commit 53b9e1c8de8446a88409d17c4aed70be33349378 Author: The Fuchsia Authors Date: Wed Jun 15 00:31:24 2016 -0700 [magenta] Initial commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..adecd81da --- /dev/null +++ b/.clang-format @@ -0,0 +1,13 @@ +Language: Cpp +ColumnLimit: 0 +UseTab: Never +IndentWidth: 4 +BreakBeforeBraces: Attach +AccessModifierOffset: -4 +DerivePointerAlignment: false +PointerAlignment: Left +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +KeepEmptyLinesAtTheStartOfBlocks: true +AlignEscapedNewlinesLeft: false +ForEachMacros: ['list_for_every_entry','list_for_every_entry_safe'] diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 000000000..66c2eafcb --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,9 @@ +;; Emacs settings. +;; Copyright (C) 2016 Google, Inc. + +( + (c-mode . ((c-file-style . "stroustrup") + (indent-tabs-mode . nil))) + (c++-mode . ((c-file-style . "stroustrup") + (indent-tabs-mode . nil))) +) diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..adf0b155e --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +build-*/ +*.swp +*~ +tags +TAGS +local.mk +*.orig +cscope.* +doit +t +tagit +blk.bin +/gn +*.dSYM +scripts/toolpaths.local +clang-format +*_BACKUP_* +*_REMOTE_* +*_LOCAL_* +*_BASE_* +*.sublime-* +/out* +/tools/gn/bin/linux +/tools/gn/bin/mac +/tools/gn/bin/win diff --git a/.gn b/.gn new file mode 100644 index 000000000..8da24e9f7 --- /dev/null +++ b/.gn @@ -0,0 +1,2 @@ +# The location of the build configuration file. +buildconfig = "//gnbuild/BUILDCONFIG.gn" diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..c2a4eac3c --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +# This is the list of Fuchsia Authors. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name + +Google Inc. diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 000000000..b8217ca5c --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,48 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/convert_to_raw.gni") + +# This target will be built if no target is specified when invoking Ninja. +executable("lk") { + output_extension = "elf" + configs -= [ "//gnbuild:user_defaults" ] + configs += [ "//gnbuild:kernel_defaults" ] + deps = [ + "//kernel/top", + ] + if (target_cpu == "x64") { + deps += [ + "//kernel/arch/x86", + "//kernel/arch/x86:kernel_ld", + ] + if (target_platform == "pc") { + deps += [ "//kernel/project:pc-x86-64" ] + } else if (target_platform == "qemu") { + deps += [ "//kernel/project:qemu-x86-64" ] + } + } else if (target_cpu == "arm") { + deps += [ + "//kernel/arch/arm", + "//kernel/arch/arm:onesegment_ld", + "//kernel/project:qemu-arm32", + ] + } else if (target_cpu == "arm64") { + deps += [ + "//kernel/arch/arm64", + "//kernel/arch/arm64:onesegment_ld", + "//kernel/project:qemu-arm64", + ] + } +} + +convert_to_raw("lk_bin") { + input = "${root_build_dir}/lk.elf" + output = "${root_build_dir}/lk.bin" + deps = [ + ":lk", + ] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..3423d9c5f --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +The Magenta Kernel (kernel/...) is under the MIT License, a copy of which +may be found in kernel/LICENSE + +The Magenta System (system/...) is under the Apache 2 License, a copy of +which may be found in system/LICENSE + +The Third Party Components (third_party/...) are under various licenses +(of the BSD, MIT, or Zlib style), which may be found in the root directory +of each component, respectively. diff --git a/README.md b/README.md new file mode 100644 index 000000000..cb07e76dc --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# MAGENTA REPOSITORY + +Welcome to the Magenta repository. + +The documentation is divided into + ++ [LK](docs/lk/index.md) specific. ++ [Magenta](docs/magenta/index.md) specific. diff --git a/docs/lk/index.md b/docs/lk/index.md new file mode 100644 index 000000000..a7c15c603 --- /dev/null +++ b/docs/lk/index.md @@ -0,0 +1,22 @@ +#LK + +The LK embedded kernel. An SMP-aware kernel designed for small systems. + +See https://github.com/littlekernel/lk for the latest version. + +See https://github.com/littlekernel/lk/wiki for documentation. + +## to build and test for ARM on linux + +1. install or build qemu. v2.4 and above is recommended. +2. install gcc for embedded arm (see note 1) +3. run scripts/do-qemuarm (from the lk directory) +4. you should see 'welcome to lk/MP' + +This will get you a interactive prompt into LK which is running in qemu +arm machine 'virt' emulation. type 'help' for commands. + +note 1: for ubuntu: +sudo apt-get install gcc-arm-none-eabi +or fetch a prebuilt toolchain from +http://newos.org/toolchains/arm-eabi-5.3.0-Linux-x86_64.tar.xz diff --git a/docs/magenta/futex.md b/docs/magenta/futex.md new file mode 100644 index 000000000..4c68aa875 --- /dev/null +++ b/docs/magenta/futex.md @@ -0,0 +1,76 @@ +# Futexes + +## What is a futex? + +A **futex** is a Fast Userspace muTEX. It is a low level +synchronization primitive which is a building block for higher level +APIs such as `pthread_mutex_t` and `pthread_cond_t`. + +Futexes are designed to not enter the kernel or allocate kernel +resources in the uncontested case. + +## Papers about futexes + +- [Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux](https://www.kernel.org/doc/ols/2002/ols2002-pages-479-495.pdf), Hubertus Franke and Rusty Russell + + This is the original white paper describing the Linux futex. It + documents the history and design of the original implementation, + prior (failed) attempts at creating a fast userspace + synchronization primitive, and performance measurements. + +- [Futexes Are Tricky](https://www.akkadia.org/drepper/futex.pdf), Ulrich Drepper + This paper describes some gotchas and implementation details of + futexes in Linux. It discusses the kernel implementation, and goes + into more detail about correct and efficient userspace + implementations of mutexes, condition variables, and so on. + +## API + +The magenta futex implementation currently supports three operations: + +```C + uint32_t sys_futex_wait(int* value_ptr, int current_value, uint32_t timeout) + uint32_t sys_futex_wake(int* value_ptr, uint32_t wake_count) + uint32_t sys_futex_requeue(int* value_ptr, uint32_t wake_count, int current_value, int* requeue_ptr, uint32_t requeue_count); +``` + +All of these share a `value_ptr` parameter, which is the virtual +address of an aligned userspace integer. This virtual address is the +information used in kernel to track what futex given threads are +waiting on. The kernel does not currently modify the value of +`*value_ptr` (but see below for future operations which might do +so). It is up to userspace code to correctly atomically modify this +value across threads in order to build mutexes and so on. + +### `sys_futex_wait` + +Waiting on a futex (or acquiring it) causes a thread to sleep until +the futex is made available by a call to `sys_futex_wake`. Optionally, +the thread can also be woken up after the timeout argument expires. + +### `sys_futex_wake` + +Waking a futex causes `wake_count` threads waiting on that futex to be +woken up. + +### `sys_futex_requeue` + +Requeuing is a generalization of waking. After waking `wake_count` +threads, `requeue_count` threads are moved from the original futex's +wait queue to the wait queue corresponding to `requeue_ptr`, another +futex. + +This requeueing behavior is used to avoid thundering herds on wake. + +## Differences from Linux futexes + +Note that all of the magenta futex operations key off of the virtual +address of an userspace pointer. This differs from the Linux +implementation, which distinguishes private futex operations (which +correspond to our in-process-only ones) from ones shared across +address spaces. + +As noted above, all of our futex operations leave the value of the +futex unmodified from the kernel. Other potential operations, such as +Linux's `FUTEX_WAKE_OP`, requires atomic manipulation of the value +from the kernel, which our current implementation does not require. diff --git a/docs/magenta/gn.md b/docs/magenta/gn.md new file mode 100644 index 000000000..ddd388a34 --- /dev/null +++ b/docs/magenta/gn.md @@ -0,0 +1,107 @@ +# GN + +## Prerequisites + +1. run `sudo apt-get install ninja-build` to install Ninja + +2. build toolchains for aarch64 and x86_64: + + ```bash + cd $SRC + git clone https://github.com/travisg/toolchains.git + cd toolchains + ./doit -a 'arm i686 aarch64 x86_64' -f -j32 + export PATH=$SRC/toolchains/aarch64-elf-5.3.0-Linux-x86_64/bin:$SRC/toolchains/x86_64-elf-5.3.0-Linux-x86_64/bin:$PATH + ``` + +3. build and install qemu: + + ```bash + cd $SRC + git clone http://git.qemu.org/git/qemu.git + cd qemu + ./configure --target-list=aarch64-softmmu,x86_64-softmmu + make -j32 + ``` + +4. run `./scripts/download-gn` (from the lk directory) to download GN + +## Build Magenta with GN for QEMU x64 + +1. run GN to generate Ninja build script: + + ```bash + ./gn gen out/qemu-x64 --script-executable=/bin/sh --args='target_cpu="x64" target_platform="qemu"' + ``` + +2. run Ninja to build the Magenta: + + ```bash + ninja -C out/qemu-x64 + ``` + +3. run Magenta using qemu: + + ```bash + ./scripts/run-magenta-x86-64 -o out/qemu-x64 + ``` + +## Build Magenta with GN for QEMU arm64 + +1. run GN to generate Ninja build script: + + ```bash + ./gn gen out/qemu-arm64 --script-executable=/bin/sh --args='target_cpu="arm64" target_platform="qemu"' + ``` + +2. run Ninja to build the Magenta: + + ```bash + ninja -C out/qemu-arm64 + ``` + +3. run Magenta using qemu: + + ```bash + ./scripts/run-magenta-arm64 -o out/qemu-arm64 + ``` + +## Build Magenta with GN for Pixel 2 + +1. run GN to generate Ninja build script: + + ```bash + ./gn gen out/pc-x64 --script-executable=/bin/sh --args='target_cpu="x64" target_platform="pc"' + ``` + +2. run Ninja to build the Magenta: + + ```bash + ninja -C out/pc-x64 + ``` + +3. run Magenta using network boot: + + ```bash + ./tools/bootserver out/pc-x64/lk.bin + ``` + +## Build Magenta with GN for QEMU arm32 + +1. run GN to generate Ninja build script: + + ```bash + ./gn gen out/qemu-arm32 --script-executable=/bin/sh --args='target_cpu="arm32" target_platform="qemu"' + ``` + +2. run Ninja to build the Magenta: + + ```bash + ninja -C out/qemu-arm32 + ``` + +3. run Magenta using qemu: + + ```bash + ./scripts/run-magenta-arm32 -o out/qemu-arm32 + ``` diff --git a/docs/magenta/index.md b/docs/magenta/index.md new file mode 100644 index 000000000..9428c8675 --- /dev/null +++ b/docs/magenta/index.md @@ -0,0 +1,14 @@ +# Magenta + +Magenta is the OS kernel that powers FNL for Phones and +Personal Computers. + +This page is a non-comprehensive index of the magenta documentation. + ++ [Relationship with LK](mg_and_lk.md) ++ [Kernel Objects](kernel_objects.md) + + [Process Objects](process_object.md) + + [Thread Objects](thread_object.md) ++ [Futexes](futex.md) ++ [System Calls](syscalls.md) ++ [Build System](gn.md) diff --git a/docs/magenta/kernel_objects.md b/docs/magenta/kernel_objects.md new file mode 100644 index 000000000..f670014ca --- /dev/null +++ b/docs/magenta/kernel_objects.md @@ -0,0 +1,54 @@ +# Magenta Kernel objects + +[TOC] + +Magenta is a object-based kernel. User mode code almost exclusively interacts +with OS resources via object handles which map kernel objects to processes. + +## Kernel objects in progress + ++ [Process](process_object.md) ++ [Thread](thread_object.md) ++ Event ++ Message pipe ++ Interrupt request ++ Futex + +## Kernel objects planned + ++ Data pipe ++ Memory mapping (VM object) ++ Job + +## Kernel Object and LK +Most kernel objects wrap one or more LK-level constructs. For example the +Thread object wraps one thread_t, or the Event object wraps one event_t. +The Message Pipe however wraps two port_t objects and there is not a fixed +mapping from LK to the Process object. + +## Kernel object lifetime +Kernel objects are ref-counted. Most kernel objects are born during a syscall +and are held alive at refcount = 1 by the handle which binds the handle value +given as the output of the syscall. The handle object is held alive as long it +is attached to a handle table. Handles are detached from the handle table +closing them (for example via `sys_close()`) which decrements the refcount of +the kernel object. Usually, when the last handle is closed the kernel object +refcount will reach 0 which causes the destructor to be run. + +The refcount increases both when new handles (referring to the object) are +created and when a direct pointer reference (by some kernel code) is acquired; +therefore a kernel object lifetime might be longer than the lifetime of the +process that created it. + +## Dispatchers +A kernel object is implemented as a C++ class that derives from `Dispatcher` +and that overrides the methods it implements. Thus, for example, the code +of the Thread object is found in `ThreadDispatcher`. There is plenty of +code that only cares about kernel objects in the generic sense, in that case +the name you'll see is `utils::RefPtr`. + +## Kernel Object security +In principle, kernel objects do not have an intrinsic notion of security and +do not do authorization; security rights are held by each handle. A Single +process can have two different handles to the same object with different +rights. diff --git a/docs/magenta/mg_and_lk.md b/docs/magenta/mg_and_lk.md new file mode 100644 index 000000000..8f36e3887 --- /dev/null +++ b/docs/magenta/mg_and_lk.md @@ -0,0 +1,22 @@ +# Magenta and LK + +Magenta is based on [LK](https://github.com/littlekernel/lk) but over time it +will diverge from it significantly. As it does this document should be updated +accordingly. + +LK is a Kernel designed for small systems typically used in embedded +applications. It is good alternative to commercial offerings like +[FreeRTOS](http://www.freertos.org/) or [ThreadX](http://rtos.com/products/threadx/). +Such systems often have a very limited amount of ram, a fixed set of peripherals +and a bounded set of tasks. + +On the other hand, Magenta targets modern phones and modern personal computers +with fast processors, non-trivial amounts of ram with arbitrary peripherals +doing open ended computation. + +More specifically, some the visible differences are: + ++ Magenta has user-mode support `lib/lkuser, lib/magenta`, upstream LK does not. ++ Magenta has objects, they are manipulated by user mode via handles. ++ Magenta has a capability-based security model. In LK all code is trusted. ++ Magenta supports at the kernel level, the Mojo application model. diff --git a/docs/magenta/process_object.md b/docs/magenta/process_object.md new file mode 100644 index 000000000..c20f612ea --- /dev/null +++ b/docs/magenta/process_object.md @@ -0,0 +1,22 @@ +# Process Object +The process object, just like on other OSes is a container of the following +resources: + ++ Handle table ++ Memory regions ++ [Threads](thread_object.md) + +In general it operates more or less like a Linux or Windows process in +terms of being it associated with code (one or more ELF binaries) which it +is executing until it is forcefully terminated or the program exits. + +## Lifetime +A process is created via `sys_process_create()` which take no parameters. +The process starts destruction when main thread terminates or the last handle +is closed. [⚠ not implemented]. + +Next, the main binary is loaded into the process via `sys_process_load()` and +its execution begins with `sys_process_start()`. + +A thread in another process can wait for a process to exit with +`sys_process_join()`. diff --git a/docs/magenta/syscalls.md b/docs/magenta/syscalls.md new file mode 100644 index 000000000..94d5100be --- /dev/null +++ b/docs/magenta/syscalls.md @@ -0,0 +1,14 @@ +# Magenta System Calls + +## Handles + ++ [handle_close](syscalls/handle_close.md) ++ [handle_duplicate](syscalls/handle_duplicate.md) ++ [handle_wait_many](syscalls/handle_wait_many.md) ++ [handle_wait_one](syscalls/handle_wait_one.md) + +## Message Pipes + ++ [message_pipe_create](syscalls/message_pipe_create.md) ++ [message_read](syscalls/message_read.md) ++ [message_write](syscalls/message_write.md) diff --git a/docs/magenta/syscalls/handle_close.md b/docs/magenta/syscalls/handle_close.md new file mode 100644 index 000000000..c4e68b43e --- /dev/null +++ b/docs/magenta/syscalls/handle_close.md @@ -0,0 +1,27 @@ +# _magenta_handle_close + +## NAME + +handle_close - close a handle + +## SYNOPSIS + +``` +#include + +mx_status_t _magenta_handle_close(mx_handle_t handle); +``` + +## DESCRIPTION + +**handle_close**() closes a *handle*, causing the underlying object to be +reclaimed by the kernel if no other handles to it exist. + +## RETURN VALUE + +**handle_close**() returns **NO_ERROR** on success. + +## ERRORS + +**ERR_INVALID_ARGS** *handle* isn't a valid handle. + diff --git a/docs/magenta/syscalls/handle_duplicate.md b/docs/magenta/syscalls/handle_duplicate.md new file mode 100644 index 000000000..2eb19ae51 --- /dev/null +++ b/docs/magenta/syscalls/handle_duplicate.md @@ -0,0 +1,33 @@ +# _magenta_handle_duplicate + +## NAME + +handle_duplicate - duplicate a handle + +## SYNOPSIS + +``` +#include + +mx_handle_t _magenta_handle_duplicate(mx_handle_t handle); +``` + +## DESCRIPTION + +**handle_duplicate**() creates a duplicate of *handle*, referring +to the same underlying object, suitable for passing to another process +via a message pipe. + +## RETURN VALUE + +**handle_duplicate**() returns the duplicate handle on success (a +positive value), or an error code (negative). + +## ERRORS + +**ERR_INVALID_ARGS** *handle* isn't a valid handle. + +**ERR_ACCESS_DENIED** *handle* does not have **MX_RIGHT_DUPLICATE** and may not be duplicated. + +**ERR_NO_MEMORY** (Temporary) out of memory situation. + diff --git a/docs/magenta/syscalls/handle_wait_many.md b/docs/magenta/syscalls/handle_wait_many.md new file mode 100644 index 000000000..54ec240d2 --- /dev/null +++ b/docs/magenta/syscalls/handle_wait_many.md @@ -0,0 +1,70 @@ +# _magenta_handle_wait_many + +## NAME + +handle_wait_many - wait for signals on multiple handles + +## SYNOPSIS + +``` +#include + +mx_status_t _magenta_handle_wait_many(uint32_t count, const mx_handle_t* handles, + const mx_signals_t* signals, + mx_time_t timeout, + mx_signals_t* satisfied_signals, + mx_signals_t* satisfiable_signals); +``` + +## DESCRIPTION + +**handle_wait_many**() is a blocking syscall which causes the caller to +wait until at least one of the specified *signals* is pending on one of +the specified handle *handles* or *timeout* elapses. + +The caller must provide *count* handles in the *handles* array and *count* +signal bitmasks in the *signals* array. For each entry in the *handles* +array, the corresponding entry in *signals* indicates which signals the +calling thread should be resumed for. + +The *timeout* parameter is relative time (from now) in nanoseconds which +takes two special values: **0** and **MX_TIME_INFINITE**. The former causes +the wait to complete immediately and the latter signals that wait will +never times out. + +Upon return, if non-NULL, the *satisfied_signals* array is filled with +a bitmap for each of the *count* specified handles, indicating which +signals are pending on that particular handle. + +It is possible to have the call return with a *satisfiable_signals* array +with values different than the values that caused the wait to complete +if other threads are further modifing the objects behind the *handles*. + +If non-NULL, the *satisfiable_signals* is filled with a bitmap for each of +the specified handles indicating which signals are possible to be pending +on that handle, given its type and current state. + +## RETURN VALUE + +**handle_wait_many**() returns **NO_ERROR** on success when the wait was +satisfied by the *signals* input or **ERR_TIMED_OUT** if the wait completed +because *timeout* nanoseconds have elapsed. + +In the event of **ERR_TIMED_OUT**, *satisfied_signals* may indicate +signals that were satisfied after the timeout but before the syscall +returned. + +## ERRORS + +**ERR_INVALID_ARGS** *handle* isn't a valid handle or *satisfied_signals* +or *satisfiable_signals* were invalid pointers. + +**ERR_ACCESS_DENIED** One or more of the provided *handles* does not +have **MX_RIGHT_READ** and may not be waited upon. + +**ERR_NO_MEMORY** (Temporary) failure due to lack of memory. + +## BUGS + +Currently the *satisfiable_signals* array is filled with the same content +as the *satisifed_signals* array. diff --git a/docs/magenta/syscalls/handle_wait_one.md b/docs/magenta/syscalls/handle_wait_one.md new file mode 100644 index 000000000..0ff7113f7 --- /dev/null +++ b/docs/magenta/syscalls/handle_wait_one.md @@ -0,0 +1,58 @@ +# _magenta_handle_wait_one + +## NAME + +handle_wait_one - wait for signals on a handle + +## SYNOPSIS + +``` +#include + +mx_status_t _magenta_handle_wait_one(mx_handle_t handle, mx_signals_t signals, + mx_signals_t* satisfied_signals, + mx_time timeout, + mx_signals_t* satisfiable_signals); +``` + +## DESCRIPTION + +**handle_wait_one**() is a blocking syscall which causes the caller to +wait until at least one of the specified *signals* is pending on *handle* +or *timeout* elapses. + +Upon return, if non-NULL, *satisfied_signals* is a bitmap of all of the +signals which are pending on *handle* and *satisfiable_signals* is +a bitmap of all of the signals which are possible to be pending on +*handle*, given its type and current state. + +It is possible to have the call return with a *satisfiable_signals* +value being different than the value that caused the wait to complete +if another thread is further modifing the object behind *handle*. + +The *timeout* parameter is relative time (from now) in nanoseconds which +takes two special values: **0** and **MX_TIME_INFINITE**. The former causes +the wait to complete immediately and the latter signals that wait will +never times out. + +## RETURN VALUE + +**handle_wait_one**() returns **NO_ERROR** on success or **ERR_TIMED_OUT** +if the wait completed because *timeout* nanoseconds have elapsed. + +In the event of **ERR_TIMED_OUT**, *satisfied_signals* may indicate +signals that were satisfied after the timeout but before the syscall +returned. + +## ERRORS + +**ERR_INVALID_ARGS** *handle* isn't a valid handle or *satisfied_signals* +or *satisfiable_signals* were invalid pointers. + +**ERR_ACCESS_DENIED** *handle* does not have **MX_RIGHT_READ** and may +not be waited upon. + +## BUGS + +Currently the *satisfiable_signals* return value is filled with the same +content as the *satisifed_signals* value. diff --git a/docs/magenta/syscalls/message_pipe_create.md b/docs/magenta/syscalls/message_pipe_create.md new file mode 100644 index 000000000..1488043ab --- /dev/null +++ b/docs/magenta/syscalls/message_pipe_create.md @@ -0,0 +1,53 @@ +# _magenta_message_pipe_create + +## NAME + +message_pipe_create - create a message pipe + +## SYNOPSIS + +``` +#include + +mx_handle_t _magenta_message_pipe_create(mx_handle_t* other_handle); + +``` + +## DESCRIPTION + +**message_pipe_create**() creates a message pipe, a bi-directional +datagram-style message transport capable of sending raw data bytes +as well as handles from one side to the other. + +Two handles are returned on success, providing access to both sides +of the message pipe. Messages written to one handle may be read +from the opposite. + +The handles will have MX_RIGHT_TRANSFER (allowing them to be sent +to another process via message pipe write), MX_RIGHT_WRITE (allowing +messages to be written to them), and MX_RIGHT_READ (allowing messages +to be read from them). + +## RETURN VALUE + +**message_pipe_create**() returns a valid message pipe handle (positive) +on success, in which case the handle to the other side of the message +pipe is returned via the *other_handle* pointer. In the event of failure, +a negative error value is returned. Zero (the "invalid handle") is never +returned. + +## ERRORS + +**ERR_INVALID_ARGS** *other_handle* is an inavlid pointer or NULL. + +**ERR_NO_MEMORY** (Temporary) Failure due to lack of memory. + +## SEE ALSO + +[handle_close](handle_close.md), +[handle_duplicate](handle_duplicate.md), +[handle_wait_one](handle_wait_one), +[handle_wait_many](handle_wait_many.md), +[message_read](message_read.md), +[message_write](message_write.md). + diff --git a/docs/magenta/syscalls/message_read.md b/docs/magenta/syscalls/message_read.md new file mode 100644 index 000000000..4b318cc58 --- /dev/null +++ b/docs/magenta/syscalls/message_read.md @@ -0,0 +1,76 @@ +# _magenta_message_read + +## NAME + +message_read - read a message from a message pipe + +## SYNOPSIS + +``` +#include + +mx_status_t _magenta_message_read(mx_handle_t handle, + void* bytes, uint32_t* num_bytes, + mx_handle_t* handles, uint32_t* num_handles, + uint32_t flags); +``` + +## DESCRIPTION + +**message_read**() attempts to read the first message from the message +pipe specified by *handle* into the provided *bytes* and/or *handles* +buffers. + +The pointers *num_bytes* and *num_handles* are used to specify the +size of the read buffers, and upon return may be used to indicate the +actual size of the message read (upon success) or the size of the +message (upon failure due to the provided buffers being too small. +If these pointers are NULL, their respective buffer sizes are understood +to be zero. + +Message pipe messages may contain both byte data and handle payloads +and may only be read in their entirety. Partial reads are not possible. + +## RETURN VALUE + +**message_read**() returns **NO_ERROR** on success, and the uint32_t's +pointed at by *num_bytes* and/or *num_handles* (provided they are +non-NULL) are updated to reflect the exact size of the byte and handle +payloads of the message read. + +## ERRORS + +**ERR_INVALID_ARGS** *handle* isn't a valid message pipe handle, or +*num_bytes* (if non-NULL) is an invalid pointer, or *num_handles* (if +non-NULL) is an invalid pointer, or *bytes* is non-NULL but +*num_bytes* is NULL, or *handles* is non-NULL but *num_handles* +is null, or *handles* or *num_handles* (if non-NULL) are invalid +pointers. + +**ERR_ACCESS_DENIED** *handle* does not have **MX_RIGHT_READ**. + +**ERR_NO_MSG** The message pipe contained no messages to read. + +**ERR_BAD_STATE** The other side of the message pipe is closed. + +**ERR_NO_MEMORY** (Temporary) Failure due to lack of memory. + +**ERR_NOT_ENOUGH_BUFFER** The provided *bytes* or *handles* buffers +are too small (in which case, the minimum sizes necessary to receive +the message will be written to the uint32_t's pointed at by these +parameters, provided they are non-NULL). + +## NOTES + +*num_handles* is a pointer to a count of the number of elements in +the *handles* array, not its size in bytes. + +## SEE ALSO + +[handle_close](handle_close.md), +[handle_duplicate](handle_duplicate.md), +[handle_wait_one](handle_wait_one), +[handle_wait_many](handle_wait_many.md), +[message_pipe_create](message_pipe_create.md), +[message_write](message_write.md). + diff --git a/docs/magenta/syscalls/message_write.md b/docs/magenta/syscalls/message_write.md new file mode 100644 index 000000000..ac166bef0 --- /dev/null +++ b/docs/magenta/syscalls/message_write.md @@ -0,0 +1,58 @@ +# _magenta_message_write + +## NAME + +message_write - write a message to a message pipe + +## SYNOPSIS + +``` +#include + +mx_status_t _magenta_message_write(mx_handle_t handle, + void* bytes, uint32_t num_bytes, + mx_handle_t* handles, uint32_t num_handles, + uint32_t flags); +``` + +## DESCRIPTION + +**message_write**() attempts to write a message of *num_bytes* +bytes and *num_handles* handles to the message pipe specified by +*handle*. The pointers *handles* and *bytes* may be null if their +respective sizes are zero. + +## RETURN VALUE + +**message_write**() returns **NO_ERROR** on success. + +## ERRORS + +**ERR_INVALID_ARGS** *handle* isn't a valid message pipe handle, or +*bytes* is an invalid pointer, or *handles* is an invalid pointer, +or any of the handles passed via the *handles* array are invalid +handles. + +**ERR_ACCESS_DENIED** *handle* does not have **MX_RIGHT_WRITE**. + +**ERR_BAD_STATE** The other side of the message pipe is closed. + +**ERR_NO_MEMORY** (Temporary) Failure due to lack of memory. + +**ERR_TOO_BIG** *num_bytes* or *num_handles* are larger than the +largest allowable size for message pipe messages. + +## NOTES + +*num_handles* is a count of the number of elements in the *handles* +array, not its size in bytes. + +## SEE ALSO + +[handle_close](handle_close.md). +[handle_duplicate](handle_duplicate.md), +[handle_wait_one](handle_wait_one), +[handle_wait_many](handle_wait_many.md), +[message_pipe_create](message_pipe_create.md), +[message_read](message_read.md). + diff --git a/docs/magenta/thread_object.md b/docs/magenta/thread_object.md new file mode 100644 index 000000000..845699844 --- /dev/null +++ b/docs/magenta/thread_object.md @@ -0,0 +1,14 @@ +# Thread +Just like in other OSes, the thread object is the construct that represents a +time-shared CPU execution context. Thread objects live associated to a +particular [Process Object](process_object.md) which provides the memory and +the handles to other objects necessary for I/O and computation. + +## Lifetime +A thread can be created implicitly by calling `sys_process_start()`, in which +case the new thread is the "main thread" and the thread entrypoint is defined by +the previously loaded ELF binary. Or it can be created by calling +`sys_thread_create()` which takes the entrypoint as a parameter. + +A thread terminates when it `return`s from executing the routine specified as +the entrypoint or by calling `sys_thread_exit()`. diff --git a/gnbuild/BUILD.gn b/gnbuild/BUILD.gn new file mode 100644 index 000000000..3c93a238c --- /dev/null +++ b/gnbuild/BUILD.gn @@ -0,0 +1,318 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("compiler_defaults") { + cflags = [ + "-O2", + "-finline", + "-ffunction-sections", + "-fdata-sections", + ] + cflags_c = [ "-std=c11" ] + cflags_cc = [ + "-std=c++11", + "-fno-exceptions", + "-fno-asynchronous-unwind-tables", + "-fno-rtti", + "-fno-threadsafe-statics", + ] + + if (target_cpu == "x64") { + defines = [ + "ARCH_X86=1", + "ARCH_X86_64=1", + "ARCH_X86_32=0", + "IS_64BIT=1", + "ARCH=\"x86\"", + "PLATFORM=\"PC\"", + "PLATFORM_PC=1", + "PLATFORM_HAS_DYNAMIC_TIMER=1", + "X86_WITH_FPU=1", + ] + if (target_platform == "qemu") { + defines += [ + "PROJECT_MAGENTA_QEMU_X86_64=1", + "PROJECT=\"MAGENTA_QEMU_X86_64\"", + "TARGET_QEMU_X86_64=1", + "TARGET=\"QEMU_X86_64\"", + ] + } else if (target_platform == "pc") { + defines += [ + "PROJECT_MAGENTA_PC_UEFI=1", + "PROJECT=\"MAGENTA_PC_UEFI\"", + "TARGET_PC_UEFI=1", + "TARGET=\"PC_UEFI\"", + ] + } + cflags += [ + "-fno-pic", + "-fno-stack-protector", + ] + if (is_clang) { + cflags += [ + "-target", + "x86_64-elf", + ] + } + } else if (target_cpu == "arm") { + defines = [ + "__thumb__", + "ARCH_ARM=1", + "ARM_CPU_CORTEX_A15=1", + "ARM_WITH_CP15=1", + "ARM_WITH_MMU=1", + "ARM_ISA_ARMV7=1", + "ARM_ISA_ARMV7A=1", + "ARM_WITH_THUMB=1", + "ARM_WITH_THUMB2=1", + "ARM_WITH_CACHE=1", + "ARM_WITH_L2=1", + "ARM_WITH_VFP=1", + "ARM_WITH_NEON=1", + "ARCH_DEFAULT_STACK_SIZE=4096", + "PLATFORM_HAS_DYNAMIC_TIMER=1", + "PLATFORM_SUPPORTS_PANIC_SHELL=1", + "MMU_WITH_TRAMPOLINE=1", + "ARCH=\"arm\"", + "PLATFORM_QEMU_VIRT=1", + "PLATFORM=\"QEMU_VIRT\"", + "PROJECT_MAGENTA_QEMU_ARM32=1", + "PROJECT=\"MAGENTA_QEMU_ARM32\"", + "TARGET_QEMU_VIRT=1", + "TARGET=\"QEMU_VIRT\"", + ] + cflags += [ + "-mthumb-interwork", + "-mcpu=cortex-a15", + "-mfpu=vfpv3", + "-mfloat-abi=softfp", + "-mthumb", + ] + asmflags = [ + "-mthumb-interwork", + "-mcpu=cortex-a15", + "-mfpu=vfpv3", + "-mfloat-abi=softfp", + "-mthumb", + ] + if (is_clang) { + cflags += [ + "-target", + "arm-elf", + ] + } + } else if (target_cpu == "arm64") { + defines = [ + "ARM64_CPU_CORTEX_A53=1", + "ARCH_ARM64=1", + "ARM_ISA_ARMV8=1", + "ARM_ISA_ARMV8A=1", + "IS_64BIT=1", + "ARCH_DEFAULT_STACK_SIZE=4096", + "PLATFORM_HAS_DYNAMIC_TIMER=1", + "PLATFORM_SUPPORTS_PANIC_SHELL=1", + "MMU_WITH_TRAMPOLINE=1", + "ARCH=\"arm64\"", + "ARM_CPU=\"cortex-a53\"", + "PLATFORM_QEMU_VIRT=1", + "PLATFORM=\"QEMU_VIRT\"", + "PROJECT_MAGENTA_QEMU_ARM64=1", + "PROJECT=\"MAGENTA_QEMU_ARM64\"", + "TARGET_QEMU_VIRT=1", + "TARGET=\"QEMU_VIRT\"", + ] + if (is_clang) { + cflags += [ + "-target", + "aarch64-elf", + ] + } + } +} + +config("no_floats") { + defines = [ "WITH_NO_FP=1" ] + if (target_cpu == "x64") { + cflags = [ + "-msoft-float", + "-mno-mmx", + "-mno-sse", + "-mno-sse2", + "-mno-3dnow", + "-mno-avx", + "-mno-avx2", + ] + if (!is_clang) { + cflags += [ + "-mno-80387", + "-mno-fp-ret-in-387", + ] + } + } +} + +config("kernel_defaults") { + configs = [ ":no_floats" ] + include_dirs = [ "//kernel/include" ] + defines = [ + "LK=1", + "_KERNEL", + ] + cflags = [ "-ffreestanding" ] + asmflags = [ "-DASSEMBLY" ] + + if (is_debug) { + defines += [ "LK_DEBUGLEVEL=${debug_level}" ] + if (enable_debug_linebuffer) { + defines += [ "WITH_DEBUG_LINEBUFFER=1" ] + } + cflags += [ "-g" ] + if (target_cpu == "x64") { + cflags += [ "-gdwarf-2" ] + } + } + + if (enable_vm) { + defines += [ "WITH_KERNEL_VM=1" ] + } + + if (target_cpu == "x64") { + include_dirs += [ "//kernel/arch/x86/include" ] + cflags += [ + "-mcmodel=kernel", + "-mno-red-zone", + ] + if (!is_clang) { + cflags += [ + "-mskip-rax-setup", + "-falign-jumps=1", + "-falign-loops=1", + "-falign-functions=4", + ] + } + if (enable_smp) { + defines += [ + "WITH_SMP=1", + "SMP_MAX_CPUS=16", + ] + } else { + defines += [ "SMP_MAX_CPUS=1" ] + } + } else if (target_cpu == "arm") { + include_dirs += [ + "//kernel/arch/arm/include", + "//kernel/arch/arm/arm/include", + ] + if (enable_smp) { + defines += [ + "WITH_SMP=1", + "SMP_MAX_CPUS=4", + "SMP_CPU_CLUSTER_SHIFT=8", + "SMP_CPU_ID_BITS=24", + ] + } else { + defines += [ "WITH_SMP=0" ] + } + } else if (target_cpu == "arm64") { + include_dirs += [ "//kernel/arch/arm64/include" ] + if (enable_smp) { + defines += [ + "WITH_SMP=1", + "SMP_MAX_CPUS=4", + "SMP_CPU_CLUSTER_SHIFT=8", + "SMP_CPU_ID_BITS=24", + ] + } else { + defines += [ "WITH_SMP=0" ] + } + } + + if (target_cpu == "x64") { + linker_script = "${root_gen_dir}/kernel.ld" + } else if (target_cpu == "arm") { + linker_script = "${root_gen_dir}/system-onesegment.ld" + } else if (target_cpu == "arm64") { + linker_script = "${root_gen_dir}/system-onesegment.ld" + } + ldflags = [ + "-Wl,-T", + rebase_path(linker_script, root_out_dir), + ] +} + +config("user_defaults") { + defines = [ + "_XOPEN_SOURCE=700", + "_BSD_SOURCE", + ] + + if (is_debug) { + cflags = [ "-g" ] + if (target_cpu == "x64") { + cflags += [ "-gdwarf-2" ] + } + } + + if (target_cpu == "x64") { + linker_script = "//kernel/arch/x86/64/user.ld" + } else if (target_cpu == "arm") { + linker_script = "//kernel/arch/arm/user.ld" + } else if (target_cpu == "arm64") { + linker_script = "//kernel/arch/arm64/user.ld" + } + ldflags = [ + "-Wl,-T", + rebase_path(linker_script, root_out_dir), + ] +} + +config("executable_ldconfig") { + ldflags = [ + "-nostdlib", + "-Wl,-z,max-page-size=4096", + "-Wl,--gc-sections", + ] + if (!is_clang) { + libs = [ exec_script("libgcc_path.sh", [ toolprefix ], "trim string") ] + } +} + +config("default_warnings") { + # TODO(phosek): split these into multiple configs + cflags = [ + "-Wall", + + #-Wextra + #-Werror + "-Wno-multichar", + "-Wno-unused-parameter", + "-Wno-unused-function", + "-Wno-unused-label", + "-Werror=return-type", + + #"-Wundef", + ] + if (is_clang) { + cflags += [ + "-Wno-incompatible-pointer-types-discards-qualifiers", + "-Wno-format", + ] + } +} + +config("strict_compiler_flags") { + cflags_c = [ + "-Werror-implicit-function-declaration", + "-Wstrict-prototypes", + "-Wwrite-strings", + ] +} + +config("no_stack_protector") { + cflags = [ "-fno-stack-protector" ] +} diff --git a/gnbuild/BUILDCONFIG.gn b/gnbuild/BUILDCONFIG.gn new file mode 100644 index 000000000..13cdc32b3 --- /dev/null +++ b/gnbuild/BUILDCONFIG.gn @@ -0,0 +1,96 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +if (target_os == "") { + target_os = "fuchsia" +} +if (target_cpu == "") { + target_cpu = host_cpu +} +if (current_cpu == "") { + current_cpu = target_cpu +} +if (current_os == "") { + current_os = target_os +} + +declare_args() { + # The desired platform for the build. + target_platform = "qemu" + + # Debug build. + is_debug = true + + # Set to true when compiling with the Clang compiler. + is_clang = false + + # This should not be set as a build argument. + target_toolchain = "" + + # This should not be set as a build argument. + host_toolchain = "" +} + +# All binary targets will get this list of configs by default. +_shared_binary_target_configs = [ + "//gnbuild:compiler_defaults", + "//gnbuild:default_warnings", + "//gnbuild:strict_compiler_flags", +] + +# Apply that default list to the binary target types. +set_defaults("source_set") { + configs = _shared_binary_target_configs + configs += [ "//gnbuild:user_defaults" ] +} +set_defaults("static_library") { + configs = _shared_binary_target_configs + configs += [ "//gnbuild:user_defaults" ] +} +set_defaults("module") { + configs = _shared_binary_target_configs + configs += [ "//gnbuild:kernel_defaults" ] +} +set_defaults("executable") { + configs = _shared_binary_target_configs + configs += [ + "//gnbuild:user_defaults", + "//gnbuild:executable_ldconfig", + ] +} + +# Toolchain + +if (target_cpu == "arm" || target_cpu == "arm64" || target_cpu == "x64") { + if (is_clang) { + target_toolchain = "//gnbuild/toolchain:clang_target" + } else { + target_toolchain = "//gnbuild/toolchain:target" + } +} else { + assert(false, "Target CPU not supported") +} + +set_default_toolchain(target_toolchain) + +if (host_os == "linux") { + host_toolchain = "//gnbuild/toolchain:gcc_host" +} else if (host_os == "mac") { + host_toolchain = "//gnbuild/toolchain:clang_host" +} else { + assert(false, "Host OS not supported") +} + +# Module + +# The template for kernel module. +# +# Accepts everything source_set accepts. +template("module") { + source_set(target_name) { + forward_variables_from(invoker, "*") + } +} diff --git a/gnbuild/compiled_action.gni b/gnbuild/compiled_action.gni new file mode 100644 index 000000000..69b49f86a --- /dev/null +++ b/gnbuild/compiled_action.gni @@ -0,0 +1,164 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# This file introduces two related templates that act like action and +# action_foreach but instead of running a script, it will compile a given tool +# in the host toolchain and run that (either once or over the list of inputs, +# depending on the variant). +# +# Parameters +# +# tool (required) +# [label] Label of the tool to run. This should be an executable, and +# this label should not include a toolchain (anything in parens). The +# host compile of this tool will be used. +# +# outputs (required) +# [list of files] Like the outputs of action (if using "compiled_action", +# this would be just the list of outputs), or action_foreach (if using +# "compiled_action_foreach", this would contain source expansions mapping +# input to output files). +# +# args (required) +# [list of strings] Same meaning as action/action_foreach. +# +# inputs (optional) +# Files the binary takes as input. The step will be re-run whenever any +# of these change. If inputs is empty, the step will run only when the +# binary itself changes. +# +# visibility +# deps +# args (all optional) +# Same meaning as action/action_foreach. +# +# +# Example of usage: +# +# compiled_action("run_my_tool") { +# tool = "//tools/something:mytool" +# outputs = [ +# "$target_gen_dir/mysource.cc", +# "$target_gen_dir/mysource.h", +# ] +# +# # The tool takes this input. +# inputs = [ "my_input_file.idl" ] +# +# # In this case, the tool takes as arguments the input file and the output +# # build dir (both relative to the "cd" that the script will be run in) +# # and will produce the output files listed above. +# args = [ +# rebase_path("my_input_file.idl", root_build_dir), +# "--output-dir", rebase_path(target_gen_dir, root_build_dir), +# ] +# } +# +# You would typically declare your tool like this: +# if (host_toolchain == current_toolchain) { +# executable("mytool") { +# ... +# } +# } +# The if statement around the executable is optional. That says "I only care +# about this target in the host toolchain". Usually this is what you want, and +# saves unnecessarily compiling your tool for the target platform. But if you +# need a target build of your tool as well, just leave off the if statement. + +template("compiled_action") { + assert(defined(invoker.tool), "tool must be defined for $target_name") + assert(defined(invoker.outputs), "outputs must be defined for $target_name") + assert(defined(invoker.args), "args must be defined for $target_name") + + assert(!defined(invoker.sources), + "compiled_action doesn't take a sources arg. Use inputs instead.") + + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "inputs", + "outputs", + "testonly", + "visibility", + ]) + if (!defined(deps)) { + deps = [] + } + if (!defined(inputs)) { + inputs = [] + } + + script = "//gnbuild/gn_run_binary.sh" + + # Constuct the host toolchain version of the tool. + host_tool = invoker.tool + "($host_toolchain)" + + # Get the path to the executable. Currently, this assumes that the tool + # does not specify output_name so that the target name is the name to use. + # If that's not the case, we'll need another argument to the script to + # specify this, since we can't know what the output name is (it might be in + # another file not processed yet). + host_executable = get_label_info(host_tool, "root_out_dir") + "/" + + get_label_info(host_tool, "name") + + # Add the executable itself as an input. + inputs += [ host_executable ] + + deps += [ host_tool ] + + # The script takes as arguments the binary to run, and then the arguments + # to pass it. + args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args + } +} + +template("compiled_action_foreach") { + assert(defined(invoker.sources), "sources must be defined for $target_name") + assert(defined(invoker.tool), "tool must be defined for $target_name") + assert(defined(invoker.outputs), "outputs must be defined for $target_name") + assert(defined(invoker.args), "args must be defined for $target_name") + + action_foreach(target_name) { + forward_variables_from(invoker, + [ + "deps", + "inputs", + "outputs", + "sources", + "testonly", + "visibility", + ]) + if (!defined(deps)) { + deps = [] + } + if (!defined(inputs)) { + inputs = [] + } + + script = "//gnbuild/gn_run_binary.sh" + + # Constuct the host toolchain version of the tool. + host_tool = invoker.tool + "($host_toolchain)" + + # Get the path to the executable. Currently, this assumes that the tool + # does not specify output_name so that the target name is the name to use. + # If that's not the case, we'll need another argument to the script to + # specify this, since we can't know what the output name is (it might be in + # another file not processed yet). + host_executable = get_label_info(host_tool, "root_out_dir") + "/" + + get_label_info(host_tool, "name") + + # Add the executable itself as an input. + inputs += [ host_executable ] + + deps += [ host_tool ] + + # The script takes as arguments the binary to run, and then the arguments + # to pass it. + args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args + } +} diff --git a/gnbuild/config.gni b/gnbuild/config.gni new file mode 100644 index 000000000..95d0d380e --- /dev/null +++ b/gnbuild/config.gni @@ -0,0 +1,131 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +declare_args() { + # Use linebuffer for debug output. + enable_debug_linebuffer = true + + # Debug output verbosity. + debug_level = 2 + + # Predefines used by the kernel. + kernel_defines = [] +} + +# TODO(phosek): toolchain configuration could be moved to a separate file +if (is_clang) { + default_toolprefix = "" +} else if (target_cpu == "arm") { + default_toolprefix = "arm-eabi-" +} else if (target_cpu == "arm64") { + default_toolprefix = "aarch64-elf-" +} else if (target_cpu == "x64") { + default_toolprefix = "x86_64-elf-" +} else { + assert(false, "Target CPU not supported") +} + +declare_args() { + # Toolchain prefix. + toolprefix = default_toolprefix +} + +# Support for SMP. +enable_smp = false + +# Support for virtual memory. +enable_vm = true + +# Support for Intel HDA QEMU quirks. +enable_intel_hda_qemu_quirks = false + +# Support for PCIe. +enable_pcie = true + +# Support for application shell. +enable_shell = false + +# Kernel console. +enable_console = true + +# Support for debug log. +enable_debuglog = true + +# Support for partitioning. +enable_partition = false + +# Support for kernel log. +enable_klog = true + +# The heap implementation used. +heap_implementation = "miniheap" + +# Magenta. +enable_magenta = true + +# Support for user boot. +enable_userboot = true + +if (target_cpu == "x64") { + enable_vm = true + enable_smp = true + enable_debug_linebuffer = true + heap_implementation = "cmpctmalloc" + embed_user_bootfs = true + if (target_platform == "qemu") { + enable_intel_hda_qemu_quirks = true + } + + # TODO(phosek): Turn these into a config in arch/x86 + kernel_defines = [ + "MEMBASE=0", + "KERNEL_ASPACE_BASE=0xffffff8000000000", + "KERNEL_ASPACE_SIZE=0x0000008000000000", + "KERNEL_BASE=0xffffffff80000000", + "KERNEL_LOAD_OFFSET=0x00100000", + "KERNEL_SIZE=0x40000000", + "USER_ASPACE_BASE=0x0000000001000000", + "USER_ASPACE_SIZE=0x00007fffff000000", + "HEADER_LOAD_OFFSET=0x00010000", + "PHYS_HEADER_LOAD_OFFSET=0x00002000", + ] +} else if (target_cpu == "arm") { + enable_vm = true + enable_smp = true + enable_debug_linebuffer = true + heap_implementation = "cmpctmalloc" + embed_user_bootfs = true + + # TODO(phosek): Turn these into a config in arch/arm + kernel_defines = [ + "MEMBASE=0x40000000", + "MEMSIZE=0x08000000", + "KERNEL_ASPACE_BASE=0x40000000", + "KERNEL_ASPACE_SIZE=0xc0000000", + "KERNEL_BASE=0x80000000", + "KERNEL_LOAD_OFFSET=0x10000", + ] +} else if (target_cpu == "arm64") { + enable_vm = true + enable_smp = true + enable_debug_linebuffer = true + heap_implementation = "cmpctmalloc" + embed_user_bootfs = true + + # TODO(phosek): Turn these into a config in arch/arm64 + kernel_defines = [ + "MEMBASE=0x40000000", + "MEMSIZE=0x08000000", + "KERNEL_ASPACE_BASE=0xffff000000000000", + "KERNEL_ASPACE_SIZE=0x0001000000000000", + "USER_ASPACE_BASE=0x0000000001000000", + "USER_ASPACE_SIZE=0x0000fffffe000000", + "KERNEL_BASE=0xffff000000000000", + "KERNEL_LOAD_OFFSET=0x10000", + ] +} else { + assert(false, "Target CPU not supported") +} diff --git a/gnbuild/convert_to_raw.gni b/gnbuild/convert_to_raw.gni new file mode 100644 index 000000000..441c0d5e5 --- /dev/null +++ b/gnbuild/convert_to_raw.gni @@ -0,0 +1,46 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +# Generate a raw binary file for a given file. +# +# Parameters +# +# input (required) +# Input file name +# +# output (required) +# Output file name +# +# deps (optional) +template("convert_to_raw") { + assert(defined(invoker.input), "must specify \"input\" value") + assert(defined(invoker.output), "must specify \"output\" value") + forward_variables_from(invoker, + [ + "input", + "output", + ]) + + action(target_name) { + forward_variables_from(invoker, [ "deps" ]) + + script = "//gnbuild/convert_to_raw.sh" + sources = [ + input, + ] + outputs = [ + output, + ] + + args = [ + toolprefix, + rebase_path(input), + rebase_path(output), + ] + } +} diff --git a/gnbuild/convert_to_raw.sh b/gnbuild/convert_to_raw.sh new file mode 100644 index 000000000..c6e0a949a --- /dev/null +++ b/gnbuild/convert_to_raw.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Generate a raw binary file from the given input file. + +readonly PREFIX="$1" +readonly INPUT="$2" +readonly OUTPUT="$3" + +"${PREFIX}objcopy" -O binary "${INPUT}" "${OUTPUT}" diff --git a/gnbuild/generate_ld_script.gni b/gnbuild/generate_ld_script.gni new file mode 100644 index 000000000..5d422c824 --- /dev/null +++ b/gnbuild/generate_ld_script.gni @@ -0,0 +1,43 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Generate a linker script by replacing all variables with provided values. +# +# Parameters +# +# output (required) +# Input file name +# +# input (required) +# Output file name +# +# defines (required) +# List of defines used for substitution +template("generate_ld_script") { + assert(defined(invoker.input), "must specify \"input\" value") + assert(defined(invoker.output), "must specify \"output\" value") + assert(defined(invoker.defines), "must specify \"defines\" value") + forward_variables_from(invoker, + [ + "input", + "output", + "defines", + ]) + action(target_name) { + script = "//gnbuild/generate_ld_script.sh" + sources = [ + input, + ] + outputs = [ + output, + ] + + args = [ + rebase_path(input), + rebase_path(output), + ] + defines + } +} diff --git a/gnbuild/generate_ld_script.sh b/gnbuild/generate_ld_script.sh new file mode 100644 index 000000000..dcac72a9a --- /dev/null +++ b/gnbuild/generate_ld_script.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Generate a linker script by substituting all variables with provided values. + +declare PATTERN="" + +for i in "$@"; do + case ${i} in + *=*) + PATTERN="${PATTERN}s/%${i%=*}%/${i#*=}/;" + ;; + esac +done + +sed "${PATTERN}" <$1 >$2 diff --git a/gnbuild/gn_run_binary.sh b/gnbuild/gn_run_binary.sh new file mode 100644 index 000000000..7c41c14f5 --- /dev/null +++ b/gnbuild/gn_run_binary.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Helper script to run an arbitrary binary produced by the current build. + +"./${1}" "${@:2}" diff --git a/gnbuild/libgcc_path.sh b/gnbuild/libgcc_path.sh new file mode 100644 index 000000000..5ae0a8235 --- /dev/null +++ b/gnbuild/libgcc_path.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +TOOL_PREFIX=$1 + +${TOOL_PREFIX}gcc -print-libgcc-file-name diff --git a/gnbuild/toolchain/BUILD.gn b/gnbuild/toolchain/BUILD.gn new file mode 100644 index 000000000..c0fdc4dab --- /dev/null +++ b/gnbuild/toolchain/BUILD.gn @@ -0,0 +1,291 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +# Defines a toolchain which looks and behaves like gcc. +# +# Parameters +# +# cc +# cxx +# ar +# ld +# +# toolchain_cpu +# What "current_cpu" should be set to when invoking a build +# using this toolchain. +# +# toolchain_os +# What "current_os" should be set to when invoking a +# build using this toolchain. +# +# strip +# Whether to run strip on all shared libraries and executables as +# they're built. +# +# is_clang +# Whether to use clang instead of gcc. +# +# use_gold +# Whether the toolchain uses gold instead of ld. +template("gcc_toolchain") { + toolchain(target_name) { + assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") + assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value") + assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") + assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value") + assert(defined(invoker.toolchain_cpu), + "gcc_toolchain() must specify a \"toolchain_cpu\"") + assert(defined(invoker.toolchain_os), + "gcc_toolchain() must specify a \"toolchain_os\"") + + forward_variables_from(invoker, + [ + "cc", + "cxx", + "ar", + "ld", + ]) + + tool("cc") { + depfile = "{{output}}.d" + command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CC {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("cxx") { + depfile = "{{output}}.d" + command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CXX {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("asm") { + depfile = "{{output}}.d" + command = "$cc {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" + description = "ASM {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("alink") { + rspfile = "{{output}}.rsp" + command = + "rm -f {{output}} && $ar {{arflags}} rcsD {{output}} @\"$rspfile\"" + description = "AR {{output}}" + rspfile_content = "{{inputs}}" + outputs = [ + "{{output_dir}}/{{target_output_name}}{{output_extension}}", + ] + default_output_dir = "{{target_out_dir}}" + default_output_extension = ".a" + output_prefix = "lib" + } + + tool("solink") { + outname = "{{target_output_name}}{{output_extension}}" + outfile = "{{output_dir}}/$outname" + rspfile = "$outfile.rsp" + unstripped_outfile = outfile + if (defined(invoker.strip)) { + unstripped_outfile = "{{root_out_dir}}/lib.unstripped/{{target_output_name}}{{output_extension}}" + } + if (invoker.toolchain_os == "mac") { + command = "$ld -shared {{ldflags}} -o \"$unstripped_outfile\" -Wl,-filelist,\"$rspfile\" {{libs}} {{solibs}}" + rspfile_content = "{{inputs_newline}}" + default_output_extension = ".dylib" + } else { + command = "$ld -shared {{ldflags}} -o \"$unstripped_outfile\" -Wl,-soname=\"$outname\" @\"$rspfile\"" + rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}" + default_output_extension = ".so" + } + if (defined(invoker.strip)) { + command += + " && ${invoker.strip} -S -o \"$outfile\" \"$unstripped_outfile\"" + } + description = "SOLINK $outfile" + default_output_dir = "{{root_out_dir}}" + output_prefix = "lib" + outputs = [ + outfile, + ] + if (outfile != unstripped_outfile) { + outputs += [ unstripped_outfile ] + } + } + + tool("solink_module") { + outname = "{{target_output_name}}{{output_extension}}" + outfile = "{{output_dir}}/$outname" + rspfile = "$outfile.rsp" + if (defined(invoker.strip)) { + unstripped_outfile = "{{root_out_dir}}/lib.unstripped/{{target_output_name}}{{output_extension}}" + } else { + unstripped_outfile = outfile + } + if (invoker.toolchain_os == "mac") { + command = "$ld -shared {{ldflags}} -o \"$unstripped_outfile\" -Wl,-filelist,\"$rspfile\" {{libs}} {{solibs}}" + rspfile_content = "{{inputs_newline}}" + default_output_extension = ".dylib" + } else { + command = "$ld -shared {{ldflags}} -o \"$unstripped_outfile\" -Wl,-soname=\"$outname\" @\"$rspfile\"" + rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}" + default_output_extension = ".so" + } + if (defined(invoker.strip)) { + command += + " && ${invoker.strip} -S -o \"$outfile\" \"$unstripped_outfile\"" + } + description = "SOLINK $outfile" + default_output_dir = "{{root_out_dir}}" + output_prefix = "lib" + outputs = [ + outfile, + ] + if (outfile != unstripped_outfile) { + outputs += [ unstripped_outfile ] + } + } + + tool("link") { + outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" + rspfile = "$outfile.rsp" + unstripped_outfile = outfile + if (defined(invoker.strip)) { + unstripped_outfile = "{{root_out_dir}}/exe.unstripped/{{target_output_name}}{{output_extension}}" + } + if (invoker.toolchain_os == "mac") { + command = "$ld {{ldflags}} -o \"$unstripped_outfile\" -Wl,-filelist,\"$rspfile\" {{solibs}} {{libs}}" + } else { + command = "$ld {{ldflags}} -o \"$unstripped_outfile\" -Wl,--start-group @\"$rspfile\" {{solibs}} -Wl,--end-group {{libs}}" + } + if (defined(invoker.strip)) { + command += + " && ${invoker.strip} -S -o \"$outfile\" \"$unstripped_outfile\"" + } + description = "LINK $outfile" + rspfile_content = "{{inputs}}" + default_output_dir = "{{root_out_dir}}" + outputs = [ + outfile, + ] + if (outfile != unstripped_outfile) { + outputs += [ unstripped_outfile ] + } + } + + tool("stamp") { + command = "touch {{output}}" + description = "STAMP {{output}}" + } + + tool("copy") { + command = "cp -af {{source}} {{output}}" + description = "COPY {{source}} {{output}}" + } + + # When invoking this toolchain not as the default one, these args will be + # passed to the build. They are ignored when this is the default toolchain. + toolchain_args() { + current_cpu = invoker.toolchain_cpu + current_os = invoker.toolchain_os + + # These values need to be passed through unchanged. + target_toolchain = target_toolchain + target_os = target_os + target_cpu = target_cpu + + if (defined(invoker.is_clang)) { + is_clang = invoker.is_clang + } + if (defined(invoker.use_gold)) { + use_gold = invoker.use_gold + } + } + } +} + +template("clang_toolchain") { + assert(defined(invoker.cc), "clang_toolchain() must specify a \"cc\" value") + assert(defined(invoker.cxx), "clang_toolchain() must specify a \"cxx\" value") + assert(defined(invoker.ar), "clang_toolchain() must specify a \"ar\" value") + assert(defined(invoker.ld), "clang_toolchain() must specify a \"ld\" value") + assert(defined(invoker.toolchain_cpu), + "clang_toolchain() must specify a \"toolchain_cpu\"") + assert(defined(invoker.toolchain_os), + "clang_toolchain() must specify a \"toolchain_os\"") + + gcc_toolchain(target_name) { + is_clang = true + + forward_variables_from(invoker, + [ + "cc", + "cxx", + "ld", + "ar", + "strip", + "toolchain_cpu", + "toolchain_os", + "use_gold", + ]) + } +} + +gcc_toolchain("target") { + cc = "${toolprefix}gcc" + cxx = "${toolprefix}g++" + ar = "${toolprefix}ar" + ld = cxx + strip = "${toolprefix}strip" + + toolchain_cpu = target_cpu + toolchain_os = target_os + is_clang = false +} + +clang_toolchain("clang_target") { + cc = "${toolprefix}clang" + cxx = "${toolprefix}clang++" + ld = cxx + ar = "${toolprefix}ar" + strip = "${toolprefix}strip" + + toolchain_cpu = target_cpu + toolchain_os = target_os +} + +gcc_toolchain("gcc_host") { + cc = "gcc" + cxx = "g++" + ar = "ar" + ld = cxx + strip = "strip" + + toolchain_cpu = host_cpu + toolchain_os = host_os + is_clang = false +} + +clang_toolchain("clang_host") { + cc = "clang" + cxx = "clang++" + ld = cxx + ar = "ar" + strip = "strip" + + toolchain_cpu = host_cpu + toolchain_os = host_os +} diff --git a/kernel/LICENSE b/kernel/LICENSE new file mode 100644 index 000000000..8580f02bb --- /dev/null +++ b/kernel/LICENSE @@ -0,0 +1,21 @@ +Copyright 2016 The Fuchsia Authors +Copyright (c) 2008-2015 Travis Geiselbrecht + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/kernel/app/BUILD.gn b/kernel/app/BUILD.gn new file mode 100644 index 000000000..3fe949e2c --- /dev/null +++ b/kernel/app/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("app") { + sources = [ + "app.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/app/app.c b/kernel/app/app.c new file mode 100644 index 000000000..bbacbe44e --- /dev/null +++ b/kernel/app/app.c @@ -0,0 +1,55 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +extern const struct app_descriptor __start_apps[] __WEAK; +extern const struct app_descriptor __stop_apps[] __WEAK; + +static void start_app(const struct app_descriptor *app); + +/* one time setup */ +void apps_init(void) +{ + const struct app_descriptor *app; + + /* call all the init routines */ + for (app = __start_apps; app != __stop_apps; app++) { + if (app->init) + app->init(app); + } + + /* start any that want to start on boot */ + for (app = __start_apps; app != __stop_apps; app++) { + if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) { + start_app(app); + } + } +} + +static int app_thread_entry(void *arg) +{ + const struct app_descriptor *app = (const struct app_descriptor *)arg; + + app->entry(app, NULL); + + return 0; +} + +static void start_app(const struct app_descriptor *app) +{ + uint32_t stack_size = (app->flags & APP_FLAG_CUSTOM_STACK_SIZE) ? app->stack_size : DEFAULT_STACK_SIZE; + + printf("starting app %s\n", app->name); + thread_t *t = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, stack_size); + thread_detach(t); + thread_resume(t); +} + diff --git a/kernel/app/inetsrv/BUILD.gn b/kernel/app/inetsrv/BUILD.gn new file mode 100644 index 000000000..74e922042 --- /dev/null +++ b/kernel/app/inetsrv/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("inetsrv") { + sources = [ + "inetsrv.c", + "inetsrv.h", + ] + deps = [ + "//kernel/lib/libc", + "//kernel/lib/minip", + "//kernel/lib/tftp", + "//third_party/lib/cksum", + ] +} diff --git a/kernel/app/inetsrv/inetsrv.c b/kernel/app/inetsrv/inetsrv.c new file mode 100644 index 000000000..256188f80 --- /dev/null +++ b/kernel/app/inetsrv/inetsrv.c @@ -0,0 +1,223 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inetsrv.h" + +static int chargen_worker(void *socket) +{ + uint64_t count = 0; + tcp_socket_t *s = socket; + + /* enough buffer to hold an entire defacto chargen sequences */ +#define CHARGEN_BUFSIZE (0x5f * 0x5f) // 9025 bytes + + uint8_t *buf = malloc(CHARGEN_BUFSIZE); + if (!buf) + return ERR_NO_MEMORY; + + /* generate the sequence */ + uint8_t c = '!'; + for (size_t i = 0; i < CHARGEN_BUFSIZE; i++) { + buf[i] = c++; + if (c == 0x7f) + c = ' '; + } + + lk_time_t t = current_time(); + for (;;) { + ssize_t ret = tcp_write(s, buf, CHARGEN_BUFSIZE); + //TRACEF("tcp_write returns %d\n", ret); + if (ret < 0) + break; + + count += ret; + } + t = current_time() - t; + + TRACEF("chargen worker exiting, wrote %llu bytes in %u msecs (%llu bytes/sec)\n", + count, (uint32_t)t, count * 1000 / t); + free(buf); + tcp_close(s); + + return 0; +} + +static int chargen_server(void *arg) +{ + status_t err; + tcp_socket_t *listen_socket; + + err = tcp_open_listen(&listen_socket, 19); + if (err < 0) { + TRACEF("error opening chargen listen socket\n"); + return -1; + } + + for (;;) { + tcp_socket_t *accept_socket; + + err = tcp_accept(listen_socket, &accept_socket); + TRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket); + if (err < 0) { + TRACEF("error accepting socket, retrying\n"); + continue; + } + + TRACEF("starting chargen worker\n"); + thread_detach_and_resume(thread_create("chargen_worker", &chargen_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + } +} + +static int discard_worker(void *socket) +{ + uint64_t count = 0; + uint32_t crc = 0; + tcp_socket_t *s = socket; + +#define DISCARD_BUFSIZE 1024 + + uint8_t *buf = malloc(DISCARD_BUFSIZE); + if (!buf) { + TRACEF("error allocating buffer\n"); + } + + lk_time_t t = current_time(); + for (;;) { + ssize_t ret = tcp_read(s, buf, DISCARD_BUFSIZE); + if (ret <= 0) + break; + + crc = crc32(crc, buf, ret); + + count += ret; + } + t = current_time() - t; + + TRACEF("discard worker exiting, read %llu bytes in %u msecs (%llu bytes/sec), crc32 0x%x\n", + count, (uint32_t)t, count * 1000 / t, crc); + tcp_close(s); + + free(buf); + + return 0; +} + +static int discard_server(void *arg) +{ + status_t err; + tcp_socket_t *listen_socket; + + err = tcp_open_listen(&listen_socket, 9); + if (err < 0) { + TRACEF("error opening discard listen socket\n"); + return -1; + } + + for (;;) { + tcp_socket_t *accept_socket; + + err = tcp_accept(listen_socket, &accept_socket); + TRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket); + if (err < 0) { + TRACEF("error accepting socket, retrying\n"); + continue; + } + + TRACEF("starting discard worker\n"); + thread_detach_and_resume(thread_create("discard_worker", &discard_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + } +} + +static int echo_worker(void *socket) +{ + tcp_socket_t *s = socket; + +#define ECHO_BUFSIZE 1024 + + uint8_t *buf = malloc(ECHO_BUFSIZE); + if (!buf) { + TRACEF("error allocating buffer\n"); + return ERR_NO_MEMORY; + } + + for (;;) { + ssize_t ret = tcp_read(s, buf, sizeof(buf)); + if (ret <= 0) + break; + + tcp_write(s, buf, ret); + if (ret <= 0) + break; + } + + TRACEF("echo worker exiting\n"); + tcp_close(s); + free(buf); + + return 0; +} + +static int echo_server(void *arg) +{ + status_t err; + tcp_socket_t *listen_socket; + + err = tcp_open_listen(&listen_socket, 7); + if (err < 0) { + TRACEF("error opening echo listen socket\n"); + return -1; + } + + for (;;) { + tcp_socket_t *accept_socket; + + err = tcp_accept(listen_socket, &accept_socket); + TRACEF("tcp_accept returns returns %d, handle %p\n", err, accept_socket); + if (err < 0) { + TRACEF("error accepting socket, retrying\n"); + continue; + } + + TRACEF("starting echo worker\n"); + thread_detach_and_resume(thread_create("echo_worker", &echo_worker, accept_socket, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + } +} + +static void inetsrv_init(const struct app_descriptor *app) +{ +} + +static void inetsrv_entry(const struct app_descriptor *app, void *args) +{ + /* XXX wait for the stack to initialize */ + + printf("starting internet servers\n"); + + thread_detach_and_resume(thread_create("chargen", &chargen_server, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("discard", &discard_server, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("echo", &echo_server, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + tftp_server_init(NULL); +} + +APP_START(inetsrv) +.init = inetsrv_init, + .entry = inetsrv_entry, + .flags = 0, + APP_END diff --git a/kernel/app/inetsrv/inetsrv.h b/kernel/app/inetsrv/inetsrv.h new file mode 100644 index 000000000..1b8a12206 --- /dev/null +++ b/kernel/app/inetsrv/inetsrv.h @@ -0,0 +1,9 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + diff --git a/kernel/app/inetsrv/rules.mk b/kernel/app/inetsrv/rules.mk new file mode 100644 index 000000000..de68f1bf3 --- /dev/null +++ b/kernel/app/inetsrv/rules.mk @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/inetsrv.c \ + + +MODULE_DEPS := \ + lib/cksum \ + lib/minip \ + lib/tftp \ + +include make/module.mk diff --git a/kernel/app/pcitests/BUILD.gn b/kernel/app/pcitests/BUILD.gn new file mode 100644 index 000000000..f221f3562 --- /dev/null +++ b/kernel/app/pcitests/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("pci_tests") { + sources = [ + "pci_tests.c", + ] +} diff --git a/kernel/app/pcitests/pci_tests.c b/kernel/app/pcitests/pci_tests.c new file mode 100644 index 000000000..eaf57b537 --- /dev/null +++ b/kernel/app/pcitests/pci_tests.c @@ -0,0 +1,245 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WITH_LIB_CONSOLE) +#include + +/* + * enumerates pci devices + */ +static void pci_list(void) +{ + pci_location_t state; + uint16_t device_id, vendor_id; + uint8_t header_type; + uint8_t base_class, sub_class, interface; + int busses = 0, devices = 0, lines = 0, devfn, ret; + int c; + + printf("Scanning...\n"); + + for (state.bus = 0; state.bus <= pci_get_last_bus(); state.bus++) { + busses++; + + for (devfn = 0; devfn < 256; devfn++) { + state.dev_fn = devfn; + + ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id); + if (ret != _PCI_SUCCESSFUL) goto error; + + ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id); + if (ret != _PCI_SUCCESSFUL) goto error; + + ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type); + if (ret != _PCI_SUCCESSFUL) goto error; + + ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_BASE, &base_class); + if (ret != _PCI_SUCCESSFUL) goto error; + + ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_SUB, &sub_class); + if (ret != _PCI_SUCCESSFUL) goto error; + + ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_INTR, &interface); + if (ret != _PCI_SUCCESSFUL) goto error; + + if (vendor_id != 0xffff) { + printf("%02x:%02x vendor_id=%04x device_id=%04x, header_type=%02x " + "base_class=%02x, sub_class=%02x, interface=%02x\n", state.bus, state.dev_fn, + vendor_id, device_id, header_type, base_class, sub_class, interface); + devices++; + lines++; + } + + if (~header_type & PCI_HEADER_TYPE_MULTI_FN) { + // this is not a multi-function device, so advance to the next device + devfn |= 7; + } + + if (lines == 23) { + printf("... press any key to continue, q to quit ..."); + while ((c = getchar()) < 0); + printf("\n"); + lines = 0; + + if (c == 'q' || c == 'Q') goto quit; + } + } + } + + printf("... done. Scanned %d busses, %d device/functions\n", busses, devices); +quit: + return; + +error: + printf("Error while reading PCI config space: %02x\n", ret); +} + +/* + * a somewhat fugly pci config space examine/modify command. this should probably + * be broken up a bit. + */ +static int pci_config(int argc, const cmd_args *argv) +{ + pci_location_t loc; + pci_config_t config; + uint32_t offset; + unsigned int i; + int ret; + + if (argc < 5) { + return -1; + } + + if (!strcmp(argv[2].str, "dump")) { + loc.bus = atoui(argv[3].str); + loc.dev_fn = atoui(argv[4].str); + + for (i=0; i < sizeof(pci_config_t); i++) { + ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i); + if (ret != _PCI_SUCCESSFUL) goto error; + } + + printf("Device at %02x:%02x vendor id=%04x device id=%04x\n", loc.bus, + loc.dev_fn, config.vendor_id, config.device_id); + printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n", + config.command, config.status, config.program_interface, + config.sub_class, config.base_class); + + for (i=0; i < 6; i+=2) { + printf("bar%d=%08x bar%d=%08x\n", i, config.base_addresses[i], + i+1, config.base_addresses[i+1]); + } + } else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) { + if (argc != 6) { + return -1; + } + + loc.bus = atoui(argv[3].str); + loc.dev_fn = atoui(argv[4].str); + offset = atoui(argv[5].str); + + switch (argv[2].str[1]) { + case 'b': { + uint8_t value; + ret = pci_read_config_byte(&loc, offset, &value); + if (ret != _PCI_SUCCESSFUL) goto error; + + printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value); + } + break; + + case 'h': { + uint16_t value; + ret = pci_read_config_half(&loc, offset, &value); + if (ret != _PCI_SUCCESSFUL) goto error; + + printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value); + } + break; + + case 'w': { + uint32_t value; + ret = pci_read_config_word(&loc, offset, &value); + if (ret != _PCI_SUCCESSFUL) goto error; + + printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value); + } + break; + } + } else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) { + if (argc != 7) { + return -1; + } + + loc.bus = atoui(argv[3].str); + loc.dev_fn = atoui(argv[4].str); + offset = atoui(argv[5].str); + + switch (argv[2].str[1]) { + case 'b': { + uint8_t value = atoui(argv[6].str); + ret = pci_write_config_byte(&loc, offset, value); + if (ret != _PCI_SUCCESSFUL) goto error; + + printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value); + } + break; + + case 'h': { + uint16_t value = atoui(argv[6].str); + ret = pci_write_config_half(&loc, offset, value); + if (ret != _PCI_SUCCESSFUL) goto error; + + printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value); + } + break; + + case 'w': { + uint32_t value = atoui(argv[6].str); + ret = pci_write_config_word(&loc, offset, value); + if (ret != _PCI_SUCCESSFUL) goto error; + + printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value); + } + break; + } + } else { + return -1; + } + + return 0; + +error: + printf("Error while reading PCI config space: %02x\n", ret); + return -2; +} + +static int pci_cmd(int argc, const cmd_args *argv) +{ + if (argc < 2) { + printf("pci commands:\n"); +usage: + printf("%s list\n", argv[0].str); + printf("%s config dump \n", argv[0].str); + printf("%s config \n", argv[0].str); + printf("%s config \n", argv[0].str); + goto out; + } + + if (!strcmp(argv[1].str, "list")) { + pci_list(); + } else if (!strcmp(argv[1].str, "config")) { + if (pci_config(argc, argv)) { + goto usage; + } + } else { + goto usage; + } + +out: + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("pci", "pci toolbox", &pci_cmd) +STATIC_COMMAND_END(pcitests); + +#endif + +APP_START(pcitests) +APP_END + diff --git a/kernel/app/pcitests/rules.mk b/kernel/app/pcitests/rules.mk new file mode 100644 index 000000000..fe05f9584 --- /dev/null +++ b/kernel/app/pcitests/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/pci_tests.c + +include make/module.mk diff --git a/kernel/app/rules.mk b/kernel/app/rules.mk new file mode 100644 index 000000000..6b096daf7 --- /dev/null +++ b/kernel/app/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/app.c + +include make/module.mk diff --git a/kernel/app/shell/BUILD.gn b/kernel/app/shell/BUILD.gn new file mode 100644 index 000000000..9ad9a835a --- /dev/null +++ b/kernel/app/shell/BUILD.gn @@ -0,0 +1,31 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_shell") { + if (enable_shell) { + defines = [ "WITH_APP_SHELL=1" ] + } else { + defines = [ "WITH_APP_SHELL=0" ] + } +} + +config("_shell_config") { + visibility = [ ":*" ] + configs = [ ":enable_shell" ] +} + +module("shell") { + public_configs = [ ":_shell_config" ] + sources = [ + "shell.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/app/shell/rules.mk b/kernel/app/shell/rules.mk new file mode 100644 index 000000000..cb6814e9e --- /dev/null +++ b/kernel/app/shell/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/console + +MODULE_SRCS += \ + $(LOCAL_DIR)/shell.c + +include make/module.mk diff --git a/kernel/app/shell/shell.c b/kernel/app/shell/shell.c new file mode 100644 index 000000000..0d3a9ce7b --- /dev/null +++ b/kernel/app/shell/shell.c @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +static void shell_init(const struct app_descriptor *app) +{ + console_init(); +} + +static void shell_entry(const struct app_descriptor *app, void *args) +{ + console_start(); +} + +APP_START(shell) +.init = shell_init, + .entry = shell_entry, + APP_END + diff --git a/kernel/app/stringtests/BUILD.gn b/kernel/app/stringtests/BUILD.gn new file mode 100644 index 000000000..9f187307d --- /dev/null +++ b/kernel/app/stringtests/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("stringtests") { + sources = [ + "string_tests.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/app/stringtests/rules.mk b/kernel/app/stringtests/rules.mk new file mode 100644 index 000000000..a053b8bcf --- /dev/null +++ b/kernel/app/stringtests/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/string_tests.c \ + +# put arch local .S files here if developing memcpy/memmove + +include make/module.mk diff --git a/kernel/app/stringtests/string_tests.c b/kernel/app/stringtests/string_tests.c new file mode 100644 index 000000000..bb64a9fe1 --- /dev/null +++ b/kernel/app/stringtests/string_tests.c @@ -0,0 +1,345 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +static uint8_t *src; +static uint8_t *dst; + +static uint8_t *src2; +static uint8_t *dst2; + +#define BUFFER_SIZE (2*1024*1024) +#define ITERATIONS (256*1024*1024 / BUFFER_SIZE) // enough iterations to have to copy/set 256MB of memory + +#if 1 +static inline void *mymemcpy(void *dst, const void *src, size_t len) { return memcpy(dst, src, len); } +static inline void *mymemset(void *dst, int c, size_t len) { return memset(dst, c, len); } +#else +// if we're testing our own memcpy, use this +extern void *mymemcpy(void *dst, const void *src, size_t len); +extern void *mymemset(void *dst, int c, size_t len); +#endif + +/* reference implementations of memmove/memcpy */ +typedef long word; + +#define lsize sizeof(word) +#define lmask (lsize - 1) + +static void *c_memmove(void *dest, void const *src, size_t count) +{ + char *d = (char *)dest; + const char *s = (const char *)src; + int len; + + if (count == 0 || dest == src) + return dest; + + if ((long)d < (long)s) { + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count < lsize)) + len = count; // copy the rest of the buffer with the byte mover + else + len = lsize - ((long)d & lmask); // move the ptrs up to a word boundary + + count -= len; + for (; len > 0; len--) + *d++ = *s++; + } + for (len = count / lsize; len > 0; len--) { + *(word *)d = *(word *)s; + d += lsize; + s += lsize; + } + for (len = count & lmask; len > 0; len--) + *d++ = *s++; + } else { + d += count; + s += count; + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count <= lsize)) + len = count; + else + len = ((long)d & lmask); + + count -= len; + for (; len > 0; len--) + *--d = *--s; + } + for (len = count / lsize; len > 0; len--) { + d -= lsize; + s -= lsize; + *(word *)d = *(word *)s; + } + for (len = count & lmask; len > 0; len--) + *--d = *--s; + } + + return dest; +} + +static void *c_memset(void *s, int c, size_t count) +{ + char *xs = (char *) s; + size_t len = (-(size_t)s) & lmask; + word cc = c & 0xff; + + if ( count > len ) { + count -= len; + cc |= cc << 8; + cc |= cc << 16; + if (sizeof(word) == 8) + cc |= (uint64_t)cc << 32; // should be optimized out on 32 bit machines + + // write to non-aligned memory byte-wise + for ( ; len > 0; len-- ) + *xs++ = c; + + // write to aligned memory dword-wise + for ( len = count / lsize; len > 0; len-- ) { + *((word *)xs) = (word)cc; + xs += lsize; + } + + count &= lmask; + } + + // write remaining bytes + for ( ; count > 0; count-- ) + *xs++ = c; + + return s; +} + +static void *null_memcpy(void *dst, const void *src, size_t len) +{ + return dst; +} + +static lk_time_t bench_memcpy_routine(void *memcpy_routine(void *, const void *, size_t), size_t srcalign, size_t dstalign) +{ + int i; + lk_time_t t0; + + t0 = current_time(); + for (i=0; i < ITERATIONS; i++) { + memcpy_routine(dst + dstalign, src + srcalign, BUFFER_SIZE); + } + return current_time() - t0; +} + +static void bench_memcpy(void) +{ + lk_time_t null, c, libc, mine; + size_t srcalign, dstalign; + + printf("memcpy speed test\n"); + thread_sleep(200); // let the debug string clear the serial port + + for (srcalign = 0; srcalign < 64; ) { + for (dstalign = 0; dstalign < 64; ) { + + null = bench_memcpy_routine(&null_memcpy, srcalign, dstalign); + c = bench_memcpy_routine(&c_memmove, srcalign, dstalign); + libc = bench_memcpy_routine(&memcpy, srcalign, dstalign); + mine = bench_memcpy_routine(&mymemcpy, srcalign, dstalign); + + printf("srcalign %zu, dstalign %zu: ", srcalign, dstalign); + printf(" null memcpy %u msecs\n", null); + printf("c memcpy %u msecs, %llu bytes/sec; ", c, (uint64_t)BUFFER_SIZE * ITERATIONS * 1000ULL / c); + printf("libc memcpy %u msecs, %llu bytes/sec; ", libc, (uint64_t)BUFFER_SIZE * ITERATIONS * 1000ULL / libc); + printf("my memcpy %u msecs, %llu bytes/sec; ", mine, (uint64_t)BUFFER_SIZE * ITERATIONS * 1000ULL / mine); + printf("\n"); + + if (dstalign < 8) + dstalign++; + else + dstalign <<= 1; + } + if (srcalign < 8) + srcalign++; + else + srcalign <<= 1; + } +} + +static void fillbuf(void *ptr, size_t len, uint32_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + ((char *)ptr)[i] = seed; + seed *= 0x1234567; + } +} + +static void validate_memcpy(void) +{ + size_t srcalign, dstalign, size; + const size_t maxsize = 256; + + printf("testing memcpy for correctness\n"); + + /* + * do the simple tests to make sure that memcpy doesn't color outside + * the lines for all alignment cases + */ + for (srcalign = 0; srcalign < 64; srcalign++) { + printf("srcalign %zu\n", srcalign); + for (dstalign = 0; dstalign < 64; dstalign++) { + //printf("\tdstalign %zu\n", dstalign); + for (size = 0; size < maxsize; size++) { + + //printf("srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size); + + fillbuf(src, maxsize * 2, 567); + fillbuf(src2, maxsize * 2, 567); + fillbuf(dst, maxsize * 2, 123514); + fillbuf(dst2, maxsize * 2, 123514); + + c_memmove(dst + dstalign, src + srcalign, size); + memcpy(dst2 + dstalign, src2 + srcalign, size); + + int comp = memcmp(dst, dst2, maxsize * 2); + if (comp != 0) { + printf("error! srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size); + } + } + } + } +} + +static lk_time_t bench_memset_routine(void *memset_routine(void *, int, size_t), size_t dstalign, size_t len) +{ + int i; + lk_time_t t0; + + t0 = current_time(); + for (i=0; i < ITERATIONS; i++) { + memset_routine(dst + dstalign, 0, len); + } + return current_time() - t0; +} + +static void bench_memset(void) +{ + lk_time_t c, libc, mine; + size_t dstalign; + + printf("memset speed test\n"); + thread_sleep(200); // let the debug string clear the serial port + + for (dstalign = 0; dstalign < 64; dstalign++) { + + c = bench_memset_routine(&c_memset, dstalign, BUFFER_SIZE); + libc = bench_memset_routine(&memset, dstalign, BUFFER_SIZE); + mine = bench_memset_routine(&mymemset, dstalign, BUFFER_SIZE); + + printf("dstalign %zu: ", dstalign); + printf("c memset %u msecs, %llu bytes/sec; ", c, (uint64_t)BUFFER_SIZE * ITERATIONS * 1000ULL / c); + printf("libc memset %u msecs, %llu bytes/sec; ", libc, (uint64_t)BUFFER_SIZE * ITERATIONS * 1000ULL / libc); + printf("my memset %u msecs, %llu bytes/sec; ", mine, (uint64_t)BUFFER_SIZE * ITERATIONS * 1000ULL / mine); + printf("\n"); + } +} + +static void validate_memset(void) +{ + size_t dstalign, size; + int c; + const size_t maxsize = 256; + + printf("testing memset for correctness\n"); + + for (dstalign = 0; dstalign < 64; dstalign++) { + printf("align %zd\n", dstalign); + for (size = 0; size < maxsize; size++) { + for (c = -1; c < 257; c++) { + + fillbuf(dst, maxsize * 2, 123514); + fillbuf(dst2, maxsize * 2, 123514); + + c_memset(dst + dstalign, c, size); + memset(dst2 + dstalign, c, size); + + int comp = memcmp(dst, dst2, maxsize * 2); + if (comp != 0) { + printf("error! align %zu, c 0x%hhx, size %zu\n", dstalign, c, size); + } + } + } + } +} + +#if defined(WITH_LIB_CONSOLE) +#include + +static int string_tests(int argc, const cmd_args *argv) +{ + src = memalign(64, BUFFER_SIZE + 256); + dst = memalign(64, BUFFER_SIZE + 256); + src2 = memalign(64, BUFFER_SIZE + 256); + dst2 = memalign(64, BUFFER_SIZE + 256); + + printf("src %p, dst %p\n", src, dst); + printf("src2 %p, dst2 %p\n", src2, dst2); + + if (!src || !dst || !src2 || !dst2) { + printf("failed to allocate all the buffers\n"); + goto out; + } + + if (argc < 3) { + printf("not enough arguments:\n"); +usage: + printf("%s validate \n", argv[0].str); + printf("%s bench \n", argv[0].str); + goto out; + } + + if (!strcmp(argv[1].str, "validate")) { + if (!strcmp(argv[2].str, "memcpy")) { + validate_memcpy(); + } else if (!strcmp(argv[2].str, "memset")) { + validate_memset(); + } + } else if (!strcmp(argv[1].str, "bench")) { + if (!strcmp(argv[2].str, "memcpy")) { + bench_memcpy(); + } else if (!strcmp(argv[2].str, "memset")) { + bench_memset(); + } + } else { + goto usage; + } + +out: + free(src); + free(dst); + free(src2); + free(dst2); + + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("string", "memcpy tests", &string_tests) +STATIC_COMMAND_END(stringtests); + +#endif + +APP_START(stringtests) +APP_END + diff --git a/kernel/app/tests/BUILD.gn b/kernel/app/tests/BUILD.gn new file mode 100644 index 000000000..29d4122d0 --- /dev/null +++ b/kernel/app/tests/BUILD.gn @@ -0,0 +1,52 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("tests") { + configs += [ "//kernel/kernel:enable_vm" ] + cflags = [ + "-Wno-format", + "-fno-builtin", + ] + include_dirs = [ "include" ] + public = [ + "include/app/tests.h", + ] + sources = [ + "arena_tests.cpp", + "auto_call_tests.cpp", + "benchmarks.c", + "cache_tests.c", + "clock_tests.c", + "fibo.c", + "float.c", + "float_instructions.S", + "float_test_vec.c", + "forward_tests.cpp", + "hash_tests.cpp", + "list_tests.cpp", + "mem_tests.c", + "port_tests.c", + "printf_tests.c", + "ref_call_counter.cpp", + "ref_call_counter.h", + "ref_counted_tests.cpp", + "ref_ptr_tests.cpp", + "sync_ipi_tests.c", + "tests.c", + "thread_tests.c", + "unique_ptr_tests.cpp", + "unittests.c", + "vm_tests.cpp", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/crypto", + "//kernel/lib/libc", + "//kernel/lib/unittest", + "//kernel/lib/utils", + "//third_party/lib/safeint", + ] +} diff --git a/kernel/app/tests/arena_tests.cpp b/kernel/app/tests/arena_tests.cpp new file mode 100644 index 000000000..df692bf45 --- /dev/null +++ b/kernel/app/tests/arena_tests.cpp @@ -0,0 +1,68 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#include + +static int arena_dtor_count = 0; + +struct ArenaFoo { + char ff; + int xx, yy, zz; + + ArenaFoo(int x, int y, int z) : ff(0), xx(x), yy(y), zz(z) {} + ~ArenaFoo() { ++arena_dtor_count; } +}; + + +extern "C" int arena_tests(int argc, const cmd_args* argv) +{ + bool all_ok = true; + + utils::TypedArena arena; + arena.Init("arena_tests", 1000); + + const int count = 30; + + for (int times = 0; times != 5; ++times) { + ArenaFoo* afp[count] = {0}; + + for (int ix = 0; ix != count; ++ix) { + afp[ix] = arena.New(17, 5, ix + 100); + EXPECT_TRUE(afp[ix] != nullptr, ""); + } + + arena.Delete(afp[3]); + arena.Delete(afp[4]); + arena.Delete(afp[5]); + afp[3] = afp[4] = afp[5] = nullptr; + + afp[4] = arena.New(17, 5, 104); + + for (int ix = 0; ix != count; ++ix) { + if (!afp[ix]) continue; + + EXPECT_EQ(17, afp[ix]->xx, ""); + EXPECT_EQ(5, afp[ix]->yy, ""); + EXPECT_EQ(ix + 100, afp[ix]->zz, ""); + + arena.Delete(afp[ix]); + } + + EXPECT_EQ((count + 1) * (times + 1), arena_dtor_count, ""); + + // Leak a few objects. + for (int ix = 0; ix != 7; ++ix) { + auto leak = arena.New(2121, 77, 55); + EXPECT_TRUE(leak != nullptr, ""); + } + } + + printf("arena tests : %s\n", all_ok ? "ok" : "failed"); + return 0; +} diff --git a/kernel/app/tests/auto_call_tests.cpp b/kernel/app/tests/auto_call_tests.cpp new file mode 100644 index 000000000..85d1b4aa8 --- /dev/null +++ b/kernel/app/tests/auto_call_tests.cpp @@ -0,0 +1,85 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include + +static volatile int test_func_count; + +__NO_INLINE static void test_func() +{ + test_func_count++; +} + +int auto_call_tests(int argc, const cmd_args *argv) +{ +// extern int foo(); +// int a; +// +// auto ac = MakeAutoCall([&](){ a = 1; }); +// auto ac2 = MakeAutoCall(foo); +// +// auto func = [&](){ a = 2; }; +// AutoCall ac3(func); +// AutoCall ac4(&foo); +// +// // abort the call +// ac2.cancel(); + + BEGIN_TEST; + + // mark as volatile to make sure it generates code + volatile int a; + + // call a lambda + { + a = 0; + auto ac = utils::MakeAutoCall([&](){ a++; }); + EXPECT_EQ(a, 0, "autocall hasn't run"); + } + EXPECT_EQ(a, 1, "autocall has run"); + + { + a = 0; + auto ac = utils::MakeAutoCall([&](){ a++; }); + EXPECT_EQ(a, 0, "autocall hasn't run"); + + ac.cancel(); + EXPECT_EQ(a, 0, "autocall still hasn't run"); + + ac.call(); + EXPECT_EQ(a, 0, "autocall still hasn't run"); + } + EXPECT_EQ(a, 0, "autocall still hasn't run"); + + { + a = 0; + auto ac = utils::MakeAutoCall([&](){ a++; }); + EXPECT_EQ(a, 0, "autocall hasn't run"); + + ac.call(); + EXPECT_EQ(a, 1, "autocall should have run\n"); + + ac.cancel(); + EXPECT_EQ(a, 1, "autocall ran only once\n"); + } + EXPECT_EQ(a, 1, "autocall ran only once\n"); + + // call a regular function + { + test_func_count = 0; + auto ac = utils::MakeAutoCall(&test_func); + EXPECT_EQ(test_func_count, 0, "autocall hasn't run"); + } + EXPECT_EQ(test_func_count, 1, "autocall has run"); + + END_TEST; + + return 0; +} + diff --git a/kernel/app/tests/benchmarks.c b/kernel/app/tests/benchmarks.c new file mode 100644 index 000000000..60114303d --- /dev/null +++ b/kernel/app/tests/benchmarks.c @@ -0,0 +1,240 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const size_t BUFSIZE = (1024*1024); +const uint ITER = 1024; + +__NO_INLINE static void bench_set_overhead(void) +{ + uint32_t *buf = malloc(BUFSIZE); + + uint count = arch_cycle_count(); + for (uint i = 0; i < ITER; i++) { + __asm__ volatile(""); + } + count = arch_cycle_count() - count; + + printf("took %u cycles overhead to loop %u times\n", + count, ITER); + + free(buf); +} + +__NO_INLINE static void bench_memset(void) +{ + void *buf = malloc(BUFSIZE); + + uint count = arch_cycle_count(); + for (uint i = 0; i < ITER; i++) { + memset(buf, 0, BUFSIZE); + } + count = arch_cycle_count() - count; + + uint64_t bytes_cycle = (BUFSIZE * ITER * 1000ULL) / count; + printf("took %u cycles to memset a buffer of size %u %d times (%u bytes), %llu.%03llu bytes/cycle\n", + count, BUFSIZE, ITER, BUFSIZE * ITER, bytes_cycle / 1000, bytes_cycle % 1000); + + free(buf); +} + +#define bench_cset(type) \ +__NO_INLINE static void bench_cset_##type(void) \ +{ \ + type *buf = malloc(BUFSIZE); \ + \ + uint count = arch_cycle_count(); \ + for (uint i = 0; i < ITER; i++) { \ + for (uint j = 0; j < BUFSIZE / sizeof(*buf); j++) { \ + buf[j] = 0; \ + } \ + } \ + count = arch_cycle_count() - count; \ + \ + uint64_t bytes_cycle = (BUFSIZE * ITER * 1000ULL) / count; \ + printf("took %u cycles to manually clear a buffer using wordsize %d of size %u %d times (%u bytes), %llu.%03llu bytes/cycle\n", \ + count, sizeof(*buf), BUFSIZE, ITER, BUFSIZE * ITER, bytes_cycle / 1000, bytes_cycle % 1000); \ + \ + free(buf); \ +} + +bench_cset(uint8_t) +bench_cset(uint16_t) +bench_cset(uint32_t) +bench_cset(uint64_t) + +__NO_INLINE static void bench_cset_wide(void) +{ + uint32_t *buf = malloc(BUFSIZE); + + uint count = arch_cycle_count(); + for (uint i = 0; i < ITER; i++) { + for (uint j = 0; j < BUFSIZE / sizeof(*buf) / 8; j++) { + buf[j*8] = 0; + buf[j*8+1] = 0; + buf[j*8+2] = 0; + buf[j*8+3] = 0; + buf[j*8+4] = 0; + buf[j*8+5] = 0; + buf[j*8+6] = 0; + buf[j*8+7] = 0; + } + } + count = arch_cycle_count() - count; + + uint64_t bytes_cycle = (BUFSIZE * ITER * 1000ULL) / count; + printf("took %u cycles to manually clear a buffer of size %u %d times 8 words at a time (%u bytes), %llu.%03llu bytes/cycle\n", + count, BUFSIZE, ITER, BUFSIZE * ITER, bytes_cycle / 1000, bytes_cycle % 1000); + + free(buf); +} + +__NO_INLINE static void bench_memcpy(void) +{ + uint8_t *buf = calloc(1, BUFSIZE); + + uint count = arch_cycle_count(); + for (uint i = 0; i < ITER; i++) { + memcpy(buf, buf + BUFSIZE / 2, BUFSIZE / 2); + } + count = arch_cycle_count() - count; + + uint64_t bytes_cycle = (BUFSIZE / 2 * ITER * 1000ULL) / count; + printf("took %u cycles to memcpy a buffer of size %u %d times (%u source bytes), %llu.%03llu source bytes/cycle\n", + count, BUFSIZE / 2, ITER, BUFSIZE / 2 * ITER, bytes_cycle / 1000, bytes_cycle % 1000); + + free(buf); +} + +#if ARCH_ARM +__NO_INLINE static void arm_bench_cset_stm(void) +{ + uint32_t *buf = malloc(BUFSIZE); + + uint count = arch_cycle_count(); + for (uint i = 0; i < ITER; i++) { + for (uint j = 0; j < BUFSIZE / sizeof(*buf) / 8; j++) { + __asm__ volatile( + "stm %0, {r0-r7};" + :: "r" (&buf[j*8]) + ); + } + } + count = arch_cycle_count() - count; + + uint64_t bytes_cycle = (BUFSIZE * ITER * 1000ULL) / count; + printf("took %u cycles to manually clear a buffer of size %u %d times 8 words at a time using stm (%u bytes), %llu.%03llu bytes/cycle\n", + count, BUFSIZE, ITER, BUFSIZE * ITER, bytes_cycle / 1000, bytes_cycle % 1000); + + free(buf); +} + +#if (__CORTEX_M >= 0x03) +__NO_INLINE static void arm_bench_multi_issue(void) +{ + uint32_t cycles; + uint32_t a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0; +#define ITER 1000000 + uint count = ITER; + cycles = arch_cycle_count(); + while (count--) { + __asm__ volatile (""); + __asm__ volatile ("add %0, %0, %0" : "=r" (a) : "r" (a)); + __asm__ volatile ("add %0, %0, %0" : "=r" (b) : "r" (b)); + __asm__ volatile ("and %0, %0, %0" : "=r" (c) : "r" (c)); + __asm__ volatile ("mov %0, %0" : "=r" (d) : "r" (d)); + __asm__ volatile ("orr %0, %0, %0" : "=r" (e) : "r" (e)); + __asm__ volatile ("add %0, %0, %0" : "=r" (f) : "r" (f)); + __asm__ volatile ("and %0, %0, %0" : "=r" (g) : "r" (g)); + __asm__ volatile ("mov %0, %0" : "=r" (h) : "r" (h)); + } + cycles = arch_cycle_count() - cycles; + + uint64_t bytes_cycle = (cycles * 1000ULL) / ITER; + printf("took %u cycles to issue 8 integer ops (%llu.%03llu cycles/iteration)\n", cycles, bytes_cycle / 1000, bytes_cycle % 1000); +#undef ITER +} +#endif // __CORTEX_M +#endif // ARCH_ARM + +#if WITH_LIB_LIBM && !WITH_NO_FP +#include + +__NO_INLINE static void bench_sincos(void) +{ + printf("touching the floating point unit\n"); + __UNUSED volatile double _hole = sin(0); + + uint count = arch_cycle_count(); + __UNUSED double a = sin(2.0); + count = arch_cycle_count() - count; + printf("took %u cycles for sin()\n", count); + + count = arch_cycle_count(); + a = cos(2.0); + count = arch_cycle_count() - count; + printf("took %u cycles for cos()\n", count); + + count = arch_cycle_count(); + a = sinf(2.0); + count = arch_cycle_count() - count; + printf("took %u cycles for sinf()\n", count); + + count = arch_cycle_count(); + a = cosf(2.0); + count = arch_cycle_count() - count; + printf("took %u cycles for cosf()\n", count); + + count = arch_cycle_count(); + a = sqrt(1234567.0); + count = arch_cycle_count() - count; + printf("took %u cycles for sqrt()\n", count); + + count = arch_cycle_count(); + a = sqrtf(1234567.0f); + count = arch_cycle_count() - count; + printf("took %u cycles for sqrtf()\n", count); +} + +#endif // WITH_LIB_LIBM + +void benchmarks(void) +{ + bench_set_overhead(); + bench_memset(); + bench_memcpy(); + + bench_cset_uint8_t(); + bench_cset_uint16_t(); + bench_cset_uint32_t(); + bench_cset_uint64_t(); + bench_cset_wide(); + +#if ARCH_ARM + arm_bench_cset_stm(); + +#if (__CORTEX_M >= 0x03) + arm_bench_multi_issue(); +#endif +#endif +#if WITH_LIB_LIBM && !WITH_NO_FP + bench_sincos(); +#endif +} + diff --git a/kernel/app/tests/cache_tests.c b/kernel/app/tests/cache_tests.c new file mode 100644 index 000000000..8a37349b3 --- /dev/null +++ b/kernel/app/tests/cache_tests.c @@ -0,0 +1,73 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if ARM_WITH_CACHE + +#include +#include +#include +#include +#include +#include +#include +#include + +static void bench_cache(size_t bufsize, uint8_t *buf) +{ + lk_bigtime_t t; + bool do_free; + + if (buf == 0) { + buf = memalign(PAGE_SIZE, bufsize); + do_free = true; + } else { + do_free = false; + } + + printf("buf %p, size %zu\n", buf, bufsize); + + if (!buf) + return; + + t = current_time_hires(); + arch_clean_cache_range((addr_t)buf, bufsize); + t = current_time_hires() - t; + + printf("took %llu usecs to clean %d bytes (cold)\n", t, bufsize); + + memset(buf, 0x99, bufsize); + + t = current_time_hires(); + arch_clean_cache_range((addr_t)buf, bufsize); + t = current_time_hires() - t; + + if (do_free) + free(buf); + + printf("took %llu usecs to clean %d bytes (hot)\n", t, bufsize); +} + +static int cache_tests(int argc, const cmd_args *argv) +{ + uint8_t *buf; + buf = (uint8_t *)((argc > 1) ? argv[1].u : 0UL); + + printf("testing cache\n"); + + bench_cache(2*1024, buf); + bench_cache(64*1024, buf); + bench_cache(256*1024, buf); + bench_cache(1*1024*1024, buf); + bench_cache(8*1024*1024, buf); + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("cache_tests", "test/bench the cpu cache", &cache_tests) +STATIC_COMMAND_END(cache_tests); + +#endif diff --git a/kernel/app/tests/clock_tests.c b/kernel/app/tests/clock_tests.c new file mode 100644 index 000000000..b10f4e8e9 --- /dev/null +++ b/kernel/app/tests/clock_tests.c @@ -0,0 +1,101 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void clock_tests(void) +{ + uint32_t c; + lk_time_t t; + lk_bigtime_t t2; + + thread_sleep(100); + c = arch_cycle_count(); + t = current_time(); + c = arch_cycle_count() - c; + printf("%u cycles per current_time()\n", c); + + thread_sleep(100); + c = arch_cycle_count(); + t2 = current_time_hires(); + c = arch_cycle_count() - c; + printf("%u cycles per current_time_hires()\n", c); + + printf("making sure time never goes backwards\n"); + { + printf("testing current_time()\n"); + lk_time_t start = current_time(); + lk_time_t last = start; + for (;;) { + t = current_time(); + //printf("%lu %lu\n", last, t); + if (TIME_LT(t, last)) { + printf("WARNING: time ran backwards: %lu < %lu\n", t, last); + last = t; + continue; + } + last = t; + if (last - start > 5000) + break; + } + } + { + printf("testing current_time_hires()\n"); + lk_bigtime_t start = current_time_hires(); + lk_bigtime_t last = start; + for (;;) { + t2 = current_time_hires(); + //printf("%llu %llu\n", last, t2); + if (t2 < last) { + printf("WARNING: time ran backwards: %llu < %llu\n", t2, last); + last = t2; + continue; + } + last = t2; + if (last - start > 5000000) + break; + } + } + + printf("making sure current_time() and current_time_hires() are always the same base\n"); + { + lk_time_t start = current_time(); + for (;;) { + t = current_time(); + t2 = current_time_hires(); + if (t > ((t2 + 500) / 1000)) { + printf("WARNING: current_time() ahead of current_time_hires() %lu %llu\n", t, t2); + } + if (t - start > 5000) + break; + } + } + + printf("counting to 5, in one second intervals\n"); + for (int i = 0; i < 5; i++) { + thread_sleep(1000); + printf("%d\n", i + 1); + } + + printf("measuring cpu clock against current_time_hires()\n"); + for (int i = 0; i < 5; i++) { + uint cycles = arch_cycle_count(); + lk_bigtime_t start = current_time_hires(); + while ((current_time_hires() - start) < 1000000) + ; + cycles = arch_cycle_count() - cycles; + printf("%u cycles per second\n", cycles); + } +} diff --git a/kernel/app/tests/fibo.c b/kernel/app/tests/fibo.c new file mode 100644 index 000000000..f02199701 --- /dev/null +++ b/kernel/app/tests/fibo.c @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int fibo_thread(void *argv) +{ + long fibo = (intptr_t)argv; + + thread_t *t[2]; + + if (fibo == 0) + return 0; + if (fibo == 1) + return 1; + + char name[32]; + snprintf(name, sizeof(name), "fibo %lu", fibo - 1); + t[0] = thread_create(name, &fibo_thread, (void *)(fibo - 1), DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + if (!t[0]) { + printf("error creating thread for fibo %d\n", fibo-1); + return 0; + } + snprintf(name, sizeof(name), "fibo %lu", fibo - 2); + t[1] = thread_create(name, &fibo_thread, (void *)(fibo - 2), DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + if (!t[1]) { + printf("error creating thread for fibo %d\n", fibo-2); + thread_resume(t[0]); + thread_join(t[0], NULL, INFINITE_TIME); + return 0; + } + + thread_resume(t[0]); + thread_resume(t[1]); + + int retcode0, retcode1; + + thread_join(t[0], &retcode0, INFINITE_TIME); + thread_join(t[1], &retcode1, INFINITE_TIME); + + return retcode0 + retcode1; +} + +int fibo(int argc, const cmd_args *argv) +{ + + if (argc < 2) { + printf("not enough args\n"); + return -1; + } + + lk_time_t tim = current_time(); + + thread_t *t = thread_create("fibo", &fibo_thread, (void *)(uintptr_t)argv[1].u, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t); + + int retcode; + thread_join(t, &retcode, INFINITE_TIME); + + tim = current_time() - tim; + + printf("fibo %d\n", retcode); + printf("took %u msecs to calculate\n", tim); + + return NO_ERROR; +} diff --git a/kernel/app/tests/float.c b/kernel/app/tests/float.c new file mode 100644 index 000000000..620e593fd --- /dev/null +++ b/kernel/app/tests/float.c @@ -0,0 +1,101 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if !WITH_NO_FP || ARM_WITH_VFP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void float_vfp_arm_instruction_test(void); +extern void float_vfp_thumb_instruction_test(void); +extern void float_neon_arm_instruction_test(void); +extern void float_neon_thumb_instruction_test(void); + +/* optimize this function to cause it to try to use a lot of registers */ +__OPTIMIZE("O3") +static int float_thread(void *arg) +{ + double *val = arg; + uint i, j; + + double a[16]; + + /* do a bunch of work with floating point to test context switching */ + a[0] = *val; + for (i = 1; i < countof(a); i++) { + a[i] = a[i-1] * 1.01; + } + + for (i = 0; i < 1000000; i++) { + a[0] += i; + for (j = 1; j < countof(a); j++) { + a[j] += a[j-1] * 0.00001; + } + } + + *val = a[countof(a) - 1]; + + return 1; +} + +#if ARCH_ARM +static void arm_float_instruction_trap_test(void) +{ + printf("testing fpu trap\n"); + +#if !ARM_ONLY_THUMB + float_vfp_arm_instruction_test(); + float_neon_arm_instruction_test(); +#endif + float_vfp_thumb_instruction_test(); + float_neon_thumb_instruction_test(); + + printf("if we got here, we probably decoded everything properly\n"); +} +#endif + +static void float_tests(void) +{ + printf("floating point test:\n"); + + /* test lazy fpu load on separate thread */ + thread_t *t[8]; + double val[countof(t)]; + + printf("creating %u floating point threads\n", countof(t)); + for (uint i = 0; i < countof(t); i++) { + val[i] = i; + t[i] = thread_create("float", &float_thread, &val[i], LOW_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t[i]); + } + + int res; + for (uint i = 0; i < countof(t); i++) { + thread_join(t[i], &res, INFINITE_TIME); + printf("float thread %u returns %d, val %f\n", i, res, val[i]); + } + printf("the above values should be close\n"); + +#if ARCH_ARM + /* test all the instruction traps */ + arm_float_instruction_trap_test(); +#endif +} + +STATIC_COMMAND_START +STATIC_COMMAND("float_tests", "floating point test", (console_cmd)&float_tests) +STATIC_COMMAND_END(float_tests); + +#endif diff --git a/kernel/app/tests/float_instructions.S b/kernel/app/tests/float_instructions.S new file mode 100644 index 000000000..16f938b37 --- /dev/null +++ b/kernel/app/tests/float_instructions.S @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#if ARM_WITH_VFP + +.fpu neon +.syntax unified + +.macro disable, scratchreg + vmrs \scratchreg, fpexc + bic \scratchreg, #(1<<30) + vmsr fpexc, \scratchreg +.endm + +.macro vfp_instructions + disable r12 + vadd.f32 s0, s0, s0 + + disable r12 + vadd.f64 d0, d0, d0 + + disable r12 + ldr r0, =float_test_scratch + vldr s0, [r0] +.endm + +.macro neon_instructions + disable r12 + vadd.f32 q0, q0, q0 + + disable r12 + ldr r0, =float_test_scratch + vld1.f32 { q0 }, [r0] + + disable r12 + vmov s0, r0 +.endm + +#if !ARM_ONLY_THUMB +.arm + +FUNCTION(float_vfp_arm_instruction_test) + vfp_instructions + bx lr + +FUNCTION(float_neon_arm_instruction_test) + neon_instructions + bx lr +#endif + +.thumb + +FUNCTION(float_vfp_thumb_instruction_test) + vfp_instructions + bx lr + +FUNCTION(float_neon_thumb_instruction_test) + neon_instructions + bx lr + +.data +LOCAL_DATA(float_test_scratch) + .word 0 + .word 0 + +#endif // ARM_WITH_VFP diff --git a/kernel/app/tests/float_print_host.c b/kernel/app/tests/float_print_host.c new file mode 100644 index 000000000..c1b21f49b --- /dev/null +++ b/kernel/app/tests/float_print_host.c @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#define countof(a) (sizeof(a) / sizeof((a)[0])) + +#include "float_test_vec.c" + +int main(void) +{ + printf("floating point printf tests\n"); + + for (size_t i = 0; i < float_test_vec_size; i++) { + PRINT_FLOAT; + } + + return 0; +} + diff --git a/kernel/app/tests/float_test_vec.c b/kernel/app/tests/float_test_vec.c new file mode 100644 index 000000000..364aa5908 --- /dev/null +++ b/kernel/app/tests/float_test_vec.c @@ -0,0 +1,66 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +union double_int { + double d; + uint64_t i; +}; + +static const union double_int float_test_vec[] = { + { .d = -2.0 }, + { .d = -1.0 }, + { .d = -0.5 }, + { .d = -0.0 }, + { .d = 0.0 }, + { .d = 0.01 }, + { .d = 0.1 }, + { .d = 0.2 }, + { .d = 0.25 }, + { .d = 0.5 }, + { .d = 0.75 }, + { .d = 1.0 }, + { .d = 2.0 }, + { .d = 3.0 }, + { .d = 10.0 }, + { .d = 100.0 }, + { .d = 123456.0 }, + { .d = -123456.0 }, + { .d = 546.5645644531f }, + { .d = -546.5645644531f }, + { .d = 0.12345 }, + { .d = 0.0000012345 }, + { .d = 0.0000019999 }, + { .d = 0.0000015 }, + { .i = 0x4005bf0a8b145649ULL }, // e + { .i = 0x400921fb54442d18ULL }, // pi + { .i = 0x43f0000000000000ULL }, // 2^64 + { .i = 0x7fefffffffffffffULL }, // largest normalized + { .i = 0x0010000000000000ULL }, // least positive normalized + { .i = 0x0000000000000001ULL }, // smallest possible denorm + { .i = 0x000fffffffffffffULL }, // largest possible denorm + { .i = 0x7ff0000000000001ULL }, // smallest SNAn + { .i = 0x7ff7ffffffffffffULL }, // largest SNAn + { .i = 0x7ff8000000000000ULL }, // smallest QNAn + { .i = 0x7fffffffffffffffULL }, // largest QNAn + { .i = 0xfff0000000000000ULL }, // -infinity + { .i = 0x7ff0000000000000ULL }, // +infinity +}; + +#define countof(a) (sizeof(a) / sizeof((a)[0])) +static const unsigned int float_test_vec_size = countof(float_test_vec); + +#define PRINT_FLOAT \ + printf("0x%016llx %f %F %a %A\n", \ + float_test_vec[i], \ + *(const double *)&float_test_vec[i], \ + *(const double *)&float_test_vec[i], \ + *(const double *)&float_test_vec[i], \ + *(const double *)&float_test_vec[i]) + diff --git a/kernel/app/tests/forward_tests.cpp b/kernel/app/tests/forward_tests.cpp new file mode 100644 index 000000000..ba9384022 --- /dev/null +++ b/kernel/app/tests/forward_tests.cpp @@ -0,0 +1,94 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +enum Category { CAT_LVALUE, CAT_RVALUE }; + +int category(const int& arg) { return CAT_LVALUE; } + +int category(int&& arg) { return CAT_RVALUE; } + +template +int passing(T&& t) +{ + return category(t); +} + +template +int moving(T&& t) +{ + return category(utils::move(t)); +} + +template +int forwarding(T&& t) +{ + return category(utils::forward(t)); +} + +template +int forward_copy(T&& t) +{ + return category(utils::forward(t)); +} + +struct A { + A(int&& n) : category(CAT_RVALUE) {} + A(int& n) : category(CAT_LVALUE) {} + int category; +}; + +template +T make_object(U&& u) +{ + return T(utils::forward(u)); +} + +extern "C" int forward_tests(int argc, const cmd_args* argv) +{ + bool all_ok = true; + + int val = 42; + int& ref = val; + const int& cref = val; + + EXPECT_EQ(CAT_LVALUE, passing(42), ""); + EXPECT_EQ(CAT_LVALUE, passing(val), ""); + EXPECT_EQ(CAT_LVALUE, passing(ref), ""); + EXPECT_EQ(CAT_LVALUE, passing(cref), ""); + EXPECT_EQ(CAT_LVALUE, passing(val + 1), ""); + + EXPECT_EQ(CAT_RVALUE, moving(42), ""); + EXPECT_EQ(CAT_RVALUE, moving(val), ""); + EXPECT_EQ(CAT_RVALUE, moving(ref), ""); + EXPECT_EQ(CAT_LVALUE, moving(cref), ""); + EXPECT_EQ(CAT_RVALUE, moving(val + 1), ""); + + EXPECT_EQ(CAT_RVALUE, forwarding(42), ""); + EXPECT_EQ(CAT_LVALUE, forwarding(val), ""); + EXPECT_EQ(CAT_LVALUE, forwarding(ref), ""); + EXPECT_EQ(CAT_LVALUE, forward_copy(cref), ""); + EXPECT_EQ(CAT_RVALUE, forwarding(val + 1), ""); + + EXPECT_EQ(CAT_LVALUE, forward_copy(42), ""); + EXPECT_EQ(CAT_LVALUE, forward_copy(val), ""); + EXPECT_EQ(CAT_LVALUE, forward_copy(ref), ""); + EXPECT_EQ(CAT_LVALUE, forward_copy(cref), ""); + EXPECT_EQ(CAT_LVALUE, forward_copy(val + 1), ""); + + auto a1 = make_object(42); + auto a2 = make_object(val); + + EXPECT_EQ(CAT_RVALUE, a1.category, ""); + EXPECT_EQ(CAT_LVALUE, a2.category, ""); + + if (all_ok) printf("all tests passed\n"); + return 0; +} diff --git a/kernel/app/tests/hash_tests.cpp b/kernel/app/tests/hash_tests.cpp new file mode 100644 index 000000000..a2e99acb8 --- /dev/null +++ b/kernel/app/tests/hash_tests.cpp @@ -0,0 +1,80 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +class FooHash { +public: + FooHash(int value) : key_(-1), value_(value), next_(nullptr) {} + int get_value() const { return value_; } + + int get_key() const { return key_; } + void set_key(int key) { key_ = key; } + + void list_set_next(FooHash* foo) { next_ = foo; } + const FooHash* list_next() const { return next_; } + FooHash* list_next() { return next_; } + +private: + int key_; + int value_; + FooHash* next_; +}; + +struct FooHashFn { + size_t operator()(int key) const + { + auto s = reinterpret_cast(&key); + auto p = s; + size_t h = 1; + for (int ix = 0; ix != sizeof(int); ++p, ++ix) { + h = ((h << 4) * 17) + *p; + } + return h; + } +}; + +int GetHashTableKey(FooHash* fh) { return fh->get_key(); } + +void SetHashTableKey(FooHash* fh, int key) { fh->set_key(key); } + +extern "C" int hash_tests(int argc, const cmd_args* argv) +{ + bool all_ok = true; + + utils::HashTable foo_table; + + const size_t count = 5; + int keys[count] = {50, 500, 5000, 50000, 500000}; + FooHash foo[count] = {1, 2, 3, 4, 5}; + + for (size_t ix = 0; ix != count; ++ix) { + foo_table.add(keys[ix], &foo[ix]); + } + + EXPECT_EQ(count, foo_table.size(), ""); + + int sum = 0; + foo_table.for_each([&sum](FooHash* f) { + sum += f->get_value(); + }); + + EXPECT_EQ(15, sum, ""); + + auto item = foo_table.remove(5000); + EXPECT_EQ(3, item->get_value(), ""); + EXPECT_EQ(count - 1, foo_table.size(), ""); + + EXPECT_TRUE(nullptr == foo_table.remove(5000), ""); + + foo_table.clear(); + EXPECT_EQ(0U, foo_table.size(), ""); + + printf("hash tests : %s\n", all_ok ? "ok" : "failed"); + return 0; +} diff --git a/kernel/app/tests/include/app/tests.h b/kernel/app/tests/include/app/tests.h new file mode 100644 index 000000000..aef407793 --- /dev/null +++ b/kernel/app/tests/include/app/tests.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __APP_TESTS_H +#define __APP_TESTS_H + +#include +#include + +__BEGIN_CDECLS + +int thread_tests(void); +int port_tests(void); +void printf_tests(void); +void clock_tests(void); +void benchmarks(void); +int fibo(int argc, const cmd_args *argv); +int spinner(int argc, const cmd_args *argv); +int ref_counted_tests(int argc, const cmd_args *argv); +int ref_ptr_tests(int argc, const cmd_args *argv); +int unique_ptr_tests(int argc, const cmd_args *argv); +int forward_tests(int argc, const cmd_args *argv); +int list_tests(int argc, const cmd_args *argv); +int hash_tests(int argc, const cmd_args *argv); +int vm_tests(int argc, const cmd_args *argv); +int auto_call_tests(int argc, const cmd_args *argv); +int sync_ipi_tests(int argc, const cmd_args *argv); +int arena_tests(int argc, const cmd_args *argv); +void unittests(void); + +__END_CDECLS + +#endif + diff --git a/kernel/app/tests/list_tests.cpp b/kernel/app/tests/list_tests.cpp new file mode 100644 index 000000000..da17dc4be --- /dev/null +++ b/kernel/app/tests/list_tests.cpp @@ -0,0 +1,279 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +class TestValue { +public: + TestValue(int val) : val_(val) {} + int value() const { return val_; } + +private: + int val_; +}; + +class Foo : public TestValue { +public: + Foo(int val) : TestValue(val), next_(nullptr) {} + + void list_set_next(Foo* foo) { next_ = foo; } + const Foo* list_next() const { return next_; } + Foo* list_next() { return next_; } + +private: + Foo* next_; +}; + +class Bar : public TestValue { +public: + Bar(int val) : TestValue(val), next_l1_(nullptr), next_l2_(nullptr) {} + + struct List1Traits { + static Bar* next(Bar* bar) { return bar->next_l1_; } + static const Bar* next(const Bar* bar) { return bar->next_l1_; } + static void set_next(Bar* bar, Bar* next) { bar->next_l1_ = next; } + }; + + struct List2Traits { + static Bar* next(Bar* bar) { return bar->next_l2_; } + static const Bar* next(const Bar* bar) { return bar->next_l2_; } + static void set_next(Bar* bar, Bar* next) { bar->next_l2_ = next; } + }; + +private: + Bar* next_l1_; + Bar* next_l2_; +}; + +class Baz : public TestValue { +public: + Baz(int val) : TestValue(val), next_(nullptr), prev_(nullptr) {} + + Baz* list_prev() { return prev_; } + const Baz* list_prev() const { return prev_; } + + Baz* list_next() { return next_; } + const Baz* list_next() const { return next_; } + + void list_set_prev(Baz* prev) { prev_ = prev; } + void list_set_next(Baz* next) { next_ = next; } + +private: + Baz* next_; + Baz* prev_; +}; + +static bool all_ok = true; + +static void singly_linked_one_list_test() { + const size_t count = 7; + int prev = 0; + + Foo foo[count] = {1, 2, 3, 4, 5, 6, 7}; + + utils::SinglyLinkedList slist; + + EXPECT_EQ(0U, slist.size_slow(), ""); + + for (int ix = 0; ix != count; ++ix) { + slist.push_front(&foo[ix]); + } + + EXPECT_EQ(count, slist.size_slow(), ""); + + Foo* found = utils::find_if(&slist, [](Foo* f) { + return f->value() == 4; + }); + + EXPECT_TRUE(found == &foo[3], ""); + + int sum = 0; + utils::for_each(&slist, [&sum](Foo* f) { sum += f->value(); }); + + EXPECT_EQ(28, sum, ""); + + prev = 8; + for (int ix = 0; ix != count; ++ix) { + Foo* foo = slist.pop_front(); + EXPECT_TRUE(prev > foo->value(), ""); + prev = foo->value(); + } + + EXPECT_TRUE(slist.is_empty(), ""); + + slist.push_front(&foo[2]); + slist.push_front(&foo[3]); + slist.push_front(&foo[4]); + + found = utils::pop_if(&slist, [](Foo* f) { + return f->value() == 4; + }); + + EXPECT_EQ(2U, slist.size_slow(), ""); + + found = utils::pop_if(&slist, [](Foo* f) { + return f->value() == 3; + }); + + EXPECT_EQ(1U, slist.size_slow(), ""); + + slist.clear(); +} + +void singly_linked_two_lists_test() { + const size_t count = 7; + int prev = 0; + + Bar bar[count] = {7, 6, 5, 4, 3, 2, 1}; + + utils::SinglyLinkedList slist1; + utils::SinglyLinkedList slist2; + + for (int ix = 0; ix != count; ++ix) { + slist1.push_front(&bar[ix]); + slist2.push_front(&bar[ix]); + } + + EXPECT_EQ(count, slist1.size_slow(), ""); + EXPECT_EQ(count, slist2.size_slow(), ""); + + prev = 0; + for (int ix = 0; ix != count; ++ix) { + Bar* bar = slist1.pop_front(); + EXPECT_TRUE(prev < bar->value(), ""); + prev = bar->value(); + } + + prev = 0; + for (int ix = 0; ix != count; ++ix) { + Bar* bar = slist2.pop_front(); + EXPECT_TRUE(prev < bar->value(), ""); + prev = bar->value(); + } + + EXPECT_TRUE(slist1.is_empty(), ""); + EXPECT_TRUE(slist2.is_empty(), ""); +} + +void doubly_linked_one_list_test() { + const size_t count = 5; + + Baz baz[count] = {1, 2, 3, 4, 5}; + + utils::DoublyLinkedList dlist; + + EXPECT_EQ(0U, dlist.size_slow(), ""); + EXPECT_TRUE(dlist.pop_front() == nullptr, ""); + EXPECT_TRUE(dlist.pop_back() == nullptr, ""); + + dlist.push_front(&baz[0]); + EXPECT_EQ(1U, dlist.size_slow(), ""); + + EXPECT_TRUE(dlist.pop_back() == &baz[0], ""); + EXPECT_EQ(0U, dlist.size_slow(), ""); + EXPECT_TRUE(dlist.is_empty(), ""); + + dlist.push_back(&baz[1]); + EXPECT_EQ(1U, dlist.size_slow(), ""); + + EXPECT_TRUE(dlist.pop_front() == &baz[1], ""); + EXPECT_EQ(0U, dlist.size_slow(), ""); + EXPECT_TRUE(dlist.is_empty(), ""); + + dlist.push_back(&baz[0]); + dlist.push_back(&baz[1]); + EXPECT_TRUE(dlist.pop_front() == &baz[0], ""); + EXPECT_TRUE(dlist.pop_front() == &baz[1], ""); + EXPECT_EQ(0U, dlist.size_slow(), ""); + + for (int ix = 0; ix != count; ++ix) { + dlist.push_front(&baz[ix]); + } + EXPECT_EQ(5U, dlist.size_slow(), ""); + + int sum = 0; + for_each(&dlist, [&sum](Baz* b) { sum += b->value(); }); + EXPECT_EQ(15, sum, ""); + + int prev = 6; + for (int ix = 0; ix != count; ++ix) { + auto baz = dlist.pop_front(); + EXPECT_TRUE(prev > baz->value(), ""); + prev = baz->value(); + } + + EXPECT_EQ(0U, dlist.size_slow(), ""); + + for (int ix = 0; ix != count; ++ix) { + dlist.push_back(&baz[ix]); + } + EXPECT_EQ(5U, dlist.size_slow(), ""); + + prev = 6; + for (int ix = 0; ix != count; ++ix) { + auto baz = dlist.pop_back(); + EXPECT_TRUE(prev > baz->value(), ""); + prev = baz->value(); + } + + EXPECT_EQ(0U, dlist.size_slow(), ""); + + dlist.push_back(&baz[2]); + dlist.push_back(&baz[3]); + dlist.remove(dlist.first()); + + EXPECT_EQ(1U, dlist.size_slow(), ""); + EXPECT_TRUE(dlist.first() == &baz[3], ""); + + dlist.remove(dlist.first()); + EXPECT_EQ(0U, dlist.size_slow(), ""); + EXPECT_TRUE(dlist.first() == nullptr, ""); + + dlist.clear(); +} + +void list_move_test() +{ + const size_t count = 7; + Foo foo[count] = {1, 2, 3, 4, 5, 6, 7}; + utils::SinglyLinkedList slist_src; + + for (int ix = 0; ix != count; ++ix) { + slist_src.push_front(&foo[ix]); + } + + utils::SinglyLinkedList slist_dst; + utils::move_if(&slist_src, &slist_dst, [](Foo* foo) { + return ((foo->value() % 2) == 0); + }); + + EXPECT_EQ(3U, slist_dst.size_slow(), ""); + EXPECT_EQ(4U, slist_src.size_slow(), ""); + + utils::move_if(&slist_dst, &slist_src, [](Foo* foo) { + return ((foo->value() % 2) == 0); + }); + + EXPECT_EQ(0U, slist_dst.size_slow(), ""); + EXPECT_EQ(7U, slist_src.size_slow(), ""); + + slist_src.clear(); +} + +extern "C" int list_tests(int argc, const cmd_args* argv) +{ + singly_linked_one_list_test(); + singly_linked_two_lists_test(); + doubly_linked_one_list_test(); + list_move_test(); + + printf("list tests : %s\n", all_ok ? "ok" : "failed"); + return 0; +} diff --git a/kernel/app/tests/mem_tests.c b/kernel/app/tests/mem_tests.c new file mode 100644 index 000000000..a451242ec --- /dev/null +++ b/kernel/app/tests/mem_tests.c @@ -0,0 +1,227 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_KERNEL_VM +#include +#endif + +static void mem_test_fail(void *ptr, uint32_t should, uint32_t is) +{ + printf("ERROR at %p: should be 0x%x, is 0x%x\n", ptr, should, is); + + ptr = (void *)ROUNDDOWN((uintptr_t)ptr, 64); + hexdump(ptr, 128); +} + +static status_t do_pattern_test(void *ptr, size_t len, uint32_t pat) +{ + volatile uint32_t *vbuf32 = ptr; + size_t i; + + printf("\tpattern 0x%08x\n", pat); + for (i = 0; i < len / 4; i++) { + vbuf32[i] = pat; + } + + for (i = 0; i < len / 4; i++) { + if (vbuf32[i] != pat) { + mem_test_fail((void *)&vbuf32[i], pat, vbuf32[i]); + return ERR_GENERIC; + } + } + + return NO_ERROR; +} + +static status_t do_moving_inversion_test(void *ptr, size_t len, uint32_t pat) +{ + volatile uint32_t *vbuf32 = ptr; + size_t i; + + printf("\tpattern 0x%08x\n", pat); + + /* fill memory */ + for (i = 0; i < len / 4; i++) { + vbuf32[i] = pat; + } + + /* from the bottom, walk through each cell, inverting the value */ + //printf("\t\tbottom up invert\n"); + for (i = 0; i < len / 4; i++) { + if (vbuf32[i] != pat) { + mem_test_fail((void *)&vbuf32[i], pat, vbuf32[i]); + return ERR_GENERIC; + } + + vbuf32[i] = ~pat; + } + + /* repeat, walking from top down */ + //printf("\t\ttop down invert\n"); + for (i = len / 4; i > 0; i--) { + if (vbuf32[i-1] != ~pat) { + mem_test_fail((void *)&vbuf32[i-1], ~pat, vbuf32[i-1]); + return ERR_GENERIC; + } + + vbuf32[i-1] = pat; + } + + /* verify that we have the original pattern */ + //printf("\t\tfinal test\n"); + for (i = 0; i < len / 4; i++) { + if (vbuf32[i] != pat) { + mem_test_fail((void *)&vbuf32[i], pat, vbuf32[i]); + return ERR_GENERIC; + } + } + + return NO_ERROR; +} + +static void do_mem_tests(void *ptr, size_t len) +{ + size_t i; + + /* test 1: simple write address to memory, read back */ + printf("test 1: simple address write, read back\n"); + volatile uint32_t *vbuf32 = ptr; + for (i = 0; i < len / 4; i++) { + vbuf32[i] = i; + } + + for (i = 0; i < len / 4; i++) { + if (vbuf32[i] != i) { + mem_test_fail((void *)&vbuf32[i], i, vbuf32[i]); + goto out; + } + } + + /* test 2: write various patterns, read back */ + printf("test 2: write patterns, read back\n"); + + static const uint32_t pat[] = { + 0x0, 0xffffffff, + 0xaaaaaaaa, 0x55555555, + }; + + for (size_t p = 0; p < countof(pat); p++) { + if (do_pattern_test(ptr, len, pat[p]) < 0) + goto out; + } + // shift bits through 32bit word + for (uint32_t p = 1; p != 0; p <<= 1) { + if (do_pattern_test(ptr, len, p) < 0) + goto out; + } + // shift bits through 16bit word, invert top of 32bit + for (uint16_t p = 1; p != 0; p <<= 1) { + if (do_pattern_test(ptr, len, ((~p) << 16) | p) < 0) + goto out; + } + + /* test 3: moving inversion, patterns */ + printf("test 3: moving inversions with patterns\n"); + for (size_t p = 0; p < countof(pat); p++) { + if (do_moving_inversion_test(ptr, len, pat[p]) < 0) + goto out; + + } + // shift bits through 32bit word + for (uint32_t p = 1; p != 0; p <<= 1) { + if (do_moving_inversion_test(ptr, len, p) < 0) + goto out; + } + // shift bits through 16bit word, invert top of 32bit + for (uint16_t p = 1; p != 0; p <<= 1) { + if (do_moving_inversion_test(ptr, len, ((~p) << 16) | p) < 0) + goto out; + } + +out: + printf("done with tests\n"); +} + +static int mem_test(int argc, const cmd_args *argv) +{ + if (argc < 2) { + printf("not enough arguments\n"); +usage: + printf("usage: %s \n", argv[0].str); + printf("usage: %s \n", argv[0].str); + return -1; + } + + if (argc == 2) { + void *ptr; + size_t len = argv[1].u; + +#if WITH_KERNEL_VM + /* rounding up len to the next page */ + len = PAGE_ALIGN(len); + if (len == 0) { + printf("invalid length\n"); + return -1; + } + + /* allocate a region to test in */ + status_t err = vmm_alloc_contiguous(vmm_get_kernel_aspace(), "memtest", len, &ptr, 0, 0, ARCH_MMU_FLAG_UNCACHED); + if (err < 0) { + printf("error %d allocating test region\n", err); + return -1; + } + + paddr_t pa; + pa = vaddr_to_paddr(ptr); + printf("physical address 0x%lx\n", pa); +#else + /* allocate from the heap */ + ptr = malloc(len); + if (!ptr ) { + printf("error allocating test area from heap\n"); + return -1; + } + +#endif + + printf("got buffer at %p of length 0x%lx\n", ptr, len); + + /* run the tests */ + do_mem_tests(ptr, len); + +#if WITH_KERNEL_VM + // XXX free memory region here + printf("NOTE: leaked memory\n"); +#else + free(ptr); +#endif + } else if (argc == 3) { + void *ptr = argv[1].p; + size_t len = argv[2].u; + + /* run the tests */ + do_mem_tests(ptr, len); + } else { + goto usage; + } + + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("mem_test", "test memory", &mem_test) +STATIC_COMMAND_END(mem_tests); diff --git a/kernel/app/tests/port_tests.c b/kernel/app/tests/port_tests.c new file mode 100644 index 000000000..3aa720b18 --- /dev/null +++ b/kernel/app/tests/port_tests.c @@ -0,0 +1,836 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define LOCAL_TRACE 0 + +void *context1 = (void *) 0x53; + +static void dump_port_result(const port_result_t *result) +{ + const port_packet_t *p = &result->packet; + LTRACEF("[%02x %02x %02x %02x %02x %02x %02x %02x]\n", + p->value[0], p->value[1], p->value[2], p->value[3], + p->value[4], p->value[5], p->value[6], p->value[7]); +} + +static int single_thread_basic(void) +{ + port_t w_port; + status_t st = port_create("sh_prt1", PORT_MODE_UNICAST, &w_port); + if (st < 0) { + printf("could not create port, status = %d\n", st); + return __LINE__; + } + + port_t r_port; + st = port_open("sh_prt0", context1, &r_port); + if (st != ERR_NOT_FOUND) { + printf("expected not to find port, status = %d\n", st); + return __LINE__; + } + + st = port_open("sh_prt1", context1, &r_port); + if (st < 0) { + printf("could not open port, status = %d\n", st); + return __LINE__; + } + + port_packet_t packet[3] = { + {{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}}, + {{{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11}}}, + {{{0x33, 0x66, 0x99, 0xcc, 0x33, 0x66, 0x99, 0xcc}}}, + }; + + st = port_write(w_port, &packet[0], 1); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + + port_result_t res = {0}; + + st = port_peek(r_port, &res); + if (st < 0) { + printf("could not peek port, status = %d\n", st); + return __LINE__; + } + if (res.ctx != context1) { + printf("bad context! = %p\n", res.ctx); + return __LINE__; + } + + res.ctx = NULL; + + st = port_read(r_port, 0, &res); + if (st < 0) { + printf("could not read port, status = %d\n", st); + return __LINE__; + } + if (res.ctx != context1) { + printf("bad context! = %p\n", res.ctx); + return __LINE__; + } + + st = port_peek(r_port, &res); + if (st != ERR_NOT_READY) { + printf("expected 'not ready', status = %d\n", st); + return __LINE__; + } + + st = port_read(r_port, 0, &res); + if (st != ERR_TIMED_OUT) { + printf("expected timeout, status = %d\n", st); + return __LINE__; + } + + st = port_write(w_port, &packet[1], 1); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + + st = port_write(w_port, &packet[0], 1); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + + st = port_write(w_port, &packet[2], 1); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + + int expected_count = 3; + while (true) { + st = port_read(r_port, 0, &res); + if (st < 0) + break; + dump_port_result(&res); + --expected_count; + } + + if (expected_count != 0) { + printf("invalid read count = %d\n", expected_count); + return __LINE__; + } + + // port should be empty. should be able to write 8 packets. + expected_count = 8; + while (true) { + st = port_write(w_port, &packet[1], 1); + if (st < 0) + break; + --expected_count; + st = port_write(w_port, &packet[2], 1); + if (st < 0) + break; + --expected_count; + } + + if (expected_count != 0) { + printf("invalid write count = %d\n", expected_count); + return __LINE__; + } + + // LK 'classic' ports return ERR_PARTIAL_WRITE. + if (st != ERR_CHANNEL_CLOSED) { + printf("expected buffer error, status =%d\n", st); + return __LINE__; + } + + // read 3 packets. + for (int ix = 0; ix != 3; ++ix) { + st = port_read(r_port, 0, &res); + if (st < 0) { + printf("could not read port, status = %d\n", st); + return __LINE__; + } + } + + // there are 5 packets, now we add another 3. + st = port_write(w_port, packet, 3); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + + expected_count = 8; + while (true) { + st = port_read(r_port, 0, &res); + if (st < 0) + break; + dump_port_result(&res); + --expected_count; + } + + if (expected_count != 0) { + printf("invalid read count = %d\n", expected_count); + return __LINE__; + } + + // attempt to use the wrong port. + st = port_write(r_port, &packet[1], 1); + if (st != ERR_BAD_HANDLE) { + printf("expected bad handle error, status = %d\n", st); + return __LINE__; + } + + st = port_read(w_port, 0, &res); + if (st != ERR_BAD_HANDLE) { + printf("expected bad handle error, status = %d\n", st); + return __LINE__; + } + + st = port_close(r_port); + if (st < 0) { + printf("could not close read port, status = %d\n", st); + return __LINE__; + } + + st = port_close(w_port); + if (st < 0) { + printf("could not close write port, status = %d\n", st); + return __LINE__; + } + + st = port_close(r_port); + if (st != ERR_BAD_HANDLE) { + printf("expected bad handle error, status = %d\n", st); + return __LINE__; + } + + st = port_close(w_port); + if (st != ERR_BAD_HANDLE) { + printf("expected bad handle error, status = %d\n", st); + return __LINE__; + } + + st = port_destroy(w_port); + if (st < 0) { + printf("could not destroy port, status = %d\n", st); + return __LINE__; + } + + printf("single_thread_basic : ok\n"); + return 0; +} + +static int single_thread_wait(void) +{ + port_t w_port; + status_t st = port_create("sh_prt3", PORT_MODE_UNICAST, &w_port); + if (st < 0) { + printf("could not create port, status = %d\n", st); + return __LINE__; + } + + port_t r_port; + st = port_open("sh_prt3", context1, &r_port); + if (st < 0) { + printf("could not open port, status = %d\n", st); + return __LINE__; + } + + port_packet_t packet = {{{0}}}; + + st = port_wait(r_port, 0); + if (st != ERR_TIMED_OUT) { + printf("expected timeout, status = %d\n", st); + return __LINE__; + } + + st = port_write(w_port, &packet, 1); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + + st = port_wait(r_port, 100); + if (st < 0) { + printf("unexpected end of wait, status = %d\n", st); + return __LINE__; + } + + port_result_t res = {0}; + + st = port_read(r_port, 0, &res); + if (st < 0) { + printf("could not read port, status = %d\n", st); + return __LINE__; + } + + st = port_wait(r_port, 10); + if (st != ERR_TIMED_OUT) { + printf("expected timeout, status = %d\n", st); + return __LINE__; + } + + st = port_close(w_port); + if (st < 0) + return __LINE__; + st = port_destroy(w_port); + if (st < 0) + return __LINE__; + + st = port_wait(r_port, 0); + if (st != ERR_CHANNEL_CLOSED) { + printf("expected close, status = %d\n", st); + return __LINE__; + } + + st = port_close(r_port); + if (st < 0) + return __LINE__; + + printf("single_thread_wait : ok\n"); + return 0; +} + +static int ping_pong_thread(void *arg) +{ + port_t r_port; + status_t st = port_open("ping_port", NULL, &r_port); + if (st < 0) { + printf("thread: could not open port, status = %d\n", st); + return __LINE__; + } + + bool should_dispose_pong_port = true; + port_t w_port; + st = port_create("pong_port", PORT_MODE_UNICAST, &w_port); + if (st == ERR_ALREADY_EXISTS) { + // won the race to create the port. + should_dispose_pong_port = false; + } else if (st < 0) { + printf("thread: could not open port, status = %d\n", st); + return __LINE__; + } + + port_result_t pr; + + // the loop is read-mutate-write until the write port + // is closed by the master thread. + while (true) { + st = port_read(r_port, INFINITE_TIME, &pr); + + if (st == ERR_CHANNEL_CLOSED) { + break; + } else if (st < 0) { + printf("thread: could not read port, status = %d\n", st); + return __LINE__; + } + + pr.packet.value[0]++; + pr.packet.value[5]--; + + st = port_write(w_port, &pr.packet, 1); + if (st < 0) { + printf("thread: could not write port, status = %d\n", st); + return __LINE__; + } + } + + port_close(r_port); + + if (should_dispose_pong_port) { + port_close(w_port); + port_destroy(w_port); + } + + return 0; + +bail: + return __LINE__; +} + +int two_threads_basic(void) +{ + port_t w_port; + status_t st = port_create("ping_port", PORT_MODE_BROADCAST, &w_port); + if (st < 0) { + printf("could not create port, status = %d\n", st); + return __LINE__; + } + + thread_t *t1 = thread_create( + "worker1", &ping_pong_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_t *t2 = thread_create( + "worker2", &ping_pong_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t1); + thread_resume(t2); + + // wait for the pong port to be created, the two threads race to do it. + port_t r_port; + while (true) { + status_t st = port_open("pong_port", NULL, &r_port); + if (st == NO_ERROR) { + break; + } else if (st == ERR_NOT_FOUND) { + thread_sleep(100); + } else { + printf("could not open port, status = %d\n", st); + return __LINE__; + } + } + + // We have two threads listening to the ping port. Which both reply + // on the pong port, so we get two packets in per packet out. + const int passes = 256; + printf("two_threads_basic test, %d passes\n", passes); + + port_packet_t packet_out = {{{0xaf, 0x77, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}}}; + + port_result_t pr; + for (int ix = 0; ix != passes; ++ix) { + const size_t count = 1 + ((unsigned int)rand() % 3); + + for (size_t jx = 0; jx != count; ++jx) { + st = port_write(w_port, &packet_out, 1); + if (st < 0) { + printf("could not write port, status = %d\n", st); + return __LINE__; + } + } + + packet_out.value[0]++; + packet_out.value[5]--; + + for (size_t jx = 0; jx != count * 2; ++jx) { + st = port_read(r_port, INFINITE_TIME, &pr); + if (st < 0) { + printf("could not read port, status = %d\n", st); + return __LINE__; + } + + if ((pr.packet.value[0] != packet_out.value[0]) || + (pr.packet.value[5] != packet_out.value[5])) { + printf("unexpected data in packet, loop %d", ix); + return __LINE__; + } + } + } + + thread_sleep(100); + + // there should be no more packets to read. + st = port_read(r_port, 0, &pr); + if (st != ERR_TIMED_OUT) { + printf("unexpected packet, status = %d\n", st); + return __LINE__; + } + + printf("two_threads_basic master shutdown\n"); + + st = port_close(r_port); + if (st < 0) { + printf("could not close port, status = %d\n", st); + return __LINE__; + } + + st = port_close(w_port); + if (st < 0) { + printf("could not close port, status = %d\n", st); + return __LINE__; + } + + st = port_destroy(w_port); + if (st < 0) { + printf("could not destroy port, status = %d\n", st); + return __LINE__; + } + + int retcode = -1; + thread_join(t1, &retcode, INFINITE_TIME); + if (retcode) + goto fail; + + thread_join(t2, &retcode, INFINITE_TIME); + if (retcode) + goto fail; + + printf("two_threads_basic : ok\n"); + return 0; + +fail: + printf("child thread exited with %d\n", retcode); + return __LINE__; +} + +#define CMD_PORT_CTX ((void*) 0x77) +#define TS1_PORT_CTX ((void*) 0x11) +#define TS2_PORT_CTX ((void*) 0x12) + +typedef enum { + NONE, + ADD_PORT, + QUIT +} action_t; + +status_t send_watcher_cmd(port_t cmd_port, action_t action, port_t port) +{ + size_t count = 1; + port_packet_t pp[2]; + pp[0].value[0] = (char) action; + + if (port) { + count = 2; + pp[1].pvalue = port; + } + return port_write(cmd_port, pp, count); +} + +static int group_watcher_thread(void *arg) +{ + port_t watched[8] = {0}; + status_t st = port_open("grp_ctrl", CMD_PORT_CTX, &watched[0]); + if (st < 0) { + printf("could not open port, status = %d\n", st); + return __LINE__; + } + + size_t count = 1; + port_t group; + int ctx_count = -1; + + while (true) { + st = port_group(watched, count, &group); + if (st < 0) { + printf("could not make group, status = %d\n", st); + return __LINE__; + } + + port_result_t pr; + while (true) { + st = port_read(group, INFINITE_TIME, &pr); + if (st < 0) { + printf("could not read port, status = %d\n", st); + return __LINE__; + } + + if (pr.ctx == CMD_PORT_CTX) { + break; + } else if (pr.ctx == TS1_PORT_CTX) { + ctx_count += 1; + } else if (pr.ctx == TS2_PORT_CTX) { + ctx_count += 2; + } else { + printf("unknown context %p\n", pr.ctx); + return __LINE__; + } + } + + // Either adding a port or exiting; either way close the + // existing group port and create a new one if needed + // at the top of the loop. + st = port_close(group); + if (st <0) { + printf("could not close port, status = %d\n", st); + return __LINE__; + } + + action_t action = pr.packet.value[0]; + + if (action == ADD_PORT) { + // There is a second packet for the "add port" action. + st = port_read(watched[0], 0, &pr); + if (st < 0) { + printf("could not read port, status = %d\n", st); + return __LINE__; + } + watched[count++] = pr.packet.pvalue; + + } else if (action == QUIT) { + break; + } else { + printf("unknown action %d\n", action); + return __LINE__; + } + } + + if (ctx_count != 2) { + printf("unexpected context count %d", ctx_count); + return __LINE__; + } + + for (size_t ix = 0; ix != count; ++ix) { + st = port_close(watched[ix]); + if (st < 0) { + printf("failed to close read port, status = %d\n", st); + return __LINE__; + } + } + + return 0; +} + +static status_t make_port_pair(const char *name, void *ctx, port_t *write, port_t *read) +{ + status_t st = port_create(name, PORT_MODE_UNICAST, write); + if (st < 0) + return st; + return port_open(name, ctx, read); +} + +int group_basic(void) +{ + // we spin a thread that connects to a well known port, then we + // send two ports that it will add to a group port. + port_t cmd_port; + status_t st = port_create("grp_ctrl", PORT_MODE_UNICAST, &cmd_port); + if (st < 0 ) { + printf("could not create port, status = %d\n", st); + return __LINE__; + } + + thread_t *wt = thread_create( + "g_watcher", &group_watcher_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(wt); + + port_t w_test_port1, r_test_port1; + st = make_port_pair("tst_port1", TS1_PORT_CTX, &w_test_port1, &r_test_port1); + if (st < 0) + return __LINE__; + + port_t w_test_port2, r_test_port2; + st = make_port_pair("tst_port2", TS2_PORT_CTX, &w_test_port2, &r_test_port2); + if (st < 0) + return __LINE__; + + st = send_watcher_cmd(cmd_port, ADD_PORT, r_test_port1); + if (st < 0) + return __LINE__; + + st = send_watcher_cmd(cmd_port, ADD_PORT, r_test_port2); + if (st < 0) + return __LINE__; + + thread_sleep(50); + + port_packet_t pp = {{{0}}}; + st = port_write(w_test_port1, &pp, 1); + if (st < 0) + return __LINE__; + + st = port_write(w_test_port2, &pp, 1); + if (st < 0) + return __LINE__; + + st = send_watcher_cmd(cmd_port, QUIT, 0); + if (st < 0) + return __LINE__; + + int retcode = -1; + thread_join(wt, &retcode, INFINITE_TIME); + if (retcode) { + printf("child thread exited with %d\n", retcode); + return __LINE__; + } + + st = port_close(w_test_port1); + if (st < 0) + return __LINE__; + st = port_close(w_test_port2); + if (st < 0) + return __LINE__; + st = port_close(cmd_port); + if (st < 0) + return __LINE__; + st = port_destroy(w_test_port1); + if (st < 0) + return __LINE__; + st = port_destroy(w_test_port2); + if (st < 0) + return __LINE__; + st = port_destroy(cmd_port); + if (st < 0) + return __LINE__; + + printf("group_basic : ok\n"); + return 0; +} + +int group_dynamic(void) +{ + status_t st; + + port_t w_test_port1, r_test_port1; + st = make_port_pair("tst_port1", TS1_PORT_CTX, &w_test_port1, &r_test_port1); + if (st < 0) + return __LINE__; + + port_t w_test_port2, r_test_port2; + st = make_port_pair("tst_port2", TS2_PORT_CTX, &w_test_port2, &r_test_port2); + if (st < 0) + return __LINE__; + + port_t pg; + st = port_group(&r_test_port1, 1, &pg); + if (st < 0) + return __LINE__; + + port_packet_t pkt = {{{ 0 }}}; + st = port_write(w_test_port2, &pkt, 1); + if (st < 0) + return __LINE__; + + port_result_t rslt; + st = port_read(pg, 0, &rslt); + if (st != ERR_TIMED_OUT) + return __LINE__; + + // Attach the port that has been written to to the port group and ensure + // that we can read from it. + st = port_group_add(pg, r_test_port2); + if (st < 0) + return __LINE__; + + st = port_read(pg, 0, &rslt); + if (st < 0) + return __LINE__; + + // Write some data to a port then remove it from the port group and ensure + // that we can't read from it. + st = port_write(w_test_port1, &pkt, 1); + if (st < 0) + return __LINE__; + + st = port_group_remove(pg, r_test_port1); + if (st < 0) + return __LINE__; + + st = port_read(pg, 0, &rslt); + if (st != ERR_TIMED_OUT) + return __LINE__; + + st = port_close(w_test_port1); + if (st < 0) + return __LINE__; + st = port_close(w_test_port2); + if (st < 0) + return __LINE__; + st = port_destroy(w_test_port1); + if (st < 0) + return __LINE__; + st = port_destroy(w_test_port2); + if (st < 0) + return __LINE__; + + printf("group_dynamic : ok\n"); + return 0; +} + +event_t group_waiting_sync_evt; + +static int receive_thread(void *arg) +{ + port_t pg = (port_t)arg; + + // Try to read from an empty port group. When the other thread adds a port + // to this port group, we should wake up and + port_result_t rslt; + status_t st = port_read(pg, 500, &rslt); + if (st == ERR_TIMED_OUT) + return __LINE__; + + event_signal(&group_waiting_sync_evt, true); + + return 0; +} + +/* Test the edge case where a read port with data available is added to a port + * group that has a read-blocked receiver. + */ +int group_waiting(void) +{ + status_t st; + + event_init(&group_waiting_sync_evt, false, EVENT_FLAG_AUTOUNSIGNAL); + + port_t w_test_port1, r_test_port1; + st = make_port_pair("tst_port1", TS1_PORT_CTX, &w_test_port1, &r_test_port1); + if (st < 0) + return __LINE__; + + // Write something to this port group that currently has no receivers. + port_packet_t pkt = {{{ 0 }}}; + st = port_write(w_test_port1, &pkt, 1); + if (st < 0) + return __LINE__; + + // Create an empty port group. + port_t pg; + st = port_group(NULL, 0, &pg); + if (st < 0) + return __LINE__; + + thread_t *t1 = thread_create( + "receiver", + &receive_thread, + (void *)pg, + DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE + ); + + thread_resume(t1); + + // Wait for the other thread to block on the read. + thread_sleep(20); + + // Adding a port that has data available to the port group should wake any + // threads waiting on that port group. + port_group_add(pg, r_test_port1); + + if (event_wait_timeout(&group_waiting_sync_evt, 500) != NO_ERROR) + return __LINE__; + + st = port_close(w_test_port1); + if (st < 0) + return __LINE__; + + st = port_destroy(w_test_port1); + if (st < 0) + return __LINE__; + + return 0; +} + +#define RUN_TEST(t) result = t(); if (result) goto fail + +int port_tests(void) +{ + int result; + int count = 3; + while (count--) { + RUN_TEST(single_thread_basic); + RUN_TEST(single_thread_wait); + RUN_TEST(two_threads_basic); + RUN_TEST(group_basic); + RUN_TEST(group_dynamic); + } + + printf("all tests passed\n"); + return 0; +fail: + printf("test failed at line %d\n", result); + return 1; +} + +#undef RUN_TEST diff --git a/kernel/app/tests/printf_tests.c b/kernel/app/tests/printf_tests.c new file mode 100644 index 000000000..f7c74f43c --- /dev/null +++ b/kernel/app/tests/printf_tests.c @@ -0,0 +1,122 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +#if !WITH_NO_FP +#include "float_test_vec.c" + +static void printf_tests_float(void) +{ + printf("floating point printf tests\n"); + + for (size_t i = 0; i < float_test_vec_size; i++) { + PRINT_FLOAT; + } +} +#endif + +void printf_tests(void) +{ + printf("printf tests\n"); + + printf("numbers:\n"); + printf("int8: %hhd %hhd %hhd\n", -12, 0, 254); + printf("uint8: %hhu %hhu %hhu\n", -12, 0, 254); + printf("int16: %hd %hd %hd\n", -1234, 0, 1234); + printf("uint16:%hu %hu %hu\n", -1234, 0, 1234); + printf("int: %d %d %d\n", -12345678, 0, 12345678); + printf("uint: %u %u %u\n", -12345678, 0, 12345678); + printf("long: %ld %ld %ld\n", -12345678L, 0L, 12345678L); + printf("ulong: %lu %lu %lu\n", -12345678UL, 0UL, 12345678UL); + + printf("longlong: %lli %lli %lli\n", -12345678LL, 0LL, 12345678LL); + printf("ulonglong: %llu %llu %llu\n", -12345678LL, 0LL, 12345678LL); + printf("ssize_t: %zd %zd %zd\n", (ssize_t)-12345678, (ssize_t)0, (ssize_t)12345678); + printf("usize_t: %zu %zu %zu\n", (size_t)-12345678, (size_t)0, (size_t)12345678); + printf("intmax_t: %jd %jd %jd\n", (intmax_t)-12345678, (intmax_t)0, (intmax_t)12345678); + printf("uintmax_t: %ju %ju %ju\n", (uintmax_t)-12345678, (uintmax_t)0, (uintmax_t)12345678); + printf("ptrdiff_t: %td %td %td\n", (ptrdiff_t)-12345678, (ptrdiff_t)0, (ptrdiff_t)12345678); + printf("ptrdiff_t (u): %tu %tu %tu\n", (ptrdiff_t)-12345678, (ptrdiff_t)0, (ptrdiff_t)12345678); + + printf("hex:\n"); + printf("uint8: %hhx %hhx %hhx\n", -12, 0, 254); + printf("uint16:%hx %hx %hx\n", -1234, 0, 1234); + printf("uint: %x %x %x\n", -12345678, 0, 12345678); + printf("ulong: %lx %lx %lx\n", -12345678UL, 0UL, 12345678UL); + printf("ulong: %X %X %X\n", -12345678, 0, 12345678); + printf("ulonglong: %llx %llx %llx\n", -12345678LL, 0LL, 12345678LL); + printf("usize_t: %zx %zx %zx\n", (size_t)-12345678, (size_t)0, (size_t)12345678); + + printf("alt/sign:\n"); + printf("uint: %#x %#X\n", 0xabcdef, 0xabcdef); + printf("int: %+d %+d\n", 12345678, -12345678); + printf("int: % d %+d\n", 12345678, 12345678); + + printf("formatting\n"); + printf("int: a%8da\n", 12345678); + printf("int: a%9da\n", 12345678); + printf("int: a%-9da\n", 12345678); + printf("int: a%10da\n", 12345678); + printf("int: a%-10da\n", 12345678); + printf("int: a%09da\n", 12345678); + printf("int: a%010da\n", 12345678); + printf("int: a%6da\n", 12345678); + + printf("a%1sa\n", "b"); + printf("a%9sa\n", "b"); + printf("a%-9sa\n", "b"); + printf("a%5sa\n", "thisisatest"); + + printf("%03d\n", -2); /* '-02' */ + printf("%0+3d\n", -2); /* '-02' */ + printf("%0+3d\n", 2); /* '+02' */ + printf("%+3d\n", 2); /* ' +2' */ + printf("% 3d\n", -2000); /* '-2000' */ + printf("% 3d\n", 2000); /* ' 2000' */ + printf("%+3d\n", 2000); /* '+2000' */ + printf("%10s\n", "test"); /* ' test' */ + printf("%010s\n", "test"); /* ' test' */ + printf("%-10s\n", "test"); /* 'test ' */ + printf("%-010s\n", "test"); /* 'test ' */ + + int err; + + err = printf("a"); + printf(" returned %d\n", err); + err = printf("ab"); + printf(" returned %d\n", err); + err = printf("abc"); + printf(" returned %d\n", err); + err = printf("abcd"); + printf(" returned %d\n", err); + err = printf("abcde"); + printf(" returned %d\n", err); + err = printf("abcdef"); + printf(" returned %d\n", err); + + /* make sure snprintf terminates at the right spot */ + char buf[32]; + + memset(buf, 0, sizeof(buf)); + err = sprintf(buf, "0123456789abcdef012345678"); + printf("sprintf returns %d\n", err); + hexdump8(buf, sizeof(buf)); + + memset(buf, 0, sizeof(buf)); + err = snprintf(buf, 15, "0123456789abcdef012345678"); + printf("snprintf returns %d\n", err); + hexdump8(buf, sizeof(buf)); + +#if !WITH_NO_FP + printf_tests_float(); +#endif +} + diff --git a/kernel/app/tests/ref_call_counter.cpp b/kernel/app/tests/ref_call_counter.cpp new file mode 100644 index 000000000..e45ce390d --- /dev/null +++ b/kernel/app/tests/ref_call_counter.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "ref_call_counter.h" + +RefCallCounter::RefCallCounter() : add_ref_calls_(0u), release_calls_(0u) {} + +void RefCallCounter::AddRef() { add_ref_calls_++; } +bool RefCallCounter::Release() +{ + release_calls_++; + return false; +} diff --git a/kernel/app/tests/ref_call_counter.h b/kernel/app/tests/ref_call_counter.h new file mode 100644 index 000000000..af84a160e --- /dev/null +++ b/kernel/app/tests/ref_call_counter.h @@ -0,0 +1,24 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +class RefCallCounter { +public: + RefCallCounter(); + + void AddRef(); + bool Release(); + + void Adopt() {} + + int add_ref_calls() const { return add_ref_calls_; } + int release_calls() const { return release_calls_; } + +private: + int add_ref_calls_; + int release_calls_; +}; diff --git a/kernel/app/tests/ref_counted_tests.cpp b/kernel/app/tests/ref_counted_tests.cpp new file mode 100644 index 000000000..c1a2d4561 --- /dev/null +++ b/kernel/app/tests/ref_counted_tests.cpp @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +class DestructionTracker : public utils::RefCounted { +public: + explicit DestructionTracker(bool* destroyed) : destroyed_(destroyed) {} + ~DestructionTracker() { *destroyed_ = true; } + +private: + bool* destroyed_; +}; + +static int inc_and_dec(void* arg) +{ + DestructionTracker* tracker = reinterpret_cast(arg); + for (size_t i = 0u; i < 500; ++i) { + utils::RefPtr ptr(tracker); + } + return 0; +} + +extern "C" int ref_counted_tests(int argc, const cmd_args* argv) +{ + BEGIN_TEST; + + bool destroyed = false; + { + utils::RefPtr ptr = utils::AdoptRef(new DestructionTracker(&destroyed)); + EXPECT_FALSE(destroyed, "should not be destroyed"); + void* arg = reinterpret_cast(ptr.get()); + + thread_t* threads[5]; + threads[0] = thread_create("inc_and_dec thread 0", &inc_and_dec, arg, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE); + threads[1] = thread_create("inc_and_dec thread 1", &inc_and_dec, arg, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE); + threads[2] = thread_create("inc_and_dec thread 2", &inc_and_dec, arg, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE); + threads[3] = thread_create("inc_and_dec thread 3", &inc_and_dec, arg, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE); + threads[4] = thread_create("inc_and_dec thread 4", &inc_and_dec, arg, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE); + for (size_t i = 0u; i < 5u; ++i) thread_resume(threads[i]); + + inc_and_dec(arg); + + for (size_t i = 0u; i < 5u; ++i) thread_join(threads[i], NULL, INFINITE_TIME); + + EXPECT_FALSE(destroyed, "should not be destroyed after inc/dec pairs"); + } + EXPECT_TRUE(destroyed, "should be when RefPtr falls out of scope"); + + printf("all tests done\n"); + END_TEST; +} diff --git a/kernel/app/tests/ref_ptr_tests.cpp b/kernel/app/tests/ref_ptr_tests.cpp new file mode 100644 index 000000000..d5ad8d9b8 --- /dev/null +++ b/kernel/app/tests/ref_ptr_tests.cpp @@ -0,0 +1,83 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +#include "ref_call_counter.h" + +extern "C" int ref_ptr_tests(int argc, const cmd_args* argv) +{ + BEGIN_TEST; + using RefCallPtr = utils::RefPtr; + + RefCallCounter counter; + RefCallPtr ptr = utils::AdoptRef(&counter); + + EXPECT_TRUE(&counter == ptr.get(), ".get() should point to object"); + EXPECT_TRUE(static_cast(ptr), "operator bool"); + EXPECT_TRUE(&counter == &(*ptr), "operator*"); + + // Adoption should not manipulate the refcount. + EXPECT_EQ(0, counter.add_ref_calls(), ""); + EXPECT_EQ(0, counter.release_calls(), ""); + + { + RefCallPtr ptr2 = ptr; + + // Copying to a new RefPtr should call add once. + EXPECT_EQ(1, counter.add_ref_calls(), ""); + EXPECT_EQ(0, counter.release_calls(), ""); + } + // Destroying the new RefPtr should release once. + EXPECT_EQ(1, counter.add_ref_calls(), ""); + EXPECT_EQ(1, counter.release_calls(), ""); + + { + RefCallPtr ptr2; + + EXPECT_TRUE(!static_cast(ptr2), ""); + + ptr.swap(ptr2); + + // Swapping shouldn't cause any add or release calls, but should update + // values. + EXPECT_EQ(1, counter.add_ref_calls(), ""); + EXPECT_EQ(1, counter.release_calls(), ""); + + EXPECT_TRUE(!static_cast(ptr), ""); + EXPECT_TRUE(&counter == ptr2.get(), ""); + + ptr2.swap(ptr); + } + + EXPECT_EQ(1, counter.add_ref_calls(), ""); + EXPECT_EQ(1, counter.release_calls(), ""); + + { + RefCallPtr ptr2 = utils::move(ptr); + + // Moving shouldn't cause any add or release but should update values. + EXPECT_EQ(1, counter.add_ref_calls(), ""); + EXPECT_EQ(1, counter.release_calls(), ""); + + EXPECT_FALSE(static_cast(ptr), ""); + EXPECT_TRUE(&counter == ptr2.get(), ""); + + ptr2.swap(ptr); + } + + // Reset should calls release and clear out the pointer. + ptr.reset(nullptr); + EXPECT_EQ(2, counter.release_calls(), ""); + EXPECT_FALSE(static_cast(ptr), ""); + EXPECT_FALSE(ptr.get(), ""); + + printf("all tests done\n"); + END_TEST; +} diff --git a/kernel/app/tests/rules.mk b/kernel/app/tests/rules.mk new file mode 100644 index 000000000..c1520f4aa --- /dev/null +++ b/kernel/app/tests/rules.mk @@ -0,0 +1,48 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/arena_tests.cpp \ + $(LOCAL_DIR)/auto_call_tests.cpp \ + $(LOCAL_DIR)/benchmarks.c \ + $(LOCAL_DIR)/cache_tests.c \ + $(LOCAL_DIR)/clock_tests.c \ + $(LOCAL_DIR)/fibo.c \ + $(LOCAL_DIR)/float.c \ + $(LOCAL_DIR)/float_instructions.S \ + $(LOCAL_DIR)/float_test_vec.c \ + $(LOCAL_DIR)/forward_tests.cpp \ + $(LOCAL_DIR)/hash_tests.cpp \ + $(LOCAL_DIR)/list_tests.cpp \ + $(LOCAL_DIR)/mem_tests.c \ + $(LOCAL_DIR)/port_tests.c \ + $(LOCAL_DIR)/printf_tests.c \ + $(LOCAL_DIR)/ref_call_counter.cpp \ + $(LOCAL_DIR)/ref_counted_tests.cpp \ + $(LOCAL_DIR)/ref_ptr_tests.cpp \ + $(LOCAL_DIR)/sync_ipi_tests.c \ + $(LOCAL_DIR)/tests.c \ + $(LOCAL_DIR)/thread_tests.c \ + $(LOCAL_DIR)/unique_ptr_tests.cpp \ + $(LOCAL_DIR)/unittests.c \ + $(LOCAL_DIR)/vm_tests.cpp \ + +MODULE_DEPS += \ + lib/safeint \ + lib/unittest \ + lib/utils \ + lib/crypto \ + +MODULE_ARM_OVERRIDE_SRCS := \ + +MODULE_COMPILEFLAGS += -Wno-format -fno-builtin + +include make/module.mk diff --git a/kernel/app/tests/sync_ipi_tests.c b/kernel/app/tests/sync_ipi_tests.c new file mode 100644 index 000000000..be86e0178 --- /dev/null +++ b/kernel/app/tests/sync_ipi_tests.c @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define TEST_RUNS 1000 + +void inorder_count_task(void *raw_context) { + ASSERT(arch_ints_disabled()); + int *inorder_counter = raw_context; + uint cpu_num = arch_curr_cpu_num(); + + int oldval = atomic_add(inorder_counter, 1); + ASSERT(oldval == (int)cpu_num); + LTRACEF(" CPU %u checked in\n", cpu_num); +} + +void counter_task(void *raw_context) { + ASSERT(arch_ints_disabled()); + int *counter = raw_context; + atomic_add(counter, 1); +} + +int sync_ipi_tests(int argc, const cmd_args *argv) +{ + uint num_cpus = arch_max_num_cpus(); + uint online = mp_get_online_mask(); + if (online != (1U << num_cpus) - 1) { + printf("Can only run test with all CPUs online\n"); + return ERR_NOT_SUPPORTED; + } + + uint runs = TEST_RUNS; + if (argc > 1) { + runs = argv[1].u; + } + + /* Test that we're actually blocking and only signaling the ones we target */ + for (uint i = 0; i < runs; ++i) { + LTRACEF("Sequential test\n"); + int inorder_counter = 0; + for (uint i = 0; i < num_cpus; ++i) { + mp_sync_exec(1 << i, inorder_count_task, &inorder_counter); + LTRACEF(" Finished signaling CPU %u\n", i); + } + } + + /* Test that we can signal multiple CPUs at the same time */ + for (uint i = 0; i < runs; ++i) { + LTRACEF("Counter test (%u CPUs)\n", num_cpus); + int counter = 0; + + spin_lock_saved_state_t irqstate; + arch_interrupt_save(&irqstate, SPIN_LOCK_FLAG_INTERRUPTS); + + mp_sync_exec(MP_CPU_ALL_BUT_LOCAL, counter_task, &counter); + + arch_interrupt_restore(irqstate, SPIN_LOCK_FLAG_INTERRUPTS); + + LTRACEF(" Finished signaling all but local (%d)\n", counter); + ASSERT((uint)counter == num_cpus - 1); + } + + printf("Success\n"); + return NO_ERROR; +} diff --git a/kernel/app/tests/tests.c b/kernel/app/tests/tests.c new file mode 100644 index 000000000..9881ddedf --- /dev/null +++ b/kernel/app/tests/tests.c @@ -0,0 +1,47 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +#if defined(WITH_LIB_CONSOLE) +#include + +STATIC_COMMAND_START +STATIC_COMMAND("printf_tests", "test printf", (console_cmd)&printf_tests) +STATIC_COMMAND("thread_tests", "test the scheduler", (console_cmd)&thread_tests) +STATIC_COMMAND("port_tests", "test the ports", (console_cmd)&port_tests) +STATIC_COMMAND("clock_tests", "test clocks", (console_cmd)&clock_tests) +STATIC_COMMAND("bench", "miscellaneous benchmarks", (console_cmd)&benchmarks) +STATIC_COMMAND("fibo", "threaded fibonacci", (console_cmd)&fibo) +STATIC_COMMAND("spinner", "create a spinning thread", (console_cmd)&spinner) +STATIC_COMMAND("ref_ptr_tests", "test ref_ptr", (console_cmd)&ref_ptr_tests) +STATIC_COMMAND("ref_counted_tests", "test ref_counted", (console_cmd)&ref_counted_tests) +STATIC_COMMAND("unique_ptr_tests", "test unique_ptr", (console_cmd)&unique_ptr_tests) +STATIC_COMMAND("forward_tests", "test forward", (console_cmd)&forward_tests) +STATIC_COMMAND("list_tests", "test lists", (console_cmd)&list_tests) +STATIC_COMMAND("hash_tests", "test hash tables", (console_cmd)&hash_tests) +STATIC_COMMAND("vm_tests", "test the virtual memory system", (console_cmd)&vm_tests) +STATIC_COMMAND("auto_call_tests", "test auto call", (console_cmd)&auto_call_tests) +STATIC_COMMAND("sync_ipi_tests", "test synchronous IPIs", (console_cmd)&sync_ipi_tests) +STATIC_COMMAND("arena_tests", "test arena allocator", (console_cmd)&arena_tests) +STATIC_COMMAND("unit_tests", "run all unittests", (console_cmd)&unittests) +STATIC_COMMAND_END(tests); + +#endif + +static void tests_init(const struct app_descriptor *app) +{ +} + +APP_START(tests) +.init = tests_init, + .flags = 0, +APP_END + diff --git a/kernel/app/tests/thread_tests.c b/kernel/app/tests/thread_tests.c new file mode 100644 index 000000000..0ba56e7ae --- /dev/null +++ b/kernel/app/tests/thread_tests.c @@ -0,0 +1,649 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int sleep_thread(void *arg) +{ + for (;;) { + printf("sleeper %p\n", get_current_thread()); + thread_sleep(rand() % 500); + } + return 0; +} + +int sleep_test(void) +{ + int i; + for (i=0; i < 16; i++) + thread_detach_and_resume(thread_create("sleeper", &sleep_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + return 0; +} + +static semaphore_t sem; +static const int sem_total_its = 10000; +static const int sem_thread_max_its = 1000; +static const int sem_start_value = 10; +static int sem_remaining_its = 0; +static int sem_threads = 0; +static mutex_t sem_test_mutex; + +static int semaphore_producer(void *unused) +{ + printf("semaphore producer %p starting up, running for %d iterations\n", get_current_thread(), sem_total_its); + + for (int x = 0; x < sem_total_its; x++) { + sem_post(&sem, true); + } + + return 0; +} + +static int semaphore_consumer(void *unused) +{ + unsigned int iterations = 0; + + mutex_acquire(&sem_test_mutex); + if (sem_remaining_its >= sem_thread_max_its) { + iterations = rand(); + iterations %= sem_thread_max_its; + } else { + iterations = sem_remaining_its; + } + sem_remaining_its -= iterations; + mutex_release(&sem_test_mutex); + + printf("semaphore consumer %p starting up, running for %u iterations\n", get_current_thread(), iterations); + for (unsigned int x = 0; x < iterations; x++) + sem_wait(&sem); + printf("semaphore consumer %p done\n", get_current_thread()); + atomic_add(&sem_threads, -1); + return 0; +} + +static int semaphore_test(void) +{ + static semaphore_t isem = SEMAPHORE_INITIAL_VALUE(isem, 99); + printf("preinitialized sempahore:\n"); + hexdump(&isem, sizeof(isem)); + + sem_init(&sem, sem_start_value); + mutex_init(&sem_test_mutex); + + sem_remaining_its = sem_total_its; + while (1) { + mutex_acquire(&sem_test_mutex); + if (sem_remaining_its) { + thread_detach_and_resume(thread_create("semaphore consumer", &semaphore_consumer, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + atomic_add(&sem_threads, 1); + } else { + mutex_release(&sem_test_mutex); + break; + } + mutex_release(&sem_test_mutex); + } + + thread_detach_and_resume(thread_create("semaphore producer", &semaphore_producer, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + + while (sem_threads) + thread_yield(); + + if (sem.count == sem_start_value) + printf("semaphore tests successfully complete\n"); + else + printf("semaphore tests failed: %d != %d\n", sem.count, sem_start_value); + + sem_destroy(&sem); + mutex_destroy(&sem_test_mutex); + + return 0; +} + +static int mutex_thread(void *arg) +{ + int i; + const int iterations = 1000000; + + static volatile int shared = 0; + + mutex_t *m = (mutex_t *)arg; + + printf("mutex tester thread %p starting up, will go for %d iterations\n", get_current_thread(), iterations); + + for (i = 0; i < iterations; i++) { + mutex_acquire(m); + + if (shared != 0) + panic("someone else has messed with the shared data\n"); + + shared = (intptr_t)get_current_thread(); + thread_yield(); + shared = 0; + + mutex_release(m); + thread_yield(); + } + + return 0; +} + +static int mutex_timeout_thread(void *arg) +{ + mutex_t *timeout_mutex = (mutex_t *)arg; + status_t err; + + printf("mutex_timeout_thread acquiring mutex %p with 1 second timeout\n", timeout_mutex); + err = mutex_acquire_timeout(timeout_mutex, 1000); + if (err == ERR_TIMED_OUT) + printf("mutex_acquire_timeout returns with TIMEOUT\n"); + else + printf("mutex_acquire_timeout returns %d\n", err); + + return err; +} + +static int mutex_zerotimeout_thread(void *arg) +{ + mutex_t *timeout_mutex = (mutex_t *)arg; + status_t err; + + printf("mutex_zerotimeout_thread acquiring mutex %p with zero second timeout\n", timeout_mutex); + err = mutex_acquire_timeout(timeout_mutex, 0); + if (err == ERR_TIMED_OUT) + printf("mutex_acquire_timeout returns with TIMEOUT\n"); + else + printf("mutex_acquire_timeout returns %d\n", err); + + return err; +} + +int mutex_test(void) +{ + static mutex_t imutex = MUTEX_INITIAL_VALUE(imutex); + printf("preinitialized mutex:\n"); + hexdump(&imutex, sizeof(imutex)); + + mutex_t m; + mutex_init(&m); + + thread_t *threads[5]; + + for (uint i=0; i < countof(threads); i++) { + threads[i] = thread_create("mutex tester", &mutex_thread, &m, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(threads[i]); + } + + for (uint i=0; i < countof(threads); i++) { + thread_join(threads[i], NULL, INFINITE_TIME); + } + + printf("done with simple mutex tests\n"); + + printf("testing mutex timeout\n"); + + mutex_t timeout_mutex; + + mutex_init(&timeout_mutex); + mutex_acquire(&timeout_mutex); + + for (uint i=0; i < 2; i++) { + threads[i] = thread_create("mutex timeout tester", &mutex_timeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(threads[i]); + } + + for (uint i=2; i < 4; i++) { + threads[i] = thread_create("mutex timeout tester", &mutex_zerotimeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(threads[i]); + } + + thread_sleep(5000); + mutex_release(&timeout_mutex); + + for (uint i=0; i < 4; i++) { + thread_join(threads[i], NULL, INFINITE_TIME); + } + + printf("done with mutex tests\n"); + + mutex_destroy(&timeout_mutex); + + return 0; +} + +static event_t e; + +static int event_signaller(void *arg) +{ + printf("event signaller pausing\n"); + thread_sleep(1000); + +// for (;;) { + printf("signalling event\n"); + event_signal(&e, true); + printf("done signalling event\n"); + thread_yield(); +// } + + return 0; +} + +static int event_waiter(void *arg) +{ + int count = (intptr_t)arg; + + printf("event waiter starting\n"); + + while (count > 0) { + printf("%p: waiting on event...\n", get_current_thread()); + if (event_wait(&e) < 0) { + printf("%p: event_wait() returned error\n", get_current_thread()); + return -1; + } + printf("%p: done waiting on event...\n", get_current_thread()); + thread_yield(); + count--; + } + + return 0; +} + +void event_test(void) +{ + thread_t *threads[5]; + + static event_t ievent = EVENT_INITIAL_VALUE(ievent, true, 0x1234); + printf("preinitialized event:\n"); + hexdump(&ievent, sizeof(ievent)); + + printf("event tests starting\n"); + + /* make sure signalling the event wakes up all the threads */ + event_init(&e, false, 0); + threads[0] = thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[1] = thread_create("event waiter 0", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[2] = thread_create("event waiter 1", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[3] = thread_create("event waiter 2", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[4] = thread_create("event waiter 3", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + + for (uint i = 0; i < countof(threads); i++) + thread_resume(threads[i]); + + thread_sleep(2000); + printf("destroying event\n"); + event_destroy(&e); + + for (uint i = 0; i < countof(threads); i++) + thread_join(threads[i], NULL, INFINITE_TIME); + + /* make sure signalling the event wakes up precisely one thread */ + event_init(&e, false, EVENT_FLAG_AUTOUNSIGNAL); + threads[0] = thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[1] = thread_create("event waiter 0", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[2] = thread_create("event waiter 1", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[3] = thread_create("event waiter 2", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + threads[4] = thread_create("event waiter 3", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + + for (uint i = 0; i < countof(threads); i++) + thread_resume(threads[i]); + + thread_sleep(2000); + event_destroy(&e); + + for (uint i = 0; i < countof(threads); i++) + thread_join(threads[i], NULL, INFINITE_TIME); + + printf("event tests done\n"); +} + +static int quantum_tester(void *arg) +{ + for (;;) { + printf("%p: in this thread. rq %d\n", get_current_thread(), get_current_thread()->remaining_quantum); + } + return 0; +} + +void quantum_test(void) +{ + thread_detach_and_resume(thread_create("quantum tester 0", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("quantum tester 1", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("quantum tester 2", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("quantum tester 3", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); +} + +static event_t context_switch_event; +static event_t context_switch_done_event; + +static int context_switch_tester(void *arg) +{ + int i; + uint total_count = 0; + const int iter = 100000; + int thread_count = (intptr_t)arg; + + event_wait(&context_switch_event); + + uint count = arch_cycle_count(); + for (i = 0; i < iter; i++) { + thread_yield(); + } + total_count += arch_cycle_count() - count; + thread_sleep(1000); + printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n", + total_count, iter, total_count / iter, total_count / iter / thread_count); + + event_signal(&context_switch_done_event, true); + + return 0; +} + +void context_switch_test(void) +{ + event_init(&context_switch_event, false, 0); + event_init(&context_switch_done_event, false, 0); + + thread_detach_and_resume(thread_create("context switch idle", &context_switch_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_sleep(100); + event_signal(&context_switch_event, true); + event_wait(&context_switch_done_event); + thread_sleep(100); + + event_unsignal(&context_switch_event); + event_unsignal(&context_switch_done_event); + thread_detach_and_resume(thread_create("context switch 2a", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("context switch 2b", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_sleep(100); + event_signal(&context_switch_event, true); + event_wait(&context_switch_done_event); + thread_sleep(100); + + event_unsignal(&context_switch_event); + event_unsignal(&context_switch_done_event); + thread_detach_and_resume(thread_create("context switch 4a", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("context switch 4b", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("context switch 4c", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_detach_and_resume(thread_create("context switch 4d", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + thread_sleep(100); + event_signal(&context_switch_event, true); + event_wait(&context_switch_done_event); + thread_sleep(100); +} + +static volatile int atomic; +static volatile int atomic_count; + +static int atomic_tester(void *arg) +{ + int add = (intptr_t)arg; + int i; + + const int iter = 10000000; + + TRACEF("add %d, %d iterations\n", add, iter); + + for (i=0; i < iter; i++) { + atomic_add(&atomic, add); + } + + int old = atomic_add(&atomic_count, -1); + TRACEF("exiting, old count %d\n", old); + + return 0; +} + +static void atomic_test(void) +{ + atomic = 0; + atomic_count = 8; + + printf("testing atomic routines\n"); + + thread_t *threads[8]; + threads[0] = thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[1] = thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[2] = thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[3] = thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[4] = thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[5] = thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[6] = thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + threads[7] = thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE); + + /* start all the threads */ + for (uint i = 0; i < countof(threads); i++) + thread_resume(threads[i]); + + /* wait for them to all stop */ + for (uint i = 0; i < countof(threads); i++) { + thread_join(threads[i], NULL, INFINITE_TIME); + } + + printf("atomic count == %d (should be zero)\n", atomic); +} + +static volatile int preempt_count; + +static int preempt_tester(void *arg) +{ + spin(1000000); + + printf("exiting ts %lld\n", current_time_hires()); + + atomic_add(&preempt_count, -1); +#undef COUNT + + return 0; +} + +static void preempt_test(void) +{ + /* create 5 threads, let them run. If the system is properly timer preempting, + * the threads should interleave each other at a fine enough granularity so + * that they complete at roughly the same time. */ + printf("testing preemption\n"); + + preempt_count = 5; + + for (int i = 0; i < preempt_count; i++) + thread_detach_and_resume(thread_create("preempt tester", &preempt_tester, NULL, LOW_PRIORITY, DEFAULT_STACK_SIZE)); + + while (preempt_count > 0) { + thread_sleep(1000); + } + + printf("done with preempt test, above time stamps should be very close\n"); + + /* do the same as above, but mark the threads as real time, which should + * effectively disable timer based preemption for them. They should + * complete in order, about a second apart. */ + printf("testing real time preemption\n"); + + preempt_count = 5; + + for (int i = 0; i < preempt_count; i++) { + thread_t *t = thread_create("preempt tester", &preempt_tester, NULL, LOW_PRIORITY, DEFAULT_STACK_SIZE); + thread_set_real_time(t); + thread_detach_and_resume(t); + } + + while (preempt_count > 0) { + thread_sleep(1000); + } + + printf("done with real-time preempt test, above time stamps should be 1 second apart\n"); +} + +static int join_tester(void *arg) +{ + long val = (long)arg; + + printf("\t\tjoin tester starting\n"); + thread_sleep(500); + printf("\t\tjoin tester exiting with result %ld\n", val); + + return val; +} + +static int join_tester_server(void *arg) +{ + int ret; + status_t err; + thread_t *t; + + printf("\ttesting thread_join/thread_detach\n"); + + printf("\tcreating and waiting on thread to exit with thread_join\n"); + t = thread_create("join tester", &join_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t); + ret = 99; + printf("\tthread magic is 0x%x (should be 0x%x)\n", t->magic, THREAD_MAGIC); + err = thread_join(t, &ret, INFINITE_TIME); + printf("\tthread_join returns err %d, retval %d\n", err, ret); + printf("\tthread magic is 0x%x (should be 0)\n", t->magic); + + printf("\tcreating and waiting on thread to exit with thread_join, after thread has exited\n"); + t = thread_create("join tester", &join_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t); + thread_sleep(1000); // wait until thread is already dead + ret = 99; + printf("\tthread magic is 0x%x (should be 0x%x)\n", t->magic, THREAD_MAGIC); + err = thread_join(t, &ret, INFINITE_TIME); + printf("\tthread_join returns err %d, retval %d\n", err, ret); + printf("\tthread magic is 0x%x (should be 0)\n", t->magic); + + printf("\tcreating a thread, detaching it, let it exit on its own\n"); + t = thread_create("join tester", &join_tester, (void *)3, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_detach(t); + thread_resume(t); + thread_sleep(1000); // wait until the thread should be dead + printf("\tthread magic is 0x%x (should be 0)\n", t->magic); + + printf("\tcreating a thread, detaching it after it should be dead\n"); + t = thread_create("join tester", &join_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t); + thread_sleep(1000); // wait until thread is already dead + printf("\tthread magic is 0x%x (should be 0x%x)\n", t->magic, THREAD_MAGIC); + thread_detach(t); + printf("\tthread magic is 0x%x\n", t->magic); + + printf("\texiting join tester server\n"); + + return 55; +} + +static void join_test(void) +{ + int ret; + status_t err; + thread_t *t; + + printf("testing thread_join/thread_detach\n"); + + printf("creating thread join server thread\n"); + t = thread_create("join tester server", &join_tester_server, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(t); + ret = 99; + err = thread_join(t, &ret, INFINITE_TIME); + printf("thread_join returns err %d, retval %d (should be 0 and 55)\n", err, ret); +} + +static void spinlock_test(void) +{ + spin_lock_saved_state_t state; + spin_lock_t lock; + + spin_lock_init(&lock); + + // verify basic functionality (single core) + printf("testing spinlock:\n"); + ASSERT(!spin_lock_held(&lock)); + ASSERT(!arch_ints_disabled()); + spin_lock_irqsave(&lock, state); + ASSERT(arch_ints_disabled()); + ASSERT(spin_lock_held(&lock)); + spin_unlock_irqrestore(&lock, state); + ASSERT(!spin_lock_held(&lock)); + ASSERT(!arch_ints_disabled()); + printf("seems to work\n"); + +#define COUNT (1024*1024) + uint32_t c = arch_cycle_count(); + for (uint i = 0; i < COUNT; i++) { + spin_lock(&lock); + spin_unlock(&lock); + } + c = arch_cycle_count() - c; + + printf("%u cycles to acquire/release lock %u times (%u cycles per)\n", c, COUNT, c / COUNT); + + c = arch_cycle_count(); + for (uint i = 0; i < COUNT; i++) { + spin_lock_irqsave(&lock, state); + spin_unlock_irqrestore(&lock, state); + } + c = arch_cycle_count() - c; + + printf("%u cycles to acquire/release lock w/irqsave %u times (%u cycles per)\n", c, COUNT, c / COUNT); +#undef COUNT +} + +int thread_tests(void) +{ + mutex_test(); + semaphore_test(); + event_test(); + + spinlock_test(); + atomic_test(); + + thread_sleep(200); + context_switch_test(); + + preempt_test(); + + join_test(); + + return 0; +} + +static int spinner_thread(void *arg) +{ + for (;;) + ; + + return 0; +} + +int spinner(int argc, const cmd_args *argv) +{ + if (argc < 2) { + printf("not enough args\n"); + printf("usage: %s \n", argv[0].str); + return -1; + } + + thread_t *t = thread_create("spinner", spinner_thread, NULL, argv[1].u, DEFAULT_STACK_SIZE); + if (!t) + return ERR_NO_MEMORY; + + if (argc >= 3 && !strcmp(argv[2].str, "rt")) { + thread_set_real_time(t); + } + thread_resume(t); + + return 0; +} diff --git a/kernel/app/tests/unique_ptr_tests.cpp b/kernel/app/tests/unique_ptr_tests.cpp new file mode 100644 index 000000000..c3118398f --- /dev/null +++ b/kernel/app/tests/unique_ptr_tests.cpp @@ -0,0 +1,151 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +static int destroy_count = 0; + +struct CountingDeleter { + void operator()(int* p) + { + destroy_count++; + delete p; + } +}; + +extern "C" int unique_ptr_tests(int argc, const cmd_args* argv) +{ + BEGIN_TEST; + // Test for unique_ptr variant + using CountingPtr = utils::unique_ptr; + + // Construct and let a unique_ptr fall out of scope. + { + CountingPtr ptr(new int); + } + + EXPECT_EQ(1, destroy_count, ""); + + destroy_count = 0; + + // Construct and move into another unique_ptr. + { + CountingPtr ptr(new int); + CountingPtr ptr2 = utils::move(ptr); + if (ptr.get() != nullptr) { + printf("assert failed: expected ptr to be null on line %d\n", __LINE__); + return 1; + } + } + + EXPECT_EQ(1, destroy_count, ""); + + destroy_count = 0; + + // Construct a null unique_ptr and let it fall out of scope - should not call + // deleter. + { + CountingPtr ptr(nullptr); + } + + EXPECT_EQ(0, destroy_count, ""); + + // Construct a pair of unique_ptrs in different scopes, swap them, and verify + // that the values change places and that the values are destroyed at the + // correct times. + { + CountingPtr ptr1(new int(4)); + { + CountingPtr ptr2(new int(7)); + ptr1.swap(ptr2); + EXPECT_EQ(7, *ptr1, ""); + EXPECT_EQ(4, *ptr2, ""); + } + EXPECT_EQ(1, destroy_count, ""); + } + EXPECT_EQ(2, destroy_count, ""); + + destroy_count = 0; + + // Test operator bool + { + CountingPtr foo(new int); + EXPECT_TRUE(static_cast(foo), ""); + + foo.reset(); + EXPECT_EQ(1, destroy_count, ""); + EXPECT_FALSE(static_cast(foo), ""); + } + + destroy_count = 0; + + // Test for unique_ptr variant + using CountingArrPtr = utils::unique_ptr; + + // Construct and let a unique_ptr fall out of scope. + { + CountingArrPtr ptr(new int[1]); + } + + EXPECT_EQ(1, destroy_count, ""); + + destroy_count = 0; + + // Construct and move into another unique_ptr. + { + CountingArrPtr ptr(new int[1]); + CountingArrPtr ptr2 = utils::move(ptr); + } + + EXPECT_EQ(1, destroy_count, ""); + + destroy_count = 0; + + // Construct a null unique_ptr and let it fall out of scope - should not call + // deleter. + { + CountingArrPtr ptr(nullptr); + } + + EXPECT_EQ(0, destroy_count, ""); + + // Construct a pair of unique_ptrs in different scopes, swap them, and verify + // that the values change places and that the values are destroyed at the + // correct times. + { + CountingArrPtr ptr1(new int[1]); + ptr1[0] = 4; + { + CountingArrPtr ptr2(new int[1]); + ptr2[0] = 7; + ptr1.swap(ptr2); + EXPECT_EQ(7, ptr1[0], ""); + EXPECT_EQ(4, ptr2[0], ""); + } + EXPECT_EQ(1, destroy_count, ""); + } + EXPECT_EQ(2, destroy_count, ""); + + destroy_count = 0; + + // Test operator bool + { + CountingArrPtr foo(new int[1]); + EXPECT_TRUE(static_cast(foo), ""); + + foo.reset(); + EXPECT_EQ(1, destroy_count, ""); + EXPECT_FALSE(static_cast(foo), ""); + } + + destroy_count = 0; + + printf("all tests passed\n"); + END_TEST; +} diff --git a/kernel/app/tests/unittests.c b/kernel/app/tests/unittests.c new file mode 100644 index 000000000..207d55c1c --- /dev/null +++ b/kernel/app/tests/unittests.c @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +void unittests() +{ + bool success = run_all_tests(); + printf(success ? "Success\n" : "Failure\n"); +} diff --git a/kernel/app/tests/vm_tests.cpp b/kernel/app/tests/vm_tests.cpp new file mode 100644 index 000000000..534b0dd5e --- /dev/null +++ b/kernel/app/tests/vm_tests.cpp @@ -0,0 +1,555 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__NO_INLINE static bool pmm_tests() { + BEGIN_TEST; + printf("starting pmm tests\n"); + + // allocate a single page, translate it to a vm_page_t and free it + printf("allocating single page, then freeing it\n"); + { + paddr_t pa; + + vm_page_t* page = pmm_alloc_page(0, &pa); + EXPECT_NEQ(nullptr, page, "pmm_alloc single page"); + EXPECT_NEQ(0u, pa, "pmm_alloc single page"); + + vm_page_t* page2 = paddr_to_vm_page(pa); + EXPECT_EQ(page2, page, "paddr_to_vm_page on single page"); + + auto ret = pmm_free_page(page); + EXPECT_EQ(1u, ret, "pmm_free_page on single page"); + } + + // allocate a bunch of pages then free them + printf("allocating a lot of pages, then freeing them\n"); + { + list_node list = LIST_INITIAL_VALUE(list); + + static const size_t alloc_count = 1024; + + auto count = pmm_alloc_pages(alloc_count, 0, &list); + EXPECT_EQ(alloc_count, count, "pmm_alloc_pages a bunch of pages count"); + EXPECT_EQ(alloc_count, list_length(&list), "pmm_alloc_pages a bunch of pages list count"); + + auto ret = pmm_free(&list); + EXPECT_EQ(alloc_count, ret, "pmm_free_page on a list of pages"); + } + + // allocate too many pages and make sure it fails nicely + printf("allocating too many pages, then freeing them\n"); + { + list_node list = LIST_INITIAL_VALUE(list); + + static const size_t alloc_count = (128 * 1024 * 1024 * 1024ULL) / PAGE_SIZE; // 128GB + + auto count = pmm_alloc_pages(alloc_count, 0, &list); + EXPECT_NEQ(alloc_count, 0, "pmm_alloc_pages too many pages count > 0"); + EXPECT_NEQ(alloc_count, count, "pmm_alloc_pages too many pages count"); + EXPECT_EQ(count, list_length(&list), "pmm_alloc_pages too many pages list count"); + + auto ret = pmm_free(&list); + EXPECT_EQ(count, ret, "pmm_free_page on a list of pages"); + } + + printf("done with pmm tests\n"); + END_TEST; +} + +static uint32_t test_rand(uint32_t seed) { + return (seed = seed * 1664525 + 1013904223); +} + +// fill a region of memory with a pattern based on the address of the region +static void fill_region(uintptr_t seed, void* _ptr, size_t len) { + uint32_t* ptr = (uint32_t*)_ptr; + + ASSERT(IS_ALIGNED((uintptr_t)ptr, 4)); + + uint32_t val = (uint32_t)seed; +#if UINTPTR_MAX > UINT32_MAX + val ^= (uint32_t)(seed >> 32); +#endif + for (size_t i = 0; i < len / 4; i++) { + ptr[i] = val; + + val = test_rand(val); + } +} + +// test a region of memory against a known pattern +static bool test_region(uintptr_t seed, void* _ptr, size_t len) { + uint32_t* ptr = (uint32_t*)_ptr; + + ASSERT(IS_ALIGNED((uintptr_t)ptr, 4)); + + uint32_t val = (uint32_t)seed; +#if UINTPTR_MAX > UINT32_MAX + val ^= (uint32_t)(seed >> 32); +#endif + for (size_t i = 0; i < len / 4; i++) { + if (ptr[i] != val) { + printf("value at %p (%zu) is incorrect: 0x%x vs 0x%x\n", &ptr[i], i, ptr[i], val); + return false; + } + + val = test_rand(val); + } + + return true; +} + +static void fill_and_test(bool& all_ok, void* ptr, size_t len) { + // fill it with a pattern + fill_region((uintptr_t)ptr, ptr, len); + + // test that the pattern is read back properly + auto result = test_region((uintptr_t)ptr, ptr, len); + EXPECT_TRUE(result, "testing region for corruption"); +} + +__NO_INLINE static bool vmm_tests() { + BEGIN_TEST; + printf("starting vmm tests\n"); + + printf("allocating a region in kernel space, read/write it, then destroy it\n"); + { + static const size_t alloc_size = 256 * 1024; + + // allocate a region of memory + void* ptr; + auto err = vmm_alloc(vmm_get_kernel_aspace(), "test", alloc_size, &ptr, 0, 0, 0); + EXPECT_EQ(0, err, "vmm_allocate region of memory"); + EXPECT_NEQ(nullptr, ptr, "vmm_allocate region of memory"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + // free the region + err = vmm_free_region(vmm_get_kernel_aspace(), (vaddr_t)ptr); + EXPECT_EQ(0, err, "vmm_free_region region of memory"); + } + + printf("allocating a contiguous region in kernel space, read/write it, then destroy it\n"); + { + static const size_t alloc_size = 256 * 1024; + + // allocate a region of memory + void* ptr; + auto err = vmm_alloc_contiguous(vmm_get_kernel_aspace(), "test", alloc_size, &ptr, 0, + VMM_FLAG_COMMIT, 0); + EXPECT_EQ(0, err, "vmm_allocate_contiguous region of memory"); + EXPECT_NEQ(nullptr, ptr, "vmm_allocate_contiguous region of memory"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + // test that it is indeed contiguous + printf("testing that region is contiguous\n"); + paddr_t last_pa = 0; + for (size_t i = 0; i < alloc_size / PAGE_SIZE; i++) { + paddr_t pa = vaddr_to_paddr((uint8_t*)ptr + i * PAGE_SIZE); + if (last_pa != 0) { + EXPECT_EQ(pa, last_pa + PAGE_SIZE, "region is contiguous"); + } + + last_pa = pa; + } + + // free the region + err = vmm_free_region(vmm_get_kernel_aspace(), (vaddr_t)ptr); + EXPECT_EQ(0, err, "vmm_free_region region of memory"); + } + + printf("allocating a new address space and creating a few regions in it, then destroy it\n"); + { + void* ptr; + vmm_aspace_t* aspace; + static const size_t alloc_size = 16 * 1024; + + auto err = vmm_create_aspace(&aspace, "test aspace", 0); + EXPECT_EQ(0, err, "vmm_allocate_aspace error code"); + EXPECT_NEQ(nullptr, aspace, "vmm_allocate_aspace pointer"); + + vmm_aspace_t *old_aspace = get_current_thread()->aspace; + vmm_set_active_aspace(aspace); + + // allocate region 0 + err = vmm_alloc(aspace, "test0", alloc_size, &ptr, 0, 0, 0); + EXPECT_EQ(0, err, "vmm_allocate region of memory"); + EXPECT_NEQ(nullptr, ptr, "vmm_allocate region of memory"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + // allocate region 1 + err = vmm_alloc(aspace, "test1", 16384, &ptr, 0, 0, 0); + EXPECT_EQ(0, err, "vmm_allocate region of memory"); + EXPECT_NEQ(nullptr, ptr, "vmm_allocate region of memory"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + // allocate region 2 + err = vmm_alloc(aspace, "test2", 16384, &ptr, 0, 0, 0); + EXPECT_EQ(0, err, "vmm_allocate region of memory"); + EXPECT_NEQ(nullptr, ptr, "vmm_allocate region of memory"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + vmm_set_active_aspace(old_aspace); + + // free the address space all at once + err = vmm_free_aspace(aspace); + EXPECT_EQ(0, err, "vmm_free_aspace"); + } + + printf("test for some invalid arguments\n"); + { + void* ptr; + status_t err; + + // zero size + err = vmm_alloc(vmm_get_kernel_aspace(), "test", 0, &ptr, 0, 0, 0); + EXPECT_EQ(ERR_INVALID_ARGS, err, "invalid args to vmm_alloc"); + + // bad pointer + ptr = (void*)1; + err = vmm_alloc(vmm_get_kernel_aspace(), "test", 16384, &ptr, 0, + VMM_FLAG_VALLOC_SPECIFIC | VMM_FLAG_COMMIT, 0); + EXPECT_EQ(ERR_INVALID_ARGS, err, "invalid args to vmm_alloc"); + + // should have VMM_FLAG_COMMIT + err = vmm_alloc_contiguous(vmm_get_kernel_aspace(), "test", 4096, &ptr, 0, 0, 0); + EXPECT_EQ(ERR_INVALID_ARGS, err, "invalid args to vmm_alloc_contiguous"); + + // zero size + err = vmm_alloc_contiguous(vmm_get_kernel_aspace(), "test", 0, &ptr, 0, VMM_FLAG_COMMIT, 0); + EXPECT_EQ(ERR_INVALID_ARGS, err, "invalid args to vmm_alloc_contiguous"); + } + + printf("allocating a vm address space object directly, allowing it to go out of scope\n"); + { + auto aspace = VmAspace::Create(0, "test aspace"); + } + + printf("allocating a vm address space object directly, mapping somethign on it, allowing it to go out of scope\n"); + { + auto aspace = VmAspace::Create(0, "test aspace2"); + + void *ptr; + auto err = aspace->Alloc("test", PAGE_SIZE, &ptr, 0, 0, 0); + EXPECT_EQ(NO_ERROR, err, "allocating region\n"); + + // destroy the aspace, which should drop all the internal refs to it + aspace->Destroy(); + + // drop the ref held by this pointer + aspace.reset(); + } + + printf("verify there are no test aspaces left around\n"); + DumpAllAspaces(); + + printf("done with vmm tests\n"); + END_TEST; +} + +__NO_INLINE static bool vmm_object_tests() { + BEGIN_TEST; + printf("starting vmm object based tests\n"); + + printf("creating vm object\n"); + { + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, PAGE_SIZE); + EXPECT_TRUE(vmo, "vmobject creation\n"); + } + + printf("creating vm object, committing memory\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ret = vmo->CommitRange(0, alloc_size); + EXPECT_EQ((ssize_t)alloc_size, ret, "committing vm object\n"); + } + + printf("creating vm object, committing odd sized memory\n"); + { + static const size_t alloc_size = 15; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ret = vmo->CommitRange(0, alloc_size); + EXPECT_EQ((ssize_t)alloc_size, ret, "committing vm object\n"); + } + + printf("creating vm object, committing contiguous memory\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ret = vmo->CommitRangeContiguous(0, alloc_size, 0); + EXPECT_EQ((ssize_t)alloc_size, ret, "committing vm object contiguously\n"); + } + + printf("creating vm object, mapping it, precommitted\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ka = VmAspace::kernel_aspace(); + void* ptr; + auto ret = + ka->MapObject(vmo, "test", 0, alloc_size, &ptr, 0, VMM_FLAG_COMMIT, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(NO_ERROR, ret, "mapping object"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + auto err = ka->FreeRegion((vaddr_t)ptr); + EXPECT_EQ(NO_ERROR, err, "unmapping object"); + } + + printf("creating vm object, mapping it, demand paged\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ka = VmAspace::kernel_aspace(); + void* ptr; + auto ret = ka->MapObject(vmo, "test", 0, alloc_size, &ptr, 0, 0, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(ret, NO_ERROR, "mapping object"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + auto err = ka->FreeRegion((vaddr_t)ptr); + EXPECT_EQ(NO_ERROR, err, "unmapping object"); + } + + printf("creating vm object, mapping it, dropping ref before unmapping\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ka = VmAspace::kernel_aspace(); + void* ptr; + auto ret = ka->MapObject(utils::move(vmo), "test", 0, alloc_size, &ptr, 0, VMM_FLAG_COMMIT, + PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(ret, NO_ERROR, "mapping object"); + + EXPECT_FALSE(vmo, "dropped ref to object"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + auto err = ka->FreeRegion((vaddr_t)ptr); + EXPECT_EQ(NO_ERROR, err, "unmapping object"); + } + + printf( + "creating vm object, mapping it, filling it with data, unmapping, mapping again somewhere " + "else\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ka = VmAspace::kernel_aspace(); + void* ptr; + auto ret = + ka->MapObject(vmo, "test", 0, alloc_size, &ptr, 0, VMM_FLAG_COMMIT, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(NO_ERROR, ret, "mapping object"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + auto err = ka->FreeRegion((vaddr_t)ptr); + EXPECT_EQ(NO_ERROR, err, "unmapping object"); + + // map it again + ret = + ka->MapObject(vmo, "test", 0, alloc_size, &ptr, 0, VMM_FLAG_COMMIT, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(ret, NO_ERROR, "mapping object"); + + // test that the pattern is still valid + bool result = test_region((uintptr_t)ptr, ptr, alloc_size); + EXPECT_TRUE(result, "testing region for corruption"); + + err = ka->FreeRegion((vaddr_t)ptr); + EXPECT_EQ(NO_ERROR, err, "unmapping object"); + } + + printf( + "creating vm object, mapping it, filling it with data, mapping it a second time and third " + "time somwehere else\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + auto ka = VmAspace::kernel_aspace(); + void* ptr; + auto ret = ka->MapObject(vmo, "test0", 0, alloc_size, &ptr, 0, 0, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(NO_ERROR, ret, "mapping object"); + + // fill with known pattern and test + fill_and_test(all_ok, ptr, alloc_size); + + // map it again + void* ptr2; + ret = ka->MapObject(vmo, "test1", 0, alloc_size, &ptr2, 0, 0, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(ret, NO_ERROR, "mapping object second time"); + EXPECT_NEQ(ptr, ptr2, "second mapping is different"); + + // test that the pattern is still valid + bool result = test_region((uintptr_t)ptr, ptr2, alloc_size); + EXPECT_TRUE(result, "testing region for corruption"); + + // map it a third time with an offset + void* ptr3; + static const size_t alloc_offset = PAGE_SIZE; + ret = ka->MapObject(vmo, "test2", alloc_offset, alloc_size - alloc_offset, &ptr3, 0, 0, + PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(ret, NO_ERROR, "mapping object third time"); + EXPECT_NEQ(ptr3, ptr2, "third mapping is different"); + EXPECT_NEQ(ptr3, ptr, "third mapping is different"); + + // test that the pattern is still valid + int mc = memcmp((uint8_t*)ptr + alloc_offset, ptr3, alloc_size - alloc_offset); + EXPECT_EQ(0, mc, "testing region for corruption"); + + ret = ka->FreeRegion((vaddr_t)ptr3); + EXPECT_EQ(NO_ERROR, ret, "unmapping object third time"); + + ret = ka->FreeRegion((vaddr_t)ptr2); + EXPECT_EQ(NO_ERROR, ret, "unmapping object second time"); + + ret = ka->FreeRegion((vaddr_t)ptr); + EXPECT_EQ(NO_ERROR, ret, "unmapping object"); + } + + printf("creating vm object, writing to it\n"); + { + static const size_t alloc_size = PAGE_SIZE * 16; + + // create object + auto vmo = VmObject::Create(0, alloc_size); + EXPECT_TRUE(vmo, "vmobject creation\n"); + + // create test buffer + utils::Array a(new uint8_t[alloc_size], alloc_size); + fill_region(99, a.get(), alloc_size); + + // write to it, make sure it seems to work with valid args + size_t bytes_written = -1; + status_t err = vmo->Write(a.get(), 0, 0, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(0u, bytes_written, "writing to object"); + + bytes_written = -1; + err = vmo->Write(a.get(), 0, 37, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(37u, bytes_written, "writing to object"); + + bytes_written = -1; + err = vmo->Write(a.get(), 99, 37, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(37u, bytes_written, "writing to object"); + + // should trim the returned size + bytes_written = -1; + err = vmo->Write(a.get(), 0, alloc_size + 47, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(alloc_size - 0, bytes_written, "writing to object"); + + bytes_written = -1; + err = vmo->Write(a.get(), 31, alloc_size + 47, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(alloc_size - 31, bytes_written, "writing to object"); + + // should return an error because out of range + bytes_written = -1; + err = vmo->Write(a.get(), alloc_size + 99, 42, &bytes_written); + EXPECT_EQ(ERR_OUT_OF_RANGE, err, "writing to object"); + EXPECT_EQ(0u, bytes_written, "writing to object"); + + // map the object + auto ka = VmAspace::kernel_aspace(); + uint8_t* ptr; + err = ka->MapObject(vmo, "test", 0, alloc_size, (void **)&ptr, 0, 0, PMM_ALLOC_FLAG_ANY); + EXPECT_EQ(NO_ERROR, err, "mapping object"); + + // write to it at odd offsets + bytes_written = -1; + err = vmo->Write(a.get(), 31, 4197, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(4197u, bytes_written, "writing to object"); + int cmpres = memcmp(ptr + 31, a.get(), 4197); + EXPECT_EQ(0, cmpres, "reading from object"); + + // write to it, filling the object completely + err = vmo->Write(a.get(), 0, alloc_size, &bytes_written); + EXPECT_EQ(NO_ERROR, err, "writing to object"); + EXPECT_EQ(alloc_size, bytes_written, "writing to object"); + + // test that the data was actually written to it + bool result = test_region(99, ptr, alloc_size); + EXPECT_TRUE(result, "writing to object"); + + // unmap it + ka->FreeRegion((vaddr_t)ptr); + + // test that we can read from it + printf("reading back from vm object\n"); + utils::Array b(new uint8_t[alloc_size], alloc_size); + + size_t bytes_read = -1; + err = vmo->Read(b.get(), 0, alloc_size, &bytes_read); + EXPECT_EQ(NO_ERROR, err, "reading from object"); + EXPECT_EQ(alloc_size, bytes_read, "reading from object"); + + // validate the buffer is valid + cmpres = memcmp(b.get(), a.get(), alloc_size); + EXPECT_EQ(0, cmpres, "reading from object"); + + // read from it at an offset + bytes_read = -1; + err = vmo->Read(b.get(), 31, 4197, &bytes_read); + EXPECT_EQ(NO_ERROR, err, "reading from object"); + EXPECT_EQ(4197u, bytes_read, "reading from object"); + cmpres = memcmp(b.get(), a.get() + 31, 4197); + EXPECT_EQ(0, cmpres, "reading from object"); + } + + printf("done with vmm object based tests\n"); + END_TEST; +} + +int vm_tests(int argc, const cmd_args* argv) { + pmm_tests(); + vmm_tests(); + vmm_object_tests(); + + return 0; +} diff --git a/kernel/app/usbtest/BUILD.gn b/kernel/app/usbtest/BUILD.gn new file mode 100644 index 000000000..42f9a5193 --- /dev/null +++ b/kernel/app/usbtest/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("usbtest") { + sources = [ + "descriptor.c", + "usbtest.c", + ] + deps = [ + "//kernel/dev/usb/client", + "//kernel/lib/libc", + ] +} diff --git a/kernel/app/usbtest/descriptor.c b/kernel/app/usbtest/descriptor.c new file mode 100644 index 000000000..955a9bfd5 --- /dev/null +++ b/kernel/app/usbtest/descriptor.c @@ -0,0 +1,114 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +#define W(w) (w & 0xff), (w >> 8) +#define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff) + +/* top level device descriptor */ +static const uint8_t dev_descr[] = { + 0x12, /* descriptor length */ + DEVICE, /* Device Descriptor type */ + W(0x0200), /* USB Version */ + 0xff, /* class */ + 0xff, /* subclass */ + 0xff, /* protocol */ + 64, /* max packet size, ept0 */ + W(0x9999), /* vendor */ + W(0x9999), /* product */ + W(0x9999), /* release */ + 0x0, /* manufacturer string */ + 0x0, /* product string */ + 0x0, /* serialno string */ + 0x1, /* num configs */ +}; + +/* high/low speed device qualifier */ +static const uint8_t devqual_descr[] = { + 0x0a, /* len */ + DEVICE_QUALIFIER, /* Device Qualifier type */ + W(0x0200), /* USB version */ + 0x00, /* class */ + 0x00, /* subclass */ + 0x00, /* protocol */ + 64, /* max packet size, ept0 */ + 0x01, /* num configs */ + 0x00 /* reserved */ +}; + +static const uint8_t cfg_descr[] = { + 0x09, /* Length of Cfg Descr */ + CONFIGURATION, /* Type of Cfg Descr */ + W(0x09), /* Total Length (incl ifc, ept) */ + 0x00, /* # Interfaces */ + 0x01, /* Cfg Value */ + 0x00, /* Cfg String */ + 0xc0, /* Attributes -- self powered */ + 250, /* Power Consumption - 500mA */ +}; + +static const uchar langid[] = { 0x04, 0x03, 0x09, 0x04 }; + +static const uint8_t if_descriptor_lowspeed[] = { + 0x09, /* length */ + INTERFACE, /* type */ + 0x01, /* interface num */ + 0x00, /* alternates */ + 0x02, /* endpoint count */ + 0xff, /* interface class */ + 0xff, /* interface subclass */ + 0x00, /* interface protocol */ + 0x00, /* string index */ + + /* endpoint 1 IN */ + 0x07, /* length */ + ENDPOINT, /* type */ + 0x81, /* address: 1 IN */ + 0x02, /* type: bulk */ + W(64), /* max packet size: 64 */ + 00, /* interval */ + + /* endpoint 1 OUT */ + 0x07, /* length */ + ENDPOINT, /* type */ + 0x01, /* address: 1 OUT */ + 0x02, /* type: bulk */ + W(64), /* max packet size: 64 */ + 00, /* interval */ +}; + +static usb_config config = { + .lowspeed = { + .device = USB_DESC_STATIC(dev_descr), + .device_qual = USB_DESC_STATIC(devqual_descr), + .config = USB_DESC_STATIC(cfg_descr), + }, + .highspeed = { + .device = USB_DESC_STATIC(dev_descr), + .device_qual = USB_DESC_STATIC(devqual_descr), + .config = USB_DESC_STATIC(cfg_descr), + }, + + .langid = USB_DESC_STATIC(langid), +}; + +void usbtest_usb_setup(void) +{ + usb_setup(&config); + printf("appending interfaces\n"); + usb_append_interface_lowspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed)); + usb_append_interface_highspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed)); + usbc_setup_endpoint(1, USB_OUT, 64); + usbc_setup_endpoint(1, USB_IN, 64); +} diff --git a/kernel/app/usbtest/rules.mk b/kernel/app/usbtest/rules.mk new file mode 100644 index 000000000..ffded9fd8 --- /dev/null +++ b/kernel/app/usbtest/rules.mk @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + dev/usb/client + +MODULE_SRCS += \ + $(LOCAL_DIR)/usbtest.c \ + $(LOCAL_DIR)/descriptor.c \ + +include make/module.mk + diff --git a/kernel/app/usbtest/usbtest.c b/kernel/app/usbtest/usbtest.c new file mode 100644 index 000000000..382614d5e --- /dev/null +++ b/kernel/app/usbtest/usbtest.c @@ -0,0 +1,136 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 1 + +extern void usbtest_usb_setup(void); + +static status_t rx_callback(ep_t endpoint, struct usbc_transfer *transfer); +static usbc_transfer_t rx; +static uint8_t rxbuf[4096]; +static volatile bool rxqueued; + +static status_t tx_callback(ep_t endpoint, struct usbc_transfer *transfer); +static usbc_transfer_t tx; +static uint8_t txbuf[4095]; +static volatile bool txqueued; + +static event_t testevent; + +/* RX */ +static void queue_rx_transfer(void) +{ + rx.callback = rx_callback; + rx.result = 0; + rx.buf = rxbuf; + rx.buflen = sizeof(rxbuf); + rx.bufpos = 0; + rx.extra = NULL; + + memset(rxbuf, 0x99, sizeof(rxbuf)); + + rxqueued = true; + usbc_queue_rx(1, &rx); +} + +static status_t rx_callback(ep_t endpoint, struct usbc_transfer *transfer) +{ + LTRACEF("ep %u, transfer %p\n", endpoint, transfer); + + rxqueued = false; + event_signal(&testevent, false); + + return NO_ERROR; +} + +/* TX */ +static void queue_tx_transfer(void) +{ + tx.callback = tx_callback; + tx.result = 0; + tx.buf = txbuf; + tx.buflen = sizeof(txbuf); + tx.bufpos = 0; + tx.extra = NULL; + + for (uint i = 0; i < sizeof(txbuf); i++) + txbuf[i] = i * 3; + + txqueued = true; + usbc_queue_tx(1, &tx); +} + +static status_t tx_callback(ep_t endpoint, struct usbc_transfer *transfer) +{ + LTRACEF("ep %u, transfer %p\n", endpoint, transfer); + + txqueued = false; + event_signal(&testevent, false); + + return NO_ERROR; +} + +static void usbtest_init(const struct app_descriptor *app) +{ + LTRACE_ENTRY; + event_init(&testevent, false, EVENT_FLAG_AUTOUNSIGNAL); + usbtest_usb_setup(); + LTRACE_EXIT; +} + +static void usbtest_entry(const struct app_descriptor *app, void *args) +{ + LTRACE_ENTRY; + + TRACEF("starting usb stack\n"); + usb_start(); + + // XXX get callback from stack + thread_sleep(2000); + + TRACEF("queuing transfers\n"); + queue_rx_transfer(); + queue_tx_transfer(); + + while (event_wait(&testevent) == NO_ERROR) { + if (!rxqueued) { + /* dump the state of the transfer */ + LTRACEF("rx transfer completed\n"); + usbc_dump_transfer(&rx); + hexdump8(rx.buf, MIN(128, rx.bufpos)); + + queue_rx_transfer(); + } + if (!txqueued) { + /* dump the state of the transfer */ + LTRACEF("tx transfer completed\n"); + usbc_dump_transfer(&tx); + + queue_tx_transfer(); + } + } + + LTRACE_EXIT; +} + +APP_START(usbtest) +.init = usbtest_init, + .entry = usbtest_entry, + APP_END + + diff --git a/kernel/arch/arm/BUILD.gn b/kernel/arch/arm/BUILD.gn new file mode 100644 index 000000000..690187701 --- /dev/null +++ b/kernel/arch/arm/BUILD.gn @@ -0,0 +1,61 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "arm") + +import("//gnbuild/config.gni") +import("//gnbuild/generate_ld_script.gni") + +module("arm") { + configs += [ + "//kernel/kernel:enable_vm", + "//kernel/lib/console:enable_console", + "//kernel/lib/magenta:enable_magenta", + ] + include_dirs = [ + "//kernel/dev/interrupt/include", + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + "//kernel/lib/magenta/include", + "//kernel/lib/user_copy/include", + "//system/ulib/magenta/include", + ] + + # These defines would be ideally defined as a config, but they're currently + # also shared by the ld script target and as such has to be defined as + # variable. + defines = kernel_defines + sources = [ + "arm/arch.c", + "arm/asm.S", + "arm/cache-ops.S", + "arm/cache.c", + "arm/debug.c", + "arm/exceptions.S", + "arm/faults.c", + "arm/fpu.c", + "arm/mmu.c", + "arm/ops.S", + "arm/start.S", + "arm/thread.c", + "arm/uspace_entry.S", + ] + deps = [ + ":onesegment_ld", + ] + if (enable_smp) { + include_dirs += [ "//kernel/dev/interrupt/include" ] + sources += [ "arm/mp.c" ] + deps += [ "//kernel/dev/interrupt/arm_gic" ] + } +} + +generate_ld_script("onesegment_ld") { + input = "system-onesegment.ld" + output = "${root_gen_dir}/system-onesegment.ld" + defines = kernel_defines +} diff --git a/kernel/arch/arm/arm-m/arch.c b/kernel/arch/arm/arm-m/arch.c new file mode 100644 index 000000000..7572686e7 --- /dev/null +++ b/kernel/arch/arm/arm-m/arch.c @@ -0,0 +1,152 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void *vectab; + +#if ARM_CM_DYNAMIC_PRIORITY_SIZE +unsigned int arm_cm_num_irq_pri_bits; +unsigned int arm_cm_irq_pri_mask; +#endif + +void arch_early_init(void) +{ + + arch_disable_ints(); + +#if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300) + uint i; + /* set the vector table base */ + SCB->VTOR = (uint32_t)&vectab; + +#if ARM_CM_DYNAMIC_PRIORITY_SIZE + /* number of priorities */ + for (i=0; i < 7; i++) { + __set_BASEPRI(1 << i); + if (__get_BASEPRI() != 0) + break; + } + arm_cm_num_irq_pri_bits = 8 - i; + arm_cm_irq_pri_mask = ~((1 << i) - 1) & 0xff; +#endif + + /* clear any pending interrupts and set all the vectors to medium priority */ + uint groups = (SCnSCB->ICTR & 0xf) + 1; + for (i = 0; i < groups; i++) { + NVIC->ICER[i] = 0xffffffff; + NVIC->ICPR[i] = 0xffffffff; + for (uint j = 0; j < 32; j++) { + NVIC_SetPriority(i*32 + j, arm_cm_medium_priority()); + } + } + + /* leave BASEPRI at 0 */ + __set_BASEPRI(0); + + /* set priority grouping to 0 */ + NVIC_SetPriorityGrouping(0); + + /* enable certain faults */ + SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk); + + /* set the svc and pendsv priority level to pretty low */ +#endif + NVIC_SetPriority(SVCall_IRQn, arm_cm_lowest_priority()); + NVIC_SetPriority(PendSV_IRQn, arm_cm_lowest_priority()); + + /* set systick and debugmonitor to medium priority */ + NVIC_SetPriority(SysTick_IRQn, arm_cm_medium_priority()); + +#if (__CORTEX_M >= 0x03) + NVIC_SetPriority(DebugMonitor_IRQn, arm_cm_medium_priority()); +#endif + +#if ARM_WITH_CACHE + arch_enable_cache(UCACHE); +#endif +} + +void arch_init(void) +{ +#if ENABLE_CYCLE_COUNTER + *REG32(SCB_DEMCR) |= 0x01000000; // global trace enable + *REG32(DWT_CYCCNT) = 0; + *REG32(DWT_CTRL) |= 1; // enable cycle counter +#endif +} + +void arch_quiesce(void) +{ +} + +void arch_idle(void) +{ + __asm__ volatile("wfi"); +} + +#if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300) + +void _arm_cm_set_irqpri(uint32_t pri) +{ + if (pri == 0) { + __disable_irq(); // cpsid i + __set_BASEPRI(0); + } else if (pri >= 256) { + __set_BASEPRI(0); + __enable_irq(); + } else { + uint32_t _pri = pri & arm_cm_irq_pri_mask; + + if (_pri == 0) + __set_BASEPRI(1 << (8 - arm_cm_num_irq_pri_bits)); + else + __set_BASEPRI(_pri); + __enable_irq(); // cpsie i + } +} +#endif + + +void arm_cm_irq_entry(void) +{ + // Set PRIMASK to 1 + // This is so that later calls to arch_ints_disabled() returns true while we're inside the int handler + // Note: this will probably screw up future efforts to stack higher priority interrupts since we're setting + // the cpu to essentially max interrupt priority here. Will have to rethink it then. + __disable_irq(); + + THREAD_STATS_INC(interrupts); + KEVLOG_IRQ_ENTER(__get_IPSR()); + + target_set_debug_led(1, true); +} + +void arm_cm_irq_exit(bool reschedule) +{ + target_set_debug_led(1, false); + + if (reschedule) + arm_cm_trigger_preempt(); + + KEVLOG_IRQ_EXIT(__get_IPSR()); + + __enable_irq(); // clear PRIMASK +} + +void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) +{ + PANIC_UNIMPLEMENTED; +} diff --git a/kernel/arch/arm/arm-m/cache.c b/kernel/arch/arm/arm-m/cache.c new file mode 100644 index 000000000..b1ebfb489 --- /dev/null +++ b/kernel/arch/arm/arm-m/cache.c @@ -0,0 +1,119 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +#if ARM_WITH_CACHE + +/* cache flushing routines for cortex-m cores that support it */ + +void arch_disable_cache(uint flags) +{ + if (flags & DCACHE) + SCB_DisableDCache(); + + if (flags & ICACHE) + SCB_DisableICache(); +} + +void arch_enable_cache(uint flags) +{ + if (flags & DCACHE) + SCB_EnableDCache(); + + if (flags & ICACHE) + SCB_EnableICache(); +} + +/* clean (writeback) data in the data cache on the range */ +void arch_clean_cache_range(addr_t start, size_t len) +{ + addr_t end = start + len; + + /* align the start address on CACHE_LINE boundary */ + start &= ~(CACHE_LINE - 1); + + SCB_CleanDCache_by_Addr((uint32_t *)start, end - start); +} + +/* clean (writeback) and then evict data from the data cache on the range */ +void arch_clean_invalidate_cache_range(addr_t start, size_t len) +{ + addr_t end = start + len; + + /* align the start address on CACHE_LINE boundary */ + start &= ~(CACHE_LINE - 1); + + SCB_CleanInvalidateDCache_by_Addr((uint32_t *)start, end - start); +} + +/* evict data from the data cache on the range */ +void arch_invalidate_cache_range(addr_t start, size_t len) +{ + addr_t end = start + len; + + /* align the start address on CACHE_LINE boundary */ + start &= ~(CACHE_LINE - 1); + + SCB_InvalidateDCache_by_Addr((uint32_t *)start, end - start); +} + +/* + * clean (writeback) data on the range and then throw away the instruction cache, + * ensuring that new instructions fetched from the range are not stale. + */ +void arch_sync_cache_range(addr_t start, size_t len) +{ + /* flush the dcache and invalidate the icache, ensuring fresh instructions */ + arch_clean_cache_range(start, len); + SCB_InvalidateICache(); +} + +#else + +/* doesn't support cache flush, just nop */ + +void arch_disable_cache(uint flags) +{ +} + +void arch_enable_cache(uint flags) +{ +} + +/* clean (writeback) data in the data cache on the range */ +void arch_clean_cache_range(addr_t start, size_t len) +{ +} + +/* clean (writeback) and then evict data from the data cache on the range */ +void arch_clean_invalidate_cache_range(addr_t start, size_t len) +{ +} + +/* evict data from the data cache on the range */ +void arch_invalidate_cache_range(addr_t start, size_t len) +{ +} + +/* + * clean (writeback) data on the range and then throw away the instruction cache, + * ensuring that new instructions fetched from the range are not stale. + */ +void arch_sync_cache_range(addr_t start, size_t len) +{ +} + +#endif // !ARM_WITH_CACHE + diff --git a/kernel/arch/arm/arm-m/exceptions.c b/kernel/arch/arm/arm-m/exceptions.c new file mode 100644 index 000000000..e04742772 --- /dev/null +++ b/kernel/arch/arm/arm-m/exceptions.c @@ -0,0 +1,234 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +static void dump_frame(const struct arm_cm_exception_frame *frame) +{ + + printf("exception frame at %p\n", frame); + printf("\tr0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x r4 0x%08x\n", + frame->r0, frame->r1, frame->r2, frame->r3, frame->r4); + printf("\tr5 0x%08x r6 0x%08x r7 0x%08x r8 0x%08x r9 0x%08x\n", + frame->r5, frame->r6, frame->r7, frame->r8, frame->r9); + printf("\tr10 0x%08x r11 0x%08x r12 0x%08x\n", + frame->r10, frame->r11, frame->r12); + printf("\tlr 0x%08x pc 0x%08x psr 0x%08x\n", + frame->lr, frame->pc, frame->psr); +} + +static void hardfault(struct arm_cm_exception_frame *frame) +{ + printf("hardfault: "); + dump_frame(frame); + +#if (__CORTEX_M >= 0X03) || (__CORTEX_SC >= 300) + printf("HFSR 0x%x\n", SCB->HFSR); +#endif + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} + +static void memmanage(struct arm_cm_exception_frame *frame) +{ + printf("memmanage: "); + dump_frame(frame); + +#if (__CORTEX_M >= 0X03) || (__CORTEX_SC >= 300) + uint32_t mmfsr = SCB->CFSR & 0xff; + + if (mmfsr & (1<<0)) { // IACCVIOL + printf("instruction fault\n"); + } + if (mmfsr & (1<<1)) { // DACCVIOL + printf("data fault\n"); + } + if (mmfsr & (1<<3)) { // MUNSTKERR + printf("fault on exception return\n"); + } + if (mmfsr & (1<<4)) { // MSTKERR + printf("fault on exception entry\n"); + } + if (mmfsr & (1<<5)) { // MLSPERR + printf("fault on lazy fpu preserve\n"); + } + if (mmfsr & (1<<7)) { // MMARVALID + printf("fault address 0x%x\n", SCB->MMFAR); + } +#endif + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} + + +static void usagefault(struct arm_cm_exception_frame *frame) +{ + printf("usagefault: "); + dump_frame(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} + +static void busfault(struct arm_cm_exception_frame *frame) +{ + printf("busfault: "); + dump_frame(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} + +/* raw exception vectors */ + +void _nmi(void) +{ + printf("nmi\n"); + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} +#if (__CORTEX_M >= 0X03) || (__CORTEX_SC >= 300) + +__NAKED void _hardfault(void) +{ + __asm__ volatile( + "push {r4-r11};" + "mov r0, sp;" + "b %0;" + :: "i" (hardfault) + ); + __UNREACHABLE; +} + +void _memmanage(void) +{ + __asm__ volatile( + "push {r4-r11};" + "mov r0, sp;" + "b %0;" + :: "i" (memmanage) + ); + __UNREACHABLE; +} + +void _busfault(void) +{ + __asm__ volatile( + "push {r4-r11};" + "mov r0, sp;" + "b %0;" + :: "i" (busfault) + ); + __UNREACHABLE; +} + +void _usagefault(void) +{ + __asm__ volatile( + "push {r4-r11};" + "mov r0, sp;" + "b %0;" + :: "i" (usagefault) + ); + __UNREACHABLE; +} +#else + +__NAKED void _hardfault(void) +{ + struct arm_cm_exception_frame *frame; + __asm__ volatile( + "push {r4-r7};" + "mov r4, r8;" + "mov r5, r9;" + "mov r6, r10;" + "mov r7, r11;" + "push {r4-r7};" + "mov %0, sp;" + : "=r" (frame): + ); + + printf("hardfault: "); + dump_frame(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); + __UNREACHABLE; +} + +void _memmanage(void) +{ + struct arm_cm_exception_frame *frame; + __asm__ volatile( + "push {r4-r7};" + "mov r4, r8;" + "mov r5, r9;" + "mov r6, r10;" + "mov r7, r11;" + "push {r4-r7};" + "mov %0, sp;" + : "=r" (frame): + ); + printf("memmanage: "); + dump_frame(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); + __UNREACHABLE; +} + +void _busfault(void) +{ + struct arm_cm_exception_frame *frame; + __asm__ volatile( + "push {r4-r7};" + "mov r4, r8;" + "mov r5, r9;" + "mov r6, r10;" + "mov r7, r11;" + "push {r4-r7};" + "mov %0, sp;" + : "=r" (frame): + ); + printf("busfault: "); + dump_frame(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); + __UNREACHABLE; +} + +void _usagefault(void) +{ + struct arm_cm_exception_frame *frame; + __asm__ volatile( + "push {r4-r7};" + "mov r4, r8;" + "mov r5, r9;" + "mov r6, r10;" + "mov r7, r11;" + "push {r4-r7};" + "mov %0, sp;" + : "=r" (frame): + ); + printf("usagefault: "); + dump_frame(frame); + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); + __UNREACHABLE; +} +#endif +/* systick handler */ +void __WEAK _systick(void) +{ + printf("systick\n"); + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} + +void __WEAK _debugmonitor(void) +{ + printf("debugmonitor\n"); + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} diff --git a/kernel/arch/arm/arm-m/include/arch/arch_thread.h b/kernel/arch/arm/arm-m/include/arch/arch_thread.h new file mode 100644 index 000000000..0cb413dbf --- /dev/null +++ b/kernel/arch/arm/arm-m/include/arch/arch_thread.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ARM_M_ARCH_THREAD_H +#define __ARM_M_ARCH_THREAD_H + +#include +#include + +struct arch_thread { + vaddr_t sp; + bool was_preempted; +}; + +#endif + diff --git a/kernel/arch/arm/arm-m/include/arch/arm/cm.h b/kernel/arch/arm/arm-m/include/arch/arm/cm.h new file mode 100644 index 000000000..f03efd61b --- /dev/null +++ b/kernel/arch/arm/arm-m/include/arch/arm/cm.h @@ -0,0 +1,173 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* support header for all cortex-m class cpus */ + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +#if ARM_CPU_CORTEX_M0 +#include +#elif ARM_CPU_CORTEX_M0_PLUS +#include +#elif ARM_CPU_CORTEX_M3 +#include +#elif ARM_CPU_CORTEX_M4 +#include +#elif ARM_CPU_CORTEX_M7 +#include +#else +#error "unknown cortex-m core" +#endif + +/* registers dealing with the cycle counter */ +#define DWT_CTRL (0xE0001000) +#define DWT_CYCCNT (0xE0001004) +#define SCB_DEMCR (0xE000EDFC) + +struct arm_cm_exception_frame { + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; +}; + +struct arm_cm_exception_frame_short { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; +}; + +struct arm_cm_exception_frame_long { + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t lr; + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t exc_lr; + uint32_t pc; + uint32_t psr; +}; + +#if ARM_CM_DYNAMIC_PRIORITY_SIZE +extern unsigned int arm_cm_num_irq_pri_bits; +extern unsigned int arm_cm_irq_pri_mask; +#else +/* if we don't want to calculate the nubmer of priority bits, then assume + * the cpu implements 3 (8 priority levels), which is the minimum according to spec. + */ +#ifndef __NVIC_PRIO_BITS +#define __NVIC_PRIO_BITS 3 +#endif +static const unsigned int arm_cm_num_irq_pri_bits = __NVIC_PRIO_BITS; +static const unsigned int arm_cm_irq_pri_mask = ~((1 << __NVIC_PRIO_BITS) - 1) & 0xff; +#endif + +#if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300) + +void _arm_cm_set_irqpri(uint32_t pri); + +static void arm_cm_set_irqpri(uint32_t pri) +{ + if (__ISCONSTANT(pri)) { + if (pri == 0) { + __disable_irq(); // cpsid i + __set_BASEPRI(0); + } else if (pri >= 256) { + __set_BASEPRI(0); + __enable_irq(); + } else { + uint32_t _pri = pri & arm_cm_irq_pri_mask; + + if (_pri == 0) + __set_BASEPRI(1 << (8 - arm_cm_num_irq_pri_bits)); + else + __set_BASEPRI(_pri); + __enable_irq(); // cpsie i + } + } else { + _arm_cm_set_irqpri(pri); + } +} +#endif + +static inline uint32_t arm_cm_highest_priority(void) +{ + return 0; +} + +static inline uint32_t arm_cm_lowest_priority(void) +{ + return (1 << arm_cm_num_irq_pri_bits) - 1; +} + +static inline uint32_t arm_cm_medium_priority(void) +{ + return (1 << (arm_cm_num_irq_pri_bits - 1)); +} + +#if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300) +static inline void arm_cm_trigger_interrupt(int vector) +{ + NVIC->STIR = vector; +} +#endif + + +static inline void arm_cm_trigger_preempt(void) +{ + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; +} + + + +/* systick */ +void arm_cm_systick_init(uint32_t mhz); +/* extern void _systick(void); // override this */ + +/* interrupt glue */ +/* + * Platform code should put this as the first and last line of their irq handlers. + * Pass true to reschedule to request a preempt. + */ +void arm_cm_irq_entry(void); +void arm_cm_irq_exit(bool reschedule); + +__END_CDECLS diff --git a/kernel/arch/arm/arm-m/spin_cycles.c b/kernel/arch/arm/arm-m/spin_cycles.c new file mode 100644 index 000000000..87e5bdbc8 --- /dev/null +++ b/kernel/arch/arm/arm-m/spin_cycles.c @@ -0,0 +1,88 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +__ALIGNED(8) __NAKED +#if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300) + +void spin_cycles(uint32_t cycles) +{ + asm ( + /* 4 cycles per loop, subtract out 8 cycles for the overhead of the next + * 4 instructions, plus the call into and return from the function. + * Then, add 3 then >> 2 to round up to the number of loop iterations. + */ + "subs r1, %[cycles], #5\n" + "asrs r1, r1, #2\n" + "ble .Ldone\n" + + /* Padding to stay aligned on an 8 byte boundary, also has the added + * advantage of normalizing the overhead (1+1+2 cycles if the branch is + * take, or 1+1+1+1 cycles if the branch is skipped and the nop is + * executed) + */ + "nop\n" + + /* Main delay loop. + * sub is 1 cycle + * nop is 1 cycle + * branch is 2 cycles + */ + ".Lloop:\n" + "subs r1, r1, #1\n" + "nop\n" + "bne .Lloop\n" + + ".Ldone:\n" + "bx lr\n" + : /* no output */ + : [cycles] "r" (cycles) /* input is cycles */ + : "r1" /* r1 gets clobbered */ + ); +} + +#else +/* Cortex-M0 & Cortex-M0+ */ +void spin_cycles(uint32_t cycles) +{ + asm ( + /* 4 cycles per loop, subtract out 8 cycles for the overhead of the next + * 4 instructions, plus the call into and return from the function. + * Then, add 3 then >> 2 to round up to the number of loop iterations. + */ + "sub r1, %[cycles], #5\n" + "asr r1, r1, #2\n" + "cmp r1, #0\n" + "ble .Ldone\n" + + /* Padding to stay aligned on an 8 byte boundary, also has the added + * advantage of normalizing the overhead (1+1+2 cycles if the branch is + * take, or 1+1+1+1 cycles if the branch is skipped and the nop is + * executed) + */ + "nop\n" + + /* Main delay loop. + * sub is 1 cycle + * nop is 1 cycle + * branch is 2 cycles + */ + ".Lloop:\n" + "sub r1, r1, #1\n" + "cmp r1,#0\n" + "bne .Lloop\n" + + ".Ldone:\n" + "bx lr\n" + : /* no output */ + : [cycles] "r" (cycles) /* input is cycles */ + : "r1" /* r1 gets clobbered */ + ); +} +#endif diff --git a/kernel/arch/arm/arm-m/start.c b/kernel/arch/arm/arm-m/start.c new file mode 100644 index 000000000..4500aef5f --- /dev/null +++ b/kernel/arch/arm/arm-m/start.c @@ -0,0 +1,35 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +/* externals */ +extern unsigned int __data_start_rom, __data_start, __data_end; +extern unsigned int __bss_start, __bss_end; + +extern void lk_main(void) __NO_RETURN __EXTERNALLY_VISIBLE; + +void _start(void) +{ + /* copy data from rom */ + if (&__data_start != &__data_start_rom) { + unsigned int *src = &__data_start_rom; + unsigned int *dest = &__data_start; + + while (dest != &__data_end) + *dest++ = *src++; + } + + /* zero out bss */ + unsigned int *bss = &__bss_start; + while (bss != &__bss_end) + *bss++ = 0; + + lk_main(); +} diff --git a/kernel/arch/arm/arm-m/systick/rules.mk b/kernel/arch/arm/arm-m/systick/rules.mk new file mode 100644 index 000000000..ab05677cd --- /dev/null +++ b/kernel/arch/arm/arm-m/systick/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/systick.c + +include make/module.mk diff --git a/kernel/arch/arm/arm-m/systick/systick.c b/kernel/arch/arm/arm-m/systick/systick.c new file mode 100644 index 000000000..a99b37b63 --- /dev/null +++ b/kernel/arch/arm/arm-m/systick/systick.c @@ -0,0 +1,130 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/* + * Generic systick timer support for providing system time (current_time(), current_time_hires()), + * and a monotonic timer for the kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +static volatile uint64_t ticks; +static uint32_t tick_rate = 0; +static uint32_t tick_rate_mhz = 0; +static lk_time_t tick_interval_ms; +static lk_bigtime_t tick_interval_us; + +static platform_timer_callback cb; +static void *cb_args; + +static void arm_cm_systick_set_periodic(lk_time_t period) +{ + LTRACEF("clk_freq %u, period %u\n", tick_rate, (uint)period); + + uint32_t ticks = tick_rate / (1000 / period); + LTRACEF("ticks %d\n", ticks); + + SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; + SysTick->VAL = 0; + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; +} + +static void arm_cm_systick_cancel_periodic(void) +{ + SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; +} + +/* main systick irq handler */ +void _systick(void) +{ + ticks++; + + arm_cm_irq_entry(); + + bool resched = false; + if (cb) { + lk_time_t now = current_time(); + if (cb(cb_args, now) == INT_RESCHEDULE) + resched = true; + } + + arm_cm_irq_exit(resched); +} + +status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) +{ + LTRACEF("callback %p, arg %p, interval %u\n", callback, arg, interval); + + DEBUG_ASSERT(tick_rate != 0 && tick_rate_mhz != 0); + + cb = callback; + cb_args = arg; + + tick_interval_ms = interval; + tick_interval_us = interval * 1000; + arm_cm_systick_set_periodic(interval); + + return NO_ERROR; +} + +lk_time_t current_time(void) +{ + uint32_t reload = SysTick->LOAD & SysTick_LOAD_RELOAD_Msk; + + uint64_t t; + uint32_t delta; + do { + t = ticks; + delta = (volatile uint32_t)SysTick->VAL; + DMB; + } while (ticks != t); + + /* convert ticks to msec */ + delta = (reload - delta) / (tick_rate_mhz * 1000); + lk_time_t res = (t * tick_interval_ms) + delta; + + return res; +} + +lk_bigtime_t current_time_hires(void) +{ + uint32_t reload = SysTick->LOAD & SysTick_LOAD_RELOAD_Msk; + + uint64_t t; + uint32_t delta; + do { + t = ticks; + delta = (volatile uint32_t)SysTick->VAL; + DMB; + } while (ticks != t); + + /* convert ticks to usec */ + delta = (reload - delta) / tick_rate_mhz; + lk_bigtime_t res = (t * tick_interval_us) + delta; + + return res; +} + +void arm_cm_systick_init(uint32_t mhz) +{ + tick_rate = mhz; + tick_rate_mhz = mhz / 1000000; +} diff --git a/kernel/arch/arm/arm-m/thread.c b/kernel/arch/arm/arm-m/thread.c new file mode 100644 index 000000000..3fe8c5e0c --- /dev/null +++ b/kernel/arch/arm/arm-m/thread.c @@ -0,0 +1,314 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct arm_cm_context_switch_frame { + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t lr; +}; + +/* since we're implicitly uniprocessor, store a pointer to the current thread here */ +thread_t *_current_thread; + +void arch_thread_initialize(struct thread *t, vaddr_t entry_point) +{ + LTRACEF("thread %p, stack %p\n", t, t->stack); + + /* find the top of the stack and align it on an 8 byte boundary */ + uint32_t *sp = (void *)ROUNDDOWN((vaddr_t)t->stack + t->stack_size, 8); + + struct arm_cm_context_switch_frame *frame = (void *)sp; + frame--; + + /* arrange for lr to point to our starting routine */ + frame->lr = (uint32_t)entry_point; + + t->arch.sp = (addr_t)frame; + t->arch.was_preempted = false; +} + +volatile struct arm_cm_exception_frame_long *preempt_frame; + +static void pendsv(struct arm_cm_exception_frame_long *frame) +{ + arch_disable_ints(); + + LTRACEF("preempting thread %p (%s)\n", _current_thread, _current_thread->name); + + /* save the iframe the pendsv fired on and hit the preemption code */ + preempt_frame = frame; + thread_preempt(); + + LTRACEF("fell through\n"); + + /* if we got here, there wasn't anything to switch to, so just fall through and exit */ + preempt_frame = NULL; + + arch_enable_ints(); +} + +/* + * raw pendsv exception handler, triggered by interrupt glue to schedule + * a preemption check. + */ +__NAKED void _pendsv(void) +{ + __asm__ volatile( +#if (__CORTEX_M >= 0x03) + + "push { r4-r11, lr };" + "mov r0, sp;" + "bl %0;" + "pop { r4-r11, lr };" + "bx lr;" +#else + "push { lr };" + "mov r0, r8;" + "mov r1, r9;" + "mov r2, r10;" + "mov r3, r11;" + "push { r0-r3 };" + "push { r4-r7 };" + "mov r0, sp;" + "bl %c0;" + "pop { r4-r7 };" + "pop { r0-r3 };" + "mov r8 , r0;" + "mov r9 , r1;" + "mov r10, r2;" + "mov r11, r3;" + "pop { r0 };" + "mov lr, r0;" + "bx lr;" +#endif + :: "i" (pendsv) + ); + __UNREACHABLE; +} +/* + * svc handler, used to hard switch the cpu into exception mode to return + * to preempted thread. + */ +__NAKED void _svc(void) +{ + __asm__ volatile( + /* load the pointer to the original exception frame we want to restore */ +#if (__CORTEX_M >= 0x03) + "mov sp, r4;" + "pop { r4-r11, lr };" + "bx lr;" +#else + "mov sp, r4;" + "pop { r4-r7 };" + "pop { r0-r3 };" + "mov r8 , r0;" + "mov r9 , r1;" + "mov r10, r2;" + "mov r11, r3;" + "pop { pc };" +#endif + ); +} + +__NAKED static void _half_save_and_svc(vaddr_t *fromsp, vaddr_t tosp) +{ + __asm__ volatile( +#if (__CORTEX_M >= 0x03) + + "push { r4-r11, lr };" + "str sp, [r0];" + + /* make sure we load the destination sp here before we reenable interrupts */ + "mov sp, r1;" + + "clrex;" + "cpsie i;" + + "mov r4, r1;" + "svc #0;" /* make a svc call to get us into handler mode */ + +#else + "push { lr };" + "mov r2, r10;" + "mov r3, r11;" + "push { r2-r3 };" + "mov r2, r8;" + "mov r3, r9;" + "push { r2-r3 };" + "push { r4-r7 };" + + "mov r3, sp;" + "str r3, [r0];" + "mov sp, r1;" + "cpsie i;" + + "mov r4, r1;" + "svc #0;" /* make a svc call to get us into handler mode */ +#endif + ); +} + +/* simple scenario where the to and from thread yielded */ +__NAKED static void _arch_non_preempt_context_switch(vaddr_t *fromsp, vaddr_t tosp) +{ + __asm__ volatile( +#if (__CORTEX_M >= 0x03) + "push { r4-r11, lr };" + "str sp, [r0];" + + "mov sp, r1;" + "pop { r4-r11, lr };" + "clrex;" + "bx lr;" +#else + "push { lr };" + "mov r2, r10;" + "mov r3, r11;" + "push { r2-r3 };" + "mov r2, r8;" + "mov r3, r9;" + "push { r2-r3 };" + "push { r4-r7 };" + + "mov r3, sp;" + "str r3, [r0];" + "mov sp, r1;" + + "pop { r4-r7 };" + "pop { r0-r3 };" + "mov r8 , r0;" + "mov r9 , r1;" + "mov r10, r2;" + "mov r11, r3;" + "pop { pc };" +#endif + ); +} + +__NAKED static void _thread_mode_bounce(void) +{ + __asm__ volatile( +#if (__CORTEX_M >= 0x03) + "pop { r4-r11, lr };" + "bx lr;" +#else + "pop { r4-r7 };" + "pop { r0-r3 };" + "mov r8 , r0;" + "mov r9 , r1;" + "mov r10, r2;" + "mov r11, r3;" + "pop { pc };" +#endif + ); + __UNREACHABLE; +} + +/* + * The raw context switch routine. Called by the scheduler when it decides to switch. + * Called either in the context of a thread yielding or blocking (interrupts disabled, + * on the system stack), or inside the pendsv handler on a thread that is being preempted + * (interrupts disabled, in handler mode). If preempt_frame is set the thread + * is being preempted. + */ +void arch_context_switch(struct thread *oldthread, struct thread *newthread) +{ + LTRACE_ENTRY; + + /* if preempt_frame is set, we are being preempted */ + if (preempt_frame) { + oldthread->arch.was_preempted = true; + oldthread->arch.sp = (addr_t)preempt_frame; + preempt_frame = NULL; + + LTRACEF("we're preempted, new %d\n", newthread->arch.was_preempted); + if (newthread->arch.was_preempted) { + /* return directly to the preempted thread's iframe */ + __asm__ volatile( + "mov sp, %0;" +#if (__CORTEX_M >= 0x03) + "cpsie i;" + "pop { r4-r11, lr };" + "clrex;" + "bx lr;" +#else + "cpsie i;" + "pop { r4-r7 };" + "pop { r0-r3 };" + "mov r8 , r0;" + "mov r9 , r1;" + "mov r10, r2;" + "mov r11, r3;" + "pop { pc };" +#endif + :: "r"(newthread->arch.sp) + ); + __UNREACHABLE; + } else { + /* we're inside a pendsv, switching to a user mode thread */ + /* set up a fake frame to exception return to */ + struct arm_cm_exception_frame_short *frame = (void *)newthread->arch.sp; + frame--; + + frame->pc = (uint32_t)&_thread_mode_bounce; + frame->psr = (1 << 24); /* thread bit set, IPSR 0 */ + frame->r0 = frame->r1 = frame->r2 = frame->r3 = frame->r12 = frame->lr = 99; + + LTRACEF("iretting to user space\n"); + //hexdump(frame, sizeof(*frame) + 64); + + __asm__ volatile( +#if (__CORTEX_M >= 0x03) + "clrex;" +#endif + "mov sp, %0;" + "bx %1;" + :: "r"(frame), "r"(0xfffffff9) + ); + __UNREACHABLE; + } + } else { + oldthread->arch.was_preempted = false; + + if (newthread->arch.was_preempted) { + LTRACEF("not being preempted, but switching to preempted thread\n"); + _half_save_and_svc(&oldthread->arch.sp, newthread->arch.sp); + } else { + /* fast path, both sides did not preempt */ + _arch_non_preempt_context_switch(&oldthread->arch.sp, newthread->arch.sp); + } + } + +} + +void arch_dump_thread(thread_t *t) +{ + if (t->state != THREAD_RUNNING) { + dprintf(INFO, "\tarch: "); + dprintf(INFO, "sp 0x%lx, was preempted %u\n", t->arch.sp, t->arch.was_preempted); + } +} + + diff --git a/kernel/arch/arm/arm-m/vectab.c b/kernel/arch/arm/arm-m/vectab.c new file mode 100644 index 000000000..33aa7017c --- /dev/null +++ b/kernel/arch/arm/arm-m/vectab.c @@ -0,0 +1,59 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +/* + * Make a nice 8 byte aligned stack to run on before the threading system is up. + * Put it in the .bss.prebss.* section to make sure it doesn't get wiped + * when bss is cleared a little ways into boot. + */ +static uint8_t initial_stack[1024] __SECTION(".bss.prebss.initial_stack") __ALIGNED(8); + +extern void _start(void); +extern void _nmi(void); +extern void _hardfault(void); +extern void _memmanage(void); +extern void _busfault(void); +extern void _usagefault(void); +extern void _svc(void); +extern void _debugmonitor(void); +extern void _pendsv(void); +extern void _systick(void); + +#if defined(WITH_DEBUGGER_INFO) +extern struct __debugger_info__ _debugger_info; +#endif + +const void *const __SECTION(".text.boot.vectab1") vectab[] = { + /* arm exceptions */ + initial_stack + sizeof(initial_stack), + _start, + _nmi, // nmi + _hardfault, // hard fault + _memmanage, // mem manage + _busfault, // bus fault + _usagefault, // usage fault + 0, // reserved +#if defined(WITH_DEBUGGER_INFO) + (void *) 0x52474244, + &_debugger_info, +#else + 0, // reserved + 0, // reserved +#endif + 0, // reserved + _svc, // svcall + _debugmonitor, // debug monitor + 0, // reserved + _pendsv, // pendsv + _systick, // systick +}; + + + diff --git a/kernel/arch/arm/arm/arch.c b/kernel/arch/arm/arm/arch.c new file mode 100644 index 000000000..5fd62bffe --- /dev/null +++ b/kernel/arch/arm/arm/arch.c @@ -0,0 +1,430 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#if WITH_DEV_TIMER_ARM_CORTEX_A9 +#include +#endif +#if WITH_DEV_INTERRUPT_ARM_GIC +#include +#endif +#if WITH_DEV_CACHE_PL310 +#include +#endif + +/* initial and abort stacks */ +uint8_t abort_stack[ARCH_DEFAULT_STACK_SIZE *SMP_MAX_CPUS] __CPU_ALIGN; + +static void arm_basic_setup(void); +static void spinlock_test(void); +static void spinlock_test_secondary(void); + +#if WITH_SMP +/* smp boot lock */ +spin_lock_t arm_boot_cpu_lock = 1; +volatile int secondaries_to_init = 0; +uint arm_num_cpus = 1; +#endif + +void arch_early_init(void) +{ + /* turn off the cache */ + arch_disable_cache(UCACHE); +#if WITH_DEV_CACHE_PL310 + pl310_set_enable(false); +#endif + + arm_basic_setup(); + +#if WITH_SMP && ARM_CPU_CORTEX_A9 + /* enable snoop control */ + addr_t scu_base = arm_read_cbar(); + *REG32(scu_base) |= (1<<0); /* enable SCU */ +#endif + +#if ARM_WITH_MMU + arm_mmu_early_init(); + + platform_init_mmu_mappings(); +#endif + + /* turn the cache back on */ +#if WITH_DEV_CACHE_PL310 + pl310_set_enable(true); +#endif + arch_enable_cache(UCACHE); +} + +void arch_init(void) +{ +#if WITH_SMP + arch_mp_init_percpu(); + + LTRACEF("midr 0x%x\n", arm_read_midr()); + LTRACEF("sctlr 0x%x\n", arm_read_sctlr()); + LTRACEF("actlr 0x%x\n", arm_read_actlr()); +#if ARM_CPU_CORTEX_A9 + LTRACEF("cbar 0x%x\n", arm_read_cbar()); +#endif + LTRACEF("mpidr 0x%x\n", arm_read_mpidr()); + LTRACEF("ttbcr 0x%x\n", arm_read_ttbcr()); + LTRACEF("ttbr0 0x%x\n", arm_read_ttbr0()); + LTRACEF("dacr 0x%x\n", arm_read_dacr()); +#if ARM_CPU_CORTEX_A7 + LTRACEF("l2ctlr 0x%x\n", arm_read_l2ctlr()); + LTRACEF("l2ectlr 0x%x\n", arm_read_l2ectlr()); +#endif + +#if ARM_CPU_CORTEX_A9 + addr_t scu_base = arm_read_cbar(); + uint32_t scu_config = *REG32(scu_base + 4); + secondaries_to_init = scu_config & 0x3; +#elif ARM_CPU_CORTEX_A7 || ARM_CPU_CORTEX_A15 + uint32_t l2ctlr = arm_read_l2ctlr(); + secondaries_to_init = (l2ctlr >> 24); +#else + secondaries_to_init = SMP_MAX_CPUS - 1; /* TODO: get count from somewhere else, or add cpus as they boot */ +#endif + arm_num_cpus += secondaries_to_init; + + lk_init_secondary_cpus(secondaries_to_init); + + /* in platforms where the cpus have already been started, go ahead and wake up all the + * secondary cpus here. + */ + dprintf(SPEW, "releasing %d secondary cpu%c\n", secondaries_to_init, secondaries_to_init != 1 ? 's' : ' '); + + /* release the secondary cpus */ + spin_unlock(&arm_boot_cpu_lock); + + /* flush the release of the lock, since the secondary cpus are running without cache on */ + arch_clean_cache_range((addr_t)&arm_boot_cpu_lock, sizeof(arm_boot_cpu_lock)); + +#if ARM_ARCH_WAIT_FOR_SECONDARIES + /* wait for secondary cpus to boot before arm_mmu_init below, which will remove + * temporary boot mappings + * TODO: find a cleaner way to do this than this #define + */ + while (secondaries_to_init > 0) { + arch_spinloop_pause(); + } +#endif +#endif // WITH_SMP + + //spinlock_test(); + +#if ARM_WITH_MMU + /* finish intializing the mmu */ + arm_mmu_init(); +#endif +} + +#if WITH_SMP +void arm_secondary_entry(uint asm_cpu_num) +{ + uint cpu = arch_curr_cpu_num(); + if (cpu != asm_cpu_num) + return; + + arm_basic_setup(); + + /* enable the local L1 cache */ + //arch_enable_cache(UCACHE); + + // XXX may not be safe, but just hard enable i and d cache here + // at the moment cannot rely on arch_enable_cache not dumping the L2 + uint32_t sctlr = arm_read_sctlr(); + sctlr |= (1<<12) | (1<<2); // enable i and dcache + arm_write_sctlr(sctlr); + + /* run early secondary cpu init routines up to the threading level */ + lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_THREADING - 1); + + arch_mp_init_percpu(); + + LTRACEF("cpu num %d\n", cpu); + LTRACEF("sctlr 0x%x\n", arm_read_sctlr()); + LTRACEF("actlr 0x%x\n", arm_read_actlr()); + + /* we're done, tell the main cpu we're up */ + atomic_add(&secondaries_to_init, -1); + smp_mb(); + arch_spinloop_signal(); + + lk_secondary_cpu_entry(); +} +#endif + +static void arm_basic_setup(void) +{ + uint32_t sctlr = arm_read_sctlr(); + + /* ARMV7 bits */ + sctlr &= ~(1<<10); /* swp disable */ + sctlr |= (1<<11); /* enable program flow prediction */ + sctlr &= ~(1<<14); /* random cache/tlb replacement */ + sctlr &= ~(1<<25); /* E bit set to 0 on exception */ + sctlr &= ~(1<<30); /* no thumb exceptions */ + + arm_write_sctlr(sctlr); + + uint32_t actlr = arm_read_actlr(); +#if ARM_CPU_CORTEX_A9 + actlr |= (1<<2); /* enable dcache prefetch */ +#if WITH_DEV_CACHE_PL310 + actlr |= (1<<7); /* L2 exclusive cache */ + actlr |= (1<<3); /* L2 write full line of zeroes */ + actlr |= (1<<1); /* L2 prefetch hint enable */ +#endif +#if WITH_SMP + /* enable smp mode, cache and tlb broadcast */ + actlr |= (1<<6) | (1<<0); +#endif +#endif // ARM_CPU_CORTEX_A9 +#if ARM_CPU_CORTEX_A7 +#if WITH_SMP + /* enable smp mode */ + actlr |= (1<<6); +#endif +#endif // ARM_CPU_CORTEX_A7 + + arm_write_actlr(actlr); + +#if ENABLE_CYCLE_COUNTER && ARM_ISA_ARMV7 + /* enable the cycle count register */ + uint32_t en; + __asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en)); + en &= ~(1<<3); /* cycle count every cycle */ + en |= 1; /* enable all performance counters */ + __asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en)); + + /* enable cycle counter */ + en = (1<<31); + __asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en)); +#endif + +#if ARM_WITH_VFP + /* enable cp10 and cp11 */ + uint32_t val = arm_read_cpacr(); + val |= (3<<22)|(3<<20); + arm_write_cpacr(val); + + /* set enable bit in fpexc */ + __asm__ volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (val)); + val |= (1<<30); + __asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val)); + + /* make sure the fpu starts off disabled */ + arm_fpu_set_enable(false); +#endif + + /* set the vector base to our exception vectors so we dont need to double map at 0 */ +#if ARM_ISA_ARMV7 + arm_write_vbar(KERNEL_BASE + KERNEL_LOAD_OFFSET); +#endif +} + +void arch_quiesce(void) +{ +#if ENABLE_CYCLE_COUNTER +#if ARM_ISA_ARMV7 + /* disable the cycle count and performance counters */ + uint32_t en; + __asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en)); + en &= ~1; /* disable all performance counters */ + __asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en)); + + /* disable cycle counter */ + en = 0; + __asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en)); +#endif +#if ARM_CPU_ARM1136 + /* disable the cycle count and performance counters */ + uint32_t en; + __asm__ volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (en)); + en &= ~1; /* disable all performance counters */ + __asm__ volatile("mcr p15, 0, %0, c15, c12, 0" :: "r" (en)); +#endif +#endif + + uint32_t actlr = arm_read_actlr(); +#if ARM_CPU_CORTEX_A9 + actlr = 0; /* put the aux control register back to default */ +#endif // ARM_CPU_CORTEX_A9 + arm_write_actlr(actlr); +} + +#if ARM_ISA_ARMV7 +/* virtual to physical translation */ +status_t arm_vtop(addr_t va, addr_t *pa) +{ + spin_lock_saved_state_t irqstate; + + arch_interrupt_save(&irqstate, SPIN_LOCK_FLAG_INTERRUPTS); + + arm_write_ats1cpr(va & ~(PAGE_SIZE-1)); + uint32_t par = arm_read_par(); + + arch_interrupt_restore(irqstate, SPIN_LOCK_FLAG_INTERRUPTS); + + if (par & 1) + return ERR_NOT_FOUND; + + if (pa) { + *pa = (par & 0xfffff000) | (va & 0xfff); + } + + return NO_ERROR; +} +#endif + +void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) +{ +/* disabled due to changing VMM interfaces. + * resurrect when the vmm is stabilized and the need for a chain load arises. + */ +#if 0 + LTRACEF("entry %p, args 0x%lx 0x%lx 0x%lx 0x%lx\n", entry, arg0, arg1, arg2, arg3); + + /* we are going to shut down the system, start by disabling interrupts */ + arch_disable_ints(); + + /* give target and platform a chance to put hardware into a suitable + * state for chain loading. + */ + target_quiesce(); + platform_quiesce(); + + paddr_t entry_pa; + paddr_t loader_pa; + +#if WITH_KERNEL_VM + /* get the physical address of the entry point we're going to branch to */ + if (arm_vtop((addr_t)entry, &entry_pa) < 0) { + panic("error translating entry physical address\n"); + } + + /* add the low bits of the virtual address back */ + entry_pa |= ((addr_t)entry & 0xfff); + + LTRACEF("entry pa 0x%lx\n", entry_pa); + + /* figure out the mapping for the chain load routine */ + if (arm_vtop((addr_t)&arm_chain_load, &loader_pa) < 0) { + panic("error translating loader physical address\n"); + } + + /* add the low bits of the virtual address back */ + loader_pa |= ((addr_t)&arm_chain_load & 0xfff); + + paddr_t loader_pa_section = ROUNDDOWN(loader_pa, SECTION_SIZE); + + LTRACEF("loader address %p, phys 0x%lx, surrounding large page 0x%lx\n", + &arm_chain_load, loader_pa, loader_pa_section); + + /* using large pages, map around the target location */ + arch_mmu_map(&vmm_get_kernel_aspace()->arch_aspace, loader_pa_section, loader_pa_section, (2 * SECTION_SIZE / PAGE_SIZE), 0); +#else + /* for non vm case, just branch directly into it */ + entry_pa = (paddr_t)entry; + loader_pa = (paddr_t)&arm_chain_load; +#endif + + LTRACEF("disabling instruction/data cache\n"); + arch_disable_cache(UCACHE); +#if WITH_DEV_CACHE_PL310 + pl310_set_enable(false); +#endif + + /* put the booting cpu back into close to a default state */ + arch_quiesce(); + + LTRACEF("branching to physical address of loader\n"); + + /* branch to the physical address version of the chain loader routine */ + void (*loader)(paddr_t entry, ulong, ulong, ulong, ulong) __NO_RETURN = (void *)loader_pa; + loader(entry_pa, arg0, arg1, arg2, arg3); +#else + PANIC_UNIMPLEMENTED; +#endif +} + +static spin_lock_t lock = 0; + +static void spinlock_test(void) +{ + TRACE_ENTRY; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + TRACEF("cpu0: i have the lock\n"); + spin(1000000); + TRACEF("cpu0: releasing it\n"); + + spin_unlock_irqrestore(&lock, state); + + spin(1000000); +} + +static void spinlock_test_secondary(void) +{ + TRACE_ENTRY; + + spin(500000); + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + TRACEF("cpu1: i have the lock\n"); + spin(250000); + TRACEF("cpu1: releasing it\n"); + + spin_unlock_irqrestore(&lock, state); +} + +/* switch to user mode, set the user stack pointer to user_stack_top, put the svc stack pointer to the top of the kernel stack */ +void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top, void *thread_arg) +{ + DEBUG_ASSERT(IS_ALIGNED(user_stack_top, 8)); + + thread_t *ct = get_current_thread(); + + vaddr_t kernel_stack_top = (uintptr_t)ct->stack + ct->stack_size; + kernel_stack_top = ROUNDDOWN(kernel_stack_top, 8); + + uint32_t spsr = CPSR_MODE_USR; + spsr |= (entry_point & 1) ? CPSR_THUMB : 0; + + arch_disable_ints(); + + extern void arm_uspace_entry(void *thread_arg, vaddr_t kstack, vaddr_t *ustack, uint32_t spsr, vaddr_t entry_point) __NO_RETURN; + arm_uspace_entry(thread_arg, kernel_stack_top, &user_stack_top, spsr, entry_point); + __UNREACHABLE; +} diff --git a/kernel/arch/arm/arm/asm.S b/kernel/arch/arm/arm/asm.S new file mode 100644 index 000000000..6d99f2da4 --- /dev/null +++ b/kernel/arch/arm/arm/asm.S @@ -0,0 +1,128 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + + /* context switch frame is as follows: + * lr + * r11 + * r10 + * r9 + * r8 + * r7 + * r6 + * r5 + * r4 + * cp15_ro + * cp15_rw + */ +/* arm_context_switch(addr_t *old_sp, addr_t new_sp) */ +FUNCTION(arm_context_switch) + /* save non callee trashed supervisor registers */ + /* spsr and user mode registers are saved and restored in the iframe by exceptions.S */ + mrc p15, 0, r2, c13, c0, 2 + mrc p15, 0, r3, c13, c0, 3 + push { r2-r11, lr } + + /* save old sp */ + str sp, [r0] + + /* clear any exlusive locks that the old thread holds */ +#if ARM_ARCH_LEVEL >= 7 + /* can clear it directly */ + clrex +#elif ARM_ARCH_LEVEL == 6 + /* have to do a fake strex to clear it */ + ldr r0, =strex_spot + strex r3, r2, [r0] +#endif + + /* load new regs */ + mov sp, r1 + pop { r2-r11, lr } + mcr p15, 0, r2, c13, c0, 2 + mcr p15, 0, r3, c13, c0, 3 + bx lr + +.ltorg + +#if ARM_ARCH_LEVEL == 6 +.data +strex_spot: + .word 0 +#endif + +.text + +FUNCTION(arm_save_mode_regs) + mrs r1, cpsr + + stmia r0, { r13, r14 }^ /* usr */ + add r0, #8 + + cps #0x11 /* fiq */ + str r13, [r0], #4 + str r14, [r0], #4 + + cps #0x12 /* irq */ + str r13, [r0], #4 + str r14, [r0], #4 + + cps #0x13 /* svc */ + str r13, [r0], #4 + str r14, [r0], #4 + + cps #0x17 /* abt */ + str r13, [r0], #4 + str r14, [r0], #4 + + cps #0x1b /* und */ + str r13, [r0], #4 + str r14, [r0], #4 + + cps #0x1f /* sys */ + str r13, [r0], #4 + str r14, [r0], #4 + + msr cpsr_c, r1 + + bx lr + +.text + +/* void arm_chain_load(paddr_t entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) __NO_RETURN; */ +/* shut down the system, branching into the secondary system */ +FUNCTION(arm_chain_load) + /* shuffle the args around */ + mov r4, r0 /* r4 = entry point */ + mov r0, r1 + mov r1, r2 + mov r2, r3 + ldr r3, [sp] + +#if WITH_KERNEL_VM +/* The MMU is initialized and running at this point, so we'll need to + * make sure we can disable it and continue to run. The caller should + * have built a identity map for us and branched to our identity mapping, + * so it will be safe to just disable the mmu and branch to the entry + * point in physical space. + */ + /* Read SCTLR */ + mrc p15, 0, r12, c1, c0, 0 + + /* Turn off the MMU */ + bic r12, #0x1 + + /* Write back SCTLR */ + mcr p15, 0, r12, c1, c0, 0 + isb + +#endif // WITH_KERNEL_VM + + /* call the entry point */ + bx r4 diff --git a/kernel/arch/arm/arm/cache-ops.S b/kernel/arch/arm/arm/cache-ops.S new file mode 100644 index 000000000..485630d6a --- /dev/null +++ b/kernel/arch/arm/arm/cache-ops.S @@ -0,0 +1,401 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +.text + +#if ARM_WITH_CACHE + +/* low level cache routines for various cpu families */ + +#if ARM_CPU_ARM1136 + +/* void arch_disable_cache(uint flags) */ +FUNCTION(arch_disable_cache) + mov r12, #0 // zero register + mrs r3, cpsr // save the old interrupt state + cpsid iaf // interrupts disabled + +.Ldcache_disable: + tst r0, #DCACHE + beq .Licache_disable + mrc p15, 0, r1, c1, c0, 0 // cr1 + tst r1, #(1<<2) // is the dcache already disabled? + beq .Licache_disable + + bic r1, #(1<<2) + mcr p15, 0, r1, c1, c0, 0 // disable dcache + + mcr p15, 0, r12, c7, c14, 0 // clean & invalidate dcache + mcr p15, 0, r0, c7, c10, 4 // data sync barrier (formerly drain write buffer) + +.Licache_disable: + tst r0, #ICACHE + beq .Ldone_disable + + mrc p15, 0, r1, c1, c0, 0 // cr1 + bic r1, #(1<<12) + mcr p15, 0, r1, c1, c0, 0 // disable icache + + mcr p15, 0, r12, c7, c5, 0 // invalidate icache + +.Ldone_disable: + msr cpsr, r3 + bx lr + +/* void arch_enable_cache(uint flags) */ +FUNCTION(arch_enable_cache) + mov r12, #0 // zero register + mrs r3, cpsr // save the old interrupt state + cpsid iaf // interrupts disabled + +.Ldcache_enable: + tst r0, #DCACHE + beq .Licache_enable + mrc p15, 0, r1, c1, c0, 0 // cr1 + tst r1, #(1<<2) // is the dcache already enabled? + bne .Licache_enable + + mcr p15, 0, r12, c7, c6, 0 // invalidate dcache + + orr r1, #(1<<2) + mcr p15, 0, r1, c1, c0, 0 // enable dcache + +.Licache_enable: + tst r0, #ICACHE + beq .Ldone_enable + + mcr p15, 0, r12, c7, c5, 0 // invalidate icache + + mrc p15, 0, r1, c1, c0, 0 // cr1 + orr r1, #(1<<12) + mcr p15, 0, r1, c1, c0, 0 // enable icache + +.Ldone_enable: + msr cpsr, r3 + bx lr + +#elif ARM_ISA_ARMV7 + +/* void arch_disable_cache(uint flags) */ +FUNCTION(arch_disable_cache) + stmfd sp!, {r4-r11, lr} + + mov r7, r0 // save flags + + mrs r8, cpsr // save the old interrupt state + cpsid iaf // interrupts disabled + +.Ldcache_disable: + tst r7, #DCACHE + beq .Licache_disable + mrc p15, 0, r0, c1, c0, 0 // cr1 + tst r0, #(1<<2) // is the dcache already disabled? + beq .Ldcache_already_disabled + + bic r0, #(1<<2) + mcr p15, 0, r0, c1, c0, 0 // disable dcache + + // flush and invalidate the dcache + // NOTE: trashes a bunch of registers, can't be spilling stuff to the stack + bl flush_invalidate_cache_v7 + + b .Ldcache_disable_L2 + +.Ldcache_already_disabled: + // make sure all of the caches are invalidated + // NOTE: trashes a bunch of registers, can't be spilling stuff to the stack + bl invalidate_cache_v7 + +.Ldcache_disable_L2: + +#if ARM_WITH_L2 + // disable the L2, if present + mrc p15, 0, r0, c1, c0, 1 // aux cr1 + bic r0, #(1<<1) + mcr p15, 0, r0, c1, c0, 1 // disable L2 dcache +#endif + +.Licache_disable: + tst r7, #ICACHE + beq .Ldone_disable + + mrc p15, 0, r0, c1, c0, 0 // cr1 + bic r0, #(1<<12) + mcr p15, 0, r0, c1, c0, 0 // disable icache + +.Ldone_disable: + // make sure the icache is always invalidated + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 // invalidate icache to PoU + + msr cpsr, r8 + ldmfd sp!, {r4-r11, pc} + +/* void arch_enable_cache(uint flags) */ +FUNCTION(arch_enable_cache) + stmfd sp!, {r4-r12, lr} + + mov r7, r0 // save flags + + mrs r8, cpsr // save the old interrupt state + cpsid iaf // interrupts disabled + +.Ldcache_enable: + tst r7, #DCACHE + beq .Licache_enable + mrc p15, 0, r0, c1, c0, 0 // cr1 + tst r0, #(1<<2) // is the dcache already enabled? + bne .Licache_enable + + // invalidate L1 and L2 + // NOTE: trashes a bunch of registers, can't be spilling stuff to the stack + bl invalidate_cache_v7 + +#if ARM_WITH_L2 + // enable the L2, if present + mrc p15, 0, r0, c1, c0, 1 // aux cr1 + orr r0, #(1<<1) + mcr p15, 0, r0, c1, c0, 1 // enable L2 dcache +#endif + + mrc p15, 0, r0, c1, c0, 0 // cr1 + orr r0, #(1<<2) + mcr p15, 0, r0, c1, c0, 0 // enable dcache + +.Licache_enable: + tst r7, #ICACHE + beq .Ldone_enable + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 // invalidate icache to PoU + + mrc p15, 0, r0, c1, c0, 0 // cr1 + orr r0, #(1<<12) + mcr p15, 0, r0, c1, c0, 0 // enable icache + +.Ldone_enable: + isb + msr cpsr, r8 + ldmfd sp!, {r4-r12, pc} + +// flush & invalidate cache routine, trashes r0-r6, r9-r11 +flush_invalidate_cache_v7: + /* from ARMv7 manual, B2-17 */ + dmb + MRC p15, 1, R0, c0, c0, 1 // Read CLIDR + ANDS R3, R0, #0x7000000 + MOV R3, R3, LSR #23 // Cache level value (naturally aligned) + BEQ .Lfinished + MOV R10, #0 +.Loop1: + ADD R2, R10, R10, LSR #1 // Work out 3xcachelevel + MOV R1, R0, LSR R2 // bottom 3 bits are the Cache type for this level + AND R1, R1, #7 // get those 3 bits alone + CMP R1, #2 + BLT .Lskip // no cache or only instruction cache at this level + MCR p15, 2, R10, c0, c0, 0 // write the Cache Size selection register + isb // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, R1, c0, c0, 0 // reads current Cache Size ID register + AND R2, R1, #0x7 // extract the line length field + ADD R2, R2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR R4, =0x3FF + ANDS R4, R4, R1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ R5, R4 // R5 is the bit position of the way size increment + LDR R6, =0x00007FFF + ANDS R6, R6, R1, LSR #13 // R6 is the max number of the index size (right aligned) +.Loop2: + MOV R9, R4 // R9 working copy of the max way size (right aligned) +.Loop3: + ORR R11, R10, R9, LSL R5 // factor in the way number and cache number into R11 + ORR R11, R11, R6, LSL R2 // factor in the index number + MCR p15, 0, R11, c7, c14, 2 // clean & invalidate by set/way + SUBS R9, R9, #1 // decrement the way number + BGE .Loop3 + SUBS R6, R6, #1 // decrement the index + BGE .Loop2 +.Lskip: + ADD R10, R10, #2 // increment the cache number + CMP R3, R10 + BGT .Loop1 + +.Lfinished: + mov r10, #0 + mcr p15, 2, r10, c0, c0, 0 // select cache level 0 + dsb + isb + + bx lr + +// invalidate cache routine, trashes r0-r6, r9-r11 +invalidate_cache_v7: + /* from ARMv7 manual, B2-17 */ + dmb + MRC p15, 1, R0, c0, c0, 1 // Read CLIDR + ANDS R3, R0, #0x7000000 + MOV R3, R3, LSR #23 // Cache level value (naturally aligned) + BEQ .Lfinished_invalidate + MOV R10, #0 +.Loop1_invalidate: + ADD R2, R10, R10, LSR #1 // Work out 3xcachelevel + MOV R1, R0, LSR R2 // bottom 3 bits are the Cache type for this level + AND R1, R1, #7 // get those 3 bits alone + CMP R1, #2 + BLT .Lskip_invalidate // no cache or only instruction cache at this level + MCR p15, 2, R10, c0, c0, 0 // write the Cache Size selection register + isb // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, R1, c0, c0, 0 // reads current Cache Size ID register + AND R2, R1, #0x7 // extract the line length field + ADD R2, R2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR R4, =0x3FF + ANDS R4, R4, R1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ R5, R4 // R5 is the bit position of the way size increment + LDR R6, =0x00007FFF + ANDS R6, R6, R1, LSR #13 // R6 is the max number of the index size (right aligned) +.Loop2_invalidate: + MOV R9, R4 // R9 working copy of the max way size (right aligned) +.Loop3_invalidate: + ORR R11, R10, R9, LSL R5 // factor in the way number and cache number into R11 + ORR R11, R11, R6, LSL R2 // factor in the index number + MCR p15, 0, R11, c7, c6, 2 // invalidate by set/way + SUBS R9, R9, #1 // decrement the way number + BGE .Loop3_invalidate + SUBS R6, R6, #1 // decrement the index + BGE .Loop2_invalidate +.Lskip_invalidate: + ADD R10, R10, #2 // increment the cache number + CMP R3, R10 + BGT .Loop1_invalidate + +.Lfinished_invalidate: + dsb + mov r10, #0 + mcr p15, 2, r10, c0, c0, 0 // select cache level 0 + isb + + bx lr + +#else +#error unhandled cpu +#endif + +#if ARM_CPU_ARM926 || ARM_CPU_ARM1136 || ARM_ISA_ARMV7 +/* shared cache flush routines */ + + /* void arch_flush_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_clean_cache_range) +#if ARM_WITH_CP15 + mov r3, r0 // save the start address + add r2, r0, r1 // calculate the end address + bic r0, #(CACHE_LINE-1) // align the start with a cache line +0: + mcr p15, 0, r0, c7, c10, 1 // clean cache to PoC by MVA + add r0, #CACHE_LINE + cmp r0, r2 + blo 0b + +#if ARM_ISA_ARMV7 + dsb +#else + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 // data sync barrier +#endif +#endif +#if WITH_DEV_CACHE_PL310 + mov r0, r3 // put the start address back + b pl310_clean_range +#else + bx lr +#endif + + /* void arch_flush_invalidate_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_clean_invalidate_cache_range) +#if ARM_WITH_CP15 + mov r3, r0 // save the start address + add r2, r0, r1 // calculate the end address + bic r0, #(CACHE_LINE-1) // align the start with a cache line +0: + mcr p15, 0, r0, c7, c14, 1 // clean & invalidate dcache to PoC by MVA + add r0, r0, #CACHE_LINE + cmp r0, r2 + blo 0b + +#if ARM_ISA_ARMV7 + dsb +#else + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 // data sync barrier +#endif +#endif +#if WITH_DEV_CACHE_PL310 + mov r0, r3 // put the start address back + b pl310_clean_invalidate_range +#else + bx lr +#endif + + /* void arch_invalidate_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_invalidate_cache_range) +#if ARM_WITH_CP15 + mov r3, r0 // save the start address + add r2, r0, r1 // calculate the end address + bic r0, #(CACHE_LINE-1) // align the start with a cache line +0: + mcr p15, 0, r0, c7, c6, 1 // invalidate dcache to PoC by MVA + add r0, r0, #CACHE_LINE + cmp r0, r2 + blo 0b + +#if ARM_ISA_ARMV7 + dsb +#else + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 // data sync barrier +#endif +#endif +#if WITH_DEV_CACHE_PL310 + mov r0, r3 // put the start address back + b pl310_invalidate_range +#else + bx lr +#endif + + /* void arch_sync_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_sync_cache_range) + push { r14 } + bl arch_clean_cache_range + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 // invalidate icache to PoU + + pop { pc } + +#endif // ARM_CPU_... + +#else + +/* no cache */ + +FUNCTION(arch_disable_cache) + bx lr + +FUNCTION(arch_enable_cache) + bx lr + +FUNCTION(arch_clean_cache_range) + bx lr + +FUNCTION(arch_clean_invalidate_cache_range) + bx lr + +FUNCTION(arch_sync_cache_range) + bx lr + +#endif // ARM_WITH_CACHE diff --git a/kernel/arch/arm/arm/cache.c b/kernel/arch/arm/arm/cache.c new file mode 100644 index 000000000..76dbc43bc --- /dev/null +++ b/kernel/arch/arm/arm/cache.c @@ -0,0 +1,7 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + diff --git a/kernel/arch/arm/arm/debug.c b/kernel/arch/arm/arm/debug.c new file mode 100644 index 000000000..27b46ee77 --- /dev/null +++ b/kernel/arch/arm/arm/debug.c @@ -0,0 +1,195 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dcc_state { + dcc_rx_callback_t rx_callback; + mutex_t lock; + thread_t *worker; +}; + +#define SLOW_POLL_RATE 100 +#define FAST_POLL_TIMEOUT 5 + +static int dcc_worker_entry(void *arg) +{ + struct dcc_state *dcc = (struct dcc_state *)arg; + lk_time_t fast_poll_start; + bool fast_poll; + + fast_poll = false; + for (;;) { + // wait for a bit if we're in slow poll mode + if (!fast_poll) { + thread_sleep(SLOW_POLL_RATE); + } + + if (arm_dcc_read_available()) { + uint32_t val = arm_read_dbgdtrrxint(); + + dcc->rx_callback(val); + + // we just received something, so go to a faster poll rate + fast_poll = true; + fast_poll_start = current_time(); + } else { + // didn't see anything + if (fast_poll && current_time() - fast_poll_start >= FAST_POLL_TIMEOUT) { + fast_poll = false; // go back to slow poll + } + } + } + + return 0; +} + +status_t arm_dcc_enable(dcc_rx_callback_t rx_callback) +{ + struct dcc_state *state = malloc(sizeof(struct dcc_state)); + if (!state) + return ERR_NO_MEMORY; + + state->rx_callback = rx_callback; + mutex_init(&state->lock); + + state->worker = thread_create("dcc worker", dcc_worker_entry, state, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(state->worker); + + return NO_ERROR; +} + +bool arm_dcc_read_available(void) +{ + uint32_t dscr = arm_read_dbgdscr(); + if (dscr & (1<<30)) { // rx full + return true; + } else { + return false; + } +} + +ssize_t arm_dcc_read(uint32_t *buf, size_t len, lk_time_t timeout) +{ + lk_time_t start = 0; + + if (timeout != 0) + start = current_time(); + + ssize_t count = 0; + while (count < (ssize_t)len) { + + uint32_t dscr = arm_read_dbgdscr(); + if (dscr & (1<<30)) { // rx full + uint32_t val = arm_read_dbgdtrrxint(); + *buf++ = val; + + count++; + } else { + if (timeout == 0 || current_time() - start >= timeout) { + break; + } + } + } + + return count; +} + +ssize_t arm_dcc_write(const uint32_t *buf, size_t len, lk_time_t timeout) +{ + lk_time_t start = 0; + + if (timeout != 0) + start = current_time(); + + ssize_t count = 0; + while (count < (ssize_t)len) { + + uint32_t dscr = arm_read_dbgdscr(); + if ((dscr & (1<<29)) == 0) { // tx empty + arm_write_dbgdtrrxint(*buf); + count++; + buf++; + } else { + if (timeout == 0 || current_time() - start >= timeout) { + break; + } + } + } + + return count; +} + +#if WITH_LIB_CONSOLE +#include +#include + +static void dcc_rx_callback(uint32_t val) +{ + static int count = 0; + count += 4; + if ((count % 1000) == 0) + printf("count %d\n", count); +} + +static int cmd_dcc(int argc, const cmd_args *argv) +{ + static bool dcc_started = false; + + if (argc < 2) { + printf("not enough args\n"); + return -1; + } + + if (!strcmp(argv[1].str, "start")) { + if (!dcc_started) { + printf("starting dcc\n"); + + status_t err = arm_dcc_enable(&dcc_rx_callback); + printf("arm_dcc_enable returns %d\n", err); + dcc_started = true; + } + } else if (!strcmp(argv[1].str, "write")) { + for (int i = 2; i < argc; i++) { + uint32_t buf[128]; + size_t len = strlen(argv[i].str); + for (uint j = 0; j < len; j++) { + buf[j] = argv[i].str[j]; + } + arm_dcc_write(buf, strlen(argv[i].str), 1000); + } + } else if (!strcmp(argv[1].str, "read")) { + uint32_t buf[128]; + + ssize_t len = arm_dcc_read(buf, sizeof(buf), 1000); + printf("arm_dcc_read returns %ld\n", len); + if (len > 0) { + hexdump(buf, len); + } + } else { + printf("unknown args\n"); + } + + return 0; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND("dcc", "dcc stuff", &cmd_dcc) +#endif +STATIC_COMMAND_END(dcc); + +#endif + diff --git a/kernel/arch/arm/arm/exceptions.S b/kernel/arch/arm/arm/exceptions.S new file mode 100644 index 000000000..99705c858 --- /dev/null +++ b/kernel/arch/arm/arm/exceptions.S @@ -0,0 +1,243 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +/* exception handling glue. + * NOTE: only usable on armv6+ cores + */ + +#define TIMESTAMP_IRQ 0 + +/* macros to align and unalign the stack on 8 byte boundary for ABI compliance */ +.macro stack_align, tempreg + /* make sure the stack is aligned */ + mov \tempreg, sp + tst sp, #4 + subeq sp, #4 + push { \tempreg } + + /* tempreg holds the original stack */ +.endm + +.macro stack_restore, tempreg + /* restore the potentially unaligned stack */ + pop { \tempreg } + mov sp, \tempreg +.endm + +/* save and disable the vfp unit */ +.macro vfp_save, temp1 + /* save old fpexc */ + vmrs \temp1, fpexc + + push { \temp1 } + + /* hard disable the vfp unit */ + bic \temp1, #(1<<30) + vmsr fpexc, \temp1 +.endm + +/* restore the vfp enable/disable state */ +.macro vfp_restore, temp1 + /* restore fpexc */ + pop { \temp1 } + + vmsr fpexc, \temp1 +.endm + +/* Save callee trashed registers. + * At exit r0 contains a pointer to the register frame. + */ +.macro save + /* save spsr and r14 onto the svc stack */ + srsdb #0x13! + + /* switch to svc mode, interrupts disabled */ + cpsid i,#0x13 + + /* save callee trashed regs and lr */ + push { r0-r3, r12, lr } + + /* save user space sp/lr */ + sub sp, #8 + stmia sp, { r13, r14 }^ + +#if ARM_WITH_VFP + /* save and disable the vfp unit */ + vfp_save r0 +#endif + + /* make sure the stack is 8 byte aligned */ + stack_align r0 + + /* r0 now holds the pointer to the original iframe (before alignment) */ +.endm + +.macro save_offset, offset + sub lr, \offset + save +.endm + +.macro restore + /* undo the stack alignment we did before */ + stack_restore r0 + +#if ARM_WITH_VFP + /* restore the old state of the vfp unit */ + vfp_restore r0 +#endif + + /* restore user space sp/lr */ + ldmia sp, { r13, r14 }^ + add sp, #8 + + pop { r0-r3, r12, lr } + + /* return to whence we came from */ + rfeia sp! +.endm + +/* Save all registers. + * At exit r0 contains a pointer to the register frame. + */ +.macro saveall + /* save spsr and r14 onto the svc stack */ + srsdb #0x13! + + /* switch to svc mode, interrupts disabled */ + cpsid i,#0x13 + + /* save all regs */ + push { r0-r12, lr } + + /* save user space sp/lr */ + sub sp, #8 + stmia sp, { r13, r14 }^ + +#if ARM_WITH_VFP + /* save and disable the vfp unit */ + vfp_save r0 +#endif + + /* make sure the stack is 8 byte aligned */ + stack_align r0 + + /* r0 now holds the pointer to the original iframe (before alignment) */ +.endm + +.macro saveall_offset, offset + sub lr, \offset + saveall +.endm + +.macro restoreall + /* undo the stack alignment we did before */ + stack_restore r0 + +#if ARM_WITH_VFP + /* restore the old state of the vfp unit */ + vfp_restore r0 +#endif + + /* restore user space sp/lr */ + ldmia sp, { r13, r14 }^ + add sp, #8 + + pop { r0-r12, r14 } + + /* return to whence we came from */ + rfeia sp! +.endm + +FUNCTION(arm_undefined) + save + /* r0 now holds pointer to iframe */ + + bl arm_undefined_handler + + restore + +#ifndef WITH_LIB_SYSCALL +FUNCTION(arm_syscall) + saveall + /* r0 now holds pointer to iframe */ + + bl arm_syscall_handler + + restoreall +#endif + +FUNCTION(arm_prefetch_abort) + saveall_offset #4 + /* r0 now holds pointer to iframe */ + + bl arm_prefetch_abort_handler + + restoreall + +FUNCTION(arm_data_abort) + saveall_offset #8 + /* r0 now holds pointer to iframe */ + + bl arm_data_abort_handler + + restoreall + +FUNCTION(arm_reserved) + b . + +FUNCTION(arm_irq) +#if TIMESTAMP_IRQ + /* read the cycle count */ + mrc p15, 0, sp, c9, c13, 0 + str sp, [pc, #__irq_cycle_count - . - 8] +#endif + + save_offset #4 + + /* r0 now holds pointer to iframe */ + + /* track that we're inside an irq handler */ + LOADCONST(r2, __arm_in_handler) + mov r1, #1 + str r1, [r2] + + /* call into higher level code */ + bl platform_irq + + /* clear the irq handler status */ + LOADCONST(r1, __arm_in_handler) + mov r2, #0 + str r2, [r1] + + /* reschedule if the handler returns nonzero */ + cmp r0, #0 + blne thread_preempt + + restore + +FUNCTION(arm_fiq) + save_offset #4 + /* r0 now holds pointer to iframe */ + + bl platform_fiq + + restore + +.ltorg + +#if TIMESTAMP_IRQ +DATA(__irq_cycle_count) + .word 0 +#endif + +.data +DATA(__arm_in_handler) + .word 0 diff --git a/kernel/arch/arm/arm/faults.c b/kernel/arch/arm/arm/faults.c new file mode 100644 index 000000000..60e3b2075 --- /dev/null +++ b/kernel/arch/arm/arm/faults.c @@ -0,0 +1,398 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +#if WITH_LIB_MAGENTA +#include +#include +#endif + +struct fault_handler_table_entry { + uint32_t pc; + uint32_t fault_handler; +}; + +extern struct fault_handler_table_entry __fault_handler_table_start[]; +extern struct fault_handler_table_entry __fault_handler_table_end[]; + +static void dump_mode_regs(uint32_t spsr, uint32_t svc_r13, uint32_t svc_r14) +{ + struct arm_mode_regs regs; + arm_save_mode_regs(®s); + + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((spsr & CPSR_MODE_MASK) == CPSR_MODE_USR) ? '*' : ' ', "usr", regs.usr_r13, regs.usr_r14); + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((spsr & CPSR_MODE_MASK) == CPSR_MODE_FIQ) ? '*' : ' ', "fiq", regs.fiq_r13, regs.fiq_r14); + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((spsr & CPSR_MODE_MASK) == CPSR_MODE_IRQ) ? '*' : ' ', "irq", regs.irq_r13, regs.irq_r14); + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", 'a', "svc", regs.svc_r13, regs.svc_r14); + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((spsr & CPSR_MODE_MASK) == CPSR_MODE_SVC) ? '*' : ' ', "svc", svc_r13, svc_r14); + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((spsr & CPSR_MODE_MASK) == CPSR_MODE_UND) ? '*' : ' ', "und", regs.und_r13, regs.und_r14); + dprintf(CRITICAL, "%c%s r13 0x%08x r14 0x%08x\n", ((spsr & CPSR_MODE_MASK) == CPSR_MODE_SYS) ? '*' : ' ', "sys", regs.sys_r13, regs.sys_r14); + + // dump the bottom of the current stack + addr_t stack; + switch (spsr & CPSR_MODE_MASK) { + case CPSR_MODE_FIQ: + stack = regs.fiq_r13; + break; + case CPSR_MODE_IRQ: + stack = regs.irq_r13; + break; + case CPSR_MODE_SVC: + stack = svc_r13; + break; + case CPSR_MODE_UND: + stack = regs.und_r13; + break; + case CPSR_MODE_SYS: + stack = regs.sys_r13; + break; + default: + stack = 0; + } + + if (stack != 0) { + dprintf(CRITICAL, "bottom of stack at 0x%08x:\n", (unsigned int)stack); + hexdump((void *)stack, 128); + } +} + +static void dump_fault_frame(struct arm_fault_frame *frame) +{ + struct thread *current_thread = get_current_thread(); + + dprintf(CRITICAL, "current_thread %p, name %s\n", + current_thread, current_thread ? current_thread->name : ""); + + dprintf(CRITICAL, "r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n", frame->r[0], frame->r[1], frame->r[2], frame->r[3]); + dprintf(CRITICAL, "r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", frame->r[4], frame->r[5], frame->r[6], frame->r[7]); + dprintf(CRITICAL, "r8 0x%08x r9 0x%08x r10 0x%08x r11 0x%08x\n", frame->r[8], frame->r[9], frame->r[10], frame->r[11]); + dprintf(CRITICAL, "r12 0x%08x usp 0x%08x ulr 0x%08x pc 0x%08x\n", frame->r[12], frame->usp, frame->ulr, frame->pc); + dprintf(CRITICAL, "spsr 0x%08x\n", frame->spsr); + + dump_mode_regs(frame->spsr, (uintptr_t)(frame + 1), frame->lr); +} + +static void dump_iframe(struct arm_iframe *frame) +{ + dprintf(CRITICAL, "r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n", frame->r0, frame->r1, frame->r2, frame->r3); + dprintf(CRITICAL, "r12 0x%08x usp 0x%08x ulr 0x%08x pc 0x%08x\n", frame->r12, frame->usp, frame->ulr, frame->pc); + dprintf(CRITICAL, "spsr 0x%08x\n", frame->spsr); + + dump_mode_regs(frame->spsr, (uintptr_t)(frame + 1), frame->lr); +} + +static void exception_die(struct arm_fault_frame *frame, const char *msg) +{ + dprintf(CRITICAL, msg); + dump_fault_frame(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); + for (;;); +} + +static void exception_die_iframe(struct arm_iframe *frame, const char *msg) +{ + dprintf(CRITICAL, msg); + dump_iframe(frame); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); + for (;;); +} + +__WEAK void arm_syscall_handler(struct arm_fault_frame *frame) +{ + exception_die(frame, "unhandled syscall, halting\n"); +} + +#if WITH_LIB_MAGENTA +struct arch_exception_context { + bool iframe; + void *frame; +}; +#endif + +void arm_undefined_handler(struct arm_iframe *frame) +{ + /* look at the undefined instruction, figure out if it's something we can handle */ + bool in_thumb = frame->spsr & (1<<5); + if (in_thumb) { + frame->pc -= 2; + } else { + frame->pc -= 4; + } + + __UNUSED uint32_t opcode = *(uint32_t *)frame->pc; + //dprintf(CRITICAL, "undefined opcode 0x%x\n", opcode); + +#if ARM_WITH_VFP + if (in_thumb) { + /* look for a 32bit thumb instruction */ + if (opcode & 0x0000e800) { + /* swap the 16bit words */ + opcode = (opcode >> 16) | (opcode << 16); + } + + if (((opcode & 0xec000e00) == 0xec000a00) || // vfp + ((opcode & 0xef000000) == 0xef000000) || // advanced simd data processing + ((opcode & 0xff100000) == 0xf9000000)) { // VLD + + //dprintf(CRITICAL, "vfp/neon thumb instruction 0x%08x at 0x%x\n", opcode, frame->pc); + goto fpu; + } + } else { + /* look for arm vfp/neon coprocessor instructions */ + if (((opcode & 0x0c000e00) == 0x0c000a00) || // vfp + ((opcode & 0xfe000000) == 0xf2000000) || // advanced simd data processing + ((opcode & 0xff100000) == 0xf4000000)) { // VLD + //dprintf(CRITICAL, "vfp/neon arm instruction 0x%08x at 0x%x\n", opcode, frame->pc); + goto fpu; + } + } +#endif + +#if WITH_LIB_MAGENTA + // let magenta get a shot at it + struct arch_exception_context context = { .iframe = true, .frame = frame }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_UNDEFINED_INSTRUCTION, &context, frame->pc); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + + exception_die_iframe(frame, "undefined abort, halting\n"); + return; + +#if ARM_WITH_VFP +fpu: + arm_fpu_undefined_instruction(frame); +#endif +} + +static status_t arm_shared_page_fault_handler(struct arm_fault_frame *frame, uint32_t fsr, uint32_t far, + bool instruction_fault) +{ + // decode the fault status (from table B3-23) and see if we need to call into the VMM for a page fault + uint32_t fault_status = (BIT(fsr, 10) ? (1<<4) : 0) | BITS(fsr, 3, 0); + switch (fault_status) { + case 0b01101: + case 0b01111: // permission fault + // XXX add flag for permission + PANIC_UNIMPLEMENTED; + case 0b00101: + case 0b00111: { // translation fault + bool write = !!BIT(fsr, 11); + bool user = (frame->spsr & CPSR_MODE_MASK) == CPSR_MODE_USR; + + uint pf_flags = 0; + pf_flags |= write ? VMM_PF_FLAG_WRITE : 0; + pf_flags |= user ? VMM_PF_FLAG_USER : 0; + pf_flags |= instruction_fault ? VMM_PF_FLAG_INSTRUCTION : 0; + + arch_enable_ints(); + status_t err = vmm_page_fault_handler(far, pf_flags); + arch_disable_ints(); + return err; + } + case 0b00011: + case 0b00110: // access flag fault + // XXX not doing access flag yet + break; + case 0b01001: + case 0b01011: // domain fault + // XXX can we get these? + break; + } + + return ERR_FAULT; +} + +void arm_data_abort_handler(struct arm_fault_frame *frame) +{ + uint32_t fsr = arm_read_dfsr(); + uint32_t far = arm_read_dfar(); + + // see if the page fault handler can deal with it + if (likely(arm_shared_page_fault_handler(frame, fsr, far, false)) == NO_ERROR) + return; + + struct fault_handler_table_entry *fault_handler; + for (fault_handler = __fault_handler_table_start; fault_handler < __fault_handler_table_end; fault_handler++) { + if (fault_handler->pc == frame->pc) { + frame->pc = fault_handler->fault_handler; + return; + } + } + +#if WITH_LIB_MAGENTA + // let magenta get a shot at it + struct arch_exception_context context = { .iframe = false, .frame = frame }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_FATAL_PAGE_FAULT, &context, frame->pc); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + + // at this point we're dumping state and panicing + dprintf(CRITICAL, "\n\ncpu %u data abort, ", arch_curr_cpu_num()); + bool write = !!BIT(fsr, 11); + + /* decode the fault status (from table B3-23) */ + uint32_t fault_status = (BIT(fsr, 10) ? (1<<4) : 0) | BITS(fsr, 3, 0); + switch (fault_status) { + case 0b00001: // alignment fault + dprintf(CRITICAL, "alignment fault on %s\n", write ? "write" : "read"); + break; + case 0b00101: + case 0b00111: // translation fault + dprintf(CRITICAL, "translation fault on %s\n", write ? "write" : "read"); + break; + case 0b00011: + case 0b00110: // access flag fault + dprintf(CRITICAL, "access flag fault on %s\n", write ? "write" : "read"); + break; + case 0b01001: + case 0b01011: // domain fault + dprintf(CRITICAL, "domain fault, domain %lu\n", BITS_SHIFT(fsr, 7, 4)); + break; + case 0b01101: + case 0b01111: // permission fault + dprintf(CRITICAL, "permission fault on %s\n", write ? "write" : "read"); + break; + case 0b00010: // debug event + dprintf(CRITICAL, "debug event\n"); + break; + case 0b01000: // synchronous external abort + dprintf(CRITICAL, "synchronous external abort on %s\n", write ? "write" : "read"); + break; + case 0b10110: // asynchronous external abort + dprintf(CRITICAL, "asynchronous external abort on %s\n", write ? "write" : "read"); + break; + case 0b10000: // TLB conflict event + case 0b11001: // synchronous parity error on memory access + case 0b00100: // fault on instruction cache maintenance + case 0b01100: // synchronous external abort on translation table walk + case 0b01110: // " + case 0b11100: // synchronous parity error on translation table walk + case 0b11110: // " + case 0b11000: // asynchronous parity error on memory access + default: + dprintf(CRITICAL, "unhandled fault\n"); + ; + } + + dprintf(CRITICAL, "DFAR 0x%x (fault address)\n", far); + dprintf(CRITICAL, "DFSR 0x%x (fault status register)\n", fsr); + + exception_die(frame, "halting\n"); +} + +void arm_prefetch_abort_handler(struct arm_fault_frame *frame) +{ + uint32_t fsr = arm_read_ifsr(); + uint32_t far = arm_read_ifar(); + + // see if the page fault handler can deal with it + if (likely(arm_shared_page_fault_handler(frame, fsr, far, true)) == NO_ERROR) + return; + +#if WITH_LIB_MAGENTA + // let magenta get a shot at it + struct arch_exception_context context = { .iframe = false, .frame = frame }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_FATAL_PAGE_FAULT, &context, frame->pc); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + + uint32_t fault_status = (BIT(fsr, 10) ? (1<<4) : 0) | BITS(fsr, 3, 0); + + dprintf(CRITICAL, "\n\ncpu %u prefetch abort, ", arch_curr_cpu_num()); + + /* decode the fault status (from table B3-23) */ + switch (fault_status) { + case 0b00001: // alignment fault + dprintf(CRITICAL, "alignment fault\n"); + break; + case 0b00101: + case 0b00111: // translation fault + dprintf(CRITICAL, "translation fault\n"); + break; + case 0b00011: + case 0b00110: // access flag fault + dprintf(CRITICAL, "access flag fault\n"); + break; + case 0b01001: + case 0b01011: // domain fault + dprintf(CRITICAL, "domain fault, domain %lu\n", BITS_SHIFT(fsr, 7, 4)); + break; + case 0b01101: + case 0b01111: // permission fault + dprintf(CRITICAL, "permission fault\n"); + break; + case 0b00010: // debug event + dprintf(CRITICAL, "debug event\n"); + break; + case 0b01000: // synchronous external abort + dprintf(CRITICAL, "synchronous external abort\n"); + break; + case 0b10110: // asynchronous external abort + dprintf(CRITICAL, "asynchronous external abort\n"); + break; + case 0b10000: // TLB conflict event + case 0b11001: // synchronous parity error on memory access + case 0b00100: // fault on instruction cache maintenance + case 0b01100: // synchronous external abort on translation table walk + case 0b01110: // " + case 0b11100: // synchronous parity error on translation table walk + case 0b11110: // " + case 0b11000: // asynchronous parity error on memory access + default: + dprintf(CRITICAL, "unhandled fault\n"); + ; + } + + dprintf(CRITICAL, "IFAR 0x%x (fault address)\n", far); + dprintf(CRITICAL, "IFSR 0x%x (fault status register)\n", fsr); + + exception_die(frame, "halting\n"); +} + +#if WITH_LIB_MAGENTA +void arch_dump_exception_context(arch_exception_context_t *context) +{ + // based on context, this could have been a iframe or a full fault frame + uint32_t usp = 0; + if (context->iframe) { + struct arm_iframe *iframe = context->frame; + dump_iframe(iframe); + usp = iframe->usp; + } else { + struct arm_fault_frame *frame = context->frame; + dump_fault_frame(frame); + usp = frame->usp; + } + + // try to dump the user stack + if (is_user_address(usp)) { + uint8_t buf[256]; + if (copy_from_user(buf, (void *)usp, sizeof(buf)) == NO_ERROR) { + printf("bottom of user stack at 0x%lx:\n", (vaddr_t)usp); + hexdump_ex(buf, sizeof(buf), usp); + } + } +} +#endif + diff --git a/kernel/arch/arm/arm/fpu.c b/kernel/arch/arm/arm/fpu.c new file mode 100644 index 000000000..5d2833209 --- /dev/null +++ b/kernel/arch/arm/arm/fpu.c @@ -0,0 +1,116 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +static inline bool is_16regs(void) +{ + uint32_t mvfr0; + __asm__ volatile("vmrs %0, MVFR0" : "=r"(mvfr0)); + + return (mvfr0 & 0xf) == 1; +} + +static inline uint32_t read_fpexc(void) +{ + uint32_t val; + /* use legacy encoding of vmsr reg, fpexc */ + __asm__("mrc p10, 7, %0, c8, c0, 0" : "=r" (val)); + return val; +} + +static inline void write_fpexc(uint32_t val) +{ + /* use legacy encoding of vmrs fpexc, reg */ + __asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val)); +} + +void arm_fpu_set_enable(bool enable) +{ + /* set enable bit in fpexc */ + write_fpexc(enable ? (1<<30) : 0); +} + +#if ARM_WITH_VFP +void arm_fpu_undefined_instruction(struct arm_iframe *frame) +{ + thread_t *t = get_current_thread(); + + if (unlikely(arch_in_int_handler())) { + panic("floating point code in irq context. pc 0x%x\n", frame->pc); + } + + LTRACEF("enabling fpu on thread %p\n", t); + + t->arch.fpused = true; + arm_fpu_thread_swap(NULL, t); + + /* make sure the irq glue leaves the floating point unit enabled on the way out */ + frame->fpexc |= (1<<30); +} + +void arm_fpu_thread_initialize(struct thread *t) +{ + /* zero the fpu register state */ + memset(t->arch.fpregs, 0, sizeof(t->arch.fpregs)); + + t->arch.fpexc = (1<<30); + t->arch.fpscr = 0; + t->arch.fpused = false; +} + +void arm_fpu_thread_swap(struct thread *oldthread, struct thread *newthread) +{ + LTRACEF("old %p (%d), new %p (%d)\n", + oldthread, oldthread ? oldthread->arch.fpused : 0, + newthread, newthread ? newthread->arch.fpused : 0); + + if (oldthread) { + if (oldthread->arch.fpused) { + /* save the old state */ + uint32_t fpexc; + fpexc = read_fpexc(); + + oldthread->arch.fpexc = fpexc; + + /* make sure that the fpu is enabled, so the next instructions won't fault */ + arm_fpu_set_enable(true); + + __asm__ volatile("vmrs %0, fpscr" : "=r" (oldthread->arch.fpscr)); + __asm__ volatile("vstm %0, { d0-d15 }" :: "r" (&oldthread->arch.fpregs[0])); + if (!is_16regs()) { + __asm__ volatile("vstm %0, { d16-d31 }" :: "r" (&oldthread->arch.fpregs[16])); + } + + arm_fpu_set_enable(false); + } + } + + if (newthread) { + if (newthread->arch.fpused) { + // load the new state + arm_fpu_set_enable(true); + __asm__ volatile("vmsr fpscr, %0" :: "r" (newthread->arch.fpscr)); + + __asm__ volatile("vldm %0, { d0-d15 }" :: "r" (&newthread->arch.fpregs[0])); + if (!is_16regs()) { + __asm__ volatile("vldm %0, { d16-d31 }" :: "r" (&newthread->arch.fpregs[16])); + } + write_fpexc(newthread->arch.fpexc); + } else { + arm_fpu_set_enable(false); + } + } +} +#endif diff --git a/kernel/arch/arm/arm/include/arch/arch_thread.h b/kernel/arch/arm/arm/include/arch/arch_thread.h new file mode 100644 index 000000000..36efc5900 --- /dev/null +++ b/kernel/arch/arm/arm/include/arch/arch_thread.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +struct arch_thread { + vaddr_t sp; + +#if ARM_WITH_VFP + /* has this thread ever used the floating point state? */ + bool fpused; + + uint32_t fpscr; + uint32_t fpexc; + double fpregs[32]; +#endif +}; + +__END_CDECLS diff --git a/kernel/arch/arm/arm/include/arch/aspace.h b/kernel/arch/arm/arm/include/arch/aspace.h new file mode 100644 index 000000000..6f8a5b83f --- /dev/null +++ b/kernel/arch/arm/arm/include/arch/aspace.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015-2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +#define ARCH_ASPACE_MAGIC 0x41524153 // ARAS + +struct arch_aspace { + /* magic value for use-after-free detection */ + uint32_t magic; + + /* pointer to the translation table */ + paddr_t tt_phys; + uint32_t *tt_virt; + + /* range of address space */ + vaddr_t base; + size_t size; + + /* list of pages allocated for these page tables */ + struct list_node pt_page_list; +}; + +__END_CDECLS diff --git a/kernel/arch/arm/arm/mmu.c b/kernel/arch/arm/arm/mmu.c new file mode 100644 index 000000000..597e761de --- /dev/null +++ b/kernel/arch/arm/arm/mmu.c @@ -0,0 +1,932 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 +#define TRACE_CONTEXT_SWITCH 0 + +#if ARM_WITH_MMU + +#define IS_SECTION_ALIGNED(x) IS_ALIGNED(x, SECTION_SIZE) +#define IS_SUPERSECTION_ALIGNED(x) IS_ALIGNED(x, SUPERSECTION_SIZE) + +/* locals */ +static void arm_mmu_map_section(arch_aspace_t *aspace, addr_t paddr, addr_t vaddr, uint flags); +static void arm_mmu_unmap_section(arch_aspace_t *aspace, addr_t vaddr); +static void arm_mmu_protect_section(arch_aspace_t *aspace, addr_t vaddr, uint flags); + +/* the main translation table */ +uint32_t arm_kernel_translation_table[TT_ENTRY_COUNT] __ALIGNED(16384) __SECTION(".bss.prebss.translation_table"); + +/* convert user level mmu flags to flags that go in L1 descriptors */ +static uint32_t mmu_flags_to_l1_arch_flags(uint flags) +{ + uint32_t arch_flags = 0; + switch (flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_CACHED: + arch_flags |= MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE; +#if WITH_SMP + arch_flags |= MMU_MEMORY_L1_SECTION_SHAREABLE; +#endif + break; + case ARCH_MMU_FLAG_WRITE_COMBINING: + case ARCH_MMU_FLAG_UNCACHED: + arch_flags |= MMU_MEMORY_L1_TYPE_STRONGLY_ORDERED; + break; + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + arch_flags |= MMU_MEMORY_L1_TYPE_DEVICE_SHARED; + break; + default: + /* invalid user-supplied flag */ + DEBUG_ASSERT(1); + return ERR_INVALID_ARGS; + } + + switch (flags & (ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO)) { + case 0: + arch_flags |= MMU_MEMORY_L1_AP_P_RW_U_NA; + break; + case ARCH_MMU_FLAG_PERM_RO: + arch_flags |= MMU_MEMORY_L1_AP_P_RO_U_NA; + break; + case ARCH_MMU_FLAG_PERM_USER: + arch_flags |= MMU_MEMORY_L1_AP_P_RW_U_RW; + break; + case ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO: + arch_flags |= MMU_MEMORY_L1_AP_P_RO_U_RO; + break; + } + + if (flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE) { + arch_flags |= MMU_MEMORY_L1_SECTION_XN; + } + + if (flags & ARCH_MMU_FLAG_NS) { + arch_flags |= MMU_MEMORY_L1_SECTION_NON_SECURE; + } + + return arch_flags; +} + +static uint l1_arch_flags_to_mmu_flags(uint32_t l1_arch_flags) +{ + uint mmu_flags = 0; + if (l1_arch_flags & MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE) { + mmu_flags |= ARCH_MMU_FLAG_CACHED; + } else if (l1_arch_flags & MMU_MEMORY_L1_TYPE_STRONGLY_ORDERED) { + mmu_flags |= ARCH_MMU_FLAG_UNCACHED; + } else if (l1_arch_flags & MMU_MEMORY_L1_TYPE_DEVICE_SHARED) { + mmu_flags |= ARCH_MMU_FLAG_UNCACHED_DEVICE; + } else { + panic("Invalid page table caching type %u", l1_arch_flags); + } + + switch (l1_arch_flags & MMU_MEMORY_L1_AP_MASK) { + case MMU_MEMORY_L1_AP_P_RW_U_NA: + break; + case MMU_MEMORY_L1_AP_P_RO_U_NA: + mmu_flags |= ARCH_MMU_FLAG_PERM_RO; + break; + case MMU_MEMORY_L1_AP_P_RW_U_RW: + mmu_flags |= ARCH_MMU_FLAG_PERM_USER; + break; + case MMU_MEMORY_L1_AP_P_RO_U_RO: + mmu_flags |= ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO; + break; + } + + if (l1_arch_flags & MMU_MEMORY_L1_SECTION_XN) { + mmu_flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE; + } + + if (l1_arch_flags & MMU_MEMORY_L1_SECTION_NON_SECURE) { + mmu_flags |= ARCH_MMU_FLAG_NS; + } + + return mmu_flags; +} + +/* convert user level mmu flags to flags that go in L2 descriptors */ +static uint32_t mmu_flags_to_l2_arch_flags_small_page(uint flags) +{ + uint32_t arch_flags = 0; + switch (flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_CACHED: +#if WITH_SMP + arch_flags |= MMU_MEMORY_L2_SHAREABLE; +#endif + arch_flags |= MMU_MEMORY_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE; +#if WITH_SMP + arch_flags |= MMU_MEMORY_L2_SHAREABLE; +#endif + break; + case ARCH_MMU_FLAG_WRITE_COMBINING: + case ARCH_MMU_FLAG_UNCACHED: + arch_flags |= MMU_MEMORY_L2_TYPE_STRONGLY_ORDERED; + break; + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + arch_flags |= MMU_MEMORY_L2_TYPE_DEVICE_SHARED; + break; + default: + /* invalid user-supplied flag */ + DEBUG_ASSERT(1); + return ERR_INVALID_ARGS; + } + + switch (flags & (ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO)) { + case 0: + arch_flags |= MMU_MEMORY_L2_AP_P_RW_U_NA; + break; + case ARCH_MMU_FLAG_PERM_RO: + arch_flags |= MMU_MEMORY_L2_AP_P_RO_U_NA; + break; + case ARCH_MMU_FLAG_PERM_USER: + arch_flags |= MMU_MEMORY_L2_AP_P_RW_U_RW; + break; + case ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO: + arch_flags |= MMU_MEMORY_L2_AP_P_RO_U_RO; + break; + } + + if (flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE) { + arch_flags |= MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE_XN; + } else { + arch_flags |= MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE; + } + + return arch_flags; +} + +static inline bool is_valid_vaddr(arch_aspace_t *aspace, vaddr_t vaddr) +{ + return (vaddr >= aspace->base && vaddr <= aspace->base + aspace->size - 1); +} + +static void arm_mmu_map_section(arch_aspace_t *aspace, addr_t paddr, addr_t vaddr, uint flags) +{ + int index; + + LTRACEF("aspace %p tt %p pa 0x%lx va 0x%lx flags 0x%x\n", aspace, aspace->tt_virt, paddr, vaddr, flags); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + DEBUG_ASSERT(IS_SECTION_ALIGNED(paddr)); + DEBUG_ASSERT(IS_SECTION_ALIGNED(vaddr)); + DEBUG_ASSERT((flags & MMU_MEMORY_L1_DESCRIPTOR_MASK) == MMU_MEMORY_L1_DESCRIPTOR_SECTION); + + /* Get the index into the translation table */ + index = vaddr / SECTION_SIZE; + + /* Set the entry value: + * (2<<0): Section entry + * (0<<5): Domain = 0 + * flags: TEX, CB and AP bit settings provided by the caller. + */ + aspace->tt_virt[index] = (paddr & ~(MB-1)) | (MMU_MEMORY_DOMAIN_MEM << 5) | MMU_MEMORY_L1_DESCRIPTOR_SECTION | flags; +} + +static void arm_mmu_protect_section(arch_aspace_t *aspace, addr_t vaddr, uint flags) +{ + int index; + + LTRACEF("aspace %p tt %p va 0x%lx flags 0x%x\n", aspace, aspace->tt_virt, vaddr, flags); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + DEBUG_ASSERT(IS_SECTION_ALIGNED(vaddr)); + DEBUG_ASSERT((flags & MMU_MEMORY_L1_DESCRIPTOR_MASK) == MMU_MEMORY_L1_DESCRIPTOR_SECTION || + (flags & MMU_MEMORY_L1_DESCRIPTOR_MASK) == 0); + + /* Get the index into the translation table */ + index = vaddr / SECTION_SIZE; + + DEBUG_ASSERT(aspace->tt_virt[index]); + addr_t paddr = aspace->tt_virt[index] & ~(MB-1); + + /* Set the entry value: + * (2<<0): Section entry + * (0<<5): Domain = 0 + * flags: TEX, CB and AP bit settings provided by the caller. + */ + aspace->tt_virt[index] = paddr | (MMU_MEMORY_DOMAIN_MEM << 5) | MMU_MEMORY_L1_DESCRIPTOR_SECTION | flags; + DSB; + arm_invalidate_tlb_mva_no_barrier(vaddr); +} + +static void arm_mmu_unmap_l1_entry(uint32_t *translation_table, uint32_t index) +{ + DEBUG_ASSERT(translation_table); + DEBUG_ASSERT(index < TT_ENTRY_COUNT); + + translation_table[index] = 0; + DSB; + arm_invalidate_tlb_mva_no_barrier((vaddr_t)index * SECTION_SIZE); +} + +static void arm_mmu_unmap_section(arch_aspace_t *aspace, addr_t vaddr) +{ + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(IS_SECTION_ALIGNED(vaddr)); + arm_mmu_unmap_l1_entry(aspace->tt_virt, vaddr / SECTION_SIZE); +} + +void arm_mmu_early_init(void) +{ +} + +void arm_mmu_init(void) +{ + /* unmap the initial mapings that are marked temporary */ + struct mmu_initial_mapping *map = mmu_initial_mappings; + while (map->size > 0) { + if (map->flags & MMU_INITIAL_MAPPING_TEMPORARY) { + vaddr_t va = map->virt; + size_t size = map->size; + + DEBUG_ASSERT(IS_SECTION_ALIGNED(size)); + + while (size > 0) { + arm_mmu_unmap_l1_entry(arm_kernel_translation_table, va / SECTION_SIZE); + va += MB; + size -= MB; + } + } + map++; + } + arm_after_invalidate_tlb_barrier(); + +#if KERNEL_ASPACE_BASE != 0 + /* bounce the ttbr over to ttbr1 and leave 0 unmapped */ + uint32_t n = __builtin_clz(KERNEL_ASPACE_BASE) + 1; + DEBUG_ASSERT(n <= 7); + + uint32_t ttbcr = (1<<4) | n; /* disable TTBCR0 and set the split between TTBR0 and TTBR1 */ + + arm_write_ttbr1(arm_read_ttbr0()); + ISB; + arm_write_ttbcr(ttbcr); + ISB; + arm_write_ttbr0(0); + ISB; +#endif +} + +void arch_disable_mmu(void) +{ + arm_write_sctlr(arm_read_sctlr() & ~(1<<0)); // mmu disabled +} + +void arch_mmu_context_switch(arch_aspace_t *old_aspace, arch_aspace_t *aspace) +{ + if (LOCAL_TRACE && TRACE_CONTEXT_SWITCH) + LTRACEF("aspace %p\n", aspace); + + uint32_t ttbr; + uint32_t ttbcr = arm_read_ttbcr(); + if (aspace) { + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + ttbr = MMU_TTBRx_FLAGS | (aspace->tt_phys); + ttbcr &= ~(1<<4); // enable TTBR0 + } else { + ttbr = 0; + ttbcr |= (1<<4); // disable TTBR0 + } + + if (LOCAL_TRACE && TRACE_CONTEXT_SWITCH) + LTRACEF("ttbr 0x%x, ttbcr 0x%x\n", ttbr, ttbcr); + arm_write_ttbr0(ttbr); + arm_write_ttbcr(ttbcr); +} + +status_t arch_mmu_query(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t *paddr, uint *flags) +{ + LTRACEF("aspace %p, vaddr 0x%lx\n", aspace, vaddr); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + + /* Get the index into the translation table */ + uint index = vaddr / MB; + + /* decode it */ + uint32_t tt_entry = aspace->tt_virt[index]; + switch (tt_entry & MMU_MEMORY_L1_DESCRIPTOR_MASK) { + case MMU_MEMORY_L1_DESCRIPTOR_INVALID: + return ERR_NOT_FOUND; + case MMU_MEMORY_L1_DESCRIPTOR_SECTION: + if (tt_entry & (1<<18)) { + /* supersection */ + PANIC_UNIMPLEMENTED; + } + + /* section */ + if (paddr) + *paddr = MMU_MEMORY_L1_SECTION_ADDR(tt_entry) + (vaddr & (SECTION_SIZE - 1)); + + if (flags) { + *flags = 0; + if (tt_entry & MMU_MEMORY_L1_SECTION_NON_SECURE) + *flags |= ARCH_MMU_FLAG_NS; + switch (tt_entry & MMU_MEMORY_L1_TYPE_MASK) { + case MMU_MEMORY_L1_TYPE_STRONGLY_ORDERED: + *flags |= ARCH_MMU_FLAG_UNCACHED; + break; + case MMU_MEMORY_L1_TYPE_DEVICE_SHARED: + case MMU_MEMORY_L1_TYPE_DEVICE_NON_SHARED: + *flags |= ARCH_MMU_FLAG_UNCACHED_DEVICE; + break; + } + switch (tt_entry & MMU_MEMORY_L1_AP_MASK) { + case MMU_MEMORY_L1_AP_P_RO_U_NA: + *flags |= ARCH_MMU_FLAG_PERM_RO; + break; + case MMU_MEMORY_L1_AP_P_RW_U_NA: + break; + case MMU_MEMORY_L1_AP_P_RO_U_RO: + *flags |= ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO; + break; + case MMU_MEMORY_L1_AP_P_RW_U_RW: + *flags |= ARCH_MMU_FLAG_PERM_USER; + break; + } + if (tt_entry & MMU_MEMORY_L1_SECTION_XN) { + *flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE; + } + } + break; + case MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE: { + uint32_t *l2_table = paddr_to_kvaddr(MMU_MEMORY_L1_PAGE_TABLE_ADDR(tt_entry)); + uint l2_index = (vaddr % SECTION_SIZE) / PAGE_SIZE; + uint32_t l2_entry = l2_table[l2_index]; + + //LTRACEF("l2_table at %p, index %u, entry 0x%x\n", l2_table, l2_index, l2_entry); + + switch (l2_entry & MMU_MEMORY_L2_DESCRIPTOR_MASK) { + default: + case MMU_MEMORY_L2_DESCRIPTOR_INVALID: + return ERR_NOT_FOUND; + case MMU_MEMORY_L2_DESCRIPTOR_LARGE_PAGE: + PANIC_UNIMPLEMENTED; + break; + case MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE: + case MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE_XN: + if (paddr) + *paddr = MMU_MEMORY_L2_SMALL_PAGE_ADDR(l2_entry) + (vaddr & (PAGE_SIZE - 1)); + + if (flags) { + *flags = 0; + /* NS flag is only present on L1 entry */ + if (tt_entry & MMU_MEMORY_L1_PAGETABLE_NON_SECURE) + *flags |= ARCH_MMU_FLAG_NS; + switch (l2_entry & MMU_MEMORY_L2_TYPE_MASK) { + case MMU_MEMORY_L2_TYPE_STRONGLY_ORDERED: + *flags |= ARCH_MMU_FLAG_UNCACHED; + break; + case MMU_MEMORY_L2_TYPE_DEVICE_SHARED: + case MMU_MEMORY_L2_TYPE_DEVICE_NON_SHARED: + *flags |= ARCH_MMU_FLAG_UNCACHED_DEVICE; + break; + } + switch (l2_entry & MMU_MEMORY_L2_AP_MASK) { + case MMU_MEMORY_L2_AP_P_RO_U_NA: + *flags |= ARCH_MMU_FLAG_PERM_RO; + break; + case MMU_MEMORY_L2_AP_P_RW_U_NA: + break; + case MMU_MEMORY_L2_AP_P_RO_U_RO: + *flags |= ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO; + break; + case MMU_MEMORY_L2_AP_P_RW_U_RW: + *flags |= ARCH_MMU_FLAG_PERM_USER; + break; + } + if ((l2_entry & MMU_MEMORY_L2_DESCRIPTOR_MASK) == + MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE_XN) { + *flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE; + } + } + break; + } + + break; + } + default: + PANIC_UNIMPLEMENTED; + } + + return NO_ERROR; +} + + +/* + * We allow up to 4 adjacent L1 entries to point within the same memory page + * allocated for L2 page tables. + * + * L1: | 0 | 1 | 2 | 3 | .... | N+0 | N+1 | N+2 | N+3 | + * L2: [ 0 | .....[ (N/4) | + */ +#define L1E_PER_PAGE 4 + +static status_t get_l2_table(arch_aspace_t *aspace, uint32_t l1_index, paddr_t *ppa) +{ + paddr_t pa; + uint32_t tt_entry; + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(ppa); + + /* lookup an existing l2 pagetable */ + for (uint i = 0; i < L1E_PER_PAGE; i++) { + tt_entry = aspace->tt_virt[ROUNDDOWN(l1_index, L1E_PER_PAGE) + i]; + if ((tt_entry & MMU_MEMORY_L1_DESCRIPTOR_MASK) + == MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE) { + *ppa = (paddr_t)ROUNDDOWN(MMU_MEMORY_L1_PAGE_TABLE_ADDR(tt_entry), PAGE_SIZE) + + (PAGE_SIZE / L1E_PER_PAGE) * (l1_index & (L1E_PER_PAGE-1)); + return NO_ERROR; + } + } + + /* not found: allocate it */ + uint32_t *l2_va = pmm_alloc_kpages(1, &aspace->pt_page_list, &pa); + if (!l2_va) + return ERR_NO_MEMORY; + + LTRACEF("allocated page table at pa 0x%lx\n", pa); + + /* wipe it clean to set no access */ + memset(l2_va, 0, PAGE_SIZE); + + /* get physical address */ + DEBUG_ASSERT(IS_PAGE_ALIGNED((vaddr_t)l2_va)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(pa)); + + *ppa = pa + (PAGE_SIZE / L1E_PER_PAGE) * (l1_index & (L1E_PER_PAGE-1)); + + LTRACEF("allocated pagetable at %p, pa 0x%lx, ppa 0x%lx\n", l2_va, pa, *ppa); + return NO_ERROR; +} + + +static void put_l2_table(arch_aspace_t *aspace, uint32_t l1_index, paddr_t l2_pa) +{ + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + /* check if any l1 entry points to this l2 table */ + for (uint i = 0; i < L1E_PER_PAGE; i++) { + uint32_t tt_entry = aspace->tt_virt[ROUNDDOWN(l1_index, L1E_PER_PAGE) + i]; + if ((tt_entry & MMU_MEMORY_L1_DESCRIPTOR_MASK) + == MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE) { + return; + } + } + + /* we can free this l2 table */ + vm_page_t *page = paddr_to_vm_page(l2_pa); + if (!page) + panic("bad page table paddr 0x%lx\n", l2_pa); + + /* verify that it is in our page list */ + DEBUG_ASSERT(list_in_list(&page->node)); + + list_delete(&page->node); + + LTRACEF("freeing pagetable at 0x%lx\n", l2_pa); + pmm_free_page(page); +} + +#if WITH_ARCH_MMU_PICK_SPOT + +static inline bool are_regions_compatible(uint new_region_flags, + uint adjacent_region_flags) +{ + /* + * Two regions are compatible if NS flag matches. + */ + uint mask = ARCH_MMU_FLAG_NS; + + if ((new_region_flags & mask) == (adjacent_region_flags & mask)) + return true; + + return false; +} + + +vaddr_t arch_mmu_pick_spot(vaddr_t base, uint prev_region_flags, + vaddr_t end, uint next_region_flags, + vaddr_t align, size_t size, uint flags) +{ + LTRACEF("base 0x%lx, end 0x%lx, align %ld, size %zd, flags 0x%x\n", + base, end, align, size, flags); + + vaddr_t spot; + + if (align >= SECTION_SIZE || + are_regions_compatible(flags, prev_region_flags)) { + spot = ALIGN(base, align); + } else { + spot = ALIGN(base, SECTION_SIZE); + } + + vaddr_t spot_end = spot + size - 1; + if (spot_end < spot || spot_end > end) + return end; /* wrapped around or it does not fit */ + + if ((spot_end / SECTION_SIZE) == (end / SECTION_SIZE)) { + if (!are_regions_compatible(flags, next_region_flags)) + return end; + } + + return spot; +} +#endif /* WITH_ARCH_MMU_PICK_SPOT */ + + +int arch_mmu_map(arch_aspace_t *aspace, addr_t vaddr, paddr_t paddr, uint count, uint flags) +{ + LTRACEF("vaddr 0x%lx paddr 0x%lx count %u flags 0x%x\n", vaddr, paddr, count, flags); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + +#if !WITH_ARCH_MMU_PICK_SPOT + if (flags & ARCH_MMU_FLAG_NS) { + /* WITH_ARCH_MMU_PICK_SPOT is required to support NS memory */ + panic("NS mem is not supported\n"); + } +#endif + + /* paddr and vaddr must be aligned */ + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(paddr)); + if (!IS_PAGE_ALIGNED(vaddr) || !IS_PAGE_ALIGNED(paddr)) + return ERR_INVALID_ARGS; + + if (count == 0) + return NO_ERROR; + + /* see what kind of mapping we can use */ + int mapped = 0; + while (count > 0) { + if (IS_SECTION_ALIGNED(vaddr) && IS_SECTION_ALIGNED(paddr) && count >= SECTION_SIZE / PAGE_SIZE) { + /* we can use a section */ + + /* compute the arch flags for L1 sections */ + uint arch_flags = mmu_flags_to_l1_arch_flags(flags) | + MMU_MEMORY_L1_DESCRIPTOR_SECTION; + + /* map it */ + arm_mmu_map_section(aspace, paddr, vaddr, arch_flags); + count -= SECTION_SIZE / PAGE_SIZE; + mapped += SECTION_SIZE / PAGE_SIZE; + vaddr += SECTION_SIZE; + paddr += SECTION_SIZE; + } else { + /* will have to use a L2 mapping */ + uint l1_index = vaddr / SECTION_SIZE; + uint32_t tt_entry = aspace->tt_virt[l1_index]; + + LTRACEF("tt_entry 0x%x\n", tt_entry); + switch (tt_entry & MMU_MEMORY_L1_DESCRIPTOR_MASK) { + case MMU_MEMORY_L1_DESCRIPTOR_SECTION: + // XXX will have to break L1 mapping into a L2 page table + PANIC_UNIMPLEMENTED; + break; + case MMU_MEMORY_L1_DESCRIPTOR_INVALID: { + paddr_t l2_pa = 0; + if (get_l2_table(aspace, l1_index, &l2_pa) != NO_ERROR) { + TRACEF("failed to allocate pagetable\n"); + goto done; + } + tt_entry = l2_pa | MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE; + if (flags & ARCH_MMU_FLAG_NS) + tt_entry |= MMU_MEMORY_L1_PAGETABLE_NON_SECURE; + + aspace->tt_virt[l1_index] = tt_entry; + /* fallthrough */ + } + case MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE: { + uint32_t *l2_table = paddr_to_kvaddr(MMU_MEMORY_L1_PAGE_TABLE_ADDR(tt_entry)); + LTRACEF("l2_table at %p\n", l2_table); + + DEBUG_ASSERT(l2_table); + + // XXX handle 64K pages here + + /* compute the arch flags for L2 4K pages */ + uint arch_flags = mmu_flags_to_l2_arch_flags_small_page(flags); + + uint l2_index = (vaddr % SECTION_SIZE) / PAGE_SIZE; + do { + l2_table[l2_index++] = paddr | arch_flags; + count--; + mapped++; + vaddr += PAGE_SIZE; + paddr += PAGE_SIZE; + } while (count && (l2_index != (SECTION_SIZE / PAGE_SIZE))); + break; + } + default: + PANIC_UNIMPLEMENTED; + } + } + } + +done: + DSB; + return mapped; +} + +int arch_mmu_protect(arch_aspace_t *aspace, vaddr_t vaddr, uint count, uint flags) +{ + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + + LTRACEF("vaddr 0x%lx count %u\n", vaddr, count); + + uint l1_arch_flags = mmu_flags_to_l1_arch_flags(flags); + uint l2_arch_flags = mmu_flags_to_l2_arch_flags_small_page(flags); + while (count > 0) { + uint l1_index = vaddr / SECTION_SIZE; + uint32_t tt_entry = aspace->tt_virt[l1_index]; + + switch (tt_entry & MMU_MEMORY_L1_DESCRIPTOR_MASK) { + case MMU_MEMORY_L1_DESCRIPTOR_INVALID: { + /* this top level page is not mapped, move on to the next one */ + uint page_cnt = MIN((SECTION_SIZE - (vaddr % SECTION_SIZE)) / PAGE_SIZE, count); + vaddr += page_cnt * PAGE_SIZE; + count -= page_cnt; + break; + } + case MMU_MEMORY_L1_DESCRIPTOR_SECTION: + if (IS_SECTION_ALIGNED(vaddr) && count >= SECTION_SIZE / PAGE_SIZE) { + /* we're asked to protect at least all of this section, so update the + * permissions */ + // XXX test for supersection + arm_mmu_protect_section(aspace, vaddr, l1_arch_flags); + + vaddr += SECTION_SIZE; + count -= SECTION_SIZE / PAGE_SIZE; + break; + } + + // We need to convert this section into an L2 table and + // protect the part we care about + paddr_t l2_pa = 0; + if (get_l2_table(aspace, l1_index, &l2_pa) != NO_ERROR) { + TRACEF("failed to allocate pagetable\n"); + goto err; + } + bool was_ns = !!(tt_entry & MMU_MEMORY_L1_SECTION_NON_SECURE); + paddr_t old_pa = MMU_MEMORY_L1_SECTION_ADDR(tt_entry); + uint new_l2_flags = mmu_flags_to_l2_arch_flags_small_page( + l1_arch_flags_to_mmu_flags(tt_entry)); + + tt_entry = l2_pa | MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE; + if (was_ns) { + tt_entry |= MMU_MEMORY_L1_PAGETABLE_NON_SECURE; + } + + uint32_t *new_l2_table = paddr_to_kvaddr(l2_pa); + for (uint i = 0; i < SECTION_SIZE / PAGE_SIZE; i++) { + new_l2_table[i] = old_pa | new_l2_flags; + old_pa += PAGE_SIZE; + } + + aspace->tt_virt[l1_index] = tt_entry; + // Fall through + case MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE: { + uint32_t *l2_table = paddr_to_kvaddr(MMU_MEMORY_L1_PAGE_TABLE_ADDR(tt_entry)); + uint page_idx = (vaddr % SECTION_SIZE) / PAGE_SIZE; + uint page_cnt = MIN((SECTION_SIZE / PAGE_SIZE) - page_idx, count); + + /* remap page run */ + for (uint i = 0; i < page_cnt; i++) { + uint32_t entry = l2_table[page_idx]; + addr_t paddr = MMU_MEMORY_L2_SMALL_PAGE_ADDR(entry); + l2_table[page_idx] = paddr | l2_arch_flags; + page_idx++; + } + DSB; + + /* invalidate tlb */ + for (uint i = 0; i < page_cnt; i++) { + arm_invalidate_tlb_mva_no_barrier(vaddr); + vaddr += PAGE_SIZE; + } + count -= page_cnt; + break; + } + + default: + // XXX not implemented supersections + PANIC_UNIMPLEMENTED; + } + } + arm_after_invalidate_tlb_barrier(); + return 0; +err: + arm_after_invalidate_tlb_barrier(); + return ERR_GENERIC; +} + +int arch_mmu_unmap(arch_aspace_t *aspace, vaddr_t vaddr, uint count) +{ + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + + LTRACEF("vaddr 0x%lx count %u\n", vaddr, count); + + int unmapped = 0; + while (count > 0) { + uint l1_index = vaddr / SECTION_SIZE; + uint32_t tt_entry = aspace->tt_virt[l1_index]; + + switch (tt_entry & MMU_MEMORY_L1_DESCRIPTOR_MASK) { + case MMU_MEMORY_L1_DESCRIPTOR_INVALID: { + /* this top level page is not mapped, move on to the next one */ + uint page_cnt = MIN((SECTION_SIZE - (vaddr % SECTION_SIZE)) / PAGE_SIZE, count); + vaddr += page_cnt * PAGE_SIZE; + count -= page_cnt; + break; + } + case MMU_MEMORY_L1_DESCRIPTOR_SECTION: + if (IS_SECTION_ALIGNED(vaddr) && count >= SECTION_SIZE / PAGE_SIZE) { + /* we're asked to remove at least all of this section, so just zero it out */ + // XXX test for supersection + arm_mmu_unmap_section(aspace, vaddr); + + vaddr += SECTION_SIZE; + count -= SECTION_SIZE / PAGE_SIZE; + unmapped += SECTION_SIZE / PAGE_SIZE; + } else { + // XXX handle unmapping just part of a section + // will need to convert to a L2 table and then unmap the parts we are asked to + PANIC_UNIMPLEMENTED; + } + break; + case MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE: { + uint32_t *l2_table = paddr_to_kvaddr(MMU_MEMORY_L1_PAGE_TABLE_ADDR(tt_entry)); + uint page_idx = (vaddr % SECTION_SIZE) / PAGE_SIZE; + uint page_cnt = MIN((SECTION_SIZE / PAGE_SIZE) - page_idx, count); + + /* unmap page run */ + for (uint i = 0; i < page_cnt; i++) { + l2_table[page_idx++] = 0; + } + DSB; + + /* invalidate tlb */ + for (uint i = 0; i < page_cnt; i++) { + arm_invalidate_tlb_mva_no_barrier(vaddr); + vaddr += PAGE_SIZE; + } + count -= page_cnt; + unmapped += page_cnt; + + /* + * Check if all pages related to this l1 entry are deallocated. + * We only need to check pages that we did not clear above starting + * from page_idx and wrapped around SECTION. + */ + page_cnt = (SECTION_SIZE / PAGE_SIZE) - page_cnt; + while (page_cnt) { + if (page_idx == (SECTION_SIZE / PAGE_SIZE)) + page_idx = 0; + if (l2_table[page_idx++]) + break; + page_cnt--; + } + if (!page_cnt) { + /* we can kill l1 entry */ + arm_mmu_unmap_l1_entry(aspace->tt_virt, l1_index); + + /* try to free l2 page itself */ + put_l2_table(aspace, l1_index, MMU_MEMORY_L1_PAGE_TABLE_ADDR(tt_entry)); + } + break; + } + + default: + // XXX not implemented supersections or L2 tables + PANIC_UNIMPLEMENTED; + } + } + arm_after_invalidate_tlb_barrier(); + return unmapped; +} + +status_t arch_mmu_init_aspace(arch_aspace_t *aspace, vaddr_t base, size_t size, uint flags) +{ + LTRACEF("aspace %p, base 0x%lx, size 0x%zx, flags 0x%x\n", aspace, base, size, flags); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic != ARCH_ASPACE_MAGIC); + + /* validate that the base + size is sane and doesn't wrap */ + DEBUG_ASSERT(size > PAGE_SIZE); + DEBUG_ASSERT(base + size - 1 > base); + + list_initialize(&aspace->pt_page_list); + + aspace->magic = ARCH_ASPACE_MAGIC; + if (flags & ARCH_ASPACE_FLAG_KERNEL) { + aspace->base = base; + aspace->size = size; + aspace->tt_virt = arm_kernel_translation_table; + aspace->tt_phys = vaddr_to_paddr(aspace->tt_virt); + } else { + + // XXX at the moment we can only really deal with 1GB user space, and thus + // needing only a single page for the top level translation table + DEBUG_ASSERT(base < GB && (base + size) <= GB); + + aspace->base = base; + aspace->size = size; + + paddr_t pa; + uint32_t *va = pmm_alloc_kpages(1, &aspace->pt_page_list, &pa); + if (!va) + return ERR_NO_MEMORY; + + memset(va, 0, PAGE_SIZE); + + aspace->tt_virt = va; + aspace->tt_phys = pa; + } + + LTRACEF("tt_phys 0x%lx tt_virt %p\n", aspace->tt_phys, aspace->tt_virt); + + return NO_ERROR; +} + +status_t arch_mmu_destroy_aspace(arch_aspace_t *aspace) +{ + LTRACEF("aspace %p\n", aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + // XXX free all of the pages allocated in aspace->pt_page_list + vm_page_t *p; + while ((p = list_remove_head_type(&aspace->pt_page_list, vm_page_t, node)) != NULL) { + LTRACEF("freeing page %p\n", p); + pmm_free_page(p); + } + + aspace->magic = 0; + + return NO_ERROR; +} + +#endif // ARM_WITH_MMU diff --git a/kernel/arch/arm/arm/mp.c b/kernel/arch/arm/arm/mp.c new file mode 100644 index 000000000..8d8d8a55c --- /dev/null +++ b/kernel/arch/arm/arm/mp.c @@ -0,0 +1,80 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include + +#if WITH_DEV_INTERRUPT_ARM_GIC +#include +#elif PLATFORM_BCM2835 +/* bcm2835 has a weird custom interrupt controller for MP */ +extern void bcm2835_send_ipi(uint irq, uint cpu_mask); +#else +#error need other implementation of interrupt controller that can ipi +#endif + +#define LOCAL_TRACE 0 + +#define GIC_IPI_BASE (14) + +status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) +{ + LTRACEF("target 0x%x, ipi %u\n", target, ipi); + +#if WITH_DEV_INTERRUPT_ARM_GIC + uint gic_ipi_num = ipi + GIC_IPI_BASE; + + /* filter out targets outside of the range of cpus we care about */ + target &= ((1UL << SMP_MAX_CPUS) - 1); + if (target != 0) { + LTRACEF("target 0x%x, gic_ipi %u\n", target, gic_ipi_num); + u_int flags = 0; +#if WITH_LIB_SM + flags |= ARM_GIC_SGI_FLAG_NS; +#endif + arm_gic_sgi(gic_ipi_num, flags, target); + } +#elif PLATFORM_BCM2835 + /* filter out targets outside of the range of cpus we care about */ + target &= ((1UL << SMP_MAX_CPUS) - 1); + if (target != 0) { + bcm2835_send_ipi(ipi, target); + } +#endif + + return NO_ERROR; +} + +enum handler_return arm_ipi_generic_handler(void *arg) +{ + LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg); + + return mp_mbx_generic_irq(); +} + +enum handler_return arm_ipi_reschedule_handler(void *arg) +{ + LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg); + + return mp_mbx_reschedule_irq(); +} + +void arch_mp_init_percpu(void) +{ +#if WITH_DEV_INTERRUPT_ARM_GIC + register_int_handler(MP_IPI_GENERIC + GIC_IPI_BASE, &arm_ipi_generic_handler, 0); + register_int_handler(MP_IPI_RESCHEDULE + GIC_IPI_BASE, &arm_ipi_reschedule_handler, 0); +#endif + + mp_set_curr_cpu_online(true); +} + diff --git a/kernel/arch/arm/arm/ops.S b/kernel/arch/arm/arm/ops.S new file mode 100644 index 000000000..fd2cc3187 --- /dev/null +++ b/kernel/arch/arm/arm/ops.S @@ -0,0 +1,127 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +.text + +/* void _arch_enable_ints(void); */ +FUNCTION(_arch_enable_ints) + mrs r0, cpsr + bic r0, r0, #(1<<7) /* clear the I bit */ + msr cpsr_c, r0 + bx lr + +/* void _arch_disable_ints(void); */ +FUNCTION(_arch_disable_ints) + mrs r0, cpsr + orr r0, r0, #(1<<7) + msr cpsr_c, r0 + bx lr + +/* int _atomic_swap(int *ptr, int val); */ +FUNCTION(_atomic_swap) +.L_loop_swap: + ldrex r12, [r0] + strex r2, r1, [r0] + cmp r2, #0 + bne .L_loop_swap + + /* save old value */ + mov r0, r12 + bx lr + +/* int _atomic_add(int *ptr, int val); */ +FUNCTION(_atomic_add) + /* use load/store exclusive */ +.L_loop_add: + ldrex r12, [r0] + add r2, r12, r1 + strex r3, r2, [r0] + cmp r3, #0 + bne .L_loop_add + + /* save old value */ + mov r0, r12 + bx lr + +/* int _atomic_and(int *ptr, int val); */ +FUNCTION(_atomic_and) + /* use load/store exclusive */ +.L_loop_and: + ldrex r12, [r0] + and r2, r12, r1 + strex r3, r2, [r0] + cmp r3, #0 + bne .L_loop_and + + /* save old value */ + mov r0, r12 + bx lr + +/* int _atomic_or(int *ptr, int val); */ +FUNCTION(_atomic_or) + /* use load/store exclusive */ +.L_loop_or: + ldrex r12, [r0] + orr r2, r12, r1 + strex r3, r2, [r0] + cmp r3, #0 + bne .L_loop_or + + /* save old value */ + mov r0, r12 + bx lr + +FUNCTION(arch_spin_trylock) + mov r2, r0 + mov r1, #1 + ldrex r0, [r2] + cmp r0, #0 + strexeq r0, r1, [r2] + dmb + bx lr + +FUNCTION(arch_spin_lock) + mov r1, #1 +1: + ldrex r2, [r0] + cmp r2, #0 + wfene + strexeq r2, r1, [r0] + cmpeq r2, #0 + bne 1b + dmb + bx lr + +FUNCTION(arch_spin_unlock) + mov r1, #0 + dmb + str r1, [r0] + dsb + sev + bx lr + +/* void arch_idle(); */ +FUNCTION(arch_idle) +#if ARM_ARCH_LEVEL >= 7 + wfi +#elif ARM_ARCH_LEVEL == 6 + mov r0, #0 + mcr p15, 0, r0, c7, c0, #4 +#else +#error unknown cpu +#endif + bx lr + +/* void arm_invalidate_tlb(void) */ +FUNCTION(arm_invalidate_tlb) + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 + bx lr + diff --git a/kernel/arch/arm/arm/start.S b/kernel/arch/arm/arm/start.S new file mode 100644 index 000000000..5146287f1 --- /dev/null +++ b/kernel/arch/arm/arm/start.S @@ -0,0 +1,415 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +.section ".text.boot" +.globl _start +_start: + b platform_reset + b arm_undefined + b arm_syscall + b arm_prefetch_abort + b arm_data_abort + b arm_reserved + b arm_irq + b arm_fiq +#if WITH_SMP + b arm_reset +#endif + +.weak platform_reset +platform_reset: + /* Fall through for the weak symbol */ + +.globl arm_reset +arm_reset: + /* do some early cpu setup */ + mrc p15, 0, r12, c1, c0, 0 + /* i/d cache disable, mmu disabled */ + bic r12, #(1<<12) + bic r12, #(1<<2 | 1<<0) +#if WITH_KERNEL_VM + /* enable caches so atomics and spinlocks work */ + orr r12, r12, #(1<<12) + orr r12, r12, #(1<<2) +#endif // WITH_KERNEL_VM + mcr p15, 0, r12, c1, c0, 0 + + /* calculate the physical offset from our eventual virtual location */ +.Lphys_offset: + ldr r4, =.Lphys_offset + adr r11, .Lphys_offset + sub r11, r11, r4 + +#if WITH_SMP + /* figure out our cpu number */ + mrc p15, 0, r12, c0, c0, 5 /* read MPIDR */ + + /* mask off the bottom bits to test cluster number:cpu number */ + ubfx r12, r12, #0, #SMP_CPU_ID_BITS + + /* if we're not cpu 0:0, fall into a trap and wait */ + teq r12, #0 + movne r0, r12 + bne arm_secondary_setup +#endif // WITH_SMP + +#if WITH_CPU_EARLY_INIT + /* call platform/arch/etc specific init code */ + bl __cpu_early_init +#endif // WITH_CPU_EARLY_INIT + +#if WITH_NO_PHYS_RELOCATION + /* assume that image is properly loaded in physical memory */ +#else + /* see if we need to relocate to our proper location in physical memory */ + adr r4, _start /* this emits sub r4, pc, #constant */ + ldr r5, =(MEMBASE + KERNEL_LOAD_OFFSET) /* calculate the binary's physical load address */ + subs r12, r4, r5 /* calculate the delta between where we're loaded and the proper spot */ + beq .Lrelocate_done + + /* we need to relocate ourselves to the proper spot */ + ldr r6, =__data_end + ldr r7, =(KERNEL_BASE - MEMBASE) + sub r6, r7 + add r6, r12 + +.Lrelocate_loop: + ldr r7, [r4], #4 + str r7, [r5], #4 + cmp r4, r6 + bne .Lrelocate_loop + + /* we're relocated, jump to the right address */ + sub pc, r12 + nop /* skipped in the add to pc */ + + /* recalculate the physical offset */ + sub r11, r11, r12 + +.Lrelocate_done: +#endif // !WITH_NO_PHYS_RELOCATION + +#if ARM_WITH_MMU +.Lsetup_mmu: + + /* set up the mmu according to mmu_initial_mappings */ + + /* load the base of the translation table and clear the table */ + ldr r4, =arm_kernel_translation_table + add r4, r4, r11 + /* r4 = physical address of translation table */ + + mov r5, #0 + mov r6, #0 + + /* walk through all the entries in the translation table, setting them up */ +0: + str r5, [r4, r6, lsl #2] + add r6, #1 + cmp r6, #4096 + bne 0b + + /* load the address of the mmu_initial_mappings table and start processing */ + ldr r5, =mmu_initial_mappings + add r5, r5, r11 + /* r5 = physical address of mmu initial mapping table */ + +.Linitial_mapping_loop: + ldmia r5!, { r6-r10 } + /* r6 = phys, r7 = virt, r8 = size, r9 = flags, r10 = name */ + + /* round size up to 1MB alignment */ + ubfx r10, r6, #0, #20 + add r8, r8, r10 + add r8, r8, #(1 << 20) + sub r8, r8, #1 + + /* mask all the addresses and sizes to 1MB boundaries */ + lsr r6, #20 /* r6 = physical address / 1MB */ + lsr r7, #20 /* r7 = virtual address / 1MB */ + lsr r8, #20 /* r8 = size in 1MB chunks */ + + /* if size == 0, end of list */ + cmp r8, #0 + beq .Linitial_mapping_done + + /* set up the flags */ + ldr r10, =MMU_KERNEL_L1_PTE_FLAGS + teq r9, #MMU_INITIAL_MAPPING_FLAG_UNCACHED + ldreq r10, =MMU_INITIAL_MAP_STRONGLY_ORDERED + beq 0f + teq r9, #MMU_INITIAL_MAPPING_FLAG_DEVICE + ldreq r10, =MMU_INITIAL_MAP_DEVICE + /* r10 = mmu entry flags */ + +0: + orr r12, r10, r6, lsl #20 + /* r12 = phys addr | flags */ + + /* store into appropriate translation table entry */ + str r12, [r4, r7, lsl #2] + + /* loop until we're done */ + add r6, #1 + add r7, #1 + subs r8, #1 + bne 0b + + b .Linitial_mapping_loop + +.Linitial_mapping_done: + +#if MMU_WITH_TRAMPOLINE + /* move arm_kernel_translation_table address to r8 and + * set cacheable attributes on translation walk + */ + orr r8, r4, #MMU_TTBRx_FLAGS + + /* Prepare tt_trampoline page table */ + /* Calculate pagetable physical addresses */ + ldr r4, =tt_trampoline /* r4 = tt_trampoline vaddr */ + add r4, r4, r11 /* r4 = tt_trampoline paddr */ + + /* Zero tt_trampoline translation tables */ + mov r6, #0 + mov r7, #0 +1: + str r7, [r4, r6, lsl#2] + add r6, #1 + cmp r6, #0x1000 + blt 1b + + /* Setup 1M section mapping at + * phys -> phys and + * virt -> phys + */ + lsr r6, pc, #20 /* r6 = paddr index */ + ldr r7, =MMU_KERNEL_L1_PTE_FLAGS + add r7, r7, r6, lsl #20 /* r7 = pt entry */ + + str r7, [r4, r6, lsl #2] /* tt_trampoline[paddr index] = pt entry */ + + rsb r6, r11, r6, lsl #20 /* r6 = vaddr */ + str r7, [r4, r6, lsr #(20 - 2)] /* tt_trampoline[vaddr index] = pt entry */ +#endif // MMU_WITH_TRAMPOLINE + + /* set up the mmu */ + bl .Lmmu_setup +#endif // WITH_KERNEL_VM + + /* at this point we're running at our final location in virtual memory (if enabled) */ +.Lstack_setup: + /* set up the stack for irq, fiq, abort, undefined, system/user, and lastly supervisor mode */ + mov r12, #0 + + cpsid i,#0x12 /* irq */ + mov sp, r12 + + cpsid i,#0x11 /* fiq */ + mov sp, r12 + + cpsid i,#0x17 /* abort */ + mov sp, r12 + + cpsid i,#0x1b /* undefined */ + mov sp, r12 + + cpsid i,#0x1f /* system */ + mov sp, r12 + + cpsid i,#0x13 /* supervisor */ + ldr r12, =abort_stack + add r12, #ARCH_DEFAULT_STACK_SIZE + mov sp, r12 + + /* stay in supervisor mode from now on out */ + + /* copy the initialized data segment out of rom if necessary */ + ldr r4, =__data_start_rom + ldr r5, =__data_start + ldr r6, =__data_end + + cmp r4, r5 + beq .L__do_bss + +.L__copy_loop: + cmp r5, r6 + ldrlt r7, [r4], #4 + strlt r7, [r5], #4 + blt .L__copy_loop + +.L__do_bss: + /* clear out the bss */ + ldr r4, =__bss_start + ldr r5, =_end + mov r6, #0 +.L__bss_loop: + cmp r4, r5 + strlt r6, [r4], #4 + blt .L__bss_loop + + bl lk_main + b . + +#if WITH_KERNEL_VM + /* per cpu mmu setup, shared between primary and secondary cpus + args: + r4 == translation table physical + r8 == final translation table physical (if using trampoline) + */ +.Lmmu_setup: + /* Invalidate TLB */ + mov r12, #0 + mcr p15, 0, r12, c8, c7, 0 + isb + + /* Write 0 to TTBCR */ + mcr p15, 0, r12, c2, c0, 2 + isb + + /* Set cacheable attributes on translation walk */ + orr r12, r4, #MMU_TTBRx_FLAGS + + /* Write ttbr with phys addr of the translation table */ + mcr p15, 0, r12, c2, c0, 0 + isb + + /* Write DACR */ + mov r12, #0x1 + mcr p15, 0, r12, c3, c0, 0 + isb + + /* Read SCTLR into r12 */ + mrc p15, 0, r12, c1, c0, 0 + + /* Disable TRE/AFE */ + bic r12, #(1<<29 | 1<<28) + + /* Turn on the MMU */ + orr r12, #0x1 + + /* Write back SCTLR */ + mcr p15, 0, r12, c1, c0, 0 + isb + + /* Jump to virtual code address */ + ldr pc, =1f +1: + +#if MMU_WITH_TRAMPOLINE + /* Switch to main page table */ + mcr p15, 0, r8, c2, c0, 0 + isb +#endif + + /* Invalidate TLB */ + mov r12, #0 + mcr p15, 0, r12, c8, c7, 0 + isb + + /* assume lr was in physical memory, adjust it before returning */ + sub lr, r11 + bx lr +#endif + +#if WITH_SMP + /* secondary cpu entry point */ + /* r0 holds cpu number */ + /* r11 hold phys offset */ +FUNCTION(arm_secondary_setup) + /* all other cpus, trap and wait to be released */ +1: + wfe + ldr r12, =arm_boot_cpu_lock + add r12, r12, r11 + ldr r12, [r12] + cmp r12, #0 + bne 1b + + and r1, r0, #0xff + cmp r1, #(1 << SMP_CPU_CLUSTER_SHIFT) + bge unsupported_cpu_trap + bic r0, r0, #0xff + orr r0, r1, r0, LSR #(8 - SMP_CPU_CLUSTER_SHIFT) + + cmp r0, #SMP_MAX_CPUS + bge unsupported_cpu_trap + mov r5, r0 /* save cpu num */ + + /* set up the stack for irq, fiq, abort, undefined, system/user, and lastly supervisor mode */ + mov r1, #0 + cpsid i,#0x12 /* irq */ + mov sp, r1 + + cpsid i,#0x11 /* fiq */ + mov sp, r1 + + cpsid i,#0x17 /* abort */ + mov sp, r1 + + cpsid i,#0x1b /* undefined */ + mov sp, r1 + + cpsid i,#0x1f /* system */ + mov sp, r1 + + cpsid i,#0x13 /* supervisor */ + ldr r1, =abort_stack + mov r2, #ARCH_DEFAULT_STACK_SIZE + add r0, #1 + mul r2, r2, r0 + add r1, r2 + + mov sp, r1 + +#if WITH_KERNEL_VM + /* load the physical base of the translation table and clear the table */ + ldr r4, =arm_kernel_translation_table + add r4, r4, r11 + +#if MMU_WITH_TRAMPOLINE + /* move arm_kernel_translation_table address to r8 and + * set cacheable attributes on translation walk + */ + orr r8, r4, #MMU_TTBRx_FLAGS + + /* Prepare tt_trampoline page table */ + /* Calculate pagetable physical addresses */ + ldr r4, =tt_trampoline /* r4 = tt_trampoline vaddr */ + add r4, r4, r11 /* r4 = tt_trampoline paddr */ +#endif + + /* set up the mmu on this cpu and switch to virtual memory */ + bl .Lmmu_setup +#endif + + /* stay in supervisor and call into arm arch code to continue setup */ + mov r0, r5 + bl arm_secondary_entry + + /* cpus above the number we claim to support get trapped here */ +unsupported_cpu_trap: + wfe + b unsupported_cpu_trap +#endif + +.ltorg + +#if WITH_KERNEL_VM && MMU_WITH_TRAMPOLINE +.section ".bss.prebss.translation_table" +.align 14 +DATA(tt_trampoline) + .skip 16384 +#endif + +.data +.align 2 diff --git a/kernel/arch/arm/arm/thread.c b/kernel/arch/arm/arm/thread.c new file mode 100644 index 000000000..9316b54a6 --- /dev/null +++ b/kernel/arch/arm/arm/thread.c @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +struct context_switch_frame { + vaddr_t cp15_rw; + vaddr_t cp15_ro; + vaddr_t r4; + vaddr_t r5; + vaddr_t r6; + vaddr_t r7; + vaddr_t r8; + vaddr_t r9; + vaddr_t r10; + vaddr_t r11; + vaddr_t lr; +}; + +extern void arm_context_switch(addr_t *old_sp, addr_t new_sp); + +void arch_thread_initialize(thread_t *t, vaddr_t entry_point) +{ + // create a default stack frame on the stack + vaddr_t stack_top = (vaddr_t)t->stack + t->stack_size; + + // make sure the top of the stack is 8 byte aligned for EABI compliance + stack_top = ROUNDDOWN(stack_top, 8); + + struct context_switch_frame *frame = (struct context_switch_frame *)(stack_top); + frame--; + + // fill it in + memset(frame, 0, sizeof(*frame)); + frame->lr = (vaddr_t)entry_point; + + // set the stack pointer + t->arch.sp = (vaddr_t)frame; + +#if ARM_WITH_VFP + arm_fpu_thread_initialize(t); +#endif +} + +void arch_context_switch(thread_t *oldthread, thread_t *newthread) +{ +// TRACEF("arch_context_switch: cpu %u old %p (%s), new %p (%s)\n", arch_curr_cpu_num(), oldthread, oldthread->name, newthread, newthread->name); +#if ARM_WITH_VFP + arm_fpu_thread_swap(oldthread, newthread); +#endif + + arm_context_switch(&oldthread->arch.sp, newthread->arch.sp); +} + +void arch_dump_thread(thread_t *t) +{ + if (t->state != THREAD_RUNNING) { + dprintf(INFO, "\tarch: "); + dprintf(INFO, "sp 0x%lx\n", t->arch.sp); + } +} + diff --git a/kernel/arch/arm/arm/uspace_entry.S b/kernel/arch/arm/arm/uspace_entry.S new file mode 100644 index 000000000..67b2fb5b7 --- /dev/null +++ b/kernel/arch/arm/arm/uspace_entry.S @@ -0,0 +1,44 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +// void arm_uspace_entry(void *thread_arg, vaddr_t kstack, vaddr_t *ustack, uint32_t spsr, vaddr_t entry_point) __NO_RETURN; +FUNCTION(arm_uspace_entry) + // Move entry_point into LR + pop { r14 } + + // Set usermode SP + ldmia r2, { sp }^ + // Set usermode LR + mov r2, #0 + push { r2 } + ldmia sp, { lr }^ + pop { r2 } + + msr spsr, r3 + mov sp, r1 + + mov r1, #0 + mov r2, #0 + mov r3, #0 + mov r4, #0 + mov r5, #0 + mov r6, #0 + mov r7, #0 + mov r8, #0 + mov r9, #0 + mov r10, #0 + mov r11, #0 + mov r12, #0 + // Don't zero r13 and r14, they're per EL (SP and LR) + // Don't zero r15, it's PC + + mcr p15, 0, r1, c13, c0, 2 + mcr p15, 0, r1, c13, c0, 3 + + // thread_arg is already in r0, jump to usermode now + movs pc, r14 diff --git a/kernel/arch/arm/include/arch/arch_ops.h b/kernel/arch/arm/include/arch/arch_ops.h new file mode 100644 index 000000000..d0e490bc8 --- /dev/null +++ b/kernel/arch/arm/include/arch/arch_ops.h @@ -0,0 +1,412 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#ifndef ASSEMBLY + +#include +#include +#include +#include + +__BEGIN_CDECLS + +#if ARM_ISA_ARMV7 || (ARM_ISA_ARMV6 && !__thumb__) +#define ENABLE_CYCLE_COUNTER 1 + +// override of some routines +static inline void arch_enable_ints(void) +{ + CF; + __asm__ volatile("cpsie i"); +} + +static inline void arch_disable_ints(void) +{ + __asm__ volatile("cpsid i"); + CF; +} + +static inline bool arch_ints_disabled(void) +{ + unsigned int state; + +#if ARM_ISA_ARMV7M + __asm__ volatile("mrs %0, primask" : "=r"(state)); + state &= 0x1; +#else + __asm__ volatile("mrs %0, cpsr" : "=r"(state)); + state &= (1<<7); +#endif + + return !!state; +} + +static inline void arch_enable_fiqs(void) +{ + CF; + __asm__ volatile("cpsie f"); +} + +static inline void arch_disable_fiqs(void) +{ + __asm__ volatile("cpsid f"); + CF; +} + +static inline bool arch_fiqs_disabled(void) +{ + unsigned int state; + + __asm__ volatile("mrs %0, cpsr" : "=r"(state)); + state &= (1<<6); + + return !!state; +} + +static inline bool arch_in_int_handler(void) +{ + /* set by the interrupt glue to track that the cpu is inside a handler */ + extern bool __arm_in_handler; + + return __arm_in_handler; +} + +static inline void arch_spinloop_pause(void) +{ + __asm__ volatile("wfe"); +} + +static inline void arch_spinloop_signal(void) +{ + __asm__ volatile("sev"); +} + +static inline uint32_t arch_cycle_count(void) +{ +#if ARM_ISA_ARMV7M +#if ENABLE_CYCLE_COUNTER +#define DWT_CYCCNT (0xE0001004) + return *REG32(DWT_CYCCNT); +#else + return 0; +#endif +#elif ARM_ISA_ARMV7 + uint32_t count; + __asm__ volatile("mrc p15, 0, %0, c9, c13, 0" + : "=r" (count) + ); + return count; +#else +//#warning no arch_cycle_count implementation + return 0; +#endif +} + +#if WITH_SMP && ARM_ISA_ARMV7 +static inline uint arch_curr_cpu_num(void) +{ + uint32_t mpidr = arm_read_mpidr(); + return ((mpidr & ((1U << SMP_CPU_ID_BITS) - 1)) >> 8 << SMP_CPU_CLUSTER_SHIFT) | (mpidr & 0xff); +} + +extern uint arm_num_cpus; +static inline uint arch_max_num_cpus(void) +{ + return arm_num_cpus; +} +#else +static inline uint arch_curr_cpu_num(void) +{ + return 0; +} +static inline uint arch_max_num_cpus(void) +{ + return 1; +} +#endif + +/* defined in kernel/thread.h */ + +#if !ARM_ISA_ARMV7M +/* use the cpu local thread context pointer to store current_thread */ +static inline struct thread *get_current_thread(void) +{ + return (struct thread *)arm_read_tpidrprw(); +} + +static inline void set_current_thread(struct thread *t) +{ + arm_write_tpidrprw((uint32_t)t); +} +#else // ARM_ISA_ARM7M + +/* use a global pointer to store the current_thread */ +extern struct thread *_current_thread; + +static inline struct thread *get_current_thread(void) +{ + return _current_thread; +} + +static inline void set_current_thread(struct thread *t) +{ + _current_thread = t; +} + +#endif // !ARM_ISA_ARMV7M + +#elif ARM_ISA_ARMV6M // cortex-m0 cortex-m0+ + +/* the builtins are not implemented in this case, so implement them manually here */ +#define ARCH_IMPLEMENTS_ATOMICS 1 + +static inline void arch_enable_fiqs(void) +{ + CF; + __asm__ volatile("cpsie f"); +} + +static inline void arch_disable_fiqs(void) +{ + __asm__ volatile("cpsid f"); + CF; +} + +static inline bool arch_fiqs_disabled(void) +{ + unsigned int state; + + __asm__ volatile("mrs %0, cpsr" : "=r"(state)); + state &= (1<<6); + + return !!state; +} + +static inline void arch_enable_ints(void) +{ + CF; + __asm__ volatile("cpsie i"); +} +static inline void arch_disable_ints(void) +{ + __asm__ volatile("cpsid i"); + CF; +} + +static inline bool arch_ints_disabled(void) +{ + unsigned int state; + + __asm__ volatile("mrs %0, primask" : "=r"(state)); + state &= 0x1; + return !!state; +} + +static inline int atomic_add(volatile int *ptr, int val) +{ + int temp; + bool state; + + state = arch_ints_disabled(); + arch_disable_ints(); + temp = *ptr; + *ptr = temp + val; + if (!state) + arch_enable_ints(); + return temp; +} + +static inline int atomic_and(volatile int *ptr, int val) +{ + int temp; + bool state; + + state = arch_ints_disabled(); + arch_disable_ints(); + temp = *ptr; + *ptr = temp & val; + if (!state) + arch_enable_ints(); + return temp; +} + +static inline int atomic_or(volatile int *ptr, int val) +{ + int temp; + bool state; + + state = arch_ints_disabled(); + arch_disable_ints(); + temp = *ptr; + *ptr = temp | val; + if (!state) + arch_enable_ints(); + return temp; +} + +static inline int atomic_swap(volatile int *ptr, int val) +{ + int temp; + bool state; + + state = arch_ints_disabled(); + arch_disable_ints(); + temp = *ptr; + *ptr = val; + if (!state) + arch_enable_ints(); + return temp; +} + +static inline bool atomic_cmpxchg(volatile int *ptr, int *oldval, int newval) +{ + int temp; + bool state; + bool success; + + state = arch_ints_disabled(); + arch_disable_ints(); + temp = *ptr; + if (temp == oldval) { + *ptr = newval; + success = true; + } else { + *oldval = temp; + success = false; + } + if (!state) + arch_enable_ints(); + return success; +} + +static inline int atomic_load(volatile int *ptr) +{ + return *ptr; +} + +static inline void atomic_store(volatile int *ptr, int newval) +{ + *ptr = newval; +} + +static inline int atomic_swap_relaxed(volatile int *ptr, int val) +{ + return atomic_swap(ptr, val); +} + +static inline int atomic_add_relaxed(volatile int *ptr, int val) +{ + return atomic_add(ptr, val); +} + +static inline int atomic_and_relaxed(volatile int *ptr, int val) +{ + return atomic_and(ptr, val); +} + +static inline int atomic_or_relaxed(volatile int *ptr, int val) +{ + return atomic_or(ptr, val); +} + +static inline bool atomic_cmpxchg_relaxed(volatile int *ptr, int *oldval, int newval) +{ + return atomic_cmpxchg(ptr, oldval, newval); +} + +static int atomic_load_relaxed(volatile int *ptr) +{ + return atomic_load(ptr); +} + +static void atomic_store_relaxed(volatile int *ptr, int newval) +{ + atomic_store(ptr, newval); +} + +static inline uint32_t arch_cycle_count(void) +{ + return 0; +} + +static inline uint arch_curr_cpu_num(void) +{ + return 0; +} + +/* use a global pointer to store the current_thread */ +extern struct thread *_current_thread; + +static inline struct thread *get_current_thread(void) +{ + return _current_thread; +} + +static inline void set_current_thread(struct thread *t) +{ + _current_thread = t; +} + +#else // pre-armv6 || (armv6 & thumb) + +/* for pre-armv6 the bodies of these are too big to inline, call an assembly stub version */ +void _arch_enable_ints(void); +void _arch_disable_ints(void); + +/* the builtins are not implemented in this case, so implement them manually here */ +#define ARCH_IMPLEMENTS_ATOMICS 1 + +int _atomic_add(volatile int *ptr, int val); +int _atomic_and(volatile int *ptr, int val); +int _atomic_or(volatile int *ptr, int val); +int _atomic_add(volatile int *ptr, int val); +int _atomic_swap(volatile int *ptr, int val); +bool _atomic_cmpxchg(volatile int *ptr, int *oldval, int newval); + +uint32_t _arch_cycle_count(void); + +static inline int atomic_add(volatile int *ptr, int val) { return _atomic_add(ptr, val); } +static inline int atomic_and(volatile int *ptr, int val) { return _atomic_and(ptr, val); } +static inline int atomic_or(volatile int *ptr, int val) { return _atomic_or(ptr, val); } +static inline int atomic_swap(volatile int *ptr, int val) { return _atomic_swap(ptr, val); } +static inline bool atomic_cmpxchg(volatile int *ptr, int *oldval, int newval) { return _atomic_cmpxchg(ptr, oldval, newval); } +static inline void atomic_store(volatile int *ptr, int newval) { DMB; *ptr = newval; DMB; } +static inline int atomic_load(volatile int *ptr) { int v = *ptr; DMB; return v; } +static inline int atomic_add_relaxed(volatile int *ptr, int val) { return _atomic_add(ptr, val); } +static inline int atomic_and_relaxed(volatile int *ptr, int val) { return _atomic_and(ptr, val); } +static inline int atomic_or_relaxed(volatile int *ptr, int val) { return _atomic_or(ptr, val); } +static inline int atomic_swap_relaxed(volatile int *ptr, int val) { return _atomic_swap(ptr, val); } +static inline bool atomic_cmpxchg_relaxed(volatile int *ptr, int *oldval, int newval) { return _atomic_cmpxchg(ptr, oldval, newval); } +static inline void atomic_store_relaxed(volatile int *ptr, int newval) { *ptr = newval; } +static inline int atomic_load_relaxed(volatile int *ptr) { return *ptr; } + +static inline void arch_enable_ints(void) { _arch_enable_ints(); } +static inline void arch_disable_ints(void) { _arch_disable_ints(); } + +static inline uint32_t arch_cycle_count(void) { return _arch_cycle_count(); } + +#endif + +#define mb() DSB +#define wmb() DSB +#define rmb() DSB + +#ifdef WITH_SMP +#define smp_mb() DMB +#define smp_wmb() DMB +#define smp_rmb() DMB +#else +#define smp_mb() CF +#define smp_wmb() CF +#define smp_rmb() CF +#endif + +__END_CDECLS + +#endif // ASSEMBLY diff --git a/kernel/arch/arm/include/arch/arm.h b/kernel/arch/arm/include/arch/arm.h new file mode 100644 index 000000000..42b8fadd8 --- /dev/null +++ b/kernel/arch/arm/include/arch/arm.h @@ -0,0 +1,239 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +/* due to the cp15 accessors below, you're gonna have a bad time if you try + * to compile in thumb mode. Either compile in ARM only or get a thumb2 capable cpu. + +#if defined(__thumb__) && !defined(__thumb2__) +#error this file unsupported in thumb1 mode +#endif +*/ +__BEGIN_CDECLS + +#if ARM_ISA_ARMV7 +#define DSB __asm__ volatile("dsb" ::: "memory") +#define DMB __asm__ volatile("dmb" ::: "memory") +#define ISB __asm__ volatile("isb" ::: "memory") +#elif ARM_ISA_ARMV6 || ARM_ISA_ARMV6M +#define DSB __asm__ volatile("mcr p15, 0, %0, c7, c10, 4" :: "r" (0) : "memory") +#define ISB __asm__ volatile("mcr p15, 0, %0, c7, c5, 4" :: "r" (0) : "memory") +#define DMB __asm__ volatile("nop") +#else +#error unhandled arm isa +#endif +#define NOP __asm__ volatile("nop"); + +void arm_context_switch(vaddr_t *old_sp, vaddr_t new_sp); + +void arm_chain_load(paddr_t entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) __NO_RETURN; + +static inline uint32_t read_cpsr(void) +{ + uint32_t cpsr; + + __asm__ volatile("mrs %0, cpsr" : "=r" (cpsr)); + return cpsr; +} + +#define CPSR_MODE_MASK 0x1f +#define CPSR_MODE_USR 0x10 +#define CPSR_MODE_FIQ 0x11 +#define CPSR_MODE_IRQ 0x12 +#define CPSR_MODE_SVC 0x13 +#define CPSR_MODE_MON 0x16 +#define CPSR_MODE_ABT 0x17 +#define CPSR_MODE_UND 0x1b +#define CPSR_MODE_SYS 0x1f +#define CPSR_THUMB (1<<5) +#define CPSR_FIQ_MASK (1<<6) +#define CPSR_IRQ_MASK (1<<7) +#define CPSR_ABORT (1<<8) +#define CPSR_ENDIAN (1<<9) + +struct arm_iframe { +#if ARM_WITH_VFP + uint32_t fpexc; +#endif + uint32_t usp; + uint32_t ulr; + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t spsr; +}; + +struct arm_fault_frame { +#if ARM_WITH_VFP + uint32_t fpexc; +#endif + uint32_t usp; + uint32_t ulr; + uint32_t r[13]; + uint32_t lr; + uint32_t pc; + uint32_t spsr; +}; + +struct arm_mode_regs { + uint32_t usr_r13, usr_r14; + uint32_t fiq_r13, fiq_r14; + uint32_t irq_r13, irq_r14; + uint32_t svc_r13, svc_r14; + uint32_t abt_r13, abt_r14; + uint32_t und_r13, und_r14; + uint32_t sys_r13, sys_r14; +}; + +void arm_save_mode_regs(struct arm_mode_regs *regs); + +#define GEN_CP_REG_FUNCS(cp, reg, op1, c1, c2, op2) \ +static inline __ALWAYS_INLINE uint32_t arm_read_##reg(void) { \ + uint32_t val; \ + __asm__ volatile("mrc " #cp ", " #op1 ", %0, " #c1 "," #c2 "," #op2 : "=r" (val)); \ + return val; \ +} \ +\ +static inline __ALWAYS_INLINE uint32_t arm_read_##reg##_relaxed(void) { \ + uint32_t val; \ + __asm__("mrc " #cp ", " #op1 ", %0, " #c1 "," #c2 "," #op2 : "=r" (val)); \ + return val; \ +} \ +\ +static inline __ALWAYS_INLINE void arm_write_##reg(uint32_t val) { \ + __asm__ volatile("mcr " #cp ", " #op1 ", %0, " #c1 "," #c2 "," #op2 :: "r" (val)); \ + ISB; \ +} \ +\ +static inline __ALWAYS_INLINE void arm_write_##reg##_relaxed(uint32_t val) { \ + __asm__ volatile("mcr " #cp ", " #op1 ", %0, " #c1 "," #c2 "," #op2 :: "r" (val)); \ +} + +#define GEN_CP15_REG_FUNCS(reg, op1, c1, c2, op2) \ + GEN_CP_REG_FUNCS(p15, reg, op1, c1, c2, op2) + +#define GEN_CP14_REG_FUNCS(reg, op1, c1, c2, op2) \ + GEN_CP_REG_FUNCS(p14, reg, op1, c1, c2, op2) + +/* armv6+ control regs */ +GEN_CP15_REG_FUNCS(sctlr, 0, c1, c0, 0); +GEN_CP15_REG_FUNCS(actlr, 0, c1, c0, 1); +GEN_CP15_REG_FUNCS(cpacr, 0, c1, c0, 2); + +GEN_CP15_REG_FUNCS(ttbr, 0, c2, c0, 0); +GEN_CP15_REG_FUNCS(ttbr0, 0, c2, c0, 0); +GEN_CP15_REG_FUNCS(ttbr1, 0, c2, c0, 1); +GEN_CP15_REG_FUNCS(ttbcr, 0, c2, c0, 2); +GEN_CP15_REG_FUNCS(dacr, 0, c3, c0, 0); +GEN_CP15_REG_FUNCS(dfsr, 0, c5, c0, 0); +GEN_CP15_REG_FUNCS(ifsr, 0, c5, c0, 1); +GEN_CP15_REG_FUNCS(dfar, 0, c6, c0, 0); +GEN_CP15_REG_FUNCS(wfar, 0, c6, c0, 1); +GEN_CP15_REG_FUNCS(ifar, 0, c6, c0, 2); + +GEN_CP15_REG_FUNCS(fcseidr, 0, c13, c0, 0); +GEN_CP15_REG_FUNCS(contextidr, 0, c13, c0, 1); +GEN_CP15_REG_FUNCS(tpidrurw, 0, c13, c0, 2); +GEN_CP15_REG_FUNCS(tpidruro, 0, c13, c0, 3); +GEN_CP15_REG_FUNCS(tpidrprw, 0, c13, c0, 4); + +/* armv7+ */ +GEN_CP15_REG_FUNCS(midr, 0, c0, c0, 0); +GEN_CP15_REG_FUNCS(mpidr, 0, c0, c0, 5); +GEN_CP15_REG_FUNCS(vbar, 0, c12, c0, 0); +GEN_CP15_REG_FUNCS(cbar, 4, c15, c0, 0); + +GEN_CP15_REG_FUNCS(ats1cpr, 0, c7, c8, 0); +GEN_CP15_REG_FUNCS(ats1cpw, 0, c7, c8, 1); +GEN_CP15_REG_FUNCS(ats1cur, 0, c7, c8, 2); +GEN_CP15_REG_FUNCS(ats1cuw, 0, c7, c8, 3); +GEN_CP15_REG_FUNCS(ats12nsopr, 0, c7, c8, 4); +GEN_CP15_REG_FUNCS(ats12nsopw, 0, c7, c8, 5); +GEN_CP15_REG_FUNCS(ats12nsour, 0, c7, c8, 6); +GEN_CP15_REG_FUNCS(ats12nsouw, 0, c7, c8, 7); +GEN_CP15_REG_FUNCS(par, 0, c7, c4, 0); + +/* Branch predictor invalidate */ +GEN_CP15_REG_FUNCS(bpiall, 0, c7, c5, 6); +GEN_CP15_REG_FUNCS(bpimva, 0, c7, c5, 7); +GEN_CP15_REG_FUNCS(bpiallis, 0, c7, c1, 6); + +/* tlb registers */ +GEN_CP15_REG_FUNCS(tlbiallis, 0, c8, c3, 0); +GEN_CP15_REG_FUNCS(tlbimvais, 0, c8, c3, 1); +GEN_CP15_REG_FUNCS(tlbiasidis, 0, c8, c3, 2); +GEN_CP15_REG_FUNCS(tlbimvaais, 0, c8, c3, 3); +GEN_CP15_REG_FUNCS(itlbiall, 0, c8, c5, 0); +GEN_CP15_REG_FUNCS(itlbimva, 0, c8, c5, 1); +GEN_CP15_REG_FUNCS(itlbiasid, 0, c8, c5, 2); +GEN_CP15_REG_FUNCS(dtlbiall, 0, c8, c6, 0); +GEN_CP15_REG_FUNCS(dtlbimva, 0, c8, c6, 1); +GEN_CP15_REG_FUNCS(dtlbiasid, 0, c8, c6, 2); +GEN_CP15_REG_FUNCS(tlbiall, 0, c8, c7, 0); +GEN_CP15_REG_FUNCS(tlbimva, 0, c8, c7, 1); +GEN_CP15_REG_FUNCS(tlbiasid, 0, c8, c7, 2); +GEN_CP15_REG_FUNCS(tlbimvaa, 0, c8, c7, 3); + +GEN_CP15_REG_FUNCS(l2ctlr, 1, c9, c0, 2); +GEN_CP15_REG_FUNCS(l2ectlr, 1, c9, c0, 3); + +/* debug registers */ +GEN_CP14_REG_FUNCS(dbddidr, 0, c0, c0, 0); +GEN_CP14_REG_FUNCS(dbgdrar, 0, c1, c0, 0); +GEN_CP14_REG_FUNCS(dbgdsar, 0, c2, c0, 0); +GEN_CP14_REG_FUNCS(dbgdscr, 0, c0, c1, 0); +GEN_CP14_REG_FUNCS(dbgdtrtxint, 0, c0, c5, 0); +GEN_CP14_REG_FUNCS(dbgdtrrxint, 0, c0, c5, 0); /* alias to previous */ +GEN_CP14_REG_FUNCS(dbgwfar, 0, c0, c6, 0); +GEN_CP14_REG_FUNCS(dbgvcr, 0, c0, c7, 0); +GEN_CP14_REG_FUNCS(dbgecr, 0, c0, c9, 0); +GEN_CP14_REG_FUNCS(dbgdsccr, 0, c0, c10, 0); +GEN_CP14_REG_FUNCS(dbgdsmcr, 0, c0, c11, 0); +GEN_CP14_REG_FUNCS(dbgdtrrxext, 0, c0, c0, 2); +GEN_CP14_REG_FUNCS(dbgdscrext, 0, c0, c2, 2); +GEN_CP14_REG_FUNCS(dbgdtrtxext, 0, c0, c3, 2); +GEN_CP14_REG_FUNCS(dbgdrcr, 0, c0, c4, 2); +GEN_CP14_REG_FUNCS(dbgvr0, 0, c0, c0, 4); +GEN_CP14_REG_FUNCS(dbgvr1, 0, c0, c1, 4); +GEN_CP14_REG_FUNCS(dbgvr2, 0, c0, c2, 4); +GEN_CP14_REG_FUNCS(dbgbcr0, 0, c0, c0, 5); +GEN_CP14_REG_FUNCS(dbgbcr1, 0, c0, c1, 5); +GEN_CP14_REG_FUNCS(dbgbcr2, 0, c0, c2, 5); +GEN_CP14_REG_FUNCS(dbgwvr0, 0, c0, c0, 6); +GEN_CP14_REG_FUNCS(dbgwvr1, 0, c0, c1, 6); +GEN_CP14_REG_FUNCS(dbgwcr0, 0, c0, c0, 7); +GEN_CP14_REG_FUNCS(dbgwcr1, 0, c0, c1, 7); +GEN_CP14_REG_FUNCS(dbgoslar, 0, c1, c0, 4); +GEN_CP14_REG_FUNCS(dbgoslsr, 0, c1, c1, 4); +GEN_CP14_REG_FUNCS(dbgossrr, 0, c1, c2, 4); +GEN_CP14_REG_FUNCS(dbgprcr, 0, c1, c4, 4); +GEN_CP14_REG_FUNCS(dbgprsr, 0, c1, c5, 4); +GEN_CP14_REG_FUNCS(dbgclaimset, 0, c7, c8, 6); +GEN_CP14_REG_FUNCS(dbgclaimclr, 0, c7, c9, 6); +GEN_CP14_REG_FUNCS(dbgauthstatus, 0, c7, c14, 6); +GEN_CP14_REG_FUNCS(dbgdevid, 0, c7, c2, 7); + +/* fpu */ +void arm_fpu_set_enable(bool enable); +#if ARM_WITH_VFP +void arm_fpu_undefined_instruction(struct arm_iframe *frame); +struct thread; +void arm_fpu_thread_initialize(struct thread *t); +void arm_fpu_thread_swap(struct thread *oldthread, struct thread *newthread); +#endif + +__END_CDECLS diff --git a/kernel/arch/arm/include/arch/arm/cores.h b/kernel/arch/arm/include/arch/arm/cores.h new file mode 100644 index 000000000..e0610bdeb --- /dev/null +++ b/kernel/arch/arm/include/arch/arm/cores.h @@ -0,0 +1,109 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* + * make the gcc built in define a little easier to deal with + * to decide what core it is generating code for + * + * ARM_ARCH_LEVEL gets assigned a numeric value of the general family + * + * ARM_ARCH_* gets defined for each feature recursively + */ + +/* echo | gcc -E -dM - to dump builtin defines */ + +#if defined(__ARM_ARCH_7EM__) +#define ARM_ARCH_7EM 1 +#endif +#if defined(__ARM_ARCH_7M__) || defined(ARM_ARCH_7EM) +#define ARM_ARCH_7M 1 +#endif +#if defined(__ARM_ARCH_7R__) +#define ARM_ARCH_7R 1 +#endif +#if defined(__ARM_ARCH_7A__) || defined(ARM_ARCH_7R) +#define ARM_ARCH_7A 1 +#endif +#if defined(__ARM_ARCH_7__) || defined(ARM_ARCH_7A) || defined(ARM_ARCH_7M) +#define ARM_ARCH_7 1 +#ifndef ARM_ARCH_LEVEL +#define ARM_ARCH_LEVEL 7 +#endif +#endif + +#if defined(__ARM_ARCH_6M__) +#define ARM_ARCH_6M 1 +#endif +#if defined(__ARM_ARCH_6T2__) || defined(ARM_ARCH_7) +#define ARM_ARCH_6T2 1 +#endif +#if defined(__ARM_ARCH_6ZK__) +#define ARM_ARCH_6ZK 1 +#endif +#if defined(__ARM_ARCH_6Z__) || defined(ARM_ARCH_6ZK) +#define ARM_ARCH_6Z 1 +#endif +#if defined(__ARM_ARCH_6K__) || defined(ARM_ARCH_6ZK) || defined(ARM_ARCH_7) +#define ARM_ARCH_6K 1 +#endif +#if defined(__ARM_ARCH_6J__) +#define ARM_ARCH_6J 1 +#endif +#if defined(__ARM_ARCH_6__) || defined(ARM_ARCH_6J) || defined(ARM_ARCH_6K) || defined(ARM_ARCH_6Z) || defined(ARM_ARCH_6T2) || defined(ARM_ARCH_6M) +#define ARM_ARCH_6 1 +#ifndef ARM_ARCH_LEVEL +#define ARM_ARCH_LEVEL 6 +#endif +#endif + +#if defined(__ARM_ARCH_5TEJ__) +#define ARM_ARCH_5TEJ 1 +#endif +#if defined(__ARM_ARCH_5TE__) || defined(ARM_ARCH_5TEJ) || defined(ARM_ARCH_6) +#define ARM_ARCH_5TE 1 +#endif +#if defined(__ARM_ARCH_5E__) || defined(ARM_ARCH_5TE) +#define ARM_ARCH_5E 1 +#endif +#if defined(__ARM_ARCH_5T__) || defined(ARM_ARCH_5TE) +#define ARM_ARCH_5T 1 +#endif +#if defined(__ARM_ARCH_5__) || defined(ARM_ARCH_5E) || defined(ARM_ARCH_5T) +#define ARM_ARCH_5 1 +#ifndef ARM_ARCH_LEVEL +#define ARM_ARCH_LEVEL 5 +#endif +#endif + +#if defined(__ARM_ARCH_4T__) || defined(ARM_ARCH_5T) +#define ARM_ARCH_4T 1 +#endif +#if defined(__ARM_ARCH_4__) || defined(ARM_ARCH_4T) || defined(ARM_ARCH_5) +#define ARM_ARCH_4 1 +#ifndef ARM_ARCH_LEVEL +#define ARM_ARCH_LEVEL 4 +#endif +#endif + +#if 0 +/* test */ +#if ARM_ARCH_LEVEL >= 7 +#warning ARM_ARCH_LEVEL >= 7 +#endif +#if ARM_ARCH_LEVEL >= 6 +#warning ARM_ARCH_LEVEL >= 6 +#endif +#if ARM_ARCH_LEVEL >= 5 +#warning ARM_ARCH_LEVEL >= 5 +#endif +#if ARM_ARCH_LEVEL >= 4 +#warning ARM_ARCH_LEVEL >= 4 +#endif +#endif + diff --git a/kernel/arch/arm/include/arch/arm/dcc.h b/kernel/arch/arm/include/arch/arm/dcc.h new file mode 100644 index 000000000..5ac1159be --- /dev/null +++ b/kernel/arch/arm/include/arch/arm/dcc.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +/* dcc */ +typedef void (*dcc_rx_callback_t)(uint32_t val); + +status_t arm_dcc_enable(dcc_rx_callback_t rx_callback); + +bool arm_dcc_read_available(void); +ssize_t arm_dcc_read(uint32_t *buf, size_t len, lk_time_t timeout); +ssize_t arm_dcc_write(const uint32_t *buf, size_t len, lk_time_t timeout); + +__END_CDECLS diff --git a/kernel/arch/arm/include/arch/arm/mmu.h b/kernel/arch/arm/include/arch/arm/mmu.h new file mode 100644 index 000000000..4a4acd1bb --- /dev/null +++ b/kernel/arch/arm/include/arch/arm/mmu.h @@ -0,0 +1,283 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#define KB (1024UL) +#define MB (1024UL*1024UL) +#define GB (1024UL*1024UL*1024UL) + +#define SECTION_SIZE MB +#define SUPERSECTION_SIZE (16 * MB) +#define TT_ENTRY_COUNT (4096) + +#if defined(ARM_ISA_ARMV6) | defined(ARM_ISA_ARMV7) + +#define MMU_MEMORY_L1_DESCRIPTOR_INVALID (0x0 << 0) +#define MMU_MEMORY_L1_DESCRIPTOR_PAGE_TABLE (0x1 << 0) +#define MMU_MEMORY_L1_DESCRIPTOR_SECTION (0x2 << 0) +#define MMU_MEMORY_L1_DESCRIPTOR_SUPERSECTION ((0x2 << 0) | (0x1 << 18)) +#define MMU_MEMORY_L1_DESCRIPTOR_MASK (0x3 << 0) + +#define MMU_MEMORY_L2_DESCRIPTOR_INVALID (0x0 << 0) +#define MMU_MEMORY_L2_DESCRIPTOR_LARGE_PAGE (0x1 << 0) +#define MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE (0x2 << 0) +#define MMU_MEMORY_L2_DESCRIPTOR_SMALL_PAGE_XN (0x3 << 0) +#define MMU_MEMORY_L2_DESCRIPTOR_MASK (0x3 << 0) + +/* C, B and TEX[2:0] encodings without TEX remap (for first level descriptors) */ +/* TEX | CB */ +#define MMU_MEMORY_L1_TYPE_STRONGLY_ORDERED ((0x0 << 12) | (0x0 << 2)) +#define MMU_MEMORY_L1_TYPE_DEVICE_SHARED ((0x0 << 12) | (0x1 << 2)) +#define MMU_MEMORY_L1_TYPE_DEVICE_NON_SHARED ((0x2 << 12) | (0x0 << 2)) +#define MMU_MEMORY_L1_TYPE_NORMAL ((0x1 << 12) | (0x0 << 2)) +#define MMU_MEMORY_L1_TYPE_NORMAL_WRITE_THROUGH ((0x0 << 12) | (0x2 << 2)) +#define MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_NO_ALLOCATE ((0x0 << 12) | (0x3 << 2)) +#define MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE ((0x1 << 12) | (0x3 << 2)) +#define MMU_MEMORY_L1_TYPE_MASK ((0x7 << 12) | (0x3 << 2)) + +#define MMU_MEMORY_L1_TYPE_INNER_WRITE_BACK_ALLOCATE ((0x4 << 12) | (0x1 << 2)) + +/* C, B and TEX[2:0] encodings without TEX remap (for second level descriptors) */ +/* TEX | CB */ +#define MMU_MEMORY_L2_TYPE_STRONGLY_ORDERED ((0x0 << 6) | (0x0 << 2)) +#define MMU_MEMORY_L2_TYPE_DEVICE_SHARED ((0x0 << 6) | (0x1 << 2)) +#define MMU_MEMORY_L2_TYPE_DEVICE_NON_SHARED ((0x2 << 6) | (0x0 << 2)) +#define MMU_MEMORY_L2_TYPE_NORMAL ((0x1 << 6) | (0x0 << 2)) +#define MMU_MEMORY_L2_TYPE_NORMAL_WRITE_THROUGH ((0x0 << 6) | (0x2 << 2)) +#define MMU_MEMORY_L2_TYPE_NORMAL_WRITE_BACK_NO_ALLOCATE ((0x0 << 6) | (0x3 << 2)) +#define MMU_MEMORY_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE ((0x1 << 6) | (0x3 << 2)) +#define MMU_MEMORY_L2_TYPE_MASK ((0x7 << 6) | (0x3 << 2)) + +#define MMU_MEMORY_DOMAIN_MEM (0) + +/* + * AP (Access Permissions) + * +-------------------------+ + * | AP P U | + * +-------------------------+ + * | | + * | 000 NA NA | + * | | + * | 001 RW NA | + * | | + * | 010 RW R | + * | | + * | 011 RW RW | + * | | + * | 101 R NA | + * | | + * | 111 R R | + * | | + * +-------------------------+ + * + * NA = No Access + * RW = Read/Write + * R = Read only + * + * P = Privileged modes + * U = ~P + * + */ +#define MMU_MEMORY_L1_AP_P_NA_U_NA ((0x0 << 15) | (0x0 << 10)) +#define MMU_MEMORY_L1_AP_P_RW_U_RO ((0x0 << 15) | (0x2 << 10)) /* Obsolete */ +#define MMU_MEMORY_L1_AP_P_RW_U_RW ((0x0 << 15) | (0x3 << 10)) +#define MMU_MEMORY_L1_AP_P_RW_U_NA ((0x0 << 15) | (0x1 << 10)) +#define MMU_MEMORY_L1_AP_P_RO_U_RO ((0x1 << 15) | (0x3 << 10)) +#define MMU_MEMORY_L1_AP_P_RO_U_NA ((0x1 << 15) | (0x1 << 10)) +#define MMU_MEMORY_L1_AP_MASK ((0x1 << 15) | (0x3 << 10)) + +#define MMU_MEMORY_L2_AP_P_NA_U_NA ((0x0 << 9) | (0x0 << 4)) +#define MMU_MEMORY_L2_AP_P_RW_U_RO ((0x0 << 9) | (0x2 << 4)) /* Obsolete */ +#define MMU_MEMORY_L2_AP_P_RW_U_RW ((0x0 << 9) | (0x3 << 4)) +#define MMU_MEMORY_L2_AP_P_RW_U_NA ((0x0 << 9) | (0x1 << 4)) +#define MMU_MEMORY_L2_AP_P_RO_U_RO ((0x1 << 9) | (0x3 << 4)) +#define MMU_MEMORY_L2_AP_P_RO_U_NA ((0x1 << 9) | (0x1 << 4)) +#define MMU_MEMORY_L2_AP_MASK ((0x1 << 9) | (0x3 << 4)) + +#define MMU_MEMORY_L1_PAGETABLE_NON_SECURE (1 << 3) + +#define MMU_MEMORY_L1_SECTION_NON_SECURE (1 << 19) +#define MMU_MEMORY_L1_SECTION_SHAREABLE (1 << 16) +#define MMU_MEMORY_L1_SECTION_NON_GLOBAL (1 << 17) +#define MMU_MEMORY_L1_SECTION_XN (1 << 4) + +#define MMU_MEMORY_L1_CB_SHIFT 2 +#define MMU_MEMORY_L1_TEX_SHIFT 12 + +#define MMU_MEMORY_SET_L1_INNER(val) (((val) & 0x3) << MMU_MEMORY_L1_CB_SHIFT) +#define MMU_MEMORY_SET_L1_OUTER(val) (((val) & 0x3) << MMU_MEMORY_L1_TEX_SHIFT) +#define MMU_MEMORY_SET_L1_CACHEABLE_MEM (0x4 << MMU_MEMORY_L1_TEX_SHIFT) + +#define MMU_MEMORY_L2_SHAREABLE (1 << 10) +#define MMU_MEMORY_L2_NON_GLOBAL (1 << 11) + +#define MMU_MEMORY_L2_CB_SHIFT 2 +#define MMU_MEMORY_L2_TEX_SHIFT 6 + +#define MMU_MEMORY_NON_CACHEABLE 0 +#define MMU_MEMORY_WRITE_BACK_ALLOCATE 1 +#define MMU_MEMORY_WRITE_THROUGH_NO_ALLOCATE 2 +#define MMU_MEMORY_WRITE_BACK_NO_ALLOCATE 3 + +#define MMU_MEMORY_SET_L2_INNER(val) (((val) & 0x3) << MMU_MEMORY_L2_CB_SHIFT) +#define MMU_MEMORY_SET_L2_OUTER(val) (((val) & 0x3) << MMU_MEMORY_L2_TEX_SHIFT) +#define MMU_MEMORY_SET_L2_CACHEABLE_MEM (0x4 << MMU_MEMORY_L2_TEX_SHIFT) + +#define MMU_MEMORY_L1_SECTION_ADDR(x) ((x) & ~((1<<20)-1)) +#define MMU_MEMORY_L1_PAGE_TABLE_ADDR(x) ((x) & ~((1<<10)-1)) + +#define MMU_MEMORY_L2_SMALL_PAGE_ADDR(x) ((x) & ~((1<<12)-1)) +#define MMU_MEMORY_L2_LARGE_PAGE_ADDR(x) ((x) & ~((1<<16)-1)) + +#define MMU_MEMORY_TTBR_RGN(x) (((x) & 0x3) << 3) +/* IRGN[1:0] is encoded as: IRGN[0] in TTBRx[6], and IRGN[1] in TTBRx[0] */ +#define MMU_MEMORY_TTBR_IRGN(x) ((((x) & 0x1) << 6) | \ + ((((x) >> 1) & 0x1) << 0)) +#define MMU_MEMORY_TTBR_S (1 << 1) +#define MMU_MEMORY_TTBR_NOS (1 << 5) + +/* Default configuration for main kernel page table: + * - section mappings for memory + * - do cached translation walks + */ + +/* Enable cached page table walks: + * inner/outer (IRGN/RGN): write-back + write-allocate + * (select inner sharable on smp) + */ +#if WITH_SMP +#define MMU_TTBRx_SHARABLE_FLAGS (MMU_MEMORY_TTBR_S | MMU_MEMORY_TTBR_NOS) +#else +#define MMU_TTBRx_SHARABLE_FLAGS (0) +#endif +#define MMU_TTBRx_FLAGS \ + (MMU_MEMORY_TTBR_RGN(MMU_MEMORY_WRITE_BACK_ALLOCATE) |\ + MMU_MEMORY_TTBR_IRGN(MMU_MEMORY_WRITE_BACK_ALLOCATE) | \ + MMU_TTBRx_SHARABLE_FLAGS) + +/* Section mapping, TEX[2:0]=001, CB=11, S=1, AP[2:0]=001 */ +#if WITH_SMP +#define MMU_KERNEL_L1_PTE_FLAGS \ + (MMU_MEMORY_L1_DESCRIPTOR_SECTION | \ + MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE | \ + MMU_MEMORY_L1_AP_P_RW_U_NA | \ + MMU_MEMORY_L1_SECTION_SHAREABLE) +#else +#define MMU_KERNEL_L1_PTE_FLAGS \ + (MMU_MEMORY_L1_DESCRIPTOR_SECTION | \ + MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE | \ + MMU_MEMORY_L1_AP_P_RW_U_NA) +#endif + +#define MMU_INITIAL_MAP_STRONGLY_ORDERED \ + (MMU_MEMORY_L1_DESCRIPTOR_SECTION | \ + MMU_MEMORY_L1_TYPE_STRONGLY_ORDERED | \ + MMU_MEMORY_L1_AP_P_RW_U_NA) + +#define MMU_INITIAL_MAP_DEVICE \ + (MMU_MEMORY_L1_DESCRIPTOR_SECTION | \ + MMU_MEMORY_L1_TYPE_DEVICE_SHARED | \ + MMU_MEMORY_L1_AP_P_RW_U_NA) + +#endif // armv6 | armv7 + +#ifndef ASSEMBLY + +#include +#include +#include +#include + +__BEGIN_CDECLS + +void arm_mmu_early_init(void); +void arm_mmu_init(void); +status_t arm_vtop(addr_t va, addr_t *pa); + +/* tlb routines */ + +static inline void arm_after_invalidate_tlb_barrier(void) +{ +#if WITH_SMP + arm_write_bpiallis(0); +#else + arm_write_bpiall(0); +#endif + DSB; + ISB; +} + +static inline void arm_invalidate_tlb_global_no_barrier(void) +{ +#if WITH_SMP + arm_write_tlbiallis(0); +#else + arm_write_tlbiall(0); +#endif +} + +static inline void arm_invalidate_tlb_global(void) +{ + DSB; + arm_invalidate_tlb_global_no_barrier(); + arm_after_invalidate_tlb_barrier(); +} + +static inline void arm_invalidate_tlb_mva_no_barrier(vaddr_t va) +{ +#if WITH_SMP + arm_write_tlbimvaais(va & 0xfffff000); +#else + arm_write_tlbimvaa(va & 0xfffff000); +#endif +} + +static inline void arm_invalidate_tlb_mva(vaddr_t va) +{ + DSB; + arm_invalidate_tlb_mva_no_barrier(va); + arm_after_invalidate_tlb_barrier(); +} + + +static inline void arm_invalidate_tlb_asid_no_barrier(uint8_t asid) +{ +#if WITH_SMP + arm_write_tlbiasidis(asid); +#else + arm_write_tlbiasid(asid); +#endif +} + +static inline void arm_invalidate_tlb_asid(uint8_t asid) +{ + DSB; + arm_invalidate_tlb_asid_no_barrier(asid); + arm_after_invalidate_tlb_barrier(); +} + +static inline void arm_invalidate_tlb_mva_asid_no_barrier(vaddr_t va, uint8_t asid) +{ +#if WITH_SMP + arm_write_tlbimvais((va & 0xfffff000) | asid); +#else + arm_write_tlbimva((va & 0xfffff000) | asid); +#endif +} + +static inline void arm_invalidate_tlb_mva_asid(vaddr_t va, uint8_t asid) +{ + DSB; + arm_invalidate_tlb_mva_asid_no_barrier(va, asid); + arm_after_invalidate_tlb_barrier(); +} + +__END_CDECLS + +#endif /* ASSEMBLY */ diff --git a/kernel/arch/arm/include/arch/asm.h b/kernel/arch/arm/include/arch/asm.h new file mode 100644 index 000000000..7e8037b2b --- /dev/null +++ b/kernel/arch/arm/include/arch/asm.h @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#if ARM_ARCH_LEVEL >= 7 +#define LOADCONST(reg, c) \ + movw reg, #:lower16: c; \ + movt reg, #:upper16: c +#else +#define LOADCONST(reg, c) ldr reg, =##c +#endif + diff --git a/kernel/arch/arm/include/arch/asm_macros.h b/kernel/arch/arm/include/arch/asm_macros.h new file mode 100644 index 000000000..b04070c34 --- /dev/null +++ b/kernel/arch/arm/include/arch/asm_macros.h @@ -0,0 +1,17 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015, Google Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* Set fault handler for next instruction */ +.macro set_fault_handler, handler +.Lfault_location\@: +.pushsection .rodata.fault_handler_table +.long .Lfault_location\@ +.long \handler +.popsection +.endm diff --git a/kernel/arch/arm/include/arch/defines.h b/kernel/arch/arm/include/arch/defines.h new file mode 100644 index 000000000..8e1fcfc6b --- /dev/null +++ b/kernel/arch/arm/include/arch/defines.h @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* arm specific stuff */ +#define PAGE_SIZE 4096 +#define PAGE_SIZE_SHIFT 12 + +#if ARM_CPU_ARM7 +/* irrelevant, no consistent cache */ +#define CACHE_LINE 32 +#elif ARM_CPU_ARM926 +#define CACHE_LINE 32 +#elif ARM_CPU_ARM1136 +#define CACHE_LINE 32 +#elif ARM_CPU_ARMEMU +#define CACHE_LINE 32 +#elif ARM_CPU_CORTEX_A7 +#define CACHE_LINE 64 /* XXX L1 icache is 32 bytes */ +#elif ARM_CPU_CORTEX_A8 +#define CACHE_LINE 64 +#elif ARM_CPU_CORTEX_A9 +#define CACHE_LINE 32 +#elif ARM_CPU_CORTEX_M0 || ARM_CPU_CORTEX_M0_PLUS || ARM_CPU_CORTEX_M3 || ARM_CPU_CORTEX_M4 +#define CACHE_LINE 32 /* doesn't actually matter */ +#elif ARM_CPU_CORTEX_M7 +#define CACHE_LINE 32 +#elif ARM_CPU_CORTEX_A15 +#define CACHE_LINE 64 +#else +#error unknown cpu +#endif diff --git a/kernel/arch/arm/include/arch/spinlock.h b/kernel/arch/arm/include/arch/spinlock.h new file mode 100644 index 000000000..9c4810f29 --- /dev/null +++ b/kernel/arch/arm/include/arch/spinlock.h @@ -0,0 +1,96 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS; + +#define SPIN_LOCK_INITIAL_VALUE (0) + +typedef unsigned long spin_lock_t; + +typedef unsigned long spin_lock_saved_state_t; +typedef unsigned long spin_lock_save_flags_t; + +static inline void arch_spin_lock_init(spin_lock_t *lock) +{ + *lock = SPIN_LOCK_INITIAL_VALUE; +} + +static inline bool arch_spin_lock_held(spin_lock_t *lock) +{ + return *lock != 0; +} + +#if WITH_SMP + +void arch_spin_lock(spin_lock_t *lock); +int arch_spin_trylock(spin_lock_t *lock); +void arch_spin_unlock(spin_lock_t *lock); + +#else + +static inline void arch_spin_lock(spin_lock_t *lock) +{ + *lock = 1; +} + +static inline int arch_spin_trylock(spin_lock_t *lock) +{ + return 0; +} + +static inline void arch_spin_unlock(spin_lock_t *lock) +{ + *lock = 0; +} + +#endif + +/* ARM specific flags */ +#define SPIN_LOCK_FLAG_IRQ 0x40000000 +#define SPIN_LOCK_FLAG_FIQ 0x80000000 /* Do not use unless IRQs are already disabled */ +#define SPIN_LOCK_FLAG_IRQ_FIQ (SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ) + +/* default arm flag is to just disable plain irqs */ +#define ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS SPIN_LOCK_FLAG_IRQ + +enum { + /* private */ + SPIN_LOCK_STATE_RESTORE_IRQ = 1, + SPIN_LOCK_STATE_RESTORE_FIQ = 2, +}; + +static inline void +arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) +{ + spin_lock_saved_state_t state = 0; + if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_IRQ; + arch_disable_ints(); + } + if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_FIQ; + arch_disable_fiqs(); + } + *statep = state; +} + +static inline void +arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) +{ + if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) + arch_enable_fiqs(); + if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) + arch_enable_ints(); +} + +__END_CDECLS; diff --git a/kernel/arch/arm/rules.mk b/kernel/arch/arm/rules.mk new file mode 100644 index 000000000..fb622f29e --- /dev/null +++ b/kernel/arch/arm/rules.mk @@ -0,0 +1,365 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +# can override this in local.mk +ENABLE_THUMB?=true + +# default to the regular arm subarch +SUBARCH := arm + +GLOBAL_DEFINES += \ + ARM_CPU_$(ARM_CPU)=1 + +# do set some options based on the cpu core +HANDLED_CORE := false +ifeq ($(ARM_CPU),cortex-m0) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_M0=1 \ + ARM_ISA_ARMV6M=1 \ + ARM_WITH_THUMB=1 +HANDLED_CORE := true +ENABLE_THUMB := true +SUBARCH := arm-m +endif +ifeq ($(ARM_CPU),cortex-m0plus) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_M0_PLUS=1 \ + ARM_ISA_ARMV6M=1 \ + ARM_WITH_THUMB=1 +HANDLED_CORE := true +ENABLE_THUMB := true +SUBARCH := arm-m +endif +ifeq ($(ARM_CPU),cortex-m3) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_M3=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7M=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 +HANDLED_CORE := true +ENABLE_THUMB := true +SUBARCH := arm-m +endif +ifeq ($(ARM_CPU),cortex-m4) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_M4=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7M=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 +HANDLED_CORE := true +ENABLE_THUMB := true +SUBARCH := arm-m +endif +ifeq ($(ARM_CPU),cortex-m4f) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_M4=1 \ + ARM_CPU_CORTEX_M4F=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7M=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_VFP=1 \ + __FPU_PRESENT=1 +HANDLED_CORE := true +ENABLE_THUMB := true +SUBARCH := arm-m +endif +ifeq ($(ARM_CPU),cortex-m7) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_M7=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7M=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 +HANDLED_CORE := true +ENABLE_THUMB := true +SUBARCH := arm-m +endif +ifeq ($(ARM_CPU),cortex-a7) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_VFP=1 \ + ARM_WITH_NEON=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),cortex-a15) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 \ + ARM_WITH_L2=1 +ifneq ($(ARM_WITHOUT_VFP_NEON),true) +GLOBAL_DEFINES += \ + ARM_WITH_VFP=1 \ + ARM_WITH_NEON=1 +endif +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),cortex-a8) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_VFP=1 \ + ARM_WITH_NEON=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 \ + ARM_WITH_L2=1 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),cortex-a9) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),cortex-a9-neon) +GLOBAL_DEFINES += \ + ARM_CPU_CORTEX_A9=1 \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_VFP=1 \ + ARM_WITH_NEON=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_THUMB2=1 \ + ARM_WITH_CACHE=1 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),arm1136j-s) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv6=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_CACHE=1 \ + ARM_CPU_ARM1136=1 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),arm1176jzf-s) +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_WITH_MMU=1 \ + ARM_ISA_ARMv6=1 \ + ARM_WITH_VFP=1 \ + ARM_WITH_THUMB=1 \ + ARM_WITH_CACHE=1 \ + ARM_CPU_ARM1136=1 +HANDLED_CORE := true +endif +ifeq ($(ARM_CPU),armemu) +# flavor of emulated cpu by the armemu project +GLOBAL_DEFINES += \ + ARM_WITH_CP15=1 \ + ARM_ISA_ARMv7=1 \ + ARM_ISA_ARMv7A=1 \ + ARM_WITH_CACHE=1 +HANDLED_CORE := true +ENABLE_THUMB := false # armemu doesn't currently support thumb properly +endif + +ifneq ($(HANDLED_CORE),true) +$(error $(LOCAL_DIR)/rules.mk doesnt have logic for arm core $(ARM_CPU)) +endif + +THUMBCFLAGS := +THUMBINTERWORK := +ifeq ($(ENABLE_THUMB),true) +THUMBCFLAGS := -mthumb -D__thumb__ +THUMBINTERWORK := -mthumb-interwork +endif + +GLOBAL_INCLUDES += \ + $(LOCAL_DIR)/$(SUBARCH)/include + +ifeq ($(SUBARCH),arm) +MODULE_SRCS += \ + $(LOCAL_DIR)/arm/start.S \ + $(LOCAL_DIR)/arm/asm.S \ + $(LOCAL_DIR)/arm/cache-ops.S \ + $(LOCAL_DIR)/arm/cache.c \ + $(LOCAL_DIR)/arm/debug.c \ + $(LOCAL_DIR)/arm/ops.S \ + $(LOCAL_DIR)/arm/exceptions.S \ + $(LOCAL_DIR)/arm/faults.c \ + $(LOCAL_DIR)/arm/fpu.c \ + $(LOCAL_DIR)/arm/mmu.c \ + $(LOCAL_DIR)/arm/thread.c \ + $(LOCAL_DIR)/arm/uspace_entry.S + +MODULE_ARM_OVERRIDE_SRCS := \ + $(LOCAL_DIR)/arm/arch.c + +GLOBAL_DEFINES += \ + ARCH_DEFAULT_STACK_SIZE=4096 + +ARCH_OPTFLAGS := -O2 +WITH_LINKER_GC ?= 1 + +# we have a mmu and want the vmm/pmm +WITH_KERNEL_VM ?= 1 + +# for arm, have the kernel occupy the entire top 3GB of virtual space, +# but put the kernel itself at 0x80000000. +# this leaves 0x40000000 - 0x80000000 open for kernel space to use. +GLOBAL_DEFINES += \ + KERNEL_ASPACE_BASE=0x40000000 \ + KERNEL_ASPACE_SIZE=0xc0000000 + +KERNEL_BASE ?= 0x80000000 +KERNEL_LOAD_OFFSET ?= 0 + +GLOBAL_DEFINES += \ + KERNEL_BASE=$(KERNEL_BASE) \ + KERNEL_LOAD_OFFSET=$(KERNEL_LOAD_OFFSET) + +# if its requested we build with SMP, arm generically supports 4 cpus +ifeq ($(WITH_SMP),1) +SMP_MAX_CPUS ?= 4 +SMP_CPU_CLUSTER_SHIFT ?= 8 +SMP_CPU_ID_BITS ?= 24 + +GLOBAL_DEFINES += \ + WITH_SMP=1 \ + SMP_MAX_CPUS=$(SMP_MAX_CPUS) \ + SMP_CPU_CLUSTER_SHIFT=$(SMP_CPU_CLUSTER_SHIFT) \ + SMP_CPU_ID_BITS=$(SMP_CPU_ID_BITS) + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm/mp.c +else +GLOBAL_DEFINES += \ + SMP_MAX_CPUS=1 +endif + +ifeq (true,$(call TOBOOL,$(WITH_NS_MAPPING))) +GLOBAL_DEFINES += \ + WITH_ARCH_MMU_PICK_SPOT=1 +endif + +endif +ifeq ($(SUBARCH),arm-m) +MODULE_SRCS += \ + $(LOCAL_DIR)/arm-m/arch.c \ + $(LOCAL_DIR)/arm-m/cache.c \ + $(LOCAL_DIR)/arm-m/exceptions.c \ + $(LOCAL_DIR)/arm-m/start.c \ + $(LOCAL_DIR)/arm-m/spin_cycles.c \ + $(LOCAL_DIR)/arm-m/thread.c \ + $(LOCAL_DIR)/arm-m/vectab.c + +# we're building for small binaries +GLOBAL_DEFINES += \ + ARM_ONLY_THUMB=1 \ + ARCH_DEFAULT_STACK_SIZE=1024 \ + SMP_MAX_CPUS=1 + +MODULE_DEPS += \ + arch/arm/arm-m/CMSIS + +ARCH_OPTFLAGS := -Os +WITH_LINKER_GC ?= 1 +endif + +# try to find toolchain +include $(LOCAL_DIR)/toolchain.mk +TOOLCHAIN_PREFIX := $(ARCH_$(ARCH)_TOOLCHAIN_PREFIX) +$(info TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX)) + +ARCH_COMPILEFLAGS += $(ARCH_$(ARCH)_COMPILEFLAGS) + +OBJDUMP_LIST_FLAGS := -Mreg-names-raw + +GLOBAL_COMPILEFLAGS += $(THUMBINTERWORK) + +# hard disable the fpu in kernel code +KERNEL_COMPILEFLAGS += -msoft-float -mfloat-abi=soft -DWITH_NO_FP=1 + +# set the max page size to something more reasonables (defaults to 64K or above) +GLOBAL_LDFLAGS += -z max-page-size=4096 + +# userspace support +USER_LINKER_SCRIPT := $(LOCAL_DIR)/user.ld + +# find the direct path to libgcc.a for our particular multilib variant +LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(THUMBCFLAGS) -print-libgcc-file-name) +$(info LIBGCC = $(LIBGCC)) + +$(info GLOBAL_COMPILEFLAGS = $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(THUMBCFLAGS)) + +# make sure some bits were set up +MEMVARS_SET := 0 +ifneq ($(MEMBASE),) +MEMVARS_SET := 1 +endif +ifneq ($(MEMSIZE),) +MEMVARS_SET := 1 +endif +ifeq ($(MEMVARS_SET),0) +$(error missing MEMBASE or MEMSIZE variable, please set in target rules.mk) +endif + +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) + +# potentially generated files that should be cleaned out with clean make rule +GENERATED += \ + $(BUILDDIR)/system-onesegment.ld \ + $(BUILDDIR)/system-twosegment.ld + +# rules for generating the linker scripts +$(BUILDDIR)/system-onesegment.ld: $(LOCAL_DIR)/system-onesegment.ld $(wildcard arch/*.ld) linkerscript.phony + @echo generating $@ + @$(MKDIR) + $(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/" < $< > $@.tmp + @$(call TESTANDREPLACEFILE,$@.tmp,$@) + +$(BUILDDIR)/system-twosegment.ld: $(LOCAL_DIR)/system-twosegment.ld $(wildcard arch/*.ld) linkerscript.phony + @echo generating $@ + @$(MKDIR) + $(NOECHO)sed "s/%ROMBASE%/$(ROMBASE)/;s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/" < $< > $@.tmp + @$(call TESTANDREPLACEFILE,$@.tmp,$@) + +linkerscript.phony: +.PHONY: linkerscript.phony + +# arm specific script to try to guess stack usage +$(OUTLKELF).stack: LOCAL_DIR:=$(LOCAL_DIR) +$(OUTLKELF).stack: $(OUTLKELF) + $(NOECHO)echo generating stack usage $@ + $(NOECHO)$(OBJDUMP) -Mreg-names-raw -d $< | $(LOCAL_DIR)/stackusage | $(CPPFILT) | sort -n -k 1 -r > $@ + +EXTRA_BUILDDEPS += $(OUTLKELF).stack +GENERATED += $(OUTLKELF).stack + +include make/module.mk diff --git a/kernel/arch/arm/stackusage b/kernel/arch/arm/stackusage new file mode 100755 index 000000000..51afdf3cf --- /dev/null +++ b/kernel/arch/arm/stackusage @@ -0,0 +1,92 @@ +#!/usr/bin/env python + +import sys +import re + +hexrule = re.compile("([0-9a-fA-F]+)") +hex2byterule = re.compile("([0-9a-fA-F]{4})") +hexcolonrule = re.compile("([0-9a-fA-F]+)\:") +symbolrule = re.compile("<([\._a-zA-Z]+[\._0-9a-zA-Z]*)>:") +insrule = re.compile("([a-zA-Z][\.a-zA-Z]*)") + +currsymbol = "" +curraddress = 0 +count = 0 + +for line in sys.stdin: + t = line.split() + + if len(t) == 0: + continue + + try: + + # match the address + match = hexcolonrule.match(t[0]) + if match: + #print "%s %s" % (match, match.group(1)) + curraddress = int(match.group(1), 16) + #print "curraddress 0x%x" % curraddress + + # see if this is a symbol declaration + match = symbolrule.match(t[1]) + if match: + # print the previous count + if count > 0: + print "%d %s" % (count, currsymbol) + count = 0 + + #print "%s %s" % (match, match.group(1)) + currsymbol = str(match.group(1)) + #print "current symbol is now '%s'" % currsymbol + continue + + # see if it's a one or two byte opcode + iindex = 2 + match = hex2byterule.match(t[1]) + if not match: + continue + match = hex2byterule.match(t[2]) + if match: + #print "match %s, %s" % (match, match.group(0)) + iindex = 3 + + #print "instruction starts at index %d: '%s'" % (iindex, t[iindex]) + + # match the instruction string + insmatch = insrule.match(t[iindex]) + if not insmatch: + continue + ins = insmatch.group(1) + #print "instruction '%s'" % ins + + # look for a few special instructions + if ins == "push": + c = (len(t) - 1 - iindex) * 4 + #print "%d bytes pushed" % c + count += c + + # look for a few special instructions + if ins == "stmdb": + c = (len(t) - 2 - iindex) * 4 + #print "%d bytes stmed" % c + count += c + + if ins == "sub": + reg = t[iindex+1] + if reg == "sp,": + conststr = t[iindex+2] + c = int(conststr[1:]) + #print "subtracting from sp, val %d" % c + count += c + + except IndexError: + continue + except Exception as e: + print "Exception %s" % e + continue + +# print the last count +if count > 0: + print "%d %s" % (count, currsymbol) + diff --git a/kernel/arch/arm/system-onesegment.ld b/kernel/arch/arm/system-onesegment.ld new file mode 100644 index 000000000..cdfa7c350 --- /dev/null +++ b/kernel/arch/arm/system-onesegment.ld @@ -0,0 +1,133 @@ +/* +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) +SECTIONS +{ + . = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%; + + _start = .; + + /* text/read-only data */ + /* set the load address to physical MEMBASE */ + .text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) { + __code_start = .; + KEEP(*(.text.boot.vectab1)) + KEEP(*(.text.boot.vectab2)) + KEEP(*(.text.boot)) + *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) + } + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + + .dummy_post_text : { + __code_end = .; + } + + .rodata : ALIGN(4096) { + __rodata_start = .; + __fault_handler_table_start = .; + KEEP(*(.rodata.fault_handler_table)) + __fault_handler_table_end = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* + * extra linker scripts tend to insert sections just after .rodata, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_rodata : { + __rodata_end = .; + } + + .data : ALIGN(4096) { + /* writable data */ + __data_start_rom = .; + /* in one segment binaries, the rom data address is on top of the ram data address */ + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.bootfs) + } + + .ctors : ALIGN(4) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(4) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* + * extra linker scripts tend to insert sections just after .data, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_data : { + __data_end = .; + } + + /* unintialized data (in same segment as writable data) */ + .bss : ALIGN(4096) { + KEEP(*(.bss.prebss.*)) + . = ALIGN(4); + __bss_start = .; + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } + + . = ALIGN(4096); + _end = .; + + . = %KERNEL_BASE% + %MEMSIZE%; + _end_of_ram = .; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/arm/system-twosegment.ld b/kernel/arch/arm/system-twosegment.ld new file mode 100644 index 000000000..a93269ec7 --- /dev/null +++ b/kernel/arch/arm/system-twosegment.ld @@ -0,0 +1,131 @@ +/* +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) +SECTIONS +{ + . = %ROMBASE%; + + /* text/read-only data */ + .text : { + KEEP(*(.text.boot.vectab1)) + KEEP(*(.text.boot.vectab2)) + KEEP(*(.text.boot)) + *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) + } + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + + .rodata : ALIGN(4) { + __rodata_start = .; + __fault_handler_table_start = .; + KEEP(*(.rodata.fault_handler_table)) + __fault_handler_table_end = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* fake section for .data to anchor off of + * needed because extra linker scripts tend to insert sections + * just after .rodata + */ + .dummy_post_rodata : { + /* end of rodata, start of data area */ + __rodata_end = . ; + __data_start_rom = .; + } + + /* in two segment binaries, the data starts at the bottom of ram (MEMBASE) + * bump us forward to the start of ram + */ + . = %MEMBASE%; + + /* start .data segment, force the physical address to be AT() __data_start_rom */ + .data : AT ( ADDR (.dummy_post_rodata) + SIZEOF (.dummy_post_rodata) ) ALIGN(4) { + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + } + + /* code that is located in ram */ + .sram.text : ALIGN(4) { + KEEP (*(.sram.text*)) + } + .ctors : ALIGN(4) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(4) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* + * extra linker scripts tend to insert sections just after .data, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_data : { + __data_end = .; + } + + /* unintialized data (in same segment as writable data) */ + .bss : ALIGN(4) { + KEEP(*(.bss.prebss.*)) + . = ALIGN(4); + __bss_start = .; + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } + + _end = .; + + . = %MEMBASE% + %MEMSIZE%; + _end_of_ram = .; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/arm/toolchain.mk b/kernel/arch/arm/toolchain.mk new file mode 100644 index 000000000..a853f5baa --- /dev/null +++ b/kernel/arch/arm/toolchain.mk @@ -0,0 +1,113 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +ifndef ARCH_arm_TOOLCHAIN_INCLUDED +ARCH_arm_TOOLCHAIN_INCLUDED := 1 + +# try to find the toolchain +ifndef ARCH_arm_TOOLCHAIN_PREFIX + +# if TOOLCHAIN_PREFIX is not empty, try to use it first +ifneq ($(TOOLCHAIN_PREFIX),) +ARCH_arm_TOOLCHAIN_PREFIX := $(TOOLCHAIN_PREFIX) +FOUNDTOOL=$(shell which $(ARCH_arm_TOOLCHAIN_PREFIX)gcc) +endif + +# try a series of common arm toolchain prefixes in the path +ifeq ($(FOUNDTOOL),) +ARCH_arm_TOOLCHAIN_PREFIX := arm-eabi- +FOUNDTOOL=$(shell which $(ARCH_arm_TOOLCHAIN_PREFIX)gcc) +endif +ifeq ($(FOUNDTOOL),) +ARCH_arm_TOOLCHAIN_PREFIX := arm-elf- +FOUNDTOOL=$(shell which $(ARCH_arm_TOOLCHAIN_PREFIX)gcc) +endif +ifeq ($(FOUNDTOOL),) +ARCH_arm_TOOLCHAIN_PREFIX := arm-none-eabi- +FOUNDTOOL=$(shell which $(ARCH_arm_TOOLCHAIN_PREFIX)gcc) +endif +ifeq ($(FOUNDTOOL),) +ARCH_arm_TOOLCHAIN_PREFIX := arm-linux-gnueabi- +FOUNDTOOL=$(shell which $(ARCH_arm_TOOLCHAIN_PREFIX)gcc) + +# Set no stack protection if we found our gnueabi toolchain. We don't +# need it. +# +# Stack protection is default in this toolchain and we get such errors +# final linking stage: +# +# undefined reference to `__stack_chk_guard' +# undefined reference to `__stack_chk_fail' +# undefined reference to `__stack_chk_guard' +# +ifneq (,$(findstring arm-linux-gnueabi-,$(FOUNDTOOL))) + ARCH_arm_COMPILEFLAGS += -fno-stack-protector +endif +endif # arm-linux-gnueabi- + +else +FOUNDTOOL=$(shell which $(ARCH_arm_TOOLCHAIN_PREFIX)gcc) +endif # ARCH_arm_TOOLCHAIN_PREFIX + +ifeq ($(FOUNDTOOL),) +$(error cannot find toolchain, please set ARCH_arm_TOOLCHAIN_PREFIX or add it to your path) +endif + +ifeq ($(ARM_CPU),cortex-m0) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +ARCH_arm_COMPILEFLAGS += -mthumb -mfloat-abi=soft +endif +ifeq ($(ARM_CPU),cortex-m0plus) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +ARCH_arm_COMPILEFLAGS += -mthumb -mfloat-abi=soft +endif +ifeq ($(ARM_CPU),cortex-m3) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +endif +ifeq ($(ARM_CPU),cortex-m4) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +endif +ifeq ($(ARM_CPU),cortex-m7) +ARCH_arm_COMPILEFLAGS += -mcpu=cortex-m4 +endif +ifeq ($(ARM_CPU),cortex-m4f) +ARCH_arm_COMPILEFLAGS += -mcpu=cortex-m4 -mfloat-abi=softfp +endif +ifeq ($(ARM_CPU),cortex-a7) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +ARCH_arm_COMPILEFLAGS += -mfpu=vfpv3 -mfloat-abi=softfp +endif +ifeq ($(ARM_CPU),cortex-a8) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +ARCH_arm_COMPILEFLAGS += -mfpu=neon -mfloat-abi=softfp +endif +ifeq ($(ARM_CPU),cortex-a9) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +endif +ifeq ($(ARM_CPU),cortex-a9-neon) +ARCH_arm_COMPILEFLAGS += -mcpu=cortex-a9 +# XXX cannot enable neon right now because compiler generates +# neon code for 64bit integer ops +ARCH_arm_COMPILEFLAGS += -mfpu=vfpv3 -mfloat-abi=softfp +endif +ifeq ($(ARM_CPU),cortex-a15) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +ifneq ($(ARM_WITHOUT_VFP_NEON),true) +ARCH_arm_COMPILEFLAGS += -mfpu=vfpv3 -mfloat-abi=softfp +endif +endif +ifeq ($(ARM_CPU),arm1136j-s) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +endif +ifeq ($(ARM_CPU),arm1176jzf-s) +ARCH_arm_COMPILEFLAGS += -mcpu=$(ARM_CPU) +endif +ifeq ($(ARM_CPU),armemu) +ARCH_arm_COMPILEFLAGS += -march=armv7-a +endif + +endif diff --git a/kernel/arch/arm/user.ld b/kernel/arch/arm/user.ld new file mode 100644 index 000000000..1c81b43c3 --- /dev/null +++ b/kernel/arch/arm/user.ld @@ -0,0 +1,114 @@ +/* +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) +SECTIONS +{ + . = 0x01000000; /* base of user space */ + + /* bump forward so the load offset and file offset are 1:1 */ + . += SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { + *(.crt) + *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) + } + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.dyn : { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + } + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + + .rodata : ALIGN(4) { + __rodata_start = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + __rodata_end = .; + } + + .data : ALIGN(4096) { + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + } + + .ctors : ALIGN(4) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(4) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + .got : { *(.got.plt) *(.got) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + + __data_end = .; + + /* unintialized data (in same segment as writable data) */ + .bss : ALIGN(4) { + __bss_start = .; + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; + } + + _end = .; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/arm64/BUILD.gn b/kernel/arch/arm64/BUILD.gn new file mode 100644 index 000000000..ff7a893fa --- /dev/null +++ b/kernel/arch/arm64/BUILD.gn @@ -0,0 +1,61 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "arm64") + +import("//gnbuild/config.gni") +import("//gnbuild/generate_ld_script.gni") + +module("arm64") { + configs += [ + "//kernel/kernel:enable_vm", + "//kernel/lib/magenta:enable_magenta", + ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + "//kernel/lib/magenta/include", + "//kernel/lib/user_copy/include", + "//system/ulib/magenta/include", + ] + + # These defines would be ideally defined as a config, but they're currently + # also shared by the ld script target and as such has to be defined as + # variable. + defines = kernel_defines + sources = [ + "arch.c", + "asm.S", + "cache-ops.S", + "exceptions.S", + "exceptions_c.c", + "fpu.c", + "spinlock.S", + "start.S", + "thread.c", + "user_copy.S", + "user_copy_c.c", + "uspace_entry.S", + ] + if (enable_vm) { + sources += [ "mmu.c" ] + } + deps = [ + ":onesegment_ld", + ] + if (enable_smp) { + include_dirs += [ "//kernel/dev/interrupt/include" ] + sources += [ "mp.c" ] + deps += [ "//kernel/dev/interrupt/arm_gic" ] + } +} + +generate_ld_script("onesegment_ld") { + input = "system-onesegment.ld" + output = "${root_gen_dir}/system-onesegment.ld" + defines = kernel_defines +} diff --git a/kernel/arch/arm64/arch.c b/kernel/arch/arm64/arch.c new file mode 100644 index 000000000..bf306f76d --- /dev/null +++ b/kernel/arch/arm64/arch.c @@ -0,0 +1,141 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#if WITH_SMP +/* smp boot lock */ +static spin_lock_t arm_boot_cpu_lock = 1; +static volatile int secondaries_to_init = 0; +uint arm_num_cpus = 1; +#endif + +static void arm64_cpu_early_init(void) +{ + /* set the vector base */ + ARM64_WRITE_SYSREG(VBAR_EL1, (uint64_t)&arm64_exception_base); + + /* switch to EL1 */ + unsigned int current_el = ARM64_READ_SYSREG(CURRENTEL) >> 2; + if (current_el > 1) { + arm64_el3_to_el1(); + } + + arch_enable_fiqs(); +} + +void arch_early_init(void) +{ + arm64_cpu_early_init(); + platform_init_mmu_mappings(); +} + +void arch_init(void) +{ +#if WITH_SMP + arch_mp_init_percpu(); + + LTRACEF("midr_el1 0x%llx\n", ARM64_READ_SYSREG(midr_el1)); + + secondaries_to_init = SMP_MAX_CPUS - 1; /* TODO: get count from somewhere else, or add cpus as they boot */ + + lk_init_secondary_cpus(secondaries_to_init); + + LTRACEF("releasing %d secondary cpus\n", secondaries_to_init); + + /* release the secondary cpus */ + spin_unlock(&arm_boot_cpu_lock); + + /* flush the release of the lock, since the secondary cpus are running without cache on */ + arch_clean_cache_range((addr_t)&arm_boot_cpu_lock, sizeof(arm_boot_cpu_lock)); +#endif +} + +void arch_quiesce(void) +{ +} + +void arch_idle(void) +{ + __asm__ volatile("wfi"); +} + +void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) +{ + PANIC_UNIMPLEMENTED; +} + +/* switch to user mode, set the user stack pointer to user_stack_top, put the svc stack pointer to the top of the kernel stack */ +void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top, void *thread_arg) +{ + DEBUG_ASSERT(IS_ALIGNED(user_stack_top, 16)); + + thread_t *ct = get_current_thread(); + + vaddr_t kernel_stack_top = (uintptr_t)ct->stack + ct->stack_size; + kernel_stack_top = ROUNDDOWN(kernel_stack_top, 16); + + /* set up a default spsr to get into 64bit user space: + * zeroed NZCV + * no SS, no IL, no D + * all interrupts enabled + * mode 0: EL0t + */ + uint32_t spsr = 0; + + arch_disable_ints(); + + arm64_uspace_entry( + kernel_stack_top, + user_stack_top, + entry_point, + spsr, + thread_arg); + __UNREACHABLE; +} + +#if WITH_SMP +void arm64_secondary_entry(ulong asm_cpu_num) +{ + uint cpu = arch_curr_cpu_num(); + if (cpu != asm_cpu_num) + return; + + arm64_cpu_early_init(); + + spin_lock(&arm_boot_cpu_lock); + spin_unlock(&arm_boot_cpu_lock); + + /* run early secondary cpu init routines up to the threading level */ + lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_THREADING - 1); + + arch_mp_init_percpu(); + + LTRACEF("cpu num %d\n", cpu); + + /* we're done, tell the main cpu we're up */ + atomic_add(&secondaries_to_init, -1); + atomic_add((int *)&arm_num_cpus, 1); + __asm__ volatile("sev"); + + lk_secondary_cpu_entry(); +} +#endif + diff --git a/kernel/arch/arm64/asm.S b/kernel/arch/arm64/asm.S new file mode 100644 index 000000000..1dc6ddc3d --- /dev/null +++ b/kernel/arch/arm64/asm.S @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +/* void arm64_context_switch(vaddr_t *old_sp, vaddr_t new_sp); */ +FUNCTION(arm64_context_switch) + /* save old frame */ + push x28, x29 + push x26, x27 + push x24, x25 + push x22, x23 + push x20, x21 + push x18, x19 + mrs x18, tpidr_el0 + mrs x19, tpidrro_el0 + push x18, x19 + str x30, [sp,#-8]! + + /* save old sp */ + mov x15, sp + str x15, [x0] + + /* load new sp */ + mov sp, x1 + + /* restore new frame */ + ldr x30, [sp], #8 + pop x18, x19 + msr tpidr_el0, x18 + msr tpidrro_el0, x19 + pop x18, x19 + pop x20, x21 + pop x22, x23 + pop x24, x25 + pop x26, x27 + pop x28, x29 + + ret + +FUNCTION(arm64_el3_to_el1) + /* set EL2 to 64bit */ + mrs x0, scr_el3 + orr x0, x0, #(1<<10) + msr scr_el3, x0 + + /* set EL1 to 64bit */ + mov x0, #(1<<31) + msr hcr_el2, x0 + + /* disable EL2 coprocessor traps */ + mov x0, #0x33ff + msr cptr_el2, x0 + + /* disable EL1 FPU traps */ + mov x0, #(0b11<<20) + msr cpacr_el1, x0 + + /* set up the EL1 bounce interrupt */ + mov x0, sp + msr sp_el1, x0 + + adr x0, .Ltarget + msr elr_el3, x0 + + mov x0, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ + msr spsr_el3, x0 + isb + + eret + +.Ltarget: + ret diff --git a/kernel/arch/arm64/cache-ops.S b/kernel/arch/arm64/cache-ops.S new file mode 100644 index 000000000..856cd9e4f --- /dev/null +++ b/kernel/arch/arm64/cache-ops.S @@ -0,0 +1,45 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014, Google Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include + +.text + +.macro cache_range_op, cache op + add x2, x0, x1 // calculate the end address + bic x3, x0, #(CACHE_LINE-1) // align the start with a cache line +.Lcache_range_op_loop\@: + \cache \op, x3 + add x3, x3, #CACHE_LINE + cmp x3, x2 + blo .Lcache_range_op_loop\@ + dsb sy +.endm + + /* void arch_flush_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_clean_cache_range) + cache_range_op dc cvac // clean cache to PoC by MVA + ret + + /* void arch_flush_invalidate_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_clean_invalidate_cache_range) + cache_range_op dc civac // clean & invalidate dcache to PoC by MVA + ret + + /* void arch_invalidate_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_invalidate_cache_range) + cache_range_op dc ivac // invalidate dcache to PoC by MVA + ret + + /* void arch_sync_cache_range(addr_t start, size_t len); */ +FUNCTION(arch_sync_cache_range) + cache_range_op dc cvau // clean dcache to PoU by MVA + cache_range_op ic ivau // invalidate icache to PoU by MVA + ret diff --git a/kernel/arch/arm64/exceptions.S b/kernel/arch/arm64/exceptions.S new file mode 100644 index 000000000..cdcda2060 --- /dev/null +++ b/kernel/arch/arm64/exceptions.S @@ -0,0 +1,213 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +.section .text.boot.vectab +.align 12 + +#define lr x30 +#define regsave_long_offset 0xf0 +#define regsave_short_offset 0x90 + +.macro regsave_long +sub sp, sp, #32 +push x28, x29 +push x26, x27 +push x24, x25 +push x22, x23 +push x20, x21 +push x18, x19 +push x16, x17 +push x14, x15 +push x12, x13 +push x10, x11 +push x8, x9 +push x6, x7 +push x4, x5 +push x2, x3 +push x0, x1 +mrs x0, sp_el0 +mrs x1, elr_el1 +mrs x2, spsr_el1 +stp lr, x0, [sp, #regsave_long_offset] +stp x1, x2, [sp, #regsave_long_offset + 16] +.endm + +.macro regsave_short +sub sp, sp, #32 +push x16, x17 +push x14, x15 +push x12, x13 +push x10, x11 +push x8, x9 +push x6, x7 +push x4, x5 +push x2, x3 +push x0, x1 +mrs x0, sp_el0 +mrs x1, elr_el1 +mrs x2, spsr_el1 +stp lr, x0, [sp, #regsave_short_offset] +stp x1, x2, [sp, #regsave_short_offset + 16] +.endm + +.macro regrestore_long +ldp lr, x0, [sp, #regsave_long_offset] +ldp x1, x2, [sp, #regsave_long_offset + 16] +msr sp_el0, x0 +msr elr_el1, x1 +msr spsr_el1, x2 +pop x0, x1 +pop x2, x3 +pop x4, x5 +pop x6, x7 +pop x8, x9 +pop x10, x11 +pop x12, x13 +pop x14, x15 +pop x16, x17 +pop x18, x19 +pop x20, x21 +pop x22, x23 +pop x24, x25 +pop x26, x27 +pop x28, x29 +add sp, sp, #32 +.endm + +.macro regrestore_short +ldp lr, x0, [sp, #regsave_short_offset] +ldp x1, x2, [sp, #regsave_short_offset + 16] +msr sp_el0, x0 +msr elr_el1, x1 +msr spsr_el1, x2 +pop x0, x1 +pop x2, x3 +pop x4, x5 +pop x6, x7 +pop x8, x9 +pop x10, x11 +pop x12, x13 +pop x14, x15 +pop x16, x17 +add sp, sp, #32 +.endm + +.macro invalid_exception, which + regsave_long + mov x1, #\which + mov x0, sp + bl arm64_invalid_exception + b . +.endm + +.macro irq_exception, exception_flags + regsave_short + msr daifclr, #1 /* reenable fiqs once elr and spsr have been saved */ + mov x0, sp + mov x1, \exception_flags + bl arm64_irq + msr daifset, #1 /* disable fiqs to protect elr and spsr restore */ + b arm64_exc_shared_restore_short +.endm + +.macro sync_exception, exception_flags + regsave_long + mov x0, sp + mov x1, \exception_flags + bl arm64_sync_exception + b arm64_exc_shared_restore_long +.endm + +FUNCTION(arm64_exception_base) + +/* exceptions from current EL, using SP0 */ +LOCAL_FUNCTION(arm64_sync_exc_current_el_SP0) + invalid_exception 0 + +.org 0x080 +LOCAL_FUNCTION(arm64_irq_current_el_SP0) + invalid_exception 1 + +.org 0x100 +LOCAL_FUNCTION(arm64_fiq_current_el_SP0) + invalid_exception 2 + +.org 0x180 +LOCAL_FUNCTION(arm64_err_exc_current_el_SP0) + invalid_exception 3 + +/* exceptions from current EL, using SPx */ +.org 0x200 +LOCAL_FUNCTION(arm64_sync_exc_current_el_SPx) + sync_exception #0 /* same EL, arm64 */ + +.org 0x280 +LOCAL_FUNCTION(arm64_irq_current_el_SPx) + irq_exception #0 /* same EL, arm64 */ + +.org 0x300 +LOCAL_FUNCTION(arm64_fiq_current_el_SPx) + regsave_short + mov x0, sp + bl platform_fiq + b arm64_exc_shared_restore_short + +.org 0x380 +LOCAL_FUNCTION(arm64_err_exc_current_el_SPx) + invalid_exception 0x13 + +/* exceptions from lower EL, running arm64 */ +.org 0x400 +LOCAL_FUNCTION(arm64_sync_exc_lower_el_64) + sync_exception #(ARM64_EXCEPTION_FLAG_LOWER_EL) + +.org 0x480 +LOCAL_FUNCTION(arm64_irq_lower_el_64) + irq_exception #(ARM64_EXCEPTION_FLAG_LOWER_EL) + +.org 0x500 +LOCAL_FUNCTION(arm64_fiq_lower_el_64) + regsave_short + mov x0, sp + bl platform_fiq + b arm64_exc_shared_restore_short + +.org 0x580 +LOCAL_FUNCTION(arm64_err_exc_lower_el_64) + invalid_exception 0x23 + +/* exceptions from lower EL, running arm32 */ +.org 0x600 +LOCAL_FUNCTION(arm64_sync_exc_lower_el_32) + sync_exception #(ARM64_EXCEPTION_FLAG_LOWER_EL|ARM64_EXCEPTION_FLAG_ARM32) + +.org 0x680 +LOCAL_FUNCTION(arm64_irq_lower_el_32) + irq_exception #(ARM64_EXCEPTION_FLAG_LOWER_EL|ARM64_EXCEPTION_FLAG_ARM32) + +.org 0x700 +LOCAL_FUNCTION(arm64_fiq_lower_el_32) + regsave_short + mov x0, sp + bl platform_fiq + b arm64_exc_shared_restore_short + +.org 0x780 +LOCAL_FUNCTION(arm64_err_exc_lower_el_32) + invalid_exception 0x33 + +LOCAL_FUNCTION(arm64_exc_shared_restore_long) + regrestore_long + eret + +LOCAL_FUNCTION(arm64_exc_shared_restore_short) + regrestore_short + eret diff --git a/kernel/arch/arm64/exceptions_c.c b/kernel/arch/arm64/exceptions_c.c new file mode 100644 index 000000000..c6ecc5d86 --- /dev/null +++ b/kernel/arch/arm64/exceptions_c.c @@ -0,0 +1,261 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#if WITH_LIB_MAGENTA +#include +#include + +struct arch_exception_context { + struct arm64_iframe_long *frame; + uint64_t far; + uint32_t esr; +}; +#endif + +#define LOCAL_TRACE 0 + +struct fault_handler_table_entry { + uint64_t pc; + uint64_t fault_handler; +}; + +extern struct fault_handler_table_entry __fault_handler_table_start[]; +extern struct fault_handler_table_entry __fault_handler_table_end[]; + +extern enum handler_return platform_irq(struct arm64_iframe_long *frame); + +static void dump_iframe(const struct arm64_iframe_long *iframe) +{ + printf("iframe %p:\n", iframe); + printf("x0 0x%16llx x1 0x%16llx x2 0x%16llx x3 0x%16llx\n", iframe->r[0], iframe->r[1], iframe->r[2], iframe->r[3]); + printf("x4 0x%16llx x5 0x%16llx x6 0x%16llx x7 0x%16llx\n", iframe->r[4], iframe->r[5], iframe->r[6], iframe->r[7]); + printf("x8 0x%16llx x9 0x%16llx x10 0x%16llx x11 0x%16llx\n", iframe->r[8], iframe->r[9], iframe->r[10], iframe->r[11]); + printf("x12 0x%16llx x13 0x%16llx x14 0x%16llx x15 0x%16llx\n", iframe->r[12], iframe->r[13], iframe->r[14], iframe->r[15]); + printf("x16 0x%16llx x17 0x%16llx x18 0x%16llx x19 0x%16llx\n", iframe->r[16], iframe->r[17], iframe->r[18], iframe->r[19]); + printf("x20 0x%16llx x21 0x%16llx x22 0x%16llx x23 0x%16llx\n", iframe->r[20], iframe->r[21], iframe->r[22], iframe->r[23]); + printf("x24 0x%16llx x25 0x%16llx x26 0x%16llx x27 0x%16llx\n", iframe->r[24], iframe->r[25], iframe->r[26], iframe->r[27]); + printf("x28 0x%16llx x29 0x%16llx lr 0x%16llx usp 0x%16llx\n", iframe->r[28], iframe->r[29], iframe->lr, iframe->usp); + printf("elr 0x%16llx\n", iframe->elr); + printf("spsr 0x%16llx\n", iframe->spsr); +} + +__WEAK void arm64_syscall(struct arm64_iframe_long *iframe, bool is_64bit, uint32_t syscall_imm, uint64_t pc) +{ + panic("unhandled syscall vector\n"); +} + +void arm64_sync_exception(struct arm64_iframe_long *iframe, uint exception_flags) +{ + struct fault_handler_table_entry *fault_handler; + uint32_t esr = ARM64_READ_SYSREG(esr_el1); + uint32_t ec = BITS_SHIFT(esr, 31, 26); + uint32_t il = BIT(esr, 25); + uint32_t iss = BITS(esr, 24, 0); + + switch (ec) { + case 0b000000: /* unknown reason */ + /* this is for a lot of reasons, but most of them are undefined instructions */ + case 0b111000: /* BRK from arm32 */ + case 0b111100: { /* BRK from arm64 */ +#if WITH_LIB_MAGENTA + /* let magenta get a shot at it */ + arch_exception_context_t context = { .frame = iframe, .esr = esr }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_UNDEFINED_INSTRUCTION, &context, iframe->elr); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + return; + } + case 0b000111: /* floating point */ + if (unlikely((exception_flags & ARM64_EXCEPTION_FLAG_LOWER_EL) == 0)) { + /* we trapped a floating point instruction inside our own EL, this is bad */ + printf("invalid fpu use in kernel: PC at 0x%llx\n", iframe->elr); + break; + } + arm64_fpu_exception(iframe, exception_flags); + return; + case 0b010001: /* syscall from arm32 */ + case 0b010101: /* syscall from arm64 */ +#ifdef WITH_LIB_SYSCALL + void arm64_syscall(struct arm64_iframe_long *iframe); + arch_enable_fiqs(); + arm64_syscall(iframe); + arch_disable_fiqs(); + return; +#else + arm64_syscall(iframe, (ec == 0x15) ? true : false, iss & 0xffff, iframe->elr); + return; +#endif + case 0b100000: /* instruction abort from lower level */ + case 0b100001: { /* instruction abort from same level */ + /* read the FAR register */ + uint64_t far = ARM64_READ_SYSREG(far_el1); + + uint pf_flags = VMM_PF_FLAG_INSTRUCTION; + pf_flags |= BIT(ec, 0) ? 0 : VMM_PF_FLAG_USER; + + LTRACEF("instruction abort: PC at 0x%llx, FAR 0x%llx, esr 0x%x, iss 0x%x\n", + iframe->elr, far, esr, iss); + + arch_enable_ints(); + status_t err = vmm_page_fault_handler(far, pf_flags); + arch_disable_ints(); + if (err >= 0) + return; + +#if WITH_LIB_MAGENTA + /* let magenta get a shot at it */ + arch_exception_context_t context = { .frame = iframe, .esr = esr, .far = far }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_FATAL_PAGE_FAULT, &context, iframe->elr); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + + printf("instruction abort: PC at 0x%llx\n", iframe->elr); + break; + } + case 0b100100: /* data abort from lower level */ + case 0b100101: { /* data abort from same level */ + /* read the FAR register */ + uint64_t far = ARM64_READ_SYSREG(far_el1); + + uint pf_flags = 0; + pf_flags |= BIT(iss, 6) ? VMM_PF_FLAG_WRITE : 0; + pf_flags |= BIT(ec, 0) ? 0 : VMM_PF_FLAG_USER; + + LTRACEF("data fault: PC at 0x%llx, FAR 0x%llx, esr 0x%x, iss 0x%x\n", + iframe->elr, far, esr, iss); + + arch_enable_ints(); + status_t err = vmm_page_fault_handler(far, pf_flags); + arch_disable_ints(); + if (err >= 0) + return; + + // Check if the current thread was expecting a data fault and + // we should return to its handler. + thread_t *thr = get_current_thread(); + if (thr->arch.data_fault_resume != NULL) { + iframe->elr = (uintptr_t)thr->arch.data_fault_resume; + return; + } + + for (fault_handler = __fault_handler_table_start; + fault_handler < __fault_handler_table_end; + fault_handler++) { + if (fault_handler->pc == iframe->elr) { + iframe->elr = fault_handler->fault_handler; + return; + } + } + +#if WITH_LIB_MAGENTA + /* let magenta get a shot at it */ + arch_exception_context_t context = { .frame = iframe, .esr = esr, .far = far }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_FATAL_PAGE_FAULT, &context, iframe->elr); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + + /* decode the iss */ + if (BIT(iss, 24)) { /* ISV bit */ + printf("data fault: PC at 0x%llx, FAR 0x%llx, iss 0x%x (DFSC 0x%lx)\n", + iframe->elr, far, iss, BITS(iss, 5, 0)); + } else { + printf("data fault: PC at 0x%llx, FAR 0x%llx, iss 0x%x\n", iframe->elr, far, iss); + } + + break; + } + default: { +#if WITH_LIB_MAGENTA + /* let magenta get a shot at it */ + arch_exception_context_t context = { .frame = iframe, .esr = esr }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_GENERAL, &context, iframe->elr); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + printf("unhandled synchronous exception\n"); + } + } + + /* fatal exception, die here */ + printf("ESR 0x%x: ec 0x%x, il 0x%x, iss 0x%x\n", esr, ec, il, iss); + dump_iframe(iframe); + + panic("die\n"); +} + +void arm64_irq(struct arm64_iframe_long *iframe, uint exception_flags) +{ + LTRACEF("iframe %p, flags 0x%x\n", iframe, exception_flags); + + enum handler_return ret = platform_irq(iframe); + if (ret != INT_NO_RESCHEDULE) + thread_preempt(); +} + +void arm64_invalid_exception(struct arm64_iframe_long *iframe, unsigned int which) +{ + printf("invalid exception, which 0x%x\n", which); + dump_iframe(iframe); + + panic("die\n"); +} + +#if WITH_LIB_MAGENTA +void arch_dump_exception_context(arch_exception_context_t *context) +{ + uint32_t ec = BITS_SHIFT(context->esr, 31, 26); + uint32_t iss = BITS(context->esr, 24, 0); + + switch (ec) { + case 0b100000: /* instruction abort from lower level */ + case 0b100001: /* instruction abort from same level */ + printf("instruction abort: PC at 0x%llx, address 0x%llx IFSC 0x%lx %s\n", + context->frame->elr, context->far, + BITS(context->esr, 5, 0), + BIT(ec, 0) ? "" : "user "); + + break; + case 0b100100: /* data abort from lower level */ + case 0b100101: /* data abort from same level */ + printf("data abort: PC at 0x%llx, address 0x%llx %s%s\n", + context->frame->elr, context->far, + BIT(ec, 0) ? "" : "user ", + BIT(iss, 6) ? "write" : "read"); + } + + dump_iframe(context->frame); + + // try to dump the user stack + if (is_user_address(context->frame->usp)) { + uint8_t buf[256]; + if (copy_from_user(buf, (void *)context->frame->usp, sizeof(buf)) == NO_ERROR) { + printf("bottom of user stack at 0x%lx:\n", (vaddr_t)context->frame->usp); + hexdump_ex(buf, sizeof(buf), context->frame->usp); + } + } +} +#endif + diff --git a/kernel/arch/arm64/fpu.c b/kernel/arch/arm64/fpu.c new file mode 100644 index 000000000..501573d89 --- /dev/null +++ b/kernel/arch/arm64/fpu.c @@ -0,0 +1,122 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Google Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +/* FPEN bits in the cpacr register + * 0 means all fpu instructions fault + * 3 means no faulting at all EL levels + * other values are not useful to us + */ +#define FPU_ENABLE_MASK (3<<20) + +static inline bool is_fpu_enabled(uint32_t cpacr) +{ + return !!(BITS(cpacr, 21, 20) != 0); +} + +static void arm64_fpu_load_state(struct thread *t) +{ + struct fpstate *fpstate = &t->arch.fpstate; + + LTRACEF("cpu %d, thread %s, load fpstate %p\n", arch_curr_cpu_num(), t->name, fpstate); + + STATIC_ASSERT(sizeof(fpstate->regs) == 16 * 32); + __asm__ volatile("ldp q0, q1, [%0, #(0 * 32)]\n" + "ldp q2, q3, [%0, #(1 * 32)]\n" + "ldp q4, q5, [%0, #(2 * 32)]\n" + "ldp q6, q7, [%0, #(3 * 32)]\n" + "ldp q8, q9, [%0, #(4 * 32)]\n" + "ldp q10, q11, [%0, #(5 * 32)]\n" + "ldp q12, q13, [%0, #(6 * 32)]\n" + "ldp q14, q15, [%0, #(7 * 32)]\n" + "ldp q16, q17, [%0, #(8 * 32)]\n" + "ldp q18, q19, [%0, #(9 * 32)]\n" + "ldp q20, q21, [%0, #(10 * 32)]\n" + "ldp q22, q23, [%0, #(11 * 32)]\n" + "ldp q24, q25, [%0, #(12 * 32)]\n" + "ldp q26, q27, [%0, #(13 * 32)]\n" + "ldp q28, q29, [%0, #(14 * 32)]\n" + "ldp q30, q31, [%0, #(15 * 32)]\n" + "msr fpcr, %1\n" + "msr fpsr, %2\n" + :: "r"(fpstate->regs), "r"(fpstate->fpcr), "r"(fpstate->fpsr)); +} + +static void arm64_fpu_save_state(struct thread *t) +{ + struct fpstate *fpstate = &t->arch.fpstate; + + LTRACEF("cpu %d, thread %s, save fpstate %p\n", arch_curr_cpu_num(), t->name, fpstate); + + __asm__ volatile("stp q0, q1, [%2, #(0 * 32)]\n" + "stp q2, q3, [%2, #(1 * 32)]\n" + "stp q4, q5, [%2, #(2 * 32)]\n" + "stp q6, q7, [%2, #(3 * 32)]\n" + "stp q8, q9, [%2, #(4 * 32)]\n" + "stp q10, q11, [%2, #(5 * 32)]\n" + "stp q12, q13, [%2, #(6 * 32)]\n" + "stp q14, q15, [%2, #(7 * 32)]\n" + "stp q16, q17, [%2, #(8 * 32)]\n" + "stp q18, q19, [%2, #(9 * 32)]\n" + "stp q20, q21, [%2, #(10 * 32)]\n" + "stp q22, q23, [%2, #(11 * 32)]\n" + "stp q24, q25, [%2, #(12 * 32)]\n" + "stp q26, q27, [%2, #(13 * 32)]\n" + "stp q28, q29, [%2, #(14 * 32)]\n" + "stp q30, q31, [%2, #(15 * 32)]\n" + "mrs %0, fpcr\n" + "mrs %1, fpsr\n" + : "=r"(fpstate->fpcr), "=r"(fpstate->fpsr) + : "r"(fpstate->regs)); + + LTRACEF("thread %s, fpcr %x, fpsr %x\n", t->name, fpstate->fpcr, fpstate->fpsr); +} + +/* save fpu state if the thread had dirtied it and disable the fpu */ +void arm64_fpu_context_switch(struct thread *oldthread, struct thread *newthread) +{ + uint32_t cpacr = ARM64_READ_SYSREG(cpacr_el1); + if (is_fpu_enabled(cpacr)) { + LTRACEF("saving state on thread %s\n", oldthread->name); + + /* save the state */ + arm64_fpu_save_state(oldthread); + + /* disable the fpu again */ + ARM64_WRITE_SYSREG(cpacr_el1, cpacr & ~FPU_ENABLE_MASK); + } +} + +/* called because of a fpu instruction used exception */ +void arm64_fpu_exception(struct arm64_iframe_long *iframe, uint exception_flags) +{ + LTRACEF("cpu %d, thread %s, flags 0x%x\n", arch_curr_cpu_num(), get_current_thread()->name, exception_flags); + + /* only valid to be called if exception came from lower level */ + DEBUG_ASSERT(exception_flags & ARM64_EXCEPTION_FLAG_LOWER_EL); + + uint32_t cpacr = ARM64_READ_SYSREG(cpacr_el1); + DEBUG_ASSERT(!is_fpu_enabled(cpacr)); + + /* enable the fpu */ + cpacr |= FPU_ENABLE_MASK; + ARM64_WRITE_SYSREG(cpacr_el1, cpacr); + + /* load the state from the current cpu */ + thread_t *t = get_current_thread(); + if (likely(t)) + arm64_fpu_load_state(t); +} + diff --git a/kernel/arch/arm64/include/arch/arch_ops.h b/kernel/arch/arm64/include/arch/arch_ops.h new file mode 100644 index 000000000..d87fa4246 --- /dev/null +++ b/kernel/arch/arm64/include/arch/arch_ops.h @@ -0,0 +1,148 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#ifndef ASSEMBLY + +#include +#include +#include +#include + +__BEGIN_CDECLS + +#define ENABLE_CYCLE_COUNTER 1 + +// override of some routines +static inline void arch_enable_ints(void) +{ + CF; + __asm__ volatile("msr daifclr, #2" ::: "memory"); +} + +static inline void arch_disable_ints(void) +{ + __asm__ volatile("msr daifset, #2" ::: "memory"); + CF; +} + +static inline bool arch_ints_disabled(void) +{ + unsigned int state; + + __asm__ volatile("mrs %0, daif" : "=r"(state)); + state &= (1<<7); + + return !!state; +} + +static inline void arch_enable_fiqs(void) +{ + CF; + __asm__ volatile("msr daifclr, #1" ::: "memory"); +} + +static inline void arch_disable_fiqs(void) +{ + __asm__ volatile("msr daifset, #1" ::: "memory"); + CF; +} + +// XXX +static inline bool arch_fiqs_disabled(void) +{ + unsigned int state; + + __asm__ volatile("mrs %0, daif" : "=r"(state)); + state &= (1<<6); + + return !!state; +} + +static inline void arch_spinloop_pause(void) +{ + __asm__ volatile("wfe"); +} + +static inline void arch_spinloop_signal(void) +{ + __asm__ volatile("sev"); +} + +#define mb() __asm__ volatile("dsb sy" : : : "memory") +#define rmb() __asm__ volatile("dsb ld" : : : "memory") +#define wmb() __asm__ volatile("dsb st" : : : "memory") + +#ifdef WITH_SMP +#define smp_mb() __asm__ volatile("dmb ish" : : : "memory") +#define smp_rmb() __asm__ volatile("dmb ishld" : : : "memory") +#define smp_wmb() __asm__ volatile("dmb ishst" : : : "memory") +#else +#define smp_mb() CF +#define smp_wmb() CF +#define smp_rmb() CF +#endif + +static inline uint32_t arch_cycle_count(void) +{ +#if ARM_ISA_ARM7M +#if ENABLE_CYCLE_COUNTER +#define DWT_CYCCNT (0xE0001004) + return *REG32(DWT_CYCCNT); +#else + return 0; +#endif +#elif ARM_ISA_ARMV7 + uint32_t count; + __asm__ volatile("mrc p15, 0, %0, c9, c13, 0" + : "=r" (count) + ); + return count; +#else +//#warning no arch_cycle_count implementation + return 0; +#endif +} + +/* use the cpu local thread context pointer to store current_thread */ +static inline struct thread *get_current_thread(void) +{ + return (struct thread *)ARM64_READ_SYSREG(tpidr_el1); +} + +static inline void set_current_thread(struct thread *t) +{ + ARM64_WRITE_SYSREG(tpidr_el1, (uint64_t)t); +} + +#if WITH_SMP +static inline uint arch_curr_cpu_num(void) +{ + uint64_t mpidr = ARM64_READ_SYSREG(mpidr_el1); + return ((mpidr & ((1U << SMP_CPU_ID_BITS) - 1)) >> 8 << SMP_CPU_CLUSTER_SHIFT) | (mpidr & 0xff); +} +extern uint arm_num_cpus; +static inline uint arch_max_num_cpus(void) +{ + return arm_num_cpus; +} +#else +static inline uint arch_curr_cpu_num(void) +{ + return 0; +} +static inline uint arch_max_num_cpus(void) +{ + return 1; +} +#endif + +__END_CDECLS + +#endif // ASSEMBLY + diff --git a/kernel/arch/arm64/include/arch/arch_thread.h b/kernel/arch/arm64/include/arch/arch_thread.h new file mode 100644 index 000000000..e59271cf2 --- /dev/null +++ b/kernel/arch/arm64/include/arch/arch_thread.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +struct fpstate { + uint32_t fpcr; + uint32_t fpsr; + uint64_t regs[64]; +}; + +struct arch_thread { + vaddr_t sp; + + /* if non-NULL, address to return to on data fault */ + void *data_fault_resume; + + /* saved fpu state */ + struct fpstate fpstate; +}; + +__END_CDECLS diff --git a/kernel/arch/arm64/include/arch/arm64.h b/kernel/arch/arm64/include/arch/arm64.h new file mode 100644 index 000000000..9b713b260 --- /dev/null +++ b/kernel/arch/arm64/include/arch/arm64.h @@ -0,0 +1,80 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#ifndef ASSEMBLY + +#include +#include +#include + +__BEGIN_CDECLS + +#define DSB __asm__ volatile("dsb sy" ::: "memory") +#define ISB __asm__ volatile("isb" ::: "memory") + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#define ARM64_READ_SYSREG(reg) \ +({ \ + uint64_t _val; \ + __asm__ volatile("mrs %0," TOSTRING(reg) : "=r" (_val)); \ + _val; \ +}) + +#define ARM64_WRITE_SYSREG(reg, val) \ +({ \ + __asm__ volatile("msr " TOSTRING(reg) ", %0" :: "r" (val)); \ + ISB; \ +}) + +void arm64_context_switch(vaddr_t *old_sp, vaddr_t new_sp); +void arm64_uspace_entry( + vaddr_t kstack, + vaddr_t ustack, + vaddr_t entry_point, + uint32_t spsr, + void *thread_arg) __NO_RETURN; + +/* exception handling */ +struct arm64_iframe_long { + uint64_t r[30]; + uint64_t lr; + uint64_t usp; + uint64_t elr; + uint64_t spsr; +}; + +struct arm64_iframe_short { + uint64_t r[18]; + uint64_t lr; + uint64_t usp; + uint64_t elr; + uint64_t spsr; +}; + +struct thread; +extern void arm64_exception_base(void); +void arm64_el3_to_el1(void); +void arm64_sync_exception(struct arm64_iframe_long *iframe, uint exception_flags); + +/* fpu routines */ +void arm64_fpu_exception(struct arm64_iframe_long *iframe, uint exception_flags); +void arm64_fpu_context_switch(struct thread *oldthread, struct thread *newthread); + +/* overridable syscall handler */ +void arm64_syscall(struct arm64_iframe_long *iframe, bool is_64bit, uint32_t syscall_imm, uint64_t pc); + +__END_CDECLS + +#endif // __ASSEMBLY__ + +/* used in above exception_flags arguments */ +#define ARM64_EXCEPTION_FLAG_LOWER_EL (1<<0) +#define ARM64_EXCEPTION_FLAG_ARM32 (1<<1) diff --git a/kernel/arch/arm64/include/arch/arm64/mmu.h b/kernel/arch/arm64/include/arch/arm64/mmu.h new file mode 100644 index 000000000..81a007137 --- /dev/null +++ b/kernel/arch/arm64/include/arch/arm64/mmu.h @@ -0,0 +1,337 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Google Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include + +#define IFTE(c,t,e) (!!(c) * (t) | !(c) * (e)) +#define NBITS01(n) IFTE(n, 1, 0) +#define NBITS02(n) IFTE((n) >> 1, 1 + NBITS01((n) >> 1), NBITS01(n)) +#define NBITS04(n) IFTE((n) >> 2, 2 + NBITS02((n) >> 2), NBITS02(n)) +#define NBITS08(n) IFTE((n) >> 4, 4 + NBITS04((n) >> 4), NBITS04(n)) +#define NBITS16(n) IFTE((n) >> 8, 8 + NBITS08((n) >> 8), NBITS08(n)) +#define NBITS32(n) IFTE((n) >> 16, 16 + NBITS16((n) >> 16), NBITS16(n)) +#define NBITS(n) IFTE((n) >> 32, 32 + NBITS32((n) >> 32), NBITS32(n)) + +#ifndef MMU_KERNEL_SIZE_SHIFT +#define KERNEL_ASPACE_BITS (NBITS(0xffffffffffffffff-KERNEL_ASPACE_BASE)) +#define KERNEL_BASE_BITS (NBITS(0xffffffffffffffff-KERNEL_BASE)) +#if KERNEL_BASE_BITS > KERNEL_ASPACE_BITS +#define KERNEL_ASPACE_BITS KERNEL_BASE_BITS /* KERNEL_BASE should not be below KERNEL_ASPACE_BASE */ +#endif + +#if KERNEL_ASPACE_BITS < 25 +#define MMU_KERNEL_SIZE_SHIFT (25) +#else +#define MMU_KERNEL_SIZE_SHIFT (KERNEL_ASPACE_BITS) +#endif +#endif + +#ifndef MMU_USER_SIZE_SHIFT +#define MMU_USER_SIZE_SHIFT 48 +#endif + +#ifndef MMU_IDENT_SIZE_SHIFT +#define MMU_IDENT_SIZE_SHIFT 42 /* Max size supported by block mappings */ +#endif + +#define MMU_KERNEL_PAGE_SIZE_SHIFT (PAGE_SIZE_SHIFT) +#define MMU_USER_PAGE_SIZE_SHIFT (USER_PAGE_SIZE_SHIFT) + +#if MMU_IDENT_SIZE_SHIFT < 25 +#error MMU_IDENT_SIZE_SHIFT too small +#elif MMU_IDENT_SIZE_SHIFT <= 29 /* Use 2MB block mappings (4K page size) */ +#define MMU_IDENT_PAGE_SIZE_SHIFT (SHIFT_4K) +#elif MMU_IDENT_SIZE_SHIFT <= 30 /* Use 512MB block mappings (64K page size) */ +#define MMU_IDENT_PAGE_SIZE_SHIFT (SHIFT_64K) +#elif MMU_IDENT_SIZE_SHIFT <= 39 /* Use 1GB block mappings (4K page size) */ +#define MMU_IDENT_PAGE_SIZE_SHIFT (SHIFT_4K) +#elif MMU_IDENT_SIZE_SHIFT <= 42 /* Use 512MB block mappings (64K page size) */ +#define MMU_IDENT_PAGE_SIZE_SHIFT (SHIFT_64K) +#else +#error MMU_IDENT_SIZE_SHIFT too large +#endif + +/* + * TCR TGx values + * + * Page size: 4K 16K 64K + * TG0: 0 2 1 + * TG1: 2 1 3 + */ + +#define MMU_TG0(page_size_shift) ((((page_size_shift == 14) & 1) << 1) | \ + ((page_size_shift == 16) & 1)) + +#define MMU_TG1(page_size_shift) ((((page_size_shift == 12) & 1) << 1) | \ + ((page_size_shift == 14) & 1) | \ + ((page_size_shift == 16) & 1) | \ + (((page_size_shift == 16) & 1) << 1)) + +#define MMU_LX_X(page_shift, level) ((4 - (level)) * ((page_shift) - 3) + 3) + +#if MMU_USER_SIZE_SHIFT > MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 0) +#define MMU_USER_TOP_SHIFT MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 0) +#elif MMU_USER_SIZE_SHIFT > MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 1) +#define MMU_USER_TOP_SHIFT MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 1) +#elif MMU_USER_SIZE_SHIFT > MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 2) +#define MMU_USER_TOP_SHIFT MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 2) +#elif MMU_USER_SIZE_SHIFT > MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 3) +#define MMU_USER_TOP_SHIFT MMU_LX_X(MMU_USER_PAGE_SIZE_SHIFT, 3) +#else +#error User address space size must be larger than page size +#endif +#define MMU_USER_PAGE_TABLE_ENTRIES_TOP (0x1 << (MMU_USER_SIZE_SHIFT - MMU_USER_TOP_SHIFT)) + +#if MMU_KERNEL_SIZE_SHIFT > MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 0) +#define MMU_KERNEL_TOP_SHIFT MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 0) +#elif MMU_KERNEL_SIZE_SHIFT > MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 1) +#define MMU_KERNEL_TOP_SHIFT MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 1) +#elif MMU_KERNEL_SIZE_SHIFT > MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 2) +#define MMU_KERNEL_TOP_SHIFT MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 2) +#elif MMU_KERNEL_SIZE_SHIFT > MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 3) +#define MMU_KERNEL_TOP_SHIFT MMU_LX_X(MMU_KERNEL_PAGE_SIZE_SHIFT, 3) +#else +#error Kernel address space size must be larger than page size +#endif +#define MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP (0x1 << (MMU_KERNEL_SIZE_SHIFT - MMU_KERNEL_TOP_SHIFT)) + +#if MMU_IDENT_SIZE_SHIFT > MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 0) +#define MMU_IDENT_TOP_SHIFT MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 0) +#elif MMU_IDENT_SIZE_SHIFT > MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 1) +#define MMU_IDENT_TOP_SHIFT MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 1) +#elif MMU_IDENT_SIZE_SHIFT > MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 2) +#define MMU_IDENT_TOP_SHIFT MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 2) +#elif MMU_IDENT_SIZE_SHIFT > MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 3) +#define MMU_IDENT_TOP_SHIFT MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 3) +#else +#error Ident address space size must be larger than page size +#endif +#define MMU_PAGE_TABLE_ENTRIES_IDENT_SHIFT (MMU_IDENT_SIZE_SHIFT - MMU_IDENT_TOP_SHIFT) +#define MMU_PAGE_TABLE_ENTRIES_IDENT (0x1 << MMU_PAGE_TABLE_ENTRIES_IDENT_SHIFT) + +#define MMU_PTE_DESCRIPTOR_BLOCK_MAX_SHIFT (30) + +#ifndef ASSEMBLY +#define BM(base, count, val) (((val) & ((1UL << (count)) - 1)) << (base)) +#else +#define BM(base, count, val) (((val) & ((0x1 << (count)) - 1)) << (base)) +#endif + +#define MMU_SH_NON_SHAREABLE (0) +#define MMU_SH_OUTER_SHAREABLE (2) +#define MMU_SH_INNER_SHAREABLE (3) + +#define MMU_RGN_NON_CACHEABLE (0) +#define MMU_RGN_WRITE_BACK_ALLOCATE (1) +#define MMU_RGN_WRITE_THROUGH_NO_ALLOCATE (2) +#define MMU_RGN_WRITE_BACK_NO_ALLOCATE (3) + +#define MMU_TCR_TBI1 BM(38, 1, 1) +#define MMU_TCR_TBI0 BM(37, 1, 1) +#define MMU_TCR_AS BM(36, 1, 1) +#define MMU_TCR_IPS(size) BM(32, 3, (size)) +#define MMU_TCR_TG1(granule_size) BM(30, 2, (granule_size)) +#define MMU_TCR_SH1(shareability_flags) BM(28, 2, (shareability_flags)) +#define MMU_TCR_ORGN1(cache_flags) BM(26, 2, (cache_flags)) +#define MMU_TCR_IRGN1(cache_flags) BM(24, 2, (cache_flags)) +#define MMU_TCR_EPD1 BM(23, 1, 1) +#define MMU_TCR_A1 BM(22, 1, 1) +#define MMU_TCR_T1SZ(size) BM(16, 6, (size)) +#define MMU_TCR_TG0(granule_size) BM(14, 2, (granule_size)) +#define MMU_TCR_SH0(shareability_flags) BM(12, 2, (shareability_flags)) +#define MMU_TCR_ORGN0(cache_flags) BM(10, 2, (cache_flags)) +#define MMU_TCR_IRGN0(cache_flags) BM( 8, 2, (cache_flags)) +#define MMU_TCR_EPD0 BM( 7, 1, 1) +#define MMU_TCR_T0SZ(size) BM( 0, 6, (size)) + +#define MMU_MAIR_ATTR(index, attr) BM(index * 8, 8, (attr)) + + +/* L0/L1/L2/L3 descriptor types */ +#define MMU_PTE_DESCRIPTOR_INVALID BM(0, 2, 0) +#define MMU_PTE_DESCRIPTOR_MASK BM(0, 2, 3) + +/* L0/L1/L2 descriptor types */ +#define MMU_PTE_L012_DESCRIPTOR_BLOCK BM(0, 2, 1) +#define MMU_PTE_L012_DESCRIPTOR_TABLE BM(0, 2, 3) + +/* L3 descriptor types */ +#define MMU_PTE_L3_DESCRIPTOR_PAGE BM(0, 2, 3) + +/* Output address mask */ +#define MMU_PTE_OUTPUT_ADDR_MASK BM(12, 36, 0xfffffffff) + +/* Table attrs */ +#define MMU_PTE_ATTR_NS_TABLE BM(63, 1, 1) +#define MMU_PTE_ATTR_AP_TABLE_NO_WRITE BM(62, 1, 1) +#define MMU_PTE_ATTR_AP_TABLE_NO_EL0 BM(61, 1, 1) +#define MMU_PTE_ATTR_UXN_TABLE BM(60, 1, 1) +#define MMU_PTE_ATTR_PXN_TABLE BM(59, 1, 1) + +/* Block/Page attrs */ +#define MMU_PTE_ATTR_RES_SOFTWARE BM(55, 4, 0xf) +#define MMU_PTE_ATTR_UXN BM(54, 1, 1) +#define MMU_PTE_ATTR_PXN BM(53, 1, 1) +#define MMU_PTE_ATTR_CONTIGUOUS BM(52, 1, 1) + +#define MMU_PTE_ATTR_NON_GLOBAL BM(11, 1, 1) +#define MMU_PTE_ATTR_AF BM(10, 1, 1) + +#define MMU_PTE_ATTR_SH_NON_SHAREABLE BM(8, 2, 0) +#define MMU_PTE_ATTR_SH_OUTER_SHAREABLE BM(8, 2, 2) +#define MMU_PTE_ATTR_SH_INNER_SHAREABLE BM(8, 2, 3) + +#define MMU_PTE_ATTR_AP_P_RW_U_NA BM(6, 2, 0) +#define MMU_PTE_ATTR_AP_P_RW_U_RW BM(6, 2, 1) +#define MMU_PTE_ATTR_AP_P_RO_U_NA BM(6, 2, 2) +#define MMU_PTE_ATTR_AP_P_RO_U_RO BM(6, 2, 3) +#define MMU_PTE_ATTR_AP_MASK BM(6, 2, 3) + +#define MMU_PTE_ATTR_NON_SECURE BM(5, 1, 1) + +#define MMU_PTE_ATTR_ATTR_INDEX(attrindex) BM(2, 3, attrindex) +#define MMU_PTE_ATTR_ATTR_INDEX_MASK MMU_PTE_ATTR_ATTR_INDEX(7) + +#define MMU_PTE_PERMISSION_MASK (MMU_PTE_ATTR_AP_MASK | \ + MMU_PTE_ATTR_UXN | \ + MMU_PTE_ATTR_PXN) + +/* Default configuration for main kernel page table: + * - do cached translation walks + */ + +/* Device-nGnRnE memory */ +#define MMU_MAIR_ATTR0 MMU_MAIR_ATTR(0, 0x00) +#define MMU_PTE_ATTR_STRONGLY_ORDERED MMU_PTE_ATTR_ATTR_INDEX(0) + +/* Device-nGnRE memory */ +#define MMU_MAIR_ATTR1 MMU_MAIR_ATTR(1, 0x04) +#define MMU_PTE_ATTR_DEVICE MMU_PTE_ATTR_ATTR_INDEX(1) + +/* Normal Memory, Outer Write-back non-transient Read/Write allocate, + * Inner Write-back non-transient Read/Write allocate + */ +#define MMU_MAIR_ATTR2 MMU_MAIR_ATTR(2, 0xff) +#define MMU_PTE_ATTR_NORMAL_MEMORY MMU_PTE_ATTR_ATTR_INDEX(2) + +#define MMU_MAIR_ATTR3 (0) +#define MMU_MAIR_ATTR4 (0) +#define MMU_MAIR_ATTR5 (0) +#define MMU_MAIR_ATTR6 (0) +#define MMU_MAIR_ATTR7 (0) + +#define MMU_MAIR_VAL (MMU_MAIR_ATTR0 | MMU_MAIR_ATTR1 | \ + MMU_MAIR_ATTR2 | MMU_MAIR_ATTR3 | \ + MMU_MAIR_ATTR4 | MMU_MAIR_ATTR5 | \ + MMU_MAIR_ATTR6 | MMU_MAIR_ATTR7 ) + +#define MMU_TCR_IPS_DEFAULT MMU_TCR_IPS(2) /* TODO: read at runtime, or configure per platform */ + +/* Enable cached page table walks: + * inner/outer (IRGN/ORGN): write-back + write-allocate + */ +#define MMU_TCR_FLAGS1 (MMU_TCR_TG1(MMU_TG1(MMU_KERNEL_PAGE_SIZE_SHIFT)) | \ + MMU_TCR_SH1(MMU_SH_INNER_SHAREABLE) | \ + MMU_TCR_ORGN1(MMU_RGN_WRITE_BACK_ALLOCATE) | \ + MMU_TCR_IRGN1(MMU_RGN_WRITE_BACK_ALLOCATE) | \ + MMU_TCR_T1SZ(64 - MMU_KERNEL_SIZE_SHIFT)) +#define MMU_TCR_FLAGS0 (MMU_TCR_TG0(MMU_TG0(MMU_USER_PAGE_SIZE_SHIFT)) | \ + MMU_TCR_SH0(MMU_SH_INNER_SHAREABLE) | \ + MMU_TCR_ORGN0(MMU_RGN_WRITE_BACK_ALLOCATE) | \ + MMU_TCR_IRGN0(MMU_RGN_WRITE_BACK_ALLOCATE) | \ + MMU_TCR_T0SZ(64 - MMU_USER_SIZE_SHIFT)) +#define MMU_TCR_FLAGS0_IDENT \ + (MMU_TCR_TG0(MMU_TG0(MMU_IDENT_PAGE_SIZE_SHIFT)) | \ + MMU_TCR_SH0(MMU_SH_INNER_SHAREABLE) | \ + MMU_TCR_ORGN0(MMU_RGN_WRITE_BACK_ALLOCATE) | \ + MMU_TCR_IRGN0(MMU_RGN_WRITE_BACK_ALLOCATE) | \ + MMU_TCR_T0SZ(64 - MMU_IDENT_SIZE_SHIFT)) +#define MMU_TCR_FLAGS_IDENT (MMU_TCR_IPS_DEFAULT | MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0_IDENT) +#define MMU_TCR_FLAGS_KERNEL (MMU_TCR_IPS_DEFAULT | MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0 | MMU_TCR_EPD0) +#define MMU_TCR_FLAGS_USER (MMU_TCR_IPS_DEFAULT | MMU_TCR_FLAGS1 | MMU_TCR_FLAGS0) + + +#if MMU_IDENT_SIZE_SHIFT > MMU_LX_X(MMU_IDENT_PAGE_SIZE_SHIFT, 2) +#define MMU_PTE_IDENT_DESCRIPTOR MMU_PTE_L012_DESCRIPTOR_BLOCK +#else +#define MMU_PTE_IDENT_DESCRIPTOR MMU_PTE_L3_DESCRIPTOR_PAGE +#endif +#define MMU_PTE_IDENT_FLAGS \ + (MMU_PTE_IDENT_DESCRIPTOR | \ + MMU_PTE_ATTR_AF | \ + MMU_PTE_ATTR_SH_INNER_SHAREABLE | \ + MMU_PTE_ATTR_NORMAL_MEMORY | \ + MMU_PTE_ATTR_AP_P_RW_U_NA) + +#define MMU_PTE_KERNEL_RO_FLAGS \ + (MMU_PTE_ATTR_UXN | \ + MMU_PTE_ATTR_AF | \ + MMU_PTE_ATTR_SH_INNER_SHAREABLE | \ + MMU_PTE_ATTR_NORMAL_MEMORY | \ + MMU_PTE_ATTR_AP_P_RO_U_NA) + +#define MMU_PTE_KERNEL_DATA_FLAGS \ + (MMU_PTE_ATTR_UXN | \ + MMU_PTE_ATTR_PXN | \ + MMU_PTE_ATTR_AF | \ + MMU_PTE_ATTR_SH_INNER_SHAREABLE | \ + MMU_PTE_ATTR_NORMAL_MEMORY | \ + MMU_PTE_ATTR_AP_P_RW_U_NA) + +#define MMU_INITIAL_MAP_STRONGLY_ORDERED \ + (MMU_PTE_ATTR_UXN | \ + MMU_PTE_ATTR_PXN | \ + MMU_PTE_ATTR_AF | \ + MMU_PTE_ATTR_STRONGLY_ORDERED | \ + MMU_PTE_ATTR_AP_P_RW_U_NA) + +#define MMU_INITIAL_MAP_DEVICE \ + (MMU_PTE_ATTR_UXN | \ + MMU_PTE_ATTR_PXN | \ + MMU_PTE_ATTR_AF | \ + MMU_PTE_ATTR_DEVICE | \ + MMU_PTE_ATTR_AP_P_RW_U_NA) + +#ifndef ASSEMBLY + +#include +#include +#include +#include + +typedef uint64_t pte_t; + +__BEGIN_CDECLS + +#define ARM64_TLBI_NOADDR(op) \ +({ \ + __asm__ volatile("tlbi " #op::); \ + ISB; \ +}) + +#define ARM64_TLBI(op, val) \ +({ \ + __asm__ volatile("tlbi " #op ", %0" :: "r" (val)); \ + ISB; \ +}) + +#define MMU_ARM64_GLOBAL_ASID (~0U) +#define MMU_ARM64_USER_ASID (0U) +int arm64_mmu_map(vaddr_t vaddr, paddr_t paddr, size_t size, pte_t attrs, + vaddr_t vaddr_base, uint top_size_shift, + uint top_index_shift, uint page_size_shift, + pte_t *top_page_table, uint asid); +int arm64_mmu_unmap(vaddr_t vaddr, size_t size, + vaddr_t vaddr_base, uint top_size_shift, + uint top_index_shift, uint page_size_shift, + pte_t *top_page_table, uint asid); + +__END_CDECLS +#endif /* ASSEMBLY */ diff --git a/kernel/arch/arm64/include/arch/arm64/user_copy.h b/kernel/arch/arm64/include/arch/arm64/user_copy.h new file mode 100644 index 000000000..18fb7d883 --- /dev/null +++ b/kernel/arch/arm64/include/arch/arm64/user_copy.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once +#include + +__BEGIN_CDECLS + +/* These functions are identical to arch_copy_from_user, except they take an + * additional argument of fault_return, used to handle page faults within the + * function. These should not be called anywhere except in the arm64 usercopy + * implementation. */ + +status_t _arm64_copy_from_user( + void *dst, + const void *src, + size_t len, + void **fault_return); + +status_t _arm64_copy_to_user( + void *dst, + const void *src, + size_t len, + void **fault_return); + +__END_CDECLS diff --git a/kernel/arch/arm64/include/arch/asm_macros.h b/kernel/arch/arm64/include/arch/asm_macros.h new file mode 100644 index 000000000..f05d30776 --- /dev/null +++ b/kernel/arch/arm64/include/arch/asm_macros.h @@ -0,0 +1,79 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +.macro push ra, rb +stp \ra, \rb, [sp,#-16]! +.endm + +.macro pop ra, rb +ldp \ra, \rb, [sp], #16 +.endm + +.macro tbzmask, reg, mask, label, shift=0 +.if \shift >= 64 + .error "tbzmask: unsupported mask, \mask" +.elseif \mask == 1 << \shift + tbz \reg, #\shift, \label +.else + tbzmask \reg, \mask, \label, "(\shift + 1)" +.endif +.endm + +.macro tbnzmask, reg, mask, label, shift=0 +.if \shift >= 64 + .error "tbnzmask: unsupported mask, \mask" +.elseif \mask == 1 << \shift + tbnz \reg, #\shift, \label +.else + tbnzmask \reg, \mask, \label, "(\shift + 1)" +.endif +.endm + +.macro calloc_bootmem_aligned, new_ptr, new_ptr_end, tmp, size_shift, phys_offset +.if \size_shift < 4 + .error "calloc_bootmem_aligned: Unsupported size_shift, \size_shift" +.endif + + /* load boot_alloc_end */ + adrp \tmp, boot_alloc_end + ldr \new_ptr, [\tmp, #:lo12:boot_alloc_end] + + /* align to page */ +.if \size_shift > 12 + add \new_ptr, \new_ptr, #(1 << \size_shift) + sub \new_ptr, \new_ptr, #1 +.else + add \new_ptr, \new_ptr, #(1 << \size_shift) - 1 +.endif + and \new_ptr, \new_ptr, #~((1 << \size_shift) - 1) + + /* add one page and store boot_alloc_end */ + add \new_ptr_end, \new_ptr, #(1 << \size_shift) + str \new_ptr_end, [\tmp, #:lo12:boot_alloc_end] + + /* clear page */ + sub \new_ptr, \new_ptr, \phys_offset + sub \new_ptr_end, \new_ptr_end, \phys_offset + + /* clear page */ + mov \tmp, \new_ptr +.Lcalloc_bootmem_aligned_clear_loop\@: + stp xzr, xzr, [\tmp], #16 + cmp \tmp, \new_ptr_end + b.lo .Lcalloc_bootmem_aligned_clear_loop\@ +.endm + +/* Set fault handler for next instruction */ +.macro set_fault_handler, handler +.Lfault_location\@: +.pushsection .rodata.fault_handler_table + .quad .Lfault_location\@ + .quad \handler +.popsection +.endm diff --git a/kernel/arch/arm64/include/arch/aspace.h b/kernel/arch/arm64/include/arch/aspace.h new file mode 100644 index 000000000..d8d191719 --- /dev/null +++ b/kernel/arch/arm64/include/arch/aspace.h @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015-2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +#define ARCH_ASPACE_MAGIC 0x41524153 // ARAS + +struct arch_aspace { + /* magic value for use-after-free detection */ + uint32_t magic; + + /* pointer to the translation table */ + paddr_t tt_phys; + pte_t *tt_virt; + + uint flags; + + /* range of address space */ + vaddr_t base; + size_t size; +}; + +__END_CDECLS + diff --git a/kernel/arch/arm64/include/arch/defines.h b/kernel/arch/arm64/include/arch/defines.h new file mode 100644 index 000000000..586e2649a --- /dev/null +++ b/kernel/arch/arm64/include/arch/defines.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#define SHIFT_4K (12) +#define SHIFT_16K (14) +#define SHIFT_64K (16) + +/* arm specific stuff */ +#ifdef ARM64_LARGE_PAGESIZE_64K +#define PAGE_SIZE_SHIFT (SHIFT_64K) +#elif ARM64_LARGE_PAGESIZE_16K +#define PAGE_SIZE_SHIFT (SHIFT_16K) +#else +#define PAGE_SIZE_SHIFT (SHIFT_4K) +#endif +#define USER_PAGE_SIZE_SHIFT SHIFT_4K + +#define PAGE_SIZE (1UL << PAGE_SIZE_SHIFT) +#define USER_PAGE_SIZE (1UL << USER_PAGE_SIZE_SHIFT) + +#define CACHE_LINE 32 + diff --git a/kernel/arch/arm64/include/arch/spinlock.h b/kernel/arch/arm64/include/arch/spinlock.h new file mode 100644 index 000000000..aeba2ab25 --- /dev/null +++ b/kernel/arch/arm64/include/arch/spinlock.h @@ -0,0 +1,105 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +#define SPIN_LOCK_INITIAL_VALUE (0) + +typedef unsigned long spin_lock_t; + +typedef unsigned int spin_lock_saved_state_t; +typedef unsigned int spin_lock_save_flags_t; + +#if WITH_SMP +void arch_spin_lock(spin_lock_t *lock); +int arch_spin_trylock(spin_lock_t *lock); +void arch_spin_unlock(spin_lock_t *lock); +#else +static inline void arch_spin_lock(spin_lock_t *lock) +{ + *lock = 1; +} + +static inline int arch_spin_trylock(spin_lock_t *lock) +{ + return 0; +} + +static inline void arch_spin_unlock(spin_lock_t *lock) +{ + *lock = 0; +} +#endif + +static inline void arch_spin_lock_init(spin_lock_t *lock) +{ + *lock = SPIN_LOCK_INITIAL_VALUE; +} + +static inline bool arch_spin_lock_held(spin_lock_t *lock) +{ + return *lock != 0; +} + +enum { + /* Possible future flags: + * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff, + * SPIN_LOCK_FLAG_PREEMPTION = 0x10000000, + * SPIN_LOCK_FLAG_SET_PMR = 0x20000000, + */ + + /* ARM specific flags */ + SPIN_LOCK_FLAG_IRQ = 0x40000000, + SPIN_LOCK_FLAG_FIQ = 0x80000000, /* Do not use unless IRQs are already disabled */ + SPIN_LOCK_FLAG_IRQ_FIQ = SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ, + + /* Generic flags */ + SPIN_LOCK_FLAG_INTERRUPTS = SPIN_LOCK_FLAG_IRQ, +}; + +/* default arm flag is to just disable plain irqs */ +#define ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS SPIN_LOCK_FLAG_INTERRUPTS + +enum { + /* private */ + SPIN_LOCK_STATE_RESTORE_IRQ = 1, + SPIN_LOCK_STATE_RESTORE_FIQ = 2, +}; + +static inline void +arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) +{ + spin_lock_saved_state_t state = 0; + if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_IRQ; + arch_disable_ints(); + } + if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) { + state |= SPIN_LOCK_STATE_RESTORE_FIQ; + arch_disable_fiqs(); + } + *statep = state; +} + +static inline void +arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) +{ + if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ)) + arch_enable_fiqs(); + if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ)) + arch_enable_ints(); +} + +__END_CDECLS + + diff --git a/kernel/arch/arm64/mmu.c b/kernel/arch/arm64/mmu.c new file mode 100644 index 000000000..e1a69d966 --- /dev/null +++ b/kernel/arch/arm64/mmu.c @@ -0,0 +1,803 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Google Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 +#define TRACE_CONTEXT_SWITCH 0 + +STATIC_ASSERT(((long)KERNEL_BASE >> MMU_KERNEL_SIZE_SHIFT) == -1); +STATIC_ASSERT(((long)KERNEL_ASPACE_BASE >> MMU_KERNEL_SIZE_SHIFT) == -1); +STATIC_ASSERT(MMU_KERNEL_SIZE_SHIFT <= 48); +STATIC_ASSERT(MMU_KERNEL_SIZE_SHIFT >= 25); + +/* the main translation table */ +pte_t arm64_kernel_translation_table[MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP] + __ALIGNED(MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP * 8) + __SECTION(".bss.prebss.translation_table"); + +static inline bool is_valid_vaddr(arch_aspace_t *aspace, vaddr_t vaddr) +{ + return (vaddr >= aspace->base && vaddr <= aspace->base + aspace->size - 1); +} + +/* convert user level mmu flags to flags that go in L1 descriptors */ +static pte_t mmu_flags_to_pte_attr(uint flags) +{ + pte_t attr = MMU_PTE_ATTR_AF; + + switch (flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_CACHED: + attr |= MMU_PTE_ATTR_NORMAL_MEMORY | MMU_PTE_ATTR_SH_INNER_SHAREABLE; + break; + case ARCH_MMU_FLAG_WRITE_COMBINING: + case ARCH_MMU_FLAG_UNCACHED: + attr |= MMU_PTE_ATTR_STRONGLY_ORDERED; + break; + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + attr |= MMU_PTE_ATTR_DEVICE; + break; + default: + /* invalid user-supplied flag */ + DEBUG_ASSERT(1); + return ERR_INVALID_ARGS; + } + + switch (flags & (ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO)) { + case 0: + attr |= MMU_PTE_ATTR_AP_P_RW_U_NA; + break; + case ARCH_MMU_FLAG_PERM_RO: + attr |= MMU_PTE_ATTR_AP_P_RO_U_NA; + break; + case ARCH_MMU_FLAG_PERM_USER: + attr |= MMU_PTE_ATTR_AP_P_RW_U_RW; + break; + case ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO: + attr |= MMU_PTE_ATTR_AP_P_RO_U_RO; + break; + } + + if (flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE) { + attr |= MMU_PTE_ATTR_UXN | MMU_PTE_ATTR_PXN; + } + + if (flags & ARCH_MMU_FLAG_NS) { + attr |= MMU_PTE_ATTR_NON_SECURE; + } + + return attr; +} + +status_t arch_mmu_query(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t *paddr, uint *flags) +{ + uint index; + uint index_shift; + uint page_size_shift; + pte_t pte; + pte_t pte_addr; + uint descriptor_type; + pte_t *page_table; + vaddr_t vaddr_rem; + + LTRACEF("aspace %p, vaddr 0x%lx\n", aspace, vaddr); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + + /* compute shift values based on if this address space is for kernel or user space */ + if (aspace->flags & ARCH_ASPACE_FLAG_KERNEL) { + index_shift = MMU_KERNEL_TOP_SHIFT; + page_size_shift = MMU_KERNEL_PAGE_SIZE_SHIFT; + + vaddr_t kernel_base = ~0UL << MMU_KERNEL_SIZE_SHIFT; + vaddr_rem = vaddr - kernel_base; + + index = vaddr_rem >> index_shift; + ASSERT(index < MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP); + } else { + index_shift = MMU_USER_TOP_SHIFT; + page_size_shift = MMU_USER_PAGE_SIZE_SHIFT; + + vaddr_rem = vaddr; + index = vaddr_rem >> index_shift; + ASSERT(index < MMU_USER_PAGE_TABLE_ENTRIES_TOP); + } + + page_table = aspace->tt_virt; + + while (true) { + index = vaddr_rem >> index_shift; + vaddr_rem -= (vaddr_t)index << index_shift; + pte = page_table[index]; + descriptor_type = pte & MMU_PTE_DESCRIPTOR_MASK; + pte_addr = pte & MMU_PTE_OUTPUT_ADDR_MASK; + + LTRACEF("va 0x%lx, index %d, index_shift %d, rem 0x%lx, pte 0x%llx\n", + vaddr, index, index_shift, vaddr_rem, pte); + + if (descriptor_type == MMU_PTE_DESCRIPTOR_INVALID) + return ERR_NOT_FOUND; + + if (descriptor_type == ((index_shift > page_size_shift) ? + MMU_PTE_L012_DESCRIPTOR_BLOCK : + MMU_PTE_L3_DESCRIPTOR_PAGE)) { + break; + } + + if (index_shift <= page_size_shift || + descriptor_type != MMU_PTE_L012_DESCRIPTOR_TABLE) { + PANIC_UNIMPLEMENTED; + } + + page_table = paddr_to_kvaddr(pte_addr); + index_shift -= page_size_shift - 3; + } + + if (paddr) + *paddr = pte_addr + vaddr_rem; + if (flags) { + *flags = 0; + if (pte & MMU_PTE_ATTR_NON_SECURE) + *flags |= ARCH_MMU_FLAG_NS; + switch (pte & MMU_PTE_ATTR_ATTR_INDEX_MASK) { + case MMU_PTE_ATTR_STRONGLY_ORDERED: + *flags |= ARCH_MMU_FLAG_UNCACHED; + break; + case MMU_PTE_ATTR_DEVICE: + *flags |= ARCH_MMU_FLAG_UNCACHED_DEVICE; + break; + case MMU_PTE_ATTR_NORMAL_MEMORY: + break; + default: + PANIC_UNIMPLEMENTED; + } + switch (pte & MMU_PTE_ATTR_AP_MASK) { + case MMU_PTE_ATTR_AP_P_RW_U_NA: + break; + case MMU_PTE_ATTR_AP_P_RW_U_RW: + *flags |= ARCH_MMU_FLAG_PERM_USER; + break; + case MMU_PTE_ATTR_AP_P_RO_U_NA: + *flags |= ARCH_MMU_FLAG_PERM_RO; + break; + case MMU_PTE_ATTR_AP_P_RO_U_RO: + *flags |= ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO; + break; + } + if ((pte & MMU_PTE_ATTR_UXN) && (pte & MMU_PTE_ATTR_PXN)) { + *flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE; + } + } + LTRACEF("va 0x%lx, paddr 0x%lx, flags 0x%x\n", + vaddr, paddr ? *paddr : ~0UL, flags ? *flags : ~0U); + return 0; +} + +static int alloc_page_table(paddr_t *paddrp, uint page_size_shift) +{ + size_t size = 1U << page_size_shift; + + LTRACEF("page_size_shift %u\n", page_size_shift); + + if (size >= PAGE_SIZE) { + size_t count = size / PAGE_SIZE; + size_t ret = pmm_alloc_contiguous(count, PMM_ALLOC_FLAG_KMAP, page_size_shift, paddrp, NULL); + if (ret != count) + return ERR_NO_MEMORY; + } else if (size == PAGE_SIZE) { + void *vaddr = pmm_alloc_kpage(paddrp); + if (!vaddr) + return ERR_NO_MEMORY; + } else { + void *vaddr = memalign(size, size); + if (!vaddr) + return ERR_NO_MEMORY; + *paddrp = vaddr_to_paddr(vaddr); + if (*paddrp == 0) { + free(vaddr); + return ERR_NO_MEMORY; + } + } + + LTRACEF("allocated 0x%lx\n", *paddrp); + return 0; +} + +static void free_page_table(void *vaddr, paddr_t paddr, uint page_size_shift) +{ + LTRACEF("vaddr %p paddr 0x%lx page_size_shift %u\n", vaddr, paddr, page_size_shift); + + size_t size = 1U << page_size_shift; + vm_page_t *page; + + if (size >= PAGE_SIZE) { + page = paddr_to_vm_page(paddr); + if (!page) + panic("bad page table paddr 0x%lx\n", paddr); + pmm_free_page(page); + } else { + free(vaddr); + } +} + +static pte_t *arm64_mmu_get_page_table(vaddr_t index, uint page_size_shift, pte_t *page_table) +{ + pte_t pte; + paddr_t paddr; + void *vaddr; + int ret; + + pte = page_table[index]; + switch (pte & MMU_PTE_DESCRIPTOR_MASK) { + case MMU_PTE_DESCRIPTOR_INVALID: + ret = alloc_page_table(&paddr, page_size_shift); + if (ret) { + TRACEF("failed to allocate page table\n"); + return NULL; + } + vaddr = paddr_to_kvaddr(paddr); + + LTRACEF("allocated page table, vaddr %p, paddr 0x%lx\n", vaddr, paddr); + memset(vaddr, MMU_PTE_DESCRIPTOR_INVALID, 1U << page_size_shift); + + __asm__ volatile("dmb ishst" ::: "memory"); + + pte = paddr | MMU_PTE_L012_DESCRIPTOR_TABLE; + page_table[index] = pte; + LTRACEF("pte %p[0x%lx] = 0x%llx\n", page_table, index, pte); + return vaddr; + + case MMU_PTE_L012_DESCRIPTOR_TABLE: + paddr = pte & MMU_PTE_OUTPUT_ADDR_MASK; + LTRACEF("found page table 0x%lx\n", paddr); + return paddr_to_kvaddr(paddr); + + case MMU_PTE_L012_DESCRIPTOR_BLOCK: + return NULL; + + default: + PANIC_UNIMPLEMENTED; + } +} + +static bool page_table_is_clear(pte_t *page_table, uint page_size_shift) +{ + int i; + int count = 1U << (page_size_shift - 3); + pte_t pte; + + for (i = 0; i < count; i++) { + pte = page_table[i]; + if (pte != MMU_PTE_DESCRIPTOR_INVALID) { + LTRACEF("page_table at %p still in use, index %d is 0x%llx\n", + page_table, i, pte); + return false; + } + } + + LTRACEF("page table at %p is clear\n", page_table); + return true; +} + +static int arm64_mmu_unmap_pt(vaddr_t vaddr, vaddr_t vaddr_rel, + size_t size, + uint index_shift, uint page_size_shift, + pte_t *page_table, uint asid) +{ + pte_t *next_page_table; + vaddr_t index; + size_t chunk_size; + vaddr_t vaddr_rem; + vaddr_t block_size; + vaddr_t block_mask; + pte_t pte; + paddr_t page_table_paddr; + size_t unmap_size; + + LTRACEF("vaddr 0x%lx, vaddr_rel 0x%lx, size 0x%lx, index shift %d, page_size_shift %d, page_table %p\n", + vaddr, vaddr_rel, size, index_shift, page_size_shift, page_table); + + unmap_size = 0; + while (size) { + block_size = 1UL << index_shift; + block_mask = block_size - 1; + vaddr_rem = vaddr_rel & block_mask; + chunk_size = MIN(size, block_size - vaddr_rem); + index = vaddr_rel >> index_shift; + + pte = page_table[index]; + + if (index_shift > page_size_shift && + (pte & MMU_PTE_DESCRIPTOR_MASK) == MMU_PTE_L012_DESCRIPTOR_TABLE) { + page_table_paddr = pte & MMU_PTE_OUTPUT_ADDR_MASK; + next_page_table = paddr_to_kvaddr(page_table_paddr); + arm64_mmu_unmap_pt(vaddr, vaddr_rem, chunk_size, + index_shift - (page_size_shift - 3), + page_size_shift, + next_page_table, asid); + if (chunk_size == block_size || + page_table_is_clear(next_page_table, page_size_shift)) { + LTRACEF("pte %p[0x%lx] = 0 (was page table)\n", page_table, index); + page_table[index] = MMU_PTE_DESCRIPTOR_INVALID; + __asm__ volatile("dmb ishst" ::: "memory"); + free_page_table(next_page_table, page_table_paddr, page_size_shift); + } + } else if (pte) { + LTRACEF("pte %p[0x%lx] = 0\n", page_table, index); + page_table[index] = MMU_PTE_DESCRIPTOR_INVALID; + CF; + if (asid == MMU_ARM64_GLOBAL_ASID) + ARM64_TLBI(vaae1is, vaddr >> 12); + else + ARM64_TLBI(vae1is, vaddr >> 12 | (vaddr_t)asid << 48); + } else { + LTRACEF("pte %p[0x%lx] already clear\n", page_table, index); + } + vaddr += chunk_size; + vaddr_rel += chunk_size; + size -= chunk_size; + unmap_size += chunk_size; + } + + return unmap_size; +} + +static int arm64_mmu_map_pt(vaddr_t vaddr_in, vaddr_t vaddr_rel_in, + paddr_t paddr_in, + size_t size_in, pte_t attrs, + uint index_shift, uint page_size_shift, + pte_t *page_table, uint asid) +{ + int ret; + pte_t *next_page_table; + vaddr_t index; + vaddr_t vaddr = vaddr_in; + vaddr_t vaddr_rel = vaddr_rel_in; + paddr_t paddr = paddr_in; + size_t size = size_in; + size_t chunk_size; + vaddr_t vaddr_rem; + vaddr_t block_size; + vaddr_t block_mask; + pte_t pte; + size_t mapped_size; + + LTRACEF("vaddr 0x%lx, vaddr_rel 0x%lx, paddr 0x%lx, size 0x%lx, attrs 0x%llx, index shift %d, page_size_shift %d, page_table %p\n", + vaddr, vaddr_rel, paddr, size, attrs, + index_shift, page_size_shift, page_table); + + if ((vaddr_rel | paddr | size) & ((1UL << page_size_shift) - 1)) { + TRACEF("not page aligned\n"); + return ERR_INVALID_ARGS; + } + + mapped_size = 0; + while (size) { + block_size = 1UL << index_shift; + block_mask = block_size - 1; + vaddr_rem = vaddr_rel & block_mask; + chunk_size = MIN(size, block_size - vaddr_rem); + index = vaddr_rel >> index_shift; + + if (((vaddr_rel | paddr) & block_mask) || + (chunk_size != block_size) || + (index_shift > MMU_PTE_DESCRIPTOR_BLOCK_MAX_SHIFT)) { + next_page_table = arm64_mmu_get_page_table(index, page_size_shift, + page_table); + if (!next_page_table) + goto err; + + ret = arm64_mmu_map_pt(vaddr, vaddr_rem, paddr, chunk_size, attrs, + index_shift - (page_size_shift - 3), + page_size_shift, next_page_table, asid); + if (ret < 0) + goto err; + } else { + pte = page_table[index]; + if (pte) { + TRACEF("page table entry already in use, index 0x%lx, 0x%llx\n", + index, pte); + goto err; + } + + pte = paddr | attrs; + if (index_shift > page_size_shift) + pte |= MMU_PTE_L012_DESCRIPTOR_BLOCK; + else + pte |= MMU_PTE_L3_DESCRIPTOR_PAGE; + + LTRACEF("pte %p[0x%lx] = 0x%llx\n", page_table, index, pte); + page_table[index] = pte; + } + vaddr += chunk_size; + vaddr_rel += chunk_size; + paddr += chunk_size; + size -= chunk_size; + mapped_size += chunk_size; + } + + return mapped_size; + +err: + arm64_mmu_unmap_pt(vaddr_in, vaddr_rel_in, size_in - size, + index_shift, page_size_shift, page_table, asid); + DSB; + return ERR_GENERIC; +} + +static int arm64_mmu_protect_pt(vaddr_t vaddr_in, vaddr_t vaddr_rel_in, + size_t size_in, pte_t attrs, + uint index_shift, uint page_size_shift, + pte_t *page_table, uint asid) +{ + int ret; + pte_t *next_page_table; + vaddr_t index; + vaddr_t vaddr = vaddr_in; + vaddr_t vaddr_rel = vaddr_rel_in; + size_t size = size_in; + size_t chunk_size; + vaddr_t vaddr_rem; + vaddr_t block_size; + vaddr_t block_mask; + paddr_t page_table_paddr; + pte_t pte; + + LTRACEF("vaddr 0x%lx, vaddr_rel 0x%lx, size 0x%lx, attrs 0x%llx, index shift %d, page_size_shift %d, page_table %p\n", + vaddr, vaddr_rel, size, attrs, + index_shift, page_size_shift, page_table); + + if ((vaddr_rel | size) & ((1UL << page_size_shift) - 1)) { + TRACEF("not page aligned\n"); + return ERR_INVALID_ARGS; + } + + while (size) { + block_size = 1UL << index_shift; + block_mask = block_size - 1; + vaddr_rem = vaddr_rel & block_mask; + chunk_size = MIN(size, block_size - vaddr_rem); + index = vaddr_rel >> index_shift; + pte = page_table[index]; + + if (index_shift > page_size_shift && + (pte & MMU_PTE_DESCRIPTOR_MASK) == MMU_PTE_L012_DESCRIPTOR_TABLE) { + page_table_paddr = pte & MMU_PTE_OUTPUT_ADDR_MASK; + next_page_table = paddr_to_kvaddr(page_table_paddr); + ret = arm64_mmu_protect_pt(vaddr, vaddr_rem, chunk_size, + attrs, + index_shift - (page_size_shift - 3), + page_size_shift, + next_page_table, asid); + if (ret != 0) { + goto err; + } + } else if (pte) { + pte = (pte & ~MMU_PTE_PERMISSION_MASK) | attrs; + LTRACEF("pte %p[0x%lx] = 0x%llx\n", page_table, index, pte); + page_table[index] = pte; + } else { + TRACEF("page table entry does not exist, index 0x%lx, 0x%llx\n", + index, pte); + goto err; + } + vaddr += chunk_size; + vaddr_rel += chunk_size; + size -= chunk_size; + } + + DSB; + return 0; + +err: + // TODO: Unroll any changes we've made, though in practice if we've reached + // here there's a programming bug since the higher level region abstraction + // should guard against us trying to change permissions on an umapped page + DSB; + return ERR_GENERIC; +} + +int arm64_mmu_map(vaddr_t vaddr, paddr_t paddr, size_t size, pte_t attrs, + vaddr_t vaddr_base, uint top_size_shift, + uint top_index_shift, uint page_size_shift, + pte_t *top_page_table, uint asid) +{ + int ret; + vaddr_t vaddr_rel = vaddr - vaddr_base; + vaddr_t vaddr_rel_max = 1UL << top_size_shift; + + LTRACEF("vaddr 0x%lx, paddr 0x%lx, size 0x%lx, attrs 0x%llx, asid 0x%x\n", + vaddr, paddr, size, attrs, asid); + + if (vaddr_rel > vaddr_rel_max - size || size > vaddr_rel_max) { + TRACEF("vaddr 0x%lx, size 0x%lx out of range vaddr 0x%lx, size 0x%lx\n", + vaddr, size, vaddr_base, vaddr_rel_max); + return ERR_INVALID_ARGS; + } + + if (!top_page_table) { + TRACEF("page table is NULL\n"); + return ERR_INVALID_ARGS; + } + + ret = arm64_mmu_map_pt(vaddr, vaddr_rel, paddr, size, attrs, + top_index_shift, page_size_shift, top_page_table, asid); + DSB; + return ret; +} + +int arm64_mmu_unmap(vaddr_t vaddr, size_t size, + vaddr_t vaddr_base, uint top_size_shift, + uint top_index_shift, uint page_size_shift, + pte_t *top_page_table, uint asid) +{ + vaddr_t vaddr_rel = vaddr - vaddr_base; + vaddr_t vaddr_rel_max = 1UL << top_size_shift; + + LTRACEF("vaddr 0x%lx, size 0x%lx, asid 0x%x\n", vaddr, size, asid); + + if (vaddr_rel > vaddr_rel_max - size || size > vaddr_rel_max) { + TRACEF("vaddr 0x%lx, size 0x%lx out of range vaddr 0x%lx, size 0x%lx\n", + vaddr, size, vaddr_base, vaddr_rel_max); + return ERR_INVALID_ARGS; + } + + if (!top_page_table) { + TRACEF("page table is NULL\n"); + return ERR_INVALID_ARGS; + } + + int ret = arm64_mmu_unmap_pt(vaddr, vaddr_rel, size, + top_index_shift, page_size_shift, top_page_table, asid); + DSB; + return ret; +} + +static int arm64_mmu_protect(vaddr_t vaddr, size_t size, pte_t attrs, + vaddr_t vaddr_base, uint top_size_shift, + uint top_index_shift, uint page_size_shift, + pte_t *top_page_table, uint asid) +{ + int ret; + vaddr_t vaddr_rel = vaddr - vaddr_base; + vaddr_t vaddr_rel_max = 1UL << top_size_shift; + + LTRACEF("vaddr 0x%lx, size 0x%lx, attrs 0x%llx, asid 0x%x\n", + vaddr, size, attrs, asid); + + if (vaddr_rel > vaddr_rel_max - size || size > vaddr_rel_max) { + TRACEF("vaddr 0x%lx, size 0x%lx out of range vaddr 0x%lx, size 0x%lx\n", + vaddr, size, vaddr_base, vaddr_rel_max); + return ERR_INVALID_ARGS; + } + + if (!top_page_table) { + TRACEF("page table is NULL\n"); + return ERR_INVALID_ARGS; + } + + ret = arm64_mmu_protect_pt(vaddr, vaddr_rel, size, attrs, + top_index_shift, page_size_shift, top_page_table, asid); + DSB; + return ret; +} + +int arch_mmu_map(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t paddr, size_t count, uint flags) +{ + LTRACEF("vaddr 0x%lx paddr 0x%lx count %zu flags 0x%x\n", vaddr, paddr, count, flags); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + + /* paddr and vaddr must be aligned */ + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(paddr)); + if (!IS_PAGE_ALIGNED(vaddr) || !IS_PAGE_ALIGNED(paddr)) + return ERR_INVALID_ARGS; + + if (count == 0) + return NO_ERROR; + + int ret; + if (aspace->flags & ARCH_ASPACE_FLAG_KERNEL) { + ret = arm64_mmu_map(vaddr, paddr, count * PAGE_SIZE, + mmu_flags_to_pte_attr(flags), + ~0UL << MMU_KERNEL_SIZE_SHIFT, MMU_KERNEL_SIZE_SHIFT, + MMU_KERNEL_TOP_SHIFT, MMU_KERNEL_PAGE_SIZE_SHIFT, + aspace->tt_virt, MMU_ARM64_GLOBAL_ASID); + } else { + ret = arm64_mmu_map(vaddr, paddr, count * PAGE_SIZE, + mmu_flags_to_pte_attr(flags), + 0, MMU_USER_SIZE_SHIFT, + MMU_USER_TOP_SHIFT, MMU_USER_PAGE_SIZE_SHIFT, + aspace->tt_virt, MMU_ARM64_USER_ASID); + } + + return (ret < 0) ? ret : (ret / (int)PAGE_SIZE); +} + +int arch_mmu_unmap(arch_aspace_t *aspace, vaddr_t vaddr, size_t count) +{ + LTRACEF("vaddr 0x%lx count %zu\n", vaddr, count); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT(aspace->tt_virt); + + DEBUG_ASSERT(is_valid_vaddr(aspace, vaddr)); + + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_OUT_OF_RANGE; + + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + + int ret; + if (aspace->flags & ARCH_ASPACE_FLAG_KERNEL) { + ret = arm64_mmu_unmap(vaddr, count * PAGE_SIZE, + ~0UL << MMU_KERNEL_SIZE_SHIFT, MMU_KERNEL_SIZE_SHIFT, + MMU_KERNEL_TOP_SHIFT, MMU_KERNEL_PAGE_SIZE_SHIFT, + aspace->tt_virt, + MMU_ARM64_GLOBAL_ASID); + } else { + ret = arm64_mmu_unmap(vaddr, count * PAGE_SIZE, + 0, MMU_USER_SIZE_SHIFT, + MMU_USER_TOP_SHIFT, MMU_USER_PAGE_SIZE_SHIFT, + aspace->tt_virt, + MMU_ARM64_USER_ASID); + } + + return (ret < 0) ? ret : (ret / (int)PAGE_SIZE); +} + +int arch_mmu_protect(arch_aspace_t *aspace, vaddr_t vaddr, size_t count, uint flags) +{ + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + if (!is_valid_vaddr(aspace, vaddr)) + return ERR_INVALID_ARGS; + + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + + int ret; + if (aspace->flags & ARCH_ASPACE_FLAG_KERNEL) { + ret = arm64_mmu_protect(vaddr, count * PAGE_SIZE, + mmu_flags_to_pte_attr(flags), + ~0UL << MMU_KERNEL_SIZE_SHIFT, MMU_KERNEL_SIZE_SHIFT, + MMU_KERNEL_TOP_SHIFT, MMU_KERNEL_PAGE_SIZE_SHIFT, + aspace->tt_virt, + MMU_ARM64_GLOBAL_ASID); + } else { + ret = arm64_mmu_protect(vaddr, count * PAGE_SIZE, + mmu_flags_to_pte_attr(flags), + 0, MMU_USER_SIZE_SHIFT, + MMU_USER_TOP_SHIFT, MMU_USER_PAGE_SIZE_SHIFT, + aspace->tt_virt, + MMU_ARM64_USER_ASID); + } + + return ret; +} + +status_t arch_mmu_init_aspace(arch_aspace_t *aspace, vaddr_t base, size_t size, uint flags) +{ + LTRACEF("aspace %p, base 0x%lx, size 0x%zx, flags 0x%x\n", aspace, base, size, flags); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic != ARCH_ASPACE_MAGIC); + + /* validate that the base + size is sane and doesn't wrap */ + DEBUG_ASSERT(size > PAGE_SIZE); + DEBUG_ASSERT(base + size - 1 > base); + + aspace->magic = ARCH_ASPACE_MAGIC; + aspace->flags = flags; + if (flags & ARCH_ASPACE_FLAG_KERNEL) { + /* at the moment we can only deal with address spaces as globally defined */ + DEBUG_ASSERT(base == ~0UL << MMU_KERNEL_SIZE_SHIFT); + DEBUG_ASSERT(size == 1UL << MMU_KERNEL_SIZE_SHIFT); + + aspace->base = base; + aspace->size = size; + aspace->tt_virt = arm64_kernel_translation_table; + aspace->tt_phys = vaddr_to_paddr(aspace->tt_virt); + } else { + //DEBUG_ASSERT(base >= 0); + DEBUG_ASSERT(base + size <= 1UL << MMU_USER_SIZE_SHIFT); + + aspace->base = base; + aspace->size = size; + + paddr_t pa; + pte_t *va = pmm_alloc_kpage(&pa); + if (!va) + return ERR_NO_MEMORY; + + aspace->tt_virt = va; + aspace->tt_phys = pa; + + /* zero the top level translation table */ + /* XXX remove when PMM starts returning pre-zeroed pages */ + memset(aspace->tt_virt, 0, PAGE_SIZE); + } + + LTRACEF("tt_phys 0x%lx tt_virt %p\n", aspace->tt_phys, aspace->tt_virt); + + return NO_ERROR; +} + +status_t arch_mmu_destroy_aspace(arch_aspace_t *aspace) +{ + LTRACEF("aspace %p\n", aspace); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT((aspace->flags & ARCH_ASPACE_FLAG_KERNEL) == 0); + + // XXX make sure it's not mapped + + vm_page_t *page = paddr_to_vm_page(aspace->tt_phys); + DEBUG_ASSERT(page); + pmm_free_page(page); + + aspace->magic = 0; + + return NO_ERROR; +} + +void arch_mmu_context_switch(arch_aspace_t *old_aspace, arch_aspace_t *aspace) +{ + if (TRACE_CONTEXT_SWITCH) + TRACEF("aspace %p\n", aspace); + + uint64_t tcr; + uint64_t ttbr; + if (aspace) { + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + DEBUG_ASSERT((aspace->flags & ARCH_ASPACE_FLAG_KERNEL) == 0); + + tcr = MMU_TCR_FLAGS_USER; + ttbr = ((uint64_t)MMU_ARM64_USER_ASID << 48) | aspace->tt_phys; + ARM64_WRITE_SYSREG(ttbr0_el1, ttbr); + + if (TRACE_CONTEXT_SWITCH) + TRACEF("ttbr 0x%llx, tcr 0x%llx\n", ttbr, tcr); + ARM64_TLBI(aside1, MMU_ARM64_USER_ASID); + } else { + tcr = MMU_TCR_FLAGS_KERNEL; + + if (TRACE_CONTEXT_SWITCH) + TRACEF("tcr 0x%llx\n", tcr); + } + + ARM64_WRITE_SYSREG(tcr_el1, tcr); +} + diff --git a/kernel/arch/arm64/mp.c b/kernel/arch/arm64/mp.c new file mode 100644 index 000000000..d6d7ec5ab --- /dev/null +++ b/kernel/arch/arm64/mp.c @@ -0,0 +1,68 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include + +#if WITH_DEV_INTERRUPT_ARM_GIC +#include +#else +#error need other implementation of interrupt controller that can ipi +#endif + +#define LOCAL_TRACE 0 + +#define GIC_IPI_BASE (14) + +status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) +{ + LTRACEF("target 0x%x, ipi %u\n", target, ipi); + +#if WITH_DEV_INTERRUPT_ARM_GIC + uint gic_ipi_num = ipi + GIC_IPI_BASE; + + /* filter out targets outside of the range of cpus we care about */ + target &= ((1UL << SMP_MAX_CPUS) - 1); + if (target != 0) { + LTRACEF("target 0x%x, gic_ipi %u\n", target, gic_ipi_num); + arm_gic_sgi(gic_ipi_num, ARM_GIC_SGI_FLAG_NS, target); + } +#endif + + return NO_ERROR; +} + +enum handler_return arm_ipi_generic_handler(void *arg) +{ + LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg); + + return mp_mbx_generic_irq(); +} + +enum handler_return arm_ipi_reschedule_handler(void *arg) +{ + LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg); + + return mp_mbx_reschedule_irq(); +} + +void arch_mp_init_percpu(void) +{ + register_int_handler(MP_IPI_GENERIC + GIC_IPI_BASE, &arm_ipi_generic_handler, 0); + register_int_handler(MP_IPI_RESCHEDULE + GIC_IPI_BASE, &arm_ipi_reschedule_handler, 0); + + mp_set_curr_cpu_online(true); + + //unmask_interrupt(MP_IPI_GENERIC); + //unmask_interrupt(MP_IPI_RESCHEDULE); +} + diff --git a/kernel/arch/arm64/rules.mk b/kernel/arch/arm64/rules.mk new file mode 100644 index 000000000..31629de24 --- /dev/null +++ b/kernel/arch/arm64/rules.mk @@ -0,0 +1,159 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +# set some options based on the core +ifeq ($(ARM_CPU),cortex-a53) +ARCH_COMPILEFLAGS += -mcpu=$(ARM_CPU) +else +$(error $(LOCAL_DIR)/rules.mk doesnt have logic for arm core $(ARM_CPU)) +endif + +GLOBAL_DEFINES += \ + ARM64_CPU_$(ARM_CPU)=1 \ + ARM_ISA_ARMV8=1 \ + ARM_ISA_ARMV8A=1 \ + IS_64BIT=1 + +MODULE_SRCS += \ + $(LOCAL_DIR)/arch.c \ + $(LOCAL_DIR)/asm.S \ + $(LOCAL_DIR)/cache-ops.S \ + $(LOCAL_DIR)/exceptions.S \ + $(LOCAL_DIR)/exceptions_c.c \ + $(LOCAL_DIR)/fpu.c \ + $(LOCAL_DIR)/spinlock.S \ + $(LOCAL_DIR)/start.S \ + $(LOCAL_DIR)/thread.c \ + $(LOCAL_DIR)/user_copy.S \ + $(LOCAL_DIR)/user_copy_c.c \ + $(LOCAL_DIR)/uspace_entry.S + +GLOBAL_DEFINES += \ + ARCH_DEFAULT_STACK_SIZE=4096 + +# if its requested we build with SMP, arm generically supports 4 cpus +ifeq ($(WITH_SMP),1) +SMP_MAX_CPUS ?= 4 +SMP_CPU_CLUSTER_SHIFT ?= 8 +SMP_CPU_ID_BITS ?= 24 # Ignore aff3 bits for now since they are not next to aff2 + +GLOBAL_DEFINES += \ + WITH_SMP=1 \ + SMP_MAX_CPUS=$(SMP_MAX_CPUS) \ + SMP_CPU_CLUSTER_SHIFT=$(SMP_CPU_CLUSTER_SHIFT) \ + SMP_CPU_ID_BITS=$(SMP_CPU_ID_BITS) + +MODULE_SRCS += \ + $(LOCAL_DIR)/mp.c +else +GLOBAL_DEFINES += \ + SMP_MAX_CPUS=1 +endif + +ARCH_OPTFLAGS := -O2 +WITH_LINKER_GC ?= 1 + +# we have a mmu and want the vmm/pmm +WITH_KERNEL_VM ?= 1 + +ifeq ($(WITH_KERNEL_VM),1) + +MODULE_SRCS += \ + $(LOCAL_DIR)/mmu.c + +KERNEL_ASPACE_BASE ?= 0xffff000000000000 +KERNEL_ASPACE_SIZE ?= 0x0001000000000000 +USER_ASPACE_BASE ?= 0x0000000001000000 +USER_ASPACE_SIZE ?= 0x0000fffffe000000 + +GLOBAL_DEFINES += \ + KERNEL_ASPACE_BASE=$(KERNEL_ASPACE_BASE) \ + KERNEL_ASPACE_SIZE=$(KERNEL_ASPACE_SIZE) \ + USER_ASPACE_BASE=$(USER_ASPACE_BASE) \ + USER_ASPACE_SIZE=$(USER_ASPACE_SIZE) + +KERNEL_BASE ?= $(KERNEL_ASPACE_BASE) +KERNEL_LOAD_OFFSET ?= 0 + +GLOBAL_DEFINES += \ + KERNEL_BASE=$(KERNEL_BASE) \ + KERNEL_LOAD_OFFSET=$(KERNEL_LOAD_OFFSET) + +else + +KERNEL_BASE ?= $(MEMBASE) +KERNEL_LOAD_OFFSET ?= 0 + +endif + +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) + +# try to find the toolchain +include $(LOCAL_DIR)/toolchain.mk +TOOLCHAIN_PREFIX := $(ARCH_$(ARCH)_TOOLCHAIN_PREFIX) +$(info TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX)) + +ARCH_COMPILEFLAGS += $(ARCH_$(ARCH)_COMPILEFLAGS) + +# user space linker script +USER_LINKER_SCRIPT := $(LOCAL_DIR)/user.ld + +ifeq ($(CLANG),1) +GLOBAL_LDFLAGS = -m aarch64elf +GLOBAL_MODULE_LDFLAGS= -m aarch64elf +endif +GLOBAL_LDFLAGS += -z max-page-size=4096 + +# kernel hard disables floating point +KERNEL_COMPILEFLAGS += -mgeneral-regs-only -DWITH_NO_FP=1 + +ifeq ($(CLANG),1) +GLOBAL_COMPILEFLAGS += -target aarch64-elf -integrated-as +endif + +ifeq ($(CLANG),1) +ifeq ($(LIBGCC),) +$(error cannot find runtime library, please set LIBGCC) +endif +else +# figure out which libgcc we need based on our compile flags +LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) -print-libgcc-file-name) +endif + +# make sure some bits were set up +MEMVARS_SET := 0 +ifneq ($(MEMBASE),) +MEMVARS_SET := 1 +endif +ifneq ($(MEMSIZE),) +MEMVARS_SET := 1 +endif +ifeq ($(MEMVARS_SET),0) +$(error missing MEMBASE or MEMSIZE variable, please set in target rules.mk) +endif + +# potentially generated files that should be cleaned out with clean make rule +GENERATED += \ + $(BUILDDIR)/system-onesegment.ld + +# rules for generating the linker script +$(BUILDDIR)/system-onesegment.ld: $(LOCAL_DIR)/system-onesegment.ld $(wildcard arch/*.ld) linkerscript.phony + @echo generating $@ + @$(MKDIR) + $(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/" < $< > $@.tmp + @$(call TESTANDREPLACEFILE,$@.tmp,$@) + +linkerscript.phony: +.PHONY: linkerscript.phony + +include make/module.mk diff --git a/kernel/arch/arm64/spinlock.S b/kernel/arch/arm64/spinlock.S new file mode 100644 index 000000000..2238d9ff2 --- /dev/null +++ b/kernel/arch/arm64/spinlock.S @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Google Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +.text + +FUNCTION(arch_spin_trylock) + mov x2, x0 + mov x1, #1 + ldaxr x0, [x2] + cbnz x0, 1f + stxr w0, x1, [x2] +1: + ret + +FUNCTION(arch_spin_lock) + mov x1, #1 + sevl +1: + wfe + ldaxr x2, [x0] + cbnz x2, 1b + stxr w2, x1, [x0] + cbnz w2, 1b + ret + +FUNCTION(arch_spin_unlock) + stlr xzr, [x0] + ret diff --git a/kernel/arch/arm64/start.S b/kernel/arch/arm64/start.S new file mode 100644 index 000000000..bfedb3540 --- /dev/null +++ b/kernel/arch/arm64/start.S @@ -0,0 +1,375 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +/* + * Register use: + * x0-x3 Arguments + * x9-x15 Scratch + * x19-x28 Globals + */ +tmp .req x9 +tmp2 .req x10 +wtmp2 .req w10 +index .req x11 +index_shift .req x12 +page_table .req x13 +new_page_table .req x14 +phys_offset .req x15 + +cpuid .req x19 +page_table0 .req x20 +page_table1 .req x21 +mmu_initial_mapping .req x22 +vaddr .req x23 +paddr .req x24 +mapping_size .req x25 +size .req x26 +attr .req x27 + +.section .text.boot +FUNCTION(_start) +#if WITH_KERNEL_VM + /* enable caches so atomics and spinlocks work */ + mrs tmp, sctlr_el1 + orr tmp, tmp, #(1<<12) /* Enable icache */ + orr tmp, tmp, #(1<<2) /* Enable dcache/ucache */ + bic tmp, tmp, #(1<<3) /* Disable Stack Alignment Check */ /* TODO: don't use unaligned stacks */ + msr sctlr_el1, tmp + + /* set up the mmu according to mmu_initial_mappings */ + + /* load the base of the translation table and clear the table */ + adrp page_table1, arm64_kernel_translation_table + add page_table1, page_table1, #:lo12:arm64_kernel_translation_table + + /* Prepare tt_trampoline page table */ + /* Calculate pagetable physical addresses */ + adrp page_table0, tt_trampoline + add page_table0, page_table0, #:lo12:tt_trampoline + +#if WITH_SMP + mrs cpuid, mpidr_el1 + ubfx cpuid, cpuid, #0, #SMP_CPU_ID_BITS + cbnz cpuid, .Lmmu_enable_secondary +#endif + + mov tmp, #0 + + /* walk through all the entries in the translation table, setting them up */ +.Lclear_top_page_table_loop: + str xzr, [page_table1, tmp, lsl #3] + add tmp, tmp, #1 + cmp tmp, #MMU_KERNEL_PAGE_TABLE_ENTRIES_TOP + bne .Lclear_top_page_table_loop + + /* load the address of the mmu_initial_mappings table and start processing */ + adrp mmu_initial_mapping, mmu_initial_mappings + add mmu_initial_mapping, mmu_initial_mapping, #:lo12:mmu_initial_mappings + +.Linitial_mapping_loop: + ldp paddr, vaddr, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_PHYS_OFFSET] + ldp size, tmp, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_SIZE_OFFSET] + + tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_DYNAMIC, .Lnot_dynamic + adr paddr, _start + mov size, x0 + str paddr, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_PHYS_OFFSET] + str size, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_SIZE_OFFSET] + +.Lnot_dynamic: + /* if size == 0, end of list */ + cbz size, .Linitial_mapping_done + mov mapping_size, size + + /* set up the flags */ + tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_UNCACHED, .Lnot_uncached + ldr attr, =MMU_INITIAL_MAP_STRONGLY_ORDERED + b .Lmem_type_done +.Lnot_uncached: + tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_DEVICE, .Lnot_device + ldr attr, =MMU_INITIAL_MAP_DEVICE + b .Lmem_type_done +.Lnot_device: + +.Lmapping_size_loop: + ldr attr, =MMU_PTE_KERNEL_RO_FLAGS + ldr tmp, =__rodata_start + subs size, tmp, vaddr + b.hi .Lmem_type_done + orr attr, attr, #MMU_PTE_ATTR_PXN + ldr tmp, =__data_start + subs size, tmp, vaddr + b.hi .Lmem_type_done + ldr attr, =MMU_PTE_KERNEL_DATA_FLAGS + ldr tmp, =_end + subs size, tmp, vaddr + b.lo . /* Error: _end < vaddr */ + cmp mapping_size, size + b.lo . /* Error: mapping_size < size => RAM size too small for data/bss */ + mov size, mapping_size + +.Lmem_type_done: + subs mapping_size, mapping_size, size + b.lo . /* Error: mapping_size < size (RAM size too small for code/rodata?) */ + + /* Check that paddr, vaddr and size are page aligned */ + orr tmp, vaddr, paddr + orr tmp, tmp, size + tst tmp, #(1 << MMU_KERNEL_PAGE_SIZE_SHIFT) - 1 + bne . /* Error: not page aligned */ + + /* Clear top bits of virtual address (should be all set) */ + eor vaddr, vaddr, #(~0 << MMU_KERNEL_SIZE_SHIFT) + + /* Check that top bits were all set */ + tst vaddr, #(~0 << MMU_KERNEL_SIZE_SHIFT) + bne . /* Error: vaddr out of range */ + +.Lmap_range_top_loop: + /* Select top level page table */ + mov page_table, page_table1 + mov index_shift, #MMU_KERNEL_TOP_SHIFT + + lsr index, vaddr, index_shift + +.Lmap_range_one_table_loop: + /* Check if current level allow block descriptors */ + cmp index_shift, #MMU_PTE_DESCRIPTOR_BLOCK_MAX_SHIFT + b.hi .Lmap_range_need_page_table + + /* Check if paddr and vaddr alignment allows a block descriptor */ + orr tmp2, vaddr, paddr + lsr tmp, tmp2, index_shift + lsl tmp, tmp, index_shift + cmp tmp, tmp2 + b.ne .Lmap_range_need_page_table + + /* Check if size is large enough for a block mapping */ + lsr tmp, size, index_shift + cbz tmp, .Lmap_range_need_page_table + + /* Select descriptor type, page for level 3, block for level 0-2 */ + orr tmp, attr, #MMU_PTE_L3_DESCRIPTOR_PAGE + cmp index_shift, MMU_KERNEL_PAGE_SIZE_SHIFT + beq .Lmap_range_l3 + orr tmp, attr, #MMU_PTE_L012_DESCRIPTOR_BLOCK +.Lmap_range_l3: + + /* Write page table entry */ + orr tmp, tmp, paddr + str tmp, [page_table, index, lsl #3] + + /* Move to next page table entry */ + mov tmp, #1 + lsl tmp, tmp, index_shift + add vaddr, vaddr, tmp + add paddr, paddr, tmp + subs size, size, tmp + /* TODO: add local loop if next entry is in the same page table */ + b.ne .Lmap_range_top_loop /* size != 0 */ + + /* Restore top bits of virtual address (should be all set) */ + eor vaddr, vaddr, #(~0 << MMU_KERNEL_SIZE_SHIFT) + /* Move to next subtype of ram mmu_initial_mappings entry */ + cbnz mapping_size, .Lmapping_size_loop + + /* Move to next mmu_initial_mappings entry */ + add mmu_initial_mapping, mmu_initial_mapping, __MMU_INITIAL_MAPPING_SIZE + b .Linitial_mapping_loop + +.Lmap_range_need_page_table: + /* Check if page table entry is unused */ + ldr new_page_table, [page_table, index, lsl #3] + cbnz new_page_table, .Lmap_range_has_page_table + + /* Calculate phys offset (needed for memory allocation) */ +.Lphys_offset: + adr phys_offset, .Lphys_offset /* phys */ + ldr tmp, =.Lphys_offset /* virt */ + sub phys_offset, tmp, phys_offset + + /* Allocate new page table */ + calloc_bootmem_aligned new_page_table, tmp, tmp2, MMU_KERNEL_PAGE_SIZE_SHIFT, phys_offset + + /* Write page table entry (with allocated page table) */ + orr new_page_table, new_page_table, #MMU_PTE_L012_DESCRIPTOR_TABLE + str new_page_table, [page_table, index, lsl #3] + +.Lmap_range_has_page_table: + /* Check descriptor type */ + and tmp, new_page_table, #MMU_PTE_DESCRIPTOR_MASK + cmp tmp, #MMU_PTE_L012_DESCRIPTOR_TABLE + b.ne . /* Error: entry already in use (as a block entry) */ + + /* switch to next page table level */ + bic page_table, new_page_table, #MMU_PTE_DESCRIPTOR_MASK + mov tmp, #~0 + lsl tmp, tmp, index_shift + bic tmp, vaddr, tmp + sub index_shift, index_shift, #(MMU_KERNEL_PAGE_SIZE_SHIFT - 3) + lsr index, tmp, index_shift + + b .Lmap_range_one_table_loop + +.Linitial_mapping_done: + + /* Prepare tt_trampoline page table */ + + /* Zero tt_trampoline translation tables */ + mov tmp, #0 +.Lclear_tt_trampoline: + str xzr, [page_table0, tmp, lsl#3] + add tmp, tmp, #1 + cmp tmp, #MMU_PAGE_TABLE_ENTRIES_IDENT + blt .Lclear_tt_trampoline + + /* Setup mapping at phys -> phys */ + adr tmp, .Lmmu_on_pc + lsr tmp, tmp, #MMU_IDENT_TOP_SHIFT /* tmp = paddr index */ + ldr tmp2, =MMU_PTE_IDENT_FLAGS + add tmp2, tmp2, tmp, lsl #MMU_IDENT_TOP_SHIFT /* tmp2 = pt entry */ + + str tmp2, [page_table0, tmp, lsl #3] /* tt_trampoline[paddr index] = pt entry */ + +#if WITH_SMP + adr tmp, page_tables_not_ready + str wzr, [tmp] + b .Lpage_tables_ready + +.Lmmu_enable_secondary: + adr tmp, page_tables_not_ready +.Lpage_tables_not_ready: + ldr wtmp2, [tmp] + cbnz wtmp2, .Lpage_tables_not_ready +.Lpage_tables_ready: +#endif + + /* set up the mmu */ + + /* Invalidate TLB */ + tlbi vmalle1is + isb + dsb sy + + /* Initialize Memory Attribute Indirection Register */ + ldr tmp, =MMU_MAIR_VAL + msr mair_el1, tmp + + /* Initialize TCR_EL1 */ + /* set cacheable attributes on translation walk */ + /* (SMP extensions) non-shareable, inner write-back write-allocate */ + ldr tmp, =MMU_TCR_FLAGS_IDENT + msr tcr_el1, tmp + + isb + + /* Write ttbr with phys addr of the translation table */ + msr ttbr0_el1, page_table0 + msr ttbr1_el1, page_table1 + isb + + /* Read SCTLR */ + mrs tmp, sctlr_el1 + + /* Turn on the MMU */ + orr tmp, tmp, #0x1 + + /* Write back SCTLR */ + msr sctlr_el1, tmp +.Lmmu_on_pc: + isb + + /* Jump to virtual code address */ + ldr tmp, =.Lmmu_on_vaddr + br tmp + +.Lmmu_on_vaddr: + + /* Disable trampoline page-table in ttbr0 */ + ldr tmp, =MMU_TCR_FLAGS_KERNEL + msr tcr_el1, tmp + isb + + + /* Invalidate TLB */ + tlbi vmalle1 + isb + +#if WITH_SMP + cbnz cpuid, .Lsecondary_boot +#endif +#endif /* WITH_KERNEL_VM */ + + ldr tmp, =__stack_end + mov sp, tmp + + /* clear bss */ +.L__do_bss: + /* clear out the bss excluding the stack and kernel translation table */ + /* NOTE: relies on __post_prebss_bss_start and __bss_end being 8 byte aligned */ + ldr tmp, =__post_prebss_bss_start + ldr tmp2, =__bss_end + sub tmp2, tmp2, tmp + cbz tmp2, .L__bss_loop_done +.L__bss_loop: + sub tmp2, tmp2, #8 + str xzr, [tmp], #8 + cbnz tmp2, .L__bss_loop +.L__bss_loop_done: + + bl lk_main + b . + +#if WITH_SMP +.Lsecondary_boot: + and tmp, cpuid, #0xff + cmp tmp, #(1 << SMP_CPU_CLUSTER_SHIFT) + bge .Lunsupported_cpu_trap + bic cpuid, cpuid, #0xff + orr cpuid, tmp, cpuid, LSR #(8 - SMP_CPU_CLUSTER_SHIFT) + + cmp cpuid, #SMP_MAX_CPUS + bge .Lunsupported_cpu_trap + + /* Set up the stack */ + ldr tmp, =__stack_end + mov tmp2, #ARCH_DEFAULT_STACK_SIZE + mul tmp2, tmp2, cpuid + sub sp, tmp, tmp2 + + mov x0, cpuid + bl arm64_secondary_entry + +.Lunsupported_cpu_trap: + wfe + b .Lunsupported_cpu_trap +#endif + +.ltorg + +#if WITH_SMP +.data +DATA(page_tables_not_ready) + .long 1 +#endif + +.section .bss.prebss.stack + .align 4 +DATA(__stack) + .skip ARCH_DEFAULT_STACK_SIZE * SMP_MAX_CPUS +DATA(__stack_end) + +#if WITH_KERNEL_VM +.section ".bss.prebss.translation_table" +.align 3 + MMU_PAGE_TABLE_ENTRIES_IDENT_SHIFT +DATA(tt_trampoline) + .skip 8 * MMU_PAGE_TABLE_ENTRIES_IDENT +#endif diff --git a/kernel/arch/arm64/system-onesegment.ld b/kernel/arch/arm64/system-onesegment.ld new file mode 100644 index 000000000..c550737f8 --- /dev/null +++ b/kernel/arch/arm64/system-onesegment.ld @@ -0,0 +1,132 @@ +/* +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) + +ENTRY(_start) +SECTIONS +{ + . = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%; + + /* text/read-only data */ + /* set the load address to physical MEMBASE */ + .text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) { + __code_start = .; + KEEP(*(.text.boot)) + KEEP(*(.text.boot.vectab)) + *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) + } + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + + .dummy_post_text : { + __code_end = .; + } + + .rodata : ALIGN(4096) { + __rodata_start = .; + __fault_handler_table_start = .; + KEEP(*(.rodata.fault_handler_table)) + __fault_handler_table_end = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* + * extra linker scripts tend to insert sections just after .rodata, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_rodata : { + __rodata_end = .; + } + + .data : ALIGN(4096) { + /* writable data */ + __data_start_rom = .; + /* in one segment binaries, the rom data address is on top of the ram data address */ + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.bootfs) + } + + .ctors : ALIGN(8) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(8) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* + * extra linker scripts tend to insert sections just after .data, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_data : { + __data_end = .; + } + + /* unintialized data (in same segment as writable data) */ + .bss : ALIGN(4096) { + __bss_start = .; + KEEP(*(.bss.prebss.*)) + . = ALIGN(8); + __post_prebss_bss_start = .; + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + __bss_end = .; + } + + /* Align the end to ensure anything after the kernel ends up on its own pages */ + . = ALIGN(4096); + _end = .; + + . = %KERNEL_BASE% + %MEMSIZE%; + _end_of_ram = .; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/arm64/thread.c b/kernel/arch/arm64/thread.c new file mode 100644 index 000000000..1b3937dbb --- /dev/null +++ b/kernel/arch/arm64/thread.c @@ -0,0 +1,76 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct context_switch_frame { + vaddr_t lr; + vaddr_t tpidr_el0; + vaddr_t tpidrro_el0; + vaddr_t r18; + vaddr_t r19; + vaddr_t r20; + vaddr_t r21; + vaddr_t r22; + vaddr_t r23; + vaddr_t r24; + vaddr_t r25; + vaddr_t r26; + vaddr_t r27; + vaddr_t r28; + vaddr_t r29; +}; + +extern void arm64_context_switch(addr_t *old_sp, addr_t new_sp); + +void arch_thread_initialize(thread_t *t, vaddr_t entry_point) +{ + // create a default stack frame on the stack + vaddr_t stack_top = (vaddr_t)t->stack + t->stack_size; + + // make sure the top of the stack is 16 byte aligned for EABI compliance + stack_top = ROUNDDOWN(stack_top, 16); + + struct context_switch_frame *frame = (struct context_switch_frame *)(stack_top); + frame--; + + // fill it in + memset(frame, 0, sizeof(*frame)); + frame->lr = entry_point; + + // set the stack pointer + t->arch.sp = (vaddr_t)frame; + + // zero out the fpu state + memset(&t->arch.fpstate, 0, sizeof(t->arch.fpstate)); +} + +void arch_context_switch(thread_t *oldthread, thread_t *newthread) +{ + LTRACEF("old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name); +#if WITH_SMP + DSB; /* broadcast tlb operations in case the thread moves to another cpu */ +#endif + arm64_fpu_context_switch(oldthread, newthread); + arm64_context_switch(&oldthread->arch.sp, newthread->arch.sp); +} + +void arch_dump_thread(thread_t *t) +{ + if (t->state != THREAD_RUNNING) { + dprintf(INFO, "\tarch: "); + dprintf(INFO, "sp 0x%lx\n", t->arch.sp); + } +} diff --git a/kernel/arch/arm64/toolchain.mk b/kernel/arch/arm64/toolchain.mk new file mode 100644 index 000000000..165e73e58 --- /dev/null +++ b/kernel/arch/arm64/toolchain.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +ifndef ARCH_arm64_TOOLCHAIN_INCLUDED +ARCH_arm64_TOOLCHAIN_INCLUDED := 1 + +ifndef ARCH_arm64_TOOLCHAIN_PREFIX +ARCH_arm64_TOOLCHAIN_PREFIX := aarch64-elf- +ifeq ($(CLANG),1) +FOUNDTOOL=$(shell which $(ARCH_arm64_TOOLCHAIN_PREFIX)clang) +else +FOUNDTOOL=$(shell which $(ARCH_arm64_TOOLCHAIN_PREFIX)gcc) +endif +ifeq ($(FOUNDTOOL),) +ARCH_arm64_TOOLCHAIN_PREFIX := aarch64-linux-android- +FOUNDTOOL=$(shell which $(ARCH_arm64_TOOLCHAIN_PREFIX)gcc) +ifeq ($(FOUNDTOOL),) +$(error cannot find toolchain, please set ARCH_arm64_TOOLCHAIN_PREFIX or add it to your path) +endif +endif +endif + +#ARCH_arm64_COMPILEFLAGS := -mgeneral-regs-only -DWITH_NO_FP=1 + +endif diff --git a/kernel/arch/arm64/user.ld b/kernel/arch/arm64/user.ld new file mode 100644 index 000000000..cf4f8b2df --- /dev/null +++ b/kernel/arch/arm64/user.ld @@ -0,0 +1,99 @@ +/* +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) + +ENTRY(_start) +SECTIONS +{ + . = 0x01000000; /* base of user space */ + + /* bump forward so the load offset and file offset are 1:1 */ + . += SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { + *(.crt) + *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) + } + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ifunc) + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + + .rodata : ALIGN(8) { + __rodata_start = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + __rodata_end = .; + } + + .data : ALIGN(4096) { + /* writable data */ + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + } + + .ctors : ALIGN(8) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(8) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + .got : { *(.got.plt) *(.got) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + + __data_end = .; + + /* unintialized data (in same segment as writable data) */ + .bss : ALIGN(8) { + __bss_start = .; + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; + } + + _end = .; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/arm64/user_copy.S b/kernel/arch/arm64/user_copy.S new file mode 100644 index 000000000..3f3e7c05f --- /dev/null +++ b/kernel/arch/arm64/user_copy.S @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +# We do not need to check whether the addresses are in the +# kernel or virtual address spaces, sine we only access them +# using EL0 privileges. + +# status_t _arm64_copy_from_user(void *dst, const void *src, size_t len, void **fault_return) +FUNCTION(_arm64_copy_from_user) + # Setup data fault return + adr x4, .Lfault_from_user + str x4, [x3] + + # Perform the memcpy + cbz x2, 0f +.Lcopy_byte_from_user: + ldtrb w4, [x1] + strb w4, [x0] + add x0, x0, #1 + add x1, x1, #1 + sub x2, x2, #1 + cbnz x2, .Lcopy_byte_from_user +0: + + mov x0, #NO_ERROR + b .Lcleanup_from_user +.Lfault_from_user: + mov x0, #ERR_INVALID_ARGS +.Lcleanup_from_user: + # Reset data fault return + str xzr, [x3] + ret + +# status_t _arm64_copy_to_user(void *dst, const void *src, size_t len, void **fault_return) +FUNCTION(_arm64_copy_to_user) + # Setup data fault return + adr x4, .Lfault_to_user + str x4, [x3] + + # Perform the memcpy + cbz x2, 0f +.Lcopy_byte_to_user: + ldrb w4, [x1] + sttrb w4, [x0] + add x0, x0, #1 + add x1, x1, #1 + sub x2, x2, #1 + cbnz x2, .Lcopy_byte_to_user +0: + + mov x0, #NO_ERROR + b .Lcleanup_to_user +.Lfault_to_user: + mov x0, #ERR_INVALID_ARGS +.Lcleanup_to_user: + # Reset data fault return + str xzr, [x3] + ret diff --git a/kernel/arch/arm64/user_copy_c.c b/kernel/arch/arm64/user_copy_c.c new file mode 100644 index 000000000..ca13cd65a --- /dev/null +++ b/kernel/arch/arm64/user_copy_c.c @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +status_t arch_copy_from_user(void *dst, const void *src, size_t len) +{ + thread_t *thr = get_current_thread(); + status_t status = + _arm64_copy_from_user(dst, src, len, &thr->arch.data_fault_resume); + return status; +} + +status_t arch_copy_to_user(void *dst, const void *src, size_t len) +{ + thread_t *thr = get_current_thread(); + status_t status = + _arm64_copy_to_user(dst, src, len, &thr->arch.data_fault_resume); + return status; +} diff --git a/kernel/arch/arm64/uspace_entry.S b/kernel/arch/arm64/uspace_entry.S new file mode 100644 index 000000000..f01c5b442 --- /dev/null +++ b/kernel/arch/arm64/uspace_entry.S @@ -0,0 +1,49 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +// void arm64_uspace_entry(vaddr_t kstack, vaddr_t ustack, vaddr_t entry_point, uint32_t spsr, void *thread_arg) __NO_RETURN; +FUNCTION(arm64_uspace_entry) + mov sp, x0 + msr sp_el0, x1 + msr elr_el1, x2 + msr spsr_el1, x3 + mov x0, x4 + + mov x1, xzr + mov x2, xzr + mov x3, xzr + mov x4, xzr + mov x5, xzr + mov x6, xzr + mov x7, xzr + mov x8, xzr + mov x9, xzr + mov x10, xzr + mov x11, xzr + mov x12, xzr + mov x13, xzr + mov x14, xzr + mov x15, xzr + mov x16, xzr + mov x17, xzr + mov x18, xzr + mov x19, xzr + mov x20, xzr + mov x21, xzr + mov x22, xzr + mov x23, xzr + mov x24, xzr + mov x25, xzr + mov x26, xzr + mov x27, xzr + mov x28, xzr + mov x29, xzr + mov x30, xzr + + // Lazy loading of the FPU means we don't need to zero the simd registers + eret diff --git a/kernel/arch/x86/32/asm.S b/kernel/arch/x86/32/asm.S new file mode 100644 index 000000000..321f69c8f --- /dev/null +++ b/kernel/arch/x86/32/asm.S @@ -0,0 +1,9 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + diff --git a/kernel/arch/x86/32/exceptions.S b/kernel/arch/x86/32/exceptions.S new file mode 100644 index 000000000..b4f4ca0dd --- /dev/null +++ b/kernel/arch/x86/32/exceptions.S @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#define NUM_INT 256 + +/* + * Please not that the macro for generating interrupt routine stubs relies + * on macro execution counter which is shared by all invocation across this + * compilation unit. Be careful when adding additional macros to this file. + */ + +.text + +/* interrupt service routine stubs */ +_isr: +.macro def_isr +.pushsection .text +FUNCTION(_isr_\@) + /* Clear the AC flag to prevent ring 0 from performing data accesses to + * ring 3 if SMAP is available. If it was set, it will get restored by + * iretd. DO NOT REMOVE THIS CLAC, code in idt.c assumes it is here. + * It MUST be the first instruction of this function. */ + clac +.if \@ == 8 || (\@ >= 10 && \@ <= 14) || \@ == 17 + /* error code pushed by exception */ + pushl $\@ /* interrupt number */ + jmp interrupt_common +.else + pushl $0 /* fill in error code in iframe */ + pushl $\@ /* interrupt number */ + jmp interrupt_common +.endif +.popsection +.pushsection .data +.long _isr_\@ +.popsection +.endm + +.pushsection .data +/* build a table of isr entry points */ +DATA(_isr_table) +.popsection +.rept NUM_INT +def_isr +.endr + +FUNCTION(interrupt_common) + pushl %gs /* save segment registers */ + pushl %fs + pushl %es + pushl %ds + pusha /* save general purpose registers */ + movl $DATA_SELECTOR, %eax /* put known good value in segment registers */ + movl %eax, %gs + movl %eax, %fs + movl %eax, %es + movl %eax, %ds + + movl %esp, %eax /* store pointer to iframe */ + pushl %eax + + call x86_exception_handler + + popl %eax /* drop pointer to iframe */ + + popa /* restore general purpose registers */ + popl %ds /* restore segment registers */ + popl %es + popl %fs + popl %gs + addl $8, %esp /* drop exception number and error code */ + iret diff --git a/kernel/arch/x86/32/kernel.ld b/kernel/arch/x86/32/kernel.ld new file mode 100644 index 000000000..7e4914076 --- /dev/null +++ b/kernel/arch/x86/32/kernel.ld @@ -0,0 +1,94 @@ +/* +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2013 Travis Geiselbrecht +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + + +ENTRY(_protected_start) +SECTIONS +{ + . = %MEMBASE% + %HEADER_LOAD_OFFSET%; + + .text.header : AT (%MEMBASE% + %KERNEL_LOAD_OFFSET% - %PHYS_HEADER_LOAD_OFFSET%) { + KEEP(*(.text.header)) + } + + . = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%; + _start = .; + + .text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) { + __code_start = .; + KEEP(*(.text.boot)) + *(.text* .sram.text) + *(.gnu.linkonce.t.*) + __code_end = .; + } =0x9090 + + .rodata : ALIGN(4096) { + __rodata_start = .; + *(.rodata*) + *(.gnu.linkonce.r.*) + . = ALIGN(4); + } + + /* + * extra linker scripts tend to insert sections just after .rodata, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_rodata : { + __rodata_end = .; + } + + .data : ALIGN(4096) { + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + } + + .ctors : ALIGN(4) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(4) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + + /* + * extra linker scripts tend to insert sections just after .data, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_data : { + __data_end = .; + } + + _zero_page_sys_size = (__data_end - __code_start + 15) / 16; + + .bss : ALIGN(4096) { + __bss_start = .; + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } + + /* Align the end to ensure anything after the kernel ends up on its own pages */ + . = ALIGN(4096); + _end = .; + + /* put a symbol arbitrarily 4MB past the end of the kernel */ + /* used by the heap and other early boot time allocators */ + _end_of_ram = . + (4*1024*1024); + + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/x86/32/ops.S b/kernel/arch/x86/32/ops.S new file mode 100644 index 000000000..a65bdd80a --- /dev/null +++ b/kernel/arch/x86/32/ops.S @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +.text + +/* void arch_idle(); */ +FUNCTION(arch_idle) + pushf + popl %eax + andl $0x200, %eax + test %eax, %eax + je 1f /* don't halt if local interrupts are disabled */ + hlt +1: + ret + diff --git a/kernel/arch/x86/32/start.S b/kernel/arch/x86/32/start.S new file mode 100644 index 000000000..2b64471db --- /dev/null +++ b/kernel/arch/x86/32/start.S @@ -0,0 +1,162 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +.section ".text.boot" +.code32 + +FUNCTION(_protected_start) + /* attempt to detect if %esi points to a zero page structure */ + cmp $0, %esi + je .Lcommon_boot + cmpl $0x53726448, 0x202(%esi) + jne .Lcommon_boot + mov %esi, PHYS(_zero_page_boot_params) + jmp .Lcommon_boot + +FUNCTION(_multiboot_start) + cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax + jne .Lcommon_boot + movl %ebx, PHYS(_multiboot_info) + +.Lcommon_boot: + /* load our new gdt by physical pointer */ + lgdt PHYS(_gdtr_phys) + + movw $DATA_SELECTOR, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %ss + movw %ax, %gs + movw %ax, %ss + + /*We jumped here in protected mode in a code segment that migh not longer + be valid , do a long jump to our code segment, we use lret instead of + ljmp to be able to use relative labels */ + pushl $CODE_SELECTOR /*Pushing our code segment */ + pushl $PHYS(.Lfarjump) /*and jump address */ + lret /*This instruction will jump to codesel:farjump */ + +.Lfarjump: + /* zero the bss section */ + bss_setup + +paging_setup: +#ifdef PAE_MODE_ENABLED +#error broken for now + /* Preparing PAE paging, we will use 2MB pages covering 1GB + for initial bootstrap, this page table will be 1 to 1 */ + + /* Setting the First PDPTE with a PD table reference*/ + movl $pd, %eax + orl $0x01, %eax + movl %eax, (pdp) + + movl $pd, %esi + movl $0x1ff, %ecx + +fill_pd: + movl $0x1ff, %eax + subl %ecx, %eax + shll $21,%eax + orl $0x83, %eax + movl %eax, (%esi) + addl $8,%esi + loop fill_pd + + /* Set PDPT in CR3 */ + movl $pdp, %eax + mov %eax, %cr3 + + /* Enabling PAE*/ + mov %cr4, %eax + btsl $(5), %eax + mov %eax, %cr4 + + /* Enabling Paging and from this point we are in + 32 bit compatibility mode */ + mov %cr0, %eax + btsl $(31), %eax + mov %eax, %cr0 + +#else + /* map the first 1GB 1:1 */ + movl $PHYS(pd), %esi + movl $0x100, %ecx + xor %eax, %eax + +.Lfill_pd: + mov %eax, %edx + orl $X86_KERNEL_PD_LP_FLAGS, %edx + movl %edx, (%esi) + addl $4, %esi + addl $0x00400000, %eax + loop .Lfill_pd + + /* map the first 1GB to KERNEL_ASPACE_BASE */ + movl $(PHYS(pd) + 0x800), %esi + movl $0x100, %ecx + xor %eax, %eax + +.Lfill_pd2: + mov %eax, %edx + orl $X86_KERNEL_PD_LP_FLAGS, %edx + movl %edx, (%esi) + addl $4, %esi + addl $0x00400000, %eax + loop .Lfill_pd2 + + /* Set PD in CR3 */ + movl $PHYS(pd), %eax + mov %eax, %cr3 + + /* Enabling Paging and from this point we are in */ + mov %cr4, %eax + orl $0x10, %eax + mov %eax, %cr4 + + mov %cr0, %eax + btsl $(31), %eax + mov %eax, %cr0 +#endif + + /* load the high kernel stack */ + movl $(_kstack + 4096), %esp + + /* reload the high gdtr */ + lgdt PHYS(_gdtr) + + /* branch to the high address */ + movl $main_lk, %eax + jmp *%eax + +main_lk: + /* set up the idt */ + push $_idt + call idt_setup + add $4, %esp + lidt _idtr + + /* set up the per cpu gs: pointer */ + call x86_init_percpu + + /* call the main module */ + call lk_main +0: /* just sit around waiting for interrupts */ + hlt /* interrupts will unhalt the processor */ + pause + jmp 0b /* so jump back to halt to conserve power */ diff --git a/kernel/arch/x86/64/asm.S b/kernel/arch/x86/64/asm.S new file mode 100644 index 000000000..b543c3bc8 --- /dev/null +++ b/kernel/arch/x86/64/asm.S @@ -0,0 +1,60 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +/* void x86_64_context_switch(uint64_t *oldsp, uint64_t newsp) */ +FUNCTION(x86_64_context_switch) + /* save the old context and restore the new */ + pushf + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + movq %rsp,(%rdi) + movq %rsi,%rsp + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + popf + + retq + +#if WITH_SMP +/* void arch_spin_lock(unsigned long *lock) */ +FUNCTION(arch_spin_lock) +.Lspin: + cmpq $0, (%rdi) + je .Ltake_lock + pause + jmp .Lspin +.Ltake_lock: + mov $1, %rax + xchg %rax, (%rdi) + cmp $0, %rax // make sure we actually got the lock + jne .Lspin // if we lost the race, resume waiting + ret + +/* int arch_spin_trylock(unsigned long *lock) */ +FUNCTION(arch_spin_trylock) + mov $1, %rax + xchg %rax, (%rdi) + ret // return 0 if we got the lock + +/* void arch_spin_unlock(spin_lock_t *lock) */ +FUNCTION(arch_spin_unlock) + mov $0, %rax + xchg %rax, (%rdi) + ret +#endif // WITH_SMP diff --git a/kernel/arch/x86/64/bootstrap16.c b/kernel/arch/x86/64/bootstrap16.c new file mode 100644 index 000000000..7567aa5e9 --- /dev/null +++ b/kernel/arch/x86/64/bootstrap16.c @@ -0,0 +1,136 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +status_t x86_bootstrap16_prep( + paddr_t bootstrap_phys_addr, + uintptr_t entry64, + vmm_aspace_t **temp_aspace, + void **bootstrap_aperature) +{ + // Make sure bootstrap region will be entirely in the first 1MB of physical + // memory + if (bootstrap_phys_addr > (1 << 20) - 2 * PAGE_SIZE) { + return ERR_INVALID_ARGS; + } + + // Make sure the entrypoint code is in the bootstrap code that will be + // loaded + if (entry64 < (uintptr_t)x86_bootstrap16_start || + entry64 >= (uintptr_t)x86_bootstrap16_end) { + return ERR_INVALID_ARGS; + } + + vmm_aspace_t *bootstrap_aspace; + vmm_aspace_t *kernel_aspace = vmm_get_kernel_aspace(); + void *bootstrap_virt_addr = NULL; + status_t status = vmm_create_aspace( + &bootstrap_aspace, + "bootstrap16", + VMM_ASPACE_TYPE_LOW_KERNEL); + if (status != NO_ERROR) { + return status; + } + + // GDTR referring to identity-mapped gdt + extern uint8_t _gdtr_phys; + // Actual GDT address, needed for computation below + extern uint8_t _gdt; + extern uint8_t _gdt_end; + + // Compute what needs to go into the mappings + paddr_t gdt_phys_page = + vaddr_to_paddr((void *)ROUNDDOWN((uintptr_t)&_gdt, PAGE_SIZE)); + uintptr_t gdt_region_len = + ROUNDUP((uintptr_t)&_gdt_end, PAGE_SIZE) - ROUNDDOWN((uintptr_t)&_gdt, PAGE_SIZE); + + // Temporary aspace needs 5 regions mapped: + struct map_range page_mappings[] = { + // 1) The bootstrap code page (identity mapped) + // 2) The bootstrap data page (identity mapped) + { .start_vaddr = bootstrap_phys_addr, .start_paddr = bootstrap_phys_addr, .size = 2 * PAGE_SIZE }, + // 3) The page containing the GDT (identity mapped) + { .start_vaddr = (vaddr_t)gdt_phys_page, .start_paddr = gdt_phys_page, .size = gdt_region_len }, + // These next two come implicitly from the shared kernel aspace: + // 4) The kernel's version of the bootstrap code page (matched mapping) + // 5) The page containing the aps_still_booting counter (matched mapping) + }; + for (unsigned int i = 0; i < countof(page_mappings); ++i) { + void *vaddr = (void *)page_mappings[i].start_vaddr; + status = vmm_alloc_physical( + bootstrap_aspace, + "bootstrap_mapping", + page_mappings[i].size, + &vaddr, + PAGE_SIZE_SHIFT, + page_mappings[i].start_paddr, + VMM_FLAG_VALLOC_SPECIFIC, + 0); + if (status != NO_ERROR) { + TRACEF("Failed to create wakeup bootstrap aspace\n"); + goto cleanup_aspace; + } + } + + // Map the AP bootstrap page and a low mem data page to configure + // the AP processors with + status = vmm_alloc_physical( + kernel_aspace, + "bootstrap16_aperture", + PAGE_SIZE * 2, // size + &bootstrap_virt_addr, // requested virtual address + PAGE_SIZE_SHIFT, // alignment log2 + bootstrap_phys_addr, // physical address + 0, // vmm flags + ARCH_MMU_FLAG_PERM_NO_EXECUTE); // arch mmu flags + if (status != NO_ERROR) { + TRACEF("could not allocate AP bootstrap page: %d\n", status); + goto cleanup_aspace; + } + DEBUG_ASSERT(bootstrap_virt_addr != NULL); + uintptr_t bootstrap_code_len = (uintptr_t)x86_bootstrap16_end - + (uintptr_t)x86_bootstrap16_start; + DEBUG_ASSERT(bootstrap_code_len <= PAGE_SIZE); + // Copy the bootstrap code in + memcpy(bootstrap_virt_addr, x86_bootstrap16_start, bootstrap_code_len); + + // Configuration data shared with the APs to get them to 64-bit mode + struct x86_bootstrap16_data *bootstrap_data = bootstrap_virt_addr + 0x1000; + + uint32_t long_mode_entry = bootstrap_phys_addr + + (entry64 - (uintptr_t)x86_bootstrap16_start); + + bootstrap_data->phys_bootstrap_pml4 = + vmm_get_arch_aspace(bootstrap_aspace)->pt_phys; + bootstrap_data->phys_kernel_pml4 = x86_get_cr3(); + memcpy(bootstrap_data->phys_gdtr, + &_gdtr_phys, + sizeof(bootstrap_data->phys_gdtr)); + bootstrap_data->phys_long_mode_entry = long_mode_entry; + bootstrap_data->long_mode_cs = CODE_64_SELECTOR; + + *bootstrap_aperature = bootstrap_virt_addr + 0x1000; + *temp_aspace = bootstrap_aspace; + return NO_ERROR; + +cleanup_aspace: + vmm_free_aspace(bootstrap_aspace); + if (bootstrap_virt_addr) { + vmm_free_region(kernel_aspace, (vaddr_t)bootstrap_virt_addr); + } + return status; +} diff --git a/kernel/arch/x86/64/exceptions.S b/kernel/arch/x86/64/exceptions.S new file mode 100644 index 000000000..c5b94e973 --- /dev/null +++ b/kernel/arch/x86/64/exceptions.S @@ -0,0 +1,120 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#define NUM_INT 256 + +/* + * Please not that the macro for generating interrupt routine stubs relies + * on macro execution counter which is shared by all invocation across this + * compilation unit. Be careful when adding additional macros to this file. + */ + +.text + +/* interrupt service routine stubs */ +_isr: +.macro def_isr +.pushsection .text +FUNCTION(_isr_\@) + /* Clear the AC flag to prevent ring 0 from performing data accesses to + * ring 3 if SMAP is available. If it was set, it will get restored by + * iretd. DO NOT REMOVE THIS CLAC, code in idt.c assumes it is here. + * It MUST be the first instruction of this function. */ + clac +.if \@ == 8 || (\@ >= 10 && \@ <= 14) || \@ == 17 + /* error code pushed by exception */ + pushq $\@ /* interrupt number */ + jmp interrupt_common +.else + pushq $0 /* fill in error code in iframe */ + pushq $\@ /* interrupt number */ + jmp interrupt_common +.endif +.popsection +.pushsection .data +.quad _isr_\@ +.popsection +.endm + +.pushsection .data +/* build a table of isr entry points */ +DATA(_isr_table) +.popsection +.rept NUM_INT +def_isr +.endr + +FUNCTION(interrupt_common) + /* Check to see if we came from user space by testing the PL of the + * CS register that was saved on the stack automatically. Check for != 0. + */ + testb $3, 0x18(%rsp) + jz 1f + + /* swap gs to kernel space */ + swapgs + +1: + /* save general purpose registers */ + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rax + pushq %rcx + pushq %rdx + pushq %rbx + pushq %rbp + pushq %rsi + pushq %rdi + + movq %rsp, %rdi /* pass the iframe using rdi */ + + call x86_exception_handler + +/* A label to assist gdb's backtracing through kernel exceptions. + When gdb sees this as the return address it knows it can fetch + x86_iframe_t from $rsp. See scripts/lk.elf-gdb.py. */ +interrupt_common_iframe_set_up_for_debugger: + + /* restore general purpose registers */ + popq %rdi + popq %rsi + popq %rbp + popq %rbx + popq %rdx + popq %rcx + popq %rax + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + /* check if we're returning to user space as per before */ + testb $3, 0x18(%rsp) + jz 1f + + /* swap gs back to user space */ + swapgs + +1: + /* drop vector number and error code*/ + addq $16, %rsp + + iretq diff --git a/kernel/arch/x86/64/kernel.ld b/kernel/arch/x86/64/kernel.ld new file mode 100644 index 000000000..c03f5455b --- /dev/null +++ b/kernel/arch/x86/64/kernel.ld @@ -0,0 +1,97 @@ +/* +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2013 Travis Geiselbrecht +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + + +ENTRY(_protected_start) +SECTIONS +{ + . = %MEMBASE% + %HEADER_LOAD_OFFSET%; + + .text.header : AT (%MEMBASE% + %KERNEL_LOAD_OFFSET% - %PHYS_HEADER_LOAD_OFFSET%) { + KEEP(*(.text.header)) + } + + . = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%; + _start = .; + + .text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) { + __code_start = .; + KEEP(*(.text.boot)) + *(.text* .sram.text) + *(.gnu.linkonce.t.*) + __code_end = .; + } =0x9090 + + ASSERT(LOADADDR(.text.header) + SIZEOF(.text.header) == LOADADDR(.text), + "The zero page header is not at the right load address.") + + .rodata : ALIGN(4096) { + __rodata_start = .; + *(.rodata*) + *(.gnu.linkonce.r.*) + . = ALIGN(8); + } + + /* + * extra linker scripts tend to insert sections just after .rodata, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_rodata : { + __rodata_end = .; + } + + .data : ALIGN(4096) { + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.bootfs) + } + + .ctors : ALIGN(4) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(4) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + + /* + * extra linker scripts tend to insert sections just after .data, + * so we want to make sure this symbol comes after anything inserted above, + * but not aligned to the next section necessarily. + */ + .dummy_post_data : { + __data_end = .; + } + + _zero_page_sys_size = (__data_end - __code_start + 15) / 16; + + .bss : ALIGN(4096) { + __bss_start = .; + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + __bss_end = .; + } + + . = ALIGN(4096); + _end = .; + + /* put a symbol arbitrarily 4MB past the end of the kernel */ + /* used by the heap and other early boot time allocators */ + _end_of_ram = . + (4*1024*1024); + + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/x86/64/ops.S b/kernel/arch/x86/64/ops.S new file mode 100644 index 000000000..64a16dd4d --- /dev/null +++ b/kernel/arch/x86/64/ops.S @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +.text + +/* This follows the x86-64 ABI, the parameters are stored in registers in the following order*/ +/* +%rdi used to pass 1st argument +%rsi used to pass 2nd argument +%rdx used to pass 3rd argument and 2nd return register +%rcx used to pass 4th argument +%r8 used to pass 5th argument +%r9 used to pass 6th argument +%rax 1st return register +*/ + +/* void arch_idle(); */ +FUNCTION(arch_idle) + pushf + popq %rax + andq $0x200, %rax + test %rax, %rax + je 1f /* don't halt if local interrupts are disabled */ + hlt +1: + ret + diff --git a/kernel/arch/x86/64/smp.c b/kernel/arch/x86/64/smp.c new file mode 100644 index 000000000..6c8c36d48 --- /dev/null +++ b/kernel/arch/x86/64/smp.c @@ -0,0 +1,142 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bp_bootstrap_data { + // Counter of number of APs that have booted + volatile int aps_still_booting; + vmm_aspace_t *bootstrap_aspace; + + uint32_t num_apics; + uint32_t *apic_ids; +}; + +void x86_bringup_smp(uint32_t *apic_ids, uint32_t num_cpus) +{ + struct x86_ap_bootstrap_data *bootstrap_data = NULL; + + struct bp_bootstrap_data config = { + .aps_still_booting = num_cpus - 1, + .bootstrap_aspace = NULL, + .apic_ids = apic_ids, + .num_apics = num_cpus, + }; + + status_t status = x86_bootstrap16_prep( + PHYS_BOOTSTRAP_PAGE, + (uintptr_t)_x86_secondary_cpu_long_mode_entry, + &config.bootstrap_aspace, + (void **)&bootstrap_data); + if (status != NO_ERROR) { + goto finish; + } + + status = x86_allocate_ap_structures(config.num_apics); + if (status != NO_ERROR) { + goto cleanup_aspace; + } + + // Initialized to 1 since the BSP is CPU 0 + bootstrap_data->cpu_id_counter = 1; + bootstrap_data->cpu_waiting_counter = &config.aps_still_booting; + // Zero the kstack list so if we have to bail, we can safely free the + // resources. + memset(bootstrap_data->kstack_base, 0, sizeof(uint64_t) * (SMP_MAX_CPUS - 1)); + // Allocate kstacks for all processors + for (unsigned int i = 0; i < config.num_apics - 1; ++i) { + void *kstack_addr = memalign(16, PAGE_SIZE); + if (!kstack_addr) { + goto cleanup_kstacks; + } + bootstrap_data->kstack_base[i] = (uint64_t)kstack_addr; + } + + // Memory fence to ensure all writes to the bootstrap region are + // visible on the APs when they come up + smp_wmb(); + + lk_init_secondary_cpus(num_cpus - 1); + + uint32_t bsp_apic_id = apic_local_id(); + for (unsigned int i = 0; i < config.num_apics; ++i) { + uint32_t apic_id = config.apic_ids[i]; + // Don't attempt to initialize the bootstrap processor + if (apic_id == bsp_apic_id) { + continue; + } + apic_send_ipi(0, apic_id, DELIVERY_MODE_INIT); + } + + // Wait 10 ms and then send the startup signals + thread_sleep(10); + + // Actually send the startups + ASSERT(PHYS_BOOTSTRAP_PAGE < 1 * MB); + uint8_t vec = PHYS_BOOTSTRAP_PAGE >> PAGE_SIZE_SHIFT; + // Try up to two times per core + for (int tries = 0; tries < 2; ++tries) { + for (unsigned int i = 0; i < config.num_apics; ++i) { + uint32_t apic_id = config.apic_ids[i]; + // Don't attempt to initialize the bootstrap processor + if (apic_id == bsp_apic_id) { + continue; + } + // This will cause the APs to begin executing at PHYS_BOOTSTRAP_PAGE in + // physical memory. + apic_send_ipi(vec, apic_id, DELIVERY_MODE_STARTUP); + } + + if (config.aps_still_booting == 0) { + break; + } + // Wait 2ms for cores to boot. The docs recommend 200us, but we do a + // bit more work before we mark an AP as booted. + thread_sleep(2); + } + + if (config.aps_still_booting != 0) { + printf("Failed to boot %d cores\n", config.aps_still_booting); + // If we failed to boot some cores, leak the shared resources. + // There is the risk the cores will try to access them after + // we free them. + // TODO: Can we do better here + goto finish; + } + + // Now that everything is booted, cleanup all temporary structures (e.g. + // everything except the kstacks). + goto cleanup_aspace; +cleanup_kstacks: + for (unsigned int i = 0; i < config.num_apics - 1; ++i) { + if (bootstrap_data->kstack_base[i]) { + free((void *)bootstrap_data->kstack_base[i]); + } + } +cleanup_aspace: + status = vmm_free_aspace(config.bootstrap_aspace); + DEBUG_ASSERT(status == NO_ERROR); + vmm_aspace_t *kernel_aspace = vmm_get_kernel_aspace(); + vmm_free_region(kernel_aspace, (vaddr_t)bootstrap_data); +finish: + // Get all CPUs to agree on the PATs + x86_pat_sync(); +} diff --git a/kernel/arch/x86/64/start.S b/kernel/arch/x86/64/start.S new file mode 100644 index 000000000..a596981e0 --- /dev/null +++ b/kernel/arch/x86/64/start.S @@ -0,0 +1,232 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +/* shared code to set up a default 64bit page table structure */ +.macro page_table_init + /* load the physical pointer to the top level page table */ + movl $PHYS(pml4), %eax + + /* Setting the First PML4E with a PDP table reference*/ + movl $PHYS(pdp), %eax + orl $X86_KERNEL_PD_FLAGS, %eax + movl %eax, PHYS(pml4) + + /* Setting the First PDPTE with a Page table reference*/ + movl $PHYS(pte), %eax + orl $X86_KERNEL_PD_FLAGS, %eax + movl %eax, PHYS(pdp) + + /* point the pml4e at the second high PDP (for -2GB mapping) */ + movl $PHYS(pdp_high), %eax + orl $X86_KERNEL_PD_FLAGS, %eax + movl %eax, PHYS(pml4 + 8*511) + + /* point the second pdp at the same low level page table */ + movl $PHYS(pte), %eax + orl $X86_KERNEL_PD_FLAGS, %eax + movl %eax, PHYS(pdp_high + 8*510) + + /* map the first 1GB in this table */ + movl $PHYS(pte), %esi + movl $0x200, %ecx + xor %eax, %eax + +0: + mov %eax, %ebx + shll $21, %ebx + orl $X86_KERNEL_PD_LP_FLAGS, %ebx + movl %ebx, (%esi) + addl $8,%esi + inc %eax + loop 0b + + /* set up a linear map of the first 64GB at 0xffffff8000000000 */ + movl $PHYS(linear_map_pdp), %esi + movl $32768, %ecx + xor %eax, %eax + + /* loop across these page tables, incrementing the address by 2MB */ +0: + mov %eax, %ebx + shll $21, %ebx + orl $X86_KERNEL_PD_LP_FLAGS, %ebx # lower word of the entry + movl %ebx, (%esi) + mov %eax, %ebx + shrl $11, %ebx # upper word of the entry + movl %ebx, 4(%esi) + addl $8,%esi + inc %eax + loop 0b + + /* point the high pdp at our linear mapping page tables */ + movl $PHYS(pdp_high), %esi + movl $64, %ecx + movl $PHYS(linear_map_pdp), %eax + orl $X86_KERNEL_PD_FLAGS, %eax + +0: + movl %eax, (%esi) + add $8, %esi + addl $4096, %eax + loop 0b +.endm + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +.section ".text.boot" +.code32 +FUNCTION(_protected_start) + /* attempt to detect if %esi points to a zero page structure */ + cmp $0, %esi + je .Lcommon_boot + cmpl $0x53726448, 0x202(%esi) + jne .Lcommon_boot + mov %esi, PHYS(_zero_page_boot_params) + jmp .Lcommon_boot + +FUNCTION(_multiboot_start) + cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax + jne .Lcommon_boot + movl %ebx, PHYS(_multiboot_info) + +.Lcommon_boot: + /* load our new gdt by physical pointer */ + lgdt PHYS(_gdtr_phys) + + /* load our data selectors */ + movw $DATA_SELECTOR, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* We need to jump to our sane 32 bit CS */ + pushl $CODE_SELECTOR + pushl $PHYS(.Lfarjump) + lret + +.Lfarjump: + /* zero the bss section */ + bss_setup + +paging_setup: + /* Preparing 64 bit paging, we will use 2MB pages covering 1GB + * for initial bootstrap, this page table will be 1 to 1 + */ + + /* PAE bit must be enabled for 64 bit paging*/ + mov %cr4, %eax + btsl $(5), %eax + mov %eax, %cr4 + + /* Long Mode Enabled at this point*/ + movl $X86_MSR_EFER, %ecx + rdmsr + orl $X86_EFER_LME,%eax + wrmsr + + /* initialize the default page tables */ + page_table_init + + /* load the physical pointer to the top level page table */ + movl $PHYS(pml4), %eax + mov %eax, %cr3 + + /* Enabling Paging and from this point we are in + 32 bit compatibility mode*/ + mov %cr0, %eax + btsl $(31), %eax + mov %eax, %cr0 + + /* Using another long jump to be on 64 bit mode + after this we will be on real 64 bit mode */ + pushl $CODE_64_SELECTOR /*Need to put it in a the right CS*/ + pushl $PHYS(farjump64) + lret + +.align 8 +.code64 +farjump64: + /* branch to our high address */ + mov $high_entry, %rax + jmp *%rax + +high_entry: + /* zero our kernel segment data registers */ + xor %eax, %eax + mov %eax, %ds + mov %eax, %es + mov %eax, %fs + mov %eax, %gs + mov %eax, %ss + + /* load the high kernel stack */ + mov $(_kstack + 4096), %rsp + + /* reload the gdtr */ + lgdt _gdtr + + /* set up the idt */ + mov $_idt, %rdi + call idt_setup + lidt _idtr + + /* assign this core CPU# 0 and initialize its per cpu state */ + mov $0, %rdi + call x86_init_percpu + + /* call the main module */ + call lk_main + +0: /* just sit around waiting for interrupts */ + hlt /* interrupts will unhalt the processor */ + pause + jmp 0b /* so jump back to halt to conserve power */ + + /* 64bit entry point from a secondary loader */ +.align 8 +.org 0x200 +FUNCTION(_entry64) + mov %esi, PHYS(_zero_page_boot_params) + + /* ensure the stack pointer is sane */ + + /* This is enough space for the 2x push + lretq below. + * After, we switch to _kstack + 4096. + * But for some reason using _kstack + 4096 here causes + * crashes on some UEFI platforms... + */ + mov PHYS(farjump64), %esp + + /* zero the bss */ + bss_setup + +.Lpaging_setup64: + /* initialize the default page tables */ + page_table_init + + /* load the physical pointer to the top level page table */ + mov $PHYS(pml4), %rax + mov %rax, %cr3 + + /* load our gdtr */ + lgdt _gdtr + + /* long jump to our code selector and the high address */ + push $CODE_64_SELECTOR + push $high_entry + lretq diff --git a/kernel/arch/x86/64/start16.S b/kernel/arch/x86/64/start16.S new file mode 100644 index 000000000..93a3a3872 --- /dev/null +++ b/kernel/arch/x86/64/start16.S @@ -0,0 +1,131 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +# This file provides real-mode entry points for +# 1) secondary CPU initialization + +#include +#include +#include +#include +#include + +.align PAGE_SIZE + +.section .text +FUNCTION(x86_bootstrap16_start) + +.code16 +FUNCTION(x86_bootstrap16_entry) + # We cheat a little and don't switch off of our real mode segments in + # protected mode. In real mode and protected mode, all of our code + # and data accesess are relative to %cs and %ss, using the real mode + # segment calculations. + + # setup %ds/%ss to refer to the data region + mov %cs, %si + add $0x100, %si + mov %si, %ds + mov %si, %ss + + lgdtl BCD_PHYS_GDTR_OFFSET + + # enter protected mode (but without paging) + mov %cr0, %ebx + or $X86_CR0_PE, %ebx + mov %ebx, %cr0 + + # clear instruction prefetch queue + jmp 0f +0: + # enable PAE + mov %cr4, %ecx + or $X86_CR4_PAE, %ecx + mov %ecx, %cr4 + + # load CR3 with the bootstrap PML4 + mov BCD_PHYS_BOOTSTRAP_PML4_OFFSET, %ecx + mov %ecx, %cr3 + + # enable IA-32e mode and indicate support for NX pages. + # need the latter for once we switch to the real kernel + # address space. + mov $X86_MSR_EFER, %ecx + rdmsr + or $X86_EFER_LME, %eax + or $X86_EFER_NXE, %eax + wrmsr + + # enable paging + mov %cr0, %ebx + or $X86_CR0_PG, %ebx + mov %ebx, %cr0 + + # Translate data page segment into full address + mov %ds, %esi + shl $4, %esi + + # Jump to 64-bit CS + mov $BCD_PHYS_LM_ENTRY_OFFSET, %esp + lretl + +# Get the secondary cpu into 64-bit mode with interrupts disabled and no TSS +.code64 +FUNCTION(_x86_secondary_cpu_long_mode_entry) + # When we get here, %rsi should contain the absolute address of our data + # page. + mov $1, %rdi + LOCK xadd %edi, BCD_CPU_COUNTER_OFFSET(%esi) + # %rax is now the ID of this CPU + + # Retrieve this CPUs initial kernel stack + # Note: the stack is unusable until we switch cr3 below + mov %rdi, %rax + dec %rax + mov BCD_KSTACK_BASE_OFFSET(%rsi, %rax, 8), %rsp + add $PAGE_SIZE, %rsp + + # Retrieve the new PML4 address before our data page becomes unreachable + mov BCD_PHYS_KERNEL_PML4_OFFSET(%esi), %ecx + # Similarly for the CPU waiting counter + mov BCD_CPU_WAITING_OFFSET(%esi), %rdx + + # Switch out of the copied code page and into the kernel's + # version of it + mov $.Lhighaddr, %rbx + jmp *%rbx +.Lhighaddr: + # Switch to the kernel's PML4 + mov %rcx, %cr3 + # As of this point, %esi is invalid + + # Reload the GDT with one based off of non-identity mapping + lgdt _gdtr + + # Zero our data segments + xor %eax, %eax + mov %eax, %ds + mov %eax, %es + mov %eax, %fs + mov %eax, %gs + mov %eax, %ss + + # Load the IDT + lidt _idtr + + mov %rdx, %rsi + # Do an indirect call to keep this position independent + # x86_secondary_entry(cpu_id, CPU ready counter) + movq $x86_secondary_entry, %rbx + call *%rbx + +# If x86_secondary_entry returns, hang. +0: + hlt + jmp 0b + +DATA(x86_bootstrap16_end) + nop diff --git a/kernel/arch/x86/64/syscall.S b/kernel/arch/x86/64/syscall.S new file mode 100644 index 000000000..bdf6e56e9 --- /dev/null +++ b/kernel/arch/x86/64/syscall.S @@ -0,0 +1,98 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +.text + + /* kernel side of the SYSCALL instruction + * state on entry: + * RCX holds user RIP + * R11 holds user RFLAGS + * RSP still holds user stack + * CS loaded with kernel CS from IA32_STAR + * SS loaded with kernel CS + 8 from IA32_STAR + + * args passed: + * rax - syscall # and return + * rbx - saved + * rcx - modified as part of syscall instruction + * rdx - arg 3 + * rdi - arg 1 + * rsi - arg 2 + * rbp - saved + * rsp - saved + * r8 - arg 5 + * r9 - arg 6 + * r10 - arg 4 + * r11 - modified as part of syscall instruction + * r12 - arg 7 (callee saved in user space, must be copied from stack) + * r13 - arg 8 (callee saved in user space, must be copied from stack) + * r14 - saved + * r15 - saved + */ +FUNCTION(x86_syscall) + /* swap to the kernel GS register */ + swapgs + + /* save the user stack pointer */ + mov %rsp, %gs:PERCPU_SAVED_USER_SP_OFFSET + + /* load the kernel stack pointer */ + mov %gs:PERCPU_KERNEL_SP_OFFSET, %rsp + + /* save away the user stack pointer */ + push %gs:PERCPU_SAVED_USER_SP_OFFSET + + /* callee saved */ + push %rbx + push %rbp + push %r14 + push %r15 + + push %r11 /* user RFLAGS */ + + /* start to push the rest of the args on the stack as per C calling convention */ + push %rcx /* user RIP */ + push %rax /* syscall # */ + push %r13 /* arg 8 */ + push %r12 /* arg 7 */ + + /* fixup arg 4 into the proper register for calling convention */ + mov %r10, %rcx + + /* call the high level routine */ + call x86_64_syscall + + /* clean up the stack */ + pop %r12 + pop %r13 + add $0x8, %rsp + + /* put everything back */ + pop %rcx + pop %r11 + + pop %r15 + pop %r14 + pop %rbp + pop %rbx + + /* make sure interrupts are disabled */ + cli + + /* restore the user stack */ + pop %rsp + + /* put the user gs back */ + swapgs + + sysretq + +END(x86_syscall) + diff --git a/kernel/arch/x86/64/user.ld b/kernel/arch/x86/64/user.ld new file mode 100644 index 000000000..c52587113 --- /dev/null +++ b/kernel/arch/x86/64/user.ld @@ -0,0 +1,93 @@ +/* +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2013 Travis Geiselbrecht +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT +*/ + + +ENTRY(_start) +SECTIONS +{ + . = 0x01000000; /* start of user space */ + + /* bump forward so the load offset and file offset are 1:1 */ + . += SIZEOF_HEADERS; + + .text : { + *(.crt) + *(.text* .gnu.linkonce.t.*) + } =0x9090 + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + .rodata : ALIGN(8) { + __rodata_start = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + __rodata_end = .; + } + + .data : ALIGN(4096) { + __data_start = .; + *(.data .data.* .gnu.linkonce.d.*) + } + + .ctors : ALIGN(8) { + __ctor_list = .; + KEEP(*(.ctors .init_array)) + __ctor_end = .; + } + .dtors : ALIGN(8) { + __dtor_list = .; + KEEP(*(.dtors .fini_array)) + __dtor_end = .; + } + .got : { *(.got.plt) *(.got) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + + .bss : ALIGN(8) { + __bss_start = .; + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; + } + + _end = .; + + /DISCARD/ : { *(.comment .note) } +} diff --git a/kernel/arch/x86/64/user_copy.S b/kernel/arch/x86/64/user_copy.S new file mode 100644 index 000000000..a34f44a39 --- /dev/null +++ b/kernel/arch/x86/64/user_copy.S @@ -0,0 +1,136 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +/* Register use in this code: + * Callee save: + * %rbx = smap_avail + * %r12 = dst + * %r13 = src + * %r14 = len + * %r15 = fault_return + */ + +.macro begin_usercopy + push %r12 + push %r13 + push %r14 + push %r15 + push %rbx + + # shift all of the arguments into the intersection of callee save and + # not mutated by cpuid + mov %rdi, %r12 + mov %rsi, %r13 + mov %rdx, %r14 + mov %rcx, %r15 + + # Check if SMAP is enabled + mov $7, %eax + mov $0, %ecx + cpuid + and $1<<20, %rbx + + # Disable SMAP protection if SMAP is enabled + jz 0f + stac +0: +.endm + +.macro end_usercopy + # Re-enable SMAP protection + cmp $0, %rbx + jz 0f + clac +0: + pop %rbx + pop %r15 + pop %r14 + pop %r13 + pop %r12 +.endm + +# status_t _x86_copy_from_user(void *dst, const void *src, size_t len, void **fault_return) +FUNCTION(_x86_copy_from_user) + begin_usercopy + + # Check that userspace has access to the [src, src+len) buffer + mov %r13, %rdi + mov %r14, %rsi + call _x86_usercopy_can_read + cmp $0, %rax + jnz 0f + mov $ERR_INVALID_ARGS, %rax + jmp .Lcleanup_copy_from +0: + # Setup page fault return + movq $.Lfault_copy_from, (%r15) + + # Between now and the reset of the fault return, we cannot make a function + # call or manipulate the stack. We need to be able to restore all callee + # registers, without any knowledge of where between these two points we + # faulted. + + # Perform the actual copy + cld + mov %r12, %rdi + mov %r13, %rsi + mov %r14, %rcx + rep movsb + + mov $NO_ERROR, %rax + jmp .Lcleanup_copy_from + +.Lfault_copy_from: + mov $ERR_INVALID_ARGS, %rax +.Lcleanup_copy_from: + # Reset fault return + movq $0, (%r15) + + end_usercopy + ret + +# status_t _x86_copy_to_user(void *dst, const void *src, size_t len, void **fault_return) +FUNCTION(_x86_copy_to_user) + begin_usercopy + + # Check that userspace has access to the [dst, dst+len) buffer + mov %r12, %rdi + mov %r14, %rsi + call _x86_usercopy_can_write + cmp $0, %rax + jnz 0f + mov $ERR_INVALID_ARGS, %rax + jmp .Lcleanup_copy_to +0: + # Setup page fault return + movq $.Lfault_copy_to, (%r15) + + # Between now and the reset of the fault return, we cannot make a function + # call or manipulate the stack. We need to be able to restore all callee + # registers, without any knowledge of where between these two points we + # faulted. + + # Perform the actual copy + cld + mov %r12, %rdi + mov %r13, %rsi + mov %r14, %rcx + rep movsb + + mov $NO_ERROR, %rax + jmp .Lcleanup_copy_to + +.Lfault_copy_to: + mov $ERR_INVALID_ARGS, %rax +.Lcleanup_copy_to: + # Reset fault return + movq $0, (%r15) + + end_usercopy + ret diff --git a/kernel/arch/x86/64/uspace_entry.S b/kernel/arch/x86/64/uspace_entry.S new file mode 100644 index 000000000..6cff49a7a --- /dev/null +++ b/kernel/arch/x86/64/uspace_entry.S @@ -0,0 +1,46 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +# x86_uspace_entry(void* thread_arg, vaddr_t ustack, uint64_t rflags, vaddr_t entry_point) +FUNCTION(x86_uspace_entry) + /* push a fake 64bit interrupt stack frame and iret to it */ + pushq $USER_DATA_SELECTOR # ss + pushq %rsi # ustack + pushq %rdx # rflags + pushq $USER_CODE_64_SELECTOR # cs + pushq %rcx # entry + + # Clear registers + xor %rax, %rax + xor %rbx, %rbx + xor %rcx, %rcx + xor %rdx, %rdx + xor %rsi, %rsi + # Don't clear rdi, since it has the thread arg + xor %rbp, %rbp + xor %r8, %r8 + xor %r9, %r9 + xor %r10, %r10 + xor %r11, %r11 + xor %r12, %r12 + xor %r13, %r13 + xor %r14, %r14 + xor %r15, %r15 + + # TODO(teisenbe): Clear xmm/ymm stuff. Currently this is all + # handled by lazy FPU loading, but once we support YMM this will + # likely change + swapgs + + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + iretq diff --git a/kernel/arch/x86/BUILD.gn b/kernel/arch/x86/BUILD.gn new file mode 100644 index 000000000..115ea2c0b --- /dev/null +++ b/kernel/arch/x86/BUILD.gn @@ -0,0 +1,66 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "x64") + +import("//gnbuild/config.gni") +import("//gnbuild/generate_ld_script.gni") + +module("x86") { + configs += [ + "//kernel/kernel:enable_vm", + "//kernel/lib/console:enable_console", + "//kernel/lib/magenta:enable_magenta", + ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + "//kernel/lib/magenta/include", + "//kernel/lib/user_copy/include", + "//system/ulib/magenta/include", + "//kernel/dev/interrupt/include", + ] + + # These defines would be ideally defined as a config, but they're currently + # also shared by the ld script target and as such has to be defined as + # variable. + defines = kernel_defines + sources = [ + "64/ap_start.S", + "64/asm.S", + "64/exceptions.S", + "64/ops.S", + "64/smp.c", + "64/start.S", + "64/syscall.S", + "64/user_copy.S", + "64/uspace_entry.S", + "arch.c", + "cache.c", + "descriptor.c", + "faults.c", + "feature.c", + "fpu.c", + "gdt.S", + "header.S", + "idt.c", + "ioapic.c", + "ioport.c", + "lapic.c", + "mmu.cpp", + "mmu_mem_types.c", + "mp.c", + "thread.c", + "user_copy.c", + ] +} + +generate_ld_script("kernel_ld") { + input = "64/kernel.ld" + output = "${root_gen_dir}/kernel.ld" + defines = kernel_defines +} diff --git a/kernel/arch/x86/arch.c b/kernel/arch/x86/arch.c new file mode 100644 index 000000000..35172ace7 --- /dev/null +++ b/kernel/arch/x86/arch.c @@ -0,0 +1,147 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +/* early stack */ +uint8_t _kstack[PAGE_SIZE] __ALIGNED(16); + +/* save a pointer to the multiboot information coming in from whoever called us */ +/* make sure it lives in .data to avoid it being wiped out by bss clearing */ +__SECTION(".data") void *_multiboot_info; + +/* also save a pointer to the boot_params structure */ +__SECTION(".data") void *_zero_page_boot_params; + +void arch_early_init(void) +{ + x86_mmu_early_init(); +} + +void arch_init(void) +{ + x86_mmu_init(); +} + +void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) +{ + PANIC_UNIMPLEMENTED; +} + +void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top, void* thread_arg) +{ + LTRACEF("entry 0x%lx user stack 0x%lx\n", entry_point, user_stack_top); + + DEBUG_ASSERT(IS_ALIGNED(user_stack_top, 16)); + user_stack_top -= 8; /* start the user stack 8 byte unaligned, which is how the abi expects it */ + + arch_disable_ints(); + +#if ARCH_X86_32 + PANIC_UNIMPLEMENTED; +#elif ARCH_X86_64 + /* default user space flags: + * IOPL 0 + * Interrupts enabled + */ + ulong flags = (0 << X86_FLAGS_IOPL_SHIFT) | X86_FLAGS_IF; + + /* check that we're probably still pointed at the kernel gs */ + DEBUG_ASSERT(is_kernel_address(read_msr(X86_MSR_IA32_GS_BASE))); + + /* set up user's fs: gs: base */ + write_msr(X86_MSR_IA32_FS_BASE, 0); + + /* set the KERNEL_GS_BASE msr here, because we're going to swapgs below */ + write_msr(X86_MSR_IA32_KERNEL_GS_BASE, 0); + + /* TODO: clear all of the other registers to avoid leading kernel state */ + + x86_uspace_entry(thread_arg, user_stack_top, flags, entry_point); + __UNREACHABLE; +#endif +} + +#if WITH_SMP +#include +void x86_secondary_entry(uint8_t asm_cpu_num, volatile int *aps_still_booting) +{ + x86_init_percpu(asm_cpu_num); + // Would prefer this to be in init_percpu, but there is a dependency on a + // page mapping existing, and the BP calls thta before the VM subsystem is + // initialized. + apic_local_init(); + + // Signal that this CPU is initialized + atomic_add(aps_still_booting, -1); + + /* run early secondary cpu init routines up to the threading level */ + lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_THREADING - 1); + + lk_secondary_cpu_entry(); + + // lk_secondary_cpu_entry only returns on an error, halt the core in this + // case. + arch_disable_ints(); + while (1) { + x86_hlt(); + } +} +#endif + +static int cmd_cpu(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("%s features\n", argv[0].str); + return ERR_GENERIC; + } + + if (!strcmp(argv[1].str, "features")) { + x86_feature_debug(); + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("cpu", "cpu info commands", &cmd_cpu) +#endif +STATIC_COMMAND_END(cpu); diff --git a/kernel/arch/x86/cache.c b/kernel/arch/x86/cache.c new file mode 100644 index 000000000..73317e20a --- /dev/null +++ b/kernel/arch/x86/cache.c @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +/* nothing to do to sync I & D cache on x86 */ +void arch_sync_cache_range(addr_t start, size_t len) +{ +} + +void arch_clean_cache_range(addr_t start, size_t len) +{ + __asm__ volatile("wbinvd"); +} + +void arch_clean_invalidate_cache_range(addr_t start, size_t len) +{ + __asm__ volatile("wbinvd"); +} diff --git a/kernel/arch/x86/descriptor.c b/kernel/arch/x86/descriptor.c new file mode 100644 index 000000000..5df8dfd31 --- /dev/null +++ b/kernel/arch/x86/descriptor.c @@ -0,0 +1,195 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* the main global gdt in the system, declared in assembly */ +extern uint8_t _gdt[]; +static void x86_tss_assign_ists(struct x86_percpu *percpu, tss_t *tss); + +void x86_initialize_percpu_tss(void) +{ + struct x86_percpu *percpu = x86_get_percpu(); + uint8_t cpu_num = percpu->cpu_num; + tss_t *tss = &percpu->default_tss; + memset(tss, 0, sizeof(*tss)); + +#if ARCH_X86_32 + tss->esp0 = 0; + tss->ss0 = DATA_SELECTOR; + tss->ss1 = 0; + tss->ss2 = 0; + tss->eflags = 0x00003002; + tss->bitmap = offsetof(tss_32_t, tss_bitmap); + tss->trace = 1; // trap on hardware task switch + + set_global_desc_32(TSS_SELECTOR(cpu_num), (uintptr_t)tss, sizeof(*tss) - 1, 1, 0, 0, SEG_TYPE_TSS, 0, 0); +#elif ARCH_X86_64 + /* zeroed out TSS is okay for now */ + set_global_desc_64(TSS_SELECTOR(cpu_num), (uintptr_t)tss, sizeof(*tss) - 1, 1, 0, 0, SEG_TYPE_TSS, 0, 0); + + x86_tss_assign_ists(percpu, tss); + + tss->iomap_base = offsetof(tss_64_t, tss_bitmap); + + // Setup alternate stacks to gurantee stack sanity when handling these + // interrupts + idt_set_ist_index(&percpu->idt, X86_INT_NMI, NMI_IST_INDEX); + idt_set_ist_index(&percpu->idt, X86_INT_MACHINE_CHECK, MCE_IST_INDEX); + idt_set_ist_index(&percpu->idt, X86_INT_DOUBLE_FAULT, DBF_IST_INDEX); +#endif + // Need to have an extra byte at the end of the bitmap because it will always potentially read two bytes + tss->tss_bitmap[IO_BITMAP_BYTES] = 0xff; + + x86_ltr(TSS_SELECTOR(cpu_num)); +} + +#ifdef ARCH_X86_64 +static void x86_tss_assign_ists(struct x86_percpu *percpu, tss_t *tss) +{ + tss->ist1 = (uintptr_t)&percpu->interrupt_stacks[0] + PAGE_SIZE; + tss->ist2 = (uintptr_t)&percpu->interrupt_stacks[1] + PAGE_SIZE; + tss->ist3 = (uintptr_t)&percpu->interrupt_stacks[2] + PAGE_SIZE; +} +#endif + +void x86_set_tss_sp(vaddr_t sp) +{ + tss_t *tss = &x86_get_percpu()->default_tss; +#if ARCH_X86_32 + tss->esp0 = sp; +#elif ARCH_X86_64 + tss->rsp0 = sp; +#endif +} + +void x86_set_tss_io_bitmap(uint8_t *bitmap) +{ + DEBUG_ASSERT(arch_ints_disabled()); + tss_t *tss = &x86_get_percpu()->default_tss; + memcpy(tss->tss_bitmap, bitmap, IO_BITMAP_BYTES); +} + +void x86_clear_tss_io_bitmap(void) +{ + DEBUG_ASSERT(arch_ints_disabled()); + tss_t *tss = &x86_get_percpu()->default_tss; + memset(tss->tss_bitmap, 0xff, IO_BITMAP_BYTES); +} + +void set_global_desc_32(seg_sel_t sel, uint32_t base, uint32_t limit, + uint8_t present, uint8_t ring, uint8_t sys, + uint8_t type, uint8_t gran, uint8_t bits) +{ + // 16/32 bit descriptor structure + struct seg_desc_32 { + uint16_t limit_15_0; + uint16_t base_15_0; + uint8_t base_23_16; + + uint8_t type : 4; + uint8_t s : 1; + uint8_t dpl : 2; + uint8_t p : 1; + + uint8_t limit_19_16 : 4; + uint8_t avl : 1; + uint8_t reserved_0 : 1; + uint8_t d_b : 1; + uint8_t g : 1; + + uint8_t base_31_24; + } __PACKED; + + struct seg_desc_32 entry = { 0 }; + + entry.limit_15_0 = limit & 0x0000ffff; + entry.limit_19_16 = (limit & 0x000f0000) >> 16; + + entry.base_15_0 = base & 0x0000ffff; + entry.base_23_16 = (base & 0x00ff0000) >> 16; + entry.base_31_24 = base >> 24; + + entry.type = type & 0x0f; // segment type + entry.p = present != 0; // present + entry.dpl = ring & 0x03; // descriptor privilege level + entry.g = gran != 0; // granularity + entry.s = sys != 0; // system / non-system + entry.d_b = bits != 0; // 16 / 32 bit + + // copy it into the appropriate entry + uint16_t index = sel >> 3; + + // index is in units of 8 bytes into the gdt table + struct seg_desc_32 *g = (struct seg_desc_32 *)(_gdt + index * 8); + *g = entry; +} + +void set_global_desc_64(seg_sel_t sel, uint64_t base, uint32_t limit, + uint8_t present, uint8_t ring, uint8_t sys, + uint8_t type, uint8_t gran, uint8_t bits) +{ + // 64 bit descriptor structure + struct seg_desc_64 { + uint16_t limit_15_0; + uint16_t base_15_0; + uint8_t base_23_16; + + uint8_t type : 4; + uint8_t s : 1; + uint8_t dpl : 2; + uint8_t p : 1; + + uint8_t limit_19_16 : 4; + uint8_t avl : 1; + uint8_t reserved_0 : 1; + uint8_t d_b : 1; + uint8_t g : 1; + + uint8_t base_31_24; + + uint32_t base_63_32; + uint32_t reserved_sbz; + } __PACKED; + + struct seg_desc_64 entry = { 0 }; + + entry.limit_15_0 = limit & 0x0000ffff; + entry.limit_19_16 = (limit & 0x000f0000) >> 16; + + entry.base_15_0 = base & 0x0000ffff; + entry.base_23_16 = (base & 0x00ff0000) >> 16; + entry.base_31_24 = (base & 0xff000000) >> 24; + entry.base_63_32 = base >> 32; + + entry.type = type & 0x0f; // segment type + entry.p = present != 0; // present + entry.dpl = ring & 0x03; // descriptor privilege level + entry.g = gran != 0; // granularity + entry.s = sys != 0; // system / non-system + entry.d_b = bits != 0; // 16 / 32 bit + + // copy it into the appropriate entry + uint16_t index = sel >> 3; + + // index is in units of 8 bytes into the gdt table + struct seg_desc_64 *g = (struct seg_desc_64 *)(_gdt + index * 8); + *g = entry; +} + diff --git a/kernel/arch/x86/faults.c b/kernel/arch/x86/faults.c new file mode 100644 index 000000000..ddd31cccb --- /dev/null +++ b/kernel/arch/x86/faults.c @@ -0,0 +1,359 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if WITH_LIB_MAGENTA +#include + +struct arch_exception_context { + bool is_page_fault; + x86_iframe_t *frame; + ulong cr2; +}; +#endif + +extern enum handler_return platform_irq(x86_iframe_t *frame); + +static void dump_fault_frame(x86_iframe_t *frame) +{ +#if ARCH_X86_32 + dprintf(CRITICAL, " CS: %04x EIP: %08x EFL: %08x CR2: %08lx\n", + frame->cs, frame->ip, frame->flags, x86_get_cr2()); + dprintf(CRITICAL, "EAX: %08x ECX: %08x EDX: %08x EBX: %08x\n", + frame->eax, frame->ecx, frame->edx, frame->ebx); + dprintf(CRITICAL, "ESP: %08x EBP: %08x ESI: %08x EDI: %08x\n", + frame->esp, frame->ebp, frame->esi, frame->edi); + dprintf(CRITICAL, " DS: %04x ES: %04x FS: %04x GS: %04x\n", + frame->ds, frame->es, frame->fs, frame->gs); +#elif ARCH_X86_64 + dprintf(CRITICAL, " CS: %4llx RIP: %16llx EFL: %16llx CR2: %16lx\n", + frame->cs, frame->ip, frame->flags, x86_get_cr2()); + dprintf(CRITICAL, " RAX: %16llx RBX: %16llx RCX: %16llx RDX: %16llx\n", + frame->rax, frame->rbx, frame->rcx, frame->rdx); + dprintf(CRITICAL, " RSI: %16llx RDI: %16llx RBP: %16llx RSP: %16llx\n", + frame->rsi, frame->rdi, frame->rbp, frame->user_sp); + dprintf(CRITICAL, " R8: %16llx R9: %16llx R10: %16llx R11: %16llx\n", + frame->r8, frame->r9, frame->r10, frame->r11); + dprintf(CRITICAL, " R12: %16llx R13: %16llx R14: %16llx R15: %16llx\n", + frame->r12, frame->r13, frame->r14, frame->r15); + dprintf(CRITICAL, "errc: %16llx\n", + frame->err_code); +#endif + + // dump the bottom of the current stack + void *stack = frame; + + if (frame->cs == CODE_64_SELECTOR) { + dprintf(CRITICAL, "bottom of kernel stack at %p:\n", stack); + hexdump(stack, 128); + } +} + +static void exception_die(x86_iframe_t *frame, const char *msg) +{ + dprintf(CRITICAL, "%s", msg); + dump_fault_frame(frame); + +#if ARCH_X86_64 + // try to dump the user stack + if (is_user_address(frame->user_sp)) { + uint8_t buf[256]; + if (copy_from_user(buf, (void *)frame->user_sp, sizeof(buf)) == NO_ERROR) { + printf("bottom of user stack at 0x%lx:\n", (vaddr_t)frame->user_sp); + hexdump_ex(buf, sizeof(buf), frame->user_sp); + } + } +#endif + + for (;;) { + x86_cli(); + x86_hlt(); + } +} + +void x86_syscall_handler(x86_iframe_t *frame) +{ + exception_die(frame, "unhandled syscall, halting\n"); +} + +void x86_gpf_handler(x86_iframe_t *frame) +{ +#if WITH_LIB_MAGENTA + struct arch_exception_context context = { .frame = frame, .is_page_fault = false }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_GENERAL, &context, frame->ip); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + exception_die(frame, "unhandled gpf, halting\n"); +} + +void x86_invop_handler(x86_iframe_t *frame) +{ +#if WITH_LIB_MAGENTA + struct arch_exception_context context = { .frame = frame, .is_page_fault = false }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_UNDEFINED_INSTRUCTION, &context, frame->ip); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + exception_die(frame, "invalid opcode, halting\n"); +} + +void x86_unhandled_exception(x86_iframe_t *frame) +{ +#if WITH_LIB_MAGENTA + struct arch_exception_context context = { .frame = frame, .is_page_fault = false }; + arch_enable_ints(); + status_t erc = magenta_exception_handler(EXC_GENERAL, &context, frame->ip); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#endif + printf("vector %u\n", (uint)frame->vector); + exception_die(frame, "unhandled exception, halting\n"); +} + +static void x86_dump_pfe(x86_iframe_t *frame, ulong cr2) +{ + uint32_t error_code = frame->err_code; + + addr_t v_addr = cr2; + addr_t ssp = frame->user_ss & X86_8BYTE_MASK; + addr_t sp = frame->user_sp; + addr_t cs = frame->cs & X86_8BYTE_MASK; + addr_t ip = frame->ip; + + dprintf(CRITICAL, " Instruction Pointer = 0x%lx:0x%lx\n", + (ulong)cs, + (ulong)ip); + dprintf(CRITICAL, " Stack Pointer = 0x%lx:0x%lx\n", + (ulong)ssp, + (ulong)sp); + dprintf(CRITICAL, " Fault Linear Address = 0x%lx\n", + (ulong)v_addr); + dprintf(CRITICAL, " Error Code Value = 0x%lx\n", + (ulong)error_code); + dprintf(CRITICAL, " Error Code Type = %s %s %s%s, %s\n", + error_code & PFEX_U ? "user" : "supervisor", + error_code & PFEX_W ? "write" : "read", + error_code & PFEX_I ? "instruction" : "data", + error_code & PFEX_RSV ? " rsv" : "", + error_code & PFEX_P ? "protection violation" : "page not present"); +} + + +static void x86_fatal_pfe_handler(x86_iframe_t *frame, ulong cr2) +{ + x86_dump_pfe(frame, cr2); + + uint32_t error_code = frame->err_code; + + dump_thread(get_current_thread()); + + if (error_code & PFEX_U) { + // User mode page fault + switch (error_code) { + case 4: + case 5: + case 6: + case 7: + exception_die(frame, "User Page Fault exception, halting\n"); + break; + } + } else { + // Supervisor mode page fault + switch (error_code) { + + case 0: + case 1: + case 2: + case 3: + exception_die(frame, "Supervisor Page Fault exception, halting\n"); + break; + } + } + + exception_die(frame, "unhandled page fault, halting\n"); +} + +void x86_pfe_handler(x86_iframe_t *frame) +{ + /* Handle a page fault exception */ + uint32_t error_code = frame->err_code; + vaddr_t va = x86_get_cr2(); + + /* reenable interrupts */ + arch_enable_ints(); + + /* check for flags we're not prepared to handle */ + if (unlikely(error_code & ~(PFEX_I | PFEX_U | PFEX_W | PFEX_P))) { + printf("x86_pfe_handler: unhandled error code bits set, error code 0x%x\n", error_code); + x86_fatal_pfe_handler(frame, va); + } + + /* convert the PF error codes to page fault flags */ + uint flags = 0; + flags |= (error_code & PFEX_W) ? VMM_PF_FLAG_WRITE : 0; + flags |= (error_code & PFEX_U) ? VMM_PF_FLAG_USER : 0; + flags |= (error_code & PFEX_I) ? VMM_PF_FLAG_INSTRUCTION : 0; + + int pf_err = vmm_page_fault_handler(va, flags); + if (unlikely(pf_err < 0)) { + /* if the high level page fault handler can't deal with it, + * resort to trying to recover first, before bailing */ + +#ifdef ARCH_X86_64 + /* Check if a resume address is specified, and just return to it if so */ + thread_t *current_thread = get_current_thread(); + if (unlikely(current_thread->arch.page_fault_resume)) { + frame->ip = (uintptr_t)current_thread->arch.page_fault_resume; + return; + } +#endif + + /* let high level code deal with this */ +#if WITH_LIB_MAGENTA + struct arch_exception_context context = { .frame = frame, .is_page_fault = true, .cr2 = va }; + status_t erc = magenta_exception_handler(EXC_FATAL_PAGE_FAULT, &context, frame->ip); + arch_disable_ints(); + if (erc == NO_ERROR) + return; +#else + arch_disable_ints(); +#endif + + + /* fatal (for now) */ + x86_fatal_pfe_handler(frame, va); + } +} + +/* top level x86 exception handler for most exceptions and irqs */ +void x86_exception_handler(x86_iframe_t *frame) +{ + THREAD_STATS_INC(interrupts); + + // deliver the interrupt + enum handler_return ret = INT_NO_RESCHEDULE; + + switch (frame->vector) { + case X86_INT_INVALID_OP: + x86_invop_handler(frame); + break; + + case X86_INT_DEVICE_NA: { + // did we come from user or kernel space? + bool from_user = SELECTOR_PL(frame->cs) != 0; + if (unlikely(!from_user)) { + exception_die(frame, "invalid fpu use in kernel\n"); + } + fpu_dev_na_handler(); + break; + } + + case X86_INT_FPU_FP_ERROR: { + uint16_t fsw; + __asm__ __volatile__("fnstsw %0" : "=m" (fsw)); + TRACEF("fsw 0x%hx\n", fsw); + exception_die(frame, "x87 math fault\n"); + //asm volatile("fnclex"); + break; + } + case X86_INT_SIMD_FP_ERROR: { + uint32_t mxcsr; + __asm__ __volatile__("stmxcsr %0" : "=m" (mxcsr)); + TRACEF("mxcsr 0x%x\n", mxcsr); + exception_die(frame, "simd math fault\n"); + break; + } + case X86_INT_GP_FAULT: + x86_gpf_handler(frame); + break; + + case X86_INT_PAGE_FAULT: + x86_pfe_handler(frame); + break; + + /* ignore spurious APIC irqs */ + case X86_INT_APIC_SPURIOUS: break; + case X86_INT_APIC_ERROR: { + ret = apic_error_interrupt_handler(); + apic_issue_eoi(); + break; + } + case X86_INT_APIC_TIMER: { + ret = apic_timer_interrupt_handler(); + apic_issue_eoi(); + break; + } +#if WITH_SMP + case X86_INT_IPI_GENERIC: { + ret = x86_ipi_generic_handler(); + apic_issue_eoi(); + break; + } + case X86_INT_IPI_RESCHEDULE: { + ret = x86_ipi_reschedule_handler(); + apic_issue_eoi(); + break; + } +#endif + /* pass all other non-Intel defined irq vectors to the platform */ + case X86_INT_PLATFORM_BASE ... X86_INT_PLATFORM_MAX: { + ret = platform_irq(frame); + break; + } + default: + x86_unhandled_exception(frame); + } + + if (ret != INT_NO_RESCHEDULE) + thread_preempt(); +} + +__WEAK uint64_t x86_64_syscall(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, + uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8, + uint64_t syscall_num) +{ + PANIC_UNIMPLEMENTED; +} + +#if WITH_LIB_MAGENTA +void arch_dump_exception_context(arch_exception_context_t *context) +{ + if (context->is_page_fault) { + x86_dump_pfe(context->frame, context->cr2); + } + + dump_fault_frame(context->frame); + + // try to dump the user stack + if (context->frame->cs != CODE_64_SELECTOR && is_user_address(context->frame->user_sp)) { + uint8_t buf[256]; + if (copy_from_user(buf, (void *)context->frame->user_sp, sizeof(buf)) == NO_ERROR) { + printf("bottom of user stack at 0x%lx:\n", (vaddr_t)context->frame->user_sp); + hexdump_ex(buf, sizeof(buf), context->frame->user_sp); + } + } +} +#endif + + diff --git a/kernel/arch/x86/feature.c b/kernel/arch/x86/feature.c new file mode 100644 index 000000000..8f0975a76 --- /dev/null +++ b/kernel/arch/x86/feature.c @@ -0,0 +1,183 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include + +#include + +#define LOCAL_TRACE 0 + +#define MAX_SUPPORTED_CPUID (0x17) +#define MAX_SUPPORTED_CPUID_EXT (0x80000008) + +static struct cpuid_leaf _cpuid[MAX_SUPPORTED_CPUID + 1]; +static struct cpuid_leaf _cpuid_ext[MAX_SUPPORTED_CPUID_EXT - X86_CPUID_EXT_BASE + 1]; +static uint32_t max_cpuid = 0; +static uint32_t max_ext_cpuid = 0; + +static int initialized = 0; + +void x86_feature_init(void) +{ + if (atomic_swap(&initialized, 1)) { + return; + } + /* test for cpuid count */ + cpuid(0, &_cpuid[0].a, &_cpuid[0].b, &_cpuid[0].c, &_cpuid[0].d); + + max_cpuid = _cpuid[0].a; + if (max_cpuid > MAX_SUPPORTED_CPUID) + max_cpuid = MAX_SUPPORTED_CPUID; + LTRACEF("max cpuid 0x%x\n", max_cpuid); + + /* read in the base cpuids */ + for (uint32_t i = 1; i <= max_cpuid; i++) { + cpuid_c(i, 0, &_cpuid[i].a, &_cpuid[i].b, &_cpuid[i].c, &_cpuid[i].d); + } + + /* test for extended cpuid count */ + cpuid(X86_CPUID_EXT_BASE, &_cpuid_ext[0].a, &_cpuid_ext[0].b, &_cpuid_ext[0].c, &_cpuid_ext[0].d); + + max_ext_cpuid = _cpuid_ext[0].a; + LTRACEF("max extended cpuid 0x%x\n", max_ext_cpuid); + if (max_ext_cpuid > MAX_SUPPORTED_CPUID_EXT) + max_ext_cpuid = MAX_SUPPORTED_CPUID_EXT; + + /* read in the extended cpuids */ + for (uint32_t i = X86_CPUID_EXT_BASE + 1; i - 1 < max_ext_cpuid; i++) { + uint32_t index = i - X86_CPUID_EXT_BASE; + cpuid_c(i, 0, &_cpuid_ext[index].a, &_cpuid_ext[index].b, &_cpuid_ext[index].c, &_cpuid_ext[index].d); + } + +#if LK_DEBUGLEVEL > 1 + x86_feature_debug(); +#endif +} + +const struct cpuid_leaf *x86_get_cpuid_leaf(enum x86_cpuid_leaf_num leaf) +{ + if (leaf < X86_CPUID_EXT_BASE) { + if (leaf > max_cpuid) + return NULL; + + return &_cpuid[leaf]; + } else { + if (leaf > max_ext_cpuid) + return NULL; + + leaf -= X86_CPUID_EXT_BASE; + return &_cpuid_ext[leaf]; + } +} + +bool x86_get_cpuid_subleaf( + enum x86_cpuid_leaf_num num, uint32_t subleaf, struct cpuid_leaf *leaf) +{ + if (num < X86_CPUID_EXT_BASE) { + if (num > max_cpuid) + return false; + } else if (num > max_ext_cpuid) { + return false; + } + + cpuid_c((uint32_t)num, subleaf, &leaf->a, &leaf->b, &leaf->c, &leaf->d); + return true; +} + +bool x86_feature_test(struct x86_cpuid_bit bit) +{ + DEBUG_ASSERT (bit.word <= 3 && bit.bit <= 31); + + if (bit.word > 3 || bit.bit > 31) + return false; + + const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(bit.leaf_num); + if (!leaf) + return false; + + switch (bit.word) { + case 0: return !!((1u << bit.bit) & leaf->a); + case 1: return !!((1u << bit.bit) & leaf->b); + case 2: return !!((1u << bit.bit) & leaf->c); + case 3: return !!((1u << bit.bit) & leaf->d); + default: return false; + } +} + +bool x86_topology_enumerate(uint8_t level, struct x86_topology_level *info) +{ + DEBUG_ASSERT(info); + + uint32_t eax, ebx, ecx, edx; + cpuid_c(X86_CPUID_TOPOLOGY, level, &eax, &ebx, &ecx, &edx); + + uint8_t type = (ecx >> 8) & 0xff; + if (type == X86_TOPOLOGY_INVALID) { + return false; + } + + info->num_bits = eax & 0x1f; + info->type = type; + return true; +} + +void x86_feature_debug(void) +{ + printf("Features:"); + if (x86_feature_test(X86_FEATURE_FPU)) + printf(" fpu"); + if (x86_feature_test(X86_FEATURE_SSE)) + printf(" sse"); + if (x86_feature_test(X86_FEATURE_SSE2)) + printf(" sse2"); + if (x86_feature_test(X86_FEATURE_SSE3)) + printf(" sse3"); + if (x86_feature_test(X86_FEATURE_SSSE3)) + printf(" ssse3"); + if (x86_feature_test(X86_FEATURE_SSE4_1)) + printf(" sse4.1"); + if (x86_feature_test(X86_FEATURE_SSE4_2)) + printf(" sse4.2"); + if (x86_feature_test(X86_FEATURE_MMX)) + printf(" mmx"); + if (x86_feature_test(X86_FEATURE_AVX)) + printf(" avx"); + if (x86_feature_test(X86_FEATURE_AVX2)) + printf(" avx2"); + if (x86_feature_test(X86_FEATURE_FXSR)) + printf(" fxsr"); + if (x86_feature_test(X86_FEATURE_XSAVE)) + printf(" xsave"); + if (x86_feature_test(X86_FEATURE_AESNI)) + printf(" aesni"); + if (x86_feature_test(X86_FEATURE_TSC_ADJUST)) + printf(" tsc_adj"); + if (x86_feature_test(X86_FEATURE_SMEP)) + printf(" smep"); + if (x86_feature_test(X86_FEATURE_SMAP)) + printf(" smap"); + if (x86_feature_test(X86_FEATURE_RDRAND)) + printf(" rdrand"); + if (x86_feature_test(X86_FEATURE_RDSEED)) + printf(" rdseed"); + if (x86_feature_test(X86_FEATURE_PKU)) + printf(" pku"); + if (x86_feature_test(X86_FEATURE_SYSCALL)) + printf(" syscall"); + if (x86_feature_test(X86_FEATURE_NX)) + printf(" nx"); + if (x86_feature_test(X86_FEATURE_HUGE_PAGE)) + printf(" huge"); + if (x86_feature_test(X86_FEATURE_RDTSCP)) + printf(" rdtscp"); + if (x86_feature_test(X86_FEATURE_INVAR_TSC)) + printf(" invar_tsc"); + printf("\n"); +} diff --git a/kernel/arch/x86/fpu.c b/kernel/arch/x86/fpu.c new file mode 100644 index 000000000..f8f5e3edd --- /dev/null +++ b/kernel/arch/x86/fpu.c @@ -0,0 +1,147 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define FPU_MASK_ALL_EXCEPTIONS 1 + +static int fp_supported; + +static void set_fpu_enabled(bool enabled); + +/* FXSAVE area comprises 512 bytes starting with 16-byte aligned */ +static uint8_t __ALIGNED(16) fpu_init_states[512]= {0}; + +void fpu_init(void) +{ + uint16_t fcw; + uint32_t mxcsr; + +#ifdef ARCH_X86_64 + uint64_t x; +#else + uint32_t x; +#endif + + if (!x86_feature_test(X86_FEATURE_FPU) || + !x86_feature_test(X86_FEATURE_SSE) || + !x86_feature_test(X86_FEATURE_SSE2) || + !x86_feature_test(X86_FEATURE_SSE3) || + !x86_feature_test(X86_FEATURE_SSSE3) || + !x86_feature_test(X86_FEATURE_SSE4_1) || + !x86_feature_test(X86_FEATURE_SSE4_2) || + !x86_feature_test(X86_FEATURE_FXSR)) + return; + + fp_supported = 1; + + /* No x87 emul, monitor co-processor */ + + x = x86_get_cr0(); + x &= ~X86_CR0_EM; + x |= X86_CR0_NE; + x |= X86_CR0_MP; + x86_set_cr0(x); + + /* Init x87 */ + __asm__ __volatile__ ("finit"); + __asm__ __volatile__("fstcw %0" : "=m" (fcw)); +#if FPU_MASK_ALL_EXCEPTIONS + /* mask all exceptions */ + fcw |= 0x3f; +#else + /* unmask all exceptions */ + fcw &= 0xffc0; +#endif + __asm__ __volatile__("fldcw %0" : : "m" (fcw)); + + /* Init SSE */ + x = x86_get_cr4(); + x |= X86_CR4_OSXMMEXPT; + x |= X86_CR4_OSFXSR; + x &= ~X86_CR4_OSXSAVE; + x86_set_cr4(x); + + __asm__ __volatile__("stmxcsr %0" : "=m" (mxcsr)); +#if FPU_MASK_ALL_EXCEPTIONS + /* mask all exceptions */ + mxcsr = (0x3f << 7); +#else + /* unmask all exceptions */ + mxcsr &= 0x0000003f; +#endif + __asm__ __volatile__("ldmxcsr %0" : : "m" (mxcsr)); + + /* save fpu initial states, and used when new thread creates */ + /* TODO: construct this statically instead of making a copy from the state of the cpu here */ + __asm__ __volatile__("fxsave %0" : "=m" (fpu_init_states)); + + /* disable the fpu by default */ + set_fpu_enabled(false); +} + +void fpu_init_thread_states(thread_t *t) +{ + t->arch.fpu_states = (vaddr_t *)ROUNDUP(((vaddr_t)t->arch.fpu_buffer), 16); + memcpy(t->arch.fpu_states, fpu_init_states, sizeof(fpu_init_states)); +} + +static inline void set_fpu_enabled(bool enabled) +{ + DEBUG_ASSERT(arch_ints_disabled()); + + if (enabled) { + __asm__ volatile("clts"); + } else { + x86_set_cr0(x86_get_cr0() | X86_CR0_TS); + } +} + +static inline bool is_fpu_enabled(void) +{ + return !(x86_get_cr0() & X86_CR0_TS); +} + +void fpu_context_switch(thread_t *old_thread, thread_t *new_thread) +{ + if (unlikely(fp_supported == 0)) + return; + + if (is_fpu_enabled()) { + LTRACEF("need to save state on thread %s, state ptr %p\n", old_thread->name, old_thread->arch.fpu_states); + __asm__ __volatile__("fxsave %0" : "=m" (*old_thread->arch.fpu_states)); + set_fpu_enabled(false); + } +} + +void fpu_dev_na_handler(void) +{ + if (fp_supported == 0) + return; + + LTRACEF("thread %p '%s' cpu %u\n", get_current_thread(), get_current_thread()->name, arch_curr_cpu_num()); + + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(!is_fpu_enabled()); + + /* restore the thread fpu state */ + set_fpu_enabled(true); + thread_t *t = get_current_thread(); + __asm__ __volatile__("fxrstor %0" : : "m" (*t->arch.fpu_states)); +} + +/* End of file */ diff --git a/kernel/arch/x86/gdt.S b/kernel/arch/x86/gdt.S new file mode 100644 index 000000000..9ba5be271 --- /dev/null +++ b/kernel/arch/x86/gdt.S @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#define PHYS_LOAD_ADDRESS (MEMBASE + KERNEL_LOAD_OFFSET) +#define PHYS_ADDR_DELTA (KERNEL_BASE + KERNEL_LOAD_OFFSET - PHYS_LOAD_ADDRESS) +#define PHYS(x) ((x) - PHYS_ADDR_DELTA) + +.section .rodata + +.align 8 +DATA(_gdtr_phys) + .short _gdt_end - _gdt - 1 + .int PHYS(_gdt) + +.align 8 +DATA(_gdtr) + .short _gdt_end - _gdt - 1 +#if ARCH_X86_32 + .int _gdt +#elif ARCH_X86_64 + .quad _gdt +#endif + +.data +.align 8 +DATA(_gdt) + /* null entry */ + .int 0 + .int 0 + + /* CODE_SELECTOR */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */ + .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */ + .byte 0x0 /* base 31:24 */ + + /* CODE_64_SELECTOR */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */ + .byte 0b10101111 /* G(1) D(0) L(1) AVL(0) limit 19:16 */ + .byte 0x0 /* base 31:24 */ + + /* DATA_SELECTOR */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */ + .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */ + .byte 0x0 /* base 31:24 */ + + /* USER_CODE_SELECTOR */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */ + .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */ + .byte 0x0 /* base 31:24 */ + + /* USER_DATA_SELECTOR */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */ + .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */ + .byte 0x0 /* base 31:24 */ + + /* USER_CODE_64_SELECTOR */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */ + .byte 0b10101111 /* G(1) D(0) L(1) AVL(0) limit 19:16 */ + .byte 0x0 /* base 31:24 */ + +.rept SMP_MAX_CPUS + /* TSS_SELECTORs */ + .short 0 /* limit 15:00 */ + .short 0 /* base 15:00 */ + .byte 0 /* base 23:16 */ + .byte 0b10001001 /* P(1) DPL(00) 0 10 B(0) 1 */ + .byte 0b10000000 /* G(1) 0 0 AVL(0) limit 19:16 */ + .byte 0 /* base 31:24 */ + /* second half of 64bit desciptor */ + .int 0x00000000 /* base 63:32 */ + .int 0x00000000 /* reserved/sbz */ +.endr + +END(_gdt) + +DATA(_gdt_end) + diff --git a/kernel/arch/x86/header.S b/kernel/arch/x86/header.S new file mode 100644 index 000000000..b8837c1c7 --- /dev/null +++ b/kernel/arch/x86/header.S @@ -0,0 +1,302 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#define MULTIBOOT_HEADER_FLAGS 0x00010002 + +.section ".text.header" +.code16 + +.align 4 + +FUNCTION(_setup_start) + + /* screen_info 0x000-0x040 struct screen_info */ + .org 0x040 + /* apm_bios_info 0x040-0x054 struct apm_bios_info */ + .org 0x054 + /* padding */ + .org 0x058 + /* tboot_addr 0x058-0x060 */ + .org 0x060 + /* ist_info 0x060-0x070 struct ist_info */ + .org 0x070 + /* padding */ + .org 0x080 + /* hd0_info 0x080-0x090 (obsolete) */ + .org 0x090 + /* hd1_info 0x090-0x0A0 (obsolete) */ + .org 0x0A0 + /* sys_desc_table 0x0A0-0x0B0 struct sys_desc_table */ + .org 0x0B0 + /* olpc_ofw_header 0x0B0-0x0C0 */ + .org 0x0C0 + /* ext_ramdisk_image 0x0C0-0x0C4 */ + .org 0x0C4 + /* ext_ramdisk_size 0x0C4-0x0C8 */ + .org 0x0C8 + /* ext_cmd_line_ptr 0x0C8-0x0CC */ + .org 0x0CC + /* padding */ + .org 0x140 + /* edid_info 0x140-0x1C0 struct edid_info */ + .org 0x1C0 + /* efi_info 0x1C0-0x1E0 struct efi_info */ + .org 0x1E0 + /* alk_mem_k 0x1E0-0x1E4 */ + .org 0x1E4 + /* scratch 0x1E4-0x1E8 */ + .org 0x1E8 + /* e820_entries 0x1E8-0x1E9 */ +e820_entries: + .byte 0 + /* eddbuf_entries 0x1E9-0x1EA */ + .org 0x1EA + /* edd_mbr_sig_buf_entries 0x1EA-0x1EB */ + .org 0x1EB + /* kbd_status 0x1EB-0x1EC */ + .org 0x1EC + /* padding */ + .org 0x1EF + /* sentinel 0x1EF-0x1F0 */ + .org 0x1F0 + /* padding */ + .org 0x1F1 + /* hdr 0x1F1-0x268 */ + /* setup_sects */ + .byte (((_setup_end - _setup_start) >> 9) - 1) + /* root_flags */ + .short 0 + /* syssize */ + .int _zero_page_sys_size + /* ram_size */ + .short 0 + /* vid_mode */ + .short 0 + /* root_dev */ + .short 0 + /* boot_flag */ + .short 0xAA55 + /* jump */ + .byte 0xEB, end_of_setup_header - 0f +0: + /* header */ + .ascii "HdrS" + /* version */ + .short 0x020C + /* realmode_swtch */ + .int 0 + /* start_sys (obsolete) */ + .short 0x1000 + /* kernel_version */ + .short 0 + /* type_of_loader */ + .byte 0 + /* loadflags */ + .byte 0x01 + /* setup_move_size */ + .short 0 + /* code32_start */ + .int PHYS(_protected_start) + /* ramdisk_image */ + .int 0 + /* ramdisk_size */ + .int 0 + /* bootsect_kludge (obsolete) */ + .int 0 + /* heap_end_ptr */ + .short 0 + /* ext_loader_ver */ + .byte 0 + /* ext_loader_type */ + .byte 0 + /* cmd_line_ptr */ + .int 0 + /* initrd_addr_max */ + .int 0x7fffffff + /* kernel_alignment */ + .int 0x200000 + /* relocatable_kernel */ + .byte 0 + /* min_alignment */ + .byte 8 + /* xloadflags */ + .short 0 + /* cmdline_size */ + .int 2048 + /* hardware_subarch */ + .int 0 + /* hardware_subarch_data */ + .quad 0 + /* payload_offset */ + .int 0 + /* payload_length */ + .int 0 + /* setup_data */ + .quad 0 + /* pref_address */ + .long PHYS(_protected_start) + .long 0 + /* init_size */ + .long 0 + /* handover_offset */ + .long 0 +end_of_setup_header: + jmp end_of_zero_page +0: + /* padding */ + .org 0x290 + /* edd_mbr_sig_buffer 0x290-0x2D0 */ + .org 0x2D0 + /* e820_map 0x2D0-0xCD0 */ +e820_map: + .org 0xCD0 + /* padding */ + .org 0xD00 + /* eddbuf 0xD00-0xEEC */ + .org 0xEEC + /* padding */ + .org 0x1000 + +end_of_zero_page: + /* gather e820 information if it wasn't provided */ + cmpw $0, (e820_entries - _setup_start) + jne e820_loop_end + + /* %ebx is the "continuation value" and should start out as zero */ + mov $0, %ebx + /* set %es:%edi to point at the e820 map */ + mov $(e820_map - _setup_start), %edi + +e820_loop: + + /* request the e820 function of int 15 */ + mov $0xe820, %eax + /* write at most 20 bytes of data at %es:%edi */ + mov $20, %ecx + /* 'SMAP' to prove we're really asking for e820 data */ + mov $0x534d4150, %edx + + /* call the interrupt routine */ + int $0x15 + + /* if carry was set, that's an error or passing the end of the map */ + jc e820_loop_end + /* if %eax is not now equal to SMAP, then this BIOS doesn't support e820 */ + cmp $0x534d4150, %eax + jne e820_loop_end + + /* if no data was written, skip this entry */ + jecxz e820_loop + /* if the length of the entry is zero, skip it */ + mov %es:8(%edi), %eax + or %es:12(%edi), %eax + cmp $0, %eax + je e820_loop + + /* increment the entry count and the map pointer */ + incb (e820_entries - _setup_start) + add %ecx, %edi + + /* if %ebx is now zero again, we just read the last entry */ + cmp $0, %ebx + je e820_loop_end + + /* go back around and request the next entry */ + jmp e820_loop +e820_loop_end: + + + /* load a temporary GDT to help us get into protected mode */ + lgdtl (_setup_gdtr - _setup_start) + + /* enable protected mode */ + mov %cr0, %eax + btsl $0, %eax + mov %eax, %cr0 + + /* use a long jump to load the protected mode code descriptor */ + ljmpl $0x08,$0f +0: + + .code32 + + /* clear out the real mode segment state */ + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %ss + movw %ax, %gs + movw %ax, %ss + + /* %esi should point to the start of the boot_params structure */ + movl $_setup_start, %esi + + /* jump into the protected mode part of the kernel */ + jmp PHYS(_protected_start) + + /* an abridged copy of the gdt for use in real mode */ +.align 8 +_setup_gdtr: + .short _setup_gdt_end - _setup_gdt - 1 + .int _setup_gdt + +.align 8 +_setup_gdt: + .int 0 + .int 0 + + /* 32 bit CPL 0 code segment */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */ + .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */ + .byte 0x0 /* base 31:24 */ + + /* 32 bit CPL 0 data segment */ + .short 0xffff /* limit 15:00 */ + .short 0x0000 /* base 15:00 */ + .byte 0x00 /* base 23:16 */ + .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */ + .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */ + .byte 0x0 /* base 31:24 */ + +_setup_gdt_end: + +.align 8 +.type _multiboot_header,STT_OBJECT +_multiboot_header: + /* magic */ + .int MULTIBOOT_HEADER_MAGIC + /* flags */ + .int MULTIBOOT_HEADER_FLAGS + /* checksum */ + .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + + /* header_addr */ + .int PHYS_LOAD_ADDRESS - PHYS_HEADER_LOAD_OFFSET + (_multiboot_header - _setup_start) + /* load_addr */ + .int PHYS_LOAD_ADDRESS - PHYS_HEADER_LOAD_OFFSET + /* load_end_addr */ + .int PHYS(__data_end) + /* bss_end_addr */ + .int PHYS(__bss_end) + /* entry_addr */ + .int PHYS(_multiboot_start) + +.align 4096 + +_setup_end: diff --git a/kernel/arch/x86/idt.c b/kernel/arch/x86/idt.c new file mode 100644 index 000000000..337a81301 --- /dev/null +++ b/kernel/arch/x86/idt.c @@ -0,0 +1,110 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +#include +#include +#include +#include +#include + +// The size of the `clac` instruction +#define CLAC_SIZE 3 + +// Early boot shared IDT structure +struct idt _idt; +struct idtr _idtr = { .limit = sizeof(_idt) - 1, .address = (uintptr_t)&_idt }; + +static inline void idt_set_segment_sel(struct idt_entry *entry, uint16_t sel) +{ + entry->w0 = (entry->w0 & 0x0000ffff) | (sel << 16); +} + +static inline void idt_set_offset(struct idt_entry *entry, uintptr_t offset) +{ + uint32_t low_16 = offset & 0xffff; + uint32_t mid_16 = (offset >> 16) & 0xffff; + entry->w0 = (entry->w0 & 0xffff0000) | low_16; + entry->w1 = (entry->w1 & 0x0000ffff) | (mid_16 << 16); + #ifdef ARCH_X86_64 + uint32_t high_32 = offset >> 32; + entry->w2 = high_32; + #endif +} + +static inline void idt_set_present(struct idt_entry *entry, bool present) +{ + entry->w1 = (entry->w1 & ~(1 << 15)) | ((!!present) << 15); +} + +static inline void idt_set_dpl(struct idt_entry *entry, enum idt_dpl dpl) +{ + ASSERT(dpl <= 3); + entry->w1 = (entry->w1 & ~(3 << 13)) | ((uint32_t)dpl << 13); +} + +static inline void idt_set_type( + struct idt_entry *entry, + enum idt_entry_type typ) +{ + entry->w1 = (entry->w1 & ~(0xf << 8)) | ((uint32_t)typ << 8); +} + +void idt_set_vector( + struct idt *idt, + uint8_t vec, + uint16_t code_segment_sel, + uintptr_t entry_point_offset, + enum idt_dpl dpl, + enum idt_entry_type typ) +{ + struct idt_entry *entry = &idt->entries[vec]; + memset(entry, 0, sizeof(*entry)); + idt_set_segment_sel(entry, code_segment_sel); + idt_set_offset(entry, entry_point_offset); + idt_set_type(entry, typ); + idt_set_dpl(entry, dpl); + idt_set_present(entry, true); +} + +#ifdef ARCH_X86_64 +void idt_set_ist_index(struct idt *idt, uint8_t vec, uint8_t ist_idx) +{ + ASSERT(ist_idx < 8); + struct idt_entry *entry = &idt->entries[vec]; + entry->w1 = (entry->w1 & ~0x7) | ist_idx; +} +#endif + +void idt_setup(struct idt *idt) +{ + extern uintptr_t _isr_table; + uintptr_t *isrs = &_isr_table; + + // If SMAP is not available, we need to skip past the CLAC instruction + // at the beginning of the ISR stubs. + int clac_shift = 0; + if (!x86_feature_test(X86_FEATURE_SMAP)) { + clac_shift += CLAC_SIZE; + } + + uint16_t sel; + enum idt_entry_type typ; +#ifdef ARCH_X86_64 + sel = CODE_64_SELECTOR; + typ = IDT_INTERRUPT_GATE64; +#else + sel = CODE_SELECTOR; + typ = IDT_INTERRUPT_GATE32; +#endif + for (unsigned int i = 0; i < countof(idt->entries); ++i) { + uintptr_t offset = isrs[i] + clac_shift; + idt_set_vector(idt, i, sel, offset, IDT_DPL0, typ); + } +} diff --git a/kernel/arch/x86/include/arch/arch_ops.h b/kernel/arch/x86/include/arch/arch_ops.h new file mode 100644 index 000000000..482fc9f86 --- /dev/null +++ b/kernel/arch/x86/include/arch/arch_ops.h @@ -0,0 +1,75 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#ifndef ASSEMBLY + +#include +#include + +__BEGIN_CDECLS + +/* override of some routines */ +static inline void arch_enable_ints(void) +{ + CF; + __asm__ volatile("sti"); +} + +static inline void arch_disable_ints(void) +{ + __asm__ volatile("cli"); + CF; +} + +static inline bool arch_ints_disabled(void) +{ + x86_flags_t state; + + __asm__ volatile( +#if ARCH_X86_32 + "pushfl;" + "popl %%eax" +#elif ARCH_X86_64 + "pushfq;" + "popq %%rax" +#endif + : "=a" (state) + :: "memory"); + + return !(state & (1<<9)); +} + +static inline uint32_t arch_cycle_count(void) +{ + return (rdtsc() & 0xffffffff); +} + +static inline void arch_spinloop_pause(void) +{ + __asm__ volatile("pause"); +} + +static inline void arch_spinloop_signal(void) +{ +} + +#define mb() __asm__ volatile ("mfence") +#define wmb() __asm__ volatile ("sfence") +#define rmb() __asm__ volatile ("lfence") + +#define smp_mb() mb() +#define smp_wmb() wmb() +#define smp_rmb() rmb() + +__END_CDECLS + +#endif // !ASSEMBLY diff --git a/kernel/arch/x86/include/arch/arch_thread.h b/kernel/arch/x86/include/arch/arch_thread.h new file mode 100644 index 000000000..82e27b262 --- /dev/null +++ b/kernel/arch/x86/include/arch/arch_thread.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +struct arch_thread { + vaddr_t sp; +#if ARCH_X86_64 + vaddr_t fs_base; + vaddr_t gs_base; +#endif + + /* buffer to save fpu state */ + vaddr_t *fpu_states; + uint8_t fpu_buffer[512 + 16]; + + /* if non-NULL, address to return to on page fault */ + void *page_fault_resume; +}; + +__END_CDECLS diff --git a/kernel/arch/x86/include/arch/aspace.h b/kernel/arch/x86/include/arch/aspace.h new file mode 100644 index 000000000..a365d80ea --- /dev/null +++ b/kernel/arch/x86/include/arch/aspace.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +#define ARCH_ASPACE_MAGIC 0x41524153 // ARAS + +struct arch_aspace { + /* magic value for use-after-free detection */ + uint32_t magic; + + /* pointer to the translation table */ + paddr_t pt_phys; + pt_entry_t *pt_virt; + + uint flags; + + /* range of address space */ + vaddr_t base; + size_t size; + + /* if not NULL, pointer to the port IO permissions for this address space */ + void *io_bitmap_ptr; + spin_lock_t io_bitmap_lock; +}; + +__END_CDECLS + diff --git a/kernel/arch/x86/include/arch/defines.h b/kernel/arch/x86/include/arch/defines.h new file mode 100644 index 000000000..d0cb1666c --- /dev/null +++ b/kernel/arch/x86/include/arch/defines.h @@ -0,0 +1,18 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#define PAGE_SIZE 4096 +#define PAGE_SIZE_SHIFT 12 + +#define CACHE_LINE 32 + +#define ARCH_DEFAULT_STACK_SIZE 8192 +#define DEFAULT_TSS 4096 + diff --git a/kernel/arch/x86/include/arch/fpu.h b/kernel/arch/x86/include/arch/fpu.h new file mode 100644 index 000000000..286eb64f8 --- /dev/null +++ b/kernel/arch/x86/include/arch/fpu.h @@ -0,0 +1,24 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +void fpu_init(void); +void fpu_init_thread_states(thread_t *t); +void fpu_context_switch(thread_t *old_thread, thread_t *new_thread); + +/* called during a #NA exception */ +void fpu_dev_na_handler(void); + +__END_CDECLS + +/* End of file */ diff --git a/kernel/arch/x86/include/arch/spinlock.h b/kernel/arch/x86/include/arch/spinlock.h new file mode 100644 index 000000000..98130c367 --- /dev/null +++ b/kernel/arch/x86/include/arch/spinlock.h @@ -0,0 +1,83 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +__BEGIN_CDECLS + +#define SPIN_LOCK_INITIAL_VALUE (0) + +typedef unsigned long spin_lock_t; + +typedef x86_flags_t spin_lock_saved_state_t; +typedef uint spin_lock_save_flags_t; + +#if WITH_SMP +static inline void arch_spin_lock_init(spin_lock_t *lock) +{ + *lock = SPIN_LOCK_INITIAL_VALUE; +} + +static inline bool arch_spin_lock_held(spin_lock_t *lock) +{ + return *lock != 0; +} + +void arch_spin_lock(spin_lock_t *lock); +int arch_spin_trylock(spin_lock_t *lock); +void arch_spin_unlock(spin_lock_t *lock); +#else +/* simple implementation of spinlocks for no smp support */ +static inline void arch_spin_lock_init(spin_lock_t *lock) +{ + *lock = SPIN_LOCK_INITIAL_VALUE; +} + +static inline bool arch_spin_lock_held(spin_lock_t *lock) +{ + return *lock != 0; +} + +static inline void arch_spin_lock(spin_lock_t *lock) +{ + *lock = 1; +} + +static inline int arch_spin_trylock(spin_lock_t *lock) +{ + return 0; +} + +static inline void arch_spin_unlock(spin_lock_t *lock) +{ + *lock = 0; +} +#endif // WITH_SMP + +/* flags are unused on x86 */ +#define ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS 0 + +static inline void +arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) +{ + *statep = x86_save_flags(); + arch_disable_ints(); +} + +static inline void +arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) +{ + x86_restore_flags(old_state); +} + +__END_CDECLS + diff --git a/kernel/arch/x86/include/arch/x86.h b/kernel/arch/x86/include/arch/x86.h new file mode 100644 index 000000000..371b4eec1 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86.h @@ -0,0 +1,655 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +#include + +__BEGIN_CDECLS + +#define X86_8BYTE_MASK 0xFFFFFFFF + +struct x86_32_iframe { + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pushed by common handler using pusha + uint32_t ds, es, fs, gs; // pushed by common handler + uint32_t vector; // pushed by stub + uint32_t err_code; // pushed by interrupt or stub + uint32_t ip, cs, flags; // pushed by interrupt + uint32_t user_sp, user_ss; // pushed by interrupt if priv change occurs +}; + +struct x86_64_iframe { + uint64_t rdi, rsi, rbp, rbx, rdx, rcx, rax; // pushed by common handler + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; // pushed by common handler + uint64_t vector; // pushed by stub + uint64_t err_code; // pushed by interrupt or stub + uint64_t ip, cs, flags; // pushed by interrupt + uint64_t user_sp, user_ss; // pushed by interrupt +}; + +#if ARCH_X86_32 +typedef struct x86_32_iframe x86_iframe_t; +#elif ARCH_X86_64 +typedef struct x86_64_iframe x86_iframe_t; +#endif + +struct x86_32_context_switch_frame { + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; + uint32_t eflags; + uint32_t eip; +}; + +struct x86_64_context_switch_frame { + uint64_t r15, r14, r13, r12; + uint64_t rbp; + uint64_t rbx; + uint64_t rflags; + uint64_t rip; +}; + +void x86_64_context_switch(vaddr_t *oldsp, vaddr_t newsp); +void x86_uspace_entry( + void *thread_arg, + vaddr_t ustack, + uint64_t rflags, + vaddr_t entry_point) __NO_RETURN; + +/* @brief Bring all of the APs up and hand them over to the kernel + * + * Must be called on the BP + * + * @param apic_ids A list of all APIC IDs that correspond to cores that should + * be running. The BP should be in the list. + * @param num_cpus The number of entries in the apic_ids list. + */ +void x86_bringup_smp(uint32_t *apic_ids, uint32_t num_cpus); + +#define IO_BITMAP_BITS 65536 +#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8) +#define IO_BITMAP_LONGS (IO_BITMAP_BITS/sizeof(long)) + +/* + * x86-32 TSS structure + */ +typedef struct { + uint16_t backlink, __blh; + uint32_t esp0; + uint16_t ss0, __ss0h; + uint32_t esp1; + uint16_t ss1, __ss1h; + uint32_t esp2; + uint16_t ss2, __ss2h; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax, ecx, edx, ebx; + uint32_t esp, ebp, esi, edi; + uint16_t es, __esh; + uint16_t cs, __csh; + uint16_t ss, __ssh; + uint16_t ds, __dsh; + uint16_t fs, __fsh; + uint16_t gs, __gsh; + uint16_t ldt, __ldth; + uint16_t trace, bitmap; + + uint8_t tss_bitmap[IO_BITMAP_BYTES + 1]; +} __PACKED tss_32_t; + +/* + * Assignment of Interrupt Stack Table entries + */ +#define NUM_ASSIGNED_IST_ENTRIES 3 +#define NMI_IST_INDEX 1 +#define MCE_IST_INDEX 2 +#define DBF_IST_INDEX 3 + +/* + * x86-64 TSS structure + */ +typedef struct { + uint32_t rsvd0; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint32_t rsvd1; + uint32_t rsvd2; + uint64_t ist1; + uint64_t ist2; + uint64_t ist3; + uint64_t ist4; + uint64_t ist5; + uint64_t ist6; + uint64_t ist7; + uint32_t rsvd3; + uint32_t rsvd4; + uint16_t rsvd5; + uint16_t iomap_base; + + uint8_t tss_bitmap[IO_BITMAP_BYTES + 1]; +} __PACKED tss_64_t; + +#if ARCH_X86_32 +typedef tss_32_t tss_t; +#elif ARCH_X86_64 +typedef tss_64_t tss_t; +#endif + +/* shared accessors between 32 and 64bit */ +static inline void x86_clts(void) {__asm__ __volatile__ ("clts"); } +static inline void x86_hlt(void) {__asm__ __volatile__ ("hlt"); } +static inline void x86_sti(void) {__asm__ __volatile__ ("sti"); } +static inline void x86_cli(void) {__asm__ __volatile__ ("cli"); } +static inline void x86_ltr(uint16_t sel) +{ + __asm__ __volatile__ ("ltr %%ax" :: "a" (sel)); +} +static inline void x86_lidt(uintptr_t base) +{ + __asm volatile("lidt (%0)" :: "r"(base) : "memory"); +} + +static inline uint8_t inp(uint16_t _port) +{ + uint8_t rv; + __asm__ __volatile__ ("inb %1, %0" + : "=a" (rv) + : "d" (_port)); + return (rv); +} + +static inline uint16_t inpw (uint16_t _port) +{ + uint16_t rv; + __asm__ __volatile__ ("inw %1, %0" + : "=a" (rv) + : "d" (_port)); + return (rv); +} + +static inline uint32_t inpd(uint16_t _port) +{ + uint32_t rv; + __asm__ __volatile__ ("inl %1, %0" + : "=a" (rv) + : "d" (_port)); + return (rv); +} + +static inline void outp(uint16_t _port, uint8_t _data) +{ + __asm__ __volatile__ ("outb %1, %0" + : + : "d" (_port), + "a" (_data)); +} + +static inline void outpw(uint16_t _port, uint16_t _data) +{ + __asm__ __volatile__ ("outw %1, %0" + : + : "d" (_port), + "a" (_data)); +} + +static inline void outpd(uint16_t _port, uint32_t _data) +{ + __asm__ __volatile__ ("outl %1, %0" + : + : "d" (_port), + "a" (_data)); +} + +static inline uint64_t rdtsc(void) +{ + uint64_t tsc; + +#if ARCH_X86_64 + uint32_t tsc_low; + uint32_t tsc_hi; + + __asm__ __volatile__("rdtsc" : "=a" (tsc_low), "=d" (tsc_hi)); + + tsc = ((uint64_t)tsc_hi << 32) | tsc_low; +#else + __asm__ __volatile__("rdtsc" : "=A" (tsc)); +#endif + + return tsc; +} + +static inline void cpuid(uint32_t sel, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) +{ + *a = sel; + + __asm__ __volatile__("cpuid" + : "+a" (*a), "=c" (*c), "=d" (*d), "=b"(*b) + ); +} + +/* cpuid wrapper with ecx set to a second argument */ +static inline void cpuid_c(uint32_t sel, uint32_t sel_c, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) +{ + *a = sel; + *c = sel_c; + + __asm__ __volatile__("cpuid" + : "+a" (*a), "+c" (*c), "=d" (*d), "=b"(*b) + ); +} + +static inline void set_in_cr0(ulong mask) +{ + ulong temp; + + __asm__ __volatile__ ( + "mov %%cr0, %0 \n\t" + "or %1, %0 \n\t" + "mov %0, %%cr0 \n\t" + : "=r" (temp) : "irg" (mask) + :); +} + +static inline void clear_in_cr0(ulong mask) +{ + ulong temp; + + __asm__ __volatile__ ( + "mov %%cr0, %0 \n\t" + "and %1, %0 \n\t" + "mov %0, %%cr0 \n\t" + : "=r" (temp) : "irg" (~mask) + :); +} + +static inline ulong x86_get_cr2(void) +{ + ulong rv; + + __asm__ __volatile__ ( + "mov %%cr2, %0" + : "=r" (rv) + ); + + return rv; +} + +static inline ulong x86_get_cr3(void) +{ + ulong rv; + + __asm__ __volatile__ ( + "mov %%cr3, %0" + : "=r" (rv)); + return rv; +} + +static inline void x86_set_cr3(ulong in_val) +{ + __asm__ __volatile__ ( + "mov %0,%%cr3 \n\t" + : + :"r" (in_val)); +} + +static inline ulong x86_get_cr0(void) +{ + ulong rv; + + __asm__ __volatile__ ( + "mov %%cr0, %0 \n\t" + : "=r" (rv)); + return rv; +} + +static inline ulong x86_get_cr4(void) +{ + ulong rv; + + __asm__ __volatile__ ( + "mov %%cr4, %0 \n\t" + : "=r" (rv)); + return rv; +} + + +static inline void x86_set_cr0(ulong in_val) +{ + __asm__ __volatile__ ( + "mov %0,%%cr0 \n\t" + : + :"r" (in_val)); +} + +static inline void x86_set_cr4(ulong in_val) +{ + __asm__ __volatile__ ( + "mov %0,%%cr4 \n\t" + : + :"r" (in_val)); +} + +static inline uint64_t read_msr (uint32_t msr_id) +{ +#if ARCH_X86_64 + uint32_t msr_read_val_lo; + uint32_t msr_read_val_hi; + + __asm__ __volatile__ ( + "rdmsr \n\t" + : "=a" (msr_read_val_lo), "=d" (msr_read_val_hi) + : "c" (msr_id)); + + return ((uint64_t)msr_read_val_hi << 32) | msr_read_val_lo; +#else + /* =A doesn't seem to work properly on x86-64 */ + uint64_t msr_read_val; + __asm__ __volatile__ ( + "rdmsr \n\t" + : "=A" (msr_read_val) + : "c" (msr_id)); + + return msr_read_val; +#endif +} + +static inline void write_msr (uint32_t msr_id, uint64_t msr_write_val) +{ +#if ARCH_X86_64 + __asm__ __volatile__ ( + "wrmsr \n\t" + : : "c" (msr_id), "a" (msr_write_val & 0xffffffff), "d" (msr_write_val >> 32)); +#else + __asm__ __volatile__ ( + "wrmsr \n\t" + : : "c" (msr_id), "A" (msr_write_val)); +#endif +} + + +static inline bool x86_is_paging_enabled(void) +{ + if (x86_get_cr0() & X86_CR0_PG) + return true; + + return false; +} + +static inline bool x86_is_PAE_enabled(void) +{ + if (x86_is_paging_enabled() == false) + return false; + + if (!(x86_get_cr4() & X86_CR4_PAE)) + return false; + + return true; +} + +static inline ulong x86_read_gs_offset(uintptr_t offset) +{ + ulong ret; + + __asm__( + "mov %%gs:%1, %0" + : "=r" (ret) + : "m" (*(ulong *)(offset)) + : + ); + + return ret; +} + +static inline void x86_write_gs_offset(uintptr_t offset, ulong val) +{ + __asm__( + "mov %0, %%gs:%1" + : + : "r" (val), "m" (*(ulong *)(offset)) + : "memory" + ); +} + + +#if ARCH_X86_32 + +typedef uint32_t x86_flags_t; + +static inline uint32_t x86_save_flags(void) +{ + unsigned int state; + + __asm__ volatile( + "pushfl;" + "popl %0" + : "=rm" (state) + :: "memory"); + + return state; +} + +static inline void x86_restore_flags(uint32_t flags) +{ + __asm__ volatile( + "pushl %0;" + "popfl" + :: "g" (flags) + : "memory", "cc"); +} + +static inline void inprep(uint16_t _port, uint8_t *_buffer, uint32_t _reads) +{ + __asm__ __volatile__ ("pushal \n\t" + "pushfl \n\t" + "cli \n\t" + "cld \n\t" + "rep insb \n\t" + "popfl \n\t" + "popal" + : + : "d" (_port), + "D" (_buffer), + "c" (_reads)); +} + +static inline void outprep(uint16_t _port, uint8_t *_buffer, uint32_t _writes) +{ + __asm__ __volatile__ ("pushal \n\t" + "pushfl \n\t" + "cli \n\t" + "cld \n\t" + "rep outsb \n\t" + "popfl \n\t" + "popal" + : + : "d" (_port), + "S" (_buffer), + "c" (_writes)); +} + +static inline void inpwrep(uint16_t _port, uint16_t *_buffer, uint32_t _reads) +{ + __asm__ __volatile__ ("pushal \n\t" + "pushfl \n\t" + "cli \n\t" + "cld \n\t" + "rep insw \n\t" + "popfl \n\t" + "popal" + : + : "d" (_port), + "D" (_buffer), + "c" (_reads)); +} + +static inline void outpwrep(uint16_t _port, uint16_t *_buffer, + uint32_t _writes) +{ + __asm__ __volatile__ ("pushal \n\t" + "pushfl \n\t" + "cli \n\t" + "cld \n\t" + "rep outsw \n\t" + "popfl \n\t" + "popal" + : + : "d" (_port), + "S" (_buffer), + "c" (_writes)); +} + +static inline void inpdrep(uint16_t _port, uint32_t *_buffer, + uint32_t _reads) +{ + __asm__ __volatile__ ("pushal \n\t" + "pushfl \n\t" + "cli \n\t" + "cld \n\t" + "rep insl \n\t" + "popfl \n\t" + "popal" + : + : "d" (_port), + "D" (_buffer), + "c" (_reads)); +} + +static inline void outpdrep(uint16_t _port, uint32_t *_buffer, + uint32_t _writes) +{ + __asm__ __volatile__ ("pushal \n\t" + "pushfl \n\t" + "cli \n\t" + "cld \n\t" + "rep outsl \n\t" + "popfl \n\t" + "popal" + : + : "d" (_port), + "S" (_buffer), + "c" (_writes)); +} + +#endif // ARCH_X86_32 + +#if ARCH_X86_64 + +typedef uint64_t x86_flags_t; + +static inline uint64_t x86_save_flags(void) +{ + uint64_t state; + + __asm__ volatile( + "pushfq;" + "popq %0" + : "=rm" (state) + :: "memory"); + + return state; +} + +static inline void x86_restore_flags(uint64_t flags) +{ + __asm__ volatile( + "pushq %0;" + "popfq" + :: "g" (flags) + : "memory", "cc"); +} + +static inline void inprep(uint16_t _port, uint8_t *_buffer, uint32_t _reads) +{ + __asm__ __volatile__ ("pushfq \n\t" + "cli \n\t" + "cld \n\t" + "rep insb \n\t" + "popfq \n\t" + : + : "d" (_port), + "D" (_buffer), + "c" (_reads)); +} + +static inline void outprep(uint16_t _port, uint8_t *_buffer, uint32_t _writes) +{ + __asm__ __volatile__ ("pushfq \n\t" + "cli \n\t" + "cld \n\t" + "rep outsb \n\t" + "popfq \n\t" + : + : "d" (_port), + "S" (_buffer), + "c" (_writes)); +} + +static inline void inpwrep(uint16_t _port, uint16_t *_buffer, uint32_t _reads) +{ + __asm__ __volatile__ ("pushfq \n\t" + "cli \n\t" + "cld \n\t" + "rep insw \n\t" + "popfq \n\t" + : + : "d" (_port), + "D" (_buffer), + "c" (_reads)); +} + +static inline void outpwrep(uint16_t _port, uint16_t *_buffer, + uint32_t _writes) +{ + __asm__ __volatile__ ("pushfq \n\t" + "cli \n\t" + "cld \n\t" + "rep outsw \n\t" + "popfq \n\t" + : + : "d" (_port), + "S" (_buffer), + "c" (_writes)); +} + +static inline void inpdrep(uint16_t _port, uint32_t *_buffer, + uint32_t _reads) +{ + __asm__ __volatile__ ("pushfq \n\t" + "cli \n\t" + "cld \n\t" + "rep insl \n\t" + "popfq \n\t" + : + : "d" (_port), + "D" (_buffer), + "c" (_reads)); +} + +static inline void outpdrep(uint16_t _port, uint32_t *_buffer, + uint32_t _writes) +{ + __asm__ __volatile__ ("pushfq \n\t" + "cli \n\t" + "cld \n\t" + "rep outsl \n\t" + "popfq \n\t" + : + : "d" (_port), + "S" (_buffer), + "c" (_writes)); +} + +#endif // ARCH_X86_64 + +__END_CDECLS diff --git a/kernel/arch/x86/include/arch/x86/apic.h b/kernel/arch/x86/include/arch/x86/apic.h new file mode 100644 index 000000000..b12b00858 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/apic.h @@ -0,0 +1,132 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +#define INVALID_APIC_ID 0xffffffff + +enum apic_interrupt_delivery_mode { + // Unless you know what you're doing, you want FIXED. + DELIVERY_MODE_FIXED = 0, + DELIVERY_MODE_LOWEST_PRI = 1, + DELIVERY_MODE_SMI = 2, + DELIVERY_MODE_NMI = 4, + DELIVERY_MODE_INIT = 5, + DELIVERY_MODE_STARTUP = 6, + DELIVERY_MODE_EXT_INT = 7, +}; + +enum apic_interrupt_dst_mode { + DST_MODE_PHYSICAL = 0, + DST_MODE_LOGICAL = 1, +}; + +// Functionality provided by the local APIC +void apic_vm_init(void); +void apic_local_init(void); +uint8_t apic_local_id(void); +void apic_irq_set(unsigned int vector, bool enable); +void apic_send_ipi( + uint8_t vector, + uint8_t dst_apic_id, + enum apic_interrupt_delivery_mode dm); +void apic_send_self_ipi(uint8_t vector, enum apic_interrupt_delivery_mode dm); +void apic_send_broadcast_ipi( + uint8_t vector, + enum apic_interrupt_delivery_mode dm); +void apic_send_broadcast_self_ipi( + uint8_t vector, + enum apic_interrupt_delivery_mode dm); +void apic_issue_eoi(void); + +status_t apic_timer_set_oneshot(uint32_t count, uint8_t divisor, bool masked); +status_t apic_timer_set_periodic(uint32_t count, uint8_t divisor); +uint32_t apic_timer_current_count(void); +void apic_timer_mask(void); +void apic_timer_unmask(void); +void apic_timer_stop(void); + +enum handler_return apic_error_interrupt_handler(void); +enum handler_return apic_timer_interrupt_handler(void); + +// Information about the system IO APICs +struct io_apic_descriptor { + uint8_t apic_id; + // virtual IRQ base for ACPI + uint32_t global_irq_base; + // Physical address of the base of this IOAPIC's MMIO + paddr_t paddr; +}; + +enum io_apic_irq_trigger_mode { + IRQ_TRIGGER_MODE_EDGE = 0, + IRQ_TRIGGER_MODE_LEVEL = 1, +}; + +enum io_apic_irq_polarity { + IRQ_POLARITY_ACTIVE_HIGH = 0, + IRQ_POLARITY_ACTIVE_LOW = 1, +}; + +// Information describing an ISA override. An override can change the +// global IRQ number and/or change bus signaling characteristics +// for the specified ISA IRQ. +struct io_apic_isa_override { + uint8_t isa_irq; + bool remapped; + enum io_apic_irq_trigger_mode tm; + enum io_apic_irq_polarity pol; + uint32_t global_irq; +}; + +// Functionality provided by the IO APICs +#define IO_APIC_IRQ_MASK true +#define IO_APIC_IRQ_UNMASK false + +void apic_io_init( + struct io_apic_descriptor *io_apics_descs, + unsigned int num_io_apics, + struct io_apic_isa_override *overrides, + unsigned int num_overrides); +bool apic_io_is_valid_irq(uint32_t global_irq); +void apic_io_mask_irq(uint32_t global_irq, bool mask); +void apic_io_configure_irq( + uint32_t global_irq, + enum io_apic_irq_trigger_mode trig_mode, + enum io_apic_irq_polarity polarity, + enum apic_interrupt_delivery_mode del_mode, + bool mask, + enum apic_interrupt_dst_mode dst_mode, + uint8_t dst, + uint8_t vector); +void apic_io_configure_irq_vector( + uint32_t global_irq, + uint8_t vector); +uint8_t apic_io_fetch_irq_vector(uint32_t global_irq); + +void apic_io_mask_isa_irq(uint8_t isa_irq, bool mask); +// For ISA configuration, we don't need to specify the trigger mode +// and polarity since we initialize these to match the ISA bus or +// any overrides we've been told about. +void apic_io_configure_isa_irq( + uint8_t isa_irq, + enum apic_interrupt_delivery_mode del_mode, + bool mask, + enum apic_interrupt_dst_mode dst_mode, + uint8_t dst, + uint8_t vector); +void apic_io_issue_eoi(uint32_t global_irq, uint8_t vec); +uint32_t apic_io_isa_to_global(uint8_t isa_irq); + +void apic_local_debug(void); +void apic_io_debug(void); + +__END_CDECLS diff --git a/kernel/arch/x86/include/arch/x86/asm.h b/kernel/arch/x86/include/arch/x86/asm.h new file mode 100644 index 000000000..c475bd429 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/asm.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +/* x86 assembly macros used in a few files */ + +#define PHYS_LOAD_ADDRESS (MEMBASE + KERNEL_LOAD_OFFSET) +#define PHYS_ADDR_DELTA (KERNEL_BASE + KERNEL_LOAD_OFFSET - PHYS_LOAD_ADDRESS) +#define PHYS(x) ((x) - PHYS_ADDR_DELTA) + +/* zeros the bss for the kernel */ +/* trashes a lot of registers */ +.macro bss_setup + movl $PHYS(__bss_start), %edi /* starting address of the bss */ + movl $PHYS(__bss_end), %ecx /* find the length of the bss in bytes */ + subl %edi, %ecx + shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */ +0: + movl $0, (%edi) + addl $4, %edi + loop 0b +.endm + diff --git a/kernel/arch/x86/include/arch/x86/bootstrap16.h b/kernel/arch/x86/include/arch/x86/bootstrap16.h new file mode 100644 index 000000000..42c0a972d --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/bootstrap16.h @@ -0,0 +1,89 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#ifdef ARCH_X86_64 + +#define BCD_PHYS_BOOTSTRAP_PML4_OFFSET 0 +#define BCD_PHYS_KERNEL_PML4_OFFSET 4 +#define BCD_PHYS_GDTR_OFFSET 8 +#define BCD_PHYS_LM_ENTRY_OFFSET 20 +#define BCD_LM_CS_OFFSET 24 +#define BCD_CPU_COUNTER_OFFSET 28 +#define BCD_CPU_WAITING_OFFSET 32 +#define BCD_KSTACK_BASE_OFFSET 40 + +#ifndef ASSEMBLY +#include +#include + +__BEGIN_CDECLS + +#define PHYS_BOOTSTRAP_PAGE 0x9e000 + +// Markers for the application processor bootstrap code region +extern void x86_bootstrap16_start(void); +extern void x86_bootstrap16_end(void); + +// 64-bit entry points that bootstrap might transition to +extern void _x86_secondary_cpu_long_mode_entry(void); + +struct __PACKED x86_bootstrap16_data { + // Physical address of identity PML4 + uint32_t phys_bootstrap_pml4; + // Physical address of the kernel PML4 + uint32_t phys_kernel_pml4; + // Physical address of GDTR + uint8_t phys_gdtr[10]; + uint16_t __pad; + + // Ordering of these two matter; they should be usable by retfl + // Physical address of long mode entry point + uint32_t phys_long_mode_entry; + // 64-bit code segment to use + uint32_t long_mode_cs; +}; + +struct __PACKED x86_ap_bootstrap_data { + struct x86_bootstrap16_data hdr; + + // Counter for APs to use to determine CPU IDs + uint32_t cpu_id_counter; + // Pointer to value to use to determine when APs are done with boot + volatile int *cpu_waiting_counter; + // Virtual address of initial kstacks, one kstack per secondary cpu + uint64_t kstack_base[SMP_MAX_CPUS - 1]; +}; + +// Upon success, returns a pointer to the bootstrap aspace and to the +// virtual address of the bootstrap data. It is the caller's +// responsibility to free the aspace and unmap the aperature. +status_t x86_bootstrap16_prep( + paddr_t bootstrap_phys_addr, + uintptr_t entry64, + vmm_aspace_t **temp_aspace, + void **bootstrap_aperature); + +STATIC_ASSERT(sizeof(struct x86_ap_bootstrap_data) <= PAGE_SIZE); +STATIC_ASSERT(__offsetof(struct x86_bootstrap16_data, phys_bootstrap_pml4) == BCD_PHYS_BOOTSTRAP_PML4_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_bootstrap16_data, phys_kernel_pml4) == BCD_PHYS_KERNEL_PML4_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_bootstrap16_data, phys_gdtr) == BCD_PHYS_GDTR_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_bootstrap16_data, phys_long_mode_entry) == BCD_PHYS_LM_ENTRY_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_bootstrap16_data, long_mode_cs) == BCD_LM_CS_OFFSET); + +STATIC_ASSERT(__offsetof(struct x86_ap_bootstrap_data, hdr) == 0); +STATIC_ASSERT(__offsetof(struct x86_ap_bootstrap_data, cpu_id_counter) == BCD_CPU_COUNTER_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_ap_bootstrap_data, cpu_waiting_counter) == BCD_CPU_WAITING_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_ap_bootstrap_data, kstack_base) == BCD_KSTACK_BASE_OFFSET); + +__END_CDECLS + +#endif // ASSEMBLY + +#endif // ARCH_X86_64 diff --git a/kernel/arch/x86/include/arch/x86/descriptor.h b/kernel/arch/x86/include/arch/x86/descriptor.h new file mode 100644 index 000000000..e6012f722 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/descriptor.h @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2014 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* + * System Selectors + */ +#define NULL_SELECTOR 0x00 + +/********* kernel selectors *********/ +#define CODE_SELECTOR 0x08 +#define CODE_64_SELECTOR 0x10 +#define DATA_SELECTOR 0x18 + +/********* user selectors *********/ +#define USER_CODE_SELECTOR (0x20 | 3) +#define USER_DATA_SELECTOR (0x28 | 3) +#define USER_CODE_64_SELECTOR (0x30 | 3) + +#define TSS_SELECTOR(i) (0x38 + 16 * (i)) +/* 0x40 is used by the second half of the first TSS descriptor */ + +/* selector priviledge level */ +#define SELECTOR_PL(s) ((s) & 0x3) + +/* + * Descriptor Types + */ +#define SEG_TYPE_TSS 0x9 +#define SEG_TYPE_TSS_BUSY 0xb +#define SEG_TYPE_TASK_GATE 0x5 +#define SEG_TYPE_INT_GATE 0xe /* 32 bit */ +#define SEG_TYPE_DATA_RW 0x2 +#define SEG_TYPE_CODE_RW 0xa + +#ifndef ASSEMBLY + +#include +#include +#include + +__BEGIN_CDECLS + +typedef uint16_t seg_sel_t; + +/* fill in a descriptor in the GDT */ +void set_global_desc_32(seg_sel_t sel, uint32_t base, uint32_t limit, + uint8_t present, uint8_t ring, uint8_t sys, + uint8_t type, uint8_t gran, uint8_t bits); + +void set_global_desc_64(seg_sel_t sel, uint64_t base, uint32_t limit, + uint8_t present, uint8_t ring, uint8_t sys, + uint8_t type, uint8_t gran, uint8_t bits); + +/* tss stuff */ +void x86_initialize_percpu_tss(void); + +void x86_set_tss_sp(vaddr_t sp); + +void x86_set_tss_io_bitmap(uint8_t *bitmap); + +void x86_clear_tss_io_bitmap(void); + +__END_CDECLS + +#endif diff --git a/kernel/arch/x86/include/arch/x86/feature.h b/kernel/arch/x86/include/arch/x86/feature.h new file mode 100644 index 000000000..58f1cd18b --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/feature.h @@ -0,0 +1,127 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +struct cpuid_leaf { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; +}; + +enum x86_cpuid_leaf_num { + X86_CPUID_BASE = 0, + X86_CPUID_TOPOLOGY = 0xb, + + X86_CPUID_EXT_BASE = 0x80000000, + X86_CPUID_ADDR_WIDTH = 0x80000008, +}; + +struct x86_cpuid_bit { + enum x86_cpuid_leaf_num leaf_num; + uint8_t word; + uint8_t bit; +}; + +#define X86_CPUID_BIT(leaf, word, bit) \ + (struct x86_cpuid_bit){(enum x86_cpuid_leaf_num)(leaf), (word), (bit)} + +void x86_feature_init(void); +const struct cpuid_leaf *x86_get_cpuid_leaf(enum x86_cpuid_leaf_num); +/* Retrieve the specified subleaf. This function is not cached. + * Returns false if leaf num is invalid */ +bool x86_get_cpuid_subleaf( + enum x86_cpuid_leaf_num, uint32_t, struct cpuid_leaf *); +bool x86_feature_test(struct x86_cpuid_bit); + +void x86_feature_debug(void); + +/* add feature bits to test here */ +#define X86_FEATURE_SSE3 X86_CPUID_BIT(0x1, 2, 0) +#define X86_FEATURE_SSSE3 X86_CPUID_BIT(0x1, 2, 9) +#define X86_FEATURE_SSE4_1 X86_CPUID_BIT(0x1, 2, 19) +#define X86_FEATURE_SSE4_2 X86_CPUID_BIT(0x1, 2, 20) +#define X86_FEATURE_AESNI X86_CPUID_BIT(0x1, 2, 25) +#define X86_FEATURE_XSAVE X86_CPUID_BIT(0x1, 2, 26) +#define X86_FEATURE_AVX X86_CPUID_BIT(0x1, 2, 28) +#define X86_FEATURE_RDRAND X86_CPUID_BIT(0x1, 2, 30) +#define X86_FEATURE_FPU X86_CPUID_BIT(0x1, 3, 0) +#define X86_FEATURE_MMX X86_CPUID_BIT(0x1, 3, 23) +#define X86_FEATURE_FXSR X86_CPUID_BIT(0x1, 3, 24) +#define X86_FEATURE_SSE X86_CPUID_BIT(0x1, 3, 25) +#define X86_FEATURE_SSE2 X86_CPUID_BIT(0x1, 3, 26) +#define X86_FEATURE_TSC_ADJUST X86_CPUID_BIT(0x7, 1, 1) +#define X86_FEATURE_AVX2 X86_CPUID_BIT(0x7, 1, 5) +#define X86_FEATURE_SMEP X86_CPUID_BIT(0x7, 1, 7) +#define X86_FEATURE_RDSEED X86_CPUID_BIT(0x7, 1, 18) +#define X86_FEATURE_SMAP X86_CPUID_BIT(0x7, 1, 20) +#define X86_FEATURE_PKU X86_CPUID_BIT(0x7, 2, 3) +#define X86_FEATURE_SYSCALL X86_CPUID_BIT(0x80000001, 3, 11) +#define X86_FEATURE_NX X86_CPUID_BIT(0x80000001, 3, 20) +#define X86_FEATURE_HUGE_PAGE X86_CPUID_BIT(0x80000001, 3, 26) +#define X86_FEATURE_RDTSCP X86_CPUID_BIT(0x80000001, 3, 27) +#define X86_FEATURE_INVAR_TSC X86_CPUID_BIT(0x80000007, 3, 8) + +/* legacy accessors */ +static inline uint8_t x86_linear_address_width(void) +{ + const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_ADDR_WIDTH); + if (!leaf) + return 0; + + /* + Extracting bit 15:8 from eax register + Bits 15-08: #Linear Address Bits + */ + return (leaf->a >> 8) & 0xff; +} + +static inline uint8_t x86_physical_address_width(void) +{ + const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_ADDR_WIDTH); + if (!leaf) + return 0; + + /* + Extracting bit 7:0 from eax register + Bits 07-00: #Physical Address Bits + */ + return leaf->a & 0xff; +} + +#define X86_TOPOLOGY_INVALID 0 +#define X86_TOPOLOGY_SMT 1 +#define X86_TOPOLOGY_CORE 2 + +struct x86_topology_level { + /* The number of bits of the APIC ID that encode this level */ + uint8_t num_bits; + /* The type of relationship this level describes (hyperthread/core/etc) */ + uint8_t type; +}; + +/** + * @brief Fetch the topology information for the given level. + * + * This interface is uncached. + * + * @param level The level to retrieve info for. Should initially be 0 and + * incremented with each call. + * @param info The structure to populate with the discovered information + * + * @return true if the requested level existed (and there may be higher levels). + * @return false if the requested level does not exist (and no higher ones do). + */ +bool x86_topology_enumerate(uint8_t level, struct x86_topology_level *info); + +__END_CDECLS diff --git a/kernel/arch/x86/include/arch/x86/idt.h b/kernel/arch/x86/include/arch/x86/idt.h new file mode 100644 index 000000000..63686f57f --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/idt.h @@ -0,0 +1,107 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +__BEGIN_CDECLS + +struct idt_entry { + uint32_t w0, w1; +#ifdef ARCH_X86_64 + uint32_t w2, w3; +#endif +}; + +struct idt { + struct idt_entry entries[256]; +}; + +#ifdef ARCH_X86_64 +STATIC_ASSERT(sizeof(struct idt_entry) == 16); +STATIC_ASSERT(sizeof(struct idt) == 16 * 256); +#else +STATIC_ASSERT(sizeof(struct idt_entry) == 8); +STATIC_ASSERT(sizeof(struct idt) == 8* 256); +#endif + +struct idtr { + uint16_t limit; + uintptr_t address; +} __PACKED; + +enum idt_entry_type { +#ifdef ARCH_X86_64 + IDT_INTERRUPT_GATE64 = 0xe, + IDT_TRAP_GATE64 = 0xf, +#else + IDT_INTERRUPT_GATE16 = 0x6, + IDT_TRAP_GATE16 = 0x7, + IDT_INTERRUPT_GATE32 = 0xe, + IDT_TRAP_GATE32 = 0xf, +#endif +}; + +enum idt_dpl { + IDT_DPL0 = 0, + IDT_DPL1 = 1, + IDT_DPL2 = 2, + IDT_DPL3 = 3, +}; + +/* + * @brief Change an IDT entry + * + * Caution: Interrupts should probably be disabled when this is called + * + * @param idt Pointer to the IDT to change. + * @param vec The vector to replace. + * @param code_segment_sel The code segment selector to use on taking this + * interrupt. + * @param entry_point_offset The offset of the code to begin executing (relative + * to the segment). + * @param dpl The desired privilege level of the handler. + * @param typ The type of interrupt handler + */ +void idt_set_vector( + struct idt *idt, + uint8_t vec, + uint16_t code_segment_sel, + uintptr_t entry_point_offset, + enum idt_dpl dpl, + enum idt_entry_type typ); + +#ifdef ARCH_X86_64 +/* + * @brief Set the Interrupt Stack Table index to use + * + * @param idt Pointer to the IDT to change. + * @param vec The vector to change. + * @param ist_idx A value in the range [0, 8) indicating which stack to use. + * If ist_idx == 0, use the normal stack for the target privilege level. + */ +void idt_set_ist_index(struct idt *idt, uint8_t vec, uint8_t ist_idx); +#endif + +/* + * @brief Initialize this IDT with our default values + * + * @param idt Pointer to the IDT to initialize + */ +void idt_setup(struct idt *idt); + +/* + * @brief Switch to thie given IDT + * + * @param idt Pointer to the IDT + */ +static void idt_load(struct idt *idt) { + struct idtr idtr = { .limit = sizeof(*idt) - 1, .address = (uintptr_t)idt }; + x86_lidt((uintptr_t)&idtr); +} + +__END_CDECLS diff --git a/kernel/arch/x86/include/arch/x86/interrupts.h b/kernel/arch/x86/include/arch/x86/interrupts.h new file mode 100644 index 000000000..033f0831b --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/interrupts.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#ifdef ASSEMBLY +#define X86_MAX_INT 0xff +#else +enum x86_interrupt_vector { + X86_INT_DIVIDE_0 = 0, + X86_INT_DEBUG, + X86_INT_NMI, + X86_INT_BREAKPOINT, + X86_INT_OVERFLOW, + X86_INT_BOUND_RANGE, + X86_INT_INVALID_OP, + X86_INT_DEVICE_NA, + X86_INT_DOUBLE_FAULT, + X86_INT_INVALID_TSS = 0xa, + X86_INT_SEGMENT_NOT_PRESENT, + X86_INT_STACK_FAULT, + X86_INT_GP_FAULT, + X86_INT_PAGE_FAULT, + X86_INT_FPU_FP_ERROR, + X86_INT_ALIGNMENT_CHECK, + X86_INT_MACHINE_CHECK, + X86_INT_SIMD_FP_ERROR, + X86_INT_VIRT, + X86_INT_MAX_INTEL_DEFINED = 0x1f, + + X86_INT_PLATFORM_BASE = 0x20, + X86_INT_PLATFORM_MAX = 0xef, + + X86_INT_LOCAL_APIC_BASE = 0xf0, + X86_INT_APIC_SPURIOUS = 0xf0, + X86_INT_APIC_TIMER, + X86_INT_APIC_ERROR, + X86_INT_IPI_GENERIC, + X86_INT_IPI_RESCHEDULE, + + X86_MAX_INT = 0xff, +}; +#endif diff --git a/kernel/arch/x86/include/arch/x86/ioport.h b/kernel/arch/x86/include/arch/x86/ioport.h new file mode 100644 index 000000000..e1b05fc4c --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/ioport.h @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +__BEGIN_CDECLS + +/* io port stuff */ +int x86_set_io_bitmap(uint32_t port, uint32_t len, bool enable); + +__END_CDECLS diff --git a/kernel/arch/x86/include/arch/x86/mmu.h b/kernel/arch/x86/include/arch/x86/mmu.h new file mode 100644 index 000000000..bf2025925 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/mmu.h @@ -0,0 +1,203 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* top level defines for the x86 mmu */ +/* NOTE: the top part can be included from assembly */ +#define KB (1024UL) +#define MB (1024UL*1024UL) +#define GB (1024UL*1024UL*1024UL) + +#define X86_MMU_PG_P 0x0001 /* P Valid */ +#define X86_MMU_PG_RW 0x0002 /* R/W Read/Write */ +#define X86_MMU_PG_U 0x0004 /* U/S User/Supervisor */ +#define X86_MMU_PG_WT 0x0008 /* WT Write-through */ +#define X86_MMU_PG_CD 0x0010 /* CD Cache disable */ +#define X86_MMU_PG_A 0x0020 /* A Accessed */ +#define X86_MMU_PG_D 0x0040 /* D Dirty */ +#define X86_MMU_PG_PS 0x0080 /* PS Page size (0=4k,1=4M) */ +#define X86_MMU_PG_PTE_PAT 0x0080 /* PAT PAT index for 4k pages */ +#define X86_MMU_PG_LARGE_PAT 0x1000 /* PAT PAT index otherwise */ +#define X86_MMU_PG_G 0x0100 /* G Global */ +#define X86_MMU_CLEAR 0x0 +#define X86_DIRTY_ACCESS_MASK 0xf9f + +/* Page Attribute Table memory types, defined in Table 11-10 of Intel 3A */ +#define X86_PAT_UC 0x00 /* Uncached */ +#define X86_PAT_WC 0x01 /* Write-combining */ +#define X86_PAT_WT 0x04 /* Write-through */ +#define X86_PAT_WP 0x05 /* Write protected */ +#define X86_PAT_WB 0X06 /* Write-back */ +#define X86_PAT_UC_ 0x07 /* Weakly Uncached (can be overrided by a + * WC MTRR setting) */ + +/* Macros for converting from PAT index to appropriate page table flags. Note + * that the smallest level has one of the flags at a different bit index, so we + * need two versions of each macro. */ +#define _X86_PAT_COMMON_SELECTOR(x) ((((x) & 0x2) ? X86_MMU_PG_CD : 0) | \ + (((x) & 0x1) ? X86_MMU_PG_WT : 0)) +#define X86_PAT_PTE_SELECTOR(x) ((((x) & 0x4) ? X86_MMU_PG_PTE_PAT : 0) | \ + _X86_PAT_COMMON_SELECTOR(x)) +#define X86_PAT_LARGE_SELECTOR(x) ((((x) & 0x4) ? X86_MMU_PG_LARGE_PAT : 0) | \ + _X86_PAT_COMMON_SELECTOR(x)) + +#define X86_MMU_PTE_PAT_MASK X86_PAT_PTE_SELECTOR(0x7) +#define X86_MMU_LARGE_PAT_MASK X86_PAT_LARGE_SELECTOR(0x7) + +/* Our configuration for the PAT indexes. This must be kept in sync with the + * selector definitions below it. For safety, it is important to ensure that + * the default mode is less cached than our substitution. This ensures that + * any mappings defined before we switch all CPUs to this new map will still + * function correctly. */ +#define X86_PAT_INDEX0 X86_PAT_WB /* default */ +#define X86_PAT_INDEX1 X86_PAT_WT /* default */ +#define X86_PAT_INDEX2 X86_PAT_UC_ /* default */ +#define X86_PAT_INDEX3 X86_PAT_UC /* default */ +#define X86_PAT_INDEX4 X86_PAT_WB /* default */ +#define X86_PAT_INDEX5 X86_PAT_WT /* default */ +#define X86_PAT_INDEX6 X86_PAT_UC_ /* default */ +#define X86_PAT_INDEX7 X86_PAT_WC /* UC by default */ + +/* These assume our defined PAT entries. We need to update these if we decide + * to change them PAT entries */ +#define X86_MMU_PTE_PAT_WRITEBACK X86_PAT_PTE_SELECTOR(0) +#define X86_MMU_PTE_PAT_WRITETHROUGH X86_PAT_PTE_SELECTOR(1) +#define X86_MMU_PTE_PAT_UNCACHABLE X86_PAT_PTE_SELECTOR(3) +#define X86_MMU_PTE_PAT_WRITE_COMBINING X86_PAT_PTE_SELECTOR(7) +#define X86_MMU_LARGE_PAT_WRITEBACK X86_PAT_LARGE_SELECTOR(0) +#define X86_MMU_LARGE_PAT_WRITETHROUGH X86_PAT_LARGE_SELECTOR(1) +#define X86_MMU_LARGE_PAT_UNCACHABLE X86_PAT_LARGE_SELECTOR(3) +#define X86_MMU_LARGE_PAT_WRITE_COMBINING X86_PAT_LARGE_SELECTOR(7) + +/* default flags for inner page directory entries */ +#define X86_KERNEL_PD_FLAGS (X86_MMU_PG_G | X86_MMU_PG_RW | X86_MMU_PG_P) + +/* default flags for 2MB/4MB/1GB page directory entries */ +#define X86_KERNEL_PD_LP_FLAGS (X86_MMU_PG_G | X86_MMU_PG_PS | X86_MMU_PG_RW | X86_MMU_PG_P) + +#define IS_PAGE_PRESENT(pte) ((pte) & X86_MMU_PG_P) +#define IS_LARGE_PAGE(pte) ((pte) & X86_MMU_PG_PS) + +#if defined(PAE_MODE_ENABLED) || ARCH_X86_64 +#define X86_MMU_PG_NX (1UL << 63) + +#if ARCH_X86_64 +#define X86_PAGING_LEVELS 4 +#define PML4_SHIFT 39 +#else +#define X86_PAGING_LEVELS 3 +#endif + +#define PDP_SHIFT 30 +#define PD_SHIFT 21 +#define PT_SHIFT 12 +#define ADDR_OFFSET 9 +#define PDPT_ADDR_OFFSET 2 +#define NO_OF_PT_ENTRIES 512 + +#define X86_FLAGS_MASK (0x8000000000000ffful) +#define X86_LARGE_FLAGS_MASK (0x8000000000001ffful) +#define X86_PDPT_ADDR_MASK (0x00000000ffffffe0ul) +#define X86_HUGE_PAGE_FRAME (0x000fffffc0000000ul) +#define X86_LARGE_PAGE_FRAME (0x000fffffffe00000ul) +#define X86_PG_FRAME (0x000ffffffffff000ul) +#define PAGE_OFFSET_MASK_4KB ((1ul << PT_SHIFT) - 1) +#define PAGE_OFFSET_MASK_LARGE ((1ul << PD_SHIFT) - 1) +#define PAGE_OFFSET_MASK_HUGE ((1ul << PDP_SHIFT) - 1) + +#define VADDR_TO_PML4_INDEX(vaddr) ((vaddr) >> PML4_SHIFT) & ((1ul << ADDR_OFFSET) - 1) +#define VADDR_TO_PDP_INDEX(vaddr) ((vaddr) >> PDP_SHIFT) & ((1ul << ADDR_OFFSET) - 1) + +#else +/* non PAE mode */ +#define X86_PG_FRAME (0xfffff000) +#define X86_FLAGS_MASK (0x00000fff) +#define X86_LARGE_FLAGS_MASK (0x00001fff) +#define X86_LARGE_PAGE_FRAME (0xffc00000) +#define NO_OF_PT_ENTRIES 1024 +#define X86_PAGING_LEVELS 2 +#define PD_SHIFT 22 +#define PT_SHIFT 12 +#define ADDR_OFFSET 10 +#define PAGE_OFFSET_MASK_4KB ((1 << PT_SHIFT) - 1) +#define PAGE_OFFSET_MASK_LARGE ((1 << PD_SHIFT) - 1) +#endif + +#define VADDR_TO_PD_INDEX(vaddr) ((vaddr) >> PD_SHIFT) & ((1ul << ADDR_OFFSET) - 1) +#define VADDR_TO_PT_INDEX(vaddr) ((vaddr) >> PT_SHIFT) & ((1ul << ADDR_OFFSET) - 1) + +#define VADDR_TO_PML4_INDEX(vaddr) ((vaddr) >> PML4_SHIFT) & ((1ul << ADDR_OFFSET) - 1) +#define VADDR_TO_PDP_INDEX(vaddr) ((vaddr) >> PDP_SHIFT) & ((1ul << ADDR_OFFSET) - 1) + +/* on both x86-32 and x86-64 physical memory is mapped at the base of the kernel address space */ +#define X86_PHYS_TO_VIRT(x) ((uintptr_t)(x) + KERNEL_ASPACE_BASE) +#define X86_VIRT_TO_PHYS(x) ((uintptr_t)(x) - KERNEL_ASPACE_BASE) + +/* page fault error code flags */ +#define PFEX_P (1<<0) +#define PFEX_W (1<<1) +#define PFEX_U (1<<2) +#define PFEX_RSV (1<<3) +#define PFEX_I (1<<4) +#define PFEX_PK (1<<5) +#define PFEX_SGX (1<<15) + +/* C defines below */ +#ifndef ASSEMBLY + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +/* Different page table levels in the page table mgmt hirerachy */ +enum page_table_levels { + PT_L, + PD_L, +#if defined(PAE_MODE_ENABLED) || ARCH_X86_64 + PDP_L, +#endif +#if ARCH_X86_64 + PML4_L, +#endif +}; + +#define MAX_PAGING_LEVEL (enum page_table_levels)(X86_PAGING_LEVELS - 1) + +struct map_range { + vaddr_t start_vaddr; + paddr_t start_paddr; /* Physical address in the PAE mode is 32 bits wide */ + size_t size; +}; + +#if defined(PAE_MODE_ENABLED) || ARCH_X86_64 +typedef uint64_t pt_entry_t; +#define PRIxPTE PRIx64 +#else +typedef uint32_t pt_entry_t; +#define PRIxPTE PRIx32 +#endif + +typedef pt_entry_t arch_flags_t; + +bool x86_is_vaddr_canonical(vaddr_t vaddr); + +void x86_mmu_percpu_init(void); +void x86_mmu_early_init(void); +void x86_mmu_init(void); + +void x86_mmu_mem_type_init(void); +void x86_pat_sync(void); + +__END_CDECLS + +#endif // !ASSEMBLY diff --git a/kernel/arch/x86/include/arch/x86/mp.h b/kernel/arch/x86/include/arch/x86/mp.h new file mode 100644 index 000000000..7b9c6e74b --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/mp.h @@ -0,0 +1,131 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* describes the per cpu structure pointed to by gs: in the kernel */ + +/* offsets into this structure, used by assembly */ +#if ARCH_X86_32 +#define PERCPU_DIRECT_OFFSET 0x0 +#define PERCPU_CURRENT_THREAD_OFFSET 0x4 +#define PERCPU_KERNEL_SP_OFFSET 0x8 +#define PERCPU_SAVED_USER_SP_OFFSET 0xc +#define PERCPU_DEFAULT_TSS_OFFSET 0x20 +#elif ARCH_X86_64 +#define PERCPU_DIRECT_OFFSET 0x0 +#define PERCPU_CURRENT_THREAD_OFFSET 0x8 +#define PERCPU_KERNEL_SP_OFFSET 0x10 +#define PERCPU_SAVED_USER_SP_OFFSET 0x18 +#define PERCPU_DEFAULT_TSS_OFFSET 0x30 +#endif + +#ifndef ASSEMBLY + +#include +#include +#include +#include + +__BEGIN_CDECLS + +struct thread; + +struct x86_percpu { + /* a direct pointer to ourselves */ + struct x86_percpu *direct; + + /* the current thread */ + struct thread *current_thread; + + /* our current kernel sp, to be loaded by syscall */ + // TODO: Remove this and replace with a fetch from + // the current tss? + uintptr_t kernel_sp; + + /* temporarily saved during a syscall */ + uintptr_t saved_user_sp; + + /* local APIC id */ + uint32_t apic_id; + + /* CPU number */ + uint8_t cpu_num; + + /* This CPU's default TSS */ + tss_t __ALIGNED(16) default_tss; + + /* The IDT for this CPU */ + struct idt idt; +#ifdef ARCH_X86_64 + /* Reserved space for interrupt stacks */ + uint8_t interrupt_stacks[NUM_ASSIGNED_IST_ENTRIES][PAGE_SIZE]; +#endif +}; + +STATIC_ASSERT(__offsetof(struct x86_percpu, direct) == PERCPU_DIRECT_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_percpu, current_thread) == PERCPU_CURRENT_THREAD_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_percpu, kernel_sp) == PERCPU_KERNEL_SP_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_percpu, saved_user_sp) == PERCPU_SAVED_USER_SP_OFFSET); +STATIC_ASSERT(__offsetof(struct x86_percpu, default_tss) == PERCPU_DEFAULT_TSS_OFFSET); + +/* needs to be run very early in the boot process from start.S and as each cpu is brought up */ +void x86_init_percpu(uint8_t cpu_num); + +void x86_set_local_apic_id(uint32_t apic_id); + +// Allocate all of the necessary structures for all of the APs to run. +status_t x86_allocate_ap_structures(uint8_t cpu_count); + +static inline struct x86_percpu *x86_get_percpu(void) +{ +#if ARCH_X86_64 + return (struct x86_percpu *)x86_read_gs_offset(PERCPU_DIRECT_OFFSET); +#else + /* x86-32 does not yet support SMP and thus does not need a gs: pointer to point + * at the percpu structure + */ + STATIC_ASSERT(SMP_MAX_CPUS == 1); + extern struct x86_percpu bp_percpu; + return &bp_percpu; +#endif +} + +static inline struct thread *get_current_thread(void) +{ + return x86_get_percpu()->current_thread; +} + +static inline void set_current_thread(struct thread *t) +{ + x86_get_percpu()->current_thread = t; +} + +static inline uint arch_curr_cpu_num(void) +{ + return x86_get_percpu()->cpu_num; +} + +extern uint8_t x86_num_cpus; +static uint arch_max_num_cpus(void) +{ + return x86_num_cpus; +} + +/* set on every context switch and before entering user space */ +static inline void x86_set_percpu_kernel_sp(uintptr_t sp) +{ + x86_get_percpu()->kernel_sp = sp; +} + +enum handler_return x86_ipi_generic_handler(void); +enum handler_return x86_ipi_reschedule_handler(void); + +__END_CDECLS + +#endif + diff --git a/kernel/arch/x86/include/arch/x86/registers.h b/kernel/arch/x86/include/arch/x86/registers.h new file mode 100644 index 000000000..d4961d8a8 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/registers.h @@ -0,0 +1,58 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +// This header is intended to be included in both C and ASM +#define X86_CR0_PE 0x00000001 /* protected mode enable */ +#define X86_CR0_MP 0x00000002 /* monitor coprocessor */ +#define X86_CR0_EM 0x00000004 /* emulation */ +#define X86_CR0_TS 0x00000008 /* task switched */ +#define X86_CR0_NE 0x00000020 /* enable x87 exception */ +#define X86_CR0_WP 0x00010000 /* supervisor write protect */ +#define X86_CR0_NW 0x20000000 /* not write-through */ +#define X86_CR0_CD 0x40000000 /* cache disable */ +#define X86_CR0_PG 0x80000000 /* enable paging */ +#define X86_CR4_PAE 0x00000020 /* PAE paging */ +#define X86_CR4_PGE 0x00000080 /* page global enable */ +#define X86_CR4_OSFXSR 0x00000200 /* os supports fxsave */ +#define X86_CR4_OSXMMEXPT 0x00000400 /* os supports xmm exception */ +#define X86_CR4_OSXSAVE 0x00040000 /* os supports xsave */ +#define X86_CR4_SMEP 0x00100000 /* SMEP protection enabling */ +#define X86_CR4_SMAP 0x00200000 /* SMAP protection enabling */ +#define X86_EFER_SCE 0x00000001 /* enable SYSCALL */ +#define X86_EFER_LME 0x00000100 /* long mode enable */ +#define X86_EFER_LMA 0x00000400 /* long mode active */ +#define X86_EFER_NXE 0x00000800 /* to enable execute disable bit */ +#define X86_MSR_EFER 0xc0000080 /* EFER Model Specific Register id */ +#define X86_MSR_IA32_STAR 0xc0000081 /* system call address */ +#define X86_MSR_IA32_LSTAR 0xc0000082 /* long mode call address */ +#define X86_MSR_IA32_FMASK 0xc0000084 /* system call flag mask */ +#define X86_MSR_IA32_FS_BASE 0xc0000100 /* fs base address */ +#define X86_MSR_IA32_GS_BASE 0xc0000101 /* gs base address */ +#define X86_MSR_IA32_KERNEL_GS_BASE 0xc0000102 /* kernel gs base */ +#define X86_CR4_PSE 0xffffffef /* Disabling PSE bit in the CR4 */ + +/* EFLAGS/RFLAGS */ +#define X86_FLAGS_CF (1<<0) +#define X86_FLAGS_PF (1<<2) +#define X86_FLAGS_AF (1<<4) +#define X86_FLAGS_ZF (1<<6) +#define X86_FLAGS_SF (1<<7) +#define X86_FLAGS_TF (1<<8) +#define X86_FLAGS_IF (1<<9) +#define X86_FLAGS_DF (1<<10) +#define X86_FLAGS_OF (1<<11) +#define X86_FLAGS_STATUS_MASK (0xfff) +#define X86_FLAGS_IOPL_MASK (3<<12) +#define X86_FLAGS_IOPL_SHIFT (12) +#define X86_FLAGS_NT (1<<14) +#define X86_FLAGS_RF (1<<16) +#define X86_FLAGS_VM (1<<17) +#define X86_FLAGS_AC (1<<18) +#define X86_FLAGS_VIF (1<<19) +#define X86_FLAGS_VIP (1<<20) +#define X86_FLAGS_ID (1<<21) diff --git a/kernel/arch/x86/include/arch/x86/user_copy.h b/kernel/arch/x86/include/arch/x86/user_copy.h new file mode 100644 index 000000000..37f2ea558 --- /dev/null +++ b/kernel/arch/x86/include/arch/x86/user_copy.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once +#include + +__BEGIN_CDECLS + +/* These functions are identical to arch_copy_from_user, except they take an + * additional argument of fault_return, used to handle page faults within the + * function. These should not be called anywhere except in the x86 usercopy + * implementation. */ + +status_t _x86_copy_from_user( + void *dst, + const void *src, + size_t len, + void **fault_return); + +status_t _x86_copy_to_user( + void *dst, + const void *src, + size_t len, + void **fault_return); + +__END_CDECLS diff --git a/kernel/arch/x86/ioapic.c b/kernel/arch/x86/ioapic.c new file mode 100644 index 000000000..4e7f97775 --- /dev/null +++ b/kernel/arch/x86/ioapic.c @@ -0,0 +1,461 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include + +#define IO_APIC_IND(base) ((volatile uint32_t *)(base)) +#define IO_APIC_DAT(base) ((volatile uint32_t *)(((uint8_t *)(base)) + 0x10)) +#define IO_APIC_EOIR(base) ((volatile uint32_t *)(((uint8_t *)(base)) + 0x40)) +// The minimum address space required past the base address +#define IO_APIC_WINDOW_SIZE 0x44 +// The minimum version that supported the EOIR +#define IO_APIC_EOIR_MIN_VERSION 0x20 + +// IO APIC register offsets +#define IO_APIC_REG_ID 0x00 +#define IO_APIC_REG_VER 0x01 +#define IO_APIC_REG_RTE(idx) (0x10 + 2 * (idx)) + +// Macros for extracting data from REG_ID +#define IO_APIC_ID_ID(v) (((v) >> 24) & 0xf) +// Macros for extracting data from REG_VER +#define IO_APIC_VER_MAX_REDIR_ENTRY(v) (((v) >> 16) & 0xff) +#define IO_APIC_VER_VERSION(v) ((v) & 0xff) +// Macros for writing REG_RTE entries +#define IO_APIC_RTE_DST(v) (((uint64_t)(v)) << 56) +#define IO_APIC_RTE_EXTENDED_DST_ID(v) (((uint64_t)((v) & 0xf)) << 48) +#define IO_APIC_RTE_MASKED (1ULL << 16) +#define IO_APIC_RTE_TRIGGER_MODE(tm) (((uint64_t)(tm)) << 15) +#define IO_APIC_RTE_POLARITY(p) (((uint64_t)(p)) << 13) +#define IO_APIC_RTE_DST_MODE(dm) (((uint64_t)(dm)) << 11) +#define IO_APIC_RTE_DELIVERY_MODE(dm) ((((uint64_t)(dm)) & 0x7) << 8) +#define IO_APIC_RTE_VECTOR(x) (((uint64_t)(x)) & 0xff) +#define IO_APIC_RTE_MASK IO_APIC_RTE_VECTOR(0xff) +// Macros for reading REG_RTE entries +#define IO_APIC_RTE_REMOTE_IRR (1ULL << 14) +#define IO_APIC_RTE_DELIVERY_STATUS (1ULL << 12) +#define IO_APIC_RTE_GET_POLARITY(r) \ + ((enum io_apic_irq_polarity)(((r) >> 13) & 0x1)) +#define IO_APIC_RTE_GET_TRIGGER_MODE(r) \ + ((enum io_apic_irq_trigger_mode)(((r) >> 15) & 0x1)) +#define IO_APIC_RTE_GET_VECTOR(r) \ + ((uint8_t)((r) & 0xFF)) + +// Technically this can be larger, but the spec as of the 100-Series doesn't +// guarantee where the additional redirections will be. +#define IO_APIC_NUM_REDIRECTIONS 120 + + +#define LOCAL_TRACE 0 + +// Struct for tracking all we need to know about each IO APIC +struct io_apic { + struct io_apic_descriptor desc; + + // Virtual address of the base of this IOAPIC's MMIO + void *vaddr; + + uint8_t version; + // The index of the last redirection entry + uint8_t max_redirection_entry; +}; + +// General register accessors +static inline uint32_t apic_io_read_reg( + struct io_apic *io_apic, + uint8_t reg); +static inline void apic_io_write_reg( + struct io_apic *io_apic, + uint8_t reg, + uint32_t val); + +// Register-specific accessors +static uint64_t apic_io_read_redirection_entry( + struct io_apic *io_apic, + uint32_t global_irq); +static void apic_io_write_redirection_entry( + struct io_apic *io_apic, + uint32_t global_irq, + uint64_t value); + +// Utility for finding the right IO APIC for a specific global IRQ, cannot fail +static struct io_apic *apic_io_resolve_global_irq(uint32_t irq); +// Utility for finding the right IO APIC for a specific global IRQ, can fail +static struct io_apic *apic_io_resolve_global_irq_no_panic(uint32_t irq); + +// This lock guards all access to IO APIC registers +static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE; + +// Track all IO APICs in the system +static struct io_apic *io_apics; +static uint32_t num_io_apics; + +// The first 16 global IRQs are identity mapped to the legacy ISA IRQs unless +// we are told otherwise. This tracks the actual mapping. +#define NUM_ISA_IRQS 16 +// Read-only after initialization in apic_io_init() +static struct io_apic_isa_override isa_overrides[NUM_ISA_IRQS]; + +void apic_io_init( + struct io_apic_descriptor *io_apic_descs, + unsigned int num_io_apic_descs, + struct io_apic_isa_override *overrides, + unsigned int num_overrides) +{ + ASSERT(io_apics == NULL); + + num_io_apics = num_io_apic_descs; + io_apics = calloc(num_io_apics, sizeof(*io_apics)); + ASSERT(io_apics != NULL); + for (unsigned int i = 0; i < num_io_apics; ++i) { + io_apics[i].desc = io_apic_descs[i]; + } + + // Allocate windows to their control pages + for (uint32_t i = 0; i < num_io_apics; ++i) { + struct io_apic *apic = &io_apics[i]; + paddr_t paddr = apic->desc.paddr; + void *vaddr = paddr_to_kvaddr(paddr); + // If the window isn't mapped yet (multiple IO APICs can be in the + // same page), map it in. + if (vaddr == NULL) { + paddr_t paddr_page_base = ROUNDDOWN(paddr, PAGE_SIZE); + ASSERT(paddr + IO_APIC_WINDOW_SIZE <= paddr_page_base + PAGE_SIZE); + vmm_aspace_t *kernel_aspace = vmm_get_kernel_aspace(); + status_t res = vmm_alloc_physical( + kernel_aspace, + "ioapic", + PAGE_SIZE, // size + &vaddr, // requested virtual vaddress + PAGE_SIZE_SHIFT, // alignment log2 + paddr_page_base, // physical vaddress + 0, // vmm flags + ARCH_MMU_FLAG_PERM_NO_EXECUTE | + ARCH_MMU_FLAG_UNCACHED_DEVICE); // arch mmu flags + ASSERT(res == NO_ERROR); + vaddr += paddr - paddr_page_base; + } + + // Populate the rest of the descriptor + apic->vaddr = vaddr; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + uint32_t ver = apic_io_read_reg(apic, IO_APIC_REG_VER); + + apic->version = IO_APIC_VER_VERSION(ver); + apic->max_redirection_entry = IO_APIC_VER_MAX_REDIR_ENTRY(ver); + LTRACEF("Found an IO APIC at phys %p, virt %p: ver %08x\n", (void *)paddr, vaddr, ver); + if (apic->max_redirection_entry >= IO_APIC_NUM_REDIRECTIONS - 1) { + TRACEF("IO APIC supports more redirections than kernel: %08x\n", + ver); + apic->max_redirection_entry = IO_APIC_NUM_REDIRECTIONS - 1; + } + + // Cleanout the redirection entries + for (unsigned int j = 0; j <= apic->max_redirection_entry; ++j) { + apic_io_write_redirection_entry( + apic, j + apic->desc.global_irq_base, IO_APIC_RTE_MASKED); + } + spin_unlock_irqrestore(&lock, state); + } + + // Process ISA IRQ overrides + for (unsigned int i = 0; i < num_overrides; ++i) { + uint8_t isa_irq = overrides[i].isa_irq; + ASSERT(isa_irq < NUM_ISA_IRQS); + isa_overrides[isa_irq] = overrides[i]; + LTRACEF("ISA IRQ override for ISA IRQ %d, mapping to %d\n", + isa_irq, overrides[i].global_irq); + } +} + +static struct io_apic *apic_io_resolve_global_irq_no_panic(uint32_t irq) +{ + for (uint32_t i = 0; i < num_io_apics; ++i) { + uint32_t start = io_apics[i].desc.global_irq_base; + uint32_t end = start + io_apics[i].max_redirection_entry; + if (start <= irq && irq <= end) { + return &io_apics[i]; + } + } + return NULL; +} + +static struct io_apic *apic_io_resolve_global_irq(uint32_t irq) +{ + struct io_apic *res = apic_io_resolve_global_irq_no_panic(irq); + if (res) { + return res; + } + // Treat this as fatal, since dealing with an unmapped IRQ is a bug. + panic("Could not resolve global IRQ: %u\n", irq); +} + +static inline uint32_t apic_io_read_reg( + struct io_apic *io_apic, + uint8_t reg) +{ + ASSERT(io_apic != NULL); + DEBUG_ASSERT(spin_lock_held(&lock)); + *IO_APIC_IND(io_apic->vaddr) = reg; + uint32_t val = *IO_APIC_DAT(io_apic->vaddr); + return val; +} + +static inline void apic_io_write_reg( + struct io_apic *io_apic, + uint8_t reg, + uint32_t val) +{ + ASSERT(io_apic != NULL); + DEBUG_ASSERT(spin_lock_held(&lock)); + *IO_APIC_IND(io_apic->vaddr) = reg; + *IO_APIC_DAT(io_apic->vaddr) = val; +} + +static uint64_t apic_io_read_redirection_entry( + struct io_apic *io_apic, + uint32_t global_irq) +{ + DEBUG_ASSERT(spin_lock_held(&lock)); + + ASSERT(global_irq >= io_apic->desc.global_irq_base); + uint32_t offset = global_irq - io_apic->desc.global_irq_base; + ASSERT(offset <= io_apic->max_redirection_entry); + + uint8_t reg_id = IO_APIC_REG_RTE(offset); + uint64_t result = 0; + result |= apic_io_read_reg(io_apic, reg_id); + result |= ((uint64_t)apic_io_read_reg(io_apic, reg_id + 1)) << 32; + return result; +} + +static void apic_io_write_redirection_entry( + struct io_apic *io_apic, + uint32_t global_irq, + uint64_t value) +{ + DEBUG_ASSERT(spin_lock_held(&lock)); + + ASSERT(global_irq >= io_apic->desc.global_irq_base); + uint32_t offset = global_irq - io_apic->desc.global_irq_base; + ASSERT(offset <= io_apic->max_redirection_entry); + + uint8_t reg_id = IO_APIC_REG_RTE(offset); + apic_io_write_reg(io_apic, reg_id, (uint32_t)value); + apic_io_write_reg(io_apic, reg_id + 1, (uint32_t)(value >> 32)); +} + +bool apic_io_is_valid_irq(uint32_t global_irq) +{ + return apic_io_resolve_global_irq_no_panic(global_irq) != NULL; +} + +/* + * To correctly use this function, we need to do some work first. + * 1) We need to check for EOI-broadcast suppression support in the local APIC + * version register. + * 2) We need to check that the IOAPIC is new enough to support the EOI + * 3) We need to enable suppression in the spurious interrupt register. + * 4) Call this function after calling apic_issue_eoi() (or maybe modify + * apic_issue_eoi() to call this automatically). + * + * In the mean time, IO APIC EOIs are automatically issued via broadcast to + * all IO APICs whenever the local APIC receives an EOI for a level-triggered + * interrupt. + */ +void apic_io_issue_eoi(uint32_t global_irq, uint8_t vec) +{ + struct io_apic *io_apic = apic_io_resolve_global_irq(global_irq); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + ASSERT(io_apic->version >= IO_APIC_EOIR_MIN_VERSION); + *IO_APIC_EOIR(io_apic->vaddr) = vec; + + spin_unlock_irqrestore(&lock, state); +} + +void apic_io_mask_irq(uint32_t global_irq, bool mask) +{ + struct io_apic *io_apic = apic_io_resolve_global_irq(global_irq); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + uint64_t reg = apic_io_read_redirection_entry(io_apic, global_irq); + if (mask) { + reg |= IO_APIC_RTE_MASKED; + } else { + /* If we are unmasking, we had better have been assigned a valid vector */ + DEBUG_ASSERT((IO_APIC_RTE_GET_VECTOR(reg) >= X86_INT_PLATFORM_BASE) && + (IO_APIC_RTE_GET_VECTOR(reg) <= X86_INT_PLATFORM_MAX)); + reg &= ~IO_APIC_RTE_MASKED; + } + apic_io_write_redirection_entry(io_apic, global_irq, reg); + + spin_unlock_irqrestore(&lock, state); +} + +void apic_io_configure_irq( + uint32_t global_irq, + enum io_apic_irq_trigger_mode trig_mode, + enum io_apic_irq_polarity polarity, + enum apic_interrupt_delivery_mode del_mode, + bool mask, + enum apic_interrupt_dst_mode dst_mode, + uint8_t dst, + uint8_t vector) +{ + struct io_apic *io_apic = apic_io_resolve_global_irq(global_irq); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + /* If we are configuring an invalid vector, for the IRQ to be masked. */ + if ((vector < X86_INT_PLATFORM_BASE) || (vector > X86_INT_PLATFORM_MAX)) + mask = true; + + uint64_t reg = 0; + reg |= IO_APIC_RTE_TRIGGER_MODE(trig_mode); + reg |= IO_APIC_RTE_POLARITY(polarity); + reg |= IO_APIC_RTE_DELIVERY_MODE(del_mode); + reg |= IO_APIC_RTE_DST_MODE(dst_mode); + reg |= IO_APIC_RTE_DST(dst); + reg |= IO_APIC_RTE_VECTOR(vector); + if (mask) { + reg |= IO_APIC_RTE_MASKED; + } + apic_io_write_redirection_entry(io_apic, global_irq, reg); + + spin_unlock_irqrestore(&lock, state); +} + +void apic_io_configure_irq_vector( + uint32_t global_irq, + uint8_t vector) +{ + struct io_apic *io_apic = apic_io_resolve_global_irq(global_irq); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + uint64_t reg = apic_io_read_redirection_entry(io_apic, global_irq); + + /* If we are configuring an invalid vector, automatically mask the IRQ. */ + if ((IO_APIC_RTE_GET_VECTOR(reg) < X86_INT_PLATFORM_BASE) || + (IO_APIC_RTE_GET_VECTOR(reg) > X86_INT_PLATFORM_MAX)) { + reg |= IO_APIC_RTE_MASKED; + } + + reg &= ~IO_APIC_RTE_MASK; + reg |= IO_APIC_RTE_VECTOR(vector); + apic_io_write_redirection_entry(io_apic, global_irq, reg); + + spin_unlock_irqrestore(&lock, state); +} + +uint8_t apic_io_fetch_irq_vector(uint32_t global_irq) +{ + struct io_apic *io_apic = apic_io_resolve_global_irq(global_irq); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + uint64_t reg = apic_io_read_redirection_entry(io_apic, global_irq); + uint8_t vector = IO_APIC_RTE_GET_VECTOR(reg); + + spin_unlock_irqrestore(&lock, state); + + return vector; +} + +void apic_io_mask_isa_irq(uint8_t isa_irq, bool mask) +{ + ASSERT(isa_irq < NUM_ISA_IRQS); + uint32_t global_irq = isa_irq; + if (isa_overrides[isa_irq].remapped) { + global_irq = isa_overrides[isa_irq].global_irq; + } + apic_io_mask_irq(global_irq, mask); +} + +void apic_io_configure_isa_irq( + uint8_t isa_irq, + enum apic_interrupt_delivery_mode del_mode, + bool mask, + enum apic_interrupt_dst_mode dst_mode, + uint8_t dst, + uint8_t vector) +{ + ASSERT(isa_irq < NUM_ISA_IRQS); + uint32_t global_irq = isa_irq; + enum io_apic_irq_trigger_mode trig_mode = IRQ_TRIGGER_MODE_EDGE; + enum io_apic_irq_polarity polarity = IRQ_POLARITY_ACTIVE_HIGH; + if (isa_overrides[isa_irq].remapped) { + global_irq = isa_overrides[isa_irq].global_irq; + trig_mode = isa_overrides[isa_irq].tm; + polarity = isa_overrides[isa_irq].pol; + } + + apic_io_configure_irq( + global_irq, + trig_mode, + polarity, + del_mode, + mask, + dst_mode, + dst, + vector); +} + +// Convert a legacy ISA IRQ number into a global IRQ number +uint32_t apic_io_isa_to_global(uint8_t isa_irq) +{ + // It is a programming bug for this to be invoked with an invalid value. + ASSERT(isa_irq < NUM_ISA_IRQS); + if (isa_overrides[isa_irq].remapped) { + return isa_overrides[isa_irq].global_irq; + } + return isa_irq; +} + +void apic_io_debug(void) +{ + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + for (uint32_t i = 0; i < num_io_apics; ++i) { + struct io_apic *apic = &io_apics[i]; + printf("IO APIC idx %d:\n", i); + printf(" id: %08x\n", apic->desc.apic_id); + printf(" version: %08x\n", apic->version); + printf(" entries: %08x\n", apic->max_redirection_entry + 1); + for (uint8_t j = 0; j <= apic->max_redirection_entry; ++j) { + uint32_t global_irq = apic->desc.global_irq_base + j; + uint64_t reg = apic_io_read_redirection_entry(apic, global_irq); + printf(" %4d: dst: %s %02x, %s, %s, %s, dm %x, vec %2x, %s %s\n", + global_irq, + (reg & (1 << 11)) ? "l" : "p", + (uint8_t)(reg >> 56), + (reg & IO_APIC_RTE_MASKED) ? "masked" : "unmasked", + IO_APIC_RTE_GET_TRIGGER_MODE(reg) ? "level" : "edge", + IO_APIC_RTE_GET_POLARITY(reg) ? "low" : "high", + (uint8_t)((reg >> 8) & 0x7), + (uint8_t)reg, + (reg & (1 << 12)) ? "pending" : "", + (reg & (1 << 14)) ? "RIRR" : ""); + } + } + spin_unlock_irqrestore(&lock, state); +} diff --git a/kernel/arch/x86/ioport.c b/kernel/arch/x86/ioport.c new file mode 100644 index 000000000..41d3a9651 --- /dev/null +++ b/kernel/arch/x86/ioport.c @@ -0,0 +1,113 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Task used for updating IO permissions on each CPU */ +struct ioport_update_context { + // aspace that we're trying to update + arch_aspace_t *aspace; +}; +static void ioport_update_task(void* raw_context) { + DEBUG_ASSERT(arch_ints_disabled()); + struct ioport_update_context* context = + (struct ioport_update_context*)raw_context; + + thread_t *t = get_current_thread(); + if (!t->aspace) { + return; + } + + struct arch_aspace *as = vmm_get_arch_aspace(t->aspace); + if (as != context->aspace) { + return; + } + + spin_lock(&as->io_bitmap_lock); + x86_set_tss_io_bitmap(as->io_bitmap_ptr); + spin_unlock(&as->io_bitmap_lock); +} + +int x86_set_io_bitmap(uint32_t port, uint32_t len, bool enable) +{ + DEBUG_ASSERT(!arch_ints_disabled()); + + if ((port + len < port) || (port + len > IO_BITMAP_BITS)) return ERR_INVALID_ARGS; + + thread_t *t = get_current_thread(); + DEBUG_ASSERT(t->aspace); + if (!t->aspace) { + return ERR_INVALID_ARGS; + } + + struct arch_aspace *as = vmm_get_arch_aspace(t->aspace); + + // Optimistically allocate the bitmap pointer if it doesn't exist. Once + // we're in the spinlock, we'll see if we actually need this allocation or + // not. In the common case, when we make the allocation we will use it. + unsigned long *optimistic_alloc = NULL; + if (!as->io_bitmap_ptr) { + optimistic_alloc = malloc(IO_BITMAP_BYTES); + if (!optimistic_alloc) { + return ERR_NO_MEMORY; + } + memset(optimistic_alloc, 0xff, IO_BITMAP_BYTES); + } + + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + spin_lock(&as->io_bitmap_lock); + + // Initialize the io bitmap if this is the first call for this process + if (as->io_bitmap_ptr == NULL) { + DEBUG_ASSERT(optimistic_alloc); + if (!optimistic_alloc) { + spin_unlock(&as->io_bitmap_lock); + arch_interrupt_restore(state, 0); + return ERR_NO_MEMORY; + } + + as->io_bitmap_ptr = optimistic_alloc; + // Mark the allocation as used + optimistic_alloc = NULL; + } + + // Set the io bitmap in the thread structure and the tss + tss_t *tss = &x86_get_percpu()->default_tss; + + if (enable) { + bitmap_clear(as->io_bitmap_ptr, port, len); + bitmap_clear((unsigned long *)tss->tss_bitmap, port, len); + } else { + bitmap_set(as->io_bitmap_ptr, port, len); + bitmap_set((unsigned long *)tss->tss_bitmap, port, len); + } + + spin_unlock(&as->io_bitmap_lock); + + // Let all other CPUs know about the update + struct ioport_update_context task_context = { .aspace = as }; + mp_sync_exec(MP_CPU_ALL_BUT_LOCAL, ioport_update_task, &task_context); + + arch_interrupt_restore(state, 0); + + // If our optimistic allocation is still unused, release it + if (optimistic_alloc) { + free(optimistic_alloc); + } + + return NO_ERROR; +} diff --git a/kernel/arch/x86/lapic.c b/kernel/arch/x86/lapic.c new file mode 100644 index 000000000..f3f1a468d --- /dev/null +++ b/kernel/arch/x86/lapic.c @@ -0,0 +1,393 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// We currently only implement support for the xAPIC + +// Initialization MSR +#define IA32_APIC_BASE_MSR 0x01B +#define X2APIC_ENABLE (1 << 10) +#define XAPIC_ENABLE (1 << 11) + +#define APIC_PHYS_BASE 0xFEE00000 + +// Virtual address of the local APIC's MMIO registers +static void *apic_virt_base; + +#define LAPIC_ID_ADDR ((volatile uint32_t *)(apic_virt_base + 0x020)) +#define LAPIC_VERSION_ADDR ((volatile uint32_t *)(apic_virt_base + 0x030)) +#define TASK_PRIORITY_ADDR ((volatile uint32_t *)(apic_virt_base + 0x080)) +#define PROCESSOR_PRIORITY_ADDR ((volatile uint32_t *)(apic_virt_base + 0x0A0)) +#define EOI_ADDR ((volatile uint32_t *)(apic_virt_base + 0x0B0)) +#define LOGICAL_DST_ADDR ((volatile uint32_t *)(apic_virt_base + 0x0D0)) +#define SPURIOUS_IRQ_ADDR ((volatile uint32_t *)(apic_virt_base + 0x0F0)) +#define IN_SERVICE_ADDR(x) \ + ((volatile uint32_t *)(apic_virt_base + 0x100 + ((x) << 4))) +#define TRIGGER_MODE_ADDR(x) \ + ((volatile uint32_t *)(apic_virt_base + 0x180 + ((x) << 4))) +#define IRQ_REQUEST_ADDR(x) \ + ((volatile uint32_t *)(apic_virt_base + 0x200 + ((x) << 4))) +#define ERROR_STATUS_ADDR ((volatile uint32_t *)(apic_virt_base + 0x280)) +#define LVT_CMCI_ADDR ((volatile uint32_t *)(apic_virt_base + 0x2F0)) +#define IRQ_CMD_LOW_ADDR ((volatile uint32_t *)(apic_virt_base + 0x300)) +#define IRQ_CMD_HIGH_ADDR ((volatile uint32_t *)(apic_virt_base + 0x310)) +#define LVT_TIMER_ADDR ((volatile uint32_t *)(apic_virt_base + 0x320)) +#define LVT_THERMAL_ADDR ((volatile uint32_t *)(apic_virt_base + 0x330)) +#define LVT_PERF_ADDR ((volatile uint32_t *)(apic_virt_base + 0x340)) +#define LVT_LINT0_ADDR ((volatile uint32_t *)(apic_virt_base + 0x350)) +#define LVT_LINT1_ADDR ((volatile uint32_t *)(apic_virt_base + 0x360)) +#define LVT_ERROR_ADDR ((volatile uint32_t *)(apic_virt_base + 0x370)) +#define INIT_COUNT_ADDR ((volatile uint32_t *)(apic_virt_base + 0x380)) +#define CURRENT_COUNT_ADDR ((volatile uint32_t *)(apic_virt_base + 0x390)) +#define DIVIDE_CONF_ADDR ((volatile uint32_t *)(apic_virt_base + 0x3E0)) + +// Spurious IRQ bitmasks +#define SVR_APIC_ENABLE (1 << 8) +#define SVR_SPURIOUS_VECTOR(x) (x) + +// Interrupt Command bitmasks +#define ICR_VECTOR(x) (x) +#define ICR_DELIVERY_PENDING (1 << 12) +#define ICR_LEVEL_ASSERT (1 << 14) +#define ICR_DST(x) (((uint32_t)(x)) << 24) +#define ICR_DST_BROADCAST ICR_DST(0xff) +#define ICR_DELIVERY_MODE(x) (((uint32_t)(x)) << 8) +#define ICR_DST_SHORTHAND(x) (((uint32_t)(x)) << 18) +#define ICR_DST_SELF ICR_DST_SHORTHAND(1) +#define ICR_DST_ALL ICR_DST_SHORTHAND(2) +#define ICR_DST_ALL_MINUS_SELF ICR_DST_SHORTHAND(3) + +// Common LVT bitmasks +#define LVT_VECTOR(x) (x) +#define LVT_DELIVERY_MODE(x) (((uint32_t)(x)) << 8) +#define LVT_DELIVERY_PENDING (1 << 12) +#define LVT_MASKED (1 << 16) + +// LVT Timer bitmasks +#define LVT_TIMER_MODE_ONESHOT (0 << 17) +#define LVT_TIMER_MODE_PERIODIC (1 << 17) +#define LVT_TIMER_MODE_TSC_DEADLINE (2 << 17) + +static void apic_error_init(void); +static void apic_timer_init(void); + +// This function must be called once on the kernel address space +void apic_vm_init(void) +{ + ASSERT(apic_virt_base == NULL); + // Create a mapping for the page of MMIO registers + vmm_aspace_t *kernel_aspace = vmm_get_kernel_aspace(); + status_t res = vmm_alloc_physical( + kernel_aspace, + "lapic", + PAGE_SIZE, // size + &apic_virt_base, // returned virtual address + PAGE_SIZE_SHIFT, // alignment log2 + APIC_PHYS_BASE, // physical address + 0, // vmm flags + ARCH_MMU_FLAG_PERM_NO_EXECUTE | ARCH_MMU_FLAG_UNCACHED_DEVICE); // arch mmu flags + if (res != NO_ERROR) { + panic("Could not allocate APIC management page: %d\n", res); + } + ASSERT(apic_virt_base != NULL); +} + +// Initializes the current processor's local APIC. Should be called after +// apic_vm_init has been called. +void apic_local_init(void) +{ + // Enter XAPIC mode and set the base address + uint64_t v = read_msr(IA32_APIC_BASE_MSR); + v |= XAPIC_ENABLE; + write_msr(IA32_APIC_BASE_MSR, v); + + // Register the local APIC id for this processor + uint32_t apic_id = apic_local_id(); + ASSERT(apic_id != INVALID_APIC_ID); + x86_set_local_apic_id(apic_id); + + // Specify the spurious interrupt vector and enable the local APIC + uint32_t svr = SVR_SPURIOUS_VECTOR(X86_INT_APIC_SPURIOUS) | SVR_APIC_ENABLE; + *SPURIOUS_IRQ_ADDR = svr; + + apic_error_init(); + apic_timer_init(); +} + +uint8_t apic_local_id(void) +{ + return (uint8_t)(*LAPIC_ID_ADDR >> 24); +} + +static inline void apic_wait_for_ipi_send(void) { + while (*IRQ_CMD_LOW_ADDR & ICR_DELIVERY_PENDING); +} + +// We only support physical destination modes for now + +void apic_send_ipi( + uint8_t vector, + uint8_t dst_apic_id, + enum apic_interrupt_delivery_mode dm) +{ + uint32_t request = ICR_VECTOR(vector) | ICR_LEVEL_ASSERT; + request |= ICR_DELIVERY_MODE(dm); + + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *IRQ_CMD_HIGH_ADDR = ICR_DST(dst_apic_id); + *IRQ_CMD_LOW_ADDR = request; + apic_wait_for_ipi_send(); + arch_interrupt_restore(state, 0); +} + +void apic_send_self_ipi(uint8_t vector, enum apic_interrupt_delivery_mode dm) +{ + uint32_t request = ICR_VECTOR(vector) | ICR_LEVEL_ASSERT; + request |= ICR_DELIVERY_MODE(dm) | ICR_DST_SELF; + + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *IRQ_CMD_LOW_ADDR = request; + apic_wait_for_ipi_send(); + arch_interrupt_restore(state, 0); +} + +// Broadcast to everyone including self +void apic_send_broadcast_self_ipi( + uint8_t vector, + enum apic_interrupt_delivery_mode dm) +{ + uint32_t request = ICR_VECTOR(vector) | ICR_LEVEL_ASSERT; + request |= ICR_DELIVERY_MODE(dm) | ICR_DST_ALL; + + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *IRQ_CMD_HIGH_ADDR = ICR_DST_BROADCAST; + *IRQ_CMD_LOW_ADDR = request; + apic_wait_for_ipi_send(); + arch_interrupt_restore(state, 0); +} + +// Broadcast to everyone excluding self +void apic_send_broadcast_ipi( + uint8_t vector, + enum apic_interrupt_delivery_mode dm) +{ + uint32_t request = ICR_VECTOR(vector) | ICR_LEVEL_ASSERT; + request |= ICR_DELIVERY_MODE(dm) | ICR_DST_ALL_MINUS_SELF; + + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *IRQ_CMD_HIGH_ADDR = ICR_DST_BROADCAST; + *IRQ_CMD_LOW_ADDR = request; + apic_wait_for_ipi_send(); + arch_interrupt_restore(state, 0); +} + +void apic_issue_eoi(void) +{ + // Write any value to the EOI address to issue an EOI + *EOI_ADDR = 1; +} + +// If this function returns an error, timer state will not have +// been changed. +static status_t apic_timer_set_divide_value(uint8_t v) { + uint32_t new_value = 0; + switch (v) { + case 1: new_value = 0xb; break; + case 2: new_value = 0x0; break; + case 4: new_value = 0x1; break; + case 8: new_value = 0x2; break; + case 16: new_value = 0x3; break; + case 32: new_value = 0x8; break; + case 64: new_value = 0x9; break; + case 128: new_value = 0xa; break; + default: return ERR_INVALID_ARGS; + } + *DIVIDE_CONF_ADDR = new_value; + return NO_ERROR; +} + +static void apic_timer_init(void) { + *LVT_TIMER_ADDR = LVT_VECTOR(X86_INT_APIC_TIMER) | LVT_MASKED; +} + +// Racy; primarily useful for calibrating the timer. +uint32_t apic_timer_current_count(void) { + return *CURRENT_COUNT_ADDR; +} + +void apic_timer_mask(void) { + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *LVT_TIMER_ADDR |= LVT_MASKED; + arch_interrupt_restore(state, 0); +} + +void apic_timer_unmask(void) { + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *LVT_TIMER_ADDR &= ~LVT_MASKED; + arch_interrupt_restore(state, 0); +} + +void apic_timer_stop(void) { + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + *INIT_COUNT_ADDR = 0; + arch_interrupt_restore(state, 0); +} + +status_t apic_timer_set_oneshot(uint32_t count, uint8_t divisor, bool masked) { + status_t status = NO_ERROR; + uint32_t timer_config = LVT_VECTOR(X86_INT_APIC_TIMER) | + LVT_TIMER_MODE_ONESHOT; + if (masked) { + timer_config |= masked; + } + + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + + status = apic_timer_set_divide_value(divisor); + if (status != NO_ERROR) { + goto cleanup; + } + *INIT_COUNT_ADDR = count; + *LVT_TIMER_ADDR = timer_config; +cleanup: + arch_interrupt_restore(state, 0); + return status; +} + +status_t apic_timer_set_periodic(uint32_t count, uint8_t divisor) { + status_t status = NO_ERROR; + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + + status = apic_timer_set_divide_value(divisor); + if (status != NO_ERROR) { + goto cleanup; + } + *INIT_COUNT_ADDR = count; + *LVT_TIMER_ADDR = LVT_VECTOR(X86_INT_APIC_TIMER) | LVT_TIMER_MODE_PERIODIC; +cleanup: + arch_interrupt_restore(state, 0); + return status; +} + +// TODO: Where should this declaration go +extern enum handler_return platform_handle_timer_tick(void); +enum handler_return apic_timer_interrupt_handler(void) { + return platform_handle_timer_tick(); +} + +static void apic_error_init(void) { + *LVT_ERROR_ADDR = LVT_VECTOR(X86_INT_APIC_ERROR); + // Re-arm the error interrupt triggering mechanism + *ERROR_STATUS_ADDR = 0; +} + +enum handler_return apic_error_interrupt_handler(void) { + DEBUG_ASSERT(arch_ints_disabled()); + + // This write doesn't effect the subsequent read, but is required prior to + // reading. + *ERROR_STATUS_ADDR = 0; + panic("APIC error detected: %u\n", *ERROR_STATUS_ADDR); +} + +static int cmd_apic(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("%s dump io\n", argv[0].str); + printf("%s dump local\n", argv[0].str); + printf("%s broadcast \n", argv[0].str); + printf("%s self \n", argv[0].str); + return ERR_GENERIC; + } + + if (!strcmp(argv[1].str, "broadcast")) { + if (argc < 3) + goto notenoughargs; + uint8_t vec = argv[2].u; + apic_send_broadcast_ipi(vec, DELIVERY_MODE_FIXED); + printf("irr: %x\n", *IRQ_REQUEST_ADDR(vec / 32)); + printf("isr: %x\n", *IN_SERVICE_ADDR(vec / 32)); + printf("icr: %x\n", *IRQ_CMD_LOW_ADDR); + } else if (!strcmp(argv[1].str, "self")) { + if (argc < 3) + goto notenoughargs; + uint8_t vec = argv[2].u; + apic_send_self_ipi(vec, DELIVERY_MODE_FIXED); + printf("irr: %x\n", *IRQ_REQUEST_ADDR(vec / 32)); + printf("isr: %x\n", *IN_SERVICE_ADDR(vec / 32)); + printf("icr: %x\n", *IRQ_CMD_LOW_ADDR); + } else if (!strcmp(argv[1].str, "dump")) { + if (argc < 3) + goto notenoughargs; + if (!strcmp(argv[2].str, "local")) { + printf("Caution: this is only for one CPU\n"); + apic_local_debug(); + } else if (!strcmp(argv[2].str, "io")) { + apic_io_debug(); + } else { + printf("unknown subcommand\n"); + goto usage; + } + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +void apic_local_debug(void) +{ + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + + printf("apic %02x:\n", apic_local_id()); + printf(" version: %08x:\n", *LAPIC_VERSION_ADDR); + printf(" logical_dst: %08x\n", *LOGICAL_DST_ADDR); + printf(" spurious_irq: %08x\n", *SPURIOUS_IRQ_ADDR); + printf(" tpr: %02x\n", (uint8_t)*TASK_PRIORITY_ADDR); + printf(" ppr: %02x\n", (uint8_t)*PROCESSOR_PRIORITY_ADDR); + for (int i = 0; i < 8; ++i) + printf(" irr %d: %08x\n", i, *IRQ_REQUEST_ADDR(i)); + for (int i = 0; i < 8; ++i) + printf(" isr %d: %08x\n", i, *IN_SERVICE_ADDR(i)); + + arch_interrupt_restore(state, 0); +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("apic", "apic commands", &cmd_apic) +#endif +STATIC_COMMAND_END(apic); diff --git a/kernel/arch/x86/mmu.cpp b/kernel/arch/x86/mmu.cpp new file mode 100644 index 000000000..468ade5ae --- /dev/null +++ b/kernel/arch/x86/mmu.cpp @@ -0,0 +1,1206 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +/* Default address width including virtual/physical address. + * newer versions fetched below */ +#if ARCH_X86_64 +uint8_t g_vaddr_width = 48; +uint8_t g_paddr_width = 32; +#elif ARCH_X86_32 +uint8_t g_vaddr_width = 32; +uint8_t g_paddr_width = 32; +#endif + +#if ARCH_X86_64 +/* top level kernel page tables, initialized in start.S */ +pt_entry_t pml4[NO_OF_PT_ENTRIES] __ALIGNED(PAGE_SIZE); +pt_entry_t pdp[NO_OF_PT_ENTRIES] __ALIGNED(PAGE_SIZE); /* temporary */ +pt_entry_t pte[NO_OF_PT_ENTRIES] __ALIGNED(PAGE_SIZE); + +/* top level pdp needed to map the -512GB..0 space */ +pt_entry_t pdp_high[NO_OF_PT_ENTRIES] __ALIGNED(PAGE_SIZE); + +/* a big pile of page tables needed to map 64GB of memory into kernel space using 2MB pages */ +pt_entry_t linear_map_pdp[(64ULL * GB) / (2 * MB)] __ALIGNED(PAGE_SIZE); + +/* which of the above variables is the top level page table */ +#define KERNEL_PT pml4 +#else +/* 32bit code */ +pt_entry_t pd[NO_OF_PT_ENTRIES] __ALIGNED(PAGE_SIZE); + +#if PAE_MODE_ENABLED +/* PAE has one more level, with the pdp at the top */ +pt_entry_t pdp[NO_OF_PT_ENTRIES] __ALIGNED(PAGE_SIZE); +#define KERNEL_PT pdp +#else +#define KERNEL_PT pd +#endif +#endif /* !ARCH_X86_64 */ + +/* kernel base top level page table in physical space */ +static const paddr_t kernel_pt_phys = (vaddr_t)KERNEL_PT - KERNEL_BASE; + +/* test the vaddr against the address space's range */ +static bool is_valid_vaddr(arch_aspace_t* aspace, vaddr_t vaddr) { + return (vaddr >= aspace->base && vaddr <= aspace->base + aspace->size - 1); +} + +/** + * @brief check if the virtual address is canonical + */ +bool x86_is_vaddr_canonical(vaddr_t vaddr) { +#if ARCH_X86_64 + uint64_t max_vaddr_lohalf, min_vaddr_hihalf; + + /* get max address in lower-half canonical addr space */ + /* e.g. if width is 48, then 0x00007FFF_FFFFFFFF */ + max_vaddr_lohalf = ((uint64_t)1ull << (g_vaddr_width - 1)) - 1; + + /* get min address in higher-half canonical addr space */ + /* e.g. if width is 48, then 0xFFFF8000_00000000*/ + min_vaddr_hihalf = ~max_vaddr_lohalf; + + /* Check to see if the address in a canonical address */ + if ((vaddr > max_vaddr_lohalf) && (vaddr < min_vaddr_hihalf)) return false; +#endif + + return true; +} + +/** + * @brief check if the virtual address is aligned and canonical + */ +static bool x86_mmu_check_vaddr(vaddr_t vaddr) { + /* Check to see if the address is PAGE aligned */ + if (!IS_ALIGNED(vaddr, PAGE_SIZE)) return false; + + return x86_is_vaddr_canonical(vaddr); +} + +/** + * @brief check if the physical address is valid and aligned + */ +static bool x86_mmu_check_paddr(paddr_t paddr) { + uint64_t max_paddr; + + /* Check to see if the address is PAGE aligned */ + if (!IS_ALIGNED(paddr, PAGE_SIZE)) return false; + + max_paddr = ((uint64_t)1ull << g_paddr_width) - 1; + + return paddr <= max_paddr; +} + +/** + * @brief Returning the x86 arch flags from generic mmu flags + * + * These are used for page mapping entries in the table + */ +template +static arch_flags_t x86_arch_flags(uint flags) { + arch_flags_t arch_flags = 0; + + if (!(flags & ARCH_MMU_FLAG_PERM_RO)) arch_flags |= X86_MMU_PG_RW; + + if (flags & ARCH_MMU_FLAG_PERM_USER) { + arch_flags |= X86_MMU_PG_U; + } else { + /* setting global flag for kernel pages */ + arch_flags |= X86_MMU_PG_G; + } + +#if defined(PAE_MODE_ENABLED) || ARCH_X86_64 + if (flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE) arch_flags |= X86_MMU_PG_NX; + + if (Level > 0) { + switch (flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_CACHED: + arch_flags |= X86_MMU_LARGE_PAT_WRITEBACK; + break; + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + case ARCH_MMU_FLAG_UNCACHED: + arch_flags |= X86_MMU_LARGE_PAT_UNCACHABLE; + break; + case ARCH_MMU_FLAG_WRITE_COMBINING: + arch_flags |= X86_MMU_LARGE_PAT_WRITE_COMBINING; + break; + default: + PANIC_UNIMPLEMENTED; + } + } else { + switch (flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_CACHED: + arch_flags |= X86_MMU_PTE_PAT_WRITEBACK; + break; + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + case ARCH_MMU_FLAG_UNCACHED: + arch_flags |= X86_MMU_PTE_PAT_UNCACHABLE; + break; + case ARCH_MMU_FLAG_WRITE_COMBINING: + arch_flags |= X86_MMU_PTE_PAT_WRITE_COMBINING; + break; + default: + PANIC_UNIMPLEMENTED; + } + } +#else + switch (flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_CACHED: + break; + case ARCH_MMU_FLAG_WRITE_COMBINING: + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + case ARCH_MMU_FLAG_UNCACHED: + arch_flags |= X86_MMU_PG_CD | X86_MMU_PG_WT; + break; + default: + PANIC_UNIMPLEMENTED; + } +#endif + return arch_flags; +} + +/** + * @brief Returning the x86 arch flags for intermediate tables from generic + * mmu flags + */ +static arch_flags_t get_x86_intermediate_arch_flags() { + return X86_MMU_PG_RW | X86_MMU_PG_U; +} + +/** + * @brief Returning the generic mmu flags from x86 arch flags + */ +static uint arch_mmu_flags(arch_flags_t flags, enum page_table_levels level) { + uint mmu_flags = 0; + + if (!(flags & X86_MMU_PG_RW)) mmu_flags |= ARCH_MMU_FLAG_PERM_RO; + + if (flags & X86_MMU_PG_U) mmu_flags |= ARCH_MMU_FLAG_PERM_USER; + +#if defined(PAE_MODE_ENABLED) || ARCH_X86_64 + if (flags & X86_MMU_PG_NX) mmu_flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE; + + if (level > 0) { + switch (flags & X86_MMU_LARGE_PAT_MASK) { + case X86_MMU_LARGE_PAT_WRITEBACK: + mmu_flags |= ARCH_MMU_FLAG_CACHED; + break; + case X86_MMU_LARGE_PAT_UNCACHABLE: + mmu_flags |= ARCH_MMU_FLAG_UNCACHED; + break; + case X86_MMU_LARGE_PAT_WRITE_COMBINING: + mmu_flags |= ARCH_MMU_FLAG_WRITE_COMBINING; + break; + default: + PANIC_UNIMPLEMENTED; + } + } else { + switch (flags & X86_MMU_PTE_PAT_MASK) { + case X86_MMU_PTE_PAT_WRITEBACK: + mmu_flags |= ARCH_MMU_FLAG_CACHED; + break; + case X86_MMU_PTE_PAT_UNCACHABLE: + mmu_flags |= ARCH_MMU_FLAG_UNCACHED; + break; + case X86_MMU_PTE_PAT_WRITE_COMBINING: + mmu_flags |= ARCH_MMU_FLAG_WRITE_COMBINING; + break; + default: + PANIC_UNIMPLEMENTED; + } + } +#else + if (flags & X86_MMU_PG_CD) { + mmu_flags |= ARCH_MMU_FLAG_UNCACHED; + } else { + mmu_flags |= ARCH_MMU_FLAG_CACHED; + } +#endif + return mmu_flags; +} + +template +static inline uint vaddr_to_index(vaddr_t vaddr) { + static_assert(Level >= 0, "level too low"); + static_assert(Level < X86_PAGING_LEVELS, "level too high"); + + switch (Level) { +#if X86_PAGING_LEVELS > 3 + case PML4_L: + return VADDR_TO_PML4_INDEX(vaddr); +#endif +#if X86_PAGING_LEVELS > 2 + case PDP_L: + return VADDR_TO_PDP_INDEX(vaddr); +#endif + case PD_L: + return VADDR_TO_PD_INDEX(vaddr); + case PT_L: + return VADDR_TO_PT_INDEX(vaddr); + default: + panic("vaddr_to_index: invalid level\n"); + } +} + +/* + * @brief convert a pte to a physical address + */ +template +static paddr_t paddr_from_pte(pt_entry_t pte) { + static_assert(Level >= 0, "level too low"); + static_assert(Level < X86_PAGING_LEVELS, "level too high"); + + DEBUG_ASSERT(IS_PAGE_PRESENT(pte)); + + paddr_t pa; + switch (Level) { +#if X86_PAGING_LEVELS > 2 + case PDP_L: + pa = (pte & X86_HUGE_PAGE_FRAME); + break; +#endif + case PD_L: + pa = (pte & X86_LARGE_PAGE_FRAME); + break; + case PT_L: + pa = (pte & X86_PG_FRAME); + break; + default: + panic("paddr_from_pte at unhandled level %u\n", Level); + } + + LTRACEF_LEVEL(2, "pte 0x%" PRIxPTE " , level %u, paddr 0x%lx\n", pte, Level, pa); + + return pa; +} + +template +static inline size_t page_size() { + static_assert(Level >= 0, "level too low"); + static_assert(Level < X86_PAGING_LEVELS, "level too high"); + switch (Level) { + case PT_L: + return 1ULL << PT_SHIFT; + case PD_L: + return 1ULL << PD_SHIFT; +#if X86_PAGING_LEVELS > 2 + case PDP_L: + return 1ULL << PDP_SHIFT; +#if X86_PAGING_LEVELS > 3 + case PML4_L: + return 1ULL << PML4_SHIFT; +#endif +#endif + default: + panic("page_size: invalid level\n"); + } +} + +template +static inline bool page_aligned(vaddr_t vaddr) { + return (vaddr & (page_size() - 1)) == 0; +} + +static void tlb_global_invalidate(void) { + /* TODO: make sufficient for global pages */ + x86_set_cr3(x86_get_cr3()); +} + +/* Task used for invalidating a TLB entry on each CPU */ +struct tlb_invalidate_page_context { + ulong target_cr3; + vaddr_t vaddr; + enum page_table_levels level; + bool global_page; +}; +static void tlb_invalidate_page_task(void* raw_context) { + DEBUG_ASSERT(arch_ints_disabled()); + tlb_invalidate_page_context* context = (tlb_invalidate_page_context*)raw_context; + + ulong cr3 = x86_get_cr3(); + if (context->target_cr3 != cr3 && !context->global_page) { + /* This invalidation doesn't apply to this CPU, ignore it */ + return; + } + + /* TODO: Handle invalidating global mappings (gotta toggle the cr4 bit) */ + + switch (context->level) { +#if X86_PAGING_LEVELS > 3 + case PML4_L: + tlb_global_invalidate(); + break; +#endif +#if X86_PAGING_LEVELS > 2 + case PDP_L: +#endif + case PD_L: + case PT_L: + __asm__ volatile("invlpg %0" ::"m"(*(uint8_t*)context->vaddr)); + break; + } +} + +/** + * @brief Invalidate a single page at a given page table level + * + * @param cr3 The top-level page table physical address we are performing an invalidation on + * @param vaddr The virtual address we are invalidating the TLB entry for + * @param level The page table level that maps this vaddr + * @param global_page True if we are invalidating a global mapping + * + * TODO(teisenbe): Optimize this. This is horrible inefficient on several + * levels. We can easily check what CPUs are currently using this page table, + * and so cut out the spurious IPIs. We should also change this to pool + * invalidations from a single "transaction" and then only execute a single + * mp_sync_exec for that transaction, rather than one per page. + */ +void x86_tlb_invalidate_page(ulong cr3, vaddr_t vaddr, enum page_table_levels level, + bool global_page) { + struct tlb_invalidate_page_context task_context = { + .target_cr3 = cr3, .vaddr = vaddr, .level = level, .global_page = global_page, + }; + mp_sync_exec(MP_CPU_ALL, tlb_invalidate_page_task, &task_context); +} + +struct MappingCursor { + paddr_t paddr; + vaddr_t vaddr; + size_t size; +}; + +template +static void update_entry(ulong cr3, vaddr_t vaddr, pt_entry_t* pte, paddr_t paddr, + arch_flags_t flags) { + + DEBUG_ASSERT(pte); + DEBUG_ASSERT(IS_PAGE_ALIGNED(paddr)); + + pt_entry_t olde = *pte; + + /* set the new entry */ + *pte = paddr; + *pte |= flags | X86_MMU_PG_P; + + /* attempt to invalidate the page */ + if (IS_PAGE_PRESENT(olde)) { + x86_tlb_invalidate_page(cr3, vaddr, (page_table_levels)Level, is_kernel_address(vaddr)); + } +} + +template +static void unmap_entry(ulong cr3, vaddr_t vaddr, pt_entry_t* pte, bool flush) { + DEBUG_ASSERT(pte); + + pt_entry_t olde = *pte; + + *pte = 0; + + /* attempt to invalidate the page */ + if (flush && IS_PAGE_PRESENT(olde)) { + x86_tlb_invalidate_page(cr3, vaddr, (page_table_levels)Level, is_kernel_address(vaddr)); + } +} + +/** + * @brief Allocating a new page table + */ +static pt_entry_t* _map_alloc_page(void) { + pt_entry_t* page_ptr = static_cast(pmm_alloc_kpage(nullptr)); + DEBUG_ASSERT(page_ptr); + + if (page_ptr) memset(page_ptr, 0, PAGE_SIZE); + + return page_ptr; +} + +/* + * @brief Split the given large page into smaller pages + */ +template +static status_t x86_mmu_split(ulong cr3, vaddr_t vaddr, pt_entry_t* pte) { + static_assert(Level != PT_L, "tried splitting PT_L"); +#if X86_PAGING_LEVELS > 3 + // This can't easily be a static assert without duplicating + // a bunch of code in the callers + DEBUG_ASSERT(Level != PML4_L); +#endif + LTRACEF_LEVEL(2, "splitting table %p at level %u\n", pte, Level); + + DEBUG_ASSERT(IS_PAGE_PRESENT(*pte) && IS_LARGE_PAGE(*pte)); + pt_entry_t* m = _map_alloc_page(); + if (m == NULL) { + return ERR_NO_MEMORY; + } + + paddr_t paddr_base = paddr_from_pte(*pte); + arch_flags_t flags = *pte & X86_LARGE_FLAGS_MASK; + DEBUG_ASSERT(flags & X86_MMU_PG_PS); + if (Level == PD_L) { + // Note: Clear PS before the check below; the PAT bit for a PTE is the + // the same as the PS bit for a higher table entry. + flags &= ~X86_MMU_PG_PS; + + /* If the larger page had the PAT flag set, make sure it's + * transferred to the different index for a PTE */ + if (flags & X86_MMU_PG_LARGE_PAT) { + flags &= ~X86_MMU_PG_LARGE_PAT; + flags |= X86_MMU_PG_PTE_PAT; + } + } + + DEBUG_ASSERT(page_aligned(vaddr)); + vaddr_t new_vaddr = vaddr; + paddr_t new_paddr = paddr_base; + size_t ps = page_size(); + for (int i = 0; i < NO_OF_PT_ENTRIES; i++) { + pt_entry_t* e = m + i; + // If this is a PDP_L (i.e. huge page), flags will include the + // PS bit still, so the new PD entries will be large pages. + update_entry(cr3, new_vaddr, e, new_paddr, flags); + new_vaddr += ps; + new_paddr += ps; + } + DEBUG_ASSERT(new_vaddr == vaddr + page_size()); + + flags = get_x86_intermediate_arch_flags(); + update_entry(cr3, vaddr, pte, X86_VIRT_TO_PHYS(m), flags); + return NO_ERROR; +} + +/* + * @brief given a page table entry, return a pointer to the next page table one level down + */ +static inline pt_entry_t* get_next_table_from_entry(pt_entry_t entry) { + if (!IS_PAGE_PRESENT(entry) || IS_LARGE_PAGE(entry)) return NULL; + + return (pt_entry_t*)X86_PHYS_TO_VIRT(entry & X86_PG_FRAME); +} + +static bool level_supports_ps(page_table_levels level) { + DEBUG_ASSERT(level != 0); + switch (level) { + case PD_L: + return true; +#if X86_PAGING_LEVELS > 2 + // TODO(teisenbe): Technically need to feature detect this + case PDP_L: + return true; +#if X86_PAGING_LEVELS > 3 + case PML4_L: + return false; +#endif +#endif + default: + panic("Unreachable case in level_supports_ps"); + } +} + +/** + * @brief Walk the page table structures returning the entry and level that maps the address. + * + * @param table The top-level paging structure's virtual address + * @param vaddr The virtual address to retrieve the mapping for + * @param ret_level The level of the table that defines the found mapping + * @param mapping The mapping that was found + * + * @return NO_ERROR if mapping is found + * @return ERR_NOT_FOUND if mapping is not found + */ +template +static status_t x86_mmu_get_mapping(pt_entry_t* table, vaddr_t vaddr, + enum page_table_levels* ret_level, pt_entry_t** mapping) { + + DEBUG_ASSERT(table); + DEBUG_ASSERT(ret_level); + DEBUG_ASSERT(mapping); + + LTRACEF_LEVEL(2, "table %p\n", table); + + uint index = vaddr_to_index(vaddr); + pt_entry_t* e = table + index; + if (!IS_PAGE_PRESENT(*e)) return ERR_NOT_FOUND; + + /* if this is a large page, stop here */ + if (IS_LARGE_PAGE(*e)) { + *mapping = e; + *ret_level = static_cast(Level); + return NO_ERROR; + } + + pt_entry_t* next_table = get_next_table_from_entry(*e); + return x86_mmu_get_mapping(next_table, vaddr, ret_level, mapping); +} + +template <> +status_t x86_mmu_get_mapping(pt_entry_t* table, vaddr_t vaddr, + enum page_table_levels* ret_level, pt_entry_t** mapping) { + + /* do the final page table lookup */ + uint index = vaddr_to_index(vaddr); + pt_entry_t* e = table + index; + if (!IS_PAGE_PRESENT(*e)) return ERR_NOT_FOUND; + + *mapping = e; + *ret_level = PT_L; + return NO_ERROR; +} + +/** + * @brief Unmaps the range specified by start_cursor + * + * Level must be MAX_PAGING_LEVEL when invoked. + * + * @param cr3 The top-level paging structure's physical address + * @param table The top-level paging structure's virtual address + * @param start_cursor A cursor describing the range of address space to + * unmap within table + * @param new_cursor A returned cursor describing how much work was not + * completed. Must be non-null. + * + * @return true if at least one page was unmapped at this level + */ +template +static bool x86_mmu_remove_mapping(ulong cr3, pt_entry_t* table, const MappingCursor& start_cursor, + MappingCursor* new_cursor) { + static_assert(Level >= 0, "level too low"); + static_assert(Level < X86_PAGING_LEVELS, "level too high"); + + DEBUG_ASSERT(table); + LTRACEF("L: %d, %016lx %016lx\n", Level, start_cursor.vaddr, start_cursor.size); + DEBUG_ASSERT(x86_mmu_check_vaddr(start_cursor.vaddr)); + + *new_cursor = start_cursor; + + bool unmapped = false; + size_t ps = page_size(); + uint index = vaddr_to_index(new_cursor->vaddr); + for (; index != NO_OF_PT_ENTRIES && new_cursor->size != 0; ++index) { + pt_entry_t* e = table + index; + // If the page isn't even mapped, just skip it + if (!IS_PAGE_PRESENT(*e)) { + // If our endpoint was in the middle of this range, clamp the + // amount we remove from the cursor + if (new_cursor->size < ps) { + new_cursor->vaddr += new_cursor->size; + new_cursor->size = 0; + continue; + } + new_cursor->vaddr += ps; + new_cursor->size -= ps; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + continue; + } + + if (IS_LARGE_PAGE(*e)) { + bool vaddr_level_aligned = page_aligned(new_cursor->vaddr); + // If the request covers the entire large page, just unmap it + if (vaddr_level_aligned && new_cursor->size >= ps) { + unmap_entry(cr3, new_cursor->vaddr, e, true); + unmapped = true; + + new_cursor->vaddr += ps; + new_cursor->size -= ps; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + continue; + } + // Otherwise, we need to split it + vaddr_t page_vaddr = new_cursor->vaddr & ~(ps - 1); + status_t status = x86_mmu_split(cr3, page_vaddr, e); + if (status != NO_ERROR) { + panic("Need to implement recovery from split failure"); + } + } + + MappingCursor cursor; + pt_entry_t* next_table = get_next_table_from_entry(*e); + bool lower_unmapped = x86_mmu_remove_mapping( + cr3, next_table, *new_cursor, &cursor); + + // If we were requesting to unmap everything in the lower page table, + // we know we can unmap the lower level page table. Otherwise, if + // we unmapped anything in the lower level, check to see if that + // level is now empty. + bool unmap_page_table = + page_aligned(new_cursor->vaddr) && new_cursor->size >= ps; + if (!unmap_page_table && lower_unmapped) { + uint lower_idx; + for (lower_idx = 0; lower_idx < NO_OF_PT_ENTRIES; ++lower_idx) { + if (IS_PAGE_PRESENT(next_table[lower_idx])) { + break; + } + } + if (lower_idx == NO_OF_PT_ENTRIES) { + unmap_page_table = true; + } + } + if (unmap_page_table) { + unmap_entry(cr3, new_cursor->vaddr, e, false); + pmm_free_page(paddr_to_vm_page(X86_VIRT_TO_PHYS(next_table))); + unmapped = true; + } + *new_cursor = cursor; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + + DEBUG_ASSERT(new_cursor->size == 0 || page_aligned(new_cursor->vaddr)); + } + + return unmapped; +} + +// Base case of x86_remove_mapping for smallest page size +template <> +bool x86_mmu_remove_mapping(ulong cr3, pt_entry_t* table, const MappingCursor& start_cursor, + MappingCursor* new_cursor) { + + LTRACEF("%016lx %016lx\n", start_cursor.vaddr, start_cursor.size); + DEBUG_ASSERT(IS_PAGE_ALIGNED(start_cursor.size)); + + *new_cursor = start_cursor; + + bool unmapped = false; + uint index = vaddr_to_index(new_cursor->vaddr); + for (; index != NO_OF_PT_ENTRIES && new_cursor->size != 0; ++index) { + pt_entry_t* e = table + index; + if (IS_PAGE_PRESENT(*e)) { + unmap_entry(cr3, new_cursor->vaddr, e, true); + unmapped = true; + } + + new_cursor->vaddr += PAGE_SIZE; + new_cursor->size -= PAGE_SIZE; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + } + return unmapped; +} + +/** + * @brief Creates mappings for the range specified by start_cursor + * + * Level must be MAX_PAGING_LEVEL when invoked. + * + * @param cr3 The top-level paging structure's physical address + * @param table The top-level paging structure's virtual address + * @param start_cursor A cursor describing the range of address space to + * act on within table + * @param new_cursor A returned cursor describing how much work was not + * completed. Must be non-null. + * + * @return NO_ERROR if successful + * @return ERR_ALREADY_EXISTS if the range overlaps an existing mapping + * @return ERR_NO_MEMORY if intermediate page tables could not be allocated + */ +template +static status_t x86_mmu_add_mapping(ulong cr3, pt_entry_t* table, uint mmu_flags, + const MappingCursor& start_cursor, MappingCursor* new_cursor) { + static_assert(Level >= 0, "level too low"); + static_assert(Level < X86_PAGING_LEVELS, "level too high"); + + DEBUG_ASSERT(table); + DEBUG_ASSERT(x86_mmu_check_vaddr(start_cursor.vaddr)); + DEBUG_ASSERT(x86_mmu_check_paddr(start_cursor.paddr)); + + status_t ret = NO_ERROR; + *new_cursor = start_cursor; + + arch_flags_t interm_arch_flags = get_x86_intermediate_arch_flags(); + arch_flags_t arch_flags = x86_arch_flags(mmu_flags); + + size_t ps = page_size(); + bool level_supports_large_pages = level_supports_ps(static_cast(Level)); + uint index = vaddr_to_index(new_cursor->vaddr); + for (; index != NO_OF_PT_ENTRIES && new_cursor->size != 0; ++index) { + pt_entry_t* e = table + index; + // See if there's a large page in our way + if (IS_PAGE_PRESENT(*e) && IS_LARGE_PAGE(*e)) { + ret = ERR_ALREADY_EXISTS; + goto err; + } + + // Check if this is a candidate for a new large page + bool level_valigned = page_aligned(new_cursor->vaddr); + bool level_paligned = page_aligned(new_cursor->paddr); + if (level_supports_large_pages && !IS_PAGE_PRESENT(*e) && level_valigned && + level_paligned && new_cursor->size >= ps) { + + update_entry(cr3, new_cursor->vaddr, table + index, new_cursor->paddr, + arch_flags | X86_MMU_PG_PS); + + new_cursor->paddr += ps; + new_cursor->vaddr += ps; + new_cursor->size -= ps; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + } else { + // See if we need to create a new table + if (!IS_PAGE_PRESENT(*e)) { + pt_entry_t* m = _map_alloc_page(); + if (m == NULL) { + ret = ERR_NO_MEMORY; + goto err; + } + + LTRACEF_LEVEL(2, "new table %p at level %u\n", m, Level); + + update_entry(cr3, new_cursor->vaddr, e, X86_VIRT_TO_PHYS(m), + interm_arch_flags); + } + + MappingCursor cursor; + ret = x86_mmu_add_mapping(cr3, get_next_table_from_entry(*e), mmu_flags, + *new_cursor, &cursor); + *new_cursor = cursor; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + if (ret != NO_ERROR) { + goto err; + } + } + } + return NO_ERROR; +err: + if (Level == MAX_PAGING_LEVEL) { + MappingCursor cursor = start_cursor; + MappingCursor result; + // new_cursor->size should be how much is left to be mapped still + cursor.size -= new_cursor->size; + if (cursor.size > 0) { + x86_mmu_remove_mapping(cr3, table, cursor, &result); + DEBUG_ASSERT(result.size == 0); + } + } + return ret; +} + +// Base case of x86_mmu_add_mapping for smallest page size +template <> +status_t x86_mmu_add_mapping(ulong cr3, pt_entry_t* table, uint mmu_flags, + const MappingCursor& start_cursor, MappingCursor* new_cursor) { + + DEBUG_ASSERT(IS_PAGE_ALIGNED(start_cursor.size)); + + *new_cursor = start_cursor; + + arch_flags_t arch_flags = x86_arch_flags(mmu_flags); + + uint index = vaddr_to_index(new_cursor->vaddr); + for (; index != NO_OF_PT_ENTRIES && new_cursor->size != 0; ++index) { + pt_entry_t* e = table + index; + if (IS_PAGE_PRESENT(*e)) { + return ERR_ALREADY_EXISTS; + } + + update_entry(cr3, new_cursor->vaddr, table + index, new_cursor->paddr, arch_flags); + + new_cursor->paddr += PAGE_SIZE; + new_cursor->vaddr += PAGE_SIZE; + new_cursor->size -= PAGE_SIZE; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + } + + return NO_ERROR; +} + +/** + * @brief Changes the permissions/caching of the range specified by start_cursor + * + * Level must be MAX_PAGING_LEVEL when invoked. + * + * @param cr3 The top-level paging structure's physical address + * @param table The top-level paging structure's virtual address + * @param start_cursor A cursor describing the range of address space to + * act on within table + * @param new_cursor A returned cursor describing how much work was not + * completed. Must be non-null. + */ +template +static status_t x86_mmu_update_mapping(ulong cr3, pt_entry_t* table, uint mmu_flags, + const MappingCursor& start_cursor, + MappingCursor* new_cursor) { + static_assert(Level >= 0, "level too low"); + static_assert(Level < X86_PAGING_LEVELS, "level too high"); + + DEBUG_ASSERT(table); + LTRACEF("L: %d, %016lx %016lx\n", Level, start_cursor.vaddr, start_cursor.size); + DEBUG_ASSERT(x86_mmu_check_vaddr(start_cursor.vaddr)); + + status_t ret = NO_ERROR; + *new_cursor = start_cursor; + + arch_flags_t arch_flags = x86_arch_flags(mmu_flags); + + size_t ps = page_size(); + uint index = vaddr_to_index(new_cursor->vaddr); + for (; index != NO_OF_PT_ENTRIES && new_cursor->size != 0; ++index) { + pt_entry_t* e = table + index; + if (!IS_PAGE_PRESENT(*e)) { + ret = ERR_NOT_FOUND; + goto err; + } + + if (IS_LARGE_PAGE(*e)) { + bool vaddr_level_aligned = page_aligned(new_cursor->vaddr); + // If the request covers the entire large page, just change the + // permissions + if (vaddr_level_aligned && new_cursor->size >= ps) { + update_entry(cr3, new_cursor->vaddr, e, paddr_from_pte(*e), + arch_flags | X86_MMU_PG_PS); + + new_cursor->vaddr += ps; + new_cursor->size -= ps; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + continue; + } + // Otherwise, we need to split it + vaddr_t page_vaddr = new_cursor->vaddr & ~(ps - 1); + ret = x86_mmu_split(cr3, page_vaddr, e); + if (ret != NO_ERROR) { + goto err; + } + } + + MappingCursor cursor; + pt_entry_t* next_table = get_next_table_from_entry(*e); + ret = x86_mmu_update_mapping(cr3, next_table, mmu_flags, *new_cursor, &cursor); + *new_cursor = cursor; + if (ret != NO_ERROR) { + goto err; + } + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + + DEBUG_ASSERT(new_cursor->size == 0 || page_aligned(new_cursor->vaddr)); + } + return NO_ERROR; +err: + // TODO: Cleanup + return ret; +} + +// Base case of x86_update_mapping for smallest page size +template <> +status_t x86_mmu_update_mapping(ulong cr3, pt_entry_t* table, uint mmu_flags, + const MappingCursor& start_cursor, + MappingCursor* new_cursor) { + + LTRACEF("%016lx %016lx\n", start_cursor.vaddr, start_cursor.size); + DEBUG_ASSERT(IS_PAGE_ALIGNED(start_cursor.size)); + + *new_cursor = start_cursor; + + arch_flags_t arch_flags = x86_arch_flags(mmu_flags); + + uint index = vaddr_to_index(new_cursor->vaddr); + for (; index != NO_OF_PT_ENTRIES && new_cursor->size != 0; ++index) { + pt_entry_t* e = table + index; + if (!IS_PAGE_PRESENT(*e)) { + // TODO: Cleanup + return ERR_NOT_FOUND; + } + update_entry(cr3, new_cursor->vaddr, e, paddr_from_pte(*e), arch_flags); + + new_cursor->vaddr += PAGE_SIZE; + new_cursor->size -= PAGE_SIZE; + DEBUG_ASSERT(new_cursor->size <= start_cursor.size); + } + return NO_ERROR; +} + +int arch_mmu_unmap(arch_aspace_t* aspace, vaddr_t vaddr, size_t count) { + LTRACEF("aspace %p, vaddr 0x%lx, count %lx\n", aspace, vaddr, count); + + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + if (!x86_mmu_check_vaddr(vaddr)) return ERR_INVALID_ARGS; + if (!is_valid_vaddr(aspace, vaddr)) return ERR_INVALID_ARGS; + if (count == 0) return NO_ERROR; + + DEBUG_ASSERT(aspace->pt_virt); + + MappingCursor start = { + .paddr = 0, .vaddr = vaddr, .size = count * PAGE_SIZE, + }; + + MappingCursor result; + x86_mmu_remove_mapping(aspace->pt_phys, aspace->pt_virt, start, &result); + DEBUG_ASSERT(result.size == 0); + return NO_ERROR; +} + +int arch_mmu_map(arch_aspace_t* aspace, vaddr_t vaddr, paddr_t paddr, size_t count, uint flags) { + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + LTRACEF("aspace %p, vaddr 0x%lx paddr 0x%lx count %lx flags 0x%x\n", aspace, vaddr, paddr, + count, flags); + + if ((!x86_mmu_check_paddr(paddr))) return ERR_INVALID_ARGS; + if (!x86_mmu_check_vaddr(vaddr)) return ERR_INVALID_ARGS; + if (!is_valid_vaddr(aspace, vaddr)) return ERR_INVALID_ARGS; + if (count == 0) return NO_ERROR; + + DEBUG_ASSERT(aspace->pt_virt); + + MappingCursor start = { + .paddr = paddr, .vaddr = vaddr, .size = count * PAGE_SIZE, + }; + MappingCursor result; + status_t status = x86_mmu_add_mapping(aspace->pt_phys, aspace->pt_virt, flags, + start, &result); + if (status != NO_ERROR) { + dprintf(SPEW, "Add mapping failed with err=%d\n", status); + return status; + } + DEBUG_ASSERT(result.size == 0); + return NO_ERROR; +} + +int arch_mmu_protect(arch_aspace_t* aspace, vaddr_t vaddr, size_t count, uint flags) { + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + LTRACEF("aspace %p, vaddr 0x%lx count %lx flags 0x%x\n", aspace, vaddr, count, flags); + + if (!x86_mmu_check_vaddr(vaddr)) return ERR_INVALID_ARGS; + if (!is_valid_vaddr(aspace, vaddr)) return ERR_INVALID_ARGS; + if (count == 0) return NO_ERROR; + + MappingCursor start = { + .paddr = 0, .vaddr = vaddr, .size = count * PAGE_SIZE, + }; + MappingCursor result; + status_t status = x86_mmu_update_mapping(aspace->pt_phys, aspace->pt_virt, + flags, start, &result); + if (status != NO_ERROR) { + return status; + } + DEBUG_ASSERT(result.size == 0); + return NO_ERROR; +} + +void x86_mmu_early_init() { + x86_mmu_mem_type_init(); + x86_mmu_percpu_init(); + +#if ARCH_X86_64 + /* unmap the lower identity mapping */ + unmap_entry(x86_get_cr3(), 0, &pml4[0], true); +#else + /* unmap the lower identity mapping */ + for (uint i = 0; i < (1 * GB) / (4 * MB); i++) { + pd[i] = 0; + } + + /* tlb flush */ + tlb_global_invalidate(); +#endif + + /* get the address width from the CPU */ + uint8_t vaddr_width = x86_linear_address_width(); + uint8_t paddr_width = x86_physical_address_width(); + + /* if we got something meaningful, override the defaults. + * some combinations of cpu on certain emulators seems to return + * nonsense paddr widths (1), so trim it. */ + if (paddr_width > g_paddr_width) g_paddr_width = paddr_width; + if (vaddr_width > g_vaddr_width) g_vaddr_width = vaddr_width; + + LTRACEF("paddr_width %u vaddr_width %u\n", g_paddr_width, g_vaddr_width); +} + +void x86_mmu_init(void) {} + +/* + * Fill in the high level x86 arch aspace structure and allocating a top level page table. + */ +status_t arch_mmu_init_aspace(arch_aspace_t* aspace, vaddr_t base, size_t size, uint flags) { + DEBUG_ASSERT(aspace); + DEBUG_ASSERT(aspace->magic != ARCH_ASPACE_MAGIC); + + LTRACEF("aspace %p, base 0x%lx, size 0x%zx, flags 0x%x\n", aspace, base, size, flags); + + aspace->magic = ARCH_ASPACE_MAGIC; + aspace->flags = flags; + aspace->base = base; + aspace->size = size; + if (flags & ARCH_ASPACE_FLAG_KERNEL) { + aspace->pt_phys = kernel_pt_phys; + aspace->pt_virt = (pt_entry_t*)X86_PHYS_TO_VIRT(aspace->pt_phys); + LTRACEF("kernel aspace: pt phys 0x%lx, virt %p\n", aspace->pt_phys, aspace->pt_virt); + } else { +#if ARCH_X86_32 + /* not fully functional on 32bit x86 */ + return ERR_NOT_SUPPORTED; +#else + /* allocate a top level page table for the new address space */ + paddr_t pa; + aspace->pt_virt = (pt_entry_t*)pmm_alloc_kpage(&pa); + if (!aspace->pt_virt) { + TRACEF("error allocating top level page directory\n"); + return ERR_NO_MEMORY; + } + aspace->pt_phys = pa; + + /* zero out the user space half of it */ + memset(aspace->pt_virt, 0, sizeof(pt_entry_t) * NO_OF_PT_ENTRIES / 2); + + /* copy the kernel portion of it from the master kernel pt */ + memcpy(aspace->pt_virt + NO_OF_PT_ENTRIES / 2, &KERNEL_PT[NO_OF_PT_ENTRIES / 2], + sizeof(pt_entry_t) * NO_OF_PT_ENTRIES / 2); + + LTRACEF("user aspace: pt phys 0x%lx, virt %p\n", aspace->pt_phys, aspace->pt_virt); +#endif + } + aspace->io_bitmap_ptr = NULL; + spin_lock_init(&aspace->io_bitmap_lock); + + return NO_ERROR; +} + +status_t arch_mmu_destroy_aspace(arch_aspace_t* aspace) { + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + +#if LK_DEBUGLEVEL > 1 + pt_entry_t *table = static_cast(aspace->pt_virt); + uint start = vaddr_to_index(aspace->base); + uint end = vaddr_to_index(aspace->base + aspace->size - 1); + + // Don't check start if that table is shared with another aspace + if (!page_aligned(aspace->base)) { + start += 1; + } + // Do check the end if it fills out the table entry + if (page_aligned(aspace->base + aspace->size)) { + end += 1; + } + + for (uint i = start; i < end; ++i) { + DEBUG_ASSERT(!IS_PAGE_PRESENT(table[i])); + } +#endif + + if (aspace->io_bitmap_ptr) { + free(aspace->io_bitmap_ptr); + } + + pmm_free_page(paddr_to_vm_page(aspace->pt_phys)); + + aspace->magic = 0; + + return NO_ERROR; +} + +void arch_mmu_context_switch(arch_aspace_t *old_aspace, arch_aspace_t *aspace) { + if (aspace != NULL) { + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + LTRACEF_LEVEL(3, "switching to aspace %p, pt 0x%lx\n", aspace, aspace->pt_phys); + x86_set_cr3(aspace->pt_phys); + } else { + LTRACEF_LEVEL(3, "switching to kernel aspace, pt 0x%lx\n", kernel_pt_phys); + x86_set_cr3(kernel_pt_phys); + } + + /* set the io bitmap for this thread */ + bool set_bitmap = false; + if (aspace) { + spin_lock(&aspace->io_bitmap_lock); + if (aspace->io_bitmap_ptr) { + x86_set_tss_io_bitmap(static_cast(aspace->io_bitmap_ptr)); + set_bitmap = true; + } + spin_unlock(&aspace->io_bitmap_lock); + } + if (!set_bitmap && old_aspace && old_aspace->io_bitmap_ptr) { + x86_clear_tss_io_bitmap(); + } +} + +status_t arch_mmu_query(arch_aspace_t* aspace, vaddr_t vaddr, paddr_t* paddr, uint* flags) { + DEBUG_ASSERT(aspace->magic == ARCH_ASPACE_MAGIC); + + page_table_levels ret_level; + + LTRACEF("aspace %p, vaddr 0x%lx, paddr %p, flags %p\n", aspace, vaddr, paddr, flags); + + DEBUG_ASSERT(aspace); + + if (!paddr) return ERR_INVALID_ARGS; + + if (!is_valid_vaddr(aspace, vaddr)) return ERR_INVALID_ARGS; + + pt_entry_t* last_valid_entry; + status_t stat = x86_mmu_get_mapping(aspace->pt_virt, vaddr, &ret_level, + &last_valid_entry); + if (stat != NO_ERROR) return stat; + + DEBUG_ASSERT(last_valid_entry); + LTRACEF("last_valid_entry (%p) 0x%" PRIxPTE ", level %u\n", last_valid_entry, *last_valid_entry, + ret_level); + + /* based on the return level, parse the page table entry */ + switch (ret_level) { +#if X86_PAGING_LEVELS > 2 + case PDP_L: /* 1GB page */ + *paddr = paddr_from_pte(*last_valid_entry); + *paddr |= vaddr & PAGE_OFFSET_MASK_HUGE; + break; +#endif + case PD_L: /* 2MB page */ + *paddr = paddr_from_pte(*last_valid_entry); + *paddr |= vaddr & PAGE_OFFSET_MASK_LARGE; + break; + case PT_L: /* 4K page */ + *paddr = paddr_from_pte(*last_valid_entry); + *paddr |= vaddr & PAGE_OFFSET_MASK_4KB; + break; + default: + panic("arch_mmu_query: unhandled frame level\n"); + } + + LTRACEF("paddr 0x%lx\n", *paddr); + + /* converting x86 arch specific flags to arch mmu flags */ + if (flags) { + *flags = arch_mmu_flags(*last_valid_entry, ret_level); + } + + return NO_ERROR; +} + +void x86_mmu_percpu_init(void) { + ulong cr0 = x86_get_cr0(); + /* Set write protect bit in CR0*/ + cr0 |= X86_CR0_WP; + // Clear Cache disable/not write-through bits + cr0 &= ~(X86_CR0_NW | X86_CR0_CD); + x86_set_cr0(cr0); + + /* Setting the SMEP & SMAP bit in CR4 */ + ulong cr4 = x86_get_cr4(); + if (x86_feature_test(X86_FEATURE_SMEP)) cr4 |= X86_CR4_SMEP; + if (x86_feature_test(X86_FEATURE_SMAP)) cr4 |= X86_CR4_SMAP; + x86_set_cr4(cr4); + + /* Set NXE bit in MSR_EFER*/ + uint64_t efer_msr = read_msr(X86_MSR_EFER); + efer_msr |= X86_EFER_NXE; + write_msr(X86_MSR_EFER, efer_msr); +} diff --git a/kernel/arch/x86/mmu_mem_types.c b/kernel/arch/x86/mmu_mem_types.c new file mode 100644 index 000000000..f01971b36 --- /dev/null +++ b/kernel/arch/x86/mmu_mem_types.c @@ -0,0 +1,261 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* address widths from mmu.c */ +extern uint8_t g_paddr_width; + +/* MTRR MSRs */ +#define IA32_MTRRCAP 0xfe +#define IA32_MTRR_DEF_TYPE 0x2ff +#define IA32_MTRR_FIX64K_00000 0x250 +#define IA32_MTRR_FIX16K_80000 0x258 +#define IA32_MTRR_FIX16K_A0000 0x259 +#define IA32_MTRR_NUM_FIX4K 8 +#define IA32_MTRR_FIX4K_C0000(x) (0x268 + (x)) +#define IA32_MTRR_PHYSBASE(x) (0x200 + 2 * (x)) +#define IA32_MTRR_PHYSMASK(x) (0x201 + 2 * (x)) + +/* PAT MSRs */ +#define IA32_PAT 0x277 + +/* IA32_MTRRCAP read functions */ +#define MTRRCAP_VCNT(x) ((x) & 0xff) +#define MTRRCAP_FIX(x) !!((x) & (1 << 8)) +#define MTRRCAP_WC(x) !!((x) & (1 << 10)) + +/* IA32_MTRR_DEF_TYPE read functions */ +/* global enable flag for MTRRs */ +#define MTRR_DEF_TYPE_ENABLE(x) ((x) & (1 << 11)) +/* enable flag for fixed-range MTRRs */ +#define MTRR_DEF_TYPE_FIXED_ENABLE(x) ((x) & (1 << 10)) +#define MTRR_DEF_TYPE_TYPE(x) ((uint8_t)(x)) + +/* IA32_MTRR_PHYSBASE read functions */ +#define MTRR_PHYSBASE_BASE(x) ((x) & ~((1 << 12) - 1) & ((1 << g_paddr_width) - 1)) +#define MTRR_PHYSBASE_TYPE(x) ((uint8_t)(x)) + +/* IA32_MTRR_PHYSMASK read functions */ +#define MTRR_PHYSMASK_MASK(x) ((x) & ~((1 << 12) - 1) & ((1 << g_paddr_width) - 1)) +#define MTRR_PHYSMASK_VALID(x) !!((x) & (1 << 11)) + +/* Number of variable length MTRRs */ +static uint8_t num_variable = 0; +/* Whether or not fixed range MTRRs are supported */ +static bool supports_fixed_range = false; +/* Whether write-combining memory type is supported */ +static bool supports_wc = false; + +/* Function called by all CPUs to setup their PAT */ +static void x86_pat_sync_task(void *context); +struct pat_sync_task_context { + /* Barrier counters for the two barriers described in Intel's algorithm */ + volatile int barrier1; + volatile int barrier2; +}; + +void x86_mmu_mem_type_init(void) +{ + uint64_t caps = read_msr(IA32_MTRRCAP); + num_variable = MTRRCAP_VCNT(caps); + supports_fixed_range = MTRRCAP_FIX(caps); + supports_wc = MTRRCAP_WC(caps); +} + +/* @brief Give all CPUs our Page Attribute Tables + * + * This algorithm is based on section 11.11.8 of Intel 3A + * This must only be called after the APs are brought up. + */ +void x86_pat_sync(void) +{ + int num_cpus = arch_max_num_cpus(); + uint target = mp_get_online_mask(); + /* This operation is not hotplug aware */ + ASSERT(target == (1U << num_cpus) - 1); + + struct pat_sync_task_context context = { + .barrier1 = num_cpus, + .barrier2 = num_cpus, + }; + /* Step 1: Broadcast to all processors to execute the sequence */ + mp_sync_exec(MP_CPU_ALL, x86_pat_sync_task, &context); +} + +static void x86_pat_sync_task(void *raw_context) +{ + /* Step 2: Disable interrupts */ + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + + struct pat_sync_task_context *context = raw_context; + + /* Step 3: Wait for all processors to reach this point. */ + atomic_add(&context->barrier1, -1); + while (context->barrier1 != 0) { + arch_spinloop_pause(); + } + + /* Step 4: Enter the no-fill cache mode (cache-disable and writethrough) */ + ulong cr0 = x86_get_cr0(); + DEBUG_ASSERT(!(cr0 & X86_CR0_CD) && !(cr0 & X86_CR0_NW)); + cr0 |= X86_CR0_CD; + cr0 &= ~X86_CR0_NW; + x86_set_cr0(cr0); + + /* Step 5: Flush all caches */ + __asm volatile ("wbinvd" ::: "memory"); + + /* Step 6: If the PGE flag is set, clear it to flush the TLB */ + ulong cr4 = x86_get_cr4(); + bool pge_was_set = !!(cr4 & X86_CR4_PGE); + cr4 &= ~X86_CR4_PGE; + x86_set_cr4(cr4); + + /* Step 7: If the PGE flag wasn't set, flush the TLB via CR3 */ + if (!pge_was_set) { + x86_set_cr3(x86_get_cr3()); + } + + /* Starting from here, we diverge from the algorithm in 11.11.8. That + * algorithm is for MTRR changes, and 11.12.4 suggests using a variant of + * it. + */ + + /* Perform PAT changes now that caches aren't being filled and the + * TLB is flushed. */ + uint64_t pat_val = 0; + pat_val |= (uint64_t)X86_PAT_INDEX0 << 0; + pat_val |= (uint64_t)X86_PAT_INDEX1 << 8; + pat_val |= (uint64_t)X86_PAT_INDEX2 << 16; + pat_val |= (uint64_t)X86_PAT_INDEX3 << 24; + pat_val |= (uint64_t)X86_PAT_INDEX4 << 32; + pat_val |= (uint64_t)X86_PAT_INDEX5 << 40; + pat_val |= (uint64_t)X86_PAT_INDEX6 << 48; + pat_val |= (uint64_t)X86_PAT_INDEX7 << 56; + write_msr(IA32_PAT, pat_val); + + /* Step 11: Flush all cache and the TLB again */ + __asm volatile ("wbinvd" ::: "memory"); + x86_set_cr3(x86_get_cr3()); + + /* Step 12: Enter the normal cache mode */ + cr0 = x86_get_cr0(); + cr0 &= ~(X86_CR0_CD | X86_CR0_NW); + x86_set_cr0(cr0); + + /* Step 13: Re-enable PGE if it was previously set */ + if (pge_was_set) { + cr4 = x86_get_cr4(); + cr4 |= X86_CR4_PGE; + x86_set_cr4(cr4); + } + + /* Step 14: Wait for all processors to reach this point. */ + atomic_add(&context->barrier2, -1); + while (context->barrier2 != 0) { + arch_spinloop_pause(); + } + + /* Step 15: Re-enable interrupts */ + arch_interrupt_restore(state, 0); +} + +/* Helper for decoding and printing MTRRs */ +static void print_fixed_range_mtrr(uint32_t msr, uint32_t base, uint32_t record_size) +{ + uint64_t val = read_msr(msr); + for (int i = 0; i < 8; ++i) { + printf(" f %#05x-%#05x: %#02x\n", base, base + record_size - 1, (uint8_t)val); + base += record_size; + val >>= 8; + } +} + +static void print_pat_entries(void *_ignored) +{ + uint64_t pat = read_msr(IA32_PAT); + for (int i = 0; i < 8; ++i) { + printf(" Index %d: %#02x\n", i, (uint8_t)pat); + pat >>= 8; + } +} + +static int cmd_memtype(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("%s mtrr\n", argv[0].str); + printf("%s pat\n", argv[0].str); + return ERR_GENERIC; + } + + if (!strcmp(argv[1].str, "mtrr")) { + bool print_fixed = false; + if (argc > 2) { + if (!strcmp(argv[2].str, "-f")) { + print_fixed = true; + } else { + printf("usage: %s mtrr [-f]\n", argv[0].str); + printf(" -f Display fixed registers\n"); + return ERR_GENERIC; + } + } + uint64_t default_type = read_msr(IA32_MTRR_DEF_TYPE); + printf("MTRR state: master %s, fixed %s\n", + MTRR_DEF_TYPE_ENABLE(default_type) ? "enable" : "disable", + MTRR_DEF_TYPE_FIXED_ENABLE(default_type) ? "enable" : "disable"); + printf(" default: %#02x\n", MTRR_DEF_TYPE_TYPE(default_type)); + if (supports_fixed_range && print_fixed) { + print_fixed_range_mtrr(IA32_MTRR_FIX64K_00000, 0x00000, (1 << 16)); + print_fixed_range_mtrr(IA32_MTRR_FIX16K_80000, 0x80000, (1 << 14)); + print_fixed_range_mtrr(IA32_MTRR_FIX16K_A0000, 0xA0000, (1 << 14)); + for (int i = 0; i < IA32_MTRR_NUM_FIX4K; ++i) { + print_fixed_range_mtrr(IA32_MTRR_FIX4K_C0000(i), 0xC0000 + i * (1<<15), (1 << 12)); + } + } + + for (uint i = 0; i < num_variable; ++i) { + uint64_t base = read_msr(IA32_MTRR_PHYSBASE(i)); + uint64_t mask = read_msr(IA32_MTRR_PHYSMASK(i)); + printf(" v (%s) base %#016llx, mask %#016llx: %#02x\n", + MTRR_PHYSMASK_VALID(mask) ? "valid" : "invalid", + MTRR_PHYSBASE_BASE(base), + MTRR_PHYSMASK_MASK(mask), + MTRR_PHYSBASE_TYPE(base)); + } + } else if (!strcmp(argv[1].str, "pat")) { + uint num_cpus = arch_max_num_cpus(); + for (uint i = 0; i < num_cpus; ++i) { + printf("CPU %u Page Attribute Table types:\n", i); + mp_sync_exec(1 << i, print_pat_entries, NULL); + } + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("memtype", "memory type commands", &cmd_memtype) +#endif +STATIC_COMMAND_END(memtype); diff --git a/kernel/arch/x86/mp.c b/kernel/arch/x86/mp.c new file mode 100644 index 000000000..c1b692ff3 --- /dev/null +++ b/kernel/arch/x86/mp.c @@ -0,0 +1,182 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct x86_percpu bp_percpu; +static struct x86_percpu *ap_percpus; +uint8_t x86_num_cpus = 1; + +status_t x86_allocate_ap_structures(uint8_t cpu_count) +{ + ASSERT(ap_percpus == NULL); + ap_percpus = calloc(sizeof(*ap_percpus), cpu_count - 1); + if (ap_percpus == NULL) { + return ERR_NO_MEMORY; + } + x86_num_cpus = cpu_count; + return NO_ERROR; +} + +void x86_init_percpu(uint8_t cpu_num) +{ + struct x86_percpu *percpu; + if (cpu_num == 0) { + percpu = &bp_percpu; + } else { + percpu = &ap_percpus[cpu_num - 1]; + } + /* set up the percpu structure */ + percpu->direct = percpu; + percpu->cpu_num = cpu_num; + // Start with an invalid id until we know the local APIC is setup + percpu->apic_id = INVALID_APIC_ID; + +#if ARCH_X86_64 + /* point gs at the per cpu structure */ + write_msr(X86_MSR_IA32_GS_BASE, (uintptr_t)percpu); + + /* set the KERNEL_GS_BASE MSR to 0 */ + /* when we enter user space, this will be populated via a swapgs */ + write_msr(X86_MSR_IA32_KERNEL_GS_BASE, 0); +#endif + + x86_feature_init(); + fpu_init(); + + idt_setup(&percpu->idt); + idt_load(&percpu->idt); + + x86_initialize_percpu_tss(); + + x86_mmu_percpu_init(); + +#if ARCH_X86_64 + /* load the syscall entry point */ + extern void x86_syscall(void); + + write_msr(X86_MSR_IA32_LSTAR, (uint64_t)&x86_syscall); + + /* set the STAR MSR to load the appropriate kernel code selector on syscall + * and the appropriate user code selector on return. + * on syscall entry the following are loaded into segment registers: + * CS = CODE_64_SELECTOR (STAR[47:32]) + * SS = DATA_SELECTOR (STAR[47:32] + 0x8) + * on syscall exit: + * CS = USER_CODE_64_SELECTOR (STAR[63:48] + 0x16) + * SS = USER_DATA_SELECTOR (STAR[63:48] + 0x8) + */ + write_msr(X86_MSR_IA32_STAR, (uint64_t)USER_CODE_SELECTOR << 48 | (uint64_t)CODE_64_SELECTOR << 32); + + /* set the FMASK register to mask off certain bits in RFLAGS on syscall entry */ + uint64_t mask = + X86_FLAGS_AC | /* disable alignment check/access control (this + * prevents ring 0 from performing data access + * to ring 3 if SMAP is available) */ + X86_FLAGS_NT | /* clear nested task */ + X86_FLAGS_IOPL_MASK | /* set iopl to 0 */ + X86_FLAGS_STATUS_MASK; /* clear all status flags, interrupt disabled, trap flag */ + write_msr(X86_MSR_IA32_FMASK, mask); + + /* enable syscall instruction */ + uint64_t efer_msr = read_msr(X86_MSR_EFER); + efer_msr |= X86_EFER_SCE; + write_msr(X86_MSR_EFER, efer_msr); +#endif + +#if WITH_SMP + mp_set_curr_cpu_online(true); +#endif +} + +void x86_set_local_apic_id(uint32_t apic_id) +{ + x86_get_percpu()->apic_id = apic_id; +} + +#if WITH_SMP +status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) +{ + uint8_t vector = 0; + switch (ipi) { + case MP_IPI_GENERIC: + vector = X86_INT_IPI_GENERIC; + break; + case MP_IPI_RESCHEDULE: + vector = X86_INT_IPI_RESCHEDULE; + break; + default: + panic("Unexpected MP IPI value: %d", ipi); + } + + if (target == MP_CPU_ALL_BUT_LOCAL) { + apic_send_broadcast_ipi(vector, DELIVERY_MODE_FIXED); + return NO_ERROR; + } else if (target == MP_CPU_ALL) { + apic_send_broadcast_self_ipi(vector, DELIVERY_MODE_FIXED); + return NO_ERROR; + } + + ASSERT(x86_num_cpus <= sizeof(target) * 8); + + mp_cpu_mask_t remaining = target; + uint cpu_id = 0; + while (remaining && cpu_id < x86_num_cpus) { + if (remaining & 1) { + struct x86_percpu *percpu; + if (cpu_id == 0) { + percpu = &bp_percpu; + } else { + percpu = &ap_percpus[cpu_id - 1]; + } + /* Reschedule IPIs may occur before all CPUs are fully up. Just + * ignore attempts to send them to down CPUs. */ + if (ipi != MP_IPI_RESCHEDULE) { + DEBUG_ASSERT(percpu->apic_id != INVALID_APIC_ID); + } + /* Make sure the CPU is actually up before sending the IPI */ + if (percpu->apic_id != INVALID_APIC_ID) { + apic_send_ipi(vector, percpu->apic_id, DELIVERY_MODE_FIXED); + } + } + remaining >>= 1; + cpu_id++; + } + + return NO_ERROR; +} + +enum handler_return x86_ipi_generic_handler(void) +{ + //LTRACEF("cpu %u, arg %p\n", arch_curr_cpu_num(), arg); + return mp_mbx_generic_irq(); +} + +enum handler_return x86_ipi_reschedule_handler(void) +{ + //TRACEF("rescheduling on cpu %u, arg %p\n", arch_curr_cpu_num(), arg); + return mp_mbx_reschedule_irq(); +} +#endif diff --git a/kernel/arch/x86/rules.mk b/kernel/arch/x86/rules.mk new file mode 100644 index 000000000..8e9347dba --- /dev/null +++ b/kernel/arch/x86/rules.mk @@ -0,0 +1,191 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +WITH_KERNEL_VM=1 +WITH_LINKER_GC ?= 1 + +ifeq ($(SUBARCH),x86-32) +MEMBASE ?= 0x00000000 +KERNEL_BASE ?= 0x80000000 +KERNEL_SIZE ?= 0x40000000 # 1GB +KERNEL_LOAD_OFFSET ?= 0x00100000 +HEADER_LOAD_OFFSET ?= 0x00010000 +PHYS_HEADER_LOAD_OFFSET ?= 0x00002000 +KERNEL_ASPACE_BASE ?= 0x80000000 +KERNEL_ASPACE_SIZE ?= 0x7ff00000 +USER_ASPACE_BASE ?= 0x01000000 # 16MB +USER_ASPACE_SIZE ?= 0x7e000000 # full 2GB - 32MB + +SUBARCH_DIR := $(LOCAL_DIR)/32 +endif +ifeq ($(SUBARCH),x86-64) +GLOBAL_DEFINES += \ + IS_64BIT=1 \ + +MEMBASE ?= 0 +KERNEL_BASE ?= 0xffffffff80000000 +KERNEL_SIZE ?= 0x40000000 # 1GB +KERNEL_LOAD_OFFSET ?= 0x00100000 +HEADER_LOAD_OFFSET ?= 0x00010000 +PHYS_HEADER_LOAD_OFFSET ?= 0x00002000 +KERNEL_ASPACE_BASE ?= 0xffffff8000000000UL # -512GB +KERNEL_ASPACE_SIZE ?= 0x0000008000000000UL +USER_ASPACE_BASE ?= 0x0000000001000000UL # 16MB +USER_ASPACE_SIZE ?= 0x00007fffff000000UL # full user address space size - 16MB +SUBARCH_DIR := $(LOCAL_DIR)/64 +endif + +SUBARCH_BUILDDIR := $(call TOBUILDDIR,$(SUBARCH_DIR)) + +GLOBAL_DEFINES += \ + ARCH_$(SUBARCH)=1 \ + MEMBASE=$(MEMBASE) \ + KERNEL_BASE=$(KERNEL_BASE) \ + KERNEL_SIZE=$(KERNEL_SIZE) \ + KERNEL_LOAD_OFFSET=$(KERNEL_LOAD_OFFSET) \ + KERNEL_ASPACE_BASE=$(KERNEL_ASPACE_BASE) \ + KERNEL_ASPACE_SIZE=$(KERNEL_ASPACE_SIZE) \ + PHYS_HEADER_LOAD_OFFSET=$(PHYS_HEADER_LOAD_OFFSET) \ + USER_ASPACE_BASE=$(USER_ASPACE_BASE) \ + USER_ASPACE_SIZE=$(USER_ASPACE_SIZE) \ + PLATFORM_HAS_DYNAMIC_TIMER=1 + +MODULE_SRCS += \ + $(SUBARCH_DIR)/start.S \ + $(SUBARCH_DIR)/asm.S \ + $(SUBARCH_DIR)/exceptions.S \ + $(SUBARCH_DIR)/ops.S \ +\ + $(LOCAL_DIR)/arch.c \ + $(LOCAL_DIR)/cache.c \ + $(LOCAL_DIR)/descriptor.c \ + $(LOCAL_DIR)/faults.c \ + $(LOCAL_DIR)/feature.c \ + $(LOCAL_DIR)/fpu.c \ + $(LOCAL_DIR)/gdt.S \ + $(LOCAL_DIR)/header.S \ + $(LOCAL_DIR)/idt.c \ + $(LOCAL_DIR)/ioapic.c \ + $(LOCAL_DIR)/ioport.c \ + $(LOCAL_DIR)/lapic.c \ + $(LOCAL_DIR)/mmu.cpp \ + $(LOCAL_DIR)/mmu_mem_types.c \ + $(LOCAL_DIR)/mp.c \ + $(LOCAL_DIR)/thread.c \ + $(LOCAL_DIR)/user_copy.c \ + +ifeq ($(SUBARCH),x86-64) +MODULE_SRCS += \ + $(SUBARCH_DIR)/syscall.S \ + $(SUBARCH_DIR)/user_copy.S +endif + +include $(LOCAL_DIR)/toolchain.mk + +# Enable SMP for x86-64 +ifeq ($(SUBARCH),x86-64) +GLOBAL_DEFINES += \ + WITH_SMP=1 \ + SMP_MAX_CPUS=16 +MODULE_SRCS += \ + $(SUBARCH_DIR)/bootstrap16.c \ + $(SUBARCH_DIR)/start16.S \ + $(SUBARCH_DIR)/uspace_entry.S \ + $(SUBARCH_DIR)/smp.c +endif # SUBARCH x86-64 +ifeq ($(SUBARCH),x86-32) +GLOBAL_DEFINES += \ + SMP_MAX_CPUS=1 +endif # SUBARCH x86-32 + +# set the default toolchain to x86 elf and set a #define +ifeq ($(SUBARCH),x86-32) +ifndef TOOLCHAIN_PREFIX +TOOLCHAIN_PREFIX := $(ARCH_x86_TOOLCHAIN_PREFIX) +endif +endif # SUBARCH x86-32 +ifeq ($(SUBARCH),x86-64) +ifndef TOOLCHAIN_PREFIX +TOOLCHAIN_PREFIX := $(ARCH_x86_64_TOOLCHAIN_PREFIX) +endif +endif # SUBARCH x86-64 + +#$(warning ARCH_x86_TOOLCHAIN_PREFIX = $(ARCH_x86_TOOLCHAIN_PREFIX)) +#$(warning ARCH_x86_64_TOOLCHAIN_PREFIX = $(ARCH_x86_64_TOOLCHAIN_PREFIX)) +#$(warning TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX)) + +ifeq ($(CLANG),1) +ifeq ($(LIBGCC),) +$(error cannot find runtime library, please set LIBGCC) +endif +else +LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -print-libgcc-file-name) +endif + +cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`"; \ + then echo "$(2)"; else echo "$(3)"; fi ;) + +# disable SSP if the compiler supports it; it will break stuff +GLOBAL_CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) + +GLOBAL_COMPILEFLAGS += -gdwarf-2 +GLOBAL_COMPILEFLAGS += -fno-pic +ifeq ($(CLANG),1) +GLOBAL_LDFLAGS = -m elf_x86_64 +GLOBAL_MODULE_LDFLAGS= -m elf_x86_64 +endif +GLOBAL_LDFLAGS += -z max-page-size=4096 +ifneq ($(CLANG),1) +KERNEL_COMPILEFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=4 +endif + +# hard disable floating point in the kernel +KERNEL_COMPILEFLAGS += -msoft-float -mno-mmx -mno-sse -mno-sse2 -mno-3dnow -mno-avx -mno-avx2 -DWITH_NO_FP=1 +ifneq ($(CLANG),1) +KERNEL_COMPILEFLAGS += -mno-80387 -mno-fp-ret-in-387 +endif + +ifeq ($(CLANG),1) +GLOBAL_COMPILEFLAGS += -target x86_64-elf -integrated-as +endif + +ifeq ($(SUBARCH),x86-32) +# get at least 686 so builtin atomic routines are picked up +GLOBAL_COMPILEFLAGS += -march=i686 +endif + +ifeq ($(SUBARCH),x86-64) +KERNEL_COMPILEFLAGS += -mcmodel=kernel +KERNEL_COMPILEFLAGS += -mno-red-zone + +# optimization: since fpu is disabled, do not pass flag in rax to varargs routines +# that floating point args are in use. +ifneq ($(CLANG),1) +KERNEL_COMPILEFLAGS += -mskip-rax-setup +endif +endif # SUBARCH x86-64 + +ARCH_OPTFLAGS := -O2 + +USER_LINKER_SCRIPT := $(SUBARCH_DIR)/user.ld +LINKER_SCRIPT += $(SUBARCH_BUILDDIR)/kernel.ld + +# potentially generated files that should be cleaned out with clean make rule +GENERATED += $(SUBARCH_BUILDDIR)/kernel.ld + +# rules for generating the linker scripts +$(SUBARCH_BUILDDIR)/kernel.ld: $(SUBARCH_DIR)/kernel.ld $(wildcard arch/*.ld) + @echo generating $@ + @$(MKDIR) + $(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/;s/%HEADER_LOAD_OFFSET%/$(HEADER_LOAD_OFFSET)/;s/%PHYS_HEADER_LOAD_OFFSET%/$(PHYS_HEADER_LOAD_OFFSET)/;" < $< > $@.tmp + @$(call TESTANDREPLACEFILE,$@.tmp,$@) + +include make/module.mk diff --git a/kernel/arch/x86/thread.c b/kernel/arch/x86/thread.c new file mode 100644 index 000000000..4d3fd0ccf --- /dev/null +++ b/kernel/arch/x86/thread.c @@ -0,0 +1,154 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2014 Travis Geiselbrecht +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void arch_thread_initialize(thread_t *t, vaddr_t entry_point) +{ + // create a default stack frame on the stack + vaddr_t stack_top = (vaddr_t)t->stack + t->stack_size; + +#if ARCH_X86_32 + // make sure the top of the stack is 8 byte aligned for ABI compliance + stack_top = ROUNDDOWN(stack_top, 8); + struct x86_32_context_switch_frame *frame = (struct x86_32_context_switch_frame *)(stack_top); +#endif +#if ARCH_X86_64 + // make sure the top of the stack is 16 byte aligned for ABI compliance + stack_top = ROUNDDOWN(stack_top, 16); + + // make sure we start the frame 8 byte unaligned (relative to the 16 byte alignment) because + // of the way the context switch will pop the return address off the stack. After the first + // context switch, this leaves the stack in unaligned relative to how a called function expects it. + stack_top -= 8; + struct x86_64_context_switch_frame *frame = (struct x86_64_context_switch_frame *)(stack_top); +#endif + + // move down a frame size and zero it out + frame--; + memset(frame, 0, sizeof(*frame)); + +#if ARCH_X86_32 + frame->eip = entry_point; + frame->eflags = 0x3002; // IF = 0, NT = 0, IOPL = 3 +#endif + +#if ARCH_X86_64 + frame->rip = entry_point; + frame->rflags = 0x3002; /* IF = 0, NT = 0, IOPL = 3 */ +#endif + + // initialize the saved fpu state + fpu_init_thread_states(t); + + // set the stack pointer + t->arch.sp = (vaddr_t)frame; + + // initialize the fs, gs and kernel bases to 0. +#if ARCH_X86_64 + t->arch.fs_base = 0; + t->arch.gs_base = 0; +#endif +} + +void arch_dump_thread(thread_t *t) +{ + if (t->state != THREAD_RUNNING) { + dprintf(INFO, "\tarch: "); + dprintf(INFO, "sp 0x%lx\n", t->arch.sp); + } +} + +#if ARCH_X86_32 + +void arch_context_switch(thread_t *oldthread, thread_t *newthread) +{ + //dprintf(DEBUG, "arch_context_switch: old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name); + + fpu_context_switch(oldthread, newthread); + + __asm__ __volatile__ ( + "pushl $1f \n\t" + "pushf \n\t" + "pusha \n\t" + "movl %%esp,(%%edx) \n\t" + "movl %%eax,%%esp \n\t" + "popa \n\t" + "popf \n\t" + "ret \n\t" + "1: \n\t" + + : + : "d" (&oldthread->arch.sp), "a" (newthread->arch.sp) + ); + + /*__asm__ __volatile__ ( + "pushf \n\t" + "pushl %%cs \n\t" + "pushl $1f \n\t" + "pushl %%gs \n\t" + "pushl %%fs \n\t" + "pushl %%es \n\t" + "pushl %%ds \n\t" + "pusha \n\t" + "movl %%esp,(%%edx) \n\t" + "movl %%eax,%%esp \n\t" + "popa \n\t" + "popl %%ds \n\t" + "popl %%es \n\t" + "popl %%fs \n\t" + "popl %%gs \n\t" + "iret \n\t" + "1: " + : + : "d" (&oldthread->arch.sp), "a" (newthread->arch.sp) + );*/ +} +#endif + +#if ARCH_X86_64 + +void arch_context_switch(thread_t *oldthread, thread_t *newthread) +{ + fpu_context_switch(oldthread, newthread); + + /* TODO: precompute the stack top and put in the thread structure directly */ + vaddr_t kstack_top = (vaddr_t)newthread->stack + newthread->stack_size; + kstack_top = ROUNDDOWN(kstack_top, 16); + + //printf("cs 0x%llx\n", kstack_top); + + /* set the tss SP0 value to point at the top of our stack */ + x86_set_tss_sp(kstack_top); + + /* set the kernel sp in our per cpu gs: structure */ + x86_set_percpu_kernel_sp(kstack_top); + + /* user and kernel gs have been swapped, so unswap them when loading + * from the msrs + */ + oldthread->arch.fs_base = read_msr(X86_MSR_IA32_FS_BASE); + oldthread->arch.gs_base = read_msr(X86_MSR_IA32_KERNEL_GS_BASE); + + write_msr(X86_MSR_IA32_FS_BASE, newthread->arch.fs_base); + write_msr(X86_MSR_IA32_KERNEL_GS_BASE, newthread->arch.gs_base); + + x86_64_context_switch(&oldthread->arch.sp, newthread->arch.sp); +} +#endif + diff --git a/kernel/arch/x86/toolchain.mk b/kernel/arch/x86/toolchain.mk new file mode 100644 index 000000000..599222c64 --- /dev/null +++ b/kernel/arch/x86/toolchain.mk @@ -0,0 +1,45 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# x86-32 toolchain +ifeq ($(SUBARCH),x86-32) +ifndef ARCH_x86_TOOLCHAIN_INCLUDED +ARCH_x86_TOOLCHAIN_INCLUDED := 1 + +ifndef ARCH_x86_TOOLCHAIN_PREFIX +ARCH_x86_TOOLCHAIN_PREFIX := i386-elf- +endif +FOUNDTOOL=$(shell which $(ARCH_x86_TOOLCHAIN_PREFIX)gcc) + +ifeq ($(FOUNDTOOL),) +$(error cannot find toolchain, please set ARCH_x86_TOOLCHAIN_PREFIX or add it to your path) +endif + +endif +endif + +# x86-64 toolchain +ifeq ($(SUBARCH),x86-64) +ifndef ARCH_x86_64_TOOLCHAIN_INCLUDED +ARCH_x86_64_TOOLCHAIN_INCLUDED := 1 + +ifndef ARCH_x86_64_TOOLCHAIN_PREFIX +ARCH_x86_64_TOOLCHAIN_PREFIX := x86_64-elf- +endif +ifeq ($(CLANG),1) +FOUNDTOOL=$(shell which $(ARCH_x86_64_TOOLCHAIN_PREFIX)clang) +else +FOUNDTOOL=$(shell which $(ARCH_x86_64_TOOLCHAIN_PREFIX)gcc) +endif + +ifeq ($(FOUNDTOOL),) +$(error cannot find toolchain, please set ARCH_x86_64_TOOLCHAIN_PREFIX or add it to your path) +endif + +endif +endif + diff --git a/kernel/arch/x86/user_copy.c b/kernel/arch/x86/user_copy.c new file mode 100644 index 000000000..93b945fd2 --- /dev/null +++ b/kernel/arch/x86/user_copy.c @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +static inline bool ac_flag(void) +{ + return x86_save_flags() & X86_FLAGS_AC; +} + +status_t arch_copy_from_user(void *dst, const void *src, size_t len) +{ + DEBUG_ASSERT(!ac_flag()); + + thread_t *thr = get_current_thread(); + status_t status = + _x86_copy_from_user(dst, src, len, &thr->arch.page_fault_resume); + + DEBUG_ASSERT(!ac_flag()); + return status; +} + +status_t arch_copy_to_user(void *dst, const void *src, size_t len) +{ + DEBUG_ASSERT(!ac_flag()); + + thread_t *thr = get_current_thread(); + status_t status; + status = _x86_copy_to_user(dst, src, len, &thr->arch.page_fault_resume); + + DEBUG_ASSERT(!ac_flag()); + return status; +} + +static bool can_access(const void *base, size_t len, bool for_write) +{ + LTRACEF("can_access: base %p, len %lu\n", base, len); + + // If the target wraps around, it would be possible for the start + // and end to be user addresses but intermediate address to not be. + // Since the user address space is a contiguous range, we can + // get by with checking the start and end if there was no wrap-around. + vaddr_t base_vaddr = (vaddr_t)base; + if (base_vaddr + len < base_vaddr) { + return false; + } + bool in_range = is_user_address(base_vaddr) && + is_user_address(base_vaddr + len - 1); + if (!in_range) { + return false; + } + + // We don't care about whether pages are actually mapped or what their + // permissions are, as long as they are in the user address space. We + // rely on a page fault occurring if an actual permissions error occurs. + DEBUG_ASSERT(x86_get_cr0() & X86_CR0_WP); + return true; +} + +bool _x86_usercopy_can_read(const void *base, size_t len) +{ + return can_access(base, len, false); +} + +bool _x86_usercopy_can_write(const void *base, size_t len) +{ + return can_access(base, len, true); +} diff --git a/kernel/dev/BUILD.gn b/kernel/dev/BUILD.gn new file mode 100644 index 000000000..2b526d05d --- /dev/null +++ b/kernel/dev/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("dev") { + sources = [ + "class/block_api.c", + "class/fb_api.c", + "class/i2c_api.c", + "class/netif_api.c", + "class/spi_api.c", + "class/uart_api.c", + "dev.c", + "driver.c", + ] + deps = [ + "//kernel/lib/gfxconsole", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/broadwell_chipset_config/BUILD.gn b/kernel/dev/broadwell_chipset_config/BUILD.gn new file mode 100644 index 000000000..31fea650d --- /dev/null +++ b/kernel/dev/broadwell_chipset_config/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_broadwell_chipset_config_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("broadwell_chipset_config") { + public_configs = [ ":_broadwell_chipset_config_config" ] + sources = [ + "broadwell_chipset_config.c", + ] + deps = [ + "//kernel/dev/pcie", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/broadwell_chipset_config/broadwell_chipset_config.c b/kernel/dev/broadwell_chipset_config/broadwell_chipset_config.c new file mode 100644 index 000000000..247e1204f --- /dev/null +++ b/kernel/dev/broadwell_chipset_config/broadwell_chipset_config.c @@ -0,0 +1,409 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Chipset configuration registers (as well as a ton of other registers) are all + * hidden in various places underneath the Very Special 0:31.0 BDF function in + * PCI. The device class/subclass indicates that it is an ISA bridge, and the + * PCH documentation calls it the "PCI-LPC bridge" (when not calling it + * something else). See section 5.1, chapter 8 and chapter 10 of the PCH docs + * for more Fun Facts! + */ +#define LPC_BRIDGE_BUS (0x00) +#define LPC_BRIDGE_DEV (0x1F) +#define LPC_BRIDGE_FUNC (0x00) +#define LPC_BRIDGE_VID (0x8086) +static const uint16_t LPC_BRIDGE_DIDS[] = { + 0x9CC1, // Full Featured Engineering Sample with Haswell U Processor + 0x9CC2, // Full Featured Engineering Sample with Broadwell U Processor + 0x9CC3, // Premium SKU with Broadwell U Processor + 0x9CC5, // Base SKU with Broadwell U Processor + 0x9CC6, // Full Featured Engineering Sample with Broadwell Y Processor + 0x9CC7, // Premium SKU with Broadwell Y Processor + 0x9CC9, // Base SKU with Broadwell Y Processor +}; + +/* IOBP registers. Limited documentation available in section 8.1.24 */ +#define IOBPIRI_OFFSET (0x2330u) +#define IOBPD_OFFSET (0x2334u) +#define IOBPS_OFFSET (0x2338u) + +#define IOBP_REGISTER_TIMEOUT (100u) // 100us. Arbitrary; docs provides no guidance here. + +#define IOBPS_BUSY_MASK (0x00000001u) +#define IOBPS_BUSY_SHIFT (0u) +#define IOBPS_BUSY(s) (((s) & IOBPS_BUSY_MASK) >> IOBPS_BUSY_SHIFT) + +#define IOBPS_STATUS_MASK (0x00000006u) +#define IOBPS_STATUS_SHIFT (1u) +#define IOBPS_STATUS(s) (((s) & IOBPS_STATUS_MASK) >> IOBPS_STATUS_SHIFT) +#define IOBPS_STATUS_SUCCESS (0u) +#define IOBPS_STATUS_NOIMPL (1u) +#define IOBPS_STATUS_PWR_DOWN (2u) + +#define IOBPS_IFC_ACCESS_MASK (0x0000FF00u) +#define IOBPS_IFC_ACCESS_SHIFT (8u) +#define IOBPS_IFC_ACCESS_RD (0x00u) +#define IOBPS_IFC_ACCESS_WR (0x01u) +#define IOBPS_IFC_ACCESS_MMAP (0x00u) +#define IOBPS_IFC_ACCESS_IOMAP (0x02u) +#define IOBPS_IFC_ACCESS_PCICFG (0x04u) +#define IOBPS_IFC_ACCESS_ECTRL (0x06u) +#define IOBPS_IFC_ACCESS_CMD(_zone, _rdwr) \ + (0xF0000000 | \ + IOBPS_BUSY_MASK | \ + (((_zone | _rdwr) << IOBPS_IFC_ACCESS_SHIFT) & IOBPS_IFC_ACCESS_MASK)) + +/* Function Disable Registers, see 8.1.81 and 8.1.85 */ +#define CCFG_FD_OFFSET (0x3418u) +#define CCFG_FD2_OFFSET (0x3428u) + +typedef struct chipset_config_state { + pcie_device_state_t* pci_device; + + vmm_aspace_t* aspace; + paddr_t rcba_phys; + void* rcba_virt; + + // Cached pointers to the IOBP interface + volatile uint32_t* IOBPIRI; + volatile uint32_t* IOBPD; + volatile uint32_t* IOBPS; +} chipset_config_state_t; + +chipset_config_state_t g_chipset_config_state; +mutex_t g_lock = MUTEX_INITIAL_VALUE(g_lock); + +static inline status_t iobp_map_status(uint32_t status) { + switch (IOBPS_STATUS(status)) { + case IOBPS_STATUS_SUCCESS: return NO_ERROR; + case IOBPS_STATUS_NOIMPL: return ERR_NOT_IMPLEMENTED; + case IOBPS_STATUS_PWR_DOWN: return ERR_BAD_STATE; + default: return ERR_GENERIC; + } +} + +static inline uint32_t wait_iobp_not_busy(chipset_config_state_t* state) { + uint32_t status; + lk_bigtime_t start = current_time_hires(); + + while ((status = *state->IOBPS) & IOBPS_BUSY_MASK) + if ((current_time_hires() - start) > IOBP_REGISTER_TIMEOUT) + break; + + return status; +} + +static inline status_t read_write_iobp(chipset_config_state_t* state, + uint32_t index, uint32_t *data, bool write) { + uint32_t status; + + DEBUG_ASSERT(state); + DEBUG_ASSERT(data); + + status = wait_iobp_not_busy(state); + if (IOBPS_BUSY(status)) + return ERR_TIMED_OUT; + + *state->IOBPIRI = index; + if (write) { + *state->IOBPD = *data; + *state->IOBPS = IOBPS_IFC_ACCESS_CMD(IOBPS_IFC_ACCESS_ECTRL, IOBPS_IFC_ACCESS_WR); + } else { + *state->IOBPS = IOBPS_IFC_ACCESS_CMD(IOBPS_IFC_ACCESS_ECTRL, IOBPS_IFC_ACCESS_RD); + } + + status = wait_iobp_not_busy(state); + if (IOBPS_BUSY(status)) + return ERR_TIMED_OUT; + + if (!write) + *data = *state->IOBPD; + + return iobp_map_status(status); +} + +static status_t read_iobp(chipset_config_state_t* state, uint32_t index, uint32_t *out_data) { + return read_write_iobp(state, index, out_data, false); +} + +static uint32_t write_iobp(chipset_config_state_t* state, uint32_t index, uint32_t value) { + return read_write_iobp(state, index, &value, true); +} + +/**************************************************************************************** + * + * PCI callback API + * + ****************************************************************************************/ +static void* bcc_pci_probe(pcie_device_state_t* pci_device) { + DEBUG_ASSERT(pci_device); + chipset_config_state_t* state = &g_chipset_config_state; + void* ret = NULL; + + mutex_acquire(&g_lock); + + if ((pci_device->common.vendor_id != LPC_BRIDGE_VID) || + (pci_device->common.bus_id != LPC_BRIDGE_BUS) || + (pci_device->common.dev_id != LPC_BRIDGE_DEV) || + (pci_device->common.func_id != LPC_BRIDGE_FUNC)) + goto finished; + + size_t i; + for (i = 0; i < countof(LPC_BRIDGE_DIDS); ++i) + if (pci_device->common.device_id == LPC_BRIDGE_DIDS[i]) + break; + + if (i >= countof(LPC_BRIDGE_DIDS)) + goto finished; + + DEBUG_ASSERT(!state->pci_device); + state->pci_device = pci_device; + ret = state; + +finished: + mutex_release(&g_lock); + return ret; +} + +static void bcc_pci_shutdown_locked(pcie_device_state_t* pci_device) { + chipset_config_state_t* state = (chipset_config_state_t*)pci_device->driver_ctx; + DEBUG_ASSERT(state == &g_chipset_config_state); + + if (state->aspace) { + if (state->rcba_virt) { + vmm_free_region(state->aspace, (vaddr_t)state->rcba_virt); + state->rcba_virt = NULL; + } + + state->aspace = NULL; + } else { + DEBUG_ASSERT(!state->rcba_virt); + } +} + +static void bcc_pci_shutdown(pcie_device_state_t* pci_device) { + mutex_acquire(&g_lock); + bcc_pci_shutdown_locked(pci_device); + mutex_release(&g_lock); +} + +static status_t bcc_pci_startup(pcie_device_state_t* pci_device) { + chipset_config_state_t* state = (chipset_config_state_t*)pci_device->driver_ctx; + DEBUG_ASSERT(state == &g_chipset_config_state); + + status_t ret; + mutex_acquire(&g_lock); + + /* Find the "root complex base address" and make sure the registers are enabled */ + state->rcba_phys = pcie_read32((volatile uint32_t*)((intptr_t)pci_device->common.cfg + 0xf0)); + state->rcba_phys |= 0x1; + pcie_write32((volatile uint32_t*)((intptr_t)pci_device->common.cfg + 0xf0), state->rcba_phys); + state->rcba_phys &= ~((1u << 14) - 1); + + /* Map in the chipset configuration registers */ + state->aspace = vmm_get_kernel_aspace(); + if (!state->aspace) { + TRACEF("Failed to fetch kernel address space while attempting to map " + "chipset configuration registers.\n"); + ret = ERR_BAD_STATE; + goto finished; + } + + ret = vmm_alloc_physical(state->aspace, + "BW_ChipsetConfigRegs", + 0x4000, + &state->rcba_virt, + PAGE_SIZE_SHIFT, + state->rcba_phys, + 0, + ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + + if (ret != NO_ERROR) { + TRACEF("Failed to map register window (0x%x @ 0x%llx) Status = %d\n", + 0x4000, (uint64_t)state->rcba_phys, ret); + goto finished; + } + + /* Stash pointers to the IOBP register block */ + state->IOBPIRI = (volatile uint32_t*)((intptr_t)state->rcba_virt + IOBPIRI_OFFSET); + state->IOBPD = (volatile uint32_t*)((intptr_t)state->rcba_virt + IOBPD_OFFSET); + state->IOBPS = (volatile uint32_t*)((intptr_t)state->rcba_virt + IOBPS_OFFSET); + +finished: + if (ret != NO_ERROR) + bcc_pci_shutdown_locked(pci_device); + + mutex_release(&g_lock); + return ret; +} + +static void bcc_pci_release(pcie_device_state_t* pci_device) { + mutex_acquire(&g_lock); + + chipset_config_state_t* state = (chipset_config_state_t*)pci_device->driver_ctx; + DEBUG_ASSERT(state == &g_chipset_config_state); + DEBUG_ASSERT(state->pci_device); + DEBUG_ASSERT(!state->aspace); + DEBUG_ASSERT(!state->rcba_phys); + DEBUG_ASSERT(!state->rcba_virt); + + memset(state, 0, sizeof(*state)); + + mutex_release(&g_lock); +} + +static const pcie_driver_fn_table_t BCC_FN_TABLE = { + .pcie_probe_fn = bcc_pci_probe, + .pcie_startup_fn = bcc_pci_startup, + .pcie_shutdown_fn = bcc_pci_shutdown, + .pcie_release_fn = bcc_pci_release, +}; + +STATIC_PCIE_DRIVER(intel_hda, "Broadwell Chipset Config", BCC_FN_TABLE) + +/**************************************************************************************** + * + * Target Facing API + * + ****************************************************************************************/ +status_t bwcc_hide_device(bwcc_device_id_t which, bool hide) { + chipset_config_state_t* state = &g_chipset_config_state; + status_t ret; + uint32_t reg; + uint32_t clr_bits = 0x3 << 20; + uint32_t set_bits = hide ? (1 << 20) : 0; + + mutex_acquire(&g_lock); + + if (!state->rcba_virt) { + ret = ERR_NOT_READY; + goto finished; + } + + /* Appologies for all of the magic numbers here. If this were not a dirty, + * filty hack, I would clean this up. Hopefully, however, we are not going + * to be using this code for very long. + * + * Most of the addresses and bit patterns are documented in section + * 8.1.24.11.x. The SST audio DSP registers, however, are undocumented. + * The magic numbers were found by working backwards from the coreboot code. + * */ + switch (which) { + case BWCC_DEV_SERIAL_DMA_IO: reg = 0xcb000240; break; + case BWCC_DEV_I2C0: reg = 0xcb000248; break; + case BWCC_DEV_I2C1: reg = 0xcb000250; break; + case BWCC_DEV_SPI0: reg = 0xcb000258; break; + case BWCC_DEV_SPI1: reg = 0xcb000260; break; + case BWCC_DEV_UART0: reg = 0xcb000268; break; + case BWCC_DEV_UART1: reg = 0xcb000270; break; + + case BWCC_DEV_SST: + reg = 0xd7000500; + clr_bits = 0x00000083; + set_bits = hide ? 0x00000001 : 0; + break; + + case BWCC_DEV_SDIO: + ret = ERR_NOT_IMPLEMENTED; + goto finished; + + default: + ret = ERR_INVALID_ARGS; + goto finished; + } + + uint32_t val; + ret = read_iobp(state, reg, &val); + if (ret != NO_ERROR) + goto finished; + + val = (val & ~clr_bits) | set_bits; + ret = write_iobp(state, reg, val); + +finished: + mutex_release(&g_lock); + return ret; +} + +status_t bwcc_disable_fd_fd2_device(chipset_config_state_t* state, + uint32_t offset, + uint32_t bit, + bool disable) { + /* According to docs, for devices controlled by the FD/FD2 registers in the + * core Chipset Control block, it is OK to disable a device, but never to + * re-enable the device once it has been disabled. So, if someone is asking + * to enable a device, we succeed if it is already enabled and fail + * otherwise. + */ + volatile uint32_t* reg = (volatile uint32_t*)((intptr_t)state->rcba_virt + offset); + + if (!disable) + return *reg & bit ? ERR_NOT_SUPPORTED : NO_ERROR; + + *reg = *reg | bit; + return NO_ERROR; +} + +status_t bwcc_disable_device(bwcc_device_id_t which, bool disable) { + chipset_config_state_t* state = &g_chipset_config_state; + status_t ret; + uint32_t reg; + + mutex_acquire(&g_lock); + + if (!state->rcba_virt) { + ret = ERR_NOT_READY; + goto finished; + } + + /* Appologies for all of the magic numbers here. If this were not a dirty, + * filty hack, I would clean this up. Hopefully, however, we are not going + * to be using this code for very long. */ + switch (which) { + case BWCC_DEV_SERIAL_DMA_IO: reg = 0xce00aa07; break; + case BWCC_DEV_I2C0: reg = 0xce00aa47; break; + case BWCC_DEV_I2C1: reg = 0xce00aa87; break; + case BWCC_DEV_SPI0: reg = 0xce00aac7; break; + case BWCC_DEV_SPI1: reg = 0xce00ab07; break; + case BWCC_DEV_UART0: reg = 0xce00ab47; break; + case BWCC_DEV_UART1: reg = 0xce00ab87; break; + case BWCC_DEV_SDIO: reg = 0xce00ae07; break; + + /* Control of enable/disable for the SST DSP is in the Chipset Config FD + * register (see section 8.1.81). */ + case BWCC_DEV_SST: + ret = bwcc_disable_fd_fd2_device(state, CCFG_FD_OFFSET, (1 << 1), disable); + goto finished; + + default: + ret = ERR_INVALID_ARGS; + goto finished; + } + + uint32_t val; + ret = read_iobp(state, reg, &val); + if (ret != NO_ERROR) + goto finished; + + val = (val & ~(0x1u << 8)) | ((disable ? 1 : 0) << 8); + ret = write_iobp(state, reg, val); + +finished: + mutex_release(&g_lock); + return ret; +} diff --git a/kernel/dev/broadwell_chipset_config/include/dev/broadwell_chipset_config.h b/kernel/dev/broadwell_chipset_config/include/dev/broadwell_chipset_config.h new file mode 100644 index 000000000..0681a5d3d --- /dev/null +++ b/kernel/dev/broadwell_chipset_config/include/dev/broadwell_chipset_config.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include +#include + +__BEGIN_CDECLS + +typedef enum { + BWCC_DEV_SDIO, + BWCC_DEV_SERIAL_DMA_IO, + BWCC_DEV_I2C0, + BWCC_DEV_I2C1, + BWCC_DEV_SPI0, + BWCC_DEV_SPI1, + BWCC_DEV_UART0, + BWCC_DEV_UART1, + BWCC_DEV_SST, +} bwcc_device_id_t; + +status_t bwcc_hide_device(bwcc_device_id_t which, bool hide); +status_t bwcc_disable_device(bwcc_device_id_t which, bool disable); + +__END_CDECLS diff --git a/kernel/dev/broadwell_chipset_config/rules.mk b/kernel/dev/broadwell_chipset_config/rules.mk new file mode 100644 index 000000000..05fd46c31 --- /dev/null +++ b/kernel/dev/broadwell_chipset_config/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/broadwell_chipset_config.c + +MODULE_DEPS += \ + dev/pcie + +include make/module.mk diff --git a/kernel/dev/class/block_api.c b/kernel/dev/class/block_api.c new file mode 100644 index 000000000..5ca0c324d --- /dev/null +++ b/kernel/dev/class/block_api.c @@ -0,0 +1,71 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +ssize_t class_block_get_size(struct device *dev) +{ + struct block_ops *ops = device_get_driver_ops(dev, struct block_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->get_block_size) + return ops->get_block_size(dev); + else + return ERR_NOT_SUPPORTED; +} + +ssize_t class_block_get_count(struct device *dev) +{ + struct block_ops *ops = device_get_driver_ops(dev, struct block_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->get_block_count) + return ops->get_block_count(dev); + else + return ERR_NOT_SUPPORTED; +} + +ssize_t class_block_write(struct device *dev, off_t offset, const void *buf, size_t count) +{ + struct block_ops *ops = device_get_driver_ops(dev, struct block_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->write) + return ops->write(dev, offset, buf, count); + else + return ERR_NOT_SUPPORTED; +} + +ssize_t class_block_read(struct device *dev, off_t offset, void *buf, size_t count) +{ + struct block_ops *ops = device_get_driver_ops(dev, struct block_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->read) + return ops->read(dev, offset, buf, count); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_block_flush(struct device *dev) +{ + struct block_ops *ops = device_get_driver_ops(dev, struct block_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->flush) + return ops->flush(dev); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/class/fb_api.c b/kernel/dev/class/fb_api.c new file mode 100644 index 000000000..aaef841ba --- /dev/null +++ b/kernel/dev/class/fb_api.c @@ -0,0 +1,59 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +status_t class_fb_set_mode(struct device *dev, size_t width, size_t height, size_t bpp) +{ + struct fb_ops *ops = device_get_driver_ops(dev, struct fb_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->set_mode) + return ops->set_mode(dev, width, height, bpp); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_fb_get_info(struct device *dev, struct fb_info *info) +{ + struct fb_ops *ops = device_get_driver_ops(dev, struct fb_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->get_info) + return ops->get_info(dev, info); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_fb_update(struct device *dev) +{ + struct fb_ops *ops = device_get_driver_ops(dev, struct fb_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->update) + return ops->update(dev); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_fb_update_region(struct device *dev, size_t x, size_t y, size_t width, size_t height) +{ + struct fb_ops *ops = device_get_driver_ops(dev, struct fb_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->update_region) + return ops->update_region(dev, x, y, width, height); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/class/i2c_api.c b/kernel/dev/class/i2c_api.c new file mode 100644 index 000000000..b2cfeab00 --- /dev/null +++ b/kernel/dev/class/i2c_api.c @@ -0,0 +1,59 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +status_t class_i2c_write(struct device *dev, uint8_t addr, const void *buf, size_t len) +{ + struct i2c_ops *ops = device_get_driver_ops(dev, struct i2c_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->write) + return ops->write(dev, addr, buf, len); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_i2c_read(struct device *dev, uint8_t addr, void *buf, size_t len) +{ + struct i2c_ops *ops = device_get_driver_ops(dev, struct i2c_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->read) + return ops->read(dev, addr, buf, len); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_i2c_write_reg(struct device *dev, uint8_t addr, uint8_t reg, uint8_t value) +{ + struct i2c_ops *ops = device_get_driver_ops(dev, struct i2c_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->write_reg) + return ops->write_reg(dev, addr, reg, value); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_i2c_read_reg(struct device *dev, uint8_t addr, uint8_t reg, void *value) +{ + struct i2c_ops *ops = device_get_driver_ops(dev, struct i2c_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->read_reg) + return ops->read_reg(dev, addr, reg, value); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/class/netif_api.c b/kernel/dev/class/netif_api.c new file mode 100644 index 000000000..5d3f8e747 --- /dev/null +++ b/kernel/dev/class/netif_api.c @@ -0,0 +1,83 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +status_t class_netif_set_state(struct device *dev, struct netstack_state *state) +{ + struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->set_state) + return ops->set_state(dev, state); + else + return ERR_NOT_SUPPORTED; +} + +ssize_t class_netif_get_hwaddr(struct device *dev, void *buf, size_t max_len) +{ + struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->get_hwaddr) + return ops->get_hwaddr(dev, buf, max_len); + else + return ERR_NOT_SUPPORTED; +} + +ssize_t class_netif_get_mtu(struct device *dev) +{ + struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->get_mtu) + return ops->get_mtu(dev); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_netif_set_status(struct device *dev, bool up) +{ + struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->set_status) + return ops->set_status(dev, up); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_netif_output(struct device *dev, struct pbuf *p) +{ + struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->output) + return ops->output(dev, p); + else + return ERR_NOT_SUPPORTED; +} + +status_t class_netif_mcast_filter(struct device *dev, const uint8_t *mac, int action) +{ + struct netif_ops *ops = device_get_driver_ops(dev, struct netif_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->mcast_filter) + return ops->mcast_filter(dev, mac, action); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/class/spi_api.c b/kernel/dev/class/spi_api.c new file mode 100644 index 000000000..78975cc28 --- /dev/null +++ b/kernel/dev/class/spi_api.c @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +ssize_t class_spi_transaction(struct device *dev, struct spi_transaction *txn, size_t count) +{ + struct spi_ops *ops = device_get_driver_ops(dev, struct spi_ops, std); + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->transaction) + return ops->transaction(dev, txn, count); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/class/uart_api.c b/kernel/dev/class/uart_api.c new file mode 100644 index 000000000..ae105bafa --- /dev/null +++ b/kernel/dev/class/uart_api.c @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +ssize_t class_uart_read(struct device *dev, void *buf, size_t len) +{ + struct uart_ops *ops = device_get_driver_ops(dev, struct uart_ops, std); + + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->read) + return ops->read(dev, buf, len); + else + return ERR_NOT_SUPPORTED; +} + +ssize_t class_uart_write(struct device *dev, const void *buf, size_t len) +{ + struct uart_ops *ops = device_get_driver_ops(dev, struct uart_ops, std); + + if (!ops) + return ERR_NOT_CONFIGURED; + + if (ops->write) + return ops->write(dev, buf, len); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/dev.c b/kernel/dev/dev.c new file mode 100644 index 000000000..a14b11297 --- /dev/null +++ b/kernel/dev/dev.c @@ -0,0 +1,13 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +void dev_init(void) +{ + +} + diff --git a/kernel/dev/driver.c b/kernel/dev/driver.c new file mode 100644 index 000000000..dc48e1999 --- /dev/null +++ b/kernel/dev/driver.c @@ -0,0 +1,119 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include + +extern struct device __start_devices[] __WEAK; +extern struct device __stop_devices[] __WEAK; + +status_t device_init_all(void) +{ + status_t res = NO_ERROR; + + struct device *dev = __start_devices; + while (dev != __stop_devices) { + status_t code = device_init(dev); + + if (code < 0) { + TRACEF("Driver init failed for driver \"%s\", device \"%s\", reason %d\n", + dev->driver->type, dev->name, code); + + res = code; + } + + dev++; + } + + return res; +} + +status_t device_fini_all(void) +{ + status_t res = NO_ERROR; + + struct device *dev = __start_devices; + while (dev != __stop_devices) { + status_t code = device_fini(dev); + + if (code < 0) { + TRACEF("Driver fini failed for driver \"%s\", device \"%s\", reason %d\n", + dev->driver->type, dev->name, code); + + res = code; + } + + dev++; + } + + return res; +} + +status_t device_init(struct device *dev) +{ + if (!dev) + return ERR_INVALID_ARGS; + + DEBUG_ASSERT(dev->driver); + + const struct driver_ops *ops = dev->driver->ops; + + if (ops && ops->init) + return ops->init(dev); + else + return ERR_NOT_SUPPORTED; +} + +status_t device_fini(struct device *dev) +{ + if (!dev) + return ERR_INVALID_ARGS; + + DEBUG_ASSERT(dev->driver); + + const struct driver_ops *ops = dev->driver->ops; + + if (ops && ops->fini) + return ops->fini(dev); + else + return ERR_NOT_SUPPORTED; +} + +status_t device_suspend(struct device *dev) +{ + if (!dev) + return ERR_NOT_SUPPORTED; + + DEBUG_ASSERT(dev->driver); + + const struct driver_ops *ops = dev->driver->ops; + + if (ops && ops->suspend) + return ops->suspend(dev); + else + return ERR_NOT_SUPPORTED; +} + +status_t device_resume(struct device *dev) +{ + if (!dev) + return ERR_NOT_SUPPORTED; + + DEBUG_ASSERT(dev->driver); + + const struct driver_ops *ops = dev->driver->ops; + + if (ops && ops->resume) + return ops->resume(dev); + else + return ERR_NOT_SUPPORTED; +} + diff --git a/kernel/dev/gpio/debug.c b/kernel/dev/gpio/debug.c new file mode 100644 index 000000000..40af6a07b --- /dev/null +++ b/kernel/dev/gpio/debug.c @@ -0,0 +1,85 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Christopher Anderson +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include + +#if WITH_LIB_CONSOLE + +struct flag_labels { + unsigned id; + const char *label; +}; + +struct flag_labels gpio_flag_labels[] = { + { GPIO_INPUT, "input" }, + { GPIO_OUTPUT, "output" }, + { GPIO_LEVEL, "level" }, + { GPIO_EDGE, "edge" }, + { GPIO_RISING, "rising" }, + { GPIO_FALLING, "falling" }, + { GPIO_HIGH, "high" }, + { GPIO_LOW, "low" }, + { GPIO_PULLUP, "pullup" }, + { GPIO_PULLDOWN, "pulldown" }, +}; + +static unsigned int get_flag_value(const char *str) +{ + for (unsigned i = 0; i < countof(gpio_flag_labels); i++) { + if (!strcmp(str, gpio_flag_labels[i].label)) { + return gpio_flag_labels[i].id; + } + } + + return 0; +} + +/* Ideally this would be generic, but different platforms have varying manners of handling gpio + * numbers / banks etc. Nvidia uses A-F, ST uses # and ports, Xilinx uses #s and banks. Etc. + */ +static int cmd_gpio(int argc, const cmd_args *argv) +{ + if (argc == 4 && !strcmp(argv[1].str,"set")) { + unsigned int gpio = argv[2].u; + unsigned int value = argv[3].u; + + gpio_set(gpio, value); + } else if (argc == 3 && !strcmp(argv[1].str,"get")) { + unsigned int gpio = argv[2].u; + + printf("gpio %u: %d\n", gpio, gpio_get(gpio)); + } else if (argc >= 3 && !strcmp(argv[1].str,"cfg")) { + unsigned int gpio = argv[2].u; + unsigned int flags = 0; + + for (int i = 3; i < argc; i++) { + flags |= get_flag_value(argv[i].str); + } + + gpio_config(gpio, flags); + } else { + printf("gpio set \n"); + printf("gpio get \n"); + printf("gpio cfg [flags: "); + for (unsigned int i = 0; i < countof(gpio_flag_labels); i++) { + printf("%s ", gpio_flag_labels[i].label); + } + putchar(']'); + putchar('\n'); + } + + return 0; +} +STATIC_COMMAND_START +STATIC_COMMAND("gpio", "commands for manipulating system gpios", &cmd_gpio) +STATIC_COMMAND_END(gpio); + +#endif diff --git a/kernel/dev/gpio/rules.mk b/kernel/dev/gpio/rules.mk new file mode 100644 index 000000000..6864015aa --- /dev/null +++ b/kernel/dev/gpio/rules.mk @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c + +include make/module.mk + diff --git a/kernel/dev/gpio_i2c/gpio_i2c.c b/kernel/dev/gpio_i2c/gpio_i2c.c new file mode 100644 index 000000000..0d681095a --- /dev/null +++ b/kernel/dev/gpio_i2c/gpio_i2c.c @@ -0,0 +1,271 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if (!(defined(GPIO_I2C_BUS_COUNT)) || (GPIO_I2C_BUS_COUNT <= 0)) +#error ERROR: Must define GPIO_I2C_BUS_COUNT +#endif + +typedef struct gpio_i2c_state { + mutex_t lock; + const gpio_i2c_info_t *info; +} gpio_i2c_state_t; + +static gpio_i2c_state_t gpio_i2c_states[GPIO_I2C_BUS_COUNT]; + +/****************************************************************************** + * + * Internal implementation. + * + ******************************************************************************/ +static inline void send_start(const gpio_i2c_info_t *i) +{ + gpio_config(i->sda, GPIO_OUTPUT); + spin_cycles(i->qcd); + gpio_config(i->scl, GPIO_OUTPUT); + spin_cycles(i->hcd); +} + +static inline void send_stop(const gpio_i2c_info_t *i) +{ + gpio_config(i->sda, GPIO_OUTPUT); + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->qcd); + gpio_config(i->sda, GPIO_INPUT); +} + +static inline void send_restart(const gpio_i2c_info_t *i) +{ + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->qcd); + send_start(i); +} + +static inline void send_nack(const gpio_i2c_info_t *i) +{ + spin_cycles(i->hcd); + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->hcd); + gpio_config(i->scl, GPIO_OUTPUT); + gpio_config(i->sda, GPIO_INPUT); +} + +static inline void send_ack(const gpio_i2c_info_t *i) +{ + gpio_config(i->sda, GPIO_OUTPUT); + send_nack(i); +} + +static inline bool send_byte(const gpio_i2c_info_t *i, uint32_t b) +{ + bool ret; + + for (size_t j = 0; j < 8; ++j) { + if (b & 0x80) + gpio_config(i->sda, GPIO_INPUT); + else + gpio_config(i->sda, GPIO_OUTPUT); + b <<= 1; + /* setup time for data (the time between when data becomes stable and + * clock becomes a stable high) is spec'ed to be 250ns for 100KHz i2c + * and 100nsec for 400KHz i2c. If any micro running LK needs to spin + * here in order to hit that timing, they are welcome to add a spin + * right here. + */ + spin_cycles(i->hcd); + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->hcd); + gpio_config(i->scl, GPIO_OUTPUT); + } + + gpio_config(i->sda, GPIO_INPUT); + spin_cycles(i->hcd); + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->hcd); + ret = (0 == gpio_get(i->sda)); + gpio_config(i->scl, GPIO_OUTPUT); + spin_cycles(i->hcd); + + return ret; +} + +static inline void recv_byte(const gpio_i2c_info_t *i, uint8_t *b) +{ + uint32_t tmp = 0; + + for (size_t j = 0; j < 7; ++j) { + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->hcd); + if (gpio_get(i->sda)) + tmp |= 1; + tmp <<= 1; + gpio_config(i->scl, GPIO_OUTPUT); + spin_cycles(i->hcd); + } + + gpio_config(i->scl, GPIO_INPUT); + spin_cycles(i->hcd); + if (gpio_get(i->sda)) + tmp |= 1; + gpio_config(i->scl, GPIO_OUTPUT); + + *b = (uint8_t)tmp; +} + +static status_t gpio_i2c_tx_common(gpio_i2c_state_t *s, + uint8_t address, + const uint8_t *reg, + const void *buf, + size_t cnt) +{ + const gpio_i2c_info_t *i = s->info; + status_t ret = ERR_I2C_NACK; + + DEBUG_ASSERT(buf || !cnt); + + mutex_acquire(&s->lock); + send_start(i); + if (!send_byte(i, address << 1)) + goto finished; + + if ((NULL != reg) && !send_byte(i, *reg)) + goto finished; + + for (size_t j = 0; j < cnt; ++j) + if (!send_byte(i, ((const uint8_t *)buf)[j])) + goto finished; + + ret = NO_ERROR; + +finished: + send_stop(i); + mutex_release(&s->lock); + return ret; +} + +static status_t gpio_i2c_rx_common(gpio_i2c_state_t *s, + uint8_t address, + const uint8_t *reg, + void *buf, + size_t cnt) +{ + const gpio_i2c_info_t *i = s->info; + status_t ret = ERR_I2C_NACK; + + DEBUG_ASSERT(buf && cnt); + + address <<= 1; + + mutex_acquire(&s->lock); + send_start(i); + if (!send_byte(i, address | (!reg ? 0x1 : 0x0))) + goto finished; + + if (NULL != reg) { + if (!send_byte(i, *reg)) + goto finished; + + send_restart(i); + + if (!send_byte(i, address | 0x1)) + goto finished; + } + + recv_byte(i, buf++); + for (size_t j = 0; j < (cnt - 1); ++j) { + send_ack(i); + recv_byte(i, buf++); + } + send_nack(i); + ret = NO_ERROR; + +finished: + send_stop(i); + mutex_release(&s->lock); + return ret; +} + +void gpio_i2c_add_bus(uint32_t bus_id, const gpio_i2c_info_t *info) +{ + gpio_i2c_state_t *s = gpio_i2c_states + bus_id; + + DEBUG_ASSERT(info); + DEBUG_ASSERT(bus_id < GPIO_I2C_BUS_COUNT); + DEBUG_ASSERT(!s->info); + + gpio_config(info->scl, GPIO_INPUT); + gpio_config(info->sda, GPIO_INPUT); + gpio_set(info->scl, 0); + gpio_set(info->sda, 0); + + mutex_init(&s->lock); + s->info = info; +} + +/****************************************************************************** +* +* LK facing API +* +* *****************************************************************************/ +void gpio_i2c_init_early(void) { } +void gpio_i2c_init(void) { } + +status_t gpio_i2c_transmit(int bus, uint8_t address, const void *buf, size_t cnt) +{ + gpio_i2c_state_t *s = gpio_i2c_states + bus; + if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info) + return ERR_NOT_FOUND; + + return gpio_i2c_tx_common(s, address, NULL, buf, cnt); +} + +status_t gpio_i2c_receive(int bus, uint8_t address, void *buf, size_t cnt) +{ + gpio_i2c_state_t *s = gpio_i2c_states + bus; + if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info) + return ERR_NOT_FOUND; + + return gpio_i2c_rx_common(s, address, NULL, buf, cnt); +} + +status_t gpio_i2c_write_reg_bytes(int bus, uint8_t address, uint8_t reg, const uint8_t *buf, size_t cnt) +{ + gpio_i2c_state_t *s = gpio_i2c_states + bus; + if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info) + return ERR_NOT_FOUND; + + return gpio_i2c_tx_common(s, address, ®, buf, cnt); +} + +status_t gpio_i2c_read_reg_bytes(int bus, uint8_t address, uint8_t reg, uint8_t *buf, size_t cnt) +{ + gpio_i2c_state_t *s = gpio_i2c_states + bus; + if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info) { + return ERR_NOT_FOUND; + } + + return gpio_i2c_rx_common(s, address, ®, buf, cnt); +} + +void i2c_init_early(void) __WEAK_ALIAS("gpio_i2c_init_early"); +void i2c_init(void) __WEAK_ALIAS("gpio_i2c_init"); +status_t i2c_transmit(int, uint8_t, const void *, size_t) __WEAK_ALIAS("gpio_i2c_transmit"); +status_t i2c_receive(int, uint8_t, void *, size_t) __WEAK_ALIAS("gpio_i2c_receive"); +status_t i2c_write_reg_bytes(int, uint8_t, uint8_t, + const uint8_t *, size_t) __WEAK_ALIAS("gpio_i2c_write_reg_bytes"); +status_t i2c_read_reg_bytes(int, uint8_t, uint8_t, + uint8_t *, size_t) __WEAK_ALIAS("gpio_i2c_read_reg_bytes"); diff --git a/kernel/dev/gpio_i2c/rules.mk b/kernel/dev/gpio_i2c/rules.mk new file mode 100644 index 000000000..e0b75f7fb --- /dev/null +++ b/kernel/dev/gpio_i2c/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/gpio_i2c.c + +MODULE_DEFINES += \ + GPIO_I2C_BUS_COUNT=$(GPIO_I2C_BUS_COUNT) + +include make/module.mk diff --git a/kernel/dev/hw_rng/BUILD.gn b/kernel/dev/hw_rng/BUILD.gn new file mode 100644 index 000000000..edc11e08c --- /dev/null +++ b/kernel/dev/hw_rng/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_hw_rng_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("hw_rng") { + public_configs = [ ":_hw_rng_config" ] + public = [ + "include/dev/hw_rng.h", + ] + sources = [ + "debug.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/hw_rng/debug.c b/kernel/dev/hw_rng/debug.c new file mode 100644 index 000000000..47ce441a0 --- /dev/null +++ b/kernel/dev/hw_rng/debug.c @@ -0,0 +1,68 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifdef WITH_LIB_CONSOLE +#include +#include +#include +#include + +static int cmd_rng32(int argc, const cmd_args *argv) +{ + uint32_t val = hw_rng_get_u32(); + printf("Random val = %u (0x%08x)\n", val, val); + return NO_ERROR; +} + +static int cmd_rng(int argc, const cmd_args *argv) +{ + if ((argc < 2) || (argc > 3)) { + printf("Invalid argument count\n\n" + "Usage : %s [wait]\n" + "N : Number of bytes to generate.\n" + "wait : true -> wait indefinitely for bytes to be generated\n" + " : false -> terminate if HW generator runs out of entropy (default)\n", + argv[0].str); + return ERR_INVALID_ARGS; + } + + printf("Generating %lu random bytes\n", argv[1].u); + + size_t offset = 0; + bool wait = (argc == 3) ? argv[2].b : false; + while (offset < argv[1].u) { + uint8_t bytes[16]; + size_t todo, done; + + todo = MIN(sizeof(bytes), argv[1].u - offset); + done = hw_rng_get_entropy(bytes, todo, wait); + DEBUG_ASSERT(done <= todo); + + hexdump8_ex(bytes, done, offset); + offset += done; + + if (done < todo) { + printf("Entropy exhausted after %zu byte%s\n", + offset, offset == 1 ? "" : "s"); + break; + } + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +STATIC_COMMAND("rng32", + "Generate and print a random 32 bit unsigned integer using the HW RNG", + &cmd_rng32) +STATIC_COMMAND("rng", + "Generate and print N random bytes using the HW RNG", + &cmd_rng) +STATIC_COMMAND_END(hw_rng); + +#endif // WITH_LIB_CONSOLE diff --git a/kernel/dev/hw_rng/include/dev/hw_rng.h b/kernel/dev/hw_rng/include/dev/hw_rng.h new file mode 100644 index 000000000..51afc8ce4 --- /dev/null +++ b/kernel/dev/hw_rng/include/dev/hw_rng.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +size_t hw_rng_get_entropy(void* buf, size_t len, bool block); + +static inline uint32_t hw_rng_get_u32(void) { + uint32_t ret; + __UNUSED size_t fetched; + + fetched = hw_rng_get_entropy(&ret, sizeof(ret), true); + DEBUG_ASSERT(fetched == sizeof(ret)); + return ret; +} + +__END_CDECLS diff --git a/kernel/dev/hw_rng/rules.mk b/kernel/dev/hw_rng/rules.mk new file mode 100644 index 000000000..ba70f15cf --- /dev/null +++ b/kernel/dev/hw_rng/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c \ + +include make/module.mk diff --git a/kernel/dev/i915/BUILD.gn b/kernel/dev/i915/BUILD.gn new file mode 100644 index 000000000..57af8b16f --- /dev/null +++ b/kernel/dev/i915/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("i915") { + sources = [ + "i915.c", + ] + deps = [ + "//kernel/dev/pcie", + "//kernel/lib/gfx", + "//kernel/lib/gfxconsole", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/i915/i915.c b/kernel/dev/i915/i915.c new file mode 100644 index 000000000..0ebbba697 --- /dev/null +++ b/kernel/dev/i915/i915.c @@ -0,0 +1,321 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern uint32_t bootloader_fb_base; +extern uint32_t bootloader_fb_width; +extern uint32_t bootloader_fb_height; +extern uint32_t bootloader_fb_stride; +extern uint32_t bootloader_fb_format; +extern uint32_t bootloader_i915_reg_base; +extern uint32_t bootloader_fb_window_size; + +#define LOCAL_TRACE 0 + +#define INTEL_I915_VID (0x8086) +#define INTEL_I915_DID (0x1616) + +#define INTEL_I915_REG_WINDOW_SIZE (0x1000000u) +#define INTEL_I915_FB_WINDOW_SIZE (0x10000000u) + +#define BACKLIGHT_CTRL_OFFSET (0xc8250) +#define BACKLIGHT_CTRL_BIT ((uint32_t)(1u << 31)) + +typedef struct intel_i915_device { + void* regs; + size_t regs_size; + void* framebuffer; + size_t framebuffer_size; + vmm_aspace_t* aspace; + struct display_info disp; + pcie_device_state_t* pci_device; +} intel_i915_device_t; + +static intel_i915_device_t* g_i915_device; + +static void intel_i915_unmap_windows(intel_i915_device_t* dev) +{ + DEBUG_ASSERT(dev); + + if (dev->aspace) { + if (dev->regs) { + vmm_free_region(dev->aspace, (vaddr_t)dev->regs); + dev->regs = NULL; + } + + if (dev->framebuffer) { + vmm_free_region(dev->aspace, (vaddr_t)dev->framebuffer); + dev->framebuffer = NULL; + } + + dev->aspace = NULL; + } else { + DEBUG_ASSERT(!dev->regs); + DEBUG_ASSERT(!dev->framebuffer); + } +} + +static status_t intel_i915_map_reg_window(intel_i915_device_t* dev, + paddr_t reg_phys, + size_t size) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->aspace); + + if (!dev->regs) { + status_t ret; + DEBUG_ASSERT(!dev->regs_size); + + ret = vmm_alloc_physical( + dev->aspace, + "i915_reg", + size, + &dev->regs, + PAGE_SIZE_SHIFT, + reg_phys, + 0 /* vmm flags */, + ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + + if (ret == NO_ERROR) + dev->regs_size = size; + + return ret; + } else { + DEBUG_ASSERT(dev->regs_size); + + if (size != dev->regs_size) { + LTRACEF("Size mismatch when moving i915 register window. New size " + "(%zu) does not match old size (%zu)\n", + size, dev->regs_size); + return ERR_NOT_VALID; + } + + return vmm_move_region_phys(dev->aspace, + (vaddr_t)dev->regs, + reg_phys); + } +} + +static status_t intel_i915_map_fb_window(intel_i915_device_t* dev, + paddr_t fb_phys, + size_t size) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->aspace); + + if (!dev->framebuffer) { + status_t ret; + DEBUG_ASSERT(!dev->framebuffer_size); + + ret = vmm_alloc_physical( + dev->aspace, + "i915_fb", + INTEL_I915_FB_WINDOW_SIZE, + &dev->framebuffer, + PAGE_SIZE_SHIFT, + fb_phys, + 0 /* vmm flags */, + ARCH_MMU_FLAG_WRITE_COMBINING | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + + if (ret == NO_ERROR) + dev->framebuffer_size = size; + + return ret; + } else { + DEBUG_ASSERT(dev->framebuffer_size); + + if (size != dev->framebuffer_size) { + LTRACEF("Size mismatch when moving i915 framebuffer window. New size " + "(%zu) does not match old size (%zu)\n", + size, dev->framebuffer_size); + return ERR_NOT_VALID; + } + + return vmm_move_region_phys(dev->aspace, + (vaddr_t)dev->framebuffer, + fb_phys); + } +} + +static void intel_i915_cleanup_device(intel_i915_device_t* dev) +{ + if (!dev) { + DEBUG_ASSERT(!g_i915_device); + return; + } + + DEBUG_ASSERT(!dev->regs); + DEBUG_ASSERT(!dev->framebuffer); + DEBUG_ASSERT(!dev->pci_device); + DEBUG_ASSERT(dev == g_i915_device); + + intel_i915_unmap_windows(dev); + free(dev); + g_i915_device = NULL; +} + +static status_t intel_i915_setup_device(void) +{ + DEBUG_ASSERT(!g_i915_device); + + intel_i915_device_t* dev; + dev = g_i915_device = (intel_i915_device_t*)calloc(1, sizeof(*g_i915_device)); + if (!dev) { + LTRACEF("Failed to allocate %zu bytes for Intel i915 device\n", + sizeof(intel_i915_device_t)); + return ERR_NO_MEMORY; + } + + dev->aspace = vmm_get_kernel_aspace(); + if (!dev->aspace) { + LTRACEF("Failed to fetch Intel i915 device's address space!\n"); + intel_i915_cleanup_device(dev); + return ERR_NO_RESOURCES; + } + + return NO_ERROR; +} + +static void intel_i915_enable_backlight(intel_i915_device_t* dev, bool enable) { + DEBUG_ASSERT(dev); + + if (!dev->regs) + return; + + void* backlight_ctrl = (uint8_t*)dev->regs + BACKLIGHT_CTRL_OFFSET; + uint32_t tmp = pcie_read32(backlight_ctrl); + + if (enable) + tmp |= BACKLIGHT_CTRL_BIT; + else + tmp &= ~BACKLIGHT_CTRL_BIT; + + pcie_write32(backlight_ctrl, tmp); +} + +static status_t intel_i915_pci_startup(struct pcie_device_state* pci_device) { + DEBUG_ASSERT(pci_device && pci_device->driver_ctx); + intel_i915_device_t* dev = (intel_i915_device_t*)pci_device->driver_ctx; + status_t status = NO_ERROR; + + /* Figure our where the bus driver has placed our register window and our + * framebuffer window */ + const pcie_bar_info_t* info; + + info = pcie_get_device_bar_info(pci_device, 0); + if (!info || !info->is_allocated || !info->is_mmio) { + status = ERR_BAD_STATE; + goto bailout; + } + + status = intel_i915_map_reg_window(dev, info->bus_addr, info->size); + if (status != NO_ERROR) + goto bailout; + + info = pcie_get_device_bar_info(pci_device, 2); + if (!info || !info->is_allocated || !info->is_mmio) { + status = ERR_BAD_STATE; + goto bailout; + } + + status = intel_i915_map_fb_window(dev, info->bus_addr, info->size); + if (status != NO_ERROR) + goto bailout; + + pcie_enable_mmio(pci_device, true); + intel_i915_enable_backlight(dev, true); + + struct display_info di; + memset(&info, 0, sizeof(info)); + if (bootloader_fb_base) { + di.format = bootloader_fb_format; + di.width = bootloader_fb_width; + di.height = bootloader_fb_height; + di.stride = bootloader_fb_stride; + } else { + di.format = DISPLAY_FORMAT_RGB_565; + di.width = 2560 / 2; + di.height = 1700 / 2; + di.stride = 2560 / 2; + } + di.flags = DISPLAY_FLAG_HW_FRAMEBUFFER; + di.flush = NULL; + di.framebuffer = dev->framebuffer; + + gfxconsole_bind_display(&di, NULL); + +bailout: + if (status != NO_ERROR) + intel_i915_unmap_windows(dev); + + return status; +} + +static void intel_i915_pci_shutdown(struct pcie_device_state* pci_device) { + DEBUG_ASSERT(pci_device && pci_device->driver_ctx); + intel_i915_device_t* dev = (intel_i915_device_t*)pci_device->driver_ctx; + + intel_i915_enable_backlight(dev, false); + intel_i915_unmap_windows(dev); + pcie_enable_mmio(pci_device, false); +} + +static void intel_i915_pci_release(pcie_device_state_t* pci_device) { + DEBUG_ASSERT(pci_device && pci_device->driver_ctx); + DEBUG_ASSERT(g_i915_device == pci_device->driver_ctx); + DEBUG_ASSERT(g_i915_device->regs == NULL); + DEBUG_ASSERT(g_i915_device->framebuffer == NULL); + + intel_i915_cleanup_device(g_i915_device); +} + +static void* intel_i915_pci_probe(pcie_device_state_t* pci_device) { + DEBUG_ASSERT(pci_device); + + /* Is this the droid we are looking for? */ + if ((pci_device->common.vendor_id != INTEL_I915_VID) || + (pci_device->common.device_id != INTEL_I915_DID)) { + return NULL; + } + + if (!g_i915_device) { + /* Device structure has not been allocated yet. Attempt to do so now. + * If we fail, do not claim the device */ + if (intel_i915_setup_device() != NO_ERROR) + return NULL; + } else { + /* If the singleton device structure has already been allocated, check + * to see if it has already claimed a PCI device. If it has, do not + * claim this one. */ + if (g_i915_device->pci_device) + return NULL; + } + + /* Stash a reference to our PCI device and claim the device in the bus + * driver */ + g_i915_device->pci_device = pci_device; + return g_i915_device; +} + +static const pcie_driver_fn_table_t INTEL_I815_FN_TABLE = { + .pcie_probe_fn = intel_i915_pci_probe, + .pcie_startup_fn = intel_i915_pci_startup, + .pcie_shutdown_fn = intel_i915_pci_shutdown, + .pcie_release_fn = intel_i915_pci_release, +}; + +#ifdef NO_USER_DISPLAY +STATIC_PCIE_DRIVER(intel_i915, "Intel i915 Display Controller", INTEL_I815_FN_TABLE) +#endif diff --git a/kernel/dev/i915/rules.mk b/kernel/dev/i915/rules.mk new file mode 100644 index 000000000..7b5ede732 --- /dev/null +++ b/kernel/dev/i915/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += $(LOCAL_DIR)/i915.c + +MODULE_DEPS += \ + lib/gfx \ + lib/gfxconsole + +include make/module.mk diff --git a/kernel/dev/intel_hda/BUILD.gn b/kernel/dev/intel_hda/BUILD.gn new file mode 100644 index 000000000..96728d061 --- /dev/null +++ b/kernel/dev/intel_hda/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +module("intel_hda") { + configs += [ "//kernel/kernel:enable_vm" ] + if (enable_intel_hda_qemu_quirks) { + defines = [ "INTEL_HDA_QEMU_QUIRKS=1" ] + } else { + defines = [ "INTEL_HDA_QEMU_QUIRKS=0" ] + } + include_dirs = [ "//include" ] + sources = [ + "codec.c", + "debug.c", + "intel_hda.c", + ] + deps = [ + "//kernel/dev/pcie", + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/intel_hda/codec.c b/kernel/dev/intel_hda/codec.c new file mode 100644 index 000000000..3e765d910 --- /dev/null +++ b/kernel/dev/intel_hda/codec.c @@ -0,0 +1,1119 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +#include "codec.h" +#include "codec_commands.h" +#include "intel_hda.h" + +#define LOCAL_TRACE 0 + +static void intel_hda_fetch_next_function_group(intel_hda_codec_t* codec); +static void intel_hda_fetch_next_widget(intel_hda_codec_t* codec); + +/* + * intel_hda_codec_send_cmd + * + * Queue a command to be sent to a codec via the CORB (Command Output Ring + * Buffer). Writes the command to the ring buffer, but does not advance the + * write pointer to begin transmission. That will happen at the end up the + * update cycle when the driver calls intel_hda_codec_commit_corb. + * + * @note It is up to the caller to make sure that there is space in the CORB to + * send the command by checking the corb_snapshot_space member of the codec's + * device. + * + * @param codec A pointer to the codec which this command targets. + * @param nid The Node ID of node in the codec which this command targets. + * @param verb The encoded command to send. + */ +static inline void intel_hda_codec_send_cmd(intel_hda_codec_t* codec, uint16_t nid, uint32_t verb) { + DEBUG_ASSERT(codec && codec->dev); + intel_hda_device_t* dev = codec->dev; + + LTRACEF("Send Cmd: Codec ID %2u Node ID %3hu Verb 0x%05x\n", + codec->codec_id, nid, verb); + + /* + * Sanity check the parameters for the command before we compose it. + * + * Codec IDs must be < 15; we don't support broadcast verbs (nor does the spec define any). + * Node IDs must be at most 7 bits, we do not support 15-bit NIDs right now. + * Verbs are limited to 20 bits and must be non-0. 0 is an illegal verb. + */ + DEBUG_ASSERT(codec->codec_id < 0xf); + DEBUG_ASSERT(!(nid & ~0x7f)); + DEBUG_ASSERT(!(verb & ~0xfffff) && verb); + + /* Assert that we have space in the ring buffer. It is the caller's job to + * make sure that space exists before they call this method. Also assert + * that the write pointer is sane, and that we have mapped the CORB */ + DEBUG_ASSERT(dev->corb_snapshot_space); + DEBUG_ASSERT(dev->corb_wr_ptr < dev->corb_entry_count); + DEBUG_ASSERT(dev->corb); + + /* See Section 7.1.2 and Figure 52 for details on command encoding */ + uint32_t cmd = ((uint32_t)codec->codec_id << 28) | ((uint32_t)nid << 20) | verb; + + /* Write the command into the ring buffer and update the SW shadow of the + * write pointer. We will update the HW write pointer later on when we + * commit the new CORB commands. + * + * Note: Intel's ring buffers are a bit wonky. See Section 4.4.1.4, but + * the general idea is that to send a command, you write the command at WP + * and then bump the WP. Instead you write the command to (WP + 1) % + * RING_SIZE, then update WP to be (WP + 1) % RING_SIZE. IOW - The write + * pointer always points to the last command written, not the place where + * the next command will go. This behavior holds in the RIRB direction as + * well + */ + dev->corb_wr_ptr = (dev->corb_wr_ptr + 1) & dev->corb_mask; + dev->corb[dev->corb_wr_ptr].command = LE32(cmd); + dev->corb_snapshot_space--; +} + +/****************************************************************************** + * + * A long list of functions used to parse parameters fetched during initial + * codec capability enumeration. + * + ******************************************************************************/ +static void intel_hda_parse_amp_caps(struct intel_hda_codec_amp_caps* caps, uint32_t data) { + // Section 7.3.4.10 : Amplifier Capabilities + caps->can_mute = (data & 0x80000000) != 0; + caps->step_size = ((data >> 16) & 0x7f) + 1; + caps->num_steps = ((data >> 8) & 0x7f) + 1; + caps->offset = ((data >> 0) & 0x7f); +} + +static void intel_hda_parse_widget_pcm_size_rate(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (AW_CAPS_FORMAT_OVERRIDE(widget->raw_caps)) + widget->pcm_size_rate = data; + else + widget->pcm_size_rate = widget->fn_group->default_pcm_size_rate; +} + +static void intel_hda_parse_widget_pcm_formats(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (AW_CAPS_FORMAT_OVERRIDE(widget->raw_caps)) + widget->pcm_formats = data; + else + widget->pcm_formats = widget->fn_group->default_pcm_formats; +} + +static void intel_hda_parse_widget_pin_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + widget->pin_caps = data; +} + +static void intel_hda_parse_widget_input_amp_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (AW_CAPS_INPUT_AMP_PRESENT(widget->raw_caps)) { + if (AW_CAPS_AMP_PARAM_OVERRIDE(widget->raw_caps)) + intel_hda_parse_amp_caps(&widget->input_amp_caps, data); + else + widget->input_amp_caps = widget->fn_group->default_input_amp_caps; + } else { + memset(&widget->input_amp_caps, 0, sizeof(widget->input_amp_caps)); + } +} + +static void intel_hda_parse_widget_output_amp_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (AW_CAPS_OUTPUT_AMP_PRESENT(widget->raw_caps)) { + if (AW_CAPS_AMP_PARAM_OVERRIDE(widget->raw_caps)) + intel_hda_parse_amp_caps(&widget->output_amp_caps, data); + else + widget->output_amp_caps = widget->fn_group->default_output_amp_caps; + } else { + memset(&widget->output_amp_caps, 0, sizeof(widget->output_amp_caps)); + } +} + +static void intel_hda_parse_widget_connection_list_len(struct intel_hda_codec* codec, + uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (AW_CAPS_HAS_CONN_LIST(widget->raw_caps)) { + widget->long_form_conn_list = ((data & 0x80) != 0); + widget->conn_list_len = data & 0x7f; + } else { + widget->long_form_conn_list = false; + widget->conn_list_len = 0; + } +} + +static void intel_hda_parse_widget_power_states(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + /* TODO(johngro) : the spec is a bit unclear here. In section 7.3.4.6 it + * states that the power control bit in the audio widget capabilities + * "indicates that the Power State control is supported on this widget". + * It goes on to say that this can give the system finer grained power + * control and that "the power states supported is reported by the Supported + * Power States Parameter". Finally, it says "In cases where this parameter + * is not supported, the widget supports the same power states as the + * function group". + * + * So; can it be the case that the widget supports the power state control + * (section 7.3.3.10) but not the supported power state parameter (section + * 7.3.4.12)? If so, how would we detect this? For now, my assumption is + * that if the widget claims to support the control, but the parameter is + * zero, that we are supposed to use the same value as was reported at the + * function group level. + */ + if (AW_CAPS_HAS_POWER_CTL(widget->raw_caps)) { + widget->power_states = data + ? data + : widget->fn_group->power_states; + } +} + +static void intel_hda_parse_widget_processing_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (AW_CAPS_HAS_POWER_CTL(widget->raw_caps)) { + widget->can_bypass_processing = (data & 0x1) != 0; + widget->processing_coefficient_count = ((data >> 8) & 0xFF); + } else { + widget->can_bypass_processing = false; + widget->processing_coefficient_count = 0; + } +} + +static void intel_hda_parse_widget_volume_knob_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + widget->vol_knob_is_delta = (data & 0x80) != 0; + widget->vol_knob_steps = (data & 0x7f); +} + +static void intel_hda_parse_widget_type(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + /* Response format documented in section 7.3.4.6 */ + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + widget->nid = codec->widget_iter + fn_group->widget_starting_id; + widget->fn_group = fn_group; + widget->raw_caps = data; + widget->type = (data >> 20) & 0xF; + widget->delay = (data >> 16) & 0xF; + widget->ch_count = (((data >> 12) & 0xE) | (data & 0x1)) + 1; +} + +static void intel_hda_parse_afg_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + // Section 7.3.4.5 : AFG Caps + fn_group->has_beep_gen = (data & 0x10000) != 0; + fn_group->path_input_delay = (data >> 12) & 0xF; + fn_group->path_output_delay = data & 0xF; +} + +static void intel_hda_parse_afg_pcm_size_rate(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + // Section 7.3.4.7 : Supported PCM sizes and rates + fn_group->default_pcm_size_rate = data; +} + +static void intel_hda_parse_afg_pcm_formats(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + // Section 7.3.4.8 : Supported PCM formats + fn_group->default_pcm_formats = data; +} + +static void intel_hda_parse_afg_output_amp_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + intel_hda_parse_amp_caps(&fn_group->default_output_amp_caps, data); +} + +static void intel_hda_parse_afg_input_amp_caps(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + intel_hda_parse_amp_caps(&fn_group->default_input_amp_caps, data); +} + +static void intel_hda_parse_afg_power_states(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + fn_group->power_states = data; +} + +static void intel_hda_parse_afg_gpio_count(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + // Section 7.3.4.14 : GPIO Counts + fn_group->gpio_can_wake = (data & 0x80000000) != 0; + fn_group->gpio_can_send_unsolicited = (data & 0x40000000) != 0; + fn_group->gpi_count = (data >> 16) & 0xFF; + fn_group->gpo_count = (data >> 8) & 0xFF; + fn_group->gpio_count = (data >> 0) & 0xFF; +} + +static void intel_hda_parse_afg_node_count(struct intel_hda_codec* codec, uint32_t data) { + /* Response format documented in section 7.3.4.3 */ + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + fn_group->widget_count = data & 0xFF; + fn_group->widget_starting_id = (data >> 16) & 0xFF; +} + +static void intel_hda_parse_fn_group_type(struct intel_hda_codec* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + DEBUG_ASSERT(!codec->fn_groups[codec->fn_group_iter]); + + /* Response format documented in section 7.3.4.4 and Table 137 */ + uint8_t type = data & 0xFF; + bool unsol = (data & 0x100) != 0; + + /* We only support Audio Function Groups at the moment. If this is not an + * AFG, don't bother to keep enumerating it. */ + if (type != 0x01) { + LTRACEF("Ignoring unsupported function group type 0x%02x (Node ID %hu)\n", + type, codec->fn_group_iter + codec->fn_group_starting_id); + return; + } + + intel_hda_codec_audio_fn_group_t* fn_group = + (intel_hda_codec_audio_fn_group_t*)calloc(1, sizeof(intel_hda_codec_audio_fn_group_t)); + + DEBUG_ASSERT(fn_group); + fn_group->can_send_unsolicited = unsol; + fn_group->fn_group_type = type; + fn_group->nid = codec->fn_group_iter + codec->fn_group_starting_id; + codec->fn_groups[codec->fn_group_iter] = fn_group; +} + +static void intel_hda_parse_vendor_id(struct intel_hda_codec* codec, uint32_t data) { + /* Response format documented in section 7.3.4.1 */ + DEBUG_ASSERT(codec); + codec->vendor_id = (data >> 16) & 0xFFFF; + codec->device_id = data & 0xFFFF; +} + +static void intel_hda_parse_revision_id(struct intel_hda_codec* codec, uint32_t data) { + /* Response format documented in section 7.3.4.2 */ + DEBUG_ASSERT(codec); + codec->major_rev = (data >> 20) & 0xF; + codec->minor_rev = (data >> 16) & 0xF; + codec->vendor_rev_id = (data >> 8) & 0xFF; + codec->vendor_stepping_id = data & 0xFF; +} + +static void intel_hda_parse_fn_group_count(struct intel_hda_codec* codec, uint32_t data) { + /* Response format documented in section 7.3.4.3 */ + DEBUG_ASSERT(codec); + codec->fn_group_count = data & 0xFF; + codec->fn_group_starting_id = (data >> 16) & 0xFF; +} + +/****************************************************************************** + * + * Tables of parameters and parameter parsers which may be supported for the + * various objects we need to fetch information for during initial capability + * enumeration. + * + ******************************************************************************/ + +/* Widget objects */ +static const intel_hda_command_list_entry_t FETCH_AUDIO_INPUT_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PCM_SIZE_RATE), intel_hda_parse_widget_pcm_size_rate }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_STREAM_FORMATS), intel_hda_parse_widget_pcm_formats }, + { CC_GET_PARAM(CC_PARAM_INPUT_AMP_CAPS), intel_hda_parse_widget_input_amp_caps }, + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, + { CC_GET_PARAM(CC_PARAM_PROCESSING_CAPS), intel_hda_parse_widget_processing_caps }, +}; + +static const intel_hda_command_list_entry_t FETCH_AUDIO_OUTPUT_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PCM_SIZE_RATE), intel_hda_parse_widget_pcm_size_rate }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_STREAM_FORMATS), intel_hda_parse_widget_pcm_formats }, + { CC_GET_PARAM(CC_PARAM_OUTPUT_AMP_CAPS), intel_hda_parse_widget_output_amp_caps }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, + { CC_GET_PARAM(CC_PARAM_PROCESSING_CAPS), intel_hda_parse_widget_processing_caps }, +}; + +static const intel_hda_command_list_entry_t FETCH_DIGITAL_PIN_COMPLEX_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_PIN_CAPS), intel_hda_parse_widget_pin_caps }, + { CC_GET_PARAM(CC_PARAM_OUTPUT_AMP_CAPS), intel_hda_parse_widget_output_amp_caps }, + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, + { CC_GET_PARAM(CC_PARAM_PROCESSING_CAPS), intel_hda_parse_widget_processing_caps }, +}; + +static const intel_hda_command_list_entry_t FETCH_NON_DIGITAL_PIN_COMPLEX_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_PIN_CAPS), intel_hda_parse_widget_pin_caps }, + { CC_GET_PARAM(CC_PARAM_INPUT_AMP_CAPS), intel_hda_parse_widget_input_amp_caps }, + { CC_GET_PARAM(CC_PARAM_OUTPUT_AMP_CAPS), intel_hda_parse_widget_output_amp_caps }, + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, + { CC_GET_PARAM(CC_PARAM_PROCESSING_CAPS), intel_hda_parse_widget_processing_caps }, +}; + +static const intel_hda_command_list_entry_t FETCH_MIXER_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_INPUT_AMP_CAPS), intel_hda_parse_widget_input_amp_caps }, + { CC_GET_PARAM(CC_PARAM_OUTPUT_AMP_CAPS), intel_hda_parse_widget_output_amp_caps }, + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, +}; + +static const intel_hda_command_list_entry_t FETCH_SELECTOR_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_INPUT_AMP_CAPS), intel_hda_parse_widget_input_amp_caps }, + { CC_GET_PARAM(CC_PARAM_OUTPUT_AMP_CAPS), intel_hda_parse_widget_output_amp_caps }, + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, + { CC_GET_PARAM(CC_PARAM_PROCESSING_CAPS), intel_hda_parse_widget_processing_caps }, +}; + +static const intel_hda_command_list_entry_t FETCH_POWER_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, +}; + +static const intel_hda_command_list_entry_t FETCH_VOLUME_KNOB_CAPS[] = { + { CC_GET_PARAM(CC_PARAM_CONNECTION_LIST_LEN), intel_hda_parse_widget_connection_list_len }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_widget_power_states }, + { CC_GET_PARAM(CC_PARAM_VOLUME_KNOB_CAPS), intel_hda_parse_widget_volume_knob_caps }, +}; + +static const intel_hda_command_list_entry_t ID_WIDGET_COMMANDS[] = { + { CC_GET_PARAM(CC_PARAM_AW_CAPS), intel_hda_parse_widget_type }, +}; + +/* Function Group objects. Currently, we ignore Modem and Vendor specific + * function groups. */ +static const intel_hda_command_list_entry_t FETCH_AFG_PROPERTIES_COMMANDS[] = { + { CC_GET_PARAM(CC_PARAM_AFG_CAPS), intel_hda_parse_afg_caps }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PCM_SIZE_RATE), intel_hda_parse_afg_pcm_size_rate }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_STREAM_FORMATS), intel_hda_parse_afg_pcm_formats }, + { CC_GET_PARAM(CC_PARAM_INPUT_AMP_CAPS), intel_hda_parse_afg_input_amp_caps }, + { CC_GET_PARAM(CC_PARAM_OUTPUT_AMP_CAPS), intel_hda_parse_afg_output_amp_caps }, + { CC_GET_PARAM(CC_PARAM_SUPPORTED_PWR_STATES), intel_hda_parse_afg_power_states }, + { CC_GET_PARAM(CC_PARAM_GPIO_COUNT), intel_hda_parse_afg_gpio_count }, + { CC_GET_PARAM(CC_PARAM_SUBORDINATE_NODE_COUNT), intel_hda_parse_afg_node_count }, +}; + +static const intel_hda_command_list_entry_t ID_FUNCTION_GROUP_COMMANDS[] = { + { CC_GET_PARAM(CC_PARAM_FUNCTION_GROUP_TYPE), intel_hda_parse_fn_group_type }, +}; + +/* The Codec object (root of the object tree) */ +static const intel_hda_command_list_entry_t FETCH_CODEC_ROOT_COMMANDS[] = { + { CC_GET_PARAM(CC_PARAM_VENDOR_ID), intel_hda_parse_vendor_id }, + { CC_GET_PARAM(CC_PARAM_REVISION_ID), intel_hda_parse_revision_id }, + { CC_GET_PARAM(CC_PARAM_SUBORDINATE_NODE_COUNT), intel_hda_parse_fn_group_count }, +}; + +/****************************************************************************** + * + * Methods used to set up and process a static command list. Used to build the + * state machine for fetching parameters during initial capability enumeration. + * Throttles command transmits so that the CORB does not overflow. + * + ******************************************************************************/ +static void intel_hda_rx_cmd_list(intel_hda_codec_t* codec, uint32_t data) { + DEBUG_ASSERT(codec && codec->dev); + + intel_hda_command_list_state_t* s = &codec->cmd_list; + DEBUG_ASSERT(s->rx_ndx < s->tx_ndx); + DEBUG_ASSERT(s->tx_ndx <= s->cmd_count); + DEBUG_ASSERT(s->cmds); + + /* If we have a processing handler, process the response for the command we + * sent earlier */ + const intel_hda_command_list_entry_t* cmd = s->cmds + s->rx_ndx; + if (cmd->process_resp) + cmd->process_resp(codec, data); + + /* If we are done processing, clear out the solicited response handler and + * call any finished handler which may have been registered to advance the + * state machine to the next stage of processing.. + */ + s->rx_ndx++; + if (s->rx_ndx == s->cmd_count) { + codec->solicited_response_handler = NULL; + if (s->finished_handler) + s->finished_handler(codec); + } +} + +static void intel_hda_tx_cmd_list(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec && codec->dev); + + intel_hda_command_list_state_t* s = &codec->cmd_list; + DEBUG_ASSERT(s->rx_ndx <= s->tx_ndx); + DEBUG_ASSERT(s->tx_ndx < s->cmd_count); + DEBUG_ASSERT(s->cmds); + + /* As long as there is room in the CORB and we still have commands to send, + * queue some commands. */ + intel_hda_device_t* dev = codec->dev; + while (dev->corb_snapshot_space && (s->tx_ndx < s->cmd_count)) { + DEBUG_ASSERT(s->get_nid); + const intel_hda_command_list_entry_t* cmd = s->cmds + s->tx_ndx; + uint16_t nid = s->get_nid(codec); + + intel_hda_codec_send_cmd(codec, nid, cmd->verb); + s->tx_ndx++; + } + + /* If we have queued all of our requests, we can remove our pending work + * handler */ + if (s->tx_ndx == s->cmd_count) + codec->pending_work_handler = NULL; +} + +static void intel_hda_setup_cmd_list( + intel_hda_codec_t* codec, + const intel_hda_command_list_entry_t* cmds, + size_t cmd_count, + intel_hda_codec_get_cmd_list_nid_fn get_nid, + intel_hda_codec_finished_command_list_handler_fn finished_handler) { + DEBUG_ASSERT(codec && cmds && cmd_count); + + intel_hda_command_list_state_t* s = &codec->cmd_list; + + s->tx_ndx = 0; + s->rx_ndx = 0; + s->cmds = cmds; + s->cmd_count = cmd_count; + s->get_nid = get_nid; + s->finished_handler = finished_handler; + + codec->solicited_response_handler = intel_hda_rx_cmd_list; + codec->pending_work_handler = intel_hda_tx_cmd_list; +} + +/****************************************************************************** + * + * Methods used to fetch a widget's connection list. Used during initial codec + * capability enumeration. This is always the last step of widget enumeration. + * Once completed, the state machine will advance to fetching the capabilities + * of the next widget (if any). + * + ******************************************************************************/ +static void intel_hda_rx_fetch_conn_list(intel_hda_codec_t* codec, uint32_t data) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + DEBUG_ASSERT(codec->conn_list_rx_iter < widget->conn_list_len); + + /* If this is a long form connection list, unpack up to two 16 bit NIDs. + * Otherwise, unpack up to 4 8-bit NIDs. */ + if (widget->long_form_conn_list) { + for (uint i = 0; + (i < 2) && (codec->conn_list_rx_iter < widget->conn_list_len); + ++i, ++codec->conn_list_rx_iter) { + widget->conn_list[codec->conn_list_rx_iter] = data & 0xFFFF; + data >>= 16; + } + } else { + for (uint i = 0; + (i < 4) && (codec->conn_list_rx_iter < widget->conn_list_len); + ++i, ++codec->conn_list_rx_iter) { + widget->conn_list[codec->conn_list_rx_iter] = data & 0xFF; + data >>= 8; + } + } + + /* Finished? If so, move on to the next widget */ + if (codec->conn_list_rx_iter == widget->conn_list_len) { + DEBUG_ASSERT(!codec->pending_work_handler); + DEBUG_ASSERT(codec->conn_list_rx_iter >= widget->conn_list_len); + codec->solicited_response_handler = NULL; + intel_hda_fetch_next_widget(codec); + } +} + +static void intel_hda_tx_fetch_conn_list(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec && codec->dev); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + struct intel_hda_device* dev = codec->dev; + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + DEBUG_ASSERT(codec->conn_list_tx_iter < widget->conn_list_len); + + while (dev->corb_snapshot_space && (codec->conn_list_tx_iter < widget->conn_list_len)) { + intel_hda_codec_send_cmd(codec, + widget->nid, + CC_GET_CONNECTION_LIST_ENTRY(codec->conn_list_tx_iter)); + codec->conn_list_tx_iter += widget->long_form_conn_list ? 2 : 4; + } + + /* If we are finished queueing requests, remove our pending work handler. + * The solicited_response_handler will take care of finishing the fetch + * operation. */ + if (codec->conn_list_tx_iter >= widget->conn_list_len) + codec->pending_work_handler = NULL; +} + +static void intel_hda_fetch_widget_connection_list(struct intel_hda_codec* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + DEBUG_ASSERT(fn_group->widgets && (codec->widget_iter < fn_group->widget_count)); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + DEBUG_ASSERT(widget->fn_group == fn_group); + + if (widget->conn_list_len) { + /* Looks like this widget has a connection list. Allocate storage for + * it and set up the state machine to fetch the entries. */ + codec->conn_list_tx_iter = 0; + codec->conn_list_rx_iter = 0; + codec->solicited_response_handler = intel_hda_rx_fetch_conn_list; + codec->pending_work_handler = intel_hda_tx_fetch_conn_list; + widget->conn_list = (uint16_t*)calloc(widget->conn_list_len, + sizeof(*widget->conn_list)); + DEBUG_ASSERT(widget->conn_list); + } else { + /* No connection list? Just move on to the next widget. */ + intel_hda_fetch_next_widget(codec); + } +} + +/****************************************************************************** + * + * GetNID and Finished functions for various stages of the enumeration state + * machine. + * + * intel_hda_setup_cmd_list requires two function pointers in order to process a + * command list for a particular object. + * + * 1) The GetNID function is responsible for supplying the Node ID of the object + * to target each time a command needs to be queued. + * 2) The Finished function after the command list has been fully processed and + * is used to select and set-up the next stage of the state machine. + * + ******************************************************************************/ + +/* Widget GetNID and Finished functions */ +static uint16_t intel_hda_fetch_widget_get_nid(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + return codec->widget_iter + fn_group->widget_starting_id; +} + +static void intel_hda_id_widget_finished(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(!codec->solicited_response_handler); + DEBUG_ASSERT(!codec->pending_work_handler); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + intel_hda_widget_t* widget = fn_group->widgets + codec->widget_iter; + + // Now that we know what type of widget we are dealing with, fetch the + // parameters which are specific to it. If we do not recognize the widget + // type, or there are no widget specific parameters we actually care about, + // just move on to the next widget. + const intel_hda_command_list_entry_t* cmd_table = NULL; + size_t cmd_table_len = 0; + + switch (widget->type) { + case AW_TYPE_OUTPUT: + cmd_table = FETCH_AUDIO_OUTPUT_CAPS; + cmd_table_len = countof(FETCH_AUDIO_OUTPUT_CAPS); + break; + + case AW_TYPE_INPUT: + cmd_table = FETCH_AUDIO_INPUT_CAPS; + cmd_table_len = countof(FETCH_AUDIO_INPUT_CAPS); + break; + + case AW_TYPE_MIXER: + cmd_table = FETCH_MIXER_CAPS; + cmd_table_len = countof(FETCH_MIXER_CAPS); + break; + + case AW_TYPE_SELECTOR: + cmd_table = FETCH_SELECTOR_CAPS; + cmd_table_len = countof(FETCH_SELECTOR_CAPS); + break; + + case AW_TYPE_PIN_COMPLEX: + if (AW_CAPS_DIGITAL(widget->raw_caps)) { + cmd_table = FETCH_DIGITAL_PIN_COMPLEX_CAPS; + cmd_table_len = countof(FETCH_DIGITAL_PIN_COMPLEX_CAPS); + } else { + cmd_table = FETCH_NON_DIGITAL_PIN_COMPLEX_CAPS; + cmd_table_len = countof(FETCH_NON_DIGITAL_PIN_COMPLEX_CAPS); + } + break; + + case AW_TYPE_POWER: + cmd_table = FETCH_POWER_CAPS; + cmd_table_len = countof(FETCH_POWER_CAPS); + break; + + case AW_TYPE_VOLUME_KNOB: + cmd_table = FETCH_VOLUME_KNOB_CAPS; + cmd_table_len = countof(FETCH_VOLUME_KNOB_CAPS); + break; + + case AW_TYPE_BEEP_GEN: + case AW_TYPE_VENDOR: + intel_hda_fetch_next_widget(codec); + return; + + default: + LTRACEF("Unrecognized widget type 0x%02x at Node ID %hu in function group with Node ID " + "%hu\n", + widget->type, widget->nid, widget->fn_group->nid); + intel_hda_fetch_next_widget(codec); + return; + } + + DEBUG_ASSERT(cmd_table && cmd_table_len); + intel_hda_setup_cmd_list(codec, + cmd_table, + cmd_table_len, + intel_hda_fetch_widget_get_nid, + intel_hda_fetch_widget_connection_list); +} + +/* Function Group GetNID and Finished functions */ +static uint16_t intel_hda_fetch_function_group_get_nid(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec); + return codec->fn_group_iter + codec->fn_group_starting_id; +} + +static void intel_hda_fetch_afg_properties_finished(struct intel_hda_codec* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(!codec->solicited_response_handler); + DEBUG_ASSERT(!codec->pending_work_handler); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + /* If this function group has widgets, allocate storage to hold their + * pointers to their state. */ + if (fn_group->widget_count) { + fn_group->widgets = (intel_hda_widget_t*)calloc( + fn_group->widget_count, sizeof(intel_hda_widget_t)); + DEBUG_ASSERT(fn_group->widgets); + } + + /* Fetch next widget is always going to increment widget_iter. Set its + * value to -1 so the "next" widget it considers is widget 0. */ + codec->widget_iter = -1; + intel_hda_fetch_next_widget(codec); +} + +static void intel_hda_id_function_group_finished(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(!codec->solicited_response_handler); + DEBUG_ASSERT(!codec->pending_work_handler); + + /* If this is a function group type we care about (IOW - an AFG), enumerate + * it's properties. Otherwise, just move on to the next function group (if + * any) */ + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + if (codec->fn_groups[codec->fn_group_iter]) { + intel_hda_setup_cmd_list(codec, + FETCH_AFG_PROPERTIES_COMMANDS, + countof(FETCH_AFG_PROPERTIES_COMMANDS), + intel_hda_fetch_function_group_get_nid, + intel_hda_fetch_afg_properties_finished); + return; + } + + intel_hda_fetch_next_function_group(codec); +} + +/* Codec Root GetNID and Finished functions */ +static uint16_t intel_hda_fetch_codec_root_get_nid(intel_hda_codec_t* codec) { + return 0; +} + +static void intel_hda_fetch_codec_root_finished(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(!codec->solicited_response_handler); + DEBUG_ASSERT(!codec->pending_work_handler); + + /* We are done fetching our root info. If there are any function groups in + * this codec (and I sure hope that there are, or this is the world's most + * boring codec) start to enumerate their properties and widgets. */ + if (!codec->fn_group_count) + return; + + codec->fn_groups = (intel_hda_codec_audio_fn_group_t**)calloc( + codec->fn_group_count, + sizeof(intel_hda_codec_audio_fn_group_t*)); + DEBUG_ASSERT(codec->fn_groups); + + /* Fetch next function group is always going to increment fn_group_iter. + * Set its value to -1 so the "next" function group it considers is group 0. */ + codec->fn_group_iter = -1; + intel_hda_fetch_next_function_group(codec); +} + +/****************************************************************************** + * + * "fetch next" functions, generally called from the Finished functions of the + * various state machine stages in order to set up the state machine to move on + * to the object once the current object is finished. + * + ******************************************************************************/ +static void intel_hda_fetch_next_widget(intel_hda_codec_t* codec) { + DEBUG_ASSERT(codec); + DEBUG_ASSERT(codec->fn_groups && (codec->fn_group_iter < codec->fn_group_count)); + + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[codec->fn_group_iter]; + DEBUG_ASSERT(fn_group); + + codec->widget_iter++; + if (codec->widget_iter < fn_group->widget_count) { + intel_hda_setup_cmd_list(codec, + ID_WIDGET_COMMANDS, + countof(ID_WIDGET_COMMANDS), + intel_hda_fetch_widget_get_nid, + intel_hda_id_widget_finished); + return; + } + + /* Looks like we are out of widgets to enumerate for this function group. + * Move on to the next function group */ + intel_hda_fetch_next_function_group(codec); +} + +static void intel_hda_fetch_next_function_group(intel_hda_codec_t* codec) { + codec->fn_group_iter++; + if (codec->fn_group_iter < codec->fn_group_count) { + intel_hda_setup_cmd_list(codec, + ID_FUNCTION_GROUP_COMMANDS, + countof(ID_FUNCTION_GROUP_COMMANDS), + intel_hda_fetch_function_group_get_nid, + intel_hda_id_function_group_finished); + } else { + TRACEF("TODO(johngro): Codec configuration has been fetched. Time to start setup!\n"); + } +} + +/****************************************************************************** + * + * Driver facing API + * + ******************************************************************************/ +intel_hda_codec_t* intel_hda_create_codec(intel_hda_device_t* dev, uint8_t codec_id) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(codec_id < INTEL_HDA_MAX_CODECS); + + intel_hda_codec_t* codec = (intel_hda_codec_t*)calloc(1, sizeof(*codec)); + if (!codec) return NULL; + + codec->dev = dev; + codec->codec_id = codec_id; + + /* Start the process of fetching the root info for our codec. When we are + * finished, we will know the total number of function groups in the codec + * and can start to enumerate them. */ + intel_hda_setup_cmd_list(codec, + FETCH_CODEC_ROOT_COMMANDS, + countof(FETCH_CODEC_ROOT_COMMANDS), + intel_hda_fetch_codec_root_get_nid, + intel_hda_fetch_codec_root_finished); + + return codec; +} + +void intel_hda_destroy_codec(intel_hda_codec_t* codec) { + if (!codec) + return; + + if (codec->fn_groups) { + for (uint16_t i = 0; i < codec->fn_group_count; ++i) { + intel_hda_codec_audio_fn_group_t* afg = codec->fn_groups[i]; + if (afg) { + if (afg->widgets) { + for (uint16_t j = 0; j < afg->widget_count; ++j) { + intel_hda_widget_t* widget = afg->widgets + j; + if (widget->conn_list) + free(widget->conn_list); + } + free(afg->widgets); + } + free(afg); + } + } + free(codec->fn_groups); + } + free(codec); +} + +void intel_hda_codec_snapshot_corb(intel_hda_device_t* dev) { + DEBUG_ASSERT(dev && dev->regs); + DEBUG_ASSERT(dev->corb_entry_count && dev->corb_mask); + + hda_registers_t* r = dev->regs; + DEBUG_ASSERT(dev->corb_wr_ptr == REG_RD(16, r, corbwp)); + uint corb_rd_ptr = REG_RD(16, r, corbrp) & dev->corb_mask; + uint corb_used = (dev->corb_entry_count + dev->corb_wr_ptr - corb_rd_ptr) & dev->corb_mask; + + /* The way the Intel HDA command ring buffers work, it is impossible to ever + * be using more than N - 1 of the ring buffer entries. Our available + * space should be the ring buffer size, minus the amt currently used, minus 1 */ + DEBUG_ASSERT(dev->corb_entry_count > corb_used); + DEBUG_ASSERT(dev->corb_max_in_flight >= corb_used); + dev->corb_snapshot_space = dev->corb_max_in_flight - corb_used; + + LTRACEF("CORB has space for %u commands; WP is @%u\n", + dev->corb_snapshot_space, dev->corb_wr_ptr); +} + +void intel_hda_codec_commit_corb(intel_hda_device_t* dev) { + DEBUG_ASSERT(dev && dev->regs); + DEBUG_ASSERT(dev->corb_entry_count && dev->corb_mask); + DEBUG_ASSERT(dev->corb_wr_ptr < dev->corb_entry_count); + + /* TODO(johngro) : Make sure to force a write back of the cache for the + * dirty portions of the CORB before we update the write pointer if we are + * running on an architecure where cache coherency is not automatically + * managed for us via. snooping or by an explicit uncached or write-thru + * policy set on our mapped pages in the MMU. */ + + LTRACEF("Update CORB WP; WP is @%u\n", dev->corb_wr_ptr); + + hda_registers_t* r = dev->regs; + REG_WR(16, r, corbwp, dev->corb_wr_ptr); +} + +void intel_hda_codec_snapshot_rirb(intel_hda_device_t* dev) { + DEBUG_ASSERT(dev && dev->regs && dev->rirb); + hda_registers_t* r = dev->regs; + + DEBUG_ASSERT(dev->rirb_entry_count && dev->rirb_mask); + uint rirb_wr_ptr = REG_RD(16, r, rirbwp) & dev->rirb_mask; + uint pending = (dev->rirb_entry_count + rirb_wr_ptr - dev->rirb_rd_ptr) & dev->rirb_mask; + + /* Copy the current state of the RIRB into our snapshot memory. Note: we + * loop at most up to 2 times in order to deal with the case where the + * active region of the ring buffer wraps around the end. + * + * TODO(johngro) : Make sure to invalidate cache for the memory region + * occupied by the RIRB before we copy into our snapshot if we are running + * on an architecure where cache coherency is not automatically managed for + * us via. something like snooping, or by a un-cached policy set on our + * mapped pages in the MMU. */ + dev->rirb_snapshot_cnt = 0; + while (pending) { + /* Intel HDA ring buffers are strange, see comments in + * intel_hda_codec_send_cmd. */ + uint tmp_rd = (dev->rirb_rd_ptr + 1) & dev->rirb_mask; + uint todo = MIN(pending, (dev->rirb_entry_count - tmp_rd)); + + memcpy(dev->rirb_snapshot + dev->rirb_snapshot_cnt, + dev->rirb + tmp_rd, + sizeof(dev->rirb_snapshot[0]) * todo); + + dev->rirb_rd_ptr = (dev->rirb_rd_ptr + todo) & dev->rirb_mask; + dev->rirb_snapshot_cnt += todo; + pending -= todo; + } +} + +void intel_hda_codec_process_rirb(intel_hda_device_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->rirb_snapshot_cnt < HDA_RIRB_MAX_ENTRIES); + DEBUG_ASSERT(dev->rirb_snapshot_cnt < dev->rirb_entry_count); + + for (uint i = 0; i < dev->rirb_snapshot_cnt; ++i) { + hda_rirb_entry_t* resp = dev->rirb_snapshot + i; + + /* Fixup endianness */ + resp->data = LE32(resp->data); + resp->data_ex = LE32(resp->data_ex); + + /* Figure out the codec this came from and whether or not the response + * was solicited. */ + uint caddr = HDA_RIRB_CADDR(*resp); + bool unsolicited = HDA_RIRB_UNSOL(*resp); + + /* Sanity checks */ + if (caddr >= countof(dev->codecs)) { + TRACEF("Received %ssolicited response with illegal codec address (%u) " + "[0x%08x, 0x%08x]\n", + unsolicited ? "un" : "", caddr, resp->data, resp->data_ex); + continue; + } + + intel_hda_codec_t* codec = dev->codecs[caddr]; + if (!codec) { + TRACEF("Received %ssolicited response for non-existent codec address (%u) " + "[0x%08x, 0x%08x]\n", + unsolicited ? "un" : "", caddr, resp->data, resp->data_ex); + continue; + } + + intel_hda_codec_response_handler_fn handler = unsolicited + ? codec->unsolicited_response_handler + : codec->solicited_response_handler; + if (!handler) { + TRACEF("Received %ssolicited response, but codec with address %u has no handler " + "[0x%08x, 0x%08x]\n", + unsolicited ? "un" : "", caddr, resp->data, resp->data_ex); + continue; + } + + /* Dispatch the response */ + LTRACEF("RX Cmd: Codec ID %2u Data 0x%08x\n", caddr, resp->data); + handler(codec, resp->data); + } + + dev->rirb_snapshot_cnt = 0; +} + +void intel_hda_codec_process_pending_work(intel_hda_device_t* dev) { + for (size_t i = 0; i < countof(dev->codecs); ++i) { + intel_hda_codec_t* codec = dev->codecs[i]; + if (codec && codec->pending_work_handler) + codec->pending_work_handler(codec); + } +} diff --git a/kernel/dev/intel_hda/codec.h b/kernel/dev/intel_hda/codec.h new file mode 100644 index 000000000..3ad9da973 --- /dev/null +++ b/kernel/dev/intel_hda/codec.h @@ -0,0 +1,285 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +#include "registers.h" + +#define INTEL_HDA_MAX_CODECS (15u) + +/* Bitfield definitions for the PCM Size/Rate property. See section 7.3.4.7 */ +#define IHDA_PCM_SIZE_32BITS (1u << 20) // 32-bit PCM samples supported +#define IHDA_PCM_SIZE_24BITS (1u << 19) // 24-bit PCM samples supported +#define IHDA_PCM_SIZE_20BITS (1u << 18) // 20-bit PCM samples supported +#define IHDA_PCM_SIZE_16BITS (1u << 17) // 16-bit PCM samples supported +#define IHDA_PCM_SIZE_8BITS (1u << 16) // 8-bit PCM samples supported + +#define IHDA_PCM_RATE_384000 (1u << 11) // 384000 Hz +#define IHDA_PCM_RATE_192000 (1u << 10) // 192000 Hz +#define IHDA_PCM_RATE_176400 (1u << 9) // 176400 Hz +#define IHDA_PCM_RATE_96000 (1u << 8) // 96000 Hz +#define IHDA_PCM_RATE_88200 (1u << 7) // 88200 Hz +#define IHDA_PCM_RATE_48000 (1u << 6) // 48000 Hz +#define IHDA_PCM_RATE_44100 (1u << 5) // 44100 Hz +#define IHDA_PCM_RATE_32000 (1u << 4) // 32000 Hz +#define IHDA_PCM_RATE_22050 (1u << 3) // 22050 Hz +#define IHDA_PCM_RATE_16000 (1u << 2) // 16000 Hz +#define IHDA_PCM_RATE_11025 (1u << 1) // 11025 Hz +#define IHDA_PCM_RATE_8000 (1u << 0) // 8000 Hz + +/* Bitfield definitions for the PCM Formats property. See section 7.3.4.8 */ +#define IHDA_PCM_FORMAT_AC3 (1u << 2) // Dolby Digital AC-3 / ATSC A.52 +#define IHDA_PCM_FORMAT_FLOAT32 (1u << 1) // 32-bit float +#define IHDA_PCM_FORMAT_PCM (1u << 0) // PCM; See PCM size rate for details + +/* Bitfield definitions for Supported Power States. See section 7.3.4.12 */ +#define IHDA_PWR_STATE_EPSS (1u << 31) +#define IHDA_PWR_STATE_CLKSTOP (1u << 30) +#define IHDA_PWR_STATE_S3D3COLD (1u << 29) +#define IHDA_PWR_STATE_D3COLD (1u << 4) +#define IHDA_PWR_STATE_D3 (1u << 3) +#define IHDA_PWR_STATE_D2 (1u << 2) +#define IHDA_PWR_STATE_D1 (1u << 1) +#define IHDA_PWR_STATE_D0 (1u << 0) + +/* Defined audio widget types. See Table 138 */ +#define AW_TYPE_OUTPUT (0x0) +#define AW_TYPE_INPUT (0x1) +#define AW_TYPE_MIXER (0x2) +#define AW_TYPE_SELECTOR (0x3) +#define AW_TYPE_PIN_COMPLEX (0x4) +#define AW_TYPE_POWER (0x5) +#define AW_TYPE_VOLUME_KNOB (0x6) +#define AW_TYPE_BEEP_GEN (0x7) +#define AW_TYPE_VENDOR (0xf) + +/* Defined audio widget capability flags. See section 7.3.4.6 and Fig. 86 */ +#define AW_CAPS_FLAG_INPUT_AMP_PRESENT (1u << 1) +#define AW_CAPS_FLAG_OUTPUT_AMP_PRESENT (1u << 2) +#define AW_CAPS_FLAG_AMP_PARAM_OVERRIDE (1u << 3) +#define AW_CAPS_FLAG_FORMAT_OVERRIDE (1u << 4) +#define AW_CAPS_FLAG_STRIP_SUPPORTED (1u << 5) +#define AW_CAPS_FLAG_PROC_WIDGET (1u << 6) +#define AW_CAPS_FLAG_CAN_SEND_UNSOL (1u << 7) +#define AW_CAPS_FLAG_HAS_CONN_LIST (1u << 8) +#define AW_CAPS_FLAG_DIGITAL (1u << 9) +#define AW_CAPS_FLAG_HAS_POWER_CTL (1u << 10) +#define AW_CAPS_FLAG_CAN_LR_SWAP (1u << 11) +#define AW_CAPS_FLAG_HAS_CONTENT_PROT (1u << 12) + +#define AW_CAPS_INPUT_AMP_PRESENT(caps) ((caps) & AW_CAPS_FLAG_INPUT_AMP_PRESENT) +#define AW_CAPS_OUTPUT_AMP_PRESENT(caps) ((caps) & AW_CAPS_FLAG_OUTPUT_AMP_PRESENT) +#define AW_CAPS_AMP_PARAM_OVERRIDE(caps) ((caps) & AW_CAPS_FLAG_AMP_PARAM_OVERRIDE) +#define AW_CAPS_FORMAT_OVERRIDE(caps) ((caps) & AW_CAPS_FLAG_FORMAT_OVERRIDE) +#define AW_CAPS_STRIP_SUPPORTED(caps) ((caps) & AW_CAPS_FLAG_STRIP_SUPPORTED) +#define AW_CAPS_PROC_WIDGET(caps) ((caps) & AW_CAPS_FLAG_PROC_WIDGET) +#define AW_CAPS_CAN_SEND_UNSOL(caps) ((caps) & AW_CAPS_FLAG_CAN_SEND_UNSOL) +#define AW_CAPS_HAS_CONN_LIST(caps) ((caps) & AW_CAPS_FLAG_HAS_CONN_LIST) +#define AW_CAPS_DIGITAL(caps) ((caps) & AW_CAPS_FLAG_DIGITAL) +#define AW_CAPS_HAS_POWER_CTL(caps) ((caps) & AW_CAPS_FLAG_HAS_POWER_CTL) +#define AW_CAPS_CAN_LR_SWAP(caps) ((caps) & AW_CAPS_FLAG_CAN_LR_SWAP) +#define AW_CAPS_HAS_CONTENT_PROT(caps) ((caps) & AW_CAPS_FLAG_HAS_CONTENT_PROT) + +/* Defined pin capability flags. See section 7.3.4.9 and Fig. 90 */ +#define AW_PIN_CAPS_FLAG_CAN_IMPEDANCE_SENSE (1u << 0) +#define AW_PIN_CAPS_FLAG_TRIGGER_REQUIRED (1u << 1) +#define AW_PIN_CAPS_FLAG_CAN_PRESENCE_DETECT (1u << 2) +#define AW_PIN_CAPS_FLAG_CAN_DRIVE_HEADPHONES (1u << 3) +#define AW_PIN_CAPS_FLAG_CAN_OUTPUT (1u << 4) +#define AW_PIN_CAPS_FLAG_CAN_INPUT (1u << 5) +#define AW_PIN_CAPS_FLAG_BALANCED_IO (1u << 6) +#define AW_PIN_CAPS_FLAG_HDMI (1u << 7) +#define AW_PIN_CAPS_FLAG_VREF_HIZ (1u << 8) +#define AW_PIN_CAPS_FLAG_VREF_50_PERCENT (1u << 9) +#define AW_PIN_CAPS_FLAG_VREF_GROUND (1u << 10) +#define AW_PIN_CAPS_FLAG_VREF_80_PERCENT (1u << 12) +#define AW_PIN_CAPS_FLAG_VREF_100_PERCENT (1u << 13) +#define AW_PIN_CAPS_FLAG_CAN_EAPD (1u << 16) +#define AW_PIN_CAPS_FLAG_DISPLAY_PORT (1u << 24) +#define AW_PIN_CAPS_FLAG_HIGH_BIT_RATE (1u << 27) + +struct intel_hda_device; +struct intel_hda_codec; +struct intel_hda_codec_audio_fn_group; +struct intel_hda_widget_hdr; + +typedef void (*intel_hda_codec_response_handler_fn)(struct intel_hda_codec* codec, uint32_t data); +typedef void (*intel_hda_codec_pending_work_handler_fn)(struct intel_hda_codec* codec); +typedef void (*intel_hda_codec_finished_command_list_handler_fn)(struct intel_hda_codec* codec); +typedef uint16_t (*intel_hda_codec_get_cmd_list_nid_fn)(struct intel_hda_codec* codec); + +typedef struct intel_hda_command_list_entry { + uint32_t verb; + intel_hda_codec_response_handler_fn process_resp; +} intel_hda_command_list_entry_t; + +typedef struct intel_hda_command_list_state { + const intel_hda_command_list_entry_t* cmds; + size_t cmd_count; + size_t tx_ndx; + size_t rx_ndx; + intel_hda_codec_get_cmd_list_nid_fn get_nid; + intel_hda_codec_finished_command_list_handler_fn finished_handler; +} intel_hda_command_list_state_t; + +typedef struct intel_hda_codec_amp_caps { + bool can_mute; + uint8_t step_size; // amp gain step size in units of 0.25 dB + uint8_t num_steps; // Number of gain steps. 1 step means fixed, 0dB gain. + uint8_t offset; // The gain value which corresponds to 0dB +} intel_hda_codec_amp_caps_t; + +typedef struct intel_hda_widget { + struct intel_hda_codec_audio_fn_group* fn_group; + uint16_t nid; + + // Note: to simplify life, the widget struct contains the union of all of + // the different field which may be needed for any type of audio widget. + // Not all of the fields will be meaningful depending on the widget type. + uint32_t raw_caps; + uint8_t type; + uint8_t delay; + uint8_t ch_count; + + uint32_t pcm_size_rate; // Section 7.3.4.7 : Supported PCM sizes and rates + uint32_t pcm_formats; // Section 7.3.4.8 : Supported PCM formats + uint32_t pin_caps; // Section 7.3.4.9 : Pin Capabilities + + // Section 7.3.4.10 : Amplifier capabilities + intel_hda_codec_amp_caps_t input_amp_caps; + intel_hda_codec_amp_caps_t output_amp_caps; + + // Sections 7.3.3.3 & 7.3.4.11 : Connection List + bool long_form_conn_list; + uint8_t conn_list_len; + uint16_t* conn_list; + + // Section 7.3.4.12 : Supported Power States + uint32_t power_states; + + // Section 7.3.4.13 : Processing Capabilities + bool can_bypass_processing; + uint8_t processing_coefficient_count; + + // Section 7.3.4.15 : Volume Knob Capabilities + bool vol_knob_is_delta; + uint8_t vol_knob_steps; +} intel_hda_widget_t; + +typedef struct intel_hda_codec_audio_fn_group { + bool can_send_unsolicited; + uint8_t fn_group_type; + uint16_t nid; + + // Section 7.3.4.5 : AFG Caps + // Note: delays are expressed in audio frames. If a path delay value is 0, + // the delay should be computed by summing the delays of the widget chain + // used to create either the input or output paths. + bool has_beep_gen; + uint8_t path_input_delay; + uint8_t path_output_delay; + + uint32_t default_pcm_size_rate; // Section 7.3.4.7 : Supported PCM sizes and rates + uint32_t default_pcm_formats; // Section 7.3.4.8 : Supported PCM formats + + // Section 7.3.4.10 : Amplifier capabilities + intel_hda_codec_amp_caps_t default_input_amp_caps; + intel_hda_codec_amp_caps_t default_output_amp_caps; + + // Section 7.3.4.12 : Supported Power States + uint32_t power_states; + + // Section 7.3.4.14 : GPIO Counts + bool gpio_can_wake; + bool gpio_can_send_unsolicited; + uint8_t gpio_count; + uint8_t gpo_count; + uint8_t gpi_count; + + uint16_t widget_count; + uint16_t widget_starting_id; + intel_hda_widget_t* widgets; +} intel_hda_codec_audio_fn_group_t; + +typedef struct intel_hda_codec { + struct intel_hda_device* dev; + uint8_t codec_id; + + uint16_t vendor_id; + uint16_t device_id; + + uint8_t major_rev; + uint8_t minor_rev; + uint8_t vendor_rev_id; + uint8_t vendor_stepping_id; + + uint16_t fn_group_count; + uint16_t fn_group_starting_id; + intel_hda_codec_audio_fn_group_t** fn_groups; + + // State machine callbacks and bookkeeping. Used for enumerating codec + // capabilities at startup. + intel_hda_codec_response_handler_fn solicited_response_handler; + intel_hda_codec_response_handler_fn unsolicited_response_handler; + intel_hda_codec_pending_work_handler_fn pending_work_handler; + intel_hda_command_list_state_t cmd_list; + uint16_t fn_group_iter; + uint16_t widget_iter; + uint8_t conn_list_tx_iter; + uint8_t conn_list_rx_iter; +} intel_hda_codec_t; + +/* + * Create a codec for the specified device with the specified codec id. + */ +intel_hda_codec_t* intel_hda_create_codec(struct intel_hda_device* dev, uint8_t codec_id); + +/* + * Release all of the resources associated with a codec. + */ +void intel_hda_destroy_codec(intel_hda_codec_t* codec); + +/* + * Called once at the start of the codec service cycle. + * + * Observe the amount of space for new jobs in the CORB, and reset the + * bookkeeping about the number of pending jobs and current write pointer + * position. + */ +void intel_hda_codec_snapshot_corb(struct intel_hda_device* dev); + +/* + * Called once at the end of the codec service cycle. + * + * Update the CORB write pointer and begin transmitting any command requests + * which were queued by codecs during the codec service cycle. + */ +void intel_hda_codec_commit_corb(struct intel_hda_device* dev); + +/* + * Called once at the start of the codec service cycle. + * + * Take a snapshot of any responses pending in the RIRB and stash in local + * memory to minimize the chance of an undetectable ring buffer overflow.. + */ +void intel_hda_codec_snapshot_rirb(struct intel_hda_device* dev); + +/* + * Called once in the middle of the codec service cycle. + * + * Go over the RIRB snapshot and dispatch any pending responses to the various + * codecs. + */ +void intel_hda_codec_process_rirb(struct intel_hda_device* dev); + +/* + * Go over the list of codecs who may have pending work and give them a chance + * to schedule communications on the link. + */ +void intel_hda_codec_process_pending_work(struct intel_hda_device* dev); diff --git a/kernel/dev/intel_hda/codec_commands.h b/kernel/dev/intel_hda/codec_commands.h new file mode 100644 index 000000000..9f167753f --- /dev/null +++ b/kernel/dev/intel_hda/codec_commands.h @@ -0,0 +1,160 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +// Helper macros for making command verbs with either short or long payloads. +#define CC_SP_VERB(id, payload) ((((uint32_t)(id) & 0xFFF) << 8) | ((uint8_t)(payload))) +#define CC_LP_VERB(id, payload) ((((uint32_t)(id) & 0xF) << 16) | ((uint16_t)(payload))) + +#define CC_SP_GET_VERB(id) CC_SP_VERB(0xF00 | id, 0) +#define CC_SP_SET_VERB(id, payload) CC_SP_VERB(0x700 | id, payload) +#define CC_LP_GET_VERB(id) CC_LP_VERB(0x8 + id, 0) +#define CC_LP_SET_VERB(id, payload) CC_LP_VERB(0x0 + id, payload) + +// Sections 7.3.3.1, 7.3.4, 7.3.6, Table 140 +#define CC_GET_PARAM(param_id) CC_SP_VERB(0xF00, param_id) +#define CC_PARAM_VENDOR_ID (0x00) // Section 7.3.4.1 +#define CC_PARAM_REVISION_ID (0x02) // Section 7.3.4.2 +#define CC_PARAM_SUBORDINATE_NODE_COUNT (0x04) // Section 7.3.4.3 +#define CC_PARAM_FUNCTION_GROUP_TYPE (0x05) // Section 7.3.4.4 +#define CC_PARAM_AFG_CAPS (0x08) // Section 7.3.4.5 +#define CC_PARAM_AW_CAPS (0x09) // Section 7.3.4.6 +#define CC_PARAM_SUPPORTED_PCM_SIZE_RATE (0x0a) // Section 7.3.4.7 +#define CC_PARAM_SUPPORTED_STREAM_FORMATS (0x0b) // Section 7.3.4.8 +#define CC_PARAM_PIN_CAPS (0x0c) // Section 7.3.4.9 +#define CC_PARAM_INPUT_AMP_CAPS (0x0d) // Section 7.3.4.10 +#define CC_PARAM_OUTPUT_AMP_CAPS (0x12) // Section 7.3.4.10 +#define CC_PARAM_CONNECTION_LIST_LEN (0x0e) // Section 7.3.4.11 +#define CC_PARAM_SUPPORTED_PWR_STATES (0x0f) // Section 7.3.4.12 +#define CC_PARAM_PROCESSING_CAPS (0x10) // Section 7.3.4.13 +#define CC_PARAM_GPIO_COUNT (0x11) // Section 7.3.4.14 +#define CC_PARAM_VOLUME_KNOB_CAPS (0x13) // Section 7.3.4.15 + +#define CC_GET_CONNECTION_SELECT_CONTROL CC_SP_GET_VERB(0x01) // Section 7.3.3.2 +#define CC_SET_CONNECTION_SELECT_CONTROL(val) CC_SP_SET_VERB(0x01, val) // Section 7.3.3.2 + +#define CC_GET_CONNECTION_LIST_ENTRY(offset) CC_SP_VERB(0xF02, offset) // Section 7.3.3.3 + +#define CC_GET_PROCESSING_STATE CC_SP_GET_VERB(0x03) // Section 7.3.3.4 +#define CC_SET_PROCESSING_STATE(val) CC_SP_SET_VERB(0x03, val) // Section 7.3.3.4 + +#define CC_GET_COEFFICIENT_INDEX CC_LP_GET_VERB(0x05) // Section 7.3.3.5 +#define CC_SET_COEFFICIENT_INDEX(val) CC_LP_SET_VERB(0x05, val) // Section 7.3.3.5 + +#define CC_GET_PROCESSING_COEFFICIENT CC_LP_GET_VERB(0x04) // Section 7.3.3.6 +#define CC_SET_PROCESSING_COEFFICIENT(val) CC_LP_SET_VERB(0x04, val) // Section 7.3.3.6 + +#define CC_GET_AMPLIFIER_GAIN_MUTE CC_LP_GET_VERB(0x03) // Section 7.3.3.7 +#define CC_SET_AMPLIFIER_GAIN_MUTE(val) CC_LP_SET_VERB(0x03, val) // Section 7.3.3.7 + +#define CC_GET_CONVERTER_FORMAT CC_LP_GET_VERB(0x02) // Section 7.3.3.8 +#define CC_SET_CONVERTER_FORMAT(val) CC_LP_SET_VERB(0x02, val) // Section 7.3.3.8 + +#define CC_GET_DIGITAL_CONV_CONTROL CC_SP_GET_VERB(0x0D) // Section 7.3.3.9 +#define CC_SET_DIGITAL_CONV_CONTROL_1(val) CC_SP_SET_VERB(0x0D, val) // Section 7.3.3.9 +#define CC_SET_DIGITAL_CONV_CONTROL_2(val) CC_SP_SET_VERB(0x0E, val) // Section 7.3.3.9 +#define CC_SET_DIGITAL_CONV_CONTROL_3(val) CC_SP_SET_VERB(0x3E, val) // Section 7.3.3.9 +#define CC_SET_DIGITAL_CONV_CONTROL_4(val) CC_SP_SET_VERB(0x3F, val) // Section 7.3.3.9 + +#define CC_GET_POWER_STATE CC_SP_GET_VERB(0x05) // Section 7.3.3.10 +#define CC_SET_POWER_STATE(val) CC_SP_SET_VERB(0x05, val) // Section 7.3.3.10 + +#define CC_GET_CONVERTER_STREAM_CHAN CC_SP_GET_VERB(0x06) // Section 7.3.3.11 +#define CC_SET_CONVERTER_STREAM_CHAN(val) CC_SP_SET_VERB(0x06, val) // Section 7.3.3.11 + +#define CC_GET_INPUT_CONV_SDI_SELECT CC_SP_GET_VERB(0x04) // Section 7.3.3.12 +#define CC_SET_INPUT_CONV_SDI_SELECT(val) CC_SP_SET_VERB(0x04, val) // Section 7.3.3.12 + +#define CC_GET_PIN_WIDGET_CTRL CC_SP_GET_VERB(0x07) // Section 7.3.3.13 +#define CC_SET_PIN_WIDGET_CTRL(val) CC_SP_SET_VERB(0x07, val) // Section 7.3.3.13 + +#define CC_GET_UNSOLICITED_RESP_CTRL CC_SP_GET_VERB(0x08) // Section 7.3.3.14 +#define CC_SET_UNSOLICITED_RESP_CTRL(val) CC_SP_SET_VERB(0x08, val) // Section 7.3.3.14 + +#define CC_GET_PIN_SENSE_CTRL CC_SP_GET_VERB(0x09) // Section 7.3.3.15 +#define CC_SET_PIN_SENSE_CTRL(val) CC_SP_SET_VERB(0x09, val) // Section 7.3.3.15 + +#define CC_GET_EAPD_BTL_ENABLE CC_SP_GET_VERB(0x0C) // Section 7.3.3.16 +#define CC_SET_EAPD_BTL_ENABLE(val) CC_SP_SET_VERB(0x0C, val) // Section 7.3.3.16 + +#define CC_GET_GPI_DATA CC_SP_GET_VERB(0x10) // Section 7.3.3.17 +#define CC_SET_GPI_DATA(val) CC_SP_SET_VERB(0x10, val) // Section 7.3.3.17 + +#define CC_GET_GPI_WAKE_ENB_MASK CC_SP_GET_VERB(0x11) // Section 7.3.3.18 +#define CC_SET_GPI_WAKE_ENB_MASK(val) CC_SP_SET_VERB(0x11, val) // Section 7.3.3.18 + +#define CC_GET_GPI_UNSOLICITED_ENB_MASK CC_SP_GET_VERB(0x12) // Section 7.3.3.19 +#define CC_SET_GPI_UNSOLICITED_ENB_MASK(val) CC_SP_SET_VERB(0x12, val) // Section 7.3.3.19 + +#define CC_GET_GPI_STICKY_MASK CC_SP_GET_VERB(0x13) // Section 7.3.3.20 +#define CC_SET_GPI_STICKY_MASK(val) CC_SP_SET_VERB(0x13, val) // Section 7.3.3.20 + +#define CC_GET_GPO_DATA CC_SP_GET_VERB(0x14) // Section 7.3.3.21 +#define CC_SET_GPO_DATA(val) CC_SP_SET_VERB(0x14, val) // Section 7.3.3.21 + +#define CC_GET_GPIO_DATA CC_SP_GET_VERB(0x15) // Section 7.3.3.22 +#define CC_SET_GPIO_DATA(val) CC_SP_SET_VERB(0x15, val) // Section 7.3.3.22 + +#define CC_GET_GPIO_ENB_MASK CC_SP_GET_VERB(0x16) // Section 7.3.3.23 +#define CC_SET_GPIO_ENB_MASK(val) CC_SP_SET_VERB(0x16, val) // Section 7.3.3.23 + +#define CC_GET_GPIO_DIR CC_SP_GET_VERB(0x17) // Section 7.3.3.24 +#define CC_SET_GPIO_DIR(val) CC_SP_SET_VERB(0x17, val) // Section 7.3.3.24 + +#define CC_GET_GPIO_WAKE_ENB_MASK CC_SP_GET_VERB(0x18) // Section 7.3.3.25 +#define CC_SET_GPIO_WAKE_ENB_MASK(val) CC_SP_SET_VERB(0x18, val) // Section 7.3.3.25 + +#define CC_GET_GPIO_UNSOLICITED_ENB_MASK CC_SP_GET_VERB(0x19) // Section 7.3.3.26 +#define CC_SET_GPIO_UNSOLICITED_ENB_MASK(val) CC_SP_SET_VERB(0x19, val) // Section 7.3.3.26 + +#define CC_GET_GPIO_STICKY_MASK CC_SP_GET_VERB(0x1a) // Section 7.3.3.27 +#define CC_SET_GPIO_STICKY_MASK(val) CC_SP_SET_VERB(0x1a, val) // Section 7.3.3.27 + +#define CC_GET_BEEP_GENERATION CC_SP_GET_VERB(0x0a) // Section 7.3.3.28 +#define CC_SET_BEEP_GENERATION(val) CC_SP_SET_VERB(0x0a, val) // Section 7.3.3.28 + +#define CC_GET_VOLUME_KNOB CC_SP_GET_VERB(0x0f) // Section 7.3.3.29 +#define CC_SET_VOLUME_KNOB(val) CC_SP_SET_VERB(0x0f, val) // Section 7.3.3.29 + +#define CC_GET_IMPLEMENTATION_ID CC_SP_GET_VERB(0x20) // Section 7.3.3.30 +#define CC_SET_IMPLEMENTATION_ID_1(val) CC_SP_SET_VERB(0x20, val) // Section 7.3.3.30 +#define CC_SET_IMPLEMENTATION_ID_2(val) CC_SP_SET_VERB(0x21, val) // Section 7.3.3.30 +#define CC_SET_IMPLEMENTATION_ID_3(val) CC_SP_SET_VERB(0x22, val) // Section 7.3.3.30 +#define CC_SET_IMPLEMENTATION_ID_4(val) CC_SP_SET_VERB(0x23, val) // Section 7.3.3.30 + +#define CC_GET_CONFIG_DEFAULT CC_SP_GET_VERB(0x1c) // Section 7.3.3.31 +#define CC_SET_CONFIG_DEFAULT_1(val) CC_SP_SET_VERB(0x1c, val) // Section 7.3.3.31 +#define CC_SET_CONFIG_DEFAULT_2(val) CC_SP_SET_VERB(0x1d, val) // Section 7.3.3.31 +#define CC_SET_CONFIG_DEFAULT_3(val) CC_SP_SET_VERB(0x1e, val) // Section 7.3.3.31 +#define CC_SET_CONFIG_DEFAULT_4(val) CC_SP_SET_VERB(0x1f, val) // Section 7.3.3.31 + +#define CC_GET_STRIPE_CONTROL CC_SP_GET_VERB(0x24) // Section 7.3.3.32 +#define CC_SET_STRIPE_CONTROL(val) CC_SP_SET_VERB(0x24, val) // Section 7.3.3.32 + +#define CC_EXECUTE_FUNCTION_RESET CC_SP_SET_VERB(0xFF, 0) // Section 7.3.3.33 + +#define CC_GET_EDID_LIKE_DATA CC_SP_GET_VERB(0x2F) // Section 7.3.3.34 + +#define CC_GET_CONV_CHANNEL_COUNT CC_SP_GET_VERB(0x2d) // Section 7.3.3.35 +#define CC_SET_CONV_CHANNEL_COUNT(val) CC_SP_SET_VERB(0x2d, val) // Section 7.3.3.35 + +#define CC_GET_DIP_SIZE CC_SP_GET_VERB(0x2e) // Section 7.3.3.36 + +#define CC_GET_DIP_INDEX CC_SP_GET_VERB(0x30) // Section 7.3.3.37 +#define CC_SET_DIP_INDEX(val) CC_SP_SET_VERB(0x30, val) // Section 7.3.3.37 + +#define CC_GET_DIP_DATA CC_SP_GET_VERB(0x31) // Section 7.3.3.38 +#define CC_SET_DIP_DATA(val) CC_SP_SET_VERB(0x31, val) // Section 7.3.3.38 + +#define CC_GET_DIP_XMIT_CTRL CC_SP_GET_VERB(0x32) // Section 7.3.3.39 +#define CC_SET_DIP_XMIT_CTRL(val) CC_SP_SET_VERB(0x32, val) // Section 7.3.3.39 + +#define CC_GET_CP_CONTROL CC_SP_GET_VERB(0x33) // Section 7.3.3.40 +#define CC_SET_CP_CONTROL(val) CC_SP_SET_VERB(0x33, val) // Section 7.3.3.40 + +#define CC_GET_ASP_CHAN_MAPPING CC_SP_GET_VERB(0x34) // Section 7.3.3.41 +#define CC_SET_ASP_CHAN_MAPPING(val) CC_SP_SET_VERB(0x34, val) // Section 7.3.3.41 diff --git a/kernel/dev/intel_hda/debug.c b/kernel/dev/intel_hda/debug.c new file mode 100644 index 000000000..0f1bb9bb8 --- /dev/null +++ b/kernel/dev/intel_hda/debug.c @@ -0,0 +1,596 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if WITH_LIB_CONSOLE + +#include +#include +#include +#include +#include + +#include "codec.h" +#include "intel_hda.h" + +typedef struct flag_lut_entry { + uint32_t flag_bit; + const char* flag_name; +} flag_lut_entry_t; + +static void ihda_dump_flags(uint32_t flags, + const flag_lut_entry_t* table, + size_t table_size, + const char* suffix, + const char* no_flags_text) { + bool got_one = false; + for (size_t i = 0; i < table_size; ++i) { + if (flags & table[i].flag_bit) { + printf("%s%s", got_one ? " " : "", table[i].flag_name); + got_one = true; + } + } + + printf("%s\n", got_one ? suffix : no_flags_text); +} + +#define DUMP_FLAGS(flags, table, suffix, no_flags_text) \ + ihda_dump_flags(flags, table, countof(table), suffix, no_flags_text) + +static const flag_lut_entry_t POWER_STATE_FLAGS[] = { + { IHDA_PWR_STATE_EPSS, "EPSS" }, + { IHDA_PWR_STATE_CLKSTOP, "CLKSTOP" }, + { IHDA_PWR_STATE_S3D3COLD, "S3D3COLD" }, + { IHDA_PWR_STATE_D3COLD, "D3COLD" }, + { IHDA_PWR_STATE_D3, "D3HOT" }, + { IHDA_PWR_STATE_D2, "D2" }, + { IHDA_PWR_STATE_D1, "D1" }, + { IHDA_PWR_STATE_D0, "D0" }, +}; + +static const flag_lut_entry_t PCM_RATE_FLAGS[] = { + { IHDA_PCM_RATE_384000, "384000" }, + { IHDA_PCM_RATE_192000, "192000" }, + { IHDA_PCM_RATE_176400, "176400" }, + { IHDA_PCM_RATE_96000, "96000" }, + { IHDA_PCM_RATE_88200, "88200" }, + { IHDA_PCM_RATE_48000, "48000" }, + { IHDA_PCM_RATE_44100, "44100" }, + { IHDA_PCM_RATE_32000, "32000" }, + { IHDA_PCM_RATE_22050, "22050" }, + { IHDA_PCM_RATE_16000, "16000" }, + { IHDA_PCM_RATE_11025, "11025" }, + { IHDA_PCM_RATE_8000, "8000" }, +}; + +static const flag_lut_entry_t PCM_SIZE_FLAGS[] = { + { IHDA_PCM_SIZE_32BITS, "32" }, + { IHDA_PCM_SIZE_24BITS, "24" }, + { IHDA_PCM_SIZE_20BITS, "20" }, + { IHDA_PCM_SIZE_16BITS, "16" }, + { IHDA_PCM_SIZE_8BITS, "8" }, +}; + +static const flag_lut_entry_t PCM_FMT_FLAGS[] = { + { IHDA_PCM_FORMAT_AC3, "AC3" }, + { IHDA_PCM_FORMAT_FLOAT32, "FLOAT32" }, + { IHDA_PCM_FORMAT_PCM, "PCM" }, +}; + +static const flag_lut_entry_t AW_CAPS_FLAGS[] = { + { AW_CAPS_FLAG_AMP_PARAM_OVERRIDE, "AmpParamOverride" }, + { AW_CAPS_FLAG_FORMAT_OVERRIDE, "FormatOverride" }, + { AW_CAPS_FLAG_STRIP_SUPPORTED, "StripingSupported" }, + { AW_CAPS_FLAG_PROC_WIDGET, "HasProcessingControls" }, + { AW_CAPS_FLAG_CAN_SEND_UNSOL, "CanSendUnsolicited" }, + { AW_CAPS_FLAG_DIGITAL, "Digital" }, + { AW_CAPS_FLAG_CAN_LR_SWAP, "CanSwapLR" }, + { AW_CAPS_FLAG_HAS_CONTENT_PROT, "HasContentProtection" }, +}; + +static const flag_lut_entry_t PIN_CAPS_FLAGS[] = { + { AW_PIN_CAPS_FLAG_CAN_IMPEDANCE_SENSE, "ImpedanceSense" }, + { AW_PIN_CAPS_FLAG_TRIGGER_REQUIRED, "TrigReq" }, + { AW_PIN_CAPS_FLAG_CAN_PRESENCE_DETECT, "PresDetect" }, + { AW_PIN_CAPS_FLAG_CAN_DRIVE_HEADPHONES, "HeadphoneDrive" }, + { AW_PIN_CAPS_FLAG_CAN_OUTPUT, "CanOutput" }, + { AW_PIN_CAPS_FLAG_CAN_INPUT, "CanInput" }, + { AW_PIN_CAPS_FLAG_BALANCED_IO, "Balanced" }, + { AW_PIN_CAPS_FLAG_HDMI, "HDMI" }, + { AW_PIN_CAPS_FLAG_VREF_HIZ, "VREF_HIZ" }, + { AW_PIN_CAPS_FLAG_VREF_50_PERCENT, "VREF_50%" }, + { AW_PIN_CAPS_FLAG_VREF_GROUND, "VREF_GND" }, + { AW_PIN_CAPS_FLAG_VREF_80_PERCENT, "VREF_80%" }, + { AW_PIN_CAPS_FLAG_VREF_100_PERCENT, "VREF_100%" }, + { AW_PIN_CAPS_FLAG_CAN_EAPD, "EAPD" }, + { AW_PIN_CAPS_FLAG_DISPLAY_PORT, "DisplayPort" }, + { AW_PIN_CAPS_FLAG_HIGH_BIT_RATE, "HighBitRate" }, +}; + +static void cmd_ihda_list_cbk(intel_hda_device_t* dev, void* ctx) { + printf("Device #%d\n", dev->dev_id); +} + +static int cmd_ihda_list(int argc, const cmd_args *argv) { + DEBUG_ASSERT(argc >= 2); + + if (argc != 2) + goto usage; + + printf("Listing currently active Intel HDA Devices...\n"); + intel_hda_foreach(cmd_ihda_list_cbk, NULL); + printf("done\n"); + + return NO_ERROR; + +usage: + printf("usage: %s %s\n", argv[0].str, argv[1].str); + return NO_ERROR; +} + +static int ihda_dump32(const char* name, void* base, size_t offset, bool crlf) { + uint32_t val = pcie_read32((uint32_t*)((intptr_t)base + offset)); + return printf("[%02zx] %10s : %08x (%u)%s", + offset, name, val, val, crlf ? "\n" : ""); +} + +static int ihda_dump24(const char* name, void* base, size_t offset, bool crlf) { + uint32_t val = pcie_read32((uint32_t*)((intptr_t)base + offset)) & 0xFFFFFF; + return printf("[%02zx] %10s : %06x (%u)%s", + offset, name, val, val, crlf ? "\n" : ""); +} + +static int ihda_dump16(const char* name, void* base, size_t offset, bool crlf) { + uint16_t val = pcie_read16((uint16_t*)((intptr_t)base + offset)); + return printf("[%02zx] %10s : %04hx (%hu)%s", + offset, name, val, val, crlf ? "\n" : ""); +} + +static int ihda_dump8(const char* name, void* base, size_t offset, bool crlf) { + uint8_t val = pcie_read8((uint8_t*)((intptr_t)base + offset)); + return printf("[%02zx] %10s : %02x (%u)%s", + offset, name, val, val, crlf ? "\n" : ""); +} + +static void pad(int done, int width) { + if (done < 0) return; + while (done < width) { + printf(" "); + done++; + } +} + +static void ihda_dump_stream_regs(const char* name, + size_t count, + hda_stream_desc_regs_t* regs) { + static const struct { + const char* name; + int (*dump_fn)(const char*, void*, size_t, bool); + size_t offset; + } STREAM_REGS[] = { + { "CTL", ihda_dump24, offsetof(hda_stream_desc_regs_t, ctl) }, + { "STS", ihda_dump8, offsetof(hda_stream_desc_regs_t, sts) }, + { "LPIB", ihda_dump32, offsetof(hda_stream_desc_regs_t, lpib) }, + { "CBL", ihda_dump32, offsetof(hda_stream_desc_regs_t, cbl) }, + { "LVI", ihda_dump16, offsetof(hda_stream_desc_regs_t, lvi) }, + { "FIFOD", ihda_dump16, offsetof(hda_stream_desc_regs_t, fifod) }, + { "FMT", ihda_dump16, offsetof(hda_stream_desc_regs_t, fmt) }, + { "BDPL", ihda_dump32, offsetof(hda_stream_desc_regs_t, bdpl) }, + { "BDPU", ihda_dump32, offsetof(hda_stream_desc_regs_t, bdpu) }, + }; + static const size_t COLUMNS = 4; + static const int COLUMN_WIDTH = 45; + int done; + + for (size_t i = 0; i < count; i += COLUMNS) { + size_t todo = MIN(count - i, COLUMNS); + + printf("\n"); + for (size_t j = 0; j < todo; ++j) { + hda_stream_desc_regs_t* r = regs + i + j; + done = printf("%s %zu/%zu (base vaddr %p)", name, i + j + 1, count, r); + if ((j + 1) < todo) + pad(done, COLUMN_WIDTH); + } + printf("\n"); + + for (size_t reg = 0; reg < countof(STREAM_REGS); ++reg) { + for (size_t j = 0; j < todo; ++j) { + hda_stream_desc_regs_t* r = regs + i + j; + done = STREAM_REGS[reg].dump_fn(STREAM_REGS[reg].name, + r, + STREAM_REGS[reg].offset, + false); + if ((j + 1) < todo) + pad(done, COLUMN_WIDTH); + } + printf("\n"); + } + } +} + +static void ihda_dump_conn_list(intel_hda_widget_t* widget) { + if (!widget->conn_list_len) { + printf("empty\n"); + return; + } + + for (uint i = 0; i < widget->conn_list_len; ++i) { + printf("%s%hu", i ? " " : "", widget->conn_list[i]); + } + + printf("\n"); +} + +static void ihda_dump_amp_caps(intel_hda_codec_amp_caps_t* caps) { + DEBUG_ASSERT(caps); + if (!caps->step_size || !caps->num_steps) { + printf("none\n"); + return; + } else if (caps->num_steps == 1) { + printf("fixed 0 dB gain"); + } else { + static const char* FRAC_LUT[] = { ".00", ".25", ".50", ".75" }; + int start, stop, step; + + step = caps->step_size; + start = -((int)caps->offset) * step; + stop = start + (((int)caps->num_steps - 1) * step); + + printf("[%d%s, %d%s] dB in %d%s dB steps", + start >> 2, FRAC_LUT[start & 0x3], + stop >> 2, FRAC_LUT[stop & 0x3], + step >> 2, FRAC_LUT[step & 0x3]); + } + + printf(" (Can%s mute)\n", caps->can_mute ? "" : "'t"); +} + +static void ihda_dump_delay(uint8_t delay) { + if (delay) + printf("%u samples\n", delay); + else + printf("unknown\n"); +} + +static const char* ihda_get_widget_type_string(uint8_t type_id) { + switch (type_id) { + case AW_TYPE_OUTPUT: return "Audio Output"; + case AW_TYPE_INPUT: return "Audio Input"; + case AW_TYPE_MIXER: return "Audio Mixer"; + case AW_TYPE_SELECTOR: return "Audio Selector"; + case AW_TYPE_PIN_COMPLEX: return "Pin Complex"; + case AW_TYPE_POWER: return "Power Widget"; + case AW_TYPE_VOLUME_KNOB: return "Volume Knob"; + case AW_TYPE_BEEP_GEN: return "Beep Generator"; + case AW_TYPE_VENDOR: return "Vendor"; + default: return "Unknown"; + } +} + +static const char* ihda_get_fn_group_type_string(intel_hda_codec_audio_fn_group_t* fn_group) { + uint8_t type_id = fn_group ? fn_group->fn_group_type : 0x00; + if (type_id >= 0x80) + return "Vendor"; + + switch (type_id) { + case 0x01: return "Audio"; + case 0x02: return "Modem"; + default: return "Unknown"; + } +} + +#define FMT(fmt) "%s%17s : " fmt, widget_pad +static const char* widget_pad = "+----- "; + +static void ihda_dump_widget(intel_hda_codec_audio_fn_group_t* fn_group, uint id) { + DEBUG_ASSERT(fn_group && fn_group->widgets && (id < fn_group->widget_count)); + + intel_hda_widget_t* widget = &fn_group->widgets[id]; + + printf("%sWidget %hu/%hu\n", widget_pad, id + 1, fn_group->widget_count); + printf(FMT("%hu\n"), "Node ID", widget->nid); + printf(FMT("[%02x] %s\n"), "Type", widget->type, ihda_get_widget_type_string(widget->type)); + + printf(FMT(""), "Flags"); + DUMP_FLAGS(widget->raw_caps, AW_CAPS_FLAGS, "", "none"); + + printf(FMT(""), "Delay"); + ihda_dump_delay(widget->delay); + + printf(FMT("%u\n"), "MaxChan", widget->ch_count); + + if (AW_CAPS_INPUT_AMP_PRESENT(widget->raw_caps)) { + printf(FMT(""), "InputAmp"); + ihda_dump_amp_caps(&widget->input_amp_caps); + } + + if (AW_CAPS_OUTPUT_AMP_PRESENT(widget->raw_caps)) { + printf(FMT(""), "OutputAmp"); + ihda_dump_amp_caps(&widget->output_amp_caps); + } + + if (AW_CAPS_FORMAT_OVERRIDE(widget->raw_caps)) { + printf(FMT(""), "PCM Rates"); + DUMP_FLAGS(widget->pcm_size_rate, PCM_RATE_FLAGS, "", "none"); + + printf(FMT(""), "PCM Sizes"); + DUMP_FLAGS(widget->pcm_size_rate, PCM_SIZE_FLAGS, " bits", "none"); + + printf(FMT(""), "PCM Formats"); + DUMP_FLAGS(widget->pcm_formats, PCM_FMT_FLAGS, "", "none"); + } + + if (widget->type == AW_TYPE_PIN_COMPLEX) { + printf(FMT(""), "Pin Caps"); + DUMP_FLAGS(widget->pin_caps, PIN_CAPS_FLAGS, "", "none"); + } + + if (AW_CAPS_HAS_POWER_CTL(widget->raw_caps)) { + printf(FMT(""), "Pwr States"); + DUMP_FLAGS(widget->power_states, POWER_STATE_FLAGS, "", "none"); + } + + if (AW_CAPS_HAS_CONN_LIST(widget->raw_caps)) { + printf(FMT(""), "ConnList"); + ihda_dump_conn_list(widget); + } + + if (AW_CAPS_PROC_WIDGET(widget->raw_caps)) { + printf(FMT("%s\n"), "Can Bypass Proc", widget->can_bypass_processing ? "yes" : "no"); + printf(FMT("%u\n"), "Proc Coefficients", widget->processing_coefficient_count); + } + + if (widget->type == AW_TYPE_VOLUME_KNOB) { + printf(FMT("%s\n"), "Vol Knob Type", widget->vol_knob_is_delta ? "delta" : "absolute"); + printf(FMT("%u\n"), "Vol Knob Steps", widget->vol_knob_steps); + } + + printf("%s\n", widget_pad); +} +#undef FMT + +#define FMT(fmt) "%s%26s : " fmt, pad +static void ihda_dump_codec_fn_group(intel_hda_codec_t* codec, uint id) { + DEBUG_ASSERT(codec && codec->fn_groups && (id < codec->fn_group_count)); + static const char* pad = "+--- "; + intel_hda_codec_audio_fn_group_t* fn_group = codec->fn_groups[id]; + + printf("%sFunction Group %hu/%hu\n", pad, id + 1, codec->fn_group_count); + printf(FMT("%hu\n"), "Node ID", codec->fn_group_starting_id + id); + printf(FMT("%s\n"), "Type", ihda_get_fn_group_type_string(fn_group)); + + if (!fn_group) + return; + + printf(FMT("Can%s send unsolicited responses\n"), "Unsol", fn_group->can_send_unsolicited ? "" : "not"); + printf(FMT("%s\n"), "Beep Gen", fn_group->has_beep_gen ? "yes" : "no"); + + printf(FMT(""), "Input Path Delay"); + ihda_dump_delay(fn_group->path_input_delay); + + printf(FMT(""), "Output Path Delay"); + ihda_dump_delay(fn_group->path_output_delay); + + printf(FMT(""), "Default PCM Rates"); + DUMP_FLAGS(fn_group->default_pcm_size_rate, PCM_RATE_FLAGS, "", "none"); + + printf(FMT(""), "Default PCM Sizes"); + DUMP_FLAGS(fn_group->default_pcm_size_rate, PCM_SIZE_FLAGS, " bits", "none"); + + printf(FMT(""), "Default PCM Formats"); + DUMP_FLAGS(fn_group->default_pcm_formats, PCM_FMT_FLAGS, "", "none"); + + printf(FMT(""), "Default Input Amp Caps"); + ihda_dump_amp_caps(&fn_group->default_input_amp_caps); + + printf(FMT(""), "Default Output Amp Caps"); + ihda_dump_amp_caps(&fn_group->default_output_amp_caps); + + printf(FMT(""), "Supported Power States"); + DUMP_FLAGS(fn_group->power_states, POWER_STATE_FLAGS, "", "none"); + + printf(FMT("%u\n"), "GPIOs", fn_group->gpio_count); + printf(FMT("%u\n"), "GPIs", fn_group->gpi_count); + printf(FMT("%u\n"), "GPOs", fn_group->gpo_count); + printf(FMT("%s\n"), "GPIOs can wake", fn_group->gpio_can_wake ? "yes" : "no"); + printf(FMT("%s\n"), "GPIOs can send unsolicited", + fn_group->gpio_can_send_unsolicited ? "yes" : "no"); + + printf(FMT("%u\n"), "Widgets", fn_group->widget_count); + + for (uint16_t i = 0; i < fn_group->widget_count; ++i) { + ihda_dump_widget(fn_group, i); + } +} +#undef FMT + +#define FMT(fmt) "%s%10s : " fmt, pad +static void ihda_dump_codec(intel_hda_codec_t* codec) { + static const char* pad = "+- "; + + printf(FMT("0x%04hx:0x%04hx\n"), "VID/DID", codec->vendor_id, codec->device_id); + printf(FMT("%u.%u\n"), "Rev", codec->major_rev, codec->minor_rev); + printf(FMT("%u.%u\n"), "Vendor Rev", codec->vendor_rev_id, codec->vendor_stepping_id); + printf("%s%u function group%s\n", + pad, codec->fn_group_count, codec->fn_group_count == 1 ? "" : "s"); + + for (uint16_t i = 0; i < codec->fn_group_count; ++i) { + ihda_dump_codec_fn_group(codec, i); + } +} +#undef FMT + +static void ihda_dump_codecs(intel_hda_device_t* dev) { + /* Note: This is only safe because we do not currently support hot + * unplugging of codecs. Once a codec exists, it cannot cease to exist. + * Neither can any of its function groups, nor their widgets. If/when hot + * unplugging of codecs becomes a thing, this code will need to be + * revisited. + */ + DEBUG_ASSERT(dev); + + /* Count the number of active codecs */ + uint codec_count = 0; + for (size_t i = 0; i < countof(dev->codecs); ++i) + if (dev->codecs[i]) + codec_count++; + + printf("Intel HDA Audio Controller @%02x:%02x.%01x has %u active codec%s\n", + dev->pci_device->common.bus_id, + dev->pci_device->common.dev_id, + dev->pci_device->common.func_id, + codec_count, + codec_count == 1 ? "" : "s"); + + /* Print the header for each active codec, then proceed to dumping the + * function groups */ + uint codec_ndx = 0; + for (size_t i = 0; i < countof(dev->codecs); ++i) { + intel_hda_codec_t* codec = dev->codecs[i]; + + if (codec) { + codec_ndx++; + printf("Codec %u/%u (Codec Address %zu) has %u function group%s\n", + codec_ndx, codec_count, i, codec->fn_group_count, + codec->fn_group_count == 1 ? "" : "s"); + ihda_dump_codec(codec); + } + } +} + +static int cmd_ihda_regs(int argc, const cmd_args *argv) { + DEBUG_ASSERT(argc >= 2); + + long dev_id = 0; + for (int i = 2; i < argc; ++i) { + if (!strcmp("-d", argv[i].str) && (++i < argc)) { + dev_id = argv[i].i; + } else { + goto usage; + } + } + + intel_hda_device_t* dev = intel_hda_acquire(dev_id); + if (dev) { + hda_registers_t* r = dev->regs; + + DEBUG_ASSERT(r); + printf("Registers for Intel HDA Device #%ld (base vaddr %p)\n", dev_id, r); + + ihda_dump16("GCAP", r, offsetof(hda_registers_t, gcap), true); + ihda_dump8 ("VMIN", r, offsetof(hda_registers_t, vmin), true); + ihda_dump8 ("VMAJ", r, offsetof(hda_registers_t, vmaj), true); + ihda_dump16("OUTPAY", r, offsetof(hda_registers_t, outpay), true); + ihda_dump16("INPAY", r, offsetof(hda_registers_t, inpay), true); + ihda_dump32("GCTL", r, offsetof(hda_registers_t, gctl), true); + ihda_dump16("WAKEEN", r, offsetof(hda_registers_t, wakeen), true); + ihda_dump16("STATESTS", r, offsetof(hda_registers_t, statests), true); + ihda_dump16("GSTS", r, offsetof(hda_registers_t, gsts), true); + ihda_dump16("OUTSTRMPAY", r, offsetof(hda_registers_t, outstrmpay), true); + ihda_dump16("INSTRMPAY", r, offsetof(hda_registers_t, instrmpay), true); + ihda_dump32("INTCTL", r, offsetof(hda_registers_t, intctl), true); + ihda_dump32("INTSTS", r, offsetof(hda_registers_t, intsts), true); + ihda_dump32("WALCLK", r, offsetof(hda_registers_t, walclk), true); + ihda_dump32("SSYNC", r, offsetof(hda_registers_t, ssync), true); + ihda_dump32("CORBLBASE", r, offsetof(hda_registers_t, corblbase), true); + ihda_dump32("CORBUBASE", r, offsetof(hda_registers_t, corbubase), true); + ihda_dump16("CORBWP", r, offsetof(hda_registers_t, corbwp), true); + ihda_dump16("CORBRP", r, offsetof(hda_registers_t, corbrp), true); + ihda_dump8 ("CORBCTL", r, offsetof(hda_registers_t, corbctl), true); + ihda_dump8 ("CORBSTS", r, offsetof(hda_registers_t, corbsts), true); + ihda_dump8 ("CORBSIZE", r, offsetof(hda_registers_t, corbsize), true); + ihda_dump32("RIRBLBASE", r, offsetof(hda_registers_t, rirblbase), true); + ihda_dump32("RIRBUBASE", r, offsetof(hda_registers_t, rirbubase), true); + ihda_dump16("RIRBWP", r, offsetof(hda_registers_t, rirbwp), true); + ihda_dump16("RINTCNT", r, offsetof(hda_registers_t, rintcnt), true); + ihda_dump8 ("RIRBCTL", r, offsetof(hda_registers_t, rirbctl), true); + ihda_dump8 ("RIRBSTS", r, offsetof(hda_registers_t, rirbsts), true); + ihda_dump8 ("RIRBSIZE", r, offsetof(hda_registers_t, rirbsize), true); + ihda_dump32("ICOI", r, offsetof(hda_registers_t, icoi), true); + ihda_dump32("ICII", r, offsetof(hda_registers_t, icii), true); + ihda_dump16("ICIS", r, offsetof(hda_registers_t, icis), true); + ihda_dump32("DPIBLBASE", r, offsetof(hda_registers_t, dpiblbase), true); + ihda_dump32("DPIBUBASE", r, offsetof(hda_registers_t, dpibubase), true); + + ihda_dump_stream_regs("Input Stream", dev->input_strm_cnt, dev->input_strm_regs); + ihda_dump_stream_regs("Output Stream", dev->output_strm_cnt, dev->output_strm_regs); + ihda_dump_stream_regs("Bi-dir Stream", dev->bidir_strm_cnt, dev->bidir_strm_regs); + + intel_hda_release(dev); + } else { + printf("Intel HDA Device #%ld not found!\n", dev_id); + } + + return NO_ERROR; + +usage: + printf("usage: %s %s [-d ]\n", argv[0].str, argv[1].str); + return NO_ERROR; +} + +static int cmd_ihda_codecs(int argc, const cmd_args *argv) { + DEBUG_ASSERT(argc >= 2); + + long dev_id = 0; + for (int i = 2; i < argc; ++i) { + if (!strcmp("-d", argv[i].str) && (++i < argc)) { + dev_id = argv[i].i; + } else { + goto usage; + } + } + + intel_hda_device_t* dev = intel_hda_acquire(dev_id); + if (dev) { + ihda_dump_codecs(dev); + intel_hda_release(dev); + } else { + printf("Intel HDA Device #%ld not found!\n", dev_id); + } + + return NO_ERROR; + +usage: + printf("usage: %s %s [-d ]\n", argv[0].str, argv[1].str); + return NO_ERROR; +} + + +static int cmd_ihda(int argc, const cmd_args *argv) +{ + static const struct { + const char* name; + int (*subcmd)(int, const cmd_args*); + } SUBCMDS[] = { + { "list", cmd_ihda_list }, + { "regs", cmd_ihda_regs }, + { "codecs", cmd_ihda_codecs }, + }; + + if (argc >= 2) { + for (size_t i = 0; i < countof(SUBCMDS); ++i) + if (!strcmp(argv[1].str, SUBCMDS[i].name)) + return SUBCMDS[i].subcmd(argc, argv); + } + + printf("usage: %s [args]\n" + "Valid cmds are...\n" + "\thelp : Show this message\n" + "\tlist : List currently active device IDs\n" + "\tregs : Dump the registers for the specified device ID\n" + "\tcodecs : Dump the codec description for the specified device ID\n", + argv[0].str); + + return NO_ERROR; +} + +STATIC_COMMAND_START +STATIC_COMMAND("ihda", + "Low level commands to manipulate Intel High Definition Audio devices", + &cmd_ihda) +STATIC_COMMAND_END(intel_hda_commands); + +#endif // WITH_LIB_CONSOLE diff --git a/kernel/dev/intel_hda/intel_hda.c b/kernel/dev/intel_hda/intel_hda.c new file mode 100644 index 000000000..c13fe81ca --- /dev/null +++ b/kernel/dev/intel_hda/intel_hda.c @@ -0,0 +1,984 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if !WITH_KERNEL_VM +/* TODO(johngro) : Make this work without a VM */ +#error Intel HDA Controller driver depends on the kernel VM module! +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intel_hda.h" + +#define LOCAL_TRACE 0 + +#define INTEL_HDA_VID (0x8086) +#define INTEL_HDA_DID (0x2668) +#define INTEL_HDA_RESET_HOLD_TIME_USEC (100) // Section 5.5.1.2 +#define INTEL_HDA_RESET_TIMEOUT_USEC (1000) // Arbitrary +#define INTEL_HDA_RING_BUF_RESET_TIMEOUT_USEC (1000) // Arbitrary +#define INTEL_HDA_CODEC_DISCOVERY_WAIT_USEC (521) // Section 4.3 +#define INTEL_HDA_WORK_THREAD_NAME "Intel HDA Driver" +#ifndef INTEL_HDA_WORK_THREAD_PRIORITY +#define INTEL_HDA_WORK_THREAD_PRIORITY HIGH_PRIORITY +#endif // INTEL_HDA_WORK_THREAD_PRIORITY + +#ifndef INTEL_HDA_QEMU_QUIRKS +#define INTEL_HDA_QEMU_QUIRKS 0 +#endif // INTEL_HDA_QEMU_QUIRKS + +#define INTEL_HDA_RIRB_RESERVED_RESPONSE_SLOTS (8u) + +static int intel_hda_work_thread(void *arg); +static void intel_hda_module_init(uint level); + +typedef struct intel_hda_module_state { + mutex_t device_list_lock; + struct list_node device_list; + + spin_lock_t pending_work_list_lock; + struct list_node pending_work_list; + + mutex_t work_thread_lock; + event_t work_thread_wakeup; + bool work_thread_quit; + thread_t* work_thread; + + int dev_id_gen; +} intel_hda_module_state_t; + +static intel_hda_module_state_t g_module_state; +LK_INIT_HOOK(intel_hda_init, intel_hda_module_init, LK_INIT_LEVEL_KERNEL); + +static void intel_hda_module_init(uint level) { + intel_hda_module_state_t* mod = &g_module_state; + + mutex_init (&mod->device_list_lock); + list_initialize(&mod->device_list); + + spin_lock_init (&mod->pending_work_list_lock); + list_initialize(&mod->pending_work_list); + + mutex_init (&mod->work_thread_lock); + event_init (&mod->work_thread_wakeup, false, 0); + mod->work_thread_quit = false; + mod->dev_id_gen = 0; + mod->work_thread = thread_create(INTEL_HDA_WORK_THREAD_NAME, + intel_hda_work_thread, + mod, + INTEL_HDA_WORK_THREAD_PRIORITY, + DEFAULT_STACK_SIZE); + DEBUG_ASSERT(mod->work_thread); + thread_resume(mod->work_thread); +} + +static void intel_hda_module_unload(void) { + /* TODO(johngro): finish this someday. Right now, driver modules cannot + * unload, so this is mostly just a comment which the compiler checks and + * the linker drops. In order to even be able to do this properly, we would + * need to be able to dynamically unregister this driver with the PCIe bus + * driver, and make sure that all instances of our devices have been shut + * down before proceeding. + */ + intel_hda_module_state_t* mod = &g_module_state; + DEBUG_ASSERT(list_is_empty(&mod->device_list)); + + /* shutdown the work thread */ + spin_lock_saved_state_t spinlock_state; + spin_lock_irqsave(&mod->pending_work_list_lock, spinlock_state); + mod->work_thread_quit = true; + event_signal(&mod->work_thread_wakeup, true); + spin_unlock_irqrestore(&mod->pending_work_list_lock, spinlock_state); + + int retcode; + status_t res; + res = thread_join(mod->work_thread, &retcode, 10); + if (NO_ERROR != res) { + dprintf(CRITICAL, "Failed to shutdown Intel HDA module work thread (res %d)\n", res); + } +} + +static bool intel_hda_reset(intel_hda_device_t* dev, bool assert) { + hda_registers_t* r = dev->regs; + uint32_t expected; + lk_bigtime_t start; + + if (assert) { + expected = 0; + REG_CLR_BITS(32, r, gctl, HDA_REG_GCTL_HWINIT); + } else { + expected = HDA_REG_GCTL_HWINIT; + REG_SET_BITS(32, r, gctl, HDA_REG_GCTL_HWINIT); + } + + start = current_time_hires(); + while ((REG_RD(32, r, gctl) & HDA_REG_GCTL_HWINIT) != expected) { + if ((current_time_hires() - start) >= INTEL_HDA_RESET_TIMEOUT_USEC) { + LTRACEF("Timeout waiting for device to exit reset\n"); + return false; + } + } + + return true; +} + +static bool intel_hda_do_reset_cycle(intel_hda_device_t* dev) { + if (!intel_hda_reset(dev, true)) + return false; + + spin(INTEL_HDA_RESET_HOLD_TIME_USEC); + + if (!intel_hda_reset(dev, false)) + return false; + + spin(INTEL_HDA_CODEC_DISCOVERY_WAIT_USEC); + + return true; +} + +static inline status_t intel_hda_reset_corbrp(intel_hda_device_t* dev) { + DEBUG_ASSERT(dev); + hda_registers_t* r = dev->regs; + DEBUG_ASSERT(r); + +#if INTEL_HDA_QEMU_QUIRKS + /* See Section 3.3.21 + * + * QEMU does not properly implement the emulated hardware behavior for + * resetting the pretend CORB read pointer. Just write a 0 to the register + * and leave it at that. + */ + REG_WR(16, r, corbrp, 0); +#else + lk_bigtime_t start; + + /* Set the reset bit, wait for the hardware to respond by setting the bit in + * the readback. */ + REG_WR(16, r, corbrp, HDA_REG_CORBRP_RST); + start = current_time_hires(); + while (!(REG_RD(16, r, corbrp) & HDA_REG_CORBRP_RST)) { + if ((current_time_hires() - start) >= INTEL_HDA_RING_BUF_RESET_TIMEOUT_USEC) { + LTRACEF("Timeout waiting for ring buffer reset ack\n"); + return ERR_TIMED_OUT; + } + } + + /* Clear the reset bit, wait for the hardware to respond by clearing the bit + * in the readback. */ + REG_WR(16, r, corbrp, 0); + start = current_time_hires(); + while (REG_RD(16, r, corbrp) & HDA_REG_CORBRP_RST) { + if ((current_time_hires() - start) >= INTEL_HDA_RING_BUF_RESET_TIMEOUT_USEC) { + LTRACEF("Timeout waiting for ring buffer reset clear\n"); + return ERR_TIMED_OUT; + } + } +#endif // INTEL_HDA_QEMU_QUIRKS + + return NO_ERROR; +} + +static inline status_t intel_hda_setup_command_buffer_size(volatile uint8_t* size_reg, + uint* entry_count) { + // Note: this method takes advantage of the fact that the TX and RX ring + // buffer size register bitfield definitions are identical. + uint8_t tmp = REG_RD_ADDR(8, size_reg); + uint8_t cmd; + + if (tmp & HDA_REG_CORBSIZE_CAP_256ENT) { + *entry_count = 256; + cmd = HDA_REG_CORBSIZE_CFG_256ENT; + } else if (tmp & HDA_REG_CORBSIZE_CAP_16ENT) { + *entry_count = 16; + cmd = HDA_REG_CORBSIZE_CFG_16ENT; + } else if (tmp & HDA_REG_CORBSIZE_CAP_2ENT) { + *entry_count = 2; + cmd = HDA_REG_CORBSIZE_CFG_2ENT; + } else { + LTRACEF("Invalid ring buffer capabilities! (0x%02x @ %p)\n", tmp, size_reg); + return ERR_NOT_VALID; + } + + REG_WR_ADDR(8, size_reg, cmd); + return NO_ERROR; +} + +static status_t intel_hda_setup_command_buffers(intel_hda_device_t* dev) { + status_t ret; + DEBUG_ASSERT(dev); + hda_registers_t* r = dev->regs; + DEBUG_ASSERT(r); + + /* Start by making sure that the output and response ring buffers are being + * held in the stopped state */ + REG_WR(8, r, corbctl, 0); + REG_WR(8, r, rirbctl, 0); + + /* Reset the read and write pointers for both ring buffers */ + REG_WR(16, r, corbwp, 0); + ret = intel_hda_reset_corbrp(dev); + if (ret != NO_ERROR) + return ret; + + /* Note; the HW does not expose a Response Input Ring Buffer Read Pointer, + * we have to maintain our own. */ + dev->rirb_rd_ptr = 0; + REG_WR(16, r, rirbwp, HDA_REG_RIRBWP_RST); + + /* Grab a page from the physical memory manager. + * + * TODO(johngro) : Depending on the architechture we are running on, and + * snoop capabilities of this device, we might want to make sure that the + * command buffer memory is mapped with an uncached policy in the MMU. This + * will need to be dealt with more formally as we migrate to Magenta and + * start to run more on non-emulated hardware with actual cache HW. */ + if (pmm_alloc_pages(1, PMM_ALLOC_FLAG_ANY, &dev->codec_cmd_buf_pages) != 1) + return ERR_NO_MEMORY; + + /* Determine the ring buffer sizes. If there are options, make them as + * large as possible. Even the largest buffers permissible should fit within + * a single 4k page. */ + static_assert(PAGE_SIZE >= (HDA_CORB_MAX_BYTES + HDA_RIRB_MAX_BYTES)); + + ret = intel_hda_setup_command_buffer_size(&r->corbsize, &dev->corb_entry_count); + if (ret != NO_ERROR) + return ret; + + ret = intel_hda_setup_command_buffer_size(&r->rirbsize, &dev->rirb_entry_count); + if (ret != NO_ERROR) + return ret; + + /* Stash these so we don't have to constantly recalculate then */ + dev->corb_mask = dev->corb_entry_count - 1; + dev->rirb_mask = dev->rirb_entry_count - 1; + dev->corb_max_in_flight = dev->rirb_mask > INTEL_HDA_RIRB_RESERVED_RESPONSE_SLOTS + ? dev->rirb_mask - INTEL_HDA_RIRB_RESERVED_RESPONSE_SLOTS + : 1; + dev->corb_max_in_flight = MIN(dev->corb_max_in_flight, dev->corb_mask); + + /* Program the base address registers for the TX/RX ring buffers, and set up the virtual + * pointers to the ring buffer entries */ + paddr_t cmd_buf_paddr; + uintptr_t cmd_buf_vaddr; + uint64_t cmd_buf_paddr_64; + + vm_page_t* page = containerof(list_peek_head(&dev->codec_cmd_buf_pages), vm_page_t, node); + cmd_buf_paddr = vm_page_to_paddr(page); + cmd_buf_vaddr = (uintptr_t)paddr_to_kvaddr(cmd_buf_paddr); + cmd_buf_paddr_64 = (uint64_t)cmd_buf_paddr; + + /* TODO(johngro) : If the controller does not support 64 bit phys + * addressing, we need to make sure to get a page from low memory to use for + * our command buffers. */ + bool gcap_64bit_ok = (REG_RD(16, r, gcap) & HDA_REG_GCAP_64OK) != 0; + if ((cmd_buf_paddr_64 >> 32) && !gcap_64bit_ok) { + LTRACEF("Intel HDA controller does not support 64-bit physical addressing!\n"); + return ERR_NOT_SUPPORTED; + } + + /* Section 4.4.1.1; corb ring buffer base address must be 128 byte aligned. */ + DEBUG_ASSERT(!(cmd_buf_paddr_64 & 0x7F)); + REG_WR(32, r, corblbase, ((uint32_t)(cmd_buf_paddr_64 & 0xFFFFFFFF))); + REG_WR(32, r, corbubase, ((uint32_t)(cmd_buf_paddr_64 >> 32))); + dev->corb = (hda_corb_entry_t*)cmd_buf_vaddr; + + cmd_buf_paddr_64 += HDA_CORB_MAX_BYTES; + cmd_buf_vaddr += HDA_CORB_MAX_BYTES; + + /* Section 4.4.2.2; rirb ring buffer base address must be 128 byte aligned. */ + DEBUG_ASSERT(!(cmd_buf_paddr_64 & 0x7F)); + REG_WR(32, r, rirblbase, ((uint32_t)(cmd_buf_paddr_64 & 0xFFFFFFFF))); + REG_WR(32, r, rirbubase, ((uint32_t)(cmd_buf_paddr_64 >> 32))); + dev->rirb = (hda_rirb_entry_t*)cmd_buf_vaddr; + + /* Set the response interrupt count threshold. The RIRB IRQ will fire any + * time all of the SDATA_IN lines stop having codec responses to transmit, + * or when RINTCNT responses have been received, whichever happens + * first. We would like to batch up responses to minimize IRQ load, but we + * also need to make sure to... + * 1) Not configure the threshold to be larger than the available space in + * the ring buffer. + * 2) Reserve some space (if we can) at the end of the ring buffer so the + * hardware has space to write while we are servicing our IRQ. If we + * reserve no space, then the ring buffer is going to fill up and + * potentially overflow before we can get in there and process responses. + */ + uint16_t thresh = dev->rirb_entry_count - 1; + if (thresh > INTEL_HDA_RIRB_RESERVED_RESPONSE_SLOTS) + thresh -= INTEL_HDA_RIRB_RESERVED_RESPONSE_SLOTS; + DEBUG_ASSERT(thresh); + REG_WR(16, r, rintcnt, thresh); + + /* Clear out any lingering interrupt status */ + REG_WR(8, r, corbsts, HDA_REG_CORBSTS_MEI); + REG_WR(8, r, rirbsts, HDA_REG_RIRBSTS_INTFL | HDA_REG_RIRBSTS_OIS); + + /* Enable the TX/RX IRQs and DMA engines. */ + REG_WR(8, r, corbctl, HDA_REG_CORBCTL_MEIE | HDA_REG_CORBCTL_DMA_EN); + REG_WR(8, r, rirbctl, HDA_REG_RIRBCTL_INTCTL | HDA_REG_RIRBCTL_DMA_EN | HDA_REG_RIRBCTL_OIC); + + return NO_ERROR; +} + +static void intel_hda_activate_device(intel_hda_device_t* dev) { + intel_hda_module_state_t* mod = &g_module_state; + mutex_acquire(&mod->device_list_lock); + list_add_tail(&mod->device_list, &dev->device_list_node); + mutex_release(&mod->device_list_lock); +} + +static void intel_hda_deactivate_device(intel_hda_device_t* dev) { + intel_hda_module_state_t* mod = &g_module_state; + + /* If we are in the list of active devices, remove ourselves. We are no + * longer active. */ + mutex_acquire(&mod->device_list_lock); + if (list_in_list(&dev->device_list_node)) + list_delete(&dev->device_list_node); + mutex_release(&mod->device_list_lock); + + /* Block the hardware from directly accessing main system memory */ + pcie_enable_bus_master(dev->pci_device, false); + + /* TODO(johngro): Disengage from and synchronize with any upward facing API + * layers we are currently registered with. */ + + /* Shut off our IRQ at the PCIe level and synchronize with the PCIe bus + * driver's IRQ dispatcher. After this point, we are certain that we can no + * longer be added to the pending work list by the IRQ handler. */ + pcie_set_irq_mode_disabled(&dev->pci_device->common); + + /* Purge ourselves from the pending work list if we are currently on it. + * Keep track of whether or not we were on the pending work list. If we + * were, then we know that the work thread was not servicing us when we + * removed ourselves, therefor there is no reason to synchronize with the + * work thread.*/ + spin_lock_saved_state_t spinlock_state; + bool was_pending; + + spin_lock_irqsave(&mod->pending_work_list_lock, spinlock_state); + was_pending = list_in_list(&dev->pending_work_list_node); + if (was_pending) + list_delete(&dev->pending_work_list_node); + spin_unlock_irqrestore(&mod->pending_work_list_lock, spinlock_state); + + /* If we were not in the pending work list, then there is a chance that the + * work thread is servicing our device right now. Bouncing through the work + * thread mutex will ensure that the work thread is finished with any job + * it's currently processing. + */ + if (!was_pending) { + mutex_acquire(&mod->work_thread_lock); + mutex_release(&mod->work_thread_lock); + } + + /* Finished. We are now certain that we have cleanly disengaged from any + * executional context which may have been aware of us when we started to + * de-active. + */ +} + +pcie_irq_handler_retval_t intel_hda_pci_irq_handler(struct pcie_common_state* pci_device, + uint irq_id, + void* ctx) { + DEBUG_ASSERT(pci_device && ctx); + intel_hda_module_state_t* mod = &g_module_state; + intel_hda_device_t* dev = (intel_hda_device_t*)ctx; + hda_registers_t* r = dev->regs; + + /* start by shutting off our interrupt at the top level of the device's + * interrupt tree. We will re-enable it once the work thread is finished + * servicing us. */ + DEBUG_ASSERT(r); + REG_CLR_BITS(32, r, intctl, HDA_REG_INTCTL_GIE); + + /* Add this device to the work thread's pending work list, and make certain + * that it is signalled to wake up. If the pending work list was not + * already empty, then we should be able to assert that the thread is + * currently being signalled and that there is no need to force an immediate + * reschedule. If we just went from 0 devices to 1 device on the pending + * work list, we need to make sure to wake up the work thread and request a + * resched. */ + bool need_resched; + spin_lock(&mod->pending_work_list_lock); + + DEBUG_ASSERT(!list_in_list(&dev->pending_work_list_node)); + need_resched = list_is_empty(&mod->pending_work_list); + list_add_tail(&mod->pending_work_list, &dev->pending_work_list_node); + if (need_resched) + event_signal(&mod->work_thread_wakeup, false); + + spin_unlock(&mod->pending_work_list_lock); + + return need_resched ? PCIE_IRQRET_RESCHED : PCIE_IRQRET_NO_ACTION; +} + +static status_t intel_hda_pci_startup(struct pcie_device_state* pci_device) { + DEBUG_ASSERT(pci_device && pci_device->driver_ctx); + intel_hda_device_t* dev = (intel_hda_device_t*)(pci_device->driver_ctx); + hda_registers_t* r = NULL; + status_t ret = ERR_GENERIC; + + DEBUG_ASSERT(dev->pci_device == pci_device); + LTRACEF("Starting %s @ %02x:%02x.%01x\n", + pcie_driver_name(pci_device->driver), + pci_device->common.bus_id, + pci_device->common.dev_id, + pci_device->common.func_id); + + /* Fetch the information about where our registers have been mapped for us, + * then sanity check. */ + const pcie_bar_info_t* info = pcie_get_device_bar_info(pci_device, 0); + if (!info || !info->is_allocated || !info->is_mmio) { + TRACEF("Failed to fetch base address register info!\n"); + ret = ERR_BAD_STATE; + goto finished; + } + + if (sizeof(hda_all_registers_t) != info->size) { + TRACEF("Unexpected register window size! (Got %llu; expected %zu)\n", + info->size, sizeof(hda_all_registers_t)); + ret = ERR_NOT_VALID; + goto finished; + } + + /* Map in the device registers */ + vmm_aspace_t *aspace = vmm_get_kernel_aspace(); + DEBUG_ASSERT(aspace); + ret = vmm_alloc_physical(aspace, + "iHDA_reg", + info->size, + (void**)&r, + PAGE_SIZE_SHIFT, + info->bus_addr, + 0, + ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + + if (ret != NO_ERROR) { + TRACEF("Failed to map register window (0x%llx @ 0x%llx) Status = %d\n", + info->size, info->bus_addr, ret); + goto finished; + } + DEBUG_ASSERT(r); + + dev->regs = r; + pcie_enable_mmio(pci_device, true); + + /* Check our hardware version */ + uint8_t major = pcie_read8(&r->vmaj); + uint8_t minor = pcie_read8(&r->vmin); + + if ((1 != major) || (0 != minor)) { + TRACEF("Unexpected HW revision %d.%d!\n", major, minor); + ret = ERR_NOT_VALID; + goto finished; + } + + /* setup our pointers to our stream descriptor registers */ + uint16_t gcap = pcie_read16(&r->gcap); + dev->input_strm_cnt = HDA_REG_GCAP_ISS(gcap); + dev->output_strm_cnt = HDA_REG_GCAP_OSS(gcap); + dev->bidir_strm_cnt = HDA_REG_GCAP_BSS(gcap); + + if ((dev->input_strm_cnt + + dev->output_strm_cnt + + dev->bidir_strm_cnt) > countof(r->stream_desc)) { + TRACEF("Invalid stream counts in GCAP register (In %zu Out %zu Bidir %zu; Max %zu)\n", + dev->input_strm_cnt, + dev->output_strm_cnt, + dev->bidir_strm_cnt, + countof(r->stream_desc)); + ret = ERR_NOT_VALID; + goto finished; + } + + if (dev->input_strm_cnt) + dev->input_strm_regs = r->stream_desc; + + if (dev->output_strm_cnt) + dev->output_strm_regs = r->stream_desc + dev->input_strm_cnt; + + if (dev->bidir_strm_cnt) + dev->bidir_strm_regs = r->stream_desc + dev->input_strm_cnt + dev->output_strm_cnt; + + /* TODO(johngro) : figure out the proper behavior here. + * + * So, there are a few confusing things which it would be good to clear up + * surrounding the issue of the reset sequence involving what the spec says, + * observed QEMU virtual Intel HDA behavior, and actual Intel HDA controller + * behavior. Note: At the time of writing this, actual Intel HDA controller + * behavior has not been observed. + * + * What the spec says: + * 1) Register writes will have no effect while controller reset (CRST) is + * asserted (GCTL[0] == 0). See section 4.2.2 + * 2) Among other things, asserting CRST will cause the physical link RST# + * line to become asserted. See section 5.5.1 + * 3) The controller begins the process of codec address asssignment and + * initialization in response to a codec initialization request. + * Ignoring hotplug events, codecs must request initialization within 25 + * frame syncs (521 uSec) of the deassertion of RST#. See seciton + * 5.5.1.2. + * 4) After successfully assigning an address to a codec, the relevant bit + * in the STATESTS register will be set to indicate a codec state change + * event. See Section 4.3 + * 5) Bits in the WAKEEN and STATESTS registers are preserved across both + * low power states and reset. WAKEEN bits must be set to a proper + * value, and STATESTS bits must be cleared following a reset operation. + * See section 4.2.2 + * + * Already, there is a race condition issue here. The host cannot clear + * STATESTS bits until after CRST has been de-asserted. After CRST has been + * de-asserted, the controller will listen for codec initialization requests + * and set bits in the STATESTS register. If... + * + * 1) Host releases CRST + * 2) Codec is assigned and address and STATESTS[x] is set. + * 3) Host clears the contents of STATESTS. + * + * Then the host will miss the presence of the codec in the system. + * + * To make things more confusing, the behavior of the QEMU virtual Intel HDA + * controller does not seem to obey the spec. In particular... + * + * 1) Writes used to clear bits STATESTS have an effect while CRST is + * asserted. This contradicts Spec(1) above. + * 2) Virtual codecs appear in the STATESTS register when CRST is asserted. + * Specifically, they appear when a 0 is written to CRST, regardless of + * whether or not CRST was already asserted. This contradicts Spec(3-4) + * above. + * 3) Virtual codecs do not appear in the STATESTS register when CRST is + * de-asserted. This also contradicts Spec(3-4) above. + * + * What actual hardware does is currently unclear. For now, the following + * behavior is implemented at startup in order to work around the apparent + * race condition in the spec, as well as the apparent spec violation of the + * QEMU virtual Intel HDA controller. + * + * 1) A full reset cycle is conducted, including the 521 uSec wait for codec + * enumeration and address assignment. At this point, regardless of the + * initial state of STATESTS and whether or not this is a real or virtual + * controller, codecs present in the system should have their STATESTS + * bits properly set. + * 2) WAKEEN and STATESTS are cleared. Disregarding hot-plug for the moment, + * we should be certain that there are no codecs reported in the STATESTS + * register. + * 3) Another full reset cycle is conducted. As there were no "ghost" + * codecs present at the start of this operation, the only codecs we + * should see at the end of the operation should be codecs actually + * connected to the system (virtual or otherwise). + */ + intel_hda_do_reset_cycle(dev); + REG_CLR_BITS(16, r, wakeen, 0x7FFF); + REG_WR (16, r, statests, 0x7FFF); + intel_hda_do_reset_cycle(dev); + + /* Setup the codec command and control transmit and receive buffers. */ + ret = intel_hda_setup_command_buffers(dev); + if (ret != NO_ERROR) + goto finished; + + /* Allow the device to act as a bus master */ + pcie_enable_bus_master(dev->pci_device, true); + + /* Add ourselves to the list of active devices */ + intel_hda_activate_device(dev); + + /* Select our IRQ mode and register our handler. Try to use MSI, but if we + * can't, fall back on legacy. */ + ret = pcie_set_irq_mode(&pci_device->common, + PCIE_IRQ_MODE_MSI, + 1, + PCIE_IRQ_SHARE_MODE_EXCLUSIVE); + + if (ret != NO_ERROR) { + TRACEF("Failed to configure PCIe device for MSI IRQ mode (err = %d), " + "falling back on Legacy mode\n", ret); + + ret = pcie_set_irq_mode(&pci_device->common, + PCIE_IRQ_MODE_LEGACY, + 1, + PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED); + + if (ret != NO_ERROR) { + TRACEF("Failed to configure PCIe device for Legacy IRQ mode (err = %d)\n", ret); + goto finished; + } + } + + /* Register our handler; if the mode we are operating in does not support + * masking, we might start to receive interrupts as soon as we register. */ + ret = pcie_register_irq_handler(&pci_device->common, 0, intel_hda_pci_irq_handler, dev); + if (ret != NO_ERROR) { + TRACEF("Failed to register IRQ handler (err = %d)\n", ret); + goto finished; + } + + ret = pcie_unmask_irq(&pci_device->common, 0); + if (ret != NO_ERROR) { + TRACEF("Failed to unmask IRQ (err = %d)\n", ret); + goto finished; + } + + /* Enable the controller IRQ, and unmask all of the codec wake IRQs in order + * to start the process of codec discovery. */ + REG_SET_BITS(16, r, wakeen, 0x7FFF); + REG_SET_BITS(32, r, intctl, (HDA_REG_INTCTL_GIE | HDA_REG_INTCTL_CIE)); + + ret = NO_ERROR; + +finished: + if (ret != NO_ERROR) { + /* Something went wrong. Shutdown is not going to get called, so make + * sure that we have undone any partially completed startup tasks. */ + intel_hda_deactivate_device(dev); + + if (r) { + REG_WR(32, r, intctl, 0); // Dissable all interrupts + intel_hda_reset(dev, true); // Place the device into reset + } + } + + return ret; +} + +static void intel_hda_pci_shutdown(struct pcie_device_state* pci_device) { + DEBUG_ASSERT(pci_device && pci_device->driver_ctx); + intel_hda_device_t* dev = (intel_hda_device_t*)(pci_device->driver_ctx); + hda_registers_t* r = dev->regs; + + LTRACEF("Shutting down %s @ %02x:%02x.%01x\n", + pcie_driver_name(pci_device->driver), + pci_device->common.bus_id, + pci_device->common.dev_id, + pci_device->common.func_id); + + /* Deactivate the device. This will ensure that... + * + * 1) Our IRQ is disabled at the PCIe level. + * 2) No PCIe IRQ dispatches for this device are currently in flight. + * 3) No work for this device is either scheduled or currently being performed by the module's + * work thread. + * 4) The device no longer exists on the module's list of active devices. + */ + intel_hda_deactivate_device(dev); + + /* Shut down all interrupt sources in the device's interrupt tree. Clear out any sticky pending + * interrupt status bits. */ + REG_WR (32, r, intctl, 0x0); + REG_CLR_BITS(16, r, wakeen, 0x7FFF); + REG_WR (16, r, statests, 0x7FFF); + /* TODO(johngro): shut down all stream IRQs as well */ + + /* Place the device into reset */ + intel_hda_reset(dev, true); +} + +static void intel_hda_pci_release(struct pcie_device_state* pci_device) { + DEBUG_ASSERT(pci_device && pci_device->driver_ctx); + intel_hda_device_t* dev = (intel_hda_device_t*)(pci_device->driver_ctx); + + dev->pci_device = NULL; + + DEBUG_ASSERT(!list_in_list(&dev->device_list_node)); + intel_hda_release(dev); +} + +void intel_hda_work_thread_service_device(intel_hda_device_t* dev) { + /* Note: the module's work thread lock is being held at the moment. */ + DEBUG_ASSERT(dev && dev->regs); + hda_registers_t* r = dev->regs; + + /* Read the top level interrupt status and figure out what we are supposed + * to be doing. */ + uint32_t intctl = REG_RD(32, r, intctl); + uint32_t intsts = REG_RD(32, r, intsts) & intctl; + + /* If the global interrupt enable bit is set, then something is seriously + * wrong. The IRQ handler was supposed to have turned it off. */ + DEBUG_ASSERT(!(intctl & HDA_REG_INTCTL_GIE)); + + /* Take a snapshot of any pending responses ASAP in order to minimize the + * chance of an RIRB overflow. We will process the responses which we + * snapshot-ed in a short while after we are done handling other important + * IRQ tasks. */ + intel_hda_codec_snapshot_rirb(dev); + + /* Set up the CORB bookkeeping for this cycle before we start to create + * codecs and dispatch responses */ + intel_hda_codec_snapshot_corb(dev); + + /* Do we have a pending controller interrupt? If so, something has either + * changed with current codec status, or something is going on with the + * command ring buffers. Figure out what is going on and take care of it. + */ + if (intsts & HDA_REG_INTCTL_CIE) { + intsts &= ~HDA_REG_INTCTL_CIE; + + /* Read and ack the pending state interrupts */ + uint16_t statests = REG_RD(16, r, statests); + REG_WR(16, r, statests, statests); + + /* Take care of each codec which has delivered a wake interrupt */ + for (size_t codec_ndx = 0; + statests && (codec_ndx < countof(dev->codecs)); + codec_ndx++, statests >>= 1) { + /* TODO(johngro) : Right now, we do not deal with hotplugging or + * sleep/wake. The only codec interrupts we should be receiving + * should be during initial codec enumeration. If we receive an IRQ + * for a codec we have already discovered, it's probably an unplug + * event. Log a warning, but ignore the IRQ. + */ + if (dev->codecs[codec_ndx]) { + dprintf(INFO, "Received wake IRQ for a codec (id %zu) we already know about!\n", + codec_ndx); + continue; + } + + dev->codecs[codec_ndx] = intel_hda_create_codec(dev, (uint8_t)codec_ndx); + if (!dev->codecs[codec_ndx]) { + dprintf(CRITICAL, + "Failed to allocate control structure for codec (id %zu). Codec will be " + "non-functional\n", + codec_ndx); + } + } + + /* Check IRQ status for the two command ring buffers */ + uint8_t corbsts = REG_RD(8, r, corbsts); + uint8_t rirbsts = REG_RD(8, r, rirbsts); + + if (corbsts & HDA_REG_CORBSTS_MEI) { + /* TODO(johngro) : Implement proper controller reset behavior. + * + * The MEI bit in CORBSTS indicates some form memory error detected + * by the controller while attempting to read from system memory. + * This is Extremely Bad and should never happen. If it does, the + * TRM suggests that all bets are off, and the only reasonable + * action is to completely shutdown and reset the controller. + * + * Right now, we do not implement this behavior. Instead we log, + * then assert in debug builds. In release builds, we simply ack + * the interrupt and move on. + */ + dprintf(CRITICAL, + "CRITICAL ERROR: controller encountered an unrecoverable " + "error attempting to read from system memory!\n"); + DEBUG_ASSERT(false); + } + + if (rirbsts & HDA_REG_RIRBSTS_OIS) { + /* TODO(johngro) : Implement retry behavior for codec command and + * control. + * + * The OIS bit in the RIRBSTS register indicates that hardware has + * encountered a overrun while attempting to write to the Response + * Input Ring Buffer. IOW - responses were received, but the + * controller was unable to write to system memory in time, and some + * of the responses were lost. This should *really* never happen. + * If it does, all bets are pretty much off. Every command verb + * sent is supposed to receive a response from the codecs; if a + * response is dropped it can easily wedge a codec's command and + * control state machine. + * + * This problem is not limited to HW being unable to write to system + * memory in time. There is no HW read pointer for the RIRB. The + * implication of this is that HW has no way to know that it has + * overrun SW if SW is not keeping up. If this was to happen, there + * would be no way for the system to know, it would just look like a + * large number of responses were lost. + * + * In either case, the only mitigation we could possibly implement + * would be a reasonable retry system at the codec driver level. + * + * Right now, we just log the error, ack the IRQ and move on. + */ + dprintf(CRITICAL, + "CRITICAL ERROR: controller overrun detected while " + "attempting to write to response input ring buffer.\n"); + } + + /* Ack the command ring buffer IRQs. No need to have an explicit + * handler for RIRB:INTFL, we are going to process any pending codec + * responses no matter what. */ + REG_WR(8, r, corbsts, corbsts); + REG_WR(8, r, rirbsts, rirbsts); + } + + /* Process any snapshot-ed codec responses */ + intel_hda_codec_process_rirb(dev); + + /* Give any codecs who have pending work a chance to talk on the link. */ + intel_hda_codec_process_pending_work(dev); + + /* Commit any commands which were queued by codecs during this cycle */ + intel_hda_codec_commit_corb(dev); + + /* Currently, we have not support for streams or stream interrupts. If we + * have a pending unmasked stream interrupt, something is seriously wrong. + */ + DEBUG_ASSERT(!intsts); + + /* Turn interrupts back on at the global level. */ + REG_SET_BITS(32, r, intctl, HDA_REG_INTCTL_GIE); +} + +static int intel_hda_work_thread(void *arg) { + intel_hda_module_state_t* mod = &g_module_state; + + LTRACEF("Work thread started\n"); + + do { + event_wait(&mod->work_thread_wakeup); + if (mod->work_thread_quit) + break; + + /* Process devices which the hard IRQ handler has posted to us until we + * either run out of devices to process, or until it is time to shut + * down. + */ + while (!mod->work_thread_quit) { + struct list_node* pending_device; + spin_lock_saved_state_t spinlock_state; + spin_lock_irqsave(&mod->pending_work_list_lock, spinlock_state); + + /* Stop processing if we have run out of work */ + if (list_is_empty(&mod->pending_work_list)) { + event_unsignal(&mod->work_thread_wakeup); + spin_unlock_irqrestore(&mod->pending_work_list_lock, spinlock_state); + break; + } + + /* Grab the first device which needs service, then exchange the + * pending work spinlock for the work thread lock and service the + * device. + * + * Note: this lock exchange feels dangerous, but is required to + * ensure that devices can properly synchronized against the IRQ + * handler and the work thread during shutdown. It is safe because + * no other entity in the system ever attempts to hold both the + * pending work list spinlock at the same time as holding the work + * thread lock. + */ + pending_device = list_remove_head(&mod->pending_work_list); + mutex_acquire(&mod->work_thread_lock); + spin_unlock_irqrestore(&mod->pending_work_list_lock, spinlock_state); + + intel_hda_work_thread_service_device(containerof(pending_device, + intel_hda_device_t, + pending_work_list_node)); + + mutex_release(&mod->work_thread_lock); + } + } while (!mod->work_thread_quit); + + LTRACEF("Work thread finished\n"); + return 0; +} + +static void* intel_hda_pci_probe(struct pcie_device_state* pci_device) { + DEBUG_ASSERT(pci_device); + intel_hda_module_state_t* mod = &g_module_state; + + if ((pci_device->common.vendor_id != INTEL_HDA_VID) || + (pci_device->common.device_id != INTEL_HDA_DID)) { + return NULL; + } + + /* Allocate our device state */ + intel_hda_device_t* dev = (intel_hda_device_t*)calloc(1, sizeof(intel_hda_device_t)); + if (!dev) { + LTRACEF("Failed to allocate %zu bytes for Intel HDA device\n", sizeof(intel_hda_device_t)); + return NULL; + } + + /* Initialize our device state. */ + dev->ref_count = 1; // The PCI bus will be holding the first ref on us + dev->dev_id = atomic_add(&mod->dev_id_gen, 1); // Generate a unique device ID + dev->pci_device = pci_device; + list_initialize(&dev->codec_cmd_buf_pages); // command buffer page list starts as empty + + /* Note: no need to explicitly initialize these list node members. calloc + * has done this for us already. */ + // list_clear_node(dev->device_list_node); + // list_clear_node(dev->pending_work_list_node); + + /* Return a pointer to our device state in order to claim this device as ours */ + return dev; +} + +void intel_hda_foreach(intel_hda_foreach_cbk cbk, void* ctx) { + if (!cbk) return; + + intel_hda_module_state_t* mod = &g_module_state; + mutex_acquire(&mod->device_list_lock); + + intel_hda_device_t* dev; + list_for_every_entry(&mod->device_list, dev, intel_hda_device_t, device_list_node) { + cbk(dev, ctx); + } + + mutex_release(&mod->device_list_lock); +} + +intel_hda_device_t* intel_hda_acquire(int dev_id) { + intel_hda_module_state_t* mod = &g_module_state; + intel_hda_device_t* ret = NULL; + + mutex_acquire(&mod->device_list_lock); + + intel_hda_device_t* dev; + list_for_every_entry(&mod->device_list, dev, intel_hda_device_t, device_list_node) { + DEBUG_ASSERT(dev->ref_count > 0); + if (dev_id == dev->dev_id) { + ret = dev; + atomic_add(&ret->ref_count, 1); + break; + } + } + + mutex_release(&mod->device_list_lock); + return ret; +} + +void intel_hda_release(intel_hda_device_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->ref_count > 0); + + if (atomic_add(&dev->ref_count, -1) == 1) { + for (size_t i = 0; i < countof(dev->codecs); ++i) { + intel_hda_destroy_codec(dev->codecs[i]); + dev->codecs[i] = NULL; + } + + if (!list_is_empty(&dev->codec_cmd_buf_pages)) + pmm_free(&dev->codec_cmd_buf_pages); + + free(dev); + } +} + + +static const pcie_driver_fn_table_t INTEL_HDA_FN_TABLE = { + .pcie_probe_fn = intel_hda_pci_probe, + .pcie_startup_fn = intel_hda_pci_startup, + .pcie_shutdown_fn = intel_hda_pci_shutdown, + .pcie_release_fn = intel_hda_pci_release, +}; + +STATIC_PCIE_DRIVER(intel_hda, "Intel HD Audio", INTEL_HDA_FN_TABLE) diff --git a/kernel/dev/intel_hda/intel_hda.h b/kernel/dev/intel_hda/intel_hda.h new file mode 100644 index 000000000..481558007 --- /dev/null +++ b/kernel/dev/intel_hda/intel_hda.h @@ -0,0 +1,84 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +#include "codec.h" +#include "registers.h" + +__BEGIN_CDECLS + +typedef struct intel_hda_device { + struct list_node device_list_node; + struct list_node pending_work_list_node; + int ref_count; + int dev_id; + pcie_device_state_t* pci_device; + + /* Mapped registers */ + hda_registers_t* regs; + hda_stream_desc_regs_t* input_strm_regs; + hda_stream_desc_regs_t* output_strm_regs; + hda_stream_desc_regs_t* bidir_strm_regs; + size_t input_strm_cnt; + size_t output_strm_cnt; + size_t bidir_strm_cnt; + + /* Codec Command TX/RX queue state. */ + struct list_node codec_cmd_buf_pages; + + hda_corb_entry_t* corb; + uint corb_entry_count; + uint corb_mask; + uint corb_wr_ptr; + uint corb_snapshot_space; + uint corb_max_in_flight; + + hda_rirb_entry_t* rirb; + uint rirb_entry_count; + uint rirb_mask; + uint rirb_rd_ptr; + uint rirb_snapshot_cnt; + hda_rirb_entry_t rirb_snapshot[HDA_RIRB_MAX_ENTRIES]; + + /* Codec State */ + intel_hda_codec_t* codecs[INTEL_HDA_MAX_CODECS]; +} intel_hda_device_t; + +/** + * Callback used when iterating the list of active Intel HDA audio devices. + */ +typedef void (*intel_hda_foreach_cbk)(intel_hda_device_t* dev, void* ctx); + +/** + * Iterate over the current list of Intel HDA audio devices calling 'cbk' (and + * supplying ctx in the process) once for each active device. + * + * @note Use with caution! A module-wide lock is being held during your + * callback! This method is mostly for the debug console to be able to list the + * devices which are currently plugged in. + */ +void intel_hda_foreach(intel_hda_foreach_cbk cbk, void* ctx); + +/** + * Grab a reference and return a pointer to the Intel HDA device with the given + * device ID. intel_hda_release MUST be called to release the device reference + * when finished. + */ +intel_hda_device_t* intel_hda_acquire(int dev_id); + +/** + * Release the reference for a device which was acquired using + * intel_hda_acquire. + */ +void intel_hda_release(intel_hda_device_t* dev); + +__END_CDECLS diff --git a/kernel/dev/intel_hda/registers.h b/kernel/dev/intel_hda/registers.h new file mode 100644 index 000000000..3c79a44d4 --- /dev/null +++ b/kernel/dev/intel_hda/registers.h @@ -0,0 +1,203 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +/* Macros used for common register manipulation operations */ +#define REG_MOD(reg_width, reg_base, reg_name, mask, val) \ + pcie_write##reg_width(®_base->reg_name, \ + (pcie_read##reg_width(®_base->reg_name) \ + & ((uint##reg_width##_t)(mask))) \ + | ((uint##reg_width##_t)(val))); +#define REG_SET_BITS(reg_width, reg_base, reg_name, bits) \ + REG_MOD(reg_width, reg_base, reg_name, ~bits, bits) +#define REG_CLR_BITS(reg_width, reg_base, reg_name, bits) \ + REG_MOD(reg_width, reg_base, reg_name, ~bits, 0) +#define REG_RD(reg_width, reg_base, reg_name) pcie_read##reg_width(®_base->reg_name) +#define REG_WR(reg_width, reg_base, reg_name, val) pcie_write##reg_width(®_base->reg_name, val) +#define REG_RD_ADDR(reg_width, reg_addr) pcie_read##reg_width(reg_addr) +#define REG_WR_ADDR(reg_width, reg_addr, val) pcie_write##reg_width(reg_addr, val) + +/** + * Register definitions taken from + * + * Intel High Definition Audio Specification + * Revision 1.0a + * June 17, 2010 + * + * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/high-definition-audio-specification.pdf + */ + +typedef struct hda_stream_desc_regs { + uint8_t ctl[3]; // (0x00) Input Stream Descriptor 0 Control + uint8_t sts; // (0x03) SD_n Status + uint32_t lpib; // (0x04) SD_n Link Position in Current Buffer + uint32_t cbl; // (0x08) SD_n Cyclic Buffer Length + uint16_t lvi; // (0x0C) SD_n Last Valid Index + uint8_t __rsvd0[2]; // (0x8E) Reserved + uint16_t fifod; // (0x10) SD_n FIFO Size + uint16_t fmt; // (0x12) SD_n Format + uint8_t __rsvd1[4]; // (0x14) Reserved + uint32_t bdpl; // (0x18) SD_n Buffer Descriptor List Pointer - Lower + uint32_t bdpu; // (0x1C) SD_n Buffer Descriptor List Pointer - Upper +} __PACKED hda_stream_desc_regs_t; + +typedef struct hda_registers { + uint16_t gcap; // (0x00) Global Capabilities + uint8_t vmin; // (0x02) Minor Version + uint8_t vmaj; // (0x03) Major Version + uint16_t outpay; // (0x04) Output Payload Capability + uint16_t inpay; // (0x06) Input Payload Capability + uint32_t gctl; // (0x08) Global Control + uint16_t wakeen; // (0x0C) Wake Enable + uint16_t statests; // (0x0E) State Change Status + uint16_t gsts; // (0x10) Global Status + uint8_t __rsvd0[6]; // (0x12) Reserved + uint16_t outstrmpay; // (0x18) Output Stream Payload Capability + uint16_t instrmpay; // (0x1A) Input Stream Payload Capability + uint8_t __rsvd1[4]; // (0x1C) Reserved + uint32_t intctl; // (0x20) Interrupt Control + uint32_t intsts; // (0x24) Interrupt Status + uint8_t __rsvd2[8]; // (0x28) Reserved + uint32_t walclk; // (0x30) Wall Clock Counter + uint8_t __rsvd3[4]; // (0x34) Reserved + uint32_t ssync; // (0x38) Stream Synchronization + uint8_t __rsvd4[4]; // (0x3C) Reserved + uint32_t corblbase; // (0x40) CORB Lower Base Address + uint32_t corbubase; // (0x44) CORB Upper Base Address + uint16_t corbwp; // (0x48) CORB Write Pointer + uint16_t corbrp; // (0x4A) CORB Read Pointer + uint8_t corbctl; // (0x4C) CORB Control + uint8_t corbsts; // (0x4D) CORB Status + uint8_t corbsize; // (0x4E) CORB Size + uint8_t __rsvd5[1]; // (0x4F) Reserved + uint32_t rirblbase; // (0x50) RIRB Lower Base Address + uint32_t rirbubase; // (0x54) RIRB Upper Base Address + uint16_t rirbwp; // (0x58) RIRB Write Pointer + uint16_t rintcnt; // (0x5A) Response Interrupt Count + uint8_t rirbctl; // (0x5C) RIRB Control + uint8_t rirbsts; // (0x5D) RIRB Status + uint8_t rirbsize; // (0x5E) RIRB Size + uint8_t __rsvd6[1]; // (0x5F) Reserved + uint32_t icoi; // (0x60) Immediate Command Output Interface + uint32_t icii; // (0x64) Immediate Command Input Interface + uint16_t icis; // (0x68) Immediate Command Status + uint8_t __rsvd7[6]; // (0x6A) Reserved + uint32_t dpiblbase; // (0x70) DMA Position Buffer Lower Base + uint32_t dpibubase; // (0x74) DMA Position Buffer Upper Base + uint8_t __rsvd8[8]; // (0x78) Reserved + + // A max of 30 streams may be present in the system at any point in time (no + // more than 15 input and 15 output). The stream descriptor registers start + // at 0x80, and are layed out as Input, then Output, then Bidirectional. + // The number of each type of stream present in the hardware can be + // determined using the GCAP register. + hda_stream_desc_regs_t stream_desc[30]; // (0x80) + uint8_t __rsvd9[0x1BC0]; // (0x440 - 0x1FFF) +} __PACKED hda_registers_t; + +typedef struct hda_stream_desc_alias_regs { + uint8_t __rsvd0[0x04]; // (0x00) Reserved + uint32_t lpib; // (0x04) SD_n Link Position in Current Buffer Alias + uint8_t __rsvd1[0x18]; // (0x08) Reserved +} __PACKED hda_stream_desc_alias_regs_t; + +typedef struct hda_alias_registers { + uint8_t __rsvd0[0x30]; // (0x00) Reserved + uint32_t wallclk; // (0x30) Wall Clock Counter Alias + uint8_t __rsvd1[0x4C]; // (0x34) Reserved + hda_stream_desc_alias_regs_t stream_desc[30]; // (0x80) + uint8_t __rsvd9[0x1BC0]; // (0x440 - 0x1FFF) +} __PACKED hda_alias_registers_t; + +typedef struct hda_all_registers { + hda_registers_t regs; + hda_alias_registers_t alias_regs; +} __PACKED hda_all_registers_t; + +/* Structs and constants for the command ring buffers */ +typedef struct hda_corb_entry { + uint32_t command; +} __PACKED hda_corb_entry_t; + +#define HDA_CORB_MAX_ENTRIES (256u) +#define HDA_CORB_MAX_BYTES (HDA_CORB_MAX_ENTRIES * sizeof(hda_corb_entry_t)) + +typedef struct hda_rirb_entry { // See Table 54 + uint32_t data; + uint32_t data_ex; +} __PACKED hda_rirb_entry_t; + +#define HDA_RIRB_MAX_ENTRIES (256u) +#define HDA_RIRB_MAX_BYTES (HDA_RIRB_MAX_ENTRIES * sizeof(hda_rirb_entry_t)) +#define HDA_RIRB_CADDR(resp) (((resp).data_ex) & 0xF) +#define HDA_RIRB_UNSOL(resp) ((((resp).data_ex) & 0x10) != 0) + +/** + * Bitfield definitions for various registers + */ + +/* Global Capabilities Reigster (GCAP - offset 0x00) */ +#define HDA_REG_GCAP_64OK ((uint16_t)0x0001) +#define HDA_REG_GCAP_NSDO(val) (((val) >> 1) & 0x03) +#define HDA_REG_GCAP_BSS(val) (((val) >> 3) & 0x1F) +#define HDA_REG_GCAP_ISS(val) (((val) >> 8) & 0x0F) +#define HDA_REG_GCAP_OSS(val) (((val) >> 12) & 0x0F) + +/* Global Control Reigster (GCTL - offset 0x08) */ +#define HDA_REG_GCTL_HWINIT ((uint32_t)0x0001) +#define HDA_REG_GCTL_FCNTRL ((uint32_t)0x0002) +#define HDA_REG_GCTL_UNSOL ((uint32_t)0x0100) + +/* Interrupt Control Register (INTCTL - offset 0x20) */ +#define HDA_REG_INTCTL_GIE ((uint32_t)0x80000000) +#define HDA_REG_INTCTL_CIE ((uint32_t)0x40000000) +#define HDA_REG_INTCTL_SIE(n) (((uint32_t)0x1 << n) & 0x3FFFFFFF) + +/* Command Output Ring Buffer Read Ptr (CORBRP - offset 0x4a) */ +#define HDA_REG_CORBRP_RST ((uint16_t)0x1000) + +/* Command Output Ring Buffer Control (CORBCTL - offset 0x4c) */ +#define HDA_REG_CORBCTL_MEIE ((uint8_t)0x01) // Mem Error Int Enable +#define HDA_REG_CORBCTL_DMA_EN ((uint8_t)0x02) // DMA Enable + +/* Command Output Ring Buffer Status (CORBSTS - offset 0x4d) */ +#define HDA_REG_CORBSTS_MEI ((uint8_t)0x01) // Memory Error Indicator + +/* Command Output Ring Buffer Size (CORBSIZE - offset 0x4e) */ +#define HDA_REG_CORBSIZE_CFG_2ENT ((uint8_t)0x00) +#define HDA_REG_CORBSIZE_CFG_16ENT ((uint8_t)0x01) +#define HDA_REG_CORBSIZE_CFG_256ENT ((uint8_t)0x02) +#define HDA_REG_CORBSIZE_CAP_2ENT ((uint8_t)0x10) +#define HDA_REG_CORBSIZE_CAP_16ENT ((uint8_t)0x20) +#define HDA_REG_CORBSIZE_CAP_256ENT ((uint8_t)0x40) + +/* Response Input Ring Buffer Write Ptr (RIRBWP - offset 0x58) */ +#define HDA_REG_RIRBWP_RST ((uint16_t)0x1000) + +/* Response Input Ring Buffer Control (RIRBCTL - offset 0x5c) */ +#define HDA_REG_RIRBCTL_INTCTL ((uint8_t)0x01) // Interrupt Control +#define HDA_REG_RIRBCTL_DMA_EN ((uint8_t)0x02) // DMA Enable +#define HDA_REG_RIRBCTL_OIC ((uint8_t)0x04) // Overrun Interrupt Control + +/* Response Input Ring Buffer Status (RIRBSTS - offset 0x5d) */ +#define HDA_REG_RIRBSTS_INTFL ((uint8_t)0x01) // Response Interrupt Flag +#define HDA_REG_RIRBSTS_OIS ((uint8_t)0x04) // Overrun Interrupt Status + +/* Response Input Ring Buffer Size (RIRBSIZE - offset 0x5e) */ +#define HDA_REG_RIRBSIZE_CFG_2ENT ((uint8_t)0x00) +#define HDA_REG_RIRBSIZE_CFG_16ENT ((uint8_t)0x01) +#define HDA_REG_RIRBSIZE_CFG_256ENT ((uint8_t)0x02) +#define HDA_REG_RIRBSIZE_CAP_2ENT ((uint8_t)0x10) +#define HDA_REG_RIRBSIZE_CAP_16ENT ((uint8_t)0x20) +#define HDA_REG_RIRBSIZE_CAP_256ENT ((uint8_t)0x40) + +__END_CDECLS diff --git a/kernel/dev/intel_hda/rules.mk b/kernel/dev/intel_hda/rules.mk new file mode 100644 index 000000000..d40a2412e --- /dev/null +++ b/kernel/dev/intel_hda/rules.mk @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/codec.c \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/intel_hda.c + +MODULE_DEPS += \ + dev/pcie \ + +ifneq ($(INTEL_HDA_QEMU_QUIRKS),) +MODULE_DEFINES += INTEL_HDA_QEMU_QUIRKS=1 +endif + +include make/module.mk diff --git a/kernel/dev/interrupt/BUILD.gn b/kernel/dev/interrupt/BUILD.gn new file mode 100644 index 000000000..67efe3954 --- /dev/null +++ b/kernel/dev/interrupt/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_interrupt_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("interrupt") { + public_configs = [ ":_interrupt_config" ] + public = [ + "include/dev/interrupt.h", + "include/dev/interrupt_event.h", + ] + sources = [ + "interrupt_event.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/interrupt/arm_gic/BUILD.gn b/kernel/dev/interrupt/arm_gic/BUILD.gn new file mode 100644 index 000000000..a6153f7ee --- /dev/null +++ b/kernel/dev/interrupt/arm_gic/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_arm_gic_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + defines = [ "WITH_DEV_INTERRUPT_ARM_GIC=1" ] +} + +module("arm_gic") { + public_configs = [ ":_arm_gic_config" ] + include_dirs = [ + "//kernel/platform/qemu-virt/include", + "//kernel/dev/interrupt/include", + ] + sources = [ + "arm_gic.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/interrupt/arm_gic/arm_gic.c b/kernel/dev/interrupt/arm_gic/arm_gic.c new file mode 100644 index 000000000..d05987ddd --- /dev/null +++ b/kernel/dev/interrupt/arm_gic/arm_gic.c @@ -0,0 +1,565 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WITH_LIB_SM +#include +#include +#endif + +#define LOCAL_TRACE 0 + +#if ARCH_ARM +#include +#define iframe arm_iframe +#define IFRAME_PC(frame) ((frame)->pc) +#endif +#if ARCH_ARM64 +#include +#define iframe arm64_iframe_short +#define IFRAME_PC(frame) ((frame)->elr) +#endif + +static status_t arm_gic_set_secure_locked(u_int irq, bool secure); + +static spin_lock_t gicd_lock; +#if WITH_LIB_SM +#define GICD_LOCK_FLAGS SPIN_LOCK_FLAG_IRQ_FIQ +#else +#define GICD_LOCK_FLAGS SPIN_LOCK_FLAG_INTERRUPTS +#endif +#define GIC_MAX_PER_CPU_INT 32 + +#if WITH_LIB_SM +static bool arm_gic_non_secure_interrupts_frozen; + +static bool arm_gic_interrupt_change_allowed(int irq) +{ + if (!arm_gic_non_secure_interrupts_frozen) + return true; + + TRACEF("change to interrupt %d ignored after booting ns\n", irq); + return false; +} + +static void suspend_resume_fiq(bool resume_gicc, bool resume_gicd); +#else +static bool arm_gic_interrupt_change_allowed(int irq) +{ + return true; +} + +static void suspend_resume_fiq(bool resume_gicc, bool resume_gicd) +{ +} +#endif + + +struct int_handler_struct { + int_handler handler; + void *arg; +}; + +static struct int_handler_struct int_handler_table_per_cpu[GIC_MAX_PER_CPU_INT][SMP_MAX_CPUS]; +static struct int_handler_struct int_handler_table_shared[MAX_INT-GIC_MAX_PER_CPU_INT]; + +static struct int_handler_struct *get_int_handler(unsigned int vector, uint cpu) +{ + if (vector < GIC_MAX_PER_CPU_INT) + return &int_handler_table_per_cpu[vector][cpu]; + else + return &int_handler_table_shared[vector - GIC_MAX_PER_CPU_INT]; +} + +void register_int_handler(unsigned int vector, int_handler handler, void *arg) +{ + struct int_handler_struct *h; + uint cpu = arch_curr_cpu_num(); + + spin_lock_saved_state_t state; + + if (vector >= MAX_INT) + panic("register_int_handler: vector out of range %d\n", vector); + + spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS); + + if (arm_gic_interrupt_change_allowed(vector)) { + h = get_int_handler(vector, cpu); + h->handler = handler; + h->arg = arg; + } + + spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS); +} + +bool is_valid_interrupt(unsigned int vector, uint32_t flags) +{ + return (vector < MAX_INT); +} + +#if WITH_LIB_SM +static DEFINE_GIC_SHADOW_REG(gicd_igroupr, 32, ~0U, 0); +#endif +static DEFINE_GIC_SHADOW_REG(gicd_itargetsr, 4, 0x01010101, 32); + +static void gic_set_enable(uint vector, bool enable) +{ + int reg = vector / 32; + uint32_t mask = 1ULL << (vector % 32); + + if (enable) + GICREG(0, GICD_ISENABLER(reg)) = mask; + else + GICREG(0, GICD_ICENABLER(reg)) = mask; +} + +static void arm_gic_init_percpu(uint level) +{ +#if WITH_LIB_SM + GICREG(0, GICC_CTLR) = 0xb; // enable GIC0 and select fiq mode for secure + GICREG(0, GICD_IGROUPR(0)) = ~0U; /* GICD_IGROUPR0 is banked */ +#else + GICREG(0, GICC_CTLR) = 1; // enable GIC0 +#endif + GICREG(0, GICC_PMR) = 0xFF; // unmask interrupts at all priority levels +} + +LK_INIT_HOOK_FLAGS(arm_gic_init_percpu, + arm_gic_init_percpu, + LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_FLAG_SECONDARY_CPUS); + +static void arm_gic_suspend_cpu(uint level) +{ + suspend_resume_fiq(false, false); +} + +LK_INIT_HOOK_FLAGS(arm_gic_suspend_cpu, arm_gic_suspend_cpu, + LK_INIT_LEVEL_PLATFORM, LK_INIT_FLAG_CPU_SUSPEND); + +static void arm_gic_resume_cpu(uint level) +{ + spin_lock_saved_state_t state; + bool resume_gicd = false; + + spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS); + if (!(GICREG(0, GICD_CTLR) & 1)) { + dprintf(SPEW, "%s: distibutor is off, calling arm_gic_init instead\n", __func__); + arm_gic_init(); + resume_gicd = true; + } else { + arm_gic_init_percpu(0); + } + spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS); + suspend_resume_fiq(true, resume_gicd); +} + +LK_INIT_HOOK_FLAGS(arm_gic_resume_cpu, arm_gic_resume_cpu, + LK_INIT_LEVEL_PLATFORM, LK_INIT_FLAG_CPU_RESUME); + +static int arm_gic_max_cpu(void) +{ + return (GICREG(0, GICD_TYPER) >> 5) & 0x7; +} + +void arm_gic_init(void) +{ + int i; + + for (i = 0; i < MAX_INT; i+= 32) { + GICREG(0, GICD_ICENABLER(i / 32)) = ~0; + GICREG(0, GICD_ICPENDR(i / 32)) = ~0; + } + + if (arm_gic_max_cpu() > 0) { + /* Set external interrupts to target cpu 0 */ + for (i = 32; i < MAX_INT; i += 4) { + GICREG(0, GICD_ITARGETSR(i / 4)) = gicd_itargetsr[i / 4]; + } + } + + GICREG(0, GICD_CTLR) = 1; // enable GIC0 +#if WITH_LIB_SM + GICREG(0, GICD_CTLR) = 3; // enable GIC0 ns interrupts + /* + * Iterate through all IRQs and set them to non-secure + * mode. This will allow the non-secure side to handle + * all the interrupts we don't explicitly claim. + */ + for (i = 32; i < MAX_INT; i += 32) { + u_int reg = i / 32; + GICREG(0, GICD_IGROUPR(reg)) = gicd_igroupr[reg]; + } +#endif + arm_gic_init_percpu(0); +} + +static status_t arm_gic_set_secure_locked(u_int irq, bool secure) +{ +#if WITH_LIB_SM + int reg = irq / 32; + uint32_t mask = 1ULL << (irq % 32); + + if (irq >= MAX_INT) + return ERR_INVALID_ARGS; + + if (secure) + GICREG(0, GICD_IGROUPR(reg)) = (gicd_igroupr[reg] &= ~mask); + else + GICREG(0, GICD_IGROUPR(reg)) = (gicd_igroupr[reg] |= mask); + LTRACEF("irq %d, secure %d, GICD_IGROUP%d = %x\n", + irq, secure, reg, GICREG(0, GICD_IGROUPR(reg))); +#endif + return NO_ERROR; +} + +static status_t arm_gic_set_target_locked(u_int irq, u_int cpu_mask, u_int enable_mask) +{ + u_int reg = irq / 4; + u_int shift = 8 * (irq % 4); + u_int old_val; + u_int new_val; + + cpu_mask = (cpu_mask & 0xff) << shift; + enable_mask = (enable_mask << shift) & cpu_mask; + + old_val = GICREG(0, GICD_ITARGETSR(reg)); + new_val = (gicd_itargetsr[reg] & ~cpu_mask) | enable_mask; + GICREG(0, GICD_ITARGETSR(reg)) = gicd_itargetsr[reg] = new_val; + LTRACEF("irq %i, GICD_ITARGETSR%d %x => %x (got %x)\n", + irq, reg, old_val, new_val, GICREG(0, GICD_ITARGETSR(reg))); + + return NO_ERROR; +} + +static status_t arm_gic_get_priority(u_int irq) +{ + u_int reg = irq / 4; + u_int shift = 8 * (irq % 4); + return (GICREG(0, GICD_IPRIORITYR(reg)) >> shift) & 0xff; +} + +static status_t arm_gic_set_priority_locked(u_int irq, uint8_t priority) +{ + u_int reg = irq / 4; + u_int shift = 8 * (irq % 4); + u_int mask = 0xff << shift; + uint32_t regval; + + regval = GICREG(0, GICD_IPRIORITYR(reg)); + LTRACEF("irq %i, old GICD_IPRIORITYR%d = %x\n", irq, reg, regval); + regval = (regval & ~mask) | ((uint32_t)priority << shift); + GICREG(0, GICD_IPRIORITYR(reg)) = regval; + LTRACEF("irq %i, new GICD_IPRIORITYR%d = %x, req %x\n", + irq, reg, GICREG(0, GICD_IPRIORITYR(reg)), regval); + + return 0; +} + +status_t arm_gic_sgi(u_int irq, u_int flags, u_int cpu_mask) +{ + u_int val = + ((flags & ARM_GIC_SGI_FLAG_TARGET_FILTER_MASK) << 24) | + ((cpu_mask & 0xff) << 16) | + ((flags & ARM_GIC_SGI_FLAG_NS) ? (1U << 15) : 0) | + (irq & 0xf); + + if (irq >= 16) + return ERR_INVALID_ARGS; + + LTRACEF("GICD_SGIR: %x\n", val); + + GICREG(0, GICD_SGIR) = val; + + return NO_ERROR; +} + +status_t mask_interrupt(unsigned int vector) +{ + if (vector >= MAX_INT) + return ERR_INVALID_ARGS; + + if (arm_gic_interrupt_change_allowed(vector)) + gic_set_enable(vector, false); + + return NO_ERROR; +} + +status_t unmask_interrupt(unsigned int vector) +{ + if (vector >= MAX_INT) + return ERR_INVALID_ARGS; + + if (arm_gic_interrupt_change_allowed(vector)) + gic_set_enable(vector, true); + + return NO_ERROR; +} + +unsigned int remap_interrupt(unsigned int vector) +{ + return vector; +} + +static +enum handler_return __platform_irq(struct iframe *frame) +{ + // get the current vector + uint32_t iar = GICREG(0, GICC_IAR); + unsigned int vector = iar & 0x3ff; + + if (vector >= 0x3fe) { + // spurious + return INT_NO_RESCHEDULE; + } + + THREAD_STATS_INC(interrupts); + KEVLOG_IRQ_ENTER(vector); + + uint cpu = arch_curr_cpu_num(); + + LTRACEF_LEVEL(2, "iar 0x%x cpu %u currthread %p vector %d pc 0x%lx\n", iar, cpu, + get_current_thread(), vector, (uintptr_t)IFRAME_PC(frame)); + + // deliver the interrupt + enum handler_return ret; + + ret = INT_NO_RESCHEDULE; + struct int_handler_struct *handler = get_int_handler(vector, cpu); + if (handler->handler) + ret = handler->handler(handler->arg); + + GICREG(0, GICC_EOIR) = iar; + + LTRACEF_LEVEL(2, "cpu %u exit %d\n", cpu, ret); + + KEVLOG_IRQ_EXIT(vector); + + return ret; +} + +enum handler_return platform_irq(struct iframe *frame) +{ +#if WITH_LIB_SM + uint32_t ahppir = GICREG(0, GICC_AHPPIR); + uint32_t pending_irq = ahppir & 0x3ff; + struct int_handler_struct *h; + uint cpu = arch_curr_cpu_num(); + + LTRACEF("ahppir %d\n", ahppir); + if (pending_irq < MAX_INT && get_int_handler(pending_irq, cpu)->handler) { + enum handler_return ret = 0; + uint32_t irq; + uint8_t old_priority; + spin_lock_saved_state_t state; + + spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS); + + /* Temporarily raise the priority of the interrupt we want to + * handle so another interrupt does not take its place before + * we can acknowledge it. + */ + old_priority = arm_gic_get_priority(pending_irq); + arm_gic_set_priority_locked(pending_irq, 0); + DSB; + irq = GICREG(0, GICC_AIAR) & 0x3ff; + arm_gic_set_priority_locked(pending_irq, old_priority); + + spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS); + + LTRACEF("irq %d\n", irq); + if (irq < MAX_INT && (h = get_int_handler(pending_irq, cpu))->handler) + ret = h->handler(h->arg); + else + TRACEF("unexpected irq %d != %d may get lost\n", irq, pending_irq); + GICREG(0, GICC_AEOIR) = irq; + return ret; + } + return sm_handle_irq(); +#else + return __platform_irq(frame); +#endif +} + +void platform_fiq(struct iframe *frame) +{ +#if WITH_LIB_SM + sm_handle_fiq(); +#else + PANIC_UNIMPLEMENTED; +#endif +} + +#if WITH_LIB_SM +static status_t arm_gic_get_next_irq_locked(u_int min_irq, bool per_cpu) +{ + u_int irq; + u_int max_irq = per_cpu ? GIC_MAX_PER_CPU_INT : MAX_INT; + uint cpu = arch_curr_cpu_num(); + + if (!per_cpu && min_irq < GIC_MAX_PER_CPU_INT) + min_irq = GIC_MAX_PER_CPU_INT; + + for (irq = min_irq; irq < max_irq; irq++) + if (get_int_handler(irq, cpu)->handler) + return irq; + + return SM_ERR_END_OF_INPUT; +} + +long smc_intc_get_next_irq(smc32_args_t *args) +{ + status_t ret; + spin_lock_saved_state_t state; + + spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS); + + arm_gic_non_secure_interrupts_frozen = true; + ret = arm_gic_get_next_irq_locked(args->params[0], args->params[1]); + LTRACEF("min_irq %d, per_cpu %d, ret %d\n", + args->params[0], args->params[1], ret); + + spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS); + + return ret; +} + +static u_long enabled_fiq_mask[BITMAP_NUM_WORDS(MAX_INT)]; + +static void bitmap_update_locked(u_long *bitmap, u_int bit, bool set) +{ + u_long mask = 1UL << BITMAP_BIT_IN_WORD(bit); + + bitmap += BITMAP_WORD(bit); + if (set) + *bitmap |= mask; + else + *bitmap &= ~mask; +} + +long smc_intc_request_fiq(smc32_args_t *args) +{ + u_int fiq = args->params[0]; + bool enable = args->params[1]; + spin_lock_saved_state_t state; + + dprintf(SPEW, "%s: fiq %d, enable %d\n", __func__, fiq, enable); + spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS); + + arm_gic_set_secure_locked(fiq, true); + arm_gic_set_target_locked(fiq, ~0, ~0); + arm_gic_set_priority_locked(fiq, 0); + + gic_set_enable(fiq, enable); + bitmap_update_locked(enabled_fiq_mask, fiq, enable); + + dprintf(SPEW, "%s: fiq %d, enable %d done\n", __func__, fiq, enable); + + spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS); + + return NO_ERROR; +} + +static u_int current_fiq[8] = { 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff }; + +static bool update_fiq_targets(u_int cpu, bool enable, u_int triggered_fiq, bool resume_gicd) +{ + u_int i, j; + u_long mask; + u_int fiq; + bool smp = arm_gic_max_cpu() > 0; + bool ret = false; + + spin_lock(&gicd_lock); /* IRQs and FIQs are already masked */ + for (i = 0; i < BITMAP_NUM_WORDS(MAX_INT); i++) { + mask = enabled_fiq_mask[i]; + while (mask) { + j = _ffz(~mask); + mask &= ~(1UL << j); + fiq = i * BITMAP_BITS_PER_WORD + j; + if (fiq == triggered_fiq) + ret = true; + LTRACEF("cpu %d, irq %i, enable %d\n", cpu, fiq, enable); + if (smp) + arm_gic_set_target_locked(fiq, 1U << cpu, enable ? ~0 : 0); + if (!smp || resume_gicd) + gic_set_enable(fiq, enable); + } + } + spin_unlock(&gicd_lock); + return ret; +} + +static void suspend_resume_fiq(bool resume_gicc, bool resume_gicd) +{ + u_int cpu = arch_curr_cpu_num(); + + ASSERT(cpu < 8); + + update_fiq_targets(cpu, resume_gicc, ~0, resume_gicd); +} + +status_t sm_intc_fiq_enter(void) +{ + u_int cpu = arch_curr_cpu_num(); + u_int irq = GICREG(0, GICC_IAR) & 0x3ff; + bool fiq_enabled; + + ASSERT(cpu < 8); + + LTRACEF("cpu %d, irq %i\n", cpu, irq); + + if (irq >= 1020) { + LTRACEF("spurious fiq: cpu %d, old %d, new %d\n", cpu, current_fiq[cpu], irq); + return ERR_NO_MSG; + } + + fiq_enabled = update_fiq_targets(cpu, false, irq, false); + GICREG(0, GICC_EOIR) = irq; + + if (current_fiq[cpu] != 0x3ff) { + dprintf(INFO, "more than one fiq active: cpu %d, old %d, new %d\n", cpu, current_fiq[cpu], irq); + return ERR_ALREADY_STARTED; + } + + if (!fiq_enabled) { + dprintf(INFO, "got disabled fiq: cpu %d, new %d\n", cpu, irq); + return ERR_NOT_READY; + } + + current_fiq[cpu] = irq; + + return 0; +} + +void sm_intc_fiq_exit(void) +{ + u_int cpu = arch_curr_cpu_num(); + + ASSERT(cpu < 8); + + LTRACEF("cpu %d, irq %i\n", cpu, current_fiq[cpu]); + if (current_fiq[cpu] == 0x3ff) { + dprintf(INFO, "%s: no fiq active, cpu %d\n", __func__, cpu); + return; + } + update_fiq_targets(cpu, true, current_fiq[cpu], false); + current_fiq[cpu] = 0x3ff; +} +#endif diff --git a/kernel/dev/interrupt/arm_gic/include/dev/interrupt/arm_gic.h b/kernel/dev/interrupt/arm_gic/include/dev/interrupt/arm_gic.h new file mode 100644 index 000000000..10c6ddd24 --- /dev/null +++ b/kernel/dev/interrupt/arm_gic/include/dev/interrupt/arm_gic.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_INTERRUPT_ARM_GIC_H +#define __DEV_INTERRUPT_ARM_GIC_H + +#include + +void arm_gic_init(void); + +enum { + /* Ignore cpu_mask and forward interrupt to all CPUs other than the current cpu */ + ARM_GIC_SGI_FLAG_TARGET_FILTER_NOT_SENDER = 0x1, + /* Ignore cpu_mask and forward interrupt to current CPU only */ + ARM_GIC_SGI_FLAG_TARGET_FILTER_SENDER = 0x2, + ARM_GIC_SGI_FLAG_TARGET_FILTER_MASK = 0x3, + + /* Only forward the interrupt to CPUs that has the interrupt configured as group 1 (non-secure) */ + ARM_GIC_SGI_FLAG_NS = 0x4, +}; +status_t arm_gic_sgi(u_int irq, u_int flags, u_int cpu_mask); + +#endif + diff --git a/kernel/dev/interrupt/arm_gic/include/dev/interrupt/arm_gic_regs.h b/kernel/dev/interrupt/arm_gic/include/dev/interrupt/arm_gic_regs.h new file mode 100644 index 000000000..e42993843 --- /dev/null +++ b/kernel/dev/interrupt/arm_gic/include/dev/interrupt/arm_gic_regs.h @@ -0,0 +1,58 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +#define GICREG(gic, reg) (*REG32(GICBASE(gic) + (reg))) + +/* main cpu regs */ +#define GICC_CTLR (GICC_OFFSET + 0x0000) +#define GICC_PMR (GICC_OFFSET + 0x0004) +#define GICC_BPR (GICC_OFFSET + 0x0008) +#define GICC_IAR (GICC_OFFSET + 0x000c) +#define GICC_EOIR (GICC_OFFSET + 0x0010) +#define GICC_RPR (GICC_OFFSET + 0x0014) +#define GICC_HPPIR (GICC_OFFSET + 0x0018) +#define GICC_APBR (GICC_OFFSET + 0x001c) +#define GICC_AIAR (GICC_OFFSET + 0x0020) +#define GICC_AEOIR (GICC_OFFSET + 0x0024) +#define GICC_AHPPIR (GICC_OFFSET + 0x0028) +#define GICC_APR(n) (GICC_OFFSET + 0x00d0 + (n) * 4) +#define GICC_NSAPR(n) (GICC_OFFSET + 0x00e0 + (n) * 4) +#define GICC_IIDR (GICC_OFFSET + 0x00fc) +#define GICC_DIR (GICC_OFFSET + 0x1000) + +/* distribution regs */ +#define GICD_CTLR (GICD_OFFSET + 0x000) +#define GICD_TYPER (GICD_OFFSET + 0x004) +#define GICD_IIDR (GICD_OFFSET + 0x008) +#define GICD_IGROUPR(n) (GICD_OFFSET + 0x080 + (n) * 4) +#define GICD_ISENABLER(n) (GICD_OFFSET + 0x100 + (n) * 4) +#define GICD_ICENABLER(n) (GICD_OFFSET + 0x180 + (n) * 4) +#define GICD_ISPENDR(n) (GICD_OFFSET + 0x200 + (n) * 4) +#define GICD_ICPENDR(n) (GICD_OFFSET + 0x280 + (n) * 4) +#define GICD_ISACTIVER(n) (GICD_OFFSET + 0x300 + (n) * 4) +#define GICD_ICACTIVER(n) (GICD_OFFSET + 0x380 + (n) * 4) +#define GICD_IPRIORITYR(n) (GICD_OFFSET + 0x400 + (n) * 4) +#define GICD_ITARGETSR(n) (GICD_OFFSET + 0x800 + (n) * 4) +#define GICD_ICFGR(n) (GICD_OFFSET + 0xc00 + (n) * 4) +#define GICD_NSACR(n) (GICD_OFFSET + 0xe00 + (n) * 4) +#define GICD_SGIR (GICD_OFFSET + 0xf00) +#define GICD_CPENDSGIR(n) (GICD_OFFSET + 0xf10 + (n) * 4) +#define GICD_SPENDSGIR(n) (GICD_OFFSET + 0xf20 + (n) * 4) + +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define GIC_REG_COUNT(bit_per_reg) DIV_ROUND_UP(MAX_INT, (bit_per_reg)) +#define DEFINE_GIC_SHADOW_REG(name, bit_per_reg, init_val, init_from) \ + uint32_t (name)[GIC_REG_COUNT(bit_per_reg)] = { \ + [(init_from / bit_per_reg) ... \ + (GIC_REG_COUNT(bit_per_reg) - 1)] = (init_val) \ + } + diff --git a/kernel/dev/interrupt/arm_gic/rules.mk b/kernel/dev/interrupt/arm_gic/rules.mk new file mode 100644 index 000000000..e526c8702 --- /dev/null +++ b/kernel/dev/interrupt/arm_gic/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm_gic.c + +MODULE_DEPS += \ + dev/interrupt + +include make/module.mk diff --git a/kernel/dev/interrupt/arm_gicv2m/BUILD.gn b/kernel/dev/interrupt/arm_gicv2m/BUILD.gn new file mode 100644 index 000000000..541ea3edd --- /dev/null +++ b/kernel/dev/interrupt/arm_gicv2m/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_arm_gicv2m_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("arm_gicv2m") { + public_configs = [ ":_arm_gicv2m_config" ] + include_dirs = [ + "//kernel/platform/qemu-virt/include", + "//kernel/dev/interrupt/include", + ] + sources = [ + "arm_gicv2m.c", + "arm_gicv2m_msi.c", + ] + deps = [ + "//kernel/dev/interrupt/arm_gic", + "//kernel/dev/pcie", + "//kernel/lib/libc", + "//kernel/lib/pow2_range_allocator", + ] +} diff --git a/kernel/dev/interrupt/arm_gicv2m/arm_gicv2m.c b/kernel/dev/interrupt/arm_gicv2m/arm_gicv2m.c new file mode 100644 index 000000000..66a5c2616 --- /dev/null +++ b/kernel/dev/interrupt/arm_gicv2m/arm_gicv2m.c @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +// Section 9.7 +#define MSI_TYPER_OFFSET (0x008) // Type Register +#define MSI_SETSPI_NS_OFFSET (0x040) // Doorbell register (whack here for interrupt) +#define MSI_IIDR_OFFSET (0xFCC) // Interface ID register +#define REG_RD(base, off) (((volatile uint32_t*)(base))[(off) >> 2]) + +// Section 9.9.1 +#define MIN_VALID_MSI_SPI (32) +#define MAX_VALID_MSI_SPI (1020) + +const paddr_t* g_reg_frames; +uint g_reg_frame_count; + +void arm_gicv2m_init(const paddr_t* reg_frames, uint reg_frame_count) { + // Protect against double init. + DEBUG_ASSERT(!g_reg_frames); + DEBUG_ASSERT(!g_reg_frame_count); + + // If the user has no register frames, they should be using arm_gic, not + // arm_gicv2m + DEBUG_ASSERT(reg_frames); + DEBUG_ASSERT(reg_frame_count); + + // Initialize the base GIC module first + arm_gic_init(); + + // Stash the frame info + g_reg_frames = reg_frames; + g_reg_frame_count = reg_frame_count; + + // Walk the list of regions, and make sure that all of the controlled SPIs + // are configured for edge triggered mode. + for (uint i = 0; i < g_reg_frame_count; ++i) { + void* kvaddr = paddr_to_kvaddr(g_reg_frames[i]); + uint32_t type_reg = REG_RD(kvaddr, MSI_TYPER_OFFSET); + uint base_spi = (type_reg >> 16) & 0x3FF; + uint num_spi = type_reg & 0x3FF; + + for (uint i = 0; i < num_spi; ++i) { + uint spi_id = base_spi + i; + if ((spi_id < MIN_VALID_MSI_SPI) || (spi_id > MAX_VALID_MSI_SPI)) { + TRACEF("Invalid SPI ID (%u) found in GICv2m register frame @%p\n", + spi_id, (void*)g_reg_frames[i]); + continue; + } + + uint reg_ndx = spi_id >> 4; + uint bit_shift = ((spi_id & 0xF) << 1) + 1; + uint32_t reg_val = GICREG(0, GICD_ICFGR(reg_ndx)); + reg_val |= (0x1u << bit_shift); + GICREG(0, GICD_ICFGR(reg_ndx)) = reg_val; + } + } + +} + +status_t arm_gicv2m_get_frame_info(uint frame_ndx, arm_gicv2m_frame_info_t* out_info) { + if (!out_info) + return ERR_INVALID_ARGS; + + memset(out_info, 0, sizeof(*out_info)); + + if (!g_reg_frames || !g_reg_frame_count) + return ERR_NOT_READY; + + if (frame_ndx >= g_reg_frame_count) + return ERR_NOT_FOUND; + + void* kvaddr = paddr_to_kvaddr(g_reg_frames[frame_ndx]); + uint32_t type_reg = REG_RD(kvaddr, MSI_TYPER_OFFSET); + uint base_spi = (type_reg >> 16) & 0x3FF; + uint num_spi = type_reg & 0x3FF; + uint last_spi = base_spi + num_spi - 1; + + if (!num_spi || + (base_spi < MIN_VALID_MSI_SPI) || + (last_spi > MAX_VALID_MSI_SPI)) + return ERR_BAD_STATE; + + out_info->start_spi_id = base_spi; + out_info->end_spi_id = last_spi; + out_info->doorbell = g_reg_frames[frame_ndx] + MSI_SETSPI_NS_OFFSET; + out_info->iid = REG_RD(kvaddr, MSI_IIDR_OFFSET); + + return NO_ERROR; +} diff --git a/kernel/dev/interrupt/arm_gicv2m/arm_gicv2m_msi.c b/kernel/dev/interrupt/arm_gicv2m/arm_gicv2m_msi.c new file mode 100644 index 000000000..eb0a86c11 --- /dev/null +++ b/kernel/dev/interrupt/arm_gicv2m/arm_gicv2m_msi.c @@ -0,0 +1,170 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* If we are building with PCIe support, go ahead and implement management of + * MSI IRQ blocks here, instead of requiring each platform to do so on their + * own. */ +#if WITH_DEV_PCIE + +p2ra_state_t g_32bit_targets; +p2ra_state_t g_64bit_targets; + +status_t arm_gic2vm_msi_init(void) { + status_t ret; + + ret = p2ra_init(&g_32bit_targets, PCIE_MAX_MSI_IRQS); + if (ret != NO_ERROR) { + TRACEF("Failed to initialize 32 bit allocation pool!\n"); + return ret; + } + + ret = p2ra_init(&g_64bit_targets, PCIE_MAX_MSI_IRQS); + if (ret != NO_ERROR) { + TRACEF("Failed to initialize 64 bit allocation pool!\n"); + p2ra_free(&g_32bit_targets); + return ret; + } + + /* TODO(johngro) + * + * Right now, the pow2 range allocator will not accept overlapping ranges. + * It may be possible for fancy GIC implementations to have multiple MSI + * frames aligned on 4k boundaries (for virtualisation) with either + * completely or partially overlapping IRQ ranges. If/when we need to deal + * with hardware like this, we will need to come back here and make this + * system more sophisticated. + */ + arm_gicv2m_frame_info_t info; + for (uint i = 0; arm_gicv2m_get_frame_info(i, &info) == NO_ERROR; ++i) { + p2ra_state_t* pool = ((uint64_t)info.doorbell & 0xFFFFFFFF00000000) + ? &g_64bit_targets + : &g_32bit_targets; + + uint len = info.end_spi_id - info.start_spi_id + 1; + ret = p2ra_add_range(pool, info.start_spi_id, len); + if (ret != NO_ERROR) { + TRACEF("Failed to add MSI IRQ range [%u, %u] to allocator (ret %d).\n", + info.start_spi_id, len, ret); + goto finished; + } + } + +finished: + if (ret != NO_ERROR) { + p2ra_free(&g_32bit_targets); + p2ra_free(&g_64bit_targets); + } + + return ret; +} + +status_t arm_gicv2m_alloc_msi_block(uint requested_irqs, + bool can_target_64bit, + bool is_msix, + pcie_msi_block_t* out_block) { + if (!out_block) + return ERR_INVALID_ARGS; + + if (out_block->allocated) + return ERR_BAD_STATE; + + if (!requested_irqs || (requested_irqs > PCIE_MAX_MSI_IRQS)) + return ERR_INVALID_ARGS; + + status_t ret = ERR_GENERIC; + bool is_32bit = false; + uint alloc_size = 1u << log2_uint_roundup(requested_irqs); + uint alloc_start; + + /* If this MSI request can tolerate a 64 bit target address, start by + * attempting to allocate from the 64 bit pool */ + if (can_target_64bit) + ret = p2ra_allocate_range(&g_64bit_targets, alloc_size, &alloc_start); + + /* No allocation yet? Fall back on the 32 bit pool */ + if (ret != NO_ERROR) { + ret = p2ra_allocate_range(&g_32bit_targets, alloc_size, &alloc_start); + is_32bit = true; + } + + /* If we have not managed to allocate yet, then we fail */ + if (ret != NO_ERROR) + return ret; + + /* Find the target physical address for this allocation. + * + * TODO(johngro) : we could make this O(k) instead of O(n) by associating a + * context pointer with ranges registered with the pow2 allocator. Right + * now, however, N tends to be 1, so it is difficult to be too concerned + * about this. + */ + arm_gicv2m_frame_info_t info; + for (uint i = 0; (ret = arm_gicv2m_get_frame_info(i, &info)) == NO_ERROR; ++i) { + uint alloc_end = alloc_start + alloc_size - 1; + + if (((alloc_start >= info.start_spi_id) && (alloc_start <= info.end_spi_id)) && + ((alloc_end >= info.start_spi_id) && (alloc_end <= info.end_spi_id))) + break; + } + + /* This should never ever fail */ + DEBUG_ASSERT(ret == NO_ERROR); + if (ret != NO_ERROR) { + p2ra_free_range(is_32bit ? &g_32bit_targets : &g_64bit_targets, alloc_start, alloc_size); + return ret; + } + + /* Success! Fill out the bookkeeping and we are done */ + out_block->platform_ctx = (void*)is_32bit; + out_block->base_irq_id = alloc_start; + out_block->num_irq = alloc_size; + out_block->tgt_addr = info.doorbell; + out_block->tgt_data = alloc_start; + out_block->allocated = true; + return NO_ERROR; +} + +void arm_gicv2m_free_msi_block(pcie_msi_block_t* block) { + DEBUG_ASSERT(block); + DEBUG_ASSERT(block->allocated); + + /* We stashed whether or not this came from the 32 bit pool in the platform context pointer */ + p2ra_state_t* pool = block->platform_ctx ? &g_32bit_targets : &g_64bit_targets; + p2ra_free_range(pool, block->base_irq_id, block->num_irq); + memset(block, 0, sizeof(*block)); +} + +void arm_gicv2m_register_msi_handler(const pcie_msi_block_t* block, + uint msi_id, + int_handler handler, + void* ctx) { + DEBUG_ASSERT(block && block->allocated); + DEBUG_ASSERT(msi_id < block->num_irq); + register_int_handler(block->base_irq_id + msi_id, handler, ctx); +} + +void arm_gicv2m_mask_unmask_msi(const pcie_msi_block_t* block, + uint msi_id, + bool mask) { + DEBUG_ASSERT(block && block->allocated); + DEBUG_ASSERT(msi_id < block->num_irq); + if (mask) mask_interrupt(block->base_irq_id + msi_id); + else unmask_interrupt(block->base_irq_id + msi_id); +} + +#endif // WITH_DEV_PCIE diff --git a/kernel/dev/interrupt/arm_gicv2m/include/dev/interrupt/arm_gicv2m.h b/kernel/dev/interrupt/arm_gicv2m/include/dev/interrupt/arm_gicv2m.h new file mode 100644 index 000000000..3a97e91c2 --- /dev/null +++ b/kernel/dev/interrupt/arm_gicv2m/include/dev/interrupt/arm_gicv2m.h @@ -0,0 +1,47 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +/** + * Structure used to hold information about a GICv2m register frame + * @see arm_gicv2m_get_frame_info + */ +typedef struct arm_gicv2m_frame_info { + uint start_spi_id; /** The first valid SPI ID in the frame */ + uint end_spi_id; /** The last valid SPI ID in the frame */ + paddr_t doorbell; /** The physical address of the doorbell register */ + uint32_t iid; /** The value of the Interface ID register */ +} arm_gicv2m_frame_info_t; + +/** + * Support for the MSI extensions to the GICv2 architecture. See the ARM Server + * Base System Architecture v3.0 (ARM_DEN_0029) Appendix E for details. + * + * @param reg_frames An array of physical addresses of the 4k V2M register + * frames implemented by this platform's GIC. Note: The memory backing this + * array must be alive for the lifetime of the system. + * @param reg_frame_count The number of entries in the reg_frames array. + */ +void arm_gicv2m_init(const paddr_t* reg_frames, uint reg_frame_count); + +/** + * Fetch info about a specific GICv2m register frame + * + * @param frame_num The index of the frame to fetch info for + * @param out_info A pointer to the structure which will hold info about the frame + * @return A status code indicating the success or failure of the operation. + * Status codes may include... + * ++ ERR_NOT_READY The GICv2m subsystem was never initialized + * ++ ERR_NOT_FOUND frame_ndx is out of range + * ++ ERR_INVALID_ARGS out_info is NULL + * ++ ERR_BAD_STATE The frame index exists, but the registers in the frame + * appear to be corrupt or invalid (internal error) + */ +status_t arm_gicv2m_get_frame_info(uint frame_ndx, arm_gicv2m_frame_info_t* out_info); diff --git a/kernel/dev/interrupt/arm_gicv2m/include/dev/interrupt/arm_gicv2m_msi.h b/kernel/dev/interrupt/arm_gicv2m/include/dev/interrupt/arm_gicv2m_msi.h new file mode 100644 index 000000000..0cb45b744 --- /dev/null +++ b/kernel/dev/interrupt/arm_gicv2m/include/dev/interrupt/arm_gicv2m_msi.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#if WITH_DEV_PCIE +#include +#include + +/** + * Initialize the GICv2m management of MSI blocks. + * + * @return A status code indicating the success or failure of the initialization. + */ +status_t arm_gic2vm_msi_init(void); + +/** + * Implementation of the PCIe bus driver hooks. + * + * @see platform_alloc_msi_block_t in dev/pcie/pcie_irqs.h + */ +status_t arm_gicv2m_alloc_msi_block(uint requested_irqs, + bool can_target_64bit, + bool is_msix, + pcie_msi_block_t* out_block); + +/** + * @see platform_free_msi_block_t in dev/pcie/pcie_irqs.h + */ +void arm_gicv2m_free_msi_block(pcie_msi_block_t* block); + +/** + * @see platform_register_msi_handler_t in dev/pcie/pcie_irqs.h + */ +void arm_gicv2m_register_msi_handler(const pcie_msi_block_t* block, + uint msi_id, + int_handler handler, + void* ctx); + +/** + * @see platform_mask_unmask_msi_t in dev/pcie/pcie_irqs.h + */ +void arm_gicv2m_mask_unmask_msi(const pcie_msi_block_t* block, + uint msi_id, + bool mask); + +#endif // WITH_DEV_PCIE diff --git a/kernel/dev/interrupt/arm_gicv2m/rules.mk b/kernel/dev/interrupt/arm_gicv2m/rules.mk new file mode 100644 index 000000000..c052bc2e9 --- /dev/null +++ b/kernel/dev/interrupt/arm_gicv2m/rules.mk @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm_gicv2m.c \ + $(LOCAL_DIR)/arm_gicv2m_msi.c + +MODULE_DEPS += \ + dev/interrupt \ + dev/interrupt/arm_gic \ + lib/pow2_range_allocator + +include make/module.mk diff --git a/kernel/dev/interrupt/include/dev/interrupt.h b/kernel/dev/interrupt/include/dev/interrupt.h new file mode 100644 index 000000000..3717a4ccb --- /dev/null +++ b/kernel/dev/interrupt/include/dev/interrupt.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +status_t mask_interrupt(unsigned int vector); +status_t unmask_interrupt(unsigned int vector); + +typedef enum handler_return (*int_handler)(void* arg); + +void register_int_handler(unsigned int vector, int_handler handler, void* arg); + +bool is_valid_interrupt(unsigned int vector, uint32_t flags); + +unsigned int remap_interrupt(unsigned int vector); + +__END_CDECLS diff --git a/kernel/dev/interrupt/include/dev/interrupt_event.h b/kernel/dev/interrupt/include/dev/interrupt_event.h new file mode 100644 index 000000000..be899243d --- /dev/null +++ b/kernel/dev/interrupt/include/dev/interrupt_event.h @@ -0,0 +1,36 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +typedef void* interrupt_event_t; + +/* Interrupt events are raised by hardware and can be waited upon by one or more threads. + * Rules: + * - An interrupt is unmasked when create_interrupt_event() is called for it for the first time + * - All threads that are waiting are woken up when an interrupt is raised. + * - Each thread must call interrupt_event_complete() before waiting again. + * - The interrupt is masked until all woken threads call interrupt_event_complete(). + */ + +// Creates an interrupt event if there is none for this vector. +#define INTERRUPT_EVENT_FLAG_REMAP_IRQ (0x1) +status_t interrupt_event_create(unsigned int vector, uint32_t flags, interrupt_event_t* ie); + +// Waits for an interrupt event. If there is a pending interrupt, this returns immediately. +// Otherwise, the thread is blocked until the next interrupt. +status_t interrupt_event_wait(interrupt_event_t ie); + +// Notifies the kernel that the interrupt has been processed by the calling thread. +void interrupt_event_complete(interrupt_event_t ie); + +__END_CDECLS diff --git a/kernel/dev/interrupt/interrupt_event.c b/kernel/dev/interrupt/interrupt_event.c new file mode 100644 index 000000000..621fd9dee --- /dev/null +++ b/kernel/dev/interrupt/interrupt_event.c @@ -0,0 +1,181 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define INTERRUPT_EVENT_MAGIC (0x696e7472) // "intr" + +typedef struct interrupt_event_impl { + int magic; + struct list_node node; + bool signalled; + int woken_count; + unsigned int vector; + uint flags; + wait_queue_t wait; +} interrupt_event_impl_t; + +#define INTERRUPT_EVENT_INITIAL_VALUE(iei, initial, _vector, _flags) \ +{ \ + .magic = INTERRUPT_EVENT_MAGIC, \ + .signalled = initial, \ + .woken_count = 0, \ + .vector = _vector, \ + .flags = _flags, \ + .wait = WAIT_QUEUE_INITIAL_VALUE((iei).wait), \ +} + +static struct list_node interrupt_event_list = LIST_INITIAL_VALUE(interrupt_event_list); + +static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE; + +static interrupt_event_impl_t *get_interrupt_event(unsigned int vector) +{ + DEBUG_ASSERT(spin_lock_held(&lock)); + + interrupt_event_impl_t *iei; + list_for_every_entry(&interrupt_event_list, iei, interrupt_event_impl_t, node) { + if (iei->vector == vector) { + return iei; + } + } + return NULL; +} + +static enum handler_return interrupt_event_int_handler(void *arg) +{ + interrupt_event_impl_t *iei = (interrupt_event_impl_t *)arg; + + THREAD_LOCK(state); + + DEBUG_ASSERT(!iei->signalled); + + mask_interrupt(iei->vector); + + // wait up threads waiting for this interrupt + iei->woken_count = wait_queue_wake_all(&iei->wait, false, NO_ERROR); + if (iei->woken_count <= 0) { + // if no threads are woken up, mark the interrupt as signalled + iei->signalled = true; + } + + THREAD_UNLOCK(state); + + // reschedule if there are any threads waiting for the interrupt + if (iei->woken_count > 0) { + return INT_RESCHEDULE; + } else { + return INT_NO_RESCHEDULE; + } +} + +status_t interrupt_event_create(unsigned int vector, uint32_t flags, interrupt_event_t *ie) +{ + if (flags & INTERRUPT_EVENT_FLAG_REMAP_IRQ) vector = remap_interrupt(vector); + + if (!is_valid_interrupt(vector, flags)) return ERR_INVALID_ARGS; + + interrupt_event_impl_t *iei = calloc(1, sizeof(interrupt_event_impl_t)); + // an entry could already exist for this vector even if we failed to allocate, don't + // error here + + spin_lock(&lock); + + // check if an entry already exists for this vector + interrupt_event_impl_t *existing = get_interrupt_event(vector); + if (existing == NULL) { + + if (iei) { + // initialize the new entry and add to the list if there is no existing entry + *iei = (interrupt_event_impl_t)INTERRUPT_EVENT_INITIAL_VALUE(*iei, false, vector, flags); + list_add_tail(&interrupt_event_list, &iei->node); + + register_int_handler(vector, &interrupt_event_int_handler, iei); + unmask_interrupt(vector); + + spin_unlock(&lock); + } else { + spin_unlock(&lock); + // fail if we cannot allocate and there is no existing entry + return ERR_NO_MEMORY; + } + + } else { + spin_unlock(&lock); + + // if an entry already exists, free the new entry and return the existing entry + free(iei); + iei = existing; + } + + *ie = (interrupt_event_t)(iei); + + return NO_ERROR; +} + +void interrupt_destroy(interrupt_event_t ie) +{ + interrupt_event_impl_t *iei = (interrupt_event_impl_t *)ie; + + DEBUG_ASSERT(iei->magic == INTERRUPT_EVENT_MAGIC); + + THREAD_LOCK(state); + + iei->magic = 0; + iei->signalled = false; + iei->flags = 0; + wait_queue_destroy(&iei->wait, true); + + THREAD_UNLOCK(state); +} + +status_t interrupt_event_wait(interrupt_event_t ie) +{ + status_t ret = NO_ERROR; + interrupt_event_impl_t *iei = (interrupt_event_impl_t *)ie; + + DEBUG_ASSERT(iei->magic == INTERRUPT_EVENT_MAGIC); + + THREAD_LOCK(state); + + if (iei->signalled) { + // has pending interrupt, fall through + iei->signalled = false; + } else { + ret = wait_queue_block(&iei->wait, INFINITE_TIME); + } + + THREAD_UNLOCK(state); + + return ret; +} + +void interrupt_event_complete(interrupt_event_t ie) +{ + interrupt_event_impl_t *iei = (interrupt_event_impl_t *)ie; + + DEBUG_ASSERT(iei->magic == INTERRUPT_EVENT_MAGIC); + + THREAD_LOCK(state); + + // TODO(yky): maybe we need a token + if (iei->woken_count > 0) + iei->woken_count--; + + if (iei->woken_count == 0) + unmask_interrupt(iei->vector); + + THREAD_UNLOCK(state); +} + diff --git a/kernel/dev/interrupt/rules.mk b/kernel/dev/interrupt/rules.mk new file mode 100644 index 000000000..3c17d10ed --- /dev/null +++ b/kernel/dev/interrupt/rules.mk @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/interrupt_event.c + +include make/module.mk diff --git a/kernel/dev/net/pcnet/pcnet.c b/kernel/dev/net/pcnet/pcnet.c new file mode 100644 index 000000000..7ae1ca9fb --- /dev/null +++ b/kernel/dev/net/pcnet/pcnet.c @@ -0,0 +1,623 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define PCNET_INIT_TIMEOUT 20000 +#define MAX_PACKET_SIZE 1518 + +#define QEMU_IRQ_BUG_WORKAROUND 1 + +struct pcnet_state { + int irq; + addr_t base; + + uint8_t padr[6]; + + struct init_block_32 *ib; + + struct rd_style3 *rd; + struct td_style3 *td; + + struct pbuf **rx_buffers; + struct pbuf **tx_buffers; + + /* queue accounting */ + int rd_head; + int td_head; + int td_tail; + + int rd_count; + int td_count; + + int tx_pending; + + mutex_t tx_lock; + + /* bottom half state */ + event_t event; + event_t initialized; + bool done; + + struct netstack_state *netstack_state; +}; + +static status_t pcnet_init(struct device *dev); +static status_t pcnet_read_pci_config(struct device *dev, pci_location_t *loc); + +static enum handler_return pcnet_irq_handler(void *arg); + +static int pcnet_thread(void *arg); +static bool pcnet_service_tx(struct device *dev); +static bool pcnet_service_rx(struct device *dev); + +static status_t pcnet_set_state(struct device *dev, struct netstack_state *state); +static ssize_t pcnet_get_hwaddr(struct device *dev, void *buf, size_t max_len); +static ssize_t pcnet_get_mtu(struct device *dev); + +static status_t pcnet_output(struct device *dev, struct pbuf *p); + +static struct netif_ops pcnet_ops = { + .std = { + .init = pcnet_init, + }, + + .set_state = pcnet_set_state, + .get_hwaddr = pcnet_get_hwaddr, + .get_mtu = pcnet_get_mtu, + + .output = pcnet_output, +}; + +DRIVER_EXPORT(netif, &pcnet_ops.std); + +static inline uint32_t pcnet_read_csr(struct device *dev, uint8_t rap) +{ + struct pcnet_state *state = dev->state; + + outpd(state->base + REG_RAP, rap); + return inpd(state->base + REG_RDP); +} + +static inline void pcnet_write_csr(struct device *dev, uint8_t rap, uint16_t data) +{ + struct pcnet_state *state = dev->state; + + outpd(state->base + REG_RAP, rap); + outpd(state->base + REG_RDP, data); +} + +static inline uint32_t pcnet_read_bcr(struct device *dev, uint8_t rap) +{ + struct pcnet_state *state = dev->state; + + outpd(state->base + REG_RAP, rap); + return inpd(state->base + REG_BDP); +} + +static inline void pcnet_write_bcr(struct device *dev, uint8_t rap, uint16_t data) +{ + struct pcnet_state *state = dev->state; + + outpd(state->base + REG_RAP, rap); + outpd(state->base + REG_BDP, data); +} + +static status_t pcnet_init(struct device *dev) +{ + status_t res = NO_ERROR; + pci_location_t loc; + int i; + + const struct platform_pcnet_config *config = dev->config; + + if (!config) + return ERR_NOT_CONFIGURED; + + if (pci_find_pci_device(&loc, config->device_id, config->vendor_id, config->index) != _PCI_SUCCESSFUL) + return ERR_NOT_FOUND; + + struct pcnet_state *state = calloc(1, sizeof(struct pcnet_state)); + if (!state) + return ERR_NO_MEMORY; + + dev->state = state; + + res = pcnet_read_pci_config(dev, &loc); + if (res) + goto error; + + for (i=0; i < 6; i++) + state->padr[i] = inp(state->base + i); + + LTRACEF("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", state->padr[0], state->padr[1], state->padr[2], + state->padr[3], state->padr[4], state->padr[5]); + + /* put the controller into 32bit wide mode by performing a 32bit write to CSR0 */ + outpd(state->base + 0, 0); + + /* stop the controller for configuration */ + pcnet_write_csr(dev, 0, CSR0_STOP); + + /* setup 32bit (style 3) structures, burst, all CSR4 bits valid, TDM1[29] is ADD_FCS */ + pcnet_write_csr(dev, 58, 3); + + /* DMA plus enable */ + pcnet_write_csr(dev, 4, pcnet_read_csr(dev, 4) | CSR4_DMAPLUS); + + /* allocate 128 tx and 128 rx descriptor rings */ + state->td_count = 128; + state->rd_count = 128; + state->td = memalign(16, state->td_count * DESC_SIZE); + state->rd = memalign(16, state->rd_count * DESC_SIZE); + + state->rx_buffers = calloc(state->rd_count, sizeof(struct pbuf *)); + state->tx_buffers = calloc(state->td_count, sizeof(struct pbuf *)); + + state->tx_pending = 0; + + if (!state->td || !state->rd || !state->tx_buffers || !state->rx_buffers) { + res = ERR_NO_MEMORY; + goto error; + } + + memset(state->td, 0, state->td_count * DESC_SIZE); + memset(state->rd, 0, state->rd_count * DESC_SIZE); + + /* allocate temporary init block space */ + state->ib = memalign(4, sizeof(struct init_block_32)); + if (!state->ib) { + res = ERR_NO_MEMORY; + goto error; + } + + LTRACEF("Init block addr: %p\n", state->ib); + + /* setup init block */ + state->ib->tlen = 7; // 128 descriptors + state->ib->rlen = 7; // 128 descriptors + state->ib->mode = 0; + + state->ib->ladr = ~0; + state->ib->tdra = (uint32_t) state->td; + state->ib->rdra = (uint32_t) state->rd; + + memcpy(state->ib->padr, state->padr, 6); + + /* load the init block address */ + pcnet_write_csr(dev, 1, (uint32_t) state->ib); + pcnet_write_csr(dev, 2, (uint32_t) state->ib >> 16); + + /* setup receive descriptors */ + for (i=0; i < state->rd_count; i++) { + //LTRACEF("Allocating pbuf %d\n", i); + struct pbuf *p = pbuf_alloc(PBUF_RAW, MAX_PACKET_SIZE, PBUF_RAM); + + state->rd[i].rbadr = (uint32_t) p->payload; + state->rd[i].bcnt = -p->tot_len; + state->rd[i].ones = 0xf; + state->rd[i].own = 1; + + state->rx_buffers[i] = p; + } + + mutex_init(&state->tx_lock); + + state->done = false; + event_init(&state->event, false, EVENT_FLAG_AUTOUNSIGNAL); + event_init(&state->initialized, false, 0); + + /* start up a thread to process packet activity */ + thread_resume(thread_create("[pcnet bh]", pcnet_thread, dev, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE)); + + register_int_handler(state->irq, pcnet_irq_handler, dev); + unmask_interrupt(state->irq); + +#if QEMU_IRQ_BUG_WORKAROUND + uint32_t irq = apic_io_isa_to_global(15); + register_int_handler(irq, pcnet_irq_handler, dev); + unmask_interrupt(irq); +#endif + + /* wait for initialization to complete */ + res = event_wait_timeout(&state->initialized, PCNET_INIT_TIMEOUT); + if (res) { + /* TODO: cancel bottom half thread and tear down device instance */ + LTRACEF("Failed to wait for IDON: %d\n", res); + return res; + } + + LTRACE_EXIT; + return res; + +error: + LTRACEF("Error: %d\n", res); + + if (state) { + free(state->td); + free(state->rd); + free(state->ib); + free(state->tx_buffers); + free(state->rx_buffers); + } + + free(state); + + return res; +} + +static status_t pcnet_read_pci_config(struct device *dev, pci_location_t *loc) +{ + status_t res = NO_ERROR; + pci_config_t config; + uint8_t *buf = (uint8_t *) &config; + unsigned i; + + DEBUG_ASSERT(dev->state); + + struct pcnet_state *state = dev->state; + + for (i=0; i < sizeof(config); i++) + pci_read_config_byte(loc, i, buf + i); + + LTRACEF("Resources:\n"); + + for (i=0; i < countof(config.base_addresses); i++) { + if (config.base_addresses[i] & 0x1) { + LTRACEF(" BAR %d I/O REG: %04x\n", i, config.base_addresses[i] & ~0x3); + + state->base = config.base_addresses[i] & ~0x3; + break; + } + } + + if (!state->base) { + res = ERR_NOT_CONFIGURED; + goto error; + } + + if (config.interrupt_line != 0xff) { + LTRACEF(" IRQ %u\n", config.interrupt_line); + + state->irq = apic_io_isa_to_global(config.interrupt_line); + } else { + res = ERR_NOT_CONFIGURED; + goto error; + } + + LTRACEF("Command: %04x\n", config.command); + LTRACEF("Status: %04x\n", config.status); + + pci_write_config_half(loc, PCI_CONFIG_COMMAND, + (config.command | PCI_COMMAND_IO_EN | PCI_COMMAND_BUS_MASTER_EN) & ~PCI_COMMAND_MEM_EN); + +error: + return res; +} + +static enum handler_return pcnet_irq_handler(void *arg) +{ + struct device *dev = arg; + struct pcnet_state *state = dev->state; + + mask_interrupt(state->irq); + +#if QEMU_IRQ_BUG_WORKAROUND + mask_interrupt(apic_io_isa_to_global(15)); +#endif + + event_signal(&state->event, false); + + return INT_RESCHEDULE; +} + +static int pcnet_thread(void *arg) +{ + DEBUG_ASSERT(arg); + + struct device *dev = arg; + struct pcnet_state *state = dev->state; + + /* kick off init, enable ints, and start operation */ + pcnet_write_csr(dev, 0, CSR0_INIT | CSR0_IENA | CSR0_STRT); + + while (!state->done) { + LTRACEF("Waiting for event.\n"); + //event_wait_timeout(&state->event, 5000); + event_wait(&state->event); + + int csr0 = pcnet_read_csr(dev, 0); + + /* disable interrupts at the controller */ + pcnet_write_csr(dev, 0, csr0 & ~CSR0_IENA); + + LTRACEF("CSR0 = %04x\n", csr0); + +#if LOCAL_TRACE + if (csr0 & CSR0_RINT) TRACEF("RINT\n"); + if (csr0 & CSR0_TINT) TRACEF("TINT\n"); +#endif + + if (csr0 & CSR0_IDON) { + LTRACEF("IDON\n"); + + /* free the init block that we no longer need */ + free(state->ib); + state->ib = NULL; + + event_signal(&state->initialized, true); + } + + if (csr0 & CSR0_ERR) { + LTRACEF("ERR\n"); + + /* TODO: handle errors, though not many need it */ + + /* clear flags, preserve necessary enables */ + pcnet_write_csr(dev, 0, csr0 & (CSR0_TXON | CSR0_RXON | CSR0_IENA)); + } + + bool again = !!(csr0 & (CSR0_RINT | CSR0_TINT)); + while (again) { + again = pcnet_service_tx(dev) | pcnet_service_rx(dev); + } + + /* enable interrupts at the controller */ + pcnet_write_csr(dev, 0, CSR0_IENA); + unmask_interrupt(state->irq); + +#if QEMU_IRQ_BUG_WORKAROUND + unmask_interrupt(apic_io_isa_to_global(15)); +#endif + } + + return 0; +} + +static bool pcnet_service_tx(struct device *dev) +{ + LTRACE_ENTRY; + + struct pcnet_state *state = dev->state; + + mutex_acquire(&state->tx_lock); + + struct td_style3 *td = &state->td[state->td_tail]; + + if (state->tx_pending && td->own == 0) { + struct pbuf *p = state->tx_buffers[state->td_tail]; + DEBUG_ASSERT(p); + + state->tx_buffers[state->td_tail] = NULL; + + LTRACEF("Retiring packet: td_tail=%d p=%p tot_len=%u\n", state->td_tail, p, p->tot_len); + + state->tx_pending--; + state->td_tail = (state->td_tail + 1) % state->td_count; + + if (td->err) { + LTRACEF("Descriptor error status encountered\n"); + hexdump8(td, sizeof(*td)); + } + + mutex_release(&state->tx_lock); + + pbuf_free(p); + + LTRACE_EXIT; + return true; + } else { + mutex_release(&state->tx_lock); + +#if 0 + LTRACEF("Nothing to do for TX.\n"); + for (int i=0; i < state->td_count; i++) + printf("%d ", state->td[i].own); + printf("\n"); +#endif + + LTRACE_EXIT; + return false; + } +} + +static bool pcnet_service_rx(struct device *dev) +{ + LTRACE_ENTRY; + + struct pcnet_state *state = dev->state; + + struct rd_style3 *rd = &state->rd[state->rd_head]; + + if (rd->own == 0) { + struct pbuf *p = state->rx_buffers[state->rd_head]; + DEBUG_ASSERT(p); + + LTRACEF("Processing RX descriptor %d\n", state->rd_head); + + if (rd->err) { + LTRACEF("Descriptor error status encountered\n"); + hexdump8(rd, sizeof(*rd)); + } else { + if (rd->mcnt <= p->tot_len) { + + pbuf_realloc(p, rd->mcnt); + +#if LOCAL_TRACE + LTRACEF("payload=%p len=%u\n", p->payload, p->tot_len); + hexdump8(p->payload, p->tot_len); +#endif + + class_netstack_input(dev, state->netstack_state, p); + + p = state->rx_buffers[state->rd_head] = pbuf_alloc(PBUF_RAW, MAX_PACKET_SIZE, PBUF_RAM); + } else { + LTRACEF("RX packet size error: mcnt = %u, buf len = %u\n", rd->mcnt, p->tot_len); + } + } + + memset(rd, 0, sizeof(*rd)); + memset(p->payload, 0, p->tot_len); + + rd->rbadr = (uint32_t) p->payload; + rd->bcnt = -p->tot_len; + rd->ones = 0xf; + rd->own = 1; + + state->rd_head = (state->rd_head + 1) % state->rd_count; + + LTRACE_EXIT; + return true; + } else { +#if 0 + LTRACEF("Nothing to do for RX: rd_head=%d.\n", state->rd_head); + for (int i=0; i < state->rd_count; i++) + printf("%d ", state->rd[i].own); + printf("\n"); +#endif + } + + LTRACE_EXIT; + return false; +} + +static status_t pcnet_set_state(struct device *dev, struct netstack_state *netstack_state) +{ + if (!dev) + return ERR_INVALID_ARGS; + + if (!dev->state) + return ERR_NOT_CONFIGURED; + + struct pcnet_state *state = dev->state; + + state->netstack_state = netstack_state; + + return NO_ERROR; +} + +static ssize_t pcnet_get_hwaddr(struct device *dev, void *buf, size_t max_len) +{ + if (!dev || !buf) + return ERR_INVALID_ARGS; + + if (!dev->state) + return ERR_NOT_CONFIGURED; + + struct pcnet_state *state = dev->state; + + memcpy(buf, state->padr, MIN(sizeof(state->padr), max_len)); + + return sizeof(state->padr); +} + +static ssize_t pcnet_get_mtu(struct device *dev) +{ + if (!dev) + return ERR_INVALID_ARGS; + + return 1500; +} + +static status_t pcnet_output(struct device *dev, struct pbuf *p) +{ + LTRACE_ENTRY; + + if (!dev || !p) + return ERR_INVALID_ARGS; + + if (!dev->state) + return ERR_NOT_CONFIGURED; + + status_t res = NO_ERROR; + struct pcnet_state *state = dev->state; + + mutex_acquire(&state->tx_lock); + + struct td_style3 *td = &state->td[state->td_head]; + + if (td->own) { + LTRACEF("TX descriptor ring full\n"); + res = ERR_NOT_READY; // maybe this should be ERR_NOT_ENOUGH_BUFFER? + goto done; + } + + pbuf_ref(p); + p = pbuf_coalesce(p, PBUF_RAW); + +#if LOCAL_TRACE + LTRACEF("Queuing packet: td_head=%d p=%p tot_len=%u\n", state->td_head, p, p->tot_len); + hexdump8(p->payload, p->tot_len); +#endif + + /* clear flags */ + memset(td, 0, sizeof(*td)); + + td->tbadr = (uint32_t) p->payload; + td->bcnt = -p->tot_len; + td->stp = 1; + td->enp = 1; + td->add_no_fcs = 1; + td->ones = 0xf; + + state->tx_buffers[state->td_head] = p; + state->tx_pending++; + + state->td_head = (state->td_head + 1) % state->td_count; + + td->own = 1; + + /* trigger tx */ + pcnet_write_csr(dev, 0, CSR0_TDMD); + +done: + mutex_release(&state->tx_lock); + LTRACE_EXIT; + return res; +} + +static const struct platform_pcnet_config pcnet0_config = { + .vendor_id = 0x1022, + .device_id = 0x2000, + .index = 0, +}; + +DEVICE_INSTANCE(netif, pcnet0, &pcnet0_config); + +static void pcnet_init_hook(uint level) +{ + device_init(device_get_by_name(netif, pcnet0)); + class_netif_add(device_get_by_name(netif, pcnet0)); +} + +LK_INIT_HOOK(pcnet, &pcnet_init_hook, LK_INIT_LEVEL_PLATFORM); + diff --git a/kernel/dev/net/pcnet/rules.mk b/kernel/dev/net/pcnet/rules.mk new file mode 100644 index 000000000..0d217d858 --- /dev/null +++ b/kernel/dev/net/pcnet/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/pcnet.c + +MODULE_DEPS := lib/lwip + +include make/module.mk diff --git a/kernel/dev/net/smc91c96/include/dev/net/smc91c96.h b/kernel/dev/net/smc91c96/include/dev/net/smc91c96.h new file mode 100644 index 000000000..9a640743a --- /dev/null +++ b/kernel/dev/net/smc91c96/include/dev/net/smc91c96.h @@ -0,0 +1,14 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef _DEV_NET_SMC91C96_H +#define _DEV_NET_SMC91C96_H + +void smc91c96_init(void); + +#endif + diff --git a/kernel/dev/net/smc91c96/rules.mk b/kernel/dev/net/smc91c96/rules.mk new file mode 100644 index 000000000..2a209b7c5 --- /dev/null +++ b/kernel/dev/net/smc91c96/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/smc91c96.c + +include make/module.mk diff --git a/kernel/dev/net/smc91c96/smc91c96.c b/kernel/dev/net/smc91c96/smc91c96.c new file mode 100644 index 000000000..26386f038 --- /dev/null +++ b/kernel/dev/net/smc91c96/smc91c96.c @@ -0,0 +1,56 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include "smc91c96_p.h" + +#if !defined(SMC91C96_BASE_ADDR) || !defined(SMC91C96_IRQ) +#error need to define SMC91C96_BASE_ADDR and SMC91C96_IRQ in project +#endif + +static addr_t smc91c96_base = SMC91C96_BASE_ADDR; +static uint8_t mac_addr[6]; + +#define SMC_REG16(reg) ((volatile uint16_t *)(smc91c96_base + (reg))) +#define SMC_REG8(reg) ((volatile uint8_t *)(smc91c96_base + (reg))) + +static inline void smc_bank(int bank) +{ + *SMC_REG16(SMC_BSR) = bank; +} + +void smc91c96_init(void) +{ + int i; + + TRACE; + + // try to detect it + if ((*SMC_REG16(SMC_BSR) & 0xff00) != 0x3300) { + TRACEF("didn't see smc91c96 chip at 0x%x\n", (unsigned int)smc91c96_base); + } + + // read revision + smc_bank(3); + TRACEF("detected, revision 0x%x\n", *SMC_REG16(SMC_REV)); + + // read in the mac address + smc_bank(1); + for (i=0; i < 6; i++) { + mac_addr[i] = *SMC_REG8(SMC_IAR0 + i); + } + TRACEF("mac address %02x:%02x:%02x:%02x:%02x:%02x\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + smc_bank(0); +} + diff --git a/kernel/dev/net/smc91c96/smc91c96_p.h b/kernel/dev/net/smc91c96/smc91c96_p.h new file mode 100644 index 000000000..082b1d0cf --- /dev/null +++ b/kernel/dev/net/smc91c96/smc91c96_p.h @@ -0,0 +1,65 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __SMC91C96_P_H +#define __SMC91C96_P_H + +// LAN91C96 stuffs + +/* registers */ + +#define SMC_BSR 14 + +/* bank 0 */ +#define SMC_TCR 0 +#define SMC_EPHSR 2 +#define SMC_RCR 4 +#define SMC_ECR 6 +#define SMC_MIR 8 +#define SMC_MCR 10 + +/* bank 1 */ +#define SMC_CR 0 +#define SMC_BAR 2 +#define SMC_IAR0 4 +#define SMC_IAR1 5 +#define SMC_IAR2 6 +#define SMC_IAR3 7 +#define SMC_IAR4 8 +#define SMC_IAR5 9 +#define SMC_GPR 10 +#define SMC_CTR 12 + +/* bank 2 */ +#define SMC_MMUCR 0 +#define SMC_AUTOTX 1 +#define SMC_PNR 2 +#define SMC_ARR 3 +#define SMC_FIFO 4 +#define SMC_PTR 6 +#define SMC_DATA0 8 +#define SMC_DATA1 10 +#define SMC_IST 12 +#define SMC_ACK 12 +#define SMC_MSK 13 + +/* bank 3 */ +#define SMC_MT0 0 +#define SMC_MT1 1 +#define SMC_MT2 2 +#define SMC_MT3 3 +#define SMC_MT4 4 +#define SMC_MT5 5 +#define SMC_MT6 6 +#define SMC_MT7 7 +#define SMC_MGMT 8 +#define SMC_REV 10 +#define SMC_ERCV 12 + + +#endif + diff --git a/kernel/dev/pcie/BUILD.gn b/kernel/dev/pcie/BUILD.gn new file mode 100644 index 000000000..0356623a5 --- /dev/null +++ b/kernel/dev/pcie/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_pcie") { + if (enable_pcie) { + defines = [ "WITH_DEV_PCIE=1" ] + } else { + defines = [ "WITH_DEV_PCIE=0" ] + } +} + +config("_pcie_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + configs = [ ":enable_pcie" ] +} + +module("pcie") { + public_configs = [ ":_pcie_config" ] + configs += [ "//kernel/kernel:enable_vm" ] + public = [ + "include/dev/pcie/pcie.h", + "include/dev/pcie/pcie_caps.h", + "include/dev/pcie/pcie_constants.h", + "include/dev/pcie/pcie_irqs.h", + ] + sources = [ + "debug.c", + "pcie.c", + "pcie_caps.c", + "pcie_irqs.c", + "pcie_priv.h", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] + public_deps = [ + "//kernel/dev/interrupt", + ] +} diff --git a/kernel/dev/pcie/debug.c b/kernel/dev/pcie/debug.c new file mode 100644 index 000000000..90a0277d6 --- /dev/null +++ b/kernel/dev/pcie/debug.c @@ -0,0 +1,673 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifdef WITH_LIB_CONSOLE + +#include +#include +#include +#include +#include + +#include "pcie_priv.h" + +/* Class code/Subclass code definitions taken from + * http://wiki.osdev.org/Pci#Class_Codes */ +typedef struct { + uint8_t class; + uint8_t subclass; + uint8_t prof_if_start; + uint8_t prof_if_end; + const char* desc; +} pci_dev_type_lut_entry_t; + +typedef struct lspci_params { + bool verbose; + bool tree; + uint indent_level; + uint bus_id; + uint dev_id; + uint func_id; + uint cfg_dump_amt; + bool force_dump_cfg; +} lspci_params_t; + +#define WILDCARD_ID (0xFFFFFFFF) + +#define LUT_ENTRY(_class, _subclass, _pif_start, _pif_end, _desc) { \ + .class = _class, \ + .subclass = _subclass, \ + .prof_if_start = _pif_start, \ + .prof_if_end = _pif_end, \ + .desc = _desc, \ +} + +#define LUT_ENTRY_ONE_PIF(_class, _subclass, _pif, _desc) \ + LUT_ENTRY(_class, _subclass, _pif, _pif, _desc) + +#define LUT_ENTRY_ALL_PIF(_class, _subclass, _desc) \ + LUT_ENTRY(_class, _subclass, 0x00, 0xFF, _desc) + +static const pci_dev_type_lut_entry_t PCI_DEV_TYPE_LUT[] = { + LUT_ENTRY_ONE_PIF(0x00, 0x00, 0x00, "Any device except for VGA-Compatible devices"), + LUT_ENTRY_ONE_PIF(0x00, 0x01, 0x00, "VGA-Compatible Device"), + LUT_ENTRY_ONE_PIF(0x01, 0x00, 0x00, "SCSI Bus Controller"), + LUT_ENTRY_ALL_PIF(0x01, 0x01, "IDE Controller"), + LUT_ENTRY_ONE_PIF(0x01, 0x02, 0x00, "Floppy Disk Controller"), + LUT_ENTRY_ONE_PIF(0x01, 0x03, 0x00, "IPI Bus Controller"), + LUT_ENTRY_ONE_PIF(0x01, 0x04, 0x00, "RAID Controller"), + LUT_ENTRY_ONE_PIF(0x01, 0x05, 0x20, "ATA Controller (Single DMA)"), + LUT_ENTRY_ONE_PIF(0x01, 0x05, 0x30, "ATA Controller (Chained DMA)"), + LUT_ENTRY_ONE_PIF(0x01, 0x06, 0x00, "Serial ATA (Vendor Specific Interface)"), + LUT_ENTRY_ONE_PIF(0x01, 0x06, 0x01, "Serial ATA (AHCI 1.0)"), + LUT_ENTRY_ONE_PIF(0x01, 0x07, 0x00, "Serial Attached SCSI (SAS)"), + LUT_ENTRY_ONE_PIF(0x01, 0x80, 0x00, "Other Mass Storage Controller"), + LUT_ENTRY_ONE_PIF(0x02, 0x00, 0x00, "Ethernet Controller"), + LUT_ENTRY_ONE_PIF(0x02, 0x01, 0x00, "Token Ring Controller"), + LUT_ENTRY_ONE_PIF(0x02, 0x02, 0x00, "FDDI Controller"), + LUT_ENTRY_ONE_PIF(0x02, 0x03, 0x00, "ATM Controller"), + LUT_ENTRY_ONE_PIF(0x02, 0x04, 0x00, "ISDN Controller"), + LUT_ENTRY_ONE_PIF(0x02, 0x05, 0x00, "WorldFip Controller"), + LUT_ENTRY_ALL_PIF(0x02, 0x06, "PICMG 2.14 Multi Computing"), + LUT_ENTRY_ONE_PIF(0x02, 0x80, 0x00, "Other Network Controller"), + LUT_ENTRY_ONE_PIF(0x03, 0x00, 0x00, "VGA-Compatible Controller"), + LUT_ENTRY_ONE_PIF(0x03, 0x00, 0x01, "8512-Compatible Controller"), + LUT_ENTRY_ONE_PIF(0x03, 0x01, 0x00, "XGA Controller"), + LUT_ENTRY_ONE_PIF(0x03, 0x02, 0x00, "3D Controller (Not VGA-Compatible)"), + LUT_ENTRY_ONE_PIF(0x03, 0x80, 0x00, "Other Display Controller"), + LUT_ENTRY_ONE_PIF(0x04, 0x00, 0x00, "Video Device"), + LUT_ENTRY_ONE_PIF(0x04, 0x01, 0x00, "Audio Device"), + LUT_ENTRY_ONE_PIF(0x04, 0x02, 0x00, "Computer Telephony Device"), + LUT_ENTRY_ONE_PIF(0x04, 0x80, 0x00, "Other Multimedia Device"), + LUT_ENTRY_ONE_PIF(0x05, 0x00, 0x00, "RAM Controller"), + LUT_ENTRY_ONE_PIF(0x05, 0x01, 0x00, "Flash Controller"), + LUT_ENTRY_ONE_PIF(0x05, 0x80, 0x00, "Other Memory Controller"), + LUT_ENTRY_ONE_PIF(0x06, 0x00, 0x00, "Host Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x01, 0x00, "ISA Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x02, 0x00, "EISA Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x03, 0x00, "MCA Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x04, 0x00, "PCI-to-PCI Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x04, 0x01, "PCI-to-PCI Bridge (Subtractive Decode)"), + LUT_ENTRY_ONE_PIF(0x06, 0x05, 0x00, "PCMCIA Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x06, 0x00, "NuBus Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x07, 0x00, "CardBus Bridge"), + LUT_ENTRY_ALL_PIF(0x06, 0x08, "RACEway Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x09, 0x40, "PCI-to-PCI Bridge (Semi-Transparent, Primary)"), + LUT_ENTRY_ONE_PIF(0x06, 0x09, 0x80, "PCI-to-PCI Bridge (Semi-Transparent, Secondary)"), + LUT_ENTRY_ONE_PIF(0x06, 0x0A, 0x00, "InfiniBrand-to-PCI Host Bridge"), + LUT_ENTRY_ONE_PIF(0x06, 0x80, 0x00, "Other Bridge Device"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x00, "Generic XT-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x01, "16450-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x02, "16550-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x03, "16650-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x04, "16750-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x05, "16850-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x06, "16950-Compatible Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x00, "Parallel Port"), + LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x01, "Bi-Directional Parallel Port"), + LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x02, "ECP 1.X Compliant Parallel Port"), + LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x03, "IEEE 1284 Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x01, 0xFE, "IEEE 1284 Target Device"), + LUT_ENTRY_ONE_PIF(0x07, 0x02, 0x00, "Multiport Serial Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x00, "Generic Modem"), + LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x01, "Hayes Compatible Modem (16450-Compatible Interface)"), + LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x02, "Hayes Compatible Modem (16550-Compatible Interface)"), + LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x03, "Hayes Compatible Modem (16650-Compatible Interface)"), + LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x04, "Hayes Compatible Modem (16750-Compatible Interface)"), + LUT_ENTRY_ONE_PIF(0x07, 0x04, 0x00, "IEEE 488.1/2 (GPIB) Controller"), + LUT_ENTRY_ONE_PIF(0x07, 0x05, 0x00, "Smart Card"), + LUT_ENTRY_ONE_PIF(0x07, 0x80, 0x00, "Other Communications Device"), + LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x00, "Generic 8259 PIC"), + LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x01, "ISA PIC"), + LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x02, "EISA PIC"), + LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x10, "I/O APIC Interrupt Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x20, "I/O(x) APIC Interrupt Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x01, 0x00, "Generic 8237 DMA Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x01, 0x01, "ISA DMA Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x01, 0x02, "EISA DMA Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x02, 0x00, "Generic 8254 System Timer"), + LUT_ENTRY_ONE_PIF(0x08, 0x02, 0x01, "ISA System Timer"), + LUT_ENTRY_ONE_PIF(0x08, 0x02, 0x02, "EISA System Timer"), + LUT_ENTRY_ONE_PIF(0x08, 0x03, 0x00, "Generic RTC Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x03, 0x01, "ISA RTC Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x04, 0x00, "Generic PCI Hot-Plug Controller"), + LUT_ENTRY_ONE_PIF(0x08, 0x80, 0x00, "Other System Peripheral"), + LUT_ENTRY_ONE_PIF(0x09, 0x00, 0x00, "Keyboard Controller"), + LUT_ENTRY_ONE_PIF(0x09, 0x01, 0x00, "Digitizer"), + LUT_ENTRY_ONE_PIF(0x09, 0x02, 0x00, "Mouse Controller"), + LUT_ENTRY_ONE_PIF(0x09, 0x03, 0x00, "Scanner Controller"), + LUT_ENTRY_ONE_PIF(0x09, 0x04, 0x00, "Gameport Controller (Generic)"), + LUT_ENTRY_ONE_PIF(0x09, 0x04, 0x10, "Gameport Contrlller (Legacy)"), + LUT_ENTRY_ONE_PIF(0x09, 0x80, 0x00, "Other Input Controller"), + LUT_ENTRY_ONE_PIF(0x0a, 0x00, 0x00, "Generic Docking Station"), + LUT_ENTRY_ONE_PIF(0x0a, 0x80, 0x00, "Other Docking Station"), + LUT_ENTRY_ONE_PIF(0x0b, 0x00, 0x00, "386 Processor"), + LUT_ENTRY_ONE_PIF(0x0b, 0x01, 0x00, "486 Processor"), + LUT_ENTRY_ONE_PIF(0x0b, 0x02, 0x00, "Pentium Processor"), + LUT_ENTRY_ONE_PIF(0x0b, 0x10, 0x00, "Alpha Processor"), + LUT_ENTRY_ONE_PIF(0x0b, 0x20, 0x00, "PowerPC Processor"), + LUT_ENTRY_ONE_PIF(0x0b, 0x30, 0x00, "MIPS Processor"), + LUT_ENTRY_ONE_PIF(0x0b, 0x40, 0x00, "Co-Processor"), + LUT_ENTRY_ONE_PIF(0x0c, 0x00, 0x00, "IEEE 1394 Controller (FireWire)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x00, 0x10, "IEEE 1394 Controller (1394 OpenHCI Spec)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x01, 0x00, "ACCESS.bus"), + LUT_ENTRY_ONE_PIF(0x0c, 0x02, 0x00, "SSA"), + LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x00, "USB (Universal Host Controller Spec)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x10, "USB (Open Host Controller Spec)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x20, "USB2 Host Controller (Intel EHCI)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x30, "USB3 XHCI Controller"), + LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x80, "Unspecified USB Controller"), + LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0xFE, "USB (Not Host Controller)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x04, 0x00, "Fibre Channel"), + LUT_ENTRY_ONE_PIF(0x0c, 0x05, 0x00, "SMBus"), + LUT_ENTRY_ONE_PIF(0x0c, 0x06, 0x00, "InfiniBand"), + LUT_ENTRY_ONE_PIF(0x0c, 0x07, 0x00, "IPMI SMIC Interface"), + LUT_ENTRY_ONE_PIF(0x0c, 0x07, 0x01, "IPMI Kybd Controller Style Interface"), + LUT_ENTRY_ONE_PIF(0x0c, 0x07, 0x02, "IPMI Block Transfer Interface"), + LUT_ENTRY_ONE_PIF(0x0c, 0x08, 0x00, "SERCOS Interface Standard (IEC 61491)"), + LUT_ENTRY_ONE_PIF(0x0c, 0x09, 0x00, "CANbus"), + LUT_ENTRY_ONE_PIF(0x0d, 0x00, 0x00, "iRDA Compatible Controller"), + LUT_ENTRY_ONE_PIF(0x0d, 0x01, 0x00, "Consumer IR Controller"), + LUT_ENTRY_ONE_PIF(0x0d, 0x10, 0x00, "RF Controller"), + LUT_ENTRY_ONE_PIF(0x0d, 0x11, 0x00, "Bluetooth Controller"), + LUT_ENTRY_ONE_PIF(0x0d, 0x12, 0x00, "Broadband Controller"), + LUT_ENTRY_ONE_PIF(0x0d, 0x20, 0x00, "Ethernet Controller (802.11a)"), + LUT_ENTRY_ONE_PIF(0x0d, 0x21, 0x00, "Ethernet Controller (802.11b)"), + LUT_ENTRY_ONE_PIF(0x0d, 0x80, 0x00, "Other Wireless Controller"), + LUT_ENTRY (0x0e, 0x00, 0x01, 0xFF, "I20 Architecture"), + LUT_ENTRY_ONE_PIF(0x0e, 0x00, 0x00, "Message FIFO"), + LUT_ENTRY_ONE_PIF(0x0f, 0x01, 0x00, "TV Controller"), + LUT_ENTRY_ONE_PIF(0x0f, 0x02, 0x00, "Audio Controller"), + LUT_ENTRY_ONE_PIF(0x0f, 0x03, 0x00, "Voice Controller"), + LUT_ENTRY_ONE_PIF(0x0f, 0x04, 0x00, "Data Controller"), + LUT_ENTRY_ONE_PIF(0x10, 0x00, 0x00, "Network and Computing Encrpytion/Decryption"), + LUT_ENTRY_ONE_PIF(0x10, 0x10, 0x00, "Entertainment Encryption/Decryption"), + LUT_ENTRY_ONE_PIF(0x10, 0x80, 0x00, "Other Encryption/Decryption"), + LUT_ENTRY_ONE_PIF(0x11, 0x00, 0x00, "DPIO Modules"), + LUT_ENTRY_ONE_PIF(0x11, 0x01, 0x00, "Performance Counters"), + LUT_ENTRY_ONE_PIF(0x11, 0x10, 0x00, "Communications Syncrhonization"), + LUT_ENTRY_ONE_PIF(0x11, 0x20, 0x00, "Management Card"), + LUT_ENTRY_ONE_PIF(0x11, 0x80, 0x00, "Other Data Acquisition/Signal Processing Controller"), +}; + +#undef LUT_ENTRY +#undef LUT_ENTRY_ONE_PIF +#undef LUT_ENTRY_ALL_PIF + +static const char* pci_class_code_to_string(uint8_t class_code) +{ + switch (class_code) { + case 0x00: return "Pre-Class Code Device"; + case 0x01: return "Mass Storage Controller"; + case 0x02: return "Network Controller"; + case 0x03: return "Display Controller"; + case 0x04: return "Multimedia Controller"; + case 0x05: return "Memory Controller"; + case 0x06: return "Bridge Device"; + case 0x07: return "Simple Communication Controller"; + case 0x08: return "Base System Peripheral"; + case 0x09: return "Input Device"; + case 0x0A: return "Docking Station"; + case 0x0B: return "Processor"; + case 0x0C: return "Serial Bus Controller"; + case 0x0D: return "Wireless Controller"; + case 0x0E: return "Intelligent I/O Controller"; + case 0x0F: return "Satellite Communication Controller"; + case 0x10: return "Encryption/Decryption Controller"; + case 0x11: return "Data Acquisition or Signal Processing Controller"; + case 0xFF: return "Vendor"; + default: return ""; + } +} + +static const char* pci_device_type(const pcie_common_state_t* node) +{ + // TODO(johngro): It might be a good idea, some day, to make this something + // better than an O(n) search. + DEBUG_ASSERT(node); + + // If this is a PCIe style bridge with a specific device type spelled out in + // its PCI Express Capabilities structure, use that to provide the type + // string. + switch (node->pcie_caps.devtype) { + case PCIE_DEVTYPE_RC_ROOT_PORT: return "PCIe Root Port"; + case PCIE_DEVTYPE_SWITCH_UPSTREAM_PORT: return "PCIe Upstream Switch Port"; + case PCIE_DEVTYPE_SWITCH_DOWNSTREAM_PORT: return "PCIe Downstream Switch Port"; + case PCIE_DEVTYPE_PCIE_TO_PCI_BRIDGE: return "PCIe-to-PCI Bridge"; + case PCIE_DEVTYPE_PCI_TO_PCIE_BRIDGE: return "PCI-to-PCIe Bridge"; + default: break; + } + + for (size_t i = 0; i < countof(PCI_DEV_TYPE_LUT); ++i) { + const pci_dev_type_lut_entry_t* entry = PCI_DEV_TYPE_LUT + i; + + if ((node->class_id == entry->class) && + (node->subclass == entry->subclass) && + (node->prog_if >= entry->prof_if_start) && + (node->prog_if <= entry->prof_if_end)) + return entry->desc; + } + + return pci_class_code_to_string(node->class_id); +} + +static void do_lspci_indent(uint level) { + while (level--) + printf(" "); +} +#define LSPCI_PRINTF(_fmt, ...) \ + do { \ + do_lspci_indent(params->indent_level); \ + printf(_fmt, ##__VA_ARGS__); \ + } while (0) + +static void dump_pcie_hdr(const pcie_common_state_t* node, lspci_params_t* params) +{ + DEBUG_ASSERT(node && params); + LSPCI_PRINTF("[%02x:%02x.%01x] - VID 0x%04x DID 0x%04x :: %s", + node->bus_id, node->dev_id, node->func_id, + node->vendor_id, node->device_id, + pci_device_type(node)); + + const pcie_device_state_t* device = pcie_downcast_to_device(node); + if (device && device->driver) { + printf(" [driver = \"%s\"]", pcie_driver_name(device->driver)); + } + + printf("\n"); +} + +static void dump_pcie_bars(const pcie_common_state_t* node, + lspci_params_t* params, + uint bar_count) +{ + pci_config_t* cfg = &node->cfg->base; + + DEBUG_ASSERT(bar_count <= countof(cfg->base_addresses)); + DEBUG_ASSERT(bar_count <= countof(node->bars)); + for (uint i = 0; i < bar_count; ++i) { + DEBUG_ASSERT(i < bar_count); + + LSPCI_PRINTF("Base Addr[%u] : 0x%08x", i, pcie_read32(&cfg->base_addresses[i])); + + const pcie_bar_info_t* info = pcie_get_bar_info(node, i); + if (!info) { + printf("\n"); + continue; + } + + printf(" :: paddr 0x%llx size 0x%llx%s%s %s\n", + info->bus_addr, + info->size, + info->is_prefetchable ? " prefetchable" : "", + info->is_mmio ? (info->is_64bit ? " 64-bit" : " 32-bit") : "", + info->is_mmio ? "MMIO" : "PIO"); + } +} + +static void dump_pcie_common(const pcie_common_state_t* node, lspci_params_t* params) +{ + pci_config_t* cfg = &node->cfg->base; + uint8_t base_class = pcie_read8(&cfg->base_class); + + LSPCI_PRINTF("Command : 0x%04x\n", pcie_read16(&cfg->command)); + LSPCI_PRINTF("Status : 0x%04x\n", pcie_read16(&cfg->status)); + LSPCI_PRINTF("Rev ID : 0x%02x\n", pcie_read8(&cfg->revision_id_0)); + LSPCI_PRINTF("Prog Iface : 0x%02x\n", pcie_read8(&cfg->program_interface)); + LSPCI_PRINTF("Sub Class : 0x%02x\n", pcie_read8(&cfg->sub_class)); + LSPCI_PRINTF("Base Class : 0x%02x %s\n", base_class, + pci_class_code_to_string(base_class)); + LSPCI_PRINTF("Cache Line Sz : 0x%02x\n", pcie_read8(&cfg->cache_line_size)); + LSPCI_PRINTF("Latency Timer : 0x%02x\n", pcie_read8(&cfg->latency_timer)); + LSPCI_PRINTF("Header Type : 0x%02x\n", pcie_read8(&cfg->header_type)); + LSPCI_PRINTF("BIST : 0x%02x\n", pcie_read8(&cfg->bist)); +} + +static void dump_pcie_standard(const pcie_common_state_t* node, lspci_params_t* params) +{ + pci_config_t* cfg = &node->cfg->base; + LSPCI_PRINTF("Cardbus CIS : 0x%08x\n", pcie_read32(&cfg->cardbus_cis_ptr)); + LSPCI_PRINTF("Subsystem VID : 0x%04x\n", pcie_read16(&cfg->subsystem_vendor_id)); + LSPCI_PRINTF("Subsystem ID : 0x%04x\n", pcie_read16(&cfg->subsystem_id)); + LSPCI_PRINTF("Exp ROM addr : 0x%08x\n", pcie_read32(&cfg->expansion_rom_address)); + LSPCI_PRINTF("Cap Ptr : 0x%02x\n", pcie_read8(&cfg->capabilities_ptr)); + LSPCI_PRINTF("IRQ line : 0x%02x\n", pcie_read8(&cfg->interrupt_line)); + LSPCI_PRINTF("IRQ pin : 0x%02x\n", pcie_read8(&cfg->interrupt_pin)); + LSPCI_PRINTF("Min Grant : 0x%02x\n", pcie_read8(&cfg->min_grant)); + LSPCI_PRINTF("Max Latency : 0x%02x\n", pcie_read8(&cfg->max_latency)); + +} + +static void dump_pcie_bridge(const pcie_common_state_t* node, lspci_params_t* params) +{ + pci_to_pci_bridge_config_t* bcfg = (pci_to_pci_bridge_config_t*)(&node->cfg->base); + + LSPCI_PRINTF("P. Bus ID : 0x%02x\n", pcie_read8(&bcfg->primary_bus_id)); + LSPCI_PRINTF("S. Bus Range : [0x%02x, 0x%02x]\n", + pcie_read8(&bcfg->secondary_bus_id), + pcie_read8(&bcfg->subordinate_bus_id)); + LSPCI_PRINTF("S. Latency Timer : 0x%02x\n", pcie_read8(&bcfg->secondary_latency_timer)); + LSPCI_PRINTF("IO Base : 0x%02x\n", pcie_read8(&bcfg->io_base)); + LSPCI_PRINTF("IO Base Upper : 0x%04x\n", pcie_read16(&bcfg->io_base_upper)); + LSPCI_PRINTF("IO Limit : 0x%02x\n", pcie_read8(&bcfg->io_limit)); + LSPCI_PRINTF("IO Limit Upper : 0x%04x\n", pcie_read16(&bcfg->io_limit_upper)); + LSPCI_PRINTF("Secondary Status : 0x%04x\n", pcie_read16(&bcfg->secondary_status)); + LSPCI_PRINTF("Memory Limit : 0x%04x\n", pcie_read16(&bcfg->memory_limit)); + LSPCI_PRINTF("Memory Base : 0x%04x\n", pcie_read16(&bcfg->memory_base)); + LSPCI_PRINTF("PFMem Base : 0x%04x\n", pcie_read16(&bcfg->prefetchable_memory_base)); + LSPCI_PRINTF("PFMem Base Upper : 0x%08x\n", pcie_read32(&bcfg->prefetchable_memory_base_upper)); + LSPCI_PRINTF("PFMem Limit : 0x%04x\n", pcie_read16(&bcfg->prefetchable_memory_limit)); + LSPCI_PRINTF("PFMem Limit Upper : 0x%08x\n", pcie_read32(&bcfg->prefetchable_memory_limit_upper)); + LSPCI_PRINTF("Capabilities Ptr : 0x%02x\n", pcie_read8(&bcfg->capabilities_ptr)); + LSPCI_PRINTF("Exp ROM Address : 0x%08x\n", pcie_read32(&bcfg->expansion_rom_address)); + LSPCI_PRINTF("Interrupt Line : 0x%02x\n", pcie_read8(&bcfg->interrupt_line)); + LSPCI_PRINTF("Interrupt Pin : 0x%02x\n", pcie_read8(&bcfg->interrupt_pin)); + LSPCI_PRINTF("Bridge Control : 0x%04x\n", pcie_read16(&bcfg->bridge_control)); + +} + +static void dump_pcie_raw_config(uint amt, void* kvaddr, uint64_t phys) { + printf("%u bytes of raw config (kvaddr %p; phys 0x%llx)\n", amt, kvaddr, phys); + hexdump8(kvaddr, amt); +} + +static size_t dump_pcie_node(const pcie_common_state_t* node, lspci_params_t* params) +{ + DEBUG_ASSERT(node && params); + + bool match = (((params->bus_id == WILDCARD_ID) || (params->bus_id == node->bus_id)) && + ((params->dev_id == WILDCARD_ID) || (params->dev_id == node->dev_id)) && + ((params->func_id == WILDCARD_ID) || (params->func_id == node->func_id))); + + + /* Dump the header if this device matches our filter, or if it is a bridge + * and we are in tree dump mode */ + if (match || (params->tree && pcie_downcast_to_bridge(node))) + dump_pcie_hdr(node, params); + + /* Only dump details if we are in verbose mode and this device matches our + * filter */ + if (match && params->verbose) { + params->indent_level += 2; + + dump_pcie_common(node, params); + + uint8_t header_type = pcie_read8(&node->cfg->base.header_type) & PCI_HEADER_TYPE_MASK; + switch (header_type) { + case PCI_HEADER_TYPE_STANDARD: + dump_pcie_bars(node, params, 6); + dump_pcie_standard(node, params); + break; + + case PCI_HEADER_TYPE_PCI_BRIDGE: + dump_pcie_bars(node, params, 2); + dump_pcie_bridge(node, params); + break; + + case PCI_HEADER_TYPE_CARD_BUS: + printf("TODO : Implemnt CardBus Config header register dump\n"); + break; + + default: + printf("Unknown Header Type (0x%02x)\n", header_type); + break; + } + + params->indent_level -= 2; + } + + if (match && params->cfg_dump_amt) + dump_pcie_raw_config(params->cfg_dump_amt, node->cfg, (uint64_t)node->cfg_phys); + + return match ? 1 : 0; +} + +static size_t do_lspci(const pcie_common_state_t* node, lspci_params_t* params, bool show_node) +{ + size_t found = 0; + DEBUG_ASSERT(node && params); + + if (show_node) + found += dump_pcie_node(node, params); + + const pcie_bridge_state_t* bridge = pcie_downcast_to_bridge(node); + if (bridge) { + if (params->tree) { + params->indent_level++; + + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + const pcie_common_state_t* downstream = bridge->downstream[i]; + + if (downstream) + found += do_lspci(downstream, params, true); + } + + params->indent_level--; + } else { + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + const pcie_common_state_t* downstream = bridge->downstream[i]; + if (downstream) + found += dump_pcie_node(downstream, params); + } + + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + const pcie_common_state_t* downstream = bridge->downstream[i]; + if (downstream) + found += do_lspci(downstream, params, false); + } + } + } + + return found; +} + +static int cmd_lspci(int argc, const cmd_args *argv) +{ + lspci_params_t params; + size_t found; + uint filter_ndx = 0; + + memset(¶ms, 0, sizeof(params)); + params.bus_id = WILDCARD_ID; + params.dev_id = WILDCARD_ID; + params.func_id = WILDCARD_ID; + + for (int i = 1; i < argc; ++i) { + bool confused = false; + + if (argv[i].str[0] == '-') { + const char* c = argv[i].str + 1; + if (!(*c)) + confused = true; + + while (!confused && *c) { + switch (*c) { + case 't': + params.tree = true; + break; + + case 'f': + if (params.cfg_dump_amt < PCIE_BASE_CONFIG_SIZE) + params.cfg_dump_amt = PCIE_BASE_CONFIG_SIZE; + params.force_dump_cfg = true; + break; + + case 'e': + if (params.cfg_dump_amt < PCIE_EXTENDED_CONFIG_SIZE) + params.cfg_dump_amt = PCIE_EXTENDED_CONFIG_SIZE; + // deliberate fall-thru + + case 'c': + if (params.cfg_dump_amt < PCIE_BASE_CONFIG_SIZE) + params.cfg_dump_amt = PCIE_BASE_CONFIG_SIZE; + // deliberate fall-thru + + case 'l': + params.verbose = true; + break; + + default: + confused = true; + break; + } + + c++; + } + } else { + switch (filter_ndx) { + case 0: + params.bus_id = argv[i].i; + if (params.bus_id >= PCIE_MAX_BUSSES) + confused = true; + break; + + case 1: + params.dev_id = argv[i].i; + if (params.dev_id >= PCIE_MAX_DEVICES_PER_BUS) + confused = true; + break; + + case 2: + params.func_id = argv[i].i; + if (params.func_id >= PCIE_MAX_FUNCTIONS_PER_DEVICE) + confused = true; + break; + + default: + confused = true; + break; + } + + filter_ndx++; + } + + if (confused) { + printf("usage: %s [-t] [-l] [] [] []\n", argv[0].str); + printf(" -t : Dump using tree formating\n"); + printf(" -l : Be verbose when dumping info about discovered devices.\n"); + printf(" -c : Dump raw standard config (implies -l)\n"); + printf(" -e : Dump raw extended config (implies -l -c)\n"); + printf(" -f : Force dump at least standard config, even if the device didn't " + "enumerate (requires a full BDF address)\n"); + return NO_ERROR; + } + } + + const pcie_bus_driver_state_t* drv = pcie_get_bus_driver_state(); + DEBUG_ASSERT(drv); + + if (!drv->host_bridge) { + printf("No host bridge discovered...\n"); + return NO_ERROR; + } + + found = do_lspci(&drv->host_bridge->common, ¶ms, true); + + if (!found && params.force_dump_cfg && + (params.bus_id != WILDCARD_ID) && + (params.dev_id != WILDCARD_ID) && + (params.func_id != WILDCARD_ID)) { + pcie_config_t* cfg; + uint64_t cfg_phys; + + cfg = pcie_get_config(drv, &cfg_phys, params.bus_id, params.dev_id, params.func_id); + if (!cfg) { + printf("Config space for %02x:%02x.%01x not mapped by bus driver!\n", + params.bus_id, params.dev_id, params.func_id); + } else { + dump_pcie_raw_config(params.cfg_dump_amt, cfg, cfg_phys); + } + } else { + printf("PCIe scan discovered %zu device%s\n", found, (found == 1) ? "" : "s"); + } + + return NO_ERROR; +} + +static int cmd_pcishutdown(int argc, const cmd_args *argv) +{ + bool confused = false; + uint bus_id, dev_id, func_id; + + if (argc == 4) { + bus_id = argv[1].i; + dev_id = argv[2].i; + func_id = argv[3].i; + + if ((bus_id >= PCIE_MAX_BUSSES) || + (dev_id >= PCIE_MAX_DEVICES_PER_BUS) || + (func_id >= PCIE_MAX_FUNCTIONS_PER_DEVICE)) + confused = true; + } else { + confused = true; + } + + if (confused) { + printf("usage: %s \n", argv[0].str); + return NO_ERROR; + } + + pcie_bus_driver_state_t* drv = pcie_get_bus_driver_state(); + pcie_device_state_t* device = NULL; + pcie_device_state_t* tmp; + + DEBUG_ASSERT(drv); + + /* + * TODO(johngro) : Remove this soon. + * + * Now that we are adding user mode drivers, triggering this from the debug + * console is fundamentally unsafe. Shutting down a device out from + * underneath a user-mode driver is guaranteed to cause Very Bad things to + * happen. Also, if a user mode device driver shuts down and unclaims its + * device after we have picked it out of this list, but before we attempt to + * shut the device down ourselves, we are guaranteed to explode. + */ + mutex_acquire(&drv->claimed_devices_lock); + list_for_every_entry(&drv->claimed_devices, tmp, pcie_device_state_t, claimed_device_node) { + if ((tmp->common.bus_id == bus_id) && + (tmp->common.dev_id == dev_id) && + (tmp->common.func_id == func_id)) { + device = tmp; + break; + } + } + mutex_release(&drv->claimed_devices_lock); + + if (!device) { + printf("Failed to find claimed PCI device %02x:%02x.%x. " + "Are you sure it has a loaded driver?\n", bus_id, dev_id, func_id); + } else { + printf("Shutting down PCI device %02x:%02x.%x (%s)...\n", + bus_id, dev_id, func_id, pcie_driver_name(device->driver)); + pcie_shutdown_device(device); + printf("done\n"); + } + + return NO_ERROR; +} + +static int cmd_pcirescan(int argc, const cmd_args *argv) +{ + pcie_scan_and_start_devices(pcie_get_bus_driver_state()); + return NO_ERROR; +} + +STATIC_COMMAND_START +STATIC_COMMAND("lspci", + "Enumerate the devices detected in PCIe ECAM space", + &cmd_lspci) +STATIC_COMMAND("pcishutdown", + "Shutdown the specified PCIe device instance", + &cmd_pcishutdown) +STATIC_COMMAND("pcirescan", + "Force a rescan of the PCIe configuration space, matching drivers to unclaimed " + "devices as we go. Then attempt to start all newly claimed devices.", + &cmd_pcirescan) +STATIC_COMMAND_END(pcie); + +#endif // WITH_LIB_CONSOLE diff --git a/kernel/dev/pcie/include/dev/pcie.h b/kernel/dev/pcie/include/dev/pcie.h new file mode 100644 index 000000000..c604641b4 --- /dev/null +++ b/kernel/dev/pcie/include/dev/pcie.h @@ -0,0 +1,473 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +typedef struct pcie_config { + pci_config_t base; + uint8_t __pad0[PCIE_BASE_CONFIG_SIZE - sizeof(pci_config_t)]; + uint8_t extended[PCIE_EXTENDED_CONFIG_SIZE - PCIE_BASE_CONFIG_SIZE]; +} __PACKED pcie_config_t; + +/* Fwd decls */ +struct pcie_common_state; +struct pcie_bridge_state; +struct pcie_bus_driver_state; +struct pcie_device_state; +struct pcie_driver_registration; +struct pcie_legacy_irq_handler_state; + +/* + * struct used to fetch information about a configured base address register + */ +typedef struct pcie_bar_info { + struct pcie_common_state* dev; + + uint64_t size; + uint64_t bus_addr; + bool is_mmio; + bool is_64bit; + bool is_prefetchable; + uint first_bar_reg; + bool is_allocated; +} pcie_bar_info_t; + +/** + * A struct used to describe a sub-range of the address space of one of the + * system buses. Typically, this is a range of the main system bus, but it + * might also be the I/O space bus on an architecture like x86/x64 + * + * @param bus_addr The base address of the I/O range on the appropriate bus. + * For MMIO or memory mapped config, this will be an address on the main system + * bus. For PIO regions, this may also be a an address on the main system bus + * for architectures which do not have a sepearate I/O bus (ARM, MIPS, etc..). + * For systems which do have a separate I/O bus (x86/x64) this should be the + * base address in I/O space. + * + * @param size The size of the range in bytes. + */ +typedef struct pcie_io_range { + uint64_t bus_addr; + size_t size; +} pcie_io_range_t; + +/** + * A struct used to describe a range of the Extended Configuration Access + * Mechanism (ECAM) region. + * + * @param io_range The MMIO range which describes the region of the main system + * bus where this slice of the ECAM resides. + * @param bus_start The ID of the first bus covered by this slice of ECAM. + * @param bus_end The ID of the last bus covered by this slice of ECAM. + */ +typedef struct pcie_ecam_range { + pcie_io_range_t io_range; + uint8_t bus_start; + uint8_t bus_end; +} pcie_ecam_range_t; + +/** + * A struct used to describe the resources to be used by the PCIe subsystem for + * discovering and configuring PCIe controllers, bridges and devices. + */ +typedef struct pcie_init_info { + /** + * A pointer to an array of pcie_ecam_range_t structures which describe the + * ECAM regions available to the subsytem. The windows must... + * -# Be listed in ascending bus_start order. + * -# Contain a range which describes Bus #0 + * -# Consist of non-overlapping [bus_start, bus_end] ranges. + * -# Have a sufficiently sized IO range to contain the configuration + * structures for the given bus range. Each bus requries 4KB * 8 + * functions * 32 devices worth of config space. + */ + const pcie_ecam_range_t* ecam_windows; + + /** The number of elements in the ecam_windows array. */ + size_t ecam_window_count; + + /** + * The low-memory region of MMIO space. The physical addresses for the + * range must exist entirely below the 4GB mark on the system bus. 32-bit + * MMIO regions described by device BARs must be allocated from this window. + */ + pcie_io_range_t mmio_window_lo; + + /** + * The high-memory region of MMIO space. This range is optional; set + * mmio_window_hi.size to zero if there is no high memory range on this + * system. 64-bit MMIO regions described by device BARs will be + * preferentally allocated from this window. + */ + pcie_io_range_t mmio_window_hi; + + /** + * The PIO space. On x86/x64 systems, this will describe the regions of the + * 16-bit IO address space which are availavle to be allocated to PIO BARs + * for PCI devices. On other systems, this describes the physical address + * space that the system reserves for producing PIO cycles on PCI. Note; + * this region must exist in low memory (below the 4GB mark) + */ + pcie_io_range_t pio_window; + + /** Platform-specific legacy IRQ remapping. @see platform_legacy_irq_swizzle_t */ + platform_legacy_irq_swizzle_t legacy_irq_swizzle; + + /** + * Routines for allocating and freeing blocks of IRQs for use with MSI or + * MSI-X, and for registering handlers for IRQs within blocks. May be NULL + * if the platform's interrupts controller is not compatible with MSI. + * @note Either all of these routines must be provided, or none of them. + */ + platform_alloc_msi_block_t alloc_msi_block; + platform_free_msi_block_t free_msi_block; + platform_register_msi_handler_t register_msi_handler; + + /** + * Routine for masking/unmasking MSI IRQ handlers. May be NULL if the + * platform is incapable of masking individual MSI handlers. + */ + platform_mask_unmask_msi_t mask_unmask_msi; +} pcie_init_info_t; + +/* Function table registered by a device driver. Method requirements and device + * lifecycle are described below. + * + * + pcie_probe_fn + * Called by the bus driver during bus scanning/probing to determine which + * registered driver (if any) wishes to claim and manage a device. Drivers + * who wish to claim a device must return a non-NULL void* context pointer + * which will be made available as the driver_ctx member of the + * pcie_device_state_t structure and provided to all subsequent callbacks via + * the pci_device member. + * + * + startup_hook + * Called by the bus driver in order to start a device after it has been + * claimed. All MMIO/PIO registers will be allocated, but un-mapped in at the + * time the startup hook is invoked, and the device IRQ will be masked. + * Devices should not enable their IRQ during startup. Device IRQs will be + * automatically enabled at the PCI level following a successful startup if a + * device has registered an IRQ hook. + * + * + shutdown_hook + * Called by the bus driver on a successfully started device when it is time + * to shut down. Device registers are guaranteed to be mapped when shutdown + * is called. Shutdown will not be called for devices who fail to start-up, + * so devices which encounter problems during start-up should take care to + * leave their device in a quiescent state before returning their error code + * to the bus driver. Devices may use pcie_enable_irq to mask their IRQ and + * synchronize with the bus's IRQ dispatcher at the appropriate point in their + * shutdown sequence. + * + * + release_hook + * Called on a non-started device when it is time to release any resources + * which may have been allocated during its life cycle. At a minimum, drivers + * who dynamically allocate context during pcie_probe_fn should register a + * release_hook in order to clean up their dynamically allocated resources. A + * driver's release hook will always be called for a device which was claimed + * during probe, even if the startup_hook was never called (possibly due to + * bus level resource exhaustion). + */ +typedef struct pcie_driver_fn_table { + void* (*pcie_probe_fn) (struct pcie_device_state* pci_device); + status_t (*pcie_startup_fn) (struct pcie_device_state* pci_device); + void (*pcie_shutdown_fn)(struct pcie_device_state* pci_device); + void (*pcie_release_fn) (struct pcie_device_state* pci_device); +} pcie_driver_fn_table_t; + +typedef struct pcie_driver_registration { + const char* name; + const pcie_driver_fn_table_t* fn_table; +} pcie_driver_registration_t; + +/* An enumeration used to flag whether a node in the system-wide bridge/device + * tree is a bridge or a device */ +typedef enum { + PCIE_INVALID_NODE_TYPE = 0, + PCIE_BRIDGE, + PCIE_DEVICE, +} pcie_node_type_t; + +/* + * Struct used to hold the information common to all bridges and devices in the + * tree describing the PCIe complex for a system. + */ +typedef struct pcie_common_state { + pcie_config_t* cfg; // Pointer to the memory mapped ECAM (kernel vaddr) + paddr_t cfg_phys; // The physical address of the device's ECAM + struct pcie_bridge_state* upstream; // The upstream bridge, or NULL if we are root + struct pcie_bus_driver_state* bus_drv; // Pointer to our bus driver state. + pcie_node_type_t type; // Type of the node (bridge or device) + uint16_t vendor_id; // The device's vendor ID, as read from config + uint16_t device_id; // The device's device ID, as read from config + uint8_t class_id; // The device's class ID, as read from config. + uint8_t subclass; // The device's subclass, as read from config. + uint8_t prog_if; // The device's programming interface (from cfg) + uint bus_id; // The bus ID this bridge/device exists on + uint dev_id; // The device ID of this bridge/device + uint func_id; // The function ID of this bridge/device + + /* Info about the BARs computed and cached during the initial setup/probe, + * indexed by starting BAR register index */ + pcie_bar_info_t bars[PCIE_MAX_BAR_REGS]; + + /* PCI Express Capabilities (Standard Capability 0x10) if present */ + struct { + pcie_capabilities_t* ecam; // pointer to the caps structure in ECAM + pcie_device_type_t devtype; // device type parts from pcie_caps + bool has_flr; // true if device supports function level reset + } pcie_caps; + + /* IRQ configuration and handling state */ + struct { + /* Shared state */ + pcie_irq_mode_t mode; + pcie_irq_sharing_mode_t share_mode; + pcie_irq_handler_state_t singleton_handler; + pcie_irq_handler_state_t* handlers; + uint handler_count; + + /* Legacy IRQ state */ + struct { + uint8_t pin; + struct list_node shared_handler_node; + struct pcie_legacy_irq_handler_state* shared_handler; + } legacy; + + /* MSI state */ + struct { + pcie_cap_msi_t* cfg; + uint max_irqs; + bool is64bit; + volatile uint32_t* pvm_mask_reg; + pcie_msi_block_t irq_block; + } msi; + + /* TODO(johngro) : Add MSI-X state */ + struct { } msi_x; + } irq; + +} pcie_common_state_t; + +typedef struct pcie_bridge_state { + pcie_common_state_t common; // State shared by every node in the bridge/device tree + uint managed_bus_id; // The ID of the downstream bus which this bridge manages. + + /* An array of pointers for all the possible functions which exist on the + * downstream bus of this bridge. Note: in the special case of the root + * host bridge, the function pointer will always be NULL in order to avoid + * cycles in the graph. + * + * TODO(johngro): This would be more efficient if it were kept as a set<> + * sorted by bus/dev/func identifiers. Switch this when we fully transition + * to C++ and Magenta. + */ + pcie_common_state_t* downstream[PCIE_MAX_FUNCTIONS_PER_BUS]; +} pcie_bridge_state_t; + +/* + * Struct used to manage the relationship between a PCIe device/function and its + * associated driver. During a bus scan/probe operation, all drivers will have + * their registered probe methods called until a driver claims a device. A + * driver may claim a device by returning a pointer to a driver-managed + * pcie_device_state struct, with the driver owned fields filled out. + */ +typedef struct pcie_device_state { + pcie_common_state_t common; + const pcie_driver_registration_t* driver; + void* driver_ctx; + struct list_node claimed_device_node; + bool started; +} pcie_device_state_t; + +/* + * Endian independent PCIe register access helpers. + */ +static inline uint8_t pcie_read8 (const volatile uint8_t* reg) { return *reg; } +static inline uint16_t pcie_read16(const volatile uint16_t* reg) { return LE16(*reg); } +static inline uint32_t pcie_read32(const volatile uint32_t* reg) { return LE32(*reg); } + +static inline void pcie_write8 (volatile uint8_t* reg, uint8_t val) { *reg = val; } +static inline void pcie_write16(volatile uint16_t* reg, uint16_t val) { *reg = LE16(val); } +static inline void pcie_write32(volatile uint32_t* reg, uint32_t val) { *reg = LE32(val); } + +/* + * Helper methods used for safely downcasting from pcie_common_state_t's to + * their derrived types. + */ +static inline pcie_bridge_state_t* pcie_downcast_to_bridge(const pcie_common_state_t* common) { + DEBUG_ASSERT(common); + return common->type != PCIE_BRIDGE ? NULL : containerof(common, pcie_bridge_state_t, common); +} + +static inline pcie_device_state_t* pcie_downcast_to_device(const pcie_common_state_t* common) { + DEBUG_ASSERT(common); + return common->type != PCIE_DEVICE ? NULL : containerof(common, pcie_device_state_t, common); +} + +/* + * Init the PCIe subsystem + * + * @param init_info A pointer to the information describing the resources to be + * used by the bus driver to access the PCIe subsystem on this platform. See \p + * struct pcie_init_info for more details. + * + * @return NO_ERROR if everything goes well. + */ +status_t pcie_init(const pcie_init_info_t* init_info); + +/* + * Shutdown the PCIe subsystem + */ +void pcie_shutdown(void); + +/* + * For iterating through all PCI devices. Returns the nth device, or NULL + * if index is >= the number of PCI devices. + */ +pcie_device_state_t* pci_get_nth_device(uint32_t index); + +/* + * Attaches a driver to a PCI device. Returns ERR_BUSY if the device has already been + * claimed by another driver. + */ +status_t pcie_claim_and_start_device(pcie_device_state_t* device, + const pcie_driver_registration_t* driver, + void* driver_ctx); + +/* + * Shutdown and unclaim a device had been successfully claimed with + * pcie_claim_and_start_device() + */ +void pcie_shutdown_device(pcie_device_state_t* device); + +/* + * Return information about the requested base address register, if it has been + * allocated. Otherwise, return NULL. + * + * @param common A pointer to the pcie device/bridge node to fetch BAR info for. + * @param bar_ndx The index of the BAR register to fetch info for. + * + * @return A pointer to the BAR info, including where in the bus address space + * the BAR window has been mapped, or NULL if the BAR window does not exist or + * has not been allocated. + */ +static inline const pcie_bar_info_t* pcie_get_bar_info( + const pcie_common_state_t* common, + uint bar_ndx) +{ + DEBUG_ASSERT(common); + DEBUG_ASSERT(bar_ndx < countof(common->bars)); + + const pcie_bar_info_t* ret = &common->bars[bar_ndx]; + return ret->is_allocated ? ret : NULL; +} + +/* + * A helper version of pcie_get_bar_info which takes a pcie_device_state_t + * pointer and passes the pointer to the common state along. + */ +static inline const pcie_bar_info_t* pcie_get_device_bar_info( + const pcie_device_state_t* device, + uint bar_ndx) +{ + DEBUG_ASSERT(device); + return pcie_get_bar_info(&device->common, bar_ndx); +} + +/* + * Modify bits in the device's command register (in the device config space), + * clearing the bits specified by clr_bits and setting the bits specified by set + * bits. Specifically, the operation will be applied as... + * + * WR(cmd, (RD(cmd) & ~clr) | set) + * + * @param device A pointer to the device whose command register is to be + * modified. + * @param clr_bits The mask of bits to be cleared. + * @param clr_bits The mask of bits to be set. + */ +void pcie_modify_cmd(const pcie_device_state_t* device, uint16_t clr_bits, uint16_t set_bits); + +/* + * Enable or disable bus mastering in a device's configuration. + * + * @param device A pointer to the target device. + * @param enable If true, allow the device to access main system memory as a bus + * master. + */ +static inline void pcie_enable_bus_master(const pcie_device_state_t* device, bool enabled) { + pcie_modify_cmd(device, + enabled ? 0 : PCI_COMMAND_BUS_MASTER_EN, + enabled ? PCI_COMMAND_BUS_MASTER_EN : 0); +} + +/* + * Enable or disable PIO access in a device's configuration. + * + * @param device A pointer to the target device. + * @param enable If true, allow the device to access its PIO mapped registers. + */ +static inline void pcie_enable_pio(const pcie_device_state_t* device, bool enabled) { + pcie_modify_cmd(device, + enabled ? 0 : PCI_COMMAND_IO_EN, + enabled ? PCI_COMMAND_IO_EN : 0); +} + +/* + * Enable or disable MMIO access in a device's configuration. + * + * @param device A pointer to the target device. + * @param enable If true, allow the device to access its MMIO mapped registers. + */ +static inline void pcie_enable_mmio(const pcie_device_state_t* device, bool enabled) { + pcie_modify_cmd(device, + enabled ? 0 : PCI_COMMAND_MEM_EN, + enabled ? PCI_COMMAND_MEM_EN : 0); +} + +/* + * Simple inline helper which fetches a device driver's name, or substitutes + * "" if the driver didn't supply a name, or for some mysterious + * reason, is NULL. + */ +static inline const char* pcie_driver_name(const pcie_driver_registration_t* driver) { + return (driver && driver->name) ? driver->name : ""; +} + +#if WITH_DEV_PCIE +#define STATIC_PCIE_DRIVER(var_name, drv_name, drv_fn_table) \ + extern const pcie_driver_registration_t __pcie_drv_reg_##var_name; \ + const pcie_driver_registration_t __pcie_drv_reg_##var_name \ + __ALIGNED(sizeof(void *)) __SECTION("pcie_builtin_drivers") = \ + { \ + .name = drv_name, \ + .fn_table = &drv_fn_table, \ + }; +#else // WITH_DEV_PCIE +#define STATIC_PCIE_DRIVER(var_name, drv_name, drv_fn_table) +#endif // WITH_DEV_PCIE + +/** + * Temporary hack; do not use! + */ +void pcie_rescan_bus(void); + +__END_CDECLS diff --git a/kernel/dev/pcie/include/dev/pcie_caps.h b/kernel/dev/pcie/include/dev/pcie_caps.h new file mode 100644 index 000000000..e1633364c --- /dev/null +++ b/kernel/dev/pcie/include/dev/pcie_caps.h @@ -0,0 +1,258 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +/** + * Standard PCI/PCIe capability headers are 16 bits long, with the 8 LSB being + * the type field, and the 8 MSB being the next pointer. Note, the 2 LSBs of + * the next pointer are reserved for future use and must be masked by system + * software to ensure future compatibility. @see Section 6.7 of the PCI Local + * Bus specificiaion v3.0. + */ +typedef uint16_t pcie_cap_hdr_t; + +static inline uint8_t pcie_cap_hdr_get_type(pcie_cap_hdr_t hdr) { + return (uint8_t)(hdr & 0xFF); +} + +static inline uint8_t pcie_cap_hdr_get_next_ptr(pcie_cap_hdr_t hdr) { + return (uint8_t)((hdr >> 8) & 0xFC); +} + +/** + * @see PCI Code and ID Assignment Specification Revision 1.7 Section 2 + */ +#define PCIE_CAP_ID_NULL 0x00 +#define PCIE_CAP_ID_PCI_PWR_MGMT 0x01 +#define PCIE_CAP_ID_AGP 0x02 +#define PCIE_CAP_ID_VPD 0x03 +#define PCIE_CAP_ID_MSI 0x05 +#define PCIE_CAP_ID_PCIX 0x07 +#define PCIE_CAP_ID_HYPERTRANSPORT 0x08 +#define PCIE_CAP_ID_VENDOR 0x09 +#define PCIE_CAP_ID_DEBUG_PORT 0x0A +#define PCIE_CAP_ID_COMPACTPCI_CRC 0x0B +#define PCIE_CAP_ID_PCI_HOTPLUG 0x0C +#define PCIE_CAP_ID_PCI_BRIDGE_SUBSYSTEM_VID 0x0D +#define PCIE_CAP_ID_AGP_8X 0x0E +#define PCIE_CAP_ID_SECURE_DEVICE 0x0F +#define PCIE_CAP_ID_PCI_EXPRESS 0x10 +#define PCIE_CAP_ID_MSIX 0x11 +#define PCIE_CAP_ID_SATA_DATA_NDX_CFG 0x12 +#define PCIE_CAP_ID_ADVANCED_FEATURES 0x13 +#define PCIE_CAP_ID_ENHANCED_ALLOCATION 0x14 + +/** + * Structure definitions for capability PCIE_CAP_ID_MSI + * + * @see The PCI Local Bus specificiaion v3.0 Section 6.8.1 + */ +typedef struct pcie_cap_msi { + pcie_cap_hdr_t hdr; + uint16_t ctrl; + uint32_t addr; + + union { + struct { + uint16_t data; + } nopvm_32bit; + + struct { + uint16_t data; + uint16_t __rsvd; + uint32_t mask_bits; + uint32_t pending_bits; + } pvm_32bit; + + struct { + uint32_t addr_upper; + uint16_t data; + } nopvm_64bit; + + struct { + uint32_t addr_upper; + uint16_t data; + uint16_t __rsvd; + uint32_t mask_bits; + uint32_t pending_bits; + } pvm_64bit; + }; +} __PACKED pcie_cap_msi_t; + +#define PCIE_CAP_MSI_CAP_HDR_SIZE (offsetof(pcie_cap_msi_t, nopvm_32bit)) +#define PCIE_CAP_MSI_CTRL_PVM_SUPPORTED(ctrl) ((ctrl & 0x0100) != 0) +#define PCIE_CAP_MSI_CTRL_64BIT_SUPPORTED(ctrl) ((ctrl & 0x0080) != 0) +#define PCIE_CAP_MSI_CTRL_GET_MME(ctrl) ((ctrl >> 4) & 0x7) +#define PCIE_CAP_MSI_CTRL_GET_MMC(ctrl) ((ctrl >> 1) & 0x7) +#define PCIE_CAP_MSI_CTRL_GET_ENB(ctrl) ((ctrl & 0x0001) != 0) + +#define PCIE_CAP_MSI_CTRL_SET_MME(val, ctrl) ((ctrl & ~0x0070) | ((val & 0x7) << 4)) +#define PCIE_CAP_MSI_CTRL_SET_ENB(val, ctrl) ((ctrl & ~0x0001) | (!!val)) + +/** + * Structure definitions for capability PCIE_CAP_ID_MSIX and the tables it + * refers to. + * + * @see The PCI Local Bus specificiaion v3.0 Section 6.8.2 + */ +typedef struct pcie_cap_msix { + pcie_cap_hdr_t hdr; + uint16_t ctrl; + uint32_t vector_table_bir_offset; + uint32_t pba_table_bir_offset; +} __PACKED pcie_cap_msix_t; + +typedef struct pcie_msix_vector_entry { + uint32_t addr; + uint32_t addr_upper; + uint32_t data; + uint32_t vector_ctrl; +} __PACKED pcie_msix_vector_entry_t; + +/** + * Structure and type definitions for capability PCIE_CAP_ID_PCI_EXPRESS + * + * @see The PCI Express Base Spec v3.1a, Section 7.8 + */ +typedef struct pcie_caps_chunk { + uint32_t caps; + uint16_t ctrl; + uint16_t status; +} __PACKED pcie_caps_chunk_t; + +typedef struct pcie_capabilities { + pcie_cap_hdr_t hdr; + uint16_t caps; + + pcie_caps_chunk_t device; + pcie_caps_chunk_t link; + pcie_caps_chunk_t slot; + + struct { + uint16_t ctrl; + uint16_t caps; + uint32_t status; + } __PACKED root; + + pcie_caps_chunk_t device2; + pcie_caps_chunk_t link2; + pcie_caps_chunk_t slot2; +} __PACKED pcie_capabilities_t; + +typedef enum { + // Type 0 config header types + PCIE_DEVTYPE_PCIE_ENDPOINT = 0x0, + PCIE_DEVTYPE_LEGACY_PCIE_ENDPOINT = 0x1, + PCIE_DEVTYPE_RC_INTEGRATED_ENDPOINT = 0x9, + PCIE_DEVTYPE_RC_EVENT_COLLECTOR = 0xA, + + // Type 1 config header types + PCIE_DEVTYPE_RC_ROOT_PORT = 0x4, + PCIE_DEVTYPE_SWITCH_UPSTREAM_PORT = 0x5, + PCIE_DEVTYPE_SWITCH_DOWNSTREAM_PORT = 0x6, + PCIE_DEVTYPE_PCIE_TO_PCI_BRIDGE = 0x7, + PCIE_DEVTYPE_PCI_TO_PCIE_BRIDGE = 0x8, + + // Default value; used for device which have no pcie_capabilities extension. + PCIE_DEVTYPE_UNKNOWN = 0xFF, +} pcie_device_type_t; + +// Section 7.8.2 Table 7-12 +#define PCS_CAPS_VERSION(val) (((val) >> 0) & 0xF) +#define PCS_CAPS_DEVTYPE(val) (((val) >> 4) & 0xF) +#define PCS_CAPS_SLOT_IMPL(val) (((val) >> 8) & 0x1) +#define PCS_CAPS_IRQ_MSG_NUM(val) (((val) >> 9) & 0x1F) + +// Section 7.8.3 Table 7-13 +#define PCS_DEV_CAPS_MAX_PAYLOAD_SIZE(val) (((val) >> 0) & 0x07) +#define PCS_DEV_CAPS_PHANTOM_FUNC_SUPPORTED(val) (((val) >> 3) & 0x03) +#define PCS_DEV_CAPS_EXT_TAG_SUPPORTED(val) (((val) >> 5) & 0x01) +#define PCS_DEV_CAPS_MAX_EL0_LATENCY(val) (((val) >> 6) & 0x07) +#define PCS_DEV_CAPS_MAX_EL1_LATENCY(val) (((val) >> 9) & 0x07) +#define PCS_DEV_CAPS_ROLE_BASED_ERR_REP(val) (((val) >> 15) & 0x01) +#define PCS_DEV_CAPS_CAP_SLOT_PWR_LIMIT_VAL(val) (((val) >> 18) & 0xFF) +#define PCS_DEV_CAPS_CAP_SLOT_PWR_LIMIT_SCALE(val) (((val) >> 26) & 0x03) +#define PCS_DEV_CAPS_FUNC_LEVEL_RESET(val) (((val) >> 28) & 0x01) + +// TODO(johngro) : so many other bitfields to define... eventually, get around +// to doing so. + +/** + * Extended PCIe capability headers are 32 bits long with the following packing. + * + * [0:15] : 16-bit Extended Capability ID. + * [16:19] : 4-bit Capability Version. + * [20:31] : Next pointer; 2 LSB must be masked by system software. + */ +typedef uint32_t pcie_ext_cap_hdr_t; + +static inline uint16_t pcie_ext_cap_hdr_get_type(pcie_ext_cap_hdr_t hdr) { + return (uint16_t)(hdr & 0xFFFF); +} + +static inline uint8_t pcie_ext_cap_hdr_get_cap_version(pcie_ext_cap_hdr_t hdr) { + return (uint8_t)((hdr >> 16) & 0xF); +} + +static inline uint16_t pcie_ext_cap_hdr_get_next_ptr(pcie_ext_cap_hdr_t hdr) { + return (uint16_t)((hdr >> 20) & 0xFFC); +} + +/** + * @see PCI Code and ID Assignment Specification Revision 1.7 Section 3 + */ +#define PCIE_EXT_CAP_ID_NULL 0x0000 +#define PCIE_EXT_CAP_ID_ADVANCED_ERROR_REPORTING 0x0001 +#define PCIE_EXT_CAP_ID_VIRTUAL_CHANNEL_NO_MFVC 0x0002 +#define PCIE_EXT_CAP_ID_DEVICE_SERIAL_NUMBER 0x0003 +#define PCIE_EXT_CAP_ID_POWER_BUDGETING 0x0004 +#define PCIE_EXT_CAP_ID_ROOT_COMPLEX_LINK_DECLARATION 0x0005 +#define PCIE_EXT_CAP_ID_ROOT_COMPLEX_INTERNAL_LINK_CONTROL 0x0006 +#define PCIE_EXT_CAP_ID_ROOT_COMPLEX_EVENT_COLLECTOR_EP_ASSOC 0x0007 +#define PCIE_EXT_CAP_ID_MULTI_FUNCTION_VIRTUAL_CHANNEL 0x0008 +#define PCIE_EXT_CAP_ID_VIRTUAL_CHANNEL_MFVC 0x0009 +#define PCIE_EXT_CAP_ID_ROOT_COMPLEX_REGISTER_BLOCK 0x000A +#define PCIE_EXT_CAP_ID_VENDOR_SPECIFIC 0x000B +#define PCIE_EXT_CAP_ID_CONFIGURATION_ACCESS_CORRELATION 0x000C +#define PCIE_EXT_CAP_ID_ACCESS_CONTROL_SERVICES 0x000D +#define PCIE_EXT_CAP_ID_ALTERNATIVE_ROUTING_ID_INTERPRETATION 0x000E +#define PCIE_EXT_CAP_ID_ADDRESS_TRANSLATION_SERVICES 0x000F +#define PCIE_EXT_CAP_ID_SINGLE_ROOT_IO_VIRTUALIZATION 0x0010 +#define PCIE_EXT_CAP_ID_MULTI_ROOT_IO_VIRTUALIZATION 0x0011 +#define PCIE_EXT_CAP_ID_MULTICAST 0x0012 +#define PCIE_EXT_CAP_ID_PAGE_REQUEST 0x0013 +#define PCIE_EXT_CAP_ID_RESERVED_FOR_AMD 0x0014 +#define PCIE_EXT_CAP_ID_RESIZABLE_BAR 0x0015 +#define PCIE_EXT_CAP_ID_DYNAMIC_POWER_ALLOCATION 0x0016 +#define PCIE_EXT_CAP_ID_TLP_PROCESSING_HINTS 0x0017 +#define PCIE_EXT_CAP_ID_LATENCY_TOLERANCE_REPORTING 0x0018 +#define PCIE_EXT_CAP_ID_SECONDARY_PCI_EXPRESS 0x0019 +#define PCIE_EXT_CAP_ID_PROTOCOL_MULTIPLEXING 0x001A +#define PCIE_EXT_CAP_ID_PROCESS_ADDRESS_SPACE_ID 0x001B +#define PCIE_EXT_CAP_ID_LN_REQUESTER 0x001C +#define PCIE_EXT_CAP_ID_DOWNSTREAM_PORT_CONTAINMENT 0x001D +#define PCIE_EXT_CAP_ID_L1_PM_SUBSTATES 0x001E +#define PCIE_EXT_CAP_ID_PRECISION_TIME_MEASUREMENT 0x001F +#define PCIE_EXT_CAP_ID_PCI_EXPRESS_OVER_MPHY 0x0020 +#define PCIE_EXT_CAP_ID_FRS_QUEUEING 0x0021 +#define PCIE_EXT_CAP_ID_READINESS_TIME_REPORTING 0x0022 +#define PCIE_EXT_CAP_ID_DESIGNATED_VENDOR_SPECIFIC 0x0023 + +__END_CDECLS + diff --git a/kernel/dev/pcie/include/dev/pcie_constants.h b/kernel/dev/pcie/include/dev/pcie_constants.h new file mode 100644 index 000000000..1dcdbf419 --- /dev/null +++ b/kernel/dev/pcie/include/dev/pcie_constants.h @@ -0,0 +1,88 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +#define PCIE_MAX_BUSSES (256u) +#define PCIE_MAX_DEVICES_PER_BUS (32u) +#define PCIE_MAX_FUNCTIONS_PER_DEVICE (8u) +#define PCIE_MAX_FUNCTIONS_PER_BUS (PCIE_MAX_DEVICES_PER_BUS * PCIE_MAX_FUNCTIONS_PER_DEVICE) + +#define PCIE_MAX_LEGACY_IRQ_PINS (4u) +#define PCIE_MAX_MSI_IRQS (32u) +#define PCIE_MAX_MSIX_IRQS (2048u) + +#define PCIE_STANDARD_CONFIG_HDR_SIZE (64u) +#define PCIE_BASE_CONFIG_SIZE (256u) +#define PCIE_EXTENDED_CONFIG_SIZE (4096u) +STATIC_ASSERT(sizeof(pci_config_t) == PCIE_STANDARD_CONFIG_HDR_SIZE); + +#define PCIE_ECAM_BYTE_PER_BUS (PCIE_EXTENDED_CONFIG_SIZE * PCIE_MAX_FUNCTIONS_PER_BUS) + +#define PCIE_BAR_REGS_PER_BRIDGE (2u) +#define PCIE_BAR_REGS_PER_DEVICE (6u) +#define PCIE_MAX_BAR_REGS (6u) + +#define PCIE_INVALID_VENDOR_ID (0xFFFF) + +/** + * The maximum possible number of standard capabilities for a PCI + * device/function is 48. This comes from the facts that... + * + * ++ There are 256 bytes in the standard configuration space. + * ++ The first 64 bytes are used by the standard configuration header, leaving + * 192 bytes for capabilities. + * ++ Even though the capability header is only 2 bytes long, it must be aligned + * on a 4 byte boundary. The means that one can pack (at most) 192 / 4 == 48 + * properly aligned standard PCI capabilities. + * + * Similar logic may be applied to extended capabilities which must also be 4 + * byte aligned, but exist in the region after the standard configuration block. + */ +#define PCIE_CAPABILITY_ALIGNMENT (4u) + +#define PCIE_MAX_CAPABILITIES ((PCIE_BASE_CONFIG_SIZE - sizeof(pci_config_t)) \ + / PCIE_CAPABILITY_ALIGNMENT) +#define PCIE_CAP_PTR_NULL (0u) +#define PCIE_CAP_PTR_MIN_VALID (PCIE_STANDARD_CONFIG_HDR_SIZE) +#define PCIE_CAP_PTR_MAX_VALID (PCIE_BASE_CONFIG_SIZE - PCIE_CAPABILITY_ALIGNMENT) + +#define PCIE_EXT_CAP_PTR_NULL (0u) +#define PCIE_EXT_CAP_PTR_MIN_VALID (PCIE_BASE_CONFIG_SIZE) +#define PCIE_EXT_CAP_PTR_MAX_VALID (PCIE_EXTENDED_CONFIG_SIZE - PCIE_CAPABILITY_ALIGNMENT) +#define PCIE_MAX_EXT_CAPABILITIES ((PCIE_EXTENDED_CONFIG_SIZE - PCIE_BASE_CONFIG_SIZE) \ + / PCIE_CAPABILITY_ALIGNMENT) + +/* + * PCI BAR register masks and constants + */ +#define PCI_BAR_IO_TYPE_MASK (0x00000001) +#define PCI_BAR_IO_TYPE_MMIO (0x00000000) +#define PCI_BAR_IO_TYPE_PIO (0x00000001) + +#define PCI_BAR_MMIO_TYPE_MASK (0x00000006) +#define PCI_BAR_MMIO_TYPE_32BIT (0x00000000) +#define PCI_BAR_MMIO_TYPE_64BIT (0x00000004) + +#define PCI_BAR_MMIO_PREFETCH_MASK (0x00000008) +#define PCI_BAR_MMIO_ADDR_MASK (0xFFFFFFF0) +#define PCI_BAR_PIO_ADDR_MASK (0xFFFFFFFC) + +/* + * Extra bits used in the CFG command and status registers defined by PCIe. See + * the PCIe Base Specification, sections 7.5.1.1 and 7.5.1.2 + */ +#define PCIE_CFG_COMMAND_INT_DISABLE ((uint16_t)(1 << 10)) +#define PCIE_CFG_STATUS_INT_STS ((uint16_t)(1 << 3)) + +__END_CDECLS diff --git a/kernel/dev/pcie/include/dev/pcie_irqs.h b/kernel/dev/pcie/include/dev/pcie_irqs.h new file mode 100644 index 000000000..09c26ebb2 --- /dev/null +++ b/kernel/dev/pcie/include/dev/pcie_irqs.h @@ -0,0 +1,375 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +/* Fwd decls */ +struct pcie_common_state; + +/** + * Enumeration which defines the IRQ modes a PCIe device may be operating in. + * IRQ modes are exclusive, a device may be operating in only one mode at any + * given point in time. Drivers may query the maximum number of IRQs supported + * by each mode using the pcie_query_irq_mode_capabilities function. Drivers + * may request a particular number of IRQs be allocated when selecting an IRQ + * mode with pcie_set_irq_mode. IRQ identifiers used in the system when + * registering, un-registering and dispatching IRQs are on the range [0, N-1] + * where N are the number of IRQs successfully allocated using a call to + * pcie_set_irq_mode. + * + * ++ PCIE_IRQ_MODE_DISABLED + * All IRQs are disabled. 0 total IRQs are supported in this mode. + * + * ++ PCIE_IRQ_MODE_LEGACY + * Devices may support up to 1 legacy IRQ in total. Exclusive IRQ access + * cannot be guaranteed (the IRQ may be shared with other devices) + * + * ++ PCIE_IRQ_MODE_MSI + * Devices may support up to 32 MSI IRQs in total. IRQs may be allocated + * exclusively, resources permitting. + * + * ++ PCIE_IRQ_MODE_MSI_X + * Devices may support up to 2048 MSI-X IRQs in total. IRQs may be allocated + * exclusively, resources permitting. + */ +typedef enum pcie_irq_mode { + PCIE_IRQ_MODE_DISABLED = 0, + PCIE_IRQ_MODE_LEGACY, + PCIE_IRQ_MODE_MSI, + PCIE_IRQ_MODE_MSI_X, +} pcie_irq_mode_t; + +/** + * A structure used to hold output parameters when calling + * pcie_query_irq_mode_capabilities + */ +typedef struct pcie_irq_mode_caps { + uint max_irqs; /** The maximum number of IRQ supported by the selected mode */ + /** + * For MSI or MSI-X, indicates whether or not per-vector-masking has been + * implementd by the hardware. + */ + bool per_vector_masking_supported; +} pcie_irq_mode_caps_t; + +/** + * An enumeration which controls the requested behavior regarding sharing system + * interrupts when selecting an IRQ mode. The system is permitted to configure + * vectors in a more exclusive mode than the mode requested, but not a less + * exclusive mode. For example, if a driver requests SYSTEM_SHARED exclusivity, + * the system is permitted to deliver either DEVICE_SHARED or EXCLUSIVE service + * (resources permitting) but must fail the call if EXCLUSIVE is requests but + * only one of the lesser grades of service is available. + * + * ++ PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED + * Device driver will permit its IRQ vector(s) to be shared with other + * devices in the system. + * + * ++ PCIE_IRQ_SHARE_MODE_DEVICE_SHARED + * Device driver will permit its IRQ vector(s) to be shared with other + * vectors in the device, not with other devices in the system. + * + * ++ PCIE_IRQ_SHARE_MODE_EXCLUSIVE + * Device driver will not permit any of its IRQ vector(s) to be shared. Each + * vector must be mapped to an individually triggered and managed system IRQ. + */ +typedef enum pcie_irq_share_mode { + PCIE_IRQ_SHARE_MODE_INVALID = 0, + PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED, + PCIE_IRQ_SHARE_MODE_DEVICE_SHARED, + PCIE_IRQ_SHARE_MODE_EXCLUSIVE, +} pcie_irq_sharing_mode_t; + +/** + * An enumeration of the permitted return values from a PCIe IRQ handler. + * + * ++ PCIE_IRQRET_NO_ACTION + * Do not mask the IRQ, do not request that the kernel perform a reschedule. + * + * ++ PCIE_IRQRET_RESCHED + * Do not mask the IRQ, request that the kernel perform a reschedule. + * + * ++ PCIE_IRQRET_MASK + * Mask the IRQ if (and only if) per vector masking is supported, but do not + * request that the kernel perform a reschedule. + * + * ++ PCIE_IRQRET_MASK_AND_RESCHED + * Mask the IRQ if (and only if) per vector masking is supported, and request + * that the kernel perform a reschedule. + */ +typedef enum pcie_irq_handler_retval { + PCIE_IRQRET_NO_ACTION = 0x0, + PCIE_IRQRET_RESCHED = 0x1, + PCIE_IRQRET_MASK = 0x2, + PCIE_IRQRET_MASK_AND_RESCHED = PCIE_IRQRET_RESCHED | PCIE_IRQRET_MASK, +} pcie_irq_handler_retval_t; + +/** + * A structure which holds the state of a block of IRQs allocated by the + * platform to be used for delivering MSI or MSI-X interrupts. + */ +typedef struct pcie_msi_block { + void* platform_ctx; /** Allocation context owned by the platform */ + uint64_t tgt_addr; /** The target write transaction physical address */ + bool allocated; /** Whether or not this block has been allocated */ + uint base_irq_id; /** The first IRQ id in the allocated block */ + uint num_irq; /** The number of irqs in the allocated block */ + + /** + * The data which the device should write when triggering an IRQ. Note, + * only the lower 16 bits are used when the block has been allocated for MSI + * instead of MSI-X + */ + uint32_t tgt_data; +} pcie_msi_block_t; + +/** + * Definition of the callback registered with pcie_register_irq_handler. This + * callback will be called by a bus central IRQ dispatcher any time a chosen + * device IRQ occurs. + * + * @note Masked/unmasked status of an IRQ MUST not be manipulated via the API + * during an IRQ handler dispatch. If an IRQ needs to be masked as part of a + * handler's behavior, the appropriate return value should be used instead of in + * the API. @see pcie_irq_handler_retval_t + * + * @param dev A pointer to the pci device for which this IRQ occurred. + * @param irq_id The 0-indexed ID of the IRQ which occurred. + * @param ctx The context pointer registered when registering the handler. + */ +typedef pcie_irq_handler_retval_t (*pcie_irq_handler_fn_t)(struct pcie_common_state* dev, + uint irq_id, + void* ctx); + +/** + * Callback definition used for platform-specific legacy IRQ remapping. + * + * @param common A pointer to the pcie device/bridge to swizzle for. + * @param pin The pin we want to swizzle + * @param irq An output pointer for what IRQ this pin goes to + * + * @return NO_ERROR if we successfully swizzled + * @return ERR_NOT_FOUND if we did not know how to swizzle this pin + */ +typedef status_t (*platform_legacy_irq_swizzle_t)(const struct pcie_common_state* common, + uint pin, + uint *irq); + +/** + * Callback definition used for platform allocation of blocks of MSI and MSI-X + * compatible IRQ targets. + * + * @param requested_irqs The total number of irqs being requested. + * @param can_target_64bit True if the target address of the MSI block can + * be located past the 4GB boundary. False if the target address must be + * in low memory. + * @param is_msix True if this request is for an MSI-X compatible block. False + * for plain old MSI. + * @param out_block A pointer to the allocation bookkeeping to be filled out + * upon successful allocation of the reqested block of IRQs. + * + * @return A status code indicating the success or failure of the operation. + */ +typedef status_t (*platform_alloc_msi_block_t)(uint requested_irqs, + bool can_target_64bit, + bool is_msix, + pcie_msi_block_t* out_block); + +/** + * Callback definition used by the bus driver to return a block of MSI IRQs + * previously allocated with a call to a platform_alloc_msi_block_t + * implementation to the platform pool. + * + * @param block A pointer to the block to be returned. + */ +typedef void (*platform_free_msi_block_t)(pcie_msi_block_t* block); + +/** + * Callback definition used for platform registration of MSI handlers. + * + * @param block A pointer to a block of MSIs allocated using a platform supplied + * platform_alloc_msi_block_t callback. + * @param msi_id The ID (indexed from 0) with the block of MSIs to register a + * handler for. + * @param handler A pointer to the handler to register, or NULL to unregister. + * @param ctx A context pointer to be supplied when the handler is invoked. + */ +typedef void (*platform_register_msi_handler_t)(const pcie_msi_block_t* block, + uint msi_id, + int_handler handler, + void* ctx); + +/** + * Callback definition used for platform masking/unmaskingof MSI handlers. + * + * @param block A pointer to a block of MSIs allocated using a platform supplied + * platform_alloc_msi_block_t callback. + * @param msi_id The ID (indexed from 0) with the block of MSIs to mask or + * unmask. + * @param mask If true, mask the handler. Otherwise, unmask it. + */ +typedef void (*platform_mask_unmask_msi_t)(const pcie_msi_block_t* block, + uint msi_id, + bool mask); + +/** + * Structure used internally to hold the state of a registered handler. + */ +typedef struct pcie_irq_handler_state { + spin_lock_t lock; + pcie_irq_handler_fn_t handler; + void* ctx; + struct pcie_common_state* dev; + uint pci_irq_id; + bool masked; +} pcie_irq_handler_state_t; + +/** + * Query the number of IRQs which are supported for a given IRQ mode by a given + * device. + * + * @param dev A pointer to the pci device to query. + * @param mode The IRQ mode to query capabilities for. + * @param out_caps A pointer to structure which, upon success, will hold the + * capabilities of the selected IRQ mode. + * + * @return A status_t indicating the success or failure of the operation. + */ +status_t pcie_query_irq_mode_capabilities(const struct pcie_common_state* dev, + pcie_irq_mode_t mode, + pcie_irq_mode_caps_t* out_caps); +/** + * Configure the base IRQ mode, requesting a specific number of vectors and + * sharing mode in the process. + * + * Devices are not permitted to transition from an active mode (anything but + * DISABLED) to a different active mode. They must first transition to + * DISABLED, then request the new mode. + * + * Transitions to the DISABLED state will automatically mask and un-register all + * IRQ handlers, and return all allocated resources to the system pool. IRQ + * dispatch may continue to occur for unmasked IRQs during a transition to + * DISABLED, but is guaranteed not to occur after the call to pcie_set_irq_mode + * has completed. + * + * @param dev A pointer to the pci device to configure. + * @param mode The requested mode. + * @param requested_irqs The number of individual IRQ vectors the device would + * like to use. + * @param share_mode The level of sharing the driver is willing to tolerate for + * its IRQ vectors. @see pcie_irq_sharing_mode_t for details. + * + * @return A status_t indicating the success or failure of the operation. + * Status codes may include (but are not limited to)... + * + * ++ ERR_BAD_STATE + * The device cannot transition into the selected mode at this point in time + * due to the mode it is currently in. + * ++ ERR_NOT_SUPPORTED + * ++ The chosen mode is not supported by the device + * ++ The chosen share_mode is not compatible with the chosen irq mode. For + * example, legacy IRQ mode demands that IRQs be shared at the system level. + * ++ The device supports the chosen mode, but does not support the number of + * IRQs requested. + * ++ ERR_NO_RESOURCES + * The system is unable to allocate sufficient system IRQs to satisfy the + * number of IRQs and exclusivity mode requested the device driver. + */ +status_t pcie_set_irq_mode(struct pcie_common_state* dev, + pcie_irq_mode_t mode, + uint requested_irqs, + pcie_irq_sharing_mode_t share_mode); + +/** + * Set the current IRQ mode to PCIE_IRQ_MODE_DISABLED + * + * Convenience function. @see pcie_set_irq_mode for details. + */ +static inline void pcie_set_irq_mode_disabled(struct pcie_common_state* dev) { + /* It should be impossible to fail a transition to the DISABLED state, + * regardless of the state of the system. ASSERT this in debug builds */ + __UNUSED status_t result; + + result = pcie_set_irq_mode(dev, PCIE_IRQ_MODE_DISABLED, 0, PCIE_IRQ_SHARE_MODE_INVALID); + + DEBUG_ASSERT(result == NO_ERROR); +} + +/** + * Register an IRQ handler for the specified IRQ ID. + * + * @param dev A pointer to the pci device to configure. + * @param irq_id The ID of the IRQ to register. + * @param handler A pointer to the handler function to call when the IRQ is + * received. Pass NULL to automatically mask the IRQ and unregister the + * handler. + * @param ctx A user supplied context pointer to pass to a registered handler. + * + * @return A status_t indicating the success or failure of the operation. + * Status codes may include (but are not limited to)... + * + * ++ ERR_BAD_STATE + * The device is in DISABLED IRQ mode. + * ++ ERR_INVALID_ARGS + * The irq_id parameter is out of range for the currently configured mode. + */ +status_t pcie_register_irq_handler(struct pcie_common_state* dev, + uint irq_id, + pcie_irq_handler_fn_t handler, + void* ctx); + +/** + * Mask or unmask the specified IRQ for the given device. + * + * @param dev A pointer to the pci device to configure. + * @param irq_id The ID of the IRQ to mask or unmask. + * @param mask If true, mask (disable) the IRQ. Otherwise, unmask it. + * + * @return A status_t indicating the success or failure of the operation. + * Status codes may include (but are not limited to)... + * + * ++ ERR_BAD_STATE + * Attempting to mask or unmask an IRQ while in the DISABLED mode or with no + * handler registered. + * ++ ERR_INVALID_ARGS + * The irq_id parameter is out of range for the currently configured mode. + * ++ ERR_NOT_SUPPORTED + * The device is operating in MSI mode, but neither the PCI device nor the + * platform interrupt controller support masking the MSI vector. + */ +status_t pcie_mask_unmask_irq(struct pcie_common_state* dev, + uint irq_id, + bool mask); + +/** + * Mask the specified IRQ for the given device. + * + * Convenience function. @see pcie_mask_unmask_irq for details. + */ +static inline status_t pcie_mask_irq(struct pcie_common_state* dev, uint irq_id) { + return pcie_mask_unmask_irq(dev, irq_id, true); +} + +/** + * Unmask the specified IRQ for the given device. + * + * Convenience function. @see pcie_mask_unmask_irq for details. + */ +static inline status_t pcie_unmask_irq(struct pcie_common_state* dev, uint irq_id) { + return pcie_mask_unmask_irq(dev, irq_id, false); +} + +__END_CDECLS diff --git a/kernel/dev/pcie/pcie.c b/kernel/dev/pcie/pcie.c new file mode 100644 index 000000000..15392feeb --- /dev/null +++ b/kernel/dev/pcie/pcie.c @@ -0,0 +1,1087 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie_priv.h" + +#define LOCAL_TRACE 0 + +/* TODO(johngro) : figure this out someday. + * + * In theory, BARs which map PIO regions for devices are supposed to be able to + * use bits [2, 31] to describe the programable section of the PIO window. On + * real x86/64 systems, however, using the write-1s-readback technique to + * determine programable bits of the BAR's address (and therefor the size of the + * I/O window) shows that the upper 16 bits are not programable. This makes + * sense for x86 (where I/O space is only 16-bits), but fools the system into + * thinking that the I/O window is enormous. + * + * For now, just define a mask which can be used during PIO window space + * calculations which limits the size to 16 bits for x86/64 systems. non-x86 + * systems are still free to use all of the bits for their PIO addresses + * (although, it is still a bit unclear what it would mean to generate an IO + * space cycle on an architecture which has no such thing as IO space). + */ +#if (defined(ARCH_X86) && ARCH_X86) +#define PCIE_HAS_IO_ADDR_SPACE (1) +#else +#define PCIE_HAS_IO_ADDR_SPACE (0) +#endif + +#if PCIE_HAS_IO_ADDR_SPACE +#define PCIE_PIO_ADDR_SPACE_MASK (0xFFFF) +#define PCIE_PIO_ADDR_SPACE_SIZE (0x10000ull) +#else +#define PCIE_PIO_ADDR_SPACE_MASK (0xFFFFFFFF) +#define PCIE_PIO_ADDR_SPACE_SIZE (0x100000000ull) +#endif + +#ifdef WITH_LIB_CONSOLE +#define EXPORT_TO_DEBUG_CONSOLE +#else +#define EXPORT_TO_DEBUG_CONSOLE static +#endif + +static pcie_bus_driver_state_t g_drv_state; // The driver state singleton + +#ifdef WITH_LIB_CONSOLE +pcie_bus_driver_state_t* pcie_get_bus_driver_state(void) { return &g_drv_state; } +#endif + +// External references to the device driver registration tables. +extern pcie_driver_registration_t __start_pcie_builtin_drivers[] __WEAK; +extern pcie_driver_registration_t __stop_pcie_builtin_drivers[] __WEAK; + +// Fwd decls +static void pcie_scan_bus(pcie_bridge_state_t* bridge); + +EXPORT_TO_DEBUG_CONSOLE +pcie_config_t* pcie_get_config(const pcie_bus_driver_state_t* bus_drv, + uint64_t* cfg_phys, + uint bus_id, + uint dev_id, + uint func_id) { + DEBUG_ASSERT(bus_drv); + DEBUG_ASSERT(bus_id < PCIE_MAX_BUSSES); + DEBUG_ASSERT(dev_id < PCIE_MAX_DEVICES_PER_BUS); + DEBUG_ASSERT(func_id < PCIE_MAX_FUNCTIONS_PER_DEVICE); + + for (size_t i = 0; i < bus_drv->ecam_window_count; ++i) { + pcie_kmap_ecam_range_t* window = bus_drv->ecam_windows + i; + pcie_ecam_range_t* ecam = &window->ecam; + + if ((bus_id >= ecam->bus_start) && (bus_id <= ecam->bus_end)) { + size_t offset; + + bus_id -= ecam->bus_start; + offset = (((size_t)bus_id) << 20) | + (((size_t)dev_id) << 15) | + (((size_t)func_id) << 12); + + DEBUG_ASSERT(window->vaddr); + DEBUG_ASSERT(ecam->io_range.size >= PCIE_EXTENDED_CONFIG_SIZE); + DEBUG_ASSERT(offset <= (ecam->io_range.size - PCIE_EXTENDED_CONFIG_SIZE)); + + if (cfg_phys) + *cfg_phys = window->ecam.io_range.bus_addr + offset; + + return (pcie_config_t*)(window->vaddr + offset); + } + } + + if (cfg_phys) + *cfg_phys = 0; + + return NULL; +} + +static bool pcie_probe_bar_info(pcie_config_t* cfg, + uint bar_id, + uint bar_count, + pcie_bar_info_t* info_out) { + DEBUG_ASSERT(cfg); + DEBUG_ASSERT(bar_id < bar_count); + DEBUG_ASSERT(info_out); + + memset(info_out, 0, sizeof(*info_out)); + + /* Determine the type of BAR this is. Make sure that it is one of the types we understand */ + volatile uint32_t* bar_reg = &cfg->base.base_addresses[bar_id]; + uint32_t bar_val = pcie_read32(bar_reg); + info_out->is_mmio = (bar_val & PCI_BAR_IO_TYPE_MASK) == PCI_BAR_IO_TYPE_MMIO; + info_out->is_64bit = info_out->is_mmio && + ((bar_val & PCI_BAR_MMIO_TYPE_MASK) == PCI_BAR_MMIO_TYPE_64BIT); + info_out->is_prefetchable = info_out->is_mmio && (bar_val & PCI_BAR_MMIO_PREFETCH_MASK); + info_out->first_bar_reg = bar_id; + + if (info_out->is_64bit) { + if ((bar_id + 1) >= bar_count) { + TRACEF("Illegal 64-bit MMIO BAR position (%u/%u) while fetching BAR info " + "for device config @%p\n", + bar_id, bar_count, cfg); + return false; + } + } else { + if (info_out->is_mmio && ((bar_val & PCI_BAR_MMIO_TYPE_MASK) != PCI_BAR_MMIO_TYPE_32BIT)) { + TRACEF("Unrecognized MMIO BAR type (BAR[%u] == 0x%08x) while fetching BAR info " + "for device config @%p\n", + bar_id, bar_val, cfg); + return false; + } + } + + /* Figure out the size of this BAR region by writing 1's to the + * address bits, then reading back to see which bits the device + * considers un-configurable. */ + uint32_t addr_mask = info_out->is_mmio ? PCI_BAR_MMIO_ADDR_MASK : PCI_BAR_PIO_ADDR_MASK; + uint64_t size_mask; + + pcie_write32(bar_reg, bar_val | addr_mask); + size_mask = ~(pcie_read32(bar_reg) & addr_mask); + pcie_write32(bar_reg, bar_val); + + if (info_out->is_mmio) { + if (info_out->is_64bit) { + /* 64bit MMIO? Probe the upper bits as well */ + bar_reg++; + bar_val = pcie_read32(bar_reg); + pcie_write32(bar_reg, 0xFFFFFFFF); + size_mask |= ((uint64_t)~pcie_read32(bar_reg)) << 32; + pcie_write32(bar_reg, bar_val); + info_out->size = size_mask + 1; + } else { + info_out->size = (uint32_t)(size_mask + 1); + } + } else { + /* PIO BAR */ + info_out->size = ((uint32_t)(size_mask + 1)) & PCIE_PIO_ADDR_SPACE_MASK; + } + + /* Success */ + return (info_out->size > 0); +} + +static void pcie_enumerate_bars(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev && dev->cfg); + + pcie_config_t* cfg = dev->cfg; + uint8_t header_type = pcie_read8(&cfg->base.header_type) & PCI_HEADER_TYPE_MASK; + uint bar_count; + + static_assert(PCIE_MAX_BAR_REGS >= PCIE_BAR_REGS_PER_DEVICE); + static_assert(PCIE_MAX_BAR_REGS >= PCIE_BAR_REGS_PER_BRIDGE); + + switch (header_type) { + case PCI_HEADER_TYPE_STANDARD: + bar_count = PCIE_BAR_REGS_PER_DEVICE; + break; + + case PCI_HEADER_TYPE_PCI_BRIDGE: + bar_count = PCIE_BAR_REGS_PER_BRIDGE; + break; + + case PCI_HEADER_TYPE_CARD_BUS: + return; // Nothing to do if this header type has no BARs + + default: + TRACEF("Unrecognized header type (0x%02x) in %s for device %02x:%02x:%01x.\n", + header_type, __FUNCTION__, dev->bus_id, dev->dev_id, dev->func_id); + return; + } + + DEBUG_ASSERT(bar_count <= countof(dev->bars)); + for (uint i = 0; i < bar_count; ++i) { + /* If this is a re-scan of the bus, We should not be re-enumerating BARs. */ + DEBUG_ASSERT(dev->bars[i].size == 0); + DEBUG_ASSERT(!dev->bars[i].is_allocated); + + if (pcie_probe_bar_info(cfg, i, bar_count, &dev->bars[i])) { + DEBUG_ASSERT(dev->bars[i].size != 0); + + dev->bars[i].dev = dev; + + /* If this was a 64 bit bar, it took two registers to store. Make + * sure to skip the next register */ + if (dev->bars[i].is_64bit) { + i++; + DEBUG_ASSERT(i < bar_count); + } + } + } +} + +static status_t pcie_scan_init_common(pcie_common_state_t* common, + pcie_bridge_state_t* upstream_bridge, + pcie_bus_driver_state_t* bus_drv, + uint bus_id, + uint dev_id, + uint func_id) { + DEBUG_ASSERT(common); + DEBUG_ASSERT(bus_drv); + + status_t status; + uint64_t cfg_phys; + pcie_config_t* cfg = pcie_get_config(bus_drv, &cfg_phys, bus_id, dev_id, func_id); + + DEBUG_ASSERT(cfg); + + common->cfg = cfg; + common->cfg_phys = cfg_phys; + common->upstream = upstream_bridge; + common->bus_drv = bus_drv; + common->vendor_id = pcie_read16(&cfg->base.vendor_id); + common->device_id = pcie_read16(&cfg->base.device_id); + common->class_id = pcie_read8(&cfg->base.base_class); + common->subclass = pcie_read8(&cfg->base.sub_class); + common->prog_if = pcie_read8(&cfg->base.program_interface); + common->bus_id = bus_id; + common->dev_id = dev_id; + common->func_id = func_id; + + /* PCI Express Capabilities */ + common->pcie_caps.devtype = PCIE_DEVTYPE_UNKNOWN; + + /* Build this device's list of BARs with non-zero size, but do not actually + * allocate them yet. */ + pcie_enumerate_bars(common); + + /* Parse and sanity check the capabilities and extended capabilities lists + * if they exist */ + status = pcie_parse_capabilities(common); + if (status != NO_ERROR) + return status; + + /* Now that we know what our capabilities are, initialize our internal IRQ + * bookkeeping */ + return pcie_init_device_irq_state(common); +} + +static void pcie_scan_function(pcie_bridge_state_t* upstream_bridge, + pcie_config_t* cfg, + uint64_t cfg_phys, + uint dev_id, + uint func_id) { + DEBUG_ASSERT(upstream_bridge && cfg); + DEBUG_ASSERT(dev_id < PCIE_MAX_DEVICES_PER_BUS); + DEBUG_ASSERT(func_id < PCIE_MAX_FUNCTIONS_PER_DEVICE); + + pcie_common_state_t* common = NULL; + uint bus_id = upstream_bridge->managed_bus_id; + uint ndx = (dev_id * PCIE_MAX_FUNCTIONS_PER_DEVICE) + func_id; + + DEBUG_ASSERT(ndx < countof(upstream_bridge->downstream)); + DEBUG_ASSERT(!upstream_bridge->downstream[ndx]); + + /* Is there an actual device here? */ + uint16_t vendor_id = pcie_read16(&cfg->base.vendor_id); + if (vendor_id == PCIE_INVALID_VENDOR_ID) + return; + + LTRACEF("Scanning new function at %02x:%02x.%01x\n", bus_id, dev_id, func_id); + + /* If this function is a PCI bridge, extract the bus ID of the other side of + * the bridge, initialize the bridge node and recurse. + * + * TODO(johngro) : Add some protection against cycles in the bridge + * configuration which could lead to infinite recursion. + */ + uint8_t header_type = pcie_read8(&cfg->base.header_type) & PCI_HEADER_TYPE_MASK; + if (header_type == PCI_HEADER_TYPE_PCI_BRIDGE) { + pci_to_pci_bridge_config_t* bridge_cfg = (pci_to_pci_bridge_config_t*)(&cfg->base); + + uint primary_id = pcie_read8(&bridge_cfg->primary_bus_id); + uint secondary_id = pcie_read8(&bridge_cfg->secondary_bus_id); + + if (primary_id != bus_id) { + TRACEF("PCI-to-PCI bridge detected at %02x:%02x.%01x has invalid primary bus id " + "(%02x)... skipping scan.\n", + bus_id, dev_id, func_id, primary_id); + return; + } + + if (primary_id == secondary_id) { + TRACEF("PCI-to-PCI bridge detected at %02x:%02x.%01x claims to be bridged to itsef " + "(primary %02x == secondary %02x)... skipping scan.\n", + bus_id, dev_id, func_id, primary_id, secondary_id); + return; + } + + /* Allocate and initialize our bridge structure */ + pcie_bridge_state_t* bridge = calloc(1, sizeof(*bridge)); + if (!bridge) { + TRACEF("Failed to allocate bridge node for %02x:%02x.%01x during bus scan.\n", + bus_id, dev_id, func_id); + return; + } + + common = &bridge->common; + bridge->common.type = PCIE_BRIDGE; + bridge->managed_bus_id = secondary_id; + } else { + /* Allocate and initialize our device structure */ + pcie_device_state_t* device = calloc(1, sizeof(*device)); + if (!device) { + TRACEF("Failed to allocate device node for %02x:%02x.%01x during bus scan.\n", + bus_id, dev_id, func_id); + return; + } + + common = &device->common; + device->common.type = PCIE_DEVICE; + } + + /* Link up the graph, and initialize common fields + * + * TODO(johngro): Don't assert that this succeeds. Instead handle sanity + * check failures at runtime. This goes for all of the other things which + * might fail their sanity checks (BAR configurations, header types, etc...) + * + * We should probably keep the device definition around, do our best to + * quiesce it, and flag it as bad to prevent it from ever being handed out + * to a driver. + */ + __UNUSED status_t res; + upstream_bridge->downstream[ndx] = common; + res = pcie_scan_init_common(common, + upstream_bridge, + upstream_bridge->common.bus_drv, + bus_id, dev_id, func_id); + DEBUG_ASSERT(NO_ERROR == res); + + + /* If this was a bridge device, recurse and continue probing. */ + pcie_bridge_state_t* bridge = pcie_downcast_to_bridge(common); + if (bridge) + pcie_scan_bus(bridge); +} + +static void pcie_scan_bus(pcie_bridge_state_t* bridge) { + DEBUG_ASSERT(bridge); + + for (uint dev_id = 0; dev_id < PCIE_MAX_DEVICES_PER_BUS; ++dev_id) { + for (uint func_id = 0; func_id < PCIE_MAX_FUNCTIONS_PER_DEVICE; ++func_id) { + /* Special case for the host controller. */ + if (!bridge->managed_bus_id && !dev_id && !func_id) + continue; + + /* If we can find the config, and it has a valid vendor ID, go ahead + * and scan it looking for a valid function. */ + uint64_t cfg_phys; + pcie_config_t* cfg = pcie_get_config(bridge->common.bus_drv, &cfg_phys, + bridge->managed_bus_id, dev_id, func_id); + bool good_device = cfg && (pcie_read16(&cfg->base.vendor_id) != PCIE_INVALID_VENDOR_ID); + if (good_device) { + /* Don't scan the function again if we have already discovered + * it. If this function happens to be a bridge, go ahead and + * look under it for new devices. */ + uint ndx = (dev_id * PCIE_MAX_FUNCTIONS_PER_DEVICE) + func_id; + DEBUG_ASSERT(ndx < countof(bridge->downstream)); + + pcie_common_state_t* downstream = bridge->downstream[ndx]; + if (!downstream) { + pcie_scan_function(bridge, cfg, cfg_phys, dev_id, func_id); + } else { + pcie_bridge_state_t* downstream_bridge = pcie_downcast_to_bridge(downstream); + if (downstream_bridge) + pcie_scan_bus(downstream_bridge); + } + } + + /* If this was function zero, and there is either no device, or the + * config's header type indicates that this is not a multi-function + * device, then just move on to the next device. */ + if (!func_id && + (!good_device || !(pcie_read8(&cfg->base.header_type) & PCI_HEADER_TYPE_MULTI_FN))) + break; + } + } +} + +static void pcie_free_bridge_device_tree(pcie_common_state_t* common) { + DEBUG_ASSERT(common); + + pcie_device_state_t* device = pcie_downcast_to_device(common); + if (device) { + /* ASSERT that any driver which may have been associated with this + * device has been properly shutdown already. */ + DEBUG_ASSERT(!device->driver); + DEBUG_ASSERT(!device->driver_ctx); + DEBUG_ASSERT(!device->started); + free(device); + } else { + /* If this is not a device, it had better be a bridge */ + pcie_bridge_state_t* bridge = pcie_downcast_to_bridge(common); + DEBUG_ASSERT(bridge); + + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + pcie_common_state_t* downstream_node = bridge->downstream[i]; + + if (downstream_node) + pcie_free_bridge_device_tree(downstream_node); + + free(bridge); + } + } +} + +static bool pcie_allocate_bar(pcie_bar_info_t* info) { + DEBUG_ASSERT(info); + DEBUG_ASSERT(info->dev); + DEBUG_ASSERT(info->dev->bus_drv); + DEBUG_ASSERT(info->dev->cfg); + + /* Do not attempt to remap if we are rescanning the bus and this BAR is + * already allocated */ + if (info->is_allocated) + return true; + + pcie_common_state_t* dev = info->dev; + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + pcie_config_t* cfg = dev->cfg; + + /* Choose which range we will attempt to allocate from, then check to see if we have the + * space. */ + pcie_io_range_alloc_t* io_range = !info->is_mmio + ? &bus_drv->pio + : (info->is_64bit ? &bus_drv->mmio_hi : &bus_drv->mmio_lo); + uint32_t addr_mask = info->is_mmio + ? PCI_BAR_MMIO_ADDR_MASK + : PCI_BAR_PIO_ADDR_MASK; + + /* If check to see if we have the space to allocate within the chosen + * range. In the case of a 64 bit MMIO BAR, if we run out of space in + * the high-memory MMIO range, try the low memory range as well. + */ + uint64_t align_mask, avail, tmp64, align_overhead; + while (true) { + /* MMIO windows and I/O windows on systems where I/O space is actually + * memory mapped must be aligned to a page boundary, at least. */ + bool is_io_space = PCIE_HAS_IO_ADDR_SPACE && !info->is_mmio; + DEBUG_ASSERT(io_range->used <= io_range->io.size); + align_mask = ((info->size >= PAGE_SIZE) || is_io_space) + ? (info->size - 1) + : (PAGE_SIZE - 1); + avail = (io_range->io.size - io_range->used); + tmp64 = io_range->io.bus_addr + io_range->used; + align_overhead = (info->size - (tmp64 & align_mask)) & align_mask; + + if ((avail < align_overhead) || + ((avail - align_overhead) < info->size)) { + + if (io_range == &bus_drv->mmio_hi) { + LTRACEF("Insufficient space to map 64-bit MMIO BAR in high region while " + "configuring BARs for device at %02x:%02x.%01x (cfg vaddr = %p). Falling " + "back on low memory region.\n", + dev->bus_id, dev->dev_id, dev->func_id, cfg); + io_range = &bus_drv->mmio_lo; + continue; + } + + TRACEF("Insufficient space to map BAR region while configuring BARs for device at " + "%02x:%02x.%01x (cfg vaddr = %p)\n", + dev->bus_id, dev->dev_id, dev->func_id, cfg); + TRACEF("BAR region size 0x%llx Alignment overhead 0x%llx Space available 0x%llx\n", + info->size, align_overhead, avail); + + return false; + } + + break; + } + + /* Looks like we have enough space. Update our range bookkeeping, + * and record our allocated and aligned physical address in our + * BAR(s) */ + volatile uint32_t* bar_reg = &cfg->base.base_addresses[info->first_bar_reg]; + + io_range->used += (size_t)(align_overhead + info->size); + tmp64 += align_overhead; + tmp64 &= ((uint64_t)0xFFFFFFFF << 32) | + ((uint64_t)addr_mask); + + pcie_write32(bar_reg, (uint32_t)(tmp64 & 0xFFFFFFFF) | (pcie_read32(bar_reg) & ~addr_mask)); + if (info->is_64bit) + pcie_write32(bar_reg + 1, (uint32_t)(tmp64 >> 32)); + + /* Success! Fill out the info structure and we are done. */ + info->bus_addr = tmp64; + info->is_allocated = true; + return true; +} + +static void pcie_allocate_bars(pcie_common_state_t* common) { + /* TODO(johngro) : This method should be much smarter. Right now, it just + * allocates the BARs in the order it happens to enumerate them in, paying + * no attention to the bridge topology, nor making any effort to be + * efficient in how it divides up the available regions. + * + * Moving forward, it needs to do a better job. It should allocate in a + * depth first fashion across the bridge tree (to make certain that bridge + * regions do not overlap), and within each bridge region, apply some + * heuristic to achieve efficient alignment and packing (probably allocating + * the largest regions first is a good start) + */ + + DEBUG_ASSERT(common); + DEBUG_ASSERT(common->cfg); + + /* If this is a device, and it has been claimed by a driver, do not make any + * changes to the BAR allocation. */ + pcie_device_state_t* device = pcie_downcast_to_device(common); + if (device && device->driver) + return; + + /* Make sure the device has no access to either MMIO or PIO space, cannot + * access main system memory, and has its IRQ(s) disabled */ + pcie_write16(&common->cfg->base.command, PCIE_CFG_COMMAND_INT_DISABLE); + + /* Allocate BARs for the device */ + for (size_t i = 0; i < countof(common->bars); ++i) { + if (common->bars[i].size) + pcie_allocate_bar(&common->bars[i]); + } + + /* If this is a bridge, recurse and keep allocating */ + pcie_bridge_state_t* bridge = pcie_downcast_to_bridge(common); + if (bridge) { + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + if (bridge->downstream[i]) { + pcie_allocate_bars(bridge->downstream[i]); + } + } + } +} + +/* + * Attaches a driver to a PCI device if not already claimed. + */ +static status_t pcie_do_claim_device(pcie_device_state_t* device, + const pcie_driver_registration_t* driver, + void* driver_ctx) { + DEBUG_ASSERT(device); + DEBUG_ASSERT(driver && driver->fn_table); + + pcie_common_state_t* common = &device->common; + pcie_bus_driver_state_t* bus_drv = common->bus_drv; + status_t ret; + + mutex_acquire(&bus_drv->claimed_devices_lock); + + if (list_in_list(&device->claimed_device_node)) { + DEBUG_ASSERT(device->driver); + ret = ERR_BUSY; + } else { + DEBUG_ASSERT(!device->driver); + DEBUG_ASSERT(!device->driver_ctx); + DEBUG_ASSERT(!device->started); + + device->driver = driver; + device->driver_ctx = driver_ctx; + list_add_tail(&bus_drv->claimed_devices, &device->claimed_device_node); + ret = NO_ERROR; + } + + mutex_release(&bus_drv->claimed_devices_lock); + + if (ret == NO_ERROR) { + LTRACEF("Device %04hx:%04hx at %02x:%02x.%01x (cfg vaddr = %p) claimed by driver \"%s\"\n", + device->common.vendor_id, + device->common.device_id, + device->common.bus_id, + device->common.dev_id, + device->common.func_id, + device->common.cfg, + pcie_driver_name(driver)); + } + + return ret; +} + +static void pcie_claim_devices(pcie_common_state_t* common) { + DEBUG_ASSERT(common); + DEBUG_ASSERT(common->cfg); + + /* Currently, we do not allow for custom bridge drivers. If this is a + * bridge, just recurse over its children. */ + pcie_bridge_state_t* bridge = pcie_downcast_to_bridge(common); + if (bridge) { + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + if (bridge->downstream[i]) { + pcie_claim_devices(bridge->downstream[i]); + } + } + + return; + } + + /* This had better be a device, or something is very very wrong */ + pcie_device_state_t* device = pcie_downcast_to_device(common); + DEBUG_ASSERT(device); + if (!device) + return; + + /* Bail out if this device has already been claimed */ + if (device->driver) { + return; + } + + /* Go over our list of builtin drivers and see if any are interested in this + * device. */ + void* driver_ctx = NULL; + + const pcie_driver_registration_t* driver; + for (driver = __start_pcie_builtin_drivers; driver < __stop_pcie_builtin_drivers; ++driver) { + const pcie_driver_fn_table_t* fn_table = driver->fn_table; + DEBUG_ASSERT(fn_table->pcie_probe_fn); + driver_ctx = fn_table->pcie_probe_fn(device); + if (driver_ctx) + break; + } + + /* If we found a driver who wants this device, Finish filling out the + * structure and add the device to the claimed devices list */ + if (driver_ctx) { + __UNUSED status_t result; + DEBUG_ASSERT(driver < __stop_pcie_builtin_drivers); + + result = pcie_do_claim_device(device, driver, driver_ctx); + DEBUG_ASSERT(result == NO_ERROR); + } +} + +/* + * The claimed_devices_lock must be held while calling this function. + */ +static status_t pcie_start_claimed_device(pcie_device_state_t* device) { + const pcie_driver_fn_table_t* fn_table = device->driver->fn_table; + status_t err = NO_ERROR; + if (fn_table->pcie_startup_fn && ((err = fn_table->pcie_startup_fn(device)) != NO_ERROR)) { + /* Device failed to start.*/ + TRACEF("Failed to start %04hx:%04hx at %02x:%02x.%01x claimed by driver " + "\"%s\" (err %d)\n", + pcie_read16(&device->common.cfg->base.vendor_id), + pcie_read16(&device->common.cfg->base.device_id), + device->common.bus_id, + device->common.dev_id, + device->common.func_id, + pcie_driver_name(device->driver), + err); + + /* Call the driver release method (if any) */ + if (fn_table->pcie_release_fn) + fn_table->pcie_release_fn(device); + + /* Clear out any internal driver related bookkeeping */ + device->driver = NULL; + device->driver_ctx = NULL; + DEBUG_ASSERT(!device->started); + } else { + device->started = true; + } + return err; +} + +void pcie_start_claimed_devices(pcie_bus_driver_state_t* bus_drv) { + DEBUG_ASSERT(bus_drv); + + pcie_device_state_t* device; + pcie_device_state_t* tmp; + + /* Try to start device on the claimed list which is not already started. */ + mutex_acquire(&bus_drv->claimed_devices_lock); + list_for_every_entry_safe(&bus_drv->claimed_devices, + device, tmp, pcie_device_state_t, claimed_device_node) { + /* Skip this device if it has already started */ + if (device->started) + continue; + + if (pcie_start_claimed_device(device) != NO_ERROR) { + /* Remove the device from the claimed list */ + list_delete(&device->claimed_device_node); + } + } + mutex_release(&bus_drv->claimed_devices_lock); +} + +static pcie_device_state_t* do_get_nth_device(pcie_common_state_t* node, uint32_t* index) { + const pcie_bridge_state_t* bridge = pcie_downcast_to_bridge(node); + if (bridge) { + for (size_t i = 0; i < countof(bridge->downstream); ++i) { + pcie_common_state_t* downstream = bridge->downstream[i]; + if (downstream) { + pcie_device_state_t* device = do_get_nth_device(downstream, index); + if (device) return device; + } + } + } else { + pcie_device_state_t* device = pcie_downcast_to_device(node); + if (device && (*index)-- == 0) return device; + } + return NULL; +} + +/* + * For iterating through all PCI devices. Returns the nth device, or NULL + * if index is >= the number of PCI devices. + */ +pcie_device_state_t* pci_get_nth_device(uint32_t index) { + pcie_bus_driver_state_t* bus_drv = pcie_get_bus_driver_state(); + if (!bus_drv || !bus_drv->host_bridge) return NULL; + + uint32_t mutable_index = index; + return do_get_nth_device(&bus_drv->host_bridge->common, &mutable_index); +} + +/* + * Attaches a driver to a PCI device. Returns ERR_BUSY if the device has already been + * claimed by another driver. + */ +status_t pcie_claim_and_start_device(pcie_device_state_t* device, + const pcie_driver_registration_t* driver, + void* driver_ctx) { + status_t result; + + result = pcie_do_claim_device(device, driver, driver_ctx); + if (result != NO_ERROR) + return result; + + /* "start" the device. This operation should never fail as this function + * should only ever be called when registering user mode device drivers. + * User mode device drivers should never have a kernel_mode startup hook (so + * they should never fail to start */ + result = pcie_start_claimed_device(device); + DEBUG_ASSERT(result == NO_ERROR); + + return result; +} + +/* + * Shutdown and unclaim a device had been successfully claimed with + * pcie_claim_and_start_device() + */ +void pcie_shutdown_device(pcie_device_state_t* device) { + DEBUG_ASSERT(device && device->driver && device->driver->fn_table); + pcie_bus_driver_state_t* bus_drv = device->common.bus_drv; + const pcie_driver_fn_table_t* fn = device->driver->fn_table; + + LTRACEF("Shutting down PCI device %02x:%02x.%x (%s)...\n", + device->common.bus_id, + device->common.dev_id, + device->common.func_id, + pcie_driver_name(device->driver)); + + /* If startup was ever successfully called for this device, and the device + * has registered a shutdown hook, give it a chance to shutdown cleanly */ + if (device->started && fn->pcie_shutdown_fn) { + fn->pcie_shutdown_fn(device); + device->started = false; + } + + /* Make sure that all IRQs are shutdown and all handlers released for this device */ + pcie_set_irq_mode_disabled(&device->common); + + /* Disable access to MMIO windows, PIO windows, and system memory */ + pcie_write16(&device->common.cfg->base.command, PCIE_CFG_COMMAND_INT_DISABLE); + + /* If the device has a release hook, call it in order to allow it to free + * any dynamically allocated resources. */ + if (fn->pcie_release_fn) + fn->pcie_release_fn(device); + + /* Unclaim the device. */ + mutex_acquire(&bus_drv->claimed_devices_lock); + + DEBUG_ASSERT(list_in_list(&device->claimed_device_node)); + list_delete(&device->claimed_device_node); + device->driver = NULL; + device->driver_ctx = NULL; + + mutex_release(&bus_drv->claimed_devices_lock); +} + +EXPORT_TO_DEBUG_CONSOLE +void pcie_scan_and_start_devices(pcie_bus_driver_state_t* bus_drv) { + DEBUG_ASSERT(bus_drv); + + /* If we have not already discovered the host bridge, start by looking for it */ + if (!bus_drv->host_bridge) { + /* 00:00.0 had better exist and be a host bridge, or we are not going to proceed. */ + uint64_t cfg_phys; + pcie_config_t* cfg = pcie_get_config(bus_drv, &cfg_phys, 0, 0, 0); + if (!cfg) { + TRACEF("Failed to find configuration for root host bridge (device 00:00.0)\n"); + return; + } + + uint16_t vendor_id = pcie_read16(&cfg->base.vendor_id); + if (vendor_id == PCIE_INVALID_VENDOR_ID) { + TRACEF("No device detected at 00:00.0\n"); + return; + } + + /* TODO(johngro) : make a header file with all of the classes, subclasses + * and programming interface magic numbers. */ + uint8_t base_class = pcie_read8(&cfg->base.base_class); + uint8_t sub_class = pcie_read8(&cfg->base.sub_class); + if ((base_class != 0x06) && (sub_class != 0x00)) { + TRACEF("Device 00:00.0 is not a host bridge (base 0x%02x sub 0x%02x)\n", + base_class, sub_class); + return; + } + + /* Allocate the host bridge, initialize the structure and start the scan. */ + pcie_bridge_state_t* root; + root = bus_drv->host_bridge = calloc(1, sizeof(*bus_drv->host_bridge)); + if (!root) { + TRACEF("Failed to allocate bridge node for 00:00.0 during bus scan.\n"); + return; + } + + /* Initialize common fields + * + * TODO(johngro): Don't assert that this succeeds. Instead handle sanity + * check failures at runtime. This goes for all of the other things which + * might fail their sanity checks (BAR configurations, header types, etc...) + * + * We should probably keep the device definition around, do our best to + * quiesce it, and flag it as bad to prevent it from ever being handed out + * to a driver. + */ + __UNUSED status_t res; + res = pcie_scan_init_common(&bus_drv->host_bridge->common, NULL, bus_drv, 0, 0, 0); + DEBUG_ASSERT(NO_ERROR == res); + root->common.type = PCIE_BRIDGE; + } + + /* Now that we have found the host bridge, scan the bus it controls, looking + * for devices and other bridges. */ + pcie_scan_bus(bus_drv->host_bridge); + + /* Now that we have scanned the config space, allocate I/O widows for each + * of the BARs discovered by carving up the regions of the system and I/O + * buses which were provided to us by the platform. */ + pcie_allocate_bars(&bus_drv->host_bridge->common); + + /* Go over our tree and look for drivers who might want to take ownership of + * device. */ + pcie_claim_devices(&bus_drv->host_bridge->common); + + /* Give the devices claimed by drivers a chance to start */ + pcie_start_claimed_devices(bus_drv); +} + +status_t pcie_init(const pcie_init_info_t* init_info) { + pcie_bus_driver_state_t* bus_drv = &g_drv_state; + status_t status = NO_ERROR; + + if (!init_info) { + TRACEF("Failed to initialize PCIe bus driver; no init info provided"); + return ERR_INVALID_ARGS; + } + + if (bus_drv->ecam_windows) { + TRACEF("Failed to initialize PCIe bus driver; driver already initialized\n"); + return ERR_ALREADY_STARTED; + } + + /* Initialize our state */ + status = pcie_init_irqs(bus_drv, init_info); + if (status != NO_ERROR) + return status; + + mutex_init (&bus_drv->claimed_devices_lock); + list_initialize(&bus_drv->claimed_devices); + + bus_drv->mmio_lo.io = init_info->mmio_window_lo; + bus_drv->mmio_hi.io = init_info->mmio_window_hi; + bus_drv->pio.io = init_info->pio_window; + bus_drv->mmio_lo.used = 0; + bus_drv->mmio_hi.used = 0; + bus_drv->pio.used = 0; + + /* In debug builds, sanity check the init info */ + /* TODO(johngro) : turn these into runtime checks and return proper error codes */ +#if LK_DEBUGLEVEL > 1 + /* Start by checking the ECAM window requirements */ + DEBUG_ASSERT(init_info->ecam_windows); + DEBUG_ASSERT(init_info->ecam_window_count > 0); + DEBUG_ASSERT(init_info->ecam_windows[0].bus_start == 0); + for (size_t i = 0; i < init_info->ecam_window_count; ++i) { + const pcie_ecam_range_t* window = init_info->ecam_windows + i; + DEBUG_ASSERT(window->bus_start <= window->bus_end); + DEBUG_ASSERT(window->io_range.size >= ((window->bus_end - window->bus_start + 1u) * + PCIE_ECAM_BYTE_PER_BUS)); + + if (i) { + const pcie_ecam_range_t* prev = init_info->ecam_windows + i - 1; + DEBUG_ASSERT(window->bus_start > prev->bus_end); + } + } + + /* The MMIO low memory region must be below the physical 4GB mark */ + DEBUG_ASSERT((bus_drv->mmio_lo.io.bus_addr + 0ull) < 0x100000000ull); + DEBUG_ASSERT((bus_drv->mmio_lo.io.size + 0ull) < 0x100000000ull); + DEBUG_ASSERT(bus_drv->mmio_lo.io.bus_addr <= (0x100000000ull - bus_drv->mmio_lo.io.size)); + + /* The PIO region must fit somewhere in the architecture's I/O bus region */ + DEBUG_ASSERT((bus_drv->pio.io.bus_addr + 0ull) < PCIE_PIO_ADDR_SPACE_SIZE); + DEBUG_ASSERT((bus_drv->pio.io.size + 0ull) < PCIE_PIO_ADDR_SPACE_SIZE); + DEBUG_ASSERT(bus_drv->pio.io.bus_addr <= PCIE_PIO_ADDR_SPACE_SIZE - bus_drv->pio.io.size); +#endif + + /* Stash the ECAM window info and map the ECAM windows into the bus driver's + * address space so we can access config space. */ + bus_drv->ecam_window_count = init_info->ecam_window_count; + bus_drv->ecam_windows = (pcie_kmap_ecam_range_t*)calloc(bus_drv->ecam_window_count, + sizeof(*bus_drv->ecam_windows)); + if (!bus_drv->ecam_windows) { + TRACEF("Failed to initialize PCIe bus driver; could not allocate %zu " + "bytes for ECAM window state\n", + bus_drv->ecam_window_count * sizeof(*bus_drv->ecam_windows)); + status = ERR_NO_MEMORY; + goto bailout; + } + + /* TODO(johngro) : Don't grab a reference to the kernel's address space. + * What we want is a reference to our current address space (The one that + * the bus driver will run in). */ + DEBUG_ASSERT(!bus_drv->aspace); + bus_drv->aspace = vmm_get_kernel_aspace(); + if (bus_drv->aspace == NULL) { + TRACEF("Failed to initialize PCIe bus driver; could not obtain handle " + "to kernel address space\n"); + status = ERR_GENERIC; + goto bailout; + } + + for (size_t i = 0; i < bus_drv->ecam_window_count; ++i) { + pcie_kmap_ecam_range_t* window = &bus_drv->ecam_windows[i]; + pcie_ecam_range_t* ecam = &window->ecam; + char name_buf[32]; + + *ecam = init_info->ecam_windows[i]; + + if ((ecam->io_range.size & ((size_t)PAGE_SIZE - 1)) || + (ecam->io_range.bus_addr & ((uint64_t)PAGE_SIZE - 1))) { + TRACEF("Failed to initialize PCIe bus driver; Invalid ECAM window " + "(0x%zx @ 0x%llx). Windows must be page aligned and a " + "multiple of pages in length.\n", + ecam->io_range.size, ecam->io_range.bus_addr); + status = ERR_INVALID_ARGS; + goto bailout; + } + + snprintf(name_buf, sizeof(name_buf), "pcie_cfg%zu", i); + name_buf[sizeof(name_buf) - 1] = 0; + + status = vmm_alloc_physical( + bus_drv->aspace, + name_buf, + ecam->io_range.size, + &window->vaddr, + PAGE_SIZE_SHIFT, + ecam->io_range.bus_addr, + 0 /* vmm flags */, + ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + if (status != NO_ERROR) { + TRACEF("Failed to initialize PCIe bus driver; Failed to map ECAM window " + "(0x%zx @ 0x%llx). Status = %d.\n", + ecam->io_range.size, ecam->io_range.bus_addr, status); + goto bailout; + } + } + + /* Scan the bus and start up any drivers who claim devices we discover */ + pcie_scan_and_start_devices(bus_drv); + +bailout: + if (status != NO_ERROR) + pcie_shutdown(); + + return status; +} + +void pcie_shutdown(void) { + pcie_bus_driver_state_t* bus_drv = &g_drv_state; + + /* Force shutdown any devices which happen to still be running. + * + * TODO(johngro) : Rework this so that shutdown of devices can happen in an + * orderly asynchronous fashion before we finally free all of the bus driver + * resources. This is technically not safe as a device might attempt to + * shut itself down while we are tryign to shut down the bus. By the time + * we get to this point, we should be able to assert that all driver have + * been shutdown and unclaimed their devices, and that no new device claims + * can happen. + */ + pcie_device_state_t* device; + while ((device = list_peek_head_type(&bus_drv->claimed_devices, + pcie_device_state_t, + claimed_device_node)) != NULL) { + pcie_shutdown_device(device); + } + + /* Shut off all of our IRQs and free all of our bookkeeping */ + pcie_shutdown_irqs(bus_drv); + + /* Free the device tree */ + if (bus_drv->host_bridge) { + pcie_free_bridge_device_tree(&bus_drv->host_bridge->common); + bus_drv->host_bridge = NULL; + } + + /* Free the ECAM window bookkeeping */ + if (bus_drv->ecam_windows) { + DEBUG_ASSERT(bus_drv->aspace); + + for (size_t i = 0; i < bus_drv->ecam_window_count; ++i) { + pcie_kmap_ecam_range_t* window = &bus_drv->ecam_windows[i]; + + if (window->vaddr) + vmm_free_region(bus_drv->aspace, (vaddr_t)window->vaddr); + } + + free(bus_drv->ecam_windows); + } + + memset(bus_drv, 0, sizeof(*bus_drv)); +} + +void pcie_modify_cmd(const pcie_device_state_t* device, uint16_t clr_bits, uint16_t set_bits) { + DEBUG_ASSERT(device); + spin_lock_saved_state_t irq_state; + pcie_bus_driver_state_t* bus_drv = device->common.bus_drv; + pcie_config_t* cfg = device->common.cfg; + + /* In order to keep internal bookkeeping coherent, and interactions between + * MSI/MSI-X and Legacy IRQ mode safe, API users may not directly manipulate + * the legacy IRQ enable/disable bit. Just ignore them if they try to + * manipulate the bit via the modify cmd API. */ + clr_bits &= ~PCIE_CFG_COMMAND_INT_DISABLE; + set_bits &= ~PCIE_CFG_COMMAND_INT_DISABLE; + + DEBUG_ASSERT(bus_drv && cfg); + spin_lock_irqsave(&bus_drv->legacy_irq_handler_lock, irq_state); + pcie_write16(&cfg->base.command, (pcie_read16(&cfg->base.command) & ~clr_bits) | set_bits); + spin_unlock_irqrestore(&bus_drv->legacy_irq_handler_lock, irq_state); +} + +void pcie_rescan_bus(void) { + pcie_scan_and_start_devices(&g_drv_state); +} diff --git a/kernel/dev/pcie/pcie_caps.c b/kernel/dev/pcie/pcie_caps.c new file mode 100644 index 000000000..b0a83990a --- /dev/null +++ b/kernel/dev/pcie/pcie_caps.c @@ -0,0 +1,507 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +#include "pcie_priv.h" + +#define LOCAL_TRACE 0 + +typedef struct pcie_caps_parse_table_entry { + status_t (*parse)(pcie_common_state_t* common, void* hdr, uint version, uint space_left); + uint cap_id; +} pcie_caps_parse_table_entry_t; + +typedef struct pcie_caps_fetch_hdr_params { + void* hdr; + uint cap_id; + uint cap_version; + uint space_left; +} pcie_caps_fetch_hdr_params_t; + +typedef struct pcie_do_parse_caps_params { + status_t (*fetch_hdr)(pcie_common_state_t* common, + void* prev_hdr, + pcie_caps_fetch_hdr_params_t *out_params); + const pcie_caps_parse_table_entry_t* parse_table; + const size_t parse_table_size; + const uint max_possible_caps; +} pcie_do_parse_caps_params_t; + +/* + * PCI Express Base Specification 3.1a Section 7.8 + */ +static status_t pcie_parse_pci_express_caps(struct pcie_common_state* common, + void* hdr, + uint version, + uint space_left) { + DEBUG_ASSERT(common); + DEBUG_ASSERT(hdr); + DEBUG_ASSERT(!version); // Standard capabilities do not have versions + + /* Size sanity check */ + pcie_capabilities_t* ecam = (pcie_capabilities_t*)hdr; + if (sizeof(*ecam) > space_left) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has illegally positioned PCI " + "Express capability structure. Structure is %zu bytes long, but " + "only %u bytes remain in ECAM standard config.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + sizeof(*ecam), space_left); + return ERR_NOT_VALID; + } + + /* Read the caps field, then parse and sanity check the device/port type */ + uint16_t caps = pcie_read16(&ecam->caps); + pcie_device_type_t devtype = PCS_CAPS_DEVTYPE(caps); + switch (devtype) { + // Type 0 config header types + case PCIE_DEVTYPE_PCIE_ENDPOINT: + case PCIE_DEVTYPE_LEGACY_PCIE_ENDPOINT: + case PCIE_DEVTYPE_RC_INTEGRATED_ENDPOINT: + case PCIE_DEVTYPE_RC_EVENT_COLLECTOR: + if (!pcie_downcast_to_device(common)) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has a Type 0 header " + "PCIe device type (0x%x) in PCIe capabilties structure, " + "but does not have a Type 0 config header.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + devtype); + return ERR_NOT_VALID; + } + break; + + // Type 1 config header types + case PCIE_DEVTYPE_RC_ROOT_PORT: + case PCIE_DEVTYPE_SWITCH_UPSTREAM_PORT: + case PCIE_DEVTYPE_SWITCH_DOWNSTREAM_PORT: + case PCIE_DEVTYPE_PCIE_TO_PCI_BRIDGE: + case PCIE_DEVTYPE_PCI_TO_PCIE_BRIDGE: + if (!pcie_downcast_to_bridge(common)) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has a Type 1 header " + "PCIe device type (0x%x) in PCIe capabilties structure, " + "but does not have a Type 1 config header.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + devtype); + return ERR_NOT_VALID; + } + break; + + default: + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has an illegal PCIe " + "device type (0x%x) in PCIe capabilties structure.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + devtype); + return ERR_NOT_VALID; + } + + /* TODO(johngro): remember to read the MSI/MSI-X interrupt message number + * field when setting up for MSI/MSI-X. We almost certainly need to hook + * this IRQ in order to be aware of any changes to the extended + * capabilities. It is unclear whether or not we should allow this IRQ to + * be passed thru to the device driver or not. + */ + + /* Check device capabilities to see if we support function level reset or + * not */ + uint32_t devcaps = pcie_read32(&ecam->device.caps); + bool has_flr = PCS_DEV_CAPS_FUNC_LEVEL_RESET(devcaps) != 0; + + /* Success, stash our results and we are done */ + common->pcie_caps.ecam = ecam; + common->pcie_caps.devtype = devtype; + common->pcie_caps.has_flr = has_flr; + return NO_ERROR; +} + +/* + * PCI Local Bus Specification 3.0 Section 6.8.1 + */ +static status_t pcie_parse_msi_caps(struct pcie_common_state* common, + void* hdr, + uint version, + uint space_left) { + DEBUG_ASSERT(common); + + /* Zero out the devices MSI IRQ state */ + memset(&common->irq.msi, 0, sizeof(common->irq.msi)); + + /* Make sure we have at least enough space to hold the common header. */ + size_t min_size = PCIE_CAP_MSI_CAP_HDR_SIZE; + if (space_left < min_size) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has illegally positioned MSI " + "capability structure. Structure header is at least %zu bytes " + "long, but only %u bytes remain in ECAM standard config.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + min_size, space_left); + return ERR_NOT_VALID; + } + + /* Extract the control field and figure out what sub-type of MSI capability + * struture we are dealing with. */ + pcie_cap_msi_t* msi_cap = (pcie_cap_msi_t*)hdr; + uint16_t ctrl = pcie_read16(&msi_cap->ctrl); + bool pvm = PCIE_CAP_MSI_CTRL_PVM_SUPPORTED(ctrl); + bool is64bit = PCIE_CAP_MSI_CTRL_64BIT_SUPPORTED(ctrl); + + if (pvm) min_size += is64bit ? sizeof(msi_cap->pvm_64bit) : sizeof(msi_cap->pvm_32bit); + else min_size += is64bit ? sizeof(msi_cap->nopvm_64bit) : sizeof(msi_cap->nopvm_32bit); + + if (space_left < min_size) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has illegally positioned MSI " + "capability structure. Structure %s 64-bit addressing and %s " + "per-vector masking and should be %zu bytes long, but only %u " + "bytes remain in ECAM standard config.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + is64bit ? "supports" : "does not support", + pvm ? "supports" : "does not support", + min_size, space_left); + return ERR_NOT_VALID; + } + + /* Sanity check the Multi-Message Capable field */ + uint max_irqs = 0x1u << PCIE_CAP_MSI_CTRL_GET_MMC(ctrl); + if (max_irqs > PCIE_MAX_MSI_IRQS) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has invalid Multi-Message " + "Capable value in MSI capability structure (%u). Structure " + "claims to support %u vectors, but %u is the maximum allowed.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + PCIE_CAP_MSI_CTRL_GET_MMC(ctrl), max_irqs, PCIE_MAX_MSI_IRQS); + return ERR_NOT_VALID; + } + + /* Success! + * + * Make sure that MSI is disabled and that the Multi-Message Enable field is + * set to 1-vector (multi-message disabled). Then record our capabilities + * in the device's bookkeeping and we are done. + */ + pcie_write16(&msi_cap->ctrl, PCIE_CAP_MSI_CTRL_SET_MME(0, + PCIE_CAP_MSI_CTRL_SET_ENB(0, ctrl))); + + common->irq.msi.cfg = msi_cap; + common->irq.msi.max_irqs = max_irqs; + common->irq.msi.is64bit = is64bit; + if (pvm) { + /* + * If we support PVM, cache a pointer to the mask register (so we don't + * have to keep constantly checking if we are 64 bit or 32 bit MSI to + * figure out where our register is). Also, mask sure that all vectors + * are currently masked. + */ + common->irq.msi.pvm_mask_reg = is64bit + ? &msi_cap->pvm_64bit.mask_bits + : &msi_cap->pvm_32bit.mask_bits; + pcie_write32(common->irq.msi.pvm_mask_reg, 0xFFFFFFFF); + } + + return NO_ERROR; +} + +static status_t pcie_fetch_standard_cap_hdr(pcie_common_state_t* common, + void* prev_hdr, + pcie_caps_fetch_hdr_params_t *out_params) { + DEBUG_ASSERT(common); + DEBUG_ASSERT(common->cfg); + DEBUG_ASSERT(out_params); + + /* By default, return a NULL next header and stop searching */ + memset(out_params, 0, sizeof(*out_params)); + + /* Determine the position of the next header based on the previous header. */ + uint8_t cptr; + if (!prev_hdr) { + /* If there was no previous header at all, check to see if this device + * even has a standard capability list */ + uint16_t status = pcie_read16(&common->cfg->base.status); + if (!(status & PCI_STATUS_NEW_CAPS)) + return NO_ERROR; + + /* Start of the standard config list comes from the capabilities ptr + * member of the config header */ + cptr = pcie_read8(&common->cfg->base.capabilities_ptr) + & ~(PCIE_CAPABILITY_ALIGNMENT - 1); + } else { + /* Extract the next header pointer from the previous header */ + cptr = pcie_cap_hdr_get_next_ptr(pcie_read16((pcie_cap_hdr_t*)prev_hdr)); + } + + /* NULL next pointer means that we are done */ + if (cptr == PCIE_CAP_PTR_NULL) + return NO_ERROR; + + /* Sanity check the capability pointer. */ + if (!((cptr >= PCIE_CAP_PTR_MIN_VALID) && (cptr <= PCIE_CAP_PTR_MAX_VALID))) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has illegal capability " + "pointer (0x%02x) in standard capability list.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + cptr); + return ERR_NOT_VALID; + } + + /* Read the next header */ + static_assert(PCIE_CAP_PTR_MAX_VALID <= PCIE_BASE_CONFIG_SIZE); + uint space = PCIE_BASE_CONFIG_SIZE - cptr; + DEBUG_ASSERT(space >= sizeof(pcie_cap_hdr_t)); + + pcie_cap_hdr_t* hdr_ptr = (pcie_cap_hdr_t*)((uintptr_t)(common->cfg) + cptr); + pcie_cap_hdr_t hdr_val = pcie_read16(hdr_ptr); + + /* Things look good. Fill out our output params and we are done */ + out_params->hdr = hdr_ptr; + out_params->cap_id = pcie_cap_hdr_get_type(hdr_val); + out_params->cap_version = 0x0; + out_params->space_left = space; + return NO_ERROR; +} + +static status_t pcie_fetch_extended_cap_hdr(pcie_common_state_t* common, + void* prev_hdr, + pcie_caps_fetch_hdr_params_t *out_params) { + DEBUG_ASSERT(common); + DEBUG_ASSERT(common->cfg); + DEBUG_ASSERT(out_params); + + /* By default, return a NULL next header and stop searching */ + memset(out_params, 0, sizeof(*out_params)); + + /* Determine the position of the next header based on the previous header. */ + uint16_t cptr = prev_hdr + ? pcie_ext_cap_hdr_get_next_ptr(pcie_read32((pcie_ext_cap_hdr_t*)prev_hdr)) + : PCIE_BASE_CONFIG_SIZE; + + /* NULL next pointer means that we are done */ + if (cptr == PCIE_EXT_CAP_PTR_NULL) + return NO_ERROR; + + /* Sanity check the capability pointer. */ + if (!((cptr >= PCIE_EXT_CAP_PTR_MIN_VALID) && (cptr <= PCIE_EXT_CAP_PTR_MAX_VALID))) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has illegal capability " + "pointer (0x%02x) in extended capability list.\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + cptr); + return ERR_NOT_VALID; + } + + /* Read the next header */ + static_assert(PCIE_EXT_CAP_PTR_MAX_VALID <= PCIE_EXTENDED_CONFIG_SIZE); + uint space = PCIE_EXTENDED_CONFIG_SIZE - cptr; + DEBUG_ASSERT(space >= sizeof(pcie_ext_cap_hdr_t)); + + pcie_ext_cap_hdr_t* hdr_ptr = (pcie_ext_cap_hdr_t*)((uintptr_t)(common->cfg) + cptr); + pcie_ext_cap_hdr_t hdr_val = pcie_read32(hdr_ptr); + + /* + * TODO(johngro) : Figure this out. + * + * In theory all PCIe device are supposed to have an extended caps list. If + * the list is empty, it is supposed to start with a NULL capability ID + * followed by a 0x000 next pointer. + * + * Some devices (such as the PCI-to-ISA bridge in Broadwell, and all of the + * emulated devices in QEMU) seem to fill their extended capabilities config + * region with 0xFF instead of zero. This might be because they are + * supposed to be considered to be "legacy endpoints", however it is unclear + * what the proper way to test for this is. + * + * Section 7.8 of the PCIe 3.1a spec defines the "PCI Express Capability + * Structure" and says "The PCI Express Capability structure is required for + * PCI Express device Functions". Unfortunately there are devices (the Intel + * HDA audio controller in Broadwell, for example) which lack this standard + * header, but possess extended capabilities. + * + * For now, we just special case this. If we see a header in the extended + * config whose values are all 0xFs, just assume that this device has no + * extended capabilities and stop looking. + */ + if (hdr_val == 0xFFFFFFFF) + return NO_ERROR; + + /* A raw extended header value of 0 indicates the end of the list */ + if (!hdr_val) + return NO_ERROR; + + /* Things look good. Fill out our output params and we are done */ + out_params->hdr = hdr_ptr; + out_params->cap_id = pcie_ext_cap_hdr_get_type(hdr_val); + out_params->cap_version = pcie_ext_cap_hdr_get_cap_version(hdr_val); + out_params->space_left = space; + + return NO_ERROR; +} + +static status_t pcie_do_parse_caps(pcie_common_state_t* common, + const pcie_do_parse_caps_params_t* params) { + DEBUG_ASSERT(common); + DEBUG_ASSERT(common->cfg); + DEBUG_ASSERT(params); + DEBUG_ASSERT((params->fetch_hdr == pcie_fetch_standard_cap_hdr) || + (params->fetch_hdr == pcie_fetch_extended_cap_hdr)); + DEBUG_ASSERT(params->parse_table); + + __UNUSED const char* dbg_tag = (params->fetch_hdr == pcie_fetch_standard_cap_hdr) + ? "standard" + : "extended"; + + status_t res; + pcie_caps_fetch_hdr_params_t fp; + uint caps_found = 0; + + /* Fetch headers using the proper fetch function until we encounter a fatal + * error, or we run out of capabilities to parse. */ + for (res = params->fetch_hdr(common, NULL, &fp); + fp.hdr && (res == NO_ERROR); + res = params->fetch_hdr(common, fp.hdr, &fp)) { + /* Sanity check to make sure we're not looping excessively because of + * something like a cycle in our list. Note: this check does not ensure + * that none of the capability structures are overlapping (which might + * be a good thing to check as well), it just makes sure that we have + * not processed more capability headers than it is possible to fit + * inside of a standard or extended configuration block. */ + caps_found += 1; + if (caps_found > params->max_possible_caps) { + TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has too many %s " + "capabilities! %u capability headers have been found so " + "far!\n", + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id, + dbg_tag, caps_found); + return ERR_NOT_VALID; + } + + /* Look through our parse table to find a parse hook */ + const pcie_caps_parse_table_entry_t* entry = NULL; + for (size_t i = 0; (i < params->parse_table_size) && !entry; ++i) { + if (params->parse_table[i].cap_id == fp.cap_id) { + entry = ¶ms->parse_table[i]; + break; + } + } + + /* If we failed to find a hook, log a warning and keep going. A new + * capability ID may have been added to the standard since this code was + * written */ + if (!entry) { + TRACEF("Skipping unnknown %s capability (#%u, id = 0x%02x) for device " + "%02x:%02x.%01x (%04hx:%04hx)\n", + dbg_tag, caps_found, fp.cap_id, + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id); + continue; + } + + LTRACEF("Found %s capability (#%u, id = 0x%02x) for device %02x:%02x.%01x (%04hx:%04hx)\n", + dbg_tag, caps_found, fp.cap_id, + common->bus_id, common->dev_id, common->func_id, + common->vendor_id, common->device_id); + + /* Process the capability if we have a parse hook. Stop processing if + * something goes fatally wrong */ + if (entry->parse) { + res = entry->parse(common, fp.hdr, fp.cap_version, fp.space_left); + if (res != NO_ERROR) + break; + } + } + + return res; +} + +#define PTE(_cap_id, _parse_fn) { .cap_id = _cap_id, .parse = _parse_fn } +static const pcie_caps_parse_table_entry_t PCIE_STANDARD_CAPS_PARSE_TABLE[] = { + PTE(PCIE_CAP_ID_PCI_PWR_MGMT, NULL), + PTE(PCIE_CAP_ID_AGP, NULL), + PTE(PCIE_CAP_ID_VPD, NULL), + PTE(PCIE_CAP_ID_MSI, pcie_parse_msi_caps), + PTE(PCIE_CAP_ID_PCIX, NULL), + PTE(PCIE_CAP_ID_HYPERTRANSPORT, NULL), + PTE(PCIE_CAP_ID_VENDOR, NULL), + PTE(PCIE_CAP_ID_DEBUG_PORT, NULL), + PTE(PCIE_CAP_ID_COMPACTPCI_CRC, NULL), + PTE(PCIE_CAP_ID_PCI_HOTPLUG, NULL), + PTE(PCIE_CAP_ID_PCI_BRIDGE_SUBSYSTEM_VID, NULL), + PTE(PCIE_CAP_ID_AGP_8X, NULL), + PTE(PCIE_CAP_ID_SECURE_DEVICE, NULL), + PTE(PCIE_CAP_ID_PCI_EXPRESS, pcie_parse_pci_express_caps), + PTE(PCIE_CAP_ID_MSIX, NULL), + PTE(PCIE_CAP_ID_SATA_DATA_NDX_CFG, NULL), + PTE(PCIE_CAP_ID_ADVANCED_FEATURES, NULL), + PTE(PCIE_CAP_ID_ENHANCED_ALLOCATION, NULL), +}; + +static const pcie_caps_parse_table_entry_t PCIE_EXTENDED_CAPS_PARSE_TABLE[] = { + PTE(PCIE_EXT_CAP_ID_ADVANCED_ERROR_REPORTING, NULL), + PTE(PCIE_EXT_CAP_ID_VIRTUAL_CHANNEL_NO_MFVC, NULL), + PTE(PCIE_EXT_CAP_ID_DEVICE_SERIAL_NUMBER, NULL), + PTE(PCIE_EXT_CAP_ID_POWER_BUDGETING, NULL), + PTE(PCIE_EXT_CAP_ID_ROOT_COMPLEX_LINK_DECLARATION, NULL), + PTE(PCIE_EXT_CAP_ID_ROOT_COMPLEX_INTERNAL_LINK_CONTROL, NULL), + PTE(PCIE_EXT_CAP_ID_ROOT_COMPLEX_EVENT_COLLECTOR_EP_ASSOC, NULL), + PTE(PCIE_EXT_CAP_ID_MULTI_FUNCTION_VIRTUAL_CHANNEL, NULL), + PTE(PCIE_EXT_CAP_ID_VIRTUAL_CHANNEL_MFVC, NULL), + PTE(PCIE_EXT_CAP_ID_ROOT_COMPLEX_REGISTER_BLOCK, NULL), + PTE(PCIE_EXT_CAP_ID_VENDOR_SPECIFIC, NULL), + PTE(PCIE_EXT_CAP_ID_CONFIGURATION_ACCESS_CORRELATION, NULL), + PTE(PCIE_EXT_CAP_ID_ACCESS_CONTROL_SERVICES, NULL), + PTE(PCIE_EXT_CAP_ID_ALTERNATIVE_ROUTING_ID_INTERPRETATION, NULL), + PTE(PCIE_EXT_CAP_ID_ADDRESS_TRANSLATION_SERVICES, NULL), + PTE(PCIE_EXT_CAP_ID_SINGLE_ROOT_IO_VIRTUALIZATION, NULL), + PTE(PCIE_EXT_CAP_ID_MULTI_ROOT_IO_VIRTUALIZATION, NULL), + PTE(PCIE_EXT_CAP_ID_MULTICAST, NULL), + PTE(PCIE_EXT_CAP_ID_PAGE_REQUEST, NULL), + PTE(PCIE_EXT_CAP_ID_RESERVED_FOR_AMD, NULL), + PTE(PCIE_EXT_CAP_ID_RESIZABLE_BAR, NULL), + PTE(PCIE_EXT_CAP_ID_DYNAMIC_POWER_ALLOCATION, NULL), + PTE(PCIE_EXT_CAP_ID_TLP_PROCESSING_HINTS, NULL), + PTE(PCIE_EXT_CAP_ID_LATENCY_TOLERANCE_REPORTING, NULL), + PTE(PCIE_EXT_CAP_ID_SECONDARY_PCI_EXPRESS, NULL), + PTE(PCIE_EXT_CAP_ID_PROTOCOL_MULTIPLEXING, NULL), + PTE(PCIE_EXT_CAP_ID_PROCESS_ADDRESS_SPACE_ID, NULL), + PTE(PCIE_EXT_CAP_ID_LN_REQUESTER, NULL), + PTE(PCIE_EXT_CAP_ID_DOWNSTREAM_PORT_CONTAINMENT, NULL), + PTE(PCIE_EXT_CAP_ID_L1_PM_SUBSTATES, NULL), + PTE(PCIE_EXT_CAP_ID_PRECISION_TIME_MEASUREMENT, NULL), + PTE(PCIE_EXT_CAP_ID_PCI_EXPRESS_OVER_MPHY, NULL), + PTE(PCIE_EXT_CAP_ID_FRS_QUEUEING, NULL), + PTE(PCIE_EXT_CAP_ID_READINESS_TIME_REPORTING, NULL), + PTE(PCIE_EXT_CAP_ID_DESIGNATED_VENDOR_SPECIFIC, NULL), +}; +#undef PTE + +static const pcie_do_parse_caps_params_t PCIE_STANDARD_PARSE_CAPS_PARAMS = { + .fetch_hdr = pcie_fetch_standard_cap_hdr, + .parse_table = PCIE_STANDARD_CAPS_PARSE_TABLE, + .parse_table_size = countof(PCIE_STANDARD_CAPS_PARSE_TABLE), + .max_possible_caps = PCIE_MAX_CAPABILITIES, +}; + +static const pcie_do_parse_caps_params_t PCIE_EXTENDED_PARSE_CAPS_PARAMS = { + .fetch_hdr = pcie_fetch_extended_cap_hdr, + .parse_table = PCIE_EXTENDED_CAPS_PARSE_TABLE, + .parse_table_size = countof(PCIE_EXTENDED_CAPS_PARSE_TABLE), + .max_possible_caps = PCIE_MAX_EXT_CAPABILITIES, +}; + +status_t pcie_parse_capabilities(struct pcie_common_state* common) { + status_t ret = pcie_do_parse_caps(common, &PCIE_STANDARD_PARSE_CAPS_PARAMS); + if (NO_ERROR != ret) + return ret; + + return pcie_do_parse_caps(common, &PCIE_EXTENDED_PARSE_CAPS_PARAMS); + +}; diff --git a/kernel/dev/pcie/pcie_irqs.c b/kernel/dev/pcie/pcie_irqs.c new file mode 100644 index 000000000..af6e59169 --- /dev/null +++ b/kernel/dev/pcie/pcie_irqs.c @@ -0,0 +1,1010 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie_priv.h" + +#define LOCAL_TRACE 0 + +/****************************************************************************** + * + * Helper routines common to all IRQ modes. + * + ******************************************************************************/ +static void pcie_reset_common_irq_bookkeeping(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + + if (dev->irq.handler_count > 1) { + DEBUG_ASSERT(dev->irq.handlers != &dev->irq.singleton_handler); + free(dev->irq.handlers); + } + + memset(&dev->irq.singleton_handler, 0, sizeof(dev->irq.singleton_handler)); + dev->irq.mode = PCIE_IRQ_MODE_DISABLED; + dev->irq.share_mode = PCIE_IRQ_SHARE_MODE_INVALID; + dev->irq.handlers = NULL; + dev->irq.handler_count = 0; +} + +static status_t pcie_alloc_irq_handlers(pcie_common_state_t* dev, uint requested_irqs) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(requested_irqs); + DEBUG_ASSERT(!dev->irq.handlers); + DEBUG_ASSERT(!dev->irq.handler_count); + + if (requested_irqs == 1) { + memset(&dev->irq.singleton_handler, 0, sizeof(dev->irq.singleton_handler)); + dev->irq.handlers = &dev->irq.singleton_handler; + dev->irq.handler_count = 1; + goto finish_bookkeeping; + } + + dev->irq.handlers = calloc(requested_irqs, sizeof(*dev->irq.handlers)); + if (!dev->irq.handlers) + return ERR_NO_MEMORY; + dev->irq.handler_count = requested_irqs; + +finish_bookkeeping: + for (uint i = 0; i < dev->irq.handler_count; ++i) { + pcie_irq_handler_state_t* h = &dev->irq.handlers[i]; + h->dev = dev; + h->pci_irq_id = i; + spin_lock_init(&h->lock); + } + return NO_ERROR; +} + +/****************************************************************************** + * + * Legacy IRQ mode routines. + * + ******************************************************************************/ +static enum handler_return pcie_legacy_irq_handler(void *arg) { + DEBUG_ASSERT(arg); + pcie_legacy_irq_handler_state_t* legacy_hstate = (pcie_legacy_irq_handler_state_t*)(arg); + pcie_bus_driver_state_t* bus_drv = legacy_hstate->bus_drv; + bool need_resched = false; + + /* Go over the list of device's which share this legacy IRQ and give them a + * chance to handle any interrupts which may be pending in their device. + * Keep track of whether or not any device has requested a re-schedule event + * at the end of this IRQ. Also, if we receive an interrupt for a device + * who has no registered legacy_hstate, print a warning and disable the IRQ at the + * PCIe controller level. With no registered legacy_hstate, we have no way to + * suppress the IRQ and need to disable it in order to prevent locking up + * the whole system. + */ + pcie_common_state_t* dev; + spin_lock(&bus_drv->legacy_irq_handler_lock); + + if (list_is_empty(&legacy_hstate->device_handler_list)) { + TRACEF("Received legacy PCI INT (system IRQ %u), but there are no devices registered to " + "handle this interrupt. This is Very Bad. Disabling the interrupt at the system " + "IRQ level to prevent meltdown.\n", + legacy_hstate->irq_id); + mask_interrupt(legacy_hstate->irq_id); + goto finished; + } + + list_for_every_entry(&legacy_hstate->device_handler_list, + dev, + pcie_common_state_t, + irq.legacy.shared_handler_node) { + pcie_config_t* cfg = dev->cfg; + + uint16_t command = pcie_read16(&cfg->base.command); + uint16_t status = pcie_read16(&cfg->base.status); + + if ((status & PCIE_CFG_STATUS_INT_STS) && !(command & PCIE_CFG_COMMAND_INT_DISABLE)) { + DEBUG_ASSERT(dev); + pcie_irq_handler_retval_t irq_ret = PCIE_IRQRET_MASK; + pcie_irq_handler_state_t* hstate = &dev->irq.handlers[0]; + + if (hstate) { + spin_lock(&hstate->lock); + + if (hstate->handler) { + if (!hstate->masked) + irq_ret = hstate->handler(dev, 0, hstate->ctx); + + if (irq_ret & PCIE_IRQRET_RESCHED) + need_resched = true; + } else { + pcie_device_state_t* tmp = pcie_downcast_to_device(dev); + + TRACEF("Received legacy PCI INT (system IRQ %u) for %02x:%02x.%02x (driver " + "\"%s\"), but no irq handler has been registered by the driver. Force " + "disabling the interrupt.\n", + legacy_hstate->irq_id, + dev->bus_id, dev->dev_id, dev->func_id, + tmp ? pcie_driver_name(tmp->driver) : ""); + } + + if (irq_ret & PCIE_IRQRET_MASK) + hstate->masked = true; + } else { + pcie_device_state_t* tmp = pcie_downcast_to_device(dev); + TRACEF("Received legacy PCI INT (system IRQ %u) for %02x:%02x.%02x (driver " + "\"%s\"), but no irq handlers have been allocated! Force " + "disabling the interrupt.\n", + legacy_hstate->irq_id, + dev->bus_id, dev->dev_id, dev->func_id, + tmp ? pcie_driver_name(tmp->driver) : ""); + } + + if (irq_ret & PCIE_IRQRET_MASK) + pcie_write16(&cfg->base.command, command | PCIE_CFG_COMMAND_INT_DISABLE); + + spin_unlock(&hstate->lock); + } + } + +finished: + spin_unlock(&bus_drv->legacy_irq_handler_lock); + return need_resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +static inline status_t pcie_mask_unmask_legacy_irq(pcie_common_state_t* dev, + bool mask) { + + if (!dev->irq.handlers || !dev->irq.handler_count) + return ERR_INVALID_ARGS; + + pcie_config_t* cfg = dev->cfg; + pcie_irq_handler_state_t* hstate = &dev->irq.handlers[0]; + spin_lock_saved_state_t irq_state; + uint16_t val; + + spin_lock_irqsave(&hstate->lock, irq_state); + + val = pcie_read16(&cfg->base.command); + if (mask) val |= PCIE_CFG_COMMAND_INT_DISABLE; + else val &= ~PCIE_CFG_COMMAND_INT_DISABLE; + pcie_write16(&cfg->base.command, val); + hstate->masked = mask; + + spin_unlock_irqrestore(&hstate->lock, irq_state); + + return NO_ERROR; +} + +/* + * Map from a device's interrupt pin ID to the proper system IRQ ID. Follow the + * PCIe graph up to the root, swizzling as we traverse PCIe switches, + * PCIe-to-PCI bridges, and native PCI-to-PCI bridges. Once we hit the root, + * perform the final remapping using the platform supplied remapping routine. + * + * Platform independent swizzling behavior is documented in the PCIe base + * specification in section 2.2.8.1 and Table 2-20. + * + * Platform dependent remapping is an exercise for the reader. FWIW: PC + * architectures use the _PRT tables in ACPI to perform the remapping. + */ +static uint pcie_map_pin_to_irq(pcie_common_state_t* device, uint pin) { + DEBUG_ASSERT(device); + DEBUG_ASSERT(device->cfg); + DEBUG_ASSERT(pin); + DEBUG_ASSERT(pin <= PCIE_MAX_LEGACY_IRQ_PINS); + + pin -= 1; // Change to 0s indexing + + /* Walk up the PCI/PCIe tree, applying the swizzling rules as we go. Stop + * when we reach the device which is hanging off of the root bus/root + * complex. At this point, platform specific swizzling takes over. + */ + pcie_bridge_state_t* upstream = device->upstream; + DEBUG_ASSERT(upstream); // We should not be mapping IRQs for the root complex + while (upstream->common.upstream) { + /* We need to swizzle every time we pass through... + * 1) A PCI-to-PCI bridge (real or virtual) + * 2) A PCIe-to-PCI bridge + * 3) The Upstream port of a switch. + * + * We do NOT swizzle when we pass through... + * 1) A root port hanging off the root complex. (any swizzling here is up + * to the platform implementation) + * 2) A Downstream switch port. Since downstream PCIe switch ports are + * only permitted to have a single device located at position 0 on + * their "bus", it does not really matter if we do the swizzle or + * not, since it would turn out to be an identity transformation + * anyway. + * + * TODO(johngro) : Consider removing this logic. For both of the cases + * where we traverse a node with a type 1 config header but don't apply + * the swizzling rules (downstream switch ports and root ports), + * application of the swizzle operation should be a no-op because the + * device number of the device hanging off the "secondary bus" should + * always be zero. The final step through the root complex, either from + * integrated endpoint or root port, is left to the system and does not + * pass through this code. + */ + switch (upstream->common.pcie_caps.devtype) { + /* UNKNOWN devices are devices which did not have a PCI Express + * Capabilities structure in their capabilities list. Since every + * device we pass through on the way up the tree should be a device + * with a Type 1 header, these should be PCI-to-PCI bridges (real or + * virtual) */ + case PCIE_DEVTYPE_UNKNOWN: + case PCIE_DEVTYPE_SWITCH_UPSTREAM_PORT: + case PCIE_DEVTYPE_PCIE_TO_PCI_BRIDGE: + case PCIE_DEVTYPE_PCI_TO_PCIE_BRIDGE: + pin = (pin + device->dev_id) % PCIE_MAX_LEGACY_IRQ_PINS; + break; + + default: + break; + } + + /* Climb one branch higher up the tree */ + device = &upstream->common; + upstream = device->upstream; + } + + uint irq; + __UNUSED status_t status; + pcie_bus_driver_state_t* bus_drv = device->bus_drv; + DEBUG_ASSERT(bus_drv && bus_drv->legacy_irq_swizzle); + status = bus_drv->legacy_irq_swizzle(device, pin, &irq); + DEBUG_ASSERT(status == NO_ERROR); + + return irq; +} + +static pcie_legacy_irq_handler_state_t* pcie_find_legacy_irq_handler( + pcie_bus_driver_state_t* bus_drv, + uint irq_id) { + DEBUG_ASSERT(bus_drv); + + /* Search to see if we have already created a shared handler for this system + * level IRQ id already */ + pcie_legacy_irq_handler_state_t* ret = NULL; + mutex_acquire(&bus_drv->legacy_irq_list_lock); + + list_for_every_entry(&bus_drv->legacy_irq_list, + ret, + pcie_legacy_irq_handler_state_t, + legacy_irq_list_node) { + if (irq_id == ret->irq_id) + goto finished; + } + + + /* Looks like we didn't find one. Allocate and initialize a new entry, then + * add it to the list. */ + ret = (pcie_legacy_irq_handler_state_t*)calloc(1, sizeof(*ret)); + ASSERT(ret); + + ret->bus_drv = bus_drv; + ret->irq_id = irq_id; + list_initialize(&ret->device_handler_list); + list_add_tail (&bus_drv->legacy_irq_list, &ret->legacy_irq_list_node); + + register_int_handler(ret->irq_id, pcie_legacy_irq_handler, (void*)ret); + unmask_interrupt(ret->irq_id); + +finished: + mutex_release(&bus_drv->legacy_irq_list_lock); + return ret; +} + +/* Add this device to the shared legacy IRQ handler assigned to it. */ +static void pcie_register_legacy_irq_handler(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.legacy.shared_handler); + DEBUG_ASSERT(!list_in_list(&dev->irq.legacy.shared_handler_node)); + + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + pcie_legacy_irq_handler_state_t* handler = dev->irq.legacy.shared_handler; + spin_lock_saved_state_t irq_state; + DEBUG_ASSERT(bus_drv); + + /* Add this dev to the handler's list. */ + spin_lock_irqsave(&bus_drv->legacy_irq_handler_lock, irq_state); + list_add_tail(&handler->device_handler_list, &dev->irq.legacy.shared_handler_node); + spin_unlock_irqrestore(&bus_drv->legacy_irq_handler_lock, irq_state); +} + +/* + * If this dev is currently registered with its shared legacy IRQ handler, + * unregister it now. + */ +static void pcie_unregister_legacy_irq_handler(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.legacy.shared_handler); + DEBUG_ASSERT(list_in_list(&dev->irq.legacy.shared_handler_node)); + + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + spin_lock_saved_state_t irq_state; + DEBUG_ASSERT(bus_drv); + + /* Make absolutely sure we have been masked at the PCIe config level before + * removing ourselves from the shared handler list. */ + pcie_write16(&dev->cfg->base.command, pcie_read16(&dev->cfg->base.command) | + PCIE_CFG_COMMAND_INT_DISABLE); + + /* Remove the dev from the shared handler's list */ + spin_lock_irqsave(&bus_drv->legacy_irq_handler_lock, irq_state); + list_delete(&dev->irq.legacy.shared_handler_node); + spin_unlock_irqrestore(&bus_drv->legacy_irq_handler_lock, irq_state); +} + +static void pcie_leave_legacy_irq_mode(pcie_common_state_t* dev) { + /* Disable legacy IRQs and unregister from the shared legacy handler */ + pcie_mask_unmask_legacy_irq(dev, true); + pcie_unregister_legacy_irq_handler(dev); + + /* Release any handler storage and reset all of our bookkeeping */ + pcie_reset_common_irq_bookkeeping(dev); +} + +static status_t pcie_enter_legacy_irq_mode(pcie_common_state_t* dev, + uint requested_irqs, + pcie_irq_sharing_mode_t share_mode) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(requested_irqs); + + if (!dev->irq.legacy.pin || + (requested_irqs > 1) || + (share_mode != PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED)) + return ERR_NOT_SUPPORTED; + + /* We can never fail to allocated a single handlers (since we are going to + * use the pre-allocated singleton) */ + __UNUSED status_t res = pcie_alloc_irq_handlers(dev, requested_irqs); + DEBUG_ASSERT(res == NO_ERROR); + DEBUG_ASSERT(dev->irq.handlers == &dev->irq.singleton_handler); + + dev->irq.mode = PCIE_IRQ_MODE_LEGACY; + dev->irq.share_mode = PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED; + + pcie_register_legacy_irq_handler(dev); + return NO_ERROR; +} + +/****************************************************************************** + * + * MSI IRQ mode routines. + * + ******************************************************************************/ +static inline void pcie_set_msi_enb(pcie_common_state_t* dev, bool enb) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.msi.cfg); + + volatile uint16_t* ctrl_reg = &dev->irq.msi.cfg->ctrl; + pcie_write16(ctrl_reg, PCIE_CAP_MSI_CTRL_SET_ENB(pcie_read16(ctrl_reg), enb)); +} + +static inline bool pcie_mask_unmask_msi_irq_locked(pcie_common_state_t* dev, + uint irq_id, + bool mask) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.mode == PCIE_IRQ_MODE_MSI); + DEBUG_ASSERT(irq_id < dev->irq.handler_count); + DEBUG_ASSERT(dev->irq.handlers); + + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + pcie_irq_handler_state_t* hstate = &dev->irq.handlers[irq_id]; + DEBUG_ASSERT(spin_lock_held(&hstate->lock)); + + /* Internal code should not be calling this function if they want to mask + * the interrupt, but it is not possible to do so. */ + DEBUG_ASSERT(!mask || bus_drv->mask_unmask_msi || dev->irq.msi.pvm_mask_reg); + + /* If we can mask at the PCI device level, do so. */ + if (dev->irq.msi.pvm_mask_reg) { + DEBUG_ASSERT(irq_id < PCIE_MAX_MSI_IRQS); + uint32_t val = pcie_read32(dev->irq.msi.pvm_mask_reg); + if (mask) val |= ((uint32_t)1 << irq_id); + else val &= ~((uint32_t)1 << irq_id); + pcie_write32(dev->irq.msi.pvm_mask_reg, val); + } + + + /* If we can mask at the platform interrupt controller level, do so. */ + DEBUG_ASSERT(dev->irq.msi.irq_block.allocated); + DEBUG_ASSERT(irq_id < dev->irq.msi.irq_block.num_irq); + if (bus_drv->mask_unmask_msi) + bus_drv->mask_unmask_msi(&dev->irq.msi.irq_block, irq_id, mask); + + bool ret = hstate->masked; + hstate->masked = mask; + return ret; +} + +static inline status_t pcie_mask_unmask_msi_irq(pcie_common_state_t* dev, + uint irq_id, + bool mask) { + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + spin_lock_saved_state_t irq_state; + + if (irq_id >= dev->irq.handler_count) + return ERR_INVALID_ARGS; + + /* If a mask is being requested, and we cannot mask at either the platform + * interrupt controller or the PCI device level, tell the caller that the + * operation is unsupported. */ + if (mask && !bus_drv->mask_unmask_msi && !dev->irq.msi.pvm_mask_reg) + return ERR_NOT_SUPPORTED; + + DEBUG_ASSERT(dev->irq.handlers); + + spin_lock_irqsave(&dev->irq.handlers[irq_id].lock, irq_state); + pcie_mask_unmask_msi_irq_locked(dev, irq_id, mask); + spin_unlock_irqrestore(&dev->irq.handlers[irq_id].lock, irq_state); + + return NO_ERROR; +} + +static void pcie_mask_all_msi_vectors(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.msi.cfg); + + for (uint i = 0; i < dev->irq.handler_count; i++) + pcie_mask_unmask_msi_irq(dev, i, true); + + /* In theory, this should not be needed as all of the relevant bits should + * have already been masked during the calls to pcie_mask_unmask_msi_irq. + * Just to be careful, however, we explicitly mask all of the upper bits as well. */ + if (dev->irq.msi.pvm_mask_reg) + pcie_write32(dev->irq.msi.pvm_mask_reg, 0xFFFFFFFF); +} + +static void pcie_set_msi_target(pcie_common_state_t* dev, + uint64_t tgt_addr, + uint32_t tgt_data) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.msi.cfg); + DEBUG_ASSERT(dev->irq.msi.is64bit || !(tgt_addr >> 32)); + DEBUG_ASSERT(!(tgt_data >> 16)); + + /* Make sure MSI is disabled and all vectors masked (if possible) before + * changing the target address and data. */ + pcie_set_msi_enb(dev, false); + pcie_mask_all_msi_vectors(dev); + + /* lower bits of the address register are common to all forms of the MSI + * capability structure. Upper address bits and data position depend on + * whether this is a 64 bit or 32 bit version */ + pcie_write32(&dev->irq.msi.cfg->addr, (uint32_t)(tgt_addr & 0xFFFFFFFF)); + if (dev->irq.msi.is64bit) { + pcie_write32(&dev->irq.msi.cfg->nopvm_64bit.addr_upper, (uint32_t)(tgt_addr >> 32)); + pcie_write16(&dev->irq.msi.cfg->nopvm_64bit.data, (uint16_t)(tgt_data & 0xFFFF)); + } else { + pcie_write16(&dev->irq.msi.cfg->nopvm_32bit.data, (uint16_t)(tgt_data & 0xFFFF)); + } +} + +static enum handler_return pcie_msi_irq_handler(void *arg) { + DEBUG_ASSERT(arg); + pcie_irq_handler_state_t* hstate = (pcie_irq_handler_state_t*)arg; + pcie_common_state_t* dev = hstate->dev; + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + + /* No need to save IRQ state; we are in an IRQ handler at the moment. */ + DEBUG_ASSERT(hstate); + spin_lock(&hstate->lock); + + /* Mask our IRQ if we can. */ + bool was_masked; + if (bus_drv->mask_unmask_msi || dev->irq.msi.pvm_mask_reg) { + was_masked = pcie_mask_unmask_msi_irq_locked(dev, hstate->pci_irq_id, true); + } else { + DEBUG_ASSERT(!hstate->masked); + was_masked = false; + } + + /* If the IRQ was masked or the handler removed by the time we got here, + * leave the IRQ masked, unlock and get out. */ + if (was_masked || !hstate->handler) { + spin_unlock(&hstate->lock); + return INT_NO_RESCHEDULE; + } + + /* Dispatch */ + pcie_irq_handler_retval_t irq_ret = hstate->handler(dev, hstate->pci_irq_id, hstate->ctx); + + /* Re-enable the IRQ if asked to do so */ + if (!(irq_ret & PCIE_IRQRET_MASK)) + pcie_mask_unmask_msi_irq_locked(dev, hstate->pci_irq_id, false); + + /* Unlock and request a reschedule if asked to do so */ + spin_unlock(&hstate->lock); + return (irq_ret & PCIE_IRQRET_RESCHED) ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +static void pcie_free_msi_block(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + + /* If no block has been allocated, there is nothing to do */ + if (!dev->irq.msi.irq_block.allocated) + return; + + DEBUG_ASSERT(bus_drv->register_msi_handler); + DEBUG_ASSERT(bus_drv->free_msi_block); + + /* Mask the IRQ at the platform interrupt controller level if we can, and + * unregister any registered handler. */ + const pcie_msi_block_t* b = &dev->irq.msi.irq_block; + for (uint i = 0; i < b->num_irq; i++) { + if (bus_drv->mask_unmask_msi) + bus_drv->mask_unmask_msi(b, i, true); + + bus_drv->register_msi_handler(b, i, NULL, NULL); + } + + DEBUG_ASSERT(bus_drv); + DEBUG_ASSERT(bus_drv->free_msi_block); + + /* Give the block of IRQs back to the plaform */ + bus_drv->free_msi_block(&dev->irq.msi.irq_block); + DEBUG_ASSERT(!dev->irq.msi.irq_block.allocated); +} + +static void pcie_set_msi_multi_message_enb(pcie_common_state_t* dev, uint requested_irqs) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->irq.msi.cfg); + DEBUG_ASSERT((requested_irqs >= 1) && (requested_irqs <= PCIE_MAX_MSI_IRQS)); + + uint log2 = log2_uint_roundup(requested_irqs); + + DEBUG_ASSERT(log2 <= 5); + DEBUG_ASSERT(!log2 || ((0x1u << (log2 - 1)) < requested_irqs)); + DEBUG_ASSERT((0x1u << log2) >= requested_irqs); + + volatile uint16_t* ctrl_reg = &dev->irq.msi.cfg->ctrl; + pcie_write16(ctrl_reg, + PCIE_CAP_MSI_CTRL_SET_MME(log2, pcie_read16(ctrl_reg))); +} + +static void pcie_leave_msi_irq_mode(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->bus_drv); + + /* Disable MSI, mask all vectors and zero out the target */ + pcie_set_msi_target(dev, 0x0, 0x0); + + /* Return any allocated irq block to the platform, unregistering with + * the interrupt controller and synchronizing with the dispatchers in + * the process. */ + pcie_free_msi_block(dev); + + /* Reset our common state, free any allocated handlers */ + pcie_reset_common_irq_bookkeeping(dev); +} + +static status_t pcie_enter_msi_irq_mode(pcie_common_state_t* dev, + uint requested_irqs, + pcie_irq_sharing_mode_t share_mode) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->bus_drv); + DEBUG_ASSERT(requested_irqs); + + status_t res = NO_ERROR; + + /* We cannot go into MSI mode if we don't support MSI at all, or we + * don't support the number of IRQs requested */ + if (!dev->irq.msi.cfg || + !dev->bus_drv->alloc_msi_block || + (requested_irqs > dev->irq.msi.max_irqs)) + return ERR_NOT_SUPPORTED; + + DEBUG_ASSERT(dev->bus_drv->free_msi_block && + dev->bus_drv->register_msi_handler); + + /* Ask the platform for a chunk of MSI compatible IRQs */ + DEBUG_ASSERT(!dev->irq.msi.irq_block.allocated); + res = dev->bus_drv->alloc_msi_block(requested_irqs, + dev->irq.msi.is64bit, + false, /* is_msix == false */ + &dev->irq.msi.irq_block); + if (res != NO_ERROR) { + LTRACEF("Failed to allocate a block of %u MSI IRQs for device " + "%02x:%02x.%01x (res %d)\n", + requested_irqs, dev->bus_id, dev->dev_id, dev->func_id, res); + goto bailout; + } + + /* Allocate our handler table */ + res = pcie_alloc_irq_handlers(dev, requested_irqs); + if (res != NO_ERROR) + goto bailout; + + /* Record our new IRQ and share mode + * + * Note, no matter what the user asked for regarding the sharing mode, we + * only support exclusive mode for MSI right now. + */ + dev->irq.mode = PCIE_IRQ_MODE_MSI; + dev->irq.share_mode = PCIE_IRQ_SHARE_MODE_EXCLUSIVE; + + /* Program the target write transaction into the MSI registers. As a side + * effect, this will ensure that... + * + * 1) MSI mode has been disabled at the top level + * 2) Each IRQ has been masked at system level (if supported) + * 3) Each IRQ has been masked at the PCI PVM level (if supported) + */ + DEBUG_ASSERT(dev->irq.msi.irq_block.allocated); + pcie_set_msi_target(dev, + dev->irq.msi.irq_block.tgt_addr, + dev->irq.msi.irq_block.tgt_data); + + /* Properly program the multi-message enable field in the control register */ + pcie_set_msi_multi_message_enb(dev, requested_irqs); + + /* Register each IRQ with the dispatcher */ + DEBUG_ASSERT(dev->irq.handler_count <= dev->irq.msi.irq_block.num_irq); + for (uint i = 0; i < dev->irq.handler_count; ++i) { + dev->bus_drv->register_msi_handler(&dev->irq.msi.irq_block, + i, + pcie_msi_irq_handler, + dev->irq.handlers + i); + } + + /* Enable MSI at the top level */ + pcie_set_msi_enb(dev, true); + +bailout: + if (res != NO_ERROR) + pcie_leave_msi_irq_mode(dev); + + return res; +} + +/****************************************************************************** + * + * Internal implementation of the Kernel facing API. + * + ******************************************************************************/ +static status_t pcie_mask_unmask_irq_internal(pcie_common_state_t* dev, + uint irq_id, + bool mask); + +static status_t pcie_query_irq_mode_capabilities_internal(const pcie_common_state_t* dev, + pcie_irq_mode_t mode, + pcie_irq_mode_caps_t* out_caps) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->bus_drv); + DEBUG_ASSERT(out_caps); + + pcie_bus_driver_state_t* bus_drv = dev->bus_drv; + memset(out_caps, 0, sizeof(*out_caps)); + + switch (mode) { + case PCIE_IRQ_MODE_LEGACY: + if (!dev->irq.legacy.pin) + return ERR_NOT_SUPPORTED; + + out_caps->max_irqs = 1; + out_caps->per_vector_masking_supported = true; + break; + + case PCIE_IRQ_MODE_MSI: + /* If the platorm cannot allocate MSI blocks, then we don't support MSI, + * even if the device does. */ + if (!bus_drv->alloc_msi_block) + return ERR_NOT_SUPPORTED; + + /* If the device supports MSI, it will have a pointer to the control + * structure in config. */ + if (!dev->irq.msi.cfg) + return ERR_NOT_SUPPORTED; + + /* We support PVM if either the device does, or if the platform is + * capable of masking and unmasking individual IRQs from an MSI block + * allocation. */ + out_caps->max_irqs = dev->irq.msi.max_irqs; + out_caps->per_vector_masking_supported = (dev->irq.msi.pvm_mask_reg != NULL) + || (bus_drv->mask_unmask_msi != NULL); + break; + + case PCIE_IRQ_MODE_MSI_X: + /* If the platorm cannot allocate MSI blocks, then we don't support + * MSI-X, even if the device does. */ + if (!bus_drv->alloc_msi_block) + return ERR_NOT_SUPPORTED; + + /* TODO(johngro) : finish MSI-X implementation. */ + return ERR_NOT_IMPLEMENTED; + + default: + return ERR_INVALID_ARGS; + } + + return NO_ERROR; +} + +static status_t pcie_set_irq_mode_internal(pcie_common_state_t* dev, + pcie_irq_mode_t mode, + uint requested_irqs, + pcie_irq_sharing_mode_t share_mode) { + DEBUG_ASSERT(dev); + + /* Are we disabling IRQs? */ + if (mode == PCIE_IRQ_MODE_DISABLED) { + /* If so, and we are already disabled, cool! Run some sanity checks and we are done */ + if (dev->irq.mode == PCIE_IRQ_MODE_DISABLED) { + DEBUG_ASSERT(dev->irq.share_mode == PCIE_IRQ_SHARE_MODE_INVALID); + DEBUG_ASSERT(!dev->irq.handlers); + DEBUG_ASSERT(!dev->irq.handler_count); + return NO_ERROR; + } + + DEBUG_ASSERT(dev->irq.handlers); + DEBUG_ASSERT(dev->irq.handler_count); + + switch (dev->irq.mode) { + case PCIE_IRQ_MODE_LEGACY: + DEBUG_ASSERT(list_in_list(&dev->irq.legacy.shared_handler_node)); + DEBUG_ASSERT(dev->irq.share_mode == PCIE_IRQ_SHARE_MODE_EXCLUSIVE); + pcie_leave_legacy_irq_mode(dev); + return NO_ERROR; + + case PCIE_IRQ_MODE_MSI: + DEBUG_ASSERT(dev->irq.share_mode == PCIE_IRQ_SHARE_MODE_EXCLUSIVE); + DEBUG_ASSERT(dev->irq.msi.cfg); + DEBUG_ASSERT(dev->irq.msi.irq_block.allocated); + pcie_leave_msi_irq_mode(dev); + return NO_ERROR; + + /* Right now, there should be no way to get into MSI-X mode */ + case PCIE_IRQ_MODE_MSI_X: + DEBUG_ASSERT(false); + return ERR_NOT_IMPLEMENTED; + + default: + /* mode is not one of the valid enum values, this should be impossible */ + DEBUG_ASSERT(false); + return ERR_GENERIC; + } + } + + /* We are picking an active IRQ mode, sanity check the args */ + if (requested_irqs < 1) + return ERR_INVALID_ARGS; + + switch (share_mode) { + case PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED: + case PCIE_IRQ_SHARE_MODE_DEVICE_SHARED: + case PCIE_IRQ_SHARE_MODE_EXCLUSIVE: + break; + default: + return ERR_INVALID_ARGS; + } + + /* If we are picking an active IRQ mode, we need to currently be in the + * disabled state */ + if (dev->irq.mode != PCIE_IRQ_MODE_DISABLED) + return ERR_BAD_STATE; + + switch (mode) { + case PCIE_IRQ_MODE_LEGACY: return pcie_enter_legacy_irq_mode(dev, requested_irqs, share_mode); + case PCIE_IRQ_MODE_MSI: return pcie_enter_msi_irq_mode (dev, requested_irqs, share_mode); + case PCIE_IRQ_MODE_MSI_X: return ERR_NOT_IMPLEMENTED; + default: return ERR_INVALID_ARGS; + } +} + +static status_t pcie_register_irq_handler_internal(pcie_common_state_t* dev, + uint irq_id, + pcie_irq_handler_fn_t handler, + void* ctx) { + DEBUG_ASSERT(dev); + + /* Cannot register a handler if we are currently disabled */ + if (dev->irq.mode == PCIE_IRQ_MODE_DISABLED) + return ERR_BAD_STATE; + + DEBUG_ASSERT(dev->irq.handlers); + DEBUG_ASSERT(dev->irq.handler_count); + + /* Make sure that the IRQ ID is within range */ + if (irq_id >= dev->irq.handler_count) + return ERR_INVALID_ARGS; + + /* Looks good, register (or unregister the handler) and we are done. */ + spin_lock_saved_state_t irq_state; + pcie_irq_handler_state_t* hstate = &dev->irq.handlers[irq_id]; + + spin_lock_irqsave(&hstate->lock, irq_state); + hstate->handler = handler; + hstate->ctx = handler ? ctx : NULL; + spin_unlock_irqrestore(&hstate->lock, irq_state); + + return NO_ERROR; +} + +static status_t pcie_mask_unmask_irq_internal(pcie_common_state_t* dev, + uint irq_id, + bool mask) { + DEBUG_ASSERT(dev); + + /* Cannot manipulate mask status while in the DISABLED state */ + if (dev->irq.mode == PCIE_IRQ_MODE_DISABLED) + return ERR_BAD_STATE; + + DEBUG_ASSERT(dev->irq.handlers); + DEBUG_ASSERT(dev->irq.handler_count); + + /* Make sure that the IRQ ID is within range */ + if (irq_id >= dev->irq.handler_count) + return ERR_INVALID_ARGS; + + /* If we are unmasking (enabling), then we need to make sure that there is a + * handler in place for the IRQ we are enabling. */ + pcie_irq_handler_state_t* hstate = &dev->irq.handlers[irq_id]; + if (!mask && !hstate->handler) + return ERR_BAD_STATE; + + /* OK, everything looks good. Go ahead and make the change based on the + * mode we are curently in. */ + switch (dev->irq.mode) { + case PCIE_IRQ_MODE_LEGACY: return pcie_mask_unmask_legacy_irq(dev, mask); + case PCIE_IRQ_MODE_MSI: return pcie_mask_unmask_msi_irq(dev, irq_id, mask); + case PCIE_IRQ_MODE_MSI_X: return ERR_NOT_IMPLEMENTED; + default: + DEBUG_ASSERT(false); /* This should be un-possible! */ + return ERR_GENERIC; + } + + return NO_ERROR; +} + +/****************************************************************************** + * + * Kernel API; prototypes in dev/pcie_irqs.h + * + ******************************************************************************/ +status_t pcie_query_irq_mode_capabilities(const pcie_common_state_t* dev, + pcie_irq_mode_t mode, + pcie_irq_mode_caps_t* out_caps) { + DEBUG_ASSERT(dev); + status_t ret; + + // TODO(johngro) : obtain API lock here! + ret = pcie_query_irq_mode_capabilities_internal(dev, mode, out_caps); + // TODO(johngro) : release API lock here! + + return ret; +} + +status_t pcie_set_irq_mode(pcie_common_state_t* dev, + pcie_irq_mode_t mode, + uint requested_irqs, + pcie_irq_sharing_mode_t share_mode) { + DEBUG_ASSERT(dev); + status_t ret; + + // TODO(johngro) : obtain API lock here! + ret = pcie_set_irq_mode_internal(dev, mode, requested_irqs, share_mode); + // TODO(johngro) : release API lock here! + + return ret; +} + +status_t pcie_register_irq_handler(pcie_common_state_t* dev, + uint irq_id, + pcie_irq_handler_fn_t handler, + void* ctx) { + DEBUG_ASSERT(dev); + status_t ret; + + // TODO(johngro) : obtain API lock here! + ret = pcie_register_irq_handler_internal(dev, irq_id, handler, ctx); + // TODO(johngro) : release API lock here! + + return ret; +} + +status_t pcie_mask_unmask_irq(pcie_common_state_t* dev, + uint irq_id, + bool mask) { + DEBUG_ASSERT(dev); + status_t ret; + + // TODO(johngro) : obtain API lock here! + ret = pcie_mask_unmask_irq_internal(dev, irq_id, mask); + // TODO(johngro) : release API lock here! + + return ret; +} + +/****************************************************************************** + * + * Internal API; prototypes in pcie_priv.h + * + ******************************************************************************/ +status_t pcie_init_device_irq_state(pcie_common_state_t* dev) { + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->cfg); + DEBUG_ASSERT(!dev->irq.legacy.pin); + DEBUG_ASSERT(!dev->irq.legacy.shared_handler); + + dev->irq.legacy.pin = pcie_read8(&dev->cfg->base.interrupt_pin); + if (dev->irq.legacy.pin) { + uint irq_id; + + irq_id = pcie_map_pin_to_irq(dev, dev->irq.legacy.pin); + dev->irq.legacy.shared_handler = pcie_find_legacy_irq_handler(dev->bus_drv, irq_id); + + if (!dev->irq.legacy.shared_handler) { + LTRACEF("Failed to find or create shared legacy IRQ handler for " + "dev %02x:%02x.%01x (pin %u, irq id %u)\n", + dev->bus_id, dev->dev_id, dev->func_id, + dev->irq.legacy.pin, irq_id); + return ERR_NO_RESOURCES; + } + } + + return NO_ERROR; +} + +status_t pcie_init_irqs(pcie_bus_driver_state_t* bus_drv, const pcie_init_info_t* init_info) { + DEBUG_ASSERT(bus_drv); + DEBUG_ASSERT(init_info); + + if (bus_drv->legacy_irq_swizzle) { + TRACEF("Failed to initialize PCIe IRQs; IRQs already initialized\n"); + return ERR_ALREADY_STARTED; + } + + if (!init_info->legacy_irq_swizzle) { + TRACEF("No platform specific legacy IRQ swizzle supplied!\n"); + return ERR_INVALID_ARGS; + } + + if (((init_info->alloc_msi_block == NULL) != (init_info->free_msi_block == NULL)) || + ((init_info->alloc_msi_block == NULL) != (init_info->register_msi_handler == NULL))) { + TRACEF("Must provide all of the alloc/free/register msi callbacks, or none of them. " + "(alloc == %p, free == %p, register == %p)\n", + init_info->alloc_msi_block, + init_info->free_msi_block, + init_info->register_msi_handler); + return ERR_INVALID_ARGS; + } + + spin_lock_init (&bus_drv->legacy_irq_handler_lock); + mutex_init (&bus_drv->legacy_irq_list_lock); + list_initialize(&bus_drv->legacy_irq_list); + bus_drv->legacy_irq_swizzle = init_info->legacy_irq_swizzle; + bus_drv->alloc_msi_block = init_info->alloc_msi_block; + bus_drv->free_msi_block = init_info->free_msi_block; + bus_drv->register_msi_handler = init_info->register_msi_handler; + bus_drv->mask_unmask_msi = init_info->mask_unmask_msi; + + return NO_ERROR; +} + +void pcie_shutdown_irqs(pcie_bus_driver_state_t* bus_drv) { + DEBUG_ASSERT(bus_drv); + + /* Shut off all of our IRQs and free all of our bookkeeping */ + pcie_legacy_irq_handler_state_t* handler; + mutex_acquire(&bus_drv->legacy_irq_list_lock); + while ((handler = list_remove_head_type(&bus_drv->legacy_irq_list, + pcie_legacy_irq_handler_state_t, + legacy_irq_list_node)) != NULL) { + DEBUG_ASSERT(list_is_empty(&handler->device_handler_list)); + mask_interrupt(handler->irq_id); + register_int_handler(handler->irq_id, NULL, NULL); + free(handler); + } + mutex_release(&bus_drv->legacy_irq_list_lock); +} diff --git a/kernel/dev/pcie/pcie_priv.h b/kernel/dev/pcie/pcie_priv.h new file mode 100644 index 000000000..e22e6dbe5 --- /dev/null +++ b/kernel/dev/pcie/pcie_priv.h @@ -0,0 +1,92 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +struct pcie_bus_driver_state; + +typedef struct pcie_kmap_ecam_range { + pcie_ecam_range_t ecam; + void* vaddr; +} pcie_kmap_ecam_range_t; + +typedef struct pcie_io_range_alloc { + pcie_io_range_t io; + size_t used; +} pcie_io_range_alloc_t; + +typedef struct pcie_legacy_irq_handler_state { + struct pcie_bus_driver_state* bus_drv; + struct list_node legacy_irq_list_node; + struct list_node device_handler_list; + uint irq_id; +} pcie_legacy_irq_handler_state_t; + +typedef struct pcie_bus_driver_state { + mutex_t claimed_devices_lock; + struct list_node claimed_devices; + pcie_bridge_state_t* host_bridge; + + vmm_aspace_t* aspace; + pcie_kmap_ecam_range_t* ecam_windows; + size_t ecam_window_count; + + pcie_io_range_alloc_t mmio_lo; + pcie_io_range_alloc_t mmio_hi; + pcie_io_range_alloc_t pio; + + platform_legacy_irq_swizzle_t legacy_irq_swizzle; + spin_lock_t legacy_irq_handler_lock; + mutex_t legacy_irq_list_lock; + struct list_node legacy_irq_list; + + platform_alloc_msi_block_t alloc_msi_block; + platform_free_msi_block_t free_msi_block; + platform_register_msi_handler_t register_msi_handler; + platform_mask_unmask_msi_t mask_unmask_msi; +} pcie_bus_driver_state_t; + + +/****************************************************************************** + * + * pcie.c + * + ******************************************************************************/ +pcie_bus_driver_state_t* pcie_get_bus_driver_state(void); +void pcie_scan_and_start_devices(pcie_bus_driver_state_t* bus_drv); +pcie_config_t* pcie_get_config(const pcie_bus_driver_state_t* bus_drv, + uint64_t* cfg_phys, + uint bus_id, + uint dev_id, + uint func_id); + +/****************************************************************************** + * + * pcie_caps.c + * + ******************************************************************************/ +status_t pcie_parse_capabilities(struct pcie_common_state* common); + +/****************************************************************************** + * + * pcie_irqs.c + * + ******************************************************************************/ +status_t pcie_init_device_irq_state(pcie_common_state_t* device); +status_t pcie_init_irqs(pcie_bus_driver_state_t* drv, const pcie_init_info_t* init_info); +void pcie_shutdown_irqs(pcie_bus_driver_state_t* drv); + +__END_CDECLS diff --git a/kernel/dev/pcie/rules.mk b/kernel/dev/pcie/rules.mk new file mode 100644 index 000000000..3a3d9e85e --- /dev/null +++ b/kernel/dev/pcie/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/pcie.c \ + $(LOCAL_DIR)/pcie_caps.c \ + $(LOCAL_DIR)/pcie_irqs.c + +include make/module.mk diff --git a/kernel/dev/rules.mk b/kernel/dev/rules.mk new file mode 100644 index 000000000..a0c0b44bb --- /dev/null +++ b/kernel/dev/rules.mk @@ -0,0 +1,22 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/dev.c \ + $(LOCAL_DIR)/driver.c \ + $(LOCAL_DIR)/class/block_api.c \ + $(LOCAL_DIR)/class/i2c_api.c \ + $(LOCAL_DIR)/class/spi_api.c \ + $(LOCAL_DIR)/class/uart_api.c \ + $(LOCAL_DIR)/class/fb_api.c \ + $(LOCAL_DIR)/class/netif_api.c \ + +include make/module.mk diff --git a/kernel/dev/thermal/intel_pch_thermal/BUILD.gn b/kernel/dev/thermal/intel_pch_thermal/BUILD.gn new file mode 100644 index 000000000..306749db6 --- /dev/null +++ b/kernel/dev/thermal/intel_pch_thermal/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("intel_pch_thermal") { + sources = [ + "debug.c", + "thermal.c", + ] + deps = [ + "//kernel/dev/pcie", + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/thermal/intel_pch_thermal/debug.c b/kernel/dev/thermal/intel_pch_thermal/debug.c new file mode 100644 index 000000000..90ffeb121 --- /dev/null +++ b/kernel/dev/thermal/intel_pch_thermal/debug.c @@ -0,0 +1,76 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if WITH_LIB_CONSOLE + +#include +#include +#include + +#include +#include "pch_thermal.h" + +static int cmd_pchtherm_regs(int argc, const cmd_args *argv) +{ + if (g_pch_thermal_context.regs == NULL) { + printf("No device found\n"); + return NO_ERROR; + } + + uint16_t raw_temp = g_pch_thermal_context.regs->temp; + int whole_temp = decode_temp(raw_temp); + int frac_temp = 5 * (raw_temp & 1); + printf("TEMP: %#02x (%d.%d C)\n", raw_temp, whole_temp, frac_temp); + printf("TSC: %#02x\n", g_pch_thermal_context.regs->tsc); + printf("TSS: %#02x\n", g_pch_thermal_context.regs->tss); + printf("TSEL: %#02x\n", g_pch_thermal_context.regs->tsel); + printf("TSREL: %#02x\n", g_pch_thermal_context.regs->tsrel); + printf("TSMIC: %#02x\n", g_pch_thermal_context.regs->tsmic); + printf("CTT: %#02x\n", g_pch_thermal_context.regs->ctt); + printf("TAHV: %#04x\n", g_pch_thermal_context.regs->tahv); + printf("TALV: %#04x\n", g_pch_thermal_context.regs->talv); + printf("TSPM: %#04x\n", g_pch_thermal_context.regs->tspm); + printf("TL: %#08x\n", g_pch_thermal_context.regs->tl); + printf("TL2: %#08x\n", g_pch_thermal_context.regs->tl2); + printf("PHL: %#04x\n", g_pch_thermal_context.regs->phl); + printf("PHLC: %#02x\n", g_pch_thermal_context.regs->phlc); + printf("TAS: %#02x\n", g_pch_thermal_context.regs->tas); + printf("TSPIEN: %#02x\n", g_pch_thermal_context.regs->tspien); + printf("TSGPEN: %#02x\n", g_pch_thermal_context.regs->tsgpen); + return NO_ERROR; +} + +static int cmd_pchtherm(int argc, const cmd_args *argv) +{ + static const struct { + const char* name; + int (*subcmd)(int, const cmd_args*); + } SUBCMDS[] = { + { "regs", cmd_pchtherm_regs }, + }; + + if (argc >= 2) { + for (size_t i = 0; i < countof(SUBCMDS); ++i) + if (!strcmp(argv[1].str, SUBCMDS[i].name)) + return SUBCMDS[i].subcmd(argc, argv); + } + + printf("usage: %s [args]\n" + "Valid cmds are...\n" + "\thelp : Show this message\n" + "\tregs : Dump the registers for the device, if present\n", + argv[0].str); + + return NO_ERROR; +} + +STATIC_COMMAND_START +STATIC_COMMAND("pchtherm", + "Low level commands to manipulate the Intel PCH Thermal Sensors device", + &cmd_pchtherm) +STATIC_COMMAND_END(intel_pch_thermal_commands); + +#endif diff --git a/kernel/dev/thermal/intel_pch_thermal/pch_thermal.h b/kernel/dev/thermal/intel_pch_thermal/pch_thermal.h new file mode 100644 index 000000000..81f08cc97 --- /dev/null +++ b/kernel/dev/thermal/intel_pch_thermal/pch_thermal.h @@ -0,0 +1,88 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +struct pcie_device_state; + +struct pch_thermal_context { + vmm_aspace_t *aspace; + struct pch_thermal_registers *regs; + struct pcie_device_state* pci_device; +}; + +static inline uint16_t encode_temp(int16_t temp_c) +{ + uint16_t val = (temp_c + 50) * 2; + ASSERT(!(val & ~0x1ff)); + return val; +} + +static inline int16_t decode_temp(uint16_t val) +{ + val = val & 0x1ff; + return val / 2 - 50; +} + +/* Thermal registers */ +struct __PACKED pch_thermal_registers { + /* Temperature */ + volatile uint16_t temp; + volatile uint16_t _reserved0; + /* Thermal Sensor Control */ + volatile uint8_t tsc; + volatile uint8_t _reserved1; + /* Thermal Sensor Status */ + volatile uint8_t tss; + volatile uint8_t _reserved2; + /* Thermal Sensor Enable and Lock */ + volatile uint8_t tsel; + volatile uint8_t _reserved3; + /* Thermal Sensor Report Enable and Lock */ + volatile uint8_t tsrel; + volatile uint8_t _reserved4; + /* Thermal Sensor SMI Control */ + volatile uint8_t tsmic; + volatile uint8_t _reserved5[3]; + /* Catastrophic trip Point */ + volatile uint16_t ctt; + volatile uint16_t _reserved6; + /* Thermal Alert High Value */ + volatile uint16_t tahv; + volatile uint16_t _reserved7; + /* Thermal Alert Low Value */ + volatile uint16_t talv; + volatile uint16_t _reserved8; + /* Thermal Sensor Power Management */ + volatile uint16_t tspm; + volatile uint8_t _reserved9[0x40-0x1e]; + /* Throttle Levels */ + volatile uint32_t tl; + volatile uint8_t _reserved10[0x50-0x44]; + volatile uint32_t tl2; + volatile uint8_t _reserved11[0x60-0x54]; + /* PCH Hot Level */ + volatile uint16_t phl; + /* PCH Control */ + volatile uint8_t phlc; + volatile uint8_t _reserved12[0x80-0x63]; + /* Thermal Alert Status */ + volatile uint8_t tas; + volatile uint8_t _reserved13; + /* PCI Interrupt Event Enables */ + volatile uint8_t tspien; + volatile uint8_t _reserved14; + /* PCI Interrupt Event Enables */ + volatile uint8_t tsgpen; +}; +STATIC_ASSERT(__offsetof(struct pch_thermal_registers, tsgpen) == 0x84); + +#if WITH_LIB_CONSOLE +extern struct pch_thermal_context g_pch_thermal_context; +#endif diff --git a/kernel/dev/thermal/intel_pch_thermal/rules.mk b/kernel/dev/thermal/intel_pch_thermal/rules.mk new file mode 100644 index 000000000..2a09c41a5 --- /dev/null +++ b/kernel/dev/thermal/intel_pch_thermal/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/thermal.c + +include make/module.mk diff --git a/kernel/dev/thermal/intel_pch_thermal/thermal.c b/kernel/dev/thermal/intel_pch_thermal/thermal.c new file mode 100644 index 000000000..1b8ec30b8 --- /dev/null +++ b/kernel/dev/thermal/intel_pch_thermal/thermal.c @@ -0,0 +1,172 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#include +#include "pch_thermal.h" + +#define LOCAL_TRACE 0 + +/* Vendor and device IDs */ +#define INTEL_VID 0x8086 +static const uint16_t intel_dids[] = { 0x3a32, 0x9ca4 }; + +/* Driver state */ +struct pch_thermal_context g_pch_thermal_context; + +static void pch_thermal_cleanup(struct pch_thermal_context* ctx) +{ + if (ctx->pci_device) + pcie_set_irq_mode_disabled(&ctx->pci_device->common); + + if (ctx->regs) { + /* Disable thermal sensor */ + ctx->regs->tsel &= ~1; + + /* Unmap our registers */ + vmm_free_region(ctx->aspace, (vaddr_t)ctx->regs); + } + + ctx->aspace = NULL; + ctx->regs = NULL; +} + +pcie_irq_handler_retval_t pch_thermal_irq_handler(struct pcie_common_state* dev, + uint irq_id, + void* ctx) +{ + TRACEF("Thermal interrupt\n"); + return PCIE_IRQRET_NO_ACTION; +} + +static void* pch_thermal_probe(struct pcie_device_state* pci_device) +{ + /* If we've already claimed a device, do not claim another */ + if (g_pch_thermal_context.pci_device) { + return NULL; + } + + g_pch_thermal_context.pci_device = pci_device; + + bool claim = false; + if (pci_device->common.vendor_id == INTEL_VID) { + for (uint i = 0; i < countof(intel_dids); ++i) { + if (pci_device->common.device_id == intel_dids[i]) { + claim = true; + break; + } + } + } + + if (!claim) { + return NULL; + } + + return &g_pch_thermal_context; +} + +static status_t pch_thermal_startup(struct pcie_device_state* pci_device) +{ + DEBUG_ASSERT(!g_pch_thermal_context.regs); + DEBUG_ASSERT(g_pch_thermal_context.pci_device == pci_device); + status_t status; + + g_pch_thermal_context.aspace = vmm_get_kernel_aspace(); + + const pcie_bar_info_t* bar_info = pcie_get_device_bar_info( + pci_device, + 0); + DEBUG_ASSERT(bar_info->bus_addr); + + /* Select legacy IRQ Mode */ + status = pcie_set_irq_mode(&pci_device->common, + PCIE_IRQ_MODE_LEGACY, + 1, + PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED); + if (status != NO_ERROR) { + TRACEF("Failed to configure PCIe device for Legacy IRQ mode (err = %d)\n", status); + goto finished; + } + + /* Register our IRQ handler */ + status = pcie_register_irq_handler(&pci_device->common, 0, pch_thermal_irq_handler, NULL); + if (status != NO_ERROR) { + TRACEF("Failed to register Legacy IRQ handler (err = %d)\n", status); + goto finished; + } + + uint64_t size = ROUNDUP(bar_info->size, PAGE_SIZE); + void *vaddr = NULL; + status = vmm_alloc_physical( + g_pch_thermal_context.aspace, + "pch_therm", + size, + &vaddr, + PAGE_SIZE_SHIFT, + bar_info->bus_addr, + 0, + ARCH_MMU_FLAG_UNCACHED_DEVICE | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + if (status != NO_ERROR) { + TRACEF("Failed to map registers (err = %d)\n", status); + goto finished; + } + DEBUG_ASSERT(vaddr); + + pcie_enable_mmio(pci_device, true); + + g_pch_thermal_context.regs = vaddr; + + /* Enable thermal sensor */ + g_pch_thermal_context.regs->tsel |= 1; + + /* Set the catastrophic trip threshold */ + int16_t current_ctt = decode_temp(g_pch_thermal_context.regs->ctt & 0x1ff); + if (current_ctt >= 113) { + /* The PCH spec suggests we should avoid 120C, but the sensor might be + * 2C off due to the location of the sensor. In the range 90C to 120C, + * the sensor has +- 5C accuracy, so take that into account, too. */ + g_pch_thermal_context.regs->ctt = encode_temp(113); + } + + /* Enable poweroff on catastrophic threshold trip */ + g_pch_thermal_context.regs->tsc |= 1; + + /* Enable our interrupt */ + status = pcie_unmask_irq(&pci_device->common, 0); + if (status != NO_ERROR) { + TRACEF("Failed to unmask IRQ (err = %d)\n", status); + goto finished; + } + +finished: + if (status != NO_ERROR) + pch_thermal_cleanup(&g_pch_thermal_context); + + return status; +} + +static void pch_thermal_shutdown(struct pcie_device_state* pci_device) +{ + DEBUG_ASSERT(pci_device == g_pch_thermal_context.pci_device); + pch_thermal_cleanup(&g_pch_thermal_context); +} + +static void pch_thermal_release(struct pcie_device_state* pci_device) +{ + DEBUG_ASSERT(!g_pch_thermal_context.regs); + DEBUG_ASSERT(!g_pch_thermal_context.pci_device); +} + +static pcie_driver_fn_table_t DRV_FN_TABLE = { + .pcie_probe_fn = pch_thermal_probe, + .pcie_startup_fn = pch_thermal_startup, + .pcie_shutdown_fn = pch_thermal_shutdown, + .pcie_release_fn = pch_thermal_release, +}; + +STATIC_PCIE_DRIVER(intel_pch_thermal, "Intel PCH Thermal Sensors", DRV_FN_TABLE); diff --git a/kernel/dev/timer/arm_cortex_a9/arm_cortex_a9_timer.c b/kernel/dev/timer/arm_cortex_a9/arm_cortex_a9_timer.c new file mode 100644 index 000000000..0f70c1fc3 --- /dev/null +++ b/kernel/dev/timer/arm_cortex_a9/arm_cortex_a9_timer.c @@ -0,0 +1,210 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* driver for cortex-a9's private timer */ +#define LOCAL_TRACE 0 + +/* interrupts for cortex-a9 timer and watchdog */ +#define CPU_GLOB_TIMER_INT 27 +#define CPU_PRIV_TIMER_INT 29 +#define CPU_WATCHDOG_INT 30 + +/* offsets into the per cpu private scu base */ +#define GLOBAL_TIMER_OFFSET (0x0200) +#define PRIV_TIMER_OFFSET (0x0600) + +#define TIMREG(reg) (*REG32(scu_control_base + PRIV_TIMER_OFFSET + (reg))) + +#define TIMER_LOAD (0x00) +#define TIMER_COUNTER (0x04) +#define TIMER_CONTROL (0x08) +#define TIMER_ISR (0x0c) +#define WDOG_LOAD (0x20) +#define WDOG_COUNTER (0x24) +#define WDOG_CONTROL (0x28) +#define WDOG_ISR (0x2c) + +#define GTIMREG(reg) (*REG32(scu_control_base + GLOBAL_TIMER_OFFSET + (reg))) + +#define GTIMER_COUNT_LO (0x00) +#define GTIMER_COUNT_HI (0x04) +#define GTIMER_CONTROL (0x08) +#define GTIMER_ISR (0x0c) +#define GTIMER_COMPARE_LO (0x10) +#define GTIMER_COMPARE_HI (0x14) +#define GTIMER_INCREMENT (0x18) + +static platform_timer_callback t_callback; +static addr_t scu_control_base; +static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE; + +static lk_time_t periodic_interval; +static lk_time_t oneshot_interval; +static uint32_t timer_freq; +static struct fp_32_64 timer_freq_msec_conversion; +static struct fp_32_64 timer_freq_usec_conversion_inverse; +static struct fp_32_64 timer_freq_msec_conversion_inverse; + +static void arm_cortex_a9_timer_init_percpu(uint level); + +uint64_t get_global_val(void) +{ + uint32_t lo, hi; + +retry: + hi = GTIMREG(GTIMER_COUNT_HI); + lo = GTIMREG(GTIMER_COUNT_LO); + if (GTIMREG(GTIMER_COUNT_HI) != hi) + goto retry; + + return ((uint64_t)hi << 32 | lo); +} + +lk_bigtime_t current_time_hires(void) +{ + lk_bigtime_t time; + + time = u64_mul_u64_fp32_64(get_global_val(), timer_freq_usec_conversion_inverse); + + return time; +} + +lk_time_t current_time(void) +{ + lk_time_t time; + + time = u32_mul_u64_fp32_64(get_global_val(), timer_freq_msec_conversion_inverse); + + return time; +} + +status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) +{ + LTRACEF("callback %p, arg %p, interval %u\n", callback, arg, interval); + + uint64_t ticks = u64_mul_u64_fp32_64(interval, timer_freq_msec_conversion); + if (unlikely(ticks == 0)) + ticks = 1; + if (unlikely(ticks > 0xffffffff)) + ticks = 0xffffffff; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + t_callback = callback; + + periodic_interval = interval; + + // disable timer + TIMREG(TIMER_CONTROL) = 0; + + TIMREG(TIMER_LOAD) = ticks; + TIMREG(TIMER_CONTROL) = (1<<2) | (1<<1) | (1<<0); // irq enable, autoreload, enable + + spin_unlock_irqrestore(&lock, state); + + return NO_ERROR; +} + +status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) +{ + LTRACEF("callback %p, arg %p, timeout %u\n", callback, arg, interval); + + uint64_t ticks = u64_mul_u64_fp32_64(interval, timer_freq_msec_conversion); + if (unlikely(ticks == 0)) + ticks = 1; + if (unlikely(ticks > 0xffffffff)) + ticks = 0xffffffff; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + t_callback = callback; + oneshot_interval = interval; + + // disable timer + TIMREG(TIMER_CONTROL) = 0; + + TIMREG(TIMER_LOAD) = ticks; + TIMREG(TIMER_CONTROL) = (1<<2) | (1<<0) | (1<<0); // irq enable, oneshot, enable + + spin_unlock_irqrestore(&lock, state); + + return NO_ERROR; +} + +void platform_stop_timer(void) +{ + LTRACE; + + TIMREG(TIMER_CONTROL) = 0; +} + +static enum handler_return platform_tick(void *arg) +{ + LTRACE; + + TIMREG(TIMER_ISR) = 1; // ack the irq + + if (t_callback) { + return t_callback(arg, current_time()); + } else { + return INT_NO_RESCHEDULE; + } +} + +void arm_cortex_a9_timer_init(addr_t _scu_control_base, uint32_t freq) +{ + scu_control_base = _scu_control_base; + + arm_cortex_a9_timer_init_percpu(0); + + /* save the timer frequency for later calculations */ + timer_freq = freq; + + /* precompute the conversion factor for global time to real time */ + fp_32_64_div_32_32(&timer_freq_msec_conversion, timer_freq, 1000); + fp_32_64_div_32_32(&timer_freq_usec_conversion_inverse, 1000000, timer_freq); + fp_32_64_div_32_32(&timer_freq_msec_conversion_inverse, 1000, timer_freq); +} + +static void arm_cortex_a9_timer_init_percpu(uint level) +{ + /* disable timer */ + TIMREG(TIMER_CONTROL) = 0; + + /* kill the watchdog */ + TIMREG(WDOG_CONTROL) = 0; + + /* ack any irqs that may be pending */ + TIMREG(TIMER_ISR) = 1; + + /* register the platform tick on each cpu */ + register_int_handler(CPU_PRIV_TIMER_INT, &platform_tick, NULL); + unmask_interrupt(CPU_PRIV_TIMER_INT); +} + +/* secondary cpu initialize the timer just before the kernel starts with interrupts enabled */ +LK_INIT_HOOK_FLAGS(arm_cortex_a9_timer_init_percpu, + arm_cortex_a9_timer_init_percpu, + LK_INIT_LEVEL_THREADING - 1, LK_INIT_FLAG_SECONDARY_CPUS); diff --git a/kernel/dev/timer/arm_cortex_a9/include/dev/timer/arm_cortex_a9.h b/kernel/dev/timer/arm_cortex_a9/include/dev/timer/arm_cortex_a9.h new file mode 100644 index 000000000..da2a492df --- /dev/null +++ b/kernel/dev/timer/arm_cortex_a9/include/dev/timer/arm_cortex_a9.h @@ -0,0 +1,12 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +void arm_cortex_a9_timer_init(addr_t scu_control_base, uint32_t freq); diff --git a/kernel/dev/timer/arm_cortex_a9/rules.mk b/kernel/dev/timer/arm_cortex_a9/rules.mk new file mode 100644 index 000000000..4ed34becf --- /dev/null +++ b/kernel/dev/timer/arm_cortex_a9/rules.mk @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +GLOBAL_DEFINES += \ + PLATFORM_HAS_DYNAMIC_TIMER=1 + +MODULE_DEPS += \ + lib/fixed_point + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm_cortex_a9_timer.c + +include make/module.mk diff --git a/kernel/dev/timer/arm_generic/BUILD.gn b/kernel/dev/timer/arm_generic/BUILD.gn new file mode 100644 index 000000000..20db6fa95 --- /dev/null +++ b/kernel/dev/timer/arm_generic/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_arm_generic_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("arm_generic") { + public_configs = [ ":_arm_generic_config" ] + defines = [ "PLATFORM_HAS_DYNAMIC_TIMER=1" ] + sources = [ + "arm_generic_timer.c", + ] + deps = [ + "//kernel/dev/interrupt", + "//kernel/lib/fixed_point", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/timer/arm_generic/arm_generic_timer.c b/kernel/dev/timer/arm_generic/arm_generic_timer.c new file mode 100644 index 000000000..86641d3aa --- /dev/null +++ b/kernel/dev/timer/arm_generic/arm_generic_timer.c @@ -0,0 +1,361 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#include + +#if ARCH_ARM64 + +/* CNTFRQ AArch64 register */ +#define TIMER_REG_CNTFRQ cntfrq_el0 + +/* CNTP AArch64 registers */ +#define TIMER_REG_CNTP_CTL cntp_ctl_el0 +#define TIMER_REG_CNTP_CVAL cntp_cval_el0 +#define TIMER_REG_CNTP_TVAL cntp_tval_el0 +#define TIMER_REG_CNTPCT cntpct_el0 + +/* CNTPS AArch64 registers */ +#define TIMER_REG_CNTPS_CTL cntps_ctl_el1 +#define TIMER_REG_CNTPS_CVAL cntps_cval_el1 +#define TIMER_REG_CNTPS_TVAL cntps_tval_el1 +#define TIMER_REG_CNTPSCT cntpct_el0 + +/* CNTV AArch64 registers */ +#define TIMER_REG_CNTV_CTL cntv_ctl_el0 +#define TIMER_REG_CNTV_CVAL cntv_cval_el0 +#define TIMER_REG_CNTV_TVAL cntv_tval_el0 +#define TIMER_REG_CNTVCT cntvct_el0 + +#define READ_TIMER_REG32(reg) ARM64_READ_SYSREG(reg) +#define READ_TIMER_REG64(reg) ARM64_READ_SYSREG(reg) +#define WRITE_TIMER_REG32(reg, val) ARM64_WRITE_SYSREG(reg, val) +#define WRITE_TIMER_REG64(reg, val) ARM64_WRITE_SYSREG(reg, val) + +#else + +/* CNTFRQ AArch32 register */ +#define TIMER_REG_CNTFRQ "c0, 0" + +/* CNTP AArch32 registers */ +#define TIMER_REG_CNTP_CTL "c2, 1" +#define TIMER_REG_CNTP_CVAL "2" +#define TIMER_REG_CNTP_TVAL "c2, 0" +#define TIMER_REG_CNTPCT "0" + +/* CNTPS AArch32 registers are banked and accessed though CNTP */ +#define CNTPS CNTP + +/* CNTV AArch32 registers */ +#define TIMER_REG_CNTV_CTL "c3, 1" +#define TIMER_REG_CNTV_CVAL "3" +#define TIMER_REG_CNTV_TVAL "c3, 0" +#define TIMER_REG_CNTVCT "1" + +#define READ_TIMER_REG32(reg) \ +({ \ + uint32_t _val; \ + __asm__ volatile("mrc p15, 0, %0, c14, " reg : "=r" (_val)); \ + _val; \ +}) + +#define READ_TIMER_REG64(reg) \ +({ \ + uint64_t _val; \ + __asm__ volatile("mrrc p15, " reg ", %0, %H0, c14" : "=r" (_val)); \ + _val; \ +}) + +#define WRITE_TIMER_REG32(reg, val) \ +({ \ + __asm__ volatile("mcr p15, 0, %0, c14, " reg :: "r" (val)); \ + ISB; \ +}) + +#define WRITE_TIMER_REG64(reg, val) \ +({ \ + __asm__ volatile("mcrr p15, " reg ", %0, %H0, c14" :: "r" (val)); \ + ISB; \ +}) + +#endif + +#ifndef TIMER_ARM_GENERIC_SELECTED +#define TIMER_ARM_GENERIC_SELECTED CNTP +#endif + +#define COMBINE3(a,b,c) a ## b ## c +#define XCOMBINE3(a,b,c) COMBINE3(a, b, c) + +#define SELECTED_TIMER_REG(reg) XCOMBINE3(TIMER_REG_, TIMER_ARM_GENERIC_SELECTED, reg) +#define TIMER_REG_CTL SELECTED_TIMER_REG(_CTL) +#define TIMER_REG_CVAL SELECTED_TIMER_REG(_CVAL) +#define TIMER_REG_TVAL SELECTED_TIMER_REG(_TVAL) +#define TIMER_REG_CT SELECTED_TIMER_REG(CT) + + +static platform_timer_callback t_callback; +static int timer_irq; + +struct fp_32_64 cntpct_per_ms; +struct fp_32_64 ms_per_cntpct; +struct fp_32_64 us_per_cntpct; + +static uint64_t lk_time_to_cntpct(lk_time_t lk_time) +{ + return u64_mul_u32_fp32_64(lk_time, cntpct_per_ms); +} + +static lk_time_t cntpct_to_lk_time(uint64_t cntpct) +{ + return u32_mul_u64_fp32_64(cntpct, ms_per_cntpct); +} + +static lk_bigtime_t cntpct_to_lk_bigtime(uint64_t cntpct) +{ + return u64_mul_u64_fp32_64(cntpct, us_per_cntpct); +} + +static uint32_t read_cntfrq(void) +{ + uint32_t cntfrq; + + cntfrq = READ_TIMER_REG32(TIMER_REG_CNTFRQ); + LTRACEF("cntfrq: 0x%08x, %u\n", cntfrq, cntfrq); + return cntfrq; +} + +static uint32_t read_cntp_ctl(void) +{ + uint32_t cntp_ctl; + + cntp_ctl = READ_TIMER_REG32(TIMER_REG_CTL); + return cntp_ctl; +} + +static void write_cntp_ctl(uint32_t cntp_ctl) +{ + LTRACEF_LEVEL(3, "cntp_ctl: 0x%x %x\n", cntp_ctl, read_cntp_ctl()); + WRITE_TIMER_REG32(TIMER_REG_CTL, cntp_ctl); +} + +static void write_cntp_cval(uint64_t cntp_cval) +{ + LTRACEF_LEVEL(3, "cntp_cval: 0x%016llx, %llu\n", cntp_cval, cntp_cval); + WRITE_TIMER_REG64(TIMER_REG_CVAL, cntp_cval); +} + +static void write_cntp_tval(int32_t cntp_tval) +{ + LTRACEF_LEVEL(3, "cntp_tval: 0x%08x, %d\n", cntp_tval, cntp_tval); + WRITE_TIMER_REG32(TIMER_REG_TVAL, cntp_tval); +} + +static uint64_t read_cntpct(void) +{ + uint64_t cntpct; + + cntpct = READ_TIMER_REG64(TIMER_REG_CT); + LTRACEF_LEVEL(3, "cntpct: 0x%016llx, %llu\n", cntpct, cntpct); + return cntpct; +} + +static enum handler_return platform_tick(void *arg) +{ + write_cntp_ctl(0); + if (t_callback) { + return t_callback(arg, current_time()); + } else { + return INT_NO_RESCHEDULE; + } +} + +status_t platform_set_oneshot_timer(platform_timer_callback callback, void *arg, lk_time_t interval) +{ + uint64_t cntpct_interval = lk_time_to_cntpct(interval); + + ASSERT(arg == NULL); + + t_callback = callback; + if (cntpct_interval <= INT_MAX) + write_cntp_tval(cntpct_interval); + else + write_cntp_cval(read_cntpct() + cntpct_interval); + write_cntp_ctl(1); + + return 0; +} + +void platform_stop_timer(void) +{ + write_cntp_ctl(0); +} + +lk_bigtime_t current_time_hires(void) +{ + return cntpct_to_lk_bigtime(read_cntpct()); +} + +lk_time_t current_time(void) +{ + return cntpct_to_lk_time(read_cntpct()); +} + +static uint32_t abs_int32(int32_t a) +{ + return (a > 0) ? a : -a; +} + +static uint64_t abs_int64(int64_t a) +{ + return (a > 0) ? a : -a; +} + +static void test_time_conversion_check_result(uint64_t a, uint64_t b, uint64_t limit, bool is32) +{ + if (a != b) { + uint64_t diff = is32 ? abs_int32(a - b) : abs_int64(a - b); + if (diff <= limit) + LTRACEF("ROUNDED by %llu (up to %llu allowed)\n", diff, limit); + else + TRACEF("FAIL, off by %llu\n", diff); + } +} + +static void test_lk_time_to_cntpct(uint32_t cntfrq, lk_time_t lk_time) +{ + uint64_t cntpct = lk_time_to_cntpct(lk_time); + uint64_t expected_cntpct = ((uint64_t)cntfrq * lk_time + 500) / 1000; + + test_time_conversion_check_result(cntpct, expected_cntpct, 1, false); + LTRACEF_LEVEL(2, "lk_time_to_cntpct(%u): got %llu, expect %llu\n", lk_time, cntpct, expected_cntpct); +} + +static void test_cntpct_to_lk_time(uint32_t cntfrq, lk_time_t expected_lk_time, uint32_t wrap_count) +{ + lk_time_t lk_time; + uint64_t cntpct; + + cntpct = (uint64_t)cntfrq * expected_lk_time / 1000; + if ((uint64_t)cntfrq * wrap_count > UINT_MAX) + cntpct += (((uint64_t)cntfrq << 32) / 1000) * wrap_count; + else + cntpct += (((uint64_t)(cntfrq * wrap_count) << 32) / 1000); + lk_time = cntpct_to_lk_time(cntpct); + + test_time_conversion_check_result(lk_time, expected_lk_time, (1000 + cntfrq - 1) / cntfrq, true); + LTRACEF_LEVEL(2, "cntpct_to_lk_time(%llu): got %u, expect %u\n", cntpct, lk_time, expected_lk_time); +} + +static void test_cntpct_to_lk_bigtime(uint32_t cntfrq, uint64_t expected_s) +{ + lk_bigtime_t expected_lk_bigtime = expected_s * 1000 * 1000; + uint64_t cntpct = (uint64_t)cntfrq * expected_s; + lk_bigtime_t lk_bigtime = cntpct_to_lk_bigtime(cntpct); + + test_time_conversion_check_result(lk_bigtime, expected_lk_bigtime, (1000 * 1000 + cntfrq - 1) / cntfrq, false); + LTRACEF_LEVEL(2, "cntpct_to_lk_bigtime(%llu): got %llu, expect %llu\n", cntpct, lk_bigtime, expected_lk_bigtime); +} + +static void test_time_conversions(uint32_t cntfrq) +{ + test_lk_time_to_cntpct(cntfrq, 0); + test_lk_time_to_cntpct(cntfrq, 1); + test_lk_time_to_cntpct(cntfrq, INT_MAX); + test_lk_time_to_cntpct(cntfrq, INT_MAX + 1U); + test_lk_time_to_cntpct(cntfrq, ~0); + test_cntpct_to_lk_time(cntfrq, 0, 0); + test_cntpct_to_lk_time(cntfrq, INT_MAX, 0); + test_cntpct_to_lk_time(cntfrq, INT_MAX + 1U, 0); + test_cntpct_to_lk_time(cntfrq, ~0, 0); + test_cntpct_to_lk_time(cntfrq, 0, 1); + test_cntpct_to_lk_time(cntfrq, 0, 7); + test_cntpct_to_lk_time(cntfrq, 0, 70); + test_cntpct_to_lk_time(cntfrq, 0, 700); + test_cntpct_to_lk_bigtime(cntfrq, 0); + test_cntpct_to_lk_bigtime(cntfrq, 1); + test_cntpct_to_lk_bigtime(cntfrq, 60 * 60 * 24); + test_cntpct_to_lk_bigtime(cntfrq, 60 * 60 * 24 * 365); + test_cntpct_to_lk_bigtime(cntfrq, 60 * 60 * 24 * (365 * 10 + 2)); + test_cntpct_to_lk_bigtime(cntfrq, 60ULL * 60 * 24 * (365 * 100 + 2)); +} + +static void arm_generic_timer_init_conversion_factors(uint32_t cntfrq) +{ + fp_32_64_div_32_32(&cntpct_per_ms, cntfrq, 1000); + fp_32_64_div_32_32(&ms_per_cntpct, 1000, cntfrq); + fp_32_64_div_32_32(&us_per_cntpct, 1000 * 1000, cntfrq); + LTRACEF("cntpct_per_ms: %08x.%08x%08x\n", cntpct_per_ms.l0, cntpct_per_ms.l32, cntpct_per_ms.l64); + LTRACEF("ms_per_cntpct: %08x.%08x%08x\n", ms_per_cntpct.l0, ms_per_cntpct.l32, ms_per_cntpct.l64); + LTRACEF("us_per_cntpct: %08x.%08x%08x\n", us_per_cntpct.l0, us_per_cntpct.l32, us_per_cntpct.l64); +} + +void arm_generic_timer_init(int irq, uint32_t freq_override) +{ + uint32_t cntfrq; + + if (freq_override == 0) { + cntfrq = read_cntfrq(); + + if (!cntfrq) { + TRACEF("Failed to initialize timer, frequency is 0\n"); + return; + } + } else { + cntfrq = freq_override; + } + +#if LOCAL_TRACE + LTRACEF("Test min cntfrq\n"); + arm_generic_timer_init_conversion_factors(1); + test_time_conversions(1); + LTRACEF("Test max cntfrq\n"); + arm_generic_timer_init_conversion_factors(~0); + test_time_conversions(~0); + LTRACEF("Set actual cntfrq\n"); +#endif + arm_generic_timer_init_conversion_factors(cntfrq); + test_time_conversions(cntfrq); + + LTRACEF("register irq %d on cpu %d\n", irq, arch_curr_cpu_num()); + register_int_handler(irq, &platform_tick, NULL); + unmask_interrupt(irq); + + timer_irq = irq; +} + +static void arm_generic_timer_init_secondary_cpu(uint level) +{ + LTRACEF("register irq %d on cpu %d\n", timer_irq, arch_curr_cpu_num()); + register_int_handler(timer_irq, &platform_tick, NULL); + unmask_interrupt(timer_irq); +} + +/* secondary cpu initialize the timer just before the kernel starts with interrupts enabled */ +LK_INIT_HOOK_FLAGS(arm_generic_timer_init_secondary_cpu, + arm_generic_timer_init_secondary_cpu, + LK_INIT_LEVEL_THREADING - 1, LK_INIT_FLAG_SECONDARY_CPUS); + +static void arm_generic_timer_resume_cpu(uint level) +{ + /* Always trigger a timer interrupt on each cpu for now */ + write_cntp_tval(0); + write_cntp_ctl(1); +} + +LK_INIT_HOOK_FLAGS(arm_generic_timer_resume_cpu, arm_generic_timer_resume_cpu, + LK_INIT_LEVEL_PLATFORM, LK_INIT_FLAG_CPU_RESUME); diff --git a/kernel/dev/timer/arm_generic/include/dev/timer/arm_generic.h b/kernel/dev/timer/arm_generic/include/dev/timer/arm_generic.h new file mode 100644 index 000000000..a6a1530c5 --- /dev/null +++ b/kernel/dev/timer/arm_generic/include/dev/timer/arm_generic.h @@ -0,0 +1,17 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_TIMER_ARM_GENERIC_H +#define __DEV_TIMER_ARM_GENERIC_H + +#include + +/* if freq_override != 0, use that as the operating frequency instead of CNTFRQ register */ +void arm_generic_timer_init(int irq, uint32_t freq_override); + +#endif + diff --git a/kernel/dev/timer/arm_generic/rules.mk b/kernel/dev/timer/arm_generic/rules.mk new file mode 100644 index 000000000..4ea6cf806 --- /dev/null +++ b/kernel/dev/timer/arm_generic/rules.mk @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +GLOBAL_DEFINES += \ + PLATFORM_HAS_DYNAMIC_TIMER=1 + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm_generic_timer.c + +MODULE_DEPS += \ + lib/fixed_point + +include make/module.mk diff --git a/kernel/dev/udisplay/BUILD.gn b/kernel/dev/udisplay/BUILD.gn new file mode 100644 index 000000000..088148a69 --- /dev/null +++ b/kernel/dev/udisplay/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_udisplay_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("udisplay") { + public_configs = [ ":_udisplay_config" ] + public = [ + "include/dev/udisplay.h", + ] + sources = [ + "udisplay.c", + ] + deps = [ + "//kernel/lib/gfx", + "//kernel/lib/gfxconsole", + "//kernel/lib/klog", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/udisplay/include/dev/udisplay.h b/kernel/dev/udisplay/include/dev/udisplay.h new file mode 100644 index 000000000..3e202a9ac --- /dev/null +++ b/kernel/dev/udisplay/include/dev/udisplay.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS; + +status_t udisplay_init(void); +status_t udisplay_set_framebuffer(paddr_t fb_phys, void* fb_user_virt, size_t fb_size); +status_t udisplay_set_display_info(struct display_info* display); +status_t udisplay_bind_gfxconsole(void); + +__END_CDECLS; diff --git a/kernel/dev/udisplay/rules.mk b/kernel/dev/udisplay/rules.mk new file mode 100644 index 000000000..412a69254 --- /dev/null +++ b/kernel/dev/udisplay/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/klog \ + lib/gfx \ + lib/gfxconsole + +MODULE_SRCS += \ + $(LOCAL_DIR)/udisplay.c + +include make/module.mk diff --git a/kernel/dev/udisplay/udisplay.c b/kernel/dev/udisplay/udisplay.c new file mode 100644 index 000000000..071f48c23 --- /dev/null +++ b/kernel/dev/udisplay/udisplay.c @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct udisplay_info { + paddr_t framebuffer_phys; + void* framebuffer_user_virt; + void* framebuffer_virt; + size_t framebuffer_size; + struct display_info info; +}; + +static struct udisplay_info g_udisplay; + +status_t udisplay_init(void) { + return NO_ERROR; +} + +status_t udisplay_set_framebuffer(paddr_t fb_phys, void* fb_user_virt, size_t fb_size) { + g_udisplay.framebuffer_phys = fb_phys; + g_udisplay.framebuffer_user_virt = fb_user_virt; + g_udisplay.framebuffer_size = fb_size; + + return NO_ERROR; +} + +status_t udisplay_set_display_info(struct display_info* display) { + memcpy(&g_udisplay.info, display, sizeof(struct display_info)); + return NO_ERROR; +} + +status_t udisplay_bind_gfxconsole(void) { + assert(g_udisplay.framebuffer_phys); + assert(g_udisplay.framebuffer_size); + + // unmap the framebuffer from the user's aspace + vmm_aspace_t* aspace = vaddr_to_aspace(g_udisplay.framebuffer_user_virt); + vmm_free_region(aspace, (vaddr_t)g_udisplay.framebuffer_user_virt); + + // map the framebuffer + aspace = vmm_get_kernel_aspace(); + status_t result = vmm_alloc_physical( + aspace, + "udisplay_fb", + g_udisplay.framebuffer_size, + &g_udisplay.framebuffer_virt, + PAGE_SIZE_SHIFT, + g_udisplay.framebuffer_phys, + 0 /* vmm flags */, + ARCH_MMU_FLAG_WRITE_COMBINING | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + if (result) return result; + + // bind the display to the gfxconsole + g_udisplay.info.framebuffer = g_udisplay.framebuffer_virt; + + gfxconsole_bind_display(&g_udisplay.info, NULL); + + return NO_ERROR; +} diff --git a/kernel/dev/usb/client/class/bulktest/bulktest.c b/kernel/dev/usb/client/class/bulktest/bulktest.c new file mode 100644 index 000000000..9debd191d --- /dev/null +++ b/kernel/dev/usb/client/class/bulktest/bulktest.c @@ -0,0 +1,154 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* a simple demo usb class device that reflects data written to + * one endpoint to the other. + */ + +#define LOCAL_TRACE 0 + +#define W(w) (w & 0xff), (w >> 8) +#define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff) + +static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t); +static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t); + +#define TRANSFER_SIZE 512 + +static void queue_rx(void) +{ + static usbc_transfer_t transfer; + static uint8_t buf[TRANSFER_SIZE]; + + transfer.callback = &ep_cb_rx; + transfer.result = 0; + transfer.buf = &buf; + transfer.buflen = sizeof(buf); + transfer.bufpos = 0; + transfer.extra = 0; + + usbc_queue_rx(1, &transfer); +} + +static void queue_tx(void) +{ + static usbc_transfer_t transfer; + static uint8_t buf[TRANSFER_SIZE]; + + for (uint i = 0; i < sizeof(buf); i++) { + buf[i] = ~i; + } + + transfer.callback = &ep_cb_tx; + transfer.result = 0; + transfer.buf = &buf; + transfer.buflen = sizeof(buf); + transfer.bufpos = 0; + transfer.extra = 0; + + usbc_queue_tx(1, &transfer); +} + + +static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t) +{ +#if LOCAL_TRACE + LTRACEF("ep %u transfer %p\n", endpoint, t); + usbc_dump_transfer(t); + + if (t->result >= 0) { + hexdump8(t->buf, t->bufpos); + } +#endif + + if (t->result >= 0) + queue_rx(); + + return NO_ERROR; +} + +static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t) +{ +#if LOCAL_TRACE + LTRACEF("ep %u transfer %p\n", endpoint, t); + usbc_dump_transfer(t); +#endif + + if (t->result >= 0) + queue_tx(); + + return NO_ERROR; +} + +static status_t bulktest_usb_cb(void *cookie, usb_callback_op_t op, const union usb_callback_args *args) +{ + LTRACEF("cookie %p, op %u, args %p\n", cookie, op, args); + + if (op == USB_CB_ONLINE) { + usbc_setup_endpoint(1, USB_IN, 0x40); + usbc_setup_endpoint(1, USB_OUT, 0x40); + + queue_rx(); + queue_tx(); + } + return NO_ERROR; +} + +status_t usb_class_bulktest_init(uint interface_num, ep_t epin, ep_t epout) +{ + LTRACEF("epin %u, epout %u\n", epin, epout); + + /* build a descriptor for it */ + uint8_t if_descriptor[] = { + 0x09, /* length */ + INTERFACE, /* type */ + interface_num, /* interface num */ + 0x00, /* alternates */ + 0x02, /* endpoint count */ + 0xff, /* interface class */ + 0xff, /* interface subclass */ + 0x00, /* interface protocol */ + 0x00, /* string index */ + + /* endpoint 1 IN */ + 0x07, /* length */ + ENDPOINT, /* type */ + epin | 0x80, /* address: 1 IN */ + 0x02, /* type: bulk */ + W(64), /* max packet size: 64 */ + 00, /* interval */ + + /* endpoint 1 OUT */ + 0x07, /* length */ + ENDPOINT, /* type */ + epout, /* address: 1 OUT */ + 0x02, /* type: bulk */ + W(64), /* max packet size: 64 */ + 00, /* interval */ + }; + + usb_append_interface_lowspeed(if_descriptor, sizeof(if_descriptor)); + usb_append_interface_highspeed(if_descriptor, sizeof(if_descriptor)); + + usb_register_callback(&bulktest_usb_cb, NULL); + + return NO_ERROR; +} + diff --git a/kernel/dev/usb/client/class/bulktest/include/dev/usb/class/bulktest.h b/kernel/dev/usb/client/class/bulktest/include/dev/usb/class/bulktest.h new file mode 100644 index 000000000..d61c288a7 --- /dev/null +++ b/kernel/dev/usb/client/class/bulktest/include/dev/usb/class/bulktest.h @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +status_t usb_class_bulktest_init(uint interface_num, ep_t epin, ep_t epout); + diff --git a/kernel/dev/usb/client/class/bulktest/rules.mk b/kernel/dev/usb/client/class/bulktest/rules.mk new file mode 100644 index 000000000..a9546898d --- /dev/null +++ b/kernel/dev/usb/client/class/bulktest/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := dev/usb/client + +MODULE_SRCS += \ + $(LOCAL_DIR)/bulktest.c + +include make/module.mk diff --git a/kernel/dev/usb/client/include/usb/client/udc.h b/kernel/dev/usb/client/include/usb/client/udc.h new file mode 100644 index 000000000..f5abb049d --- /dev/null +++ b/kernel/dev/usb/client/include/usb/client/udc.h @@ -0,0 +1,74 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009, Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __DEV_UDC_H +#define __DEV_UDC_H + +#include + +typedef struct udc_request udc_request_t; +typedef struct udc_gadget udc_gadget_t; +typedef struct udc_device udc_device_t; + +/* endpoints are opaque handles specific to the particular device controller */ +typedef struct udc_endpoint udc_endpoint_t; + +/* USB Device Controller Transfer Request */ +struct udc_request { + void *buffer; + unsigned length; + void (*complete)(udc_request_t *req, unsigned actual, int status); + void *context; +}; + +udc_request_t *udc_request_alloc(void); +void udc_request_free(udc_request_t *req); +int udc_request_queue(udc_endpoint_t *ept, udc_request_t *req); +int udc_request_cancel(udc_endpoint_t *ept, udc_request_t *req); + +#define UDC_BULK_IN 0x82 +#define UDC_BULK_OUT 0x02 + +udc_endpoint_t *udc_endpoint_alloc(unsigned type, unsigned maxpkt); +void udc_endpoint_free(udc_endpoint_t *ept); + +#define UDC_EVENT_ONLINE 1 +#define UDC_EVENT_OFFLINE 2 + +struct udc_gadget { + void (*notify)(udc_gadget_t *gadget, unsigned event); + void *context; + + struct udc_gadget *next; // do not modify + + uint8_t ifc_class; + uint8_t ifc_subclass; + uint8_t ifc_protocol; + uint8_t ifc_endpoints; + const char *ifc_string; + unsigned flags; + + udc_endpoint_t **ept; +}; + +struct udc_device { + uint16_t vendor_id; + uint16_t product_id; + uint16_t version_id; + + const char *manufacturer; + const char *product; + const char *serialno; +}; + +int udc_init(udc_device_t *devinfo); +int udc_register_gadget(udc_gadget_t *gadget); +int udc_start(void); +int udc_stop(void); + +#endif diff --git a/kernel/dev/usb/client/include/usb/client/usb.h b/kernel/dev/usb/client/include/usb/client/usb.h new file mode 100644 index 000000000..fd0bd72c1 --- /dev/null +++ b/kernel/dev/usb/client/include/usb/client/usb.h @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_USB_H +#define __DEV_USB_H + +#include +#include + +__BEGIN_CDECLS + +/* top level initialization for usb client, abstracts away the interfaces */ +typedef struct { + void *desc; + size_t len; + uint flags; +} usb_descriptor __ALIGNED(2); + +#define USB_DESC_FLAG_STATIC (0x1) + +#define USB_DESC_STATIC(x) { .desc = (void *)(x), .len = sizeof(x), .flags = USB_DESC_FLAG_STATIC } + +typedef struct { + usb_descriptor string; + uint8_t id; +} usb_string; + +/* complete usb config struct, passed in to usb_setup() */ +typedef struct { + struct usb_descriptor_speed { + usb_descriptor device; + usb_descriptor device_qual; + usb_descriptor config; + } lowspeed, highspeed; + usb_descriptor langid; +} usb_config; + +/* external code needs to set up the usb stack via the following calls */ +status_t usb_setup(usb_config *config); + +/* apped new interface descriptors to the existing config if desired */ +status_t usb_append_interface_highspeed(const uint8_t *int_descr, size_t len); +status_t usb_append_interface_lowspeed(const uint8_t *int_descr, size_t len); + +status_t usb_add_string(const char *string, uint8_t id); + +status_t usb_start(void); +status_t usb_stop(void); + +/* callbacks from usbc and usb layers */ +typedef enum { + USB_CB_RESET, + USB_CB_SUSPEND, + USB_CB_RESUME, + USB_CB_DISCONNECT, + USB_CB_ONLINE, + USB_CB_OFFLINE, + USB_CB_SETUP_MSG, +} usb_callback_op_t; + +/* setup arg is valid during CB_SETUP_MSG */ +union usb_callback_args { + const struct usb_setup *setup; +}; + +typedef status_t (*usb_callback_t)(void *cookie, usb_callback_op_t op, const union usb_callback_args *args); + +/* callback api the usbc driver uses */ +status_t usbc_callback(usb_callback_op_t op, const union usb_callback_args *args); + +/* callback api that anyone can register for */ +status_t usb_register_callback(usb_callback_t, void *cookie); + +__END_CDECLS + +#endif + diff --git a/kernel/dev/usb/client/include/usb/client/usbc.h b/kernel/dev/usb/client/include/usb/client/usbc.h new file mode 100644 index 000000000..bdfbfa536 --- /dev/null +++ b/kernel/dev/usb/client/include/usb/client/usbc.h @@ -0,0 +1,69 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_USBC_H +#define __DEV_USBC_H + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +void usbc_init(void); + +typedef uint ep_t; + +typedef enum { + USB_IN = 0, + USB_OUT +} ep_dir_t; + +struct usbc_transfer; +typedef status_t (*ep_callback)(ep_t endpoint, struct usbc_transfer *transfer); + +typedef struct usbc_transfer { + ep_callback callback; + status_t result; + void *buf; + size_t buflen; + uint bufpos; + void *extra; // extra pointer to store whatever you want +} usbc_transfer_t; + +enum { + USB_TRANSFER_RESULT_OK = 0, + USB_TRANSFER_RESULT_ERR = -1, + USB_TRANSFER_RESULT_CANCELLED = -2, +}; + +status_t usbc_setup_endpoint(ep_t ep, ep_dir_t dir, uint width); +status_t usbc_queue_rx(ep_t ep, usbc_transfer_t *transfer); +status_t usbc_queue_tx(ep_t ep, usbc_transfer_t *transfer); + +status_t usbc_set_active(bool active); +void usbc_set_address(uint8_t address); + +/* called back from within a callback to handle setup responses */ +void usbc_ep0_ack(void); +void usbc_ep0_stall(void); +void usbc_ep0_send(const void *buf, size_t len, size_t maxlen); +void usbc_ep0_recv(void *buf, size_t len, ep_callback); + +bool usbc_is_highspeed(void); + +static inline void usbc_dump_transfer(const usbc_transfer_t *t) +{ + printf("usb transfer %p: cb %p buf %p, buflen %zd, bufpos %u, result %d\n", t, t->callback, t->buf, t->buflen, t->bufpos, t->result); +} + +__END_CDECLS + +#endif + diff --git a/kernel/dev/usb/client/rules.mk b/kernel/dev/usb/client/rules.mk new file mode 100644 index 000000000..898cd80fb --- /dev/null +++ b/kernel/dev/usb/client/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/usb.c + +include make/module.mk diff --git a/kernel/dev/usb/client/usb.c b/kernel/dev/usb/client/usb.c new file mode 100644 index 000000000..5b2542bbc --- /dev/null +++ b/kernel/dev/usb/client/usb.c @@ -0,0 +1,380 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define MAX_STRINGS 8 +static struct { + bool active; + uint8_t active_config; + + usb_config *config; + + struct list_node cb_list; + + usb_string strings[MAX_STRINGS]; +} usb; + +typedef struct { + struct list_node node; + usb_callback_t cb; + void *cookie; +} usb_callback_container_t; + +static void usb_do_callbacks(usb_callback_op_t op, const union usb_callback_args *args); + +static void append_desc_data(usb_descriptor *desc, const void *dat, size_t len) +{ + uint8_t *ptr = malloc(desc->len + len); + + memcpy(ptr, desc->desc, desc->len); + memcpy(ptr + desc->len, dat, len); + + /* free the old buffer if it wasn't marked static */ + if ((desc->flags & USB_DESC_FLAG_STATIC) == 0) + free(desc->desc); + desc->flags &= ~USB_DESC_FLAG_STATIC; + + desc->desc = ptr; + desc->len += len; +} + +/* returns the interface number assigned */ +static int usb_append_interface(usb_descriptor *desc, const uint8_t *int_descr, size_t len) +{ + uint8_t *ptr = malloc(len); + int interface_num; + + // create a temporary copy of the interface + memcpy(ptr, int_descr, len); + + // find the last interface used + interface_num = ((uint8_t *)desc->desc)[4]; // current interface + + // patch our interface descriptor with the new id + ptr[2] = interface_num; + + // append it to our config desriptor + append_desc_data(desc, ptr, len); + free(ptr); + + // patch the total length of the config descriptor and set the number of interfaces + ((uint16_t *)desc->desc)[1] += len; + interface_num++; + ((uint8_t *)desc->desc)[4] = interface_num; + + return interface_num - 1; +} + +int usb_append_interface_highspeed(const uint8_t *int_descr, size_t len) +{ + return usb_append_interface(&usb.config->highspeed.config, int_descr, len); +} + +int usb_append_interface_lowspeed(const uint8_t *int_descr, size_t len) +{ + return usb_append_interface(&usb.config->lowspeed.config, int_descr, len); +} + +void usb_set_string_descriptor(usb_descriptor *desc, const char *string) +{ + int len = strlen(string); + ushort *data; + int datalen = len * 2 + 2; + + data = malloc(datalen); + + /* write length field */ + data[0] = 0x0300 + datalen; + + /* copy the string into the uint16_t based usb string */ + int i; + for (i = 0; i < len; i++) { + data[i + 1] = string[i]; + } + + desc->desc = (void *)data; + desc->len = datalen; +} + +static void set_usb_id(uint16_t vendor, uint16_t product) +{ + // patch the current configuration to with the vendor/product id + ((uint16_t *)usb.config->lowspeed.device.desc)[4] = vendor; + ((uint16_t *)usb.config->lowspeed.device.desc)[5] = product; + + ((uint16_t *)usb.config->highspeed.device.desc)[4] = vendor; + ((uint16_t *)usb.config->highspeed.device.desc)[5] = product; +} + +status_t usb_add_string(const char *string, uint8_t id) +{ + uint i; + size_t len = strlen(string); + + uint16_t *strbuf = malloc(len * 2 + 2); + if (!strbuf) + return ERR_NO_MEMORY; + + /* build the usb string descriptor */ + strbuf[0] = 0x300 | (len * 2 + 2); + for (i = 0; i < len; i++) { + strbuf[i + 1] = (uint16_t)string[i]; + } + + /* find a slot to put it */ + for (i = 0; i < MAX_STRINGS; i++) { + if (usb.strings[i].id == 0) { + usb.strings[i].string.desc = strbuf; + usb.strings[i].string.len = len * 2 + 2; + usb.strings[i].id = id; + return NO_ERROR; + } + } + + /* couldn't find a spot */ + free(strbuf); + return ERR_NO_MEMORY; +} + +static void usb_set_active_config(uint8_t config) +{ + if (config != usb.active_config) { + usb.active_config = config; + if (usb.active_config != 0) { + printf("usb online\n"); + usb_do_callbacks(USB_CB_ONLINE, NULL); + } else { + printf("usb offline\n"); + usb_do_callbacks(USB_CB_OFFLINE, NULL); + } + } +} + +status_t usb_register_callback(usb_callback_t cb, void *cookie) +{ + DEBUG_ASSERT(cb); + + usb_callback_container_t *c = malloc(sizeof(usb_callback_container_t)); + if (!c) + return ERR_NO_MEMORY; + + c->cb = cb; + c->cookie = cookie; + list_add_tail(&usb.cb_list, &c->node); + + return NO_ERROR; +} + +static void usb_do_callbacks(usb_callback_op_t op, const union usb_callback_args *args) +{ + usb_callback_container_t *c; + list_for_every_entry(&usb.cb_list, c, usb_callback_container_t, node) { + c->cb(c->cookie, op, args); + } +} + +status_t usbc_callback(usb_callback_op_t op, const union usb_callback_args *args) +{ + LTRACEF("op %d, args %p\n", op, args); + + /* start looking for specific things to handle */ + if (op == USB_CB_SETUP_MSG) { + bool setup_handled = false; + const struct usb_setup *setup = args->setup; + DEBUG_ASSERT(setup); + LTRACEF("SETUP: req_type=%#x req=%#x value=%#x index=%#x len=%#x\n", + setup->request_type, setup->request, setup->value, setup->index, setup->length); + + if ((setup->request_type & TYPE_MASK) == TYPE_STANDARD) { + switch (setup->request) { + case SET_ADDRESS: + LTRACEF("SET_ADDRESS 0x%x\n", setup->value); + usbc_ep0_ack(); + usbc_set_address(setup->value); + setup_handled = true; + break; + case SET_FEATURE: + case CLEAR_FEATURE: + LTRACEF("SET/CLEAR_FEATURE, feature 0x%x\n", setup->value); + usbc_ep0_ack(); + setup_handled = true; + break; + case SET_DESCRIPTOR: + LTRACEF("SET_DESCRIPTOR\n"); + usbc_ep0_stall(); + setup_handled = true; + break; + case GET_DESCRIPTOR: { + if ((setup->request_type & RECIP_MASK) == RECIP_DEVICE) { + /* handle device descriptor fetches */ + + /* Get the right descriptors based on current speed */ + const struct usb_descriptor_speed *speed; + if (usbc_is_highspeed()) { + speed = &usb.config->highspeed; + } else { + speed = &usb.config->lowspeed; + } + + switch (setup->value) { + case 0x100: /* device */ + LTRACEF("got GET_DESCRIPTOR, device descriptor\n"); + usbc_ep0_send(speed->device.desc, speed->device.len, + setup->length); + break; + case 0x200: /* CONFIGURATION */ + LTRACEF("got GET_DESCRIPTOR, config descriptor\n"); + usbc_ep0_send(speed->config.desc, speed->config.len, + setup->length); + break; + case 0x300: /* Language ID */ + LTRACEF("got GET_DESCRIPTOR, language id\n"); + usbc_ep0_send(usb.config->langid.desc, + usb.config->langid.len, setup->length); + break; + case (0x301)...(0x3ff): { + /* string descriptor, search our list for a match */ + uint i; + bool found = false; + uint8_t id = setup->value & 0xff; + for (i = 0; i < MAX_STRINGS; i++) { + if (usb.strings[i].id == id) { + usbc_ep0_send(usb.strings[i].string.desc, + usb.strings[i].string.len, + setup->length); + found = true; + break; + } + } + if (!found) { + /* couldn't find one, stall */ + usbc_ep0_stall(); + } + break; + } + case 0x600: /* DEVICE QUALIFIER */ + LTRACEF("got GET_DESCRIPTOR, device qualifier\n"); + usbc_ep0_send(speed->device_qual.desc, + speed->device_qual.len, setup->length); + break; + case 0xa00: + /* we aint got one of these */ + LTRACEF("got GET_DESCRIPTOR, debug descriptor\n"); + usbc_ep0_stall(); + break; + default: + LTRACEF("unhandled descriptor %#x\n", setup->value); + // stall + break; + } + setup_handled = true; + } + break; + } + + case SET_CONFIGURATION: + LTRACEF("SET_CONFIGURATION %d\n", setup->value); + usbc_ep0_ack(); + usb_set_active_config(setup->value); + break; + + case GET_CONFIGURATION: + LTRACEF("GET_CONFIGURATION\n"); + usbc_ep0_send(&usb.active_config, 1, setup->length); + break; + + case SET_INTERFACE: + LTRACEF("SET_INTERFACE %d\n", setup->value); + usbc_ep0_ack(); + break; + + case GET_INTERFACE: { + static uint8_t i = 1; + LTRACEF("GET_INTERFACE\n"); + usbc_ep0_send(&i, 1, setup->length); + break; + } + + case GET_STATUS: { + static uint16_t i = 1; // self powered + LTRACEF("GET_STATUS\n"); + usbc_ep0_send(&i, 2, setup->length); + break; + } + default: + LTRACEF("unhandled standard request 0x%x\n", setup->request); + } + } else { + LTRACEF("unhandled nonstandard request 0x%x\n", setup->request); + } + + if (!setup_handled) { + usb_do_callbacks(op, args); + } + } else if (op == USB_CB_RESET) { + usb_do_callbacks(op, args); + + usb.active_config = 0; + usb_do_callbacks(USB_CB_OFFLINE, args); + } else { + // other non setup messages, pass them down to anyone else + usb_do_callbacks(op, args); + } + + return NO_ERROR; +} + +status_t usb_setup(usb_config *config) +{ + DEBUG_ASSERT(config); + DEBUG_ASSERT(usb.active == false); + + usb.config = config; + + return NO_ERROR; +} + +status_t usb_start(void) +{ + DEBUG_ASSERT(usb.config); + DEBUG_ASSERT(usb.active == false); + + // go online + usbc_set_active(true); + usb.active = true; + + return NO_ERROR; +} + +status_t usb_stop(void) +{ + DEBUG_ASSERT(usb.active == true); + + usb.active = false; + usbc_set_active(false); + + return NO_ERROR; +} + +static void usb_init(uint level) +{ + list_initialize(&usb.cb_list); +} + +LK_INIT_HOOK(usb, usb_init, LK_INIT_LEVEL_THREADING); diff --git a/kernel/dev/virtio/BUILD.gn b/kernel/dev/virtio/BUILD.gn new file mode 100644 index 000000000..e4b593bf8 --- /dev/null +++ b/kernel/dev/virtio/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_virtio_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("virtio") { + public_configs = [ ":_virtio_config" ] + configs += [ "//kernel/kernel:enable_vm" ] + sources = [ + "virtio.c", + "virtio_priv.h", + ] + deps = [ + "//kernel/dev/interrupt", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/virtio/block/BUILD.gn b/kernel/dev/virtio/block/BUILD.gn new file mode 100644 index 000000000..d3950e212 --- /dev/null +++ b/kernel/dev/virtio/block/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("block") { + configs += [ "//kernel/kernel:enable_vm" ] + sources = [ + "virtio-block.c", + ] + deps = [ + "//kernel/dev/virtio", + "//kernel/lib/bio", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/virtio/block/rules.mk b/kernel/dev/virtio/block/rules.mk new file mode 100644 index 000000000..a4f1e3fd1 --- /dev/null +++ b/kernel/dev/virtio/block/rules.mk @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/virtio-block.c \ + +MODULE_DEPS += \ + dev/virtio \ + lib/bio + + +include make/module.mk diff --git a/kernel/dev/virtio/block/virtio-block.c b/kernel/dev/virtio/block/virtio-block.c new file mode 100644 index 000000000..2396ff750 --- /dev/null +++ b/kernel/dev/virtio/block/virtio-block.c @@ -0,0 +1,331 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct virtio_blk_config { + uint64_t capacity; + uint32_t size_max; + uint32_t seg_max; + struct virtio_blk_geometry { + uint16_t cylinders; + uint8_t heads; + uint8_t sectors; + } geometry; + uint32_t blk_size; +} __PACKED; + +struct virtio_blk_req { + uint32_t type; + uint32_t ioprio; + uint64_t sector; +} __PACKED; + +#define VIRTIO_BLK_F_BARRIER (1<<0) +#define VIRTIO_BLK_F_SIZE_MAX (1<<1) +#define VIRTIO_BLK_F_SEG_MAX (1<<2) +#define VIRTIO_BLK_F_GEOMETRY (1<<4) +#define VIRTIO_BLK_F_RO (1<<5) +#define VIRTIO_BLK_F_BLK_SIZE (1<<6) +#define VIRTIO_BLK_F_SCSI (1<<7) +#define VIRTIO_BLK_F_FLUSH (1<<9) +#define VIRTIO_BLK_F_TOPOLOGY (1<<10) +#define VIRTIO_BLK_F_CONFIG_WCE (1<<11) + +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 +#define VIRTIO_BLK_T_FLUSH 4 + +#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2 + +static enum handler_return virtio_block_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e); +static ssize_t virtio_bdev_read_block(struct bdev *bdev, void *buf, bnum_t block, uint count); +static ssize_t virtio_bdev_write_block(struct bdev *bdev, const void *buf, bnum_t block, uint count); +static status_t virtio_block_init(struct virtio_device *dev, uint32_t host_features); + +struct virtio_block_dev { + struct virtio_device *dev; + + mutex_t lock; + event_t io_event; + + /* bio block device */ + bdev_t bdev; + + /* one blk_req structure for io, not crossing a page boundary */ + struct virtio_blk_req *blk_req; + paddr_t blk_req_phys; + + /* one uint8_t response word */ + uint8_t blk_response; + paddr_t blk_response_phys; +}; + +VIRTIO_DEV_CLASS(block, VIRTIO_DEV_ID_BLOCK, NULL, virtio_block_init, NULL); + +static status_t virtio_block_init(struct virtio_device *dev, uint32_t host_features) +{ + LTRACEF("dev %p, host_features 0x%x\n", dev, host_features); + + /* allocate a new block device */ + struct virtio_block_dev *bdev = malloc(sizeof(struct virtio_block_dev)); + if (!bdev) + return ERR_NO_MEMORY; + + mutex_init(&bdev->lock); + event_init(&bdev->io_event, false, EVENT_FLAG_AUTOUNSIGNAL); + + bdev->dev = dev; + dev->priv = bdev; + + bdev->blk_req = memalign(sizeof(struct virtio_blk_req), sizeof(struct virtio_blk_req)); +#if WITH_KERNEL_VM + bdev->blk_req_phys = vaddr_to_paddr(bdev->blk_req); +#else + bdev->blk_req_phys = (paddr_t)bdev->blk_req; +#endif + LTRACEF("blk_req structure at %p (0x%lx phys)\n", bdev->blk_req, bdev->blk_req_phys); + +#if WITH_KERNEL_VM + bdev->blk_response_phys = vaddr_to_paddr(&bdev->blk_response); +#else + bdev->blk_response_phys = (paddr_t)&bdev->blk_response; +#endif + + /* make sure the device is reset */ + virtio_reset_device(dev); + + volatile struct virtio_blk_config *config = (struct virtio_blk_config *)dev->config_ptr; + + LTRACEF("capacity 0x%llx\n", config->capacity); + LTRACEF("size_max 0x%x\n", config->size_max); + LTRACEF("seg_max 0x%x\n", config->seg_max); + LTRACEF("blk_size 0x%x\n", config->blk_size); + + /* ack and set the driver status bit */ + virtio_status_acknowledge_driver(dev); + + // XXX check features bits and ack/nak them + + /* allocate a virtio ring */ + status_t err = virtio_alloc_ring(dev, 0, 256); + if (err < 0) + panic("failed to allocate virtio ring\n"); + + /* set our irq handler */ + dev->irq_driver_callback = &virtio_block_irq_driver_callback; + + /* set DRIVER_OK */ + virtio_status_driver_ok(dev); + + /* construct the block device */ + static uint8_t found_index = 0; + char buf[16]; + snprintf(buf, sizeof(buf), "virtio%u", found_index++); + bio_initialize_bdev(&bdev->bdev, buf, + config->blk_size, config->capacity, + 0, NULL, BIO_FLAGS_NONE); + + /* override our block device hooks */ + bdev->bdev.read_block = &virtio_bdev_read_block; + bdev->bdev.write_block = &virtio_bdev_write_block; + + bio_register_device(&bdev->bdev); + + printf("found virtio block device of size %lld\n", config->capacity * config->blk_size); + + return NO_ERROR; +} + +static enum handler_return virtio_block_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e) +{ + struct virtio_block_dev *bdev = (struct virtio_block_dev *)dev->priv; + + LTRACEF("dev %p, ring %u, e %p, id %u, len %u\n", dev, ring, e, e->id, e->len); + + /* parse our descriptor chain, add back to the free queue */ + uint16_t i = e->id; + for (;;) { + int next; + struct vring_desc *desc = virtio_desc_index_to_desc(dev, ring, i); + + //virtio_dump_desc(desc); + + if (desc->flags & VRING_DESC_F_NEXT) { + next = desc->next; + } else { + /* end of chain */ + next = -1; + } + + virtio_free_desc(dev, ring, i); + + if (next < 0) + break; + i = next; + } + + /* signal our event */ + event_signal(&bdev->io_event, false); + + return INT_RESCHEDULE; +} + +ssize_t virtio_block_read_write(struct virtio_device *dev, void *buf, off_t offset, size_t len, bool write) +{ + struct virtio_block_dev *bdev = (struct virtio_block_dev *)dev->priv; + + uint16_t i; + struct vring_desc *desc; + paddr_t pa; + vaddr_t va = (vaddr_t)buf; + + LTRACEF("dev %p, buf %p, offset 0x%llx, len %zu\n", dev, buf, offset, len); + + mutex_acquire(&bdev->lock); + + /* set up the request */ + bdev->blk_req->type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN; + bdev->blk_req->ioprio = 0; + bdev->blk_req->sector = offset / 512; + LTRACEF("blk_req type %u ioprio %u sector %llu\n", + bdev->blk_req->type, bdev->blk_req->ioprio, bdev->blk_req->sector); + + /* put together a transfer */ + desc = virtio_alloc_desc_chain(dev, 0, 3, &i); + LTRACEF("after alloc chain desc %p, i %u\n", desc, i); + + // XXX not cache safe. + // At the moment only tested on arm qemu, which doesn't emulate cache. + + /* set up the descriptor pointing to the head */ + desc->addr = bdev->blk_req_phys; + desc->len = sizeof(struct virtio_blk_req); + desc->flags |= VRING_DESC_F_NEXT; + + /* set up the descriptor pointing to the buffer */ + desc = virtio_desc_index_to_desc(dev, 0, desc->next); +#if WITH_KERNEL_VM + /* translate the first buffer */ + pa = vaddr_to_paddr((void *)va); + // XXX check for error + desc->addr = (uint64_t)pa; + /* desc->len is filled in below */ +#else + desc->addr = (uint64_t)(uintptr_t)buf; + desc->len = len; +#endif + desc->flags |= write ? 0 : VRING_DESC_F_WRITE; /* mark buffer as write-only if its a block read */ + desc->flags |= VRING_DESC_F_NEXT; + +#if WITH_KERNEL_VM + /* see if we need to add more descriptors due to scatter gather */ + paddr_t next_pa = PAGE_ALIGN(pa + 1); + desc->len = MIN(next_pa - pa, len); + LTRACEF("first descriptor va 0x%lx desc->addr 0x%llx desc->len %u\n", va, desc->addr, desc->len); + len -= desc->len; + while (len > 0) { + /* amount of source buffer handled by this iteration of the loop */ + size_t len_tohandle = MIN(len, PAGE_SIZE); + + /* translate the next page in the buffer */ + va = PAGE_ALIGN(va + 1); + pa = vaddr_to_paddr((void *)va); + // XXX check for error + LTRACEF("va now 0x%lx, pa 0x%lx, next_pa 0x%lx, remaining len %zu\n", va, pa, next_pa, len); + + /* is the new translated physical address contiguous to the last one? */ + if (next_pa == pa) { + LTRACEF("extending last one by %zu bytes\n", len_tohandle); + desc->len += len_tohandle; + } else { + uint16_t next_i = virtio_alloc_desc(dev, 0); + struct vring_desc *next_desc = virtio_desc_index_to_desc(dev, 0, next_i); + DEBUG_ASSERT(next_desc); + + LTRACEF("doesn't extend, need new desc, allocated desc %i (%p)\n", next_i, next_desc); + + /* fill this descriptor in and put it after the last one but before the response descriptor */ + next_desc->addr = (uint64_t)pa; + next_desc->len = len_tohandle; + next_desc->flags = write ? 0 : VRING_DESC_F_WRITE; /* mark buffer as write-only if its a block read */ + next_desc->flags |= VRING_DESC_F_NEXT; + next_desc->next = desc->next; + desc->next = next_i; + + desc = next_desc; + } + len -= len_tohandle; + next_pa += PAGE_SIZE; + } +#endif + + /* set up the descriptor pointing to the response */ + desc = virtio_desc_index_to_desc(dev, 0, desc->next); + desc->addr = bdev->blk_response_phys; + desc->len = 1; + desc->flags = VRING_DESC_F_WRITE; + + /* submit the transfer */ + virtio_submit_chain(dev, 0, i); + + /* kick it off */ + virtio_kick(dev, 0); + + /* wait for the transfer to complete */ + event_wait(&bdev->io_event); + + LTRACEF("status 0x%hhx\n", bdev->blk_response); + + mutex_release(&bdev->lock); + + return len; +} + +static ssize_t virtio_bdev_read_block(struct bdev *bdev, void *buf, bnum_t block, uint count) +{ + struct virtio_block_dev *dev = containerof(bdev, struct virtio_block_dev, bdev); + + LTRACEF("dev %p, buf %p, block 0x%x, count %u\n", bdev, buf, block, count); + + if (virtio_block_read_write(dev->dev, buf, (off_t)block * dev->bdev.block_size, + count * dev->bdev.block_size, false) == 0) { + return count * dev->bdev.block_size; + } else { + return ERR_IO; + } +} + +static ssize_t virtio_bdev_write_block(struct bdev *bdev, const void *buf, bnum_t block, uint count) +{ + struct virtio_block_dev *dev = containerof(bdev, struct virtio_block_dev, bdev); + + LTRACEF("dev %p, buf %p, block 0x%x, count %u\n", bdev, buf, block, count); + + if (virtio_block_read_write(dev->dev, (void *)buf, (off_t)block * dev->bdev.block_size, + count * dev->bdev.block_size, true) == 0) { + return count * dev->bdev.block_size; + } else { + return ERR_IO; + } +} + diff --git a/kernel/dev/virtio/gpu/BUILD.gn b/kernel/dev/virtio/gpu/BUILD.gn new file mode 100644 index 000000000..69fe6f61c --- /dev/null +++ b/kernel/dev/virtio/gpu/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("gpu") { + configs += [ "//kernel/kernel:enable_vm" ] + sources = [ + "virtio-gpu.c", + ] + deps = [ + "//kernel/dev/virtio", + "//kernel/lib/gfx", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/virtio/gpu/rules.mk b/kernel/dev/virtio/gpu/rules.mk new file mode 100644 index 000000000..d271aecf9 --- /dev/null +++ b/kernel/dev/virtio/gpu/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/virtio-gpu.c \ + +MODULE_DEPS += \ + dev/virtio \ + lib/gfx + +include make/module.mk diff --git a/kernel/dev/virtio/gpu/virtio-gpu.c b/kernel/dev/virtio/gpu/virtio-gpu.c new file mode 100644 index 000000000..b40b13f52 --- /dev/null +++ b/kernel/dev/virtio/gpu/virtio-gpu.c @@ -0,0 +1,564 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virtio_gpu.h" + +#define LOCAL_TRACE 0 + +static enum handler_return virtio_gpu_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e); +static enum handler_return virtio_gpu_config_change_callback(struct virtio_device *dev); +static int virtio_gpu_flush_thread(void *arg); +static status_t virtio_gpu_init(struct virtio_device *dev, uint32_t host_features); +static status_t virtio_gpu_start(struct virtio_device *dev); + +struct virtio_gpu_dev { + struct virtio_device *dev; + + mutex_t lock; + event_t io_event; + + void *gpu_request; + paddr_t gpu_request_phys; + + /* a saved copy of the display */ + struct virtio_gpu_display_one pmode; + int pmode_id; + + /* resource id that is set as scanout */ + uint32_t display_resource_id; + + /* next resource id */ + uint32_t next_resource_id; + + event_t flush_event; + + /* framebuffer */ + void *fb; +}; + +VIRTIO_DEV_CLASS(gpu, VIRTIO_DEV_ID_GPU, NULL, virtio_gpu_init, virtio_gpu_start); + +static struct virtio_gpu_dev *the_gdev; + +static status_t send_command_response(struct virtio_gpu_dev *gdev, const void *cmd, size_t cmd_len, void **_res, size_t res_len) +{ + DEBUG_ASSERT(gdev); + DEBUG_ASSERT(cmd); + DEBUG_ASSERT(_res); + DEBUG_ASSERT(cmd_len + res_len < PAGE_SIZE); + + LTRACEF("gdev %p, cmd %p, cmd_len %zu, res %p, res_len %zu\n", gdev, cmd, cmd_len, _res, res_len); + + uint16_t i; + struct vring_desc *desc = virtio_alloc_desc_chain(gdev->dev, 0, 2, &i); + DEBUG_ASSERT(desc); + + memcpy(gdev->gpu_request, cmd, cmd_len); + + desc->addr = gdev->gpu_request_phys; + desc->len = cmd_len; + desc->flags |= VRING_DESC_F_NEXT; + + /* set the second descriptor to the response with the write bit set */ + desc = virtio_desc_index_to_desc(gdev->dev, 0, desc->next); + DEBUG_ASSERT(desc); + + void *res = (void *)((uint8_t *)gdev->gpu_request + cmd_len); + *_res = res; + paddr_t res_phys = gdev->gpu_request_phys + cmd_len; + memset(res, 0, res_len); + + desc->addr = res_phys; + desc->len = res_len; + desc->flags = VRING_DESC_F_WRITE; + + /* submit the transfer */ + virtio_submit_chain(gdev->dev, 0, i); + + /* kick it off */ + virtio_kick(gdev->dev, 0); + + /* wait for result */ + event_wait(&gdev->io_event); + + return NO_ERROR; +} + +static status_t get_display_info(struct virtio_gpu_dev *gdev) +{ + status_t err; + + LTRACEF("gdev %p\n", gdev); + + DEBUG_ASSERT(gdev); + + /* grab a lock to keep this single message at a time */ + mutex_acquire(&gdev->lock); + + /* construct the get display info message */ + struct virtio_gpu_ctrl_hdr req; + memset(&req, 0, sizeof(req)); + req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO; + + /* send the message and get a response */ + struct virtio_gpu_resp_display_info *info; + err = send_command_response(gdev, &req, sizeof(req), (void **)&info, sizeof(*info)); + DEBUG_ASSERT(err == NO_ERROR); + if (err < NO_ERROR) { + mutex_release(&gdev->lock); + return ERR_NOT_FOUND; + } + + /* we got response */ + if (info->hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO) { + mutex_release(&gdev->lock); + return ERR_NOT_FOUND; + } + + LTRACEF("response:\n"); + for (uint i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) { + if (info->pmodes[i].enabled) { + LTRACEF("%u: x %u y %u w %u h %u flags 0x%x\n", i, + info->pmodes[i].r.x, info->pmodes[i].r.y, info->pmodes[i].r.width, info->pmodes[i].r.height, + info->pmodes[i].flags); + if (gdev->pmode_id < 0) { + /* save the first valid pmode we see */ + memcpy(&gdev->pmode, &info->pmodes[i], sizeof(gdev->pmode)); + gdev->pmode_id = i; + } + } + } + + /* release the lock */ + mutex_release(&gdev->lock); + + return NO_ERROR; +} + +static status_t allocate_2d_resource(struct virtio_gpu_dev *gdev, uint32_t *resource_id, uint32_t width, uint32_t height) +{ + status_t err; + + LTRACEF("gdev %p\n", gdev); + + DEBUG_ASSERT(gdev); + DEBUG_ASSERT(resource_id); + + /* grab a lock to keep this single message at a time */ + mutex_acquire(&gdev->lock); + + /* construct the request */ + struct virtio_gpu_resource_create_2d req; + memset(&req, 0, sizeof(req)); + + req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D; + req.resource_id = gdev->next_resource_id++; + *resource_id = req.resource_id; + req.format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; + req.width = width; + req.height = height; + + /* send the command and get a response */ + struct virtio_gpu_ctrl_hdr *res; + err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res)); + DEBUG_ASSERT(err == NO_ERROR); + + /* see if we got a valid response */ + LTRACEF("response type 0x%x\n", res->type); + err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY; + + /* release the lock */ + mutex_release(&gdev->lock); + + return err; +} + +static status_t attach_backing(struct virtio_gpu_dev *gdev, uint32_t resource_id, void *ptr, size_t buf_len) +{ + status_t err; + + LTRACEF("gdev %p, resource_id %u, ptr %p, buf_len %zu\n", gdev, resource_id, ptr, buf_len); + + DEBUG_ASSERT(gdev); + DEBUG_ASSERT(ptr); + + /* grab a lock to keep this single message at a time */ + mutex_acquire(&gdev->lock); + + /* construct the request */ + struct { + struct virtio_gpu_resource_attach_backing req; + struct virtio_gpu_mem_entry mem; + } req; + memset(&req, 0, sizeof(req)); + + req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING; + req.req.resource_id = resource_id; + req.req.nr_entries = 1; + + paddr_t pa; + pa = vaddr_to_paddr(ptr); + req.mem.addr = pa; + req.mem.length = buf_len; + + /* send the command and get a response */ + struct virtio_gpu_ctrl_hdr *res; + err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res)); + DEBUG_ASSERT(err == NO_ERROR); + + /* see if we got a valid response */ + LTRACEF("response type 0x%x\n", res->type); + err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY; + + /* release the lock */ + mutex_release(&gdev->lock); + + return err; +} + +static status_t set_scanout(struct virtio_gpu_dev *gdev, uint32_t scanout_id, uint32_t resource_id, uint32_t width, uint32_t height) +{ + status_t err; + + LTRACEF("gdev %p, scanout_id %u, resource_id %u, width %u, height %u\n", gdev, scanout_id, resource_id, width, height); + + /* grab a lock to keep this single message at a time */ + mutex_acquire(&gdev->lock); + + /* construct the request */ + struct virtio_gpu_set_scanout req; + memset(&req, 0, sizeof(req)); + + req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT; + req.r.x = req.r.y = 0; + req.r.width = width; + req.r.height = height; + req.scanout_id = scanout_id; + req.resource_id = resource_id; + + /* send the command and get a response */ + struct virtio_gpu_ctrl_hdr *res; + err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res)); + DEBUG_ASSERT(err == NO_ERROR); + + /* see if we got a valid response */ + LTRACEF("response type 0x%x\n", res->type); + err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY; + + /* release the lock */ + mutex_release(&gdev->lock); + + return err; +} + +static status_t flush_resource(struct virtio_gpu_dev *gdev, uint32_t resource_id, uint32_t width, uint32_t height) +{ + status_t err; + + LTRACEF("gdev %p, resource_id %u, width %u, height %u\n", gdev, resource_id, width, height); + + /* grab a lock to keep this single message at a time */ + mutex_acquire(&gdev->lock); + + /* construct the request */ + struct virtio_gpu_resource_flush req; + memset(&req, 0, sizeof(req)); + + req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH; + req.r.x = req.r.y = 0; + req.r.width = width; + req.r.height = height; + req.resource_id = resource_id; + + /* send the command and get a response */ + struct virtio_gpu_ctrl_hdr *res; + err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res)); + DEBUG_ASSERT(err == NO_ERROR); + + /* see if we got a valid response */ + LTRACEF("response type 0x%x\n", res->type); + err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY; + + /* release the lock */ + mutex_release(&gdev->lock); + + return err; +} + +static status_t transfer_to_host_2d(struct virtio_gpu_dev *gdev, uint32_t resource_id, uint32_t width, uint32_t height) +{ + status_t err; + + LTRACEF("gdev %p, resource_id %u, width %u, height %u\n", gdev, resource_id, width, height); + + /* grab a lock to keep this single message at a time */ + mutex_acquire(&gdev->lock); + + /* construct the request */ + struct virtio_gpu_transfer_to_host_2d req; + memset(&req, 0, sizeof(req)); + + req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D; + req.r.x = req.r.y = 0; + req.r.width = width; + req.r.height = height; + req.offset = 0; + req.resource_id = resource_id; + + /* send the command and get a response */ + struct virtio_gpu_ctrl_hdr *res; + err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res)); + DEBUG_ASSERT(err == NO_ERROR); + + /* see if we got a valid response */ + LTRACEF("response type 0x%x\n", res->type); + err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY; + + /* release the lock */ + mutex_release(&gdev->lock); + + return err; +} + +static status_t virtio_gpu_start(struct virtio_device *dev) +{ + status_t err; + + LTRACEF("dev %p\n", dev); + + struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)dev->priv; + + /* get the display info and see if we find a valid pmode */ + err = get_display_info(gdev); + if (err < 0) { + LTRACEF("failed to get display info\n"); + return err; + } + + if (gdev->pmode_id < 0) { + LTRACEF("we failed to find a pmode, exiting\n"); + return ERR_NOT_FOUND; + } + + /* allocate a resource */ + err = allocate_2d_resource(gdev, &gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height); + if (err < 0) { + LTRACEF("failed to allocate 2d resource\n"); + return err; + } + + /* attach a backing store to the resource */ + size_t len = gdev->pmode.r.width * gdev->pmode.r.height * 4; + gdev->fb = pmm_alloc_kpages(ROUNDUP(len, PAGE_SIZE) / PAGE_SIZE, NULL, NULL); + if (!gdev->fb) { + TRACEF("failed to allocate framebuffer, wanted 0x%zx bytes\n", len); + return ERR_NO_MEMORY; + } + + printf("virtio-gpu: framebuffer at %p, 0x%zx bytes\n", gdev->fb, len); + + err = attach_backing(gdev, gdev->display_resource_id, gdev->fb, len); + if (err < 0) { + LTRACEF("failed to attach backing store\n"); + return err; + } + + /* attach this resource as a scanout */ + err = set_scanout(gdev, gdev->pmode_id, gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height); + if (err < 0) { + LTRACEF("failed to set scanout\n"); + return err; + } + + /* create the flush thread */ + thread_t *t; + t = thread_create("virtio gpu flusher", &virtio_gpu_flush_thread, (void *)gdev, HIGH_PRIORITY, DEFAULT_STACK_SIZE); + thread_detach_and_resume(t); + + /* kick it once */ + event_signal(&gdev->flush_event, true); + + LTRACE_EXIT; + + return NO_ERROR; +} + + +static void dump_gpu_config(const volatile struct virtio_gpu_config *config) +{ + LTRACEF("events_read 0x%x\n", config->events_read); + LTRACEF("events_clear 0x%x\n", config->events_clear); + LTRACEF("num_scanouts 0x%x\n", config->num_scanouts); + LTRACEF("reserved 0x%x\n", config->reserved); +} + +static status_t virtio_gpu_init(struct virtio_device *dev, uint32_t host_features) +{ + LTRACEF("dev %p, host_features 0x%x\n", dev, host_features); + + /* allocate a new gpu device */ + struct virtio_gpu_dev *gdev = malloc(sizeof(struct virtio_gpu_dev)); + if (!gdev) + return ERR_NO_MEMORY; + + mutex_init(&gdev->lock); + event_init(&gdev->io_event, false, EVENT_FLAG_AUTOUNSIGNAL); + event_init(&gdev->flush_event, false, EVENT_FLAG_AUTOUNSIGNAL); + + gdev->dev = dev; + dev->priv = gdev; + + gdev->pmode_id = -1; + gdev->next_resource_id = 1; + + /* allocate memory for a gpu request */ +#if WITH_KERNEL_VM + gdev->gpu_request = pmm_alloc_kpage(&gdev->gpu_request_phys); +#else + gdev->gpu_request = malloc(sizeof(struct virtio_gpu_resp_display_info)); // XXX get size better + gdev->gpu_request_phys = (paddr_t)gdev->gpu_request; +#endif + + /* make sure the device is reset */ + virtio_reset_device(dev); + + volatile struct virtio_gpu_config *config = (struct virtio_gpu_config *)dev->config_ptr; + dump_gpu_config(config); + + /* ack and set the driver status bit */ + virtio_status_acknowledge_driver(dev); + + // XXX check features bits and ack/nak them + + /* allocate a virtio ring */ + virtio_alloc_ring(dev, 0, 16); + + /* set our irq handler */ + dev->irq_driver_callback = &virtio_gpu_irq_driver_callback; + dev->config_change_callback = &virtio_gpu_config_change_callback; + + /* set DRIVER_OK */ + virtio_status_driver_ok(dev); + + /* save the main device we've found */ + the_gdev = gdev; + + printf("found virtio gpu device\n"); + + return NO_ERROR; +} + +static enum handler_return virtio_gpu_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e) +{ + struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)dev->priv; + + LTRACEF("dev %p, ring %u, e %p, id %u, len %u\n", dev, ring, e, e->id, e->len); + + /* parse our descriptor chain, add back to the free queue */ + uint16_t i = e->id; + for (;;) { + int next; + struct vring_desc *desc = virtio_desc_index_to_desc(dev, ring, i); + + //virtio_dump_desc(desc); + + if (desc->flags & VRING_DESC_F_NEXT) { + next = desc->next; + } else { + /* end of chain */ + next = -1; + } + + virtio_free_desc(dev, ring, i); + + if (next < 0) + break; + i = next; + } + + /* signal our event */ + event_signal(&gdev->io_event, false); + + return INT_RESCHEDULE; +} + +static enum handler_return virtio_gpu_config_change_callback(struct virtio_device *dev) +{ + struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)dev->priv; + + LTRACEF("gdev %p\n", gdev); + + volatile struct virtio_gpu_config *config = (struct virtio_gpu_config *)dev->config_ptr; + dump_gpu_config(config); + + return INT_RESCHEDULE; +} + +static int virtio_gpu_flush_thread(void *arg) +{ + struct virtio_gpu_dev *gdev = (struct virtio_gpu_dev *)arg; + status_t err; + + for (;;) { + event_wait(&gdev->flush_event); + + /* transfer to host 2d */ + err = transfer_to_host_2d(gdev, gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height); + if (err < 0) { + LTRACEF("failed to flush resource\n"); + continue; + } + + /* resource flush */ + err = flush_resource(gdev, gdev->display_resource_id, gdev->pmode.r.width, gdev->pmode.r.height); + if (err < 0) { + LTRACEF("failed to flush resource\n"); + continue; + } + } + + return 0; +} + +void virtio_gpu_gfx_flush(uint starty, uint endy) +{ + event_signal(&the_gdev->flush_event, !arch_ints_disabled()); +} + +status_t display_get_info(struct display_info *info) +{ + memset(info, 0, sizeof(*info)); + + if (!the_gdev) + return ERR_NOT_FOUND; + + info->framebuffer = the_gdev->fb; + info->format = DISPLAY_FORMAT_RGB_x888; + info->width = the_gdev->pmode.r.width; + info->height = the_gdev->pmode.r.height; + info->stride = info->width; + info->flush = virtio_gpu_gfx_flush; + + return NO_ERROR; +} + + diff --git a/kernel/dev/virtio/gpu/virtio_gpu.h b/kernel/dev/virtio/gpu/virtio_gpu.h new file mode 100644 index 000000000..19ed6d278 --- /dev/null +++ b/kernel/dev/virtio/gpu/virtio_gpu.h @@ -0,0 +1,208 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * + * This header is BSD licensed so anyone can use the definitions + * to implement compatible drivers/servers: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* taken from qemu sources */ + +#ifndef VIRTIO_GPU_HW_H +#define VIRTIO_GPU_HW_H + +#include + +enum virtio_gpu_ctrl_type { + VIRTIO_GPU_UNDEFINED = 0, + + /* 2d commands */ + VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, + VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, + VIRTIO_GPU_CMD_RESOURCE_UNREF, + VIRTIO_GPU_CMD_SET_SCANOUT, + VIRTIO_GPU_CMD_RESOURCE_FLUSH, + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, + VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, + VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, + + /* cursor commands */ + VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, + VIRTIO_GPU_CMD_MOVE_CURSOR, + + /* success responses */ + VIRTIO_GPU_RESP_OK_NODATA = 0x1100, + VIRTIO_GPU_RESP_OK_DISPLAY_INFO, + + /* error responses */ + VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, + VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, + VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, + VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, +}; + +#define VIRTIO_GPU_FLAG_FENCE (1 << 0) + +struct virtio_gpu_ctrl_hdr { + uint32_t type; + uint32_t flags; + uint64_t fence_id; + uint32_t ctx_id; + uint32_t padding; +}; + +/* data passed in the cursor vq */ + +struct virtio_gpu_cursor_pos { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */ +struct virtio_gpu_update_cursor { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_cursor_pos pos; /* update & move */ + uint32_t resource_id; /* update only */ + uint32_t hot_x; /* update only */ + uint32_t hot_y; /* update only */ + uint32_t padding; +}; + +/* data passed in the control vq, 2d related */ + +struct virtio_gpu_rect { + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_UNREF */ +struct virtio_gpu_resource_unref { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */ +struct virtio_gpu_resource_create_2d { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t format; + uint32_t width; + uint32_t height; +}; + +/* VIRTIO_GPU_CMD_SET_SCANOUT */ +struct virtio_gpu_set_scanout { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + uint32_t scanout_id; + uint32_t resource_id; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */ +struct virtio_gpu_resource_flush { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + uint32_t resource_id; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */ +struct virtio_gpu_transfer_to_host_2d { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + uint64_t offset; + uint32_t resource_id; + uint32_t padding; +}; + +struct virtio_gpu_mem_entry { + uint64_t addr; + uint32_t length; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */ +struct virtio_gpu_resource_attach_backing { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t nr_entries; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */ +struct virtio_gpu_resource_detach_backing { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t padding; +}; + +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */ +#define VIRTIO_GPU_MAX_SCANOUTS 16 +struct virtio_gpu_resp_display_info { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_display_one { + struct virtio_gpu_rect r; + uint32_t enabled; + uint32_t flags; + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; +}; + +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) + +struct virtio_gpu_config { + uint32_t events_read; + uint32_t events_clear; + uint32_t num_scanouts; + uint32_t reserved; +}; + +/* simple formats for fbcon/X use */ +enum virtio_gpu_formats { + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, + + VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, + VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, + + VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, + VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, +}; + +#endif diff --git a/kernel/dev/virtio/include/dev/virtio.h b/kernel/dev/virtio/include/dev/virtio.h new file mode 100644 index 000000000..41d93be07 --- /dev/null +++ b/kernel/dev/virtio/include/dev/virtio.h @@ -0,0 +1,114 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include + +/* Device IDs taken from Section 5 of the VirtIO 1.0 Draft Specification + * http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.pdf */ +#define VIRTIO_DEV_ID_INVALID 0x00 +#define VIRTIO_DEV_ID_NET 0x01 +#define VIRTIO_DEV_ID_BLOCK 0x02 +#define VIRTIO_DEV_ID_CONSOLE 0x03 +#define VIRTIO_DEV_ID_ENTROPY_SRC 0x04 +#define VIRTIO_DEV_ID_MEM_BALLOON 0x05 +#define VIRTIO_DEV_ID_IO_MEMORY 0x06 +#define VIRTIO_DEV_ID_RPMSG 0x07 +#define VIRTIO_DEV_ID_SCSI_HOST 0x08 +#define VIRTIO_DEV_ID_9P_TRANSPORT 0x09 +#define VIRTIO_DEV_ID_MAC80211_WLAN 0x0A +#define VIRTIO_DEV_ID_RPROC_SERIAL 0x0B +#define VIRTIO_DEV_ID_CAIF 0x0C +#define VIRTIO_DEV_ID_GPU 0x10 +#define VIRTIO_DEV_ID_INPUT 0x12 + +/* detect a virtio mmio hardware block + * returns number of devices found */ +int virtio_mmio_detect(void *ptr, uint count, const uint irqs[]); + +#define MAX_VIRTIO_RINGS 4 + +struct virtio_mmio_config; + +struct virtio_device { + bool valid; + + uint index; + uint irq; + + volatile struct virtio_mmio_config *mmio_config; + void *config_ptr; + + void *priv; /* a place for the driver to put private data */ + + enum handler_return (*irq_driver_callback)(struct virtio_device *dev, uint ring, const struct vring_used_elem *e); + enum handler_return (*config_change_callback)(struct virtio_device *dev); + + /* virtio rings */ + uint32_t active_rings_bitmap; + struct vring ring[MAX_VIRTIO_RINGS]; +}; + +void virtio_reset_device(struct virtio_device *dev); +void virtio_status_acknowledge_driver(struct virtio_device *dev); +void virtio_status_driver_ok(struct virtio_device *dev); + +/* api used by devices to interact with the virtio bus */ +status_t virtio_alloc_ring(struct virtio_device *dev, uint index, uint16_t len) __NONNULL(); + +/* add a descriptor at index desc_index to the free list on ring_index */ +void virtio_free_desc(struct virtio_device *dev, uint ring_index, uint16_t desc_index); + +/* add the descriptor(s) in the chain starting at chain_head to the free list on ring_index */ +void virtio_free_desc_chain(struct virtio_device *dev, uint ring_index, uint16_t chain_head); + +/* allocate a descriptor off the free list, 0xffff is error */ +uint16_t virtio_alloc_desc(struct virtio_device *dev, uint ring_index); + +/* allocate a descriptor chain the free list */ +struct vring_desc *virtio_alloc_desc_chain(struct virtio_device *dev, uint ring_index, size_t count, uint16_t *start_index); + +static inline struct vring_desc *virtio_desc_index_to_desc(struct virtio_device *dev, uint ring_index, uint16_t desc_index) +{ + DEBUG_ASSERT(desc_index != 0xffff); + return &dev->ring[ring_index].desc[desc_index]; +} + +void virtio_dump_desc(const struct vring_desc *desc); + +/* submit a chain to the avail list */ +void virtio_submit_chain(struct virtio_device *dev, uint ring_index, uint16_t desc_index); + +void virtio_kick(struct virtio_device *dev, uint ring_idnex); + +/* class driver registration */ +typedef void(*virtio_module_init_func)(void); +typedef status_t(*virtio_init_func)(struct virtio_device*, uint32_t); +typedef status_t(*virtio_starup_func)(struct virtio_device*); +typedef struct virtio_dev_class { + uint32_t device_id; + const char* name; + virtio_module_init_func module_init_fn; + virtio_init_func init_fn; + virtio_starup_func startup_fn; +} virtio_dev_class_t; + +#define VIRTIO_DEV_CLASS(_name, id, mod_init, init, startup) \ +extern const virtio_dev_class_t __virtio_class_##_name; \ +const virtio_dev_class_t __virtio_class_##_name __SECTION("virtio_classes") = { \ + .device_id = id, \ + .name = #_name, \ + .module_init_fn = mod_init, \ + .init_fn = init, \ + .startup_fn = startup, \ +}; + diff --git a/kernel/dev/virtio/include/dev/virtio/virtio_ring.h b/kernel/dev/virtio/include/dev/virtio/virtio_ring.h new file mode 100644 index 000000000..525cb51c8 --- /dev/null +++ b/kernel/dev/virtio/include/dev/virtio/virtio_ring.h @@ -0,0 +1,176 @@ +/* taken from linux source 3.15 at include/uapi/linux/virtio_ring.h */ +#ifndef _UAPI_LINUX_VIRTIO_RING_H +#define _UAPI_LINUX_VIRTIO_RING_H +/* An interface for efficient virtio implementation, currently for use by KVM + * and lguest, but hopefully others soon. Do NOT change this since it will + * break existing servers and clients. + * + * This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright Rusty Russell IBM Corporation 2007. */ +#include +#include + +/* This marks a buffer as continuing via the next field. */ +#define VRING_DESC_F_NEXT 1 +/* This marks a buffer as write-only (otherwise read-only). */ +#define VRING_DESC_F_WRITE 2 +/* This means the buffer contains a list of buffer descriptors. */ +#define VRING_DESC_F_INDIRECT 4 + +/* The Host uses this in used->flags to advise the Guest: don't kick me when + * you add a buffer. It's unreliable, so it's simply an optimization. Guest + * will still kick if it's out of buffers. */ +#define VRING_USED_F_NO_NOTIFY 1 +/* The Guest uses this in avail->flags to advise the Host: don't interrupt me + * when you consume a buffer. It's unreliable, so it's simply an + * optimization. */ +#define VRING_AVAIL_F_NO_INTERRUPT 1 + +/* We support indirect buffer descriptors */ +#define VIRTIO_RING_F_INDIRECT_DESC 28 + +/* The Guest publishes the used index for which it expects an interrupt + * at the end of the avail ring. Host should ignore the avail->flags field. */ +/* The Host publishes the avail index for which it expects a kick + * at the end of the used ring. Guest should ignore the used->flags field. */ +#define VIRTIO_RING_F_EVENT_IDX 29 + +/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */ +struct vring_desc { + /* Address (guest-physical). */ + uint64_t addr; + /* Length. */ + uint32_t len; + /* The flags as indicated above. */ + uint16_t flags; + /* We chain unused descriptors via this, too */ + uint16_t next; +}; + +struct vring_avail { + uint16_t flags; + uint16_t idx; + uint16_t ring[]; +}; + +/* u32 is used here for ids for padding reasons. */ +struct vring_used_elem { + /* Index of start of used descriptor chain. */ + uint32_t id; + /* Total length of the descriptor chain which was used (written to) */ + uint32_t len; +}; + +struct vring_used { + uint16_t flags; + uint16_t idx; + struct vring_used_elem ring[]; +}; + +struct vring { + uint32_t num; + uint32_t num_mask; + + uint16_t free_list; /* head of a free list of descriptors per ring. 0xffff is NULL */ + uint16_t free_count; + + uint16_t last_used; + + struct vring_desc *desc; + + struct vring_avail *avail; + + struct vring_used *used; +}; + +/* The standard layout for the ring is a continuous chunk of memory which looks + * like this. We assume num is a power of 2. + * + * struct vring + * { + * // The actual descriptors (16 bytes each) + * struct vring_desc desc[num]; + * + * // A ring of available descriptor heads with free-running index. + * uint16_t avail_flags; + * uint16_t avail_idx; + * uint16_t available[num]; + * uint16_t used_event_idx; + * + * // Padding to the next align boundary. + * char pad[]; + * + * // A ring of used descriptor heads with free-running index. + * uint16_t used_flags; + * uint16_t used_idx; + * struct vring_used_elem used[num]; + * uint16_t avail_event_idx; + * }; + */ +/* We publish the used event index at the end of the available ring, and vice + * versa. They are at the end for backwards compatibility. */ +#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) +#define vring_avail_event(vr) (*(uint16_t *)&(vr)->used->ring[(vr)->num]) + +static inline void vring_init(struct vring *vr, unsigned int num, void *p, + unsigned long align) +{ + vr->num = num; + vr->num_mask = (1 << log2_uint(num)) - 1; + vr->free_list = 0xffff; + vr->free_count = 0; + vr->last_used = 0; + vr->desc = p; + vr->avail = p + num*sizeof(struct vring_desc); + vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(uint16_t) + + align-1) & ~(align - 1)); +} + +static inline unsigned vring_size(unsigned int num, unsigned long align) +{ + return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (3 + num) + + align - 1) & ~(align - 1)) + + sizeof(uint16_t) * 3 + sizeof(struct vring_used_elem) * num; +} + +/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */ +/* Assuming a given event_idx value from the other size, if + * we have just incremented index from old to new_idx, + * should we trigger an event? */ +static inline int vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) +{ + /* Note: Xen has similar logic for notification hold-off + * in include/xen/interface/io/ring.h with req_event and req_prod + * corresponding to event_idx + 1 and new_idx respectively. + * Note also that req_event and req_prod in Xen start at 1, + * event indexes in virtio start at 0. */ + return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old); +} + +#endif /* _UAPI_LINUX_VIRTIO_RING_H */ + diff --git a/kernel/dev/virtio/net/BUILD.gn b/kernel/dev/virtio/net/BUILD.gn new file mode 100644 index 000000000..8ae17c63d --- /dev/null +++ b/kernel/dev/virtio/net/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("net") { + configs += [ "//kernel/kernel:enable_vm" ] + sources = [ + "virtio-net.c", + ] + deps = [ + "//kernel/dev/virtio", + "//kernel/lib/libc", + "//kernel/lib/pktbuf", + ] +} diff --git a/kernel/dev/virtio/net/include/dev/virtio/net.h b/kernel/dev/virtio/net/include/dev/virtio/net.h new file mode 100644 index 000000000..7afd3d7c1 --- /dev/null +++ b/kernel/dev/virtio/net/include/dev/virtio/net.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +status_t virtio_net_start(void); + +/* return the count of virtio interfaces found */ +int virtio_net_found(void); + +status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]); + +struct pktbuf; +extern status_t virtio_net_send_minip_pkt(struct pktbuf *p); + diff --git a/kernel/dev/virtio/net/rules.mk b/kernel/dev/virtio/net/rules.mk new file mode 100644 index 000000000..742007aac --- /dev/null +++ b/kernel/dev/virtio/net/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/virtio-net.c + +MODULE_DEPS += \ + dev/virtio \ + lib/minip + +include make/module.mk diff --git a/kernel/dev/virtio/net/virtio-net.c b/kernel/dev/virtio/net/virtio-net.c new file mode 100644 index 000000000..3503fe440 --- /dev/null +++ b/kernel/dev/virtio/net/virtio-net.c @@ -0,0 +1,461 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct virtio_net_config { + uint8_t mac[6]; + uint16_t status; + uint16_t max_virtqueue_pairs; +} __PACKED; + +struct virtio_net_hdr { + uint8_t flags; + uint8_t gso_type; + uint16_t hdr_len; + uint16_t gso_size; + uint16_t csum_start; + uint16_t csum_offset; + uint16_t num_buffers; // unused in tx +} __PACKED; + +#define VIRTIO_NET_F_CSUM (1<<0) +#define VIRTIO_NET_F_GUEST_CSUM (1<<1) +#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS (1<<2) +#define VIRTIO_NET_F_MAC (1<<5) +#define VIRTIO_NET_F_GSO (1<<6) +#define VIRTIO_NET_F_GUEST_TSO4 (1<<7) +#define VIRTIO_NET_F_GUEST_TSO6 (1<<8) +#define VIRTIO_NET_F_GUEST_ECN (1<<9) +#define VIRTIO_NET_F_GUEST_UFO (1<<10) +#define VIRTIO_NET_F_HOST_TSO4 (1<<11) +#define VIRTIO_NET_F_HOST_TSO6 (1<<12) +#define VIRTIO_NET_F_HOST_ECN (1<<13) +#define VIRTIO_NET_F_HOST_UFO (1<<14) +#define VIRTIO_NET_F_MRG_RXBUF (1<<15) +#define VIRTIO_NET_F_STATUS (1<<16) +#define VIRTIO_NET_F_CTRL_VQ (1<<17) +#define VIRTIO_NET_F_CTRL_RX (1<<18) +#define VIRTIO_NET_F_CTRL_VLAN (1<<19) +#define VIRTIO_NET_F_GUEST_ANNOUNCE (1<<21) +#define VIRTIO_NET_F_MQ (1<<22) +#define VIRTIO_NET_F_CTRL_MAC_ADDR (1<<23) + +#define VIRTIO_NET_S_LINK_UP (1<<0) +#define VIRTIO_NET_S_ANNOUNCE (1<<1) + +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 16 + +#define RING_RX 0 +#define RING_TX 1 + +#define VIRTIO_NET_MSS 1514 + +struct virtio_net_dev { + struct virtio_device *dev; + bool started; + + struct virtio_net_config *config; + + spin_lock_t lock; + event_t rx_event; + + /* list of active tx/rx packets to be freed at irq time */ + pktbuf_t *pending_tx_packet[TX_RING_SIZE]; + pktbuf_t *pending_rx_packet[RX_RING_SIZE]; + + uint tx_pending_count; + struct list_node completed_rx_queue; +}; + +static enum handler_return virtio_net_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e); +static int virtio_net_rx_worker(void *arg); +static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p); +static status_t virtio_net_init(struct virtio_device *dev, uint32_t host_features); + +VIRTIO_DEV_CLASS(net, VIRTIO_DEV_ID_NET, NULL, virtio_net_init, NULL); + +// XXX remove need for this +static struct virtio_net_dev *the_ndev; + +static void dump_feature_bits(uint32_t feature) +{ + printf("virtio-net host features (0x%x):", feature); + if (feature & VIRTIO_NET_F_CSUM) printf(" CSUM"); + if (feature & VIRTIO_NET_F_GUEST_CSUM) printf(" GUEST_CSUM"); + if (feature & VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) printf(" CTRL_GUEST_OFFLOADS"); + if (feature & VIRTIO_NET_F_MAC) printf(" MAC"); + if (feature & VIRTIO_NET_F_GSO) printf(" GSO"); + if (feature & VIRTIO_NET_F_GUEST_TSO4) printf(" GUEST_TSO4"); + if (feature & VIRTIO_NET_F_GUEST_TSO6) printf(" GUEST_TSO6"); + if (feature & VIRTIO_NET_F_GUEST_ECN) printf(" GUEST_ECN"); + if (feature & VIRTIO_NET_F_GUEST_UFO) printf(" GUEST_UFO"); + if (feature & VIRTIO_NET_F_HOST_TSO4) printf(" HOST_TSO4"); + if (feature & VIRTIO_NET_F_HOST_TSO6) printf(" HOST_TSO6"); + if (feature & VIRTIO_NET_F_HOST_ECN) printf(" HOST_ECN"); + if (feature & VIRTIO_NET_F_HOST_UFO) printf(" HOST_UFO"); + if (feature & VIRTIO_NET_F_MRG_RXBUF) printf(" MRG_RXBUF"); + if (feature & VIRTIO_NET_F_STATUS) printf(" STATUS"); + if (feature & VIRTIO_NET_F_CTRL_VQ) printf(" CTRL_VQ"); + if (feature & VIRTIO_NET_F_CTRL_RX) printf(" CTRL_RX"); + if (feature & VIRTIO_NET_F_CTRL_VLAN) printf(" CTRL_VLAN"); + if (feature & VIRTIO_NET_F_GUEST_ANNOUNCE) printf(" GUEST_ANNOUNCE"); + if (feature & VIRTIO_NET_F_MQ) printf(" MQ"); + if (feature & VIRTIO_NET_F_CTRL_MAC_ADDR) printf(" CTRL_MAC_ADDR"); + printf("\n"); +} + +static status_t virtio_net_init(struct virtio_device *dev, uint32_t host_features) +{ + LTRACEF("dev %p, host_features 0x%x\n", dev, host_features); + + /* allocate a new net device */ + struct virtio_net_dev *ndev = calloc(1, sizeof(struct virtio_net_dev)); + if (!ndev) + return ERR_NO_MEMORY; + + ndev->dev = dev; + dev->priv = ndev; + ndev->started = false; + + ndev->lock = SPIN_LOCK_INITIAL_VALUE; + event_init(&ndev->rx_event, false, EVENT_FLAG_AUTOUNSIGNAL); + list_initialize(&ndev->completed_rx_queue); + + ndev->config = (struct virtio_net_config *)dev->config_ptr; + + /* ack and set the driver status bit */ + virtio_status_acknowledge_driver(dev); + + // XXX check features bits and ack/nak them + dump_feature_bits(host_features); + + /* set our irq handler */ + dev->irq_driver_callback = &virtio_net_irq_driver_callback; + + /* set DRIVER_OK */ + virtio_status_driver_ok(dev); + + /* allocate a pair of virtio rings */ + virtio_alloc_ring(dev, RING_RX, RX_RING_SIZE); // rx + virtio_alloc_ring(dev, RING_TX, TX_RING_SIZE); // tx + + the_ndev = ndev; + + return NO_ERROR; +} + +status_t virtio_net_start(void) +{ + if (the_ndev->started) + return ERR_ALREADY_STARTED; + + the_ndev->started = true; + + /* start the rx worker thread */ + thread_resume(thread_create("virtio_net_rx", &virtio_net_rx_worker, (void *)the_ndev, HIGH_PRIORITY, DEFAULT_STACK_SIZE)); + + /* queue up a bunch of rxes */ + for (uint i = 0; i < RX_RING_SIZE - 1; i++) { + pktbuf_t *p = pktbuf_alloc(); + if (p) { + virtio_net_queue_rx(the_ndev, p); + } + } + + return NO_ERROR; +} + +static status_t virtio_net_queue_tx_pktbuf(struct virtio_net_dev *ndev, pktbuf_t *p2) +{ + struct virtio_device *vdev = ndev->dev; + + uint16_t i; + pktbuf_t *p; + + DEBUG_ASSERT(ndev); + + p = pktbuf_alloc(); + if (!p) + return ERR_NO_MEMORY; + + /* point our header to the base of the first pktbuf */ + struct virtio_net_hdr *hdr = pktbuf_append(p, sizeof(struct virtio_net_hdr) - 2); + memset(hdr, 0, p->dlen); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&ndev->lock, state); + + /* only queue if we have enough tx descriptors */ + if (ndev->tx_pending_count + 2 > TX_RING_SIZE) + goto nodesc; + + /* allocate a chain of descriptors for our transfer */ + struct vring_desc *desc = virtio_alloc_desc_chain(vdev, RING_TX, 2, &i); + if (!desc) { + spin_unlock_irqrestore(&ndev->lock, state); + +nodesc: + TRACEF("out of virtio tx descriptors, tx_pending_count %u\n", ndev->tx_pending_count); + pktbuf_free(p, true); + + return ERR_NO_MEMORY; + } + + ndev->tx_pending_count += 2; + + /* save a pointer to our pktbufs for the irq handler to free */ + LTRACEF("saving pointer to pkt in index %u and %u\n", i, desc->next); + DEBUG_ASSERT(ndev->pending_tx_packet[i] == NULL); + DEBUG_ASSERT(ndev->pending_tx_packet[desc->next] == NULL); + ndev->pending_tx_packet[i] = p; + ndev->pending_tx_packet[desc->next] = p2; + + /* set up the descriptor pointing to the header */ + desc->addr = pktbuf_data_phys(p); + desc->len = p->dlen; + desc->flags |= VRING_DESC_F_NEXT; + + /* set up the descriptor pointing to the buffer */ + desc = virtio_desc_index_to_desc(vdev, RING_TX, desc->next); + desc->addr = pktbuf_data_phys(p2); + desc->len = p2->dlen; + desc->flags = 0; + + /* submit the transfer */ + virtio_submit_chain(vdev, RING_TX, i); + + /* kick it off */ + virtio_kick(vdev, RING_TX); + + spin_unlock_irqrestore(&ndev->lock, state); + + return NO_ERROR; +} + +/* variant of the above function that copies the buffer into a pktbuf before sending */ +static status_t virtio_net_queue_tx(struct virtio_net_dev *ndev, const void *buf, size_t len) +{ + DEBUG_ASSERT(ndev); + DEBUG_ASSERT(buf); + + pktbuf_t *p = pktbuf_alloc(); + if (!p) + return ERR_NO_MEMORY; + + /* copy the outgoing packet into the pktbuf */ + p->data = p->buffer; + p->dlen = len; + memcpy(p->data, buf, len); + + /* call through to the variant of the function that takes a pre-populated pktbuf */ + status_t err = virtio_net_queue_tx_pktbuf(ndev, p); + if (err < 0) { + pktbuf_free(p, true); + } + + return err; +} + +static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p) +{ + struct virtio_device *vdev = ndev->dev; + + DEBUG_ASSERT(ndev); + DEBUG_ASSERT(p); + + /* point our header to the base of the pktbuf */ + p->data = p->buffer; + struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)p->data; + memset(hdr, 0, sizeof(struct virtio_net_hdr) - 2); + + p->dlen = sizeof(struct virtio_net_hdr) - 2 + VIRTIO_NET_MSS; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&ndev->lock, state); + + /* allocate a chain of descriptors for our transfer */ + uint16_t i; + struct vring_desc *desc = virtio_alloc_desc_chain(vdev, RING_RX, 1, &i); + DEBUG_ASSERT(desc); /* shouldn't be possible not to have a descriptor ready */ + + /* save a pointer to our pktbufs for the irq handler to use */ + DEBUG_ASSERT(ndev->pending_rx_packet[i] == NULL); + ndev->pending_rx_packet[i] = p; + + /* set up the descriptor pointing to the header */ + desc->addr = pktbuf_data_phys(p); + desc->len = p->dlen; + desc->flags = VRING_DESC_F_WRITE; + + /* submit the transfer */ + virtio_submit_chain(vdev, RING_RX, i); + + /* kick it off */ + virtio_kick(vdev, RING_RX); + + spin_unlock_irqrestore(&ndev->lock, state); + + return NO_ERROR; +} + +static enum handler_return virtio_net_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e) +{ + struct virtio_net_dev *ndev = (struct virtio_net_dev *)dev->priv; + + LTRACEF("dev %p, ring %u, e %p, id %u, len %u\n", dev, ring, e, e->id, e->len); + + spin_lock(&ndev->lock); + + /* parse our descriptor chain, add back to the free queue */ + uint16_t i = e->id; + for (;;) { + int next; + struct vring_desc *desc = virtio_desc_index_to_desc(dev, ring, i); + + if (desc->flags & VRING_DESC_F_NEXT) { + next = desc->next; + } else { + /* end of chain */ + next = -1; + } + + virtio_free_desc(dev, ring, i); + + if (ring == RING_RX) { + /* put the freed rx buffer in a queue */ + pktbuf_t *p = ndev->pending_rx_packet[i]; + ndev->pending_rx_packet[i] = NULL; + + DEBUG_ASSERT(p); + LTRACEF("rx pktbuf %p filled\n", p); + + /* trim the pktbuf according to the written length in the used element descriptor */ + if (e->len > (sizeof(struct virtio_net_hdr) - 2 + VIRTIO_NET_MSS)) { + TRACEF("bad used len on RX %u\n", e->len); + p->dlen = 0; + } else { + p->dlen = e->len; + } + + list_add_tail(&ndev->completed_rx_queue, &p->list); + } else { // ring == RING_TX + /* free the pktbuf associated with the tx packet we just consumed */ + pktbuf_t *p = ndev->pending_tx_packet[i]; + ndev->pending_tx_packet[i] = NULL; + ndev->tx_pending_count--; + + DEBUG_ASSERT(p); + LTRACEF("freeing pktbuf %p\n", p); + + pktbuf_free(p, false); + } + + if (next < 0) + break; + i = next; + } + + spin_unlock(&ndev->lock); + + /* if rx ring, signal our event */ + if (ring == 0) { + event_signal(&ndev->rx_event, false); + } + + return INT_RESCHEDULE; +} + +static int virtio_net_rx_worker(void *arg) +{ + struct virtio_net_dev *ndev = (struct virtio_net_dev *)arg; + + for (;;) { + event_wait(&ndev->rx_event); + + /* pull some packets from the received queue */ + for (;;) { + spin_lock_saved_state_t state; + spin_lock_irqsave(&ndev->lock, state); + + pktbuf_t *p = list_remove_head_type(&ndev->completed_rx_queue, pktbuf_t, list); + + spin_unlock_irqrestore(&ndev->lock, state); + + if (!p) + break; /* nothing left in the queue, go back to waiting */ + + LTRACEF("got packet len %u\n", p->dlen); + + /* process our packet */ + struct virtio_net_hdr *hdr = pktbuf_consume(p, sizeof(struct virtio_net_hdr) - 2); + if (hdr) { + /* call up into the stack */ + minip_rx_driver_callback(p); + } + + /* requeue the pktbuf in the rx queue */ + virtio_net_queue_rx(ndev, p); + } + } + return 0; +} + +int virtio_net_found(void) +{ + return the_ndev ? 1 : 0; +} + +status_t virtio_net_get_mac_addr(uint8_t mac_addr[6]) +{ + if (!the_ndev) + return ERR_NOT_FOUND; + + memcpy(mac_addr, the_ndev->config->mac, 6); + + return NO_ERROR; +} + +status_t virtio_net_send_minip_pkt(pktbuf_t *p) +{ + LTRACEF("p %p, dlen %u, flags 0x%x\n", p, p->dlen, p->flags); + + DEBUG_ASSERT(p && p->dlen); + + if ((p->flags & PKTBUF_FLAG_EOF) == 0) { + /* can't handle multi part packets yet */ + PANIC_UNIMPLEMENTED; + + return ERR_NOT_IMPLEMENTED; + } + + /* hand the pktbuf off to the nic, it owns the pktbuf from now on out unless it fails */ + status_t err = virtio_net_queue_tx_pktbuf(the_ndev, p); + if (err < 0) { + pktbuf_free(p, true); + } + + return err; +} + diff --git a/kernel/dev/virtio/rng/BUILD.gn b/kernel/dev/virtio/rng/BUILD.gn new file mode 100644 index 000000000..b0645ed11 --- /dev/null +++ b/kernel/dev/virtio/rng/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("rng") { + configs += [ "//kernel/kernel:enable_vm" ] + sources = [ + "virtio-rng.c", + ] + deps = [ + "//kernel/dev/hw_rng", + "//kernel/dev/virtio", + "//kernel/lib/cbuf", + "//kernel/lib/libc", + ] +} diff --git a/kernel/dev/virtio/rng/rules.mk b/kernel/dev/virtio/rng/rules.mk new file mode 100644 index 000000000..45dae3450 --- /dev/null +++ b/kernel/dev/virtio/rng/rules.mk @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/virtio-rng.c \ + +MODULE_DEPS += \ + dev/virtio \ + dev/hw_rng \ + lib/cbuf + +include make/module.mk diff --git a/kernel/dev/virtio/rng/virtio-rng.c b/kernel/dev/virtio/rng/virtio-rng.c new file mode 100644 index 000000000..3e2b7ce18 --- /dev/null +++ b/kernel/dev/virtio/rng/virtio-rng.c @@ -0,0 +1,283 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include + +/* + * Some notes about using the VirtIO RNG in QEMU on Linux. + * + * In Linux there are a few different choices of which device node to bind to in + * order to generate random numbers depending on the behavior that you want to + * see. + * + * /dev/random + * This will give you random bytes from the kernel limited, high quality, + * entropy pool. Typically, HW RNGs are a bit slow, and /dev/random really + * demonstrates this. Once you are out of random bits, reads from /dev/random + * will begin to block, which (in this driver) will manifest as long delays in + * attempting to refill the entropy pool. Because of this, there is probably no + * need to throttle the VirtIO host side device in order to provide a good + * simulation of a real HW RNG. This said, the pool is small, and unless you + * need the best of the best bits, you might want to consider using something + * else. Pulling too hard on /dev/random in your simulated machine may slow + * down other operations in your host which need to use /dev/random for high + * quality entropy. + * + * /dev/urandom + * This will give you pretty good entropy. It will seed from /dev/random and + * churn out pseudo-random bits instead of blocking when the kernel entropy pool + * runs out. Because of this, there is virtual no limit to how fast you can + * make random bits when you use /dev/urandom, and you should probably consider + * configuring a throttle in order to more accurately simulate a real HW RNG. + * + * /dev/zero + * If you want something deterministic, and you don't need to actually be random + * at all, /dev/zero is a simple option. Again, a throttle is probably + * appropriate. + * + * Two sets of arguments need to be passed to QEMU in order to instantiate a + * host side MMIO VirtIO RNG device. + * + * -object rng-random,filename=,id=rng0 + * + * This set declares the deivce in the guest. Its name will be "rng0" and + * needs to match the name in the next set of params which defines the host + * side device. should be set to the name of the device node you want + * to bind the virtual device to (ex: /dev/urandom) + * + * -device virtio-rng-device,rng=rng0 + * + * This set selects the host side device driver and binds it to the name of the + * device object instantiated in the first set of parameters. In this case, we + * are binding the MMIO VirtIO RNG driver to the object "rng0". + * + * If you need to throttle the virtual device, you can do so using the + * "max-bytes" and "period" options which get passed to the driver. The host + * driver line would look something like... + * + * -device virtio-rng-device,rng=rng0,max-bytes=,period=" + * + * N defines the number of bytes which get generated by the virtual device + * every T milliseconds. + * + * Putting it all together, to get random bits from urandom and produce them at + * a rate of 1 Kbps with coarse (1/8 sec) timing granularity, one would add the + * following to your QEMU command line. + * + * -object rng-random,filename=/dev/urandom,id=rng0 + * -device virtio-rng-device,rng=rng0,max-bytes=16,period=125" + * + * One final note: You do not need to instantiate a device if you don't want + * to, but if you don't, and user code calls the hw_rng API in a blocking + * fashion (either via hw_rng_get_entropy or hw_rng_get_u32), it will hang. + * Non-blocking calls will always return 0 bytes. + */ + +#define LOCAL_TRACE 0 + +#define VIRTIO_RNG_VIRTQUEUE_ID 0u +#define VIRTIO_RNG_VIRTQUEUE_DESC_COUNT 2u + +#ifndef VIRTIO_RNG_ENTROPY_POOL_SIZE +#define VIRTIO_RNG_ENTROPY_POOL_SIZE 256 +#endif + +struct virtio_rng_device { + struct virtio_device *vio_dev; + cbuf_t entropy_pool_cbuf; + paddr_t entropy_pool_paddr; + bool fill_op_in_flight; + uint8_t entropy_pool[VIRTIO_RNG_ENTROPY_POOL_SIZE]; +}; + +static void virtio_rng_module_init(void); +static status_t virtio_rng_init(struct virtio_device *vio_dev, uint32_t host_features); + +VIRTIO_DEV_CLASS(rng, VIRTIO_DEV_ID_ENTROPY_SRC, virtio_rng_module_init, virtio_rng_init, NULL); + +static struct virtio_rng_device g_device; + +static void virtio_rng_fill_entropy_pool(struct virtio_rng_device *dev) { + // If we were never successfully bound to an underlying VirtIO device, then + // this is a no-op. + if (!dev->vio_dev) + return; + + // If there is space in the buffer, and there is not already a read + // operation in flight, start a new read op. + spin_lock_saved_state_t state; + spin_lock_irqsave(&dev->entropy_pool_cbuf.lock, state); + + if ((dev->fill_op_in_flight) || !cbuf_space_avail(&dev->entropy_pool_cbuf)) { + spin_unlock_irqrestore(&dev->entropy_pool_cbuf.lock, state); + return; + } + + dev->fill_op_in_flight = true; + spin_unlock_irqrestore(&dev->entropy_pool_cbuf.lock, state); + + // How much space do we need to fill up? + __UNUSED size_t to_fill; + iovec_t fill_regions[2]; + to_fill = cbuf_peek_write(&dev->entropy_pool_cbuf, fill_regions); + DEBUG_ASSERT(to_fill); + + // Grab a descriptor chain of appropriate length. + struct vring_desc* chain; + uint16_t chain_head; + size_t chain_len = fill_regions[1].iov_len ? 2 : 1; + + chain = virtio_alloc_desc_chain(dev->vio_dev, + VIRTIO_RNG_VIRTQUEUE_ID, + chain_len, + &chain_head); + DEBUG_ASSERT(chain); + + // Point the chain at the regions of the cbuf which need to be filled. + for (size_t i = 0; i < chain_len; ++i) { + if (i) { + DEBUG_ASSERT(chain->flags == (VRING_DESC_F_NEXT | VRING_DESC_F_WRITE)); + chain = virtio_desc_index_to_desc(dev->vio_dev, + VIRTIO_RNG_VIRTQUEUE_ID, + chain->next); + DEBUG_ASSERT(chain); + } + + size_t offset = (size_t)((intptr_t)fill_regions[i].iov_base - + (intptr_t)dev->entropy_pool); + + DEBUG_ASSERT(fill_regions[i].iov_base && fill_regions[i].iov_len); + DEBUG_ASSERT((offset < sizeof(dev->entropy_pool)) && + (fill_regions[i].iov_len <=(sizeof(dev->entropy_pool) - offset))); + + chain->addr = dev->entropy_pool_paddr + offset; + chain->len = fill_regions[i].iov_len; + chain->flags |= VRING_DESC_F_WRITE; + } + + DEBUG_ASSERT(chain->flags == VRING_DESC_F_WRITE); + + // Submit it and start the transfer + virtio_submit_chain(dev->vio_dev, VIRTIO_RNG_VIRTQUEUE_ID, chain_head); + virtio_kick(dev->vio_dev, VIRTIO_RNG_VIRTQUEUE_ID); +} + +static enum handler_return virtio_rng_irq(struct virtio_device *vio_dev, + uint virtqueue_id, + const struct vring_used_elem *used) { + struct virtio_rng_device* dev = (struct virtio_rng_device*)(vio_dev->priv); + + DEBUG_ASSERT(virtqueue_id == VIRTIO_RNG_VIRTQUEUE_ID); + DEBUG_ASSERT(used->len <= cbuf_space_avail(&dev->entropy_pool_cbuf)); + DEBUG_ASSERT(dev->fill_op_in_flight); + + // Give the chain back. + virtio_free_desc_chain(dev->vio_dev, VIRTIO_RNG_VIRTQUEUE_ID, used->id); + + // Advance the cbuf write pointer. + // TODO(johngro): invalidate the dcache for the region of the cbuf we just DMAed to. + cbuf_advance_write(&dev->entropy_pool_cbuf, used->len, false); + + // Flag the fact that this fill operation is no longer in flight. + dev->fill_op_in_flight = false; + smp_wmb(); + + // Schedule the next read, if needed. + virtio_rng_fill_entropy_pool(dev); + + return INT_RESCHEDULE; +} + +// VirtIO MMIO Driver API implementation +static void virtio_rng_module_init(void) +{ + struct virtio_rng_device* dev = &g_device; + + /* Set up our cbuf to use our entropy pool buffer */ + cbuf_initialize_etc(&dev->entropy_pool_cbuf, + sizeof(dev->entropy_pool), + dev->entropy_pool); +} + +static status_t virtio_rng_init(struct virtio_device *vio_dev, uint32_t host_features) +{ + struct virtio_rng_device* dev = &g_device; + + /* Already initialized? */ + if (dev->vio_dev) + return ERR_ALREADY_STARTED; + + /* Grab the physical address of the entropy pool buffer. */ +#if WITH_KERNEL_VM + dev->entropy_pool_paddr = vaddr_to_paddr(dev->entropy_pool); +#else + dev->entropy_pool_paddr = (paddr_t)dev->entropy_pool; +#endif + + /* Place the device in reset */ + virtio_reset_device(vio_dev); + + /* Let the device know that we see it, and know how to talk to it */ + virtio_status_acknowledge_driver(vio_dev); + + /* TODO(johngro): negotiate features */ + + /* Create out virtqueue */ + status_t res = virtio_alloc_ring(vio_dev, + VIRTIO_RNG_VIRTQUEUE_ID, + VIRTIO_RNG_VIRTQUEUE_DESC_COUNT); + if (res != NO_ERROR) { + LTRACEF("Failed to allocate virtqueue for VirtIO HW RNG (queue #%u, desc_count %u)\n", + VIRTIO_RNG_VIRTQUEUE_ID, VIRTIO_RNG_VIRTQUEUE_DESC_COUNT); + goto finished; + } + + /* Setup our callbacks */ + vio_dev->priv = dev; + vio_dev->irq_driver_callback = &virtio_rng_irq; + vio_dev->config_change_callback = NULL; + dev->vio_dev = vio_dev; + + /* Inform the device that we are ready to go. */ + virtio_status_driver_ok(vio_dev); + + /* Send out a transfer to fill up the entropy pool with tasty random bits */ + virtio_rng_fill_entropy_pool(dev); + +finished: + return res; +} + +// HW RNG API implementation +size_t hw_rng_get_entropy(void* buf, size_t len, bool block) { + if (!len) + return 0; + + DEBUG_ASSERT(buf); + + struct virtio_rng_device* dev = &g_device; + size_t done = 0; + + done = cbuf_read(&dev->entropy_pool_cbuf, buf, len, block); + virtio_rng_fill_entropy_pool(dev); // Make sure we are keeping the pool full + + if (block) { + while (done < len) { + done += cbuf_read(&dev->entropy_pool_cbuf, buf + done, len - done, true); + virtio_rng_fill_entropy_pool(dev); + } + } + + return done; +} diff --git a/kernel/dev/virtio/rules.mk b/kernel/dev/virtio/rules.mk new file mode 100644 index 000000000..321a67ee3 --- /dev/null +++ b/kernel/dev/virtio/rules.mk @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/virtio.c + +include make/module.mk diff --git a/kernel/dev/virtio/virtio.c b/kernel/dev/virtio/virtio.c new file mode 100644 index 000000000..15d9a3024 --- /dev/null +++ b/kernel/dev/virtio/virtio.c @@ -0,0 +1,376 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virtio_priv.h" + +#define LOCAL_TRACE 0 + +/* list of class drivers, declared with VIRTIO_DEV_CLASS() macro */ +extern const virtio_dev_class_t __start_virtio_classes[] __WEAK; +extern const virtio_dev_class_t __stop_virtio_classes[] __WEAK; + +static struct virtio_device *devices; + +static void dump_mmio_config(const volatile struct virtio_mmio_config *mmio) +{ + printf("mmio at %p\n", mmio); + printf("\tmagic 0x%x\n", mmio->magic); + printf("\tversion 0x%x\n", mmio->version); + printf("\tdevice_id 0x%x\n", mmio->device_id); + printf("\tvendor_id 0x%x\n", mmio->vendor_id); + printf("\thost_features 0x%x\n", mmio->host_features); + printf("\tguest_page_size %u\n", mmio->guest_page_size); + printf("\tqnum %u\n", mmio->queue_num); + printf("\tqnum_max %u\n", mmio->queue_num_max); + printf("\tqnum_align %u\n", mmio->queue_align); + printf("\tqnum_pfn %u\n", mmio->queue_pfn); + printf("\tstatus 0x%x\n", mmio->status); +} + +void virtio_dump_desc(const struct vring_desc *desc) +{ + printf("vring descriptor %p\n", desc); + printf("\taddr 0x%llx\n", desc->addr); + printf("\tlen 0x%x\n", desc->len); + printf("\tflags 0x%hhx\n", desc->flags); + printf("\tnext 0x%hhx\n", desc->next); +} + +static enum handler_return virtio_mmio_irq(void *arg) +{ + struct virtio_device *dev = (struct virtio_device *)arg; + LTRACEF("dev %p, index %u\n", dev, dev->index); + + uint32_t irq_status = dev->mmio_config->interrupt_status; + LTRACEF("status 0x%x\n", irq_status); + + enum handler_return ret = INT_NO_RESCHEDULE; + if (irq_status & 0x1) { /* used ring update */ + // XXX is this safe? + dev->mmio_config->interrupt_ack = 0x1; + + /* cycle through all the active rings */ + for (uint r = 0; r < MAX_VIRTIO_RINGS; r++) { + if ((dev->active_rings_bitmap & (1<ring[r]; + LTRACEF("ring %u: used flags 0x%hhx idx 0x%hhx last_used %u\n", r, ring->used->flags, ring->used->idx, ring->last_used); + + uint cur_idx = ring->used->idx; + for (uint i = ring->last_used; i != (cur_idx & ring->num_mask); i = (i + 1) & ring->num_mask) { + LTRACEF("looking at idx %u\n", i); + + // process chain + struct vring_used_elem *used_elem = &ring->used->ring[i]; + LTRACEF("id %u, len %u\n", used_elem->id, used_elem->len); + + DEBUG_ASSERT(dev->irq_driver_callback); + ret |= dev->irq_driver_callback(dev, r, used_elem); + + ring->last_used = (ring->last_used + 1) & ring->num_mask; + } + } + } + if (irq_status & 0x2) { /* config change */ + dev->mmio_config->interrupt_ack = 0x2; + + if (dev->config_change_callback) { + ret |= dev->config_change_callback(dev); + } + } + + LTRACEF("exiting irq\n"); + + return ret; +} + +int virtio_mmio_detect(void *ptr, uint count, const uint irqs[]) +{ + LTRACEF("ptr %p, count %u\n", ptr, count); + + DEBUG_ASSERT(ptr); + DEBUG_ASSERT(irqs); + DEBUG_ASSERT(!devices); + + /* allocate an array big enough to hold a list of devices */ + devices = calloc(count, sizeof(struct virtio_device)); + if (!devices) + return ERR_NO_MEMORY; + + int found = 0; + for (uint i = 0; i < count; i++) { + volatile struct virtio_mmio_config *mmio = (struct virtio_mmio_config *)((uint8_t *)ptr + i * 0x200); + struct virtio_device *dev = &devices[i]; + + dev->index = i; + dev->irq = irqs[i]; + + mask_interrupt(irqs[i]); + register_int_handler(irqs[i], &virtio_mmio_irq, (void *)dev); + + LTRACEF("looking at magic 0x%x version 0x%x did 0x%x vid 0x%x\n", + mmio->magic, mmio->version, mmio->device_id, mmio->vendor_id); + + if ((mmio->magic != VIRTIO_MMIO_MAGIC) || + (mmio->device_id == VIRTIO_DEV_ID_INVALID)) + continue; + +#if LOCAL_TRACE + dump_mmio_config(mmio); +#endif + const virtio_dev_class_t *class; + for (class = __start_virtio_classes; class != __stop_virtio_classes; class++) { + if (mmio->device_id != class->device_id) + continue; + + LTRACEF("found %s device\n", class->name); + dev->mmio_config = mmio; + dev->config_ptr = (void *)mmio->config; + + status_t err = class->init_fn(dev, mmio->host_features); + if (err >= 0) { + // good device + dev->valid = true; + + if (dev->irq_driver_callback) + unmask_interrupt(dev->irq); + + if (class->startup_fn) + class->startup_fn(dev); + } else { + LTRACEF("Failed to initialize VirtIO MMIO device id %u at position %u (err = %d)\n", + mmio->device_id, i, err); + + // indicate to the device that something went fatally wrong on the driver side. + dev->mmio_config->status |= VIRTIO_STATUS_FAILED; + } + + break; + } + + if (class == __stop_virtio_classes) { + TRACEF("Unrecognized VirtIO MMIO device id %u discovered at position %u\n", + mmio->device_id, i); + } + + if (dev->valid) + found++; + } + + return found; +} + +void virtio_free_desc(struct virtio_device *dev, uint ring_index, uint16_t desc_index) +{ + LTRACEF("dev %p ring %u index %u free_count %u\n", dev, ring_index, desc_index, dev->ring[ring_index].free_count); + dev->ring[ring_index].desc[desc_index].next = dev->ring[ring_index].free_list; + dev->ring[ring_index].free_list = desc_index; + dev->ring[ring_index].free_count++; +} + +void virtio_free_desc_chain(struct virtio_device *dev, uint ring_index, uint16_t chain_head) +{ + struct vring_desc* desc = virtio_desc_index_to_desc(dev, ring_index, chain_head); + + while (desc->flags & VRING_DESC_F_NEXT) { + uint16_t next = desc->next; + virtio_free_desc(dev, ring_index, chain_head); + chain_head = next; + desc = virtio_desc_index_to_desc(dev, ring_index, chain_head); + } + + virtio_free_desc(dev, ring_index, chain_head); +} + +uint16_t virtio_alloc_desc(struct virtio_device *dev, uint ring_index) +{ + if (dev->ring[ring_index].free_count == 0) + return 0xffff; + + DEBUG_ASSERT(dev->ring[ring_index].free_list != 0xffff); + + uint16_t i = dev->ring[ring_index].free_list; + struct vring_desc *desc = &dev->ring[ring_index].desc[i]; + dev->ring[ring_index].free_list = desc->next; + + dev->ring[ring_index].free_count--; + + return i; +} + +struct vring_desc *virtio_alloc_desc_chain(struct virtio_device *dev, uint ring_index, size_t count, uint16_t *start_index) +{ + if (dev->ring[ring_index].free_count < count) + return NULL; + + /* start popping entries off the chain */ + struct vring_desc *last = 0; + uint16_t last_index = 0; + while (count > 0) { + uint16_t i = dev->ring[ring_index].free_list; + struct vring_desc *desc = &dev->ring[ring_index].desc[i]; + + dev->ring[ring_index].free_list = desc->next; + dev->ring[ring_index].free_count--; + + if (last) { + desc->flags = VRING_DESC_F_NEXT; + desc->next = last_index; + } else { + // first one + desc->flags = 0; + desc->next = 0; + } + last = desc; + last_index = i; + count--; + } + + if (start_index) + *start_index = last_index; + + return last; +} + +void virtio_submit_chain(struct virtio_device *dev, uint ring_index, uint16_t desc_index) +{ + LTRACEF("dev %p, ring %u, desc %u\n", dev, ring_index, desc_index); + + /* add the chain to the available list */ + struct vring_avail *avail = dev->ring[ring_index].avail; + + avail->ring[avail->idx & dev->ring[ring_index].num_mask] = desc_index; + DSB; + avail->idx++; + +#if LOCAL_TRACE + hexdump(avail, 16); +#endif +} + +void virtio_kick(struct virtio_device *dev, uint ring_index) +{ + LTRACEF("dev %p, ring %u\n", dev, ring_index); + + dev->mmio_config->queue_notify = ring_index; + DSB; +} + +status_t virtio_alloc_ring(struct virtio_device *dev, uint index, uint16_t len) +{ + LTRACEF("dev %p, index %u, len %u\n", dev, index, len); + + DEBUG_ASSERT(dev); + DEBUG_ASSERT(len > 0 && ispow2(len)); + DEBUG_ASSERT(index < MAX_VIRTIO_RINGS); + + if (len == 0 || !ispow2(len)) + return ERR_INVALID_ARGS; + + struct vring *ring = &dev->ring[index]; + + /* allocate a ring */ + size_t size = vring_size(len, PAGE_SIZE); + LTRACEF("need %zu bytes\n", size); + +#if WITH_KERNEL_VM + void *vptr; + status_t err = vmm_alloc_contiguous(vmm_get_kernel_aspace(), "virtio_ring", size, &vptr, 0, VMM_FLAG_COMMIT, ARCH_MMU_FLAG_UNCACHED_DEVICE); + if (err < 0) + return ERR_NO_MEMORY; + + LTRACEF("allocated virtio_ring at va %p\n", vptr); + + /* compute the physical address */ + paddr_t pa; + pa = vaddr_to_paddr(vptr); + if (pa == 0) { + return ERR_NO_MEMORY; + } + + LTRACEF("virtio_ring at pa 0x%lx\n", pa); +#else + void *vptr = memalign(PAGE_SIZE, size); + if (!vptr) + return ERR_NO_MEMORY; + + LTRACEF("ptr %p\n", vptr); + memset(vptr, 0, size); + + /* compute the physical address */ + paddr_t pa = (paddr_t)vptr; +#endif + + /* initialize the ring */ + vring_init(ring, len, vptr, PAGE_SIZE); + dev->ring[index].free_list = 0xffff; + dev->ring[index].free_count = 0; + + /* add all the descriptors to the free list */ + for (uint i = 0; i < len; i++) { + virtio_free_desc(dev, index, i); + } + + /* register the ring with the device */ + DEBUG_ASSERT(dev->mmio_config); + dev->mmio_config->guest_page_size = PAGE_SIZE; + dev->mmio_config->queue_sel = index; + dev->mmio_config->queue_num = len; + dev->mmio_config->queue_align = PAGE_SIZE; + dev->mmio_config->queue_pfn = pa / PAGE_SIZE; + + /* mark the ring active */ + dev->active_rings_bitmap |= (1 << index); + + return NO_ERROR; +} + +void virtio_reset_device(struct virtio_device *dev) +{ + dev->mmio_config->status = 0; +} + +void virtio_status_acknowledge_driver(struct virtio_device *dev) +{ + dev->mmio_config->status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER; +} + +void virtio_status_driver_ok(struct virtio_device *dev) +{ + dev->mmio_config->status |= VIRTIO_STATUS_DRIVER_OK; +} + +void virtio_init(uint level) +{ + /* call all the class driver module init hooks */ + const virtio_dev_class_t *class; + for (class = __start_virtio_classes; class != __stop_virtio_classes; class++) { + if (class->module_init_fn) + class->module_init_fn(); + } +} + +LK_INIT_HOOK(virtio, &virtio_init, LK_INIT_LEVEL_THREADING); + diff --git a/kernel/dev/virtio/virtio_priv.h b/kernel/dev/virtio/virtio_priv.h new file mode 100644 index 000000000..c7f495082 --- /dev/null +++ b/kernel/dev/virtio/virtio_priv.h @@ -0,0 +1,50 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +struct virtio_mmio_config { + /* 0x00 */ uint32_t magic; + uint32_t version; + uint32_t device_id; + uint32_t vendor_id; + /* 0x10 */ uint32_t host_features; + uint32_t host_features_sel; + uint32_t __reserved0[2]; + /* 0x20 */ uint32_t guest_features; + uint32_t guest_features_sel; + uint32_t guest_page_size; + uint32_t __reserved1[1]; + /* 0x30 */ uint32_t queue_sel; + uint32_t queue_num_max; + uint32_t queue_num; + uint32_t queue_align; + /* 0x40 */ uint32_t queue_pfn; + uint32_t __reserved2[3]; + /* 0x50 */ uint32_t queue_notify; + uint32_t __reserved3[3]; + /* 0x60 */ uint32_t interrupt_status; + uint32_t interrupt_ack; + uint32_t __reserved4[2]; + /* 0x70 */ uint32_t status; + uint8_t __reserved5[0x8c]; + /* 0x100 */ uint32_t config[0]; +}; + +STATIC_ASSERT(sizeof(struct virtio_mmio_config) == 0x100); + +#define VIRTIO_MMIO_MAGIC 0x74726976 // 'virt' + +#define VIRTIO_STATUS_ACKNOWLEDGE (1<<0) +#define VIRTIO_STATUS_DRIVER (1<<1) +#define VIRTIO_STATUS_DRIVER_OK (1<<2) +#define VIRTIO_STATUS_FEATURES_OK (1<<3) +#define VIRTIO_STATUS_DEVICE_NEEDS_RESET (1<<6) +#define VIRTIO_STATUS_FAILED (1<<7) diff --git a/kernel/engine.mk b/kernel/engine.mk new file mode 100644 index 000000000..86a80569d --- /dev/null +++ b/kernel/engine.mk @@ -0,0 +1,357 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_MAKEFILE:=$(MAKEFILE_LIST) + +BUILDROOT ?= . + +ifeq ($(MAKECMDGOALS),spotless) +spotless: + rm -rf -- "$(BUILDROOT)"/build-* +else + +ifndef LKROOT +$(error please define LKROOT to the root of the lk build system) +endif + +-include local.mk +include make/macros.mk + +# If one of our goals (from the commandline) happens to have a +# matching project/goal.mk, then we should re-invoke make with +# that project name specified... + +project-name := $(firstword $(MAKECMDGOALS)) + +ifneq ($(project-name),) +ifneq ($(strip $(foreach d,$(LKINC),$(wildcard $(d)/project/$(project-name).mk))),) +do-nothing := 1 +$(MAKECMDGOALS) _all: make-make +make-make: + @PROJECT=$(project-name) $(MAKE) -rR -f $(LOCAL_MAKEFILE) $(filter-out $(project-name), $(MAKECMDGOALS)) + +.PHONY: make-make +endif +endif + +# some additional rules to print some help +include make/help.mk + +ifeq ($(do-nothing),) + +ifeq ($(PROJECT),) + +ifneq ($(DEFAULT_PROJECT),) +PROJECT := $(DEFAULT_PROJECT) +else +$(error No project specified. Use 'make list' for a list of projects or 'make help' for additional help) +endif +endif + +DEBUG ?= 2 + +BUILDDIR_SUFFIX ?= +BUILDDIR := $(BUILDROOT)/build-$(PROJECT)$(BUILDDIR_SUFFIX) +OUTLKBIN := $(BUILDDIR)/lk.bin +LKELF := lk.elf +OUTLKELF := $(BUILDDIR)/$(LKELF) +CONFIGHEADER := $(BUILDDIR)/config.h + +GLOBAL_INCLUDES := $(BUILDDIR) $(addsuffix /include,$(LKINC)) +GLOBAL_OPTFLAGS ?= $(ARCH_OPTFLAGS) +GLOBAL_COMPILEFLAGS := -g -finline -include $(CONFIGHEADER) +GLOBAL_COMPILEFLAGS += -Wall -Wextra -Wno-multichar -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Werror=return-type +ifeq ($(CLANG),1) +GLOBAL_COMPILEFLAGS += -Wno-error +endif +GLOBAL_CFLAGS := --std=c11 -Werror-implicit-function-declaration -Wstrict-prototypes -Wwrite-strings +# Note: Both -fno-exceptions and -fno-asynchronous-unwind-tables is needed +# in order to stop gcc from emitting .eh_frame (which is part of the loaded +# image by default). +GLOBAL_CPPFLAGS := --std=c++11 -fno-exceptions -fno-asynchronous-unwind-tables -fno-rtti -fno-threadsafe-statics -Wconversion +#GLOBAL_CPPFLAGS += -Weffc++ +GLOBAL_ASMFLAGS := -DASSEMBLY +GLOBAL_LDFLAGS := -nostdlib + +GLOBAL_LDFLAGS += $(addprefix -L,$(LKINC)) + +# Kernel compile flags +KERNEL_COMPILEFLAGS := -ffreestanding +KERNEL_CFLAGS := +KERNEL_CPPFLAGS := +KERNEL_ASMFLAGS := + +# User space compile flags +USER_COMPILEFLAGS := +USER_CFLAGS := +USER_CPPFLAGS := +KERUSER_ASMFLAGS := + +# Architecture specific compile flags +ARCH_COMPILEFLAGS := +ARCH_CFLAGS := +ARCH_CPPFLAGS := +ARCH_ASMFLAGS := + +# top level rule +all:: $(OUTLKBIN) $(OUTLKELF).lst $(OUTLKELF).debug.lst $(OUTLKELF).sym $(OUTLKELF).sym.sorted $(OUTLKELF).size $(OUTLKELF).dump $(OUTLKELF)-gdb.py + +# master module object list +ALLOBJS_MODULE := + +# master object list (for dep generation) +ALLOBJS := + +# master source file list +ALLSRCS := + +# a linker script needs to be declared in one of the project/target/platform files +LINKER_SCRIPT := + +# anything you add here will be deleted in make clean +GENERATED := $(CONFIGHEADER) + +# anything added to GLOBAL_DEFINES will be put into $(BUILDDIR)/config.h +GLOBAL_DEFINES := LK=1 + +# Anything added to GLOBAL_SRCDEPS will become a dependency of every source file in the system. +# Useful for header files that may be included by one or more source files. +GLOBAL_SRCDEPS := $(CONFIGHEADER) + +# these need to be filled out by the project/target/platform rules.mk files +TARGET := +PLATFORM := +ARCH := +ALLMODULES := + +# add any external module dependencies +MODULES := $(EXTERNAL_MODULES) + +# any .mk specified here will be included before build.mk +EXTRA_BUILDRULES := + +# any rules you put here will also be built by the system before considered being complete +EXTRA_BUILDDEPS := + +# any rules you put here will be depended on in clean builds +EXTRA_CLEANDEPS := + +# any objects you put here get linked with the final image +EXTRA_OBJS := + +# userspace apps to build and include in initfs +ALLUSER_APPS := + +# userspace app modules +ALLUSER_MODULES := + +USER_MANIFEST := $(BUILDDIR)/user.manifest +USER_MANIFEST_LINES := + +USER_BOOTFS := $(BUILDDIR)/user.bootfs +USER_FS := $(BUILDDIR)/user.fs + +# if someone defines this, the build id will be pulled into lib/version +BUILDID ?= + +# set V=1 in the environment if you want to see the full command line of every command +ifeq ($(V),1) +NOECHO := +else +NOECHO ?= @ +endif + +# try to include the project file +-include project/$(PROJECT).mk +ifndef TARGET +$(error couldn't find project or project doesn't define target) +endif +include target/$(TARGET)/rules.mk +ifndef PLATFORM +$(error couldn't find target or target doesn't define platform) +endif +include platform/$(PLATFORM)/rules.mk + +$(info PROJECT = $(PROJECT)) +$(info PLATFORM = $(PLATFORM)) +$(info TARGET = $(TARGET)) + +include arch/$(ARCH)/rules.mk +include top/rules.mk + +# recursively include any modules in the MODULE variable, leaving a trail of included +# modules in the ALLMODULES list +include make/recurse.mk + +# any extra top level build dependencies that someone declared +all:: $(EXTRA_BUILDDEPS) + +# make the build depend on all of the user apps +all:: $(foreach app,$(ALLUSER_APPS),$(app) $(app).lst $(app).dump $(app).strip) + + +# generate linkage dependencies for userspace apps after +# all modules have been evaluated, so we can recursively +# expand the module dependencies and handle cases like +# APP A depends on LIB B which depends on LIB C +# +# Duplicates are removed from the list with $(sort), which +# works due to how we're linking binaries now. If we shift +# to true .a files we'll need to get fancier here. +EXPAND_DEPS = $(1) $(foreach DEP,$(MODULE_$(1)_DEPS),$(call EXPAND_DEPS,$(DEP))) + +GET_USERAPP_DEPS = $(sort $(foreach DEP,$(MODULE_$(1)_DEPS),$(call EXPAND_DEPS,$(DEP)))) + +GET_USERAPP_LIBS = $(foreach DEP,$(call GET_USERAPP_DEPS,$(1)),$(call TOBUILDDIR,$(DEP).mod.o)) + +# NOTE: Uses :: rules to set deps on the app binary +# A rule in build.mk sets the final link line +LINK_USERAPP = $(eval $(1):: $(2))$(eval $(1): _LIBS := $(2)) + +$(foreach app,$(ALLUSER_MODULES),\ + $(eval $(call LINK_USERAPP,\ + $(call TOBUILDDIR,$(app).elf),\ + $(call GET_USERAPP_LIBS,$(app))))) + +# Generate a list of short module names (filtering out the LKINC roots) +# for use in generating the WITH_... symbols +LKPREFIXES := $(patsubst %,%/,$(filter-out .,$(LKINC))) +SHORTNAMES := $(ALLMODULES) +$(foreach pfx,$(LKPREFIXES),$(eval SHORTNAMES := $(patsubst $(pfx)%,%,$(SHORTNAMES)))) + +# add some automatic configuration defines +GLOBAL_DEFINES += \ + PROJECT_$(PROJECT)=1 \ + PROJECT=\"$(PROJECT)\" \ + TARGET_$(TARGET)=1 \ + TARGET=\"$(TARGET)\" \ + PLATFORM_$(PLATFORM)=1 \ + PLATFORM=\"$(PLATFORM)\" \ + ARCH_$(ARCH)=1 \ + ARCH=\"$(ARCH)\" \ + $(addsuffix =1,$(addprefix WITH_,$(SHORTNAMES))) + +# debug build? +ifneq ($(DEBUG),) +GLOBAL_DEFINES += \ + LK_DEBUGLEVEL=$(DEBUG) +endif + +# allow additional defines from outside the build system +ifneq ($(EXTERNAL_DEFINES),) +GLOBAL_DEFINES += $(EXTERNAL_DEFINES) +$(info EXTERNAL_DEFINES = $(EXTERNAL_DEFINES)) +endif + +# prefix all of the paths in GLOBAL_INCLUDES with -I +GLOBAL_INCLUDES := $(addprefix -I,$(GLOBAL_INCLUDES)) + +# test for some old variables +ifneq ($(INCLUDES),) +$(error INCLUDES variable set, please move to GLOBAL_INCLUDES: $(INCLUDES)) +endif +ifneq ($(DEFINES),) +$(error DEFINES variable set, please move to GLOBAL_DEFINES: $(DEFINES)) +endif + +# default to no ccache +CCACHE ?= +ifeq ($(CLANG),1) +CC := $(CCACHE) $(TOOLCHAIN_PREFIX)clang +else +CC := $(CCACHE) $(TOOLCHAIN_PREFIX)gcc +endif +LD := $(TOOLCHAIN_PREFIX)ld +AR := $(TOOLCHAIN_PREFIX)ar +OBJDUMP := $(TOOLCHAIN_PREFIX)objdump +OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy +CPPFILT := $(TOOLCHAIN_PREFIX)c++filt +SIZE := $(TOOLCHAIN_PREFIX)size +NM := $(TOOLCHAIN_PREFIX)nm +STRIP := $(TOOLCHAIN_PREFIX)strip + +# try to have the compiler output colorized error messages if available +export GCC_COLORS ?= 1 + +# the logic to compile and link stuff is in here +include make/build.mk + +DEPS := $(ALLOBJS:%o=%d) + +# put all of the global build flags in config.h to force a rebuild if any change +GLOBAL_DEFINES += GLOBAL_INCLUDES=\"$(subst $(SPACE),_,$(GLOBAL_INCLUDES))\" +GLOBAL_DEFINES += GLOBAL_COMPILEFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_COMPILEFLAGS))\" +GLOBAL_DEFINES += GLOBAL_OPTFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_OPTFLAGS))\" +GLOBAL_DEFINES += GLOBAL_CFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CFLAGS))\" +GLOBAL_DEFINES += GLOBAL_CPPFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CPPFLAGS))\" +GLOBAL_DEFINES += GLOBAL_ASMFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_ASMFLAGS))\" +GLOBAL_DEFINES += GLOBAL_LDFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_LDFLAGS))\" +GLOBAL_DEFINES += ARCH_COMPILEFLAGS=\"$(subst $(SPACE),_,$(ARCH_COMPILEFLAGS))\" +GLOBAL_DEFINES += ARCH_CFLAGS=\"$(subst $(SPACE),_,$(ARCH_CFLAGS))\" +GLOBAL_DEFINES += ARCH_CPPFLAGS=\"$(subst $(SPACE),_,$(ARCH_CPPFLAGS))\" +GLOBAL_DEFINES += ARCH_ASMFLAGS=\"$(subst $(SPACE),_,$(ARCH_ASMFLAGS))\" +GLOBAL_DEFINES += KERNEL_COMPILEFLAGS=\"$(subst $(SPACE),_,$(KERNEL_COMPILEFLAGS))\" +GLOBAL_DEFINES += KERNEL_CFLAGS=\"$(subst $(SPACE),_,$(KERNEL_CFLAGS))\" +GLOBAL_DEFINES += KERNEL_CPPFLAGS=\"$(subst $(SPACE),_,$(KERNEL_CPPFLAGS))\" +GLOBAL_DEFINES += KERNEL_ASMFLAGS=\"$(subst $(SPACE),_,$(KERNEL_ASMFLAGS))\" +GLOBAL_DEFINES += USER_COMPILEFLAGS=\"$(subst $(SPACE),_,$(USER_COMPILEFLAGS))\" +GLOBAL_DEFINES += USER_CFLAGS=\"$(subst $(SPACE),_,$(USER_CFLAGS))\" +GLOBAL_DEFINES += USER_CPPFLAGS=\"$(subst $(SPACE),_,$(USER_CPPFLAGS))\" +GLOBAL_DEFINES += USER_ASMFLAGS=\"$(subst $(SPACE),_,$(USER_ASMFLAGS))\" + +ifneq ($(OBJS),) +$(warning OBJS=$(OBJS)) +$(error OBJS is not empty, please convert to new module format) +endif +ifneq ($(OPTFLAGS),) +$(warning OPTFLAGS=$(OPTFLAGS)) +$(error OPTFLAGS is not empty, please use GLOBAL_OPTFLAGS or MODULE_OPTFLAGS) +endif +ifneq ($(CFLAGS),) +$(warning CFLAGS=$(CFLAGS)) +$(error CFLAGS is not empty, please use GLOBAL_CFLAGS or MODULE_CFLAGS) +endif +ifneq ($(CPPFLAGS),) +$(warning CPPFLAGS=$(CPPFLAGS)) +$(error CPPFLAGS is not empty, please use GLOBAL_CPPFLAGS or MODULE_CPPFLAGS) +endif + +#$(info LIBGCC = $(LIBGCC)) +#$(info GLOBAL_COMPILEFLAGS = $(GLOBAL_COMPILEFLAGS)) +#$(info GLOBAL_OPTFLAGS = $(GLOBAL_OPTFLAGS)) + +# make all object files depend on any targets in GLOBAL_SRCDEPS +$(ALLOBJS): $(GLOBAL_SRCDEPS) + +clean: $(EXTRA_CLEANDEPS) + rm -f $(ALLOBJS) + rm -f $(DEPS) + rm -f $(GENERATED) + rm -f $(OUTLKBIN) $(OUTLKELF) $(OUTLKELF).lst $(OUTLKELF).debug.lst $(OUTLKELF).sym $(OUTLKELF).sym.sorted $(OUTLKELF).size $(OUTLKELF).hex $(OUTLKELF).dump $(OUTLKELF)-gdb.py + rm -f $(foreach app,$(ALLUSER_APPS),$(app) $(app).lst $(app).dump $(app).strip) + +install: all + scp $(OUTLKBIN) 192.168.0.4:/tftproot + +# generate a config.h file with all of the GLOBAL_DEFINES laid out in #define format +configheader: + +$(CONFIGHEADER): configheader + @$(call MAKECONFIGHEADER,$@,GLOBAL_DEFINES) + +# Empty rule for the .d files. The above rules will build .d files as a side +# effect. Only works on gcc 3.x and above, however. +%.d: + +ifeq ($(filter $(MAKECMDGOALS), clean), ) +-include $(DEPS) +endif + +.PHONY: configheader +endif + +endif # make spotless diff --git a/kernel/include/app.h b/kernel/include/app.h new file mode 100644 index 000000000..f87526d69 --- /dev/null +++ b/kernel/include/app.h @@ -0,0 +1,44 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __APP_H +#define __APP_H + +#include +#include + +__BEGIN_CDECLS; + +/* app support api */ +void apps_init(void); /* one time setup */ + +/* app entry point */ +struct app_descriptor; +typedef void (*app_init)(const struct app_descriptor *); +typedef void (*app_entry)(const struct app_descriptor *, void *args); + +/* app startup flags */ +#define APP_FLAG_DONT_START_ON_BOOT 0x1 +#define APP_FLAG_CUSTOM_STACK_SIZE 0x2 + +/* each app needs to define one of these to define its startup conditions */ +struct app_descriptor { + const char *name; + app_init init; + app_entry entry; + unsigned int flags; + size_t stack_size; +}; + +#define APP_START(appname) const struct app_descriptor _app_##appname __ALIGNED(sizeof(void *)) __SECTION("apps") = { .name = #appname, + +#define APP_END }; + +__END_CDECLS; + +#endif + diff --git a/kernel/include/arch.h b/kernel/include/arch.h new file mode 100644 index 000000000..e3a250619 --- /dev/null +++ b/kernel/include/arch.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ARCH_H +#define __ARCH_H + +#include +#include + +__BEGIN_CDECLS + +void arch_early_init(void); +void arch_init(void); +void arch_quiesce(void); +void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) __NO_RETURN; +void arch_enter_uspace(vaddr_t entry_point, vaddr_t user_stack_top, void *thread_arg) __NO_RETURN; + +__END_CDECLS + +/* arch specific bits */ +#include + +#endif diff --git a/kernel/include/arch/mmu.h b/kernel/include/arch/mmu.h new file mode 100644 index 000000000..4ebb6084d --- /dev/null +++ b/kernel/include/arch/mmu.h @@ -0,0 +1,59 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +/* to bring in definition of arch_aspace */ +#include + +__BEGIN_CDECLS + +#define ARCH_MMU_FLAG_CACHED (0<<0) +#define ARCH_MMU_FLAG_UNCACHED (1<<0) +#define ARCH_MMU_FLAG_UNCACHED_DEVICE (2<<0) /* only exists on some arches, otherwise UNCACHED */ +#define ARCH_MMU_FLAG_WRITE_COMBINING (3<<0) /* only exists on some arches, otherwise UNCACHED */ +#define ARCH_MMU_FLAG_CACHE_MASK (3<<0) + +#define ARCH_MMU_FLAG_PERM_USER (1<<2) +#define ARCH_MMU_FLAG_PERM_RO (1<<3) +#define ARCH_MMU_FLAG_PERM_NO_EXECUTE (1<<4) +#define ARCH_MMU_FLAG_NS (1<<5) /* NON-SECURE */ +#define ARCH_MMU_FLAG_INVALID (1<<6) /* indicates that flags are not specified */ + +/* forward declare the per-address space arch-specific context object */ +typedef struct arch_aspace arch_aspace_t; + +#define ARCH_ASPACE_FLAG_KERNEL (1<<0) + +/* initialize per address space */ +status_t arch_mmu_init_aspace(arch_aspace_t *aspace, vaddr_t base, size_t size, uint flags) __NONNULL((1)); +status_t arch_mmu_destroy_aspace(arch_aspace_t *aspace) __NONNULL((1)); + +/* routines to map/unmap/update permissions/query mappings per address space */ +int arch_mmu_map(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t paddr, size_t count, uint flags) __NONNULL((1)); +int arch_mmu_unmap(arch_aspace_t *aspace, vaddr_t vaddr, size_t count) __NONNULL((1)); +int arch_mmu_protect(arch_aspace_t *aspace, vaddr_t vaddr, size_t count, uint flags) __NONNULL((1)); +status_t arch_mmu_query(arch_aspace_t *aspace, vaddr_t vaddr, paddr_t *paddr, uint *flags) __NONNULL((1)); + +vaddr_t arch_mmu_pick_spot(arch_aspace_t *aspace, + vaddr_t base, uint prev_region_arch_mmu_flags, + vaddr_t end, uint next_region_arch_mmu_flags, + vaddr_t align, size_t size, uint arch_mmu_flags) __NONNULL((1)); + +/* load a new user address space context. + * aspace argument NULL should unload user space. + */ +void arch_mmu_context_switch(arch_aspace_t *old_aspace, arch_aspace_t *aspace); + +void arch_disable_mmu(void); + +__END_CDECLS + diff --git a/kernel/include/arch/mp.h b/kernel/include/arch/mp.h new file mode 100644 index 000000000..6e7d61c4a --- /dev/null +++ b/kernel/include/arch/mp.h @@ -0,0 +1,16 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +/* send inter processor interrupt, if supported */ +status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi); + +void arch_mp_init_percpu(void); diff --git a/kernel/include/arch/ops.h b/kernel/include/arch/ops.h new file mode 100644 index 000000000..1bcd41584 --- /dev/null +++ b/kernel/include/arch/ops.h @@ -0,0 +1,150 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* #defines for the cache routines below */ +#define ICACHE 1 +#define DCACHE 2 +#define UCACHE (ICACHE|DCACHE) + +#ifndef ASSEMBLY + +#include +#include +#include +#include + +__BEGIN_CDECLS + +/* fast routines that most arches will implement inline */ +static void arch_enable_ints(void); +static void arch_disable_ints(void); +static bool arch_ints_disabled(void); +static bool arch_in_int_handler(void); + +static int atomic_swap(volatile int *ptr, int val); +static int atomic_add(volatile int *ptr, int val); +static int atomic_and(volatile int *ptr, int val); +static int atomic_or(volatile int *ptr, int val); +static bool atomic_cmpxchg(volatile int *ptr, int *oldval, int newval); +static int atomic_load(volatile int *ptr); +static void atomic_store(volatile int *ptr, int newval); + +static uint32_t arch_cycle_count(void); + +static uint arch_curr_cpu_num(void); +static uint arch_max_num_cpus(void); + +/* Use to align structures on cache lines to avoid cpu aliasing. */ +#define __CPU_ALIGN __ALIGNED(CACHE_LINE) + +void arch_disable_cache(uint flags); +void arch_enable_cache(uint flags); + +void arch_clean_cache_range(addr_t start, size_t len); +void arch_clean_invalidate_cache_range(addr_t start, size_t len); +void arch_invalidate_cache_range(addr_t start, size_t len); +void arch_sync_cache_range(addr_t start, size_t len); + +void arch_idle(void); + +/* function to call in spinloops to idle */ +static void arch_spinloop_pause(void); +/* function to call when an event happens that may trigger the exit from + * a spinloop */ +static void arch_spinloop_signal(void); + +/* give the specific arch a chance to override some routines */ +#include + +/* if the arch specific code doesn't override these, implement + * atomics with compiler builtins. + */ +#if !ARCH_IMPLEMENTS_ATOMICS + +/* strongly ordered versions of the atomic routines as implemented + * by the compiler with arch-dependent memory barriers. + */ +static inline int atomic_swap(volatile int *ptr, int val) +{ + return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST); +} + +static inline int atomic_add(volatile int *ptr, int val) +{ + return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST); +} + +static inline int atomic_and(volatile int *ptr, int val) +{ + return __atomic_fetch_and(ptr, val, __ATOMIC_SEQ_CST); +} + +static inline int atomic_or(volatile int *ptr, int val) +{ + return __atomic_fetch_or(ptr, val, __ATOMIC_SEQ_CST); +} + +static inline bool atomic_cmpxchg(volatile int *ptr, int *oldval, int newval) +{ + return __atomic_compare_exchange_n(ptr, oldval, newval, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +static inline int atomic_load(volatile int *ptr) +{ + return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); +} + +static inline void atomic_store(volatile int *ptr, int newval) +{ + __atomic_store_n(ptr, newval, __ATOMIC_SEQ_CST); +} + +/* relaxed versions of the above */ +static inline int atomic_swap_relaxed(volatile int *ptr, int val) +{ + return __atomic_exchange_n(ptr, val, __ATOMIC_RELAXED); +} + +static inline int atomic_add_relaxed(volatile int *ptr, int val) +{ + return __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED); +} + +static inline int atomic_and_relaxed(volatile int *ptr, int val) +{ + return __atomic_fetch_and(ptr, val, __ATOMIC_RELAXED); +} + +static inline int atomic_or_relaxed(volatile int *ptr, int val) +{ + return __atomic_fetch_or(ptr, val, __ATOMIC_RELAXED); +} + +static inline bool atomic_cmpxchg_relaxed(volatile int *ptr, int *oldval, int newval) +{ + return __atomic_compare_exchange_n(ptr, oldval, newval, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static int atomic_load_relaxed(volatile int *ptr) +{ + return __atomic_load_n(ptr, __ATOMIC_RELAXED); +} + +static void atomic_store_relaxed(volatile int *ptr, int newval) +{ + __atomic_store_n(ptr, newval, __ATOMIC_RELAXED); +} + +#endif + +__END_CDECLS + +#endif // !ASSEMBLY diff --git a/kernel/include/arch/thread.h b/kernel/include/arch/thread.h new file mode 100644 index 000000000..6150ab707 --- /dev/null +++ b/kernel/include/arch/thread.h @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ARCH_THREAD_H +#define __ARCH_THREAD_H + +// give the arch code a chance to declare the arch_thread struct +#include + +struct thread; + +void arch_thread_initialize(struct thread *, vaddr_t entry_point); +void arch_context_switch(struct thread *oldthread, struct thread *newthread); + +#endif diff --git a/kernel/include/arch/user_copy.h b/kernel/include/arch/user_copy.h new file mode 100644 index 000000000..0296e3bd8 --- /dev/null +++ b/kernel/include/arch/user_copy.h @@ -0,0 +1,42 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +/* + * @brief Copy data from userspace into kernelspace + * + * This function validates that usermode has access to src before copying the + * data. + * + * @param dst The destination buffer. + * @param src The source buffer. + * @param len The number of bytes to copy. + * + * @return NO_ERROR on success + */ +status_t arch_copy_from_user(void *dst, const void *src, size_t len); + +/* + * @brief Copy data from kernelspace into userspace + * + * This function validates that usermode has access to dst before copying the + * data. + * + * @param dst The destination buffer. + * @param src The source buffer. + * @param len The number of bytes to copy. + * + * @return NO_ERROR on success + */ +status_t arch_copy_to_user(void *dst, const void *src, size_t len); + +__END_CDECLS diff --git a/kernel/include/asm.h b/kernel/include/asm.h new file mode 100644 index 000000000..0b70888cf --- /dev/null +++ b/kernel/include/asm.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ASM_H +#define __ASM_H + +#define FUNCTION(x) .global x; .type x,STT_FUNC; x: +#define DATA(x) .global x; .type x,STT_OBJECT; x: + +#define LOCAL_FUNCTION(x) .type x,STT_FUNC; x: +#define LOCAL_DATA(x) .type x,STT_OBJECT; x: + +#define END(x) .size x, . - x + +#endif + diff --git a/kernel/include/bits.h b/kernel/include/bits.h new file mode 100644 index 000000000..c4fd7f0bf --- /dev/null +++ b/kernel/include/bits.h @@ -0,0 +1,108 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __BITS_H +#define __BITS_H + +#include +#include + +__BEGIN_CDECLS; + +#define clz(x) __builtin_clz(x) +#define ctz(x) __builtin_ctz(x) + +#define BIT(x, bit) ((x) & (1UL << (bit))) +#define BIT_SHIFT(x, bit) (((x) >> (bit)) & 1) +#define BITS(x, high, low) ((x) & (((1UL<<((high)+1))-1) & ~((1UL<<(low))-1))) +#define BITS_SHIFT(x, high, low) (((x) >> (low)) & ((1UL<<((high)-(low)+1))-1)) +#define BIT_SET(x, bit) (((x) & (1UL << (bit))) ? 1 : 0) + +#define BITMAP_BITS_PER_WORD (sizeof(unsigned long) * 8) +#define BITMAP_NUM_WORDS(x) (((x) + BITMAP_BITS_PER_WORD - 1) / BITMAP_BITS_PER_WORD) +#define BITMAP_WORD(x) ((x) / BITMAP_BITS_PER_WORD) +#define BITMAP_BIT_IN_WORD(x) ((x) & (BITMAP_BITS_PER_WORD - 1)) + +#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITMAP_BITS_PER_WORD)) +#define BITMAP_LAST_WORD_MASK(nbits) (((nbits) % BITMAP_BITS_PER_WORD) ? (1UL<<((nbits) % BITMAP_BITS_PER_WORD))-1 : ~0UL) + +#define BITMAP_BITS_PER_INT (sizeof(unsigned int) * 8) +#define BITMAP_BIT_IN_INT(x) ((x) & (BITMAP_BITS_PER_INT - 1)) +#define BITMAP_INT(x) ((x) / BITMAP_BITS_PER_INT) + +#define BIT_MASK(x) (((x) >= sizeof(unsigned long) * 8) ? (0UL-1) : ((1UL << (x)) - 1)) + +static inline void bitmap_set(unsigned long *bitmap, int start, int nr) +{ + unsigned long *p = bitmap + BITMAP_WORD(start); + const long size = start + nr; + int bits_to_set = BITMAP_BITS_PER_WORD - (start % BITMAP_BITS_PER_WORD); + unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); + + while (nr - bits_to_set >= 0) { + *p |= mask_to_set; + nr -= bits_to_set; + bits_to_set = BITMAP_BITS_PER_WORD; + mask_to_set = ~0UL; + p++; + } + if (nr) { + mask_to_set &= BITMAP_LAST_WORD_MASK(size); + *p |= mask_to_set; + } +} + +static inline void bitmap_clear(unsigned long *bitmap, int start, int nr) +{ + unsigned long *p = bitmap + BITMAP_WORD(start); + const long size = start + nr; + int bits_to_clear = BITMAP_BITS_PER_WORD - (start % BITMAP_BITS_PER_WORD); + unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); + + while (nr - bits_to_clear >= 0) { + *p &= ~mask_to_clear; + nr -= bits_to_clear; + bits_to_clear = BITMAP_BITS_PER_WORD; + mask_to_clear = ~0UL; + p++; + } + if (nr) { + mask_to_clear &= BITMAP_LAST_WORD_MASK(size); + *p &= ~mask_to_clear; + } +} + +static inline int bitmap_test(unsigned long *bitmap, int bit) +{ + return BIT_SET(bitmap[BITMAP_WORD(bit)], BITMAP_BIT_IN_WORD(bit)); +} + +/* find first zero bit starting from LSB */ +static inline unsigned long _ffz(unsigned long x) +{ + return __builtin_ffsl(~x) - 1; +} + +static inline int bitmap_ffz(unsigned long *bitmap, int numbits) +{ + uint i; + int bit; + + for (i = 0; i < BITMAP_NUM_WORDS(numbits); i++) { + if (bitmap[i] == ~0UL) + continue; + bit = i * BITMAP_BITS_PER_WORD + _ffz(bitmap[i]); + if (bit < numbits) + return bit; + return -1; + } + return -1; +} + +__END_CDECLS; + +#endif diff --git a/kernel/include/compiler.h b/kernel/include/compiler.h new file mode 100644 index 000000000..dcead332b --- /dev/null +++ b/kernel/include/compiler.h @@ -0,0 +1,159 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __COMPILER_H +#define __COMPILER_H + +#ifndef __ASSEMBLY__ + +#if __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define __UNUSED __attribute__((__unused__)) +#define __PACKED __attribute__((packed)) +#define __ALIGNED(x) __attribute__((aligned(x))) +#define __PRINTFLIKE(__fmt,__varargs) __attribute__((__format__ (__printf__, __fmt, __varargs))) +#define __SCANFLIKE(__fmt,__varargs) __attribute__((__format__ (__scanf__, __fmt, __varargs))) +#define __SECTION(x) __attribute((section(x))) +#define __PURE __attribute((pure)) +#define __CONST __attribute((const)) +#define __NO_RETURN __attribute__((noreturn)) +#define __MALLOC __attribute__((malloc)) +#define __WEAK __attribute__((weak)) +#define __GNU_INLINE __attribute__((gnu_inline)) +#define __GET_CALLER(x) __builtin_return_address(0) +#define __GET_FRAME(x) __builtin_frame_address(0) +#define __NAKED __attribute__((naked)) +#define __ISCONSTANT(x) __builtin_constant_p(x) +#define __NO_INLINE __attribute((noinline)) +#define __SRAM __NO_INLINE __SECTION(".sram.text") +#define __CONSTRUCTOR __attribute__((constructor)) +#define __DESTRUCTOR __attribute__((destructor)) +#ifndef __clang__ +#define __OPTIMIZE(x) __attribute__((optimize(x))) +#else +#define __OPTIMIZE(x) +#endif + +#define INCBIN(symname, sizename, filename, section) \ + __asm__ (".section " section "; .align 4; .globl "#symname); \ + __asm__ (""#symname ":\n.incbin \"" filename "\""); \ + __asm__ (".section " section "; .align 1;"); \ + __asm__ (""#symname "_end:"); \ + __asm__ (".section " section "; .align 4; .globl "#sizename); \ + __asm__ (""#sizename ": .long "#symname "_end - "#symname " - 1"); \ + extern unsigned char symname[]; \ + extern unsigned int sizename + +#define INCFILE(symname, sizename, filename) INCBIN(symname, sizename, filename, ".rodata") + +/* look for gcc 3.0 and above */ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 0) +#define __ALWAYS_INLINE __attribute__((always_inline)) +#else +#define __ALWAYS_INLINE +#endif + +/* look for gcc 3.1 and above */ +#if !defined(__DEPRECATED) // seems to be built in in some versions of the compiler +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define __DEPRECATED __attribute((deprecated)) +#else +#define __DEPRECATED +#endif +#endif + +/* look for gcc 3.3 and above */ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +/* the may_alias attribute was introduced in gcc 3.3; before that, there + * was no way to specify aliasiang rules on a type-by-type basis */ +#define __MAY_ALIAS __attribute__((may_alias)) + +/* nonnull was added in gcc 3.3 as well */ +#define __NONNULL(x) __attribute((nonnull x)) +#else +#define __MAY_ALIAS +#define __NONNULL(x) +#endif + +/* look for gcc 3.4 and above */ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __WARN_UNUSED_RESULT __attribute((warn_unused_result)) +#else +#define __WARN_UNUSED_RESULT +#endif + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) && !defined(__clang__) +#define __EXTERNALLY_VISIBLE __attribute__((externally_visible)) +#else +#define __EXTERNALLY_VISIBLE +#endif + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) || defined(__clang__) +#define __UNREACHABLE __builtin_unreachable() +#else +#define __UNREACHABLE +#endif + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || defined(__clang__) +#ifdef __cplusplus +#define STATIC_ASSERT(e) static_assert(e, #e) +#else +#define STATIC_ASSERT(e) _Static_assert(e, #e) +#endif +#else +#define STATIC_ASSERT(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] +#endif + +/* compiler fence */ +#define CF do { __asm__ volatile("" ::: "memory"); } while(0) + +#define __WEAK_ALIAS(x) __attribute__((weak, alias(x))) +#define __ALIAS(x) __attribute__((alias(x))) + +#define __EXPORT __attribute__ ((visibility("default"))) +#define __LOCAL __attribute__ ((visibility("hidden"))) + +#define __THREAD __thread + +#define __offsetof(type, field) __builtin_offsetof(type, field) + +#else + +#define likely(x) (x) +#define unlikely(x) (x) +#define __UNUSED +#define __PACKED +#define __ALIGNED(x) +#define __PRINTFLIKE(__fmt,__varargs) +#define __SCANFLIKE(__fmt,__varargs) +#define __SECTION(x) +#define __PURE +#define __CONST +#define __NONNULL(x) +#define __DEPRECATED +#define __WARN_UNUSED_RESULT +#define __ALWAYS_INLINE +#define __MAY_ALIAS +#define __NO_RETURN +#endif + +#endif + +/* TODO: add type check */ +#define countof(a) (sizeof(a) / sizeof((a)[0])) + +/* CPP header guards */ +#ifdef __cplusplus +#define __BEGIN_CDECLS extern "C" { +#define __END_CDECLS } +#else +#define __BEGIN_CDECLS +#define __END_CDECLS +#endif + +#endif diff --git a/kernel/include/debug.h b/kernel/include/debug.h new file mode 100644 index 000000000..0151f7e3f --- /dev/null +++ b/kernel/include/debug.h @@ -0,0 +1,77 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +#if !defined(LK_DEBUGLEVEL) +#define LK_DEBUGLEVEL 0 +#endif + +#if LK_DEBUGLEVEL > 0 +#define LK_DEBUG_BUILD 1 +#else +#undef LK_DEBUG_BUILD +#endif + +/* debug levels */ +#define CRITICAL 0 +#define ALWAYS 0 +#define INFO 1 +#define SPEW 2 + +__BEGIN_CDECLS + +#if !DISABLE_DEBUG_OUTPUT + +/* Obtain the panic file descriptor. */ +FILE *get_panic_fd(void); + +/* dump memory */ +void hexdump_ex(const void *ptr, size_t len, uint64_t disp_addr_start); +void hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr_start); + +#else + +/* Obtain the panic file descriptor. */ +static inline FILE *get_panic_fd(void) { return NULL; } + +/* dump memory */ +static inline void hexdump_ex(const void *ptr, size_t len, uint64_t disp_addr_start) { } +static inline void hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr_start) { } + +#endif /* DISABLE_DEBUG_OUTPUT */ + +static inline void hexdump(const void *ptr, size_t len) +{ + hexdump_ex(ptr, len, (uint64_t)((addr_t)ptr)); +} + +static inline void hexdump8(const void *ptr, size_t len) +{ + hexdump8_ex(ptr, len, (uint64_t)((addr_t)ptr)); +} + +#define dprintf(level, x...) do { if ((level) <= LK_DEBUGLEVEL) { printf(x); } } while (0) + +/* systemwide halts */ +void _panic(void *caller, const char *fmt, ...) __PRINTFLIKE(2, 3) __NO_RETURN; +#define panic(x...) _panic(__GET_CALLER(), x) + +#define PANIC_UNIMPLEMENTED panic("%s unimplemented\n", __PRETTY_FUNCTION__) + +/* spin the cpu for a period of (short) time */ +void spin(uint32_t usecs); + +/* spin the cpu for a certain number of cpu cycles */ +void spin_cycles(uint32_t usecs); + +__END_CDECLS diff --git a/kernel/include/dev/accelerometer.h b/kernel/include/dev/accelerometer.h new file mode 100644 index 000000000..b8fab32ae --- /dev/null +++ b/kernel/include/dev/accelerometer.h @@ -0,0 +1,18 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Eric Holland +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_ACCELEROMETER_H +#define __DEV_ACCELEROMETER_H +typedef struct { + double x; + double y; + double z; +} position_vector_t; + +status_t acc_read_xyz(position_vector_t *pos_vector); + +#endif diff --git a/kernel/include/dev/class/block.h b/kernel/include/dev/class/block.h new file mode 100644 index 000000000..48479a396 --- /dev/null +++ b/kernel/include/dev/class/block.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_CLASS_BLOCK_H +#define __DEV_CLASS_BLOCK_H + +#include +#include + +/* block interface */ +struct block_ops { + struct driver_ops std; + + ssize_t (*get_block_size)(struct device *dev); + ssize_t (*get_block_count)(struct device *dev); + + ssize_t (*write)(struct device *dev, off_t offset, const void *buf, size_t count); + ssize_t (*read)(struct device *dev, off_t offset, void *buf, size_t count); + + status_t (*flush)(struct device *dev); +}; + +__BEGIN_CDECLS + +ssize_t class_block_get_size(struct device *dev); +ssize_t class_block_get_count(struct device *dev); +ssize_t class_block_write(struct device *dev, off_t offset, const void *buf, size_t count); +ssize_t class_block_read(struct device *dev, off_t offset, void *buf, size_t count); +status_t class_block_flush(struct device *dev); + +__END_CDECLS + +#endif + diff --git a/kernel/include/dev/class/fb.h b/kernel/include/dev/class/fb.h new file mode 100644 index 000000000..025a8b00b --- /dev/null +++ b/kernel/include/dev/class/fb.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_CLASS_FB_H +#define __DEV_CLASS_FB_H + +#include +#include + +struct fb_info { + void *addr; + size_t line_width; + size_t width; + size_t height; + size_t bpp; +}; + +/* fb interface */ +struct fb_ops { + struct driver_ops std; + + status_t (*set_mode)(struct device *dev, size_t width, size_t height, size_t bpp); + status_t (*get_info)(struct device *dev, struct fb_info *info); + status_t (*update)(struct device *dev); + status_t (*update_region)(struct device *dev, size_t x, size_t y, size_t width, size_t height); +}; + +__BEGIN_CDECLS + +status_t class_fb_set_mode(struct device *dev, size_t width, size_t height, size_t bpp); +status_t class_fb_get_info(struct device *dev, struct fb_info *info); +status_t class_fb_update(struct device *dev); +status_t class_fb_update_region(struct device *dev, size_t x, size_t y, size_t width, size_t height); + +__END_CDECLS + +#endif + + diff --git a/kernel/include/dev/class/i2c.h b/kernel/include/dev/class/i2c.h new file mode 100644 index 000000000..876402079 --- /dev/null +++ b/kernel/include/dev/class/i2c.h @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_CLASS_I2C_H +#define __DEV_CLASS_I2C_H + +#include +#include + +/* i2c interface */ +struct i2c_ops { + struct driver_ops std; + + status_t (*write)(struct device *dev, uint8_t addr, const void *buf, size_t len); + status_t (*read)(struct device *dev, uint8_t addr, void *buf, size_t len); + + status_t (*write_reg)(struct device *dev, uint8_t addr, uint8_t reg, uint8_t value); + status_t (*read_reg)(struct device *dev, uint8_t addr, uint8_t reg, void *value); +}; + +__BEGIN_CDECLS + +status_t class_i2c_write(struct device *dev, uint8_t addr, const void *buf, size_t len); +status_t class_i2c_read(struct device *dev, uint8_t addr, void *buf, size_t len); +status_t class_i2c_write_reg(struct device *dev, uint8_t addr, uint8_t reg, uint8_t value); +status_t class_i2c_read_reg(struct device *dev, uint8_t addr, uint8_t reg, void *value); + +__END_CDECLS + +#endif diff --git a/kernel/include/dev/class/netif.h b/kernel/include/dev/class/netif.h new file mode 100644 index 000000000..f42b107ca --- /dev/null +++ b/kernel/include/dev/class/netif.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_CLASS_NETIF_H +#define __DEV_CLASS_NETIF_H + +#include +#include +#include + +struct netstack_state; +struct pbuf; + +/* netif interface */ +struct netif_ops { + struct driver_ops std; + + status_t (*set_state)(struct device *dev, struct netstack_state *state); + ssize_t (*get_hwaddr)(struct device *dev, void *buf, size_t max_len); + ssize_t (*get_mtu)(struct device *dev); + + status_t (*set_status)(struct device *dev, bool up); + status_t (*output)(struct device *dev, struct pbuf *p); + status_t (*mcast_filter)(struct device *dev, const uint8_t *mac, int action); +}; + +__BEGIN_CDECLS + +/* netif API */ +status_t class_netif_set_state(struct device *dev, struct netstack_state *state); +ssize_t class_netif_get_hwaddr(struct device *dev, void *buf, size_t max_len); +ssize_t class_netif_get_mtu(struct device *dev); +status_t class_netif_set_status(struct device *dev, bool up); +status_t class_netif_output(struct device *dev, struct pbuf *p); +status_t class_netif_mcast_filter(struct device *dev, const uint8_t *mac, int action); + +status_t class_netif_add(struct device *dev); + +/* network stack API - called by drivers */ +status_t class_netstack_input(struct device *dev, struct netstack_state *state, struct pbuf *p); + +status_t class_netstack_wait_for_network(lk_time_t timeout); + +__END_CDECLS + +#endif + diff --git a/kernel/include/dev/class/spi.h b/kernel/include/dev/class/spi.h new file mode 100644 index 000000000..8d467f764 --- /dev/null +++ b/kernel/include/dev/class/spi.h @@ -0,0 +1,44 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_CLASS_SPI_H +#define __DEV_CLASS_SPI_H + +#include +#include + +/* spi transaction flags */ +enum spi_flags { + SPI_READ = (1<<0), + SPI_WRITE = (1<<1), + SPI_CS_ASSERT = (1<<2), + SPI_CS_DEASSERT = (1<<3), +}; + +/* spi transaction */ +struct spi_transaction { + enum spi_flags flags; + void *tx_buf; + void *rx_buf; + size_t len; +}; + +/* spi interface */ +struct spi_ops { + struct driver_ops std; + + ssize_t (*transaction)(struct device *dev, struct spi_transaction *txn, size_t count); +}; + +__BEGIN_CDECLS + +ssize_t class_spi_transaction(struct device *dev, struct spi_transaction *txn, size_t count); + +__END_CDECLS + +#endif + diff --git a/kernel/include/dev/class/uart.h b/kernel/include/dev/class/uart.h new file mode 100644 index 000000000..dad2e923f --- /dev/null +++ b/kernel/include/dev/class/uart.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_CLASS_UART_H +#define __DEV_CLASS_UART_H + +#include + +/* uart interface */ +struct uart_ops { + struct driver_ops std; + + ssize_t (*read)(struct device *dev, void *buf, size_t len); + ssize_t (*write)(struct device *dev, const void *buf, size_t len); +}; + + +ssize_t class_uart_read(struct device *dev, void *buf, size_t len); +ssize_t class_uart_write(struct device *dev, const void *buf, size_t len); + +#endif + diff --git a/kernel/include/dev/display.h b/kernel/include/dev/display.h new file mode 100644 index 000000000..dec2dee50 --- /dev/null +++ b/kernel/include/dev/display.h @@ -0,0 +1,48 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_DISPLAY_H +#define __DEV_DISPLAY_H + +#include +#include +#include + +int display_init(void *framebuffer); +int display_enable(bool enable); +void display_pre_freq_change(void); +void display_post_freq_change(void); + +#define DISPLAY_FORMAT_NONE (-1) +#define DISPLAY_FORMAT_RGB_565 (0) +#define DISPLAY_FORMAT_RGB_332 (1) +#define DISPLAY_FORMAT_RGB_2220 (2) +#define DISPLAY_FORMAT_ARGB_8888 (3) +#define DISPLAY_FORMAT_RGB_x888 (4) +#define DISPLAY_FORMAT_MONO_1 (5) +#define DISPLAY_FORMAT_MONO_8 (6) + +#define DISPLAY_FLAG_HW_FRAMEBUFFER (1<<0) +#define DISPLAY_FLAG_NEEDS_CACHE_FLUSH (1<<1) + +struct display_info { + void *framebuffer; + int format; + uint width; + uint height; + uint stride; + + uint32_t flags; + + // Update function + void (*flush)(uint starty, uint endy); +}; + +status_t display_get_info(struct display_info *info); + +#endif + diff --git a/kernel/include/dev/driver.h b/kernel/include/dev/driver.h new file mode 100644 index 000000000..f1062dea1 --- /dev/null +++ b/kernel/include/dev/driver.h @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include // for containerof +#include + +__BEGIN_CDECLS + +struct driver; + +/* + * Contains the data pertaining to an instance of a device. More than one + * instance may exist for a given driver type (i.e. uart0, uart1, etc..). + */ +struct device { + const char *name; + const struct driver *driver; + + /* instance specific config data populated at instantiation */ + const void *config; + + /* instance specific data populated by the driver at init */ + void *state; + + // TODO: add generic state, such as suspend/resume state, etc... +}; + +/* device class, mainly used as a unique magic pointer to validate ops */ +struct device_class { + const char *name; +}; + +/* standard driver ops; extensions should contain this ops structure */ +struct driver_ops { + const struct device_class *device_class; + + status_t (*init)(struct device *dev); + status_t (*fini)(struct device *dev); + + status_t (*suspend)(struct device *dev); + status_t (*resume)(struct device *dev); +}; + +/* describes a driver, one per driver type */ +struct driver { + const char *type; + const struct driver_ops *ops; +}; + +/* macro-expanding concat */ +#define concat(a, b) __ex_concat(a, b) +#define __ex_concat(a, b) a ## b + +#define DRIVER_EXPORT(type_, ops_) \ + extern const struct driver concat(__driver_, type_); \ + const struct driver concat(__driver_, type_) \ + __ALIGNED(sizeof(void *)) __SECTION("drivers") = { \ + .type = #type_, \ + .ops = ops_, \ + } + +#define DEVICE_INSTANCE(type_, name_, config_) \ + extern struct driver concat(__driver_, type_); \ + struct device concat(__device_, concat(type_, concat(_, name_))) \ + __ALIGNED(sizeof(void *)) __SECTION("devices") = { \ + .name = #name_, \ + .driver = &concat(__driver_, type_), \ + .config = config_, \ + } + +/* + * returns the driver specific ops pointer given the device instance, specifc + * ops type, and generic ops member name within the specific ops structure. + */ +#define device_get_driver_ops(dev, type, member) ({ \ + type *__ops = NULL; \ + if (dev && dev->driver && dev->driver->ops) \ + __ops = containerof(dev->driver->ops, type, member); \ + __ops; \ +}) + +#define device_get_by_name(type_, name_) ({ \ + extern struct device concat(__device_, concat(type_, concat(_, name_))); \ + &concat(__device_, concat(type_, concat(_, name_))); \ +}) + +status_t device_init_all(void); +status_t device_fini_all(void); + +status_t device_init(struct device *dev); +status_t device_fini(struct device *dev); + +status_t device_suspend(struct device *dev); +status_t device_resume(struct device *dev); + +__END_CDECLS + diff --git a/kernel/include/dev/ethernet.h b/kernel/include/dev/ethernet.h new file mode 100644 index 000000000..0542ab658 --- /dev/null +++ b/kernel/include/dev/ethernet.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_ETHERNET_H +#define __DEV_ETHERNET_H + +#include + +/* Queue an ethernet frame for send. +** +** CRC and minimum length padding are handled by the driver. +** +** Data is malloc()'d and ownership is transfered to the ethernet +** device which will free() it once the packet is transmitted. +** +*/ +int ethernet_send(void *data, unsigned length); + +status_t ethernet_init(void); /* initialize the ethernet device */ + +#endif diff --git a/kernel/include/dev/flash_nor.h b/kernel/include/dev/flash_nor.h new file mode 100644 index 000000000..2e751494d --- /dev/null +++ b/kernel/include/dev/flash_nor.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_FLASH_NOR_H +#define __DEV_FLASH_NOR_H + +#include + +struct flash_nor_bank { + addr_t base; + size_t len; + size_t page_size; + uint flags; +}; + +#define FLASH_NOR_FLAG_NONE 0 + +const struct flash_nor_bank *flash_nor_get_bank(unsigned int bank); + +#endif + diff --git a/kernel/include/dev/gpio.h b/kernel/include/dev/gpio.h new file mode 100644 index 000000000..aca0ddef5 --- /dev/null +++ b/kernel/include/dev/gpio.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008, Google Inc. +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __DEV_GPIO_H +#define __DEV_GPIO_H + +enum gpio_flags { + GPIO_INPUT = (1 << 0), + GPIO_OUTPUT = (1 << 1), + GPIO_LEVEL = (1 << 2), + GPIO_EDGE = (1 << 3), + GPIO_RISING = (1 << 4), + GPIO_FALLING = (1 << 5), + GPIO_HIGH = (1 << 6), + GPIO_LOW = (1 << 7), + GPIO_PULLUP = (1 << 8), + GPIO_PULLDOWN = (1 << 9), +}; + +/* top 16 bits of the gpio flags are platform specific */ +#define GPIO_PLATFORM_MASK 0xffff0000 + +int gpio_config(unsigned nr, unsigned flags); +void gpio_set(unsigned nr, unsigned on); +int gpio_get(unsigned nr); + +#endif diff --git a/kernel/include/dev/gpio_i2c.h b/kernel/include/dev/gpio_i2c.h new file mode 100644 index 000000000..b144b8453 --- /dev/null +++ b/kernel/include/dev/gpio_i2c.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __GPIO_I2C__ +#define __GPIO_I2C__ + +#include +#include + +typedef struct gpio_i2c_info { + const int sda; + const int scl; + uint32_t hcd; /* 1/2 I2C clock delay in cpu cycles */ + uint32_t qcd; /* 1/4 I2C clock delay in cpu cycles */ +} gpio_i2c_info_t; + +#define DEFINE_GPIO_I2C(_name, \ + _sda_gpio_id, \ + _scl_gpio_id, \ + _clk_ticks) \ +static const gpio_i2c_info_t _name = { \ + .sda = _sda_gpio_id, \ + .scl = _scl_gpio_id, \ + .hcd = ((_clk_ticks + 1) >> 1), \ + .qcd = ((_clk_ticks + 3) >> 2), \ +} + +void gpio_i2c_add_bus(uint32_t bus_id, const gpio_i2c_info_t *info); + +void gpio_i2c_init_early(void); +void gpio_i2c_init(void); +status_t gpio_i2c_transmit(int, uint8_t, const void *, size_t); +status_t gpio_i2c_receive(int, uint8_t, void *, size_t); +status_t gpio_i2c_write_reg_bytes(int, uint8_t, uint8_t, const uint8_t *, size_t); +status_t gpio_i2c_read_reg_bytes(int, uint8_t, uint8_t, uint8_t *, size_t); + +#endif // __GPIO_I2C__ diff --git a/kernel/include/dev/gpio_keypad.h b/kernel/include/dev/gpio_keypad.h new file mode 100644 index 000000000..04d2d438f --- /dev/null +++ b/kernel/include/dev/gpio_keypad.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008, Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __DEV_GPIO_KEYPAD_H +#define __DEV_GPIO_KEYPAD_H + +#include + +/* unset: drive active output low, set: drive active output high */ +#define GPIOKPF_ACTIVE_HIGH (1U << 0) +#define GPIOKPF_DRIVE_INACTIVE (1U << 1) + +struct gpio_keypad_info { + /* size must be ninputs * noutputs */ + const uint16_t *keymap; + unsigned *input_gpios; + unsigned *output_gpios; + int ninputs; + int noutputs; + /* time to wait before reading inputs after driving each output */ + time_t settle_time; + time_t poll_time; + unsigned flags; +}; + +void gpio_keypad_init(struct gpio_keypad_info *kpinfo); + +#endif /* __DEV_GPIO_KEYPAD_H */ diff --git a/kernel/include/dev/i2c.h b/kernel/include/dev/i2c.h new file mode 100644 index 000000000..87290c031 --- /dev/null +++ b/kernel/include/dev/i2c.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_I2C_H +#define __DEV_I2C_H + +#include + +#include // size_t +#include // status_t + +void i2c_init(void); +void i2c_init_early(void); + +/* Notes about I2C addresses + * + Currently, there is no API support for 10-bit I2C addresses. 7-bit only. + * + Addresses should be supplied as the actual 7-bit address of the device. + * The platform driver is responsible for left shifting this address by 1 and + * suppling the appropriate value for the R/W bit. + */ + +/* send and receive blocks of data */ +status_t i2c_transmit(int bus, uint8_t address, const void *buf, size_t count); +status_t i2c_receive(int bus, uint8_t address, void *buf, size_t count); + +/* A few convenience routines based on the usual way of accessing registers on + * i2c slave devices. + */ +status_t i2c_write_reg_bytes(int bus, uint8_t address, uint8_t reg, const uint8_t *val, size_t cnt); +status_t i2c_read_reg_bytes(int bus, uint8_t address, uint8_t reg, uint8_t *val, size_t cnt); + +static inline status_t i2c_write_reg(int bus, uint8_t address, uint8_t reg, uint8_t val) +{ + return i2c_write_reg_bytes(bus, address, reg, &val, 1); +} + +static inline status_t i2c_read_reg(int bus, uint8_t address, uint8_t reg, uint8_t *val) +{ + return i2c_read_reg_bytes(bus, address, reg, val, 1); +} +#endif + diff --git a/kernel/include/dev/keys.h b/kernel/include/dev/keys.h new file mode 100644 index 000000000..c87615808 --- /dev/null +++ b/kernel/include/dev/keys.h @@ -0,0 +1,66 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009, Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __DEV_KEYS_H +#define __DEV_KEYS_H + +#include + +/* these are just the ascii values for the chars */ +#define KEY_0 0x30 +#define KEY_1 0x31 +#define KEY_2 0x32 +#define KEY_3 0x33 +#define KEY_4 0x34 +#define KEY_5 0x35 +#define KEY_6 0x36 +#define KEY_7 0x37 +#define KEY_8 0x38 +#define KEY_9 0x39 + +#define KEY_A 0x61 + +#define KEY_ESC 0x100 +#define KEY_F1 0x101 +#define KEY_F2 0x102 +#define KEY_F3 0x103 +#define KEY_F4 0x104 +#define KEY_F5 0x105 +#define KEY_F6 0x106 +#define KEY_F7 0x107 +#define KEY_F8 0x108 +#define KEY_F9 0x109 + +#define KEY_LEFT 0x110 +#define KEY_RIGHT 0x111 +#define KEY_UP 0x112 +#define KEY_DOWN 0x113 +#define KEY_CENTER 0x114 + +#define KEY_VOLUMEUP 0x115 +#define KEY_VOLUMEDOWN 0x116 +#define KEY_MUTE 0x117 + +#define KEY_SOFT1 0x11a +#define KEY_SOFT2 0x11b +#define KEY_STAR 0x11c +#define KEY_SHARP 0x11d +#define KEY_MAIL 0x11e + +#define KEY_SEND 0x120 +#define KEY_CLEAR 0x121 +#define KEY_HOME 0x122 +#define KEY_BACK 0x123 + +#define MAX_KEYS 0x1ff + +void keys_init(void); +void keys_post_event(uint16_t code, int16_t value); +int keys_get_state(uint16_t code); + +#endif /* __DEV_KEYS_H */ diff --git a/kernel/include/dev/pci.h b/kernel/include/dev/pci.h new file mode 100644 index 000000000..1f8bdd7e9 --- /dev/null +++ b/kernel/include/dev/pci.h @@ -0,0 +1,203 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PCI_H +#define __PCI_H + +#include +#include + +/* + * PCI access return codes + */ +#define _PCI_SUCCESSFUL 0x00 +#define _PCI_FUNC_NOT_SUPPORTED 0x81 +#define _PCI_BAD_VENDOR_ID 0x83 +#define _PCI_DEVICE_NOT_FOUND 0x86 +#define _PCI_BAD_REGISTER_NUMBER 0x87 +#define _PCI_SET_FAILED 0x88 +#define _PCI_BUFFER_TOO_SMALL 0x89 + +/* + * PCI configuration space offsets + */ +#define PCI_CONFIG_VENDOR_ID 0x00 +#define PCI_CONFIG_DEVICE_ID 0x02 +#define PCI_CONFIG_COMMAND 0x04 +#define PCI_CONFIG_STATUS 0x06 +#define PCI_CONFIG_REVISION_ID 0x08 +#define PCI_CONFIG_CLASS_CODE 0x09 +#define PCI_CONFIG_CLASS_CODE_INTR 0x09 +#define PCI_CONFIG_CLASS_CODE_SUB 0x0a +#define PCI_CONFIG_CLASS_CODE_BASE 0x0b +#define PCI_CONFIG_CACHE_LINE_SIZE 0x0c +#define PCI_CONFIG_LATENCY_TIMER 0x0d +#define PCI_CONFIG_HEADER_TYPE 0x0e +#define PCI_CONFIG_BIST 0x0f +#define PCI_CONFIG_BASE_ADDRESSES 0x10 +#define PCI_CONFIG_CARDBUS_CIS_PTR 0x28 +#define PCI_CONFIG_SUBSYS_VENDOR_ID 0x2c +#define PCI_CONFIG_SUBSYS_ID 0x2e +#define PCI_CONFIG_EXP_ROM_ADDRESS 0x30 +#define PCI_CONFIG_CAPABILITIES 0x34 +#define PCI_CONFIG_INTERRUPT_LINE 0x3c +#define PCI_CONFIG_INTERRUPT_PIN 0x3d +#define PCI_CONFIG_MIN_GRANT 0x3e +#define PCI_CONFIG_MAX_LATENCY 0x3f + +/* + * PCI header type register bits + */ +#define PCI_HEADER_TYPE_MASK 0x7f +#define PCI_HEADER_TYPE_MULTI_FN 0x80 + +/* + * PCI header types + */ +#define PCI_HEADER_TYPE_STANDARD 0x00 +#define PCI_HEADER_TYPE_PCI_BRIDGE 0x01 +#define PCI_HEADER_TYPE_CARD_BUS 0x02 + +/* + * PCI command register bits + */ +#define PCI_COMMAND_IO_EN 0x0001 +#define PCI_COMMAND_MEM_EN 0x0002 +#define PCI_COMMAND_BUS_MASTER_EN 0x0004 +#define PCI_COMMAND_SPECIAL_EN 0x0008 +#define PCI_COMMAND_MEM_WR_INV_EN 0x0010 +#define PCI_COMMAND_PAL_SNOOP_EN 0x0020 +#define PCI_COMMAND_PERR_RESP_EN 0x0040 +#define PCI_COMMAND_AD_STEP_EN 0x0080 +#define PCI_COMMAND_SERR_EN 0x0100 +#define PCI_COMMAND_FAST_B2B_EN 0x0200 + +/* + * PCI status register bits + */ +#define PCI_STATUS_NEW_CAPS 0x0010 +#define PCI_STATUS_66_MHZ 0x0020 +#define PCI_STATUS_FAST_B2B 0x0080 +#define PCI_STATUS_MSTR_PERR 0x0100 +#define PCI_STATUS_DEVSEL_MASK 0x0600 +#define PCI_STATUS_TARG_ABORT_SIG 0x0800 +#define PCI_STATUS_TARG_ABORT_RCV 0x1000 +#define PCI_STATUS_MSTR_ABORT_RCV 0x2000 +#define PCI_STATUS_SERR_SIG 0x4000 +#define PCI_STATUS_PERR 0x8000 + +typedef struct { + uint16_t vendor_id; + uint16_t device_id; + uint16_t command; + uint16_t status; + uint8_t revision_id_0; + uint8_t program_interface; + uint8_t sub_class; + uint8_t base_class; + uint8_t cache_line_size; + uint8_t latency_timer; + uint8_t header_type; + uint8_t bist; + uint32_t base_addresses[6]; + uint32_t cardbus_cis_ptr; + uint16_t subsystem_vendor_id; + uint16_t subsystem_id; + uint32_t expansion_rom_address; + uint8_t capabilities_ptr; + uint8_t reserved_0[3]; + uint32_t reserved_1; + uint8_t interrupt_line; + uint8_t interrupt_pin; + uint8_t min_grant; + uint8_t max_latency; +} __PACKED pci_config_t; + +typedef struct { + uint16_t vendor_id; + uint16_t device_id; + uint16_t command; + uint16_t status; + uint8_t revision_id_0; + uint8_t program_interface; + uint8_t sub_class; + uint8_t base_class; + uint8_t cache_line_size; + uint8_t latency_timer; + uint8_t header_type; + uint8_t bist; + uint32_t base_addresses[2]; + uint8_t primary_bus_id; + uint8_t secondary_bus_id; + uint8_t subordinate_bus_id; + uint8_t secondary_latency_timer; + uint8_t io_base; + uint8_t io_limit; + uint16_t secondary_status; + uint16_t memory_limit; + uint16_t memory_base; + uint16_t prefetchable_memory_limit; + uint16_t prefetchable_memory_base; + uint32_t prefetchable_memory_base_upper; + uint32_t prefetchable_memory_limit_upper; + uint16_t io_base_upper; + uint16_t io_limit_upper; + uint8_t capabilities_ptr; + uint8_t reserved_0[3]; + uint32_t expansion_rom_address; + uint8_t interrupt_line; + uint8_t interrupt_pin; + uint16_t bridge_control; +} __PACKED pci_to_pci_bridge_config_t; + +/* + * PCI address structure + */ +typedef struct { + uint8_t bus; + uint8_t dev_fn; +} pci_location_t; + +typedef struct { + uint8_t id; + uint8_t next; +} __PACKED pci_capability_t; + +typedef struct { + uint8_t bus; + uint8_t device; + uint8_t link_int_a; + uint16_t irq_int_a; + uint8_t link_int_b; + uint16_t irq_int_b; + uint8_t link_int_c; + uint16_t irq_int_c; + uint8_t link_int_d; + uint16_t irq_int_d; + uint8_t slot; + uint8_t reserved; +} __PACKED irq_routing_entry; + +void pci_init(void); + +int pci_get_last_bus(void); + +int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index); +int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index); + +int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value); +int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value); +int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value); + +int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value); +int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value); +int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value); + +int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs); +int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq); + +#endif diff --git a/kernel/include/dev/uart.h b/kernel/include/dev/uart.h new file mode 100644 index 000000000..68a8d0f02 --- /dev/null +++ b/kernel/include/dev/uart.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __DEV_UART_H +#define __DEV_UART_H + +#include +#include + +void uart_init(void); +void uart_init_early(void); + +int uart_putc(int port, char c); +int uart_getc(int port, bool wait); +void uart_flush_tx(int port); +void uart_flush_rx(int port); +void uart_init_port(int port, uint baud); + +/* panic-time uart accessors, intended to be run with interrupts disabled */ +int uart_pputc(int port, char c); +int uart_pgetc(int port); + +#endif + diff --git a/kernel/include/err.h b/kernel/include/err.h new file mode 100644 index 000000000..155c9c52c --- /dev/null +++ b/kernel/include/err.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ERR_H +#define __ERR_H + +#ifndef ASSEMBLY +#include // for status_t +#endif + +#define NO_ERROR (0) +#define ERR_GENERIC (-1) +#define ERR_NOT_FOUND (-2) +#define ERR_NOT_READY (-3) +#define ERR_NO_MSG (-4) +#define ERR_NO_MEMORY (-5) +#define ERR_ALREADY_STARTED (-6) +#define ERR_NOT_VALID (-7) +#define ERR_INVALID_ARGS (-8) +#define ERR_NOT_ENOUGH_BUFFER (-9) +#define ERR_NOT_SUSPENDED (-10) +#define ERR_OBJECT_DESTROYED (-11) +#define ERR_NOT_BLOCKED (-12) +#define ERR_TIMED_OUT (-13) +#define ERR_ALREADY_EXISTS (-14) +#define ERR_CHANNEL_CLOSED (-15) +#define ERR_OFFLINE (-16) +#define ERR_NOT_ALLOWED (-17) +#define ERR_BAD_PATH (-18) +#define ERR_ALREADY_MOUNTED (-19) +#define ERR_IO (-20) +#define ERR_NOT_DIR (-21) +#define ERR_NOT_FILE (-22) +#define ERR_RECURSE_TOO_DEEP (-23) +#define ERR_NOT_SUPPORTED (-24) +#define ERR_TOO_BIG (-25) +#define ERR_CANCELLED (-26) +#define ERR_NOT_IMPLEMENTED (-27) +#define ERR_CHECKSUM_FAIL (-28) +#define ERR_CRC_FAIL (-29) +#define ERR_CMD_UNKNOWN (-30) +#define ERR_BAD_STATE (-31) +#define ERR_BAD_LEN (-32) +#define ERR_BUSY (-33) +#define ERR_THREAD_DETACHED (-34) +#define ERR_I2C_NACK (-35) +#define ERR_ALREADY_EXPIRED (-36) +#define ERR_OUT_OF_RANGE (-37) +#define ERR_NOT_CONFIGURED (-38) +#define ERR_NOT_MOUNTED (-39) +#define ERR_FAULT (-40) +#define ERR_NO_RESOURCES (-41) +#define ERR_BAD_HANDLE (-42) +#define ERR_ACCESS_DENIED (-43) +#define ERR_PARTIAL_WRITE (-44) +#define ERR_BAD_SYSCALL (-45) + +#define ERR_USER_BASE (-16384) + +#endif diff --git a/kernel/include/hw/mii.h b/kernel/include/hw/mii.h new file mode 100644 index 000000000..233fda16c --- /dev/null +++ b/kernel/include/hw/mii.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2006 Brian Swetland +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __HW_MII_H +#define __HW_MII_H + +#define MII_REG_BCR 0x00 +#define MII_REG_BSR 0x01 +#define MII_REG_PHY_ID1 0x02 +#define MII_REG_PHY_ID2 0x03 +#define MII_REG_AUTO_ADV 0x04 +#define MII_REG_AUTO_LINK 0x05 +#define MII_REG_AUTO_EXPN 0x06 +#define MII_REG_AUTO_NEXT 0x07 +#define MII_REG_LINK_NEXT 0x08 +#define MII_REG_RXER_CNT 0x15 +#define MII_REG_ICSR 0x1b +#define MII_REG_100TX_PHY 0x1f + +#define MII_BCR_RESET 0x8000 +#define MII_BCR_LOOPBACK 0x4000 +#define MII_BCR_100MBPS 0x2000 +#define MII_BCR_AUTO_ENABLE 0x1000 +#define MII_BCR_PWR_DOWN 0x0800 +#define MII_BCR_ISOLATE 0x0400 +#define MII_BCR_AUTO_RESTART 0x0200 +#define MII_BCR_FULL_DUPLEX 0x0100 +#define MII_BCR_COL_TEST 0x0080 +#define MII_BCR_TX_DISABLE 0x0001 + +#define MII_BSR_T4 0x8000 +#define MII_BSR_100TX_FULL 0x4000 +#define MII_BSR_100TX_HALF 0x2000 +#define MII_BSR_10T_FULL 0x1000 +#define MII_BSR_10T_HALF 0x0800 +#define MII_BSR_NO_PREAMBLE 0x0040 +#define MII_BSR_AUTO_COMPLETE 0x0020 +#define MII_BSR_REMOTE_FAULT 0x0010 +#define MII_BSR_AUTO_ABLE 0x0008 +#define MII_BSR_LINK_UP 0x0004 +#define MII_BSR_JABBER 0x0002 +#define MII_BSR_EXTEND 0x0001 + +#define MII_100TX_PHY_ISOLATE 0x0040 +#define MII_100TX_MODE_MASK 0x001C +#define MII_100TX_MODE_AUTO 0x0000 +#define MII_100TX_MODE_10T_H 0x0004 +#define MII_100TX_MODE_100TX_H 0x0008 +#define MII_100TX_MODE_10T_F 0x0014 +#define MII_100TX_MODE_100TX_F 0x0018 +#define MII_100TX_MODE_ISOLATE 0x001C +#define MII_100TX_SQE_TEST 0x0002 +#define MII_100TX_NO_SCRAMBLE 0x0001 + +#endif diff --git a/kernel/include/hw/usb.h b/kernel/include/hw/usb.h new file mode 100644 index 000000000..53292f278 --- /dev/null +++ b/kernel/include/hw/usb.h @@ -0,0 +1,91 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __HW_USB_H +#define __HW_USB_H + +#include +#include + +/* GLOBAL STATUS VALUES */ +#define STD_COMMAND 0x00 +#define SETUP_COMMAND_PHASE 0x40 +#define FUNCTION_ERROR 0x7F /* Used when we are stalling the function EP0 */ +#define HUB_ERROR 0xFF /* Used when we are stalling the HUB EP0 */ + +/* Request Types */ +#define DIR_OUT (0 << 7) +#define DIR_IN (1 << 7) +#define DIR_MASK (1 << 7) +#define TYPE_STANDARD (0 << 5) +#define TYPE_CLASS (1 << 5) +#define TYPE_VENDOR (2 << 5) +#define TYPE_MASK (3 << 5) +#define RECIP_DEVICE (0 << 0) +#define RECIP_INTERFACE (1 << 0) +#define RECIP_ENDPOINT (2 << 0) +#define RECIP_OTHER (3 << 0) +#define RECIP_MASK (0x1f << 0) + +/* 1.0 Request Values */ +#define GET_STATUS 0x00 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 +#define SET_ADDRESS 0x05 +#define GET_DESCRIPTOR 0x06 +#define SET_DESCRIPTOR 0x07 +#define GET_CONFIGURATION 0x08 +#define SET_CONFIGURATION 0x09 +#define GET_INTERFACE 0x0A +#define SET_INTERFACE 0x0B +#define SYNCH_FRAME 0x0C + +/* Mass storage requests */ +#define MASS_STORAGE_GET_MAX_LUN 0xfe +#define MASS_STORAGE_RESET 0xff + +/* DFU requests */ +#define DFU_DETACH 0x00 +#define DFU_DNLOAD 0x01 +#define DFU_UPLOAD 0x02 +#define DFU_GETSTATUS 0x03 +#define DFU_CLRSTATUS 0x04 +#define DFU_GETSTATE 0x05 +#define DFU_ABORT 0x06 + +/* HID Request Values */ +#define GET_REPORT 0x01 +#define GET_IDLE 0x02 +#define GET_PROTOCOL 0x03 +#define SET_REPORT 0x09 +#define SET_IDLE 0x0A +#define SET_PROTOCOL 0x0B + +/* Descriptor Types */ +#define DEVICE 0x01 +#define CONFIGURATION 0x02 +#define STRING 0x03 +#define INTERFACE 0x04 +#define ENDPOINT 0x05 +#define DEVICE_QUALIFIER 0x06 +#define OTHER_SPEED_CONFIGURATION 0x07 +#define INTERFACE_POWER 0x08 +#define HID 0x21 +#define HIDREPORT 0x22 +#define HIDPHYSICAL 0x23 + +/* general USB defines */ +struct usb_setup { + uint8_t request_type; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; +} __PACKED; + +#endif + diff --git a/kernel/include/kernel/auto_lock.h b/kernel/include/kernel/auto_lock.h new file mode 100644 index 000000000..f4f724752 --- /dev/null +++ b/kernel/include/kernel/auto_lock.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +class AutoLock { +public: + AutoLock(mutex_t* mutex) + : mutex_(mutex) { + mutex_acquire(mutex_); + } + + AutoLock(mutex_t& mutex) + : AutoLock(&mutex) {} + + ~AutoLock() { + release(); + } + + // early release the mutex before the object goes out of scope + void release() { + if (mutex_) { + mutex_release(mutex_); + mutex_ = nullptr; + } + } + + // suppress default constructors + AutoLock(const AutoLock& am) = delete; + AutoLock& operator=(const AutoLock& am) = delete; + AutoLock(AutoLock&& c) = delete; + AutoLock& operator=(AutoLock&& c) = delete; + +private: + mutex_t* mutex_; +}; diff --git a/kernel/include/kernel/cond.h b/kernel/include/kernel/cond.h new file mode 100644 index 000000000..ecbddfa45 --- /dev/null +++ b/kernel/include/kernel/cond.h @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_COND_H +#define __KERNEL_COND_H + +#include +#include +#include +#include + +__BEGIN_CDECLS; + +#define COND_MAGIC (0x636f6e64) // "cond" + +typedef struct cond { + uint32_t magic; + wait_queue_t wait; +} cond_t; + +#define COND_INITIAL_VALUE(cond) \ +{ \ + .magic = COND_MAGIC, \ + .wait = WAIT_QUEUE_INITIAL_VALUE((cond).wait), \ +} + +void cond_init(cond_t *cond); +void cond_destroy(cond_t *cond); +status_t cond_wait_timeout(cond_t *cond, mutex_t *mutex, lk_time_t timeout); +void cond_signal(cond_t *cond); + +__END_CDECLS; + +#endif diff --git a/kernel/include/kernel/debug.h b/kernel/include/kernel/debug.h new file mode 100644 index 000000000..c76254f91 --- /dev/null +++ b/kernel/include/kernel/debug.h @@ -0,0 +1,68 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_DEBUG_H +#define __KERNEL_DEBUG_H + +#include + +__BEGIN_CDECLS; + +#include + +/* kernel event log */ +#if WITH_KERNEL_EVLOG + +#include + +#ifndef KERNEL_EVLOG_LEN +#define KERNEL_EVLOG_LEN 1024 +#endif + +void kernel_evlog_init(void); + +void kernel_evlog_add(uintptr_t id, uintptr_t arg0, uintptr_t arg1); +void kernel_evlog_dump(void); + +#else // !WITH_KERNEL_EVLOG + +/* do nothing versions */ +static inline void kernel_evlog_init(void) {} +static inline void kernel_evlog_add(uintptr_t id, uintptr_t arg0, uintptr_t arg1) {} +static inline void kernel_evlog_dump(void) {} + +#endif + +enum { + KERNEL_EVLOG_NULL = 0, + KERNEL_EVLOG_CONTEXT_SWITCH, + KERNEL_EVLOG_PREEMPT, + KERNEL_EVLOG_TIMER_TICK, + KERNEL_EVLOG_TIMER_CALL, + KERNEL_EVLOG_IRQ_ENTER, + KERNEL_EVLOG_IRQ_EXIT, +}; + +#define KEVLOG_THREAD_SWITCH(from, to) kernel_evlog_add(KERNEL_EVLOG_CONTEXT_SWITCH, (uintptr_t)from, (uintptr_t)to) +#define KEVLOG_THREAD_PREEMPT(thread) kernel_evlog_add(KERNEL_EVLOG_PREEMPT, (uintptr_t)thread, 0) +#define KEVLOG_TIMER_TICK() kernel_evlog_add(KERNEL_EVLOG_TIMER_TICK, 0, 0) +#define KEVLOG_TIMER_CALL(ptr, arg) kernel_evlog_add(KERNEL_EVLOG_TIMER_CALL, (uintptr_t)ptr, (uintptr_t)arg) +#define KEVLOG_IRQ_ENTER(irqn) kernel_evlog_add(KERNEL_EVLOG_IRQ_ENTER, (uintptr_t)irqn, 0) +#define KEVLOG_IRQ_EXIT(irqn) kernel_evlog_add(KERNEL_EVLOG_IRQ_EXIT, (uintptr_t)irqn, 0) + +/* kernel log */ +#if WITH_LIB_KLOG +void kernel_log_init(void); +#else +/* do nothing */ +static inline void kernel_log_init(void) {} +#endif + +__END_CDECLS; + +#endif + diff --git a/kernel/include/kernel/event.h b/kernel/include/kernel/event.h new file mode 100644 index 000000000..97c3a4d6d --- /dev/null +++ b/kernel/include/kernel/event.h @@ -0,0 +1,74 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_EVENT_H +#define __KERNEL_EVENT_H + +#include +#include +#include +#include + +__BEGIN_CDECLS; + +#define EVENT_MAGIC (0x65766E74) // "evnt" + +typedef struct event { + int magic; + bool signalled; + uint flags; + wait_queue_t wait; +} event_t; + +#define EVENT_FLAG_AUTOUNSIGNAL 1 + +#define EVENT_INITIAL_VALUE(e, initial, _flags) \ +{ \ + .magic = EVENT_MAGIC, \ + .signalled = initial, \ + .flags = _flags, \ + .wait = WAIT_QUEUE_INITIAL_VALUE((e).wait), \ +} + +/* Rules for Events: + * - Events may be signaled from interrupt context *but* the reschedule + * parameter must be false in that case. + * - Events may not be waited upon from interrupt context. + * - Events without FLAG_AUTOUNSIGNAL: + * - Wake up any waiting threads when signaled. + * - Continue to do so (no threads will wait) until unsignaled. + * - Events with FLAG_AUTOUNSIGNAL: + * - If one or more threads are waiting when signaled, one thread will + * be woken up and return. The signaled state will not be set. + * - If no threads are waiting when signaled, the Event will remain + * in the signaled state until a thread attempts to wait (at which + * time it will unsignal atomicly and return immediately) or + * event_unsignal() is called. +*/ + +void event_init(event_t *, bool initial, uint flags); +void event_destroy(event_t *); + +status_t event_wait_timeout(event_t *, lk_time_t); +int event_signal_etc(event_t *, bool reschedule, status_t result); +status_t event_signal(event_t *, bool reschedule); +status_t event_unsignal(event_t *); + +static inline bool event_initialized(event_t *e) +{ + return e->magic == EVENT_MAGIC; +} + +static inline status_t event_wait(event_t *e) +{ + return event_wait_timeout(e, INFINITE_TIME); +} + +__END_CDECLS; + +#endif + diff --git a/kernel/include/kernel/mp.h b/kernel/include/kernel/mp.h new file mode 100644 index 000000000..24b141420 --- /dev/null +++ b/kernel/include/kernel/mp.h @@ -0,0 +1,159 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS; + +typedef uint32_t mp_cpu_mask_t; +typedef void (*mp_ipi_task_func_t)(void *context); +typedef void (*mp_sync_task_t)(void *context); + +#define MP_CPU_ALL_BUT_LOCAL (UINT32_MAX) +#define MP_CPU_ALL (1U<<31) +STATIC_ASSERT(SMP_MAX_CPUS <= 31); + +/* by default, mp_mbx_reschedule does not signal to cpus that are running realtime + * threads. Override this behavior. + */ +#define MP_RESCHEDULE_FLAG_REALTIME (0x1) + +typedef enum { + MP_IPI_GENERIC, + MP_IPI_RESCHEDULE, +} mp_ipi_t; + +#ifdef WITH_SMP +void mp_init(void); + +void mp_reschedule(mp_cpu_mask_t target, uint flags); +void mp_sync_exec(mp_cpu_mask_t target, mp_sync_task_t task, void *context); +void mp_set_curr_cpu_online(bool online); +void mp_set_curr_cpu_active(bool active); + +/* called from arch code during reschedule irq */ +enum handler_return mp_mbx_reschedule_irq(void); +/* called from arch code during generic task irq */ +enum handler_return mp_mbx_generic_irq(void); + +/* represents a pending task for some number of CPUs to execute */ +struct mp_ipi_task { + struct list_node node; + + mp_ipi_task_func_t func; + void *context; +}; + +/* global mp state to track what the cpus are up to */ +struct mp_state { + /* cpus that are currently online */ + volatile mp_cpu_mask_t online_cpus; + /* cpus that are currently schedulable */ + volatile mp_cpu_mask_t active_cpus; + + /* only safely accessible with thread lock held */ + mp_cpu_mask_t idle_cpus; + mp_cpu_mask_t realtime_cpus; + + spin_lock_t ipi_task_lock; + /* list of outstanding tasks for CPUs to execute. Should only be + * accessed with the ipi_task_lock held */ + struct list_node ipi_task_list[SMP_MAX_CPUS]; +}; + +extern struct mp_state mp; + +static inline int mp_is_cpu_active(uint cpu) +{ + return mp.active_cpus & (1 << cpu); +} + +static inline int mp_is_cpu_idle(uint cpu) +{ + return mp.idle_cpus & (1 << cpu); +} + +/* must be called with the thread lock held */ +static inline void mp_set_cpu_idle(uint cpu) +{ + mp.idle_cpus |= 1U << cpu; +} + +static inline void mp_set_cpu_busy(uint cpu) +{ + mp.idle_cpus &= ~(1U << cpu); +} + +static inline mp_cpu_mask_t mp_get_idle_mask(void) +{ + return mp.idle_cpus; +} + +static inline mp_cpu_mask_t mp_get_active_mask(void) +{ + return mp.active_cpus; +} + +static inline mp_cpu_mask_t mp_get_online_mask(void) +{ + return mp.online_cpus; +} + +static inline void mp_set_cpu_realtime(uint cpu) +{ + mp.realtime_cpus |= 1U << cpu; +} + +static inline void mp_set_cpu_non_realtime(uint cpu) +{ + mp.realtime_cpus &= ~(1U << cpu); +} + +static inline mp_cpu_mask_t mp_get_realtime_mask(void) +{ + return mp.realtime_cpus; +} +#else +static inline void mp_init(void) {} +static inline void mp_reschedule(mp_cpu_mask_t target, uint flags) {} +static inline void mp_sync_exec(mp_cpu_mask_t target, mp_sync_task_t task, void *context) +{ + if (target != MP_CPU_ALL && + (!(target & 0x1) || target == MP_CPU_ALL_BUT_LOCAL)) return; + task(context); +} +static inline void mp_set_curr_cpu_active(bool active) {} +static inline void mp_set_curr_cpu_online(bool online) {} + +static inline enum handler_return mp_mbx_reschedule_irq(void) { return INT_NO_RESCHEDULE; } +static inline enum handler_return mp_mbx_generic_irq(void) { return INT_NO_RESCHEDULE; } + +// only one cpu exists in UP and if you're calling these functions, it's active... +static inline int mp_is_cpu_active(uint cpu) { return 1; } +static inline int mp_is_cpu_idle(uint cpu) { return (get_current_thread()->flags & THREAD_FLAG_IDLE) != 0; } + +static inline void mp_set_cpu_idle(uint cpu) {} +static inline void mp_set_cpu_busy(uint cpu) {} + +static inline mp_cpu_mask_t mp_get_idle_mask(void) { return 0; } + +static inline void mp_set_cpu_realtime(uint cpu) {} +static inline void mp_set_cpu_non_realtime(uint cpu) {} + +static inline mp_cpu_mask_t mp_get_realtime_mask(void) { return 0; } + +static inline mp_cpu_mask_t mp_get_active_mask(void) { return 1; } +static inline mp_cpu_mask_t mp_get_online_mask(void) { return 1; } +#endif + +__END_CDECLS; diff --git a/kernel/include/kernel/mutex.h b/kernel/include/kernel/mutex.h new file mode 100644 index 000000000..2dfb4e30b --- /dev/null +++ b/kernel/include/kernel/mutex.h @@ -0,0 +1,63 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// Copyright (c) 2012 Shantanu Gupta +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_MUTEX_H +#define __KERNEL_MUTEX_H + +#include +#include +#include +#include + +__BEGIN_CDECLS; + +#define MUTEX_MAGIC (0x6D757478) // 'mutx' + +typedef struct mutex { + uint32_t magic; + thread_t *holder; + int count; + wait_queue_t wait; +} mutex_t; + +#define MUTEX_INITIAL_VALUE(m) \ +{ \ + .magic = MUTEX_MAGIC, \ + .holder = NULL, \ + .count = 0, \ + .wait = WAIT_QUEUE_INITIAL_VALUE((m).wait), \ +} + +/* Rules for Mutexes: + * - Mutexes are only safe to use from thread context. + * - Mutexes are non-recursive. +*/ + +void mutex_init(mutex_t *); +void mutex_destroy(mutex_t *); +status_t mutex_acquire_timeout(mutex_t *, lk_time_t); /* try to acquire the mutex with a timeout value */ +status_t mutex_release(mutex_t *); + +/* Internal functions for use by condvar implementation. */ +status_t mutex_acquire_timeout_internal(mutex_t *m, lk_time_t timeout); +void mutex_release_internal(mutex_t *m, bool reschedule); + +static inline status_t mutex_acquire(mutex_t *m) +{ + return mutex_acquire_timeout(m, INFINITE_TIME); +} + +/* does the current thread hold the mutex? */ +static bool is_mutex_held(mutex_t *m) +{ + return m->holder == get_current_thread(); +} + +__END_CDECLS; +#endif + diff --git a/kernel/include/kernel/novm.h b/kernel/include/kernel/novm.h new file mode 100644 index 000000000..389cd2363 --- /dev/null +++ b/kernel/include/kernel/novm.h @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_NOVM_H +#define __KERNEL_NOVM_H + +#include +#include +#include + +#if WITH_KERNEL_VM +#error novm header is included when it shouldnt +#endif + +#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) +#define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE) + +// arena bitmaps for novm_alloc_pages +#define NOVM_ARENA_ANY (UINT32_MAX) +#define NOVM_ARENA_MAIN (1<<0) +#define NOVM_ARENA_SECONDARY (~NOVM_ARENA_MAIN) + +void *novm_alloc_pages(size_t pages, uint32_t arena_bitmap); +void novm_free_pages(void *address, size_t pages); +status_t novm_alloc_specific_pages(void *address, size_t pages); + +// You can call this once and it will give you some possibly unaligned memory +// that would otherwise go to waste. The memory can't be freed. +void *novm_alloc_unaligned(size_t *size_return); + +void novm_add_arena(const char *name, uintptr_t arena_start, uintptr_t arena_size); + +#endif diff --git a/kernel/include/kernel/port.h b/kernel/include/kernel/port.h new file mode 100644 index 000000000..78e20468e --- /dev/null +++ b/kernel/include/kernel/port.h @@ -0,0 +1,155 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_PORT_H +#define __KERNEL_PORT_H + +#include +#include + + +__BEGIN_CDECLS; + +/* Ports are named, opaque objects and come in three flavors, the + * write-side, the read-side and a port group which is a collection + * of read-side ports. + */ + +#define PORT_NAME_LEN 12 + +typedef void *port_t; + +typedef struct { + union { + char value[8]; + void* pvalue; + }; +} port_packet_t; + +typedef struct { + void *ctx; + port_packet_t packet; +} port_result_t; + +typedef enum { + PORT_MODE_BROADCAST = 0, + PORT_MODE_UNICAST = 1, + PORT_MODE_BIG_BUFFER = 2, +} port_mode_t; + +/* Inits the port subsystem + */ +void port_init(void); + +/* Make a named write-side port. Broadcast ports can be opened by any + * number of read-clients. |name| can be up to PORT_NAME_LEN chars. If + * the write port exists it is returned even if the |mode| does not match. + * + * The combination PORT_MODE_BROADCAST | PORT_MODE_BIG_BUFFER is not + * valid. + * Returns ERR_ALREADY_EXISTS if a write-side port with that name + * already exists. Returns NO_ERROR upon success. + */ +status_t port_create(const char *name, port_mode_t mode, port_t *port); + +/* Make a read-side port. Only non-destroyed existing write ports can + * be opened with this api. Unicast ports can only be opened once. For + * broadcast ports, each call if successful returns a new port. + * + * Returns ERR_NOT_FOUND if a write-side port with |name| cannot be found. + * + * Returns ERR_NOT_ALLOWED if the named port is PORT_MODE_UNICAST and + * has already a connected read-side port. + * + * Returns NO_ERROR upon success. + */ +status_t port_open(const char *name, void *ctx, port_t *port); + +/* Creates a read-side port group which behaves just like a regular + * read-side port. A given port can only be assoicated with one port group. + * + * Returns ERR_BAD_HANDLE if at least one of the |ports| is not a read-side + * port. + * + * Returns NO_ERROR upon success. + */ +status_t port_group(port_t *ports, size_t count, port_t *group); + +/* Adds a read-side port to an existing port group. + * + * Returns NO_ERROR upon success. + */ +status_t port_group_add(port_t group, port_t port); + +/* Removes a read-side port to an existing port group. + * + * Returns NO_ERROR upon success. + */ +status_t port_group_remove(port_t group, port_t port); + +/* Write to a port |count| packets, non-blocking, all or none atomic success + * for unicast ports. It can return ERR_PARTIAL_WRITE for multicast. + * + * Returns ERR_CHANNEL_CLOSED if there was a read port that got closed. + * + * Returns NO_ERROR upon success. + */ +status_t port_write(port_t port, const port_packet_t *pk, size_t count); + +/* Read one packet from the port or port group, blocking. The |result| contains + * the port that the message was read from. If |timeout| is zero the call + * does not block and returns ERR_TIMED_OUT if there is nothing to read. + * + * Returns ERR_CHANNEL_CLOSED if there is nothing to read and the write-side + * port has been destroyed. + * + * Returns NO_ERROR upon success. + */ +status_t port_read(port_t port, lk_time_t timeout, port_result_t *result); + +/* Peek one packet from the port, non-blocking. + * + * Returns ERR_CHANNEL_CLOSED if there is nothing to read and the write-side + * port has been destroyed. + * + * Returns ERR_NOT_READY if there is no packet pending. + * + * Returns NO_ERROR upon success. + */ +status_t port_peek(port_t port, port_result_t *result); + +/* Wait for the arrival of one or more packets. + * + * Waits up until |timeout| for a packet to be available for reading or the + * write-side port to be destroyed. + * + * If a packet is available for reading it returns NO_ERROR. + * + * Otherwise, if the write-side is closed it returns ERR_CHANNEL_CLOSED. + * + * Otherwise it returns ERR_TIMED_OUT. + */ +status_t port_wait(port_t port, lk_time_t timeout); + +/* Destroy the write-side port, flush queued packets and release all resources, + * all calls will now fail on that port. Only a closed port can be destroyed. + * + * Returns NO_ERROR upon success. + */ +status_t port_destroy(port_t port); + +/* Close the read-side port or the write side port. A closed write side port + * can be opened and the pending packets read. closing a port group does not + * close the included ports. + * + * Returns NO_ERROR upon success. + */ +status_t port_close(port_t port); + +__END_CDECLS; + +#endif diff --git a/kernel/include/kernel/semaphore.h b/kernel/include/kernel/semaphore.h new file mode 100644 index 000000000..88c090eb5 --- /dev/null +++ b/kernel/include/kernel/semaphore.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2012 Christopher Anderson +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __KERNEL_SEMAPHORE_H +#define __KERNEL_SEMAPHORE_H + +#include +#include +#include + +__BEGIN_CDECLS; + +#define SEMAPHORE_MAGIC (0x73656D61) // 'sema' + +typedef struct semaphore { + int magic; + int count; + wait_queue_t wait; +} semaphore_t; + +#define SEMAPHORE_INITIAL_VALUE(s, _count) \ +{ \ + .magic = SEMAPHORE_MAGIC, \ + .count = _count, \ + .wait = WAIT_QUEUE_INITIAL_VALUE((s).wait), \ +} + +void sem_init(semaphore_t *, unsigned int); +void sem_destroy(semaphore_t *); +int sem_post(semaphore_t *, bool resched); +status_t sem_wait(semaphore_t *); +status_t sem_trywait(semaphore_t *); +status_t sem_timedwait(semaphore_t *, lk_time_t); + +__END_CDECLS; +#endif diff --git a/kernel/include/kernel/spinlock.h b/kernel/include/kernel/spinlock.h new file mode 100644 index 000000000..1568602b4 --- /dev/null +++ b/kernel/include/kernel/spinlock.h @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +/* interrupts should already be disabled */ +static inline void spin_lock(spin_lock_t *lock) +{ + arch_spin_lock(lock); +} + +/* Returns 0 on success, non-0 on failure */ +static inline int spin_trylock(spin_lock_t *lock) +{ + return arch_spin_trylock(lock); +} + +/* interrupts should already be disabled */ +static inline void spin_unlock(spin_lock_t *lock) +{ + arch_spin_unlock(lock); +} + +static inline void spin_lock_init(spin_lock_t *lock) +{ + arch_spin_lock_init(lock); +} + +static inline bool spin_lock_held(spin_lock_t *lock) +{ + return arch_spin_lock_held(lock); +} + +/* spin lock irq save flags: */ + +/* Possible future flags: + * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff + * SPIN_LOCK_FLAG_PREEMPTION = 0x00000100 + * SPIN_LOCK_FLAG_SET_PMR = 0x00000200 + */ + +/* Generic flags */ +#define SPIN_LOCK_FLAG_INTERRUPTS ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS + +/* same as spin lock, but save disable and save interrupt state first */ +static inline void spin_lock_save( + spin_lock_t *lock, + spin_lock_saved_state_t *statep, + spin_lock_save_flags_t flags) +{ + arch_interrupt_save(statep, flags); + spin_lock(lock); +} + +/* restore interrupt state before unlocking */ +static inline void spin_unlock_restore( + spin_lock_t *lock, + spin_lock_saved_state_t old_state, + spin_lock_save_flags_t flags) +{ + spin_unlock(lock); + arch_interrupt_restore(old_state, flags); +} + +/* hand(ier) routines */ +#define spin_lock_irqsave(lock, statep) spin_lock_save(lock, &(statep), SPIN_LOCK_FLAG_INTERRUPTS) +#define spin_unlock_irqrestore(lock, statep) spin_unlock_restore(lock, statep, SPIN_LOCK_FLAG_INTERRUPTS) + +__END_CDECLS diff --git a/kernel/include/kernel/thread.h b/kernel/include/kernel/thread.h new file mode 100644 index 000000000..f8866bbde --- /dev/null +++ b/kernel/include/kernel/thread.h @@ -0,0 +1,250 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_THREAD_H +#define __KERNEL_THREAD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_KERNEL_VM +#include +#endif + +__BEGIN_CDECLS; + +/* debug-enable runtime checks */ +#if LK_DEBUGLEVEL > 1 +#define THREAD_STATS 1 +#define THREAD_STACK_BOUNDS_CHECK 1 +#ifndef THREAD_STACK_PADDING_SIZE +#define THREAD_STACK_PADDING_SIZE 256 +#endif +#endif + +enum thread_state { + THREAD_SUSPENDED = 0, + THREAD_READY, + THREAD_RUNNING, + THREAD_BLOCKED, + THREAD_SLEEPING, + THREAD_DEATH, +}; + +typedef int (*thread_start_routine)(void *arg); + +/* thread local storage */ +enum thread_tls_list { +#ifdef WITH_LIB_UTHREAD + TLS_ENTRY_UTHREAD, +#endif +#ifdef WITH_LIB_USERBOOT + TLS_ENTRY_LKUSER, +#endif + MAX_TLS_ENTRY +}; + +#define THREAD_FLAG_DETACHED (1<<0) +#define THREAD_FLAG_FREE_STACK (1<<1) +#define THREAD_FLAG_FREE_STRUCT (1<<2) +#define THREAD_FLAG_REAL_TIME (1<<3) +#define THREAD_FLAG_IDLE (1<<4) +#define THREAD_FLAG_DEBUG_STACK_BOUNDS_CHECK (1<<5) + +#define THREAD_MAGIC (0x74687264) // 'thrd' + +#define THREAD_NAME_LENGTH 64 + +#define THREAD_LINEBUFFER_LENGTH 128 + +typedef struct thread { + int magic; + struct list_node thread_list_node; + + /* active bits */ + struct list_node queue_node; + int priority; + enum thread_state state; + int remaining_quantum; + unsigned int flags; +#if WITH_SMP + int curr_cpu; + int pinned_cpu; /* only run on pinned_cpu if >= 0 */ +#endif +#if WITH_KERNEL_VM + vmm_aspace_t *aspace; +#endif + + /* if blocked, a pointer to the wait queue */ + struct wait_queue *blocking_wait_queue; + status_t wait_queue_block_ret; + + /* architecture stuff */ + struct arch_thread arch; + + /* stack stuff */ + void *stack; + size_t stack_size; + + /* entry point */ + thread_start_routine entry; + void *arg; + +#if WITH_DEBUG_LINEBUFFER + int linebuffer_pos; +#endif + + /* return code */ + int retcode; + struct wait_queue retcode_wait_queue; + + /* thread local storage */ + uintptr_t tls[MAX_TLS_ENTRY]; + + char name[THREAD_NAME_LENGTH]; +#if WITH_DEBUG_LINEBUFFER + /* buffering for debug/klog output */ + char linebuffer[THREAD_LINEBUFFER_LENGTH]; +#endif +} thread_t; + +#if WITH_SMP +#define thread_curr_cpu(t) ((t)->curr_cpu) +#define thread_pinned_cpu(t) ((t)->pinned_cpu) +#define thread_set_curr_cpu(t,c) ((t)->curr_cpu = (c)) +#define thread_set_pinned_cpu(t, c) ((t)->pinned_cpu = (c)) +#else +#define thread_curr_cpu(t) (0) +#define thread_pinned_cpu(t) (-1) +#define thread_set_curr_cpu(t,c) do {} while(0) +#define thread_set_pinned_cpu(t, c) do {} while(0) +#endif + +/* thread priority */ +#define NUM_PRIORITIES 32 +#define LOWEST_PRIORITY 0 +#define HIGHEST_PRIORITY (NUM_PRIORITIES - 1) +#define DPC_PRIORITY (NUM_PRIORITIES - 2) +#define IDLE_PRIORITY LOWEST_PRIORITY +#define LOW_PRIORITY (NUM_PRIORITIES / 4) +#define DEFAULT_PRIORITY (NUM_PRIORITIES / 2) +#define HIGH_PRIORITY ((NUM_PRIORITIES / 4) * 3) + +/* stack size */ +#ifdef CUSTOM_DEFAULT_STACK_SIZE +#define DEFAULT_STACK_SIZE CUSTOM_DEFAULT_STACK_SIZE +#else +#define DEFAULT_STACK_SIZE ARCH_DEFAULT_STACK_SIZE +#endif + +/* functions */ +void thread_init_early(void); +void thread_init(void); +void thread_become_idle(void) __NO_RETURN; +void thread_secondary_cpu_init_early(void); +void thread_secondary_cpu_entry(void) __NO_RETURN; +void thread_set_name(const char *name); +void thread_set_priority(int priority); +thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size); +thread_t *thread_create_etc(thread_t *t, const char *name, thread_start_routine entry, void *arg, int priority, void *stack, size_t stack_size); +status_t thread_resume(thread_t *); +void thread_exit(int retcode) __NO_RETURN; +void thread_sleep(lk_time_t delay); +status_t thread_detach(thread_t *t); +status_t thread_join(thread_t *t, int *retcode, lk_time_t timeout); +status_t thread_detach_and_resume(thread_t *t); +status_t thread_set_real_time(thread_t *t); + +void dump_thread(thread_t *t); +void arch_dump_thread(thread_t *t); +void dump_all_threads(void); + +/* scheduler routines */ +void thread_yield(void); /* give up the cpu voluntarily */ +void thread_preempt(void); /* get preempted (inserted into head of run queue) */ +void thread_block(void); /* block on something and reschedule */ +void thread_unblock(thread_t *t, bool resched); /* go back in the run queue */ + +#ifdef WITH_LIB_UTHREAD +void uthread_context_switch(thread_t *oldthread, thread_t *newthread); +#endif + +/* called on every timer tick for the scheduler to do quantum expiration */ +enum handler_return thread_timer_tick(void); + +/* the current thread */ +thread_t *get_current_thread(void); +void set_current_thread(thread_t *); + +/* scheduler lock */ +extern spin_lock_t thread_lock; + +#define THREAD_LOCK(state) spin_lock_saved_state_t state; spin_lock_irqsave(&thread_lock, state) +#define THREAD_UNLOCK(state) spin_unlock_irqrestore(&thread_lock, state) + +static inline bool thread_lock_held(void) +{ + return spin_lock_held(&thread_lock); +} + +/* thread local storage */ +static inline __ALWAYS_INLINE uintptr_t tls_get(uint entry) +{ + return get_current_thread()->tls[entry]; +} + +static inline __ALWAYS_INLINE uintptr_t __tls_set(uint entry, uintptr_t val) +{ + uintptr_t oldval = get_current_thread()->tls[entry]; + get_current_thread()->tls[entry] = val; + return oldval; +} + +#define tls_set(e,v) \ + ({ \ + STATIC_ASSERT((e) < MAX_TLS_ENTRY); \ + __tls_set(e, v); \ + }) + +/* thread level statistics */ +#if THREAD_STATS +struct thread_stats { + lk_bigtime_t idle_time; + lk_bigtime_t last_idle_timestamp; + ulong reschedules; + ulong context_switches; + ulong preempts; + ulong yields; + ulong interrupts; /* platform code increment this */ + ulong timer_ints; /* timer code increment this */ + ulong timers; /* timer code increment this */ + +#if WITH_SMP + ulong reschedule_ipis; +#endif +}; + +extern struct thread_stats thread_stats[SMP_MAX_CPUS]; + +#define THREAD_STATS_INC(name) do { thread_stats[arch_curr_cpu_num()].name++; } while(0) + +#else + +#define THREAD_STATS_INC(name) do { } while (0) + +#endif + +__END_CDECLS; + +#endif diff --git a/kernel/include/kernel/timer.h b/kernel/include/kernel/timer.h new file mode 100644 index 000000000..61b4586a8 --- /dev/null +++ b/kernel/include/kernel/timer.h @@ -0,0 +1,59 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_TIMER_H +#define __KERNEL_TIMER_H + +#include +#include +#include + +__BEGIN_CDECLS; + +void timer_init(void); + +struct timer; +typedef enum handler_return (*timer_callback)(struct timer *, lk_time_t now, void *arg); + +#define TIMER_MAGIC (0x74696D72) //'timr' + +typedef struct timer { + int magic; + struct list_node node; + + lk_time_t scheduled_time; + lk_time_t periodic_time; + + timer_callback callback; + void *arg; +} timer_t; + +#define TIMER_INITIAL_VALUE(t) \ +{ \ + .magic = TIMER_MAGIC, \ + .node = LIST_INITIAL_CLEARED_VALUE, \ + .scheduled_time = 0, \ + .periodic_time = 0, \ + .callback = NULL, \ + .arg = NULL, \ +} + +/* Rules for Timers: + * - Timer callbacks occur from interrupt context + * - Timers may be programmed or canceled from interrupt or thread context + * - Timers may be canceled or reprogrammed from within their callback + * - Timers currently are dispatched from a 10ms periodic tick +*/ +void timer_initialize(timer_t *); +void timer_set_oneshot(timer_t *, lk_time_t delay, timer_callback, void *arg); +void timer_set_periodic(timer_t *, lk_time_t period, timer_callback, void *arg); +void timer_cancel(timer_t *); + +__END_CDECLS; + +#endif + diff --git a/kernel/include/kernel/vm.h b/kernel/include/kernel/vm.h new file mode 100644 index 000000000..44d7eddc6 --- /dev/null +++ b/kernel/include/kernel/vm.h @@ -0,0 +1,262 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* some assembly #defines, need to match the structure below */ +#if IS_64BIT +#define __MMU_INITIAL_MAPPING_PHYS_OFFSET 0 +#define __MMU_INITIAL_MAPPING_VIRT_OFFSET 8 +#define __MMU_INITIAL_MAPPING_SIZE_OFFSET 16 +#define __MMU_INITIAL_MAPPING_FLAGS_OFFSET 24 +#define __MMU_INITIAL_MAPPING_SIZE 40 +#else +#define __MMU_INITIAL_MAPPING_PHYS_OFFSET 0 +#define __MMU_INITIAL_MAPPING_VIRT_OFFSET 4 +#define __MMU_INITIAL_MAPPING_SIZE_OFFSET 8 +#define __MMU_INITIAL_MAPPING_FLAGS_OFFSET 12 +#define __MMU_INITIAL_MAPPING_SIZE 20 +#endif + +/* flags for initial mapping struct */ +#define MMU_INITIAL_MAPPING_TEMPORARY (0x1) +#define MMU_INITIAL_MAPPING_FLAG_UNCACHED (0x2) +#define MMU_INITIAL_MAPPING_FLAG_DEVICE (0x4) +#define MMU_INITIAL_MAPPING_FLAG_DYNAMIC (0x8) /* entry has to be patched up by platform_reset */ + +#ifndef ASSEMBLY + +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +#define PAGE_ALIGN(x) ALIGN((x), PAGE_SIZE) +#define ROUNDUP_PAGE_SIZE(x) ROUNDUP((x), PAGE_SIZE) +#define IS_PAGE_ALIGNED(x) IS_ALIGNED((x), PAGE_SIZE) + +struct mmu_initial_mapping { + paddr_t phys; + vaddr_t virt; + size_t size; + unsigned int flags; + const char* name; +}; + +/* Assert that the assembly macros above match this struct. */ +STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, phys) == __MMU_INITIAL_MAPPING_PHYS_OFFSET); +STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, virt) == __MMU_INITIAL_MAPPING_VIRT_OFFSET); +STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, size) == __MMU_INITIAL_MAPPING_SIZE_OFFSET); +STATIC_ASSERT(__offsetof(struct mmu_initial_mapping, flags) == __MMU_INITIAL_MAPPING_FLAGS_OFFSET); +STATIC_ASSERT(sizeof(struct mmu_initial_mapping) == __MMU_INITIAL_MAPPING_SIZE); + +/* Platform or target must fill out one of these to set up the initial memory map + * for kernel and enough IO space to boot. + */ +extern struct mmu_initial_mapping mmu_initial_mappings[]; + +/* core per page structure */ +typedef struct vm_page { + struct list_node node; + + uint8_t state; + uint8_t flags; +} vm_page_t; + +enum vm_page_state { + VM_PAGE_STATE_FREE, + VM_PAGE_STATE_ALLOC, + VM_PAGE_STATE_MMU, /* allocated to serve arch-specific mmu purposes */ +}; + +/* kernel address space */ +#ifndef KERNEL_ASPACE_BASE +#define KERNEL_ASPACE_BASE ((vaddr_t)0x80000000UL) +#endif +#ifndef KERNEL_ASPACE_SIZE +#define KERNEL_ASPACE_SIZE ((vaddr_t)0x80000000UL) +#endif + +STATIC_ASSERT(KERNEL_ASPACE_BASE + (KERNEL_ASPACE_SIZE - 1) > KERNEL_ASPACE_BASE); + +static inline bool is_kernel_address(vaddr_t va) { + return (va >= (vaddr_t)KERNEL_ASPACE_BASE && + va <= ((vaddr_t)KERNEL_ASPACE_BASE + ((vaddr_t)KERNEL_ASPACE_SIZE - 1))); +} + +/* user address space, defaults to below kernel space with a 16MB guard gap on either side */ +#ifndef USER_ASPACE_BASE +#define USER_ASPACE_BASE ((vaddr_t)0x01000000UL) +#endif +#ifndef USER_ASPACE_SIZE +#define USER_ASPACE_SIZE ((vaddr_t)KERNEL_ASPACE_BASE - USER_ASPACE_BASE - 0x01000000UL) +#endif + +STATIC_ASSERT(USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1) > USER_ASPACE_BASE); + +static inline bool is_user_address(vaddr_t va) { + return (va >= USER_ASPACE_BASE && va <= (USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1))); +} + +/* physical allocator */ +typedef struct pmm_arena { + struct list_node node; + const char* name; + + uint flags; + uint priority; + + paddr_t base; + size_t size; + + size_t free_count; + + struct vm_page* page_array; + struct list_node free_list; +} pmm_arena_t; + +#define PMM_ARENA_FLAG_KMAP (0x1) /* this arena is already mapped and useful for kallocs */ + +/* Add a pre-filled memory arena to the physical allocator. */ +status_t pmm_add_arena(pmm_arena_t* arena) __NONNULL((1)); + +/* flags for allocation routines below */ +#define PMM_ALLOC_FLAG_ANY (0x0) /* no restrictions on which arena to allocate from */ +#define PMM_ALLOC_FLAG_KMAP (0x1) /* allocate only from arenas marked KMAP */ + +/* Allocate count pages of physical memory, adding to the tail of the passed list. + * The list must be initialized. + * Returns the number of pages allocated. + */ +size_t pmm_alloc_pages(size_t count, uint alloc_flags, struct list_node* list) __NONNULL((3)); + +/* Allocate a single page of physical memory. + */ +vm_page_t* pmm_alloc_page(uint alloc_flags, paddr_t* pa); + +/* Allocate a specific range of physical pages, adding to the tail of the passed list. + * Returns the number of pages allocated. + */ +size_t pmm_alloc_range(paddr_t address, size_t count, struct list_node* list); + +/* Allocate a run of contiguous pages, aligned on log2 byte boundary (0-31) + * If the optional physical address pointer is passed, return the address. + * If the optional list is passed, append the allocate page structures to the tail of the list. + */ +size_t pmm_alloc_contiguous(size_t count, uint alloc_flags, uint8_t align_log2, paddr_t* pa, + struct list_node* list); + +/* Free a list of physical pages. + * Returns the number of pages freed. + */ +size_t pmm_free(struct list_node* list) __NONNULL((1)); + +/* Helper routine for the above. */ +size_t pmm_free_page(vm_page_t* page) __NONNULL((1)); + +/* Allocate a run of pages out of the kernel area and return the pointer in kernel space. + * If the optional list is passed, append the allocate page structures to the tail of the list. + * If the optional physical address pointer is passed, return the address. + */ +void* pmm_alloc_kpages(size_t count, struct list_node* list, paddr_t* pa); + +/* Same as above but a single page at a time */ +void* pmm_alloc_kpage(paddr_t* pa); + +size_t pmm_free_kpages(void* ptr, size_t count); + +/* physical to virtual */ +void* paddr_to_kvaddr(paddr_t pa); + +/* virtual to physical */ +paddr_t vaddr_to_paddr(void* va); + +/* vm_page_t to physical address */ +paddr_t vm_page_to_paddr(const vm_page_t* page); + +/* paddr to vm_page_t */ +vm_page_t* paddr_to_vm_page(paddr_t addr); + +/* C friendly opaque handle to the internals of the VMM. + * Never defined, just used as a handle for C apis. + */ +typedef struct vmm_aspace vmm_aspace_t; + +/* grab a handle to the kernel address space */ +vmm_aspace_t* vmm_get_kernel_aspace(void); + +/* virtual to container address space */ +struct vmm_aspace* vaddr_to_aspace(void* ptr); + +/* retrieve the arch-specific information for this aspace */ +arch_aspace_t* vmm_get_arch_aspace(vmm_aspace_t* aspace); + +/* reserve a chunk of address space to prevent allocations from that space */ +status_t vmm_reserve_space(vmm_aspace_t* aspace, const char* name, size_t size, vaddr_t vaddr) + __NONNULL((1)); + +/* For region creation routines */ +#define VMM_FLAG_VALLOC_SPECIFIC (1 << 0) /* allocate at specific address */ +#define VMM_FLAG_COMMIT (1 << 1) /* commit memory up front (no demand paging) */ + +/* allocate a region of virtual space that maps a physical piece of address space. + the physical pages that back this are not allocated from the pmm. */ +status_t vmm_alloc_physical(vmm_aspace_t* aspace, const char* name, size_t size, void** ptr, + uint8_t align_log2, paddr_t paddr, uint vmm_flags, uint arch_mmu_flags) + __NONNULL((1)); + +/* allocate a region of memory backed by newly allocated contiguous physical memory */ +status_t vmm_alloc_contiguous(vmm_aspace_t* aspace, const char* name, size_t size, void** ptr, + uint8_t align_log2, uint vmm_flags, uint arch_mmu_flags) + __NONNULL((1)); + +/* allocate a region of memory backed by newly allocated physical memory */ +status_t vmm_alloc(vmm_aspace_t* aspace, const char* name, size_t size, void** ptr, + uint8_t align_log2, uint vmm_flags, uint arch_mmu_flags) __NONNULL((1)); + +/* Unmap previously allocated region and free physical memory pages backing it (if any) */ +status_t vmm_free_region(vmm_aspace_t* aspace, vaddr_t va); + +/* Change the base physical address of a previously allocated region */ +status_t vmm_move_region_phys(vmm_aspace_t* aspace, vaddr_t va, paddr_t paddr); + +/* Change permissions on a previously allocated region */ +status_t vmm_protect_region(vmm_aspace_t* aspace, vaddr_t va, uint arch_mmu_flags); + +#define VMM_ASPACE_TYPE_USER (0 << 0) +#define VMM_ASPACE_TYPE_KERNEL (1 << 0) +#define VMM_ASPACE_TYPE_LOW_KERNEL (2 << 0) +#define VMM_ASPACE_TYPE_MASK (3 << 0) +/* allocate a new address space */ +status_t vmm_create_aspace(vmm_aspace_t** aspace, const char* name, uint flags) __NONNULL((1)); + +/* destroy everything in the address space */ +status_t vmm_free_aspace(vmm_aspace_t* aspace) __NONNULL((1)); + +/* internal kernel routines below, do not call directly */ + +/* internal routine by the scheduler to swap mmu contexts */ +void vmm_context_switch(vmm_aspace_t* oldspace, vmm_aspace_t* newaspace); + +/* set the current user aspace as active on the current thread. + NULL is a valid argument, which unmaps the current user address space */ +void vmm_set_active_aspace(vmm_aspace_t* aspace); + +/* page fault handler, called during page fault context, with interrupts enabled */ +#define VMM_PF_FLAG_WRITE (1u << 0) +#define VMM_PF_FLAG_USER (1u << 1) +#define VMM_PF_FLAG_INSTRUCTION (1u << 2) +status_t vmm_page_fault_handler(vaddr_t addr, uint flags); + +__END_CDECLS + +#endif // !ASSEMBLY diff --git a/kernel/include/kernel/vm/vm_aspace.h b/kernel/include/kernel/vm/vm_aspace.h new file mode 100644 index 000000000..da176c817 --- /dev/null +++ b/kernel/include/kernel/vm/vm_aspace.h @@ -0,0 +1,155 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class VmRegion; +class VmObject; + +class VmAspace : public utils::RefCounted { +public: + // complete initialization, may fail in OOM cases + status_t Init(); + + // factory that creates a user/kernel address space based on flags + // may fail due to resource starvation + static utils::RefPtr Create(uint flags, const char* name); + + void Rename(const char* name); + + // flags + static const uint32_t TYPE_USER = VMM_ASPACE_TYPE_USER; + static const uint32_t TYPE_KERNEL = VMM_ASPACE_TYPE_KERNEL; + // You probably do not want to use LOW_KERNEL. It is primarily + // used for SMP bootstrap to allow mappings of very low memory using + // the standard VMM subsystem. + static const uint32_t TYPE_LOW_KERNEL = VMM_ASPACE_TYPE_LOW_KERNEL; + static const uint32_t TYPE_MASK = VMM_ASPACE_TYPE_MASK; + + // simple accessors + vaddr_t base() const { return base_; } + size_t size() const { return size_; } + arch_aspace_t& arch_aspace() { return arch_aspace_; } + bool is_user() const { return (flags_ & TYPE_MASK) == TYPE_USER; } + + // global aspace list + void list_set_prev(VmAspace* node) { prev_ = node; } + void list_set_next(VmAspace* node) { next_ = node; } + VmAspace* list_prev() { return prev_; } + VmAspace* list_next() { return next_; } + + // map a vm object at a given offset + status_t MapObject(utils::RefPtr vmo, const char* name, uint64_t offset, size_t size, + void** ptr, uint8_t align_pow2, uint vmm_flags, uint arch_mmu_flags); + + // common routines, mostly used by internal kernel code + + // create a blank map of vm address space + status_t ReserveSpace(const char* name, size_t size, vaddr_t vaddr); + + // allocate a vm region mapping a physical range of memory + status_t AllocPhysical(const char* name, size_t size, void** ptr, uint8_t align_pow2, + paddr_t paddr, uint vmm_flags, uint arch_mmu_flags); + + // allocate a block of virtual memory + status_t Alloc(const char* name, size_t size, void** ptr, uint8_t align_pow2, uint vmm_flags, + uint arch_mmu_flags); + + // allocate a block of virtual memory with physically contiguous backing pages + status_t AllocContiguous(const char* name, size_t size, void** ptr, uint8_t align_pow2, + uint vmm_flags, uint arch_mmu_flags); + + // return a pointer to a region based on virtual address + utils::RefPtr FindRegion(vaddr_t vaddr); + + // free the region at a given address + status_t FreeRegion(vaddr_t vaddr); + + // destroy but not free the address space + status_t Destroy(); + + // accessor for singleton kernel address space + static VmAspace* kernel_aspace() { + return kernel_aspace_; + } + + // set the per thread aspace pointer to this + void AttachToThread(thread_t* t); + + void Dump(); + +private: + // nocopy + VmAspace(const VmAspace&) = delete; + VmAspace& operator=(const VmAspace&) = delete; + + // can only be constructed via factory + VmAspace(vaddr_t base, size_t size, uint32_t flags, const char* name); + + // private destructor that can only be used from the ref ptr or vmm_free_aspace + ~VmAspace(); + friend utils::RefPtr; + friend status_t vmm_free_aspace(vmm_aspace_t* _aspace); + + // internal page fault routine, friended to be only called by vmm_page_fault_handler + status_t PageFault(vaddr_t va, uint flags); + friend status_t vmm_page_fault_handler(vaddr_t va, uint flags); + + // private internal routines + status_t AddRegion(utils::RefPtr r); + utils::RefPtr AllocRegion(const char* name, size_t size, vaddr_t vaddr, + uint8_t align_pow2, uint32_t vmm_flags, + uint arch_mmu_flags); + vaddr_t AllocSpot(size_t size, uint8_t align_pow2, uint arch_mmu_flags, VmRegion** before); + VmRegion* FindRegionLocked(vaddr_t vaddr); + + // magic + static const uint32_t MAGIC = 0x564d4153; // VMAS + uint32_t magic_ = MAGIC; + + // members + vaddr_t base_; + size_t size_; + uint32_t flags_; + char name_[32]; + + mutex_t lock_ = MUTEX_INITIAL_VALUE(lock_); + + // pointers for the global list of aspaces + VmAspace* prev_ = nullptr; + VmAspace* next_ = nullptr; + + // sorted list of regions + utils::DoublyLinkedList regions_; + + // architecturally specific part of the aspace + arch_aspace_t arch_aspace_ = {}; + + // initialization routines need to construct the singleton kernel address space + // at a particular points in the bootup process + static void KernelAspaceInit(); + static VmAspace* kernel_aspace_; + friend void vm_init_preheap(uint level); +}; + +void DumpAllAspaces(); + +// hack to convert from vmm_aspace_t to VmAspace +static VmAspace* vmm_aspace_to_obj(vmm_aspace_t* aspace) { + return reinterpret_cast(aspace); +} + +static const VmAspace* vmm_aspace_to_obj(const vmm_aspace_t* aspace) { + return reinterpret_cast(aspace); +} diff --git a/kernel/include/kernel/vm/vm_object.h b/kernel/include/kernel/vm/vm_object.h new file mode 100644 index 000000000..3d025aba7 --- /dev/null +++ b/kernel/include/kernel/vm/vm_object.h @@ -0,0 +1,96 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +// The base vm object that holds a range of bytes of data +// +// Can be created without mapping and used as a container of data, or mappable +// into an address space via VmAspace::MapObject + +class VmObject : public utils::RefCounted { +public: + static utils::RefPtr Create(uint32_t pmm_alloc_flags, uint64_t size); + + status_t Resize(uint64_t size); + + uint64_t size() const { return size_; } + + // add a page to the object + status_t AddPage(vm_page_t* p, uint64_t offset); + + // find physical pages to back the range of the object + int64_t CommitRange(uint64_t offset, uint64_t len); + + // find a contiguous run of physical pages to back the range of the object + int64_t CommitRangeContiguous(uint64_t offset, uint64_t len, uint8_t alignment_log2 = 0); + + // get a pointer to a page at a given offset + vm_page_t* GetPage(uint64_t offset); + + // fault in a page at a given offset with PF_FLAGS + vm_page_t* FaultPage(uint64_t offset, uint pf_flags); + + // read/write operators against kernel pointers only + status_t Read(void* ptr, uint64_t offset, size_t len, size_t* bytes_read); + status_t Write(const void* ptr, uint64_t offset, size_t len, size_t* bytes_written); + + // read/write operators against user space pointers only + status_t ReadUser(void* ptr, uint64_t offset, size_t len, size_t* bytes_read); + status_t WriteUser(const void* ptr, uint64_t offset, size_t len, size_t* bytes_written); + + void Dump(); + +private: + // kill copy constructors + VmObject(const VmObject& o) = delete; + VmObject& operator=(VmObject& o) = delete; + + // private constructor (use Create()) + explicit VmObject(uint32_t pmm_alloc_flags); + + // private destructor, only called from refptr + ~VmObject(); + friend utils::RefPtr; + + // fault in a page at a given offset with PF_FLAGS + vm_page_t* FaultPageLocked(uint64_t offset, uint pf_flags); + + // internal page list routine + void AddPageToArray(size_t index, vm_page_t* p); + + // internal read/write routine that takes a templated copy function to help share some code + template + status_t ReadWriteInternal(uint64_t offset, size_t len, size_t* bytes_copied, bool write, + T copyfunc); + + // constants + static const uint64_t MAX_SIZE = SIZE_MAX * PAGE_SIZE; + + // magic value + static const uint32_t MAGIC = 0x564d4f5f; // VMO_ + uint32_t magic_ = MAGIC; + + // members + uint64_t size_ = 0; + uint32_t pmm_alloc_flags_ = PMM_ALLOC_FLAG_ANY; + mutex_t lock_ = MUTEX_INITIAL_VALUE(lock_); + + // array of page pointers, one per page offset into the object + utils::Array page_array_; + + // list of all allocated pages + list_node page_list_ = LIST_INITIAL_VALUE(page_list_); +}; diff --git a/kernel/include/kernel/vm/vm_region.h b/kernel/include/kernel/vm/vm_region.h new file mode 100644 index 000000000..74e456d0a --- /dev/null +++ b/kernel/include/kernel/vm/vm_region.h @@ -0,0 +1,93 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +class VmAspace; +class VmObject; + +class VmRegion : public utils::RefCounted { +public: + static utils::RefPtr Create(VmAspace& aspace, vaddr_t base, size_t size, + uint arch_mmu_flags, const char* name); + ~VmRegion(); + + // accessors + vaddr_t base() const { return base_; } + size_t size() const { return size_; } + uint arch_mmu_flags() const { return arch_mmu_flags_; } + + // set base address + void set_base(vaddr_t vaddr) { base_ = vaddr; } + + // list for aspace + void list_set_prev(VmRegion* node) { prev_ = node; } + void list_set_next(VmRegion* node) { next_ = node; } + VmRegion* list_prev() { return prev_; } + VmRegion* list_next() { return next_; } + const VmRegion* list_prev() const { return prev_; } + const VmRegion* list_next() const { return next_; } + + void Dump() const; + + // set the object that this region backs + status_t SetObject(utils::RefPtr o, uint64_t offset); + + // map in pages from the underlying vm object, optionally committing pages as it goes + status_t MapRange(size_t offset, size_t len, bool commit); + + // map in a physical range of memory to this region + status_t MapPhysicalRange(size_t offset, size_t len, paddr_t paddr, bool allow_remap); + + // unmap all pages and remove dependency on vm object it has a ref to + status_t Destroy(); + + // unmap the region of memory in the container address space + int Unmap(); + + // change mapping permissions + status_t Protect(uint arch_mmu_flags); + + // page fault in an address into the region + status_t PageFault(vaddr_t va, uint pf_flags); + +private: + // private constructor, use Create() + VmRegion(VmAspace& aspace, vaddr_t base, size_t size, uint arch_mmu_flags, const char* name); + + // nocopy + VmRegion(const VmRegion&) = delete; + VmRegion& operator=(const VmRegion&) = delete; + + // magic value + static const uint32_t MAGIC = 0x564d5247; // VMRG + uint32_t magic_ = MAGIC; + + // address/size within the container address space + vaddr_t base_; + size_t size_; + + // cached mapping flags (read/write/user/etc) + uint arch_mmu_flags_; + + // pointer back to our member address space + utils::RefPtr aspace_; + + // pointer and region of the object we are mapping + utils::RefPtr object_; + uint64_t object_offset_ = 0; + + char name_[32]; + + // doubly link list stuff + VmRegion* prev_ = nullptr; + VmRegion* next_ = nullptr; +}; diff --git a/kernel/include/kernel/wait.h b/kernel/include/kernel/wait.h new file mode 100644 index 000000000..ca7e329fd --- /dev/null +++ b/kernel/include/kernel/wait.h @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_WAIT_H +#define __KERNEL_WAIT_H + +#include +#include +#include +#include +#include +#include + +__BEGIN_CDECLS; + +/* wait queue stuff */ +#define WAIT_QUEUE_MAGIC (0x77616974) // 'wait' + +typedef struct wait_queue { + int magic; + struct list_node list; + int count; +} wait_queue_t; + +#define WAIT_QUEUE_INITIAL_VALUE(q) \ +{ \ + .magic = WAIT_QUEUE_MAGIC, \ + .list = LIST_INITIAL_VALUE((q).list), \ + .count = 0 \ +} + +/* wait queue primitive */ +/* NOTE: must be inside critical section when using these */ +void wait_queue_init(wait_queue_t *wait); + +/* + * release all the threads on this wait queue with a return code of ERR_OBJECT_DESTROYED. + * the caller must assure that no other threads are operating on the wait queue during or + * after the call. + */ +void wait_queue_destroy(wait_queue_t *, bool reschedule); + +/* + * block on a wait queue. + * return status is whatever the caller of wait_queue_wake_*() specifies. + * a timeout other than INFINITE_TIME will set abort after the specified time + * and return ERR_TIMED_OUT. a timeout of 0 will immediately return. + */ +status_t wait_queue_block(wait_queue_t *, lk_time_t timeout); + +/* + * release one or more threads from the wait queue. + * reschedule = should the system reschedule if any is released. + * wait_queue_error = what wait_queue_block() should return for the blocking thread. + */ +int wait_queue_wake_one(wait_queue_t *, bool reschedule, status_t wait_queue_error); +int wait_queue_wake_all(wait_queue_t *, bool reschedule, status_t wait_queue_error); + +/* + * remove the thread from whatever wait queue it's in. + * return an error if the thread is not currently blocked (or is the current thread) + */ +status_t thread_unblock_from_wait_queue(struct thread *t, status_t wait_queue_error); + +__END_CDECLS; + +#endif + diff --git a/kernel/include/lib/bytes.h b/kernel/include/lib/bytes.h new file mode 100644 index 000000000..b4fe3a97d --- /dev/null +++ b/kernel/include/lib/bytes.h @@ -0,0 +1,58 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __BYTES_H +#define __BYTES_H + +#include +#include + +#if BYTE_ORDER == BIG_ENDIAN +#define bytes_read_u16(x) bytes_read_u16_be(x) +#define bytes_read_u24(x) bytes_read_u24_be(x) +#define bytes_read_u32(x) bytes_read_u32_be(x) +#define bytes_write_u16(x, y) bytes_write_u16_be(x, y) +#define bytes_write_u24(x, y) bytes_write_u24_be(x, y) +#define bytes_write_u32(x, y) bytes_write_u32_be(x, y) +#elif BYTE_ORDER == LITTLE_ENDIAN +#define bytes_read_u16(x) bytes_read_u16_le(x) +#define bytes_read_u24(x) bytes_read_u24_le(x) +#define bytes_read_u32(x) bytes_read_u32_le(x) +#define bytes_write_u16(x, y) bytes_write_u16_le(x, y) +#define bytes_write_u24(x, y) bytes_write_u24_le(x, y) +#define bytes_write_u32(x, y) bytes_write_u32_le(x, y) +#else +#error "Endianness not defined!" +#endif + + +// Big endian interfaces +uint16_t bytes_read_u16_be(const uint8_t *buf); +uint32_t bytes_read_u24_be(const uint8_t *buf); +uint32_t bytes_read_u32_be(const uint8_t *buf); + +uint8_t *bytes_write_u16_be(uint8_t *buf, uint16_t val); +uint8_t *bytes_write_u24_be(uint8_t *buf, uint32_t val); +uint8_t *bytes_write_u32_be(uint8_t *buf, uint32_t val); + +// Little endian interfaces +uint16_t bytes_read_u16_le(const uint8_t *buf); +uint32_t bytes_read_u24_le(const uint8_t *buf); +uint32_t bytes_read_u32_le(const uint8_t *buf); + +uint8_t *bytes_write_u16_le(uint8_t *buf, uint16_t val); +uint8_t *bytes_write_u24_le(uint8_t *buf, uint32_t val); +uint8_t *bytes_write_u32_le(uint8_t *buf, uint32_t val); + +// Bit swapping interfaces +uint8_t bytes_swap_bits_u8(uint8_t val); +uint16_t bytes_swap_bits_u16(uint16_t val); +uint32_t bytes_swap_bits_u24(uint32_t val); +uint32_t bytes_swap_bits_u32(uint32_t val); + +#endif + diff --git a/kernel/include/lib/console.h b/kernel/include/lib/console.h new file mode 100644 index 000000000..4bc427d62 --- /dev/null +++ b/kernel/include/lib/console.h @@ -0,0 +1,97 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_CONSOLE_H +#define __LIB_CONSOLE_H + +#include +#include +#include +#include + +__BEGIN_CDECLS; + +/* command args */ +typedef struct { + const char *str; + unsigned long u; + void *p; + long i; + bool b; +} cmd_args; + +typedef int (*console_cmd)(int argc, const cmd_args *argv); + +#define CMD_AVAIL_NORMAL (0x1 << 0) +#define CMD_AVAIL_PANIC (0x1 << 1) +#define CMD_AVAIL_ALWAYS (CMD_AVAIL_NORMAL | CMD_AVAIL_PANIC) + +/* a block of commands to register */ +typedef struct { + const char *cmd_str; + const char *help_str; + const console_cmd cmd_callback; + uint8_t availability_mask; +} cmd; + +typedef struct _cmd_block { + struct _cmd_block *next; + size_t count; + const cmd *list; +} cmd_block; + +/* register a static block of commands at init time */ +#if WITH_LIB_CONSOLE + +/* enable the panic shell if we're being built */ +#if !defined(ENABLE_PANIC_SHELL) && PLATFORM_SUPPORTS_PANIC_SHELL +#define ENABLE_PANIC_SHELL 1 +#endif + +#define STATIC_COMMAND_START static const cmd _cmd_list[] = { + +#define STATIC_COMMAND_END(name) }; cmd_block _cmd_block_##name __ALIGNED(sizeof(void *)) __SECTION("commands") = \ + { NULL, sizeof(_cmd_list) / sizeof(_cmd_list[0]), _cmd_list } + +#define STATIC_COMMAND_START_NAMED(name) static const cmd _cmd_list_##name[] = { + +#define STATIC_COMMAND_END_NAMED(name) }; cmd_block _cmd_block_##name __ALIGNED(sizeof(void *)) __SECTION("commands") = \ + { NULL, sizeof(_cmd_list_##name) / sizeof(_cmd_list_##name[0]), _cmd_list_##name } + +#define STATIC_COMMAND(command_str, help_str, func) { command_str, help_str, func, CMD_AVAIL_NORMAL }, +#define STATIC_COMMAND_MASKED(command_str, help_str, func, availability_mask) { command_str, help_str, func, availability_mask }, + +#else + +/* no command blocks, so null them out */ +#define STATIC_COMMAND_START +#define STATIC_COMMAND_END(name) +#define STATIC_COMMAND_START_NAMED(name) +#define STATIC_COMMAND_END_NAMED(name) + +#define STATIC_COMMAND(command_str, help_str, func) + +#endif + +#define COMMAND_BLOCK_INIT_ITEM(cmd_block_ptr, cmd_ptr) {(cmd_block_ptr)->next = NULL; (cmd_block_ptr)->count = 1; (cmd_block_ptr)->list = cmd_ptr;} + +/* external api */ +int console_init(void); +void console_start(void); +void console_register_commands(cmd_block *block); +int console_run_script(const char *string); +int console_run_script_locked(const char *string); // special case from inside a command +console_cmd console_get_command_handler(const char *command); +void console_abort_script(void); + +/* panic shell api */ +void panic_shell_start(void); + +extern int lastresult; + +__END_CDECLS; +#endif diff --git a/kernel/include/lib/dpc.h b/kernel/include/lib/dpc.h new file mode 100644 index 000000000..738d91ced --- /dev/null +++ b/kernel/include/lib/dpc.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __KERNEL_DPC_H +#define __KERNEL_DPC_H + +#include +#include + +typedef void (*dpc_callback)(void *arg); + +#define DPC_FLAG_NORESCHED 0x1 + +status_t dpc_queue(dpc_callback, void *arg, uint flags); + +#endif + diff --git a/kernel/include/lib/evlog.h b/kernel/include/lib/evlog.h new file mode 100644 index 000000000..b066ace2d --- /dev/null +++ b/kernel/include/lib/evlog.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_EVLOG_H +#define __LIB_EVLOG_H + +#include +#include + +typedef struct evlog { + uint head; + uint unitsize; + uint len_pow2; + uintptr_t *items; +} evlog_t; + +status_t evlog_init_etc(evlog_t *e, uint len, uint unitsize, uintptr_t *items); +status_t evlog_init(evlog_t *e, uint len, uint unitsize); + +/* callback to evlog_dump. */ +typedef void (*evlog_dump_cb)(const uintptr_t *); + +void evlog_dump(evlog_t *e, evlog_dump_cb cb); + +/* bump the head pointer and return the old one. + */ +uint evlog_bump_head(evlog_t *e); + +/* + * It's assumed you're following a pattern similar to the following: + * +void evlog_add2(evlog_t *e, uintptr_t a, uintptr_t b) +{ + uint index = evlog_bump_head(e); + + e->items[index] = a; + e->items[index + 1] = b; +} +*/ + +#endif + diff --git a/kernel/include/lib/font.h b/kernel/include/lib/font.h new file mode 100644 index 000000000..1c8ebef0c --- /dev/null +++ b/kernel/include/lib/font.h @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_FONT_H +#define __LIB_FONT_H + +#include + +#define FONT_X 6 +#define FONT_Y 12 + +void font_draw_char(gfx_surface *surface, unsigned char c, int x, int y, uint32_t color, uint32_t bgcolor); + +#endif + diff --git a/kernel/include/lib/gfx.h b/kernel/include/lib/gfx.h new file mode 100644 index 000000000..62b612380 --- /dev/null +++ b/kernel/include/lib/gfx.h @@ -0,0 +1,109 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_GFX_H +#define __LIB_GFX_H + +#include +#include +#include + +// gfx library + +// different graphics formats +typedef enum { + GFX_FORMAT_NONE, + GFX_FORMAT_RGB_565, + GFX_FORMAT_RGB_332, + GFX_FORMAT_RGB_2220, + GFX_FORMAT_ARGB_8888, + GFX_FORMAT_RGB_x888, + GFX_FORMAT_MONO, + + GFX_FORMAT_MAX +} gfx_format; + +#define MAX_ALPHA 255 + +// surface flags +#define GFX_FLAG_FREE_ON_DESTROY (1<<0) // free the ptr at destroy +#define GFX_FLAG_FLUSH_CPU_CACHE (1<<1) // do a cache flush during gfx_flush + +/** + * @brief Describe a graphics drawing surface + * + * The gfx_surface object represents a framebuffer that can be rendered + * to. Elements include a pointer to the actual pixel memory, its size, its + * layout, and pointers to basic drawing functions. + * + * @ingroup graphics + */ +typedef struct gfx_surface { + void *ptr; + uint32_t flags; + gfx_format format; + uint width; + uint height; + uint stride; + uint pixelsize; + size_t len; + uint alpha; + + // function pointers + uint32_t (*translate_color)(uint32_t input); + void (*copyrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint x2, uint y2); + void (*fillrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint color); + void (*putpixel)(struct gfx_surface *, uint x, uint y, uint color); + void (*flush)(uint starty, uint endy); +} gfx_surface; + +// copy a rect from x,y with width x height to x2, y2 +void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2); + +// fill a rect within the surface with a color +void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color); + +// draw a pixel at x, y in the surface +void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color); + +// draw a single pixel line between x1,y1 and x2,y1 +void gfx_line(gfx_surface *surface, uint x1, uint y1, uint x2, uint y2, uint color); + +// blend between two surfaces +void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty); + +// ensure the surface is written back to memory and optionally backing store +void gfx_flush(struct gfx_surface *surface); + +// flush a subset of the surface +void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end); + +// clear the entire surface with a color +static inline void gfx_clear(gfx_surface *surface, uint color) +{ + surface->fillrect(surface, 0, 0, surface->width, surface->height, color); + gfx_flush(surface); +} + +// surface setup +gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags); +status_t gfx_init_surface(gfx_surface *surface, void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags); + +// utility routine to make a surface out of a display info +struct display_info; +gfx_surface *gfx_create_surface_from_display(struct display_info *); +status_t gfx_init_surface_from_display(gfx_surface *surface, struct display_info *); + +// free the surface +// optionally frees the buffer if the free bit is set +void gfx_surface_destroy(struct gfx_surface *surface); + +// utility routine to fill the display with a little moire pattern +void gfx_draw_pattern(void); + +#endif + diff --git a/kernel/include/lib/gfxconsole.h b/kernel/include/lib/gfxconsole.h new file mode 100644 index 000000000..34ae37916 --- /dev/null +++ b/kernel/include/lib/gfxconsole.h @@ -0,0 +1,18 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_GFXCONSOLE_H +#define __LIB_GFXCONSOLE_H + +#include + +status_t gfxconsole_display_get_info(struct display_info *info); +void gfxconsole_start(gfx_surface *surface, gfx_surface *hw_surface); +void gfxconsole_bind_display(struct display_info *info, void *raw_sw_fb); + +#endif + diff --git a/kernel/include/lib/page_alloc.h b/kernel/include/lib/page_alloc.h new file mode 100644 index 000000000..d92898a91 --- /dev/null +++ b/kernel/include/lib/page_alloc.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_PAGE_ALLOC_H +#define __LIB_PAGE_ALLOC_H + +#include +#include +#include + +// to pick up PAGE_SIZE, PAGE_ALIGN, etc +#if WITH_KERNEL_VM +#include +#else +#include +#endif + +/* A simple page-aligned wrapper around the pmm or novm implementation of + * the underlying physical page allocator. Used by system heaps or any + * other user that wants pages of memory but doesn't want to use LK + * specific apis. + */ + +__BEGIN_CDECLS; + +void *page_alloc(size_t pages); +void page_free(void *ptr, size_t pages); + +// You can call this once at the start, and it will either return a page or it +// will return some non-page-aligned memory that would otherwise go to waste. +void *page_first_alloc(size_t *size_return); + +__END_CDECLS; + +#endif diff --git a/kernel/include/lib/partition.h b/kernel/include/lib/partition.h new file mode 100644 index 000000000..41749681c --- /dev/null +++ b/kernel/include/lib/partition.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_PARTITION_H +#define __LIB_PARTITION_H + +#include + +/* examine and try to publish partitions on a particular device at a particular offset */ +int partition_publish(const char *device, off_t offset); + +/* remove any published subdevices on this device */ +int partition_unpublish(const char *device); + +#endif + diff --git a/kernel/include/lib/ptable.h b/kernel/include/lib/ptable.h new file mode 100644 index 000000000..8f6a972c8 --- /dev/null +++ b/kernel/include/lib/ptable.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// Copyright (c) 2014, Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +#define MAX_FLASH_PTABLE_NAME_LEN 12 +#define FLASH_PTABLE_ALLOC_END 0x1 + +struct ptable_entry { + uint64_t offset; + uint64_t length; + uint32_t flags; + uint8_t name[MAX_FLASH_PTABLE_NAME_LEN]; +}; + +bool ptable_found_valid(void); +bdev_t *ptable_get_device(void); +status_t ptable_scan(const char *bdev_name, uint64_t offset); +status_t ptable_find(const char *name, struct ptable_entry *entry) __NONNULL((1)); +status_t ptable_create_default(const char *bdev_name, uint64_t offset) __NONNULL(); +status_t ptable_add(const char *name, uint64_t min_len, uint32_t flags) __NONNULL(); +status_t ptable_remove(const char *name) __NONNULL(); +void ptable_dump(void); diff --git a/kernel/include/lib/sysparam.h b/kernel/include/lib/sysparam.h new file mode 100644 index 000000000..cd9b24237 --- /dev/null +++ b/kernel/include/lib/sysparam.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +#ifndef SYSPARAM_ALLOW_WRITE +#define SYSPARAM_ALLOW_WRITE 0 +#endif + +status_t sysparam_scan(bdev_t *bdev, off_t offset, size_t len); +status_t sysparam_reload(void); + +void sysparam_dump(bool show_all); + +ssize_t sysparam_length(const char *name); +ssize_t sysparam_read(const char *name, void *data, size_t len); +status_t sysparam_get_ptr(const char *name, const void **ptr, size_t *len); + +#if SYSPARAM_ALLOW_WRITE +status_t sysparam_add(const char *name, const void *value, size_t len); +status_t sysparam_remove(const char *name); +status_t sysparam_lock(const char *name); +status_t sysparam_write(void); +#endif + diff --git a/kernel/include/lib/text.h b/kernel/include/lib/text.h new file mode 100644 index 000000000..7627b8ae9 --- /dev/null +++ b/kernel/include/lib/text.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_TEXT_H +#define __LIB_TEXT_H + +#include + +/* super cheezy mechanism to stick lines of text up on top of whatever is being drawn */ +/* XXX replace with something more generic later */ +void text_draw(int x, int y, const char *string); + +/* super dumb, someone has to call this to refresh everything */ +void text_update(void); + +#endif + diff --git a/kernel/include/list.h b/kernel/include/list.h new file mode 100644 index 000000000..57550517e --- /dev/null +++ b/kernel/include/list.h @@ -0,0 +1,272 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIST_H +#define __LIST_H + +#include +#include +#include + +__BEGIN_CDECLS; + +#define containerof(ptr, type, member) \ + ((type *)((addr_t)(ptr) - offsetof(type, member))) + +struct list_node { + struct list_node *prev; + struct list_node *next; +}; + +#define LIST_INITIAL_VALUE(list) { &(list), &(list) } +#define LIST_INITIAL_CLEARED_VALUE { NULL, NULL } + +static inline void list_initialize(struct list_node *list) +{ + list->prev = list->next = list; +} + +static inline void list_clear_node(struct list_node *item) +{ + item->prev = item->next = 0; +} + +static inline bool list_in_list(const struct list_node *item) +{ + if (item->prev == 0 && item->next == 0) + return false; + else + return true; +} + +static inline void list_add_head(struct list_node *list, struct list_node *item) +{ + item->next = list->next; + item->prev = list; + list->next->prev = item; + list->next = item; +} + +#define list_add_after(entry, new_entry) list_add_head(entry, new_entry) + +static inline void list_add_tail(struct list_node *list, struct list_node *item) +{ + item->prev = list->prev; + item->next = list; + list->prev->next = item; + list->prev = item; +} + +#define list_add_before(entry, new_entry) list_add_tail(entry, new_entry) + +static inline void list_delete(struct list_node *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; + item->prev = item->next = 0; +} + +static inline struct list_node *list_remove_head(struct list_node *list) +{ + if (list->next != list) { + struct list_node *item = list->next; + list_delete(item); + return item; + } else { + return NULL; + } +} + +#define list_remove_head_type(list, type, element) ({\ + struct list_node *__nod = list_remove_head(list);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_remove_tail(struct list_node *list) +{ + if (list->prev != list) { + struct list_node *item = list->prev; + list_delete(item); + return item; + } else { + return NULL; + } +} + +#define list_remove_tail_type(list, type, element) ({\ + struct list_node *__nod = list_remove_tail(list);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_peek_head(struct list_node *list) +{ + if (list->next != list) { + return list->next; + } else { + return NULL; + } +} + +#define list_peek_head_type(list, type, element) ({\ + struct list_node *__nod = list_peek_head(list);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_peek_tail(struct list_node *list) +{ + if (list->prev != list) { + return list->prev; + } else { + return NULL; + } +} + +#define list_peek_tail_type(list, type, element) ({\ + struct list_node *__nod = list_peek_tail(list);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_prev(struct list_node *list, struct list_node *item) +{ + if (item->prev != list) + return item->prev; + else + return NULL; +} + +#define list_prev_type(list, item, type, element) ({\ + struct list_node *__nod = list_prev(list, item);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_prev_wrap(struct list_node *list, struct list_node *item) +{ + if (item->prev != list) + return item->prev; + else if (item->prev->prev != list) + return item->prev->prev; + else + return NULL; +} + +#define list_prev_wrap_type(list, item, type, element) ({\ + struct list_node *__nod = list_prev_wrap(list, item);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_next(struct list_node *list, struct list_node *item) +{ + if (item->next != list) + return item->next; + else + return NULL; +} + +#define list_next_type(list, item, type, element) ({\ + struct list_node *__nod = list_next(list, item);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +static inline struct list_node *list_next_wrap(struct list_node *list, struct list_node *item) +{ + if (item->next != list) + return item->next; + else if (item->next->next != list) + return item->next->next; + else + return NULL; +} + +#define list_next_wrap_type(list, item, type, element) ({\ + struct list_node *__nod = list_next_wrap(list, item);\ + type *__t;\ + if(__nod)\ + __t = containerof(__nod, type, element);\ + else\ + __t = (type *)0;\ + __t;\ +}) + +// iterates over the list, node should be struct list_node* +#define list_for_every(list, node) \ + for(node = (list)->next; node != (list); node = node->next) + +// iterates over the list in a safe way for deletion of current node +// node and temp_node should be struct list_node* +#define list_for_every_safe(list, node, temp_node) \ + for(node = (list)->next, temp_node = (node)->next;\ + node != (list);\ + node = temp_node, temp_node = (node)->next) + +// iterates over the list, entry should be the container structure type * +#define list_for_every_entry(list, entry, type, member) \ + for((entry) = containerof((list)->next, type, member);\ + &(entry)->member != (list);\ + (entry) = containerof((entry)->member.next, type, member)) + +// iterates over the list in a safe way for deletion of current node +// entry and temp_entry should be the container structure type * +#define list_for_every_entry_safe(list, entry, temp_entry, type, member) \ + for(entry = containerof((list)->next, type, member),\ + temp_entry = containerof((entry)->member.next, type, member);\ + &(entry)->member != (list);\ + entry = temp_entry, temp_entry = containerof((temp_entry)->member.next, type, member)) + +static inline bool list_is_empty(struct list_node *list) +{ + return (list->next == list) ? true : false; +} + +static inline size_t list_length(struct list_node *list) +{ + size_t cnt = 0; + struct list_node *node = list; + list_for_every(list, node) { + cnt++; + } + + return cnt; +} + +__END_CDECLS; + +#endif diff --git a/kernel/include/lk/init.h b/kernel/include/lk/init.h new file mode 100644 index 000000000..030832ad9 --- /dev/null +++ b/kernel/include/lk/init.h @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +/* + * LK's init system + */ + +typedef void (*lk_init_hook)(uint level); + +enum lk_init_level { + LK_INIT_LEVEL_EARLIEST = 1, + + LK_INIT_LEVEL_ARCH_EARLY = 0x10000, + LK_INIT_LEVEL_PLATFORM_EARLY = 0x20000, + LK_INIT_LEVEL_TARGET_EARLY = 0x30000, + LK_INIT_LEVEL_HEAP = 0x40000, + LK_INIT_LEVEL_VM = 0x50000, + LK_INIT_LEVEL_KERNEL = 0x60000, + LK_INIT_LEVEL_THREADING = 0x70000, + LK_INIT_LEVEL_ARCH = 0x80000, + LK_INIT_LEVEL_PLATFORM = 0x90000, + LK_INIT_LEVEL_TARGET = 0xa0000, + LK_INIT_LEVEL_APPS = 0xb0000, + + LK_INIT_LEVEL_LAST = UINT_MAX, +}; + +enum lk_init_flags { + LK_INIT_FLAG_PRIMARY_CPU = 0x1, + LK_INIT_FLAG_SECONDARY_CPUS = 0x2, + LK_INIT_FLAG_ALL_CPUS = LK_INIT_FLAG_PRIMARY_CPU | LK_INIT_FLAG_SECONDARY_CPUS, + LK_INIT_FLAG_CPU_SUSPEND = 0x4, + LK_INIT_FLAG_CPU_RESUME = 0x8, +}; + +void lk_init_level(enum lk_init_flags flags, uint start_level, uint stop_level); + +static inline void lk_primary_cpu_init_level(uint start_level, uint stop_level) +{ + lk_init_level(LK_INIT_FLAG_PRIMARY_CPU, start_level, stop_level); +} + +static inline void lk_init_level_all(enum lk_init_flags flags) +{ + lk_init_level(flags, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_LAST); +} + +struct lk_init_struct { + uint level; + uint flags; + lk_init_hook hook; + const char *name; +}; + +#define LK_INIT_HOOK_FLAGS(_name, _hook, _level, _flags) \ + extern const struct lk_init_struct _init_struct_##_name; \ + const struct lk_init_struct _init_struct_##_name __ALIGNED(sizeof(void *)) __SECTION("lk_init") = { \ + .level = _level, \ + .flags = _flags, \ + .hook = _hook, \ + .name = #_name, \ + }; + +#define LK_INIT_HOOK(_name, _hook, _level) \ + LK_INIT_HOOK_FLAGS(_name, _hook, _level, LK_INIT_FLAG_PRIMARY_CPU) + +__END_CDECLS diff --git a/kernel/include/lk/main.h b/kernel/include/lk/main.h new file mode 100644 index 000000000..bc684b5b1 --- /dev/null +++ b/kernel/include/lk/main.h @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + + +void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3) __NO_RETURN __EXTERNALLY_VISIBLE; +void lk_secondary_cpu_entry(void); +void lk_init_secondary_cpus(uint secondary_cpu_count); diff --git a/kernel/include/platform.h b/kernel/include/platform.h new file mode 100644 index 000000000..b9a8eb1a3 --- /dev/null +++ b/kernel/include/platform.h @@ -0,0 +1,74 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_H +#define __PLATFORM_H + +#include +#include + +__BEGIN_CDECLS; + +typedef enum { + HALT_ACTION_HALT = 0, // Spin forever. + HALT_ACTION_REBOOT, // Reset the CPU. + HALT_ACTION_SHUTDOWN, // Shutdown and power off. +} platform_halt_action; + +typedef enum { + HALT_REASON_UNKNOWN = 0, + HALT_REASON_POR, // Cold-boot + HALT_REASON_HW_WATCHDOG, // HW watchdog timer + HALT_REASON_LOWVOLTAGE, // LV/Brownout condition + HALT_REASON_HIGHVOLTAGE, // High voltage condition. + HALT_REASON_THERMAL, // Thermal reason (probably overtemp) + HALT_REASON_OTHER_HW, // Other hardware (platform) specific reason + HALT_REASON_SW_RESET, // Generic Software Initiated Reboot + HALT_REASON_SW_WATCHDOG, // Reboot triggered by a SW watchdog timer + HALT_REASON_SW_PANIC, // Reboot triggered by a SW panic or ASSERT + HALT_REASON_SW_UPDATE, // SW triggered reboot in order to begin firmware update +} platform_halt_reason; + +lk_time_t current_time(void); +lk_bigtime_t current_time_hires(void); + +/* super early platform initialization, before almost everything */ +void platform_early_init(void); + +/* later init, after the kernel has come up */ +void platform_init(void); + +/* called by the arch init code to get the platform to set up any mmu mappings it may need */ +void platform_init_mmu_mappings(void); + +/* if the platform has knowledge of what caused the latest reboot, it can report + * it to applications with this function. */ +platform_halt_reason platform_get_reboot_reason(void); + +/* platform_halt is a method which is called from various places in the LK + * system, and may be implemented by platforms and called by applications. This + * call represents the end of the life of SW for a device; there is no returning + * from this function. Callers will provide a reason for the halt, and a + * suggested action for the platform to take, but it is the platform's + * responsibility to determine the final action taken. For example, in the case + * of a failed ASSERT or a panic, LK will call platform halt and suggest a Halt + * action, but a release build on a platform with no debug channel may choose to + * reboot instead as there is no one to tell about the ASSERT, and no one + * waiting to debug the device in its halted state. If not overloaded by the + * platform, the default behavior of platform halt will be to dprintf the + * reason, and then halt execution by turning off interrupts and spinning + * forever. + */ +void platform_halt(platform_halt_action suggested_action, + platform_halt_reason reason) __NO_RETURN; + +/* called during chain loading to make sure drivers and platform is put into a stopped state */ +void platform_quiesce(void); + +__END_CDECLS; + +#endif diff --git a/kernel/include/platform/debug.h b/kernel/include/platform/debug.h new file mode 100644 index 000000000..231e5e02d --- /dev/null +++ b/kernel/include/platform/debug.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_DEBUG_H +#define __PLATFORM_DEBUG_H + +#include +#include +#include +#include + +__BEGIN_CDECLS + +void platform_dputc(char c); +int platform_dgetc(char *c, bool wait); + +// Should be available even if the system has panicked. +void platform_pputc(char c); +int platform_pgetc(char *c, bool wait); + +__END_CDECLS + +#endif + diff --git a/kernel/include/platform/timer.h b/kernel/include/platform/timer.h new file mode 100644 index 000000000..cf65fded3 --- /dev/null +++ b/kernel/include/platform/timer.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_TIMER_H +#define __PLATFORM_TIMER_H + +#include + +typedef enum handler_return (*platform_timer_callback)(void *arg, lk_time_t now); + +status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval); + +#if PLATFORM_HAS_DYNAMIC_TIMER +status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval); +void platform_stop_timer(void); +#endif + +#endif + diff --git a/kernel/include/pow2.h b/kernel/include/pow2.h new file mode 100644 index 000000000..2bbdbacdc --- /dev/null +++ b/kernel/include/pow2.h @@ -0,0 +1,79 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __POW2_H +#define __POW2_H + +#include +#include +#include +#include + +__BEGIN_CDECLS + +/* routines for dealing with power of 2 values for efficiency */ +static inline __ALWAYS_INLINE bool ispow2(uint val) +{ + return ((val - 1) & val) == 0; +} + +static inline __ALWAYS_INLINE uint log2_uint(uint val) +{ + if (val == 0) + return 0; // undefined + + return (uint)(sizeof(val) * 8) - 1 - __builtin_clz(val); +} + +static inline __ALWAYS_INLINE uint log2_uint_roundup(uint val) +{ + if (val == 0) + return 0; // undefined + + // log2 of anything greater than a uint with just the MSB set will round up + // to number-of-bits-in-uint. + if (val > (1u << ((sizeof(val) * 8) - 1))) + return (sizeof(val) * 8); + + val = (val << 1) - 1; + + return (uint)(sizeof(val) * 8) - 1 - __builtin_clz(val); +} + +static inline __ALWAYS_INLINE uint valpow2(uint valp2) +{ + return 1U << valp2; +} + +static inline __ALWAYS_INLINE uint divpow2(uint val, uint divp2) +{ + return val >> divp2; +} + +static inline __ALWAYS_INLINE uint modpow2(uint val, uint modp2) +{ + return val & ((1U << modp2) - 1); +} + +// Cribbed from: +// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 +static inline __ALWAYS_INLINE uint32_t round_up_pow2_u32(uint32_t v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +__END_CDECLS + +#endif + diff --git a/kernel/include/reg.h b/kernel/include/reg.h new file mode 100644 index 000000000..28d82edbb --- /dev/null +++ b/kernel/include/reg.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __REG_H +#define __REG_H + +#include + +/* low level macros for accessing memory mapped hardware registers */ +#define REG64(addr) ((volatile uint64_t *)(uintptr_t)(addr)) +#define REG32(addr) ((volatile uint32_t *)(uintptr_t)(addr)) +#define REG16(addr) ((volatile uint16_t *)(uintptr_t)(addr)) +#define REG8(addr) ((volatile uint8_t *)(uintptr_t)(addr)) + +#define RMWREG64(addr, startbit, width, val) *REG64(addr) = (*REG64(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) +#define RMWREG32(addr, startbit, width, val) *REG32(addr) = (*REG32(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) +#define RMWREG16(addr, startbit, width, val) *REG16(addr) = (*REG16(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) +#define RMWREG8(addr, startbit, width, val) *REG8(addr) = (*REG8(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) + +#define writel(v, a) (*REG32(a) = (v)) +#define readl(a) (*REG32(a)) +#define writew(v, a) (*REG16(a) = (v)) +#define readw(a) (*REG16(a)) +#define writeb(v, a) (*REG8(a) = (v)) +#define readb(a) (*REG8(a)) + +#endif diff --git a/kernel/include/sys/types.h b/kernel/include/sys/types.h new file mode 100644 index 000000000..147f2373c --- /dev/null +++ b/kernel/include/sys/types.h @@ -0,0 +1,65 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __SYS_TYPES_H +#define __SYS_TYPES_H + +#include +#include +#include + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +typedef long long off_t; + +typedef int status_t; + +typedef uintptr_t addr_t; +typedef uintptr_t vaddr_t; +typedef uintptr_t paddr_t; + +typedef int kobj_id; + +typedef uint32_t lk_time_t; +typedef unsigned long long lk_bigtime_t; +#define INFINITE_TIME UINT32_MAX + +#define TIME_GTE(a, b) ((int32_t)((a) - (b)) >= 0) +#define TIME_LTE(a, b) ((int32_t)((a) - (b)) <= 0) +#define TIME_GT(a, b) ((int32_t)((a) - (b)) > 0) +#define TIME_LT(a, b) ((int32_t)((a) - (b)) < 0) + +enum handler_return { + INT_NO_RESCHEDULE = 0, + INT_RESCHEDULE, +}; + +typedef signed long int ssize_t; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + +#endif diff --git a/kernel/include/target.h b/kernel/include/target.h new file mode 100644 index 000000000..64963560c --- /dev/null +++ b/kernel/include/target.h @@ -0,0 +1,36 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __TARGET_H +#define __TARGET_H + +#include +#include + +__BEGIN_CDECLS; + +/* super early platform initialization, before almost everything */ +void target_early_init(void); + +/* later init, after the kernel has come up */ +void target_init(void); + +/* called during chain loading to make sure target specific bits are put into a stopped state */ +void target_quiesce(void); + +/* a target can optionally define a set of debug leds that can be used + * in various locations in the system. + */ +#if TARGET_HAS_DEBUG_LED +void target_set_debug_led(unsigned int led, bool on); +#else +#define target_set_debug_led(led, on) ((void)(0)) +#endif + +__END_CDECLS; + +#endif diff --git a/kernel/include/trace.h b/kernel/include/trace.h new file mode 100644 index 000000000..a47f12a4b --- /dev/null +++ b/kernel/include/trace.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __TRACE_H +#define __TRACE_H + +#include + +//#define __FUNC__ __PRETTY_FUNCTION__ +#define __FUNC__ __func__ + +/* trace routines */ +#define TRACE_ENTRY printf("%s: entry\n", __FUNC__) +#define TRACE_EXIT printf("%s: exit\n", __FUNC__) +#define TRACE_ENTRY_OBJ printf("%s: entry obj %p\n", __FUNC__, this) +#define TRACE_EXIT_OBJ printf("%s: exit obj %p\n", __FUNC__, this) +#define TRACE printf("%s:%d\n", __FUNC__, __LINE__) +#define TRACEF(str, x...) do { printf("%s:%d: " str, __FUNC__, __LINE__, ## x); } while (0) + +/* trace routines that work if LOCAL_TRACE is set */ +#define LTRACE_ENTRY do { if (LOCAL_TRACE) { TRACE_ENTRY; } } while (0) +#define LTRACE_EXIT do { if (LOCAL_TRACE) { TRACE_EXIT; } } while (0) +#define LTRACE_ENTRY_OBJ do { if (LOCAL_TRACE) { TRACE_ENTRY_OBJ; } } while (0) +#define LTRACE_EXIT_OBJ do { if (LOCAL_TRACE) { TRACE_EXIT_OBJ; } } while (0) +#define LTRACE do { if (LOCAL_TRACE) { TRACE; } } while (0) +#define LTRACEF(x...) do { if (LOCAL_TRACE) { TRACEF(x); } } while (0) +#define LTRACEF_LEVEL(level, x...) do { if (LOCAL_TRACE >= (level)) { TRACEF(x); } } while (0) + +#endif diff --git a/kernel/kernel/BUILD.gn b/kernel/kernel/BUILD.gn new file mode 100644 index 000000000..243c56a4b --- /dev/null +++ b/kernel/kernel/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_vm") { + if (enable_vm) { + defines = [ "WITH_KERNEL_VM=1" ] + } else { + defines = [ "WITH_KERNEL_VM=0" ] + } +} + +module("kernel") { + configs += [ ":enable_vm" ] + sources = [ + "cond.c", + "debug.c", + "event.c", + "init.c", + "mp.c", + "mutex.c", + "port.c", + "semaphore.c", + "thread.c", + "timer.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/debug", + "//kernel/lib/heap", + "//kernel/lib/libc", + ] + if (enable_klog) { + deps += [ "//kernel/lib/klog" ] + } + if (enable_vm) { + deps += [ "vm" ] + } else { + deps += [ "novm" ] + } +} diff --git a/kernel/kernel/cond.c b/kernel/kernel/cond.c new file mode 100644 index 000000000..24d75fc03 --- /dev/null +++ b/kernel/kernel/cond.c @@ -0,0 +1,62 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include + +void cond_init(cond_t *cond) +{ + *cond = (cond_t)COND_INITIAL_VALUE(*cond); +} + +void cond_destroy(cond_t *cond) +{ + DEBUG_ASSERT(cond->magic == COND_MAGIC); + + THREAD_LOCK(state); + + cond->magic = 0; + wait_queue_destroy(&cond->wait, true); + + THREAD_UNLOCK(state); +} + +status_t cond_wait_timeout(cond_t *cond, mutex_t *mutex, lk_time_t timeout) +{ + DEBUG_ASSERT(cond->magic == COND_MAGIC); + DEBUG_ASSERT(mutex->magic == MUTEX_MAGIC); + + THREAD_LOCK(state); + + // We specifically want reschedule=false here, otherwise the + // combination of releasing the mutex and enqueuing the current thread + // would not be atomic, which would mean that we could miss wakeups. + mutex_release_internal(mutex, /* reschedule= */ false); + + status_t result = wait_queue_block(&cond->wait, timeout); + + mutex_acquire_timeout_internal(mutex, INFINITE_TIME); + + THREAD_UNLOCK(state); + + return result; +} + +void cond_signal(cond_t *cond) +{ + DEBUG_ASSERT(cond->magic == COND_MAGIC); + + THREAD_LOCK(state); + + wait_queue_wake_one(&cond->wait, true, NO_ERROR); + + THREAD_UNLOCK(state); +} diff --git a/kernel/kernel/debug.c b/kernel/kernel/debug.c new file mode 100644 index 000000000..7b8654f40 --- /dev/null +++ b/kernel/kernel/debug.c @@ -0,0 +1,250 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @defgroup debug Debug + * @{ + */ + +/** + * @file + * @brief Debug console functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_LIB_CONSOLE +#include + +static int cmd_threads(int argc, const cmd_args *argv); +static int cmd_threadstats(int argc, const cmd_args *argv); +static int cmd_threadload(int argc, const cmd_args *argv); +static int cmd_kevlog(int argc, const cmd_args *argv); + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND_MASKED("threads", "list kernel threads", &cmd_threads, CMD_AVAIL_ALWAYS) +#endif +#if THREAD_STATS +STATIC_COMMAND("threadstats", "thread level statistics", &cmd_threadstats) +STATIC_COMMAND("threadload", "toggle thread load display", &cmd_threadload) +#endif +#if WITH_KERNEL_EVLOG +STATIC_COMMAND_MASKED("kevlog", "dump kernel event log", &cmd_kevlog, CMD_AVAIL_ALWAYS) +#endif +STATIC_COMMAND_END(kernel); + +#if LK_DEBUGLEVEL > 1 +static int cmd_threads(int argc, const cmd_args *argv) +{ + printf("thread list:\n"); + dump_all_threads(); + + return 0; +} +#endif + +#if THREAD_STATS +static int cmd_threadstats(int argc, const cmd_args *argv) +{ + for (uint i = 0; i < SMP_MAX_CPUS; i++) { + if (!mp_is_cpu_active(i)) + continue; + + printf("thread stats (cpu %d):\n", i); + printf("\ttotal idle time: %lld\n", thread_stats[i].idle_time); + printf("\ttotal busy time: %lld\n", current_time_hires() - thread_stats[i].idle_time); + printf("\treschedules: %lu\n", thread_stats[i].reschedules); +#if WITH_SMP + printf("\treschedule_ipis: %lu\n", thread_stats[i].reschedule_ipis); +#endif + printf("\tcontext_switches: %lu\n", thread_stats[i].context_switches); + printf("\tpreempts: %lu\n", thread_stats[i].preempts); + printf("\tyields: %lu\n", thread_stats[i].yields); + printf("\tinterrupts: %lu\n", thread_stats[i].interrupts); + printf("\ttimer interrupts: %lu\n", thread_stats[i].timer_ints); + printf("\ttimers: %lu\n", thread_stats[i].timers); + } + + return 0; +} + +static enum handler_return threadload(struct timer *t, lk_time_t now, void *arg) +{ + static struct thread_stats old_stats[SMP_MAX_CPUS]; + static lk_bigtime_t last_idle_time[SMP_MAX_CPUS]; + + for (uint i = 0; i < SMP_MAX_CPUS; i++) { + /* dont display time for inactiv cpus */ + if (!mp_is_cpu_active(i)) + continue; + + lk_bigtime_t idle_time = thread_stats[i].idle_time; + + /* if the cpu is currently idle, add the time since it went idle up until now to the idle counter */ + bool is_idle = !!mp_is_cpu_idle(i); + if (is_idle) { + idle_time += current_time_hires() - thread_stats[i].last_idle_timestamp; + } + + lk_bigtime_t delta_time = idle_time - last_idle_time[i]; + lk_bigtime_t busy_time = 1000000ULL - (delta_time > 1000000ULL ? 1000000ULL : delta_time); + uint busypercent = (busy_time * 10000) / (1000000); + + printf("cpu %u LOAD: " + "%u.%02u%%, " + "cs %lu, " + "pmpts %lu, " +#if WITH_SMP + "rs_ipis %lu, " +#endif + "ints %lu, " + "tmr ints %lu, " + "tmrs %lu\n", + i, + busypercent / 100, busypercent % 100, + thread_stats[i].context_switches - old_stats[i].context_switches, + thread_stats[i].preempts - old_stats[i].preempts, +#if WITH_SMP + thread_stats[i].reschedule_ipis - old_stats[i].reschedule_ipis, +#endif + thread_stats[i].interrupts - old_stats[i].interrupts, + thread_stats[i].timer_ints - old_stats[i].timer_ints, + thread_stats[i].timers - old_stats[i].timers); + + old_stats[i] = thread_stats[i]; + last_idle_time[i] = idle_time; + } + + return INT_NO_RESCHEDULE; +} + +static int cmd_threadload(int argc, const cmd_args *argv) +{ + static bool showthreadload = false; + static timer_t tltimer; + + if (showthreadload == false) { + // start the display + timer_initialize(&tltimer); + timer_set_periodic(&tltimer, 1000, &threadload, NULL); + showthreadload = true; + } else { + timer_cancel(&tltimer); + showthreadload = false; + } + + return 0; +} + +#endif // THREAD_STATS + +#endif // WITH_LIB_CONSOLE + +#if WITH_KERNEL_EVLOG + +#include + +static evlog_t kernel_evlog; +volatile bool kernel_evlog_enable; + +void kernel_evlog_init(void) +{ + evlog_init(&kernel_evlog, KERNEL_EVLOG_LEN, 4); + + kernel_evlog_enable = true; +} + +void kernel_evlog_add(uintptr_t id, uintptr_t arg0, uintptr_t arg1) +{ + if (kernel_evlog_enable) { + uint index = evlog_bump_head(&kernel_evlog); + + kernel_evlog.items[index] = (uintptr_t)current_time_hires(); + kernel_evlog.items[index+1] = (arch_curr_cpu_num() << 16) | id; + kernel_evlog.items[index+2] = arg0; + kernel_evlog.items[index+3] = arg1; + } +} + +#if WITH_LIB_CONSOLE + +static void kevdump_cb(const uintptr_t *i) +{ + switch (i[1] & 0xffff) { + case KERNEL_EVLOG_CONTEXT_SWITCH: + printf("%lu.%lu: context switch from %p to %p\n", i[0], i[1] >> 16, (void *)i[2], (void *)i[3]); + break; + case KERNEL_EVLOG_PREEMPT: + printf("%lu.%lu: preempt on thread %p\n", i[0], i[1] >> 16, (void *)i[2]); + break; + case KERNEL_EVLOG_TIMER_TICK: + printf("%lu.%lu: timer tick\n", i[0], i[1] >> 16); + break; + case KERNEL_EVLOG_TIMER_CALL: + printf("%lu.%lu: timer call %p, arg %p\n", i[0], i[1] >> 16, (void *)i[2], (void *)i[3]); + break; + case KERNEL_EVLOG_IRQ_ENTER: + printf("%lu.%lu: irq entry %lu\n", i[0], i[1] >> 16, i[2]); + break; + case KERNEL_EVLOG_IRQ_EXIT: + printf("%lu.%lu: irq exit %lu\n", i[0], i[1] >> 16, i[2]); + break; + default: + printf("%lu: unknown id 0x%lx 0x%lx 0x%lx\n", i[0], i[1], i[2], i[3]); + } +} + +void kernel_evlog_dump(void) +{ + kernel_evlog_enable = false; + evlog_dump(&kernel_evlog, &kevdump_cb); + kernel_evlog_enable = true; +} + +static int cmd_kevlog(int argc, const cmd_args *argv) +{ + printf("kernel event log:\n"); + kernel_evlog_dump(); + + return NO_ERROR; +} + +#endif + +#endif // WITH_KERNEL_EVLOG + +#if WITH_LIB_KLOG + +#include + +#include +#include + +#define NUM_KLOGS 1 +#define KLOG_BUF_LEN (1 << 12) // 4k +#define KLOG_BUFS_LEN (KLOG_BUF_LEN * NUM_KLOGS) + +static char __klog_bufs[KLOG_BUFS_LEN] __ALIGNED(PAGE_SIZE); + +void kernel_log_init(void) +{ + status_t res = klog_create(__klog_bufs, KLOG_BUFS_LEN, NUM_KLOGS); + if (res != NO_ERROR) + return; + klog_init(); +} + +#endif // WITH_LIB_KLOG diff --git a/kernel/kernel/event.c b/kernel/kernel/event.c new file mode 100644 index 000000000..32a5b7d73 --- /dev/null +++ b/kernel/kernel/event.c @@ -0,0 +1,202 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Event wait and signal functions for threads. + * @defgroup event Events + * + * An event is a subclass of a wait queue. + * + * Threads wait for events, with optional timeouts. + * + * Events are "signaled", releasing waiting threads to continue. + * Signals may be one-shot signals (EVENT_FLAG_AUTOUNSIGNAL), in which + * case one signal releases only one thread, at which point it is + * automatically cleared. Otherwise, signals release all waiting threads + * to continue immediately until the signal is manually cleared with + * event_unsignal(). + * + * @{ + */ + +#include +#include +#include +#include +#include + +/** + * @brief Initialize an event object + * + * @param e Event object to initialize + * @param initial Initial value for "signaled" state + * @param flags 0 or EVENT_FLAG_AUTOUNSIGNAL + */ +void event_init(event_t *e, bool initial, uint flags) +{ + *e = (event_t)EVENT_INITIAL_VALUE(*e, initial, flags); +} + +/** + * @brief Destroy an event object. + * + * Event's resources are freed and it may no longer be + * used until event_init() is called again. Any threads + * still waiting on the event will be resumed. + * + * @param e Event object to initialize + */ +void event_destroy(event_t *e) +{ + DEBUG_ASSERT(e->magic == EVENT_MAGIC); + + THREAD_LOCK(state); + + e->magic = 0; + e->signalled = false; + e->flags = 0; + wait_queue_destroy(&e->wait, true); + + THREAD_UNLOCK(state); +} + +/** + * @brief Wait for event to be signaled + * + * If the event has already been signaled, this function + * returns immediately. Otherwise, the current thread + * goes to sleep until the event object is signaled, + * the timeout is reached, or the event object is destroyed + * by another thread. + * + * @param e Event object + * @param timeout Timeout value, in ms + * + * @return 0 on success, ERR_TIMED_OUT on timeout, + * other values depending on wait_result value + * when event_signal_etc is used. + */ +status_t event_wait_timeout(event_t *e, lk_time_t timeout) +{ + status_t ret = NO_ERROR; + + DEBUG_ASSERT(e->magic == EVENT_MAGIC); + + THREAD_LOCK(state); + + if (e->signalled) { + /* signalled, we're going to fall through */ + if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) { + /* autounsignal flag lets one thread fall through before unsignalling */ + e->signalled = false; + } + } else { + /* unsignalled, block here */ + ret = wait_queue_block(&e->wait, timeout); + } + + THREAD_UNLOCK(state); + + return ret; +} + +/** + * @brief Signal an event + * + * Signals an event. If EVENT_FLAG_AUTOUNSIGNAL is set in the event + * object's flags, only one waiting thread is allowed to proceed. Otherwise, + * all waiting threads are allowed to proceed until such time as + * event_unsignal() is called. + * + * @param e Event object + * @param reschedule If true, waiting thread(s) are executed immediately, + * and the current thread resumes only after the + * waiting threads have been satisfied. If false, + * waiting threads are placed at the end of the run + * queue. + * @param wait_result What status event_wait_timeout will return to the + * thread or threads that are woken up. + * + * @return Returns the number of threads that have been unblocked. + */ +int event_signal_etc(event_t *e, bool reschedule, status_t wait_result) +{ + DEBUG_ASSERT(e->magic == EVENT_MAGIC); + + THREAD_LOCK(state); + + int wake_count = 0; + + if (!e->signalled) { + if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) { + /* try to release one thread and leave unsignalled if successful */ + if ((wake_count = wait_queue_wake_one(&e->wait, reschedule, wait_result)) <= 0) { + /* + * if we didn't actually find a thread to wake up, go to + * signalled state and let the next call to event_wait + * unsignal the event. + */ + e->signalled = true; + } + } else { + /* release all threads and remain signalled */ + e->signalled = true; + wake_count = wait_queue_wake_all(&e->wait, reschedule, wait_result); + } + } + + THREAD_UNLOCK(state); + + return wake_count; +} + +/** + * @brief Signal an event + * + * Signals an event. If EVENT_FLAG_AUTOUNSIGNAL is set in the event + * object's flags, only one waiting thread is allowed to proceed. Otherwise, + * all waiting threads are allowed to proceed until such time as + * event_unsignal() is called. + * + * @param e Event object + * @param reschedule If true, waiting thread(s) are executed immediately, + * and the current thread resumes only after the + * waiting threads have been satisfied. If false, + * waiting threads are placed at the end of the run + * queue. + * + * @return Returns NO_ERROR on success. + */ +status_t event_signal(event_t *e, bool reschedule) +{ + event_signal_etc(e, reschedule, NO_ERROR); + return NO_ERROR; +} + +/** + * @brief Clear the "signaled" property of an event + * + * Used mainly for event objects without the EVENT_FLAG_AUTOUNSIGNAL + * flag. Once this function is called, threads that call event_wait() + * functions will once again need to wait until the event object + * is signaled. + * + * @param e Event object + * + * @return Returns NO_ERROR on success. + */ +status_t event_unsignal(event_t *e) +{ + DEBUG_ASSERT(e->magic == EVENT_MAGIC); + + e->signalled = false; + + return NO_ERROR; +} + diff --git a/kernel/kernel/init.c b/kernel/kernel/init.c new file mode 100644 index 000000000..21a48fb4b --- /dev/null +++ b/kernel/kernel/init.c @@ -0,0 +1,40 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +void kernel_init(void) +{ + // if enabled, configure kernel log + kernel_log_init(); + + // if enabled, configure the kernel's event log + kernel_evlog_init(); + + // initialize the threading system + dprintf(SPEW, "initializing mp\n"); + mp_init(); + + // initialize the threading system + dprintf(SPEW, "initializing threads\n"); + thread_init(); + + // initialize kernel timers + dprintf(SPEW, "initializing timers\n"); + timer_init(); + + // initialize ports + dprintf(SPEW, "initializing ports\n"); + port_init(); +} + diff --git a/kernel/kernel/mp.c b/kernel/kernel/mp.c new file mode 100644 index 000000000..9be053da4 --- /dev/null +++ b/kernel/kernel/mp.c @@ -0,0 +1,222 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#if WITH_SMP +/* a global state structure, aligned on cpu cache line to minimize aliasing */ +struct mp_state mp __CPU_ALIGN; + +/* Helpers used for implementing mp_sync */ +struct mp_sync_context; +static void mp_sync_task(void *context); + +void mp_init(void) +{ + mp.ipi_task_lock = SPIN_LOCK_INITIAL_VALUE; + for (uint i = 0; i < countof(mp.ipi_task_list); ++i) { + list_initialize(&mp.ipi_task_list[i]); + } +} + +void mp_reschedule(mp_cpu_mask_t target, uint flags) +{ + uint local_cpu = arch_curr_cpu_num(); + + LTRACEF("local %d, target 0x%x\n", local_cpu, target); + + if (target == MP_CPU_ALL) { + target = mp.active_cpus; + } + + /* mask out cpus that are not active and the local cpu */ + target &= mp.active_cpus; + + /* mask out cpus that are currently running realtime code */ + if ((flags & MP_RESCHEDULE_FLAG_REALTIME) == 0) { + target &= ~mp.realtime_cpus; + } + target &= ~(1U << local_cpu); + + LTRACEF("local %d, post mask target now 0x%x\n", local_cpu, target); + + arch_mp_send_ipi(target, MP_IPI_RESCHEDULE); +} + +struct mp_sync_context { + mp_sync_task_t task; + void *task_context; + volatile int tasks_running; +}; + +static void mp_sync_task(void *raw_context) +{ + struct mp_sync_context *context = raw_context; + context->task(context->task_context); + /* use seq-cst atomic to ensure this update is not seen before the + * side-effects of context->task */ + atomic_add(&context->tasks_running, -1); + arch_spinloop_signal(); +} + +/* @brief Execute a task on the specified CPUs, and block on the calling + * CPU until all CPUs have finished the task. + * + * If MP_CPU_ALL or MP_CPU_ALL_BUT_LOCAL is the target, the online CPU + * mask will be used to determine actual targets. + * + * Interrupts must be disabled if calling with MP_CPU_ALL_BUT_LOCAL as target + */ +void mp_sync_exec(mp_cpu_mask_t target, mp_sync_task_t task, void *context) +{ + uint num_cpus = arch_max_num_cpus(); + uint num_targets = 0; + + if (target == MP_CPU_ALL) { + target = mp.online_cpus; + } else if (target == MP_CPU_ALL_BUT_LOCAL) { + /* targeting all other CPUs but the current one is hazardous + * if the local CPU may be changed underneath us */ + DEBUG_ASSERT(arch_ints_disabled()); + target = mp.online_cpus & ~(1U << arch_curr_cpu_num()); + } + + /* initialize num_targets (may include self) */ + mp_cpu_mask_t remaining = target; + uint cpu_id = 0; + while (remaining && cpu_id < num_cpus) { + if (remaining & 1) { + num_targets++; + } + remaining >>= 1; + cpu_id++; + } + + /* disable interrupts so our current CPU doesn't change */ + spin_lock_saved_state_t irqstate; + arch_interrupt_save(&irqstate, SPIN_LOCK_FLAG_INTERRUPTS); + smp_rmb(); + + uint local_cpu = arch_curr_cpu_num(); + /* remove self from target lists, since no need to IPI ourselves */ + bool targetting_self = + (target != MP_CPU_ALL_BUT_LOCAL && (target & (1U << local_cpu))); + target &= ~(1U << local_cpu); + + /* create tasks to enqueue (we need one per target due to each containing + * a linked list node */ + struct mp_sync_context sync_context = { + .task = task, + .task_context = context, + .tasks_running = num_targets, + }; + + struct mp_ipi_task sync_tasks[SMP_MAX_CPUS] = { 0 }; + for (uint i = 0; i < num_cpus; ++i) { + sync_tasks[i].func = mp_sync_task; + sync_tasks[i].context = &sync_context; + } + + /* enqueue tasks */ + spin_lock(&mp.ipi_task_lock); + remaining = target; + cpu_id = 0; + while (remaining && cpu_id < num_cpus) { + if (remaining & 1) { + list_add_tail(&mp.ipi_task_list[cpu_id], &sync_tasks[cpu_id].node); + } + remaining >>= 1; + cpu_id++; + } + spin_unlock(&mp.ipi_task_lock); + + /* let CPUs know to begin executing */ + __UNUSED status_t status = arch_mp_send_ipi(target, MP_IPI_GENERIC); + DEBUG_ASSERT(status == NO_ERROR); + + if (targetting_self) { + mp_sync_task(&sync_context); + } + smp_mb(); + + /* we can take interrupts again once we've executed our task */ + arch_interrupt_restore(irqstate, SPIN_LOCK_FLAG_INTERRUPTS); + + /* wait for all other CPUs to be done with the context */ + while (sync_context.tasks_running != 0) { + arch_spinloop_pause(); + } + smp_mb(); + + /* make sure the sync_tasks aren't in lists anymore, since they're + * stack allocated */ + for (uint i = 0; i < num_cpus; ++i) { + ASSERT(!list_in_list(&sync_tasks[i].node)); + } +} + +void mp_set_curr_cpu_online(bool online) +{ + if (online) { + atomic_or((volatile int *)&mp.online_cpus, 1U << arch_curr_cpu_num()); + } else { + atomic_and((volatile int *)&mp.online_cpus, ~(1U << arch_curr_cpu_num())); + } +} + +void mp_set_curr_cpu_active(bool active) +{ + if (active) { + atomic_or((volatile int *)&mp.active_cpus, 1U << arch_curr_cpu_num()); + } else { + atomic_and((volatile int *)&mp.active_cpus, ~(1U << arch_curr_cpu_num())); + } +} + +enum handler_return mp_mbx_generic_irq(void) +{ + DEBUG_ASSERT(arch_ints_disabled()); + uint local_cpu = arch_curr_cpu_num(); + + while (1) { + struct mp_ipi_task *task; + spin_lock(&mp.ipi_task_lock); + task = list_remove_head_type(&mp.ipi_task_list[local_cpu], struct mp_ipi_task, node); + spin_unlock(&mp.ipi_task_lock); + if (task == NULL) { + break; + } + + task->func(task->context); + } + return INT_NO_RESCHEDULE; +} + +enum handler_return mp_mbx_reschedule_irq(void) +{ + uint cpu = arch_curr_cpu_num(); + + LTRACEF("cpu %u\n", cpu); + + THREAD_STATS_INC(reschedule_ipis); + + return (mp.active_cpus & (1U << cpu)) ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +#endif diff --git a/kernel/kernel/mutex.c b/kernel/kernel/mutex.c new file mode 100644 index 000000000..22e0ab67b --- /dev/null +++ b/kernel/kernel/mutex.c @@ -0,0 +1,136 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// Copyright (c) 2012-2012 Shantanu Gupta +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Mutex functions + * + * @defgroup mutex Mutex + * @{ + */ + +#include +#include +#include +#include +#include + +/** + * @brief Initialize a mutex_t + */ +void mutex_init(mutex_t *m) +{ + *m = (mutex_t)MUTEX_INITIAL_VALUE(*m); +} + +/** + * @brief Destroy a mutex_t + * + * This function frees any resources that were allocated + * in mutex_init(). The mutex_t object itself is not freed. + */ +void mutex_destroy(mutex_t *m) +{ + DEBUG_ASSERT(m->magic == MUTEX_MAGIC); + +#if LK_DEBUGLEVEL > 0 + if (unlikely(m->holder != 0 && get_current_thread() != m->holder)) + panic("mutex_destroy: thread %p (%s) tried to release mutex %p it doesn't own. owned by %p (%s)\n", + get_current_thread(), get_current_thread()->name, m, m->holder, m->holder->name); +#endif + + THREAD_LOCK(state); + m->magic = 0; + m->count = 0; + wait_queue_destroy(&m->wait, true); + THREAD_UNLOCK(state); +} + +status_t mutex_acquire_timeout_internal(mutex_t *m, lk_time_t timeout) +{ + if (unlikely(++m->count > 1)) { + status_t ret = wait_queue_block(&m->wait, timeout); + if (unlikely(ret < NO_ERROR)) { + /* if the acquisition timed out, back out the acquire and exit */ + if (likely(ret == ERR_TIMED_OUT)) { + /* + * race: the mutex may have been destroyed after the timeout, + * but before we got scheduled again which makes messing with the + * count variable dangerous. + */ + m->count--; + } + /* if there was a general error, it may have been destroyed out from + * underneath us, so just exit (which is really an invalid state anyway) + */ + return ret; + } + } + + m->holder = get_current_thread(); + + return NO_ERROR; +} + +/** + * @brief Mutex wait with timeout + * + * This function waits up to \a timeout ms for the mutex to become available. + * Timeout may be zero, in which case this function returns immediately if + * the mutex is not free. + * + * @return NO_ERROR on success, ERR_TIMED_OUT on timeout, + * other values on error + */ +status_t mutex_acquire_timeout(mutex_t *m, lk_time_t timeout) +{ + DEBUG_ASSERT(m->magic == MUTEX_MAGIC); + +#if LK_DEBUGLEVEL > 0 + if (unlikely(get_current_thread() == m->holder)) + panic("mutex_acquire_timeout: thread %p (%s) tried to acquire mutex %p it already owns.\n", + get_current_thread(), get_current_thread()->name, m); +#endif + + THREAD_LOCK(state); + status_t ret = mutex_acquire_timeout_internal(m, timeout); + THREAD_UNLOCK(state); + return ret; +} + +void mutex_release_internal(mutex_t *m, bool reschedule) +{ + m->holder = 0; + + if (unlikely(--m->count >= 1)) { + /* release a thread */ + wait_queue_wake_one(&m->wait, reschedule, NO_ERROR); + } +} + +/** + * @brief Release mutex + */ +status_t mutex_release(mutex_t *m) +{ + DEBUG_ASSERT(m->magic == MUTEX_MAGIC); + +#if LK_DEBUGLEVEL > 0 + if (unlikely(get_current_thread() != m->holder)) { + panic("mutex_release: thread %p (%s) tried to release mutex %p it doesn't own. owned by %p (%s)\n", + get_current_thread(), get_current_thread()->name, m, m->holder, m->holder ? m->holder->name : "none"); + } +#endif + + THREAD_LOCK(state); + mutex_release_internal(m, true); + THREAD_UNLOCK(state); + return NO_ERROR; +} + diff --git a/kernel/kernel/novm/BUILD.gn b/kernel/kernel/novm/BUILD.gn new file mode 100644 index 000000000..8afed25d0 --- /dev/null +++ b/kernel/kernel/novm/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("novm") { + sources = [ + "novm.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/kernel/novm/novm.c b/kernel/kernel/novm/novm.c new file mode 100644 index 000000000..85862b9c4 --- /dev/null +++ b/kernel/kernel/novm/novm.c @@ -0,0 +1,314 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include "kernel/novm.h" + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct novm_arena { + mutex_t lock; + const char *name; + size_t pages; + char *map; + char *base; + size_t size; + + // We divide the memory up into pages. If there is memory we can use before + // the first aligned page address, then we record it here and the heap will use + // it. +#define MINIMUM_USEFUL_UNALIGNED_SIZE 64 + void *unaligned_area; + size_t unaligned_size; +}; + + +/* not a static vm, not using the kernel vm */ +extern int _end; +extern int _end_of_ram; + +#define MEM_START ((uintptr_t)&_end) +#define MEM_SIZE ((MEMBASE + MEMSIZE) - MEM_START) +#define DEFAULT_MAP_SIZE (MEMSIZE >> PAGE_SIZE_SHIFT) + +/* a static list of arenas */ +#ifndef NOVM_MAX_ARENAS +#define NOVM_MAX_ARENAS 1 +#endif +struct novm_arena arena[NOVM_MAX_ARENAS]; + +void *novm_alloc_unaligned(size_t *size_return) +{ + /* only do the unaligned thing in the first arena */ + if (arena[0].unaligned_area != NULL) { + *size_return = arena[0].unaligned_size; + void *result = arena[0].unaligned_area; + arena[0].unaligned_area = NULL; + arena[0].unaligned_size = 0; + return result; + } + *size_return = PAGE_SIZE; + return novm_alloc_pages(1, NOVM_ARENA_ANY); +} + +static bool in_arena(struct novm_arena *n, void *p) +{ + if (n->size == 0) + return false; + + char *ptr = (char *)p; + char *base = n->base; + return ptr >= base && ptr < base + n->size; +} + +static void novm_init_helper(struct novm_arena *n, const char *name, + uintptr_t arena_start, uintptr_t arena_size, + char *default_map, size_t default_map_size) +{ + uintptr_t start = ROUNDUP(arena_start, PAGE_SIZE); + uintptr_t size = ROUNDDOWN(arena_start + arena_size, PAGE_SIZE) - start; + + mutex_init(&n->lock); + + size_t map_size = size >> PAGE_SIZE_SHIFT; + char *map = default_map; + if (map == NULL || default_map_size < map_size) { + // allocate the map out of the arena itself + map = (char *)arena_start; + + // Grab enough map for 16Mbyte of arena each time around the loop. + while (start - arena_start < map_size) { + start += PAGE_SIZE; + size -= PAGE_SIZE; + map_size--; + } + + if ((char *)start - (map + ROUNDUP(map_size, 4)) >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + n->unaligned_area = map + ROUNDUP(map_size, 4); + n->unaligned_size = (char *)start - (map + ROUNDUP(map_size, 4)); + } + } else if (start - arena_start >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + n->unaligned_area = (char *)arena_start; + n->unaligned_size = start - arena_start; + } + n->name = name; + n->map = map; + memset(n->map, 0, map_size); + n->pages = map_size; + n->base = (char *)start; + n->size = size; +} + +void novm_add_arena(const char *name, uintptr_t arena_start, uintptr_t arena_size) +{ + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (arena[i].pages == 0) { + novm_init_helper(&arena[i], name, arena_start, arena_size, NULL, 0); + return; + } + } + panic("novm_add_arena: too many arenas added, bump NOVM_MAX_ARENAS!\n"); +} + +static void novm_init(uint level) +{ + static char mem_allocation_map[DEFAULT_MAP_SIZE]; + novm_init_helper(&arena[0], "main", MEM_START, MEM_SIZE, mem_allocation_map, DEFAULT_MAP_SIZE); +} + +LK_INIT_HOOK(novm, &novm_init, LK_INIT_LEVEL_PLATFORM_EARLY - 1); + +void *novm_alloc_helper(struct novm_arena *n, size_t pages) +{ + if (pages == 0 || pages > n->pages) + return NULL; + + mutex_acquire(&n->lock); + for (size_t i = 0; i <= n->pages - pages; i++) { + bool found = true; + for (size_t j = 0; j < pages; j++) { + if (n->map[i + j] != 0) { + i += j; + found = false; + break; + } + } + if (found) { + memset(n->map + i, 1, pages); + mutex_release(&n->lock); + return n->base + (i << PAGE_SIZE_SHIFT); + } + } + mutex_release(&n->lock); + + return NULL; +} + +void *novm_alloc_pages(size_t pages, uint32_t arena_bitmap) +{ + LTRACEF("pages %zu\n", pages); + + /* allocate from any arena */ + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (arena_bitmap & (1U << i)) { + void *result = novm_alloc_helper(&arena[i], pages); + if (result) + return result; + } + } + + return NULL; +} + +void novm_free_pages(void *address, size_t pages) +{ + LTRACEF("address %p, pages %zu\n", address, pages); + + struct novm_arena *n = NULL; + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (in_arena(&arena[i], address)) { + n = &arena[i]; + break; + } + } + if (!n) + return; + + DEBUG_ASSERT(in_arena(n, address)); + + size_t index = ((char *)address - (char *)(n->base)) >> PAGE_SIZE_SHIFT; + char *map = n->map; + + mutex_acquire(&n->lock); + for (size_t i = 0; i < pages; i++) map[index + i] = 0; + mutex_release(&n->lock); +} + +status_t novm_alloc_specific_pages(void *address, size_t pages) +{ + LTRACEF("address %p, pages %zu\n", address, pages); + + struct novm_arena *n = NULL; + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (in_arena(&arena[i], address)) { + n = &arena[i]; + break; + } + } + if (!n) + return ERR_NOT_FOUND; + + size_t index = ((char *)address - (char *)(n->base)) >> PAGE_SIZE_SHIFT; + char *map = n->map; + + status_t err = NO_ERROR; + + mutex_acquire(&n->lock); + for (size_t i = 0; i < pages; i++) { + if (map[index + i] != 0) { + err = ERR_NO_MEMORY; + break; + } + map[index + i] = 1; + } + mutex_release(&n->lock); + + return err; +} + + +#if LK_DEBUGLEVEL > 1 +#if WITH_LIB_CONSOLE + +#include + +static int cmd_novm(int argc, const cmd_args *argv); +static void novm_dump(void); + +STATIC_COMMAND_START +STATIC_COMMAND("novm", "page allocator (for devices without VM support) debug commands", &cmd_novm) +STATIC_COMMAND_END(novm); + +static int cmd_novm(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + printf("\t%s alloc [arena bitmap]\n", argv[0].str); + printf("\t%s free
[numberofpages]\n", argv[0].str); + return -1; + } + + if (strcmp(argv[1].str, "info") == 0) { + novm_dump(); + } else if (strcmp(argv[1].str, "alloc") == 0) { + if (argc < 3) goto notenoughargs; + + uint32_t arena_bitmap = (argc >= 4) ? argv[3].u : NOVM_ARENA_ANY; + void *ptr = novm_alloc_pages(argv[2].u, arena_bitmap); + printf("novm_alloc_pages returns %p\n", ptr); + } else if (strcmp(argv[1].str, "free") == 0) { + if (argc < 3) goto notenoughargs; + size_t pages = (argc >= 4) ? argv[3].u : 1; + novm_free_pages(argv[2].p, pages); + printf("novm_free_pages: %zd pages at %p\n", pages, argv[2].p); + } else { + printf("unrecognized command\n"); + goto usage; + } + + return 0; +} + +static void novm_dump_arena(struct novm_arena *n) +{ + if (n->pages == 0) { + return; + } + + mutex_acquire(&n->lock); + printf("name '%s', %d pages, each %zdk (%zdk in all)\n", n->name, n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); + printf(" range: %p-%p\n", (void *)n->base, (char *)n->base + n->size); + printf(" unaligned range: %p-%p\n", n->unaligned_area, n->unaligned_area + n->unaligned_size); + unsigned i; + size_t in_use = 0; + for (i = 0; i < n->pages; i++) if (n->map[i] != 0) in_use++; + printf(" %zd/%zd in use\n", in_use, n->pages); +#define MAX_PRINT 1024u + for (i = 0; i < MAX_PRINT && i < n->pages; i++) { + if ((i & 63) == 0) printf(" "); + printf("%c", n->map[i] ? '*' : '.'); + if ((i & 63) == 63) printf("\n"); + } + if (i == MAX_PRINT && n->pages > MAX_PRINT) { + printf(" etc., %zd more pages.", n->pages - MAX_PRINT); + } + printf("\n"); + mutex_release(&n->lock); +} + +static void novm_dump(void) +{ + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + novm_dump_arena(&arena[i]); + } +} + +#endif +#endif + diff --git a/kernel/kernel/novm/rules.mk b/kernel/kernel/novm/rules.mk new file mode 100644 index 000000000..30d389df7 --- /dev/null +++ b/kernel/kernel/novm/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/novm.c + +include make/module.mk diff --git a/kernel/kernel/port.c b/kernel/kernel/port.c new file mode 100644 index 000000000..5b7cec1ec --- /dev/null +++ b/kernel/kernel/port.c @@ -0,0 +1,657 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Port object functions + * @defgroup event Events + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +// write ports can be in two states, open and closed, which have a +// different magic number. + +#define WRITEPORT_MAGIC_W (0x70727477) // 'prtw' +#define WRITEPORT_MAGIC_X (0x70727478) // 'prtx' + +#define READPORT_MAGIC (0x70727472) // 'prtr' +#define PORTGROUP_MAGIC (0x70727467) // 'prtg' + +#define PORT_BUFF_SIZE 8 +#define PORT_BUFF_SIZE_BIG 256 + +#define RESCHEDULE_POLICY 1 + +#define MAX_PORT_GROUP_COUNT 256 + +typedef struct { + uint log2; + uint avail; + uint head; + uint tail; + port_packet_t packet[1]; +} port_buf_t; + +typedef struct { + int magic; + struct list_node node; + port_buf_t *buf; + struct list_node rp_list; + port_mode_t mode; + char name[PORT_NAME_LEN]; +} write_port_t; + +typedef struct { + int magic; + wait_queue_t wait; + struct list_node rp_list; +} port_group_t; + +typedef struct { + int magic; + struct list_node w_node; + struct list_node g_node; + port_buf_t *buf; + void *ctx; + wait_queue_t wait; + write_port_t *wport; + port_group_t *gport; +} read_port_t; + + +static struct list_node write_port_list; + + +static port_buf_t *make_buf(uint pk_count) +{ + uint size = sizeof(port_buf_t) + ((pk_count - 1) * sizeof(port_packet_t)); + port_buf_t *buf = (port_buf_t *) malloc(size); + if (!buf) + return NULL; + buf->log2 = log2_uint(pk_count); + buf->head = buf->tail = 0; + buf->avail = pk_count; + return buf; +} + +static inline bool buf_is_empty(port_buf_t *buf) +{ + return buf->avail == valpow2(buf->log2); +} + +static status_t buf_write(port_buf_t *buf, const port_packet_t *packets, size_t count) +{ + if (buf->avail < count) + return ERR_NOT_ENOUGH_BUFFER; + + for (size_t ix = 0; ix != count; ix++) { + buf->packet[buf->tail] = packets[ix]; + buf->tail = modpow2(++buf->tail, buf->log2); + } + buf->avail -= count; + return NO_ERROR; +} + +static status_t buf_read(port_buf_t *buf, port_result_t *pr) +{ + if (buf_is_empty(buf)) + return ERR_NO_MSG; + pr->packet = buf->packet[buf->head]; + buf->head = modpow2(++buf->head, buf->log2); + ++buf->avail; + return NO_ERROR; +} + +port_packet_t* buf_peek(port_buf_t* buf) { + return buf_is_empty(buf) ? NULL : &buf->packet[buf->head]; +} + +// must be called before any use of ports. +void port_init(void) +{ + list_initialize(&write_port_list); +} + +status_t port_create(const char *name, port_mode_t mode, port_t *port) +{ + if (!name || !port) + return ERR_INVALID_ARGS; + + // only unicast ports can have a large buffer. + if (mode & PORT_MODE_BROADCAST) { + if (mode & PORT_MODE_BIG_BUFFER) + return ERR_INVALID_ARGS; + } + + if (strlen(name) >= PORT_NAME_LEN) + return ERR_INVALID_ARGS; + + // lookup for existing port, return that if found. + write_port_t *wp = NULL; + THREAD_LOCK(state1); + list_for_every_entry(&write_port_list, wp, write_port_t, node) { + if (strcmp(wp->name, name) == 0) { + // can't return closed ports. + if (wp->magic == WRITEPORT_MAGIC_X) + wp = NULL; + THREAD_UNLOCK(state1); + if (wp) { + *port = (void *) wp; + return ERR_ALREADY_EXISTS; + } else { + return ERR_BUSY; + } + } + } + THREAD_UNLOCK(state1); + + // not found, create the write port and the circular buffer. + wp = calloc(1, sizeof(write_port_t)); + if (!wp) + return ERR_NO_MEMORY; + + wp->magic = WRITEPORT_MAGIC_W; + wp->mode = mode; + strlcpy(wp->name, name, sizeof(wp->name)); + list_initialize(&wp->rp_list); + + uint size = (mode & PORT_MODE_BIG_BUFFER) ? PORT_BUFF_SIZE_BIG : PORT_BUFF_SIZE; + wp->buf = make_buf(size); + if (!wp->buf) { + free(wp); + return ERR_NO_MEMORY; + } + + // todo: race condtion! a port with the same name could have been created + // by another thread at is point. + THREAD_LOCK(state2); + list_add_tail(&write_port_list, &wp->node); + THREAD_UNLOCK(state2); + + *port = (void *)wp; + return NO_ERROR; +} + +status_t port_open(const char *name, void *ctx, port_t *port) +{ + if (!name || !port) + return ERR_INVALID_ARGS; + + // assume success; create the read port and buffer now. + read_port_t *rp = calloc(1, sizeof(read_port_t)); + if (!rp) + return ERR_NO_MEMORY; + + rp->magic = READPORT_MAGIC; + wait_queue_init(&rp->wait); + rp->ctx = ctx; + + // |buf| might not be needed, but we always allocate outside the lock. + // this buffer is only needed for broadcast ports, but we don't know + // that here. + port_buf_t *buf = make_buf(PORT_BUFF_SIZE); + if (!buf) { + free(rp); + return ERR_NO_MEMORY; + } + + // find the named write port and associate it with read port. + status_t rc = ERR_NOT_FOUND; + + THREAD_LOCK(state); + write_port_t *wp = NULL; + list_for_every_entry(&write_port_list, wp, write_port_t, node) { + if (strcmp(wp->name, name) == 0) { + // found; add read port to write port list. + rp->wport = wp; + if (wp->buf) { + // this is the first read port; transfer the circular buffer. + list_add_tail(&wp->rp_list, &rp->w_node); + rp->buf = wp->buf; + wp->buf = NULL; + rc = NO_ERROR; + } else if (buf) { + // not first read port. + if (wp->mode & PORT_MODE_UNICAST) { + // cannot add a second listener. + rc = ERR_NOT_ALLOWED; + break; + } + // use the new (small) circular buffer. + list_add_tail(&wp->rp_list, &rp->w_node); + rp->buf = buf; + buf = NULL; + rc = NO_ERROR; + } else { + // |buf| allocation failed and the buffer was needed. + rc = ERR_NO_MEMORY; + } + break; + } + } + THREAD_UNLOCK(state); + + if (buf) + free(buf); + + if (rc == NO_ERROR) { + *port = (void *)rp; + } else { + free(rp); + } + return rc; +} + +status_t port_group(port_t *ports, size_t count, port_t *group) +{ + if (count > MAX_PORT_GROUP_COUNT) + return ERR_TOO_BIG; + + // Allow empty port groups. + if (count && !ports) + return ERR_INVALID_ARGS; + + if (!group) + return ERR_INVALID_ARGS; + + // assume success; create port group now. + port_group_t *pg = calloc(1, sizeof(port_group_t)); + if (!pg) + return ERR_NO_MEMORY; + + pg->magic = PORTGROUP_MAGIC; + wait_queue_init(&pg->wait); + list_initialize(&pg->rp_list); + + status_t rc = NO_ERROR; + + THREAD_LOCK(state); + for (size_t ix = 0; ix != count; ix++) { + read_port_t *rp = (read_port_t *)ports[ix]; + if ((rp->magic != READPORT_MAGIC) || rp->gport) { + // wrong type of port, or port already part of a group, + // in any case, undo the changes to the previous read ports. + for (size_t jx = 0; jx != ix; jx++) { + ((read_port_t *)ports[jx])->gport = NULL; + } + rc = ERR_BAD_HANDLE; + break; + } + // link port group and read port. + rp->gport = pg; + list_add_tail(&pg->rp_list, &rp->g_node); + } + THREAD_UNLOCK(state); + + if (rc == NO_ERROR) { + *group = (port_t *)pg; + } else { + free(pg); + } + return rc; +} + +status_t port_group_add(port_t group, port_t port) +{ + if (!port || !group) + return ERR_INVALID_ARGS; + + // Make sure the user has actually passed in a port group and a read-port. + port_group_t *pg = (port_group_t *)group; + if (pg->magic != PORTGROUP_MAGIC) + return ERR_INVALID_ARGS; + + read_port_t *rp = (read_port_t *)port; + if (rp->magic != READPORT_MAGIC || rp->gport) + return ERR_BAD_HANDLE; + + status_t rc = NO_ERROR; + THREAD_LOCK(state); + + if (list_length(&pg->rp_list) == MAX_PORT_GROUP_COUNT) { + rc = ERR_TOO_BIG; + } else { + rp->gport = pg; + list_add_tail(&pg->rp_list, &rp->g_node); + // If the new read port being added has messages available, try to wake + // any readers that might be present. + if (!buf_is_empty(rp->buf)) { + wait_queue_wake_one(&pg->wait, false, NO_ERROR); + } + } + + THREAD_UNLOCK(state); + return rc; +} + +status_t port_group_remove(port_t group, port_t port) +{ + if (!port || !group) + return ERR_INVALID_ARGS; + + // Make sure the user has actually passed in a port group and a read-port. + port_group_t *pg = (port_group_t *)group; + if (pg->magic != PORTGROUP_MAGIC) + return ERR_INVALID_ARGS; + + read_port_t *rp = (read_port_t *)port; + if (rp->magic != READPORT_MAGIC || rp->gport != pg) + return ERR_BAD_HANDLE; + + THREAD_LOCK(state); + + bool found = false; + read_port_t *current_rp; + list_for_every_entry(&pg->rp_list, current_rp, read_port_t, g_node) { + if (current_rp == rp) { + found = true; + } + } + + if (!found) + return ERR_BAD_HANDLE; + + list_delete(&rp->g_node); + + THREAD_UNLOCK(state); + return NO_ERROR; +} + +status_t port_write(port_t port, const port_packet_t *pk, size_t count) +{ + if (!port || !pk) + return ERR_INVALID_ARGS; + + write_port_t *wp = (write_port_t *)port; + THREAD_LOCK(state); + if (wp->magic != WRITEPORT_MAGIC_W) { + // wrong port type. + THREAD_UNLOCK(state); + return ERR_BAD_HANDLE; + } + + status_t status = NO_ERROR; + int awake_count = 0; + int write_count = 0; + + if (wp->buf) { + // there are no read ports, just write to the buffer. + status = buf_write(wp->buf, pk, count); + write_count = 1; + } else { + // there might be read ports. for each, write and attempt to wake a thread + // from the port group or from the read port itself. + read_port_t *rp; + list_for_every_entry(&wp->rp_list, rp, read_port_t, w_node) { + if (buf_write(rp->buf, pk, count) < 0) { + // buffer full. + status = ERR_PARTIAL_WRITE; + continue; + } + + ++write_count; + + int awaken = 0; + if (rp->gport) { + awaken = wait_queue_wake_one(&rp->gport->wait, false, NO_ERROR); + } + if (!awaken) { + awaken = wait_queue_wake_one(&rp->wait, false, NO_ERROR); + } + + awake_count += awaken; + } + } + + THREAD_UNLOCK(state); + +#if RESCHEDULE_POLICY + if (awake_count) + thread_yield(); +#endif + + if (!write_count) + return ERR_CHANNEL_CLOSED; + + return status; +} + +static inline status_t read_no_lock(read_port_t *rp, lk_time_t timeout, port_result_t *result) +{ + status_t status = buf_read(rp->buf, result); + result->ctx = rp->ctx; + + if (status != ERR_NO_MSG) + return status; + + // early return allows compiler to elide the rest for the group read case. + if (!timeout) + return ERR_TIMED_OUT; + + status_t wr = wait_queue_block(&rp->wait, timeout); + if (wr != NO_ERROR) + return wr; + // recursive tail call is usually optimized away with a goto. + return read_no_lock(rp, timeout, result); +} + +status_t port_read(port_t port, lk_time_t timeout, port_result_t *result) +{ + if (!port || !result) + return ERR_INVALID_ARGS; + + status_t rc = ERR_GENERIC; + read_port_t *rp = (read_port_t *)port; + + THREAD_LOCK(state); + if (rp->magic == READPORT_MAGIC) { + // dealing with a single port. + rc = read_no_lock(rp, timeout, result); + if ((rc == ERR_TIMED_OUT) && (timeout == 0) && (rp->wport == NULL)) + rc = ERR_CHANNEL_CLOSED; + } else if (rp->magic == PORTGROUP_MAGIC) { + // dealing with a port group. + port_group_t *pg = (port_group_t *)port; + do { + // read each port with no timeout. + // todo: this order is fixed, probably a bad thing. + list_for_every_entry(&pg->rp_list, rp, read_port_t, g_node) { + rc = read_no_lock(rp, 0, result); + if (rc != ERR_TIMED_OUT) + goto read_exit; + } + // no data, block on the group waitqueue. + rc = wait_queue_block(&pg->wait, timeout); + } while (rc == NO_ERROR); + } else { + // wrong port type. + rc = ERR_BAD_HANDLE; + } + +read_exit: + THREAD_UNLOCK(state); + return rc; +} + +status_t port_peek(port_t port, port_result_t *result) +{ + if (!port || !result) + return ERR_INVALID_ARGS; + + status_t rc = ERR_GENERIC; + read_port_t *rp = (read_port_t *)port; + + THREAD_LOCK(state); + if (rp->magic != READPORT_MAGIC) { + rc = ERR_BAD_HANDLE; + } else { + port_packet_t* pp = buf_peek(rp->buf); + if (!pp) { + rc = rp->wport != NULL ? ERR_NOT_READY : ERR_CHANNEL_CLOSED; + } else { + result->ctx = rp->ctx; + result->packet = *pp; + rc = NO_ERROR; + } + } + THREAD_UNLOCK(state); + return rc; +} + +status_t port_wait(port_t port, lk_time_t timeout) { + if (!port) + return ERR_INVALID_ARGS; + + status_t rc = ERR_GENERIC; + read_port_t *rp = (read_port_t *)port; + + THREAD_LOCK(state); + if (rp->magic == READPORT_MAGIC) { + // dealing with a single port. + if (!buf_is_empty(rp->buf)) { + rc = NO_ERROR; + } else if (!rp->wport) { + rc = ERR_CHANNEL_CLOSED; + } else if (!timeout) { + rc = ERR_TIMED_OUT; + } else { + rc = wait_queue_block(&rp->wait, timeout); + } + } else if (rp->magic == PORTGROUP_MAGIC) { + // dealing with a port group. + port_group_t *pg = (port_group_t *)port; + list_for_every_entry(&pg->rp_list, rp, read_port_t, g_node) { + if (!buf_is_empty(rp->buf)) { + rc = NO_ERROR; + goto wait_exit; + } else if (!rp->wport) { + rc = ERR_CHANNEL_CLOSED; + goto wait_exit; + } + } + // no data, block on the group waitqueue. + rc = wait_queue_block(&pg->wait, timeout); + } else { + // wrong port type. + rc = ERR_BAD_HANDLE; + } + +wait_exit: + THREAD_UNLOCK(state); + return rc; +} + +status_t port_destroy(port_t port) +{ + if (!port) + return ERR_INVALID_ARGS; + + write_port_t *wp = (write_port_t *) port; + port_buf_t *buf = NULL; + + THREAD_LOCK(state); + if (wp->magic != WRITEPORT_MAGIC_X) { + // wrong port type. + THREAD_UNLOCK(state); + return ERR_BAD_HANDLE; + } + // remove self from global named ports list. + list_delete(&wp->node); + + if (wp->buf) { + // we have no readers. + buf = wp->buf; + } else { + // for each reader: + read_port_t *rp; + list_for_every_entry(&wp->rp_list, rp, read_port_t, w_node) { + // wake the read and group ports. + wait_queue_wake_all(&rp->wait, false, ERR_CHANNEL_CLOSED); + if (rp->gport) { + wait_queue_wake_all(&rp->gport->wait, false, ERR_CHANNEL_CLOSED); + } + // remove self from reader ports. + rp->wport = NULL; + } + } + + wp->magic = 0; + THREAD_UNLOCK(state); + + free(buf); + free(wp); + return NO_ERROR; +} + +status_t port_close(port_t port) +{ + if (!port) + return ERR_INVALID_ARGS; + + read_port_t *rp = (read_port_t *) port; + port_buf_t *buf = NULL; + + THREAD_LOCK(state); + if (rp->magic == READPORT_MAGIC) { + // dealing with a read port. + if (rp->wport) { + // remove self from write port list. + list_delete(&rp->w_node); + buf = rp->buf; + } + if (rp->gport) { + // remove self from port group list. + list_delete(&rp->g_node); + } + // wake up waiters, the return code is ERR_OBJECT_DESTROYED. + wait_queue_destroy(&rp->wait, true); + rp->magic = 0; + + } else if (rp->magic == PORTGROUP_MAGIC) { + // dealing with a port group. + port_group_t *pg = (port_group_t *) port; + // wake up waiters. + wait_queue_destroy(&pg->wait, true); + // remove self from reader ports. + rp = NULL; + list_for_every_entry(&pg->rp_list, rp, read_port_t, g_node) { + rp->gport = NULL; + } + pg->magic = 0; + + } else if (rp->magic == WRITEPORT_MAGIC_W) { + // dealing with a write port. + write_port_t *wp = (write_port_t *) port; + // mark it as closed. Now it can be read but not written to. + wp->magic = WRITEPORT_MAGIC_X; + THREAD_UNLOCK(state); + return NO_ERROR; + + } else { + THREAD_UNLOCK(state); + return ERR_BAD_HANDLE; + } + + THREAD_UNLOCK(state); + + free(buf); + free(port); + return NO_ERROR; +} + diff --git a/kernel/kernel/rules.mk b/kernel/kernel/rules.mk new file mode 100644 index 000000000..0f054967e --- /dev/null +++ b/kernel/kernel/rules.mk @@ -0,0 +1,38 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/libc \ + lib/debug \ + lib/heap \ + lib/klog \ + + +MODULE_SRCS := \ + $(LOCAL_DIR)/cond.c \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/event.c \ + $(LOCAL_DIR)/init.c \ + $(LOCAL_DIR)/mutex.c \ + $(LOCAL_DIR)/thread.c \ + $(LOCAL_DIR)/timer.c \ + $(LOCAL_DIR)/semaphore.c \ + $(LOCAL_DIR)/mp.c \ + $(LOCAL_DIR)/port.c \ + + +ifeq ($(WITH_KERNEL_VM),1) +MODULE_DEPS += kernel/vm +else +MODULE_DEPS += kernel/novm +endif + +include make/module.mk diff --git a/kernel/kernel/semaphore.c b/kernel/kernel/semaphore.c new file mode 100644 index 000000000..1ec287314 --- /dev/null +++ b/kernel/kernel/semaphore.c @@ -0,0 +1,91 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2012 Christopher Anderson +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include + +void sem_init(semaphore_t *sem, unsigned int value) +{ + *sem = (semaphore_t)SEMAPHORE_INITIAL_VALUE(*sem, value); +} + +void sem_destroy(semaphore_t *sem) +{ + THREAD_LOCK(state); + sem->count = 0; + wait_queue_destroy(&sem->wait, true); + THREAD_UNLOCK(state); +} + +int sem_post(semaphore_t *sem, bool resched) +{ + int ret = 0; + + THREAD_LOCK(state); + + /* + * If the count is or was negative then a thread is waiting for a resource, otherwise + * it's safe to just increase the count available with no downsides + */ + if (unlikely(++sem->count <= 0)) + ret = wait_queue_wake_one(&sem->wait, resched, NO_ERROR); + + THREAD_UNLOCK(state); + + return ret; +} + +status_t sem_wait(semaphore_t *sem) +{ + status_t ret = NO_ERROR; + THREAD_LOCK(state); + + /* + * If there are no resources available then we need to + * sit in the wait queue until sem_post adds some. + */ + if (unlikely(--sem->count < 0)) + ret = wait_queue_block(&sem->wait, INFINITE_TIME); + + THREAD_UNLOCK(state); + return ret; +} + +status_t sem_trywait(semaphore_t *sem) +{ + status_t ret = NO_ERROR; + THREAD_LOCK(state); + + if (unlikely(sem->count <= 0)) + ret = ERR_NOT_READY; + else + sem->count--; + + THREAD_UNLOCK(state); + return ret; +} + +status_t sem_timedwait(semaphore_t *sem, lk_time_t timeout) +{ + status_t ret = NO_ERROR; + THREAD_LOCK(state); + + if (unlikely(--sem->count < 0)) { + ret = wait_queue_block(&sem->wait, timeout); + if (ret < NO_ERROR) { + if (ret == ERR_TIMED_OUT) { + sem->count++; + } + } + } + + THREAD_UNLOCK(state); + return ret; +} diff --git a/kernel/kernel/thread.c b/kernel/kernel/thread.c new file mode 100644 index 000000000..8e69de50f --- /dev/null +++ b/kernel/kernel/thread.c @@ -0,0 +1,1291 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Kernel threading + * + * This file is the core kernel threading interface. + * + * @defgroup thread Threads + * @{ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WITH_KERNEL_VM +#include +#endif + +#if THREAD_STATS +struct thread_stats thread_stats[SMP_MAX_CPUS]; +#endif + +#define STACK_DEBUG_BYTE (0x99) +#define STACK_DEBUG_WORD (0x99999999) + +#define DEBUG_THREAD_CONTEXT_SWITCH 0 + +/* global thread list */ +static struct list_node thread_list; + +/* master thread spinlock */ +spin_lock_t thread_lock = SPIN_LOCK_INITIAL_VALUE; + +/* the run queue */ +static struct list_node run_queue[NUM_PRIORITIES]; +static uint32_t run_queue_bitmap; + +/* make sure the bitmap is large enough to cover our number of priorities */ +STATIC_ASSERT(NUM_PRIORITIES <= sizeof(run_queue_bitmap) * 8); + +/* the idle thread(s) (statically allocated) */ +#if WITH_SMP +static thread_t _idle_threads[SMP_MAX_CPUS]; +#define idle_thread(cpu) (&_idle_threads[cpu]) +#else +static thread_t _idle_thread; +#define idle_thread(cpu) (&_idle_thread) +#endif + +/* local routines */ +static void thread_resched(void); +static void idle_thread_routine(void) __NO_RETURN; + +#if PLATFORM_HAS_DYNAMIC_TIMER +/* preemption timer */ +static timer_t preempt_timer[SMP_MAX_CPUS]; +#endif + +/* run queue manipulation */ +static void insert_in_run_queue_head(thread_t *t) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(t->state == THREAD_READY); + DEBUG_ASSERT(!list_in_list(&t->queue_node)); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + list_add_head(&run_queue[t->priority], &t->queue_node); + run_queue_bitmap |= (1<priority); +} + +static void insert_in_run_queue_tail(thread_t *t) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(t->state == THREAD_READY); + DEBUG_ASSERT(!list_in_list(&t->queue_node)); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + list_add_tail(&run_queue[t->priority], &t->queue_node); + run_queue_bitmap |= (1<priority); +} + +static void init_thread_struct(thread_t *t, const char *name) +{ + memset(t, 0, sizeof(thread_t)); + t->magic = THREAD_MAGIC; + thread_set_pinned_cpu(t, -1); + strlcpy(t->name, name, sizeof(t->name)); +} + +static void initial_thread_func(void) __NO_RETURN; +static void initial_thread_func(void) +{ + int ret; + + /* release the thread lock that was implicitly held across the reschedule */ + spin_unlock(&thread_lock); + arch_enable_ints(); + + thread_t *ct = get_current_thread(); + ret = ct->entry(ct->arg); + + thread_exit(ret); +} + +/** + * @brief Create a new thread + * + * This function creates a new thread. The thread is initially suspended, so you + * need to call thread_resume() to execute it. + * + * @param name Name of thread + * @param entry Entry point of thread + * @param arg Arbitrary argument passed to entry() + * @param priority Execution priority for the thread. + * @param stack_size Stack size for the thread. + * + * Thread priority is an integer from 0 (lowest) to 31 (highest). Some standard + * prioritys are defined in : + * + * HIGHEST_PRIORITY + * DPC_PRIORITY + * HIGH_PRIORITY + * DEFAULT_PRIORITY + * LOW_PRIORITY + * IDLE_PRIORITY + * LOWEST_PRIORITY + * + * Stack size is typically set to DEFAULT_STACK_SIZE + * + * @return Pointer to thread object, or NULL on failure. + */ +thread_t *thread_create_etc(thread_t *t, const char *name, thread_start_routine entry, void *arg, int priority, void *stack, size_t stack_size) +{ + unsigned int flags = 0; + + if (!t) { + t = malloc(sizeof(thread_t)); + if (!t) + return NULL; + flags |= THREAD_FLAG_FREE_STRUCT; + } + + init_thread_struct(t, name); + + t->entry = entry; + t->arg = arg; + t->priority = priority; + t->state = THREAD_SUSPENDED; + t->blocking_wait_queue = NULL; + t->wait_queue_block_ret = NO_ERROR; + thread_set_curr_cpu(t, -1); + + t->retcode = 0; + wait_queue_init(&t->retcode_wait_queue); + +#if WITH_KERNEL_VM + t->aspace = NULL; +#endif + + /* create the stack */ + if (!stack) { +#if THREAD_STACK_BOUNDS_CHECK + stack_size += THREAD_STACK_PADDING_SIZE; + flags |= THREAD_FLAG_DEBUG_STACK_BOUNDS_CHECK; +#endif + t->stack = malloc(stack_size); + if (!t->stack) { + if (flags & THREAD_FLAG_FREE_STRUCT) + free(t); + return NULL; + } + flags |= THREAD_FLAG_FREE_STACK; +#if THREAD_STACK_BOUNDS_CHECK + memset(t->stack, STACK_DEBUG_BYTE, THREAD_STACK_PADDING_SIZE); +#endif + } else { + t->stack = stack; + } + + t->stack_size = stack_size; + + /* save whether or not we need to free the thread struct and/or stack */ + t->flags = flags; + + /* inheirit thread local storage from the parent */ + thread_t *current_thread = get_current_thread(); + int i; + for (i=0; i < MAX_TLS_ENTRY; i++) + t->tls[i] = current_thread->tls[i]; + + /* set up the initial stack frame */ + arch_thread_initialize(t, (vaddr_t)&initial_thread_func); + + /* add it to the global thread list */ + THREAD_LOCK(state); + list_add_head(&thread_list, &t->thread_list_node); + THREAD_UNLOCK(state); + + return t; +} + +thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size) +{ + return thread_create_etc(NULL, name, entry, arg, priority, NULL, stack_size); +} + +/** + * @brief Flag a thread as real time + * + * @param t Thread to flag + * + * @return NO_ERROR on success + */ +status_t thread_set_real_time(thread_t *t) +{ + if (!t) + return ERR_INVALID_ARGS; + + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + + THREAD_LOCK(state); +#if PLATFORM_HAS_DYNAMIC_TIMER + if (t == get_current_thread()) { + /* if we're currently running, cancel the preemption timer. */ + timer_cancel(&preempt_timer[arch_curr_cpu_num()]); + } +#endif + t->flags |= THREAD_FLAG_REAL_TIME; + THREAD_UNLOCK(state); + + return NO_ERROR; +} + +static bool thread_is_realtime(thread_t *t) +{ + return (t->flags & THREAD_FLAG_REAL_TIME) && t->priority > DEFAULT_PRIORITY; +} + +static bool thread_is_idle(thread_t *t) +{ + return !!(t->flags & THREAD_FLAG_IDLE); +} + +static bool thread_is_real_time_or_idle(thread_t *t) +{ + return !!(t->flags & (THREAD_FLAG_REAL_TIME | THREAD_FLAG_IDLE)); +} + +/** + * @brief Make a suspended thread executable. + * + * This function is typically called to start a thread which has just been + * created with thread_create() + * + * @param t Thread to resume + * + * @return NO_ERROR on success, ERR_NOT_SUSPENDED if thread was not suspended. + */ +status_t thread_resume(thread_t *t) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(t->state != THREAD_DEATH); + + bool resched = false; + bool ints_disabled = arch_ints_disabled(); + THREAD_LOCK(state); + if (t->state == THREAD_SUSPENDED) { + t->state = THREAD_READY; + insert_in_run_queue_head(t); + if (!ints_disabled) /* HACK, don't resced into bootstrap thread before idle thread is set up */ + resched = true; + } + + mp_reschedule(MP_CPU_ALL_BUT_LOCAL, 0); + + THREAD_UNLOCK(state); + + if (resched) + thread_yield(); + + return NO_ERROR; +} + +status_t thread_detach_and_resume(thread_t *t) +{ + status_t err; + err = thread_detach(t); + if (err < 0) + return err; + return thread_resume(t); +} + +status_t thread_join(thread_t *t, int *retcode, lk_time_t timeout) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + + THREAD_LOCK(state); + + if (t->flags & THREAD_FLAG_DETACHED) { + /* the thread is detached, go ahead and exit */ + THREAD_UNLOCK(state); + return ERR_THREAD_DETACHED; + } + + /* wait for the thread to die */ + if (t->state != THREAD_DEATH) { + status_t err = wait_queue_block(&t->retcode_wait_queue, timeout); + if (err < 0) { + THREAD_UNLOCK(state); + return err; + } + } + + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(t->state == THREAD_DEATH); + DEBUG_ASSERT(t->blocking_wait_queue == NULL); + DEBUG_ASSERT(!list_in_list(&t->queue_node)); + + /* save the return code */ + if (retcode) + *retcode = t->retcode; + + /* remove it from the master thread list */ + list_delete(&t->thread_list_node); + + /* clear the structure's magic */ + t->magic = 0; + + THREAD_UNLOCK(state); + + /* free its stack and the thread structure itself */ + if (t->flags & THREAD_FLAG_FREE_STACK && t->stack) + free(t->stack); + + if (t->flags & THREAD_FLAG_FREE_STRUCT) + free(t); + + return NO_ERROR; +} + +status_t thread_detach(thread_t *t) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + + THREAD_LOCK(state); + + /* if another thread is blocked inside thread_join() on this thread, + * wake them up with a specific return code */ + wait_queue_wake_all(&t->retcode_wait_queue, false, ERR_THREAD_DETACHED); + + /* if it's already dead, then just do what join would have and exit */ + if (t->state == THREAD_DEATH) { + t->flags &= ~THREAD_FLAG_DETACHED; /* makes sure thread_join continues */ + THREAD_UNLOCK(state); + return thread_join(t, NULL, 0); + } else { + t->flags |= THREAD_FLAG_DETACHED; + THREAD_UNLOCK(state); + return NO_ERROR; + } +} + +/** + * @brief Terminate the current thread + * + * Current thread exits with the specified return code. + * + * This function does not return. + */ +void thread_exit(int retcode) +{ + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(current_thread->magic == THREAD_MAGIC); + DEBUG_ASSERT(current_thread->state == THREAD_RUNNING); + DEBUG_ASSERT(!thread_is_idle(current_thread)); + +// dprintf("thread_exit: current %p\n", current_thread); + + THREAD_LOCK(state); + + /* enter the dead state */ + current_thread->state = THREAD_DEATH; + current_thread->retcode = retcode; + + /* if we're detached, then do our teardown here */ + if (current_thread->flags & THREAD_FLAG_DETACHED) { + /* remove it from the master thread list */ + list_delete(¤t_thread->thread_list_node); + + /* clear the structure's magic */ + current_thread->magic = 0; + + /* free its stack and the thread structure itself */ + if (current_thread->flags & THREAD_FLAG_FREE_STACK && current_thread->stack) { + heap_delayed_free(current_thread->stack); + + /* make sure its not going to get a bounds check performed on the half-freed stack */ + current_thread->flags &= ~THREAD_FLAG_DEBUG_STACK_BOUNDS_CHECK; + } + + if (current_thread->flags & THREAD_FLAG_FREE_STRUCT) + heap_delayed_free(current_thread); + } else { + /* signal if anyone is waiting */ + wait_queue_wake_all(¤t_thread->retcode_wait_queue, false, 0); + } + + /* reschedule */ + thread_resched(); + + panic("somehow fell through thread_exit()\n"); +} + +__NO_RETURN static void idle_thread_routine(void) +{ + for (;;) + arch_idle(); +} + +static thread_t *get_top_thread(int cpu) +{ + thread_t *newthread; + uint32_t local_run_queue_bitmap = run_queue_bitmap; + + while (local_run_queue_bitmap) { + /* find the first (remaining) queue with a thread in it */ + uint next_queue = HIGHEST_PRIORITY - __builtin_clz(local_run_queue_bitmap) + - (sizeof(run_queue_bitmap) * 8 - NUM_PRIORITIES); + + list_for_every_entry(&run_queue[next_queue], newthread, thread_t, queue_node) { +#if WITH_SMP + if (newthread->pinned_cpu < 0 || newthread->pinned_cpu == cpu) +#endif + { + list_delete(&newthread->queue_node); + + if (list_is_empty(&run_queue[next_queue])) + run_queue_bitmap &= ~(1<state != THREAD_RUNNING); + + THREAD_STATS_INC(reschedules); + + newthread = get_top_thread(cpu); + + DEBUG_ASSERT(newthread); + + newthread->state = THREAD_RUNNING; + + oldthread = current_thread; + + if (newthread == oldthread) + return; + + /* set up quantum for the new thread if it was consumed */ + if (newthread->remaining_quantum <= 0) { + newthread->remaining_quantum = 5; // XXX make this smarter + } + + /* mark the cpu ownership of the threads */ + thread_set_curr_cpu(oldthread, -1); + thread_set_curr_cpu(newthread, cpu); + +#if WITH_SMP + if (thread_is_idle(newthread)) { + mp_set_cpu_idle(cpu); + } else { + mp_set_cpu_busy(cpu); + } + + if (thread_is_realtime(newthread)) { + mp_set_cpu_realtime(cpu); + } else { + mp_set_cpu_non_realtime(cpu); + } +#endif + +#if THREAD_STATS + THREAD_STATS_INC(context_switches); + + if (thread_is_idle(oldthread)) { + lk_bigtime_t now = current_time_hires(); + thread_stats[cpu].idle_time += now - thread_stats[cpu].last_idle_timestamp; + } + if (thread_is_idle(newthread)) { + thread_stats[cpu].last_idle_timestamp = current_time_hires(); + } +#endif + + KEVLOG_THREAD_SWITCH(oldthread, newthread); + +#if PLATFORM_HAS_DYNAMIC_TIMER + if (thread_is_real_time_or_idle(newthread)) { + if (!thread_is_real_time_or_idle(oldthread)) { + /* if we're switching from a non real time to a real time, cancel + * the preemption timer. */ +#if DEBUG_THREAD_CONTEXT_SWITCH + dprintf(ALWAYS, "arch_context_switch: stop preempt, cpu %d, old %p (%s), new %p (%s)\n", + cpu, oldthread, oldthread->name, newthread, newthread->name); +#endif + timer_cancel(&preempt_timer[cpu]); + } + } else if (thread_is_real_time_or_idle(oldthread)) { + /* if we're switching from a real time (or idle thread) to a regular one, + * set up a periodic timer to run our preemption tick. */ +#if DEBUG_THREAD_CONTEXT_SWITCH + dprintf(ALWAYS, "arch_context_switch: start preempt, cpu %d, old %p (%s), new %p (%s)\n", + cpu, oldthread, oldthread->name, newthread, newthread->name); +#endif + timer_set_periodic(&preempt_timer[cpu], 10, (timer_callback)thread_timer_tick, NULL); + } +#endif + + /* set some optional target debug leds */ + target_set_debug_led(0, !thread_is_idle(newthread)); + + /* do the switch */ + set_current_thread(newthread); + +#if DEBUG_THREAD_CONTEXT_SWITCH + dprintf(ALWAYS, "arch_context_switch: cpu %d, old %p (%s, pri %d, flags 0x%x), new %p (%s, pri %d, flags 0x%x)\n", + cpu, oldthread, oldthread->name, oldthread->priority, + oldthread->flags, newthread, newthread->name, + newthread->priority, newthread->flags); +#endif + +#if THREAD_STACK_BOUNDS_CHECK + /* check that the old thread has not blown its stack just before pushing its context */ + if (oldthread->flags & THREAD_FLAG_DEBUG_STACK_BOUNDS_CHECK) { + STATIC_ASSERT((THREAD_STACK_PADDING_SIZE % sizeof(uint32_t)) == 0); + uint32_t *s = (uint32_t *)oldthread->stack; + for (size_t i = 0; i < THREAD_STACK_PADDING_SIZE / sizeof(uint32_t); i++) { + if (unlikely(s[i] != STACK_DEBUG_WORD)) { + /* NOTE: will probably blow the stack harder here, but hopefully enough + * state exists to at least get some sort of debugging done. + */ + panic("stack overrun at %p: thread %p (%s), stack %p\n", &s[i], + oldthread, oldthread->name, oldthread->stack); + } + } + } +#endif + +#ifdef WITH_LIB_UTHREAD + uthread_context_switch(oldthread, newthread); +#endif + +#if WITH_KERNEL_VM + /* see if we need to swap mmu context */ + if (newthread->aspace != oldthread->aspace) { + vmm_context_switch(oldthread->aspace, newthread->aspace); + } +#endif + + /* do the low level context switch */ + arch_context_switch(oldthread, newthread); +} + +/** + * @brief Yield the cpu to another thread + * + * This function places the current thread at the end of the run queue + * and yields the cpu to another waiting thread (if any.) + * + * This function will return at some later time. Possibly immediately if + * no other threads are waiting to execute. + */ +void thread_yield(void) +{ + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(current_thread->magic == THREAD_MAGIC); + DEBUG_ASSERT(current_thread->state == THREAD_RUNNING); + + THREAD_LOCK(state); + + THREAD_STATS_INC(yields); + + /* we are yielding the cpu, so stick ourselves into the tail of the run queue and reschedule */ + current_thread->state = THREAD_READY; + current_thread->remaining_quantum = 0; + if (likely(!thread_is_idle(current_thread))) { /* idle thread doesn't go in the run queue */ + insert_in_run_queue_tail(current_thread); + } + thread_resched(); + + THREAD_UNLOCK(state); +} + +/** + * @brief Briefly yield cpu to another thread + * + * This function is similar to thread_yield(), except that it will + * restart more quickly. + * + * This function places the current thread at the head of the run + * queue and then yields the cpu to another thread. + * + * Exception: If the time slice for this thread has expired, then + * the thread goes to the end of the run queue. + * + * This function will return at some later time. Possibly immediately if + * no other threads are waiting to execute. + */ +void thread_preempt(void) +{ + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(current_thread->magic == THREAD_MAGIC); + DEBUG_ASSERT(current_thread->state == THREAD_RUNNING); + +#if THREAD_STATS + if (!thread_is_idle(current_thread)) + THREAD_STATS_INC(preempts); /* only track when a meaningful preempt happens */ +#endif + + KEVLOG_THREAD_PREEMPT(current_thread); + + THREAD_LOCK(state); + + /* we are being preempted, so we get to go back into the front of the run queue if we have quantum left */ + current_thread->state = THREAD_READY; + if (likely(!thread_is_idle(current_thread))) { /* idle thread doesn't go in the run queue */ + if (current_thread->remaining_quantum > 0) + insert_in_run_queue_head(current_thread); + else + insert_in_run_queue_tail(current_thread); /* if we're out of quantum, go to the tail of the queue */ + } + thread_resched(); + + THREAD_UNLOCK(state); +} + +/** + * @brief Suspend thread until woken. + * + * This function schedules another thread to execute. This function does not + * return until the thread is made runable again by some other module. + * + * You probably don't want to call this function directly; it's meant to be called + * from other modules, such as mutex, which will presumably set the thread's + * state to blocked and add it to some queue or another. + */ +void thread_block(void) +{ + __UNUSED thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(current_thread->magic == THREAD_MAGIC); + DEBUG_ASSERT(current_thread->state == THREAD_BLOCKED); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + DEBUG_ASSERT(!thread_is_idle(current_thread)); + + /* we are blocking on something. the blocking code should have already stuck us on a queue */ + thread_resched(); +} + +void thread_unblock(thread_t *t, bool resched) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(t->state == THREAD_BLOCKED); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + DEBUG_ASSERT(!thread_is_idle(t)); + + t->state = THREAD_READY; + insert_in_run_queue_head(t); + mp_reschedule(MP_CPU_ALL_BUT_LOCAL, 0); + if (resched) + thread_resched(); +} + +enum handler_return thread_timer_tick(void) +{ + thread_t *current_thread = get_current_thread(); + + if (thread_is_real_time_or_idle(current_thread)) + return INT_NO_RESCHEDULE; + + current_thread->remaining_quantum--; + if (current_thread->remaining_quantum <= 0) { + return INT_RESCHEDULE; + } else { + return INT_NO_RESCHEDULE; + } +} + +/* timer callback to wake up a sleeping thread */ +static enum handler_return thread_sleep_handler(timer_t *timer, lk_time_t now, void *arg) +{ + thread_t *t = (thread_t *)arg; + + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(t->state == THREAD_SLEEPING); + + THREAD_LOCK(state); + + t->state = THREAD_READY; + insert_in_run_queue_head(t); + + THREAD_UNLOCK(state); + + return INT_RESCHEDULE; +} + +/** + * @brief Put thread to sleep; delay specified in ms + * + * This function puts the current thread to sleep until the specified + * delay in ms has expired. + * + * Note that this function could sleep for longer than the specified delay if + * other threads are running. When the timer expires, this thread will + * be placed at the head of the run queue. + */ +void thread_sleep(lk_time_t delay) +{ + timer_t timer; + + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(current_thread->magic == THREAD_MAGIC); + DEBUG_ASSERT(current_thread->state == THREAD_RUNNING); + DEBUG_ASSERT(!thread_is_idle(current_thread)); + + timer_initialize(&timer); + + THREAD_LOCK(state); + timer_set_oneshot(&timer, delay, thread_sleep_handler, (void *)current_thread); + current_thread->state = THREAD_SLEEPING; + thread_resched(); + THREAD_UNLOCK(state); +} + +/** + * @brief Initialize threading system + * + * This function is called once, from kmain() + */ +void thread_init_early(void) +{ + int i; + + DEBUG_ASSERT(arch_curr_cpu_num() == 0); + + /* initialize the run queues */ + for (i=0; i < NUM_PRIORITIES; i++) + list_initialize(&run_queue[i]); + + /* initialize the thread list */ + list_initialize(&thread_list); + + /* create a thread to cover the current running state */ + thread_t *t = idle_thread(0); + init_thread_struct(t, "bootstrap"); + + /* half construct this thread, since we're already running */ + t->priority = HIGHEST_PRIORITY; + t->state = THREAD_RUNNING; + t->flags = THREAD_FLAG_DETACHED; + thread_set_curr_cpu(t, 0); + thread_set_pinned_cpu(t, 0); + wait_queue_init(&t->retcode_wait_queue); + list_add_head(&thread_list, &t->thread_list_node); + set_current_thread(t); +} + +/** + * @brief Complete thread initialization + * + * This function is called once at boot time + */ +void thread_init(void) +{ +#if PLATFORM_HAS_DYNAMIC_TIMER + for (uint i = 0; i < SMP_MAX_CPUS; i++) { + timer_initialize(&preempt_timer[i]); + } +#endif +} + +/** + * @brief Change name of current thread + */ +void thread_set_name(const char *name) +{ + thread_t *current_thread = get_current_thread(); + strlcpy(current_thread->name, name, sizeof(current_thread->name)); +} + +/** + * @brief Change priority of current thread + * + * See thread_create() for a discussion of priority values. + */ +void thread_set_priority(int priority) +{ + thread_t *current_thread = get_current_thread(); + + THREAD_LOCK(state); + + if (priority <= IDLE_PRIORITY) + priority = IDLE_PRIORITY + 1; + if (priority > HIGHEST_PRIORITY) + priority = HIGHEST_PRIORITY; + current_thread->priority = priority; + + current_thread->state = THREAD_READY; + insert_in_run_queue_head(current_thread); + thread_resched(); + + THREAD_UNLOCK(state); +} + +/** + * @brief Become an idle thread + * + * This function marks the current thread as the idle thread -- the one which + * executes when there is nothing else to do. This function does not return. + * This function is called once at boot time. + */ +void thread_become_idle(void) +{ + DEBUG_ASSERT(arch_ints_disabled()); + + thread_t *t = get_current_thread(); + +#if WITH_SMP + char name[16]; + snprintf(name, sizeof(name), "idle %d", arch_curr_cpu_num()); + thread_set_name(name); +#else + thread_set_name("idle"); +#endif + + /* mark ourself as idle */ + t->priority = IDLE_PRIORITY; + t->flags |= THREAD_FLAG_IDLE; + thread_set_pinned_cpu(t, arch_curr_cpu_num()); + + mp_set_curr_cpu_active(true); + mp_set_cpu_idle(arch_curr_cpu_num()); + + /* enable interrupts and start the scheduler */ + arch_enable_ints(); + thread_yield(); + + idle_thread_routine(); +} + +/* create an idle thread for the cpu we're on, and start scheduling */ + +void thread_secondary_cpu_init_early(void) +{ + DEBUG_ASSERT(arch_ints_disabled()); + + /* construct an idle thread to cover our cpu */ + uint cpu = arch_curr_cpu_num(); + thread_t *t = idle_thread(cpu); + + char name[16]; + snprintf(name, sizeof(name), "idle %u", cpu); + init_thread_struct(t, name); + thread_set_pinned_cpu(t, cpu); + + /* half construct this thread, since we're already running */ + t->priority = HIGHEST_PRIORITY; + t->state = THREAD_RUNNING; + t->flags = THREAD_FLAG_DETACHED | THREAD_FLAG_IDLE; + thread_set_curr_cpu(t, cpu); + thread_set_pinned_cpu(t, cpu); + wait_queue_init(&t->retcode_wait_queue); + + THREAD_LOCK(state); + + list_add_head(&thread_list, &t->thread_list_node); + set_current_thread(t); + + THREAD_UNLOCK(state); +} + +void thread_secondary_cpu_entry(void) +{ + uint cpu = arch_curr_cpu_num(); + thread_t *t = get_current_thread(); + t->priority = IDLE_PRIORITY; + + mp_set_curr_cpu_active(true); + mp_set_cpu_idle(cpu); + + /* enable interrupts and start the scheduler on this cpu */ + arch_enable_ints(); + thread_yield(); + + idle_thread_routine(); +} + +static const char *thread_state_to_str(enum thread_state state) +{ + switch (state) { + case THREAD_SUSPENDED: + return "susp"; + case THREAD_READY: + return "rdy"; + case THREAD_RUNNING: + return "run"; + case THREAD_BLOCKED: + return "blok"; + case THREAD_SLEEPING: + return "slep"; + case THREAD_DEATH: + return "deth"; + default: + return "unkn"; + } +} + +/** + * @brief Dump debugging info about the specified thread. + */ +void dump_thread(thread_t *t) +{ + dprintf(INFO, "dump_thread: t %p (%s)\n", t, t->name); +#if WITH_SMP + dprintf(INFO, "\tstate %s, curr_cpu %d, pinned_cpu %d, priority %d, remaining quantum %d\n", + thread_state_to_str(t->state), t->curr_cpu, t->pinned_cpu, t->priority, t->remaining_quantum); +#else + dprintf(INFO, "\tstate %s, priority %d, remaining quantum %d\n", + thread_state_to_str(t->state), t->priority, t->remaining_quantum); +#endif + dprintf(INFO, "\tstack %p, stack_size %zd\n", t->stack, t->stack_size); + dprintf(INFO, "\tentry %p, arg %p, flags 0x%x\n", t->entry, t->arg, t->flags); + dprintf(INFO, "\twait queue %p, wait queue ret %d\n", t->blocking_wait_queue, t->wait_queue_block_ret); +#if WITH_KERNEL_VM + dprintf(INFO, "\taspace %p\n", t->aspace); +#endif + if (MAX_TLS_ENTRY > 0) { + dprintf(INFO, "\ttls:"); + int i; + for (i=0; i < MAX_TLS_ENTRY; i++) { + dprintf(INFO, " 0x%lx", t->tls[i]); + } + dprintf(INFO, "\n"); + } + arch_dump_thread(t); +} + +/** + * @brief Dump debugging info about all threads + */ +void dump_all_threads(void) +{ + thread_t *t; + + THREAD_LOCK(state); + list_for_every_entry(&thread_list, t, thread_t, thread_list_node) { + if (t->magic != THREAD_MAGIC) { + dprintf(INFO, "bad magic on thread struct %p, aborting.\n", t); + hexdump(t, sizeof(thread_t)); + break; + } + dump_thread(t); + } + THREAD_UNLOCK(state); +} + +/** @} */ + + +/** + * @defgroup wait Wait Queue + * @{ + */ +void wait_queue_init(wait_queue_t *wait) +{ + *wait = (wait_queue_t)WAIT_QUEUE_INITIAL_VALUE(*wait); +} + +static enum handler_return wait_queue_timeout_handler(timer_t *timer, lk_time_t now, void *arg) +{ + thread_t *thread = (thread_t *)arg; + + DEBUG_ASSERT(thread->magic == THREAD_MAGIC); + + spin_lock(&thread_lock); + + enum handler_return ret = INT_NO_RESCHEDULE; + if (thread_unblock_from_wait_queue(thread, ERR_TIMED_OUT) >= NO_ERROR) { + ret = INT_RESCHEDULE; + } + + spin_unlock(&thread_lock); + + return ret; +} + +/** + * @brief Block until a wait queue is notified. + * + * This function puts the current thread at the end of a wait + * queue and then blocks until some other thread wakes the queue + * up again. + * + * @param wait The wait queue to enter + * @param timeout The maximum time, in ms, to wait + * + * If the timeout is zero, this function returns immediately with + * ERR_TIMED_OUT. If the timeout is INFINITE_TIME, this function + * waits indefinitely. Otherwise, this function returns with + * ERR_TIMED_OUT at the end of the timeout period. + * + * @return ERR_TIMED_OUT on timeout, else returns the return + * value specified when the queue was woken by wait_queue_wake_one(). + */ +status_t wait_queue_block(wait_queue_t *wait, lk_time_t timeout) +{ + timer_t timer; + + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(wait->magic == WAIT_QUEUE_MAGIC); + DEBUG_ASSERT(current_thread->state == THREAD_RUNNING); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + if (timeout == 0) + return ERR_TIMED_OUT; + + list_add_tail(&wait->list, ¤t_thread->queue_node); + wait->count++; + current_thread->state = THREAD_BLOCKED; + current_thread->blocking_wait_queue = wait; + current_thread->wait_queue_block_ret = NO_ERROR; + + /* if the timeout is nonzero or noninfinite, set a callback to yank us out of the queue */ + if (timeout != INFINITE_TIME) { + timer_initialize(&timer); + timer_set_oneshot(&timer, timeout, wait_queue_timeout_handler, (void *)current_thread); + } + + thread_resched(); + + /* we don't really know if the timer fired or not, so it's better safe to try to cancel it */ + if (timeout != INFINITE_TIME) { + timer_cancel(&timer); + } + + return current_thread->wait_queue_block_ret; +} + +/** + * @brief Wake up one thread sleeping on a wait queue + * + * This function removes one thread (if any) from the head of the wait queue and + * makes it executable. The new thread will be placed at the head of the + * run queue. + * + * @param wait The wait queue to wake + * @param reschedule If true, the newly-woken thread will run immediately. + * @param wait_queue_error The return value which the new thread will receive + * from wait_queue_block(). + * + * @return The number of threads woken (zero or one) + */ +int wait_queue_wake_one(wait_queue_t *wait, bool reschedule, status_t wait_queue_error) +{ + thread_t *t; + int ret = 0; + + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(wait->magic == WAIT_QUEUE_MAGIC); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + t = list_remove_head_type(&wait->list, thread_t, queue_node); + if (t) { + wait->count--; + DEBUG_ASSERT(t->state == THREAD_BLOCKED); + t->state = THREAD_READY; + t->wait_queue_block_ret = wait_queue_error; + t->blocking_wait_queue = NULL; + + /* if we're instructed to reschedule, stick the current thread on the head + * of the run queue first, so that the newly awakened thread gets a chance to run + * before the current one, but the current one doesn't get unnecessarilly punished. + */ + if (reschedule) { + current_thread->state = THREAD_READY; + insert_in_run_queue_head(current_thread); + } + insert_in_run_queue_head(t); + mp_reschedule(MP_CPU_ALL_BUT_LOCAL, 0); + if (reschedule) { + thread_resched(); + } + ret = 1; + + } + + return ret; +} + + +/** + * @brief Wake all threads sleeping on a wait queue + * + * This function removes all threads (if any) from the wait queue and + * makes them executable. The new threads will be placed at the head of the + * run queue. + * + * @param wait The wait queue to wake + * @param reschedule If true, the newly-woken threads will run immediately. + * @param wait_queue_error The return value which the new thread will receive + * from wait_queue_block(). + * + * @return The number of threads woken (zero or one) + */ +int wait_queue_wake_all(wait_queue_t *wait, bool reschedule, status_t wait_queue_error) +{ + thread_t *t; + int ret = 0; + + thread_t *current_thread = get_current_thread(); + + DEBUG_ASSERT(wait->magic == WAIT_QUEUE_MAGIC); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + if (reschedule && wait->count > 0) { + /* if we're instructed to reschedule, stick the current thread on the head + * of the run queue first, so that the newly awakened threads get a chance to run + * before the current one, but the current one doesn't get unnecessarilly punished. + */ + current_thread->state = THREAD_READY; + insert_in_run_queue_head(current_thread); + } + + /* pop all the threads off the wait queue into the run queue */ + while ((t = list_remove_head_type(&wait->list, thread_t, queue_node))) { + wait->count--; + DEBUG_ASSERT(t->state == THREAD_BLOCKED); + t->state = THREAD_READY; + t->wait_queue_block_ret = wait_queue_error; + t->blocking_wait_queue = NULL; + + insert_in_run_queue_head(t); + ret++; + } + + DEBUG_ASSERT(wait->count == 0); + + if (ret > 0) { + mp_reschedule(MP_CPU_ALL_BUT_LOCAL, 0); + if (reschedule) { + thread_resched(); + } + } + + return ret; +} + +/** + * @brief Free all resources allocated in wait_queue_init() + * + * If any threads were waiting on this queue, they are all woken. + */ +void wait_queue_destroy(wait_queue_t *wait, bool reschedule) +{ + DEBUG_ASSERT(wait->magic == WAIT_QUEUE_MAGIC); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + wait_queue_wake_all(wait, reschedule, ERR_OBJECT_DESTROYED); + wait->magic = 0; +} + +/** + * @brief Wake a specific thread in a wait queue + * + * This function extracts a specific thread from a wait queue, wakes it, and + * puts it at the head of the run queue. + * + * @param t The thread to wake + * @param wait_queue_error The return value which the new thread will receive + * from wait_queue_block(). + * + * @return ERR_NOT_BLOCKED if thread was not in any wait queue. + */ +status_t thread_unblock_from_wait_queue(thread_t *t, status_t wait_queue_error) +{ + DEBUG_ASSERT(t->magic == THREAD_MAGIC); + DEBUG_ASSERT(arch_ints_disabled()); + DEBUG_ASSERT(spin_lock_held(&thread_lock)); + + if (t->state != THREAD_BLOCKED) + return ERR_NOT_BLOCKED; + + DEBUG_ASSERT(t->blocking_wait_queue != NULL); + DEBUG_ASSERT(t->blocking_wait_queue->magic == WAIT_QUEUE_MAGIC); + DEBUG_ASSERT(list_in_list(&t->queue_node)); + + list_delete(&t->queue_node); + t->blocking_wait_queue->count--; + t->blocking_wait_queue = NULL; + t->state = THREAD_READY; + t->wait_queue_block_ret = wait_queue_error; + insert_in_run_queue_head(t); + mp_reschedule(MP_CPU_ALL_BUT_LOCAL, 0); + + return NO_ERROR; +} + +#if defined(WITH_DEBUGGER_INFO) +// This is, by necessity, arch-specific, and arm-m specific right now, +// but lives here due to thread_list being static. +// +// It contains sufficient information for a remote debugger to walk +// the thread list without needing the symbols and debug sections in +// the elf binary for lk or the ability to parse them. +const struct __debugger_info__ { + u32 version; // flags:16 major:8 minor:8 + void *thread_list_ptr; + void *current_thread_ptr; + u8 off_list_node; + u8 off_state; + u8 off_saved_sp; + u8 off_was_preempted; + u8 off_name; + u8 off_waitq; +} _debugger_info = { + .version = 0x0100, + .thread_list_ptr = &thread_list, + .current_thread_ptr = &_current_thread, + .off_list_node = __builtin_offsetof(thread_t, thread_list_node), + .off_state = __builtin_offsetof(thread_t, state), + .off_saved_sp = __builtin_offsetof(thread_t, arch.sp), + .off_was_preempted = __builtin_offsetof(thread_t, arch.was_preempted), + .off_name = __builtin_offsetof(thread_t, name), + .off_waitq = __builtin_offsetof(thread_t, blocking_wait_queue), +}; +#endif diff --git a/kernel/kernel/timer.c b/kernel/kernel/timer.c new file mode 100644 index 000000000..df118333f --- /dev/null +++ b/kernel/kernel/timer.c @@ -0,0 +1,297 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Kernel timer subsystem + * @defgroup timer Timers + * + * The timer subsystem allows functions to be scheduled for later + * execution. Each timer object is used to cause one function to + * be executed at a later time. + * + * Timer callback functions are called in interrupt context. + * + * @{ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +spin_lock_t timer_lock; + +struct timer_state { + struct list_node timer_queue; +} __CPU_ALIGN; + +static struct timer_state timers[SMP_MAX_CPUS]; + +static enum handler_return timer_tick(void *arg, lk_time_t now); + +/** + * @brief Initialize a timer object + */ +void timer_initialize(timer_t *timer) +{ + *timer = (timer_t)TIMER_INITIAL_VALUE(*timer); +} + +static void insert_timer_in_queue(uint cpu, timer_t *timer) +{ + timer_t *entry; + + DEBUG_ASSERT(arch_ints_disabled()); + + LTRACEF("timer %p, cpu %u, scheduled %u, periodic %u\n", timer, cpu, timer->scheduled_time, timer->periodic_time); + + list_for_every_entry(&timers[cpu].timer_queue, entry, timer_t, node) { + if (TIME_GT(entry->scheduled_time, timer->scheduled_time)) { + list_add_before(&entry->node, &timer->node); + return; + } + } + + /* walked off the end of the list */ + list_add_tail(&timers[cpu].timer_queue, &timer->node); +} + +static void timer_set(timer_t *timer, lk_time_t delay, lk_time_t period, timer_callback callback, void *arg) +{ + lk_time_t now; + + LTRACEF("timer %p, delay %u, period %u, callback %p, arg %p\n", timer, delay, period, callback, arg); + + DEBUG_ASSERT(timer->magic == TIMER_MAGIC); + + if (list_in_list(&timer->node)) { + panic("timer %p already in list\n", timer); + } + + now = current_time(); + timer->scheduled_time = now + delay; + timer->periodic_time = period; + timer->callback = callback; + timer->arg = arg; + + LTRACEF("scheduled time %u\n", timer->scheduled_time); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&timer_lock, state); + + uint cpu = arch_curr_cpu_num(); + insert_timer_in_queue(cpu, timer); + +#if PLATFORM_HAS_DYNAMIC_TIMER + if (list_peek_head_type(&timers[cpu].timer_queue, timer_t, node) == timer) { + /* we just modified the head of the timer queue */ + LTRACEF("setting new timer for %u msecs\n", delay); + platform_set_oneshot_timer(timer_tick, NULL, delay); + } +#endif + + spin_unlock_irqrestore(&timer_lock, state); +} + +/** + * @brief Set up a timer that executes once + * + * This function specifies a callback function to be called after a specified + * delay. The function will be called one time. + * + * @param timer The timer to use + * @param delay The delay, in ms, before the timer is executed + * @param callback The function to call when the timer expires + * @param arg The argument to pass to the callback + * + * The timer function is declared as: + * enum handler_return callback(struct timer *, lk_time_t now, void *arg) { ... } + */ +void timer_set_oneshot(timer_t *timer, lk_time_t delay, timer_callback callback, void *arg) +{ + if (delay == 0) + delay = 1; + timer_set(timer, delay, 0, callback, arg); +} + +/** + * @brief Set up a timer that executes repeatedly + * + * This function specifies a callback function to be called after a specified + * delay. The function will be called repeatedly. + * + * @param timer The timer to use + * @param delay The delay, in ms, before the timer is executed + * @param callback The function to call when the timer expires + * @param arg The argument to pass to the callback + * + * The timer function is declared as: + * enum handler_return callback(struct timer *, lk_time_t now, void *arg) { ... } + */ +void timer_set_periodic(timer_t *timer, lk_time_t period, timer_callback callback, void *arg) +{ + if (period == 0) + period = 1; + timer_set(timer, period, period, callback, arg); +} + +/** + * @brief Cancel a pending timer + */ +void timer_cancel(timer_t *timer) +{ + DEBUG_ASSERT(timer->magic == TIMER_MAGIC); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&timer_lock, state); + +#if PLATFORM_HAS_DYNAMIC_TIMER + uint cpu = arch_curr_cpu_num(); + + timer_t *oldhead = list_peek_head_type(&timers[cpu].timer_queue, timer_t, node); +#endif + + if (list_in_list(&timer->node)) + list_delete(&timer->node); + + /* to keep it from being reinserted into the queue if called from + * periodic timer callback. + */ + timer->periodic_time = 0; + timer->callback = NULL; + timer->arg = NULL; + +#if PLATFORM_HAS_DYNAMIC_TIMER + /* see if we've just modified the head of the timer queue */ + timer_t *newhead = list_peek_head_type(&timers[cpu].timer_queue, timer_t, node); + if (newhead == NULL) { + LTRACEF("clearing old hw timer, nothing in the queue\n"); + platform_stop_timer(); + } else if (newhead != oldhead) { + lk_time_t delay; + lk_time_t now = current_time(); + + if (TIME_LT(newhead->scheduled_time, now)) + delay = 0; + else + delay = newhead->scheduled_time - now; + + LTRACEF("setting new timer to %u\n", (uint) delay); + platform_set_oneshot_timer(timer_tick, NULL, delay); + } +#endif + + spin_unlock_irqrestore(&timer_lock, state); +} + +/* called at interrupt time to process any pending timers */ +static enum handler_return timer_tick(void *arg, lk_time_t now) +{ + timer_t *timer; + enum handler_return ret = INT_NO_RESCHEDULE; + + DEBUG_ASSERT(arch_ints_disabled()); + + THREAD_STATS_INC(timer_ints); +// KEVLOG_TIMER_TICK(); // enable only if necessary + + uint cpu = arch_curr_cpu_num(); + + LTRACEF("cpu %u now %u, sp %p\n", cpu, now, __GET_FRAME()); + + spin_lock(&timer_lock); + + for (;;) { + /* see if there's an event to process */ + timer = list_peek_head_type(&timers[cpu].timer_queue, timer_t, node); + if (likely(timer == 0)) + break; + LTRACEF("next item on timer queue %p at %u now %u (%p, arg %p)\n", timer, timer->scheduled_time, now, timer->callback, timer->arg); + if (likely(TIME_LT(now, timer->scheduled_time))) + break; + + /* process it */ + LTRACEF("timer %p\n", timer); + DEBUG_ASSERT(timer && timer->magic == TIMER_MAGIC); + list_delete(&timer->node); + + /* we pulled it off the list, release the list lock to handle it */ + spin_unlock(&timer_lock); + + LTRACEF("dequeued timer %p, scheduled %u periodic %u\n", timer, timer->scheduled_time, timer->periodic_time); + + THREAD_STATS_INC(timers); + + bool periodic = timer->periodic_time > 0; + + LTRACEF("timer %p firing callback %p, arg %p\n", timer, timer->callback, timer->arg); + KEVLOG_TIMER_CALL(timer->callback, timer->arg); + if (timer->callback(timer, now, timer->arg) == INT_RESCHEDULE) + ret = INT_RESCHEDULE; + + DEBUG_ASSERT(arch_ints_disabled()); + /* it may have been requeued or periodic, grab the lock so we can safely inspect it */ + spin_lock(&timer_lock); + + /* if it was a periodic timer and it hasn't been requeued + * by the callback put it back in the list + */ + if (periodic && !list_in_list(&timer->node) && timer->periodic_time > 0) { + LTRACEF("periodic timer, period %u\n", timer->periodic_time); + timer->scheduled_time = now + timer->periodic_time; + insert_timer_in_queue(cpu, timer); + } + } + +#if PLATFORM_HAS_DYNAMIC_TIMER + /* reset the timer to the next event */ + timer = list_peek_head_type(&timers[cpu].timer_queue, timer_t, node); + if (timer) { + /* has to be the case or it would have fired already */ + DEBUG_ASSERT(TIME_GT(timer->scheduled_time, now)); + + lk_time_t delay = timer->scheduled_time - now; + + LTRACEF("setting new timer for %u msecs for event %p\n", (uint)delay, timer); + platform_set_oneshot_timer(timer_tick, NULL, delay); + } + + /* we're done manipulating the timer queue */ + spin_unlock(&timer_lock); +#else + /* release the timer lock before calling the tick handler */ + spin_unlock(&timer_lock); + + /* let the scheduler have a shot to do quantum expiration, etc */ + /* in case of dynamic timer, the scheduler will set up a periodic timer */ + if (thread_timer_tick() == INT_RESCHEDULE) + ret = INT_RESCHEDULE; +#endif + + return ret; +} + +void timer_init(void) +{ + timer_lock = SPIN_LOCK_INITIAL_VALUE; + for (uint i = 0; i < SMP_MAX_CPUS; i++) { + list_initialize(&timers[i].timer_queue); + } +#if !PLATFORM_HAS_DYNAMIC_TIMER + /* register for a periodic timer tick */ + platform_set_periodic_timer(timer_tick, NULL, 10); /* 10ms */ +#endif +} diff --git a/kernel/kernel/vm/BUILD.gn b/kernel/kernel/vm/BUILD.gn new file mode 100644 index 000000000..cca3d6397 --- /dev/null +++ b/kernel/kernel/vm/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +module("vm") { + configs += [ "//kernel/kernel:enable_vm" ] + defines = kernel_defines + sources = [ + "bootalloc.cpp", + "pmm.cpp", + "vm.cpp", + "vm_aspace.cpp", + "vm_object.cpp", + "vm_priv.h", + "vm_region.cpp", + "vmm.cpp", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + "//kernel/lib/user_copy", + "//kernel/lib/utils", + ] +} diff --git a/kernel/kernel/vm/bootalloc.cpp b/kernel/kernel/vm/bootalloc.cpp new file mode 100644 index 000000000..91d7caba1 --- /dev/null +++ b/kernel/kernel/vm/bootalloc.cpp @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "vm_priv.h" +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) + +/* cheezy allocator that chews up space just after the end of the kernel mapping */ + +/* track how much memory we've used */ +extern int _end; + +uintptr_t boot_alloc_start = (uintptr_t)&_end; +uintptr_t boot_alloc_end = (uintptr_t)&_end; + +void* boot_alloc_mem(size_t len) { + uintptr_t ptr; + + ptr = ALIGN(boot_alloc_end, 8); + boot_alloc_end = (ptr + ALIGN(len, 8)); + + LTRACEF("len %zu, ptr %p\n", len, (void*)ptr); + + return (void*)ptr; +} diff --git a/kernel/kernel/vm/pmm.cpp b/kernel/kernel/vm/pmm.cpp new file mode 100644 index 000000000..1e8c7c36a --- /dev/null +++ b/kernel/kernel/vm/pmm.cpp @@ -0,0 +1,569 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "vm_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) + +static struct list_node arena_list = LIST_INITIAL_VALUE(arena_list); +static mutex_t lock = MUTEX_INITIAL_VALUE(lock); + +#define PAGE_BELONGS_TO_ARENA(page, arena) \ + (((uintptr_t)(page) >= (uintptr_t)(arena)->page_array) && \ + ((uintptr_t)(page) < \ + ((uintptr_t)(arena)->page_array + (arena)->size / PAGE_SIZE * sizeof(vm_page_t)))) + +#define PAGE_ADDRESS_FROM_ARENA(page, arena) \ + ((paddr_t)(((uintptr_t)(page) - (uintptr_t)(arena)->page_array) / sizeof(vm_page_t)) * PAGE_SIZE + \ + (arena)->base) + +#define ADDRESS_IN_ARENA(address, arena) \ + ((address) >= (arena)->base && (address) <= (arena)->base + (arena)->size - 1) + +static inline bool page_is_free(const vm_page_t* page) { + return page->state == VM_PAGE_STATE_FREE; +} + +paddr_t vm_page_to_paddr(const vm_page_t* page) { + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + if (PAGE_BELONGS_TO_ARENA(page, a)) { + return PAGE_ADDRESS_FROM_ARENA(page, a); + } + } + return -1; +} + +vm_page_t* paddr_to_vm_page(paddr_t addr) { + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + if (addr >= a->base && addr <= a->base + a->size - 1) { + size_t index = (addr - a->base) / PAGE_SIZE; + return &a->page_array[index]; + } + } + return NULL; +} + +status_t pmm_add_arena(pmm_arena_t* arena) { + LTRACEF("arena %p name '%s' base 0x%lx size 0x%zx\n", arena, arena->name, arena->base, + arena->size); + + DEBUG_ASSERT(IS_PAGE_ALIGNED(arena->base)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(arena->size)); + DEBUG_ASSERT(arena->size > 0); + + /* walk the arena list and add arena based on priority order */ + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + if (a->priority > arena->priority) { + list_add_before(&a->node, &arena->node); + goto done_add; + } + } + + /* walked off the end, add it to the end of the list */ + list_add_tail(&arena_list, &arena->node); + +done_add: + + /* zero out some of the structure */ + arena->free_count = 0; + list_initialize(&arena->free_list); + + /* allocate an array of pages to back this one */ + size_t page_count = arena->size / PAGE_SIZE; + arena->page_array = (vm_page_t*)boot_alloc_mem(page_count * sizeof(vm_page_t)); + + /* initialize all of the pages */ + memset(arena->page_array, 0, page_count * sizeof(vm_page_t)); + + /* add them to the free list */ + for (size_t i = 0; i < page_count; i++) { + vm_page_t* p = &arena->page_array[i]; + + list_add_tail(&arena->free_list, &p->node); + + arena->free_count++; + } + + return NO_ERROR; +} + +vm_page_t* pmm_alloc_page(uint alloc_flags, paddr_t* pa) { + AutoLock al(lock); + + /* walk the arenas in order until we find one with a free page */ + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + /* skip the arena if it's not KMAP and the KMAP only allocation flag was passed */ + if (alloc_flags & PMM_ALLOC_FLAG_KMAP) { + if ((a->flags & PMM_ARENA_FLAG_KMAP) == 0) + continue; + } + vm_page_t* page = list_remove_head_type(&a->free_list, vm_page_t, node); + if (!page) + continue; + + a->free_count--; + + DEBUG_ASSERT(page_is_free(page)); + + page->state = VM_PAGE_STATE_ALLOC; + + if (pa) { + /* compute the physical address of the page based on its offset into the arena */ + *pa = PAGE_ADDRESS_FROM_ARENA(page, a); + } + + LTRACEF("allocating page %p, pa 0x%lx\n", page, PAGE_ADDRESS_FROM_ARENA(page, a)); + + return page; + } + + LTRACEF("failed to allocate page\n"); + return nullptr; +} + +size_t pmm_alloc_pages(size_t count, uint alloc_flags, struct list_node* list) { + LTRACEF("count %zu\n", count); + + /* list must be initialized prior to calling this */ + DEBUG_ASSERT(list); + + uint allocated = 0; + if (count == 0) + return 0; + + AutoLock al(lock); + + /* walk the arenas in order, allocating as many pages as we can from each */ + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + /* skip the arena if it's not KMAP and the KMAP only allocation flag was passed */ + if (alloc_flags & PMM_ALLOC_FLAG_KMAP) { + if ((a->flags & PMM_ARENA_FLAG_KMAP) == 0) + continue; + } + while (allocated < count) { + vm_page_t* page = list_remove_head_type(&a->free_list, vm_page_t, node); + if (!page) + return allocated; + + a->free_count--; + + DEBUG_ASSERT(page_is_free(page)); + + page->state = VM_PAGE_STATE_ALLOC; + list_add_tail(list, &page->node); + + allocated++; + } + } + + return allocated; +} + +size_t pmm_alloc_range(paddr_t address, size_t count, struct list_node* list) { + LTRACEF("address 0x%lx, count %zu\n", address, count); + + uint allocated = 0; + if (count == 0) + return 0; + + address = ROUNDDOWN(address, PAGE_SIZE); + + AutoLock al(lock); + + /* walk through the arenas, looking to see if the physical page belongs to it */ + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + while (allocated < count && ADDRESS_IN_ARENA(address, a)) { + size_t index = (address - a->base) / PAGE_SIZE; + + DEBUG_ASSERT(index < a->size / PAGE_SIZE); + + vm_page_t* page = &a->page_array[index]; + if (!page_is_free(page)) { + /* we hit an allocated page */ + break; + } + + DEBUG_ASSERT(list_in_list(&page->node)); + + list_delete(&page->node); + page->state = VM_PAGE_STATE_ALLOC; + + if (list) + list_add_tail(list, &page->node); + + a->free_count--; + allocated++; + address += PAGE_SIZE; + } + + if (allocated == count) + break; + } + + return allocated; +} + +size_t pmm_alloc_contiguous(size_t count, uint alloc_flags, uint8_t alignment_log2, paddr_t* pa, + struct list_node* list) { + LTRACEF("count %zu, align %u\n", count, alignment_log2); + + if (count == 0) + return 0; + if (alignment_log2 < PAGE_SIZE_SHIFT) + alignment_log2 = PAGE_SIZE_SHIFT; + + AutoLock al(lock); + + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + /* skip the arena if it's not KMAP and the KMAP only allocation flag was passed */ + if (alloc_flags & PMM_ALLOC_FLAG_KMAP) { + if ((a->flags & PMM_ARENA_FLAG_KMAP) == 0) + continue; + } + /* walk the list starting at alignment boundaries. + * calculate the starting offset into this arena, based on the + * base address of the arena to handle the case where the arena + * is not aligned on the same boundary requested. + */ + paddr_t rounded_base = ROUNDUP(a->base, 1UL << alignment_log2); + if (rounded_base < a->base || rounded_base > a->base + a->size - 1) + continue; + + paddr_t aligned_offset = (rounded_base - a->base) / PAGE_SIZE; + paddr_t start = aligned_offset; + LTRACEF("starting search at aligned offset %lu\n", start); + LTRACEF("arena base 0x%lx size %zu\n", a->base, a->size); + + retry: + /* search while we're still within the arena and have a chance of finding a slot + (start + count < end of arena) */ + while ((start < a->size / PAGE_SIZE) && ((start + count) <= a->size / PAGE_SIZE)) { + vm_page_t* p = &a->page_array[start]; + for (uint i = 0; i < count; i++) { + if (!page_is_free(p)) { + /* this run is broken, break out of the inner loop. + * start over at the next alignment boundary + */ + start = ROUNDUP(start - aligned_offset + i + 1, + 1UL << (alignment_log2 - PAGE_SIZE_SHIFT)) + + aligned_offset; + goto retry; + } + p++; + } + + /* we found a run */ + LTRACEF("found run from pn %lu to %lu\n", start, start + count); + + /* remove the pages from the run out of the free list */ + for (paddr_t i = start; i < start + count; i++) { + p = &a->page_array[i]; + DEBUG_ASSERT(page_is_free(p)); + DEBUG_ASSERT(list_in_list(&p->node)); + + list_delete(&p->node); + p->state = VM_PAGE_STATE_ALLOC; + a->free_count--; + + if (list) + list_add_tail(list, &p->node); + } + + if (pa) + *pa = a->base + start * PAGE_SIZE; + + return count; + } + } + + LTRACEF("couldn't find run\n"); + return 0; +} + +/* physically allocate a run from arenas marked as KMAP */ +void* pmm_alloc_kpages(size_t count, struct list_node* list, paddr_t* _pa) { + LTRACEF("count %zu\n", count); + + paddr_t pa; + /* fast path for single count allocations */ + if (count == 1) { + vm_page_t* p = pmm_alloc_page(PMM_ALLOC_FLAG_KMAP, &pa); + if (!p) + return nullptr; + + if (list) { + list_add_tail(list, &p->node); + } + } else { + size_t alloc_count = + pmm_alloc_contiguous(count, PMM_ALLOC_FLAG_KMAP, PAGE_SIZE_SHIFT, &pa, list); + if (alloc_count == 0) + return nullptr; + } + + LTRACEF("pa 0x%lx\n", pa); + void* ptr = paddr_to_kvaddr(pa); + DEBUG_ASSERT(ptr); + + if (_pa) + *_pa = pa; + return ptr; +} + +/* allocate a single page from a KMAP arena and return its virtual address */ +void* pmm_alloc_kpage(paddr_t* _pa) { + LTRACE_ENTRY; + + paddr_t pa; + vm_page_t* p = pmm_alloc_page(PMM_ALLOC_FLAG_KMAP, &pa); + if (!p) + return nullptr; + + void* ptr = paddr_to_kvaddr(pa); + DEBUG_ASSERT(ptr); + + if (_pa) + *_pa = pa; + return ptr; +} + +size_t pmm_free_kpages(void* _ptr, size_t count) { + LTRACEF("ptr %p, count %zu\n", _ptr, count); + + uint8_t* ptr = (uint8_t*)_ptr; + + struct list_node list; + list_initialize(&list); + + while (count > 0) { + vm_page_t* p = paddr_to_vm_page(vaddr_to_paddr(ptr)); + if (p) { + list_add_tail(&list, &p->node); + } + + ptr += PAGE_SIZE; + count--; + } + + return pmm_free(&list); +} + +size_t pmm_free(struct list_node* list) { + LTRACEF("list %p\n", list); + + DEBUG_ASSERT(list); + + AutoLock al(lock); + + uint count = 0; + while (!list_is_empty(list)) { + vm_page_t* page = list_remove_head_type(list, vm_page_t, node); + + DEBUG_ASSERT(!list_in_list(&page->node)); + DEBUG_ASSERT(!page_is_free(page)); + + /* see which arena this page belongs to and add it */ + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { + if (PAGE_BELONGS_TO_ARENA(page, a)) { + page->state = VM_PAGE_STATE_FREE; + + list_add_head(&a->free_list, &page->node); + a->free_count++; + count++; + break; + } + } + } + + return count; +} + +size_t pmm_free_page(vm_page_t* page) { + struct list_node list; + list_initialize(&list); + + list_add_head(&list, &page->node); + + return pmm_free(&list); +} + +static const char* page_state_to_str(const vm_page_t* page) { + switch (page->state) { + case VM_PAGE_STATE_FREE: + return "free"; + case VM_PAGE_STATE_ALLOC: + return "alloc"; + case VM_PAGE_STATE_MMU: + return "mmu"; + default: + return "unknown"; + } +} + +static void dump_page(const vm_page_t* page) { + printf("page %p: address 0x%lx state %s flags 0x%x\n", page, vm_page_to_paddr(page), + page_state_to_str(page), page->flags); +} + +static void dump_arena(const pmm_arena_t* arena, bool dump_pages) { + printf("arena %p: name '%s' base 0x%lx size 0x%zx priority %u flags 0x%x\n", arena, arena->name, + arena->base, arena->size, arena->priority, arena->flags); + printf("\tpage_array %p, free_count %zu\n", arena->page_array, arena->free_count); + + /* dump all of the pages */ + if (dump_pages) { + for (size_t i = 0; i < arena->size / PAGE_SIZE; i++) { + dump_page(&arena->page_array[i]); + } + } + + /* dump the free pages */ + printf("\tfree ranges:\n"); + ssize_t last = -1; + for (size_t i = 0; i < arena->size / PAGE_SIZE; i++) { + if (page_is_free(&arena->page_array[i])) { + if (last == -1) { + last = i; + } + } else { + if (last != -1) { + printf("\t\t0x%lx - 0x%lx\n", arena->base + last * PAGE_SIZE, + arena->base + i * PAGE_SIZE); + } + last = -1; + } + } + + if (last != -1) { + printf("\t\t0x%lx - 0x%lx\n", arena->base + last * PAGE_SIZE, arena->base + arena->size); + } +} + +static int cmd_pmm(int argc, const cmd_args* argv) { + if (argc < 2) { + notenoughargs: + printf("not enough arguments\n"); + usage: + printf("usage:\n"); + printf("%s arenas\n", argv[0].str); + printf("%s alloc \n", argv[0].str); + printf("%s alloc_range
\n", argv[0].str); + printf("%s alloc_kpages \n", argv[0].str); + printf("%s alloc_contig \n", argv[0].str); + printf("%s dump_alloced\n", argv[0].str); + printf("%s free_alloced\n", argv[0].str); + return ERR_GENERIC; + } + + static struct list_node allocated = LIST_INITIAL_VALUE(allocated); + + if (!strcmp(argv[1].str, "arenas")) { + pmm_arena_t* a; + list_for_every_entry (&arena_list, a, pmm_arena_t, node) { dump_arena(a, false); } + } else if (!strcmp(argv[1].str, "alloc")) { + if (argc < 3) + goto notenoughargs; + + struct list_node list; + list_initialize(&list); + + size_t count = pmm_alloc_pages((uint)argv[2].u, 0, &list); + printf("alloc returns %zu\n", count); + + vm_page_t* p; + list_for_every_entry (&list, p, vm_page_t, node) { + printf("\tpage %p, address 0x%lx\n", p, vm_page_to_paddr(p)); + } + + /* add the pages to the local allocated list */ + struct list_node* node; + while ((node = list_remove_head(&list))) { + list_add_tail(&allocated, node); + } + } else if (!strcmp(argv[1].str, "dump_alloced")) { + vm_page_t* page; + + list_for_every_entry (&allocated, page, vm_page_t, node) { dump_page(page); } + } else if (!strcmp(argv[1].str, "alloc_range")) { + if (argc < 4) + goto notenoughargs; + + struct list_node list; + list_initialize(&list); + + size_t count = pmm_alloc_range(argv[2].u, (uint)argv[3].u, &list); + printf("alloc returns %zu\n", count); + + vm_page_t* p; + list_for_every_entry (&list, p, vm_page_t, node) { + printf("\tpage %p, address 0x%lx\n", p, vm_page_to_paddr(p)); + } + + /* add the pages to the local allocated list */ + struct list_node* node; + while ((node = list_remove_head(&list))) { + list_add_tail(&allocated, node); + } + } else if (!strcmp(argv[1].str, "alloc_kpages")) { + if (argc < 3) + goto notenoughargs; + + paddr_t pa; + void* ptr = pmm_alloc_kpages((uint)argv[2].u, NULL, &pa); + printf("pmm_alloc_kpages returns %p pa 0x%lx\n", ptr, pa); + } else if (!strcmp(argv[1].str, "alloc_contig")) { + if (argc < 4) + goto notenoughargs; + + struct list_node list; + list_initialize(&list); + + paddr_t pa; + size_t ret = pmm_alloc_contiguous((uint)argv[2].u, 0, (uint8_t)argv[3].u, &pa, &list); + printf("pmm_alloc_contiguous returns %zu, address 0x%lx\n", ret, pa); + printf("address %% align = 0x%lx\n", pa % argv[3].u); + + /* add the pages to the local allocated list */ + struct list_node* node; + while ((node = list_remove_head(&list))) { + list_add_tail(&allocated, node); + } + } else if (!strcmp(argv[1].str, "free_alloced")) { + size_t err = pmm_free(&allocated); + printf("pmm_free returns %zu\n", err); + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("pmm", "physical memory manager", &cmd_pmm) +#endif +STATIC_COMMAND_END(pmm); diff --git a/kernel/kernel/vm/rules.mk b/kernel/kernel/vm/rules.mk new file mode 100644 index 000000000..c76f29ec4 --- /dev/null +++ b/kernel/kernel/vm/rules.mk @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/utils \ + lib/user_copy + +MODULE_SRCS += \ + $(LOCAL_DIR)/bootalloc.cpp \ + $(LOCAL_DIR)/pmm.cpp \ + $(LOCAL_DIR)/vm.cpp \ + $(LOCAL_DIR)/vm_aspace.cpp \ + $(LOCAL_DIR)/vm_object.cpp \ + $(LOCAL_DIR)/vm_region.cpp \ + $(LOCAL_DIR)/vmm.cpp \ + +include make/module.mk diff --git a/kernel/kernel/vm/vm.cpp b/kernel/kernel/vm/vm.cpp new file mode 100644 index 000000000..eb26cafc9 --- /dev/null +++ b/kernel/kernel/vm/vm.cpp @@ -0,0 +1,308 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "vm_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) + +extern int _start; +extern int _end; + +extern int __code_start; +extern int __code_end; +extern int __rodata_start; +extern int __rodata_end; +extern int __data_start; +extern int __data_end; +extern int __bss_start; +extern int __bss_end; + +// mark the physical pages backing a range of virtual as in use. +// allocate the physical pages and throw them away +static void mark_pages_in_use(vaddr_t va, size_t len) { + LTRACEF("va 0x%lx, len 0x%zx\n", va, len); + + // make sure we are inclusive of all of the pages in the address range + len = PAGE_ALIGN(len + (va & (PAGE_SIZE - 1))); + va = ROUNDDOWN(va, PAGE_SIZE); + + LTRACEF("aligned va 0x%lx, len 0x%zx\n", va, len); + + for (size_t offset = 0; offset < len; offset += PAGE_SIZE) { + uint flags; + paddr_t pa; + + status_t err = arch_mmu_query(&vmm_aspace_to_obj(vmm_get_kernel_aspace())->arch_aspace(), + va + offset, &pa, &flags); + if (err >= 0) { + // LTRACEF("va 0x%x, pa 0x%x, flags 0x%x, err %d\n", va + offset, pa, flags, err); + + // alloate the range, throw the results away + pmm_alloc_range(pa, 1, nullptr); + } else { + panic("Could not find pa for va 0x%lx\n", va); + } + } +} + +void vm_init_preheap(uint level) { + LTRACE_ENTRY; + + // allow the vmm a shot at initializing some of its data structures + VmAspace::KernelAspaceInit(); + + // mark all of the kernel pages in use + LTRACEF("marking all kernel pages as used\n"); + mark_pages_in_use((vaddr_t)&_start, ((uintptr_t)&_end - (uintptr_t)&_start)); + + // mark the physical pages used by the boot time allocator + if (boot_alloc_end != boot_alloc_start) { + LTRACEF("marking boot alloc used from 0x%lx to 0x%lx\n", boot_alloc_start, boot_alloc_end); + + mark_pages_in_use(boot_alloc_start, boot_alloc_end - boot_alloc_start); + } +} + +void vm_init_postheap(uint level) { + LTRACE_ENTRY; + + vmm_aspace_t* aspace = vmm_get_kernel_aspace(); + + // we expect the kernel to be in a temporary mapping, define permanent + // regions for those now + struct temp_region { + const char* name; + vaddr_t base; + size_t size; + uint arch_mmu_flags; + } regions[] = { + { + .name = "kernel_code", + .base = (vaddr_t)&__code_start, + .size = ROUNDUP((size_t)&__code_end - (size_t)&__code_start, PAGE_SIZE), + .arch_mmu_flags = ARCH_MMU_FLAG_PERM_RO, + }, + { + .name = "kernel_rodata", + .base = (vaddr_t)&__rodata_start, + .size = ROUNDUP((size_t)&__rodata_end - (size_t)&__rodata_start, PAGE_SIZE), + .arch_mmu_flags = ARCH_MMU_FLAG_PERM_RO | ARCH_MMU_FLAG_PERM_NO_EXECUTE, + }, + { + .name = "kernel_data", + .base = (vaddr_t)&__data_start, + .size = ROUNDUP((size_t)&__data_end - (size_t)&__data_start, PAGE_SIZE), + .arch_mmu_flags = ARCH_MMU_FLAG_PERM_NO_EXECUTE, + }, + { + .name = "kernel_bss", + .base = (vaddr_t)&__bss_start, + .size = ROUNDUP((size_t)&__bss_end - (size_t)&__bss_start, PAGE_SIZE), + .arch_mmu_flags = ARCH_MMU_FLAG_PERM_NO_EXECUTE, + }, + { + .name = "kernel_bootalloc", + .base = (vaddr_t)boot_alloc_start, + .size = ROUNDUP(boot_alloc_end - boot_alloc_start, PAGE_SIZE), + .arch_mmu_flags = ARCH_MMU_FLAG_PERM_NO_EXECUTE, + }, + }; + + for (uint i = 0; i < countof(regions); ++i) { + temp_region* region = ®ions[i]; + ASSERT(IS_PAGE_ALIGNED(region->base)); + status_t status = vmm_reserve_space(aspace, region->name, region->size, region->base); + ASSERT(status == NO_ERROR); + status = vmm_protect_region(aspace, region->base, region->arch_mmu_flags); + ASSERT(status == NO_ERROR); + } + + // mmu_initial_mappings should reflect where we are now, use it to construct the actual + // mappings. We will carve out the kernel code/data from any mappings and + // unmap any temporary ones. + const struct mmu_initial_mapping* map = mmu_initial_mappings; + for (map = mmu_initial_mappings; map->size > 0; ++map) { + LTRACEF("looking at mapping %p (%s)\n", map, map->name); + // Unmap temporary mappings except where they intersect with the + // kernel code/data regions. + vaddr_t vaddr = map->virt; + LTRACEF("vaddr 0x%lx, virt + size 0x%lx\n", vaddr, map->virt + map->size); + while (vaddr != map->virt + map->size) { + vaddr_t next_kernel_region = map->virt + map->size; + vaddr_t next_kernel_region_end = map->virt + map->size; + + // Find the kernel code/data region with the lowest start address + // that is within this mapping. + for (uint i = 0; i < countof(regions); ++i) { + temp_region* region = ®ions[i]; + + if (region->base >= vaddr && region->base < map->virt + map->size && + region->base < next_kernel_region) { + + next_kernel_region = region->base; + next_kernel_region_end = region->base + region->size; + } + } + + // If vaddr isn't the start of a kernel code/data region, then we should make + // a mapping between it and the next closest one. + if (next_kernel_region != vaddr) { + status_t status = + vmm_reserve_space(aspace, map->name, next_kernel_region - vaddr, vaddr); + ASSERT(status == NO_ERROR); + + if (map->flags & MMU_INITIAL_MAPPING_TEMPORARY) { + // If the region is part of a temporary mapping, immediately unmap it + LTRACEF("Freeing region [%016lx, %016lx)\n", vaddr, next_kernel_region); + status = vmm_free_region(aspace, vaddr); + ASSERT(status == NO_ERROR); + } else { + // Otherwise, mark it no-exec since it's not explicitly code + status = vmm_protect_region( + aspace, + vaddr, + ARCH_MMU_FLAG_PERM_NO_EXECUTE); + ASSERT(status == NO_ERROR); + } + } + vaddr = next_kernel_region_end; + } + } +} + +void* paddr_to_kvaddr(paddr_t pa) { + // slow path to do reverse lookup + struct mmu_initial_mapping* map = mmu_initial_mappings; + while (map->size > 0) { + if (!(map->flags & MMU_INITIAL_MAPPING_TEMPORARY) && pa >= map->phys && + pa <= map->phys + map->size - 1) { + return (void*)(map->virt + (pa - map->phys)); + } + map++; + } + return nullptr; +} + +paddr_t vaddr_to_paddr(void* ptr) { + vmm_aspace_t* _aspace = vaddr_to_aspace(ptr); + if (!_aspace) + return (paddr_t) nullptr; + + VmAspace* aspace = vmm_aspace_to_obj(_aspace); + + paddr_t pa; + status_t rc = arch_mmu_query(&aspace->arch_aspace(), (vaddr_t)ptr, &pa, nullptr); + if (rc) + return (paddr_t) nullptr; + + return pa; +} + +vmm_aspace_t* vaddr_to_aspace(void* ptr) { + if (is_kernel_address((vaddr_t)ptr)) { + return vmm_get_kernel_aspace(); + } else if (is_user_address((vaddr_t)ptr)) { + return get_current_thread()->aspace; + } else { + return nullptr; + } +} + +static int cmd_vm(int argc, const cmd_args* argv) { + if (argc < 2) { + notenoughargs: + printf("not enough arguments\n"); + usage: + printf("usage:\n"); + printf("%s phys2virt
\n", argv[0].str); + printf("%s virt2phys
\n", argv[0].str); + printf("%s map \n", argv[0].str); + printf("%s unmap \n", argv[0].str); + return ERR_GENERIC; + } + + if (!strcmp(argv[1].str, "phys2virt")) { + if (argc < 3) + goto notenoughargs; + + void* ptr = paddr_to_kvaddr((paddr_t)argv[2].u); + printf("paddr_to_kvaddr returns %p\n", ptr); + } else if (!strcmp(argv[1].str, "virt2phys")) { + if (argc < 3) + goto notenoughargs; + + vmm_aspace_t* _aspace = vaddr_to_aspace((void*)argv[2].u); + if (!_aspace) { + printf("ERROR: outside of any address space\n"); + return -1; + } + + VmAspace* aspace = vmm_aspace_to_obj(_aspace); + + paddr_t pa; + uint flags; + status_t err = arch_mmu_query(&aspace->arch_aspace(), argv[2].u, &pa, &flags); + printf("arch_mmu_query returns %d\n", err); + if (err >= 0) { + printf("\tpa 0x%lx, flags 0x%x\n", pa, flags); + } + } else if (!strcmp(argv[1].str, "map")) { + if (argc < 6) + goto notenoughargs; + + vmm_aspace_t* _aspace = vaddr_to_aspace((void*)argv[2].u); + if (!_aspace) { + printf("ERROR: outside of any address space\n"); + return -1; + } + + VmAspace* aspace = vmm_aspace_to_obj(_aspace); + + int err = arch_mmu_map(&aspace->arch_aspace(), argv[3].u, argv[2].u, (uint)argv[4].u, + (uint)argv[5].u); + printf("arch_mmu_map returns %d\n", err); + } else if (!strcmp(argv[1].str, "unmap")) { + if (argc < 4) + goto notenoughargs; + + vmm_aspace_t* _aspace = vaddr_to_aspace((void*)argv[2].u); + if (!_aspace) { + printf("ERROR: outside of any address space\n"); + return -1; + } + + VmAspace* aspace = vmm_aspace_to_obj(_aspace); + + int err = arch_mmu_unmap(&aspace->arch_aspace(), argv[2].u, (uint)argv[3].u); + printf("arch_mmu_unmap returns %d\n", err); + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("vm", "vm commands", &cmd_vm) +#endif +STATIC_COMMAND_END(vm); + +LK_INIT_HOOK(vm_preheap, &vm_init_preheap, LK_INIT_LEVEL_HEAP - 1); +LK_INIT_HOOK(vm, &vm_init_postheap, LK_INIT_LEVEL_VM); diff --git a/kernel/kernel/vm/vm_aspace.cpp b/kernel/kernel/vm/vm_aspace.cpp new file mode 100644 index 000000000..898706709 --- /dev/null +++ b/kernel/kernel/vm/vm_aspace.cpp @@ -0,0 +1,710 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include "vm_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) + +// pointer to a singleton kernel address space +VmAspace* VmAspace::kernel_aspace_ = nullptr; + +// list of all address spaces +static mutex_t aspace_list_lock = MUTEX_INITIAL_VALUE(aspace_list_lock); +static utils::DoublyLinkedList aspaces; + +// called once at boot to initialize the singleton kernel address space +void VmAspace::KernelAspaceInit() { + // the singleton kernel address space + static VmAspace _kernel_aspace(KERNEL_ASPACE_BASE, KERNEL_ASPACE_SIZE, VmAspace::TYPE_KERNEL, + "kernel"); + auto err = _kernel_aspace.Init(); + ASSERT(err >= 0); + +#if LK_DEBUGLEVEL > 0 + _kernel_aspace.Adopt(); +#endif + + aspaces.push_front(&_kernel_aspace); + + // save a pointer to the singleton kernel address space + VmAspace::kernel_aspace_ = &_kernel_aspace; +} + +// simple test routines +static inline bool is_inside(VmAspace& aspace, vaddr_t vaddr) { + return (vaddr >= aspace.base() && vaddr <= aspace.base() + aspace.size() - 1); +} + +static inline bool is_inside(VmAspace& aspace, VmRegion& r) { + // is the starting address within the address space + if (!is_inside(aspace, r.base())) + return false; + + if (r.size() == 0) + return true; + + // see if the size is enough to wrap the integer + if (r.base() + r.size() - 1 < r.base()) + return false; + + // test to see if the end address is within the address space's + if (r.base() + r.size() - 1 > aspace.base() + aspace.size() - 1) + return false; + + return true; +} + +static inline size_t trim_to_aspace(VmAspace& aspace, vaddr_t vaddr, size_t size) { + DEBUG_ASSERT(is_inside(aspace, vaddr)); + + if (size == 0) + return size; + + size_t offset = vaddr - aspace.base(); + + // LTRACEF("vaddr 0x%lx size 0x%zx offset 0x%zx aspace base 0x%lx aspace size 0x%zx\n", + // vaddr, size, offset, aspace.base(), aspace.size()); + + if (offset + size < offset) + size = ULONG_MAX - offset - 1; + + // LTRACEF("size now 0x%zx\n", size); + + if (offset + size >= aspace.size() - 1) + size = aspace.size() - offset; + + // LTRACEF("size now 0x%zx\n", size); + + return size; +} + +VmAspace::VmAspace(vaddr_t base, size_t size, uint32_t flags, const char* name) + : base_(base), size_(size), flags_(flags) { + + DEBUG_ASSERT(size != 0); + DEBUG_ASSERT(base + size - 1 >= base); + + Rename(name); + + LTRACEF("%p '%s'\n", this, name_); +} + +status_t VmAspace::Init() { + DEBUG_ASSERT(magic_ == MAGIC); + + LTRACEF("%p '%s'\n", this, name_); + + // intialize the architectually specific part + bool is_high_kernel = (flags_ & TYPE_MASK) == TYPE_KERNEL; + uint arch_aspace_flags = is_high_kernel ? ARCH_ASPACE_FLAG_KERNEL : 0; + return arch_mmu_init_aspace(&arch_aspace_, base_, size_, arch_aspace_flags); +} + +utils::RefPtr VmAspace::Create(uint32_t flags, const char* name) { + LTRACEF("flags 0x%x, name '%s'\n", flags, name); + + vaddr_t base; + size_t size; + switch (flags & TYPE_MASK) { + case TYPE_USER: + base = USER_ASPACE_BASE; + size = USER_ASPACE_SIZE; + break; + case TYPE_KERNEL: + base = KERNEL_ASPACE_BASE; + size = KERNEL_ASPACE_SIZE; + break; + case TYPE_LOW_KERNEL: + base = 0; + size = USER_ASPACE_BASE + USER_ASPACE_SIZE; + break; + default: + panic("Invalid aspace type"); + } + auto aspace = utils::AdoptRef(new VmAspace(base, size, flags, name)); + if (!aspace) + return nullptr; + + // initialize the arch specific component to our address space + auto err = aspace->Init(); + if (err < 0) { + return nullptr; + } + + // add it to the global list + { + AutoLock a(aspace_list_lock); + aspaces.push_back(aspace.get()); + } + + // return a ref pointer to the aspace + return utils::move(aspace); +} + +void VmAspace::Rename(const char* name) { + DEBUG_ASSERT(magic_ == MAGIC); + strlcpy(name_, name ? name : "unnamed", sizeof(name_)); +} + +VmAspace::~VmAspace() { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s'\n", this, name_); + + // we have to have already been destroyed before freeing + DEBUG_ASSERT(regions_.is_empty()); + + // pop it out of the global aspace list + { + AutoLock a(aspace_list_lock); + aspaces.remove(this); + } + + // destroy the arch portion of the aspace + arch_mmu_destroy_aspace(&arch_aspace_); + + // clear the magic + magic_ = 0; +} + +status_t VmAspace::Destroy() { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s'\n", this, name_); + + // tear down and free all of the regions in our address space + mutex_acquire(&lock_); + VmRegion* r; + while ((r = regions_.pop_front())) { + r->Unmap(); + + mutex_release(&lock_); + + // free any resources the region holds + r->Destroy(); + + // free it if we have the last ref + if (r->Release()) + delete r; + + mutex_acquire(&lock_); + } + + mutex_release(&lock_); + + return NO_ERROR; +} + +// add a region to the appropriate spot in the address space list, +// testing to see if there's a space +status_t VmAspace::AddRegion(utils::RefPtr r) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(r); + + LTRACEF_LEVEL(2, "aspace %p base 0x%lx size 0x%zx r %p base 0x%lx size 0x%zx\n", this, base_, + size_, r.get(), r->base(), r->size()); + + // only try if the region will at least fit in the address space + if (r->size() == 0 || !is_inside(*this, *r)) { + LTRACEF_LEVEL(2, "region was out of range\n"); + return ERR_OUT_OF_RANGE; + } + + vaddr_t r_end = r->base() + r->size() - 1; + + // does it fit in front + auto first = regions_.first(); + if (!first || r_end < first->base()) { + // empty list or not empty and fits before the first element + regions_.push_front(r.get()); + r->AddRef(); + return NO_ERROR; + } + + for (auto last = regions_.first(); last; last = regions_.next(last)) { + // does it go after last? + if (r->base() > last->base() + last->size() - 1) { + // get the next element in the list + auto next = regions_.next(last); + if (!next || (r_end < next->base())) { + // end of the list or next exists and it goes between them + regions_.add_after(last, r.get()); + r->AddRef(); + return NO_ERROR; + } + } + } + + LTRACEF_LEVEL(2, "couldn't find spot\n"); + return ERR_NO_MEMORY; +} + +// +// Try to pick the spot within specified gap +// +// Arch can override this to impose it's own restrictions. + +__WEAK vaddr_t arch_mmu_pick_spot(arch_aspace_t* aspace, vaddr_t base, + uint prev_region_arch_mmu_flags, vaddr_t end, + uint next_region_arch_mmu_flags, vaddr_t align, size_t size, + uint arch_mmu_flags) { + // just align it by default + return ALIGN(base, align); +} + +// +// Returns true if the caller has to stop search + +static inline bool check_gap(VmAspace* aspace, VmRegion* prev, VmRegion* next, vaddr_t* pva, + vaddr_t align, size_t size, uint arch_mmu_flags) { + vaddr_t gap_beg; // first byte of a gap + vaddr_t gap_end; // last byte of a gap + + DEBUG_ASSERT(pva); + + if (prev) + gap_beg = prev->base() + prev->size(); + else + gap_beg = aspace->base(); + + if (next) { + if (gap_beg == next->base()) + goto next_gap; // no gap between regions + gap_end = next->base() - 1; + } else { + if (gap_beg == (aspace->base() + aspace->size())) + goto not_found; // no gap at the end of address space. Stop search + gap_end = aspace->base() + aspace->size() - 1; + } + + *pva = arch_mmu_pick_spot(&aspace->arch_aspace(), gap_beg, + prev ? prev->arch_mmu_flags() : ARCH_MMU_FLAG_INVALID, gap_end, + next ? next->arch_mmu_flags() : ARCH_MMU_FLAG_INVALID, align, size, + arch_mmu_flags); + if (*pva < gap_beg) + goto not_found; // address wrapped around + + if (*pva < gap_end && ((gap_end - *pva + 1) >= size)) { + // we have enough room + return true; // found spot, stop search + } + +next_gap: + return false; // continue search + +not_found: + *pva = -1; + return true; // not_found: stop search +} + +// search for a spot to allocate for a region of a given size, returning the pointer to the region +// before in the list +vaddr_t VmAspace::AllocSpot(size_t size, uint8_t align_pow2, uint arch_mmu_flags, + VmRegion** before) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(size > 0 && IS_PAGE_ALIGNED(size)); + + LTRACEF_LEVEL(2, "aspace %p size 0x%zx align %hhu\n", this, size, align_pow2); + + if (align_pow2 < PAGE_SIZE_SHIFT) + align_pow2 = PAGE_SIZE_SHIFT; + vaddr_t align = 1UL << align_pow2; + + vaddr_t spot; + + // try to pick spot at the beginning of address space + VmRegion* r = nullptr; + if (check_gap(this, nullptr, regions_.first(), &spot, align, size, arch_mmu_flags)) + goto done; + + // search the middle of the list + for (r = regions_.first(); r; r = regions_.next(r)) { + if (check_gap(this, r, regions_.next(r), &spot, align, size, arch_mmu_flags)) + goto done; + } + + // couldn't find anything + return -1; + +done: + if (before) + *before = r; + return spot; +} + +// allocate a region and insert it into the list +utils::RefPtr VmAspace::AllocRegion(const char* name, size_t size, vaddr_t vaddr, + uint8_t align_pow2, uint vmm_flags, + uint arch_mmu_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(is_mutex_held(&lock_)); + LTRACEF_LEVEL(2, "aspace %p name '%s' size 0x%zx vaddr 0x%lx\n", this, name, size, vaddr); + + // make a region struct for it and stick it in the list + utils::RefPtr r = VmRegion::Create(*this, vaddr, size, arch_mmu_flags, name); + if (!r) + return nullptr; + + // if they ask us for a specific spot, put it there + if (vmm_flags & VMM_FLAG_VALLOC_SPECIFIC) { + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + + // stick it in the list, checking to see if it fits + if (AddRegion(r) < 0) { + // didn't fit + return nullptr; + } + } else { + // allocate a virtual slot for it + VmRegion* before; + + vaddr = AllocSpot(size, align_pow2, arch_mmu_flags, &before); + LTRACEF_LEVEL(2, "alloc_spot returns 0x%lx, before %p\n", vaddr, before); + + if (vaddr == (vaddr_t)-1) { + LTRACEF_LEVEL(2, "failed to find spot\n"); + return nullptr; + } + + r->set_base(vaddr); + + // add it to the region list + r->AddRef(); + if (before) + regions_.add_after(before, r.get()); + else + regions_.push_front(r.get()); + } + + return utils::move(r); +} + +// internal find region search routine +VmRegion* VmAspace::FindRegionLocked(vaddr_t vaddr) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(is_mutex_held(&lock_)); + + // search the region list + for (auto r = regions_.first(); r; r = regions_.next(r)) { + if ((vaddr >= r->base()) && (vaddr <= r->base() + r->size() - 1)) + return r; + } + + return nullptr; +} + +// return a ref pointer to a region +utils::RefPtr VmAspace::FindRegion(vaddr_t vaddr) { + AutoLock a(lock_); + + auto r = FindRegionLocked(vaddr); + + return utils::RefPtr(r); +} + +status_t VmAspace::MapObject(utils::RefPtr vmo, const char* name, uint64_t offset, + size_t size, void** ptr, uint8_t align_pow2, uint vmm_flags, + uint arch_mmu_flags) { + + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF( + "aspace %p name '%s' vmo %p, offset 0x%llx size 0x%zx ptr %p align %hhu vmm_flags 0x%x " + "arch_mmu_flags 0x%x\n", + this, name, vmo.get(), offset, size, ptr ? *ptr : 0, align_pow2, vmm_flags, arch_mmu_flags); + + size = ROUNDUP(size, PAGE_SIZE); + if (size == 0) + return ERR_INVALID_ARGS; + if (!vmo) + return ERR_INVALID_ARGS; + if (!IS_PAGE_ALIGNED(offset)) + return ERR_INVALID_ARGS; + + vaddr_t vaddr = 0; + // if they're asking for a specific spot, copy the address + if (vmm_flags & VMM_FLAG_VALLOC_SPECIFIC) { + // can't ask for a specific spot and then not provide one + if (!ptr) { + return ERR_INVALID_ARGS; + } + vaddr = (vaddr_t)*ptr; + + // check that it's page aligned + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + } + + // hold the vmm lock for the rest of the function + AutoLock a(lock_); + + // allocate a region and put it in the aspace list + auto r = AllocRegion(name, size, vaddr, align_pow2, vmm_flags, arch_mmu_flags); + if (!r) { + return ERR_NO_MEMORY; + } + + // associate the vm object with it + r->SetObject(utils::move(vmo), offset); + + // if we're committing it, map the region now + if (vmm_flags & VMM_FLAG_COMMIT) { + auto err = r->MapRange(0, size, true); + if (err < 0) + return err; + } + + // return the vaddr if requested + if (ptr) + *ptr = (void*)r->base(); + + return NO_ERROR; +} + +status_t VmAspace::ReserveSpace(const char* name, size_t size, vaddr_t vaddr) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("aspace %p name '%s' size 0x%zx vaddr 0x%lx\n", this, name, size, vaddr); + + DEBUG_ASSERT(IS_PAGE_ALIGNED(vaddr)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(size)); + + size = ROUNDUP_PAGE_SIZE(size); + if (size == 0) + return NO_ERROR; + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + if (!is_inside(*this, vaddr)) + return ERR_OUT_OF_RANGE; + + // trim the size + size = trim_to_aspace(*this, vaddr, size); + + AutoLock a(lock_); + + // lookup how it's already mapped + uint arch_mmu_flags = 0; + auto err = arch_mmu_query(&arch_aspace_, vaddr, nullptr, &arch_mmu_flags); + if (err) { + // if it wasn't already mapped, use some sort of strict default + arch_mmu_flags = + ARCH_MMU_FLAG_CACHED | ARCH_MMU_FLAG_PERM_RO | ARCH_MMU_FLAG_PERM_NO_EXECUTE; + } + + // build a new region structure without any backing vm object + auto r = AllocRegion(name, size, vaddr, 0, VMM_FLAG_VALLOC_SPECIFIC, arch_mmu_flags); + + return r ? NO_ERROR : ERR_NO_MEMORY; +} + +status_t VmAspace::AllocPhysical(const char* name, size_t size, void** ptr, uint8_t align_log2, + paddr_t paddr, uint vmm_flags, uint arch_mmu_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF( + "aspace %p name '%s' size 0x%zx ptr %p paddr 0x%lx vmm_flags 0x%x arch_mmu_flags 0x%x\n", + this, name, size, ptr ? *ptr : 0, paddr, vmm_flags, arch_mmu_flags); + + DEBUG_ASSERT(IS_PAGE_ALIGNED(paddr)); + + if (size == 0) + return NO_ERROR; + if (!IS_PAGE_ALIGNED(paddr)) + return ERR_INVALID_ARGS; + + size = ROUNDUP_PAGE_SIZE(size); + + // test for invalid flags + if (vmm_flags & VMM_FLAG_COMMIT) + return ERR_INVALID_ARGS; + + vaddr_t vaddr = 0; + + // if they're asking for a specific spot, copy the address + if (vmm_flags & VMM_FLAG_VALLOC_SPECIFIC) { + // can't ask for a specific spot and then not provide one + if (!ptr) { + return ERR_INVALID_ARGS; + } + vaddr = reinterpret_cast(*ptr); + + // check that it's page aligned + if (!IS_PAGE_ALIGNED(vaddr)) + return ERR_INVALID_ARGS; + } + + AutoLock a(lock_); + + // allocate a region and put it in the aspace list + auto r = AllocRegion(name, size, vaddr, align_log2, vmm_flags, arch_mmu_flags); + if (!r) { + return ERR_NO_MEMORY; + } + + // map memory physically + auto err = r->MapPhysicalRange(0, size, paddr, false); + if (err < 0) { + // TODO: remove the region from the aspace + return err; + } + + // return the vaddr if requested + if (ptr) + *ptr = reinterpret_cast(r->base()); + + return NO_ERROR; +} + +status_t VmAspace::AllocContiguous(const char* name, size_t size, void** ptr, uint8_t align_pow2, + uint vmm_flags, uint arch_mmu_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("aspace %p name '%s' size 0x%zx ptr %p align %hhu vmm_flags 0x%x arch_mmu_flags 0x%x\n", + this, name, size, ptr ? *ptr : 0, align_pow2, vmm_flags, arch_mmu_flags); + + size = ROUNDUP(size, PAGE_SIZE); + if (size == 0) + return ERR_INVALID_ARGS; + + // test for invalid flags + if (!(vmm_flags & VMM_FLAG_COMMIT)) + return ERR_INVALID_ARGS; + + // create a vm object to back it + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, size); + if (!vmo) + return ERR_NO_MEMORY; + + // always immediately commit memory to the object + int64_t committed = vmo->CommitRangeContiguous(0, size, align_pow2); + if (committed < 0 || (size_t)committed < size) { + LTRACEF("failed to allocate enough pages (asked for %zu, got %zu)\n", size / PAGE_SIZE, + (size_t)committed / PAGE_SIZE); + return ERR_NO_MEMORY; + } + + return MapObject(utils::move(vmo), name, 0, size, ptr, align_pow2, vmm_flags, arch_mmu_flags); +} + +status_t VmAspace::Alloc(const char* name, size_t size, void** ptr, uint8_t align_pow2, + uint vmm_flags, uint arch_mmu_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("aspace %p name '%s' size 0x%zx ptr %p align %hhu vmm_flags 0x%x arch_mmu_flags 0x%x\n", + this, name, size, ptr ? *ptr : 0, align_pow2, vmm_flags, arch_mmu_flags); + + size = ROUNDUP(size, PAGE_SIZE); + if (size == 0) + return ERR_INVALID_ARGS; + + // allocate a vm object to back it + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, size); + if (!vmo) + return ERR_NO_MEMORY; + + // commit memory up front if requested + if (vmm_flags & VMM_FLAG_COMMIT) { + // commit memory to the object + int64_t committed = vmo->CommitRange(0, size); + if (committed < 0 || (size_t)committed < size) { + LTRACEF("failed to allocate enough pages (asked for %zu, got %zu)\n", size / PAGE_SIZE, + (size_t)committed / PAGE_SIZE); + return ERR_NO_MEMORY; + } + } + + // map it, creating a new region + return MapObject(utils::move(vmo), name, 0, size, ptr, align_pow2, vmm_flags, arch_mmu_flags); +} + +status_t VmAspace::FreeRegion(vaddr_t vaddr) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("vaddr 0x%lx\n", vaddr); + + VmRegion* r; + { + AutoLock a(lock_); + + r = FindRegionLocked(vaddr); + if (!r) { + return ERR_NOT_FOUND; + } + + // remove it from the address space list + regions_.remove(r); + + // unmap it + r->Unmap(); + } + + // destroy the region + r->Destroy(); + + // drop a ref and potentially free it + if (r->Release()) + delete r; + + return NO_ERROR; +} + +void VmAspace::AttachToThread(thread_t* t) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(t); + + // point the lk thread at our object via the dummy C vmm_aspace_t struct + THREAD_LOCK(state); + + // not prepared to handle setting a new address space or one on a running thread + DEBUG_ASSERT(!t->aspace); + DEBUG_ASSERT(t->state != THREAD_RUNNING); + + t->aspace = reinterpret_cast(this); + THREAD_UNLOCK(state); +} + +status_t VmAspace::PageFault(vaddr_t va, uint flags) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("va 0x%lx, flags 0x%x\n", va, flags); + + // for now, hold the aspace lock across the page fault operation, + // which stops any other operations on the address space from moving + // the region out from underneath it + AutoLock a(lock_); + + auto r = FindRegionLocked(va); + if (unlikely(!r)) + return ERR_NOT_FOUND; + + return r->PageFault(va, flags); +} + +void VmAspace::Dump() { + DEBUG_ASSERT(magic_ == MAGIC); + printf("aspace %p: ref %u name '%s' range 0x%lx - 0x%lx size 0x%zx flags 0x%x\n", this, + ref_count_debug(), name_, base_, base_ + size_ - 1, size_, flags_); + + printf("regions:\n"); + AutoLock a(lock_); + for (auto r = regions_.first(); r; r = regions_.next(r)) { + r->Dump(); + } +} + +void DumpAllAspaces() { + AutoLock a(aspace_list_lock); + + utils::for_each(&aspaces, [](VmAspace* a) { a->Dump(); }); +} diff --git a/kernel/kernel/vm/vm_object.cpp b/kernel/kernel/vm/vm_object.cpp new file mode 100644 index 000000000..ecd686c3b --- /dev/null +++ b/kernel/kernel/vm/vm_object.cpp @@ -0,0 +1,459 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "kernel/vm/vm_object.h" + +#include "vm_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) + +static void ZeroPage(paddr_t pa) { + void* ptr = paddr_to_kvaddr(pa); + DEBUG_ASSERT(ptr); + + memset(ptr, 0, PAGE_SIZE); +} + +static void ZeroPage(vm_page_t* p) { + paddr_t pa = vm_page_to_paddr(p); + ZeroPage(pa); +} + +static size_t OffsetToIndex(uint64_t offset) { + uint64_t index64 = offset / PAGE_SIZE; + + DEBUG_ASSERT(index64 <= SIZE_MAX); + + return static_cast(index64); +} + +VmObject::VmObject(uint32_t pmm_alloc_flags) + : pmm_alloc_flags_(pmm_alloc_flags) { + LTRACEF("%p\n", this); +} + +VmObject::~VmObject() { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p\n", this); + + list_node list; + list_initialize(&list); + + // free all of the pages attached to us + size_t count = 0; + for (size_t i = 0; i < page_array_.size(); i++) { + auto p = page_array_[i]; + if (p) { + LTRACEF("freeing page %p (0x%lx)\n", p, vm_page_to_paddr(p)); + + // remove it from the object list of pages + DEBUG_ASSERT(list_in_list(&p->node)); + list_delete(&p->node); + + // add to the temporary free list + list_add_tail(&list, &p->node); + count++; + } + } + + DEBUG_ASSERT(list_length(&page_list_) == 0); + + __UNUSED auto freed = pmm_free(&list); + DEBUG_ASSERT(freed == count); + + // clear our magic value + magic_ = 0; +} + +utils::RefPtr VmObject::Create(uint32_t pmm_alloc_flags, uint64_t size) { + // there's a max size to keep indexes within range + if (size >= MAX_SIZE) + return nullptr; + + auto vmo = utils::AdoptRef(new VmObject(pmm_alloc_flags)); + if (!vmo) + return nullptr; + + auto err = vmo->Resize(size); + DEBUG_ASSERT(err == NO_ERROR); + if (err != NO_ERROR) + return nullptr; + + return vmo; +} + +void VmObject::Dump() { + DEBUG_ASSERT(magic_ == MAGIC); + + size_t count = 0; + { + AutoLock a(lock_); + for (size_t i = 0; i < page_array_.size(); i++) { + if (page_array_[i]) + count++; + } + } + printf("\t\tobject %p: ref %u size 0x%llx, %zu allocated pages\n", this, ref_count_debug(), + size_, count); +} + +status_t VmObject::Resize(uint64_t s) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("vmo %p, size %llu\n", this, s); + + // there's a max size to keep indexes within range + if (s >= MAX_SIZE) + return ERR_TOO_BIG; + + AutoLock a(lock_); + + if (size_ != 0) { + return ERR_NOT_IMPLEMENTED; // TODO: support resizing an existing object + } + + // compute the number of pages we cover + size_t page_count = OffsetToIndex(ROUNDUP_PAGE_SIZE(s)); + + // save bytewise size + size_ = s; + + // allocate a new array + DEBUG_ASSERT(!page_array_); // no resizing + vm_page_t** pa = new vm_page_t* [page_count] {}; + if (!pa) + return ERR_NO_MEMORY; + + page_array_.reset(pa, page_count); + + return NO_ERROR; +} + +void VmObject::AddPageToArray(size_t index, vm_page_t* p) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(is_mutex_held(&lock_)); + + DEBUG_ASSERT(page_array_); + DEBUG_ASSERT(!page_array_[index]); + DEBUG_ASSERT(index < page_array_.size()); + page_array_[index] = p; + + DEBUG_ASSERT(!list_in_list(&p->node)); + list_add_tail(&page_list_, &p->node); +} + +status_t VmObject::AddPage(vm_page_t* p, uint64_t offset) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("vmo %p, offset 0x%llx, page %p (0x%lx)\n", this, offset, p, vm_page_to_paddr(p)); + + DEBUG_ASSERT(p); + + AutoLock a(lock_); + + if (offset >= size_) + return ERR_OUT_OF_RANGE; + + size_t index = OffsetToIndex(offset); + + AddPageToArray(index, p); + + return NO_ERROR; +} + +vm_page_t* VmObject::GetPage(uint64_t offset) { + DEBUG_ASSERT(magic_ == MAGIC); + AutoLock a(lock_); + + if (offset >= size_) + return nullptr; + + size_t index = OffsetToIndex(offset); + + return page_array_[index]; +} + +vm_page_t* VmObject::FaultPageLocked(uint64_t offset, uint pf_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(is_mutex_held(&lock_)); + + LTRACEF("vmo %p, offset 0x%llx, pf_flags 0x%x\n", this, offset, pf_flags); + + if (offset >= size_) + return nullptr; + + size_t index = OffsetToIndex(offset); + + vm_page_t* p = page_array_[index]; + if (p) + return p; + + // allocate a page + paddr_t pa; + p = pmm_alloc_page(pmm_alloc_flags_, &pa); + if (!p) + return nullptr; + + // TODO: remove once pmm returns zeroed pages + ZeroPage(pa); + + AddPageToArray(index, p); + + LTRACEF("faulted in page %p, pa 0x%lx\n", p, pa); + + return p; +} + +vm_page_t* VmObject::FaultPage(uint64_t offset, uint pf_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + AutoLock a(lock_); + + return FaultPageLocked(offset, pf_flags); +} + +int64_t VmObject::CommitRange(uint64_t offset, uint64_t len) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("offset 0x%llx, len 0x%llx\n", offset, len); + + AutoLock a(lock_); + + // trim the size + if (!TrimRange(offset, len, size_)) + return ERR_OUT_OF_RANGE; + + // was in range, just zero length + if (len == 0) + return 0; + + // compute a page aligned end to do our searches in to make sure we cover all the pages + uint64_t end = ROUNDUP_PAGE_SIZE(offset + len); + DEBUG_ASSERT(end > offset); + + // make a pass through the list, counting the number of pages we need to allocate + size_t count = 0; + for (uint64_t o = offset; o < end; o += PAGE_SIZE) { + size_t index = OffsetToIndex(o); + + if (!page_array_[index]) + count++; + } + if (count == 0) + return 0; + + // allocate count number of pages + list_node page_list; + list_initialize(&page_list); + + size_t allocated = pmm_alloc_pages(count, pmm_alloc_flags_, &page_list); + if (allocated < count) { + LTRACEF("failed to allocate enough pages (asked for %zu, got %zu)\n", count, allocated); + pmm_free(&page_list); + return ERR_NO_MEMORY; + } + + // add them to the appropriate range of the object + for (uint64_t o = offset; o < end; o += PAGE_SIZE) { + size_t index = OffsetToIndex(o); + + vm_page_t* p = list_remove_head_type(&page_list, vm_page_t, node); + DEBUG_ASSERT(p); + + // TODO: remove once pmm returns zeroed pages + ZeroPage(p); + + AddPageToArray(index, p); + } + + DEBUG_ASSERT(list_is_empty(&page_list)); + + return len; +} + +int64_t VmObject::CommitRangeContiguous(uint64_t offset, uint64_t len, uint8_t alignment_log2) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("offset 0x%llx, len 0x%llx, alignment %hhu\n", offset, len, alignment_log2); + + AutoLock a(lock_); + + // trim the size + if (!TrimRange(offset, len, size_)) + return ERR_OUT_OF_RANGE; + + // was in range, just zero length + if (len == 0) + return 0; + + // compute a page aligned end to do our searches in to make sure we cover all the pages + uint64_t end = ROUNDUP_PAGE_SIZE(offset + len); + DEBUG_ASSERT(end > offset); + + // make a pass through the list, making sure we have an empty run on the object + size_t count = 0; + for (uint64_t o = offset; o < end; o += PAGE_SIZE) { + size_t index = OffsetToIndex(o); + + if (page_array_[index]) + return ERR_NO_MEMORY; + + count++; + } + + DEBUG_ASSERT(count == len / PAGE_SIZE); + + // allocate count number of pages + list_node page_list; + list_initialize(&page_list); + + size_t allocated = + pmm_alloc_contiguous(count, pmm_alloc_flags_, alignment_log2, nullptr, &page_list); + if (allocated < count) { + LTRACEF("failed to allocate enough pages (asked for %zu, got %zu)\n", count, allocated); + pmm_free(&page_list); + return ERR_NO_MEMORY; + } + + DEBUG_ASSERT(list_length(&page_list) == allocated); + + // add them to the appropriate range of the object + for (uint64_t o = offset; o < end; o += PAGE_SIZE) { + size_t index = OffsetToIndex(o); + + vm_page_t* p = list_remove_head_type(&page_list, vm_page_t, node); + DEBUG_ASSERT(p); + + // TODO: remove once pmm returns zeroed pages + ZeroPage(p); + + AddPageToArray(index, p); + } + + return count * PAGE_SIZE; +} + +// perform some sort of copy in/out on a range of the object using a passed in lambda +// for the copy routine +template +status_t VmObject::ReadWriteInternal(uint64_t offset, size_t len, size_t* bytes_copied, + bool write, T copyfunc) { + DEBUG_ASSERT(magic_ == MAGIC); + if (bytes_copied) + *bytes_copied = 0; + + AutoLock a(lock_); + + // trim the size + if (!TrimRange(offset, len, size_)) + return ERR_OUT_OF_RANGE; + + // was in range, just zero length + if (len == 0) + return 0; + + // walk the list of pages and do the write + size_t dest_offset = 0; + while (len > 0) { + size_t page_offset = offset % PAGE_SIZE; + size_t tocopy = MIN(PAGE_SIZE - page_offset, len); + + // fault in the page + vm_page_t* p = FaultPageLocked(offset, write ? VMM_PF_FLAG_WRITE : 0); + if (!p) + return ERR_NO_MEMORY; + + // compute the kernel mapping of this page + paddr_t pa = vm_page_to_paddr(p); + uint8_t* page_ptr = reinterpret_cast(paddr_to_kvaddr(pa)); + + // call the copy routine + auto err = copyfunc(page_ptr + page_offset, dest_offset, tocopy); + if (err < 0) + return err; + + offset += tocopy; + if (bytes_copied) + *bytes_copied += tocopy; + dest_offset += tocopy; + len -= tocopy; + } + + return NO_ERROR; +} + +status_t VmObject::Read(void* _ptr, uint64_t offset, size_t len, size_t* bytes_read) { + DEBUG_ASSERT(magic_ == MAGIC); + // test to make sure this is a kernel pointer + if (!is_kernel_address(reinterpret_cast(_ptr))) { + DEBUG_ASSERT_MSG(0, "non kernel pointer passed\n"); + return ERR_INVALID_ARGS; + } + + // read routine that just uses a memcpy + uint8_t* ptr = reinterpret_cast(_ptr); + auto read_routine = [ptr](const void* src, size_t offset, size_t len) -> status_t { + memcpy(ptr + offset, src, len); + return NO_ERROR; + }; + + return ReadWriteInternal(offset, len, bytes_read, false, read_routine); +} + +status_t VmObject::Write(const void* _ptr, uint64_t offset, size_t len, size_t* bytes_written) { + DEBUG_ASSERT(magic_ == MAGIC); + // test to make sure this is a kernel pointer + if (!is_kernel_address(reinterpret_cast(_ptr))) { + DEBUG_ASSERT_MSG(0, "non kernel pointer passed\n"); + return ERR_INVALID_ARGS; + } + + // write routine that just uses a memcpy + const uint8_t* ptr = reinterpret_cast(_ptr); + auto write_routine = [ptr](void* dst, size_t offset, size_t len) -> status_t { + memcpy(dst, ptr + offset, len); + return NO_ERROR; + }; + + return ReadWriteInternal(offset, len, bytes_written, true, write_routine); +} + +status_t VmObject::ReadUser(void* _ptr, uint64_t offset, size_t len, size_t* bytes_read) { + DEBUG_ASSERT(magic_ == MAGIC); + // test to make sure this is a iuser pointer + if (!is_user_address(reinterpret_cast(_ptr))) { + DEBUG_ASSERT_MSG(0, "non user pointer passed\n"); + return ERR_INVALID_ARGS; + } + + // read routine that uses copy_to_user + uint8_t* ptr = reinterpret_cast(_ptr); + auto read_routine = [ptr](const void* src, size_t offset, size_t len) -> status_t { + return copy_to_user(ptr + offset, src, len); + }; + + return ReadWriteInternal(offset, len, bytes_read, false, read_routine); +} + +status_t VmObject::WriteUser(const void* _ptr, uint64_t offset, size_t len, size_t* bytes_written) { + DEBUG_ASSERT(magic_ == MAGIC); + // test to make sure this is a iuser pointer + if (!is_user_address(reinterpret_cast(_ptr))) { + DEBUG_ASSERT_MSG(0, "non user pointer passed\n"); + return ERR_INVALID_ARGS; + } + + // write routine that uses copy_from_user + const uint8_t* ptr = reinterpret_cast(_ptr); + auto write_routine = [ptr](void* dst, size_t offset, size_t len) -> status_t { + return copy_from_user(dst, ptr + offset, len); + }; + + return ReadWriteInternal(offset, len, bytes_written, true, write_routine); +} diff --git a/kernel/kernel/vm/vm_priv.h b/kernel/kernel/vm/vm_priv.h new file mode 100644 index 000000000..ecda438e4 --- /dev/null +++ b/kernel/kernel/vm/vm_priv.h @@ -0,0 +1,53 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include + +#define VM_GLOBAL_TRACE 0 + +/* simple boot time allocator */ +extern "C" void* boot_alloc_mem(size_t len) __MALLOC; +extern uintptr_t boot_alloc_start; +extern uintptr_t boot_alloc_end; + +void vmm_init_preheap(void); +void vmm_init(void); + +// global vmm lock (for now) +extern mutex_t vmm_lock; + +// utility function to trim offset + len to trim_to_len, modifying offset and len +// returns false if out of range +// may return length 0 if it precisely trims +// NOTE: only use unsigned lengths +template +static inline bool TrimRange(O& offset, L& len, O trim_to_len) { + static_assert(utils::numeric_limits::is_signed == false, "TrimRange requires unsigned type O"); + static_assert(utils::numeric_limits::is_signed == false, "TrimRange requires unsigned type L"); + + // trim offset/len to the range + if (offset + len < offset) return false; // offset + len wrapped + + // we started off the end of the range + if (offset > trim_to_len) + return false; + + // trim to the range + if (offset + len > trim_to_len) + len = static_cast(trim_to_len - offset); + + return true; +} + + diff --git a/kernel/kernel/vm/vm_region.cpp b/kernel/kernel/vm/vm_region.cpp new file mode 100644 index 000000000..839958956 --- /dev/null +++ b/kernel/kernel/vm/vm_region.cpp @@ -0,0 +1,259 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include "vm_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) + +VmRegion::VmRegion(VmAspace& aspace, vaddr_t base, size_t size, uint arch_mmu_flags, + const char* name) + : base_(base), size_(size), arch_mmu_flags_(arch_mmu_flags), aspace_(&aspace) { + strlcpy(name_, name, sizeof(name_)); + LTRACEF("%p '%s'\n", this, name_); +} + +utils::RefPtr VmRegion::Create(VmAspace& aspace, vaddr_t base, size_t size, + uint arch_mmu_flags, const char* name) { + return utils::AdoptRef(new VmRegion(aspace, base, size, arch_mmu_flags, name)); +} + +VmRegion::~VmRegion() { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s'\n", this, name_); + + Destroy(); + + // clear the magic + magic_ = 0; +} + +status_t VmRegion::Destroy() { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s'\n", this, name_); + + // detach from any object we have mapped + object_.reset(); + + return NO_ERROR; +} + +void VmRegion::Dump() const { + DEBUG_ASSERT(magic_ == MAGIC); + printf( + "\tregion %p: ref %d name '%s' range 0x%lx - 0x%lx size 0x%zx mmu_flags 0x%x " + "vmo %p offset 0x%llx\n", + this, ref_count_debug(), name_, base_, base_ + size_ - 1, size_, arch_mmu_flags_, + object_.get(), object_offset_); + if (object_.get()) { + object_->Dump(); + } +} + +status_t VmRegion::Protect(uint arch_mmu_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + arch_mmu_flags_ = arch_mmu_flags; + + auto err = arch_mmu_protect(&aspace_->arch_aspace(), base_, size_ / PAGE_SIZE, arch_mmu_flags); + LTRACEF("arch_mmu_protect returns %d\n", err); + // TODO: deal with error mapping here + + return NO_ERROR; +} + +int VmRegion::Unmap() { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s'\n", this, name_); + + // unmap the section of address space we cover + return arch_mmu_unmap(&aspace_->arch_aspace(), base_, size_ / PAGE_SIZE); +} + +status_t VmRegion::SetObject(utils::RefPtr o, uint64_t offset) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s', o %p, offset 0x%llx\n", this, name_, &o, offset); + + DEBUG_ASSERT(IS_PAGE_ALIGNED(offset)); + + DEBUG_ASSERT(!object_); // cant handle setting a different object than before right now + + object_ = o; + object_offset_ = offset; + + return NO_ERROR; +} + +status_t VmRegion::MapPhysicalRange(size_t offset, size_t len, paddr_t paddr, bool allow_remap) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("%p '%s', offset 0x%zu, size 0x%zx, paddr 0x%lx, remap %d\n", this, name_, offset, len, + paddr, allow_remap); + + DEBUG_ASSERT(IS_PAGE_ALIGNED(offset)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); + + DEBUG_ASSERT(!object_); // assert on this for now + + if (!TrimRange(offset, len, size_)) + return ERR_INVALID_ARGS; + + if (object_) { + // we have a backing object, which means we should not be physically mapping this + return ERR_NO_MEMORY; + } + + if (allow_remap) { + auto ret = arch_mmu_unmap(&aspace_->arch_aspace(), base_ + offset, len / PAGE_SIZE); + if (ret < 0) { + TRACEF("error unmapping old region\n"); + return ret; + } + } + + auto ret = arch_mmu_map(&aspace_->arch_aspace(), base_ + offset, paddr, len / PAGE_SIZE, + arch_mmu_flags_); + if (ret < 0) { + TRACEF("error %d mapping pages at va 0x%lx pa 0x%lx\n", ret, base_, paddr); + } + return (ret < 0) ? ret : 0; +} + +status_t VmRegion::MapRange(size_t offset, size_t len, bool commit) { + DEBUG_ASSERT(magic_ == MAGIC); + LTRACEF("region %p '%s', offset 0x%zu, size 0x%zx\n", this, name_, offset, len); + + DEBUG_ASSERT(IS_PAGE_ALIGNED(offset)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); + + DEBUG_ASSERT(object_); // assert on this for now + + if (!object_) { + // we have no backing object, you should not call MapRange on this + return ERR_NO_MEMORY; + } + + // iterate through the range, grabbing a page from the underlying object and mapping it in + size_t o; + for (o = offset; o < offset + len; o += PAGE_SIZE) { + uint64_t vmo_offset = object_offset_ + o; + vm_page_t* p = object_->GetPage(vmo_offset); + if (!p) { + if (!commit) { + // no page to map, skip ahead + continue; + } + + int64_t committed = object_->CommitRange(vmo_offset, PAGE_SIZE); + if (committed < 0 || committed != PAGE_SIZE) { + LTRACEF("error committing memory for region\n"); + return (status_t)committed; + } + + p = object_->GetPage(vmo_offset); + } + + DEBUG_ASSERT(p); + + vaddr_t va = base_ + o; + paddr_t pa = vm_page_to_paddr(p); + LTRACEF_LEVEL(2, "mapping pa 0x%lx to va 0x%lx\n", pa, va); + + auto ret = arch_mmu_map(&aspace_->arch_aspace(), va, pa, 1, arch_mmu_flags_); + if (ret < 0) { + TRACEF("error %d mapping page at va 0x%lx pa 0x%lx\n", ret, va, pa); + } + } + + return NO_ERROR; +} + +status_t VmRegion::PageFault(vaddr_t va, uint pf_flags) { + DEBUG_ASSERT(magic_ == MAGIC); + DEBUG_ASSERT(va >= base_ && va <= base_ + size_ - 1); + + va = ROUNDDOWN(va, PAGE_SIZE); + uint64_t vmo_offset = va - base_ + object_offset_; + + LTRACEF("%p '%s', vmo_offset 0x%llx, pf_flags 0x%x\n", this, name_, vmo_offset, pf_flags); + + // make sure we have permission to continue + if ((pf_flags & VMM_PF_FLAG_USER) && (arch_mmu_flags_ & ARCH_MMU_FLAG_PERM_USER) == 0) { + // user page fault on non user mapped region + LTRACEF("permission failure: user fault on non user region\n"); + return ERR_ACCESS_DENIED; + } + if ((pf_flags & VMM_PF_FLAG_WRITE) && (arch_mmu_flags_ & ARCH_MMU_FLAG_PERM_RO)) { + // write to a read only region + LTRACEF("permission failure: write fault on read only region\n"); + return ERR_ACCESS_DENIED; + } + if ((pf_flags & VMM_PF_FLAG_INSTRUCTION) && (arch_mmu_flags_ & ARCH_MMU_FLAG_PERM_NO_EXECUTE)) { + // instruction fetch from a no execute region + LTRACEF("permission failure: execute fault on no execute region\n"); + return ERR_ACCESS_DENIED; + } + + if (!object_) { + // we have no backing object, error + TRACEF("ERROR: faulted on region with no backing object\n"); + return ERR_NO_MEMORY; + } + + // fault in or grab an existing page + vm_page_t* new_p = object_->FaultPage(vmo_offset, pf_flags); + if (!new_p) { + TRACEF("ERROR: failed to fault in or grab existing page\n"); + return ERR_NO_MEMORY; + } + paddr_t new_pa = vm_page_to_paddr(new_p); + + // see if something is mapped here now + // this may happen if we are one of multiple threads racing on a single address + uint page_flags; + paddr_t pa; + status_t err = arch_mmu_query(&aspace_->arch_aspace(), va, &pa, &page_flags); + if (err >= 0) { + LTRACEF("queried va, page at pa 0x%lx, flags 0x%x is already there\n", pa, page_flags); + if (pa == new_pa) { + // page was already mapped, are the permissions compatible? + if (page_flags == arch_mmu_flags_) + return NO_ERROR; + + // same page, different permission + auto ret = arch_mmu_protect(&aspace_->arch_aspace(), va, 1, arch_mmu_flags_); + if (ret < 0) { + TRACEF("failed to modify permissions on existing mapping\n"); + return ERR_NO_MEMORY; + } + } else { + // some other page is mapped there already + // currently this is an error situation, since there's no way for this to have + // happened, but in the future this will be a path for copy-on-write. + // TODO: implement + printf("KERN: thread %s faulted on va 0x%lx, different page was present, unhandled\n", + get_current_thread()->name, va); + return ERR_NOT_IMPLEMENTED; + } + } else { + // nothing was mapped there before, map it now + LTRACEF("mapping pa 0x%lx to va 0x%lx\n", new_pa, va); + auto ret = arch_mmu_map(&aspace_->arch_aspace(), va, new_pa, 1, arch_mmu_flags_); + if (ret < 0) { + TRACEF("failed to map page\n"); + return ERR_NO_MEMORY; + } + } + + return NO_ERROR; +} diff --git a/kernel/kernel/vm/vmm.cpp b/kernel/kernel/vm/vmm.cpp new file mode 100644 index 000000000..d8aeeba2d --- /dev/null +++ b/kernel/kernel/vm/vmm.cpp @@ -0,0 +1,293 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "vm_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE MAX(VM_GLOBAL_TRACE, 0) +#define TRACE_PAGE_FAULT 0 + +// This file mostly contains C wrappers around the underlying C++ objects, conforming to +// the older api. + +static void vmm_context_switch(VmAspace* oldspace, VmAspace* newaspace); + +status_t vmm_reserve_space(vmm_aspace_t* _aspace, const char* name, size_t size, vaddr_t vaddr) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + return aspace->ReserveSpace(name, size, vaddr); +} + +status_t vmm_alloc_physical(vmm_aspace_t* _aspace, const char* name, size_t size, void** ptr, + uint8_t align_pow2, paddr_t paddr, uint vmm_flags, + uint arch_mmu_flags) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + return aspace->AllocPhysical(name, size, ptr, align_pow2, paddr, vmm_flags, arch_mmu_flags); +} + +status_t vmm_alloc_contiguous(vmm_aspace_t* _aspace, const char* name, size_t size, void** ptr, + uint8_t align_pow2, uint vmm_flags, uint arch_mmu_flags) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + return aspace->AllocContiguous(name, size, ptr, align_pow2, vmm_flags, arch_mmu_flags); +} + +status_t vmm_alloc(vmm_aspace_t* _aspace, const char* name, size_t size, void** ptr, + uint8_t align_pow2, uint vmm_flags, uint arch_mmu_flags) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + return aspace->Alloc(name, size, ptr, align_pow2, vmm_flags, arch_mmu_flags); +} + +status_t vmm_protect_region(vmm_aspace_t* _aspace, vaddr_t va, uint arch_mmu_flags) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + auto r = aspace->FindRegion(va); + if (!r) + return ERR_NOT_FOUND; + + return r->Protect(arch_mmu_flags); +} + +status_t vmm_move_region_phys(vmm_aspace_t* _aspace, vaddr_t va, paddr_t paddr) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + auto r = aspace->FindRegion(va); + if (!r) + return ERR_NOT_FOUND; + + return r->MapPhysicalRange(0, r->size(), paddr, true); +} + +status_t vmm_free_region(vmm_aspace_t* _aspace, vaddr_t vaddr) { + auto aspace = vmm_aspace_to_obj(_aspace); + if (!aspace) + return ERR_INVALID_ARGS; + + return aspace->FreeRegion(vaddr); +} + +status_t vmm_create_aspace(vmm_aspace_t** _aspace, const char* name, uint flags) { + + auto aspace = VmAspace::Create(flags, name ? name : "unnamed"); + + *_aspace = reinterpret_cast(aspace.get()); + + // Since we're allocating this with the C api, + // to keep it from going out of scope, add a ref here. + // The ref will be implicitly removed in vmm_free_aspace() + aspace->AddRef(); + + return NO_ERROR; +} + +status_t vmm_free_aspace(vmm_aspace_t* _aspace) { + auto aspace = vmm_aspace_to_obj(_aspace); + + if (!aspace) + return ERR_INVALID_ARGS; + + // make sure the current thread does not map the aspace + thread_t* current_thread = get_current_thread(); + if (current_thread->aspace == (void*)aspace) { + THREAD_LOCK(state); + current_thread->aspace = nullptr; + vmm_context_switch(aspace, nullptr); + THREAD_UNLOCK(state); + } + + // tell it to destroy all of the regions + aspace->Destroy(); + + // drop the ref we grabbed in vmm_create_aspace + if (aspace->Release()) + delete aspace; + + return NO_ERROR; +} + +static inline void vmm_context_switch(VmAspace* oldspace, VmAspace* newaspace) { + DEBUG_ASSERT(thread_lock_held()); + + arch_mmu_context_switch(oldspace ? &oldspace->arch_aspace() : nullptr, + newaspace ? &newaspace->arch_aspace() : nullptr); +} + +void vmm_context_switch(vmm_aspace_t* oldspace, vmm_aspace_t* newaspace) { + vmm_context_switch(reinterpret_cast(oldspace), + reinterpret_cast(newaspace)); +} + +status_t vmm_page_fault_handler(vaddr_t addr, uint flags) { +#if TRACE_PAGE_FAULT || LOCAL_TRACE + thread_t* current_thread = get_current_thread(); + TRACEF("thread %s va 0x%lx, flags 0x%x\n", current_thread->name, addr, + flags); +#endif + + // get the address space object this pointer is in + VmAspace* aspace = vmm_aspace_to_obj(vaddr_to_aspace((void*)addr)); + if (!aspace) + return ERR_NOT_FOUND; + + // page fault it + return aspace->PageFault(addr, flags); +} + +void vmm_set_active_aspace(vmm_aspace_t* aspace) { + LTRACEF("aspace %p\n", aspace); + + thread_t* t = get_current_thread(); + DEBUG_ASSERT(t); + + if (aspace == t->aspace) + return; + + // grab the thread lock and switch to the new address space + THREAD_LOCK(state); + vmm_aspace_t* old = t->aspace; + t->aspace = aspace; + vmm_context_switch(old, t->aspace); + THREAD_UNLOCK(state); +} + +vmm_aspace_t* vmm_get_kernel_aspace(void) { + return reinterpret_cast(VmAspace::kernel_aspace()); +} + +arch_aspace_t* vmm_get_arch_aspace(vmm_aspace_t* aspace) { + auto real_aspace = reinterpret_cast(aspace); + return &real_aspace->arch_aspace(); +} + +static int cmd_vmm(int argc, const cmd_args* argv) { + if (argc < 2) { + notenoughargs: + printf("not enough arguments\n"); + usage: + printf("usage:\n"); + printf("%s aspaces\n", argv[0].str); + printf("%s alloc \n", argv[0].str); + printf("%s alloc_physical \n", argv[0].str); + printf("%s alloc_contig \n", argv[0].str); + printf("%s free_region
\n", argv[0].str); + printf("%s create_aspace\n", argv[0].str); + printf("%s create_test_aspace\n", argv[0].str); + printf("%s free_aspace
\n", argv[0].str); + printf("%s set_test_aspace
\n", argv[0].str); + return ERR_GENERIC; + } + + static vmm_aspace_t* test_aspace; + if (!test_aspace) + test_aspace = vmm_get_kernel_aspace(); + + if (!strcmp(argv[1].str, "aspaces")) { + DumpAllAspaces(); + } else if (!strcmp(argv[1].str, "alloc")) { + if (argc < 3) + goto notenoughargs; + + void* ptr = (void*)0x99; + uint8_t align = (argc >= 4) ? (uint8_t)argv[3].u : 0u; + status_t err = vmm_alloc(test_aspace, "alloc test", argv[2].u, &ptr, align, 0, 0); + printf("vmm_alloc returns %d, ptr %p\n", err, ptr); + } else if (!strcmp(argv[1].str, "alloc_physical")) { + if (argc < 4) + goto notenoughargs; + + void* ptr = (void*)0x99; + uint8_t align = (argc >= 5) ? (uint8_t)argv[4].u : 0u; + status_t err = vmm_alloc_physical(test_aspace, "physical test", argv[3].u, &ptr, align, + argv[2].u, 0, ARCH_MMU_FLAG_UNCACHED_DEVICE); + printf("vmm_alloc_physical returns %d, ptr %p\n", err, ptr); + } else if (!strcmp(argv[1].str, "alloc_contig")) { + if (argc < 3) + goto notenoughargs; + + void* ptr = (void*)0x99; + uint8_t align = (argc >= 4) ? (uint8_t)argv[3].u : 0u; + status_t err = + vmm_alloc_contiguous(test_aspace, "contig test", argv[2].u, &ptr, align, 0, 0); + printf("vmm_alloc_contig returns %d, ptr %p\n", err, ptr); + } else if (!strcmp(argv[1].str, "free_region")) { + if (argc < 2) + goto notenoughargs; + + status_t err = vmm_free_region(test_aspace, (vaddr_t)argv[2].u); + printf("vmm_free_region returns %d\n", err); + } else if (!strcmp(argv[1].str, "create_aspace")) { + vmm_aspace_t* aspace; + status_t err = vmm_create_aspace(&aspace, "test", 0); + printf("vmm_create_aspace returns %d, aspace %p\n", err, aspace); + } else if (!strcmp(argv[1].str, "create_test_aspace")) { + vmm_aspace_t* aspace; + status_t err = vmm_create_aspace(&aspace, "test", 0); + printf("vmm_create_aspace returns %d, aspace %p\n", err, aspace); + if (err < 0) + return err; + + test_aspace = aspace; + get_current_thread()->aspace = aspace; + thread_sleep(1); // XXX hack to force it to reschedule and thus load the aspace + } else if (!strcmp(argv[1].str, "free_aspace")) { + if (argc < 2) + goto notenoughargs; + + vmm_aspace_t* aspace = (vmm_aspace_t*)(void*)argv[2].u; + if (test_aspace == aspace) + test_aspace = nullptr; + + if (get_current_thread()->aspace == aspace) { + get_current_thread()->aspace = nullptr; + thread_sleep(1); // hack + } + + status_t err = vmm_free_aspace(aspace); + printf("vmm_free_aspace returns %d\n", err); + } else if (!strcmp(argv[1].str, "set_test_aspace")) { + if (argc < 2) + goto notenoughargs; + + test_aspace = (vmm_aspace_t*)(void*)argv[2].u; + get_current_thread()->aspace = test_aspace; + thread_sleep(1); // XXX hack to force it to reschedule and thus load the aspace + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("vmm", "virtual memory manager", &cmd_vmm) +#endif +STATIC_COMMAND_END(vmm); diff --git a/kernel/lib/bcache/BUILD.gn b/kernel/lib/bcache/BUILD.gn new file mode 100644 index 000000000..0ef1fbbba --- /dev/null +++ b/kernel/lib/bcache/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_bcache_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("bcache") { + public_configs = [ ":_bcache_config" ] + public = [ + "include/lib/bcache.h", + ] + sources = [ + "bcache.c", + ] + deps = [ + "//kernel/lib/bio", + ] +} diff --git a/kernel/lib/bcache/bcache.c b/kernel/lib/bcache/bcache.c new file mode 100644 index 000000000..45b2ac8a8 --- /dev/null +++ b/kernel/lib/bcache/bcache.c @@ -0,0 +1,335 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2007 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct bcache_block { + struct list_node node; + bnum_t blocknum; + int ref_count; + bool is_dirty; + void *ptr; +}; + +struct bcache_stats { + uint32_t hits; + uint32_t depth; + uint32_t misses; + uint32_t reads; + uint32_t writes; +}; + +struct bcache { + bdev_t *dev; + size_t block_size; + int count; + struct bcache_stats stats; + + struct list_node free_list; + struct list_node lru_list; + + struct bcache_block *blocks; +}; + +bcache_t bcache_create(bdev_t *dev, size_t block_size, int block_count) +{ + struct bcache *cache; + + cache = malloc(sizeof(struct bcache)); + + cache->dev = dev; + cache->block_size = block_size; + cache->count = block_count; + memset(&cache->stats, 0, sizeof(cache->stats)); + + list_initialize(&cache->free_list); + list_initialize(&cache->lru_list); + + cache->blocks = malloc(sizeof(struct bcache_block) * block_count); + int i; + for (i=0; i < block_count; i++) { + cache->blocks[i].ref_count = 0; + cache->blocks[i].is_dirty = false; + cache->blocks[i].ptr = malloc(block_size); + // add to the free list + list_add_head(&cache->free_list, &cache->blocks[i].node); + } + + return (bcache_t)cache; +} + +static int flush_block(struct bcache *cache, struct bcache_block *block) +{ + int rc; + + rc = bio_write(cache->dev, block->ptr, + (off_t)block->blocknum * cache->block_size, + cache->block_size); + if (rc < 0) + goto exit; + + block->is_dirty = false; + cache->stats.writes++; + rc = 0; +exit: + return (rc); +} + +void bcache_destroy(bcache_t _cache) +{ + struct bcache *cache = _cache; + int i; + + for (i=0; i < cache->count; i++) { + DEBUG_ASSERT(cache->blocks[i].ref_count == 0); + + if (cache->blocks[i].is_dirty) + printf("warning: freeing dirty block %u\n", + cache->blocks[i].blocknum); + + free(cache->blocks[i].ptr); + } + + free(cache); +} + +/* find a block if it's already present */ +static struct bcache_block *find_block(struct bcache *cache, uint blocknum) +{ + uint32_t depth = 0; + struct bcache_block *block; + + LTRACEF("num %u\n", blocknum); + + block = NULL; + list_for_every_entry(&cache->lru_list, block, struct bcache_block, node) { + LTRACEF("looking at entry %p, num %u\n", block, block->blocknum); + depth++; + + if (block->blocknum == blocknum) { + list_delete(&block->node); + list_add_tail(&cache->lru_list, &block->node); + cache->stats.hits++; + cache->stats.depth += depth; + return block; + } + } + + cache->stats.misses++; + return NULL; +} + +/* allocate a new block */ +static struct bcache_block *alloc_block(struct bcache *cache) +{ + int err; + struct bcache_block *block; + + /* pop one off the free list if it's present */ + block = list_remove_head_type(&cache->free_list, struct bcache_block, node); + if (block) { + block->ref_count = 0; + list_add_tail(&cache->lru_list, &block->node); + LTRACEF("found block %p on free list\n", block); + return block; + } + + /* walk the lru, looking for a free block */ + list_for_every_entry(&cache->lru_list, block, struct bcache_block, node) { + LTRACEF("looking at %p, num %u\n", block, block->blocknum); + if (block->ref_count == 0) { + if (block->is_dirty) { + err = flush_block(cache, block); + if (err) + return NULL; + } + + // add it to the tail of the lru + list_delete(&block->node); + list_add_tail(&cache->lru_list, &block->node); + return block; + } + } + + return NULL; +} + +static struct bcache_block *find_or_fill_block(struct bcache *cache, uint blocknum) +{ + int err; + + LTRACEF("block %u\n", blocknum); + + /* see if it's already in the cache */ + struct bcache_block *block = find_block(cache, blocknum); + if (block == NULL) { + LTRACEF("wasn't allocated\n"); + + /* allocate a new block and fill it */ + block = alloc_block(cache); + DEBUG_ASSERT(block); + + LTRACEF("wasn't allocated, new block %p\n", block); + + block->blocknum = blocknum; + err = bio_read(cache->dev, block->ptr, (off_t)blocknum * cache->block_size, cache->block_size); + if (err < 0) { + /* free the block, return an error */ + list_add_tail(&cache->free_list, &block->node); + return NULL; + } + + cache->stats.reads++; + } + + DEBUG_ASSERT(block->blocknum == blocknum); + + return block; +} + +int bcache_read_block(bcache_t _cache, void *buf, uint blocknum) +{ + struct bcache *cache = _cache; + + LTRACEF("buf %p, blocknum %u\n", buf, blocknum); + + struct bcache_block *block = find_or_fill_block(cache, blocknum); + if (block == NULL) { + /* error */ + return -1; + } + + memcpy(buf, block->ptr, cache->block_size); + return 0; +} + +int bcache_get_block(bcache_t _cache, void **ptr, uint blocknum) +{ + struct bcache *cache = _cache; + + LTRACEF("ptr %p, blocknum %u\n", ptr, blocknum); + + DEBUG_ASSERT(ptr); + + struct bcache_block *block = find_or_fill_block(cache, blocknum); + if (block == NULL) { + /* error */ + return -1; + } + + /* increment the ref count to keep it from being freed */ + block->ref_count++; + *ptr = block->ptr; + + return 0; +} + +int bcache_put_block(bcache_t _cache, uint blocknum) +{ + struct bcache *cache = _cache; + + LTRACEF("blocknum %u\n", blocknum); + + struct bcache_block *block = find_block(cache, blocknum); + + /* be pretty hard on the caller for now */ + DEBUG_ASSERT(block); + DEBUG_ASSERT(block->ref_count > 0); + + block->ref_count--; + + return 0; +} + +int bcache_mark_block_dirty(bcache_t priv, uint blocknum) +{ + int err; + struct bcache *cache = priv; + struct bcache_block *block; + + block = find_block(cache, blocknum); + if (!block) { + err = -1; + goto exit; + } + + block->is_dirty = true; + err = 0; +exit: + return (err); +} + +int bcache_zero_block(bcache_t priv, uint blocknum) +{ + int err; + struct bcache *cache = priv; + struct bcache_block *block; + + block = find_block(cache, blocknum); + if (!block) { + block = alloc_block(cache); + if (!block) { + err = -1; + goto exit; + } + + block->blocknum = blocknum; + } + + memset(block->ptr, 0, cache->block_size); + block->is_dirty = true; + err = 0; +exit: + return (err); +} + +int bcache_flush(bcache_t priv) +{ + int err; + struct bcache *cache = priv; + struct bcache_block *block; + + list_for_every_entry(&cache->lru_list, block, struct bcache_block, node) { + if (block->is_dirty) { + err = flush_block(cache, block); + if (err) + goto exit; + } + } + + err = 0; +exit: + return (err); +} + +void bcache_dump(bcache_t priv, const char *name) +{ + uint32_t finds; + struct bcache *cache = priv; + + finds = cache->stats.hits + cache->stats.misses; + + printf("%s: hits=%u(%u%%) depth=%u misses=%u(%u%%) reads=%u writes=%u\n", + name, + cache->stats.hits, + finds ? (cache->stats.hits * 100) / finds : 0, + cache->stats.hits ? cache->stats.depth / cache->stats.hits : 0, + cache->stats.misses, + finds ? (cache->stats.misses * 100) / finds : 0, + cache->stats.reads, + cache->stats.writes); +} diff --git a/kernel/lib/bcache/include/lib/bcache.h b/kernel/lib/bcache/include/lib/bcache.h new file mode 100644 index 000000000..625c1c80b --- /dev/null +++ b/kernel/lib/bcache/include/lib/bcache.h @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2007 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +typedef void *bcache_t; + +bcache_t bcache_create(bdev_t *dev, size_t block_size, int block_count); +void bcache_destroy(bcache_t); + +int bcache_read_block(bcache_t, void *, uint block); + +// get and put a pointer directly to the block +int bcache_get_block(bcache_t, void **, uint block); +int bcache_put_block(bcache_t, uint block); + diff --git a/kernel/lib/bcache/rules.mk b/kernel/lib/bcache/rules.mk new file mode 100644 index 000000000..b8b5c6adf --- /dev/null +++ b/kernel/lib/bcache/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += lib/bio + +MODULE_SRCS += \ + $(LOCAL_DIR)/bcache.c + +include make/module.mk diff --git a/kernel/lib/bio/BUILD.gn b/kernel/lib/bio/BUILD.gn new file mode 100644 index 000000000..658217637 --- /dev/null +++ b/kernel/lib/bio/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_bio_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("bio") { + public_configs = [ ":_bio_config" ] + configs += [ "//kernel/lib/partition:enable_partition" ] + public = [ + "include/lib/bio.h", + ] + cflags = [ + "-Wno-sign-compare", + "-Wno-int-to-pointer-cast", + ] + sources = [ + "bio.c", + "debug.c", + "mem.c", + "subdev.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + "//kernel/lib/user_copy", + "//third_party/lib/cksum", + ] +} diff --git a/kernel/lib/bio/bio.c b/kernel/lib/bio/bio.c new file mode 100644 index 000000000..4043f9b11 --- /dev/null +++ b/kernel/lib/bio/bio.c @@ -0,0 +1,580 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +static struct { + struct list_node list; + mutex_t lock; +} bdevs = { + .list = LIST_INITIAL_VALUE(bdevs.list), + .lock = MUTEX_INITIAL_VALUE(bdevs.lock), +}; + +/* default implementation is to use the read_block hook to 'deblock' the device */ +static ssize_t bio_default_read(struct bdev *dev, void *_buf, off_t offset, size_t len) +{ + uint8_t *buf = (uint8_t *)_buf; + ssize_t bytes_read = 0; + bnum_t block; + ssize_t err = 0; + STACKBUF_DMA_ALIGN(temp, dev->block_size); // temporary buffer for partial block transfers + + /* find the starting block */ + block = offset / dev->block_size; + + LTRACEF("buf %p, offset %lld, block %u, len %zd\n", buf, offset, block, len); + /* handle partial first block */ + if ((offset % dev->block_size) != 0) { + /* read in the block */ + err = bio_read_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + /* copy what we need */ + size_t block_offset = offset % dev->block_size; + size_t tocopy = MIN(dev->block_size - block_offset, len); + memcpy(buf, temp + block_offset, tocopy); + + /* increment our buffers */ + buf += tocopy; + len -= tocopy; + bytes_read += tocopy; + block++; + } + + LTRACEF("buf %p, block %u, len %zd\n", buf, block, len); + + // If the device requires alignment AND our buffer is not alread aligned. + bool requires_alignment = + (dev->flags & BIO_FLAG_CACHE_ALIGNED_READS) && + (IS_ALIGNED((size_t)buf, CACHE_LINE) == false); + /* handle middle blocks */ + if (requires_alignment) { + while (len >= dev->block_size) { + /* do the middle reads */ + err = bio_read_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + memcpy(buf, temp, dev->block_size); + + buf += dev->block_size; + len -= dev->block_size; + bytes_read += dev->block_size; + block++; + } + } else { + uint32_t num_blocks = divpow2(len, dev->block_shift); + err = bio_read_block(dev, buf, block, num_blocks); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size * num_blocks) { + err = ERR_IO; + goto err; + } + buf += err; + len -= err; + bytes_read += err; + block += num_blocks; + } + + LTRACEF("buf %p, block %u, len %zd\n", buf, block, len); + /* handle partial last block */ + if (len > 0) { + /* read the block */ + err = bio_read_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + /* copy the partial block from our temp buffer */ + memcpy(buf, temp, len); + + bytes_read += len; + } + +err: + /* return error or bytes read */ + return (err >= 0) ? bytes_read : err; +} + +static ssize_t bio_default_write(struct bdev *dev, const void *_buf, off_t offset, size_t len) +{ + const uint8_t *buf = (const uint8_t *)_buf; + ssize_t bytes_written = 0; + bnum_t block; + ssize_t err = 0; + STACKBUF_DMA_ALIGN(temp, dev->block_size); // temporary buffer for partial block transfers + + /* find the starting block */ + block = offset / dev->block_size; + + LTRACEF("buf %p, offset %lld, block %u, len %zd\n", buf, offset, block, len); + /* handle partial first block */ + if ((offset % dev->block_size) != 0) { + /* read in the block */ + err = bio_read_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + /* copy what we need */ + size_t block_offset = offset % dev->block_size; + size_t tocopy = MIN(dev->block_size - block_offset, len); + memcpy(temp + block_offset, buf, tocopy); + + /* write it back out */ + err = bio_write_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + /* increment our buffers */ + buf += tocopy; + len -= tocopy; + bytes_written += tocopy; + block++; + } + + LTRACEF("buf %p, block %u, len %zd\n", buf, block, len); + + // If the device requires alignment AND our buffer is not alread aligned. + bool requires_alignment = + (dev->flags & BIO_FLAG_CACHE_ALIGNED_WRITES) && + (IS_ALIGNED((size_t)buf, CACHE_LINE) == false); + + /* handle middle blocks */ + if (requires_alignment) { + while (len >= dev->block_size) { + /* do the middle reads */ + memcpy(temp, buf, dev->block_size); + err = bio_write_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + buf += dev->block_size; + len -= dev->block_size; + bytes_written += dev->block_size; + block++; + } + } else { + uint32_t block_count = divpow2(len, dev->block_shift); + err = bio_write_block(dev, buf, block, block_count); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size * block_count) { + err = ERR_IO; + goto err; + } + + DEBUG_ASSERT((size_t)err == (block_count * dev->block_size)); + + buf += err; + len -= err; + bytes_written += err; + block += block_count; + } + + LTRACEF("buf %p, block %u, len %zd\n", buf, block, len); + /* handle partial last block */ + if (len > 0) { + /* read the block */ + err = bio_read_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + /* copy the partial block from our temp buffer */ + memcpy(temp, buf, len); + + /* write it back out */ + err = bio_write_block(dev, temp, block, 1); + if (err < 0) { + goto err; + } else if ((size_t)err != dev->block_size) { + err = ERR_IO; + goto err; + } + + bytes_written += len; + } + +err: + /* return error or bytes written */ + return (err >= 0) ? bytes_written : err; +} + +static ssize_t bio_default_erase(struct bdev *dev, off_t offset, size_t len) +{ + /* default erase operation is to just write zeros over the device */ + STACKBUF_DMA_ALIGN(erase_buf, dev->block_size); + + memset(erase_buf, dev->erase_byte, dev->block_size); + + ssize_t erased = 0; + size_t remaining = len; + off_t pos = offset; + while (remaining > 0) { + size_t towrite = MIN(remaining, dev->block_size); + + ssize_t written = bio_write(dev, erase_buf, pos, towrite); + if (written < 0) + return written; + + erased += written; + pos += written; + remaining -= written; + + if ((size_t)written < towrite) + break; + } + + return erased; +} + +static ssize_t bio_default_read_block(struct bdev *dev, void *buf, bnum_t block, uint count) +{ + return ERR_NOT_SUPPORTED; +} + +static ssize_t bio_default_write_block(struct bdev *dev, const void *buf, bnum_t block, uint count) +{ + return ERR_NOT_SUPPORTED; +} + +static void bdev_inc_ref(bdev_t *dev) +{ + LTRACEF("Add ref \"%s\" %d -> %d\n", dev->name, dev->ref, dev->ref + 1); + atomic_add(&dev->ref, 1); +} + +static void bdev_dec_ref(bdev_t *dev) +{ + int oldval = atomic_add(&dev->ref, -1); + + LTRACEF("Dec ref \"%s\" %d -> %d\n", dev->name, oldval, dev->ref); + + if (oldval == 1) { + // last ref, remove it + DEBUG_ASSERT(!list_in_list(&dev->node)); + + TRACEF("last ref, removing (%s)\n", dev->name); + + // call the close hook if it exists + if (dev->close) + dev->close(dev); + + free(dev->name); + } +} + +size_t bio_trim_range(const bdev_t *dev, off_t offset, size_t len) +{ + DEBUG_ASSERT(dev && (dev->total_size >= 0)); + /* range check */ + if (offset < 0) + return 0; + if (offset >= dev->total_size) + return 0; + if (len == 0) + return 0; + if (len > (uint64_t)(dev->total_size - offset)) + len = dev->total_size - offset; + + return len; +} + +uint bio_trim_block_range(const bdev_t *dev, bnum_t block, uint count) +{ + if (block > dev->block_count) + return 0; + if (count == 0) + return 0; + if (block + count > dev->block_count) + count = dev->block_count - block; + + return count; +} + +bdev_t *bio_open(const char *name) +{ + bdev_t *bdev = NULL; + + LTRACEF(" '%s'\n", name); + + /* see if it's in our list */ + bdev_t *entry; + mutex_acquire(&bdevs.lock); + list_for_every_entry(&bdevs.list, entry, bdev_t, node) { + DEBUG_ASSERT(entry->ref > 0); + if (!strcmp(entry->name, name)) { + bdev = entry; + bdev_inc_ref(bdev); + break; + } + } + mutex_release(&bdevs.lock); + + return bdev; +} + +void bio_close(bdev_t *dev) +{ + DEBUG_ASSERT(dev); + LTRACEF(" '%s'\n", dev->name); + bdev_dec_ref(dev); +} + +ssize_t bio_read(bdev_t *dev, void *buf, off_t offset, size_t len) +{ + LTRACEF("dev '%s', buf %p, offset %lld, len %zd\n", dev->name, buf, offset, len); + + DEBUG_ASSERT(dev && dev->ref > 0); + DEBUG_ASSERT(buf); + + /* range check */ + len = bio_trim_range(dev, offset, len); + if (len == 0) + return 0; + + return dev->read(dev, buf, offset, len); +} + +ssize_t bio_read_block(bdev_t *dev, void *buf, bnum_t block, uint count) +{ + LTRACEF("dev '%s', buf %p, block %d, count %u\n", dev->name, buf, block, count); + + DEBUG_ASSERT(dev && dev->ref > 0); + DEBUG_ASSERT(buf); + + /* range check */ + count = bio_trim_block_range(dev, block, count); + if (count == 0) + return 0; + + return dev->read_block(dev, buf, block, count); +} + +ssize_t bio_write(bdev_t *dev, const void *buf, off_t offset, size_t len) +{ + LTRACEF("dev '%s', buf %p, offset %lld, len %zd\n", dev->name, buf, offset, len); + + DEBUG_ASSERT(dev && dev->ref > 0); + DEBUG_ASSERT(buf); + + /* range check */ + len = bio_trim_range(dev, offset, len); + if (len == 0) + return 0; + + return dev->write(dev, buf, offset, len); +} + +ssize_t bio_write_block(bdev_t *dev, const void *buf, bnum_t block, uint count) +{ + LTRACEF("dev '%s', buf %p, block %d, count %u\n", dev->name, buf, block, count); + + DEBUG_ASSERT(dev && dev->ref > 0); + DEBUG_ASSERT(buf); + + /* range check */ + count = bio_trim_block_range(dev, block, count); + if (count == 0) + return 0; + + return dev->write_block(dev, buf, block, count); +} + +ssize_t bio_erase(bdev_t *dev, off_t offset, size_t len) +{ + LTRACEF("dev '%s', offset %lld, len %zd\n", dev->name, offset, len); + + DEBUG_ASSERT(dev && dev->ref > 0); + + /* range check */ + len = bio_trim_range(dev, offset, len); + if (len == 0) + return 0; + + return dev->erase(dev, offset, len); +} + +int bio_ioctl(bdev_t *dev, int request, void *argp) +{ + LTRACEF("dev '%s', request %08x, argp %p\n", dev->name, request, argp); + + if (dev->ioctl == NULL) { + return ERR_NOT_SUPPORTED; + } else { + return dev->ioctl(dev, request, argp); + } +} + +void bio_initialize_bdev(bdev_t *dev, + const char *name, + size_t block_size, + bnum_t block_count, + size_t geometry_count, + const bio_erase_geometry_info_t *geometry, + const uint32_t flags) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(name); + + // Block size must be finite powers of 2 + DEBUG_ASSERT(block_size && ispow2(block_size)); + + list_clear_node(&dev->node); + dev->name = strdup(name); + dev->block_size = block_size; + dev->block_count = block_count; + dev->block_shift = log2_uint(block_size); + dev->total_size = (off_t)block_count << dev->block_shift; + dev->geometry_count = geometry_count; + dev->geometry = geometry; + dev->erase_byte = 0; + dev->ref = 0; + dev->flags = flags; + +#if DEBUG + // If we have been supplied information about our erase geometry, sanity + // check it in debug bulids. + if (geometry_count && geometry) { + for (size_t i = 0; i < geometry_count; ++i) { + bio_erase_geometry_info_t *info = geometry + i; + + // Erase sizes must be powers of two and agree with the supplied erase shift. + DEBUG_ASSERT(info->erase_size); + DEBUG_ASSERT(info->erase_size == ((size_t)1 << info->erase_shift)); + + info->start = desc->start; + info->erase_size = desc->erase_size; + info->erase_shift = log2_uint(desc->erase_size); + info->size = ((off_t)desc->block_count) << desc->block_size; + + // Make sure that region is aligned on both a program and erase block boundary. + DEBUG_ASSERT(!(info->start & (((off_t)1 << info->block_shift) - 1))); + DEBUG_ASSERT(!(info->start & (((off_t)1 << info->erase_shift) - 1))); + + // Make sure that region's length is an integral multiple of both the + // program and erase block size. + DEBUG_ASSERT(!(info->size & (((off_t)1 << dev->block_shift) - 1))); + DEBUG_ASSERT(!(info->size & (((off_t)1 << info->erase_shift) - 1))); + } + + // Make sure that none of the regions overlap each other and that they are + // listed in ascending order. + for (size_t i = 0; (i + 1) < geometry_count; ++i) { + bio_geometry_info_t *r1 = dev->geometry + i; + bio_geometry_info_t *r2 = dev->geometry + i + 1; + DEBUG_ASSERT(r1->start <= r2->start); + + for (size_t j = (i + 1); j < geometry_count; ++j) { + bio_geometry_info_t *r2 = dev->geometry + j; + DEBUG_ASSERT(!bio_does_overlap(r1->start, r1->size, r2->start, r2->size)); + } + } + } +#endif + + /* set up the default hooks, the sub driver should override the block operations at least */ + dev->read = bio_default_read; + dev->read_block = bio_default_read_block; + dev->write = bio_default_write; + dev->write_block = bio_default_write_block; + dev->erase = bio_default_erase; + dev->close = NULL; +} + +void bio_register_device(bdev_t *dev) +{ + DEBUG_ASSERT(dev); + + LTRACEF(" '%s'\n", dev->name); + + bdev_inc_ref(dev); + + mutex_acquire(&bdevs.lock); + list_add_tail(&bdevs.list, &dev->node); + mutex_release(&bdevs.lock); +} + +void bio_unregister_device(bdev_t *dev) +{ + DEBUG_ASSERT(dev); + + LTRACEF(" '%s'\n", dev->name); + + // remove it from the list + mutex_acquire(&bdevs.lock); + list_delete(&dev->node); + mutex_release(&bdevs.lock); + + bdev_dec_ref(dev); // remove the ref the list used to have +} + +void bio_dump_devices(void) +{ + printf("block devices:\n"); + bdev_t *entry; + mutex_acquire(&bdevs.lock); + list_for_every_entry(&bdevs.list, entry, bdev_t, node) { + + printf("\t%s, size %lld, bsize %zd, ref %d", + entry->name, entry->total_size, entry->block_size, entry->ref); + + if (!entry->geometry_count || !entry->geometry) { + printf(" (no erase geometry)\n"); + } else { + for (size_t i = 0; i < entry->geometry_count; ++i) { + const bio_erase_geometry_info_t *geo = entry->geometry + i; + printf("\n\t\terase_region[%zu] : start %lld size %lld erase size %zu", + i, geo->start, geo->size, geo->erase_size); + + } + } + + printf("\n"); + } + mutex_release(&bdevs.lock); +} diff --git a/kernel/lib/bio/debug.c b/kernel/lib/bio/debug.c new file mode 100644 index 000000000..caaa93c4b --- /dev/null +++ b/kernel/lib/bio/debug.c @@ -0,0 +1,552 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_LIB_CKSUM +#include +#endif + +#define DMA_ALIGNMENT (CACHE_LINE) +#define THREE_BYTE_ADDR_BOUNDARY (16777216) +#define SUB_ERASE_TEST_SAMPLES (32) + +#if defined(WITH_LIB_CONSOLE) + +#if LK_DEBUGLEVEL > 0 +static int cmd_bio(int argc, const cmd_args *argv); +static int bio_test_device(bdev_t *device); + +STATIC_COMMAND_START +STATIC_COMMAND("bio", "block io debug commands", &cmd_bio) +STATIC_COMMAND_END(bio); + +static int cmd_bio(int argc, const cmd_args *argv) +{ + int rc = 0; + + if (argc < 2) { +notenoughargs: + printf("not enough arguments:\n"); +usage: + printf("%s list\n", argv[0].str); + printf("%s read
\n", argv[0].str); + printf("%s write
\n", argv[0].str); + printf("%s dump \n", argv[0].str); + printf("%s erase \n", argv[0].str); + printf("%s ioctl \n", argv[0].str); + printf("%s remove \n", argv[0].str); + printf("%s test \n", argv[0].str); +#if WITH_LIB_PARTITION + printf("%s partscan [offset]\n", argv[0].str); +#endif +#if WITH_LIB_CKSUM + printf("%s crc32 [repeat]\n", argv[0].str); +#endif + return -1; + } + + if (!strcmp(argv[1].str, "list")) { + bio_dump_devices(); + } else if (!strcmp(argv[1].str, "read")) { + if (argc < 6) goto notenoughargs; + + addr_t address = argv[3].u; + off_t offset = argv[4].u; // XXX use long + size_t len = argv[5].u; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + lk_time_t t = current_time(); + ssize_t err = bio_read(dev, (void *)address, offset, len); + t = current_time() - t; + dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); + + bio_close(dev); + + rc = err; + } else if (!strcmp(argv[1].str, "write")) { + if (argc < 6) goto notenoughargs; + + addr_t address = argv[3].u; + off_t offset = argv[4].u; // XXX use long + size_t len = argv[5].u; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + lk_time_t t = current_time(); + ssize_t err = bio_write(dev, (void *)address, offset, len); + t = current_time() - t; + dprintf(INFO, "bio_write returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); + + bio_close(dev); + + rc = err; + } else if (!strcmp(argv[1].str, "dump")) { + if (argc < 5) { + printf("not enough arguments:\n"); + goto usage; + } + + off_t offset = argv[3].u; // XXX use long + size_t len = argv[4].u; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + uint8_t *buf = memalign(CACHE_LINE, 256); + ssize_t err = 0; + while (len > 0) { + size_t amt = MIN(256, len); + ssize_t err = bio_read(dev, buf, offset, amt); + + if (err < 0) { + dprintf(ALWAYS, "read error %s %zu@%zu (err %d)\n", + argv[2].str, amt, (size_t)offset, (int)err); + break; + } + + DEBUG_ASSERT((size_t)err <= amt); + hexdump8_ex(buf, err, offset); + + if ((size_t)err != amt) { + dprintf(ALWAYS, "short read from %s @%zu (wanted %zu, got %zu)\n", + argv[2].str, (size_t)offset, amt, (size_t)err); + break; + } + + offset += amt; + len -= amt; + } + + bio_close(dev); + rc = err; + } else if (!strcmp(argv[1].str, "erase")) { + if (argc < 5) goto notenoughargs; + + off_t offset = argv[3].u; // XXX use long + size_t len = argv[4].u; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + lk_time_t t = current_time(); + ssize_t err = bio_erase(dev, offset, len); + t = current_time() - t; + dprintf(INFO, "bio_erase returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); + + bio_close(dev); + + rc = err; + } else if (!strcmp(argv[1].str, "ioctl")) { + if (argc < 4) goto notenoughargs; + + int request = argv[3].u; + intptr_t arg = (argc == 5) ? argv[4].u : 0; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + int err = bio_ioctl(dev, request, (void *)arg); + dprintf(INFO, "bio_ioctl returns %d\n", err); + + bio_close(dev); + + rc = err; + } else if (!strcmp(argv[1].str, "remove")) { + if (argc < 3) goto notenoughargs; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + bio_unregister_device(dev); + bio_close(dev); + } else if (!strcmp(argv[1].str, "test")) { + if (argc < 3) goto notenoughargs; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + int err = bio_test_device(dev); + bio_close(dev); + + rc = err; +#if WITH_LIB_PARTITION + } else if (!strcmp(argv[1].str, "partscan")) { + if (argc < 3) goto notenoughargs; + + off_t offset = 0; + if (argc > 3) + offset = argv[3].u; + + rc = partition_publish(argv[2].str, offset); + dprintf(INFO, "partition_publish returns %d\n", rc); +#endif +#if WITH_LIB_CKSUM + } else if (!strcmp(argv[1].str, "crc32")) { + if (argc < 5) goto notenoughargs; + + uint64_t offset = argv[3].u; // XXX parse console args as 64bit ints? + size_t len = argv[4].u; + + bdev_t *dev = bio_open(argv[2].str); + if (!dev) { + printf("error opening block device\n"); + return -1; + } + + void *buf = malloc(dev->block_size); + + bool repeat = false; + if (argc >= 6 && !strcmp(argv[5].str, "repeat")) { + repeat = true; + } + + do { + uint32_t crc = 0; + uint64_t pos = 0; + while (pos < len) { + ssize_t err = bio_read(dev, + buf, + pos + offset, + MIN(len - pos, dev->block_size)); + + if (err <= 0) { + printf("error reading at offset 0x%llx\n", offset + pos); + break; + } + + crc = crc32(crc, buf, err); + + pos += err; + } + + printf("crc 0x%08x\n", crc); + } while (repeat); + + bio_close(dev); + free(buf); + +#endif + } else { + printf("unrecognized subcommand\n"); + goto usage; + } + + return rc; +} + +#endif + +#endif + +// Returns the number of blocks that do not match the reference pattern. +static bool is_valid_block(bdev_t *device, bnum_t block_num, uint8_t *pattern, + size_t pattern_length) +{ + uint8_t *block_contents = memalign(DMA_ALIGNMENT, device->block_size); + + ssize_t n_bytes = device->read_block(device, block_contents, block_num, 1); + if (n_bytes < 0 || n_bytes != (ssize_t)device->block_size) { + free(block_contents); + return false; + } + + for (size_t i = 0; i < device->block_size; i++) { + if (block_contents[i] != pattern[i % pattern_length]) { + free(block_contents); + block_contents = NULL; + return false; + } + } + + free(block_contents); + block_contents = NULL; + + return true; +} + +static ssize_t erase_test(bdev_t *device) +{ + printf("erasing device...\n"); + + ssize_t err = bio_erase(device, 0, device->total_size); + if (err < 0) { + return err; + } else if (err != device->total_size) { + return ERR_IO; + } + + printf("validating erase...\n"); + size_t num_invalid_blocks = 0; + for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { + if (!is_valid_block(device, bnum, &device->erase_byte, sizeof(device->erase_byte))) { + num_invalid_blocks++; + } + } + return num_invalid_blocks; +} + +static bool test_erase_block(bdev_t *device, uint32_t block_addr) +{ + bool success = false; + uint8_t valid_byte[1]; + + uint8_t *block_contents = memalign(DMA_ALIGNMENT, device->block_size); + memset(block_contents, ~(device->erase_byte), device->block_size); + + ssize_t err = bio_write_block(device, block_contents, block_addr, 1); + if (err != (ssize_t)device->block_size) { + goto finish; + } + + valid_byte[0] = ~(device->erase_byte); + if (!is_valid_block(device, block_addr, valid_byte, 1)) { + goto finish; + } + + err = bio_erase(device, block_addr * device->block_size, 1); + if (err <= 0) { + goto finish; + } + + valid_byte[0] = device->erase_byte; + if (is_valid_block(device, block_addr, valid_byte, 1)) { + success = true; + } + +finish: + free(block_contents); + return success; +} + +// Ensure that (sub)sector erase work. +static bool sub_erase_test(bdev_t *device, uint32_t n_samples) +{ + printf("Sampling the device %d times.\n", n_samples); + for (uint32_t i = 0; i < n_samples; i++) { + bnum_t block_addr = rand() % device->block_count; + if (!test_erase_block(device, block_addr)) { + return false; + } + } + return true; +} + +static uint8_t get_signature(uint32_t word) +{ + uint8_t *sigptr = (uint8_t *)(&word); + return sigptr[0] ^ sigptr[1] ^ sigptr[2] ^ sigptr[3]; +} + +// returns the number of blocks where the write was not successful. +static ssize_t write_test(bdev_t *device) +{ + uint8_t *test_buffer = memalign(DMA_ALIGNMENT, device->block_size); + + for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { + memset(test_buffer, get_signature(bnum), device->block_size); + ssize_t err = bio_write_block(device, test_buffer, bnum, 1); + if (err < 0) { + free(test_buffer); + return err; + } + } + + size_t num_errors = 0; + uint8_t expected_pattern[1]; + for (bnum_t bnum = 0; bnum < device->block_count; bnum++) { + expected_pattern[0] = get_signature(bnum); + if (!is_valid_block(device, bnum, expected_pattern, sizeof(expected_pattern))) { + num_errors++; + } + } + + free(test_buffer); + + return num_errors; +} + +static status_t memory_mapped_test(bdev_t *device) +{ + status_t retcode = NO_ERROR; + + uint8_t *test_buffer = memalign(DMA_ALIGNMENT, device->block_size); + if (!test_buffer) { + printf("Could not allocate %zu bytes for a temporary buffer. " + "Aborting.\n", device->block_size); + return ERR_NO_MEMORY; + } + + uint8_t *reference_buffer = memalign(DMA_ALIGNMENT, device->block_size); + if (!reference_buffer) { + printf("Could not allocate %zu bytes for a temporary reference " + "buffer. Aborting.\n", device->block_size); + free(test_buffer); + return ERR_NO_MEMORY; + } + + // Erase the first page of the Device. + ssize_t err = bio_erase(device, 0, device->block_size); + if (err < (ssize_t)device->block_size) { + printf("Expected to erase at least %zu bytes but only erased %ld. " + "Not continuing to test memory mapped mode.\n", + device->block_size, err); + retcode = ERR_IO; + goto finish; + } + + // Write a pattern to the first page of the device. + uint8_t pattern_seed = (uint8_t)(rand() % 256); + + for (size_t i = 0; i < device->block_size; i++) { + test_buffer[i] = (uint8_t)((pattern_seed + i) % 256); + } + + err = bio_write_block(device, test_buffer, 0, 1); + if (err != (ssize_t)device->block_size) { + printf("Error while writing test pattern to device. Expected to write " + "%zu bytes but actually wrote %ld. Not continuing to test memory " + "mapped mode.\n", device->block_size, err); + retcode = ERR_IO; + goto finish; + } + + // Put the device into linear mode if possible. + uint8_t *devaddr; + int ioctl_result = bio_ioctl(device, BIO_IOCTL_GET_MEM_MAP, (void *)&devaddr); + if (ioctl_result == ERR_NOT_SUPPORTED) { + printf("Device does not support linear mode. Aborting.\n"); + retcode = ERR_NOT_SUPPORTED; + goto finish; + } else if (ioctl_result != NO_ERROR) { + printf("BIO_IOCTL_GET_MEM_MAP returned error %d. Aborting.\n", + ioctl_result); + retcode = ioctl_result; + goto finish; + } + + uint8_t *testptr = test_buffer; + for (uint i = 0; i < device->block_size; i++) { + if (*testptr != *devaddr) { + printf("Data mismatch at position %d. Expected %d got %d. " + "Aborting.\n", i, *testptr, *devaddr); + goto finish; + } + testptr++; + devaddr++; + } + + // Put the device back into command mode. + ioctl_result = bio_ioctl(device, BIO_IOCTL_PUT_MEM_MAP, NULL); + if (ioctl_result != NO_ERROR) { + printf("BIO_IOCTL_GET_MEM_MAP returned error %d. Aborting.\n", + ioctl_result); + retcode = ioctl_result; + goto finish; + } + + // Read the first page into memory using command mode and compare it with + // what we wrote back earlier. + err = bio_read_block(device, reference_buffer, 0, 1); + if (err != (ssize_t)device->block_size) { + printf("Expected to read %zu bytes, actually read %ld. Aborting.\n", + device->block_size, err); + retcode = ERR_IO; + goto finish; + } + + uint8_t *expected = test_buffer; + uint8_t *actual = reference_buffer; + for (uint i = 0; i < device->block_size; i++) { + if (*actual != *expected) { + printf("Data mismatch at position %d. Expected %d got %d. " + "Aborting.\n", i, *expected, *actual); + goto finish; + } + expected++; + actual++; + } + +finish: + free(test_buffer); + free(reference_buffer); + return retcode; +} + +static int bio_test_device(bdev_t *device) +{ + ssize_t num_errors = erase_test(device); + if (num_errors < 0) { + printf("error %ld performing erase test\n", num_errors); + return -1; + } + printf("discovered %ld error(s) while testing erase.\n", num_errors); + if (num_errors) { + // No point in continuing the tests if we couldn't erase the device. + printf("not continuing to test writes.\n"); + return -1; + } + + num_errors = write_test(device); + printf("Discovered %ld error(s) while testing write.\n", num_errors); + if (num_errors) { + return -1; + } + + printf ("Testing sub-erase...\n"); + bool success = sub_erase_test(device, SUB_ERASE_TEST_SAMPLES); + if (!success) { + printf("Discovered errors while testing sub-erase.\n"); + return -1; + } else { + printf("No errors while testing sub-erase.\n"); + } + + printf("Testing memory mapped mode...\n"); + status_t test_result = memory_mapped_test(device); + if (test_result != NO_ERROR) { + printf("Memory mapped test returned error %d\n", test_result); + } else { + printf("Memory mapped mode tests returned successfully\n"); + } + + return 0; +} diff --git a/kernel/lib/bio/include/lib/bio.h b/kernel/lib/bio/include/lib/bio.h new file mode 100644 index 000000000..c16805850 --- /dev/null +++ b/kernel/lib/bio/include/lib/bio.h @@ -0,0 +1,134 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS; + +#define BIO_FLAGS_NONE (0 << 0) +#define BIO_FLAG_CACHE_ALIGNED_READS (1 << 0) +#define BIO_FLAG_CACHE_ALIGNED_WRITES (1 << 1) + +typedef uint32_t bnum_t; + +typedef struct bio_erase_geometry_info { + off_t start; // start of the region in bytes. + off_t size; + size_t erase_size; + size_t erase_shift; +} bio_erase_geometry_info_t; + +typedef struct bdev { + struct list_node node; + volatile int ref; + + /* info about the block device */ + char *name; + off_t total_size; + + size_t block_size; + size_t block_shift; + bnum_t block_count; + + size_t geometry_count; + const bio_erase_geometry_info_t *geometry; + + uint8_t erase_byte; + + uint32_t flags; + + /* function pointers */ + ssize_t (*read)(struct bdev *, void *buf, off_t offset, size_t len); + ssize_t (*read_block)(struct bdev *, void *buf, bnum_t block, uint count); + ssize_t (*write)(struct bdev *, const void *buf, off_t offset, size_t len); + ssize_t (*write_block)(struct bdev *, const void *buf, bnum_t block, uint count); + ssize_t (*erase)(struct bdev *, off_t offset, size_t len); + int (*ioctl)(struct bdev *, int request, void *argp); + void (*close)(struct bdev *); +} bdev_t; + +/* user api */ +bdev_t *bio_open(const char *name); +void bio_close(bdev_t *dev); +ssize_t bio_read(bdev_t *dev, void *buf, off_t offset, size_t len); +ssize_t bio_read_block(bdev_t *dev, void *buf, bnum_t block, uint count); +ssize_t bio_write(bdev_t *dev, const void *buf, off_t offset, size_t len); +ssize_t bio_write_block(bdev_t *dev, const void *buf, bnum_t block, uint count); +ssize_t bio_erase(bdev_t *dev, off_t offset, size_t len); +int bio_ioctl(bdev_t *dev, int request, void *argp); + +/* register a block device */ +void bio_register_device(bdev_t *dev); +void bio_unregister_device(bdev_t *dev); + +/* used during bdev construction */ +void bio_initialize_bdev(bdev_t *dev, + const char *name, + size_t block_size, + bnum_t block_count, + size_t geometry_count, + const bio_erase_geometry_info_t *geometry, + const uint32_t flags); + +/* debug stuff */ +void bio_dump_devices(void); + +/* subdevice support */ +status_t bio_publish_subdevice(const char *parent_dev, + const char *subdev, + bnum_t startblock, + bnum_t block_count); + +/* memory based block device */ +int create_membdev(const char *name, void *ptr, size_t len); + +/* helper routine to trim an offset + len to the device */ +size_t bio_trim_range(const bdev_t *dev, off_t offset, size_t len); + +/* helper routine to trim to a block range in the device */ +uint bio_trim_block_range(const bdev_t *dev, bnum_t block, uint count); + +/* utility routine */ +static inline bool bio_does_overlap(uint64_t start1, uint64_t len1, + uint64_t start2, uint64_t len2) +{ + uint64_t end1 = start1 + len1; + uint64_t end2 = start2 + len2; + + DEBUG_ASSERT(end1 >= start1); + DEBUG_ASSERT(end2 >= start2); + + return (((start1 >= start2) && (start1 < end2)) || + ((start2 >= start1) && (start2 < end1))); +} + +static inline bool bio_contains_range(uint64_t container_start, uint64_t container_len, + uint64_t contained_start, uint64_t contained_len) +{ + uint64_t container_end = container_start + container_len; + uint64_t contained_end = contained_start + contained_len; + + DEBUG_ASSERT(container_end >= container_start); + DEBUG_ASSERT(contained_end >= contained_start); + + return ((container_start <= contained_start) && + (container_end >= contained_end)); +} + +/* generic bio ioctls */ +enum bio_ioctl_num { + BIO_IOCTL_NULL = 0, + BIO_IOCTL_GET_MEM_MAP, /* if supported, request a pointer to the memory map of the device */ + BIO_IOCTL_PUT_MEM_MAP, /* if needed, return the pointer (to 'close' the map) */ + BIO_IOCTL_GET_MAP_ADDR, /* if supported, request a pointer to the memory map without putting the device into linear mode */ +}; + +__END_CDECLS; \ No newline at end of file diff --git a/kernel/lib/bio/mem.c b/kernel/lib/bio/mem.c new file mode 100644 index 000000000..ca74d6c4e --- /dev/null +++ b/kernel/lib/bio/mem.c @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define BLOCKSIZE 512 + +typedef struct mem_bdev { + bdev_t dev; // base device + + void *ptr; +} mem_bdev_t; + +static ssize_t mem_bdev_read(bdev_t *bdev, void *buf, off_t offset, size_t len) +{ + mem_bdev_t *mem = (mem_bdev_t *)bdev; + + LTRACEF("bdev %s, buf %p, offset %lld, len %zu\n", bdev->name, buf, offset, len); + + // TODO: This is a hack, we should get rid of it when we have a real loader + if (is_user_address((vaddr_t)buf)) { + status_t status = copy_to_user(buf, (uint8_t *)mem->ptr + offset, len); + if (status != NO_ERROR) { + return status; + } + } else { + memcpy(buf, mem->ptr + offset, len); + } + + return len; +} + +static ssize_t mem_bdev_read_block(struct bdev *bdev, void *buf, bnum_t block, uint count) +{ + mem_bdev_t *mem = (mem_bdev_t *)bdev; + + LTRACEF("bdev %s, buf %p, block %u, count %u\n", bdev->name, buf, block, count); + + status_t status = copy_to_user( + buf, + (uint8_t *)mem->ptr + block * BLOCKSIZE, + count * BLOCKSIZE); + if (status != NO_ERROR) { + return status; + } + + return count * BLOCKSIZE; +} + +static ssize_t mem_bdev_write(bdev_t *bdev, const void *buf, off_t offset, size_t len) +{ + mem_bdev_t *mem = (mem_bdev_t *)bdev; + + LTRACEF("bdev %s, buf %p, offset %lld, len %zu\n", bdev->name, buf, offset, len); + + memcpy((uint8_t *)mem->ptr + offset, buf, len); + + return len; +} + +static ssize_t mem_bdev_write_block(struct bdev *bdev, const void *buf, bnum_t block, uint count) +{ + mem_bdev_t *mem = (mem_bdev_t *)bdev; + + LTRACEF("bdev %s, buf %p, block %u, count %u\n", bdev->name, buf, block, count); + + memcpy((uint8_t *)mem->ptr + block * BLOCKSIZE, buf, count * BLOCKSIZE); + + return count * BLOCKSIZE; +} + +int create_membdev(const char *name, void *ptr, size_t len) +{ + mem_bdev_t *mem = malloc(sizeof(mem_bdev_t)); + + /* set up the base device */ + bio_initialize_bdev(&mem->dev, name, BLOCKSIZE, len / BLOCKSIZE, 0, NULL, + BIO_FLAGS_NONE); + + /* our bits */ + mem->ptr = ptr; + mem->dev.read = mem_bdev_read; + mem->dev.read_block = mem_bdev_read_block; + mem->dev.write = mem_bdev_write; + mem->dev.write_block = mem_bdev_write_block; + + /* register it */ + bio_register_device(&mem->dev); + + return 0; +} + diff --git a/kernel/lib/bio/rules.mk b/kernel/lib/bio/rules.mk new file mode 100644 index 000000000..133a0deb5 --- /dev/null +++ b/kernel/lib/bio/rules.mk @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/bio.c \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/mem.c \ + $(LOCAL_DIR)/subdev.c + +MODULE_DEPS := \ + lib/user_copy \ + +include make/module.mk diff --git a/kernel/lib/bio/subdev.c b/kernel/lib/bio/subdev.c new file mode 100644 index 000000000..5b48b8105 --- /dev/null +++ b/kernel/lib/bio/subdev.c @@ -0,0 +1,183 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +typedef struct { + // inheirit the usual bits + bdev_t dev; + + // we're a subdevice of this + bdev_t *parent; + + // Storage for our erase geometry info. Subdevices are only permitted to + // have homogeneous erase geometry. + bio_erase_geometry_info_t geometry; + + // we're this many blocks into it + bnum_t offset; +} subdev_t; + +static ssize_t subdev_read(struct bdev *_dev, void *buf, off_t offset, size_t len) +{ + subdev_t *subdev = (subdev_t *)_dev; + + return bio_read(subdev->parent, buf, offset + subdev->offset * subdev->dev.block_size, len); +} + +static ssize_t subdev_read_block(struct bdev *_dev, void *buf, bnum_t block, uint count) +{ + subdev_t *subdev = (subdev_t *)_dev; + + return bio_read_block(subdev->parent, buf, block + subdev->offset, count); +} + +static ssize_t subdev_write(struct bdev *_dev, const void *buf, off_t offset, size_t len) +{ + subdev_t *subdev = (subdev_t *)_dev; + + return bio_write(subdev->parent, buf, offset + subdev->offset * subdev->dev.block_size, len); +} + +static ssize_t subdev_write_block(struct bdev *_dev, const void *buf, bnum_t block, uint count) +{ + subdev_t *subdev = (subdev_t *)_dev; + + return bio_write_block(subdev->parent, buf, block + subdev->offset, count); +} + +static ssize_t subdev_erase(struct bdev *_dev, off_t offset, size_t len) +{ + subdev_t *subdev = (subdev_t *)_dev; + + return bio_erase(subdev->parent, offset + subdev->offset * subdev->dev.block_size, len); +} + +static void subdev_close(struct bdev *_dev) +{ + subdev_t *subdev = (subdev_t *)_dev; + + bio_close(subdev->parent); + subdev->parent = NULL; +} + +#define BAIL(__err) do { err = __err; goto bailout; } while (0) +status_t bio_publish_subdevice(const char *parent_dev, + const char *subdev, + bnum_t startblock, + bnum_t block_count) +{ + status_t err = NO_ERROR; + bdev_t *parent = NULL; + subdev_t *sub = NULL; + size_t geometry_count; + bio_erase_geometry_info_t *geometry; + + LTRACEF("parent \"%s\", sub \"%s\", startblock %u, count %u\n", parent_dev, subdev, startblock, block_count); + + // Make sure our parent exists + parent = bio_open(parent_dev); + if (!parent) { + LTRACEF("Failed to find parent \"%s\"\n", parent_dev); + BAIL(ERR_NOT_FOUND); + } + + // Allocate our sub-device. + sub = malloc(sizeof(subdev_t)); + if (!sub) { + LTRACEF("Failed to allocate subdevice\n"); + BAIL(ERR_NO_MEMORY); + } + + /* Make sure we're able to do this. If the device has a specified erase + * geometry, the specified sub-region must exist entirely with one of our + * parent's erase regions, and be aligned to an erase unit boundary. + * Otherwise, the specified region must simply exist within the block range + * of the device. + */ + if (parent->geometry_count && parent->geometry) { + uint64_t byte_start = ((uint64_t)startblock << parent->block_shift); + uint64_t byte_size = ((uint64_t)block_count << parent->block_shift); + const bio_erase_geometry_info_t *geo = NULL; + + LTRACEF("Searching geometry for region which contains @[0x%llx, 0x%llx)\n", + byte_start, byte_start + byte_size); + + // Start by finding the erase region which completely contains the requested range. + for (size_t i = 0; i < parent->geometry_count; ++i) { + geo = parent->geometry + i; + + LTRACEF("Checking geometry @[0x%llx, 0x%llx) erase size 0x%zx\n", + geo->start, + geo->start + geo->size, + geo->erase_size); + + if (bio_contains_range(geo->start, geo->size, byte_start, byte_size)) + break; + } + + if (!geo) { + LTRACEF("No suitable erase region found\n"); + BAIL(ERR_INVALID_ARGS); + } + + // Now check out alignment. + uint64_t erase_mask = ((uint64_t)0x1 << geo->erase_shift) - 1; + if ((byte_start & erase_mask) || (byte_size & erase_mask)) { + LTRACEF("Requested region has improper alignment/length\n"); + BAIL(ERR_INVALID_ARGS); + } + + geometry_count = 1; + geometry = &sub->geometry; + + geometry->start = 0; + geometry->size = byte_size; + geometry->erase_size = geo->erase_size; + geometry->erase_shift = geo->erase_shift; + } else { + bnum_t endblock = startblock + block_count; + + if ((endblock < startblock) || (endblock > parent->block_count)) + BAIL(ERR_INVALID_ARGS); + + geometry_count = 0; + geometry = NULL; + } + + bio_initialize_bdev(&sub->dev, subdev, + parent->block_size, block_count, + geometry_count, geometry, BIO_FLAGS_NONE); + + sub->parent = parent; + sub->offset = startblock; + + sub->dev.read = &subdev_read; + sub->dev.read_block = &subdev_read_block; + sub->dev.write = &subdev_write; + sub->dev.write_block = &subdev_write_block; + sub->dev.erase = &subdev_erase; + sub->dev.close = &subdev_close; + + bio_register_device(&sub->dev); + +bailout: + if (err < 0) { + if (NULL != parent) + bio_close(parent); + free(sub); + } + + return err; +} +#undef BAIL diff --git a/kernel/lib/bootargs/BUILD.gn b/kernel/lib/bootargs/BUILD.gn new file mode 100644 index 000000000..1b2ed1de0 --- /dev/null +++ b/kernel/lib/bootargs/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_bootargs_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("bootargs") { + public_configs = [ ":_bootargs_config" ] + configs += [ "//kernel/kernel:enable_vm" ] + public = [ + "include/lib/bootargs.h", + ] + sources = [ + "bootargs.c", + ] +} diff --git a/kernel/lib/bootargs/bootargs.c b/kernel/lib/bootargs/bootargs.c new file mode 100644 index 000000000..8a8e4b0f5 --- /dev/null +++ b/kernel/lib/bootargs/bootargs.c @@ -0,0 +1,233 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include + +#if WITH_KERNEL_VM +#include +#endif + +#define LOCAL_TRACE 0 + +/* saved by the main entry point in lk */ +extern ulong lk_boot_args[4]; + +static bool boot_args_valid = false; +static struct lk_boot_arg *boot_args; + +#define LK_BOOT_ARG_MAGIC 'lkbt' + +/* lk style boot args are spread across the 4 incoming argument pointers as follows: + * + * [0] = LK_BOOT_ARG_MAGIC + * [1] = pointer to lk_boot_arg list + * [2] = unused + * [3] = xor of ULONG_MAX and the previous 3 + */ + +#define LK_BOOT_ARG_TYPE_INITIAL 'args' +#define LK_BOOT_ARG_TYPE_COMMAND_LINE 'cmdl' +#define LK_BOOT_ARG_TYPE_BOOTIMAGE 'bimg' +#define LK_BOOT_ARG_TYPE_END 0 + +struct lk_boot_arg { + uint32_t type; + uint32_t len; + + uint8_t data[]; +}; + +struct lk_boot_arg_bootimage { + uint64_t offset; + size_t len; + + char device[]; +}; + +static void *find_end(void *buf, size_t buf_len) +{ + uint8_t *ptr = (uint8_t *)buf; + struct lk_boot_arg *arg = (struct lk_boot_arg *)ptr; + + while (arg->type != LK_BOOT_ARG_TYPE_END) { + ptr += sizeof(struct lk_boot_arg) + arg->len; + + if ((uintptr_t)ptr - (uintptr_t)buf > buf_len) + return NULL; + + arg = (struct lk_boot_arg *)ptr; + } + + return ptr; +} + +status_t bootargs_start(void *buf, size_t buf_len) +{ + if (buf_len < sizeof(struct lk_boot_arg)) + return ERR_NO_MEMORY; + + memset(buf, 0, buf_len); + + struct lk_boot_arg *arg = (struct lk_boot_arg *)buf; + arg->type = LK_BOOT_ARG_TYPE_INITIAL; + arg->len = 0; + + return NO_ERROR; +} + +status_t bootargs_add_command_line(void *buf, size_t buf_len, const char *str) +{ + struct lk_boot_arg *arg = find_end(buf, buf_len); + if (!arg) + return ERR_NO_MEMORY; + + arg->type = LK_BOOT_ARG_TYPE_COMMAND_LINE; + arg->len = ROUNDUP(strlen(str) + 1, 4); + memset(arg->data, 0, arg->len); + strcpy((char *)arg->data, str); + + return NO_ERROR; +} + +status_t bootargs_add_bootimage_pointer(void *buf, size_t buf_len, const char *device, uint64_t offset, size_t len) +{ + struct lk_boot_arg *arg = find_end(buf, buf_len); + if (!arg) + return ERR_NO_MEMORY; + + arg->type = LK_BOOT_ARG_TYPE_BOOTIMAGE; + size_t string_len = device ? ROUNDUP(strlen(device) + 1, 4) : 0; + arg->len = string_len + sizeof(struct lk_boot_arg_bootimage); + + struct lk_boot_arg_bootimage *bi = (struct lk_boot_arg_bootimage *)arg->data; + + bi->offset = offset; + bi->len = len; + if (device) { + memset(bi->device, 0, string_len); + strcpy(bi->device, device); + } + + return NO_ERROR; +} + +void bootargs_generate_lk_arg_values(ulong buf, ulong args[4]) +{ + args[0] = LK_BOOT_ARG_MAGIC; + args[1] = buf; + args[2] = 0; + args[3] = ULONG_MAX ^ args[0] ^ args[1] ^ args[2]; +} + +static void bootargs_init_hook(uint level) +{ + LTRACE_ENTRY; + + /* see if there are any lk style boot arguments here */ + if (lk_boot_args[0] != LK_BOOT_ARG_MAGIC) { + LTRACEF("failed magic check\n"); + return; + } + + if (lk_boot_args[3] != (ULONG_MAX ^ lk_boot_args[0] ^ lk_boot_args[1] ^ lk_boot_args[2])) { + LTRACEF("failed checksum\n"); + return; + } + + /* parse the boot arg pointer */ +#if WITH_KERNEL_VM + boot_args = paddr_to_kvaddr(lk_boot_args[1]); +#else + boot_args = (void *)lk_boot_args[1]; +#endif + + if (!boot_args) { + LTRACEF("null or invalid boot pointer\n"); + return; + } + + /* see if the initial entry is the right one */ + if (boot_args[0].type != LK_BOOT_ARG_TYPE_INITIAL) { + LTRACEF("bad initial arg\n"); + return; + } + + /* looks good */ + boot_args_valid = true; + + LTRACEF("valid args found\n"); +} + +bool bootargs_are_valid(void) +{ + return boot_args_valid; +} + +static struct lk_boot_arg *find_tag(uint32_t tag) +{ + if (!boot_args_valid) + return NULL; + + struct lk_boot_arg *arg = boot_args; + + while (arg->type != LK_BOOT_ARG_TYPE_END) { + if (arg->type == tag) + return arg; + + arg = (struct lk_boot_arg *)((uintptr_t)arg + sizeof(struct lk_boot_arg) + arg->len); + } + + return NULL; +} + +const char *bootargs_get_command_line(void) +{ + struct lk_boot_arg *arg = find_tag(LK_BOOT_ARG_TYPE_COMMAND_LINE); + if (!arg) + return NULL; + + // XXX validate it + + return (const char *)arg->data; +} + +status_t bootargs_get_bootimage_pointer(uint64_t *offset, size_t *len, const char **device) +{ + struct lk_boot_arg *arg = find_tag(LK_BOOT_ARG_TYPE_BOOTIMAGE); + if (!arg) + return ERR_NOT_FOUND; + + // XXX validate it + + struct lk_boot_arg_bootimage *bi = (struct lk_boot_arg_bootimage *)arg->data; + + if (device) { + if (arg->len != sizeof(struct lk_boot_arg_bootimage)) { + /* string is present */ + *device = bi->device; + } else { + *device = NULL; + } + } + + if (offset) + *offset = bi->offset; + if (len) + *len = bi->len; + + return NO_ERROR; +} + +LK_INIT_HOOK(bootargs, bootargs_init_hook, LK_INIT_LEVEL_THREADING); + diff --git a/kernel/lib/bootargs/include/lib/bootargs.h b/kernel/lib/bootargs/include/lib/bootargs.h new file mode 100644 index 000000000..7898e8970 --- /dev/null +++ b/kernel/lib/bootargs/include/lib/bootargs.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +/* recovering boot arguments that were passed */ +bool bootargs_are_valid(void); +const char *bootargs_get_command_line(void); +status_t bootargs_get_bootimage_pointer(uint64_t *offset, size_t *len, const char **device); + +/* constructing boot arguments */ +status_t bootargs_start(void *buf, size_t buf_len); +status_t bootargs_add_command_line(void *buf, size_t buf_len, const char *str); +status_t bootargs_add_bootimage_pointer(void *buf, size_t buf_len, const char *device, uint64_t offset, size_t len); + +/* build 4 ulong arguments to pass to a second stage */ +void bootargs_generate_lk_arg_values(ulong buf, ulong args[4]); + diff --git a/kernel/lib/bootargs/rules.mk b/kernel/lib/bootargs/rules.mk new file mode 100644 index 000000000..ecd46f524 --- /dev/null +++ b/kernel/lib/bootargs/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + +MODULE_SRCS := \ + $(LOCAL_DIR)/bootargs.c + +include make/module.mk diff --git a/kernel/lib/bootfs/BUILD.gn b/kernel/lib/bootfs/BUILD.gn new file mode 100644 index 000000000..f0c79d8d5 --- /dev/null +++ b/kernel/lib/bootfs/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_bootfs_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("bootfs") { + public_configs = [ ":_bootfs_config" ] + public = [ + "include/lib/bootfs.h", + ] + sources = [ + "bootfs.c", + ] + deps = [ + "//kernel/lib/bio", + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/bootfs/bootfs.c b/kernel/lib/bootfs/bootfs.c new file mode 100644 index 000000000..f9115d45a --- /dev/null +++ b/kernel/lib/bootfs/bootfs.c @@ -0,0 +1,107 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +static const char FSMAGIC[16] = "[BOOTFS]\0\0\0\0\0\0\0\0"; + +// BOOTFS is a trivial "filesystem" format +// +// It has a 16 byte magic/version value (FSMAGIC) +// Followed by a series of records of: +// namelength (32bit le) +// filesize (32bit le) +// fileoffset (32bit le) +// namedata (namelength bytes, includes \0) +// +// - fileoffsets must be page aligned (multiple of 4096) + +#define NLEN 0 +#define FSIZ 1 +#define FOFF 2 + +int bootfs_parse_bio(bdev_t *bdev, uint64_t offset, struct list_node *list) { + char buf[16]; + ssize_t err; + + err = bio_read(bdev, buf, offset, sizeof(FSMAGIC)); + if (err < (ssize_t)sizeof(FSMAGIC)) { + return ERR_INVALID_ARGS; + } + if (memcmp(buf, FSMAGIC, sizeof(FSMAGIC))) { + LTRACEF("bootfs: bad magic\n"); + return ERR_INVALID_ARGS; + } + offset += sizeof(FSMAGIC); + + int found = 0; + while (offset < (uint64_t)bdev->total_size) { + uint32_t header[3]; + + err = bio_read(bdev, &header, offset, sizeof(header)); + if (err < (ssize_t)sizeof(header)) { + break; + } + offset += sizeof(header); + + // dump the header + LTRACEF("bootfs: %d: namesize=%u filesize=%u offset=%u\n", + found, header[NLEN], header[FSIZ], header[FOFF]); + + // check for end marker + if (header[NLEN] == 0) break; + + // require reasonable filename size + if ((header[NLEN] < 2) || (header[NLEN] > BOOTFS_MAX_NAME_LEN)) { + dprintf(INFO, "bootfs: %d: bogus filename length\n", found); + break; + } + + // require correct alignment + if (header[FOFF] & 4095) { + dprintf(INFO, "bootfs: %d: badly aligned offset\n", found); + break; + } + + struct bootfs_file *file = malloc(sizeof(*file) + header[NLEN]); + if (!file) break; + + err = bio_read(bdev, file->name, offset, header[NLEN]); + if (err < (ssize_t)header[NLEN]) { + free(file); + break; + } + offset += header[NLEN]; + + // last byte must be a \0, ensure that is true + file->name[header[NLEN] - 1] = 0; + + // save the offset and length of the file + file->offset = header[FOFF]; + file->len = header[FSIZ]; + file->bdev = bdev; + + // add this file to the list we're returning + list_add_tail(list, &file->node); + found++; + } + + return found; +} + + + diff --git a/kernel/lib/bootfs/include/lib/bootfs.h b/kernel/lib/bootfs/include/lib/bootfs.h new file mode 100644 index 000000000..3ebc0ba83 --- /dev/null +++ b/kernel/lib/bootfs/include/lib/bootfs.h @@ -0,0 +1,30 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +__BEGIN_CDECLS + +#define BOOTFS_MAX_NAME_LEN 256 + +struct bootfs_file { + struct list_node node; + + uint64_t offset; + uint64_t len; + bdev_t* bdev; + + char name[0]; +}; + +/* parse a bootfs archive off of a block device */ +/* returns the number of files added to the list, or error */ +int bootfs_parse_bio(bdev_t* bdev, uint64_t offset, struct list_node* list) __NONNULL((1)) __NONNULL((3)); + +__END_CDECLS diff --git a/kernel/lib/bootfs/rules.mk b/kernel/lib/bootfs/rules.mk new file mode 100644 index 000000000..a3b98ff5b --- /dev/null +++ b/kernel/lib/bootfs/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/bootfs.c + +MODULE_DEPS += \ + lib/bio + +include make/module.mk diff --git a/kernel/lib/bootimage/BUILD.gn b/kernel/lib/bootimage/BUILD.gn new file mode 100644 index 000000000..7e4db01ba --- /dev/null +++ b/kernel/lib/bootimage/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_bootimage_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("bootimage") { + public_configs = [ ":_bootimage_config" ] + public = [ + "include/lib/bootimage.h", + "include/lib/bootimage_struct.h", + ] + sources = [ + "bootimage.c", + ] + deps = [ + "//kernel/lib/mincrypt", + ] +} diff --git a/kernel/lib/bootimage/bootimage.c b/kernel/lib/bootimage/bootimage.c new file mode 100644 index 000000000..1db2c098d --- /dev/null +++ b/kernel/lib/bootimage/bootimage.c @@ -0,0 +1,208 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LOCAL_TRACE 1 + +struct bootimage { + const uint8_t *ptr; + size_t len; +}; + +static status_t validate_bootimage(bootimage_t *bi) +{ + if (!bi) + return ERR_INVALID_ARGS; + + /* is it large enough to hold the first entry */ + if (bi->len < 4096) { + LTRACEF("bootentry too short\n"); + return ERR_BAD_LEN; + } + + bootentry *be = (bootentry *)bi->ptr; + + /* check that the first entry is a file, type boot info, and is 4096 bytes at offset 0 */ + if (be->kind != KIND_FILE || + be->file.type != TYPE_BOOT_IMAGE || + be->file.offset != 0 || + be->file.length != 4096 || + memcmp(be->file.name, BOOT_MAGIC, sizeof(be->file.name))) { + LTRACEF("invalid first entry\n"); + return ERR_INVALID_ARGS; + } + + /* check the sha256 of the rest of the first page */ + SHA256_CTX ctx; + SHA256_init(&ctx); + + SHA256_update(&ctx, be + 1, 4096 - sizeof(bootentry)); + const uint8_t *hash = SHA256_final(&ctx); + + if (memcmp(hash, be->file.sha256, sizeof(be->file.sha256)) != 0) { + LTRACEF("bad hash of first section\n"); + + return ERR_CHECKSUM_FAIL; + } + + /* look at the second entry, which should be a boot info structure */ + if (be[1].kind != KIND_BOOT_INFO) { + LTRACEF("second entry not boot info\n"); + return ERR_INVALID_ARGS; + } + + bootentry_info *info = &be[1].info; + + /* is the image a handled version */ + if (info->version > BOOT_VERSION) { + LTRACEF("unhandled version 0x%x\n", info->version); + return ERR_INVALID_ARGS; + } + + /* is the image the right size? */ + if (info->image_size > bi->len) { + LTRACEF("boot image block says image is too big (0x%x bytes)\n", info->image_size); + return ERR_INVALID_ARGS; + } + + /* trim the len to what the info block says */ + bi->len = info->image_size; + + /* iterate over the remaining entries in the list */ + for (size_t i = 2; i < info->entry_count; i++) { + if (be[i].kind == 0) + break; + + LTRACEF("%u: kind 0x%x\n", i, be[i].kind); + + switch (be[i].kind) { + case KIND_BOOT_INFO: + break; + case KIND_BOARD: + break; + case KIND_BUILD: + break; + case KIND_FILE: { + LTRACEF("\ttype %c%c%c%c offset 0x%x, length 0x%x\n", + (be[i].file.type >> 0) & 0xff, (be[i].file.type >> 8) & 0xff, + (be[i].file.type >> 16) & 0xff, (be[i].file.type >> 24) & 0xff, + be[i].file.offset, be[i].file.length); + + /* check that the file section is inside the overall image */ + uint32_t end = be[i].file.offset + be[i].file.length; + if (end < be[i].file.offset || end > info->image_size) { + LTRACEF("bad file section, size too large\n"); + return ERR_INVALID_ARGS; + } + + /* check the sha256 hash */ + SHA256_init(&ctx); + + LTRACEF("\tvalidating SHA256 hash\n"); + SHA256_update(&ctx, (const uint8_t *)bi->ptr + be[i].file.offset, be[i].file.length); + const uint8_t *hash = SHA256_final(&ctx); + + if (memcmp(hash, be[i].file.sha256, sizeof(be[i].file.sha256)) != 0) { + LTRACEF("bad hash of file section\n"); + + return ERR_CHECKSUM_FAIL; + } + + break; + } + default: + LTRACEF("unknown kind 0x%x\n", be[i].kind); + return ERR_INVALID_ARGS; + } + } + + LTRACEF("image good\n"); + return NO_ERROR; +} + +status_t bootimage_open(const void *ptr, size_t len, bootimage_t **bi) +{ + LTRACEF("ptr %p, len %zu\n", ptr, len); + + if (!bi) + return ERR_INVALID_ARGS; + + *bi = calloc(1, sizeof(bootimage_t)); + if (!*bi) + return ERR_NO_MEMORY; + + (*bi)->ptr = ptr; + (*bi)->len = len; + + /* try to validate it */ + status_t err = validate_bootimage(*bi); + if (err < 0) { + bootimage_close(*bi); + return err; + } + + return NO_ERROR; +} + +status_t bootimage_close(bootimage_t *bi) +{ + if (bi) + free(bi); + + return NO_ERROR; +} + +status_t bootimage_get_range(bootimage_t *bi, const void **ptr, size_t *len) +{ + if (!bi) + return ERR_INVALID_ARGS; + + if (ptr) + *ptr = bi->ptr; + if (len) + *len = bi->len; + + return NO_ERROR; +} + +status_t bootimage_get_file_section(bootimage_t *bi, uint32_t type, const void **ptr, size_t *len) +{ + if (!bi) + return ERR_INVALID_ARGS; + + bootentry *be = (bootentry *)bi->ptr; + bootentry_info *info = &be[1].info; + + for (size_t i = 2; i < info->entry_count; i++) { + if (be[i].kind == 0) + break; + + if (be[i].kind != KIND_FILE) + continue; + + if (type == be[i].file.type) { + if (ptr) + *ptr = bi->ptr + be[i].file.offset; + if (len) + *len = be[i].file.length; + return NO_ERROR; + } + } + + return ERR_NOT_FOUND; +} + diff --git a/kernel/lib/bootimage/include/lib/bootimage.h b/kernel/lib/bootimage/include/lib/bootimage.h new file mode 100644 index 000000000..0807a99bc --- /dev/null +++ b/kernel/lib/bootimage/include/lib/bootimage.h @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +typedef struct bootimage bootimage_t; + +status_t bootimage_open(const void *ptr, size_t len, bootimage_t **bi) __NONNULL(); +status_t bootimage_close(bootimage_t *bi) __NONNULL(); +status_t bootimage_get_range(bootimage_t *bi, const void **ptr, size_t *len) __NONNULL((1)); + +/* ask for a file section of the bootimage, by type */ +status_t bootimage_get_file_section(bootimage_t *bi, uint32_t type, const void **ptr, size_t *len) __NONNULL((1)); + diff --git a/kernel/lib/bootimage/include/lib/bootimage_struct.h b/kernel/lib/bootimage/include/lib/bootimage_struct.h new file mode 100644 index 000000000..c06edf920 --- /dev/null +++ b/kernel/lib/bootimage/include/lib/bootimage_struct.h @@ -0,0 +1,79 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Brian Swetland +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include + +typedef struct { + uint32_t kind; + uint32_t type; + uint32_t offset; /* byte offset from start of file */ + uint32_t length; /* length in bytes */ + uint8_t name[16]; + uint8_t sha256[32]; +} __attribute__ ((packed)) bootentry_file; + +typedef struct { + uint32_t kind; + union { + uint32_t u[15]; + uint8_t b[60]; + } __attribute__((packed)) u; +} __attribute__((packed)) bootentry_data; + +typedef struct { + uint32_t kind; + uint32_t version; /* bootimage version */ + uint32_t image_size; /* byte size of entire image */ + uint32_t entry_count; /* number of valid bootentries */ + uint32_t reserved[12]; +} __attribute__((packed)) bootentry_info; + +typedef union { + uint32_t kind; + bootentry_file file; + bootentry_data data; + bootentry_info info; +} bootentry; + +#define BOOT_VERSION 0x00010000 /* 1.0 */ + +#define BOOT_MAGIC "" +#define BOOT_MAGIC_LENGTH 16 + +// header (bootentry_file, but special): + +// bootentry kinds: +#define KIND_FILE 0x656c6966 // 'file' +#define KIND_BOOT_INFO 0x6f666e69 // 'info' +#define KIND_BOARD 0x67726174 // 'targ' board id string +#define KIND_BUILD 0x706d7473 // 'stmp' build id string + +// bootentry_file types: +#define TYPE_BOOT_IMAGE 0x746f6f62 // 'boot' +#define TYPE_LK 0x6b6c6b6c // 'lklk' +#define TYPE_FPGA_IMAGE 0x61677066 // 'fpga' +#define TYPE_LINUX_KERNEL 0x6b78636c // 'lcxk' +#define TYPE_LINUX_INITRD 0x64697264 // 'drid' +#define TYPE_DEVICE_TREE 0x74766564 // 'devt' +#define TYPE_SYSPARAMS 0x70737973 // 'sysp' +#define TYPE_UNKNOWN 0x6e6b6e75 // 'unkn' + +// first entry must be: +// kind: KIND_FILE +// type: TYPE_BOOT_IMAGE +// offset: 0 +// length: 4096 +// name: BOOT_MAGIC +// sha256: of bootentry[1..63] + +// second entry must be: +// kind: KIND_BOOT_INFO + +// offsets should be multiple-of-4096 diff --git a/kernel/lib/bootimage/rules.mk b/kernel/lib/bootimage/rules.mk new file mode 100644 index 000000000..5b1339431 --- /dev/null +++ b/kernel/lib/bootimage/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/mincrypt + +MODULE_SRCS := \ + $(LOCAL_DIR)/bootimage.c + +include make/module.mk diff --git a/kernel/lib/buildsig/BUILD.gn b/kernel/lib/buildsig/BUILD.gn new file mode 100644 index 000000000..74a7433a2 --- /dev/null +++ b/kernel/lib/buildsig/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_buildsig_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("buildsig") { + public_configs = [ ":_buildsig_config" ] + public = [ + "include/lib/buildsig.h", + ] + sources = [ + "buildsig.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/version", + ] +} diff --git a/kernel/lib/buildsig/buildsig.c b/kernel/lib/buildsig/buildsig.c new file mode 100644 index 000000000..b76c27345 --- /dev/null +++ b/kernel/lib/buildsig/buildsig.c @@ -0,0 +1,146 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAGIC ((uint32_t)'BSIG') +#define MAGIC2 (~MAGIC) +#define MAGIC3 ((uint32_t)'BSG2') + +struct buildsig { + uint32_t magic; + + const lk_version_t *version; + + uint32_t magic2; + + uint32_t buildtype; + uint32_t start; + uint32_t end; + uint32_t crc32; + + uint32_t magic3; +}; + +extern char __rom_start; +extern char __rom_end; + +const struct buildsig buildsig __SECTION(".text.boot") = { + .magic = MAGIC, + .version = &version, + .magic2 = MAGIC2, +#if WITH_APP_BOOTLOADER + .buildtype = 1, /* TODO: pull from systemwide headers */ +#else + .buildtype = 0, +#endif + .start = (uint32_t) &__rom_start, + .end = (uint32_t) &__rom_end, + .crc32 = 0, /* filled in via an external tool */ + .magic3 = MAGIC3 +}; + +status_t buildsig_search(const void *_ptr, size_t search_len, size_t max_len, const lk_version_t **version) +{ + if (max_len < search_len) + return ERR_INVALID_ARGS; + + if (max_len < sizeof(lk_version_t)) + return ERR_INVALID_ARGS; + + /* search for the build signature on 4 byte boundaries */ + const uint32_t *ptr = _ptr; + for (size_t pos = 0; pos < search_len / 4; pos++) { + const struct buildsig *sig = (void *)&ptr[pos]; + + /* see if the buildsig's magic matches */ + if (sig->magic != MAGIC || sig->magic2 != MAGIC2) + continue; + + /* make sure the pointer to the version struct makes sense */ + if ((size_t)sig->version - (size_t)ptr > max_len - sizeof(lk_version_t)) + continue; + + /* validate the strings in the version struct make sense */ + /* ensure they lie within the search area (ptr .. ptr+max_len) */ +#define VALIDSTR(str) \ + (((size_t)(str) >= (size_t)ptr) && (((size_t)(str) - (size_t)ptr) < max_len)) + if (!VALIDSTR(sig->version->arch)) + continue; + if (!VALIDSTR(sig->version->platform)) + continue; + if (!VALIDSTR(sig->version->target)) + continue; + if (!VALIDSTR(sig->version->project)) + continue; + if (!VALIDSTR(sig->version->buildid)) + continue; +#undef VALIDSTR + + *version = sig->version; + return NO_ERROR; + } + + return ERR_NOT_FOUND; +} + +#if WITH_LIB_CONSOLE + +#include + +extern char __rom_start; + +static int cmd_buildsig(int argc, const cmd_args *argv) +{ + if (argc < 2) { +//notenoughargs: + printf("not enough args\n"); +usage: + printf("usage: %s dump [offset]\n", argv[0].str); + return -1; + } + + if (!strcmp(argv[1].str, "dump")) { + const void *offset = &__rom_start; + if (argc >= 3) { + offset = argv[2].p; + } + + const lk_version_t *v; + status_t err = buildsig_search(offset, DEFAULT_BUILDSIG_SEARCH_LEN, 256*1024, &v); + if (err < 0) { + printf("could not find build signature\n"); + return ERR_NOT_FOUND; + } + + printf("found signature:\n"); + printf("\tarch: %s\n\tplatform: %s\n\ttarget: %s\n\tproject: %s\n\tbuildid: %s\n", + v->arch, v->platform, v->target, v->project, v->buildid); + } else { + goto usage; + } + + return NO_ERROR; +} + + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND("buildsig", "scan for and dump build signature", &cmd_buildsig) +#endif +STATIC_COMMAND_END(buildid); + +#endif + diff --git a/kernel/lib/buildsig/include/lib/buildsig.h b/kernel/lib/buildsig/include/lib/buildsig.h new file mode 100644 index 000000000..331efa8cd --- /dev/null +++ b/kernel/lib/buildsig/include/lib/buildsig.h @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_BUILDSIG_H +#define __LIB_BUILDSIG_H + +#include +#include +#include + +/* routines for searching for and finding a build signature */ +status_t buildsig_search(const void *ptr, size_t search_len, size_t max_len, + const lk_version_t **version); + +#define DEFAULT_BUILDSIG_SEARCH_LEN 1024 + +#endif + diff --git a/kernel/lib/buildsig/rules.mk b/kernel/lib/buildsig/rules.mk new file mode 100644 index 000000000..ba06369ab --- /dev/null +++ b/kernel/lib/buildsig/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/version + +MODULE_SRCS := \ + $(LOCAL_DIR)/buildsig.c + +include make/module.mk diff --git a/kernel/lib/bytes/BUILD.gn b/kernel/lib/bytes/BUILD.gn new file mode 100644 index 000000000..5bd99ecd9 --- /dev/null +++ b/kernel/lib/bytes/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("bytes") { + sources = [ + "bytes.c", + ] +} diff --git a/kernel/lib/bytes/bytes.c b/kernel/lib/bytes/bytes.c new file mode 100644 index 000000000..83499173f --- /dev/null +++ b/kernel/lib/bytes/bytes.c @@ -0,0 +1,163 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +// Big endian interfaces +uint16_t bytes_read_u16_be(const uint8_t *buf) +{ + uint16_t val; + + val = (buf[0] << 8) | buf[1]; + + return (val); +} + +uint32_t bytes_read_u24_be(const uint8_t *buf) +{ + uint32_t val; + + val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + + return (val); +} + +uint32_t bytes_read_u32_be(const uint8_t *buf) +{ + uint32_t val; + + val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + + return (val); +} + +uint8_t *bytes_write_u16_be(uint8_t *buf, uint16_t val) +{ + *buf++ = (val >> 8) & 0xFF; + *buf++ = (val ) & 0xFF; + + return (buf); +} + +uint8_t *bytes_write_u24_be(uint8_t *buf, uint32_t val) +{ + *buf++ = (val >> 16) & 0xFF; + *buf++ = (val >> 8) & 0xFF; + *buf++ = (val ) & 0xFF; + + return (buf); +} + +uint8_t *bytes_write_u32_be(uint8_t *buf, uint32_t val) +{ + *buf++ = (val >> 24) & 0xFF; + *buf++ = (val >> 16) & 0xFF; + *buf++ = (val >> 8) & 0xFF; + *buf++ = (val ) & 0xFF; + + return (buf); +} + + +// Little endian interfaces +uint16_t bytes_read_u16_le(const uint8_t *buf) +{ + uint16_t val; + + val = (buf[1] << 8) | buf[0]; + + return (val); +} + +uint32_t bytes_read_u24_le(const uint8_t *buf) +{ + uint32_t val; + + val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + return (val); +} + +uint32_t bytes_read_u32_le(const uint8_t *buf) +{ + uint32_t val; + + val = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + return (val); +} + +uint8_t *bytes_write_u16_le(uint8_t *buf, uint16_t val) +{ + *buf++ = (val ) & 0xFF; + *buf++ = (val >> 8) & 0xFF; + + return (buf); +} + +uint8_t *bytes_write_u24_le(uint8_t *buf, uint32_t val) +{ + *buf++ = (val ) & 0xFF; + *buf++ = (val >> 8) & 0xFF; + *buf++ = (val >> 16) & 0xFF; + + return (buf); +} + +uint8_t *bytes_write_u32_le(uint8_t *buf, uint32_t val) +{ + *buf++ = (val ) & 0xFF; + *buf++ = (val >> 8) & 0xFF; + *buf++ = (val >> 16) & 0xFF; + *buf++ = (val >> 24) & 0xFF; + + return (buf); +} + +uint8_t bytes_swap_bits_u8(uint8_t val) +{ + val = ((val >> 1) & 0x55) | ((val & 0x55) << 1); + val = ((val >> 2) & 0x33) | ((val & 0x33) << 2); + val = ((val >> 4) & 0x0f) | ((val & 0x0f) << 4); + + return (val); +} + +uint16_t bytes_swap_bits_u16(uint16_t val) +{ + val = ((val >> 1) & 0x5555) | ((val & 0x5555) << 1); + val = ((val >> 2) & 0x3333) | ((val & 0x3333) << 2); + val = ((val >> 4) & 0x0f0f) | ((val & 0x0f0f) << 4); + val = ((val >> 8) & 0x00ff) | ((val & 0x00ff) << 8); + + return (val); +} + +uint32_t bytes_swap_bits_u24(uint32_t val) +{ + val &= 0x00FFFFFF; + val = ((val >> 1) & 0x555555) | ((val & 0x555555) << 1); + val = ((val >> 2) & 0x333333) | ((val & 0x333333) << 2); + val = ((val >> 4) & 0x0f0f0f) | ((val & 0x0f0f0f) << 4); + val = ((val >> 16) & 0x0000ff) | ((val & 0x0000ff) << 16) | (val & 0x00FF00); + + return (val); +} + +uint32_t bytes_swap_bits_u32(uint32_t val) +{ + val = ((val >> 1) & 0x55555555) | ((val & 0x55555555) << 1); + val = ((val >> 2) & 0x33333333) | ((val & 0x33333333) << 2); + val = ((val >> 4) & 0x0f0f0f0f) | ((val & 0x0f0f0f0f) << 4); + val = ((val >> 8) & 0x00ff00ff) | ((val & 0x00ff00ff) << 8); + val = ((val >> 16) & 0x0000ffff) | ((val & 0x0000ffff) << 16); + + return (val); +} + diff --git a/kernel/lib/bytes/rules.mk b/kernel/lib/bytes/rules.mk new file mode 100644 index 000000000..b5edbff12 --- /dev/null +++ b/kernel/lib/bytes/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/bytes.c + +include make/module.mk diff --git a/kernel/lib/cbuf/BUILD.gn b/kernel/lib/cbuf/BUILD.gn new file mode 100644 index 000000000..4602578a8 --- /dev/null +++ b/kernel/lib/cbuf/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_cbuf_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("cbuf") { + public_configs = [ ":_cbuf_config" ] + public = [ + "include/lib/cbuf.h", + ] + sources = [ + "cbuf.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/cbuf/cbuf.c b/kernel/lib/cbuf/cbuf.c new file mode 100644 index 000000000..9c52908d4 --- /dev/null +++ b/kernel/lib/cbuf/cbuf.c @@ -0,0 +1,258 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define INC_POINTER(cbuf, ptr, inc) \ + modpow2(((ptr) + (inc)), (cbuf)->len_pow2) + +void cbuf_initialize(cbuf_t *cbuf, size_t len) +{ + cbuf_initialize_etc(cbuf, len, malloc(len)); +} + +void cbuf_initialize_etc(cbuf_t *cbuf, size_t len, void *buf) +{ + DEBUG_ASSERT(cbuf); + DEBUG_ASSERT(len > 0); + DEBUG_ASSERT(ispow2(len)); + + cbuf->head = 0; + cbuf->tail = 0; + cbuf->len_pow2 = log2_uint(len); + cbuf->buf = buf; + event_init(&cbuf->event, false, 0); + spin_lock_init(&cbuf->lock); + + LTRACEF("len %zd, len_pow2 %u\n", len, cbuf->len_pow2); +} + +size_t cbuf_space_avail(cbuf_t *cbuf) +{ + uint consumed = modpow2((uint)(cbuf->head - cbuf->tail), cbuf->len_pow2); + return valpow2(cbuf->len_pow2) - consumed - 1; +} + +size_t cbuf_space_used(cbuf_t *cbuf) +{ + return modpow2((uint)(cbuf->head - cbuf->tail), cbuf->len_pow2); +} + +size_t cbuf_write_etc(cbuf_t *cbuf, const void *_buf, size_t len, uint32_t flags) +{ + const char *buf = (const char *)_buf; + + LTRACEF("len %zd\n", len); + + DEBUG_ASSERT(cbuf); + DEBUG_ASSERT(len < valpow2(cbuf->len_pow2)); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&cbuf->lock, state); + + size_t write_len; + size_t pos = 0; + + while (pos < len && cbuf_space_avail(cbuf) > 0) { + if (cbuf->head >= cbuf->tail) { + write_len = MIN(valpow2(cbuf->len_pow2) - cbuf->head, len - pos); + } else { + write_len = MIN(cbuf->tail - cbuf->head - 1, len - pos); + } + + // if it's full, abort and return how much we've written + if (write_len == 0) { + break; + } + + if (NULL == buf) { + if (!(flags & CBUF_WRITE_FLAG_NOFILL)) { + memset(cbuf->buf + cbuf->head, 0, write_len); + } + } else { + memcpy(cbuf->buf + cbuf->head, buf + pos, write_len); + } + + cbuf->head = INC_POINTER(cbuf, cbuf->head, write_len); + pos += write_len; + } + + if (cbuf->head != cbuf->tail) + event_signal(&cbuf->event, false); + + spin_unlock_irqrestore(&cbuf->lock, state); + + // XXX convert to only rescheduling if + if (flags & CBUF_WRITE_FLAG_CANRESCHEDULE) + thread_preempt(); + + return pos; +} + +size_t cbuf_read(cbuf_t *cbuf, void *_buf, size_t buflen, bool block) +{ + char *buf = (char *)_buf; + + DEBUG_ASSERT(cbuf); + +retry: + // block on the cbuf outside of the lock, which may + // unblock us early and we'll have to double check below + if (block) + event_wait(&cbuf->event); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&cbuf->lock, state); + + // see if there's data available + size_t ret = 0; + if (cbuf->tail != cbuf->head) { + size_t pos = 0; + + // loop until we've read everything we need + // at most this will make two passes to deal with wraparound + while (pos < buflen && cbuf->tail != cbuf->head) { + size_t read_len; + if (cbuf->head > cbuf->tail) { + // simple case where there is no wraparound + read_len = MIN(cbuf->head - cbuf->tail, buflen - pos); + } else { + // read to the end of buffer in this pass + read_len = MIN(valpow2(cbuf->len_pow2) - cbuf->tail, buflen - pos); + } + + // Only perform the copy if a buf was supplied + if (NULL != buf) { + memcpy(buf + pos, cbuf->buf + cbuf->tail, read_len); + } + + cbuf->tail = INC_POINTER(cbuf, cbuf->tail, read_len); + pos += read_len; + } + + if (cbuf->tail == cbuf->head) { + DEBUG_ASSERT(pos > 0); + // we've emptied the buffer, unsignal the event + event_unsignal(&cbuf->event); + } + + ret = pos; + } + + spin_unlock_irqrestore(&cbuf->lock, state); + + // we apparently blocked but raced with another thread and found no data, retry + if (block && ret == 0) + goto retry; + + return ret; +} + +size_t cbuf_peek_etc(cbuf_t *cbuf, iovec_t *regions, bool writable) +{ + DEBUG_ASSERT(cbuf && regions); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&cbuf->lock, state); + + size_t sz = cbuf_size(cbuf); + size_t ret, pos; + + if (writable) { + DEBUG_ASSERT(cbuf->head < sz); + ret = cbuf_space_avail(cbuf); + pos = cbuf->head; + } else { + DEBUG_ASSERT(cbuf->tail < sz); + ret = cbuf_space_used(cbuf); + pos = cbuf->tail; + } + DEBUG_ASSERT(ret <= sz); + + regions[0].iov_base = ret ? (cbuf->buf + pos) : NULL; + if (ret + pos > sz) { + regions[0].iov_len = sz - pos; + regions[1].iov_base = cbuf->buf; + regions[1].iov_len = ret - regions[0].iov_len; + } else { + regions[0].iov_len = ret; + regions[1].iov_base = NULL; + regions[1].iov_len = 0; + } + + spin_unlock_irqrestore(&cbuf->lock, state); + return ret; +} + +size_t cbuf_write_char(cbuf_t *cbuf, char c, bool canreschedule) +{ + DEBUG_ASSERT(cbuf); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&cbuf->lock, state); + + size_t ret = 0; + if (cbuf_space_avail(cbuf) > 0) { + cbuf->buf[cbuf->head] = c; + + cbuf->head = INC_POINTER(cbuf, cbuf->head, 1); + ret = 1; + + if (cbuf->head != cbuf->tail) + event_signal(&cbuf->event, canreschedule); + } + + spin_unlock_irqrestore(&cbuf->lock, state); + + return ret; +} + +size_t cbuf_read_char(cbuf_t *cbuf, char *c, bool block) +{ + DEBUG_ASSERT(cbuf); + DEBUG_ASSERT(c); + +retry: + if (block) + event_wait(&cbuf->event); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&cbuf->lock, state); + + // see if there's data available + size_t ret = 0; + if (cbuf->tail != cbuf->head) { + + *c = cbuf->buf[cbuf->tail]; + cbuf->tail = INC_POINTER(cbuf, cbuf->tail, 1); + + if (cbuf->tail == cbuf->head) { + // we've emptied the buffer, unsignal the event + event_unsignal(&cbuf->event); + } + + ret = 1; + } + + spin_unlock_irqrestore(&cbuf->lock, state); + + if (block && ret == 0) + goto retry; + + return ret; +} + diff --git a/kernel/lib/cbuf/include/lib/cbuf.h b/kernel/lib/cbuf/include/lib/cbuf.h new file mode 100644 index 000000000..256b01c93 --- /dev/null +++ b/kernel/lib/cbuf/include/lib/cbuf.h @@ -0,0 +1,207 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009-2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +#define CBUF_WRITE_FLAG_CANRESCHEDULE 0x1 +#define CBUF_WRITE_FLAG_NOFILL 0x2 + +typedef struct cbuf { + uint head; + uint tail; + uint len_pow2; + char *buf; + event_t event; + spin_lock_t lock; +} cbuf_t; + +/** + * cbuf_initialize + * + * Initialize a cbuf structure, mallocing the underlying data buffer in the + * process. Make sure that the buffer has enough space for at least len bytes. + * + * @param[in] cbuf A pointer to the cbuf structure to allocate. + * @param[in] len The minimum number of bytes for the underlying data buffer. + */ +void cbuf_initialize(cbuf_t *cbuf, size_t len); + +/** + * cbuf_initalize_etc + * + * Initialize a cbuf structure using the supplied buffer for internal storage. + * + * @param[in] cbuf A pointer to the cbuf structure to allocate. + * @param[in] len The size of the supplied buffer, in bytes. + * @param[in] buf A pointer to the memory to be used for internal storage. + */ +void cbuf_initialize_etc(cbuf_t *cbuf, size_t len, void *buf); + +/** + * cbuf_read + * + * Read up to buflen bytes in to the supplied buffer. + * + * @param[in] cbuf The cbuf instance to read from. + * @param[in] buf A pointer to a buffer to read data into. If NULL, cbuf_read + * will skip up to the next buflen bytes from the cbuf. + * @param[in] buflen The maximum number of bytes to read from the cbuf. + * @param[in] block When true, will cause the caller to block until there is at + * least one byte available to read from the cbuf. + * + * @return The actual number of bytes which were read (or skipped). + */ +size_t cbuf_read(cbuf_t *cbuf, void *buf, size_t buflen, bool block); + +/** + * cbuf_peek_etc + * + * Peek at the data available for read/write in the cbuf right now. Fills out a + * pair of iovec structures describing the (up to) two currently available + * contiguous regions. In the case of a read peak, this call does not actually + * consume the data. + * + * @param[in] cbuf The cbuf instance to peek into. + * @param[out] A pointer to two iovec structures to hold the description of the + * contiguous regions. NOTE: regions must point to a chunk of memory which is + * at least sizeof(iovec_t) * 2 bytes long. + * @param[in] writable When true, calculate the currently writable regions of + * the cbuf. Otherwise, calculate the currently readable regions of the cbuf. + * + * @return The total number of bytes which could be read/written. + */ +size_t cbuf_peek_etc(cbuf_t *cbuf, iovec_t *regions, bool writable); + +/** + * cbuf_peek + * + * @see cbuf_peek_etc + * + * Alias which peeks at the data available for read in the cbuf right now. + */ +static inline size_t cbuf_peek(cbuf_t *cbuf, iovec_t *regions) { + return cbuf_peek_etc(cbuf, regions, false); +} + +/** + * cbuf_peek_write + * + * @see cbuf_peek_etc + * + * Alias which peeks at the space available for write in the cbuf right now. + */ +static inline size_t cbuf_peek_write(cbuf_t *cbuf, iovec_t *regions) { + return cbuf_peek_etc(cbuf, regions, true); +} + +/** + * cbuf_write_etc + * + * Write up to len bytes from the supplied buffer into the cbuf. + * + * @param[in] cbuf The cbuf instance to write to. + * @param[in] buf A pointer to a buffer to read data from. If NULL, cbuf_write + * will skip up to the next len bytes in the cbuf, filling with zeros instead of + * supplied data. + * @param[in] len The maximum number of bytes to write to the cbuf. + * @param[in] flags May contain any valid combination of CBUF_WRITE_FLAGS. + * - CBUF_WRITE_FLAG_CANRECHEDULE Signals rescheduling policy passed through + * to the internal event when signalling the event to indicate that there is + * now data in the buffer to be read. + * - CBUF_WRITE_FLAG_NOFILL When set, and the buf parameter is NULL, do not + * fill the internal cbuf with zeros. Instead, simply advance the write + * pointer. + * + * @return The number of bytes which were written (or skipped). + */ +size_t cbuf_write_etc(cbuf_t *cbuf, const void *buf, size_t len, uint32_t flags); + +/** + * cbuf_write + * + * @see cbuf_write_etc + * + * Alias which write (or zeros) len bytes to the cbuf. + */ +static inline size_t cbuf_write(cbuf_t *cbuf, const void *buf, size_t len, bool canreschedule) { + return cbuf_write_etc(cbuf, buf, len, canreschedule ? CBUF_WRITE_FLAG_CANRESCHEDULE : 0); +} + +/** + * cbuf_advance_write + * + * @see cbuf_write_etc + * + * Alias which advances the cbuf write pointer, writing nothing to the + * underlying buffer in the process. + */ +static inline size_t cbuf_advance_write(cbuf_t *cbuf, size_t len, bool canreschedule) { + return cbuf_write_etc(cbuf, NULL, len, + canreschedule + ? CBUF_WRITE_FLAG_NOFILL | CBUF_WRITE_FLAG_CANRESCHEDULE + : CBUF_WRITE_FLAG_NOFILL); +} + +/** + * cbuf_space_avail + * + * @param[in] cbuf The cbuf instance to query + * + * @return The number of free space available in the cbuf (IOW - the maximum + * number of bytes which can currently be written) + */ +size_t cbuf_space_avail(cbuf_t *cbuf); + +/** + * cbuf_space_used + * + * @param[in] cbuf The cbuf instance to query + * + * @return The number of used bytes in the cbuf (IOW - the maximum number of + * bytes which can currently be read). + */ +size_t cbuf_space_used(cbuf_t *cbuf); + +/** + * cbuf_size + * + * @param[in] cbuf The cbuf instance to query + * + * @return The size of the cbuf's underlying data buffer. + */ +static inline size_t cbuf_size(cbuf_t *cbuf) +{ + return (1UL << cbuf->len_pow2); +} + +/** + * cbuf_reset + * + * Reset the cbuf instance, discarding any data which may be in the buffer at + * the moment. + * + * @param[in] cbuf The cbuf instance to reset. + */ +static inline void cbuf_reset(cbuf_t *cbuf) +{ + cbuf_read(cbuf, NULL, cbuf_size(cbuf), false); +} + +/* special cases for dealing with a single char of data */ +size_t cbuf_read_char(cbuf_t *cbuf, char *c, bool block); +size_t cbuf_write_char(cbuf_t *cbuf, char c, bool canreschedule); + +__END_CDECLS + diff --git a/kernel/lib/cbuf/rules.mk b/kernel/lib/cbuf/rules.mk new file mode 100644 index 000000000..22a0c6612 --- /dev/null +++ b/kernel/lib/cbuf/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/cbuf.c + +include make/module.mk diff --git a/kernel/lib/console/BUILD.gn b/kernel/lib/console/BUILD.gn new file mode 100644 index 000000000..664fcf4b3 --- /dev/null +++ b/kernel/lib/console/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_console") { + if (enable_console) { + defines = [ "WITH_LIB_CONSOLE=1" ] + } else { + defines = [ "WITH_LIB_CONSOLE=0" ] + } +} + +module("console") { + public_configs = [ ":enable_console" ] + sources = [ + "console.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/console/console.c b/kernel/lib/console/console.c new file mode 100644 index 000000000..451883955 --- /dev/null +++ b/kernel/lib/console/console.c @@ -0,0 +1,904 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WITH_LIB_ENV +#include +#endif + +#ifndef CONSOLE_ENABLE_HISTORY +#define CONSOLE_ENABLE_HISTORY 1 +#endif + +#define LINE_LEN 128 + +#define PANIC_LINE_LEN 32 + +#define MAX_NUM_ARGS 16 + +#define HISTORY_LEN 16 + +#define LOCAL_TRACE 0 + +#define WHITESPACE " \t" + +/* debug buffer */ +static char *debug_buffer; + +/* echo commands? */ +static bool echo = true; + +/* command processor state */ +static mutex_t *command_lock; +int lastresult; +static bool abort_script; + +#if CONSOLE_ENABLE_HISTORY +/* command history stuff */ +static char *history; // HISTORY_LEN rows of LINE_LEN chars a piece +static uint history_next; + +static void init_history(void); +static void add_history(const char *line); +static uint start_history_cursor(void); +static const char *next_history(uint *cursor); +static const char *prev_history(uint *cursor); +static void dump_history(void); +#endif + +/* list of installed commands */ +static cmd_block *command_list = NULL; + +/* a linear array of statically defined command blocks, + defined in the linker script. + */ +extern cmd_block __start_commands[] __WEAK; +extern cmd_block __stop_commands[] __WEAK; + +static int cmd_help(int argc, const cmd_args *argv); +static int cmd_help_panic(int argc, const cmd_args *argv); +static int cmd_echo(int argc, const cmd_args *argv); +static int cmd_test(int argc, const cmd_args *argv); +#if CONSOLE_ENABLE_HISTORY +static int cmd_history(int argc, const cmd_args *argv); +#endif + +STATIC_COMMAND_START +STATIC_COMMAND("help", "this list", &cmd_help) +STATIC_COMMAND_MASKED("help", "this list", &cmd_help_panic, CMD_AVAIL_PANIC) +STATIC_COMMAND("echo", NULL, &cmd_echo) +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND("test", "test the command processor", &cmd_test) +#if CONSOLE_ENABLE_HISTORY +STATIC_COMMAND("history", "command history", &cmd_history) +#endif +#endif +STATIC_COMMAND_END(help); + +int console_init(void) +{ + LTRACE_ENTRY; + + command_lock = calloc(sizeof(mutex_t), 1); + mutex_init(command_lock); + + /* add all the statically defined commands to the list */ + cmd_block *block; + for (block = __start_commands; block != __stop_commands; block++) { + console_register_commands(block); + } + +#if CONSOLE_ENABLE_HISTORY + init_history(); +#endif + + return 0; +} + +#if CONSOLE_ENABLE_HISTORY +static int cmd_history(int argc, const cmd_args *argv) +{ + dump_history(); + return 0; +} + +static inline char *history_line(uint line) +{ + return history + line * LINE_LEN; +} + +static inline uint ptrnext(uint ptr) +{ + return (ptr + 1) % HISTORY_LEN; +} + +static inline uint ptrprev(uint ptr) +{ + return (ptr - 1) % HISTORY_LEN; +} + +static void dump_history(void) +{ + printf("command history:\n"); + uint ptr = ptrprev(history_next); + int i; + for (i=0; i < HISTORY_LEN; i++) { + if (history_line(ptr)[0] != 0) + printf("\t%s\n", history_line(ptr)); + ptr = ptrprev(ptr); + } +} + +static void init_history(void) +{ + /* allocate and set up the history buffer */ + history = calloc(1, HISTORY_LEN * LINE_LEN); + history_next = 0; +} + +static void add_history(const char *line) +{ + // reject some stuff + if (line[0] == 0) + return; + + uint last = ptrprev(history_next); + if (strcmp(line, history_line(last)) == 0) + return; + + strlcpy(history_line(history_next), line, LINE_LEN); + history_next = ptrnext(history_next); +} + +static uint start_history_cursor(void) +{ + return ptrprev(history_next); +} + +static const char *next_history(uint *cursor) +{ + uint i = ptrnext(*cursor); + + if (i == history_next) + return ""; // can't let the cursor hit the head + + *cursor = i; + return history_line(i); +} + +static const char *prev_history(uint *cursor) +{ + uint i; + const char *str = history_line(*cursor); + + /* if we are already at head, stop here */ + if (*cursor == history_next) + return str; + + /* back up one */ + i = ptrprev(*cursor); + + /* if the next one is gonna be null */ + if (history_line(i)[0] == '\0') + return str; + + /* update the cursor */ + *cursor = i; + return str; +} +#endif + +static const cmd *match_command(const char *command, const uint8_t availability_mask) +{ + cmd_block *block; + size_t i; + + for (block = command_list; block != NULL; block = block->next) { + const cmd *curr_cmd = block->list; + for (i = 0; i < block->count; i++) { + if ((availability_mask & curr_cmd[i].availability_mask) == 0) { + continue; + } + if (strcmp(command, curr_cmd[i].cmd_str) == 0) { + return &curr_cmd[i]; + } + } + } + + return NULL; +} + +#if WITH_LIB_DEBUGLOG +static inline int cgetchar(void) { + char c; + int r = platform_dgetc(&c, true); + return (r < 0) ? r : c; +} +static inline void cputchar(char c) { + platform_dputc(c); +} +static inline void cputs(const char* s) { + while (*s) { + platform_dputc(*s++); + } +} +#else +static inline int cgetchar(void) { + return getchar(); +} +static inline void cputchar(char c) { + putchar(c); +} +static inline void cputs(const char* s) { + fputs(s, stdout); +} +#endif + +static int read_debug_line(const char **outbuffer, void *cookie) +{ + int pos = 0; + int escape_level = 0; +#if CONSOLE_ENABLE_HISTORY + uint history_cursor = start_history_cursor(); +#endif + + char *buffer = debug_buffer; + + for (;;) { + /* loop until we get a char */ + int c; + if ((c = cgetchar()) < 0) + continue; + +// TRACEF("c = 0x%hhx\n", c); + + if (escape_level == 0) { + switch (c) { + case '\r': + case '\n': + if (echo) + cputchar('\n'); + goto done; + + case 0x7f: // backspace or delete + case 0x8: + if (pos > 0) { + pos--; + cputs("\b \b"); // wipe out a character + } + break; + + case 0x1b: // escape + escape_level++; + break; + + default: + buffer[pos++] = c; + if (echo) + cputchar(c); + } + } else if (escape_level == 1) { + // inside an escape, look for '[' + if (c == '[') { + escape_level++; + } else { + // we didn't get it, abort + escape_level = 0; + } + } else { // escape_level > 1 + switch (c) { + case 67: // right arrow + buffer[pos++] = ' '; + if (echo) + cputchar(' '); + break; + case 68: // left arrow + if (pos > 0) { + pos--; + if (echo) { + cputs("\b \b"); // wipe out a character + } + } + break; +#if CONSOLE_ENABLE_HISTORY + case 65: // up arrow -- previous history + case 66: // down arrow -- next history + // wipe out the current line + while (pos > 0) { + pos--; + if (echo) { + cputs("\b \b"); // wipe out a character + } + } + + if (c == 65) + strlcpy(buffer, prev_history(&history_cursor), LINE_LEN); + else + strlcpy(buffer, next_history(&history_cursor), LINE_LEN); + pos = strlen(buffer); + if (echo) + cputs(buffer); + break; +#endif + default: + break; + } + escape_level = 0; + } + + /* end of line. */ + if (pos == (LINE_LEN - 1)) { + cputs("\nerror: line too long\n"); + pos = 0; + goto done; + } + } + +done: +// dprintf("returning pos %d\n", pos); + + // null terminate + buffer[pos] = 0; + +#if CONSOLE_ENABLE_HISTORY + // add to history + add_history(buffer); +#endif + + // return a pointer to our buffer + *outbuffer = buffer; + + return pos; +} + +static int tokenize_command(const char *inbuffer, const char **continuebuffer, char *buffer, size_t buflen, cmd_args *args, int arg_count) +{ + int inpos; + int outpos; + int arg; + enum { + INITIAL = 0, + NEXT_FIELD, + SPACE, + IN_SPACE, + TOKEN, + IN_TOKEN, + QUOTED_TOKEN, + IN_QUOTED_TOKEN, + VAR, + IN_VAR, + COMMAND_SEP, + } state; + char varname[128]; + int varnamepos; + + inpos = 0; + outpos = 0; + arg = 0; + varnamepos = 0; + state = INITIAL; + *continuebuffer = NULL; + + for (;;) { + char c = inbuffer[inpos]; + +// dprintf(SPEW, "c 0x%hhx state %d arg %d inpos %d pos %d\n", c, state, arg, inpos, outpos); + + switch (state) { + case INITIAL: + case NEXT_FIELD: + if (c == '\0') + goto done; + if (isspace(c)) + state = SPACE; + else if (c == ';') + state = COMMAND_SEP; + else + state = TOKEN; + break; + case SPACE: + state = IN_SPACE; + break; + case IN_SPACE: + if (c == '\0') + goto done; + if (c == ';') { + state = COMMAND_SEP; + } else if (!isspace(c)) { + state = TOKEN; + } else { + inpos++; // consume the space + } + break; + case TOKEN: + // start of a token + DEBUG_ASSERT(c != '\0'); + if (c == '"') { + // start of a quoted token + state = QUOTED_TOKEN; + } else if (c == '$') { + // start of a variable + state = VAR; + } else { + // regular, unquoted token + state = IN_TOKEN; + args[arg].str = &buffer[outpos]; + } + break; + case IN_TOKEN: + if (c == '\0') { + arg++; + goto done; + } + if (isspace(c) || c == ';') { + arg++; + buffer[outpos] = 0; + outpos++; + /* are we out of tokens? */ + if (arg == arg_count) + goto done; + state = NEXT_FIELD; + } else { + buffer[outpos] = c; + outpos++; + inpos++; + } + break; + case QUOTED_TOKEN: + // start of a quoted token + DEBUG_ASSERT(c == '"'); + + state = IN_QUOTED_TOKEN; + args[arg].str = &buffer[outpos]; + inpos++; // consume the quote + break; + case IN_QUOTED_TOKEN: + if (c == '\0') { + arg++; + goto done; + } + if (c == '"') { + arg++; + buffer[outpos] = 0; + outpos++; + /* are we out of tokens? */ + if (arg == arg_count) + goto done; + + state = NEXT_FIELD; + } + buffer[outpos] = c; + outpos++; + inpos++; + break; + case VAR: + DEBUG_ASSERT(c == '$'); + + state = IN_VAR; + args[arg].str = &buffer[outpos]; + inpos++; // consume the dollar sign + + // initialize the place to store the variable name + varnamepos = 0; + break; + case IN_VAR: + if (c == '\0' || isspace(c) || c == ';') { + // hit the end of variable, look it up and stick it inline + varname[varnamepos] = 0; +#if WITH_LIB_ENV + int rc = env_get(varname, &buffer[outpos], buflen - outpos); +#else + (void)varname[0]; // nuke a warning + int rc = -1; +#endif + if (rc < 0) { + buffer[outpos++] = '0'; + buffer[outpos++] = 0; + } else { + outpos += strlen(&buffer[outpos]) + 1; + } + arg++; + /* are we out of tokens? */ + if (arg == arg_count) + goto done; + + state = NEXT_FIELD; + } else { + varname[varnamepos] = c; + varnamepos++; + inpos++; + } + break; + case COMMAND_SEP: + // we hit a ;, so terminate the command and pass the remainder of the command back in continuebuffer + DEBUG_ASSERT(c == ';'); + + inpos++; // consume the ';' + *continuebuffer = &inbuffer[inpos]; + goto done; + } + } + +done: + buffer[outpos] = 0; + return arg; +} + +static void convert_args(int argc, cmd_args *argv) +{ + int i; + + for (i = 0; i < argc; i++) { + unsigned long u = atoul(argv[i].str); + argv[i].u = u; + argv[i].p = (void *)u; + argv[i].i = atol(argv[i].str); + + if (!strcmp(argv[i].str, "true") || !strcmp(argv[i].str, "on")) { + argv[i].b = true; + } else if (!strcmp(argv[i].str, "false") || !strcmp(argv[i].str, "off")) { + argv[i].b = false; + } else { + argv[i].b = (argv[i].u == 0) ? false : true; + } + } +} + + +static status_t command_loop(int (*get_line)(const char **, void *), void *get_line_cookie, bool showprompt, bool locked) +{ + bool exit; +#if WITH_LIB_ENV + bool report_result; +#endif + cmd_args *args = NULL; + const char *buffer; + const char *continuebuffer; + char *outbuf = NULL; + + args = (cmd_args *) malloc (MAX_NUM_ARGS * sizeof(cmd_args)); + if (unlikely(args == NULL)) { + goto no_mem_error; + } + + const size_t outbuflen = 1024; + outbuf = malloc(outbuflen); + if (unlikely(outbuf == NULL)) { + goto no_mem_error; + } + + exit = false; + continuebuffer = NULL; + while (!exit) { + // read a new line if it hadn't been split previously and passed back from tokenize_command + if (continuebuffer == NULL) { + if (showprompt) + cputs("] "); + + int len = get_line(&buffer, get_line_cookie); + if (len < 0) + break; + if (len == 0) + continue; + } else { + buffer = continuebuffer; + } + +// dprintf("line = '%s'\n", buffer); + + /* tokenize the line */ + int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen, + args, MAX_NUM_ARGS); + if (argc < 0) { + if (showprompt) + printf("syntax error\n"); + continue; + } else if (argc == 0) { + continue; + } + +// dprintf("after tokenize: argc %d\n", argc); +// for (int i = 0; i < argc; i++) +// dprintf("%d: '%s'\n", i, args[i].str); + + /* convert the args */ + convert_args(argc, args); + + /* try to match the command */ + const cmd *command = match_command(args[0].str, CMD_AVAIL_NORMAL); + if (!command) { + if (showprompt) + printf("command not found\n"); + continue; + } + + if (!locked) + mutex_acquire(command_lock); + + abort_script = false; + lastresult = command->cmd_callback(argc, args); + +#if WITH_LIB_ENV + bool report_result; + env_get_bool("reportresult", &report_result, false); + if (report_result) { + if (lastresult < 0) + printf("FAIL %d\n", lastresult); + else + printf("PASS %d\n", lastresult); + } +#endif + +#if WITH_LIB_ENV + // stuff the result in an environment var + env_set_int("?", lastresult, true); +#endif + + // someone must have aborted the current script + if (abort_script) + exit = true; + abort_script = false; + + if (!locked) + mutex_release(command_lock); + } + + free(outbuf); + free(args); + return NO_ERROR; + +no_mem_error: + if (outbuf) + free(outbuf); + + if (args) + free(args); + + dprintf(INFO, "%s: not enough memory\n", __func__); + return ERR_NO_MEMORY; +} + +void console_abort_script(void) +{ + abort_script = true; +} + +void console_start(void) +{ + debug_buffer = malloc(LINE_LEN); + + dprintf(INFO, "entering main console loop\n"); + + + while (command_loop(&read_debug_line, NULL, true, false) == NO_ERROR) + ; + + dprintf(INFO, "exiting main console loop\n"); + + free (debug_buffer); +} + +struct line_read_struct { + const char *string; + int pos; + char *buffer; + size_t buflen; +}; + +static int fetch_next_line(const char **buffer, void *cookie) +{ + struct line_read_struct *lineread = (struct line_read_struct *)cookie; + + // we're done + if (lineread->string[lineread->pos] == 0) + return -1; + + size_t bufpos = 0; + while (lineread->string[lineread->pos] != 0) { + if (lineread->string[lineread->pos] == '\n') { + lineread->pos++; + break; + } + if (bufpos == (lineread->buflen - 1)) + break; + lineread->buffer[bufpos] = lineread->string[lineread->pos]; + lineread->pos++; + bufpos++; + } + lineread->buffer[bufpos] = 0; + + *buffer = lineread->buffer; + + return bufpos; +} + +static int console_run_script_etc(const char *string, bool locked) +{ + struct line_read_struct lineread; + + lineread.string = string; + lineread.pos = 0; + lineread.buffer = malloc(LINE_LEN); + lineread.buflen = LINE_LEN; + + command_loop(&fetch_next_line, (void *)&lineread, false, locked); + + free(lineread.buffer); + + return lastresult; +} + +int console_run_script(const char *string) +{ + return console_run_script_etc(string, false); +} + +int console_run_script_locked(const char *string) +{ + return console_run_script_etc(string, true); +} + +console_cmd console_get_command_handler(const char *commandstr) +{ + const cmd *command = match_command(commandstr, CMD_AVAIL_NORMAL); + + if (command) + return command->cmd_callback; + else + return NULL; +} + +void console_register_commands(cmd_block *block) +{ + DEBUG_ASSERT(block); + DEBUG_ASSERT(block->next == NULL); + + block->next = command_list; + command_list = block; +} + + +static int cmd_help_impl(uint8_t availability_mask) +{ + printf("command list:\n"); + + cmd_block *block; + size_t i; + + for (block = command_list; block != NULL; block = block->next) { + const cmd *curr_cmd = block->list; + for (i = 0; i < block->count; i++) { + if ((availability_mask & curr_cmd[i].availability_mask) == 0) { + // Skip commands that aren't available in the current shell. + continue; + } + if (curr_cmd[i].help_str) + printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str); + } + } + + return 0; +} + +static int cmd_help(int argc, const cmd_args *argv) +{ + return cmd_help_impl(CMD_AVAIL_NORMAL); +} + +static int cmd_help_panic(int argc, const cmd_args *argv) +{ + return cmd_help_impl(CMD_AVAIL_PANIC); +} + +static int cmd_echo(int argc, const cmd_args *argv) +{ + if (argc > 1) + echo = argv[1].b; + return NO_ERROR; +} + +static void read_line_panic(char *buffer, const size_t len, FILE *panic_fd) +{ + size_t pos = 0; + + for (;;) { + int c; + if ((c = getc(panic_fd)) < 0) { + continue; + } + + switch (c) { + case '\r': + case '\n': + fputc('\n', panic_fd); + goto done; + case 0x7f: // backspace or delete + case 0x8: + if (pos > 0) { + pos--; + fputs("\b \b", panic_fd); // wipe out a character + } + break; + default: + buffer[pos++] = c; + fputc(c, panic_fd); + } + if (pos == (len - 1)) { + fputs("\nerror: line too long\n", panic_fd); + pos = 0; + goto done; + } + } +done: + buffer[pos] = 0; +} + +void panic_shell_start(void) +{ + dprintf(INFO, "entering panic shell loop\n"); + char input_buffer[PANIC_LINE_LEN]; + cmd_args args[MAX_NUM_ARGS]; + + // panic_fd allows us to do I/O using the polling drivers. + // These drivers function even if interrupts are disabled. + FILE *panic_fd = get_panic_fd(); + if (!panic_fd) + return; + + for (;;) { + fputs("! ", panic_fd); + read_line_panic(input_buffer, PANIC_LINE_LEN, panic_fd); + + int argc; + char *tok = strtok(input_buffer, WHITESPACE); + for (argc = 0; argc < MAX_NUM_ARGS; argc++) { + if (tok == NULL) { + break; + } + args[argc].str = tok; + tok = strtok(NULL, WHITESPACE); + } + + if (argc == 0) { + continue; + } + + convert_args(argc, args); + + const cmd *command = match_command(args[0].str, CMD_AVAIL_PANIC); + if (!command) { + fputs("command not found\n", panic_fd); + continue; + } + + command->cmd_callback(argc, args); + } +} + +#if LK_DEBUGLEVEL > 1 +static int cmd_test(int argc, const cmd_args *argv) +{ + int i; + + printf("argc %d, argv %p\n", argc, argv); + for (i = 0; i < argc; i++) + printf("\t%d: str '%s', i %ld, u %#lx, b %d\n", i, argv[i].str, argv[i].i, argv[i].u, argv[i].b); + + return 0; +} +#endif diff --git a/kernel/lib/console/rules.mk b/kernel/lib/console/rules.mk new file mode 100644 index 000000000..c67b82ad4 --- /dev/null +++ b/kernel/lib/console/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/console.c + +include make/module.mk diff --git a/kernel/lib/crypto/BUILD.gn b/kernel/lib/crypto/BUILD.gn new file mode 100644 index 000000000..2cdb83bb7 --- /dev/null +++ b/kernel/lib/crypto/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_crypto_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("crypto") { + public_configs = [ ":_crypto_config" ] + public = [ + "include/lib/crypto/hash.h", + "include/lib/crypto/prng.h", + ] + sources = [ + "hash.cpp", + "hash_unittest.cpp", + "prng.cpp", + "prng_unittest.cpp", + ] + deps = [ + "//kernel/lib/libc", + "//kernel/lib/unittest", + "//third_party/lib/cryptolib", + ] +} diff --git a/kernel/lib/crypto/hash.cpp b/kernel/lib/crypto/hash.cpp new file mode 100644 index 000000000..9ab6498bb --- /dev/null +++ b/kernel/lib/crypto/hash.cpp @@ -0,0 +1,43 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include + +namespace crypto { + +Hash256::Hash256() : digest_(0) { +#if defined(LK_DEBUG_BUILD) + finalized_ = false; +#endif + clSHA256_init(&ctx_); +} + +Hash256::Hash256(const void* data, int len) : Hash256() { + Hash256::Update(data, len); + Hash256::Final(); +} + +Hash256::~Hash256() {} + +void Hash256::Update(const void* data, int len) { + DEBUG_ASSERT(!finalized_); + clHASH_update(&ctx_, data, len); +} + +void Hash256::Final() { +#if defined(LK_DEBUG_BUILD) + DEBUG_ASSERT(!finalized_); + finalized_ = true; +#endif + + digest_ = clHASH_final(&ctx_); +} + +} // namespace crypto diff --git a/kernel/lib/crypto/hash_unittest.cpp b/kernel/lib/crypto/hash_unittest.cpp new file mode 100644 index 000000000..17fd27314 --- /dev/null +++ b/kernel/lib/crypto/hash_unittest.cpp @@ -0,0 +1,101 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +namespace crypto { + +namespace { +bool instantiate(void) { + BEGIN_TEST; + + { Hash256 hash(); } + + END_TEST; +} + +// Test an implementation detail of the Hash256 class: that it is a valid +// SHA256. +bool compute_hashes(void) { + BEGIN_TEST; + + // Test vectors from + // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf + + static const char kTestVector1[] = "abc"; + static const int kTestSize1 = 3; + static const uint8_t kExpected1[Hash256::kHashSize] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, + 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, + 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + + { + Hash256 hash1; + hash1.Update(kTestVector1, kTestSize1); + hash1.Final(); + + EXPECT_EQ(0, memcmp(kExpected1, hash1.digest(), sizeof(kExpected1)), + "invalid hash1"); + } + + { + Hash256 hash1; + hash1.Update(kTestVector1, 1); + hash1.Update(kTestVector1 + 1, kTestSize1 - 1); + hash1.Final(); + + EXPECT_EQ(0, memcmp(kExpected1, hash1.digest(), sizeof(kExpected1)), + "invalid hash1"); + } + + { + const Hash256 hash1(kTestVector1, kTestSize1); + EXPECT_EQ(0, memcmp(kExpected1, hash1.digest(), sizeof(kExpected1)), + "invalid hash1"); + } + + static const char kTestVector2[] = ""; + static const uint8_t kExpected2[Hash256::kHashSize] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, + 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, + 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + + { + const Hash256 hash2(kTestVector2, 0); + EXPECT_EQ(0, memcmp(kExpected2, hash2.digest(), sizeof(kExpected2)), + "invalid hash2"); + } + + static const char kTestVector3[] = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + static const int kTestSize3 = 448 / 8; + static const uint8_t kExpected3[Hash256::kHashSize] = { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, + 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, + 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 + + }; + + { + const Hash256 hash3(kTestVector3, kTestSize3); + EXPECT_EQ(0, memcmp(kExpected3, hash3.digest(), sizeof(kExpected3)), + "invalid hash3"); + } + + END_TEST; +} + +} // namespace + +BEGIN_TEST_CASE(hash256_tests); + +RUN_TEST(instantiate); +RUN_TEST(compute_hashes); + +END_TEST_CASE(hash256_tests); + +} // namespace crypto diff --git a/kernel/lib/crypto/include/lib/crypto/hash.h b/kernel/lib/crypto/include/lib/crypto/hash.h new file mode 100644 index 000000000..0362db158 --- /dev/null +++ b/kernel/lib/crypto/include/lib/crypto/hash.h @@ -0,0 +1,52 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +#include + +namespace crypto { + +// This class implements a cryptographically secure 256 bits hash function. +// It can be used in two ways: +// +// 1. +// Hash256 hash1("abc", 3); +// hash1.digest() returns the hash of "abc" +// +// 2. +// Hash256 hash2; +// hash2.Update("a", 1); +// hash2.Update("bc", 2); +// hash2.Final(); +// hash2.digest() returns the hash of "abc". +class Hash256 { + public: + static const size_t kHashSize = 256 / 8; + Hash256(); + Hash256(const void* data, int len); + ~Hash256(); + + void Update(const void* data, int len); + void Final(); + const uint8_t* digest() const { return digest_; } + + private: + Hash256(const Hash256&) = delete; + Hash256& operator=(const Hash256&) = delete; + + clSHA256_CTX ctx_; + const uint8_t* digest_; +#if defined(LK_DEBUG_BUILD) + bool finalized_; +#endif +}; + +} // namespace crypto diff --git a/kernel/lib/crypto/include/lib/crypto/prng.h b/kernel/lib/crypto/include/lib/crypto/prng.h new file mode 100644 index 000000000..b6bea0664 --- /dev/null +++ b/kernel/lib/crypto/include/lib/crypto/prng.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +#include + +namespace crypto { + +// This exposes a cryptographically secure PRNG. +// This PRNG should be seeded with at least 256 bits of "real" entropy before +// being used for cryptographic applications. +class PRNG { + public: + // The PRNG must be seeded. For cryptographic applications, 256 bits are + // expected. |size| is in bytes. + PRNG(const void* data, int size); + ~PRNG(); + + // Re-seed the PRNG by mixing-in new entropy. |size| is in bytes. + void AddEntropy(const void* data, int size); + + // get pseudo-random output of |size| bytes. + void Draw(void* out, int size); + + private: + PRNG(const PRNG&) = delete; + PRNG& operator=(const PRNG&) = delete; + + clPRNG_CTX ctx_; +}; + +} // namespace crypto diff --git a/kernel/lib/crypto/prng.cpp b/kernel/lib/crypto/prng.cpp new file mode 100644 index 000000000..e504a3de3 --- /dev/null +++ b/kernel/lib/crypto/prng.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include + +namespace crypto { + +PRNG::PRNG(const void* data, int size) { clPRNG_init(&ctx_, data, size); } + +void PRNG::AddEntropy(const void* data, int size) { + clPRNG_entropy(&ctx_, data, size); +} + +void PRNG::Draw(void* out, int size) { clPRNG_draw(&ctx_, out, size); } + +PRNG::~PRNG() {} + +} // namespace crypto diff --git a/kernel/lib/crypto/prng_unittest.cpp b/kernel/lib/crypto/prng_unittest.cpp new file mode 100644 index 000000000..af6ede90c --- /dev/null +++ b/kernel/lib/crypto/prng_unittest.cpp @@ -0,0 +1,77 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include + +namespace crypto { + +namespace { +bool instantiate(void) { + BEGIN_TEST; + + { PRNG prng("", 0); } + + END_TEST; +} + +bool prng_output(void) { + BEGIN_TEST; + + static const char kSeed1[] = "abc"; + static const int kSeed1Size = 3; + static const int kDrawSize = 13; + + PRNG prng1(kSeed1, kSeed1Size); + uint8_t out1[kDrawSize]; + prng1.Draw(out1, sizeof(out1)); + + PRNG prng2(kSeed1, kSeed1Size); + uint8_t out2[kDrawSize]; + prng2.Draw(out2, sizeof(out2)); + + EXPECT_EQ(0, memcmp(out1, out2, sizeof(out1)), "inconsistent prng"); + + // Draw from prng1 again. Check that the output is different this time. + // There is no theoritical guarantee that the output is different, but + // kDrawSize is large enough that the probability of this happening is + // negligible. Also this test is fully deterministic for one given PRNG + // implementation. + prng1.Draw(out1, sizeof(out1)); + + EXPECT_NEQ(0, memcmp(out1, out2, sizeof(out1)), "prng output is constant"); + + // We can expect the same output from prng2. + prng2.Draw(out2, sizeof(out2)); + + EXPECT_EQ(0, memcmp(out1, out2, sizeof(out1)), "inconsistent prng"); + + // Now verify that different seeds produce different outputs. + PRNG prng3("blah", 4); + uint8_t out3[kDrawSize]; + prng3.Draw(out3, sizeof(out3)); + + PRNG prng4("bleh", 4); + uint8_t out4[kDrawSize]; + prng3.Draw(out4, sizeof(out4)); + + EXPECT_NEQ(0, memcmp(out3, out4, sizeof(out3)), "prng output is constant"); + + END_TEST; +} + +} // namespace + +BEGIN_TEST_CASE(prng_tests); + +RUN_TEST(instantiate); +RUN_TEST(prng_output); + +END_TEST_CASE(prng_tests); + +} // namespace crypto diff --git a/kernel/lib/crypto/rules.mk b/kernel/lib/crypto/rules.mk new file mode 100644 index 000000000..574d55440 --- /dev/null +++ b/kernel/lib/crypto/rules.mk @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/hash.cpp \ + $(LOCAL_DIR)/hash_unittest.cpp \ + $(LOCAL_DIR)/prng.cpp \ + $(LOCAL_DIR)/prng_unittest.cpp + +MODULE_DEPS += lib/unittest +MODULE_DEPS += lib/cryptolib + +include make/module.mk diff --git a/kernel/lib/debug/BUILD.gn b/kernel/lib/debug/BUILD.gn new file mode 100644 index 000000000..2f54251f5 --- /dev/null +++ b/kernel/lib/debug/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("debug") { + sources = [ + "debug.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/debug/debug.c b/kernel/lib/debug/debug.c new file mode 100644 index 000000000..b7ed1b2b2 --- /dev/null +++ b/kernel/lib/debug/debug.c @@ -0,0 +1,160 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void spin(uint32_t usecs) +{ + lk_bigtime_t start = current_time_hires(); + + while ((current_time_hires() - start) < usecs) + ; +} + +void _panic(void *caller, const char *fmt, ...) +{ + printf("panic (caller %p): ", caller); + + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC); +} + +#if !DISABLE_DEBUG_OUTPUT + +static int __panic_stdio_fgetc(void *ctx) +{ + char c; + int err; + + err = platform_pgetc(&c, false); + if (err < 0) + return err; + return (unsigned char)c; +} + +static ssize_t __panic_stdio_read(io_handle_t *io, char *s, size_t len) +{ + if (len == 0) + return 0; + + int err = platform_pgetc(s, false); + if (err < 0) + return err; + + return 1; +} + +static ssize_t __panic_stdio_write(io_handle_t *io, const char *s, size_t len) +{ + for (size_t i = 0; i < len; i++) { + platform_pputc(s[i]); + } + return len; +} + +FILE *get_panic_fd(void) +{ + static const io_handle_hooks_t panic_hooks = { + .write = __panic_stdio_write, + .read = __panic_stdio_read, + }; + static io_handle_t panic_io = { + .magic = IO_HANDLE_MAGIC, + .hooks = &panic_hooks + }; + static FILE panic_fd = { + .io = &panic_io + }; + + return &panic_fd; +} + +void hexdump_ex(const void *ptr, size_t len, uint64_t disp_addr) +{ + addr_t address = (addr_t)ptr; + size_t count; + + for (count = 0 ; count < len; count += 16) { + union { + uint32_t buf[4]; + uint8_t cbuf[16]; + } u; + size_t s = ROUNDUP(MIN(len - count, 16), 4); + size_t i; + + printf(((disp_addr + len) > 0xFFFFFFFF) + ? "0x%016llx: " + : "0x%08llx: ", disp_addr + count); + + for (i = 0; i < s / 4; i++) { + u.buf[i] = ((const uint32_t *)address)[i]; + printf("%08x ", u.buf[i]); + } + for (; i < 4; i++) { + printf(" "); + } + printf("|"); + + for (i=0; i < 16; i++) { + char c = u.cbuf[i]; + if (i < s && isprint(c)) { + printf("%c", c); + } else { + printf("."); + } + } + printf("|\n"); + address += 16; + } +} + +void hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr) +{ + addr_t address = (addr_t)ptr; + size_t count; + size_t i; + + for (count = 0 ; count < len; count += 16) { + printf(((disp_addr + len) > 0xFFFFFFFF) + ? "0x%016llx: " + : "0x%08llx: ", disp_addr + count); + + for (i=0; i < MIN(len - count, 16); i++) { + printf("%02hhx ", *(const uint8_t *)(address + i)); + } + + for (; i < 16; i++) { + printf(" "); + } + + printf("|"); + + for (i=0; i < MIN(len - count, 16); i++) { + char c = ((const char *)address)[i]; + printf("%c", isprint(c) ? c : '.'); + } + + printf("\n"); + address += 16; + } +} + +#endif // !DISABLE_DEBUG_OUTPUT diff --git a/kernel/lib/debug/rules.mk b/kernel/lib/debug/rules.mk new file mode 100644 index 000000000..ab308a8d3 --- /dev/null +++ b/kernel/lib/debug/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c + +include make/module.mk diff --git a/kernel/lib/debugcommands/BUILD.gn b/kernel/lib/debugcommands/BUILD.gn new file mode 100644 index 000000000..3aea27218 --- /dev/null +++ b/kernel/lib/debugcommands/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("debugcommands") { + configs += [ "//kernel/kernel:enable_vm" ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + ] + sources = [ + "debugcommands.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/debug", + ] +} diff --git a/kernel/lib/debugcommands/debugcommands.c b/kernel/lib/debugcommands/debugcommands.c new file mode 100644 index 000000000..d30ecc1f4 --- /dev/null +++ b/kernel/lib/debugcommands/debugcommands.c @@ -0,0 +1,361 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if WITH_KERNEL_VM +#include +#endif + +static int cmd_display_mem(int argc, const cmd_args *argv); +static int cmd_modify_mem(int argc, const cmd_args *argv); +static int cmd_fill_mem(int argc, const cmd_args *argv); +static int cmd_reset(int argc, const cmd_args *argv); +static int cmd_memtest(int argc, const cmd_args *argv); +static int cmd_copy_mem(int argc, const cmd_args *argv); +static int cmd_chain(int argc, const cmd_args *argv); +static int cmd_sleep(int argc, const cmd_args *argv); +static int cmd_crash(int argc, const cmd_args *argv); +static int cmd_stackstomp(int argc, const cmd_args *argv); + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND_MASKED("dw", "display memory in words", &cmd_display_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("dh", "display memory in halfwords", &cmd_display_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("db", "display memory in bytes", &cmd_display_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("mw", "modify word of memory", &cmd_modify_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("mh", "modify halfword of memory", &cmd_modify_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("mb", "modify byte of memory", &cmd_modify_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("fw", "fill range of memory by word", &cmd_fill_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("fh", "fill range of memory by halfword", &cmd_fill_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("fb", "fill range of memory by byte", &cmd_fill_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND_MASKED("mc", "copy a range of memory", &cmd_copy_mem, CMD_AVAIL_ALWAYS) +STATIC_COMMAND("crash", "intentionally crash", &cmd_crash) +STATIC_COMMAND("stackstomp", "intentionally overrun the stack", &cmd_stackstomp) +#endif +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND("mtest", "simple memory test", &cmd_memtest) +#endif +STATIC_COMMAND("chain", "chain load another binary", &cmd_chain) +STATIC_COMMAND("sleep", "sleep number of seconds", &cmd_sleep) +STATIC_COMMAND("sleepm", "sleep number of milliseconds", &cmd_sleep) +STATIC_COMMAND_END(mem); + +static int cmd_display_mem(int argc, const cmd_args *argv) +{ + /* save the last address and len so we can continue where we left off */ + static unsigned long address; + static size_t len; + + if (argc < 3 && len == 0) { + printf("not enough arguments\n"); + printf("%s [-l] [-b] [address] [length]\n", argv[0].str); + return -1; + } + + int size; + if (strcmp(argv[0].str, "dw") == 0) { + size = 4; + } else if (strcmp(argv[0].str, "dh") == 0) { + size = 2; + } else { + size = 1; + } + + uint byte_order = BYTE_ORDER; + int argindex = 1; + bool read_address = false; + while (argc > argindex) { + if (!strcmp(argv[argindex].str, "-l")) { + byte_order = LITTLE_ENDIAN; + } else if (!strcmp(argv[argindex].str, "-b")) { + byte_order = BIG_ENDIAN; + } else if (!read_address) { + address = argv[argindex].u; + read_address = true; + } else { + len = argv[argindex].u; + } + + argindex++; + } + + unsigned long stop = address + len; + int count = 0; + + if ((address & (size - 1)) != 0) { + printf("unaligned address, cannot display\n"); + return -1; + } + +#if WITH_KERNEL_VM + /* preflight the start address to see if it's mapped */ + if (vaddr_to_paddr((void *)address) == 0) { + printf("ERROR: address 0x%lx is unmapped\n", address); + return -1; + } +#endif + + for ( ; address < stop; address += size) { + if (count == 0) + printf("0x%08lx: ", address); + switch (size) { + case 4: { + uint32_t val = (byte_order != BYTE_ORDER) ? + SWAP_32(*(uint32_t *)address) : + *(uint32_t *)address; + printf("%08x ", val); + break; + } + case 2: { + uint16_t val = (byte_order != BYTE_ORDER) ? + SWAP_16(*(uint16_t *)address) : + *(uint16_t *)address; + printf("%04hx ", val); + break; + } + case 1: + printf("%02hhx ", *(uint8_t *)address); + break; + } + count += size; + if (count == 16) { + printf("\n"); + count = 0; + } + } + + if (count != 0) + printf("\n"); + + return 0; +} + +static int cmd_modify_mem(int argc, const cmd_args *argv) +{ + int size; + + if (argc < 3) { + printf("not enough arguments\n"); + printf("%s
\n", argv[0].str); + return -1; + } + + if (strcmp(argv[0].str, "mw") == 0) { + size = 4; + } else if (strcmp(argv[0].str, "mh") == 0) { + size = 2; + } else { + size = 1; + } + + unsigned long address = argv[1].u; + unsigned int val = argv[2].u; + + if ((address & (size - 1)) != 0) { + printf("unaligned address, cannot modify\n"); + return -1; + } + + switch (size) { + case 4: + *(uint32_t *)address = (uint32_t)val; + break; + case 2: + *(uint16_t *)address = (uint16_t)val; + break; + case 1: + *(uint8_t *)address = (uint8_t)val; + break; + } + + return 0; +} + +static int cmd_fill_mem(int argc, const cmd_args *argv) +{ + int size; + + if (argc < 4) { + printf("not enough arguments\n"); + printf("%s
\n", argv[0].str); + return -1; + } + + if (strcmp(argv[0].str, "fw") == 0) { + size = 4; + } else if (strcmp(argv[0].str, "fh") == 0) { + size = 2; + } else { + size = 1; + } + + unsigned long address = argv[1].u; + unsigned long len = argv[2].u; + unsigned long stop = address + len; + unsigned int val = argv[3].u; + + if ((address & (size - 1)) != 0) { + printf("unaligned address, cannot modify\n"); + return -1; + } + + for ( ; address < stop; address += size) { + switch (size) { + case 4: + *(uint32_t *)address = (uint32_t)val; + break; + case 2: + *(uint16_t *)address = (uint16_t)val; + break; + case 1: + *(uint8_t *)address = (uint8_t)val; + break; + } + } + + return 0; +} + +static int cmd_copy_mem(int argc, const cmd_args *argv) +{ + if (argc < 4) { + printf("not enough arguments\n"); + printf("%s \n", argv[0].str); + return -1; + } + + addr_t source = argv[1].u; + addr_t target = argv[2].u; + size_t len = argv[3].u; + + memcpy((void *)target, (const void *)source, len); + + return 0; +} + +static int cmd_memtest(int argc, const cmd_args *argv) +{ + if (argc < 3) { + printf("not enough arguments\n"); + printf("%s \n", argv[0].str); + return -1; + } + + uint32_t *ptr; + size_t len; + + ptr = (uint32_t *)argv[1].u; + len = (size_t)argv[2].u; + + size_t i; + // write out + printf("writing first pass..."); + for (i = 0; i < len / 4; i++) { + ptr[i] = i; + } + printf("done\n"); + + // verify + printf("verifying..."); + for (i = 0; i < len / 4; i++) { + if (ptr[i] != i) + printf("error at %p\n", &ptr[i]); + } + printf("done\n"); + + return 0; +} + +static int cmd_chain(int argc, const cmd_args *argv) +{ + if (argc < 2) { + printf("not enough arguments\n"); + printf("%s
\n", argv[0].str); + return -1; + } + + arch_chain_load(argv[1].p, 0, 0, 0, 0); + + return 0; +} + +static int cmd_sleep(int argc, const cmd_args *argv) +{ + lk_time_t t = 1000; /* default to 1 second */ + + if (argc >= 2) { + t = argv[1].u; + if (!strcmp(argv[0].str, "sleep")) + t *= 1000; + } + + thread_sleep(t); + + return 0; +} + +static int crash_thread(void *arg) +{ + /* should crash */ + volatile uint32_t *ptr = (void *)1; + *ptr = 1; + + return 0; +} + +static int cmd_crash(int argc, const cmd_args *argv) +{ + if (argc > 1) { + if (!strcmp(argv[1].str, "thread")) { + thread_t *t = thread_create("crasher", &crash_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + t->tls[0] = 0; + thread_resume(t); + + thread_join(t, NULL, INFINITE_TIME); + return 0; + } + } + + /* should crash */ + volatile uint32_t *ptr = (void *)1; + *ptr = 1; + + /* if it didn't, panic the system */ + panic("crash"); + + return 0; +} + +static int cmd_stackstomp(int argc, const cmd_args *argv) +{ + for (size_t i = 0; i < DEFAULT_STACK_SIZE * 2; i++) { + uint8_t death[i]; + + memset(death, 0xaa, i); + thread_sleep(1); + } + + printf("survived.\n"); + + return 0; +} + + diff --git a/kernel/lib/debugcommands/rules.mk b/kernel/lib/debugcommands/rules.mk new file mode 100644 index 000000000..33fa2ea56 --- /dev/null +++ b/kernel/lib/debugcommands/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/debug \ + lib/console + +MODULE_SRCS += \ + $(LOCAL_DIR)/debugcommands.c + +include make/module.mk diff --git a/kernel/lib/debuglog/BUILD.gn b/kernel/lib/debuglog/BUILD.gn new file mode 100644 index 000000000..35de31398 --- /dev/null +++ b/kernel/lib/debuglog/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_debuglog") { + if (enable_debuglog) { + defines = [ "WITH_LIB_DEBUGLOG=1" ] + } else { + defines = [ "WITH_LIB_DEBUGLOG=0" ] + } +} + +config("_debuglog_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + configs = [ ":enable_debuglog" ] +} + +module("debuglog") { + public_configs = [ ":_debuglog_config" ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + ] + public = [ + "include/lib/debuglog.h", + ] + sources = [ + "debuglog.c", + ] + deps = [ + "//kernel/lib/user_copy", + ] +} diff --git a/kernel/lib/debuglog/debuglog.c b/kernel/lib/debuglog/debuglog.c new file mode 100644 index 000000000..64dabcd53 --- /dev/null +++ b/kernel/lib/debuglog/debuglog.c @@ -0,0 +1,202 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include + +#define DLOG_SIZE (64 * 1024) + +static uint8_t DLOG_DATA[DLOG_SIZE]; + +static dlog_t DLOG = { + .lock = MUTEX_INITIAL_VALUE(DLOG.lock), + .size = DLOG_SIZE, + .data = DLOG_DATA, + .readers = LIST_INITIAL_VALUE(DLOG.readers), +}; + +#define MAX_DATA_SIZE (DLOG_MAX_ENTRY - sizeof(dlog_record_t)) + +#define ALIGN8(n) (((n) + 7) & (~7)) + +#define REC(ptr, off) ((dlog_record_t*)((ptr) + (off))) + +// To avoid complexity with splitting record headers, this is +// a mostly-circular buffer -- each record has a next index +// that can be used to advance to the next record, allowing the +// leftover space not large enough for a full record at the end +// to be skipped easily. +status_t dlog_write(uint32_t flags, const void* ptr, size_t len) { + dlog_t* log = &DLOG; + + if (arch_ints_disabled()) { + return ERR_BAD_STATE; + } + + if (len > MAX_DATA_SIZE) { + return ERR_TOO_BIG; + } + + // Keep record headers uint64 aligned + size_t sz = ALIGN8(len + sizeof(dlog_record_t)); + + mutex_acquire(&log->lock); + + // Determine location of new record and next record after it + uint32_t dst = log->head; + uint32_t end = log->head + sz; + uint32_t nxt = end; + if ((nxt + DLOG_MAX_ENTRY) > log->size) { + nxt = 0; + } + + // Advance our tail if we write past it. + if (log->head != log->tail) { + while ((log->tail >= dst) && (log->tail < end)) { + log->tail = REC(log->data, log->tail)->next; + } + } + + // Notify readers and advance their tails if necessary + dlog_reader_t* rdr; + list_for_every_entry (&log->readers, rdr, dlog_reader_t, node) { + if (rdr->tail == log->head) { + // Reader view was empty, point reader's tail + // at the message we're writing now + rdr->tail = dst; + } else { + // If we're about to overwrite the message at + // the reader's tail, advance that tail. + // This will never cause the reader view to be "empty". + while ((rdr->tail >= dst) && (rdr->tail < end)) { + rdr->tail = REC(log->data, rdr->tail)->next; + } + } + event_signal(&rdr->event, false); + } + + // Write the new record + dlog_record_t* rec = REC(log->data, dst); + rec->next = nxt; + rec->datalen = len; + rec->flags = flags; + rec->timestamp = current_time_hires() * 1000ULL; + memcpy(rec->data, ptr, len); + + // Advance the head pointer + log->head = nxt; + + mutex_release(&log->lock); + return NO_ERROR; +} + +// TODO: support reading multiple messages at a time +// TODO: filter with flags +status_t dlog_read_etc(dlog_reader_t* rdr, uint32_t flags, void* ptr, size_t len, bool user) { + dlog_t* log = rdr->log; + status_t r = ERR_NO_MSG; + + mutex_acquire(&log->lock); + if (rdr->tail != log->head) { + dlog_record_t* rec = REC(log->data, rdr->tail); + size_t copylen = rec->datalen + sizeof(dlog_record_t); + if (copylen > len) { + r = ERR_NOT_ENOUGH_BUFFER; + } else { + if (user) { + r = copy_to_user(ptr, rec, copylen); + if (r == NO_ERROR) { + r = copylen; + } + } else { + memcpy(ptr, rec, copylen); + r = copylen; + } + rdr->tail = rec->next; + if (rdr->tail == log->head) { + // Nothing left to read, we're in the "empty" state now. + event_unsignal(&rdr->event); + } + } + } + mutex_release(&log->lock); + return r; +} + +void dlog_reader_init(dlog_reader_t* rdr) { + dlog_t* log = &DLOG; + + rdr->log = log; + event_init(&rdr->event, false, 0); + + mutex_acquire(&log->lock); + list_add_tail(&log->readers, &rdr->node); + rdr->tail = log->tail; + if (log->head != log->tail) { + event_signal(&rdr->event, false); + } + mutex_release(&log->lock); +} + +void dlog_reader_destroy(dlog_reader_t* rdr) { + dlog_t* log = rdr->log; + + mutex_acquire(&log->lock); + list_delete(&rdr->node); + event_destroy(&rdr->event); + mutex_release(&log->lock); +} + +void dlog_wait(dlog_reader_t* rdr) { + event_wait(&rdr->event); +} + +static void cputs(const char* data, size_t len) { + while (len-- > 0) { + char c = *data++; + if (c != '\n') { + platform_dputc(c); + } + } +} + +static int debuglog_reader(void* arg) { + uint8_t buffer[DLOG_MAX_ENTRY]; + dlog_record_t* rec = (dlog_record_t*)buffer; + dlog_reader_t reader; + + dlog_reader_init(&reader); + for (;;) { + dlog_wait(&reader); + while (dlog_read(&reader, 0, rec, DLOG_MAX_ENTRY) > 0) { + char tmp[64]; + snprintf(tmp, 64, "[%05d.%03d] %c ", + (int) (rec->timestamp / 1000000000ULL), + (int) ((rec->timestamp / 1000000ULL) % 1000ULL), + (rec->flags & DLOG_FLAG_KERNEL) ? 'K' : 'U'); + cputs(tmp, strlen(tmp)); + cputs(rec->data, rec->datalen); + platform_dputc('\n'); + } + } + return NO_ERROR; +} + +static void dlog_init_hook(uint level) { + thread_t* rthread = thread_create("debuglog-reader", debuglog_reader, NULL, + HIGH_PRIORITY - 1, DEFAULT_STACK_SIZE); + if (rthread) { + thread_resume(rthread); + } +} + +LK_INIT_HOOK(debuglog, dlog_init_hook, LK_INIT_LEVEL_THREADING - 1); diff --git a/kernel/lib/debuglog/include/lib/debuglog.h b/kernel/lib/debuglog/include/lib/debuglog.h new file mode 100644 index 000000000..a7fe69219 --- /dev/null +++ b/kernel/lib/debuglog/include/lib/debuglog.h @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +// clang-format off +#define DLOG_LEVEL_SPEW 0x0000 +#define DLOG_LEVEL_INFO 0x0002 +#define DLOG_LEVEL_WARN 0x0007 +#define DLOG_LEVEL_ERROR 0x000E +#define DLOG_LEVEL_FATAL 0x000F +#define DLOG_LEVEL(n) ((n) & 15) + +#define DLOG_FLAG_KERNEL 0x0100 +#define DLOG_FLAG_DEVMGR 0x0200 +#define DLOG_FLAG_CONSOLE 0x0400 +#define DLOG_FLAG_DEVICE 0x0800 +#define DLOG_FLAG_MASK 0x0F00 + +#define DLOG_FLAG_WAIT 0x80000000 + +#define DLOG_MAX_ENTRY 256 +// clang-format on + +typedef struct dlog dlog_t; +typedef struct dlog_record dlog_record_t; +typedef struct dlog_reader dlog_reader_t; + +struct dlog { + mutex_t lock; + + uint32_t size; + uint32_t head; + uint32_t tail; + void* data; + + struct list_node readers; +}; + +struct dlog_reader { + struct list_node node; + event_t event; + dlog_t* log; + uint32_t tail; +}; + +struct dlog_record { + uint32_t next; + uint16_t datalen; + uint16_t flags; + uint64_t timestamp; + char data[0]; +}; + +void dlog_reader_init(dlog_reader_t* rdr); +void dlog_reader_destroy(dlog_reader_t* rdr); +status_t dlog_write(uint32_t flags, const void* ptr, size_t len); +status_t dlog_read_etc(dlog_reader_t* rdr, uint32_t flags, void* ptr, size_t len, bool user); +static inline status_t dlog_read(dlog_reader_t* rdr, uint32_t flags, void* ptr, size_t len) { + return dlog_read_etc(rdr, flags, ptr, len, false); +} +static inline status_t dlog_read_user(dlog_reader_t* rdr, uint32_t flags, void* uptr, size_t len) { + return dlog_read_etc(rdr, flags, uptr, len, true); +} +void dlog_wait(dlog_reader_t* rdr); + +__END_CDECLS \ No newline at end of file diff --git a/kernel/lib/debuglog/rules.mk b/kernel/lib/debuglog/rules.mk new file mode 100644 index 000000000..b4a1558f4 --- /dev/null +++ b/kernel/lib/debuglog/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/debuglog.c \ + +include make/module.mk diff --git a/kernel/lib/devicetree/BUILD.gn b/kernel/lib/devicetree/BUILD.gn new file mode 100644 index 000000000..e257a93bb --- /dev/null +++ b/kernel/lib/devicetree/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_devicetree_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("devicetree") { + public_configs = [ ":_devicetree_config" ] + sources = [ + "devicetree.c", + ] +} diff --git a/kernel/lib/devicetree/devicetree.c b/kernel/lib/devicetree/devicetree.c new file mode 100644 index 000000000..dc41b1525 --- /dev/null +++ b/kernel/lib/devicetree/devicetree.c @@ -0,0 +1,194 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Brian Swetland +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include "devicetree.h" + +#define DT_MAGIC 0xD00DFEED +#define DT_NODE_BEGIN 1 +#define DT_NODE_END 2 +#define DT_PROP 3 +#define DT_END 9 + +typedef struct dt_slice slice_t; + +u32 dt_rd32(u8 *data) { + return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; +} + +void dt_wr32(u32 n, u8 *data) { + *data++ = n >> 24; + *data++ = n >> 16; + *data++ = n >> 8; + *data = n; +} + +/* init subslice from slice, returning 0 if successful */ +static int sslice(slice_t *src, slice_t *dst, u32 off, u32 len) { + if (off >= src->size) + return -1; + if (len >= src->size) + return -1; + if ((off + len) > src->size) + return -1; + dst->data = src->data + off; + dst->size = len; + return 0; +} + +/* return nonzero if slice is empty */ +static inline int sempty(slice_t *s) { + return s->size == 0; +} + +/* read be32 from slice, + * or 0 (and make slice empty) if slice is too small + */ +static u32 su32(slice_t *s) { + if (s->size < 4) { + s->size = 0; + return 0; + } else { + u32 n = (s->data[0] << 24) | (s->data[1] << 16) | (s->data[2] << 8) | s->data[3]; + s->size -= 4; + s->data += 4; + return n; + } +} + +/* return pointer to data in slice, + * or 0 (and make slice empty) if slice is too small + */ +static void *sdata(slice_t *s, u32 len) { + if (len > s->size) { + s->size = 0; + return 0; + } else { + void *data = s->data; + s->size -= len; + s->data += len; + while (len & 3) { + if (s->size) { + s->size++; + s->data++; + } + len++; + } + return data; + } +} + +/* return pointer to string in slice, + * or "" (and make slice empty) if slice is too small + */ +static const char *sstring(slice_t *s) { + u32 sz = s->size; + u8 *end = s->data; + const char *data; + while (sz-- > 0) { + if (*end++ == 0) { + while (((end - s->data) & 3) && (sz > 0)) { + end++; + sz--; + } + data = (const char*) s->data; + s->size = sz; + s->data = end; + return data; + } + } + s->size = 0; + return ""; +} + +static int oops(devicetree_t *dt, const char *msg) { + if (dt->error) + dt->error(msg); + return -1; +} + +int dt_init(devicetree_t *dt, void *data, u32 len) { + slice_t s; + + dt->top.data = data; + dt->top.size = len; + + s = dt->top; + + dt->hdr.magic = su32(&s); + dt->hdr.size = su32(&s); + dt->hdr.off_struct = su32(&s); + dt->hdr.off_strings = su32(&s); + dt->hdr.off_reserve = su32(&s); + dt->hdr.version = su32(&s); + dt->hdr.version_compat = su32(&s); + dt->hdr.boot_cpuid = su32(&s); + dt->hdr.sz_strings = su32(&s); + dt->hdr.sz_struct = su32(&s); + + if (dt->hdr.magic != DT_MAGIC) + return oops(dt, "bad magic"); + if (dt->hdr.size > dt->top.size) + return oops(dt, "bogus size field"); + if (dt->hdr.version != 17) + return oops(dt, "version != 17"); + if (sslice(&dt->top, &dt->dt, dt->hdr.off_struct, dt->hdr.sz_struct)) + return oops(dt, "invalid structure off/len"); + if (sslice(&dt->top, &dt->ds, dt->hdr.off_strings, dt->hdr.sz_strings)) + return oops(dt, "invalid strings off/len"); + + return 0; +} + +int dt_walk(devicetree_t *dtree, dt_node_cb ncb, dt_prop_cb pcb, void *cookie) { + const char *p; + void *data; + u32 depth = 0; + slice_t dt, ds; + u32 sz, str; + + dt = dtree->dt; + ds = dtree->ds; + + while (!sempty(&dt)) { + u32 type = su32(&dt); + switch (type) { + case DT_END: + if (depth) + return oops(dtree, "unexpected DT_END"); + return 0; + case DT_NODE_BEGIN: + depth++; + p = sstring(&dt); + if (ncb(depth, p, cookie)) + return 0; + break; + case DT_NODE_END: + if (depth == 0) + return oops(dtree, "unexpected NODE_END"); + depth--; + break; + case DT_PROP: + if (depth == 0) + return oops(dtree, "PROP outside of NODE"); + sz = su32(&dt); + str = su32(&dt); + data = sdata(&dt, sz); + if (pcb((const char*) (ds.data + str), data, sz, cookie)) + return 0; + break; + default: + return oops(dtree, "invalid node type"); + + } + } + + if (depth != 0) + return oops(dtree, "incomplete tree"); + + return 0; +} diff --git a/kernel/lib/devicetree/devicetreedump.c b/kernel/lib/devicetree/devicetreedump.c new file mode 100644 index 000000000..a9f425904 --- /dev/null +++ b/kernel/lib/devicetree/devicetreedump.c @@ -0,0 +1,96 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Brian Swetland +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include "devicetree.h" + +#include +#include +#include +#include +#include + +void error(const char *msg) { + printf("error: %s\n", msg); +}; + +void indent(u32 n) { + while (n-- > 0) + putchar(' '); +} + +void hexdump(u8 *data, u32 count) { + while (count-- > 0) + printf("%02x ", *data++); +} + +int loadfile(const char *fn, dt_slice_t *out) { + void *data = NULL; + off_t end; + int fd; + if ((fd = open(fn, O_RDONLY)) < 0) + return -1; + if ((end = lseek(fd, 0, SEEK_END)) == -1) + goto oops; + if (lseek(fd, 0, SEEK_SET)) + goto oops; + if ((data = malloc(end + 1)) == NULL) + goto oops; + if ((read(fd, data, end) != end)) + goto oops; + out->data = data; + out->size = end; + close(fd); + return 0; +oops: + free(data); + close(fd); + return -1; +} + +static int _depth = 0; + +int node_cb(int depth, const char *name, void *cookie) { + _depth = depth; + indent(depth*2); + printf("node: '%s'\n", name); + return 0; +} + +int prop_cb(const char *name, u8 *data, u32 size, void *cookie) { + indent(_depth * 2 + 2); + printf("prop '%s' sz=%d\n", name, size); + indent(_depth * 2 + 2); + printf("data "); + hexdump(data, size); + printf("\n"); + return 0; +} + +int main(int argc, char **argv) { + devicetree_t dt; + dt_slice_t s; + + dt.error = error; + + if (argc != 2) + return -1; + if (loadfile(argv[1], &s)) + return -1; + if (dt_init(&dt, s.data, s.size)) + return -1; + + printf("magic %x\n", dt.hdr.magic); + printf("size %d\n", dt.hdr.size); + printf("off_struct %d (%d)\n", dt.hdr.off_struct, dt.hdr.sz_struct); + printf("off_strings %d (%d)\n", dt.hdr.off_strings, dt.hdr.sz_strings); + printf("version %d (min %d)\n", dt.hdr.version, dt.hdr.version_compat); + + dt_walk(&dt, node_cb, prop_cb, NULL); + return 0; +} + diff --git a/kernel/lib/devicetree/include/lib/devicetree.h b/kernel/lib/devicetree/include/lib/devicetree.h new file mode 100644 index 000000000..9b2d1af31 --- /dev/null +++ b/kernel/lib/devicetree/include/lib/devicetree.h @@ -0,0 +1,50 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Brian Swetland +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef _DEVICETREE_H_ +#define _DEVICETREE_H_ + +#include + +typedef struct dt_slice { + u8 *data; + u32 size; +} dt_slice_t; + +struct devicetree_header { + u32 magic; + u32 size; + u32 off_struct; // offset from start to DT 'structure' + u32 off_strings; // offset from start to stringdata + u32 off_reserve; // offset from start to reserve memory map + u32 version; + u32 version_compat; // last compatible version + u32 boot_cpuid; + u32 sz_strings; // size of stringdata + u32 sz_struct; // size of DT 'structure' +}; + +typedef struct devicetree { + dt_slice_t top; + dt_slice_t dt; + dt_slice_t ds; + struct devicetree_header hdr; + void (*error)(const char *msg); +} devicetree_t; + +typedef int (*dt_node_cb)(int depth, const char *name, void *cookie); +typedef int (*dt_prop_cb)(const char *name, u8 *data, u32 size, void *cookie); + +int dt_init(devicetree_t *dt, void *data, u32 len); +int dt_walk(devicetree_t *dt, dt_node_cb ncb, dt_prop_cb pcb, void *cookie); + +u32 dt_rd32(u8 *data); +void dt_wr32(u32 n, u8 *data); + +#endif + diff --git a/kernel/lib/devicetree/rules.mk b/kernel/lib/devicetree/rules.mk new file mode 100644 index 000000000..6293222d2 --- /dev/null +++ b/kernel/lib/devicetree/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/devicetree.c + +include make/module.mk diff --git a/kernel/lib/elf/BUILD.gn b/kernel/lib/elf/BUILD.gn new file mode 100644 index 000000000..3ace56e87 --- /dev/null +++ b/kernel/lib/elf/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_elf_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("elf") { + public_configs = [ ":_elf_config" ] + public = [ + "include/lib/elf_defines.h", + "include/lib/elf.h", + ] + sources = [ + "elf.cpp", + ] + deps = [ + "//kernel/lib/bio", + "//kernel/lib/libc", + "//kernel/lib/user_copy", + "//kernel/lib/utils", + ] +} diff --git a/kernel/lib/elf/elf.cpp b/kernel/lib/elf/elf.cpp new file mode 100644 index 000000000..4cfb20289 --- /dev/null +++ b/kernel/lib/elf/elf.cpp @@ -0,0 +1,367 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +namespace ElfLoader { + +// conditionally define a 32 or 64 bit version of the data structures +// we care about, based on our bitness. +#if WITH_ELF32 +#define ELF_OFF_PRINT_U "%u" +#define ELF_OFF_PRINT_X "%x" +#define ELF_ADDR_PRINT_U "%u" +#define ELF_ADDR_PRINT_X "%x" +#else +#define ELF_OFF_PRINT_U "%llu" +#define ELF_OFF_PRINT_X "%llx" +#define ELF_ADDR_PRINT_U "%llu" +#define ELF_ADDR_PRINT_X "%llx" +#endif + +static int verify_eheader(const elf_ehdr* eheader) { + if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) return ERR_NOT_FOUND; + +#if WITH_ELF32 + if (eheader->e_ident[EI_CLASS] != ELFCLASS32) return ERR_NOT_FOUND; +#else + if (eheader->e_ident[EI_CLASS] != ELFCLASS64) return ERR_NOT_FOUND; +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN + if (eheader->e_ident[EI_DATA] != ELFDATA2LSB) return ERR_NOT_FOUND; +#elif BYTE_ORDER == BIG_ENDIAN + if (eheader->e_ident[EI_DATA] != ELFDATA2MSB) return ERR_NOT_FOUND; +#endif + + if (eheader->e_ident[EI_VERSION] != EV_CURRENT) return ERR_NOT_FOUND; + + if (eheader->e_phoff == 0) return ERR_NOT_FOUND; + + if (eheader->e_phentsize < sizeof(elf_phdr)) return ERR_NOT_FOUND; + +#if ARCH_ARM + if (eheader->e_machine != EM_ARM) return ERR_NOT_FOUND; +#elif ARCH_ARM64 + if (eheader->e_machine != EM_AARCH64) return ERR_NOT_FOUND; +#elif ARCH_X86_64 + if (eheader->e_machine != EM_X86_64) return ERR_NOT_FOUND; +#elif ARCH_X86_32 + if (eheader->e_machine != EM_386) return ERR_NOT_FOUND; +#elif ARCH_MICROBLAZE + if (eheader->e_machine != EM_MICROBLAZE) return ERR_NOT_FOUND; +#else +#error find proper EM_ define for your machine +#endif + + return NO_ERROR; +} + +status_t File::Load() { + // validate that this is an ELF file + size_t bytes_read; + status_t err = Read(&eheader_, 0, sizeof(eheader_), &bytes_read); + if (err < 0 || bytes_read < sizeof(eheader_)) { + LTRACEF("couldn't read elf header\n"); + return ERR_NOT_FOUND; + } + + if (verify_eheader(reinterpret_cast(&eheader_))) { + LTRACEF("header not valid\n"); + return ERR_NOT_FOUND; + } + + // sanity check number of program headers + LTRACEF("number of program headers %u, entry size %u\n", eheader_.e_phnum, + eheader_.e_phentsize); + if (eheader_.e_phnum > 16 || eheader_.e_phentsize != sizeof(elf_phdr)) { + LTRACEF("too many program headers or bad size\n"); + return ERR_NO_MEMORY; + } + + // at this point e_phentsize == sizeof(elf_phdr) so we can use the sizeof + + // allocate and read in the program headers + size_t buffer_size = eheader_.e_phnum * sizeof(elf_phdr); + pheaders_.reset(new elf_phdr[eheader_.e_phnum], eheader_.e_phnum); + if (!pheaders_) { + LTRACEF("failed to allocate memory for program headers\n"); + return ERR_NO_MEMORY; + } + + err = Read(pheaders_.get(), eheader_.e_phoff, buffer_size, &bytes_read); + if (err < 0 || bytes_read < buffer_size) { + LTRACEF("failed to read program headers\n"); + return ERR_NO_MEMORY; + } + + LTRACEF("program headers:\n"); + uint seg_num = 0; + for (uint i = 0; i < eheader_.e_phnum; i++) { + // parse the program headers + elf_phdr* pheader = &pheaders_[i]; + + LTRACEF("%u: type %u offset 0x" ELF_OFF_PRINT_X " vaddr " ELF_ADDR_PRINT_X + " paddr " ELF_ADDR_PRINT_X " memsiz " ELF_ADDR_PRINT_U " filesize " ELF_ADDR_PRINT_U + "\n", + i, pheader->p_type, pheader->p_offset, pheader->p_vaddr, pheader->p_paddr, + pheader->p_memsz, pheader->p_filesz); + + // we only care about PT_LOAD segments at the moment + if (pheader->p_type == PT_LOAD) { + // allocate a block of memory to back the segment + status_t err = AllocateSegment((vaddr_t)pheader->p_vaddr, pheader->p_memsz, seg_num); + if (err < 0) { + LTRACEF("mem hook failed, abort\n"); + // XXX clean up what we got so far + return err; + } + + void* ptr = (void*)(uintptr_t)pheader->p_vaddr; + + // read the file portion of the segment into memory at vaddr + LTRACEF("reading segment at offset 0x" ELF_OFF_PRINT_X " to address %p\n", + pheader->p_offset, ptr); + err = Read(seg_num, 0, pheader->p_offset, pheader->p_filesz, &bytes_read); + if (err < 0 || bytes_read < pheader->p_filesz) { + LTRACEF("error %d (bytes_read %zu) reading program header %u\n", err, bytes_read, + i); + return (err < 0) ? err : ERR_IO; + } + + // zero out he difference between memsz and filesz + size_t tozero = pheader->p_memsz - pheader->p_filesz; + if (tozero > 0) { + LTRACEF("zeroing memory in segment %u, offset 0x%zx, size 0x%zx\n", seg_num, + (size_t)pheader->p_filesz, tozero); + + ZeroSegment(seg_num, pheader->p_filesz, tozero); + } + + // track the number of load segments we have seen to pass the mem alloc hook + seg_num++; + } + } + + // save the entry point + entry_ = eheader_.e_entry; + + loaded_ = true; + + FreeResources(); + + return NO_ERROR; +} + +status_t ToMemFile::AllocateSegment(vaddr_t vaddr, size_t len, uint seg_num) { + LTRACEF("%p, vaddr 0x%lx, len %zu, seg_num %u\n", this, vaddr, len, seg_num); + + if (seg_num >= SEG_COUNT) return ERR_INVALID_ARGS; + + // make sure the segment isn't already loaded + if (seg_[seg_num].va) return ERR_INVALID_ARGS; + + char name[32]; + snprintf(name, sizeof(name), "%s_seg%u", name_, seg_num); + + // allocate a vm object to back this segment + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, ROUNDUP(len, PAGE_SIZE)); + if (!vmo) return ERR_NO_MEMORY; + + // map it into the address space + void* ptr = (void*)vaddr; + auto err = + aspace_->MapObject(vmo, name, 0, len, &ptr, 0, VMM_FLAG_VALLOC_SPECIFIC | VMM_FLAG_COMMIT, + aspace_->is_user() ? ARCH_MMU_FLAG_PERM_USER : 0); + if (err < 0) return err; + + // save the pointer + seg_[seg_num].vmo = utils::move(vmo); + seg_[seg_num].va = (vaddr_t)ptr; + seg_[seg_num].len = len; + + return NO_ERROR; +} + +// zero memory within a particular segment, if overridden +// XXX temporary until pmm gives us zeroed pages +status_t ToMemFile::ZeroSegment(uint seg_num, size_t seg_offset, size_t len) { + LTRACEF("%p, seg num %u, seg_offset 0x%zx, len %zu\n", this, seg_num, seg_offset, len); + + size_t offset = seg_offset; + VmObject* vmo = seg_[seg_num].vmo.get(); + + size_t end = offset + len; + while (offset < end) { + size_t page_offset = offset % PAGE_SIZE; + size_t tozero = MIN(end - offset, PAGE_SIZE - page_offset); + + LTRACEF("offset 0x%zx, tozero 0x%zx\n", offset, tozero); + + // TODO: move this logic to using a write method on the vm object directly + + // get a pointer to the underlying page in the object + auto p = vmo->FaultPage(ROUNDDOWN(offset, PAGE_SIZE), VMM_PF_FLAG_WRITE); + LTRACEF("page %p\n", p); + if (!p) { + panic("unhandled bad fault while reading into vm object\n"); + } + + // compute the kernel mapping of this page + paddr_t pa = vm_page_to_paddr(p); + LTRACEF("pa 0x%lx\n", pa); + + uint8_t* ptr = (uint8_t*)paddr_to_kvaddr(pa); + ptr += page_offset; + LTRACEF("ptr %p\n", ptr); + + // memset it + memset(ptr, 0, tozero); + + // get to the next page boundary + size_t tonext = PAGE_SIZE - page_offset; + offset += tonext; + } + + return NO_ERROR; +} + +ToMemFile::segment ToMemFile::GetSegment(uint seg_num) { + if (seg_num >= SEG_COUNT) return {}; + + return seg_[seg_num]; +} + +// memory to memory loader + +MemFile::MemFile(const char* name, utils::RefPtr aspace, const void* src_ptr, + size_t src_len) + : ToMemFile(name, aspace), src_ptr_(src_ptr), src_len_(src_len) {} + +MemFile::~MemFile() {} + +// memory from the source into the segment at a particular offset +status_t MemFile::Read(uint seg_num, size_t seg_offset, size_t source_offset, size_t len, + size_t* bytes_read) { + LTRACEF("%p, seg %u, seg_offset %zu source_offset 0x%zx, len %zu\n", this, seg_num, seg_offset, + source_offset, len); + + *bytes_read = 0; + if (seg_num >= SEG_COUNT) return ERR_INVALID_ARGS; + if (!seg_[seg_num].va) return ERR_INVALID_ARGS; + + size_t toread = len; + if (source_offset >= src_len_) toread = 0; + if (source_offset + len >= src_len_) toread = src_len_ - source_offset; + + VmObject* vmo = seg_[seg_num].vmo.get(); + DEBUG_ASSERT(vmo); + + size_t bytes_written; + status_t err = vmo->Write((const uint8_t*)src_ptr_ + source_offset, seg_offset, toread, &bytes_written); + if (err < 0) return err; + if (bytes_written != toread) return ERR_IO; + + *bytes_read = toread; + return NO_ERROR; +} + +// memory from the source into memory +status_t MemFile::Read(void* ptr, size_t source_offset, size_t len, size_t* bytes_read) { + LTRACEF("%p, ptr %p source_offset 0x%zx, len %zu\n", this, ptr, source_offset, len); + + *bytes_read = 0; + + ssize_t toread = len; + if (source_offset >= src_len_) toread = 0; + if (source_offset + len >= src_len_) toread = src_len_ - source_offset; + + memcpy(ptr, (const uint8_t*)src_ptr_ + source_offset, toread); + + *bytes_read = toread; + return NO_ERROR; +} + +// block device to memory loader +BioToMemFile::BioToMemFile(const char* name, utils::RefPtr aspace, bdev* bdev, + uint64_t bdev_offset, uint64_t bdev_len) + : ToMemFile(name, aspace), bdev_(bdev), bdev_offset_(bdev_offset), bdev_len_(bdev_len) {} + +BioToMemFile::~BioToMemFile() {} + +// memory from the source into the segment at a particular offset +status_t BioToMemFile::Read(uint seg_num, size_t seg_offset, size_t source_offset, size_t len, + size_t* bytes_read) { + LTRACEF("%p, seg %u, seg_offset %zu source_offset 0x%zx, len %zu\n", this, seg_num, seg_offset, + source_offset, len); + + *bytes_read = 0; + if (seg_num >= SEG_COUNT) return ERR_INVALID_ARGS; + if (!seg_[seg_num].va) return ERR_INVALID_ARGS; + + size_t offset = seg_offset; + VmObject* vmo = seg_[seg_num].vmo.get(); + DEBUG_ASSERT(vmo); + + // allocate a temporary buffer for the read operation + utils::Array temp_buf(new uint8_t[PAGE_SIZE], PAGE_SIZE); + if (!temp_buf) return ERR_NO_MEMORY; + + size_t end = offset + len; + while (offset < end) { + size_t toread = MIN(end - offset, PAGE_SIZE); + size_t page_offset = offset % PAGE_SIZE; + + LTRACEF("offset 0x%zx, toread 0x%zx\n", offset, toread); + + // to the bio read into our temporary buffer + ssize_t readerr = bio_read(bdev_, temp_buf.get(), source_offset + bdev_offset_, toread); + if (readerr < 0 || static_cast(readerr) != toread) { + return ERR_IO; + } + + // write the data out to the object + size_t bytes_written; + status_t err = vmo->Write(temp_buf.get(), offset, toread, &bytes_written); + if (err < 0) return err; + if (bytes_written != toread) return ERR_IO; + + // get to the next page boundary + size_t tonext = PAGE_SIZE - page_offset; + offset += tonext; + source_offset += tonext; + *bytes_read += tonext; + } + + return NO_ERROR; +} + +// memory from the source into memory +status_t BioToMemFile::Read(void* ptr, size_t source_offset, size_t len, size_t* bytes_read) { + LTRACEF("%p, ptr %p source_offset 0x%zx, len %zu\n", this, ptr, source_offset, len); + + *bytes_read = 0; + ssize_t ret = bio_read(bdev_, ptr, source_offset + bdev_offset_, len); + if (ret < 0) return static_cast(ret); + *bytes_read = static_cast(ret); + return NO_ERROR; +} + +} // ElfLoader diff --git a/kernel/lib/elf/include/lib/elf.h b/kernel/lib/elf/include/lib/elf.h new file mode 100644 index 000000000..c58180899 --- /dev/null +++ b/kernel/lib/elf/include/lib/elf.h @@ -0,0 +1,168 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// based on our bitness, support 32 or 64 bit elf +#if IS_64BIT +#define WITH_ELF64 1 +#else +#define WITH_ELF32 1 +#endif + +// forward declaration +struct bdev; + +namespace ElfLoader { + +// some local typedefs to help disambiguate between 32 and 64bit +#if WITH_ELF32 +using elf_ehdr = Elf32_Ehdr; +using elf_phdr = Elf32_Phdr; +#else +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +#endif + +// pure virtual base class for loading a file from a generic place +class File { +public: + File(const char* name = nullptr) { + strlcpy(name_, name ? name : "unnamed", sizeof(name_)); + } + virtual ~File() {} + + File(const File&) = delete; + + status_t Load(); + + bool loaded() const { + return loaded_; + } + addr_t load_address() const { + return load_address_; + } + addr_t entry() const { + return entry_; + } + + // subclass overloaded versions for allocating and reading data + + // Called by the loader to allocate memory for a segment. + // Handle holds a pointer to the allocated memory + virtual status_t AllocateSegment(vaddr_t vaddr, size_t len, uint seg_num) = 0; + + // memory from the source into the segment at a particular offset + virtual status_t Read(uint seg_num, size_t seg_offset, size_t source_offset, size_t len, + size_t* bytes_read) = 0; + + // memory from the source into memory + virtual status_t Read(void* ptr, size_t source_offset, size_t len, size_t* bytes_read) = 0; + + // called when done loading, subclass can free any resources it had + virtual void FreeResources() {} + + // zero memory within a particular segment, if overridden + virtual status_t ZeroSegment(uint seg_num, size_t seg_offset, size_t len) { + return NO_ERROR; + } + +protected: + char name_[32]; + +private: + bool loaded_ = false; + + // after loading, these hold the load address and entry point + addr_t load_address_ = 0; + addr_t entry_ = 0; + + // loaded info about the elf file + elf_ehdr eheader_ = {}; // a copy of the main elf header + utils::Array pheaders_; // a pointer to a buffer of program headers +}; + +// partial implementation for loading from something to vmm allocated memory +class ToMemFile : public File { +public: + ToMemFile(const char* name, utils::RefPtr aspace) + : File(name), aspace_(utils::move(aspace)) {} + virtual ~ToMemFile() override {} + + // Called by the loader to allocate memory for a segment. + // Handle holds a pointer to the allocated memory + virtual status_t AllocateSegment(vaddr_t vaddr, size_t len, uint seg_num) override; + + // zero memory within a particular segment, if overridden + virtual status_t ZeroSegment(uint seg_num, size_t seg_offset, size_t len) override; + + // a loaded segment + struct segment { + utils::RefPtr vmo; + vaddr_t va; + size_t len; + }; + + // return a segment + segment GetSegment(uint seg_num); + +protected: + utils::RefPtr aspace_; + + static const size_t SEG_COUNT = 16; + segment seg_[SEG_COUNT] = {}; +}; + +// fully overloaded implementation for loading from memory to vmm allocated memory +class MemFile : public ToMemFile { +public: + MemFile(const char* name, utils::RefPtr aspace, const void* src_ptr, size_t src_len); + virtual ~MemFile() override; + + // memory from the source into the segment at a particular offset + virtual status_t Read(uint seg_num, size_t seg_offset, size_t source_offset, size_t len, + size_t* bytes_read) override; + + // memory from the source into a buffer used by the loader + virtual status_t Read(void* ptr, size_t source_offset, size_t len, size_t* bytes_read) override; + +private: + const void* src_ptr_; + size_t src_len_; +}; + +// fully overloaded implementation for loading from a block device to vmm allocated memory +class BioToMemFile : public ToMemFile { +public: + BioToMemFile(const char* name, utils::RefPtr aspace, struct bdev* bdev, + uint64_t bdev_offset, uint64_t bdev_len); + virtual ~BioToMemFile() override; + + // memory from the source into the segment at a particular offset + virtual status_t Read(uint seg_num, size_t seg_offset, size_t source_offset, size_t len, + size_t* bytes_read) override; + + // memory from the source into a buffer used by the loader + virtual status_t Read(void* ptr, size_t source_offset, size_t len, size_t* bytes_read) override; + +private: + bdev* bdev_; + uint64_t bdev_offset_; + uint64_t bdev_len_; +}; + +}; // namespace Elf diff --git a/kernel/lib/elf/include/lib/elf_defines.h b/kernel/lib/elf/include/lib/elf_defines.h new file mode 100644 index 000000000..cbaef6feb --- /dev/null +++ b/kernel/lib/elf/include/lib/elf_defines.h @@ -0,0 +1,573 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +/* elf defines */ +#define ELF_MAGIC "\x7f""ELF" + +/* e_ident */ +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +/* e_machine */ +#define EM_NONE 0 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_MIPS 8 +#define EM_SPARC32PLUS 18 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_ARM 40 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_IA_64 50 +#define EM_X86_64 62 +#define EM_OR1K 92 +#define EM_AARCH64 183 +#define EM_MICROBLAZE 189 +#define EM_ALPHA 0x9026 + +/* e_ident[EI_CLASS] */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +/* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +/* e_ident[EI_VERSION] */ +#define EV_CURRENT 1 + +/* e_type */ +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 + +/* e_flags */ +#define EF_ARM_RELEXEC 0x1 +#define EF_ARM_HASENTRY 0x2 +#define EF_ARM_SYMSARESORTED 0x4 +#define EF_ARM_DYNSYMSUSESEGIDX 0x8 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_LE8 0x00400000 +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_EABIMASK 0xFF000000 +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 +#define EF_ARM_INTERWORK 0x00000004 +#define EF_ARM_APCS_26 0x00000008 +#define EF_ARM_APCS_FLOAT 0x00000010 +#define EF_ARM_PIC 0x00000020 +#define EF_ARM_ALIGN8 0x00000040 +#define EF_ARM_NEW_ABI 0x00000080 +#define EF_ARM_OLD_ABI 0x00000100 +#define EF_ARM_SOFT_FLOAT 0x00000200 +#define EF_ARM_VFP_FLOAT 0x00000400 +#define EF_ARM_MAVERICK_FLOAT 0x00000800 + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_TLS 0x400 +#define SHF_MASKPROC 0xf0000000 + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 +#define PF_MASKPROC 0xf0000000 + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_TLS 6 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STN_UNDEF 0 + +/* d_tag */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6fff0000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* + * i386 relocation types + */ +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +/* + * x86-64 relocation types + */ +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DPTMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 +#define R_X86_64_TLSLD 20 +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 +#define R_X86_64_TPOFF32 23 + +/* + * sh4 relocation types + */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 + +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_LOOP_START 36 +#define R_SH_LOOP_END 37 +#define R_SH_DIR5U 45 +#define R_SH_DIR6U 46 +#define R_SH_DIR6S 47 +#define R_SH_DIR10S 48 +#define R_SH_DIR10SW 49 +#define R_SH_DIR10SL 50 +#define R_SH_DIR10SQ 51 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +#define R_SH_GOTPLT32 168 +#define R_SH_GOT_LOW16 169 +#define R_SH_GOT_MEDLOW16 170 +#define R_SH_GOT_MEDHI16 171 +#define R_SH_GOT_HI16 172 +#define R_SH_GOTPLT_LOW16 173 +#define R_SH_GOTPLT_MEDLOW16 174 +#define R_SH_GOTPLT_MEDHI16 175 +#define R_SH_GOTPLT_HI16 176 +#define R_SH_PLT_LOW16 177 +#define R_SH_PLT_MEDLOW16 178 +#define R_SH_PLT_MEDHI16 179 +#define R_SH_PLT_HI16 180 +#define R_SH_GOTOFF_LOW16 181 +#define R_SH_GOTOFF_MEDLOW16 182 +#define R_SH_GOTOFF_MEDHI16 183 +#define R_SH_GOTOFF_HI16 184 +#define R_SH_GOTPC_LOW16 185 +#define R_SH_GOTPC_MEDLOW16 186 +#define R_SH_GOTPC_MEDHI16 187 +#define R_SH_GOTPC_HI16 188 +#define R_SH_GOT10BY4 189 +#define R_SH_GOTPLT10BY4 190 +#define R_SH_GOT10BY8 191 +#define R_SH_GOTPLT10BY8 192 +#define R_SH_COPY64 193 +#define R_SH_GLOB_DAT64 194 +#define R_SH_JMP_SLOT64 195 +#define R_SH_RELATIVE64 196 +#define R_SH_SHMEDIA_CODE 242 +#define R_SH_PT_16 243 +#define R_SH_IMMS16 244 +#define R_SH_IMMU16 245 +#define R_SH_IMM_LOW16 246 +#define R_SH_IMM_LOW16_PCREL 247 +#define R_SH_IMM_MEDLOW16 248 +#define R_SH_IMM_MEDLOW16_PCREL 249 +#define R_SH_IMM_MEDHI16 250 +#define R_SH_IMM_MEDHI16_PCREL 251 +#define R_SH_IMM_HI16 252 +#define R_SH_IMM_HI16_PCREL 253 +#define R_SH_64 254 +#define R_SH_64_PCREL 255 + +/* + * ppc relocation types + */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +#define R_PPC_NUM 37 + +/* + * ARM relocation types + */ +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +/* elf32 stuff */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +struct Elf32_Shdr { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +}; + +struct Elf32_Phdr { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +struct Elf32_Sym { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xf)) + +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +struct Elf32_Dyn { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +/* elf64 stuff */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef int64_t Elf64_Sxword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Lword; +typedef uint64_t Elf64_Xword; + + +struct Elf64_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +}; + +struct Elf64_Shdr { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +}; + +struct Elf64_Phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +}; + +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info) & 0xf) +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +struct Elf64_Rel { + Elf64_Addr r_offset; + Elf64_Xword r_info; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +}; + +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xffffffffL) + +#define ELF64_R_INFO(sym, type) (((sym) << 32) + ((type) & 0xffffffffL)) + +#define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info)<<32)>>40) +#define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info)<<56)>>56) +#define ELF64_R_TYPE_INFO(data, type) (((Elf64_Xword)(data)<<8)+(Elf64_Xword)(type)) + diff --git a/kernel/lib/elf/rules.mk b/kernel/lib/elf/rules.mk new file mode 100644 index 000000000..9477674b8 --- /dev/null +++ b/kernel/lib/elf/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/elf.cpp + +MODULE_DEPS := \ + lib/user_copy \ + lib/bio \ + +include make/module.mk diff --git a/kernel/lib/evlog/BUILD.gn b/kernel/lib/evlog/BUILD.gn new file mode 100644 index 000000000..fd769a814 --- /dev/null +++ b/kernel/lib/evlog/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("evlog") { + sources = [ + "evlog.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/evlog/evlog.c b/kernel/lib/evlog/evlog.c new file mode 100644 index 000000000..d799a681e --- /dev/null +++ b/kernel/lib/evlog/evlog.c @@ -0,0 +1,66 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +#define INCPTR(e, ptr, inc) \ + modpow2((ptr) + (inc), (e)->len_pow2) + +status_t evlog_init_etc(evlog_t *e, uint len, uint unitsize, uintptr_t *items) +{ + if (len < 2 || !ispow2(len)) { + return ERR_INVALID_ARGS; + } + if (unitsize < 1 || !ispow2(unitsize)) { + return ERR_INVALID_ARGS; + } + if (unitsize > len) { + return ERR_INVALID_ARGS; + } + + e->head = 0; + e->unitsize = unitsize; + e->len_pow2 = log2_uint(len); + e->items = items; + + return NO_ERROR; +} + +status_t evlog_init(evlog_t *e, uint len, uint unitsize) +{ + uintptr_t *items = calloc(1, len * sizeof(uintptr_t)); + if (!items) { + return ERR_NO_MEMORY; + } + + status_t err = evlog_init_etc(e, len, unitsize, items); + if (err < 0) + free(items); + return err; +} + +uint evlog_bump_head(evlog_t *e) +{ + uint index = e->head; + e->head = INCPTR(e, e->head, e->unitsize); + + return index; +} + +void evlog_dump(evlog_t *e, evlog_dump_cb cb) +{ + for (uint index = INCPTR(e, e->head, e->unitsize); index != e->head; index = INCPTR(e, index, e->unitsize)) { + cb(&e->items[index]); + } +} + + diff --git a/kernel/lib/evlog/rules.mk b/kernel/lib/evlog/rules.mk new file mode 100644 index 000000000..df03e8195 --- /dev/null +++ b/kernel/lib/evlog/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/evlog.c + +include make/module.mk diff --git a/kernel/lib/fixed_point/BUILD.gn b/kernel/lib/fixed_point/BUILD.gn new file mode 100644 index 000000000..d89180e85 --- /dev/null +++ b/kernel/lib/fixed_point/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_fixed_point_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("fixed_point") { + public_configs = [ ":_fixed_point_config" ] + public = [ + "include/lib/fixed_point.h", + "include/lib/fixed_point_debug.h", + ] + sources = [ + "fixed_point.c", + ] +} diff --git a/kernel/lib/fixed_point/fixed_point.c b/kernel/lib/fixed_point/fixed_point.c new file mode 100644 index 000000000..6fceac90d --- /dev/null +++ b/kernel/lib/fixed_point/fixed_point.c @@ -0,0 +1,6 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + diff --git a/kernel/lib/fixed_point/include/lib/fixed_point.h b/kernel/lib/fixed_point/include/lib/fixed_point.h new file mode 100644 index 000000000..890b87342 --- /dev/null +++ b/kernel/lib/fixed_point/include/lib/fixed_point.h @@ -0,0 +1,124 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include + +#ifndef DEBUG_FIXED_POINT +#define DEBUG_FIXED_POINT 0 +#endif + +struct fp_32_64 { + uint32_t l0; /* unshifted value */ + uint32_t l32; /* value shifted left 32 bits (or bit -1 to -32) */ + uint32_t l64; /* value shifted left 64 bits (or bit -33 to -64) */ +}; + +#include "fixed_point_debug.h" + +static void +fp_32_64_div_32_32(struct fp_32_64 *result, uint32_t dividend, uint32_t divisor) +{ + uint64_t tmp; + uint32_t rem; + + tmp = ((uint64_t)dividend << 32) / divisor; + rem = ((uint64_t)dividend << 32) % divisor; + result->l0 = tmp >> 32; + result->l32 = tmp; + tmp = ((uint64_t)rem << 32) / divisor; + result->l64 = tmp; +} + +static uint64_t +mul_u32_u32(uint32_t a, uint32_t b, int a_shift, int b_shift) +{ + uint64_t ret = (uint64_t)a * b; + debug_mul_u32_u32(a, b, a_shift, b_shift, ret); + return ret; +} + +static uint64_t +u64_mul_u32_fp32_64(uint32_t a, struct fp_32_64 b) +{ + uint64_t tmp; + uint64_t res_0; + uint64_t res_l32; + uint32_t res_l32_32; + uint64_t ret; + + res_0 = mul_u32_u32(a, b.l0, 0, 0); + tmp = mul_u32_u32(a, b.l32, 0, -32); + res_0 += tmp >> 32; + res_l32 = (uint32_t)tmp; + res_l32 += mul_u32_u32(a, b.l64, 0, -64) >> 32; /* Improve rounding accuracy */ + res_0 += res_l32 >> 32; + res_l32_32 = res_l32; + ret = res_0 + (res_l32_32 >> 31); /* Round to nearest integer */ + + debug_u64_mul_u32_fp32_64(a, b, res_0, res_l32_32, ret); + + return ret; +} + +static uint32_t +u32_mul_u64_fp32_64(uint64_t a, struct fp_32_64 b) +{ + uint32_t a_r32 = a >> 32; + uint32_t a_0 = a; + uint64_t res_l32; + uint32_t ret; + + /* mul_u32_u32(a_r32, b.l0, 32, 0) does not affect result */ + res_l32 = mul_u32_u32(a_0, b.l0, 0, 0) << 32; + res_l32 += mul_u32_u32(a_r32, b.l32, 32, -32) << 32; + res_l32 += mul_u32_u32(a_0, b.l32, 0, -32); + res_l32 += mul_u32_u32(a_r32, b.l64, 32, -64); + res_l32 += mul_u32_u32(a_0, b.l64, 0, -64) >> 32; /* Improve rounding accuracy */ + ret = (res_l32 >> 32) + ((uint32_t)res_l32 >> 31); /* Round to nearest integer */ + + debug_u32_mul_u64_fp32_64(a, b, res_l32, ret); + + return ret; +} + +static uint64_t +u64_mul_u64_fp32_64(uint64_t a, struct fp_32_64 b) +{ + uint32_t a_r32 = a >> 32; + uint32_t a_0 = a; + uint64_t res_0; + uint64_t res_l32; + uint32_t res_l32_32; + uint64_t tmp; + uint64_t ret; + + tmp = mul_u32_u32(a_r32, b.l0, 32, 0); + res_0 = tmp << 32; + tmp = mul_u32_u32(a_0, b.l0, 0, 0); + res_0 += tmp; + tmp = mul_u32_u32(a_r32, b.l32, 32, -32); + res_0 += tmp; + tmp = mul_u32_u32(a_0, b.l32, 0, -32); + res_0 += tmp >> 32; + res_l32 = (uint32_t)tmp; + tmp = mul_u32_u32(a_r32, b.l64, 32, -64); + res_0 += tmp >> 32; + res_l32 += (uint32_t)tmp; + tmp = mul_u32_u32(a_0, b.l64, 0, -64); /* Improve rounding accuracy */ + res_l32 += tmp >> 32; + res_0 += res_l32 >> 32; + res_l32_32 = res_l32; + ret = res_0 + (res_l32_32 >> 31); /* Round to nearest integer */ + + debug_u64_mul_u64_fp32_64(a, b, res_0, res_l32_32, ret); + + return ret; +} + diff --git a/kernel/lib/fixed_point/include/lib/fixed_point_debug.h b/kernel/lib/fixed_point/include/lib/fixed_point_debug.h new file mode 100644 index 000000000..9192f8752 --- /dev/null +++ b/kernel/lib/fixed_point/include/lib/fixed_point_debug.h @@ -0,0 +1,121 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google Inc. All rights reserved. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +static const char * +fpd_shift_prefix_32(int shift) +{ + switch (shift) { + case 32: + return ""; + case 0: + return " "; + case -32: + return " 0."; + case -64: + return " 0.00000000 "; + default: + return "???"; + } +} + +static const char * +fpd_shift_prefix_64(int shift) +{ + switch (shift) { + case 32: + return ""; + case 0: + return " "; + case -32: + return " "; + case -64: + return " 0."; + default: + return "???"; + } +} + +static const char * +fpd_shift_suffix(int shift) +{ + switch (shift) { + case 32: + return " 00000000 "; + case 0: + return " "; + case -32: + return " "; + case -64: + return ""; + default: + return "???"; + } +} + +static void +debug_mul_u32_u32(uint32_t a, uint32_t b, int a_shift, int b_shift, uint64_t ret) +{ +#if DEBUG_FIXED_POINT + TRACEF(" %s%08x%s * %s%08x%s = %s%08x%s%08x%s\n", + fpd_shift_prefix_32(a_shift), a, fpd_shift_suffix(a_shift), + fpd_shift_prefix_32(b_shift), b, fpd_shift_suffix(b_shift), + fpd_shift_prefix_64(a_shift + b_shift), + (uint32_t)(ret >> 32), + (a_shift + b_shift == -32) ? "." : " ", + (uint32_t)ret, + fpd_shift_suffix(a_shift + b_shift)); +#endif +} + +static void +debug_u64_mul_u32_fp32_64(uint32_t a, struct fp_32_64 b, uint64_t res_0, uint32_t res_l32_32, uint64_t ret) +{ +#if DEBUG_FIXED_POINT + TRACEF(" %08x * %08x.%08x %08x" + " = %08x %08x.%08x\n", + a, b.l0, b.l32, b.l64, + (uint32_t)(res_0 >> 32), (uint32_t)res_0, res_l32_32); + TRACEF(" " + " " + "~= %08x %08x\n", + (uint32_t)(ret >> 32), (uint32_t)ret); +#endif +} + +static void +debug_u32_mul_u64_fp32_64(uint64_t a, struct fp_32_64 b, uint64_t res_l32, uint32_t ret) +{ +#if DEBUG_FIXED_POINT + TRACEF("%08x %08x * %08x.%08x %08x" + " = %08x.%08x\n", + (uint32_t)(a >> 32), (uint32_t)a, b.l0, b.l32, b.l64, + (uint32_t)(res_l32 >> 32), (uint32_t)res_l32); + TRACEF(" " + " " + "~= %08x\n", + ret); +#endif +} + +static void +debug_u64_mul_u64_fp32_64(uint64_t a, struct fp_32_64 b, uint64_t res_0, uint32_t res_l32_32, uint64_t ret) +{ +#if DEBUG_FIXED_POINT + TRACEF("%08x %08x * %08x.%08x %08x" + " = %08x %08x.%08x\n", + (uint32_t)(a >> 32), (uint32_t)a, b.l0, b.l32, b.l64, + (uint32_t)(res_0 >> 32), (uint32_t)res_0, res_l32_32); + TRACEF(" " + " " + "~= %08x %08x\n", + (uint32_t)(ret >> 32), (uint32_t)ret); +#endif +} + diff --git a/kernel/lib/fixed_point/rules.mk b/kernel/lib/fixed_point/rules.mk new file mode 100644 index 000000000..f348903ef --- /dev/null +++ b/kernel/lib/fixed_point/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/fixed_point.c + +include make/module.mk diff --git a/kernel/lib/font/BUILD.gn b/kernel/lib/font/BUILD.gn new file mode 100644 index 000000000..320eaca9d --- /dev/null +++ b/kernel/lib/font/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("font") { + sources = [ + "font.c", + "font.h", + ] + deps = [ + "//kernel/lib/gfx", + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/font/font.c b/kernel/lib/font/font.c new file mode 100644 index 000000000..df584614c --- /dev/null +++ b/kernel/lib/font/font.c @@ -0,0 +1,46 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Font display + * + * This file contains functions to render fonts onto the graphics drawing + * surface. + * + * @ingroup graphics + */ + +#include +#include +#include + +#include "font.h" + +/** + * @brief Draw one character from the built-in font + * + * @ingroup graphics + */ +void font_draw_char(gfx_surface *surface, unsigned char c, int x, int y, uint32_t color, uint32_t bgcolor) +{ + uint i,j; + uint line; + + // draw this char into a buffer + for (i = 0; i < FONT_Y; i++) { + line = FONT[c * FONT_Y + i]; + for (j = 0; j < FONT_X; j++) { + gfx_putpixel(surface, x + j, y + i, (line & 1) ? color : bgcolor); + line = line >> 1; + } + } + gfx_flush_rows(surface, y, y + FONT_Y); +} + + diff --git a/kernel/lib/font/font.h b/kernel/lib/font/font.h new file mode 100644 index 000000000..5062e12cc --- /dev/null +++ b/kernel/lib/font/font.h @@ -0,0 +1,144 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +/* derived from a font by Brian Swetland ages ago */ +#ifndef __FONT_H +#define __FONT_H + +static const unsigned char FONT[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '!' */ + 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '"' */ + 0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /* '#' */ + 0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /* '$' */ + 0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /* '%' */ + 0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /* '&' */ + 0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ''' */ + 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /* '(' */ + 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /* ')' */ + 0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /* '*' */ + 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* '+' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ',' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '-' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* '.' */ + 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* '/' */ + 0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '0' */ + 0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* '1' */ + 0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* '2' */ + 0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '3' */ + 0x00, 0x10, 0x18, 0x18, 0x14, 0x14, 0x3e, 0x10, 0x38, 0x00, 0x00, 0x00, /* '4' */ + 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '5' */ + 0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '6' */ + 0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /* '7' */ + 0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '8' */ + 0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /* '9' */ + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ':' */ + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ';' */ + 0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /* '<' */ + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /* '=' */ + 0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /* '>' */ + 0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '?' */ + 0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /* '@' */ + 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'A' */ + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'B' */ + 0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'C' */ + 0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /* 'D' */ + 0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'E' */ + 0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'F' */ + 0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'G' */ + 0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'H' */ + 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /* 'I' */ + 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'J' */ + 0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'K' */ + 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'L' */ + 0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'M' */ + 0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /* 'N' */ + 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'O' */ + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'P' */ + 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /* 'Q' */ + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'R' */ + 0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'S' */ + 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'T' */ + 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'U' */ + 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'V' */ + 0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /* 'W' */ + 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'X' */ + 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'Y' */ + 0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'Z' */ + 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /* '[' */ + 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /* '\' */ + 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /* ']' */ + 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '^' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /* '_' */ + 0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '`' */ + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'a' */ + 0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'b' */ + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /* 'c' */ + 0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /* 'e' */ + 0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /* 'f' */ + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'g' */ + 0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'h' */ + 0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'i' */ + 0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /* 'j' */ + 0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /* 'k' */ + 0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'l' */ + 0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /* 'm' */ + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'n' */ + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'o' */ + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /* 'p' */ + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /* 'q' */ + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'r' */ + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /* 's' */ + 0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /* 't' */ + 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'u' */ + 0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'v' */ + 0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /* 'w' */ + 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /* 'x' */ + 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'y' */ + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /* 'z' */ + 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /* '{' */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* '|' */ + 0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /* '}' */ + 0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '~' */ + 0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /* '' */ +}; + +#endif + diff --git a/kernel/lib/font/rules.mk b/kernel/lib/font/rules.mk new file mode 100644 index 000000000..985fb562e --- /dev/null +++ b/kernel/lib/font/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += lib/gfx + +MODULE_SRCS += \ + $(LOCAL_DIR)/font.c + +include make/module.mk diff --git a/kernel/lib/gfx/BUILD.gn b/kernel/lib/gfx/BUILD.gn new file mode 100644 index 000000000..20357b651 --- /dev/null +++ b/kernel/lib/gfx/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("gfx") { + sources = [ + "gfx.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/gfx/gfx.c b/kernel/lib/gfx/gfx.c new file mode 100644 index 000000000..692e04aa0 --- /dev/null +++ b/kernel/lib/gfx/gfx.c @@ -0,0 +1,860 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2010, 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @defgroup graphics Graphics + * + * @{ + */ + +/** + * @file + * @brief Graphics drawing library + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +// Convert a 32bit ARGB image to its respective gamma corrected grayscale value. +static uint32_t ARGB8888_to_Luma(uint32_t in) +{ + uint8_t out; + + uint32_t blue = (in & 0xFF) * 74; + uint32_t green = ((in >> 8) & 0xFF) * 732; + uint32_t red = ((in >> 16) & 0xFF) * 218; + + uint32_t intensity = red + blue + green; + + out = (intensity >> 10) & 0xFF; + + return out; +} + +static uint32_t ARGB8888_to_RGB565(uint32_t in) +{ + uint16_t out; + + out = (in >> 3) & 0x1f; // b + out |= ((in >> 10) & 0x3f) << 5; // g + out |= ((in >> 19) & 0x1f) << 11; // r + + return out; +} + +static uint32_t ARGB8888_to_RGB332(uint32_t in) +{ + uint8_t out = 0; + + out = (in >> 6) & 0x3; // b + out |= ((in >> 13) & 0x7) << 2; // g + out |= ((in >> 21) & 0x7) << 5; // r + + return out; +} + +static uint32_t ARGB8888_to_RGB2220(uint32_t in) +{ + uint8_t out = 0; + + out = ((in >> 6) & 0x3) << 2; + out |= ((in >> 14) & 0x3) << 4; + out |= ((in >> 22) & 0x3) << 6; + + return out; +} + +/** + * @brief Copy a rectangle of pixels from one part of the display to another. + */ +void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // trim + if (x >= surface->width) + return; + if (x2 >= surface->width) + return; + if (y >= surface->height) + return; + if (y2 >= surface->height) + return; + if (width == 0 || height == 0) + return; + + // clip the width to src or dest + if (x + width > surface->width) + width = surface->width - x; + if (x2 + width > surface->width) + width = surface->width - x2; + + // clip the height to src or dest + if (y + height > surface->height) + height = surface->height - y; + if (y2 + height > surface->height) + height = surface->height - y2; + + surface->copyrect(surface, x, y, width, height, x2, y2); +} + +/** + * @brief Fill a rectangle on the screen with a constant color. + */ +void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + LTRACEF("surface %p, x %u y %u w %u h %u c %u\n", surface, x, y, width, height, color); + // trim + if (unlikely(x >= surface->width)) + return; + if (y >= surface->height) + return; + if (width == 0 || height == 0) + return; + + // clip the width + if (x + width > surface->width) + width = surface->width - x; + + // clip the height + if (y + height > surface->height) + height = surface->height - y; + + surface->fillrect(surface, x, y, width, height, color); +} + +/** + * @brief Write a single pixel to the screen. + */ +void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color) +{ + if (unlikely(x >= surface->width)) + return; + if (y >= surface->height) + return; + + surface->putpixel(surface, x, y, color); +} + +static void putpixel16(gfx_surface *surface, uint x, uint y, uint color) +{ + uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride]; + + // colors come in in ARGB 8888 form, flatten them + *dest = (uint16_t)(surface->translate_color(color)); +} + +static void putpixel32(gfx_surface *surface, uint x, uint y, uint color) +{ + uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride]; + + *dest = color; +} + +static void putpixel8(gfx_surface *surface, uint x, uint y, uint color) +{ + uint8_t *dest = &((uint8_t *)surface->ptr)[x + y * surface->stride]; + + // colors come in in ARGB 8888 form, flatten them + *dest = (uint8_t)(surface->translate_color(color)); +} + +static void copyrect8(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // copy + const uint8_t *src = &((const uint8_t *)surface->ptr)[x + y * surface->stride]; + uint8_t *dest = &((uint8_t *)surface->ptr)[x2 + y2 * surface->stride]; + uint stride_diff = surface->stride - width; + + if (dest < src) { + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += stride_diff; + src += stride_diff; + } + } else { + // copy backwards + src += height * surface->stride + width; + dest += height * surface->stride + width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest--; + src--; + } + dest -= stride_diff; + src -= stride_diff; + } + } +} + +static void fillrect8(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + uint8_t *dest = &((uint8_t *)surface->ptr)[x + y * surface->stride]; + uint stride_diff = surface->stride - width; + + uint8_t color8 = (uint8_t)(surface->translate_color(color)); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = color8; + dest++; + } + dest += stride_diff; + } +} + +static void copyrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // copy + const uint16_t *src = &((const uint16_t *)surface->ptr)[x + y * surface->stride]; + uint16_t *dest = &((uint16_t *)surface->ptr)[x2 + y2 * surface->stride]; + uint stride_diff = surface->stride - width; + + if (dest < src) { + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += stride_diff; + src += stride_diff; + } + } else { + // copy backwards + src += height * surface->stride + width; + dest += height * surface->stride + width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest--; + src--; + } + dest -= stride_diff; + src -= stride_diff; + } + } +} + +static void fillrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride]; + uint stride_diff = surface->stride - width; + + uint16_t color16 = (uint16_t)(surface->translate_color(color)); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = color16; + dest++; + } + dest += stride_diff; + } +} + +static void copyrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // copy + const uint32_t *src = &((const uint32_t *)surface->ptr)[x + y * surface->stride]; + uint32_t *dest = &((uint32_t *)surface->ptr)[x2 + y2 * surface->stride]; + uint stride_diff = surface->stride - width; + + if (dest < src) { + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += stride_diff; + src += stride_diff; + } + } else { + // copy backwards + src += height * surface->stride + width; + dest += height * surface->stride + width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest--; + src--; + } + dest -= stride_diff; + src -= stride_diff; + } + } +} + +static void fillrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride]; + uint stride_diff = surface->stride - width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = color; + dest++; + } + dest += stride_diff; + } +} + +void gfx_line(gfx_surface *surface, uint x1, uint y1, uint x2, uint y2, uint color) +{ + if (unlikely(x1 >= surface->width)) + return; + if (unlikely(x2 >= surface->width)) + return; + + if (y1 >= surface->height) + return; + if (y2 >= surface->height) + return; + + int dx = x2 - x1; + int dy = y2 - y1; + + int sdx = (0 < dx) - (dx < 0); + int sdy = (0 < dy) - (dy < 0); + + uint dxabs = (dx > 0) ? dx : -dx; + uint dyabs = (dy > 0) ? dy : -dy; + + uint x = dyabs >> 1; + uint y = dxabs >> 1; + + uint px = x1; + uint py = y1; + + if (dxabs >= dyabs) { + // mostly horizontal line. + for (uint i = 0; i < dxabs; i++) { + y += dyabs; + if (y >= dxabs) { + y -= dxabs; + py += sdy; + } + px += sdx; + surface->putpixel(surface, px, py, color); + } + } else { + // mostly vertical line. + for (uint i = 0; i < dyabs; i++) { + x += dxabs; + if (x >= dyabs) { + x -= dyabs; + px += sdx; + } + py += sdy; + surface->putpixel(surface, px, py, color); + } + } +} + +uint32_t alpha32_add_ignore_destalpha(uint32_t dest, uint32_t src) +{ + uint32_t cdest[3]; + uint32_t csrc[3]; + + uint32_t srca; + uint32_t srcainv; + + srca = (src >> 24) & 0xff; + if (srca == 0) { + return dest; + } else if (srca == 255) { + return src; + } + srca++; + srcainv = (255 - srca); + + cdest[0] = (dest >> 16) & 0xff; + cdest[1] = (dest >> 8) & 0xff; + cdest[2] = (dest >> 0) & 0xff; + + csrc[0] = (src >> 16) & 0xff; + csrc[1] = (src >> 8) & 0xff; + csrc[2] = (src >> 0) & 0xff; + +// if (srca > 0) +// printf("s %d %d %d d %d %d %d a %d ai %d\n", csrc[0], csrc[1], csrc[2], cdest[0], cdest[1], cdest[2], srca, srcainv); + + uint32_t cres[3]; + + cres[0] = ((csrc[0] * srca) / 256) + ((cdest[0] * srcainv) / 256); + cres[1] = ((csrc[1] * srca) / 256) + ((cdest[1] * srcainv) / 256); + cres[2] = ((csrc[2] * srca) / 256) + ((cdest[2] * srcainv) / 256); + + return (srca << 24) | (cres[0] << 16) | (cres[1] << 8) | (cres[2]); +} + +/** + * @brief Copy pixels from source to dest. + * + * Currently does not support alpha channel. + */ +void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty) +{ + DEBUG_ASSERT(target->format == source->format); + + LTRACEF("target %p, source %p, destx %u, desty %u\n", target, source, destx, desty); + + if (destx >= target->width) + return; + if (desty >= target->height) + return; + + uint width = source->width; + if (destx + width > target->width) + width = target->width - destx; + + uint height = source->height; + if (desty + height > target->height) + height = target->height - desty; + + // XXX total hack to deal with various blends + if (source->format == GFX_FORMAT_RGB_565 && target->format == GFX_FORMAT_RGB_565) { + // 16 bit to 16 bit + const uint16_t *src = (const uint16_t *)source->ptr; + uint16_t *dest = &((uint16_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else if (source->format == GFX_FORMAT_ARGB_8888 && target->format == GFX_FORMAT_ARGB_8888) { + // both are 32 bit modes, both alpha + const uint32_t *src = (const uint32_t *)source->ptr; + uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + // XXX ignores destination alpha + *dest = alpha32_add_ignore_destalpha(*dest, *src); + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else if (source->format == GFX_FORMAT_RGB_x888 && target->format == GFX_FORMAT_RGB_x888) { + // both are 32 bit modes, no alpha + const uint32_t *src = (const uint32_t *)source->ptr; + uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else if (source->format == GFX_FORMAT_MONO && target->format == GFX_FORMAT_MONO) { + // both are 8 bit modes, no alpha + const uint8_t *src = (const uint8_t *)source->ptr; + uint8_t *dest = &((uint8_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else { + panic("gfx_surface_blend: unimplemented colorspace combination (source %d target %d)\n", source->format, target->format); + } +} + +/** + * @brief Ensure all graphics rendering is sent to display + */ +void gfx_flush(gfx_surface *surface) +{ + if (surface->flags & GFX_FLAG_FLUSH_CPU_CACHE) + arch_clean_cache_range((addr_t)surface->ptr, surface->len); + + if (surface->flush) + surface->flush(0, surface->height-1); +} + +/** + * @brief Ensure that a sub-region of the display is up to date. + */ +void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end) +{ + if (start > end) { + uint temp = start; + start = end; + end = temp; + } + + if (start >= surface->height) + return; + if (end >= surface->height) + end = surface->height - 1; + + if (surface->flags & GFX_FLAG_FLUSH_CPU_CACHE) { + uint32_t runlen = surface->stride * surface->pixelsize; + arch_clean_cache_range((addr_t)surface->ptr + start * runlen, (end - start + 1) * runlen); + } + + if (surface->flush) + surface->flush(start, end); +} + +/** + * @brief Create a new graphics surface object + */ +gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags) +{ + gfx_surface *surface = calloc(1, sizeof(*surface)); + if (surface == NULL) return NULL; + if (gfx_init_surface(surface, ptr, width, height, stride, format, flags)) { + free(surface); + return NULL; + } + return surface; +} + +int gfx_init_surface(gfx_surface *surface, void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags) +{ + DEBUG_ASSERT(width > 0); + DEBUG_ASSERT(height > 0); + DEBUG_ASSERT(stride >= width); + DEBUG_ASSERT(format < GFX_FORMAT_MAX); + + surface->flags = flags; + surface->format = format; + surface->width = width; + surface->height = height; + surface->stride = stride; + surface->alpha = MAX_ALPHA; + + // set up some function pointers + switch (format) { + case GFX_FORMAT_RGB_565: + surface->translate_color = &ARGB8888_to_RGB565; + surface->copyrect = ©rect16; + surface->fillrect = &fillrect16; + surface->putpixel = &putpixel16; + surface->pixelsize = 2; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_RGB_x888: + case GFX_FORMAT_ARGB_8888: + surface->translate_color = NULL; + surface->copyrect = ©rect32; + surface->fillrect = &fillrect32; + surface->putpixel = &putpixel32; + surface->pixelsize = 4; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_MONO: + surface->translate_color = &ARGB8888_to_Luma; + surface->copyrect = ©rect8; + surface->fillrect = &fillrect8; + surface->putpixel = &putpixel8; + surface->pixelsize = 1; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_RGB_332: + surface->translate_color = &ARGB8888_to_RGB332; + surface->copyrect = ©rect8; + surface->fillrect = &fillrect8; + surface->putpixel = &putpixel8; + surface->pixelsize = 1; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_RGB_2220: + surface->translate_color = &ARGB8888_to_RGB2220; + surface->copyrect = ©rect8; + surface->fillrect = &fillrect8; + surface->putpixel = &putpixel8; + surface->pixelsize = 1; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + default: + dprintf(INFO, "invalid graphics format\n"); + return ERR_INVALID_ARGS; + } + + if (ptr == NULL) { + // allocate a buffer + ptr = malloc(surface->len); + if (ptr == NULL) { + return ERR_NO_MEMORY; + } + DEBUG_ASSERT(ptr); + surface->flags |= GFX_FLAG_FREE_ON_DESTROY; + } + surface->ptr = ptr; + return 0; +} + +/** + * @brief Create a new graphics surface object from a display + */ +gfx_surface *gfx_create_surface_from_display(struct display_info *info) +{ + gfx_surface *surface = calloc(1, sizeof(*surface)); + if (surface == NULL) + return NULL; + if (gfx_init_surface_from_display(surface, info)) { + free(surface); + return NULL; + } + return surface; +} + +int gfx_init_surface_from_display(gfx_surface *surface, struct display_info *info) +{ + int r; + gfx_format format; + switch (info->format) { + case DISPLAY_FORMAT_RGB_565: + format = GFX_FORMAT_RGB_565; + break; + case DISPLAY_FORMAT_RGB_332: + format = GFX_FORMAT_RGB_332; + break; + case DISPLAY_FORMAT_RGB_2220: + format = GFX_FORMAT_RGB_2220; + break; + case DISPLAY_FORMAT_ARGB_8888: + format = GFX_FORMAT_ARGB_8888; + break; + case DISPLAY_FORMAT_RGB_x888: + format = GFX_FORMAT_RGB_x888; + break; + case DISPLAY_FORMAT_MONO_8: + format = GFX_FORMAT_MONO; + break; + case DISPLAY_FORMAT_MONO_1: + format = GFX_FORMAT_MONO; + break; + default: + DEBUG_ASSERT_MSG(0, "invalid graphics format %u", info->format); + return ERR_INVALID_ARGS; + } + + uint32_t flags = (info->flags & DISPLAY_FLAG_NEEDS_CACHE_FLUSH) ? GFX_FLAG_FLUSH_CPU_CACHE : 0; + r = gfx_init_surface(surface, info->framebuffer, info->width, info->height, info->stride, format, flags); + + surface->flush = info->flush; + return r; +} + +/** + * @brief Destroy a graphics surface and free all resources allocated to it. + * + * @param surface Surface to destroy. This pointer is no longer valid after + * this call. + */ +void gfx_surface_destroy(struct gfx_surface *surface) +{ + if (surface->flags & GFX_FLAG_FREE_ON_DESTROY) + free(surface->ptr); + free(surface); +} + +/** + * @brief Write a test pattern to the default display. + */ +void gfx_draw_pattern(void) +{ + struct display_info info; + if (display_get_info(&info) < 0) + return; + + gfx_surface *surface = gfx_create_surface_from_display(&info); + + uint x, y; + for (y = 0; y < surface->height; y++) { + for (x = 0; x < surface->width; x++) { + uint scaledx; + uint scaledy; + + scaledx = x * 256 / surface->width; + scaledy = y * 256 / surface->height; + + gfx_putpixel(surface, x, y, (0xff << 24) | (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1); + } + } + + gfx_flush(surface); + + gfx_surface_destroy(surface); +} + +/** + * @brief Fill default display with white + */ +void gfx_draw_pattern_white(void) +{ + struct display_info info; + if (display_get_info(&info) < 0) + return; + + gfx_surface *surface = gfx_create_surface_from_display(&info); + + uint x, y; + for (y = 0; y < surface->height; y++) { + for (x = 0; x < surface->width; x++) { + gfx_putpixel(surface, x, y, 0xFFFFFFFF); + } + } + + gfx_flush(surface); + + gfx_surface_destroy(surface); +} + +#if defined(WITH_LIB_CONSOLE) + +#if LK_DEBUGLEVEL > 1 +#include + +static int cmd_gfx(int argc, const cmd_args *argv); + +STATIC_COMMAND_START +STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx) +STATIC_COMMAND_END(gfx); + +static int gfx_draw_rgb_bars(gfx_surface *surface) +{ + uint x, y; + + uint step = surface->height*100 / 256; + uint color; + + for (y = 0; y < surface->height; y++) { + //R + for (x = 0; x < surface->width/3; x++) { + color = y*100 / step; + gfx_putpixel(surface, x, y, 0xff << 24 | color << 16); + } + //G + for (; x < 2*(surface->width/3); x++) { + color = y*100 / step; + gfx_putpixel(surface, x, y, 0xff << 24 | color << 8); + } + //B + for (; x < surface->width; x++) { + color = y*100 / step; + gfx_putpixel(surface, x, y, 0xff << 24 | color); + } + } + + return 0; +} + +static int cmd_gfx(int argc, const cmd_args *argv) +{ + if (argc < 2) { + printf("not enough arguments:\n"); + printf("%s display_info : output information bout the current display\n", argv[0].str); + printf("%s rgb_bars : Fill frame buffer with rgb bars\n", argv[0].str); + printf("%s test_pattern : Fill frame with test pattern\n", argv[0].str); + printf("%s fill r g b : Fill frame buffer with RGB888 value and force update\n", argv[0].str); + + return -1; + } + + struct display_info info; + if (display_get_info(&info) < 0) { + printf("no display to draw on!\n"); + return -1; + } + + gfx_surface *surface = gfx_create_surface_from_display(&info); + + if (!strcmp(argv[1].str, "display_info")) { + printf("display:\n"); + printf("\tframebuffer %p\n", info.framebuffer); + printf("\twidth %u height %u stride %u\n", info.width, info.height, info.stride); + printf("\tformat %u\n", info.format); + printf("\tflags 0x%x\n", info.flags); + } else if (!strcmp(argv[1].str, "rgb_bars")) { + gfx_draw_rgb_bars(surface); + } else if (!strcmp(argv[1].str, "test_pattern")) { + gfx_draw_pattern(); + } else if (!strcmp(argv[1].str, "fill")) { + uint x, y; + + for (y = 0; y < surface->height; y++) { + for (x = 0; x < surface->width; x++) { + /* write pixel to frame buffer */ + gfx_putpixel(surface, x, y, (0xff << 24) | (argv[2].i << 16) | (argv[3].i << 8) | argv[4].i); + } + } + } + + gfx_flush(surface); + + gfx_surface_destroy(surface); + + return 0; +} + +#endif +#endif diff --git a/kernel/lib/gfx/rules.mk b/kernel/lib/gfx/rules.mk new file mode 100644 index 000000000..f7719c384 --- /dev/null +++ b/kernel/lib/gfx/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/gfx.c + +include make/module.mk diff --git a/kernel/lib/gfxconsole/BUILD.gn b/kernel/lib/gfxconsole/BUILD.gn new file mode 100644 index 000000000..256ca58f0 --- /dev/null +++ b/kernel/lib/gfxconsole/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("gfxconsole") { + sources = [ + "gfxconsole.c", + ] + deps = [ + "//kernel/lib/font", + "//kernel/lib/libc", + ] + public_deps = [ + "//kernel/lib/gfx", + ] +} diff --git a/kernel/lib/gfxconsole/gfxconsole.c b/kernel/lib/gfxconsole/gfxconsole.c new file mode 100644 index 000000000..bc465315e --- /dev/null +++ b/kernel/lib/gfxconsole/gfxconsole.c @@ -0,0 +1,303 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2010, 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Manage graphics console + * + * This file contains functions to provide stdout to the graphics console. + * + * @ingroup graphics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEXT_COLOR 0xffffffff +#define BACK_COLOR 0x00000000 + +/** @addtogroup graphics + * @{ + */ + +/** + * @brief Represent state of graphics console + */ +static struct { + // main surface to draw on + gfx_surface *surface; + // underlying hw surface, if different from above + gfx_surface *hw_surface; + + // surface to do single line sub-region flushing with + gfx_surface line; + uint linestride; + + uint rows, columns; + uint extray; // extra pixels left over if the rows doesn't fit precisely + + uint x, y; + + uint32_t front_color; + uint32_t back_color; +} gfxconsole; + +static void draw_char(char c) +{ + font_draw_char(gfxconsole.surface, c, gfxconsole.x * FONT_X, gfxconsole.y * FONT_Y, + gfxconsole.front_color, gfxconsole.back_color); +} + +static bool gfxconsole_putc(char c) +{ + static enum { NORMAL, ESCAPE } state = NORMAL; + static uint32_t p_num = 0; + bool inval = 0; + + if (state == NORMAL) { + switch (c) { + case '\r': + gfxconsole.x = 0; + break; + case '\n': + gfxconsole.y++; + inval = 1; + break; + case '\b': + // back up one character unless we're at the left side + if (gfxconsole.x > 0) { + gfxconsole.x--; + } + break; + case '\t': + gfxconsole.x = ROUNDUP(gfxconsole.x + 1, 8); + break; + case 0x1b: + p_num = 0; + state = ESCAPE; + break; + default: + draw_char(c); + gfxconsole.x++; + break; + } + } else if (state == ESCAPE) { + if (c >= '0' && c <= '9') { + p_num = (p_num * 10) + (c - '0'); + } else if (c == 'D') { + if (p_num <= gfxconsole.x) + gfxconsole.x -= p_num; + state = NORMAL; + } else if (c == '[') { + // eat this character + } else { + draw_char(c); + gfxconsole.x++; + state = NORMAL; + } + } + + if (gfxconsole.x >= gfxconsole.columns) { + gfxconsole.x = 0; + gfxconsole.y++; + inval = 1; + } + if (gfxconsole.y >= gfxconsole.rows) { + // scroll up + gfx_copyrect(gfxconsole.surface, 0, FONT_Y, gfxconsole.surface->width, + gfxconsole.surface->height - FONT_Y - gfxconsole.extray, 0, 0); + gfxconsole.y--; + + // clear the bottom line + gfx_fillrect(gfxconsole.surface, 0, gfxconsole.surface->height - FONT_Y - gfxconsole.extray, + gfxconsole.surface->width, FONT_Y, gfxconsole.back_color); + gfx_flush(gfxconsole.surface); + inval = 1; + } + return inval; +} + +void gfxconsole_print_callback(print_callback_t *cb, const char *str, size_t len) +{ + int refresh_full_screen = 0; + for (size_t i = 0; i < len; i++) { + if (str[i] == '\n') + gfxconsole_putc('\r'); + refresh_full_screen |= gfxconsole_putc(str[i]); + } + + // blit from the software surface to the hardware + if (gfxconsole.surface != gfxconsole.hw_surface) { + if (refresh_full_screen) { + gfx_surface_blend(gfxconsole.hw_surface, gfxconsole.surface, 0, 0); + } else { + // Only re-blit the active console line. + // Since blend only works in whole surfaces, configure a sub-surface + // to use as the blend source. + gfxconsole.line.ptr = ((uint8_t*) gfxconsole.surface->ptr) + + (gfxconsole.y * gfxconsole.linestride); + gfx_surface_blend(gfxconsole.hw_surface, &gfxconsole.line, + 0, gfxconsole.y * FONT_Y); + } + gfx_flush(gfxconsole.hw_surface); + } +} + +static print_callback_t cb = { + .entry = { 0 }, + .print = gfxconsole_print_callback, + .context = NULL +}; + +static void gfxconsole_setup(gfx_surface *surface, gfx_surface *hw_surface) +{ + // set up the surface + gfxconsole.surface = surface; + gfxconsole.hw_surface = hw_surface; + + // set up line-height sub-surface, for line-only invalidation + memcpy(&gfxconsole.line, surface, sizeof(*surface)); + gfxconsole.line.height = FONT_Y; + gfxconsole.linestride = surface->stride * surface->pixelsize * FONT_Y; + + // calculate how many rows/columns we have + gfxconsole.rows = surface->height / FONT_Y; + gfxconsole.columns = surface->width / FONT_X; + gfxconsole.extray = surface->height - (gfxconsole.rows * FONT_Y); + + dprintf(SPEW, "gfxconsole: rows %d, columns %d, extray %d\n", gfxconsole.rows, + gfxconsole.columns, gfxconsole.extray); +} + +static void gfxconsole_clear(void) +{ + // start in the upper left + gfxconsole.x = 0; + gfxconsole.y = 0; + + // colors are black and magenta + gfxconsole.front_color = TEXT_COLOR; + gfxconsole.back_color = BACK_COLOR; + + // fill screen with back color + gfx_fillrect(gfxconsole.surface, 0, 0, gfxconsole.surface->width, gfxconsole.surface->height, + gfxconsole.back_color); + gfx_flush(gfxconsole.surface); +} + +/** + * @brief Initialize graphics console on given drawing surface. + * + * The graphics console subsystem is initialized, and registered as + * an output device for debug output. + */ +void gfxconsole_start(gfx_surface *surface, gfx_surface *hw_surface) +{ + DEBUG_ASSERT(gfxconsole.surface == NULL); + + gfxconsole_setup(surface, hw_surface); + gfxconsole_clear(); + + // register for debug callbacks + register_print_callback(&cb); +} + +static gfx_surface hw_surface; +static gfx_surface sw_surface; +static struct display_info dispinfo; + +status_t gfxconsole_display_get_info(struct display_info *info) +{ + if (gfxconsole.surface) { + memcpy(info, &dispinfo, sizeof(*info)); + return 0; + } else { + return -1; + } +} + +/** + * @brief Initialize graphics console and bind to a display + * + * If the display was previously initialized, first it is shut down and + * detached from the print callback. + * + * If the new display_info is NULL, nothing else is done, otherwise the + * display is initialized against the provided display_info. + * + * If raw_sw_fb is non-NULL it is a memory large enough to be a backing + * surface (stride * height * pixelsize) for the provided hardware display. + * This is used for very early framebuffer init before the heap is alive. + */ +void gfxconsole_bind_display(struct display_info *info, void *raw_sw_fb) { + static bool active = false; + bool same_as_before = false; + struct gfx_surface hw; + + if (active) { + // on re-init or detach, we need to unhook from print callbacks + active = false; + unregister_print_callback(&cb); + } + if (info == NULL) { + return; + } + + if (gfx_init_surface_from_display(&hw, info)) { + return; + } + if ((hw.format == hw_surface.format) && (hw.width == hw_surface.width) && + (hw.height == hw_surface.height) && (hw.stride == hw_surface.stride) && + (hw.pixelsize == hw_surface.pixelsize)) { + // we are binding to a new hw surface with the same properties + // as the existing one + same_as_before = true; + } else { + // we cannot re-use the sw backing surface, so destroy it + if (sw_surface.ptr && (sw_surface.flags & GFX_FLAG_FREE_ON_DESTROY)) { + free(sw_surface.ptr); + } + memset(&sw_surface, 0, sizeof(sw_surface)); + } + memcpy(&hw_surface, &hw, sizeof(hw)); + + gfx_surface *s = &hw_surface; + if (info->flags & DISPLAY_FLAG_HW_FRAMEBUFFER) { + if (!same_as_before) { + // we can't re-use the existing sw_surface, create a new one + if (gfx_init_surface(&sw_surface, raw_sw_fb, hw_surface.width, + hw_surface.height, hw_surface.stride, hw_surface.format, 0)) { + return; + } + } + s = &sw_surface; + } else { + // for non-hw surfaces we're not using a backing surface + // so we can't be the same as before and must fully init + same_as_before = false; + } + + gfxconsole_setup(s, &hw_surface); + + if (!same_as_before) { + // on first init, or different-backing-buffer re-init + // we clear and reset to x,y @ 0,0 + gfxconsole_clear(); + } + + memcpy(&dispinfo, info, sizeof(*info)); + register_print_callback(&cb); + active = true; +} diff --git a/kernel/lib/gfxconsole/rules.mk b/kernel/lib/gfxconsole/rules.mk new file mode 100644 index 000000000..002fd31f7 --- /dev/null +++ b/kernel/lib/gfxconsole/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/gfx \ + lib/font + +MODULE_SRCS += \ + $(LOCAL_DIR)/gfxconsole.c + +include make/module.mk diff --git a/kernel/lib/heap/BUILD.gn b/kernel/lib/heap/BUILD.gn new file mode 100644 index 000000000..4b916d413 --- /dev/null +++ b/kernel/lib/heap/BUILD.gn @@ -0,0 +1,50 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("_heap_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("heap") { + configs += [ + "//kernel/kernel:enable_vm", + "//kernel/lib/console:enable_console", + ] + public_configs = [ ":_heap_config" ] + public = [ + "include/lib/heap.h", + ] + include_dirs = [ + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + ] + sources = [ + "heap_wrapper.c", + "new.cpp", + "page_alloc.c", + ] + + # TODO(phosek): this dependency, even though correct as heap + # implementation does depend on console if enabled currently + # causes a cyclic dependency + # deps = [ + # "//kernel/lib/console", + # ] + if (heap_implementation == "cmpctmalloc") { + deps = [ + "//kernel/lib/heap/cmpctmalloc", + ] + } else if (heap_implementation == "miniheap") { + deps = [ + "//kernel/lib/heap/miniheap", + ] + } else { + assert(false, "Unsupported heap implementation") + } +} diff --git a/kernel/lib/heap/cmpctmalloc/BUILD.gn b/kernel/lib/heap/cmpctmalloc/BUILD.gn new file mode 100644 index 000000000..773906b70 --- /dev/null +++ b/kernel/lib/heap/cmpctmalloc/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_cmpctmalloc_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + defines = [ "WITH_LIB_HEAP_CMPCTMALLOC=1" ] +} + +module("cmpctmalloc") { + configs += [ "//kernel/kernel:enable_vm" ] + public_configs = [ ":_cmpctmalloc_config" ] + public = [ + "include/lib/cmpctmalloc.h", + ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + ] + sources = [ + "cmpctmalloc.c", + ] +} diff --git a/kernel/lib/heap/cmpctmalloc/cmpctmalloc.c b/kernel/lib/heap/cmpctmalloc/cmpctmalloc.c new file mode 100644 index 000000000..db8ccd423 --- /dev/null +++ b/kernel/lib/heap/cmpctmalloc/cmpctmalloc.c @@ -0,0 +1,899 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Malloc implementation tuned for space. +// +// Allocation strategy takes place with a global mutex. Freelist entries are +// kept in linked lists with 8 different sizes per binary order of magnitude +// and the header size is two words with eager coalescing on free. + +#if defined(DEBUG) || LK_DEBUGLEVEL > 1 +#define CMPCT_DEBUG +#endif + +#define LOCAL_TRACE 0 + +#define ALLOC_FILL 0x99 +#define FREE_FILL 0x77 +#define PADDING_FILL 0x55 + +#if WITH_KERNEL_VM && !defined(HEAP_GROW_SIZE) +#define HEAP_GROW_SIZE (1 * 1024 * 1024) /* Grow aggressively */ +#elif !defined(HEAP_GROW_SIZE) +#define HEAP_GROW_SIZE (4 * 1024) /* Grow less aggressively */ +#endif + +STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); + +// Individual allocations above 4Mbytes are just fetched directly from the +// block allocator. +#define HEAP_ALLOC_VIRTUAL_BITS 22 + +// When we grow the heap we have to have somewhere in the freelist to put the +// resulting freelist entry, so the freelist has to have a certain number of +// buckets. +STATIC_ASSERT(HEAP_GROW_SIZE <= (1u << HEAP_ALLOC_VIRTUAL_BITS)); + +// Buckets for allocations. The smallest 15 buckets are 8, 16, 24, etc. up to +// 120 bytes. After that we round up to the nearest size that can be written +// /^0*1...0*$/, giving 8 buckets per order of binary magnitude. The freelist +// entries in a given bucket have at least the given size, plus the header +// size. On 64 bit, the 8 byte bucket is useless, since the freelist header +// is 16 bytes larger than the header, but we have it for simplicity. +#define NUMBER_OF_BUCKETS (1 + 15 + (HEAP_ALLOC_VIRTUAL_BITS - 7) * 8) + +// All individual memory areas on the heap start with this. +typedef struct header_struct { + struct header_struct *left; // Pointer to the previous area in memory order. + size_t size; +} header_t; + +typedef struct free_struct { + header_t header; + struct free_struct *next; + struct free_struct *prev; +} free_t; + +struct heap { + size_t size; + size_t remaining; + mutex_t lock; + free_t *free_lists[NUMBER_OF_BUCKETS]; + // We have some 32 bit words that tell us whether there is an entry in the + // freelist. +#define BUCKET_WORDS (((NUMBER_OF_BUCKETS) + 31) >> 5) + uint32_t free_list_bits[BUCKET_WORDS]; +}; + +// Heap static vars. +static struct heap theheap; + +static ssize_t heap_grow(size_t len, free_t **bucket); + +static void lock(void) +{ + mutex_acquire(&theheap.lock); +} + +static void unlock(void) +{ + mutex_release(&theheap.lock); +} + +static void dump_free(header_t *header) +{ + dprintf(INFO, "\t\tbase %p, end 0x%lx, len 0x%zx\n", header, (vaddr_t)header + header->size, header->size); +} + +void cmpct_dump(void) +{ + lock(); + dprintf(INFO, "Heap dump (using cmpctmalloc):\n"); + dprintf(INFO, "\tsize %lu, remaining %lu\n", + (unsigned long)theheap.size, + (unsigned long)theheap.remaining); + + dprintf(INFO, "\tfree list:\n"); + for (int i = 0; i < NUMBER_OF_BUCKETS; i++) { + bool header_printed = false; + free_t *free_area = theheap.free_lists[i]; + for (; free_area != NULL; free_area = free_area->next) { + ASSERT(free_area != free_area->next); + if (!header_printed) { + dprintf(INFO, "\tbucket %d\n", i); + header_printed = true; + } + dump_free(&free_area->header); + } + } + unlock(); +} + +// Operates in sizes that don't include the allocation header. +static int size_to_index_helper( + size_t size, size_t *rounded_up_out, int adjust, int increment) +{ + // First buckets are simply 8-spaced up to 128. + if (size <= 128) { + if (sizeof(size_t) == 8u && size <= sizeof(free_t) - sizeof(header_t)) { + *rounded_up_out = sizeof(free_t) - sizeof(header_t); + } else { + *rounded_up_out = size; + } + // No allocation is smaller than 8 bytes, so the first bucket is for 8 + // byte spaces (not including the header). For 64 bit, the free list + // struct is 16 bytes larger than the header, so no allocation can be + // smaller than that (otherwise how to free it), but we have empty 8 + // and 16 byte buckets for simplicity. + return (size >> 3) - 1; + } + + // We are going to go up to the next size to round up, but if we hit a + // bucket size exactly we don't want to go up. By subtracting 8 here, we + // will do the right thing (the carry propagates up for the round numbers + // we are interested in). + size += adjust; + // After 128 the buckets are logarithmically spaced, every 16 up to 256, + // every 32 up to 512 etc. This can be thought of as rows of 8 buckets. + // GCC intrinsic count-leading-zeros. + // Eg. 128-255 has 24 leading zeros and we want row to be 4. + unsigned row = sizeof(size_t) * 8 - 4 - __builtin_clzl(size); + // For row 4 we want to shift down 4 bits. + unsigned column = (size >> row) & 7; + int row_column = (row << 3) | column; + row_column += increment; + size = (8 + (row_column & 7)) << (row_column >> 3); + *rounded_up_out = size; + // We start with 15 buckets, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, + // 104, 112, 120. Then we have row 4, sizes 128 and up, with the + // row-column 8 and up. + int answer = row_column + 15 - 32; + DEBUG_ASSERT(answer < NUMBER_OF_BUCKETS); + return answer; +} + +// Round up size to next bucket when allocating. +static int size_to_index_allocating(size_t size, size_t *rounded_up_out) +{ + size_t rounded = ROUNDUP(size, 8); + return size_to_index_helper(rounded, rounded_up_out, -8, 1); +} + +// Round down size to next bucket when freeing. +static int size_to_index_freeing(size_t size) +{ + size_t dummy; + return size_to_index_helper(size, &dummy, 0, 0); +} + +static inline header_t *tag_as_free(void *left) +{ + return (header_t *)((uintptr_t)left | 1); +} + +static inline bool is_tagged_as_free(header_t *header) +{ + return ((uintptr_t)(header->left) & 1) != 0; +} + +static inline header_t *untag(void *left) +{ + return (header_t *)((uintptr_t)left & ~1); +} + +static inline header_t *right_header(header_t *header) +{ + return (header_t *)((char *)header + header->size); +} + +static inline void set_free_list_bit(int index) +{ + theheap.free_list_bits[index >> 5] |= (1u << (31 - (index & 0x1f))); +} + +static inline void clear_free_list_bit(int index) +{ + theheap.free_list_bits[index >> 5] &= ~(1u << (31 - (index & 0x1f))); +} + +static int find_nonempty_bucket(int index) +{ + uint32_t mask = (1u << (31 - (index & 0x1f))) - 1; + mask = mask * 2 + 1; + mask &= theheap.free_list_bits[index >> 5]; + if (mask != 0) return (index & ~0x1f) + __builtin_clz(mask); + for (index = ROUNDUP(index + 1, 32); index <= NUMBER_OF_BUCKETS; index += 32) { + mask = theheap.free_list_bits[index >> 5]; + if (mask != 0u) return index + __builtin_clz(mask); + } + return -1; +} + +static bool is_start_of_os_allocation(header_t *header) +{ + return header->left == untag(NULL); +} + +static void create_free_area(void *address, void *left, size_t size, free_t **bucket) +{ + free_t *free_area = (free_t *)address; + free_area->header.size = size; + free_area->header.left = tag_as_free(left); + if (bucket == NULL) { + int index = size_to_index_freeing(size - sizeof(header_t)); + set_free_list_bit(index); + bucket = &theheap.free_lists[index]; + } + free_t *old_head = *bucket; + if (old_head != NULL) old_head->prev = free_area; + free_area->next = old_head; + free_area->prev = NULL; + *bucket = free_area; + theheap.remaining += size; +#ifdef CMPCT_DEBUG + memset(free_area + 1, FREE_FILL, size - sizeof(free_t)); +#endif +} + +static bool is_end_of_os_allocation(char *address) +{ + return ((header_t *)address)->size == 0; +} + +static void free_to_os(header_t *header, size_t size) +{ + DEBUG_ASSERT(IS_PAGE_ALIGNED(size)); + page_free(header, size >> PAGE_SIZE_SHIFT); + theheap.size -= size; +} + +static void free_memory(void *address, void *left, size_t size) +{ + left = untag(left); + if (IS_PAGE_ALIGNED(left) && + is_start_of_os_allocation(left) && + is_end_of_os_allocation((char *)address + size)) { + free_to_os(left, size + ((header_t *)left)->size + sizeof(header_t)); + } else { + create_free_area(address, left, size, NULL); + } +} + +static void unlink_free(free_t *free_area, int bucket) +{ + theheap.remaining -= free_area->header.size; + ASSERT(theheap.remaining < 4000000000u); + free_t *next = free_area->next; + free_t *prev = free_area->prev; + if (theheap.free_lists[bucket] == free_area) { + theheap.free_lists[bucket] = next; + if (next == NULL) clear_free_list_bit(bucket); + } + if (prev != NULL) prev->next = next; + if (next != NULL) next->prev = prev; +} + +static void unlink_free_unknown_bucket(free_t *free_area) +{ + return unlink_free(free_area, size_to_index_freeing(free_area->header.size - sizeof(header_t))); +} + +static void *create_allocation_header( + void *address, size_t offset, size_t size, void *left) +{ + header_t *standalone = (header_t *)((char *)address + offset); + standalone->left = untag(left); + standalone->size = size; + return standalone + 1; +} + +static void FixLeftPointer(header_t *right, header_t *new_left) +{ + int tag = (uintptr_t)right->left & 1; + right->left = (header_t *)(((uintptr_t)new_left & ~1) | tag); +} + +static void WasteFreeMemory(void) +{ + while (theheap.remaining != 0) cmpct_alloc(1); +} + +// If we just make a big allocation it gets rounded off. If we actually +// want to use a reasonably accurate amount of memory for test purposes, we +// have to do many small allocations. +static void *TestTrimHelper(ssize_t target) +{ + char *answer = NULL; + size_t remaining = theheap.remaining; + while (theheap.remaining - target > 512) { + char *next_block = cmpct_alloc(8 + ((theheap.remaining - target) >> 2)); + *(char **)next_block = answer; + answer = next_block; + if (theheap.remaining > remaining) return answer; + // Abandon attemt to hit particular freelist entry size if we accidentally got more memory + // from the OS. + remaining = theheap.remaining; + } + return answer; +} + +static void TestTrimFreeHelper(char *block) +{ + while (block) { + char *next_block = *(char **)block; + cmpct_free(block); + block = next_block; + } +} + +static void cmpct_test_trim(void) +{ + // XXX: Re-enable this test if we want, disabled due to float math + return; + WasteFreeMemory(); + + size_t test_sizes[200]; + int sizes = 0; + + for (size_t s = 1; s < PAGE_SIZE * 4; s = (s + 1) * 1.1) { + test_sizes[sizes++] = s; + ASSERT(sizes < 200); + } + for (ssize_t s = -32; s <= 32; s += 8) { + test_sizes[sizes++] = PAGE_SIZE + s; + ASSERT(sizes < 200); + } + + // Test allocations at the start of an OS allocation. + for (int with_second_alloc = 0; with_second_alloc < 2; with_second_alloc++) { + for (int i = 0; i < sizes; i++) { + size_t s = test_sizes[i]; + + char *a, *a2 = NULL; + a = cmpct_alloc(s); + if (with_second_alloc) { + a2 = cmpct_alloc(1); + if (s < PAGE_SIZE >> 1) { + // It is the intention of the test that a is at the start of an OS allocation + // and that a2 is "right after" it. Otherwise we are not testing what I + // thought. OS allocations are certainly not smaller than a page, so check in + // that case. + ASSERT((uintptr_t)(a2 - a) < s * 1.13 + 48); + } + } + cmpct_trim(); + size_t remaining = theheap.remaining; + // We should have < 1 page on either side of the a allocation. + ASSERT(remaining < PAGE_SIZE * 2); + cmpct_free(a); + if (with_second_alloc) { + // Now only a2 is holding onto the OS allocation. + ASSERT(theheap.remaining > remaining); + } else { + ASSERT(theheap.remaining == 0); + } + remaining = theheap.remaining; + cmpct_trim(); + ASSERT(theheap.remaining <= remaining); + // If a was at least one page then the trim should have freed up that page. + if (s >= PAGE_SIZE && with_second_alloc) ASSERT(theheap.remaining < remaining); + if (with_second_alloc) cmpct_free(a2); + } + ASSERT(theheap.remaining == 0); + } + + ASSERT(theheap.remaining == 0); + + // Now test allocations near the end of an OS allocation. + for (ssize_t wobble = -64; wobble <= 64; wobble += 8) { + for (int i = 0; i < sizes; i++) { + size_t s = test_sizes[i]; + + if ((ssize_t)s + wobble < 0) continue; + + char *start_of_os_alloc = cmpct_alloc(1); + + // If the OS allocations are very small this test does not make sense. + if (theheap.remaining <= s + wobble) { + cmpct_free(start_of_os_alloc); + continue; + } + + char *big_bit_in_the_middle = TestTrimHelper(s + wobble); + size_t remaining = theheap.remaining; + + // If the remaining is big we started a new OS allocation and the test + // makes no sense. + if (remaining > 128 + s * 1.13 + wobble) { + cmpct_free(start_of_os_alloc); + TestTrimFreeHelper(big_bit_in_the_middle); + continue; + } + + cmpct_free(start_of_os_alloc); + remaining = theheap.remaining; + + // This trim should sometimes trim a page off the end of the OS allocation. + cmpct_trim(); + ASSERT(theheap.remaining <= remaining); + remaining = theheap.remaining; + + // We should have < 1 page on either side of the big allocation. + ASSERT(remaining < PAGE_SIZE * 2); + + TestTrimFreeHelper(big_bit_in_the_middle); + } + } +} + + +static void cmpct_test_buckets(void) +{ + size_t rounded; + unsigned bucket; + // Check for the 8-spaced buckets up to 128. + for (unsigned i = 1; i <= 128; i++) { + // Round up when allocating. + bucket = size_to_index_allocating(i, &rounded); + unsigned expected = (ROUNDUP(i, 8) >> 3) - 1; + ASSERT(bucket == expected); + ASSERT(IS_ALIGNED(rounded, 8)); + ASSERT(rounded >= i); + if (i >= sizeof(free_t) - sizeof(header_t)) { + // Once we get above the size of the free area struct (4 words), we + // won't round up much for these small size. + ASSERT(rounded - i < 8); + } + // Only rounded sizes are freed. + if ((i & 7) == 0) { + // Up to size 128 we have exact buckets for each multiple of 8. + ASSERT(bucket == (unsigned)size_to_index_freeing(i)); + } + } + int bucket_base = 7; + for (unsigned j = 16; j < 1024; j *= 2, bucket_base += 8) { + // Note the "<=", which ensures that we test the powers of 2 twice to ensure + // that both ways of calculating the bucket number match. + for (unsigned i = j * 8; i <= j * 16; i++) { + // Round up to j multiple in this range when allocating. + bucket = size_to_index_allocating(i, &rounded); + unsigned expected = bucket_base + ROUNDUP(i, j) / j; + ASSERT(bucket == expected); + ASSERT(IS_ALIGNED(rounded, j)); + ASSERT(rounded >= i); + ASSERT(rounded - i < j); + // Only 8-rounded sizes are freed or chopped off the end of a free area + // when allocating. + if ((i & 7) == 0) { + // When freeing, if we don't hit the size of the bucket precisely, + // we have to put the free space into a smaller bucket, because + // the buckets have entries that will always be big enough for + // the corresponding allocation size (so we don't have to + // traverse the free chains to find a big enough one). + if ((i % j) == 0) { + ASSERT((int)bucket == size_to_index_freeing(i)); + } else { + ASSERT((int)bucket - 1 == size_to_index_freeing(i)); + } + } + } + } +} + +static void cmpct_test_get_back_newly_freed_helper(size_t size) +{ + void *allocated = cmpct_alloc(size); + if (allocated == NULL) return; + char *allocated2 = cmpct_alloc(8); + char *expected_position = (char *)allocated + size; + if (allocated2 < expected_position || allocated2 > expected_position + 128) { + // If the allocated2 allocation is not in the same OS allocation as the + // first allocation then the test may not work as expected (the memory + // may be returned to the OS when we free the first allocation, and we + // might not get it back). + cmpct_free(allocated); + cmpct_free(allocated2); + return; + } + + cmpct_free(allocated); + void *allocated3 = cmpct_alloc(size); + // To avoid churn and fragmentation we would want to get the newly freed + // memory back again when we allocate the same size shortly after. + ASSERT(allocated3 == allocated); + cmpct_free(allocated2); + cmpct_free(allocated3); +} + +static void cmpct_test_get_back_newly_freed(void) +{ + size_t increment = 16; + for (size_t i = 128; i <= 0x8000000; i *= 2, increment *= 2) { + for (size_t j = i; j < i * 2; j += increment) { + cmpct_test_get_back_newly_freed_helper(i - 8); + cmpct_test_get_back_newly_freed_helper(i); + cmpct_test_get_back_newly_freed_helper(i + 1); + } + } + for (size_t i = 1024; i <= 2048; i++) { + cmpct_test_get_back_newly_freed_helper(i); + } +} + +static void cmpct_test_return_to_os(void) +{ + cmpct_trim(); + size_t remaining = theheap.remaining; + // This goes in a new OS allocation since the trim above removed any free + // area big enough to contain it. + void *a = cmpct_alloc(5000); + void *b = cmpct_alloc(2500); + cmpct_free(a); + cmpct_free(b); + // If things work as expected the new allocation is at the start of an OS + // allocation. There's just one sentinel and one header to the left of it. + // It that's not the case then the allocation was met from some space in + // the middle of an OS allocation, and our test won't work as expected, so + // bail out. + if (((uintptr_t)a & (PAGE_SIZE - 1)) != sizeof(header_t) * 2) return; + // No trim needed when the entire OS allocation is free. + ASSERT(remaining == theheap.remaining); +} + +void cmpct_test(void) +{ + cmpct_test_buckets(); + cmpct_test_get_back_newly_freed(); + cmpct_test_return_to_os(); + cmpct_test_trim(); + cmpct_dump(); + void *ptr[16]; + + ptr[0] = cmpct_alloc(8); + ptr[1] = cmpct_alloc(32); + ptr[2] = cmpct_alloc(7); + cmpct_trim(); + ptr[3] = cmpct_alloc(0); + ptr[4] = cmpct_alloc(98713); + ptr[5] = cmpct_alloc(16); + + cmpct_free(ptr[5]); + cmpct_free(ptr[1]); + cmpct_free(ptr[3]); + cmpct_free(ptr[0]); + cmpct_free(ptr[4]); + cmpct_free(ptr[2]); + + cmpct_dump(); + cmpct_trim(); + cmpct_dump(); + + int i; + for (i=0; i < 16; i++) + ptr[i] = 0; + + for (i=0; i < 32768; i++) { + unsigned int index = (unsigned int)rand() % 16; + + if ((i % (16*1024)) == 0) + printf("pass %d\n", i); + +// printf("index 0x%x\n", index); + if (ptr[index]) { +// printf("freeing ptr[0x%x] = %p\n", index, ptr[index]); + cmpct_free(ptr[index]); + ptr[index] = 0; + } + unsigned int align = 1 << ((unsigned int)rand() % 8); + ptr[index] = cmpct_memalign((unsigned int)rand() % 32768, align); +// printf("ptr[0x%x] = %p, align 0x%x\n", index, ptr[index], align); + + DEBUG_ASSERT(((addr_t)ptr[index] % align) == 0); +// cmpct_dump(); + } + + for (i=0; i < 16; i++) { + if (ptr[i]) + cmpct_free(ptr[i]); + } + + cmpct_dump(); +} + +static void *large_alloc(size_t size) +{ +#ifdef CMPCT_DEBUG + size_t requested_size = size; +#endif + size = ROUNDUP(size, 8); + free_t *free_area = NULL; + lock(); + heap_grow(size, &free_area); + void *result = + create_allocation_header(free_area, 0, free_area->header.size, free_area->header.left); + // Normally the 'remaining free space' counter would be decremented when we + // unlink the free area from its bucket. However in this case the free + // area was too big to go in any bucket and we had it in our own + // "free_area" variable so there is no unlinking and we have to adjust the + // counter here. + theheap.remaining -= free_area->header.size; + unlock(); +#ifdef CMPCT_DEBUG + memset(result, ALLOC_FILL, requested_size); + memset((char *)result + requested_size, PADDING_FILL, free_area->header.size - requested_size); +#endif + return result; +} + +void cmpct_trim(void) +{ + // Look at free list entries that are at least as large as one page plus a + // header. They might be at the start or the end of a block, so we can trim + // them and free the page(s). + lock(); + for (int bucket = size_to_index_freeing(PAGE_SIZE); + bucket < NUMBER_OF_BUCKETS; + bucket++) { + free_t *next; + for (free_t *free_area = theheap.free_lists[bucket]; + free_area != NULL; + free_area = next) { + DEBUG_ASSERT(free_area->header.size >= PAGE_SIZE + sizeof(header_t)); + next = free_area->next; + header_t *right = right_header(&free_area->header); + if (is_end_of_os_allocation((char *)right)) { + char *old_os_allocation_end = (char *)ROUNDUP((uintptr_t)right, PAGE_SIZE); + // The page will end with a smaller free list entry and a header-sized sentinel. + char *new_os_allocation_end = (char *) + ROUNDUP((uintptr_t)free_area + sizeof(header_t) + sizeof(free_t), PAGE_SIZE); + size_t freed_up = old_os_allocation_end - new_os_allocation_end; + DEBUG_ASSERT(IS_PAGE_ALIGNED(freed_up)); + // Rare, because we only look at large freelist entries, but unlucky rounding + // could mean we can't actually free anything here. + if (freed_up == 0) continue; + unlink_free(free_area, bucket); + size_t new_free_size = free_area->header.size - freed_up; + DEBUG_ASSERT(new_free_size >= sizeof(free_t)); + // Right sentinel, not free, stops attempts to coalesce right. + create_allocation_header(free_area, new_free_size, 0, free_area); + // Also puts it in the correct bucket. + create_free_area(free_area, untag(free_area->header.left), new_free_size, NULL); + page_free(new_os_allocation_end, freed_up >> PAGE_SIZE_SHIFT); + theheap.size -= freed_up; + } else if (is_start_of_os_allocation(untag(free_area->header.left))) { + char *old_os_allocation_start = + (char *)ROUNDDOWN((uintptr_t)free_area, PAGE_SIZE); + // For the sentinel, we need at least one header-size of space between the page + // edge and the first allocation to the right of the free area. + char *new_os_allocation_start = + (char *)ROUNDDOWN((uintptr_t)(right - 1), PAGE_SIZE); + size_t freed_up = new_os_allocation_start - old_os_allocation_start; + DEBUG_ASSERT(IS_PAGE_ALIGNED(freed_up)); + // This should not happen because we only look at the large free list buckets. + if (freed_up == 0) continue; + unlink_free(free_area, bucket); + size_t sentinel_size = sizeof(header_t); + size_t new_free_size = free_area->header.size - freed_up; + if (new_free_size < sizeof(free_t)) { + sentinel_size += new_free_size; + new_free_size = 0; + } + // Left sentinel, not free, stops attempts to coalesce left. + create_allocation_header(new_os_allocation_start, 0, sentinel_size, NULL); + if (new_free_size == 0) { + FixLeftPointer(right, (header_t *)new_os_allocation_start); + } else { + DEBUG_ASSERT(new_free_size >= sizeof(free_t)); + char *new_free = new_os_allocation_start + sentinel_size; + // Also puts it in the correct bucket. + create_free_area(new_free, new_os_allocation_start, new_free_size, NULL); + FixLeftPointer(right, (header_t *)new_free); + } + page_free(old_os_allocation_start, freed_up >> PAGE_SIZE_SHIFT); + theheap.size -= freed_up; + } + } + } + unlock(); +} + +void *cmpct_alloc(size_t size) +{ + if (size == 0u) return NULL; + + if (size + sizeof(header_t) > (1u << HEAP_ALLOC_VIRTUAL_BITS)) return large_alloc(size); + + size_t rounded_up; + int start_bucket = size_to_index_allocating(size, &rounded_up); + + rounded_up += sizeof(header_t); + + lock(); + int bucket = find_nonempty_bucket(start_bucket); + if (bucket == -1) { + // Grow heap by at least 12% if we can. + size_t growby = MIN(1u << HEAP_ALLOC_VIRTUAL_BITS, + MAX(theheap.size >> 3, + MAX(HEAP_GROW_SIZE, rounded_up))); + while (heap_grow(growby, NULL) < 0) { + if (growby <= rounded_up) { + unlock(); + return NULL; + } + growby = MAX(growby >> 1, rounded_up); + } + bucket = find_nonempty_bucket(start_bucket); + } + free_t *head = theheap.free_lists[bucket]; + size_t left_over = head->header.size - rounded_up; + // We can't carve off the rest for a new free space if it's smaller than the + // free-list linked structure. We also don't carve it off if it's less than + // 1.6% the size of the allocation. This is to avoid small long-lived + // allocations being placed right next to large allocations, hindering + // coalescing and returning pages to the OS. + if (left_over >= sizeof(free_t) && left_over > (size >> 6)) { + header_t *right = right_header(&head->header); + unlink_free(head, bucket); + void *free = (char *)head + rounded_up; + create_free_area(free, head, left_over, NULL); + FixLeftPointer(right, (header_t *)free); + head->header.size -= left_over; + } else { + unlink_free(head, bucket); + } + void *result = + create_allocation_header(head, 0, head->header.size, head->header.left); +#ifdef CMPCT_DEBUG + memset(result, ALLOC_FILL, size); + memset(((char *)result) + size, PADDING_FILL, rounded_up - size - sizeof(header_t)); +#endif + unlock(); + return result; +} + +void *cmpct_memalign(size_t size, size_t alignment) +{ + if (alignment < 8) return cmpct_alloc(size); + size_t padded_size = + size + alignment + sizeof(free_t) + sizeof(header_t); + char *unaligned = (char *)cmpct_alloc(padded_size); + lock(); + size_t mask = alignment - 1; + uintptr_t payload_int = (uintptr_t)unaligned + sizeof(free_t) + + sizeof(header_t) + mask; + char *payload = (char *)(payload_int & ~mask); + if (unaligned != payload) { + header_t *unaligned_header = (header_t *)unaligned - 1; + header_t *header = (header_t *)payload - 1; + size_t left_over = payload - unaligned; + create_allocation_header( + header, 0, unaligned_header->size - left_over, unaligned_header); + header_t *right = right_header(unaligned_header); + unaligned_header->size = left_over; + FixLeftPointer(right, header); + unlock(); + cmpct_free(unaligned); + } else { + unlock(); + } + // TODO: Free the part after the aligned allocation. + return payload; +} + +void cmpct_free(void *payload) +{ + if (payload == NULL) return; + header_t *header = (header_t *)payload - 1; + DEBUG_ASSERT(!is_tagged_as_free(header)); // Double free! + size_t size = header->size; + lock(); + header_t *left = header->left; + if (left != NULL && is_tagged_as_free(left)) { + // Coalesce with left free object. + unlink_free_unknown_bucket((free_t *)left); + header_t *right = right_header(header); + if (is_tagged_as_free(right)) { + // Coalesce both sides. + unlink_free_unknown_bucket((free_t *)right); + header_t *right_right = right_header(right); + FixLeftPointer(right_right, left); + free_memory(left, left->left, left->size + size + right->size); + } else { + // Coalesce only left. + FixLeftPointer(right, left); + free_memory(left, left->left, left->size + size); + } + } else { + header_t *right = right_header(header); + if (is_tagged_as_free(right)) { + // Coalesce only right. + header_t *right_right = right_header(right); + unlink_free_unknown_bucket((free_t *)right); + FixLeftPointer(right_right, header); + free_memory(header, left, size + right->size); + } else { + free_memory(header, left, size); + } + } + unlock(); +} + +void *cmpct_realloc(void *payload, size_t size) +{ + if (payload == NULL) return cmpct_alloc(size); + header_t *header = (header_t *)payload - 1; + size_t old_size = header->size - sizeof(header_t); + void *new_payload = cmpct_alloc(size); + memcpy(new_payload, payload, MIN(size, old_size)); + cmpct_free(payload); + return new_payload; +} + +static void add_to_heap(void *new_area, size_t size, free_t **bucket) +{ + void *top = (char *)new_area + size; + header_t *left_sentinel = (header_t *)new_area; + // Not free, stops attempts to coalesce left. + create_allocation_header(left_sentinel, 0, sizeof(header_t), NULL); + header_t *new_header = left_sentinel + 1; + size_t free_size = size - 2 * sizeof(header_t); + create_free_area(new_header, left_sentinel, free_size, bucket); + header_t *right_sentinel = (header_t *)(top - sizeof(header_t)); + // Not free, stops attempts to coalesce right. + create_allocation_header(right_sentinel, 0, 0, new_header); +} + +// Create a new free-list entry of at least size bytes (including the +// allocation header). Called with the lock, apart from during init. +static ssize_t heap_grow(size_t size, free_t **bucket) +{ + // The new free list entry will have a header on each side (the + // sentinels) so we need to grow the gross heap size by this much more. + size += 2 * sizeof(header_t); + size = ROUNDUP(size, PAGE_SIZE); + void *ptr = page_alloc(size >> PAGE_SIZE_SHIFT); + theheap.size += size; + if (ptr == NULL) return -1; + LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); + add_to_heap(ptr, size, bucket); + return size; +} + +void cmpct_init(void) +{ + LTRACE_ENTRY; + + // Create a mutex. + mutex_init(&theheap.lock); + + // Initialize the free list. + for (int i = 0; i < NUMBER_OF_BUCKETS; i++) { + theheap.free_lists[i] = NULL; + } + for (int i = 0; i < BUCKET_WORDS; i++) { + theheap.free_list_bits[i] = 0; + } + + size_t initial_alloc = HEAP_GROW_SIZE - 2 * sizeof(header_t); + + theheap.remaining = 0; + + heap_grow(initial_alloc, NULL); +} diff --git a/kernel/lib/heap/cmpctmalloc/include/lib/cmpctmalloc.h b/kernel/lib/heap/cmpctmalloc/include/lib/cmpctmalloc.h new file mode 100644 index 000000000..441393c78 --- /dev/null +++ b/kernel/lib/heap/cmpctmalloc/include/lib/cmpctmalloc.h @@ -0,0 +1,24 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +__BEGIN_CDECLS; + +void *cmpct_alloc(size_t); +void *cmpct_realloc(void *, size_t); +void cmpct_free(void *); +void *cmpct_memalign(size_t size, size_t alignment); + +void cmpct_init(void); +void cmpct_dump(void); +void cmpct_test(void); +void cmpct_trim(void); + +__END_CDECLS; diff --git a/kernel/lib/heap/cmpctmalloc/rules.mk b/kernel/lib/heap/cmpctmalloc/rules.mk new file mode 100644 index 000000000..7071cbfa1 --- /dev/null +++ b/kernel/lib/heap/cmpctmalloc/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/cmpctmalloc.c + +include make/module.mk diff --git a/kernel/lib/heap/heap_wrapper.c b/kernel/lib/heap/heap_wrapper.c new file mode 100644 index 000000000..1d2db8dbb --- /dev/null +++ b/kernel/lib/heap/heap_wrapper.c @@ -0,0 +1,376 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +/* heap tracing */ +#if LK_DEBUGLEVEL > 0 +static bool heap_trace = false; +#else +#define heap_trace (false) +#endif + +/* delayed free list */ +struct list_node delayed_free_list = LIST_INITIAL_VALUE(delayed_free_list); +spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; + +#if WITH_LIB_HEAP_MINIHEAP +/* miniheap implementation */ +#include + +static inline void *HEAP_MALLOC(size_t s) { return miniheap_alloc(s, 0); } +static inline void *HEAP_REALLOC(void *ptr, size_t s) { return miniheap_realloc(ptr, s); } +static inline void *HEAP_MEMALIGN(size_t boundary, size_t s) { return miniheap_alloc(s, boundary); } +#define HEAP_FREE miniheap_free +static inline void *HEAP_CALLOC(size_t n, size_t s) +{ + size_t realsize = n * s; + + void *ptr = miniheap_alloc(realsize, 0); + if (likely(ptr)) + memset(ptr, 0, realsize); + return ptr; +} +static inline void HEAP_INIT(void) +{ + /* start the heap off with some spare memory in the page allocator */ + size_t len; + void *ptr = page_first_alloc(&len); + miniheap_init(ptr, len); +} +#define HEAP_DUMP miniheap_dump +#define HEAP_TRIM miniheap_trim + +/* end miniheap implementation */ +#elif WITH_LIB_HEAP_CMPCTMALLOC +/* cmpctmalloc implementation */ +#include + +#define HEAP_MEMALIGN(boundary, s) cmpct_memalign(s, boundary) +#define HEAP_MALLOC cmpct_alloc +#define HEAP_REALLOC cmpct_realloc +#define HEAP_FREE cmpct_free +#define HEAP_INIT cmpct_init +#define HEAP_DUMP cmpct_dump +#define HEAP_TRIM cmpct_trim +static inline void *HEAP_CALLOC(size_t n, size_t s) +{ + size_t realsize = n * s; + + void *ptr = cmpct_alloc(realsize); + if (likely(ptr)) + memset(ptr, 0, realsize); + return ptr; +} + +/* end cmpctmalloc implementation */ +#elif WITH_LIB_HEAP_DLMALLOC +/* dlmalloc implementation */ +#include + +#define HEAP_MALLOC(s) dlmalloc(s) +#define HEAP_CALLOC(n, s) dlcalloc(n, s) +#define HEAP_MEMALIGN(b, s) dlmemalign(b, s) +#define HEAP_REALLOC(p, s) dlrealloc(p, s) +#define HEAP_FREE(p) dlfree(p) +static inline void HEAP_INIT(void) {} + +static void dump_callback(void *start, void *end, size_t used_bytes, void *arg) { + printf("\t\tstart %p end %p used_bytes %zu\n", start, end, used_bytes); +} + +static inline void HEAP_DUMP(void) +{ + struct mallinfo minfo = dlmallinfo(); + + printf("\tmallinfo (dlmalloc):\n"); + printf("\t\tarena space 0x%zx\n", minfo.arena); + printf("\t\tfree chunks 0x%zx\n", minfo.ordblks); + printf("\t\tspace in mapped regions 0x%zx\n", minfo.hblkhd); + printf("\t\tmax total allocated 0x%zx\n", minfo.usmblks); + printf("\t\ttotal allocated 0x%zx\n", minfo.uordblks); + printf("\t\tfree 0x%zx\n", minfo.fordblks); + printf("\t\treleasable space 0x%zx\n", minfo.keepcost); + + printf("\theap block list:\n"); + + dlmalloc_inspect_all(&dump_callback, NULL); +} + +static inline void HEAP_TRIM(void) { dlmalloc_trim(0); } + +/* end dlmalloc implementation */ +#else +#error need to select valid heap implementation or provide wrapper +#endif + +static void heap_free_delayed_list(void) +{ + struct list_node list; + + list_initialize(&list); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&delayed_free_lock, state); + + struct list_node *node; + while ((node = list_remove_head(&delayed_free_list))) { + list_add_head(&list, node); + } + spin_unlock_irqrestore(&delayed_free_lock, state); + + while ((node = list_remove_head(&list))) { + LTRACEF("freeing node %p\n", node); + HEAP_FREE(node); + } +} + +void heap_init(void) +{ + HEAP_INIT(); +} + +void heap_trim(void) +{ + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + HEAP_TRIM(); +} + +void *malloc(size_t size) +{ + LTRACEF("size %zd\n", size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + void *ptr = HEAP_MALLOC(size); + if (heap_trace) + printf("caller %p malloc %zu -> %p\n", __GET_CALLER(), size, ptr); + return ptr; +} + +void *memalign(size_t boundary, size_t size) +{ + LTRACEF("boundary %zu, size %zd\n", boundary, size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + void *ptr = HEAP_MEMALIGN(boundary, size); + if (heap_trace) + printf("caller %p memalign %zu, %zu -> %p\n", __GET_CALLER(), boundary, size, ptr); + return ptr; +} + +void *calloc(size_t count, size_t size) +{ + LTRACEF("count %zu, size %zd\n", count, size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + void *ptr = HEAP_CALLOC(count, size); + if (heap_trace) + printf("caller %p calloc %zu, %zu -> %p\n", __GET_CALLER(), count, size, ptr); + return ptr; +} + +void *realloc(void *ptr, size_t size) +{ + LTRACEF("ptr %p, size %zd\n", ptr, size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + void *ptr2 = HEAP_REALLOC(ptr, size); + if (heap_trace) + printf("caller %p realloc %p, %zu -> %p\n", __GET_CALLER(), ptr, size, ptr2); + return ptr2; +} + +void free(void *ptr) +{ + LTRACEF("ptr %p\n", ptr); + if (heap_trace) + printf("caller %p free %p\n", __GET_CALLER(), ptr); + + HEAP_FREE(ptr); +} + +/* critical section time delayed free */ +void heap_delayed_free(void *ptr) +{ + LTRACEF("ptr %p\n", ptr); + + /* throw down a structure on the free block */ + /* XXX assumes the free block is large enough to hold a list node */ + struct list_node *node = (struct list_node *)ptr; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&delayed_free_lock, state); + list_add_head(&delayed_free_list, node); + spin_unlock_irqrestore(&delayed_free_lock, state); +} + +static void heap_dump(void) +{ + HEAP_DUMP(); + + printf("\tdelayed free list:\n"); + spin_lock_saved_state_t state; + spin_lock_irqsave(&delayed_free_lock, state); + struct list_node *node; + list_for_every(&delayed_free_list, node) { + printf("\t\tnode %p\n", node); + } + spin_unlock_irqrestore(&delayed_free_lock, state); +} + +static void heap_test(void) +{ +#if WITH_LIB_HEAP_CMPCTMALLOC + cmpct_test(); +#else + void *ptr[16]; + + ptr[0] = HEAP_MALLOC(8); + ptr[1] = HEAP_MALLOC(32); + ptr[2] = HEAP_MALLOC(7); + ptr[3] = HEAP_MALLOC(0); + ptr[4] = HEAP_MALLOC(98713); + ptr[5] = HEAP_MALLOC(16); + + HEAP_FREE(ptr[5]); + HEAP_FREE(ptr[1]); + HEAP_FREE(ptr[3]); + HEAP_FREE(ptr[0]); + HEAP_FREE(ptr[4]); + HEAP_FREE(ptr[2]); + + HEAP_DUMP(); + + int i; + for (i=0; i < 16; i++) + ptr[i] = 0; + + for (i=0; i < 32768; i++) { + unsigned int index = (unsigned int)rand() % 16; + + if ((i % (16*1024)) == 0) + printf("pass %d\n", i); + +// printf("index 0x%x\n", index); + if (ptr[index]) { +// printf("freeing ptr[0x%x] = %p\n", index, ptr[index]); + HEAP_FREE(ptr[index]); + ptr[index] = 0; + } + unsigned int align = 1 << ((unsigned int)rand() % 8); + ptr[index] = HEAP_MEMALIGN(align, (unsigned int)rand() % 32768); +// printf("ptr[0x%x] = %p, align 0x%x\n", index, ptr[index], align); + + DEBUG_ASSERT(((addr_t)ptr[index] % align) == 0); +// heap_dump(); + } + + for (i=0; i < 16; i++) { + if (ptr[i]) + HEAP_FREE(ptr[i]); + } + + HEAP_DUMP(); +#endif +} + + +#if LK_DEBUGLEVEL > 1 +#if WITH_LIB_CONSOLE + +#include + +static int cmd_heap(int argc, const cmd_args *argv); + +STATIC_COMMAND_START +STATIC_COMMAND("heap", "heap debug commands", &cmd_heap) +STATIC_COMMAND_END(heap); + +static int cmd_heap(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + printf("\t%s trace\n", argv[0].str); + printf("\t%s trim\n", argv[0].str); + printf("\t%s alloc [alignment]\n", argv[0].str); + printf("\t%s realloc \n", argv[0].str); + printf("\t%s free
\n", argv[0].str); + return -1; + } + + if (strcmp(argv[1].str, "info") == 0) { + heap_dump(); + } else if (strcmp(argv[1].str, "test") == 0) { + heap_test(); + } else if (strcmp(argv[1].str, "trace") == 0) { + heap_trace = !heap_trace; + printf("heap trace is now %s\n", heap_trace ? "on" : "off"); + } else if (strcmp(argv[1].str, "trim") == 0) { + heap_trim(); + } else if (strcmp(argv[1].str, "alloc") == 0) { + if (argc < 3) goto notenoughargs; + + void *ptr = memalign((argc >= 4) ? argv[3].u : 0, argv[2].u); + printf("memalign returns %p\n", ptr); + } else if (strcmp(argv[1].str, "realloc") == 0) { + if (argc < 4) goto notenoughargs; + + void *ptr = realloc(argv[2].p, argv[3].u); + printf("realloc returns %p\n", ptr); + } else if (strcmp(argv[1].str, "free") == 0) { + if (argc < 2) goto notenoughargs; + + free(argv[2].p); + } else { + printf("unrecognized command\n"); + goto usage; + } + + return 0; +} + +#endif +#endif + + diff --git a/kernel/lib/heap/include/lib/heap.h b/kernel/lib/heap/include/lib/heap.h new file mode 100644 index 000000000..da5bdb3dc --- /dev/null +++ b/kernel/lib/heap/include/lib/heap.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS; + +/* standard heap definitions */ +void *malloc(size_t size) __MALLOC; +void *memalign(size_t boundary, size_t size) __MALLOC; +void *calloc(size_t count, size_t size) __MALLOC; +void *realloc(void *ptr, size_t size) __MALLOC; +void free(void *ptr); + +void heap_init(void); + +/* critical section time delayed free */ +void heap_delayed_free(void *); + +/* tell the heap to return any free pages it can find */ +void heap_trim(void); + +__END_CDECLS; diff --git a/kernel/lib/heap/miniheap/BUILD.gn b/kernel/lib/heap/miniheap/BUILD.gn new file mode 100644 index 000000000..2239181c0 --- /dev/null +++ b/kernel/lib/heap/miniheap/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_miniheap_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + defines = [ "WITH_LIB_HEAP_MINIHEAP=1" ] +} + +module("miniheap") { + public_configs = [ ":_miniheap_config" ] + public = [ + "include/lib/miniheap.h", + ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + ] + sources = [ + "miniheap.c", + ] +} diff --git a/kernel/lib/heap/miniheap/include/lib/miniheap.h b/kernel/lib/heap/miniheap/include/lib/miniheap.h new file mode 100644 index 000000000..310a9a966 --- /dev/null +++ b/kernel/lib/heap/miniheap/include/lib/miniheap.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +__BEGIN_CDECLS; + +struct miniheap_stats { + void *heap_start; + size_t heap_len; + size_t heap_free; + size_t heap_max_chunk; + size_t heap_low_watermark; +}; + +void miniheap_get_stats(struct miniheap_stats *ptr); + +void *miniheap_alloc(size_t, unsigned int alignment); +void *miniheap_realloc(void *, size_t); +void miniheap_free(void *); + +void miniheap_init(void *ptr, size_t len); +void miniheap_dump(void); +void miniheap_trim(void); + +__END_CDECLS; diff --git a/kernel/lib/heap/miniheap/miniheap.c b/kernel/lib/heap/miniheap/miniheap.c new file mode 100644 index 000000000..4514c6907 --- /dev/null +++ b/kernel/lib/heap/miniheap/miniheap.c @@ -0,0 +1,515 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2009,2012-2015 Travis Geiselbrecht +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define DEBUG_HEAP 0 +#define ALLOC_FILL 0x99 +#define FREE_FILL 0x77 +#define PADDING_FILL 0x55 +#define PADDING_SIZE 64 + +// whether or not the heap will try to trim itself every time a free happens +#ifndef MINIHEAP_AUTOTRIM +#define MINIHEAP_AUTOTRIM 0 +#endif + +#define HEAP_MAGIC (0x48454150) // 'HEAP' + +struct free_heap_chunk { + struct list_node node; + size_t len; +}; + +struct heap { + void *base; + size_t len; + size_t remaining; + size_t low_watermark; + mutex_t lock; + struct list_node free_list; +}; + +// heap static vars +static struct heap theheap; + +// structure placed at the beginning every allocation +struct alloc_struct_begin { +#if LK_DEBUGLEVEL > 1 + unsigned int magic; +#endif + void *ptr; + size_t size; +#if DEBUG_HEAP + void *padding_start; + size_t padding_size; +#endif +}; + +static ssize_t heap_grow(size_t len); + +static void dump_free_chunk(struct free_heap_chunk *chunk) +{ + dprintf(INFO, "\t\tbase %p, end 0x%lx, len 0x%zx\n", chunk, (vaddr_t)chunk + chunk->len, chunk->len); +} + +void miniheap_dump(void) +{ + dprintf(INFO, "Heap dump (using miniheap):\n"); + dprintf(INFO, "\tbase %p, len 0x%zx\n", theheap.base, theheap.len); + dprintf(INFO, "\tfree list:\n"); + + mutex_acquire(&theheap.lock); + + struct free_heap_chunk *chunk; + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + dump_free_chunk(chunk); + } + mutex_release(&theheap.lock); + +} + +// try to insert this free chunk into the free list, consuming the chunk by merging it with +// nearby ones if possible. Returns base of whatever chunk it became in the list. +static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk) +{ +#if LK_DEBUGLEVEL > INFO + vaddr_t chunk_end = (vaddr_t)chunk + chunk->len; +#endif + + LTRACEF("chunk ptr %p, size 0x%zx\n", chunk, chunk->len); + + struct free_heap_chunk *next_chunk; + struct free_heap_chunk *last_chunk; + + mutex_acquire(&theheap.lock); + + theheap.remaining += chunk->len; + + // walk through the list, finding the node to insert before + list_for_every_entry(&theheap.free_list, next_chunk, struct free_heap_chunk, node) { + if (chunk < next_chunk) { + DEBUG_ASSERT(chunk_end <= (vaddr_t)next_chunk); + + list_add_before(&next_chunk->node, &chunk->node); + + goto try_merge; + } + } + + // walked off the end of the list, add it at the tail + list_add_tail(&theheap.free_list, &chunk->node); + + // try to merge with the previous chunk +try_merge: + last_chunk = list_prev_type(&theheap.free_list, &chunk->node, struct free_heap_chunk, node); + if (last_chunk) { + if ((vaddr_t)last_chunk + last_chunk->len == (vaddr_t)chunk) { + // easy, just extend the previous chunk + last_chunk->len += chunk->len; + + // remove ourself from the list + list_delete(&chunk->node); + + // set the chunk pointer to the newly extended chunk, in case + // it needs to merge with the next chunk below + chunk = last_chunk; + } + } + + // try to merge with the next chunk + if (next_chunk) { + if ((vaddr_t)chunk + chunk->len == (vaddr_t)next_chunk) { + // extend our chunk + chunk->len += next_chunk->len; + + // remove them from the list + list_delete(&next_chunk->node); + } + } + + mutex_release(&theheap.lock); + + return chunk; +} + +static struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len, bool allow_debug) +{ + DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary + +#if DEBUG_HEAP + if (allow_debug) + memset(ptr, FREE_FILL, len); +#endif + + struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr; + chunk->len = len; + + return chunk; +} + +void *miniheap_alloc(size_t size, unsigned int alignment) +{ + void *ptr; +#if DEBUG_HEAP + size_t original_size = size; +#endif + + LTRACEF("size %zd, align %d\n", size, alignment); + + // alignment must be power of 2 + if (alignment & (alignment - 1)) + return NULL; + + // we always put a size field + base pointer + magic in front of the allocation + size += sizeof(struct alloc_struct_begin); +#if DEBUG_HEAP + size += PADDING_SIZE; +#endif + + // make sure we allocate at least the size of a struct free_heap_chunk so that + // when we free it, we can create a struct free_heap_chunk struct and stick it + // in the spot + if (size < sizeof(struct free_heap_chunk)) + size = sizeof(struct free_heap_chunk); + + // round up size to a multiple of native pointer size + size = ROUNDUP(size, sizeof(void *)); + + // deal with nonzero alignments + if (alignment > 0) { + if (alignment < 16) + alignment = 16; + + // add alignment for worst case fit + size += alignment; + } + + int retry_count = 0; +retry: + mutex_acquire(&theheap.lock); + + // walk through the list + ptr = NULL; + struct free_heap_chunk *chunk; + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + DEBUG_ASSERT((chunk->len % sizeof(void *)) == 0); // len should always be a multiple of pointer size + + // is it big enough to service our allocation? + if (chunk->len >= size) { + ptr = chunk; + + // remove it from the list + struct list_node *next_node = list_next(&theheap.free_list, &chunk->node); + list_delete(&chunk->node); + + if (chunk->len > size + sizeof(struct free_heap_chunk)) { + // there's enough space in this chunk to create a new one after the allocation + struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size, true); + + // truncate this chunk + chunk->len -= chunk->len - size; + + // add the new one where chunk used to be + if (next_node) + list_add_before(next_node, &newchunk->node); + else + list_add_tail(&theheap.free_list, &newchunk->node); + } + + // the allocated size is actually the length of this chunk, not the size requested + DEBUG_ASSERT(chunk->len >= size); + size = chunk->len; + +#if DEBUG_HEAP + memset(ptr, ALLOC_FILL, size); +#endif + + ptr = (void *)((addr_t)ptr + sizeof(struct alloc_struct_begin)); + + // align the output if requested + if (alignment > 0) { + ptr = (void *)ROUNDUP((addr_t)ptr, (addr_t)alignment); + } + + struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; + as--; +#if LK_DEBUGLEVEL > 1 + as->magic = HEAP_MAGIC; +#endif + as->ptr = (void *)chunk; + as->size = size; + theheap.remaining -= size; + + if (theheap.remaining < theheap.low_watermark) { + theheap.low_watermark = theheap.remaining; + } +#if DEBUG_HEAP + as->padding_start = ((uint8_t *)ptr + original_size); + as->padding_size = (((addr_t)chunk + size) - ((addr_t)ptr + original_size)); +// printf("padding start %p, size %u, chunk %p, size %u\n", as->padding_start, as->padding_size, chunk, size); + + memset(as->padding_start, PADDING_FILL, as->padding_size); +#endif + + break; + } + } + + mutex_release(&theheap.lock); + + /* try to grow the heap if we can */ + if (ptr == NULL && retry_count == 0) { + ssize_t err = heap_grow(size); + if (err >= 0) { + retry_count++; + goto retry; + } + } + + LTRACEF("returning ptr %p\n", ptr); + + return ptr; +} + +void *miniheap_realloc(void *ptr, size_t size) +{ + /* slow implementation */ + if (!ptr) + return miniheap_alloc(size, 0); + if (size == 0) { + miniheap_free(ptr); + return NULL; + } + + // XXX better implementation + void *p = miniheap_alloc(size, 0); + if (!p) + return NULL; + + memcpy(p, ptr, size); // XXX wrong + miniheap_free(ptr); + + return p; +} + +void miniheap_free(void *ptr) +{ + if (!ptr) + return; + + LTRACEF("ptr %p\n", ptr); + + // check for the old allocation structure + struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; + as--; + + DEBUG_ASSERT(as->magic == HEAP_MAGIC); + +#if DEBUG_HEAP + { + uint i; + uint8_t *pad = (uint8_t *)as->padding_start; + + for (i = 0; i < as->padding_size; i++) { + if (pad[i] != PADDING_FILL) { + printf("free at %p scribbled outside the lines:\n", ptr); + hexdump(pad, as->padding_size); + panic("die\n"); + } + } + } +#endif + + LTRACEF("allocation was %zd bytes long at ptr %p\n", as->size, as->ptr); + + // looks good, create a free chunk and add it to the pool + heap_insert_free_chunk(heap_create_free_chunk(as->ptr, as->size, true)); + +#if MINIHEAP_AUTOTRIM + miniheap_trim(); +#endif +} + +void miniheap_trim(void) +{ + LTRACE_ENTRY; + + mutex_acquire(&theheap.lock); + + // walk through the list, finding free chunks that can be returned to the page allocator + struct free_heap_chunk *chunk; + struct free_heap_chunk *next_chunk; + list_for_every_entry_safe(&theheap.free_list, chunk, next_chunk, struct free_heap_chunk, node) { + LTRACEF("looking at chunk %p, len 0x%zx\n", chunk, chunk->len); + + uintptr_t start = (uintptr_t)chunk; + uintptr_t end = start + chunk->len; + DEBUG_ASSERT(end > start); // make sure it doesn't wrap the address space and has a positive len + + // compute the page aligned region in this free block (if any) + uintptr_t start_page = ROUNDUP(start, PAGE_SIZE); + uintptr_t end_page = ROUNDDOWN(end, PAGE_SIZE); + DEBUG_ASSERT(end_page <= end); + DEBUG_ASSERT(start_page >= start); + + LTRACEF("start page 0x%lx, end page 0x%lx\n", start_page, end_page); + +retry: + // see if the free block encompasses at least one page + if (unlikely(end_page > start_page)) { + LTRACEF("could trim: start 0x%lx, end 0x%lx\n", start_page, end_page); + + // cases where the start of the block is already page aligned + if (start_page == start) { + // look for special case, we're going to completely remove the chunk + if (end_page == end) { + LTRACEF("special case, free chunk completely covers page(s)\n"); + list_delete(&chunk->node); + goto free_chunk; + } + } else { + // start of block is not page aligned, + // will there be enough space before the block if we trim? + if (start_page - start < sizeof(struct free_heap_chunk)) { + LTRACEF("not enough space for free chunk before\n"); + start_page += PAGE_SIZE; + goto retry; + } + } + + // do we need to split the free block and create a new block afterwards? + if (end_page < end) { + size_t new_chunk_size = end - end_page; + LTRACEF("will have to split, new chunk will be 0x%zx bytes long\n", new_chunk_size); + + // if there's not enough space afterwards for a free chunk, we can't free the last page + if (new_chunk_size < sizeof(struct free_heap_chunk)) { + LTRACEF("not enough space for free chunk afterwards\n"); + end_page -= PAGE_SIZE; + goto retry; + } + + // trim the new space off the end of the current chunk + chunk->len -= new_chunk_size; + end = end_page; + + // create a new chunk after the one we're trimming + struct free_heap_chunk *new_chunk = heap_create_free_chunk((void *)end_page, new_chunk_size, false); + + // link it with the current block + list_add_after(&chunk->node, &new_chunk->node); + } + + // check again to see if we are now completely covering a block + if (start_page == start && end_page == end) { + LTRACEF("special case, after splitting off new chunk, free chunk completely covers page(s)\n"); + list_delete(&chunk->node); + goto free_chunk; + } + + // trim the size of the block + chunk->len -= end_page - start_page; + +free_chunk: + // return it to the allocator + LTRACEF("returning %p size 0x%lx to the page allocator\n", (void *)start_page, end_page - start_page); + page_free((void *)start_page, (end_page - start_page) / PAGE_SIZE); + + // tweak accounting + theheap.remaining -= end_page - start_page; + } + } + + mutex_release(&theheap.lock); +} + +void miniheap_get_stats(struct miniheap_stats *ptr) +{ + struct free_heap_chunk *chunk; + + ptr->heap_start = theheap.base; + ptr->heap_len = theheap.len; + ptr->heap_free=0; + ptr->heap_max_chunk = 0; + + mutex_acquire(&theheap.lock); + + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + ptr->heap_free += chunk->len; + + if (chunk->len > ptr->heap_max_chunk) { + ptr->heap_max_chunk = chunk->len; + } + } + + ptr->heap_low_watermark = theheap.low_watermark; + + mutex_release(&theheap.lock); +} + +static ssize_t heap_grow(size_t size) +{ + size = ROUNDUP(size, PAGE_SIZE); + void *ptr = page_alloc(size / PAGE_SIZE); + if (!ptr) { + TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); + return ERR_NO_MEMORY; + } + + LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); + + heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true)); + + /* change the heap start and end variables */ + if ((uintptr_t)ptr < (uintptr_t)theheap.base || theheap.base == 0) + theheap.base = ptr; + + uintptr_t endptr = (uintptr_t)ptr + size; + if (endptr > (uintptr_t)theheap.base + theheap.len) { + theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; + } + + return size; +} + +void miniheap_init(void *ptr, size_t len) +{ + LTRACEF("ptr %p, len %zu\n", ptr, len); + + // create a mutex + mutex_init(&theheap.lock); + + // initialize the free list + list_initialize(&theheap.free_list); + + // set the heap range + theheap.base = ptr; + theheap.len = len; + theheap.remaining = 0; // will get set by heap_insert_free_chunk() + theheap.low_watermark = 0; + + // if passed a default range, use it + if (len > 0) + heap_insert_free_chunk(heap_create_free_chunk(ptr, len, true)); +} + diff --git a/kernel/lib/heap/miniheap/rules.mk b/kernel/lib/heap/miniheap/rules.mk new file mode 100644 index 000000000..d6a3474dd --- /dev/null +++ b/kernel/lib/heap/miniheap/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +GLOBAL_INCLUDES += $(LOCAL_DIR)/include + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/miniheap.c + +include make/module.mk diff --git a/kernel/lib/heap/new.cpp b/kernel/lib/heap/new.cpp new file mode 100644 index 000000000..1607db27d --- /dev/null +++ b/kernel/lib/heap/new.cpp @@ -0,0 +1,36 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2006-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +void *operator new(size_t s) +{ + return malloc(s); +} + +void *operator new[](size_t s) +{ + return malloc(s); +} + +void *operator new(size_t , void *p) +{ + return p; +} + +void operator delete(void *p) +{ + return free(p); +} + +void operator delete[](void *p) +{ + return free(p); +} + diff --git a/kernel/lib/heap/page_alloc.c b/kernel/lib/heap/page_alloc.c new file mode 100644 index 000000000..6aeee7822 --- /dev/null +++ b/kernel/lib/heap/page_alloc.c @@ -0,0 +1,113 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +#include +#include +#include +#include +#if WITH_KERNEL_VM +#include +#else +#include +#endif + +/* A simple page-aligned wrapper around the pmm or novm implementation of + * the underlying physical page allocator. Used by system heaps or any + * other user that wants pages of memory but doesn't want to use LK + * specific apis. + */ +#define LOCAL_TRACE 0 + +#if WITH_STATIC_HEAP + +#error "fix static heap post page allocator and novm stuff" + +#if !defined(HEAP_START) || !defined(HEAP_LEN) +#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined +#endif + +#endif + +void *page_alloc(size_t pages) +{ +#if WITH_KERNEL_VM + void *result = pmm_alloc_kpages(pages, NULL, NULL); + return result; +#else + void *result = novm_alloc_pages(pages, NOVM_ARENA_ANY); + return result; +#endif +} + +void page_free(void *ptr, size_t pages) +{ +#if WITH_KERNEL_VM + DEBUG_ASSERT(IS_PAGE_ALIGNED((uintptr_t)ptr)); + + pmm_free_kpages(ptr, pages); +#else + novm_free_pages(ptr, pages); +#endif +} + +void *page_first_alloc(size_t *size_return) +{ +#if WITH_KERNEL_VM + *size_return = PAGE_SIZE; + return page_alloc(1); +#else + return novm_alloc_unaligned(size_return); +#endif +} + +#if LK_DEBUGLEVEL > 1 +#if WITH_LIB_CONSOLE + +#include + +static int cmd_page_alloc(int argc, const cmd_args *argv); +static void page_alloc_dump(void); + +STATIC_COMMAND_START +STATIC_COMMAND("page_alloc", "page allocator debug commands", &cmd_page_alloc) +STATIC_COMMAND_END(page_alloc); + +static int cmd_page_alloc(int argc, const cmd_args *argv) +{ + if (argc != 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + return -1; + } + + if (strcmp(argv[1].str, "info") == 0) { + page_alloc_dump(); + } else { + printf("unrecognized command\n"); + goto usage; + } + + return 0; +} + +static void page_alloc_dump(void) +{ +#ifdef WITH_KERNEL_VM + dprintf(INFO, "Page allocator is based on pmm\n"); +#else + dprintf(INFO, "Page allocator is based on novm\n"); +#endif +} + +#endif +#endif diff --git a/kernel/lib/heap/rules.mk b/kernel/lib/heap/rules.mk new file mode 100644 index 000000000..a32acc5ca --- /dev/null +++ b/kernel/lib/heap/rules.mk @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +GLOBAL_INCLUDES += $(LOCAL_DIR)/include + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/heap_wrapper.c \ + $(LOCAL_DIR)/page_alloc.c \ + $(LOCAL_DIR)/new.cpp + +# pick a heap implementation +ifndef LK_HEAP_IMPLEMENTATION +LK_HEAP_IMPLEMENTATION=miniheap +endif +ifeq ($(LK_HEAP_IMPLEMENTATION),miniheap) +MODULE_DEPS := lib/heap/miniheap +endif +ifeq ($(LK_HEAP_IMPLEMENTATION),cmpctmalloc) +MODULE_DEPS := lib/heap/cmpctmalloc +endif + +GLOBAL_DEFINES += LK_HEAP_IMPLEMENTATION=$(LK_HEAP_IMPLEMENTATION) + +include make/module.mk diff --git a/kernel/lib/io/BUILD.gn b/kernel/lib/io/BUILD.gn new file mode 100644 index 000000000..4169ab978 --- /dev/null +++ b/kernel/lib/io/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("_io_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + defines = [ "WITH_LIB_IO=1" ] +} + +module("io") { + public_configs = [ ":_io_config" ] + public = [ + "include/lib/io.h", + ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/libc/include", + ] + sources = [ + "console.c", + "io.c", + ] + if (enable_debuglog) { + # TODO(phosek): only console.c depends on debuglog, we should move it to + # a separate source_set to break up the dependency + deps = [ + "//kernel/lib/debuglog", + ] + } +} diff --git a/kernel/lib/io/console.c b/kernel/lib/io/console.c new file mode 100644 index 000000000..905b30504 --- /dev/null +++ b/kernel/lib/io/console.c @@ -0,0 +1,154 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_LIB_DEBUGLOG +#include +#endif + +/* routines for dealing with main console io */ + +#if WITH_LIB_SM +#define PRINT_LOCK_FLAGS SPIN_LOCK_FLAG_IRQ_FIQ +#else +#define PRINT_LOCK_FLAGS SPIN_LOCK_FLAG_INTERRUPTS +#endif + +static spin_lock_t print_spin_lock = 0; +static struct list_node print_callbacks = LIST_INITIAL_VALUE(print_callbacks); + + +#if WITH_DEBUG_LINEBUFFER +static void __out_count(const char *str, size_t len); + +static void out_count(const char *str, size_t len) { + thread_t *t = get_current_thread(); + + if (t == NULL) { + __out_count(str, len); + return; + } + + char *buf = t->linebuffer; + size_t pos = t->linebuffer_pos; + + while (len-- > 0) { + char c = *str++; + buf[pos++] = c; + if (c == '\n') { + __out_count(buf, pos); + pos = 0; + continue; + } + if (pos == (THREAD_LINEBUFFER_LENGTH - 1)) { + buf[pos++] = '\n'; + __out_count(buf, pos); + pos = 0; + continue; + } + } + t->linebuffer_pos = pos; +} +#else +#define __out_count out_count +#endif + +static spin_lock_t dputc_spin_lock = 0; +static void __raw_out_count(const char *str, size_t len) { + spin_lock_saved_state_t state; + spin_lock_save(&dputc_spin_lock, &state, PRINT_LOCK_FLAGS); + /* write out the serial port */ + for (size_t i = 0; i < len; i++) { + platform_dputc(str[i]); + } + spin_unlock_restore(&dputc_spin_lock, state, PRINT_LOCK_FLAGS); +} + +/* print lock must be held when invoking out, outs, outc */ +static void __out_count(const char *str, size_t len) +{ + print_callback_t *cb; + + /* print to any registered loggers */ + if (!list_is_empty(&print_callbacks)) { + spin_lock_saved_state_t state; + spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS); + + list_for_every_entry(&print_callbacks, cb, print_callback_t, entry) { + if (cb->print) + cb->print(cb, str, len); + } + + spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS); + } + +#if WITH_LIB_DEBUGLOG + if (dlog_write(DLOG_FLAG_KERNEL, str, len)) { + __raw_out_count(str, len); + } +#else + __raw_out_count(str, len); +#endif +} + +void register_print_callback(print_callback_t *cb) +{ + spin_lock_saved_state_t state; + spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS); + + list_add_head(&print_callbacks, &cb->entry); + + spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS); +} + +void unregister_print_callback(print_callback_t *cb) +{ + spin_lock_saved_state_t state; + spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS); + + list_delete(&cb->entry); + + spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS); +} + +static ssize_t __debug_stdio_write(io_handle_t *io, const char *s, size_t len) +{ + out_count(s, len); + return len; +} + +static ssize_t __debug_stdio_read(io_handle_t *io, char *s, size_t len) +{ + if (len == 0) + return 0; + + int err = platform_dgetc(s, true); + if (err < 0) + return err; + + return 1; +} + +/* global console io handle */ +static const io_handle_hooks_t console_io_hooks = { + .write = __debug_stdio_write, + .read = __debug_stdio_read, +}; + +io_handle_t console_io = IO_HANDLE_INITIAL_VALUE(&console_io_hooks); diff --git a/kernel/lib/io/include/lib/io.h b/kernel/lib/io/include/lib/io.h new file mode 100644 index 000000000..8bff1c5a5 --- /dev/null +++ b/kernel/lib/io/include/lib/io.h @@ -0,0 +1,59 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +/* LK specific calls to register to get input/output of the main console */ + +__BEGIN_CDECLS + +typedef struct __print_callback print_callback_t; +struct __print_callback { + struct list_node entry; + void (*print)(print_callback_t *cb, const char *str, size_t len); + void *context; +}; + +/* register callback to receive debug prints */ +void register_print_callback(print_callback_t *cb); +void unregister_print_callback(print_callback_t *cb); + +/* the underlying handle to talk to io devices */ +struct io_handle; +typedef struct io_handle_hooks { + ssize_t (*write)(struct io_handle *handle, const char *buf, size_t len); + ssize_t (*read)(struct io_handle *handle, char *buf, size_t len); +} io_handle_hooks_t; + +#define IO_HANDLE_MAGIC (0x696f6820) // "ioh " + +typedef struct io_handle { + uint32_t magic; + const io_handle_hooks_t *hooks; +} io_handle_t; + +/* routines to call through the io handle */ +ssize_t io_write(io_handle_t *io, const char *buf, size_t len); +ssize_t io_read(io_handle_t *io, char *buf, size_t len); + +/* initialization routine */ +#define IO_HANDLE_INITIAL_VALUE(_hooks) { .magic = IO_HANDLE_MAGIC, .hooks = _hooks } + +static inline void io_handle_init(io_handle_t *io, io_handle_hooks_t *hooks) +{ + *io = (io_handle_t)IO_HANDLE_INITIAL_VALUE(hooks); +} + +/* the main console io handle */ +extern io_handle_t console_io; + + +__END_CDECLS diff --git a/kernel/lib/io/io.c b/kernel/lib/io/io.c new file mode 100644 index 000000000..d6589aa8c --- /dev/null +++ b/kernel/lib/io/io.c @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include + +ssize_t io_write(io_handle_t *io, const char *buf, size_t len) +{ + DEBUG_ASSERT(io->magic == IO_HANDLE_MAGIC); + + if (!io->hooks->write) + return ERR_NOT_SUPPORTED; + + return io->hooks->write(io, buf, len); +} + +ssize_t io_read(io_handle_t *io, char *buf, size_t len) +{ + DEBUG_ASSERT(io->magic == IO_HANDLE_MAGIC); + + if (!io->hooks->read) + return ERR_NOT_SUPPORTED; + + return io->hooks->read(io, buf, len); +} + diff --git a/kernel/lib/io/rules.mk b/kernel/lib/io/rules.mk new file mode 100644 index 000000000..a49baed1f --- /dev/null +++ b/kernel/lib/io/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + +MODULE_SRCS += \ + $(LOCAL_DIR)/console.c \ + $(LOCAL_DIR)/io.c \ + +include make/module.mk diff --git a/kernel/lib/iovec/BUILD.gn b/kernel/lib/iovec/BUILD.gn new file mode 100644 index 000000000..b106c3cfd --- /dev/null +++ b/kernel/lib/iovec/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("iovec") { + sources = [ + "iovec.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/iovec/iovec.c b/kernel/lib/iovec/iovec.c new file mode 100644 index 000000000..88241ce26 --- /dev/null +++ b/kernel/lib/iovec/iovec.c @@ -0,0 +1,74 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +#include + +#define LOCAL_TRACE 0 + +/* + * Calc total size of iovec buffers + */ +ssize_t iovec_size (const iovec_t *iov, uint iov_cnt) +{ + if (!iov) + return (ssize_t) ERR_INVALID_ARGS; + + size_t c = 0; + for (uint i = 0; i < iov_cnt; i++, iov++) { + c += iov->iov_len; + } + return (ssize_t) c; +} + +/* + * Copy out portion of iovec started from given position + * into single buffer + */ +ssize_t iovec_to_membuf (uint8_t *buf, uint buf_len, const iovec_t *iov, uint iov_cnt, uint iov_pos) +{ + uint buf_pos = 0; + + if (!buf || !iov) + return (ssize_t) ERR_INVALID_ARGS; + + /* for all iovec */ + for (uint i = 0; i < iov_cnt; i++, iov++) { + + if (iov_pos >= iov->iov_len) { + iov_pos -= iov->iov_len; /* skip whole chunks */ + continue; + } + + /* calc number of bytes left in current iov */ + size_t to_copy = (size_t) (iov->iov_len - iov_pos); + + /* limit it to number of bytes left in buffer */ + if (to_copy > buf_len) + to_copy = buf_len; + + /* copy data out */ + memcpy (buf + buf_pos, (uint8_t *)iov->iov_base + iov_pos, to_copy); + + /* advance in buffer position */ + buf_pos += to_copy; + buf_len -= to_copy; + + /* check if we need to copy more data */ + if (buf_len == 0) + break; + + iov_pos = 0; /* it is only possible to have fully copied iovec here */ + } + + return (ssize_t) buf_pos; +} diff --git a/kernel/lib/iovec/rules.mk b/kernel/lib/iovec/rules.mk new file mode 100644 index 000000000..efd08e4a8 --- /dev/null +++ b/kernel/lib/iovec/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/iovec.c \ + +include make/module.mk diff --git a/kernel/lib/klog/BUILD.gn b/kernel/lib/klog/BUILD.gn new file mode 100644 index 000000000..6710c96e7 --- /dev/null +++ b/kernel/lib/klog/BUILD.gn @@ -0,0 +1,37 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_klog") { + if (enable_klog) { + defines = [ "WITH_LIB_KLOG=1" ] + } else { + defines = [ "WITH_LIB_KLOG=0" ] + } +} + +config("_klog_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + configs = [ ":enable_klog" ] +} + +module("klog") { + public_configs = [ ":_klog_config" ] + public = [ + "include/lib/klog.h", + ] + sources = [ + "klog.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/io", + "//kernel/lib/libc", + "//third_party/lib/cksum", + ] +} diff --git a/kernel/lib/klog/include/lib/klog.h b/kernel/lib/klog/include/lib/klog.h new file mode 100644 index 000000000..ca2650083 --- /dev/null +++ b/kernel/lib/klog/include/lib/klog.h @@ -0,0 +1,65 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include + +__BEGIN_CDECLS + +#if WITH_LIB_KLOG + +#define KLOG_CURRENT_BUFFER -1 + +void klog_init(void); + +ssize_t klog_recover(void *ptr); +status_t klog_create(void *ptr, size_t len, uint count); + +uint klog_buffer_count(void); +uint klog_current_buffer(void); +status_t klog_set_current_buffer(uint buffer); + +/* dump the klog to the console, -1 is current buffer */ +void klog_dump(int buffer); + +/* + * Fill in an iovec that points to the requested buffer, -1 is current buffer. + * The buffer may be in 2 pieces, due to the internal circular buffer. + * Return is number of iovec runs. + */ +int klog_get_buffer(int buffer, iovec_t *vec); + +/* + * Read functions actively remove data from the klog on read + */ +ssize_t klog_read(char *buf, size_t len, int buf_id); +char klog_getc(int buf_id); +char klog_getchar(void); +bool klog_has_data(void); + +void klog_putchar(char c); +void klog_puts(const char *str); +void klog_printf(const char *fmt, ...) __PRINTFLIKE(1, 2); +void klog_vprintf(const char *fmt, va_list ap); + +#else + +/* if klog is not present, stub out the input routines */ +static inline void klog_putc(char c) {} +static inline void klog_puts(const char *str) {} +static inline void klog_printf(const char *fmt, ...) {} +static inline void klog_vprintf(const char *fmt, va_list ap) {} + +#endif + +__END_CDECLS diff --git a/kernel/lib/klog/klog.c b/kernel/lib/klog/klog.c new file mode 100644 index 000000000..341209125 --- /dev/null +++ b/kernel/lib/klog/klog.c @@ -0,0 +1,623 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#ifndef MAX_KLOG_SIZE +#define MAX_KLOG_SIZE (32*1024) +#endif + +#define KLOG_BUFFER_HEADER_MAGIC 'KLGB' + +struct klog_buffer_header { + uint32_t magic; + uint32_t header_crc32; + uint32_t log_count; + uint32_t current_log; + uint32_t total_size; +}; + +#define KLOG_HEADER_MAGIC 'KLOG' + +struct klog_header { + uint32_t magic; + uint32_t size; + uint32_t head; + uint32_t tail; + uint32_t data_checksum; + uint8_t data[0]; +}; + +/* current klog buffer */ +static struct klog_buffer_header *klog_buf; + +/* current klog */ +static struct klog_header *klog; + +static struct klog_header *find_nth_log(uint log) +{ + DEBUG_ASSERT(klog_buf); + DEBUG_ASSERT(klog_buf->magic == KLOG_BUFFER_HEADER_MAGIC); + DEBUG_ASSERT(log < klog_buf->log_count); + + struct klog_header *k = (struct klog_header *)(klog_buf + 1); + while (log > 0) { + DEBUG_ASSERT(k->magic == KLOG_HEADER_MAGIC); + + uint8_t *ptr = (uint8_t *)k->data; + ptr += k->size; + k = (struct klog_header *)ptr; + + log--; + } + + return k; +} + +static uint32_t get_checksum_klog_buffer_header(const struct klog_buffer_header *kb) +{ + DEBUG_ASSERT(kb); + DEBUG_ASSERT(kb->magic == KLOG_BUFFER_HEADER_MAGIC); + + return crc32(0, (const void *)(&kb->header_crc32 + 1), sizeof(*kb) - 8); +} + +static uint32_t get_checksum_klog_data(const struct klog_header *k) +{ + DEBUG_ASSERT(k); + DEBUG_ASSERT(k->magic == KLOG_HEADER_MAGIC); + + uint32_t sum = 0; + for (uint i = 0; i < k->size; i++) { + sum += k->data[i]; + } + + return sum; +} + +static void checksum_klog_buffer_header(struct klog_buffer_header *kb) +{ + DEBUG_ASSERT(kb); + DEBUG_ASSERT(kb->magic == KLOG_BUFFER_HEADER_MAGIC); + + kb->header_crc32 = get_checksum_klog_buffer_header(kb); +} + +static void checksum_klog_data(struct klog_header *k) +{ + DEBUG_ASSERT(k); + DEBUG_ASSERT(k->magic == KLOG_HEADER_MAGIC); + + k->data_checksum = get_checksum_klog_data(k); +} + +status_t klog_create(void *_ptr, size_t len, uint count) +{ + uint8_t *ptr = _ptr; + LTRACEF("ptr %p len %zu count %u\n", ptr, len, count); + + /* check args */ + if (!ptr) + return ERR_INVALID_ARGS; + if (count == 0) + return ERR_INVALID_ARGS; + + /* check that the size is big enough */ + if (len < (sizeof(struct klog_buffer_header) + sizeof(struct klog_header) * count + 4 * count)) + return ERR_INVALID_ARGS; + + /* set up the buffer header */ + klog_buf = (struct klog_buffer_header *)ptr; + klog_buf->magic = KLOG_BUFFER_HEADER_MAGIC; + klog_buf->log_count = count; + klog_buf->current_log = 0; + klog_buf->total_size = len; + checksum_klog_buffer_header(klog_buf); + ptr += sizeof(struct klog_buffer_header); + + /* set up each buffer */ + uint bufsize = len - sizeof(struct klog_buffer_header) - sizeof(struct klog_header) * count; + bufsize /= count; + bufsize = ROUNDDOWN(bufsize, 4); + while (count > 0) { + klog = (struct klog_header *)ptr; + klog->magic = KLOG_HEADER_MAGIC; + klog->size = bufsize; + klog->head = 0; + klog->tail = 0; + klog->data_checksum = 0; + memset(klog + 1, 0, bufsize); + checksum_klog_data(klog); + ptr += sizeof(struct klog_header) + bufsize; + count--; + } + + klog_set_current_buffer(0); + + DEBUG_ASSERT(klog_buf); + DEBUG_ASSERT(klog); + + return NO_ERROR; +} + +ssize_t klog_recover(void *_ptr) +{ + uint8_t *ptr = _ptr; + LTRACEF("ptr %p\n", ptr); + + if (!ptr) + return ERR_INVALID_ARGS; + + /* look for header at pointer */ + struct klog_buffer_header *kbuf = (struct klog_buffer_header *)ptr; + if (kbuf->magic != KLOG_BUFFER_HEADER_MAGIC) + return ERR_NOT_FOUND; + uint32_t crc = get_checksum_klog_buffer_header(kbuf); + if (crc != kbuf->header_crc32) + return ERR_NOT_FOUND; + + /* some sanity checks */ + if (kbuf->total_size > MAX_KLOG_SIZE) + return ERR_NOT_FOUND; + if (kbuf->current_log >= kbuf->log_count) + return ERR_NOT_FOUND; + + /* walk the list of klogs, validating */ + ptr += sizeof(struct klog_buffer_header); + for (uint i = 0; i < kbuf->log_count; i++) { + struct klog_header *k = (struct klog_header *)ptr; + + /* validate the individual klog */ + if (k->magic != KLOG_HEADER_MAGIC) + return ERR_NOT_FOUND; + + /* validate some fields */ + if ((k->size > 0) && (k->size & 3)) + return ERR_NOT_FOUND; + if (k->size > MAX_KLOG_SIZE) + return ERR_NOT_FOUND; + if (k->head >= k->size) + return ERR_NOT_FOUND; + if (k->tail >= k->size) + return ERR_NOT_FOUND; + + /* data checksum */ + if (k->data_checksum) { + crc = get_checksum_klog_data(k); + if (crc != k->data_checksum) + return ERR_NOT_FOUND; + } + + ptr += sizeof(struct klog_header) + k->size; + } + + /* everything checks out */ + klog_buf = kbuf; + klog_set_current_buffer(klog_buf->current_log); + + LTRACEF("found buffer at %p, current log %u (%p) head %u tail %u size %u\n", + klog_buf, klog_buf->current_log, klog, klog->head, klog->tail, klog->size); + + return NO_ERROR; +} + +uint klog_buffer_count(void) +{ + if (!klog_buf) + return 0; + + DEBUG_ASSERT(klog_buf); + DEBUG_ASSERT(klog_buf->magic == KLOG_BUFFER_HEADER_MAGIC); + + return klog_buf->log_count; +} + +uint klog_current_buffer(void) +{ + if (!klog_buf) + return 0; + + DEBUG_ASSERT(klog_buf); + DEBUG_ASSERT(klog_buf->magic == KLOG_BUFFER_HEADER_MAGIC); + + return klog_buf->current_log; +} + +status_t klog_set_current_buffer(uint buffer) +{ + if (!klog_buf) + return ERR_NOT_FOUND; + + DEBUG_ASSERT(klog_buf); + DEBUG_ASSERT(klog_buf->magic == KLOG_BUFFER_HEADER_MAGIC); + + if (buffer >= klog_buf->log_count) + return ERR_INVALID_ARGS; + + /* find the nth buffer */ + klog = find_nth_log(buffer); + + /* update the klog buffer header */ + if (buffer != klog_buf->current_log) { + klog_buf->current_log = buffer; + checksum_klog_buffer_header(klog_buf); + } + + return NO_ERROR; +} + +#include + +ssize_t klog_read(char *buf, size_t len, int buf_id) +{ + size_t offset = 0; + size_t tmp_len; + iovec_t vec[2]; + LTRACEF("read (len %zu, buf %u)\n", len, buf_id); + + DEBUG_ASSERT(klog); + DEBUG_ASSERT(klog->magic == KLOG_HEADER_MAGIC); + + /* If a klog wraps around at the end then it becomes two iovecs with + * tail being the start of 1 and head being the end of 0. This means we + * need to check where we are in the overall klog to properly determine + * which iovec we want to read from */ + int vec_cnt = klog_get_buffer(buf_id, vec); + if (vec_cnt < 1) + return vec_cnt; + + tmp_len = MIN(len, vec[0].iov_len); + memcpy(buf, (const char *)vec[0].iov_base, tmp_len); + offset += tmp_len; + len -= tmp_len; + + if (len != 0 && vec_cnt > 1) { + tmp_len = MIN(len, vec[1].iov_len); + memcpy(buf + offset, (const char *)vec[1].iov_base, tmp_len); + offset += tmp_len; + } + + /* Since iovecs are generated by get_buffer we only need to update the tail pointer */ + klog->tail += offset; + if (klog->tail >= klog->size) + klog->tail -= klog->size; + + return offset; +} + +char klog_getc(int buf_id) +{ + char c = '\0'; + int err = klog_read(&c, 1, buf_id); + + return (err < 0) ? err : c; +} + +char klog_getchar(void) +{ + return klog_getc(-1); +} + +/* Returns whether the currently selected klog contains data */ +bool klog_has_data(void) +{ + DEBUG_ASSERT(klog); + + return (klog->head != klog->tail); +} + +static size_t klog_puts_len(const char *str, size_t len) +{ + LTRACEF("puts '%s'\n", str); + + DEBUG_ASSERT(klog); + DEBUG_ASSERT(klog->magic == KLOG_HEADER_MAGIC); + + LTRACEF("before write head %u tail %u size %u\n", klog->head, klog->tail, klog->size); + uint32_t deltasum = 0; + size_t count = 0; + while (count < len && *str) { + /* compute the delta checksum */ + deltasum += *str - klog->data[klog->head]; + + /* store the data */ + klog->data[klog->head] = *str; + + /* bump the head */ + uint newhead = klog->head + 1; + if (newhead >= klog->size) + newhead -= klog->size; + DEBUG_ASSERT(newhead < klog->size); + + /* bump the tail if the head collided with it */ + if (klog->tail == newhead) { + uint newtail = klog->tail + 1; + if (newtail >= klog->size) + newtail -= klog->size; + DEBUG_ASSERT(newtail < klog->size); + klog->tail = newtail; + } + + /* writeback the head */ + klog->head = newhead; + + str++; + count++; + } + LTRACEF("after write head %u tail %u\n", klog->head, klog->tail); + + klog->data_checksum += deltasum; + + LTRACEF("kputs len %zu\n", count); + + return count; +} + +void klog_putchar(char c) +{ + klog_puts_len(&c, 1); +} + +void klog_puts(const char *str) +{ + if (!klog_buf) + return; + + klog_puts_len(str, SIZE_MAX); +} + +static int _klog_output_func(const char *str, size_t len, void *state) +{ + return klog_puts_len(str, len); +} + +void klog_printf(const char *fmt, ...) +{ + if (!klog_buf) + return; + + va_list ap; + va_start(ap, fmt); + _printf_engine(&_klog_output_func, NULL, fmt, ap); + va_end(ap); +} + +void klog_vprintf(const char *fmt, va_list ap) +{ + if (!klog_buf) + return; + + _printf_engine(&_klog_output_func, NULL, fmt, ap); +} + +int klog_get_buffer(int buffer, iovec_t *vec) +{ + if (!klog_buf) + return 0; + if (!vec) + return ERR_INVALID_ARGS; + if (buffer >= 0 && (uint)buffer >= klog_buf->log_count) + return ERR_INVALID_ARGS; + + struct klog_header *k; + if (buffer < 0) + k = klog; + else + k = find_nth_log(buffer); + + DEBUG_ASSERT(k); + DEBUG_ASSERT(k->magic == KLOG_HEADER_MAGIC); + + vec[0].iov_base = &k->data[k->tail]; + if (k->head == k->tail) { + return 0; + } else if (k->head > k->tail) { + /* single run of data, between tail and head */ + vec[0].iov_len = k->head - k->tail; + + return 1; + } else { + vec[0].iov_len = k->size - k->tail; + + /* two segments */ + vec[1].iov_base = &k->data[0]; + vec[1].iov_len = k->head; + + return 2; + } +} + +void klog_dump(int buffer) +{ + iovec_t vec[2]; + + int err = klog_get_buffer(buffer, vec); + if (err <= 0) + return; + + for (uint i = 0; i < vec[0].iov_len; i++) + putchar(*((const char *)vec[0].iov_base + i)); + if (err > 1) { + for (uint i = 0; i < vec[1].iov_len; i++) + putchar(*((const char *)vec[1].iov_base + i)); + } +} + +#if WITH_LIB_IO + +#include + +static void klog_print_callback(print_callback_t *cb, const char *str, size_t len) +{ + klog_puts_len(str, len); +} + +static print_callback_t klog_cb = { + .entry = { 0 }, + .print = klog_print_callback, + .context = NULL +}; + +void klog_init(void) +{ + register_print_callback(&klog_cb); +} + +#else +void klog_init(void) +{ +} +#endif + +#if WITH_LIB_CONSOLE + +#include + +#define KLOG_RETENTION_TEST 0 +#if KLOG_RETENTION_TEST +#include + +_RETENTION_NOCLEAR(static uint8_t klog_test_buf[512]); +#endif + +static int cmd_klog(int argc, const cmd_args *argv) +{ + status_t err; + + if (argc < 2) { +notenoughargs: + printf("ERROR not enough arguments\n"); +usage: + printf("usage: %s create \n", argv[0].str); +#if KLOG_RETENTION_TEST + printf("usage: %s createret \n", argv[0].str); + printf("usage: %s recoverret \n", argv[0].str); +#endif + printf("usage: %s getbufcount\n", argv[0].str); + printf("usage: %s getbufnum\n", argv[0].str); + printf("usage: %s getbufptr\n", argv[0].str); + printf("usage: %s setbufnum \n", argv[0].str); + printf("usage: %s puts \n", argv[0].str); + printf("usage: %s read \n", argv[0].str); + printf("usage: %s printftest\n", argv[0].str); + printf("usage: %s dump [buffer num]\n", argv[0].str); + printf("usage: %s vec [buffer num]\n", argv[0].str); + return -1; + } + + if (!strcmp(argv[1].str, "create")) { + if (argc < 4) goto notenoughargs; + + uint size = argv[2].u; + uint count = argv[3].u; + + void *ptr = malloc(size); + if (!ptr) { + printf("error allocating memory for klog\n"); + return -1; + } + err = klog_create(ptr, size, count); + printf("klog_create returns %d\n", err); + if (err < 0) + free(ptr); +#if KLOG_RETENTION_TEST + } else if (!strcmp(argv[1].str, "createret")) { + err = klog_create(klog_test_buf, sizeof(klog_test_buf), 1); + printf("klog_create returns %d\n", err); + } else if (!strcmp(argv[1].str, "recoverret")) { + err = klog_recover(klog_test_buf); + printf("klog_recover returns %d\n", err); +#endif + } else if (!strcmp(argv[1].str, "getbufcount")) { + printf("%d buffers\n", klog_buffer_count()); + } else if (!strcmp(argv[1].str, "getbufnum")) { + printf("%d current buffer\n", klog_current_buffer()); + } else if (!strcmp(argv[1].str, "getbufptr")) { + printf("ptr %p\n", klog); + } else if (!strcmp(argv[1].str, "setbufnum")) { + if (argc < 3) goto notenoughargs; + + err = klog_set_current_buffer(argv[2].u); + printf("klog_set_current_buffer returns %d\n", err); + } else if (!strcmp(argv[1].str, "puts")) { + if (argc < 3) goto notenoughargs; + + klog_puts(argv[2].str); + klog_putchar('\n'); + } else if (!strcmp(argv[1].str, "read")) { + if (argc < 4) goto notenoughargs; + size_t len = argv[2].u; + int buf_id = argv[3].i; + char *buf = malloc(len); + if (!buf) { + printf("error allocating memory for klog read\n"); + return -1; + } + size_t count = klog_read(buf, len, buf_id); + if (count > 0) { + printf("read %zu byte(s): \"", count); + for (size_t i = 0; i < count; i++) + putchar(buf[i]); + putchar('\"'); + putchar('\n'); + } else { + printf("read returned error: %zd\n", count); + } + free(buf); + } else if (!strcmp(argv[1].str, "getc")) { + if (argc < 3) goto notenoughargs; + int buf_id = argv[2].i; + printf("read: '%c'\n", klog_getc(buf_id)); + } else if (!strcmp(argv[1].str, "printftest")) { + klog_printf("a plain string\n"); + klog_printf("numbers: %d %d %d %u\n", 1, 2, 3, 99); + klog_printf("strings: '%s' '%s'\n", "a little string", "another one"); + } else if (!strcmp(argv[1].str, "dump")) { + int buffer = -1; + + if (argc >= 3) + buffer = argv[2].u; + + klog_dump(buffer); + } else if (!strcmp(argv[1].str, "vec")) { + int buffer = -1; + + if (argc >= 3) + buffer = argv[2].u; + + iovec_t vec[2]; + memset(vec, 0x99, sizeof(vec)); + int err = klog_get_buffer(buffer, vec); + printf("klog_get_buffer returns %d\n", err); + printf("vec %d: base %p, len %zu\n", 0, vec[0].iov_base, vec[0].iov_len); + printf("vec %d: base %p, len %zu\n", 1, vec[1].iov_base, vec[1].iov_len); + } else { + printf("ERROR unknown command\n"); + goto usage; + } + + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("klog", "commands for manipulating klog", &cmd_klog) +STATIC_COMMAND_END(klog); + +#endif // WITH_LIB_CONSOLE + diff --git a/kernel/lib/klog/rules.mk b/kernel/lib/klog/rules.mk new file mode 100644 index 000000000..6da48adf7 --- /dev/null +++ b/kernel/lib/klog/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/cksum + +MODULE_SRCS := \ + $(LOCAL_DIR)/klog.c \ + +include make/module.mk diff --git a/kernel/lib/libc/BUILD.gn b/kernel/lib/libc/BUILD.gn new file mode 100644 index 000000000..114680899 --- /dev/null +++ b/kernel/lib/libc/BUILD.gn @@ -0,0 +1,57 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("_libc_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("libc") { + public_configs = [ ":_libc_config" ] + public = [ + "include/printf.h", + "include/alloca.h", + "include/rand.h", + "include/endian.h", + "include/iovec.h", + "include/stdio.h", + "include/strings.h", + "include/ctype.h", + "include/stdlib.h", + "include/new.h", + "include/errno.h", + "include/stdint.h", + "include/assert.h", + "include/limits.h", + "include/malloc.h", + "include/string.h", + "include/inttypes.h", + ] + sources = [ + "atexit.c", + "atoi.c", + "bsearch.c", + "ctype.c", + "eabi.c", + "errno.c", + "printf.c", + "pure_virtual.cpp", + "qsort.c", + "rand.c", + "stdio.c", + "strtol.c", + "strtoll.c", + ] + deps = [ + "//kernel/lib/libc/string", + ] + public_deps = [ + "//kernel/lib/heap", + "//kernel/lib/io", + ] +} diff --git a/kernel/lib/libc/atexit.c b/kernel/lib/libc/atexit.c new file mode 100644 index 000000000..a5e4db6a6 --- /dev/null +++ b/kernel/lib/libc/atexit.c @@ -0,0 +1,14 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/* nulled out atexit. static object constructors call this */ +int atexit(void (*func)(void)) +{ + return 0; +} + diff --git a/kernel/lib/libc/atoi.c b/kernel/lib/libc/atoi.c new file mode 100644 index 000000000..193dc902e --- /dev/null +++ b/kernel/lib/libc/atoi.c @@ -0,0 +1,174 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include + +#define LONG_IS_INT 1 + +static int hexval(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return 0; +} + +int atoi(const char *num) +{ +#if !LONG_IS_INT + // XXX fail +#else + return atol(num); +#endif +} + +unsigned int atoui(const char *num) +{ +#if !LONG_IS_INT + // XXX fail +#else + return atoul(num); +#endif +} + +long atol(const char *num) +{ + long value = 0; + int neg = 0; + + if (num[0] == '0' && num[1] == 'x') { + // hex + num += 2; + while (*num && isxdigit(*num)) + value = value * 16 + hexval(*num++); + } else { + // decimal + if (num[0] == '-') { + neg = 1; + num++; + } + while (*num && isdigit(*num)) + value = value * 10 + *num++ - '0'; + } + + if (neg) + value = -value; + + return value; +} + +unsigned long atoul(const char *num) +{ + unsigned long value = 0; + if (num[0] == '0' && num[1] == 'x') { + // hex + num += 2; + while (*num && isxdigit(*num)) + value = value * 16 + hexval(*num++); + } else { + // decimal + while (*num && isdigit(*num)) + value = value * 10 + *num++ - '0'; + } + + return value; +} + +unsigned long long atoull(const char *num) +{ + unsigned long long value = 0; + if (num[0] == '0' && num[1] == 'x') { + // hex + num += 2; + while (*num && isxdigit(*num)) + value = value * 16 + hexval(*num++); + } else { + // decimal + while (*num && isdigit(*num)) + value = value * 10 + *num++ - '0'; + } + + return value; +} + +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + int neg = 0; + unsigned long ret = 0; + + if (base < 0 || base == 1 || base > 36) { + errno = EINVAL; + return 0; + } + + while (isspace(*nptr)) { + nptr++; + } + + if (*nptr == '+') { + nptr++; + } else if (*nptr == '-') { + neg = 1; + nptr++; + } + + if ((base == 0 || base == 16) && nptr[0] == '0' && nptr[1] == 'x') { + base = 16; + nptr += 2; + } else if (base == 0 && nptr[0] == '0') { + base = 8; + nptr++; + } else if (base == 0) { + base = 10; + } + + for (;;) { + char c = *nptr; + int v = -1; + unsigned long new_ret; + + if (c >= 'A' && c <= 'Z') { + v = c - 'A' + 10; + } else if (c >= 'a' && c <= 'z') { + v = c - 'a' + 10; + } else if (c >= '0' && c <= '9') { + v = c - '0'; + } + + if (v < 0 || v >= base) { + if (endptr) { + *endptr = (char *) nptr; + } + break; + } + + new_ret = ret * base; + if (new_ret / base != ret || + new_ret + v < new_ret || + ret == ULONG_MAX) { + ret = ULONG_MAX; + errno = ERANGE; + } else { + ret = new_ret + v; + } + + nptr++; + } + + if (neg && ret != ULONG_MAX) { + ret = -ret; + } + + return ret; +} diff --git a/kernel/lib/libc/bsearch.c b/kernel/lib/libc/bsearch.c new file mode 100644 index 000000000..66f7d4300 --- /dev/null +++ b/kernel/lib/libc/bsearch.c @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014, Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +void *bsearch(const void *key, const void *base, size_t num_elems, size_t size, + int (*compare)(const void *, const void *)) +{ + size_t low = 0, high = num_elems - 1; + + if (num_elems == 0) { + return NULL; + } + + for (;;) { + size_t mid = low + ((high - low) / 2); + const void *mid_elem = ((unsigned char *) base) + mid*size; + int r = compare(key, mid_elem); + + if (r < 0) { + if (mid == 0) { + return NULL; + } + high = mid - 1; + } else if (r > 0) { + low = mid + 1; + if (low < mid || low > high) { + return NULL; + } + } else { + return (void *) mid_elem; + } + } +} diff --git a/kernel/lib/libc/ctype.c b/kernel/lib/libc/ctype.c new file mode 100644 index 000000000..c464a51bd --- /dev/null +++ b/kernel/lib/libc/ctype.c @@ -0,0 +1,83 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +int isblank(int c) +{ + return (c == ' ' || c == '\t'); +} + +int isspace(int c) +{ + return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'); +} + +int islower(int c) +{ + return ((c >= 'a') && (c <= 'z')); +} + +int isupper(int c) +{ + return ((c >= 'A') && (c <= 'Z')); +} + +int isdigit(int c) +{ + return ((c >= '0') && (c <= '9')); +} + +int isalpha(int c) +{ + return isupper(c) || islower(c); +} + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +int isxdigit(int c) +{ + return isdigit(c) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')); +} + +int isgraph(int c) +{ + return ((c > ' ') && (c < 0x7f)); +} + +int iscntrl(int c) +{ + return ((c < ' ') || (c == 0x7f)); +} + +int isprint(int c) +{ + return ((c >= 0x20) && (c < 0x7f)); +} + +int ispunct(int c) +{ + return isgraph(c) && (!isalnum(c)); +} + +int tolower(int c) +{ + if ((c >= 'A') && (c <= 'Z')) + return c + ('a' - 'A'); + return c; +} + +int toupper(int c) +{ + if ((c >= 'a') && (c <= 'z')) + return c + ('A' - 'a'); + return c; +} + diff --git a/kernel/lib/libc/eabi.c b/kernel/lib/libc/eabi.c new file mode 100644 index 000000000..c3f912708 --- /dev/null +++ b/kernel/lib/libc/eabi.c @@ -0,0 +1,48 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/* some cruft we have to define when using the linux toolchain */ +#include + +void *__dso_handle; + +#if defined(__ARM_EABI_UNWINDER__) && __ARM_EABI_UNWINDER__ + +/* Our toolchain has eabi functionality built in, but they're not really used. + * so we stub them out here. */ +_Unwind_Reason_Code __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context) +{ + return _URC_FAILURE; +} + +_Unwind_Reason_Code __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context) +{ + return _URC_FAILURE; +} + +_Unwind_Reason_Code __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context) +{ + return _URC_FAILURE; +} + +#endif + +/* needed by some piece of EABI */ +void raise(void) +{ +} + +extern int __cxa_atexit(void (*func)(void *), void *arg, void *d); + +int __aeabi_atexit(void *arg, void (*func)(void *), void *d) +{ + return __cxa_atexit(func, arg, d); +} + + + diff --git a/kernel/lib/libc/errno.c b/kernel/lib/libc/errno.c new file mode 100644 index 000000000..298b92793 --- /dev/null +++ b/kernel/lib/libc/errno.c @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +/* completely un-threadsafe implementation of errno */ +/* TODO: pull from kernel TLS or some other thread local storage */ +static int _errno; + +int *__geterrno(void) +{ + return &_errno; +} + diff --git a/kernel/lib/libc/include/alloca.h b/kernel/lib/libc/include/alloca.h new file mode 100644 index 000000000..001c8da8d --- /dev/null +++ b/kernel/lib/libc/include/alloca.h @@ -0,0 +1,12 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if !defined(__ALLOCA_H) +#define __ALLOCA_H + +#define alloca(size) __builtin_alloca (size) + +#endif /* !__ALLOCA_H */ diff --git a/kernel/lib/libc/include/assert.h b/kernel/lib/libc/include/assert.h new file mode 100644 index 000000000..a6cb37861 --- /dev/null +++ b/kernel/lib/libc/include/assert.h @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ASSERT_H +#define __ASSERT_H + +#include +#include + +#define ASSERT(x) \ + do { if (unlikely(!(x))) { panic("ASSERT FAILED at (%s:%d): %s\n", __FILE__, __LINE__, #x); } } while (0) +#define ASSERT_MSG(x, msg, msgargs...) \ + do { if (unlikely(!(x))) { panic("ASSERT FAILED at (%s:%d): %s\n" msg "\n", __FILE__, __LINE__, #x, ## msgargs); } } while (0) + +#if LK_DEBUGLEVEL > 1 +#define DEBUG_ASSERT(x) \ + do { if (unlikely(!(x))) { panic("DEBUG ASSERT FAILED at (%s:%d): %s\n", __FILE__, __LINE__, #x); } } while (0) +#define DEBUG_ASSERT_MSG(x, msg, msgargs...) \ + do { if (unlikely(!(x))) { panic("DEBUG ASSERT FAILED at (%s:%d): %s\n" msg "\n", __FILE__, __LINE__, #x, ## msgargs); } } while (0) +#else +#define DEBUG_ASSERT(x) \ + do { } while(0) +#define DEBUG_ASSERT_MSG(x, msg, msgargs...) \ + do { } while(0) +#endif + +#define assert(e) DEBUG_ASSERT(e) + +#ifndef __cplusplus +#define static_assert(e) STATIC_ASSERT(e) +#endif + +#endif diff --git a/kernel/lib/libc/include/ctype.h b/kernel/lib/libc/include/ctype.h new file mode 100644 index 000000000..6cc62a8a6 --- /dev/null +++ b/kernel/lib/libc/include/ctype.h @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __CTYPE_H +#define __CTYPE_H + +#include + +__BEGIN_CDECLS; + +int isalnum(int c); +int isalpha(int c); +int isblank(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); + +int tolower(int c); +int toupper(int c); + +__END_CDECLS; + +#endif + diff --git a/kernel/lib/libc/include/endian.h b/kernel/lib/libc/include/endian.h new file mode 100644 index 000000000..c182a18a0 --- /dev/null +++ b/kernel/lib/libc/include/endian.h @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ENDIAN_H +#define __ENDIAN_H + +#include + +#ifndef __BYTE_ORDER__ +#error Compiler does not provide __BYTE_ORDER__ +#endif + +/* the compiler provides it, use what it says */ +#define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#define BYTE_ORDER __BYTE_ORDER__ + +// define a macro that unconditionally swaps +#define SWAP_32(x) \ + (((uint32_t)(x) << 24) | (((uint32_t)(x) & 0xff00) << 8) |(((uint32_t)(x) & 0x00ff0000) >> 8) | ((uint32_t)(x) >> 24)) +#define SWAP_16(x) \ + ((((uint16_t)(x) & 0xff) << 8) | ((uint16_t)(x) >> 8)) +#define SWAP_64(x) ((((uint64_t)(SWAP_32((uint64_t)(x)))) << 32) | (SWAP_32(((uint64_t)(x)) >> 32))) + +// standard swap macros +#if BYTE_ORDER == BIG_ENDIAN +#define LE64(val) SWAP_64(val) +#define LE32(val) SWAP_32(val) +#define LE16(val) SWAP_16(val) +#define BE64(val) (val) +#define BE32(val) (val) +#define BE16(val) (val) +#else +#define LE64(val) (val) +#define LE32(val) (val) +#define LE16(val) (val) +#define BE64(val) SWAP_64(val) +#define BE32(val) SWAP_32(val) +#define BE16(val) SWAP_16(val) +#endif + +#define LE32SWAP(var) (var) = LE32(var); +#define LE16SWAP(var) (var) = LE16(var); +#define BE32SWAP(var) (var) = BE32(var); +#define BE16SWAP(var) (var) = BE16(var); + +/* classic network byte swap stuff */ +#define ntohs(n) BE16(n) +#define htons(h) BE16(h) +#define ntohl(n) BE32(n) +#define htonl(h) BE32(h) + +/* 64-bit network byte swap stuff */ +#define htobe64(h) BE64(h) +#define be64toh(b) BE64(b) + +// some memory access macros +#if __POWERPC__ +#include + +#define READ_MEM_WORD(ptr) __lwbrx((word *)(ptr), 0) +#define READ_MEM_HALFWORD(ptr) __lhbrx((halfword *)(ptr), 0) +#define READ_MEM_BYTE(ptr) (*(byte *)(ptr)) +#define WRITE_MEM_WORD(ptr, data) __stwbrx(data, (word *)(ptr), 0) +#define WRITE_MEM_HALFWORD(ptr, data) __sthbrx(data, (halfword *)(ptr), 0) +#define WRITE_MEM_BYTE(ptr, data) (*(byte *)(ptr) = (data)) +#else +#define READ_MEM_WORD(ptr) SWAPIT_32(*(word *)(ptr)) +#define READ_MEM_HALFWORD(ptr) SWAPIT_16(*(halfword *)(ptr)) +#define READ_MEM_BYTE(ptr) (*(byte *)(ptr)) +#define WRITE_MEM_WORD(ptr, data) (*(word *)(ptr) = SWAPIT_32(data)) +#define WRITE_MEM_HALFWORD(ptr, data) (*(halfword *)(ptr) = SWAPIT_16(data)) +#define WRITE_MEM_BYTE(ptr, data) (*(byte *)(ptr) = (data)) +#endif + + +#endif diff --git a/kernel/lib/libc/include/errno.h b/kernel/lib/libc/include/errno.h new file mode 100644 index 000000000..886f0c499 --- /dev/null +++ b/kernel/lib/libc/include/errno.h @@ -0,0 +1,148 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __ERRNO_H +#define __ERRNO_H + +#include + +__BEGIN_CDECLS + +extern int *__geterrno(void); + +#define errno (*__geterrno()) + +#define EPERM 1 /* Not super-user */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math arg out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define ENOMSG 35 /* No message of desired type */ +#define EIDRM 36 /* Identifier removed */ +#define ECHRNG 37 /* Channel number out of range */ +#define EL2NSYNC 38 /* Level 2 not synchronized */ +#define EL3HLT 39 /* Level 3 halted */ +#define EL3RST 40 /* Level 3 reset */ +#define ELNRNG 41 /* Link number out of range */ +#define EUNATCH 42 /* Protocol driver not attached */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#define EDEADLK 45 /* Deadlock condition */ +#define ENOLCK 46 /* No record locks available */ +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#define EDEADLOCK 56 /* File locking deadlock error */ +#define EBFONT 57 /* Bad font file fmt */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#define ENOLINK 67 /* The link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#define EBADMSG 77 /* Trying to read unreadable message */ +#define EFTYPE 79 /* Inappropriate file type or format */ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#define ENOSYS 88 /* Function not implemented */ +#define ENMFILE 89 /* No more files */ +#define ENOTEMPTY 90 /* Directory not empty */ +#define ENAMETOOLONG 91 /* File or path name too long */ +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#define ETIMEDOUT 116 /* Connection timed out */ +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 +#define EPROCLIM 130 +#define EUSERS 131 +#define EDQUOT 132 +#define ESTALE 133 +#define ENOTSUP 134 /* Not supported */ +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#define EILSEQ 138 +#define EOVERFLOW 139 /* Value too large for defined data type */ + +#define EWOULDBLOCK EAGAIN /* Operation would block */ + +#define __ELASTERROR 2000 /* Users can add values starting here */ + +__END_CDECLS + +#endif diff --git a/kernel/lib/libc/include/inttypes.h b/kernel/lib/libc/include/inttypes.h new file mode 100644 index 000000000..94705563b --- /dev/null +++ b/kernel/lib/libc/include/inttypes.h @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __INTTYPES_H +#define __INTTYPES_H + +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIu64 "llu" +#define PRIx64 "llx" + +#include + +#endif + diff --git a/kernel/lib/libc/include/iovec.h b/kernel/lib/libc/include/iovec.h new file mode 100644 index 000000000..74643f8d2 --- /dev/null +++ b/kernel/lib/libc/include/iovec.h @@ -0,0 +1,30 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __IOVEC_H +#define __IOVEC_H + +#include +#include +#include + +__BEGIN_CDECLS; + +typedef struct iovec { + void *iov_base; + size_t iov_len; +} iovec_t; + +ssize_t iovec_size(const iovec_t *iov, uint iov_cnt); + +ssize_t iovec_to_membuf(uint8_t *buf, uint buf_len, + const iovec_t *iov, uint iov_cnt, uint iov_pos); + +__END_CDECLS; + +#endif + diff --git a/kernel/lib/libc/include/limits.h b/kernel/lib/libc/include/limits.h new file mode 100644 index 000000000..192e84b58 --- /dev/null +++ b/kernel/lib/libc/include/limits.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +// use the GCC builtins until we need something ourselves +#if !defined(_GCC_LIMITS_H_) +#include_next +#endif + +#ifndef LLONG_MAX +#define LLONG_MAX ((1LL << (CHAR_BIT * sizeof(long long) - 1)) - 1) +#endif +#ifndef ULLONG_MAX +#define ULLONG_MAX (~0ULL) +#endif +#ifndef LLONG_MIN +#define LLONG_MIN (LLONG_MAX + 1) +#endif diff --git a/kernel/lib/libc/include/malloc.h b/kernel/lib/libc/include/malloc.h new file mode 100644 index 000000000..8ae8181db --- /dev/null +++ b/kernel/lib/libc/include/malloc.h @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __MALLOC_H +#define __MALLOC_H + +#include +#include +#include + +/* lib/heap provides malloc/free definitions */ +#include + +#endif + diff --git a/kernel/lib/libc/include/new.h b/kernel/lib/libc/include/new.h new file mode 100644 index 000000000..d33689e73 --- /dev/null +++ b/kernel/lib/libc/include/new.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __NEW_H +#define __NEW_H + +#include + +void *operator new(size_t); +void *operator new(size_t, void *ptr); +void *operator new[](size_t); +void *operator new[](size_t, void *ptr); +void operator delete(void *p); +void operator delete[](void *p); + +#endif diff --git a/kernel/lib/libc/include/printf.h b/kernel/lib/libc/include/printf.h new file mode 100644 index 000000000..96ee977e4 --- /dev/null +++ b/kernel/lib/libc/include/printf.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_PRINTF_H +#define __LIB_PRINTF_H + +#include +#include +#include + +__BEGIN_CDECLS + +/* printf engine that parses the format string and generates output */ + +/* function pointer to pass the printf engine, called back during the formatting. + * input is a string to output, length bytes to output, + * return code is number of characters that would have been written, or error code (if negative) + */ +typedef int (*_printf_engine_output_func)(const char *str, size_t len, void *state); + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap); + +__END_CDECLS + +#endif diff --git a/kernel/lib/libc/include/rand.h b/kernel/lib/libc/include/rand.h new file mode 100644 index 000000000..05d6298cc --- /dev/null +++ b/kernel/lib/libc/include/rand.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __RAND_H +#define __RAND_H + +#include +#include + +__BEGIN_CDECLS; + +int rand(void); +void srand(unsigned int seed); + +/* non standard extension to add some entropy to the seed */ +void rand_add_entropy(const void *buf, size_t len); + +__END_CDECLS; + +#endif + diff --git a/kernel/lib/libc/include/stdint.h b/kernel/lib/libc/include/stdint.h new file mode 100644 index 000000000..185a7e532 --- /dev/null +++ b/kernel/lib/libc/include/stdint.h @@ -0,0 +1,128 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __STDINT_H +#define __STDINT_H + +#include // for ULONG_MAX + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +#define INT8_MIN CHAR_MIN +#define INT16_MIN SHORT_MIN +#define INT32_MIN INT_MIN + +#if defined(LLONG_MIN) +#define INT64_MIN LLONG_MIN +#elif defined(__LONG_LONG_MAX__) +#define INT64_MIN (-__LONG_LONG_MAX__-1LL) +#endif + +#define INT8_MAX CHAR_MAX +#define INT16_MAX SHORT_MAX +#define INT32_MAX INT_MAX + +#if defined(LLONG_MAX) +#define INT64_MAX LLONG_MAX +#elif defined(__LONG_LONG_MAX__) +#define INT64_MAX __LONG_LONG_MAX__ +#endif + +#define UINT8_MAX UCHAR_MAX +#define UINT16_MAX USHORT_MAX +#define UINT32_MAX UINT_MAX + +#if defined(ULLONG_MAX) +#define UINT64_MAX ULLONG_MAX +#elif defined(__LONG_LONG_MAX__) +#define UINT64_MAX (__LONG_LONG_MAX__*2ULL + 1ULL) +#endif + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +typedef long intptr_t; +typedef unsigned long uintptr_t; + +#define INTPTR_MIN LONG_MIN +#define INTPTR_MAX LONG_MAX +#define UINTPTR_MAX ULONG_MAX + +typedef long long intmax_t; +typedef unsigned long long uintmax_t; + +#define INTMAX_MAX LLONG_MAX +#define INTMAX_MIN LLONG_MIN +#define UINTMAX_MAX ULLONG_MAX + +#define SIZE_MAX ULONG_MAX + +#define INT8_C(c) (c) +#define INT16_C(c) (c) +#define INT32_C(c) (c) +#define INT64_C(c) (c ## LL) + +#define UINT8_C(c) (c) +#define UINT16_C(c) (c) +#define UINT32_C(c) (c ## U) +#define UINT64_C(c) (c ## ULL) + +#define INTMAX_C(c) INT64_C(c) +#define UINTMAX_C(c) UINT64_C(c) + +#endif + diff --git a/kernel/lib/libc/include/stdio.h b/kernel/lib/libc/include/stdio.h new file mode 100644 index 000000000..61ea2a5e4 --- /dev/null +++ b/kernel/lib/libc/include/stdio.h @@ -0,0 +1,75 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __STDIO_H +#define __STDIO_H + +#include +#include +#include +#include + +__BEGIN_CDECLS + +typedef struct FILE { + io_handle_t *io; +} FILE; + +extern FILE __stdio_FILEs[]; + +#define stdin (&__stdio_FILEs[0]) +#define stdout (&__stdio_FILEs[1]) +#define stderr (&__stdio_FILEs[2]) + +FILE *fopen(const char *filename, const char *mode); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t count, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream); +int fflush(FILE *stream); +int feof(FILE *stream); + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +int fseek(FILE *stream, long offset, int whence); +long ftell(FILE *stream); + +int fputc(int c, FILE *fp); +#define putc(c, fp) fputc(c, fp) +int putchar(int c); + +int fputs(const char *s, FILE *fp); +int puts(const char *str); + +int getc(FILE *fp); +int getchar(void); + +#if !DISABLE_DEBUG_OUTPUT +#define printf(x...) _printf(x) +#define vprintf(x...) _vprintf(x) +#else +static inline int __PRINTFLIKE(1, 2) printf(const char *fmt, ...) { return 0; } +static inline int vprintf(const char *fmt, va_list ap) { return 0; } +#endif + +int _printf(const char *fmt, ...) __PRINTFLIKE(1, 2); +int _vprintf(const char *fmt, va_list ap); + +int fprintf(FILE *fp, const char *fmt, ...) __PRINTFLIKE(2, 3); +int vfprintf(FILE *fp, const char *fmt, va_list ap); + +int sprintf(char *str, const char *fmt, ...) __PRINTFLIKE(2, 3); +int snprintf(char *str, size_t len, const char *fmt, ...) __PRINTFLIKE(3, 4); +int vsprintf(char *str, const char *fmt, va_list ap); +int vsnprintf(char *str, size_t len, const char *fmt, va_list ap); + + +__END_CDECLS + +#endif + diff --git a/kernel/lib/libc/include/stdlib.h b/kernel/lib/libc/include/stdlib.h new file mode 100644 index 000000000..740d43e3f --- /dev/null +++ b/kernel/lib/libc/include/stdlib.h @@ -0,0 +1,52 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __STDLIB_H +#define __STDLIB_H + +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_CDECLS; + +int atoi(const char *num); +unsigned int atoui(const char *num); +long atol(const char *num); +unsigned long atoul(const char *num); +unsigned long long atoull(const char *num); + +long strtol(const char *nptr, char **endptr, int base); +long long strtoll(const char *nptr, char **endptr, int base); + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) +#define ROUNDDOWN(a, b) ((a) & ~((b)-1)) + +#define ALIGN(a, b) ROUNDUP(a, b) +#define IS_ALIGNED(a, b) (!(((uintptr_t)(a)) & (((uintptr_t)(b))-1))) + +/* allocate a buffer on the stack aligned and padded to the cpu's cache line size */ +#define STACKBUF_DMA_ALIGN(var, size) \ + uint8_t var[ROUNDUP(size, CACHE_LINE)] __ALIGNED(CACHE_LINE); +void abort(void) __attribute__((noreturn)); +void qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)); +void *bsearch(const void *key, const void *base, size_t num_elems, size_t size, + int (*compare)(const void *, const void *)); +unsigned long int strtoul(const char *nptr, char **endptr, int base); +char *getenv(const char *name); + +__END_CDECLS; + +#endif + diff --git a/kernel/lib/libc/include/string.h b/kernel/lib/libc/include/string.h new file mode 100644 index 000000000..160f72411 --- /dev/null +++ b/kernel/lib/libc/include/string.h @@ -0,0 +1,52 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_STRING_H +#define __LIB_STRING_H + +#include +#include + +__BEGIN_CDECLS + +void *memchr (void const *, int, size_t) __PURE; +int memcmp (void const *, const void *, size_t) __PURE; +void *memcpy (void *, void const *, size_t); +void *memmove(void *, void const *, size_t); +void *memset (void *, int, size_t); + +char *strcat(char *, char const *); +char *strchr(char const *, int) __PURE; +int strcmp(char const *, char const *) __PURE; +char *strcpy(char *, char const *); +char const *strerror(int) __CONST; +size_t strlen(char const *) __PURE; +char *strncat(char *, char const *, size_t); +int strncmp(char const *, char const *, size_t) __PURE; +char *strncpy(char *, char const *, size_t); +char *strpbrk(char const *, char const *) __PURE; +char *strrchr(char const *, int) __PURE; +size_t strspn(char const *, char const *) __PURE; +size_t strcspn(const char *s, const char *) __PURE; +char *strstr(char const *, char const *) __PURE; +char *strtok(char *, char const *); +int strcoll(const char *s1, const char *s2) __PURE; +size_t strxfrm(char *dest, const char *src, size_t n) __PURE; +char *strdup(const char *str) __MALLOC; + +/* non standard */ +void bcopy(void const *, void *, size_t); +void bzero(void *, size_t); +size_t strlcat(char *, char const *, size_t); +size_t strlcpy(char *, char const *, size_t); +int strncasecmp(char const *, char const *, size_t) __PURE; +int strnicmp(char const *, char const *, size_t) __PURE; +size_t strnlen(char const *s, size_t count) __PURE; + +__END_CDECLS + +#endif diff --git a/kernel/lib/libc/include/strings.h b/kernel/lib/libc/include/strings.h new file mode 100644 index 000000000..6ba035047 --- /dev/null +++ b/kernel/lib/libc/include/strings.h @@ -0,0 +1,18 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#if !defined(__STRINGS_H) +#define __STRINGS_H + +#include + +__BEGIN_CDECLS; + +int strcasecmp(const char *s1, const char *s2); + +__END_CDECLS; + +#endif /* !__STRINGS_H */ diff --git a/kernel/lib/libc/printf.c b/kernel/lib/libc/printf.c new file mode 100644 index 000000000..147b0c0b2 --- /dev/null +++ b/kernel/lib/libc/printf.c @@ -0,0 +1,622 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_NO_FP +#define FLOAT_PRINTF 0 +#else +#define FLOAT_PRINTF 1 +#endif + +int sprintf(char *str, const char *fmt, ...) +{ + int err; + + va_list ap; + va_start(ap, fmt); + err = vsprintf(str, fmt, ap); + va_end(ap); + + return err; +} + +int snprintf(char *str, size_t len, const char *fmt, ...) +{ + int err; + + va_list ap; + va_start(ap, fmt); + err = vsnprintf(str, len, fmt, ap); + va_end(ap); + + return err; +} + +int vsprintf(char *str, const char *fmt, va_list ap) +{ + return vsnprintf(str, INT_MAX, fmt, ap); +} + +struct _output_args { + char *outstr; + size_t len; + size_t pos; +}; + +static int _vsnprintf_output(const char *str, size_t len, void *state) +{ + struct _output_args *args = state; + + size_t count = 0; + while (count < len) { + if (args->pos < args->len) { + args->outstr[args->pos++] = *str; + } + + str++; + count++; + } + + return count; +} + +int vsnprintf(char *str, size_t len, const char *fmt, va_list ap) +{ + struct _output_args args; + int wlen; + + args.outstr = str; + args.len = len; + args.pos = 0; + + wlen = _printf_engine(&_vsnprintf_output, (void *)&args, fmt, ap); + if (args.pos >= len) + str[len-1] = '\0'; + else + str[wlen] = '\0'; + return wlen; +} + +#define LONGFLAG 0x00000001 +#define LONGLONGFLAG 0x00000002 +#define HALFFLAG 0x00000004 +#define HALFHALFFLAG 0x00000008 +#define SIZETFLAG 0x00000010 +#define INTMAXFLAG 0x00000020 +#define PTRDIFFFLAG 0x00000040 +#define ALTFLAG 0x00000080 +#define CAPSFLAG 0x00000100 +#define SHOWSIGNFLAG 0x00000200 +#define SIGNEDFLAG 0x00000400 +#define LEFTFORMATFLAG 0x00000800 +#define LEADZEROFLAG 0x00001000 +#define BLANKPOSFLAG 0x00002000 + +__NO_INLINE static char *longlong_to_string(char *buf, unsigned long long n, size_t len, uint flag, char *signchar) +{ + size_t pos = len; + int negative = 0; + + if ((flag & SIGNEDFLAG) && (long long)n < 0) { + negative = 1; + n = -n; + } + + buf[--pos] = 0; + + /* only do the math if the number is >= 10 */ + while (n >= 10) { + int digit = n % 10; + + n /= 10; + + buf[--pos] = digit + '0'; + } + buf[--pos] = n + '0'; + + if (negative) + *signchar = '-'; + else if ((flag & SHOWSIGNFLAG)) + *signchar = '+'; + else if ((flag & BLANKPOSFLAG)) + *signchar = ' '; + else + *signchar = '\0'; + + return &buf[pos]; +} + +static const char hextable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +static const char hextable_caps[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +__NO_INLINE static char *longlong_to_hexstring(char *buf, unsigned long long u, size_t len, uint flag) +{ + size_t pos = len; + const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable; + + buf[--pos] = 0; + do { + unsigned int digit = u % 16; + u /= 16; + + buf[--pos] = table[digit]; + } while (u != 0); + + return &buf[pos]; +} + +#if FLOAT_PRINTF +union double_int { + double d; + uint64_t i; +}; + +#define OUT(c) buf[pos++] = (c) +#define OUTSTR(str) do { for (size_t i = 0; (str)[i] != 0; i++) OUT((str)[i]); } while (0) + +/* print up to a 4 digit exponent as string, with sign */ +__NO_INLINE static size_t exponent_to_string(char *buf, int32_t exponent) +{ + size_t pos = 0; + + /* handle sign */ + if (exponent < 0) { + OUT('-'); + exponent = -exponent; + } else { + OUT('+'); + } + + /* see how far we need to bump into the string to print from the right */ + if (exponent >= 1000) pos += 4; + else if (exponent >= 100) pos += 3; + else if (exponent >= 10) pos += 2; + else pos++; + + /* print decimal string, from the right */ + uint i = pos; + do { + uint digit = (uint32_t)exponent % 10; + + buf[--i] = digit + '0'; + + exponent /= 10; + } while (exponent != 0); + + /* return number of characters printed */ + return pos; +} + +__NO_INLINE static char *double_to_string(char *buf, size_t len, double d, uint flag) +{ + size_t pos = 0; + union double_int u = { d }; + + uint32_t exponent = (u.i >> 52) & 0x7ff; + uint64_t fraction = (u.i & ((1ULL << 52) - 1)); + bool neg = !!(u.i & (1ULL << 63)); + + /* start constructing the string */ + if (neg) { + OUT('-'); + d = -d; + } + + /* longest: + * 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000o + */ + + /* look for special cases */ + if (exponent == 0x7ff) { + if (fraction == 0) { + /* infinity */ + if (flag & CAPSFLAG) OUTSTR("INF"); + else OUTSTR("inf"); + } else { + /* NaN */ + if (flag & CAPSFLAG) OUTSTR("NAN"); + else OUTSTR("nan"); + } + } else if (exponent == 0) { + if (fraction == 0) { + /* zero */ + OUTSTR("0.000000"); + } else { + /* denormalized */ + /* XXX does not handle */ + if (flag & CAPSFLAG) OUTSTR("DEN"); + else OUTSTR("den"); + } + } else { + /* see if it's in the range of floats we can easily print */ + int exponent_signed = exponent - 1023; + if (exponent_signed < -52 || exponent_signed > 52) { + OUTSTR(""); + } else { + /* start by walking backwards through the string */ +#define OUTREV(c) do { if (&buf[pos] == buf) goto done; else buf[--pos] = (c); } while (0) + pos = len; + OUTREV(0); + + /* reserve space for the fractional component first */ + for (int i = 0; i <= 6; i++) + OUTREV('0'); + size_t decimal_spot = pos; + + /* print the integer portion */ + uint64_t u; + if (exponent_signed >= 0) { + u = fraction; + u |= (1ULL<<52); + u >>= (52 - exponent_signed); + + char *s = longlong_to_string(buf, u, pos + 1, flag, &(char) {0}); + + pos = s - buf; + } else { + /* exponent is negative */ + u = 0; + OUTREV('0'); + } + + buf[decimal_spot] = '.'; + + /* handle the fractional part */ + uint32_t frac = ((d - u) * 1000000) + .5; + + uint i = decimal_spot + 6 + 1; + while (frac != 0) { + uint digit = frac % 10; + + buf[--i] = digit + '0'; + + frac /= 10; + } + + if (neg) + OUTREV('-'); + +done: + /* separate return path, since we've been walking backwards through the string */ + return &buf[pos]; + } +#undef OUTREV + } + + buf[pos] = 0; + return buf; +} + +__NO_INLINE static char *double_to_hexstring(char *buf, size_t len, double d, uint flag) +{ + size_t pos = 0; + union double_int u = { d }; + + uint32_t exponent = (u.i >> 52) & 0x7ff; + uint64_t fraction = (u.i & ((1ULL << 52) - 1)); + bool neg = !!(u.i & (1ULL << 63)); + + /* start constructing the string */ + if (neg) { + OUT('-'); + } + + /* look for special cases */ + if (exponent == 0x7ff) { + if (fraction == 0) { + /* infinity */ + if (flag & CAPSFLAG) OUTSTR("INF"); + else OUTSTR("inf"); + } else { + /* NaN */ + if (flag & CAPSFLAG) OUTSTR("NAN"); + else OUTSTR("nan"); + } + } else if (exponent == 0) { + if (fraction == 0) { + /* zero */ + if (flag & CAPSFLAG) OUTSTR("0X0P+0"); + else OUTSTR("0x0p+0"); + } else { + /* denormalized */ + /* XXX does not handle */ + if (flag & CAPSFLAG) OUTSTR("DEN"); + else OUTSTR("den"); + } + } else { + /* regular normalized numbers: + * 0x1p+1 + * 0x1.0000000000001p+1 + * 0X1.FFFFFFFFFFFFFP+1023 + * 0x1.FFFFFFFFFFFFFP+1023 + */ + int exponent_signed = exponent - 1023; + + /* implicit 1. */ + if (flag & CAPSFLAG) OUTSTR("0X1"); + else OUTSTR("0x1"); + + /* select the appropriate hex case table */ + const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable; + + int zero_count = 0; + bool output_dot = false; + for (int i = 52 - 4; i >= 0; i -= 4) { + uint digit = (fraction >> i) & 0xf; + + if (digit == 0) { + zero_count++; + } else { + /* output a . the first time we output a char */ + if (!output_dot) { + OUT('.'); + output_dot = true; + } + /* if we have a non zero digit, see if we need to output a string of zeros */ + while (zero_count > 0) { + OUT('0'); + zero_count--; + } + buf[pos++] = table[digit]; + } + } + + /* handle the exponent */ + buf[pos++] = (flag & CAPSFLAG) ? 'P' : 'p'; + pos += exponent_to_string(&buf[pos], exponent_signed); + } + + buf[pos] = 0; + return buf; +} + +#undef OUT +#undef OUTSTR + +#endif // FLOAT_PRINTF + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap) +{ + int err = 0; + char c; + unsigned char uc; + const char *s; + size_t string_len; + unsigned long long n; + void *ptr; + int flags; + unsigned int format_num; + char signchar; + size_t chars_written = 0; + char num_buffer[32]; + +#define OUTPUT_STRING(str, len) do { err = out(str, len, state); if (err < 0) { goto exit; } else { chars_written += err; } } while(0) +#define OUTPUT_CHAR(c) do { char __temp[1] = { c }; OUTPUT_STRING(__temp, 1); } while (0) + + for (;;) { + /* reset the format state */ + flags = 0; + format_num = 0; + signchar = '\0'; + + /* handle regular chars that aren't format related */ + s = fmt; + string_len = 0; + while ((c = *fmt++) != 0) { + if (c == '%') + break; /* we saw a '%', break and start parsing format */ + string_len++; + } + + /* output the string we've accumulated */ + OUTPUT_STRING(s, string_len); + + /* make sure we haven't just hit the end of the string */ + if (c == 0) + break; + +next_format: + /* grab the next format character */ + c = *fmt++; + if (c == 0) + break; + + switch (c) { + case '0'...'9': + if (c == '0' && format_num == 0) + flags |= LEADZEROFLAG; + format_num *= 10; + format_num += c - '0'; + goto next_format; + case '.': + /* XXX for now eat numeric formatting */ + goto next_format; + case '%': + OUTPUT_CHAR('%'); + break; + case 'c': + uc = va_arg(ap, unsigned int); + OUTPUT_CHAR(uc); + break; + case 's': + s = va_arg(ap, const char *); + if (s == 0) + s = ""; + flags &= ~LEADZEROFLAG; /* doesn't make sense for strings */ + goto _output_string; + case '-': + flags |= LEFTFORMATFLAG; + goto next_format; + case '+': + flags |= SHOWSIGNFLAG; + goto next_format; + case ' ': + flags |= BLANKPOSFLAG; + goto next_format; + case '#': + flags |= ALTFLAG; + goto next_format; + case 'l': + if (flags & LONGFLAG) + flags |= LONGLONGFLAG; + flags |= LONGFLAG; + goto next_format; + case 'h': + if (flags & HALFFLAG) + flags |= HALFHALFFLAG; + flags |= HALFFLAG; + goto next_format; + case 'z': + flags |= SIZETFLAG; + goto next_format; + case 'j': + flags |= INTMAXFLAG; + goto next_format; + case 't': + flags |= PTRDIFFFLAG; + goto next_format; + case 'i': + case 'd': + n = (flags & LONGLONGFLAG) ? va_arg(ap, long long) : + (flags & LONGFLAG) ? va_arg(ap, long) : + (flags & HALFHALFFLAG) ? (signed char)va_arg(ap, int) : + (flags & HALFFLAG) ? (short)va_arg(ap, int) : + (flags & SIZETFLAG) ? va_arg(ap, ssize_t) : + (flags & INTMAXFLAG) ? va_arg(ap, intmax_t) : + (flags & PTRDIFFFLAG) ? va_arg(ap, ptrdiff_t) : + va_arg(ap, int); + flags |= SIGNEDFLAG; + s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar); + goto _output_string; + case 'u': + n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) : + (flags & LONGFLAG) ? va_arg(ap, unsigned long) : + (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) : + (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) : + (flags & SIZETFLAG) ? va_arg(ap, size_t) : + (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) : + (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) : + va_arg(ap, unsigned int); + s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar); + goto _output_string; + case 'p': + flags |= LONGFLAG | ALTFLAG; + goto hex; + case 'X': + flags |= CAPSFLAG; + /* fallthrough */ +hex: + case 'x': + n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) : + (flags & LONGFLAG) ? va_arg(ap, unsigned long) : + (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) : + (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) : + (flags & SIZETFLAG) ? va_arg(ap, size_t) : + (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) : + (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) : + va_arg(ap, unsigned int); + s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags); + if (flags & ALTFLAG) { + OUTPUT_CHAR('0'); + OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x'); + } + goto _output_string; + case 'n': + ptr = va_arg(ap, void *); + if (flags & LONGLONGFLAG) + *(long long *)ptr = chars_written; + else if (flags & LONGFLAG) + *(long *)ptr = chars_written; + else if (flags & HALFHALFFLAG) + *(signed char *)ptr = chars_written; + else if (flags & HALFFLAG) + *(short *)ptr = chars_written; + else if (flags & SIZETFLAG) + *(size_t *)ptr = chars_written; + else + *(int *)ptr = chars_written; + break; +#if FLOAT_PRINTF + case 'F': + flags |= CAPSFLAG; + /* fallthrough */ + case 'f': { + double d = va_arg(ap, double); + s = double_to_string(num_buffer, sizeof(num_buffer), d, flags); + goto _output_string; + } + case 'A': + flags |= CAPSFLAG; + /* fallthrough */ + case 'a': { + double d = va_arg(ap, double); + s = double_to_hexstring(num_buffer, sizeof(num_buffer), d, flags); + goto _output_string; + } +#endif + default: + OUTPUT_CHAR('%'); + OUTPUT_CHAR(c); + break; + } + + /* move on to the next field */ + continue; + + /* shared output code */ +_output_string: + string_len = strlen(s); + + if (flags & LEFTFORMATFLAG) { + /* left justify the text */ + OUTPUT_STRING(s, string_len); + uint written = err; + + /* pad to the right (if necessary) */ + for (; format_num > written; format_num--) + OUTPUT_CHAR(' '); + } else { + /* right justify the text (digits) */ + + /* if we're going to print a sign digit, + it'll chew up one byte of the format size */ + if (signchar != '\0' && format_num > 0) + format_num--; + + /* output the sign char before the leading zeros */ + if (flags & LEADZEROFLAG && signchar != '\0') + OUTPUT_CHAR(signchar); + + /* pad according to the format string */ + for (; format_num > string_len; format_num--) + OUTPUT_CHAR(flags & LEADZEROFLAG ? '0' : ' '); + + /* if not leading zeros, output the sign char just before the number */ + if (!(flags & LEADZEROFLAG) && signchar != '\0') + OUTPUT_CHAR(signchar); + + /* output the string */ + OUTPUT_STRING(s, string_len); + } + continue; + } + +#undef OUTPUT_STRING +#undef OUTPUT_CHAR + +exit: + return (err < 0) ? err : (int)chars_written; +} diff --git a/kernel/lib/libc/pure_virtual.cpp b/kernel/lib/libc/pure_virtual.cpp new file mode 100644 index 000000000..491429a4d --- /dev/null +++ b/kernel/lib/libc/pure_virtual.cpp @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2006 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +extern "C" void __cxa_pure_virtual(void) +{ + panic("pure virtual called\n"); +} + +extern "C" int __cxa_atexit(void (*destructor)(void *), void *arg, void *__dso_handle) +{ + return 0; +} + diff --git a/kernel/lib/libc/qsort.c b/kernel/lib/libc/qsort.c new file mode 100644 index 000000000..c3650415d --- /dev/null +++ b/kernel/lib/libc/qsort.c @@ -0,0 +1,162 @@ +/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +static __inline char *med3(char *, char *, char *, int ( *)(const void *, const void *)); +static __inline void swapfunc(char *, char *, int, int); + +#define min(a, b) (a) < (b) ? a : b + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static __inline void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) + } + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static __inline char * +med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void +qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + char *a = aa; + +loop: + SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } + /* qsort(pn - r, r / es, es, cmp); */ +} diff --git a/kernel/lib/libc/rand.c b/kernel/lib/libc/rand.c new file mode 100644 index 000000000..3b08f2a80 --- /dev/null +++ b/kernel/lib/libc/rand.c @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +static unsigned int randseed = 12345; + +void srand(unsigned int seed) +{ + randseed = seed; +} + +void rand_add_entropy(const void *buf, size_t len) +{ + if (len == 0) + return; + + uint32_t enp = 0; + for (size_t i = 0; i < len; i++) { + enp ^= ((enp << 8) | (enp >> 24)) ^ ((const uint8_t *)buf)[i]; + } + + randseed ^= enp; +} + +int rand(void) +{ + return (randseed = randseed * 1664525 + 1013904223); +} diff --git a/kernel/lib/libc/rules.mk b/kernel/lib/libc/rules.mk new file mode 100644 index 000000000..0413a1bf5 --- /dev/null +++ b/kernel/lib/libc/rules.mk @@ -0,0 +1,33 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/heap \ + lib/io + +MODULE_SRCS += \ + $(LOCAL_DIR)/atoi.c \ + $(LOCAL_DIR)/bsearch.c \ + $(LOCAL_DIR)/ctype.c \ + $(LOCAL_DIR)/errno.c \ + $(LOCAL_DIR)/printf.c \ + $(LOCAL_DIR)/rand.c \ + $(LOCAL_DIR)/strtol.c \ + $(LOCAL_DIR)/strtoll.c \ + $(LOCAL_DIR)/stdio.c \ + $(LOCAL_DIR)/qsort.c \ + $(LOCAL_DIR)/eabi.c \ + $(LOCAL_DIR)/atexit.c \ + $(LOCAL_DIR)/pure_virtual.cpp + +include $(LOCAL_DIR)/string/rules.mk + +include make/module.mk diff --git a/kernel/lib/libc/stdio.c b/kernel/lib/libc/stdio.c new file mode 100644 index 000000000..eda30f395 --- /dev/null +++ b/kernel/lib/libc/stdio.c @@ -0,0 +1,120 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +#define DEFINE_STDIO_DESC(id) \ + [(id)] = { \ + .io = &console_io, \ + } + +FILE __stdio_FILEs[3] = { + DEFINE_STDIO_DESC(0), /* stdin */ + DEFINE_STDIO_DESC(1), /* stdout */ + DEFINE_STDIO_DESC(2), /* stderr */ +}; +#undef DEFINE_STDIO_DESC + +int fputc(int _c, FILE *fp) +{ + unsigned char c = _c; + return io_write(fp->io, (char *)&c, 1); +} + +int putchar(int c) +{ + return fputc(c, stdout); +} + +int puts(const char *str) +{ + int err = fputs(str, stdout); + if (err >= 0) + err = fputc('\n', stdout); + return err; +} + +int fputs(const char *s, FILE *fp) +{ + size_t len = strlen(s); + + return io_write(fp->io, s, len); +} + +size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp) +{ + size_t bytes_written; + + if (size == 0 || count == 0) + return 0; + + // fast path for size == 1 + if (likely(size == 1)) { + return io_write(fp->io, ptr, count); + } + + bytes_written = io_write(fp->io, ptr, size * count); + return bytes_written / size; +} + +int getc(FILE *fp) +{ + char c; + ssize_t ret = io_read(fp->io, &c, sizeof(c)); + + return (ret > 0) ? c : ret; +} + +int getchar(void) +{ + return getc(stdin); +} + +static int _fprintf_output_func(const char *str, size_t len, void *state) +{ + FILE *fp = (FILE *)state; + + return io_write(fp->io, str, len); +} + +int vfprintf(FILE *fp, const char *fmt, va_list ap) +{ + return _printf_engine(&_fprintf_output_func, (void *)fp, fmt, ap); +} + +int fprintf(FILE *fp, const char *fmt, ...) +{ + va_list ap; + int err; + + va_start(ap, fmt); + err = vfprintf(fp, fmt, ap); + va_end(ap); + return err; +} + +int _printf(const char *fmt, ...) +{ + va_list ap; + int err; + + va_start(ap, fmt); + err = vfprintf(stdout, fmt, ap); + va_end(ap); + + return err; +} + +int _vprintf(const char *fmt, va_list ap) +{ + return vfprintf(stdout, fmt, ap); +} diff --git a/kernel/lib/libc/string/BUILD.gn b/kernel/lib/libc/string/BUILD.gn new file mode 100644 index 000000000..0115504d3 --- /dev/null +++ b/kernel/lib/libc/string/BUILD.gn @@ -0,0 +1,55 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("string") { + sources = [ + "bcopy.c", + "bzero.c", + "memchr.c", + "memcmp.c", + "memcpy.c", + "memmove.c", + "memset.c", + "strcat.c", + "strchr.c", + "strcmp.c", + "strcoll.c", + "strcpy.c", + "strdup.c", + "strerror.c", + "strlcat.c", + "strlcpy.c", + "strlen.c", + "strncat.c", + "strncmp.c", + "strncpy.c", + "strnicmp.c", + "strnlen.c", + "strpbrk.c", + "strrchr.c", + "strspn.c", + "strstr.c", + "strtok.c", + "strxfrm.c", + ] + include_dirs = [ + "//kernel/lib/libc/include", + "//kernel/lib/heap/include", + ] + if (target_cpu == "arm") { + sources -= [ + "bcopy.c", + "bzero.c", + "memcpy.c", + "memmove.c", + "memset.c", + ] + sources += [ + "arch/arm/arm/memcpy.S", + "arch/arm/arm/memset.S", + ] + } +} diff --git a/kernel/lib/libc/string/arch/arm/arm-m/memcpy.S b/kernel/lib/libc/string/arch/arm/arm-m/memcpy.S new file mode 100644 index 000000000..204305a01 --- /dev/null +++ b/kernel/lib/libc/string/arch/arm/arm-m/memcpy.S @@ -0,0 +1,120 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +.text +.syntax unified +.thumb +.align 2 + +/* void bcopy(const void *src, void *dest, size_t n); */ +FUNCTION(bcopy) + // swap args for bcopy + mov r12, r0 + mov r0, r1 + mov r1, r12 + +/* void *memcpy(void *dest, const void *src, size_t count) */ +FUNCTION(memcpy) + push { r0, r14 } + + // test for zero length or pointers being equivalent + cbz r2, .L_done + cmp r0, r1 + beq .L_done + + // check for a short copy len + cmp r2, #16 + blt .L_bytewise + + // check to see if the pointers are similarly dword aligned + eors r3, r0, r1 + ands r3, #7 + beq .L_prepare_dword + + // see how many bytes we need to move to align dest to word boundary + and r3, r0, #3 + cbz r3, .L_prepare_wordwise + rsb r3, #4 + subs r2, r3 + + .align 2 +.L_bytewise_align: + // bytewise to align memcpy + ldrb r12, [r1], #1 + subs r3, r3, #1 + strb r12, [r0], #1 + bgt .L_bytewise_align + +.L_prepare_wordwise: + // load the number of words left + lsrs r3, r2, #2 + + .align 2 +.L_wordwise: + // wordwise copy + ldr r12, [r1], #4 + subs r3, r3, #1 + str r12, [r0], #4 + bgt .L_wordwise + + // remaining bytes + ands r2, #3 + beq .L_done + + .align 2 +.L_bytewise: + // simple bytewise copy + ldrb r12, [r1], #1 + subs r2, r2, #1 + strb r12, [r0], #1 + bgt .L_bytewise + +.L_done: + pop { r0, pc } + +// Handle copying by dword (8 bytes at a time) increments +.L_prepare_dword: + // see how many bytes we need to move to align dest to dword boundary + and r3, r0, #7 + cbz r3, .L_prepare_dwordwise + rsb r3, #8 + subs r2, r3 + + .align 2 +.L_bytewise_align_dword: + // bytewise to align memcpy + ldrb r12, [r1], #1 + subs r3, r3, #1 + strb r12, [r0], #1 + bgt .L_bytewise_align_dword + +.L_prepare_dwordwise: + // load the number of dwords left + lsrs r3, r2, #3 + + push { r5 } + + .align 2 +.L_dwordwise: + // dwordwise copy + ldrd r5, r12, [r1], #8 + subs r3, r3, #1 + strd r5, r12, [r0], #8 + bgt .L_dwordwise + + pop { r5 } + + // remaining bytes + ands r2, #7 + beq .L_done + + // finish the remaining bytes and exit + b .L_bytewise + diff --git a/kernel/lib/libc/string/arch/arm/arm-m/memset.S b/kernel/lib/libc/string/arch/arm/arm-m/memset.S new file mode 100644 index 000000000..08193e400 --- /dev/null +++ b/kernel/lib/libc/string/arch/arm/arm-m/memset.S @@ -0,0 +1,75 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +.text +.syntax unified +.thumb +.align 2 + +/* void bzero(void *s, size_t n); */ +FUNCTION(bzero) + mov r2, r1 + movs r1, #0 + +/* void *memset(void *s, int c, size_t n); */ +FUNCTION(memset) + // save the original pointer + push { r0, lr } + + // check for zero length + cbz r2, .L_done + + // short memsets aren't worth optimizing and make sure we have + // enough headroom to try to do dwordwise move optimization + cmp r2, #16 + blt .L_bytewise + + // see how many bytes we need to move to align to dword boundaries + and r3, r0, #7 + cbz r3, .L_prepare_dwordwise + rsb r3, #8 + subs r2, r3 + +.L_bytewise_align: + // bytewise to align memset + subs r3, r3, #1 + strb r1, [r0], #1 + bgt .L_bytewise_align + +.L_prepare_dwordwise: + // fill a pair of 32 bit registers with the 8 bit value + uxtb r1, r1 + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r12, r1 + + // load the number of dwords left + lsrs r3, r2, #3 + +.L_dwordwise: + // dwordwise memset + subs r3, r3, #1 + strd r1, r12, [r0], #8 + bgt .L_dwordwise + + // remaining bytes + ands r2, #7 + beq .L_done + +.L_bytewise: + // bytewise memset + subs r2, r2, #1 + strb r1, [r0], #1 + bgt .L_bytewise + +.L_done: + // restore the base pointer as return value + pop { r0, pc } + diff --git a/kernel/lib/libc/string/arch/arm/arm/memcpy.S b/kernel/lib/libc/string/arch/arm/arm/memcpy.S new file mode 100644 index 000000000..6a13b2485 --- /dev/null +++ b/kernel/lib/libc/string/arch/arm/arm/memcpy.S @@ -0,0 +1,163 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +.text +.align 2 + +/* void bcopy(const void *src, void *dest, size_t n); */ +FUNCTION(bcopy) + // swap args for bcopy + mov r12, r0 + mov r0, r1 + mov r1, r12 + +/* void *memcpy(void *dest, const void *src, size_t n); */ +FUNCTION(memmove) +FUNCTION(memcpy) + // check for zero length copy or the same pointer + cmp r2, #0 + cmpne r1, r0 + bxeq lr + + // save a few registers for use and the return code (input dst) + stmfd sp!, {r0, r4, r5, lr} + + // check for forwards overlap (src > dst, distance < len) + subs r3, r0, r1 + cmphi r2, r3 + bhi .L_forwardoverlap + + // check for a short copy len. + // 20 bytes is enough so that if a 16 byte alignment needs to happen there is at least a + // wordwise copy worth of work to be done. + cmp r2, #(16+4) + blo .L_bytewise + + // see if they are similarly aligned on 4 byte boundaries + eor r3, r0, r1 + tst r3, #3 + bne .L_bytewise // dissimilarly aligned, nothing we can do (for now) + + // check for 16 byte alignment on dst. + // this will also catch src being not 4 byte aligned, since it is similarly 4 byte + // aligned with dst at this point. + tst r0, #15 + bne .L_not16bytealigned + + // check to see if we have at least 32 bytes of data to copy. + // if not, just revert to wordwise copy + cmp r2, #32 + blo .L_wordwise + +.L_bigcopy: + // copy 32 bytes at a time. src & dst need to be at least 4 byte aligned, + // and we need at least 32 bytes remaining to copy + + // save r6-r7 for use in the big copy + stmfd sp!, {r6-r11} + + sub r2, r2, #32 // subtract an extra 32 to the len so we can avoid an extra compare + +.L_bigcopy_loop: + pld [r1, #64] + ldmia r1!, {r4-r11} + subs r2, r2, #32 + stmia r0!, {r4-r11} + bhs .L_bigcopy_loop + + // restore r6-r7 + ldmfd sp!, {r6-r11} + + // see if we are done + adds r2, r2, #32 + beq .L_done + + // less then 4 bytes left? + cmp r2, #4 + blo .L_bytewise + +.L_wordwise: + // copy 4 bytes at a time. + // src & dst are guaranteed to be word aligned, and at least 4 bytes are left to copy. + subs r2, r2, #4 + +.L_wordwise_loop: + ldr r3, [r1], #4 + subs r2, r2, #4 + str r3, [r0], #4 + bhs .L_wordwise_loop + + // correct the remaining len and test for completion + adds r2, r2, #4 + beq .L_done + +.L_bytewise: + // simple bytewise copy + ldrb r3, [r1], #1 + subs r2, r2, #1 + strb r3, [r0], #1 + bhi .L_bytewise + +.L_done: + // load dst for return and restore r4,r5 +#if ARM_ARCH_LEVEL >= 5 + ldmfd sp!, {r0, r4, r5, pc} +#else + ldmfd sp!, {r0, r4, r5, lr} + bx lr +#endif + +.L_not16bytealigned: + // dst is not 16 byte aligned, so we will copy up to 15 bytes to get it aligned. + // src is guaranteed to be similarly word aligned with dst. + + // set the condition flags based on the alignment. + lsl r12, r0, #28 + rsb r12, r12, #0 + msr CPSR_f, r12 // move into NZCV fields in CPSR + + // move as many bytes as necessary to get the dst aligned + ldrvsb r3, [r1], #1 // V set + ldrcsh r4, [r1], #2 // C set + ldreq r5, [r1], #4 // Z set + + strvsb r3, [r0], #1 + strcsh r4, [r0], #2 + streq r5, [r0], #4 + + ldmmiia r1!, {r3-r4} // N set + stmmiia r0!, {r3-r4} + + // fix the remaining len + sub r2, r2, r12, lsr #28 + + // test to see what we should do now + cmp r2, #32 + bhs .L_bigcopy + b .L_wordwise + + // src and dest overlap 'forwards' or dst > src +.L_forwardoverlap: + + // do a bytewise reverse copy for now + add r1, r1, r2 + add r0, r0, r2 + sub r1, r1, #1 + sub r0, r0, #1 + +.L_bytewisereverse: + // simple bytewise reverse copy + ldrb r3, [r1], #-1 + subs r2, r2, #1 + strb r3, [r0], #-1 + bhi .L_bytewisereverse + + b .L_done + diff --git a/kernel/lib/libc/string/arch/arm/arm/memset.S b/kernel/lib/libc/string/arch/arm/arm/memset.S new file mode 100644 index 000000000..afbe212b1 --- /dev/null +++ b/kernel/lib/libc/string/arch/arm/arm/memset.S @@ -0,0 +1,98 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +.text +.align 2 + +/* void bzero(void *s, size_t n); */ +FUNCTION(bzero) + mov r2, r1 + mov r1, #0 + +/* void *memset(void *s, int c, size_t n); */ +FUNCTION(memset) + // check for zero length + cmp r2, #0 + bxeq lr + + // save the original pointer + mov r12, r0 + + // short memsets aren't worth optimizing + cmp r2, #(32 + 16) + blt .L_bytewise + + // fill a 32 bit register with the 8 bit value + and r1, r1, #0xff + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + + // check for 16 byte alignment + tst r0, #15 + bne .L_not16bytealigned + +.L_bigset: + // dump some registers to make space for our values + stmfd sp!, { r4-r5 } + + // fill a bunch of registers with the set value + mov r3, r1 + mov r4, r1 + mov r5, r1 + + // prepare the count register so we can avoid an extra compare + sub r2, r2, #32 + + // 32 bytes at a time +.L_bigset_loop: + stmia r0!, { r1, r3, r4, r5 } + subs r2, r2, #32 + stmia r0!, { r1, r3, r4, r5 } + bge .L_bigset_loop + + // restore our dumped registers + ldmfd sp!, { r4-r5 } + + // see if we're done + adds r2, r2, #32 + beq .L_done + +.L_bytewise: + // bytewise memset + subs r2, r2, #1 + strb r1, [r0], #1 + bgt .L_bytewise + +.L_done: + // restore the base pointer as return value + mov r0, r12 + bx lr + +.L_not16bytealigned: + // dst is not 16 byte aligned, so we will set up to 15 bytes to get it aligned. + + // set the condition flags based on the alignment. + lsl r3, r0, #28 + rsb r3, r3, #0 + msr CPSR_f, r3 // move into NZCV fields in CPSR + + // move as many bytes as necessary to get the dst aligned + strvsb r1, [r0], #1 // V set + strcsh r1, [r0], #2 // C set + streq r1, [r0], #4 // Z set + strmi r1, [r0], #4 // N set + strmi r1, [r0], #4 // N set + + // fix the remaining len + sub r2, r2, r3, lsr #28 + + // do the large memset + b .L_bigset + diff --git a/kernel/lib/libc/string/arch/arm/rules.mk b/kernel/lib/libc/string/arch/arm/rules.mk new file mode 100644 index 000000000..5fa5806e8 --- /dev/null +++ b/kernel/lib/libc/string/arch/arm/rules.mk @@ -0,0 +1,48 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +ifeq ($(SUBARCH),arm) + +ASM_STRING_OPS := bcopy bzero memcpy memmove memset + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm/memcpy.S \ + $(LOCAL_DIR)/arm/memset.S + +# filter out the C implementation +C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS)) +endif + +ifeq ($(SUBARCH),arm-m) +ifeq ($(ARM_CPU),cortex-m0) + +ASM_STRING_OPS := + +MODULE_SRCS += \ + +else ifeq ($(ARM_CPU),cortex-m0plus) + +ASM_STRING_OPS := + +MODULE_SRCS += \ + +else + +ASM_STRING_OPS := bcopy bzero memcpy memset + +MODULE_SRCS += \ + $(LOCAL_DIR)/arm-m/memcpy.S \ + $(LOCAL_DIR)/arm-m/memset.S +endif + +# filter out the C implementation +C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS)) +endif + + diff --git a/kernel/lib/libc/string/arch/arm64/rules.mk b/kernel/lib/libc/string/arch/arm64/rules.mk new file mode 100644 index 000000000..a9fdc6b76 --- /dev/null +++ b/kernel/lib/libc/string/arch/arm64/rules.mk @@ -0,0 +1,9 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + diff --git a/kernel/lib/libc/string/arch/microblaze/rules.mk b/kernel/lib/libc/string/arch/microblaze/rules.mk new file mode 100644 index 000000000..cb7cfa8ee --- /dev/null +++ b/kernel/lib/libc/string/arch/microblaze/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +ASM_STRING_OPS := #bcopy bzero memcpy memmove memset + +MODULE_SRCS += \ + #$(LOCAL_DIR)/memcpy.S \ + #$(LOCAL_DIR)/memset.S + +# filter out the C implementation +C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS)) + diff --git a/kernel/lib/libc/string/arch/mips/rules.mk b/kernel/lib/libc/string/arch/mips/rules.mk new file mode 100644 index 000000000..cb7cfa8ee --- /dev/null +++ b/kernel/lib/libc/string/arch/mips/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +ASM_STRING_OPS := #bcopy bzero memcpy memmove memset + +MODULE_SRCS += \ + #$(LOCAL_DIR)/memcpy.S \ + #$(LOCAL_DIR)/memset.S + +# filter out the C implementation +C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS)) + diff --git a/kernel/lib/libc/string/arch/or1k/rules.mk b/kernel/lib/libc/string/arch/or1k/rules.mk new file mode 100644 index 000000000..6e94b4a64 --- /dev/null +++ b/kernel/lib/libc/string/arch/or1k/rules.mk @@ -0,0 +1,7 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + diff --git a/kernel/lib/libc/string/arch/x86-64/memcpy.S b/kernel/lib/libc/string/arch/x86-64/memcpy.S new file mode 100644 index 000000000..271dc865a --- /dev/null +++ b/kernel/lib/libc/string/arch/x86-64/memcpy.S @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +/* TODO: */ + +.text +.align 2 + +/* void bcopy(const void *src, void *dest, size_t n); */ +FUNCTION(bcopy) + ret + +/* void *memcpy(void *dest, const void *src, size_t n); */ +FUNCTION(memmove) +FUNCTION(memcpy) + ret + diff --git a/kernel/lib/libc/string/arch/x86-64/memset.S b/kernel/lib/libc/string/arch/x86-64/memset.S new file mode 100644 index 000000000..94bf1fc4b --- /dev/null +++ b/kernel/lib/libc/string/arch/x86-64/memset.S @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +/* TODO: */ + +.text +.align 2 + +/* void bzero(void *s, size_t n); */ +FUNCTION(bzero) + ret + +/* void *memset(void *s, int c, size_t n); */ +FUNCTION(memset) + ret + diff --git a/kernel/lib/libc/string/arch/x86-64/rules.mk b/kernel/lib/libc/string/arch/x86-64/rules.mk new file mode 100644 index 000000000..cb7cfa8ee --- /dev/null +++ b/kernel/lib/libc/string/arch/x86-64/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +ASM_STRING_OPS := #bcopy bzero memcpy memmove memset + +MODULE_SRCS += \ + #$(LOCAL_DIR)/memcpy.S \ + #$(LOCAL_DIR)/memset.S + +# filter out the C implementation +C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS)) + diff --git a/kernel/lib/libc/string/arch/x86/memcpy.S b/kernel/lib/libc/string/arch/x86/memcpy.S new file mode 100644 index 000000000..271dc865a --- /dev/null +++ b/kernel/lib/libc/string/arch/x86/memcpy.S @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +/* TODO: */ + +.text +.align 2 + +/* void bcopy(const void *src, void *dest, size_t n); */ +FUNCTION(bcopy) + ret + +/* void *memcpy(void *dest, const void *src, size_t n); */ +FUNCTION(memmove) +FUNCTION(memcpy) + ret + diff --git a/kernel/lib/libc/string/arch/x86/memset.S b/kernel/lib/libc/string/arch/x86/memset.S new file mode 100644 index 000000000..94bf1fc4b --- /dev/null +++ b/kernel/lib/libc/string/arch/x86/memset.S @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +/* TODO: */ + +.text +.align 2 + +/* void bzero(void *s, size_t n); */ +FUNCTION(bzero) + ret + +/* void *memset(void *s, int c, size_t n); */ +FUNCTION(memset) + ret + diff --git a/kernel/lib/libc/string/arch/x86/rules.mk b/kernel/lib/libc/string/arch/x86/rules.mk new file mode 100644 index 000000000..cb7cfa8ee --- /dev/null +++ b/kernel/lib/libc/string/arch/x86/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +ASM_STRING_OPS := #bcopy bzero memcpy memmove memset + +MODULE_SRCS += \ + #$(LOCAL_DIR)/memcpy.S \ + #$(LOCAL_DIR)/memset.S + +# filter out the C implementation +C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS)) + diff --git a/kernel/lib/libc/string/bcopy.c b/kernel/lib/libc/string/bcopy.c new file mode 100644 index 000000000..c1daa6062 --- /dev/null +++ b/kernel/lib/libc/string/bcopy.c @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +void bcopy(void const *src, void *dest, size_t count) +{ + memcpy(dest, src, count); +} + diff --git a/kernel/lib/libc/string/bzero.c b/kernel/lib/libc/string/bzero.c new file mode 100644 index 000000000..881b737b3 --- /dev/null +++ b/kernel/lib/libc/string/bzero.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +void +bzero(void *dst, size_t count) +{ + memset(dst, 0, count); +} + diff --git a/kernel/lib/libc/string/memchr.c b/kernel/lib/libc/string/memchr.c new file mode 100644 index 000000000..815e75acb --- /dev/null +++ b/kernel/lib/libc/string/memchr.c @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2001, Manuel J. Petit. +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +void * +memchr(void const *buf, int c, size_t len) +{ + size_t i; + unsigned char const *b= buf; + unsigned char x= (c&0xff); + + for (i= 0; i< len; i++) { + if (b[i]== x) { + return (void *)(b+i); + } + } + + return NULL; +} + diff --git a/kernel/lib/libc/string/memcmp.c b/kernel/lib/libc/string/memcmp.c new file mode 100644 index 000000000..c6aa8df34 --- /dev/null +++ b/kernel/lib/libc/string/memcmp.c @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +int +memcmp(const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + signed char res = 0; + + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} diff --git a/kernel/lib/libc/string/memcpy.c b/kernel/lib/libc/string/memcpy.c new file mode 100644 index 000000000..ab19a1a19 --- /dev/null +++ b/kernel/lib/libc/string/memcpy.c @@ -0,0 +1,50 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + + +#if !_ASM_MEMCPY + +typedef long word; + +#define lsize sizeof(word) +#define lmask (lsize - 1) + +void *memcpy(void *dest, const void *src, size_t count) +{ + char *d = (char *)dest; + const char *s = (const char *)src; + int len; + + if (count == 0 || dest == src) + return dest; + + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count < lsize)) + len = count; // copy the rest of the buffer with the byte mover + else + len = lsize - ((long)d & lmask); // move the ptrs up to a word boundary + + count -= len; + for (; len > 0; len--) + *d++ = *s++; + } + for (len = count / lsize; len > 0; len--) { + *(word *)d = *(word *)s; + d += lsize; + s += lsize; + } + for (len = count & lmask; len > 0; len--) + *d++ = *s++; + + return dest; +} + +#endif diff --git a/kernel/lib/libc/string/memmove.c b/kernel/lib/libc/string/memmove.c new file mode 100644 index 000000000..2f795d6ba --- /dev/null +++ b/kernel/lib/libc/string/memmove.c @@ -0,0 +1,74 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#if !_ASM_MEMMOVE + +typedef long word; + +#define lsize sizeof(word) +#define lmask (lsize - 1) + +void * +memmove(void *dest, void const *src, size_t count) +{ + char *d = (char *)dest; + const char *s = (const char *)src; + int len; + + if (count == 0 || dest == src) + return dest; + + if ((long)d < (long)s) { + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count < lsize)) + len = count; // copy the rest of the buffer with the byte mover + else + len = lsize - ((long)d & lmask); // move the ptrs up to a word boundary + + count -= len; + for (; len > 0; len--) + *d++ = *s++; + } + for (len = count / lsize; len > 0; len--) { + *(word *)d = *(word *)s; + d += lsize; + s += lsize; + } + for (len = count & lmask; len > 0; len--) + *d++ = *s++; + } else { + d += count; + s += count; + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count <= lsize)) + len = count; + else + len = ((long)d & lmask); + + count -= len; + for (; len > 0; len--) + *--d = *--s; + } + for (len = count / lsize; len > 0; len--) { + d -= lsize; + s -= lsize; + *(word *)d = *(word *)s; + } + for (len = count & lmask; len > 0; len--) + *--d = *--s; + } + + return dest; +} + +#endif + diff --git a/kernel/lib/libc/string/memscan.c b/kernel/lib/libc/string/memscan.c new file mode 100644 index 000000000..ebeba93fb --- /dev/null +++ b/kernel/lib/libc/string/memscan.c @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +void *memscan(void *addr, int c, size_t size) +{ + unsigned char *p = (unsigned char *)addr; + + while (size) { + if (*p == c) + return (void *)p; + p++; + size--; + } + return (void *)p; +} diff --git a/kernel/lib/libc/string/memset.c b/kernel/lib/libc/string/memset.c new file mode 100644 index 000000000..cb343d9e7 --- /dev/null +++ b/kernel/lib/libc/string/memset.c @@ -0,0 +1,45 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2001, Travis Geiselbrecht +// Copyright 2005, Michael Noisternig +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +void * +memset(void *s, int c, size_t count) +{ + char *xs = (char *) s; + size_t len = (-(size_t)s) & (sizeof(size_t)-1); + size_t cc = c & 0xff; + + if ( count > len ) { + count -= len; + cc |= cc << 8; + cc |= cc << 16; + if (sizeof(size_t) == 8) + cc |= (uint64_t)cc << 32; // should be optimized out on 32 bit machines + + // write to non-aligned memory byte-wise + for ( ; len > 0; len-- ) + *xs++ = c; + + // write to aligned memory dword-wise + for ( len = count/sizeof(size_t); len > 0; len-- ) { + *((size_t *)xs) = (size_t)cc; + xs += sizeof(size_t); + } + + count &= sizeof(size_t)-1; + } + + // write remaining bytes + for ( ; count > 0; count-- ) + *xs++ = c; + + return s; +} diff --git a/kernel/lib/libc/string/rules.mk b/kernel/lib/libc/string/rules.mk new file mode 100644 index 000000000..aaa4d7959 --- /dev/null +++ b/kernel/lib/libc/string/rules.mk @@ -0,0 +1,49 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +C_STRING_OPS := \ + bcopy \ + bzero \ + memchr \ + memcmp \ + memcpy \ + memmove \ + memset \ + strcat \ + strchr \ + strcmp \ + strcoll \ + strcpy \ + strdup \ + strerror \ + strlcat \ + strlcpy \ + strlen \ + strncat \ + strncpy \ + strncmp \ + strnicmp \ + strnlen \ + strpbrk \ + strrchr \ + strspn \ + strstr \ + strtok \ + strxfrm + +LIBC_STRING_C_DIR := $(LOCAL_DIR) + +# include the arch specific string routines +# +# the makefile may filter out implemented versions from the C_STRING_OPS variable +include $(LOCAL_DIR)/arch/$(ARCH)/rules.mk + +MODULE_SRCS += \ + $(addprefix $(LIBC_STRING_C_DIR)/,$(addsuffix .c,$(C_STRING_OPS))) + diff --git a/kernel/lib/libc/string/strcat.c b/kernel/lib/libc/string/strcat.c new file mode 100644 index 000000000..6f7e07817 --- /dev/null +++ b/kernel/lib/libc/string/strcat.c @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strcat(char *dest, char const *src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + diff --git a/kernel/lib/libc/string/strchr.c b/kernel/lib/libc/string/strchr.c new file mode 100644 index 000000000..0d0601837 --- /dev/null +++ b/kernel/lib/libc/string/strchr.c @@ -0,0 +1,18 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strchr(const char *s, int c) +{ + for (; *s != (char) c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} diff --git a/kernel/lib/libc/string/strcmp.c b/kernel/lib/libc/string/strcmp.c new file mode 100644 index 000000000..75131f7be --- /dev/null +++ b/kernel/lib/libc/string/strcmp.c @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +int +strcmp(char const *cs, char const *ct) +{ + signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + } + + return __res; +} diff --git a/kernel/lib/libc/string/strcoll.c b/kernel/lib/libc/string/strcoll.c new file mode 100644 index 000000000..cf9c7a916 --- /dev/null +++ b/kernel/lib/libc/string/strcoll.c @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +int +strcoll(const char *s1, const char *s2) +{ + return strcmp(s1, s2); +} + diff --git a/kernel/lib/libc/string/strcpy.c b/kernel/lib/libc/string/strcpy.c new file mode 100644 index 000000000..30f4890c6 --- /dev/null +++ b/kernel/lib/libc/string/strcpy.c @@ -0,0 +1,20 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strcpy(char *dest, char const *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + ; + return tmp; +} + diff --git a/kernel/lib/libc/string/strdup.c b/kernel/lib/libc/string/strdup.c new file mode 100644 index 000000000..d9daa1c34 --- /dev/null +++ b/kernel/lib/libc/string/strdup.c @@ -0,0 +1,24 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strdup(const char *str) +{ + size_t len; + char *copy; + + len = strlen(str) + 1; + copy = malloc(len); + if (copy == NULL) + return NULL; + memcpy(copy, str, len); + return copy; +} + diff --git a/kernel/lib/libc/string/strerror.c b/kernel/lib/libc/string/strerror.c new file mode 100644 index 000000000..321fc38ad --- /dev/null +++ b/kernel/lib/libc/string/strerror.c @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +char const * +strerror(int errnum) +{ + if (errnum < 0) { + return "General Error"; + } else { + return "No Error"; + } +} + diff --git a/kernel/lib/libc/string/strlcat.c b/kernel/lib/libc/string/strlcat.c new file mode 100644 index 000000000..ff690f606 --- /dev/null +++ b/kernel/lib/libc/string/strlcat.c @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2002, Manuel J. Petit +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +size_t +strlcat(char *dst, char const *src, size_t s) +{ + size_t i; + size_t j= strnlen(dst, s); + + if (!s) { + return j+strlen(src); + } + + dst+= j; + + for (i= 0; ((i< s-1) && src[i]); i++) { + dst[i]= src[i]; + } + + dst[i]= 0; + + return j + i + strlen(src+i); +} diff --git a/kernel/lib/libc/string/strlcpy.c b/kernel/lib/libc/string/strlcpy.c new file mode 100644 index 000000000..76af49d4b --- /dev/null +++ b/kernel/lib/libc/string/strlcpy.c @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2002, Manuel J. Petit +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +size_t +strlcpy(char *dst, char const *src, size_t s) +{ + size_t i= 0; + + if (!s) { + return strlen(src); + } + + for (i= 0; ((i< s-1) && src[i]); i++) { + dst[i]= src[i]; + } + + dst[i]= 0; + + return i + strlen(src+i); +} diff --git a/kernel/lib/libc/string/strlen.c b/kernel/lib/libc/string/strlen.c new file mode 100644 index 000000000..9e86f0ff3 --- /dev/null +++ b/kernel/lib/libc/string/strlen.c @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +size_t +strlen(char const *s) +{ + size_t i; + + i= 0; + while (s[i]) { + i+= 1; + } + + return i; +} diff --git a/kernel/lib/libc/string/strncat.c b/kernel/lib/libc/string/strncat.c new file mode 100644 index 000000000..e8bc5db3f --- /dev/null +++ b/kernel/lib/libc/string/strncat.c @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strncat(char *dest, char const *src, size_t count) +{ + char *tmp = dest; + + if (count > 0) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest = '\0'; + break; + } + } + } + + return tmp; +} + diff --git a/kernel/lib/libc/string/strncmp.c b/kernel/lib/libc/string/strncmp.c new file mode 100644 index 000000000..461e7b2ac --- /dev/null +++ b/kernel/lib/libc/string/strncmp.c @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +int +strncmp(char const *cs, char const *ct, size_t count) +{ + signed char __res = 0; + + while (count > 0) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} diff --git a/kernel/lib/libc/string/strncpy.c b/kernel/lib/libc/string/strncpy.c new file mode 100644 index 000000000..c270a6857 --- /dev/null +++ b/kernel/lib/libc/string/strncpy.c @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strncpy(char *dest, char const *src, size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + ; + + return tmp; +} + diff --git a/kernel/lib/libc/string/strnicmp.c b/kernel/lib/libc/string/strnicmp.c new file mode 100644 index 000000000..a998e1c75 --- /dev/null +++ b/kernel/lib/libc/string/strnicmp.c @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +int +strnicmp(char const *s1, char const *s2, size_t len) +{ + unsigned char c1 = '\0'; + unsigned char c2 = '\0'; + + if (len > 0) { + do { + c1 = *s1; + c2 = *s2; + s1++; + s2++; + if (!c1) + break; + if (!c2) + break; + if (c1 == c2) + continue; + c1 = tolower(c1); + c2 = tolower(c2); + if (c1 != c2) + break; + } while (--len); + } + return (int)c1 - (int)c2; +} +#pragma weak strncasecmp=strnicmp diff --git a/kernel/lib/libc/string/strnlen.c b/kernel/lib/libc/string/strnlen.c new file mode 100644 index 000000000..506b76bed --- /dev/null +++ b/kernel/lib/libc/string/strnlen.c @@ -0,0 +1,19 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +size_t +strnlen(char const *s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + ; + return sc - s; +} diff --git a/kernel/lib/libc/string/strpbrk.c b/kernel/lib/libc/string/strpbrk.c new file mode 100644 index 000000000..106a01d57 --- /dev/null +++ b/kernel/lib/libc/string/strpbrk.c @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strpbrk(char const *cs, char const *ct) +{ + const char *sc1; + const char *sc2; + + for (sc1 = cs; *sc1 != '\0'; ++sc1) { + for (sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *)sc1; + } + } + + return NULL; +} diff --git a/kernel/lib/libc/string/strrchr.c b/kernel/lib/libc/string/strrchr.c new file mode 100644 index 000000000..5c0875887 --- /dev/null +++ b/kernel/lib/libc/string/strrchr.c @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright 2001, Manuel J. Petit +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strrchr(char const *s, int c) +{ + char const *last= c?0:s; + + + while (*s) { + if (*s== c) { + last= s; + } + + s+= 1; + } + + return (char *)last; +} diff --git a/kernel/lib/libc/string/strspn.c b/kernel/lib/libc/string/strspn.c new file mode 100644 index 000000000..61789202f --- /dev/null +++ b/kernel/lib/libc/string/strspn.c @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +size_t +strspn(char const *s, char const *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (a = accept; *a != '\0'; ++a) { + if (*p == *a) + break; + } + if (*a == '\0') + return count; + ++count; + } + + return count; +} diff --git a/kernel/lib/libc/string/strstr.c b/kernel/lib/libc/string/strstr.c new file mode 100644 index 000000000..451b7119a --- /dev/null +++ b/kernel/lib/libc/string/strstr.c @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +char * +strstr(char const *s1, char const *s2) +{ + int l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *)s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!memcmp(s1,s2,l2)) + return (char *)s1; + s1++; + } + return NULL; +} diff --git a/kernel/lib/libc/string/strtok.c b/kernel/lib/libc/string/strtok.c new file mode 100644 index 000000000..d2db94f92 --- /dev/null +++ b/kernel/lib/libc/string/strtok.c @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +static char *___strtok = NULL; + +char * +strtok(char *s, char const *ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return ( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} diff --git a/kernel/lib/libc/string/strxfrm.c b/kernel/lib/libc/string/strxfrm.c new file mode 100644 index 000000000..2fecd026f --- /dev/null +++ b/kernel/lib/libc/string/strxfrm.c @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +size_t +strxfrm(char *dest, const char *src, size_t n) +{ + size_t len = strlen(src); + + if (n) { + size_t copy_len = len < n ? len : n - 1; + memcpy(dest, src, copy_len); + dest[copy_len] = 0; + } + return len; +} + diff --git a/kernel/lib/libc/strtol.c b/kernel/lib/libc/strtol.c new file mode 100644 index 000000000..d87bde03a --- /dev/null +++ b/kernel/lib/libc/strtol.c @@ -0,0 +1,140 @@ +/* $OpenBSD: strtol.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(const char *nptr, char **endptr, int base) +{ + const char *s; + long acc, cutoff; + int c; + int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = (unsigned char) *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? LONG_MIN : LONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + if (neg) { + if (cutlim > 0) { + cutlim -= base; + cutoff += 1; + } + cutlim = -cutlim; + } + for (acc = 0, any = 0;; c = (unsigned char) *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0) + continue; + if (neg) { + if (acc < cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = LONG_MIN; + errno = ERANGE; + } else { + any = 1; + acc *= base; + acc -= c; + } + } else { + if (acc > cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = LONG_MAX; + errno = ERANGE; + } else { + any = 1; + acc *= base; + acc += c; + } + } + } + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/kernel/lib/libc/strtoll.c b/kernel/lib/libc/strtoll.c new file mode 100644 index 000000000..e63c66ae5 --- /dev/null +++ b/kernel/lib/libc/strtoll.c @@ -0,0 +1,142 @@ +/* $OpenBSD: strtoll.c,v 1.6 2005/11/10 10:00:17 espie Exp $ */ +/*- + * Copyright (c) 1992 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +/* + * Convert a string to a long long. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long long +strtoll(const char *nptr, char **endptr, int base) +{ + const char *s; + long long acc, cutoff; + int c; + int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = (unsigned char) *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for long longs is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? LLONG_MIN : LLONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + if (neg) { + if (cutlim > 0) { + cutlim -= base; + cutoff += 1; + } + cutlim = -cutlim; + } + for (acc = 0, any = 0;; c = (unsigned char) *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0) + continue; + if (neg) { + if (acc < cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = LLONG_MIN; + errno = ERANGE; + } else { + any = 1; + acc *= base; + acc -= c; + } + } else { + if (acc > cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = LLONG_MAX; + errno = ERANGE; + } else { + any = 1; + acc *= base; + acc += c; + } + } + } + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/kernel/lib/magenta/BUILD.gn b/kernel/lib/magenta/BUILD.gn new file mode 100644 index 000000000..ced61a63f --- /dev/null +++ b/kernel/lib/magenta/BUILD.gn @@ -0,0 +1,92 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_magenta") { + if (enable_magenta) { + defines = [ "WITH_LIB_MAGENTA=1" ] + } else { + defines = [ "WITH_LIB_MAGENTA=0" ] + } +} + +config("_magenta_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + "//system/ulib/magenta/include", + ] +} + +module("magenta") { + public_configs = [ ":_magenta_config" ] + configs += [ "//kernel/lib/userboot:enable_userboot" ] + public = [ + "include/magenta/dispatcher.h", + "include/magenta/event_dispatcher.h", + "include/magenta/futex_context.h", + "include/magenta/futex_node.h", + "include/magenta/handle.h", + "include/magenta/interrupt_dispatcher.h", + "include/magenta/io_mapping_dispatcher.h", + "include/magenta/log_dispatcher.h", + "include/magenta/magenta.h", + "include/magenta/msg_pipe_dispatcher.h", + "include/magenta/msg_pipe.h", + "include/magenta/process_owner_dispatcher.h", + "include/magenta/thread_dispatcher.h", + "include/magenta/user_copy.h", + "include/magenta/user_process.h", + "include/magenta/user_thread.h", + "include/magenta/vm_object_dispatcher.h", + "include/magenta/waiter.h", + ] + sources = [ + "event_dispatcher.cpp", + "exception.cpp", + "futex_context.cpp", + "futex_node.cpp", + "handle.cpp", + "interrupt_dispatcher.cpp", + "io_mapping_dispatcher.cpp", + "log_dispatcher.cpp", + "magenta.cpp", + "msg_pipe.cpp", + "msg_pipe_dispatcher.cpp", + "process_owner_dispatcher.cpp", + "thread_dispatcher.cpp", + "user_copy.cpp", + "user_process.cpp", + "user_thread.cpp", + "vm_object_dispatcher.cpp", + "waiter.cpp", + ] + deps = [ + "//kernel/dev/interrupt", + "//kernel/dev/udisplay", + "//kernel/lib/console", + "//kernel/lib/libc", + "//kernel/lib/user_copy", + "//kernel/lib/utils", + ] + if (enable_debuglog) { + deps += [ "//kernel/lib/debuglog" ] + } + if (enable_pcie) { + public += [ + "include/magenta/pci_device_dispatcher.h", + "include/magenta/pci_interrupt_dispatcher.h", + "include/magenta/pci_io_mapping_dispatcher.h", + ] + sources += [ + "pci_device_dispatcher.cpp", + "pci_interrupt_dispatcher.cpp", + "pci_io_mapping_dispatcher.cpp", + ] + deps += [ "//kernel/dev/pcie" ] + } +} diff --git a/kernel/lib/magenta/event_dispatcher.cpp b/kernel/lib/magenta/event_dispatcher.cpp new file mode 100644 index 000000000..b791df096 --- /dev/null +++ b/kernel/lib/magenta/event_dispatcher.cpp @@ -0,0 +1,56 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include + +#include + +#include + +constexpr mx_rights_t kDefaultEventRights = + MX_RIGHT_DUPLICATE | MX_RIGHT_TRANSFER | MX_RIGHT_READ | MX_RIGHT_WRITE; + +status_t EventDispatcher::Create(uint32_t options, utils::RefPtr* dispatcher, + mx_rights_t* rights) { + auto disp = new EventDispatcher(options); + if (!disp) return ERR_NO_MEMORY; + + *rights = kDefaultEventRights; + *dispatcher = utils::AdoptRef(disp); + return NO_ERROR; +} + +EventDispatcher::EventDispatcher(uint32_t options) {} + +EventDispatcher::~EventDispatcher() {} + +void EventDispatcher::Close(Handle* handle) { + waiter_.CloseHandle(handle); +} + +Waiter* EventDispatcher::BeginWait(event_t* event, Handle* handle, mx_signals_t signals) { + return waiter_.BeginWait(event, handle, signals); +} + +status_t EventDispatcher::SignalEvent() { + waiter_.Signal(MX_SIGNAL_SIGNALED); + return NO_ERROR; +} + +status_t EventDispatcher::ResetEvent() { + waiter_.Reset(); + return NO_ERROR; +} + + +status_t EventDispatcher::UserSignal(uint32_t set_mask, uint32_t clear_mask) { + waiter_.Modify(set_mask, clear_mask); + return NO_ERROR; +} diff --git a/kernel/lib/magenta/exception.cpp b/kernel/lib/magenta/exception.cpp new file mode 100644 index 000000000..1a20d5522 --- /dev/null +++ b/kernel/lib/magenta/exception.cpp @@ -0,0 +1,152 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include + +#include +#include + +#define LOCAL_TRACE 0 +#define TRACE_EXCEPTIONS 1 + +static const char* exception_type_to_string(uint type) { + switch (type) { + case EXC_FATAL_PAGE_FAULT: + return "fatal page fault"; + case EXC_UNDEFINED_INSTRUCTION: + return "undefined instruction"; + case EXC_GENERAL: + return "general fault"; + default: + return "unknown fault"; + } +} + +static void build_exception_context(mx_exception_context_t* context, + uint exception_type, + arch_exception_context_t* arch_context) { + context->type = exception_type; + // TODO(dje): add more stuff +} + +static void build_exception_report(mx_exception_report_t* report, + UserThread* thread, + uint exception_type, + arch_exception_context_t* context, + ulong ip) { + memset(report, 0, sizeof(*report)); + report->pid = thread->process()->id(); + report->tid = thread->id(); + report->pc = ip; + build_exception_context(&report->context, exception_type, context); +} + +static status_t recv_exception_result(UserThread* thread, + utils::RefPtr dispatcher, + const mx_exception_report_t* report) { + LTRACE_ENTRY; + return thread->WaitForExceptionHandler(dispatcher, report); +} + +static status_t try_exception_handler(utils::RefPtr dispatcher, + UserThread* thread, uint exception_type, + arch_exception_context_t* context, mx_vaddr_t ip) { + if (!dispatcher) + return ERR_NOT_FOUND; + + mx_exception_report_t report; + build_exception_report(&report, thread, exception_type, context, ip); + + status_t status = recv_exception_result(thread, dispatcher, &report); + LTRACEF("recv_exception_result returned %d\n", status); + return status; +} + +static status_t try_thread_exception_handler(UserThread* thread, + uint exception_type, + arch_exception_context_t* context, + mx_vaddr_t ip) { + return try_exception_handler(thread->exception_handler(), thread, + exception_type, context, ip); +} + +static status_t try_process_exception_handler(UserThread* thread, + uint exception_type, + arch_exception_context_t* context, + mx_vaddr_t ip) { + return try_exception_handler(thread->process()->exception_handler(), thread, + exception_type, context, ip); +} + +static status_t try_system_exception_handler(UserThread* thread, + uint exception_type, + arch_exception_context_t* context, + mx_vaddr_t ip) { + return try_exception_handler(GetSystemExceptionHandler(), thread, + exception_type, context, ip); +} + +// exception handler from low level architecturally-specific code +// +// If we return NO_ERROR, the caller is expected to resume the thread "as if" +// nothing happened, the handler is expected to have modified state such that +// resumption is possible. +// Otherwise, if we return, the result is ERR_NOT_VALID meaning the thread is +// not a magenta thread. +// +// TODO(dje): Support unwinding from this exception and introducing a +// different exception. + +status_t magenta_exception_handler(uint exception_type, + arch_exception_context_t* context, + mx_vaddr_t ip) { + LTRACEF("type %u, context %p\n", exception_type, context); + + UserThread* thread = UserThread::GetCurrent(); + if (unlikely(!thread)) { + // we're not in magenta thread context, bail + return ERR_NOT_VALID; + } + UserProcess* process = thread->process(); + + status_t status; + + status = try_thread_exception_handler(thread, exception_type, context, ip); + if (status == NO_ERROR) + return NO_ERROR; + + status = try_process_exception_handler(thread, exception_type, context, ip); + if (status == NO_ERROR) + return NO_ERROR; + + status = try_system_exception_handler(thread, exception_type, context, ip); + if (status == NO_ERROR) + return NO_ERROR; + +#if TRACE_EXCEPTIONS + printf("KERN: %s in magenta thread '%s' in process '%s' at IP 0x%lx\n", + exception_type_to_string(exception_type), thread->name().data(), + process->name().data(), ip); + + arch_dump_exception_context(context); +#endif + + // kill our process + process->Kill(); + + // exit + thread->Exit(); + + // should not get here + panic("arch_exception_handler: fell out of thread exit somehow!\n"); + + return ERR_NOT_SUPPORTED; +} diff --git a/kernel/lib/magenta/futex_context.cpp b/kernel/lib/magenta/futex_context.cpp new file mode 100644 index 000000000..198e33476 --- /dev/null +++ b/kernel/lib/magenta/futex_context.cpp @@ -0,0 +1,221 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +FutexContext::FutexContext() { + LTRACE_ENTRY; + + mutex_init(&lock_); +} + +FutexContext::~FutexContext() { + LTRACE_ENTRY; + + mutex_destroy(&lock_); +} + +status_t FutexContext::FutexWait(int* value_ptr, int current_value, mx_time_t timeout) { + LTRACE_ENTRY; + + uintptr_t futex_key = reinterpret_cast(value_ptr); + FutexNode* node; + + // FutexWait() checks that the address value_ptr still contains + // current_value, and if so it sleeps awaiting a FutexWake() on value_ptr. + // Those two steps must together be atomic with respect to FutexWake(). + // If a FutexWake() operation could occur between them, a userland mutex + // operation built on top of futexes would have a race condition that + // could miss wakeups. + AutoLock lock(lock_); + int value; + status_t result = magenta_copy_from_user(value_ptr, &value, sizeof(value)); + if (result != NO_ERROR) return result; + if (value != current_value) return ERR_BUSY; + + node = UserThread::GetCurrent()->futex_node(); + node->set_hash_key(futex_key); + node->set_next(nullptr); + node->set_tail(node); + + QueueNodesLocked(futex_key, node); + + // Block current thread + result = node->BlockThread(&lock_, timeout); + if (result == NO_ERROR) { + // All the work necessary for removing us from the hash table was be done by FutexWake() + return NO_ERROR; + } + // If we got a timeout, we need to remove the thread's node from the + // wait queue, since FutexWake() didn't do that. We need to re-get the + // hash table key, because it might have changed if the thread was + // requeued by FutexRequeue(). + futex_key = node->hash_key(); + FutexNode* list_head = futex_table_.get(futex_key); + FutexNode* test = list_head; + FutexNode* prev = nullptr; + while (test) { + DEBUG_ASSERT(test->hash_key() == futex_key); + FutexNode* next = test->next(); + if (test == node) { + if (prev) { + // unlink from linked list + prev->set_next(next); + if (!next) { + // We have removed the last element, so we need to + // update the tail pointer. + list_head->set_tail(prev); + } + } else { + // reset head of futex + futex_table_.remove(futex_key); + if (next) { + next->set_tail(list_head->tail()); + futex_table_.add(futex_key, next); + } + } + return result; + } + prev = test; + test = next; + } + // The current thread was not found on the wait queue. This means + // that, although we got a timeout, we were *also* woken by FutexWake() + // (which removed the thread from the wait queue) -- the two raced + // together. + // + // In this case, we want to return a success status. This preserves + // the property that if FutexWake() is called with wake_count=1 and + // there are waiting threads, then at least one FutexWait() call + // returns success. + // + // If that property is broken, it can lead to missed wakeups in + // concurrency constructs that are built on top of futexes. For + // example, suppose a FutexWake() call from pthread_mutex_unlock() + // races with a FutexWait() timeout from pthread_mutex_timedlock(). A + // typical implementation of pthread_mutex_timedlock() will return + // immediately without trying again to claim the mutex if this + // FutexWait() call returns a timeout status. If that happens, and if + // another thread is waiting on the mutex, then that thread won't get + // woken -- the wakeup from the FutexWake() call would have got lost. + return NO_ERROR; +} + +status_t FutexContext::FutexWake(int* value_ptr, uint32_t count) { + LTRACE_ENTRY; + + if (count == 0) return NO_ERROR; + + uintptr_t futex_key = reinterpret_cast(value_ptr); + + { + AutoLock lock(lock_); + + FutexNode* node = futex_table_.get(futex_key); + if (!node) { + // nothing blocked on this futex if we can't find it + return NO_ERROR; + } + + FutexNode* wake_head = node; + node = node->RemoveFromHead(count, futex_key, futex_key); + // node is now the new blocked thread list head + + futex_table_.remove(futex_key); + if (node != nullptr) { + // TODO - Add a HashTable::replace() and use that instead of removing and re-adding + futex_table_.add(futex_key, node); + } + + // Traversing this list of threads must be done while holding the + // lock, because any of these threads might wake up from a timeout + // and call FutexWait(), which would clobber the "next" pointer in + // the thread's FutexNode. + FutexNode::WakeThreads(wake_head); + } + + return NO_ERROR; +} + +status_t FutexContext::FutexRequeue(int* wake_ptr, uint32_t wake_count, int current_value, + int* requeue_ptr, uint32_t requeue_count) { + LTRACE_ENTRY; + + AutoLock lock(lock_); + + int value; + status_t result = magenta_copy_from_user(wake_ptr, &value, sizeof(value)); + if (result != NO_ERROR) return result; + if (value != current_value) return ERR_BUSY; + + uintptr_t wake_key = reinterpret_cast(wake_ptr); + uintptr_t requeue_key = reinterpret_cast(requeue_ptr); + if (wake_key == requeue_key) return ERR_INVALID_ARGS; + + FutexNode* node = futex_table_.get(wake_key); + if (!node) { + // nothing blocked on this futex if we can't find it + return NO_ERROR; + } + + // This must happen before RemoveFromHead() calls set_hash_key() on + // nodes below, because operations on futex_table_ look at the hash_key + // field of the list head nodes for wake_key and requeue_key. + futex_table_.remove(wake_key); + + FutexNode* wake_head; + if (wake_count == 0) { + wake_head = nullptr; + } else { + wake_head = node; + node = node->RemoveFromHead(wake_count, wake_key, wake_key); + } + + // node is now the head of wake_ptr futex after possibly removing some threads to wake + if (node != nullptr) { + if (requeue_count > 0) { + // head and tail of list of nodes to requeue + FutexNode* requeue_head = node; + node = node->RemoveFromHead(requeue_count, wake_key, requeue_key); + + // now requeue our nodes to requeue_ptr mutex + QueueNodesLocked(requeue_key, requeue_head); + } + } + + // add any remaining nodes back to wake_key futex + if (node != nullptr) { + futex_table_.add(wake_key, node); + } + + FutexNode::WakeThreads(wake_head); + + return NO_ERROR; +} + +void FutexContext::QueueNodesLocked(uintptr_t futex_key, FutexNode* head) { + FutexNode* current_head = futex_table_.get(futex_key); + if (!current_head) { + // The current thread is first to block on this futex, so add it to the hash table. + futex_table_.add(futex_key, head); + } else { + // push node for current thread at end of list + current_head->AppendList(head); + } +} + +size_t FutexContext::FutexHashFn::operator()(uintptr_t key) const { + // Futex address is likely 8 byte aligned, so ignore low 3 bits + return static_cast((key >> 3) % FUTEX_HASH_BUCKET_COUNT); +} diff --git a/kernel/lib/magenta/futex_node.cpp b/kernel/lib/magenta/futex_node.cpp new file mode 100644 index 000000000..a62dcca28 --- /dev/null +++ b/kernel/lib/magenta/futex_node.cpp @@ -0,0 +1,77 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +FutexNode::FutexNode() : hash_next_(nullptr), next_(nullptr), tail_(nullptr) { + LTRACE_ENTRY; + + cond_init(&condvar_); +} + +FutexNode::~FutexNode() { + LTRACE_ENTRY; + + cond_destroy(&condvar_); +} + +void FutexNode::AppendList(FutexNode* head) { + // tail of blocked thread list must be non-null and must have null next_ pointer + DEBUG_ASSERT(tail_ != nullptr); + DEBUG_ASSERT(tail_->next_ == nullptr); + tail_->next_ = head; + tail_ = head->tail(); +} + +// remove up to |count| nodes from our head and return new head +// the removed nodes remain a valid list after this operation +FutexNode* FutexNode::RemoveFromHead(uint32_t count, uintptr_t old_hash_key, + uintptr_t new_hash_key) { + if (count == 0) return this; + + FutexNode* node = this; + FutexNode* last = this; + for (uint32_t i = 0; i < count && node != nullptr; i++) { + DEBUG_ASSERT(node->hash_key() == old_hash_key); + // For requeuing, update the key so that FutexWait() can remove the + // thread from its current queue if the wait operation times out. + node->set_hash_key(new_hash_key); + + last = node; + node = node->next_; + } + + if (node != nullptr) node->tail_ = tail_; + last->next_ = nullptr; + tail_ = last; + return node; +} + +status_t FutexNode::BlockThread(mutex_t* mutex, mx_time_t timeout) { + lk_time_t t = mx_time_to_lk(timeout); + + return cond_wait_timeout(&condvar_, mutex, t); +} + +void FutexNode::WakeThreads(FutexNode* head) { + while (head != nullptr) { + cond_signal(&head->condvar_); + head = head->next_; + } +} + +uintptr_t GetHashTableKey(FutexNode* node) { + return node->hash_key(); +} +void SetHashTableKey(FutexNode* node, uintptr_t key) { + node->set_hash_key(key); +} diff --git a/kernel/lib/magenta/handle.cpp b/kernel/lib/magenta/handle.cpp new file mode 100644 index 000000000..4569bfd70 --- /dev/null +++ b/kernel/lib/magenta/handle.cpp @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include + +Handle::Handle(utils::RefPtr dispatcher, uint32_t rights) + : process_id_(0u), + rights_(rights), + dispatcher_(utils::move(dispatcher)), + prev_(nullptr), + next_(nullptr) {} + +Handle::Handle(const Handle& rhs) + : process_id_(rhs.process_id_), + rights_(rhs.rights_), + dispatcher_(rhs.dispatcher_), + prev_(nullptr), + next_(nullptr) {} + +Handle::~Handle() { + // Setting the pid to zero on destruction is critical for the correct + // operation of the handle lookup. + process_id_ = 0u; + rights_ = 0u; +} + +utils::RefPtr Handle::dispatcher() { + return dispatcher_; +} + +// Closes a handle. Always succeeds. +void Handle::Close() { + dispatcher_->Close(this); +} diff --git a/kernel/lib/magenta/include/magenta/dispatcher.h b/kernel/lib/magenta/include/magenta/dispatcher.h new file mode 100644 index 000000000..57c00286b --- /dev/null +++ b/kernel/lib/magenta/include/magenta/dispatcher.h @@ -0,0 +1,90 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +class HandleList; +class Waiter; + +// The Kernel Objects. Keep this list sorted. +class EventDispatcher; +class InterruptDispatcher; +class LogDispatcher; +class MessagePipeDispatcher; +class PciInterruptDispatcher; +class PciDeviceDispatcher; +class ProcessOwnerDispatcher; +class ThreadDispatcher; +class VmObjectDispatcher; +class IoMappingDispatcher; + + +class Dispatcher : public utils::RefCounted { +public: + virtual ~Dispatcher() {} + + virtual void Close(Handle* handle) = 0; + + virtual status_t UserSignal(uint32_t set_mask, uint32_t clear_mask) { + return ERR_NOT_SUPPORTED; + } + + virtual Waiter* BeginWait(event_t* event, Handle* handle, mx_signals_t signals) { + return nullptr; + } + + virtual EventDispatcher* get_event_dispatcher() { + return nullptr; + } + + virtual InterruptDispatcher* get_interrupt_dispatcher() { + return nullptr; + } + + virtual MessagePipeDispatcher* get_message_pipe_dispatcher() { + return nullptr; + } + + virtual ProcessOwnerDispatcher* get_process_owner_dispatcher() { + return nullptr; + } + + virtual ThreadDispatcher* get_thread_dispatcher() { + return nullptr; + } + + virtual VmObjectDispatcher* get_vm_object_dispatcher() { + return nullptr; + } + + virtual PciDeviceDispatcher* get_pci_device_dispatcher() { + return nullptr; + } + + virtual PciInterruptDispatcher* get_pci_interrupt_dispatcher() { + return nullptr; + } + + virtual IoMappingDispatcher* get_io_mapping_dispatcher() { + return nullptr; + } + + virtual LogDispatcher* get_log_dispatcher() { + return nullptr; + } +}; diff --git a/kernel/lib/magenta/include/magenta/event_dispatcher.h b/kernel/lib/magenta/include/magenta/event_dispatcher.h new file mode 100644 index 000000000..f67515dd4 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/event_dispatcher.h @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include +#include + +#include + +class EventDispatcher final : public Dispatcher { +public: + static status_t Create(uint32_t options, utils::RefPtr* dispatcher, + mx_rights_t* rights); + + ~EventDispatcher() final; + void Close(Handle* handle) final; + EventDispatcher* get_event_dispatcher() final { return this; } + + + Waiter* BeginWait(event_t* event, Handle* handle, mx_signals_t signals); + + status_t SignalEvent(); + + status_t ResetEvent(); + + status_t UserSignal(uint32_t set_mask, uint32_t clear_mask) final; + +private: + explicit EventDispatcher(uint32_t options); + Waiter waiter_; +}; diff --git a/kernel/lib/magenta/include/magenta/exception.h b/kernel/lib/magenta/include/magenta/exception.h new file mode 100644 index 000000000..39b0ce28b --- /dev/null +++ b/kernel/lib/magenta/include/magenta/exception.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +// low level to high level exception handler, called at interrupt or exception context +enum { + EXC_FATAL_PAGE_FAULT, + EXC_UNDEFINED_INSTRUCTION, + EXC_GENERAL, +}; + +typedef struct arch_exception_context arch_exception_context_t; + +status_t magenta_exception_handler(uint exception_type, + struct arch_exception_context* context, + mx_vaddr_t ip); + +// arch code must implement this to dump the architecturally specific state they passed to magenta_exception_handler +void arch_dump_exception_context(arch_exception_context_t *); + +__END_CDECLS diff --git a/kernel/lib/magenta/include/magenta/futex_context.h b/kernel/lib/magenta/include/magenta/futex_context.h new file mode 100644 index 000000000..c49a2c745 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/futex_context.h @@ -0,0 +1,70 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +#define FUTEX_HASH_BUCKET_COUNT 37 + +class FutexNode; + +// FutexContext is a class that encapsulates support for futex operations. +// FutexContext uses a hash table keyed on the futex address (a pointer to integer in userspace) +// to contain all active futexes. +// A futex is considered active if there is one or more threads blocked on the futex. +// After no threads are left blocked on a futex it is removed from the hash table. +// The value in the futex hash table is the FutexNode object associated with the head +// of the list of threads blocked on the futex. +// To avoid memory allocation at futex operation time, a FutexNode is embedded in each +// UserThread object. +// When the thread at the head of the futex's blocked thread list is resumed, +// The FutexNode for the new head of the blocked thread list is set as the hash table value +// for the futex. +class FutexContext { +public: + FutexContext(); + ~FutexContext(); + + // FutexWait first verifies that the integer pointed to by |value_ptr| + // still equals |current_value|. If the test fails, FutexWait returns FAILED_PRECONDITION. + // Otherwise it will block the current thread for up to |timeout| nanoseconds, + // or until the thread is woken by a FutexWake or FutexRequeue operation + // on the same |value_ptr| futex. + status_t FutexWait(int* value_ptr, int current_value, mx_time_t timeout); + + // FutexWake will wake up to |count| number of threads blocked on the |value_ptr| futex. + status_t FutexWake(int* value_ptr, uint32_t count); + + // FutexWait first verifies that the integer pointed to by |wake_ptr| + // still equals |current_value|. If the test fails, FutexWait returns FAILED_PRECONDITION. + // Otherwise it will wake up to |wake_count| number of threads blocked on the |wake_ptr| futex. + // If any other threads remain blocked on on the |wake_ptr| futex, up to |requeue_count| + // of them will then be requeued to the tail of the list of threads + // blocked on the |requeue_ptr| futex. + status_t FutexRequeue(int* wake_ptr, uint32_t wake_count, int current_value, int* requeue_ptr, + uint32_t requeue_count); + +private: + FutexContext(const FutexContext&) = delete; + FutexContext& operator=(const FutexContext&) = delete; + + void QueueNodesLocked(uintptr_t futex_key, FutexNode* head); + + // hash function for our hash table + struct FutexHashFn { + size_t operator()(uintptr_t key) const; + }; + + // protects futex_table_ + mutex_t lock_; + + // Hash table for futexes in this context. + // Key is futex address, value is the FutexNode for the head of futex's blocked thread list. + utils::HashTable futex_table_; +}; diff --git a/kernel/lib/magenta/include/magenta/futex_node.h b/kernel/lib/magenta/include/magenta/futex_node.h new file mode 100644 index 000000000..8132fcb0f --- /dev/null +++ b/kernel/lib/magenta/include/magenta/futex_node.h @@ -0,0 +1,91 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include + +// Node for linked list of threads blocked on a futex +// Intended to be embedded within a UserThread Instance +class FutexNode { +public: + FutexNode(); + ~FutexNode(); + + // adds a list of nodes to our tail + void AppendList(FutexNode* head); + + // remove up to |count| nodes from our head and return new head + // the removed nodes remain a valid list after this operation + FutexNode* RemoveFromHead(uint32_t count, uintptr_t old_hash_key, + uintptr_t new_hash_key); + + // block the current thread, releasing the given mutex while the thread + // is blocked + status_t BlockThread(mutex_t* mutex, mx_time_t timeout); + + // wakes the list of threads starting with node |head| + static void WakeThreads(FutexNode* head); + + FutexNode* next() const { + return next_; + } + void set_next(FutexNode* node) { + next_ = node; + } + + // for SinglyLinkedList entry in the FutexContext hash table + FutexNode* list_next() { + return hash_next_; + } + void list_set_next(FutexNode* node) { + hash_next_ = node; + } + + uintptr_t hash_key() const { + return hash_key_; + } + void set_hash_key(uintptr_t key) { + hash_key_ = key; + } + + FutexNode* tail() const { + return tail_; + } + void set_tail(FutexNode* tail) { + tail_ = tail; + } + +private: + // hash_key_ contains the futex address. This field has two roles: + // * It is used by FutexWait() to determine which queue to remove the + // thread from when a wait operation times out. + // * Additionally, when this FutexNode is the head of a futex wait + // queue, this field is used by the HashTable (because it uses + // intrusive SinglyLinkedLists). + uintptr_t hash_key_; + + // condition variable used for blocking our containing thread on + cond_t condvar_; + + // for SinglyLinkedList entry in futex hash table + FutexNode* hash_next_; + + // for list of threads blocked on a futex + FutexNode* next_; + + // tail node of the node list + // only valid if this node is the list head + FutexNode* tail_; +}; + +uintptr_t GetHashTableKey(FutexNode* node); +void SetHashTableKey(FutexNode* node, uintptr_t key); diff --git a/kernel/lib/magenta/include/magenta/handle.h b/kernel/lib/magenta/include/magenta/handle.h new file mode 100644 index 000000000..6bb0ac133 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/handle.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include +#include + +class Dispatcher; + +class Handle final { +public: + Handle(utils::RefPtr dispatcher, mx_rights_t rights); + Handle(const Handle& rhs); + ~Handle(); + + utils::RefPtr dispatcher(); + + mx_pid_t process_id() const { + return process_id_; + } + void set_process_id(mx_pid_t pid) { + process_id_ = pid; + } + + uint32_t rights() const { + return rights_; + } + + // Closes a handle. Always succeeds. + void Close(); + + Handle* list_prev() { + return prev_; + } + Handle* list_next() { + return next_; + } + const Handle* list_prev() const { + return prev_; + } + const Handle* list_next() const { + return next_; + } + + void list_set_prev(Handle* node) { + prev_ = node; + } + void list_set_next(Handle* node) { + next_ = node; + } + +private: + mx_pid_t process_id_; + mx_rights_t rights_; + utils::RefPtr dispatcher_; + Handle* prev_; + Handle* next_; +}; diff --git a/kernel/lib/magenta/include/magenta/interrupt_dispatcher.h b/kernel/lib/magenta/include/magenta/interrupt_dispatcher.h new file mode 100644 index 000000000..78b796841 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/interrupt_dispatcher.h @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +class InterruptDispatcher final : public Dispatcher { +public: + static status_t Create(uint32_t vector, uint32_t flags, utils::RefPtr* dispatcher, + mx_rights_t* rights); + + virtual ~InterruptDispatcher() final; + void Close(Handle* handle) final; + + InterruptDispatcher* get_interrupt_dispatcher() final { return this; } + + // Wait for an interrupt. + status_t InterruptWait(); + // Notify the system that the caller has finished processing the interrupt. + // Required before the handle can be waited upon again. + status_t InterruptComplete(); + +private: + explicit InterruptDispatcher(interrupt_event_t ie); + + interrupt_event_t interrupt_event_; + bool signaled_; +}; diff --git a/kernel/lib/magenta/include/magenta/io_mapping_dispatcher.h b/kernel/lib/magenta/include/magenta/io_mapping_dispatcher.h new file mode 100644 index 000000000..04fa85b0a --- /dev/null +++ b/kernel/lib/magenta/include/magenta/io_mapping_dispatcher.h @@ -0,0 +1,45 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +class IoMappingDispatcher : public Dispatcher { +public: + static status_t Create(const char* dbg_name, + paddr_t paddr, size_t size, + uint vmm_flags, uint arch_mmu_flags, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights); + + ~IoMappingDispatcher() override; + void Close(Handle* handle) override; + IoMappingDispatcher* get_io_mapping_dispatcher() final { return this; } + + bool closed() const; + paddr_t paddr() const { return paddr_; } + vaddr_t vaddr() const { return vaddr_; } + size_t size() const { return size_; } + const utils::RefPtr& aspace() { return aspace_; } + +protected: + static constexpr mx_rights_t kDefaultRights = MX_RIGHT_READ; + IoMappingDispatcher() { } + void Cleanup(); + + status_t Init(const char* dbg_name, + paddr_t paddr, size_t size, + uint vmm_flags, uint arch_mmu_flags); + +private: + utils::RefPtr aspace_; + paddr_t paddr_; + vaddr_t vaddr_ = 0; + size_t size_; +}; diff --git a/kernel/lib/magenta/include/magenta/log_dispatcher.h b/kernel/lib/magenta/include/magenta/log_dispatcher.h new file mode 100644 index 000000000..ec0bb0b4b --- /dev/null +++ b/kernel/lib/magenta/include/magenta/log_dispatcher.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include + +class LogDispatcher final : public Dispatcher { +public: + static status_t Create(uint32_t flags, utils::RefPtr* dispatcher, mx_rights_t* rights); + + ~LogDispatcher() final; + void Close(Handle* handle) final; + LogDispatcher* get_log_dispatcher() final { return this; } + + status_t Write(const void* ptr, size_t len, uint32_t flags); + status_t Read(void* ptr, size_t len, uint32_t flags); + status_t ReadFromUser(void* userptr, size_t len, uint32_t flags); + +private: + explicit LogDispatcher(uint32_t flags); + dlog_reader reader_; + uint32_t flags_; +}; \ No newline at end of file diff --git a/kernel/lib/magenta/include/magenta/magenta.h b/kernel/lib/magenta/include/magenta/magenta.h new file mode 100644 index 000000000..5dd78ad9c --- /dev/null +++ b/kernel/lib/magenta/include/magenta/magenta.h @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include +#include + +#include +#include + +class Handle; +class Dispatcher; +class UserProcess; + +// Creates a handle attached to |dispatcher| and with |rights| from a +// specific arena which makes their addresses come from a fixed range. +Handle* MakeHandle(utils::RefPtr dispatcher, mx_rights_t rights); + +// Duplicate a handle created by MakeHandle(). +Handle* DupHandle(Handle* source); + +// Deletes a |handle| made by MakeHandle() or DupHandle(). +void DeleteHandle(Handle* handle); + +// Maps a handle created by MakeHandle() to the 0 to 2^32 range. +uint32_t MapHandleToU32(Handle* handle); + +// Maps an integer obtained by MapHandleToU32() back to a Handle. +Handle* MapU32ToHandle(uint32_t value); + +// Registers a |process|. The return value is a unique id which can serve +// as a process id. +uint32_t AddProcess(UserProcess* process); + +// Unregisters |process|. +void RemoveProcess(UserProcess* process); + +// Outputs via the console the current list of processes; +void DebugDumpProcessList(); + +// Set/get the system exception handler. +void SetSystemExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour); +utils::RefPtr GetSystemExceptionHandler(); + +struct handle_delete { + inline void operator()(Handle* h) const { + DeleteHandle(h); + } +}; + +bool magenta_rights_check(mx_rights_t actual, mx_rights_t desired); + +using HandleUniquePtr = utils::unique_ptr; + +// (temporary) conversion from mx_time (nanoseconds) to lk_time_t (milliseconds) +// remove once mx_time_t is converted to 1:1 match mx_time_t +static inline lk_time_t mx_time_to_lk(mx_time_t mxt) { + if (mxt == MX_TIME_INFINITE) + return INFINITE_TIME; + + uint64_t temp = mxt / 1000000; // nanosecs to milliseconds + if (temp >= UINT32_MAX) + return UINT32_MAX - 1; + return static_cast(temp & 0xffffffff); +} + diff --git a/kernel/lib/magenta/include/magenta/msg_pipe.h b/kernel/lib/magenta/include/magenta/msg_pipe.h new file mode 100644 index 000000000..ca3f4a01a --- /dev/null +++ b/kernel/lib/magenta/include/magenta/msg_pipe.h @@ -0,0 +1,69 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include + +#include +#include +#include + +#include + +class Handle; + +struct MessagePacket { + MessagePacket* next; + MessagePacket* prev; + utils::Array data; + utils::Array handles; + + ~MessagePacket(); + + void ReturnHandles(); + + MessagePacket* list_prev() { + return prev; + } + const MessagePacket* list_prev() const { + return prev; + } + MessagePacket* list_next() { + return next; + } + const MessagePacket* list_next() const { + return next; + } + void list_set_prev(MessagePacket* prv) { + prev = prv; + } + void list_set_next(MessagePacket* nxt) { + next = nxt; + } +}; + +class MessagePipe : public utils::RefCounted { +public: + MessagePipe(); + ~MessagePipe(); + + void OnDispatcherDestruction(size_t side); + + status_t Read(size_t side, utils::unique_ptr* msg); + status_t Write(size_t side, utils::unique_ptr msg); + + Waiter* GetWaiter(size_t side); + +private: + bool dispatcher_alive_[2]; + utils::DoublyLinkedList messages_[2]; + // This lock protects |dispatcher_alive_| and |messages_|. + mutex_t lock_; + Waiter waiter_[2]; +}; diff --git a/kernel/lib/magenta/include/magenta/msg_pipe_dispatcher.h b/kernel/lib/magenta/include/magenta/msg_pipe_dispatcher.h new file mode 100644 index 000000000..d6036f82d --- /dev/null +++ b/kernel/lib/magenta/include/magenta/msg_pipe_dispatcher.h @@ -0,0 +1,42 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +class MessagePipeDispatcher final : public Dispatcher { +public: + static status_t Create(utils::RefPtr* dispatcher0, + utils::RefPtr* dispatcher1, mx_rights_t* rights); + + ~MessagePipeDispatcher() final; + void Close(Handle* handle) final; + Waiter* BeginWait(event_t* event, Handle* handle, mx_signals_t signals) final; + MessagePipeDispatcher* get_message_pipe_dispatcher() final { return this; } + + status_t BeginRead(uint32_t* message_size, uint32_t* handle_count); + status_t AcceptRead(utils::Array* data, utils::Array* handles); + status_t Write(utils::Array data, utils::Array handles); + +private: + MessagePipeDispatcher(size_t side, utils::RefPtr pipe); + + size_t side_; + utils::RefPtr pipe_; + utils::unique_ptr pending_; + mutex_t lock_; +}; diff --git a/kernel/lib/magenta/include/magenta/pci_device_dispatcher.h b/kernel/lib/magenta/include/magenta/pci_device_dispatcher.h new file mode 100644 index 000000000..96d277a0e --- /dev/null +++ b/kernel/lib/magenta/include/magenta/pci_device_dispatcher.h @@ -0,0 +1,91 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +class PciInterruptDispatcher; + +class PciDeviceDispatcher final : public Dispatcher { +public: + class PciDeviceWrapper final : public utils::RefCounted { + public: + static status_t Create(pcie_device_state_t* device, + utils::RefPtr* out_device); + + status_t Claim(); // Called only from PciDeviceDispatcher while holding dispatcher lock_ + + status_t AddBarCachePolicyRef(uint bar_num, uint32_t cache_policy); + void ReleaseBarCachePolicyRef(uint bar_num); + + pcie_device_state_t* device() const { return device_; } + bool claimed() const { return claimed_; } + + private: + friend class utils::RefPtr; + + struct CachePolicyRef { + uint ref_count; + uint32_t cache_policy; + }; + + explicit PciDeviceWrapper(pcie_device_state_t* device); + ~PciDeviceWrapper(); + + mutex_t cp_ref_lock_; + CachePolicyRef cp_refs_[PCIE_MAX_BAR_REGS]; + pcie_device_state_t* device_; + bool claimed_ = false; + }; + + static status_t Create(uint32_t index, + mx_pcie_get_nth_info_t* out_info, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights); + + ~PciDeviceDispatcher() final; + void Close(Handle* handle) final; + PciDeviceDispatcher* get_pci_device_dispatcher() final { return this; } + + void ReleaseDevice(); + + status_t ClaimDevice(); + status_t EnableBusMaster(bool enable); + status_t ResetDevice(); + status_t MapConfig(utils::RefPtr* out_mapping, + mx_rights_t* out_rights); + status_t MapMmio(uint32_t bar_num, + uint32_t cache_policy, + utils::RefPtr* out_mapping, + mx_rights_t* out_rights); + status_t MapInterrupt(int32_t which_irq, + utils::RefPtr* interrupt_dispatcher, + mx_rights_t* rights); + + bool irqs_maskable() const { return irqs_maskable_; } + +private: + PciDeviceDispatcher(utils::RefPtr device, + mx_pcie_get_nth_info_t* out_info); + + // Lock protecting upward facing APIs. Generally speaking, this lock is + // held for the duration of most of our dispatcher API implementations. It + // is unsafe to ever attempt to acquire this lock during a callback from the + // PCI bus driver level. + mutex_t lock_; + utils::RefPtr device_; + + uint irqs_supported_ = 0; + bool irqs_maskable_ = false; +}; diff --git a/kernel/lib/magenta/include/magenta/pci_interrupt_dispatcher.h b/kernel/lib/magenta/include/magenta/pci_interrupt_dispatcher.h new file mode 100644 index 000000000..3b10a300f --- /dev/null +++ b/kernel/lib/magenta/include/magenta/pci_interrupt_dispatcher.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include + +class PciDeviceDispatcher; + +class PciInterruptDispatcher final : public Dispatcher { +public: + static status_t Create(const utils::RefPtr& device, + uint32_t irq_id, + bool maskable, + mx_rights_t* out_rights, + utils::RefPtr* out_interrupt); + + ~PciInterruptDispatcher() final; + void Close(Handle* handle) final; + PciInterruptDispatcher* get_pci_interrupt_dispatcher() final { return this; } + + status_t InterruptWait(); + +private: + static pcie_irq_handler_retval_t IrqThunk(struct pcie_common_state* dev, + uint irq_id, + void* ctx); + PciInterruptDispatcher(uint32_t irq); + + uint32_t irq_id_; + bool maskable_; + event_t event_; + mutex_t lock_; + mutex_t wait_lock_; + utils::RefPtr device_; +}; diff --git a/kernel/lib/magenta/include/magenta/pci_io_mapping_dispatcher.h b/kernel/lib/magenta/include/magenta/pci_io_mapping_dispatcher.h new file mode 100644 index 000000000..d19a6f46d --- /dev/null +++ b/kernel/lib/magenta/include/magenta/pci_io_mapping_dispatcher.h @@ -0,0 +1,42 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +class PciDeviceDispatcher; +class PciIoMappingDispatcher final : public IoMappingDispatcher { +public: + static status_t Create(const utils::RefPtr& device, + const char* dbg_tag, + paddr_t paddr, + size_t size, + uint vmm_flags, + uint arch_mmu_flags, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights); + + static status_t CreateBarMapping( + const utils::RefPtr& device, + uint bar_num, + uint vmm_flags, + uint cache_policy, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights); + + ~PciIoMappingDispatcher() final; + void Close(Handle* handle) final; + +private: + PciIoMappingDispatcher(const utils::RefPtr& device) + : device_(device) { } + + utils::RefPtr device_; + uint bar_num_ = PCIE_MAX_BAR_REGS; +}; diff --git a/kernel/lib/magenta/include/magenta/process_owner_dispatcher.h b/kernel/lib/magenta/include/magenta/process_owner_dispatcher.h new file mode 100644 index 000000000..2003a598e --- /dev/null +++ b/kernel/lib/magenta/include/magenta/process_owner_dispatcher.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include +#include +#include + +#include + +#include + +class UserProcess; + +class ProcessOwnerDispatcher : public Dispatcher { +public: + static status_t Create(utils::RefPtr* dispatcher, mx_rights_t* rights, utils::StringPiece name); + + // $$$ move to private? + explicit ProcessOwnerDispatcher(utils::unique_ptr process); + + virtual ~ProcessOwnerDispatcher() final; + void Close(Handle* handle) final; + ProcessOwnerDispatcher* get_process_owner_dispatcher() final { return this; } + + Waiter* BeginWait(event_t* event, Handle* handle, mx_signals_t signals); + status_t Start(mx_handle_t handle, mx_vaddr_t pc_vaddr); + mx_handle_t AddHandle(HandleUniquePtr handle); + utils::RefPtr GetVmAspace() { return process_->aspace(); } + status_t GetInfo(mx_process_info_t *info); + status_t SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour); + +private: + utils::unique_ptr process_; +}; diff --git a/kernel/lib/magenta/include/magenta/thread_dispatcher.h b/kernel/lib/magenta/include/magenta/thread_dispatcher.h new file mode 100644 index 000000000..9895919e1 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/thread_dispatcher.h @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +class UserThread; + +class ThreadDispatcher : public Dispatcher { +public: + // Does not take ownership of |thread| + static status_t Create(UserThread* thread, utils::RefPtr* dispatcher, + mx_rights_t* rights); + + virtual ~ThreadDispatcher() final; + void Close(Handle* handle) final; + ThreadDispatcher* get_thread_dispatcher() final { return this; } + + Waiter* BeginWait(event_t* event, Handle* handle, mx_signals_t signals); + status_t SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour); + status_t MarkExceptionHandled(mx_exception_status_t status); + +private: + explicit ThreadDispatcher(UserThread* thread); + + UserThread* thread() { + return thread_; + } + + UserThread* thread_; +}; diff --git a/kernel/lib/magenta/include/magenta/user_copy.h b/kernel/lib/magenta/include/magenta/user_copy.h new file mode 100644 index 000000000..71d0105e0 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/user_copy.h @@ -0,0 +1,16 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +status_t magenta_copy_from_user(const void* src, void* dest, size_t len); + +status_t magenta_copy_user_string(const char* src, size_t src_len, char* buf, size_t buf_len, + utils::StringPiece* sp); + +status_t magenta_copy_user_dynamic(const void* src, uint8_t** dst, size_t len, size_t max_len); diff --git a/kernel/lib/magenta/include/magenta/user_process.h b/kernel/lib/magenta/include/magenta/user_process.h new file mode 100644 index 000000000..582cfbcb9 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/user_process.h @@ -0,0 +1,175 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class Dispatcher; + +class UserProcess { +public: + // state of the process + enum State { + PROC_STATE_INITIAL, + PROC_STATE_LOADING, + PROC_STATE_LOADED, + PROC_STATE_STARTING, + PROC_STATE_RUNNING, + PROC_STATE_DEAD, + }; + + UserProcess(utils::StringPiece name); + ~UserProcess(); + + mx_pid_t id() const { + return id_; + } + + // Performs initialization on a newly constructed UserProcess + // If this fails, then the object is invalid and should be deleted + status_t Initialize(); + + // Called when the process owner handle is closed + void Close(); + + // Map a |handle| to an integer which can be given to usermode as a + // handle value. Uses MapHandleToU32() plus additional mixing. + mx_handle_t MapHandleToValue(Handle* handle); + + // Maps a handle value into a Handle as long we can verify that + // it belongs to this process. + Handle* GetHandle_NoLock(mx_handle_t handle_value); + + // Adds |hadle| to this process handle list. The handle->process_id() is + // set to this process id(). + void AddHandle(HandleUniquePtr handle); + void AddHandle_NoLock(HandleUniquePtr handle); + + // Removes the Handle corresponding to |handle_value| from this process + // handle list. + HandleUniquePtr RemoveHandle(mx_handle_t handle_value); + HandleUniquePtr RemoveHandle_NoLock(mx_handle_t handle_value); + + // Puts back the |handle_value| which has not yet been given to another process + // back into this process. + void UndoRemoveHandle_NoLock(mx_handle_t handle_value); + + bool GetDispatcher(mx_handle_t handle_value, utils::RefPtr* dispatcher, + uint32_t* rights); + + mutex_t& handle_table_lock() { return handle_table_lock_; } + + static UserProcess* GetCurrent() { + UserThread *current = UserThread::GetCurrent(); + DEBUG_ASSERT(current); + return current->process(); + } + FutexContext* futex_context() { return &futex_context_; } + + Waiter* GetWaiter() { return &waiter_; } + + // Starts the process running + // The process must first be in state PROC_STATE_LOADED + status_t Start(void* arg, mx_vaddr_t vaddr); + + void Exit(int retcode); + void Kill(); + + status_t GetInfo(mx_process_info_t *info); + + mx_tid_t GetNextThreadId(); + + utils::RefPtr aspace() { return aspace_; } + + const utils::StringPiece name() const { return name_; } + + status_t SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour); + + utils::RefPtr exception_handler(); + + // The following two methods can slow and innacurrate and should only be + // called from diagnostics code. + uint32_t HandleCount(); + uint32_t ThreadCount(); + + // Necessary members for using DoublyLinkedList. + UserProcess* list_prev() { return prev_; } + UserProcess* list_next() { return next_; } + const UserProcess* list_prev() const { return prev_; } + const UserProcess* list_next() const { return next_; } + void list_set_prev(UserProcess* node) { prev_ = node; } + void list_set_next(UserProcess* node) { next_ = node; } + +private: + UserProcess(const UserProcess&) = delete; + UserProcess& operator=(const UserProcess&) = delete; + + // Thread lifecycle support + friend class UserThread; + void AddThread(UserThread* t); + void ThreadDetached(UserThread* t); + + // Transition to dead state and signal waiter. + void Dead_NoLock(); + + mx_pid_t id_; + + mx_handle_t handle_rand_; + + // The next thread id to assign. + // This is an int as we use atomic_add. TODO(dje): wip + int next_thread_id_; + + // protects thread_list_, as well as the UserThread joined_ and detached_ flags + mutex_t thread_list_lock_; + // list of running threads + struct list_node thread_list_; + + // our address space + utils::RefPtr aspace_; + + mutex_t handle_table_lock_; // protects |handles_|. + utils::DoublyLinkedList handles_; + + Waiter waiter_; + + FutexContext futex_context_; + + State state_; + mutex_t state_lock_; + + // process return code + int retcode_; + + // main entry point to the process + thread_start_routine entry_; + + utils::RefPtr exception_handler_; + mx_exception_behaviour_t exception_behaviour_; + mutex_t exception_lock_; + + // Holds the linked list of processes that magenta.cpp mantains. + UserProcess* prev_; + UserProcess* next_; + + // The user-friendly process name. For debug purposes only. + char name_[THREAD_NAME_LENGTH / 2]; +}; diff --git a/kernel/lib/magenta/include/magenta/user_thread.h b/kernel/lib/magenta/include/magenta/user_thread.h new file mode 100644 index 000000000..95baf2bc5 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/user_thread.h @@ -0,0 +1,111 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +class ThreadHandle; +class UserProcess; + +class UserThread { +public: + UserThread(UserProcess* process, thread_start_routine entry, void* arg); + ~UserThread(); + + // Performs initialization on a newly constructed UserThread + // If this fails, then the object is invalid and should be deleted + status_t Initialize(utils::StringPiece name); + void Start(); + void Exit(); + void Detach(); + + UserProcess* process() const { + return process_; + } + + mx_tid_t id() const { + return id_; + } + + static UserThread* GetCurrent() { + return reinterpret_cast(tls_get(TLS_ENTRY_LKUSER)); + } + + status_t SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour); + utils::RefPtr exception_handler(); + + FutexNode* futex_node() { + return &futex_node_; + } + + const utils::StringPiece name() const { return thread_.name; } + + Waiter* GetWaiter() { return &waiter_; } + + // TODO(dje): Support unwinding from this exception and introducing a + // different exception. + status_t WaitForExceptionHandler(utils::RefPtr dispatcher, const mx_exception_report_t* report); + void WakeFromExceptionHandler(mx_exception_status_t status); + +private: + UserThread(const UserThread&) = delete; + UserThread& operator=(const UserThread&) = delete; + + static int StartRoutine(void* arg); + + // my process + UserProcess* process_; + + // So UserProcess can access node_, thread_, joined_ and detached_ + friend class UserProcess; + + // for my process's thread list + struct list_node node_; + + // A unique thread id within the process. + mx_tid_t id_; + + // thread start routine and argument pointer + thread_start_routine entry_; + void* arg_; + + // True if the thread has been joined + // Only set by UserProcess, protected by UserProcess::thread_list_lock_ + bool joined_; + // We are detached if there are no handles remaining that refer to us. + // In that case, it is safe to delete this UserThread instance when the thread is joined. + // Only set by UserProcess, protected by UserProcess::thread_list_lock_ + bool detached_; + + thread_t thread_; + void* user_stack_; + + // Node for linked list of threads blocked on a futex + FutexNode futex_node_; + + Waiter waiter_; + + // A thread-level exception handler for this thread. + utils::RefPtr exception_handler_; + mx_exception_behaviour_t exception_behaviour_; + mutex_t exception_lock_; + + // Support for waiting for an exception handler. + // Reply from handler. + mx_exception_status_t exception_status_; + cond_t exception_wait_cond_; + mutex_t exception_wait_lock_; + + static const int kDefaultStackSize = 16 * PAGE_SIZE; +}; diff --git a/kernel/lib/magenta/include/magenta/vm_object_dispatcher.h b/kernel/lib/magenta/include/magenta/vm_object_dispatcher.h new file mode 100644 index 000000000..8092b2ba7 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/vm_object_dispatcher.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +#include + +class VmObject; +class VmAspace; + +class VmObjectDispatcher : public Dispatcher { +public: + static status_t Create(utils::RefPtr vmo, utils::RefPtr* dispatcher, + mx_rights_t* rights); + + ~VmObjectDispatcher() final; + void Close(Handle* handle) final; + VmObjectDispatcher* get_vm_object_dispatcher() final { return this; } + + mx_ssize_t Read(void* user_data, mx_size_t length, uint64_t offset); + mx_ssize_t Write(const void* user_data, mx_size_t length, uint64_t offset); + mx_status_t SetSize(uint64_t); + mx_status_t GetSize(uint64_t* size); + + // XXX really belongs in process + mx_status_t Map(utils::RefPtr aspace, uint32_t vmo_rights, uint64_t offset, mx_size_t len, + uintptr_t* ptr, uint32_t flags); + +private: + explicit VmObjectDispatcher(utils::RefPtr vmo); + + utils::RefPtr vmo_; +}; diff --git a/kernel/lib/magenta/include/magenta/waiter.h b/kernel/lib/magenta/include/magenta/waiter.h new file mode 100644 index 000000000..0c4924404 --- /dev/null +++ b/kernel/lib/magenta/include/magenta/waiter.h @@ -0,0 +1,87 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#include +#include + +#include +#include + +class Handle; + +// Magenta Waiter +// +// Provides the interface between the syscall layer and the +// kernel object layer that allows waiting for object state changes. +// + +class Waiter { +public: + Waiter(); + + Waiter(const Waiter& o) = delete; + Waiter& operator=(const Waiter& o) = delete; + + // The syscall layer uses these 2 functions when doing a wait. + // assume an array of handles to wait and an array of signals: + // + // event_t event; + // Waiter* warr = new Waiter*[n_waits]; + // + // for (size_t ix = 0; ix != n_waits; ++ix) { + // warr[ix] = handles[ix]->dispatcher()->BeginWait( + // &event, handles[ix], signals[ix]); + // } + // + // event_wait(&event); + // + // for (size_t ix = 0; ix != n_waits; ++ix) { + // warr[ix]->FinishWait(&event); + // } + // + + Waiter* BeginWait(event_t* event, Handle* handle, mx_signals_t signals); + mx_signals_t FinishWait(event_t* event); + + // The syscall layer calls this when a handle is closed. + bool CloseHandle(Handle* handle); + + // The object internally calls this method when its state changes. + // If there is a matching wait, the associated event will be signaled. + bool Signal(mx_signals_t signals); + + // Call to clear the signal, but not unsignal any events. + void ClearSignal(mx_signals_t signals); + + void Modify(mx_signals_t set_mask, mx_signals_t clear_mask); + + bool Reset(); + +private: + struct WaitNode { + WaitNode* next; + event_t* event; + Handle* handle; + mx_signals_t signals; + + void list_set_next(WaitNode* node) { + next = node; + } + WaitNode* list_next() { + return next; + } + }; + + int SignalComplete_NoLock(); + + utils::SinglyLinkedList nodes_; + mutex_t lock_; + mx_signals_t signals_; +}; diff --git a/kernel/lib/magenta/interrupt_dispatcher.cpp b/kernel/lib/magenta/interrupt_dispatcher.cpp new file mode 100644 index 000000000..db87b3a9c --- /dev/null +++ b/kernel/lib/magenta/interrupt_dispatcher.cpp @@ -0,0 +1,66 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include + +#define LOCAL_TRACE 0 + +constexpr mx_rights_t kDefaultInterruptRights = + MX_RIGHT_TRANSFER | MX_RIGHT_READ | MX_RIGHT_WRITE; + +// static +status_t InterruptDispatcher::Create(uint32_t vector, uint32_t flags, + utils::RefPtr* dispatcher, mx_rights_t* rights) { + interrupt_event_t ie; + + // convert from MX_FLAG to internal INTERRUPT_EVENT_FLAG + uint32_t ie_flags = 0; + ie_flags |= (flags & MX_FLAG_REMAP_IRQ) ? INTERRUPT_EVENT_FLAG_REMAP_IRQ : 0; + + status_t result = interrupt_event_create(vector, ie_flags, &ie); + if (result != NO_ERROR) return result; + + auto disp = new InterruptDispatcher(ie); + if (!disp) return ERR_NO_MEMORY; + + *rights = kDefaultInterruptRights; + *dispatcher = utils::AdoptRef(disp); + return NO_ERROR; +} + +InterruptDispatcher::InterruptDispatcher(interrupt_event_t ie) + : interrupt_event_(ie), signaled_(false) {} + +InterruptDispatcher::~InterruptDispatcher() {} + +status_t InterruptDispatcher::InterruptWait() { + if (signaled_) { + LTRACEF("need to call InterruptHandle::Complete() first!\n"); + return ERR_BAD_STATE; + } + + status_t result = interrupt_event_wait(interrupt_event_); + if (result != NO_ERROR) return result; + + signaled_ = true; + return NO_ERROR; +} + +status_t InterruptDispatcher::InterruptComplete() { + if (signaled_) { + interrupt_event_complete(interrupt_event_); + signaled_ = false; + } + return NO_ERROR; +} + +void InterruptDispatcher::Close(Handle* handle) { + // TODO(yky): figure this out with thread lifecycle. need to wake up the waiting thread +} diff --git a/kernel/lib/magenta/io_mapping_dispatcher.cpp b/kernel/lib/magenta/io_mapping_dispatcher.cpp new file mode 100644 index 000000000..9a9483874 --- /dev/null +++ b/kernel/lib/magenta/io_mapping_dispatcher.cpp @@ -0,0 +1,83 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +constexpr mx_rights_t IoMappingDispatcher::kDefaultRights; + +status_t IoMappingDispatcher::Create(const char* dbg_name, + paddr_t paddr, size_t size, + uint vmm_flags, uint arch_mmu_flags, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights) { + if (!out_dispatcher || !out_rights) + return ERR_INVALID_ARGS; + + IoMappingDispatcher* disp = new IoMappingDispatcher(); + if (!disp) + return ERR_NO_MEMORY; + + status_t status; + status = disp->Init(dbg_name, paddr, size, vmm_flags, arch_mmu_flags); + if (status != NO_ERROR) { + delete disp; + } else { + *out_dispatcher = utils::AdoptRef(disp); + *out_rights = kDefaultRights; + } + + return status; +} + +IoMappingDispatcher::~IoMappingDispatcher() { + Cleanup(); +} + +void IoMappingDispatcher::Close(Handle* handle) { + Cleanup(); +} + +void IoMappingDispatcher::Cleanup() { + if (vaddr_) { + DEBUG_ASSERT(aspace_); + aspace_->FreeRegion(vaddr_); + } + + vaddr_ = 0; + aspace_.reset(); +} + +bool IoMappingDispatcher::closed() const { + return !aspace_ || !vaddr_; +} + +status_t IoMappingDispatcher::Init(const char* dbg_name, + paddr_t paddr, size_t size, + uint vmm_flags, uint arch_mmu_flags) { + DEBUG_ASSERT(closed()); + + if (!IS_ALIGNED(paddr, PAGE_SIZE) || + !IS_ALIGNED(size, PAGE_SIZE) || + !size) + return ERR_INVALID_ARGS; + + aspace_ = UserProcess::GetCurrent()->aspace(); + DEBUG_ASSERT(aspace_); // This should never fail. + if (!aspace_) + return ERR_GENERIC; + + paddr_ = paddr; + size_ = size; + + return aspace_->AllocPhysical(dbg_name, + size, + reinterpret_cast(&vaddr_), + PAGE_SIZE_SHIFT, + paddr, + vmm_flags, + arch_mmu_flags); +} diff --git a/kernel/lib/magenta/log_dispatcher.cpp b/kernel/lib/magenta/log_dispatcher.cpp new file mode 100644 index 000000000..5abc7852a --- /dev/null +++ b/kernel/lib/magenta/log_dispatcher.cpp @@ -0,0 +1,52 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include + +constexpr mx_rights_t kDefaultEventRights = + MX_RIGHT_TRANSFER | MX_RIGHT_READ | MX_RIGHT_WRITE; + +status_t LogDispatcher::Create(uint32_t flags, utils::RefPtr* dispatcher, + mx_rights_t* rights) { + auto disp = new LogDispatcher(flags); + if (!disp) return ERR_NO_MEMORY; + + *rights = kDefaultEventRights; + *dispatcher = utils::AdoptRef(disp); + return NO_ERROR; +} + +LogDispatcher::LogDispatcher(uint32_t flags) : flags_(flags) { + dlog_reader_init(&reader_); +} + +LogDispatcher::~LogDispatcher() { + dlog_reader_destroy(&reader_); +} + +void LogDispatcher::Close(Handle* handle) { +} + +status_t LogDispatcher::Write(const void* ptr, size_t len, uint32_t flags) { + return dlog_write(flags_, ptr, len); +} + +status_t LogDispatcher::Read(void* ptr, size_t len, uint32_t flags) { + return dlog_read(&reader_, 0, ptr, len); +} + +status_t LogDispatcher::ReadFromUser(void* ptr, size_t len, uint32_t flags) { + for (;;) { + mx_status_t r = dlog_read_user(&reader_, 0, ptr, len); + if ((r == ERR_NO_MSG) && (flags & MX_LOG_FLAG_WAIT)) { + dlog_wait(&reader_); + continue; + } + return r; + } +} diff --git a/kernel/lib/magenta/magenta.cpp b/kernel/lib/magenta/magenta.cpp new file mode 100644 index 000000000..8b2a98598 --- /dev/null +++ b/kernel/lib/magenta/magenta.cpp @@ -0,0 +1,162 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +// This handle limit is super low, but we can increase it when the arena +// can reserve VA ranges. Currently it commits physical pages. +constexpr size_t kMaxHandleCount = 8 * 1024; + +// The handle arena and its mutex. +mutex_t handle_mutex; +utils::TypedArena handle_arena; + +// The process list, id and its mutex. +mutex_t process_mutex; +uint32_t next_process_id = 4u; +utils::DoublyLinkedList process_list; + +// The system exception handler +static utils::RefPtr system_exception_handler; +static mx_exception_behaviour_t system_exception_behaviour; +static mutex_t system_exception_mutex; + +void magenta_init(uint level) { + mutex_init(&handle_mutex); + handle_arena.Init("handles", kMaxHandleCount); + + mutex_init(&process_mutex); + + system_exception_behaviour = MX_EXCEPTION_BEHAVIOUR_DEFAULT; + mutex_init(&system_exception_mutex); +} + +Handle* MakeHandle(utils::RefPtr dispatcher, mx_rights_t rights) { + AutoLock lock(&handle_mutex); + return handle_arena.New(utils::move(dispatcher), rights); +} + +Handle* DupHandle(Handle* source) { + AutoLock lock(&handle_mutex); + return handle_arena.New(*source); +} + +void DeleteHandle(Handle* handle) { + handle->~Handle(); + AutoLock lock(&handle_mutex); + handle_arena.RawFree(handle); +} + +bool HandleInRange(void* addr) { + AutoLock lock(&handle_mutex); + return handle_arena.in_range(addr); +} + +uint32_t MapHandleToU32(Handle* handle) { + auto va = reinterpret_cast(handle) - reinterpret_cast(handle_arena.start()); + return static_cast(va); +} + +Handle* MapU32ToHandle(uint32_t value) { + auto va = value + reinterpret_cast(handle_arena.start()); + if (value % sizeof(Handle) != 0) + return nullptr; + if (!HandleInRange(va)) + return nullptr; + return reinterpret_cast(va); +} + +uint32_t AddProcess(UserProcess* process) { + // Don't call any method of |process|, it is not yet fully constructed. + AutoLock lock(&process_mutex); + ++next_process_id; + process_list.push_front(process); + LTRACEF("Adding process %p : id = %u\n", process, next_process_id); + return next_process_id; +} + +void RemoveProcess(UserProcess* process) { + AutoLock lock(&process_mutex); + process_list.remove(process); + LTRACEF("Removing process %p : id = %u\n", process, process->id()); +} + +void DebugDumpProcessList() { + AutoLock lock(&process_mutex); + printf("ps: [id] [#threads] [#handles] [addr] [name]\n"); + utils::for_each(&process_list, [](UserProcess* process) { + printf("%3u %3u %3u %p %s\n", + process->id(), + process->ThreadCount(), + process->HandleCount(), + process, + process->name().data()); + }); +} + +void SetSystemExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour) { + AutoLock lock(&system_exception_mutex); + + system_exception_handler = handler; + system_exception_behaviour = behaviour; +} + +utils::RefPtr GetSystemExceptionHandler() { + AutoLock lock(&system_exception_mutex); + return system_exception_handler; +} + +bool magenta_rights_check(mx_rights_t actual, mx_rights_t desired) { + if ((actual & desired) == desired) + return true; + LTRACEF("rights check fail!! has 0x%x, needs 0x%x\n", actual, desired); + return false; +} + +static int cmd_magenta(int argc, const cmd_args* argv) { + int rc = 0; + + if (argc < 2) { + notenoughargs: + printf("not enough arguments:\n"); + usage: + printf("%s ps : list processes\n", argv[0].str); + return -1; + } + + if (!strcmp(argv[1].str, "ps")) { + DebugDumpProcessList(); + } else { + printf("unrecognized subcommand\n"); + goto usage; + } + return rc; +} + +LK_INIT_HOOK(magenta, magenta_init, LK_INIT_LEVEL_THREADING); + +STATIC_COMMAND_START +STATIC_COMMAND("mx", "magenta information", &cmd_magenta) +STATIC_COMMAND_END(mx); diff --git a/kernel/lib/magenta/msg_pipe.cpp b/kernel/lib/magenta/msg_pipe.cpp new file mode 100644 index 000000000..35cb39a77 --- /dev/null +++ b/kernel/lib/magenta/msg_pipe.cpp @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#include +#include +#include +#include + +#include + +namespace { +size_t other_side(size_t side) { + return side ? 0u : 1u; +} + +void clean_list(utils::DoublyLinkedList* list) { + MessagePacket* msg; + do { + msg = list->pop_front(); + delete msg; + } while (msg); +} +} + +void MessagePacket::ReturnHandles() { + handles.reset(); +} + +MessagePacket::~MessagePacket() { + for (size_t ix = 0; ix != handles.size(); ++ix) { + handles[ix]->Close(); + DeleteHandle(handles[ix]); + } +} + +MessagePipe::MessagePipe() + : dispatcher_alive_{true, true} { + mutex_init(&lock_); +} + +MessagePipe::~MessagePipe() { + // No need to lock. We are single threaded and will not have new requests. + clean_list(&messages_[0]); + clean_list(&messages_[1]); +} + +void MessagePipe::OnDispatcherDestruction(size_t side) { + bool other_alive; + auto other = other_side(side); + + AutoLock lock(&lock_); + dispatcher_alive_[side] = false; + other_alive = dispatcher_alive_[other]; + + if (other_alive) + waiter_[other].Signal(MX_SIGNAL_PEER_CLOSED); +} + +status_t MessagePipe::Read(size_t side, utils::unique_ptr* msg) { + bool other_alive; + auto other = other_side(side); + + { + AutoLock lock(&lock_); + msg->reset(messages_[side].pop_front()); + other_alive = dispatcher_alive_[other]; + + if (messages_[side].is_empty()) { + waiter_[side].ClearSignal(MX_SIGNAL_READABLE); + } + } + + if (*msg) + return NO_ERROR; + return other_alive ? ERR_NO_MSG : ERR_BAD_STATE; +} + +status_t MessagePipe::Write(size_t side, utils::unique_ptr msg) { + auto other = other_side(side); + + AutoLock lock(&lock_); + bool other_alive = dispatcher_alive_[other]; + if (!other_alive) { + // |msg| will be destroyed but we want to keep the handles alive since + // the caller should put them back into the process table. + msg->ReturnHandles(); + return ERR_BAD_STATE; + } + + messages_[other].push_back(msg.release()); + + waiter_[other].Signal(MX_SIGNAL_READABLE); + return NO_ERROR; +} + +Waiter* MessagePipe::GetWaiter(size_t side) { + return &waiter_[side]; +} diff --git a/kernel/lib/magenta/msg_pipe_dispatcher.cpp b/kernel/lib/magenta/msg_pipe_dispatcher.cpp new file mode 100644 index 000000000..c2fc22f20 --- /dev/null +++ b/kernel/lib/magenta/msg_pipe_dispatcher.cpp @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#define LOCAL_TRACE 0 + +constexpr mx_rights_t kDefaultPipeRights = MX_RIGHT_TRANSFER | MX_RIGHT_READ | MX_RIGHT_WRITE; + +// static +status_t MessagePipeDispatcher::Create(utils::RefPtr* dispatcher0, + utils::RefPtr* dispatcher1, + mx_rights_t* rights) { + LTRACE_ENTRY; + + utils::RefPtr pipe = utils::AdoptRef(new MessagePipe()); + if (!pipe) return ERR_NO_MEMORY; + + Dispatcher* msgp0 = new MessagePipeDispatcher(0u, pipe); + if (!msgp0) return ERR_NO_MEMORY; + + Dispatcher* msgp1 = new MessagePipeDispatcher(1u, pipe); + if (!msgp1) return ERR_NO_MEMORY; + + *rights = kDefaultPipeRights; + *dispatcher0 = utils::AdoptRef(msgp0); + *dispatcher1 = utils::AdoptRef(msgp1); + return NO_ERROR; +} + +MessagePipeDispatcher::MessagePipeDispatcher(size_t side, utils::RefPtr pipe) + : side_(side), pipe_(utils::move(pipe)) { + mutex_init(&lock_); +} + +MessagePipeDispatcher::~MessagePipeDispatcher() { + pipe_->OnDispatcherDestruction(side_); +} + +void MessagePipeDispatcher::Close(Handle* handle) { + LTRACE_ENTRY; + pipe_->GetWaiter(side_)->CloseHandle(handle); +} + +Waiter* MessagePipeDispatcher::BeginWait(event_t* event, Handle* handle, mx_signals_t signals) { + LTRACE_ENTRY; + return pipe_->GetWaiter(side_)->BeginWait(event, handle, signals); +} + +status_t MessagePipeDispatcher::BeginRead(uint32_t* message_size, uint32_t* handle_count) { + LTRACE_ENTRY; + // Note that a second thread can arrive here before the first thread + // calls AcceptRead(). Both threads now race to retrieve this message. + status_t result; + { + AutoLock lock(&lock_); + result = pending_ ? NO_ERROR : pipe_->Read(side_, &pending_); + if (result == NO_ERROR) { + *message_size = static_cast(pending_->data.size()); + *handle_count = static_cast(pending_->handles.size()); + } + } + return result; +} + +status_t MessagePipeDispatcher::AcceptRead(utils::Array* data, + utils::Array* handles) { + LTRACE_ENTRY; + + utils::unique_ptr msg; + { + AutoLock lock(&lock_); + msg = utils::move(pending_); + // if there is no message it means another user thread beat us here. + if (!msg) return ERR_NO_MSG; + + *data = utils::move(msg->data); + *handles = utils::move(msg->handles); + } + return NO_ERROR; +} + +status_t MessagePipeDispatcher::Write(utils::Array data, utils::Array handles) { + LTRACE_ENTRY; + utils::unique_ptr msg( + new MessagePacket{nullptr, nullptr, utils::move(data), utils::move(handles)}); + if (!msg) return ERR_NO_MEMORY; + + return pipe_->Write(side_, utils::move(msg)); +} diff --git a/kernel/lib/magenta/pci_device_dispatcher.cpp b/kernel/lib/magenta/pci_device_dispatcher.cpp new file mode 100644 index 000000000..20330784e --- /dev/null +++ b/kernel/lib/magenta/pci_device_dispatcher.cpp @@ -0,0 +1,286 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +constexpr mx_rights_t kDefaultPciDeviceRights = + MX_RIGHT_READ | MX_RIGHT_WRITE | MX_RIGHT_DUPLICATE | MX_RIGHT_TRANSFER; + +static const pcie_driver_fn_table_t PCIE_FN_TABLE = { + .pcie_probe_fn = nullptr, + .pcie_startup_fn = nullptr, + .pcie_shutdown_fn = nullptr, + .pcie_release_fn = nullptr, +}; + +static const pcie_driver_registration_t PCIE_DRIVER_REGISTRATION = { + .name = "userspace PCI driver", .fn_table = &PCIE_FN_TABLE, +}; + +status_t PciDeviceDispatcher::Create(uint32_t index, + mx_pcie_get_nth_info_t* out_info, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights) { + pcie_device_state_t* device = pci_get_nth_device(index); + if (!device) + return ERR_OUT_OF_RANGE; + + status_t status; + utils::RefPtr device_wrapper; + + status = PciDeviceWrapper::Create(device, &device_wrapper); + if (status != NO_ERROR) + return status; + + DEBUG_ASSERT(device_wrapper); + auto disp = new PciDeviceDispatcher(device_wrapper, out_info); + if (!disp) + return ERR_NO_MEMORY; + + *out_dispatcher = utils::AdoptRef(disp); + *out_rights = kDefaultPciDeviceRights; + return NO_ERROR; +} + +PciDeviceDispatcher::PciDeviceDispatcher(utils::RefPtr device, + mx_pcie_get_nth_info_t* out_info) + : device_(device) { + mutex_init(&lock_); + + const pcie_common_state_t& common = device_->device()->common; + const pcie_config_t* cfg = common.cfg; + DEBUG_ASSERT(cfg); + + out_info->vendor_id = pcie_read16(&cfg->base.vendor_id); + out_info->device_id = pcie_read16(&cfg->base.device_id); + out_info->base_class = pcie_read8 (&cfg->base.base_class); + out_info->sub_class = pcie_read8 (&cfg->base.sub_class); + out_info->program_interface = pcie_read8 (&cfg->base.program_interface); + out_info->revision_id = pcie_read8 (&cfg->base.revision_id_0); + out_info->bus_id = static_cast(common.bus_id); + out_info->dev_id = static_cast(common.dev_id); + out_info->func_id = static_cast(common.func_id); +} + +PciDeviceDispatcher::~PciDeviceDispatcher() { + // By the time that we destruct, we should have been formally closed. + DEBUG_ASSERT(!device_); +} + +void PciDeviceDispatcher::Close(Handle* handle) { + // Release our reference to the underlying PCI device state to indicate that + // we are now closed. + AutoLock lock(&lock_); + device_ = nullptr; +} + +status_t PciDeviceDispatcher::ClaimDevice() { + status_t result; + AutoLock lock(&lock_); + + if (!device_) return ERR_BAD_HANDLE; // Are we closed already? + if (device_->claimed()) return ERR_BUSY; // Are we claimed already? + + // TODO(johngro) : Lifetime management issues regarding interactions between + // PCIe bus driver level objects and this dispatcher need to be addressed. + // Specifially, if a device were to spontaniously shutdown (hot-unplug + // event) and call back through the driver shutdown hook, Bad Things could + // happen if there was a user mode thread currently attempting to interact + // with the device. See Bug #MG-65 + result = device_->Claim(); + if (result != NO_ERROR) + return result; + + // TODO(johngro) : Move the process of negotiating the IRQ mode, allocation + // and sharing disposition up to the user-mode driver. + // + // Query the device to figure out which IRQ modes it supports, then pick a + // mode and claim our vectors. + pcie_irq_mode_caps_t mode_caps; + + // Does this device support MSI? If so, choose this as the mode and attempt + // to grab as many vectors as we can get away with. + result = pcie_query_irq_mode_capabilities(&device_->device()->common, + PCIE_IRQ_MODE_MSI, + &mode_caps); + if (result == NO_ERROR) { + while (mode_caps.max_irqs) { + result = pcie_set_irq_mode(&device_->device()->common, + PCIE_IRQ_MODE_MSI, + mode_caps.max_irqs, + PCIE_IRQ_SHARE_MODE_EXCLUSIVE); + + if (result == NO_ERROR) { + irqs_supported_ = mode_caps.max_irqs; + irqs_maskable_ = mode_caps.per_vector_masking_supported; + break; + } + + mode_caps.max_irqs >>= 1; + } + } + + // If MSI didn't end up working out for us, try for Legacy mode. + if (!irqs_supported_) { + result = pcie_set_irq_mode(&device_->device()->common, + PCIE_IRQ_MODE_LEGACY, + 1, + PCIE_IRQ_SHARE_MODE_SYSTEM_SHARED); + if (result == NO_ERROR) { + irqs_supported_ = 1; + irqs_maskable_ = true; + } + } + + return NO_ERROR; +} + +status_t PciDeviceDispatcher::EnableBusMaster(bool enable) { + AutoLock lock(&lock_); + + if (!device_) return ERR_BAD_HANDLE; // Are we closed already? + if (!device_->claimed()) return ERR_BAD_STATE; // Are we not claimed yet? + + pcie_enable_bus_master(device_->device(), enable); + + return NO_ERROR; +} + +status_t PciDeviceDispatcher::ResetDevice() { + // TODO(johngro) : Either remove this from the API, or implement it as function level reset. + return ERR_NOT_IMPLEMENTED; +} + +status_t PciDeviceDispatcher::MapConfig(utils::RefPtr* out_mapping, + mx_rights_t* out_rights) { + AutoLock lock(&lock_); + return PciIoMappingDispatcher::Create(device_, + "cfg", + device_->device()->common.cfg_phys, + PCIE_EXTENDED_CONFIG_SIZE, + 0 /* vmm flags */, + ARCH_MMU_FLAG_UNCACHED_DEVICE | + ARCH_MMU_FLAG_PERM_RO | + ARCH_MMU_FLAG_PERM_NO_EXECUTE | + ARCH_MMU_FLAG_PERM_USER, + out_mapping, + out_rights); +} + +status_t PciDeviceDispatcher::MapMmio(uint32_t bar_num, + uint32_t cache_policy, + utils::RefPtr* out_mapping, + mx_rights_t* out_rights) { + AutoLock lock(&lock_); + if (!device_) return ERR_BAD_HANDLE; // Are we closed already? + if (!device_->claimed()) return ERR_BAD_STATE; // Are we not claimed yet? + + status_t status; + status = PciIoMappingDispatcher::CreateBarMapping(device_, + bar_num, + 0 /* vmm flags */, + cache_policy, + out_mapping, + out_rights); + + // If things went well, make sure that mmio is turned on + if (status == NO_ERROR) + pcie_enable_mmio(device_->device(), true); + + return status; +} + +status_t PciDeviceDispatcher::MapInterrupt(int32_t which_irq, + utils::RefPtr* interrupt_dispatcher, + mx_rights_t* rights) { + AutoLock lock(&lock_); + + if (!device_) return ERR_BAD_HANDLE; // Are we closed already? + if (!device_->claimed()) return ERR_BAD_STATE; // Are we not claimed yet? + if ((which_irq < 0) || + (static_cast(which_irq) >= irqs_supported_)) return ERR_INVALID_ARGS; + + // Attempt to create the dispatcher. It will take care of things like checking for + // duplicate registration. + return PciInterruptDispatcher::Create(device_, + which_irq, + irqs_maskable_, + rights, + interrupt_dispatcher); +} + +PciDeviceDispatcher::PciDeviceWrapper::PciDeviceWrapper(pcie_device_state_t* device) + : device_(device) { + DEBUG_ASSERT(device_); + mutex_init(&cp_ref_lock_); + memset(&cp_refs_, 0, sizeof(cp_refs_)); +} + +PciDeviceDispatcher::PciDeviceWrapper::~PciDeviceWrapper() { + DEBUG_ASSERT(device_); + if (claimed_) + pcie_shutdown_device(device_); +} + +status_t PciDeviceDispatcher::PciDeviceWrapper::Claim() { + if (claimed_) + return ERR_BUSY; + + status_t result = pcie_claim_and_start_device(device_, &PCIE_DRIVER_REGISTRATION, NULL); + if (result != NO_ERROR) + return result; + + claimed_ = true; + + return NO_ERROR; +} + +status_t PciDeviceDispatcher::PciDeviceWrapper::Create( + pcie_device_state_t* device, + utils::RefPtr* out_device) { + if (!device || !out_device) + return ERR_INVALID_ARGS; + + *out_device = utils::AdoptRef(new PciDeviceWrapper(device)); + + return *out_device ? NO_ERROR : ERR_NO_MEMORY; +} + +status_t PciDeviceDispatcher::PciDeviceWrapper::AddBarCachePolicyRef(uint bar_num, + uint32_t cache_policy) { + AutoLock lock(&cp_ref_lock_); + + if (bar_num >= countof(cp_refs_)) + return ERR_INVALID_ARGS; + + CachePolicyRef& r = cp_refs_[bar_num]; + if (r.ref_count && (r.cache_policy != cache_policy)) + return ERR_BAD_STATE; + + r.ref_count++; + r.cache_policy = cache_policy; + + return NO_ERROR; +} + +void PciDeviceDispatcher::PciDeviceWrapper::ReleaseBarCachePolicyRef(uint bar_num) { + AutoLock lock(&cp_ref_lock_); + + CachePolicyRef& r = cp_refs_[bar_num]; + DEBUG_ASSERT(bar_num < countof(cp_refs_)); + DEBUG_ASSERT(r.ref_count); + + r.ref_count--; +} diff --git a/kernel/lib/magenta/pci_interrupt_dispatcher.cpp b/kernel/lib/magenta/pci_interrupt_dispatcher.cpp new file mode 100644 index 000000000..600e6007c --- /dev/null +++ b/kernel/lib/magenta/pci_interrupt_dispatcher.cpp @@ -0,0 +1,147 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +constexpr mx_rights_t kDefaultPciInterruptRights = MX_RIGHT_READ | MX_RIGHT_TRANSFER; + +PciInterruptDispatcher::PciInterruptDispatcher(uint32_t irq_id) + : irq_id_(irq_id) { + mutex_init(&wait_lock_); + mutex_init(&lock_); + event_init(&event_, false, EVENT_FLAG_AUTOUNSIGNAL); +} + +PciInterruptDispatcher::~PciInterruptDispatcher() { + event_destroy(&event_); + mutex_destroy(&lock_); + mutex_destroy(&wait_lock_); +} + +pcie_irq_handler_retval_t PciInterruptDispatcher::IrqThunk(struct pcie_common_state* dev, + uint irq_id, + void* ctx) { + DEBUG_ASSERT(ctx); + PciInterruptDispatcher* dispatcher = (PciInterruptDispatcher*)ctx; + + // Wake up any thread which has been waiting for us to fire. + event_signal(&dispatcher->event_, false); + + // Mask the IRQ at the PCIe hardware level if we can, and tell the kernel to + // trigger a reschedule event. + return PCIE_IRQRET_MASK_AND_RESCHED; +} + +status_t PciInterruptDispatcher::Create( + const utils::RefPtr& device, + uint32_t irq_id, + bool maskable, + mx_rights_t* out_rights, + utils::RefPtr* out_interrupt) { + // Sanity check our args + if (!device || !out_rights || !out_interrupt) + return ERR_INVALID_ARGS; + + // Attempt to allocate a new dispatcher wrapper. + PciInterruptDispatcher* interrupt_dispatcher = new PciInterruptDispatcher(irq_id); + utils::RefPtr dispatcher = utils::AdoptRef(interrupt_dispatcher); + if (!dispatcher) + return ERR_NO_MEMORY; + + // Attempt to register our dispatcher with the bus driver. + DEBUG_ASSERT(device->device()); + status_t result = pcie_register_irq_handler(&device->device()->common, + irq_id, + IrqThunk, + interrupt_dispatcher); + if (result != NO_ERROR) + return result; + + // Everything seems to have gone well. Stash reference to the underlying + // device in the dispatcher we just created, then transfer our reference to + // the dispatcher out parameter. + interrupt_dispatcher->device_ = device; + interrupt_dispatcher->maskable_ = maskable; + *out_interrupt = dispatcher; + *out_rights = kDefaultPciInterruptRights; + return NO_ERROR; +} + +void PciInterruptDispatcher::Close(Handle* handle) { + { + AutoLock lock(&lock_); + + // If we no longer have a reference to to the underlying PCI device, we + // are already closed and don't need to do anything else. + if (!device_) + return; + + // Start by unregistering our IRQ handler with the bus driver. + __UNUSED status_t ret; + ret = pcie_register_irq_handler(&device_->device()->common, irq_id_, NULL, NULL); + DEBUG_ASSERT(ret == NO_ERROR); // This should never fail. + + // Release our reference to our device in order to indicate that we are + // now closed, then leave the main lock. + device_ = nullptr; + } + + // Force signal our event one last time to make certain that anyone who + // might have been waiting on the IRQ has been released. + event_signal(&event_, true); +} + +status_t PciInterruptDispatcher::InterruptWait() { + // Obtain the main lock and make sure that we are not currently closed. + { + status_t result; + AutoLock lock(&lock_); + if (!device_) + return ERR_BAD_HANDLE; + + // Try to grab the wait_lock. If we can't, it's because someone is already + // waiting on the interrupt. Right now, we only support a single waiter at + // a time, so tell the user code that we are busy. + result = mutex_acquire_timeout(&wait_lock_, 0); + if (result != NO_ERROR) { + DEBUG_ASSERT(result == ERR_TIMED_OUT); + return ERR_BUSY; + } + + // If IRQ masking is supported, unmask the IRQ. If/when it fires, it + // will signal our event and then disable itself. + if (maskable_) { + DEBUG_ASSERT(device_->device() && device_->claimed()); + result = pcie_unmask_irq(&device_->device()->common, irq_id_); + if (result != NO_ERROR) { + // Something went horribly wrong. Be sure to release the wait + // lock before we unwind our of the main lock and report our + // shameful failure to the caller. + mutex_release(&wait_lock_); + return result; + } + } + + // Fall out of the main AutoLock scope, releasing the main lock in the + // process. NOTE: we are still holding the wait lock. + } + + // Wait on our event while holding the wait lock. + event_wait(&event_); + + // Release the wait lock, then obtain the main lock and check to see if we + // were closed while waiting for the interrupt to fire. NOTE: it is very + // important to release the wait lock before attempting to acquire the main + // lock. Failure to do this can produce a lock ordering problem which will + // lead to deadlock. + mutex_release(&wait_lock_); + { + AutoLock lock(&lock_); + return device_ ? NO_ERROR : ERR_CANCELLED; + } +} diff --git a/kernel/lib/magenta/pci_io_mapping_dispatcher.cpp b/kernel/lib/magenta/pci_io_mapping_dispatcher.cpp new file mode 100644 index 000000000..b4913b962 --- /dev/null +++ b/kernel/lib/magenta/pci_io_mapping_dispatcher.cpp @@ -0,0 +1,126 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +status_t PciIoMappingDispatcher::Create( + const utils::RefPtr& device, + const char* dbg_tag, + paddr_t paddr, + size_t size, + uint vmm_flags, + uint arch_mmu_flags, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights) { + // Sanity check our args + if (!device || !out_rights || !out_dispatcher) + return ERR_INVALID_ARGS; + + // Attempt to allocate a new dispatcher wrapper. + PciIoMappingDispatcher* pim_disp = new PciIoMappingDispatcher(device); + if (!pim_disp) + return ERR_NO_MEMORY; + + // Create a debug name for the mapping. + char name[32]; + const pcie_common_state_t& c = device->device()->common; + snprintf(name, sizeof(name), "usr_pci_%s_%02x_%02x_%x", dbg_tag, c.bus_id, c.dev_id, c.func_id); + + // Initialize the mapping + utils::RefPtr disp = utils::AdoptRef(pim_disp); + status_t status = pim_disp->Init(name, paddr, size, vmm_flags, arch_mmu_flags); + if (status != NO_ERROR) + return status; + + // Success! Stash the results. + *out_dispatcher = disp; + *out_rights = IoMappingDispatcher::kDefaultRights; + return NO_ERROR; +} + +status_t PciIoMappingDispatcher::CreateBarMapping( + const utils::RefPtr& device, + uint bar_num, + uint vmm_flags, + uint cache_policy, + utils::RefPtr* out_dispatcher, + mx_rights_t* out_rights) { + // Sanity check our args + if (!device || !out_rights || !out_dispatcher) + return ERR_INVALID_ARGS; + + // Fetch our BAR info. + const pcie_bar_info_t* info = pcie_get_bar_info(&device->device()->common, bar_num); + if (!info) return ERR_INVALID_ARGS; + DEBUG_ASSERT(bar_num < PCIE_MAX_BAR_REGS); + + // Fail if this is a PIO windows instead of an MMIO window. For the time + // being, PIO accesses need to go through the specialized PIO API. + if (!info->is_mmio) return ERR_INVALID_ARGS; + + // Caller only gets to control the cache policy, nothing else. + if (cache_policy & ~ARCH_MMU_FLAG_CACHE_MASK) return ERR_INVALID_ARGS; + + // check to make sure the 64bit values will fit in arch-sized physical addresses and size + if (info->bus_addr > ULONG_MAX) return ERR_OUT_OF_RANGE; + if (info->size > SIZE_MAX) return ERR_OUT_OF_RANGE; + + // Attempt to mark this BAR as being mapped with the specified cache policy. + // While mapping a BAR multiple times is allowed, the cache policy must + // match each time. + status_t status = device->AddBarCachePolicyRef(bar_num, cache_policy); + if (status != NO_ERROR) + return status; + + // Create our debug tag + char tag[32]; + snprintf(tag, sizeof(tag), "bar%u", bar_num); + + // Go ahead and create the I/O Mapping object. If this fails, remember to + // release our cache policy reference. + status = Create(device, + tag, + static_cast(info->bus_addr), + static_cast(info->size), + 0 /* vmm flags */, + cache_policy | + ARCH_MMU_FLAG_PERM_NO_EXECUTE | + ARCH_MMU_FLAG_PERM_USER, + out_dispatcher, + out_rights); + + if (status != NO_ERROR) { + device->ReleaseBarCachePolicyRef(bar_num); + return status; + } + + // Success, record our BAR number in our I/O mapping object so that it will + // release its cache mode reference when it becomes closed. + DEBUG_ASSERT(out_dispatcher); + static_cast(out_dispatcher->get())->bar_num_ = bar_num; + return NO_ERROR; +} + +PciIoMappingDispatcher::~PciIoMappingDispatcher() { + // Just ASSERT that we have been closed already. + DEBUG_ASSERT(device_ == nullptr); +} + +void PciIoMappingDispatcher::Close(Handle* handle) { + // Close the underlying mapping; this will unmap the range from the user's process. + IoMappingDispatcher::Close(handle); + + // Now that we are unmapped, if this was a BAR mapping, be sure to release + // the reference to the cache policy we were holding. + if (bar_num_ < PCIE_MAX_BAR_REGS) { + device_->ReleaseBarCachePolicyRef(bar_num_); + bar_num_ = PCIE_MAX_BAR_REGS; + } + + device_ = nullptr; +} diff --git a/kernel/lib/magenta/process_owner_dispatcher.cpp b/kernel/lib/magenta/process_owner_dispatcher.cpp new file mode 100644 index 000000000..c9fd193ff --- /dev/null +++ b/kernel/lib/magenta/process_owner_dispatcher.cpp @@ -0,0 +1,58 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include + +constexpr mx_rights_t kDefaultProcessRights = MX_RIGHT_READ | MX_RIGHT_WRITE | MX_RIGHT_TRANSFER; + +status_t ProcessOwnerDispatcher::Create(utils::RefPtr* dispatcher, + mx_rights_t* rights, + utils::StringPiece name) { + utils::unique_ptr new_process(new UserProcess(name)); + if (!new_process) + return ERR_NO_MEMORY; + + status_t result = new_process->Initialize(); + if (result != NO_ERROR) + return result; + + *rights = kDefaultProcessRights; + *dispatcher = utils::AdoptRef(new ProcessOwnerDispatcher(utils::move(new_process))); + return (*dispatcher) ? NO_ERROR : ERR_NO_MEMORY; +} + +ProcessOwnerDispatcher::ProcessOwnerDispatcher(utils::unique_ptr process) + : process_(utils::move(process)) {} + +ProcessOwnerDispatcher::~ProcessOwnerDispatcher() {} + +void ProcessOwnerDispatcher::Close(Handle* handle) { + process_->Close(); +} + +Waiter* ProcessOwnerDispatcher::BeginWait(event_t* event, Handle* handle, mx_signals_t signals) { + return process_->GetWaiter()->BeginWait(event, handle, signals); +} + +status_t ProcessOwnerDispatcher::Start(mx_handle_t handle, mx_vaddr_t entry) { + return process_->Start(reinterpret_cast(handle), entry); +} + +mx_handle_t ProcessOwnerDispatcher::AddHandle(HandleUniquePtr handle) { + auto hv = process_->MapHandleToValue(handle.get()); + process_->AddHandle(utils::move(handle)); + return hv; +} + +status_t ProcessOwnerDispatcher::GetInfo(mx_process_info_t *info) { + return process_->GetInfo(info); +} + +status_t ProcessOwnerDispatcher::SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour) { + return process_->SetExceptionHandler(handler, behaviour); +} diff --git a/kernel/lib/magenta/rules.mk b/kernel/lib/magenta/rules.mk new file mode 100644 index 000000000..b1e2df537 --- /dev/null +++ b/kernel/lib/magenta/rules.mk @@ -0,0 +1,39 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/event_dispatcher.cpp \ + $(LOCAL_DIR)/exception.cpp \ + $(LOCAL_DIR)/futex_context.cpp \ + $(LOCAL_DIR)/futex_node.cpp \ + $(LOCAL_DIR)/handle.cpp \ + $(LOCAL_DIR)/interrupt_dispatcher.cpp \ + $(LOCAL_DIR)/io_mapping_dispatcher.cpp \ + $(LOCAL_DIR)/log_dispatcher.cpp \ + $(LOCAL_DIR)/magenta.cpp \ + $(LOCAL_DIR)/msg_pipe_dispatcher.cpp \ + $(LOCAL_DIR)/msg_pipe.cpp \ + $(LOCAL_DIR)/pci_device_dispatcher.cpp \ + $(LOCAL_DIR)/pci_interrupt_dispatcher.cpp \ + $(LOCAL_DIR)/pci_io_mapping_dispatcher.cpp \ + $(LOCAL_DIR)/process_owner_dispatcher.cpp \ + $(LOCAL_DIR)/thread_dispatcher.cpp \ + $(LOCAL_DIR)/user_copy.cpp \ + $(LOCAL_DIR)/user_process.cpp \ + $(LOCAL_DIR)/user_thread.cpp \ + $(LOCAL_DIR)/vm_object_dispatcher.cpp \ + $(LOCAL_DIR)/waiter.cpp \ + +MODULE_DEPS := \ + lib/utils \ + dev/udisplay \ + +include make/module.mk diff --git a/kernel/lib/magenta/thread_dispatcher.cpp b/kernel/lib/magenta/thread_dispatcher.cpp new file mode 100644 index 000000000..78752fc48 --- /dev/null +++ b/kernel/lib/magenta/thread_dispatcher.cpp @@ -0,0 +1,53 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include + +#define LOCAL_TRACE 0 + +constexpr mx_rights_t kDefaultThreadRights = + MX_RIGHT_READ | MX_RIGHT_DUPLICATE | MX_RIGHT_TRANSFER; + +// static +status_t ThreadDispatcher::Create(UserThread* thread, utils::RefPtr* dispatcher, + mx_rights_t* rights) { + Dispatcher* disp = new ThreadDispatcher(thread); + if (!disp) return ERR_NO_MEMORY; + + *rights = kDefaultThreadRights; + *dispatcher = utils::AdoptRef(disp); + return NO_ERROR; +} + +ThreadDispatcher::ThreadDispatcher(UserThread* thread) : thread_(thread) { + LTRACE_ENTRY; +} + +ThreadDispatcher::~ThreadDispatcher() { + LTRACE_ENTRY; + + // thread is effectively detached when there are no more handles referring to it + thread_->Detach(); +} + +Waiter* ThreadDispatcher::BeginWait(event_t* event, Handle* handle, mx_signals_t signals) { + return thread_->GetWaiter()->BeginWait(event, handle, signals); +} + +void ThreadDispatcher::Close(Handle* handle) {} + +status_t ThreadDispatcher::SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour) { + return thread_->SetExceptionHandler(handler, behaviour); +} + +status_t ThreadDispatcher::MarkExceptionHandled(mx_exception_status_t status) { + // TODO(dje): Verify thread is waiting. + thread_->WakeFromExceptionHandler(status); + return NO_ERROR; +} diff --git a/kernel/lib/magenta/user_copy.cpp b/kernel/lib/magenta/user_copy.cpp new file mode 100644 index 000000000..3b83a8fc4 --- /dev/null +++ b/kernel/lib/magenta/user_copy.cpp @@ -0,0 +1,51 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include + +status_t magenta_copy_from_user(const void* src, void* dest, size_t len) { + if (src == nullptr) return ERR_INVALID_ARGS; + status_t status = copy_from_user(dest, src, len); + if (status != NO_ERROR) { + return ERR_INVALID_ARGS; + } + return NO_ERROR; +} + +status_t magenta_copy_user_string(const char* src, size_t src_len, char* buf, size_t buf_len, + utils::StringPiece* sp) { + if (src_len > buf_len) return ERR_INVALID_ARGS; + + status_t result = magenta_copy_from_user(src, buf, src_len); + if (result != NO_ERROR) return result; + + // ensure zero termination + size_t str_len = (src_len == buf_len ? src_len - 1 : src_len); + buf[str_len] = 0; + *sp = utils::StringPiece(buf); + + return NO_ERROR; +} + +status_t magenta_copy_user_dynamic(const void* src, uint8_t** dest, size_t len, size_t max_len) { + *dest = nullptr; + + if (len > max_len) return ERR_INVALID_ARGS; + + auto buf = new uint8_t[len]; + if (!buf) return ERR_NO_MEMORY; + + status_t status = copy_from_user(buf, src, len); + if (status != NO_ERROR) { + delete[] buf; + return ERR_INVALID_ARGS; + } + *dest = buf; + return NO_ERROR; +} diff --git a/kernel/lib/magenta/user_process.cpp b/kernel/lib/magenta/user_process.cpp new file mode 100644 index 000000000..bc79b4d66 --- /dev/null +++ b/kernel/lib/magenta/user_process.cpp @@ -0,0 +1,310 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +UserProcess::UserProcess(utils::StringPiece name) + : next_thread_id_(1), + aspace_(nullptr), + state_(PROC_STATE_INITIAL), + retcode_(NO_ERROR), + exception_behaviour_(MX_EXCEPTION_BEHAVIOUR_DEFAULT), + prev_(nullptr), + next_(nullptr), + name_() { + LTRACE_ENTRY_OBJ; + + id_ = AddProcess(this); + + list_initialize(&thread_list_); + mutex_init(&thread_list_lock_); + mutex_init(&handle_table_lock_); + mutex_init(&state_lock_); + mutex_init(&exception_lock_); + + // Generate handle XOR mask with top bit and bottom two bits cleared + handle_rand_ = (rand() << 2) & INT_MAX; + + if (name.length() > 0 && (name.length() < sizeof(name_))) + strlcpy(name_, name.data(), sizeof(name_)); +} + +UserProcess::~UserProcess() { + LTRACE_ENTRY_OBJ; + + RemoveProcess(this); + + // clean up the handle table + LTRACEF_LEVEL(2, "cleaning up handle table on proc %p\n", this); + { + AutoLock lock(&handle_table_lock_); + while (handles_.first()) { + auto handle = handles_.pop_front(); + handle->Close(); + DeleteHandle(handle); + }; + } + LTRACEF_LEVEL(2, "done cleaning up handle table on proc %p\n", this); + + // tear down the address space + aspace_->Destroy(); + + mutex_destroy(&state_lock_); + mutex_destroy(&handle_table_lock_); + mutex_destroy(&thread_list_lock_); + + LTRACE_EXIT_OBJ; +} + +status_t UserProcess::Initialize() { + LTRACE_ENTRY_OBJ; + + // create an address space for this process. + aspace_ = VmAspace::Create(0, nullptr); + if (!aspace_) { + TRACEF("error creating address space\n"); + return ERR_NO_MEMORY; + } + + return NO_ERROR; +} + +void UserProcess::Close() { + LTRACE_ENTRY_OBJ; + + // TODO - we should kill all of our threads here, but no mechanism exists yet for that. + // So for now we block until all the threads have exited. + // After which, it will be safe to delete this object. + mutex_acquire(&thread_list_lock_); + + // Join all our running threads + list_node* node; + while ((node = list_remove_head(&thread_list_)) != nullptr) { + // need to release thread_list_lock_ before calling thread_join + mutex_release(&thread_list_lock_); + + UserThread* thread = containerof(node, UserThread, node_); + + LTRACEF_LEVEL(2, "processs %p waiting on thread %p\n", this, thread); + thread_join(&thread->thread_, nullptr, INFINITE_TIME); + LTRACEF_LEVEL(2, "processs %p done waiting on thread %p\n", this, thread); + + mutex_acquire(&thread_list_lock_); + + // need to reacquire before looking at joined_ and detached_ + thread->joined_ = true; + if (thread->detached_) delete thread; + } + + mutex_release(&thread_list_lock_); +} + +mx_handle_t UserProcess::MapHandleToValue(Handle* handle) { + auto handle_index = MapHandleToU32(handle) + 1; + return handle_index ^ handle_rand_; +} + +Handle* UserProcess::GetHandle_NoLock(mx_handle_t handle_value) { + auto handle_index = (handle_value ^ handle_rand_) - 1; + Handle* handle = MapU32ToHandle(handle_index); + if (!handle) + return nullptr; + return (handle->process_id() == id_) ? handle : nullptr; +} + +void UserProcess::AddHandle(HandleUniquePtr handle) { + AutoLock lock(&handle_table_lock_); + AddHandle_NoLock(utils::move(handle)); +} + +void UserProcess::AddHandle_NoLock(HandleUniquePtr handle) { + handle->set_process_id(id_); + handles_.push_front(handle.release()); +} + +HandleUniquePtr UserProcess::RemoveHandle(mx_handle_t handle_value) { + AutoLock lock(&handle_table_lock_); + return RemoveHandle_NoLock(handle_value); +} + +HandleUniquePtr UserProcess::RemoveHandle_NoLock(mx_handle_t handle_value) { + auto handle = GetHandle_NoLock(handle_value); + if (!handle) + return nullptr; + handles_.remove(handle); + handle->set_process_id(0u); + + return HandleUniquePtr(handle); +} + +void UserProcess::UndoRemoveHandle_NoLock(mx_handle_t handle_value) { + auto handle_index = (handle_value ^ handle_rand_) - 1; + Handle* handle = MapU32ToHandle(handle_index); + AddHandle_NoLock(HandleUniquePtr(handle)); +} + +bool UserProcess::GetDispatcher(mx_handle_t handle_value, utils::RefPtr* dispatcher, + uint32_t* rights) { + AutoLock lock(&handle_table_lock_); + Handle* handle = GetHandle_NoLock(handle_value); + if (!handle) + return false; + + *rights = handle->rights(); + *dispatcher = handle->dispatcher(); + return true; +} + +status_t UserProcess::Start(void* arg, mx_vaddr_t entry) { + LTRACE_ENTRY_OBJ; + + { + AutoLock lock(state_lock_); + + // make sure we're in the right state + if ((state_ != PROC_STATE_INITIAL) && (state_ != PROC_STATE_LOADED)) { + TRACEF("UserProcess has not been loaded\n"); + return ERR_BAD_STATE; + } + state_ = PROC_STATE_STARTING; + } + + if (entry) { + entry_ = (thread_start_routine)entry; + } + + status_t result; + // create the first thread + UserThread* t = new UserThread(this, entry_, arg); + if (!t) { + result = ERR_NO_MEMORY; + } else { + result = t->Initialize(utils::StringPiece("main thread")); + } + + { + AutoLock lock(state_lock_); + if (result == NO_ERROR) { + // we're ready to run now + state_ = PROC_STATE_RUNNING; + } else { + // to be safe, assume process is dead after failed start + Dead_NoLock(); + delete t; + return result; + } + } + + LTRACEF("starting main thread\n"); + t->Start(); + + // main thread has no handle, so it can be freed on join + ThreadDetached(t); + + return NO_ERROR; +} + +void UserProcess::Exit(int retcode) { + LTRACE_ENTRY_OBJ; + + { + AutoLock lock(state_lock_); + + retcode_ = retcode; + Dead_NoLock(); + } + + // TODO - kill our other threads here? + + UserThread::GetCurrent()->Exit(); +} + +void UserProcess::Kill() { + LTRACE_ENTRY_OBJ; + + AutoLock lock(state_lock_); + + Dead_NoLock(); + + // TODO - kill our other threads here +} + + +void UserProcess::AddThread(UserThread* t) { + LTRACE_ENTRY_OBJ; + + AutoLock lock(&thread_list_lock_); + list_add_head(&thread_list_, &t->node_); +} + +void UserProcess::ThreadDetached(UserThread* t) { + LTRACE_ENTRY_OBJ; + + AutoLock lock(&thread_list_lock_); + t->detached_ = true; + + if (t->joined_) + delete t; +} + +void UserProcess::Dead_NoLock() { + state_ = PROC_STATE_DEAD; + waiter_.Signal(MX_SIGNAL_SIGNALED); +} + +status_t UserProcess::GetInfo(mx_process_info_t *info) { + info->len = sizeof(mx_process_info_t); + + info->return_code = retcode_; + + return NO_ERROR; +} + +mx_tid_t UserProcess::GetNextThreadId() { + return atomic_add(&next_thread_id_, 1); +} + +status_t UserProcess::SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour) { + AutoLock lock(&exception_lock_); + + exception_handler_ = handler; + exception_behaviour_ = behaviour; + + return NO_ERROR; +} + +utils::RefPtr UserProcess::exception_handler() { + AutoLock lock(&exception_lock_); + return exception_handler_; +} + +uint32_t UserProcess::HandleCount() { + AutoLock lock(&handle_table_lock_); + return static_cast(handles_.size_slow()); +} + +uint32_t UserProcess::ThreadCount() { + AutoLock lock(&thread_list_lock_); + return static_cast(list_length(&thread_list_)); +} diff --git a/kernel/lib/magenta/user_thread.cpp b/kernel/lib/magenta/user_thread.cpp new file mode 100644 index 000000000..7cfc11338 --- /dev/null +++ b/kernel/lib/magenta/user_thread.cpp @@ -0,0 +1,176 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define LOCAL_TRACE 0 + +UserThread::UserThread(UserProcess* process, thread_start_routine entry, void* arg) + : process_(process), entry_(entry), arg_(arg), joined_(false), detached_(false), user_stack_(nullptr), + exception_behaviour_(MX_EXCEPTION_BEHAVIOUR_DEFAULT), + exception_status_(MX_EXCEPTION_STATUS_NOT_HANDLED) { + LTRACE_ENTRY_OBJ; + + id_ = process->GetNextThreadId(); + + list_clear_node(&node_); + mutex_init(&exception_lock_); + cond_init(&exception_wait_cond_); + mutex_init(&exception_wait_lock_); +} + +UserThread::~UserThread() { + LTRACE_ENTRY_OBJ; + + process_->aspace()->FreeRegion(reinterpret_cast(user_stack_)); + cond_destroy(&exception_wait_cond_); + mutex_destroy(&exception_wait_lock_); +} + +status_t UserThread::Initialize(utils::StringPiece name) { + LTRACE_ENTRY_OBJ; + + // Make sure we can hold process name and thread name combined. + static_assert((MX_MAX_NAME_LEN * 2) == THREAD_NAME_LENGTH, "name length issue"); + + char full_name[THREAD_NAME_LENGTH + 1]; + auto pname = process_->name(); + if ((pname.length() > 0) && (pname.length() < THREAD_NAME_LENGTH)) { + snprintf(full_name, sizeof(full_name), "%s:%s", pname.data(), name.data()); + } else { + snprintf(full_name, sizeof(full_name), ":%s", name.data()); + } + + // create an underlying LK thread + thread_t* lkthread = thread_create_etc(&thread_, full_name, StartRoutine, this, LOW_PRIORITY, + NULL, DEFAULT_STACK_SIZE); + + if (!lkthread) { + TRACEF("error creating thread\n"); + return ERR_NO_MEMORY; + } + DEBUG_ASSERT(lkthread == &thread_); + + // set the per-thread pointer + thread_.tls[TLS_ENTRY_LKUSER] = reinterpret_cast(this); + + // associate the proc's address space with this thread + process_->aspace()->AttachToThread(lkthread); + + return NO_ERROR; +} + +void UserThread::Start() { + LTRACE_ENTRY_OBJ; + + process_->AddThread(this); + thread_resume(&thread_); +} + +void UserThread::Exit() { + LTRACE_ENTRY_OBJ; + + waiter_.Signal(MX_SIGNAL_SIGNALED); + + thread_exit(0); +} + +void UserThread::Detach() { + LTRACE_ENTRY_OBJ; + + process_->ThreadDetached(this); +} + +int UserThread::StartRoutine(void* arg) { + LTRACE_ENTRY; + + UserThread* t = (UserThread*)arg; + + // create a user stack for the new thread + auto err = t->process_->aspace()->Alloc("user stack", kDefaultStackSize, &t->user_stack_, PAGE_SIZE_SHIFT, 0, + ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_NO_EXECUTE); + LTRACEF("alloc returns %d, stack at %p\n", err, t->user_stack_); + + LTRACEF("arch_enter_uspace SP: %p PC: %p\n", t->user_stack_, t->entry_); + // switch to user mode and start the process + arch_enter_uspace(reinterpret_cast(t->entry_), + reinterpret_cast(t->user_stack_) + kDefaultStackSize, t->arg_); + + __UNREACHABLE; +} + +status_t UserThread::SetExceptionHandler(utils::RefPtr handler, mx_exception_behaviour_t behaviour) { + AutoLock lock(&exception_lock_); + + exception_handler_ = handler; + exception_behaviour_ = behaviour; + + return NO_ERROR; +} + +utils::RefPtr UserThread::exception_handler() { + AutoLock lock(&exception_lock_); + return exception_handler_; +} + +static status_t send_exception_report(utils::RefPtr dispatcher, const mx_exception_report_t* report) { + LTRACE_ENTRY; + + utils::Array data; + utils::Array handles; + + uint8_t* report_bytes = new uint8_t[sizeof(*report)]; + memcpy(report_bytes, report, sizeof(*report)); + data.reset(report_bytes, sizeof(*report)); + + // TODO(cpu): We should rather deal RefPtr in the exception code. + auto message_pipe = dispatcher->get_message_pipe_dispatcher(); + DEBUG_ASSERT(message_pipe); + + status_t status = message_pipe->Write(utils::move(data), utils::move(handles)); + if (status != NO_ERROR) + LTRACEF("dispatcher->Write returned %d\n", status); + return status; +} + +status_t UserThread::WaitForExceptionHandler(utils::RefPtr dispatcher, const mx_exception_report_t* report) { + LTRACE_ENTRY_OBJ; + AutoLock lock(&exception_wait_lock_); + // Status if handler disappears. + exception_status_ = MX_EXCEPTION_STATUS_NOT_HANDLED; + // Send message, wait for reply. + status_t status = send_exception_report(dispatcher, report); + if (status != NO_ERROR) { + LTRACEF("send_exception_report returned %d\n", status); + return status; + } + status = cond_wait_timeout(&exception_wait_cond_, &exception_wait_lock_, INFINITE_TIME); + DEBUG_ASSERT(status == NO_ERROR); + if (exception_status_ != MX_EXCEPTION_STATUS_RESUME) + return ERR_GENERIC; + return NO_ERROR; +} + +void UserThread::WakeFromExceptionHandler(mx_exception_status_t status) { + LTRACE_ENTRY_OBJ; + AutoLock lock(&exception_wait_lock_); + exception_status_ = status; + cond_signal(&exception_wait_cond_); +} diff --git a/kernel/lib/magenta/vm_object_dispatcher.cpp b/kernel/lib/magenta/vm_object_dispatcher.cpp new file mode 100644 index 000000000..92a969d80 --- /dev/null +++ b/kernel/lib/magenta/vm_object_dispatcher.cpp @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include + +#include +#include +#include + +constexpr mx_rights_t kDefaultVmoRights = + MX_RIGHT_DUPLICATE | MX_RIGHT_TRANSFER | MX_RIGHT_READ | MX_RIGHT_WRITE | MX_RIGHT_EXECUTE; + +status_t VmObjectDispatcher::Create(utils::RefPtr vmo, + utils::RefPtr* dispatcher, + mx_rights_t* rights) { + auto disp = new VmObjectDispatcher(utils::move(vmo)); + if (!disp) + return ERR_NO_MEMORY; + + *rights = kDefaultVmoRights; + *dispatcher = utils::AdoptRef(disp); + return NO_ERROR; +} + +VmObjectDispatcher::VmObjectDispatcher(utils::RefPtr vmo) + : vmo_(vmo) {} + +VmObjectDispatcher::~VmObjectDispatcher() {} + +void VmObjectDispatcher::Close(Handle* handle) { +} + +mx_ssize_t VmObjectDispatcher::Read(void* user_data, mx_size_t length, uint64_t offset) { + + size_t bytes_read; + status_t err = vmo_->ReadUser(user_data, offset, length, &bytes_read); + if (err < 0) + return err; + + return bytes_read; +} + +mx_ssize_t VmObjectDispatcher::Write(const void* user_data, mx_size_t length, uint64_t offset) { + + size_t bytes_written; + status_t err = vmo_->WriteUser(user_data, offset, length, &bytes_written); + if (err < 0) + return err; + + return bytes_written; +} + +mx_status_t VmObjectDispatcher::SetSize(uint64_t size) { + return vmo_->Resize(size); +} + +mx_status_t VmObjectDispatcher::GetSize(uint64_t* size) { + *size = vmo_->size(); + + return NO_ERROR; +} + +mx_status_t VmObjectDispatcher::Map(utils::RefPtr aspace, uint32_t vmo_rights, uint64_t offset, mx_size_t len, + uintptr_t* _ptr, uint32_t flags) { + DEBUG_ASSERT(aspace); + + // add magenta vm flags, test against rights, and convert to vmm flags + uint vmm_flags = 0; + if (flags & MX_VM_FLAG_FIXED) { + // TODO: test against right + vmm_flags |= VMM_FLAG_VALLOC_SPECIFIC; + } + + // TODO: test the following against rights on the process and vmo handle + uint arch_mmu_flags = ARCH_MMU_FLAG_PERM_USER; + switch (flags & (MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE)) { + case MX_VM_FLAG_PERM_READ: + arch_mmu_flags |= ARCH_MMU_FLAG_PERM_RO; + break; + case MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE: + // default flags + break; + case 0: // no way to express no permissions + case MX_VM_FLAG_PERM_WRITE: + // no way to express write only + return ERR_INVALID_ARGS; + } + + if ((flags & MX_VM_FLAG_PERM_EXECUTE) == 0) { + arch_mmu_flags |= ARCH_MMU_FLAG_PERM_NO_EXECUTE; + } + + auto status = aspace->MapObject(vmo_, "unnamed", offset, len, reinterpret_cast(_ptr), 0, vmm_flags, arch_mmu_flags); + if (status < 0) + return status; + + return status; +} diff --git a/kernel/lib/magenta/waiter.cpp b/kernel/lib/magenta/waiter.cpp new file mode 100644 index 000000000..13585df2c --- /dev/null +++ b/kernel/lib/magenta/waiter.cpp @@ -0,0 +1,123 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include + +#include +#include + +Waiter::Waiter() + : signals_(0u) { + mutex_init(&lock_); +} + +Waiter* Waiter::BeginWait(event_t* event, Handle* handle, mx_signals_t signals) { + auto node = new WaitNode{nullptr, event, handle, signals}; + if (!node) + return nullptr; + + { + AutoLock lock(&lock_); + nodes_.push_front(node); + + if (signals & signals_) + event_signal(event, true); + } + return this; +} + +mx_signals_t Waiter::FinishWait(event_t* event) { + WaitNode* node = nullptr; + { + AutoLock lock(&lock_); + node = utils::pop_if(&nodes_, [event](WaitNode* node) { + return (node->event == event); + }); + } + if (node) + delete node; + return signals_; +} + +bool Waiter::Signal(mx_signals_t signals) { + int wake_count = 0; + { + AutoLock lock(&lock_); + + auto prev = signals_; + signals_ |= signals; + + if (prev == signals_) + return false; + + wake_count = SignalComplete_NoLock(); + } + + if (wake_count) + thread_yield(); + + return true; +} + +void Waiter::ClearSignal(mx_signals_t signals) { + signals_ &= ~signals; +} + +void Waiter::Modify(mx_signals_t set_mask, mx_signals_t clear_mask) { + int wake_count = 0; + { + AutoLock lock(&lock_); + + auto prev = signals_; + signals_ = (signals_ & (~clear_mask)) | set_mask; + + if (prev == signals_) + return; + + wake_count = SignalComplete_NoLock(); + } + + if (wake_count) + thread_yield(); +} + +bool Waiter::Reset() { + AutoLock lock(&lock_); + utils::for_each(&nodes_, [](WaitNode* node) { + event_unsignal(node->event); + }); + return true; +} + +bool Waiter::CloseHandle(Handle* handle) { + int wake_count = 0; + { + AutoLock lock(&lock_); + + utils::for_each(&nodes_, [handle, &wake_count](WaitNode* node) { + if (node->handle == handle) + wake_count += event_signal_etc(node->event, false, ERR_CANCELLED); + }); + } + + if (wake_count) + thread_yield(); + + return true; +} + +int Waiter::SignalComplete_NoLock() { + int wake_count = 0; + + utils::for_each(&nodes_, [this, &wake_count](WaitNode* node) { + if (node->signals & this->signals_) + wake_count += event_signal_etc(node->event, false, NO_ERROR); + }); + return wake_count; +} diff --git a/kernel/lib/partition/BUILD.gn b/kernel/lib/partition/BUILD.gn new file mode 100644 index 000000000..c2ba15b03 --- /dev/null +++ b/kernel/lib/partition/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +config("enable_partition") { + if (enable_partition) { + defines = [ "WITH_LIB_PARTITION=1" ] + } else { + defines = [ "WITH_LIB_PARTITION=0" ] + } +} + +module("partition") { + public_configs = [ ":enable_partition" ] + sources = [ + "partition.c", + ] + deps = [ + "//kernel/lib/bio", + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/partition/partition.c b/kernel/lib/partition/partition.c new file mode 100644 index 000000000..50037847d --- /dev/null +++ b/kernel/lib/partition/partition.c @@ -0,0 +1,138 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +struct chs { + uint8_t c; + uint8_t h; + uint8_t s; +} __PACKED; + +struct mbr_part { + uint8_t status; + struct chs start; + uint8_t type; + struct chs end; + uint32_t lba_start; + uint32_t lba_length; +} __PACKED; + +static status_t validate_mbr_partition(bdev_t *dev, const struct mbr_part *part) +{ + /* check for invalid types */ + if (part->type == 0) + return -1; + /* check for invalid status */ + if (part->status != 0x80 && part->status != 0x00) + return -1; + + /* make sure the range fits within the device */ + if (part->lba_start >= dev->block_count) + return -1; + if ((part->lba_start + part->lba_length) > dev->block_count) + return -1; + + /* that's about all we can do, MBR has no other good way to see if it's valid */ + + return 0; +} + +int partition_publish(const char *device, off_t offset) +{ + int err = 0; + int count = 0; + + // clear any partitions that may have already existed + partition_unpublish(device); + + bdev_t *dev = bio_open(device); + if (!dev) { + printf("partition_publish: unable to open device\n"); + return -1; + } + + // get a dma aligned and padded block to read info + STACKBUF_DMA_ALIGN(buf, dev->block_size); + + /* sniff for MBR partition types */ + do { + int i; + + err = bio_read(dev, buf, offset, 512); + if (err < 0) + goto err; + + /* look for the aa55 tag */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + break; + + /* see if a partition table makes sense here */ + struct mbr_part part[4]; + memcpy(part, buf + 446, sizeof(part)); + +#if LK_DEBUGLEVEL >= INFO + dprintf(INFO, "mbr partition table dump:\n"); + for (i=0; i < 4; i++) { + dprintf(INFO, "\t%i: status 0x%hhx, type 0x%hhx, start 0x%x, len 0x%x\n", i, part[i].status, part[i].type, part[i].lba_start, part[i].lba_length); + } +#endif + + /* validate each of the partition entries */ + for (i=0; i < 4; i++) { + if (validate_mbr_partition(dev, &part[i]) >= 0) { + // publish it + char subdevice[128]; + + sprintf(subdevice, "%sp%d", device, i); + + err = bio_publish_subdevice(device, subdevice, part[i].lba_start, part[i].lba_length); + if (err < 0) { + dprintf(INFO, "error publishing subdevice '%s'\n", subdevice); + continue; + } + count++; + } + } + } while (0); + + bio_close(dev); + +err: + return (err < 0) ? err : count; +} + +int partition_unpublish(const char *device) +{ + int i; + int count; + bdev_t *dev; + char devname[512]; + + count = 0; + for (i=0; i < 16; i++) { + sprintf(devname, "%sp%d", device, i); + + dev = bio_open(devname); + if (!dev) + continue; + + bio_unregister_device(dev); + bio_close(dev); + count++; + } + + return count; +} + diff --git a/kernel/lib/partition/rules.mk b/kernel/lib/partition/rules.mk new file mode 100644 index 000000000..0dda59fcf --- /dev/null +++ b/kernel/lib/partition/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += lib/bio + +MODULE_SRCS += \ + $(LOCAL_DIR)/partition.c + +include make/module.mk diff --git a/kernel/lib/pool/BUILD.gn b/kernel/lib/pool/BUILD.gn new file mode 100644 index 000000000..1cb8d1011 --- /dev/null +++ b/kernel/lib/pool/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_pool_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("pool") { + public_configs = [ ":_pool_config" ] + public = [ + "include/lib/pool.h", + ] + sources = [ + "pool.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/pool/include/lib/pool.h b/kernel/lib/pool/include/lib/pool.h new file mode 100644 index 000000000..37e392cba --- /dev/null +++ b/kernel/lib/pool/include/lib/pool.h @@ -0,0 +1,157 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once +/** + * A generic pool allocator. + * + * This is an efficient (constant-time allocation and freeing) allocator for objects of a fixed size + * and alignment (typically, fixed type), based on a fixed-size object pool. + * + * The main API works with void* buffers and a couple of helper macros are used for a type-safe + * (well, as far as C can go with type safety) "templatization" of the pool for a specific object + * type. + * + * Typical usage: + * + * typedef struct { + * ... + * } foo_t; + * + * // "Specialize" the pool for type foo_t. + * #define FOO_POOL_STORAGE_SIZE(object_count) TYPED_POOL_STORAGE_SIZE(foo_t, object_count) + * #define FOO_POOL_STORAGE_ALIGN() TYPED_POOL_STORAGE_ALIGN(foo_t) + * #define DEFINE_FOO_POOL_STORAGE(name, count) DEFINE_TYPED_POOL_STORAGE(foo_t, name, count) + * #define FOO_POOL_INIT(pool, count, storage) TYPED_POOL_INIT(foo_t, pool, count, storage) + * #define FOO_POOL_ALLOC(pool) TYPED_POOL_ALLOC(foo_t, pool) + * #define FOO_POOL_FREE(pool, object) TYPED_POOL_FREE(foo_t, pool, object) + * + * // Allocate storage for a pool of 100 objects. + * DEFINE_FOO_POOL_STORAGE(foo_pool_storage, 100); + * + * // Alternatively, allocate storage some other way, using the FOO_POOL_STORAGE_SIZE() and + * // FOO_POOL_STORAGE_ALIGN() to determine the required size and alignment of the storage buffer. + * + * // Instantiate the pool. + * pool_t pool; + * FOO_POOL_INIT(&pool, 100, &foo_pool_storage); + * + * // Allocate a foo_t from the pool. + * foo_t * newfoo = FOO_POOL_ALLOC(&pool); + * + * if (!newfoo) { + * // Handle allocation failure. + * } else { + * // Use newfoo. + * ... + * // Free it. + * FOO_POOL_FREE(&pool, newfoo); + * } + */ + +#include +#include +#include + +__BEGIN_CDECLS + +/** + * Pool type. + */ +typedef struct { + // Private: + void *next_free; +} pool_t; + +/** + * Helper macro, not for public usage. + */ +#define _MAX(a,b) \ + ((a) > (b) ? (a) : (b)) + +/** + * Helper macro, not for public usage. + */ +#define _PAD(size, align) \ + (((size) + (align) - 1) / (align) * (align)) + +/** + * Calculates the required alignment for the pool storage given the size and alignment of the object + * type. + */ +#define POOL_STORAGE_ALIGN(object_size, object_align) \ + (_MAX(__alignof(void *), object_align)) + +/** + * Helper macro, not for public usage. + */ +#define POOL_PADDED_OBJECT_SIZE(object_size, object_align) \ + _PAD(_MAX(sizeof(void *), object_size), POOL_STORAGE_ALIGN(object_size, object_align)) + +/** + * Calculates the size of the pool storage given the size and alignment of the object type and the + * total number of objects in the pool. + */ +#define POOL_STORAGE_SIZE(object_size, object_align, object_count) \ + ((object_count) * POOL_PADDED_OBJECT_SIZE(object_size, object_align)) + +/** + * Convenience macro for static allocation of pool storage. + */ +#define DEFINE_POOL_STORAGE(name, object_size, object_align, object_count) \ + uint8_t name[POOL_STORAGE_SIZE(object_size, object_align, object_count)] \ + __attribute__((aligned(POOL_STORAGE_ALIGN(object_size, object_align)))) + +/** + * Initialize the pool object. + * Provided storage must be aligned to POOL_STORAGE_ALIGN(object_size, object_align) and of size of + * at least POOL_STORAGE_SIZE(object_size, object_align, object_count). + * The DEFINE_POOL_STORAGE(...) makes this process simple for cases when the storage is to be + * statically allocated. + */ +void pool_init(pool_t *pool, + size_t object_size, + size_t object_align, + size_t object_count, + void *storage); + +/** + * Allocate an object from the pool. + * Returns NULL if all pool objects are currently allocated. + * Otherwise, the return value is guarantee to be aligned at object_align and be at least of size + * object_size. + */ +void *pool_alloc(pool_t *pool); + +/** + * Free an object previously allocated with pool_alloc. + */ +void pool_free(pool_t *pool, void *object); + +/** + * This set of macros help in "specializing" the pool API to a specific object type. + * See example at the header of this file. + */ + +#define TYPED_POOL_STORAGE_SIZE(type, object_count) \ + POOL_STORAGE_SIZE(sizeof(type), __alignof(type), object_count) + +#define TYPED_POOL_STORAGE_ALIGN(type) \ + POOL_STORAGE_ALIGN(sizeof(type), __alignof(type)) + +#define DEFINE_TYPED_POOL_STORAGE(type, name, count) \ + DEFINE_POOL_STORAGE(name, sizeof(type), __alignof(type), count) + +#define TYPED_POOL_INIT(type, pool, count, storage) \ + pool_init(pool, sizeof(type), __alignof(type), count, storage) + +#define TYPED_POOL_ALLOC(type, pool) \ + ((type*) pool_alloc(pool)) + +#define TYPED_POOL_FREE(type, pool, object) \ + pool_free(pool, object) + +__END_CDECLS diff --git a/kernel/lib/pool/pool.c b/kernel/lib/pool/pool.c new file mode 100644 index 000000000..89d9482fc --- /dev/null +++ b/kernel/lib/pool/pool.c @@ -0,0 +1,48 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Ytai Ben-tsvi +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include + +void pool_init(pool_t *pool, + size_t object_size, + size_t object_align, + size_t object_count, + void *storage) +{ + assert(pool); + assert(!object_count || storage); + assert((intptr_t) storage % POOL_STORAGE_ALIGN(object_size, object_align) == 0); + + size_t offset = 0; + for (size_t i = 0; i < object_count; ++i) { + pool_free(pool, (uint8_t *) storage + offset); + offset += POOL_PADDED_OBJECT_SIZE(object_size, object_align); + } +} + +void *pool_alloc(pool_t *pool) +{ + assert(pool); + + void *result = pool->next_free; + if (!result) { + return NULL; + } + pool->next_free = *((void **) result); + return result; +} + +void pool_free(pool_t *pool, void *object) +{ + assert(pool); + assert(object); + + *((void **) object) = pool->next_free; + pool->next_free = object; +} diff --git a/kernel/lib/pool/rules.mk b/kernel/lib/pool/rules.mk new file mode 100644 index 000000000..7b7ade992 --- /dev/null +++ b/kernel/lib/pool/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/pool.c + +include make/module.mk diff --git a/kernel/lib/pool/test/pool_test.cc b/kernel/lib/pool/test/pool_test.cc new file mode 100644 index 000000000..fb2a59fa1 --- /dev/null +++ b/kernel/lib/pool/test/pool_test.cc @@ -0,0 +1,42 @@ +#include + +#include + +#define DEFINE_DOUBLE_POOL_STORAGE(name, count) DEFINE_TYPED_POOL_STORAGE(double, name, count) +#define DOUBLE_POOL_INIT(pool, count, storage) TYPED_POOL_INIT(double, pool, count, storage) +#define DOUBLE_POOL_ALLOC(pool) TYPED_POOL_ALLOC(double, pool) +#define DOUBLE_POOL_FREE(pool, object) TYPED_POOL_FREE(double, pool, object) + +TEST(Pool, Basic) { + pool_t pool; + DEFINE_DOUBLE_POOL_STORAGE(storage, 5); + DOUBLE_POOL_INIT(&pool, 3, storage); + + // First 3 allocations should succeed. + double * d0 = DOUBLE_POOL_ALLOC(&pool); + EXPECT_NE(nullptr, d0); + EXPECT_EQ(0, (intptr_t) d0 % __alignof(double)); + + double * d1 = DOUBLE_POOL_ALLOC(&pool); + EXPECT_NE(nullptr, d1); + EXPECT_EQ(0, (intptr_t) d1 % __alignof(double)); + + double * d2 = DOUBLE_POOL_ALLOC(&pool); + EXPECT_NE(nullptr, d2); + EXPECT_EQ(0, (intptr_t) d2 % __alignof(double)); + + // All objects need to be different. + EXPECT_NE(d1, d0); + EXPECT_NE(d2, d0); + EXPECT_NE(d2, d1); + + // Next allocation should fail. + double * d3 = DOUBLE_POOL_ALLOC(&pool); + EXPECT_EQ(nullptr, d3); + + // But after we free something it should succeed. + DOUBLE_POOL_FREE(&pool, d0); + d3 = DOUBLE_POOL_ALLOC(&pool); + EXPECT_NE(nullptr, d3); + EXPECT_EQ(0, (intptr_t) d3 % __alignof(double)); +} diff --git a/kernel/lib/pow2_range_allocator/BUILD.gn b/kernel/lib/pow2_range_allocator/BUILD.gn new file mode 100644 index 000000000..3a1b4b3db --- /dev/null +++ b/kernel/lib/pow2_range_allocator/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_pow2_range_allocator_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("pow2_range_allocator") { + public_configs = [ ":_pow2_range_allocator_config" ] + public = [ + "include/lib/pow2_range_allocator.h", + ] + sources = [ + "pow2_range_allocator.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/pow2_range_allocator/include/lib/pow2_range_allocator.h b/kernel/lib/pow2_range_allocator/include/lib/pow2_range_allocator.h new file mode 100644 index 000000000..c92856cbf --- /dev/null +++ b/kernel/lib/pow2_range_allocator/include/lib/pow2_range_allocator.h @@ -0,0 +1,110 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include +#include +#include +#include + +__BEGIN_CDECLS + +/** + * The pow2_range_allocator is a small utility library which partitions a set of + * ranges of integers into sub-ranges which are power of 2 in length and power + * of 2 aligned and then manages allocating and freeing the subranges for + * clients. It is responsible for breaking larger sub-regions into smaller ones + * as needed for allocation, and for merging sub-regions into larger sub-regions + * as needed during free operations. + * + * Its primary use is as a utility library for plaforms who need to manage + * allocating blocks MSI IRQ IDs on behalf of the PCI bus driver, but could (in + * theory) be used for other things). + */ + +typedef struct p2ra_state { + mutex_t lock; + struct list_node ranges; + struct list_node unused_blocks; + struct list_node allocated_blocks; + struct list_node* free_block_buckets; + uint bucket_count; +} p2ra_state_t; + +/** + * Initialize the state of a pow2 range allocator. + * + * @param state A pointer to the state structure to be initialized. + * @param max_alloc_size The maximum size of a single contiguous allocation. + * Must be a power of 2. + * + * @return A status code indicating the success or failure of the operation. + */ +status_t p2ra_init(p2ra_state_t* state, uint max_alloc_size); + +/** + * Free all of the state associated with a previously initialized pow2 range + * allocator. + * + * @param state A pointer to the state structure to be cleaned up. + */ +void p2ra_free(p2ra_state_t* state); + +/** + * Add a range of uints to the pool of ranges to be allocated. + * + * @param state A pointer to the state structure to add the range to. + * @param range_start The start of the uint range. + * @param range_len The length of the uint range. + * + * @return A status code incidcating the success or failure of the operation. + * Possible return values include + * ++ ERR_INVALID_ARGS range_len is zero, or would cause the range to wrap the + * maximum range of a uint. + * ++ ERR_ALREADY_EXISTS the specified range overlaps with a range already added + * to the allocator. + * ++ ERR_NO_MEMORY Not enough memory to allocate the bookkeeping required for + * managing the range. + */ +status_t p2ra_add_range(p2ra_state_t* state, uint range_start, uint range_len); + +/** + * Attempt to allocate a range of uints from the available sub-ranges. The + * sizeo the allocated range must be a power of 2, and if the allocation + * succeeds, it is guaranteed to be aligned on a power of 2 boundary matching it + * size. + * + * @param state A pointer to the state structure to allocate from. + * @param size The requested size of the region. + * @param out_range_start An out parameter which will hold the start of the + * allocated range upon success. + * + * @return A status code indicating the success or failure of the operation. + * Possible return values include + * ++ ERR_INVALID_ARGS Multiple reasons, including... + * ++ size is zero. + * ++ size is not a power of two. + * ++ out_range_start is NULL. + * ++ ERR_NO_RESOURCES No contiguous, aligned region could be found to satisfy + * the allocation request. + * ++ ERR_NO_MEMORY A region could be found, but memory required for bookkeeping + * could not be allocated. + */ +status_t p2ra_allocate_range(p2ra_state_t* state, uint size, uint* out_range_start); + +/** + * Free a range previously allocated using p2ra_allocate_range. + * + * @param state A pointer to the state structure to return the range to. + * @param range_start The start of the previously allocated range. + * @param size The size of the previously allocated range. + */ +void p2ra_free_range(p2ra_state_t* state, uint range_start, uint size); + +__END_CDECLS diff --git a/kernel/lib/pow2_range_allocator/pow2_range_allocator.c b/kernel/lib/pow2_range_allocator/pow2_range_allocator.c new file mode 100644 index 000000000..a0f3e68fd --- /dev/null +++ b/kernel/lib/pow2_range_allocator/pow2_range_allocator.c @@ -0,0 +1,400 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +typedef struct p2ra_block { + struct list_node node; + uint bucket; + uint start; +} p2ra_block_t; + +typedef struct p2ra_range { + struct list_node node; + uint start, len; +} p2ra_range_t; + +static inline p2ra_block_t* p2ra_get_unused_block(p2ra_state_t* state) { + DEBUG_ASSERT(state); + + if (!list_is_empty(&state->unused_blocks)) + return list_remove_head_type(&state->unused_blocks, p2ra_block_t, node); + + return (p2ra_block_t*)calloc(1, sizeof(p2ra_block_t)); +} + +static inline void p2ra_free_block_list(struct list_node* block_list) { + p2ra_block_t* block; + while ((block = list_remove_head_type(block_list, p2ra_block_t, node)) != NULL) + free(block); +} + +static inline void p2ra_free_range_list(struct list_node* range_list) { + p2ra_range_t* range; + while ((range = list_remove_head_type(range_list, p2ra_range_t, node)) != NULL) + free(range); +} + +static void p2ra_return_free_block(p2ra_state_t* state, + p2ra_block_t* block, + bool merge_allowed) { + DEBUG_ASSERT(state); + DEBUG_ASSERT(block); + DEBUG_ASSERT(block->bucket < state->bucket_count); + DEBUG_ASSERT(!list_in_list(&block->node)); + DEBUG_ASSERT(!(block->start & ((1u << block->bucket) - 1))); + + /* Return the block to its proper free bucket, sorted by base ID. Start by + * finding the block which should come after this block in the list. */ + struct list_node* l = &state->free_block_buckets[block->bucket]; + p2ra_block_t* after = list_peek_head_type(l, p2ra_block_t, node); + uint block_len = 1u << block->bucket; + + while (after) { + /* We do not allow ranges to overlap */ + __UNUSED uint after_len = 1u << after->bucket; + DEBUG_ASSERT((block->start >= (after->start + after_len)) || + (after->start >= (block->start + block_len))); + + if (after->start > block->start) { + list_add_before(&after->node, &block->node); + break; + } + + /* Advance the iterator */ + after = list_next_type(l, &after->node, p2ra_block_t, node); + } + + /* If no block comes after this one, it goes on the end of the list */ + if (!after) + list_add_tail(l, &block->node); + + /* Don't merge blocks in the largest bucket. */ + if (block->bucket + 1 == state->bucket_count) + return; + + /* Check to see if we should be merging this block into a larger aligned block. */ + p2ra_block_t* first; + p2ra_block_t* second; + if (block->start & ((block_len << 1) - 1)) { + /* Odd alignment. This might be the second block of a merge pair */ + second = block; + first = list_prev_type(l, &block->node, p2ra_block_t, node); + } else { + /* Even alignment. This might be the first block of a merge pair */ + first = block; + second = list_next_type(l, &block->node, p2ra_block_t, node); + } + + /* Do these chunks fit together? */ + if (first && second) { + uint first_len = 1u << first->bucket; + if ((first->start + first_len) == second->start) { + /* Assert that we are allowed to perform a merge. If the caller is + * not expecting us to have to merge anything, then there is a fatal + * bookkeeping error somewhere */ + DEBUG_ASSERT(merge_allowed); + DEBUG_ASSERT(first->bucket == second->bucket); + + /* Remove the two blocks' bookkeeping from their bucket */ + list_delete(&first->node); + list_delete(&second->node); + + /* Place one half of the bookkeeping back on the unused list */ + list_add_tail(&state->unused_blocks, &second->node); + + /* Reuse the other half to track the newly merged block, and place + * it in the next bucket size up. */ + first->bucket++; + p2ra_return_free_block(state, first, merge_allowed); + } + } +} + + +status_t p2ra_init(p2ra_state_t* state, uint max_alloc_size) { + if (!state) + return ERR_INVALID_ARGS; + + if (!max_alloc_size || !ispow2(max_alloc_size)) { + TRACEF("max_alloc_size (%u) is not an integer power of two!\n", max_alloc_size); + return ERR_INVALID_ARGS; + } + + /* Allocate the storage for our free buckets */ + state->bucket_count = log2_uint(max_alloc_size) + 1; + state->free_block_buckets = malloc(state->bucket_count * sizeof(state->free_block_buckets[0])); + if (!state->free_block_buckets) { + TRACEF("Failed to allocate storage for %u free bucket lists!\n", state->bucket_count); + return ERR_NO_MEMORY; + } + + /* Initialize the rest of our bookeeping */ + mutex_init(&state->lock); + list_initialize(&state->ranges); + list_initialize(&state->unused_blocks); + list_initialize(&state->allocated_blocks); + for (uint i = 0; i < state->bucket_count; ++i) + list_initialize(&state->free_block_buckets[i]); + + return NO_ERROR; +} + +void p2ra_free(p2ra_state_t* state) { + DEBUG_ASSERT(state); + DEBUG_ASSERT(state->bucket_count); + DEBUG_ASSERT(state->free_block_buckets); + DEBUG_ASSERT(list_is_empty(&state->allocated_blocks)); + + p2ra_free_range_list(&state->ranges); + p2ra_free_block_list(&state->unused_blocks); + p2ra_free_block_list(&state->allocated_blocks); + for (uint i = 0; i < state->bucket_count; ++i) + p2ra_free_block_list(&state->free_block_buckets[i]); + + mutex_destroy(&state->lock); + memset(state, 0, sizeof(*state)); +} + +status_t p2ra_add_range(p2ra_state_t* state, uint range_start, uint range_len) { + LTRACEF("Adding range [%u, %u]\n", range_start, range_start + range_len - 1); + + if (!state || + !range_len || + ((range_start + range_len) < range_start)) + return ERR_INVALID_ARGS; + + status_t ret = NO_ERROR; + p2ra_range_t* new_range = NULL; + struct list_node new_blocks; + list_initialize(&new_blocks); + + /* Enter the lock and check for overlap with pre-existing ranges */ + mutex_acquire(&state->lock); + + p2ra_range_t* range; + list_for_every_entry(&state->ranges, range, p2ra_range_t, node) { + if (((range->start >= range_start) && (range->start < (range_start + range_len))) || + ((range_start >= range->start) && (range_start < (range->start + range->len)))) { + TRACEF("Range [%u, %u] overlaps with existing range [%u, %u].\n", + range_start, range_start + range_len - 1, + range->start, range->start + range->len - 1); + ret = ERR_ALREADY_EXISTS; + goto finished; + } + } + + /* Allocate our range state */ + new_range = calloc(1, sizeof(*new_range)); + if (!new_range) { + ret = ERR_NO_MEMORY; + goto finished; + } + new_range->start = range_start; + new_range->len = range_len; + + /* Break the range we were given into power of two aligned chunks, and place + * them on the new blocks list to be added to the free-blocks buckets */ + DEBUG_ASSERT(state->bucket_count && state->free_block_buckets); + uint bucket = state->bucket_count - 1; + uint csize = (1u << bucket); + uint max_csize = csize; + while (range_len) { + /* Shrink the chunk size until it is aligned with the start of the + * range, and not larger than the number of irqs we have left. */ + bool shrunk = false; + while ((range_start & (csize - 1)) || (range_len < csize)) { + csize >>= 1; + bucket--; + shrunk = true; + } + + /* If we didn't need to shrink the chunk size, perhaps we can grow it + * instead. */ + if (!shrunk) { + uint tmp = csize << 1; + while ((tmp <= max_csize) && + (tmp <= range_len) && + (!(range_start & (tmp - 1)))) { + bucket++; + csize = tmp; + tmp <<= 1; + DEBUG_ASSERT(bucket < state->bucket_count); + } + } + + /* Break off a chunk of the range */ + DEBUG_ASSERT((1u << bucket) == csize); + DEBUG_ASSERT(bucket < state->bucket_count); + DEBUG_ASSERT(!(range_start & (csize - 1))); + DEBUG_ASSERT(csize <= range_len); + DEBUG_ASSERT(csize); + + p2ra_block_t* block = p2ra_get_unused_block(state); + if (!block) { + TRACEF("WARNING! Failed to allocate block bookkeeping with sub-range " + "[%u, %u] still left to track.\n", + range_start, range_start + range_len - 1); + ret = ERR_NO_MEMORY; + goto finished; + } + + block->bucket = bucket; + block->start = range_start; + list_add_tail(&new_blocks, &block->node); + + range_start += csize; + range_len -= csize; + } + + /* Looks like we managed to allocate everything we needed to. Go ahead and + * add all of our newly allocated bookkeeping to the state. */ + list_add_tail(&state->ranges, &new_range->node); + + p2ra_block_t* block; + while ((block = list_remove_head_type(&new_blocks, p2ra_block_t, node)) != NULL) + p2ra_return_free_block(state, block, false); + + +finished: + mutex_release(&state->lock); + + if (ret != NO_ERROR) { + if (new_range) { + DEBUG_ASSERT(!list_in_list(&new_range->node)); + free(new_range); + } + + p2ra_free_block_list(&new_blocks); + } + + return ret; +} + +status_t p2ra_allocate_range(p2ra_state_t* state, uint size, uint* out_range_start) { + if (!state || !out_range_start) + return ERR_INVALID_ARGS; + + if (!size || !ispow2(size)) { + TRACEF("Size (%u) is not an integer power of 2.\n", size); + return ERR_INVALID_ARGS; + } + + uint orig_bucket = log2_uint(size); + uint bucket = orig_bucket; + if (bucket >= state->bucket_count) { + TRACEF("Invalid size (%u). Valid sizes are integer powers of 2 from [1, %u]\n", + size, 1u << (state->bucket_count - 1)); + return ERR_INVALID_ARGS; + } + + /* Lock state during allocation */ + p2ra_block_t* block = NULL; + status_t ret = NO_ERROR; + mutex_acquire(&state->lock); + + /* Find the smallest sized chunk which can hold the allocation and is + * compatible with the requested addressing capabilities */ + while (bucket < state->bucket_count) { + block = list_remove_head_type(&state->free_block_buckets[bucket], p2ra_block_t, node); + if (block) + break; + bucket++; + } + + /* Nothing found, unlock and get out */ + if (!block) { + ret = ERR_NO_RESOURCES; + goto finished; + } + + /* Looks like we have a chunk which can satisfy this allocation request. + * Split it as many times as needed to match the requested size. */ + DEBUG_ASSERT(block->bucket == bucket); + DEBUG_ASSERT(bucket >= orig_bucket); + + while (bucket > orig_bucket) { + p2ra_block_t* split_block = p2ra_get_unused_block(state); + + /* If we failed to allocate bookkeeping for the split block, put the block + * we failed to split back into the free list (merging if required), + * then fail the allocation */ + if (!split_block) { + TRACEF("Failed to allocated free bookkeeping block when attempting to " + "split for allocation\n"); + p2ra_return_free_block(state, block, true); + ret = ERR_NO_MEMORY; + goto finished; + } + + DEBUG_ASSERT(bucket); + bucket--; + + /* Cut the first chunk in half */ + block->bucket = bucket; + + /* Fill out the bookkeeping for the second half of the chunk */ + split_block->start = block->start + (1u << block->bucket); + split_block->bucket = bucket; + + /* Return the second half of the chunk to the free pool */ + p2ra_return_free_block(state, split_block, false); + } + + /* Success! Mark the block as allocated and return the block to the user */ + list_add_head(&state->allocated_blocks, &block->node); + *out_range_start = block->start; + +finished: + mutex_release(&state->lock); + return ret; +} + +void p2ra_free_range(p2ra_state_t* state, uint range_start, uint size) { + DEBUG_ASSERT(state); + DEBUG_ASSERT(size && ispow2(size)); + + uint bucket = log2_uint(size); + + mutex_acquire(&state->lock); + + /* In a debug build, find the specific block being returned in the list of + * allocated blocks and use it as the bookkeeping for returning to the free + * bucket. Because this is an O(n) operation, and serves only as a sanity + * check, we only do this in debug builds. In release builds, we just grab + * any piece of bookkeeping memory off the allocated_blocks list and use + * that instead. */ + p2ra_block_t* block; +#if LK_DEBUGLEVEL > 1 + block = list_peek_head_type(&state->allocated_blocks, p2ra_block_t, node); + while (block) { + if ((block->start == range_start) && (block->bucket == bucket)) { + list_delete(&block->node); + break; + } + block = list_next_type(&state->allocated_blocks, &block->node, p2ra_block_t, node); + } + ASSERT(block); +#else + DEBUG_ASSERT(!list_is_empty(&state->allocated_bocks)); + block = list_remove_head_type(&state->allocated_blocks, p2ra_block_t, node); + block->start = range_start; + block->bucket = bucket; +#endif + + /* Return the block to the free buckets (merging as needed) and we are done */ + p2ra_return_free_block(state, block, true); + mutex_release(&state->lock); +} diff --git a/kernel/lib/pow2_range_allocator/rules.mk b/kernel/lib/pow2_range_allocator/rules.mk new file mode 100644 index 000000000..d726b80ea --- /dev/null +++ b/kernel/lib/pow2_range_allocator/rules.mk @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/pow2_range_allocator.c + +include make/module.mk diff --git a/kernel/lib/ptable/BUILD.gn b/kernel/lib/ptable/BUILD.gn new file mode 100644 index 000000000..a9f005e1d --- /dev/null +++ b/kernel/lib/ptable/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("ptable") { + sources = [ + "ptable.c", + ] + deps = [ + "//kernel/lib/bio", + "//kernel/lib/console", + "//third_party/lib/cksum", + ] +} diff --git a/kernel/lib/ptable/ptable.c b/kernel/lib/ptable/ptable.c new file mode 100644 index 000000000..2725f6d52 --- /dev/null +++ b/kernel/lib/ptable/ptable.c @@ -0,0 +1,920 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// Copyright (c) 2014, Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define PTABLE_MAGIC '1BTP' +#define PTABLE_MIN_ENTRIES 16 +#define PTABLE_PART_NAME "ptable" + +struct ptable_header { + uint32_t magic; + uint32_t crc32; /* (total ptable according to total_length, 0 where crc field is) */ + uint32_t generation; /* incremented by one every time its saved */ + uint32_t total_length; /* valid length of table, only covers entries that are used */ +}; + +struct ptable_mem_entry { + struct list_node node; + struct ptable_entry entry; +}; + +static struct ptable_state { + bdev_t *bdev; + uint32_t gen; + struct list_node list; +} ptable; + +#define PTABLE_HEADER_NUM_ENTRIES(header) (((header).total_length - sizeof(struct ptable_header)) / sizeof(struct ptable_entry)) +#define BAIL(__err) do { err = __err; goto bailout; } while (0) + +static inline size_t ptable_length(size_t entry_cnt) +{ + return sizeof(struct ptable_header) + (sizeof(struct ptable_entry) * entry_cnt); +} + +static status_t validate_entry(const struct ptable_entry *entry) +{ + if (entry->offset > entry->offset + entry->length) + return ERR_GENERIC; + if (entry->offset + entry->length > (uint64_t)ptable.bdev->total_size) + return ERR_GENERIC; + + uint i; + for (i = 0; i < sizeof(entry->name); i++) + if (entry->name[i] == 0) + break; + + if (!i || (i >= sizeof(entry->name))) + return ERR_GENERIC; + + return NO_ERROR; +} + +static status_t ptable_write(void) +{ + uint8_t *buf = NULL; + bdev_t *bdev = NULL; + ssize_t err = ERR_GENERIC; + + if (!ptable_found_valid()) + return ERR_NOT_MOUNTED; + + bdev = bio_open(PTABLE_PART_NAME); + if (!bdev) + return ERR_BAD_STATE; + + /* count the number of entries in the list and calculate the total size */ + size_t count = 0; + struct list_node *node; + list_for_every(&ptable.list, node) { + count++; + } + LTRACEF("%u entries\n", count); + size_t total_length = sizeof(struct ptable_header) + sizeof(struct ptable_entry) * count; + + /* can we fit our partition table in our ptable subdevice? */ + if (total_length > bdev->total_size) + BAIL(ERR_TOO_BIG); + + /* allocate a buffer to hold it */ + buf = malloc(total_length); + if (!buf) + BAIL(ERR_NO_MEMORY); + + /* fill in a default header */ + struct ptable_header *header = (struct ptable_header *)buf; + header->magic = PTABLE_MAGIC; + header->crc32 = 0; + header->generation = ptable.gen++; + header->total_length = total_length; + + /* start the crc calculation */ + header->crc32 = crc32(0, (void *)header, sizeof(*header)); + + /* start by writing the entries */ + size_t off = sizeof(struct ptable_header); + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + + memcpy(buf + off, entry, sizeof(struct ptable_entry)); + + /* update the header */ + header->crc32 = crc32(header->crc32, (void *)entry, sizeof(struct ptable_entry)); + + off += sizeof(struct ptable_entry); + } + + /* write it to the block device. If the device has an erase geometry, start + * by erasing the partition. + */ + if (bdev->geometry_count && bdev->geometry) { + /* This is a subdevice, it should have a homogeneous erase geometry */ + DEBUG_ASSERT(1 == bdev->geometry_count); + + ssize_t err = bio_erase(bdev, 0, bdev->total_size); + if (err != (ssize_t)bdev->total_size) { + LTRACEF("error %d erasing device\n", (int)err); + BAIL(ERR_IO); + } + } + + err = bio_write(bdev, buf, 0, total_length); + if (err < (ssize_t)total_length) { + LTRACEF("error %d writing data to device\n", (int)err); + BAIL(ERR_IO); + } + + LTRACEF("wrote ptable:\n"); + if (LOCAL_TRACE) + hexdump(buf, total_length); + + err = NO_ERROR; + +bailout: + if (bdev) + bio_close(bdev); + + free(buf); + + return err; +} + +static void ptable_init(uint level) +{ + memset(&ptable, 0, sizeof(ptable)); + list_initialize(&ptable.list); +} + +LK_INIT_HOOK(ptable, &ptable_init, LK_INIT_LEVEL_THREADING); + +static void ptable_unpublish(struct ptable_mem_entry *mentry) +{ + if (mentry) { + bdev_t *bdev; + + bdev = bio_open((char *)mentry->entry.name); + if (bdev) { + bio_unregister_device(bdev); + bio_close(bdev); + } + + if (list_in_list(&mentry->node)) + list_delete(&mentry->node); + + free(mentry); + } +} + +static void ptable_reset(void) +{ + /* walk through the partition list, clearing any entries */ + struct ptable_mem_entry *mentry; + struct ptable_mem_entry *temp; + list_for_every_entry_safe(&ptable.list, mentry, temp, struct ptable_mem_entry, node) { + ptable_unpublish(mentry); + } + + /* release our reference to our primary device */ + if (NULL != ptable.bdev) + bio_close(ptable.bdev); + + /* Reset initialize our bookkeeping */ + ptable_init(LK_INIT_LEVEL_THREADING); +} + +static void ptable_push_entry (struct ptable_mem_entry *mentry) +{ + DEBUG_ASSERT (mentry); + + // iterator for the list + struct ptable_mem_entry *it_mentry; + + // The ptable list must be ordered by offset, so let's find the correct + // spot for this entry + list_for_every_entry(&ptable.list, it_mentry, struct ptable_mem_entry, node) { + if (it_mentry->entry.offset > mentry->entry.offset) { + // push the entry and we are done ! + list_add_before(&it_mentry->node, &mentry->node); + // All done + return; + } + } + + // if we exist the loop, that means that the + // entry has not been added, let add it at the tail + list_add_tail(&ptable.list, &mentry->node); +} + +static status_t ptable_publish(const struct ptable_entry *entry) +{ + status_t err; + struct ptable_mem_entry *mentry = NULL; + + DEBUG_ASSERT(entry && ptable.bdev); + size_t block_mask = ((size_t)0x01 << ptable.bdev->block_shift) - 1; + + err = validate_entry(entry); + if (err < 0) { + LTRACEF("entry failed valid check\n"); + BAIL(ERR_NOT_FOUND); + } + + // Make sure the partition does not already exist. + const char *part_name = (const char *)entry->name; + err = ptable_find(part_name, 0); + if (err >= 0) { + LTRACEF("entry \"%s\" already exists\n", part_name); + BAIL(ERR_ALREADY_EXISTS); + } + + // make sure that the partition is aligned properly + if ((entry->offset & block_mask) || (entry->length & block_mask)) { + LTRACEF("Entry in parition (\"%s\") is misaligned " + "(off 0x%llx len 0x%llx blockmask 0x%zx\n", + part_name, entry->offset, entry->length, block_mask); + BAIL(ERR_BAD_STATE); + } + + // make sure that length is non-zero and does not wrap + if ((entry->offset + entry->length) <= entry->offset) { + LTRACEF("Bad offset/length 0x%llx/0x%llx\n", entry->offset, entry->length); + BAIL(ERR_INVALID_ARGS); + } + + // make sure entry can fit in the device + if ((entry->offset + entry->length) > (uint64_t)ptable.bdev->total_size) { + LTRACEF("outside of device\n"); + BAIL(ERR_INVALID_ARGS); + } + + /* create an in-memory copy and attempt to publish a subdevice for the + * partition + */ + mentry = calloc(1, sizeof(struct ptable_mem_entry)); + if (!mentry) { + LTRACEF("Out of memory\n"); + BAIL(ERR_NO_MEMORY); + } + + memcpy(&mentry->entry, entry, sizeof(struct ptable_entry)); + err = bio_publish_subdevice(ptable.bdev->name, part_name, + entry->offset >> ptable.bdev->block_shift, + entry->length >> ptable.bdev->block_shift); + if (err < 0) { + LTRACEF("Failed to publish subdevice for \"%s\"\n", part_name); + goto bailout; + } + + err = NO_ERROR; + +bailout: + /* If we failed to publish, clean up whatever we may have allocated. + * Otherwise, put our new entry on the in-memory list. + */ + if (err < 0) { + ptable_unpublish(mentry); + } else { + ptable_push_entry (mentry); + } + + return err; +} + +static off_t ptable_adjust_request_for_erase_geometry(uint64_t region_start, + uint64_t region_len, + uint64_t *plength, + bool alloc_end) +{ + DEBUG_ASSERT(plength && ptable.bdev); + + LTRACEF("[0x%llx, 0x%llx) len 0x%llx%s\n", + region_start, region_start + region_len, *plength, alloc_end ? " (alloc end)" : ""); + + uint64_t block_mask = ((uint64_t)0x1 << ptable.bdev->block_shift) - 1; + DEBUG_ASSERT(!(*plength & block_mask)); + DEBUG_ASSERT(!(region_start & block_mask)); + DEBUG_ASSERT(!(region_len & block_mask)); + + uint64_t region_end = region_start + region_len; + DEBUG_ASSERT(region_end >= region_start); + + // Can we fit in the region at all? + if (*plength > region_len) { + LTRACEF("Request too large for region (0x%llx > 0x%llx)\n", *plength, region_len); + return ERR_TOO_BIG; + } + + // If our block device does not have an erase geometry to obey, then great! + // No special modifications to the request are needed. Just determine the + // offset based on if we are allocating from the start or the end. + if (!ptable.bdev->geometry_count || !ptable.bdev->geometry) { + off_t ret = alloc_end ? (region_start + region_len - *plength) : region_start; + LTRACEF("No geometry; allocating at [0x%llx, 0x%llx)\n", ret, ret + *plength); + return ret; + } + + // Intersect each of the erase regions with the region being proposed and + // see if we can fit the allocation request in the intersection, after + // adjusting the intersection and requested length to multiples of and + // alligned to the erase block size. Test the geometries back-to-front + // instead of front-to-back if alloc_end has been reqeusted. + for (size_t i = 0; i < ptable.bdev->geometry_count; ++i) { + size_t geo_index = alloc_end ? (ptable.bdev->geometry_count - i - 1) : i; + const bio_erase_geometry_info_t *geo = ptable.bdev->geometry + geo_index; + uint64_t erase_mask = ((uint64_t)0x1 << geo->erase_shift) - 1; + + LTRACEF("Considering erase region [0x%llx, 0x%llx) (erase size 0x%zx)\n", + geo->start, geo->start + geo->size, geo->erase_size); + + // If the erase region and the allocation region do not intersect at + // all, just move on to the next region. + if (!bio_does_overlap(region_start, region_len, geo->start, geo->size)) { + LTRACEF("No overlap...\n"); + continue; + } + + // Compute the intersection of the request region with the erase region. + uint64_t erase_end = geo->start + geo->size; + uint64_t rstart = MAX(region_start, (uint64_t)geo->start); + uint64_t rend = MIN(region_end, erase_end); + + // Align to erase unit boundaries. Move the start of the intersected + // region up and the end of the intersected region down. + rstart = (rstart + erase_mask) & ~erase_mask; + rend = rend & ~erase_mask; + + // Round the requested length up to a multiple of the erase unit. + uint64_t length = (*plength + erase_mask) & ~erase_mask; + + LTRACEF("Trimmed and aligned request [0x%llx, 0x%llx) len 0x%llx%s\n", + rstart, rend, length, alloc_end ? " (alloc end)" : ""); + + // Is there enough space in the aligned intersection to hold the + // request? + uint64_t tmp = rstart + length; + if ((tmp < rstart) || (rend < tmp)) { + LTRACEF("Not enough space\n"); + continue; + } + + // Yay! We found space for this allocation! Adjust the requested + // length and return the approprate offset based on whether we want to + // allocate from the start or the end. + off_t ret; + *plength = length; + ret = alloc_end ? (rend - length) : rstart; + LTRACEF("Allocating at [0x%llx, 0x%llx) (erase_size 0x%zx)\n", + ret, ret + *plength, geo->erase_size); + return ret; + } + + // Looks like we didn't find a place to put this allocation. + LTRACEF("No location found!\n"); + return ERR_INVALID_ARGS; +} + +static off_t ptable_allocate(uint64_t *plength, uint flags) +{ + DEBUG_ASSERT(plength); + + if (!ptable.bdev) + return ERR_BAD_STATE; + + LTRACEF("length 0x%llx, flags 0x%x\n", *plength, flags); + + uint64_t block_mask = ((uint64_t)0x1 << ptable.bdev->block_shift) - 1; + uint64_t length = (*plength + block_mask) & ~block_mask; + off_t offset = ERR_NOT_FOUND; + bool alloc_end = 0 != (flags & FLASH_PTABLE_ALLOC_END); + + if (list_is_empty(&ptable.list)) { + /* If the ptable is empty, then we have the entire device to use for + * allocation. Apply the erase geometry and return the result. + */ + offset = ptable_adjust_request_for_erase_geometry(0, + ptable.bdev->total_size, + &length, + alloc_end); + goto done; + } + + const struct ptable_entry *lastentry = NULL; + struct ptable_mem_entry *mentry; + uint64_t region_start; + uint64_t region_len; + uint64_t test_len; + off_t test_offset; + + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + + // Figure out the region we are testing, then adjust the request + // based on the device erase geometry. + region_start = lastentry ? (lastentry->offset + lastentry->length): 0; + region_len = entry->offset - region_start; + DEBUG_ASSERT((int64_t)region_len >= 0); + + LTRACEF("Considering region [0x%llx, 0x%llx) between \"%s\" and \"%s\"\n", + region_start, + region_start + region_len, + lastentry ? (char *)lastentry->name : "", + entry->name); + lastentry = entry; + + // Don't bother with the region if it is of zero length + if (!region_len) + continue; + + test_len = length; + test_offset = ptable_adjust_request_for_erase_geometry(region_start, + region_len, + &test_len, + alloc_end); + + // If this region was no good, move onto the next one. + if (test_offset < 0) + continue; + + // We found a possible answer, go ahead and record it. If we are + // allocating from the front, then we are finished. If we are + // attempting to allocate from the back, keep looking to see if + // there are other (better) answers. + offset = test_offset; + length = test_len; + if (!alloc_end) + goto done; + } + + /* still looking... the final region to test goes from the end of the previous + * region to the end of the device. + */ + DEBUG_ASSERT(lastentry); /* should always have a valid tail */ + + region_start = lastentry->offset + lastentry->length; + region_len = ptable.bdev->total_size - region_start; + DEBUG_ASSERT((int64_t)region_len >= 0); + + if (region_len) { + LTRACEF("Considering region [0x%llx, 0x%llx) between \"%s\" and \"%s\"\n", + region_start, + region_start + region_len, + lastentry->name, + ""); + test_len = length; + test_offset = ptable_adjust_request_for_erase_geometry(region_start, + region_len, + &test_len, + alloc_end); + if (test_offset >= 0) { + offset = test_offset; + length = test_len; + } + } + +done: + if (offset < 0) { + LTRACEF("Failed to find a suitable region of at least length %llu (err %lld)\n", + *plength, offset); + } else { + LTRACEF("Found region for %lld byte request @[%lld, %lld)\n", + *plength, offset, offset + length); + *plength = length; + } + + return offset; +} + +static status_t ptable_allocate_at(off_t _offset, uint64_t *plength) +{ + if (!ptable.bdev) + return ERR_BAD_STATE; + + if ((_offset < 0) || !plength) + return ERR_INVALID_ARGS; + + /* to make life easier, get our offset into unsigned */ + uint64_t offset = (uint64_t)_offset; + + /* Make certain the request was aligned to a program block boundary, and + * adjust the length to be a multiple of program blocks in size. + */ + uint64_t block_mask = ((uint64_t)0x1 << ptable.bdev->block_shift) - 1; + if (offset & block_mask) + return ERR_INVALID_ARGS; + + *plength = (*plength + block_mask) & ~block_mask; + + /* Make sure the request is contained within the extent of the device + * itself. + */ + if (!bio_contains_range(0, ptable.bdev->total_size, offset, *plength)) + return ERR_INVALID_ARGS; + + /* Adjust the request base on the erase geometry. If the offset needs to + * move to accomadate the erase geometry, we cannot satisfy this request. + */ + uint64_t new_offset = ptable_adjust_request_for_erase_geometry(offset, + ptable.bdev->total_size - offset, + plength, + false); + if (new_offset != offset) + return ERR_INVALID_ARGS; + + /* Finally, check the adjusted request against all of the existing + * partitions. The final region may not overlap an of the existing + * partitions. + */ + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + + if (bio_does_overlap(offset, *plength, entry->offset, entry->length)) + return ERR_NOT_FOUND; + } + + // Success. + return NO_ERROR; +} + +status_t ptable_scan(const char *bdev_name, uint64_t offset) +{ + ssize_t err; + DEBUG_ASSERT(bdev_name); + + ptable_reset(); + + /* Open a reference to the main block device */ + ptable.bdev = bio_open(bdev_name); + if (NULL == ptable.bdev) { + LTRACEF("Failed to find device \"%s\"", bdev_name); + BAIL(ERR_NOT_FOUND); + } + + /* validate the header */ + struct ptable_header header; + + err = bio_read(ptable.bdev, &header, offset, sizeof(header)); + if (err < (ssize_t)sizeof(header)) { + LTRACEF("failed to read partition table header @%llu (%ld)\n", offset, err); + goto bailout; + } + + if (LOCAL_TRACE) + hexdump(&header, sizeof(struct ptable_header)); + + if (header.magic != PTABLE_MAGIC) { + LTRACEF("failed magic test\n"); + BAIL(ERR_NOT_FOUND); + } + if (header.total_length < sizeof(struct ptable_header)) { + LTRACEF("total length too short\n"); + BAIL(ERR_NOT_FOUND); + } + if (header.total_length > ptable.bdev->block_size) { + LTRACEF("total length too long\n"); + BAIL(ERR_NOT_FOUND); + } + if (((header.total_length - sizeof(struct ptable_header)) % sizeof(struct ptable_entry)) != 0) { + LTRACEF("total length not multiple of header + multiple of entry size\n"); + BAIL(ERR_NOT_FOUND); + } + + /* start a crc check by calculating the header */ + uint32_t crc; + uint32_t saved_crc = header.crc32; + header.crc32 = 0; + crc = crc32(0, (void *)&header, sizeof(header)); + header.crc32 = saved_crc; + bool found_ptable = false; + + /* read the entries into memory */ + off_t off = offset + sizeof(struct ptable_header); + for (uint i = 0; i < PTABLE_HEADER_NUM_ENTRIES(header); i++) { + struct ptable_entry entry; + + /* read the next entry off the device */ + err = bio_read(ptable.bdev, &entry, off, sizeof(entry)); + if (err < 0) { + LTRACEF("failed to read entry\n"); + goto bailout; + } + + LTRACEF("looking at entry:\n"); + if (LOCAL_TRACE) + hexdump(&entry, sizeof(entry)); + + /* Attempt to publish the entry */ + err = ptable_publish(&entry); + if (err < 0) { + goto bailout; + } + + /* If this was the "ptable" entry, was it in the right place? */ + if (!strncmp((char *)entry.name, PTABLE_PART_NAME, sizeof(entry.name))) { + found_ptable = true; + + if (entry.offset != offset) { + LTRACEF("\"ptable\" in the wrong location! (expected %lld got %lld)\n", + offset, entry.offset); + BAIL(ERR_BAD_STATE); + } + } + + /* append the crc */ + crc = crc32(crc, (void *)&entry, sizeof(entry)); + + /* Move on to the next entry */ + off += sizeof(struct ptable_entry); + } + + if (header.crc32 != crc) { + LTRACEF("failed crc check at the end (0x%08x != 0x%08x)\n", header.crc32, crc); + BAIL(ERR_CRC_FAIL); + } + + if (!found_ptable) { + LTRACEF("\"ptable\" partition not found\n"); + BAIL(ERR_NOT_FOUND); + } + + err = NO_ERROR; + +bailout: + if (err < 0) + ptable_reset(); + + return (status_t)err; +} + +bool ptable_found_valid(void) +{ + return (NULL != ptable.bdev); +} + +bdev_t *ptable_get_device(void) +{ + return ptable.bdev; +} + +status_t ptable_find(const char *name, struct ptable_entry *_entry) +{ + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + if (strcmp(name, (void *)entry->name) == 0) { + /* copy the entry to the passed in pointer */ + if (_entry) { + memcpy(_entry, entry, sizeof(struct ptable_entry)); + } + + return NO_ERROR; + } + } + + return ERR_NOT_FOUND; +} + +status_t ptable_create_default(const char *bdev_name, uint64_t offset) +{ + DEBUG_ASSERT(bdev_name); + + /* Reset the system */ + ptable_reset(); + ptable.bdev = bio_open(bdev_name); + if (!ptable.bdev) { + LTRACEF("Failed to open \"%s\"\n", bdev_name); + return ERR_NOT_FOUND; + } + + /* See if we can put the partition table partition at the requested + * location, and determine the size needed based on program block size and + * erase block geometry. + */ + uint64_t len = ptable_length(PTABLE_MIN_ENTRIES); + status_t err = ptable_allocate_at(offset, &len); + if (err < 0) { + LTRACEF("Failed to allocate partition of len 0x%llx @ 0x%llx (err %d)\n", + len, offset, err); + goto bailout; + } + + /* Publish the ptable partition */ + struct ptable_entry ptable_entry; + ptable_entry.offset = offset; + ptable_entry.length = len; + ptable_entry.flags = 0; + strncpy((char *)ptable_entry.name, PTABLE_PART_NAME, sizeof(ptable_entry.name)); + err = ptable_publish(&ptable_entry); + if (err < 0) { + LTRACEF("Failed to publish ptable partition\n"); + goto bailout; + } + + /* Commit the partition table to storage */ + err = ptable_write(); + if (err < 0) { + LTRACEF("Failed to commit ptable\n"); + goto bailout; + } + +bailout: + /* if we failed, reset the system. */ + if (err < 0) + ptable_reset(); + + return err; +} + +status_t ptable_remove(const char *name) +{ + DEBUG_ASSERT(ptable.bdev); + + LTRACEF("name %s\n", name); + + if (!ptable_found_valid()) + return ERR_NOT_MOUNTED; + + if (!name) + return ERR_INVALID_ARGS; + + if (!strcmp(name, "ptable")) + return ERR_NOT_ALLOWED; + + bool found = false; + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + if (strcmp(name, (void *)entry->name) == 0) { + ptable_unpublish(mentry); + found = true; + break; + } + } + + if (!found) + return ERR_NOT_FOUND; + + /* rewrite the page table */ + status_t err = ptable_write(); + return err; +} + +status_t ptable_add(const char *name, uint64_t min_len, uint32_t flags) +{ + LTRACEF("name %s min_len 0x%llx flags 0x%x\n", name, min_len, flags); + + if (!ptable_found_valid()) + return ERR_NOT_MOUNTED; + + /* see if the name is valid */ + if (strlen(name) > MAX_FLASH_PTABLE_NAME_LEN - 1) { + LTRACEF("Name too long\n"); + return ERR_INVALID_ARGS; + } + + // Find a place for the requested partition, adjust the length as needed + off_t part_loc = ptable_allocate(&min_len, flags); + if (part_loc < 0) { + LTRACEF("Failed to usable find location.\n"); + return (status_t)part_loc; + } + + /* Attempt to publish the partition */ + struct ptable_entry ptable_entry; + ptable_entry.offset = part_loc; + ptable_entry.length = min_len; + ptable_entry.flags = 0; + strncpy((char *)ptable_entry.name, name, sizeof(ptable_entry.name)); + status_t err = ptable_publish(&ptable_entry); + if (err < 0) { + LTRACEF("Failed to publish\n"); + return err; + } + + /* Commit the partition table */ + err = ptable_write(); + if (err < 0) { + LTRACEF("Failed to commit ptable\n"); + } + + return err; +} + +void ptable_dump(void) +{ + int i = 0; + struct ptable_mem_entry *mentry; + list_for_every_entry(&ptable.list, mentry, struct ptable_mem_entry, node) { + const struct ptable_entry *entry = &mentry->entry; + + printf("%d: %16s off 0x%016llx len 0x%016llx flags 0x%08x\n", + i, entry->name, entry->offset, entry->length, entry->flags); + i++; + } +} + +#if WITH_LIB_CONSOLE + +#include + +static int cmd_ptable(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage: %s scan \n", argv[0].str); + printf("usage: %s default \n", argv[0].str); + printf("usage: %s list\n", argv[0].str); + printf("usage: %s add \n", argv[0].str); + printf("usage: %s remove \n", argv[0].str); + printf("usage: %s alloc \n", argv[0].str); + printf("usage: %s allocend \n", argv[0].str); + printf("usage: %s write\n", argv[0].str); + return -1; + } + + status_t err; + if (!strcmp(argv[1].str, "scan")) { + if (argc < 4) goto notenoughargs; + status_t err = ptable_scan(argv[2].str, argv[3].u); + printf("ptable_scan returns %d\n", err); + } else if (!strcmp(argv[1].str, "default")) { + if (argc < 4) goto notenoughargs; + status_t err = ptable_create_default(argv[2].str, argv[3].u); + printf("ptable_create_default returns %d\n", err); + } else if (!strcmp(argv[1].str, "list")) { + ptable_dump(); + } else if (!strcmp(argv[1].str, "nuke")) { + bdev_t *ptable_dev = bio_open(PTABLE_PART_NAME); + + if (ptable_dev) { + status_t err; + err = bio_erase(ptable_dev, 0, ptable_dev->total_size); + if (err < 0) { + printf("ptable nuke failed (err %d)\n", err); + } else { + printf("ptable nuke OK\n"); + } + bio_close(ptable_dev); + } else { + printf("Failed to find ptable device\n"); + } + } else if (!strcmp(argv[1].str, "add")) { + if (argc < 5) goto notenoughargs; + err = ptable_add(argv[2].str, argv[3].u, argv[4].u); + if (err < NO_ERROR) + printf("ptable_add returns err %d\n", err); + } else if (!strcmp(argv[1].str, "remove")) { + if (argc < 3) goto notenoughargs; + ptable_remove(argv[2].str); + } else if (!strcmp(argv[1].str, "alloc") || + !strcmp(argv[1].str, "allocend")) { + if (argc < 3) goto notenoughargs; + + uint flags = !strcmp(argv[1].str, "allocend") ? FLASH_PTABLE_ALLOC_END : 0; + uint64_t len = argv[2].u; + off_t off = ptable_allocate(&len, flags); + + if (off < 0) { + printf("%s of 0x%lx failed (err %lld)\n", + argv[1].str, argv[2].u, off); + } else { + printf("%s of 0x%lx gives [0x%llx, 0x%llx)\n", + argv[1].str, argv[2].u, off, off + len); + } + } else if (!strcmp(argv[1].str, "write")) { + printf("ptable_write result %d\n", ptable_write()); + } else { + goto usage; + } + + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("ptable", "commands for manipulating the flash partition table", &cmd_ptable) +STATIC_COMMAND_END(ptable); + +#endif // WITH_LIB_CONSOLE + diff --git a/kernel/lib/ptable/rules.mk b/kernel/lib/ptable/rules.mk new file mode 100644 index 000000000..a427e0e4e --- /dev/null +++ b/kernel/lib/ptable/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/bio \ + lib/cksum + +MODULE_SRCS += \ + $(LOCAL_DIR)/ptable.c + +include make/module.mk diff --git a/kernel/lib/syscalls/BUILD.gn b/kernel/lib/syscalls/BUILD.gn new file mode 100644 index 000000000..34ae0ad10 --- /dev/null +++ b/kernel/lib/syscalls/BUILD.gn @@ -0,0 +1,37 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_syscalls_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +# TODO(phosek): this should be disabled if enable_userboot is false +module("syscalls") { + public_configs = [ ":_syscalls_config" ] + configs += [ "//kernel/lib/userboot:enable_userboot" ] + include_dirs = [ "//system/ulib/magenta/include" ] + sources = [ + "syscalls.cpp", + "syscalls_ddk.cpp", + "syscalls_debug.cpp", + "syscalls_exceptions.cpp", + "syscalls_magenta.cpp", + "syscalls_priv.h", + "syscalls_test.cpp", + ] + deps = [ + "//kernel/dev/interrupt", + "//kernel/dev/pcie", + "//kernel/dev/udisplay", + "//kernel/lib/console", + "//kernel/lib/debuglog", + "//kernel/lib/libc", + "//kernel/lib/magenta", + "//kernel/lib/user_copy", + "//kernel/lib/utils", + ] +} diff --git a/kernel/lib/syscalls/rules.mk b/kernel/lib/syscalls/rules.mk new file mode 100644 index 000000000..2642f9e5b --- /dev/null +++ b/kernel/lib/syscalls/rules.mk @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/console \ + lib/magenta \ + lib/user_copy \ + +MODULE_SRCS := \ + $(LOCAL_DIR)/syscalls.cpp \ + $(LOCAL_DIR)/syscalls_debug.cpp \ + $(LOCAL_DIR)/syscalls_ddk.cpp \ + $(LOCAL_DIR)/syscalls_exceptions.cpp \ + $(LOCAL_DIR)/syscalls_magenta.cpp \ + $(LOCAL_DIR)/syscalls_test.cpp \ + +include make/module.mk diff --git a/kernel/lib/syscalls/syscalls.cpp b/kernel/lib/syscalls/syscalls.cpp new file mode 100644 index 000000000..f9d94c8db --- /dev/null +++ b/kernel/lib/syscalls/syscalls.cpp @@ -0,0 +1,182 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "syscalls_priv.h" + +#define LOCAL_TRACE 0 + +int sys_invalid_syscall(void) { + LTRACEF("invalid syscall\n"); + return ERR_BAD_SYSCALL; +} + +#if ARCH_ARM + +using syscall_func = int64_t (*)(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, + uint32_t f, uint32_t g, uint32_t h); + +extern "C" void arm_syscall_handler(struct arm_fault_frame* frame) { + uint64_t ret = 0; + uint32_t syscall_num = frame->r[12]; + + /* check for magic value to differentiate our syscalls */ + if (unlikely((syscall_num & 0xf0f00000) != 0xf0f00000)) { + TRACEF("syscall does not have magenta magic, 0x%x @ PC 0x%x\n", syscall_num, frame->pc); + + ret = ERR_BAD_SYSCALL; + goto out; + } + syscall_num &= 0x000fffff; + + /* re-enable interrupts to maintain kernel preemptiveness */ + arch_enable_ints(); + + LTRACEF_LEVEL(2, "arm syscall: num 0x%x, pc 0x%x\n", syscall_num, frame->pc); + + /* build a function pointer to call the routine. + * the args are jammed into the function independent of if the function + * uses them or not, which is safe for simple arg passing. + */ + syscall_func sfunc; + + switch (syscall_num) { +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) \ + case n: \ + sfunc = reinterpret_cast(sys_##name); \ + break; +#include + default: + sfunc = reinterpret_cast(sys_invalid_syscall); + } + + /* call the routine */ + ret = sfunc(frame->r[0], frame->r[1], frame->r[2], frame->r[3], frame->r[4], + frame->r[5], frame->r[6], frame->r[7]); + + LTRACEF_LEVEL(2, "ret 0x%llx\n", ret); + +out: + /* unpack the 64bit return back into r0 and r1 */ + frame->r[0] = ret & 0xffffffff; + frame->r[1] = static_cast((ret >> 32) & 0xffffffff); +} +#endif + +#if ARCH_ARM64 +#include + +using syscall_func = int64_t (*)(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, + uint64_t f, uint64_t g, uint64_t h); + +extern "C" void arm64_syscall(struct arm64_iframe_long* frame, bool is_64bit, uint32_t syscall_imm, uint64_t pc) { + uint64_t syscall_num = frame->r[16]; + + /* check for magic value to differentiate our syscalls */ + if (unlikely(syscall_imm != 0xf0f)) { + TRACEF("syscall does not have magenta magic, 0x%llx @ PC 0x%llx\n", syscall_num, pc); + frame->r[0] = ERR_BAD_SYSCALL; + return; + } + + /* re-enable interrupts to maintain kernel preemptiveness */ + arch_enable_ints(); + + LTRACEF_LEVEL(2, "num %llu\n", syscall_num); + + /* build a function pointer to call the routine. + * the args are jammed into the function independent of if the function + * uses them or not, which is safe for simple arg passing. + */ + syscall_func sfunc; + + switch (syscall_num) { +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) \ + case n: \ + sfunc = reinterpret_cast(sys_##name); \ + break; +#include + default: + sfunc = reinterpret_cast(sys_invalid_syscall); + } + + /* call the routine */ + uint64_t ret = sfunc(frame->r[0], frame->r[1], frame->r[2], frame->r[3], frame->r[4], + frame->r[5], frame->r[6], frame->r[7]); + + LTRACEF_LEVEL(2, "ret 0x%llx\n", ret); + + /* put the return code back */ + frame->r[0] = ret; + + /* re-disable interrupts on the way out */ + arch_disable_ints(); +} + +#endif + +#if ARCH_X86_64 +#include + +using syscall_func = int64_t (*)(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, + uint64_t f, uint64_t g, uint64_t h); + +extern "C" uint64_t x86_64_syscall(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, + uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8, + uint64_t syscall_num, uint64_t ip) { + + /* check for magic value to differentiate our syscalls */ + if (unlikely((syscall_num >> 32) != 0xff00ff)) { + TRACEF("syscall does not have magenta magic, 0x%llx @ IP 0x%llx\n", syscall_num, ip); + return ERR_BAD_SYSCALL; + } + syscall_num &= 0xffffffff; + + /* re-enable interrupts to maintain kernel preemptiveness */ + arch_enable_ints(); + + LTRACEF_LEVEL(2, "syscall num 0x%llx\n", syscall_num); + + /* build a function pointer to call the routine. + * the args are jammed into the function independent of if the function + * uses them or not, which is safe for simple arg passing. + */ + syscall_func sfunc; + + switch (syscall_num) { +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) \ + case n: \ + sfunc = reinterpret_cast(sys_##name); \ + break; +#include + default: + sfunc = reinterpret_cast(sys_invalid_syscall); + } + + /* call the routine */ + uint64_t ret = sfunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + + LTRACEF_LEVEL(2, "ret 0x%llx\n", ret); + + return ret; +} + +#endif diff --git a/kernel/lib/syscalls/syscalls_ddk.cpp b/kernel/lib/syscalls/syscalls_ddk.cpp new file mode 100644 index 000000000..2f67ea5b3 --- /dev/null +++ b/kernel/lib/syscalls/syscalls_ddk.cpp @@ -0,0 +1,509 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "syscalls_priv.h" + +#define LOCAL_TRACE 0 + +static_assert(MX_CACHE_POLICY_CACHED == ARCH_MMU_FLAG_CACHED, + "Cache policy constant mismatch - CACHED"); +static_assert(MX_CACHE_POLICY_UNCACHED == ARCH_MMU_FLAG_UNCACHED, + "Cache policy constant mismatch - UNCACHED"); +static_assert(MX_CACHE_POLICY_UNCACHED_DEVICE == ARCH_MMU_FLAG_UNCACHED_DEVICE, + "Cache policy constant mismatch - UNCACHED_DEVICE"); +static_assert(MX_CACHE_POLICY_WRITE_COMBINING == ARCH_MMU_FLAG_WRITE_COMBINING, + "Cache policy constant mismatch - WRITE_COMBINING"); + +mx_handle_t sys_interrupt_event_create(uint32_t vector, uint32_t flags) { + LTRACEF("vector %u flags 0x%x\n", vector, flags); + + utils::RefPtr dispatcher; + mx_rights_t rights; + status_t result = InterruptDispatcher::Create(vector, flags, &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + + auto up = UserProcess::GetCurrent(); + mx_handle_t hv = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + return hv; +} + +mx_status_t sys_interrupt_event_wait(mx_handle_t handle_value) { + LTRACEF("handle %u\n", handle_value); + + uint32_t rights = 0u; + utils::RefPtr dispatcher; + + auto up = UserProcess::GetCurrent(); + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto interrupt = dispatcher->get_interrupt_dispatcher(); + if (!interrupt) + return ERR_BAD_HANDLE; + + return interrupt->InterruptWait(); +} + +mx_status_t sys_interrupt_event_complete(mx_handle_t handle_value) { + LTRACEF("handle %u\n", handle_value); + + uint32_t rights = 0u; + utils::RefPtr dispatcher; + + auto up = UserProcess::GetCurrent(); + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto interrupt = dispatcher->get_interrupt_dispatcher(); + if (!interrupt) + return ERR_BAD_HANDLE; + + return interrupt->InterruptComplete(); +} + +mx_status_t sys_mmap_device_memory(uintptr_t paddr, uint32_t len, void** out_vaddr) { + LTRACEF("addr 0x%lx len 0x%x\n", paddr, len); + + if (!out_vaddr) + return ERR_INVALID_ARGS; + + void* vaddr = nullptr; + uint arch_mmu_flags = + ARCH_MMU_FLAG_PERM_NO_EXECUTE | ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_UNCACHED_DEVICE; + + auto aspace = UserProcess::GetCurrent()->aspace(); + status_t res = aspace->AllocPhysical("user_mmio", len, &vaddr, + PAGE_SIZE_SHIFT, (paddr_t)paddr, + 0, // vmm flags + arch_mmu_flags); + + if (res != NO_ERROR) + return res; + + if (copy_to_user(reinterpret_cast(out_vaddr), &vaddr, sizeof(void*)) != NO_ERROR) { + aspace->FreeRegion(reinterpret_cast(vaddr)); + return ERR_INVALID_ARGS; + } + + return NO_ERROR; +} + +mx_status_t sys_alloc_device_memory(uint32_t len, void** out_paddr, void** out_vaddr) { + LTRACEF("len 0x%x\n", len); + + if (!out_paddr) + return ERR_INVALID_ARGS; + if (!out_vaddr) + return ERR_INVALID_ARGS; + + void* vaddr = nullptr; + auto aspace = UserProcess::GetCurrent()->aspace(); + uint arch_mmu_flags = + ARCH_MMU_FLAG_PERM_NO_EXECUTE | ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_UNCACHED_DEVICE; + + status_t res = aspace->AllocContiguous("user_mmio", len, &vaddr, + PAGE_SIZE_SHIFT, VMM_FLAG_COMMIT, + arch_mmu_flags); + if (res != NO_ERROR) + return res; + + paddr_t paddr = vaddr_to_paddr(vaddr); + if (copy_to_user(reinterpret_cast(out_vaddr), &vaddr, sizeof(void*)) != NO_ERROR || + copy_to_user(reinterpret_cast(out_paddr), &paddr, sizeof(void*)) != NO_ERROR) { + aspace->FreeRegion(reinterpret_cast(vaddr)); + return ERR_INVALID_ARGS; + } + + return NO_ERROR; +} + +#if ARCH_X86 +extern uint32_t bootloader_fb_base; +extern uint32_t bootloader_fb_width; +extern uint32_t bootloader_fb_height; +extern uint32_t bootloader_fb_stride; +extern uint32_t bootloader_fb_format; +#endif + +mx_status_t sys_bootloader_fb_get_info(uint32_t* format, uint32_t* width, uint32_t* height, uint32_t* stride) { +#if ARCH_X86 + if (!bootloader_fb_base || copy_to_user_u32(format, bootloader_fb_format) || copy_to_user_u32(width, bootloader_fb_width) || copy_to_user_u32(height, bootloader_fb_height) || copy_to_user_u32(stride, bootloader_fb_stride)) { + return ERR_INVALID_ARGS; + } else { + return NO_ERROR; + } +#else + return ERR_NOT_SUPPORTED; +#endif +} + +mx_status_t sys_set_framebuffer(void* vaddr, uint32_t len, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { + intptr_t paddr = vaddr_to_paddr(vaddr); + udisplay_set_framebuffer(paddr, vaddr, len); + + struct display_info di; + memset(&di, 0, sizeof(struct display_info)); + di.format = format; + di.width = width; + di.height = height; + di.stride = stride; + di.flags = DISPLAY_FLAG_HW_FRAMEBUFFER; + udisplay_set_display_info(&di); + + return NO_ERROR; +} + +mx_handle_t sys_pci_get_nth_device(uint32_t index, mx_pcie_get_nth_info_t* out_info) { + /** + * Returns the pci config of a device. + * @param index Device index + * @param out_info Device info (BDF address, vendor id, etc...) + */ + LTRACE_ENTRY; + + if (!out_info) + return ERR_INVALID_ARGS; + + utils::RefPtr dispatcher; + mx_rights_t rights; + mx_pcie_get_nth_info_t info; + status_t result = PciDeviceDispatcher::Create(index, &info, &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + auto up = UserProcess::GetCurrent(); + mx_handle_t handle_value = up->MapHandleToValue(handle.get()); + + if (copy_to_user(reinterpret_cast(out_info), + &info, sizeof(*out_info)) != NO_ERROR) + return ERR_INVALID_ARGS; + + up->AddHandle(utils::move(handle)); + return handle_value; +} + +mx_status_t sys_pci_claim_device(mx_handle_t handle) { + /** + * Claims the PCI device associated with the handle. Called when a driver + * successfully probes the device. + * @param handle Handle associated with a PCI device + */ + LTRACEF("handle %u\n", handle); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_device = dispatcher->get_pci_device_dispatcher(); + if (!pci_device) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + return pci_device->ClaimDevice(); +} + +mx_status_t sys_pci_enable_bus_master(mx_handle_t handle, bool enable) { + /** + * Enables or disables bus mastering for the PCI device associated with the handle. + * @param handle Handle associated with a PCI device + * @param enable true if bus mastering should be enabled. + */ + LTRACEF("handle %u\n", handle); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_device = dispatcher->get_pci_device_dispatcher(); + if (!pci_device) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + return pci_device->EnableBusMaster(enable); +} + +mx_status_t sys_pci_reset_device(mx_handle_t handle) { + /** + * Resets the PCI device associated with the handle. + * @param handle Handle associated with a PCI device + */ + LTRACEF("handle %u\n", handle); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_device = dispatcher->get_pci_device_dispatcher(); + if (!pci_device) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + return pci_device->ResetDevice(); +} + +mx_handle_t sys_pci_map_mmio(mx_handle_t handle, uint32_t bar_num, mx_cache_policy_t cache_policy) { + /** + * Performs MMIO mapping for the PCI device associated with the handle. + * @param handle Handle associated with a PCI device + * @param bar_num BAR number + */ + LTRACEF("handle %u\n", handle); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + // Caller only gets to control the cache policy, nothing else. + if (cache_policy & ~ARCH_MMU_FLAG_CACHE_MASK) + return ERR_INVALID_ARGS; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_device = dispatcher->get_pci_device_dispatcher(); + if (!pci_device) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + mx_rights_t mmio_rights; + utils::RefPtr mmio_io_mapping; + status_t result = pci_device->MapMmio(bar_num, cache_policy, &mmio_io_mapping, &mmio_rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr mmio_handle(MakeHandle(utils::move(mmio_io_mapping), mmio_rights)); + if (!handle) + return ERR_NO_MEMORY; + + mx_handle_t ret_val = up->MapHandleToValue(mmio_handle.get()); + up->AddHandle(utils::move(mmio_handle)); + return ret_val; +} + +mx_status_t sys_pci_io_write(mx_handle_t handle, uint32_t bar_num, uint32_t offset, uint32_t len, + uint32_t value) { + /** + * Performs port I/O write for the PCI device associated with the handle. + * @param handle Handle associated with a PCI device + * @param bar_num BAR number + * @param offset Offset from the base + * @param len Length of the operation in bytes + * @param value_ptr Pointer to the value to write + */ + return ERR_NOT_SUPPORTED; +} + +mx_status_t sys_pci_io_read(mx_handle_t handle, uint32_t bar_num, uint32_t offset, uint32_t len, + uint32_t* out_value_ptr) { + /** + * Performs port I/O read for the PCI device associated with the handle. + * @param handle Handle associated with a PCI device + * @param bar_num BAR number + * @param offset Offset from the base + * @param len Length of the operation in bytes + * @param out_value_ptr Pointer to read the value into + */ + return ERR_NOT_SUPPORTED; +} + +mx_handle_t sys_pci_map_interrupt(mx_handle_t handle_value, int32_t which_irq) { + /** + * Returns a handle that can be waited on in sys_pci_interrupt_wait. + * @param handle Handle associated with a PCI device + * @param which_irq Identifier for an IRQ, returned in sys_pci_get_nth_device, or -1 for legacy + * interrupts + */ + LTRACEF("handle %u\n", handle_value); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr device_dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle_value, &device_dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_device = device_dispatcher->get_pci_device_dispatcher(); + if (!pci_device) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + utils::RefPtr interrupt_dispatcher; + status_t result = pci_device->MapInterrupt(which_irq, &interrupt_dispatcher, &rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr handle(MakeHandle(utils::move(interrupt_dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + mx_handle_t interrupt_handle = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + return interrupt_handle; +} + +mx_status_t sys_pci_interrupt_wait(mx_handle_t handle) { + /** + * TODO: perhaps unify all IRQ types in the kernel + * Waits for an interrupt on this handle + * @param handle Handle associated with a PCI interrupt + */ + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_interrupt = dispatcher->get_pci_interrupt_dispatcher(); + if (!pci_interrupt) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + return pci_interrupt->InterruptWait(); +} + +mx_handle_t sys_pci_map_config(mx_handle_t handle) { + /** + * Fetch an I/O Mapping object which maps the PCI device's mmaped config + * into the caller's address space (read only) + * + * @param handle Handle associated with a PCI device + */ + LTRACEF("handle %u\n", handle); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto pci_device = dispatcher->get_pci_device_dispatcher(); + if (!pci_device) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + mx_rights_t config_rights; + utils::RefPtr config_io_mapping; + status_t result = pci_device->MapConfig(&config_io_mapping, &config_rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr config_handle(MakeHandle(utils::move(config_io_mapping), config_rights)); + if (!config_handle) + return ERR_NO_MEMORY; + + mx_handle_t ret_val = up->MapHandleToValue(config_handle.get()); + up->AddHandle(utils::move(config_handle)); + return ret_val; +} + +/** + * Gets info about an I/O mapping object. + * @param handle Handle associated with an I/O mapping object. + * @param out_vaddr Mapped virtual address for the I/O range. + * @param out_len Mapped size of the I/O range. + */ +mx_status_t sys_io_mapping_get_info(mx_handle_t handle, void** out_vaddr, uint64_t* out_size) { + LTRACEF("handle %u\n", handle); + + if (!out_vaddr || !out_size) + return ERR_INVALID_ARGS; + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto io_mapping = dispatcher->get_io_mapping_dispatcher(); + if (!io_mapping || io_mapping->closed()) + return ERR_BAD_HANDLE; + + // If we do not have read rights, or we are calling from a different address + // space than the one that this mapping exists in, refuse to tell the user + // the vaddr/len of the mapping. + if (!magenta_rights_check(rights, MX_RIGHT_READ) || + (UserProcess::GetCurrent()->aspace() != io_mapping->aspace())) + return ERR_ACCESS_DENIED; + + void* vaddr = reinterpret_cast(io_mapping->vaddr()); + uint64_t size = io_mapping->size(); + status_t status; + + status = copy_to_user(out_vaddr, &vaddr, sizeof(*out_vaddr)); + if (status != NO_ERROR) + return status; + + return copy_to_user(out_size, &size, sizeof(*out_size)); +} + +#if ARCH_X86 +#include +#include + +mx_status_t sys_mmap_device_io(uint32_t io_addr, uint32_t len) { + LTRACEF("addr 0x%x len 0x%x\n", io_addr, len); + + return x86_set_io_bitmap(io_addr, len, 1); +} +#else +mx_status_t sys_mmap_device_io(uint32_t io_addr, uint32_t len) { + // doesn't make sense on non-x86 + return ERR_NOT_SUPPORTED; +} +#endif diff --git a/kernel/lib/syscalls/syscalls_debug.cpp b/kernel/lib/syscalls/syscalls_debug.cpp new file mode 100644 index 000000000..03ba562b1 --- /dev/null +++ b/kernel/lib/syscalls/syscalls_debug.cpp @@ -0,0 +1,85 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "syscalls_priv.h" + +#define LOCAL_TRACE 0 + +constexpr uint32_t kMaxDebugWriteSize = 256u; + +#if WITH_LIB_DEBUGLOG +#include +#endif + +int sys_debug_read(void* ptr, uint32_t len) { + LTRACEF("ptr %p\n", ptr); + + if (!len) + return 0; + // TODO: remove this cast. + auto uptr = reinterpret_cast(ptr); + auto end = uptr + len; + + for (; uptr != end; ++uptr) { + int c = getchar(); + if (c < 0) + break; + + if (c == '\r') + c = '\n'; + if (copy_to_user_u8(uptr, static_cast(c)) != NO_ERROR) + break; + } + // TODO: fix this cast, which can overflow. + return static_cast(reinterpret_cast(uptr) - reinterpret_cast(ptr)); +} + +int sys_debug_write(const void* ptr, uint32_t len) { + LTRACEF("ptr %p, len %d\n", ptr, len); + + if (len > kMaxDebugWriteSize) + return ERR_TOO_BIG; + + char buf[kMaxDebugWriteSize]; + if (magenta_copy_from_user(ptr, buf, len) != NO_ERROR) + return ERR_INVALID_ARGS; + + for (uint32_t i = 0; i < len; i++) { + platform_dputc(buf[i]); + } + return len; +} + +int sys_debug_send_command(const void* ptr, uint32_t len) { + LTRACEF("ptr %p, len %d\n", ptr, len); + + if (len > kMaxDebugWriteSize) + return ERR_INVALID_ARGS; + + char buf[kMaxDebugWriteSize + 2]; + if (magenta_copy_from_user(ptr, buf, len) != NO_ERROR) + return ERR_INVALID_ARGS; + + buf[len] = '\n'; + buf[len + 1] = 0; + return console_run_script(buf); +} diff --git a/kernel/lib/syscalls/syscalls_exceptions.cpp b/kernel/lib/syscalls/syscalls_exceptions.cpp new file mode 100644 index 000000000..74f6d90e0 --- /dev/null +++ b/kernel/lib/syscalls/syscalls_exceptions.cpp @@ -0,0 +1,124 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "syscalls_priv.h" + +#define LOCAL_TRACE 0 + +// TODO(dje): This is a temp hack as there is no handle of an object +// provided on which to do rights checking (does the caller have permission +// to set the system exception handler?). When a suitable object is created +// this routine can be deleted in favor of set_exception_handler. + +mx_status_t sys_set_system_exception_handler(mx_handle_t pipe_handle, mx_exception_behaviour_t behaviour) { + LTRACE_ENTRY; + + auto up = UserProcess::GetCurrent(); + + utils::RefPtr pipe_dispatcher; + mx_rights_t pipe_rights; + if (!up->GetDispatcher(pipe_handle, &pipe_dispatcher, &pipe_rights)) + return ERR_INVALID_ARGS; + // TODO(dje): verify is a pipe of appropriate kind + // TODO(dje): rights checking of pipe? + + if (behaviour > MX_EXCEPTION_MAX_BEHAVIOUR) + return ERR_INVALID_ARGS; + + SetSystemExceptionHandler(utils::move(pipe_dispatcher), behaviour); + + return NO_ERROR; +} + +mx_status_t sys_set_exception_handler(mx_handle_t object_handle, + mx_handle_t pipe_handle, mx_exception_behaviour_t behaviour) { + LTRACE_ENTRY; + + auto up = UserProcess::GetCurrent(); + + utils::RefPtr pipe_dispatcher; + mx_rights_t pipe_rights; + if (!up->GetDispatcher(pipe_handle, &pipe_dispatcher, &pipe_rights)) + return ERR_INVALID_ARGS; + // TODO(dje): verify is a pipe of appropriate kind + // TODO(dje): rights checking of pipe? + + if (behaviour > MX_EXCEPTION_MAX_BEHAVIOUR) + return ERR_INVALID_ARGS; + + // TODO(dje): Temp hack, 0 == "this process" + if (object_handle == 0) { + return up->SetExceptionHandler(utils::move(pipe_dispatcher), behaviour); + } else { + // TODO(dje): Rights checking ok? + utils::RefPtr dispatcher; + mx_rights_t rights; + if (!up->GetDispatcher(object_handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + // TODO(dje): What's the right right here? [READ is a temp hack] + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + auto process = dispatcher->get_process_owner_dispatcher(); + if (process) + return process->SetExceptionHandler(utils::move(pipe_dispatcher), behaviour); + + auto thread = dispatcher->get_thread_dispatcher(); + if (thread) + return thread->SetExceptionHandler(utils::move(pipe_dispatcher), behaviour); + + return ERR_BAD_HANDLE; + } +} + +mx_status_t sys_mark_exception_handled(mx_handle_t thread_handle, mx_exception_status_t excp_status) { + LTRACE_ENTRY; + + auto up = UserProcess::GetCurrent(); + + if (excp_status != MX_EXCEPTION_STATUS_NOT_HANDLED && + excp_status != MX_EXCEPTION_STATUS_RESUME) + return ERR_INVALID_ARGS; + + utils::RefPtr dispatcher; + mx_rights_t rights; + if (!up->GetDispatcher(thread_handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto thread = dispatcher->get_thread_dispatcher(); + if (!thread) + return ERR_BAD_HANDLE; + + // TODO(dje): What's the right right here? [READ is a temp hack] + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + return thread->MarkExceptionHandled(excp_status); +} diff --git a/kernel/lib/syscalls/syscalls_magenta.cpp b/kernel/lib/syscalls/syscalls_magenta.cpp new file mode 100644 index 000000000..c97002571 --- /dev/null +++ b/kernel/lib/syscalls/syscalls_magenta.cpp @@ -0,0 +1,1041 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "syscalls_priv.h" + +#define LOCAL_TRACE 0 + +constexpr uint32_t kMaxMessageSize = 65536u; +constexpr uint32_t kMaxMessageHandles = 1024u; + +constexpr uint32_t kMaxWaitHandleCount = 256u; + +void sys_exit(int retcode) { + LTRACEF("retcode %d\n", retcode); + + UserProcess::GetCurrent()->Exit(retcode); +} + +int sys_nanosleep(mx_time_t nanoseconds) { + LTRACEF("nseconds %llu\n", nanoseconds); + + lk_time_t t = mx_time_to_lk(nanoseconds); + + thread_sleep(t); + return 0; +} + +uint64_t sys_current_time() { + return current_time_hires() * 1000; // microseconds to nanoseconds +} + +struct WaitHelper { + utils::RefPtr dispatcher; + Waiter* waiter; + + WaitHelper() + : waiter(nullptr) {} + ~WaitHelper() { DEBUG_ASSERT(dispatcher.get() == nullptr); } + + status_t Begin(Handle* handle, event_t* event, mx_signals_t signals) { + dispatcher = handle->dispatcher(); + waiter = dispatcher->BeginWait(event, handle, signals); + return waiter ? NO_ERROR : ERR_NOT_SUPPORTED; + } + + mx_signals_t End(event_t* event) { + auto s = waiter->FinishWait(event); + dispatcher.reset(); + return s; + } +}; + +mx_status_t sys_handle_wait_one(mx_handle_t handle_value, + mx_signals_t signals, + mx_time_t timeout, + mx_signals_t* satisfied_signals, + mx_signals_t* satisfiable_signals) { + LTRACEF("handle %u\n", handle_value); + + event_t event; + event_init(&event, false, 0); + + status_t result; + WaitHelper wait_helper; + + { + auto up = UserProcess::GetCurrent(); + AutoLock lock(up->handle_table_lock()); + + Handle* handle = up->GetHandle_NoLock(handle_value); + if (!handle) + return ERR_INVALID_ARGS; + if (!magenta_rights_check(handle->rights(), MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + result = wait_helper.Begin(handle, &event, signals); + if (result != NO_ERROR) + return result; + } + + uint32_t satisfied = 0u; + uint32_t satisfiable = 0u; + + result = event_wait_timeout(&event, mx_time_to_lk(timeout)); + + // Regardless of wait outcome, we must call FinishWait(). + satisfiable = wait_helper.End(&event); + + // TODO(cpu): This is incorrect. See MG-32 bug. + satisfied = satisfiable; + + if ((result != NO_ERROR) && (result != ERR_TIMED_OUT)) { + return result; + } + + if (satisfied_signals) { + if (copy_to_user_u32(satisfied_signals, satisfied) != NO_ERROR) + return ERR_INVALID_ARGS; + } + + if (satisfiable_signals) { + if (copy_to_user_u32(satisfiable_signals, satisfiable) != NO_ERROR) + return ERR_INVALID_ARGS; + } + + return result; +} + +mx_status_t sys_handle_wait_many(uint32_t count, + const mx_handle_t* _handle_values, + const mx_signals_t* _signals, + mx_time_t timeout, + mx_signals_t* _satisfied_signals, + mx_signals_t* _satisfiable_signals) { + LTRACEF("count %u\n", count); + + if (!_handle_values || !_signals) + return ERR_INVALID_ARGS; + if (!count || count > kMaxWaitHandleCount) + return ERR_INVALID_ARGS; + + uint32_t max_size = kMaxWaitHandleCount * sizeof(uint32_t); + uint32_t bytes_size = static_cast(sizeof(uint32_t) * count); + + uint8_t* copy; + status_t result; + + result = magenta_copy_user_dynamic(_handle_values, ©, bytes_size, max_size); + if (result != NO_ERROR) + return result; + utils::unique_ptr handle_values(reinterpret_cast(copy)); + + result = magenta_copy_user_dynamic(_signals, ©, bytes_size, max_size); + if (result != NO_ERROR) + return result; + utils::unique_ptr signals(reinterpret_cast(copy)); + + utils::unique_ptr waiters(new WaitHelper[count]); + if (!waiters) + return ERR_NO_MEMORY; + + utils::unique_ptr satisfied; + if (_satisfied_signals) { + satisfied.reset(new uint32_t[count]); + if (!satisfied) + return ERR_NO_MEMORY; + } + + event_t event; + event_init(&event, false, 0); + + { + auto up = UserProcess::GetCurrent(); + AutoLock lock(up->handle_table_lock()); + + for (size_t ix = 0; ix != count; ++ix) { + Handle* handle = up->GetHandle_NoLock(handle_values[ix]); + if (!handle) + return ERR_INVALID_ARGS; + if (!magenta_rights_check(handle->rights(), MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + result = waiters[ix].Begin(handle, &event, signals[ix]); + if (result != NO_ERROR) + return result; + } + } + + result = event_wait_timeout(&event, mx_time_to_lk(timeout)); + + // Regardless of wait outcome, we must call FinishWait(). + for (size_t ix = 0; ix != count; ++ix) { + auto s = waiters[ix].End(&event); + if (satisfied) + satisfied[ix] = s; + } + + if ((result != NO_ERROR) && (result != ERR_TIMED_OUT)) { + return result; + } + + if (_satisfied_signals) { + if (copy_to_user(_satisfied_signals, satisfied.get(), bytes_size) != NO_ERROR) + return ERR_INVALID_ARGS; + } + // TODO(cpu): This is incorrect. See MG-32 bug. + if (_satisfiable_signals) { + if (copy_to_user(_satisfiable_signals, satisfied.get(), bytes_size) != NO_ERROR) + return ERR_INVALID_ARGS; + } + + return result; +} + +mx_status_t sys_handle_close(mx_handle_t handle_value) { + LTRACEF("handle %u\n", handle_value); + auto up = UserProcess::GetCurrent(); + HandleUniquePtr handle(up->RemoveHandle(handle_value)); + if (handle) + handle->Close(); + + return (handle) ? NO_ERROR : ERR_INVALID_ARGS; +} + +mx_handle_t sys_handle_duplicate(mx_handle_t handle_value) { + LTRACEF("handle %u\n", handle_value); + + auto up = UserProcess::GetCurrent(); + HandleUniquePtr dest; + + { + AutoLock lock(up->handle_table_lock()); + Handle* source = up->GetHandle_NoLock(handle_value); + if (!source) + return ERR_INVALID_ARGS; + + if (!magenta_rights_check(source->rights(), MX_RIGHT_DUPLICATE)) + return ERR_ACCESS_DENIED; + dest.reset(DupHandle(source)); + } + + if (!dest) + return ERR_NO_MEMORY; + + mx_handle_t dup_hv = up->MapHandleToValue(dest.get()); + + up->AddHandle(utils::move(dest)); + return dup_hv; +} + +mx_status_t sys_message_read(mx_handle_t handle_value, void* _bytes, uint32_t* _num_bytes, + mx_handle_t* _handles, uint32_t* _num_handles, uint32_t flags) { + LTRACEF("handle %d bytes %p num_bytes %p handles %p num_handles %p flags 0x%x\n", + handle_value, _bytes, _num_bytes, _handles, _num_handles, flags); + + uint32_t num_bytes = 0; + uint32_t num_handles = 0; + + if (_num_bytes) { + if (copy_from_user_u32(&num_bytes, _num_bytes) != NO_ERROR) + return ERR_INVALID_ARGS; + } + + if (_num_handles) { + if (copy_from_user_u32(&num_handles, _num_handles) != NO_ERROR) + return ERR_INVALID_ARGS; + } + + if (_bytes != 0u && !_num_bytes) + return ERR_INVALID_ARGS; + if (_handles != 0u && !_num_handles) + return ERR_INVALID_ARGS; + + utils::unique_ptr handles; + + if (num_handles) { + handles.reset(new uint32_t[num_handles]()); + if (!handles) + return ERR_NO_MEMORY; + } + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto msg_pipe = dispatcher->get_message_pipe_dispatcher(); + if (!msg_pipe) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + uint32_t next_message_size = 0u; + uint32_t next_message_num_handles = 0u; + status_t result = msg_pipe->BeginRead(&next_message_size, &next_message_num_handles); + if (result != NO_ERROR) + return result; + + // Always set the actual size and handle count so the caller can provide larger buffers. + if (_num_bytes) { + if (copy_to_user_u32(_num_bytes, next_message_size) != NO_ERROR) + return ERR_INVALID_ARGS; + } + if (_num_handles) { + if (copy_to_user_u32(_num_handles, next_message_num_handles) != NO_ERROR) + return ERR_INVALID_ARGS; + } + + // If the caller provided buffers are too small, abort the read so the caller can try again. + if (num_bytes < next_message_size || num_handles < next_message_num_handles) + return ERR_NOT_ENOUGH_BUFFER; + + // OK, now we can accept the message. + utils::Array bytes; + utils::Array handle_list; + + result = msg_pipe->AcceptRead(&bytes, &handle_list); + + if (_bytes) { + if (copy_to_user(reinterpret_cast(_bytes), bytes.get(), num_bytes) != NO_ERROR) { + // $$$ free handles. + return ERR_INVALID_ARGS; + } + } + + if (next_message_num_handles != 0u) { + for (size_t ix = 0u; ix < next_message_num_handles; ++ix) { + auto hv = up->MapHandleToValue(handle_list[ix]); + if (copy_to_user_32(&_handles[ix], hv) != NO_ERROR) { + // $$$ free handles. + return ERR_INVALID_ARGS; + } + } + } + + for (size_t idx = 0u; idx < next_message_num_handles; ++idx) { + HandleUniquePtr handle(handle_list[idx]); + up->AddHandle(utils::move(handle)); + } + + return result; +} + +mx_status_t sys_message_write(mx_handle_t handle_value, const void* _bytes, uint32_t num_bytes, + const mx_handle_t* _handles, uint32_t num_handles, uint32_t flags) { + LTRACEF("handle %d bytes %p num_bytes %u handles %p num_handles %u flags 0x%x\n", + handle_value, _bytes, num_bytes, _handles, num_handles, flags); + + if (num_bytes != 0u && !_bytes) + return ERR_INVALID_ARGS; + if (num_handles != 0u && !_handles) + return ERR_INVALID_ARGS; + + if (num_bytes > kMaxMessageSize) + return ERR_TOO_BIG; + if (num_handles > kMaxMessageHandles) + return ERR_TOO_BIG; + + status_t result; + utils::Array bytes; + + if (num_bytes) { + uint8_t* copy; + result = magenta_copy_user_dynamic(_bytes, ©, num_bytes, kMaxMessageSize); + if (result != NO_ERROR) + return result; + bytes.reset(copy, num_bytes); + } + + utils::unique_ptr handles; + if (num_handles) { + void* c_handles; + status_t status = copy_from_user_dynamic( + &c_handles, _handles, num_handles * sizeof(_handles[0]), kMaxMessageHandles); + // |status| can be ERR_NO_MEMORY or ERR_INVALID_ARGS. + if (status != NO_ERROR) + return status; + + handles.reset(static_cast(c_handles)); + } + + auto up = UserProcess::GetCurrent(); + + utils::RefPtr dispatcher; + uint32_t rights; + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto msg_pipe = dispatcher->get_message_pipe_dispatcher(); + if (!msg_pipe) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + utils::Array handle_list(new Handle*[num_handles], num_handles); + { + // Loop twice, first we collect and validate handles, the second pass + // we remove them from this process. + AutoLock lock(up->handle_table_lock()); + + for (size_t ix = 0; ix != num_handles; ++ix) { + auto handle = up->GetHandle_NoLock(handles[ix]); + if (!handle) + return ERR_INVALID_ARGS; + handle_list[ix] = handle; + } + + for (size_t ix = 0; ix != num_handles; ++ix) { + up->RemoveHandle_NoLock(handles[ix]).release(); + } + } + + result = msg_pipe->Write(utils::move(bytes), utils::move(handle_list)); + + if (result != NO_ERROR) { + // Write failed, put back the handles into this process. + AutoLock lock(up->handle_table_lock()); + for (size_t ix = 0; ix != num_handles; ++ix) { + up->UndoRemoveHandle_NoLock(handles[ix]); + } + } + + return result; +} + +mx_handle_t sys_message_pipe_create(mx_handle_t* out_handle) { + LTRACE_ENTRY; + + if (!out_handle) + return ERR_INVALID_ARGS; + + utils::RefPtr mpd0, mpd1; + mx_rights_t rights; + status_t result = MessagePipeDispatcher::Create(&mpd0, &mpd1, &rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr h0(MakeHandle(utils::move(mpd0), rights)); + if (!h0) + return ERR_NO_MEMORY; + + HandleUniquePtr h1(MakeHandle(utils::move(mpd1), rights)); + if (!h1) + return ERR_NO_MEMORY; + + auto up = UserProcess::GetCurrent(); + mx_handle_t hv[2] = {up->MapHandleToValue(h0.get()), up->MapHandleToValue(h1.get())}; + + if (copy_to_user_32(out_handle, hv[1]) != NO_ERROR) + return ERR_INVALID_ARGS; + + up->AddHandle(utils::move(h0)); + up->AddHandle(utils::move(h1)); + return hv[0]; +} + +mx_handle_t sys_thread_create(int (*entry)(void*), void* arg, const char* name, uint32_t name_len) { + LTRACEF("entry %p\n", entry); + + char buf[MX_MAX_NAME_LEN]; + utils::StringPiece sp; + status_t result = magenta_copy_user_string(name, name_len, buf, sizeof(buf), &sp); + if (result != NO_ERROR) + return result; + + auto up = UserProcess::GetCurrent(); + + utils::unique_ptr user_thread(new UserThread(up, entry, arg)); + if (!user_thread) + return ERR_NO_MEMORY; + + result = user_thread->Initialize(buf); + if (result != NO_ERROR) + return result; + + user_thread->Start(); + + utils::RefPtr dispatcher; + mx_rights_t rights; + result = ThreadDispatcher::Create(user_thread.release(), &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + + mx_handle_t hv = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + return hv; +} + +void sys_thread_exit() { + LTRACE_ENTRY; + return UserThread::GetCurrent()->Exit(); +} + +mx_status_t sys_thread_arch_prctl(mx_handle_t handle_value, uint32_t op, uintptr_t* value_ptr) { + LTRACEF("handle %u operation %u value_ptr %p", handle_value, op, value_ptr); + + // TODO(cpu) what to do with |handle_value|? + + uintptr_t value; + +#ifdef ARCH_X86_64 + switch (op) { + case ARCH_SET_FS: + if (copy_from_user_uptr(&value, value_ptr) != NO_ERROR) + return ERR_INVALID_ARGS; + if (!x86_is_vaddr_canonical(value)) + return ERR_INVALID_ARGS; + write_msr(X86_MSR_IA32_FS_BASE, value); + break; + case ARCH_GET_FS: + value = read_msr(X86_MSR_IA32_FS_BASE); + if (copy_to_user_uptr(value_ptr, value) != NO_ERROR) + return ERR_INVALID_ARGS; + break; + case ARCH_SET_GS: + if (copy_from_user_uptr(&value, value_ptr) != NO_ERROR) + return ERR_INVALID_ARGS; + if (!x86_is_vaddr_canonical(value)) + return ERR_INVALID_ARGS; + write_msr(X86_MSR_IA32_KERNEL_GS_BASE, value); + break; + case ARCH_GET_GS: + value = read_msr(X86_MSR_IA32_KERNEL_GS_BASE); + if (copy_to_user_uptr(value_ptr, value) != NO_ERROR) + return ERR_INVALID_ARGS; + break; + default: + return ERR_INVALID_ARGS; + } +#elif ARCH_ARM64 + switch (op) { + case ARCH_SET_TPIDRRO_EL0: + if (copy_from_user_uptr(&value, value_ptr) != NO_ERROR) + return ERR_INVALID_ARGS; + ARM64_WRITE_SYSREG(tpidrro_el0, value); + break; + default: + return ERR_INVALID_ARGS; + } +#elif ARCH_ARM + switch (op) { + case ARCH_SET_CP15_READONLY: + if (copy_from_user_uptr(&value, value_ptr) != NO_ERROR) + return ERR_INVALID_ARGS; + __asm__ volatile("mcr p15, 0, %0, c13, c0, 3" : : "r" (value)); + ISB; + break; + default: + return ERR_INVALID_ARGS; + } +#else + // Unsupported architecture. + (void)value; + return ERR_INVALID_ARGS; +#endif + + return NO_ERROR; +} + +mx_handle_t sys_process_create(const char* name, uint32_t name_len) { + LTRACEF("name %s\n", name); + + char buf[MX_MAX_NAME_LEN]; + utils::StringPiece sp; + status_t result = magenta_copy_user_string(name, name_len, buf, sizeof(buf), &sp); + if (result != NO_ERROR) + return result; + + utils::RefPtr dispatcher; + mx_rights_t rights; + status_t res = ProcessOwnerDispatcher::Create(&dispatcher, &rights, sp); + if (res != NO_ERROR) + return res; + + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + auto up = UserProcess::GetCurrent(); + mx_handle_t hv = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + return hv; +} + +mx_status_t sys_process_start(mx_handle_t handle_value, mx_handle_t arg_handle_value, mx_vaddr_t entry) { + LTRACEF("handle %u\n", handle_value); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto process = dispatcher->get_process_owner_dispatcher(); + if (!process) + return ERR_BAD_HANDLE; + + HandleUniquePtr arg_handle = up->RemoveHandle(arg_handle_value); + if (!arg_handle_value) + return ERR_INVALID_ARGS; + + mx_handle_t arg_nhv = process->AddHandle(utils::move(arg_handle)); + + return process->Start(arg_nhv, entry); +} + +mx_status_t sys_process_get_info(mx_handle_t handle, mx_process_info_t* user_info, mx_size_t info_len) { + LTRACEF("handle %d, info %p, info_len %lu\n", handle, user_info, info_len); + + mx_process_info_t info; + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto process = dispatcher->get_process_owner_dispatcher(); + if (!process) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + status_t result = process->GetInfo(&info); + if (result != NO_ERROR) + return result; + + size_t copy_len = MIN(info_len, sizeof(info)); + return (copy_to_user(user_info, &info, copy_len) != NO_ERROR) ? ERR_INVALID_ARGS : 0; +} + +mx_handle_t sys_event_create(uint32_t options) { + LTRACEF("options 0x%x\n", options); + + utils::RefPtr dispatcher; + mx_rights_t rights; + + status_t result = EventDispatcher::Create(options, &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + auto up = UserProcess::GetCurrent(); + + mx_handle_t hv = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + return hv; +} + +mx_status_t sys_event_signal(mx_handle_t handle_value) { + LTRACEF("handle %u\n", handle_value); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto event = dispatcher->get_event_dispatcher(); + if (!event) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + return event->SignalEvent(); +} + +mx_status_t sys_event_reset(mx_handle_t handle_value) { + LTRACEF("handle %u\n", handle_value); + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto event = dispatcher->get_event_dispatcher(); + if (!event) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + return event->ResetEvent(); +} + +mx_status_t sys_object_signal(mx_handle_t handle_value, uint32_t set_mask, uint32_t clear_mask) { + LTRACEF("handle %u\n", handle_value); + + if ((set_mask & MX_SIGNAL_USER_ALL) != set_mask) + return ERR_INVALID_ARGS; + if ((clear_mask & MX_SIGNAL_USER_ALL) != clear_mask) + return ERR_INVALID_ARGS; + + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + + if (!up->GetDispatcher(handle_value, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + return dispatcher->UserSignal(set_mask, clear_mask); +} + +mx_status_t sys_futex_wait(int* value_ptr, int current_value, mx_time_t timeout) { + return UserProcess::GetCurrent()->futex_context()->FutexWait(value_ptr, current_value, timeout); +} + +mx_status_t sys_futex_wake(int* value_ptr, uint32_t count) { + return UserProcess::GetCurrent()->futex_context()->FutexWake(value_ptr, count); +} + +mx_status_t sys_futex_requeue(int* wake_ptr, uint32_t wake_count, int current_value, + int* requeue_ptr, uint32_t requeue_count) { + return UserProcess::GetCurrent()->futex_context()->FutexRequeue( + wake_ptr, wake_count, current_value, requeue_ptr, requeue_count); +} + +mx_handle_t sys_vm_object_create(uint64_t size) { + LTRACEF("size 0x%llx\n", size); + + // create a vm object + utils::RefPtr vmo = VmObject::Create(0, size); + if (!vmo) + return ERR_NO_MEMORY; + + // create a Vm Object dispatcher + utils::RefPtr dispatcher; + mx_rights_t rights; + mx_status_t result = VmObjectDispatcher::Create(utils::move(vmo), &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + // create a handle and attach the dispatcher to it + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + auto up = UserProcess::GetCurrent(); + + mx_handle_t hv = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + + return hv; +} + +mx_ssize_t sys_vm_object_read(mx_handle_t handle, void* data, uint64_t offset, mx_size_t len) { + LTRACEF("handle %d, data %p, offset 0x%llx, len 0x%lx\n", handle, data, offset, len); + + // lookup the dispatcher from handle + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto vmo = dispatcher->get_vm_object_dispatcher(); + if (!vmo) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + // do the read operation + return vmo->Read(data, len, offset); +} + +mx_ssize_t sys_vm_object_write(mx_handle_t handle, const void* data, uint64_t offset, mx_size_t len) { + LTRACEF("handle %d, data %p, offset 0x%llx, len 0x%lx\n", handle, data, offset, len); + + // lookup the dispatcher from handle + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto vmo = dispatcher->get_vm_object_dispatcher(); + if (!vmo) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + // do the write operation + return vmo->Write(data, len, offset); +} + +mx_status_t sys_vm_object_get_size(mx_handle_t handle, uint64_t* _size) { + LTRACEF("handle %d, sizep %p\n", handle, _size); + + // lookup the dispatcher from handle + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto vmo = dispatcher->get_vm_object_dispatcher(); + if (!vmo) + return ERR_BAD_HANDLE; + + // no rights check, anyone should be able to get the size + + // do the operation + uint64_t size = 0; + mx_status_t status = vmo->GetSize(&size); + + // copy the size back, even if it failed + if (copy_to_user(reinterpret_cast(_size), &size, sizeof(size)) != NO_ERROR) + return ERR_INVALID_ARGS; + + return status; +} + +mx_status_t sys_vm_object_set_size(mx_handle_t handle, uint64_t size) { + LTRACEF("handle %d, size 0x%llx\n", handle, size); + + // lookup the dispatcher from handle + auto up = UserProcess::GetCurrent(); + utils::RefPtr dispatcher; + uint32_t rights; + if (!up->GetDispatcher(handle, &dispatcher, &rights)) + return ERR_INVALID_ARGS; + + auto vmo = dispatcher->get_vm_object_dispatcher(); + if (!vmo) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + // do the operation + return vmo->SetSize(size); +} + +mx_status_t sys_process_vm_map(mx_handle_t proc_handle, mx_handle_t vmo_handle, + uint64_t offset, mx_size_t len, uintptr_t* user_ptr, uint32_t flags) { + + LTRACEF("proc handle %d, vmo handle %d, offset 0x%llx, len 0x%lx, user_ptr %p, flags 0x%x\n", + proc_handle, vmo_handle, offset, len, user_ptr, flags); + + // current process + auto up = UserProcess::GetCurrent(); + + // get the vmo dispatcher + utils::RefPtr vmo_dispatcher; + uint32_t vmo_rights; + if (!up->GetDispatcher(vmo_handle, &vmo_dispatcher, &vmo_rights)) + return ERR_INVALID_ARGS; + + auto vmo = vmo_dispatcher->get_vm_object_dispatcher(); + if (!vmo) + return ERR_BAD_HANDLE; + + // get a reffed pointer to the address space in the target process + utils::RefPtr aspace; + if (proc_handle == 0) { + // handle 0 is magic for 'current process' + // TODO: remove this hack and switch to requiring user to pass the current process handle + aspace = up->aspace(); + } else { + // get the process dispatcher and convert to aspace + utils::RefPtr proc_dispatcher; + uint32_t proc_rights; + if (!up->GetDispatcher(proc_handle, &proc_dispatcher, &proc_rights)) + return ERR_INVALID_ARGS; + + auto process = proc_dispatcher->get_process_owner_dispatcher(); + if (!process) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(proc_rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + // get the aspace out of the process dispatcher + aspace = process->GetVmAspace(); + if (!aspace) + return ERR_INVALID_ARGS; + } + + // copy the user pointer in + uintptr_t ptr; + if (copy_from_user(&ptr, reinterpret_cast(user_ptr), sizeof(ptr)) != NO_ERROR) + return ERR_INVALID_ARGS; + + // do the map call + mx_status_t status = vmo->Map(utils::move(aspace), vmo_rights, offset, len, &ptr, flags); + if (status != NO_ERROR) + return status; + + // copy the user pointer back + if (copy_to_user(reinterpret_cast(user_ptr), &ptr, sizeof(ptr)) != NO_ERROR) + return ERR_INVALID_ARGS; + + return NO_ERROR; +} + +mx_status_t sys_process_vm_unmap(mx_handle_t proc_handle, uintptr_t address, mx_size_t len) { + LTRACEF("proc handle %d, address 0x%lx, len 0x%lx\n", proc_handle, address, len); + + // get a reffed pointer to the address space in the target process + auto up = UserProcess::GetCurrent(); + utils::RefPtr aspace; + if (proc_handle == 0) { + // handle 0 is magic for 'current process' + // TODO: remove this hack and switch to requiring user to pass the current process handle + aspace = up->aspace(); + } else { + // get the process dispatcher and convert to aspace + utils::RefPtr proc_dispatcher; + uint32_t proc_rights; + if (!up->GetDispatcher(proc_handle, &proc_dispatcher, &proc_rights)) + return ERR_INVALID_ARGS; + + auto process = proc_dispatcher->get_process_owner_dispatcher(); + if (!process) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(proc_rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + // get the aspace out of the process dispatcher + aspace = process->GetVmAspace(); + if (!aspace) + return ERR_INVALID_ARGS; + } + + // TODO: support range unmapping + // at the moment only support unmapping what is at a given address, signalled with len = 0 + if (len != 0) + return ERR_INVALID_ARGS; + + // TODO: get the unmap call into the dispatcher + // It's not really feasible to do it because of the handle 0 hack at the moment, and there's + // not a good way to get to the current dispatcher without going through a handle + return aspace->FreeRegion(address); +} + +int sys_log_create(uint32_t flags) { + LTRACEF("flags 0x%x\n", flags); + + // kernel flag is forbidden to userspace + flags &= (~DLOG_FLAG_KERNEL); + + // create a Log dispatcher + utils::RefPtr dispatcher; + mx_rights_t rights; + mx_status_t result = LogDispatcher::Create(flags, &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + // create a handle and attach the dispatcher to it + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + auto up = UserProcess::GetCurrent(); + + mx_handle_t hv = up->MapHandleToValue(handle.get()); + up->AddHandle(utils::move(handle)); + + return hv; +} + +int sys_log_write(mx_handle_t log_handle, uint32_t len, const void* ptr, uint32_t flags) { + LTRACEF("log handle %d, len 0x%x, ptr 0x%p\n", log_handle, len, ptr); + + if (len > DLOG_MAX_ENTRY) + return ERR_TOO_BIG; + + auto up = UserProcess::GetCurrent(); + + utils::RefPtr log_dispatcher; + uint32_t log_rights; + if (!up->GetDispatcher(log_handle, &log_dispatcher, &log_rights)) + return ERR_INVALID_ARGS; + + auto log = log_dispatcher->get_log_dispatcher(); + if (!log) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(log_rights, MX_RIGHT_WRITE)) + return ERR_ACCESS_DENIED; + + char buf[DLOG_MAX_ENTRY]; + if (magenta_copy_from_user(ptr, buf, len) != NO_ERROR) + return ERR_INVALID_ARGS; + + return log->Write(buf, len, flags); +} + +int sys_log_read(mx_handle_t log_handle, uint32_t len, void* ptr, uint32_t flags) { + LTRACEF("log handle %d, len 0x%x, ptr 0x%p\n", log_handle, len, ptr); + + auto up = UserProcess::GetCurrent(); + + utils::RefPtr log_dispatcher; + uint32_t log_rights; + if (!up->GetDispatcher(log_handle, &log_dispatcher, &log_rights)) + return ERR_INVALID_ARGS; + + auto log = log_dispatcher->get_log_dispatcher(); + if (!log) + return ERR_BAD_HANDLE; + + if (!magenta_rights_check(log_rights, MX_RIGHT_READ)) + return ERR_ACCESS_DENIED; + + return log->ReadFromUser(ptr, len, flags); +} diff --git a/kernel/lib/syscalls/syscalls_priv.h b/kernel/lib/syscalls/syscalls_priv.h new file mode 100644 index 000000000..ebc5c66ae --- /dev/null +++ b/kernel/lib/syscalls/syscalls_priv.h @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +// Please don't put CDECLS here. We want the stricter declaration matching +// rules of C++. + +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) ret sys_##name(args); +#include diff --git a/kernel/lib/syscalls/syscalls_test.cpp b/kernel/lib/syscalls/syscalls_test.cpp new file mode 100644 index 000000000..fc492f4ff --- /dev/null +++ b/kernel/lib/syscalls/syscalls_test.cpp @@ -0,0 +1,35 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "syscalls_priv.h" + +int sys_syscall_test_0(void) { + return 0; +} +int sys_syscall_test_1(int a) { + return a; +} +int sys_syscall_test_2(int a, int b) { + return a + b; +} +int sys_syscall_test_3(int a, int b, int c) { + return a + b + c; +} +int sys_syscall_test_4(int a, int b, int c, int d) { + return a + b + c + d; +} +int sys_syscall_test_5(int a, int b, int c, int d, int e) { + return a + b + c + d + e; +} +int sys_syscall_test_6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} +int sys_syscall_test_7(int a, int b, int c, int d, int e, int f, int g) { + return a + b + c + d + e + f + g; +} +int sys_syscall_test_8(int a, int b, int c, int d, int e, int f, int g, int h) { + return a + b + c + d + e + f + g + h; +} diff --git a/kernel/lib/sysparam/BUILD.gn b/kernel/lib/sysparam/BUILD.gn new file mode 100644 index 000000000..78d872fad --- /dev/null +++ b/kernel/lib/sysparam/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("sysparam") { + sources = [ + "sysparam.c", + ] + deps = [ + "//kernel/lib/bio", + "//kernel/lib/console", + "//third_party/lib/cksum", + ] +} diff --git a/kernel/lib/sysparam/rules.mk b/kernel/lib/sysparam/rules.mk new file mode 100644 index 000000000..e5fca7254 --- /dev/null +++ b/kernel/lib/sysparam/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += \ + lib/bio \ + lib/cksum + +MODULE_SRCS += \ + $(LOCAL_DIR)/sysparam.c + +include make/module.mk diff --git a/kernel/lib/sysparam/sysparam.c b/kernel/lib/sysparam/sysparam.c new file mode 100644 index 000000000..6a4f34b80 --- /dev/null +++ b/kernel/lib/sysparam/sysparam.c @@ -0,0 +1,700 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* implementation of system parameter block, stored on a block device */ +/* sysparams are simple name/value pairs, with the data unstructured */ +#define LOCAL_TRACE 0 + +#define SYSPARAM_MAGIC 'SYSP' + +#define SYSPARAM_FLAG_LOCK 0x1 + +struct sysparam_phys { + uint32_t magic; + uint32_t crc32; // crc of entire structure below crc including padding + uint32_t flags; + uint16_t namelen; + uint16_t datalen; + + //uint8_t name[namelen]; + // 0 padding to next multiple of 4 + //uint8_t data[data]; + // 0 padding to next multiple of 4 + + uint8_t namedata[0]; +}; + +/* a copy we keep in memory */ +struct sysparam { + struct list_node node; + + uint32_t flags; + + char *name; + + size_t datalen; + void *data; + + /* in memory size to hold this structure, the name string, and the data */ + size_t memlen; +}; + +/* global state */ +static struct { + struct list_node list; + + bool dirty; + + bdev_t *bdev; + off_t offset; + size_t len; +} params; + +static void sysparam_init(uint level) +{ + list_initialize(¶ms.list); +} + +LK_INIT_HOOK(sysparam, &sysparam_init, LK_INIT_LEVEL_THREADING); + +static inline bool sysparam_is_locked(const struct sysparam *param) +{ + return param->flags & SYSPARAM_FLAG_LOCK; +} + +static inline size_t sysparam_len(const struct sysparam_phys *sp) +{ + size_t len = sizeof(struct sysparam_phys); + + len += ROUNDUP(sp->namelen, 4); + len += ROUNDUP(sp->datalen, 4); + + return len; +} + +static inline uint32_t sysparam_crc32(const struct sysparam_phys *sp) +{ + size_t len = sysparam_len(sp); + + LTRACEF("len %d\n", len); + uint32_t sum = crc32(0, (const void *)&sp->flags, len - 8); + LTRACEF("sum is 0x%x\n", sum); + + return sum; +} + +static struct sysparam *sysparam_create(const char *name, size_t namelen, const void *data, size_t datalen, uint32_t flags) +{ + struct sysparam *param = malloc(sizeof(struct sysparam)); + if (!param) + return NULL; + + param->flags = flags; + param->memlen = sizeof(struct sysparam); + + param->name = malloc(namelen + 1); + if (!param->name) { + free(param); + return NULL; + } + param->memlen += namelen + 1; + + memcpy(param->name, name, namelen); + param->name[namelen] = '\0'; + + param->datalen = datalen; + size_t alloclen = ROUNDUP(datalen, 4); /* allocate a multiple of 4 for padding purposes */ + param->data = malloc(alloclen); + if (!param->data) { + free(param->name); + free(param); + return NULL; + } + param->memlen += alloclen; + + memcpy(param->data, data, datalen); + memset((char *)param->data + datalen, 0, alloclen - datalen); /* zero out the trailing space */ + + return param; +} + +static struct sysparam *sysparam_read_phys(const struct sysparam_phys *sp) +{ + return sysparam_create((const char *)sp->namedata, sp->namelen, sp->namedata + ROUNDUP(sp->namelen, 4), sp->datalen, sp->flags); +} + +static struct sysparam *sysparam_find(const char *name) +{ + struct sysparam *param; + list_for_every_entry(¶ms.list, param, struct sysparam, node) { + if (strcmp(name, param->name) == 0) + return param; + } + + return NULL; +} + +status_t sysparam_scan(bdev_t *bdev, off_t offset, size_t len) +{ + status_t err = NO_ERROR; + + LTRACEF("bdev %p (%s), offset 0x%llx, len 0x%zx\n", bdev, bdev->name, offset, len); + + DEBUG_ASSERT(bdev); + DEBUG_ASSERT(len > 0); + DEBUG_ASSERT(offset + len <= bdev->total_size); + DEBUG_ASSERT((offset % bdev->block_size) == 0); + + params.bdev = bdev; + params.offset = offset; + params.len = len; + params.dirty = false; + + /* allocate a len sized block */ + uint8_t *buf = malloc(len); + if (!buf) + return ERR_NO_MEMORY; + + /* read in the sector at the scan offset */ + err = bio_read(bdev, buf, offset, len); + if (err < (ssize_t)len) { + err = ERR_IO; + goto err; + } + + LTRACEF("looking for sysparams in block:\n"); + if (LOCAL_TRACE) + hexdump(buf, len); + + size_t pos = 0; + while (pos < len) { + struct sysparam_phys *sp = (struct sysparam_phys *)(buf + pos); + + /* examine the sysparam entry, making sure it's valid */ + if (sp->magic != SYSPARAM_MAGIC) { + pos += 4; /* try searching in the next spot */ + //LTRACEF("failed magic check\n"); + continue; + } + + /* looks valid, see if length is sane */ + size_t splen = sysparam_len(sp); + if (pos + splen > offset + len) { + /* length exceeds the size of the area */ + LTRACEF("param at 0x%x: bad length\n", pos); + break; + } + + pos += splen; + + /* calculate a checksum of it */ + uint32_t sum = sysparam_crc32(sp); + + if (sp->crc32 != sum) { + /* failed checksum */ + LTRACEF("param at 0x%x: failed checksum\n", pos - splen); + continue; + } + + LTRACEF("got param at offset 0x%zx\n", pos - splen); + + struct sysparam *param = sysparam_read_phys(sp); + if (!param) { + LTRACEF("param at 0x%x: failed to make memory copy\n", pos - splen); + err = ERR_NO_MEMORY; + break; + } + + list_add_tail(¶ms.list, ¶m->node); + } + + +err: + free(buf); + + LTRACE_EXIT; + return err; +} + +status_t sysparam_reload(void) +{ + if (params.bdev == NULL) + return ERR_INVALID_ARGS; + if (params.len == 0) + return ERR_INVALID_ARGS; + + /* wipe out the existing memory entries */ + struct sysparam *param; + struct sysparam *temp; + list_for_every_entry_safe(¶ms.list, param, temp, struct sysparam, node) { + list_delete(¶m->node); + + free(param->name); + free(param->data); + free(param); + } + + /* reset the list back to scratch */ + params.dirty = false; + + status_t err = sysparam_scan(params.bdev, params.offset, params.len); + + return err; +} + +ssize_t sysparam_read(const char *name, void *data, size_t len) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (!param) + return ERR_NOT_FOUND; + + size_t toread = MIN(len, param->datalen); + memcpy(data, param->data, toread); + + return toread; +} + +ssize_t sysparam_length(const char *name) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (!param) + return ERR_NOT_FOUND; + + return param->datalen; +} + +status_t sysparam_get_ptr(const char *name, const void **ptr, size_t *len) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (!param) + return ERR_NOT_FOUND; + + if (ptr) + *ptr = param->data; + if (len) + *len = param->datalen; + + return NO_ERROR; +} + +#if SYSPARAM_ALLOW_WRITE + +/* write all of the parameters in memory to the space reserved in flash */ +status_t sysparam_write(void) +{ + if (params.bdev == NULL) + return ERR_INVALID_ARGS; + if (params.len == 0) + return ERR_INVALID_ARGS; + + if (!params.dirty) + return NO_ERROR; + + /* preflight the length, make sure we have enough space */ + struct sysparam *param; + off_t total_len = 0; + list_for_every_entry(¶ms.list, param, struct sysparam, node) { + total_len += sizeof(struct sysparam_phys); + total_len += ROUNDUP(strlen(param->name), 4); + total_len += ROUNDUP(param->datalen, 4); + } + + if (total_len > params.len) + return ERR_NO_MEMORY; + + /* allocate a buffer to stage it */ + uint8_t *buf = calloc(1, params.len); + if (!buf) { + TRACEF("error allocating buffer to stage write\n"); + return ERR_NO_MEMORY; + } + + /* erase the block device area this covers */ + ssize_t err = bio_erase(params.bdev, params.offset, params.len); + if (err < (ssize_t)params.len) { + TRACEF("error erasing sysparam area\n"); + free(buf); + return ERR_IO; + } + + /* serialize all of the parameters */ + off_t pos = 0; + list_for_every_entry(¶ms.list, param, struct sysparam, node) { + struct sysparam_phys phys; + + /* start filling out a struct */ + phys.magic = SYSPARAM_MAGIC; + phys.crc32 = 0; + phys.flags = param->flags; + phys.namelen = strlen(param->name); + phys.datalen = param->datalen; + + /* calculate the crc of the entire thing + padding */ + uint32_t zero = 0; + uint32_t sum = crc32(0, (const void *)&phys.flags, 8); + sum = crc32(sum, (const void *)param->name, strlen(param->name)); + if (strlen(param->name) % 4) + sum = crc32(sum, (const void *)&zero, 4 - (strlen(param->name) % 4)); + sum = crc32(sum, (const void *)param->data, ROUNDUP(param->datalen, 4)); + phys.crc32 = sum; + + /* structure portion */ + memcpy(buf + pos, &phys, sizeof(struct sysparam_phys)); + pos += sizeof(struct sysparam_phys); + + /* name portion */ + memcpy(buf + pos, param->name, strlen(param->name)); + pos += ROUNDUP(strlen(param->name), 2); + if (pos % 4) { + /* write 2 zeros to realign */ + pos += 2; + } + + /* data portion */ + memcpy(buf + pos, param->data, param->datalen); + pos += ROUNDUP(param->datalen, 4); + } + + /* write the block out */ + bio_write(params.bdev, buf, params.offset, params.len); + + free(buf); + + params.dirty = false; + + return NO_ERROR; +} + +status_t sysparam_add(const char *name, const void *value, size_t len) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (param) + return ERR_ALREADY_EXISTS; + + param = sysparam_create(name, strlen(name), value, len, 0); + if (!param) + return ERR_NO_MEMORY; + + list_add_tail(¶ms.list, ¶m->node); + + params.dirty = true; + + return NO_ERROR; +} + +status_t sysparam_remove(const char *name) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (!param) + return ERR_NOT_FOUND; + + if (sysparam_is_locked(param)) + return ERR_NOT_ALLOWED; + + list_delete(¶m->node); + + free(param->name); + free(param->data); + free(param); + + params.dirty = true; + + return NO_ERROR; +} + +status_t sysparam_lock(const char *name) +{ + struct sysparam *param; + + param = sysparam_find(name); + if (!param) + return ERR_NOT_FOUND; + + /* set the lock bit if it isn't already */ + if (!sysparam_is_locked(param)) { + param->flags |= SYSPARAM_FLAG_LOCK; + params.dirty = true; + } + + return NO_ERROR; +} + +#endif // SYSPARAM_ALLOW_WRITE + +#define MAX_DUMP_LEN 16 + +void sysparam_dump(bool show_all) +{ + printf("system parameters:\n"); + + size_t total_memlen = 0; + + struct sysparam *param; + list_for_every_entry(¶ms.list, param, struct sysparam, node) { + printf("________%c %-16s : ", + (param->flags & SYSPARAM_FLAG_LOCK) ? 'L' : '_', + param->name); + + const uint8_t *dat = (const uint8_t *)param->data; + uint32_t pr_len = param->datalen; + + if (!show_all) { + if (pr_len > MAX_DUMP_LEN) + pr_len = MAX_DUMP_LEN; + } + + for (uint i = 0; i < pr_len; i++) { + printf("%02x", dat[i]); + } + if (pr_len != param->datalen) + printf("...\n"); + else + printf("\n"); + + total_memlen += param->memlen; + } + + printf("total in-memory usage: %zu bytes\n", total_memlen); +} + +#if WITH_LIB_CONSOLE + +#include +#include + +static ssize_t hexstr_to_val(const char *str, uint8_t **buf) +{ + /* parse the value parameter as a hex code */ + uint8_t *hexbuffer = calloc(1, strlen(str) / 2 + 1); + uint pos; + for (pos = 0; str[pos] != 0; pos++) { + uint8_t c = str[pos]; + + if (!isxdigit(c)) { + return ERR_NOT_VALID; + } + + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 0xa; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 0xa; + + hexbuffer[pos / 2] |= (!(pos % 2)) ? (c << 4) : c; + } + pos = (pos + 1) / 2; /* round down, keeping partial bytes */ + + *buf = hexbuffer; + return pos; +} + +static int cmd_sysparam(int argc, const cmd_args *argv) +{ + status_t err; + + if (argc < 2) { +notenoughargs: + printf("ERROR not enough arguments\n"); +usage: + printf("usage: %s dump\n", argv[0].str); + printf("usage: %s list\n", argv[0].str); + printf("usage: %s reload\n", argv[0].str); +#if SYSPARAM_ALLOW_WRITE + printf("usage: %s add \n", argv[0].str); + printf("usage: %s addhex \n", argv[0].str); + printf("usage: %s addlong \n", argv[0].str); + printf("usage: %s remove \n", argv[0].str); + printf("usage: %s lock \n", argv[0].str); + printf("usage: %s write\n", argv[0].str); +#endif + printf("usage: %s length \n", argv[0].str); + printf("usage: %s read \n", argv[0].str); + return -1; + } + + err = NO_ERROR; + if (!strcmp(argv[1].str, "dump")) { + sysparam_dump(true); + } else if (!strcmp(argv[1].str, "list")) { + struct sysparam *param; + list_for_every_entry(¶ms.list, param, struct sysparam, node) { + printf("%s\n", param->name); + } + } else if (!strcmp(argv[1].str, "reload")) { + err = sysparam_reload(); +#if SYSPARAM_ALLOW_WRITE + } else if (!strcmp(argv[1].str, "add")) { + if (argc < 4) goto notenoughargs; + + err = sysparam_add(argv[2].str, argv[3].str, strlen(argv[3].str)); + } else if (!strcmp(argv[1].str, "addhex")) { + if (argc < 4) goto notenoughargs; + + /* parse the value parameter as a hex code */ + uint8_t *hexbuffer; + + ssize_t len = hexstr_to_val(argv[3].str, &hexbuffer); + if (len < 0) { + err = ERR_INVALID_ARGS; + goto done; + } + + err = sysparam_add(argv[2].str, hexbuffer, len); + free(hexbuffer); + } else if (!strcmp(argv[1].str, "addlong")) { + if (argc < 3) goto notenoughargs; + + char *str; + ssize_t buflen = 64; + ssize_t len = 0; + str = malloc(buflen + 1); + if (!str) { + err = ERR_NO_MEMORY; + goto done; + } + + for (;;) { + int c = getchar(); + if (err < 0) + break; + if (c == '\r') + continue; + if (c == '\04') /* ^d */ + break; + if (c == '\n') + break; + + if (len == buflen) { + buflen *= 2; + char *origstr = str; + str = realloc(str, buflen + 1); + if (!str) { + err = ERR_NO_MEMORY; + free(origstr); + goto done; + } + } + + str[len++] = c; + } + str[len] = '\0'; + + /* parse the value parameter as a hex code */ + uint8_t *hexbuffer; + + len = hexstr_to_val(str, &hexbuffer); + + free(str); + + if (len < 0) { + err = ERR_INVALID_ARGS; + goto done; + } + + err = sysparam_add(argv[2].str, hexbuffer, len); + + free(hexbuffer); + } else if (!strcmp(argv[1].str, "remove")) { + if (argc < 3) goto notenoughargs; + + err = sysparam_remove(argv[2].str); + } else if (!strcmp(argv[1].str, "lock")) { + if (argc < 3) goto notenoughargs; + + err = sysparam_lock(argv[2].str); + } else if (!strcmp(argv[1].str, "write")) { + err = sysparam_write(); + } else if (!strcmp(argv[1].str, "nuke")) { + ssize_t err = bio_erase(params.bdev, params.offset, params.len); + printf("erase returns %d\n", (int)err); +#endif // SYSPARAM_ALLOW_WRITE + } else if (!strcmp(argv[1].str, "length")) { + if (argc < 3) goto notenoughargs; + ssize_t len = sysparam_length(argv[2].str); + if (len >= 0) { + printf("%zu\n", (size_t)len); + } + err = (len >= 0) ? NO_ERROR : len; + } else if (!strcmp(argv[1].str, "read")) { + if (argc < 3) goto notenoughargs; + ssize_t len = sysparam_length(argv[2].str); + if (len < 0) { + err = len; + goto done; + } + uint8_t *buf = malloc(len); + if (!buf) { + err = ERR_NO_MEMORY; + goto done; + } + len = sysparam_read(argv[2].str, buf, len); + if (len < 0) { + err = len; + goto done; + } + err = NO_ERROR; + + for (int i = 0; i < len; i++) + printf("%02x", buf[i]); + printf("\n"); + free(buf); + } else { + printf("ERROR unknown command\n"); + goto usage; + } + +done: + /* shared error reporting */ + if (err >= NO_ERROR) { + printf("OK\n"); + } else if (err == ERR_NO_MEMORY) { + printf("ERROR out of memory\n"); + } else if (err == ERR_ALREADY_EXISTS) { + printf("ERROR already exists\n"); + } else if (err == ERR_INVALID_ARGS) { + printf("ERROR invalid argument\n"); + } else if (err == ERR_NOT_FOUND) { + printf("ERROR not found\n"); + } else if (err == ERR_NOT_ALLOWED) { + printf("ERROR not allowed (locked)\n"); + } else { + printf("ERROR generic error %d\n", err); + } + + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("sysparam", "commands for manipulating system parameters", &cmd_sysparam) +STATIC_COMMAND_END(sysparam); + +#endif // WITH_LIB_CONSOLE diff --git a/kernel/lib/text/BUILD.gn b/kernel/lib/text/BUILD.gn new file mode 100644 index 000000000..2e194c554 --- /dev/null +++ b/kernel/lib/text/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("text") { + sources = [ + "text.c", + ] + deps = [ + "//kernel/lib/font", + ] +} diff --git a/kernel/lib/text/rules.mk b/kernel/lib/text/rules.mk new file mode 100644 index 000000000..dcec2f70e --- /dev/null +++ b/kernel/lib/text/rules.mk @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS += lib/font + +MODULE_SRCS += \ + $(LOCAL_DIR)/text.c + +include make/module.mk diff --git a/kernel/lib/text/text.c b/kernel/lib/text/text.c new file mode 100644 index 000000000..1189c2c42 --- /dev/null +++ b/kernel/lib/text/text.c @@ -0,0 +1,85 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @addtogroup graphics + * @{ + */ + +/** + * @file + * @brief Console text display + * + * This module displays text on the console. The text is retained so that + * it can be redisplayed if the display is cleared. + * + * Output is to the default graphics display + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEXT_COLOR 0xffffffff + +static struct list_node text_list = LIST_INITIAL_VALUE(text_list); + +struct text_line { + struct list_node node; + const char *str; + int x, y; +}; + +/** + * @brief Add a string to the console text + */ +void text_draw(int x, int y, const char *string) +{ + struct text_line *line = malloc(sizeof(struct text_line)); + + line->str = strdup(string); + line->x = x; + line->y = y; + + list_add_head(&text_list, &line->node); + + text_update(); +} + +/** + * @brief Refresh the display + */ +void text_update(void) +{ + struct display_info info; + if (display_get_info(&info) < 0) + return; + + /* get the display's surface */ + gfx_surface *surface = gfx_create_surface_from_display(&info); + + struct text_line *line; + list_for_every_entry(&text_list, line, struct text_line, node) { + const char *c; + int x = line->x; + for (c = line->str; *c; c++) { + font_draw_char(surface, *c, x, line->y, TEXT_COLOR); + x += FONT_X; + } + } + + gfx_flush(surface); + + gfx_surface_destroy(surface); +} + diff --git a/kernel/lib/tftp/BUILD.gn b/kernel/lib/tftp/BUILD.gn new file mode 100644 index 000000000..cc9f37a09 --- /dev/null +++ b/kernel/lib/tftp/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_tftp_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("tftp") { + public_configs = [ ":_tftp_config" ] + public = [ + "include/lib/tftp.h", + ] + sources = [ + "tftp.c", + ] + deps = [ + "//kernel/lib/minip", + ] +} diff --git a/kernel/lib/tftp/include/lib/tftp.h b/kernel/lib/tftp/include/lib/tftp.h new file mode 100644 index 000000000..ce5cc58e3 --- /dev/null +++ b/kernel/lib/tftp/include/lib/tftp.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Carlos Pizano-Uribe +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#pragma once + +#include + +__BEGIN_CDECLS + +typedef int (*tftp_callback_t)(void *data, size_t len, void *arg); + +int tftp_server_init(void *arg); + +int tftp_set_write_client(const char *file_name, tftp_callback_t cb, void *arg); + +__END_CDECLS diff --git a/kernel/lib/tftp/rules.mk b/kernel/lib/tftp/rules.mk new file mode 100644 index 000000000..f450e7f16 --- /dev/null +++ b/kernel/lib/tftp/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + lib/minip \ + +MODULE_SRCS += \ + $(LOCAL_DIR)/tftp.c \ + +include make/module.mk diff --git a/kernel/lib/tftp/tftp.c b/kernel/lib/tftp/tftp.c new file mode 100644 index 000000000..c1bc4588c --- /dev/null +++ b/kernel/lib/tftp/tftp.c @@ -0,0 +1,268 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Carlos Pizano-Uribe +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOCAL_TRACE 0 + +// TFTP Opcodes: +#define TFTP_OPCODE_RRQ 1UL +#define TFTP_OPCODE_WRQ 2UL +#define TFTP_OPCODE_DATA 3UL +#define TFTP_OPCODE_ACK 4UL +#define TFTP_OPCODE_ERROR 5UL + +// TFTP Errors: +#define TFTP_ERROR_UNDEF 0UL +#define TFTP_ERROR_NOT_FOUND 1UL +#define TFTP_ERROR_ACCESS 2UL +#define TFTP_ERROR_FULL 3UL +#define TFTP_ERROR_ILLEGAL_OP 4UL +#define TFTP_ERROR_UNKNOWN_XFER 4UL +#define TFTP_ERROR_EXISTS 6UL +#define TFTP_ERROR_NO_SUCH_USER 7UL + +#define TFTP_PORT 69 + +#define RD_U16(ptr) \ + (uint16_t)(((uint16_t)*((uint8_t*)(ptr)+1)<<8)|(uint16_t)*(uint8_t*)(ptr)) + +static struct list_node tftp_list = LIST_INITIAL_VALUE(tftp_list); + +// Represents tftp jobs and clients of them. If |socket| is not null the +// job is in progress and members below it are valid. +typedef struct { + struct list_node list; + // Registration info. + const char *file_name; + tftp_callback_t callback; + void *arg; + // Current job info. + udp_socket_t *socket; + uint32_t src_addr; + uint16_t src_port; + uint16_t listen_port; + uint16_t pkt_count; +} tftp_job_t; + +uint16_t next_port = 2224; + +static void send_ack(udp_socket_t *socket, uint16_t count) +{ + // Packet is [4][count]. + status_t st; + uint16_t ack[] = {htons(TFTP_OPCODE_ACK), htons(count)}; + st = udp_send(ack, sizeof(ack), socket); + if (st < 0) { + LTRACEF("send_ack failed: %d\n", st); + } +} + +static void send_error(udp_socket_t *socket, uint16_t code) +{ + // Packet is [5][error code][error in ascii-string][0]. + status_t st; + uint16_t ncode = htons(code); + uint16_t err[] = { htons(TFTP_OPCODE_ERROR), ncode, + 0x7245, 0x2072, 0x3030 + ncode, 0 + }; + st = udp_send(err, sizeof(err), socket); + if (st < 0) { + LTRACEF("send_err failed: %d\n", st); + } +} + +static void end_transfer(tftp_job_t *job, bool do_callback) +{ + udp_listen(job->listen_port, NULL, NULL); + udp_close(job->socket); + job->socket = NULL; + job->src_addr = 0UL; + if (do_callback) { + job->callback(NULL, 0UL, job->arg); + } +} + +static void udp_wrq_callback(void *data, size_t len, + uint32_t srcaddr, uint16_t srcport, + void *arg) +{ + // Packet is [3][count][data]. All packets but the last have 512 + // bytes of data, including zero data. + char *data_c = data; + tftp_job_t *job = arg; + job->pkt_count++; + + if (len < 4) { + // Not to spec. Ignore. + return; + } + + if (!job->socket) { + // It is possible to have the client sent another packet + // after we called end_transfer(). + return; + } + + if ((srcaddr != job->src_addr) || (srcport != job->src_port)) { + LTRACEF("invalid source\n"); + send_error(job->socket, TFTP_ERROR_UNKNOWN_XFER); + end_transfer(job, true); + return; + } + + if (RD_U16(data_c) != htons(TFTP_OPCODE_DATA)) { + LTRACEF("invalid opcode\n"); + send_error(job->socket, TFTP_ERROR_ILLEGAL_OP); + end_transfer(job, true); + return; + } + + send_ack(job->socket, job->pkt_count); + + if (job->callback(&data_c[4], len - 4, job->arg) < 0) { + // The client wants to abort. + send_error(job->socket, TFTP_ERROR_FULL); + end_transfer(job, true); + } + + // 512 bytes payload plus 4 of fixed header. The last packet. + // has always less than 512 bytes of payload. + if (len != 516) { + end_transfer(job, true); + } +} + +static tftp_job_t *get_job_by_name(const char *file_name) +{ + DEBUG_ASSERT(file_name); + tftp_job_t *entry; + list_for_every_entry(&tftp_list, entry, tftp_job_t, list) { + if (strcmp(entry->file_name, file_name) == 0) { + return entry; + } + } + return NULL; +} + +static void udp_svc_callback(void *data, size_t len, + uint32_t srcaddr, uint16_t srcport, + void *arg) +{ + status_t st; + uint16_t opcode; + udp_socket_t *socket; + tftp_job_t *job; + + st = udp_open(srcaddr, next_port, srcport, &socket); + if (st < 0) { + LTRACEF("error opening send socket %d\n", st); + return; + } + + opcode = ntohs(RD_U16(data)); + + if (opcode != TFTP_OPCODE_WRQ) { + // Operation not suported. + LTRACEF("op not supported, opcode: %d\n", opcode); + send_error(socket, TFTP_ERROR_ACCESS); + udp_close(socket); + return; + } + + // Look for a client that can hadle the file. TODO: |data| + // needs to be null terminated. A malicious client can crash us. + job = get_job_by_name(((char *)data) + 2); + + if (!job) { + // Nobody claims to handle that file. + LTRACEF("no client registered for file\n"); + send_error(socket, TFTP_ERROR_UNKNOWN_XFER); + udp_close(socket); + return; + } + + if (job->socket) { + // There is already an ongoing job. + // TODO: garbage collect the existing one if too long since the + // last packet was processed. + LTRACEF("existing job in progress\n"); + send_error(socket, TFTP_ERROR_EXISTS); + udp_close(socket); + return; + } + + LTRACEF("write op accepted, port %d\n", srcport); + // Request accepted. The rest of the transfer happens between + // next_port <----> srcport via udp_wrq_callback(). + + job->socket = socket; + job->src_addr = srcaddr; + job->src_port = srcport; + job->pkt_count = 0UL; + job->listen_port = next_port; + + st = udp_listen(job->listen_port, &udp_wrq_callback, job); + if (st < 0) { + LTRACEF("error listening on port\n"); + return; + } + + send_ack(socket, 0UL); + next_port++; +} + +int tftp_set_write_client(const char *file_name, tftp_callback_t cb, void *arg) +{ + DEBUG_ASSERT(file_name); + DEBUG_ASSERT(cb); + + tftp_job_t *job; + + list_for_every_entry(&tftp_list, job, tftp_job_t, list) { + if (strcmp(file_name, job->file_name) == 0) { + list_delete(&job->list); + if (job->socket) { + // There is a job in progress. It will be cancelled silently. + end_transfer(job, false); + } + return 0; + } + } + + if ((job = malloc(sizeof(tftp_job_t))) == NULL) { + return -1; + } + + memset(job, 0, sizeof(tftp_job_t)); + job->file_name = file_name; + job->callback = cb; + job->arg = arg; + + list_add_tail(&tftp_list, &job->list); + return 0; +} + +int tftp_server_init(void *arg) +{ + status_t st = udp_listen(TFTP_PORT, &udp_svc_callback, 0); + return st; +} + diff --git a/kernel/lib/tga/BUILD.gn b/kernel/lib/tga/BUILD.gn new file mode 100644 index 000000000..cc8900dbd --- /dev/null +++ b/kernel/lib/tga/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_tga_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("tga") { + public_configs = [ ":_tga_config" ] + public = [ + "include/lib/tga.h", + ] + sources = [ + "tga.c", + ] +} diff --git a/kernel/lib/tga/include/lib/tga.h b/kernel/lib/tga/include/lib/tga.h new file mode 100644 index 000000000..2b7391817 --- /dev/null +++ b/kernel/lib/tga/include/lib/tga.h @@ -0,0 +1,17 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __LIB_TGA_H +#define __LIB_TGA_H + +#include +#include + +gfx_surface *tga_decode(const void *ptr, size_t len, gfx_format format); + +#endif + diff --git a/kernel/lib/tga/rules.mk b/kernel/lib/tga/rules.mk new file mode 100644 index 000000000..b9b256482 --- /dev/null +++ b/kernel/lib/tga/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/tga.c + +include make/module.mk diff --git a/kernel/lib/tga/tga.c b/kernel/lib/tga/tga.c new file mode 100644 index 000000000..a9a3aef47 --- /dev/null +++ b/kernel/lib/tga/tga.c @@ -0,0 +1,217 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2010 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/** + * @file + * @brief Parse tga format files + * + * @ingroup graphics + */ + +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct tga_header { + uint8_t idlength; + uint8_t colormaptype; + uint8_t datatypecode; + uint16_t colormaporigin; + uint16_t colormaplength; + uint8_t colormapdepth; + uint16_t x_origin; + uint16_t y_origin; + uint16_t width; + uint16_t height; + uint8_t bitsperpixel; + uint8_t imagedescriptor; +} __PACKED; + +static void print_tga_info(const struct tga_header *header) +{ + LTRACEF("idlength %hhd\n", header->idlength); + LTRACEF("colormaptype %hhd\n", header->colormaptype); + LTRACEF("datatypecode %hhd\n", header->datatypecode); + LTRACEF("colormaporigin %hd\n", header->colormaporigin); + LTRACEF("colormaplength %hd\n", header->colormaplength); + LTRACEF("colormapdepth %hhd\n", header->colormapdepth); + LTRACEF("x_origin %hd\n", header->x_origin); + LTRACEF("y_origin %hd\n", header->y_origin); + LTRACEF("width %hd\n", header->width); + LTRACEF("height %hd\n", header->height); + LTRACEF("bitsperpixel %hhd\n", header->bitsperpixel); + LTRACEF("imagedescriptor %hhd\n", header->imagedescriptor); + +} + +static void decode_2byte(gfx_surface *surface, uint x, uint y, const void *input) +{ + const uint8_t *in = (const uint8_t *)input; + +// printf("in 0x%hhx 0x%hhx\n", in[0], in[1]); + uint r,g,b; + + b = (in[0] & 0x1f) << 3; + g = (((in[0] >> 5) & 0x7) | ((in[1] & 0x3) << 3)) << 3; + r = ((in[1] >> 2) & 0x1f) << 3; + + gfx_putpixel(surface, x, y, 0xff000000 | r << 16 | g << 8 | b); +} + +static void decode_3byte(gfx_surface *surface, uint x, uint y, const void *input) +{ + const uint8_t *in = (const uint8_t *)input; + +// printf("in 0x%hhx 0x%hhx\n", in[0], in[1]); + + gfx_putpixel(surface, x, y, 0xff000000 | in[2] << 16 | in[1] << 8 | in[0]); +} + +static void decode_4byte(gfx_surface *surface, uint x, uint y, const void *input) +{ + const uint8_t *in = (const uint8_t *)input; + +// printf("in 0x%hhx 0x%hhx 0x%hhx 0x%hhx\n", in[0], in[1], in[2], in[3]); + + if (in[3] == 0) + gfx_putpixel(surface, x, y, 0); + else + gfx_putpixel(surface, x, y, in[3] << 24 | in[2] << 16 | in[1] << 8 | in[0]); +} + +/** + * @brief Decode a tga image + * + * @param ptr Pointer to tga data in memory + * @param len Length of tga data + * @param format Desired format of returned graphics surface + * + * @return Graphics surface or NULL on error. + * + * @ingroup graphics + */ +gfx_surface *tga_decode(const void *ptr, size_t len, gfx_format format) +{ + const struct tga_header *header = (const struct tga_header *)ptr; + + LTRACEF("ptr %p, len %zu\n", ptr, len); + +#if LOCAL_TRACE > 0 + print_tga_info(header); +#endif + + /* do some sanity checks */ + if (header->datatypecode != 2 && header->datatypecode != 10) { + dprintf(INFO, "tga_decode: unknown data type %d\n", header->datatypecode); + return NULL; + } + if (header->bitsperpixel != 16 && header->bitsperpixel != 24 && header->bitsperpixel != 32) { + dprintf(INFO, "tga_decode: unsupported bits per pixel %d\n", header->bitsperpixel); + return NULL; + } + if (header->colormaptype != 0) { + dprintf(INFO, "tga_decode: has colormap, can't handle\n"); + return NULL; + } + + const void *imagestart = ((const uint8_t *)ptr + sizeof(struct tga_header) + header->idlength); + + /* create a surface to hold the decoded bits */ + gfx_surface *surface = gfx_create_surface(NULL, header->width, header->height, header->width, format, 0); + DEBUG_ASSERT(surface); + + /* copy the bits out */ + void (*decodefunc)(gfx_surface *, uint x, uint y, const void *) = NULL; + + uint step = 1; + if (header->bitsperpixel == 16) { + step = 2; + decodefunc = decode_2byte; + } else if (header->bitsperpixel == 24) { + step = 3; + decodefunc = decode_3byte; + } else if (header->bitsperpixel == 32) { + step = 4; + decodefunc = decode_4byte; + } + + if (header->datatypecode == 2) { + /* no RLE */ + uint pos = 0; + uint x, y; + uint surfacey; + + for (y = 0; y < header->height; y++) { + + if ((header->imagedescriptor & (1 << 5)) == 0) + surfacey = (surface->height - 1) - y; + else + surfacey = y; + + for (x = 0; x < header->width; x++) { + decodefunc(surface, x, surfacey, (const uint8_t *)imagestart + pos); + pos += step; + } + } + } else if (header->datatypecode == 10) { + /* RLE compression */ + uint pos = 0; + uint count = 0; + uint x, y; + + x = 0; + if ((header->imagedescriptor & (1 << 5)) == 0) + y = header->height - 1; + else + y = 0; + + while (count < (uint)header->height * (uint)header->width) { + uint runpos; + + uint8_t run = *((const uint8_t *)imagestart + pos); + bool repeat_run = (run & 0x80); + uint runlen = (run & 0x7f) + 1; + +// printf("pos 0x%x count %u run 0x%hhx runtype %d runlen %u\n", pos, count, run, run & 0x80, runlen); + + /* consume the run byte */ + pos++; + + /* start of a run */ + for (runpos = 0; runpos < runlen; runpos++) { + decodefunc(surface, x, y, (const uint8_t *)imagestart + pos); + count++; + + x++; + if (x == surface->width) { + if ((header->imagedescriptor & (1 << 5)) == 0) + y--; + else + y++; + x = 0; + } + + /* if a run of raw pixels, consume an input pixel */ + if (!repeat_run) + pos += step; + } + /* if this was a run of repeated pixels, consume the one input pixel we repeated */ + if (repeat_run) + pos += step; + + } +// printf("done with RLE: x %d, y %d, pos %d, count %d\n", x, y, pos, count); + } + + return surface; +} + diff --git a/kernel/lib/unittest/BUILD.gn b/kernel/lib/unittest/BUILD.gn new file mode 100644 index 000000000..6bf8efbfa --- /dev/null +++ b/kernel/lib/unittest/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_unittest_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("unittest") { + public_configs = [ ":_unittest_config" ] + public = [ + "include/unittest.h", + ] + sources = [ + "all_tests.c", + "unittest.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/unittest/all_tests.c b/kernel/lib/unittest/all_tests.c new file mode 100644 index 000000000..5a264de70 --- /dev/null +++ b/kernel/lib/unittest/all_tests.c @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +/* + * All unit tests get registered here. A call to run_all_tests() will run + * them and provide results. + */ +#include +#include + +static struct test_case_element *test_case_list = NULL; +static struct test_case_element *failed_test_case_list = NULL; + +/* + * Registers a test case with the unit test framework. + */ +void unittest_register_test_case(struct test_case_element *elem) +{ + DEBUG_ASSERT(elem); + DEBUG_ASSERT(elem->next == NULL); + elem->next = test_case_list; + test_case_list = elem; +} + +/* + * Runs all registered test cases. + */ +bool run_all_tests(void) +{ + unsigned int n_tests = 0; + unsigned int n_success = 0; + unsigned int n_failed = 0; + + bool all_success = true; + struct test_case_element *current = test_case_list; + while (current) { + if (!current->test_case()) { + current->failed_next = failed_test_case_list; + failed_test_case_list = current; + all_success = false; + } + current = current->next; + n_tests++; + } + + if (all_success) { + n_success = n_tests; + unittest_printf("SUCCESS! All test cases passed!\n"); + } else { + struct test_case_element *failed = failed_test_case_list; + while (failed) { + struct test_case_element *failed_next = + failed->failed_next; + failed->failed_next = NULL; + failed = failed_next; + n_failed++; + } + n_success = n_tests - n_failed; + failed_test_case_list = NULL; + } + + unittest_printf("\n====================================================\n"); + unittest_printf (" CASES: %d SUCCESS: %d FAILED: %d ", + n_tests, n_success, n_failed); + unittest_printf("\n====================================================\n"); + + return all_success; +} diff --git a/kernel/lib/unittest/include/unittest.h b/kernel/lib/unittest/include/unittest.h new file mode 100644 index 000000000..52593fc33 --- /dev/null +++ b/kernel/lib/unittest/include/unittest.h @@ -0,0 +1,309 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef _LIB_UNITTEST_INCLUDE_UNITTEST_H_ +#define _LIB_UNITTEST_INCLUDE_UNITTEST_H_ +/* + * Macros for writing unit tests. + * + * Sample usage: + * + * A test case runs a collection of tests like this, with + * BEGIN_TEST_CASE and END_TEST_CASE and the beginning and end of the + * function and RUN_TEST to call each individual test, as follows: + * + * BEGIN_TEST_CASE(foo_tests); + * + * RUN_TEST(test_foo); + * RUN_TEST(test_bar); + * RUN_TEST(test_baz); + * + * END_TEST_CASE(foo_tests); + * + * This creates a static function foo_tests() and registers it with the + * unit test framework. foo_tests() can be executed either by a shell + * command or by a call to run_all_tests(), which runs all registered + * unit tests. + * + * A test looks like this, using the BEGIN_TEST and END_TEST macros at + * the beginning and end of the test and the EXPECT_* macros to + * validate test results, as shown: + * + * static bool test_foo(void) + * { + * BEGIN_TEST; + * + * ...declare variables and do stuff... + * int foo_value = foo_func(); + * ...See if the stuff produced the correct value... + * EXPECT_EQ(1, foo_value, "foo_func failed"); + * ... there are EXPECT_* macros for many conditions... + * EXPECT_TRUE(foo_condition(), "condition should be true"); + * EXPECT_NEQ(ERR_TIMED_OUT, foo_event(), "event timed out"); + * + * END_TEST; + * } + * + * To your rules.mk file, add lib/unittest to MODULE_DEPS: + * + * MODULE_DEPS += \ + * lib/unittest \ + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PRINT_BUFFER_SIZE (512) + +__BEGIN_CDECLS + +/* + * Type for unit test result Output + */ +typedef void (*test_output_func)(const char* line, int len, void* arg); + +/* + * Printf dedicated to the unittest library + * the default output is the printf + */ +void unittest_printf(const char* format, ...); + +/* + * Function to set the callback for printing + * the unit test output + */ +void unittest_set_output_function(test_output_func fun, void* arg); + +/* + * Macros to format the error string + */ +#define EXPECTED_STRING "%s:\n expected " +#define UNITTEST_TRACEF(str, x...) \ + do { \ + unittest_printf(" [FAILED] \n %s:%d:\n " str, \ + __PRETTY_FUNCTION__, __LINE__, ##x); \ + } while (0) + +/* + * BEGIN_TEST_CASE and END_TEST_CASE define a function that calls + * RUN_TEST. + */ +#define BEGIN_TEST_CASE(case_name) \ + bool case_name(void) \ + { \ + bool all_success = true; \ + unittest_printf("\nCASE %-49s [STARTED] \n", #case_name); + +#define DEFINE_REGISTER_TEST_CASE(case_name) \ + static void _register_##case_name(void) \ + { \ + unittest_register_test_case(&_##case_name##_element); \ + } \ + void (*_register_##case_name##_ptr)(void) __SECTION(".ctors") = \ + _register_##case_name; + +#define END_TEST_CASE(case_name) \ + if (all_success) { \ + unittest_printf("CASE %-59s [PASSED]\n", #case_name); \ + } else { \ + unittest_printf("CASE %-59s [FAILED]\n", #case_name); \ + } \ + return all_success; \ + } \ + static struct test_case_element _##case_name##_element = { \ + .next = NULL, \ + .failed_next = NULL, \ + .name = #case_name, \ + .test_case = case_name, \ + }; \ + DEFINE_REGISTER_TEST_CASE(case_name); + +#define RUN_TEST(test) \ + unittest_printf(" %-50s [RUNNING]", #test); \ + if (!test()) { \ + all_success = false; \ + } else { \ + unittest_printf(" [PASSED] \n"); \ + } + +/* + * BEGIN_TEST and END_TEST go in a function that is called by RUN_TEST + * and that call the EXPECT_ macros. + */ +#define BEGIN_TEST bool all_ok = true +#define END_TEST return all_ok + +#ifdef __cplusplus +#define AUTO_TYPE_VAR(type) auto& +#else +#define AUTO_TYPE_VAR(type) __typeof__(type) +#endif + +/* + * Use the EXPECT_* macros to check test results. + */ +#define EXPECT_EQ(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e != _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld), " \ + "actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_NEQ(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + if (_e == (actual)) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld), %s" \ + " to differ, but they are the same %ld\n", \ + msg, #expected, (long)_e, #actual); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_LE(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e > _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " less-than-or-equal-to actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_LT(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e >= _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " less-than actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_GE(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e < _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " greater-than-or-equal-to actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_GT(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e <= _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " greater-than actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_TRUE(actual, msg) \ + if (!(actual)) { \ + UNITTEST_TRACEF("%s: %s is false\n", msg, #actual); \ + all_ok = false; \ + } + +#define EXPECT_FALSE(actual, msg) \ + if (actual) { \ + UNITTEST_TRACEF("%s: %s is true\n", msg, #actual); \ + all_ok = false; \ + } + +#define EXPECT_BYTES_EQ(expected, actual, length, msg) \ + if (!expect_bytes_eq((expected), (actual), (length), msg)) { \ + all_ok = false; \ + } + +#define EXPECT_BYTES_NE(bytes1, bytes2, length, msg) \ + if (!memcmp(bytes1, bytes2, length)) { \ + UNITTEST_TRACEF( \ + "%s and %s are the same; " \ + "expected different\n", \ + #bytes1, #bytes2); \ + hexdump8(bytes1, length); \ + all_ok = false; \ + } + +/* For comparing uint64_t, like hw_id_t. */ +#define EXPECT_EQ_LL(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e != _a) { \ + UNITTEST_TRACEF("%s: expected %llu, actual %llu\n", msg, _e, _a); \ + all_ok = false; \ + } \ + } while (0) + +/* + * The ASSERT_* macros are similar to the EXPECT_* macros except that + * they return on failure. + */ +#define ASSERT_NOT_NULL(p) \ + if (!p) { \ + UNITTEST_TRACEF("ERROR: NULL pointer\n"); \ + return false; \ + } + +/* + * The list of test cases is made up of these elements. + */ +struct test_case_element { + struct test_case_element* next; + struct test_case_element* failed_next; + const char* name; + bool (*test_case)(void); +}; + +/* + * Registers a test case with the unit test framework. + */ +void unittest_register_test_case(struct test_case_element* elem); + +/* + * Runs all registered test cases. + */ +bool run_all_tests(void); + +/* + * Returns false if expected does not equal actual and prints msg and a hexdump8 + * of the input buffers. + */ +bool expect_bytes_eq(const uint8_t* expected, const uint8_t* actual, size_t len, + const char* msg); + +__END_CDECLS + +#endif /* _LIB_UNITTEST_INCLUDE_UNITTEST_H_ */ diff --git a/kernel/lib/unittest/rules.mk b/kernel/lib/unittest/rules.mk new file mode 100644 index 000000000..ac5d5fac8 --- /dev/null +++ b/kernel/lib/unittest/rules.mk @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/unittest.c \ + $(LOCAL_DIR)/all_tests.c \ + +include make/module.mk diff --git a/kernel/lib/unittest/unittest.c b/kernel/lib/unittest/unittest.c new file mode 100644 index 000000000..03af4d4e4 --- /dev/null +++ b/kernel/lib/unittest/unittest.c @@ -0,0 +1,74 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +/* + * Functions for unit tests. See lib/unittest/include/unittest.h for usage. + */ +#include +#include +#include +#include +#include +#include +#include + +/** + * \brief Default function to dump unit test results + * + * \param[in] line is the buffer to dump + * \param[in] len is the length of the buffer to dump + * \param[in] arg can be any kind of arguments needed to dump the values + */ +static void default_printf (const char *line, int len, void *arg) +{ + printf ("%s", line); +} + +// Default output function is the printf +static test_output_func out_func = default_printf; +// Buffer the argument to be sent to the output function +static void *out_func_arg = NULL; + +/** + * \brief Function called to dump results + * + * This function will call the out_func callback + */ +void unittest_printf (const char *format, ...) +{ + static char print_buffer[PRINT_BUFFER_SIZE]; + + va_list argp; + va_start (argp, format); + + if (out_func != NULL) { + // Format the string + vsnprintf(print_buffer, PRINT_BUFFER_SIZE, format, argp); + out_func (print_buffer, PRINT_BUFFER_SIZE, out_func_arg); + } + + va_end (argp); +} + +bool expect_bytes_eq(const uint8_t *expected, const uint8_t *actual, size_t len, + const char *msg) +{ + if (memcmp(expected, actual, len)) { + printf("%s. expected\n", msg); + hexdump8(expected, len); + printf("actual\n"); + hexdump8(actual, len); + return false; + } + return true; +} + +void unittest_set_output_function (test_output_func fun, void *arg) +{ + out_func = fun; + out_func_arg = arg; +} diff --git a/kernel/lib/user_copy/BUILD.gn b/kernel/lib/user_copy/BUILD.gn new file mode 100644 index 000000000..ea63f6686 --- /dev/null +++ b/kernel/lib/user_copy/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_user_copy_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("user_copy") { + public_configs = [ ":_user_copy_config" ] + include_dirs = [ + "//kernel/lib/heap/include", + "//kernel/lib/io/include", + "//kernel/lib/libc/include", + ] + public = [ + "include/lib/user_copy.h", + ] + sources = [ + "user_copy.c", + ] +} diff --git a/kernel/lib/user_copy/include/lib/user_copy.h b/kernel/lib/user_copy/include/lib/user_copy.h new file mode 100644 index 000000000..9807a86c1 --- /dev/null +++ b/kernel/lib/user_copy/include/lib/user_copy.h @@ -0,0 +1,69 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +#define copy_to_user arch_copy_to_user +#define copy_from_user arch_copy_from_user + +/** + * @brief Copies data from userspace into a newly allocated buffer + * + * Upon a successful call, the returned buffer is owned by the caller. + * When the caller is done with it, it can be released with free(). + * + * @param dst A pointer to write the allocated buffer into + * @param src The userspace buffer to copy + * @param len The length of the userspace buffer + * @param max_len The maximum allowed length of the userspace buffer + * + * @return NO_ERROR on success + * @return ERR_NO_MEMORY on allocation failure + * @return ERR_INVALID_ARGS if len > max_len + * @return See copy_from_user for other possible errors + */ +status_t copy_from_user_dynamic( + void **dst, + const void *src, + size_t len, + size_t max_len); + +// Convenience functions for common data types +#define MAKE_COPY_TO_USER(name, type) \ + static inline status_t name(type *dst, type value) { \ + return copy_to_user(dst, &value, sizeof(type)); \ + } + +MAKE_COPY_TO_USER(copy_to_user_u8, uint8_t); +MAKE_COPY_TO_USER(copy_to_user_u16, uint16_t); +MAKE_COPY_TO_USER(copy_to_user_32, int32_t); +MAKE_COPY_TO_USER(copy_to_user_u32, uint32_t); +MAKE_COPY_TO_USER(copy_to_user_u64, uint64_t); +MAKE_COPY_TO_USER(copy_to_user_uptr, uintptr_t); + +#undef MAKE_COPY_TO_USER + +#define MAKE_COPY_FROM_USER(name, type) \ + static inline status_t name(type *dst, type *src) { \ + return copy_from_user(dst, src, sizeof(type)); \ + } + +MAKE_COPY_FROM_USER(copy_from_user_u8, uint8_t); +MAKE_COPY_FROM_USER(copy_from_user_u16, uint16_t); +MAKE_COPY_FROM_USER(copy_from_user_u32, uint32_t); +MAKE_COPY_FROM_USER(copy_from_user_32, int32_t); +MAKE_COPY_FROM_USER(copy_from_user_u64, uint64_t); +MAKE_COPY_FROM_USER(copy_from_user_uptr, uintptr_t); + +#undef MAKE_COPY_FROM_USER + +__END_CDECLS diff --git a/kernel/lib/user_copy/rules.mk b/kernel/lib/user_copy/rules.mk new file mode 100644 index 000000000..7ece6408b --- /dev/null +++ b/kernel/lib/user_copy/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/user_copy.c \ + +include make/module.mk diff --git a/kernel/lib/user_copy/user_copy.c b/kernel/lib/user_copy/user_copy.c new file mode 100644 index 000000000..f28afe0b3 --- /dev/null +++ b/kernel/lib/user_copy/user_copy.c @@ -0,0 +1,47 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include + +status_t copy_from_user_dynamic( + void **dst, + const void *src, + size_t len, + size_t max_len) +{ + DEBUG_ASSERT(dst); + if (len > max_len) { + return ERR_INVALID_ARGS; + } + void *buf = calloc(len, 1); + if (!buf) { + return ERR_NO_MEMORY; + } + status_t status = copy_from_user(buf, src, len); + if (status != NO_ERROR) { + free(buf); + return status; + } + *dst = buf; + return NO_ERROR; +} + +// Default implementations of arch_copy* functions, almost certainly +// want to override with arch-specific versions that check access permissions +__WEAK status_t arch_copy_from_user(void *dst, const void *src, size_t len) { + memcpy(dst, src, len); + return NO_ERROR; +} + +__WEAK status_t arch_copy_to_user(void *dst, const void *src, size_t len) { + memcpy(dst, src, len); + return NO_ERROR; +} diff --git a/kernel/lib/userboot/BUILD.gn b/kernel/lib/userboot/BUILD.gn new file mode 100644 index 000000000..2b15712ab --- /dev/null +++ b/kernel/lib/userboot/BUILD.gn @@ -0,0 +1,50 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") + +declare_args() { + # Userboot filesystem image filename. + user_bootfs = "$root_gen_dir/user.bootfs" +} + +# Whether to embed the bootfs into the kernel image. +embed_user_bootfs = enable_magenta && enable_userboot + +config("enable_userboot") { + if (enable_userboot) { + defines = [ "WITH_LIB_USERBOOT=1" ] + } else { + defines = [ "WITH_LIB_USERBOOT=0" ] + } +} + +# TODO(phosek): this should be enabled only if magenta is +module("userboot") { + public_configs = [ ":enable_userboot" ] + sources = [ + "userboot.cpp", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/elf", + "//kernel/lib/libc", + "//kernel/lib/magenta", + "//kernel/lib/utils", + ] + if (enable_shell) { + deps += [ "//kernel/app/shell" ] + } + if (embed_user_bootfs) { + bootfs_file = rebase_path(user_bootfs, root_build_dir) + defines = [ + "EMBED_USER_BOOTFS=1", + "USER_BOOTFS_FILENAME=\"${bootfs_file}\"", + ] + sources += [ "bootfs.S" ] + deps += [ "//kernel/project/virtual:bootfs" ] + } +} diff --git a/kernel/lib/userboot/bootfs.S b/kernel/lib/userboot/bootfs.S new file mode 100644 index 000000000..0d8d7565c --- /dev/null +++ b/kernel/lib/userboot/bootfs.S @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +.section .bootfs +.align 4 + +// include the bootfs archive containing user +DATA(user_bootfs) +.incbin USER_BOOTFS_FILENAME + +user_bootfs_end: +.size user_bootfs, user_bootfs_end - user_bootfs + +DATA(user_bootfs_len) + .int user_bootfs_end - user_bootfs +.size user_bootfs_len, . - user_bootfs_len diff --git a/kernel/lib/userboot/rules.mk b/kernel/lib/userboot/rules.mk new file mode 100644 index 000000000..54de7e904 --- /dev/null +++ b/kernel/lib/userboot/rules.mk @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/userboot.cpp + +MODULE_DEPS := \ + lib/elf + +ifeq ($(call TOBOOL,$(EMBED_USER_BOOTFS)),true) +MODULE_SRCDEPS += $(USER_BOOTFS) +MODULE_DEFINES += EMBED_USER_BOOTFS=1 +MODULE_COMPILEFLAGS += -DUSER_BOOTFS_FILENAME="\"$(USER_BOOTFS)\"" +MODULE_SRCS += $(LOCAL_DIR)/bootfs.S +endif + +include make/module.mk diff --git a/kernel/lib/userboot/userboot.cpp b/kernel/lib/userboot/userboot.cpp new file mode 100644 index 000000000..f0152e74a --- /dev/null +++ b/kernel/lib/userboot/userboot.cpp @@ -0,0 +1,133 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USERBOOT_PAYLOAD 0x2000000 + +static int join_thread(void* arg) { + //UserProcess* proc = (UserProcess*)arg; + + // TODO: block on the process in some other way + //proc->Join(nullptr); + //delete proc; + return 0; +} + +static int attempt_userboot(const void* userboot, size_t ublen, + const void* bootfs, size_t bfslen) { + dprintf(INFO, "userboot: bootfs @%p (%zd)\n", bootfs, bfslen); + dprintf(INFO, "userboot: userboot @%p (%zd)\n", userboot, ublen); + + utils::unique_ptr proc(new UserProcess("userboot")); + if (!proc) { + return ERR_NO_MEMORY; + } + status_t err = proc->Initialize(); + if (err != NO_ERROR) { + return err; + } + + auto aspace = proc->aspace(); + + ElfLoader::MemFile loader("userboot", aspace, userboot, ublen); + if ((err = loader.Load()) != NO_ERROR) { + return err; + } + + // map bootfs into the userboot process + auto vmo = VmObject::Create(PMM_ALLOC_FLAG_ANY, bfslen); + if (!vmo) { + return ERR_NO_MEMORY; + } + + size_t written; + if (vmo->Write(bootfs, 0, bfslen, &written) < 0) { + return ERR_NO_MEMORY; + } + + // create a Vm Object dispatcher + utils::RefPtr dispatcher; + mx_rights_t rights; + mx_status_t result = VmObjectDispatcher::Create(utils::move(vmo), &dispatcher, &rights); + if (result != NO_ERROR) + return result; + + // create a handle and attach the dispatcher to it + HandleUniquePtr handle(MakeHandle(utils::move(dispatcher), rights)); + if (!handle) + return ERR_NO_MEMORY; + + mx_handle_t hv = proc->MapHandleToValue(handle.get()); + proc->AddHandle(utils::move(handle)); + + err = proc->Start((void*)(uintptr_t)hv, loader.entry()); + if (err != NO_ERROR) { + printf("userboot: failed to start process %d\n", err); + return err; + } + + // create a thread to Join and delete the UserProcess so we don't leak + thread_detach_and_resume(thread_create("join_thread", &join_thread, proc.get(), + DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); + proc.release(); + return NO_ERROR; +} + +#if EMBED_USER_BOOTFS +extern "C" uint8_t user_bootfs[]; +extern "C" uint32_t user_bootfs_len; + +#define FSMAGIC "[BOOTFS]\0\0\0\0\0\0\0\0" + +// bootfs contains multiple entries, but the first one +// must be the userboot binary, so we only need to be +// concerned with it +typedef struct bootfs { + uint8_t magic[16]; + uint32_t namelen; + uint32_t size; + uint32_t offset; +} bootfs_t; + +void userboot_init(uint level) { + bootfs_t* bootfs = (bootfs_t*)user_bootfs; + +#if !WITH_APP_SHELL + dprintf(INFO, "userboot: console init\n"); + console_init(); +#endif + + if (user_bootfs_len < sizeof(bootfs_t)) { + return; + } + if (memcmp(bootfs->magic, FSMAGIC, 16)) { + dprintf(INFO, "userboot: bad magic in bootfs\n"); + return; + } + if (bootfs->offset >= user_bootfs_len) { + return; + } + if (bootfs->size > (user_bootfs_len - bootfs->offset)) { + return; + } + attempt_userboot(user_bootfs + bootfs->offset, bootfs->size, + user_bootfs, user_bootfs_len); +} + +LK_INIT_HOOK(userboot, userboot_init, LK_INIT_LEVEL_APPS - 1); +#endif diff --git a/kernel/lib/utils/BUILD.gn b/kernel/lib/utils/BUILD.gn new file mode 100644 index 000000000..b643e615e --- /dev/null +++ b/kernel/lib/utils/BUILD.gn @@ -0,0 +1,36 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_utils_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("utils") { + public_configs = [ ":_utils_config" ] + public = [ + "include/utils/arena.h", + "include/utils/array.h", + "include/utils/auto_call.h", + "include/utils/hash_table.h", + "include/utils/intrusive_double_list.h", + "include/utils/intrusive_single_list.h", + "include/utils/limits.h", + "include/utils/list_utils.h", + "include/utils/ref_counted.h", + "include/utils/ref_counted_internal.h", + "include/utils/ref_ptr.h", + "include/utils/string_piece.h", + "include/utils/type_support.h", + "include/utils/unique_ptr.h", + ] + sources = [ + "arena.cpp", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/utils/arena.cpp b/kernel/lib/utils/arena.cpp new file mode 100644 index 000000000..3b6b75138 --- /dev/null +++ b/kernel/lib/utils/arena.cpp @@ -0,0 +1,103 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include + +#include + +namespace utils { + +Arena::Arena() + : ob_size_(0u), + c_start_(nullptr), + c_top_(nullptr), + d_start_(nullptr), + d_top_(nullptr), + d_end_(nullptr) {} + +Arena::~Arena() { + free_.clear(); + auto kspace = vmm_get_kernel_aspace(); + if (c_start_) vmm_free_region(kspace, reinterpret_cast(c_start_)); + if (d_start_) vmm_free_region(kspace, reinterpret_cast(d_start_)); +} + +status_t Arena::Init(const char* name, size_t ob_size, size_t count) { + if (!ob_size) return ERR_INVALID_ARGS; + if (!count) return ERR_INVALID_ARGS; + + ob_size_ = ob_size; + + char vname[24 + 8] = {}; + if (strlen(name) >= (sizeof(vname) - 8)) return ERR_INVALID_ARGS; + + auto kspace = vmm_get_kernel_aspace(); + void* start = nullptr; + status_t st; + + sprintf(vname, "%s_ctrl", name); + st = vmm_alloc(kspace, vname, count * sizeof(Node), &start, PAGE_SIZE_SHIFT, 0, + ARCH_MMU_FLAG_PERM_NO_EXECUTE); + if (st < 0) return st; + + c_start_ = reinterpret_cast(start); + c_top_ = c_start_; + + sprintf(vname, "%s_data", name); + st = vmm_alloc(kspace, vname, count * ob_size, &start, PAGE_SIZE_SHIFT, 0, + ARCH_MMU_FLAG_PERM_NO_EXECUTE); + if (st < 0) { + vmm_free_region(kspace, reinterpret_cast(c_start_)); + return st; + } + + d_start_ = reinterpret_cast(start); + d_top_ = d_start_; + + d_end_ = d_start_ + count * ob_size; + + return NO_ERROR; +} + +void* Arena::Alloc() { + // Prefers to give a previously used memory in the hopes that it is + // still in the cache. + if (!free_.is_empty()) { + auto node = free_.pop_front(); + c_top_ -= sizeof(Node); + return node->slot; + } else if (d_top_ < d_end_) { + auto slot = d_top_; + d_top_ += ob_size_; + return slot; + } else { + return nullptr; + } +} + +void Arena::Free(void* addr) { + if (!addr) return; + DEBUG_ASSERT((addr >= d_start_) && (addr < d_end_)); + + auto node = new (reinterpret_cast(c_top_)) Node{nullptr, addr}; + c_top_ += sizeof(Node); + free_.push_front(node); +} + +size_t Arena::Trim() { + // TODO(cpu). Impement this. The general idea is: + // 1 - find max |slot| in the |free_| list. + // 2 - compute pages bettween max of #1 and |d_end_| + // 3- free pages, adjust d_end_, etc; + return 0u; +} +} diff --git a/kernel/lib/utils/include/utils/arena.h b/kernel/lib/utils/include/utils/arena.h new file mode 100644 index 000000000..72c73568e --- /dev/null +++ b/kernel/lib/utils/include/utils/arena.h @@ -0,0 +1,106 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +#include +#include + +namespace utils { + +// Arena is a fast memory allocator for objects of a single size. +// Both Alloc() and Free() are always O(1) and memory always comes +// from a single contigous chunck of page-aligned memory. +// +// The control structures and data are not interleaved so it is +// more resilient to memory bugs than traditional pool allocators. +// +// The overhead per object is two pointers (16 bytes in 64-bits) + +class Arena { +public: + Arena(); + ~Arena(); + + status_t Init(const char* name, size_t ob_size, size_t max_count); + void* Alloc(); + void Free(void* addr); + size_t Trim(); + + bool in_range(void* addr) const { + return ((addr >= static_cast(d_start_)) && + (addr < static_cast(d_top_))); + } + + void* start() const { return d_start_; } + void* end() const { return d_end_; } + +private: + Arena(const Arena&) = delete; + Arena& operator=(const Arena&) = delete; + + struct Node { + Node* next; + void* slot; + + Node* list_next() { + return next; + } + const Node* list_next() const { + return next; + } + void list_set_next(Node* node) { + next = node; + } + }; + + SinglyLinkedList free_; + + size_t ob_size_; + + // Control region pointers. + char* c_start_; + char* c_top_; + // Data region pointers. + char* d_start_; + char* d_top_; + char* d_end_; +}; + +template +class TypedArena { +public: + status_t Init(const char* name, size_t max_count) { + return arena_.Init(name, sizeof(T), max_count); + } + + template + T* New(Args&&... args) { + void* addr = arena_.Alloc(); + return addr ? new (addr) T(utils::forward(args)...) : nullptr; + }; + + void Delete(T* obj) { + obj->~T(); + arena_.Free(obj); + } + + void RawFree(void* mem) { + arena_.Free(mem); + } + + bool in_range(void* obj) const { return arena_.in_range(obj); } + + void* start() const { return arena_.start(); } + void* end() const { return arena_.end(); } + +private: + Arena arena_; +}; +} diff --git a/kernel/lib/utils/include/utils/array.h b/kernel/lib/utils/include/utils/array.h new file mode 100644 index 000000000..5cbf04a85 --- /dev/null +++ b/kernel/lib/utils/include/utils/array.h @@ -0,0 +1,86 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +namespace utils { + +template > +class Array { +public: + constexpr Array() : ptr_(nullptr), count_(0U) {} + constexpr Array(decltype(nullptr)) : Array() {} + + Array(T* array, size_t count) : ptr_(array), count_(count) {} + + Array(Array&& other) : ptr_(nullptr), count_(other.count_) { + ptr_ = other.release(); + } + + size_t size() const { + return count_; + } + + ~Array() { + if (ptr_) Deleter()(ptr_); + } + + Array& operator=(Array&& o) { + auto count = o.count_; + reset(o.release(), count); + return *this; + } + + Array(const Array& o) = delete; + Array& operator=(const Array& o) = delete; + + T* release() { + T* t = ptr_; + ptr_ = nullptr; + count_ = 0; + return t; + } + + void reset() { + reset(nullptr, 0U); + } + + void reset(T* t, size_t count) { + if (ptr_) Deleter()(ptr_); + ptr_ = t; + count_ = count; + } + + void swap(Array& other) { + T* t = ptr_; + ptr_ = other.ptr_; + other.ptr_ = t; + size_t c = count_; + count_ = other.count_; + other.count_ = c; + } + + T* get() const { + return ptr_; + } + + explicit operator bool() const { + return static_cast(ptr_); + } + + T& operator[](size_t i) const { + DEBUG_ASSERT(i < count_); + return ptr_[i]; + } + +private: + T* ptr_; + size_t count_; +}; +} diff --git a/kernel/lib/utils/include/utils/auto_call.h b/kernel/lib/utils/include/utils/auto_call.h new file mode 100644 index 000000000..03fd6fd24 --- /dev/null +++ b/kernel/lib/utils/include/utils/auto_call.h @@ -0,0 +1,75 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +// RAII class to automatically call a function-like thing as it goes out of +// scope +// +// Examples: +// +// extern int foo(); +// int a; +// +// auto ac = MakeAutoCall([&](){ a = 1; }); +// auto ac2 = MakeAutoCall(foo); +// +// auto func = [&](){ a = 2; }; +// AutoCall ac3(func); +// AutoCall ac4(&foo); +// +// // abort the call +// ac2.cancel(); +namespace utils { + +template +class AutoCall { +public: + constexpr explicit AutoCall(T c) : call_(move(c)) {} + ~AutoCall() { + call(); + } + + // move semantics + AutoCall(AutoCall&& c) : call_(move(c.call_)), active_(c.active_) { + c.cancel(); + } + + AutoCall& operator=(AutoCall&& c) { + call_ = move(c.call_); + c.cancel(); + } + + // no copy + AutoCall(const AutoCall& c) = delete; + AutoCall& operator=(const AutoCall& c) = delete; + + // cancel the eventual call + void cancel() { + active_ = false; + } + + // call it immediately + void call() { + if (active_) (call_)(); + cancel(); + } + +private: + T call_; + bool active_ = true; +}; + +// helper routine to create an autocall object without needing template +// specialization +template +inline AutoCall MakeAutoCall(T c) { + return AutoCall(move(c)); +} + +}; // namespace utils diff --git a/kernel/lib/utils/include/utils/hash_table.h b/kernel/lib/utils/include/utils/hash_table.h new file mode 100644 index 000000000..48cc7b4a5 --- /dev/null +++ b/kernel/lib/utils/include/utils/hash_table.h @@ -0,0 +1,80 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +namespace utils { + +// The number of buckets should be a nice prime such as 37, 211, 389 unless +// The hash function is really good. Lots of cheap hash functions have hidden +// periods for which the mod with prime above 'mostly' fixes. + +template > +class HashTable { +public: + constexpr HashTable() {} + ~HashTable() { + DEBUG_ASSERT(count_ == 0); + } + + void add(Key key, T* entry) { + ++count_; + SetHashTableKey(entry, key); + GetBucket(key).push_front(entry); + } + + T* get(Key key) { + T* found = + find_if(&GetBucket(key), [key](T* entry) { return key == GetHashTableKey(entry); }); + return found; + } + + T* remove(Key key) { + T* found = + pop_if(&GetBucket(key), [key](T* entry) { return key == GetHashTableKey(entry); }); + if (found) --count_; + return found; + } + + void clear() { + for (auto& e : buckets_) { + e.clear(); + } + count_ = 0; + } + + size_t size() const { + return count_; + } + bool is_empty() const { + return count_ == 0; + } + + template + void for_each(UnaryFn fn) { + for (auto& e : buckets_) { + utils::for_each(&e, fn); + } + } + +private: + SinglyLinkedList& GetBucket(Key key) { + return buckets_[hashfn_(key) % num_buckets]; + } + + HashTable(const HashTable&) = delete; + HashTable& operator=(const HashTable&) = delete; + + size_t count_ = 0UL; + SinglyLinkedList buckets_[num_buckets]; + HashFn hashfn_; +}; +} diff --git a/kernel/lib/utils/include/utils/intrusive_double_list.h b/kernel/lib/utils/include/utils/intrusive_double_list.h new file mode 100644 index 000000000..079a2ab6a --- /dev/null +++ b/kernel/lib/utils/include/utils/intrusive_double_list.h @@ -0,0 +1,195 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +namespace utils { + +template +struct DoublyLinkedListTraits { + static T* prev(T* obj) { + return obj->list_prev(); + } + static const T* prev(const T* obj) { + return obj->list_prev(); + } + static T* next(T* obj) { + return obj->list_next(); + } + static const T* next(const T* obj) { + return obj->list_next(); + } + + static void set_prev(T* obj, T* prev) { + return obj->list_set_prev(prev); + } + static void set_next(T* obj, T* next) { + return obj->list_set_next(next); + } +}; + +template > +class DoublyLinkedList { +public: + using ValueType = T; + + static void reset(ValueType* obj) { + Traits::set_prev(obj, obj); + Traits::set_next(obj, obj); + } + + constexpr DoublyLinkedList() : head_(nullptr) {} + ~DoublyLinkedList() { + DEBUG_ASSERT(is_empty()); + } + + bool is_empty() const { + return (head_ == nullptr); + } + + void clear() { + head_ = nullptr; + } + + void push_front(ValueType* obj) { + if (!head_) { + head_ = obj; + reset(head_); + return; + } + + auto tail = Traits::prev(head_); + + Traits::set_next(obj, head_); + Traits::set_prev(obj, tail); + Traits::set_prev(head_, obj); + Traits::set_next(tail, obj); + + head_ = obj; + } + + void push_back(ValueType* obj) { + if (!head_) { + head_ = obj; + reset(head_); + return; + } + + auto tail = Traits::prev(head_); + + Traits::set_prev(obj, tail); + Traits::set_next(obj, head_); + Traits::set_next(tail, obj); + Traits::set_prev(head_, obj); + } + + void add_after(ValueType *after, ValueType* obj) { + auto next = Traits::next(after); + + Traits::set_prev(obj, after); + Traits::set_next(obj, next); + Traits::set_next(after, obj); + Traits::set_prev(next, obj); + } + + void add_before(ValueType *before, ValueType* obj) { + auto prev = Traits::prev(before); + + Traits::set_prev(obj, prev); + Traits::set_next(obj, before); + Traits::set_prev(before, obj); + Traits::set_next(prev, obj); + + if (head_ == before) { + head_ = obj; + } + } + + ValueType* pop_front() { + return is_empty() ? nullptr : pop_front_unsafe(); + } + + ValueType* pop_back() { + return is_empty() ? nullptr : remove(Traits::prev(head_)); + } + + ValueType* remove(ValueType* obj) { + return (obj == head_) ? pop_front_unsafe() : remove_unsafe(obj); + } + + ValueType* first() { + return head_; + } + const ValueType* first() const { + return head_; + } + + ValueType* last() { + return is_empty() ? nullptr : Traits::prev(head_); + } + + const ValueType* last() const { + return is_empty() ? nullptr : Traits::prev(head_); + } + + ValueType* prev(ValueType* obj) const { + return (head_ == obj) ? nullptr : Traits::prev(obj); + } + + const ValueType* prev(const ValueType* obj) const { + return (head_ == obj) ? nullptr : Traits::prev(obj); + } + + ValueType* next(ValueType* obj) const { + auto next = Traits::next(obj); + return (head_ == next) ? nullptr : next; + } + + const ValueType* next(const ValueType* obj) const { + auto next = Traits::next(obj); + return (head_ == next) ? nullptr : next; + } + + size_t size_slow() const { + size_t count = 0; + const ValueType* t = head_; + while (t) { + ++count; + t = next(t); + } + return count; + } + +private: + static ValueType* remove_unsafe(ValueType* obj) { + auto next = Traits::next(obj); + auto prev = Traits::prev(obj); + Traits::set_prev(next, prev); + Traits::set_next(prev, next); + Traits::set_prev(obj, nullptr); + Traits::set_next(obj, nullptr); + return obj; + } + + ValueType* pop_front_unsafe() { + auto list_next = Traits::next(head_); + if (list_next == head_) { + head_ = nullptr; + Traits::set_prev(list_next, nullptr); + Traits::set_next(list_next, nullptr); + return list_next; + } + ValueType* t = head_; + head_ = list_next; + return remove_unsafe(t); + } + + ValueType* head_; +}; + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/intrusive_single_list.h b/kernel/lib/utils/include/utils/intrusive_single_list.h new file mode 100644 index 000000000..b88d28a32 --- /dev/null +++ b/kernel/lib/utils/include/utils/intrusive_single_list.h @@ -0,0 +1,105 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +namespace utils { + +template +struct SinglyLinkedListTraits { + static T* next(T* node) { + return node->list_next(); + } + static const T* next(const T* node) { + return node->list_next(); + } + static void set_next(T* node, T* next) { + node->list_set_next(next); + } +}; + +template > +class SinglyLinkedList { +public: + using ValueType = T; + + constexpr SinglyLinkedList() {} + ~SinglyLinkedList() { + DEBUG_ASSERT(is_empty()); + } + + ValueType* first() { + return head_; + } + const ValueType* first() const { + return head_; + } + + ValueType* next(ValueType* node) { + return Traits::next(node); + } + const ValueType* next(const ValueType* node) const { + return Traits::next(node); + } + + bool is_empty() const { + return head_ == nullptr; + } + + void push_front(ValueType* node) { + Traits::set_next(node, head_); + head_ = node; + } + + void add_after(ValueType *after, ValueType* node) { + auto next = Traits::next(after); + + Traits::set_next(node, next); + Traits::set_next(after, node); + } + + ValueType* pop_front() { + if (is_empty()) return nullptr; + auto t = head_; + head_ = Traits::next(head_); + Traits::set_next(t, nullptr); + return t; + } + + ValueType* pop_next(ValueType* prev) { + auto node = Traits::next(prev); + auto next = Traits::next(node); + Traits::set_next(prev, next); + Traits::set_next(node, nullptr); + return node; + } + + size_t size_slow() const { + size_t count = 0; + const ValueType* t = head_; + while (t) { + ++count; + t = Traits::next(t); + } + return count; + } + + void clear() { + head_ = nullptr; + } + +private: + SinglyLinkedList(const SinglyLinkedList&) = delete; + SinglyLinkedList& operator=(const SinglyLinkedList&) = delete; + + ValueType* head_ = nullptr; +}; + +// TODO: support C++11 range iterator. + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/limits.h b/kernel/lib/utils/include/utils/limits.h new file mode 100644 index 000000000..13b820325 --- /dev/null +++ b/kernel/lib/utils/include/utils/limits.h @@ -0,0 +1,101 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +namespace utils { + +template +class numeric_limits {}; + +#define SPECIALIZE_INT(type, sign, modulo, digits_, min_, max_) \ + template <> \ + class numeric_limits { \ + public: \ + static constexpr bool is_specialized = true; \ + static constexpr bool is_signed = (sign); \ + static constexpr bool is_integer = true; \ + static constexpr bool is_exact = true; \ + static constexpr bool has_infinity = false; \ + static constexpr bool has_quiet_NaN = false; \ + static constexpr bool has_signaling_NaN = false; \ + static constexpr bool has_denorm = false; \ + static constexpr bool has_denorm_loss = false; \ + static constexpr bool round_style = false; \ + static constexpr bool is_iec559 = false; \ + static constexpr bool is_bounded = true; \ + static constexpr bool is_modulo = (modulo); \ + static constexpr int digits = (digits_); \ + static constexpr int digits10 = (digits_) * 3 / 10; \ + static constexpr int max_digits10 = 0; \ + static constexpr int radix = 2; \ + static constexpr int min_exponent = 0; \ + static constexpr int min_exponent10 = 0; \ + static constexpr int max_exponent = 0; \ + static constexpr int max_exponent10 = 0; \ + static constexpr bool traps = false; \ + static constexpr bool tinyness_before = false; \ + static constexpr type min() { \ + return (min_); \ + } \ + static constexpr type lowest() { \ + return (min_); \ + } \ + static constexpr type max() { \ + return (max_); \ + } \ + static constexpr type epsilon() { \ + return 0; \ + } \ + static constexpr type round_error() { \ + return 0; \ + } \ + static constexpr type infinity() { \ + return 0; \ + } \ + static constexpr type quiet_NaN() { \ + return 0; \ + } \ + static constexpr type signaling_NaN() { \ + return 0; \ + } \ + static constexpr type denorm_min() { \ + return 0; \ + } \ + } + +#define SPECIALIZE_SIGNED(type, min, max) \ + SPECIALIZE_INT(type, true, false, CHAR_BIT * sizeof(type) - 1, min, max) + +#define SPECIALIZE_UNSIGNED(type, min, max) \ + SPECIALIZE_INT(type, false, true, CHAR_BIT * sizeof(type), min, max) + +SPECIALIZE_INT(bool, false, true, 1, false, true); +#if CHAR_MIN == 0 +SPECIALIZE_SIGNED(char, CHAR_MIN, CHAR_MAX); +#else +SPECIALIZE_UNSIGNED(char, CHAR_MIN, CHAR_MAX); +#endif +SPECIALIZE_SIGNED(signed char, SCHAR_MIN, SCHAR_MAX); +SPECIALIZE_UNSIGNED(unsigned char, 0, UCHAR_MAX); + +SPECIALIZE_SIGNED(short, SHRT_MIN, SHRT_MAX); +SPECIALIZE_UNSIGNED(unsigned short, 0, USHRT_MAX); +SPECIALIZE_SIGNED(int, INT_MIN, INT_MAX); +SPECIALIZE_UNSIGNED(unsigned int, 0, UINT_MAX); +SPECIALIZE_SIGNED(long, LONG_MIN, LONG_MAX); +SPECIALIZE_UNSIGNED(unsigned long, 0, ULONG_MAX); +SPECIALIZE_SIGNED(long long, LLONG_MIN, LLONG_MAX); +SPECIALIZE_UNSIGNED(unsigned long long, 0, ULLONG_MAX); + +#undef SPECIALIZE_SIGNED +#undef SPECIALIZE_UNSIGNED +#undef SPECIALIZE_INT + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/list_utils.h b/kernel/lib/utils/include/utils/list_utils.h new file mode 100644 index 000000000..012bc589f --- /dev/null +++ b/kernel/lib/utils/include/utils/list_utils.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +namespace utils { + +template +void for_each(List* list, UnaryFn fn) { + for (typename List::ValueType* node = list->first(); node; node = list->next(node)) { + fn(node); + } +} + +template +typename List::ValueType* find_if(List* list, UnaryFn fn) { + for (typename List::ValueType* node = list->first(); node; node = list->next(node)) { + if (fn(node)) return node; + } + return nullptr; +} + +template +typename List::ValueType* pop_if(List* list, UnaryFn fn) { + typename List::ValueType* prev = nullptr; + for (typename List::ValueType* node = list->first(); node; node = list->next(node)) { + if (fn(node)) return prev ? list->pop_next(prev) : list->pop_front(); + prev = node; + } + return nullptr; +} + +template +size_t move_if(List* list_src, List* list_dst, UnaryFn fn) { + size_t count = 0; + typename List::ValueType* prev = nullptr; + typename List::ValueType* node = list_src->first(); + + while (node) { + if (!fn(node)) { + prev = node; + node = list_src->next(node); + continue; + } + + typename List::ValueType* moved; + if (prev) { + moved = list_src->pop_next(prev); + node = prev; + } else { + moved = list_src->pop_front(); + node = list_src->first(); + } + + list_dst->push_front(moved); + ++count; + } + return count; +} + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/ref_counted.h b/kernel/lib/utils/include/utils/ref_counted.h new file mode 100644 index 000000000..5582e5de0 --- /dev/null +++ b/kernel/lib/utils/include/utils/ref_counted.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +namespace utils { + +// Base class for a reference counted type. Use as +// +// class Handle : public RefCounted { +// }; +// +// This supports intrusive atomic reference counting with adoption. This means +// that a new object starts life at a reference count of 1 and has to be adopted +// by a type (such as a utils::RefPtr) that begins manipulation of the reference +// count. If the reference count ever reaches zero, the object's lifetime is +// over and it should be destroyed (Release() returns true if this is the case). +template +class RefCounted : public internal::RefCountedBase { +public: + RefCounted() {} + ~RefCounted() {} + + using internal::RefCountedBase::AddRef; + using internal::RefCountedBase::Release; + +#if (LK_DEBUGLEVEL > 0) + using internal::RefCountedBase::Adopt; +#endif + +private: + RefCounted(const RefCounted&) = delete; + RefCounted& operator=(const RefCounted&) = delete; +}; + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/ref_counted_internal.h b/kernel/lib/utils/include/utils/ref_counted_internal.h new file mode 100644 index 000000000..94290204f --- /dev/null +++ b/kernel/lib/utils/include/utils/ref_counted_internal.h @@ -0,0 +1,55 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include +#include + +namespace utils { +namespace internal { + +class RefCountedBase { +protected: + constexpr RefCountedBase() {} + ~RefCountedBase() {} + void AddRef() { + DEBUG_ASSERT(adopted_); + // TODO(jamesr): Replace uses of GCC builtins with something safer. + __atomic_fetch_add(&ref_count_, 1, __ATOMIC_RELAXED); + } + // Returns true if the object should self-delete. + bool Release() __WARN_UNUSED_RESULT { + DEBUG_ASSERT(adopted_); + if (__atomic_fetch_add(&ref_count_, -1, __ATOMIC_RELEASE) == 1) { + __atomic_thread_fence(__ATOMIC_ACQUIRE); + return true; + } + return false; + } + +#if (LK_DEBUGLEVEL > 0) + void Adopt() { + DEBUG_ASSERT(!adopted_); + adopted_ = true; + } +#endif + + // Current ref count. Only to be used for debugging purposes. + int ref_count_debug() const { + return __atomic_load_n(&ref_count_, __ATOMIC_RELAXED); + } + +private: + int ref_count_ = 1; +#if (LK_DEBUGLEVEL > 0) + bool adopted_ = false; +#endif +}; + +} // namespace internal +} // namespace utils diff --git a/kernel/lib/utils/include/utils/ref_ptr.h b/kernel/lib/utils/include/utils/ref_ptr.h new file mode 100644 index 000000000..ca6fd56fd --- /dev/null +++ b/kernel/lib/utils/include/utils/ref_ptr.h @@ -0,0 +1,130 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +namespace utils { + +template +class RefPtr; + +template +RefPtr AdoptRef(T* ptr); + +// RefPtr holds a reference to an intrusively-refcounted object of type T. +// +// T should be a subclass of utils::RefCounted<>, or something that adheres to +// the +// same contract for AddRef() and Release(). +// +// Except for initial construction (see below), this generally adheres to a +// subset of the interface for std::shared_ptr<>. Unlike std::shared_ptr<> this +// type does not support conversions between different pointer types, vending +// weak pointers, introspecting the reference count, or any operations that +// would result in allocating memory (unless T::AddRef or T::Release allocate +// memory). +// +// Construction: To create a RefPtr around a freshly created object, use the +// AdoptRef free function at the bottom of this header. To construct a RefPtr to +// hold a reference to an object that already exists use the copy or move +// constructor or assignment operator. +template +class RefPtr final { +public: + // Constructors + constexpr RefPtr() : ptr_(nullptr) {} + constexpr RefPtr(decltype(nullptr)) : RefPtr() {} + // Constructs a RefPtr from a pointer that has already been adopted. See + // AdoptRef() below for constructing the very first RefPtr to an object. + explicit RefPtr(T* p) : ptr_(p) { + if (ptr_) ptr_->AddRef(); + } + + // Copy + RefPtr(const RefPtr& r) : ptr_(r.ptr_) { + if (ptr_) ptr_->AddRef(); + } + + // Assignment + RefPtr& operator=(const RefPtr& r) { + // Ref first so self-assignments work. + if (r.ptr_) r.ptr_->AddRef(); + T* old = ptr_; + ptr_ = r.ptr_; + if (old && old->Release()) delete static_cast(old); + return *this; + } + + // Move + RefPtr(RefPtr&& r) : ptr_(r.ptr_) { + r.ptr_ = nullptr; + } + // Move assignment + RefPtr& operator=(RefPtr&& r) { + utils::move(r).swap(*this); + return *this; + } + + ~RefPtr() { + if (ptr_ && ptr_->Release()) delete static_cast(ptr_); + } + + void reset(T* ptr = nullptr) { + RefPtr(ptr).swap(*this); + } + + void swap(RefPtr& r) { + T* p = ptr_; + ptr_ = r.ptr_; + r.ptr_ = p; + } + + T* get() const { + return ptr_; + } + T& operator*() const { + return *ptr_; + } + T* operator->() const { + return ptr_; + } + explicit operator bool() const { + return !!ptr_; + } + + bool operator ==(const RefPtr& other) const { return ptr_ == other.ptr_; } + bool operator !=(const RefPtr& other) const { return ptr_ != other.ptr_; } + +private: + template + friend class RefPtr; + + friend RefPtr AdoptRef(T*); + + enum AdoptTag { ADOPT }; + RefPtr(T* ptr, AdoptTag) : ptr_(ptr) { +#if (LK_DEBUGLEVEL > 0) + ptr_->Adopt(); +#endif + } + T* ptr_; +}; + +// Constructs a RefPtr from a fresh object that has not been referenced before. +// Use like: +// +// RefPtr h = AdoptRef(new Happy); +// if (!h) +// // Deal with allocation failure here +// h->DoStuff(); +template +inline RefPtr AdoptRef(T* ptr) { + return RefPtr(ptr, RefPtr::ADOPT); +} + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/string_piece.h b/kernel/lib/utils/include/utils/string_piece.h new file mode 100644 index 000000000..a41e4d489 --- /dev/null +++ b/kernel/lib/utils/include/utils/string_piece.h @@ -0,0 +1,42 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +namespace utils { + +// A string-like object that points to a sized piece of memory. +// The string data may or may not be null terminated. +// The string piece does not own the data it points to. + +class StringPiece { +public: + constexpr StringPiece() : ptr_(nullptr), length_(0) {} + StringPiece(const char* str) : ptr_(str), length_((str == nullptr) ? 0 : strlen(str)) {} + constexpr StringPiece(const char* str, size_t len) : ptr_(str), length_(len) {} + + const char* data() const { + return ptr_; + } + size_t length() const { + return length_; + } + + void set(const char* data_in, size_t len) { + ptr_ = data_in; + length_ = len; + } + +private: + // Pointer to string data, not necessarily null terminated + const char* ptr_; + // Length of the string data + size_t length_; +}; + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/type_support.h b/kernel/lib/utils/include/utils/type_support.h new file mode 100644 index 000000000..500a9e5e8 --- /dev/null +++ b/kernel/lib/utils/include/utils/type_support.h @@ -0,0 +1,73 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +namespace utils { + +template +struct integral_constant { + static constexpr T value = v; + + using value_type = T; + using type = integral_constant; +}; + +using true_type = integral_constant; +using false_type = integral_constant; + +template +struct is_lvalue_reference : false_type {}; + +template +struct is_lvalue_reference : true_type {}; + +template +struct is_rvalue_reference : false_type {}; + +template +struct is_rvalue_reference : true_type {}; + +template +struct remove_reference { + using type = T; +}; + +template +struct remove_reference { + using type = T; +}; + +template +struct remove_reference { + using type = T; +}; + +template +constexpr typename remove_reference::type&& move(T&& t) { + return static_cast::type&&>(t); +} + +template +constexpr T&& forward(typename remove_reference::type& t) { + return static_cast(t); +} + +template +constexpr T&& forward(typename remove_reference::type&& t) { + static_assert(!is_lvalue_reference::value, "bad util::forward call"); + return static_cast(t); +} + +template struct is_same : false_type {}; +template struct is_same : true_type {}; + +template struct enable_if { }; +template struct enable_if { + typedef T type; +}; + +} // namespace utils diff --git a/kernel/lib/utils/include/utils/unique_ptr.h b/kernel/lib/utils/include/utils/unique_ptr.h new file mode 100644 index 000000000..bffcc7f07 --- /dev/null +++ b/kernel/lib/utils/include/utils/unique_ptr.h @@ -0,0 +1,171 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include +#include + +namespace utils { + +template +struct default_delete { + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete ptr; + } +}; + +template +struct default_delete { + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete[] ptr; + } + +private: + // Disable this whenever U != T as C++14 and before do. See + // http://cplusplus.github.io/LWG/lwg-defects.html#938 for motivation. + // C++17 has more complex rules for when U(*)[] is implicitly convertible to + // T(*)[] but we don't do that. + template + void operator()(U* ptr) const = delete; +}; + +template +struct default_delete { + // Disallow things like unique_ptr. + static_assert(sizeof(T) == -1, "do not use array with size as type in unique_ptr<>"); +}; + +// Deleter that invokes 'free' on its parameter. Can be used to store +// malloc-allocated pointers as follows: +// +// unique_ptr foo(static_cast(malloc(sizeof(int)))); +struct free_delete { + inline void operator()(void* ptr) const { + ::free(ptr); + } +}; + +// This is a simplified version of std::unique_ptr that supports custom +// stateless deleters but doesn't support type conversions between different +// pointer types. +template > +class unique_ptr { +public: + constexpr unique_ptr() : ptr_(nullptr) {} + constexpr unique_ptr(decltype(nullptr)) : unique_ptr() {} + + explicit unique_ptr(T* t) : ptr_(t) {} + + ~unique_ptr() { + if (ptr_) Deleter()(ptr_); + } + + unique_ptr(unique_ptr&& o) : ptr_(o.release()) {} + unique_ptr& operator=(unique_ptr&& o) { + reset(o.release()); + return *this; + } + + unique_ptr& operator=(decltype(nullptr)) { + reset(); + return *this; + } + + unique_ptr(const unique_ptr& o) = delete; + unique_ptr& operator=(const unique_ptr& o) = delete; + + T* release() { + T* t = ptr_; + ptr_ = nullptr; + return t; + } + void reset(T* t = nullptr) { + if (ptr_) Deleter()(ptr_); + ptr_ = t; + } + void swap(unique_ptr& other) { + T* t = ptr_; + ptr_ = other.ptr_; + other.ptr_ = t; + } + + T* get() const { + return ptr_; + } + + explicit operator bool() const { + return static_cast(ptr_); + } + + T& operator*() const { + return *ptr_; + } + T* operator->() const { + return ptr_; + } + +private: + T* ptr_; +}; + +template +class unique_ptr { +public: + constexpr unique_ptr() : ptr_(nullptr) {} + constexpr unique_ptr(decltype(nullptr)) : unique_ptr() {} + + explicit unique_ptr(T* array) : ptr_(array) {} + + unique_ptr(unique_ptr&& other) : ptr_(other.release()) {} + + ~unique_ptr() { + if (ptr_) Deleter()(ptr_); + } + + unique_ptr& operator=(unique_ptr&& o) { + reset(o.release()); + return *this; + } + + unique_ptr(const unique_ptr& o) = delete; + unique_ptr& operator=(const unique_ptr& o) = delete; + + T* release() { + T* t = ptr_; + ptr_ = nullptr; + return t; + } + void reset(T* t = nullptr) { + if (ptr_) Deleter()(ptr_); + ptr_ = t; + } + void swap(unique_ptr& other) { + T* t = ptr_; + ptr_ = other.ptr_; + other.ptr_ = t; + } + + T* get() const { + return ptr_; + } + + explicit operator bool() const { + return static_cast(ptr_); + } + T& operator[](size_t i) const { + return ptr_[i]; + } + +private: + T* ptr_; +}; + +// TODO: operator==, operator!=, operator<, etc + +} // namespace utils diff --git a/kernel/lib/utils/rules.mk b/kernel/lib/utils/rules.mk new file mode 100644 index 000000000..6f86eaaf2 --- /dev/null +++ b/kernel/lib/utils/rules.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +GLOBAL_INCLUDES += $(LOCAL_DIR)/include + +MODULE_SRCS := \ + $(LOCAL_DIR)/arena.cpp + +include make/module.mk + diff --git a/kernel/lib/version/BUILD.gn b/kernel/lib/version/BUILD.gn new file mode 100644 index 000000000..ca3d6a436 --- /dev/null +++ b/kernel/lib/version/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +action("generate_buildid") { + script = "buildid.sh" + outputs = [ + "${target_gen_dir}/buildid.h", + ] + args = [ rebase_path("${target_gen_dir}/buildid.h") ] +} + +config("_version_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("version") { + public_configs = [ ":_version_config" ] + include_dirs = [ target_gen_dir ] + public = [ + "include/lib/version.h", + ] + sources = [ + "version.c", + ] + deps = [ + ":generate_buildid", + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/lib/version/buildid.sh b/kernel/lib/version/buildid.sh new file mode 100755 index 000000000..a3ac2d4dd --- /dev/null +++ b/kernel/lib/version/buildid.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +eval `date -u +'BYR=%Y BMON=%-m BDOM=%-d BHR=%-H BMIN=%-M'` +chr () { + printf \\$(($1/64*100+$1%64/8*10+$1%8)) +} +b36 () { + if [ $1 -le 9 ]; then echo $1; else chr $((0x41 + $1 - 10)); fi +} +id=$(printf '%c%c%c%c%c\n' `chr $((0x41 + $BYR - 2011))` `b36 $BMON` `b36 $BDOM` `b36 $BHR` `b36 $(($BMIN/2))`) + +if [[ $# -eq 1 ]]; then + cat > "$1" < + +__BEGIN_CDECLS + +#define VERSION_STRUCT_VERSION 0x1 + +typedef struct { + unsigned int struct_version; + const char *arch; + const char *platform; + const char *target; + const char *project; + const char *buildid; +} lk_version_t; + +extern const lk_version_t version; + +void print_version(void); + +__END_CDECLS + +#endif + diff --git a/kernel/lib/version/rules.mk b/kernel/lib/version/rules.mk new file mode 100644 index 000000000..779a51814 --- /dev/null +++ b/kernel/lib/version/rules.mk @@ -0,0 +1,39 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/version.c + +# if no one else has defined it by now, build us a default buildid +# based on the current time. +# suffix it with _LOCAL if OFFICIAL_BUILD is unset +ifeq ($(strip $(BUILDID)),) +ifneq ($(OFFICIAL_BUILD),) +BUILDID := "$(shell $(LOCAL_DIR)/buildid.sh)" +else +BUILDID := "$(shell $(LOCAL_DIR)/buildid.sh)_LOCAL" +endif +endif + +# Generate a buildid.h file, lazy evaulated BUILDID_DEFINE at the end +# of the first make pass. This lets modules that haven't been +# included yet set BUILDID. +BUILDID_DEFINE="BUILDID=\"$(BUILDID)\"" +BUILDID_H := $(BUILDDIR)/buildid.h +$(BUILDID_H): .PHONY + @$(call MAKECONFIGHEADER,$@,BUILDID_DEFINE) + +GENERATED += $(BUILDID_H) + +# make sure the module properly depends on and can find buildid.h +MODULE_SRCDEPS := $(BUILDID_H) + +include make/module.mk diff --git a/kernel/lib/version/version.c b/kernel/lib/version/version.c new file mode 100644 index 000000000..545e1bfc4 --- /dev/null +++ b/kernel/lib/version/version.c @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include + +/* generated for us */ +#include + +/* ARCH, PLATFORM, TARGET, PROJECT should be defined by the build system */ + +/* BUILDID is optional, and may be defined anywhere */ +#ifndef BUILDID +#define BUILDID "" +#endif + +const lk_version_t version = { + .struct_version = VERSION_STRUCT_VERSION, + .arch = ARCH, + .platform = PLATFORM, + .target = TARGET, + .project = PROJECT, + .buildid = BUILDID +}; + +void print_version(void) +{ + printf("version:\n"); + printf("\tarch: %s\n", version.arch); + printf("\tplatform: %s\n", version.platform); + printf("\ttarget: %s\n", version.target); + printf("\tproject: %s\n", version.project); + printf("\tbuildid: %s\n", version.buildid); +} + +#if WITH_LIB_CONSOLE + +#include +#include + +static int cmd_version(int argc, const cmd_args *argv) +{ + print_version(); + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("version", "print version", &cmd_version) +STATIC_COMMAND_END(version); + +#endif // WITH_LIB_CONSOLE + +#if LK_DEBUGLEVEL > 0 +// print the version string if any level of debug is set +LK_INIT_HOOK(version, (void *)&print_version, LK_INIT_LEVEL_HEAP - 1); +#endif + diff --git a/kernel/lib/watchdog/BUILD.gn b/kernel/lib/watchdog/BUILD.gn new file mode 100644 index 000000000..621fa87b8 --- /dev/null +++ b/kernel/lib/watchdog/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +config("_watchdog_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("watchdog") { + public_configs = [ ":_watchdog_config" ] + public = [ + "include/lib/watchdog.h", + ] + sources = [ + "watchdog.c", + ] +} diff --git a/kernel/lib/watchdog/include/lib/watchdog.h b/kernel/lib/watchdog/include/lib/watchdog.h new file mode 100644 index 000000000..cae68b397 --- /dev/null +++ b/kernel/lib/watchdog/include/lib/watchdog.h @@ -0,0 +1,70 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __LIB_WATCHDOG_H__ +#define __LIB_WATCHDOG_H__ + +#include +#include +#include +#include + +#define WATCHDOG_MAGIC 'wdog' + +typedef struct watchdog { + uint32_t magic; + const char *name; + bool enabled; + lk_time_t timeout; + timer_t expire_timer; +} watchdog_t; + +/* A global weak-reference to the common watchdog handler. By default, this + * function will dprintf a message indicating which watchdog fired, and then + * request a halt using platform_halt, indicating that a SW watchdog was the + * reason for the reset. It is the platform/target's responsibility to either + * implement the panic behavior they want when a watchdog fires in + * platform_halt, or to replace the implementation of the watchdog handler with + * their own appropriate implementation. + */ +void watchdog_handler(watchdog_t *dog) __NO_RETURN; + +status_t watchdog_init(watchdog_t *dog, lk_time_t timeout, const char *name); +void watchdog_set_enabled(watchdog_t *dog, bool enabled); +void watchdog_pet(watchdog_t *dog); + +/* HW watchdog support. This is nothing but a simple helper used to + * automatically dismiss a platform's HW watchdog using LK timers. Platforms + * must supply + * + * platform_watchdog_init + * platform_watchdog_set_enabled + * platform_watchdog_pet + * + * in order to use the HW watchdog helper functions. After initialized, users + * may enable and disable the HW watchdog whenever appropriate. The helper will + * maintain a timer which dismisses the watchdog at the pet interval recommended + * by the platform. Any programming error which prevents the scheduler timer + * mechanism from running properly will eventually result in the watchdog firing + * and the system rebooting. Whenever possible, when using SW based watchdogs, + * it is recommended that systems provide platform support for a HW watchdog and + * enable the HW watchdog. SW watchdogs are based on LK timers, and should be + * reliable as long as the scheduler and timer mechanism is running properly; + * the HW watchdog functionality provided here should protect the system in case + * something managed to break timers on LK. + */ + +extern status_t platform_watchdog_init(lk_time_t target_timeout, + lk_time_t *recommended_pet_period); +extern void platform_watchdog_set_enabled(bool enabled); +extern void platform_watchdog_pet(void); + +status_t watchdog_hw_init(lk_time_t timeout); +void watchdog_hw_set_enabled(bool enabled); + +#endif // __LIB_WATCHDOG_H__ diff --git a/kernel/lib/watchdog/rules.mk b/kernel/lib/watchdog/rules.mk new file mode 100644 index 000000000..e85e81fd1 --- /dev/null +++ b/kernel/lib/watchdog/rules.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := \ + $(LOCAL_DIR)/watchdog.c + +include make/module.mk diff --git a/kernel/lib/watchdog/watchdog.c b/kernel/lib/watchdog/watchdog.c new file mode 100644 index 000000000..9783a37cf --- /dev/null +++ b/kernel/lib/watchdog/watchdog.c @@ -0,0 +1,129 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Google Inc. +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE; + +__WEAK void watchdog_handler(watchdog_t *dog) +{ + dprintf(INFO, "Watchdog \"%s\" (timeout %u mSec) just fired!!\n", + dog->name, (uint32_t)dog->timeout); + platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_WATCHDOG); +} + +static enum handler_return watchdog_timer_callback(struct timer *timer, lk_time_t now, void *arg) +{ + watchdog_handler((watchdog_t *)arg); + + /* We should never get here; watchdog handlers should always be fatal. */ + DEBUG_ASSERT(false); + + return INT_NO_RESCHEDULE; +} + +status_t watchdog_init(watchdog_t *dog, lk_time_t timeout, const char *name) +{ + DEBUG_ASSERT(NULL != dog); + DEBUG_ASSERT(INFINITE_TIME != timeout); + + dog->magic = WATCHDOG_MAGIC; + dog->name = name ? name : "unnamed watchdog"; + dog->enabled = false; + dog->timeout = timeout; + timer_initialize(&dog->expire_timer); + + return NO_ERROR; +} + +void watchdog_set_enabled(watchdog_t *dog, bool enabled) +{ + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + DEBUG_ASSERT((NULL != dog) && (WATCHDOG_MAGIC == dog->magic)); + + if (dog->enabled == enabled) + goto done; + + dog->enabled = enabled; + if (enabled) + timer_set_oneshot(&dog->expire_timer, dog->timeout, watchdog_timer_callback, dog); + else + timer_cancel(&dog->expire_timer); + +done: + spin_unlock_irqrestore(&lock, state); +} + +void watchdog_pet(watchdog_t *dog) +{ + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + DEBUG_ASSERT((NULL != dog) && (WATCHDOG_MAGIC == dog->magic)); + + if (!dog->enabled) + goto done; + + timer_cancel(&dog->expire_timer); + timer_set_oneshot(&dog->expire_timer, dog->timeout, watchdog_timer_callback, dog); + +done: + spin_unlock_irqrestore(&lock, state); +} + + +static timer_t hw_watchdog_timer; +static bool hw_watchdog_enabled; +static lk_time_t hw_watchdog_pet_timeout; + +static enum handler_return hw_watchdog_timer_callback(struct timer *timer, lk_time_t now, void *arg) +{ + platform_watchdog_pet(); + return INT_NO_RESCHEDULE; +} + +status_t watchdog_hw_init(lk_time_t timeout) +{ + DEBUG_ASSERT(INFINITE_TIME != timeout); + timer_initialize(&hw_watchdog_timer); + return platform_watchdog_init(timeout, &hw_watchdog_pet_timeout); +} + +void watchdog_hw_set_enabled(bool enabled) +{ + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + if (hw_watchdog_enabled == enabled) + goto done; + + hw_watchdog_enabled = enabled; + platform_watchdog_set_enabled(enabled); + if (enabled) + timer_set_periodic(&hw_watchdog_timer, + hw_watchdog_pet_timeout, + hw_watchdog_timer_callback, + NULL); + else + timer_cancel(&hw_watchdog_timer); + +done: + spin_unlock_irqrestore(&lock, state); +} diff --git a/kernel/lk_inc.mk b/kernel/lk_inc.mk new file mode 100644 index 000000000..58e291df7 --- /dev/null +++ b/kernel/lk_inc.mk @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# copy this and makefile to your external root directory and customize +# according to how you want to use a split repository + +# the top level directory that all paths are relative to +#LKMAKEROOT := . + +# paths relative to LKMAKEROOT where additional modules should be searched +#LKINC := + +# the path relative to LKMAKEROOT where the main lk repository lives +#LKROOT := . + +# set the directory relative to LKMAKEROOT where output will go +#BUILDROOT ?= . + +# set the default project if no args are passed +DEFAULT_PROJECT ?= magenta-qemu-arm64 + +#TOOLCHAIN_PREFIX := diff --git a/kernel/lk_inc.mk.example b/kernel/lk_inc.mk.example new file mode 100644 index 000000000..b19e4a1f4 --- /dev/null +++ b/kernel/lk_inc.mk.example @@ -0,0 +1,19 @@ +# copy this and makefile to your external root directory and customize +# according to how you want to use a split repository + +# the top level directory that all paths are relative to +LKMAKEROOT := . + +# paths relative to LKMAKEROOT where additional modules should be searched +LKINC := projectroot + +# the path relative to LKMAKEROOT where the main lk repository lives +LKROOT := lk + +# set the directory relative to LKMAKEROOT where output will go +BUILDROOT ?= . + +# set the default project if no args are passed +DEFAULT_PROJECT ?= testproject + +#TOOLCHAIN_PREFIX := diff --git a/kernel/make/build.mk b/kernel/make/build.mk new file mode 100644 index 000000000..f8d247106 --- /dev/null +++ b/kernel/make/build.mk @@ -0,0 +1,118 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# use linker garbage collection, if requested +ifeq ($(WITH_LINKER_GC),1) +GLOBAL_COMPILEFLAGS += -ffunction-sections -fdata-sections +GLOBAL_LDFLAGS += --gc-sections +endif + +ifneq (,$(EXTRA_BUILDRULES)) +-include $(EXTRA_BUILDRULES) +endif + +$(OUTLKBIN): $(OUTLKELF) + @echo generating image: $@ + $(NOECHO)$(SIZE) $< + $(NOECHO)$(OBJCOPY) -O binary $< $@ + +$(OUTLKELF).hex: $(OUTLKELF) + @echo generating hex file: $@ + $(NOECHO)$(OBJCOPY) -O ihex $< $@ + +$(OUTLKELF): $(ALLMODULE_OBJS) $(EXTRA_OBJS) $(LINKER_SCRIPT) + @echo linking $@ + $(NOECHO)$(SIZE) -t --common $(sort $(ALLMODULE_OBJS)) $(EXTRA_OBJS) + $(NOECHO)$(LD) $(GLOBAL_LDFLAGS) -dT $(LINKER_SCRIPT) \ + $(ALLMODULE_OBJS) $(EXTRA_OBJS) $(LIBGCC) -o $@ + +$(OUTLKELF).sym: $(OUTLKELF) + @echo generating symbols: $@ + $(NOECHO)$(OBJDUMP) -t $< | $(CPPFILT) > $@ + +$(OUTLKELF).sym.sorted: $(OUTLKELF) + @echo generating sorted symbols: $@ + $(NOECHO)$(OBJDUMP) -t $< | $(CPPFILT) | sort > $@ + +$(OUTLKELF).lst: $(OUTLKELF) + @echo generating listing: $@ + $(NOECHO)$(OBJDUMP) $(OBJDUMP_LIST_FLAGS) -d $< | $(CPPFILT) > $@ + +$(OUTLKELF).debug.lst: $(OUTLKELF) + @echo generating listing: $@ + $(NOECHO)$(OBJDUMP) $(OBJDUMP_LIST_FLAGS) -S $< | $(CPPFILT) > $@ + +$(OUTLKELF).dump: $(OUTLKELF) + @echo generating objdump: $@ + $(NOECHO)$(OBJDUMP) -x $< > $@ + +$(OUTLKELF).size: $(OUTLKELF) + @echo generating size map: $@ + $(NOECHO)$(NM) -S --size-sort $< > $@ + +$(OUTLKELF)-gdb.py: scripts/$(LKELF)-gdb.py + @echo generating $@ + $(NOECHO)ln -sf ../$< $@ + +# print some information about the build +$(BUILDDIR)/srcfiles.txt: + @echo generating $@ + $(NOECHO)echo $(sort $(ALLSRCS)) | tr ' ' '\n' > $@ + +.PHONY: $(BUILDDIR)/srcfiles.txt +GENERATED += $(BUILDDIR)/srcfiles.txt + +$(BUILDDIR)/include_paths.txt: + @echo generating $@ + $(NOECHO)echo $(subst -I,,$(sort $(GLOBAL_INCLUDES))) | tr ' ' '\n' > $@ + +.PHONY: $(BUILDDIR)/include_paths.txt +GENERATED += $(BUILDDIR)/include_paths.txt + +.PHONY: $(BUILDDIR)/user_include_paths.txt +GENERATED += $(BUILDDIR)/user_include_paths.txt + +# userspace app build rule +# NOTE: another rule in engine.mk adds additional deps to individual .elf files +# so they will be reflected in the $^ expansion of the link line +$(BUILDDIR)/%.elf:: $(BUILDDIR)/%.mod.o $(USER_LINKER_SCRIPT) + @echo linking $@ + $(NOECHO)$(LD) $(GLOBAL_LDFLAGS) -T $(USER_LINKER_SCRIPT) $(ARCH_LDFLAGS) \ + $(filter-out $(USER_LINKER_SCRIPT),$^) $(LIBGCC) -o $@ + +$(BUILDDIR)/%.elf.dump: $(BUILDDIR)/%.elf + @echo generating $@ + $(NOECHO)$(OBJDUMP) -x $< > $@ + +$(BUILDDIR)/%.elf.lst: $(BUILDDIR)/%.elf + @echo generating $@ + $(NOECHO)$(OBJDUMP) $(OBJDUMP_LIST_FLAGS) -d $< > $@ + +$(BUILDDIR)/%.elf.strip: $(BUILDDIR)/%.elf + @echo generating $@ + $(NOECHO)$(STRIP) -d $< -o $@ + +# Manifest Lines are bootfspath=buildpath +# Extract the part after the = for each line +# to generate dependencies +USER_MANIFEST_DEPS := $(foreach x,$(USER_MANIFEST_LINES),$(lastword $(subst =,$(SPACE),$(strip $(x))))) + +$(USER_MANIFEST): $(CONFIGHEADER) $(USER_MANIFEST_DEPS) + @echo generating $@ + @$(MKDIR) + $(NOECHO)echo $(USER_MANIFEST_LINES) | tr ' ' '\n' | sort > $@ + +GENERATED += $(USER_MANIFEST) + +# build userspace filesystem image +$(USER_FS): $(USER_BOOTFS) + @echo generating $@ + $(NOECHO)dd if=/dev/zero of=$@ bs=1048576 count=16 + $(NOECHO)dd if=$(USER_BOOTFS) of=$@ conv=notrunc + +# add the fs image to the clean list +GENERATED += $(USER_FS) diff --git a/kernel/make/compile.mk b/kernel/make/compile.mk new file mode 100644 index 000000000..0fab9fa62 --- /dev/null +++ b/kernel/make/compile.mk @@ -0,0 +1,103 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + + +# create a separate list of objects per source type +MODULE_CSRCS := $(filter %.c,$(MODULE_SRCS)) +MODULE_CPPSRCS := $(filter %.cpp,$(MODULE_SRCS)) +MODULE_ASMSRCS := $(filter %.S,$(MODULE_SRCS)) +MODULE_ASMSRCS2 := $(filter %.s,$(MODULE_SRCS)) + +MODULE_COBJS := $(call TOBUILDDIR,$(patsubst %.c,%.c.o,$(MODULE_CSRCS))) +MODULE_CPPOBJS := $(call TOBUILDDIR,$(patsubst %.cpp,%.cpp.o,$(MODULE_CPPSRCS))) +MODULE_ASMOBJS := $(call TOBUILDDIR,$(patsubst %.S,%.S.o,$(MODULE_ASMSRCS))) +MODULE_ASMOBJS2 := $(call TOBUILDDIR,$(patsubst %.s,%.s.o,$(MODULE_ASMSRCS2))) + +# do the same thing for files specified in arm override mode +MODULE_ARM_CSRCS := $(filter %.c,$(MODULE_ARM_OVERRIDE_SRCS)) +MODULE_ARM_CPPSRCS := $(filter %.cpp,$(MODULE_ARM_OVERRIDE_SRCS)) +MODULE_ARM_ASMSRCS := $(filter %.S,$(MODULE_ARM_OVERRIDE_SRCS)) +MODULE_ARM_ASMSRCS2 := $(filter %.s,$(MODULE_ARM_OVERRIDE_SRCS2)) + +MODULE_ARM_COBJS := $(call TOBUILDDIR,$(patsubst %.c,%.arm.c.o,$(MODULE_ARM_CSRCS))) +MODULE_ARM_CPPOBJS := $(call TOBUILDDIR,$(patsubst %.cpp,%.arm.cpp.o,$(MODULE_ARM_CPPSRCS))) +MODULE_ARM_ASMOBJS := $(call TOBUILDDIR,$(patsubst %.S,%.arm.S.o,$(MODULE_ARM_ASMSRCS))) +MODULE_ARM_ASMOBJS2 := $(call TOBUILDDIR,$(patsubst %.s,%.arm.s.o,$(MODULE_ARM_ASMSRCS2))) + +MODULE_OBJS := $(MODULE_COBJS) $(MODULE_CPPOBJS) $(MODULE_ASMOBJS) $(MODULE_ASMOBJS2) $(MODULE_ARM_COBJS) $(MODULE_ARM_CPPOBJS) $(MODULE_ARM_ASMOBJS) $(MODULE_ARM_ASMOBJS2) + +#$(info MODULE_SRCS = $(MODULE_SRCS)) +#$(info MODULE_CSRCS = $(MODULE_CSRCS)) +#$(info MODULE_CPPSRCS = $(MODULE_CPPSRCS)) +#$(info MODULE_ASMSRCS = $(MODULE_ASMSRCS)) +#$(info MODULE_ASMSRCS2 = $(MODULE_ASMSRCS2)) + +#$(info MODULE_OBJS = $(MODULE_OBJS)) +#$(info MODULE_COBJS = $(MODULE_COBJS)) +#$(info MODULE_CPPOBJS = $(MODULE_CPPOBJS)) +#$(info MODULE_ASMOBJS2 = $(MODULE_ASMOBJS2)) + +$(MODULE_OBJS): MODULE_OPTFLAGS:=$(MODULE_OPTFLAGS) +$(MODULE_OBJS): MODULE_COMPILEFLAGS:=$(MODULE_COMPILEFLAGS) +$(MODULE_OBJS): MODULE_CFLAGS:=$(MODULE_CFLAGS) +$(MODULE_OBJS): MODULE_CPPFLAGS:=$(MODULE_CPPFLAGS) +$(MODULE_OBJS): MODULE_ASMFLAGS:=$(MODULE_ASMFLAGS) +$(MODULE_OBJS): MODULE_SRCDEPS:=$(MODULE_SRCDEPS) + +$(MODULE_COBJS): $(BUILDDIR)/%.c.o: %.c $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CFLAGS) $(KERNEL_CFLAGS) $(ARCH_CFLAGS) $(MODULE_CFLAGS) $(THUMBCFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_CPPOBJS): $(BUILDDIR)/%.cpp.o: %.cpp $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CPPFLAGS) $(KERNEL_CPPFLAGS) $(ARCH_CPPFLAGS) $(MODULE_CPPFLAGS) $(THUMBCFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ASMOBJS): $(BUILDDIR)/%.S.o: %.S $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(KERNEL_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) $(THUMBCFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ASMOBJS2): $(BUILDDIR)/%.s.o: %.s $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(KERNEL_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) $(THUMBCFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +# overridden arm versions +$(MODULE_ARM_COBJS): $(BUILDDIR)/%.arm.c.o: %.c $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CFLAGS) $(KERNEL_CFLAGS) $(ARCH_CFLAGS) $(MODULE_CFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ARM_CPPOBJS): $(BUILDDIR)/%.arm.cpp.o: %.cpp $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CPPFLAGS) $(KERNEL_CPPFLAGS) $(ARCH_CPPFLAGS) $(MODULE_CPPFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ARM_ASMOBJS): $(BUILDDIR)/%.arm.S.o: %.S $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(KERNEL_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ARM_ASMOBJS2): $(BUILDDIR)/%.arm.s.o: %.s $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(KERNEL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(KERNEL_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) $(GLOBAL_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +# clear some variables we set here +MODULE_CSRCS := +MODULE_CPPSRCS := +MODULE_ASMSRCS := +MODULE_COBJS := +MODULE_CPPOBJS := +MODULE_ASMOBJS := +MODULE_ASMOBJS2 := + +# MODULE_OBJS is passed back +#MODULE_OBJS := + diff --git a/kernel/make/help.mk b/kernel/make/help.mk new file mode 100644 index 000000000..169892172 --- /dev/null +++ b/kernel/make/help.mk @@ -0,0 +1,60 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# routines and rules to print some helpful stuff + + +#$(warning MAKECMDGOALS = $(MAKECMDGOALS)) + +# print some help and exit +ifeq ($(firstword $(MAKECMDGOALS)),help) +do-nothing=1 + +.PHONY: help +help: + @echo "LK build system quick help" + @echo "Individual projects are built into a build- directory" + @echo "Output binary is located at build-/lk.bin" + @echo "Environment or command line variables controlling build:" + @echo "PROJECT = " + @echo "TOOLCHAIN_PREFIX = " + @echo "" + @echo "Special make targets:" + @echo "make help: This help" + @echo "make list: List of buildable projects" + @echo "make clean: cleans build of current project" + @echo "make spotless: removes all build directories" + @echo "make : try to build project named " + @echo "" + @echo "Examples:" + @echo "PROJECT=testproject make" + @echo "PROJECT=testproject make clean" + @echo "make testproject" + @echo "make testproject clean" + @echo "" + @echo "output will be in build-testproject/" + +endif + +# list projects +ifeq ($(firstword $(MAKECMDGOALS)),list) +do-nothing=1 + +# get a list of all the .mk files in the top level project directories +PROJECTS:=$(basename $(strip $(foreach d,$(LKINC),$(wildcard $(d)/project/*.mk)))) +PROJECTS:=$(shell basename -a $(PROJECTS)) + +.PHONY: list +list: + @echo 'List of all buildable projects: (look in project/ directory)'; \ + for p in $(PROJECTS); do \ + echo $$p; \ + done + +endif + +# vim: set syntax=make noexpandtab diff --git a/kernel/make/include_diagram.txt b/kernel/make/include_diagram.txt new file mode 100644 index 000000000..6a1f29f4a --- /dev/null +++ b/kernel/make/include_diagram.txt @@ -0,0 +1,24 @@ +Makefile Include Diagram + + /---> project/$(PROJECT).mk + | + |---> target/$(TARGET)/rules.mk + | + |---> platform/$(PLATFORM)/rules.mk + | + |---> arch/$(ARCH)/rules.mk + | + |---> top/rules.mk + | +engine.mk --->| + | /---> rules.mk ---> make/module.mk ---> make/compile.mk + | | + | | + |---> make/recurse.mk --->| + | ^ | + | | | + | | | + | \____________/ + | + | + \---> make/build.mk diff --git a/kernel/make/macros.mk b/kernel/make/macros.mk new file mode 100644 index 000000000..e444d3538 --- /dev/null +++ b/kernel/make/macros.mk @@ -0,0 +1,65 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Find the local dir of the make file +GET_LOCAL_DIR = $(patsubst %/,%,$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))) + +# makes sure the target dir exists +MKDIR = if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi + +# prepends the BUILD_DIR var to each item in the list +TOBUILDDIR = $(addprefix $(BUILDDIR)/,$(1)) + +# converts specified variable to boolean value +TOBOOL = $(if $(filter-out 0 false,$1),true,false) + +COMMA := , +SPACE := +SPACE += + +# test if two files are different, replacing the first +# with the second if so +# args: $1 - temporary file to test +# $2 - file to replace +define TESTANDREPLACEFILE + if [ -f "$2" ]; then \ + if cmp "$1" "$2"; then \ + rm -f $1; \ + else \ + mv $1 $2; \ + fi \ + else \ + mv $1 $2; \ + fi +endef + +# generate a header file at $1 with an expanded variable in $2 +define MAKECONFIGHEADER + $(MKDIR); \ + rm -f $1.tmp; \ + LDEF=`echo $1 | tr '/\\.-' '_' | sed "s/C++/CPP/g;s/c++/cpp/g"`; \ + echo \#ifndef __$${LDEF}_H > $1.tmp; \ + echo \#define __$${LDEF}_H >> $1.tmp; \ + for d in `echo $($2) | tr '[:lower:]' '[:upper:]'`; do \ + echo "#define $$d" | sed "s/=/\ /g;s/-/_/g;s/\//_/g;s/\./_/g;s/\//_/g;s/C++/CPP/g" >> $1.tmp; \ + done; \ + echo \#endif >> $1.tmp; \ + $(call TESTANDREPLACEFILE,$1.tmp,$1) +endef + +# Tools to make module names canonical (expand to a full path relative +# to LKROOT) and to ensure that canonical names exist and are non-ambigous. + +# Check that the expansion $(2) of a module name $(1) resolves to exactly +# one canonical name, error out (differently) on 0 or >1 matches +modname-check = $(if $(word 2,$(2)),$(error MODULE $(1): resolves to: $(2)),$(if $(2),$(2),$(error MODULE $(1): unresolvable))) + +# First, check if the name resolves directly, in which case, take that. +# Second, wildcard against each LKINC path as a .../ prefix and make +# sure that there is only one match (via modname-check) +modname-make-canonical = $(strip $(if $(wildcard $(1)),$(1),$(call modname-check,$(1),$(foreach pfx,$(LKINC),$(wildcard $(pfx)/$(1)))))) + diff --git a/kernel/make/module.mk b/kernel/make/module.mk new file mode 100644 index 000000000..dd9d6a6d3 --- /dev/null +++ b/kernel/make/module.mk @@ -0,0 +1,179 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + + +# modules +# +# args: +# MODULE : module name (required) +# MODULE_SRCS : list of source files, local path (required) +# MODULE_DEPS : other modules that this one depends on +# MODULE_HEADER_DEPS : other headers that this one depends on, in addition to MODULE_DEPS +# MODULE_DEFINES : #defines local to this module +# MODULE_OPTFLAGS : OPTFLAGS local to this module +# MODULE_COMPILEFLAGS : COMPILEFLAGS local to this module +# MODULE_CFLAGS : CFLAGS local to this module +# MODULE_CPPFLAGS : CPPFLAGS local to this module +# MODULE_ASMFLAGS : ASMFLAGS local to this module +# MODULE_SRCDEPS : extra dependencies that all of this module's files depend on +# MODULE_EXTRA_OBJS : extra .o files that should be linked with the module +# MODULE_TYPE : "userapp" for userspace executables, "userlib" for userspace library, +# "" for standard LK module + +# MODULE_ARM_OVERRIDE_SRCS : list of source files, local path that should be force compiled with ARM (if applicable) + +# the minimum module rules.mk file is as follows: +# +# LOCAL_DIR := $(GET_LOCAL_DIR) +# MODULE := $(LOCAL_DIR) +# +# MODULE_SRCS := $(LOCAL_DIR)/at_least_one_source_file.c +# +# include make/module.mk + +# test for old style rules.mk +ifneq ($(MODULE_OBJS),) +$(warning MODULE_OBJS = $(MODULE_OBJS)) +$(error MODULE $(MODULE) is setting MODULE_OBJS, change to MODULE_SRCS) +endif +ifneq ($(OBJS),) +$(warning OBJS = $(OBJS)) +$(error MODULE $(MODULE) is probably setting OBJS, change to MODULE_SRCS) +endif + +MODULE_SRCDIR := $(MODULE) +MODULE_BUILDDIR := $(call TOBUILDDIR,$(MODULE_SRCDIR)) + +ifeq ($(MODULE_TYPE),) +# add a local include dir to the global include path for kernel code +GLOBAL_INCLUDES += $(MODULE_SRCDIR)/include +endif + +# expand deps to canonical paths +MODULE_DEPS := $(foreach d,$(MODULE_DEPS),$(call modname-make-canonical,$(d))) +MODULE_HEADER_DEPS := $(foreach d,$(MODULE_HEADER_DEPS),$(call modname-make-canonical,$(strip $(d)))) + +# add the listed module deps to the global list +MODULES += $(MODULE_DEPS) + +# add the headers to include to a list +HEADER_MODULE_DEPS := $(MODULE_DEPS) +HEADER_MODULE_DEPS += $(MODULE_HEADER_DEPS) + +#$(info module $(MODULE)) +#$(info MODULE_SRCDIR $(MODULE_SRCDIR)) +#$(info MODULE_BUILDDIR $(MODULE_BUILDDIR)) +#$(info MODULE_DEPS $(MODULE_DEPS)) +#$(info MODULE_SRCS $(MODULE_SRCS)) + +MODULE_DEFINES += MODULE_COMPILEFLAGS=\"$(subst $(SPACE),_,$(MODULE_COMPILEFLAGS))\" +MODULE_DEFINES += MODULE_CFLAGS=\"$(subst $(SPACE),_,$(MODULE_CFLAGS))\" +MODULE_DEFINES += MODULE_CPPFLAGS=\"$(subst $(SPACE),_,$(MODULE_CPPFLAGS))\" +MODULE_DEFINES += MODULE_ASMFLAGS=\"$(subst $(SPACE),_,$(MODULE_ASMFLAGS))\" +MODULE_DEFINES += MODULE_LDFLAGS=\"$(subst $(SPACE),_,$(MODULE_LDFLAGS))\" +MODULE_DEFINES += MODULE_OPTFLAGS=\"$(subst $(SPACE),_,$(MODULE_OPTFLAGS))\" +MODULE_DEFINES += MODULE_SRCDEPS=\"$(subst $(SPACE),_,$(MODULE_SRCDEPS))\" +MODULE_DEFINES += MODULE_DEPS=\"$(subst $(SPACE),_,$(MODULE_DEPS))\" +MODULE_DEFINES += MODULE_SRCS=\"$(subst $(SPACE),_,$(MODULE_SRCS))\" +MODULE_DEFINES += MODULE_HEADER_DEPS=\"$(subst $(SPACE),_,$(MODULE_HEADER_DEPS))\" +MODULE_DEFINES += MODULE_TYPE=\"$(subst $(SPACE),_,$(MODULE_TYPE))\" + +# Introduce local, libc, and dependency include paths and defines +ifneq (,$(filter userapp userlib,$(MODULE_TYPE))) +MODULE_COMPILEFLAGS += -I$(LOCAL_DIR)/include +MODULE_COMPILEFLAGS += -Isystem/ulib/global/include +MODULE_COMPILEFLAGS += -Ithird_party/ulib/musl/include +MODULE_COMPILEFLAGS += -D_XOPEN_SOURCE=700 +ifneq ($(MODULE),third_party/ulib/musl) +# musl has to carefully manipulate this define internally, so don't set it for it. +MODULE_COMPILEFLAGS += -D_BSD_SOURCE +endif +MODULE_COMPILEFLAGS += $(foreach DEP,$(HEADER_MODULE_DEPS),-I$(DEP)/include) +else +MODULE_COMPILEFLAGS += -D_KERNEL +endif + +# generate a per-module config.h file +MODULE_CONFIG := $(MODULE_BUILDDIR)/module_config.h + +$(MODULE_CONFIG): MODULE_DEFINES:=$(MODULE_DEFINES) +$(MODULE_CONFIG): configheader + @$(call MAKECONFIGHEADER,$@,MODULE_DEFINES) + +GENERATED += $(MODULE_CONFIG) + +MODULE_COMPILEFLAGS += --include $(MODULE_CONFIG) + +MODULE_SRCDEPS += $(MODULE_CONFIG) + +# include the rules to compile the module's object files +ifeq ($(MODULE_TYPE),) +# for kernel code +include make/compile.mk +else +# for userspace code +include make/ucompile.mk +endif + +# MODULE_OBJS is passed back from compile.mk +#$(info MODULE_OBJS = $(MODULE_OBJS)) + +# build a ld -r style combined object +MODULE_OBJECT := $(call TOBUILDDIR,$(MODULE_SRCDIR).mod.o) +$(MODULE_OBJECT): $(MODULE_OBJS) $(MODULE_EXTRA_OBJS) + @$(MKDIR) + @echo linking $@ + $(NOECHO)$(LD) $(GLOBAL_MODULE_LDFLAGS) -r $^ -o $@ + +# track all of the source files compiled +ALLSRCS += $(MODULE_SRCS) + +# track all the objects built +ALLOBJS += $(MODULE_OBJS) + +# track the module object for make clean +GENERATED += $(MODULE_OBJECT) + +# track the requested install name of the module +ifeq ($(MODULE_NAME),) +MODULE_NAME := $(basename $(notdir $(MODULE))) +endif + +ifeq ($(MODULE_TYPE),) +# make the rest of the build depend on our output +ALLMODULE_OBJS := $(ALLMODULE_OBJS) $(MODULE_OBJECT) +else ifeq ($(MODULE_TYPE),userapp) +MODULE_$(MODULE)_DEPS := $(MODULE_DEPS) +MODULE_USERAPP_OBJECT := $(patsubst %.mod.o,%.elf,$(MODULE_OBJECT)) +ALLUSER_APPS += $(MODULE_USERAPP_OBJECT) +ALLUSER_MODULES += $(MODULE) +USER_MANIFEST_LINES += bin/$(MODULE_NAME)=$(addsuffix .strip,$(MODULE_USERAPP_OBJECT)) +else ifeq ($(MODULE_TYPE),userlib) +MODULE_$(MODULE)_DEPS := $(MODULE_DEPS) +endif + +# empty out any vars set here +MODULE := +MODULE_SRCDIR := +MODULE_BUILDDIR := +MODULE_DEPS := +MODULE_HEADER_DEPS := +MODULE_SRCS := +MODULE_OBJS := +MODULE_DEFINES := +MODULE_OPTFLAGS := +MODULE_COMPILEFLAGS := +MODULE_CFLAGS := +MODULE_CPPFLAGS := +MODULE_ASMFLAGS := +MODULE_SRCDEPS := +MODULE_EXTRA_OBJS := +MODULE_CONFIG := +MODULE_OBJECT := +MODULE_ARM_OVERRIDE_SRCS := +MODULE_TYPE := +MODULE_NAME := diff --git a/kernel/make/recurse.mk b/kernel/make/recurse.mk new file mode 100644 index 000000000..ee960692b --- /dev/null +++ b/kernel/make/recurse.mk @@ -0,0 +1,31 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# included from the main makefile to include a set of rules.mk to satisfy +# the current MODULE list. If as a byproduct of including the rules.mk +# more stuff shows up on the MODULE list, recurse + +# Canonicalize module names so we never include one twice due +# to two versions of the name resolving to the same rules.mk on disk +MODULES := $(foreach d,$(strip $(MODULES)),$(call modname-make-canonical,$(strip $(d)))) + +# sort and filter out any modules that have already been included +MODULES := $(sort $(MODULES)) +MODULES := $(filter-out $(ALLMODULES),$(MODULES)) + +ifneq ($(MODULES),) + +ALLMODULES += $(MODULES) +ALLMODULES := $(sort $(ALLMODULES)) +INCMODULES := $(MODULES) +MODULES := +include $(addsuffix /rules.mk,$(INCMODULES)) + +include make/recurse.mk + +endif + diff --git a/kernel/make/ucompile.mk b/kernel/make/ucompile.mk new file mode 100644 index 000000000..dea49f15f --- /dev/null +++ b/kernel/make/ucompile.mk @@ -0,0 +1,104 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + + +# create a separate list of objects per source type +MODULE_CSRCS := $(filter %.c,$(MODULE_SRCS)) +MODULE_CPPSRCS := $(filter %.cpp,$(MODULE_SRCS)) +MODULE_ASMSRCS := $(filter %.S,$(MODULE_SRCS)) +MODULE_ASMSRCS2 := $(filter %.s,$(MODULE_SRCS)) + +MODULE_COBJS := $(call TOBUILDDIR,$(patsubst %.c,%.c.o,$(MODULE_CSRCS))) +MODULE_CPPOBJS := $(call TOBUILDDIR,$(patsubst %.cpp,%.cpp.o,$(MODULE_CPPSRCS))) +MODULE_ASMOBJS := $(call TOBUILDDIR,$(patsubst %.S,%.S.o,$(MODULE_ASMSRCS))) +MODULE_ASMOBJS2 := $(call TOBUILDDIR,$(patsubst %.s,%.s.o,$(MODULE_ASMSRCS2))) + +# do the same thing for files specified in arm override mode +MODULE_ARM_CSRCS := $(filter %.c,$(MODULE_ARM_OVERRIDE_SRCS)) +MODULE_ARM_CPPSRCS := $(filter %.cpp,$(MODULE_ARM_OVERRIDE_SRCS)) +MODULE_ARM_ASMSRCS := $(filter %.S,$(MODULE_ARM_OVERRIDE_SRCS)) +MODULE_ARM_ASMSRCS2 := $(filter %.s,$(MODULE_ARM_OVERRIDE_SRCS2)) + +MODULE_ARM_COBJS := $(call TOBUILDDIR,$(patsubst %.c,%.arm.c.o,$(MODULE_ARM_CSRCS))) +MODULE_ARM_CPPOBJS := $(call TOBUILDDIR,$(patsubst %.cpp,%.arm.cpp.o,$(MODULE_ARM_CPPSRCS))) +MODULE_ARM_ASMOBJS := $(call TOBUILDDIR,$(patsubst %.S,%.arm.S.o,$(MODULE_ARM_ASMSRCS))) +MODULE_ARM_ASMOBJS2 := $(call TOBUILDDIR,$(patsubst %.s,%.arm.s.o,$(MODULE_ARM_ASMSRCS2))) + +MODULE_OBJS := $(MODULE_COBJS) $(MODULE_CPPOBJS) $(MODULE_ASMOBJS) $(MODULE_ASMOBJS2) $(MODULE_ARM_COBJS) $(MODULE_ARM_CPPOBJS) $(MODULE_ARM_ASMOBJS) $(MODULE_ARM_ASMOBJS2) + +#$(info MODULE_SRCS = $(MODULE_SRCS)) +#$(info MODULE_CSRCS = $(MODULE_CSRCS)) +#$(info MODULE_CPPSRCS = $(MODULE_CPPSRCS)) +#$(info MODULE_ASMSRCS = $(MODULE_ASMSRCS)) +#$(info MODULE_ASMSRCS2 = $(MODULE_ASMSRCS2)) + +#$(info MODULE_OBJS = $(MODULE_OBJS)) +#$(info MODULE_COBJS = $(MODULE_COBJS)) +#$(info MODULE_CPPOBJS = $(MODULE_CPPOBJS)) +#$(info MODULE_ASMOBJS = $(MODULE_ASMOBJS)) +#$(info MODULE_ASMOBJS2 = $(MODULE_ASMOBJS2)) + +$(MODULE_OBJS): MODULE_OPTFLAGS:=$(MODULE_OPTFLAGS) +$(MODULE_OBJS): MODULE_COMPILEFLAGS:=$(MODULE_COMPILEFLAGS) +$(MODULE_OBJS): MODULE_CFLAGS:=$(MODULE_CFLAGS) +$(MODULE_OBJS): MODULE_CPPFLAGS:=$(MODULE_CPPFLAGS) +$(MODULE_OBJS): MODULE_ASMFLAGS:=$(MODULE_ASMFLAGS) +$(MODULE_OBJS): MODULE_SRCDEPS:=$(MODULE_SRCDEPS) + +$(MODULE_COBJS): $(BUILDDIR)/%.c.o: %.c $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CFLAGS) $(USER_CFLAGS) $(ARCH_CFLAGS) $(MODULE_CFLAGS) $(THUMBCFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_CPPOBJS): $(BUILDDIR)/%.cpp.o: %.cpp $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CPPFLAGS) $(USER_CPPFLAGS) $(ARCH_CPPFLAGS) $(MODULE_CPPFLAGS) $(THUMBCFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ASMOBJS): $(BUILDDIR)/%.S.o: %.S $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(USER_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) $(THUMBCFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ASMOBJS2): $(BUILDDIR)/%.s.o: %.s $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(USER_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) $(THUMBCFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +# overridden arm versions +$(MODULE_ARM_COBJS): $(BUILDDIR)/%.arm.c.o: %.c $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CFLAGS) $(USER_CFLAGS) $(ARCH_CFLAGS) $(MODULE_CFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ARM_CPPOBJS): $(BUILDDIR)/%.arm.cpp.o: %.cpp $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_CPPFLAGS) $(USER_CPPFLAGS) $(ARCH_CPPFLAGS) $(MODULE_CPPFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ARM_ASMOBJS): $(BUILDDIR)/%.arm.S.o: %.S $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(USER_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +$(MODULE_ARM_ASMOBJS2): $(BUILDDIR)/%.arm.s.o: %.s $(MODULE_SRCDEPS) + @$(MKDIR) + @echo compiling $< + $(NOECHO)$(CC) $(GLOBAL_OPTFLAGS) $(MODULE_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(USER_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(MODULE_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(USER_ASMFLAGS) $(ARCH_ASMFLAGS) $(MODULE_ASMFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +# clear some variables we set here +MODULE_CSRCS := +MODULE_CPPSRCS := +MODULE_ASMSRCS := +MODULE_COBJS := +MODULE_CPPOBJS := +MODULE_ASMOBJS := +MODULE_ASMOBJS2 := + +# MODULE_OBJS is passed back +#MODULE_OBJS := + diff --git a/kernel/makefile b/kernel/makefile new file mode 100644 index 000000000..fcaf49a6c --- /dev/null +++ b/kernel/makefile @@ -0,0 +1,45 @@ +# +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT +# + +# the above include may override LKROOT and LKINC to allow external +# directories to be included in the build +-include lk_inc.mk + +LKMAKEROOT ?= . +LKROOT ?= . +LKINC ?= +BUILDROOT ?= . +DEFAULT_PROJECT ?= +TOOLCHAIN_PREFIX ?= + +# check if LKROOT is already a part of LKINC list and add it only if it is not +ifneq ($(findstring $(LKROOT),$(LKINC)), $(LKROOT)) +LKINC := $(LKROOT) $(LKINC) +endif + +# add the external path to LKINC +ifneq ($(LKROOT),.) +LKINC += $(LKROOT)/external +else +LKINC += external +endif + +export LKMAKEROOT +export LKROOT +export LKINC +export BUILDROOT +export DEFAULT_PROJECT +export TOOLCHAIN_PREFIX + +# vaneer makefile that calls into the engine with lk as the build root +# if we're the top level invocation, call ourselves with additional args +$(MAKECMDGOALS) _top: + @$(MAKE) -C $(LKMAKEROOT) -rR -f $(LKROOT)/engine.mk $(addprefix -I,$(LKINC)) $(MAKECMDGOALS) + +.PHONY: _top diff --git a/kernel/platform/BUILD.gn b/kernel/platform/BUILD.gn new file mode 100644 index 000000000..8586f8c99 --- /dev/null +++ b/kernel/platform/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("platform") { + configs += [ "//kernel/kernel:enable_vm" ] + sources = [ + "debug.c", + "init.c", + "power.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/kernel/platform/debug.c b/kernel/platform/debug.c new file mode 100644 index 000000000..0ca901599 --- /dev/null +++ b/kernel/platform/debug.c @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include + +/* Default implementation of panic time getc/putc. + * Just calls through to the underlying dputc/dgetc implementation + * unless the platform overrides it. + */ +__WEAK void platform_pputc(char c) +{ + return platform_dputc(c); +} + +__WEAK int platform_pgetc(char *c, bool wait) +{ + return platform_dgetc(c, wait); +} diff --git a/kernel/platform/init.c b/kernel/platform/init.c new file mode 100644 index 000000000..ba10f0862 --- /dev/null +++ b/kernel/platform/init.c @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include + +/* + * default implementations of these routines, if the platform code + * chooses not to implement. + */ + +__WEAK void platform_init_mmu_mappings(void) +{ +} + +__WEAK void platform_early_init(void) +{ +} + +__WEAK void platform_init(void) +{ +} + +__WEAK void platform_quiesce(void) +{ +} + diff --git a/kernel/platform/pc/BUILD.gn b/kernel/platform/pc/BUILD.gn new file mode 100644 index 000000000..e5649e043 --- /dev/null +++ b/kernel/platform/pc/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "x64") + +import("//gnbuild/config.gni") + +config("_pc_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("pc") { + configs += [ "//kernel/kernel:enable_vm" ] + public_configs = [ ":_pc_config" ] + defines = kernel_defines + cflags = [ "-Wno-pointer-to-int-cast" ] + public = [ + "include/pcnet.h", + "include/platform/pcnet.h", + "include/platform/acpi.h", + "include/platform/uart.h", + "include/platform/pc/memmap.h", + "include/platform/pc/iomap.h", + "include/platform/keyboard.h", + "include/platform/pc.h", + "include/platform/multiboot.h", + "include/platform/ide.h", + "include/platform/console.h", + "include/platform/pic.h", + ] + sources = [ + "acpi.c", + "acpi_debug.c", + "console.c", + "debug.c", + "ide.c", + "interrupts.c", + "keyboard.c", + "memory.c", + "pci.c", + "pic.c", + "platform.c", + "platform_p.h", + "timer.c", + "uart.c", + ] + deps = [ + "//kernel/dev/interrupt", + "//kernel/lib/cbuf", + "//kernel/lib/console", + "//kernel/lib/gfxconsole", + "//kernel/lib/libc", + "//kernel/lib/pow2_range_allocator", + "//third_party/lib/acpica", + ] + if (enable_pcie) { + deps += [ "//kernel/dev/pcie" ] + } +} diff --git a/kernel/platform/pc/acpi.c b/kernel/platform/pc/acpi.c new file mode 100644 index 000000000..f0920e38a --- /dev/null +++ b/kernel/platform/pc/acpi.c @@ -0,0 +1,671 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define ACPI_MAX_INIT_TABLES 16 +static ACPI_TABLE_DESC acpi_tables[ACPI_MAX_INIT_TABLES]; +static bool acpi_initialized = false; + +static ACPI_STATUS acpi_set_apic_irq_mode(void); + +/** + * @brief Initialize early-access ACPI tables + * + * This function enables *only* the ACPICA Table Manager subsystem. + * The rest of the ACPI subsystem will remain uninitialized. + */ +void platform_init_acpi_tables(uint level) +{ + DEBUG_ASSERT(!acpi_initialized); + + ACPI_STATUS status; + status = AcpiInitializeTables(acpi_tables, ACPI_MAX_INIT_TABLES, FALSE); + + if (status == AE_NOT_FOUND) { + TRACEF("WARNING: could not find ACPI tables\n"); + return; + } else if (status == AE_NO_MEMORY) { + TRACEF("WARNING: could not initialize ACPI tables\n"); + return; + } else if (status != AE_OK) { + TRACEF("WARNING: could not initialize ACPI tables for unknown reason\n"); + return; + } + + acpi_initialized = true; + LTRACEF("ACPI tables initialized\n"); +} + +/** + * @brief Handle the Power Button Fixed Event + * + * We simply write to a well known port. A user-mode driver should pick + * this event and take action. + */ +static uint32_t power_button_event_handler(void* ctx) +{ + port_packet_t packet = { {"1"} }; + port_write((port_t) ctx, &packet, 1); + // Note that the spec indicates to return 0. The code in the + // Intel implementation (AcpiEvFixedEventDetect) reads differently. + return ACPI_INTERRUPT_HANDLED; +} + +/** + * @brief Initialize the entire ACPI subsystem + * + * This subsystem depends on the following subsystems + * 1) VM + * 2) Timers + * 3) Interrupts + */ +void platform_init_acpi(void) +{ + // This sequence is described in section 10.1.2.2 (ACPICA Initialization With + // Early ACPI Table Access) of the ACPICA developer's reference. + ACPI_STATUS status = AcpiInitializeSubsystem(); + if (status != AE_OK) { + TRACEF("WARNING: could not initialize ACPI\n"); + // TODO: Do something better here + return; + } + + status = AcpiReallocateRootTable(); + if (status != AE_OK) { + TRACEF("WARNING: could not reallocate ACPI root table\n"); + // TODO: Do something better here + return; + } + + status = AcpiLoadTables(); + if (status != AE_OK) { + TRACEF("WARNING: could not load ACPI tables\n"); + // TODO: Do something better here + return; + } + + // TODO: Install local handlers here + + status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); + if (status != AE_OK) { + TRACEF("WARNING: could not enable ACPI\n"); + // TODO: Do something better here + return; + } + + status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); + if (status != AE_OK) { + TRACEF("WARNING: could not initialize ACPI objects\n"); + // TODO: Do something better here + return; + } + + status = acpi_set_apic_irq_mode(); + if (status == AE_NOT_FOUND) { + TRACEF("WARNING: Could not find ACPI IRQ mode switch\n"); + } else { + ASSERT(status == AE_OK); + } + + port_t power_button_port; + if (port_create(POWER_BUTTON_PORT, PORT_MODE_BROADCAST, + &power_button_port) < 0) { + TRACEF("Failed to create power button port\n"); + return; + } + + status = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, + power_button_event_handler, + power_button_port); + if (status != AE_OK) { + printf("Failed to install POWER_BUTTON handler\n"); + } + + LTRACEF("ACPI initialized\n"); +} +/* initialize ACPI tables as soon as we have a working VM */ +LK_INIT_HOOK(acpi_tables, &platform_init_acpi_tables, LK_INIT_LEVEL_VM + 1); + +/* @brief Switch interrupts to APIC model (controls IRQ routing) */ +static ACPI_STATUS acpi_set_apic_irq_mode(void) +{ + ACPI_OBJECT selector = { + .Integer.Type = ACPI_TYPE_INTEGER, + .Integer.Value = 1, // 1 means APIC mode according to ACPI v5 5.8.1 + }; + ACPI_OBJECT_LIST params = { + .Count = 1, + .Pointer = &selector, + }; + return AcpiEvaluateObject(NULL, (char *)"\\_PIC", ¶ms, NULL); +} + +/* Helper routine for translating IRQ routing tables into usable form + * + * @param port_dev_id The device ID on the root bus of this root port or + * UINT8_MAX if this call is for the root bus, not a root port + * @param port_func_id The function ID on the root bus of this root port or + * UINT8_MAX if this call is for the root bus, not a root port + */ +static ACPI_STATUS acpi_handle_prt( + ACPI_HANDLE object, + struct acpi_pcie_irq_mapping *irq_mapping, + uint8_t port_dev_id, + uint8_t port_func_id) +{ + ASSERT((port_dev_id == UINT8_MAX && port_func_id == UINT8_MAX) || + (port_dev_id != UINT8_MAX && port_func_id != UINT8_MAX)); + + ACPI_BUFFER buffer = { + // Request that the ACPI subsystem allocate the buffer + .Length = ACPI_ALLOCATE_BUFFER, + .Pointer = NULL, + }; + ACPI_BUFFER crs_buffer = { + .Length = ACPI_ALLOCATE_BUFFER, + .Pointer = NULL, + }; + + ACPI_STATUS status = AcpiGetIrqRoutingTable(object, &buffer); + // IRQ routing tables are *required* to exist on the root hub + if (status != AE_OK) { + goto cleanup; + } + DEBUG_ASSERT(buffer.Pointer); + + uintptr_t entry_addr = (uintptr_t)buffer.Pointer; + ACPI_PCI_ROUTING_TABLE *entry; + for (entry = (ACPI_PCI_ROUTING_TABLE *)entry_addr; + entry->Length != 0; + entry_addr += entry->Length, entry = (ACPI_PCI_ROUTING_TABLE *)entry_addr) { + + DEBUG_ASSERT(entry_addr <= (uintptr_t)buffer.Pointer + buffer.Length); + if (entry->Pin >= PCIE_MAX_LEGACY_IRQ_PINS) { + return AE_ERROR; + } + uint8_t dev_id = (entry->Address >> 16) & (PCIE_MAX_DEVICES_PER_BUS - 1); + // Either we're handling the root complex (port_dev_id == UINT8_MAX), or + // we're handling a root port, and if it's a root port, dev_id should + // be 0. + ASSERT(port_dev_id == UINT8_MAX || dev_id == 0); + + uint32_t global_irq = ACPI_NO_IRQ_MAPPING; + bool level_triggered = true; + bool active_high = false; + if (entry->Source[0]) { + // If the Source is not just a NULL byte, then it refers to a + // PCI Interrupt Link Device + ACPI_HANDLE ild; + status = AcpiGetHandle(object, entry->Source, &ild); + if (status != AE_OK) { + goto cleanup; + } + status = AcpiGetCurrentResources(ild, &crs_buffer); + if (status != AE_OK) { + goto cleanup; + } + DEBUG_ASSERT(crs_buffer.Pointer); + + uintptr_t crs_entry_addr = (uintptr_t)crs_buffer.Pointer; + ACPI_RESOURCE *res = (ACPI_RESOURCE *)crs_entry_addr; + while (res->Type != ACPI_RESOURCE_TYPE_END_TAG) { + if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { + ACPI_RESOURCE_EXTENDED_IRQ *irq = &res->Data.ExtendedIrq; + if (global_irq != ACPI_NO_IRQ_MAPPING) { + // TODO: Handle finding two allocated IRQs. Shouldn't + // happen? + PANIC_UNIMPLEMENTED; + } + if (irq->InterruptCount != 1) { + // TODO: Handle finding two allocated IRQs. Shouldn't + // happen? + PANIC_UNIMPLEMENTED; + } + if (irq->Interrupts[0] != 0) { + active_high = (irq->Polarity == IRQ_POLARITY_ACTIVE_HIGH); + level_triggered = (irq->Triggering == IRQ_TRIGGER_MODE_LEVEL); + global_irq = irq->Interrupts[0]; + } + } else { + // TODO: Handle non extended IRQs + PANIC_UNIMPLEMENTED; + } + crs_entry_addr += res->Length; + res = (ACPI_RESOURCE *)crs_entry_addr; + } + if (global_irq == ACPI_NO_IRQ_MAPPING) { + // TODO: Invoke PRS to find what is allocatable and allocate it with SRS + PANIC_UNIMPLEMENTED; + } + AcpiOsFree(crs_buffer.Pointer); + crs_buffer.Length = ACPI_ALLOCATE_BUFFER; + crs_buffer.Pointer = NULL; + } else { + // Otherwise, SourceIndex refers to a global IRQ number that the pin + // is connected to + global_irq = entry->SourceIndex; + } + + // Check if we've seen this IRQ already, and if so, confirm the + // IRQ signaling is the same. + bool found_irq = false; + for (uint i = 0; i < irq_mapping->num_irqs; ++i) { + struct acpi_irq_signal *sig = &irq_mapping->irqs[i]; + if (global_irq != sig->global_irq) { + continue; + } + if (active_high != sig->active_high || + level_triggered != sig->level_triggered) { + + // TODO: Handle mismatch here + PANIC_UNIMPLEMENTED; + } + found_irq = true; + break; + } + if (!found_irq) { + ASSERT(irq_mapping->num_irqs < countof(irq_mapping->irqs)); + struct acpi_irq_signal *sig = &irq_mapping->irqs[irq_mapping->num_irqs]; + sig->global_irq = global_irq; + sig->active_high = active_high; + sig->level_triggered = level_triggered; + irq_mapping->num_irqs++; + } + + if (port_dev_id == UINT8_MAX) { + for (uint i = 0; i < PCIE_MAX_FUNCTIONS_PER_DEVICE; ++i) { + irq_mapping->dev_pin_to_global_irq[dev_id][i][entry->Pin] = + global_irq; + } + } else { + irq_mapping->dev_pin_to_global_irq[port_dev_id][port_func_id][entry->Pin] = global_irq; + } + } + +cleanup: + if (crs_buffer.Pointer) { + AcpiOsFree(crs_buffer.Pointer); + } + if (buffer.Pointer) { + AcpiOsFree(buffer.Pointer); + } + return status; +} + +/* @brief Device enumerator for platform_configure_pcie_legacy_irqs */ +static ACPI_STATUS acpi_get_pcie_devices_irq( + ACPI_HANDLE object, + UINT32 nesting_level, + void *context, + void **ret) +{ + struct acpi_pcie_irq_mapping *irq_mapping = context; + ACPI_STATUS status = acpi_handle_prt( + object, + irq_mapping, + UINT8_MAX, + UINT8_MAX); + if (status != AE_OK) { + return status; + } + + // Enumerate root ports + ACPI_HANDLE child = NULL; + while (1) { + status = AcpiGetNextObject(ACPI_TYPE_DEVICE, object, child, &child); + if (status == AE_NOT_FOUND) { + break; + } else if (status != AE_OK) { + printf("Failed to get next child object of root complex\n"); + return status; + } + + ACPI_OBJECT object = { 0 }; + ACPI_BUFFER buffer = { + .Length = sizeof(object), + .Pointer = &object, + }; + status = AcpiEvaluateObject(child, (char *)"_ADR", NULL, &buffer); + if (status != AE_OK || + buffer.Length < sizeof(object) || + object.Type != ACPI_TYPE_INTEGER) { + + continue; + } + UINT64 data = object.Integer.Value; + uint8_t port_dev_id = (data >> 16) & (PCIE_MAX_DEVICES_PER_BUS - 1); + uint8_t port_func_id = data & (PCIE_MAX_FUNCTIONS_PER_DEVICE - 1); + // Ignore the return value of this, since if child is not a + // root port, it will fail and we don't care. + acpi_handle_prt( + child, + irq_mapping, + port_dev_id, + port_func_id); + } + return AE_OK; +} + +/* @brief Find the legacy IRQ swizzling for the PCIe root bus + * + * @param root_bus_map The mapping to populate + * + * @return NO_ERROR on success + */ +status_t platform_find_pcie_legacy_irq_mapping(struct acpi_pcie_irq_mapping *root_bus_map) +{ + uint map_len = sizeof(root_bus_map->dev_pin_to_global_irq)/sizeof(uint32_t); + for (uint i = 0; i < map_len; ++i) { + uint32_t *flat_map = (uint32_t *)&root_bus_map->dev_pin_to_global_irq; + flat_map[i] = ACPI_NO_IRQ_MAPPING; + } + root_bus_map->num_irqs = 0; + + ACPI_STATUS status = AcpiGetDevices( + (char*)"PNP0A08", // PCIe root hub + acpi_get_pcie_devices_irq, + root_bus_map, + NULL); + if (status != AE_OK) { + return ERR_GENERIC; + } + return NO_ERROR; +} + +void acpi_poweroff(void) +{ + ACPI_STATUS status = AcpiEnterSleepStatePrep(5); + if (status == AE_OK) { + AcpiEnterSleepState(5); + } +} + +status_t acpi_get_madt_record_limits(uintptr_t *start, uintptr_t *end) +{ + ACPI_TABLE_HEADER *table = NULL; + ACPI_STATUS status = AcpiGetTable((char *)ACPI_SIG_MADT, 1, &table); + if (status != AE_OK) { + TRACEF("could not find MADT\n"); + return ERR_NOT_FOUND; + } + ACPI_TABLE_MADT *madt = (ACPI_TABLE_MADT *)table; + uintptr_t records_start = ((uintptr_t)madt) + sizeof(*madt); + uintptr_t records_end = ((uintptr_t)madt) + madt->Header.Length; + if (records_start >= records_end) { + TRACEF("MADT wraps around address space\n"); + return ERR_NOT_VALID; + } + // Shouldn't be too many records + if (madt->Header.Length > 4096) { + TRACEF("MADT suspiciously long: %d\n", madt->Header.Length); + return ERR_NOT_VALID; + } + *start = records_start; + *end = records_end; + return NO_ERROR; +} + +/* @brief Enumerate all functioning CPUs and their APIC IDs + * + * If apic_ids is NULL, just returns the number of logical processors + * via num_cpus. + * + * @param apic_ids Array to write found APIC ids into. + * @param len Length of apic_ids. + * @param num_cpus Output for the number of logical processors detected. + * + * @return NO_ERROR on success. Note that if len < *num_cpus, not all + * logical apic_ids will be returned. + */ +status_t platform_enumerate_cpus( + uint32_t *apic_ids, + uint32_t len, + uint32_t *num_cpus) +{ + if (num_cpus == NULL) { + return ERR_INVALID_ARGS; + } + + uintptr_t records_start, records_end; + status_t status = acpi_get_madt_record_limits(&records_start, &records_end); + if (status != AE_OK) { + return status; + } + uint32_t count = 0; + uintptr_t addr; + for (addr = records_start; addr < records_end;) { + ACPI_SUBTABLE_HEADER *record_hdr = (ACPI_SUBTABLE_HEADER *)addr; + switch (record_hdr->Type) { + case ACPI_MADT_TYPE_LOCAL_APIC: { + ACPI_MADT_LOCAL_APIC *lapic = (ACPI_MADT_LOCAL_APIC *)record_hdr; + if (!(lapic->LapicFlags & ACPI_MADT_ENABLED)) { + TRACEF("Skipping disabled processor %02x\n", lapic->Id); + continue; + } + if (apic_ids != NULL && count < len) { + apic_ids[count] = lapic->Id; + } + count++; + break; + } + } + + addr += record_hdr->Length; + } + if (addr != records_end) { + TRACEF("malformed MADT\n"); + return ERR_NOT_VALID; + } + *num_cpus = count; + return NO_ERROR; +} + +/* @brief Enumerate all IO APICs + * + * If io_apics is NULL, just returns the number of IO APICs + * via num_io_apics. + * + * @param io_apics Array to populate descriptors into. + * @param len Length of io_apics. + * @param num_io_apics Number of IO apics found + * + * @return NO_ERROR on success. Note that if len < *num_io_apics, not all + * IO APICs will be returned. + */ +status_t platform_enumerate_io_apics( + struct io_apic_descriptor *io_apics, + uint32_t len, + uint32_t *num_io_apics) +{ + if (num_io_apics == NULL) { + return ERR_INVALID_ARGS; + } + + uintptr_t records_start, records_end; + status_t status = acpi_get_madt_record_limits(&records_start, &records_end); + if (status != AE_OK) { + return status; + } + + uint32_t count = 0; + uintptr_t addr; + for (addr = records_start; addr < records_end;) { + ACPI_SUBTABLE_HEADER *record_hdr = (ACPI_SUBTABLE_HEADER *)addr; + switch (record_hdr->Type) { + case ACPI_MADT_TYPE_IO_APIC: { + ACPI_MADT_IO_APIC *io_apic = (ACPI_MADT_IO_APIC *)record_hdr; + if (io_apics != NULL && count < len) { + io_apics[count].apic_id = io_apic->Id; + io_apics[count].paddr = io_apic->Address; + io_apics[count].global_irq_base = io_apic->GlobalIrqBase; + } + count++; + break; + } + } + + addr += record_hdr->Length; + } + if (addr != records_end) { + TRACEF("malformed MADT\n"); + return ERR_NOT_VALID; + } + *num_io_apics = count; + return NO_ERROR; +} + +/* @brief Enumerate all interrupt source overrides + * + * If isos is NULL, just returns the number of ISOs via num_isos. + * + * @param isos Array to populate overrides into. + * @param len Length of isos. + * @param num_isos Number of ISOs found + * + * @return NO_ERROR on success. Note that if len < *num_isos, not all + * ISOs will be returned. + */ +status_t platform_enumerate_interrupt_source_overrides( + struct io_apic_isa_override *isos, + uint32_t len, + uint32_t *num_isos) +{ + if (num_isos == NULL) { + return ERR_INVALID_ARGS; + } + + uintptr_t records_start, records_end; + status_t status = acpi_get_madt_record_limits(&records_start, &records_end); + if (status != AE_OK) { + return status; + } + + uint32_t count = 0; + uintptr_t addr; + for (addr = records_start; addr < records_end;) { + ACPI_SUBTABLE_HEADER *record_hdr = (ACPI_SUBTABLE_HEADER *)addr; + switch (record_hdr->Type) { + case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: { + ACPI_MADT_INTERRUPT_OVERRIDE *iso = + (ACPI_MADT_INTERRUPT_OVERRIDE *)record_hdr; + if (isos != NULL && count < len) { + ASSERT(iso->Bus == 0); // 0 means ISA, ISOs are only ever for ISA IRQs + isos[count].isa_irq = iso->SourceIrq; + isos[count].remapped = true; + isos[count].global_irq = iso->GlobalIrq; + + uint32_t flags = iso->IntiFlags; + uint32_t polarity = flags & ACPI_MADT_POLARITY_MASK; + uint32_t trigger = flags & ACPI_MADT_TRIGGER_MASK; + + // Conforms below means conforms to the bus spec. ISA is + // edge triggered and active high. + switch (polarity) { + case ACPI_MADT_POLARITY_CONFORMS: + case ACPI_MADT_POLARITY_ACTIVE_HIGH: + isos[count].pol = IRQ_POLARITY_ACTIVE_HIGH; + break; + case ACPI_MADT_POLARITY_ACTIVE_LOW: + isos[count].pol = IRQ_POLARITY_ACTIVE_LOW; + break; + default: + panic("Unknown IRQ polarity in override: %d\n", + polarity); + } + + switch (trigger) { + case ACPI_MADT_TRIGGER_CONFORMS: + case ACPI_MADT_TRIGGER_EDGE: + isos[count].tm = IRQ_TRIGGER_MODE_EDGE; + break; + case ACPI_MADT_TRIGGER_LEVEL: + isos[count].tm = IRQ_TRIGGER_MODE_LEVEL; + break; + default: + panic("Unknown IRQ trigger in override: %d\n", + trigger); + } + } + count++; + break; + } + } + + addr += record_hdr->Length; + } + if (addr != records_end) { + TRACEF("malformed MADT\n"); + return ERR_NOT_VALID; + } + *num_isos = count; + return NO_ERROR; +} + +/* @brief Find the PCIE config (returns the first one found) + * + * @param config The structure to populate with the found config. + * + * @return NO_ERROR on success. + */ +status_t platform_find_pcie_config(struct acpi_pcie_config *config) +{ + ACPI_TABLE_HEADER *raw_table = NULL; + ACPI_STATUS status = AcpiGetTable((char *)ACPI_SIG_MCFG, 1, &raw_table); + if (status != AE_OK) { + TRACEF("could not find MCFG\n"); + return ERR_NOT_FOUND; + } + ACPI_TABLE_MCFG *mcfg = (ACPI_TABLE_MCFG *)raw_table; + ACPI_MCFG_ALLOCATION *table_start = ((void *)mcfg) + sizeof(*mcfg); + ACPI_MCFG_ALLOCATION *table_end = ((void *)mcfg) + mcfg->Header.Length; + uintptr_t table_bytes = (uintptr_t)table_end - (uintptr_t)table_start; + if (table_bytes % sizeof(*table_start) != 0) { + TRACEF("MCFG has unexpected size\n"); + return ERR_NOT_VALID; + } + int num_entries = table_end - table_start; + if (num_entries == 0) { + TRACEF("MCFG has no entries\n"); + return ERR_NOT_FOUND; + } + if (num_entries > 1) { + TRACEF("MCFG has more than one entry, just taking the first\n"); + } + + size_t size_per_bus = PCIE_EXTENDED_CONFIG_SIZE * + PCIE_MAX_DEVICES_PER_BUS * PCIE_MAX_FUNCTIONS_PER_DEVICE; + int num_buses = table_start->EndBusNumber - table_start->StartBusNumber + 1; + + config->segment_group = table_start->PciSegment; + config->start_bus = table_start->StartBusNumber; + config->end_bus = table_start->EndBusNumber; + // We need to adjust the physical address we received to align to the proper + // bus number. + // + // Citation from PCI Firmware Spec 3.0: + // For PCI-X and PCI Express platforms utilizing the enhanced + // configuration access method, the base address of the memory mapped + // configuration space always corresponds to bus number 0 (regardless + // of the start bus number decoded by the host bridge). + config->ecam_phys = table_start->Address + size_per_bus * config->start_bus; + // The size of this mapping is defined in the PCI Firmware v3 spec to be + // big enough for all of the buses in this config. + config->ecam_size = size_per_bus * num_buses; + return NO_ERROR; +} diff --git a/kernel/platform/pc/acpi_debug.c b/kernel/platform/pc/acpi_debug.c new file mode 100644 index 000000000..0a057fc07 --- /dev/null +++ b/kernel/platform/pc/acpi_debug.c @@ -0,0 +1,541 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +//#include "acdisasm.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +extern status_t acpi_get_madt_record_limits(uintptr_t *start, uintptr_t *end); + +static void acpi_debug_madt(void) +{ + uintptr_t records_start, records_end; + status_t status = acpi_get_madt_record_limits(&records_start, &records_end); + if (status != AE_OK) { + printf("Invalid MADT\n"); + return; + } + + uintptr_t addr; + for (addr = records_start; addr < records_end;) { + ACPI_SUBTABLE_HEADER *record_hdr = (ACPI_SUBTABLE_HEADER *)addr; + printf("Entry type %2d ", record_hdr->Type); + switch (record_hdr->Type) { + case ACPI_MADT_TYPE_LOCAL_APIC: { + ACPI_MADT_LOCAL_APIC *apic = (ACPI_MADT_LOCAL_APIC *)record_hdr; + printf("Local APIC\n"); + printf(" ACPI id: %02x\n", apic->ProcessorId); + printf(" APIC id: %02x\n", apic->Id); + printf(" flags: %08x\n", apic->LapicFlags); + break; + } + case ACPI_MADT_TYPE_IO_APIC: { + ACPI_MADT_IO_APIC *apic = (ACPI_MADT_IO_APIC *)record_hdr; + printf("IO APIC\n"); + printf(" APIC id: %02x\n", apic->Id); + printf(" phys: %08x\n", apic->Address); + printf(" global IRQ base: %08x\n", apic->GlobalIrqBase); + break; + } + case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: { + ACPI_MADT_INTERRUPT_OVERRIDE *io = + (ACPI_MADT_INTERRUPT_OVERRIDE *)record_hdr; + printf("Interrupt Source Override\n"); + printf(" bus: %02x (ISA==0)\n", io->Bus); + printf(" source IRQ: %02x\n", io->SourceIrq); + printf(" global IRQ: %08x\n", io->GlobalIrq); + const char *trigger = ""; + const char *polarity = ""; + switch (io->IntiFlags & ACPI_MADT_POLARITY_MASK) { + case ACPI_MADT_POLARITY_CONFORMS: + polarity = "conforms"; break; + case ACPI_MADT_POLARITY_ACTIVE_HIGH: + polarity = "high"; break; + case ACPI_MADT_POLARITY_RESERVED: + polarity = "invalid"; break; + case ACPI_MADT_POLARITY_ACTIVE_LOW: + polarity = "low"; break; + } + switch (io->IntiFlags & ACPI_MADT_TRIGGER_MASK) { + case ACPI_MADT_TRIGGER_CONFORMS: + trigger = "conforms"; break; + case ACPI_MADT_TRIGGER_EDGE: + trigger = "edge"; break; + case ACPI_MADT_TRIGGER_RESERVED: + trigger = "invalid"; break; + case ACPI_MADT_TRIGGER_LEVEL: + trigger = "level"; break; + } + + printf(" flags: %04x (trig %s, pol %s)\n", + io->IntiFlags, trigger, polarity); + break; + } + case ACPI_MADT_TYPE_LOCAL_APIC_NMI: { + ACPI_MADT_LOCAL_APIC_NMI *nmi = + (ACPI_MADT_LOCAL_APIC_NMI *)record_hdr; + printf("Local APIC NMI\n"); + printf(" ACPI processor id: %02x\n", nmi->ProcessorId); + printf(" flags: %04x\n", nmi->IntiFlags); + printf(" LINTn: %02x\n", nmi->Lint); + break; + } + default: + printf("Unknown\n"); + } + + addr += record_hdr->Length; + } + if (addr != records_end) { + printf("malformed MADT, last record past the end of the table\n"); + } +} + +static void acpi_debug_mcfg(void) +{ + ACPI_TABLE_HEADER *raw_table = NULL; + ACPI_STATUS status = AcpiGetTable((char *)ACPI_SIG_MCFG, 1, &raw_table); + if (status != AE_OK) { + printf("could not find MCFG\n"); + return; + } + ACPI_TABLE_MCFG *mcfg = (ACPI_TABLE_MCFG *)raw_table; + ACPI_MCFG_ALLOCATION *table_start = ((void *)mcfg) + sizeof(*mcfg); + ACPI_MCFG_ALLOCATION *table_end = ((void *)mcfg) + mcfg->Header.Length; + ACPI_MCFG_ALLOCATION *table; + int count = 0; + if (table_start + 1 > table_end) { + printf("MCFG has unexpected size\n"); + return; + } + for (table = table_start; table < table_end; ++table) { + printf("Controller %d:\n", count); + printf(" Physical address: %#016llx\n", table->Address); + printf(" Segment group: %04x\n", table->PciSegment); + printf(" Start bus number: %02x\n", table->StartBusNumber); + printf(" End bus number: %02x\n", table->EndBusNumber); + ++count; + } + if (table != table_end) { + printf("MCFG has unexpected size\n"); + return; + } +} + +static inline void do_indent(uint level) { + while (level) { + printf(" "); + level--; + } +} + +#define INDENT_PRINTF( ...) do { do_indent(level); printf(__VA_ARGS__); } while (0) + +enum print_resource_request { + CURRENT_RESOURCES, + POSSIBLE_RESOURCES, +}; + +static ACPI_STATUS acpi_print_resources( + ACPI_HANDLE object, + uint level, + enum print_resource_request type) +{ + ACPI_BUFFER buffer = { + .Length = ACPI_ALLOCATE_BUFFER, + .Pointer = NULL, + }; + ACPI_STATUS status = AE_BAD_PARAMETER; + if (type == POSSIBLE_RESOURCES) { + status = AcpiGetPossibleResources(object, &buffer); + } else if (type == CURRENT_RESOURCES) { + status = AcpiGetCurrentResources(object, &buffer); + } else { + printf("Invalid resource type to print\n"); + return AE_BAD_PARAMETER;; + } + + if (status != AE_OK) { + if (buffer.Pointer) { + AcpiOsFree(buffer.Pointer); + } + return status; + } + if (type == POSSIBLE_RESOURCES) { + INDENT_PRINTF("PRS:\n"); + } else if (type == CURRENT_RESOURCES) { + INDENT_PRINTF("CRS:\n"); + } + + uintptr_t entry_addr = (uintptr_t)buffer.Pointer; + ACPI_RESOURCE *res = (ACPI_RESOURCE *)entry_addr; + level += 1; + while (res->Type != ACPI_RESOURCE_TYPE_END_TAG) { + INDENT_PRINTF("Entry: "); + level += 1; + switch (res->Type) { + case ACPI_RESOURCE_TYPE_IO: { + printf("IO\n"); + ACPI_RESOURCE_IO *io = &res->Data.Io; + INDENT_PRINTF("io_decode: %d\n", io->IoDecode); + INDENT_PRINTF("alignment: %d\n", io->Alignment); + INDENT_PRINTF("addrlen: %d\n", io->AddressLength); + INDENT_PRINTF("address min: %#04x\n", io->Minimum); + INDENT_PRINTF("address max: %#04x\n", io->Maximum); + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS16: { + printf("Address16\n"); + ACPI_RESOURCE_ADDRESS16 *a16 = &res->Data.Address16; + INDENT_PRINTF("res_type: %d\n", a16->ResourceType); + INDENT_PRINTF("produce_consume: %d\n", a16->ProducerConsumer); + INDENT_PRINTF("decode: %d\n", a16->Decode); + INDENT_PRINTF("min_addr_fixed: %d\n", a16->MinAddressFixed); + INDENT_PRINTF("max_addr_fixed: %d\n", a16->MaxAddressFixed); + INDENT_PRINTF("address granularity: %#04x\n", a16->Address.Granularity); + INDENT_PRINTF("address min: %#04x\n", a16->Address.Minimum); + INDENT_PRINTF("address max: %#04x\n", a16->Address.Maximum); + INDENT_PRINTF("address xlat offset: %#04x\n", a16->Address.TranslationOffset); + INDENT_PRINTF("address len: %#04x\n", a16->Address.AddressLength); + // TODO: extract MTRR info from a16->Info + break; + } + case ACPI_RESOURCE_TYPE_ADDRESS32: { + printf("Address32\n"); + ACPI_RESOURCE_ADDRESS32 *a32 = &res->Data.Address32; + INDENT_PRINTF("res_type: %d\n", a32->ResourceType); + INDENT_PRINTF("produce_consume: %d\n", a32->ProducerConsumer); + INDENT_PRINTF("decode: %d\n", a32->Decode); + INDENT_PRINTF("min_addr_fixed: %d\n", a32->MinAddressFixed); + INDENT_PRINTF("max_addr_fixed: %d\n", a32->MaxAddressFixed); + INDENT_PRINTF("address granularity: %#08x\n", a32->Address.Granularity); + INDENT_PRINTF("address min: %#08x\n", a32->Address.Minimum); + INDENT_PRINTF("address max: %#08x\n", a32->Address.Maximum); + INDENT_PRINTF("address xlat offset: %#08x\n", a32->Address.TranslationOffset); + INDENT_PRINTF("address len: %#08x\n", a32->Address.AddressLength); + // TODO: extract MTRR info from a32->Info + break; + } + case ACPI_RESOURCE_TYPE_IRQ: { + printf("IRQ\n"); + ACPI_RESOURCE_IRQ *irq = &res->Data.Irq; + INDENT_PRINTF("trigger: %s\n", irq->Triggering == ACPI_EDGE_SENSITIVE ? "edge" : "level"); + const char *pol = "invalid"; + switch (irq->Polarity) { + case ACPI_ACTIVE_BOTH: pol = "both"; break; + case ACPI_ACTIVE_LOW: pol = "low"; break; + case ACPI_ACTIVE_HIGH: pol = "high"; break; + } + INDENT_PRINTF("polarity: %s\n", pol); + INDENT_PRINTF("sharable: %d\n", irq->Sharable); + INDENT_PRINTF("wake_cap: %d\n", irq->WakeCapable); + for (uint i = 0; i < irq->InterruptCount; ++i) { + INDENT_PRINTF("irq #%d: %d\n", i, irq->Interrupts[i]); + } + break; + } + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: { + printf("Extended IRQ\n"); + ACPI_RESOURCE_EXTENDED_IRQ *irq = &res->Data.ExtendedIrq; + INDENT_PRINTF("produce_consume: %d\n", irq->ProducerConsumer); + INDENT_PRINTF("trigger: %s\n", irq->Triggering == ACPI_EDGE_SENSITIVE ? "edge" : "level"); + const char *pol = "invalid"; + switch (irq->Polarity) { + case ACPI_ACTIVE_BOTH: pol = "both"; break; + case ACPI_ACTIVE_LOW: pol = "low"; break; + case ACPI_ACTIVE_HIGH: pol = "high"; break; + } + INDENT_PRINTF("polarity: %s\n", pol); + INDENT_PRINTF("sharable: %d\n", irq->Sharable); + INDENT_PRINTF("wake_cap: %d\n", irq->WakeCapable); + for (uint i = 0; i < irq->InterruptCount; ++i) { + INDENT_PRINTF("irq #%d: %d\n", i, irq->Interrupts[i]); + } + break; + } + default: + printf("Unknown (type %u)\n", res->Type); + } + level -= 1; + + entry_addr += res->Length; + res = (ACPI_RESOURCE *)entry_addr; + } + level -= 1; + + AcpiOsFree(buffer.Pointer); + return AE_OK; +} + +static ACPI_STATUS acpi_get_pcie_devices_crs( + ACPI_HANDLE object, + UINT32 nesting_level, + void *context, + void **ret) +{ + printf("Found object %p\n", object); + return acpi_print_resources(object, 1, CURRENT_RESOURCES); +} + +static void acpi_debug_pcie_crs(void) +{ + ACPI_STATUS status = AcpiGetDevices( + (char*)"PNP0A08", + acpi_get_pcie_devices_crs, + NULL, + NULL); + if (status != AE_OK) { + printf("Could not find PCIe root complex\n"); + } +} + +static ACPI_STATUS acpi_print_prt(uint level, ACPI_HANDLE object) +{ + ACPI_STATUS status = AE_OK; + + ACPI_BUFFER buffer = { + // Request that the ACPI subsystem allocate the buffer + .Length = ACPI_ALLOCATE_BUFFER, + .Pointer = NULL, + }; + status = AcpiGetIrqRoutingTable(object, &buffer); + if (status != AE_OK) { + if (buffer.Pointer) { + AcpiOsFree(buffer.Pointer); + } + return status; + } + DEBUG_ASSERT(buffer.Pointer); + + uintptr_t entry_addr = (uintptr_t)buffer.Pointer; + ACPI_PCI_ROUTING_TABLE *entry; + for (entry = (ACPI_PCI_ROUTING_TABLE *)entry_addr; + entry->Length != 0; + entry_addr += entry->Length, entry = (ACPI_PCI_ROUTING_TABLE *)entry_addr) { + + DEBUG_ASSERT(entry_addr <= (uintptr_t)buffer.Pointer + buffer.Length); + + INDENT_PRINTF("Entry:\n"); + level += 1; + if (entry->Pin > 3) { + INDENT_PRINTF("Pin: Invalid (%08x)\n", entry->Pin); + } else { + INDENT_PRINTF("Pin: INT%c\n", 'A' + entry->Pin); + } + INDENT_PRINTF("Address: %#016llx\n", entry->Address); + level += 1; + INDENT_PRINTF("Dev ID: %#04x\n", (uint16_t)(entry->Address >> 16)); + level -= 1; + + if (entry->Source[0]) { + // If the Source is not just a NULL byte, then it refers to a + // PCI Interrupt Link Device + INDENT_PRINTF("Source: %s\n", entry->Source); + INDENT_PRINTF("Source Index: %u\n", entry->SourceIndex); + ACPI_HANDLE ild; + status = AcpiGetHandle(object, entry->Source, &ild); + if (status != AE_OK) { + INDENT_PRINTF("Could not lookup Interrupt Link Device\n"); + continue; + } + status = acpi_print_resources(ild, 2, CURRENT_RESOURCES); + if (status != AE_OK) { + INDENT_PRINTF("Could not lookup ILD CRS\n"); + } + status = acpi_print_resources(ild, 2, POSSIBLE_RESOURCES); + if (status != AE_OK) { + INDENT_PRINTF("Could not lookup ILD PRS\n"); + } + } else { + // Otherwise, it just refers to a global IRQ number that the pin + // is connected to + INDENT_PRINTF("GlobalIRQ: %u\n", entry->SourceIndex); + } + level -= 1; + } + + AcpiOsFree(buffer.Pointer); + return AE_OK; +} + +static ACPI_STATUS acpi_get_pcie_devices_irq( + ACPI_HANDLE object, + UINT32 nesting_level, + void *context, + void **ret) +{ + ACPI_STATUS status = acpi_print_prt(nesting_level, object); + if (status != AE_OK) { + printf("Failed to print PRT for root complex\n"); + return status; + } + + // Enumerate root ports + ACPI_HANDLE child = NULL; + while (1) { + status = AcpiGetNextObject(ACPI_TYPE_DEVICE, object, child, &child); + if (status == AE_NOT_FOUND) { + break; + } else if (status != AE_OK) { + printf("Failed to get next child object of root complex\n"); + return status; + } + + ACPI_OBJECT object = { 0 }; + ACPI_BUFFER buffer = { + .Length = sizeof(object), + .Pointer = &object, + }; + status = AcpiEvaluateObject(child, (char *)"_ADR", NULL, &buffer); + if (status != AE_OK || + buffer.Length < sizeof(object) || + object.Type != ACPI_TYPE_INTEGER) { + + continue; + } + UINT64 data = object.Integer.Value; + uint level = nesting_level; + INDENT_PRINTF( + "Device %#02x Function %#01x:\n", + (uint8_t)(data >> 16), + (uint8_t)(data & 0x7)); + status = acpi_print_prt(nesting_level + 1, child); + if (status != AE_OK) { + continue; + } + } + + return AE_OK; +} + + +static void acpi_debug_pcie_irq_routing(void) +{ + ACPI_STATUS status = AcpiGetDevices( + (char*)"PNP0A08", + acpi_get_pcie_devices_irq, + NULL, + NULL); + if (status != AE_OK) { + printf("Could not enumerate PRTs\n"); + } +} + +static ACPI_STATUS acpi_debug_print_device( + ACPI_HANDLE object, + UINT32 nesting_level, + void *context, + void **ret) +{ + ACPI_DEVICE_INFO *info = NULL; + ACPI_STATUS status = AcpiGetObjectInfo(object, &info); + if (status != AE_OK) { + if (info) { + ACPI_FREE(info); + } + return status; + } + + uint level = nesting_level; + INDENT_PRINTF("%4s\n", (char *)&info->Name); + + ACPI_FREE(info); + return NO_ERROR; +} + +static void acpi_debug_walk_ns(void) +{ + ACPI_STATUS status = AcpiWalkNamespace( + ACPI_TYPE_DEVICE, + ACPI_ROOT_OBJECT, + INT_MAX, + acpi_debug_print_device, + NULL, + NULL, + NULL); + if (status != AE_OK) { + printf("Failed to walk namespace\n"); + } +} + +static int spy_thread(void* arg) { + port_t port; + if (port_open(POWER_BUTTON_PORT, NULL, &port) < 0) { + printf("acpi port open failed\n"); + } + + port_result_t pr; + for(;;) { + if (port_read(port, INFINITE_TIME, &pr) < 0) { + break; + } + printf("[acpi: pwr-sw %s]\n", pr.packet.value); + } + + printf("acpi spy thread terminated\n"); + return 0; +} + +static void acpi_debug_hook_all_events(void) +{ + thread_t* th = thread_create("acpi-spy", spy_thread, NULL, + DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_resume(th); + printf("listening for ACPI events\n"); +} + +#undef INDENT_PRINTF + +static int cmd_acpi(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("%s madt\n", argv[0].str); + printf("%s mcfg\n", argv[0].str); + printf("%s pcie-crs\n", argv[0].str); + printf("%s pcie-irq\n", argv[0].str); + printf("%s walk-ns\n", argv[0].str); + printf("%s spy\n", argv[0].str); + return ERR_GENERIC; + } + + if (!strcmp(argv[1].str, "madt")) { + acpi_debug_madt(); + } else if (!strcmp(argv[1].str, "mcfg")) { + acpi_debug_mcfg(); + } else if (!strcmp(argv[1].str, "pcie-crs")) { + acpi_debug_pcie_crs(); + } else if (!strcmp(argv[1].str, "pcie-irq")) { + acpi_debug_pcie_irq_routing(); + } else if (!strcmp(argv[1].str, "walk-ns")) { + acpi_debug_walk_ns(); + } else if (!strcmp(argv[1].str, "spy")) { + acpi_debug_hook_all_events(); + } else { + printf("unknown command\n"); + goto usage; + } + + return NO_ERROR; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("acpi", "acpi commands", &cmd_acpi) +#endif +STATIC_COMMAND_END(acpi); diff --git a/kernel/platform/pc/console.c b/kernel/platform/pc/console.c new file mode 100644 index 000000000..d8711c17a --- /dev/null +++ b/kernel/platform/pc/console.c @@ -0,0 +1,299 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +/* memory mapped framebuffer */ +#define FB (0xB8000U + KERNEL_ASPACE_BASE) + +/* CGA values */ +#define CURSOR_START 0x0A +#define CURSOR_END 0x0B +#define VIDEO_ADDRESS_MSB 0x0C +#define VIDEO_ADDRESS_LSB 0x0D +#define CURSOR_POS_MSB 0x0E +#define CURSOR_POS_LSB 0x0F + +/* curr settings */ +static unsigned char curr_x; +static unsigned char curr_y; +static unsigned char curr_start; +static unsigned char curr_end; +static unsigned char curr_attr = 0x7; + +/* video page buffer */ +#define VPAGE_SIZE 2048 +#define PAGE_MAX 8 + +static int active_page = 0; +static int visual_page = 0; + +static int curs_x[PAGE_MAX]; +static int curs_y[PAGE_MAX]; + +static struct { + int x1, y1, x2, y2; +} view_window = { + 0, 0, 79, 24 +}; + +void platform_init_console(void) +{ + curr_save(); + window(0, 0, 79, 24); + clear(); + place(0, 0); +} + +void set_visual_page(int page) +{ + unsigned short page_offset = page*VPAGE_SIZE; + visual_page = page; + + outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB); + outp(CGA_DATA_REG, page_offset & 0xFF); + outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB); + outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF); +} + +void set_active_page(int page) +{ + curs_x[active_page] = curr_x; + curs_y[active_page] = curr_y; + curr_x = curs_x[page]; + curr_y = curs_y[page]; + active_page = page; +} + +int get_visual_page(void) +{ + return visual_page; +} + +int get_active_page(void) +{ + return active_page; +} + +void place(int x,int y) +{ + unsigned short cursor_word = x + y*80 + active_page*VPAGE_SIZE; + + /* + * program CGA using index reg, then data reg + */ + outp(CGA_INDEX_REG, CURSOR_POS_LSB); + outp(CGA_DATA_REG, cursor_word & 0xFF); + outp(CGA_INDEX_REG, CURSOR_POS_MSB); + outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF); + + curr_x = x; + curr_y = y; +} + +void cursor(int start,int end) +{ + outp(CGA_INDEX_REG, CURSOR_START); + outp(CGA_DATA_REG, start); + outp(CGA_INDEX_REG, CURSOR_END); + outp(CGA_DATA_REG, end); +} + +void curr_save(void) +{ +#if 0 + /* grab some info from the bios data area (these should be defined in memmap.h */ + curr_attr = *((unsigned char *)FB + 159); + curr_x = *((unsigned char *)0x00450); + curr_y = *((unsigned char *)0x00451); + curr_end = *((unsigned char *)0x00460); + curr_start = *((unsigned char *)0x00461); +#endif + active_page = visual_page = 0; +} + +void curr_restore(void) +{ +#if 0 + *((unsigned char *)0x00450) = curr_x; + *((unsigned char *)0x00451) = curr_y; +#endif + + place(curr_x, curr_y); + cursor(curr_start, curr_end); +} + +void window(int x1, int y1, int x2, int y2) +{ + view_window.x1 = x1; + view_window.y1 = y1; + view_window.x2 = x2; + view_window.y2 = y2; + + //place(x1, y1); +} + +void _clear(char c,char attr,int x1,int y1,int x2,int y2) +{ + register int i,j; + unsigned short w = attr; + + w <<= 8; + w |= c; + for (i = x1; i <= x2; i++) { + for (j = y1; j <= y2; j++) { + *((unsigned short *)(uintptr_t)(FB + 2*i+160*j + 2 * active_page * VPAGE_SIZE)) = w; + } + } + + place(x1,y1); + curr_y = y1; + curr_x = x1; +} + +void clear() +{ + _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2, + view_window.y2); +} + +void _scroll(char attr, int x1, int y1, int x2, int y2) +{ + register int x,y; + unsigned short xattr = attr << 8,w; + unsigned char *v = (unsigned char *)(uintptr_t)(FB + active_page*(2*VPAGE_SIZE)); + + for (y = y1+1; y <= y2; y++) { + for (x = x1; x <= x2; x++) { + w = *((unsigned short *) (v + 2*(y*80+x))); + *((unsigned short *)(v + 2*((y-1)*80+x))) = w; + } + } + + for (x = x1; x <= x2; x++) { + *((unsigned short *)(v + 2*((y-1)*80+x))) = xattr; + } +} + +void scroll(void) +{ + _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2, + view_window.y2); +} + +void cputc(char c) +{ + static unsigned short scan_x, x, y; + unsigned char *v = (unsigned char *)(uintptr_t)(FB + active_page*(2*VPAGE_SIZE)); + x = curr_x; + y = curr_y; + + switch (c) { + case '\t': + x += 8; + if (x >= view_window.x2+1) { + x = view_window.x1; + if (y == view_window.y2) { + scroll(); + } else { + y++; + } + } else { + scan_x = 0; + + while ((scan_x+8) < x) { + scan_x += 8; + } + + x = scan_x; + } + break; + + case '\r': + x = view_window.x1; + break; + + case '\n': + if (y == view_window.y2) { + scroll(); + } else { + y++; + } + break; + + case '\b': + x--; + break; + + default: + *(v + 2*(x + y*80)) = c; + x++; + + if (x >= view_window.x2+1) { + x = view_window.x1; + if (y == view_window.y2) { + scroll(); + } else { + y++; + } + } + } + + place(x, y); +} + +void cputs(char *s) +{ + char c; + while (*s != '\0') { + c = *s++; + cputc(c); + } +} + +void puts_xy(int x,int y,char attr,char *s) +{ + unsigned char *v = (unsigned char *)(uintptr_t)(FB + (80*y+x)*2 + active_page*(2*VPAGE_SIZE)); + while (*s != 0) { + *v = *s; + s++; + v++; + *v = attr; + v++; + } +} + +void putc_xy(int x, int y, char attr, char c) +{ + unsigned char *v = (unsigned char *)(uintptr_t)(FB + (80*y+x)*2 + active_page*(2*VPAGE_SIZE)); + *v = c; + v++; + *v = attr; +} + +int printf_xy(int x, int y, char attr, char *fmt, ...) +{ + char cbuf[200]; + va_list parms; + int result; + + va_start(parms, fmt); + result = vsprintf(cbuf, fmt, parms); + va_end(parms); + + puts_xy(x, y, attr, cbuf); + + return result; +} diff --git a/kernel/platform/pc/debug.c b/kernel/platform/pc/debug.c new file mode 100644 index 000000000..c7572d84f --- /dev/null +++ b/kernel/platform/pc/debug.c @@ -0,0 +1,119 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int uart_baud_rate = 115200; +static const int uart_io_port = 0x3f8; + +cbuf_t console_input_buf; + +enum handler_return platform_drain_debug_uart_rx(void) +{ + unsigned char c; + bool resched = false; + + while (inp(uart_io_port + 5) & (1<<0)) { + c = inp(uart_io_port + 0); + cbuf_write_char(&console_input_buf, c, false); + resched = true; + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +static enum handler_return uart_irq_handler(void *arg) +{ + return platform_drain_debug_uart_rx(); +} + +void platform_init_debug_early(void) +{ + /* configure the uart */ + int divisor = 115200 / uart_baud_rate; + + /* get basic config done so that tx functions */ + outp(uart_io_port + 3, 0x80); // set up to load divisor latch + outp(uart_io_port + 0, divisor & 0xff); // lsb + outp(uart_io_port + 1, divisor >> 8); // msb + outp(uart_io_port + 3, 3); // 8N1 + outp(uart_io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold +} + +void platform_init_debug(void) +{ + /* finish uart init to get rx going */ + cbuf_initialize(&console_input_buf, 1024); + + uint32_t irq = apic_io_isa_to_global(ISA_IRQ_SERIAL1); + register_int_handler(irq, uart_irq_handler, NULL); + unmask_interrupt(irq); + + outp(uart_io_port + 1, 0x1); // enable receive data available interrupt +} + +static void debug_uart_putc(char c) +{ + while ((inp(uart_io_port + 5) & (1<<6)) == 0) + ; + outp(uart_io_port + 0, c); +} + +void platform_dputc(char c) +{ + if (c == '\n') + platform_dputc('\r'); + + cputc(c); + debug_uart_putc(c); +} + +int platform_dgetc(char *c, bool wait) +{ + return cbuf_read_char(&console_input_buf, c, wait); +} + +void platform_halt( + platform_halt_action suggested_action, + platform_halt_reason reason) +{ + switch (suggested_action) { + case HALT_ACTION_SHUTDOWN: + printf("Powering off...\n"); + acpi_poweroff(); + printf("Power off failed, halting\n"); + break; + case HALT_ACTION_REBOOT: + printf("Rebooting...\n"); + pc_keyboard_reboot(); + printf("Reboot failed, halting\n"); + break; + case HALT_ACTION_HALT: + printf("Halting...\n"); + break; + } + + for (;;) { + x86_cli(); + x86_hlt(); + } +} diff --git a/kernel/platform/pc/ide.c b/kernel/platform/pc/ide.c new file mode 100644 index 000000000..4f81a8408 --- /dev/null +++ b/kernel/platform/pc/ide.c @@ -0,0 +1,894 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +// status register bits +#define IDE_CTRL_BSY 0x80 +#define IDE_DRV_RDY 0x40 +#define IDE_DRV_WRTFLT 0x20 +#define IDE_DRV_SKCOMP 0x10 +#define IDE_DRV_DRQ 0x08 +#define IDE_DRV_CORDAT 0x04 +#define IDE_DRV_IDX 0x02 +#define IDE_DRV_ERR 0x01 + +// ATA commands +#define ATA_NOP 0x00 +#define ATA_ATAPIRESET 0x08 +#define ATA_RECALIBRATE 0x10 +#define ATA_READMULT_RET 0x20 +#define ATA_READMULT 0x21 +#define ATA_READECC_RET 0x22 +#define ATA_READECC 0x23 +#define ATA_WRITEMULT_RET 0x30 +#define ATA_WRITEMULT 0x31 +#define ATA_WRITEECC_RET 0x32 +#define ATA_WRITEECC 0x33 +#define ATA_VERIFYMULT_RET 0x40 +#define ATA_VERIFYMULT 0x41 +#define ATA_FORMATTRACK 0x50 +#define ATA_SEEK 0x70 +#define ATA_DIAG 0x90 +#define ATA_INITPARAMS 0x91 +#define ATA_ATAPIPACKET 0xA0 +#define ATA_ATAPIIDENTIFY 0xA1 +#define ATA_ATAPISERVICE 0xA2 +#define ATA_READ_DMA 0xC8 +#define ATA_READ_DMA_EXT 0x25 +#define ATA_WRITE_DMA 0xCA +#define ATA_WRITE_DMA_EXT 0x35 +#define ATA_GETDEVINFO 0xEC +#define ATA_ATAPISETFEAT 0xEF + +// error codes +#define IDE_NOERROR 0 +#define IDE_ADDRESSMARK 1 +#define IDE_CYLINDER0 2 +#define IDE_INVALIDCOMMAND 3 +#define IDE_MEDIAREQ 4 +#define IDE_SECTNOTFOUND 5 +#define IDE_MEDIACHANGED 6 +#define IDE_BADDATA 7 +#define IDE_BADSECTOR 8 +#define IDE_TIMEOUT 9 +#define IDE_DMAERROR 10 + +enum { + IDE_REG_DATA = 0, + IDE_REG_ERROR = 1, + IDE_REG_PRECOMP = 1, + IDE_REG_SECTOR_COUNT = 2, + IDE_REG_SECTOR_NUM = 3, + IDE_REG_CYLINDER_LOW = 4, + IDE_REG_CYLINDER_HIGH = 5, + IDE_REG_DRIVE_HEAD = 6, + IDE_REG_STATUS = 7, + IDE_REG_COMMAND = 7, + IDE_REG_ALT_STATUS = 8, + IDE_REG_DEVICE_CONTROL = 8, + + IDE_REG_NUM, +}; + +enum { + TYPE_NONE, + TYPE_UNKNOWN, + TYPE_FLOPPY, + TYPE_IDECDROM, + TYPE_SCSICDROM, + TYPE_IDEDISK, + TYPE_SCSIDISK +}; + +static const char *ide_type_str[] = { + "None", + "Unknown", + "Floppy", + "IDE CDROM", + "SCSI CDROM", + "IDE Disk", + "SCSI Disk", +}; + +static const char *ide_error_str[] = { + "Unknown error", + "Address mark not found", + "Cylinder 0 not found", + "Command aborted - invalid command", + "Media change requested", + "ID or target sector not found", + "Media changed", + "Uncorrectable data error", + "Bad sector detected", + "Command timed out", + "DMA error" +}; + +struct ide_driver_state { + uint32_t irq; + const uint16_t *regs; + + event_t completion; + + int type[2]; + struct { + int sectors; + int sector_size; + } drive[2]; +}; + +static const uint16_t ide_device_regs[][IDE_REG_NUM] = { + { 0x01F0, 0x01F1, 0x01F2, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x03F6 }, + { 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0376 }, +}; + +static const int ide_device_isa_irqs[] = { + ISA_IRQ_IDE0, + ISA_IRQ_IDE1, +}; + +static status_t ide_init(struct device *dev); + +static enum handler_return ide_irq_handler(void *arg); + +static status_t ide_init(struct device *dev); +static ssize_t ide_get_block_size(struct device *dev); +static ssize_t ide_get_block_count(struct device *dev); +static ssize_t ide_write(struct device *dev, off_t offset, const void *buf, size_t count); +static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t count); + +static struct block_ops the_ops = { + .std = { + .init = ide_init, + }, + .get_block_size = ide_get_block_size, + .get_block_count = ide_get_block_count, + .write = ide_write, + .read = ide_read, +}; + +DRIVER_EXPORT(ide, &the_ops.std); + +static uint8_t ide_read_reg8(struct device *dev, int index); +static uint16_t ide_read_reg16(struct device *dev, int index); +static uint32_t ide_read_reg32(struct device *dev, int index); + +static void ide_write_reg8(struct device *dev, int index, uint8_t value); +static void ide_write_reg16(struct device *dev, int index, uint16_t value); +static void ide_write_reg32(struct device *dev, int index, uint32_t value); + +static void ide_read_reg8_array(struct device *dev, int index, void *buf, size_t count); +static void ide_read_reg16_array(struct device *dev, int index, void *buf, size_t count); +static void ide_read_reg32_array(struct device *dev, int index, void *buf, size_t count); + +static void ide_write_reg8_array(struct device *dev, int index, const void *buf, size_t count); +static void ide_write_reg16_array(struct device *dev, int index, const void *buf, size_t count); +static void ide_write_reg32_array(struct device *dev, int index, const void *buf, size_t count); + +static void ide_device_select(struct device *dev, int index); +static void ide_device_reset(struct device *dev); +static void ide_delay_400ns(struct device *dev); +static int ide_poll_status(struct device *dev, uint8_t on_mask, uint8_t off_mask); +static int ide_eval_error(struct device *dev); +static void ide_detect_drives(struct device *dev); +static int ide_wait_for_completion(struct device *dev); +static int ide_detect_ata(struct device *dev, int index); +static void ide_lba_setup(struct device *dev, uint32_t addr, int index); + +static status_t ide_init(struct device *dev) +{ + pci_location_t loc; + pci_config_t pci_config; + status_t res = NO_ERROR; + uint32_t i; + int err; + + if (!dev) + return ERR_INVALID_ARGS; + + if (!dev->config) + return ERR_NOT_CONFIGURED; + + __UNUSED const struct platform_ide_config *config = dev->config; + + err = pci_find_pci_class_code(&loc, 0x010180, 0); + if (err != _PCI_SUCCESSFUL) { + LTRACEF("Failed to find IDE device\n"); + res = ERR_NOT_FOUND; + } + + LTRACEF("Found IDE device at %02x:%02x\n", loc.bus, loc.dev_fn); + + for (i=0; i < sizeof(pci_config) / sizeof(uint32_t); i++) { + uint32_t reg = sizeof(uint32_t) * i; + + err = pci_read_config_word(&loc, reg, ((uint32_t *) &pci_config) + i); + if (err != _PCI_SUCCESSFUL) { + LTRACEF("Failed to read config reg %d: 0x%02x\n", reg, err); + res = ERR_NOT_CONFIGURED; + goto done; + } + } + + for (i=0; i < 6; i++) { + LTRACEF("BAR[%d]: 0x%08x\n", i, pci_config.base_addresses[i]); + } + + struct ide_driver_state *state = malloc(sizeof(struct ide_driver_state)); + if (!state) { + res = ERR_NO_MEMORY; + goto done; + } + dev->state = state; + + /* TODO: select io regs and irq based on device index */ + state->irq = apic_io_isa_to_global(ide_device_isa_irqs[0]); + state->regs = ide_device_regs[0]; + state->type[0] = state->type[1] = TYPE_NONE; + + event_init(&state->completion, false, EVENT_FLAG_AUTOUNSIGNAL); + + register_int_handler(state->irq, ide_irq_handler, dev); + unmask_interrupt(state->irq); + + /* enable interrupts */ + ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 0); + + /* detect drives */ + ide_detect_drives(dev); + +done: + return res; +} + +static enum handler_return ide_irq_handler(void *arg) +{ + struct device *dev = arg; + struct ide_driver_state *state = dev->state; + uint8_t val; + + val = ide_read_reg8(dev, IDE_REG_STATUS); + + if ((val & IDE_DRV_ERR) == 0) { + event_signal(&state->completion, false); + + return INT_RESCHEDULE; + } else { + return INT_NO_RESCHEDULE; + } +} + +static ssize_t ide_get_block_size(struct device *dev) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->state); + + struct ide_driver_state *state = dev->state; + return state->drive[0].sector_size; +} + +static ssize_t ide_get_block_count(struct device *dev) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->state); + + struct ide_driver_state *state = dev->state; + return state->drive[0].sectors; +} + +static ssize_t ide_write(struct device *dev, off_t offset, const void *buf, size_t count) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->state); + + __UNUSED struct ide_driver_state *state = dev->state; + + size_t sectors, do_sectors, i; + const uint16_t *ubuf = buf; + int index = 0; // hard code drive for now + ssize_t ret = 0; + int err; + + ide_device_select(dev, index); + ide_delay_400ns(dev); + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ); + if (err) { + LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + sectors = count; + + while (sectors > 0) { + do_sectors = sectors; + + if (do_sectors > 256) + do_sectors = 256; + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY); + if (err) { + LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + ide_lba_setup(dev, offset, index); + + if (do_sectors == 256) + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0); + else + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, do_sectors); + + err = ide_poll_status(dev, IDE_DRV_RDY, 0); + if (err) { + LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + ide_write_reg8(dev, IDE_REG_COMMAND, ATA_WRITEMULT_RET); + ide_delay_400ns(dev); + + for (i=0; i < do_sectors; i++) { + err = ide_poll_status(dev, IDE_DRV_DRQ, 0); + if (err) { + LTRACEF("Error while waiting for drive: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + ide_write_reg16_array(dev, IDE_REG_DATA, ubuf, 256); + + ubuf += 256; + } + + err = ide_wait_for_completion(dev); + if (err) { + LTRACEF("Error waiting for completion: %s\n", ide_error_str[err]); + ret = ERR_TIMED_OUT; + goto done; + } + + sectors -= do_sectors; + offset += do_sectors; + } + + ret = count; + +done: + return ret; +} + +static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t count) +{ + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->state); + + __UNUSED struct ide_driver_state *state = dev->state; + + size_t sectors, do_sectors, i; + uint16_t *ubuf = buf; + int index = 0; // hard code drive for now + ssize_t ret = 0; + int err; + + ide_device_select(dev, index); + ide_delay_400ns(dev); + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ); + if (err) { + LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + sectors = count; + + while (sectors > 0) { + do_sectors = sectors; + + if (do_sectors > 256) + do_sectors = 256; + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY); + if (err) { + LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + ide_lba_setup(dev, offset, index); + + if (do_sectors == 256) + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0); + else + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, do_sectors); + + err = ide_poll_status(dev, IDE_DRV_RDY, 0); + if (err) { + LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + ide_write_reg8(dev, IDE_REG_COMMAND, ATA_READMULT_RET); + ide_delay_400ns(dev); + + for (i=0; i < do_sectors; i++) { + err = ide_poll_status(dev, IDE_DRV_DRQ, 0); + if (err) { + LTRACEF("Error while waiting for drive: %s\n", ide_error_str[err]); + ret = ERR_GENERIC; + goto done; + } + + ide_read_reg16_array(dev, IDE_REG_DATA, ubuf, 256); + + ubuf += 256; + } + + err = ide_wait_for_completion(dev); + if (err) { + LTRACEF("Error waiting for completion: %s\n", ide_error_str[err]); + ret = ERR_TIMED_OUT; + goto done; + } + + sectors -= do_sectors; + offset += do_sectors; + } + + ret = count; + +done: + return ret; +} + +static uint8_t ide_read_reg8(struct device *dev, int index) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + return inp(state->regs[index]); +} + +static uint16_t ide_read_reg16(struct device *dev, int index) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + return inpw(state->regs[index]); +} + +static uint32_t ide_read_reg32(struct device *dev, int index) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + return inpd(state->regs[index]); +} + +static void ide_read_reg8_array(struct device *dev, int index, void *buf, size_t count) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + inprep(state->regs[index], (uint8_t *) buf, count); +} + +static void ide_read_reg16_array(struct device *dev, int index, void *buf, size_t count) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + inpwrep(state->regs[index], (uint16_t *) buf, count); +} + +static void ide_read_reg32_array(struct device *dev, int index, void *buf, size_t count) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + inpdrep(state->regs[index], (uint32_t *) buf, count); +} + +static void ide_write_reg8_array(struct device *dev, int index, const void *buf, size_t count) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + outprep(state->regs[index], (uint8_t *) buf, count); +} + +static void ide_write_reg16_array(struct device *dev, int index, const void *buf, size_t count) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + outpwrep(state->regs[index], (uint16_t *) buf, count); +} + +static void ide_write_reg32_array(struct device *dev, int index, const void *buf, size_t count) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + outpdrep(state->regs[index], (uint32_t *) buf, count); +} + +static void ide_write_reg8(struct device *dev, int index, uint8_t value) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + outp(state->regs[index], value); +} + +static void ide_write_reg16(struct device *dev, int index, uint16_t value) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + outpw(state->regs[index], value); +} + +static void ide_write_reg32(struct device *dev, int index, uint32_t value) +{ + DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM); + + struct ide_driver_state *state = dev->state; + + outpd(state->regs[index], value); +} + +static void ide_device_select(struct device *dev, int index) +{ + ide_write_reg8(dev, IDE_REG_DRIVE_HEAD, (index & 1) << 4); +} + +static void ide_delay_400ns(struct device *dev) +{ + ide_read_reg8(dev, IDE_REG_ALT_STATUS); + ide_read_reg8(dev, IDE_REG_ALT_STATUS); + ide_read_reg8(dev, IDE_REG_ALT_STATUS); + ide_read_reg8(dev, IDE_REG_ALT_STATUS); +} + +static void ide_device_reset(struct device *dev) +{ + struct ide_driver_state *state = dev->state; + + lk_time_t start; + uint8_t sect_cnt, sect_num; + int err; + + ide_device_select(dev, 0); + ide_delay_400ns(dev); + + // set bit 2 for at least 4.8us + ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 1<<2); + + // delay 5us + spin(5); + + ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 0x00); + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY); + if (err) { + LTRACEF("Failed while waiting for controller to be ready: %s\n", ide_error_str[err]); + return; + } + + // make sure the slave is ready if present + if (state->type[1] != TYPE_NONE) { + ide_device_select(dev, 1); + ide_delay_400ns(dev); + + start = current_time(); + + do { + sect_cnt = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT); + sect_num = ide_read_reg8(dev, IDE_REG_SECTOR_NUM); + + if (sect_cnt == 1 && sect_num == 1) { + err = ide_poll_status(dev, 0, IDE_CTRL_BSY); + if (err) { + LTRACEF("Failed while waiting for slave ready: %s\n", ide_error_str[err]); + return; + } + + break; + } + } while (TIME_LTE(current_time(), start + 20000)); + + err = ide_read_reg8(dev, IDE_REG_ALT_STATUS); + if (err & IDE_DRV_ERR) { + err = ide_eval_error(dev); + LTRACEF("Failed while resetting controller: %s\n", ide_error_str[err]); + return; + } + } +} + +static int ide_eval_error(struct device *dev) +{ + int err = 0; + uint8_t data = 0; + + data = ide_read_reg8(dev, IDE_REG_ERROR); + + if (data & 0x01) { + err = IDE_ADDRESSMARK; + } else if (data & 0x02) { + err = IDE_CYLINDER0; + } else if (data & 0x04) { + err = IDE_INVALIDCOMMAND; + } else if (data & 0x08) { + err = IDE_MEDIAREQ; + } else if (data & 0x10) { + err = IDE_SECTNOTFOUND; + } else if (data & 0x20) { + err = IDE_MEDIACHANGED; + } else if (data & 0x40) { + err = IDE_BADDATA; + } else if (data & 0x80) { + err = IDE_BADSECTOR; + } else { + err = IDE_NOERROR; + } + + return err; +} + +static int ide_poll_status(struct device *dev, uint8_t on_mask, uint8_t off_mask) +{ + int err; + uint8_t value; + lk_time_t start = current_time(); + + do { + value = ide_read_reg8(dev, IDE_REG_ALT_STATUS); + + if (value & IDE_DRV_ERR) { + err = ide_eval_error(dev); + LTRACEF("Error while polling status: %s\n", ide_error_str[err]); + return err; + } + + if ((value & on_mask) == on_mask && (value & off_mask) == 0) + return IDE_NOERROR; + } while (TIME_LTE(current_time(), start + 20000)); + + return IDE_TIMEOUT; +} + +static void ide_detect_drives(struct device *dev) +{ + struct ide_driver_state *state = dev->state; + uint8_t sc = 0, sn = 0, st = 0, cl = 0, ch = 0; + + ide_device_select(dev, 0); + ide_delay_400ns(dev); + ide_delay_400ns(dev); + + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa); + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0xaa); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0x55); + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa); + + sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT); + sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM); + + if (sc == 0x55 && sn == 0xaa) { + state->type[0] = TYPE_UNKNOWN; + } + + // check for device 1 + ide_device_select(dev, 1); + ide_delay_400ns(dev); + + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa); + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0xaa); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0x55); + ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa); + + sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT); + sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM); + + if (sc == 0x55 && sn == 0xaa) { + state->type[1] = TYPE_UNKNOWN; + } + + // now the drives present should be known + // soft reset now + ide_device_select(dev, 0); + ide_delay_400ns(dev); + ide_device_reset(dev); + + ide_device_select(dev, 0); + ide_delay_400ns(dev); + + sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT); + sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM); + if (sc == 0x01 && sn == 0x01) { + state->type[0] = TYPE_UNKNOWN; + + st = ide_read_reg8(dev, IDE_REG_STATUS); + cl = ide_read_reg8(dev, IDE_REG_CYLINDER_LOW); + ch = ide_read_reg8(dev, IDE_REG_CYLINDER_HIGH); + + // PATAPI or SATAPI respectively + if ((cl == 0x14 && ch == 0xeb) || (cl == 0x69 && ch == 0x96)) { + state->type[0] = TYPE_IDECDROM; + } else if (st != 0 && ((cl == 0x00 && ch == 0x00) || (cl == 0x3c && ch == 0xc3))) { + state->type[0] = TYPE_IDEDISK; + } + } + + ide_device_select(dev, 1); + ide_delay_400ns(dev); + + sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT); + sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM); + if (sc == 0x01 && sn == 0x01) { + state->type[1] = TYPE_UNKNOWN; + + st = ide_read_reg8(dev, IDE_REG_STATUS); + cl = ide_read_reg8(dev, IDE_REG_CYLINDER_LOW); + ch = ide_read_reg8(dev, IDE_REG_CYLINDER_HIGH); + + // PATAPI or SATAPI respectively + if ((cl == 0x14 && ch == 0xeb) || (cl == 0x69 && ch == 0x96)) { + state->type[1] = TYPE_IDECDROM; + } else if (st != 0 && ((cl == 0x00 && ch == 0x00) || (cl == 0x3c && ch == 0xc3))) { + state->type[1] = TYPE_IDEDISK; + } + } + + LTRACEF("Detected drive 0: %s\n", ide_type_str[state->type[0]]); + LTRACEF("Detected drive 1: %s\n", ide_type_str[state->type[1]]); + + switch (state->type[0]) { + case TYPE_IDEDISK: + ide_detect_ata(dev, 0); + break; + + default: + break; + } + + switch (state->type[1]) { + case TYPE_IDEDISK: + ide_detect_ata(dev, 1); + break; + + default: + break; + } +} + +static int ide_wait_for_completion(struct device *dev) +{ + struct ide_driver_state *state = dev->state; + status_t err; + + err = event_wait_timeout(&state->completion, 20000); + if (err) + return IDE_TIMEOUT; + + return IDE_NOERROR; +} + +static status_t ide_detect_ata(struct device *dev, int index) +{ + struct ide_driver_state *state = dev->state; + status_t res = NO_ERROR; + uint8_t *info = NULL; + int err; + + ide_device_select(dev, index); + ide_delay_400ns(dev); + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ); + if (err) { + LTRACEF("Error while detecting drive %d: %s\n", index, ide_error_str[err]); + res = ERR_TIMED_OUT; + goto error; + } + + ide_device_select(dev, index); + ide_delay_400ns(dev); + + err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ); + if (err) { + LTRACEF("Error while detecting drive %d: %s\n", index, ide_error_str[err]); + res = ERR_TIMED_OUT; + goto error; + } + + // try to wait for the selected drive to be ready, but don't quit if not + // since CD-ROMs don't seem to respond to this when they're masters + ide_poll_status(dev, IDE_DRV_RDY, 0); + + // send the "identify device" command + ide_write_reg8(dev, IDE_REG_COMMAND, ATA_GETDEVINFO); + ide_delay_400ns(dev); + + err = ide_wait_for_completion(dev); + if (err) { + LTRACEF("Error while waiting for command: %s\n", ide_error_str[err]); + res = ERR_TIMED_OUT; + goto error; + } + + info = malloc(512); + if (!info) { + res = ERR_NO_MEMORY; + goto error; + } + + LTRACEF("Found ATA hard disk on channel %d!\n", index); + + ide_read_reg16_array(dev, IDE_REG_DATA, info, 256); + + state->drive[index].sectors = *((uint32_t *) (info + 120)); + state->drive[index].sector_size = 512; + + LTRACEF("Disk supports %u sectors for a total of %u bytes\n", state->drive[index].sectors, + state->drive[index].sectors * 512); + +error: + free(info); + return res; +} + +static void ide_lba_setup(struct device *dev, uint32_t addr, int drive) +{ + ide_write_reg8(dev, IDE_REG_DRIVE_HEAD, 0xe0 | ((drive & 0x00000001) << 4) | ((addr >> 24) & 0xf)); + ide_write_reg8(dev, IDE_REG_CYLINDER_LOW, (addr >> 8) & 0xff); + ide_write_reg8(dev, IDE_REG_CYLINDER_HIGH, (addr >> 16) & 0xff); + ide_write_reg8(dev, IDE_REG_SECTOR_NUM, addr & 0xff); + ide_write_reg8(dev, IDE_REG_PRECOMP, 0xff); +} + diff --git a/kernel/platform/pc/include/pcnet.h b/kernel/platform/pc/include/pcnet.h new file mode 100644 index 000000000..de090caa9 --- /dev/null +++ b/kernel/platform/pc/include/pcnet.h @@ -0,0 +1,116 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_PC_PCNET_H +#define __PLATFORM_PC_PCNET_H + +#include +#include + +#define REG_APROM 0x00 +#define REG_RDP 0x10 +#define REG_RAP 0x14 +#define REG_RESET 0x18 +#define REG_BDP 0x1c + +#define CSR0_INIT 0x0001 +#define CSR0_STRT 0x0002 +#define CSR0_STOP 0x0004 +#define CSR0_TDMD 0x0008 +#define CSR0_TXON 0x0010 +#define CSR0_RXON 0x0020 +#define CSR0_IENA 0x0040 +#define CSR0_INTR 0x0080 +#define CSR0_IDON 0x0100 +#define CSR0_TINT 0x0200 +#define CSR0_RINT 0x0400 +#define CSR0_MERR 0x0800 +#define CSR0_MISS 0x1000 +#define CSR0_CERR 0x2000 +#define CSR0_BABL 0x4000 +#define CSR0_ERR 0x8000 + +#define CSR4_DMAPLUS 0x4000 + +#define DESC_SIZE (4*sizeof(uint32_t)) + +struct init_block_32 { + uint16_t mode; + + uint16_t reserved_0 : 4; + uint16_t rlen : 4; + uint16_t reserved_1 : 4; + uint16_t tlen : 4; + + uint8_t padr[6]; + + uint16_t reserved_2; + + uint64_t ladr; + uint32_t rdra; + uint32_t tdra; +} __PACKED; + +struct td_style3 { + uint32_t trc : 4; + uint32_t reserved_1 : 8; + uint32_t tdr : 14; + uint32_t rtry : 1; + uint32_t lcar : 1; + uint32_t lcol : 1; + uint32_t exdef : 1; + uint32_t uflo : 1; + uint32_t buff : 1; + + uint32_t bcnt : 12; + uint32_t ones : 4; + uint32_t reserved_0 : 7; + uint32_t bpe : 1; + uint32_t enp : 1; + uint32_t stp : 1; + uint32_t def : 1; + uint32_t one : 1; + uint32_t more_ltinit : 1; + uint32_t add_no_fcs : 1; + uint32_t err : 1; + uint32_t own : 1; + + uint32_t tbadr; + + uint32_t reserved_2; +} __PACKED; + +struct rd_style3 { + uint16_t mcnt : 12; + uint16_t zeros : 4; + + uint8_t rpc; + uint8_t rcc; + + uint32_t bcnt : 12; + uint32_t ones : 4; + uint32_t reserved_0 : 4; + uint32_t bam : 1; + uint32_t lafm : 1; + uint32_t pam : 1; + uint32_t bpe : 1; + uint32_t enp : 1; + uint32_t stp : 1; + uint32_t buff : 1; + uint32_t crc : 1; + uint32_t oflo : 1; + uint32_t fram : 1; + uint32_t err : 1; + uint32_t own : 1; + + uint32_t rbadr; + + uint32_t reserved_1; +} __PACKED; + +#endif + diff --git a/kernel/platform/pc/include/platform/acpi.h b/kernel/platform/pc/include/platform/acpi.h new file mode 100644 index 000000000..f5f158695 --- /dev/null +++ b/kernel/platform/pc/include/platform/acpi.h @@ -0,0 +1,71 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_ACPI_H +#define __PLATFORM_ACPI_H + +#include + +#include + +#include +#include + +__BEGIN_CDECLS + +struct acpi_pcie_config { + // Physical address of the configuration space window for bus start_bus + // NOTE: The ACPI deata actually yields the address for bus 0 always, so + // we adjust it before populating this structure. + paddr_t ecam_phys; + size_t ecam_size; + // ACPI segment group + uint16_t segment_group; + // The range of buses supported by this bridge + uint8_t start_bus; + uint8_t end_bus; +}; + +struct acpi_irq_signal { + uint32_t global_irq; + bool level_triggered; + bool active_high; +}; + +#define ACPI_NO_IRQ_MAPPING UINT32_MAX +#define MAX_IRQ_SIGNALS 16 +struct acpi_pcie_irq_mapping { + uint32_t dev_pin_to_global_irq[PCIE_MAX_DEVICES_PER_BUS][PCIE_MAX_FUNCTIONS_PER_DEVICE][PCIE_MAX_LEGACY_IRQ_PINS]; + + uint32_t num_irqs; + struct acpi_irq_signal irqs[MAX_IRQ_SIGNALS]; +}; + +void platform_init_acpi_tables(uint levels); +void platform_init_acpi(void); +status_t platform_enumerate_cpus( + uint32_t *apic_ids, + uint32_t len, + uint32_t *num_cpus); +status_t platform_enumerate_io_apics( + struct io_apic_descriptor *io_apics, + uint32_t len, + uint32_t *num_io_apics); +status_t platform_enumerate_interrupt_source_overrides( + struct io_apic_isa_override *isos, + uint32_t len, + uint32_t *num_isos); +status_t platform_find_pcie_config(struct acpi_pcie_config *config); +status_t platform_find_pcie_legacy_irq_mapping(struct acpi_pcie_irq_mapping *root_bus_map); + +// Powers off the machine. Returns on failure +void acpi_poweroff(void); + +#define POWER_BUTTON_PORT "sys/pwr/sw" + +__END_CDECLS + +#endif diff --git a/kernel/platform/pc/include/platform/console.h b/kernel/platform/pc/include/platform/console.h new file mode 100644 index 000000000..7d5f65447 --- /dev/null +++ b/kernel/platform/pc/include/platform/console.h @@ -0,0 +1,70 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_CONSOLE_H +#define __PLATFORM_CONSOLE_H + +#include + +__BEGIN_CDECLS + +void platform_init_console(void); + +void set_visual_page(int page); +void set_active_page(int page); + +int get_visual_page(void); +int get_active_page(void); + +void place(int x,int y); +void cursor(int start, int end); + +void _clear(char c, char attr, int x1, int y1, int x2, int y2); +void clear(void); + +void _scroll(char attr, int x1, int y1, int x2, int y2); +void scroll(void); + +void curr_save(void); +void curr_restore(void); + +void cputc(char c); +void cputs(char *s); + +void window(int x1, int y1, int x2, int y2); + +void putc_xy(int x, int y, char attr, char c); +void puts_xy(int x, int y, char attr, char *s); + +int printf_xy(int x, int y, char attr, char *fmt, ...) __PRINTFLIKE(4, 5); + +#define CURSOR_BLOCK() cursor(0, 15); +#define CURSOR_OFF() cursor(16, 16); +#define CURSOR_STD() cursor(14, 15); + +/* text colors */ +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define BROWN 6 +#define LIGHTGRAY 7 +#define DARKGRAY 8 +#define LIGHTBLUE 9 +#define LIGHTGREEN 10 +#define LIGHTCYAN 11 +#define LIGHTRED 12 +#define LIGHTMAGENTA 13 +#define YELLOW 14 +#define WHITE 15 + +__END_CDECLS + +#endif + diff --git a/kernel/platform/pc/include/platform/ide.h b/kernel/platform/pc/include/platform/ide.h new file mode 100644 index 000000000..5e70e49c7 --- /dev/null +++ b/kernel/platform/pc/include/platform/ide.h @@ -0,0 +1,17 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __PLATFORM_IDE_H +#define __PLATFORM_IDE_H + +struct platform_ide_config { +}; + +#endif + + diff --git a/kernel/platform/pc/include/platform/keyboard.h b/kernel/platform/pc/include/platform/keyboard.h new file mode 100644 index 000000000..3200fbb0c --- /dev/null +++ b/kernel/platform/pc/include/platform/keyboard.h @@ -0,0 +1,17 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +void platform_init_keyboard(cbuf_t *buffer); + +int platform_read_key(char *c); + +// Reboot the system via the keyboard, returns on failure. +void pc_keyboard_reboot(void); diff --git a/kernel/platform/pc/include/platform/multiboot.h b/kernel/platform/pc/include/platform/multiboot.h new file mode 100644 index 000000000..883c4611d --- /dev/null +++ b/kernel/platform/pc/include/platform/multiboot.h @@ -0,0 +1,115 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_MULTIBOOT_H +#define __PLATFORM_MULTIBOOT_H + +#include + +/* magic number for multiboot header */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* flags for multiboot header */ +#ifdef __ELF__ +#define MULTIBOOT_HEADER_FLAGS 0x00000003 +#else +#define MULTIBOOT_HEADER_FLAGS 0x00010003 +#endif + +/* magic number passed by multiboot-compliant boot loaders */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +#ifndef ASSEMBLY + +/* multiboot header */ +typedef struct multiboot_header { + uint32_t magic; + uint32_t flags; + uint32_t checksum; + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; +} multiboot_header_t; + +/* symbol table for a.out */ +typedef struct aout_symbol_table { + uint32_t tabsize; + uint32_t strsize; + uint32_t addr; + uint32_t reserved; +} aout_symbol_table_t; + +/* section header table for ELF */ +typedef struct elf_section_header_table { + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; +} elf_section_header_table_t; + +/* multiboot info */ +typedef struct multiboot_info { + uint32_t flags; + uint32_t mem_lower; + uint32_t mem_upper; + uint32_t boot_device; + uint32_t cmdline; + uint32_t mods_count; + uint32_t mods_addr; + union { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + uint32_t mmap_length; + uint32_t mmap_addr; +} multiboot_info_t; + +enum { + MB_INFO_MEM_SIZE = 0x001, + MB_INFO_BOOT_DEV = 0x002, + MB_INFO_CMD_LINE = 0x004, + MB_INFO_MODS = 0x008, + MB_INFO_SYMS = 0x010, + MB_INFO_MMAP = 0x020, + MB_INFO_DRIVES = 0x040, + MB_INFO_CONFIG = 0x080, + MB_INFO_BOOT_LOADER = 0x100, + MB_INFO_APM_TABLE = 0x200, + MB_INFO_VBE = 0x400, +}; + +/* module structure */ +typedef struct module { + uint32_t mod_start; + uint32_t mod_end; + uint32_t string; + uint32_t reserved; +} module_t; + +/* memory map - be careful that the offset 0 is base_addr_low without size */ +typedef struct memory_map { + uint32_t size; + uint32_t base_addr_low; + uint32_t base_addr_high; + uint32_t length_low; + uint32_t length_high; + uint32_t type; +} memory_map_t; + +/* memory map entry types */ +enum { + MB_MMAP_TYPE_AVAILABLE = 0x01, + MB_MMAP_TYPE_RESERVED = 0x02, + MB_MMAP_TYPE_ACPI_RECLAIM = 0x03, + MB_MMAP_TYPE_ACPI_NVS = 0x04, +}; + +#endif + +#endif diff --git a/kernel/platform/pc/include/platform/pc.h b/kernel/platform/pc/include/platform/pc.h new file mode 100644 index 000000000..f1a36f297 --- /dev/null +++ b/kernel/platform/pc/include/platform/pc.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_PC_H +#define __PLATFORM_PC_H + +#include +#include +#include + +/* NOTE: keep arch/x86/crt0.S in sync with these definitions */ + +/* defined interrupts */ +#define ISA_IRQ_PIT 0 +#define ISA_IRQ_KEYBOARD 1 +#define ISA_IRQ_PIC2 2 +#define ISA_IRQ_SERIAL1 4 +#define ISA_IRQ_CMOSRTC 8 +#define ISA_IRQ_PS2MOUSE 12 +#define ISA_IRQ_IDE0 14 +#define ISA_IRQ_IDE1 15 + +/* PIC remap bases */ +#define PIC1_BASE X86_INT_PLATFORM_BASE +#define PIC2_BASE (PIC1_BASE + 8) + +#endif + diff --git a/kernel/platform/pc/include/platform/pc/iomap.h b/kernel/platform/pc/include/platform/pc/iomap.h new file mode 100644 index 000000000..30354f401 --- /dev/null +++ b/kernel/platform/pc/include/platform/pc/iomap.h @@ -0,0 +1,24 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __IOMAP_H +#define __IOMAP_H + +/* i8253/i8254 programmable interval timer registers */ +#define I8253_CONTROL_REG 0x43 +#define I8253_DATA_REG 0x40 + +/* i8042 keyboard controller registers */ +#define I8042_COMMAND_REG 0x64 +#define I8042_STATUS_REG 0x64 +#define I8042_DATA_REG 0x60 + +/* CGA registers */ +#define CGA_INDEX_REG 0x3D4 +#define CGA_DATA_REG 0x3D5 + +#endif diff --git a/kernel/platform/pc/include/platform/pc/memmap.h b/kernel/platform/pc/include/platform/pc/memmap.h new file mode 100644 index 000000000..e255bc341 --- /dev/null +++ b/kernel/platform/pc/include/platform/pc/memmap.h @@ -0,0 +1,18 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __MEMMAP_H +#define __MEMMAP_H + +/* some helpful macros */ +#define REG(x) ((volatile unsigned int *)(x)) +#define REG_H(x) ((volatile unsigned short *)(x)) +#define REG_B(x) ((volatile unsigned char *)(x)) + +/* TODO: put fixed memory address definitions here */ + +#endif diff --git a/kernel/platform/pc/include/platform/pcnet.h b/kernel/platform/pc/include/platform/pcnet.h new file mode 100644 index 000000000..ca09f6f28 --- /dev/null +++ b/kernel/platform/pc/include/platform/pcnet.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __PLATFORM_PCNET_H +#define __PLATFORM_PCNET_H + +#include + +struct platform_pcnet_config { + uint16_t vendor_id; + uint16_t device_id; + int index; +}; + +#endif + + + diff --git a/kernel/platform/pc/include/platform/pic.h b/kernel/platform/pc/include/platform/pic.h new file mode 100644 index 000000000..d7e94504d --- /dev/null +++ b/kernel/platform/pc/include/platform/pic.h @@ -0,0 +1,10 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +void pic_map(uint32_t pic1, uint32_t pic2); +void pic_disable(void); diff --git a/kernel/platform/pc/include/platform/uart.h b/kernel/platform/pc/include/platform/uart.h new file mode 100644 index 000000000..f7a467173 --- /dev/null +++ b/kernel/platform/pc/include/platform/uart.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#ifndef __PLATFORM_UART_H +#define __PLATFORM_UART_H + +struct platform_uart_config { + int baud_rate; + int io_port; + int irq; + int rx_buf_len; + int tx_buf_len; +}; + +#endif + diff --git a/kernel/platform/pc/interrupts.c b/kernel/platform/pc/interrupts.c new file mode 100644 index 000000000..b21e4c11c --- /dev/null +++ b/kernel/platform/pc/interrupts.c @@ -0,0 +1,321 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "platform_p.h" +#include +#include +#include +#include +#include + +#ifdef WITH_DEV_PCIE +#include +#define MAX_IRQ_BLOCK_SIZE PCIE_MAX_MSI_IRQS +#else +#define MAX_IRQ_BLOCK_SIZE (1u) +#endif + +#include + +struct int_handler_struct { + spin_lock_t lock; + int_handler handler; + void *arg; +}; + +static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE; +static struct int_handler_struct int_handler_table[X86_MAX_INT]; +static p2ra_state_t x86_irq_vector_allocator; + +void platform_init_apic(uint level) +{ + pic_map(PIC1_BASE, PIC2_BASE); + pic_disable(); + + for (size_t i = 0; i < countof(int_handler_table); ++i) + spin_lock_init(&int_handler_table[i].lock); + + // Enumerate the IO APICs + uint32_t num_io_apics; + status_t status = platform_enumerate_io_apics(NULL, 0, &num_io_apics); + // TODO: If we want to support x86 without IO APICs, we should do something + // better here. + ASSERT(status == NO_ERROR); + struct io_apic_descriptor *io_apics = + calloc(num_io_apics, sizeof(*io_apics)); + ASSERT(io_apics != NULL); + uint32_t num_found = 0; + status = platform_enumerate_io_apics(io_apics, num_io_apics, &num_found); + ASSERT(status == NO_ERROR); + ASSERT(num_io_apics == num_found); + + // Enumerate the IO APICs + uint32_t num_isos; + status = platform_enumerate_interrupt_source_overrides(NULL, 0, &num_isos); + ASSERT(status == NO_ERROR); + struct io_apic_isa_override *isos = calloc(num_isos, sizeof(*isos)); + ASSERT(isos != NULL); + status = platform_enumerate_interrupt_source_overrides( + isos, + num_isos, + &num_found); + ASSERT(status == NO_ERROR); + ASSERT(num_isos == num_found); + + apic_vm_init(); + apic_local_init(); + apic_io_init(io_apics, num_io_apics, isos, num_isos); + + free(io_apics); + free(isos); + + ASSERT(arch_ints_disabled()); + + // Initialize the delivery modes/targets for the ISA interrupts + uint8_t local_apic_id = apic_local_id(); + for (int irq = 0; irq < 8; ++irq) { + // Explicitly skip mapping the PIC2 interrupt, since it is actually + // just used internally on the PICs for daisy chaining. QEMU remaps + // ISA IRQ 0 to global IRQ 2, but does not remap ISA IRQ 2 off of + // global IRQ 2, so skipping this mapping also prevents a collision + // with the PIT IRQ. + if (irq != ISA_IRQ_PIC2) { + apic_io_configure_isa_irq( + irq, + DELIVERY_MODE_FIXED, + IO_APIC_IRQ_MASK, + DST_MODE_PHYSICAL, + local_apic_id, + 0); + } + apic_io_configure_isa_irq( + irq + 8, + DELIVERY_MODE_FIXED, + IO_APIC_IRQ_MASK, + DST_MODE_PHYSICAL, + local_apic_id, + 0); + } + + // Initialize the x86 IRQ vector allocator and add the range of vectors to manage. + status = p2ra_init(&x86_irq_vector_allocator, MAX_IRQ_BLOCK_SIZE); + ASSERT(status == NO_ERROR); + + status = p2ra_add_range(&x86_irq_vector_allocator, + X86_INT_PLATFORM_BASE, + X86_INT_PLATFORM_MAX - X86_INT_PLATFORM_BASE + 1); + ASSERT(status == NO_ERROR); +} +LK_INIT_HOOK(apic, &platform_init_apic, LK_INIT_LEVEL_VM + 2); + +status_t mask_interrupt(unsigned int vector) +{ + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + apic_io_mask_irq(vector, IO_APIC_IRQ_MASK); + + spin_unlock_irqrestore(&lock, state); + + return NO_ERROR; +} + +status_t unmask_interrupt(unsigned int vector) +{ + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + apic_io_mask_irq(vector, IO_APIC_IRQ_UNMASK); + + spin_unlock_irqrestore(&lock, state); + + return NO_ERROR; +} + +enum handler_return platform_irq(x86_iframe_t *frame) +{ + // get the current vector + unsigned int x86_vector = frame->vector; + DEBUG_ASSERT(x86_vector >= X86_INT_PLATFORM_BASE && + x86_vector <= X86_INT_PLATFORM_MAX); + + // deliver the interrupt + enum handler_return ret = INT_NO_RESCHEDULE; + + struct int_handler_struct *handler = &int_handler_table[x86_vector]; + + spin_lock(&handler->lock); + if (handler->handler) + ret = handler->handler(handler->arg); + spin_unlock(&handler->lock); + + apic_issue_eoi(); + return ret; +} + +void register_int_handler(unsigned int vector, int_handler handler, void *arg) +{ + DEBUG_ASSERT(is_valid_interrupt(vector, 0)); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + /* Fetch the x86 vector currently configured for this global irq. Force + * it's value to zero if it is currently invalid */ + uint8_t x86_vector = apic_io_fetch_irq_vector(vector); + if ((x86_vector < X86_INT_PLATFORM_BASE) || + (x86_vector > X86_INT_PLATFORM_MAX)) + x86_vector = 0; + + if (x86_vector && !handler) { + /* If the x86 vector is valid, and we are unregistering the handler, + * return the x86 vector to the pool. */ + p2ra_free_range(&x86_irq_vector_allocator, x86_vector, 1); + x86_vector = 0; + } else if (!x86_vector && handler) { + /* If the x86 vector is invalid, and we are registering a handler, + * attempt to get a new x86 vector from the pool. */ + uint range_start; + status_t result; + + /* Right now, there is not much we can do if the allocation fails. In + * debug builds, we ASSERT that everything went well. In release + * builds, we log a message and then silently ignore the request to + * register a new handler. */ + result = p2ra_allocate_range(&x86_irq_vector_allocator, 1, &range_start); + DEBUG_ASSERT(result == NO_ERROR); + + if (result != NO_ERROR) { + TRACEF("Failed to allocate x86 IRQ vector for global IRQ (%u) when " + "registering new handler (%p, %p)\n", + vector, handler, arg); + goto finished; + } + + DEBUG_ASSERT((range_start >= X86_INT_PLATFORM_BASE) && + (range_start <= X86_INT_PLATFORM_MAX)); + x86_vector = (uint8_t)range_start; + } + + // Update the handler table and register the x86 vector with the io_apic. + DEBUG_ASSERT(!!x86_vector == !!handler); + + // No need to irq_save; we already did that when we grabbed the outer lock. + spin_lock(&int_handler_table[x86_vector].lock); + int_handler_table[x86_vector].handler = handler; + int_handler_table[x86_vector].arg = handler ? arg : NULL; + spin_unlock(&int_handler_table[x86_vector].lock); + + apic_io_configure_irq_vector(vector, x86_vector); + +finished: + spin_unlock_irqrestore(&lock, state); +} + +bool is_valid_interrupt(unsigned int vector, uint32_t flags) +{ + return apic_io_is_valid_irq(vector); +} + +unsigned int remap_interrupt(unsigned int vector) { + return apic_io_isa_to_global(vector); +} + +#ifdef WITH_DEV_PCIE +status_t x86_alloc_msi_block(uint requested_irqs, + bool can_target_64bit, + bool is_msix, + pcie_msi_block_t* out_block) { + if (!out_block) + return ERR_INVALID_ARGS; + + if (out_block->allocated) + return ERR_BAD_STATE; + + if (!requested_irqs || (requested_irqs > PCIE_MAX_MSI_IRQS)) + return ERR_INVALID_ARGS; + + status_t res; + uint alloc_start; + uint alloc_size = 1u << log2_uint_roundup(requested_irqs); + + res = p2ra_allocate_range(&x86_irq_vector_allocator, alloc_size, &alloc_start); + if (res == NO_ERROR) { + // Compute the target address. + // See section 10.11.1 of the Intel 64 and IA-32 Architectures Software + // Developer's Manual Volume 3A. + // + // TODO(johngro) : don't just bind this block to the Local APIC of the + // processor which is active when calling alloc_msi_block. Instead, + // there should either be a system policy (like, always send to any + // processor, or just processor 0, or something), or the decision of + // which CPUs to bind to should be left to the caller. + uint32_t tgt_addr = 0xFEE00000; // base addr + tgt_addr |= ((uint32_t)apic_local_id()) << 12; // Dest ID == our local APIC ID + tgt_addr |= 0x08; // Redir hint == 1 + tgt_addr &= ~0x04; // Dest Mode == Physical + + // Compute the target data. + // See section 10.11.2 of the Intel 64 and IA-32 Architectures Software + // Developer's Manual Volume 3A. + // + // delivery mode == 0 (fixed) + // trigger mode == 0 (edge) + // vector == start of block range + DEBUG_ASSERT(!(alloc_start & ~0xFF)); + DEBUG_ASSERT(!(alloc_start & (alloc_size - 1))); + uint32_t tgt_data = alloc_start; + + /* Success! Fill out the bookkeeping and we are done */ + out_block->platform_ctx = NULL; + out_block->base_irq_id = alloc_start; + out_block->num_irq = alloc_size; + out_block->tgt_addr = tgt_addr; + out_block->tgt_data = tgt_data; + out_block->allocated = true; + } + + return res; +} + +void x86_free_msi_block(pcie_msi_block_t* block) { + DEBUG_ASSERT(block); + DEBUG_ASSERT(block->allocated); + p2ra_free_range(&x86_irq_vector_allocator, block->base_irq_id, block->num_irq); + memset(block, 0, sizeof(*block)); +} + +void x86_register_msi_handler(const pcie_msi_block_t* block, + uint msi_id, + int_handler handler, + void* ctx) { + DEBUG_ASSERT(block && block->allocated); + DEBUG_ASSERT(msi_id < block->num_irq); + + uint x86_vector = msi_id + block->base_irq_id; + DEBUG_ASSERT((x86_vector >= X86_INT_PLATFORM_BASE) && + (x86_vector <= X86_INT_PLATFORM_MAX)); + + spin_lock(&int_handler_table[x86_vector].lock); + int_handler_table[x86_vector].handler = handler; + int_handler_table[x86_vector].arg = handler ? ctx : NULL; + spin_unlock(&int_handler_table[x86_vector].lock); +} +#endif // WITH_DEV_PCIE diff --git a/kernel/platform/pc/keyboard.c b/kernel/platform/pc/keyboard.c new file mode 100644 index 000000000..39b4a4cb8 --- /dev/null +++ b/kernel/platform/pc/keyboard.c @@ -0,0 +1,486 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "platform_p.h" +#include +#include +#include + +#define LOCAL_TRACE 0 + +static inline int i8042_read_data(void) +{ + return inp(I8042_DATA_REG); +} + +static inline int i8042_read_status(void) +{ + return inp(I8042_STATUS_REG); +} + +static inline void i8042_write_data(int val) +{ + outp(I8042_DATA_REG, val); +} + +static inline void i8042_write_command(int val) +{ + outp(I8042_COMMAND_REG, val); +} + +/* + * timeout in milliseconds + */ +#define I8042_CTL_TIMEOUT 500 + +/* + * status register bits + */ +#define I8042_STR_PARITY 0x80 +#define I8042_STR_TIMEOUT 0x40 +#define I8042_STR_AUXDATA 0x20 +#define I8042_STR_KEYLOCK 0x10 +#define I8042_STR_CMDDAT 0x08 +#define I8042_STR_MUXERR 0x04 +#define I8042_STR_IBF 0x02 +#define I8042_STR_OBF 0x01 + +/* + * control register bits + */ +#define I8042_CTR_KBDINT 0x01 +#define I8042_CTR_AUXINT 0x02 +#define I8042_CTR_IGNKEYLK 0x08 +#define I8042_CTR_KBDDIS 0x10 +#define I8042_CTR_AUXDIS 0x20 +#define I8042_CTR_XLATE 0x40 + +/* + * commands + */ +#define I8042_CMD_CTL_RCTR 0x0120 +#define I8042_CMD_CTL_WCTR 0x1060 +#define I8042_CMD_CTL_TEST 0x01aa + +#define I8042_CMD_KBD_DIS 0x00ad +#define I8042_CMD_KBD_EN 0x00ae +#define I8042_CMD_PULSE_RESET 0x00fe +#define I8042_CMD_KBD_TEST 0x01ab +#define I8042_CMD_KBD_MODE 0x01f0 + +/* + * used for flushing buffers. the i8042 internal buffer shoudn't exceed this. + */ +#define I8042_BUFFER_LENGTH 32 + +/* extended keys that aren't pure ascii */ +enum { + KEY_RETURN = 0x80, + KEY_ESC, + KEY_LSHIFT, + KEY_RSHIFT, + KEY_LCTRL, + KEY_RCTRL, + KEY_LALT, + KEY_RALT, + KEY_CAPSLOCK, + KEY_LWIN, + KEY_RWIN, + KEY_MENU, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_F13, + KEY_F14, + KEY_F15, + KEY_F16, + KEY_F17, + KEY_F18, + KEY_F19, + KEY_F20, + KEY_PRTSCRN, + KEY_SCRLOCK, + KEY_PAUSE, + KEY_TAB, + KEY_BACKSPACE, + KEY_INS, + KEY_DEL, + KEY_HOME, + KEY_END, + KEY_PGUP, + KEY_PGDN, + KEY_ARROW_UP, + KEY_ARROW_DOWN, + KEY_ARROW_LEFT, + KEY_ARROW_RIGHT, + KEY_PAD_NUMLOCK, + KEY_PAD_DIVIDE, + KEY_PAD_MULTIPLY, + KEY_PAD_MINUS, + KEY_PAD_PLUS, + KEY_PAD_ENTER, + KEY_PAD_PERIOD, + KEY_PAD_0, + KEY_PAD_1, + KEY_PAD_2, + KEY_PAD_3, + KEY_PAD_4, + KEY_PAD_5, + KEY_PAD_6, + KEY_PAD_7, + KEY_PAD_8, + KEY_PAD_9, + + _KEY_LAST, +} extended_keys; + +static_assert(_KEY_LAST < 0x100); + +/* scancode translation tables */ +const uint8_t pc_keymap_set1_lower[128] = { + /* 0x00 */ 0, KEY_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, KEY_TAB, + /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', KEY_RETURN, KEY_LCTRL, 'a', 's', + /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', KEY_LSHIFT, '\\', 'z', 'x', 'c', 'v', + /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT, '*', KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, KEY_F2, + KEY_F3, KEY_F4, KEY_F5, + /* 0x40 */ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_PAD_NUMLOCK, KEY_SCRLOCK, KEY_PAD_7, KEY_PAD_8, + KEY_PAD_9, KEY_PAD_MINUS, KEY_PAD_4, KEY_PAD_5, KEY_PAD_6, KEY_PAD_PLUS, KEY_PAD_1, + /* 0x50 */ KEY_PAD_2, KEY_PAD_3, KEY_PAD_0, KEY_PAD_PERIOD, 0, 0, 0, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, +}; + +const uint8_t pc_keymap_set1_upper[128] = { + /* 0x00 */ 0, KEY_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', KEY_BACKSPACE, KEY_TAB, + /* 0x10 */ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', KEY_RETURN, KEY_LCTRL, 'A', 'S', + /* 0x20 */ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', KEY_LSHIFT, '|', 'Z', 'X', 'C', 'V', + /* 0x30 */ 'B', 'N', 'M', '<', '>', '?', KEY_RSHIFT, '*', KEY_LALT, ' ', KEY_CAPSLOCK, KEY_F1, KEY_F2, + KEY_F3, KEY_F4, KEY_F5, + /* 0x40 */ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_PAD_NUMLOCK, KEY_SCRLOCK, KEY_PAD_7, KEY_PAD_8, + KEY_PAD_9, KEY_PAD_MINUS, KEY_PAD_4, KEY_PAD_5, KEY_PAD_6, KEY_PAD_PLUS, KEY_PAD_1, + /* 0x50 */ KEY_PAD_2, KEY_PAD_3, KEY_PAD_0, KEY_PAD_PERIOD, 0, 0, 0, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, +}; + +const uint8_t pc_keymap_set1_e0[128] = { + /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PAD_ENTER, KEY_RCTRL, 0, 0, + /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 */ 0, 0, 0, 0, 0, KEY_PAD_DIVIDE, 0, KEY_PRTSCRN, KEY_RALT, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, KEY_ARROW_UP, KEY_PGUP, 0, KEY_ARROW_LEFT, 0, KEY_ARROW_RIGHT, 0, KEY_END, + /* 0x50 */ KEY_ARROW_DOWN, KEY_PGDN, KEY_INS, 0, 0, 0, 0, 0, 0, 0, 0, KEY_LWIN, KEY_RWIN, KEY_MENU, 0, 0 +}; + +/* + * state key flags + */ +static bool key_lshift; +static bool key_rshift; +static int last_code; + +static cbuf_t *key_buf; + +static int i8042_process_scode(uint8_t scode, unsigned int flags) +{ + // is this a multi code sequence? + bool multi = (last_code == 0xe0); + + // update the last received code + last_code = scode; + + // save the key up event bit + bool key_up = !!(scode & 0x80); + scode &= 0x7f; + + // translate the key based on our translation table + uint8_t key_code; + if (multi) { + key_code = pc_keymap_set1_e0[scode]; + } else if (key_lshift || key_rshift) { + key_code = pc_keymap_set1_upper[scode]; + } else { + key_code = pc_keymap_set1_lower[scode]; + } + + LTRACEF("scancode 0x%x, keyup %u, multi %u: keycode 0x%x\n", scode, !!key_up, multi, key_code); + + // generate a character string to feed into the queue + char str[4] = { 0 }; + switch (key_code) { + // for all the usual ascii strings, generate the target string directly + case 1 ... 0x7f: + str[0] = key_code; + break; + + // a few special keys we can generate stuff for directly + case KEY_RETURN: + case KEY_PAD_ENTER: + str[0] = '\n'; + break; + case KEY_BACKSPACE: + str[0] = '\b'; + break; + case KEY_TAB: + str[0] = '\t'; + break; + + // generate vt100 key codes for arrows + case KEY_ARROW_UP: + str[0] = 0x1b; + str[1] = '['; + str[2] = 65; + break; + case KEY_ARROW_DOWN: + str[0] = 0x1b; + str[1] = '['; + str[2] = 66; + break; + case KEY_ARROW_RIGHT: + str[0] = 0x1b; + str[1] = '['; + str[2] = 67; + break; + case KEY_ARROW_LEFT: + str[0] = 0x1b; + str[1] = '['; + str[2] = 68; + break; + + // left and right shift are special + case KEY_LSHIFT: + key_lshift = !key_up; + break; + case KEY_RSHIFT: + key_rshift = !key_up; + break; + + // everything else we just eat + default: + ; // nothing + } + + int chars_added = 0; + if (!key_up) { + for (uint i = 0; str[i] != '\0'; i++) { + LTRACEF("char 0x%hhx (%c)\n", str[i], isprint(str[i]) ? (str[i]) : ' '); + cbuf_write_char(key_buf, str[i], false); + chars_added++; + } + } + + return chars_added; +} + +static int i8042_wait_read(void) +{ + int i = 0; + while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { + spin(10); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +static int i8042_wait_write(void) +{ + int i = 0; + while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { + spin(10); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +static int i8042_flush(void) +{ + unsigned char data __UNUSED; + int i = 0; + + while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_LENGTH)) { + spin(10); + data = i8042_read_data(); + } + + return i; +} + +static int i8042_command(uint8_t *param, int command) +{ + int retval = 0, i = 0; + + retval = i8042_wait_write(); + if (!retval) { + i8042_write_command(command & 0xff); + } + + if (!retval) { + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) { + break; + } + + i8042_write_data(param[i]); + } + } + + if (!retval) { + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) { + break; + } + + if (i8042_read_status() & I8042_STR_AUXDATA) { + param[i] = ~i8042_read_data(); + } else { + param[i] = i8042_read_data(); + } + } + } + + return retval; +} + +static int keyboard_command(uint8_t *param, int command) +{ + int retval = 0, i = 0; + + retval = i8042_wait_write(); + if (!retval) { + i8042_write_data(command & 0xff); + } + + if (!retval) { + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) { + break; + } + + i8042_write_data(param[i]); + } + } + + if (!retval) { + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) { + break; + } + + if (i8042_read_status() & I8042_STR_AUXDATA) { + param[i] = ~i8042_read_data(); + } else { + param[i] = i8042_read_data(); + } + } + } + + return retval; +} + +static enum handler_return i8042_interrupt(void *arg) +{ + bool resched = false; + + // keep handling status on the keyboard controller until no bits are set we care about + bool retry; + do { + retry = false; + + uint8_t str = i8042_read_status(); + + // check for incoming data from the controller + if (str & I8042_STR_OBF) { + uint8_t data = i8042_read_data(); + int chars_added = i8042_process_scode(data, + ((str & I8042_STR_PARITY) ? I8042_STR_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? I8042_STR_TIMEOUT : 0)); + if (chars_added > 0) + resched = true; + + retry = true; + } + + // TODO: check other status bits here + } while (retry); + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +int platform_read_key(char *c) +{ + ssize_t len; + + len = cbuf_read_char(key_buf, c, true); + return len; +} + +void platform_init_keyboard(cbuf_t *buffer) +{ + uint8_t ctr; + + key_buf = buffer; + + i8042_flush(); + + if (i8042_command(&ctr, I8042_CMD_CTL_RCTR)) { + dprintf(SPEW, "Failed to read CTR while initializing i8042\n"); + return; + } + + // turn on translation + ctr |= I8042_CTR_XLATE; + + // enable keyboard and keyboard irq + ctr &= ~I8042_CTR_KBDDIS; + ctr |= I8042_CTR_KBDINT; + + if (i8042_command(&ctr, I8042_CMD_CTL_WCTR)) { + dprintf(SPEW, "Failed to write CTR while initializing i8042\n"); + return; + } + + /* enable PS/2 port */ + i8042_command(NULL, I8042_CMD_KBD_EN); + + /* send a enable scan command to the keyboard */ + keyboard_command(&ctr, 0x1f4); + + uint32_t irq = apic_io_isa_to_global(ISA_IRQ_KEYBOARD); + register_int_handler(irq, &i8042_interrupt, NULL); + unmask_interrupt(irq); + + i8042_interrupt(NULL); +} + +void pc_keyboard_reboot(void) +{ + while (i8042_read_status() & I8042_STR_IBF); + i8042_write_command(I8042_CMD_PULSE_RESET); + // Wait a second for the command to process before declaring failure + spin(1000000); +} diff --git a/kernel/platform/pc/memory.c b/kernel/platform/pc/memory.c new file mode 100644 index 000000000..d4bf26508 --- /dev/null +++ b/kernel/platform/pc/memory.c @@ -0,0 +1,439 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include "platform_p.h" +#include + +#define LOCAL_TRACE 0 + +/* multiboot information passed in, if present */ +extern multiboot_info_t *_multiboot_info; +extern void *_zero_page_boot_params; + +/* statically allocate an array of pmm_arena_ts to be filled in at boot time */ +#define PMM_ARENAS 16 +static pmm_arena_t mem_arenas[PMM_ARENAS]; + +struct addr_range { + uint64_t base; + uint64_t size; +}; + +/* Values that will store the largest low-memory contiguous address space + * that we can let the PCIe bus driver use for allocations */ +paddr_t pcie_mem_lo_base; +size_t pcie_mem_lo_size; + +/* Store the PIO region for PCIe; make thes variables so we can easily + * change them later */ +#define BASE_PMIO_ADDR 0x1000 +uint16_t pcie_pio_base = BASE_PMIO_ADDR; +uint16_t pcie_pio_size = 0x10000 - BASE_PMIO_ADDR; + +/* Scratch space for storing discovered address ranges so we can sort them */ +#define MAX_ADDRESS_RANGES 32 +static struct addr_range address_ranges[MAX_ADDRESS_RANGES]; + +#define DEFAULT_MEMEND (16*1024*1024) + +/* boot_addr_range_t is an iterator which iterates over address ranges from + * the boot loader + */ +struct boot_addr_range; + +typedef void (*boot_addr_range_advance_func)( + struct boot_addr_range *range_struct); +typedef void (*boot_addr_range_reset_func)( + struct boot_addr_range *range_struct); + +typedef struct boot_addr_range { + /* the base of the current address range */ + uint64_t base; + /* the size of the current address range */ + uint64_t size; + /* whether this range contains memory */ + int is_mem; + /* whether this range is currently reset and invalid */ + int is_reset; + + /* private information for the advance function to keep its place */ + void *seq; + /* a function which advances this iterator to the next address range */ + boot_addr_range_advance_func advance; + /* a function which resets this range and its sequencing information */ + boot_addr_range_reset_func reset; +} boot_addr_range_t; + +/* a utility function to reset the common parts of a boot_addr_range_t */ +static void boot_addr_range_reset(boot_addr_range_t *range) +{ + range->base = 0; + range->size = 0; + range->is_mem = 0; + range->is_reset = 1; +} + +/* this function uses the boot_addr_range_t iterator to walk through address + * ranges described by the boot loader. it fills in the mem_arenas global + * array with the ranges of memory it finds, compacted to the start of the + * array. it returns the total count of arenas which have been populated. + */ +static int mem_arena_init(boot_addr_range_t *range) +{ + int used = 0; + + for (range->reset(range), range->advance(range); + !range->is_reset && used < PMM_ARENAS; + range->advance(range)) { + + LTRACEF("Range at %#llx of %#llx bytes is %smemory.\n", + range->base, range->size, range->is_mem ? "" : "not "); + + if (!range->is_mem) + continue; + + /* trim off parts of memory ranges that are smaller than a page */ + uint64_t base = ROUNDUP(range->base, PAGE_SIZE); + uint64_t size = ROUNDDOWN(range->base + range->size, PAGE_SIZE) - + base; + + /* trim any memory below 1MB for safety and SMP booting purposes */ + if (base < 1*MB) { + uint64_t adjust = 1*MB - base; + if (adjust >= size) + continue; + + base += adjust; + size -= adjust; + } + +#if ARCH_X86_32 + /* X86-32 can only handle up to 1GB of physical memory */ + if (base > 1*GB) + continue; + + if (base + size > 1*GB) { + uint64_t adjust = 1*GB - base; + + size -= adjust; + } +#endif + + while (size && used < PMM_ARENAS) { + pmm_arena_t *arena = &mem_arenas[used]; + + arena->base = base; + arena->size = size; + + if ((uint64_t)arena->base != base) { + LTRACEF("Range base %#llx is too high.\n", base); + break; + } + if ((uint64_t)arena->size != size) { + LTRACEF("Range size %#llx is too large, splitting it.\n", size); + arena->size = -PAGE_SIZE; + } + + size -= arena->size; + base += arena->size; + + LTRACEF("Adding pmm range at %#lx of %#lx bytes.\n", + arena->base, arena->size); + + arena->name = "memory"; + arena->priority = 1; + arena->flags = PMM_ARENA_FLAG_KMAP; + + used++; + } + } + + return used; +} + +#define E820_ENTRIES_OFFSET 0x1e8 +#define E820_MAP_OFFSET 0x2d0 + +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +struct e820entry { + uint64_t addr; + uint64_t size; + uint32_t type; +} __attribute__((packed)); + +typedef struct e820_range_seq { + struct e820entry *map; + int index; + int count; +} e820_range_seq_t; + +static void e820_range_reset(boot_addr_range_t *range) +{ + boot_addr_range_reset(range); + + e820_range_seq_t *seq = (e820_range_seq_t *)(range->seq); + seq->index = -1; +} + +static void e820_range_advance(boot_addr_range_t *range) +{ + e820_range_seq_t *seq = (e820_range_seq_t *)(range->seq); + + seq->index++; + + if (seq->index == seq->count) { + /* reset range to signal that we're at the end of the map */ + e820_range_reset(range); + return; + } + + struct e820entry *entry = &seq->map[seq->index]; + range->base = entry->addr; + range->size = entry->size; + range->is_mem = (entry->type == E820_RAM) ? 1 : 0; + range->is_reset = 0; +} + +static int e820_range_init(boot_addr_range_t *range, e820_range_seq_t *seq) +{ + range->seq = seq; + range->advance = &e820_range_advance; + range->reset = &e820_range_reset; + + if (_zero_page_boot_params == NULL) { + LTRACEF("No zero page found.\n"); + return 0; + } + + uintptr_t zero_page = (uintptr_t)_zero_page_boot_params + KERNEL_BASE; + + seq->count = *(uint8_t *)(zero_page + E820_ENTRIES_OFFSET); + LTRACEF("There are %d e820 mappings.\n", seq->count); + + seq->map = (void *)(zero_page + E820_MAP_OFFSET); + + range->reset(range); + + return 1; +} + + +typedef struct multiboot_range_seq { + multiboot_info_t *info; + memory_map_t *mmap; + int index; + int count; +} multiboot_range_seq_t; + +static void multiboot_range_reset(boot_addr_range_t *range) +{ + boot_addr_range_reset(range); + + multiboot_range_seq_t *seq = (multiboot_range_seq_t *)(range->seq); + seq->index = -1; +} + +static void multiboot_range_advance(boot_addr_range_t *range) +{ + multiboot_range_seq_t *seq = (multiboot_range_seq_t *)(range->seq); + + if (seq->mmap) { + /* memory map based range information */ + seq->index++; + + if (seq->index == seq->count) { + multiboot_range_reset(range); + return; + } + + memory_map_t *entry = &seq->mmap[seq->index]; + + range->base = entry->base_addr_high; + range->base <<= 32; + range->base |= entry->base_addr_low; + + range->size = entry->length_high; + range->size <<= 32; + range->size |= entry->length_low; + + range->is_mem = (entry->type == MB_MMAP_TYPE_AVAILABLE) ? 1 : 0; + + range->is_reset = 0; + } else { + /* scalar info about a single range */ + if (!range->is_reset) { + /* toggle back and forth between reset and valid */ + multiboot_range_reset(range); + return; + } + + range->base = seq->info->mem_lower * 1024U; + range->size = (seq->info->mem_upper - seq->info->mem_lower) * 1024U; + range->is_mem = 1; + range->is_reset = 0; + } +} + +static int multiboot_range_init(boot_addr_range_t *range, + multiboot_range_seq_t *seq) +{ + LTRACEF("_multiboot_info %p\n", _multiboot_info); + + range->seq = seq; + range->advance = &multiboot_range_advance; + range->reset = &multiboot_range_reset; + + if (_multiboot_info == NULL) { + /* no multiboot info found. */ + return 0; + } + + seq->info = (multiboot_info_t *)X86_PHYS_TO_VIRT(_multiboot_info); + seq->mmap = NULL; + seq->count = 0; + + if (seq->info->flags & MB_INFO_MMAP) { + /* we've been told the memory map is valid, so set it up */ + seq->mmap = (memory_map_t *)(uintptr_t)(seq->info->mmap_addr - 4); + seq->count = seq->info->mmap_length / sizeof(memory_map_t); + + multiboot_range_reset(range); + return 1; + } + + if (seq->info->flags & MB_INFO_MEM_SIZE) { + /* no additional setup required for the scalar range */ + return 1; + } + + /* no memory information in the multiboot info */ + return 0; +} + +int addr_range_cmp(const void* p1, const void* p2) +{ + const struct addr_range *a1 = p1; + const struct addr_range *a2 = p2; + + if (a1->base < a2->base) + return -1; + else if (a1->base == a2->base) + return 0; + return 1; +} + +/* Find the largest low-memory gap in the memory map provided by the + * bootloader to assign to PCIe. + */ +static void find_pcie_mmio_region(void) +{ + boot_addr_range_t range; + + e820_range_seq_t e820_seq; + multiboot_range_seq_t multiboot_seq; + if (!e820_range_init(&range, &e820_seq)) { + if (!multiboot_range_init(&range, &multiboot_seq)) { + pcie_mem_lo_base = 0; + pcie_mem_lo_size = 0; + } + } + + uint num_ranges = 0; + for (range.reset(&range), range.advance(&range); + !range.is_reset; + range.advance(&range)) { + + /* TODO(teisenbe): We can probably just dynamically allocate an array + * here to avoid the too many address ranges case */ + if (num_ranges == MAX_ADDRESS_RANGES) { + printf("WARNING: Too many address ranges, cannot allocate PCIe region\n"); + pcie_mem_lo_base = 0; + pcie_mem_lo_size = 0; + return; + } + address_ranges[num_ranges].base = range.base; + address_ranges[num_ranges].size = range.size; + /* make sure we don't wrap the address space */ + DEBUG_ASSERT(range.base <= range.base + range.size); + num_ranges++; + } + if (num_ranges == 0) { + return; + } + qsort(address_ranges, num_ranges, sizeof(address_ranges[0]), addr_range_cmp); + + /* Assume the ranges are non-overlapping and search for the biggest gap */ + for (uint i = 0; i < num_ranges - 1; ++i) { + DEBUG_ASSERT(address_ranges[i].base < address_ranges[i + 1].base); + uint64_t end = address_ranges[i].base + address_ranges[i].size; + if (end > HIGH_ADDRESS_LIMIT) { + break; + } + uint64_t next_start = address_ranges[i + 1].base; + if (next_start > HIGH_ADDRESS_LIMIT) { + next_start = HIGH_ADDRESS_LIMIT; + } + DEBUG_ASSERT(next_start >= end); + uint64_t size = next_start - end; + if (size > pcie_mem_lo_size) { + pcie_mem_lo_size = size; + pcie_mem_lo_base = end; + } + } + + uint64_t end = address_ranges[num_ranges - 1].base + address_ranges[num_ranges - 1].size; + if (end < HIGH_ADDRESS_LIMIT) { + uint64_t size = HIGH_ADDRESS_LIMIT - end; + if (size > pcie_mem_lo_size) { + pcie_mem_lo_size = size; + pcie_mem_lo_base = end; + } + } +} + +static int platform_mem_range_init(void) +{ + boot_addr_range_t range; + int count = 0; + + /* try getting range info from e820 first */ + e820_range_seq_t e820_seq; + if (e820_range_init(&range, &e820_seq) && + (count = mem_arena_init(&range))) + return count; + + /* if no ranges were found, try multiboot */ + multiboot_range_seq_t multiboot_seq; + if (multiboot_range_init(&range, &multiboot_seq) && + (count = mem_arena_init(&range))) + return count; + + /* if still no ranges were found, make a safe guess */ + mem_arenas[0].name = "memory"; + mem_arenas[0].base = MEMBASE; + mem_arenas[0].size = DEFAULT_MEMEND; + mem_arenas[0].priority = 1; + mem_arenas[0].flags = PMM_ARENA_FLAG_KMAP; + return 1; +} + +/* Discover the basic memory map */ +void platform_mem_init(void) +{ + int arena_count = platform_mem_range_init(); + for (int i = 0; i < arena_count; i++) + pmm_add_arena(&mem_arenas[i]); + + find_pcie_mmio_region(); +} diff --git a/kernel/platform/pc/pci.c b/kernel/platform/pc/pci.c new file mode 100644 index 000000000..61fae1e15 --- /dev/null +++ b/kernel/platform/pc/pci.c @@ -0,0 +1,577 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +static int last_bus = 0; +static spin_lock_t lock; + +typedef struct { + uint16_t size; + void *offset; + uint16_t selector; +} __PACKED irq_routing_options_t; + +static int pci_type1_detect(void); +static int pci_bios_detect(void); + +int pci_get_last_bus(void) +{ + return last_bus; +} + +/* + * pointers to installed PCI routines + */ +int (*g_pci_find_pci_device)(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index); +int (*g_pci_find_pci_class_code)(pci_location_t *state, uint32_t class_code, uint16_t index); + +int (*g_pci_read_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t *value); +int (*g_pci_read_config_half)(const pci_location_t *state, uint32_t reg, uint16_t *value); +int (*g_pci_read_config_word)(const pci_location_t *state, uint32_t reg, uint32_t *value); + +int (*g_pci_write_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t value); +int (*g_pci_write_config_half)(const pci_location_t *state, uint32_t reg, uint16_t value); +int (*g_pci_write_config_word)(const pci_location_t *state, uint32_t reg, uint32_t value); + +int (*g_pci_get_irq_routing_options)(irq_routing_options_t *options, uint16_t *pci_irqs); +int (*g_pci_set_irq_hw_int)(const pci_location_t *state, uint8_t int_pin, uint8_t irq); + + +int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_find_pci_device(state, device_id, vendor_id, index); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_find_pci_class_code(state, class_code, index); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_read_config_byte(state, reg, value); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} +int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_read_config_half(state, reg, value); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_read_config_word(state, reg, value); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_write_config_byte(state, reg, value); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_write_config_half(state, reg, value); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_write_config_word(state, reg, value); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + + +int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs) +{ + irq_routing_options_t options; + options.size = sizeof(irq_routing_entry) **count; + options.selector = DATA_SELECTOR; + options.offset = entries; + + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_get_irq_routing_options(&options, pci_irqs); + + spin_unlock_irqrestore(&lock, irqstate); + + *count = options.size / sizeof(irq_routing_entry); + + return res; +} + +int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq) +{ + spin_lock_saved_state_t irqstate; + spin_lock_irqsave(&lock, irqstate); + + int res = g_pci_set_irq_hw_int(state, int_pin, irq); + + spin_unlock_irqrestore(&lock, irqstate); + + return res; +} + +void pci_init(void) +{ + if (!pci_bios_detect()) { + dprintf(INFO, "pci bios functions installed\n"); + dprintf(INFO, "last pci bus is %d\n", last_bus); + } +} + +#define PCIBIOS_PRESENT 0xB101 +#define PCIBIOS_FIND_PCI_DEVICE 0xB102 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0xB103 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xB106 +#define PCIBIOS_READ_CONFIG_BYTE 0xB108 +#define PCIBIOS_READ_CONFIG_WORD 0xB109 +#define PCIBIOS_READ_CONFIG_DWORD 0xB10A +#define PCIBIOS_WRITE_CONFIG_BYTE 0xB10B +#define PCIBIOS_WRITE_CONFIG_WORD 0xB10C +#define PCIBIOS_WRITE_CONFIG_DWORD 0xB10D +#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0xB10E +#define PCIBIOS_PCI_SET_IRQ_HW_INT 0xB10F + +#define PCIBIOS_SUCCESSFUL 0x00 +#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 +#define PCIBIOS_BAD_VENDOR_ID 0x83 +#define PCIBIOS_DEVICE_NOT_FOUND 0x86 +#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 +#define PCIBIOS_SET_FAILED 0x88 +#define PCIBIOS_BUFFER_TOO_SMALL 0x89 + +/* + * far call structure used by BIOS32 routines + */ +static struct { + uint32_t offset; + uint16_t selector; +} __PACKED bios32_entry; + +/* + * BIOS32 entry header + */ +typedef struct { + uint8_t magic[4]; // "_32_" + void *entry; // entry point + uint8_t revision; + uint8_t length; + uint8_t checksum; + uint8_t reserved[5]; +} __PACKED pci_bios_info; + +/* + * scan for pci bios + */ +static const char *pci_bios_magic = "_32_"; +static pci_bios_info *find_pci_bios_info(void) +{ + uint32_t *head = (uint32_t *) (0x000e0000 + KERNEL_BASE); + int8_t sum, *b; + uint i; + + while (head < (uint32_t *) (0x000ffff0 + KERNEL_BASE)) { + if (*head == *(uint32_t *) pci_bios_magic) { + // perform the checksum + sum = 0; + b = (int8_t *) head; + for (i=0; i < sizeof(pci_bios_info); i++) { + sum += b[i]; + } + + if (sum == 0) { + return (pci_bios_info *) head; + } + } + + head += 4; + } + + return NULL; +} + +/* + * local BIOS32 PCI routines + */ +static int bios_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index) +{ + uint32_t bx, ret; + + __asm__( + "lcall *(%%edi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=b"(bx), + "=a"(ret) + : "1"(PCIBIOS_FIND_PCI_DEVICE), + "c"(device_id), + "d"(vendor_id), + "S"(index), + "D"(&bios32_entry)); + + state->bus = bx >> 8; + state->dev_fn = bx & 0xFF; + + ret >>= 8; + return ret & 0xFF; +} + +static int bios_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index) +{ + uint32_t bx, ret; + + __asm__( + "lcall *(%%edi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=b"(bx), + "=a"(ret) + : "1"(PCIBIOS_FIND_PCI_CLASS_CODE), + "c"(class_code), + "S"(index), + "D"(&bios32_entry)); + + state->bus = bx >> 8; + state->dev_fn = bx & 0xFF; + + ret >>= 8; + return ret & 0xFF; +} + + +static int bios_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value) +{ + uint32_t bx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=c"(*value), + "=a"(ret) + : "1"(PCIBIOS_READ_CONFIG_BYTE), + "b"(bx), + "D"(reg), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static int bios_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value) +{ + uint32_t bx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=c"(*value), + "=a"(ret) + : "1"(PCIBIOS_READ_CONFIG_WORD), + "b"(bx), + "D"(reg), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static int bios_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value) +{ + uint32_t bx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=c"(*value), + "=a"(ret) + : "1"(PCIBIOS_READ_CONFIG_DWORD), + "b"(bx), + "D"(reg), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static int bios_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value) +{ + uint32_t bx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=a"(ret) + : "0"(PCIBIOS_WRITE_CONFIG_BYTE), + "c"(value), + "b"(bx), + "D"(reg), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static int bios_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value) +{ + uint32_t bx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=a"(ret) + : "0"(PCIBIOS_WRITE_CONFIG_WORD), + "c"(value), + "b"(bx), + "D"(reg), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static int bios_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value) +{ + uint32_t bx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=a"(ret) + : "0"(PCIBIOS_WRITE_CONFIG_DWORD), + "c"(value), + "b"(bx), + "D"(reg), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static int bios_get_irq_routing_options(irq_routing_options_t *route_buffer, uint16_t *pciIrqs) +{ + uint32_t ret; + + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=b"(*pciIrqs), + "=a"(ret) + : "1"(PCIBIOS_GET_IRQ_ROUTING_OPTIONS), + "b"(0), + "D"(route_buffer), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xff; +} + +static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq) +{ + uint32_t bx, cx, ret; + + bx = state->bus; + bx <<= 8; + bx |= state->dev_fn; + cx = irq; + cx <<= 8; + cx |= int_pin; + __asm__( + "lcall *(%%esi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=a"(ret) + : "0"(PCIBIOS_PCI_SET_IRQ_HW_INT), + "b"(bx), + "c"(cx), + "S"(&bios32_entry)); + ret >>= 8; + return ret & 0xFF; +} + +static const char *pci_signature = "PCI "; +static int pci_bios_detect(void) +{ + // XXX disable for now + return 0; + + pci_bios_info *pci = find_pci_bios_info(); + if (pci != NULL) { + printf("Found PCI structure at %p\n", pci); + + printf("\nPCI header info:\n"); + printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2], + pci->magic[3]); + printf("%p\n", pci->entry); + printf("%d\n", pci->length * 16); + printf("%d\n", pci->checksum); + + uint32_t adr, temp, len; + uint8_t err; + + bios32_entry.offset = (uint32_t)(uintptr_t)pci->entry + KERNEL_BASE; + bios32_entry.selector = CODE_SELECTOR; + + __asm__( + "lcall *(%%edi)" + : "=a"(err), /* AL out=status */ + "=b"(adr), /* EBX out=code segment base adr */ + "=c"(len), /* ECX out=code segment size */ + "=d"(temp) /* EDX out=entry pt offset in code */ + : "0"(0x49435024),/* EAX in=service="$PCI" */ + "1"(0), /* EBX in=0=get service entry pt */ + "D"(&bios32_entry) + ); + + if (err == 0x80) { + dprintf(INFO, "BIOS32 found, but no PCI BIOS\n"); + return -1; + } + + if (err != 0) { + dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err); + return -1; + } + + bios32_entry.offset = adr + temp; + + // now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus + uint16_t present, version, busses; + uint32_t signature; + __asm__( + "lcall *(%%edi) \n\t" + "jc 1f \n\t" + "xor %%ah,%%ah \n" + "1:" + : "=a"(present), + "=b"(version), + "=c"(busses), + "=d"(signature) + : "0"(PCIBIOS_PRESENT), + "D"(&bios32_entry) + ); + + if (present & 0xff00) { + dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8); + return -1; + } + + if (signature != *(uint32_t *)pci_signature) { + dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature); + return -1; + } + + //dprintf(DEBUG, "busses=%04x\n", busses); + last_bus = busses & 0xff; + + g_pci_find_pci_device = bios_find_pci_device; + g_pci_find_pci_class_code = bios_find_pci_class_code; + + g_pci_read_config_word = bios_read_config_word; + g_pci_read_config_half = bios_read_config_half; + g_pci_read_config_byte = bios_read_config_byte; + + g_pci_write_config_word = bios_write_config_word; + g_pci_write_config_half = bios_write_config_half; + g_pci_write_config_byte = bios_write_config_byte; + + g_pci_get_irq_routing_options = bios_get_irq_routing_options; + g_pci_set_irq_hw_int = bios_set_irq_hw_int; + + return 0; + } + + return -1; +} diff --git a/kernel/platform/pc/pic.c b/kernel/platform/pc/pic.c new file mode 100644 index 000000000..4993a53a9 --- /dev/null +++ b/kernel/platform/pc/pic.c @@ -0,0 +1,50 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +#include +#include +#include + +#define PIC1 0x20 +#define PIC2 0xA0 + +#define ICW1 0x11 +#define ICW4 0x01 + +/* + * init the PICs and remap them + */ +void pic_map(uint32_t pic1, uint32_t pic2) { + /* send ICW1 */ + outp(PIC1, ICW1); + outp(PIC2, ICW1); + + /* send ICW2 */ + outp(PIC1 + 1, pic1); /* remap */ + outp(PIC2 + 1, pic2); /* pics */ + + /* send ICW3 */ + outp(PIC1 + 1, 4); /* IRQ2 -> connection to slave */ + outp(PIC2 + 1, 2); + + /* send ICW4 */ + outp(PIC1 + 1, 5); + outp(PIC2 + 1, 1); + + /* disable all IRQs */ + outp(PIC1 + 1, 0xff); + outp(PIC2 + 1, 0xff); +} + +void pic_disable(void) { + outp(PIC2 + 1, 0xff); + outp(PIC1 + 1, 0xff); +} diff --git a/kernel/platform/pc/platform.c b/kernel/platform/pc/platform.c new file mode 100644 index 000000000..f0dc9127d --- /dev/null +++ b/kernel/platform/pc/platform.c @@ -0,0 +1,331 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// Copyright (c) 2015 Intel Corporation +// Copyright (c) 2016 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include "platform_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +extern void pci_init(void); +extern status_t x86_alloc_msi_block(uint requested_irqs, + bool can_target_64bit, + bool is_msix, + pcie_msi_block_t* out_block); +extern void x86_free_msi_block(pcie_msi_block_t* block); +extern void x86_register_msi_handler(const pcie_msi_block_t* block, + uint msi_id, + int_handler handler, + void* ctx); + +#if WITH_KERNEL_VM +struct mmu_initial_mapping mmu_initial_mappings[] = { +#if ARCH_X86_64 + /* 64GB of memory mapped where the kernel lives */ + { + .phys = MEMBASE, + .virt = KERNEL_ASPACE_BASE, + .size = 64ULL*GB, /* x86-64 maps first 64GB by default */ + .flags = 0, + .name = "memory" + }, +#endif + /* KERNEL_SIZE of memory mapped where the kernel lives. + * On x86-64, this only sticks around until the VM is brought up, after + * that this will be replaced with mappings of the correct privileges. */ + { + .phys = MEMBASE, + .virt = KERNEL_BASE, + .size = KERNEL_SIZE, /* x86 maps first KERNEL_SIZE by default */ +#if ARCH_X86_64 + .flags = MMU_INITIAL_MAPPING_TEMPORARY, + .name = "kernel_temp" +#else + .flags = 0, + .name = "kernel", +#endif + }, + /* null entry to terminate the list */ + { 0 } +}; +#endif + +static struct acpi_pcie_irq_mapping pcie_root_irq_map; + +void *_zero_page_boot_params; + +uint32_t bootloader_acpi_rsdp; +uint32_t bootloader_fb_base; +uint32_t bootloader_fb_width; +uint32_t bootloader_fb_height; +uint32_t bootloader_fb_stride; +uint32_t bootloader_fb_format; +uint32_t bootloader_i915_reg_base; +uint32_t bootloader_fb_window_size; + +/* This is a temporary extension to the "zero page" protcol, making use + * of obsolete fields to pass some additional data from bootloader to + * kernel in a way that would to badly interact with a Linux kernel booting + * from the same loader. + */ +void platform_save_bootloader_data(void) +{ + uint32_t *zp = (void*) ((uintptr_t)_zero_page_boot_params + KERNEL_BASE); + + if (zp[0x220 / 4] == 0xDBC64323) { + bootloader_acpi_rsdp = zp[0x80 / 4]; + bootloader_fb_base = zp[0x90 / 4]; + bootloader_fb_width = zp[0x94 / 4]; + bootloader_fb_height = zp[0x98 / 4]; + bootloader_fb_stride = zp[0x9C / 4]; + bootloader_fb_format = zp[0xA0 / 4]; + bootloader_i915_reg_base = zp[0xA4 / 4]; + bootloader_fb_window_size = zp[0xA8 / 4]; + } +} + +#include +#include + +void *boot_alloc_mem(size_t len); + +status_t display_get_info(struct display_info *info) { + return gfxconsole_display_get_info(info); +} + +void platform_early_display_init(void) { + struct display_info info; + void *bits; + + if (bootloader_fb_base == 0) { + return; + } + + // allocate an offscreen buffer of worst-case size, page aligned + bits = boot_alloc_mem(8192 + bootloader_fb_height * bootloader_fb_width * 4); + bits = (void*) ((((uintptr_t) bits) + 4095) & (~4095)); + + memset(&info, 0, sizeof(info)); + info.format = bootloader_fb_format; + info.width = bootloader_fb_width; + info.height = bootloader_fb_height; + info.stride = bootloader_fb_stride; + info.flags = DISPLAY_FLAG_HW_FRAMEBUFFER; + info.framebuffer = (void*) X86_PHYS_TO_VIRT(bootloader_fb_base); + + gfxconsole_bind_display(&info, bits); +} + +void platform_early_init(void) +{ + /* get the debug output working */ + platform_init_debug_early(); + + /* get the text console working */ + platform_init_console(); + + /* extract "zero page" data while still accessible */ + platform_save_bootloader_data(); + + /* if the bootloader has framebuffer info, use it for early console */ + platform_early_display_init(); + + /* initialize physical memory arenas */ + platform_mem_init(); +} + +#if WITH_SMP +void platform_init_smp(void) +{ + uint32_t num_cpus = 0; + status_t status = platform_enumerate_cpus(NULL, 0, &num_cpus); + if (status != NO_ERROR) { + TRACEF("failed to enumerate CPUs, disabling SMP\n"); + return; + } + + printf("Found %d cpus\n", num_cpus); + if (num_cpus > SMP_MAX_CPUS) { + TRACEF("Clamping number of CPUs to %d\n", SMP_MAX_CPUS); + num_cpus = SMP_MAX_CPUS; + } + + uint32_t *apic_ids = malloc(sizeof(*apic_ids) * num_cpus); + if (apic_ids == NULL) { + TRACEF("failed to allocate apic_ids table, disabling SMP\n"); + return; + } + uint32_t real_num_cpus; + status = platform_enumerate_cpus(apic_ids, num_cpus, &real_num_cpus); + if (status != NO_ERROR) { + TRACEF("failed to enumerate CPUs, disabling SMP\n"); + free(apic_ids); + return; + } + + if (num_cpus == SMP_MAX_CPUS) { + // If we are at the max number of CPUs, sanity check that the bootstrap + // processor is in that set, to make sure clamping didn't go awry. + uint32_t bsp_apic_id = apic_local_id(); + bool found_bp = false; + for (unsigned int i = 0; i < num_cpus; ++i) { + if (apic_ids[i] == bsp_apic_id) { + found_bp = true; + break; + } + } + ASSERT(found_bp); + } + + x86_bringup_smp(apic_ids, num_cpus); + free(apic_ids); +} +#endif + +static status_t acpi_pcie_irq_swizzle(const pcie_common_state_t* common, + uint pin, + uint *irq) +{ + DEBUG_ASSERT(common); + DEBUG_ASSERT(pin < 4); + if (common->bus_id != 0) { + return ERR_NOT_FOUND; + } + uint32_t val = pcie_root_irq_map.dev_pin_to_global_irq[common->dev_id][common->func_id][pin]; + if (val == ACPI_NO_IRQ_MAPPING) { + return ERR_NOT_FOUND; + } + *irq = val; + return NO_ERROR; +} + +void platform_init_pcie(void) { + struct acpi_pcie_config config; + status_t status = platform_find_pcie_config(&config); + if (status != NO_ERROR) { + TRACEF("failed to find PCIe configuration space\n"); + return; + } + if (config.start_bus != 0) { + TRACEF("PCIe buses that don't start at 0 not currently supported\n"); + return; + } + if (config.segment_group != 0) { + TRACEF("PCIe segment groups not currently supported\n"); + return; + } + + status = platform_find_pcie_legacy_irq_mapping(&pcie_root_irq_map); + if (status != NO_ERROR) { + TRACEF("failed to find PCIe IRQ remapping\n"); + return; + } + + // Configure the discovered PCIe IRQs + for (uint i = 0; i < pcie_root_irq_map.num_irqs; ++i) { + struct acpi_irq_signal *sig = &pcie_root_irq_map.irqs[i]; + enum io_apic_irq_trigger_mode trig_mode = IRQ_TRIGGER_MODE_EDGE; + enum io_apic_irq_polarity polarity = IRQ_POLARITY_ACTIVE_LOW; + if (sig->active_high) { + polarity = IRQ_POLARITY_ACTIVE_HIGH; + } + if (sig->level_triggered) { + trig_mode = IRQ_TRIGGER_MODE_LEVEL; + } + apic_io_configure_irq( + sig->global_irq, + trig_mode, + polarity, + DELIVERY_MODE_FIXED, + IO_APIC_IRQ_MASK, + DST_MODE_PHYSICAL, + // TODO(teisenbe): Balance IRQs + apic_local_id(), + 0); + } + + // Check for a quirk that we've seen. Some systems will report overly large + // PCIe config regions that collide with architectural registers. + paddr_t end = config.ecam_phys + + (config.end_bus - config.start_bus + 1) * PCIE_ECAM_BYTE_PER_BUS; + DEBUG_ASSERT(config.start_bus <= config.end_bus); + if (end > HIGH_ADDRESS_LIMIT) { + TRACEF("PCIe config space collides with arch devices, truncating\n"); + end = HIGH_ADDRESS_LIMIT; + DEBUG_ASSERT(end >= config.ecam_phys); + config.ecam_size = ROUNDDOWN(end - config.ecam_phys, PCIE_ECAM_BYTE_PER_BUS); + config.end_bus = (config.ecam_size / PCIE_ECAM_BYTE_PER_BUS) + config.start_bus - 1; + } + + // TODO(johngro): Do not limit this to a single range. Instead, fetch all + // of the ECAM ranges from ACPI, as well as the appropriate bus start/end + // ranges. + DEBUG_ASSERT(config.ecam_size >= PCIE_ECAM_BYTE_PER_BUS); + const pcie_ecam_range_t PCIE_ECAM_WINDOWS[] = { + { + .io_range = { .bus_addr = config.ecam_phys, .size = config.ecam_size }, + .bus_start = 0x00, + .bus_end = (uint8_t)(config.ecam_size / PCIE_ECAM_BYTE_PER_BUS) - 1, + }, + }; + + const pcie_init_info_t PCIE_INIT_INFO = { + .ecam_windows = PCIE_ECAM_WINDOWS, + .ecam_window_count = countof(PCIE_ECAM_WINDOWS), + .mmio_window_lo = { .bus_addr = pcie_mem_lo_base, .size = pcie_mem_lo_size }, + .mmio_window_hi = { .bus_addr = 0, .size = 0 }, + .pio_window = { .bus_addr = pcie_pio_base, .size = pcie_pio_size }, + .legacy_irq_swizzle = acpi_pcie_irq_swizzle, + .alloc_msi_block = x86_alloc_msi_block, + .free_msi_block = x86_free_msi_block, + .register_msi_handler = x86_register_msi_handler, + .mask_unmask_msi = NULL, + }; + + status = pcie_init(&PCIE_INIT_INFO); + if (status != NO_ERROR) + TRACEF("Failed to initialize PCIe bus driver! (status = %d)\n", status); +} + +void platform_init(void) +{ + platform_init_debug(); + +#if NO_USER_KEYBOARD + platform_init_keyboard(&console_input_buf); +#endif + +#if WITH_SMP + platform_init_smp(); +#endif + + platform_init_acpi(); + + // detach the early console - pcie init may move it + gfxconsole_bind_display(NULL, NULL); + + platform_init_pcie(); +} diff --git a/kernel/platform/pc/platform_p.h b/kernel/platform/pc/platform_p.h new file mode 100644 index 000000000..4dd8daceb --- /dev/null +++ b/kernel/platform/pc/platform_p.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +extern cbuf_t console_input_buf; + +/* Do not use anything above this address for PCIe stuff. A bunch of + * architectural devices often occupy this area */ +#define HIGH_ADDRESS_LIMIT 0xfec00000 + +extern paddr_t pcie_mem_lo_base; +extern size_t pcie_mem_lo_size; + +extern uint16_t pcie_pio_base; +extern uint16_t pcie_pio_size; + +void platform_init_debug_early(void); +void platform_init_debug(void); +void platform_init_timer_percpu(void); +void platform_mem_init(void); diff --git a/kernel/platform/pc/rules.mk b/kernel/platform/pc/rules.mk new file mode 100644 index 000000000..458cf068f --- /dev/null +++ b/kernel/platform/pc/rules.mk @@ -0,0 +1,42 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +CPU := generic + +MODULE_DEPS += \ + lib/cbuf \ + +MODULE_SRCS += \ + $(LOCAL_DIR)/acpi.c \ + $(LOCAL_DIR)/acpi_debug.c \ + $(LOCAL_DIR)/console.c \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/ide.c \ + $(LOCAL_DIR)/interrupts.c \ + $(LOCAL_DIR)/keyboard.c \ + $(LOCAL_DIR)/memory.c \ + $(LOCAL_DIR)/pci.c \ + $(LOCAL_DIR)/pic.c \ + $(LOCAL_DIR)/platform.c \ + $(LOCAL_DIR)/timer.c \ + $(LOCAL_DIR)/uart.c \ + +MODULE_DEPS += \ + lib/acpica \ + lib/gfxconsole \ + lib/pow2_range_allocator \ + dev/interrupt \ + dev/pcie \ + +LK_HEAP_IMPLEMENTATION ?= cmpctmalloc + +include make/module.mk + diff --git a/kernel/platform/pc/timer.c b/kernel/platform/pc/timer.c new file mode 100644 index 000000000..2d9d0a182 --- /dev/null +++ b/kernel/platform/pc/timer.c @@ -0,0 +1,321 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2009 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "platform_p.h" + +// Current timer scheme: +// The PIT is used to calibrate the local APIC timers initially. +// Afterwards, it is only used for maintaining wall time. +// +// The local APICs are responsible for handling timer callbacks +// sent from the scheduler. + +static platform_timer_callback t_callback[SMP_MAX_CPUS] = {NULL}; +static void *callback_arg[SMP_MAX_CPUS] = {NULL}; + +// PIT time accounting info +static uint64_t next_trigger_time; +static uint64_t next_trigger_delta; +static uint64_t ticks_per_ms; +static uint64_t timer_delta_time; +static volatile uint64_t timer_current_time; +static uint16_t pit_divisor; + +// Whether or not we have an Invariant TSC (controls whether we use the PIT or +// not after initialization). +static bool invariant_tsc; + +// APIC timer calibration values +static volatile uint32_t apic_ticks_per_ms = 0; +static uint8_t apic_divisor = 0; + +// TSC timer calibration values +static uint64_t tsc_ticks_per_ms; + +#define INTERNAL_FREQ 1193182ULL +#define INTERNAL_FREQ_3X 3579546ULL + +/* Maximum amount of time that can be program on the timer to schedule the next + * interrupt, in miliseconds */ +#define MAX_TIMER_INTERVAL 55 + +#define LOCAL_TRACE 0 + +lk_time_t current_time(void) +{ + lk_time_t time; + + if (invariant_tsc) { + uint64_t tsc = rdtsc(); + time = tsc / tsc_ticks_per_ms; + } else { + // XXX slight race + time = (lk_time_t) (timer_current_time >> 32); + } + + return time; +} + +lk_bigtime_t current_time_hires(void) +{ + lk_bigtime_t time; + + if (invariant_tsc) { + uint64_t tsc = rdtsc(); + time = tsc / (tsc_ticks_per_ms / 1000); + } else { + // XXX slight race + time = (lk_bigtime_t) ((timer_current_time >> 22) * 1000) >> 10; + } + + return time; +} + +// The PIT timer will keep track of wall time if we aren't using the TSC +static enum handler_return pit_timer_tick(void *arg) +{ + timer_current_time += timer_delta_time; + return INT_NO_RESCHEDULE; +} + +// The APIC timers will call this when they fire +enum handler_return platform_handle_timer_tick(void) { + DEBUG_ASSERT(arch_ints_disabled()); + uint cpu = arch_curr_cpu_num(); + + lk_time_t time = current_time(); + //lk_bigtime_t btime = current_time_hires(); + //printf_xy(71, 0, WHITE, "%08u", (uint32_t) time); + //printf_xy(63, 1, WHITE, "%016llu", (uint64_t) btime); + + if (t_callback[cpu] && timer_current_time >= next_trigger_time) { + lk_time_t delta = timer_current_time - next_trigger_time; + next_trigger_time = timer_current_time + next_trigger_delta - delta; + + return t_callback[cpu](callback_arg[cpu], time); + } else { + return INT_NO_RESCHEDULE; + } +} + +static void set_pit_frequency(uint32_t frequency) +{ + uint32_t count, remainder; + + /* figure out the correct pit_divisor for the desired frequency */ + if (frequency <= 18) { + count = 0xffff; + } else if (frequency >= INTERNAL_FREQ) { + count = 1; + } else { + count = INTERNAL_FREQ_3X / frequency; + remainder = INTERNAL_FREQ_3X % frequency; + + if (remainder >= INTERNAL_FREQ_3X / 2) { + count += 1; + } + + count /= 3; + remainder = count % 3; + + if (remainder >= 1) { + count += 1; + } + } + + pit_divisor = count & 0xffff; + + /* + * funky math that i don't feel like explaining. essentially 32.32 fixed + * point representation of the configured timer delta. + */ + timer_delta_time = (3685982306ULL * count) >> 10; + + //dprintf(DEBUG, "set_pit_frequency: dt=%016llx\n", timer_delta_time); + //dprintf(DEBUG, "set_pit_frequency: pit_divisor=%04x\n", pit_divisor); + + /* + * setup the Programmable Interval Timer + * timer 0, mode 2, binary counter, LSB followed by MSB + */ + outp(I8253_CONTROL_REG, 0x34); + outp(I8253_DATA_REG, pit_divisor & 0xff); // LSB + outp(I8253_DATA_REG, pit_divisor >> 8); // MSB +} + +static void calibrate_apic_timer(void) +{ + ASSERT(arch_ints_disabled()); + ASSERT(ticks_per_ms <= 0xffff); + + apic_divisor = 1; + while (apic_divisor != 0) { + uint32_t best_time = UINT32_MAX; + for (int tries = 0; tries < 3; ++tries) { + // Make the PIT run for 1ms + uint16_t init_pic_count = ticks_per_ms; + // Program PIT in the software strobe configuration, this makes + // it just count down. When it hits 0, it will wrap around and + // keep counting, so we need to watch for overflow below. + outp(I8253_CONTROL_REG, 0x38); + outp(I8253_DATA_REG, init_pic_count & 0xff); // LSB + outp(I8253_DATA_REG, init_pic_count >> 8); // MSB + + // Setup APIC timer to count down with interrupt masked + status_t status = apic_timer_set_oneshot( + UINT32_MAX, + apic_divisor, + true); + ASSERT(status == NO_ERROR); + + uint16_t count = 0; + do { + // Latch the count for channel 0 (does not pause the actual + // count) + outp(I8253_CONTROL_REG, 0x00); + count = inp(I8253_DATA_REG); + count |= inp(I8253_DATA_REG) << 8; + } while (count <= init_pic_count && count != 0); + + uint32_t apic_ticks = UINT32_MAX - apic_timer_current_count(); + if (apic_ticks < best_time) { + best_time = apic_ticks; + } + LTRACEF("Calibration trial %d found %u ticks/ms\n", + tries, apic_ticks); + } + + // If the APIC ran out of time every time, try again with a higher + // divisor + if (best_time == UINT32_MAX) { + apic_divisor *= 2; + continue; + } + + apic_ticks_per_ms = best_time; + break; + } + ASSERT(apic_divisor != 0); + + LTRACEF("APIC timer calibrated: %u ticks/ms, %d divisor\n", + apic_ticks_per_ms, apic_divisor); +} + +static void calibrate_tsc(void) +{ + ASSERT(arch_ints_disabled()); + ASSERT(ticks_per_ms <= 0xffff); + + uint64_t best_time = UINT64_MAX; + for (int tries = 0; tries < 3; ++tries) { + // Make the PIT run for 1ms + uint16_t init_pic_count = ticks_per_ms; + // Program PIT in the software strobe configuration, this makes + // it just count down. When it hits 0, it will wrap around and + // keep counting, so we need to watch for overflow below. + outp(I8253_CONTROL_REG, 0x38); + outp(I8253_DATA_REG, init_pic_count & 0xff); // LSB + outp(I8253_DATA_REG, init_pic_count >> 8); // MSB + + // Use CPUID to serialize the instruction stream + uint32_t _ignored; + cpuid(0, &_ignored, &_ignored, &_ignored, &_ignored); + uint64_t start = rdtsc(); + uint16_t count = 0; + do { + // Latch the count for channel 0 (does not pause the actual + // count) + outp(I8253_CONTROL_REG, 0x00); + count = inp(I8253_DATA_REG); + count |= inp(I8253_DATA_REG) << 8; + } while (count <= init_pic_count && count != 0); + cpuid(0, &_ignored, &_ignored, &_ignored, &_ignored); + uint64_t end = rdtsc(); + + uint64_t tsc_ticks = end - start; + if (tsc_ticks < best_time) { + best_time = tsc_ticks; + } + LTRACEF("Calibration trial %d found %llu ticks/ms\n", + tries, tsc_ticks); + } + + tsc_ticks_per_ms = best_time; + + LTRACEF("TSC calibrated: %llu ticks/ms\n", tsc_ticks_per_ms); +} + +void platform_init_timer(uint level) +{ + invariant_tsc = x86_feature_test(X86_FEATURE_INVAR_TSC); + ticks_per_ms = INTERNAL_FREQ/1000; + calibrate_apic_timer(); + if (invariant_tsc) { + calibrate_tsc(); + // Program PIT in the software strobe configuration, but do not load + // the count. This will pause the PIT. + outp(I8253_CONTROL_REG, 0x38); + } else { + timer_current_time = 0; + set_pit_frequency(1000); // ~1ms granularity + + uint32_t irq = apic_io_isa_to_global(ISA_IRQ_PIT); + register_int_handler(irq, &pit_timer_tick, NULL); + unmask_interrupt(irq); + } +} +LK_INIT_HOOK(timer, &platform_init_timer, LK_INIT_LEVEL_VM + 3); + +status_t platform_set_oneshot_timer(platform_timer_callback callback, + void *arg, lk_time_t interval) +{ + DEBUG_ASSERT(arch_ints_disabled()); + uint cpu = arch_curr_cpu_num(); + + t_callback[cpu] = callback; + callback_arg[cpu] = arg; + + if (interval > MAX_TIMER_INTERVAL) + interval = MAX_TIMER_INTERVAL; + if (interval < 1) interval = 1; + + uint8_t extra_divisor = 1; + while (apic_ticks_per_ms > UINT32_MAX / interval / extra_divisor) { + extra_divisor *= 2; + } + uint32_t count = (apic_ticks_per_ms / extra_divisor) * interval; + uint32_t divisor = apic_divisor * extra_divisor; + ASSERT(divisor <= UINT8_MAX); + LTRACEF("Scheduling oneshot timer: %u count, %d div\n", count, divisor); + return apic_timer_set_oneshot(count, divisor, false /* unmasked */); +} + +void platform_stop_timer(void) +{ + /* Enable interrupt mode that will stop the decreasing counter of the PIT */ + //outp(I8253_CONTROL_REG, 0x30); + apic_timer_stop(); +} diff --git a/kernel/platform/pc/uart.c b/kernel/platform/pc/uart.c new file mode 100644 index 000000000..5ede29e54 --- /dev/null +++ b/kernel/platform/pc/uart.c @@ -0,0 +1,162 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct device_class uart_device_class = { + .name = "uart", +}; + +struct uart_driver_state { + struct cbuf rx_buf; + struct cbuf tx_buf; +}; + +static status_t uart_init(struct device *dev); + +static enum handler_return uart_irq_handler(void *arg); +static int uart_write_thread(void *arg); + +static ssize_t uart_read(struct device *dev, void *buf, size_t len); +static ssize_t uart_write(struct device *dev, const void *buf, size_t len); + +static struct uart_ops the_ops = { + .std = { + .device_class = &uart_device_class, + .init = uart_init, + }, + .read = uart_read, + .write = uart_write, +}; + +DRIVER_EXPORT(uart, &the_ops.std); + +static status_t uart_init(struct device *dev) +{ + status_t res = NO_ERROR; + + if (!dev) + return ERR_INVALID_ARGS; + + if (!dev->config) + return ERR_NOT_CONFIGURED; + + const struct platform_uart_config *config = dev->config; + + struct uart_driver_state *state = malloc(sizeof(struct uart_driver_state)); + if (!state) { + res = ERR_NO_MEMORY; + goto done; + } + + dev->state = state; + + /* set up the driver state */ + cbuf_initialize(&state->rx_buf, config->rx_buf_len); + cbuf_initialize(&state->tx_buf, config->tx_buf_len); + + /* configure the uart */ + int divisor = 115200 / config->baud_rate; + + outp(config->io_port + 3, 0x80); // set up to load divisor latch + outp(config->io_port + 0, divisor & 0xff); // lsb + outp(config->io_port + 1, divisor >> 8); // msb + outp(config->io_port + 3, 3); // 8N1 + outp(config->io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold + + register_int_handler(config->irq, uart_irq_handler, dev); + unmask_interrupt(config->irq); + + //outp(config->io_port + 1, 0x3); // enable rx data available and tx holding empty interrupts + outp(config->io_port + 1, 0x1); // enable rx data available interrupts + + thread_resume(thread_create("[uart writer]", uart_write_thread, dev, DEFAULT_PRIORITY, + DEFAULT_STACK_SIZE)); + +done: + return res; +} + +static enum handler_return uart_irq_handler(void *arg) +{ + bool resched = false; + struct device *dev = arg; + + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->config); + DEBUG_ASSERT(dev->state); + + const struct platform_uart_config *config = dev->config; + struct uart_driver_state *state = dev->state; + + while (inp(config->io_port + 5) & (1<<0)) { + char c = inp(config->io_port + 0); + cbuf_write(&state->rx_buf, &c, 1, false); + resched = true; + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +static int uart_write_thread(void *arg) +{ + struct device *dev = arg; + + DEBUG_ASSERT(dev); + DEBUG_ASSERT(dev->config); + DEBUG_ASSERT(dev->state); + + const struct platform_uart_config *config = dev->config; + struct uart_driver_state *state = dev->state; + + return 0; + + while (true) { + char c = cbuf_read(&state->tx_buf, &c, 1, true); + + while ((inp(config->io_port + 5) & (1<<6)) == 0) + ; + + outp(config->io_port + 0, c); + } + + return 0; +} + +static ssize_t uart_read(struct device *dev, void *buf, size_t len) +{ + if (!dev || !buf) + return ERR_INVALID_ARGS; + + DEBUG_ASSERT(dev->state); + struct uart_driver_state *state = dev->state; + + return cbuf_read(&state->rx_buf, buf, len, true); +} + +static ssize_t uart_write(struct device *dev, const void *buf, size_t len) +{ + if (!dev || !buf) + return ERR_INVALID_ARGS; + + DEBUG_ASSERT(dev->state); + struct uart_driver_state *state = dev->state; + + return cbuf_write(&state->tx_buf, buf, len, true); +} + diff --git a/kernel/platform/power.c b/kernel/platform/power.c new file mode 100644 index 000000000..dcd440391 --- /dev/null +++ b/kernel/platform/power.c @@ -0,0 +1,62 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Google, Inc. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * default implementations of these routines, if the platform code + * chooses not to implement. + */ +__WEAK void platform_halt(platform_halt_action suggested_action, + platform_halt_reason reason) +{ +#if ENABLE_PANIC_SHELL + + if (reason == HALT_REASON_SW_PANIC) { + dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); + arch_disable_ints(); + panic_shell_start(); + } + +#endif // ENABLE_PANIC_SHELL + + dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); + arch_disable_ints(); + for (;;); +} + +#if WITH_LIB_CONSOLE + +#include + +static int cmd_reboot(int argc, const cmd_args *argv) +{ + platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET); + return 0; +} + +static int cmd_poweroff(int argc, const cmd_args *argv) +{ + platform_halt(HALT_ACTION_SHUTDOWN, HALT_REASON_SW_RESET); + return 0; +} + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND("reboot", "soft reset", &cmd_reboot) +STATIC_COMMAND("poweroff", "powerdown", &cmd_poweroff) +#endif +STATIC_COMMAND_END(platform_power); + +#endif diff --git a/kernel/platform/qemu-virt/BUILD.gn b/kernel/platform/qemu-virt/BUILD.gn new file mode 100644 index 000000000..276ef0c37 --- /dev/null +++ b/kernel/platform/qemu-virt/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "arm" || target_cpu == "arm64") + +import("//gnbuild/config.gni") + +config("_qemu-virt_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("qemu-virt") { + public_configs = [ ":_qemu-virt_config" ] + include_dirs = [ "//kernel/target/qemu-virt/include" ] + defines = kernel_defines + public = [ + "include/platform/gic.h", + "include/platform/qemu-virt.h", + ] + sources = [ + "debug.c", + "platform.c", + "platform_p.h", + "secondary_boot.S", + "uart.c", + ] + deps = [ + "//kernel/dev/interrupt/arm_gic", + "//kernel/dev/interrupt/arm_gicv2m", + "//kernel/dev/timer/arm_generic", + "//kernel/dev/virtio/", + "//kernel/dev/virtio/block", + "//kernel/dev/virtio/gpu", + "//kernel/dev/virtio/rng", + "//kernel/lib/cbuf", + "//kernel/lib/libc", + "//third_party/lib/fdt", + ] + if (enable_pcie) { + deps += [ "//kernel/dev/pcie" ] + } +} diff --git a/kernel/platform/qemu-virt/debug.c b/kernel/platform/qemu-virt/debug.c new file mode 100644 index 000000000..b9b33539b --- /dev/null +++ b/kernel/platform/qemu-virt/debug.c @@ -0,0 +1,58 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* DEBUG_UART must be defined to 0 or 1 */ +#if defined(DEBUG_UART) && DEBUG_UART == 0 +#define DEBUG_UART_BASE UART0_BASE +#elif defined(DEBUG_UART) && DEBUG_UART == 1 +#define DEBUG_UART_BASE UART1_BASE +#else +#error define DEBUG_UART to something valid +#endif + +void platform_dputc(char c) +{ + if (c == '\n') + uart_putc(DEBUG_UART, '\r'); + uart_putc(DEBUG_UART, c); +} + +int platform_dgetc(char *c, bool wait) +{ + int ret = uart_getc(DEBUG_UART, wait); + if (ret == -1) + return -1; + *c = ret; + return 0; +} + +void platform_pputc(char c) +{ + if (c == '\n') + uart_pputc(DEBUG_UART, '\r'); + uart_pputc(DEBUG_UART, c); +} + +int platform_pgetc(char *c, bool wait) +{ + int ret = uart_pgetc(DEBUG_UART); + if (ret < 0) + return ret; + *c = ret; + return 0; +} + diff --git a/kernel/platform/qemu-virt/include/platform/gic.h b/kernel/platform/qemu-virt/include/platform/gic.h new file mode 100644 index 000000000..cd48abec2 --- /dev/null +++ b/kernel/platform/qemu-virt/include/platform/gic.h @@ -0,0 +1,15 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#include + +#define GICBASE(n) (CPUPRIV_BASE_VIRT) +#define GICD_OFFSET (0x00000) +#define GICC_OFFSET (0x10000) + diff --git a/kernel/platform/qemu-virt/include/platform/qemu-virt.h b/kernel/platform/qemu-virt/include/platform/qemu-virt.h new file mode 100644 index 000000000..989d8ba19 --- /dev/null +++ b/kernel/platform/qemu-virt/include/platform/qemu-virt.h @@ -0,0 +1,91 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +/* up to 30 GB of ram */ +#define MEMORY_BASE_PHYS (0x40000000) +#if ARCH_ARM64 +#define MEMORY_APERTURE_SIZE (30ULL * 1024 * 1024 * 1024) +#else +#define MEMORY_APERTURE_SIZE (1UL * 1024 * 1024 * 1024) +#endif + +/* memory map of peripherals, from qemu hw/arm/virt.c */ +#if 0 +static const MemMapEntry a15memmap[] = { + /* Space up to 0x8000000 is reserved for a boot ROM */ + [VIRT_FLASH] = { 0, 0x08000000 }, + [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 }, + /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ + [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, + [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, + [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, + [VIRT_UART] = { 0x09000000, 0x00001000 }, + [VIRT_RTC] = { 0x09010000, 0x00001000 }, + [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, + [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, + /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ + [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, + [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 }, + [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 }, + [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 }, + [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, +}; + +static const int a15irqmap[] = { + [VIRT_UART] = 1, + [VIRT_RTC] = 2, + [VIRT_PCIE] = 3, /* ... to 6 */ + [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ + [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ + [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ +}; +#endif + +/* map all of 0-1GB into kernel space in one shot */ +#define PERIPHERAL_BASE_PHYS (0) +#define PERIPHERAL_BASE_SIZE (0x40000000UL) // 1GB + +#if ARCH_ARM64 +#define PERIPHERAL_BASE_VIRT (0xffffffffc0000000ULL) // -1GB +#else +#define PERIPHERAL_BASE_VIRT (0xc0000000UL) // -1GB +#endif + +/* individual peripherals in this mapping */ +#define CPUPRIV_BASE_VIRT (PERIPHERAL_BASE_VIRT + 0x08000000) +#define CPUPRIV_BASE_PHYS (PERIPHERAL_BASE_PHYS + 0x08000000) +#define CPUPRIV_SIZE (0x00020000) +#define UART_BASE (PERIPHERAL_BASE_VIRT + 0x09000000) +#define UART_SIZE (0x00001000) +#define RTC_BASE (PERIPHERAL_BASE_VIRT + 0x09010000) +#define RTC_SIZE (0x00001000) +#define FW_CFG_BASE (PERIPHERAL_BASE_VIRT + 0x09020000) +#define FW_CFG_SIZE (0x00001000) +#define NUM_VIRTIO_TRANSPORTS 32 +#define VIRTIO_BASE (PERIPHERAL_BASE_VIRT + 0x0a000000) +#define VIRTIO_SIZE (NUM_VIRTIO_TRANSPORTS * 0x200) +#define PCIE_MMIO_BASE_PHYS ((paddr_t)(PERIPHERAL_BASE_PHYS + 0x10000000)) +#define PCIE_MMIO_SIZE (0x2eff0000) +#define PCIE_PIO_BASE_PHYS ((paddr_t)(PERIPHERAL_BASE_PHYS + 0x3eff0000)) +#define PCIE_PIO_SIZE (0x00010000) +#define PCIE_ECAM_BASE_PHYS ((paddr_t)(PERIPHERAL_BASE_PHYS + 0x3f000000)) +#define PCIE_ECAM_SIZE (0x01000000) +#define GICV2M_FRAME_PHYS (PERIPHERAL_BASE_PHYS + 0x08020000) + + +/* interrupts */ +#define ARM_GENERIC_TIMER_VIRTUAL_INT 27 +#define ARM_GENERIC_TIMER_PHYSICAL_INT 30 +#define UART0_INT (32 + 1) +#define PCIE_INT_BASE (32 + 3) +#define PCIE_INT_COUNT (4) +#define VIRTIO0_INT (32 + 16) + +#define MAX_INT 128 + diff --git a/kernel/platform/qemu-virt/platform.c b/kernel/platform/qemu-virt/platform.c new file mode 100644 index 000000000..a752b4299 --- /dev/null +++ b/kernel/platform/qemu-virt/platform.c @@ -0,0 +1,192 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "platform_p.h" + +#define DEFAULT_MEMORY_SIZE (MEMSIZE) /* try to fetch from the emulator via the fdt */ + +static const pcie_ecam_range_t PCIE_ECAM_WINDOWS[] = { + { + .io_range = { .bus_addr = PCIE_ECAM_BASE_PHYS, .size = PCIE_ECAM_SIZE }, + .bus_start = 0x00, + .bus_end = (uint8_t)(PCIE_ECAM_SIZE / PCIE_ECAM_BYTE_PER_BUS) - 1, + }, +}; + +static const paddr_t GICV2M_REG_FRAMES[] = { GICV2M_FRAME_PHYS }; + +static status_t qemu_pcie_irq_swizzle(const pcie_common_state_t* common, + uint pin, + uint *irq) +{ + DEBUG_ASSERT(common && irq); + DEBUG_ASSERT(pin < PCIE_MAX_LEGACY_IRQ_PINS); + + if (common->bus_id != 0) + return ERR_NOT_FOUND; + + *irq = PCIE_INT_BASE + ((pin + common->dev_id) % PCIE_MAX_LEGACY_IRQ_PINS); + return NO_ERROR; +} + +static pcie_init_info_t PCIE_INIT_INFO = { + .ecam_windows = PCIE_ECAM_WINDOWS, + .ecam_window_count = countof(PCIE_ECAM_WINDOWS), + .mmio_window_lo = { .bus_addr = PCIE_MMIO_BASE_PHYS, .size = PCIE_MMIO_SIZE }, + .mmio_window_hi = { .bus_addr = 0, .size = 0 }, + .pio_window = { .bus_addr = PCIE_PIO_BASE_PHYS, .size = PCIE_PIO_SIZE }, + .legacy_irq_swizzle = qemu_pcie_irq_swizzle, + .alloc_msi_block = arm_gicv2m_alloc_msi_block, + .free_msi_block = arm_gicv2m_free_msi_block, + .register_msi_handler = arm_gicv2m_register_msi_handler, + .mask_unmask_msi = arm_gicv2m_mask_unmask_msi, +}; + +/* initial memory mappings. parsed by start.S */ +struct mmu_initial_mapping mmu_initial_mappings[] = { + /* all of memory */ + { + .phys = MEMORY_BASE_PHYS, + .virt = KERNEL_BASE, + .size = MEMORY_APERTURE_SIZE, + .flags = 0, + .name = "memory" + }, + + /* 1GB of peripherals */ + { + .phys = PERIPHERAL_BASE_PHYS, + .virt = PERIPHERAL_BASE_VIRT, + .size = PERIPHERAL_BASE_SIZE, + .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE, + .name = "peripherals" + }, + + /* null entry to terminate the list */ + { 0 } +}; + +static pmm_arena_t arena = { + .name = "ram", + .base = MEMORY_BASE_PHYS, + .size = DEFAULT_MEMORY_SIZE, + .flags = PMM_ARENA_FLAG_KMAP, +}; + +extern void psci_call(ulong arg0, ulong arg1, ulong arg2, ulong arg3); + +void platform_early_init(void) +{ + /* initialize the interrupt controller */ + arm_gicv2m_init(GICV2M_REG_FRAMES, countof(GICV2M_REG_FRAMES)); + + arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 0); + + uart_init_early(); + + /* look for a flattened device tree just before the kernel */ + const void *fdt = (void *)KERNEL_BASE; + int err = fdt_check_header(fdt); + if (err >= 0) { + /* walk the nodes, looking for 'memory' */ + int depth = 0; + int offset = 0; + for (;;) { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0) + break; + + /* get the name */ + const char *name = fdt_get_name(fdt, offset, NULL); + if (!name) + continue; + + /* look for the 'memory' property */ + if (strcmp(name, "memory") == 0) { + int lenp; + const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); + if (prop_ptr && lenp == 0x10) { + /* we're looking at a memory descriptor */ + //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); + uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); + + /* trim size on certain platforms */ +#if ARCH_ARM + if (len > 1024*1024*1024U) { + len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ + printf("trimming memory to 1GB\n"); + } +#endif + + /* set the size in the pmm arena */ + arena.size = len; + } + } + } + } + + /* add the main memory arena */ + pmm_add_arena(&arena); + + /* reserve the first 64k of ram, which should be holding the fdt */ + pmm_alloc_range(MEMBASE, 0x10000 / PAGE_SIZE, NULL); + + /* boot the secondary cpus using the Power State Coordintion Interface */ + ulong psci_call_num = 0x84000000 + 3; /* SMC32 CPU_ON */ +#if ARCH_ARM64 + psci_call_num += 0x40000000; /* SMC64 */ +#endif + for (uint i = 1; i < SMP_MAX_CPUS; i++) { + psci_call(psci_call_num, i, MEMBASE + KERNEL_LOAD_OFFSET, 0); + } +} + +void platform_init(void) +{ + uart_init(); + + /* detect any virtio devices */ + uint virtio_irqs[NUM_VIRTIO_TRANSPORTS]; + for (int i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) { + virtio_irqs[i] = VIRTIO0_INT + i; + } + + virtio_mmio_detect((void *)VIRTIO_BASE, NUM_VIRTIO_TRANSPORTS, virtio_irqs); + + /* Initialize the MSI allocator */ + status_t ret = arm_gic2vm_msi_init(); + if (ret != NO_ERROR) { + TRACEF("Failed to initialize MSI allocator (ret = %d). PCI will be " + "restricted to legacy IRQ mode.\n", ret); + PCIE_INIT_INFO.alloc_msi_block = NULL; + PCIE_INIT_INFO.free_msi_block = NULL; + } + + /* Tell the PCIe subsystem where it can find its resources. */ + status_t status = pcie_init(&PCIE_INIT_INFO); + if (status != NO_ERROR) + TRACEF("Failed to initialize PCIe bus driver! (status = %d)\n", status); +} diff --git a/kernel/platform/qemu-virt/platform_p.h b/kernel/platform/qemu-virt/platform_p.h new file mode 100644 index 000000000..02647aeac --- /dev/null +++ b/kernel/platform/qemu-virt/platform_p.h @@ -0,0 +1,14 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef __PLATFORM_P_H +#define __PLATFORM_P_H + +void platform_init_timer(void); + +#endif + diff --git a/kernel/platform/qemu-virt/rules.mk b/kernel/platform/qemu-virt/rules.mk new file mode 100644 index 000000000..0ed318c80 --- /dev/null +++ b/kernel/platform/qemu-virt/rules.mk @@ -0,0 +1,55 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +ifeq ($(ARCH),) +ARCH := arm64 +endif +ifeq ($(ARCH),arm64) +ARM_CPU ?= cortex-a53 +endif +ifeq ($(ARCH),arm) +ARM_CPU ?= cortex-a15 +endif +WITH_SMP ?= 1 + +LK_HEAP_IMPLEMENTATION ?= cmpctmalloc + +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/platform.c \ + $(LOCAL_DIR)/secondary_boot.S \ + $(LOCAL_DIR)/uart.c + +MEMBASE := 0x40000000 +MEMSIZE ?= 0x08000000 # 512MB +KERNEL_LOAD_OFFSET := 0x10000 # 64k + +MODULE_DEPS += \ + lib/cbuf \ + lib/fdt \ + dev/pcie \ + dev/timer/arm_generic \ + dev/interrupt/arm_gicv2m \ + dev/virtio/block \ + dev/virtio/gpu \ + dev/virtio/rng \ + +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) \ + PLATFORM_SUPPORTS_PANIC_SHELL=1 + +GLOBAL_DEFINES += MMU_WITH_TRAMPOLINE=1 \ + +LINKER_SCRIPT += \ + $(BUILDDIR)/system-onesegment.ld + +include make/module.mk diff --git a/kernel/platform/qemu-virt/secondary_boot.S b/kernel/platform/qemu-virt/secondary_boot.S new file mode 100644 index 000000000..c6a22f76d --- /dev/null +++ b/kernel/platform/qemu-virt/secondary_boot.S @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include + +.section .text + +/* used to call into PSCI firmware (Power State Coordination Firmware) */ +FUNCTION(psci_call) + hvc #0 +#if ARCH_ARM + bx lr +#else + ret +#endif + +.ltorg + diff --git a/kernel/platform/qemu-virt/uart.c b/kernel/platform/qemu-virt/uart.c new file mode 100644 index 000000000..1086835af --- /dev/null +++ b/kernel/platform/qemu-virt/uart.c @@ -0,0 +1,175 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +/* PL011 implementation */ +#define UART_DR (0x00) +#define UART_RSR (0x04) +#define UART_TFR (0x18) +#define UART_ILPR (0x20) +#define UART_IBRD (0x24) +#define UART_FBRD (0x28) +#define UART_LCRH (0x2c) +#define UART_CR (0x30) +#define UART_IFLS (0x34) +#define UART_IMSC (0x38) +#define UART_TRIS (0x3c) +#define UART_TMIS (0x40) +#define UART_ICR (0x44) +#define UART_DMACR (0x48) + +#define UARTREG(base, reg) (*REG32((base) + (reg))) + +#define RXBUF_SIZE 16 +#define NUM_UART 1 + +static cbuf_t uart_rx_buf[NUM_UART]; + +static inline uintptr_t uart_to_ptr(unsigned int n) +{ + switch (n) { + default: + case 0: + return UART_BASE; + } +} + +static enum handler_return uart_irq(void *arg) +{ + bool resched = false; + uint port = (uintptr_t)arg; + uintptr_t base = uart_to_ptr(port); + + /* read interrupt status and mask */ + uint32_t isr = UARTREG(base, UART_TMIS); + + if (isr & (1<<4)) { // rxmis + cbuf_t *rxbuf = &uart_rx_buf[port]; + + /* while fifo is not empty, read chars out of it */ + while ((UARTREG(base, UART_TFR) & (1<<4)) == 0) { + /* if we're out of rx buffer, mask the irq instead of handling it */ + if (cbuf_space_avail(rxbuf) == 0) { + UARTREG(base, UART_IMSC) &= ~(1<<4); // !rxim + break; + } + + char c = UARTREG(base, UART_DR); + cbuf_write_char(rxbuf, c, false); + + resched = true; + } + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +void uart_init(void) +{ + for (size_t i = 0; i < NUM_UART; i++) { + uintptr_t base = uart_to_ptr(i); + + // create circular buffer to hold received data + cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE); + + // assumes interrupts are contiguous + register_int_handler(UART0_INT + i, &uart_irq, (void *)i); + + // clear all irqs + UARTREG(base, UART_ICR) = 0x3ff; + + // set fifo trigger level + UARTREG(base, UART_IFLS) = 0; // 1/8 rxfifo, 1/8 txfifo + + // enable rx interrupt + UARTREG(base, UART_IMSC) = (1<<4); // rxim + + // enable receive + UARTREG(base, UART_CR) |= (1<<9); // rxen + + // enable interrupt + unmask_interrupt(UART0_INT + i); + } +} + +void uart_init_early(void) +{ + for (size_t i = 0; i < NUM_UART; i++) { + UARTREG(uart_to_ptr(i), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten + } +} + +int uart_putc(int port, char c) +{ + uintptr_t base = uart_to_ptr(port); + + /* spin while fifo is full */ + while (UARTREG(base, UART_TFR) & (1<<5)) + ; + UARTREG(base, UART_DR) = c; + + return 1; +} + +int uart_getc(int port, bool wait) +{ + cbuf_t *rxbuf = &uart_rx_buf[port]; + + char c; + if (cbuf_read_char(rxbuf, &c, wait) == 1) { + UARTREG(uart_to_ptr(port), UART_IMSC) = (1<<4); // rxim + return c; + } + + return -1; +} + +/* panic-time getc/putc */ +int uart_pputc(int port, char c) +{ + uintptr_t base = uart_to_ptr(port); + + /* spin while fifo is full */ + while (UARTREG(base, UART_TFR) & (1<<5)) + ; + UARTREG(base, UART_DR) = c; + + return 1; +} + +int uart_pgetc(int port, bool wait) +{ + uintptr_t base = uart_to_ptr(port); + + if ((UARTREG(base, UART_TFR) & (1<<4)) == 0) { + return UARTREG(base, UART_DR); + } else { + return -1; + } +} + + +void uart_flush_tx(int port) +{ +} + +void uart_flush_rx(int port) +{ +} + +void uart_init_port(int port, uint baud) +{ +} + diff --git a/kernel/platform/rules.mk b/kernel/platform/rules.mk new file mode 100644 index 000000000..7f56d4624 --- /dev/null +++ b/kernel/platform/rules.mk @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +# shared platform code +MODULE_SRCS += \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/init.c \ + $(LOCAL_DIR)/power.c + +include make/module.mk + + diff --git a/kernel/project/BUILD.gn b/kernel/project/BUILD.gn new file mode 100644 index 000000000..186a5cf16 --- /dev/null +++ b/kernel/project/BUILD.gn @@ -0,0 +1,43 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +if (target_cpu == "arm") { + group("qemu-arm32") { + deps = [ + "//kernel/project/target:qemu-virt-a15", + "//kernel/project/virtual:test", + "//kernel/project/virtual:user", + ] + } +} + +if (target_cpu == "arm64") { + group("qemu-arm64") { + deps = [ + "//kernel/project/target:qemu-virt-a53", + "//kernel/project/virtual:test", + "//kernel/project/virtual:user", + ] + } +} + +if (target_cpu == "x64") { + group("qemu-x86-64") { + deps = [ + "//kernel/project/target:pc-x86", + "//kernel/project/virtual:test", + "//kernel/project/virtual:user", + ] + } + + group("pc-x86-64") { + deps = [ + "//kernel/project/target:pc-uefi", + "//kernel/project/virtual:test", + "//kernel/project/virtual:user", + ] + } +} diff --git a/kernel/project/magenta-pc-uefi.mk b/kernel/project/magenta-pc-uefi.mk new file mode 100644 index 000000000..7ea94afc4 --- /dev/null +++ b/kernel/project/magenta-pc-uefi.mk @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +SUBARCH := x86-64 +MODULES += + +# we're going to need to put the user cpio archive in the kernel binary directly +EMBED_USER_BOOTFS:=true + +include project/virtual/test.mk +include project/virtual/user.mk +include project/target/pc-uefi.mk diff --git a/kernel/project/magenta-qemu-arm32.mk b/kernel/project/magenta-qemu-arm32.mk new file mode 100644 index 000000000..df6799641 --- /dev/null +++ b/kernel/project/magenta-qemu-arm32.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Project file to build magenta + user space on top of qemu +# for 32bit arm (cortex-a15) + +EMBED_USER_BOOTFS:=true + +MODULES += + +include project/virtual/test.mk +include project/virtual/user.mk +include project/target/qemu-virt-a15.mk + diff --git a/kernel/project/magenta-qemu-arm64.mk b/kernel/project/magenta-qemu-arm64.mk new file mode 100644 index 000000000..6b44678d8 --- /dev/null +++ b/kernel/project/magenta-qemu-arm64.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Project file to build magenta + user space on top of qemu +# for 64bit arm (cortex-a53) + +EMBED_USER_BOOTFS:=true + +MODULES += + +include project/virtual/test.mk +include project/virtual/user.mk +include project/target/qemu-virt-a53.mk + diff --git a/kernel/project/magenta-qemu-x86-64.mk b/kernel/project/magenta-qemu-x86-64.mk new file mode 100644 index 000000000..9690cff0f --- /dev/null +++ b/kernel/project/magenta-qemu-x86-64.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# Project file to build magenta + user space on top of qemu +# emulating a standard PC with a 64bit x86 core + +SUBARCH := x86-64 +MODULES += + +# we're going to need to put the user cpio archive in the kernel binary directly +EMBED_USER_BOOTFS:=true + +include project/virtual/test.mk +include project/virtual/user.mk +include project/target/pc-x86.mk diff --git a/kernel/project/pc-x86-64-test.mk b/kernel/project/pc-x86-64-test.mk new file mode 100644 index 000000000..e63c82f0a --- /dev/null +++ b/kernel/project/pc-x86-64-test.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# top level project rules for the pc-x86-64-test project +# +SUBARCH := x86-64 +MODULES += + +include project/virtual/nouser.mk +include project/virtual/test.mk +include project/target/pc-x86.mk diff --git a/kernel/project/pc-x86-test.mk b/kernel/project/pc-x86-test.mk new file mode 100644 index 000000000..38bc6f6e8 --- /dev/null +++ b/kernel/project/pc-x86-test.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# top level project rules for the pc-x86-test project +# +SUBARCH := x86-32 +MODULES += + +include project/virtual/nouser.mk +include project/virtual/test.mk +include project/target/pc-x86.mk diff --git a/kernel/project/qemu-virt-a15-test.mk b/kernel/project/qemu-virt-a15-test.mk new file mode 100644 index 000000000..b1a0f80bb --- /dev/null +++ b/kernel/project/qemu-virt-a15-test.mk @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# main project for qemu-arm32 +MODULES += + +include project/virtual/nouser.mk +include project/virtual/test.mk +include project/target/qemu-virt-a15.mk + diff --git a/kernel/project/qemu-virt-a53-test.mk b/kernel/project/qemu-virt-a53-test.mk new file mode 100644 index 000000000..ac4c66d4a --- /dev/null +++ b/kernel/project/qemu-virt-a53-test.mk @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# main project for qemu-aarch64 +MODULES += + +include project/virtual/nouser.mk +include project/virtual/test.mk +include project/target/qemu-virt-a53.mk + diff --git a/kernel/project/target/BUILD.gn b/kernel/project/target/BUILD.gn new file mode 100644 index 000000000..c4d1fe6ab --- /dev/null +++ b/kernel/project/target/BUILD.gn @@ -0,0 +1,48 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +group("qemu-virt") { + deps = [ + "//kernel/dev/intel_hda", + ] +} + +if (target_cpu == "arm") { + group("qemu-virt-a15") { + deps = [ + ":qemu-virt", + "//kernel/platform/qemu-virt", + "//kernel/target/qemu-virt", + ] + } +} + +if (target_cpu == "arm64") { + group("qemu-virt-a53") { + deps = [ + ":qemu-virt", + "//kernel/platform/qemu-virt", + "//kernel/target/qemu-virt", + ] + } +} + +if (target_cpu == "x64") { + group("pc-x86") { + deps = [ + ":qemu-virt", + "//kernel/platform/pc", + "//kernel/target/pc-x86", + ] + } + + group("pc-uefi") { + deps = [ + "//kernel/platform/pc", + "//kernel/target/pc-uefi", + ] + } +} diff --git a/kernel/project/target/pc-uefi.mk b/kernel/project/target/pc-uefi.mk new file mode 100644 index 000000000..6118805f2 --- /dev/null +++ b/kernel/project/target/pc-uefi.mk @@ -0,0 +1,10 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +ARCH := x86 +SUBARCH ?= x86-64 +TARGET := pc-uefi diff --git a/kernel/project/target/pc-x86.mk b/kernel/project/target/pc-x86.mk new file mode 100644 index 000000000..5893049b8 --- /dev/null +++ b/kernel/project/target/pc-x86.mk @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# top level project rules for the pc-x86 project +# +ARCH := x86 +SUBARCH ?= x86-32 +TARGET := pc-x86 + +MODULES += dev/intel_hda + +INTEL_HDA_QEMU_QUIRKS := 1 diff --git a/kernel/project/target/qemu-virt-a15.mk b/kernel/project/target/qemu-virt-a15.mk new file mode 100644 index 000000000..6af7dd2e9 --- /dev/null +++ b/kernel/project/target/qemu-virt-a15.mk @@ -0,0 +1,13 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# main project for qemu-arm32 +ARCH := arm +ARM_CPU := cortex-a15 + +include project/target/qemu-virt.mk + diff --git a/kernel/project/target/qemu-virt-a53.mk b/kernel/project/target/qemu-virt-a53.mk new file mode 100644 index 000000000..27336022a --- /dev/null +++ b/kernel/project/target/qemu-virt-a53.mk @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# main project for qemu-aarch64 +ARCH := arm64 +ARM_CPU := cortex-a53 + +include project/target/qemu-virt.mk + + diff --git a/kernel/project/target/qemu-virt.mk b/kernel/project/target/qemu-virt.mk new file mode 100644 index 000000000..94442a90a --- /dev/null +++ b/kernel/project/target/qemu-virt.mk @@ -0,0 +1,13 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# main project for qemu-virt +TARGET := qemu-virt + +MODULES += dev/intel_hda + +INTEL_HDA_QEMU_QUIRKS := 1 diff --git a/kernel/project/virtual/BUILD.gn b/kernel/project/virtual/BUILD.gn new file mode 100644 index 000000000..4a90652a4 --- /dev/null +++ b/kernel/project/virtual/BUILD.gn @@ -0,0 +1,115 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +import("//gnbuild/config.gni") +import("//gnbuild/compiled_action.gni") + +group("test") { + deps = [ + "//kernel/app/stringtests", + "//kernel/app/tests", + "//kernel/lib/debugcommands", + "//kernel/lib/version", + ] +} + +group("user") { + deps = [ + "//kernel/lib/syscalls", + "//kernel/lib/userboot", + ] + if (enable_debuglog) { + deps += [ "//kernel/lib/debuglog" ] + } +} + +template("mkbootfs") { + runtime_deps_file = "$target_gen_dir/$target_name.runtime_deps" + manifest_file = "$target_gen_dir/$target_name.manifest" + + group("${target_name}_write_deps") { + visibility = [ ":*" ] + forward_variables_from(invoker, + [ + "data", + "data_deps", + "deps", + "public_deps", + ]) + write_runtime_deps = runtime_deps_file + } + + action("${target_name}_generate_manifest") { + visibility = [ ":*" ] + script = "generate_manifest.sh" + inputs = [ + runtime_deps_file, + ] + outputs = [ + manifest_file, + ] + args = [ + rebase_path(runtime_deps_file, root_build_dir), + rebase_path(manifest_file, root_build_dir), + ] + deps = [ + ":${invoker.target_name}_write_deps", + ] + } + + compiled_action(target_name) { + tool = "//tools:mkbootfs" + + inputs = [ + manifest_file, + ] + outputs = [ + "$root_gen_dir/user.bootfs", + ] + args = [ + "-o", + rebase_path("$root_gen_dir/user.bootfs", root_build_dir), + ] + rebase_path(inputs, root_build_dir) + deps = [ + ":${target_name}_generate_manifest", + ] + } +} + +mkbootfs("bootfs") { + data_deps = [ + "//system/uapp/crasher", + "//system/uapp/devmgr", + "//system/uapp/dlog", + "//system/uapp/mxsh", + "//system/uapp/netsvc", + "//system/uapp/strerror", + "//system/uapp/userboot", + "//system/utest/arch-registers", + "//system/utest/bad-syscall", + "//system/utest/cleanup", + "//system/utest/dump1", + "//system/utest/echo", + "//system/utest/errno", + "//system/utest/events", + "//system/utest/evil", + "//system/utest/exceptions", + "//system/utest/fpu", + "//system/utest/futex", + "//system/utest/handle-transfer", + "//system/utest/message-pipe", + "//system/utest/mxr-mutex", + "//system/utest/mxr-thread", + "//system/utest/mxr-tls", + "//system/utest/process", + "//system/utest/pthread", + "//system/utest/reply-handle", + "//system/utest/thread-initial-state", + "//system/utest/thread-local-storage", + "//system/utest/threads", + "//system/utest/vmo", + ] +} diff --git a/kernel/project/virtual/generate_manifest.sh b/kernel/project/virtual/generate_manifest.sh new file mode 100644 index 000000000..e257bf4e7 --- /dev/null +++ b/kernel/project/virtual/generate_manifest.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +if [[ $# -lt 1 ]]; then + echo "Insufficient number of arguments" >&2 + exit 1 +fi + +readonly RUNTIME_DEPS="$1" +readonly DEFAULT_NAME="$(basename "${RUNTIME_DEPS}")" +readonly DEFAULT_MANIFEST="${DEFAULT_NAME%.*}.manifest" + +MANIFEST=() +while read file; do + path="bin/$(basename $file)" + MANIFEST+=("${path}=${file}") +done <${RUNTIME_DEPS} + +(IFS=$'\n'; echo "${MANIFEST[*]}" >${2:-$DEFAULT_MANIFEST}) diff --git a/kernel/project/virtual/nouser.mk b/kernel/project/virtual/nouser.mk new file mode 100644 index 000000000..18b652242 --- /dev/null +++ b/kernel/project/virtual/nouser.mk @@ -0,0 +1,11 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# modules needed to implement user space + +MODULES += \ + app/shell diff --git a/kernel/project/virtual/test.mk b/kernel/project/virtual/test.mk new file mode 100644 index 000000000..8ba7ff765 --- /dev/null +++ b/kernel/project/virtual/test.mk @@ -0,0 +1,15 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# common libraries for -test variants + +MODULES += \ + app/stringtests \ + app/tests \ + lib/debugcommands \ + lib/version \ + diff --git a/kernel/project/virtual/user.mk b/kernel/project/virtual/user.mk new file mode 100644 index 000000000..e2e269be5 --- /dev/null +++ b/kernel/project/virtual/user.mk @@ -0,0 +1,50 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# modules needed to implement user space + +GLOBAL_DEFINES += WITH_DEBUG_LINEBUFFER=1 + +MODULES += \ + ulib/musl \ + lib/syscalls \ + lib/userboot \ + lib/debuglog \ + uapp/crasher \ + uapp/devmgr \ + uapp/i2c \ + uapp/mxsh \ + uapp/strerror \ + uapp/userboot \ + uapp/dlog \ + uapp/netsvc \ + ulib/magenta \ + ulib/mojo \ + ulib/mxio \ + ulib/inet6 \ + utest \ + +# if we're not embedding the bootfs, build a standalone image +ifneq ($(EMBED_USER_BOOTFS),true) +EXTRA_BUILDDEPS += $(USER_FS) +endif + +EXTRA_BUILDDEPS += $(USER_BOOTFS) + +MKBOOTFS := $(BUILDDIR)/tools/mkbootfs + +$(MKBOOTFS): tools/mkbootfs.c + @echo compiling $@ + @$(MKDIR) + cc -Wall -o $@ $< + +$(USER_BOOTFS): $(MKBOOTFS) $(USER_MANIFEST) + @echo generating $@ + @$(MKDIR) + $(NOECHO)$(MKBOOTFS) -o $(USER_BOOTFS) $(USER_MANIFEST) + +GENERATED += $(USER_BOOTFS) $(MKBOOTFS) $(USERBOOT_BIN) diff --git a/kernel/project/virtual/userdrv.mk b/kernel/project/virtual/userdrv.mk new file mode 100644 index 000000000..370eb7209 --- /dev/null +++ b/kernel/project/virtual/userdrv.mk @@ -0,0 +1,11 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# drivers in user space modules + +MODULES += \ + uapp/userirq diff --git a/kernel/target/BUILD.gn b/kernel/target/BUILD.gn new file mode 100644 index 000000000..25e3aec87 --- /dev/null +++ b/kernel/target/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("target") { + sources = [ + "init.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/kernel/target/init.c b/kernel/target/init.c new file mode 100644 index 000000000..4e6adb5eb --- /dev/null +++ b/kernel/target/init.c @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include + +/* + * default implementations of these routines, if the target code + * chooses not to implement. + */ + +__WEAK void target_early_init(void) +{ +} + +__WEAK void target_init(void) +{ +} + +__WEAK void target_set_led(unsigned int led, bool on) +{ +} + +__WEAK void target_quiesce(void) +{ +} + diff --git a/kernel/target/pc-uefi/BUILD.gn b/kernel/target/pc-uefi/BUILD.gn new file mode 100644 index 000000000..c95c8fc74 --- /dev/null +++ b/kernel/target/pc-uefi/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "x64") + +module("pc-uefi") { + sources = [ + "config.c", + "debug.c", + "pixel2_quirks.c", + ] + deps = [ + "//kernel/dev/broadwell_chipset_config", + "//kernel/dev/i915", + "//kernel/dev/pcie", + "//kernel/dev/thermal/intel_pch_thermal", + "//kernel/lib/libc", + "//third_party/lib/acpica", + ] +} diff --git a/kernel/target/pc-uefi/config.c b/kernel/target/pc-uefi/config.c new file mode 100644 index 000000000..5e931d0e5 --- /dev/null +++ b/kernel/target/pc-uefi/config.c @@ -0,0 +1,13 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include "target_p.h" + +void target_init(void) +{ + pc_uefi_debug_init(); +} + diff --git a/kernel/target/pc-uefi/debug.c b/kernel/target/pc-uefi/debug.c new file mode 100644 index 000000000..ca653f2c6 --- /dev/null +++ b/kernel/target/pc-uefi/debug.c @@ -0,0 +1,62 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#include +#include +#include +#include +#include +#include "target_p.h" + +/* declared in platform/pc/debug.c */ +extern enum handler_return platform_drain_debug_uart_rx(void); + +/* since the com1 IRQs do not work on pixel hardware, run a timer to poll for incoming + * characters. + */ +static timer_t uart_rx_poll_timer; + +static enum handler_return uart_rx_poll(struct timer *t, lk_time_t now, void *arg) +{ + return platform_drain_debug_uart_rx(); +} + +static ACPI_STATUS acpi_get_cros_ec_device( + ACPI_HANDLE object, + UINT32 nesting_level, + void *context, + void **ret) +{ + bool *has_cros_ec = context; + *has_cros_ec = true; + return AE_OK; +} + +bool has_cros_embedded_controller(void) +{ + bool has_cros_ec = false; + __UNUSED ACPI_STATUS status = AcpiGetDevices( + (char*)"GOOG0003", // CrOS EC PD + acpi_get_cros_ec_device, + &has_cros_ec, + NULL); + DEBUG_ASSERT(status == NO_ERROR); + return has_cros_ec; +} + +void pc_uefi_debug_init(void) +{ + /* The Pixel2 does not have the serial RX IRQ wired up for the debug UART. + * Try to detect if we're a Pixel2 by checking for a CrOS embedded + * controller so we can poll instead of waiting for RX interrupts. */ + if (has_cros_embedded_controller()) { + printf("Enabling Debug UART RX Hack\n"); + /* poll for input periodically in case rx interrupts are broken */ + timer_initialize(&uart_rx_poll_timer); + timer_set_periodic(&uart_rx_poll_timer, 10, uart_rx_poll, NULL); + } +} + diff --git a/kernel/target/pc-uefi/pixel2_quirks.c b/kernel/target/pc-uefi/pixel2_quirks.c new file mode 100644 index 000000000..b1577e7c7 --- /dev/null +++ b/kernel/target/pc-uefi/pixel2_quirks.c @@ -0,0 +1,63 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2016, Google, Inc. All rights reserved +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include + +extern bool has_cros_embedded_controller(void); + +static const struct { + bwcc_device_id_t dev_id; + const char* dev_name; +} DEVICES_TO_UNHIDE[] = { + { .dev_id = BWCC_DEV_SERIAL_DMA_IO, .dev_name = "Serial DMA" }, + { .dev_id = BWCC_DEV_I2C0, .dev_name = "I2C0" }, + { .dev_id = BWCC_DEV_SST, .dev_name = "Smart Sound DSP" }, +}; + +void pixel2_init_quirks(uint level) +{ + /* If we do not have a CrOS embedded controller, then this cannot be a pixel + * 2, so we should not try to un-hide these devices. */ + if (!has_cros_embedded_controller()) + return; + + status_t res = NO_ERROR; + for (size_t i = 0; i < countof(DEVICES_TO_UNHIDE); ++i) { + res = bwcc_disable_device(DEVICES_TO_UNHIDE[i].dev_id, false); + if (res != NO_ERROR) { + TRACEF("Failed to enable %s! (res = %d)\n", DEVICES_TO_UNHIDE[i].dev_name, res); + break; + } + + res = bwcc_hide_device(DEVICES_TO_UNHIDE[i].dev_id, false); + if (res != NO_ERROR) { + TRACEF("Failed to un-hide %s! (res = %d)\n", DEVICES_TO_UNHIDE[i].dev_name, res); + break; + } + } + + /* If something goes terribly wrong, do our best to hide and disable the + * devices we were trying to unhide. Otherwise, trigger a rescan of the + * PCIe bus in order to discover the devices we just un-hid */ + if (res != NO_ERROR) { + for (size_t i = 0; i < countof(DEVICES_TO_UNHIDE); ++i) { + bwcc_hide_device(DEVICES_TO_UNHIDE[i].dev_id, true); + bwcc_disable_device(DEVICES_TO_UNHIDE[i].dev_id, true); + } + } else { + pcie_rescan_bus(); + } +} + +LK_INIT_HOOK(pixel2_quirks, &pixel2_init_quirks, LK_INIT_LEVEL_TARGET + 10); + diff --git a/kernel/target/pc-uefi/rules.mk b/kernel/target/pc-uefi/rules.mk new file mode 100644 index 000000000..b6921becc --- /dev/null +++ b/kernel/target/pc-uefi/rules.mk @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +PLATFORM := pc + +MODULE_SRCS += \ + $(LOCAL_DIR)/config.c \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/pixel2_quirks.c + +MODULE_DEPS += \ + dev/broadwell_chipset_config \ + dev/i915 \ + dev/thermal/intel_pch_thermal + +include make/module.mk + diff --git a/kernel/target/pc-uefi/target_p.h b/kernel/target/pc-uefi/target_p.h new file mode 100644 index 000000000..73661b991 --- /dev/null +++ b/kernel/target/pc-uefi/target_p.h @@ -0,0 +1,9 @@ +// Copyright 2016 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +void pc_uefi_debug_init(void); diff --git a/kernel/target/pc-x86/BUILD.gn b/kernel/target/pc-x86/BUILD.gn new file mode 100644 index 000000000..06e4d9367 --- /dev/null +++ b/kernel/target/pc-x86/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "x64") + +module("pc-x86") { + sources = [ + "config.c", + ] + deps = [ + "//kernel/lib/libc", + "//kernel/platform/pc", + ] +} diff --git a/kernel/target/pc-x86/config.c b/kernel/target/pc-x86/config.c new file mode 100644 index 000000000..453ce73d0 --- /dev/null +++ b/kernel/target/pc-x86/config.c @@ -0,0 +1,44 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2012 Corey Tabaka +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +static const struct platform_uart_config uart0_config = { + .io_port = 0x3f8, + .irq = ISA_IRQ_SERIAL1, + .baud_rate = 115200, + .rx_buf_len = 1024, + .tx_buf_len = 1024, +}; + +DEVICE_INSTANCE(uart, uart0, &uart0_config); +#endif + +#ifndef ARCH_X86_64 +static const struct platform_ide_config ide0_config = { +}; + +DEVICE_INSTANCE(ide, ide0, &ide0_config); + +#endif + +void target_init(void) +{ + //device_init_all(); +} + diff --git a/kernel/target/pc-x86/rules.mk b/kernel/target/pc-x86/rules.mk new file mode 100644 index 000000000..22eb834b3 --- /dev/null +++ b/kernel/target/pc-x86/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# mostly null target configuration for pc-x86 +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +PLATFORM := pc + +MODULE_SRCS += \ + $(LOCAL_DIR)/config.c + +include make/module.mk + diff --git a/kernel/target/qemu-virt/BUILD.gn b/kernel/target/qemu-virt/BUILD.gn new file mode 100644 index 000000000..729c41a42 --- /dev/null +++ b/kernel/target/qemu-virt/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +assert(target_cpu == "arm" || target_cpu == "arm64") + +config("_qemu-virt_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +group("qemu-virt") { + public_configs = [ ":_qemu-virt_config" ] +} diff --git a/kernel/target/qemu-virt/include/target/debugconfig.h b/kernel/target/qemu-virt/include/target/debugconfig.h new file mode 100644 index 000000000..24727d97b --- /dev/null +++ b/kernel/target/qemu-virt/include/target/debugconfig.h @@ -0,0 +1,11 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2014 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#pragma once + +#define DEBUG_UART 0 + diff --git a/kernel/target/qemu-virt/rules.mk b/kernel/target/qemu-virt/rules.mk new file mode 100644 index 000000000..42b490963 --- /dev/null +++ b/kernel/target/qemu-virt/rules.mk @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +GLOBAL_INCLUDES += \ + $(LOCAL_DIR)/include + +PLATFORM := qemu-virt + +#include make/module.mk + diff --git a/kernel/target/rules.mk b/kernel/target/rules.mk new file mode 100644 index 000000000..127a57b77 --- /dev/null +++ b/kernel/target/rules.mk @@ -0,0 +1,16 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/init.c + +include make/module.mk + diff --git a/kernel/top/BUILD.gn b/kernel/top/BUILD.gn new file mode 100644 index 000000000..187a3f4d6 --- /dev/null +++ b/kernel/top/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +module("top") { + sources = [ + "init.c", + "main.c", + ] + deps = [ + "//kernel/app", + "//kernel/dev", + "//kernel/kernel", + "//kernel/lib/libc", + "//kernel/platform", + "//kernel/target", + ] +} diff --git a/kernel/top/init.c b/kernel/top/init.c new file mode 100644 index 000000000..31736db82 --- /dev/null +++ b/kernel/top/init.c @@ -0,0 +1,119 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/* + * Global init hook mechanism. Allows code anywhere in the system to define + * a init hook that is called at increasing init levels as the system is + * initialized. + */ +#include +#include + +#include +#include +#include +#include + +#define LOCAL_TRACE 0 +#define TRACE_INIT (LK_DEBUGLEVEL >= 2) +#ifndef EARLIEST_TRACE_LEVEL +#define EARLIEST_TRACE_LEVEL LK_INIT_LEVEL_TARGET_EARLY +#endif + +extern const struct lk_init_struct __start_lk_init[] __WEAK; +extern const struct lk_init_struct __stop_lk_init[] __WEAK; + +void lk_init_level(enum lk_init_flags required_flag, uint start_level, uint stop_level) +{ + LTRACEF("flags %#x, start_level %#x, stop_level %#x\n", + required_flag, start_level, stop_level); + + ASSERT(start_level > 0); + uint last_called_level = start_level - 1; + const struct lk_init_struct *last = NULL; + for (;;) { + /* search for the lowest uncalled hook to call */ + LTRACEF("last %p, last_called_level %#x\n", last, last_called_level); + + const struct lk_init_struct *found = NULL; + bool seen_last = false; + for (const struct lk_init_struct *ptr = __start_lk_init; ptr != __stop_lk_init; ptr++) { + LTRACEF("looking at %p (%s) level %#x, flags %#x, seen_last %d\n", ptr, ptr->name, ptr->level, ptr->flags, seen_last); + + if (ptr == last) + seen_last = true; + + /* reject the easy ones */ + if (!(ptr->flags & required_flag)) + continue; + if (ptr->level > stop_level) + continue; + if (ptr->level < last_called_level) + continue; + if (found && found->level <= ptr->level) + continue; + + /* keep the lowest one we haven't called yet */ + if (ptr->level >= start_level && ptr->level > last_called_level) { + found = ptr; + continue; + } + + /* if we're at the same level as the last one we called and we've + * already passed over it this time around, we can mark this one + * and early terminate the loop. + */ + if (ptr->level == last_called_level && ptr != last && seen_last) { + found = ptr; + break; + } + } + + if (!found) + break; + +#if TRACE_INIT + if (found->level >= EARLIEST_TRACE_LEVEL) { + printf("INIT: cpu %d, calling hook %p (%s) at level %#x, flags %#x\n", + arch_curr_cpu_num(), found->hook, found->name, found->level, found->flags); + } +#endif + found->hook(found->level); + last_called_level = found->level; + last = found; + } +} + +#if 0 +void test_hook(uint level) +{ + LTRACEF("level %#x\n", level); +} +void test_hook1(uint level) +{ + LTRACEF("level %#x\n", level); +} +void test_hook1a(uint level) +{ + LTRACEF("level %#x\n", level); +} +void test_hook1b(uint level) +{ + LTRACEF("level %#x\n", level); +} +void test_hook2(uint level) +{ + LTRACEF("level %#x\n", level); +} + +LK_INIT_HOOK(test, test_hook, 1); +LK_INIT_HOOK(test1, test_hook1, 1); +LK_INIT_HOOK(test2, test_hook2, 2); +LK_INIT_HOOK(test1a, test_hook1a, 1); +LK_INIT_HOOK(test1b, test_hook1b, 1); +#endif diff --git a/kernel/top/main.c b/kernel/top/main.c new file mode 100644 index 000000000..a5355dacc --- /dev/null +++ b/kernel/top/main.c @@ -0,0 +1,186 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2013-2015 Travis Geiselbrecht +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + + +/* + * Main entry point to the OS. Initializes modules in order and creates + * the default thread. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* saved boot arguments from whoever loaded the system */ +ulong lk_boot_args[4]; + +extern void *__ctor_list; +extern void *__ctor_end; +extern int __bss_start; +extern int _end; + +#if WITH_SMP +static thread_t *secondary_bootstrap_threads[SMP_MAX_CPUS - 1]; +static uint secondary_bootstrap_thread_count; +#endif + +static int bootstrap2(void *arg); + +extern void kernel_init(void); + +static void call_constructors(void) +{ + void **ctor; + + ctor = &__ctor_list; + while (ctor != &__ctor_end) { + void (*func)(void); + + func = (void ( *)(void))*ctor; + + func(); + ctor++; + } +} + +/* called from arch code */ +void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3) +{ + // save the boot args + lk_boot_args[0] = arg0; + lk_boot_args[1] = arg1; + lk_boot_args[2] = arg2; + lk_boot_args[3] = arg3; + + // get us into some sort of thread context + thread_init_early(); + + // early arch stuff + lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1); + arch_early_init(); + + // do any super early platform initialization + lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1); + platform_early_init(); + + // do any super early target initialization + lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1); + target_early_init(); + +#if WITH_SMP + dprintf(INFO, "\nwelcome to lk/MP\n\n"); +#else + dprintf(INFO, "\nwelcome to lk\n\n"); +#endif + dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n", + lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]); + + // bring up the kernel heap + lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1); + dprintf(SPEW, "initializing heap\n"); + heap_init(); + + // deal with any static constructors + dprintf(SPEW, "calling constructors\n"); + call_constructors(); + + // initialize the kernel + lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_KERNEL - 1); + kernel_init(); + + lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1); + + // create a thread to complete system initialization + dprintf(SPEW, "creating bootstrap completion thread\n"); + thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + thread_set_pinned_cpu(t, 0); + thread_detach(t); + thread_resume(t); + + // become the idle thread and enable interrupts to start the scheduler + thread_become_idle(); +} + +static int bootstrap2(void *arg) +{ + dprintf(SPEW, "top of bootstrap2()\n"); + + lk_primary_cpu_init_level(LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_ARCH - 1); + arch_init(); + + // initialize the rest of the platform + dprintf(SPEW, "initializing platform\n"); + lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH, LK_INIT_LEVEL_PLATFORM - 1); + platform_init(); + + // initialize the target + dprintf(SPEW, "initializing target\n"); + lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM, LK_INIT_LEVEL_TARGET - 1); + target_init(); + + dprintf(SPEW, "calling apps_init()\n"); + lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET, LK_INIT_LEVEL_APPS - 1); + apps_init(); + + lk_primary_cpu_init_level(LK_INIT_LEVEL_APPS, LK_INIT_LEVEL_LAST); + + return 0; +} + +#if WITH_SMP +void lk_secondary_cpu_entry(void) +{ + uint cpu = arch_curr_cpu_num(); + + if (cpu > secondary_bootstrap_thread_count) { + dprintf(CRITICAL, "Invalid secondary cpu num %d, SMP_MAX_CPUS %d, secondary_bootstrap_thread_count %d\n", + cpu, SMP_MAX_CPUS, secondary_bootstrap_thread_count); + return; + } + + thread_secondary_cpu_init_early(); + thread_resume(secondary_bootstrap_threads[cpu - 1]); + + dprintf(SPEW, "entering scheduler on cpu %d\n", cpu); + thread_secondary_cpu_entry(); +} + +static int secondary_cpu_bootstrap2(void *arg) +{ + /* secondary cpu initialize from threading level up. 0 to threading was handled in arch */ + lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_LAST); + + return 0; +} + +void lk_init_secondary_cpus(uint secondary_cpu_count) +{ + if (secondary_cpu_count >= SMP_MAX_CPUS) { + dprintf(CRITICAL, "Invalid secondary_cpu_count %d, SMP_MAX_CPUS %d\n", + secondary_cpu_count, SMP_MAX_CPUS); + secondary_cpu_count = SMP_MAX_CPUS - 1; + } + for (uint i = 0; i < secondary_cpu_count; i++) { + dprintf(SPEW, "creating bootstrap completion thread for cpu %d\n", i + 1); + thread_t *t = thread_create("secondarybootstrap2", + &secondary_cpu_bootstrap2, NULL, + DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); + t->pinned_cpu = i + 1; + thread_detach(t); + secondary_bootstrap_threads[i] = t; + } + secondary_bootstrap_thread_count = secondary_cpu_count; +} +#endif diff --git a/kernel/top/rules.mk b/kernel/top/rules.mk new file mode 100644 index 000000000..e998dab2a --- /dev/null +++ b/kernel/top/rules.mk @@ -0,0 +1,23 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_DEPS := \ + platform \ + target \ + app \ + dev \ + kernel + +MODULE_SRCS := \ + $(LOCAL_DIR)/init.c \ + $(LOCAL_DIR)/main.c \ + +include make/module.mk diff --git a/makefile b/makefile new file mode 100644 index 000000000..31dccd02a --- /dev/null +++ b/makefile @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008-2015 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +LKMAKEROOT := . +LKROOT := kernel +LKINC := system third_party +BUILDROOT := . +DEFAULT_PROJECT ?= magenta-qemu-x86-64 +TOOLCHAIN_PREFIX ?= + +# check if LKROOT is already a part of LKINC list and add it only if it is not +ifneq ($(findstring $(LKROOT),$(LKINC)), $(LKROOT)) +LKINC := $(LKROOT) $(LKINC) +endif + +export LKMAKEROOT +export LKROOT +export LKINC +export BUILDROOT +export DEFAULT_PROJECT +export TOOLCHAIN_PREFIX + +# vaneer makefile that calls into the engine with lk as the build root +# if we're the top level invocation, call ourselves with additional args +$(MAKECMDGOALS) _top: + @$(MAKE) -C $(LKMAKEROOT) -rR -f $(LKROOT)/engine.mk $(addprefix -I,$(LKINC)) $(MAKECMDGOALS) + +.PHONY: _top diff --git a/scripts/LICENSE b/scripts/LICENSE new file mode 100644 index 000000000..66b16788c --- /dev/null +++ b/scripts/LICENSE @@ -0,0 +1,21 @@ +Copyright 2016 The Fuchsia Authors +Copyright (c) 2008 Travis Geiselbrecht + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/scripts/build-all-magenta b/scripts/build-all-magenta new file mode 100755 index 000000000..f8c5148ea --- /dev/null +++ b/scripts/build-all-magenta @@ -0,0 +1,23 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# build all magenta projects in the project directory +PROJECTS=`echo kernel/project/magenta*.mk | xargs -n1 basename | sed 's/\.mk//'` +FAILED="" + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +for p in $PROJECTS; do + nice $DIR/make-parallel $p || FAILED="$FAILED $p" +done + +if [ "$FAILED" != "" ]; then + echo + echo some projects have failed to build: + echo $FAILED +fi diff --git a/scripts/build-magenta-arm32 b/scripts/build-magenta-arm32 new file mode 100755 index 000000000..24cfdc50f --- /dev/null +++ b/scripts/build-magenta-arm32 @@ -0,0 +1,13 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +export PROJECT=magenta-qemu-arm32 + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +$DIR/make-parallel $PROJECT diff --git a/scripts/build-magenta-arm64 b/scripts/build-magenta-arm64 new file mode 100755 index 000000000..3913ba262 --- /dev/null +++ b/scripts/build-magenta-arm64 @@ -0,0 +1,13 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +export PROJECT=magenta-qemu-arm64 + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +$DIR/make-parallel $PROJECT diff --git a/scripts/build-magenta-pixel2 b/scripts/build-magenta-pixel2 new file mode 100755 index 000000000..ed3ed4ef1 --- /dev/null +++ b/scripts/build-magenta-pixel2 @@ -0,0 +1,28 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +export PROJECT=magenta-pc-uefi + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +$DIR/make-parallel $PROJECT || exit + +BUILDDIR=build-$PROJECT +BOOTDIR=scripts/build-magenta-pixel2-deps + +FUTILITY=futility + +$FUTILITY --debug vbutil_kernel \ + --pack $BUILDDIR/pixel2_kernel.bin \ + --keyblock $BOOTDIR/kernel.keyblock \ + --signprivate $BOOTDIR/kernel_data_key.vbprivk \ + --version 1 \ + --config $BOOTDIR/config.txt \ + --bootloader $BOOTDIR/bootstub.efi \ + --vmlinuz $BUILDDIR/lk.bin + diff --git a/scripts/build-magenta-x86-64 b/scripts/build-magenta-x86-64 new file mode 100755 index 000000000..1626b4f79 --- /dev/null +++ b/scripts/build-magenta-x86-64 @@ -0,0 +1,13 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +export PROJECT=magenta-qemu-x86-64 + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +$DIR/make-parallel $PROJECT diff --git a/scripts/buildall b/scripts/buildall new file mode 100755 index 000000000..a424070d4 --- /dev/null +++ b/scripts/buildall @@ -0,0 +1,60 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +function HELP { + echo "help:" + echo "-f : Exit on first failure" + echo "-r : Also build release mode builds" + echo "-h for help" + exit 1 +} + +FAIL_FAST=0 +DO_RELEASE=0 + +while getopts fhr FLAG; do + case $FLAG in + f) FAIL_FAST=1;; + h) HELP;; + r) DO_RELEASE=1;; + \?) + echo unrecognized option + HELP + esac +done +shift $((OPTIND-1)) + +# build everything in the projects directory +PROJECTS=`echo kernel/project/*.mk | xargs -n1 basename | sed 's/\.mk//'` +FAILED="" + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +for p in $PROJECTS; do + if ! nice $DIR/make-parallel $p; then + FAILED="$FAILED $p" + if [ "$FAIL_FAST" -eq 1 ]; then + break + fi + fi + if [ "$DO_RELEASE" -eq 1 ]; then + if ! nice $DIR/make-release $p; then + FAILED="$FAILED $p-release" + if [ "$FAIL_FAST" -eq 1 ]; then + break + fi + fi + fi +done + +if [ "$FAILED" != "" ]; then + echo + echo some projects have failed to build: + echo $FAILED +fi diff --git a/scripts/clang-fmt b/scripts/clang-fmt new file mode 100755 index 000000000..ce5c2ec9f --- /dev/null +++ b/scripts/clang-fmt @@ -0,0 +1,29 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +if [ ! -f ".clang-format" ]; then + echo "local .clang-format not found. aborting" + exit 0 +fi + +# There might be more than one clang-format tool, specially if chromium's +# depot tools are in the path. Try to use the system one. + +CLANGFMT=/usr/bin/clang-format + +if [ ! -f $CLANGFMT ]; then + # try local dir + CLANGFMT=./clang-format +fi +if [ ! -f $CLANGFMT ]; then + echo "$CLANGFMT not found. Go to http://llvm.org/releases/ to get it." + exit 0 +fi + +$CLANGFMT -i -style=file $@ + diff --git a/scripts/do-cppcheck b/scripts/do-cppcheck new file mode 100755 index 000000000..af9301f1a --- /dev/null +++ b/scripts/do-cppcheck @@ -0,0 +1,30 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +if [ "$#" -lt 1 ]; then + echo "not enough arguments" + echo "usage: $0 " + exit 1 +fi + +case `uname` in +Linux) + N=`cat /proc/cpuinfo | grep processor | wc -l` + JOBS=-j$N + ;; +*) + JOBS=-j4 + ;; +esac + +PROJ=$1 +PROJ_DIR=build-${PROJ} +TESTS="--enable=warning,style,performance,portability,information" + +cppcheck --force --file-list=${PROJ_DIR}/srcfiles.txt --includes-file=${PROJ_DIR}/include_paths.txt --include=${PROJ_DIR}/config.h -q --platform=unix32 $TESTS $JOBS diff --git a/scripts/do-qemuarm b/scripts/do-qemuarm new file mode 100755 index 000000000..0bac5b5d7 --- /dev/null +++ b/scripts/do-qemuarm @@ -0,0 +1,116 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +function HELP { + echo "help:" + echo "-a : add intel hda sound" + echo "-b : a virtio block device" + echo "-c : cmpctmalloc instead of dlmalloc" + echo "-M : miniheap instead of dlmalloc" + echo "-n : a virtio network device" + echo "-t : a virtio tap network device" + echo "-d : a virtio display" + echo "-3 : cortex-m3 based platform" + echo "-6 : 64bit arm" + echo "-m " + echo "-s " + echo "-h for help" + echo "all arguments after -- are passed to qemu directly" + exit 1 +} + +DO_AUDIO=0 +DO_BLOCK=0 +DO_NET=0 +DO_NET_TAP=0 +DO_64BIT=0 +DO_CORTEX_M3=0 +DO_DISPLAY=0 +DO_CMPCTMALLOC=0 +DO_MINIHEAP=0 +SMP=1 +MEMSIZE=512 +SUDO="" + +while getopts abdhm:cMnt36s: FLAG; do + case $FLAG in + a) DO_AUDIO=1;; + b) DO_BLOCK=1;; + c) DO_CMPCTMALLOC=1;; + d) DO_DISPLAY=1;; + M) DO_MINIHEAP=1;; + n) DO_NET=1;; + t) DO_NET_TAP=1;; + 3) DO_CORTEX_M3=1;; + 6) DO_64BIT=1;; + m) MEMSIZE=$OPTARG;; + s) SMP=$OPTARG;; + h) HELP;; + \?) + echo unrecognized option + HELP + esac +done + +shift $((OPTIND-1)) + +if [ $DO_64BIT == 1 ]; then + QEMU="qemu-system-aarch64 -machine virt -cpu cortex-a53" + PROJECT="qemu-virt-a53-test" +elif [ $DO_CORTEX_M3 == 1 ]; then + QEMU="qemu-system-arm -machine lm3s6965evb -cpu cortex-m3" + PROJECT="lm3s6965evb-test" +else + QEMU="qemu-system-arm -machine virt -cpu cortex-a15" + PROJECT="qemu-virt-a15-test" +fi + +ARGS=" -m $MEMSIZE -smp $SMP -kernel build-${PROJECT}/lk.elf" + +AUDIO_ARGS=" -soundhw hda" +BLOCK_ARGS=" -drive if=none,file=blk.bin,id=blk,format=raw -device virtio-blk-device,drive=blk" +NET_ARGS=" -netdev user,id=vmnic,hostname=qemu -device virtio-net-device,netdev=vmnic" +NET_TAP_ARGS=" -netdev tap,id=vmnic -device virtio-net-device,netdev=vmnic" +NO_DISPLAY_ARGS=" -nographic" +DISPLAY_ARGS=" -device virtio-gpu-device -serial stdio" + +echo DO_BLOCK = $DO_BLOCK +echo DO_NET = $DO_NET + +if [ $DO_AUDIO == 1 ]; then + ARGS+=$AUDIO_ARGS + export QEMU_AUDIO_DRV=none +fi +if [ $DO_BLOCK == 1 ]; then + ARGS+=$BLOCK_ARGS +fi +if [ $DO_NET == 1 ]; then + ARGS+=$NET_ARGS +fi +if [ $DO_NET_TAP == 1 ]; then + ARGS+=$NET_TAP_ARGS + SUDO="sudo " +fi +if [ $DO_DISPLAY == 1 ]; then + ARGS+=$DISPLAY_ARGS +else + ARGS+=$NO_DISPLAY_ARGS +fi + +MAKE_VARS="" + +if [ $DO_CMPCTMALLOC == 1 ]; then + MAKE_VARS=LK_HEAP_IMPLEMENTATION=cmpctmalloc +elif [ $DO_MINIHEAP == 1 ]; then + MAKE_VARS=LK_HEAP_IMPLEMENTATION=miniheap +fi + +make $MAKE_VARS $PROJECT -j4 && +echo $SUDO $QEMU $ARGS $@ && +$SUDO $QEMU $ARGS $@ diff --git a/scripts/do-qemux86 b/scripts/do-qemux86 new file mode 100755 index 000000000..8915c7930 --- /dev/null +++ b/scripts/do-qemux86 @@ -0,0 +1,91 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +function HELP { + echo "help:" + echo "-a : add intel hda sound" + echo "-b : a virtio block device" + echo "-n : a virtio network device" + echo "-g : with graphics" + echo "-k : use KVM" + echo "-6 : x86-64" + echo "-m " + echo "-s " + echo "-h for help" + echo "all arguments after -- are passed to qemu directly" + exit 1 +} + +DO_AUDIO=0 +DO_BLOCK=0 +DO_NET=0 +DO_64BIT=0 +DO_GRAPHICS=0 +DO_KVM=0 +MEMSIZE=512 +SMP=1 +SUDO="" +MAKE_VARS="" + +while getopts 6abngkm:s:h FLAG; do + case $FLAG in + a) DO_AUDIO=1;; + b) DO_BLOCK=1;; + n) DO_NET=1;; + 6) DO_64BIT=1;; + g) DO_GRAPHICS=1;; + k) DO_KVM=1;; + m) MEMSIZE=$OPTARG;; + s) SMP=$OPTARG;; + h) HELP;; + \?) + echo unrecognized option + HELP + esac +done + +shift $((OPTIND-1)) + +if [ $DO_64BIT == 1 ]; then + QEMU="qemu-system-x86_64" + PROJECT="pc-x86-64-test" +else + QEMU="qemu-system-i386" + PROJECT="pc-x86-test" +fi + +AUDIO_ARGS=" -soundhw hda" +BLOCK_ARGS=" -drive if=virtio,file=blk.bin,id=blk,format=raw" +NET_ARGS=" -netdev type=user,hostname=qemu,id=net0 -device virtio-net-pci,netdev=net0" + +ARGS=" -m $MEMSIZE -smp $SMP -machine q35 -kernel build-${PROJECT}/lk.bin" + +if [ $DO_AUDIO == 1 ]; then + ARGS+=$AUDIO_ARGS + export QEMU_AUDIO_DRV=none +fi +if [ $DO_BLOCK == 1 ]; then + ARGS+=$BLOCK_ARGS +fi +if [ $DO_NET == 1 ]; then + ARGS+=$NET_ARGS +fi +if [ $DO_GRAPHICS == 0 ]; then + ARGS+=" -nographic" +else + ARGS+=" -serial stdio" +fi +if [ $DO_KVM != 0 ]; then + ARGS+=" -enable-kvm -cpu host" +fi + +make $MAKE_VARS $PROJECT -j4 && +echo $SUDO $QEMU $ARGS $@ && +$SUDO $QEMU $ARGS $@ + diff --git a/scripts/download-gn b/scripts/download-gn new file mode 100755 index 000000000..46d54951b --- /dev/null +++ b/scripts/download-gn @@ -0,0 +1,43 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +set -o pipefail + +readonly OS="$(uname)" +readonly ARCH="$(uname -m)" +readonly REPO="https://chromium.googlesource.com/chromium/buildtools/+/master" +readonly BUCKET="https://storage.googleapis.com/chromium-gn" + +err() { + echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 +} + +if [[ "${ARCH}" != "x86_64" ]]; then + err "Unsupported architecture: ${ARCH}" + exit 1 +fi + +if [[ "${OS}" == "Linux" ]]; then + readonly HOST="linux64" +elif [[ "${OS}" == "Darwin" ]]; then + readonly HOST="mac" +fi + +DIGEST=$(curl "${REPO}/${HOST}/gn.sha1?format=TEXT" 2>/dev/null | base64 --decode) +if [[ $? -ne 0 ]]; then + err "Failed to find GN revision" + exit 1 +fi + +curl -o gn "${BUCKET}/${DIGEST}" 2>/dev/null +if [[ $? -ne 0 ]]; then + err "Failed to download GN" + exit 1 +fi + +chmod 0755 gn diff --git a/scripts/fetch-clang-fmt b/scripts/fetch-clang-fmt new file mode 100755 index 000000000..4836eef0e --- /dev/null +++ b/scripts/fetch-clang-fmt @@ -0,0 +1,36 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +HASH= + +# hashes saved from +# +# https://chromium.googlesource.com/chromium/buildtools/+/master/linux64/clang-format.sha1 +# https://chromium.googlesource.com/chromium/buildtools/+/master/mac/clang-format.sha1 + +case `uname` in +Linux) + HASH=8b68e8093516183b8f38626740eeaff97f112f7e + ;; +Darwin) + HASH=afe0942b94fe33619361efe1510ae081c3070dc1 + ;; +*) + echo "OS not understood" + exit 1 +esac + +if [ -f clang-format ]; then + echo "clang-format already exists in local directory" + exit 1 +fi + +# fetch clang-format into the local directory +curl https://storage.googleapis.com/chromium-clang-format/$HASH > clang-format.fetch && +chmod +x clang-format.fetch && +mv clang-format.fetch clang-format diff --git a/scripts/lk.elf-gdb.py b/scripts/lk.elf-gdb.py new file mode 100644 index 000000000..7ab4fe85f --- /dev/null +++ b/scripts/lk.elf-gdb.py @@ -0,0 +1,645 @@ +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +# GDB support for magenta kernel. + +# TODO(dje): gdb should let us use a better command class than COMMAND_DATA. +# TODO(dje): Add arm64 support. + +import sys +import gdb +import gdb.printing +import re +from gdb.unwinder import Unwinder + +# The command prefix, passed in from gdbinit.py. +_MAGENTA_COMMAND_PREFIX = "magenta" +_KERNEL_EXCEPTION_UNWINDER_PARAMETER = "kernel-exception-unwinder" + +_THREAD_MAGIC = 0x74687264 + +print "Loading lk.elf-gdb.py ..." + + +def _is_x86_64(): + """Return True if we're on an x86-64 platform.""" + # TODO(dje): gdb doesn't provide us with a simple way to do this. + arch_text = gdb.execute("show architecture", to_string=True) + return re.search(r"x86-64", arch_text) + + +# The default is 2 seconds which is too low. +# But don't override something the user set. +# [If the user set it to the default, too bad. :-)] +# TODO(dje): Alas this trips over upstream PR 20084. +#_DEFAULT_GDB_REMOTETIMEOUT = 2 +#if int(gdb.parameter("remotetimeout")) == _DEFAULT_GDB_REMOTETIMEOUT: +# gdb.execute("set remotetimeout 10") + + +class _MagentaPrefix(gdb.Command): + """magenta command prefix""" + + def __init__(self): + super(_MagentaPrefix, self).__init__("%s" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, + prefix=True) + + +class _InfoMagenta(gdb.Command): + """info magenta command prefix""" + + def __init__(self): + super(_InfoMagenta, self).__init__("info %s" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, + prefix=True) + + +class _SetMagenta(gdb.Command): + """set magenta command prefix""" + + def __init__(self): + super(_SetMagenta, self).__init__("set %s" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, + prefix=True) + + +class _ShowMagenta(gdb.Command): + """show magenta command prefix""" + + def __init__(self): + super(_ShowMagenta, self).__init__("show %s" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, + prefix=True) + + +class _MagentaMaxInfoThreads(gdb.Parameter): + """Parameter to limit output of "info magenta threads" command. + + This parameter is an escape hatch to catch corrupted lists. + We don't want "info magenta threads" to loop forever. + + The value is the maximum number of threads that will be printed. + """ + + set_doc = "Set the maximum number of magenta threads to print." + show_doc = "Show the maximum number of magenta threads to print." + + def __init__(self): + super(_MagentaMaxInfoThreads, self).__init__( + "%s max-info-threads" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, gdb.PARAM_UINTEGER) + self.value = 1000 + + def get_show_string(self, pvalue): + return "Maximum number of threads to print is " + pvalue + "." + + def get_set_string(self): + # Ugh. There doesn't seem to be a way to implement a gdb parameter in + # Python that will be silent when the user changes the value. + if self.value is None: + value = "unlimited" + else: + value = self.value + return "Maximum number of threads to print been set to %s." % (value) + + +class _MagentaMaxInfoProcesses(gdb.Parameter): + """Parameter to limit output of "info magenta processes" command. + + This parameter is an escape hatch to catch corrupted lists. + We don't want "info magenta processes" to loop forever. + + The value is the maximum number of processes that will be printed. + """ + + set_doc = "Set the maximum number of magenta processes to print." + show_doc = "Show the maximum number of magenta processes to print." + + def __init__(self): + super(_MagentaMaxInfoProcesses, self).__init__( + "%s max-info-processes" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, gdb.PARAM_UINTEGER) + self.value = 1000 + + def get_show_string(self, pvalue): + return "Maximum number of processes to print is " + pvalue + "." + + def get_set_string(self): + # Ugh. There doesn't seem to be a way to implement a gdb parameter in + # Python that will be silent when the user changes the value. + if self.value is None: + value = "unlimited" + else: + value = self.value + return "Maximum number of processes to print been set to %s." % (value) + + +class _MagentaMaxInfoHandles(gdb.Parameter): + """Parameter to limit output of "info magenta handles" command. + + This parameter is an escape hatch to catch corrupted lists. + We don't want "info magenta handles" to loop forever. + + The value is the maximum number of handles that will be printed. + """ + + set_doc = "Set the maximum number of magenta handles to print." + show_doc = "Show the maximum number of magenta handles to print." + + def __init__(self): + super(_MagentaMaxInfoHandles, self).__init__( + "%s max-info-handles" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_DATA, gdb.PARAM_UINTEGER) + self.value = 1000 + + def get_show_string(self, pvalue): + return "Maximum number of handles to print is " + pvalue + "." + + def get_set_string(self): + # Ugh. There doesn't seem to be a way to implement a gdb parameter in + # Python that will be silent when the user changes the value. + if self.value is None: + value = "unlimited" + else: + value = self.value + return "Maximum number of handles to print been set to %s." % (value) + + +def containerof(node_ptr, type_name, member_name): + """Python version of magenta's containerof macro.""" + # TODO(dje): This could only be computed once. + # For more popular types, compute all possible once. + char_ptr = gdb.lookup_type("char").pointer() + ptr = node_ptr.cast(char_ptr) + type_object_ptr = gdb.lookup_type(type_name).pointer() + offsetof = long(gdb.Value(0).cast(type_object_ptr)[member_name].address) + return (ptr - offsetof).cast(type_object_ptr) + + +def _build_magenta_pretty_printers(): + pp = gdb.printing.RegexpCollectionPrettyPrinter("magenta") + # Insert printer registration here. + #pp.add_printer("foo", "^foo$", _MagentaFooPrinter) + return pp + + +def register_magenta_pretty_printers(obj): + if obj is None: + obj = gdb + gdb.printing.register_pretty_printer(obj, _build_magenta_pretty_printers(), + replace=True) + + +def _get_thread_list(): + """ Return a list of all thread_t threads. + + The result is constrained by "magenta max-info-threads". + """ + threads = [] + head = gdb.parse_and_eval("&thread_list") + t = head["next"] + count = 0 + max_threads = gdb.parameter("%s max-info-threads" % (_MAGENTA_COMMAND_PREFIX)) + int_type = gdb.lookup_type("int") + ptr_size = int_type.pointer().sizeof + # Note: A "corrupted" list can happen for a short time while an + # element is being added/removed. And, in non-stop mode, the list can + # change while we're at it. This isn't a problem in all-stop mode, but + # non-stop mode is generally preferable. We'll see how this works in + # practice. + while t and t != head: + if max_threads is not None and count >= max_threads: + break + # Catch misaligned pointers. + # Casting to int shouldn't be necessary, but the python API doesn't + # support creating an int from a pointer. + # We assume the object is aligned at least as great as a pointer. + if (t.cast(int_type) & (ptr_size - 1)) != 0: + break + # TODO(dje): Do a range check? + thread_ptr = containerof(t, "thread", "thread_list_node") + if thread_ptr["magic"] != _THREAD_MAGIC: + break + # TODO(dje): Move this to a routine, more list printers will want this. + threads.append(thread_ptr) + t = t["next"] + count += 1 + return threads + + +def _get_process_list(): + """Return list of all processes. + + The result is constrained by "magenta max-info-processes". + """ + processes = [] + head = gdb.parse_and_eval("&process_list") + head = head["head_"] + p = head + count = 0 + max_processes = gdb.parameter("%s max-info-processes" % (_MAGENTA_COMMAND_PREFIX)) + int_type = gdb.lookup_type("int") + ptr_size = int_type.pointer().sizeof + # Note: A "corrupted" list can happen for a short time while an + # element is being added/removed. And, in non-stop mode, the list can + # change while we're at it. This isn't a problem in all-stop mode, but + # non-stop mode is generally preferable. We'll see how this works in + # practice. + while p: + if max_processes is not None and count >= max_processes: + break + # Catch misaligned pointers. + # Casting to int shouldn't be necessary, but the python API doesn't + # support creating an int from a pointer. + # We assume the object is aligned at least as great as a pointer. + if (p.cast(int_type) & (ptr_size - 1)) != 0: + break + # TODO(dje): Do a range check? + # TODO(dje): Move this to a routine, more list printers will want this. + processes.append(p) + p = p["next_"] + count += 1 + if p == head: + break + return processes + + +def _get_handle_list(process): + """Return list of all handles of process. + + The result is constrained by "magenta max-info-handles". + """ + handles = [] + head = process["handles_"] + head = head["head_"] + h = head + count = 0 + max_handles = gdb.parameter("%s max-info-handles" % (_MAGENTA_COMMAND_PREFIX)) + int_type = gdb.lookup_type("int") + ptr_size = int_type.pointer().sizeof + # Note: A "corrupted" list can happen for a short time while an + # element is being added/removed. And, in non-stop mode, the list can + # change while we're at it. This isn't a problem in all-stop mode, but + # non-stop mode is generally preferable. We'll see how this works in + # practice. + while h: + if max_handles is not None and count >= max_handles: + break + # Catch misaligned pointers. + # Casting to int shouldn't be necessary, but the python API doesn't + # support creating an int from a pointer. + # We assume the object is aligned at least as great as a pointer. + if (h.cast(int_type) & (ptr_size - 1)) != 0: + break + # TODO(dje): Do a range check? + # TODO(dje): Move this to a routine, more list printers will want this. + handles.append(h) + h = h["next_"] + count += 1 + if h == head: + break + return handles + + +def _print_thread_summary(thread, number, tls_entry, user_thread_ptr_t): + user_thread = thread["tls"][tls_entry] + if user_thread: + user_thread_ptr = user_thread.cast(user_thread_ptr_t) + # TODO(dje): Why is str necessary here? Otherwise -> + # "Cannot convert value to int." + pid = str(user_thread_ptr["process_"]["id_"]) + else: + pid = "kern" + name = str(thread["name"].lazy_string().value()).strip('"') + print "%3d %5s %#16x %-32s %s" % ( + number, pid, thread.address, name, thread["state"]) + + +class _InfoMagentaThreads(gdb.Command): + """info magenta threads command + + This command prints a list of all magenta threads. + TODO: Allow specifying which threads to print. + """ + + def __init__(self): + super(_InfoMagentaThreads, self).__init__("info %s threads" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_USER) + + def invoke(self, arg, from_tty): + # Do this first to make sure the previous value gets cleared out. + # There's no way to unset a convenience var, so KISS. + gdb.execute("set $mx_threads = (thread_t*[1]) { 0 }") + tls_entry_lkuser = gdb.parse_and_eval("TLS_ENTRY_LKUSER") + threads = _get_thread_list() + num_threads = len(threads) + # The array is origin-1-indexed. Have a null first entry to KISS. + gdb.execute("set $mx_threads = (thread_t*[%d]) { 0 }" % (num_threads + 1)) + + # Populate the array first, before printing the summary, to make sure this + # gets done even if there's an error during printing. + num = 1 + for thread_ptr in threads: + gdb.execute("set $mx_threads[%d] = (thread_t*) %u" % (num, thread_ptr)) + num += 1 + + # Translating gdb values to python often trips over these. Heads up. + save_print_address = "yes" if gdb.parameter("print address") else "no" + save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" + gdb.execute("set print address off") + gdb.execute("set print symbol off") + + print "%3s %5s %-18s %-32s %s" % ( + "Num", "Pid", "thread_t*", "Name", "State") + # Make sure we restore these when we're done. + try: + user_thread_ptr_t = gdb.lookup_type("UserThread").pointer() + num = 1 + for thread_ptr in threads: + # TODO(dje): remove dereference + _print_thread_summary(thread_ptr.dereference(), num, tls_entry_lkuser, user_thread_ptr_t) + num += 1 + finally: + gdb.execute("set print address %s" % (save_print_address)) + gdb.execute("set print symbol %s" % (save_print_symbol)) + if num_threads: + print "Note: Each thread is now available in $mx_threads[num]." + else: + print "" + + +def _print_process_summary(process, number): + state = str(process["state_"]) + state = state.replace("UserProcess::", "") + print "%3d %#16x %4u %s" % ( + number, process.address, process["id_"], state) + + +class _InfoMagentaProcesses(gdb.Command): + """info magenta processes command + + This command prints a list of all magenta processes. + TODO: Allow specifying which processes to print. + """ + + def __init__(self): + super(_InfoMagentaProcesses, self).__init__("info %s processes" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_USER) + + def invoke(self, arg, from_tty): + # Do this first to make sure the previous value gets cleared out. + # There's no way to unset a convenience var, so KISS. + gdb.execute("set $mx_processes = (UserProcess*[1]) { 0 }") + tls_entry_lkuser = gdb.parse_and_eval("TLS_ENTRY_LKUSER") + processes = _get_process_list() + num_processes = len(processes) + # The array is origin-1-indexed. Have a null first entry to KISS. + gdb.execute("set $mx_processes = (UserProcess*[%d]) { 0 }" % (num_processes + 1)) + + # Populate the array first, before printing the summary, to make sure this + # gets done even if there's an error during printing. + num = 1 + for process_ptr in processes: + gdb.execute("set $mx_processes[%d] = (UserProcess*) %u" % (num, process_ptr)) + num += 1 + + # Translating gdb values to python often trips over these. Heads up. + save_print_address = "yes" if gdb.parameter("print address") else "no" + save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" + gdb.execute("set print address off") + gdb.execute("set print symbol off") + + print "%3s %-18s %4s %s" % ( + "Num", "UserProcess*", "Pid", "State") + # Make sure we restore these when we're done. + try: + num = 1 + for process_ptr in processes: + _print_process_summary(process_ptr.dereference(), num) + num += 1 + finally: + gdb.execute("set print address %s" % (save_print_address)) + gdb.execute("set print symbol %s" % (save_print_symbol)) + if num_processes: + print "Note: Each process is now available in $mx_processes[num]." + else: + print "" + + +def _print_handle_summary(handle, number): + process_id = handle["process_id_"] + rights = handle["rights_"] + dispatcher = handle["dispatcher_"]["ptr_"] + # TODO(dje): This is a hack to get the underlying type from the vtable. + # The python API should support this directly. + dispatcher_text = gdb.execute("output *(Dispatcher*) %s" % (dispatcher), to_string=True) + dispatcher_split_text = dispatcher_text.split(" ", 1) + if len(dispatcher_split_text) == 2: + dispatcher_type = dispatcher_split_text[0].strip("()") + else: + dispatcher_type = "Dispatcher" + dispatcher_text = "(%s*) %s" % (dispatcher_type, dispatcher) + print " %3d %-18s %4u %#8x %s" % ( + number, handle.address, process_id, rights, dispatcher_text) + + +class _InfoMagentaHandles(gdb.Command): + """info magenta handles command + + This command prints a list of all magenta handles. + TODO: Allow specifying which handles to print. + """ + + def __init__(self): + super(_InfoMagentaHandles, self).__init__("info %s handles" % (_MAGENTA_COMMAND_PREFIX), + gdb.COMMAND_USER) + + def invoke(self, arg, from_tty): + processes = _get_process_list() + + # Translating gdb values to python often trips over these. Heads up. + save_print_address = "yes" if gdb.parameter("print address") else "no" + save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" + gdb.execute("set print address on") + gdb.execute("set print symbol off") + + # Make sure we restore these when we're done. + try: + for p in processes: + handles = _get_handle_list(p) + num_handles = len(handles) + + print "Process %u" % (p["id_"]) + print " %3s %-18s %4s %8s %s" % ( + "Num", "Handle*", "Pid", "Rights", "Dispatcher") + + num = 1 + for handle_ptr in handles: + _print_handle_summary(handle_ptr.dereference(), num) + num += 1 + + if not num_handles: + print " " + + finally: + gdb.execute("set print address %s" % (save_print_address)) + gdb.execute("set print symbol %s" % (save_print_symbol)) + + +class _MagentaKernelExceptionUnwinder(gdb.Parameter): + """Parameter to enable magenta kernel exception unwinding. + + This parameter is an escape hatch in case there are problems with the unwinder. + + N.B. Perhaps this command should flush registers. + It doesn't now to avoid side-effects, and the user is responsible for typing + "flushregs" if s/he wants to reprint a recent backtrace. + """ + + set_doc = "Set whether the magenta kernel exception unwinder is enabled." + show_doc = "Show whether the magenta kernel exception unwinder is enabled." + + def __init__(self): + super(_MagentaKernelExceptionUnwinder, self).__init__( + "%s %s" % (_MAGENTA_COMMAND_PREFIX, _KERNEL_EXCEPTION_UNWINDER_PARAMETER), + gdb.COMMAND_DATA, gdb.PARAM_BOOLEAN) + self.value = True + + def get_show_string(self, pvalue): + value = "enabled" if self.value else "disabled" + return "The kernel exception unwinder is %s." % (value) + + def get_set_string(self): + # Ugh. There doesn't seem to be a way to implement a gdb parameter in + # Python that will be silent when the user changes the value. + value = "enabled" if self.value else "disabled" + return "The kernel exception unwinder is %s." % (value) + + +class _Amd64KernelExceptionUnwinder(Unwinder): + # See arch/x86/64/exceptions.S. + AT_IFRAME_SETUP = "interrupt_common_iframe_set_up_for_debugger" + INTERRUPT_COMMON = "interrupt_common" + + class FrameId(object): + def __init__(self, sp, pc): + self.sp = sp + self.pc = pc + + @staticmethod + def lookup_minsym(minsym_name): + """Return the address of "minimal symbol" minsym_name.""" + # TODO(dje): What's here now is a quick hack to get things going. + # GDB's python API doesn't yet provide the ability to look up minsyms. + try: + output = gdb.execute("output %s" % (minsym_name), to_string=True) + except (gdb.error): + return None + symbol_value = None + if not output.startswith("No symbol"): + symbol_match = re.search(r"0x[0-9a-f]+", output) + if symbol_match is not None: + symbol_value = long(symbol_match.group(0), 16) + return symbol_value + + @staticmethod + def is_user_space(iframe): + """Return True if iframe is from user space.""" + # See arch/x86/include/arch/x86/descriptor.h:SELECTOR_PL. + return (iframe["cs"] & 3) != 0 + + def __init__(self): + super(_Amd64KernelExceptionUnwinder, self).__init__("AMD64 kernel exception unwinder") + # We assume uintptr_t is present in the debug info. + # We *could* use unsigned long, but it's a bit of an obfuscation. + self.uintptr_t = gdb.lookup_type("uintptr_t") + # We assume "unsigned int" is 32 bits. + self.uint32_t = gdb.lookup_type("unsigned int") + self.iframe_ptr_t = gdb.lookup_type("x86_iframe_t").pointer() + # We need to know when the pc is at the point where it has called + # x86_exception_handler. + self.at_iframe_setup = self.lookup_minsym(_Amd64KernelExceptionUnwinder.AT_IFRAME_SETUP) + self.interrupt_common_begin_addr = self.lookup_minsym(_Amd64KernelExceptionUnwinder.INTERRUPT_COMMON) + + def is_in_icommon(self, pc): + """Return True if pc is in the interrupt_common function.""" + # First do the preferred test. + # If the pc is here then we've called into x86_exception_handler. + if self.at_iframe_setup is not None and pc == self.at_iframe_setup: + return True + # Fall back to this in case the special symbol doesn't exist. + if self.interrupt_common_begin_addr is None: + return False + end_addr = self.interrupt_common_begin_addr + 64 + return pc >= self.interrupt_common_begin_addr and pc < end_addr + + def __call__(self, pending_frame): + try: + # Punt if disabled. + if not gdb.parameter("%s %s" % (_MAGENTA_COMMAND_PREFIX, _KERNEL_EXCEPTION_UNWINDER_PARAMETER)): + return None + # Note: We use rip,rsp here instead of pc,sp to work around bug 20128 + #pc = pending_frame.read_register("pc").cast(self.uintptr_t) + pc = pending_frame.read_register("rip").cast(self.uintptr_t) + #print "icommon unwinder, pc = %#x" % (long(str(pc))) # work around bug 20126 + if not self.is_in_icommon(pc): + return None + sp = pending_frame.read_register("rsp").cast(self.uintptr_t) + #print "icommon unwinder, sp = %#x" % (long(str(sp))) + iframe = sp.cast(self.iframe_ptr_t) + # This is only for kernel faults, not user-space ones. + if self.is_user_space(iframe): + return None + frame_id = self.FrameId(sp, pc) + unwind_info = pending_frame.create_unwind_info(frame_id) + unwind_info.add_saved_register("rip", iframe["ip"]) + unwind_info.add_saved_register("rsp", iframe["user_sp"]) + unwind_info.add_saved_register("rax", iframe["rax"]) + unwind_info.add_saved_register("rbx", iframe["rbx"]) + unwind_info.add_saved_register("rcx", iframe["rcx"]) + unwind_info.add_saved_register("rdx", iframe["rdx"]) + unwind_info.add_saved_register("rbp", iframe["rbp"]) + unwind_info.add_saved_register("rsi", iframe["rsi"]) + unwind_info.add_saved_register("r8", iframe["r8"]) + unwind_info.add_saved_register("r9", iframe["r9"]) + unwind_info.add_saved_register("r10", iframe["r10"]) + unwind_info.add_saved_register("r11", iframe["r11"]) + unwind_info.add_saved_register("r12", iframe["r12"]) + unwind_info.add_saved_register("r13", iframe["r13"]) + unwind_info.add_saved_register("r14", iframe["r14"]) + unwind_info.add_saved_register("r15", iframe["r15"]) + # Flags is recorded as 64 bits, but gdb needs to see 32. + unwind_info.add_saved_register("eflags", iframe["flags"].cast(self.uint32_t)) + #print "Unwind info:" + #print unwind_info + return unwind_info + except (gdb.error, RuntimeError): + return None + + +_MagentaPrefix() +_InfoMagenta() +_SetMagenta() +_ShowMagenta() + +_MagentaMaxInfoThreads() +_MagentaMaxInfoProcesses() +_MagentaMaxInfoHandles() + +_InfoMagentaThreads() +_InfoMagentaProcesses() +_InfoMagentaHandles() + +_MagentaKernelExceptionUnwinder() + +def _install(): + current_objfile = gdb.current_objfile() + register_magenta_pretty_printers(current_objfile) + if current_objfile is not None and _is_x86_64(): + gdb.unwinder.register_unwinder(current_objfile, _Amd64KernelExceptionUnwinder(), True) + +_install() diff --git a/scripts/make-magenta-x86-64-grub b/scripts/make-magenta-x86-64-grub new file mode 100755 index 000000000..c1c918bb6 --- /dev/null +++ b/scripts/make-magenta-x86-64-grub @@ -0,0 +1,28 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +set -e -u + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +PROJECT="magenta-pc-uefi" +PROJECT_DIR="$DIR/../build-$PROJECT" + +(cd "$DIR/.."; $DIR/make-parallel $PROJECT) || exit + +TEMP="$(mktemp -d)" +mkdir -p "$TEMP/boot/grub" +cp "$PROJECT_DIR/lk.bin" "$TEMP/boot/lk.bin" +cat > "$TEMP/boot/grub/grub.cfg" << EOF +set timeout=0 +menuentry "Magenta" { + multiboot /boot/lk.bin +} +EOF +grub-mkrescue -o "$PROJECT_DIR/lk.iso" "$TEMP" +rm -rf "$TEMP" diff --git a/scripts/make-parallel b/scripts/make-parallel new file mode 100755 index 000000000..c7e57bcb9 --- /dev/null +++ b/scripts/make-parallel @@ -0,0 +1,22 @@ +#!/bin/sh + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +case `uname` in +Linux) + N=`cat /proc/cpuinfo | grep processor | wc -l` + PARALLEL=-j`expr $N + $N` + ;; +Darwin) + PARALLEL=-j`sysctl -n hw.ncpu` + ;; +*) + PARALLEL=-j8 + ;; +esac + +make $PARALLEL "$@" diff --git a/scripts/make-release b/scripts/make-release new file mode 100755 index 000000000..2df4a96bc --- /dev/null +++ b/scripts/make-release @@ -0,0 +1,14 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# make a release build +# +# release builds are regular builds with DEBUG=0 and the -release suffix added to the build dir +DEBUG=0 BUILDDIR_SUFFIX=-release $DIR/make-parallel "$@" diff --git a/scripts/run-magenta b/scripts/run-magenta new file mode 100755 index 000000000..990921cc5 --- /dev/null +++ b/scripts/run-magenta @@ -0,0 +1,157 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +function HELP { + echo "help:" + echo "-a : arm32, arm64, or x86-64" + echo "-b : build first" + echo "-d : run with emulated disk" + echo "-g : use graphical console" + echo "-k : use KVM" + echo "-m : default 512MB" + echo "-n : run with emulated nic" + echo "-o : build directory" + echo "-r : run release build" + echo "-u : use uniprocessor" + echo "-v : use vnc based display" + echo "-h for help" + echo "all arguments after -- are passed to qemu directly" + exit 1 +} + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +ARCH= +BUILD=0 +DISK=0 +BUILDDIR= +GRAPHICS=0 +DO_KVM=0 +MEMSIZE=512 +NET=0 +UP=0 +RELEASE=0 +VNC=0 + +while getopts a:bdgkm:no:ruvh FLAG; do + case $FLAG in + a) ARCH=$OPTARG;; + b) BUILD=1;; + d) DISK=1;; + g) GRAPHICS=1;; + k) DO_KVM=1;; + m) MEMSIZE=$OPTARG;; + n) NET=1;; + o) BUILDDIR=$OPTARG;; + r) RELEASE=1;; + u) UP=1;; + v) VNC=1;; + h) HELP;; + \?) + echo unrecognized option + HELP + esac +done +shift $((OPTIND-1)) + +# arch argument is non optional +if [ "$ARCH" == "" ]; then + echo must specify arch + HELP +fi + +PROJECT=magenta-qemu-$ARCH + +# build the project if asked for +if [ "$BUILD" -eq 1 ]; then + if [ "$RELEASE" -eq 1 ]; then + $DIR/make-release $PROJECT || exit 1 + else + $DIR/make-parallel $PROJECT || exit 1 + fi +fi + +# append the release path if requested +if [ "$RELEASE" -eq 1 ]; then + PROJECT=$PROJECT-release +fi + +if [ "$BUILDDIR" == "" ]; then + BUILDDIR=build-$PROJECT +fi + +# construct the args for qemu +ARGS=" -m $MEMSIZE" +if [ "$VNC" -eq 1 ]; then + ARGS+=" -vnc :0" +fi + +if [ "$GRAPHICS" -eq 0 ]; then + ARGS+=" -nographic" +else + ARGS+=" -serial stdio" + if [ "$ARCH" != "x86-64" ]; then + # PC already has a vga framebuffer + ARGS+=" -device virtio-gpu-device" + fi +fi + +if [ "$DISK" -eq 1 ]; then + # virtio based block device + if [ "$ARCH" == "x86-64" ]; then + ARGS+=" -drive file=blk.bin,if=virtio,format=raw" + else + ARGS+=" -drive if=none,file=blk.bin,id=blk,format=raw -device virtio-blk-device,drive=blk" + fi +fi + +if [ "$NET" -eq 1 ]; then + # virtio based network interface + if [ "$ARCH" == "x86-64" ]; then + ARGS+=" -netdev type=user,hostname=qemu,id=net0 -device virtio-net-pci,netdev=net0" + else + ARGS+=" -netdev user,id=vmnic,hostname=qemu -device virtio-net-device,netdev=vmnic" + fi +fi +case $ARCH in + arm32) + QEMU=qemu-system-arm + ARGS+=" -machine virt -cpu cortex-a15 -kernel $BUILDDIR/lk.elf" + if [ "$UP" -eq 0 ]; then + ARGS+=" -smp cores=2,sockets=1" + fi + ;; + arm64) + QEMU=qemu-system-aarch64 + ARGS+=" -machine virt -cpu cortex-a53 -kernel $BUILDDIR/lk.elf" + if [ "$UP" -eq 0 ]; then + ARGS+=" -smp cores=2,sockets=1" + fi + ;; + x86-64) + QEMU=qemu-system-x86_64 + ARGS+=" -machine q35 -kernel $BUILDDIR/lk.bin" + if [ "$UP" -eq 0 ]; then + ARGS+=" -smp cores=2,threads=2,sockets=1" + fi + if [ $DO_KVM -ne 0 ]; then + ARGS+=" -enable-kvm -cpu host" + else + ARGS+=" -cpu Haswell,+smap" + fi + ;; + *) + echo unsupported arch + HELP + ;; +esac + +# run qemu +echo $QEMU $ARGS $@ +$QEMU $ARGS $@ + diff --git a/scripts/run-magenta-arm32 b/scripts/run-magenta-arm32 new file mode 100755 index 000000000..ea00e0d0a --- /dev/null +++ b/scripts/run-magenta-arm32 @@ -0,0 +1,11 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +exec $DIR/run-magenta -a arm32 $@ diff --git a/scripts/run-magenta-arm64 b/scripts/run-magenta-arm64 new file mode 100755 index 000000000..80672d0cd --- /dev/null +++ b/scripts/run-magenta-arm64 @@ -0,0 +1,11 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +exec $DIR/run-magenta -a arm64 $@ diff --git a/scripts/run-magenta-x86-64 b/scripts/run-magenta-x86-64 new file mode 100755 index 000000000..cb9f9b59e --- /dev/null +++ b/scripts/run-magenta-x86-64 @@ -0,0 +1,11 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +exec $DIR/run-magenta -a x86-64 $@ diff --git a/scripts/toolpaths.default b/scripts/toolpaths.default new file mode 100644 index 000000000..fb6dba2c1 --- /dev/null +++ b/scripts/toolpaths.default @@ -0,0 +1,15 @@ +#!/bin/bash + +# Copyright 2016 The Fuchsia Authors +# Copyright (c) 2008 Travis Geiselbrecht +# +# Use of this source code is governed by a MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +LOCAL_TOOLPATH="$DIR/toolpaths.local" +if [ -e "$LOCAL_TOOLPATH" ] +then + source $LOCAL_TOOLPATH +fi diff --git a/system/LICENSE b/system/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/system/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/system/uapp/crasher/BUILD.gn b/system/uapp/crasher/BUILD.gn new file mode 100644 index 000000000..4aaca28b7 --- /dev/null +++ b/system/uapp/crasher/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("crasher") { + sources = [ + "crasher.c", + ] + deps = [ + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/crasher/crasher.c b/system/uapp/crasher/crasher.c new file mode 100644 index 000000000..ff590933c --- /dev/null +++ b/system/uapp/crasher/crasher.c @@ -0,0 +1,114 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +typedef struct { + const char* name; + int (*func)(volatile unsigned int*); + const char* desc; +} command_t; + +int blind_write(volatile unsigned int* addr) { + *addr = 0xBAD1DEA; + return 0; +} + +int blind_read(volatile unsigned int* addr) { + return (int)(*addr); +} + +int ro_write(volatile unsigned int *addr) { + // test that we cannot write to RO code memory + volatile unsigned int *p = (volatile unsigned int *)&ro_write; + *p = 99; + return 0; +} + +int nx_run(volatile unsigned int *addr) { + // test that we cannot execute NX memory + static uint8_t codebuf[16]; + void (*func)(void) = (void *)codebuf; + func(); + return 0; +} + +// Note that as of 5/21/16 the crash reads: +// PageFault:199: UNIMPLEMENTED: faulting with a page already present. +int stack_overflow(volatile unsigned int* i_array) { + volatile unsigned int array[512]; + if (i_array) { + array[0] = i_array[0] + 1; + if (array[0] < 4096) + return stack_overflow(array); + } else { + array[0] = 0; + return stack_overflow(array); + } + return 0; +} + +int undefined(volatile unsigned int* unused) { +#if ARCH_X86_64 + __asm__ volatile("ud2"); +#elif ARCH_ARM64 + __asm__ volatile("brk #0"); // not undefined, but close enough +#elif ARCH_ARM + __asm__ volatile("udf"); +#else +#error "need to define undefined for this architecture" +#endif + return 0; +} + +command_t commands[] = { + {"write0", blind_write, "write to address 0x0"}, + {"read0", blind_read, "read address 0x0"}, + {"writero", ro_write, "write to read only code segment"}, + {"stackov", stack_overflow, "overflow the stack (recursive)"}, + {"und", undefined, "undefined instruction"}, + {"nx_run", nx_run, "run in no-execute memory"}, + {NULL, NULL, NULL}}; + +int main(int argc, char** argv) { + printf("=@ crasher @=\n"); + + if (argc < 2) { + printf("default to write0 (use 'help' for more options).\n"); + blind_write(NULL); + } else { + if (strcmp("help", argv[1])) { + for (command_t* cmd = commands; cmd->name != NULL; ++cmd) { + if (strcmp(cmd->name, argv[1]) == 0) { + printf("doing : %s\n", cmd->desc); + cmd->func(NULL); + goto exit; // should not reach here. + } + } + } + + printf("known commands are:\n"); + for (command_t* cmd = commands; cmd->name != NULL; ++cmd) { + printf("%s : %s\n", cmd->name, cmd->desc); + } + return 0; + } + +exit: + printf("crasher: exiting normally ?!!\n"); + return 0; +} diff --git a/system/uapp/crasher/rules.mk b/system/uapp/crasher/rules.mk new file mode 100644 index 000000000..b39bc8d84 --- /dev/null +++ b/system/uapp/crasher/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/crasher.c \ + +MODULE_NAME := crasher + +MODULE_DEPS := \ + ulib/musl ulib/mxio + +include make/module.mk diff --git a/system/uapp/devmgr/BUILD.gn b/system/uapp/devmgr/BUILD.gn new file mode 100644 index 000000000..26fdceb09 --- /dev/null +++ b/system/uapp/devmgr/BUILD.gn @@ -0,0 +1,38 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("devmgr") { + sources = [ + "api.c", + "device_internal.h", + "devmgr.c", + "devmgr.h", + "dmctl.c", + "main.c", + "mxio.c", + "remote.c", + "vfs-boot.c", + "vfs-device.c", + "vfs-memory.c", + "vfs.c", + "vfs.h", + ] + deps = [ + "servers/vc", + "//system/udev", + "//system/ulib/ddk", + "//system/ulib/mxio", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/devmgr/api.c b/system/uapp/devmgr/api.c new file mode 100644 index 000000000..e8320e1af --- /dev/null +++ b/system/uapp/devmgr/api.c @@ -0,0 +1,90 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "devmgr.h" + +// These are the API entry-points from drivers +// They must take the devmgr_api_lock before calling devmgr_* internals +// +// Driver code MUST NOT directly call devmgr_* APIs + +void driver_add(mx_driver_t* drv) { + DM_LOCK(); + devmgr_driver_add(drv); + DM_UNLOCK(); +} + +void driver_remove(mx_driver_t* drv) { + DM_LOCK(); + devmgr_driver_remove(drv); + DM_UNLOCK(); +} + +mx_status_t device_create(mx_device_t** dev, mx_driver_t* drv, + const char* name, mx_protocol_device_t* ops) { + mx_status_t r; + DM_LOCK(); + r = devmgr_device_create(dev, drv, name, ops); + DM_UNLOCK(); + return r; +} + +mx_status_t device_init(mx_device_t* dev, mx_driver_t* drv, + const char* name, mx_protocol_device_t* ops) { + mx_status_t r; + DM_LOCK(); + r = devmgr_device_init(dev, drv, name, ops); + DM_UNLOCK(); + return r; +} + +mx_status_t device_add(mx_device_t* dev, mx_device_t* parent) { + mx_status_t r; + DM_LOCK(); + r = devmgr_device_add(dev, parent); + DM_UNLOCK(); + return r; +} + +mx_status_t device_remove(mx_device_t* dev) { + mx_status_t r; + DM_LOCK(); + r = devmgr_device_remove(dev); + DM_UNLOCK(); + return r; +} + +void device_set_bindable(mx_device_t* dev, bool bindable) { + DM_LOCK(); + devmgr_device_set_bindable(dev, bindable); + DM_UNLOCK(); +} + +mx_status_t device_open(mx_device_t* dev, uint32_t flags) { + mx_status_t r; + DM_LOCK(); + r = devmgr_device_open(dev, flags); + DM_UNLOCK(); + return r; +} + +mx_status_t device_close(mx_device_t* dev) { + mx_status_t r; + DM_LOCK(); + r = devmgr_device_close(dev); + DM_UNLOCK(); + return r; +} diff --git a/system/uapp/devmgr/device_internal.h b/system/uapp/devmgr/device_internal.h new file mode 100644 index 000000000..099bbd241 --- /dev/null +++ b/system/uapp/devmgr/device_internal.h @@ -0,0 +1,35 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#define DEV_FLAG_PROTOCOL 1 +// device represents a protocol + +#define DEV_FLAG_DEAD 2 +// Device has been removed and is waiting for refcount zero + +#define DEV_FLAG_UNBINDABLE 4 +// Drivers are not allowed to bind to this device + +#define DEV_FLAG_REMOTE 8 +// This driver is not local to devmgr + +#define DEV_FLAG_BUSY 16 +// Device manager is actively processing this device + +mx_status_t device_open(mx_device_t* dev, uint32_t flags); +mx_status_t device_close(mx_device_t* dev); diff --git a/system/uapp/devmgr/devmgr.c b/system/uapp/devmgr/devmgr.c new file mode 100644 index 000000000..15e19c052 --- /dev/null +++ b/system/uapp/devmgr/devmgr.c @@ -0,0 +1,572 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "devmgr.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include + + +#define TRACE 0 + +#if TRACE +#define xprintf(fmt...) printf(fmt) +#else +#define xprintf(fmt...) \ + do { \ + } while (0) +#endif + +// if true this is a devhost, not the actual devmgr +// and devhost_handle is the rpc link to the real devmgr +bool devmgr_is_remote = false; +bool __dm_locked = false; +mx_handle_t devhost_handle; + +mxr_mutex_t __devmgr_api_lock = MXR_MUTEX_INIT; + +// The Root Driver +static mx_driver_t root_driver = { + .name = "devmgr", +}; + +static mx_driver_t remote_driver = { + .name = "devhost", +}; + +// The Root Device +mx_status_t device_base_get_protocol(mx_device_t* dev, uint32_t proto_id, void** proto) { + if (proto_id == MX_PROTOCOL_DEVICE) { + *proto = dev->ops; + return NO_ERROR; + } + if ((proto_id == dev->protocol_id) && (dev->protocol_id != 0)) { + *proto = dev->protocol_ops; + return NO_ERROR; + } + return ERR_NOT_SUPPORTED; +} + +mx_status_t root_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +mx_status_t root_close(mx_device_t* dev) { + return NO_ERROR; +} + +mx_status_t root_release(mx_device_t* dev) { + return ERR_NOT_SUPPORTED; +} + +static mx_protocol_device_t root_device_proto = { + .get_protocol = device_base_get_protocol, + .open = root_open, + .close = root_close, + .release = root_release, +}; + +static mx_device_t* root_dev = NULL; +static mx_device_t* proto_dev = NULL; + +static struct list_node unmatched_device_list = LIST_INITIAL_VALUE(unmatched_device_list); + +// TODO maybe organize in a tree structure +static struct list_node driver_list = LIST_INITIAL_VALUE(driver_list); + +// handler for messages from device host processes +mxio_dispatcher_t* devmgr_dispatcher; + +#define PNMAX 16 +static const char* proto_name(uint32_t id, char buf[PNMAX]) { + switch (id) { + case MX_PROTOCOL_DEVICE: + return "device"; + case MX_PROTOCOL_CHAR: + return "char"; + case MX_PROTOCOL_CONSOLE: + return "console"; + case MX_PROTOCOL_DISPLAY: + return "display"; + case MX_PROTOCOL_FB: + return "fb"; + case MX_PROTOCOL_PCI: + return "pci"; + case MX_PROTOCOL_USB_DEVICE: + return "usb-device"; + case MX_PROTOCOL_USB_HCI: + return "usb-hci"; + case MX_PROTOCOL_USB_BUS: + return "usb-bus"; + case MX_PROTOCOL_USB_HUB: + return "usb-hub"; + case MX_PROTOCOL_ETHERNET: + return "ethernet"; + case MX_PROTOCOL_BLUETOOTH_HCI: + return "bluetooth-hci"; + default: + snprintf(buf, PNMAX, "<%08x>", id); + return buf; + } +} + +struct devmgr_protocol_list_node { + uint32_t proto_id; + const char* name; + struct list_node device_list; + struct list_node node; +}; + +static struct list_node device_list_by_protocol = LIST_INITIAL_VALUE(device_list_by_protocol); + +extern mx_driver_t* _builtin_drivers; + +#define device_is_bound(dev) (!!dev->owner) + +static struct list_node* devmgr_get_device_list_by_protocol(uint32_t proto_id) { + struct devmgr_protocol_list_node* node = NULL; + struct devmgr_protocol_list_node* protocol = NULL; + // find the protocol in the list + list_for_every_entry (&device_list_by_protocol, node, struct devmgr_protocol_list_node, node) { + if (node->proto_id == proto_id) { + protocol = node; + break; + } + } + // if no list is found, create one for the new protocol + if (!protocol) { + char tmp[PNMAX]; + protocol = (struct devmgr_protocol_list_node*)malloc(sizeof(struct devmgr_protocol_list_node)); + assert(protocol); // TODO out of memory + protocol->proto_id = proto_id; + protocol->name = proto_name(proto_id, tmp); + list_initialize(&protocol->device_list); + list_add_tail(&device_list_by_protocol, &protocol->node); + + // create a device to represent this protocol family + mx_device_t* pdev; + if (devmgr_device_create(&pdev, &root_driver, protocol->name, &root_device_proto) == NO_ERROR) { + pdev->flags |= DEV_FLAG_PROTOCOL | DEV_FLAG_UNBINDABLE; + pdev->protocol_ops = &protocol->device_list; + devmgr_device_add(pdev, proto_dev); + } + } + return &protocol->device_list; +} + +static const char* safename(const char* name) { + return name ? name : ""; +} + +static void dev_ref_release(mx_device_t* dev) { + dev->refcount--; + if (dev->refcount == 0) { + printf("device: %p(%s): ref=0. releasing.\n", dev, safename(dev->name)); + _magenta_handle_close(dev->event); + DM_UNLOCK(); + dev->ops->release(dev); + DM_LOCK(); + } +} + +static mx_status_t devmgr_device_probe(mx_device_t* dev, mx_driver_t* drv) { + mx_status_t status; + + xprintf("devmgr: probe dev=%p(%s) drv=%p(%s)\n", + dev, safename(dev->name), drv, safename(drv->name)); + + for (uint32_t n = 0; n < drv->binding_count; n++) { + if (drv->binding[n].protocol_id == dev->protocol_id) { + goto protocol_match; + } + } + return ERR_NOT_SUPPORTED; + +protocol_match: + if (drv->ops.probe == NULL) { + return ERR_NOT_SUPPORTED; + } + if (drv == dev->driver) { + return ERR_NOT_SUPPORTED; + } + + DM_UNLOCK(); + status = drv->ops.probe(drv, dev); + DM_LOCK(); + if (status) { + return status; + } + + // Determine if we should remote-host this driver + if ((status = devmgr_host_process(dev, drv)) == ERR_NOT_SUPPORTED) { + DM_UNLOCK(); + status = drv->ops.bind(drv, dev); + DM_LOCK(); + if (status < 0) { + return status; + } + dev->owner = drv; + dev->refcount++; + return NO_ERROR; + } + if (status < 0) { + return status; + dev->owner = &remote_driver; + dev->refcount++; + } + return NO_ERROR; +} + +mx_status_t devmgr_device_init(mx_device_t* dev, mx_driver_t* driver, + const char* name, mx_protocol_device_t* ops) { + xprintf("devmgr: init '%s' drv=%p, ops=%p\n", safename(name), driver, ops); + + if (name == NULL) return ERR_INVALID_ARGS; + if (strlen(name) > MX_DEVICE_NAME_MAX) return ERR_INVALID_ARGS; + + memset(dev, 0, sizeof(mx_device_t)); + strncpy(dev->namedata, name, MX_DEVICE_NAME_MAX); + dev->magic = MX_DEVICE_MAGIC; + dev->name = dev->namedata; + dev->ops = ops; + dev->driver = driver; + list_initialize(&dev->device_list); + return NO_ERROR; +} + +mx_status_t devmgr_device_create(mx_device_t** out, mx_driver_t* driver, + const char* name, mx_protocol_device_t* ops) { + mx_device_t* dev = malloc(sizeof(mx_device_t)); + if (dev == NULL) return ERR_NO_MEMORY; + mx_status_t status = devmgr_device_init(dev, driver, name, ops); + if (status) { + free(dev); + } else { + *out = dev; + } + return status; +} + +void devmgr_device_set_bindable(mx_device_t* dev, bool bindable) { + if (bindable) { + dev->flags &= ~DEV_FLAG_UNBINDABLE; + } else { + dev->flags |= DEV_FLAG_UNBINDABLE; + } +} + +mx_status_t devmgr_device_add(mx_device_t* dev, mx_device_t* parent) { + if (dev == NULL) return ERR_INVALID_ARGS; + if (parent == NULL) { + if (devmgr_is_remote) { + //printf("device add: %p(%s): not allowed in devhost\n", dev, safename(dev->name)); + return ERR_NOT_SUPPORTED; + } + parent = root_dev; + } + + if (parent->flags & DEV_FLAG_DEAD) { + printf("device add: %p: is dead, cannot add child %p\n", parent, dev); + return ERR_OBJECT_DESTROYED; + } + xprintf("%s: device add: %p(%s) parent=%p(%s)\n", devmgr_is_remote ? "devhost" : "devmgr", + dev, safename(dev->name), parent, safename(parent->name)); + + if (dev->ops == NULL) { + printf("device add: %p(%s): NULL ops\n", dev, safename(dev->name)); + return ERR_INVALID_ARGS; + } + if ((dev->ops->get_protocol == NULL) || (dev->ops->open == NULL) || + (dev->ops->close == NULL) || (dev->ops->release == NULL)) { + printf("device add: %p(%s): incomplete ops\n", dev, safename(dev->name)); + return ERR_INVALID_ARGS; + } + + // Don't create event handle if we alredy have one + if (dev->event == MX_HANDLE_INVALID && (dev->event = _magenta_event_create(0)) < 0) { + printf("device add: %p(%s): cannot create event: %d\n", + dev, safename(dev->name), dev->event); + return dev->event; + } + + dev->flags |= DEV_FLAG_BUSY; + + // add to the protocol list + if (proto_dev && dev->protocol_id) { + struct list_node* protocol = devmgr_get_device_list_by_protocol(dev->protocol_id); + list_add_tail(protocol, &dev->pnode); + } + + // add to the device tree + dev->parent = parent; + dev->parent->refcount++; + + // this is balanced by end of devmgr_device_remove + dev->refcount++; + list_add_tail(&parent->device_list, &dev->node); + + if (devmgr_is_remote) { + mx_status_t r = devhost_add(dev, parent); + if (r < 0) { + printf("devhost: remote add failed %d\n", r); + dev->flags &= (~DEV_FLAG_BUSY); + return r; + } + } + + if (dev->flags & DEV_FLAG_REMOTE) { + xprintf("dev %p is REMOTE\n", dev); + // for now devhost'd devices are openable but not bindable + dev->flags |= DEV_FLAG_UNBINDABLE; + } + + if ((dev->flags & DEV_FLAG_UNBINDABLE) == 0) { + if (!device_is_bound(dev)) { + // probe the device with all drivers and initialize if the probe is successful + mx_driver_t* drv = NULL; + list_for_every_entry (&driver_list, drv, mx_driver_t, node) { + if (devmgr_device_probe(dev, drv) == NO_ERROR) { + break; + } + } + } + + // if no driver is bound, add the device to the unmatched list + if (!device_is_bound(dev)) { + list_add_tail(&unmatched_device_list, &dev->unode); + } + } + + dev->flags &= (~DEV_FLAG_BUSY); + return NO_ERROR; +} + +mx_status_t devmgr_device_remove(mx_device_t* dev) { + if (dev->flags & DEV_FLAG_DEAD) { + printf("device: %p: cannot be removed (already dead)\n", dev); + return ERR_INVALID_ARGS; + } + if (dev->flags & DEV_FLAG_BUSY) { + printf("device: %p: cannot be removed (busy)\n", dev); + return ERR_BAD_STATE; + } + printf("device: %p: is being removed\n", dev); + if (!list_is_empty(&dev->device_list)) { + printf("device: %p: still has children! now orphaned.\n", dev); + } + dev->flags |= DEV_FLAG_DEAD; + if (dev->parent) { + list_delete(&dev->node); + dev_ref_release(dev->parent); + } + if (list_in_list(&dev->pnode)) { + list_delete(&dev->pnode); + } + if (list_in_list(&dev->unode)) { + list_delete(&dev->unode); + } + if (dev->owner) { + if (dev->owner->ops.unbind) { + DM_UNLOCK(); + dev->owner->ops.unbind(dev->owner, dev); + DM_LOCK(); + } + dev->owner = NULL; + dev_ref_release(dev); + } + + // this must be last, since it may result in the device structure being destroyed + dev_ref_release(dev); + + return NO_ERROR; +} + +mx_status_t devmgr_device_open(mx_device_t* dev, uint32_t flags) { + if (dev->flags & DEV_FLAG_DEAD) { + printf("device open: %p(%s) is dead!\n", dev, safename(dev->name)); + return ERR_OBJECT_DESTROYED; + } + dev->refcount++; + mx_status_t r; + DM_UNLOCK(); + r = dev->ops->open(dev, flags); + DM_LOCK(); + return r; +} + +mx_status_t devmgr_device_close(mx_device_t* dev) { + mx_status_t r; + DM_UNLOCK(); + r = dev->ops->close(dev); + DM_LOCK(); + dev_ref_release(dev); + return r; +} + +mx_status_t devmgr_driver_add(mx_driver_t* drv) { + xprintf("driver add: %p(%s)\n", drv, safename(drv->name)); + + if (drv->ops.init) { + mx_status_t r; + DM_UNLOCK(); + r = drv->ops.init(drv); + DM_LOCK(); + if (r < 0) return r; + } + + // add the driver to the driver list + list_add_tail(&driver_list, &drv->node); + + // probe unmatched devices with the driver and initialize if the probe is successful + mx_device_t* dev = NULL; + mx_device_t* temp = NULL; + list_for_every_entry_safe (&unmatched_device_list, dev, temp, mx_device_t, unode) { + if (devmgr_device_probe(dev, drv) == NO_ERROR) { + break; + } + } + return NO_ERROR; +} + +mx_status_t devmgr_driver_remove(mx_driver_t* drv) { + // TODO: implement + return ERR_NOT_SUPPORTED; +} + +extern mx_driver_t __start_builtin_drivers[] __WEAK; +extern mx_driver_t __stop_builtin_drivers[] __WEAK; + +void devmgr_init(bool devhost) { + xprintf("devmgr: init\n"); + + devmgr_is_remote = devhost; + + // init device tree + device_create(&root_dev, &root_driver, "root", &root_device_proto); + + if (!devhost) { + // init a place to hang protocols + device_create(&proto_dev, &root_driver, "protocol", &root_device_proto); + proto_dev->flags |= DEV_FLAG_UNBINDABLE; + device_add(proto_dev, root_dev); + } + + mxio_dispatcher_create(&devmgr_dispatcher, devhost ? mxio_rio_handler : devmgr_handler); +} + +void devmgr_init_builtin_drivers(void) { + mx_driver_t* drv; + for (drv = __start_builtin_drivers; drv < __stop_builtin_drivers; drv++) { + if (devmgr_is_remote) { + if (drv->binding_count == 0) { + // root-level devices not loaded on devhost instances + continue; + } + } + driver_add(drv); + } +} + +void devmgr_handle_messages(void) { + mxio_dispatcher_run(devmgr_dispatcher); +} + +static void devmgr_dump_device(uint level, mx_device_t* dev) { + for (uint i = 0; i < level; i++) { + printf(" "); + } + printf("%c %s drv@%p", list_is_empty(&dev->device_list) ? '|' : '+', dev->name, dev->driver); + if (dev->driver) printf(" (%s)", dev->driver->name); + if (dev->owner) printf(" owner: %s", dev->owner->name); + printf("\n"); +} + +static void devmgr_dump_recursive(uint level, mx_device_t* _dev) { + devmgr_dump_device(level, _dev); + mx_device_t* dev = NULL; + list_for_every_entry (&_dev->device_list, dev, mx_device_t, node) { + devmgr_dump_recursive(level + 1, dev); + } +} + +static void devmgr_dump_protocols(void) { + struct devmgr_protocol_list_node* protocol = NULL; + list_for_every_entry (&device_list_by_protocol, protocol, struct devmgr_protocol_list_node, node) { + printf("%s:\n", protocol->name); + mx_device_t* dev = NULL; + list_for_every_entry (&protocol->device_list, dev, mx_device_t, pnode) { + printf(" %s drv@%p\n", dev->name, dev->driver); + } + } +} + +void devmgr_dump(void) { + mx_device_t* dev = NULL; + DM_LOCK(); + printf("---- Device Tree ----\n"); + devmgr_dump_recursive(0, root_dev); + printf("---- End Device Tree ----\n"); + printf("\n"); + printf("---- Protocols ----\n"); + devmgr_dump_protocols(); + printf("---- End Protocols ----\n"); + printf("\n"); + printf("---- Unmatched Devices -----\n"); + list_for_every_entry(&unmatched_device_list, dev, mx_device_t, unode) { + if (!dev->owner) { + devmgr_dump_device(0, dev); + } + } + printf("---- End Unmatched Devices ----\n"); + printf("\n"); + mx_driver_t* drv = NULL; + printf("---- Driver List ----\n"); + list_for_every_entry (&driver_list, drv, mx_driver_t, node) { + printf("%s\n", drv->name); + } + printf("---- End Driver List ----\n"); + DM_UNLOCK(); +} + +mx_device_t* devmgr_device_root(void) { + return root_dev; +} + +mx_status_t devmgr_control(const char* cmd) { + if (!strcmp(cmd, "dump")) { + devmgr_dump(); + return NO_ERROR; + } if (!strcmp(cmd, "crash")) { + *((int*) 0x1234) = 42; + return NO_ERROR; + } else { + return ERR_NOT_SUPPORTED; + } +} + diff --git a/system/uapp/devmgr/devmgr.h b/system/uapp/devmgr/devmgr.h new file mode 100644 index 000000000..b343a5458 --- /dev/null +++ b/system/uapp/devmgr/devmgr.h @@ -0,0 +1,122 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include "device_internal.h" + +#include + +#include + +void cprintf(const char* fmt, ...); + +// Nothing outside of devmgr/main.c and devmgr/devmgr.c +// should be calling devmgr_*() APIs, as this could +// violate the internal locking design. + +// Safe external APIs are in device.h and device_internal.h + +mx_status_t devmgr_driver_add(mx_driver_t* driver); +mx_status_t devmgr_driver_remove(mx_driver_t* driver); + +mx_status_t devmgr_device_add(mx_device_t* dev, mx_device_t* parent); +mx_status_t devmgr_device_remove(mx_device_t* dev); +mx_status_t devmgr_device_create(mx_device_t** dev, mx_driver_t* driver, + const char* name, mx_protocol_device_t* ops); +mx_status_t devmgr_device_init(mx_device_t* dev, mx_driver_t* driver, + const char* name, mx_protocol_device_t* ops); +void devmgr_device_set_bindable(mx_device_t* dev, bool bindable); + +mx_device_t* devmgr_device_root(void); + +mx_status_t devmgr_device_open(mx_device_t* dev, uint32_t flags); +mx_status_t devmgr_device_close(mx_device_t* dev); + +mx_status_t devmgr_control(const char* cmd); + +// Internals +void devmgr_init(bool hostproc); +void devmgr_init_builtin_drivers(void); +void devmgr_dump(void); +void devmgr_handle_messages(void); + +void devmgr_io_init(void); +void devmgr_vfs_init(void* bootfs, size_t len); +void devmgr_launch(const char* app, const char* device); +void devmgr_launch_devhost(mx_handle_t h, const char* arg0, const char* arg1); + +int devmgr_get_pcidev_index(mx_device_t* dev); +mx_status_t devmgr_create_pcidev(mx_device_t** out, uint32_t index); + +typedef struct devhost_msg devhost_msg_t; +struct devhost_msg { + uint32_t op; + int32_t arg; + uintptr_t device_id; + uint32_t protocol_id; + char namedata[MX_DEVICE_NAME_MAX+1]; +}; + +#define DH_OP_STATUS 0 +#define DH_OP_ADD 1 +#define DH_OP_REMOVE 2 + +mx_status_t devmgr_host_process(mx_device_t* dev, mx_driver_t* drv); +mx_status_t devmgr_handler(mx_handle_t h, void* cb, void* cookie); + +// routines devhost uses to talk to devmgr +mx_status_t devhost_add(mx_device_t* dev, mx_device_t* parent); +mx_status_t devhost_remove(mx_device_t* dev); + +extern bool devmgr_is_remote; +extern mx_handle_t devhost_handle; +extern mxr_mutex_t __devmgr_api_lock; + +extern bool __dm_locked; + +#if 0 +static inline void __DM_DIE(const char* fn, int ln) { + cprintf("OOPS: %s: %d\n", fn, ln); + *((int*) 0x3333) = 1; +} +static inline void __DM_LOCK(const char* fn, int ln) { + //cprintf(devmgr_is_remote ? "X" : "+"); + if (__dm_locked) __DM_DIE(fn, ln); + mxr_mutex_lock(&__devmgr_api_lock); + cprintf("LOCK: %s: %d\n", fn, ln); + __dm_locked = true; +} + +static inline void __DM_UNLOCK(const char* fn, int ln) { + cprintf("UNLK: %s: %d\n", fn, ln); + //cprintf(devmgr_is_remote ? "x" : "-"); + if (!__dm_locked) __DM_DIE(fn, ln); + __dm_locked = false; + mxr_mutex_unlock(&__devmgr_api_lock); +} + +#define DM_LOCK() __DM_LOCK(__FILE__,__LINE__) +#define DM_UNLOCK() __DM_UNLOCK(__FILE__,__LINE__) +#else +static inline void DM_LOCK(void) { + mxr_mutex_lock(&__devmgr_api_lock); +} + +static inline void DM_UNLOCK(void) { + mxr_mutex_unlock(&__devmgr_api_lock); +} +#endif \ No newline at end of file diff --git a/system/uapp/devmgr/dmctl.c b/system/uapp/devmgr/dmctl.c new file mode 100644 index 000000000..21d172f63 --- /dev/null +++ b/system/uapp/devmgr/dmctl.c @@ -0,0 +1,82 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include +#include + +#include "devmgr.h" + +static ssize_t dmctl_read(mx_device_t* dev, void* buf, size_t count) { + return NO_ERROR; +} + +static ssize_t dmctl_write(mx_device_t* dev, const void* buf, size_t count) { + char cmd[128]; + if (count < sizeof(cmd)) { + memcpy(cmd, buf, count); + cmd[count] = 0; + } else { + return ERR_INVALID_ARGS; + } + return devmgr_control(cmd); +} + +static mx_protocol_char_t dmctl_char_proto = { + .read = dmctl_read, + .write = dmctl_write, +}; + +static mx_status_t dmctl_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t dmctl_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t dmctl_release(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_protocol_device_t dmctl_device_proto = { + .get_protocol = device_base_get_protocol, + .open = dmctl_open, + .close = dmctl_close, + .release = dmctl_release, +}; + +mx_status_t dmctl_init(mx_driver_t* driver) { + mx_device_t* dev; + if (device_create(&dev, driver, "dmctl", &dmctl_device_proto) == NO_ERROR) { + dev->protocol_id = MX_PROTOCOL_CHAR; + dev->protocol_ops = &dmctl_char_proto; + if (device_add(dev, NULL) < 0) { + free(dev); + } + } + return NO_ERROR; +} + +mx_driver_t _driver_dmctl BUILTIN_DRIVER = { + .name = "dmctl", + .ops = { + .init = dmctl_init, + }, +}; diff --git a/system/uapp/devmgr/main.c b/system/uapp/devmgr/main.c new file mode 100644 index 000000000..21ce9c756 --- /dev/null +++ b/system/uapp/devmgr/main.c @@ -0,0 +1,129 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devmgr.h" + +#define VC_COUNT 4 + +int devicehost(int argc, char** argv) { + devhost_handle = mxr_process_get_handle(MX_HND_INFO(MX_HND_TYPE_USER1, 0)); + if (devhost_handle <= 0) { + printf("devhost: no rpc handle?!\n"); + return -1; + } + if (argc != 3) { + return -1; + } + if (!strncmp(argv[1], "pci=", 4)) { + uint32_t index = strtoul(argv[1] + 4, NULL, 10); + uintptr_t id = strtoull(argv[2], NULL, 10); + + printf("devhost: pci host %d: driver: %p\n", index, (void*) id); + devmgr_init(true); + mx_device_t* pcidev; + if (devmgr_create_pcidev(&pcidev, index)) { + printf("devhost: cannot create pci device\n"); + return -1; + } + device_add(pcidev, devmgr_device_root()); + printf("devhost: load drivers\n"); + devmgr_init_builtin_drivers(); + printf("devhost: message loop\n"); + devmgr_handle_messages(); + } + printf("devhost: exiting\n"); + return 0; +} + +int console_starter(void* arg) { + printf("devmgr: vc startup\n"); + // don't start a shell on vc0, since it is the debug console + for (uint i = 1; i < VC_COUNT;) { + int fd; + char name[64]; + snprintf(name, sizeof(name), "/dev/protocol/char/vc%u", i); + //printf("? %s\n", name); + if ((fd = open(name, O_RDWR)) < 0) { + _magenta_nanosleep(100000000ULL); + continue; + } + close(fd); + devmgr_launch("/boot/bin/mxsh", name); + i++; + } + return 0; +} + +int main(int argc, char** argv) { + mx_handle_t bootfs_vmo; + mx_status_t status; + uint64_t bootfs_size; + uintptr_t bootfs_val; + + devmgr_io_init(); + + if (argc > 1) { + return devicehost(argc, argv); + } + + bootfs_vmo = mxr_process_get_handle(MX_HND_INFO(MX_HND_TYPE_USER0, 0)); + status = _magenta_vm_object_get_size(bootfs_vmo, &bootfs_size); + if (status < 0) { + cprintf("devmgr: failed to get bootfs size (%d)\n", status); + return -1; + } + status = _magenta_process_vm_map(0, bootfs_vmo, 0, bootfs_size, + &bootfs_val, MX_VM_FLAG_PERM_READ); + if (status < 0) { + cprintf("devmgr: failed to map bootfs (%d)\n", status); + return -1; + } + + printf("devmgr: main()\n"); + devmgr_init(false); + devmgr_vfs_init((void*)bootfs_val, bootfs_size); + + printf("devmgr: load drivers\n"); + devmgr_init_builtin_drivers(); + + mxr_thread_t *t; + if ((mxr_thread_create(console_starter, NULL, "console-starter", &t)) == 0) { + mxr_thread_detach(t); + } + +#if !WITH_APP_SHELL + // if no kernel shell on serial uart, start a mxsh there + printf("devmgr: shell startup\n"); + devmgr_launch("/boot/bin/mxsh", "/dev/console"); +#endif + + devmgr_launch("/boot/bin/netsvc", "/dev/console"); + + devmgr_handle_messages(); + printf("devmgr: message handler returned?!\n"); + return 0; +} diff --git a/system/uapp/devmgr/mxio.c b/system/uapp/devmgr/mxio.c new file mode 100644 index 000000000..039f62105 --- /dev/null +++ b/system/uapp/devmgr/mxio.c @@ -0,0 +1,149 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "devmgr.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "vfs.h" + +mx_status_t vnd_get_node(vnode_t** out, mx_device_t* dev); + +vnode_t* vnb_get_root(void); +mx_status_t vnb_add_file(const char* path, void* data, size_t len); +mx_status_t vnb_mount_at(vnode_t* vn, const char* dirname); + +vnode_t* mem_get_root(void); + +typedef struct bootfile bootfile_t; +struct bootfile { + bootfile_t* next; + const char* name; + void* data; + size_t len; +}; + +static uint8_t* bootfs = NULL; +static int bootfiles_count = 0; + +static void callback(const char* path, size_t off, size_t len) { + //printf("bootfs: %s @%zd (%zd bytes)\n", path, off, len); + char tmp[1024]; + snprintf(tmp, sizeof(tmp), "boot/%s", path); + vnb_add_file(tmp, bootfs + off, len); +} + +void devmgr_launch(const char* app, const char* device) { + mx_handle_t hnd[5 * VFS_MAX_HANDLES]; + uint32_t ids[5 * VFS_MAX_HANDLES]; + unsigned n = 1; + mx_status_t r; + + ids[0] = MX_HND_TYPE_MXIO_ROOT; + hnd[0] = vfs_create_root_handle(); + + // TODO: correct open flags once we have them + if ((r = vfs_open_handles(hnd + n, ids + n, 0, device, 0)) < 0) { + goto fail; + } + n += r; + if ((r = vfs_open_handles(hnd + n, ids + n, 1, device, 0)) < 0) { + goto fail; + } + n += r; + if ((r = vfs_open_handles(hnd + n, ids + n, 2, device, 0)) < 0) { + goto fail; + } + n += r; + printf("devmgr: launch shell on %s\n", device); + mxio_start_process_etc(1, (char**)&app, n, hnd, ids); + return; +fail: + while (n > 0) { + n--; + _magenta_handle_close(hnd[n]); + } +} + +void devmgr_launch_devhost(mx_handle_t h, const char* arg0, const char* arg1) { + const char* name = "/boot/bin/devmgr"; + const char* args[3] = { name, arg0, arg1, }; + mx_handle_t hnd[2]; + uint32_t ids[2]; + ids[0] = MX_HND_TYPE_MXIO_ROOT; + hnd[0] = vfs_create_root_handle(); + ids[1] = MX_HND_TYPE_USER1; + hnd[1] = h; + printf("devmgr: launch host: %s %s\n", arg0, arg1); + mxio_start_process_etc(3, (char**)args, 2, hnd, ids); +} + +void devmgr_io_init(void) { + // setup stdout + uint32_t flags = devmgr_is_remote ? MX_LOG_FLAG_DEVICE : MX_LOG_FLAG_DEVMGR; + mx_handle_t h; + if ((h = _magenta_log_create(flags)) < 0) { + return; + } + mxio_t* logger; + if ((logger = mxio_logger_create(h)) == NULL) { + return; + } + close(1); + mxio_bind_to_fd(logger, 1); +} + +void devmgr_vfs_init(void* _bootfs, size_t len) { + printf("devmgr: vfs init\n"); + + // setup bootfs if present + if (_bootfs != NULL) { + bootfs = _bootfs; + bootfs_parse(bootfs, len, callback); + if (bootfiles_count) { + printf("devmgr: bootfs contains %d file%s\n", + bootfiles_count, (bootfiles_count == 1) ? "" : "s"); + } + } + + // init vfs, bootfs is root + vfs_init(vnb_get_root()); + + // install devfs at /dev + vnode_t* vn; + if (vnd_get_node(&vn, devmgr_device_root()) == NO_ERROR) { + vnb_mount_at(vn, "dev"); + } + + // install memfs at /tmp + vnb_mount_at(mem_get_root(), "tmp"); + + // give our own process access to files in the vfs + mx_handle_t h = vfs_create_root_handle(); + if (h > 0) { + mxio_install_root(mxio_remote_create(h, 0)); + } +} diff --git a/system/uapp/devmgr/remote.c b/system/uapp/devmgr/remote.c new file mode 100644 index 000000000..f22e3038c --- /dev/null +++ b/system/uapp/devmgr/remote.c @@ -0,0 +1,381 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "devmgr.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#define SINGLE_PROCESS 0 + +static mx_driver_t proxy_driver = { + .name = "proxy", +}; + +extern mxio_dispatcher_t* devmgr_dispatcher; + +static list_node_t devhost_list = LIST_INITIAL_VALUE(devhost_list); + +typedef struct devhost devhost_t; +typedef struct proxy proxy_t; + +struct proxy { + mx_device_t device; + list_node_t node; +}; + +static mx_status_t proxy_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t proxy_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t proxy_release(mx_device_t* dev) { + return ERR_NOT_SUPPORTED; +} + +static mx_protocol_device_t proxy_device_proto = { + .get_protocol = device_base_get_protocol, + .open = proxy_open, + .close = proxy_close, + .release = proxy_release, +}; + +struct devhost { + mx_handle_t handle; + // message pipe the devhost uses to make requests of devmgr; + + list_node_t devices; + // list of remoted devices associated with this devhost + + list_node_t node; + // entry in devhost_list + + mx_device_t* root; + // the local object that is the root (id 0) object to remote +}; + +static mx_device_t* devhost_id_to_dev(devhost_t* dh, uintptr_t id) { + proxy_t* proxy; + mx_device_t* dev = (mx_device_t*) id; + list_for_every_entry(&dh->devices, proxy, proxy_t, node) { + if (&proxy->device == dev) { + return dev; + } + } + return NULL; +} + +static mx_status_t devhost_remote_add(devhost_t* dh, devhost_msg_t* msg, mx_handle_t h) { + mx_status_t r = NO_ERROR; + mx_device_t* dev; + + if (msg->device_id) { + dev = devhost_id_to_dev(dh, msg->device_id); + } else { + dev = dh->root; + } + //printf("devmgr: remote %p add %p %x: dev=%p\n", dh, (void*)msg->device_id, h, dev); + if (dev == NULL) { + r = ERR_NOT_FOUND; + goto fail0; + } + proxy_t* proxy; + if ((proxy = malloc(sizeof(proxy_t))) == NULL) { + r = ERR_NO_MEMORY; + goto fail0; + } + if ((r = devmgr_device_init(&proxy->device, &proxy_driver, + msg->namedata, &proxy_device_proto))< 0) { + goto fail1; + } + proxy->device.remote = h; + proxy->device.flags |= DEV_FLAG_REMOTE; + proxy->device.protocol_id = msg->protocol_id; + if ((r = devmgr_device_add(&proxy->device, dev)) < 0) { + printf("devmgr: remote add failed %d\n", r); + goto fail1; + } + list_add_tail(&dh->devices, &proxy->node); + + msg->device_id = (uintptr_t) &proxy->device; + return NO_ERROR; +fail1: + free(proxy); +fail0: + _magenta_handle_close(h); + return r; +} + +static mx_status_t devhost_remote_remove(devhost_t* dh, devhost_msg_t* msg) { + mx_device_t* dev = devhost_id_to_dev(dh, msg->device_id); + //printf("devmgr: remote %p remove %p: dev=%p\n", dh, (void*)msg->device_id, dev); + if (dev == NULL) { + return ERR_NOT_FOUND; + } + return ERR_NOT_SUPPORTED; +} + +static void devhost_remote_died(devhost_t* dh) { + printf("devmgr: remote %p died\n", dh); +} + +// handle devhost_msgs from devhosts +mx_status_t devmgr_handler(mx_handle_t h, void* cb, void* cookie) { + devhost_t* dh = cookie; + devhost_msg_t msg; + mx_handle_t hnd; + mx_status_t r; + + if (h == 0) { + devhost_remote_died(dh); + return NO_ERROR; + } + + uint32_t dsz = sizeof(msg); + uint32_t hcount = 1; + if ((r = _magenta_message_read(h, &msg, &dsz, &hnd, &hcount, 0)) < 0) { + return r; + } + if (dsz != sizeof(msg)) { + goto fail; + } + switch (msg.op) { + case DH_OP_ADD: + if (hcount != 1) { + goto fail; + } + DM_LOCK(); + msg.arg = devhost_remote_add(dh, &msg, hnd); + DM_UNLOCK(); + break; + case DH_OP_REMOVE: + if (hcount != 0) { + goto fail; + } + DM_LOCK(); + msg.arg = devhost_remote_remove(dh, &msg); + DM_UNLOCK(); + break; + default: + goto fail; + } + msg.op = DH_OP_STATUS; + if ((r = _magenta_message_write(h, &msg, sizeof(msg), NULL, 0, 0)) < 0) { + return r; + } + return NO_ERROR; +fail: + printf("devmgr_handler: error %d\n", r); + if (hcount) { + _magenta_handle_close(hnd); + } + return ERR_IO; +} + +static mx_status_t devhost_rpc(mx_handle_t h, devhost_msg_t* msg, mx_handle_t harg) { + mx_status_t r; + if ((r = _magenta_message_write(h, msg, sizeof(*msg), &harg, harg ? 1 : 0, 0)) < 0) { + return r; + } + mx_signals_t pending; + if ((r = _magenta_handle_wait_one(h, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL)) < 0) { + return r; + } + if (pending & MX_SIGNAL_PEER_CLOSED) { + return ERR_CHANNEL_CLOSED; + } + uint32_t dsz = sizeof(*msg); + if ((r = _magenta_message_read(h, msg, &dsz, NULL, NULL, 0)) < 0) { + return r; + } + if ((dsz != sizeof(*msg)) || (msg->op != DH_OP_STATUS)) { + return ERR_IO; + } + return msg->arg; +} + +static mx_status_t rio_handler(mx_rio_msg_t* msg, void* cookie) { + mx_device_t* dev = cookie; + uint32_t len = msg->datalen; + int32_t arg = msg->arg; + msg->datalen = 0; + + for (unsigned i = 0; i < msg->hcount; i++) { + _magenta_handle_close(msg->handle[i]); + } + + switch (MX_RIO_OP(msg->op)) { + case MX_RIO_CLOSE: + return NO_ERROR; + case MX_RIO_CLONE: { + mx_handle_t h0, h1; + if ((h0 = _magenta_message_pipe_create(&h1)) < 0) { + return h0; + } + msg->handle[0] = h0; + if (dev->event > 0) { + if ((msg->handle[1] = _magenta_handle_duplicate(dev->event)) < 0) { + _magenta_handle_close(h0); + _magenta_handle_close(h1); + return msg->handle[1]; + } + msg->hcount = 2; + } else { + msg->hcount = 1; + } + mxio_dispatcher_add(devmgr_dispatcher, h1, rio_handler, dev); + msg->off = MXIO_PROTOCOL_REMOTE; + return NO_ERROR; + } + case MX_RIO_READ: { + mx_status_t r; + mx_protocol_char_t* proto; + if ((r = device_get_protocol(dev, MX_PROTOCOL_CHAR, (void**) &proto)) < 0) { + return r; + } + if ((r = proto->read(dev, msg->data, arg)) > 0) { + msg->datalen = r; + } + msg->off = 0; + return r; + } + case MX_RIO_WRITE: { + mx_status_t r; + mx_protocol_char_t* proto; + if ((r = device_get_protocol(dev, MX_PROTOCOL_CHAR, (void**) &proto)) < 0) { + return r; + } + if ((r = proto->write(dev, msg->data, len)) > 0) { + msg->off = 0; + } + return r; + } + case MX_RIO_IOCTL: { + mx_status_t r; + mx_protocol_char_t* proto; + if (len > MXIO_IOCTL_MAX_INPUT || arg > (ssize_t)sizeof(msg->data)) { + return ERR_INVALID_ARGS; + } + if ((r = device_get_protocol(dev, MX_PROTOCOL_CHAR, (void**) &proto)) < 0) { + return r; + } + if (!proto->ioctl) { + return ERR_NOT_SUPPORTED; + } + + char in_buf[MXIO_IOCTL_MAX_INPUT]; + memcpy(in_buf, msg->data, len); + if ((r = proto->ioctl(dev, msg->off, in_buf, len, msg->data, arg)) > 0) { + msg->datalen = r; + } + msg->off = 0; + return r; + } + default: + return ERR_NOT_SUPPORTED; + } +} + + +mx_status_t devhost_add(mx_device_t* dev, mx_device_t* parent) { + mx_handle_t h0, h1; + if ((h0 = _magenta_message_pipe_create(&h1)) < 0) { + return h0; + } + //printf("devhost_add(%p, %p)\n", dev, parent); + devhost_msg_t msg; + msg.op = DH_OP_ADD; + msg.arg = 0; + msg.device_id = parent->remote_id; + msg.protocol_id = dev->protocol_id; + memcpy(msg.namedata, dev->namedata, sizeof(dev->namedata)); + mx_status_t r = devhost_rpc(devhost_handle, &msg, h1); + //printf("devhost_add() %d\n", r); + + if (r == NO_ERROR) { + //printf("devhost: dev=%p remoted\n", dev); + mxio_dispatcher_add(devmgr_dispatcher, h0, rio_handler, dev); + dev->remote_id = msg.device_id; + } else { + _magenta_handle_close(h0); + } + return r; +} + +mx_status_t devhost_remove(mx_device_t* dev) { + devhost_msg_t msg; + memset(&msg, 0, sizeof(msg)); + msg.op = DH_OP_REMOVE; + msg.device_id = (uintptr_t) dev->remote_id; + return devhost_rpc(devhost_handle, &msg, 0); +} + + +mx_status_t devmgr_host_process(mx_device_t* dev, mx_driver_t* drv) { +#if SINGLE_PROCESS + return ERR_NOT_SUPPORTED; +#else + if (devmgr_is_remote) { + return ERR_NOT_SUPPORTED; + } + // pci drivers get their own host process + int index = devmgr_get_pcidev_index(dev); + if (index < 0) { + return ERR_NOT_SUPPORTED; + } + + devhost_t* dh = calloc(1, sizeof(devhost_t)); + if (dh == NULL) { + return ERR_NO_MEMORY; + } + + mx_handle_t h0, h1; + if ((h0 = _magenta_message_pipe_create(&h1)) < 0) { + free(dh); + return h0; + } + + dh->root = dev; + dh->handle = h0; + list_initialize(&dh->devices); + list_add_tail(&devhost_list, &dh->node); + mxio_dispatcher_add(devmgr_dispatcher, h0, NULL, dh); + + char arg0[32]; + char arg1[32]; + snprintf(arg0, 32, "pci=%d", index); + snprintf(arg1, 32, "%p", drv); + devmgr_launch_devhost(h1, arg0, arg1); + //TODO: make drv ineligible for further probing? + return 0; +#endif +} + diff --git a/system/uapp/devmgr/rules.mk b/system/uapp/devmgr/rules.mk new file mode 100644 index 000000000..dba64dc71 --- /dev/null +++ b/system/uapp/devmgr/rules.mk @@ -0,0 +1,63 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_NAME := devmgr + +MODULE_TYPE := userapp + +# grab sources for all built-in drivers +# someday these will become dynamically loadable modules +LOCAL_SAVEDIR := $(LOCAL_DIR) +DRIVER_SRCS := +DRIVERS := $(patsubst %/rules.mk,%,$(wildcard system/udev/*/driver.mk)) +DRIVERS += $(patsubst %/rules.mk,%,$(wildcard external/udev/*/driver.mk)) +-include $(DRIVERS) +LOCAL_DIR := $(LOCAL_SAVEDIR) + +MODULE_SRCS := \ + $(DRIVER_SRCS) \ + +MODULE_SRCS += \ + $(LOCAL_DIR)/servers/vc/vc-char.c \ + $(LOCAL_DIR)/servers/vc/vc-console.c \ + $(LOCAL_DIR)/servers/vc/vc-device.c \ + $(LOCAL_DIR)/servers/vc/vc-gfx.c \ + $(LOCAL_DIR)/servers/vc/textcon.c \ + $(LOCAL_DIR)/servers/vc/main.c \ + $(LOCAL_DIR)/devmgr.c \ + $(LOCAL_DIR)/remote.c \ + $(LOCAL_DIR)/dmctl.c \ + $(LOCAL_DIR)/api.c \ + $(LOCAL_DIR)/vfs.c \ + $(LOCAL_DIR)/vfs-device.c \ + $(LOCAL_DIR)/vfs-boot.c \ + $(LOCAL_DIR)/vfs-memory.c \ + $(LOCAL_DIR)/mxio.c \ + $(LOCAL_DIR)/main.c + +MODULE_DEPS := \ + ulib/musl \ + ulib/ddk \ + ulib/mxio \ + ulib/gfx \ + ulib/font \ + ulib/runtime \ + ulib/mxu \ + ulib/magenta + +include make/module.mk diff --git a/system/uapp/devmgr/servers/vc/BUILD.gn b/system/uapp/devmgr/servers/vc/BUILD.gn new file mode 100644 index 000000000..9c0b48817 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/BUILD.gn @@ -0,0 +1,33 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("vc") { + sources = [ + "main.c", + "textcon.c", + "textcon.h", + "vc-char.c", + "vc-console.c", + "vc-device.c", + "vc-gfx.c", + "vc.h", + "vcdebug.h", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/font", + "//system/ulib/mxio", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/devmgr/servers/vc/main.c b/system/uapp/devmgr/servers/vc/main.c new file mode 100644 index 000000000..6a21d03cc --- /dev/null +++ b/system/uapp/devmgr/servers/vc/main.c @@ -0,0 +1,393 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../vfs.h" + +#define VCDEBUG 1 + +#include "vc.h" +#include "vcdebug.h" + +static gfx_surface hw_gfx; // framebuffer +static mxr_thread_t* input_thread; // input wait thread +static mxr_thread_t* logreader_thread; + +static struct list_node vc_list = LIST_INITIAL_VALUE(vc_list); +static vc_device_t* debug_vc; +static vc_device_t* active_vc; +static uint active_vc_index; +static uint vc_count; +static mxr_mutex_t active_lock = MXR_MUTEX_INIT; + +// TODO create dynamically +#define VC_COUNT 4 + +// TODO need a better way to find the display/input devices +#if PROJECT_MAGENTA_QEMU_X86_64 +static const char* input_dev = "/dev/protocol/char/i8042_keyboard"; +#elif PROJECT_MAGENTA_PC_UEFI +static const char* input_dev = "/dev/protocol/char/i8042_keyboard"; +#else +static const char* input_dev = NULL; +#endif + +// TODO move this to ulib/gfx +static gfx_format display_format_to_gfx_format(uint display_format) { + gfx_format format; + switch (display_format) { + case MX_DISPLAY_FORMAT_RGB_565: + format = GFX_FORMAT_RGB_565; + break; + case MX_DISPLAY_FORMAT_RGB_332: + format = GFX_FORMAT_RGB_332; + break; + case MX_DISPLAY_FORMAT_RGB_2220: + format = GFX_FORMAT_RGB_2220; + break; + case MX_DISPLAY_FORMAT_ARGB_8888: + format = GFX_FORMAT_ARGB_8888; + break; + case MX_DISPLAY_FORMAT_RGB_x888: + format = GFX_FORMAT_RGB_x888; + break; + case MX_DISPLAY_FORMAT_MONO_8: + format = GFX_FORMAT_MONO; + break; + default: + xprintf("invalid graphics format)"); + return ERR_INVALID_ARGS; + } + return format; +} + +static bool vc_ischar(mx_key_event_t* ev) { + return ev->pressed && ((ev->keycode >= 1 && ev->keycode <= 0x7f) || + ev->keycode == MX_KEY_RETURN || + ev->keycode == MX_KEY_PAD_ENTER || + ev->keycode == MX_KEY_BACKSPACE || + ev->keycode == MX_KEY_TAB || + (ev->keycode >= MX_KEY_ARROW_UP && ev->keycode <= MX_KEY_ARROW_LEFT)); +} + +static int vc_input_thread(void* arg) { + int fd = open(input_dev, O_RDONLY); + if (fd < 0) { + printf("vc: cannot open '%s'\n", input_dev); + return 0; + } + mx_key_event_t ev; + int modifiers = 0; + + for (;;) { + mxio_wait_fd(fd, MXIO_EVT_READABLE, NULL); + int r = read(fd, &ev, sizeof(mx_key_event_t)); + if (r < 0) { + return r; + } + if ((size_t)(r) != sizeof(mx_key_event_t)) { + continue; + } + int consumed = 0; + if (ev.pressed) { + switch (ev.keycode) { + // modifier keys are special + case MX_KEY_LSHIFT: + modifiers |= MOD_LSHIFT; + break; + case MX_KEY_RSHIFT: + modifiers |= MOD_RSHIFT; + break; + case MX_KEY_LALT: + modifiers |= MOD_LALT; + break; + case MX_KEY_RALT: + modifiers |= MOD_RALT; + break; + case MX_KEY_LCTRL: + modifiers |= MOD_LCTRL; + break; + case MX_KEY_RCTRL: + modifiers |= MOD_RCTRL; + break; + + case MX_KEY_F1: + vc_set_active_console(active_vc_index == 0 ? vc_count - 1 : active_vc_index - 1); + consumed = 1; + break; + case MX_KEY_F2: + vc_set_active_console(active_vc_index == vc_count - 1 ? 0 : active_vc_index + 1); + consumed = 1; + break; + + case MX_KEY_ARROW_UP: + if (modifiers & MOD_LALT || modifiers & MOD_RALT) { + vc_device_scroll_viewport(active_vc, -1); + consumed = 1; + } + break; + case MX_KEY_ARROW_DOWN: + if (modifiers & MOD_LALT || modifiers & MOD_RALT) { + vc_device_scroll_viewport(active_vc, 1); + consumed = 1; + } + break; + + // eat everything else + default: + ; // nothing + } + } else { + switch (ev.keycode) { + // modifier keys are special + case MX_KEY_LSHIFT: + modifiers &= ~MOD_LSHIFT; + break; + case MX_KEY_RSHIFT: + modifiers &= ~MOD_RSHIFT; + break; + case MX_KEY_LALT: + modifiers &= ~MOD_LALT; + break; + case MX_KEY_RALT: + modifiers &= ~MOD_RALT; + break; + case MX_KEY_LCTRL: + modifiers &= ~MOD_LCTRL; + break; + case MX_KEY_RCTRL: + modifiers &= ~MOD_RCTRL; + break; + + default: + ; // nothing + } + } + if (!consumed) { + // TODO: decouple char device from actual device + // TODO: ensure active vc can't change while this is going on + mxr_mutex_lock(&active_vc->fifo.lock); + if ((active_vc->fifo.head == active_vc->fifo.tail) && (active_vc->charcount == 0)) { + active_vc->flags |= VC_FLAG_RESETSCROLL; + device_state_set(&active_vc->device, DEV_STATE_READABLE); + } + mx_key_fifo_write(&active_vc->fifo, &ev); + mxr_mutex_unlock(&active_vc->fifo.lock); + } + } + return 0; +} + +#define ESCAPE_HIDE_CURSOR "\033[?25l" + +static int vc_logreader_thread(void* arg) { + mx_handle_t h; + + if ((h = _magenta_log_create(MX_LOG_FLAG_CONSOLE)) < 0) { + return h; + } + + vc_device_t* vc = debug_vc; + // hide cursor in logreader + vc_char_write(&vc->device, ESCAPE_HIDE_CURSOR, strlen(ESCAPE_HIDE_CURSOR)); + + char buf[MX_LOG_RECORD_MAX]; + mx_log_record_t* rec = (mx_log_record_t*) buf; + for (;;) { + if (_magenta_log_read(h, MX_LOG_RECORD_MAX, rec, MX_LOG_FLAG_WAIT) > 0) { + char tmp[64]; + snprintf(tmp, 64, "[%05d.%03d] %c ", + (int) (rec->timestamp / 1000000000ULL), + (int) ((rec->timestamp / 1000000ULL) % 1000ULL), + (rec->flags & MX_LOG_FLAG_KERNEL) ? 'K' : 'U'); + vc_char_write(&vc->device, tmp, strlen(tmp)); + vc_char_write(&vc->device, rec->data, rec->datalen); + if (rec->data[rec->datalen - 1] != '\n') { + vc_char_write(&vc->device, "\n", 1); + } + } + } + return 0; +} + +mx_status_t vc_set_active_console(uint console) { + if (console >= vc_count) return ERR_INVALID_ARGS; + + uint i = 0; + vc_device_t* device = NULL; + list_for_every_entry(&vc_list, device, vc_device_t, node) { + if (i == console) break; + i++; + } + if (device == active_vc) return NO_ERROR; + mxr_mutex_lock(&active_lock); + if (active_vc) active_vc->active = false; + device->active = true; + active_vc = device; + active_vc->flags &= ~VC_FLAG_HASINPUT; + active_vc_index = console; + mxr_mutex_unlock(&active_lock); + vc_device_render(active_vc); + return NO_ERROR; +} + +void vc_get_status_line(char* str, int n) { + vc_device_t* device = NULL; + char* ptr = str; + uint i = 0; + // TODO add process name, etc. + list_for_every_entry(&vc_list, device, vc_device_t, node) { + int lines = vc_device_get_scrollback_lines(device); + int chars = snprintf(ptr, n, "%s[%u] %s%c %c%c \033[m", + device->active ? "\033[36m\033[1m" : "", + i, + device->title, + device->flags & VC_FLAG_HASINPUT ? '*' : ' ', + lines > 0 && -device->vpy < lines ? '<' : ' ', + device->vpy < 0 ? '>' : ' '); + ptr += chars; + i++; + } +} + +static mx_protocol_device_t vc_device_proto = { + .get_protocol = vc_device_get_protocol, + .open = vc_device_open, + .close = vc_device_close, + .release = vc_device_release, +}; + +static mx_driver_t _driver_vc = { + .name = "vc", + .ops = { + }, +}; + +static mx_status_t vc_root_bind(mx_driver_t* drv, mx_device_t* dev) { + mx_status_t status; + + mx_display_protocol_t* disp; + if ((status = device_get_protocol(dev, MX_PROTOCOL_DISPLAY, (void**)&disp)) < 0) { + return status; + } + + // get display info + mx_display_info_t info; + if ((status = disp->get_mode(dev, &info)) < 0) { + return status; + } + + // get framebuffer + void* framebuffer; + if ((status = disp->get_framebuffer(dev, &framebuffer)) < 0) { + return status; + } + + // get display format + gfx_format format = display_format_to_gfx_format(info.format); + + // initialize the hw surface + if ((status = gfx_init_surface(&hw_gfx, framebuffer, info.width, info.height, info.stride, format, 0)) < 0) { + return status; + } + + uint i; + for (i = 0; i < VC_COUNT; i++) { + // allocate vc# devices + vc_device_t* device; + if ((status = vc_device_alloc(&hw_gfx, &device)) < 0) { + break; + } + + // init the vc device + char name[4]; + snprintf(name, sizeof(name), "vc%u", i); + if ((status = device_init(&device->device, &_driver_vc, name, &vc_device_proto)) < 0) { + break; + } + if (i == 0) { + strncpy(device->title, "syslog", sizeof(device->title)); + } else { + strncpy(device->title, name, sizeof(device->title)); + } + device->device.protocol_id = MX_PROTOCOL_CHAR; + + // add devices to root node + list_add_tail(&vc_list, &device->node); + device_add(&device->device, dev); + } + if (i == 0) { + // TODO: cleanup surface and thread + return status; + } + vc_count = i; + vc_set_active_console(0); + // vc0 is the debug console + debug_vc = active_vc; + + xprintf("initialized vc on display %s, width=%u height=%u stride=%u format=%u, count=%u\n", dev->name, info.width, info.height, info.stride, format, i); + + // start a thread to wait for input + if ((status = mxr_thread_create(vc_input_thread, NULL, "vc-input", &input_thread)) < 0) { + printf("vc-input thread did not start %d\n", status); + } + + mxr_thread_create(vc_logreader_thread, NULL, "vc-debuglog", &logreader_thread); + + return NO_ERROR; +} + +static mx_status_t vc_root_probe(mx_driver_t* drv, mx_device_t* dev) { + if (vc_count > 0) { + // disallow multiple instances + return ERR_NOT_SUPPORTED; + } + // TODO: bind by protocol + if (strcmp(dev->name, "bochs_vbe") && strcmp(dev->name, "intel_i915_disp")) { + return ERR_NOT_SUPPORTED; + } + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_DISPLAY, +}; + +mx_driver_t _driver_vc_root BUILTIN_DRIVER = { + .name = "vc-root", + .ops = { + .probe = vc_root_probe, + .bind = vc_root_bind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/uapp/devmgr/servers/vc/textcon.c b/system/uapp/devmgr/servers/vc/textcon.c new file mode 100644 index 000000000..a78168652 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/textcon.c @@ -0,0 +1,514 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textcon.h" + +#define VCDEBUG 1 +#include "vcdebug.h" + +#include + +#define dataxy(tc, x, y) ((tc)->data + ((y)*tc->w) + (x)) + +static inline void invalidate(textcon_t* tc, int x, int y, int w, int h) { + tc->invalidate(tc->cookie, x, y, w, h); +} +static inline void movecursor(textcon_t* tc, int x, int y) { + tc->movecursor(tc->cookie, x, y); +} +static inline void pushline(textcon_t* tc, int y) { + tc->pushline(tc->cookie, y); +} +static inline void setparam(textcon_t* tc, int param, void* arg, size_t arglen) { + tc->setparam(tc->cookie, param, arg, arglen); +} + +#define ATTR(tc) ((((tc)->fg & 15) << 8) | (((tc)->bg & 15) << 12)) + +static void moveto(textcon_t* tc, int x, int y) { + if (x < 0) { + x = 0; + } else if (x >= tc->w) { + x = tc->w - 1; + } + if (y < 0) { + y = 0; + } else if (y > tc->h) { + y = tc->h - 1; + } + tc->x = x; + tc->y = y; +} + +static inline void moverel(textcon_t* tc, int dx, int dy) { + moveto(tc, tc->x + dx, tc->y + dy); +} + +static void fill(vc_char_t* ptr, vc_char_t val, size_t count) { + while (count-- > 0) { + *ptr++ = val; + } +} + +static void erase_region(textcon_t* tc, int x0, int y0, int x1, int y1) { + vc_char_t* ptr = dataxy(tc, x0, y0); + vc_char_t* end = dataxy(tc, x1, y1) + 1; + fill(ptr, ' ' | ATTR(tc), end - ptr); + invalidate(tc, x0, y0, x1 - x0 + 1, y1 - y0 + 1); +} + +static void erase_screen(textcon_t* tc, int arg) { + switch (arg) { + case 0: // erase downward + erase_region(tc, tc->x, tc->y, tc->w - 1, tc->h - 1); + break; + case 1: // erase upward + erase_region(tc, 0, 0, tc->x, tc->w - 1); + break; + case 2: // erase all + erase_region(tc, 0, 0, tc->w - 1, tc->h - 1); + break; + } +} + +static void erase_line(textcon_t* tc, int arg) { + switch (arg) { + case 0: // erase to eol + erase_region(tc, tc->x, tc->y, tc->w - 1, tc->y); + break; + case 1: // erase from bol + erase_region(tc, 0, tc->y, tc->x, tc->y); + break; + case 2: // erase line + erase_region(tc, 0, tc->y, tc->w - 1, tc->y); + break; + } +} + +static void erase_chars(textcon_t* tc, int arg) { + if (arg < 0) { + arg = 0; + } + if (arg > tc->w) { + arg = tc->w; + } + + vc_char_t* dst = dataxy(tc, tc->x, tc->y); + vc_char_t* src = dataxy(tc, tc->x + arg, tc->y); + vc_char_t* end = dataxy(tc, tc->x + tc->w, tc->y); + + while (src < end) { + *dst++ = *src++; + } + while (dst < end) { + *dst++ = ' ' | ATTR(tc); + } + + invalidate(tc, tc->x, tc->y, tc->w - tc->x, 1); +} + +static void _scroll_up(textcon_t* tc, int y0, int y1) { + vc_char_t* dst = dataxy(tc, 0, y0); + vc_char_t* src = dataxy(tc, 0, y0 + 1); + vc_char_t* end = dataxy(tc, 0, y1); + + if (src < end) { + pushline(tc, y0); + memmove(dst, src, (end - src) * sizeof(vc_char_t)); + fill(end - tc->w, ' ' | ATTR(tc), tc->w); + } +} + +static void _scroll_down(textcon_t* tc, int y0, int y1) { + vc_char_t* src = dataxy(tc, 0, y0); + vc_char_t* dst = dataxy(tc, 0, y0 + 1); + vc_char_t* end = dataxy(tc, 0, y1); + + if (src < end) { + // todo: push topline + memmove(dst, src, (end - dst) * sizeof(vc_char_t)); + fill(src, ' ' | ATTR(tc), tc->w); + } +} + +static void scroll_up(textcon_t* tc) { + _scroll_up(tc, tc->scroll_y0, tc->scroll_y1); + tc->scroll(tc->cookie, tc->scroll_y0, tc->scroll_y1, 1); +} + +// positive = up, negative = down +static void scroll_at_pos(textcon_t* tc, int dir) { + if (tc->y < tc->scroll_y0) + return; + if (tc->y >= tc->scroll_y1) + return; + + int count = dir; + while (count > 0) { + _scroll_up(tc, tc->y, tc->scroll_y1); + count--; + } + while (count < 0) { + _scroll_down(tc, tc->y, tc->scroll_y1); + count++; + } + tc->scroll(tc->cookie, tc->y, tc->scroll_y1, dir); + invalidate(tc, 0, tc->y, tc->w, tc->scroll_y1 - tc->y); +} + +void set_scroll(textcon_t* tc, int y0, int y1) { + if (y0 > y1) { + return; + } + tc->scroll_y0 = (y0 < 0) ? 0 : y0; + tc->scroll_y1 = (y1 > tc->h) ? tc->h : y1; +} + +static void putc_plain(textcon_t* tc, uint8_t c); +static void putc_escape2(textcon_t* tc, uint8_t c); + +static void putc_ignore(textcon_t* tc, uint8_t c) { + tc->putc = putc_plain; +} + +static void putc_param(textcon_t* tc, uint8_t c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + tc->num = tc->num * 10 + (c - '0'); + return; + case ';': + if (tc->argc < TC_MAX_ARG) { + tc->argn[tc->argc++] = tc->num; + } + tc->putc = putc_escape2; + break; + default: + if (tc->argc < TC_MAX_ARG) { + tc->argn[tc->argc++] = tc->num; + } + tc->putc = putc_escape2; + putc_escape2(tc, c); + break; + } +} + +#define ARG0(def) ((tc->argc > 0) ? tc->argn[0] : (def)) +#define ARG1(def) ((tc->argc > 1) ? tc->argn[1] : (def)) + +static void putc_dec(textcon_t* tc, uint8_t c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + tc->num = tc->num * 10 + (c - '0'); + return; + case 'h': + if (tc->num == 25) setparam(tc, TC_SHOW_CURSOR, NULL, 0); + break; + case 'l': + if (tc->num == 25) setparam(tc, TC_HIDE_CURSOR, NULL, 0); + break; + default: + putc_plain(tc, c); + break; + } + tc->putc = putc_plain; +} + +static textcon_param_t osc_to_param(int osc) { + switch (osc) { + case 2: + return TC_SET_TITLE; + default: + return -1; + } +} + +static void putc_osc2(textcon_t* tc, uint8_t c) { + switch (c) { + case 7: // end command + if (tc->argsn) setparam(tc, osc_to_param(ARG0(-1)), tc->args, tc->argsn); + tc->putc = putc_plain; + break; + default: + if (tc->argsn < TC_MAX_ARG_LENGTH) tc->args[tc->argsn++] = c; + break; + } +} + +static void putc_osc(textcon_t* tc, uint8_t c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + tc->num = tc->num * 10 + (c - '0'); + return; + case ';': + if (tc->argc < TC_MAX_ARG) { + tc->argn[tc->argc++] = tc->num; + } + memset(tc->args, 0, TC_MAX_ARG_LENGTH); + tc->argsn = 0; + tc->putc = putc_osc2; + break; + default: + if (tc->argc < TC_MAX_ARG) { + tc->argn[tc->argc++] = tc->num; + } + tc->putc = putc_osc2; + putc_osc2(tc, c); + break; + } +} + +static void putc_escape2(textcon_t* tc, uint8_t c) { + int x, y; + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + tc->num = c - '0'; + tc->putc = putc_param; + return; + case ';': // end parameter + if (tc->argc < TC_MAX_ARG) { + tc->argn[tc->argc++] = 0; + } + return; + case '?': + tc->num = 0; + tc->argc = 0; + tc->putc = putc_dec; + return; + case 'A': // (CUU) Cursor Up + moverel(tc, 0, -ARG0(1)); + break; + case 'B': // (CUD) Cursor Down + moverel(tc, 0, ARG0(1)); + break; + case 'C': // (CUF) Cursor Forward + moverel(tc, ARG0(1), 0); + break; + case 'D': // (CUB) Cursor Backward + moverel(tc, -ARG0(1), 0); + break; + case 'E': + moveto(tc, 0, tc->y + ARG0(1)); + break; + case 'F': + moveto(tc, 0, tc->y - ARG0(1)); + break; + case 'G': // move xpos absolute + x = ARG0(1); + moveto(tc, x ? (x - 1) : 0, tc->y); + break; + case 'H': // (CUP) Cursor Position + case 'f': // (HVP) Horizontal and Vertical Position + x = ARG1(1); + y = ARG0(1); + moveto(tc, x ? (x - 1) : 0, y ? (y - 1) : 0); + break; + case 'J': // (ED) erase in display + erase_screen(tc, ARG0(0)); + break; + case 'K': // (EL) erase in line + erase_line(tc, ARG0(0)); + break; + case 'L': // (IL) insert line(s) at cursor + scroll_at_pos(tc, -ARG0(1)); + break; + case 'M': // (DL) delete line(s) at cursor + scroll_at_pos(tc, ARG0(1)); + break; + case 'P': // (DCH) delete character(s) + erase_chars(tc, ARG0(1)); + break; + case 'd': // move ypos absolute + y = ARG0(1); + moveto(tc, tc->x, y ? (y - 1) : 0); + break; + case 'm': // (SGR) Character Attributes + break; + case 'r': // set scroll region + set_scroll(tc, ARG0(1) - 1, ARG1(tc->h)); + break; + case 's': // save cursor position ?? + tc->save_x = tc->x; + tc->save_y = tc->y; + break; + case 'u': // restore cursor position ?? + moveto(tc, tc->save_x, tc->save_y); + break; + case '@': // (ICH) Insert Blank Character(s) + case 'T': // Initiate Hilight Mouse Tracking (xterm) + case 'c': // (DA) Send Device Attributes + case 'g': // (TBC) Tab Clear + case 'h': // (SM) Set Mode (4=Insert,20=AutoNewline) + case 'l': // (RM) Reset Mode (4=Replace,20=NormalLinefeed) + case 'n': // (DSR) Device Status Report + case 'x': // Request Terminal Parameters + default: + break; + } + movecursor(tc, tc->x, tc->y); + tc->putc = putc_plain; +} + +static void putc_escape(textcon_t* tc, uint8_t c) { + switch (c) { + case 27: // escape + return; + case '(': + case ')': + case '*': + case '+': + // select various character sets + tc->putc = putc_ignore; + return; + case '[': + tc->num = 0; + tc->argc = 0; + tc->putc = putc_escape2; + return; + case ']': + tc->num = 0; + tc->argc = 0; + tc->putc = putc_osc; + return; + case '7': // (DECSC) Save Cursor + tc->save_x = tc->x; + tc->save_y = tc->y; + // save attribute + break; + case '8': // (DECRC) Restore Cursor + moveto(tc, tc->save_x, tc->save_y); + movecursor(tc, tc->x, tc->y); + break; + case 'E': // (NEL) Next Line + tc->x = 0; + case 'D': // (IND) Index + tc->y++; + if (tc->y >= tc->scroll_y1) { + tc->y--; + scroll_at_pos(tc, 1); // ?? + } + movecursor(tc, tc->x, tc->y); + break; + case 'M': // (RI) Reverse Index) + tc->y--; + if (tc->y < tc->scroll_y0) { + tc->y++; + scroll_at_pos(tc, -1); + } + movecursor(tc, tc->x, tc->y); + break; + } + tc->putc = putc_plain; +} + +static void putc_plain(textcon_t* tc, uint8_t c) { + switch (c) { + case 7: // bell + break; + case 8: // backspace / ^H + dataxy(tc, tc->x, tc->y)[0] = ' ' | ATTR(tc); + tc->x--; + if (tc->x < 0) { + tc->x = tc->w - 1; + tc->y--; + if (tc->y < 0) { + tc->y = 0; + } + } + break; + case 9: // tab / ^I + moveto(tc, (tc->x + 7) & (~7), tc->y); + break; + case 10: // newline + tc->x = 0; + tc->y++; + if (tc->y >= tc->scroll_y1) { + tc->y--; + scroll_up(tc); + } + break; + case 12: + erase_screen(tc, 2); + break; + case 13: // carriage return + tc->x = 0; + break; + case 27: // escape + tc->putc = putc_escape; + return; + default: + if ((c < ' ') || (c > 127)) { + return; + } + dataxy(tc, tc->x, tc->y)[0] = c | ATTR(tc); + invalidate(tc, tc->x, tc->y, 1, 1); + tc->x++; + if (tc->x >= tc->w) { + tc->x = tc->w - 1; + // sometimes scroll + newline?? + } + break; + } + movecursor(tc, tc->x, tc->y); +} + +void tc_init(textcon_t* tc, int w, int h, void* data, uint8_t fg, uint8_t bg) { + tc->w = w; + tc->h = h; + tc->x = 0; + tc->y = 0; + tc->data = data; + tc->scroll_y0 = 0; + tc->scroll_y1 = h; + tc->save_x = 0; + tc->save_y = 0; + tc->fg = fg; + tc->bg = bg; + tc->putc = putc_plain; +} diff --git a/system/uapp/devmgr/servers/vc/textcon.h b/system/uapp/devmgr/servers/vc/textcon.h new file mode 100644 index 000000000..a8afab244 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/textcon.h @@ -0,0 +1,77 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#define TC_MAX_ARG 16 +#define TC_MAX_ARG_LENGTH 8 // matches vc title length + +typedef struct textcon textcon_t; +typedef uint16_t vc_char_t; + +typedef enum textcon_param { + TC_SET_TITLE, + TC_SHOW_CURSOR, + TC_HIDE_CURSOR, +} textcon_param_t; + +struct textcon { + void (*putc)(textcon_t* tc, uint8_t c); + + // backing data + vc_char_t* data; + + // dimensions of display + int w; + int h; + + // cursor position + int x; + int y; + + // callbacks to update visible display + void (*invalidate)(void* cookie, int x, int y, int w, int h); + void (*movecursor)(void* cookie, int x, int y); + void (*pushline)(void* cookie, int y); + void (*scroll)(void* cookie, int x, int y0, int y1); + void (*setparam)(void* cookie, int param, uint8_t* arg, size_t arglen); + void* cookie; + + // scrolling region + int scroll_y0; + int scroll_y1; + + // saved cursor position + int save_x; + int save_y; + + uint8_t fg; + uint8_t bg; + + // escape sequence parameter parsing + int num; + int argc; + int argn[TC_MAX_ARG]; + int argsn; + uint8_t args[TC_MAX_ARG_LENGTH + 1]; +}; + +void tc_init(textcon_t* tc, int w, int h, void* data, uint8_t fg, uint8_t bg); + +static inline void tc_putc(textcon_t* tc, uint8_t c) { + tc->putc(tc, c); +} diff --git a/system/uapp/devmgr/servers/vc/vc-char.c b/system/uapp/devmgr/servers/vc/vc-char.c new file mode 100644 index 000000000..186c7fa7a --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vc-char.c @@ -0,0 +1,202 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#define VCDEBUG 1 + +#include "vc.h" +#include "vcdebug.h" + +// implement char protocol: + +ssize_t vc_char_read(mx_device_t *dev, void *buf, size_t count) { + vc_device_t* device = get_vc_device(dev); + mx_key_event_t ev; + ssize_t r = 0; + mxr_mutex_lock(&device->fifo.lock); + while (count > 0) { + if (device->charcount > 0) { + if (count > device->charcount) { + count = device->charcount; + } + memcpy(buf, device->chardata, count); + device->charcount -= count; + if (device->charcount > 0) { + memmove(device->chardata, device->chardata + count, device->charcount); + } + r = count; + break; + } + if (mx_key_fifo_read(&device->fifo, &ev)) { + // TODO: better error? + r = 0; + break; + } + + char* str = device->chardata; + if (ev.pressed) { + switch (ev.keycode) { + case MX_KEY_LSHIFT: + device->modifiers |= MOD_LSHIFT; + break; + case MX_KEY_RSHIFT: + device->modifiers |= MOD_RSHIFT; + break; + case MX_KEY_LCTRL: + device->modifiers |= MOD_LCTRL; + break; + case MX_KEY_RCTRL: + device->modifiers |= MOD_RCTRL; + break; + case MX_KEY_LALT: + device->modifiers |= MOD_LALT; + break; + case MX_KEY_RALT: + device->modifiers |= MOD_RALT; + break; + case 'a' ... 'z': + if (device->modifiers & MOD_CTRL) { + str[0] = ev.keycode - 'a' + 1; + } else { + str[0] = ev.keycode; + } + device->charcount = 1; + break; + case 'A' ... 'Z': + if (device->modifiers & MOD_CTRL) { + str[0] = ev.keycode - 'A' + 1; + } else { + str[0] = ev.keycode; + } + device->charcount = 1; + break; + + // generate special stuff for a few different keys + case MX_KEY_RETURN: + case MX_KEY_PAD_ENTER: + str[0] = '\n'; + device->charcount = 1; + break; + case MX_KEY_BACKSPACE: + str[0] = '\b'; + device->charcount = 1; + break; + case MX_KEY_TAB: + str[0] = '\t'; + device->charcount = 1; + break; + + // generate vt100 key codes for arrows + case MX_KEY_ARROW_UP: + str[0] = 0x1b; + str[1] = '['; + str[2] = 65; + device->charcount = 3; + break; + case MX_KEY_ARROW_DOWN: + str[0] = 0x1b; + str[1] = '['; + str[2] = 66; + device->charcount = 3; + break; + case MX_KEY_ARROW_RIGHT: + str[0] = 0x1b; + str[1] = '['; + str[2] = 67; + device->charcount = 3; + break; + case MX_KEY_ARROW_LEFT: + str[0] = 0x1b; + str[1] = '['; + str[2] = 68; + device->charcount = 3; + break; + + default: + if (ev.keycode < 0x80) { + str[0] = ev.keycode; + device->charcount = 1; + } + break; + } + } else { + switch (ev.keycode) { + case MX_KEY_LSHIFT: + device->modifiers &= (~MOD_LSHIFT); + break; + case MX_KEY_RSHIFT: + device->modifiers &= (~MOD_RSHIFT); + break; + case MX_KEY_LCTRL: + device->modifiers &= (~MOD_LCTRL); + break; + case MX_KEY_RCTRL: + device->modifiers &= (~MOD_RCTRL); + break; + case MX_KEY_LALT: + device->modifiers &= (~MOD_LALT); + break; + case MX_KEY_RALT: + device->modifiers &= (~MOD_RALT); + break; + } + } + } + if ((device->fifo.head == device->fifo.tail) && (device->charcount == 0)) { + device_state_clr(dev, DEV_STATE_READABLE); + } + mxr_mutex_unlock(&device->fifo.lock); + return r; +} + +ssize_t vc_char_write(mx_device_t *dev, const void *buf, size_t count) { + vc_device_t* device = get_vc_device(dev); + mxr_mutex_lock(&device->lock); + const uint8_t* str = (const uint8_t*)buf; + for (size_t i = 0; i < count; i++) { + device->textcon.putc(&device->textcon, str[i]); + } + if (!device->active && !(device->flags & VC_FLAG_HASINPUT)) { + device->flags |= VC_FLAG_HASINPUT; + vc_device_write_status(device); + vc_gfx_invalidate(device, 0, 0, device->columns, 1); + } + mxr_mutex_unlock(&device->lock); + return count; +} + +ssize_t vc_char_ioctl(mx_device_t *dev, uint32_t op, + const void* cmd, size_t cmdlen, + void* reply, size_t max) { + vc_device_t* device = get_vc_device(dev); + switch(op) { + case CONSOLE_OP_GET_DIMENSIONS: { + ioctl_console_dimensions_t* dims = reply; + if (sizeof(*dims) < max) { + return ERR_NOT_ENOUGH_BUFFER; + } + dims->width = device->columns; + dims->height = device->rows; + return sizeof(*dims); + } + default: + return ERR_NOT_SUPPORTED; + } +} diff --git a/system/uapp/devmgr/servers/vc/vc-console.c b/system/uapp/devmgr/servers/vc/vc-console.c new file mode 100644 index 000000000..66da90049 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vc-console.c @@ -0,0 +1,35 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define VCDEBUG 1 + +#include "vc.h" +#include "vcdebug.h" + +mx_handle_t vc_console_getsurface(mx_device_t* dev, uint32_t* width, uint32_t* height) { + return MX_HANDLE_INVALID; +} + +void vc_console_invalidate(mx_device_t* dev, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { +} + +void vc_console_movecursor(mx_device_t* dev, uint32_t x, uint32_t y, bool visible) { +} + +void vc_console_setpalette(mx_device_t* dev, uint32_t colors[16]) { +} + +mx_status_t vc_console_readkey(mx_device_t* dev, uint32_t flags) { + return ERR_NOT_SUPPORTED; +} diff --git a/system/uapp/devmgr/servers/vc/vc-device.c b/system/uapp/devmgr/servers/vc/vc-device.c new file mode 100644 index 000000000..9c58d03f6 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vc-device.c @@ -0,0 +1,356 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#define VCDEBUG 1 + +#include "vc.h" +#include "vcdebug.h" + +static uint32_t default_palette[] = { + 0xff000000, // black + 0xff0000aa, // blue + 0xff00aa00, // green + 0xff00aaaa, // cyan + 0xffaa0000, // red + 0xffaa00aa, // magenta + 0xffaa5500, // brown + 0xffaaaaaa, // grey + 0xff555555, // dark grey + 0xff5555ff, // bright blue + 0xff55ff55, // bright green + 0xff55ffff, // bright cyan + 0xffff5555, // bright red + 0xffff55ff, // bright magenta + 0xffffff55, // yellow + 0xffffffff, // white +}; + +#define DEFAULT_FRONT_COLOR 0x0 // black +#define DEFAULT_BACK_COLOR 0xf // white + +#define SCROLLBACK_ROWS 1024 // TODO make configurable +#define TOTAL_ROWS(dev) (dev->rows + dev->scrollback_rows) + +#define ABS(val) (((val) >= 0) ? (val) : -(val)) + +static mx_status_t vc_device_setup(vc_device_t *dev) { + assert(dev->gfx); + assert(dev->hw_gfx); + + dev->lock = MXR_MUTEX_INIT; + + // calculate how many rows/columns we have + dev->rows = dev->gfx->height / FONT_Y; + dev->columns = dev->gfx->width / FONT_X; + dev->scrollback_rows = SCROLLBACK_ROWS; + + // allocate the text buffer + dev->text_buf = calloc(1, dev->rows * dev->columns * sizeof(vc_char_t)); + if (!dev->text_buf) return ERR_NO_MEMORY; + + // allocate the scrollback buffer + dev->scrollback_buf = calloc(1, dev->scrollback_rows * dev->columns * sizeof(vc_char_t)); + if (!dev->scrollback_buf) { + free(dev->text_buf); + return ERR_NO_MEMORY; + } + + // set up the default palette + memcpy(&dev->palette, default_palette, sizeof(default_palette)); + dev->front_color = DEFAULT_FRONT_COLOR; + dev->back_color = DEFAULT_BACK_COLOR; + + return NO_ERROR; +} + +static void vc_device_invalidate(void* cookie, int x0, int y0, int w, int h) { + vc_device_t* dev = cookie; + for (int y = y0; y < y0 + h; y++) { + int sc = 0; + if (y < 0) { + sc = dev->sc_t + y; + if (sc < 0) sc += dev->scrollback_rows; + } + for (int x = x0; x < x0 + w; x++) { + if (y < 0) { + vc_gfx_draw_char(dev, dev->scrollback_buf[x + sc * dev->columns], x, y - dev->vpy); + } else { + vc_gfx_draw_char(dev, dev->text_buf[x + y * dev->columns], x, y - dev->vpy); + } + } + } +} + +// implement tc callbacks: + +static void vc_tc_invalidate(void* cookie, int x0, int y0, int w, int h) { + vc_device_t* dev = cookie; + if (dev->flags & VC_FLAG_RESETSCROLL) { + dev->flags &= ~VC_FLAG_RESETSCROLL; + vc_device_scroll_viewport(dev, -dev->vpy); + } + if (dev->vpy < 0) return; + vc_device_invalidate(cookie, x0, y0, w, h); + vc_gfx_invalidate(dev, x0, y0, w, h); +} + +static void vc_tc_movecursor(void* cookie, int x, int y) { + vc_device_t* dev = cookie; + if (!dev->hide_cursor) { + vc_device_invalidate(cookie, dev->x, dev->y, 1, 1); + vc_gfx_invalidate(dev, dev->x, dev->y, 1, 1); + gfx_fillrect(dev->gfx, x * FONT_X, y * FONT_Y, FONT_X, FONT_Y, palette_to_color(dev, dev->front_color)); + vc_gfx_invalidate(dev, x, y, 1, 1); + } + dev->x = x; + dev->y = y; +} + +static void vc_tc_pushline(void* cookie, int y) { + vc_device_t* dev = cookie; + vc_char_t* dst = &dev->scrollback_buf[dev->sc_t * dev->columns]; + vc_char_t* src = &dev->text_buf[y * dev->columns]; + memcpy(dst, src, dev->columns * sizeof(vc_char_t)); + dev->sc_t += 1; + if (dev->vpy < 0) dev->vpy -= 1; + if (dev->sc_t >= dev->scrollback_rows) { + dev->sc_t -= dev->scrollback_rows; + if (dev->sc_t >= dev->sc_h) dev->sc_h = dev->sc_t + 1; + } +} + +// positive = up, negative = down +// textbuf must be updated before calling scroll +static void vc_tc_scroll(void* cookie, int y0, int y1, int dir) { + vc_device_t* dev = cookie; + if (dev->vpy < 0) return; + // invalidate the cursor before copying + vc_device_invalidate(cookie, dev->x, dev->y, 1, 1); + int delta = ABS(dir); + if (dir > 0) { + gfx_copyrect(dev->gfx, 0, (y0 + delta) * FONT_Y, dev->gfx->width, (y1 - y0 - delta) * FONT_Y, 0, y0); + vc_device_invalidate(cookie, 0, y1 - delta, dev->columns, delta); + } else { + gfx_copyrect(dev->gfx, 0, y0, dev->gfx->width, (y1 - y0 - delta) * FONT_Y, 0, (y0 + delta) * FONT_Y); + vc_device_invalidate(cookie, 0, y0, dev->columns, delta); + } + gfx_flush(dev->gfx); + vc_device_write_status(dev); + vc_gfx_invalidate_all(dev); +} + +static void vc_tc_setparam(void* cookie, int param, uint8_t* arg, size_t arglen) { + vc_device_t* dev = cookie; + switch (param) { + case TC_SET_TITLE: + strncpy(dev->title, (char*)arg, sizeof(dev->title)); + vc_device_write_status(dev); + vc_gfx_invalidate_status(dev); + break; + case TC_SHOW_CURSOR: + if (dev->hide_cursor) { + dev->hide_cursor = false; + vc_tc_movecursor(dev, dev->x, dev->y); + gfx_fillrect(dev->gfx, dev->x * FONT_X, dev->y * FONT_Y, FONT_X, FONT_Y, palette_to_color(dev, dev->front_color)); + vc_gfx_invalidate(dev, dev->x, dev->y, 1, 1); + } + break; + case TC_HIDE_CURSOR: + if (!dev->hide_cursor) { + dev->hide_cursor = true; + vc_device_invalidate(cookie, dev->x, dev->y, 1, 1); + vc_gfx_invalidate(dev, dev->x, dev->y, 1, 1); + } + default: + ; // nothing + } +} + +static void vc_device_reset(vc_device_t *dev) { + // reset the cursor + dev->x = 0; + dev->y = 0; + // reset the viewport position + dev->vpy = 0; + + tc_init(&dev->textcon, dev->columns, dev->rows, dev->text_buf, dev->front_color, dev->back_color); + dev->textcon.cookie = dev; + dev->textcon.invalidate = vc_tc_invalidate; + dev->textcon.movecursor = vc_tc_movecursor; + dev->textcon.pushline = vc_tc_pushline; + dev->textcon.scroll = vc_tc_scroll; + dev->textcon.setparam = vc_tc_setparam; + + // fill textbuffer with blank characters + size_t count = dev->rows * dev->columns; + vc_char_t* ptr = dev->text_buf; + while (count--) { + *ptr++ = CHARVAL(' ', dev->front_color, dev->back_color); + } + + // fill screen with back color + gfx_fillrect(dev->gfx, 0, 0, dev->gfx->width, dev->gfx->height, palette_to_color(dev, dev->back_color)); + gfx_flush(dev->gfx); + + vc_gfx_invalidate_all(dev); +} + +void vc_device_write_status(vc_device_t* dev) { + static enum { NORMAL, ESCAPE } state = NORMAL; + int fg = 7; + int bg = 0; + char c, str[512]; + int idx = 0; + int p_num = 0; + vc_get_status_line(str, sizeof(str)); + // TODO clean this up with textcon stuff + gfx_fillrect(dev->st_gfx, 0, 0, dev->st_gfx->width, dev->st_gfx->height, palette_to_color(dev, bg)); + for (uint i = 0; i < MIN(dev->columns, strlen(str)); i++) { + c = str[i]; + if (state == NORMAL) { + if (c == 0x1b) { + state = ESCAPE; + p_num = 0; + } else { + font_draw_char(dev->st_gfx, c, idx++ * FONT_X, 0, palette_to_color(dev, fg), palette_to_color(dev, bg)); + } + } else if (state == ESCAPE) { + if (c >= '0' && c <= '9') { + p_num = (p_num * 10) + (c - '0'); + } else if (c == 'm') { + if (p_num >= 30 && p_num <= 37) { + fg = p_num - 30; + } else if (p_num >= 40 && p_num <= 47) { + bg = p_num - 40; + } else if (p_num == 1 && fg <= 0x7) { + fg += 8; + } else if (p_num == 0) { + fg = 7; + bg = 0; + } + state = NORMAL; + } else { + // eat unrecognized escape sequences in status + } + } + } + gfx_flush(dev->st_gfx); +} + +void vc_device_render(vc_device_t* dev) { + vc_device_write_status(dev); + vc_gfx_invalidate_all(dev); +} + +int vc_device_get_scrollback_lines(vc_device_t* dev) { + return dev->sc_t >= dev->sc_h ? dev->sc_t - dev->sc_h : dev->scrollback_rows - 1; +} + +void vc_device_scroll_viewport(vc_device_t* dev, int dir) { + int vpy = MAX(MIN(dev->vpy + dir, 0), -vc_device_get_scrollback_lines(dev)); + int delta = ABS(dev->vpy - vpy); + if (delta == 0) return; + dev->vpy = vpy; + if (dir > 0) { + gfx_copyrect(dev->gfx, 0, delta * FONT_Y, dev->gfx->width, (dev->rows - delta) * FONT_Y, 0, 0); + vc_device_invalidate(dev, 0, vpy + dev->rows - delta, dev->columns, delta); + } else { + gfx_copyrect(dev->gfx, 0, 0, dev->gfx->width, (dev->rows - delta) * FONT_Y, 0, delta * FONT_Y); + vc_device_invalidate(dev, 0, vpy, dev->columns, delta); + } + gfx_flush(dev->gfx); + vc_device_write_status(dev); + vc_gfx_invalidate_all(dev); +} + +static mx_protocol_char_t vc_char_proto = { + .read = vc_char_read, + .write = vc_char_write, + .ioctl = vc_char_ioctl, +}; + +static mx_protocol_console_t vc_console_proto = { + .getsurface = vc_console_getsurface, + .invalidate = vc_console_invalidate, + .movecursor = vc_console_movecursor, + .setpalette = vc_console_setpalette, + .readkey = vc_console_readkey, +}; + +// implement device protocol + +mx_status_t vc_device_get_protocol(mx_device_t* dev, uint32_t protocol_id, void** protocol) { + switch (protocol_id) { + case MX_PROTOCOL_CHAR: + *protocol = &vc_char_proto; + break; + case MX_PROTOCOL_CONSOLE: + *protocol = &vc_console_proto; + break; + default: + return ERR_NOT_SUPPORTED; + } + return NO_ERROR; +} + +mx_status_t vc_device_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +mx_status_t vc_device_close(mx_device_t* dev) { + return NO_ERROR; +} + +mx_status_t vc_device_release(mx_device_t* dev) { + return NO_ERROR; +} + +mx_protocol_device_t vc_device_proto = { + .get_protocol = vc_device_get_protocol, + .open = vc_device_open, + .close = vc_device_close, + .release = vc_device_release, +}; + +mx_status_t vc_device_alloc(gfx_surface *hw_gfx, vc_device_t** out_dev) { + vc_device_t* device = calloc(1, sizeof(vc_device_t)); + if (!device) return ERR_NO_MEMORY; + + // init the status bar + device->st_gfx = gfx_create_surface(NULL, hw_gfx->width, FONT_Y, hw_gfx->stride, hw_gfx->format, 0); + if (!device->st_gfx) goto fail; + + // init the main surface + device->gfx = gfx_create_surface(NULL, hw_gfx->width, hw_gfx->height - FONT_Y, hw_gfx->stride, hw_gfx->format, 0); + if (!device->gfx) goto fail; + device->hw_gfx = hw_gfx; + + vc_device_setup(device); + vc_device_reset(device); + + *out_dev = device; + return NO_ERROR; +fail: + if (device->st_gfx) gfx_surface_destroy(device->st_gfx); + free(device); + return ERR_NO_MEMORY; +} diff --git a/system/uapp/devmgr/servers/vc/vc-gfx.c b/system/uapp/devmgr/servers/vc/vc-gfx.c new file mode 100644 index 000000000..6bed5c714 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vc-gfx.c @@ -0,0 +1,44 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#define VCDEBUG 1 + +#include "vc.h" +#include "vcdebug.h" + +void vc_gfx_draw_char(vc_device_t* dev, vc_char_t ch, uint x, uint y) { + font_draw_char(dev->gfx, TOCHAR(ch), x * FONT_X, y * FONT_Y, palette_to_color(dev, TOFG(ch)), palette_to_color(dev, TOBG(ch))); +} + +void vc_gfx_invalidate_all(vc_device_t* dev) { + if (!dev->active) return; + gfx_surface_blend(dev->hw_gfx, dev->st_gfx, 0, 0); + gfx_surface_blend(dev->hw_gfx, dev->gfx, 0, dev->st_gfx->height); + gfx_flush(dev->hw_gfx); +} + +void vc_gfx_invalidate_status(vc_device_t* dev) { + gfx_surface_blend(dev->hw_gfx, dev->st_gfx, 0, 0); + gfx_flush_rows(dev->hw_gfx, 0, dev->st_gfx->height); +} + +void vc_gfx_invalidate(vc_device_t* dev, uint x, uint y, uint w, uint h) { + if (!dev->active) return; + uint desty = dev->st_gfx->height + y * FONT_Y; + gfx_blend(dev->hw_gfx, dev->gfx, x * FONT_X, y * FONT_Y, w * FONT_X, h * FONT_Y, x * FONT_X, desty); + gfx_flush_rows(dev->hw_gfx, desty, desty + h * FONT_Y); +} diff --git a/system/uapp/devmgr/servers/vc/vc.h b/system/uapp/devmgr/servers/vc/vc.h new file mode 100644 index 000000000..245a32577 --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vc.h @@ -0,0 +1,152 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "textcon.h" + +typedef uint16_t vc_char_t; +#define CHARVAL(ch, fg, bg) (((ch) & 0xff) | (((fg) & 0xf) << 8) | (((bg) & 0xf) << 12)) +#define TOCHAR(ch) ((ch) & 0xff) +#define TOFG(ch) (((ch) >> 8) & 0xf) +#define TOBG(ch) (((ch) >> 12) & 0xf) + +#define MAX_COLOR 0xf + +typedef struct vc_device { + mx_device_t device; + + mxr_mutex_t lock; + // protect output state of the vc + // fifo.lock below protects input state + + char title[8]; + // vc title, shown in status bar + bool active; + uint flags; + + // TODO make static + gfx_surface *gfx; + // surface to draw on + gfx_surface *st_gfx; + // status bar surface + gfx_surface* hw_gfx; + // backing store + + vc_char_t* text_buf; + // text buffer + vc_char_t* scrollback_buf; + // scrollback buffer + + uint rows, columns; + // screen size + uint scrollback_rows; + // number of rows in scrollback + + uint x, y; + // cursor + bool hide_cursor; + // cursor visibility + int vpy; + // viewport position, must be <= 0 + uint sc_h, sc_t; + // offsets into the scrollback buffer in rows + + uint32_t palette[16]; + uint front_color; + uint back_color; + // color + + textcon_t textcon; + + mx_key_fifo_t fifo; + // key event fifo + + struct list_node node; + // for virtual console list + + // for char interface + uint32_t modifiers; + char chardata[4]; + uint32_t charcount; +} vc_device_t; + +#define get_vc_device(dev) containerof(dev, vc_device_t, device) + +#define VC_FLAG_HASINPUT (1 << 0) +#define VC_FLAG_RESETSCROLL (1 << 1) + +mx_status_t vc_device_alloc(gfx_surface* hw_gfx, vc_device_t** out_dev); +static inline mx_status_t vc_device_free(vc_device_t* dev) { return ERR_NOT_SUPPORTED; }; + +mx_status_t vc_set_active_console(uint console); +void vc_get_status_line(char* str, int n); + +void vc_device_write_status(vc_device_t* dev); +void vc_device_render(vc_device_t* dev); +int vc_device_get_scrollback_lines(vc_device_t* dev); +void vc_device_scroll_viewport(vc_device_t* dev, int dir); + +// drawing: + +void vc_gfx_invalidate_all(vc_device_t* dev); +void vc_gfx_invalidate_status(vc_device_t* dev); +void vc_gfx_invalidate(vc_device_t* dev, uint x, uint y, uint w, uint h); +void vc_gfx_draw_char(vc_device_t* dev, vc_char_t ch, uint x, uint y); + +static inline uint32_t palette_to_color(vc_device_t* dev, uint8_t color) { + assert(color <= MAX_COLOR); + return dev->palette[color]; +} + +// device protocol: + +mx_status_t vc_device_get_protocol(mx_device_t* dev, uint32_t protocol_id, void** protocol); +mx_status_t vc_device_open(mx_device_t* dev, uint32_t flags); +mx_status_t vc_device_close(mx_device_t* dev); +mx_status_t vc_device_release(mx_device_t* dev); + +// console protocol: + +mx_handle_t vc_console_getsurface(mx_device_t* dev, uint32_t* width, uint32_t* height); +void vc_console_invalidate(mx_device_t* dev, uint32_t x, uint32_t y, uint32_t width, uint32_t height); +void vc_console_movecursor(mx_device_t* dev, uint32_t x, uint32_t y, bool visible); +void vc_console_setpalette(mx_device_t* dev, uint32_t colors[16]); +mx_status_t vc_console_readkey(mx_device_t* dev, uint32_t flags); + +// char protocol: + +ssize_t vc_char_read(mx_device_t *dev, void *buf, size_t count); +ssize_t vc_char_write(mx_device_t *dev, const void *buf, size_t count); +ssize_t vc_char_ioctl(mx_device_t *dev, uint32_t op, + const void* cmd, size_t cmdlen, + void* reply, size_t max); + +#define MOD_LSHIFT (1 << 0) +#define MOD_RSHIFT (1 << 1) +#define MOD_LALT (1 << 2) +#define MOD_RALT (1 << 3) +#define MOD_LCTRL (1 << 4) +#define MOD_RCTRL (1 << 5) + +#define MOD_SHIFT (MOD_LSHIFT | MOD_RSHIFT) +#define MOD_ALT (MOD_LALT | MOD_RALT) +#define MOD_CTRL (MOD_LCTRL | MOD_RCTRL) diff --git a/system/uapp/devmgr/servers/vc/vcdebug.c b/system/uapp/devmgr/servers/vc/vcdebug.c new file mode 100644 index 000000000..e7650eacb --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vcdebug.c @@ -0,0 +1,30 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include "vcdebug.h" + +void cprintf(const char* fmt, ...) { + char buf[128]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + _magenta_debug_write(buf, strlen(buf)); +} diff --git a/system/uapp/devmgr/servers/vc/vcdebug.h b/system/uapp/devmgr/servers/vc/vcdebug.h new file mode 100644 index 000000000..965b6f3dd --- /dev/null +++ b/system/uapp/devmgr/servers/vc/vcdebug.h @@ -0,0 +1,22 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +void cprintf(const char* fmt, ...); + +#define xprintf(fmt...) do { if (VCDEBUG) cprintf(fmt); } while (0) diff --git a/system/uapp/devmgr/vfs-boot.c b/system/uapp/devmgr/vfs-boot.c new file mode 100644 index 000000000..5b0edc660 --- /dev/null +++ b/system/uapp/devmgr/vfs-boot.c @@ -0,0 +1,238 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +#include +#include + +#include +#include + +#define MXDEBUG 0 + +typedef struct vnboot vnboot_t; +struct vnboot { + vnode_t vn; + const char* name; + void* data; + vnode_t *mounted; + size_t namelen; + size_t datalen; + struct list_node children; + struct list_node node; +}; + +mx_status_t vnb_get_node(vnode_t** out, mx_device_t* dev); + +static void vnb_release(vnode_t* vn) { +} + +static mx_status_t vnb_open(vnode_t** _vn, uint32_t flags) { + vnode_t* vn = *_vn; + vn_acquire(vn); + return NO_ERROR; +} + +static mx_status_t vnb_close(vnode_t* vn) { + vn_release(vn); + return NO_ERROR; +} + +static ssize_t vnb_read(vnode_t* vn, void* data, size_t len, size_t off) { + vnboot_t* vnb = vn->pdata; + if (off > vnb->datalen) return 0; + size_t rlen = vnb->datalen - off; + if (len > rlen) len = rlen; + memcpy(data, vnb->data + off, len); + return len; +} + +static ssize_t vnb_write(vnode_t* vn, const void* data, size_t len, size_t off) { + return ERR_NOT_SUPPORTED; +} + +static mx_status_t vnb_lookup(vnode_t* vn, vnode_t** out, const char* name, size_t len) { + vnboot_t* parent = vn->pdata; + vnboot_t* vnb; + xprintf("vnb_lookup: vn=%p name='%.*s'\n", vn, (int)len, name); + list_for_every_entry (&parent->children, vnb, vnboot_t, node) { + xprintf("? dev=%p name='%s'\n", vnb, vnb->name); + if (vnb->namelen != len) continue; + if (memcmp(vnb->name, name, len)) continue; + if (vnb->mounted) { + vn_acquire(vnb->mounted); + *out = vnb->mounted; + } else { + vn_acquire(&vnb->vn); + *out = &vnb->vn; + } + return NO_ERROR; + } + return ERR_NOT_FOUND; +} + +static mx_status_t vnb_getattr(vnode_t* vn, vnattr_t* attr) { + vnboot_t* vnb = vn->pdata; + memset(attr, 0, sizeof(vnattr_t)); + if (list_is_empty(&vnb->children)) { + attr->size = vnb->datalen; + attr->mode = V_TYPE_FILE | V_IRUSR; + } else { + attr->mode = V_TYPE_DIR | V_IRUSR; + } + return NO_ERROR; +} + +static mx_status_t vnb_readdir(vnode_t* vn, void* cookie, void* data, size_t len) { + vnboot_t* parent = vn->pdata; + vdircookie_t* c = cookie; + vnboot_t* last = c->p; + size_t pos = 0; + char* ptr = data; + bool search = (last != NULL); + mx_status_t r; + vnboot_t* vnb; + + list_for_every_entry (&parent->children, vnb, vnboot_t, node) { + if (search) { + if (vnb == last) { + search = false; + } + } else { + uint32_t vtype = list_is_empty(&vnb->children) ? V_TYPE_DIR : V_TYPE_FILE; + r = vfs_fill_dirent((void*)(ptr + pos), len - pos, + vnb->name, vnb->namelen, + VTYPE_TO_DTYPE(vtype)); + if (r < 0) break; + last = vnb; + pos += r; + } + } + c->p = last; + return pos; +} + +static mx_status_t vnb_create(vnode_t* vn, vnode_t** out, const char* name, size_t len, uint32_t mode) { + return ERR_NOT_SUPPORTED; +} + +static mx_status_t vnb_gethandles(vnode_t* vn, mx_handle_t* handles, uint32_t* ids) { + return ERR_NOT_SUPPORTED; +} + +static vnode_ops_t vn_boot_ops = { + .release = vnb_release, + .open = vnb_open, + .close = vnb_close, + .read = vnb_read, + .write = vnb_write, + .lookup = vnb_lookup, + .getattr = vnb_getattr, + .readdir = vnb_readdir, + .create = vnb_create, + .gethandles = vnb_gethandles, +}; + +static vnboot_t vnb_root = { + .vn = { + .ops = &vn_boot_ops, + .refcount = 1, + .pdata = &vnb_root, + }, + .name = "bootfs", + .namelen = 6, + .node = LIST_INITIAL_VALUE(vnb_root.node), + .children = LIST_INITIAL_VALUE(vnb_root.children), +}; + +static mx_status_t _vnb_create(vnboot_t* parent, vnboot_t** out, + const char* name, size_t namelen, + void* data, size_t datalen) { + vnboot_t* vnb; + if ((vnb = calloc(1, sizeof(vnboot_t) + namelen + 1)) == NULL) return ERR_NO_MEMORY; + xprintf("vnb_create: vn=%p, parent=%p name='%.*s' datalen=%zd\n", + vnb, parent, (int)namelen, name, datalen); + + char* tmp = ((char*)vnb) + sizeof(vnboot_t); + memcpy(tmp, name, namelen); + tmp[namelen] = 0; + + vnb->vn.ops = &vn_boot_ops; + vnb->vn.refcount = 1; + vnb->vn.pdata = vnb; + vnb->name = tmp; + vnb->namelen = namelen; + vnb->data = data; + vnb->datalen = datalen; + list_initialize(&vnb->node); + list_initialize(&vnb->children); + + list_add_tail(&parent->children, &vnb->node); + *out = vnb; + return NO_ERROR; +} + +static mx_status_t _vnb_mkdir(vnboot_t* parent, vnboot_t** out, const char* name, size_t namelen) { + vnboot_t* vnb; + list_for_every_entry (&parent->children, vnb, vnboot_t, node) { + if (vnb->namelen != namelen) continue; + if (memcmp(vnb->name, name, namelen)) continue; + if (vnb->mounted) return ERR_NOT_SUPPORTED; + *out = vnb; + return NO_ERROR; + } + return _vnb_create(parent, out, name, namelen, NULL, 0); +} + +mx_status_t vnb_add_file(const char* path, void* data, size_t len) { + vnboot_t* vnb = &vnb_root; + mx_status_t r; + if ((path[0] == '/') || (path[0] == 0)) return ERR_INVALID_ARGS; + for (;;) { + const char* nextpath = strchr(path, '/'); + if (nextpath == NULL) { + if (path[0] == 0) return ERR_INVALID_ARGS; + return _vnb_create(vnb, &vnb, path, strlen(path), data, len); + } else { + if (nextpath == path) return ERR_INVALID_ARGS; + r = _vnb_mkdir(vnb, &vnb, path, nextpath - path); + if (r < 0) return r; + path = nextpath + 1; + } + } +} + +vnode_t* vnb_get_root(void) { + return &vnb_root.vn; +} + +mx_status_t vnb_mount_at(vnode_t* vn, const char* dirname) { + if (dirname == NULL) { + return ERR_INVALID_ARGS; + } + if (strchr(dirname, '/')) { + return ERR_INVALID_ARGS; + } + vnboot_t* parent; + mx_status_t r; + if ((r = _vnb_mkdir(&vnb_root, &parent, dirname, strlen(dirname))) < 0) { + return r; + } + parent->mounted = vn; + return NO_ERROR; +} diff --git a/system/uapp/devmgr/vfs-device.c b/system/uapp/devmgr/vfs-device.c new file mode 100644 index 000000000..94a8010ae --- /dev/null +++ b/system/uapp/devmgr/vfs-device.c @@ -0,0 +1,257 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "device_internal.h" +#include "vfs.h" + +// NOTE +// - devmgr creates protocol family devices under /dev/protocol/... +// - these devices store a pointer to a list in their protocol_ops field +// (which is otherwise unused) +// - they also have DEV_TYPE_PROTOCOL set in their flags field +// - vnd_lookup() and vnd_readdir() know about this so they can look at +// this list when walking through protocol devices +// - TODO: replace with symlinks once we have 'em + +#define MXDEBUG 0 + +mx_status_t vnd_get_node(vnode_t** out, mx_device_t* dev); + +static void vnd_release(vnode_t* vn) { +} + +static mx_status_t vnd_open(vnode_t** _vn, uint32_t flags) { + vnode_t* vn = *_vn; + mx_device_t* dev = vn->pdata; + xprintf("vnd_open: vn=%p, dev=%p, flags=%d\n", vn, dev, flags); + mx_status_t r = device_open(dev, flags); + if (r == 0) { + vn_acquire(vn); + } + return r; +} + +static mx_status_t vnd_close(vnode_t* vn) { +// TODO: must integrate CLONE ops into refcounting first +#if 0 + mx_device_t* dev = vn->pdata; + device_close(dev); + vn_release(vn); +#endif + return NO_ERROR; +} + +static ssize_t vnd_read(vnode_t* vn, void* data, size_t len, size_t off) { + mx_protocol_char_t* ops = vn->pops; + if (ops) { + return ops->read(vn->pdata, data, len); + } else { + return ERR_NOT_SUPPORTED; + } +} + +static ssize_t vnd_write(vnode_t* vn, const void* data, size_t len, size_t off) { + mx_protocol_char_t* ops = vn->pops; + if (ops) { + return ops->write(vn->pdata, data, len); + } else { + return ERR_NOT_SUPPORTED; + } +} + +static ssize_t vnd_ioctl( + vnode_t* vn, uint32_t op, + const void* in_data, size_t in_len, + void* out_data, size_t out_len) { + + mx_protocol_char_t* ops = vn->pops; + if (ops && ops->ioctl) { + return ops->ioctl(vn->pdata, op, in_data, in_len, out_data, out_len); + } else { + return ERR_NOT_SUPPORTED; + } +} + +static mx_status_t vnd_lookup(vnode_t* vn, vnode_t** out, const char* name, size_t len) { + mx_device_t* parent = vn->pdata; + mx_device_t* dev; + + xprintf("vnd_lookup: vn=%p dev=%p name='%.*s'\n", vn, parent, (int)len, name); + + if (parent->flags & DEV_FLAG_PROTOCOL) { + struct list_node* list = parent->protocol_ops; + list_for_every_entry (list, dev, mx_device_t, pnode) { + xprintf("? dev=%p name='%s'\n", dev, dev->name); + size_t n = strlen(dev->name); + if (n != len) continue; + if (memcmp(dev->name, name, len)) continue; + xprintf("vnd_lookup: dev=%p\n", dev); + return vnd_get_node(out, dev); + } + return ERR_NOT_FOUND; + } + + list_for_every_entry (&parent->device_list, dev, mx_device_t, node) { + xprintf("? dev=%p name='%s'\n", dev, dev->name); + size_t n = strlen(dev->name); + if (n != len) continue; + if (memcmp(dev->name, name, len)) continue; + xprintf("vnd_lookup: dev=%p\n", dev); + return vnd_get_node(out, dev); + } + return ERR_NOT_FOUND; +} + +static mx_status_t vnd_getattr(vnode_t* vn, vnattr_t* attr) { + mx_device_t* dev = vn->pdata; + memset(attr, 0, sizeof(vnattr_t)); + if (list_is_empty(&dev->device_list)) { + attr->mode = V_TYPE_CDEV | V_IRUSR | V_IWUSR; + } else { + attr->mode = V_TYPE_DIR | V_IRUSR; + } + return NO_ERROR; +} + +static mx_status_t vnd_readdir(vnode_t* vn, void* cookie, void* data, size_t len) { + mx_device_t* parent = vn->pdata; + vdircookie_t* c = cookie; + mx_device_t* last = c->p; + size_t pos = 0; + char* ptr = data; + bool search = (last != NULL); + mx_status_t r; + mx_device_t* dev; + + if (parent->flags & DEV_FLAG_PROTOCOL) { + struct list_node* list = parent->protocol_ops; + list_for_every_entry (list, dev, mx_device_t, pnode) { + if (search) { + if (dev == last) { + search = false; + } + } else { + uint32_t vtype = list_is_empty(&dev->device_list) ? V_TYPE_DIR : V_TYPE_FILE; + r = vfs_fill_dirent((void*)(ptr + pos), len - pos, + dev->name, strlen(dev->name), + VTYPE_TO_DTYPE(vtype)); + if (r < 0) break; + last = dev; + pos += r; + } + } + c->p = last; + return pos; + } + + list_for_every_entry (&parent->device_list, dev, mx_device_t, node) { + if (search) { + if (dev == last) { + search = false; + } + } else { + uint32_t vtype = list_is_empty(&dev->device_list) ? V_TYPE_DIR : V_TYPE_FILE; + r = vfs_fill_dirent((void*)(ptr + pos), len - pos, + dev->name, strlen(dev->name), + VTYPE_TO_DTYPE(vtype)); + if (r < 0) break; + last = dev; + pos += r; + } + } + c->p = last; + return pos; +} + +static mx_status_t vnd_create(vnode_t* vn, vnode_t** out, const char* name, size_t len, uint32_t mode) { + return ERR_NOT_SUPPORTED; +} + +mx_status_t __mx_rio_clone(mx_handle_t h, mx_handle_t* handles, uint32_t* types); + +static mx_handle_t vnd_gethandles(vnode_t* vn, mx_handle_t* handles, uint32_t* ids) { + mx_device_t* dev = vn->pdata; + + if (dev->flags & DEV_FLAG_REMOTE) { + mx_status_t r = __mx_rio_clone(dev->remote, handles, ids); + return r; + } + + if ((handles[0] = vfs_create_handle(vn)) < 0) { + return handles[0]; + } + ids[0] = MX_HND_TYPE_MXIO_REMOTE; + + if (dev->event <= 0) { + return 1; + } + + if ((handles[1] = _magenta_handle_duplicate(dev->event)) < 0) { + _magenta_handle_close(handles[0]); + return handles[1]; + } + ids[1] = MX_HND_TYPE_MXIO_REMOTE; + return 2; +} + + +static vnode_ops_t vn_device_ops = { + .release = vnd_release, + .open = vnd_open, + .close = vnd_close, + .read = vnd_read, + .write = vnd_write, + .lookup = vnd_lookup, + .getattr = vnd_getattr, + .readdir = vnd_readdir, + .create = vnd_create, + .gethandles = vnd_gethandles, + .ioctl = vnd_ioctl, +}; + +mx_status_t vnd_get_node(vnode_t** out, mx_device_t* dev) { + if (dev->vnode) { + vn_acquire(dev->vnode); + *out = dev->vnode; + return NO_ERROR; + } else { + vnode_t* vn; + if ((vn = malloc(sizeof(vnode_t))) == NULL) return ERR_NO_MEMORY; + vn->ops = &vn_device_ops, + vn->vfs = NULL; + // TODO: set this based on device properties + vn->flags = V_FLAG_DEVICE; + vn->refcount = 1; + vn->pdata = dev; + vn->pops = NULL; + device_get_protocol(dev, MX_PROTOCOL_CHAR, (void**)&vn->pops); + dev->vnode = vn; + *out = vn; + return NO_ERROR; + } +} diff --git a/system/uapp/devmgr/vfs-memory.c b/system/uapp/devmgr/vfs-memory.c new file mode 100644 index 000000000..a9e4175c6 --- /dev/null +++ b/system/uapp/devmgr/vfs-memory.c @@ -0,0 +1,252 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +#include +#include + +#include +#include + +#define MXDEBUG 0 + +#define MAXBLOCKS 64 +#define BLOCKSIZE 8192 + +typedef struct mnode mnode_t; +struct mnode { + vnode_t vn; + const char* name; + size_t namelen; + size_t datalen; + struct list_node children; + struct list_node node; + uint8_t* block[MAXBLOCKS]; +}; + +mx_status_t mem_get_node(vnode_t** out, mx_device_t* dev); + +static void mem_release(vnode_t* vn) { +} + +static mx_status_t mem_open(vnode_t** _vn, uint32_t flags) { + vnode_t* vn = *_vn; + vn_acquire(vn); + return NO_ERROR; +} + +static mx_status_t mem_close(vnode_t* vn) { + vn_release(vn); + return NO_ERROR; +} + +static ssize_t mem_read(vnode_t* vn, void* _data, size_t len, size_t off) { + mnode_t* mem = vn->pdata; + uint8_t* data = _data; + ssize_t count = 0; + if (off >= mem->datalen) return 0; + if (len > (mem->datalen - off)) len = mem->datalen - off; + + size_t bno = off / BLOCKSIZE; + off = off % BLOCKSIZE; + while (len > 0) { + size_t xfer = (BLOCKSIZE - off); + if (len < xfer) xfer = len; + if (mem->block[bno] == NULL) { + xprintf("mem_read: hole at %zu\n", bno); + memset(data, 0, xfer); + } else { + memcpy(data, mem->block[bno] + off, xfer); + } + data += xfer; + len -= xfer; + count += xfer; + bno++; + off = 0; + } + return count; +} + +static ssize_t mem_write(vnode_t* vn, const void* _data, size_t len, size_t off) { + mnode_t* mem = vn->pdata; + const uint8_t* data = _data; + ssize_t count = 0; + size_t bno = off / BLOCKSIZE; + off = off % BLOCKSIZE; + while (len > 0) { + size_t xfer = (BLOCKSIZE - off); + if (len < xfer) xfer = len; + if (bno >= MAXBLOCKS) { + return count ? count : ERR_NO_MEMORY; + } + if (mem->block[bno] == NULL) { + xprintf("mem_write: alloc at %zu\n", bno); + if ((mem->block[bno] = calloc(1, BLOCKSIZE)) == NULL) { + return count ? count : ERR_NO_MEMORY; + } + } + memcpy(mem->block[bno] + off, data, xfer); + + size_t pos = bno * BLOCKSIZE + off + xfer; + if (pos > mem->datalen) mem->datalen = pos; + + data += xfer; + len -= xfer; + count += xfer; + bno++; + off = 0; + } + return count; +} + +static mx_status_t mem_lookup(vnode_t* vn, vnode_t** out, const char* name, size_t len) { + mnode_t* parent = vn->pdata; + mnode_t* mem; + xprintf("mem_lookup: vn=%p name='%.*s'\n", vn, (int)len, name); + list_for_every_entry (&parent->children, mem, mnode_t, node) { + xprintf("? dev=%p name='%s'\n", mem, mem->name); + if (mem->namelen != len) continue; + if (memcmp(mem->name, name, len)) continue; + vn_acquire(&mem->vn); + *out = &mem->vn; + return NO_ERROR; + } + return ERR_NOT_FOUND; +} + +static mx_status_t mem_getattr(vnode_t* vn, vnattr_t* attr) { + mnode_t* mem = vn->pdata; + memset(attr, 0, sizeof(vnattr_t)); + if (list_is_empty(&mem->children)) { + attr->size = mem->datalen; + attr->mode = V_TYPE_FILE | V_IRUSR; + } else { + attr->mode = V_TYPE_DIR | V_IRUSR; + } + return NO_ERROR; +} + +static mx_status_t mem_readdir(vnode_t* vn, void* cookie, void* data, size_t len) { + mnode_t* parent = vn->pdata; + vdircookie_t* c = cookie; + mnode_t* last = c->p; + size_t pos = 0; + char* ptr = data; + bool search = (last != NULL); + mx_status_t r; + mnode_t* mem; + + list_for_every_entry (&parent->children, mem, mnode_t, node) { + if (search) { + if (mem == last) { + search = false; + } + } else { + uint32_t vtype = list_is_empty(&mem->children) ? V_TYPE_DIR : V_TYPE_FILE; + r = vfs_fill_dirent((void*)(ptr + pos), len - pos, + mem->name, mem->namelen, + VTYPE_TO_DTYPE(vtype)); + if (r < 0) break; + last = mem; + pos += r; + } + } + c->p = last; + return pos; +} + +static mx_status_t _mem_create(mnode_t* parent, mnode_t** out, + const char* name, size_t namelen); + +static mx_status_t mem_create(vnode_t* vn, vnode_t** out, const char* name, size_t len, uint32_t mode) { + mnode_t* parent = vn->pdata; + mnode_t* mem; + mx_status_t r = _mem_create(parent, &mem, name, len); + if (r >= 0) { + *out = &mem->vn; + } + return r; +} + +static mx_status_t mem_gethandles(vnode_t* vn, mx_handle_t* handles, uint32_t* ids) { + return ERR_NOT_SUPPORTED; +} + +static vnode_ops_t vn_mem_ops = { + .release = mem_release, + .open = mem_open, + .close = mem_close, + .read = mem_read, + .write = mem_write, + .lookup = mem_lookup, + .getattr = mem_getattr, + .readdir = mem_readdir, + .create = mem_create, + .gethandles = mem_gethandles, +}; + +static mnode_t mem_root = { + .vn = { + .ops = &vn_mem_ops, + .refcount = 1, + .pdata = &mem_root, + }, + .name = "memory", + .namelen = 6, + .node = LIST_INITIAL_VALUE(mem_root.node), + .children = LIST_INITIAL_VALUE(mem_root.children), +}; + +static mx_status_t _mem_create(mnode_t* parent, mnode_t** out, + const char* name, size_t namelen) { + mnode_t* mem; + if ((mem = calloc(1, sizeof(mnode_t) + namelen + 1)) == NULL) return ERR_NO_MEMORY; + xprintf("mem_create: vn=%p, parent=%p name='%.*s'\n", + mem, parent, (int)namelen, name); + + char* tmp = ((char*)mem) + sizeof(mnode_t); + memcpy(tmp, name, namelen); + tmp[namelen] = 0; + + mem->vn.ops = &vn_mem_ops; + mem->vn.refcount = 1; + mem->vn.pdata = mem; + mem->name = tmp; + mem->namelen = namelen; + list_initialize(&mem->node); + list_initialize(&mem->children); + + list_add_tail(&parent->children, &mem->node); + *out = mem; + return NO_ERROR; +} + +static mx_status_t _mem_mkdir(mnode_t* parent, mnode_t** out, const char* name, size_t namelen) { + mnode_t* mem; + list_for_every_entry (&parent->children, mem, mnode_t, node) { + if (mem->namelen != namelen) continue; + if (memcmp(mem->name, name, namelen)) continue; + *out = mem; + return NO_ERROR; + } + return _mem_create(parent, out, name, namelen); +} + +vnode_t* mem_get_root(void) { + return &mem_root.vn; +} diff --git a/system/uapp/devmgr/vfs.c b/system/uapp/devmgr/vfs.c new file mode 100644 index 000000000..9ebc8fc10 --- /dev/null +++ b/system/uapp/devmgr/vfs.c @@ -0,0 +1,406 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "vfs.h" + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#define MXDEBUG 0 + +static vnode_t* vfs_root; + +// Starting at vnode vn, walk the tree described by the path string, +// returning the final vnode via out on success. +// +// If nameout is non-NULL, the final segment of the path will not +// be traversed (useful for stopping at the directory node for a +// create() op or the like) +mx_status_t vfs_walk(vnode_t* vn, vnode_t** out, const char* path, const char** nameout) { + const char* nextpath; + mx_status_t r; + size_t len; + + for (;;) { + if ((nextpath = strchr(path, '/')) != NULL) { + len = nextpath - path; + nextpath++; + xprintf("vfs_walk: vn=%p name='%.*s' nextpath='%s'\n", vn, (int)len, path, nextpath); + if ((r = vn->ops->lookup(vn, &vn, path, len))) { + return r; + } + path = nextpath; + } else { + xprintf("vfs_walk: vn=%p name='%s'\n", vn, path); + if (nameout != NULL) { + *out = vn; + *nameout = path; + return 0; + } + return vn->ops->lookup(vn, out, path, strlen(path)); + } + } + return ERR_NOT_FOUND; +} + +mx_status_t vfs_open(vnode_t** out, const char* path, uint32_t flags) { + if ((out == NULL) || (path == NULL) || (path[0] != '/')) { + return ERR_INVALID_ARGS; + } + if (path[1] == 0) { + vn_acquire(vfs_root); + *out = vfs_root; + return NO_ERROR; + } + vnode_t* vn; + mx_status_t r; + if ((r = vfs_walk(vfs_root, &vn, path + 1, NULL)) < 0) { + return r; + } + if ((r = vn->ops->open(&vn, flags)) < 0) { + xprintf("vn open r = %d", r); + return r; + } + *out = vn; + return NO_ERROR; +} + +mx_status_t vfs_create(vnode_t** out, const char* path, uint32_t flags, uint32_t mode) { + if ((out == NULL) || (path == NULL) || (path[0] != '/')) { + xprintf("vfs_create: bogus args\n"); + return ERR_INVALID_ARGS; + } + if (path[1] == 0) { + return ERR_NOT_ALLOWED; + } + xprintf("vfs_create: path='%s' flags=%d mode=%d\n", path, flags, mode); + vnode_t *vn; + mx_status_t r; + if ((r = vfs_walk(vfs_root, &vn, path + 1, &path)) < 0) { + xprintf("vfs_create: walk r=%d\n", r); + return r; + } + r = vn->ops->create(vn, out, path, strlen(path), mode); + xprintf("vfs_create: create r=%d\n", r); + return r; +} + +mx_status_t vfs_fill_dirent(vdirent_t* de, size_t delen, + const char* name, size_t len, uint32_t type) { + size_t sz = sizeof(vdirent_t) + len + 1; + + // round up to uint32 aligned + if (sz & 3) sz = (sz + 3) & (~3); + if (sz > delen) return ERR_TOO_BIG; + de->size = sz; + de->type = type; + memcpy(de->name, name, len); + de->name[len] = 0; + return sz; +} + +static mx_status_t vfs_get_handles(vnode_t* vn, mx_handle_t* hnds, uint32_t* ids) { + mx_status_t r; + if ((r = vn->ops->gethandles(vn, hnds, ids)) == ERR_NOT_SUPPORTED) { + // local vnode, we will create the handles + hnds[0] = vfs_create_handle(vn); + ids[0] = MX_HND_TYPE_MXIO_REMOTE; + r = 1; + } + return r; +} + +mx_status_t vfs_open_handles(mx_handle_t* hnds, uint32_t* ids, uint32_t arg, + const char* path, uint32_t flags) { + mx_status_t r; + vnode_t *vn; + + if (flags & O_CREAT) { + return ERR_NOT_SUPPORTED; + } + if ((r = vfs_open(&vn, path, flags)) < 0) { + return r; + } + if ((r = vfs_get_handles(vn, hnds, ids)) < 0) { + return r; + } + for (int i = 0; i < r; i++) { + ids[i] |= (arg & 0xFFFF) << 16; + } + return r; +} + +// remoteio transport wrapper +static mx_status_t root_handler(mx_rio_msg_t* msg, void* cookie) { + uint32_t len = msg->datalen; + int32_t arg = msg->arg; + mx_status_t r; + vnode_t* vn; + + msg->datalen = 0; + + for (unsigned i = 0; i < msg->hcount; i++) { + _magenta_handle_close(msg->handle[i]); + } + + switch (MX_RIO_OP(msg->op)) { + case MX_RIO_OPEN: { + if ((len < 1) || (len > 1024)) { + return ERR_INVALID_ARGS; + } + msg->data[len] = 0; + xprintf("root: open name='%s' flags=%d mode=%lld\n", (const char*) msg->data, arg, msg->off); + if (arg & O_CREAT) { + r = vfs_create(&vn, (const char*) msg->data, arg, msg->off); + } else { + r = vfs_open(&vn, (const char*) msg->data, arg); + } + xprintf("root: open: r=%d\n", r); + if (r < 0) { + return r; + } + uint32_t ids[VFS_MAX_HANDLES]; + if ((r = vfs_get_handles(vn, msg->handle, ids)) < 0) { + return r; + } + // TODO: ensure this is always true: + msg->off = MXIO_PROTOCOL_REMOTE; + msg->hcount = r; + xprintf("root: open: h=%x\n", msg->handle[0]); + return NO_ERROR; + } + case MX_RIO_CLONE: + msg->off = MXIO_PROTOCOL_REMOTE; + msg->hcount = 1; + if ((msg->handle[0] = vfs_create_root_handle()) < 0) { + return msg->handle[0]; + } else { + return NO_ERROR; + } + case MX_RIO_CLOSE: + return NO_ERROR; + default: + return ERR_NOT_SUPPORTED; + } +} + +typedef struct iostate iostate_t; +struct iostate { + vnode_t* vn; + size_t io_off; + vdircookie_t cookie; +}; + +static vnode_t* volatile vfs_txn_vn; +static volatile int vfs_txn_op; + +static mx_status_t _vfs_handler(mx_rio_msg_t* msg, void* cookie) { + iostate_t* ios = cookie; + vnode_t* vn = ios->vn; + uint32_t len = msg->datalen; + int32_t arg = msg->arg; + msg->datalen = 0; + + vfs_txn_vn = vn; + vfs_txn_op = MX_RIO_OP(msg->op); + + for (unsigned i = 0; i < msg->hcount; i++) { + _magenta_handle_close(msg->handle[i]); + } + + switch (MX_RIO_OP(msg->op)) { + case MX_RIO_CLOSE: + vn->ops->close(vn); + free(ios); + return NO_ERROR; + case MX_RIO_CLONE: { + uint32_t ids[VFS_MAX_HANDLES]; + mx_status_t r = vfs_get_handles(vn, msg->handle, ids); + if (r < 0) { + return r; + } + // TODO: ensure this is always true: + msg->off = MXIO_PROTOCOL_REMOTE; + msg->hcount = r; + return NO_ERROR; + } + case MX_RIO_READ: { + ssize_t r = vn->ops->read(vn, msg->data, arg, ios->io_off); + if (r >= 0) { + ios->io_off += r; + msg->off = ios->io_off; + msg->datalen = r; + } + return r; + } + case MX_RIO_WRITE: { + ssize_t r = vn->ops->write(vn, msg->data, len, ios->io_off); + if (r >= 0) { + ios->io_off += r; + msg->off = ios->io_off; + } + return r; + } + case MX_RIO_SEEK: + switch (arg) { + case SEEK_SET: + ios->io_off = msg->off; + break; + case SEEK_CUR: + break; + case SEEK_END: { + vnattr_t attr; + mx_status_t r; + if ((r = vn->ops->getattr(vn, &attr)) < 0) return r; + ios->io_off = attr.size; + break; + } + default: + return ERR_INVALID_ARGS; + } + msg->off = ios->io_off; + return NO_ERROR; + case MX_RIO_STAT: { + mx_status_t r; + msg->datalen = sizeof(vnattr_t); + if ((r = vn->ops->getattr(vn, (vnattr_t*) msg->data)) < 0) { + return r; + } + return msg->datalen; + } + case MX_RIO_READDIR: { + if (arg > MXIO_CHUNK_SIZE) { + return ERR_INVALID_ARGS; + } + mx_status_t r = vn->ops->readdir(vn, &ios->cookie, msg->data, arg); + if (r >= 0) { + msg->datalen = r; + } + return r; + } + case MX_RIO_IOCTL: { + if (!vn->ops->ioctl) { + return ERR_NOT_SUPPORTED; + } + if (len > MXIO_IOCTL_MAX_INPUT) { + return ERR_INVALID_ARGS; + } + char in_buf[MXIO_IOCTL_MAX_INPUT]; + memcpy(in_buf, msg->data, len); + + ssize_t r = vn->ops->ioctl(vn, msg->off, in_buf, len, msg->data, arg); + if (r >= 0) { + msg->off = 0; + msg->datalen = r; + } + return r; + } + default: + return ERR_NOT_SUPPORTED; + } +} + +static mxio_dispatcher_t* vfs_dispatcher; + +mx_handle_t vfs_create_root_handle(void) { + mx_handle_t h0, h1; + mx_status_t r; + if ((h0 = _magenta_message_pipe_create(&h1)) < 0) return h0; + if ((r = mxio_dispatcher_add(vfs_dispatcher, h0, root_handler, NULL))) { + _magenta_handle_close(h0); + _magenta_handle_close(h1); + return r; + } + return h1; +} + +static volatile int vfs_txn = -1; +static int vfs_txn_no = 0; + +static mx_status_t vfs_handler(mx_rio_msg_t* msg, void* cookie) { + vfs_txn_no = (vfs_txn_no + 1) & 0x0FFFFFFF; + vfs_txn = vfs_txn_no; + mx_status_t r = _vfs_handler(msg, cookie); + vfs_txn = -1; + return r; +} + +mx_handle_t vfs_create_handle(vnode_t* vn) { + mx_handle_t h0, h1; + mx_status_t r; + iostate_t* ios; + + if ((ios = calloc(1, sizeof(iostate_t))) == NULL) return ERR_NO_MEMORY; + ios->vn = vn; + + if ((h0 = _magenta_message_pipe_create(&h1)) < 0) { + free(ios); + return h0; + } + if (vn->flags & V_FLAG_BLOCKING) { + r = mxio_handler_create(h0, vfs_handler, ios); + } else { + r = mxio_dispatcher_add(vfs_dispatcher, h0, vfs_handler, ios); + } + if (r < 0) { + _magenta_handle_close(h0); + _magenta_handle_close(h1); + free(ios); + return r; + } + return h1; +} + +static int vfs_watchdog(void* arg) { + int txn = vfs_txn; + for (;;) { + _magenta_nanosleep(500000000ULL); + int now = vfs_txn; + if ((now == txn) && (now != -1)) { + vnode_t* vn = vfs_txn_vn; + printf("devmgr: watchdog: txn %d did not complete: vn=%p op=%d\n", txn, vn, vfs_txn_op); + if (vn->flags & V_FLAG_DEVICE) { + printf("devmgr: watchdog: vn=%p is device '%s'\n", vn, + ((mx_device_t*) vn->pdata)->name); + } + } + txn = now; + } + return 0; +} + +void vfs_init(vnode_t* root) { + vfs_root = root; + if (mxio_dispatcher_create(&vfs_dispatcher, mxio_rio_handler) == NO_ERROR) { + mxio_dispatcher_start(vfs_dispatcher); + } + mxr_thread_t* t; + mxr_thread_create(vfs_watchdog, NULL, "vfs-watchdog", &t); +} diff --git a/system/uapp/devmgr/vfs.h b/system/uapp/devmgr/vfs.h new file mode 100644 index 000000000..408d6230a --- /dev/null +++ b/system/uapp/devmgr/vfs.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +void vfs_init(vnode_t* root); + +// generate mxremoteio handles +mx_handle_t vfs_create_root_handle(void); +mx_handle_t vfs_create_handle(vnode_t* vn); + +mx_status_t vfs_open_handles(mx_handle_t* hnds, uint32_t* ids, uint32_t arg, + const char* path, uint32_t flags); diff --git a/system/uapp/dlog/BUILD.gn b/system/uapp/dlog/BUILD.gn new file mode 100644 index 000000000..089252ffa --- /dev/null +++ b/system/uapp/dlog/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("dlog") { + sources = [ + "dlog.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/dlog/dlog.c b/system/uapp/dlog/dlog.c new file mode 100644 index 000000000..7bbd92bcf --- /dev/null +++ b/system/uapp/dlog/dlog.c @@ -0,0 +1,49 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +int main(int argc, char **argv) { + bool tail = false; + mx_handle_t h; + + if ((argc == 2) && (!strcmp(argv[1], "-f"))) { + tail = true; + } + if ((h = _magenta_log_create(0)) < 0) { + printf("dlog: cannot open log\n"); + } + + char buf[MX_LOG_RECORD_MAX]; + mx_log_record_t* rec = (mx_log_record_t*) buf; + for (;;) { + if (_magenta_log_read(h, MX_LOG_RECORD_MAX, rec, tail ? MX_LOG_FLAG_WAIT : 0) > 0) { + char tmp[64]; + snprintf(tmp, 64, "[%05d.%03d] %c ", + (int) (rec->timestamp / 1000000000ULL), + (int) ((rec->timestamp / 1000000ULL) % 1000ULL), + (rec->flags & MX_LOG_FLAG_KERNEL) ? 'K' : 'U'); + write(1, tmp, strlen(tmp)); + write(1, rec->data, rec->datalen); + write(1, "\n", 1); + } else { + break; + } + } + return 0; +} \ No newline at end of file diff --git a/system/uapp/dlog/rules.mk b/system/uapp/dlog/rules.mk new file mode 100644 index 000000000..0fa0d468a --- /dev/null +++ b/system/uapp/dlog/rules.mk @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/dlog.c + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/uapp/i2c/i2c.c b/system/uapp/i2c/i2c.c new file mode 100644 index 000000000..3086ff4c5 --- /dev/null +++ b/system/uapp/i2c/i2c.c @@ -0,0 +1,375 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *prog_name; + +void print_usage(void) +{ + printf("Usage:\n"); + printf("\n"); + printf("%s DEVICE COMMAND [command arguments]\n", prog_name); + printf("DEVICE is either the i2c bus or i2c slave COMMAND applies to.\n"); + printf("COMMAND is one of the following commands, optionally followed \n"); + printf("arguments which are specific to each command.\n"); + printf("\n"); + printf("add-slave ADDRESS: Add a slave device to the target bus.\n"); + printf("ADDRESS is the 7 bit chip address of the slave in hex.\n"); + printf("\n"); + printf("remove-slave ADDRESS: Remove a slave from the target bus.\n"); + printf("ADDRESS is the 7 bit chip address of the slave in hex.\n"); + printf("\n"); + printf("set-frequency FREQUENCY: Set the frequency of the target bus.\n"); + printf("FREQUENCY is the frequency to set the bus to in decimal Hz.\n"); + printf("\n"); + printf("read LENGTH: Read data from the target slave device.\n"); + printf("LENGTH is the number of bytes to read in decimal.\n"); + printf("\n"); + printf("write [data]: Write data to the target slave device.\n"); + printf("data is a sequence of hex values which each represent one byte\n"); + printf("of data to write to the target device.\n"); + printf("\n"); + printf("transfer [segments]: Perform a tranfer to/from the i2c slave.\n"); + printf("segments is a series of segment descriptions which are a\n"); + printf("direction, a length, and then (for writes) a series of bytes\n"); + printf("in hexidecimal.\n"); + printf("\n"); + printf("The direction is specified as either \"w\" for writes, or\n"); + printf("\"r\" for reads.\n"); + printf("\n"); + printf("For example, to perform a write of one byte and then a read\n"); + printf("of one byte without giving up the bus:\n"); + printf("%s [dev] transfer w 1 00 r 1\n", prog_name); +} + +int cmd_add_slave(int fd, int argc, const char **argv) +{ + if (argc < 1) { + print_usage(); + return 1; + } + + long int address = strtol(argv[0], NULL, 16); + if (errno) { + print_usage(); + return errno; + } + + i2c_ioctl_add_slave_args_t add_slave_args = { + .chip_address_width = I2C_7BIT_ADDRESS, + .chip_address = address, + }; + + int ret = mxio_ioctl(fd, I2C_BUS_ADD_SLAVE, + &add_slave_args, sizeof(add_slave_args), + NULL, 0); + if (ret < 0) { + printf("Error when adding I2C slave. (%d)\n", ret); + return 1; + } + + return 0; +} + +int cmd_remove_slave(int fd, int argc, const char **argv) +{ + if (argc < 1) { + print_usage(); + return 1; + } + + long int address = strtol(argv[0], NULL, 16); + if (errno) { + print_usage(); + return errno; + } + + i2c_ioctl_remove_slave_args_t remove_slave_args = { + .chip_address_width = I2C_7BIT_ADDRESS, + .chip_address = address, + }; + + int ret = mxio_ioctl(fd, I2C_BUS_REMOVE_SLAVE, + &remove_slave_args, sizeof(remove_slave_args), + NULL, 0); + if (ret < 0) { + printf("Error when removing I2C slave. (%d)\n", ret); + return 1; + } + + return 0; +} + +int cmd_set_bus_frequency(int fd, int argc, const char **argv) +{ + if (argc < 1) { + print_usage(); + return 1; + } + + long int frequency = strtol(argv[0], NULL, 10); + if (errno) { + print_usage(); + return errno; + } + + i2c_ioctl_set_bus_frequency_args_t set_bus_frequency_args = { + .frequency = frequency, + }; + + int ret = mxio_ioctl(fd, I2C_BUS_SET_FREQUENCY, + &set_bus_frequency_args, + sizeof(set_bus_frequency_args), + NULL, 0); + if (ret < 0) { + printf("Error when setting bus frequency. (%d)\n", ret); + return 1; + } + + return 0; +} + +int cmd_read(int fd, int argc, const char **argv) +{ + if (argc < 1) { + print_usage(); + return 1; + } + + long int length = strtol(argv[0], NULL, 10); + if (errno) { + print_usage(); + return errno; + } + + uint8_t *buf = malloc(length); + if (!buf) { + printf("Failed to allocate buffer.\n"); + return 1; + } + + int ret = read(fd, buf, length); + if (ret < 0) { + printf("Error reading from slave. (%d)\n", ret); + goto cmd_read_finish; + } + + for (int i = 0; i < length; i++) { + printf(" %02x", buf[i]); + } + printf("\n"); + +cmd_read_finish: + free(buf); + return ret; +} + +int cmd_write(int fd, int argc, const char **argv) +{ + if (argc < 1) { + print_usage(); + return 1; + } + + uint8_t *buf = malloc(argc); + if (!buf) { + printf("Failed to allocate buffer.\n"); + return 1; + } + + int ret = 0; + + for (int i = 0; i < argc; i++) { + buf[i] = strtol(argv[i], NULL, 16); + if (errno) { + ret = errno; + print_usage(); + goto cmd_write_finish; + } + } + + ret = write(fd, buf, argc); + if (ret < 0) + printf("Error writing to slave. (%d)\n", ret); + +cmd_write_finish: + free(buf); + return ret; +} + +int cmd_transfer(int fd, int argc, const char **argv) +{ + const size_t base_size = offsetof(i2c_slave_ioctl_segment_t, buf); + int ret = NO_ERROR; + + // Figure out how big our buffers need to be. + size_t in_len = 0; + size_t out_len = 0; + int count = argc; + const char **arg = argv; + while (count) { + if (count < 2) { + print_usage(); + goto cmd_transfer_finish_2; + } + + in_len += base_size; + + int read; + if (!strcmp(arg[0], "r")) { + read = 1; + } else if (!strcmp(arg[0], "w")) { + read = 0; + } else { + print_usage(); + goto cmd_transfer_finish_2; + } + + long int length = strtol(arg[1], NULL, 10); + if (errno) { + print_usage(); + return errno; + } + arg += 2; + count -= 2; + if (read) { + out_len += length; + } else { + in_len += length; + if (length > count) { + print_usage(); + goto cmd_transfer_finish_2; + } + arg += length; + count -= length; + } + } + + + // Allocate the input and output buffers. + void *in_buf = malloc(in_len); + void *out_buf = malloc(out_len); + if (!in_buf || !out_buf) { + ret = 1; + goto cmd_transfer_finish_1; + } + + + // Fill the "input" buffer which is sent to the ioctl. + uintptr_t in_addr = (uintptr_t)in_buf; + int i = 0; + while (i < argc) { + i2c_slave_ioctl_segment_t *ioctl_segment = + (i2c_slave_ioctl_segment_t *)in_addr; + in_addr += base_size; + + if (!strcmp(argv[i++], "r")) { + ioctl_segment->read = 1; + ioctl_segment->len = strtol(argv[i++], NULL, 10); + if (errno) { + print_usage(); + return errno; + } + } else { + ioctl_segment->read = 0; + ioctl_segment->len = strtol(argv[i++], NULL, 10); + if (errno) { + print_usage(); + return errno; + } + + for (int seg = 0; seg < ioctl_segment->len; seg++) { + *(uint8_t *)(in_addr++) = strtol(argv[i++], NULL, 16); + if (errno) { + print_usage(); + return errno; + } + } + } + } + + ret = mxio_ioctl(fd, I2C_SLAVE_TRANSFER, + in_buf, in_len, out_buf, out_len); + if (ret < 0) + goto cmd_transfer_finish_1; + + for (size_t i = 0; i < out_len; i++) + printf(" %02x", ((uint8_t *)out_buf)[i]); + printf("\n"); + + ret = 0; + +cmd_transfer_finish_1: + free(in_buf); + free(out_buf); +cmd_transfer_finish_2: + return ret; +} + +int main(int argc, const char **argv) +{ + if (argc < 1) + return 1; + + prog_name = argv[0]; + + if (argc < 3) { + print_usage(); + return 1; + } + + const char *dev = argv[1]; + const char *cmd = argv[2]; + + argc -= 3; + argv += 3; + + int fd = open(dev, O_WRONLY); + if (fd < 0) { + printf("Error opening I2C device.\n"); + return 1; + } + + if (!strcmp("add-slave", cmd)) { + return cmd_add_slave(fd, argc, argv); + } else if (!strcmp("remove-slave", cmd)) { + return cmd_remove_slave(fd, argc, argv); + } else if (!strcmp("set-frequency", cmd)) { + return cmd_set_bus_frequency(fd, argc, argv); + } else if (!strcmp("read", cmd)) { + return cmd_read(fd, argc, argv); + } else if (!strcmp("write", cmd)) { + return cmd_write(fd, argc, argv); + } else if (!strcmp("transfer", cmd)) { + return cmd_transfer(fd, argc, argv); + } else { + printf("Unrecognized command %s.\n", cmd); + print_usage(); + return 1; + } + + printf("We should never get here!.\n"); + return 1; +} diff --git a/system/uapp/i2c/rules.mk b/system/uapp/i2c/rules.mk new file mode 100644 index 000000000..6d8301f6b --- /dev/null +++ b/system/uapp/i2c/rules.mk @@ -0,0 +1,46 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +## +## Copyright 2016 The Fuchsia Authors +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/i2c.c + +MODULE_DEPS := \ + ulib/ddk \ + ulib/magenta \ + ulib/musl \ + ulib/mxio + +include make/module.mk diff --git a/system/uapp/mxsh/BUILD.gn b/system/uapp/mxsh/BUILD.gn new file mode 100644 index 000000000..49569a593 --- /dev/null +++ b/system/uapp/mxsh/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("mxsh") { + sources = [ + "builtin.c", + "mxsh.c", + "mxsh.h", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxu", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/mxsh/builtin.c b/system/uapp/mxsh/builtin.c new file mode 100644 index 000000000..7075c07ff --- /dev/null +++ b/system/uapp/mxsh/builtin.c @@ -0,0 +1,390 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include "mxsh.h" + +#include +#include +#include +#include +#include + +static int mxc_dump(int argc, char** argv) { + int fd; + ssize_t len; + off_t off; + char buf[4096]; + + if (argc != 2) { + printf("usage: dump \n"); + return -1; + } + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + printf("error: cannot open '%s'\n", argv[1]); + return -1; + } + off = 0; + for (;;) { + len = read(fd, buf, sizeof(buf)); + if (len <= 0) { + if (len) + printf("error: io\n"); + break; + } + mxu_hexdump8_ex(buf, len, off); + off += len; + } + close(fd); + return len; +} + +static int mxc_echo(int argc, char** argv) { + argc--; + argv++; + while (argc > 0) { + write(1, argv[0], strlen(argv[0])); + argc--; + argv++; + if (argc) + write(1, " ", 1); + } + write(1, "\n", 1); + return 0; +} + +static const char* modestr(uint32_t mode) { + switch (mode & S_IFMT) { + case S_IFREG: + return "-"; + case S_IFCHR: + return "c"; + case S_IFBLK: + return "b"; + case S_IFDIR: + return "d"; + default: + return "?"; + } +} + +int getdirents(int fd, void* ptr, size_t len); + +static int mxc_ls(int argc, char** argv) { + const char* dirn; + struct stat s; + char buf[4096]; + char tmp[2048]; + int fd, r, off; + size_t dirln; + + if ((argc > 1) && !strcmp(argv[1], "-l")) { + argc--; + argv++; + } + if (argc < 2) { + dirn = "/"; + } else { + dirn = argv[1]; + } + dirln = strlen(dirn); + + if (argc > 2) { + printf("usage: ls [ ]\n"); + return -1; + } + fd = open(dirn, O_RDONLY); + if (fd < 0) { + printf("error: cannot open '%s'\n", dirn); + return -1; + } + for (;;) { + r = getdirents(fd, buf, sizeof(buf)); + if (r <= 0) { + if (r) + printf("error: reading dirents\n"); + break; + } + off = 0; + while (off < r) { + vdirent_t* de = (vdirent_t*)(buf + off); + memset(&s, 0, sizeof(struct stat)); + if ((strlen(de->name) + dirln + 2) <= sizeof(tmp)) { + snprintf(tmp, sizeof(tmp), "%s/%s", dirn, de->name); + stat(tmp, &s); + } + printf("%s %8llu %s\n", modestr(s.st_mode), s.st_size, de->name); + off += de->size; + } + } + close(fd); + return r; +} + +#if WITH_LIBC_IO_HOOKS +static int mxc_list(int argc, char** argv) { + char line[1024]; + FILE* fp; + int num = 1; + + if (argc != 2) { + printf("usage: list \n"); + return -1; + } + + fp = fopen(argv[1], "r"); + if (fp == NULL) { + printf("error: cannot open '%s'\n", argv[1]); + return -1; + } + while (fgets(line, 1024, fp) != NULL) { + printf("%5d | %s", num, line); + num++; + } + fclose(fp); + return 0; +} +#endif + +static int mxc_cp(int argc, char** argv) { + char data[4096]; + int fdi = -1, fdo = -1; + int r, wr; + int count = 0; + if (argc != 3) { + printf("usage: cp \n"); + return -1; + } + if ((fdi = open(argv[1], O_RDONLY)) < 0) { + printf("error: cannot open '%s'\n", argv[1]); + return -1; + } + if ((fdo = open(argv[2], O_WRONLY | O_CREAT)) < 0) { + printf("error: cannot open '%s'\n", argv[2]); + r = fdo; + goto done; + } + for (;;) { + if ((r = read(fdi, data, sizeof(data))) < 0) { + printf("error: failed reading from '%s'\n", argv[1]); + break; + } + if (r == 0) { + break; + } + if ((wr = write(fdo, data, r)) != r) { + printf("error: failed writing to '%s'\n", argv[2]); + r = wr; + break; + } + count += r; + } + printf("[copied %d bytes]\n", count); +done: + close(fdi); + close(fdo); + return r; +} + +typedef struct failure { + list_node_t node; + int cause; + int rc; + char name[0]; +} failure_t; + +static void mxc_fail_test(list_node_t* failures, const char* name, int cause, int rc) { + size_t name_len = strlen(name) + 1; + failure_t* failure = malloc(sizeof(failure_t) + name_len); + failure->cause = cause; + failure->rc = rc; + memcpy(failure->name, name, name_len); + list_add_tail(failures, &failure->node); +} + +#define TESTNAME_SUFFIX "-test" +enum { + FAILED_TO_LAUNCH, + FAILED_TO_WAIT, + FAILED_TO_RETURN_CODE, + FAILED_NONZERO_RETURN_CODE, +}; +static int mxc_runtests(int argc, char** argv) { + char buf[4096]; + list_node_t failures = LIST_INITIAL_VALUE(failures); + int r, off; + + int total_count = 0; + int failed_count = 0; + + const char* dirn = "/boot/bin"; + int fd = open(dirn, O_RDONLY); + if (fd < 0) { + printf("error: cannot open '%s'\n", dirn); + return -1; + } + size_t test_suffix_len = sizeof(TESTNAME_SUFFIX) - 1; + for (;;) { + r = getdirents(fd, buf, sizeof(buf)); + if (r <= 0) { + if (r) + printf("error: reading dirents\n"); + break; + } + off = 0; + while (off < r) { + vdirent_t* de = (vdirent_t*)(buf + off); + off += de->size; + + size_t len = strlen(de->name); + if (len < test_suffix_len) { + continue; + } + char* suffix = de->name + len - test_suffix_len; + if (strncmp(suffix, TESTNAME_SUFFIX, test_suffix_len)) { + continue; + } + total_count++; + + printf("\n------------------------------------------------\n" + "RUNNING TEST: %s\n\n", de->name); + char name[4096]; + snprintf(name, sizeof(name), "/boot/bin/%s", de->name); + char* argv[] = {name}; + mx_handle_t handle = mxio_start_process(1, argv); + if (handle < 0) { + printf("FAILURE: Failed to launch %s: %d\n", de->name, handle); + mxc_fail_test(&failures, de->name, FAILED_TO_LAUNCH, 0); + failed_count++; + continue; + } + + mx_status_t status = _magenta_handle_wait_one(handle, MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, 0, 0); + if (status != NO_ERROR) { + printf("FAILURE: Failed to wait for process exiting %s: %d\n", de->name, status); + mxc_fail_test(&failures, de->name, FAILED_TO_WAIT, 0); + failed_count++; + continue; + } + + // read the return code + mx_process_info_t proc_info; + status = _magenta_process_get_info(handle, &proc_info, sizeof(proc_info)); + _magenta_handle_close(handle); + + if (status != NO_ERROR) { + printf("FAILURE: Failed to get process return code %s: %d\n", de->name, status); + mxc_fail_test(&failures, de->name, FAILED_TO_RETURN_CODE, 0); + failed_count++; + continue; + } + + if (proc_info.return_code == 0) { + printf("PASSED: %s passed\n", de->name); + } else { + printf("FAILED: %s exited with nonzero status: %d\n", de->name, proc_info.return_code); + mxc_fail_test(&failures, de->name, FAILED_NONZERO_RETURN_CODE, proc_info.return_code); + failed_count++; + } + } + } + + close(fd); + + printf("\nSUMMARY: Ran %d tests: %d failed\n", total_count, failed_count); + + if (failed_count) { + printf("\nThe following tests failed:\n"); + failure_t* failure = NULL; + failure_t* temp = NULL; + list_for_every_entry_safe(&failures, failure, temp, failure_t, node) { + switch (failure->cause) { + case FAILED_TO_LAUNCH: + printf("%s: failed to launch\n", failure->name); + break; + case FAILED_TO_WAIT: + printf("%s: failed to wait\n", failure->name); + break; + case FAILED_TO_RETURN_CODE: + printf("%s: failed to return exit code\n", failure->name); + break; + case FAILED_NONZERO_RETURN_CODE: + printf("%s: returned nonzero: %d\n", failure->name, failure->rc); + break; + } + free(failure); + } + } + + return 0; +} + +static int mxc_dm(int argc, char** argv) { + if (argc != 2) { + printf("usage: dm \n"); + return -1; + } + int fd = open("/dev/dmctl", O_RDWR); + if (fd >= 0) { + int r = write(fd, argv[1], strlen(argv[1])); + if (r < 0) { + printf("error: cannot write dmctl: %d\n", r); + } + close(fd); + return r; + } else { + printf("error: cannot open dmctl: %d\n", fd); + return fd; + } +} + +static int mxc_help(int argc, char** argv); + +builtin_t builtins[] = { + {"cp", mxc_cp, "copy a file"}, + {"dump", mxc_dump, "display a file in hexadecimal"}, + {"echo", mxc_echo, "print its arguments"}, + {"help", mxc_help, "list built-in shell commands"}, + {"dm", mxc_dm, "send command to device manager"}, + {"list", mxc_list, "display a text file with line numbers"}, + {"ls", mxc_ls, "list directory contents"}, + {"runtests", mxc_runtests, "run all test programs"}, + {NULL, NULL, NULL}, +}; + +static int mxc_help(int argc, char** argv) { + builtin_t* b; + int n = 8; + for (b = builtins; b->name != NULL; b++) { + int len = strlen(b->name); + if (len > n) + n = len; + } + for (b = builtins; b->name != NULL; b++) { + printf("%-*s %s\n", n, b->name, b->desc); + } + printf("%-*s %s\n", n, "", "run "); + printf("%-*s %s\n\n", n, "`command", "send command to kernel console"); + return 0; +} diff --git a/system/uapp/mxsh/mxsh.c b/system/uapp/mxsh/mxsh.c new file mode 100644 index 000000000..c79c15c5e --- /dev/null +++ b/system/uapp/mxsh/mxsh.c @@ -0,0 +1,359 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "mxsh.h" + +#define LINE_MAX 1024 + +void cputc(uint8_t ch) { + write(1, &ch, 1); +} + +void cputs(const char* s, size_t len) { + write(1, s, len); +} + +int cgetc(void) { + uint8_t ch; + for (;;) { + mxio_wait_fd(0, MXIO_EVT_READABLE, NULL); + int r = read(0, &ch, 1); + if (r < 0) { + return r; + } + if (r == 1) { + return ch; + } + } +} + +void beep(void) { +} + +#define CTRL_C 3 +#define BACKSPACE 8 +#define NL 10 +#define CTRL_L 12 +#define CR 13 +#define ESC 27 +#define DELETE 127 + +#define EXT_UP 'A' +#define EXT_DOWN 'B' +#define EXT_RIGHT 'C' +#define EXT_LEFT 'D' + +typedef struct { + list_node_t node; + int len; + char line[LINE_MAX]; +} hitem; + +list_node_t history = LIST_INITIAL_VALUE(history); + +static const char nl[2] = {'\r', '\n'}; +static const char bs[3] = {8, ' ', 8}; +static const char erase_line[5] = {ESC, '[', '2', 'K', '\r'}; + +typedef struct { + int pos; + int save_pos; + hitem* item; + char save[LINE_MAX]; + char line[LINE_MAX+1]; +} editstate; + +void history_add(editstate* es) { + hitem *item; + if (es->pos && ((item = malloc(sizeof(hitem))) != NULL)) { + item->len = es->pos; + memset(item->line, 0, sizeof(item->line)); + memcpy(item->line, es->line, es->pos); + list_add_tail(&history, &item->node); + } +} + +int history_up(editstate* es) { + hitem* next; + if (es->item) { + next = list_prev_type(&history, &es->item->node, hitem, node); + if (next != NULL) { + es->item = next; + memcpy(es->line, es->item->line, es->item->len); + es->pos = es->item->len; + cputs(erase_line, sizeof(erase_line)); + return 1; + } else { + beep(); + return 0; + } + } else { + next = list_peek_tail_type(&history, hitem, node); + if (next != NULL) { + es->item = next; + memset(es->save, 0, sizeof(es->save)); + memcpy(es->save, es->line, es->pos); + es->save_pos = es->pos; + es->pos = es->item->len; + memcpy(es->line, es->item->line, es->pos); + cputs(erase_line, sizeof(erase_line)); + return 1; + } else { + return 0; + } + } +} + +int history_down(editstate* es) { + if (es->item == NULL) { + beep(); + return 0; + } + hitem* next = list_next_type(&history, &es->item->node, hitem, node); + if (next != NULL) { + es->item = next; + es->pos = es->item->len; + memcpy(es->line, es->item->line, es->pos); + } else { + memcpy(es->line, es->save, es->save_pos); + es->pos = es->save_pos; + es->item = NULL; + } + cputs(erase_line, sizeof(erase_line)); + return 1; +} + +int readline(editstate* es) { + int a, b, c; + es->pos = 0; + es->save_pos = 0; + es->item = NULL; +again: + cputc('>'); + cputc(' '); + if (es->pos) { + cputs(es->line, es->pos); + } + for (;;) { + if ((c = cgetc()) < 0) { + es->item = NULL; + return c; + } + if ((c >= ' ') && (c < 127)) { + if (es->pos < LINE_MAX) { + es->line[es->pos++] = c; + cputc(c); + } + beep(); + continue; + } + switch (c) { + case CTRL_C: + es->pos = 0; + es->item = NULL; + cputs(nl, sizeof(nl)); + goto again; + case CTRL_L: + cputs(erase_line, sizeof(erase_line)); + goto again; + case BACKSPACE: + case DELETE: + backspace: + if (es->pos > 0) { + es->pos--; + cputs(bs, sizeof(bs)); + } else { + beep(); + } + es->item = NULL; + continue; + case NL: + case CR: + es->line[es->pos] = 0; + cputs(nl, sizeof(nl)); + history_add(es); + return 0; + case ESC: + if ((a = cgetc()) < 0) { + return a; + } + if ((b = cgetc()) < 0) { + return b; + } + if (a != '[') { + break; + } + switch (b) { + case EXT_UP: + if (history_up(es)) { + goto again; + } + break; + case EXT_DOWN: + if (history_down(es)) { + goto again; + } + break; + case EXT_RIGHT: + break; + case EXT_LEFT: + goto backspace; + } + } + beep(); + } +} + +static int split(char* line, char* argv[], int max) { + int n = 0; + while (max > 0) { + while (isspace(*line)) + line++; + if (*line == 0) + break; + argv[n++] = line; + max--; + line++; + while (*line && (!isspace(*line))) + line++; + if (*line == 0) + break; + *line++ = 0; + } + return n; +} + +void joinproc(mx_handle_t p) { + mx_status_t r; + mx_signals_t satisfied, satisfiable; + + r = _magenta_handle_wait_one(p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, + &satisfied, &satisfiable); + if (r != NO_ERROR) { + printf("[process(%x): wait failed? %d]\n", p, r); + return; + } + + // read the return code + mx_process_info_t proc_info; + r = _magenta_process_get_info(p, &proc_info, sizeof(proc_info)); + if (r != NO_ERROR) { + printf("[process(%x): process_get_info failed? %d]\n", p, r); + } else { + printf("[process(%x): status: %d]\n", p, proc_info.return_code); + } + + _magenta_handle_close(p); +} + +void* joiner(void* arg) { + joinproc((uintptr_t)arg); + return NULL; +} + +void command(int argc, char** argv, bool runbg) { + char tmp[LINE_MAX + 32]; + int i; + + for (i = 0; builtins[i].name != NULL; i++) { + if (strcmp(builtins[i].name, argv[0])) + continue; + builtins[i].func(argc, argv); + return; + } + + snprintf(tmp, sizeof(tmp), "%s%s", + (argv[0][0] == '/') ? "" : "/boot/bin/", argv[0]); + argv[0] = tmp; + mx_handle_t p = mxio_start_process(argc, argv); + if (p < 0) { + printf("process failed to start (%d)\n", p); + return; + } + if (runbg) { + // TODO: migrate to a unified waiter thread once we can wait + // on process exit + pthread_t t; + if (pthread_create(&t, NULL, joiner, (void*)((uintptr_t)p))) { + _magenta_handle_close(p); + } + } else { + joinproc(p); + } +} + +void console(void) { + editstate es; + char *line; + bool runbg; + char* argv[32]; + int argc; + int len; + + while (readline(&es) == 0) { + line = es.line; + if (line[0] == '`') { + _magenta_debug_send_command(line + 1, strlen(line) - 1); + continue; + } + len = strlen(line); + + // trim whitespace + while ((len > 0) && (line[len - 1] <= ' ')) { + len--; + line[len] = 0; + } + + // handle backgrounding + if ((len > 0) && (line[len - 1] == '&')) { + line[len - 1] = 0; + runbg = true; + } else { + runbg = false; + } + + // tokenize and execute + argc = split(line, argv, 32); + if (argc) { + command(argc, argv, runbg); + } + } +} + +int main(int argc, char** argv) { + const char* banner = "\033]2;mxsh\007\nMXCONSOLE...\n"; + cputs(banner, strlen(banner)); + console(); + return 0; +} diff --git a/system/uapp/mxsh/mxsh.h b/system/uapp/mxsh/mxsh.h new file mode 100644 index 000000000..c07165299 --- /dev/null +++ b/system/uapp/mxsh/mxsh.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +typedef struct builtin { + const char* name; + int (*func)(int argc, char** argv); + const char* desc; +} builtin_t; + +extern builtin_t builtins[]; \ No newline at end of file diff --git a/system/uapp/mxsh/rules.mk b/system/uapp/mxsh/rules.mk new file mode 100644 index 000000000..a4ac03fb4 --- /dev/null +++ b/system/uapp/mxsh/rules.mk @@ -0,0 +1,33 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/mxsh.c \ + $(LOCAL_DIR)/builtin.c \ + +MODULE_NAME := mxsh + +MODULE_DEPS := \ + ulib/mxio ulib/mxu ulib/musl ulib/magenta + +USER_MANIFEST_LINES += docs/kernel-objects.md=docs/magenta/kernel_objects.md +USER_MANIFEST_LINES += docs/LICENSE=kernel/LICENSE + +include make/module.mk diff --git a/system/uapp/netsvc/BUILD.gn b/system/uapp/netsvc/BUILD.gn new file mode 100644 index 000000000..85374161f --- /dev/null +++ b/system/uapp/netsvc/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("netsvc") { + sources = [ + "netsvc.c", + ] + deps = [ + "//system/ulib/inet6", + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxu", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/netsvc/netsvc.c b/system/uapp/netsvc/netsvc.c new file mode 100644 index 000000000..482e0d1b1 --- /dev/null +++ b/system/uapp/netsvc/netsvc.c @@ -0,0 +1,114 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include + +#include + +#define MAX_LOG_LINE (MX_LOG_RECORD_MAX + 32) + +static mx_handle_t loghandle; + +int get_log_line(char* out) { + char buf[MX_LOG_RECORD_MAX + 1]; + mx_log_record_t* rec = (mx_log_record_t*)buf; + if (_magenta_log_read(loghandle, MX_LOG_RECORD_MAX, rec, 0) > 0) { + if (rec->datalen && (rec->data[rec->datalen - 1] == '\n')) { + rec->datalen--; + } + rec->data[rec->datalen] = 0; + snprintf(out, MAX_LOG_LINE, "[%05d.%03d] %c %s\n", + (int)(rec->timestamp / 1000000000ULL), + (int)((rec->timestamp / 1000000ULL) % 1000ULL), + (rec->flags & MX_LOG_FLAG_KERNEL) ? 'K' : 'U', + rec->data); + return strlen(out); + } else { + return 0; + } +} + +#define MAX_LOG_DATA 1280 + +typedef struct logpacket { + uint32_t magic; + uint32_t seqno; + char data[MAX_LOG_DATA]; +} logpacket_t; + +static volatile uint32_t seqno = 1; +static volatile uint32_t pending = 0; + +void udp6_recv(void* data, size_t len, + const ip6_addr* daddr, uint16_t dport, + const ip6_addr* saddr, uint16_t sport) { + if (dport != 33338) + return; + if (len != 8) + return; + logpacket_t* pkt = data; + if (pkt->magic != 0xaeae1123) + return; + if (pkt->seqno != seqno) + return; + seqno++; + pending = 0; + printf("ack!\n"); +} + +int main(int argc, char** argv) { + logpacket_t pkt; + int len = 0; + if ((loghandle = _magenta_log_create(0)) < 0) { + return -1; + } + _magenta_nanosleep(1000000000ULL); + printf("netsvc: main()\n"); + while (netifc_open() < 0) { + _magenta_nanosleep(100000000ULL); + } + printf("netsvc: start\n"); + for (;;) { + if (pending == 0) { + pkt.magic = 0xaeae1123; + pkt.seqno = seqno; + len = 0; + while (len < (MAX_LOG_DATA - MAX_LOG_LINE)) { + int r = get_log_line(pkt.data + len); + if (r > 0) { + len += r; + } else { + break; + } + } + if (len) { + len += 8; + pending = 1; + goto transmit; + } + } + if (netifc_timer_expired()) { + transmit: + udp6_send(&pkt, 8 + len, &ip6_ll_all_nodes, 33337, 33338); + netifc_set_timer(100); + } + netifc_poll(); + } + return 0; +} diff --git a/system/uapp/netsvc/rules.mk b/system/uapp/netsvc/rules.mk new file mode 100644 index 000000000..a477d359e --- /dev/null +++ b/system/uapp/netsvc/rules.mk @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_NAME := netsvc + +MODULE_TYPE := userapp + +MODULE_HEADER_DEPS := \ + ulib/mxu + +MODULE_SRCS += \ + $(LOCAL_DIR)/netsvc.c \ + +MODULE_DEPS := \ + ulib/inet6 ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/uapp/strerror/BUILD.gn b/system/uapp/strerror/BUILD.gn new file mode 100644 index 000000000..ce23d6cec --- /dev/null +++ b/system/uapp/strerror/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("strerror") { + sources = [ + "strerror.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mojo", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/strerror/rules.mk b/system/uapp/strerror/rules.mk new file mode 100644 index 000000000..a3fe9cd00 --- /dev/null +++ b/system/uapp/strerror/rules.mk @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/strerror.c + +MODULE_DEPS := \ + ulib/musl ulib/mojo ulib/mxio ulib/runtime ulib/magenta + +include make/module.mk diff --git a/system/uapp/strerror/strerror.c b/system/uapp/strerror/strerror.c new file mode 100644 index 000000000..6b891e8ca --- /dev/null +++ b/system/uapp/strerror/strerror.c @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + for (int idx = 1; idx < argc; idx++) { + errno = 0; + long error_long = strtol(argv[idx], NULL, 10); + if (errno) + exit(ERR_INVALID_ARGS); + int error = (int)error_long; + const char* mx_error = mx_strstatus((mx_status_t)error); + const char* mojo_error = mojo_strerror((mojo_result_t)error); + char* posix_error = strerror(error); + printf("Int value: %d\n", error); + printf("\tMagenta error: %s\n", mx_error); + printf("\tMojo error: %s\n", mojo_error); + printf("\tPosix error: %s\n", posix_error); + } +} diff --git a/system/uapp/userboot/BUILD.gn b/system/uapp/userboot/BUILD.gn new file mode 100644 index 000000000..183f58877 --- /dev/null +++ b/system/uapp/userboot/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("userboot") { + sources = [ + "userboot.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/uapp/userboot/rules.mk b/system/uapp/userboot/rules.mk new file mode 100644 index 000000000..417e0a171 --- /dev/null +++ b/system/uapp/userboot/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/userboot.c + +MODULE_NAME := userboot + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/uapp/userboot/userboot.c b/system/uapp/userboot/userboot.c new file mode 100644 index 000000000..44e984f13 --- /dev/null +++ b/system/uapp/userboot/userboot.c @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include + +#include +#include + +static size_t devmgr_off = 0; +static size_t devmgr_len = 0; +static size_t end_off = 0; + +static void callback(const char* fn, size_t off, size_t len) { + //cprintf("bootfs: %s @%zd (%zd bytes)\n", fn, off, len); + if (!strcmp(fn, "bin/devmgr")) { + devmgr_off = off; + devmgr_len = len; + } + off += len; + if (off > end_off) { + end_off = off; + } +} + +static const char* args[1] = { + "bin/devmgr", +}; + +static void* arg; + +void* __libc_intercept_arg(void* _arg) { + arg = _arg; + return NULL; +} + +int main(int argc, char** argv) { + mx_handle_t bootfs_vmo = (mx_handle_t)(uintptr_t)arg; + uint64_t bootfs_size; + uintptr_t bootfs_val; + + mx_status_t status = _magenta_vm_object_get_size(bootfs_vmo, &bootfs_size); + if (status < 0) { + cprintf("userboot: failed to get bootfs size (%d)\n", status); + return -1; + } + status = _magenta_process_vm_map( + 0, bootfs_vmo, 0, bootfs_size, &bootfs_val, MX_VM_FLAG_PERM_READ); + if (status < 0) { + cprintf("userboot: failed to map bootfs (%d)\n", status); + return -1; + } + void* bootfs = (void*)bootfs_val; + + cprintf("userboot: starting...\n"); + bootfs_parse(bootfs, 32768, callback); + if (devmgr_off == 0) { + cprintf("userboot: error: bin/devmgr not found\n"); + return -1; + } + + uint8_t* devmgr = ((uint8_t*)bootfs) + devmgr_off; + mx_handle_t proc; + mx_vaddr_t entry; + mx_handle_t h; + mx_status_t r; + + const char pname[] = "devmgr"; + + if ((proc = _magenta_process_create(pname, sizeof(pname))) < 0) + return proc; + if ((r = mxio_load_elf_mem(proc, &entry, devmgr, devmgr_len))) { + cprintf("userboot: elf load of devmgr failed %d\n", r); + return r; + } + + mx_handle_t handles[1] = {bootfs_vmo}; + uint32_t ids[1] = {MX_HND_INFO(MX_HND_TYPE_USER0,0)}; + + if ((h = mxio_build_procargs(1, (char**)args, 1, handles, ids, 0)) < 0) { + cprintf("userboot: failed to build devmgr args %d\n", h); + return h; + } + _magenta_process_start(proc, h, entry); + + return 0; +} + diff --git a/system/udev/BUILD.gn b/system/udev/BUILD.gn new file mode 100644 index 000000000..d28c83e52 --- /dev/null +++ b/system/udev/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +group("udev") { + deps = [ + "bochs_vbe", + "console", + "i8042_keyboard", + "intel_i915", + "intel_rtc", + "kpci", + "null", + "usb_bt_hci", + "usb_ethernet", + "//third_party/udev/usb_bus", + "//third_party/udev/usb_keyboard", + "//third_party/udev/usb_xhci", + ] +} diff --git a/system/udev/bochs_vbe/BUILD.gn b/system/udev/bochs_vbe/BUILD.gn new file mode 100644 index 000000000..17406cc63 --- /dev/null +++ b/system/udev/bochs_vbe/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("bochs_vbe") { + sources = [ + "bochs_vbe.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/bochs_vbe/bochs_vbe.c b/system/udev/bochs_vbe/bochs_vbe.c new file mode 100644 index 000000000..7d961a423 --- /dev/null +++ b/system/udev/bochs_vbe/bochs_vbe.c @@ -0,0 +1,289 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define QEMU_VGA_VID (0x1234) +#define QEMU_VGA_DID (0x1111) + +#define TRACE 0 + +#if TRACE +#define xprintf(fmt...) printf(fmt) +#else +#define xprintf(fmt...) \ + do { \ + } while (0) +#endif + +typedef struct bochs_vbe_device { + mx_device_t device; + + void* regs; + uint64_t regs_size; + mx_handle_t regs_handle; + + void* framebuffer; + uint64_t framebuffer_size; + mx_handle_t framebuffer_handle; + + mx_display_info_t info; +} bochs_vbe_device_t; + +#define get_bochs_vbe_device(dev) containerof(dev, bochs_vbe_device_t, device) + +#define bochs_vbe_dispi_read(base, reg) pcie_read16(base + (0x500 + (reg << 1))) +#define bochs_vbe_dispi_write(base, reg, val) pcie_write16(base + (0x500 + (reg << 1)), val) + +#define BOCHS_VBE_DISPI_ID 0x0 +#define BOCHS_VBE_DISPI_XRES 0x1 +#define BOCHS_VBE_DISPI_YRES 0x2 +#define BOCHS_VBE_DISPI_BPP 0x3 +#define BOCHS_VBE_DISPI_ENABLE 0x4 +#define BOCHS_VBE_DISPI_BANK 0x5 +#define BOCHS_VBE_DISPI_VIRT_WIDTH 0x6 +#define BOCHS_VBE_DISPI_VIRT_HEIGHT 0x7 +#define BOCHS_VBE_DISPI_X_OFFSET 0x8 +#define BOCHS_VBE_DISPI_Y_OFFSET 0x9 +#define BOCHS_VBE_DISPI_VIDEO_MEMORY_64K 0xa + +static int mx_display_format_to_bpp(uint format) { + uint bpp; + switch (format) { + case MX_DISPLAY_FORMAT_RGB_565: + bpp = 16; + break; + case MX_DISPLAY_FORMAT_RGB_332: + bpp = 8; + break; + case MX_DISPLAY_FORMAT_RGB_2220: + bpp = 6; + break; + case MX_DISPLAY_FORMAT_ARGB_8888: + bpp = 32; + break; + case MX_DISPLAY_FORMAT_RGB_x888: + bpp = 24; + break; + case MX_DISPLAY_FORMAT_MONO_1: + bpp = 1; + break; + case MX_DISPLAY_FORMAT_MONO_8: + bpp = 8; + break; + default: + // unsupported + bpp = -1; + break; + } + return bpp; +} + +static void set_hw_mode(bochs_vbe_device_t* dev) { + xprintf("id: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_ID)); + + int bpp = mx_display_format_to_bpp(dev->info.format); + assert(bpp >= 0); + + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_ENABLE, 0); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_BPP, bpp); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_XRES, dev->info.width); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_YRES, dev->info.height); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_BANK, 0); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_VIRT_WIDTH, dev->info.stride); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_VIRT_HEIGHT, dev->framebuffer_size / dev->info.stride); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_X_OFFSET, 0); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_Y_OFFSET, 0); + bochs_vbe_dispi_write(dev->regs, BOCHS_VBE_DISPI_ENABLE, 0x41); + + _magenta_set_framebuffer(dev->framebuffer, dev->framebuffer_size, dev->info.format, dev->info.width, dev->info.height, dev->info.stride); + +#if TRACE + xprintf("bochs_vbe_set_hw_mode:\n"); + xprintf(" ID: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_ID)); + xprintf(" XRES: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_XRES)); + xprintf(" YRES: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_YRES)); + xprintf(" BPP: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_BPP)); + xprintf(" ENABLE: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_ENABLE)); + xprintf(" BANK: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_BANK)); + xprintf( "VWIDTH: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_VIRT_WIDTH)); + xprintf("VHEIGHT: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_VIRT_HEIGHT)); + xprintf(" XOFF: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_X_OFFSET)); + xprintf(" YOFF: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_Y_OFFSET)); + xprintf(" 64K: 0x%x\n", bochs_vbe_dispi_read(dev->regs, BOCHS_VBE_DISPI_VIDEO_MEMORY_64K)); +#endif +} + +// implement display protocol + +static mx_status_t bochs_vbe_set_mode(mx_device_t* dev, mx_display_info_t* info) { + assert(info); + bochs_vbe_device_t* vdev = get_bochs_vbe_device(dev); + memcpy(&vdev->info, info, sizeof(mx_display_info_t)); + set_hw_mode(vdev); + return NO_ERROR; +} + +static mx_status_t bochs_vbe_get_mode(mx_device_t* dev, mx_display_info_t* info) { + assert(info); + bochs_vbe_device_t* vdev = get_bochs_vbe_device(dev); + memcpy(info, &vdev->info, sizeof(mx_display_info_t)); + return NO_ERROR; +} + +static mx_status_t bochs_vbe_get_framebuffer(mx_device_t* dev, void** framebuffer) { + assert(framebuffer); + bochs_vbe_device_t* vdev = get_bochs_vbe_device(dev); + (*framebuffer) = vdev->framebuffer; + return NO_ERROR; +} + +static mx_display_protocol_t bochs_vbe_display_proto = { + .set_mode = bochs_vbe_set_mode, + .get_mode = bochs_vbe_get_mode, + .get_framebuffer = bochs_vbe_get_framebuffer, +}; + + +// implement device protocol + +static mx_status_t bochs_vbe_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t bochs_vbe_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t bochs_vbe_release(mx_device_t* dev) { + bochs_vbe_device_t* vdev = get_bochs_vbe_device(dev); + + if (vdev->regs) { + _magenta_handle_close(vdev->regs_handle); + vdev->regs_handle = -1; + } + + if (vdev->framebuffer) { + _magenta_handle_close(vdev->framebuffer_handle); + vdev->framebuffer_handle = -1; + } + + return NO_ERROR; +} + +static mx_protocol_device_t bochs_vbe_device_proto = { + .get_protocol = device_base_get_protocol, + .open = bochs_vbe_open, + .close = bochs_vbe_close, + .release = bochs_vbe_release, +}; + +// implement driver object: + +static mx_status_t bochs_vbe_probe(mx_driver_t* drv, mx_device_t* dev) { + pci_protocol_t* pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) return ERR_NOT_SUPPORTED; + + const pci_config_t* pci_config; + mx_handle_t cfg_handle = pci->get_config(dev, &pci_config); + if (cfg_handle < 0) + return cfg_handle; + + mx_status_t status; + status = (pci_config->vendor_id == QEMU_VGA_VID) && (pci_config->device_id == QEMU_VGA_DID) + ? NO_ERROR + : ERR_NOT_SUPPORTED; + + _magenta_handle_close(cfg_handle); + + return status; +} + +static mx_status_t bochs_vbe_bind(mx_driver_t* drv, mx_device_t* dev) { + pci_protocol_t* pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) return ERR_NOT_SUPPORTED; + + mx_status_t status = pci->claim_device(dev); + if (status < 0) return status; + + // map resources and initialize the device + bochs_vbe_device_t* device = calloc(1, sizeof(bochs_vbe_device_t)); + if (!device) return ERR_NO_MEMORY; + + // map register window + device->regs_handle = pci->map_mmio(dev, 2, MX_CACHE_POLICY_UNCACHED_DEVICE, + &device->regs, &device->regs_size); + if (device->regs_handle < 0) { + status = device->regs_handle; + goto fail; + } + + // map framebuffer window + device->framebuffer_handle = pci->map_mmio(dev, 0, MX_CACHE_POLICY_WRITE_COMBINING, + &device->framebuffer, + &device->framebuffer_size); + if (device->framebuffer_handle < 0) { + status = device->framebuffer_handle; + goto fail; + } + + // create and add the display (char) device + status = device_init(&device->device, drv, "bochs_vbe", &bochs_vbe_device_proto); + if (status) goto fail; + + device->device.protocol_id = MX_PROTOCOL_DISPLAY; + device->device.protocol_ops = &bochs_vbe_display_proto; + + device->info.format = MX_DISPLAY_FORMAT_RGB_565; + device->info.width = 1024; + device->info.height = 768; + device->info.stride = 1024; + set_hw_mode(device); + + device_add(&device->device, dev); + + xprintf("initialized bochs_vbe display driver, reg=0x%x regsize=0x%x fb=0x%x fbsize=0x%x\n", + device->regs, device->regs_size, device->framebuffer, device->framebuffer_size); + + return NO_ERROR; +fail: + free(device); + return status; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_PCI, +}; + +mx_driver_t _driver_bochs_vbe BUILTIN_DRIVER = { + .name = "bochs_vbe", + .ops = { + .probe = bochs_vbe_probe, + .bind = bochs_vbe_bind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/udev/bochs_vbe/driver.mk b/system/udev/bochs_vbe/driver.mk new file mode 100644 index 000000000..bb61a34e8 --- /dev/null +++ b/system/udev/bochs_vbe/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/bochs_vbe.c diff --git a/system/udev/console/BUILD.gn b/system/udev/console/BUILD.gn new file mode 100644 index 000000000..dce4aa934 --- /dev/null +++ b/system/udev/console/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("console") { + sources = [ + "console.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/console/console.c b/system/udev/console/console.c new file mode 100644 index 000000000..0c96530bf --- /dev/null +++ b/system/udev/console/console.c @@ -0,0 +1,138 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#define FIFOSIZE 256 +#define FIFOMASK (FIFOSIZE - 1) + +static struct { + uint8_t data[FIFOSIZE]; + uint32_t head; + uint32_t tail; + mxr_mutex_t lock; +} fifo = { + .lock = MXR_MUTEX_INIT, +}; + +static mx_status_t fifo_read(uint8_t* out) { + if (fifo.head == fifo.tail) { + return -1; + } + *out = fifo.data[fifo.tail]; + fifo.tail = (fifo.tail + 1) & FIFOMASK; + return NO_ERROR; +} + +static void fifo_write(uint8_t x) { + uint32_t next = (fifo.head + 1) & FIFOMASK; + if (next != fifo.tail) { + fifo.data[fifo.head] = x; + fifo.head = next; + } +} + +static int debug_reader(void* arg) { + mx_device_t* dev = arg; + uint8_t ch; + printf("debug_reader()\n"); + for (;;) { + if (_magenta_debug_read((void*)&ch, 1) == 1) { + mxr_mutex_lock(&fifo.lock); + if (fifo.head == fifo.tail) { + device_state_set(dev, DEV_STATE_READABLE); + } + fifo_write(ch); + mxr_mutex_unlock(&fifo.lock); + } + } + return 0; +} + +static ssize_t console_read(mx_device_t* dev, void* buf, size_t count) { + uint8_t* data = buf; + mxr_mutex_lock(&fifo.lock); + while (count-- > 0) { + if (fifo_read(data)) break; + data++; + } + if (fifo.head == fifo.tail) { + device_state_clr(dev, DEV_STATE_READABLE); + } + mxr_mutex_unlock(&fifo.lock); + return data - (uint8_t*)buf; +} + +static ssize_t console_write(mx_device_t* dev, const void* buf, size_t count) { + return _magenta_debug_write(buf, count); +} + +static mx_protocol_char_t console_char_proto = { + .read = console_read, + .write = console_write, +}; + +static mx_status_t console_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t console_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t console_release(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_protocol_device_t console_device_proto = { + .get_protocol = device_base_get_protocol, + .open = console_open, + .close = console_close, + .release = console_release, +}; + +mx_status_t console_init(mx_driver_t* driver) { + mx_device_t* dev; + printf("console_init()\n"); + if (device_create(&dev, driver, "console", &console_device_proto) == NO_ERROR) { + dev->protocol_id = MX_PROTOCOL_CHAR; + dev->protocol_ops = &console_char_proto; + if (device_add(dev, NULL) < 0) { + free(dev); + } else { + mxr_thread_t* t; + mxr_thread_create(debug_reader, dev, "debug-reader", &t); + } + } + return NO_ERROR; +} + +mx_driver_t _driver_console BUILTIN_DRIVER = { + .name = "console", + .ops = { + .init = console_init, + }, +}; diff --git a/system/udev/console/driver.mk b/system/udev/console/driver.mk new file mode 100644 index 000000000..fd3065d66 --- /dev/null +++ b/system/udev/console/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/console.c diff --git a/system/udev/i8042_keyboard/BUILD.gn b/system/udev/i8042_keyboard/BUILD.gn new file mode 100644 index 000000000..0d0225044 --- /dev/null +++ b/system/udev/i8042_keyboard/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("i8042_keyboard") { + sources = [ + "i8042_keyboard.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/i8042_keyboard/driver.mk b/system/udev/i8042_keyboard/driver.mk new file mode 100644 index 000000000..bf2641511 --- /dev/null +++ b/system/udev/i8042_keyboard/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/i8042_keyboard.c diff --git a/system/udev/i8042_keyboard/i8042_keyboard.c b/system/udev/i8042_keyboard/i8042_keyboard.c new file mode 100644 index 000000000..adc8c91cf --- /dev/null +++ b/system/udev/i8042_keyboard/i8042_keyboard.c @@ -0,0 +1,464 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#define MXDEBUG 0 + +typedef struct i8042_keyboard_device { + mx_device_t device; + + mx_handle_t irq; + mxr_thread_t* irq_thread; + + bool key_lshift; + bool key_rshift; + int last_code; + + mx_key_fifo_t fifo; +} i8042_device_t; + +#define get_kbd_device(dev) containerof(dev, i8042_device_t, device) + +#define I8042_COMMAND_REG 0x64 +#define I8042_STATUS_REG 0x64 +#define I8042_DATA_REG 0x60 + +#define ISA_IRQ_KEYBOARD 0x1 + +static inline int i8042_read_data(void) { + return inp(I8042_DATA_REG); +} + +static inline int i8042_read_status(void) { + return inp(I8042_STATUS_REG); +} + +static inline void i8042_write_data(int val) { + outp(I8042_DATA_REG, val); +} + +static inline void i8042_write_command(int val) { + outp(I8042_COMMAND_REG, val); +} + +/* + * timeout in milliseconds + */ +#define I8042_CTL_TIMEOUT 500 + +/* + * status register bits + */ +#define I8042_STR_PARITY 0x80 +#define I8042_STR_TIMEOUT 0x40 +#define I8042_STR_AUXDATA 0x20 +#define I8042_STR_KEYLOCK 0x10 +#define I8042_STR_CMDDAT 0x08 +#define I8042_STR_MUXERR 0x04 +#define I8042_STR_IBF 0x02 +#define I8042_STR_OBF 0x01 + +/* + * control register bits + */ +#define I8042_CTR_KBDINT 0x01 +#define I8042_CTR_AUXINT 0x02 +#define I8042_CTR_IGNKEYLK 0x08 +#define I8042_CTR_KBDDIS 0x10 +#define I8042_CTR_AUXDIS 0x20 +#define I8042_CTR_XLATE 0x40 + +/* + * commands + */ +#define I8042_CMD_CTL_RCTR 0x0120 +#define I8042_CMD_CTL_WCTR 0x1060 +#define I8042_CMD_CTL_TEST 0x01aa + +#define I8042_CMD_KBD_DIS 0x00ad +#define I8042_CMD_KBD_EN 0x00ae +#define I8042_CMD_PULSE_RESET 0x00fe +#define I8042_CMD_KBD_TEST 0x01ab +#define I8042_CMD_KBD_MODE 0x01f0 + +/* + * used for flushing buffers. the i8042 internal buffer shoudn't exceed this. + */ +#define I8042_BUFFER_LENGTH 32 + +/* scancode translation tables */ +const uint8_t pc_keymap_set1_lower[128] = { + /* 0x00 */ 0, MX_KEY_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', MX_KEY_BACKSPACE, MX_KEY_TAB, + /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', MX_KEY_RETURN, MX_KEY_LCTRL, 'a', 's', + /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', MX_KEY_LSHIFT, '\\', 'z', 'x', 'c', 'v', + /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', MX_KEY_RSHIFT, '*', MX_KEY_LALT, ' ', MX_KEY_CAPSLOCK, MX_KEY_F1, MX_KEY_F2, + MX_KEY_F3, MX_KEY_F4, MX_KEY_F5, + /* 0x40 */ MX_KEY_F6, MX_KEY_F7, MX_KEY_F8, MX_KEY_F9, MX_KEY_F10, MX_KEY_PAD_NUMLOCK, MX_KEY_SCRLOCK, MX_KEY_PAD_7, MX_KEY_PAD_8, + MX_KEY_PAD_9, MX_KEY_PAD_MINUS, MX_KEY_PAD_4, MX_KEY_PAD_5, MX_KEY_PAD_6, MX_KEY_PAD_PLUS, MX_KEY_PAD_1, + /* 0x50 */ MX_KEY_PAD_2, MX_KEY_PAD_3, MX_KEY_PAD_0, MX_KEY_PAD_PERIOD, 0, 0, 0, MX_KEY_F11, MX_KEY_F12, 0, 0, 0, 0, 0, 0, 0, +}; + +const uint8_t pc_keymap_set1_upper[128] = { + /* 0x00 */ 0, MX_KEY_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', MX_KEY_BACKSPACE, MX_KEY_TAB, + /* 0x10 */ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', MX_KEY_RETURN, MX_KEY_LCTRL, 'A', 'S', + /* 0x20 */ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', MX_KEY_LSHIFT, '|', 'Z', 'X', 'C', 'V', + /* 0x30 */ 'B', 'N', 'M', '<', '>', '?', MX_KEY_RSHIFT, '*', MX_KEY_LALT, ' ', MX_KEY_CAPSLOCK, MX_KEY_F1, MX_KEY_F2, + MX_KEY_F3, MX_KEY_F4, MX_KEY_F5, + /* 0x40 */ MX_KEY_F6, MX_KEY_F7, MX_KEY_F8, MX_KEY_F9, MX_KEY_F10, MX_KEY_PAD_NUMLOCK, MX_KEY_SCRLOCK, MX_KEY_PAD_7, MX_KEY_PAD_8, + MX_KEY_PAD_9, MX_KEY_PAD_MINUS, MX_KEY_PAD_4, MX_KEY_PAD_5, MX_KEY_PAD_6, MX_KEY_PAD_PLUS, MX_KEY_PAD_1, + /* 0x50 */ MX_KEY_PAD_2, MX_KEY_PAD_3, MX_KEY_PAD_0, MX_KEY_PAD_PERIOD, 0, 0, 0, MX_KEY_F11, MX_KEY_F12, 0, 0, 0, 0, 0, 0, 0, +}; + +const uint8_t pc_keymap_set1_e0[128] = { + /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MX_KEY_PAD_ENTER, MX_KEY_RCTRL, 0, 0, + /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 */ 0, 0, 0, 0, 0, MX_KEY_PAD_DIVIDE, 0, MX_KEY_PRTSCRN, MX_KEY_RALT, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, MX_KEY_HOME, MX_KEY_ARROW_UP, MX_KEY_PGUP, 0, MX_KEY_ARROW_LEFT, 0, MX_KEY_ARROW_RIGHT, 0, MX_KEY_END, + /* 0x50 */ MX_KEY_ARROW_DOWN, MX_KEY_PGDN, MX_KEY_INS, 0, 0, 0, 0, 0, 0, 0, 0, MX_KEY_LWIN, MX_KEY_RWIN, MX_KEY_MENU, 0, 0 +}; + +static int i8042_wait_read(void) { + int i = 0; + while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { + usleep(10); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +static int i8042_wait_write(void) { + int i = 0; + while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { + usleep(10); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +static int i8042_flush(void) { + unsigned char data __UNUSED; + int i = 0; + + while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_LENGTH)) { + usleep(10); + data = i8042_read_data(); + } + + return i; +} + +static int i8042_command(uint8_t* param, int command) { + int retval = 0, i = 0; + + retval = i8042_wait_write(); + if (!retval) { + i8042_write_command(command & 0xff); + } + + if (!retval) { + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) { + break; + } + + i8042_write_data(param[i]); + } + } + + if (!retval) { + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) { + break; + } + + if (i8042_read_status() & I8042_STR_AUXDATA) { + param[i] = ~i8042_read_data(); + } else { + param[i] = i8042_read_data(); + } + } + } + + return retval; +} + +static int i8042_selftest(void) { + uint8_t param; + int i = 0; + do { + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { + return -1; + } + if (param == 0x55) return 0; + usleep(50 * 1000); + } while (i++ < 5); + return 0; +} + +static int keyboard_command(uint8_t *param, int command) { + int retval = 0, i = 0; + + retval = i8042_wait_write(); + if (!retval) { + i8042_write_data(command & 0xff); + } + + if (!retval) { + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) { + break; + } + + i8042_write_data(param[i]); + } + } + + if (!retval) { + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) { + break; + } + + if (i8042_read_status() & I8042_STR_AUXDATA) { + param[i] = ~i8042_read_data(); + } else { + param[i] = i8042_read_data(); + } + } + } + + return retval; +} + +static void i8042_process_scode(i8042_device_t* dev, uint8_t scode, unsigned int flags) { + // is this a multi code sequence? + bool multi = (dev->last_code == 0xe0); + + // update the last received code + dev->last_code = scode; + + // save the key up event bit + bool key_up = !!(scode & 0x80); + scode &= 0x7f; + + // translate the key based on our translation table + uint8_t key_code; + if (multi) { + key_code = pc_keymap_set1_e0[scode]; + } else if (dev->key_lshift || dev->key_rshift) { + key_code = pc_keymap_set1_upper[scode]; + } else { + key_code = pc_keymap_set1_lower[scode]; + } + + if (key_code == MX_KEY_LSHIFT) { + dev->key_lshift = !key_up; + } else if (key_code == MX_KEY_RSHIFT) { + dev->key_rshift = !key_up; + } + + //cprintf("i8042: scancode=0x%x, keyup=%u, multi=%u: keycode=0x%x\n", scode, !!key_up, multi, key_code); + + mx_key_event_t ev = { .keycode = key_code, .pressed = !key_up }; + mxr_mutex_lock(&dev->fifo.lock); + if (dev->fifo.head == dev->fifo.tail) { + device_state_set(&dev->device, DEV_STATE_READABLE); + } + mx_key_fifo_write(&dev->fifo, &ev); + mxr_mutex_unlock(&dev->fifo.lock); +} + +static int i8042_irq_thread(void* arg) { + i8042_device_t* device = (i8042_device_t*)arg; + + // enable I/O port access + // TODO + mx_status_t status; + status = _magenta_mmap_device_io(I8042_COMMAND_REG, 1); + if (status) return 0; + status = _magenta_mmap_device_io(I8042_DATA_REG, 1); + if (status) return 0; + + for (;;) { + status = _magenta_interrupt_event_wait(device->irq); + if (status == NO_ERROR) { + // keep handling status on the keyboard controller until no bits are set we care about + bool retry; + do { + retry = false; + + uint8_t str = i8042_read_status(); + + // check for incoming data from the controller + if (str & I8042_STR_OBF) { + uint8_t data = i8042_read_data(); + i8042_process_scode(device, data, + ((str & I8042_STR_PARITY) ? I8042_STR_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? I8042_STR_TIMEOUT : 0)); + retry = true; + } + // TODO check other status bits here + } while (retry); + _magenta_interrupt_event_complete(device->irq); + } + } + return 0; +} + + +// implement char protocol: + +static ssize_t i8042_read(mx_device_t* dev, void* buf, size_t count) { + size_t size = sizeof(mx_key_event_t); + if (count < size || (count % size != 0)) return ERR_INVALID_ARGS; + + i8042_device_t* device = get_kbd_device(dev); + mx_key_event_t* data = (mx_key_event_t*)buf; + mxr_mutex_lock(&device->fifo.lock); + while (count > 0) { + if (mx_key_fifo_read(&device->fifo, data)) break; + data++; + count -= size; + } + if (device->fifo.head == device->fifo.tail) { + device_state_clr(dev, DEV_STATE_READABLE); + } + mxr_mutex_unlock(&device->fifo.lock); + return (data - (mx_key_event_t*)buf) * size; +} + +static ssize_t i8042_write(mx_device_t* dev, const void* buf, size_t count) { + return ERR_NOT_SUPPORTED; +} + +static mx_protocol_char_t i8042_char_proto = { + .read = i8042_read, + .write = i8042_write, +}; + +// implement device protocol: + +static mx_status_t i8042_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t i8042_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t i8042_release(mx_device_t* dev) { + i8042_device_t* device = get_kbd_device(dev); + free(device); + return NO_ERROR; +} + +static mx_protocol_device_t i8042_device_proto = { + .get_protocol = device_base_get_protocol, + .open = i8042_open, + .close = i8042_close, + .release = i8042_release, +}; + +// implement driver object: + +static mx_status_t i8042_keyboard_init(mx_driver_t* driver) { + // create device + i8042_device_t* device = calloc(1, sizeof(i8042_device_t)); + if (!device) return ERR_NO_MEMORY; + + device->fifo.lock = MXR_MUTEX_INIT; + + mx_status_t status = device_init(&device->device, driver, "i8042_keyboard", &i8042_device_proto); + if (status) { + free(device); + return status; + } + + // add to root device + device->device.protocol_id = MX_PROTOCOL_CHAR; + device->device.protocol_ops = &i8042_char_proto; + if (device_add(&device->device, NULL)) { + free(device); + return NO_ERROR; + } + + // enable I/O port access + status = _magenta_mmap_device_io(I8042_COMMAND_REG, 1); + if (status) goto fail; + status = _magenta_mmap_device_io(I8042_DATA_REG, 1); + if (status) goto fail; + + // initialize keyboard hardware + i8042_flush(); + + uint8_t ctr; + if (i8042_command(&ctr, I8042_CMD_CTL_RCTR)) goto fail; + + // turn on translation + ctr |= I8042_CTR_XLATE; + + // enable keyboard and keyboard irq + ctr &= ~I8042_CTR_KBDDIS; + ctr |= I8042_CTR_KBDINT; + + if (i8042_command(&ctr, I8042_CMD_CTL_WCTR)) goto fail; + + // enable PS/2 port + i8042_command(NULL, I8042_CMD_KBD_EN); + + // send a enable scan command to the keyboard + keyboard_command(&ctr, 0x1f4); + + // get interrupt wait handle + device->irq = _magenta_interrupt_event_create(ISA_IRQ_KEYBOARD, MX_FLAG_REMAP_IRQ); + if (device->irq < 0) goto fail; + + // create irq thread + const char* name = "i8042-irq"; + status = mxr_thread_create(i8042_irq_thread, device, name, &device->irq_thread); + if (status != NO_ERROR) goto fail; + + xprintf("initialized i8042_keyboard driver\n"); + + return NO_ERROR; +fail: + device_remove(&device->device); + return status; +} + +mx_driver_t _driver_i8042_keyboard BUILTIN_DRIVER = { + .name = "i8042_keyboard", + .ops = { + .init = i8042_keyboard_init, + }, +}; diff --git a/system/udev/intel_broadwell_serialio/dma/dma.c b/system/udev/intel_broadwell_serialio/dma/dma.c new file mode 100644 index 000000000..7acba87f7 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/dma/dma.c @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#include + +mx_status_t intel_broadwell_serialio_bind_dma(mx_driver_t *drv, + mx_device_t *dev) +{ + // Not implemented yet. + return ERR_NOT_IMPLEMENTED; +} + diff --git a/system/udev/intel_broadwell_serialio/driver.mk b/system/udev/intel_broadwell_serialio/driver.mk new file mode 100644 index 000000000..450927f2b --- /dev/null +++ b/system/udev/intel_broadwell_serialio/driver.mk @@ -0,0 +1,42 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +## +## Copyright 2016 The Fuchsia Authors +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/serialio.c \ + $(LOCAL_DIR)/dma/dma.c \ + $(LOCAL_DIR)/i2c/controller.c \ + $(LOCAL_DIR)/i2c/slave.c \ + $(LOCAL_DIR)/sdio/sdio.c \ + $(LOCAL_DIR)/spi/spi.c \ + $(LOCAL_DIR)/uart/uart.c + +MODULE_COMPILEFLAGS += -I $(LOCAL_DIR)/include/ diff --git a/system/udev/intel_broadwell_serialio/i2c/controller.c b/system/udev/intel_broadwell_serialio/i2c/controller.c new file mode 100644 index 000000000..4065bf2e9 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/i2c/controller.c @@ -0,0 +1,369 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "controller.h" +#include "slave.h" + +// Implement the functionality of the i2c bus device. + +static uint32_t chip_addr_mask(int width) +{ + return ((1 << width) - 1); +} + +static mx_status_t intel_broadwell_serialio_i2c_find_slave( + intel_broadwell_serialio_i2c_slave_device_t **slave, + intel_broadwell_serialio_i2c_device_t *device, uint16_t address) +{ + assert(slave); + + list_for_every_entry(&device->slave_list, *slave, + intel_broadwell_serialio_i2c_slave_device_t, + slave_list_node) { + if ((*slave)->chip_address == address) + return NO_ERROR; + } + + return ERR_NOT_FOUND; +} + +static mx_status_t intel_broadwell_serialio_i2c_add_slave( + mx_device_t *dev, uint8_t width, uint16_t address) +{ + mx_status_t status; + + if ((width != I2C_7BIT_ADDRESS && width != I2C_10BIT_ADDRESS) || + (address & ~chip_addr_mask(width)) != 0) { + return ERR_INVALID_ARGS; + } + + intel_broadwell_serialio_i2c_device_t *device = + get_intel_broadwell_serialio_i2c_device(dev); + + intel_broadwell_serialio_i2c_slave_device_t *slave; + + mxr_mutex_lock(&device->mutex); + + // Make sure a slave with the given address doesn't already exist. + status = intel_broadwell_serialio_i2c_find_slave(&slave, device, address); + if (status == NO_ERROR) { + status = ERR_ALREADY_EXISTS; + goto fail2; + } else if (status != ERR_NOT_FOUND) { + goto fail2; + } + + slave = malloc(sizeof(*slave)); + if (!slave) { + status = ERR_NO_MEMORY; + goto fail1; + } + + status = intel_broadwell_serialio_i2c_slave_device_init( + dev, slave, width, address); + if (status < 0) + goto fail1; + + list_add_head(&device->slave_list, &slave->slave_list_node); + + status = device_add(&slave->device, dev); + if (status < 0) + goto fail1; + + mxr_mutex_unlock(&device->mutex); + return NO_ERROR; +fail1: + free(slave); +fail2: + mxr_mutex_unlock(&device->mutex); + return status; +} + +static mx_status_t intel_broadwell_serialio_i2c_remove_slave( + mx_device_t *dev, uint8_t width, uint16_t address) +{ + mx_status_t status; + + if ((width != I2C_7BIT_ADDRESS && width != I2C_10BIT_ADDRESS) || + (address & ~chip_addr_mask(width)) != 0) { + return ERR_INVALID_ARGS; + } + + intel_broadwell_serialio_i2c_device_t *device = + get_intel_broadwell_serialio_i2c_device(dev); + + intel_broadwell_serialio_i2c_slave_device_t *slave; + + mxr_mutex_lock(&device->mutex); + + // Find the slave we're trying to remove. + status = intel_broadwell_serialio_i2c_find_slave(&slave, device, address); + if (status < 0) + goto remove_slave_finish; + if (slave->chip_address_width != width) { + xprintf("Chip address width mismatch.\n"); + status = ERR_NOT_FOUND; + goto remove_slave_finish; + } + + status = device_remove(&slave->device); + if (status < 0) + goto remove_slave_finish; + + list_delete(&slave->slave_list_node); + free(slave); + +remove_slave_finish: + mxr_mutex_unlock(&device->mutex); + return NO_ERROR; +} + +static mx_status_t intel_broadwell_serialio_i2c_set_bus_frequency( + mx_device_t *dev, uint32_t frequency) +{ + if (frequency > I2C_MAX_FAST_SPEED_HZ) + return ERR_INVALID_ARGS; + + intel_broadwell_serialio_i2c_device_t *device = + get_intel_broadwell_serialio_i2c_device(dev); + + // Assume the base clock_frequency is 100 MHz, as alluded to in the docs. + uint32_t clock_frequency = 100 * 1000 * 1000; + + // Compute high and low counts in multiples of the clock frequency. Make + // them approximately equal. + + uint32_t period = clock_frequency / frequency; + uint32_t high_count = period / 2; + uint32_t low_count = period - high_count; + + // Make sure the counts are within bounds. + if (high_count >= (1 << 16) || high_count < 6 || + low_count >= (1 << 16) || low_count < 8) { + return ERR_OUT_OF_RANGE; + } + + mxr_mutex_lock(&device->mutex); + + // Disable the controller before changing the frequency. + uint32_t orig_en = *REG32(&device->regs->i2c_en); + RMWREG32(&device->regs->i2c_en, I2C_EN_ENABLE, 1, 0); + + // Write the computed high and low counts into the fast speed registers. + RMWREG32(&device->regs->fs_scl_hcnt, 0, 16, high_count); + RMWREG32(&device->regs->fs_scl_lcnt, 0, 16, low_count); + + // Reenable the controller, if it was originally enabled. + *REG32(&device->regs->i2c_en) = orig_en; + + mxr_mutex_unlock(&device->mutex); + + return NO_ERROR; +} + +// Implement the device protocol for the bus device. + +static mx_status_t intel_broadwell_serialio_i2c_open(mx_device_t *dev, + uint32_t flags) +{ + return NO_ERROR; +} + +static mx_status_t intel_broadwell_serialio_i2c_close(mx_device_t *dev) +{ + return NO_ERROR; +} + +static mx_status_t intel_broadwell_serialio_i2c_release(mx_device_t *dev) +{ + return NO_ERROR; +} + +static mx_protocol_device_t intel_broadwell_serialio_i2c_device_proto = { + .get_protocol = &device_base_get_protocol, + .open = &intel_broadwell_serialio_i2c_open, + .close = &intel_broadwell_serialio_i2c_close, + .release = &intel_broadwell_serialio_i2c_release, +}; + +// Implement the char protocol for the bus device. + +static ssize_t intel_broadwell_serialio_i2c_read( + mx_device_t *dev, void *buf, size_t count) +{ + return ERR_NOT_SUPPORTED; +} + +static ssize_t intel_broadwell_serialio_i2c_write( + mx_device_t *dev, const void *buf, size_t count) +{ + return ERR_NOT_SUPPORTED; +} + +static ssize_t intel_broadwell_serialio_i2c_ioctl( + mx_device_t *dev, uint32_t op, const void *in_buf, size_t in_len, + void *out_buf, size_t out_len) +{ + int ret; + switch (op) { + case I2C_BUS_ADD_SLAVE: + { + const i2c_ioctl_add_slave_args_t *args = in_buf; + if (in_len < sizeof(*args)) + return ERR_INVALID_ARGS; + + ret = intel_broadwell_serialio_i2c_add_slave( + dev, args->chip_address_width, args->chip_address); + break; + } + case I2C_BUS_REMOVE_SLAVE: + { + const i2c_ioctl_remove_slave_args_t *args = in_buf; + if (in_len < sizeof(*args)) + return ERR_INVALID_ARGS; + + ret = intel_broadwell_serialio_i2c_remove_slave( + dev, args->chip_address_width, args->chip_address); + break; + } + case I2C_BUS_SET_FREQUENCY: + { + const i2c_ioctl_set_bus_frequency_args_t *args = in_buf; + if (in_len < sizeof(*args)) + return ERR_INVALID_ARGS; + + ret = intel_broadwell_serialio_i2c_set_bus_frequency( + dev, args->frequency); + break; + } + default: + return ERR_INVALID_ARGS; + } + + if (ret == NO_ERROR) + return in_len; + else + return ret; +} + +static mx_protocol_char_t intel_broadwell_serialio_i2c_char_proto = { + .read = &intel_broadwell_serialio_i2c_read, + .write = &intel_broadwell_serialio_i2c_write, + .ioctl = &intel_broadwell_serialio_i2c_ioctl, +}; + +static mx_status_t intel_broadwell_serialio_i2c_configure( + intel_broadwell_serialio_i2c_device_t *device) +{ + mx_status_t status = NO_ERROR; + + // Run the bus at 100KHz by default. + status = intel_broadwell_serialio_i2c_set_bus_frequency( + &device->device, 100000); + if (status < 0) + return status; + + mxr_mutex_lock(&device->mutex); + + // Disable the controller. + RMWREG32(&device->regs->i2c_en, I2C_EN_ENABLE, 1, 0); + + *REG32(&device->regs->ctl) = + (0x1 << CTL_SLAVE_DISABLE) | + (0x1 << CTL_RESTART_ENABLE) | + (CTL_SPEED_FAST << CTL_SPEED) | + (CTL_MASTER_MODE_ENABLED << CTL_MASTER_MODE); + + //XXX Do we need this? + *REG32(&device->regs->intr_mask) = INTR_STOP_DETECTION; + + *REG32(&device->regs->rx_tl) = 0; + *REG32(&device->regs->tx_tl) = 0; + + mxr_mutex_unlock(&device->mutex); + return status; +} + +mx_status_t intel_broadwell_serialio_bind_i2c(mx_driver_t *drv, + mx_device_t *dev) +{ + pci_protocol_t *pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) + return ERR_NOT_SUPPORTED; + + mx_status_t status = pci->claim_device(dev); + if (status < 0) + return status; + + intel_broadwell_serialio_i2c_device_t *device = malloc(sizeof(*device)); + if (!device) + return ERR_NO_MEMORY; + + list_initialize(&device->slave_list); + memset(&device->mutex, 0, sizeof(device->mutex)); + + device->regs_handle = pci->map_mmio( + dev, 0, MX_CACHE_POLICY_UNCACHED_DEVICE, + (void **)&device->regs, &device->regs_size); + if (device->regs_handle < 0) { + status = device->regs_handle; + goto fail; + } + + status = device_init(&device->device, drv, "intel_broadwell_serialio_i2c", + &intel_broadwell_serialio_i2c_device_proto); + if (status < 0) + goto fail; + + // Configure the I2C controller. + status = intel_broadwell_serialio_i2c_configure(device); + if (status < 0) + goto fail; + + device->device.protocol_id = MX_PROTOCOL_CHAR; + device->device.protocol_ops = &intel_broadwell_serialio_i2c_char_proto; + + status = device_add(&device->device, dev); + if (status < 0) + goto fail; + + xprintf("initialized intel broadwell serialio i2c driver, " + "reg=%#x regsize=%#x\n", device->regs, device->regs_size); + + return NO_ERROR; + +fail: + if (device->regs_handle >= 0) + _magenta_handle_close(device->regs_handle); + free(device); + + return status; +} diff --git a/system/udev/intel_broadwell_serialio/i2c/controller.h b/system/udev/intel_broadwell_serialio/i2c/controller.h new file mode 100644 index 000000000..417474b53 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/i2c/controller.h @@ -0,0 +1,156 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +typedef struct __attribute__((packed)) intel_broadwell_serialio_i2c_regs +{ + uint32_t ctl; + uint32_t tar_add; + uint32_t _reserved0[2]; + uint32_t data_cmd; + uint32_t ss_scl_hcnt; + uint32_t ss_scl_lcnt; + uint32_t fs_scl_hcnt; + uint32_t fs_scl_lcnt; + uint32_t _reserved1[2]; + uint32_t intr_stat; + uint32_t intr_mask; + uint32_t raw_intr_stat; + uint32_t rx_tl; + uint32_t tx_tl; + uint32_t clr_intr; + uint32_t clr_rx_under; + uint32_t clr_rx_over; + uint32_t clr_tx_over; + uint32_t _reserved2[1]; + uint32_t clr_tx_abort; + uint32_t _reserved3[1]; + uint32_t clr_activity; + uint32_t clr_stop_det; + uint32_t clr_start_det; + uint32_t clr_gen_call; + uint32_t i2c_en; + uint32_t i2c_sta; + uint32_t txflr; + uint32_t rxflr; + uint32_t sda_hold; + uint32_t tx_abrt_source; + uint32_t slv_data_nack; + uint32_t dma_ctrl; + uint32_t dma_tdlr; + uint32_t dma_rdlr; + uint32_t sda_setup; + uint32_t ack_gen_call; + uint32_t enable_status; + uint32_t _reserved4[21]; + uint32_t comp_param1; + uint32_t comp_ver; + uint32_t _reserved5[450]; + uint32_t resets; + uint32_t general; + uint32_t _reserved6[1]; + uint32_t sw_ltr_value; + uint32_t auto_ltr_value; +} intel_broadwell_serialio_i2c_regs; + +enum { + I2C_MAX_FAST_SPEED_HZ = 400000, + I2C_MAX_STANDARD_SPEED_HZ = 100000, +}; + +enum { + I2C_EN_ABORT = 1, + I2C_EN_ENABLE = 0, +}; + +enum { + CTL_SLAVE_DISABLE = 6, + CTL_RESTART_ENABLE = 5, + CTL_ADDRESSING_MODE = 4, + + CTL_ADDRESSING_MODE_7BIT = 0x0, + CTL_ADDRESSING_MODE_10BIT = 0x1, + + CTL_SPEED = 1, + CTL_SPEED_STANDARD = 0x0, + CTL_SPEED_FAST = 0x2, + + CTL_MASTER_MODE = 0, + CTL_MASTER_MODE_ENABLED = 0x1, +}; + +enum { + INTR_GENERAL_CALL = 11, + INTR_START_DETECTION = 10, + INTR_STOP_DETECTION = 9, + INTR_ACTIVITY = 8, + INTR_TX_ABORT = 6, + INTR_TX_EMPTY = 4, + INTR_TX_OVER = 3, + INTR_RX_FULL = 2, + INTR_RX_OVER = 1, + INTR_RX_UNDER = 0, +}; + +enum { + TAR_ADD_WIDTH = 12, + TAR_ADD_WIDTH_7BIT = 0x0, + TAR_ADD_WIDTH_10BIT = 0x1, + + TAR_ADD_SPECIAL = 11, + TAR_ADD_GC_OR_START = 10, + TAR_ADD_IC_TAR = 0, +}; + +enum { + I2C_STA_CA = 5, + I2C_STA_RFCF = 4, + I2C_STA_RFNE = 3, + I2C_STA_TFCE = 2, + I2C_STA_TFNF = 1, + I2C_STA_ACTIVITY = 0, +}; + +enum { + DATA_CMD_RESTART = 10, + DATA_CMD_STOP = 9, + + DATA_CMD_CMD = 8, + DATA_CMD_CMD_WRITE = 0, + DATA_CMD_CMD_READ = 1, + + DATA_CMD_DAT = 0, +}; + +typedef struct intel_broadwell_serialio_i2c_device +{ + mx_device_t device; + + intel_broadwell_serialio_i2c_regs *regs; + uint64_t regs_size; + mx_handle_t regs_handle; + + struct list_node slave_list; + + mxr_mutex_t mutex; +} intel_broadwell_serialio_i2c_device_t; + +#define get_intel_broadwell_serialio_i2c_device(dev) \ + containerof(dev, intel_broadwell_serialio_i2c_device_t, device) diff --git a/system/udev/intel_broadwell_serialio/i2c/slave.c b/system/udev/intel_broadwell_serialio/i2c/slave.c new file mode 100644 index 000000000..a35a055e8 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/i2c/slave.c @@ -0,0 +1,331 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "controller.h" +#include "slave.h" + +// Implement the device protocol for the slave devices. + +static mx_status_t intel_broadwell_serialio_i2c_slave_open(mx_device_t *dev, + uint32_t flags) +{ + return NO_ERROR; +} + +static mx_status_t intel_broadwell_serialio_i2c_slave_close(mx_device_t *dev) +{ + return NO_ERROR; +} + +static mx_status_t intel_broadwell_serialio_i2c_slave_release(mx_device_t *dev) +{ + return NO_ERROR; +} + +static mx_protocol_device_t intel_broadwell_serialio_i2c_slave_device_proto = { + .get_protocol = &device_base_get_protocol, + .open = &intel_broadwell_serialio_i2c_slave_open, + .close = &intel_broadwell_serialio_i2c_slave_close, + .release = &intel_broadwell_serialio_i2c_slave_release, +}; + +// Implement the functionality of the i2c slave devices. + +static mx_status_t intel_broadwell_serialio_i2c_slave_transfer( + mx_device_t *dev, i2c_slave_segment_t *segments, int segment_count) +{ + intel_broadwell_serialio_i2c_slave_device_t *slave = + get_intel_broadwell_serialio_i2c_slave_device(dev); + + if (!dev->parent) { + printf("Orphaned I2C slave.\n"); + return ERR_BAD_STATE; + } + + intel_broadwell_serialio_i2c_device_t *controller = + get_intel_broadwell_serialio_i2c_device(dev->parent); + + uint32_t ctl_addr_mode_bit; + uint32_t tar_add_addr_mode_bit; + if (slave->chip_address_width == I2C_7BIT_ADDRESS) { + ctl_addr_mode_bit = CTL_ADDRESSING_MODE_7BIT; + tar_add_addr_mode_bit = TAR_ADD_WIDTH_7BIT; + } else if (slave->chip_address_width == I2C_10BIT_ADDRESS) { + ctl_addr_mode_bit = CTL_ADDRESSING_MODE_10BIT; + tar_add_addr_mode_bit = TAR_ADD_WIDTH_10BIT; + } else { + printf("Bad address width.\n"); + return ERR_INVALID_ARGS; + } + + mxr_mutex_lock(&controller->mutex); + + // Wait for the bus to become idle. + uint32_t i2c_sta; + do { + i2c_sta = *REG32(&controller->regs->i2c_sta); + } while ((i2c_sta & (0x1 << I2C_STA_CA)) || + !(i2c_sta & (0x1 << I2C_STA_TFCE))); + + // Set the target adress value and width. + RMWREG32(&controller->regs->ctl, CTL_ADDRESSING_MODE, 1, ctl_addr_mode_bit); + *REG32(&controller->regs->tar_add) = + (tar_add_addr_mode_bit << TAR_ADD_WIDTH) | + (slave->chip_address << TAR_ADD_IC_TAR); + + // Enable the controller. + RMWREG32(&controller->regs->i2c_en, I2C_EN_ENABLE, 1, 1); + + int last_read = 0; + if (segment_count) + last_read = segments->read; + + while (segment_count--) { + int len = segments->len; + uint8_t *buf = segments->buf; + + // If this segment is in the same direction as the last, inject a + // restart at its start. + uint32_t restart = 0; + if (last_read == segments->read) + restart = 1; + while (len--) { + // Build the cmd register value. + uint32_t cmd = (restart << DATA_CMD_RESTART); + restart = 0; + if (!segments->read) { + while (!(*REG32(&controller->regs->i2c_sta) & + (0x1 << I2C_STA_TFNF))) + {;} + cmd |= (*buf << DATA_CMD_DAT); + cmd |= (DATA_CMD_CMD_WRITE << DATA_CMD_CMD); + } else { + cmd |= (DATA_CMD_CMD_READ << DATA_CMD_CMD); + } + if (!len) + cmd |= (0x1 << DATA_CMD_STOP); + + // Write the cmd value. + *REG32(&controller->regs->data_cmd) = cmd; + + // If this is a read, extract the data. + if (segments->read) { + while (!(*REG32(&controller->regs->i2c_sta) & + (0x1 << I2C_STA_RFNE))) + {;} + *buf = *REG32(&controller->regs->data_cmd); + } + + buf++; + } + last_read = segments->read; + segments++; + } + + while (*REG32(&controller->regs->raw_intr_stat) & INTR_STOP_DETECTION) { + // Read the data_cmd register to pull data out of the RX FIFO. + *REG32(&controller->regs->clr_stop_det); + } + + // Wait for the bus to become idle. + do { + i2c_sta = *REG32(&controller->regs->i2c_sta); + } while ((i2c_sta & (0x1 << I2C_STA_CA)) || + !(i2c_sta & (0x1 << I2C_STA_TFCE))); + while ((*REG32(&controller->regs->i2c_sta) & (0x1 << I2C_STA_CA)) || + !(*REG32(&controller->regs->i2c_sta) & (0x1 << I2C_STA_TFCE))) + {;} + + while (*REG32(&controller->regs->i2c_sta) & (0x1 << I2C_STA_RFNE)) + *REG32(&controller->regs->data_cmd); + + mxr_mutex_unlock(&controller->mutex); + return NO_ERROR; +} + +// Implement the char protocol for the slave devices. + +static ssize_t intel_broadwell_serialio_i2c_slave_read( + mx_device_t *dev, void *buf, size_t count) +{ + i2c_slave_segment_t segment = { + .read = 1, + .buf = buf, + .len = count, + }; + return intel_broadwell_serialio_i2c_slave_transfer(dev, &segment, 1); +} + +static ssize_t intel_broadwell_serialio_i2c_slave_write( + mx_device_t *dev, const void *buf, size_t count) +{ + i2c_slave_segment_t segment = { + .read = 0, + .buf = (void *)buf, + .len = count, + }; + return intel_broadwell_serialio_i2c_slave_transfer(dev, &segment, 1); +} + +static ssize_t intel_broadwell_serialio_i2c_slave_transfer_ioctl( + mx_device_t *dev, uint32_t op, const void *in_buf, size_t in_len, + void *out_buf, size_t out_len) +{ + mx_status_t status; + + size_t size = in_len; + size_t read_len = 0; + size_t write_len = 0; + int segment_count = 0; + uintptr_t segment_addr = (uintptr_t)in_buf; + // Check that the inputs and output buffer are valid. + while (size) { + const i2c_slave_ioctl_segment_t *ioctl_segment = + (const i2c_slave_ioctl_segment_t *)segment_addr; + size_t base_size = offsetof(i2c_slave_ioctl_segment_t, buf); + int len = ioctl_segment->len; + if (size < base_size) { + status = ERR_INVALID_ARGS; + goto slave_transfer_ioctl_finish_2; + } + + size_t consumed = 0; + if (ioctl_segment->read) { + read_len += len; + consumed = base_size; + } else { + write_len += len; + consumed = base_size + len; + } + if (consumed > size) { + status = ERR_INVALID_ARGS; + goto slave_transfer_ioctl_finish_2; + } + segment_addr += consumed; + size -= consumed; + segment_count++; + } + if (out_len < write_len) { + status = ERR_INVALID_ARGS; + goto slave_transfer_ioctl_finish_2; + } + + // Build a list of segments to transfer. + i2c_slave_segment_t *segments = + calloc(segment_count, sizeof(*segments)); + if (!segments) { + status = ERR_NO_MEMORY; + goto slave_transfer_ioctl_finish_2; + } + i2c_slave_segment_t *cur_segment = segments; + segment_addr = (uintptr_t)in_buf; + uintptr_t out_addr = (uintptr_t)out_buf; + size = in_len; + while (size) { + const i2c_slave_ioctl_segment_t *ioctl_segment = + (const i2c_slave_ioctl_segment_t *)segment_addr; + const size_t base_size = + offsetof(i2c_slave_ioctl_segment_t, buf); + int len = ioctl_segment->len; + + size_t consumed = 0; + if (ioctl_segment->read) { + consumed = base_size; + cur_segment->read = 1; + cur_segment->len = len; + cur_segment->buf = (uint8_t *)out_addr; + out_addr += len; + } else { + consumed = base_size + len; + cur_segment->read = 0; + cur_segment->len = len; + cur_segment->buf = (uint8_t *)(segment_addr + base_size); + } + + cur_segment++; + segment_addr += consumed; + size -= consumed; + } + + status = intel_broadwell_serialio_i2c_slave_transfer( + dev, segments, segment_count); + if (status == NO_ERROR) + status = write_len; + +slave_transfer_ioctl_finish_1: + free(segments); +slave_transfer_ioctl_finish_2: + return status; +} + +static ssize_t intel_broadwell_serialio_i2c_slave_ioctl( + mx_device_t *dev, uint32_t op, const void *in_buf, size_t in_len, + void *out_buf, size_t out_len) +{ + switch (op) { + case I2C_SLAVE_TRANSFER: + return intel_broadwell_serialio_i2c_slave_transfer_ioctl( + dev, op, in_buf, in_len, out_buf, out_len); + break; + default: + return ERR_INVALID_ARGS; + } +} + +static mx_protocol_char_t intel_broadwell_serialio_i2c_slave_char_proto = { + .read = &intel_broadwell_serialio_i2c_slave_read, + .write = &intel_broadwell_serialio_i2c_slave_write, + .ioctl = &intel_broadwell_serialio_i2c_slave_ioctl, +}; + +// Initialize a slave device structure. + +mx_status_t intel_broadwell_serialio_i2c_slave_device_init( + mx_device_t *cont, intel_broadwell_serialio_i2c_slave_device_t *slave, + uint8_t width, uint16_t address) +{ + mx_status_t status = NO_ERROR; + + char name[sizeof(address) * 2 + 2] = { + [sizeof(name) - 1] = '\0', + }; + snprintf(name, sizeof(name) - 1, "%04x", address); + + status = device_init(&slave->device, cont->driver, name, + &intel_broadwell_serialio_i2c_slave_device_proto); + if (status < 0) + return status; + + slave->device.protocol_id = MX_PROTOCOL_CHAR; + slave->device.protocol_ops = + &intel_broadwell_serialio_i2c_slave_char_proto; + + slave->chip_address_width = width; + slave->chip_address = address; + + return status; +} diff --git a/system/udev/intel_broadwell_serialio/i2c/slave.h b/system/udev/intel_broadwell_serialio/i2c/slave.h new file mode 100644 index 000000000..90fb739b5 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/i2c/slave.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include + +typedef struct intel_broadwell_serialio_i2c_slave_device +{ + mx_device_t device; + + uint8_t chip_address_width; + uint16_t chip_address; + + struct list_node slave_list_node; +} intel_broadwell_serialio_i2c_slave_device_t; + +mx_status_t intel_broadwell_serialio_i2c_slave_device_init( + mx_device_t *cont, intel_broadwell_serialio_i2c_slave_device_t *slave, + uint8_t width, uint16_t address); + +#define get_intel_broadwell_serialio_i2c_slave_device(dev) \ + containerof(dev, intel_broadwell_serialio_i2c_slave_device_t, device) diff --git a/system/udev/intel_broadwell_serialio/include/intel_broadwell_serialio/reg.h b/system/udev/intel_broadwell_serialio/include/intel_broadwell_serialio/reg.h new file mode 100644 index 000000000..8a46fd370 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/include/intel_broadwell_serialio/reg.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __REG_H +#define __REG_H + +#include + +/* low level macros for accessing memory mapped hardware registers */ +#define REG64(addr) ((volatile uint64_t *)(uintptr_t)(addr)) +#define REG32(addr) ((volatile uint32_t *)(uintptr_t)(addr)) +#define REG16(addr) ((volatile uint16_t *)(uintptr_t)(addr)) +#define REG8(addr) ((volatile uint8_t *)(uintptr_t)(addr)) + +#define RMWREG64(addr, startbit, width, val) *REG64(addr) = (*REG64(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) +#define RMWREG32(addr, startbit, width, val) *REG32(addr) = (*REG32(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) +#define RMWREG16(addr, startbit, width, val) *REG16(addr) = (*REG16(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) +#define RMWREG8(addr, startbit, width, val) *REG8(addr) = (*REG8(addr) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)) + +#define writel(v, a) (*REG32(a) = (v)) +#define readl(a) (*REG32(a)) +#define writew(v, a) (*REG16(a) = (v)) +#define readw(a) (*REG16(a)) +#define writeb(v, a) (*REG8(a) = (v)) +#define readb(a) (*REG8(a)) + +#endif diff --git a/system/udev/intel_broadwell_serialio/include/intel_broadwell_serialio/serialio.h b/system/udev/intel_broadwell_serialio/include/intel_broadwell_serialio/serialio.h new file mode 100644 index 000000000..79a2301f1 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/include/intel_broadwell_serialio/serialio.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include + +#define INTEL_VID (0x8086) +#define INTEL_BROADWELL_SERIALIO_DMA_DID (0x9ce0) +#define INTEL_BROADWELL_SERIALIO_I2C0_DID (0x9ce1) +#define INTEL_BROADWELL_SERIALIO_I2C1_DID (0x9ce2) +#define INTEL_BROADWELL_SERIALIO_SDIO_DID (0x9cb5) +#define INTEL_BROADWELL_SERIALIO_SPI0_DID (0x9ce5) +#define INTEL_BROADWELL_SERIALIO_SPI1_DID (0x9ce6) +#define INTEL_BROADWELL_SERIALIO_UART0_DID (0x9ce3) +#define INTEL_BROADWELL_SERIALIO_UART1_DID (0x9ce4) + +#define TRACE 0 + +#if TRACE +#define xprintf(fmt...) printf(fmt) +#else +#define xprintf(fmt...) \ + do { \ + } while (0) +#endif + +mx_status_t intel_broadwell_serialio_bind_dma( + mx_driver_t *drv, mx_device_t *dev); +mx_status_t intel_broadwell_serialio_bind_i2c( + mx_driver_t *drv, mx_device_t *dev); +mx_status_t intel_broadwell_serialio_bind_sdio( + mx_driver_t *drv, mx_device_t *dev); +mx_status_t intel_broadwell_serialio_bind_spi( + mx_driver_t *drv, mx_device_t *dev); +mx_status_t intel_broadwell_serialio_bind_uart( + mx_driver_t *drv, mx_device_t *dev); diff --git a/system/udev/intel_broadwell_serialio/sdio/sdio.c b/system/udev/intel_broadwell_serialio/sdio/sdio.c new file mode 100644 index 000000000..c7f1aba02 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/sdio/sdio.c @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#include + +mx_status_t intel_broadwell_serialio_bind_sdio(mx_driver_t *drv, + mx_device_t *dev) +{ + // Not implemented yet. + return ERR_NOT_IMPLEMENTED; +} + diff --git a/system/udev/intel_broadwell_serialio/serialio.c b/system/udev/intel_broadwell_serialio/serialio.c new file mode 100644 index 000000000..16b0c92fc --- /dev/null +++ b/system/udev/intel_broadwell_serialio/serialio.c @@ -0,0 +1,119 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +static mx_status_t intel_broadwell_serialio_probe(mx_driver_t *drv, + mx_device_t *dev) { + pci_protocol_t *pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) + return ERR_NOT_SUPPORTED; + + const pci_config_t* pci_config; + mx_handle_t config_handle = pci->get_config(dev, &pci_config); + + if (config_handle < 0) + return config_handle; + + mx_status_t res; + if ((pci_config->vendor_id == INTEL_VID) && + ((pci_config->device_id == INTEL_BROADWELL_SERIALIO_DMA_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_I2C0_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_I2C1_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_SDIO_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_SPI0_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_SPI1_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_UART0_DID) || + (pci_config->device_id == INTEL_BROADWELL_SERIALIO_UART1_DID))) { + res = NO_ERROR; + } else { + res = ERR_NOT_SUPPORTED; + } + + _magenta_handle_close(config_handle); + return res; +} + +static mx_status_t intel_broadwell_serialio_bind(mx_driver_t *drv, + mx_device_t *dev) +{ + pci_protocol_t *pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) + return ERR_NOT_SUPPORTED; + + const pci_config_t* pci_config; + mx_handle_t config_handle = pci->get_config(dev, &pci_config); + + if (config_handle < 0) + return config_handle; + + mx_status_t res; + switch (pci_config->device_id) { + case INTEL_BROADWELL_SERIALIO_DMA_DID: + res = intel_broadwell_serialio_bind_dma(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_I2C0_DID: + res = intel_broadwell_serialio_bind_i2c(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_I2C1_DID: + res = intel_broadwell_serialio_bind_i2c(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_SDIO_DID: + res = intel_broadwell_serialio_bind_sdio(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_SPI0_DID: + res = intel_broadwell_serialio_bind_spi(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_SPI1_DID: + res = intel_broadwell_serialio_bind_spi(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_UART0_DID: + res = intel_broadwell_serialio_bind_uart(drv, dev); + break; + case INTEL_BROADWELL_SERIALIO_UART1_DID: + res = intel_broadwell_serialio_bind_uart(drv, dev); + break; + default: + res = ERR_NOT_SUPPORTED; + break; + } + + _magenta_handle_close(config_handle); + return res; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_PCI, +}; + +mx_driver_t _intel_broadwell_serialio BUILTIN_DRIVER = { + .name = "intel_broadwell_serialio", + .ops = { + .probe = intel_broadwell_serialio_probe, + .bind = intel_broadwell_serialio_bind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/udev/intel_broadwell_serialio/spi/spi.c b/system/udev/intel_broadwell_serialio/spi/spi.c new file mode 100644 index 000000000..0f8e8dbb6 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/spi/spi.c @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#include + +mx_status_t intel_broadwell_serialio_bind_spi(mx_driver_t *drv, + mx_device_t *dev) +{ + // Not implemented yet. + return ERR_NOT_IMPLEMENTED; +} + diff --git a/system/udev/intel_broadwell_serialio/uart/uart.c b/system/udev/intel_broadwell_serialio/uart/uart.c new file mode 100644 index 000000000..d523692b2 --- /dev/null +++ b/system/udev/intel_broadwell_serialio/uart/uart.c @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#include + +mx_status_t intel_broadwell_serialio_bind_uart(mx_driver_t *drv, + mx_device_t *dev) +{ + // Not implemented yet. + return ERR_NOT_IMPLEMENTED; +} + diff --git a/system/udev/intel_i915/BUILD.gn b/system/udev/intel_i915/BUILD.gn new file mode 100644 index 000000000..c399e48b0 --- /dev/null +++ b/system/udev/intel_i915/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("intel_i915") { + sources = [ + "intel_i915.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/intel_i915/driver.mk b/system/udev/intel_i915/driver.mk new file mode 100644 index 000000000..05185087f --- /dev/null +++ b/system/udev/intel_i915/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/intel_i915.c diff --git a/system/udev/intel_i915/intel_i915.c b/system/udev/intel_i915/intel_i915.c new file mode 100644 index 000000000..6f4a74a49 --- /dev/null +++ b/system/udev/intel_i915/intel_i915.c @@ -0,0 +1,235 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define INTEL_I915_VID (0x8086) +#define INTEL_I915_DID (0x1616) + +#define INTEL_I915_REG_WINDOW_SIZE (0x1000000u) +#define INTEL_I915_FB_WINDOW_SIZE (0x10000000u) + +#define BACKLIGHT_CTRL_OFFSET (0xc8250) +#define BACKLIGHT_CTRL_BIT ((uint32_t)(1u << 31)) + +#define TRACE 0 + +#if TRACE +#define xprintf(fmt...) printf(fmt) +#else +#define xprintf(fmt...) \ + do { \ + } while (0) +#endif + +typedef struct intel_i915_device { + mx_device_t device; + void* regs; + uint64_t regs_size; + mx_handle_t regs_handle; + + void* framebuffer; + uint64_t framebuffer_size; + mx_handle_t framebuffer_handle; + + mx_display_info_t info; +} intel_i915_device_t; + +#define get_i915_device(dev) containerof(dev, intel_i915_device_t, device) + +static void intel_i915_enable_backlight(intel_i915_device_t* dev, bool enable) { + void* backlight_ctrl = (uint8_t*)dev->regs + BACKLIGHT_CTRL_OFFSET; + uint32_t tmp = pcie_read32(backlight_ctrl); + + if (enable) + tmp |= BACKLIGHT_CTRL_BIT; + else + tmp &= ~BACKLIGHT_CTRL_BIT; + + pcie_write32(backlight_ctrl, tmp); +} + +// implement display protocol + +static mx_status_t intel_i915_set_mode(mx_device_t* dev, mx_display_info_t* info) { + return ERR_NOT_SUPPORTED; +} + +static mx_status_t intel_i915_get_mode(mx_device_t* dev, mx_display_info_t* info) { + assert(info); + intel_i915_device_t* device = get_i915_device(dev); + memcpy(info, &device->info, sizeof(mx_display_info_t)); + return NO_ERROR; +} + +static mx_status_t intel_i915_get_framebuffer(mx_device_t* dev, void** framebuffer) { + assert(framebuffer); + intel_i915_device_t* device = get_i915_device(dev); + (*framebuffer) = device->framebuffer; + return NO_ERROR; +} + + +static mx_display_protocol_t intel_i915_display_proto = { + .set_mode = intel_i915_set_mode, + .get_mode = intel_i915_get_mode, + .get_framebuffer = intel_i915_get_framebuffer, +}; + +// implement device protocol + +static mx_status_t intel_i915_open(mx_device_t* dev, uint32_t flags) { + intel_i915_device_t* device = get_i915_device(dev); + intel_i915_enable_backlight(device, true); + return NO_ERROR; +} + +static mx_status_t intel_i915_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t intel_i915_release(mx_device_t* dev) { + intel_i915_device_t* device = get_i915_device(dev); + intel_i915_enable_backlight(device, false); + + if (device->regs) { + _magenta_handle_close(device->regs_handle); + device->regs_handle = -1; + } + + if (device->framebuffer) { + _magenta_handle_close(device->framebuffer_handle); + device->framebuffer_handle = -1; + } + + return NO_ERROR; +} + +static mx_protocol_device_t intel_i915_device_proto = { + .get_protocol = device_base_get_protocol, + .open = intel_i915_open, + .close = intel_i915_close, + .release = intel_i915_release, +}; + +// implement driver object: + +static mx_status_t intel_i915_probe(mx_driver_t* drv, mx_device_t* dev) { + pci_protocol_t* pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) return ERR_NOT_SUPPORTED; + + const pci_config_t* pci_config; + mx_handle_t cfg_handle = pci->get_config(dev, &pci_config); + if (cfg_handle < 0) + return cfg_handle; + + mx_status_t status; + status = (pci_config->vendor_id == INTEL_I915_VID) && (pci_config->device_id == INTEL_I915_DID) + ? NO_ERROR + : ERR_NOT_SUPPORTED; + + _magenta_handle_close(cfg_handle); + + return status; +} + +static mx_status_t intel_i915_bind(mx_driver_t* drv, mx_device_t* dev) { + pci_protocol_t* pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) return ERR_NOT_SUPPORTED; + + mx_status_t status = pci->claim_device(dev); + if (status < 0) return status; + + // map resources and initialize the device + intel_i915_device_t* device = calloc(1, sizeof(intel_i915_device_t)); + if (!device) return ERR_NO_MEMORY; + + // map register window + device->regs_handle = pci->map_mmio(dev, 0, MX_CACHE_POLICY_UNCACHED_DEVICE, + &device->regs, &device->regs_size); + if (device->regs_handle < 0) { + status = device->regs_handle; + goto fail; + } + + // map framebuffer window + device->framebuffer_handle = pci->map_mmio(dev, 2, MX_CACHE_POLICY_WRITE_COMBINING, + &device->framebuffer, + &device->framebuffer_size); + if (device->framebuffer_handle < 0) { + status = device->framebuffer_handle; + goto fail; + } + + // create and add the display (char) device + status = device_init(&device->device, drv, "intel_i915_disp", &intel_i915_device_proto); + if (status) goto fail; + + mx_display_info_t* di = &device->info; + uint32_t format, width, height, stride; + status = _magenta_bootloader_fb_get_info(&format, &width, &height, &stride); + if (status == NO_ERROR) { + di->format = format; + di->width = width; + di->height = height; + di->stride = stride; + } else { + di->format = MX_DISPLAY_FORMAT_RGB_565; + di->width = 2560 / 2; + di->height = 1700 / 2; + di->stride = 2560 / 2; + } + di->flags = MX_DISPLAY_FLAG_HW_FRAMEBUFFER; + + // TODO remove when the gfxconsole moves to user space + intel_i915_enable_backlight(device, true); + _magenta_set_framebuffer(device->framebuffer, device->framebuffer_size, format, width, height, stride); + + device->device.protocol_id = MX_PROTOCOL_DISPLAY; + device->device.protocol_ops = &intel_i915_display_proto; + device_add(&device->device, dev); + + xprintf("initialized intel i915 display driver, reg=0x%x regsize=0x%x fb=0x%x fbsize=0x%x\n", + device->regs, device->regs_size, device->framebuffer, device->framebuffer_size); + + return NO_ERROR; +fail: + free(device); + return status; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_PCI, +}; + +mx_driver_t _driver_intel_i915 BUILTIN_DRIVER = { + .name = "intel_i915_disp", + .ops = { + .probe = intel_i915_probe, + .bind = intel_i915_bind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/udev/intel_rtc/BUILD.gn b/system/udev/intel_rtc/BUILD.gn new file mode 100644 index 000000000..b07cf1dea --- /dev/null +++ b/system/udev/intel_rtc/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("intel_rtc") { + sources = [ + "intel_rtc.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/intel_rtc/driver.mk b/system/udev/intel_rtc/driver.mk new file mode 100644 index 000000000..db2e9018d --- /dev/null +++ b/system/udev/intel_rtc/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/intel_rtc.c diff --git a/system/udev/intel_rtc/intel_rtc.c b/system/udev/intel_rtc/intel_rtc.c new file mode 100644 index 000000000..0279484aa --- /dev/null +++ b/system/udev/intel_rtc/intel_rtc.c @@ -0,0 +1,153 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define RTC_IO_BASE 0x70 +#define RTC_NUM_IO_REGISTERS 8 + +#define RTC_IDX_REG 0x70 +#define RTC_DATA_REG 0x71 + +enum intel_rtc_registers { + REG_SECONDS, + REG_SECONDS_ALARM, + REG_MINUTES, + REG_MINUTES_ALARM, + REG_HOURS, + REG_HOURS_ALARM, + REG_DAY_OF_WEEK, + REG_DAY_OF_MONTH, + REG_MONTH, + REG_YEAR, +}; + + +struct rtc_time { + uint8_t seconds, minutes, hours; +}; +static void read_time(struct rtc_time *t) { + outp(RTC_IDX_REG, REG_SECONDS); + t->seconds = inp(RTC_DATA_REG); + outp(RTC_IDX_REG, REG_MINUTES); + t->minutes = inp(RTC_DATA_REG); + outp(RTC_IDX_REG, REG_HOURS); + t->hours = inp(RTC_DATA_REG); +} + +static bool rtc_time_eq(struct rtc_time *lhs, struct rtc_time *rhs) { + return lhs->seconds == rhs->seconds && + lhs->minutes == rhs->minutes && + lhs->hours == rhs->hours; +} + +// implement char protocol +static ssize_t intel_rtc_read(mx_device_t* dev, void* buf, size_t count) { + struct rtc_time cur, last; + + read_time(&cur); + do { + last = cur; + read_time(&cur); + } while (!rtc_time_eq(&cur, &last)); + + int n = snprintf(buf, count, "%02x:%02x:%02x", cur.hours, cur.minutes, cur.seconds); + if (n < 0) { + return ERR_GENERIC; + } + if ((unsigned int)n > count) { + return ERR_NOT_ENOUGH_BUFFER; + } + return n; +} + +static ssize_t intel_rtc_write(mx_device_t* dev, const void* buf, size_t count) { + return ERR_NOT_SUPPORTED; +} + +static mx_protocol_char_t intel_rtc_char_proto = { + .read = intel_rtc_read, + .write = intel_rtc_write, +}; + +// implement device protocol + +static mx_status_t intel_rtc_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t intel_rtc_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t intel_rtc_release(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_protocol_device_t intel_rtc_device_proto = { + .get_protocol = device_base_get_protocol, + .open = intel_rtc_open, + .close = intel_rtc_close, + .release = intel_rtc_release, +}; + +// implement driver object: +// +static mx_status_t intel_rtc_init(mx_driver_t* drv) { +#if ARCH_X86 + // TODO(teisenbe): This should be probed via the ACPI pseudo bus whenever it + // exists. + + mx_status_t status = _magenta_mmap_device_io(RTC_IO_BASE, RTC_NUM_IO_REGISTERS); + if (status != NO_ERROR) { + return status; + } + + mx_device_t* dev; + status = device_create(&dev, drv, "rtc", &intel_rtc_device_proto); + if (status != NO_ERROR) { + return status; + } + + dev->protocol_id = MX_PROTOCOL_CHAR; + dev->protocol_ops = &intel_rtc_char_proto; + status = device_add(dev, NULL); + if (status != NO_ERROR) { + free(dev); + return status; + } + return NO_ERROR; +#else + intel_rtc_device_proto = intel_rtc_device_proto; + intel_rtc_char_proto = intel_rtc_char_proto; + return ERR_NOT_SUPPORTED; +#endif +} + +mx_driver_t _driver_intel_rtc BUILTIN_DRIVER = { + .name = "intel_rtc", + .ops = { + .init = intel_rtc_init, + }, +}; diff --git a/system/udev/kpci/BUILD.gn b/system/udev/kpci/BUILD.gn new file mode 100644 index 000000000..1090c0b6a --- /dev/null +++ b/system/udev/kpci/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("kpci") { + sources = [ + "kpci.c", + "kpci_priv.h", + "protocol.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/kpci/driver.mk b/system/udev/kpci/driver.mk new file mode 100644 index 000000000..7dc8c9e88 --- /dev/null +++ b/system/udev/kpci/driver.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/kpci.c \ + $(LOCAL_DIR)/protocol.c diff --git a/system/udev/kpci/kpci.c b/system/udev/kpci/kpci.c new file mode 100644 index 000000000..9178ec6a4 --- /dev/null +++ b/system/udev/kpci/kpci.c @@ -0,0 +1,136 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kpci_priv.h" + +// kpci is a driver that communicates with the kernel to publish a list of pci devices. + +static mx_device_t* kpci_root_dev; + +extern pci_protocol_t _pci_protocol; + +static mx_status_t kpci_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t kpci_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t kpci_release(mx_device_t* dev) { + kpci_device_t* device = get_kpci_device(dev); + _magenta_handle_close(device->handle); + free(device); + return NO_ERROR; +} + +static mx_protocol_device_t kpci_device_proto = { + .get_protocol = device_base_get_protocol, + .open = kpci_open, + .close = kpci_close, + .release = kpci_release, +}; + +static mx_status_t kpci_init_child(mx_driver_t* drv, mx_device_t** out, uint32_t index) { + mx_pcie_get_nth_info_t info; + + mx_handle_t handle = _magenta_pci_get_nth_device(index, &info); + if (handle < 0) { + return handle; + } + + kpci_device_t* device = calloc(1, sizeof(kpci_device_t)); + mx_status_t status = ERR_NO_MEMORY; + if (!device) + goto finished; + + char name[20]; + snprintf(name, sizeof(name), "%02x:%02x:%02x", info.bus_id, info.dev_id, info.func_id); + status = device_init(&device->device, drv, name, &kpci_device_proto); + if (status != NO_ERROR) + goto finished; + + device->device.protocol_id = MX_PROTOCOL_PCI; + device->device.protocol_ops = &_pci_protocol; + device->handle = handle; + device->index = index; + *out = &device->device; + +finished: + if (status != NO_ERROR) { + if (device) free(device); + if (handle >= 0) _magenta_handle_close(handle); + } + return status; +} + +static mx_status_t kpci_init_children(mx_driver_t* drv, mx_device_t* parent) { + for (uint32_t index = 0;; index++) { + mx_device_t* device; + if (kpci_init_child(drv, &device, index) != NO_ERROR) { + break; + } + device_add(device, parent); + } + + return NO_ERROR; +} + +static mx_status_t kpci_drv_init(mx_driver_t* drv) { + mx_status_t status; + + if ((status = device_create(&kpci_root_dev, drv, "pci", &kpci_device_proto))) { + return status; + } + + // make the pci root non-bindable + device_set_bindable(kpci_root_dev, false); + + if (device_add(kpci_root_dev, NULL) < 0) { + free(kpci_root_dev); + return NO_ERROR; + } else { + return kpci_init_children(drv, kpci_root_dev); + } +} + +mx_driver_t _driver_kpci BUILTIN_DRIVER = { + .name = "pci", + .ops = { + .init = kpci_drv_init, + }, +}; + +mx_status_t devmgr_create_pcidev(mx_device_t** out, uint32_t index) { + return kpci_init_child(&_driver_kpci, out, index); +} + +int devmgr_get_pcidev_index(mx_device_t* dev) { + if (dev->parent == kpci_root_dev) { + kpci_device_t* pcidev = get_kpci_device(dev); + return (int) pcidev->index; + } else { + return -1; + } +} diff --git a/system/udev/kpci/kpci_priv.h b/system/udev/kpci/kpci_priv.h new file mode 100644 index 000000000..7d43b4c35 --- /dev/null +++ b/system/udev/kpci/kpci_priv.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +typedef struct kpci_device { + mx_device_t device; + mx_handle_t handle; + uint32_t index; +} kpci_device_t; + +#define get_kpci_device(dev) containerof(dev, kpci_device_t, device) diff --git a/system/udev/kpci/protocol.c b/system/udev/kpci/protocol.c new file mode 100644 index 000000000..fb375e807 --- /dev/null +++ b/system/udev/kpci/protocol.c @@ -0,0 +1,108 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +#include "kpci_priv.h" + +static mx_status_t pci_claim_device(mx_device_t* dev) { + kpci_device_t* device = get_kpci_device(dev); + assert(device->handle != MX_HANDLE_INVALID); + return _magenta_pci_claim_device(device->handle); +} + +static mx_status_t pci_enable_bus_master(mx_device_t* dev, bool enable) { + kpci_device_t* device = get_kpci_device(dev); + assert(device->handle != MX_HANDLE_INVALID); + return _magenta_pci_enable_bus_master(device->handle, enable); +} + +static mx_status_t pci_reset_device(mx_device_t* dev) { + kpci_device_t* device = get_kpci_device(dev); + assert(device->handle != MX_HANDLE_INVALID); + return _magenta_pci_reset_device(device->handle); +} + +static mx_handle_t pci_map_mmio(mx_device_t* dev, + uint32_t bar_num, + mx_cache_policy_t cache_policy, + void** vaddr, + uint64_t* size) { + kpci_device_t* device = get_kpci_device(dev); + assert(device->handle != MX_HANDLE_INVALID); + assert(vaddr != NULL); + assert(size != NULL); + + mx_handle_t mmio_handle; + mmio_handle = _magenta_pci_map_mmio(device->handle, bar_num, cache_policy); + if (mmio_handle < 0) + return mmio_handle; + + mx_status_t status = _magenta_io_mapping_get_info(mmio_handle, vaddr, size); + if (status != NO_ERROR) { + assert(status < 0); + _magenta_handle_close(mmio_handle); + return status; + } + + return mmio_handle; +} + +static mx_handle_t pci_map_interrupt(mx_device_t* dev, int which_irq) { + kpci_device_t* device = get_kpci_device(dev); + assert(device->handle != MX_HANDLE_INVALID); + return _magenta_pci_map_interrupt(device->handle, which_irq); +} + +static mx_status_t pci_wait_interrupt(mx_handle_t handle) { + return _magenta_pci_interrupt_wait(handle); +} + +static mx_handle_t pci_get_config(mx_device_t* dev, const pci_config_t** config) { + kpci_device_t* device = get_kpci_device(dev); + assert(device->handle != MX_HANDLE_INVALID); + assert(config != NULL); + + mx_handle_t cfg_handle; + cfg_handle = _magenta_pci_map_config(device->handle); + if (cfg_handle < 0) + return cfg_handle; + + void* vaddr = NULL; + uint64_t size; + + mx_status_t status = _magenta_io_mapping_get_info(cfg_handle, &vaddr, &size); + if (status != NO_ERROR) { + assert(status < 0); + _magenta_handle_close(cfg_handle); + *config = NULL; + return status; + } + + *config = (const pci_config_t*)vaddr; + return cfg_handle; +} + +pci_protocol_t _pci_protocol = { + .claim_device = pci_claim_device, + .enable_bus_master = pci_enable_bus_master, + .reset_device = pci_reset_device, + .map_mmio = pci_map_mmio, + .map_interrupt = pci_map_interrupt, + .pci_wait_interrupt = pci_wait_interrupt, + .get_config = pci_get_config, +}; diff --git a/system/udev/null/BUILD.gn b/system/udev/null/BUILD.gn new file mode 100644 index 000000000..dcc80f7d6 --- /dev/null +++ b/system/udev/null/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("null") { + sources = [ + "null.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/null/driver.mk b/system/udev/null/driver.mk new file mode 100644 index 000000000..38398eaa9 --- /dev/null +++ b/system/udev/null/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/null.c diff --git a/system/udev/null/null.c b/system/udev/null/null.c new file mode 100644 index 000000000..23a6e6a39 --- /dev/null +++ b/system/udev/null/null.c @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include +#include + +// null is the /dev/null device. + +// implement character protocol: + +static ssize_t null_read(mx_device_t* dev, void* buf, size_t count) { + return NO_ERROR; +} + +static ssize_t null_write(mx_device_t* dev, const void* buf, size_t count) { + return count; +} + +static mx_protocol_char_t null_char_proto = { + .read = null_read, + .write = null_write, +}; + +// implement device protocol: + +static mx_status_t null_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t null_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t null_release(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_protocol_device_t null_device_proto = { + .get_protocol = device_base_get_protocol, + .open = null_open, + .close = null_close, + .release = null_release, +}; + +// implement driver object: + +mx_status_t null_init(mx_driver_t* driver) { + mx_device_t* dev; + if (device_create(&dev, driver, "null", &null_device_proto) == NO_ERROR) { + dev->protocol_id = MX_PROTOCOL_CHAR; + dev->protocol_ops = &null_char_proto; + if (device_add(dev, NULL) < 0) { + free(dev); + } + } + return NO_ERROR; +} + +mx_driver_t _driver_null BUILTIN_DRIVER = { + .name = "null", + .ops = { + .init = null_init, + }, +}; diff --git a/system/udev/usb_bt_hci/BUILD.gn b/system/udev/usb_bt_hci/BUILD.gn new file mode 100644 index 000000000..9398359f6 --- /dev/null +++ b/system/udev/usb_bt_hci/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("usb_bt_hci") { + sources = [ + "usb_bt_hci.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/mxu", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/usb_bt_hci/driver.mk b/system/udev/usb_bt_hci/driver.mk new file mode 100644 index 000000000..502fe31a9 --- /dev/null +++ b/system/udev/usb_bt_hci/driver.mk @@ -0,0 +1,18 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/usb_bt_hci.c \ diff --git a/system/udev/usb_bt_hci/usb_bt_hci.c b/system/udev/usb_bt_hci/usb_bt_hci.c new file mode 100644 index 000000000..fb03a3f53 --- /dev/null +++ b/system/udev/usb_bt_hci/usb_bt_hci.c @@ -0,0 +1,443 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define EVENT_REQ_COUNT 8 +#define ACL_READ_REQ_COUNT 8 +#define ACL_WRITE_REQ_COUNT 8 +#define ACL_BUF_SIZE 2048 + +// Uncomment these to force using a particular Bluetooth module +// #define USB_VID 0x0a12 // CSR +// #define USB_PID 0x0001 + +typedef struct { + mx_device_t device; + mx_device_t* usb_device; + usb_device_protocol_t* device_protocol; + + mx_handle_t control_pipe[2]; + mx_handle_t acl_pipe[2]; + + void* intr_queue; + + usb_endpoint_t* bulk_in; + usb_endpoint_t* bulk_out; + usb_endpoint_t* intr_ep; + + // for accumulating HCI events + uint8_t event_buffer[2 + 255]; // 2 byte header and 0 - 255 data + size_t event_buffer_offset; + size_t event_buffer_packet_length; + + // pool of free USB requests + list_node_t free_event_reqs; + list_node_t free_acl_read_reqs; + list_node_t free_acl_write_reqs; + + mxr_mutex_t mutex; +} hci_t; +#define get_hci(dev) containerof(dev, hci_t, device) + +static void queue_acl_read_requests_locked(hci_t* hci) { + list_node_t* node; + while ((node = list_remove_head(&hci->free_acl_read_reqs)) != NULL) { + usb_request_t* req = containerof(node, usb_request_t, node); + req->transfer_length = req->buffer_length; + mx_status_t status = hci->device_protocol->queue_request(hci->usb_device, req); + if (status != NO_ERROR) { + printf("bulk queue queue_request %d\n", status); + list_add_head(&hci->free_event_reqs, &req->node); + break; + } + } +} + +static void queue_interrupt_requests_locked(hci_t* hci) { + list_node_t* node; + while ((node = list_remove_head(&hci->free_event_reqs)) != NULL) { + usb_request_t* req = containerof(node, usb_request_t, node); + req->transfer_length = req->buffer_length; + mx_status_t status = hci->device_protocol->queue_request(hci->usb_device, req); + if (status != NO_ERROR) { + printf("interrupt queue_request failed %d\n", status); + list_add_head(&hci->free_event_reqs, &req->node); + break; + } + } +} + +static void hci_event_complete(usb_request_t* request) { + hci_t* hci = (hci_t*)request->client_data; + mxr_mutex_lock(&hci->mutex); + if (request->status == NO_ERROR) { + uint8_t* buffer = request->buffer; + size_t length = request->transfer_length; + + // simple case - packet fits in received data + if (hci->event_buffer_offset == 0 && length >= 2) { + size_t packet_size = buffer[1] + 2; + if (packet_size == length) { + mx_status_t status = _magenta_message_write(hci->control_pipe[0], buffer, length, + NULL, 0, 0); + if (status < 0) { + printf("hci_interrupt failed to write\n"); + } + goto out; + } + } + + // complicated case - need to accumulate into hci->event_buffer + + if (hci->event_buffer_offset + length > sizeof(hci->event_buffer)) { + printf("hci->event_buffer would overflow!\n"); + goto out2; + } + + memcpy(&hci->event_buffer[hci->event_buffer_offset], buffer, length); + size_t packet_size; + if (hci->event_buffer_offset == 0) { + packet_size = buffer[1] + 2; + hci->event_buffer_packet_length = packet_size; + } else { + packet_size = hci->event_buffer_packet_length; + } + hci->event_buffer_offset += length; + + // check to see if we have a full packet + packet_size = hci->event_buffer[1] + 2; + if (packet_size <= hci->event_buffer_offset) { + mx_status_t status = _magenta_message_write(hci->control_pipe[0], hci->event_buffer, + packet_size, NULL, 0, 0); + if (status < 0) { + printf("hci_interrupt failed to write\n"); + } + uint32_t remaining = hci->event_buffer_offset - packet_size; + memmove(hci->event_buffer, hci->event_buffer + packet_size, remaining); + hci->event_buffer_offset = 0; + hci->event_buffer_packet_length = 0; + } + } + +out: + list_add_head(&hci->free_event_reqs, &request->node); + queue_interrupt_requests_locked(hci); +out2: + mxr_mutex_unlock(&hci->mutex); +} + +static void hci_acl_read_complete(usb_request_t* request) { + hci_t* hci = (hci_t*)request->client_data; + + if (request->status == NO_ERROR) { + mx_status_t status = _magenta_message_write(hci->acl_pipe[0], request->buffer, + request->transfer_length, NULL, 0, 0); + if (status < 0) { + printf("hci_acl_read_complete failed to write\n"); + } + } + + mxr_mutex_lock(&hci->mutex); + list_add_head(&hci->free_acl_read_reqs, &request->node); + queue_acl_read_requests_locked(hci); + mxr_mutex_unlock(&hci->mutex); +} + +static void hci_acl_write_complete(usb_request_t* request) { + hci_t* hci = (hci_t*)request->client_data; + + // FIXME what to do with error here? + mxr_mutex_lock(&hci->mutex); + list_add_tail(&hci->free_acl_write_reqs, &request->node); + mxr_mutex_unlock(&hci->mutex); +} + +static int hci_read_thread(void* arg) { + hci_t* hci = (hci_t*)arg; + + mx_handle_t handles[2]; + handles[0] = hci->control_pipe[0]; + handles[1] = hci->acl_pipe[0]; + mx_signals_t signals[2]; + signals[0] = MX_SIGNAL_READABLE; + signals[1] = MX_SIGNAL_READABLE; + + while (1) { + mx_signals_t satisfied_signals[2]; + mx_signals_t satisfiable_signals[2]; + + mx_status_t status = _magenta_handle_wait_many(countof(handles), handles, signals, + MX_TIME_INFINITE, satisfied_signals, + satisfiable_signals); + if (status < 0) { + printf("_magenta_handle_wait_many fail\n"); + break; + } + if (satisfied_signals[0] & MX_SIGNAL_READABLE) { + uint8_t buf[256]; + uint32_t length = sizeof(buf); + status = _magenta_message_read(handles[0], buf, &length, NULL, 0, 0); + if (status >= 0) { + status = hci->device_protocol->control(hci->usb_device, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, 0, 0, buf, length); + if (status < 0) { + printf("hci_read_thread control failed\n"); + } + } else { + printf("event read failed\n"); + break; + } + } + if (satisfied_signals[1] & MX_SIGNAL_READABLE) { + uint8_t buf[ACL_BUF_SIZE]; + uint32_t length = sizeof(buf); + status = _magenta_message_read(handles[1], buf, &length, NULL, 0, 0); + if (status >= 0) { + mxr_mutex_lock(&hci->mutex); + + list_node_t* node; + do { + node = list_remove_head(&hci->free_acl_write_reqs); + if (!node) { + // FIXME this is nasty + mxr_mutex_unlock(&hci->mutex); + usleep(10 * 1000); + mxr_mutex_lock(&hci->mutex); + } + } while (!node); + mxr_mutex_unlock(&hci->mutex); + + usb_request_t* request = containerof(node, usb_request_t, node); + memcpy(request->buffer, buf, length); + request->transfer_length = length; + status = hci->device_protocol->queue_request(hci->usb_device, request); + if (status < 0) { + printf("hci_read_thread bulk write failed\n"); + break; + } + } + } + } + return 0; +} + +static mx_handle_t hci_get_control_pipe(mx_device_t* device) { + hci_t* hci = get_hci(device); + return hci->control_pipe[1]; +} + +static mx_handle_t hci_get_acl_pipe(mx_device_t* device) { + hci_t* hci = get_hci(device); + return hci->acl_pipe[1]; +} + +static bluetooth_hci_protocol_t hci_proto = { + .get_control_pipe = hci_get_control_pipe, + .get_acl_pipe = hci_get_acl_pipe, +}; + +static mx_status_t hci_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t hci_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t hci_release(mx_device_t* device) { + hci_t* hci = get_hci(device); + free(hci); + + return NO_ERROR; +} + +static mx_protocol_device_t hci_device_proto = { + .get_protocol = device_base_get_protocol, + .open = hci_open, + .close = hci_close, + .release = hci_release, +}; + +static mx_status_t hci_probe(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + usb_device_config_t* device_config; + mx_status_t status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + usb_device_descriptor_t* desc = device_config->descriptor; + +#if defined(USB_VID) && defined(USB_PID) + if (desc->idVendor == USB_VID && desc->idProduct == USB_PID) { + return NO_ERROR; + } +#else + if (desc->bDeviceClass == 224 && desc->bDeviceSubClass == 1 && desc->bDeviceProtocol == 1) { + return NO_ERROR; + } +#endif + return ERR_NOT_SUPPORTED; +} + +static mx_status_t hci_bind(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + usb_device_config_t* device_config; + mx_status_t status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + // find our endpoints + usb_configuration_t* config = &device_config->configurations[0]; + usb_interface_t* intf = &config->interfaces[0]; + if (intf->num_endpoints != 3) { + printf("hci_bind wrong number of endpoints: %d\n", intf->num_endpoints); + return ERR_NOT_SUPPORTED; + } + usb_endpoint_t* bulk_in = NULL; + usb_endpoint_t* bulk_out = NULL; + usb_endpoint_t* intr_ep = NULL; + + for (int i = 0; i < intf->num_endpoints; i++) { + usb_endpoint_t* endp = &intf->endpoints[i]; + if (endp->direction == USB_ENDPOINT_OUT) { + if (endp->type == USB_ENDPOINT_BULK) { + bulk_out = endp; + } + } else { + if (endp->type == USB_ENDPOINT_BULK) { + bulk_in = endp; + } else if (endp->type == USB_ENDPOINT_INTERRUPT) { + intr_ep = endp; + } + } + } + if (!bulk_in || !bulk_out || !intr_ep) { + printf("hci_bind could not find endpoints\n"); + return ERR_NOT_SUPPORTED; + } + + hci_t* hci = calloc(1, sizeof(hci_t)); + if (!hci) { + printf("Not enough memory for hci_t\n"); + return ERR_NO_MEMORY; + } + + hci->control_pipe[0] = _magenta_message_pipe_create(&hci->control_pipe[1]); + if (hci->control_pipe[0] < 0) { + free(hci); + return ERR_NO_MEMORY; + } + hci->acl_pipe[0] = _magenta_message_pipe_create(&hci->acl_pipe[1]); + if (hci->acl_pipe[0] < 0) { + _magenta_handle_close(hci->control_pipe[0]); + _magenta_handle_close(hci->control_pipe[1]); + free(hci); + return ERR_NO_MEMORY; + } + + list_initialize(&hci->free_event_reqs); + list_initialize(&hci->free_acl_read_reqs); + list_initialize(&hci->free_acl_write_reqs); + + hci->usb_device = device; + hci->device_protocol = protocol; + hci->bulk_in = bulk_in; + hci->bulk_out = bulk_out; + hci->intr_ep = intr_ep; + + for (int i = 0; i < EVENT_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, intr_ep, intr_ep->maxpacketsize); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = hci_event_complete; + req->client_data = hci; + list_add_head(&hci->free_event_reqs, &req->node); + } + for (int i = 0; i < ACL_READ_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, bulk_in, ACL_BUF_SIZE); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = hci_acl_read_complete; + req->client_data = hci; + list_add_head(&hci->free_acl_read_reqs, &req->node); + } + for (int i = 0; i < ACL_WRITE_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, bulk_out, ACL_BUF_SIZE); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = hci_acl_write_complete; + req->client_data = hci; + list_add_head(&hci->free_acl_write_reqs, &req->node); + } + + status = device_init(&hci->device, driver, "usb_bt_hci", &hci_device_proto); + if (status != NO_ERROR) { + free(hci); + return status; + } + + mxr_mutex_lock(&hci->mutex); + queue_interrupt_requests_locked(hci); + queue_acl_read_requests_locked(hci); + mxr_mutex_unlock(&hci->mutex); + + mxr_thread_t* thread; + mxr_thread_create(hci_read_thread, hci, "hci_read_thread", &thread); + mxr_thread_detach(thread); + + hci->device.protocol_id = MX_PROTOCOL_BLUETOOTH_HCI; + hci->device.protocol_ops = &hci_proto; + device_add(&hci->device, device); + + return NO_ERROR; +} + +static mx_status_t hci_unbind(mx_driver_t* drv, mx_device_t* dev) { + // TODO - cleanup + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_USB_DEVICE, +}; + +mx_driver_t _driver_usb_bt_hci BUILTIN_DRIVER = { + .name = "usb_bt_hci", + .ops = { + .probe = hci_probe, + .bind = hci_bind, + .unbind = hci_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/udev/usb_ethernet/BUILD.gn b/system/udev/usb_ethernet/BUILD.gn new file mode 100644 index 000000000..f890c5097 --- /dev/null +++ b/system/udev/usb_ethernet/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source_set("usb_ethernet") { + sources = [ + "asix.h", + "ethernet_char.c", + "ethernet_test.c", + "usb_ethernet.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/mxu", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/udev/usb_ethernet/asix.h b/system/udev/usb_ethernet/asix.h new file mode 100644 index 000000000..652a33505 --- /dev/null +++ b/system/udev/usb_ethernet/asix.h @@ -0,0 +1,108 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +// clang-format off + +#define ASIX_VID 0x0B95 +#define ASIX_PID 0x772B + +// Vendor control requests +#define ASIX_REQ_SRAM_READ 0x02 +#define ASIX_REQ_SRAM_WRITE 0x03 +#define ASIX_REQ_SW_SERIAL_MGMT_CTRL 0x06 +#define ASIX_REQ_PHY_READ 0x07 +#define ASIX_REQ_PHY_WRITE 0x08 +#define ASIX_REQ_SW_SERIAL_MGMT_STATUS 0x09 +#define ASIX_REQ_HW_SERIAL_MGMT_CTRL 0x0A +#define ASIX_REQ_SROM_READ 0x0B +#define ASIX_REQ_SROM_WRITE 0x0C +#define ASIX_REQ_SROM_WRITE_ENABLE 0x0D +#define ASIX_REQ_SROM_WRITE_DISABLE 0x0E +#define ASIX_REQ_RX_CONTROL_READ 0x0F +#define ASIX_REQ_RX_CONTROL_WRITE 0x10 +#define ASIX_REQ_IPG_READ 0x11 +#define ASIX_REQ_IPG_WRITE 0x12 +#define ASIX_REQ_NODE_ID_READ 0x13 +#define ASIX_REQ_NODE_ID_WRITE 0x14 +#define ASIX_REQ_MULTI_FIBER_READ 0x15 +#define ASIX_REQ_MULTI_FIBER_WRITE 0x16 +#define ASIX_REQ_TEST 0x17 +#define ASIX_REQ_PHY_ADDR 0x19 +#define ASIX_REQ_MEDIUM_STATUS 0x1A +#define ASIX_REQ_MEDIUM_MODE 0x1B +#define ASIX_REQ_MONITOR_MODE_STATUS 0x1C +#define ASIX_REQ_MONITOR_MODE 0x1D +#define ASIX_REQ_GPIOS_STATUS 0x1E +#define ASIX_REQ_GPIOS 0x1F +#define ASIX_REQ_SW_RESET 0x20 +#define ASIX_REQ_SW_PHY_SELECT_STATUS 0x21 +#define ASIX_REQ_SW_PHY_SELECT 0x22 + +// GPIOs +#define ASIX_GPIO_GPO0EN 0x01 +#define ASIX_GPIO_GPO_0 0x02 +#define ASIX_GPIO_GPO1EN 0x04 +#define ASIX_GPIO_GPO_1 0x08 +#define ASIX_GPIO_GPO2EN 0x10 +#define ASIX_GPIO_GPO_2 0x20 +#define ASIX_GPIO_RSE 0x80 + +// PHY registers +#define ASIX_PHY_BMCR 0 +#define ASIX_PHY_BMSR 1 +#define ASIX_PHY_PHYIDR1 2 +#define ASIX_PHY_PHYIDR2 3 +#define ASIX_PHY_ANAR 4 +#define ASIX_PHY_ANLPAR 5 +#define ASIX_PHY_ANER 6 + +// Reset register bits +#define ASIX_RESET_RR 0x01 +#define ASIX_RESET_RT 0x02 +#define ASIX_RESET_PRTE 0x04 +#define ASIX_RESET_PRL 0x08 +#define ASIX_RESET_BZ 0x10 +#define ASIX_RESET_IPRL 0x20 +#define ASIX_RESET_IPPD 0x40 + +// RX control bits +#define ASIX_RX_CTRL_PRO 0x01 +#define ASIX_RX_CTRL_AMALL 0x02 +#define ASIX_RX_CTRL_SEP 0x04 +#define ASIX_RX_CTRL_AB 0x08 +#define ASIX_RX_CTRL_AM 0x10 +#define ASIX_RX_CTRL_AP 0x20 +#define ASIX_RX_CTRL_S0 0x80 + +// IPG register defaults +#define ASIX_IPG_DEFAULT 0x15 +#define ASIX_IPG1_DEFAULT 0x0C +#define ASIX_IPG2_DEFAULT 0x12 + +// Medium mode bits +#define ASIX_MEDIUM_MODE_GM (1 << 0) +#define ASIX_MEDIUM_MODE_FD (1 << 1) +#define ASIX_MEDIUM_MODE_AC (1 << 2) +#define ASIX_MEDIUM_MODE_EN125 (1 << 3) +#define ASIX_MEDIUM_MODE_RFC (1 << 4) +#define ASIX_MEDIUM_MODE_TFC (1 << 5) +#define ASIX_MEDIUM_MODE_JFE (1 << 6) +#define ASIX_MEDIUM_MODE_PF (1 << 7) +#define ASIX_MEDIUM_MODE_RE (1 << 8) +#define ASIX_MEDIUM_MODE_PS (1 << 9) +#define ASIX_MEDIUM_MODE_JE (1 << 10) +#define ASIX_MEDIUM_MODE_SBP (1 << 11) +#define ASIX_MEDIUM_MODE_SM (1 << 12) diff --git a/system/udev/usb_ethernet/driver.mk b/system/udev/usb_ethernet/driver.mk new file mode 100644 index 000000000..622e0ec7e --- /dev/null +++ b/system/udev/usb_ethernet/driver.mk @@ -0,0 +1,20 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/usb_ethernet.c \ + $(LOCAL_DIR)/ethernet_char.c \ + $(LOCAL_DIR)/ethernet_test.c \ diff --git a/system/udev/usb_ethernet/ethernet_char.c b/system/udev/usb_ethernet/ethernet_char.c new file mode 100644 index 000000000..a7e2261ae --- /dev/null +++ b/system/udev/usb_ethernet/ethernet_char.c @@ -0,0 +1,142 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef struct { + mx_device_t* eth_device; + mx_device_t char_device; + ethernet_protocol_t* eth_protocol; + size_t mtu; + uint8_t mac_addr[6]; +} ethernet_char_t; +#define get_eth_device(dev) containerof(dev, ethernet_char_t, char_device) + +static mx_status_t ethernet_char_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t ethernet_char_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t ethernet_char_release(mx_device_t* device) { + ethernet_char_t* eth = get_eth_device(device); + free(eth); + return NO_ERROR; +} + +static mx_protocol_device_t ethernet_char_device_proto = { + .get_protocol = device_base_get_protocol, + .open = ethernet_char_open, + .close = ethernet_char_close, + .release = ethernet_char_release, +}; + +static ssize_t ethernet_char_read(mx_device_t* device, void* buf, size_t count) { + ethernet_char_t* eth = get_eth_device(device); + + // special case reading MAC address + if (count == sizeof(eth->mac_addr)) { + memcpy(buf, eth->mac_addr, count); + return count; + } + if (count < eth->mtu) { + return ERR_NOT_ENOUGH_BUFFER; + } + return eth->eth_protocol->recv(eth->eth_device, buf, count); +} + +static ssize_t ethernet_char_write(mx_device_t* device, const void* buf, size_t count) { + ethernet_char_t* eth = get_eth_device(device); + return eth->eth_protocol->send(eth->eth_device, buf, count); +} + +static mx_protocol_char_t ethernet_char_proto = { + .read = ethernet_char_read, + .write = ethernet_char_write, +}; + +static mx_status_t ethernet_char_probe(mx_driver_t* driver, mx_device_t* device) { + ethernet_protocol_t* eth_protocol; + if (device_get_protocol(device, MX_PROTOCOL_ETHERNET, (void**)ð_protocol)) { + return ERR_NOT_SUPPORTED; + } + + return NO_ERROR; +} + +static mx_status_t ethernet_char_bind(mx_driver_t* driver, mx_device_t* device) { + ethernet_protocol_t* eth_protocol; + if (device_get_protocol(device, MX_PROTOCOL_ETHERNET, (void**)ð_protocol)) { + return ERR_NOT_SUPPORTED; + } + + ethernet_char_t* eth = calloc(1, sizeof(ethernet_char_t)); + if (!eth) + return ERR_NO_MEMORY; + eth->eth_device = device; + eth->eth_protocol = eth_protocol; + + eth->mtu = eth_protocol->get_mtu(device); + eth_protocol->get_mac_addr(device, eth->mac_addr); + + mx_status_t status = device_init(ð->char_device, driver, "ethernet_char", + ðernet_char_device_proto); + if (status != NO_ERROR) { + free(eth); + return status; + } + eth->char_device.protocol_id = MX_PROTOCOL_CHAR; + eth->char_device.protocol_ops = ðernet_char_proto; + + // duplicate ethernet device status to retweet readable/writable events + mx_handle_t event_handle = _magenta_handle_duplicate(device->event); + if (event_handle < 0) { + free(eth); + return event_handle; + } + eth->char_device.event = event_handle; + device_add(ð->char_device, device); + + return NO_ERROR; +} + +static mx_status_t ethernet_char_unbind(mx_driver_t* drv, mx_device_t* dev) { + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_ETHERNET, +}; + +mx_driver_t _driver_ethernet_char BUILTIN_DRIVER = { + .name = "ethernet_char", + .ops = { + .probe = ethernet_char_probe, + .bind = ethernet_char_bind, + .unbind = ethernet_char_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/udev/usb_ethernet/ethernet_test.c b/system/udev/usb_ethernet/ethernet_test.c new file mode 100644 index 000000000..302c640a4 --- /dev/null +++ b/system/udev/usb_ethernet/ethernet_test.c @@ -0,0 +1,121 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef struct { + mx_device_t* device; + ethernet_protocol_t* protocol; +} ethernet_test_t; + +// this is the beacon that the bootloader sends to bootserver +static const uint8_t beacon[] = { + 0x33, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x50, 0xB6, 0x17, 0x1C, 0x71, 0x86, 0xDD, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x43, 0x11, 0xFF, 0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, + 0xB6, 0xFF, 0xFE, 0x17, 0x1C, 0x71, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0x32, 0x82, 0x33, 0x00, 0x43, 0x6E, 0x0E, 0x17, 0x42, + 0x77, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x00, 0x2E, 0x31, 0x00, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x6E, + 0x6F, 0x00, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00, 0x62, 0x6F, 0x61, 0x72, 0x64, 0x00, + 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00, 0x00, 0x00}; + +static void wait_signal(ethernet_test_t* eth, mx_signals_t signal) { + mx_signals_t satisfied_signals, satisfiable_signals; + do { + _magenta_handle_wait_one(eth->device->event, signal, MX_TIME_INFINITE, + &satisfied_signals, &satisfiable_signals); + } while ((satisfied_signals & signal) != signal); +} + +static int ethernet_read_thread(void* arg) { + ethernet_test_t* eth = (ethernet_test_t*)arg; + + while (1) { + wait_signal(eth, DEV_STATE_READABLE); + uint8_t buffer[2048]; + mx_status_t status = eth->protocol->recv(eth->device, buffer, sizeof(buffer)); + printf("ethernet_read_thread got %d\n", status); + } + return 0; +} + +static int ethernet_write_thread(void* arg) { + ethernet_test_t* eth = (ethernet_test_t*)arg; + + while (1) { + wait_signal(eth, DEV_STATE_WRITABLE); + mx_status_t status = eth->protocol->send(eth->device, beacon, sizeof(beacon)); + printf("ethernet_write_thread got %d\n", status); + sleep(1); + } + return 0; +} + +static mx_status_t ethernet_test_probe(mx_driver_t* driver, mx_device_t* device) { + ethernet_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_ETHERNET, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + + return NO_ERROR; +} + +static mx_status_t ethernet_test_bind(mx_driver_t* driver, mx_device_t* device) { + ethernet_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_ETHERNET, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + + ethernet_test_t* eth = calloc(1, sizeof(ethernet_test_t)); + if (!eth) + return ERR_NO_MEMORY; + eth->device = device; + eth->protocol = protocol; + + mxr_thread_t* thread; + mxr_thread_create(ethernet_read_thread, eth, "ethernet_read_thread", &thread); + mxr_thread_detach(thread); + mxr_thread_create(ethernet_write_thread, eth, "ethernet_write_thread", &thread); + mxr_thread_detach(thread); + + return NO_ERROR; +} + +static mx_status_t ethernet_test_unbind(mx_driver_t* drv, mx_device_t* dev) { + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_ETHERNET, +}; + +// uncomment BUILTIN_DRIVER below to enable this test driver +mx_driver_t _driver_ethernet_test /* BUILTIN_DRIVER */ = { + .name = "ethernet_test", + .ops = { + .probe = ethernet_test_probe, + .bind = ethernet_test_bind, + .unbind = ethernet_test_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/udev/usb_ethernet/usb_ethernet.c b/system/udev/usb_ethernet/usb_ethernet.c new file mode 100644 index 000000000..80b7be35f --- /dev/null +++ b/system/udev/usb_ethernet/usb_ethernet.c @@ -0,0 +1,605 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "asix.h" + +#define READ_REQ_COUNT 8 +#define WRITE_REQ_COUNT 4 +#define INTR_REQ_COUNT 4 +#define USB_BUF_SIZE 2048 +#define INTR_REQ_SIZE 8 +#define ETH_HEADER_SIZE 4 + +typedef struct { + mx_device_t device; + mx_device_t* usb_device; + usb_device_protocol_t* device_protocol; + mx_driver_t* driver; + + uint8_t phy_id; + uint8_t mac_addr[6]; + uint8_t status[INTR_REQ_SIZE]; + bool online; + + usb_endpoint_t* bulk_in; + usb_endpoint_t* bulk_out; + usb_endpoint_t* intr_ep; + + // pool of free USB requests + list_node_t free_read_reqs; + list_node_t free_write_reqs; + list_node_t free_intr_reqs; + + // list of received packets not yet read by upper layer + list_node_t completed_reads; + // offset of next packet to process from completed_reads head + int read_offset; + + // the last signals we reported + mx_signals_t signals; + + mxr_mutex_t mutex; +} usb_ethernet_t; +#define get_usb_ethernet(dev) containerof(dev, usb_ethernet_t, device) + +static void update_signals_locked(usb_ethernet_t* eth) { + // TODO (voydanoff) signal error state here + mx_signals_t new_signals = 0; + if (!list_is_empty(ð->completed_reads)) + new_signals |= DEV_STATE_READABLE; + if (!list_is_empty(ð->free_write_reqs) && eth->online) + new_signals |= DEV_STATE_WRITABLE; + if (new_signals != eth->signals) { + device_state_set_clr(ð->device, new_signals & ~eth->signals, eth->signals & ~new_signals); + eth->signals = new_signals; + } +} + +static mx_status_t usb_ethernet_control(usb_ethernet_t* eth, uint8_t request_type, uint8_t request, + uint16_t value, uint16_t index, void* data, uint16_t length) { + return eth->device_protocol->control(eth->usb_device, request_type, request, value, index, data, + length); +} + +static mx_status_t usb_ethernet_set_value(usb_ethernet_t* eth, uint8_t request, uint16_t value) { + return usb_ethernet_control(eth, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + request, value, 0, NULL, 0); +} + +static mx_status_t usb_ethernet_mdio_read(usb_ethernet_t* eth, uint8_t offset, uint16_t* value) { + + mx_status_t status = usb_ethernet_set_value(eth, ASIX_REQ_SW_SERIAL_MGMT_CTRL, 0); + if (status < 0) { + printf("ASIX_REQ_SW_SERIAL_MGMT_CTRL failed\n"); + return status; + } + status = usb_ethernet_control(eth, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ASIX_REQ_PHY_READ, eth->phy_id, offset, + value, sizeof(*value)); + if (status < 0) { + printf("ASIX_REQ_PHY_READ failed\n"); + return status; + } + status = usb_ethernet_set_value(eth, ASIX_REQ_HW_SERIAL_MGMT_CTRL, 0); + if (status < 0) { + printf("ASIX_REQ_HW_SERIAL_MGMT_CTRL failed\n"); + return status; + } + + return NO_ERROR; +} + +static mx_status_t usb_ethernet_mdio_write(usb_ethernet_t* eth, uint8_t offset, uint16_t value) { + + mx_status_t status = usb_ethernet_set_value(eth, ASIX_REQ_SW_SERIAL_MGMT_CTRL, 0); + if (status < 0) { + printf("ASIX_REQ_SW_SERIAL_MGMT_CTRL failed\n"); + return status; + } + status = usb_ethernet_control(eth, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ASIX_REQ_PHY_WRITE, eth->phy_id, offset, + &value, sizeof(value)); + if (status < 0) { + printf("ASIX_REQ_PHY_READ failed\n"); + return status; + } + status = usb_ethernet_set_value(eth, ASIX_REQ_HW_SERIAL_MGMT_CTRL, 0); + if (status < 0) { + printf("ASIX_REQ_HW_SERIAL_MGMT_CTRL failed\n"); + return status; + } + + return NO_ERROR; +} + +static mx_status_t usb_ethernet_wait_for_phy(usb_ethernet_t* eth) { + + for (int i = 0; i < 100; i++) { + uint16_t bmsr; + mx_status_t status = usb_ethernet_mdio_read(eth, ASIX_PHY_BMSR, &bmsr); + if (status < 0) { + printf("usb_ethernet_mdio_read failed\n"); + return status; + } + if (bmsr) + return NO_ERROR; + usleep(50); + } + + printf("usb_ethernet_wait_for_phy timeout\n"); + return ERR_TIMED_OUT; +} + +static void requeue_read_request_locked(usb_ethernet_t* eth, usb_request_t* req) { + if (eth->online) { + req->transfer_length = req->buffer_length; + mx_status_t status = eth->device_protocol->queue_request(eth->usb_device, req); + if (status != NO_ERROR) { + printf("bulk read failed %d\n", status); + } else { + return; + } + } + + list_add_head(ð->free_read_reqs, &req->node); +} + +static void queue_interrupt_requests_locked(usb_ethernet_t* eth) { + list_node_t* node; + while ((node = list_remove_head(ð->free_intr_reqs)) != NULL) { + usb_request_t* req = containerof(node, usb_request_t, node); + req->transfer_length = req->buffer_length; + mx_status_t status = eth->device_protocol->queue_request(eth->usb_device, req); + if (status != NO_ERROR) { + printf("interrupt queue failed %d\n", status); + list_add_head(ð->free_intr_reqs, &req->node); + break; + } + } +} + +static void usb_ethernet_read_complete(usb_request_t* request) { + usb_ethernet_t* eth = (usb_ethernet_t*)request->client_data; + + mxr_mutex_lock(ð->mutex); + if (request->status == NO_ERROR) { + list_add_tail(ð->completed_reads, &request->node); + } else { + requeue_read_request_locked(eth, request); + } + update_signals_locked(eth); + mxr_mutex_unlock(ð->mutex); +} + +static void usb_ethernet_write_complete(usb_request_t* request) { + usb_ethernet_t* eth = (usb_ethernet_t*)request->client_data; + // FIXME what to do with error here? + mxr_mutex_lock(ð->mutex); + list_add_tail(ð->free_write_reqs, &request->node); + update_signals_locked(eth); + mxr_mutex_unlock(ð->mutex); +} + +static void usb_ethernet_interrupt_complete(usb_request_t* request) { + usb_ethernet_t* eth = (usb_ethernet_t*)request->client_data; + mxr_mutex_lock(ð->mutex); + if (request->status == NO_ERROR && request->transfer_length == sizeof(eth->status) && + memcmp(eth->status, request->buffer, sizeof(eth->status))) { + // const uint8_t* b = request->buffer; + // printf("usb_ethernet status changed: %02X %02X %02X %02X %02X %02X %02X %02X\n", + // b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); + memcpy(eth->status, request->buffer, sizeof(eth->status)); + uint8_t bb = eth->status[2]; + bool online = (bb & 1) != 0; + bool was_online = eth->online; + eth->online = online; + if (online && !was_online) { + // Now that we are online, queue all our read requests + usb_request_t* req; + usb_request_t* prev; + list_for_every_entry_safe (ð->free_read_reqs, req, prev, usb_request_t, node) { + list_delete(&req->node); + requeue_read_request_locked(eth, req); + } + update_signals_locked(eth); + } + } + + list_add_head(ð->free_intr_reqs, &request->node); + queue_interrupt_requests_locked(eth); + mxr_mutex_unlock(ð->mutex); +} + +mx_status_t usb_ethernet_send(mx_device_t* device, const void* buffer, size_t length) { + usb_ethernet_t* eth = get_usb_ethernet(device); + mx_status_t status = NO_ERROR; + + mxr_mutex_lock(ð->mutex); + + list_node_t* node = list_remove_head(ð->free_write_reqs); + if (!node) { + status = ERR_NOT_ENOUGH_BUFFER; + goto out; + } + usb_request_t* request = containerof(node, usb_request_t, node); + uint8_t* buf = request->buffer; + if (length + sizeof(uint32_t) > request->buffer_length) { + status = ERR_INVALID_ARGS; + goto out; + } + + // write 4 byte packet header + uint8_t lo = length & 0xFF; + uint8_t hi = length >> 8; + buf[0] = lo; + buf[1] = hi; + buf[2] = lo ^ 0xFF; + buf[3] = hi ^ 0xFF; + memcpy(buf + 4, buffer, length); + + request->transfer_length = length + ETH_HEADER_SIZE; + status = eth->device_protocol->queue_request(eth->usb_device, request); + +out: + update_signals_locked(eth); + mxr_mutex_unlock(ð->mutex); + return status; +} + +mx_status_t usb_ethernet_recv(mx_device_t* device, void* buffer, size_t length) { + usb_ethernet_t* eth = get_usb_ethernet(device); + mx_status_t status = NO_ERROR; + + mxr_mutex_lock(ð->mutex); + int offset = eth->read_offset; + + list_node_t* node = list_peek_head(ð->completed_reads); + if (!node) { + status = ERR_NO_MSG; + goto out; + } + usb_request_t* request = containerof(node, usb_request_t, node); + uint8_t* buf = request->buffer + offset; + int remaining = request->transfer_length - offset; + if (remaining < 4) { + printf("usb_ethernet_recv short packet\n"); + status = ERR_NOT_VALID; + list_remove_head(ð->completed_reads); + requeue_read_request_locked(eth, request); + goto out; + } + uint16_t length1 = (buf[0] | (uint16_t)buf[1] << 8) & 0x7FF; + uint16_t length2 = (~(buf[2] | (uint16_t)buf[3] << 8)) & 0x7FF; + + if (length1 != length2) { + printf("invalid header: length1: %d length2: %d offset %d\n", length1, length2, offset); + status = ERR_NOT_VALID; + offset = 0; + list_remove_head(ð->completed_reads); + requeue_read_request_locked(eth, request); + goto out; + } + if (length1 > length) { + status = ERR_NOT_ENOUGH_BUFFER; + goto out; + } + memcpy(buffer, buf + 4, length1); + status = length1; + offset += (length1 + 4); + if (offset & 1) + offset++; + if (offset >= request->transfer_length) { + offset = 0; + list_remove_head(ð->completed_reads); + requeue_read_request_locked(eth, request); + } + +out: + eth->read_offset = offset; + + update_signals_locked(eth); + mxr_mutex_unlock(ð->mutex); + return status; +} + +mx_status_t usb_ethernet_get_mac_addr(mx_device_t* device, uint8_t* out_addr) { + usb_ethernet_t* eth = get_usb_ethernet(device); + memcpy(out_addr, eth->mac_addr, sizeof(eth->mac_addr)); + return NO_ERROR; +} + +mx_status_t usb_ethernet_is_online(mx_device_t* device) { + usb_ethernet_t* eth = get_usb_ethernet(device); + return eth->online ? NO_ERROR : ERR_OFFLINE; +} + +size_t usb_ethernet_get_mtu(mx_device_t* device) { + return USB_BUF_SIZE - ETH_HEADER_SIZE; +} + +static ethernet_protocol_t usb_ethernet_proto = { + .send = usb_ethernet_send, + .recv = usb_ethernet_recv, + .get_mac_addr = usb_ethernet_get_mac_addr, + .is_online = usb_ethernet_is_online, + .get_mtu = usb_ethernet_get_mtu, +}; + +static mx_status_t usb_ethernet_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t usb_ethernet_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t usb_ethernet_release(mx_device_t* device) { + usb_ethernet_t* eth = get_usb_ethernet(device); + free(eth); + + return NO_ERROR; +} + +static mx_protocol_device_t usb_ethernet_device_proto = { + .get_protocol = device_base_get_protocol, + .open = usb_ethernet_open, + .close = usb_ethernet_close, + .release = usb_ethernet_release, +}; + +static int usb_ethernet_start_thread(void* arg) { + usb_ethernet_t* eth = (usb_ethernet_t*)arg; + + // set some GPIOs + mx_status_t status = usb_ethernet_set_value(eth, ASIX_REQ_GPIOS, + ASIX_GPIO_GPO2EN | ASIX_GPIO_GPO_2 | ASIX_GPIO_RSE); + if (status < 0) { + printf("ASIX_REQ_WRITE_GPIOS failed\n"); + return status; + } + + // select the PHY + uint8_t phy_addr[2]; + status = usb_ethernet_control(eth, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ASIX_REQ_PHY_ADDR, 0, 0, &phy_addr, sizeof(phy_addr)); + if (status < 0) { + printf("ASIX_REQ_READ_PHY_ADDR failed\n"); + return status; + } + eth->phy_id = phy_addr[1]; + int embed_phy = (eth->phy_id & 0x1F) == 0x10 ? 1 : 0; + status = usb_ethernet_set_value(eth, ASIX_REQ_SW_PHY_SELECT, embed_phy); + if (status < 0) { + printf("ASIX_REQ_SW_PHY_SELECT failed\n"); + return status; + } + + // Reset + status = usb_ethernet_set_value(eth, ASIX_REQ_SW_RESET, ASIX_RESET_PRL | ASIX_RESET_IPPD); + if (status < 0) { + printf("ASIX_REQ_SW_RESET failed\n"); + return status; + } + status = usb_ethernet_set_value(eth, ASIX_REQ_SW_RESET, 0); + if (status < 0) { + printf("ASIX_REQ_SW_RESET failed\n"); + return status; + } + status = usb_ethernet_set_value(eth, ASIX_REQ_SW_RESET, + (embed_phy ? ASIX_RESET_IPRL : ASIX_RESET_PRTE)); + if (status < 0) { + printf("ASIX_REQ_SW_RESET failed\n"); + return status; + } + status = usb_ethernet_set_value(eth, ASIX_REQ_RX_CONTROL_WRITE, 0); + if (status < 0) { + printf("ASIX_REQ_RX_CONTROL_WRITE failed\n"); + return status; + } + + status = usb_ethernet_wait_for_phy(eth); + if (status < 0) { + return status; + } + + uint16_t medium = ASIX_MEDIUM_MODE_FD | ASIX_MEDIUM_MODE_AC | ASIX_MEDIUM_MODE_RFC | ASIX_MEDIUM_MODE_TFC | ASIX_MEDIUM_MODE_JFE | ASIX_MEDIUM_MODE_RE | ASIX_MEDIUM_MODE_PS; + status = usb_ethernet_set_value(eth, ASIX_REQ_MEDIUM_MODE, medium); + if (status < 0) { + printf("ASIX_REQ_MEDIUM_MODE failed\n"); + return status; + } + + status = usb_ethernet_control(eth, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ASIX_REQ_IPG_WRITE, ASIX_IPG_DEFAULT | (ASIX_IPG1_DEFAULT << 8), + ASIX_IPG2_DEFAULT, NULL, 0); + if (status < 0) { + printf("ASIX_REQ_IPG_WRITE failed\n"); + return status; + } + + status = usb_ethernet_set_value(eth, ASIX_REQ_RX_CONTROL_WRITE, ASIX_RX_CTRL_AMALL | ASIX_RX_CTRL_AB | ASIX_RX_CTRL_S0); + if (status < 0) { + printf("ASIX_REQ_RX_CONTROL_WRITE failed\n"); + return status; + } + + status = usb_ethernet_control(eth, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ASIX_REQ_NODE_ID_READ, 0, 0, eth->mac_addr, sizeof(eth->mac_addr)); + if (status < 0) { + printf("ASIX_REQ_NODE_ID_READ failed\n"); + return status; + } + printf("usb_ethernet MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", + eth->mac_addr[0], eth->mac_addr[1], eth->mac_addr[2], + eth->mac_addr[3], eth->mac_addr[4], eth->mac_addr[5]); + + status = device_init(ð->device, eth->driver, "usb_ethernet", &usb_ethernet_device_proto); + if (status != NO_ERROR) { + free(eth); + return status; + } + + mxr_mutex_lock(ð->mutex); + queue_interrupt_requests_locked(eth); + mxr_mutex_unlock(ð->mutex); + + eth->device.protocol_id = MX_PROTOCOL_ETHERNET; + eth->device.protocol_ops = &usb_ethernet_proto; + device_add(ð->device, eth->usb_device); + + return NO_ERROR; +} + +static mx_status_t usb_ethernet_probe(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + usb_device_config_t* device_config; + mx_status_t status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + uint16_t vid = le16toh(device_config->descriptor->idVendor); + uint16_t pid = le16toh(device_config->descriptor->idProduct); + if (vid != ASIX_VID || pid != ASIX_PID) { + return ERR_NOT_SUPPORTED; + } + + return NO_ERROR; +} + +static mx_status_t usb_ethernet_bind(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + usb_device_config_t* device_config; + mx_status_t status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + // find our endpoints + usb_configuration_t* config = &device_config->configurations[0]; + usb_interface_t* intf = &config->interfaces[0]; + if (intf->num_endpoints != 3) { + printf("usb_ethernet_bind wrong number of endpoints: %d\n", intf->num_endpoints); + return ERR_NOT_SUPPORTED; + } + usb_endpoint_t* bulk_in = NULL; + usb_endpoint_t* bulk_out = NULL; + usb_endpoint_t* intr_ep = NULL; + + for (int i = 0; i < intf->num_endpoints; i++) { + usb_endpoint_t* endp = &intf->endpoints[i]; + if (endp->direction == USB_ENDPOINT_OUT) { + if (endp->type == USB_ENDPOINT_BULK) { + bulk_out = endp; + } + } else { + if (endp->type == USB_ENDPOINT_BULK) { + bulk_in = endp; + } else if (endp->type == USB_ENDPOINT_INTERRUPT) { + intr_ep = endp; + } + } + } + if (!bulk_in || !bulk_out || !intr_ep) { + printf("usb_ethernet_bind could not find endpoints\n"); + return ERR_NOT_SUPPORTED; + } + + usb_ethernet_t* eth = calloc(1, sizeof(usb_ethernet_t)); + if (!eth) { + printf("Not enough memory for usb_ethernet_t\n"); + return ERR_NO_MEMORY; + } + + list_initialize(ð->free_read_reqs); + list_initialize(ð->free_write_reqs); + list_initialize(ð->free_intr_reqs); + list_initialize(ð->completed_reads); + + eth->usb_device = device; + eth->driver = driver; + eth->device_protocol = protocol; + eth->bulk_in = bulk_in; + eth->bulk_out = bulk_out; + eth->intr_ep = intr_ep; + + for (int i = 0; i < READ_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, bulk_in, USB_BUF_SIZE); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = usb_ethernet_read_complete; + req->client_data = eth; + list_add_head(ð->free_read_reqs, &req->node); + } + for (int i = 0; i < WRITE_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, bulk_out, USB_BUF_SIZE); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = usb_ethernet_write_complete; + req->client_data = eth; + list_add_head(ð->free_write_reqs, &req->node); + } + for (int i = 0; i < INTR_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, intr_ep, INTR_REQ_SIZE); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = usb_ethernet_interrupt_complete; + req->client_data = eth; + list_add_head(ð->free_intr_reqs, &req->node); + } + + mxr_thread_t* thread; + mxr_thread_create(usb_ethernet_start_thread, eth, "usb_ethernet_start_thread", &thread); + mxr_thread_detach(thread); + + return NO_ERROR; +} + +static mx_status_t usb_ethernet_unbind(mx_driver_t* drv, mx_device_t* dev) { + // TODO - cleanup + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_USB_DEVICE, +}; + +mx_driver_t _driver_usb_ethernet BUILTIN_DRIVER = { + .name = "usb_ethernet", + .ops = { + .probe = usb_ethernet_probe, + .bind = usb_ethernet_bind, + .unbind = usb_ethernet_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/system/ulib/ddk/BUILD.gn b/system/ulib/ddk/BUILD.gn new file mode 100644 index 000000000..192f49e66 --- /dev/null +++ b/system/ulib/ddk/BUILD.gn @@ -0,0 +1,50 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_ddk_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("ddk") { + public_configs = [ ":_ddk_config" ] + public = [ + "include/hw/pci.h", + "include/hw/usb.h", + "include/ddk/device.h", + "include/ddk/driver.h", + "include/ddk/io_alloc.h", + "include/ddk/protocol/bluetooth_hci.h", + "include/ddk/protocol/char.h", + "include/ddk/protocol/display.h", + "include/ddk/protocol/ethernet.h", + "include/ddk/protocol/fb.h", + "include/ddk/protocol/pci.h", + "include/ddk/protocol/usb_bus.h", + "include/ddk/protocol/usb_hci.h", + "include/ddk/protocol/usb_hub.h", + ] + sources = [ + "io_alloc.c", + "protocol/keyboard.c", + ] + deps = [ + "//third_party/ulib/musl", + ] + public_deps = [ + "//system/ulib/magenta", + "//system/ulib/mxu", + "//system/ulib/runtime", + ] +} diff --git a/system/ulib/ddk/include/ddk/device.h b/system/ulib/ddk/include/ddk/device.h new file mode 100644 index 000000000..ddb75a0c0 --- /dev/null +++ b/system/ulib/ddk/include/ddk/device.h @@ -0,0 +1,130 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +typedef struct mx_device mx_device_t; +typedef struct mx_driver mx_driver_t; + +typedef struct mx_protocol_device mx_protocol_device_t; + +typedef struct vnode vnode_t; + +//TODO: multi-char constants are implementation-specific +// move to something more ABI-stable + +#define MX_DEVICE_MAGIC 'MDEV' +#define MX_DEVICE_NAME_MAX 32 + +struct mx_device { + uintptr_t magic; + + const char *name; + + mx_protocol_device_t *ops; + + uint32_t flags; + uint32_t refcount; + + mx_handle_t event; + mx_handle_t remote; + uintptr_t remote_id; + + // most devices implement a single + // protocol beyond the base device protocol + uint32_t protocol_id; + void *protocol_ops; + + mx_driver_t *driver; + // driver that has published this device + + mx_device_t *parent; + // parent in the device tree + + mx_driver_t *owner; + // driver that is bound to this device, NULL if unbound + + struct list_node node; + // for the parent's device_list + + struct list_node device_list; + // list of this device's children in the device tree + + struct list_node pnode; + // for list of all devices that implement a protocol + // TODO: will have to change for multi-protocol support + + struct list_node unode; + // for list of all unmatched devices, if not bound + // TODO: use this for general lifecycle tracking + + vnode_t* vnode; + // used by devmgr internals + + char namedata[MX_DEVICE_NAME_MAX+1]; +}; + +// mx_device_t objects must be created or initialized by the driver manager's +// device_create() and device_init() functions. Drivers MAY NOT touch any +// fields in the mx_device_t, except for the protocol_id and protocol_ops +// fields which it may fill out after init and before device_add() is called. + +// The Device Protocol +typedef struct mx_protocol_device { + mx_status_t (*get_protocol)(mx_device_t* dev, uint32_t proto_id, void** protocol); + // Asks if the device supports a specific protocol. + // If it does, protocol ops returned via **protocol. + + mx_status_t (*open)(mx_device_t* dev, uint32_t flags); + + mx_status_t (*close)(mx_device_t* dev); + + mx_status_t (*release)(mx_device_t* dev); + // Release any resources held by the mx_device_t and free() it. + // release is called after a device is remove()'d and its + // refcount hits zero (all closes and unbinds complete) +} mx_protocol_device_t; + +// Device Convenience Wrappers +static inline mx_status_t device_get_protocol(mx_device_t* dev, uint32_t proto_id, void** protocol) { + return dev->ops->get_protocol(dev, proto_id, protocol); +} + +// State change functions +// Used by driver to indicate if there's data available to read, +// or room to write, or an error condition. +#define DEV_STATE_READABLE MX_SIGNAL_USER0 +#define DEV_STATE_WRITABLE MX_SIGNAL_USER1 +#define DEV_STATE_ERROR MX_SIGNAL_USER2 + +static inline void device_state_set(mx_device_t* dev, mx_signals_t stateflag) { + _magenta_object_signal(dev->event, stateflag, 0); +} + +static inline void device_state_clr(mx_device_t* dev, mx_signals_t stateflag) { + _magenta_object_signal(dev->event, 0, stateflag); +} + +static inline void device_state_set_clr(mx_device_t* dev, mx_signals_t setflag, mx_signals_t clearflag) { + _magenta_object_signal(dev->event, setflag, clearflag); +} + + +// Devices which implement just the device protocol and one +// additional protocol may use this common implementation: +mx_status_t device_base_get_protocol(mx_device_t* dev, uint32_t proto_id, void** proto); diff --git a/system/ulib/ddk/include/ddk/driver.h b/system/ulib/ddk/include/ddk/driver.h new file mode 100644 index 000000000..1085de7e6 --- /dev/null +++ b/system/ulib/ddk/include/ddk/driver.h @@ -0,0 +1,105 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +typedef struct mx_device mx_device_t; +typedef struct mx_protocol_device mx_protocol_device_t; + +typedef struct mx_driver mx_driver_t; +typedef struct mx_driver_binding mx_driver_binding_t; + +typedef struct mx_driver_ops { + mx_status_t (*init)(mx_driver_t* driver); + // Opportunity to do on-load work. + // Called ony once, before any other ops are called. + + mx_status_t (*probe)(mx_driver_t* driver, mx_device_t *device); + // Query whether this driver can bind to this device. + // NO_ERROR indicates it can do so. + + mx_status_t (*bind)(mx_driver_t* driver, mx_device_t *device); + // Requests that the driver bind to the provided device, + // initialize it, and publish and children. + + mx_status_t (*unbind)(mx_driver_t* driver, mx_device_t *device); + // Notifies the driver that the device is being removed (has + // been hot unplugged, etc) + + mx_status_t (*shutdown)(mx_driver_t* driver); + // Requests that the driver un-publish children, release the devices + // that it's bound to, etc. + + mx_status_t (*release)(mx_driver_t* driver); + // Last call before driver is unloaded. +} mx_driver_ops_t; + +struct mx_driver { + const char* name; + + mx_driver_ops_t ops; + + struct list_node node; + + mx_driver_binding_t* binding; + uint32_t binding_count; + // list of protocols and options +}; + +struct mx_driver_binding { + uint32_t protocol_id; + void* protocol_info; +}; + +// Device Manager API +mx_status_t device_create(mx_device_t **device, mx_driver_t* driver, + const char *name, mx_protocol_device_t* ops); +mx_status_t device_init(mx_device_t *device, mx_driver_t *driver, + const char* name, mx_protocol_device_t* ops); +// Devices are created or (if embedded in a driver-specific structure) +// initialized with the above functions. The mx_device_t will be completely +// written during initialization, and after initialization and before calling +// device_add() they driver may only modify the protocol_id and protocol_ops +// fields of the mx_device_t. + +mx_status_t device_add(mx_device_t* device, mx_device_t* parent); +mx_status_t device_remove(mx_device_t* device); + +// Devices are bindable by drivers by default. +// This can be used to prevent a device from being bound by a driver +void device_set_bindable(mx_device_t* dev, bool bindable); + +void driver_add(mx_driver_t* driver); +void driver_remove(mx_driver_t* driver); + +// Protocol Identifiers +#define MX_PROTOCOL_DEVICE 'pDEV' +#define MX_PROTOCOL_CHAR 'pCHR' +#define MX_PROTOCOL_CONSOLE 'pCON' +#define MX_PROTOCOL_DISPLAY 'pDIS' +#define MX_PROTOCOL_FB 'pFBU' +#define MX_PROTOCOL_PCI 'pPCI' +#define MX_PROTOCOL_USB_HCI 'pHCI' +#define MX_PROTOCOL_USB_BUS 'pUBS' +#define MX_PROTOCOL_USB_HUB 'pHUB' +#define MX_PROTOCOL_USB_DEVICE 'pUDV' +#define MX_PROTOCOL_ETHERNET 'pETH' +#define MX_PROTOCOL_BLUETOOTH_HCI 'pBTH' + +#define BUILTIN_DRIVER __ALIGNED(sizeof(void*)) __SECTION("builtin_drivers") diff --git a/system/ulib/ddk/include/ddk/io_alloc.h b/system/ulib/ddk/include/ddk/io_alloc.h new file mode 100644 index 000000000..a9784275c --- /dev/null +++ b/system/ulib/ddk/include/ddk/io_alloc.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +typedef struct io_alloc io_alloc_t; + +io_alloc_t* io_alloc_init(size_t size); +void io_alloc_free(io_alloc_t* ioa); + +void* io_malloc(io_alloc_t* ioa, size_t size); +void* io_calloc(io_alloc_t* ioa, size_t count, size_t size); +void* io_memalign(io_alloc_t* ioa, size_t align, size_t size); +void io_free(io_alloc_t* ioa, void* ptr); +mx_paddr_t io_virt_to_phys(io_alloc_t* ioa, mx_vaddr_t virt_addr); +mx_vaddr_t io_phys_to_virt(io_alloc_t* ioa, mx_paddr_t phys_addr); diff --git a/system/ulib/ddk/include/ddk/protocol/bluetooth_hci.h b/system/ulib/ddk/include/ddk/protocol/bluetooth_hci.h new file mode 100644 index 000000000..65b51f95b --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/bluetooth_hci.h @@ -0,0 +1,24 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +typedef struct bluetooth_hci_protocol { + // returns message pipe for command & event packets + mx_handle_t (* get_control_pipe)(mx_device_t* device); + // returns message pipe for ACL data + mx_handle_t (* get_acl_pipe)(mx_device_t* device); +} bluetooth_hci_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/char.h b/system/ulib/ddk/include/ddk/protocol/char.h new file mode 100644 index 000000000..d8260af96 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/char.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +typedef struct mx_protocol_char { + ssize_t (*read)(mx_device_t *dev, void *buf, size_t count); + ssize_t (*write)(mx_device_t *dev, const void *buf, size_t count); + ssize_t (*ioctl)(mx_device_t *dev, uint32_t op, + const void *in_buf, size_t in_len, + void *out_buf, size_t out_len); +} mx_protocol_char_t; diff --git a/system/ulib/ddk/include/ddk/protocol/console.h b/system/ulib/ddk/include/ddk/protocol/console.h new file mode 100644 index 000000000..02aa199da --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/console.h @@ -0,0 +1,49 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +/** + * protocol/console.h - console protocol definitions + */ + +#define MX_CONSOLE_FLAG_BLOCKING 1 +// readkey does not return until a key is available + +typedef struct mx_protocol_console { + mx_handle_t (*getsurface)(mx_device_t* dev, uint32_t* width, uint32_t* height); + // returns a vmo pointing to an array of uint16_t's. + + void (*invalidate)(mx_device_t* dev, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + // invalidates an area in the surface + + void (*movecursor)(mx_device_t* dev, uint32_t x, uint32_t y, bool visible); + // moves/hides/shows the cursor + + void (*setpalette)(mx_device_t* dev, uint32_t colors[16]); + // install a new map of 16 XXRRGGBB values + + mx_status_t (*readkey)(mx_device_t* dev, uint32_t flags); +} mx_protocol_console_t; + + +#define CONSOLE_OP_GET_DIMENSIONS 1 + +typedef struct { + uint32_t width; + uint32_t height; +} ioctl_console_dimensions_t; \ No newline at end of file diff --git a/system/ulib/ddk/include/ddk/protocol/display.h b/system/ulib/ddk/include/ddk/protocol/display.h new file mode 100644 index 000000000..46cd0912e --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/display.h @@ -0,0 +1,55 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +/** + * protocol/display.h - display protocol definitions + */ + +#define MX_DISPLAY_FORMAT_NONE (-1) +#define MX_DISPLAY_FORMAT_RGB_565 (0) +#define MX_DISPLAY_FORMAT_RGB_332 (1) +#define MX_DISPLAY_FORMAT_RGB_2220 (2) +#define MX_DISPLAY_FORMAT_ARGB_8888 (3) +#define MX_DISPLAY_FORMAT_RGB_x888 (4) +#define MX_DISPLAY_FORMAT_MONO_1 (5) +#define MX_DISPLAY_FORMAT_MONO_8 (6) + +#define MX_DISPLAY_FLAG_HW_FRAMEBUFFER (1<<0) + +typedef struct mx_display_info { + uint format; + int width; + int height; + int stride; + uint flags; +} mx_display_info_t; + +typedef struct mx_display_protocol { + mx_status_t (*set_mode)(mx_device_t* dev, mx_display_info_t *info); + // sets the display mode + + mx_status_t (*get_mode)(mx_device_t* dev, mx_display_info_t *info); + // gets the display mode + + mx_status_t (*get_framebuffer)(mx_device_t* dev, void** framebuffer); + // gets a pointer to the framebuffer + + void (*flush)(mx_device_t* dev); + // flushes the framebuffer +} mx_display_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/ethernet.h b/system/ulib/ddk/include/ddk/protocol/ethernet.h new file mode 100644 index 000000000..5c93af7a4 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/ethernet.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +typedef struct ethernet_protocol { + mx_status_t (*send)(mx_device_t* device, const void* buffer, size_t length); + // returns length received, or error + mx_status_t (*recv)(mx_device_t* device, void* buffer, size_t length); + mx_status_t (*get_mac_addr)(mx_device_t* device, uint8_t* out_addr); + mx_status_t (*is_online)(mx_device_t* device); + size_t (*get_mtu)(mx_device_t* device); +} ethernet_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/fb.h b/system/ulib/ddk/include/ddk/protocol/fb.h new file mode 100644 index 000000000..44bb056cc --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/fb.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +/** + * protocol/fb.h - framebuffer protocol definitions + */ + +typedef struct mx_fb_protocol { + // tbd +} mx_fb_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/i2c.h b/system/ulib/ddk/include/ddk/protocol/i2c.h new file mode 100644 index 000000000..b88f7d73e --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/i2c.h @@ -0,0 +1,62 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +enum { + I2C_BUS_ADD_SLAVE = 0, + I2C_BUS_REMOVE_SLAVE = 1, + I2C_BUS_SET_FREQUENCY = 2, + + I2C_SLAVE_TRANSFER = 3, +}; + +enum { + I2C_7BIT_ADDRESS = 7, + I2C_10BIT_ADDRESS = 10, +}; + +typedef struct i2c_ioctl_add_slave_args +{ + uint8_t chip_address_width; + uint16_t chip_address; +} i2c_ioctl_add_slave_args_t; + +typedef struct i2c_ioctl_remove_slave_args +{ + uint8_t chip_address_width; + uint16_t chip_address; +} i2c_ioctl_remove_slave_args_t; + +typedef struct i2c_ioctl_set_bus_frequency_args +{ + uint32_t frequency; +} i2c_ioctl_set_bus_frequency_args_t; + + +typedef struct i2c_slave_ioctl_segment +{ + int read; + int len; + uint8_t buf[]; +} i2c_slave_ioctl_segment_t; + +typedef struct i2c_slave_segment +{ + int read; + int len; + uint8_t *buf; +} i2c_slave_segment_t; diff --git a/system/ulib/ddk/include/ddk/protocol/keyboard.h b/system/ulib/ddk/include/ddk/protocol/keyboard.h new file mode 100644 index 000000000..becc2efb7 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/keyboard.h @@ -0,0 +1,113 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +// Keyboard devices implement the char protocol and send key_event_t's for each keystroke. +// TODO don't use the char protocol when it's possible to wait on non char devices. + +// extended keys that aren't pure ascii +enum { + MX_KEY_RETURN = 0x80, + MX_KEY_ESC, + MX_KEY_LSHIFT, + MX_KEY_RSHIFT, + MX_KEY_LCTRL, + MX_KEY_RCTRL, + MX_KEY_LALT, + MX_KEY_RALT, + MX_KEY_CAPSLOCK, + MX_KEY_LWIN, + MX_KEY_RWIN, + MX_KEY_MENU, + MX_KEY_F1, + MX_KEY_F2, + MX_KEY_F3, + MX_KEY_F4, + MX_KEY_F5, + MX_KEY_F6, + MX_KEY_F7, + MX_KEY_F8, + MX_KEY_F9, + MX_KEY_F10, + MX_KEY_F11, + MX_KEY_F12, + MX_KEY_F13, + MX_KEY_F14, + MX_KEY_F15, + MX_KEY_F16, + MX_KEY_F17, + MX_KEY_F18, + MX_KEY_F19, + MX_KEY_F20, + MX_KEY_PRTSCRN, + MX_KEY_SCRLOCK, + MX_KEY_PAUSE, + MX_KEY_TAB, + MX_KEY_BACKSPACE, + MX_KEY_INS, + MX_KEY_DEL, + MX_KEY_HOME, + MX_KEY_END, + MX_KEY_PGUP, + MX_KEY_PGDN, + MX_KEY_ARROW_UP, + MX_KEY_ARROW_DOWN, + MX_KEY_ARROW_LEFT, + MX_KEY_ARROW_RIGHT, + MX_KEY_PAD_NUMLOCK, + MX_KEY_PAD_DIVIDE, + MX_KEY_PAD_MULTIPLY, + MX_KEY_PAD_MINUS, + MX_KEY_PAD_PLUS, + MX_KEY_PAD_ENTER, + MX_KEY_PAD_PERIOD, + MX_KEY_PAD_0, + MX_KEY_PAD_1, + MX_KEY_PAD_2, + MX_KEY_PAD_3, + MX_KEY_PAD_4, + MX_KEY_PAD_5, + MX_KEY_PAD_6, + MX_KEY_PAD_7, + MX_KEY_PAD_8, + MX_KEY_PAD_9, + + _MX_KEY_LAST, +} extended_keys; + + +typedef struct mx_key_event { + uint keycode; + int pressed; +} mx_key_event_t; + +// simple keyboard input queue + +#define FIFOSIZE 256 +#define FIFOMASK (FIFOSIZE - 1) + +typedef struct mx_key_fifo { + mx_key_event_t events[FIFOSIZE]; + uint32_t head; + uint32_t tail; + mxr_mutex_t lock; +} mx_key_fifo_t; + +mx_status_t mx_key_fifo_peek(mx_key_fifo_t* fifo, mx_key_event_t** out); +mx_status_t mx_key_fifo_read(mx_key_fifo_t* fifo, mx_key_event_t* out); +mx_status_t mx_key_fifo_write(mx_key_fifo_t* fifo, mx_key_event_t* ev); diff --git a/system/ulib/ddk/include/ddk/protocol/pci.h b/system/ulib/ddk/include/ddk/protocol/pci.h new file mode 100644 index 000000000..1facfea52 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/pci.h @@ -0,0 +1,40 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +/** + * protocols/pci.h - PCI protocol definitions + * + * The PCI host driver publishes mx_device_t's with its config set to a pci_device_config_t. + */ + +typedef struct pci_protocol { + mx_status_t (*claim_device)(mx_device_t* dev); + mx_handle_t (*map_mmio)(mx_device_t* dev, + uint32_t bar_num, + mx_cache_policy_t cache_policy, + void** vaddr, + uint64_t* size); + mx_status_t (*enable_bus_master)(mx_device_t* dev, bool enable); + mx_status_t (*reset_device)(mx_device_t* dev); + mx_handle_t (*map_interrupt)(mx_device_t* dev, int which_irq); + mx_status_t (*pci_wait_interrupt)(mx_handle_t handle); + mx_handle_t (*get_config)(mx_device_t* dev, const pci_config_t** config); +} pci_protocol_t; + +extern pci_protocol_t _pci_protocol; diff --git a/system/ulib/ddk/include/ddk/protocol/usb_bus.h b/system/ulib/ddk/include/ddk/protocol/usb_bus.h new file mode 100644 index 000000000..d6839c0b3 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/usb_bus.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +typedef struct usb_bus_protocol { + mx_device_t* (*attach_device)(mx_device_t* busdev, mx_device_t* hubdev, int hubaddress, int port, + usb_speed speed); + void (*detach_device)(mx_device_t* busdev, mx_device_t* dev); + void (*root_hub_port_changed)(mx_device_t* busdev, int port); + +} usb_bus_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/usb_device.h b/system/ulib/ddk/include/ddk/protocol/usb_device.h new file mode 100644 index 000000000..7af8e239a --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/usb_device.h @@ -0,0 +1,87 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +typedef int direction_t; +typedef int endpoint_type; + +typedef enum { + FULL_SPEED = 0, + LOW_SPEED = 1, + HIGH_SPEED = 2, + SUPER_SPEED = 3, +} usb_speed; + +typedef struct usb_endpoint { + usb_endpoint_descriptor_t* descriptor; + int endpoint; + direction_t direction; + int toggle; + int maxpacketsize; + endpoint_type type; + int interval; /* expressed as binary logarithm of the number + of microframes (i.e. t = 125us * 2^interval) */ +} usb_endpoint_t; + +typedef struct usb_interface { + usb_interface_descriptor_t* descriptor; + struct usb_interface* alt_interfaces; + int num_alt_interfaces; + usb_endpoint_t* endpoints; + int num_endpoints; +} usb_interface_t; + +typedef struct usb_configuration { + usb_configuration_descriptor_t* descriptor; + usb_interface_t* interfaces; + int num_interfaces; +} usb_configuration_t; + +typedef struct usb_device_config { + usb_device_descriptor_t* descriptor; + usb_configuration_t* configurations; + int num_configurations; +} usb_device_config_t; + +typedef struct usb_request { + uint8_t* buffer; // pointer to DMA memory + uint16_t buffer_length; // size of DMA buffer + uint16_t transfer_length; // number of bytes to transfer + mx_status_t status; + void (*complete_cb)(struct usb_request* request); + usb_endpoint_t* endpoint; + void* client_data; // for client use + void* driver_data; // for driver use + + // node can be used by client when request is not queued + list_node_t node; +} usb_request_t; + +typedef struct usb_device_protocol { + usb_request_t* (*alloc_request)(mx_device_t* dev, usb_endpoint_t* ep, uint16_t length); + void (*free_request)(mx_device_t* dev, usb_request_t* request); + + mx_status_t (*queue_request)(mx_device_t* dev, usb_request_t* request); + mx_status_t (*control)(mx_device_t* dev, uint8_t request_type, uint8_t request, uint16_t value, + uint16_t index, void* data, uint16_t length); + + mx_status_t (*get_config)(mx_device_t* dev, usb_device_config_t** config); + usb_speed (*get_speed)(mx_device_t* device); + int (*get_address)(mx_device_t* device); +} usb_device_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/usb_hci.h b/system/ulib/ddk/include/ddk/protocol/usb_hci.h new file mode 100644 index 000000000..0bb69ba20 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/usb_hci.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +typedef struct usb_hci_protocol { + usb_request_t* (*alloc_request)(mx_device_t* dev, uint16_t size); + void (*free_request)(mx_device_t* dev, usb_request_t* request); + + int (*queue_request)(mx_device_t* hcidev, int devaddr, usb_request_t* request); + int (*control)(mx_device_t* hcidev, int devaddr, usb_setup_t* devreq, int data_length, + uint8_t* data); + + /* set_address(): Tell the usb device its address + Also, allocate the usbdev structure, initialize enpoint 0 + (including MPS) and return its address. */ + int (*set_address)(mx_device_t* hcidev, usb_speed speed, int hubport, int hubaddr); + + /* finish_device_config(): Another hook for xHCI, returns 0 on success. */ + int (*finish_device_config)(mx_device_t* hcidev, int devaddr, usb_device_config_t* config); + + /* destroy_device(): Finally, destroy all structures that were allocated during set_address() + and finish_device_config(). */ + void (*destroy_device)(mx_device_t* hcidev, int devaddr); + + void (*set_bus_device)(mx_device_t* hcidev, mx_device_t* busdev); +} usb_hci_protocol_t; diff --git a/system/ulib/ddk/include/ddk/protocol/usb_hub.h b/system/ulib/ddk/include/ddk/protocol/usb_hub.h new file mode 100644 index 000000000..1d211eac0 --- /dev/null +++ b/system/ulib/ddk/include/ddk/protocol/usb_hub.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +typedef struct usb_hub_protocol { + /* returns 1 if the port's status changed since the last call */ + int (*port_status_changed)(mx_device_t* dev, int port); + /* returns 1 if something is connected to the port */ + int (*port_connected)(mx_device_t* dev, int port); + /* returns 1 if the port is enabled */ + int (*port_enabled)(mx_device_t* dev, int port); + /* returns speed if port is enabled, negative value if not */ + usb_speed (*port_speed)(mx_device_t* dev, int port); + + /* enables (powers up) a port (optional) */ + int (*enable_port)(mx_device_t* dev, int port); + /* disables (powers down) a port (optional) */ + int (*disable_port)(mx_device_t* dev, int port); + + /* performs a port reset (optional, generic implementations below) */ + int (*reset_port)(mx_device_t* dev, int port); + + int (*get_num_ports)(mx_device_t* dev); +} usb_hub_protocol_t; diff --git a/system/ulib/ddk/include/hw/inout.h b/system/ulib/ddk/include/hw/inout.h new file mode 100644 index 000000000..71bc1d5a4 --- /dev/null +++ b/system/ulib/ddk/include/hw/inout.h @@ -0,0 +1,71 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#if ARCH_X86 +static inline uint8_t inp(uint16_t _port) { + uint8_t rv; + __asm__ __volatile__ ("inb %1, %0" + : "=a" (rv) + : "d" (_port)); + return (rv); +} + +static inline uint16_t inpw (uint16_t _port) { + uint16_t rv; + __asm__ __volatile__ ("inw %1, %0" + : "=a" (rv) + : "d" (_port)); + return (rv); +} + +static inline uint32_t inpd(uint16_t _port) { + uint32_t rv; + __asm__ __volatile__ ("inl %1, %0" + : "=a" (rv) + : "d" (_port)); + return (rv); +} + +static inline void outp(uint16_t _port, uint8_t _data) { + __asm__ __volatile__ ("outb %1, %0" + : + : "d" (_port), + "a" (_data)); +} + +static inline void outpw(uint16_t _port, uint16_t _data) { + __asm__ __volatile__ ("outw %1, %0" + : + : "d" (_port), + "a" (_data)); +} + +static inline void outpd(uint16_t _port, uint32_t _data) { + __asm__ __volatile__ ("outl %1, %0" + : + : "d" (_port), + "a" (_data)); +} +#else +static inline uint8_t inp(uint16_t _port) { return 0; } +static inline uint16_t inpw (uint16_t _port) { return 0; } +static inline uint32_t inpd(uint16_t _port) { return 0; } +static inline void outp(uint16_t _port, uint8_t _data) { } +static inline void outpw(uint16_t _port, uint16_t _data) { } +static inline void outpd(uint16_t _port, uint32_t _data) { } +#endif diff --git a/system/ulib/ddk/include/hw/pci.h b/system/ulib/ddk/include/hw/pci.h new file mode 100644 index 000000000..58daadbe0 --- /dev/null +++ b/system/ulib/ddk/include/hw/pci.h @@ -0,0 +1,133 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +// clang-format off + +#include +#include +#include +#include +#include + +__BEGIN_CDECLS; + +/* + * PCI configuration space offsets + */ +#define PCI_CONFIG_VENDOR_ID 0x00 +#define PCI_CONFIG_DEVICE_ID 0x02 +#define PCI_CONFIG_COMMAND 0x04 +#define PCI_CONFIG_STATUS 0x06 +#define PCI_CONFIG_REVISION_ID 0x08 +#define PCI_CONFIG_CLASS_CODE 0x09 +#define PCI_CONFIG_CLASS_CODE_INTR 0x09 +#define PCI_CONFIG_CLASS_CODE_SUB 0x0a +#define PCI_CONFIG_CLASS_CODE_BASE 0x0b +#define PCI_CONFIG_CACHE_LINE_SIZE 0x0c +#define PCI_CONFIG_LATENCY_TIMER 0x0d +#define PCI_CONFIG_HEADER_TYPE 0x0e +#define PCI_CONFIG_BIST 0x0f +#define PCI_CONFIG_BASE_ADDRESSES 0x10 +#define PCI_CONFIG_CARDBUS_CIS_PTR 0x28 +#define PCI_CONFIG_SUBSYS_VENDOR_ID 0x2c +#define PCI_CONFIG_SUBSYS_ID 0x2e +#define PCI_CONFIG_EXP_ROM_ADDRESS 0x30 +#define PCI_CONFIG_CAPABILITIES 0x34 +#define PCI_CONFIG_INTERRUPT_LINE 0x3c +#define PCI_CONFIG_INTERRUPT_PIN 0x3d +#define PCI_CONFIG_MIN_GRANT 0x3e +#define PCI_CONFIG_MAX_LATENCY 0x3f + +/* + * PCI header type register bits + */ +#define PCI_HEADER_TYPE_MASK 0x7f +#define PCI_HEADER_TYPE_MULTI_FN 0x80 + +/* + * PCI header types + */ +#define PCI_HEADER_TYPE_STANDARD 0x00 +#define PCI_HEADER_TYPE_PCI_BRIDGE 0x01 +#define PCI_HEADER_TYPE_CARD_BUS 0x02 + +/* + * PCI command register bits + */ +#define PCI_COMMAND_IO_EN 0x0001 +#define PCI_COMMAND_MEM_EN 0x0002 +#define PCI_COMMAND_BUS_MASTER_EN 0x0004 +#define PCI_COMMAND_SPECIAL_EN 0x0008 +#define PCI_COMMAND_MEM_WR_INV_EN 0x0010 +#define PCI_COMMAND_PAL_SNOOP_EN 0x0020 +#define PCI_COMMAND_PERR_RESP_EN 0x0040 +#define PCI_COMMAND_AD_STEP_EN 0x0080 +#define PCI_COMMAND_SERR_EN 0x0100 +#define PCI_COMMAND_FAST_B2B_EN 0x0200 + +/* + * PCI status register bits + */ +#define PCI_STATUS_NEW_CAPS 0x0010 +#define PCI_STATUS_66_MHZ 0x0020 +#define PCI_STATUS_FAST_B2B 0x0080 +#define PCI_STATUS_MSTR_PERR 0x0100 +#define PCI_STATUS_DEVSEL_MASK 0x0600 +#define PCI_STATUS_TARG_ABORT_SIG 0x0800 +#define PCI_STATUS_TARG_ABORT_RCV 0x1000 +#define PCI_STATUS_MSTR_ABORT_RCV 0x2000 +#define PCI_STATUS_SERR_SIG 0x4000 +#define PCI_STATUS_PERR 0x8000 + +typedef struct { + uint16_t vendor_id; + uint16_t device_id; + uint16_t command; + uint16_t status; + uint8_t revision_id_0; + uint8_t program_interface; + uint8_t sub_class; + uint8_t base_class; + uint8_t cache_line_size; + uint8_t latency_timer; + uint8_t header_type; + uint8_t bist; + uint32_t base_addresses[6]; + uint32_t cardbus_cis_ptr; + uint16_t subsystem_vendor_id; + uint16_t subsystem_id; + uint32_t expansion_rom_address; + uint8_t capabilities_ptr; + uint8_t reserved_0[3]; + uint32_t reserved_1; + uint8_t interrupt_line; + uint8_t interrupt_pin; + uint8_t min_grant; + uint8_t max_latency; +} __PACKED pci_config_t; + +/* + * Endian independent PCIe register access helpers. + */ +static inline uint8_t pcie_read8 (const volatile uint8_t* reg) { return *reg; } +static inline uint16_t pcie_read16(const volatile uint16_t* reg) { return le16toh(*reg); } +static inline uint32_t pcie_read32(const volatile uint32_t* reg) { return le32toh(*reg); } + +static inline void pcie_write8 (volatile uint8_t* reg, uint8_t val) { *reg = val; } +static inline void pcie_write16(volatile uint16_t* reg, uint16_t val) { *reg = htole16(val); } +static inline void pcie_write32(volatile uint32_t* reg, uint32_t val) { *reg = htole32(val); } + +__END_CDECLS; diff --git a/system/ulib/ddk/include/hw/usb.h b/system/ulib/ddk/include/hw/usb.h new file mode 100644 index 000000000..dc736bb83 --- /dev/null +++ b/system/ulib/ddk/include/hw/usb.h @@ -0,0 +1,209 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +// clang-format off + +#include +#include + +__BEGIN_CDECLS; + +/* Request Types */ +#define USB_DIR_OUT (0 << 7) +#define USB_DIR_IN (1 << 7) +#define USB_DIR_MASK (1 << 7) +#define USB_TYPE_STANDARD (0 << 5) +#define USB_TYPE_CLASS (1 << 5) +#define USB_TYPE_VENDOR (2 << 5) +#define USB_TYPE_MASK (3 << 5) +#define USB_RECIP_DEVICE (0 << 0) +#define USB_RECIP_INTERFACE (1 << 0) +#define USB_RECIP_ENDPOINT (2 << 0) +#define USB_RECIP_OTHER (3 << 0) +#define USB_RECIP_MASK (0x1f << 0) + +/* 1.0 Request Values */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +/* USB device/interface classes */ +#define USB_CLASS_AUDIO 0x01 +#define USB_CLASS_COMM 0x02 +#define USB_CLASS_HID 0x03 +#define USB_CLASS_PHYSICAL 0x05 +#define USB_CLASS_IMAGING 0x06 +#define USB_CLASS_PRINTER 0x07 +#define USB_CLASS_MSC 0x08 +#define USB_CLASS_HUB 0x09 +#define USB_CLASS_CDC 0x0a +#define USB_CLASS_CCID 0x0b +#define USB_CLASS_SECURITY 0x0d +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_HEALTHCARE 0x0f +#define USB_CLASS_DIAGNOSTIC 0xdc +#define USB_CLASS_WIRELESS 0xe0 +#define USB_CLASS_MISC 0xef + +/* Mass storage requests */ +#define USB_MASS_STORAGE_GET_MAX_LUN 0xfe +#define USB_MASS_STORAGE_RESET 0xff + +/* HID Request Values */ +#define USB_HID_GET_REPORT 0x01 +#define USB_HID_GET_IDLE 0x02 +#define USB_HID_GET_PROTOCOL 0x03 +#define USB_HID_SET_REPORT 0x09 +#define USB_HID_SET_IDLE 0x0A +#define USB_HID_SET_PROTOCOL 0x0B + +/* Descriptor Types */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 +#define USB_DT_HID 0x21 +#define USB_DT_HIDREPORT 0x22 +#define USB_DT_HIDPHYSICAL 0x23 + +/* USB device feature selectors */ +#define USB_DEVICE_SELF_POWERED 0x00 +#define USB_DEVICE_REMOTE_WAKEUP 0x01 +#define USB_DEVICE_TEST_MODE 0x02 + +/* Endpoint direction (bEndpointAddress) */ +#define USB_ENDPOINT_IN 0x80 +#define USB_ENDPOINT_OUT 0x00 +#define USB_ENDPOINT_DIR_MASK 0x80 + +/* Endpoint types (bmAttributes) */ +#define USB_ENDPOINT_CONTROL 0x00 +#define USB_ENDPOINT_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_BULK 0x02 +#define USB_ENDPOINT_INTERRUPT 0x03 +#define USB_ENDPOINT_TYPE_MASK 0x03 + +#define USB_ENDPOINT_HALT 0x00 + +/* general USB defines */ +typedef struct { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__ ((packed)) usb_setup_t; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; +} __attribute__ ((packed)) descriptor_header_t; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} __attribute__ ((packed)) usb_device_descriptor_t; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} __attribute__ ((packed)) usb_configuration_descriptor_t; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} __attribute__ ((packed)) usb_interface_descriptor_t; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} __attribute__ ((packed)) usb_endpoint_descriptor_t; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bReportDescriptorType; + uint16_t wReportDescriptorLength; +} __attribute__ ((packed)) usb_hid_descriptor_t; + +typedef struct { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPowerOn2PwrGood; + uint8_t bHubContrCurrent; + union { + // USB 2.0 + struct { + // variable length depending on number of ports + uint8_t DeviceRemovable[4]; + uint8_t PortPwrCtrlMask[4]; + } __attribute__ ((packed)) hs; + // USB 3.0 + struct { + uint8_t bHubHdrDecLat; + uint16_t wHubDelay; + uint16_t DeviceRemovable; + } __attribute__ ((packed)) ss; + } __attribute__ ((packed)); +} __attribute__ ((packed)) usb_hub_descriptor_t; + +__END_CDECLS; diff --git a/system/ulib/ddk/io_alloc.c b/system/ulib/ddk/io_alloc.c new file mode 100644 index 000000000..f24289ab9 --- /dev/null +++ b/system/ulib/ddk/io_alloc.c @@ -0,0 +1,198 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#define MIN_ALIGN 8 + +// minimum total block size +#define MIN_BLOCK_SIZE 64 + +typedef struct io_block_header io_block_header_t; + +struct io_alloc { + void* phys; + void* virt; + size_t size; + intptr_t virt_offset; + mxr_mutex_t mutex; + io_block_header_t* free_list; +}; + +struct io_block_header { + // Allocated: pointer to beginning of block + // Free: pointer to next free block + io_block_header_t* ptr; + // total size of the block, including header and alignment padding + size_t size; +}; + +io_alloc_t* io_alloc_init(size_t size) { + io_alloc_t* ioa = calloc(1, sizeof(io_alloc_t)); + if (!ioa) + return NULL; + + ioa->mutex = MXR_MUTEX_INIT; + + void* phys; + void* virt; + mx_status_t status = _magenta_alloc_device_memory(size, &phys, &virt); + if (status) { + printf("_magenta_alloc_device_memory failed %d\n", status); + free(ioa); + return NULL; + } + + ioa->phys = phys; + ioa->virt = virt; + ioa->size = size; + ioa->virt_offset = (uintptr_t)virt - (uintptr_t)phys; + + io_block_header_t* free_list = virt; + free_list->size = size; + free_list->ptr = NULL; + ioa->free_list = free_list; + + return ioa; +} + +void io_alloc_free(io_alloc_t* ioa) { + // FIXME (voydanoff) no way to release memory allocated via _magenta_alloc_device_memory + free(ioa); +} + +void* io_malloc(io_alloc_t* ioa, size_t size) { + return io_memalign(ioa, MIN_ALIGN, size); +} + +void* io_calloc(io_alloc_t* ioa, size_t count, size_t size) { + size_t len = count * size; + void* result = io_memalign(ioa, MIN_ALIGN, len); + if (!result) + return NULL; + memset(result, 0, len); + return result; +} + +void* io_memalign(io_alloc_t* ioa, size_t align, size_t size) { + void* result = NULL; + + // align must be power of 2 + if ((align & -align) != align) { + printf("bad alignment %zu for io_memalign\n", align); + return NULL; + } + if (align < MIN_ALIGN) + align = MIN_ALIGN; + + mxr_mutex_lock(&ioa->mutex); + + io_block_header_t* block = ioa->free_list; + io_block_header_t* prev = NULL; + + while (block) { + size_t block_size = block->size; + + // compute aligned address past block header + uintptr_t ptr = (uintptr_t)block + sizeof(io_block_header_t); + ptr = (ptr + align - 1) & -align; + uintptr_t block_end = (uintptr_t)block + block_size; + size_t aligned_block_size = block_end - ptr; + + if (aligned_block_size >= size) { + // pull the block from the free list + if (prev) { + prev->ptr = block->ptr; + } else { + ioa->free_list = block->ptr; + } + + // new block header will be immediately before *ptr + io_block_header_t* header = &((io_block_header_t*)ptr)[-1]; + + // set ptr to point to beginning of block + header->ptr = block; + + if (aligned_block_size - size >= MIN_BLOCK_SIZE) { + // split our free block + + // next_block is pointer to remainder of the free block + uintptr_t next_block = ptr + size; + next_block = (next_block + MIN_ALIGN - 1) & -MIN_ALIGN; + + // newly allocated block size is next_block minus beginning of our free block + header->size = next_block - (uintptr_t)block; + + io_block_header_t* next_header = (io_block_header_t*)next_block; + next_header->size = block_end - next_block; + + // add remainder of block to free list + next_header->ptr = ioa->free_list; + ioa->free_list = next_header; + } else { + header->size = block_size; + } + + result = (void*)ptr; + break; + } + + prev = block; + block = block->ptr; + } + + mxr_mutex_unlock(&ioa->mutex); + + if (!result) + printf("OUT OF MEMORY!!!\n"); + return result; +} + +void io_free(io_alloc_t* ioa, void* ptr) { + if (!ptr) + return; + + assert(ptr > ioa->virt && ptr < ioa->virt + ioa->size); + + // block header is immediately before *ptr + io_block_header_t* header = &((io_block_header_t*)ptr)[-1]; + size_t size = header->size; + + // back up to beginning of block (might have been padded for alignment) + header = header->ptr; + header->size = size; + + mxr_mutex_lock(&ioa->mutex); + + // add to free list + // TODO (voydanoff) consider coalescing with previous and next block + header->ptr = ioa->free_list; + ioa->free_list = header; + + mxr_mutex_unlock(&ioa->mutex); +} + +mx_paddr_t io_virt_to_phys(io_alloc_t* ioa, mx_vaddr_t virt_addr) { + return virt_addr - ioa->virt_offset; +} + +mx_vaddr_t io_phys_to_virt(io_alloc_t* ioa, mx_paddr_t phys_addr) { + return phys_addr + ioa->virt_offset; +} diff --git a/system/ulib/ddk/protocol/keyboard.c b/system/ulib/ddk/protocol/keyboard.c new file mode 100644 index 000000000..c58651b74 --- /dev/null +++ b/system/ulib/ddk/protocol/keyboard.c @@ -0,0 +1,38 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +mx_status_t mx_key_fifo_peek(mx_key_fifo_t* fifo, mx_key_event_t** out) { + if (fifo->head == fifo->tail) return -1; + *out = &fifo->events[fifo->tail]; + return NO_ERROR; +} + +mx_status_t mx_key_fifo_read(mx_key_fifo_t* fifo, mx_key_event_t* out) { + if (fifo->head == fifo->tail) return -1; + if (out) memcpy(out, &fifo->events[fifo->tail], sizeof(mx_key_event_t)); + fifo->tail = (fifo->tail + 1) & FIFOMASK; + return NO_ERROR; +} + +mx_status_t mx_key_fifo_write(mx_key_fifo_t* fifo, mx_key_event_t* ev) { + uint32_t next = (fifo->head + 1) & FIFOMASK; + if (next != fifo->tail) { + memcpy(&fifo->events[fifo->head], ev, sizeof(mx_key_event_t)); + fifo->head = next; + } + return NO_ERROR; +} diff --git a/system/ulib/ddk/rules.mk b/system/ulib/ddk/rules.mk new file mode 100644 index 000000000..da854d29a --- /dev/null +++ b/system/ulib/ddk/rules.mk @@ -0,0 +1,31 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS += \ + $(LOCAL_DIR)/protocol/keyboard.c \ + $(LOCAL_DIR)/io_alloc.c + +MODULE_DEPS += \ + ulib/musl \ + ulib/magenta \ + ulib/mxu \ + ulib/runtime + +include make/module.mk diff --git a/system/ulib/font/BUILD.gn b/system/ulib/font/BUILD.gn new file mode 100644 index 000000000..6910aadb1 --- /dev/null +++ b/system/ulib/font/BUILD.gn @@ -0,0 +1,36 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_font_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("font") { + public_configs = [ ":_font_config" ] + public = [ + "include/font/font.h", + ] + sources = [ + "font.c", + "font.h", + ] + deps = [ + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] + public_deps = [ + "//system/ulib/gfx", + ] +} diff --git a/system/ulib/font/font.c b/system/ulib/font/font.c new file mode 100644 index 000000000..7c7df6fe9 --- /dev/null +++ b/system/ulib/font/font.c @@ -0,0 +1,52 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "font.h" + +#if SMALL_FONT +void font_draw_char(gfx_surface *surface, unsigned char c, + int x, int y, uint32_t color, uint32_t bgcolor) { + uint i,j; + uint line; + + // draw this char into a buffer + for (i = 0; i < FONT_Y; i++) { + line = FONT[c * (FONT_Y * 2) + (i * 2)]; + for (j = 0; j < FONT_X; j++) { + gfx_putpixel(surface, x + j, y + i, (line & 1) ? color : bgcolor); + line = line >> 2; + } + } +} +#else +void font_draw_char(gfx_surface *surface, unsigned char c, + int x, int y, uint32_t color, uint32_t bgcolor) { + uint i,j; + uint line; + + // draw this char into a buffer + for (i = 0; i < FONT_Y; i++) { + line = FONT[c * FONT_Y + i]; + for (j = 0; j < FONT_X; j++) { + gfx_putpixel(surface, x + j, y + i, (line & 1) ? color : bgcolor); + line = line >> 1; + } + } +} +#endif + diff --git a/system/ulib/font/font.h b/system/ulib/font/font.h new file mode 100644 index 000000000..945b2dfe5 --- /dev/null +++ b/system/ulib/font/font.h @@ -0,0 +1,528 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +static uint16_t FONT[] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3ffc, 0x3ffc, 0xc003, 0xc003, +0xcc33, 0xcc33, 0xc003, 0xc003, 0xc003, 0xc003, 0xcff3, 0xcff3, +0xc3c3, 0xc3c3, 0xc003, 0xc003, 0xc003, 0xc003, 0x3ffc, 0x3ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3ffc, 0x3ffc, 0xffff, 0xffff, +0xf3cf, 0xf3cf, 0xffff, 0xffff, 0xffff, 0xffff, 0xf00f, 0xf00f, +0xfc3f, 0xfc3f, 0xffff, 0xffff, 0xffff, 0xffff, 0x3ffc, 0x3ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0f3c, 0x0f3c, 0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x3fff, +0x3fff, 0x3fff, 0x0ffc, 0x0ffc, 0x03f0, 0x03f0, 0x00c0, 0x00c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x00c0, 0x00c0, 0x03f0, 0x03f0, 0x0ffc, 0x0ffc, 0x3fff, 0x3fff, +0x0ffc, 0x0ffc, 0x03f0, 0x03f0, 0x00c0, 0x00c0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, +0x0ff0, 0x0ff0, 0x0ff0, 0x0ff0, 0xfc3f, 0xfc3f, 0xfc3f, 0xfc3f, +0xfc3f, 0xfc3f, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, +0x0ff0, 0x0ff0, 0x3ffc, 0x3ffc, 0xffff, 0xffff, 0xffff, 0xffff, +0x3ffc, 0x3ffc, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0ff0, 0x0ff0, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, 0xfc3f, 0xfc3f, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0xfc3f, 0xfc3f, 0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, 0x300c, 0x300c, +0x300c, 0x300c, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xf00f, 0xf00f, 0xc3c3, 0xc3c3, 0xcff3, 0xcff3, +0xcff3, 0xcff3, 0xc3c3, 0xc3c3, 0xf00f, 0xf00f, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, +0x0000, 0x0000, 0x0000, 0x0000, 0x3fc0, 0x3fc0, 0x3f00, 0x3f00, +0x33c0, 0x33c0, 0x30f0, 0x30f0, 0x03fc, 0x03fc, 0x0f0f, 0x0f0f, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x03fc, 0x03fc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, +0x03c0, 0x03c0, 0x3ffc, 0x3ffc, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xfff0, 0xfff0, 0xf0f0, 0xf0f0, +0xfff0, 0xfff0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, +0x00f0, 0x00f0, 0x00fc, 0x00fc, 0x00ff, 0x00ff, 0x003f, 0x003f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xfffc, 0xfffc, 0xf03c, 0xf03c, +0xfffc, 0xfffc, 0xf03c, 0xf03c, 0xf03c, 0xf03c, 0xf03c, 0xf03c, +0xf03c, 0xf03c, 0xfc3c, 0xfc3c, 0xfc3f, 0xfc3f, 0x3c3f, 0x3c3f, +0x000f, 0x000f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0xf3cf, 0xf3cf, 0x0ff0, 0x0ff0, 0xfc3f, 0xfc3f, +0x0ff0, 0x0ff0, 0xf3cf, 0xf3cf, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0003, 0x0003, 0x000f, 0x000f, 0x003f, 0x003f, +0x00ff, 0x00ff, 0x03ff, 0x03ff, 0x3fff, 0x3fff, 0x03ff, 0x03ff, +0x00ff, 0x00ff, 0x003f, 0x003f, 0x000f, 0x000f, 0x0003, 0x0003, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3000, 0x3000, 0x3c00, 0x3c00, 0x3f00, 0x3f00, +0x3fc0, 0x3fc0, 0x3ff0, 0x3ff0, 0x3fff, 0x3fff, 0x3ff0, 0x3ff0, +0x3fc0, 0x3fc0, 0x3f00, 0x3f00, 0x3c00, 0x3c00, 0x3000, 0x3000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x3ffc, 0x3ffc, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x3ffc, 0x3ffc, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x0000, 0x0000, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xfffc, 0xfffc, 0xf3cf, 0xf3cf, +0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, 0xf3fc, 0xf3fc, 0xf3c0, 0xf3c0, +0xf3c0, 0xf3c0, 0xf3c0, 0xf3c0, 0xf3c0, 0xf3c0, 0xf3c0, 0xf3c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, 0x003c, 0x003c, +0x03f0, 0x03f0, 0x0f3c, 0x0f3c, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x0f3c, 0x0f3c, 0x03f0, 0x03f0, 0x0f00, 0x0f00, 0x3c0f, 0x3c0f, +0x0ffc, 0x0ffc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x3fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x3ffc, 0x3ffc, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x3ffc, 0x3ffc, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, 0x3ffc, 0x3ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x3ffc, 0x3ffc, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x3ffc, 0x3ffc, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x03c0, 0x03c0, 0x0f00, 0x0f00, 0x3fff, 0x3fff, +0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x00f0, 0x00f0, 0x003c, 0x003c, 0x3fff, 0x3fff, +0x003c, 0x003c, 0x00f0, 0x00f0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x000f, 0x000f, 0x000f, 0x000f, +0x000f, 0x000f, 0x3fff, 0x3fff, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0c30, 0x0c30, 0x3c3c, 0x3c3c, 0xffff, 0xffff, +0x3c3c, 0x3c3c, 0x0c30, 0x0c30, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x00c0, 0x00c0, 0x03f0, 0x03f0, 0x03f0, 0x03f0, 0x0ffc, 0x0ffc, +0x0ffc, 0x0ffc, 0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x3fff, 0x3fff, 0x3fff, 0x3fff, 0x0ffc, 0x0ffc, 0x0ffc, 0x0ffc, +0x03f0, 0x03f0, 0x03f0, 0x03f0, 0x00c0, 0x00c0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0ff0, 0x0ff0, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x0c30, 0x0c30, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f3c, 0x0f3c, +0x0f3c, 0x0f3c, 0x3fff, 0x3fff, 0x0f3c, 0x0f3c, 0x0f3c, 0x0f3c, +0x0f3c, 0x0f3c, 0x3fff, 0x3fff, 0x0f3c, 0x0f3c, 0x0f3c, 0x0f3c, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x300f, 0x300f, 0x000f, 0x000f, 0x0ffc, 0x0ffc, 0x3c00, 0x3c00, +0x3c00, 0x3c00, 0x3c03, 0x3c03, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x300f, 0x300f, 0x3c0f, 0x3c0f, 0x0f00, 0x0f00, 0x03c0, 0x03c0, +0x00f0, 0x00f0, 0x003c, 0x003c, 0x3c0f, 0x3c0f, 0x3c03, 0x3c03, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03f0, 0x03f0, 0x0f3c, 0x0f3c, +0x0f3c, 0x0f3c, 0x03f0, 0x03f0, 0x3cfc, 0x3cfc, 0x0fcf, 0x0fcf, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x3cfc, 0x3cfc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, +0x003c, 0x003c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0f00, 0x0f00, 0x03c0, 0x03c0, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x03c0, 0x03c0, 0x0f00, 0x0f00, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x00f0, 0x00f0, 0x03c0, 0x03c0, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x00f0, 0x00f0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0xffff, 0xffff, +0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x3ffc, 0x3ffc, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x00f0, 0x00f0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3fff, 0x3fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x3000, 0x3000, 0x3c00, 0x3c00, 0x0f00, 0x0f00, 0x03c0, 0x03c0, +0x00f0, 0x00f0, 0x003c, 0x003c, 0x000f, 0x000f, 0x0003, 0x0003, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, +0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, +0xf00f, 0xf00f, 0xf00f, 0xf00f, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03f0, 0x03f0, +0x03fc, 0x03fc, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x3ffc, 0x3ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c00, 0x3c00, 0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x00f0, 0x00f0, +0x003c, 0x003c, 0x000f, 0x000f, 0x3c0f, 0x3c0f, 0x3fff, 0x3fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x0ff0, 0x0ff0, 0x3c00, 0x3c00, +0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0f00, 0x0f00, 0x0fc0, 0x0fc0, +0x0ff0, 0x0ff0, 0x0f3c, 0x0f3c, 0x0f0f, 0x0f0f, 0x3fff, 0x3fff, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x3fc0, 0x3fc0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3fff, 0x3fff, 0x000f, 0x000f, +0x000f, 0x000f, 0x000f, 0x000f, 0x0fff, 0x0fff, 0x3c00, 0x3c00, +0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03f0, 0x03f0, 0x003c, 0x003c, +0x000f, 0x000f, 0x000f, 0x000f, 0x0fff, 0x0fff, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3fff, 0x3fff, 0x3c0f, 0x3c0f, +0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x0f00, 0x0f00, 0x03c0, 0x03c0, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3ffc, 0x3ffc, 0x3c00, 0x3c00, +0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x0f00, 0x0f00, 0x03fc, 0x03fc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x00f0, 0x00f0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x3c00, +0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x00f0, 0x00f0, 0x003c, 0x003c, +0x00f0, 0x00f0, 0x03c0, 0x03c0, 0x0f00, 0x0f00, 0x3c00, 0x3c00, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3ffc, 0x3ffc, 0x0000, 0x0000, 0x0000, 0x0000, +0x3ffc, 0x3ffc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x003c, 0x003c, +0x00f0, 0x00f0, 0x03c0, 0x03c0, 0x0f00, 0x0f00, 0x3c00, 0x3c00, +0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x00f0, 0x00f0, 0x003c, 0x003c, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3fcf, 0x3fcf, 0x3fcf, 0x3fcf, +0x3fcf, 0x3fcf, 0x0fcf, 0x0fcf, 0x000f, 0x000f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x00c0, 0x00c0, 0x03f0, 0x03f0, +0x0f3c, 0x0f3c, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3fff, 0x3fff, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0fff, 0x0fff, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ffc, 0x0ffc, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0fff, 0x0fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, +0x300f, 0x300f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, +0x000f, 0x000f, 0x300f, 0x300f, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03ff, 0x03ff, 0x0f3c, 0x0f3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0f3c, 0x0f3c, 0x03ff, 0x03ff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3fff, 0x3fff, 0x3c3c, 0x3c3c, +0x303c, 0x303c, 0x033c, 0x033c, 0x03fc, 0x03fc, 0x033c, 0x033c, +0x003c, 0x003c, 0x303c, 0x303c, 0x3c3c, 0x3c3c, 0x3fff, 0x3fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3fff, 0x3fff, 0x3c3c, 0x3c3c, +0x303c, 0x303c, 0x033c, 0x033c, 0x03fc, 0x03fc, 0x033c, 0x033c, +0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x00ff, 0x00ff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, +0x300f, 0x300f, 0x000f, 0x000f, 0x000f, 0x000f, 0x3fcf, 0x3fcf, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c3c, 0x3c3c, 0x33f0, 0x33f0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3fff, 0x3fff, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3fc0, 0x3fc0, 0x0f00, 0x0f00, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x03fc, 0x03fc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3c3f, 0x3c3f, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x0f3c, 0x0f3c, 0x03fc, 0x03fc, 0x03fc, 0x03fc, +0x0f3c, 0x0f3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3f, 0x3c3f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x00ff, 0x00ff, 0x003c, 0x003c, +0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, +0x003c, 0x003c, 0x303c, 0x303c, 0x3c3c, 0x3c3c, 0x3fff, 0x3fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xf00f, 0xf00f, 0xfc3f, 0xfc3f, +0xffff, 0xffff, 0xffff, 0xffff, 0xf3cf, 0xf3cf, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3c0f, 0x3c0f, 0x3c3f, 0x3c3f, +0x3cff, 0x3cff, 0x3fff, 0x3fff, 0x3fcf, 0x3fcf, 0x3f0f, 0x3f0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0fff, 0x0fff, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ffc, 0x0ffc, 0x003c, 0x003c, +0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x00ff, 0x00ff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3ccf, 0x3ccf, 0x3fcf, 0x3fcf, 0x0ffc, 0x0ffc, +0x0f00, 0x0f00, 0x3f00, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0fff, 0x0fff, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ffc, 0x0ffc, 0x0f3c, 0x0f3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3f, 0x3c3f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x003c, 0x003c, 0x03f0, 0x03f0, 0x0f00, 0x0f00, +0x3c00, 0x3c00, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xf3cf, 0xf3cf, +0xc3c3, 0xc3c3, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf3cf, 0xf3cf, +0xf3cf, 0xf3cf, 0xffff, 0xffff, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xf00f, 0xf00f, +0x3c03, 0x3c03, 0x0f00, 0x0f00, 0x03c0, 0x03c0, 0x00f0, 0x00f0, +0x003c, 0x003c, 0xc00f, 0xc00f, 0xf00f, 0xf00f, 0xffff, 0xffff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x00f0, 0x00f0, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0003, +0x000f, 0x000f, 0x003f, 0x003f, 0x00fc, 0x00fc, 0x03f0, 0x03f0, +0x0fc0, 0x0fc0, 0x3f00, 0x3f00, 0x3c00, 0x3c00, 0x3000, 0x3000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x0ff0, 0x0f00, 0x0f00, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x00c0, 0x00c0, 0x03f0, 0x03f0, 0x0f3c, 0x0f3c, 0x3c0f, 0x3c0f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x03c0, 0x03c0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x03fc, 0x03fc, 0x0f00, 0x0f00, 0x0ffc, 0x0ffc, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x3cfc, 0x3cfc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x003f, 0x003f, 0x003c, 0x003c, +0x003c, 0x003c, 0x03fc, 0x03fc, 0x0f3c, 0x0f3c, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, 0x000f, 0x000f, +0x000f, 0x000f, 0x000f, 0x000f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0fc0, 0x0fc0, 0x0f00, 0x0f00, +0x0f00, 0x0f00, 0x0ff0, 0x0ff0, 0x0f3c, 0x0f3c, 0x0f0f, 0x0f0f, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x3cfc, 0x3cfc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, 0x3fff, 0x3fff, +0x000f, 0x000f, 0x000f, 0x000f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03f0, 0x03f0, 0x0f3c, 0x0f3c, +0x0c3c, 0x0c3c, 0x003c, 0x003c, 0x00ff, 0x00ff, 0x003c, 0x003c, +0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x00ff, 0x00ff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3cfc, 0x3cfc, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0ffc, 0x0ffc, +0x0f00, 0x0f00, 0x0f0f, 0x0f0f, 0x03fc, 0x03fc, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x003f, 0x003f, 0x003c, 0x003c, +0x003c, 0x003c, 0x0f3c, 0x0f3c, 0x3cfc, 0x3cfc, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3f, 0x3c3f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x03f0, 0x03f0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x3c00, 0x3c00, 0x3c00, +0x0000, 0x0000, 0x3f00, 0x3f00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, +0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, 0x3c00, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x003f, 0x003f, 0x003c, 0x003c, +0x003c, 0x003c, 0x3c3c, 0x3c3c, 0x0f3c, 0x0f3c, 0x03fc, 0x03fc, +0x03fc, 0x03fc, 0x0f3c, 0x0f3c, 0x3c3c, 0x3c3c, 0x3c3f, 0x3c3f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03f0, 0x03f0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0ff0, 0x0ff0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3c3f, 0x3c3f, 0xffff, 0xffff, 0xf3cf, 0xf3cf, +0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0fcf, 0x0fcf, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0fcf, 0x0fcf, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, +0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x3c3c, 0x0ffc, 0x0ffc, +0x003c, 0x003c, 0x003c, 0x003c, 0x00ff, 0x00ff, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3cfc, 0x3cfc, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0ffc, 0x0ffc, +0x0f00, 0x0f00, 0x0f00, 0x0f00, 0x3fc0, 0x3fc0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0fcf, 0x0fcf, 0x3cfc, 0x3cfc, 0x3c3c, 0x3c3c, +0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x003c, 0x00ff, 0x00ff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0ffc, 0x0ffc, 0x3c0f, 0x3c0f, 0x003c, 0x003c, +0x03f0, 0x03f0, 0x0f00, 0x0f00, 0x3c0f, 0x3c0f, 0x0ffc, 0x0ffc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x00c0, 0x00c0, 0x00f0, 0x00f0, +0x00f0, 0x00f0, 0x0fff, 0x0fff, 0x00f0, 0x00f0, 0x00f0, 0x00f0, +0x00f0, 0x00f0, 0x00f0, 0x00f0, 0x3cf0, 0x3cf0, 0x0fc0, 0x0fc0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, +0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x3cfc, 0x3cfc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0xf00f, 0xf00f, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, 0xf00f, +0xf3cf, 0xf3cf, 0xf3cf, 0xf3cf, 0xffff, 0xffff, 0x3c3c, 0x3c3c, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0xf00f, 0xf00f, 0x3c3c, 0x3c3c, 0x0ff0, 0x0ff0, +0x03c0, 0x03c0, 0x0ff0, 0x0ff0, 0x3c3c, 0x3c3c, 0xf00f, 0xf00f, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3ffc, 0x3ffc, +0x3c00, 0x3c00, 0x0f00, 0x0f00, 0x03ff, 0x03ff, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3fff, 0x3fff, 0x0f0f, 0x0f0f, 0x03c0, 0x03c0, +0x00f0, 0x00f0, 0x003c, 0x003c, 0x3c0f, 0x3c0f, 0x3fff, 0x3fff, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3f00, 0x3f00, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x00fc, 0x00fc, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x3f00, 0x3f00, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x0000, 0x0000, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x00fc, 0x00fc, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x3f00, 0x3f00, 0x03c0, 0x03c0, +0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x03c0, 0x00fc, 0x00fc, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x3cfc, 0x3cfc, 0x0fcf, 0x0fcf, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x00c0, 0x00c0, 0x03f0, 0x03f0, 0x0f3c, 0x0f3c, 0x3c0f, 0x3c0f, +0x3c0f, 0x3c0f, 0x3c0f, 0x3c0f, 0x3fff, 0x3fff, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; diff --git a/system/ulib/font/include/font/font.h b/system/ulib/font/include/font/font.h new file mode 100644 index 000000000..a54a95d8e --- /dev/null +++ b/system/ulib/font/include/font/font.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __LIB_FONT_H +#define __LIB_FONT_H + +#include + +#define SMALL_FONT 1 + +#if SMALL_FONT +#define FONT_X 9 +#define FONT_Y 16 +#else +#define FONT_X 18 +#define FONT_Y 32 +#endif + +void font_draw_char(gfx_surface *surface, unsigned char c, int x, int y, uint32_t color, uint32_t bgcolor); + +#endif + diff --git a/system/ulib/font/rules.mk b/system/ulib/font/rules.mk new file mode 100644 index 000000000..4405073b4 --- /dev/null +++ b/system/ulib/font/rules.mk @@ -0,0 +1,30 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_HEADER_DEPS += \ + ulib/magenta \ + +MODULE_DEPS += \ + ulib/gfx \ + +MODULE_SRCS += \ + $(LOCAL_DIR)/font.c + +include make/module.mk diff --git a/system/ulib/gfx/BUILD.gn b/system/ulib/gfx/BUILD.gn new file mode 100644 index 000000000..442935660 --- /dev/null +++ b/system/ulib/gfx/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_gfx_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("gfx") { + public_configs = [ ":_gfx_config" ] + public = [ + "include/gfx/gfx.h", + ] + sources = [ + "gfx.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//system/ulib/mxu", + "//third_party/ulib/musl", + ] +} diff --git a/system/ulib/gfx/gfx.c b/system/ulib/gfx/gfx.c new file mode 100644 index 000000000..96efc5697 --- /dev/null +++ b/system/ulib/gfx/gfx.c @@ -0,0 +1,686 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @defgroup graphics Graphics + * + * @{ + */ + +/** + * @file + * @brief Graphics drawing library + */ +#include + +#include +#include +#include +#include +#include +#include + +#define TRACE 0 + +#if TRACE +#define xprintf(fmt...) printf(fmt) +#else +#define xprintf(fmt...) \ + do { \ + } while (0) +#endif + +// Convert a 32bit ARGB image to its respective gamma corrected grayscale value. +static uint32_t ARGB8888_to_Luma(uint32_t in) +{ + uint8_t out; + + uint32_t blue = (in & 0xFF) * 74; + uint32_t green = ((in >> 8) & 0xFF) * 732; + uint32_t red = ((in >> 16) & 0xFF) * 218; + + uint32_t intensity = red + blue + green; + + out = (intensity >> 10) & 0xFF; + + return out; +} + +static uint32_t ARGB8888_to_RGB565(uint32_t in) +{ + uint16_t out; + + out = (in >> 3) & 0x1f; // b + out |= ((in >> 10) & 0x3f) << 5; // g + out |= ((in >> 19) & 0x1f) << 11; // r + + return out; +} + +static uint32_t ARGB8888_to_RGB332(uint32_t in) +{ + uint8_t out = 0; + + out = (in >> 6) & 0x3; // b + out |= ((in >> 13) & 0x7) << 2; // g + out |= ((in >> 21) & 0x7) << 5; // r + + return out; +} + +static uint32_t ARGB8888_to_RGB2220(uint32_t in) +{ + uint8_t out = 0; + + out = ((in >> 6) & 0x3) << 2; + out |= ((in >> 14) & 0x3) << 4; + out |= ((in >> 22) & 0x3) << 6; + + return out; +} + +/** + * @brief Copy a rectangle of pixels from one part of the display to another. + */ +void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // trim + if (x >= surface->width) + return; + if (x2 >= surface->width) + return; + if (y >= surface->height) + return; + if (y2 >= surface->height) + return; + if (width == 0 || height == 0) + return; + + // clip the width to src or dest + if (x + width > surface->width) + width = surface->width - x; + if (x2 + width > surface->width) + width = surface->width - x2; + + // clip the height to src or dest + if (y + height > surface->height) + height = surface->height - y; + if (y2 + height > surface->height) + height = surface->height - y2; + + surface->copyrect(surface, x, y, width, height, x2, y2); +} + +/** + * @brief Fill a rectangle on the screen with a constant color. + */ +void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + xprintf("surface %p, x %u y %u w %u h %u c %u\n", surface, x, y, width, height, color); + // trim + if (unlikely(x >= surface->width)) + return; + if (y >= surface->height) + return; + if (width == 0 || height == 0) + return; + + // clip the width + if (x + width > surface->width) + width = surface->width - x; + + // clip the height + if (y + height > surface->height) + height = surface->height - y; + + surface->fillrect(surface, x, y, width, height, color); +} + +/** + * @brief Write a single pixel to the screen. + */ +void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color) +{ + if (unlikely(x >= surface->width)) + return; + if (y >= surface->height) + return; + + surface->putpixel(surface, x, y, color); +} + +static void putpixel16(gfx_surface *surface, uint x, uint y, uint color) +{ + uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride]; + + // colors come in in ARGB 8888 form, flatten them + *dest = (uint16_t)(surface->translate_color(color)); +} + +static void putpixel32(gfx_surface *surface, uint x, uint y, uint color) +{ + uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride]; + + *dest = color; +} + +static void putpixel8(gfx_surface *surface, uint x, uint y, uint color) +{ + uint8_t *dest = &((uint8_t *)surface->ptr)[x + y * surface->stride]; + + // colors come in in ARGB 8888 form, flatten them + *dest = (uint8_t)(surface->translate_color(color)); +} + +static void copyrect8(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // copy + const uint8_t *src = &((const uint8_t *)surface->ptr)[x + y * surface->stride]; + uint8_t *dest = &((uint8_t *)surface->ptr)[x2 + y2 * surface->stride]; + uint stride_diff = surface->stride - width; + + if (dest < src) { + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += stride_diff; + src += stride_diff; + } + } else { + // copy backwards + src += height * surface->stride + width; + dest += height * surface->stride + width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest--; + src--; + } + dest -= stride_diff; + src -= stride_diff; + } + } +} + +static void fillrect8(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + uint8_t *dest = &((uint8_t *)surface->ptr)[x + y * surface->stride]; + uint stride_diff = surface->stride - width; + + uint8_t color8 = (uint8_t)(surface->translate_color(color)); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = color8; + dest++; + } + dest += stride_diff; + } +} + +static void copyrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // copy + const uint16_t *src = &((const uint16_t *)surface->ptr)[x + y * surface->stride]; + uint16_t *dest = &((uint16_t *)surface->ptr)[x2 + y2 * surface->stride]; + uint stride_diff = surface->stride - width; + + if (dest < src) { + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += stride_diff; + src += stride_diff; + } + } else { + // copy backwards + src += height * surface->stride + width; + dest += height * surface->stride + width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest--; + src--; + } + dest -= stride_diff; + src -= stride_diff; + } + } +} + +static void fillrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride]; + uint stride_diff = surface->stride - width; + + uint16_t color16 = (uint16_t)(surface->translate_color(color)); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = color16; + dest++; + } + dest += stride_diff; + } +} + +static void copyrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) +{ + // copy + const uint32_t *src = &((const uint32_t *)surface->ptr)[x + y * surface->stride]; + uint32_t *dest = &((uint32_t *)surface->ptr)[x2 + y2 * surface->stride]; + uint stride_diff = surface->stride - width; + + if (dest < src) { + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += stride_diff; + src += stride_diff; + } + } else { + // copy backwards + src += height * surface->stride + width; + dest += height * surface->stride + width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest--; + src--; + } + dest -= stride_diff; + src -= stride_diff; + } + } +} + +static void fillrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) +{ + uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride]; + uint stride_diff = surface->stride - width; + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = color; + dest++; + } + dest += stride_diff; + } +} + +void gfx_line(gfx_surface *surface, uint x1, uint y1, uint x2, uint y2, uint color) +{ + if (unlikely(x1 >= surface->width)) + return; + if (unlikely(x2 >= surface->width)) + return; + + if (y1 >= surface->height) + return; + if (y2 >= surface->height) + return; + + int dx = x2 - x1; + int dy = y2 - y1; + + int sdx = (0 < dx) - (dx < 0); + int sdy = (0 < dy) - (dy < 0); + + uint dxabs = (dx > 0) ? dx : -dx; + uint dyabs = (dy > 0) ? dy : -dy; + + uint x = dyabs >> 1; + uint y = dxabs >> 1; + + uint px = x1; + uint py = y1; + + if (dxabs >= dyabs) { + // mostly horizontal line. + for (uint i = 0; i < dxabs; i++) { + y += dyabs; + if (y >= dxabs) { + y -= dxabs; + py += sdy; + } + px += sdx; + surface->putpixel(surface, px, py, color); + } + } else { + // mostly vertical line. + for (uint i = 0; i < dyabs; i++) { + x += dxabs; + if (x >= dyabs) { + x -= dyabs; + px += sdx; + } + py += sdy; + surface->putpixel(surface, px, py, color); + } + } +} + +uint32_t alpha32_add_ignore_destalpha(uint32_t dest, uint32_t src) +{ + uint32_t cdest[3]; + uint32_t csrc[3]; + + uint32_t srca; + uint32_t srcainv; + + srca = (src >> 24) & 0xff; + if (srca == 0) { + return dest; + } else if (srca == 255) { + return src; + } + srca++; + srcainv = (255 - srca); + + cdest[0] = (dest >> 16) & 0xff; + cdest[1] = (dest >> 8) & 0xff; + cdest[2] = (dest >> 0) & 0xff; + + csrc[0] = (src >> 16) & 0xff; + csrc[1] = (src >> 8) & 0xff; + csrc[2] = (src >> 0) & 0xff; + +// if (srca > 0) +// printf("s %d %d %d d %d %d %d a %d ai %d\n", csrc[0], csrc[1], csrc[2], cdest[0], cdest[1], cdest[2], srca, srcainv); + + uint32_t cres[3]; + + cres[0] = ((csrc[0] * srca) / 256) + ((cdest[0] * srcainv) / 256); + cres[1] = ((csrc[1] * srca) / 256) + ((cdest[1] * srcainv) / 256); + cres[2] = ((csrc[2] * srca) / 256) + ((cdest[2] * srcainv) / 256); + + return (srca << 24) | (cres[0] << 16) | (cres[1] << 8) | (cres[2]); +} + +/** + * @brief Copy pixels from source to dest. + * + * Currently does not support alpha channel. + */ +void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty) { + gfx_blend(target, source, 0, 0, source->width, source->height, destx, desty); +} + +/** + * @brief Copy pixels from source to dest. + */ +void gfx_blend(gfx_surface* target, gfx_surface* source, uint srcx, uint srcy, uint width, uint height, uint destx, uint desty) { + assert(target->format == source->format); + + xprintf("target %p, source %p, srcx %u, srcy %u, width %u, height %u, destx %u, desty %u\n", target, source, srcx, srcy, width, height, destx, desty); + + if (destx >= target->width) return; + if (desty >= target->height) return; + + if (srcx >= source->width) return; + if (srcy >= source->height) return; + + if (destx + width > target->width) width = target->width - destx; + if (desty + height > target->height) height = target->height - desty; + + if (srcx + width > source->width) width = source->width - srcx; + if (srcy + height > source->height) height = source->height - srcy; + + // XXX total hack to deal with various blends + if (source->format == GFX_FORMAT_RGB_565 && target->format == GFX_FORMAT_RGB_565) { + // 16 bit to 16 bit + const uint16_t *src = &((const uint16_t *)source->ptr)[srcx + srcy * source->stride]; + uint16_t *dest = &((uint16_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + xprintf("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else if (source->format == GFX_FORMAT_ARGB_8888 && target->format == GFX_FORMAT_ARGB_8888) { + // both are 32 bit modes, both alpha + const uint32_t *src = &((const uint32_t *)source->ptr)[srcx + srcy * source->stride]; + uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + xprintf("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + // XXX ignores destination alpha + *dest = alpha32_add_ignore_destalpha(*dest, *src); + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else if (source->format == GFX_FORMAT_RGB_x888 && target->format == GFX_FORMAT_RGB_x888) { + // both are 32 bit modes, no alpha + const uint32_t *src = &((const uint32_t *)source->ptr)[srcx + srcy * source->stride]; + uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + xprintf("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else if (source->format == GFX_FORMAT_MONO && target->format == GFX_FORMAT_MONO) { + // both are 8 bit modes, no alpha + const uint8_t *src = &((const uint8_t *)source->ptr)[srcx + srcy * source->stride]; + uint8_t *dest = &((uint8_t *)target->ptr)[destx + desty * target->stride]; + uint dest_stride_diff = target->stride - width; + uint source_stride_diff = source->stride - width; + + xprintf("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff); + + uint i, j; + for (i=0; i < height; i++) { + for (j=0; j < width; j++) { + *dest = *src; + dest++; + src++; + } + dest += dest_stride_diff; + src += source_stride_diff; + } + } else { + xprintf("gfx_surface_blend: unimplemented colorspace combination (source %d target %d)\n", source->format, target->format); + assert(0); + } +} + +/** + * @brief Ensure all graphics rendering is sent to display + */ +void gfx_flush(gfx_surface *surface) +{ +#if 0 + if (surface->flags & GFX_FLAG_FLUSH_CPU_CACHE) + arch_clean_cache_range((addr_t)surface->ptr, surface->len); +#endif + + if (surface->flush) + surface->flush(0, surface->height-1); +} + +/** + * @brief Ensure that a sub-region of the display is up to date. + */ +void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end) +{ + if (start > end) { + uint temp = start; + start = end; + end = temp; + } + + if (start >= surface->height) + return; + if (end >= surface->height) + end = surface->height - 1; + +#if 0 + if (surface->flags & GFX_FLAG_FLUSH_CPU_CACHE) { + uint32_t runlen = surface->stride * surface->pixelsize; + arch_clean_cache_range((addr_t)surface->ptr + start * runlen, (end - start + 1) * runlen); + } +#endif + + if (surface->flush) + surface->flush(start, end); +} + +/** + * @brief Create a new graphics surface object + */ +gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags) +{ + gfx_surface *surface = calloc(1, sizeof(*surface)); + if (surface == NULL) return NULL; + if (gfx_init_surface(surface, ptr, width, height, stride, format, flags)) { + free(surface); + return NULL; + } + return surface; +} + +int gfx_init_surface(gfx_surface *surface, void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags) +{ + assert(width > 0); + assert(height > 0); + assert(stride >= width); + assert(format < GFX_FORMAT_MAX); + + surface->flags = flags; + surface->format = format; + surface->width = width; + surface->height = height; + surface->stride = stride; + surface->alpha = MAX_ALPHA; + + // set up some function pointers + switch (format) { + case GFX_FORMAT_RGB_565: + surface->translate_color = &ARGB8888_to_RGB565; + surface->copyrect = ©rect16; + surface->fillrect = &fillrect16; + surface->putpixel = &putpixel16; + surface->pixelsize = 2; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_RGB_x888: + case GFX_FORMAT_ARGB_8888: + surface->translate_color = NULL; + surface->copyrect = ©rect32; + surface->fillrect = &fillrect32; + surface->putpixel = &putpixel32; + surface->pixelsize = 4; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_MONO: + surface->translate_color = &ARGB8888_to_Luma; + surface->copyrect = ©rect8; + surface->fillrect = &fillrect8; + surface->putpixel = &putpixel8; + surface->pixelsize = 1; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_RGB_332: + surface->translate_color = &ARGB8888_to_RGB332; + surface->copyrect = ©rect8; + surface->fillrect = &fillrect8; + surface->putpixel = &putpixel8; + surface->pixelsize = 1; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + case GFX_FORMAT_RGB_2220: + surface->translate_color = &ARGB8888_to_RGB2220; + surface->copyrect = ©rect8; + surface->fillrect = &fillrect8; + surface->putpixel = &putpixel8; + surface->pixelsize = 1; + surface->len = (surface->height * surface->stride * surface->pixelsize); + break; + default: + xprintf("invalid graphics format\n"); + return ERR_INVALID_ARGS; + } + + if (ptr == NULL) { + // allocate a buffer + ptr = malloc(surface->len); + if (ptr == NULL) { + return ERR_NO_MEMORY; + } + assert(ptr); + surface->flags |= GFX_FLAG_FREE_ON_DESTROY; + } + surface->ptr = ptr; + return 0; +} + +/** + * @brief Destroy a graphics surface and free all resources allocated to it. + * + * @param surface Surface to destroy. This pointer is no longer valid after + * this call. + */ +void gfx_surface_destroy(struct gfx_surface *surface) +{ + if (surface->flags & GFX_FLAG_FREE_ON_DESTROY) + free(surface->ptr); + free(surface); +} diff --git a/system/ulib/gfx/include/gfx/gfx.h b/system/ulib/gfx/include/gfx/gfx.h new file mode 100644 index 000000000..6b4faaa9e --- /dev/null +++ b/system/ulib/gfx/include/gfx/gfx.h @@ -0,0 +1,112 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +// gfx library + +// different graphics formats +typedef enum { + GFX_FORMAT_NONE, + GFX_FORMAT_RGB_565, + GFX_FORMAT_RGB_332, + GFX_FORMAT_RGB_2220, + GFX_FORMAT_ARGB_8888, + GFX_FORMAT_RGB_x888, + GFX_FORMAT_MONO, + + GFX_FORMAT_MAX +} gfx_format; + +#define MAX_ALPHA 255 + +// surface flags +#define GFX_FLAG_FREE_ON_DESTROY (1<<0) // free the ptr at destroy +#define GFX_FLAG_FLUSH_CPU_CACHE (1<<1) // do a cache flush during gfx_flush + +/** + * @brief Describe a graphics drawing surface + * + * The gfx_surface object represents a framebuffer that can be rendered + * to. Elements include a pointer to the actual pixel memory, its size, its + * layout, and pointers to basic drawing functions. + * + * @ingroup graphics + */ +typedef struct gfx_surface { + void *ptr; + uint32_t flags; + gfx_format format; + uint width; + uint height; + uint stride; + uint pixelsize; + size_t len; + uint alpha; + + // function pointers + uint32_t (*translate_color)(uint32_t input); + void (*copyrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint x2, uint y2); + void (*fillrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint color); + void (*putpixel)(struct gfx_surface *, uint x, uint y, uint color); + void (*flush)(uint starty, uint endy); +} gfx_surface; + +// copy a rect from x,y with width x height to x2, y2 +void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2); + +// fill a rect within the surface with a color +void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color); + +// draw a pixel at x, y in the surface +void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color); + +// draw a single pixel line between x1,y1 and x2,y1 +void gfx_line(gfx_surface *surface, uint x1, uint y1, uint x2, uint y2, uint color); + +// blend source surface to target surface +void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty); + +// blend an area from the source surface to the target surface +void gfx_blend(struct gfx_surface* target, struct gfx_surface* source, uint srcx, uint srcy, uint width, uint height, uint destx, uint desty); + +// ensure the surface is written back to memory and optionally backing store +void gfx_flush(struct gfx_surface *surface); + +// flush a subset of the surface +void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end); + +// clear the entire surface with a color +static inline void gfx_clear(gfx_surface *surface, uint color) +{ + surface->fillrect(surface, 0, 0, surface->width, surface->height, color); + gfx_flush(surface); +} + +// surface setup +gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags); +mx_status_t gfx_init_surface(gfx_surface *surface, void *ptr, uint width, uint height, uint stride, gfx_format format, uint32_t flags); + +// free the surface +// optionally frees the buffer if the free bit is set +void gfx_surface_destroy(struct gfx_surface *surface); + +// utility routine to fill the display with a little moire pattern +void gfx_draw_pattern(void); + diff --git a/system/ulib/gfx/rules.mk b/system/ulib/gfx/rules.mk new file mode 100644 index 000000000..bb02947ab --- /dev/null +++ b/system/ulib/gfx/rules.mk @@ -0,0 +1,34 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO fix to share this lib in user/kernel + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_DEPS := \ + ulib/ddk \ + ulib/magenta \ + ulib/mxu \ + +MODULE_HEADER_DEPS := \ + ulib/musl + +MODULE_SRCS += \ + $(LOCAL_DIR)/gfx.c + +include make/module.mk diff --git a/system/ulib/global/BUILD.gn b/system/ulib/global/BUILD.gn new file mode 100644 index 000000000..93838b629 --- /dev/null +++ b/system/ulib/global/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_global_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("global") { + public_configs = [ ":_global_config" ] + public = [ + "include/runtime/compiler.h", + ] +} diff --git a/system/ulib/global/include/runtime/compiler.h b/system/ulib/global/include/runtime/compiler.h new file mode 100644 index 000000000..ce6d2db6b --- /dev/null +++ b/system/ulib/global/include/runtime/compiler.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifndef __ASSEMBLY__ + +#if __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define __UNUSED __attribute__((__unused__)) +#define __PACKED __attribute__((packed)) +#define __ALIGNED(x) __attribute__((aligned(x))) +#define __PRINTFLIKE(__fmt,__varargs) __attribute__((__format__ (__printf__, __fmt, __varargs))) +#define __SCANFLIKE(__fmt,__varargs) __attribute__((__format__ (__scanf__, __fmt, __varargs))) +#define __SECTION(x) __attribute((section(x))) +#define __PURE __attribute((pure)) +#define __CONST __attribute((const)) +#define __NO_RETURN __attribute__((noreturn)) +#define __MALLOC __attribute__((malloc)) +#define __WEAK __attribute__((weak)) +#define __GNU_INLINE __attribute__((gnu_inline)) +#define __GET_CALLER(x) __builtin_return_address(0) +#define __GET_FRAME(x) __builtin_frame_address(0) +#define __NAKED __attribute__((naked)) +#define __ISCONSTANT(x) __builtin_constant_p(x) +#define __NO_INLINE __attribute((noinline)) +#define __SRAM __NO_INLINE __SECTION(".sram.text") +#define __CONSTRUCTOR __attribute__((constructor)) +#define __DESTRUCTOR __attribute__((destructor)) +#ifndef __clang__ +#define __OPTIMIZE(x) __attribute__((optimize(x))) +#else +#define __OPTIMIZE(x) +#endif +#endif + +#endif // __ASSEMBLY__ + +#define countof(a) (sizeof(a) / sizeof((a)[0])) + +// CPP header guards +#ifdef __cplusplus +#define __BEGIN_CDECLS extern "C" { +#define __END_CDECLS } +#else +#define __BEGIN_CDECLS +#define __END_CDECLS +#endif diff --git a/system/ulib/inet6/BUILD.gn b/system/ulib/inet6/BUILD.gn new file mode 100644 index 000000000..01ed3a0b6 --- /dev/null +++ b/system/ulib/inet6/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_inet6_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("inet6") { + public_configs = [ ":_inet6_config" ] + public = [ + "include/inet6/inet6.h", + "include/inet6/netifc.h", + ] + sources = [ + "inet6.c", + "netifc.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//third_party/ulib/musl", + ] +} diff --git a/system/ulib/inet6/include/inet6/inet6.h b/system/ulib/inet6/include/inet6/inet6.h new file mode 100644 index 000000000..4ba0f5289 --- /dev/null +++ b/system/ulib/inet6/include/inet6/inet6.h @@ -0,0 +1,198 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files +// (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, +// and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include + +typedef struct mac_addr_t mac_addr; +typedef struct ip6_addr_t ip6_addr; +typedef struct ip6_hdr_t ip6_hdr; +typedef struct udp_hdr_t udp_hdr; +typedef struct icmp6_hdr_t icmp6_hdr; +typedef struct ndp_n_hdr_t ndp_n_hdr; + +#define ETH_ADDR_LEN 6 +#define ETH_HDR_LEN 14 +#define ETH_MTU 1514 + +#define IP6_ADDR_LEN 16 +#define IP6_HDR_LEN 40 + +#define IP6_MIN_MTU 1280 + +#define UDP_HDR_LEN 8 + +struct mac_addr_t { + uint8_t x[ETH_ADDR_LEN]; +} __attribute__((packed)); + +struct ip6_addr_t { + uint8_t x[IP6_ADDR_LEN]; +} __attribute__((packed)); + +extern const ip6_addr ip6_ll_all_nodes; +extern const ip6_addr ip6_ll_all_routers; + +#define ETH_IP4 0x0800 +#define ETH_ARP 0x0806 +#define ETH_IP6 0x86DD + +#define HDR_HNH_OPT 0 +#define HDR_TCP 6 +#define HDR_UDP 17 +#define HDR_ROUTING 43 +#define HDR_FRAGMENT 44 +#define HDR_ICMP6 58 +#define HDR_NONE 59 +#define HDR_DST_OPT 60 + +struct ip6_hdr_t { + uint32_t ver_tc_flow; + uint16_t length; + uint8_t next_header; + uint8_t hop_limit; + uint8_t src[IP6_ADDR_LEN]; + uint8_t dst[IP6_ADDR_LEN]; +} __attribute__((packed)); + +struct udp_hdr_t { + uint16_t src_port; + uint16_t dst_port; + uint16_t length; + uint16_t checksum; +} __attribute__((packed)); + +#define ICMP6_DEST_UNREACHABLE 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAMETER_PROBLEM 4 + +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 + +#define ICMP6_NDP_N_SOLICIT 135 +#define ICMP6_NDP_N_ADVERTISE 136 + +struct icmp6_hdr_t { + uint8_t type; + uint8_t code; + uint16_t checksum; +} __attribute__((packed)); + +struct ndp_n_hdr_t { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint32_t flags; + uint8_t target[IP6_ADDR_LEN]; + uint8_t options[0]; +} __attribute__((packed)); + +#define NDP_N_SRC_LL_ADDR 1 +#define NDP_N_TGT_LL_ADDR 2 +#define NDP_N_PREFIX_INFO 3 +#define NDP_N_REDIRECTED_HDR 4 +#define NDP_N_MTU 5 + +#ifndef ntohs +#define ntohs(n) _swap16(n) +#define htons(n) _swap16(n) +static inline uint16_t _swap16(uint16_t n) { + return (n >> 8) | (n << 8); +} +#endif + +#ifndef ntohl +#define ntohl(n) _swap32(n) +#define htonl(n) _swap32(n) +static inline uint32_t _swap32(uint32_t n) { + return (n >> 24) | ((n >> 8) & 0xFF00) | + ((n & 0xFF00) << 8) | (n << 24); +} +#endif + +// Formats an IP6 address into the provided buffer (which must be +// at least IP6TOAMAX bytes in size), and returns the buffer address. +char* ip6toa(char* _out, void* ip6addr); +#define IP6TOAMAX 40 + +// provided by inet6.c +void ip6_init(void* macaddr); +void eth_recv(void* data, size_t len); + +// provided by interface driver +void* eth_get_buffer(size_t len); +void eth_put_buffer(void* ptr); +int eth_send(void* data, size_t len); +int eth_add_mcast_filter(const mac_addr* addr); + +// call to transmit a UDP packet +int udp6_send(const void* data, size_t len, + const ip6_addr* daddr, uint16_t dport, + uint16_t sport); + +// implement to recive UDP packets +void udp6_recv(void* data, size_t len, + const ip6_addr* daddr, uint16_t dport, + const ip6_addr* saddr, uint16_t sport); + +// NOTES +// +// This is an extremely minimal IPv6 stack, supporting just enough +// functionality to talk to link local hosts over UDP. +// +// It responds to ICMPv6 Neighbor Solicitations for its link local +// address, which is computed from the mac address provided by the +// ethernet interface driver. +// +// It responds to PINGs. +// +// It can only transmit to multicast addresses or to the address it +// last received a packet from (general usecase is to reply to a UDP +// packet from the UDP callback, which this supports) +// +// It does not currently do duplicate address detection, which is +// probably the most severe bug. +// +// It does not support any IPv6 options and will drop packets with +// options. +// +// It expects the network stack to provide transmit buffer allocation +// and free functionality. It will allocate a single transmit buffer +// from udp6_send() or icmp6_send() to fill out and either pass to the +// network stack via eth_send() or, in the event of an error, release +// via eth_put_buffer(). +// diff --git a/system/ulib/inet6/include/inet6/netifc.h b/system/ulib/inet6/include/inet6/netifc.h new file mode 100644 index 000000000..bafaa959d --- /dev/null +++ b/system/ulib/inet6/include/inet6/netifc.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +// setup networking +int netifc_open(void); + +// process inbound packet(s) +void netifc_poll(void); + +// return nonzero if interface exists +int netifc_active(void); + +// shut down networking +void netifc_close(void); + +// set a timer to expire after ms milliseconds +void netifc_set_timer(uint32_t ms); + +// returns true once the timer has expired +int netifc_timer_expired(void); diff --git a/system/ulib/inet6/inet6.c b/system/ulib/inet6/inet6.c new file mode 100644 index 000000000..b21fcbac6 --- /dev/null +++ b/system/ulib/inet6/inet6.c @@ -0,0 +1,441 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +#if 1 +#define BAD(n) \ + do { \ + printf("error: %s\n", n); \ + return; \ + } while (0) +#else +#define BAD(n) \ + do { \ + return; \ + } while (0) +#endif + +// useful addresses +const ip6_addr ip6_ll_all_nodes = { + .x = {0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, +}; +const ip6_addr ip6_ll_all_routers = { + .x = {0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}, +}; + +// Convert MAC Address to IPv6 Link Local Address +// aa:bb:cc:dd:ee:ff => FF80::aabb:ccFF:FEdd:eeff +// bit 2 (U/L) of the mac is inverted +void ll6addr_from_mac(ip6_addr* _ip, const mac_addr* _mac) { + uint8_t* ip = _ip->x; + const uint8_t* mac = _mac->x; + memset(ip, 0, IP6_ADDR_LEN); + ip[0] = 0xFE; + ip[1] = 0x80; + memset(ip + 2, 0, 6); + ip[8] = mac[0] ^ 2; + ip[9] = mac[1]; + ip[10] = mac[2]; + ip[11] = 0xFF; + ip[12] = 0xFE; + ip[13] = mac[3]; + ip[14] = mac[4]; + ip[15] = mac[5]; +} + +// Convert MAC Address to IPv6 Solicit Neighbor Multicast Address +// aa:bb:cc:dd:ee:ff -> FF02::1:FFdd:eeff +void snmaddr_from_mac(ip6_addr* _ip, const mac_addr* _mac) { + uint8_t* ip = _ip->x; + const uint8_t* mac = _mac->x; + ip[0] = 0xFF; + ip[1] = 0x02; + memset(ip + 2, 0, 9); + ip[11] = 0x01; + ip[12] = 0xFF; + ip[13] = mac[3]; + ip[14] = mac[4]; + ip[15] = mac[5]; +} + +// Convert IPv6 Multicast Address to Ethernet Multicast Address +void multicast_from_ip6(mac_addr* _mac, const ip6_addr* _ip6) { + const uint8_t* ip = _ip6->x; + uint8_t* mac = _mac->x; + mac[0] = 0x33; + mac[1] = 0x33; + mac[2] = ip[12]; + mac[3] = ip[13]; + mac[4] = ip[14]; + mac[5] = ip[15]; +} + +// ip6 stack configuration +mac_addr ll_mac_addr; +ip6_addr ll_ip6_addr; +mac_addr snm_mac_addr; +ip6_addr snm_ip6_addr; + +// cache for the last source addresses we've seen +static mac_addr rx_mac_addr; +static ip6_addr rx_ip6_addr; + +void ip6_init(void* macaddr) { + char tmp[IP6TOAMAX]; + mac_addr all; + + // save our ethernet MAC and synthesize link layer addresses + memcpy(&ll_mac_addr, macaddr, 6); + ll6addr_from_mac(&ll_ip6_addr, &ll_mac_addr); + snmaddr_from_mac(&snm_ip6_addr, &ll_mac_addr); + multicast_from_ip6(&snm_mac_addr, &snm_ip6_addr); + + eth_add_mcast_filter(&snm_mac_addr); + + multicast_from_ip6(&all, &ip6_ll_all_nodes); + eth_add_mcast_filter(&all); + + printf("macaddr: %02x:%02x:%02x:%02x:%02x:%02x\n", + ll_mac_addr.x[0], ll_mac_addr.x[1], ll_mac_addr.x[2], + ll_mac_addr.x[3], ll_mac_addr.x[4], ll_mac_addr.x[5]); + printf("ip6addr: %s\n", ip6toa(tmp, &ll_ip6_addr)); + printf("snmaddr: %s\n", ip6toa(tmp, &snm_ip6_addr)); +} + +static int resolve_ip6(mac_addr* _mac, const ip6_addr* _ip) { + const uint8_t* ip = _ip->x; + + // Multicast addresses are a simple transform + if (ip[0] == 0xFF) { + multicast_from_ip6(_mac, _ip); + return 0; + } + + // Trying to send to the IP that we last received a packet from? + // Assume their mac address has not changed + if (memcmp(_ip, &rx_ip6_addr, sizeof(rx_ip6_addr)) == 0) { + memcpy(_mac, &rx_mac_addr, sizeof(rx_mac_addr)); + return 0; + } + + // We don't know how to find peers or routers yet, so give up... + return -1; +} + +static uint16_t checksum(const void* _data, size_t len, uint16_t _sum) { + uint32_t sum = _sum; + const uint16_t* data = _data; + while (len > 1) { + sum += *data++; + len -= 2; + } + if (len) { + sum += (*data & 0xFF); + } + return sum + (sum >> 16); +} + +typedef struct { + uint8_t eth[16]; + ip6_hdr ip6; + uint8_t data[0]; +} ip6_pkt; + +typedef struct { + uint8_t eth[16]; + ip6_hdr ip6; + udp_hdr udp; + uint8_t data[0]; +} udp_pkt; + +static unsigned ip6_checksum(ip6_hdr* ip, unsigned type, size_t length) { + uint16_t sum; + + // length and protocol field for pseudo-header + sum = checksum(&ip->length, 2, htons(type)); + // src/dst for pseudo-header + payload + sum = checksum(ip->src, 32 + length, sum); + + // 0 is illegal, so 0xffff remains 0xffff + if (sum != 0xffff) { + return ~sum; + } else { + return sum; + } +} + +static int ip6_setup(ip6_pkt* p, const ip6_addr* daddr, size_t length, uint8_t type) { + mac_addr dmac; + + if (resolve_ip6(&dmac, daddr)) + return -1; + + // ethernet header + memcpy(p->eth + 2, &dmac, ETH_ADDR_LEN); + memcpy(p->eth + 8, &ll_mac_addr, ETH_ADDR_LEN); + p->eth[14] = (ETH_IP6 >> 8) & 0xFF; + p->eth[15] = ETH_IP6 & 0xFF; + + // ip6 header + p->ip6.ver_tc_flow = 0x60; // v=6, tc=0, flow=0 + p->ip6.length = htons(length); + p->ip6.next_header = type; + p->ip6.hop_limit = 255; + memcpy(p->ip6.src, &ll_ip6_addr, sizeof(ip6_addr)); + memcpy(p->ip6.dst, daddr, sizeof(ip6_addr)); + + return 0; +} + +#define UDP6_MAX_PAYLOAD (ETH_MTU - ETH_HDR_LEN - IP6_HDR_LEN - UDP_HDR_LEN) + +int udp6_send(const void* data, size_t dlen, const ip6_addr* daddr, uint16_t dport, uint16_t sport) { + size_t length = dlen + UDP_HDR_LEN; + udp_pkt* p = eth_get_buffer(ETH_MTU + 2); + + if (p == 0) + return -1; + if (dlen > UDP6_MAX_PAYLOAD) + goto fail; + if (ip6_setup((void*)p, daddr, length, HDR_UDP)) + goto fail; + + // udp header + p->udp.src_port = htons(sport); + p->udp.dst_port = htons(dport); + p->udp.length = htons(length); + p->udp.checksum = 0; + + memcpy(p->data, data, dlen); + p->udp.checksum = ip6_checksum(&p->ip6, HDR_UDP, length); + return eth_send(p->eth + 2, ETH_HDR_LEN + IP6_HDR_LEN + length); + +fail: + eth_put_buffer(p); + return -1; +} + +#define ICMP6_MAX_PAYLOAD (ETH_MTU - ETH_HDR_LEN - IP6_HDR_LEN) + +static int icmp6_send(const void* data, size_t length, const ip6_addr* daddr) { + ip6_pkt* p; + icmp6_hdr* icmp; + + p = eth_get_buffer(ETH_MTU + 2); + if (p == 0) + return -1; + if (length > ICMP6_MAX_PAYLOAD) + goto fail; + if (ip6_setup(p, daddr, length, HDR_ICMP6)) + goto fail; + + icmp = (void*)p->data; + memcpy(icmp, data, length); + icmp->checksum = ip6_checksum(&p->ip6, HDR_ICMP6, length); + return eth_send(p->eth + 2, ETH_HDR_LEN + IP6_HDR_LEN + length); + +fail: + eth_put_buffer(p); + return -1; +} + +void _udp6_recv(ip6_hdr* ip, void* _data, size_t len) { + udp_hdr* udp = _data; + uint16_t sum, n; + + if (len < UDP_HDR_LEN) + BAD("Bogus Header Len"); + if (udp->checksum == 0) + BAD("Checksum Invalid"); + if (udp->checksum == 0xFFFF) + udp->checksum = 0; + + sum = checksum(&ip->length, 2, htons(HDR_UDP)); + sum = checksum(ip->src, 32 + len, sum); + if (sum != 0xFFFF) + BAD("Checksum Incorrect"); + + n = ntohs(udp->length); + if (n < UDP_HDR_LEN) + BAD("Bogus Header Len"); + if (n > len) + BAD("Packet Too Short"); + len = n - UDP_HDR_LEN; + + udp6_recv((uint8_t*)_data + UDP_HDR_LEN, len, + (void*)ip->dst, ntohs(udp->dst_port), + (void*)ip->src, ntohs(udp->src_port)); +} + +void icmp6_recv(ip6_hdr* ip, void* _data, size_t len) { + icmp6_hdr* icmp = _data; + uint16_t sum; + + if (icmp->checksum == 0) + BAD("Checksum Invalid"); + if (icmp->checksum == 0xFFFF) + icmp->checksum = 0; + + sum = checksum(&ip->length, 2, htons(HDR_ICMP6)); + sum = checksum(ip->src, 32 + len, sum); + if (sum != 0xFFFF) + BAD("Checksum Incorrect"); + + if (icmp->type == ICMP6_NDP_N_SOLICIT) { + ndp_n_hdr* ndp = _data; + struct { + ndp_n_hdr hdr; + uint8_t opt[8]; + } msg; + + if (len < sizeof(ndp_n_hdr)) + BAD("Bogus NDP Message"); + if (ndp->code != 0) + BAD("Bogus NDP Code"); + if (memcmp(ndp->target, &ll_ip6_addr, IP6_ADDR_LEN)) + BAD("NDP Not For Me"); + + msg.hdr.type = ICMP6_NDP_N_ADVERTISE; + msg.hdr.code = 0; + msg.hdr.checksum = 0; + msg.hdr.flags = 0x60; // (S)olicited and (O)verride flags + memcpy(msg.hdr.target, &ll_ip6_addr, IP6_ADDR_LEN); + msg.opt[0] = NDP_N_TGT_LL_ADDR; + msg.opt[1] = 1; + memcpy(msg.opt + 2, &ll_mac_addr, ETH_ADDR_LEN); + + icmp6_send(&msg, sizeof(msg), (void*)ip->src); + return; + } + + if (icmp->type == ICMP6_ECHO_REQUEST) { + icmp->checksum = 0; + icmp->type = ICMP6_ECHO_REPLY; + icmp6_send(_data, len, (void*)ip->src); + return; + } + + BAD("ICMP6 Unhandled"); +} + +void eth_recv(void* _data, size_t len) { + uint8_t* data = _data; + ip6_hdr* ip; + uint32_t n; + + if (len < (ETH_HDR_LEN + IP6_HDR_LEN)) + BAD("Bogus Header Len"); + if (data[12] != (ETH_IP6 >> 8)) + return; + if (data[13] != (ETH_IP6 & 0xFF)) + return; + + ip = (void*)(data + ETH_HDR_LEN); + data += (ETH_HDR_LEN + IP6_HDR_LEN); + len -= (ETH_HDR_LEN + IP6_HDR_LEN); + + // require v6 + if ((ip->ver_tc_flow & 0xF0) != 0x60) + BAD("Unknown IP6 Version"); + + // ensure length is sane + n = ntohs(ip->length); + if (n > len) + BAD("IP6 Length Mismatch"); + + // ignore any trailing data in the ethernet frame + len = n; + + // require that we are the destination + if (memcmp(&ll_ip6_addr, ip->dst, IP6_ADDR_LEN) && + memcmp(&snm_ip6_addr, ip->dst, IP6_ADDR_LEN)) { + return; + } + + // stash the sender's info to simplify replies + memcpy(&rx_mac_addr, (uint8_t*)_data + 6, ETH_ADDR_LEN); + memcpy(&rx_ip6_addr, ip->src, IP6_ADDR_LEN); + + if (ip->next_header == HDR_ICMP6) { + icmp6_recv(ip, data, len); + return; + } + + if (ip->next_header == HDR_UDP) { + _udp6_recv(ip, data, len); + return; + } + + BAD("Unhandled IP6"); +} + +char* ip6toa(char* _out, void* ip6addr) { + const uint8_t* x = ip6addr; + const uint8_t* end = x + 16; + char* out = _out; + uint16_t n; + + n = (x[0] << 8) | x[1]; + while ((n == 0) && (x < end)) { + x += 2; + n = (x[0] << 8) | x[1]; + } + + if ((end - x) < 16) { + if (end == x) { + // all 0s - special case + sprintf(out, "::"); + return _out; + } + // we consumed some number of leading 0s + out += sprintf(out, ":"); + while (x < end) { + out += sprintf(out, ":%x", n); + x += 2; + n = (x[0] << 8) | x[1]; + } + return _out; + } + + while (x < (end - 2)) { + out += sprintf(out, "%x:", n); + x += 2; + n = (x[0] << 8) | x[1]; + if (n == 0) + goto middle_zeros; + } + out += sprintf(out, "%x", n); + return _out; + +middle_zeros: + while ((n == 0) && (x < end)) { + x += 2; + n = (x[0] << 8) | x[1]; + } + if (x == end) { + out += sprintf(out, ":"); + return _out; + } + while (x < end) { + out += sprintf(out, ":%x", n); + x += 2; + n = (x[0] << 8) | x[1]; + } + return _out; +} diff --git a/system/ulib/inet6/netifc.c b/system/ulib/inet6/netifc.c new file mode 100644 index 000000000..fe52c78f2 --- /dev/null +++ b/system/ulib/inet6/netifc.c @@ -0,0 +1,136 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include + +#include +#include + +static int netfd = -1; +static uint8_t netmac[6]; + +#define MAX_FILTER 8 + +#define NUM_BUFFER_PAGES 8 +#define ETH_BUFFER_SIZE 1536 +#define ETH_BUFFER_MAGIC 0x424201020304A7A7UL + +typedef struct eth_buffer eth_buffer_t; +struct eth_buffer { + uint64_t magic; + eth_buffer_t* next; + uint8_t data[0]; +}; + +static eth_buffer_t* eth_buffers = NULL; + +void* eth_get_buffer(size_t sz) { + eth_buffer_t* buf; + if (sz > ETH_BUFFER_SIZE) { + return NULL; + } + if (eth_buffers == NULL) { + printf("out of buffers\n"); + return NULL; + } + buf = eth_buffers; + eth_buffers = buf->next; + buf->next = NULL; + return buf->data; +} + +void eth_put_buffer(void* data) { + eth_buffer_t* buf = (void*)(((uintptr_t)data) & (~31)); + if (buf->magic != ETH_BUFFER_MAGIC) { + printf("fatal: eth buffer %p (from %p) bad magic %llx\n", buf, data, buf->magic); + for (;;) + ; + } + buf->next = eth_buffers; + eth_buffers = buf; +} + +int eth_send(void* data, size_t len) { + int r = write(netfd, data, len); + eth_put_buffer(data); + return r; +} + +int eth_add_mcast_filter(const mac_addr* addr) { + return 0; +} + +static uint64_t net_timer = 0; + +#define TIMER_MS(n) (((uint64_t)(n)) * 1000000ULL) + +void netifc_set_timer(uint32_t ms) { + net_timer = _magenta_current_time() + TIMER_MS(ms); +} + +int netifc_timer_expired(void) { + if (net_timer == 0) { + return 0; + } + if (_magenta_current_time() > net_timer) { + return 1; + } + return 0; +} + +int netifc_open(void) { + if ((netfd = open("/dev/protocol/char/ethernet_char", O_RDWR)) < 0) { + return -1; + } + if (read(netfd, netmac, 6) != 6) { + close(netfd); + netfd = -1; + return -1; + } + ip6_init(netmac); + for (int i = 0; i < 8; i++) { + char* buffer = malloc(sizeof(eth_buffer_t) + ETH_BUFFER_SIZE + 32); + buffer = (char*)((((uintptr_t)buffer) + 31) & (~31)); + if (buffer) { + eth_buffer_t* eb = (eth_buffer_t*)buffer; + eb->magic = ETH_BUFFER_MAGIC; + eth_put_buffer(buffer + sizeof(eth_buffer_t)); + } + } + return 0; +} + +void netifc_close(void) { + close(netfd); + netfd = -1; +} + +int netifc_active(void) { + return (netfd >= 0); +} + +void netifc_poll(void) { + uint8_t buffer[2048]; + int r; + + while ((r = read(netfd, buffer, sizeof(buffer))) > 0) { + printf("(%d)\n", r); + eth_recv(buffer, r); + } +} diff --git a/system/ulib/inet6/rules.mk b/system/ulib/inet6/rules.mk new file mode 100644 index 000000000..015f7631d --- /dev/null +++ b/system/ulib/inet6/rules.mk @@ -0,0 +1,30 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS += \ + $(LOCAL_DIR)/inet6.c \ + $(LOCAL_DIR)/netifc.c \ + +MODULE_DEPS += \ + ulib/musl \ + ulib/mxio \ + ulib/magenta + +include make/module.mk diff --git a/system/ulib/magenta/BUILD.gn b/system/ulib/magenta/BUILD.gn new file mode 100644 index 000000000..745a672ee --- /dev/null +++ b/system/ulib/magenta/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_magenta_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("magenta") { + public_configs = [ ":_magenta_config" ] + include_dirs = [ "//third_party/ulib/musl/include" ] + public = [ + "include/magenta/prctl.h", + "include/magenta/processargs.h", + "include/magenta/syscalls.h", + "include/magenta/syscalls.inc", + "include/magenta/tlsroot.h", + "include/magenta/types.h", + ] + sources = [] + if (target_cpu == "arm") { + sources += [ "syscalls_arm32.S" ] + } else if (target_cpu == "arm64") { + sources += [ "syscalls_arm64.S" ] + } else if (target_cpu == "x64") { + sources += [ "syscalls_x86_64.S" ] + } +} diff --git a/system/ulib/magenta/include/magenta/prctl.h b/system/ulib/magenta/include/magenta/prctl.h new file mode 100644 index 000000000..f9ef9620f --- /dev/null +++ b/system/ulib/magenta/include/magenta/prctl.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#if ARCH_X86_64 + +enum { ARCH_SET_FS = 0, ARCH_GET_FS = 1, ARCH_SET_GS = 2, ARCH_GET_GS = 3 }; + +#elif ARCH_ARM64 + +enum { + ARCH_SET_TPIDRRO_EL0 = 0, +}; + +#elif ARCH_ARM + +enum { + ARCH_SET_CP15_READONLY = 0, +}; + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/system/ulib/magenta/include/magenta/processargs.h b/system/ulib/magenta/include/magenta/processargs.h new file mode 100644 index 000000000..7fdf00578 --- /dev/null +++ b/system/ulib/magenta/include/magenta/processargs.h @@ -0,0 +1,98 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// This is a protocol for passing state to a new process +// via a message in a message pipe. + +#define MX_PROCARGS_PROTOCOL 0x4150585d // MXPA +#define MX_PROCARGS_VERSION 0x0001000 + +typedef struct mx_proc_args mx_proc_args_t; + +struct mx_proc_args { + // Protocol and version identifiers to allow for + // different process start message protocols and + // versioning of the same. + uint32_t protocol; + uint32_t version; + + // Offset from start of message to handle info + // array, which contains one uint32_t per handle + // passed along with the message. + uint32_t handle_info_off; + + // Offset from start of message to arguments and + // count of arguments. Arguments are provided as + // a set of null-terminated utf-8 strings, one + // after the other. + uint32_t args_off; + uint32_t args_num; +}; + +// Handle Info entries associate a type and optional +// argument with each handle included in the process +// arguments message. +#define MX_HND_INFO(type, arg) (((type)&0xFFFF)|(((arg)&0xFFFF)<<16)) +#define MX_HND_INFO_TYPE(n) ((n)&0xFFFF) +#define MX_HND_INFO_ARG(n) (((n) >> 16) & 0xFFFF) + +// handle to our own process +#define MX_HND_TYPE_PROC_SELF 1 + +// Handle types the mxio library uses +#define MX_HND_TYPE_MXIO_ROOT 0x10 +#define MX_HND_TYPE_MXIO_REMOTE 0x11 +#define MX_HND_TYPE_MXIO_PIPE 0x12 +#define MX_HND_TYPE_MXIO_EVENT 0x13 + +// Handle types for one-off use and prototyping +#define MX_HND_TYPE_USER0 0xFFF0 +#define MX_HND_TYPE_USER1 0xFFF1 +#define MX_HND_TYPE_USER2 0xFFF2 + +#define MX_PROC_INFO_MAGIC 0xd0dabb1e +#define MX_PROC_INFO_VERSION 0 + +// Utility to parse the above +typedef struct mx_proc_info mx_proc_info_t; +struct mx_proc_info { + // Identifier and version of the mx_proc_info object. + uint32_t magic; // MX_PROC_INFO_MAGIC + uint32_t version; // MX_PROC_INFO_VERSION + + // Next available TLS slot. Increment atomically. + uint32_t next_tls_slot; + + mx_proc_args_t* proc_args; + + mx_handle_t* handle; + uint32_t* handle_info; + int handle_count; + + char** argv; + int argc; +}; + +#ifdef __cplusplus +} +#endif diff --git a/system/ulib/magenta/include/magenta/syscalls.h b/system/ulib/magenta/include/magenta/syscalls.h new file mode 100644 index 000000000..6fc854a6a --- /dev/null +++ b/system/ulib/magenta/include/magenta/syscalls.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// define all of the syscalls from the syscall list header. +// user space syscall vaneer routines are all prefixed with _magenta_ +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) extern ret _magenta_##name(args); +#define MAGENTA_SYSCALL_DEF_WITH_ATTRS(nargs64, nargs32, n, ret, name, attrs, args...) extern ret _magenta_##name(args) __attribute__(attrs); + +#include + +#ifdef __cplusplus +} +#endif diff --git a/system/ulib/magenta/include/magenta/syscalls.inc b/system/ulib/magenta/include/magenta/syscalls.inc new file mode 100644 index 000000000..211842a58 --- /dev/null +++ b/system/ulib/magenta/include/magenta/syscalls.inc @@ -0,0 +1,156 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* included from other files to define a syscall api */ + +/* NOTE: to determine number of arguments for any given syscall use the following algorithm: + * + * 64bit args are simply the number of arguments, since there are no special packing rules for simple + * integer args on 64bit architectures that magenta currently supports (arm64 and x86-64). All 64 and 32bit args + * use up a single slot. + * + * For 32bit, each function argument occupies one slot, unless it is a fixed 64bit size (uint64, mx_time_t), + * in which case it uses two. Additionally, for arm32, if the 64bit slot is now not in an even/odd slot, a padding + * slot needs to be added. Examples: + * uint32 == 1 slot + * uint64 == 2 slots + * uint32, uint32, uint64 == 4 slots + * uint32, uint64, uint32 == 5 slots (uint32, padding, uint64 (2 slots), uint32) + */ + +/* MAGENTA_SYSCALL_DEF(# of 64 bit args, # of 32 bit args, syscall number, return type, name, arguments...) */ +/* MAGENTA_SYSCALL_DEF_WITH_ATTRS(# of 64 bit args, # of 32 bit args, syscall number, return type, name, attrs, arguments...) */ + +#ifndef MAGENTA_SYSCALL_DEF +#error MAGENTA_SYSCALL_DEF not defined +#endif + +#ifndef MAGENTA_SYSCALL_DEF_WITH_ATTRS +#define MAGENTA_SYSCALL_DEF_WITH_ATTRS(num_64bit_args, num_32bit_args, syscall_num, return_type, name, attrs, arguments...) \ + MAGENTA_SYSCALL_DEF(num_64bit_args, num_32bit_args, syscall_num, return_type, name, arguments) +#endif + +MAGENTA_SYSCALL_DEF_WITH_ATTRS(1, 1, 0, void, exit, (noreturn), int retcode) +MAGENTA_SYSCALL_DEF(2, 2, 1, int, debug_read, void* buffer, uint32_t length) +MAGENTA_SYSCALL_DEF(2, 2, 2, int, debug_write, const void* buffer, uint32_t length) +MAGENTA_SYSCALL_DEF(1, 2, 3, int, nanosleep, mx_time_t nanoseconds) +MAGENTA_SYSCALL_DEF(0, 0, 4, mx_time_t, current_time, void) +MAGENTA_SYSCALL_DEF(2, 2, 5, int, debug_send_command, const void* buffer, uint32_t length) + +/* Logging */ +MAGENTA_SYSCALL_DEF(1, 1, 30, mx_handle_t, log_create, uint32_t flags); +MAGENTA_SYSCALL_DEF(4, 3, 31, mx_status_t, log_write, mx_handle_t handle, uint32_t len, const void* buffer, uint32_t flags); +MAGENTA_SYSCALL_DEF(4, 3, 32, mx_status_t, log_read, mx_handle_t handle, uint32_t len, void* buffer, uint32_t flags); + +/* Generic handle operations */ +MAGENTA_SYSCALL_DEF(1, 1, 40, mx_status_t, handle_close, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(1, 1, 41, mx_handle_t, handle_duplicate, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(5, 6, 42, mx_status_t, handle_wait_one, mx_handle_t handle, mx_signals_t signals, + mx_time_t timeout, mx_signals_t* satisfied_signals, mx_signals_t* satisfiable_signals) +MAGENTA_SYSCALL_DEF(6, 8, 43, mx_status_t, handle_wait_many, uint32_t count, const mx_handle_t* handles, + const mx_signals_t* signals, mx_time_t timeout, mx_signals_t* satisfied_signals, + mx_signals_t* satisfiable_signals) + +/* Generic object operations */ +MAGENTA_SYSCALL_DEF(3, 3, 46, mx_status_t, object_signal, mx_handle_t handle, uint32_t set_mask, uint32_t clear_mask) + +/* Threads */ +MAGENTA_SYSCALL_DEF(4, 4, 50, mx_handle_t, thread_create, int (*entry)(void*), void* arg, + const char* name, uint32_t name_len) +MAGENTA_SYSCALL_DEF_WITH_ATTRS(0, 0, 51, void, thread_exit, (noreturn), void) +MAGENTA_SYSCALL_DEF(3, 3, 52, mx_status_t, thread_arch_prctl, mx_handle_t handle, uint32_t op, uintptr_t* value_ptr) + +/* Messages */ +/* TODO(jamesr): creation options */ +MAGENTA_SYSCALL_DEF(1, 1, 60, mx_handle_t, message_pipe_create, mx_handle_t* out_handle) +MAGENTA_SYSCALL_DEF(6, 6, 61, mx_status_t, message_read, mx_handle_t handle, void* bytes, + uint32_t* num_bytes, mx_handle_t* handles, uint32_t* num_handles, uint32_t flags) +MAGENTA_SYSCALL_DEF(6, 6, 62, mx_status_t, message_write, mx_handle_t handle, const void* bytes, + uint32_t num_bytes, const mx_handle_t* handles, uint32_t num_handles, uint32_t flags) + +/* Drivers */ +MAGENTA_SYSCALL_DEF(2, 2, 70, mx_handle_t, interrupt_event_create, uint32_t vector, uint32_t flags) +MAGENTA_SYSCALL_DEF(1, 1, 71, mx_status_t, interrupt_event_complete, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(1, 1, 72, mx_status_t, interrupt_event_wait, mx_handle_t handle) + +/* Processes */ +MAGENTA_SYSCALL_DEF(0, 0, 80, mx_handle_t, process_create, const char* name, uint32_t name_len) +MAGENTA_SYSCALL_DEF(3, 3, 82, mx_status_t, process_start, mx_handle_t handle, mx_handle_t handle_arg, mx_vaddr_t entry) +MAGENTA_SYSCALL_DEF(6, 7, 83, mx_status_t, process_vm_map, mx_handle_t proc_handle, mx_handle_t vmo_handle, + uint64_t offset, mx_size_t len, uintptr_t *ptr, uint32_t flags); +MAGENTA_SYSCALL_DEF(3, 3, 84, mx_status_t, process_vm_unmap, mx_handle_t proc_handle, uintptr_t address, mx_size_t len); +MAGENTA_SYSCALL_DEF(3, 3, 85, mx_status_t, process_get_info, mx_handle_t handle, mx_process_info_t *info, mx_size_t info_len); + +/* Synchronization */ +MAGENTA_SYSCALL_DEF(1, 1, 90, mx_handle_t, event_create, uint32_t options) +MAGENTA_SYSCALL_DEF(1, 1, 91, mx_status_t, event_signal, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(1, 1, 92, mx_status_t, event_reset, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(3, 4, 93, mx_status_t, futex_wait, int* value_ptr, int current_value, mx_time_t timeout) +MAGENTA_SYSCALL_DEF(2, 2, 94, mx_status_t, futex_wake, int* value_ptr, uint32_t count) +MAGENTA_SYSCALL_DEF(5, 5, 95, mx_status_t, futex_requeue, int* wake_ptr, uint32_t wake_count, int current_value, + int* requeue_ptr, uint32_t requeue_count) + +/* Memory management */ +MAGENTA_SYSCALL_DEF(1, 2, 100, mx_handle_t, vm_object_create, uint64_t size) +MAGENTA_SYSCALL_DEF(4, 5, 101, mx_ssize_t, vm_object_read, mx_handle_t handle, void *data, uint64_t offset, mx_size_t len); +MAGENTA_SYSCALL_DEF(4, 5, 102, mx_ssize_t, vm_object_write, mx_handle_t handle, const void *data, uint64_t offset, mx_size_t len); +MAGENTA_SYSCALL_DEF(2, 4, 103, mx_status_t, vm_object_get_size, mx_handle_t handle, uint64_t *size); +MAGENTA_SYSCALL_DEF(2, 4, 104, mx_status_t, vm_object_set_size, mx_handle_t handle, uint64_t size); + +/* temporary syscalls to access port and memory mapped devices */ +MAGENTA_SYSCALL_DEF(2, 2, 105, mx_status_t, mmap_device_io, uint32_t io_addr, uint32_t len) +MAGENTA_SYSCALL_DEF(3, 3, 106, mx_status_t, mmap_device_memory, uintptr_t paddr, uint32_t len, void **out_vaddr) +MAGENTA_SYSCALL_DEF(3, 3, 107, mx_status_t, alloc_device_memory, uint32_t len, void **out_vaddr, void **out_paddr) + +/* TODO(security) */ +MAGENTA_SYSCALL_DEF(4, 4, 170, mx_status_t, bootloader_fb_get_info, uint32_t* format, uint32_t* width, uint32_t* height, uint32_t* stride) +MAGENTA_SYSCALL_DEF(6, 6, 171, mx_status_t, set_framebuffer, void* vaddr, uint32_t len, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) + +/* temporary pci syscalls */ +/* TODO: remove when the pci driver moves to user space */ +MAGENTA_SYSCALL_DEF(2, 2, 180, mx_handle_t, pci_get_nth_device, uint32_t index, mx_pcie_get_nth_info_t* out_info); +MAGENTA_SYSCALL_DEF(1, 1, 181, mx_status_t, pci_claim_device, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(2, 2, 182, mx_status_t, pci_enable_bus_master, mx_handle_t handle, bool enable) +MAGENTA_SYSCALL_DEF(1, 1, 183, mx_status_t, pci_reset_device, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(3, 3, 184, mx_handle_t, pci_map_mmio, mx_handle_t handle, uint32_t bar_num, mx_cache_policy_t cache_policy); +MAGENTA_SYSCALL_DEF(5, 5, 185, mx_status_t, pci_io_write, mx_handle_t handle, uint32_t bar_num, uint32_t offset, uint32_t len, const uint32_t value) +MAGENTA_SYSCALL_DEF(5, 5, 186, mx_status_t, pci_io_read, mx_handle_t handle, uint32_t bar_num, uint32_t offset, uint32_t len, uint32_t* out_value) +MAGENTA_SYSCALL_DEF(2, 2, 187, mx_handle_t, pci_map_interrupt, mx_handle_t handle, int32_t which_irq) +MAGENTA_SYSCALL_DEF(1, 1, 188, mx_status_t, pci_interrupt_wait, mx_handle_t handle) +MAGENTA_SYSCALL_DEF(1, 1, 189, mx_handle_t, pci_map_config, mx_handle_t handle) + +/* I/O mapping objects */ +MAGENTA_SYSCALL_DEF(3, 3, 200, mx_status_t, io_mapping_get_info, mx_handle_t handle, void** out_vaddr, uint64_t* out_size) + +/* syscall arg passing tests */ +MAGENTA_SYSCALL_DEF(0, 0, 20000, int, syscall_test_0, void) +MAGENTA_SYSCALL_DEF(1, 1, 20001, int, syscall_test_1, int a) +MAGENTA_SYSCALL_DEF(2, 2, 20002, int, syscall_test_2, int a, int b) +MAGENTA_SYSCALL_DEF(3, 3, 20003, int, syscall_test_3, int a, int b, int c) +MAGENTA_SYSCALL_DEF(4, 4, 20004, int, syscall_test_4, int a, int b, int c, int d) +MAGENTA_SYSCALL_DEF(5, 5, 20005, int, syscall_test_5, int a, int b, int c, int d, int e) +MAGENTA_SYSCALL_DEF(6, 6, 20006, int, syscall_test_6, int a, int b, int c, int d, int e, int f) +MAGENTA_SYSCALL_DEF(7, 7, 20007, int, syscall_test_7, int a, int b, int c, int d, int e, int f, int g) +MAGENTA_SYSCALL_DEF(8, 8, 20008, int, syscall_test_8, int a, int b, int c, int d, int e, int f, int g, int h) + +/* exception handlers */ +MAGENTA_SYSCALL_DEF(2, 2, 210, mx_status_t, set_system_exception_handler, + mx_handle_t pipe, mx_exception_behaviour_t behaviour) +MAGENTA_SYSCALL_DEF(3, 3, 211, mx_status_t, set_exception_handler, + mx_handle_t object, mx_handle_t pipe, mx_exception_behaviour_t behaviour) +MAGENTA_SYSCALL_DEF(2, 2, 212, mx_status_t, mark_exception_handled, + mx_handle_t object, mx_exception_status_t status) + +#undef MAGENTA_SYSCALL_DEF +#undef MAGENTA_SYSCALL_DEF_WITH_ATTRS diff --git a/system/ulib/magenta/include/magenta/tlsroot.h b/system/ulib/magenta/include/magenta/tlsroot.h new file mode 100644 index 000000000..389a35422 --- /dev/null +++ b/system/ulib/magenta/include/magenta/tlsroot.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// The mx_tls_root_t describes the object pointed to by the thread-local +// storage (TLS) register in a Magenta process. It holds TLS slots that +// are used by libraries and language runtimes. +// +// To claim a slot, increment the next_tls_slot field in mx_proc_info +// with a compare-and-swap and take the old value as an index into the +// slots array. +// +// Any user code that calls the _magenta_thread_create system call is +// responsible for allocating an mx_tls_root_t object with at least 8 +// slots, setting its fields correctly, and placing a pointer to it in +// the TLS register appropriately for the current architecture. +// +// On X86_64, *mx_tls_root_t should be loaded into the FS register. +// On ARM64, *mx_tls_root_t should be loaded into the TPIDR_EL0 register. +// On ARM32, *mx_tls_root_t should be loaded into the CP15 readonly register. + +typedef struct mx_tls_root mx_tls_root_t; + +struct mx_tls_root { + mx_tls_root_t* self; + mx_proc_info_t* proc; + uint32_t magic; // MX_TLS_ROOT_MAGIC + uint16_t flags; // Reserved for future use. + uint16_t maxslots; // Number of slots in this object, minimum 8. + void* slots[1]; // TLS slots. Has length maxslots. +}; + +#define MX_TLS_ROOT_MAGIC 0x2facef0e +#define MX_TLS_MIN_SLOTS 8 + +#define MX_TLS_ROOT_SIZE(x) \ + (sizeof(mx_tls_root) + sizeof(void*) * (x->maxslots - 1)) + +#ifdef __cplusplus +} +#endif diff --git a/system/ulib/magenta/include/magenta/types.h b/system/ulib/magenta/include/magenta/types.h new file mode 100644 index 000000000..4903b24cb --- /dev/null +++ b/system/ulib/magenta/include/magenta/types.h @@ -0,0 +1,209 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// ask clang format not to mess up the indentation: +// clang-format off + +typedef int32_t mx_handle_t; +#define MX_HANDLE_INVALID ((mx_handle_t)0) + +// Same as kernel status_t +typedef int32_t mx_status_t; + +// time in nanoseconds +typedef uint64_t mx_time_t; +#define MX_TIME_INFINITE UINT64_MAX + +typedef uint32_t mx_signals_t; +#define MX_SIGNAL_NONE ((mx_signals_t)0u) +#define MX_SIGNAL_READABLE ((mx_signals_t)1u << 0) +#define MX_SIGNAL_WRITABLE ((mx_signals_t)1u << 1) +#define MX_SIGNAL_PEER_CLOSED ((mx_signals_t)1u << 2) +#define MX_SIGNAL_SIGNALED ((mx_signals_t)1u << 3) + +#define MX_SIGNAL_USER0 ((mx_signals_t)1u << 4) +#define MX_SIGNAL_USER1 ((mx_signals_t)1u << 5) +#define MX_SIGNAL_USER2 ((mx_signals_t)1u << 6) +#define MX_SIGNAL_USER3 ((mx_signals_t)1u << 7) +#define MX_SIGNAL_USER_ALL ((mx_signals_t)15u << 4) + +typedef uint32_t mx_rights_t; +#define MX_RIGHT_NONE ((mx_rights_t)0u) +#define MX_RIGHT_DUPLICATE ((mx_rights_t)1u << 0) +#define MX_RIGHT_TRANSFER ((mx_rights_t)1u << 1) +#define MX_RIGHT_READ ((mx_rights_t)1u << 2) +#define MX_RIGHT_WRITE ((mx_rights_t)1u << 3) +#define MX_RIGHT_EXECUTE ((mx_rights_t)1u << 4) + +// flags to vm map routines +#define MX_VM_FLAG_FIXED (1u << 0) +#define MX_VM_FLAG_PERM_READ (1u << 1) +#define MX_VM_FLAG_PERM_WRITE (1u << 2) +#define MX_VM_FLAG_PERM_EXECUTE (1u << 3) + +typedef uint32_t mx_exception_behaviour_t; +#define MX_EXCEPTION_BEHAVIOUR_DEFAULT 0 +#define MX_EXCEPTION_MAX_BEHAVIOUR 0 + +// virtual address +typedef uintptr_t mx_vaddr_t; + +// physical address +typedef uintptr_t mx_paddr_t; + +// size +typedef uintptr_t mx_size_t; +typedef intptr_t mx_ssize_t; + +// process id +typedef int32_t mx_pid_t; + +// thread id +typedef int32_t mx_tid_t; + +// data associated with an exception (siginfo in linux parlance) +typedef struct mx_exception_context { + // TODO(dje): This value is wip. + uint32_t type; + + // TODO(dje): add more stuff +} mx_exception_context_t; + +// data reported to an exception handler +typedef struct mx_exception_report { + mx_pid_t pid; + mx_tid_t tid; + mx_vaddr_t pc; + mx_exception_context_t context; +} mx_exception_report_t; + +// The argument to _magenta_mark_exception_handled. +typedef uint32_t mx_exception_status_t; +#define MX_EXCEPTION_STATUS_NOT_HANDLED 0 +#define MX_EXCEPTION_STATUS_RESUME 1 + +// information from process_get_info +typedef struct mx_process_info { + mx_size_t len; + + int return_code; +} mx_process_info_t; + +// Info returned to dev manager for PCIe devices when probing. +typedef struct mx_pcie_get_nth_info { + uint16_t vendor_id; + uint16_t device_id; + + uint8_t base_class; + uint8_t sub_class; + uint8_t program_interface; + uint8_t revision_id; + + uint8_t bus_id; + uint8_t dev_id; + uint8_t func_id; +} mx_pcie_get_nth_info_t; + +// Flags which can be used to to control cache policy for APIs which map memory. +typedef enum { + MX_CACHE_POLICY_CACHED = 0, + MX_CACHE_POLICY_UNCACHED = 1, + MX_CACHE_POLICY_UNCACHED_DEVICE = 2, + MX_CACHE_POLICY_WRITE_COMBINING = 3, +} mx_cache_policy_t; + +// Log entries and flags +typedef struct mx_log_record { + uint32_t reserved; + uint16_t datalen; + uint16_t flags; + mx_time_t timestamp; + char data[0]; +} mx_log_record_t; + +#define MX_LOG_RECORD_MAX 256 + +#define MX_LOG_FLAG_KERNEL 0x0100 +#define MX_LOG_FLAG_DEVMGR 0x0200 +#define MX_LOG_FLAG_CONSOLE 0x0400 +#define MX_LOG_FLAG_DEVICE 0x0800 +#define MX_LOG_FLAG_MASK 0x0F00 + +#define MX_LOG_FLAG_WAIT 0x80000000 + +// Maximum string length for kernel names (process name, thread name, etc) +#define MX_MAX_NAME_LEN (32) + +// m_status_t error codes. Must match values in include/err.h +#define NO_ERROR (0) +#define ERR_GENERIC (-1) +#define ERR_NOT_FOUND (-2) +#define ERR_NOT_READY (-3) +#define ERR_NO_MSG (-4) +#define ERR_NO_MEMORY (-5) +#define ERR_ALREADY_STARTED (-6) +#define ERR_NOT_VALID (-7) +#define ERR_INVALID_ARGS (-8) +#define ERR_NOT_ENOUGH_BUFFER (-9) +#define ERR_NOT_SUSPENDED (-10) +#define ERR_OBJECT_DESTROYED (-11) +#define ERR_NOT_BLOCKED (-12) +#define ERR_TIMED_OUT (-13) +#define ERR_ALREADY_EXISTS (-14) +#define ERR_CHANNEL_CLOSED (-15) +#define ERR_OFFLINE (-16) +#define ERR_NOT_ALLOWED (-17) +#define ERR_BAD_PATH (-18) +#define ERR_ALREADY_MOUNTED (-19) +#define ERR_IO (-20) +#define ERR_NOT_DIR (-21) +#define ERR_NOT_FILE (-22) +#define ERR_RECURSE_TOO_DEEP (-23) +#define ERR_NOT_SUPPORTED (-24) +#define ERR_TOO_BIG (-25) +#define ERR_CANCELLED (-26) +#define ERR_NOT_IMPLEMENTED (-27) +#define ERR_CHECKSUM_FAIL (-28) +#define ERR_CRC_FAIL (-29) +#define ERR_CMD_UNKNOWN (-30) +#define ERR_BAD_STATE (-31) +#define ERR_BAD_LEN (-32) +#define ERR_BUSY (-33) +#define ERR_THREAD_DETACHED (-34) +#define ERR_I2C_NACK (-35) +#define ERR_ALREADY_EXPIRED (-36) +#define ERR_OUT_OF_RANGE (-37) +#define ERR_NOT_CONFIGURED (-38) +#define ERR_NOT_MOUNTED (-39) +#define ERR_FAULT (-40) +#define ERR_NO_RESOURCES (-41) +#define ERR_BAD_HANDLE (-42) +#define ERR_ACCESS_DENIED (-43) +#define ERR_PARTIAL_WRITE (-44) +#define ERR_BAD_SYSCALL (-45) + +// interrupt flags +#define MX_FLAG_REMAP_IRQ 0x1 + +#ifdef __cplusplus +} +#endif diff --git a/system/ulib/magenta/rules.mk b/system/ulib/magenta/rules.mk new file mode 100644 index 000000000..a6db69938 --- /dev/null +++ b/system/ulib/magenta/rules.mk @@ -0,0 +1,36 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +# kernel code needs magenta headers +GLOBAL_INCLUDES += $(LOCAL_DIR)/include + +ifeq ($(ARCH),arm) +MODULE_SRCS += $(LOCAL_DIR)/syscalls_arm32.S +else ifeq ($(ARCH),arm64) +MODULE_SRCS += $(LOCAL_DIR)/syscalls_arm64.S +else ifeq ($(ARCH),x86) + ifeq ($(SUBARCH),x86-64) + MODULE_SRCS += $(LOCAL_DIR)/syscalls_x86_64.S + else + MODULE_SRCS += $(LOCAL_DIR)/syscalls_x86.S + endif +endif + +include make/module.mk diff --git a/system/ulib/magenta/syscalls_arm32.S b/system/ulib/magenta/syscalls_arm32.S new file mode 100644 index 000000000..3ed1e1a78 --- /dev/null +++ b/system/ulib/magenta/syscalls_arm32.S @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* define and implement the magenta syscall wrappers for 32bit arm */ + +.text + +#define MAGENTA_SYSCALL_MAGIC 0xf0f0 + +.macro syscall nargs, name, n +.globl \name +.type \name,STT_FUNC +\name: +.if \nargs < 5 + movw r12, #\n + movt r12, #MAGENTA_SYSCALL_MAGIC + svc #0xff00ff + mov r12, #0 + bx lr +.endif +.if \nargs == 5 + push {r4-r5} + ldr r4, [sp, #8] + movw r12, #\n + movt r12, #MAGENTA_SYSCALL_MAGIC + svc #0xff00ff + mov r12, #0 + pop {r4-r5} + bx lr +.endif +.if \nargs == 6 + push {r4-r5} + ldrd r4, r5, [sp, #8] + movw r12, #\n + movt r12, #MAGENTA_SYSCALL_MAGIC + svc #0xff00ff + mov r12, #0 + pop {r4-r5} + bx lr +.endif +.if \nargs == 7 + push {r4-r7} + ldrd r4, r5, [sp, #16] + ldr r6, [sp, #24] + movw r12, #\n + movt r12, #MAGENTA_SYSCALL_MAGIC + svc #0xff00ff + mov r12, #0 + pop {r4-r7} + bx lr +.endif +.if \nargs == 8 + push {r4-r7} + ldrd r4, r5, [sp, #16] + ldrd r6, r7, [sp, #24] + movw r12, #\n + movt r12, #MAGENTA_SYSCALL_MAGIC + svc #0xff00ff + mov r12, #0 + pop {r4-r7} + bx lr +.endif +.size \name, . - \name +.endm + +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) syscall nargs32, _magenta_##name, n + +#include + + diff --git a/system/ulib/magenta/syscalls_arm64.S b/system/ulib/magenta/syscalls_arm64.S new file mode 100644 index 000000000..c89da08a7 --- /dev/null +++ b/system/ulib/magenta/syscalls_arm64.S @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* define and implement the magenta syscall wrappers for arm64 */ + +.text + +.macro syscall name, n +.globl \name +.type \name,STT_FUNC +\name: + mov x16, #\n + svc #0xf0f /* magic value to differentiate magenta syscalls */ + ret +.size \name, . - \name +.endm + +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) syscall _magenta_##name, n + +#include + diff --git a/system/ulib/magenta/syscalls_x86_64.S b/system/ulib/magenta/syscalls_x86_64.S new file mode 100644 index 000000000..e4fc64342 --- /dev/null +++ b/system/ulib/magenta/syscalls_x86_64.S @@ -0,0 +1,69 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* define and implement the magenta syscall wrappers for x86-64 */ + +.text + +#define MAGENTA_SYSCALL_MAGIC 0x00ff00ff00000000 + +.macro _syscall nargs, name, n +.globl \name +.type \name,STT_FUNC +\name: +.if \nargs <= 6 + push %r10 + push %r11 + mov %rcx, %r10 + movabs $(MAGENTA_SYSCALL_MAGIC | \n), %rax + syscall + pop %r11 + pop %r10 + ret +.endif +.if \nargs == 7 + push %r10 + push %r11 + push %r12 + mov 0x20(%rsp), %r12 + mov %rcx, %r10 + movabs $(MAGENTA_SYSCALL_MAGIC | \n), %rax + syscall + pop %r13 + pop %r12 + pop %r11 + ret +.endif +.if \nargs == 8 + push %r10 + push %r11 + push %r12 + push %r13 + mov 0x28(%rsp), %r12 + mov 0x30(%rsp), %r13 + mov %rcx, %r10 + movabs $(MAGENTA_SYSCALL_MAGIC | \n), %rax + syscall + pop %r13 + pop %r12 + pop %r11 + pop %r10 + ret +.endif +.size \name, . - \name +.endm + +#define MAGENTA_SYSCALL_DEF(nargs64, nargs32, n, ret, name, args...) _syscall nargs64, _magenta_##name, n + +#include diff --git a/system/ulib/mojo/BUILD.gn b/system/ulib/mojo/BUILD.gn new file mode 100644 index 000000000..65d39e9f4 --- /dev/null +++ b/system/ulib/mojo/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_mojo_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("mojo") { + public_configs = [ ":_mojo_config" ] + public = [ + "include/mojo/mojo_string.h", + "include/mojo/mojo_futex.h", + "include/mojo/mojo_types.h", + "include/mojo/mojo_process.h", + "include/mojo/mojo_message_pipe.h", + "include/mojo/mojo_events.h", + "include/mojo/mojo_threads.h", + "include/mojo/mojo_interrupt.h", + "include/mojo/mojo.h", + ] + sources = [ + "mojo.c", + "mojo_strerror.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] + public_deps = [ + "//system/ulib/global", + ] +} diff --git a/system/ulib/mojo/include/mojo/mojo.h b/system/ulib/mojo/include/mojo/mojo.h new file mode 100644 index 000000000..0acadb41a --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo.h @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "mojo_types.h" + +__BEGIN_CDECLS; + +mojo_result_t mojo_wait(const mojo_handle_t* handles, const mojo_handle_signals_t* signals, + uint32_t num_handles, uint32_t* result_index, mojo_deadline_t deadline, + mojo_handle_signals_t* satisfied_signals, + mojo_handle_signals_t* satisfiable_signals); + +mojo_result_t mojo_close(mojo_handle_t handle); + +void mojo_exit(int ec) __attribute__((noreturn)); + +// returns elapsed microseconds since boot +uint64_t mojo_current_time(void); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_events.h b/system/ulib/mojo/include/mojo/mojo_events.h new file mode 100644 index 000000000..a4bba3266 --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_events.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS; + +mojo_result_t mojo_event_create(mojo_event_options_t options, mojo_handle_t* handle); + +mojo_result_t mojo_event_signal(mojo_handle_t handle); + +mojo_result_t mojo_event_reset(mojo_handle_t handle); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_futex.h b/system/ulib/mojo/include/mojo/mojo_futex.h new file mode 100644 index 000000000..4087b1607 --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_futex.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS; + +mojo_result_t mojo_futex_wait(int* value_ptr, int current_value, mojo_deadline_t timeout); +mojo_result_t mojo_futex_wake(int* value_ptr, uint32_t count); +mojo_result_t mojo_futex_requeue(int* wake_ptr, uint32_t wake_count, int current_value, + int* requeue_ptr, uint32_t requeue_count); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_interrupt.h b/system/ulib/mojo/include/mojo/mojo_interrupt.h new file mode 100644 index 000000000..207ad547c --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_interrupt.h @@ -0,0 +1,26 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS; + +mojo_result_t mojo_interrupt_event_create(uint32_t vector, uint32_t flags, mojo_handle_t* handle); + +mojo_result_t mojo_interrupt_event_complete(mojo_handle_t handle); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_message_pipe.h b/system/ulib/mojo/include/mojo/mojo_message_pipe.h new file mode 100644 index 000000000..c0151ad49 --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_message_pipe.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS; + +// TODO(jamesr): message pipe creation options. +mojo_result_t mojo_create_message_pipe(mojo_handle_t* handle0, mojo_handle_t* handle1); + +mojo_result_t mojo_read_message(mojo_handle_t handle, void* bytes, uint32_t* num_bytes, + mojo_handle_t* handles, uint32_t* num_handles, + mojo_handle_signals_t flags); + +mojo_result_t mojo_write_message(mojo_handle_t handle, const void* bytes, uint32_t num_bytes, + const mojo_handle_t* handles, uint32_t num_handles, uint32_t flags); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_process.h b/system/ulib/mojo/include/mojo/mojo_process.h new file mode 100644 index 000000000..3d051615b --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_process.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS; + +mojo_result_t mojo_process_create(mojo_handle_t* out_handle); +mojo_result_t mojo_process_load(mojo_handle_t handle, const char* name); +mojo_result_t mojo_process_start(mojo_handle_t handle, mojo_handle_t handle_arg); +mojo_result_t mojo_process_join(mojo_handle_t handle, int* out_retcode); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_string.h b/system/ulib/mojo/include/mojo/mojo_string.h new file mode 100644 index 000000000..0feaa5494 --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_string.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _MOJO_STRING_H +#define _MOJO_STRING_H + +#include "mojo_types.h" +#include + +__BEGIN_CDECLS; + +const char* mojo_strerror(mojo_result_t e); + +__END_CDECLS; + +#endif diff --git a/system/ulib/mojo/include/mojo/mojo_threads.h b/system/ulib/mojo/include/mojo/mojo_threads.h new file mode 100644 index 000000000..fcdae6091 --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_threads.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS; + +typedef int (*mojo_thread_start_routine)(void* arg); + +mojo_result_t mojo_thread_create(mojo_thread_start_routine entry, void* arg, + mojo_handle_t* out_handle, const char* name); +void mojo_thread_exit(void); +mojo_result_t mojo_thread_join(mojo_handle_t handle, mojo_deadline_t timeout); + +__END_CDECLS; diff --git a/system/ulib/mojo/include/mojo/mojo_types.h b/system/ulib/mojo/include/mojo/mojo_types.h new file mode 100644 index 000000000..e6e76ff8f --- /dev/null +++ b/system/ulib/mojo/include/mojo/mojo_types.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS + +#ifdef _KERNEL +#error "Mojo header files should only be used in userspace" +#endif + +typedef uint32_t mojo_handle_t; +#define MOJO_HANDLE_INVALID ((mojo_handle_t)0) + +typedef uint32_t mojo_result_t; +// The following defines must match the MOJO_RESULT_* defines in Mojo's system/types.h +#define MOJO_RESULT_OK ((mojo_result_t)0) +#define MOJO_RESULT_CANCELLED ((mojo_result_t)1) +#define MOJO_RESULT_UNKNOWN ((mojo_result_t)2) +#define MOJO_RESULT_INVALID_ARGUMENT ((mojo_result_t)3) +#define MOJO_RESULT_DEADLINE_EXCEEDED ((mojo_result_t)4) +#define MOJO_RESULT_NOT_FOUND ((mojo_result_t)5) +#define MOJO_RESULT_ALREADY_EXISTS ((mojo_result_t)6) +#define MOJO_RESULT_PERMISSION_DENIED ((mojo_result_t)7) +#define MOJO_RESULT_RESOURCE_EXHAUSTED ((mojo_result_t)8) +#define MOJO_RESULT_FAILED_PRECONDITION ((mojo_result_t)9) +#define MOJO_RESULT_ABORTED ((mojo_result_t)10) +#define MOJO_RESULT_OUT_OF_RANGE ((mojo_result_t)11) +#define MOJO_RESULT_UNIMPLEMENTED ((mojo_result_t)12) +#define MOJO_RESULT_INTERNAL ((mojo_result_t)13) +#define MOJO_RESULT_UNAVAILABLE ((mojo_result_t)14) +#define MOJO_RESULT_DATA_LOSS ((mojo_result_t)15) +#define MOJO_RESULT_BUSY ((mojo_result_t)16) +#define MOJO_RESULT_SHOULD_WAIT ((mojo_result_t)17) + +typedef uint64_t mojo_deadline_t; +#define MOJO_DEADLINE_INDEFINITE ((mojo_deadline_t)-1) + +typedef uint32_t mojo_handle_signals_t; +#define MOJO_HANDLE_SIGNAL_NONE ((mojo_handle_signals_t)0u) +#define MOJO_HANDLE_SIGNAL_READABLE ((mojo_handle_signals_t)1 << 0u) +#define MOJO_HANDLE_SIGNAL_WRITABLE ((mojo_handle_signals_t)1 << 1u) +#define MOJO_HANDLE_SIGNAL_PEER_CLOSED ((mojo_handle_signals_t)1 << 2u) +#define MOJO_HANDLE_SIGNAL_SIGNALED ((mojo_handle_signals_t)1 << 3u) + +typedef uint32_t mojo_event_options_t; +#define MOJO_EVENT_INITALLY_SIGNALED ((mojo_event_options_t)1 << 0u) + +__END_CDECLS diff --git a/system/ulib/mojo/mojo.c b/system/ulib/mojo/mojo.c new file mode 100644 index 000000000..3e768443e --- /dev/null +++ b/system/ulib/mojo/mojo.c @@ -0,0 +1,317 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static mx_time_t mojo_to_mx_time(mojo_deadline_t t) { + if (t == MOJO_DEADLINE_INDEFINITE) return MX_TIME_INFINITE; + // Convert microseconds to nanoseconds + return (mx_time_t)(t * 1000); +} + +static mojo_result_t lk_to_mojo_error(mx_status_t err) { + switch (err) { + case NO_ERROR: + return MOJO_RESULT_OK; + case ERR_GENERIC: + return MOJO_RESULT_UNKNOWN; + case ERR_NOT_FOUND: + return MOJO_RESULT_NOT_FOUND; + case ERR_NOT_READY: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_NO_MSG: + return MOJO_RESULT_INTERNAL; + case ERR_NO_MEMORY: + return MOJO_RESULT_RESOURCE_EXHAUSTED; + case ERR_ALREADY_STARTED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_NOT_VALID: + return MOJO_RESULT_INTERNAL; + case ERR_INVALID_ARGS: + return MOJO_RESULT_INVALID_ARGUMENT; + case ERR_NOT_ENOUGH_BUFFER: + return MOJO_RESULT_RESOURCE_EXHAUSTED; + case ERR_NOT_SUSPENDED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_OBJECT_DESTROYED: // returned from wait_queue_destroy + return MOJO_RESULT_ABORTED; + case ERR_NOT_BLOCKED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_TIMED_OUT: + return MOJO_RESULT_DEADLINE_EXCEEDED; + case ERR_ALREADY_EXISTS: + return MOJO_RESULT_ALREADY_EXISTS; + case ERR_CHANNEL_CLOSED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_OFFLINE: + return MOJO_RESULT_UNAVAILABLE; + case ERR_NOT_ALLOWED: + return MOJO_RESULT_PERMISSION_DENIED; + case ERR_BAD_PATH: + return MOJO_RESULT_INVALID_ARGUMENT; + case ERR_ALREADY_MOUNTED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_IO: + return MOJO_RESULT_INTERNAL; + case ERR_NOT_DIR: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_NOT_FILE: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_RECURSE_TOO_DEEP: + return MOJO_RESULT_INTERNAL; + case ERR_NOT_SUPPORTED: + return MOJO_RESULT_UNIMPLEMENTED; + case ERR_TOO_BIG: + return MOJO_RESULT_OUT_OF_RANGE; + case ERR_CANCELLED: + return MOJO_RESULT_ABORTED; + case ERR_NOT_IMPLEMENTED: + return MOJO_RESULT_UNIMPLEMENTED; + case ERR_CHECKSUM_FAIL: + return MOJO_RESULT_DATA_LOSS; + case ERR_CRC_FAIL: + return MOJO_RESULT_DATA_LOSS; + case ERR_CMD_UNKNOWN: + return MOJO_RESULT_INTERNAL; + case ERR_BAD_STATE: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_BAD_LEN: + return MOJO_RESULT_INTERNAL; + case ERR_BUSY: + return MOJO_RESULT_BUSY; + case ERR_THREAD_DETACHED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_I2C_NACK: + return MOJO_RESULT_DATA_LOSS; + case ERR_ALREADY_EXPIRED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_OUT_OF_RANGE: + return MOJO_RESULT_OUT_OF_RANGE; + case ERR_NOT_CONFIGURED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_NOT_MOUNTED: + return MOJO_RESULT_FAILED_PRECONDITION; + case ERR_FAULT: + return MOJO_RESULT_INTERNAL; + case ERR_NO_RESOURCES: + return MOJO_RESULT_RESOURCE_EXHAUSTED; + case ERR_BAD_HANDLE: + return MOJO_RESULT_INTERNAL; + case ERR_ACCESS_DENIED: + return MOJO_RESULT_PERMISSION_DENIED; + case ERR_PARTIAL_WRITE: + return MOJO_RESULT_RESOURCE_EXHAUSTED; + default: + return MOJO_RESULT_UNKNOWN; + } +} + +mojo_result_t mojo_close(mojo_handle_t handle) { + return lk_to_mojo_error(_magenta_handle_close(handle)); +} + +mojo_result_t mojo_duplicate(mojo_handle_t handle, mojo_handle_t* out_handle) { + mx_handle_t result = _magenta_handle_duplicate(handle); + if (result < 0) return lk_to_mojo_error(result); + *out_handle = result; + return MOJO_RESULT_OK; +} + +mojo_result_t mojo_wait(const mojo_handle_t* handles, const mojo_handle_signals_t* signals, + uint32_t num_handles, uint32_t* result_index, mojo_deadline_t deadline, + mojo_handle_signals_t* satisfied_signals, + mojo_handle_signals_t* satisfiable_signals) { + mx_status_t result; + + if (num_handles == 1u) { + result = + _magenta_handle_wait_one(*handles, *signals, mojo_to_mx_time(deadline), + satisfied_signals, satisfiable_signals); + } else { + result = _magenta_handle_wait_many(num_handles, (mx_handle_t*)handles, signals, + mojo_to_mx_time(deadline), + satisfied_signals, satisfiable_signals); + } + + // TODO(cpu): implement |result_index|, see MG-33 bug. + return lk_to_mojo_error(result); +} + +mojo_result_t mojo_create_message_pipe(mojo_handle_t* handle0, mojo_handle_t* handle1) { + mx_handle_t result = _magenta_message_pipe_create((mx_handle_t*)handle1); + if (result < 0) return lk_to_mojo_error(result); + *handle0 = result; + return MOJO_RESULT_OK; +} + +mojo_result_t mojo_read_message(mojo_handle_t handle, void* bytes, uint32_t* num_bytes, + mojo_handle_t* handles, uint32_t* num_handles, uint32_t flags) { + return lk_to_mojo_error( + _magenta_message_read(handle, bytes, num_bytes, (mx_handle_t*)handles, num_handles, flags)); +} + +mojo_result_t mojo_write_message(mojo_handle_t handle, const void* bytes, uint32_t num_bytes, + const mojo_handle_t* handles, uint32_t num_handles, + uint32_t flags) { + return lk_to_mojo_error( + _magenta_message_write(handle, bytes, num_bytes, (mx_handle_t*)handles, num_handles, flags)); +} + +void mojo_exit(int ec) { + // call the exit syscall in a loop to satisfy compiler NO_RETURN semantics + for (;;) + _magenta_exit(ec); +} + +// returns elapsed microseconds since boot +uint64_t mojo_current_time(void) { + return _magenta_current_time(); +} + +struct thread_args { + mojo_thread_start_routine entry; + void* arg; +}; + +/* Wrapper for our thread to make sure thread_exit gets called */ +static int thread_entry(void* args) { + struct thread_args* ta = args; + mojo_thread_start_routine entry = ta->entry; + void* arg = ta->arg; + free(args); + + int rc = entry(arg); + _magenta_thread_exit(); + return rc; +} + +mojo_result_t mojo_thread_create(mojo_thread_start_routine entry, void* arg, + mojo_handle_t* out_handle, const char* name) { + struct thread_args* ta = malloc(sizeof(struct thread_args)); + if (!ta) { + return MOJO_RESULT_RESOURCE_EXHAUSTED; + } + ta->entry = entry; + ta->arg = arg; + if (!name) name = ""; + mx_handle_t result = _magenta_thread_create(thread_entry, ta, name, strlen(name) + 1); + if (result < 0) return lk_to_mojo_error(result); + *out_handle = result; + return MOJO_RESULT_OK; +} + +void mojo_thread_exit(void) { + _magenta_thread_exit(); +} + +mojo_result_t mojo_thread_join(mojo_handle_t handle, mojo_deadline_t timeout) { + // TODO: add timeout + mx_status_t result = _magenta_handle_wait_one(handle, MX_SIGNAL_SIGNALED, + mojo_to_mx_time(timeout), NULL, NULL); + return lk_to_mojo_error(result); +} + +mojo_result_t mojo_interrupt_event_create(uint32_t vector, uint32_t flags, + mojo_handle_t* out_handle) { + mx_handle_t result = _magenta_interrupt_event_create(vector, flags); + if (result < 0) return lk_to_mojo_error(result); + *out_handle = result; + return MOJO_RESULT_OK; +} + +mojo_result_t mojo_interrupt_event_complete(mojo_handle_t handle) { + return lk_to_mojo_error(_magenta_interrupt_event_complete(handle)); +} + +mojo_result_t mojo_interrupt_event_wait(mojo_handle_t handle) { + return lk_to_mojo_error(_magenta_interrupt_event_wait(handle)); +} + +mojo_result_t mojo_process_create(mojo_handle_t* out_handle) { + // TODO(cpu): Get Mojo processes a name. + char pname[] = "mojo"; + mx_handle_t result = _magenta_process_create(pname, sizeof(pname)); + if (result < 0) return lk_to_mojo_error(result); + *out_handle = result; + return MOJO_RESULT_OK; +} + +mojo_result_t mojo_process_load(mojo_handle_t handle, const char* name) { + return MOJO_RESULT_UNIMPLEMENTED; +} + +mojo_result_t mojo_process_start(mojo_handle_t handle, mojo_handle_t handle_arg) { + return lk_to_mojo_error(_magenta_process_start(handle, handle_arg, 0)); +} + +mojo_result_t mojo_process_join(mojo_handle_t handle, int* out_retcode) { + *out_retcode = 0; + + // wait for the process to exit + mx_status_t r = _magenta_handle_wait_one(handle, MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL); + if (r != NO_ERROR) + return lk_to_mojo_error(r); + + // read the return code + if (out_retcode) { + mx_process_info_t proc_info; + r = _magenta_process_get_info(handle, &proc_info, sizeof(proc_info)); + if (r != NO_ERROR) + return lk_to_mojo_error(r); + + *out_retcode = proc_info.return_code; + } + + return MOJO_RESULT_OK; +} + +mojo_result_t mojo_event_create(uint32_t options, mojo_handle_t* out_handle) { + mx_handle_t result = _magenta_event_create(options); + if (result < 0) return lk_to_mojo_error(result); + *out_handle = result; + return MOJO_RESULT_OK; +} + +mojo_result_t mojo_event_signal(mojo_handle_t handle) { + return lk_to_mojo_error(_magenta_event_signal(handle)); +} + +mojo_result_t mojo_event_reset(mojo_handle_t handle) { + return lk_to_mojo_error(_magenta_event_reset(handle)); +} + +mojo_result_t mojo_futex_wait(int* value_ptr, int current_value, mojo_deadline_t timeout) { + return lk_to_mojo_error( + _magenta_futex_wait(value_ptr, current_value, mojo_to_mx_time(timeout))); +} + +mojo_result_t mojo_futex_wake(int* value_ptr, uint32_t count) { + return lk_to_mojo_error(_magenta_futex_wake(value_ptr, count)); +} + +mojo_result_t mojo_futex_requeue(int* wake_ptr, uint32_t wake_count, int current_value, + int* requeue_ptr, uint32_t requeue_count) { + return lk_to_mojo_error( + _magenta_futex_requeue(wake_ptr, wake_count, current_value, requeue_ptr, requeue_count)); +} diff --git a/system/ulib/mojo/mojo_strerror.c b/system/ulib/mojo/mojo_strerror.c new file mode 100644 index 000000000..e2bc2b0e2 --- /dev/null +++ b/system/ulib/mojo/mojo_strerror.c @@ -0,0 +1,47 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +static struct { + mojo_result_t result; + const char* message; +} messages[] = { + { MOJO_RESULT_CANCELLED, "Operation cancelled" }, + { MOJO_RESULT_NOT_FOUND, "Resource not found" }, + { MOJO_RESULT_FAILED_PRECONDITION, "Failed precondition" }, + { MOJO_RESULT_INTERNAL, "Internal Error" }, + { MOJO_RESULT_RESOURCE_EXHAUSTED, "Not enough resources" }, + { MOJO_RESULT_INVALID_ARGUMENT, "Invalid argument" }, + { MOJO_RESULT_ABORTED, "Aborted" }, + { MOJO_RESULT_DEADLINE_EXCEEDED, "Timed out" }, + { MOJO_RESULT_ALREADY_EXISTS, "Resource already exists" }, + { MOJO_RESULT_UNAVAILABLE, "Resource unavailabe" }, + { MOJO_RESULT_PERMISSION_DENIED, "Permission denied" }, + { MOJO_RESULT_UNIMPLEMENTED, "Not implemented" }, + { MOJO_RESULT_OUT_OF_RANGE, "Out of range" }, + { MOJO_RESULT_DATA_LOSS, "Possible data loss" }, + { MOJO_RESULT_BUSY, "Resource busy" }, + { MOJO_RESULT_SHOULD_WAIT, "Should wait" }, + { MOJO_RESULT_UNKNOWN, "Unknown error" }, + { MOJO_RESULT_OK, "Success" }, +}; + +const char* mojo_strerror(mojo_result_t result) { + for (size_t idx = 0; idx < sizeof(messages) / sizeof(*messages); idx++) + if (result == messages[idx].result) + return messages[idx].message; + return "No error information"; +} diff --git a/system/ulib/mojo/rules.mk b/system/ulib/mojo/rules.mk new file mode 100644 index 000000000..61f162094 --- /dev/null +++ b/system/ulib/mojo/rules.mk @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS += \ + $(LOCAL_DIR)/mojo.c \ + $(LOCAL_DIR)/mojo_strerror.c \ + +MODULE_DEPS := ulib/magenta + +include make/module.mk diff --git a/system/ulib/mxio/BUILD.gn b/system/ulib/mxio/BUILD.gn new file mode 100644 index 000000000..3045e73b8 --- /dev/null +++ b/system/ulib/mxio/BUILD.gn @@ -0,0 +1,55 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_mxio_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("mxio") { + public_configs = [ ":_mxio_config" ] + public = [ + "include/mxio/debug.h", + "include/mxio/dispatcher.h", + "include/mxio/io.h", + "include/mxio/remoteio.h", + "include/mxio/util.h", + "include/mxio/vfs.h", + ] + sources = [ + "bootfs.c", + "debug.c", + "dispatcher.c", + "elf.c", + "elf.h", + "elf_defines.h", + "logger.c", + "null.c", + "pipe.c", + "process.c", + "remoteio.c", + "unistd.c", + "util.c", + "util.h", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxu", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] + public_deps = [ + "//system/ulib/magenta", + ] +} diff --git a/system/ulib/mxio/bootfs.c b/system/ulib/mxio/bootfs.c new file mode 100644 index 000000000..b9a680697 --- /dev/null +++ b/system/ulib/mxio/bootfs.c @@ -0,0 +1,78 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +#define BOOTFS_MAX_NAME_LEN 256 + +static const char FSMAGIC[16] = "[BOOTFS]\0\0\0\0\0\0\0\0"; + +// BOOTFS is a trivial "filesystem" format +// +// It has a 16 byte magic/version value (FSMAGIC) +// Followed by a series of records of: +// namelength (32bit le) +// filesize (32bit le) +// fileoffset (32bit le) +// namedata (namelength bytes, includes \0) +// +// - fileoffsets must be page aligned (multiple of 4096) + +#define NLEN 0 +#define FSIZ 1 +#define FOFF 2 + +void bootfs_parse(void* _data, int len, + void (*cb)(const char* fn, size_t off, size_t len)) { + uint8_t* data = _data; + uint8_t* end = data + len; + char name[BOOTFS_MAX_NAME_LEN]; + uint32_t header[3]; + + if (memcmp(data, FSMAGIC, sizeof(FSMAGIC))) { + return; + } + data += sizeof(FSMAGIC); + + while ((end - data) > (int)sizeof(header)) { + memcpy(header, data, sizeof(header)); + data += sizeof(header); + + // check for end marker + if (header[NLEN] == 0) break; + + // require reasonable filename size + if ((header[NLEN] < 2) || (header[NLEN] > BOOTFS_MAX_NAME_LEN)) { + break; + } + + // require correct alignment + if (header[FOFF] & 4095) { + break; + } + + if ((end - data) < (off_t)header[NLEN]) { + break; + } + memcpy(name, data, header[NLEN]); + data += header[NLEN]; + name[header[NLEN] - 1] = 0; + + cb(name, header[FOFF], header[FSIZ]); + } +} diff --git a/system/ulib/mxio/debug.c b/system/ulib/mxio/debug.c new file mode 100644 index 000000000..35563e33e --- /dev/null +++ b/system/ulib/mxio/debug.c @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include +#include +#include + +#include +#include + +void cprintf(const char* fmt, ...) { + char buf[128]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + _magenta_debug_write(buf, strlen(buf)); +} diff --git a/system/ulib/mxio/dispatcher.c b/system/ulib/mxio/dispatcher.c new file mode 100644 index 000000000..767bd4884 --- /dev/null +++ b/system/ulib/mxio/dispatcher.c @@ -0,0 +1,178 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define MXDEBUG 0 + +typedef struct { + list_node_t node; + mx_handle_t h; + void* cb; + void* cookie; +} handler_t; + +#define MAX_HANDLERS 128 + +struct mxio_dispatcher { + list_node_t list; + mx_handle_t tx; + mx_handle_t rx; + mxr_thread_t* t; + mxio_dispatcher_cb_t cb; + + mx_handle_t handles[MAX_HANDLERS + 1]; + mx_signals_t wsigs[MAX_HANDLERS + 1]; + mx_signals_t ssigs[MAX_HANDLERS + 1]; +}; + +static void mxio_dispatcher_destroy(mxio_dispatcher_t* md) { + _magenta_handle_close(md->tx); + _magenta_handle_close(md->rx); + free(md); +} + +static void remove_handler(mxio_dispatcher_t* md, handler_t* handler, mx_status_t r) { + list_delete(&handler->node); + if (r < 0) { + md->cb(0, handler->cb, handler->cookie); + } + xprintf("handler(%x) done, status=%d\n", handler->h, r); + _magenta_handle_close(handler->h); + free(handler); +} + +static int mxio_dispatcher_thread(void* _md) { + mxio_dispatcher_t* md = _md; + handler_t* handler; + mx_status_t r; + int i, count; + +setup: + count = 0; + list_for_every_entry (&md->list, handler, handler_t, node) { + md->handles[count] = handler->h; + md->wsigs[count] = MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED; + count++; + } + md->handles[count] = md->rx; + md->wsigs[count] = MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED; + + xprintf("dispatcher: listening to %d pipe%s\n", count, (count == 1) ? "" : "s"); + for (;;) { + r = _magenta_handle_wait_many(count + 1, md->handles, md->wsigs, MX_TIME_INFINITE, + md->ssigs, NULL); + if (r < 0) { + xprintf("dispatcher: wait many failed %d\n", r); + break; + } + i = 0; + list_for_every_entry (&md->list, handler, handler_t, node) { + if (md->ssigs[i] & MX_SIGNAL_READABLE) { + if ((r = md->cb(handler->h, handler->cb, handler->cookie)) != 0) { + remove_handler(md, handler, r); + goto setup; + } + } + if (md->ssigs[i] & MX_SIGNAL_PEER_CLOSED) { + remove_handler(md, handler, ERR_CHANNEL_CLOSED); + goto setup; + } + i++; + } + if (md->ssigs[count] & MX_SIGNAL_READABLE) { + uint32_t sz = sizeof(handler_t); + handler_t a; + if ((r = _magenta_message_read(md->rx, &a, &sz, NULL, NULL, 0)) < 0) { + xprintf("dispatcher: read failure on new handle pipe %d\n", r); + break; + } + if (count == MAX_HANDLERS) { + // TODO: support growing the table, or use waitsets + md->cb(0, a.cb, a.cookie); + _magenta_handle_close(a.h); + xprintf("dispatcher(%x) discarding handler, out of memory\n", a.h); + break; + } + if ((handler = malloc(sizeof(handler_t))) == NULL) { + md->cb(0, a.cb, a.cookie); + _magenta_handle_close(a.h); + xprintf("dispatcher(%x) discarding handler, out of memory\n", a.h); + break; + } + memcpy(handler, &a, sizeof(handler_t)); + xprintf("dispatcher(%x) added %p\n", handler->h, handler->cb); + list_add_tail(&md->list, &handler->node); + goto setup; + } + } + + mxio_dispatcher_destroy(md); + return NO_ERROR; +} + +mx_status_t mxio_dispatcher_create(mxio_dispatcher_t** out, mxio_dispatcher_cb_t cb) { + mxio_dispatcher_t* md; + if ((md = malloc(sizeof(*md))) == NULL) { + return ERR_NO_MEMORY; + } + xprintf("mxio_dispatcher_create: %p\n", md); + list_initialize(&md->list); + if ((md->tx = _magenta_message_pipe_create(&md->rx)) < 0) { + mx_status_t r = md->tx; + free(md); + return r; + } + md->cb = cb; + *out = md; + return NO_ERROR; +} + +// TODO: protect against double-start +mx_status_t mxio_dispatcher_start(mxio_dispatcher_t* md) { + if (mxr_thread_create(mxio_dispatcher_thread, md, "mxio-dispatcher", &md->t)) { + mxio_dispatcher_destroy(md); + return ERR_NO_RESOURCES; + } + mxr_thread_detach(md->t); + return NO_ERROR; +} + +// TODO: protect against double-start +void mxio_dispatcher_run(mxio_dispatcher_t* md) { + mxio_dispatcher_thread(md); +} + +// TODO: error in the event of dispatcher out of resources? +mx_status_t mxio_dispatcher_add(mxio_dispatcher_t* md, mx_handle_t h, void* cb, void* cookie) { + handler_t handler; + mx_status_t r; + + handler.h = h; + handler.cb = cb; + handler.cookie = cookie; + if ((r = _magenta_message_write(md->tx, &handler, sizeof(handler), NULL, 0, 0)) < 0) { + return r; + } + return 0; +} diff --git a/system/ulib/mxio/elf.c b/system/ulib/mxio/elf.c new file mode 100644 index 000000000..8a41c4286 --- /dev/null +++ b/system/ulib/mxio/elf.c @@ -0,0 +1,241 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include "elf.h" + +#include +#include + +//#define LTRACEF(fmt...) printf(fmt) +#define LTRACEF(fmt...) do {} while (0) + +/* conditionally define a 32 or 64 bit version of the data structures + * we care about, based on our bitness. + */ +#if WITH_ELF32 +typedef struct Elf32_Ehdr elf_ehdr_t; +typedef struct Elf32_Phdr elf_phdr_t; + +#define ELF_OFF_PRINT_U "%u" +#define ELF_OFF_PRINT_X "%x" +#define ELF_ADDR_PRINT_U "%u" +#define ELF_ADDR_PRINT_X "%x" +#else +typedef struct Elf64_Ehdr elf_ehdr_t; +typedef struct Elf64_Phdr elf_phdr_t; + +#define ELF_OFF_PRINT_U "%llu" +#define ELF_OFF_PRINT_X "%llx" +#define ELF_ADDR_PRINT_U "%llu" +#define ELF_ADDR_PRINT_X "%llx" +#endif + +mx_status_t elf_open_handle(elf_handle_t* handle, mx_handle_t proc_handle, + elf_read_hook_t rh, elf_load_hook_t lh, void* arg) { + if (!handle) return ERR_INVALID_ARGS; + if (!proc_handle) return ERR_INVALID_ARGS; + if (!rh) return ERR_INVALID_ARGS; + if (!lh) return ERR_INVALID_ARGS; + + memset(handle, 0, sizeof(*handle)); + + handle->proc = proc_handle; + handle->read_hook = rh; + handle->load_hook = lh; + handle->arg = arg; + + handle->open = true; + + return NO_ERROR; +} + +void elf_close_handle(elf_handle_t* handle) { + if (!handle || !handle->open) + return; + + handle->open = false; + + free(handle->pheaders); + + if (handle->vmo > 0) + _magenta_handle_close(handle->vmo); +} + +static int verify_eheader(const void* header) { + const elf_ehdr_t* eheader = header; + + if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) + return ERR_NOT_FOUND; + +#if WITH_ELF32 + if (eheader->e_ident[EI_CLASS] != ELFCLASS32) + return ERR_NOT_FOUND; +#else + if (eheader->e_ident[EI_CLASS] != ELFCLASS64) + return ERR_NOT_FOUND; +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN + if (eheader->e_ident[EI_DATA] != ELFDATA2LSB) + return ERR_NOT_FOUND; +#elif BYTE_ORDER == BIG_ENDIAN + if (eheader->e_ident[EI_DATA] != ELFDATA2MSB) + return ERR_NOT_FOUND; +#endif + + if (eheader->e_ident[EI_VERSION] != EV_CURRENT) + return ERR_NOT_FOUND; + + if (eheader->e_phoff == 0) + return ERR_NOT_FOUND; + + if (eheader->e_phentsize < sizeof(elf_phdr_t)) + return ERR_NOT_FOUND; + +#if ARCH_ARM + if (eheader->e_machine != EM_ARM) + return ERR_NOT_FOUND; +#elif ARCH_ARM64 + if (eheader->e_machine != EM_AARCH64) + return ERR_NOT_FOUND; +#elif ARCH_X86_64 + if (eheader->e_machine != EM_X86_64) + return ERR_NOT_FOUND; +#elif ARCH_X86_32 + if (eheader->e_machine != EM_386) + return ERR_NOT_FOUND; +#elif ARCH_MICROBLAZE + if (eheader->e_machine != EM_MICROBLAZE) + return ERR_NOT_FOUND; +#else +#error find proper EM_ define for your machine +#endif + + return NO_ERROR; +} + + +mx_status_t elf_load(elf_handle_t* handle) { + if (!handle) + return ERR_INVALID_ARGS; + if (!handle->open) + return ERR_NOT_READY; + + // validate that this is an ELF file + ssize_t readerr = handle->read_hook(handle, &handle->eheader, + 0, sizeof(handle->eheader)); + if (readerr < (ssize_t)sizeof(handle->eheader)) { + LTRACEF("couldn't read elf header\n"); + return ERR_NOT_FOUND; + } + + if (verify_eheader(&handle->eheader)) { + LTRACEF("header not valid\n"); + return ERR_NOT_FOUND; + } + + // sanity check number of program headers + LTRACEF("number of program headers %u, entry size %u\n", + handle->eheader.e_phnum, handle->eheader.e_phentsize); + if (handle->eheader.e_phnum > 16 || + handle->eheader.e_phentsize != sizeof(elf_phdr_t)) { + LTRACEF("too many program headers or bad size\n"); + return ERR_NO_MEMORY; + } + + // allocate and read in the program headers + handle->pheaders = calloc(1, handle->eheader.e_phnum * handle->eheader.e_phentsize); + if (!handle->pheaders) { + LTRACEF("failed to allocate memory for program headers\n"); + return ERR_NO_MEMORY; + } + + readerr = handle->read_hook(handle, handle->pheaders, handle->eheader.e_phoff, + handle->eheader.e_phnum * handle->eheader.e_phentsize); + if (readerr < (ssize_t)(handle->eheader.e_phnum * handle->eheader.e_phentsize)) { + LTRACEF("failed to read program headers\n"); + return ERR_NO_MEMORY; + } + + LTRACEF("program headers:\n"); + for (uint i = 0; i < handle->eheader.e_phnum; i++) { + // parse the program headers + elf_phdr_t* pheader = &handle->pheaders[i]; + + LTRACEF("%u: type %u offset 0x" ELF_OFF_PRINT_X " vaddr " ELF_ADDR_PRINT_X " paddr " + ELF_ADDR_PRINT_X " memsiz " ELF_ADDR_PRINT_U " filesize " ELF_ADDR_PRINT_U + " flags 0x%x\n", + i, pheader->p_type, pheader->p_offset, pheader->p_vaddr, + pheader->p_paddr, pheader->p_memsz, pheader->p_filesz, pheader->p_flags); + + // we only care about PT_LOAD segments at the moment + if (pheader->p_type == PT_LOAD) { + // allocate a block of memory to back the segment + if (handle->vmo != 0) { + _magenta_handle_close(handle->vmo); + } + + // Some binaries declare program headers that + // do not start aligned to a page boundary. + // Fix that up so we don't make the vmo mapping + // unhappy later, and things get loaded correctly. + uint64_t align = 0; + handle->vmo_addr = (uintptr_t)pheader->p_vaddr; + if (handle->vmo_addr & (PAGE_SIZE - 1)) { + handle->vmo_addr &= (~(PAGE_SIZE - 1)); + align = PAGE_SIZE - (handle->vmo_addr & (PAGE_SIZE - 1)); + } + + handle->vmo = _magenta_vm_object_create(pheader->p_memsz + align); + if (handle->vmo < 0) { + LTRACEF("failed to allocate VMO to back elf segment at 0x%lx\n", handle->vmo_addr); + return ERR_NO_MEMORY; + } + + // map it in the target address space + uint32_t mx_flags = MX_VM_FLAG_FIXED; + mx_flags |= (pheader->p_flags & PF_R) ? MX_VM_FLAG_PERM_READ : 0; + mx_flags |= (pheader->p_flags & PF_W) ? MX_VM_FLAG_PERM_WRITE : 0; + mx_flags |= (pheader->p_flags & PF_X) ? MX_VM_FLAG_PERM_EXECUTE : 0; + uintptr_t ptr = handle->vmo_addr; + mx_status_t status = _magenta_process_vm_map(handle->proc, handle->vmo, 0, + pheader->p_memsz + align, &ptr, mx_flags); + if (status < 0) { + LTRACEF("failed to map VMO to back elf segment at 0x%lx\n", handle->vmo_addr); + return ERR_NO_MEMORY; + } + + // read the file portion of the segment into memory at vaddr + readerr = handle->load_hook(handle, pheader->p_vaddr, + pheader->p_offset, pheader->p_filesz); + if (readerr < (ssize_t)pheader->p_filesz) { + LTRACEF("error %ld reading program header %u\n", readerr, i); + return (readerr < 0) ? readerr : ERR_IO; + } + } + } + + // save the entry point + handle->entry = handle->eheader.e_entry; + + return NO_ERROR; +} diff --git a/system/ulib/mxio/elf.h b/system/ulib/mxio/elf.h new file mode 100644 index 000000000..115f30b63 --- /dev/null +++ b/system/ulib/mxio/elf.h @@ -0,0 +1,86 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "elf_defines.h" + +#include +#include +#include +#include + +/* based on our bitness, support 32 or 64 bit elf */ +#if IS_64BIT +#define WITH_ELF64 1 +#else +#define WITH_ELF32 1 +#endif + +__BEGIN_CDECLS + +/* based on our bitness, support 32 or 64 bit elf */ +#if IS_64BIT +#define WITH_ELF64 1 +#else +#define WITH_ELF32 1 +#endif + +/* api */ +typedef struct elf_handle elf_handle_t; + +// read data from elf image into buffer +typedef ssize_t (*elf_read_hook_t)(elf_handle_t*, void* buf, uintptr_t offset, size_t len); + +// read data (or zeros if offset==0) from elf image into new process +typedef mx_status_t (*elf_load_hook_t)(elf_handle_t*, uintptr_t vaddr, uintptr_t offset, size_t len); + +struct elf_handle { + bool open; + + // read hook to load binary out of memory + elf_read_hook_t read_hook; + // memory allocation callback + elf_load_hook_t load_hook; + + // handle to process to load into + mx_handle_t proc; + + // data for callbacks + void* arg; + +// loaded info about the elf file +#if WITH_ELF32 + struct Elf32_Ehdr eheader; // a copy of the main elf header + struct Elf32_Phdr* pheaders; // a pointer to a buffer of program headers +#else + struct Elf64_Ehdr eheader; // a copy of the main elf header + struct Elf64_Phdr* pheaders; // a pointer to a buffer of program headers +#endif + + // current vmo + mx_handle_t vmo; + uintptr_t vmo_addr; + + uintptr_t load_address; + uintptr_t entry; +}; + +mx_status_t elf_open_handle(elf_handle_t* handle, mx_handle_t proc_handle, + elf_read_hook_t rh, elf_load_hook_t lh, void* arg); +mx_status_t elf_load(elf_handle_t* handle); +void elf_close_handle(elf_handle_t* handle); + +__END_CDECLS diff --git a/system/ulib/mxio/elf_defines.h b/system/ulib/mxio/elf_defines.h new file mode 100644 index 000000000..d9a755575 --- /dev/null +++ b/system/ulib/mxio/elf_defines.h @@ -0,0 +1,580 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2015 Travis Geiselbrecht +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +/* elf defines */ +#define ELF_MAGIC "\x7f" \ + "ELF" + +/* e_ident */ +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +/* e_machine */ +#define EM_NONE 0 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_MIPS 8 +#define EM_SPARC32PLUS 18 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_ARM 40 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_IA_64 50 +#define EM_X86_64 62 +#define EM_OR1K 92 +#define EM_AARCH64 183 +#define EM_MICROBLAZE 189 +#define EM_ALPHA 0x9026 + +/* e_ident[EI_CLASS] */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +/* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +/* e_ident[EI_VERSION] */ +#define EV_CURRENT 1 + +/* e_type */ +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 + +/* e_flags */ +#define EF_ARM_RELEXEC 0x1 +#define EF_ARM_HASENTRY 0x2 +#define EF_ARM_SYMSARESORTED 0x4 +#define EF_ARM_DYNSYMSUSESEGIDX 0x8 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_LE8 0x00400000 +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_EABIMASK 0xFF000000 +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 +#define EF_ARM_INTERWORK 0x00000004 +#define EF_ARM_APCS_26 0x00000008 +#define EF_ARM_APCS_FLOAT 0x00000010 +#define EF_ARM_PIC 0x00000020 +#define EF_ARM_ALIGN8 0x00000040 +#define EF_ARM_NEW_ABI 0x00000080 +#define EF_ARM_OLD_ABI 0x00000100 +#define EF_ARM_SOFT_FLOAT 0x00000200 +#define EF_ARM_VFP_FLOAT 0x00000400 +#define EF_ARM_MAVERICK_FLOAT 0x00000800 + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_TLS 0x400 +#define SHF_MASKPROC 0xf0000000 + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 +#define PF_MASKPROC 0xf0000000 + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_TLS 6 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STN_UNDEF 0 + +/* d_tag */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6fff0000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* + * i386 relocation types + */ +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +/* + * x86-64 relocation types + */ +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DPTMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 +#define R_X86_64_TLSLD 20 +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 +#define R_X86_64_TPOFF32 23 + +/* + * sh4 relocation types + */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 + +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_LOOP_START 36 +#define R_SH_LOOP_END 37 +#define R_SH_DIR5U 45 +#define R_SH_DIR6U 46 +#define R_SH_DIR6S 47 +#define R_SH_DIR10S 48 +#define R_SH_DIR10SW 49 +#define R_SH_DIR10SL 50 +#define R_SH_DIR10SQ 51 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +#define R_SH_GOTPLT32 168 +#define R_SH_GOT_LOW16 169 +#define R_SH_GOT_MEDLOW16 170 +#define R_SH_GOT_MEDHI16 171 +#define R_SH_GOT_HI16 172 +#define R_SH_GOTPLT_LOW16 173 +#define R_SH_GOTPLT_MEDLOW16 174 +#define R_SH_GOTPLT_MEDHI16 175 +#define R_SH_GOTPLT_HI16 176 +#define R_SH_PLT_LOW16 177 +#define R_SH_PLT_MEDLOW16 178 +#define R_SH_PLT_MEDHI16 179 +#define R_SH_PLT_HI16 180 +#define R_SH_GOTOFF_LOW16 181 +#define R_SH_GOTOFF_MEDLOW16 182 +#define R_SH_GOTOFF_MEDHI16 183 +#define R_SH_GOTOFF_HI16 184 +#define R_SH_GOTPC_LOW16 185 +#define R_SH_GOTPC_MEDLOW16 186 +#define R_SH_GOTPC_MEDHI16 187 +#define R_SH_GOTPC_HI16 188 +#define R_SH_GOT10BY4 189 +#define R_SH_GOTPLT10BY4 190 +#define R_SH_GOT10BY8 191 +#define R_SH_GOTPLT10BY8 192 +#define R_SH_COPY64 193 +#define R_SH_GLOB_DAT64 194 +#define R_SH_JMP_SLOT64 195 +#define R_SH_RELATIVE64 196 +#define R_SH_SHMEDIA_CODE 242 +#define R_SH_PT_16 243 +#define R_SH_IMMS16 244 +#define R_SH_IMMU16 245 +#define R_SH_IMM_LOW16 246 +#define R_SH_IMM_LOW16_PCREL 247 +#define R_SH_IMM_MEDLOW16 248 +#define R_SH_IMM_MEDLOW16_PCREL 249 +#define R_SH_IMM_MEDHI16 250 +#define R_SH_IMM_MEDHI16_PCREL 251 +#define R_SH_IMM_HI16 252 +#define R_SH_IMM_HI16_PCREL 253 +#define R_SH_64 254 +#define R_SH_64_PCREL 255 + +/* + * ppc relocation types + */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +#define R_PPC_NUM 37 + +/* + * ARM relocation types + */ +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +/* elf32 stuff */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +struct Elf32_Shdr { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +}; + +struct Elf32_Phdr { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +struct Elf32_Sym { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) + +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +struct Elf32_Dyn { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +/* elf64 stuff */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef int64_t Elf64_Sxword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Lword; +typedef uint64_t Elf64_Xword; + +struct Elf64_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +}; + +struct Elf64_Shdr { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +}; + +struct Elf64_Phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +}; + +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info)&0xf) +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) + +struct Elf64_Rel { + Elf64_Addr r_offset; + Elf64_Xword r_info; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +}; + +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info)&0xffffffffL) + +#define ELF64_R_INFO(sym, type) (((sym) << 32) + ((type)&0xffffffffL)) + +#define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info) << 32) >> 40) +#define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info) << 56) >> 56) +#define ELF64_R_TYPE_INFO(data, type) (((Elf64_Xword)(data) << 8) + (Elf64_Xword)(type)) diff --git a/system/ulib/mxio/include/mxio/debug.h b/system/ulib/mxio/include/mxio/debug.h new file mode 100644 index 000000000..850959643 --- /dev/null +++ b/system/ulib/mxio/include/mxio/debug.h @@ -0,0 +1,29 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +// raw console printf, to go away before long +void cprintf(const char* fmt, ...); + +// per-file chatty debug macro +#define xprintf(fmt...) \ + do { \ + if (MXDEBUG) { \ + cprintf(fmt); \ + } \ + } while (0) diff --git a/system/ulib/mxio/include/mxio/dispatcher.h b/system/ulib/mxio/include/mxio/dispatcher.h new file mode 100644 index 000000000..bcc2c3829 --- /dev/null +++ b/system/ulib/mxio/include/mxio/dispatcher.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +typedef struct mxio_dispatcher mxio_dispatcher_t; + +typedef mx_status_t (*mxio_dispatcher_cb_t)(mx_handle_t h, void* cb, void* cookie); + +// Create a dispatcher that will process messages from many message pipes. +// +// The provided handler will be called when a handle is readable, and passed +// the cb and cookie pointers that are associated with that handle. +// +// If the remote side of the message pipe is closed, the handler will be +// called and passed a zero handle. +// +// A non-zero return will cause the handle to be closed. If the non-zero +// return is *negative*, the handler will be called one last time, as if +// the message pipe had been closed remotely (zero handle). +mx_status_t mxio_dispatcher_create(mxio_dispatcher_t** out, mxio_dispatcher_cb_t cb); + +// create a thread for a dispatcher and start it running +mx_status_t mxio_dispatcher_start(mxio_dispatcher_t* md); + +// run the dispatcher loop on the current thread, never to return +void mxio_dispatcher_run(mxio_dispatcher_t* md); + +// add a pipe and handler to a dispatcher +mx_status_t mxio_dispatcher_add(mxio_dispatcher_t* md, mx_handle_t h, void* cb, void* cookie); diff --git a/system/ulib/mxio/include/mxio/io.h b/system/ulib/mxio/include/mxio/io.h new file mode 100644 index 000000000..b03b93834 --- /dev/null +++ b/system/ulib/mxio/include/mxio/io.h @@ -0,0 +1,122 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +// MXIO provides open/close/read/write io over various transports +// via the mxio_t interface abstraction. +// +// The PIPE protocol uses message ports as simple, no-flow-control +// io pipes with a maximum message size of MX_PIPE_SIZE. +// +// The REMOTEIO protocol uses message ports to implement simple +// synchronous remoting of read/write/close operations. +// +// Currently there is no multithreading support. Do not use the +// same mxio_t endpoint from different threads. +// + +typedef struct mxio mxio_t; +typedef struct mxio_ops mxio_ops_t; + +struct mxio_ops { + ssize_t (*read)(mxio_t* io, void* data, size_t len); + ssize_t (*write)(mxio_t* io, const void* data, size_t len); + off_t (*seek)(mxio_t* io, off_t offset, int whence); + mx_status_t (*misc)(mxio_t* io, uint32_t op, uint32_t maxreply, void* data, size_t len); + mx_status_t (*close)(mxio_t* io); + mx_status_t (*open)(mxio_t* io, const char* path, int32_t flags, mxio_t** out); + mx_status_t (*clone)(mxio_t* io, mx_handle_t* out_handles, uint32_t* out_types); + mx_status_t (*wait)(mxio_t* io, uint32_t events, uint32_t *pending, mx_time_t timeout); + ssize_t (*ioctl)(mxio_t* io, uint32_t op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len); +}; + +#define MXIO_EVT_READABLE MX_SIGNAL_USER0 +#define MXIO_EVT_WRITABLE MX_SIGNAL_USER1 +#define MXIO_EVT_ERROR MX_SIGNAL_USER2 +#define MXIO_EVT_ALL (MXIO_EVT_READABLE | MXIO_EVT_WRITABLE | MXIO_EVT_ERROR) + +struct mxio { + mxio_ops_t* ops; + uint32_t magic; + uint32_t priv; +}; + +#define MXIO_MAGIC 0x4f49584d // MXIO + +#define MXIO_NONBLOCKING 1 + +#define MXIO_PROTOCOL_UNDEFINED 0 +#define MXIO_PROTOCOL_PIPE 1 +#define MXIO_PROTOCOL_REMOTE 2 + +// maximum handles used in open/clone/create +#define MXIO_MAX_HANDLES 3 + +// mxio_ops_t's read/write are able to do io of +// at least this size +#define MXIO_CHUNK_SIZE 8192 + +// Maxium size for an ioctl input +#define MXIO_IOCTL_MAX_INPUT 1024 + +static inline ssize_t mx_read(mxio_t* io, void* data, size_t len) { + return io->ops->read(io, data, len); +} +static inline ssize_t mx_write(mxio_t* io, const void* data, size_t len) { + return io->ops->write(io, data, len); +} +static inline off_t mx_seek(mxio_t* io, off_t offset, int whence) { + return io->ops->seek(io, offset, whence); +} +static inline mx_status_t mx_misc(mxio_t* io, uint32_t op, uint32_t maxreply, void* data, size_t len) { + return io->ops->misc(io, op, maxreply, data, len); +} +static inline mx_status_t mx_close(mxio_t* io) { + return io->ops->close(io); +} +static inline mx_status_t mx_open(mxio_t* io, const char* path, int32_t flags, mxio_t** out) { + return io->ops->open(io, path, flags, out); +} + +// creates a do-nothing mxio_t +mxio_t* mxio_null_create(void); + +// wraps a message port with an mxio_t using simple io +mxio_t* mxio_pipe_create(mx_handle_t h); + +// creates a mxio that wraps a log object +// this will allocate a per-thread buffer (on demand) to assemble +// entire log-lines and flush them on newline or buffer full. +mxio_t* mxio_logger_create(mx_handle_t); + +// creates a message port and pair of simple io mxio_t's +int mxio_pipe_pair(mxio_t** a, mxio_t** b); + +// wraps a message port with an mxio_t using remote io +mxio_t* mxio_remote_create(mx_handle_t h, mx_handle_t e); + +// create a mxio (if possible) from type and handles +mx_status_t mxio_from_handles(uint32_t type, mx_handle_t* handles, int hcount, mxio_t** out); + +// attempt to install a mxio in the unistd fd table +// if fd > 0, request a specific fd instead of first available +// returns fd on success +int mxio_bind_to_fd(mxio_t* io, int fd); + +// wait until one or more events are pending +mx_status_t mxio_wait_fd(int fd, uint32_t events, uint32_t* pending); diff --git a/system/ulib/mxio/include/mxio/remoteio.h b/system/ulib/mxio/include/mxio/remoteio.h new file mode 100644 index 000000000..8831abc8f --- /dev/null +++ b/system/ulib/mxio/include/mxio/remoteio.h @@ -0,0 +1,115 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +// clang-format off + +#define MX_RIO_HDR_SZ (__builtin_offsetof(mx_rio_msg_t, data)) + +#define MX_RIO_MAGIC 0x024F4952 // RIO 0x02 + +#define MX_RIO_STATUS 0x00000000 +#define MX_RIO_CLOSE 0x00000001 +#define MX_RIO_CLONE 0x00000002 +#define MX_RIO_OPEN 0x00000003 +#define MX_RIO_MISC 0x00000004 +#define MX_RIO_READ 0x00000005 +#define MX_RIO_WRITE 0x00000006 +#define MX_RIO_SEEK 0x00000007 +#define MX_RIO_STAT 0x00000008 +#define MX_RIO_READDIR 0x00000009 +#define MX_RIO_IOCTL 0x0000000a +#define MX_RIO_NUM_OPS 11 + +#define MX_RIO_OP(n) ((n) & 0xFFFF) +#define MX_RIO_REPLY_PIPE 0x01000000 + +#define MX_RIO_OPNAMES { \ + "status", "close", "clone", "open", \ + "misc", "read", "write", "seek", \ + "stat", "readdir", "ioctl" } + +typedef struct mx_rio_msg mx_rio_msg_t; + +typedef mx_status_t (*mxio_rio_cb_t)(mx_rio_msg_t* msg, void* cookie); +// callback to process a mx_rio_msg +// - on entry datalen indicates how much valid data is in msg.data[] +// - return value will be placed in msg.arg, negative is an error, +// positive values are opcode-specific +// - on non-error return msg.len indicates how much valid data to +// send. On error return msg.len will be set to 0. + +// process events on h until it fails +void mxio_rio_server(mx_handle_t h, mxio_rio_cb_t cb, void* cookie); + +// a mxio_dispatcher_handler suitable for use with a mxio_dispatcher +mx_status_t mxio_rio_handler(mx_handle_t h, void* cb, void* cookie); + +// create a thread to service mxio remote io traffic +mx_status_t mxio_handler_create(mx_handle_t h, mxio_rio_cb_t cb, void* cookie); + + +struct mx_rio_msg { + uint32_t magic; // MX_RIO_MAGIC + uint32_t op; // opcode | flags + uint32_t datalen; // size of data[] + int32_t arg; // tx: argument, rx: return value + int64_t off; // tx/rx: offset where needed + int32_t reserved; + uint32_t hcount; // number of valid handles + mx_handle_t handle[4]; // up to 3 handles + reply pipe handle + uint8_t data[MXIO_CHUNK_SIZE]; // payload +}; + +// - msg.datalen is the size of data sent or received and must be <= MXIO_CHUNK_SIZE +// - msg.arg is the return code on replies + +// request------------------------------------ response------------------------------ +// op arg off data off data handle[] +// --------- ---------- ------- -------------- ----------- -------------------------- +// CLOSE 0 0 - 0 - - +// CLONE 0 0 - objtype - handle(s) +// OPEN flags mode objtype - handle(s) +// READ maxread 0 - newoffset - +// WRITE 0 0 newoffset - - +// SEEK whence offset - offset - - +// STAT maxreply 0 - 0 - +// READDIR maxreply 0 - 0 - +// IOCTL out_len opcode 0 - +// +// +// proposed: +// +// LSTAT maxreply 0 - 0 - +// MKDIR 0 0 0 - - +// READ_AT maxread offset - newoffset - +// WRITE_AT 0 offset newoffset - - +// UNLINK 0 0 0 - - +// RENAME* name1len 0 0 - - +// SYMLINK namelen 0 0 - - +// READLINK maxreply 0 - 0 - +// MMAP flags offset offset - vmohandle +// FLUSH 0 0 - 0 - - +// SYNC 0 0 - 0 - - +// LINK** 0 0 0 - - +// +// on response arg32 is always mx_status, and may be positive for read/write calls +// * handle[0] used to pass reference to second directory handle +// ** handle[0] used to pass reference to target object + diff --git a/system/ulib/mxio/include/mxio/util.h b/system/ulib/mxio/include/mxio/util.h new file mode 100644 index 000000000..9fee7fb23 --- /dev/null +++ b/system/ulib/mxio/include/mxio/util.h @@ -0,0 +1,63 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +// These routines are "internal" to mxio but used by some companion +// code like userboot and devmgr + +// starts new process, handling fd/handle transfer +mx_handle_t mxio_start_process(int argc, char** argv); + +// Starts new process, manual configuration of initial handle set. +// Handles and ids must be one larger than hnds_count as the +// process handle is added at the very end. +mx_handle_t mxio_start_process_etc(int args_count, char* args[], + int hnds_count, mx_handle_t* handles, uint32_t* ids); + +// Utilities to help assemble handles for a new process +// may return up to MXIO_MAX_HANDLES +mx_status_t mxio_clone_root(mx_handle_t* handles, uint32_t* types); +mx_status_t mxio_clone_fd(int fd, int newfd, mx_handle_t* handles, uint32_t* types); +mx_status_t mxio_pipe_pair_raw(mx_handle_t* handles, uint32_t* types); + +// Interface for calling into our temporary ioctl +ssize_t mxio_ioctl(int fd, int op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len); + +// Create a handle containing process arguments. +// If proc is nonzero, it will be added to the +// end of the handle/id tables, so they must +// be one larger than specified in hnds_count. +mx_handle_t mxio_build_procargs(int args_count, char* args[], int hnds_count, + mx_handle_t* handles, uint32_t* ids, mx_handle_t proc); + +mx_status_t mxio_load_elf_mem(mx_handle_t process, mx_vaddr_t* entry, void* data, size_t len); + +mx_status_t mxio_load_elf_fd(mx_handle_t process, mx_vaddr_t* entry, int fd); + +// call from libc glue +void mxio_init(void* arg, int* argc, char*** argv); + +void bootfs_parse(void* _data, int len, + void (*cb)(const char* fn, size_t off, size_t len)); + +// return our own process handle if we know it +mx_handle_t mxio_get_process_handle(void); + +// used for bootstrap +void mxio_install_root(mxio_t* root); diff --git a/system/ulib/mxio/include/mxio/vfs.h b/system/ulib/mxio/include/mxio/vfs.h new file mode 100644 index 000000000..09cdab41e --- /dev/null +++ b/system/ulib/mxio/include/mxio/vfs.h @@ -0,0 +1,158 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +// ssize_t? +#include + +typedef struct vfs vfs_t; +typedef struct vfs_ops vfs_ops_t; + +typedef struct vnode vnode_t; +typedef struct vnode_ops vnode_ops_t; + +typedef struct vnattr vnattr_t; +typedef struct vdirent vdirent_t; + +typedef struct vdircookie { + uint64_t n; + void* p; +} vdircookie_t; + +#define VFS_MAX_HANDLES 2 + +struct vnode_ops { + void (*release)(vnode_t* vn); + // Called when refcount reaches zero. + + mx_status_t (*open)(vnode_t** vn, uint32_t flags); + // Attempts to open vn, refcount++ on success. + + mx_status_t (*close)(vnode_t* vn); + // Closes vn, refcount-- + + ssize_t (*read)(vnode_t* vn, void* data, size_t len, size_t off); + // Read data from vn at offset. + + ssize_t (*write)(vnode_t* vn, const void* data, size_t len, size_t off); + // Write data to vn at offset. + + mx_status_t (*lookup)(vnode_t* vn, vnode_t** out, const char* name, size_t len); + // Attempt to find child of vn, child returned with refcount++ on success. + // Name is len bytes long, and does not include a null terminator. + + mx_status_t (*getattr)(vnode_t* vn, vnattr_t* a); + // Read attributes of vn. + + mx_status_t (*readdir)(vnode_t* vn, void* cookie, void* dirents, size_t len); + // Read directory entries of vn, error if not a directory. + // Cookie must be a buffer of vdircookie_t size or larger. + // Cookie must be zero'd before first call and will be used by. + // the readdir implementation to maintain state across calls. + // To "rewind" and start from the beginning, cookie may be zero'd. + + mx_status_t (*create)(vnode_t* vn, vnode_t** out, const char* name, size_t len, uint32_t mode); + // Create a new node under vn. + // Name is len bytes long, and does not include a null terminator. + + mx_status_t (*gethandles)(vnode_t* vn, mx_handle_t* handles, uint32_t* ids); + // Returns up to VFS_MAX_HANDLES representing the remoted open object + // Returns ERR_NOT_SUPPORTED if this is a local vnode + + ssize_t (*ioctl)(vnode_t* vn, uint32_t op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len); + // Performs the given ioctl op on vn. + // On success, returns the number of bytes received. +}; + +struct vnattr { + uint32_t mode; + uint32_t reserved; + uint64_t inode; + uint64_t size; +}; + +struct vnode { + vnode_ops_t* ops; + vfs_t* vfs; + uint32_t flags; + uint32_t refcount; + + void* pdata; + void* pops; +}; + +struct vfs_ops { +}; + +struct vfs { + vfs_ops_t* ops; + vnode_t* root; +}; + +// such a node requires a dedicated service thread +#define V_FLAG_BLOCKING 1 +#define V_FLAG_DEVICE 2 + +// bits compatible with POSIX stat +#define V_TYPE_MASK 0170000 +#define V_TYPE_SOCK 0140000 +#define V_TYPE_LINK 0120000 +#define V_TYPE_FILE 0100000 +#define V_TYPE_BDEV 0060000 +#define V_TYPE_DIR 0040000 +#define V_TYPE_CDEV 0020000 +#define V_TYPE_PIPE 0010000 + +#define V_ISUID 0004000 +#define V_ISGID 0002000 +#define V_ISVTX 0001000 +#define V_IRWXU 0000700 +#define V_IRUSR 0000400 +#define V_IWUSR 0000200 +#define V_IXUSR 0000100 +#define V_IRWXG 0000070 +#define V_IRGRP 0000040 +#define V_IWGRP 0000020 +#define V_IXGRP 0000010 +#define V_IRWXO 0000007 +#define V_IROTH 0000004 +#define V_IWOTH 0000002 +#define V_IXOTH 0000001 + +#define VTYPE_TO_DTYPE(mode) (((mode)&V_TYPE_MASK) >> 12) + +struct vdirent { + uint32_t size; + uint32_t type; + char name[0]; +}; + +static inline void vn_acquire(vnode_t* vn) { + vn->refcount++; +} + +static inline void vn_release(vnode_t* vn) { + vn->refcount--; + if (vn->refcount == 0) { + vn->ops->release(vn); + } +} + +// helper for filling out dents +// returns offset to next vdirent_t on success +mx_status_t vfs_fill_dirent(vdirent_t* de, size_t delen, + const char* name, size_t len, uint32_t type); diff --git a/system/ulib/mxio/logger.c b/system/ulib/mxio/logger.c new file mode 100644 index 000000000..b22664c7e --- /dev/null +++ b/system/ulib/mxio/logger.c @@ -0,0 +1,105 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +#include + +#include +#include + +static int logbuf_tls = -1; +static mxr_mutex_t logbuf_lock; + +typedef struct mxio_log mxio_log_t; +struct mxio_log { + mxio_t io; + mx_handle_t handle; +}; + +#define LOGBUF_MAX (MX_LOG_RECORD_MAX - sizeof(mx_log_record_t)) + +typedef struct ciobuf { + uint next; + char data[LOGBUF_MAX]; +} logbuf_t; + +static ssize_t log_write(mxio_t* io, const void* _data, size_t len) { + mxio_log_t* log_io = (mxio_log_t*) io; + logbuf_t* log = mxr_tls_get(logbuf_tls); + + if (log == NULL) { + if ((log = calloc(1, sizeof(logbuf_t))) == NULL) { + return len; + } + mxr_tls_set(logbuf_tls, log); + } + + const char* data = _data; + size_t r = len; + + while (len-- > 0) { + char c = *data++; + if (c == '\n') { + _magenta_log_write(log_io->handle, log->next, log->data, 0); + log->next = 0; + continue; + } + if (c < ' ') { + continue; + } + log->data[log->next++] = c; + if (log->next == LOGBUF_MAX) { + _magenta_log_write(log_io->handle, log->next, log->data, 0); + log->next = 0; + continue; + } + } + return r; +} + +static mx_status_t log_no_impl(void) { + return ERR_NOT_SUPPORTED; +} + +static mxio_ops_t log_io_ops = { + .read = (void*) log_no_impl, + .write = log_write, + .seek = (void*) log_no_impl, + .misc = (void*) log_no_impl, + .close = (void*) log_no_impl, + .open = (void*) log_no_impl, + .clone = (void*) log_no_impl, + .ioctl = (void*) log_no_impl, +}; + +mxio_t* mxio_logger_create(mx_handle_t handle) { + mxr_mutex_lock(&logbuf_lock); + if (logbuf_tls < 0) { + logbuf_tls = mxr_tls_allocate(); + } + mxr_mutex_unlock(&logbuf_lock); + if (logbuf_tls < 0) { + return NULL; + } + mxio_log_t* log = calloc(1, sizeof(mxio_log_t)); + if (log == NULL) { + return NULL; + } + log->io.ops = &log_io_ops; + log->handle = handle; + return &log->io; +} diff --git a/system/ulib/mxio/null.c b/system/ulib/mxio/null.c new file mode 100644 index 000000000..dd197694b --- /dev/null +++ b/system/ulib/mxio/null.c @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include + +static ssize_t mx_null_write(mxio_t* io, const void* _data, size_t len) { + return len; +} + +static ssize_t mx_null_read(mxio_t* io, void* _data, size_t len) { + return 0; +} + +static mx_status_t mx_null_close(mxio_t* io) { + return 0; +} + +static mx_status_t mx_null_misc(mxio_t* io, uint32_t op, uint32_t arg, void* data, size_t len) { + return ERR_NOT_SUPPORTED; +} + +static mx_status_t mx_null_open(mxio_t* io, const char* path, int32_t flags, mxio_t** out) { + return ERR_NOT_SUPPORTED; +} + +static mx_handle_t mx_null_clone(mxio_t* io, mx_handle_t* handles, uint32_t* types) { + return ERR_NOT_SUPPORTED; +} + +static off_t mx_null_seek(mxio_t* io, off_t offset, int whence) { + return NO_ERROR; +} + +static mx_status_t mx_null_wait(mxio_t* io, uint32_t events, uint32_t *pending, mx_time_t timeout) { + return ERR_NOT_SUPPORTED; +} + +static mxio_ops_t mx_null_ops = { + .read = mx_null_read, + .write = mx_null_write, + .misc = mx_null_misc, + .close = mx_null_close, + .open = mx_null_open, + .clone = mx_null_clone, + .seek = mx_null_seek, + .wait = mx_null_wait, +}; + +mxio_t* mxio_null_create(void) { + mxio_t* io = malloc(sizeof(*io)); + if (io == NULL) return NULL; + io->ops = &mx_null_ops; + io->magic = MXIO_MAGIC; + io->priv = 0; + return io; +} diff --git a/system/ulib/mxio/pipe.c b/system/ulib/mxio/pipe.c new file mode 100644 index 000000000..c0f7b987d --- /dev/null +++ b/system/ulib/mxio/pipe.c @@ -0,0 +1,172 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include +#include + +#include "util.h" + +typedef struct mx_pipe mx_pipe_t; +struct mx_pipe { + mxio_t io; + mx_handle_t h; + uint32_t avail; + uint32_t flags; + uint8_t* next; + uint8_t data[MXIO_CHUNK_SIZE]; +}; + +static ssize_t mx_pipe_write(mxio_t* io, const void* _data, size_t len) { + mx_pipe_t* p = (mx_pipe_t*)io; + const uint8_t* data = _data; + mx_status_t r = 0; + ssize_t count = 0; + + while (len > 0) { + size_t xfer = (len > MXIO_CHUNK_SIZE) ? MXIO_CHUNK_SIZE : len; + r = _magenta_message_write(p->h, data, xfer, NULL, 0, 0); + if (r < 0) break; + len -= xfer; + count += xfer; + data += xfer; + } + + // prioritize partial write results over errors + return count ? count : r; +} + +static ssize_t mx_pipe_read(mxio_t* io, void* _data, size_t len) { + mx_pipe_t* p = (mx_pipe_t*)io; + uint8_t* data = _data; + mx_status_t r = 0; + ssize_t count = 0; + + while (len > 0) { + if (p->avail == 0) { + if (len >= MXIO_CHUNK_SIZE) { + // largest message will fit, read directly + r = mxu_blocking_read(p->h, data, MXIO_CHUNK_SIZE); + if (r <= 0) break; + data += r; + len -= r; + count += r; + continue; + } else { + r = mxu_blocking_read(p->h, p->data, MXIO_CHUNK_SIZE); + if (r <= 0) break; + p->avail = r; + p->next = p->data; + } + } + size_t xfer = (p->avail > len) ? len : p->avail; + memcpy(data, p->next, xfer); + p->next += xfer; + p->avail -= xfer; + data += xfer; + len -= xfer; + count += xfer; + } + + // prioritize partial read results over errors + return count ? count : r; +} + +static mx_status_t mx_pipe_close(mxio_t* io) { + mx_pipe_t* p = (mx_pipe_t*)io; + _magenta_handle_close(p->h); + free(p); + return 0; +} + +static mx_status_t mx_pipe_misc(mxio_t* io, uint32_t op, uint32_t maxreply, void* ptr, size_t len) { + return ERR_NOT_SUPPORTED; +} + +static mx_status_t mx_pipe_open(mxio_t* io, const char* path, int32_t flags, mxio_t** out) { + return ERR_NOT_SUPPORTED; +} + +static mx_handle_t mx_pipe_clone(mxio_t* io, mx_handle_t* handles, uint32_t* types) { + return ERR_NOT_SUPPORTED; +} + +static off_t mx_pipe_seek(mxio_t* io, off_t offset, int whence) { + return ERR_NOT_SUPPORTED; +} + +static mx_status_t mx_pipe_wait(mxio_t* io, uint32_t events, uint32_t *pending, mx_time_t timeout) { + return ERR_NOT_SUPPORTED; +} + +static mxio_ops_t mx_pipe_ops = { + .read = mx_pipe_read, + .write = mx_pipe_write, + .misc = mx_pipe_misc, + .close = mx_pipe_close, + .open = mx_pipe_open, + .clone = mx_pipe_clone, + .seek = mx_pipe_seek, + .wait = mx_pipe_wait, +}; + +mxio_t* mxio_pipe_create(mx_handle_t h) { + mx_pipe_t* p = malloc(sizeof(*p)); + if (p == NULL) return NULL; + p->io.ops = &mx_pipe_ops; + p->io.magic = MXIO_MAGIC; + p->io.priv = 0; + p->h = h; + p->avail = 0; + p->flags = 0; + return &p->io; +} + +int mxio_pipe_pair(mxio_t** _a, mxio_t** _b) { + mx_handle_t ha, hb; + mxio_t *a, *b; + ha = _magenta_message_pipe_create(&hb); + if (ha < 0) return ha; + if ((a = mxio_pipe_create(ha)) == NULL) { + _magenta_handle_close(ha); + _magenta_handle_close(hb); + return ERR_NO_MEMORY; + } + if ((b = mxio_pipe_create(hb)) == NULL) { + mx_pipe_close(a); + _magenta_handle_close(hb); + return ERR_NO_MEMORY; + } + *_a = a; + *_b = b; + return 0; +} + +mx_status_t mxio_pipe_pair_raw(mx_handle_t* handles, uint32_t* types) { + mx_handle_t ha, hb; + if ((ha = _magenta_message_pipe_create(&hb)) < 0) { + return ha; + } + handles[0] = ha; + handles[1] = hb; + types[0] = MX_HND_TYPE_MXIO_PIPE; + types[1] = MX_HND_TYPE_MXIO_PIPE; + return 2; +} + + diff --git a/system/ulib/mxio/process.c b/system/ulib/mxio/process.c new file mode 100644 index 000000000..83a144ea6 --- /dev/null +++ b/system/ulib/mxio/process.c @@ -0,0 +1,199 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "elf.h" + +mx_handle_t mxio_build_procargs(int args_count, char* args[], int hnds_count, + mx_handle_t* handles, uint32_t* ids, mx_handle_t proc) { + uint8_t data[8192]; + mx_proc_args_t pargs; + mx_handle_t h0, h1; + mx_status_t r; + off_t off = sizeof(pargs); + int n; + + + if (args_count < 1) return ERR_INVALID_ARGS; + if (hnds_count < 0) return ERR_INVALID_ARGS; + if (proc) { + proc = _magenta_handle_duplicate(proc); + if (proc < 0) { + cprintf("start_process: proc duplicate failed %d\n", proc); + return proc; + } + if ((handles == NULL) || (ids == NULL)) { + return ERR_INVALID_ARGS; + } + handles[hnds_count] = proc; + ids[hnds_count++] = MX_HND_TYPE_PROC_SELF; + } + //TODO: bounds checking + pargs.protocol = MX_PROCARGS_PROTOCOL; + pargs.version = MX_PROCARGS_VERSION; + pargs.handle_info_off = off; + memcpy(data + off, ids, hnds_count * sizeof(uint32_t)); + off += hnds_count * sizeof(uint32_t); + pargs.args_off = off; + pargs.args_num = args_count; + for (n = 0; n < args_count; n++) { + strcpy((void*)data + off, args[n]); + off += strlen(args[n]) + 1; + } + memcpy(data, &pargs, sizeof(pargs)); + + if ((h0 = _magenta_message_pipe_create(&h1)) < 0) { + return h0; + } + if ((r = _magenta_message_write(h1, data, off, handles, hnds_count, 0)) < 0) { + cprintf("start_process: failed to write args %d\n", r); + _magenta_handle_close(h0); + _magenta_handle_close(h1); + return r; + } + // we're done with our end now + _magenta_handle_close(h1); + return h0; +} + +mx_handle_t mxio_start_process_etc(int args_count, char* args[], int hnds_count, + mx_handle_t* handles, uint32_t* ids) { + uintptr_t entry = 0; + mx_handle_t h, p; + mx_status_t r; + + if (args_count < 1) return ERR_INVALID_ARGS; + + char* path = args[0]; + uint32_t path_len = MIN(strlen(path), MX_MAX_NAME_LEN); + + if ((p = _magenta_process_create(path, path_len)) < 0) { + return p; + } + if ((h = mxio_build_procargs(args_count, args, hnds_count, handles, ids, 0)) < 0) { + _magenta_handle_close(p); + return h; + } + int fd = open(path, O_RDONLY); + if (fd < 0) { + r = ERR_IO; + goto fail; + } + r = mxio_load_elf_fd(p, &entry, fd); + close(fd); + if (r < 0) { + goto fail; + } + if ((r = _magenta_process_start(p, h, entry)) < 0) { + fail: + _magenta_handle_close(h); + _magenta_handle_close(p); + return r; + } + return p; +} + +typedef struct { + uint8_t* data; + size_t len; + int fd; +} ctxt; + +static ssize_t _elf_read(elf_handle_t* elf, void* buf, uintptr_t off, size_t len) { + ctxt* c = elf->arg; + memcpy(buf, c->data + off, len); + return len; +} + +static mx_status_t _elf_load(elf_handle_t* elf, uintptr_t vaddr, uintptr_t off, size_t len) { + ctxt* c = elf->arg; + + mx_ssize_t ret = _magenta_vm_object_write(elf->vmo, c->data + off, vaddr - elf->vmo_addr, len); + if (ret < 0 || (size_t)ret != len) { + cprintf("failed to write\n"); + return ret; + } + + return len; +} + +mx_status_t mxio_load_elf_mem(mx_handle_t process, mx_vaddr_t* entry, void* data, size_t len) { + mx_status_t status; + elf_handle_t elf; + ctxt c; + c.data = data; + c.len = len; + elf_open_handle(&elf, process, _elf_read, _elf_load, &c); + status = elf_load(&elf); + *entry = elf.entry; + elf_close_handle(&elf); + return status; +} + +static ssize_t _elf_read_fd(elf_handle_t* elf, void* buf, uintptr_t off, size_t len) { + ctxt* c = elf->arg; + if (lseek(c->fd, off, SEEK_SET) != (off_t)off) return ERR_IO; + if (read(c->fd, buf, len) != (ssize_t)len) return ERR_IO; + return len; +} + +static mx_status_t _elf_load_fd(elf_handle_t* elf, uintptr_t vaddr, uintptr_t off, size_t len) { + uint8_t tmp[4096]; + ctxt* c = elf->arg; + + size_t save = len; + + if (lseek(c->fd, off, SEEK_SET) != (off_t)off) return ERR_IO; + + while (len > 0) { + size_t xfer = (len > 4096) ? 4096 : len; + if (read(c->fd, tmp, xfer) != (ssize_t)xfer) return ERR_IO; + + mx_ssize_t ret = _magenta_vm_object_write(elf->vmo, tmp, vaddr - elf->vmo_addr, xfer); + if (ret < 0 || (size_t)ret != xfer) { + return ret; + } + + len -= xfer; + vaddr += xfer; + } + return save; +} + +mx_status_t mxio_load_elf_fd(mx_handle_t process, mx_vaddr_t* entry, int fd) { + mx_status_t status; + elf_handle_t elf; + ctxt c; + c.fd = fd; + elf_open_handle(&elf, process, _elf_read_fd, _elf_load_fd, &c); + status = elf_load(&elf); + *entry = elf.entry; + elf_close_handle(&elf); + return status; +} diff --git a/system/ulib/mxio/remoteio.c b/system/ulib/mxio/remoteio.c new file mode 100644 index 000000000..9ba1f2d3e --- /dev/null +++ b/system/ulib/mxio/remoteio.c @@ -0,0 +1,536 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MXDEBUG 0 + +typedef struct mx_rio mx_rio_t; +struct mx_rio { + // base mxio io object + mxio_t io; + + // message pipe handle for rpc + mx_handle_t h; + + // event handle for device state signals + mx_handle_t e; + + uint32_t flags; +}; + + +static const char* _opnames[] = MX_RIO_OPNAMES; +static const char* opname(uint32_t op) { + op = MX_RIO_OP(op); + if (op < MX_RIO_NUM_OPS) { + return _opnames[op]; + } else { + return "unknown"; + } +} + +static void discard_handles(mx_handle_t* handles, unsigned count) { + while (count-- > 0) { + _magenta_handle_close(*handles++); + } +} + +mx_status_t mxio_rio_handler(mx_handle_t h, void* _cb, void* cookie) { + mxio_rio_cb_t cb = _cb; + mx_rio_msg_t msg; + mx_status_t r; + + if (h == 0) { + // remote side was closed; + msg.op = MX_RIO_CLOSE; + msg.arg = 0; + msg.datalen = 0; + msg.hcount = 0; + cb(&msg, cookie); + return NO_ERROR; + } + + msg.hcount = MXIO_MAX_HANDLES + 1; + uint32_t dsz = sizeof(msg); + if ((r = _magenta_message_read(h, &msg, &dsz, msg.handle, &msg.hcount, 0)) < 0) { + return r; + } + + if ((dsz < MX_RIO_HDR_SZ) || + (msg.magic != MX_RIO_MAGIC) || + (msg.datalen > MXIO_CHUNK_SIZE) || + (msg.datalen != (dsz - MX_RIO_HDR_SZ))) { + discard_handles(msg.handle, msg.hcount); + return ERR_INVALID_ARGS; + } + + bool is_close = (MX_RIO_OP(msg.op) == MX_RIO_CLOSE); + + xprintf("handle_rio: op=%s arg=%d len=%u hsz=%d\n", + opname(msg.op), msg.arg, msg.datalen, msg.hcount); + + if ((msg.arg = cb(&msg, cookie)) < 0) { + msg.datalen = 0; + } else if (msg.datalen > MXIO_CHUNK_SIZE) { + msg.datalen = 0; + msg.arg = ERR_IO; + } else if (msg.hcount > MXIO_MAX_HANDLES) { + discard_handles(msg.handle, msg.hcount); + msg.datalen = 0; + msg.arg = ERR_IO; + } + + msg.op = MX_RIO_STATUS; + r = _magenta_message_write(h, &msg, MX_RIO_HDR_SZ + msg.datalen, msg.handle, msg.hcount, 0); + if (is_close) { + // signals to not perform a close callback + return 1; + } else { + return r; + } +} + +void mxio_rio_server(mx_handle_t h, mxio_rio_cb_t cb, void* cookie) { + mx_signals_t pending; + mx_status_t r; + + xprintf("riosvr(%x) starting...\n", h); + for (;;) { + r = _magenta_handle_wait_one(h, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL); + if (r < 0) + break; + if (pending & MX_SIGNAL_READABLE) { + if ((r = mxio_rio_handler(h, cb, cookie)) != 0) { + break; + } + } + if (pending & MX_SIGNAL_PEER_CLOSED) { + r = ERR_CHANNEL_CLOSED; + break; + } + } + if (r < 0) { + mxio_rio_handler(0, cb, cookie); + } + if (r != 0) { + xprintf("riosvr(%x) done, status=%d\n", h, r); + } + _magenta_handle_close(h); +} + +// on success, msg->hcount indicates number of valid handles in msg->handle +// on error there are never any handles +static mx_status_t mx_rio_txn(mx_rio_t* rio, mx_rio_msg_t* msg) { + if ((msg->datalen > MXIO_CHUNK_SIZE) || + (msg->hcount > MXIO_MAX_HANDLES)) { + return ERR_INVALID_ARGS; + } + + xprintf("txn h=%x op=%d len=%u\n", rio->h, msg->op, msg->datalen); + uint32_t dsize = MX_RIO_HDR_SZ + msg->datalen; + mx_handle_t rh = rio->h; + + mx_status_t r; + msg->magic = MX_RIO_MAGIC; + if ((r = _magenta_message_write(rio->h, msg, dsize, msg->handle, msg->hcount, 0)) < 0) { + goto fail_discard_handles; + } + + mx_signals_t pending; + if ((r = _magenta_handle_wait_one(rh, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL)) < 0) { + return r; + } + if (pending & MX_SIGNAL_PEER_CLOSED) { + return ERR_CHANNEL_CLOSED; + } + + dsize = MX_RIO_HDR_SZ + MXIO_CHUNK_SIZE; + msg->hcount = MXIO_MAX_HANDLES + 1; + if ((r = _magenta_message_read(rh, msg, &dsize, msg->handle, &msg->hcount, 0)) < 0) { + return r; + } + // check for protocol errors + if ((dsize < MX_RIO_HDR_SZ) || + (msg->magic != MX_RIO_MAGIC) || + (MX_RIO_OP(msg->op) != MX_RIO_STATUS) || + (msg->datalen != (dsize - MX_RIO_HDR_SZ))) { + r = ERR_IO; + goto fail_discard_handles; + } + // check for remote error + if ((r = msg->arg) >= 0) { + return r; + } + +fail_discard_handles: + discard_handles(msg->handle, msg->hcount); + msg->hcount = 0; + return r; +} + +static ssize_t mx_rio_ioctl( + mxio_t* io, uint32_t op, + const void* in_buf, size_t in_len, void* out_buf, size_t out_len) { + mx_rio_t* rio = (mx_rio_t*)io; + const uint8_t* data = in_buf; + mx_status_t r = 0; + mx_rio_msg_t msg; + + if (in_len > MXIO_IOCTL_MAX_INPUT || out_len > MXIO_CHUNK_SIZE) { + return ERR_INVALID_ARGS; + } + + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = MX_RIO_IOCTL; + msg.off = op; + msg.datalen = in_len; + msg.arg = out_len; + memcpy(msg.data, data, in_len); + + if ((r = mx_rio_txn(rio, &msg)) < 0) { + return r; + } + + size_t copy_len = msg.datalen; + if (msg.datalen > out_len) { + copy_len = out_len; + } + + memcpy(out_buf, msg.data, copy_len); + discard_handles(msg.handle, msg.hcount); + return r; +} + +static ssize_t mx_rio_write(mxio_t* io, const void* _data, size_t len) { + mx_rio_t* rio = (mx_rio_t*)io; + const uint8_t* data = _data; + ssize_t count = 0; + mx_status_t r = 0; + mx_rio_msg_t msg; + ssize_t xfer; + + while (len > 0) { + xfer = (len > MXIO_CHUNK_SIZE) ? MXIO_CHUNK_SIZE : len; + + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = MX_RIO_WRITE; + msg.datalen = xfer; + memcpy(msg.data, data, xfer); + + if ((r = mx_rio_txn(rio, &msg)) < 0) { + break; + } + discard_handles(msg.handle, msg.hcount); + + if (r > xfer) { + r = ERR_IO; + break; + } + count += r; + data += r; + len -= r; + // stop at short read + if (r < xfer) { + break; + } + } + return count ? count : r; +} + +static ssize_t mx_rio_read(mxio_t* io, void* _data, size_t len) { + mx_rio_t* rio = (mx_rio_t*)io; + uint8_t* data = _data; + ssize_t count = 0; + mx_status_t r = 0; + mx_rio_msg_t msg; + ssize_t xfer; + + while (len > 0) { + xfer = (len > MXIO_CHUNK_SIZE) ? MXIO_CHUNK_SIZE : len; + + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = MX_RIO_READ; + msg.arg = xfer; + + if ((r = mx_rio_txn(rio, &msg)) < 0) { + break; + } + discard_handles(msg.handle, msg.hcount); + + if ((r > (int)msg.datalen) || (r > xfer)) { + r = ERR_IO; + break; + } + memcpy(data, msg.data, r); + count += r; + data += r; + len -= r; + + // stop at short read + if (r < xfer) { + break; + } + } + return count ? count : r; +} + +static off_t mx_rio_seek(mxio_t* io, off_t offset, int whence) { + mx_rio_t* rio = (mx_rio_t*)io; + mx_rio_msg_t msg; + mx_status_t r; + + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = MX_RIO_SEEK; + msg.off = offset; + msg.arg = whence; + + if ((r = mx_rio_txn(rio, &msg)) < 0) { + return r; + } + + discard_handles(msg.handle, msg.hcount); + return msg.off; +} + +static mx_status_t mx_rio_close(mxio_t* io) { + mx_rio_t* rio = (mx_rio_t*)io; + mx_rio_msg_t msg; + mx_status_t r; + + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = MX_RIO_CLOSE; + + if ((r = mx_rio_txn(rio, &msg)) >= 0) { + discard_handles(msg.handle, msg.hcount); + } + + // probably should defer the free + _magenta_handle_close(rio->h); + if (rio->e > 0) { + _magenta_handle_close(rio->e); + rio->e = 0; + } + rio->h = 0; + free(rio); + + return r; +} + +static mx_status_t mx_rio_misc(mxio_t* io, uint32_t op, uint32_t maxreply, void* ptr, size_t len) { + mx_rio_t* rio = (mx_rio_t*)io; + mx_rio_msg_t msg; + mx_status_t r; + + if ((len > MXIO_CHUNK_SIZE) || (maxreply > MXIO_CHUNK_SIZE)) { + return ERR_INVALID_ARGS; + } + + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = op; + msg.arg = maxreply; + msg.datalen = len; + memcpy(msg.data, ptr, len); + + if ((r = mx_rio_txn(rio, &msg)) < 0) { + return r; + } + + discard_handles(msg.handle, msg.hcount); + if (r > (int)maxreply) { + return ERR_IO; + } + memcpy(ptr, msg.data, r); + return r; +} + +mx_status_t mxio_from_handles(uint32_t type, mx_handle_t* handles, int hcount, mxio_t** out) { + mx_status_t r; + mxio_t *io; + + switch (type) { + case MXIO_PROTOCOL_REMOTE: + if (hcount == 1) { + io = mxio_remote_create(handles[0], 0); + xprintf("rio (%x,%x) -> %p\n", handles[0], 0, io); + } else if (hcount == 2) { + io = mxio_remote_create(handles[0], handles[1]); + xprintf("rio (%x,%x) -> %p\n", handles[0], handles[1], io); + } else { + r = ERR_INVALID_ARGS; + break; + } + if (io == NULL) { + r = ERR_NO_RESOURCES; + } else { + *out = io; + return NO_ERROR; + } + break; + case MXIO_PROTOCOL_PIPE: + if (hcount != 1) { + r = ERR_INVALID_ARGS; + } else if ((*out = mxio_pipe_create(handles[0])) == NULL) { + r = ERR_NO_RESOURCES; + } else { + return NO_ERROR; + } + break; + default: + r = ERR_NOT_SUPPORTED; + } + discard_handles(handles, hcount); + return r; +} + +static mx_status_t mx_rio_getobject(mx_rio_t* rio, uint32_t op, const char* name, + int32_t flags, mx_handle_t* handles, uint32_t* type) { + if (name == NULL) { + return ERR_INVALID_ARGS; + } + + size_t len = strlen(name); + if (len >= MXIO_CHUNK_SIZE) { + return ERR_INVALID_ARGS; + } + + mx_rio_msg_t msg; + memset(&msg, 0, MX_RIO_HDR_SZ); + msg.op = op; + msg.datalen = len; + msg.arg = flags; + memcpy(msg.data, name, len); + + mx_status_t r; + if ((r = mx_rio_txn(rio, &msg)) < 0) { + return r; + } + memcpy(handles, msg.handle, msg.hcount * sizeof(mx_handle_t)); + *type = msg.off; + return (mx_status_t)msg.hcount; +} + +static mx_status_t mx_rio_open(mxio_t* io, const char* path, int32_t flags, mxio_t** out) { + mx_rio_t* rio = (void*) io; + mx_handle_t handles[MXIO_MAX_HANDLES]; + uint32_t type; + mx_status_t r = mx_rio_getobject(rio, MX_RIO_OPEN, path, flags, handles, &type); + if (r > 0) { + r = mxio_from_handles(type, handles, r, out); + } + return r; +} + +static mx_status_t mx_rio_clone(mxio_t* io, mx_handle_t* handles, uint32_t* types) { + mx_rio_t* rio = (void*) io; + mx_status_t r = mx_rio_getobject(rio, MX_RIO_CLONE, "", 0, handles, types); + for (int i = 0; i < r; i++) { + types[i] = MX_HND_TYPE_MXIO_REMOTE; + } + return r; +} + +mx_status_t __mx_rio_clone(mx_handle_t h, mx_handle_t* handles, uint32_t* types) { + mx_rio_t rio; + rio.h = h; + return mx_rio_clone(&rio.io, handles, types); +} + +static mx_status_t mx_rio_wait(mxio_t* io, uint32_t events, uint32_t *_pending, mx_time_t timeout) { + mx_rio_t* rio = (void*) io; + if (rio->e == 0) { + return ERR_NOT_SUPPORTED; + } + mx_status_t r; + mx_signals_t pending; + if ((r = _magenta_handle_wait_one(rio->e, events & MXIO_EVT_ALL, + MX_TIME_INFINITE, &pending, NULL)) < 0) { + return r; + } + if (_pending) { + *_pending = pending; + } + return NO_ERROR; +} + +static mxio_ops_t mx_remote_ops = { + .read = mx_rio_read, + .write = mx_rio_write, + .misc = mx_rio_misc, + .seek = mx_rio_seek, + .close = mx_rio_close, + .open = mx_rio_open, + .clone = mx_rio_clone, + .wait = mx_rio_wait, + .ioctl = mx_rio_ioctl, +}; + +mxio_t* mxio_remote_create(mx_handle_t h, mx_handle_t e) { + mx_rio_t* rio = malloc(sizeof(*rio)); + if (rio == NULL) + return NULL; + rio->io.ops = &mx_remote_ops; + rio->io.magic = MXIO_MAGIC; + rio->io.priv = 0; + rio->h = h; + rio->e = e; + rio->flags = 0; + return &rio->io; +} + +typedef struct { + mx_handle_t h; + void* cb; + void* cookie; +} rio_args_t; + +static int rio_handler_thread(void* _args) { + rio_args_t* args = (rio_args_t*)_args; + mxio_rio_server(args->h, args->cb, args->cookie); + return 0; +} + +mx_status_t mxio_handler_create(mx_handle_t h, mxio_rio_cb_t cb, void* cookie) { + rio_args_t* args; + mxr_thread_t *t; + if ((args = malloc(sizeof(*args))) == NULL) { + goto fail; + } + args->h = h; + args->cb = cb; + args->cookie = cookie; + if (mxr_thread_create(rio_handler_thread, args, "rio-handler", &t) < 0) { + goto fail; + } + mxr_thread_detach(t); + return 0; +fail: + xprintf("riosvr: could not install handler %x %p\n", h, cb); + _magenta_handle_close(h); + free(args); + return ERR_NO_RESOURCES; +} diff --git a/system/ulib/mxio/rules.mk b/system/ulib/mxio/rules.mk new file mode 100644 index 000000000..8a1152cb0 --- /dev/null +++ b/system/ulib/mxio/rules.mk @@ -0,0 +1,40 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS += \ + $(LOCAL_DIR)/bootfs.c \ + $(LOCAL_DIR)/debug.c \ + $(LOCAL_DIR)/dispatcher.c \ + $(LOCAL_DIR)/elf.c \ + $(LOCAL_DIR)/logger.c \ + $(LOCAL_DIR)/null.c \ + $(LOCAL_DIR)/pipe.c \ + $(LOCAL_DIR)/process.c \ + $(LOCAL_DIR)/remoteio.c \ + $(LOCAL_DIR)/unistd.c \ + $(LOCAL_DIR)/util.c \ + +MODULE_DEPS += \ + ulib/magenta \ + ulib/runtime \ + ulib/mxu \ + ulib/musl + +include make/module.mk diff --git a/system/ulib/mxio/unistd.c b/system/ulib/mxio/unistd.c new file mode 100644 index 000000000..e97711164 --- /dev/null +++ b/system/ulib/mxio/unistd.c @@ -0,0 +1,375 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define MXDEBUG 0 + +// non-thread-safe emulation of unistd io functions +// using the mxio transports + +#define MAX_MXIO_FD 256 + +static mxio_t* mxio_root_handle = NULL; + +static mx_handle_t mxio_process_handle = 0; + +static mxio_t* mxio_fdtab[MAX_MXIO_FD] = { + NULL, +}; + +void mxio_install_root(mxio_t *root) { + if (mxio_root_handle == NULL) { + mxio_root_handle = root; + } +} + +//TODO: fd's pointing to same mxio, refcount, etc + +int mxio_bind_to_fd(mxio_t* io, int fd) { + if (fd >= 0) { + if (fd >= MAX_MXIO_FD) return ERR_INVALID_ARGS; + if (mxio_fdtab[fd]) return ERR_ALREADY_EXISTS; + mxio_fdtab[fd] = io; + return fd; + } + for (fd = 0; fd < MAX_MXIO_FD; fd++) { + if (mxio_fdtab[fd] == NULL) { + mxio_fdtab[fd] = io; + return fd; + } + } + return ERR_NO_RESOURCES; +} + +static inline mxio_t* fd_to_io(int fd) { + if ((fd < 0) || (fd >= MAX_MXIO_FD)) return NULL; + return mxio_fdtab[fd]; +} + +static void mxio_exit(void) { + int fd; + for (fd = 0; fd < MAX_MXIO_FD; fd++) { + mxio_t* io = mxio_fdtab[fd]; + if (io) { + io->ops->close(io); + mxio_fdtab[fd] = NULL; + } + } +} + +// hook into musl FILE* io +#if WITH_LIBC_IO_HOOKS +#define __open __libc_io_open +#define __close __libc_io_close +#else +#define __open open +#define __close close +#endif + +ssize_t __libc_io_write(int fd, const void* data, size_t len) { + return write(fd, data, len); +} + +int __libc_io_readv(int fd, const struct iovec* iov, int num) { + ssize_t count = 0; + ssize_t r; + while (num > 0) { + if (iov->iov_len != 0) { + r = read(fd, iov->iov_base, iov->iov_len); + if (r < 0) { + return count ? count : r; + } + if ((size_t)r < iov->iov_len) { + return count + r; + } + count += r; + } + iov++; + num--; + } + return count; +} + +int __libc_io_writev(int fd, const struct iovec* iov, int num) { + ssize_t count = 0; + ssize_t r; + while (num > 0) { + if (iov->iov_len != 0) { + r = write(fd, iov->iov_base, iov->iov_len); + if (r < 0) { + return count ? count : r; + } + if ((size_t)r < iov->iov_len) { + return count + r; + } + count += r; + } + iov++; + num--; + } + return count; +} + +mx_handle_t mxio_get_process_handle(void) { + return mxio_process_handle; +} + +// hook into libc process startup +void __libc_extensions_init(mx_proc_info_t* pi) { + int n; + // extract handles we care about + for (n = 0; n < pi->handle_count; n++) { + unsigned arg = MX_HND_INFO_ARG(pi->handle_info[n]); + mx_handle_t h = pi->handle[n]; + + switch (MX_HND_INFO_TYPE(pi->handle_info[n])) { + case MX_HND_TYPE_MXIO_ROOT: + mxio_root_handle = mxio_remote_create(h, 0); + break; + case MX_HND_TYPE_MXIO_REMOTE: + // remote objects may have a second handle + // which is for signalling events + if (((n+1) < pi->handle_count) && + (pi->handle_info[n] == pi->handle_info[n + 1])) { + mxio_fdtab[arg] = mxio_remote_create(h, pi->handle[n + 1]); + pi->handle_info[n + 1] = 0; + } else { + mxio_fdtab[arg] = mxio_remote_create(h, 0); + } + break; + case MX_HND_TYPE_MXIO_PIPE: + mxio_fdtab[arg] = mxio_pipe_create(h); + break; + case MX_HND_TYPE_PROC_SELF: + mxio_process_handle = h; + continue; + default: + // unknown handle, leave it alone + continue; + } + pi->handle[n] = 0; + pi->handle_info[n] = 0; + } + + // install null stdin/out/err if not init'd + for (n = 0; n < 3; n++) { + if (mxio_fdtab[n] == NULL) { + mxio_fdtab[n] = mxio_null_create(); + } + } + + atexit(mxio_exit); +} + +mx_status_t mxio_clone_root(mx_handle_t* handles, uint32_t* types) { + // TODO: better solution + mx_status_t r = mxio_root_handle->ops->clone(mxio_root_handle, handles, types); + if (r > 0) { + *types = MX_HND_TYPE_MXIO_ROOT; + } + return r; +} + +mx_status_t mxio_clone_fd(int fd, int newfd, mx_handle_t* handles, uint32_t* types) { + mx_status_t r; + mxio_t* io; + if ((io = fd_to_io(fd)) == NULL) { + return ERR_BAD_HANDLE; + } + if ((r = io->ops->clone(io, handles, types)) > 0) { + for (int i = 0; i < r; i++) { + types[i] |= (newfd << 16); + } + } + return r; +} + +ssize_t mxio_ioctl(int fd, int op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len) { + mxio_t* io; + if ((io = fd_to_io(fd)) == NULL) { + return ERR_BAD_HANDLE; + } + if (!io->ops->ioctl) { + return ERR_NOT_SUPPORTED; + } + return io->ops->ioctl(io, op, in_buf, in_len, out_buf, out_len); +} + +mx_status_t mxio_create_subprocess_handles(mx_handle_t* handles, uint32_t* types, size_t count) { + mx_status_t r; + size_t n = 0; + + if (count < MXIO_MAX_HANDLES) return ERR_NO_MEMORY; + + if ((r = mxio_clone_root(handles + n, types + n)) < 0) { + return r; + } + n += r; + count -= r; + + for (int fd = 0; (fd < MAX_MXIO_FD) && (count >= MXIO_MAX_HANDLES); fd++) { + if ((r = mxio_clone_fd(fd, fd, handles + n, types + n)) <= 0) { + continue; + } + n += r; + count -= r; + } + return n; +} + +mx_handle_t mxio_start_process(int args_count, char* args[]) { + // worset case slots for all fds plus root handle + // plus a process handle possibly added by start process + mx_handle_t hnd[(2 + MAX_MXIO_FD) * MXIO_MAX_HANDLES]; + uint32_t ids[(2 + MAX_MXIO_FD) + MXIO_MAX_HANDLES]; + mx_status_t r; + + r = mxio_create_subprocess_handles(hnd, ids, (1 + MAX_MXIO_FD) * MXIO_MAX_HANDLES); + if (r < 0) { + return r; + } else { + return mxio_start_process_etc(args_count, args, r, hnd, ids); + } +} + +mx_status_t mxio_wait_fd(int fd, uint32_t events, uint32_t* pending) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + return io->ops->wait(io, events, pending, MX_TIME_INFINITE); +} + +//TODO: errors -> errno +ssize_t read(int fd, void* buf, size_t count) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + if (buf == NULL) return ERR_INVALID_ARGS; + return io->ops->read(io, buf, count); +} + +ssize_t write(int fd, const void* buf, size_t count) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + if (buf == NULL) return ERR_INVALID_ARGS; + return io->ops->write(io, buf, count); +} + +int __close(int fd) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + int r = io->ops->close(io); + mxio_fdtab[fd] = NULL; + return r; +} + +off_t lseek(int fd, off_t offset, int whence) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + return io->ops->seek(io, offset, whence); +} + +int getdirents(int fd, void* ptr, size_t len) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + return io->ops->misc(io, MX_RIO_READDIR, len, ptr, 0); +} + +int __open(const char* path, int flags, ...) { + mxio_t* io = NULL; + mx_status_t r; + int fd; + if (path == NULL) { + return ERR_INVALID_ARGS; + } + if (mxio_root_handle == NULL) { + return ERR_BAD_HANDLE; + } + r = mxio_root_handle->ops->open(mxio_root_handle, path, flags, &io); + if (r < 0) return r; + if (io == NULL) return ERR_IO; + fd = mxio_bind_to_fd(io, -1); + if (fd < 0) { + io->ops->close(io); + return ERR_NO_RESOURCES; + } + return fd; +} + +int mx_stat(mxio_t* io, struct stat* s) { + vnattr_t attr; + int r = io->ops->misc(io, MX_RIO_STAT, sizeof(attr), &attr, 0); + if (r < 0) return r; + if (r < (int)sizeof(attr)) return ERR_IO; + memset(s, 0, sizeof(struct stat)); + s->st_mode = attr.mode; + s->st_size = attr.size; + s->st_ino = attr.inode; + return 0; +} + +int fstat(int fd, struct stat* s) { + mxio_t* io = fd_to_io(fd); + if (io == NULL) return ERR_BAD_HANDLE; + return mx_stat(io, s); +} + +int stat(const char* fn, struct stat* s) { + mxio_t* io; + mx_status_t r; + if (fn == NULL) { + return ERR_INVALID_ARGS; + } + if (mxio_root_handle == NULL) { + return ERR_BAD_HANDLE; + } + if ((r = mx_open(mxio_root_handle, fn, 0, &io)) < 0) { + return r; + } + r = mx_stat(io, s); + mx_close(io); + return r; +} + +int pipe(int pipefd[2]) { + mxio_t *a, *b; + int r = mxio_pipe_pair(&a, &b); + if (r < 0) return r; + pipefd[0] = mxio_bind_to_fd(a, -1); + if (pipefd[0] < 0) { + mx_close(a); + mx_close(b); + return pipefd[0]; + } + pipefd[1] = mxio_bind_to_fd(b, -1); + if (pipefd[1] < 0) { + close(pipefd[0]); + mx_close(b); + return pipefd[1]; + } + return 0; +} diff --git a/system/ulib/mxio/util.c b/system/ulib/mxio/util.c new file mode 100644 index 000000000..41dfdc998 --- /dev/null +++ b/system/ulib/mxio/util.c @@ -0,0 +1,90 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include + +#include "util.h" + +mx_handle_t mxu_read_handle(mx_handle_t h) { + mx_signals_t pending; + mx_handle_t out; + mx_status_t r; + uint32_t sz; + + for (;;) { + sz = 1; + r = _magenta_message_read(h, NULL, 0, &out, &sz, 0); + if (r == 0) { + return out; + } + if (r == ERR_NO_MSG) { + r = _magenta_handle_wait_one(h, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL); + if (r < 0) return r; + if (pending & MX_SIGNAL_READABLE) continue; + if (pending & MX_SIGNAL_PEER_CLOSED) return ERR_CHANNEL_CLOSED; + return ERR_GENERIC; + } + return r; + } +} + +mx_status_t mxu_blocking_read(mx_handle_t h, void* data, size_t len) { + mx_signals_t pending; + mx_status_t r; + uint32_t sz; + + for (;;) { + sz = len; + r = _magenta_message_read(h, data, &sz, NULL, NULL, 0); + if (r == 0) { + return sz; + } + if (r == ERR_NO_MSG) { + r = _magenta_handle_wait_one(h, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL); + if (r < 0) return r; + if (pending & MX_SIGNAL_READABLE) continue; + if (pending & MX_SIGNAL_PEER_CLOSED) return ERR_CHANNEL_CLOSED; + return ERR_GENERIC; + } + return r; + } +} + +mx_status_t mxu_blocking_read_h(mx_handle_t h, void* data, size_t len, mx_handle_t* out) { + mx_signals_t pending; + mx_status_t r; + uint32_t sz, hsz; + + for (;;) { + sz = len; + hsz = 1; + r = _magenta_message_read(h, data, &sz, out, &hsz, 0); + if (r == 0) { + if (hsz != 1) *out = 0; + return sz; + } + if (r == ERR_NO_MSG) { + r = _magenta_handle_wait_one(h, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL); + if (r < 0) return r; + if (pending & MX_SIGNAL_READABLE) continue; + if (pending & MX_SIGNAL_PEER_CLOSED) return ERR_CHANNEL_CLOSED; + return ERR_GENERIC; + } + return r; + } +} diff --git a/system/ulib/mxio/util.h b/system/ulib/mxio/util.h new file mode 100644 index 000000000..0066ad0ad --- /dev/null +++ b/system/ulib/mxio/util.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +mx_handle_t mxu_read_handle(mx_handle_t h); + +mx_status_t mxu_blocking_read(mx_handle_t h, void* data, size_t len); + +mx_status_t mxu_blocking_read_h(mx_handle_t h, void* data, size_t len, mx_handle_t* out); diff --git a/system/ulib/mxu/BUILD.gn b/system/ulib/mxu/BUILD.gn new file mode 100644 index 000000000..a82d74c96 --- /dev/null +++ b/system/ulib/mxu/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_mxu_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("mxu") { + public_configs = [ ":_mxu_config" ] + public = [ + "include/mxu/hexdump.h", + "include/mxu/fifo.h", + "include/mxu/list.h", + "include/mxu/unittest.h", + ] + sources = [ + "fifo.c", + "hexdump.c", + "unittest/all_tests.c", + "unittest/unittest.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] + public_deps = [ + "//system/ulib/global", + ] +} diff --git a/system/ulib/mxu/fifo.c b/system/ulib/mxu/fifo.c new file mode 100644 index 000000000..0e45783b4 --- /dev/null +++ b/system/ulib/mxu/fifo.c @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +mx_status_t fifo_read(fifo_t* fifo, uint8_t* out) { + if (fifo->head == fifo->tail) { + return -1; + } + *out = fifo->data[fifo->tail]; + fifo->tail = (fifo->tail + 1) & FIFOMASK; + return NO_ERROR; +} + +void fifo_write(fifo_t* fifo, uint8_t x) { + uint32_t next = (fifo->head + 1) & FIFOMASK; + if (next != fifo->tail) { + fifo->data[fifo->head] = x; + fifo->head = next; + } +} diff --git a/system/ulib/mxu/hexdump.c b/system/ulib/mxu/hexdump.c new file mode 100644 index 000000000..cec8bc10a --- /dev/null +++ b/system/ulib/mxu/hexdump.c @@ -0,0 +1,92 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +void mxu_hexdump_ex(const void *ptr, size_t len, uint64_t disp_addr) { + uintptr_t address = (uintptr_t)ptr; + size_t count; + + for (count = 0 ; count < len; count += 16) { + union { + uint32_t buf[4]; + uint8_t cbuf[16]; + } u; + size_t s = ROUNDUP(MIN(len - count, 16), 4); + size_t i; + + printf(((disp_addr + len) > 0xFFFFFFFF) + ? "0x%016llx: " + : "0x%08llx: ", disp_addr + count); + + for (i = 0; i < s / 4; i++) { + u.buf[i] = ((const uint32_t *)address)[i]; + printf("%08x ", u.buf[i]); + } + for (; i < 4; i++) { + printf(" "); + } + printf("|"); + + for (i=0; i < 16; i++) { + char c = u.cbuf[i]; + if (i < s && isprint(c)) { + printf("%c", c); + } else { + printf("."); + } + } + printf("|\n"); + address += 16; + } +} + +void mxu_hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr) +{ + uintptr_t address = (uintptr_t)ptr; + size_t count; + size_t i; + + for (count = 0 ; count < len; count += 16) { + printf(((disp_addr + len) > 0xFFFFFFFF) + ? "0x%016llx: " + : "0x%08llx: ", disp_addr + count); + + for (i=0; i < MIN(len - count, 16); i++) { + printf("%02hhx ", *(const uint8_t *)(address + i)); + } + + for (; i < 16; i++) { + printf(" "); + } + + printf("|"); + + for (i=0; i < MIN(len - count, 16); i++) { + char c = ((const char *)address)[i]; + printf("%c", isprint(c) ? c : '.'); + } + + printf("\n"); + address += 16; + } +} + diff --git a/system/ulib/mxu/include/mxu/fifo.h b/system/ulib/mxu/include/mxu/fifo.h new file mode 100644 index 000000000..f76a4fd26 --- /dev/null +++ b/system/ulib/mxu/include/mxu/fifo.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#define FIFOSIZE 256 +#define FIFOMASK (FIFOSIZE - 1) + +typedef struct fifo { + uint8_t data[FIFOSIZE]; + uint32_t head; + uint32_t tail; + mxr_mutex_t lock; +} fifo_t; + +mx_status_t fifo_read(fifo_t* fifo, uint8_t* out); +void fifo_write(fifo_t* fifo, uint8_t x); diff --git a/system/ulib/mxu/include/mxu/hexdump.h b/system/ulib/mxu/include/mxu/hexdump.h new file mode 100644 index 000000000..3b2e56ff7 --- /dev/null +++ b/system/ulib/mxu/include/mxu/hexdump.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +/* do a hex dump against stdout 32bits and 8bits at a time */ +void mxu_hexdump_ex(const void *ptr, size_t len, uint64_t disp_addr); +void mxu_hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr); + +static inline void mxu_hexdump(const void *ptr, size_t len) { + mxu_hexdump_ex(ptr, len, (uint64_t)((uintptr_t)ptr)); +} + +static inline void mxu_hexdump8(const void *ptr, size_t len) { + mxu_hexdump8_ex(ptr, len, (uint64_t)((uintptr_t)ptr)); +} + diff --git a/system/ulib/mxu/include/mxu/list.h b/system/ulib/mxu/include/mxu/list.h new file mode 100644 index 000000000..6f816fedc --- /dev/null +++ b/system/ulib/mxu/include/mxu/list.h @@ -0,0 +1,268 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +__BEGIN_CDECLS; + +#define containerof(ptr, type, member) ((type*)((uintptr_t)(ptr)-offsetof(type, member))) + +typedef struct list_node list_node_t; + +struct list_node { + list_node_t* prev; + list_node_t* next; +}; + +#define LIST_INITIAL_VALUE(list) \ + { &(list), &(list) } +#define LIST_INITIAL_CLEARED_VALUE \ + { NULL, NULL } + +static inline void list_initialize(list_node_t* list) { + list->prev = list->next = list; +} + +static inline void list_clear_node(list_node_t* item) { + item->prev = item->next = 0; +} + +static inline bool list_in_list(list_node_t* item) { + if (item->prev == 0 && item->next == 0) + return false; + else + return true; +} + +static inline void list_add_head(list_node_t* list, list_node_t* item) { + item->next = list->next; + item->prev = list; + list->next->prev = item; + list->next = item; +} + +#define list_add_after(entry, new_entry) list_add_head(entry, new_entry) + +static inline void list_add_tail(list_node_t* list, list_node_t* item) { + item->prev = list->prev; + item->next = list; + list->prev->next = item; + list->prev = item; +} + +#define list_add_before(entry, new_entry) list_add_tail(entry, new_entry) + +static inline void list_delete(list_node_t* item) { + item->next->prev = item->prev; + item->prev->next = item->next; + item->prev = item->next = 0; +} + +static inline list_node_t* list_remove_head(list_node_t* list) { + if (list->next != list) { + list_node_t* item = list->next; + list_delete(item); + return item; + } else { + return NULL; + } +} + +#define list_remove_head_type(list, type, element) \ + ({ \ + list_node_t* __nod = list_remove_head(list); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_remove_tail(list_node_t* list) { + if (list->prev != list) { + list_node_t* item = list->prev; + list_delete(item); + return item; + } else { + return NULL; + } +} + +#define list_remove_tail_type(list, type, element) \ + ({ \ + list_node_t* __nod = list_remove_tail(list); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_peek_head(list_node_t* list) { + if (list->next != list) { + return list->next; + } else { + return NULL; + } +} + +#define list_peek_head_type(list, type, element) \ + ({ \ + list_node_t* __nod = list_peek_head(list); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_peek_tail(list_node_t* list) { + if (list->prev != list) { + return list->prev; + } else { + return NULL; + } +} + +#define list_peek_tail_type(list, type, element) \ + ({ \ + list_node_t* __nod = list_peek_tail(list); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_prev(list_node_t* list, list_node_t* item) { + if (item->prev != list) + return item->prev; + else + return NULL; +} + +#define list_prev_type(list, item, type, element) \ + ({ \ + list_node_t* __nod = list_prev(list, item); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_prev_wrap(list_node_t* list, list_node_t* item) { + if (item->prev != list) + return item->prev; + else if (item->prev->prev != list) + return item->prev->prev; + else + return NULL; +} + +#define list_prev_wrap_type(list, item, type, element) \ + ({ \ + list_node_t* __nod = list_prev_wrap(list, item); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_next(list_node_t* list, list_node_t* item) { + if (item->next != list) + return item->next; + else + return NULL; +} + +#define list_next_type(list, item, type, element) \ + ({ \ + list_node_t* __nod = list_next(list, item); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +static inline list_node_t* list_next_wrap(list_node_t* list, list_node_t* item) { + if (item->next != list) + return item->next; + else if (item->next->next != list) + return item->next->next; + else + return NULL; +} + +#define list_next_wrap_type(list, item, type, element) \ + ({ \ + list_node_t* __nod = list_next_wrap(list, item); \ + type* __t; \ + if (__nod) \ + __t = containerof(__nod, type, element); \ + else \ + __t = (type*)0; \ + __t; \ + }) + +// iterates over the list, node should be list_node_t* +#define list_for_every(list, node) for (node = (list)->next; node != (list); node = node->next) + +// iterates over the list in a safe way for deletion of current node +// node and temp_node should be list_node_t* +#define list_for_every_safe(list, node, temp_node) \ + for (node = (list)->next, temp_node = (node)->next; node != (list); \ + node = temp_node, temp_node = (node)->next) + +// iterates over the list, entry should be the container structure type * +#define list_for_every_entry(list, entry, type, member) \ + for ((entry) = containerof((list)->next, type, member); &(entry)->member != (list); \ + (entry) = containerof((entry)->member.next, type, member)) + +// iterates over the list in a safe way for deletion of current node +// entry and temp_entry should be the container structure type * +#define list_for_every_entry_safe(list, entry, temp_entry, type, member) \ + for (entry = containerof((list)->next, type, member), \ + temp_entry = containerof((entry)->member.next, type, member); \ + &(entry)->member != (list); \ + entry = temp_entry, temp_entry = containerof((temp_entry)->member.next, type, member)) + +static inline bool list_is_empty(list_node_t* list) { + return (list->next == list) ? true : false; +} + +static inline size_t list_length(list_node_t* list) { + size_t cnt = 0; + list_node_t* node = list; + list_for_every(list, node) { + cnt++; + } + + return cnt; +} + +__END_CDECLS; diff --git a/system/ulib/mxu/include/mxu/unittest.h b/system/ulib/mxu/include/mxu/unittest.h new file mode 100644 index 000000000..0645858c3 --- /dev/null +++ b/system/ulib/mxu/include/mxu/unittest.h @@ -0,0 +1,313 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +/* + * Macros for writing unit tests. + * + * Sample usage: + * + * A test case runs a collection of tests like this, with + * BEGIN_TEST_CASE and END_TEST_CASE and the beginning and end of the + * function and RUN_TEST to call each individual test, as follows: + * + * BEGIN_TEST_CASE(foo_tests); + * + * RUN_TEST(test_foo); + * RUN_TEST(test_bar); + * RUN_TEST(test_baz); + * + * END_TEST_CASE(foo_tests); + * + * This creates a static function foo_tests() and registers it with the + * unit test framework. foo_tests() can be executed either by a shell + * command or by a call to run_all_tests(), which runs all registered + * unit tests. + * + * NOTE: at the moment auto-registration of tests does not work, so in order + * to register a test case, use unittest_register_test_case() before running them: + * unittest_register_test_case(&_foo_tests_element); + * + * A test looks like this, using the BEGIN_TEST and END_TEST macros at + * the beginning and end of the test and the EXPECT_* macros to + * validate test results, as shown: + * + * static bool test_foo(void) + * { + * BEGIN_TEST; + * + * ...declare variables and do stuff... + * int foo_value = foo_func(); + * ...See if the stuff produced the correct value... + * EXPECT_EQ(1, foo_value, "foo_func failed"); + * ... there are EXPECT_* macros for many conditions... + * EXPECT_TRUE(foo_condition(), "condition should be true"); + * EXPECT_NEQ(ERR_TIMED_OUT, foo_event(), "event timed out"); + * + * END_TEST; + * } + */ +#include +#include +#include +#include +#include +#include + +#include + +#define PRINT_BUFFER_SIZE (512) + +__BEGIN_CDECLS + +/* + * Type for unit test result Output + */ +typedef void (*test_output_func)(const char* line, int len, void* arg); + +/* + * Printf dedicated to the unittest library + * the default output is the printf + */ +void unittest_printf(const char* format, ...); + +/* + * Function to set the callback for printing + * the unit test output + */ +void unittest_set_output_function(test_output_func fun, void* arg); + +/* + * Macros to format the error string + */ +#define EXPECTED_STRING "%s:\n expected " +#define UNITTEST_TRACEF(str, x...) \ + do { \ + unittest_printf(" [FAILED] \n %s:%d:\n " str, \ + __PRETTY_FUNCTION__, __LINE__, ##x); \ + } while (0) + +/* + * BEGIN_TEST_CASE and END_TEST_CASE define a function that calls + * RUN_TEST. + */ +#define BEGIN_TEST_CASE(case_name) \ + bool case_name(void) \ + { \ + bool all_success = true; \ + unittest_printf("\nCASE %-50s [STARTED] \n", #case_name); + +#define DEFINE_REGISTER_TEST_CASE(case_name) \ + static void _register_##case_name(void) \ + { \ + unittest_register_test_case(&_##case_name##_element); \ + } \ + void (*_register_##case_name##_ptr)(void) __SECTION(".ctors") = \ + _register_##case_name; + +#define END_TEST_CASE(case_name) \ + if (all_success) { \ + unittest_printf("CASE %-50s [PASSED]\n", #case_name); \ + } else { \ + unittest_printf("CASE %-50s [FAILED]\n", #case_name); \ + } \ + return all_success; \ + } \ + static struct test_case_element _##case_name##_element = { \ + .next = NULL, \ + .failed_next = NULL, \ + .name = #case_name, \ + .test_case = case_name, \ + }; \ + DEFINE_REGISTER_TEST_CASE(case_name); + +#define RUN_TEST(test) \ + unittest_printf(" %-51s [RUNNING]", #test); \ + if (!test()) { \ + all_success = false; \ + } else { \ + unittest_printf(" [PASSED] \n"); \ + } + +/* + * BEGIN_TEST and END_TEST go in a function that is called by RUN_TEST + * and that call the EXPECT_ macros. + */ +#define BEGIN_TEST bool all_ok = true +#define END_TEST return all_ok + +#ifdef __cplusplus +#define AUTO_TYPE_VAR(type) auto& +#else +#define AUTO_TYPE_VAR(type) __typeof__(type) +#endif + +/* + * Use the EXPECT_* macros to check test results. + */ +#define EXPECT_EQ(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e != _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld), " \ + "actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_NEQ(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + if (_e == (actual)) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld), %s" \ + " to differ, but they are the same %ld\n", \ + msg, #expected, (long)_e, #actual); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_LE(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e > _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " less-than-or-equal-to actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_LT(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e >= _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " less-than actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_GE(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e < _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " greater-than-or-equal-to actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_GT(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e <= _a) { \ + UNITTEST_TRACEF(EXPECTED_STRING \ + "%s (%ld) to be" \ + " greater-than actual %s (%ld)\n", \ + msg, #expected, (long)_e, #actual, (long)_a); \ + all_ok = false; \ + } \ + } while (0) + +#define EXPECT_TRUE(actual, msg) \ + if (!(actual)) { \ + UNITTEST_TRACEF("%s: %s is false\n", msg, #actual); \ + all_ok = false; \ + } + +#define EXPECT_FALSE(actual, msg) \ + if (actual) { \ + UNITTEST_TRACEF("%s: %s is true\n", msg, #actual); \ + all_ok = false; \ + } + +#define EXPECT_BYTES_EQ(expected, actual, length, msg) \ + if (!unittest_expect_bytes_eq((expected), (actual), (length), msg)) { \ + all_ok = false; \ + } + +#define EXPECT_BYTES_NE(bytes1, bytes2, length, msg) \ + if (!memcmp(bytes1, bytes2, length)) { \ + UNITTEST_TRACEF( \ + "%s and %s are the same; " \ + "expected different\n", \ + #bytes1, #bytes2); \ + hexdump8(bytes1, length); \ + all_ok = false; \ + } + +/* For comparing uint64_t, like hw_id_t. */ +#define EXPECT_EQ_LL(expected, actual, msg) \ + do { \ + const AUTO_TYPE_VAR(expected) _e = (expected); \ + const AUTO_TYPE_VAR(actual) _a = (actual); \ + if (_e != _a) { \ + UNITTEST_TRACEF("%s: expected %llu, actual %llu\n", msg, _e, _a); \ + all_ok = false; \ + } \ + } while (0) + +/* + * The ASSERT_* macros are similar to the EXPECT_* macros except that + * they return on failure. + */ +#define ASSERT_NOT_NULL(p) \ + if (!p) { \ + UNITTEST_TRACEF("ERROR: NULL pointer\n"); \ + return false; \ + } + +/* + * The list of test cases is made up of these elements. + */ +struct test_case_element { + struct test_case_element* next; + struct test_case_element* failed_next; + const char* name; + bool (*test_case)(void); +}; + +/* + * Registers a test case with the unit test framework. + */ +void unittest_register_test_case(struct test_case_element* elem); + +/* + * Runs all registered test cases. + */ +bool unittest_run_all_tests(void); + +/* + * Returns false if expected does not equal actual and prints msg and a hexdump8 + * of the input buffers. + */ +bool unittest_expect_bytes_eq(const uint8_t* expected, const uint8_t* actual, size_t len, + const char* msg); + +__END_CDECLS + diff --git a/system/ulib/mxu/rules.mk b/system/ulib/mxu/rules.mk new file mode 100644 index 000000000..42c89bf37 --- /dev/null +++ b/system/ulib/mxu/rules.mk @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS += \ + $(LOCAL_DIR)/hexdump.c \ + $(LOCAL_DIR)/fifo.c \ + $(LOCAL_DIR)/unittest/all_tests.c \ + $(LOCAL_DIR)/unittest/unittest.c + +MODULE_DEPS += \ + ulib/musl \ + ulib/magenta \ + ulib/runtime + +include make/module.mk diff --git a/system/ulib/mxu/unittest/all_tests.c b/system/ulib/mxu/unittest/all_tests.c new file mode 100644 index 000000000..ae435f3df --- /dev/null +++ b/system/ulib/mxu/unittest/all_tests.c @@ -0,0 +1,72 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +static struct test_case_element *test_case_list = NULL; +static struct test_case_element *failed_test_case_list = NULL; + +/* + * Registers a test case with the unit test framework. + */ +void unittest_register_test_case(struct test_case_element *elem) +{ + elem->next = test_case_list; + test_case_list = elem; +} + +/* + * Runs all registered test cases. + */ +bool unittest_run_all_tests(void) +{ + unsigned int n_tests = 0; + unsigned int n_success = 0; + unsigned int n_failed = 0; + + bool all_success = true; + struct test_case_element *current = test_case_list; + while (current) { + if (!current->test_case()) { + current->failed_next = failed_test_case_list; + failed_test_case_list = current; + all_success = false; + } + current = current->next; + n_tests++; + } + + if (all_success) { + n_success = n_tests; + unittest_printf("SUCCESS! All test cases passed!\n"); + } else { + struct test_case_element *failed = failed_test_case_list; + while (failed) { + struct test_case_element *failed_next = + failed->failed_next; + failed->failed_next = NULL; + failed = failed_next; + n_failed++; + } + n_success = n_tests - n_failed; + failed_test_case_list = NULL; + } + + unittest_printf("\n====================================================\n"); + unittest_printf (" CASES: %d SUCCESS: %d FAILED: %d ", + n_tests, n_success, n_failed); + unittest_printf("\n====================================================\n"); + + return all_success; +} diff --git a/system/ulib/mxu/unittest/unittest.c b/system/ulib/mxu/unittest/unittest.c new file mode 100644 index 000000000..4c1a68ae2 --- /dev/null +++ b/system/ulib/mxu/unittest/unittest.c @@ -0,0 +1,80 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include +#include +#include + +#include + +/** + * \brief Default function to dump unit test results + * + * \param[in] line is the buffer to dump + * \param[in] len is the length of the buffer to dump + * \param[in] arg can be any kind of arguments needed to dump the values + */ +static void default_printf (const char *line, int len, void *arg) +{ + printf ("%s", line); +} + +// Default output function is the printf +static test_output_func out_func = default_printf; +// Buffer the argument to be sent to the output function +static void *out_func_arg = NULL; + +/** + * \brief Function called to dump results + * + * This function will call the out_func callback + */ +void unittest_printf (const char *format, ...) +{ + static char print_buffer[PRINT_BUFFER_SIZE]; + + va_list argp; + va_start (argp, format); + + if (out_func != NULL) { + // Format the string + vsnprintf(print_buffer, PRINT_BUFFER_SIZE, format, argp); + out_func (print_buffer, PRINT_BUFFER_SIZE, out_func_arg); + } + + va_end (argp); +} + +bool unittest_expect_bytes_eq(const uint8_t *expected, const uint8_t *actual, size_t len, + const char *msg) +{ + if (memcmp(expected, actual, len)) { + printf("%s. expected\n", msg); + mxu_hexdump8(expected, len); + printf("actual\n"); + mxu_hexdump8(actual, len); + return false; + } + return true; +} + +void unittest_set_output_function (test_output_func fun, void *arg) +{ + out_func = fun; + out_func_arg = arg; +} diff --git a/system/ulib/runtime/BUILD.gn b/system/ulib/runtime/BUILD.gn new file mode 100644 index 000000000..0a9f62e3d --- /dev/null +++ b/system/ulib/runtime/BUILD.gn @@ -0,0 +1,43 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_runtime_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +source_set("runtime") { + public_configs = [ ":_runtime_config" ] + include_dirs = [ "//third_party/ulib/musl/include" ] + public = [ + "include/runtime/atomic.h", + "include/runtime/mutex.h", + "include/runtime/process.h", + "include/runtime/status.h", + "include/runtime/tls.h", + ] + sources = [ + "mutex.c", + "process.c", + "strstatus.c", + "thread.c", + "tls.c", + ] + deps = [ + "//system/ulib/magenta", + ] + public_deps = [ + "//system/ulib/global", + ] +} diff --git a/system/ulib/runtime/include/runtime/atomic.h b/system/ulib/runtime/include/runtime/atomic.h new file mode 100644 index 000000000..ebfa210b3 --- /dev/null +++ b/system/ulib/runtime/include/runtime/atomic.h @@ -0,0 +1,98 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +/* Strongly ordered, and then relaxed, versions of the atomic routines + * as implemented by the compiler with arch-dependent memory + * barriers. Defined for with a short name for int, and with longer + * names for sized integers. + */ +#define __MAKE_ATOMICS(TYPE, TYPE_NAME) \ + static inline TYPE atomic_swap##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST); \ + } \ + \ + static inline TYPE atomic_add##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST); \ + } \ + \ + static inline TYPE atomic_and##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_fetch_and(ptr, val, __ATOMIC_SEQ_CST); \ + } \ + \ + static inline TYPE atomic_or##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_fetch_or(ptr, val, __ATOMIC_SEQ_CST); \ + } \ + \ + static inline bool atomic_cmpxchg##TYPE_NAME(volatile TYPE* ptr, TYPE* oldval, TYPE newval) { \ + return __atomic_compare_exchange_n(ptr, oldval, newval, 0, \ + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \ + } \ + \ + static inline TYPE atomic_load##TYPE_NAME(volatile TYPE* ptr) { \ + return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); \ + } \ + \ + static inline void atomic_store##TYPE_NAME(volatile TYPE* ptr, TYPE newval) { \ + __atomic_store_n(ptr, newval, __ATOMIC_SEQ_CST); \ + } \ + \ + /* relaxed versions of the above */ \ + static inline TYPE atomic_swap_relaxed##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_exchange_n(ptr, val, __ATOMIC_RELAXED); \ + } \ + \ + static inline TYPE atomic_add_relaxed##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED); \ + } \ + \ + static inline TYPE atomic_and_relaxed##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_fetch_and(ptr, val, __ATOMIC_RELAXED); \ + } \ + \ + static inline TYPE atomic_or_relaxed##TYPE_NAME(volatile TYPE* ptr, TYPE val) { \ + return __atomic_fetch_or(ptr, val, __ATOMIC_RELAXED); \ + } \ + \ + static inline TYPE atomic_cmpxchg_relaxed##TYPE_NAME(volatile TYPE* ptr, TYPE oldval, TYPE newval) { \ + (void)__atomic_compare_exchange_n(ptr, &oldval, newval, 0, \ + __ATOMIC_RELAXED, __ATOMIC_RELAXED); \ + return oldval; \ + } \ + \ + static TYPE atomic_load_relaxed##TYPE_NAME(volatile TYPE* ptr) { \ + return __atomic_load_n(ptr, __ATOMIC_RELAXED); \ + } \ + \ + static void atomic_store_relaxed##TYPE_NAME(volatile TYPE* ptr, TYPE newval) { \ + __atomic_store_n(ptr, newval, __ATOMIC_RELAXED); \ + } + +__MAKE_ATOMICS(uint8_t, _uint8) +__MAKE_ATOMICS(uint16_t, _uint16) +__MAKE_ATOMICS(uint32_t, _uint32) +__MAKE_ATOMICS(uint64_t, _uint64) +__MAKE_ATOMICS(int8_t, _int8) +__MAKE_ATOMICS(int16_t, _int16) +__MAKE_ATOMICS(int32_t, _int32) +__MAKE_ATOMICS(int64_t, _int64) +__MAKE_ATOMICS(int, ) + +__END_CDECLS diff --git a/system/ulib/runtime/include/runtime/mutex.h b/system/ulib/runtime/include/runtime/mutex.h new file mode 100644 index 000000000..b85859eef --- /dev/null +++ b/system/ulib/runtime/include/runtime/mutex.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +typedef struct { + int futex; +} mxr_mutex_t; + +#define MXR_MUTEX_INIT ((mxr_mutex_t) { 0 }) + +mx_status_t mxr_mutex_trylock(mxr_mutex_t* mutex); +mx_status_t mxr_mutex_timedlock(mxr_mutex_t* mutex, mx_time_t timeout); +void mxr_mutex_lock(mxr_mutex_t* mutex); +void mxr_mutex_unlock(mxr_mutex_t* mutex); + +__END_CDECLS diff --git a/system/ulib/runtime/include/runtime/process.h b/system/ulib/runtime/include/runtime/process.h new file mode 100644 index 000000000..3a8e6fb22 --- /dev/null +++ b/system/ulib/runtime/include/runtime/process.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +// Parse the argument of _start() and setup the global +// proc info structure. Return a pointer to the same. +mx_proc_info_t* mxr_process_parse_args(void* arg); + +// Obtain the global proc info structure +mx_proc_info_t* mxr_process_get_info(void); + +// Obtain a handle from proc args, if such a handle exists +mx_handle_t mxr_process_get_handle(uint32_t id); + +__END_CDECLS diff --git a/system/ulib/runtime/include/runtime/status.h b/system/ulib/runtime/include/runtime/status.h new file mode 100644 index 000000000..9ad3305a5 --- /dev/null +++ b/system/ulib/runtime/include/runtime/status.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +const char* mx_strstatus(mx_status_t status); + +#ifdef __cplusplus +} +#endif diff --git a/system/ulib/runtime/include/runtime/thread.h b/system/ulib/runtime/include/runtime/thread.h new file mode 100644 index 000000000..0c83c5aea --- /dev/null +++ b/system/ulib/runtime/include/runtime/thread.h @@ -0,0 +1,30 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +__BEGIN_CDECLS + +typedef int (*mxr_thread_entry_t)(void*); + +typedef struct mxr_thread mxr_thread_t; + +mx_status_t mxr_thread_create(mxr_thread_entry_t entry, void* arg, const char* name, mxr_thread_t** thread_out); +mx_status_t mxr_thread_join(mxr_thread_t* thread, int* return_value_out); +mx_status_t mxr_thread_detach(mxr_thread_t* thread); + +__END_CDECLS diff --git a/system/ulib/runtime/include/runtime/tls.h b/system/ulib/runtime/include/runtime/tls.h new file mode 100644 index 000000000..a19e5c54a --- /dev/null +++ b/system/ulib/runtime/include/runtime/tls.h @@ -0,0 +1,81 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +__BEGIN_CDECLS + +typedef uint32_t mxr_tls_t; + +#define MXR_TLS_SLOT_MAX ((mxr_tls_t)256) +#define MXR_TLS_SLOT_SELF ((mxr_tls_t)0) +#define MXR_TLS_SLOT_ERRNO ((mxr_tls_t)1) +#define MXR_TLS_SLOT_INVALID ((mxr_tls_t)-1) + +#if defined(__aarch64__) +static inline mx_tls_root_t* mxr_tls_root_get(void) { + mx_tls_root_t* tlsroot; + __asm__ volatile("mrs %0, tpidr_el0" : "=r" (tlsroot)); + return tlsroot; +} +static inline mx_status_t mxr_tls_root_set(mx_tls_root_t* tlsroot) { + __asm__ volatile("msr tpidr_el0, %0" : : "r" (tlsroot)); + return NO_ERROR; +} + +#elif defined(__arm__) +static inline mx_tls_root_t* mxr_tls_root_get(void) { + mx_tls_root_t* tlsroot; + __asm__ __volatile__("mrc p15, 0, %0, c13, c0, 3" : "=r"(tlsroot)); + return tlsroot; +} +static inline mx_status_t mxr_tls_root_set(mx_tls_root_t* tlsroot) { + // TODO(kulakowski) Thread self handle. + mx_handle_t self = 0; + return _magenta_thread_arch_prctl(self, ARCH_SET_CP15_READONLY, (uintptr_t*)&tlsroot); +} + +#elif defined(__x86_64__) +static inline mx_tls_root_t* mxr_tls_root_get(void) { + mx_tls_root_t* tlsroot; + __asm__ __volatile__("mov %%fs:0,%0" : "=r"(tlsroot)); + return tlsroot; +} +static inline mx_status_t mxr_tls_root_set(mx_tls_root_t* tlsroot) { + // TODO(kulakowski) Thread self handle. + mx_handle_t self = 0; + return _magenta_thread_arch_prctl(self, ARCH_SET_FS, (uintptr_t*)&tlsroot); +} + +#else +#error Unsupported architecture + +#endif + +mxr_tls_t mxr_tls_allocate(void); + +static inline void* mxr_tls_get(mxr_tls_t slot) { + return mxr_tls_root_get()->slots[slot]; +} + +static inline void mxr_tls_set(mxr_tls_t slot, void* value) { + mxr_tls_root_get()->slots[slot] = value; +} + +__END_CDECLS diff --git a/system/ulib/runtime/mutex.c b/system/ulib/runtime/mutex.c new file mode 100644 index 000000000..052d9bc67 --- /dev/null +++ b/system/ulib/runtime/mutex.c @@ -0,0 +1,70 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +#include + +// TODO(kulakowski) Reintroduce (correctly) optimization counting waiters. + +// These values have to be as such. UNLOCKED == 0 allows locks to be +// statically allocated, and the ordering of the values is relied upon +// in the atomic decrement in the unlock routine. +enum { + UNLOCKED = 0, + LOCKED = 1, +}; + +mx_status_t mxr_mutex_trylock(mxr_mutex_t* mutex) { + int futex_value = atomic_cmpxchg(&mutex->futex, UNLOCKED, LOCKED); + if (futex_value != UNLOCKED) + return ERR_BUSY; + return NO_ERROR; +} + +mx_status_t mxr_mutex_timedlock(mxr_mutex_t* mutex, mx_time_t timeout) { + for (;;) { + switch(__atomic_exchange_n(&mutex->futex, LOCKED, __ATOMIC_SEQ_CST)) { + case UNLOCKED: + return NO_ERROR; + case LOCKED: { + mx_status_t status = _magenta_futex_wait(&mutex->futex, LOCKED, timeout); + if (status == ERR_BUSY) { + continue; + } + if (status != NO_ERROR) { + return status; + } + continue; + } + } + } +} + +void mxr_mutex_lock(mxr_mutex_t* mutex) { + mx_status_t status = mxr_mutex_timedlock(mutex, MX_TIME_INFINITE); + if (status != NO_ERROR) + abort(); +} + +void mxr_mutex_unlock(mxr_mutex_t* mutex) { + __atomic_store_n(&mutex->futex, UNLOCKED, __ATOMIC_SEQ_CST); + mx_status_t status = _magenta_futex_wake(&mutex->futex, 0x7FFFFFFF); + if (status != NO_ERROR) + abort(); +} diff --git a/system/ulib/runtime/process.c b/system/ulib/runtime/process.c new file mode 100644 index 000000000..76c1926ef --- /dev/null +++ b/system/ulib/runtime/process.c @@ -0,0 +1,111 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include +#include + +#include +#include +#include + +// TODO: allocate via vmo perhaps? +static char __proc_data__[4096]; +static mx_proc_info_t __proc_info__; + +mx_proc_info_t* mxr_process_get_info(void) { + return &__proc_info__; +} + +mx_handle_t mxr_process_get_handle(uint32_t info) { + mx_proc_info_t* pi = &__proc_info__; + mx_handle_t h = 0; + + // TODO: locking once mxr_mutex exists + for (int n = 0; n < pi->handle_count; n++) { + if (pi->handle_info[n] == info) { + h = pi->handle[n]; + pi->handle[n] = 0; + pi->handle_info[n] = 0; + break; + } + } + return h; +} + +mx_proc_info_t* mxr_process_parse_args(void* arg) { + char* data = __proc_data__; + int avail = sizeof(__proc_data__); + mx_proc_info_t* pi = &__proc_info__; + mx_handle_t h = (uintptr_t) arg; + mx_status_t r; + uint32_t dsz = 0, hsz = 0; + char *msg = NULL; + mx_proc_args_t *pargs; + char **argv; + uint32_t n; + + memset(pi, 0, sizeof(*pi)); + + // discover size of message and handles, allocate space + r = _magenta_message_read(h, NULL, &dsz, NULL, &hsz, 0); + if (r == ERR_NOT_ENOUGH_BUFFER) { + int need = dsz + hsz * sizeof(mx_handle_t); + need = (need + 7) & (~7); + if (need > avail) return pi; + msg = data; + data += need; + avail -= need; + pi->handle = (mx_handle_t *) msg; + pi->handle_count = hsz; + msg += sizeof(mx_handle_t) * hsz; + } else { + return pi; + } + + // obtain message and handles + r = _magenta_message_read(h, msg, &dsz, pi->handle, &hsz, 0); + _magenta_handle_close(h); + if (r < 0) { + return pi; + } + + // validate proc args + pi->proc_args = pargs = (mx_proc_args_t*) msg; + if (dsz < sizeof(*pargs)) return pi; + if (pargs->protocol != MX_PROCARGS_PROTOCOL) return pi; + + // setup handle info + pi->handle_info = (uint32_t*) (msg + pargs->handle_info_off); + + // extract arguments + if ((sizeof(char*) * pargs->args_num) > (unsigned)avail) return pi; + argv = (void*) data; + + msg = msg + pargs->args_off; + for (n = 0; n < pargs->args_num; n++) { + argv[n] = msg; + while (*msg) msg++; + msg++; + } + + pi->magic = MX_PROC_INFO_MAGIC; + pi->version = MX_PROC_INFO_VERSION; + pi->argc = pargs->args_num; + pi->argv = argv; + return pi; +} diff --git a/system/ulib/runtime/rules.mk b/system/ulib/runtime/rules.mk new file mode 100644 index 000000000..575ac14f8 --- /dev/null +++ b/system/ulib/runtime/rules.mk @@ -0,0 +1,35 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS := \ + $(LOCAL_DIR)/mutex.c \ + $(LOCAL_DIR)/process.c \ + $(LOCAL_DIR)/strstatus.c \ + $(LOCAL_DIR)/thread.c \ + $(LOCAL_DIR)/tls.c \ + +MODULE_DEPS += \ + ulib/magenta + +# for stdint.h +MODULE_HEADER_DEPS += \ + ulib/musl + +include make/module.mk diff --git a/system/ulib/runtime/strstatus.c b/system/ulib/runtime/strstatus.c new file mode 100644 index 000000000..4d6cd3b94 --- /dev/null +++ b/system/ulib/runtime/strstatus.c @@ -0,0 +1,75 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +static struct { + mx_status_t status; + const char* string; +} table[] = { + { NO_ERROR, "NO_ERROR" }, + { ERR_GENERIC, "ERR_GENERIC" }, + { ERR_NOT_FOUND, "ERR_NOT_FOUND" }, + { ERR_NOT_READY, "ERR_NOT_READY" }, + { ERR_NO_MSG, "ERR_NO_MSG" }, + { ERR_NO_MEMORY, "ERR_NO_MEMORY" }, + { ERR_ALREADY_STARTED, "ERR_ALREADY_STARTED" }, + { ERR_NOT_VALID, "ERR_NOT_VALID" }, + { ERR_INVALID_ARGS, "ERR_INVALID_ARGS" }, + { ERR_NOT_ENOUGH_BUFFER, "ERR_NOT_ENOUGH_BUFFER" }, + { ERR_NOT_SUSPENDED, "ERR_NOT_SUSPENDED" }, + { ERR_OBJECT_DESTROYED, "ERR_OBJECT_DESTROYED" }, + { ERR_NOT_BLOCKED, "ERR_NOT_BLOCKED" }, + { ERR_TIMED_OUT, "ERR_TIMED_OUT" }, + { ERR_ALREADY_EXISTS, "ERR_ALREADY_EXISTS" }, + { ERR_CHANNEL_CLOSED, "ERR_CHANNEL_CLOSED" }, + { ERR_OFFLINE, "ERR_OFFLINE" }, + { ERR_NOT_ALLOWED, "ERR_NOT_ALLOWED" }, + { ERR_BAD_PATH, "ERR_BAD_PATH" }, + { ERR_ALREADY_MOUNTED, "ERR_ALREADY_MOUNTED" }, + { ERR_IO, "ERR_IO" }, + { ERR_NOT_DIR, "ERR_NOT_DIR" }, + { ERR_NOT_FILE, "ERR_NOT_FILE" }, + { ERR_RECURSE_TOO_DEEP, "ERR_RECURSE_TOO_DEEP" }, + { ERR_NOT_SUPPORTED, "ERR_NOT_SUPPORTED" }, + { ERR_TOO_BIG, "ERR_TOO_BIG" }, + { ERR_CANCELLED, "ERR_CANCELLED" }, + { ERR_NOT_IMPLEMENTED, "ERR_NOT_IMPLEMENTED" }, + { ERR_CHECKSUM_FAIL, "ERR_CHECKSUM_FAIL" }, + { ERR_CRC_FAIL, "ERR_CRC_FAIL" }, + { ERR_CMD_UNKNOWN, "ERR_CMD_UNKNOWN" }, + { ERR_BAD_STATE, "ERR_BAD_STATE" }, + { ERR_BAD_LEN, "ERR_BAD_LEN" }, + { ERR_BUSY, "ERR_BUSY" }, + { ERR_THREAD_DETACHED, "ERR_THREAD_DETACHED" }, + { ERR_I2C_NACK, "ERR_I2C_NACK" }, + { ERR_ALREADY_EXPIRED, "ERR_ALREADY_EXPIRED" }, + { ERR_OUT_OF_RANGE, "ERR_OUT_OF_RANGE" }, + { ERR_NOT_CONFIGURED, "ERR_NOT_CONFIGURED" }, + { ERR_NOT_MOUNTED, "ERR_NOT_MOUNTED" }, + { ERR_FAULT, "ERR_FAULT" }, + { ERR_NO_RESOURCES, "ERR_NO_RESOURCES" }, + { ERR_BAD_HANDLE, "ERR_BAD_HANDLE" }, + { ERR_ACCESS_DENIED, "ERR_ACCESS_DENIED" }, + { ERR_PARTIAL_WRITE, "ERR_PARTIAL_WRITE" }, + { ERR_BAD_SYSCALL, "ERR_BAD_SYSCALL" }, +}; + +const char* mx_strstatus(mx_status_t status) { + for (unsigned idx = 0; idx < sizeof(table) / sizeof(*table); idx++) + if (table[idx].status == status) + return table[idx].string; + + return "No such mx_status_t"; +} diff --git a/system/ulib/runtime/thread.c b/system/ulib/runtime/thread.c new file mode 100644 index 000000000..f706486cb --- /dev/null +++ b/system/ulib/runtime/thread.c @@ -0,0 +1,230 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// An mxr_thread_t starts its life JOINABLE. +// - If someone calls mxr_thread_join on it, it transitions to JOINED. +// - If someone calls mxr_thread_detach on it, it transitions to DETACHED. +// - If it returns before one of those calls is made, it transitions to DONE. +// No other transitions occur. +enum { + JOINABLE, + JOINED, + DETACHED, + DONE, +}; + +struct mxr_thread { + mx_handle_t handle; + int return_value; + mxr_thread_entry_t entry; + void* arg; + + int errno_value; + + mxr_mutex_t state_lock; + int state; + + mx_tls_root_t tls_root; +}; + +static mx_status_t allocate_thread_page(mxr_thread_t** thread_out) { + // TODO(kulakowski) Pull out this allocation function out + // somewhere once we have the ability to hint to the vm how and + // where to allocate threads, stacks, heap etc. + + mx_size_t len = sizeof(mxr_thread_t); + // mx_tls_root_t already accounts for 1 tls slot. + len += (MXR_TLS_SLOT_MAX - 1) * sizeof(void*); + len += PAGE_SIZE - 1; + len &= ~(PAGE_SIZE - 1); + + mx_handle_t vmo = _magenta_vm_object_create(len); + if (vmo < 0) + return (mx_status_t)vmo; + + // TODO(kulakowski) Track process handle. + mx_handle_t self_handle = 0; + uintptr_t mapping = 0; + uint32_t flags = MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE; + mx_status_t status = _magenta_process_vm_map(self_handle, vmo, 0, len, &mapping, flags); + if (status != NO_ERROR) { + _magenta_handle_close(vmo); + return status; + } + + _magenta_handle_close(vmo); + *thread_out = (mxr_thread_t*)mapping; + return NO_ERROR; +} + +static mx_status_t deallocate_thread_page(mxr_thread_t* thread) { + // TODO(kulakowski) Track process handle. + mx_handle_t self_handle = 0; + uintptr_t mapping = (uintptr_t)thread; + return _magenta_process_vm_unmap(self_handle, mapping, 0u); +} + +static mx_status_t thread_cleanup(mxr_thread_t* thread, int* return_value_out) { + mx_status_t status = _magenta_handle_close(thread->handle); + if (status != NO_ERROR) + return status; + int return_value = thread->return_value; + status = deallocate_thread_page(thread); + if (status != NO_ERROR) + return status; + if (return_value_out) + *return_value_out = return_value; + return NO_ERROR; +} + +static void init_tls(mxr_thread_t* thread) { + thread->tls_root.self = &thread->tls_root; + thread->tls_root.proc = mxr_process_get_info(); + thread->tls_root.proc = NULL; + thread->tls_root.magic = MX_TLS_ROOT_MAGIC; + thread->tls_root.flags = 0; + thread->tls_root.maxslots = MXR_TLS_SLOT_MAX; + memset(&thread->tls_root.slots, 0, MXR_TLS_SLOT_MAX * sizeof(void*)); + mxr_tls_root_set(&thread->tls_root); + mxr_tls_set(MXR_TLS_SLOT_SELF, &thread->tls_root); + mxr_tls_set(MXR_TLS_SLOT_ERRNO, &thread->errno_value); +} + +static int thread_trampoline(void* ctx) { + mxr_thread_t* thread = (mxr_thread_t*)ctx; + + init_tls(thread); + + thread->return_value = thread->entry(thread->arg); + + mxr_mutex_lock(&thread->state_lock); + switch (thread->state) { + case JOINED: + mxr_mutex_unlock(&thread->state_lock); + break; + case JOINABLE: + thread->state = DONE; + mxr_mutex_unlock(&thread->state_lock); + break; + case DETACHED: + mxr_mutex_unlock(&thread->state_lock); + thread_cleanup(thread, NULL); + break; + case DONE: + // Not reached. + abort(); + } + + _magenta_thread_exit(); + return 0; +} + +mx_status_t mxr_thread_create(mxr_thread_entry_t entry, void* arg, const char* name, mxr_thread_t** thread_out) { + mxr_thread_t* thread = NULL; + mx_status_t status = allocate_thread_page(&thread); + if (status < 0) + return status; + + thread->entry = entry; + thread->arg = arg; + thread->state_lock = MXR_MUTEX_INIT; + thread->state = JOINABLE; + + if (name == NULL) + name = ""; + size_t name_length = strlen(name) + 1; + mx_handle_t handle = _magenta_thread_create(thread_trampoline, thread, name, name_length); + if (handle < 0) { + deallocate_thread_page(thread); + return (mx_status_t)handle; + } + thread->handle = handle; + *thread_out = thread; + return NO_ERROR; +} + +mx_status_t mxr_thread_join(mxr_thread_t* thread, int* return_value_out) { + mxr_mutex_lock(&thread->state_lock); + switch (thread->state) { + case JOINED: + case DETACHED: + mxr_mutex_unlock(&thread->state_lock); + return ERR_INVALID_ARGS; + case JOINABLE: { + thread->state = JOINED; + mxr_mutex_unlock(&thread->state_lock); + mx_status_t status = _magenta_handle_wait_one(thread->handle, MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL); + if (status != NO_ERROR) + return status; + break; + } + case DONE: + mxr_mutex_unlock(&thread->state_lock); + break; + } + + return thread_cleanup(thread, return_value_out); +} + +mx_status_t mxr_thread_detach(mxr_thread_t* thread) { + mx_status_t status = NO_ERROR; + mxr_mutex_lock(&thread->state_lock); + switch (thread->state) { + case JOINABLE: + thread->state = DETACHED; + mxr_mutex_unlock(&thread->state_lock); + break; + case JOINED: + case DETACHED: + mxr_mutex_unlock(&thread->state_lock); + status = ERR_INVALID_ARGS; + break; + case DONE: + mxr_mutex_unlock(&thread->state_lock); + status = thread_cleanup(thread, NULL); + break; + } + + return status; +} + +void __mxr_thread_main(void) { + mxr_tls_t self_slot = mxr_tls_allocate(); + mxr_tls_t errno_slot = mxr_tls_allocate(); + + if (self_slot != MXR_TLS_SLOT_SELF || + errno_slot != MXR_TLS_SLOT_ERRNO) + abort(); + + mxr_thread_t* thread = NULL; + allocate_thread_page(&thread); + init_tls(thread); + thread->state_lock = MXR_MUTEX_INIT; + thread->state = JOINABLE; + // TODO(kulakowski) Once the main thread is passed a handle, save it here. + thread->handle = MX_HANDLE_INVALID; +} diff --git a/system/ulib/runtime/tls.c b/system/ulib/runtime/tls.c new file mode 100644 index 000000000..56319a8d9 --- /dev/null +++ b/system/ulib/runtime/tls.c @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +mxr_tls_t mxr_tls_allocate(void) { + mxr_tls_t* next_slot = &mxr_process_get_info()->next_tls_slot; + mxr_tls_t slot = atomic_add_uint32(next_slot, 1); + if (slot < MXR_TLS_SLOT_MAX) + return slot; + atomic_store_uint32(next_slot, MXR_TLS_SLOT_MAX); + return MXR_TLS_SLOT_INVALID; +} diff --git a/system/utest/arch-registers/BUILD.gn b/system/utest/arch-registers/BUILD.gn new file mode 100644 index 000000000..ef5e59b9e --- /dev/null +++ b/system/utest/arch-registers/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("arch-registers") { + output_name = "arch-registers-test" + sources = [ + "arch-registers.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/arch-registers/arch-registers.c b/system/utest/arch-registers/arch-registers.c new file mode 100644 index 000000000..345fe5a8f --- /dev/null +++ b/system/utest/arch-registers/arch-registers.c @@ -0,0 +1,249 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +static void fail(const char* function, int line, const char* message) { + printf("arch_registers test failure in " __FILE__ ": %s: line %d:%s\n", function, line, + message); + _magenta_exit(-1); +} + +static void yield(void) { + _magenta_nanosleep(0u); +} + +typedef uintptr_t (*register_getter)(mx_handle_t); +typedef void (*register_setter)(mx_handle_t, uintptr_t); + +typedef struct register_ops { + register_getter get; + register_setter set; + const char* name; +} register_ops; + +#if defined(__aarch64__) +static uintptr_t tpidrro_el0_get(mx_handle_t handle) { + uintptr_t value; + __asm__ volatile( + "mrs %0," + "tpidrro_el0" + : "=r"(value)); + return value; +} +static void tpidrro_el0_set(mx_handle_t handle, uintptr_t value) { + mx_status_t status = _magenta_thread_arch_prctl(handle, ARCH_SET_TPIDRRO_EL0, &value); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__, " failed to set!"); +} +static register_ops ops[] = { + { + &tpidrro_el0_get, &tpidrro_el0_set, "tpidrro_el0", + }, +}; +static uintptr_t make_valid_value(uintptr_t value) { + return value; +} +#elif defined(__arm__) +static uintptr_t cp15_readonly_get(mx_handle_t handle) { + uintptr_t value; + __asm__ volatile("mrc p15, 0, %0, c13, c0, 3" + : "=r"(value)); + return value; +} +static void cp15_readonly_set(mx_handle_t handle, uintptr_t value) { + mx_status_t status = _magenta_thread_arch_prctl(handle, ARCH_SET_CP15_READONLY, &value); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__, " failed to set!"); +} +static uintptr_t cp15_readwrite_get(mx_handle_t handle) { + uintptr_t value; + __asm__ volatile("mrc p15, 0, %0, c13, c0, 2" + : "=r"(value)); + return value; +} +static void cp15_readwrite_set(mx_handle_t handle, uintptr_t value) { + __asm__ volatile("mcr p15, 0, %0, c13, c0, 2" + : + : "r"(value)); +} +static register_ops ops[] = { + { + &cp15_readonly_get, &cp15_readonly_set, "cp15_readonly", + }, + { + &cp15_readwrite_get, &cp15_readwrite_set, "cp15_readwrite", + }, +}; +static uintptr_t make_valid_value(uintptr_t value) { + return value; +} +#elif defined(__x86_64__) +static uintptr_t fs_get(mx_handle_t handle) { + uintptr_t value; + mx_status_t status = _magenta_thread_arch_prctl(handle, ARCH_GET_FS, &value); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__, " failed to get!"); + return value; +} +static void fs_set(mx_handle_t handle, uintptr_t value) { + mx_status_t status = _magenta_thread_arch_prctl(handle, ARCH_SET_FS, &value); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__, " failed to set!"); +} +static uintptr_t gs_get(mx_handle_t handle) { + uintptr_t value; + mx_status_t status = _magenta_thread_arch_prctl(handle, ARCH_GET_GS, &value); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__, " failed to get!"); + return value; +} +static void gs_set(mx_handle_t handle, uintptr_t value) { + mx_status_t status = _magenta_thread_arch_prctl(handle, ARCH_SET_GS, &value); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__, " failed to set!"); +} +static register_ops ops[] = { + { + &fs_get, &fs_set, "fs", + }, + { + &gs_get, &gs_set, "gs", + }, +}; + +static uint8_t vaddr_bits(void) { + uint32_t eax, ebx, ecx, edx; + eax = 0x80000008; + __asm__ __volatile__("cpuid" + : "+a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx)); + return (eax >> 8) & 0xff; +} + +static uintptr_t make_valid_value(uintptr_t value) { + uint8_t vaddr_len = vaddr_bits(); + if (vaddr_len < 32) { + fail(__FUNCTION__, __LINE__, " invalid vaddr len"); + } + value &= (1 << vaddr_len) - 1; + bool sign = !!(value & (1 << (vaddr_len - 1))); + if (sign) { + value |= ~((1 << vaddr_len) - 1); + } + return value; +} +#else +#error Unsupported architecture! +#endif + +typedef struct context { + uintptr_t key; // A different bit per thread so they test different values. + mx_handle_t* thread; +} context; + +static uint64_t values[] = { + 0x0000000000000000ull, 0xffffffffffffffffull, 0x5555555555555555ull, + 0xaaaaaaaaaaaaaaaaull, 0x0123456789abcdefull, 0xfedcba9876543210ull, + 0xababababababababull, 0x912f277f61b583a5ull, 0x3b7c08b96d727cedull, +}; + +static int test_entry_point(void* arg) { + context* c = (context*)arg; + + // Test setting valid values. + for (size_t idx = 0; idx < sizeof(values) / sizeof(*values); ++idx) { + uintptr_t value = values[idx] ^ c->key; + for (uintptr_t iteration = 0; iteration < 0x10ull; ++iteration) { + value ^= (iteration << 12); + for (size_t op_idx = 0; op_idx < sizeof(ops) / sizeof(*ops); ++op_idx) { + register_ops* o = ops + op_idx; + value ^= ((uintptr_t)op_idx << 24); + uintptr_t real_value = make_valid_value(value); + yield(); + o->set(*c->thread, real_value); + yield(); + uintptr_t new_value = o->get(*c->thread); + if (new_value != real_value) + fail(__FUNCTION__, __LINE__, o->name); + } + } + } + + // Test bad op. + uintptr_t value = (uintptr_t)0xabcdabcdabcdabcdull; + mx_status_t status = _magenta_thread_arch_prctl(*c->thread, 42, &value); + if (status != ERR_INVALID_ARGS) + fail(__FUNCTION__, __LINE__, "failed to reject bad op"); + for (size_t op_idx = 0; op_idx < sizeof(ops) / sizeof(*ops); ++op_idx) { + uintptr_t current_value = ops[op_idx].get(*c->thread); + if (current_value == value) + fail(__FUNCTION__, __LINE__, "modified value in invalid call"); + } + + // TODO(kulakowski) Re-enable this part of the test once we figure + // out the right for this call. + + // Test bad handle. Assumes 0 is a valid prctl op. + // uintptr_t original_value = (uintptrt_t)0x5678567856785678ull; + // value = original_value; + // status = _magenta_thread_arch_prctl(MX_HANDLE_INVALID, 0, &value); + // if (status != ERR_INVALID_ARGS) + // fail(__FUNCTION__, __LINE__, "failed to reject bad handle"); + // if (value != original_value) fail(__FUNCTION__, __LINE__, "modified value in invalid call"); + // for (size_t op_idx = 0; op_idx < sizeof(ops) / sizeof(*ops); ++op_idx) { + // uintptr_t current_value = ops[op_idx].get(*c->thread); + // if (current_value == original_value) + // fail(__FUNCTION__, __LINE__, "modified arch register in invalid call"); + // } + + _magenta_thread_exit(); + return 0; +} + +int main(void) { + printf("Starting arch register test.\n"); + +#define num_threads 64 + + mx_handle_t threads[num_threads] = {0}; + context contexts[num_threads] = {0}; + + for (uintptr_t idx = 0; idx < num_threads; ++idx) { + const char* thread_name = "arch register"; + + contexts[idx] = (context){(1ull << idx), threads + idx}; + threads[idx] = _magenta_thread_create(test_entry_point, contexts + idx, thread_name, strlen(thread_name)); + if (threads[idx] < 0) + fail(__FUNCTION__, __LINE__, "failed to create thread"); + } + + for (uintptr_t idx = 0; idx < num_threads; ++idx) { + mx_status_t result = _magenta_handle_wait_one(threads[idx], MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL); + if (result != NO_ERROR) + fail(__FUNCTION__, __LINE__, "failed to join thread"); + result = _magenta_handle_close(threads[idx]); + if (result != NO_ERROR) + fail(__FUNCTION__, __LINE__, "failed to close thread handle"); + } + + printf("Finishing arch register test.\n"); + return 0; +} diff --git a/system/utest/arch-registers/rules.mk b/system/utest/arch-registers/rules.mk new file mode 100644 index 000000000..d329e0b3e --- /dev/null +++ b/system/utest/arch-registers/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/arch-registers.c + +MODULE_NAME := arch-registers-test + +MODULE_DEPS := \ + ulib/musl ulib/magenta ulib/mxio + +include make/module.mk diff --git a/system/utest/bad-syscall/BUILD.gn b/system/utest/bad-syscall/BUILD.gn new file mode 100644 index 000000000..860ce39d1 --- /dev/null +++ b/system/utest/bad-syscall/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//gnbuild/config.gni") +import("//system/utest/test.gni") + +test("bad-syscall") { + output_name = "bad-syscall-test" + defines = kernel_defines + sources = [ + "bad-syscall.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/bad-syscall/bad-syscall.c b/system/utest/bad-syscall/bad-syscall.c new file mode 100644 index 000000000..fa3cb6ca4 --- /dev/null +++ b/system/utest/bad-syscall/bad-syscall.c @@ -0,0 +1,34 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#define CHECK(f, expected, message) \ + if ((ret = (f)) != (expected)) \ + printf("Test failed (%s): " #f " returned %d vs. %d\n", message, ret, expected) + +int main(void) { + mx_status_t ret; + void* unmapped_addr = (void*)4096; + CHECK(_magenta_debug_write(unmapped_addr, 1), -1, "reading unmapped addr"); + CHECK(_magenta_debug_write((void*)KERNEL_BASE - 1, 5), -1, "read crossing kernel boundary"); + CHECK(_magenta_debug_write((void*)KERNEL_BASE, 1), -1, "read into kernel space"); + CHECK(_magenta_debug_write((void*)&unmapped_addr, sizeof(void*)), (int)sizeof(void*), + "good read"); + printf("Done\n"); + return 0; +} diff --git a/system/utest/bad-syscall/rules.mk b/system/utest/bad-syscall/rules.mk new file mode 100644 index 000000000..3157f09b7 --- /dev/null +++ b/system/utest/bad-syscall/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/bad-syscall.c + +MODULE_NAME := bad-syscall-test + +MODULE_DEPS := \ + ulib/musl ulib/magenta ulib/mxio + +include make/module.mk diff --git a/system/utest/cleanup/BUILD.gn b/system/utest/cleanup/BUILD.gn new file mode 100644 index 000000000..622e415ac --- /dev/null +++ b/system/utest/cleanup/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("cleanup") { + output_name = "cleanup-test" + sources = [ + "cleanup.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/cleanup/cleanup.c b/system/utest/cleanup/cleanup.c new file mode 100644 index 000000000..06d58c28f --- /dev/null +++ b/system/utest/cleanup/cleanup.c @@ -0,0 +1,144 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include + +static const char* msg = "This is a test message, please discard."; + +volatile int test_state = 0; + +int watchdog(void* arg) { + _magenta_nanosleep(100 * 1000 * 1000); + if (test_state < 100) { + printf("cleanup-test: FAILED. Stuck waiting in test%d\n", test_state); + } + _magenta_thread_exit(); + return 0; +} + +int main(int argc, char** argv) { + mx_handle_t p0tx, p0rx, p1tx, p1rx; + mx_signals_t pending; + mx_status_t r; + + _magenta_thread_create(watchdog, NULL, "watchdog", 8); + + // TEST1 + // Create a pipe, close one end, try to wait on the other. + test_state = 1; + if ((p1tx = _magenta_message_pipe_create(&p1rx)) < 0) { + printf("cleanup-test: pipe create 1 failed: %d\n", p1tx); + return -1; + } + _magenta_handle_close(p1rx); + printf("cleanup-test: about to wait, should return immediately with PEER_CLOSED\n"); + r = _magenta_handle_wait_one(p1tx, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL); + if (r) { + printf("cleanup-test: FAILED, error %d\n", r); + return -1; + } + if (pending != MX_SIGNAL_PEER_CLOSED) { + printf("cleanup-test: FAILED, pending=%x, not PEER_CLOSED\n", pending); + return -1; + } + printf("cleanup-test: SUCCESS, observed PEER_CLOSED signal\n\n"); + _magenta_handle_close(p1tx); + _magenta_handle_close(p1rx); + + // TEST2 + // Create a pipe, close one end. Then create an event and write a + // message on the pipe sending the event along. The event normally + // dissapears from this process handle table but since the message_write + // fails (because the other end is closed) The event should still + // be usable from this process. + test_state = 2; + if ((p1tx = _magenta_message_pipe_create(&p1rx)) < 0) { + printf("cleanup-test: pipe create 1 failed: %d\n", p1tx); + return -1; + } + _magenta_handle_close(p1rx); + + mx_handle_t event = _magenta_event_create(0u); + if (event < 0) { + printf("cleanup-test: event create failed: %d\n", p1tx); + return -1; + } + + r = _magenta_message_write(p1tx, &msg, sizeof(msg), &event, 1, 0); + if (r != ERR_BAD_STATE) { + printf("cleanup-test: unexpected message_write return code: %d\n", r); + return -1; + } + + if ((r = _magenta_event_signal(event)) < 0) { + printf("cleanup-test: unable to signal event!\n"); + return -1; + } + + printf("cleanup-test: SUCCESS, event is alive\n\n"); + + _magenta_handle_close(event); + _magenta_handle_close(p1tx); + + // TEST3 + // Simulates the case where we prepare a message pipe with a + // message+pipehandle already in it and the far end closed, + // like we pass to newly created processes, but then (say + // process creation fails), we delete the other end of the + // pipe we were going to send. At this point we expect + // that the pipe handle bundled with the message should + // be closed and waiting on the opposing handle should + // signal PEER_CLOSED. + test_state = 3; + if ((p0tx = _magenta_message_pipe_create(&p0rx)) < 0) { + printf("cleanup-test: pipe create 0 failed: %d\n", p0tx); + return -1; + } + + if ((p1tx = _magenta_message_pipe_create(&p1rx)) < 0) { + printf("cleanup-test: pipe create 1 failed: %d\n", p1tx); + return -1; + } + + if ((r = _magenta_message_write(p0tx, &msg, sizeof(msg), &p1rx, 1, 0)) < 0) { + printf("cleanup-test: pipe write failed: %d\n", r); + return -1; + } + + _magenta_handle_close(p0tx); + _magenta_handle_close(p0rx); + + printf("cleanup-test: about to wait, should return immediately with PEER_CLOSED\n"); + r = _magenta_handle_wait_one(p1tx, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL); + if (r) { + printf("cleanup-test: FAILED, error %d\n", r); + return -1; + } + if (pending != MX_SIGNAL_PEER_CLOSED) { + printf("cleanup-test: FAILED, pending=%x, not PEER_CLOSED\n", pending); + return -1; + } + + test_state = 100; + printf("cleanup-test: PASSED\n"); + _magenta_handle_close(p1tx); + return 0; +} diff --git a/system/utest/cleanup/rules.mk b/system/utest/cleanup/rules.mk new file mode 100644 index 000000000..731df1c71 --- /dev/null +++ b/system/utest/cleanup/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/cleanup.c + +MODULE_NAME := cleanup-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/dump1/BUILD.gn b/system/utest/dump1/BUILD.gn new file mode 100644 index 000000000..6d74225cd --- /dev/null +++ b/system/utest/dump1/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("dump1") { + output_name = "dump1" + sources = [ + "dump1.c", + ] + deps = [ + "//system/ulib/mxio", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/dump1/dump1.c b/system/utest/dump1/dump1.c new file mode 100644 index 000000000..9dd5983e6 --- /dev/null +++ b/system/utest/dump1/dump1.c @@ -0,0 +1,48 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +int main(int argc, char **argv) { + unsigned char x; + int fd = 0; + if (argc == 2) { + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + printf("dump1: cannot open '%s'\n", argv[1]); + return -1; + } + } + for (;;) { + mxio_wait_fd(fd, MXIO_EVT_READABLE, NULL); + int r = read(fd, &x, 1); + if (r == 0) { + continue; + } + if (r != 1) { + break; + } + if (x == 'z') { + break; + } + printf("%02x ", x); + fflush(stdout); + } + printf("\n"); + return 0; +} diff --git a/system/utest/dump1/rules.mk b/system/utest/dump1/rules.mk new file mode 100644 index 000000000..f230961a2 --- /dev/null +++ b/system/utest/dump1/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/dump1.c + +MODULE_NAME := dump1 + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/echo/BUILD.gn b/system/utest/echo/BUILD.gn new file mode 100644 index 000000000..6aae5ad12 --- /dev/null +++ b/system/utest/echo/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("echo") { + output_name = "echo-test" + sources = [ + "echo.c", + "echo.h", + "main.c", + "message.c", + "message.h", + "struct.c", + "struct.h", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/echo/README b/system/utest/echo/README new file mode 100644 index 000000000..34270a2a7 --- /dev/null +++ b/system/utest/echo/README @@ -0,0 +1,15 @@ +This is a simple example of reading/writing mojo messages adhering to the Echo +protocol: https://github.com/domokit/mojo/blob/master/examples/echo/echo.mojom. +The program assumes that it starts up with a handle value to a message pipe and +that something on the other end of that message pipe is sending some number of +Echo calls along the pipe. The program: +*) waits for the message pipe to be readable +*) reads an incoming message +*) validates that it seems sane +*) formats a reply message +*) sends the reply +*) goes back to waiting + +until the message pipe peer is closed or any other error is encountered. The +serialization/deserialization is hand written as we don't have code generation +for mojom set up for C yet. diff --git a/system/utest/echo/echo.c b/system/utest/echo/echo.c new file mode 100644 index 000000000..a6bfabbc7 --- /dev/null +++ b/system/utest/echo/echo.c @@ -0,0 +1,139 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "echo.h" + +#include +#include +#include + +#include + +#include "message.h" +#include "struct.h" + +bool wait_for_readable(mx_handle_t handle) { + printf("waiting for handle %u to be readable (or closed)\n", handle); + // Wait for |handle| to become readable or closed. + mx_signals_t signals = MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED; + mx_signals_t satisfied_signals; + mx_status_t wait_status = _magenta_handle_wait_one(handle, signals, MX_TIME_INFINITE, + &satisfied_signals, NULL); + if (wait_status != NO_ERROR) { + return false; + } + if (!(satisfied_signals & MX_SIGNAL_READABLE)) { + return false; + } + return true; +} + +bool serve_echo_request(mx_handle_t handle) { + if (!wait_for_readable(handle)) { + printf("handle not readable\n"); + return false; + } + + // Try to read a message from |in_handle|. + // First, figure out size. + uint32_t in_msg_size = 0u; + mx_status_t read_status = _magenta_message_read(handle, NULL, &in_msg_size, NULL, NULL, 0u); + if (read_status != ERR_NO_MEMORY) { + printf("unexpected sizing read status: %u\n", read_status); + return false; + } + printf("reading message of size %u\n", in_msg_size); + void* in_msg_buf = calloc(in_msg_size, 1u); + read_status = _magenta_message_read(handle, in_msg_buf, &in_msg_size, NULL, NULL, 0u); + if (read_status != NO_ERROR) { + printf("read failed with status %u\n", read_status); + return false; + } + // Try to parse message data. + if (!mojo_validate_struct_header(in_msg_buf, in_msg_size)) { + printf("validation failed on read message\n"); + return false; + } + + mojo_struct_header_t* in_struct_header = (mojo_struct_header_t*)in_msg_buf; + if (in_struct_header->version != 1u) { + return false; + } + + mojo_message_header_with_request_id_t* in_msg_header = + (mojo_message_header_with_request_id_t*)in_struct_header; + + if (in_msg_header->message_header.name != 0u) { + return false; + } + + if (in_msg_header->message_header.flags != MOJO_MESSAGE_HEADER_FLAGS_EXPECTS_RESPONSE) { + return false; + } + + uint64_t request_id = in_msg_header->request_id; + + void* in_payload = in_msg_header + 1u; + + uint32_t in_string_header_num_bytes = *(uint32_t*)in_payload; + uint32_t in_string_header_num_elems = *((uint32_t*)in_payload + 1u); + void* in_string_data = ((uint32_t*)in_payload) + 2u; + printf("got string: "); + for (uint32_t i = 0u; i < in_string_header_num_elems; ++i) { + printf("%c", ((char*)in_string_data)[i]); + } + printf("\n"); + + // TODO: Validate array header + + // Incoming message seems fine, form an outgoing message and send it. + + void* out_msg_buf = malloc(in_msg_size); + uint32_t out_msg_size = in_msg_size; + + // Write header + mojo_message_header_with_request_id_t* out_msg_header = + (mojo_message_header_with_request_id_t*)out_msg_buf; + + // Struct header + out_msg_header->message_header.struct_header.num_bytes = + sizeof(mojo_message_header_with_request_id_t); + out_msg_header->message_header.struct_header.version = 1u; + + // Message header + out_msg_header->message_header.name = 0u; + out_msg_header->message_header.flags = MOJO_MESSAGE_HEADER_FLAGS_IS_RESPONSE; + out_msg_header->request_id = request_id; + + uint32_t* out_string_header = (uint32_t*)out_msg_header + 1u; + *out_string_header = in_string_header_num_bytes; + *(out_string_header + 1u) = in_string_header_num_elems; + + if (in_string_header_num_bytes != 0u) { + char* out_string_dest = (char*)(out_string_header + 2u); + memcpy(out_string_dest, (char*)(in_string_data), in_string_header_num_bytes); + } + free(in_msg_buf); + + mx_status_t write_status = + _magenta_message_write(handle, out_msg_buf, out_msg_size, NULL, 0u, 0u); + free(out_msg_buf); + + if (write_status != NO_ERROR) { + return false; + } + + printf("served request!\n\n\n"); + return true; +} diff --git a/system/utest/echo/echo.h b/system/utest/echo/echo.h new file mode 100644 index 000000000..88b05f27e --- /dev/null +++ b/system/utest/echo/echo.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +// Waits for an incoming echo request on message pipe |handle|, +// parses the message, sends a reply on |handle|. Returns false if either +// message pipe handle is closed or any error occurs. Returns true if a reply is +// successfully sent. +bool serve_echo_request(mx_handle_t handle); diff --git a/system/utest/echo/main.c b/system/utest/echo/main.c new file mode 100644 index 000000000..e382cd68f --- /dev/null +++ b/system/utest/echo/main.c @@ -0,0 +1,58 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#include "echo.h" + +int main(void) { + mx_handle_t handles[2] = {0}; + handles[0] = _magenta_message_pipe_create(&handles[1]); + if (handles[0] < 0) { + printf("could not create message pipe: %u\n", handles[0]); + return 1; + } + printf("created message pipe with handle values %u and %u\n", handles[0], handles[1]); + for (int i = 0; i < 3; i++) { + printf("loop %d\n", i); + static const uint32_t buf[9] = { + 24, // struct header, num_bytes + 1, // struct header: version + 0, // struct header: flags + 1, // message header: name + 0, 0, // message header: request id (8 bytes) + 4, // array header: num bytes + 4, // array header: num elems + 0x42424143, // array contents: 'CABB' + }; + mx_handle_t status = _magenta_message_write(handles[1], (void*)buf, sizeof(buf), NULL, 0u, 0u); + if (status != NO_ERROR) { + printf("could not write echo request: %u\n", status); + return 1; + } + + if (!serve_echo_request(handles[0])) { + printf("serve_echo_request failed\n"); + break; + } + } + printf("closing handle %u\n", handles[1]); + _magenta_handle_close(handles[1]); + serve_echo_request(handles[0]); + _magenta_handle_close(handles[0]); + return 0; +} diff --git a/system/utest/echo/message.c b/system/utest/echo/message.c new file mode 100644 index 000000000..c5e2f223d --- /dev/null +++ b/system/utest/echo/message.c @@ -0,0 +1,57 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "message.h" + +#include + +_Static_assert(sizeof(mojo_message_header_t) == 16u, "mojo_message_header_t should be 16 bytes"); + +_Static_assert(sizeof(mojo_message_header_with_request_id_t) == 24u, + "mojo_message_header_t should be 24 bytes"); + +bool mojo_validate_message_header(const mojo_struct_header_t* header, size_t size) { + if (header->num_bytes < sizeof(mojo_message_header_t) || size < sizeof(mojo_message_header_t) || + size > UINT32_MAX) { + return false; + } + + const mojo_message_header_t* message_header = (const mojo_message_header_t*)header; + + // Message expects response and message is response flags are mutually + // exclusive. + if ((message_header->flags & MOJO_MESSAGE_HEADER_FLAGS_EXPECTS_RESPONSE) && + (message_header->flags & MOJO_MESSAGE_HEADER_FLAGS_IS_RESPONSE)) { + return false; + } + + if (header->version == 0u) { + if (header->num_bytes != sizeof(mojo_message_header_t)) { + return false; + } + + // Version 0 has no request id and should not have either of these flags. + if ((message_header->flags & MOJO_MESSAGE_HEADER_FLAGS_EXPECTS_RESPONSE) || + (message_header->flags & MOJO_MESSAGE_HEADER_FLAGS_IS_RESPONSE)) { + return false; + } + } else if (header->version == 1u) { + if (header->num_bytes != sizeof(mojo_message_header_with_request_id_t)) { + return false; + } + } + // Accept unknown versions of the message header to be future-proof. + + return true; +} diff --git a/system/utest/echo/message.h b/system/utest/echo/message.h new file mode 100644 index 000000000..8a75f3978 --- /dev/null +++ b/system/utest/echo/message.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MOJO_PUBLIC_C_BINDINGS_MESSAGE_H_ +#define MOJO_PUBLIC_C_BINDINGS_MESSAGE_H_ + +#include +#include +#include + +#include "struct.h" + +// These bits may be set in the |flags| field of a Mojo message header. +#define MOJO_MESSAGE_HEADER_FLAGS_EXPECTS_RESPONSE (1 << 0u) +#define MOJO_MESSAGE_HEADER_FLAGS_IS_RESPONSE (1 << 1u) + +#ifdef __cplusplus +extern "C" { +#endif + +// Validates that the buffer started at a (validated) mojo_struct_header with a +// given size contains a valid mojo message header. +bool mojo_validate_message_header(const mojo_struct_header_t* header, size_t size); + +typedef struct mojo_message_header { + mojo_struct_header_t struct_header; + uint32_t name; + uint32_t flags; +} mojo_message_header_t; + +typedef struct mojo_message_header_with_request_id { + mojo_message_header_t message_header; + uint64_t request_id; +} mojo_message_header_with_request_id_t; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_BINDINGS_MESSAGE_H_ diff --git a/system/utest/echo/rules.mk b/system/utest/echo/rules.mk new file mode 100644 index 000000000..c6524db25 --- /dev/null +++ b/system/utest/echo/rules.mk @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/echo.c \ + $(LOCAL_DIR)/main.c \ + $(LOCAL_DIR)/message.c \ + $(LOCAL_DIR)/struct.c + +MODULE_NAME := echo-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/echo/struct.c b/system/utest/echo/struct.c new file mode 100644 index 000000000..44f774553 --- /dev/null +++ b/system/utest/echo/struct.c @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "struct.h" + +#include + +_Static_assert(sizeof(mojo_struct_header_t) == 8u, "mojo_struct_header_t should be 8 bytes"); + +bool mojo_validate_struct_header(const void* data, size_t size) { + if (size < sizeof(mojo_struct_header_t) || size > UINT32_MAX) { + return false; + } + + const mojo_struct_header_t* header = (const mojo_struct_header_t*)data; + + if (header->num_bytes < sizeof(mojo_struct_header_t) || header->num_bytes > size) { + return false; + } + + return true; +} diff --git a/system/utest/echo/struct.h b/system/utest/echo/struct.h new file mode 100644 index 000000000..ee15abb13 --- /dev/null +++ b/system/utest/echo/struct.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MOJO_PUBLIC_C_BINDINGS_STRUCT_H_ +#define MOJO_PUBLIC_C_BINDINGS_STRUCT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Validates that a given buffer has a mojo struct header and that the size of +// the struct in the header matches the size of the buffer. +bool mojo_validate_struct_header(const void* data, size_t size); + +typedef struct struct_header { + uint32_t num_bytes; + uint32_t version; +} mojo_struct_header_t; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_BINDINGS_STRUCT_H_ diff --git a/system/utest/errno/BUILD.gn b/system/utest/errno/BUILD.gn new file mode 100644 index 000000000..aef722cb2 --- /dev/null +++ b/system/utest/errno/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("errno") { + output_name = "errno-test" + sources = [ + "errno.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/errno/errno.c b/system/utest/errno/errno.c new file mode 100644 index 000000000..acee4e6d3 --- /dev/null +++ b/system/utest/errno/errno.c @@ -0,0 +1,51 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +static void* do_test(void* arg) { + int thread_no = *(int*)arg; + printf("do_test for thread: %d\n", thread_no); + errno = -thread_no; + _magenta_nanosleep(300 * 1000 * 1000); + printf("comparing result for: %d\n", thread_no); + assert(errno == -thread_no); + return NULL; +} + +int main(void) { + int main_thread = 1, thread_1 = 2, thread_2 = 3; + + pthread_t thread2, thread3; + + printf("creating thread: %d\n", thread_1); + pthread_create(&thread2, NULL, do_test, &thread_1); + + printf("creating thread: %d\n", thread_2); + pthread_create(&thread3, NULL, do_test, &thread_2); + + do_test(&main_thread); + + printf("joining thread: %d\n", thread_1); + pthread_join(thread2, NULL); + + printf("joining thread: %d\n", thread_2); + pthread_join(thread3, NULL); + + return 0; +} diff --git a/system/utest/errno/rules.mk b/system/utest/errno/rules.mk new file mode 100644 index 000000000..35d204913 --- /dev/null +++ b/system/utest/errno/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/errno.c \ + +MODULE_NAME := errno-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/events/BUILD.gn b/system/utest/events/BUILD.gn new file mode 100644 index 000000000..6f0fab27e --- /dev/null +++ b/system/utest/events/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("events") { + output_name = "events-test" + sources = [ + "events.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/events/events.c b/system/utest/events/events.c new file mode 100644 index 000000000..c1c46b157 --- /dev/null +++ b/system/utest/events/events.c @@ -0,0 +1,282 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include + +#define CHECK_MX_STATUS(call) do { \ + mx_status_t status = (call); \ + if (status < 0) { \ + printf("%s:%d: %s failed: %d\n", __FILE__, __LINE__, #call, status); \ + return __LINE__; \ + } \ +} while (0) + +#define FAIL_TEST do { \ + printf("%s:%d: failed", __FILE__, __LINE__); \ + return __LINE__; \ +} while (0) + +static bool wait(mx_handle_t event, mx_handle_t quit_event) +{ + mx_status_t ms; + mx_signals_t signals[2] = {MX_SIGNAL_SIGNALED, MX_SIGNAL_SIGNALED}; + mx_signals_t satisfied[2] = {}; + mx_signals_t satisfiable[2] = {}; + mx_handle_t wev[2] = {event, quit_event}; + + ms = _magenta_handle_wait_many(2U, wev, signals, MX_TIME_INFINITE, satisfied, satisfiable); + if (ms < 0) + return false; + + return (satisfied[1] == MX_SIGNAL_SIGNALED); +} + +static bool wait_user(mx_handle_t event, mx_handle_t quit_event, mx_signals_t user_signal) +{ + mx_status_t ms; + mx_signals_t signals[2] = {user_signal, MX_SIGNAL_SIGNALED}; + mx_signals_t satisfied[2] = {}; + mx_signals_t satisfiable[2] = {}; + mx_handle_t wev[2] = {event, quit_event}; + + ms = _magenta_handle_wait_many(2U, wev, signals, MX_TIME_INFINITE, satisfied, satisfiable); + if (ms < 0) + return false; + + return (satisfied[1] == MX_SIGNAL_SIGNALED); +} + + +static int thread_fn_1(void* arg) +{ + mx_handle_t* events = (mx_handle_t*)(arg); + + do { + _magenta_nanosleep(200 * 1000 * 1000); + _magenta_event_signal(events[1]); + } while (!wait(events[2], events[0])); + + _magenta_thread_exit(); + return 0; +} + +static int thread_fn_2(void* arg) +{ + mx_handle_t* events = (mx_handle_t*)(arg); + + while (!wait(events[1], events[0])) { + _magenta_nanosleep(100 * 1000 * 1000); + _magenta_event_signal(events[2]); + } + + _magenta_thread_exit(); + return 0; +} + +static int basic_test(void) +{ + printf("basic event test\n"); + + mx_handle_t events[3]; + CHECK_MX_STATUS(events[0] = _magenta_event_create(0U)); + CHECK_MX_STATUS(events[1] = _magenta_event_create(1U)); + CHECK_MX_STATUS(events[2] = _magenta_event_create(2U)); + + mx_handle_t threads[4]; + CHECK_MX_STATUS(threads[3] = _magenta_thread_create(thread_fn_1, events, "master", 7)); + + for (int ix = 0; ix != 3; ++ix) { + CHECK_MX_STATUS(threads[ix] = _magenta_thread_create(thread_fn_2, events, "workers", 8)); + } + + _magenta_nanosleep(400 * 1000 * 1000); + _magenta_event_signal(events[0]); + + for (int ix = 0; ix != 4; ++ix) { + CHECK_MX_STATUS(_magenta_handle_wait_one(threads[ix], MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL)); + CHECK_MX_STATUS(_magenta_handle_close(threads[ix])); + } + + CHECK_MX_STATUS(_magenta_handle_close(events[0])); + CHECK_MX_STATUS(_magenta_handle_close(events[1])); + CHECK_MX_STATUS(_magenta_handle_close(events[2])); + return 0; +} + +static int thread_fn_3(void* arg) +{ + mx_handle_t* events = (mx_handle_t*)(arg); + + do { + _magenta_nanosleep(200 * 1000 * 1000); + _magenta_object_signal(events[1], MX_SIGNAL_USER1, MX_SIGNAL_USER_ALL); + } while (!wait_user(events[2], events[0], MX_SIGNAL_USER2)); + + _magenta_thread_exit(); + return 0; +} + +static int thread_fn_4(void* arg) +{ + mx_handle_t* events = (mx_handle_t*)(arg); + + while (!wait_user(events[1], events[0], MX_SIGNAL_USER1)) { + _magenta_nanosleep(100 * 1000 * 1000); + _magenta_object_signal(events[2], MX_SIGNAL_USER2, MX_SIGNAL_USER_ALL); + } + + _magenta_thread_exit(); + return 0; +} + +static int user_signals_test(void) +{ + printf("user signals event test\n"); + + mx_handle_t events[3]; + CHECK_MX_STATUS(events[0] = _magenta_event_create(0U)); + CHECK_MX_STATUS(events[1] = _magenta_event_create(1U)); + CHECK_MX_STATUS(events[2] = _magenta_event_create(2U)); + + mx_handle_t threads[4]; + CHECK_MX_STATUS(threads[3] = _magenta_thread_create(thread_fn_3, events, "master", 7)); + + for (int ix = 0; ix != 3; ++ix) { + CHECK_MX_STATUS(threads[ix] = _magenta_thread_create(thread_fn_4, events, "workers", 8)); + } + + _magenta_nanosleep(400 * 1000 * 1000); + _magenta_event_signal(events[0]); + + for (int ix = 0; ix != 4; ++ix) { + CHECK_MX_STATUS(_magenta_handle_wait_one(threads[ix], MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL)); + CHECK_MX_STATUS(_magenta_handle_close(threads[ix])); + } + + CHECK_MX_STATUS(_magenta_handle_close(events[0])); + CHECK_MX_STATUS(_magenta_handle_close(events[1])); + CHECK_MX_STATUS(_magenta_handle_close(events[2])); + return 0; +} + +static int thread_fn_closer(void* arg) { + _magenta_nanosleep(1000000); + + mx_handle_t handle = *((mx_handle_t*)arg); + int rc = (int) _magenta_handle_close(handle); + + _magenta_thread_exit(); + return rc; +} + +static int wait_signals_test(void) +{ + printf("wait signals event test\n"); + + mx_handle_t events[3]; + CHECK_MX_STATUS(events[0] = _magenta_event_create(0U)); + CHECK_MX_STATUS(events[1] = _magenta_event_create(1U)); + CHECK_MX_STATUS(events[2] = _magenta_event_create(2U)); + + mx_status_t status; + mx_signals_t satisfied[3] = {0}; + + const mx_signals_t signals[3] = { + MX_SIGNAL_SIGNALED, MX_SIGNAL_SIGNALED, MX_SIGNAL_SIGNALED + }; + + status = _magenta_handle_wait_one(events[0], signals[0], 1u, &satisfied[0], NULL); + if (status != ERR_TIMED_OUT) + FAIL_TEST; + if (satisfied[0]) + FAIL_TEST; + + status = _magenta_handle_wait_many(3u, events, signals, 1u, satisfied, NULL); + if (status != ERR_TIMED_OUT) + FAIL_TEST; + if (satisfied[0] || satisfied[1] || satisfied[2]) + FAIL_TEST; + + status = _magenta_handle_wait_one(events[0], signals[0], 0u, &satisfied[0], NULL); + if (status != ERR_TIMED_OUT) + FAIL_TEST; + if (satisfied[0]) + FAIL_TEST; + + status = _magenta_handle_wait_many(3u, events, signals, 0u, satisfied, NULL); + if (status != ERR_TIMED_OUT) + return 1; + if (satisfied[1] || satisfied[1]) + FAIL_TEST; + + CHECK_MX_STATUS(_magenta_event_signal(events[0])); + + status = _magenta_handle_wait_one(events[0], signals[0], 1u, &satisfied[0], NULL); + if (status) + FAIL_TEST; + if (satisfied[0] != MX_SIGNAL_SIGNALED) + FAIL_TEST; + + status = _magenta_handle_wait_many(3u, events, signals, 1u, satisfied, NULL); + if (status) + FAIL_TEST; + if (satisfied[0] != MX_SIGNAL_SIGNALED) + FAIL_TEST; + + status = _magenta_handle_wait_one(events[0], signals[0], 0u, &satisfied[0], NULL); + if (status) + FAIL_TEST; + if (satisfied[0] != MX_SIGNAL_SIGNALED) + FAIL_TEST; + + mx_handle_t thread; + CHECK_MX_STATUS(thread= _magenta_thread_create(thread_fn_closer, &events[1], "closer", 7)); + + status = _magenta_handle_wait_one(events[1], signals[1], MX_TIME_INFINITE, NULL, NULL); + if (status != ERR_CANCELLED) + FAIL_TEST; + + CHECK_MX_STATUS(_magenta_handle_wait_one( + thread, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL)); + + CHECK_MX_STATUS(_magenta_handle_close(thread)); + + CHECK_MX_STATUS(_magenta_handle_close(events[0])); + CHECK_MX_STATUS(_magenta_handle_close(events[2])); + + return 0; +} + +#define EXIT_TEST(n, r) if ((r)) { printf("event test %d: error %d\n", (n), (r)); return r; } + +int main(void) +{ + int res; + res = basic_test(); + EXIT_TEST(1, res); + res = user_signals_test(); + EXIT_TEST(2, res); + res = wait_signals_test(); + EXIT_TEST(3, res); + + printf("event test done\n"); + return 0; +} diff --git a/system/utest/events/rules.mk b/system/utest/events/rules.mk new file mode 100644 index 000000000..26f839665 --- /dev/null +++ b/system/utest/events/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/events.c + +MODULE_NAME := events-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/evil/BUILD.gn b/system/utest/evil/BUILD.gn new file mode 100644 index 000000000..4d849a922 --- /dev/null +++ b/system/utest/evil/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("evil") { + output_name = "evil-test" + sources = [ + "evil.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/evil/evil.c b/system/utest/evil/evil.c new file mode 100644 index 000000000..d281676c6 --- /dev/null +++ b/system/utest/evil/evil.c @@ -0,0 +1,234 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include + +#include +#include + +#define TICKS 0 + +#define USE_PTHREAD_MUTEXES 0 +#define USE_SPINLOCKS 0 +#define USE_FUTEXES 1 + +static volatile int xlock = 0; + +static void _lock(volatile int* lock) { + while (__atomic_exchange_n(lock, 1, __ATOMIC_ACQUIRE) != 0) ; +} +static void _unlock(volatile int* lock) { + __atomic_store_n(lock, 0, __ATOMIC_RELEASE); +} + +static void _ftxlock(volatile int* lock) { + while (__atomic_exchange_n(lock, 1, __ATOMIC_ACQUIRE) != 0) { + _magenta_futex_wait((int*) lock, 1, MX_TIME_INFINITE); + } +} +static void _ftxunlock(volatile int* lock) { + __atomic_store_n(lock, 0, __ATOMIC_RELEASE); + _magenta_futex_wake((int*) lock, 1); +} + +#if USE_PTHREAD_MUTEXES +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +#define LOCK() do { if (info->lock) pthread_mutex_lock(&lock); } while (0) +#define UNLOCK() do { if (info->lock) pthread_mutex_unlock(&lock); } while (0) +#endif + +#if USE_SPINLOCKS +#define LOCK() do { if (info->lock) _lock(&xlock); } while (0) +#define UNLOCK() do { if (info->lock) _unlock(&xlock); } while (0) +#endif + +#if USE_FUTEXES +#define LOCK() do { if (info->lock) _ftxlock(&xlock); } while (0) +#define UNLOCK() do { if (info->lock) _ftxunlock(&xlock); } while (0) +#endif + +#define THREADS 8 +#define BUCKETS 16 + +typedef struct info { + pthread_t t; + int n; + int lock; + int size[BUCKETS]; + void *bucket[BUCKETS]; +} info_t; + +// TODO(kulakowski) Re-add random() +long random(void) { + return 1461956749; +} + +int rnum(int m) { + return (random() & 0x7FFFFFFFU) % m; +} + +void* blaster(void* arg) { + info_t* info = arg; +#if TICKS + int tick = rnum(5000); +#endif + + for (;;) { +#if TICKS + tick++; + if (tick == 10000) { + printf("(%d)\n", info->n); + tick = rnum(5000); + } +#endif + int n = rnum(BUCKETS); + if (info->bucket[n] == NULL) { +allocnew: + info->size[n] = 7 + rnum(1024); + LOCK(); + info->bucket[n] = malloc(info->size[n]); + UNLOCK(); + if (info->bucket[n] == NULL) { + printf("blaster %d malloc failed %d\n", info->n, n); + *((unsigned*)0) = 1; + } + memset(info->bucket[n], info->n * n, info->size[n]); + } else { + int sz = info->size[n]; + uint8_t* x = info->bucket[n]; + int val = n * info->n; + for (int i = 0; i < sz; i++) { + if (x[i] != val) { + printf("blaster %d bad bucket %d\n", info->n, n); + *((unsigned*)0) = 1; + } + } + if (rnum(1000) < 750) { + LOCK(); + free(info->bucket[n]); + UNLOCK(); + goto allocnew; + } else { + memset(x, val, sz); + } + } + } + + return NULL; +} + +int heapblaster(int count, int locking) { + info_t info[THREADS]; + memset(info, 0, sizeof(info)); + if (count < 1) count = 1; + if (count >= THREADS) count = THREADS; + printf("heapblaster: starting %d threads... (%s)\n", + count, locking ? "locking" : "not locking"); + for (int n = 0; n < count; n++) { + info[n].lock = locking; + info[n].n = n; + if (count == 1) { + blaster(info + n); + return 0; + } else { + pthread_create(&info[n].t, NULL, blaster, info + n); + } + } + for (;;) sleep(1000); + return 0; +} + +static uint8_t data[65534]; + +int writespam(int opt) { + mx_handle_t p0tx, p0rx; + mx_status_t r; + uint64_t count = 0; + + if ((p0tx = _magenta_message_pipe_create(&p0rx)) < 0) { + printf("cleanup-test: pipe create 0 failed: %d\n", p0tx); + return -1; + } + + printf("evil-tests: about to spam data into a pipe\n"); + for (;;) { + count++; + if ((r = _magenta_message_write(p0tx, data, sizeof(data), NULL, 0, 0)) < 0) { + printf("evil-tests: SUCCESS, writespammer error %d after only %llu writes\n", r, count); + return 0; + } + if ((count % 1000) == 0) { + printf("evil-tests: wrote %llu messages (%llu bytes).\n", count, count * sizeof(data)); + } + } + if (opt == 0) { + printf("evil-tests: closing the pipe (full of messages)\n"); + _magenta_handle_close(p0tx); + _magenta_handle_close(p0rx); + } else { + printf("evil-tests: leaving the pipe open (full of messages)\n"); + } + return 0; +} + +int handlespam(void) { + mx_handle_t p0tx, p0rx; + uint64_t count = 0; + + printf("evil-tests: about to create all the handles\n"); + for (;;) { + if ((p0tx = _magenta_message_pipe_create(&p0rx)) < 0) { + printf("evil-tests: SUCCESS, pipe create failed %d after %llu created\n", p0tx, count); + return 0; + } + count++; + if ((count % 1000) == 0) { + printf("evil-tests: created %llu message pipes\n", count); + } + } + return 0; +} + +int main(int argc, char** argv) { + if (argc < 2) { + printf("usage: evil-tests spam1 spam writes into pipe\n" + " evil-tests spam2 spam writes, don't close pipe after\n" + " evil-tests spam3 spam handle creation\n" + " evil-tests heap1 heap stress test, locking\n" + " evil-tests heap2 heap stress test, no locking\n" + ); + return -1; + } else if (!strcmp(argv[1], "spam1")) { + return writespam(0); + } else if (!strcmp(argv[1], "spam2")) { + return writespam(1); + } else if (!strcmp(argv[1], "spam3")) { + return handlespam(); + } else if (!strcmp(argv[1], "heap1")) { + int n = (argc > 2) ? strtoul(argv[2], 0, 10) : THREADS; + return heapblaster(n, 1); + } else if (!strcmp(argv[1], "heap2")) { + int n = (argc > 2) ? strtoul(argv[2], 0, 10) : THREADS; + return heapblaster(n, 0); + } else { + printf("unknown sub-command '%s'\n", argv[1]); + return -1; + } + return 0; +} diff --git a/system/utest/evil/rules.mk b/system/utest/evil/rules.mk new file mode 100644 index 000000000..24d9e1fcb --- /dev/null +++ b/system/utest/evil/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/evil.c + +MODULE_NAME := evil-tests + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/exceptions/BUILD.gn b/system/utest/exceptions/BUILD.gn new file mode 100644 index 000000000..53e5e1b01 --- /dev/null +++ b/system/utest/exceptions/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("exceptions") { + output_name = "exceptions-test" + sources = [ + "exceptions.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/exceptions/exceptions.c b/system/utest/exceptions/exceptions.c new file mode 100644 index 000000000..fb090cd27 --- /dev/null +++ b/system/utest/exceptions/exceptions.c @@ -0,0 +1,365 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#define WATCHDOG_DURATION_SECONDS 2 +#define WATCHDOG_DURATION_NANOSECONDS ((int64_t) WATCHDOG_DURATION_SECONDS * 1000 * 1000 * 1000) + +enum handler_kind +{ + HANDLER_THREAD, + HANDLER_PROCESS, + HANDLER_SYSTEM +}; + +struct handlers +{ + mx_handle_t system; + mx_handle_t process; + mx_handle_t thread; +}; + +enum message +{ + MSG_DONE, + MSG_CRASH, + MSG_PING, + MSG_PONG +}; + +// Test only enabled on supported architectures. +static int for_real = 0; + +// Set to zero to disable for debugging purposes. +// TODO(dje): Disabled until debugger API added (we need ability to +// write thread registers). +#define ENABLE_FOR_REAL 0 + +// Set to non-zero when done, disables watchdog. +static int done_tests = 0; + +static void syscall_fail(const char *name, mx_status_t status) +{ + printf("syscall %s failed, rc %d\n", name, status); + exit(1); +} + +static mx_status_t my_create_message_pipe(mx_handle_t* handle0, mx_handle_t* handle1) +{ + mx_handle_t status = _magenta_message_pipe_create(handle1); + if (status < 0) return status; + *handle0 = status; + return NO_ERROR; +} + +typedef int (*thread_start_func)(void*); + +static mx_status_t my_thread_create(thread_start_func entry, void* arg, + mx_handle_t* out_handle, const char* name) +{ + if (!name) name = ""; + mx_handle_t status = _magenta_thread_create(entry, arg, name, strlen(name) + 1); + if (status < 0) return status; + *out_handle = status; + return NO_ERROR; +} + +static mx_status_t my_wait(const mx_handle_t* handles, const mx_signals_t* signals, + uint32_t num_handles, uint32_t* result_index, + mx_time_t deadline, //xyzdje, unused in _magenta_wait + mx_signals_t* satisfied_signals, + mx_signals_t* satisfiable_signals) +{ + mx_status_t result; + + if (num_handles == 1u) { + result = + _magenta_handle_wait_one(*handles, *signals, MX_TIME_INFINITE, + satisfied_signals, satisfiable_signals); + } else { + result = _magenta_handle_wait_many(num_handles, handles, signals, MX_TIME_INFINITE, + satisfied_signals, satisfiable_signals); + } + + // xyzdje, from _magenta_wait: TODO(cpu): implement |result_index|, see MG-33 bug. + return result; +} + +static mx_status_t my_write_message(mx_handle_t handle, const void* bytes, uint32_t num_bytes, + const mx_handle_t* handles, uint32_t num_handles, + uint32_t flags) +{ + return _magenta_message_write(handle, bytes, num_bytes, handles, num_handles, flags); +} + +static mx_status_t my_read_message(mx_handle_t handle, void* bytes, uint32_t* num_bytes, + mx_handle_t* handles, uint32_t* num_handles, uint32_t flags) +{ + return _magenta_message_read(handle, bytes, num_bytes, handles, num_handles, flags); +} + +// Architecture specific ways to crash and then recover from the crash. + +static void crash_me(void) +{ + printf("Attempting to crash thread.\n"); +#ifdef __x86_64__ + __asm__ volatile ("int3"); +#endif + printf("Thread resuming after crash.\n"); +} + +static void uncrash_me(mx_handle_t thread) +{ + printf("Attempting to recover from crash.\n"); +#ifdef __x86_64__ + // TODO(dje): Advance pc by one. +#endif +} + +// Wait until |handle| is readable or peer is closed. +// Result is true if readable, otherwise false. + +static bool wait_handle(mx_handle_t handle) +{ + mx_signals_t satisfied_signals, satisfiable_signals; + mx_signals_t signals = MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED; + mx_status_t result = my_wait(&handle, &signals, 1, NULL, WATCHDOG_DURATION_NANOSECONDS, + &satisfied_signals, &satisfiable_signals); + if (result != NO_ERROR) + syscall_fail("my_wait returned %d\n", result); + if ((satisfied_signals & MX_SIGNAL_READABLE) == 0) { + printf("my_wait: peer closed\n"); + return false; + } + return true; +} + +static void send_msg(mx_handle_t handle, enum message msg) +{ + uint64_t data = msg; + printf("sending message %d on handle %u\n", msg, handle); + mx_status_t status = my_write_message(handle, &data, sizeof(data), NULL, 0, 0); + if (status != NO_ERROR) + syscall_fail("my_write_message", status); +} + +static enum message recv_msg(mx_handle_t handle) +{ + uint64_t data; + uint32_t num_bytes = sizeof(data); + + printf("waiting for message on handle %u\n", handle); + + if (!wait_handle(handle)) + { + printf("peer closed while trying to read message\n"); + exit (1); + } + mx_status_t status = my_read_message(handle, &data, &num_bytes, NULL, 0, 0); + if (status != NO_ERROR) + syscall_fail("my_read_message", status); + if (num_bytes != sizeof(data)) + { + printf("unexpected message size: %u\n", num_bytes); + exit(1); + } + printf("received message %d\n", (enum message) data); + return (enum message) data; +} + +static void resume_thread_from_exception(mx_handle_t thread, mx_handle_t msg_pipe) +{ + if (for_real) + { + uncrash_me(thread); + _magenta_mark_exception_handled(thread, MX_EXCEPTION_STATUS_RESUME); + } + send_msg(msg_pipe, MSG_PING); + enum message msg = recv_msg(msg_pipe); + if (msg != MSG_PONG) + { + printf("unexpected reply from thread: %d\n", msg); + exit(1); + } + printf("thread has resumed\n"); +} + +static void test_received_exception(struct handlers* handlers, + enum handler_kind kind) +{ + mx_handle_t handle; + const char* kind_name; + + if (!for_real) + return; + + switch (kind) + { + case HANDLER_THREAD: + handle = handlers->thread; + kind_name = "thread"; + break; + case HANDLER_PROCESS: + handle = handlers->process; + kind_name = "process"; + break; + case HANDLER_SYSTEM: + handle = handlers->system; + kind_name = "system"; + break; + default: + abort(); + } + + if (!wait_handle(handle)) + { + printf("exception handler sender closed\n"); + exit (1); + } + + mx_exception_report_t report; + uint32_t num_bytes = sizeof(report); + mx_status_t status = my_read_message(handle, &report, &num_bytes, NULL, 0, 0); + if (status != NO_ERROR) + syscall_fail("my_read_message of exception report", status); + if (num_bytes != sizeof(report)) + { + printf("unexpected message size: %u\n", num_bytes); + exit(1); + } + + printf("exception received from %s handler: pid %u, tid %u\n", + kind_name, report.pid, report.tid); +} + +static void mark_tests_done(mx_handle_t msg_pipe) +{ + send_msg(msg_pipe, MSG_DONE); +} + +static int thread_func(void* arg) +{ + mx_handle_t msg_pipe = (mx_handle_t) (uintptr_t) arg; + + done_tests = 0; + while (!done_tests) + { + enum message msg = recv_msg(msg_pipe); + switch (msg) + { + case MSG_DONE: + done_tests = 1; + break; + case MSG_CRASH: + if (for_real) + crash_me(); + break; + case MSG_PING: + send_msg(msg_pipe, MSG_PONG); + break; + default: + printf("\nunknown message received: %d\n", msg); + break; + } + } + _magenta_thread_exit(); + return 0; // sigh +} + +static int watchdog_thread_func(void* arg) +{ + for (int i = 0; i < WATCHDOG_DURATION_SECONDS; ++i) + { + _magenta_nanosleep(1000 * 1000 * 1000); + if (done_tests) + _magenta_thread_exit(); + } + // This should kill the entire process, not just this thread. + exit (1); +} + +int main(void) +{ + mx_status_t status; + struct handlers send,recv; + mx_handle_t our_pipe, child_pipe; + +#ifdef __x86_64__ + for_real = ENABLE_FOR_REAL; +#endif + + status = my_create_message_pipe(&send.system, &recv.system); + if (status < 0) + syscall_fail("system exception pipe", status); + + status = my_create_message_pipe(&send.process, &recv.process); + if (status < 0) + syscall_fail("process exception pipe", status); + + status = my_create_message_pipe(&send.thread, &recv.thread); + if (status < 0) + syscall_fail("thread exception pipe", status); + + status = my_create_message_pipe(&our_pipe, &child_pipe); + if (status < 0) + syscall_fail("parent/child pipe", status); + + mx_handle_t thread_handle; + status = my_thread_create(thread_func, (void*) (uintptr_t) child_pipe, &thread_handle, "test-thread"); + if (status < 0) + syscall_fail("my_thread_create", status); + + mx_handle_t watchdog_thread_handle; + status = my_thread_create(watchdog_thread_func, NULL, &watchdog_thread_handle, "watchdog-thread"); + if (status < 0) + syscall_fail("my_thread_create, watchdog", status); + + // That's it for test setup, now onto the tests. + + printf("\nsystem exception handler basic test\n"); + status = _magenta_set_system_exception_handler(send.system, MX_EXCEPTION_BEHAVIOUR_DEFAULT); + if (status < 0) + syscall_fail("set_system_exception_handler", status); + send_msg(our_pipe, MSG_CRASH); + test_received_exception(&recv, HANDLER_SYSTEM); + resume_thread_from_exception(thread_handle, our_pipe); + + printf("\nprocess exception handler basic test\n"); + status = _magenta_set_exception_handler(0, send.process, MX_EXCEPTION_BEHAVIOUR_DEFAULT); + if (status < 0) + syscall_fail("set_process_exception_handler", status); + send_msg(our_pipe, MSG_CRASH); + test_received_exception(&recv, HANDLER_PROCESS); + resume_thread_from_exception(thread_handle, our_pipe); + + printf("\nthread exception handler basic test\n"); + status = _magenta_set_exception_handler(thread_handle, send.thread, MX_EXCEPTION_BEHAVIOUR_DEFAULT); + if (status < 0) + syscall_fail("set_thread_exception_handler", status); + send_msg(our_pipe, MSG_CRASH); + test_received_exception(&recv, HANDLER_THREAD); + resume_thread_from_exception(thread_handle, our_pipe); + + printf("done\n"); + mark_tests_done(our_pipe); + + return 0; +} diff --git a/system/utest/exceptions/rules.mk b/system/utest/exceptions/rules.mk new file mode 100644 index 000000000..632d0b6a4 --- /dev/null +++ b/system/utest/exceptions/rules.mk @@ -0,0 +1,27 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += $(LOCAL_DIR)/exceptions.c + +MODULE_NAME := exceptions-test + +MODULE_DEPS := ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/fpu/BUILD.gn b/system/utest/fpu/BUILD.gn new file mode 100644 index 000000000..24802f664 --- /dev/null +++ b/system/utest/fpu/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("fpu") { + output_name = "fpu-test" + sources = [ + "fputest.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/fpu/fputest.c b/system/utest/fpu/fputest.c new file mode 100644 index 000000000..6c1937b85 --- /dev/null +++ b/system/utest/fpu/fputest.c @@ -0,0 +1,102 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include + +#define THREAD_COUNT 8 +#define ITER 1000000 + +#define __OPTIMIZE(x) __attribute__((optimize(x))) + +#define countof(a) (sizeof(a) / sizeof((a)[0])) + +/* expected double bit pattern for each thread */ +static const uint64_t expected[THREAD_COUNT] = { + 0x4284755ed4188b3e, + 0x4284755ed6cb84c0, + 0x4284755ed97e7dd3, + 0x4284755edc317770, + 0x4284755edee471b9, + 0x4284755ee1976c19, + 0x4284755ee44a648b, + 0x4284755ee6fd5fa7, +}; + +/* optimize this function to cause it to try to use a lot of registers */ +__OPTIMIZE("O3") +static int float_thread(void *arg) +{ + double *val = arg; + unsigned int i, j; + double a[16]; + + printf("float_thread arg %f, running %u iterations\n", *val, ITER); + usleep(500000); + + /* do a bunch of work with floating point to test context switching */ + a[0] = *val; + for (i = 1; i < countof(a); i++) { + a[i] = a[i-1] * 1.01; + } + + for (i = 0; i < ITER; i++) { + a[0] += i; + for (j = 1; j < countof(a); j++) { + a[j] += a[j-1] * 0.00001; + } + } + + *val = a[countof(a) - 1]; + _magenta_thread_exit(); + return 0; +} + +int main(void) +{ + printf("welcome to floating point test\n"); + + /* test lazy fpu load on separate thread */ + mx_handle_t t[THREAD_COUNT]; + double val[countof(t)]; + char name[MX_MAX_NAME_LEN]; + + printf("creating %zu floating point threads\n", countof(t)); + for (unsigned int i = 0; i < countof(t); i++) { + val[i] = i; + snprintf(name, sizeof(name), "fpu thread %u", i); + t[i] = _magenta_thread_create(float_thread, &val[i], name, strlen(name)); + } + + for (unsigned int i = 0; i < countof(t); i++) { + _magenta_handle_wait_one(t[i], MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + _magenta_handle_close(t[i]); + void *v = &val[i]; + uint64_t int64_val = *(uint64_t *)v; + + printf("float thread %u returns val %f 0x%llx, expected 0x%llx\n", i, val[i], int64_val, expected[i]); + + if (int64_val != expected[i]) { + printf("ERROR: value does not match expected\n"); + } + } + + printf("floating point test done\n"); + + return 0; +} diff --git a/system/utest/fpu/rules.mk b/system/utest/fpu/rules.mk new file mode 100644 index 000000000..11ad1ed7c --- /dev/null +++ b/system/utest/fpu/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/fputest.c + +MODULE_NAME := fputest-broken + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/futex/BUILD.gn b/system/utest/futex/BUILD.gn new file mode 100644 index 000000000..f724a3fb4 --- /dev/null +++ b/system/utest/futex/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("futex") { + output_name = "futex-test" + sources = [ + "futex.cpp", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/futex/futex.cpp b/system/utest/futex/futex.cpp new file mode 100644 index 000000000..fd664e681 --- /dev/null +++ b/system/utest/futex/futex.cpp @@ -0,0 +1,434 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +static void assert_eq_check(int lhs_value, int rhs_value, + const char* lhs_expr, const char* rhs_expr, + const char* source_file, + int source_line) { + if (lhs_value != rhs_value) { + printf("Error at %s, line %d:\n", source_file, source_line); + printf("Assertion failed: %s != %s\n", lhs_expr, rhs_expr); + printf("Got values: %d != %d\n", lhs_value, rhs_value); + abort(); + } +} + +#define ASSERT_EQ(x, y) assert_eq_check((x), (y), #x, #y, __FILE__, __LINE__) + +// TODO(mseaborn): Use the standard sched_yield() here when it is available. +static void yield() { + struct timespec wait_time = { 0, 1000 /* nanoseconds */ }; + ASSERT_EQ(nanosleep(&wait_time, NULL), 0); +} + +static void test_futex_wait_value_mismatch() { + int futex_value = 123; + mx_status_t rc = _magenta_futex_wait(&futex_value, futex_value + 1, + MX_TIME_INFINITE); + ASSERT_EQ(rc, ERR_BUSY); +} + +static void test_futex_wait_timeout() { + int futex_value = 123; + mx_status_t rc = _magenta_futex_wait(&futex_value, futex_value, 0); + ASSERT_EQ(rc, ERR_TIMED_OUT); +} + +static void test_futex_wait_bad_address() { + // Check that the wait address is checked for validity. + mx_status_t rc = _magenta_futex_wait(nullptr, 123, MX_TIME_INFINITE); + ASSERT_EQ(rc, ERR_INVALID_ARGS); +} + +// This starts a thread which waits on a futex. We can do futex_wake() +// operations and then test whether or not this thread has been woken up. +class TestThread { +public: + TestThread(volatile int* futex_addr, + mx_time_t timeout_in_us = MX_TIME_INFINITE) + : futex_addr_(futex_addr), + timeout_in_us_(timeout_in_us), + state_(STATE_STARTED) { + thread_handle_ = _magenta_thread_create(wakeup_test_thread, this, + "wakeup_test_thread", 19); + ASSERT_EQ(thread_handle_ > 0, true); + while (state_ == STATE_STARTED) { + yield(); + } + // Note that this could fail if futex_wait() gets a spurious wakeup. + ASSERT_EQ(state_, STATE_ABOUT_TO_WAIT); + // This should be long enough for wakeup_test_thread() to enter + // futex_wait() and add the thread to the wait queue. + struct timespec wait_time = { 0, 100 * 1000000 /* nanoseconds */ }; + ASSERT_EQ(nanosleep(&wait_time, NULL), 0); + // This could also fail if futex_wait() gets a spurious wakeup. + ASSERT_EQ(state_, STATE_ABOUT_TO_WAIT); + } + + ~TestThread() { + ASSERT_EQ(_magenta_handle_wait_one(thread_handle_, MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL), NO_ERROR); + } + + void assert_thread_woken() { + while (state_ == STATE_ABOUT_TO_WAIT) { + yield(); + } + ASSERT_EQ(state_, STATE_WAIT_RETURNED); + } + + void assert_thread_not_woken() { + ASSERT_EQ(state_, STATE_ABOUT_TO_WAIT); + } + + void wait_for_timeout() { + ASSERT_EQ(state_, STATE_ABOUT_TO_WAIT); + while (state_ == STATE_ABOUT_TO_WAIT) { + struct timespec wait_time = { 0, 50 * 1000000 /* nanoseconds */ }; + ASSERT_EQ(nanosleep(&wait_time, NULL), 0); + } + ASSERT_EQ(state_, STATE_WAIT_RETURNED); + } + +private: + static int wakeup_test_thread(void* thread_arg) { + TestThread* thread = reinterpret_cast(thread_arg); + thread->state_ = STATE_ABOUT_TO_WAIT; + mx_status_t rc = + _magenta_futex_wait(const_cast(thread->futex_addr_), + *thread->futex_addr_, thread->timeout_in_us_); + if (thread->timeout_in_us_ == MX_TIME_INFINITE) { + ASSERT_EQ(rc, NO_ERROR); + } else { + ASSERT_EQ(rc, ERR_TIMED_OUT); + } + thread->state_ = STATE_WAIT_RETURNED; + _magenta_thread_exit(); + return 0; + } + + mx_handle_t thread_handle_; + volatile int* futex_addr_; + mx_time_t timeout_in_us_; + volatile enum { + STATE_STARTED = 100, + STATE_ABOUT_TO_WAIT = 200, + STATE_WAIT_RETURNED = 300, + } state_; +}; + +void check_futex_wake(volatile int* futex_addr, int nwake) { + // Change *futex_addr just in case our nanosleep() call did not wait + // long enough for futex_wait() to enter the wait queue, although that + // is unlikely. This prevents the test from hanging if that happens, + // though the test will fail because futex_wait() will not return a + // success result. + (*futex_addr)++; + + mx_status_t rc = _magenta_futex_wake(const_cast(futex_addr), nwake); + ASSERT_EQ(rc, NO_ERROR); +} + +// Test that we can wake up a single thread. +void test_futex_wakeup() { + volatile int futex_value = 1; + TestThread thread(&futex_value); + check_futex_wake(&futex_value, INT_MAX); + thread.assert_thread_woken(); +} + +// Test that we can wake up multiple threads, and that futex_wake() heeds +// the wakeup limit. +void test_futex_wakeup_limit() { + volatile int futex_value = 1; + TestThread thread1(&futex_value); + TestThread thread2(&futex_value); + TestThread thread3(&futex_value); + TestThread thread4(&futex_value); + check_futex_wake(&futex_value, 2); + // Test that threads are woken up in the order that they were added to + // the wait queue. This is not necessarily true for the Linux + // implementation of futexes, but it is true for Magenta's + // implementation. + thread1.assert_thread_woken(); + thread2.assert_thread_woken(); + thread3.assert_thread_not_woken(); + thread4.assert_thread_not_woken(); + + // Clean up: Wake the remaining threads so that they can exit. + check_futex_wake(&futex_value, INT_MAX); + thread3.assert_thread_woken(); + thread4.assert_thread_woken(); +} + +// Check that futex_wait() and futex_wake() heed their address arguments +// properly. A futex_wait() call on one address should not be woken by a +// futex_wake() call on another address. +void test_futex_wakeup_address() { + volatile int futex_value1 = 1; + volatile int futex_value2 = 1; + volatile int dummy_addr = 1; + TestThread thread1(&futex_value1); + TestThread thread2(&futex_value2); + + check_futex_wake(&dummy_addr, INT_MAX); + thread1.assert_thread_not_woken(); + thread2.assert_thread_not_woken(); + + check_futex_wake(&futex_value1, INT_MAX); + thread1.assert_thread_woken(); + thread2.assert_thread_not_woken(); + + // Clean up: Wake the remaining thread so that it can exit. + check_futex_wake(&futex_value2, INT_MAX); + thread2.assert_thread_woken(); +} + +// Check that when futex_wait() times out, it removes the thread from +// the futex wait queue. +void test_futex_unqueued_on_timeout() { + volatile int futex_value = 1; + mx_status_t rc = _magenta_futex_wait(const_cast(&futex_value), + futex_value, 1); + ASSERT_EQ(rc, ERR_TIMED_OUT); + TestThread thread(&futex_value); + // If the earlier futex_wait() did not remove itself from the wait + // queue properly, the following futex_wake() call will attempt to wake + // a thread that is no longer waiting, rather than waking the child + // thread. + check_futex_wake(&futex_value, 1); + thread.assert_thread_woken(); +} + +// This tests for a specific bug in list handling. +void test_futex_unqueued_on_timeout_2() { + volatile int futex_value = 10; + TestThread thread1(&futex_value); + TestThread thread2(&futex_value, 200 * 1000 * 1000); + thread2.wait_for_timeout(); + // With the bug present, thread2 was removed but the futex wait queue's + // tail pointer still points to thread2. When another thread is + // enqueued, it gets added to the thread2 node and lost. + + TestThread thread3(&futex_value); + check_futex_wake(&futex_value, 2); + thread1.assert_thread_woken(); + thread3.assert_thread_woken(); +} + +// This tests for a specific bug in list handling. +void test_futex_unqueued_on_timeout_3() { + volatile int futex_value = 10; + TestThread thread1(&futex_value, 400 * 1000 * 1000); + TestThread thread2(&futex_value); + TestThread thread3(&futex_value); + thread1.wait_for_timeout(); + // With the bug present, thread1 was removed but the futex wait queue + // is set to the thread2 node, which has an invalid (null) tail + // pointer. When another thread is enqueued, we get a null pointer + // dereference or an assertion failure. + + TestThread thread4(&futex_value); + check_futex_wake(&futex_value, 3); + thread2.assert_thread_woken(); + thread3.assert_thread_woken(); + thread4.assert_thread_woken(); +} + +void test_futex_requeue_value_mismatch() { + int futex_value1 = 100; + int futex_value2 = 200; + mx_status_t rc = _magenta_futex_requeue(&futex_value1, 1, futex_value1 + 1, + &futex_value2, 1); + ASSERT_EQ(rc, ERR_BUSY); +} + +void test_futex_requeue_same_addr() { + int futex_value = 100; + mx_status_t rc = _magenta_futex_requeue(&futex_value, 1, futex_value, + &futex_value, 1); + ASSERT_EQ(rc, ERR_INVALID_ARGS); +} + +// Test that futex_requeue() can wake up some threads and requeue others. +void test_futex_requeue() { + volatile int futex_value1 = 100; + volatile int futex_value2 = 200; + TestThread thread1(&futex_value1); + TestThread thread2(&futex_value1); + TestThread thread3(&futex_value1); + TestThread thread4(&futex_value1); + TestThread thread5(&futex_value1); + TestThread thread6(&futex_value1); + + mx_status_t rc = _magenta_futex_requeue( + const_cast(&futex_value1), 3, futex_value1, + const_cast(&futex_value2), 2); + ASSERT_EQ(rc, NO_ERROR); + // 3 of the threads should have been woken. + thread1.assert_thread_woken(); + thread2.assert_thread_woken(); + thread3.assert_thread_woken(); + thread4.assert_thread_not_woken(); + thread5.assert_thread_not_woken(); + thread6.assert_thread_not_woken(); + + // Since 2 of the threads should have been requeued, waking all the + // threads on futex_value2 should wake 2 threads. + check_futex_wake(&futex_value2, INT_MAX); + thread4.assert_thread_woken(); + thread5.assert_thread_woken(); + thread6.assert_thread_not_woken(); + + // Clean up: Wake the remaining thread so that it can exit. + check_futex_wake(&futex_value1, 1); + thread6.assert_thread_woken(); +} + +// Test the case where futex_wait() times out after having been moved to a +// different queue by futex_requeue(). Check that futex_wait() removes +// itself from the correct queue in that case. +void test_futex_requeue_unqueued_on_timeout() { + mx_time_t timeout_in_us = 300 * 1000 * 1000; + volatile int futex_value1 = 100; + volatile int futex_value2 = 200; + TestThread thread1(&futex_value1, timeout_in_us); + mx_status_t rc = _magenta_futex_requeue( + const_cast(&futex_value1), 0, futex_value1, + const_cast(&futex_value2), INT_MAX); + ASSERT_EQ(rc, NO_ERROR); + TestThread thread2(&futex_value2); + // thread1 and thread2 should now both be waiting on futex_value2. + + thread1.wait_for_timeout(); + thread2.assert_thread_not_woken(); + // thread1 should have removed itself from futex_value2's wait queue, + // so only thread2 should be waiting on futex_value2. We can test that + // by doing futex_wake() with count=1. + + check_futex_wake(&futex_value2, 1); + thread2.assert_thread_woken(); +} + +static void log(const char* str) { + uint64_t now = _magenta_current_time(); + printf("[%08llu.%08llu]: %s", now / 1000000000, now % 1000000000, str); +} + +class Event { +public: + Event() : signalled_(0) {} + + void wait() { + if (signalled_ == 0) { + _magenta_futex_wait(&signalled_, signalled_, MX_TIME_INFINITE); + } + } + + void signal() { + if (signalled_ == 0) { + signalled_ = 1; + _magenta_futex_wake(&signalled_, UINT32_MAX); + } + } + +private: + int signalled_; +}; + +Event event; + +static int signal_thread1(void* arg) { + log("thread 1 waiting on event\n"); + event.wait(); + log("thread 1 done\n"); + _magenta_thread_exit(); + return 0; +} + +static int signal_thread2(void* arg) { + log("thread 2 waiting on event\n"); + event.wait(); + log("thread 2 done\n"); + _magenta_thread_exit(); + return 0; +} + +static int signal_thread3(void* arg) { + log("thread 3 waiting on event\n"); + event.wait(); + log("thread 3 done\n"); + _magenta_thread_exit(); + return 0; +} + +static void test_event_signalling() { + mx_handle_t handle1, handle2, handle3; + + log("starting signal threads\n"); + handle1 = _magenta_thread_create(signal_thread1, NULL, "thread 1", 9); + handle2 = _magenta_thread_create(signal_thread2, NULL, "thread 2", 9); + handle3 = _magenta_thread_create(signal_thread3, NULL, "thread 3", 9); + + _magenta_nanosleep(300 * 1000 * 1000); + log("signalling event\n"); + event.signal(); + + log("joining signal threads\n"); + _magenta_handle_wait_one(handle1, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + log("signal_thread 1 joined\n"); + _magenta_handle_wait_one(handle2, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + log("signal_thread 2 joined\n"); + _magenta_handle_wait_one(handle3, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + log("signal_thread 3 joined\n"); + + _magenta_handle_close(handle1); + _magenta_handle_close(handle2); + _magenta_handle_close(handle3); +} + +static void run_test(const char* test_name, void (*test_func)()) { + printf("Running %s...\n", test_name); + test_func(); +} + +#define RUN_TEST(test_func) (run_test(#test_func, test_func)) + +extern "C" int main(void) { + RUN_TEST(test_futex_wait_value_mismatch); + RUN_TEST(test_futex_wait_timeout); + RUN_TEST(test_futex_wait_bad_address); + RUN_TEST(test_futex_wakeup); + RUN_TEST(test_futex_wakeup_limit); + RUN_TEST(test_futex_wakeup_address); + RUN_TEST(test_futex_unqueued_on_timeout); + RUN_TEST(test_futex_unqueued_on_timeout_2); + RUN_TEST(test_futex_unqueued_on_timeout_3); + RUN_TEST(test_futex_requeue_value_mismatch); + RUN_TEST(test_futex_requeue_same_addr); + RUN_TEST(test_futex_requeue); + RUN_TEST(test_futex_requeue_unqueued_on_timeout); + + RUN_TEST(test_event_signalling); + + return 0; +} diff --git a/system/utest/futex/rules.mk b/system/utest/futex/rules.mk new file mode 100644 index 000000000..6aee35acf --- /dev/null +++ b/system/utest/futex/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/futex.cpp + +MODULE_NAME := futex-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/handle-transfer/BUILD.gn b/system/utest/handle-transfer/BUILD.gn new file mode 100644 index 000000000..5effff3d7 --- /dev/null +++ b/system/utest/handle-transfer/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("handle-transfer") { + output_name = "handle-transfer-test" + sources = [ + "handle-transfer.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mojo", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/handle-transfer/handle-transfer.c b/system/utest/handle-transfer/handle-transfer.c new file mode 100644 index 000000000..d3feb9b2f --- /dev/null +++ b/system/utest/handle-transfer/handle-transfer.c @@ -0,0 +1,91 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +// This example tests transfering message pipe handles through message pipes. To do so, it: +// Creates two message pipes, A and B, with handles A0-A1 and B0-B1, respectively +// Sends message "1" into A0 +// Sends A1 to B0 +// Sends message "2" into A0 +// Reads H from B1 (should receive A1 again, possibly with a new value) +// Sends "3" into A0 +// Reads from H until empty. Should read "1", "2", "3" in that order. +int main(void) +{ + mx_handle_t A[2]; + A[0] = _magenta_message_pipe_create(&A[1]); + if (A[0] < 0) { + printf("failed to create message pipe A: %u\n", (mx_status_t)A[0]); + return 1; + } + mx_handle_t B[2]; + B[0] = _magenta_message_pipe_create(&B[1]); + if (B[0] < 0) { + printf("failed to create message pipe B: %u\n", (mx_status_t)B[0]); + return 1; + } + mx_status_t status = _magenta_message_write(A[0], "1", 1u, NULL, 0u, 0u); + if (status != NO_ERROR) { + printf("failed to write message \"1\" into A0: %u\n", status); + return 1; + } + status = _magenta_message_write(B[0], NULL, 0u, &A[1], 1u, 0u); + if (status != NO_ERROR) { + printf("failed to write message with handle A[1]: %u\n", status); + return 1; + } + A[1] = MX_HANDLE_INVALID; + status = _magenta_message_write(A[0], "2", 1u, NULL, 0u, 0u); + if (status != NO_ERROR) { + printf("failed to write message \"2\" into A0: %u\n", status); + return 1; + } + mx_handle_t H; + uint32_t num_bytes = 0u; + uint32_t num_handles = 1u; + status = _magenta_message_read(B[1], NULL, &num_bytes, &H, &num_handles, 0u); + if (status != NO_ERROR) { + printf("failed to read message from B1: %u\n", status); + return 1; + } + if (num_handles != 1u || H == MX_HANDLE_INVALID) { + printf("failed to read actual handle value from B1\n"); + return 1; + } + status = _magenta_message_write(A[0], "3", 1u, NULL, 0u, 0u); + if (status != NO_ERROR) { + printf("failed to write message \"3\" into A0: %u\n", status); + return 1; + } + for (int i=0; i < 3; ++i) { + char buf[1]; + num_bytes = 1u; + num_handles = 0u; + status = _magenta_message_read(H, buf, &num_bytes, NULL, &num_handles, 0u); + if (status != NO_ERROR) { + printf("failed to read message from H: %u\n", status); + return 1; + } + printf("read message: %c\n", buf[0]); + } + + _magenta_handle_close(A[0]); + _magenta_handle_close(B[0]); + _magenta_handle_close(B[1]); + _magenta_handle_close(H); + return 0; +} diff --git a/system/utest/handle-transfer/rules.mk b/system/utest/handle-transfer/rules.mk new file mode 100644 index 000000000..9d5c9616f --- /dev/null +++ b/system/utest/handle-transfer/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/handle-transfer.c \ + +MODULE_NAME := handle-transfer-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/message-pipe/BUILD.gn b/system/utest/message-pipe/BUILD.gn new file mode 100644 index 000000000..40ca09377 --- /dev/null +++ b/system/utest/message-pipe/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("message-pipe") { + output_name = "message-pipe-test" + sources = [ + "message-pipe.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mojo", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/message-pipe/message-pipe.c b/system/utest/message-pipe/message-pipe.c new file mode 100644 index 000000000..49295c7b7 --- /dev/null +++ b/system/utest/message-pipe/message-pipe.c @@ -0,0 +1,148 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +mojo_handle_t _pipe[4]; + +/** + * Message pipe tests with wait multiple. + * + * Tests signal state persistence and various combinations of states on multiple handles. + * + * Test sequence (may not be exact due to concurrency): + * 1. Create 2 pipes and start a reader thread. + * 2. Reader blocks wait on both pipes. + * 3. Write to both pipes and yield. + * 4. Reader wake up with pipe 1 and pipe 2 readable. + * 5. Reader reads from pipe 1, and calls wait again. + * 6. Reader should wake up immediately, with pipe 1 not readable and pipe 2 readable. + * 7. Reader blocks on wait. + * 8. Write to pipe 1 and yield. + * 9. Reader wake up with pipe 1 readable and reads from pipe 1. + * 10. Reader blocks on wait. + * 11. Write to pipe 2 and close both pipes, then yield. + * 12. Reader wake up with pipe 2 closed and readable. + * 13. Read from pipe 2 and wait. + * 14. Reader wake up with pipe 2 closed, closes both pipes and exit. + */ + +static int reader_thread(void* arg) { + unsigned int index = 2; + mojo_handle_t *pipe = &_pipe[index]; + mojo_result_t result; + mojo_handle_signals_t satisfied[2], satisfiable[2]; + mojo_handle_signals_t signals = MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED; + unsigned int packets[2] = {0, 0}; + bool closed[2] = {false, false}; + do { + result = mojo_wait(pipe, &signals, 2, NULL, MOJO_DEADLINE_INDEFINITE, satisfied, satisfiable); + if (result != MOJO_RESULT_OK) { + printf("error %u from mojo_wait\n", result); + return 0; + } + uint32_t data; + uint32_t num_bytes = sizeof(uint32_t); + if (satisfied[0] & MOJO_HANDLE_SIGNAL_READABLE) { + result = mojo_read_message(pipe[0], &data, &num_bytes, NULL, 0, 0); + assert(result == MOJO_RESULT_OK); + packets[0] += 1; + } else if (satisfied[1] & MOJO_HANDLE_SIGNAL_READABLE) { + result = mojo_read_message(pipe[1], &data, &num_bytes, NULL, 0, 0); + assert(result == MOJO_RESULT_OK); + packets[1] += 1; + } else { + if (satisfied[0] & MOJO_HANDLE_SIGNAL_PEER_CLOSED) closed[0] = true; + if (satisfied[1] & MOJO_HANDLE_SIGNAL_PEER_CLOSED) closed[1] = true; + } + } while (!closed[0] || !closed[1]); + mojo_close(pipe[0]); + mojo_close(pipe[1]); + assert(packets[0] == 3); + assert(packets[1] == 2); + return 0; +} + +int main(void) { + mojo_result_t result = mojo_create_message_pipe(&_pipe[0], &_pipe[2]); + if (result != MOJO_RESULT_OK) { + printf("error in create message pipe %u\n", result); + return result; + } + + result = mojo_create_message_pipe(&_pipe[1], &_pipe[3]); + if (result != MOJO_RESULT_OK) { + printf("error in create message pipe %u\n", result); + return result; + } + + mojo_handle_t thread; + result = mojo_thread_create(reader_thread, NULL, &thread, "reader"); + if (result != MOJO_RESULT_OK) { + printf("error %u in mojo_thread_create\n", result); + return -1; + } + + uint32_t data = 0xdeadbeef; + result = mojo_write_message(_pipe[0], &data, sizeof(uint32_t), NULL, 0, 0); + if (result != MOJO_RESULT_OK) { + printf("error %u in mojo_write_message\n", result); + return -1; + } + + result = mojo_write_message(_pipe[1], &data, sizeof(uint32_t), NULL, 0, 0); + if (result != MOJO_RESULT_OK) { + printf("error %u in mojo_write_message\n", result); + return -1; + } + + usleep(1); + + result = mojo_write_message(_pipe[0], &data, sizeof(uint32_t), NULL, 0, 0); + if (result != MOJO_RESULT_OK) { + printf("error %u in mojo_write_message\n", result); + return -1; + } + + result = mojo_write_message(_pipe[0], &data, sizeof(uint32_t), NULL, 0, 0); + if (result != MOJO_RESULT_OK) { + printf("error %u in mojo_write_message\n", result); + return -1; + } + + usleep(1); + + result = mojo_write_message(_pipe[1], &data, sizeof(uint32_t), NULL, 0, 0); + if (result != MOJO_RESULT_OK) { + printf("error %u in mojo_write_message\n", result); + return -1; + } + + mojo_close(_pipe[1]); + + usleep(1); + mojo_close(_pipe[0]); + + mojo_thread_join(thread, MOJO_DEADLINE_INDEFINITE); + + printf("Success\n"); + + return 0; +} diff --git a/system/utest/message-pipe/rules.mk b/system/utest/message-pipe/rules.mk new file mode 100644 index 000000000..2dd5a2765 --- /dev/null +++ b/system/utest/message-pipe/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/message-pipe.c \ + +MODULE_NAME := message-pipe-test + +MODULE_DEPS := \ + ulib/musl ulib/mojo ulib/mxio + +include make/module.mk diff --git a/system/utest/mxr-mutex/BUILD.gn b/system/utest/mxr-mutex/BUILD.gn new file mode 100644 index 000000000..65fc76b2a --- /dev/null +++ b/system/utest/mxr-mutex/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("mxr-mutex") { + output_name = "mxr-mutex-test" + sources = [ + "mutex.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/mxr-mutex/mutex.c b/system/utest/mxr-mutex/mutex.c new file mode 100644 index 000000000..f6b3894ef --- /dev/null +++ b/system/utest/mxr-mutex/mutex.c @@ -0,0 +1,102 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +static mxr_mutex_t mutex = MXR_MUTEX_INIT; + +static void xlog(const char* str) { + uint64_t now = _magenta_current_time(); + printf("[%08llu.%08llu]: %s", now / 1000000000, now % 1000000000, str); +} + +static int mutex_thread_1(void* arg) { + xlog("thread 1 started\n"); + + for (int times = 0; times < 300; times++) { + mxr_mutex_lock(&mutex); + _magenta_nanosleep(1000); + mxr_mutex_unlock(&mutex); + } + + xlog("thread 1 done\n"); + _magenta_thread_exit(); + return 0; +} + +static int mutex_thread_2(void* arg) { + xlog("thread 2 started\n"); + + for (int times = 0; times < 150; times++) { + mxr_mutex_lock(&mutex); + _magenta_nanosleep(2000); + mxr_mutex_unlock(&mutex); + } + + xlog("thread 2 done\n"); + _magenta_thread_exit(); + return 0; +} + +static int mutex_thread_3(void* arg) { + xlog("thread 3 started\n"); + + for (int times = 0; times < 100; times++) { + mxr_mutex_lock(&mutex); + _magenta_nanosleep(3000); + mxr_mutex_unlock(&mutex); + } + + xlog("thread 3 done\n"); + _magenta_thread_exit(); + return 0; +} + +static void test_initializer(void) { + // Let's not accidentally break .bss'd mutexes + static mxr_mutex_t static_mutex; + mxr_mutex_t mutex = MXR_MUTEX_INIT; + if (memcmp(&static_mutex, &mutex, sizeof(mxr_mutex_t))) { + printf("mxr_mutex's initializer is not all zeroes\n"); + exit(-1); + } +} + +static void test_mutexes(void) { + mx_handle_t handle1, handle2, handle3; + + handle1 = _magenta_thread_create(mutex_thread_1, NULL, "thread 1", 9); + handle2 = _magenta_thread_create(mutex_thread_2, NULL, "thread 2", 9); + handle3 = _magenta_thread_create(mutex_thread_3, NULL, "thread 3", 9); + + _magenta_handle_wait_one(handle1, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + _magenta_handle_wait_one(handle2, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + _magenta_handle_wait_one(handle3, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + + _magenta_handle_close(handle1); + _magenta_handle_close(handle2); + _magenta_handle_close(handle3); +} + +int main(int argc, char** argv) { + test_initializer(); + test_mutexes(); + + return 0; +} diff --git a/system/utest/mxr-mutex/rules.mk b/system/utest/mxr-mutex/rules.mk new file mode 100644 index 000000000..d22a87e8e --- /dev/null +++ b/system/utest/mxr-mutex/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/mutex.c + +MODULE_NAME := mxr-mutex-test + +# Depend on musl for now for crt and printf +MODULE_DEPS := ulib/musl ulib/runtime ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/mxr-thread/BUILD.gn b/system/utest/mxr-thread/BUILD.gn new file mode 100644 index 000000000..ed8d1c7e9 --- /dev/null +++ b/system/utest/mxr-thread/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("mxr-thread") { + output_name = "mxr-thread-test" + sources = [ + "thread.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/mxr-thread/rules.mk b/system/utest/mxr-thread/rules.mk new file mode 100644 index 000000000..04d374054 --- /dev/null +++ b/system/utest/mxr-thread/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/thread.c + +MODULE_NAME := mxr-thread-test + +MODULE_DEPS := \ + ulib/runtime ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/mxr-thread/thread.c b/system/utest/mxr-thread/thread.c new file mode 100644 index 000000000..7d4625cdf --- /dev/null +++ b/system/utest/mxr-thread/thread.c @@ -0,0 +1,89 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +#include + +volatile int threads_done[7]; + +static int thread_entry(void* arg) { + int thread_number = (int)(intptr_t)arg; + errno = thread_number; + printf("thread %d sleeping for .1 seconds\n", thread_number); + _magenta_nanosleep(100 * 1000 * 1000); + if (errno != thread_number) { + printf("errno changed by someone!\n"); + exit(-1); + } + threads_done[thread_number] = 1; + return thread_number; +} + +int main(void) { + mxr_thread_t* thread; + mx_status_t status; + int return_value; + + printf("Welcome to thread test!\n"); + + for (int i = 0; i != 4; ++i) { + status = mxr_thread_create(thread_entry, (void*)(intptr_t)i, "mxr thread test", &thread); + if (status != NO_ERROR) + exit(status); + status = mxr_thread_join(thread, &return_value); + if (status != NO_ERROR) + exit(status); + if (return_value != i) + exit(-1); + } + + printf("Attempting to create thread with a super long name. This should fail\n"); + status = mxr_thread_create(thread_entry, NULL, + "01234567890123456789012345678901234567890123456789012345678901234567890123456789", &thread); + if (status == NO_ERROR) + exit(-2); + printf("Attempting to create thread with a null name. This should succeed\n"); + status = mxr_thread_create(thread_entry, (void*)(intptr_t)4, NULL, &thread); + if (status != NO_ERROR) + exit(status); + status = mxr_thread_join(thread, &return_value); + if (status != NO_ERROR) + exit(status); + if (return_value != 4) + exit(-3); + + status = mxr_thread_create(thread_entry, (void*)(intptr_t)5, NULL, &thread); + if (status != NO_ERROR) + exit(status); + status = mxr_thread_detach(thread); + if (status != NO_ERROR) + exit(status); + while (!threads_done[5]) + _magenta_nanosleep(100 * 1000 * 1000); + + thread_entry((void*)(intptr_t)6); + if (!threads_done[6]) + exit(-4); + + printf("thread test done\n"); + + return 0; +} diff --git a/system/utest/mxr-tls/BUILD.gn b/system/utest/mxr-tls/BUILD.gn new file mode 100644 index 000000000..e90308b75 --- /dev/null +++ b/system/utest/mxr-tls/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("mxr-tls") { + output_name = "mxr-tls-test" + sources = [ + "tls.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/mxr-tls/rules.mk b/system/utest/mxr-tls/rules.mk new file mode 100644 index 000000000..826c322e8 --- /dev/null +++ b/system/utest/mxr-tls/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/tls.c + +MODULE_NAME := mxr-tls-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta ulib/runtime + +include make/module.mk diff --git a/system/utest/mxr-tls/tls.c b/system/utest/mxr-tls/tls.c new file mode 100644 index 000000000..3b5114d00 --- /dev/null +++ b/system/utest/mxr-tls/tls.c @@ -0,0 +1,108 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include +#include + +static void fail(const char* function, int line) { + printf("mxr tls test failure in " __FILE__ ": %s: line %d\n", function, line); + _magenta_exit(-1); +} + +static void yield(void) { + _magenta_nanosleep(0u); +} + +static uint64_t test_values[] = { + 0x0000000000000000ull, 0xffffffffffffffffull, 0x5555555555555555ull, + 0xaaaaaaaaaaaaaaaaull, 0x0123456789abcdefull, 0xfedcba9876543210ull, + 0xababababababababull, 0x912f277f61b583a5ull, 0x3b7c08b96d727cedull, +}; + +static mxr_tls_t keys[MXR_TLS_SLOT_MAX]; +static volatile size_t num_keys; + +static int test_entry_point(void* arg) { + uintptr_t id = (uintptr_t)arg; + uintptr_t values[MXR_TLS_SLOT_MAX]; + + // Test that slots are zeroed out on creation. + for (size_t idx = 0; idx < num_keys; idx++) { + if (mxr_tls_get(keys[idx])) + fail(__FUNCTION__, __LINE__); + } + + // Test setting valid values. + for (size_t value_idx = 0; value_idx < sizeof(test_values) / sizeof(*test_values); ++value_idx) { + uintptr_t value = test_values[value_idx] ^ id; + for (uintptr_t iteration = 0; iteration < 0x10ull; ++iteration) { + for (size_t idx = 0; idx < num_keys; ++idx) { + values[idx] = value; + values[idx] ^= (iteration << 12); + values[idx] ^= (idx << 16); + mxr_tls_set(keys[idx], (void*)values[idx]); + } + yield(); + for (size_t idx = 0; idx < num_keys; ++idx) { + uintptr_t new_value = (uintptr_t)mxr_tls_get(keys[idx]); + if (new_value != values[idx]) + fail(__FUNCTION__, __LINE__); + } + } + } + + return 0; +} + +int main(void) { + printf("Starting mxr tls test.\n"); + + for (;;) { + mxr_tls_t key = mxr_tls_allocate(); + if (key == MXR_TLS_SLOT_INVALID) + break; + // We shouldn't allocate too many slots. + if (num_keys >= MXR_TLS_SLOT_MAX) + fail(__FUNCTION__, __LINE__); + keys[num_keys++] = key; + } + + if (num_keys == 0) + fail(__FUNCTION__, __LINE__); + +#define num_threads 64 + + mxr_thread_t* threads[num_threads] = {0}; + + for (uintptr_t idx = 0; idx < num_threads; ++idx) { + mx_status_t status = mxr_thread_create(test_entry_point, (void*)idx, "mxr tls test", threads + idx); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__); + } + + for (uintptr_t idx = 0; idx < num_threads; ++idx) { + mx_status_t status = mxr_thread_join(threads[idx], NULL); + if (status != NO_ERROR) + fail(__FUNCTION__, __LINE__); + } + + test_entry_point((void*)(uintptr_t)num_threads); + + printf("Finishing mxr tls test.\n"); + return 0; +} diff --git a/system/utest/process/BUILD.gn b/system/utest/process/BUILD.gn new file mode 100644 index 000000000..708364dd9 --- /dev/null +++ b/system/utest/process/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("process") { + output_name = "process-test" + sources = [ + "process.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] + data_deps = [ + "child-process", + ] +} diff --git a/system/utest/process/child-process/BUILD.gn b/system/utest/process/child-process/BUILD.gn new file mode 100644 index 000000000..6705ba591 --- /dev/null +++ b/system/utest/process/child-process/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +executable("child-process") { + cflags = [ "-Wno-main" ] + sources = [ + "child-process.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mojo", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/process/child-process/child-process.c b/system/utest/process/child-process/child-process.c new file mode 100644 index 000000000..0b0ba2195 --- /dev/null +++ b/system/utest/process/child-process/child-process.c @@ -0,0 +1,107 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include + +static mx_status_t my_read_message(mx_handle_t handle, void* bytes, uint32_t* num_bytes, + mx_handle_t* handles, uint32_t* num_handles, uint32_t flags) +{ + return _magenta_message_read(handle, bytes, num_bytes, handles, num_handles, flags); +} + +static mx_status_t my_write_message(mx_handle_t handle, const void* bytes, uint32_t num_bytes, + const mx_handle_t* handles, uint32_t num_handles, + uint32_t flags) +{ + return _magenta_message_write(handle, bytes, num_bytes, handles, num_handles, flags); +} + +static mx_status_t my_wait(const mx_handle_t* handles, const mx_signals_t* signals, + uint32_t num_handles, uint32_t* result_index, + mx_time_t deadline, + mx_signals_t* satisfied_signals, + mx_signals_t* satisfiable_signals) +{ + mx_status_t result; + + if (num_handles == 1u) { + result = + _magenta_handle_wait_one(*handles, *signals, MX_TIME_INFINITE, + satisfied_signals, satisfiable_signals); + } else { + result = _magenta_handle_wait_many(num_handles, handles, signals, MX_TIME_INFINITE, + satisfied_signals, satisfiable_signals); + } + + // from _magenta_wait*: TODO(cpu): implement |result_index|, see MG-33 bug. + return result; +} + +static bool wait_readable(mx_handle_t handle) { + mx_signals_t satisfied_signals, satisfiable_signals; + mx_signals_t signals = MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED; + mx_status_t result = my_wait(&handle, &signals, 1, NULL, MX_TIME_INFINITE, + &satisfied_signals, &satisfiable_signals); + if (result != NO_ERROR) { + printf("child-test: my_wait returned %d\n", result); + return false; + } else if ((satisfied_signals & MX_SIGNAL_READABLE) == 0) { + printf("child-test: my_wait peer closed\n"); + return false; + } + return true; +} + + +static void* arg; + +void* __libc_intercept_arg(void* _arg) { + arg = _arg; + return NULL; +} + +int main(int argc, char** argv) { + mx_handle_t handle = (mx_handle_t)(intptr_t)arg; + printf("child-process: got arg %u\n", handle); + + if (!wait_readable(handle)) return -1; + + char buffer[64]; + uint32_t buffer_size = sizeof(buffer); + memset(buffer, 0, sizeof(buffer)); + mx_status_t status = my_read_message(handle, buffer, &buffer_size, NULL, NULL, 0); + printf("child-process: my_read_message returned %d\n", status); + printf("child-process: received \"%s\"\n", buffer); + + printf("child-process: sleeping a bit before responding\n"); + _magenta_nanosleep(200 * 1000 * 1000); + + buffer_size = sizeof(buffer); + snprintf(buffer, buffer_size, "Hi there to you too!"); + + status = my_write_message(handle, buffer, strlen(buffer) + 1, NULL, 0, 0); + printf("child-process: my_write_message returned %d\n", status); + + printf("child-process: done\n"); + + return 1234; +} + diff --git a/system/utest/process/child-process/rules.mk b/system/utest/process/child-process/rules.mk new file mode 100644 index 000000000..fcf5f09bc --- /dev/null +++ b/system/utest/process/child-process/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/child-process.c + +MODULE_CFLAGS := -Wno-main + +MODULE_DEPS := \ + ulib/musl ulib/magenta ulib/runtime ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/process/process.c b/system/utest/process/process.c new file mode 100644 index 000000000..4e2af5ddd --- /dev/null +++ b/system/utest/process/process.c @@ -0,0 +1,197 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include +#include + +static mx_handle_t my_process_create(const char *name, uint32_t name_len) { + return _magenta_process_create(name, name_len); +} + +static mx_status_t my_process_load(mx_handle_t process, const char* elf_file, uintptr_t* out_entry) { + int fd = open(elf_file, O_RDONLY); + if (fd < 0) return ERR_IO; + + uintptr_t entry = 0; + mx_status_t status = mxio_load_elf_fd(process, &entry, fd); + close(fd); + if (status < 0) + return status; + + *out_entry = entry; + return NO_ERROR; +} + +static mx_status_t my_process_start(mx_handle_t process, mx_handle_t handle, uintptr_t entry) { + return _magenta_process_start(process, handle, entry); +} + +static mx_status_t my_wait(const mx_handle_t* handles, const mx_signals_t* signals, + uint32_t num_handles, uint32_t* result_index, + mx_time_t deadline, + mx_signals_t* satisfied_signals, + mx_signals_t* satisfiable_signals) +{ + mx_status_t result; + + if (num_handles == 1u) { + result = + _magenta_handle_wait_one(*handles, *signals, MX_TIME_INFINITE, + satisfied_signals, satisfiable_signals); + } else { + result = _magenta_handle_wait_many(num_handles, handles, signals, MX_TIME_INFINITE, + satisfied_signals, satisfiable_signals); + } + + // from _magenta_wait_*: TODO(cpu): implement |result_index|, see MG-33 bug. + return result; +} + +static mx_status_t my_create_message_pipe(mx_handle_t* handle0, mx_handle_t* handle1) +{ + mx_handle_t result = _magenta_message_pipe_create(handle1); + if (result < 0) + return result; + *handle0 = result; + return NO_ERROR; +} + +static mx_status_t my_read_message(mx_handle_t handle, void* bytes, uint32_t* num_bytes, + mx_handle_t* handles, uint32_t* num_handles, uint32_t flags) +{ + return _magenta_message_read(handle, bytes, num_bytes, handles, num_handles, flags); +} + +static mx_status_t my_write_message(mx_handle_t handle, const void* bytes, uint32_t num_bytes, + const mx_handle_t* handles, uint32_t num_handles, + uint32_t flags) +{ + return _magenta_message_write(handle, bytes, num_bytes, handles, num_handles, flags); +} + +static mx_status_t my_close(mx_handle_t handle) +{ + return _magenta_handle_close(handle); +} + +static mx_status_t my_process_get_info(mx_handle_t handle, mx_process_info_t* info) +{ + return _magenta_process_get_info(handle, info, sizeof(*info)); +} + +static bool wait_readable(mx_handle_t handle) { + mx_signals_t satisfied_signals, satisfiable_signals; + mx_signals_t signals = MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED; + mx_status_t status = my_wait(&handle, &signals, 1, NULL, MX_TIME_INFINITE, + &satisfied_signals, &satisfiable_signals); + if (status != NO_ERROR) { + printf("process-test: my_wait returned %d\n", status); + return false; + } else if ((satisfied_signals & MX_SIGNAL_READABLE) == 0) { + printf("process-test: my_wait peer closed\n"); + return false; + } + return true; +} + +static bool wait_signalled(mx_handle_t handle) { + mx_signals_t satisfied_signals, satisfiable_signals; + mx_signals_t signals = MX_SIGNAL_SIGNALED; + mx_status_t status = my_wait(&handle, &signals, 1, NULL, MX_TIME_INFINITE, + &satisfied_signals, &satisfiable_signals); + if (status != NO_ERROR) { + printf("process-test: my_wait returned %d\n", status); + return false; + } + return true; +} + +int main(void) { + mx_handle_t child_handle, pipe1, pipe2; + + mx_status_t status = my_create_message_pipe(&pipe1, &pipe2); + if (status == NO_ERROR) { + printf("process-test: created message pipe: %u %u\n", pipe1, pipe2); + } else { + printf("process-test: my_create_message_pipe failed %d\n", status); + return status; + } + + static const char child_name[] = "child-process"; + printf("process-test: starting process \"%s\"\n", child_name); + child_handle = my_process_create(child_name, sizeof(child_name)); + printf("process-test: my_process_create returned %d\n", child_handle); + if (child_handle < 0) + return -1; + + uintptr_t entry; + status = my_process_load(child_handle, "/boot/bin/child-process", &entry); + printf("process-test: my_process_load returned %d\n", status); + if (status != NO_ERROR) { + my_close(pipe1); + my_close(child_handle); + return -1; + } + + status = my_process_start(child_handle, pipe2, entry); + printf("process-test: my_process_start returned %d\n", status); + if (status != NO_ERROR) { + my_close(pipe1); + my_close(child_handle); + return -1; + } + + char buffer[64]; + uint32_t buffer_size = sizeof(buffer); + snprintf(buffer, buffer_size, "Hi there!"); + status = my_write_message(pipe1, buffer, buffer_size, NULL, 0, 0); + printf("process-test: my_write_message returned %d\n", status); + + if (!wait_readable(pipe1)) + return -1; + + buffer_size = sizeof(buffer); + memset(buffer, 0, sizeof(buffer)); + status = my_read_message(pipe1, buffer, &buffer_size, NULL, NULL, 0); + printf("process-test: my_read_message returned %d\n", status); + printf("process-test: received \"%s\"\n", buffer); + if (strcmp(buffer, "Hi there to you too!") != 0) { + printf("process-test: unexpected message from child\n"); + return -1; + } + + printf("process-test: done\n"); + + my_close(pipe1); + + mx_process_info_t info; + if (!wait_signalled(child_handle)) return -1; + status = my_process_get_info(child_handle, &info); + printf("process-test: my_process_get_info returned %d\n", status); + if (status != NO_ERROR) + return 1; + printf("child process returned %d\n", info.return_code); + if (info.return_code != 1234) + return -1; + + my_close(child_handle); + return 0; +} diff --git a/system/utest/process/rules.mk b/system/utest/process/rules.mk new file mode 100644 index 000000000..363df1335 --- /dev/null +++ b/system/utest/process/rules.mk @@ -0,0 +1,31 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/process.c + +MODULE_NAME := process-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/mxio ulib/magenta + +MODULES += $(LOCAL_DIR)/child-process + +include make/module.mk diff --git a/system/utest/pthread/BUILD.gn b/system/utest/pthread/BUILD.gn new file mode 100644 index 000000000..ac687acaa --- /dev/null +++ b/system/utest/pthread/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("pthread") { + output_name = "pthread-test" + sources = [ + "pthread.cpp", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/pthread/pthread.cpp b/system/utest/pthread/pthread.cpp new file mode 100644 index 000000000..52ff3370e --- /dev/null +++ b/system/utest/pthread/pthread.cpp @@ -0,0 +1,191 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +int process_waked = 0; +int thread_with_lock = 0; + +static void log(const char* str) { + struct timespec time; + clock_gettime(CLOCK_REALTIME, &time); + printf("[%08lu.%08lu]: %s", time.tv_sec, time.tv_nsec / 1000, str); +} + +static void* mutex_thread_1(void* arg) { + log("thread 1 grabbing mutex\n"); + pthread_mutex_lock(&mutex); + log("thread 1 got mutex\n"); + thread_with_lock = 1; + _magenta_nanosleep(300 * 1000 * 1000); + + // Make sure no other thread woke up + assert(thread_with_lock == 1); + log("thread 1 releasing mutex\n"); + pthread_mutex_unlock(&mutex); + log("thread 1 done\n"); + return NULL; +} + +static void* mutex_thread_2(void* arg) { + _magenta_nanosleep(100 * 1000 * 1000); + log("thread 2 grabbing mutex\n"); + pthread_mutex_lock(&mutex); + log("thread 2 got mutex\n"); + thread_with_lock = 2; + + _magenta_nanosleep(300 * 1000 * 1000); + + // Make sure no other thread woke up + assert(thread_with_lock == 2); + + log("thread 2 releasing mutex\n"); + pthread_mutex_unlock(&mutex); + log("thread 2 done\n"); + return NULL; +} + +static void* mutex_thread_3(void* arg) { + _magenta_nanosleep(100 * 1000 * 1000); + log("thread 3 grabbing mutex\n"); + pthread_mutex_lock(&mutex); + log("thread 3 got mutex\n"); + thread_with_lock = 3; + + _magenta_nanosleep(300 * 1000 * 1000); + + // Make sure no other thread woke up + assert(thread_with_lock == 3); + + log("thread 3 releasing mutex\n"); + pthread_mutex_unlock(&mutex); + log("thread 3 done\n"); + return NULL; +} + +static void* cond_thread1(void* arg) { + pthread_mutex_lock(&mutex); + log("thread 1 waiting on condition\n"); + pthread_cond_wait(&cond, &mutex); + log("thread 2 waiting again\n"); + pthread_cond_wait(&cond, &mutex); + process_waked++; + pthread_mutex_unlock(&mutex); + log("thread 1 done\n"); + return NULL; +} + +static void* cond_thread2(void* arg) { + pthread_mutex_lock(&mutex); + log("thread 2 waiting on condition\n"); + pthread_cond_wait(&cond, &mutex); + log("thread 2 waiting again\n"); + pthread_cond_wait(&cond, &mutex); + process_waked++; + pthread_mutex_unlock(&mutex); + log("thread 2 done\n"); + return NULL; +} + +static void* cond_thread3(void* arg) { + pthread_mutex_lock(&mutex); + log("thread 3 waiting on condition\n"); + pthread_cond_wait(&cond, &mutex); + log("thread 3 waiting again\n"); + pthread_cond_wait(&cond, &mutex); + process_waked++; + pthread_mutex_unlock(&mutex); + log("thread 3 done\n"); + return NULL; +} + +extern "C" int main(void) { + pthread_t thread1, thread2, thread3; + + log("testing uncontested case\n"); + pthread_mutex_lock(&mutex); + pthread_mutex_unlock(&mutex); + log("mutex locked and unlocked\n"); + + log("starting cond threads\n"); + pthread_create(&thread1, NULL, cond_thread1, NULL); + pthread_create(&thread2, NULL, cond_thread2, NULL); + pthread_create(&thread3, NULL, cond_thread3, NULL); + + _magenta_nanosleep(300 * 1000 * 1000); + + log("calling pthread_cond_broadcast\n"); + pthread_cond_broadcast(&cond); + + _magenta_nanosleep(100 * 1000 * 1000); + log("calling pthread_cond_signal\n"); + pthread_cond_signal(&cond); + _magenta_nanosleep(300 * 1000 * 1000); + assert(process_waked == 1); + + log("calling pthread_cond_signal\n"); + pthread_cond_signal(&cond); + _magenta_nanosleep(100 * 1000 * 1000); + assert(process_waked == 2); + + log("calling pthread_cond_signal\n"); + pthread_cond_signal(&cond); + _magenta_nanosleep(100 * 1000 * 1000); + assert(process_waked == 3); + + log("joining cond threads\n"); + pthread_join(thread1, NULL); + log("cond_thread 1 joined\n"); + pthread_join(thread2, NULL); + log("cond_thread 2 joined\n"); + pthread_join(thread3, NULL); + log("cond_thread 3 joined\n"); + + pthread_mutex_lock(&mutex); + log("waiting on condition with 2 second timeout\n"); + struct timespec delay; + clock_gettime(CLOCK_REALTIME, &delay); + delay.tv_sec += 2; + int result = pthread_cond_timedwait(&cond, &mutex, &delay); + pthread_mutex_unlock(&mutex); + log("pthread_cond_timedwait returned\n"); + printf("pthread_cond_timedwait result: %d\n", result); + + assert(result == ERR_TIMED_OUT); + + log("creating mutex threads\n"); + pthread_create(&thread1, NULL, mutex_thread_1, NULL); + pthread_create(&thread2, NULL, mutex_thread_2, NULL); + pthread_create(&thread3, NULL, mutex_thread_3, NULL); + + log("joining mutex threads\n"); + pthread_join(thread1, NULL); + log("thread 1 joined\n"); + pthread_join(thread2, NULL); + log("thread 2 joined\n"); + pthread_join(thread3, NULL); + log("thread 3 joined\n"); + + return 0; +} diff --git a/system/utest/pthread/rules.mk b/system/utest/pthread/rules.mk new file mode 100644 index 000000000..4d73f1c5e --- /dev/null +++ b/system/utest/pthread/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/pthread.cpp + +MODULE_NAME := pthread-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/reply-handle/BUILD.gn b/system/utest/reply-handle/BUILD.gn new file mode 100644 index 000000000..52c8ad775 --- /dev/null +++ b/system/utest/reply-handle/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("reply-handle") { + output_name = "reply-handle-test" + sources = [ + "reply-handle.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] + data_deps = [ + "helper", + ] +} diff --git a/system/utest/reply-handle/helper/BUILD.gn b/system/utest/reply-handle/helper/BUILD.gn new file mode 100644 index 000000000..94c7672a3 --- /dev/null +++ b/system/utest/reply-handle/helper/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +executable("helper") { + sources = [ + "helper.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/reply-handle/helper/helper.c b/system/utest/reply-handle/helper/helper.c new file mode 100644 index 000000000..a0e619b03 --- /dev/null +++ b/system/utest/reply-handle/helper/helper.c @@ -0,0 +1,55 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include + +static void* arg; + +void* __libc_intercept_arg(void* _arg) { + arg = _arg; + return NULL; +} + +int main(int argc, char** argv) { + char data[128]; + mx_handle_t h0, h1; + uint32_t dsz, hsz; + mx_status_t r; + + cprintf("helper: start\n"); + h0 = (mx_handle_t)(uintptr_t) arg; + dsz = sizeof(data); + hsz = 1; + if ((r = _magenta_message_read(h0, data, &dsz, &h1, &hsz, 0)) < 0) { + cprintf("helper: failed to read message %d\n", r); + return -1; + } + if (hsz != 1) { + cprintf("no handle received\n"); + return -1; + } + if ((r = _magenta_message_write(h1, "okay", 5, &h1, 1, 0)) < 0) { + cprintf("helper: failed to write message %d\n", r); + _magenta_message_write(h1, "fail", 5, NULL, 0, 0); + return -1; + } + printf("helper: done\n"); + return 0; +} diff --git a/system/utest/reply-handle/helper/rules.mk b/system/utest/reply-handle/helper/rules.mk new file mode 100644 index 000000000..065d46b9b --- /dev/null +++ b/system/utest/reply-handle/helper/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/helper.c + +MODULE_NAME := reply-handle-helper + +MODULE_DEPS := \ + ulib/mxio ulib/musl ulib/runtime ulib/magenta + +include make/module.mk diff --git a/system/utest/reply-handle/reply-handle.c b/system/utest/reply-handle/reply-handle.c new file mode 100644 index 000000000..a2301ac7d --- /dev/null +++ b/system/utest/reply-handle/reply-handle.c @@ -0,0 +1,97 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +#include +#include + +int main(int argc, char** argv) { + mx_handle_t p1a, p1b, p2a, p2b; + uintptr_t entry; + mx_handle_t p; + mx_status_t r; + int fd; + + if ((p1a = _magenta_message_pipe_create(&p1b)) < 0) { + printf("failed to create pipe1 %d\n", p1a); + return -1; + } + if ((p2a = _magenta_message_pipe_create(&p2b)) < 0) { + printf("failed to create pipe2 %d\n", p2a); + return -1; + } + + // send a message and p2b through p1a + if ((r = _magenta_message_write(p1a, "hello", 6, &p2b, 1, 0)) < 0) { + printf("failed to write message+handle to p1a %d\n", r); + } + + // create helper process and pass p1b across to it + if ((p = _magenta_process_create("helper", 7)) < 0) { + printf("couldn't create process %d\n", p); + return -1; + } + if ((fd = open("/boot/bin/reply-handle-helper", O_RDONLY)) < 0) { + printf("couldn't open reply-handle-helper %d\n", fd); + return -1; + } + if ((r = mxio_load_elf_fd(p, &entry, fd)) < 0) { + printf("couldn't load reply-handle-helper %d\n", r); + return -1; + } + if ((r = _magenta_process_start(p, p1b, entry)) < 0) { + printf("process did not start %d\n", r); + return -1; + } + + mx_signals_t pending; + if ((r = _magenta_handle_wait_one(p2a, MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED, + MX_TIME_INFINITE, &pending, NULL)) < 0) { + printf("error waiting on p2a %d\n", r); + return -1; + } + if (!(pending & MX_SIGNAL_READABLE)) { + printf("pipe 2a not readable\n"); + return -1; + } + + printf("write handle %x to helper...\n", p2b); + char data[128]; + mx_handle_t h; + uint32_t dsz = sizeof(data) - 1; + uint32_t hsz = 1; + if ((r = _magenta_message_read(p2a, data, &dsz, &h, &hsz, 0)) < 0) { + printf("failed to read reply %d\n", r); + return -1; + } + data[dsz] = 0; + printf("reply: '%s' %u %u\n", data, dsz, hsz); + if (hsz != 1) { + printf("no handle returned\n"); + return -1; + } + printf("read handle %x from reply port\n", h); + if (h != p2b) { + printf("different handle returned\n"); + return -1; + } + + printf("success\n"); + return 0; +} diff --git a/system/utest/reply-handle/rules.mk b/system/utest/reply-handle/rules.mk new file mode 100644 index 000000000..9d81faeb3 --- /dev/null +++ b/system/utest/reply-handle/rules.mk @@ -0,0 +1,32 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/reply-handle.c + +MODULE_NAME := reply-handle-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +MODULES += \ + $(LOCAL_DIR)/helper + +include make/module.mk diff --git a/system/utest/rules.mk b/system/utest/rules.mk new file mode 100644 index 000000000..cdb265455 --- /dev/null +++ b/system/utest/rules.mk @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +# include all tests +MODULES += $(patsubst %/rules.mk,%,$(wildcard $(LOCAL_DIR)/*/rules.mk)) + diff --git a/system/utest/test.gni b/system/utest/test.gni new file mode 100644 index 000000000..8b85c12e9 --- /dev/null +++ b/system/utest/test.gni @@ -0,0 +1,19 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +template("test") { + executable(target_name) { + forward_variables_from(invoker, "*") + } +} diff --git a/system/utest/thread-initial-state/BUILD.gn b/system/utest/thread-initial-state/BUILD.gn new file mode 100644 index 000000000..8374e42ab --- /dev/null +++ b/system/utest/thread-initial-state/BUILD.gn @@ -0,0 +1,36 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("thread-initial-state") { + output_name = "thread-initial-state-test" + sources = [ + "asm.h", + "init-state.c", + ] + if (target_cpu == "arm") { + sources += [ "arm.S" ] + } else if (target_cpu == "arm64") { + sources += [ "arm64.S" ] + } else if (target_cpu == "x64") { + sources += [ "x86_64.S" ] + } + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/thread-initial-state/arm.S b/system/utest/thread-initial-state/arm.S new file mode 100644 index 000000000..ce5d32666 --- /dev/null +++ b/system/utest/thread-initial-state/arm.S @@ -0,0 +1,54 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "asm.h" + +.macro check_general_purpose reg + cmp \reg, #0 + bne .Lfail +.endm + +// int thread_entry(void *arg) +FUNCTION(thread_entry) + bmi .Lfail + beq .Lfail + bcs .Lfail + bvs .Lfail + + check_general_purpose r1 + check_general_purpose r2 + check_general_purpose r3 + check_general_purpose r4 + check_general_purpose r5 + check_general_purpose r6 + check_general_purpose r7 + check_general_purpose r8 + check_general_purpose r9 + check_general_purpose r10 + check_general_purpose r11 + check_general_purpose r12 + // Don't check r13, it's SP + check_general_purpose r14 + // Don't check r15, it's PC + + // test thread arg + ldr r1, =0x90abcdef + sub r0, r0, r1 + cmp r0, #0 + bne .Lfail + + // TODO: Test floating point/simd if we support + b _magenta_thread_exit +.Lfail: + b print_fail diff --git a/system/utest/thread-initial-state/arm64.S b/system/utest/thread-initial-state/arm64.S new file mode 100644 index 000000000..016ed952a --- /dev/null +++ b/system/utest/thread-initial-state/arm64.S @@ -0,0 +1,104 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "asm.h" + +.macro check_simd reg1 reg2 + fmov x0, \reg1 + cbnz x0, .Lfail + fmov x0, \reg2 + cbnz x0, .Lfail +.endm + +# int thread_entry(void *arg) +FUNCTION(thread_entry) + bmi .Lfail + beq .Lfail + bcs .Lfail + bvs .Lfail + + cbnz x1, .Lfail + cbnz x2, .Lfail + cbnz x3, .Lfail + cbnz x4, .Lfail + cbnz x5, .Lfail + cbnz x6, .Lfail + cbnz x7, .Lfail + cbnz x8, .Lfail + cbnz x9, .Lfail + cbnz x10, .Lfail + cbnz x11, .Lfail + cbnz x12, .Lfail + cbnz x13, .Lfail + cbnz x14, .Lfail + cbnz x15, .Lfail + cbnz x16, .Lfail + cbnz x17, .Lfail + cbnz x18, .Lfail + cbnz x19, .Lfail + cbnz x20, .Lfail + cbnz x21, .Lfail + cbnz x22, .Lfail + cbnz x23, .Lfail + cbnz x24, .Lfail + cbnz x25, .Lfail + cbnz x26, .Lfail + cbnz x27, .Lfail + cbnz x28, .Lfail + cbnz x29, .Lfail + cbnz x30, .Lfail + + # test thread arg + ldr x1, =0x12345678 + lsl x1, x1, 32 + ldr x2, =0x90abcdef + orr x1, x2, x1 + sub x0, x0, x1 + cbnz x0, .Lfail + + check_simd d0, v0.D[1] + check_simd d1, v1.D[1] + check_simd d2, v2.D[1] + check_simd d3, v3.D[1] + check_simd d4, v4.D[1] + check_simd d5, v5.D[1] + check_simd d6, v6.D[1] + check_simd d7, v7.D[1] + check_simd d8, v8.D[1] + check_simd d9, v9.D[1] + check_simd d10, v10.D[1] + check_simd d11, v11.D[1] + check_simd d12, v12.D[1] + check_simd d13, v13.D[1] + check_simd d14, v14.D[1] + check_simd d15, v15.D[1] + check_simd d16, v16.D[1] + check_simd d17, v17.D[1] + check_simd d18, v18.D[1] + check_simd d19, v19.D[1] + check_simd d20, v20.D[1] + check_simd d21, v21.D[1] + check_simd d22, v22.D[1] + check_simd d23, v23.D[1] + check_simd d24, v24.D[1] + check_simd d25, v25.D[1] + check_simd d26, v26.D[1] + check_simd d27, v27.D[1] + check_simd d28, v28.D[1] + check_simd d29, v29.D[1] + check_simd d30, v30.D[1] + check_simd d31, v31.D[1] + b _magenta_thread_exit +.Lfail: + b print_fail diff --git a/system/utest/thread-initial-state/asm.h b/system/utest/thread-initial-state/asm.h new file mode 100644 index 000000000..66f171b5c --- /dev/null +++ b/system/utest/thread-initial-state/asm.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ASM_H +#define __ASM_H + +#define FUNCTION(x) .global x; .type x,STT_FUNC; x: +#define DATA(x) .global x; .type x,STT_OBJECT; x: + +#define LOCAL_FUNCTION(x) .type x,STT_FUNC; x: +#define LOCAL_DATA(x) .type x,STT_OBJECT; x: + +#define END(x) .size x, . - x + +#endif + diff --git a/system/utest/thread-initial-state/init-state.c b/system/utest/thread-initial-state/init-state.c new file mode 100644 index 000000000..f972200b2 --- /dev/null +++ b/system/utest/thread-initial-state/init-state.c @@ -0,0 +1,37 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +extern int thread_entry(void *arg); + +int print_fail(void) +{ + printf("Failed\n"); + _magenta_thread_exit(); + return 1; // Not reached +} + +int main(void) +{ + void *arg = (void *)0x1234567890abcdef; + mx_handle_t handle = _magenta_thread_create(thread_entry, arg, "", 0); + assert(handle >= 0); + mx_status_t status = _magenta_handle_wait_one(handle, MX_SIGNAL_SIGNALED, + MX_TIME_INFINITE, NULL, NULL); + assert(status >= 0); + return 0; +} diff --git a/system/utest/thread-initial-state/rules.mk b/system/utest/thread-initial-state/rules.mk new file mode 100644 index 000000000..9519d3e7e --- /dev/null +++ b/system/utest/thread-initial-state/rules.mk @@ -0,0 +1,35 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += $(LOCAL_DIR)/init-state.c + +ifeq ($(SUBARCH),x86-64) +MODULE_SRCS += $(LOCAL_DIR)/x86_64.S +else ifeq ($(ARCH),arm) +MODULE_SRCS += $(LOCAL_DIR)/arm.S +else ifeq ($(ARCH),arm64) +MODULE_SRCS += $(LOCAL_DIR)/arm64.S +endif + +MODULE_NAME := thread-initial-state-test + +MODULE_DEPS := ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/thread-initial-state/x86_64.S b/system/utest/thread-initial-state/x86_64.S new file mode 100644 index 000000000..0adb159b1 --- /dev/null +++ b/system/utest/thread-initial-state/x86_64.S @@ -0,0 +1,93 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "asm.h" + +.macro check_general_purpose reg + cmpq $0, \reg + jne .Lfail +.endm + +.macro check_xmm reg + ptest \reg, \reg + jnz .Lfail +.endm + +.macro check_mm reg + movq \reg, %rax + cmpq $0, %rax + jne .Lfail +.endm + +.macro check_segment reg + mov \reg, %ax + cmpw $0, %ax + jne .Lfail +.endm + +# int thread_entry(void *arg) +FUNCTION(thread_entry) + jz .Lfail + jc .Lfail + js .Lfail + jp .Lfail + + check_general_purpose %rax + check_general_purpose %rbx + check_general_purpose %rcx + check_general_purpose %rdx + check_general_purpose %rbp + check_general_purpose %rsi + check_general_purpose %r8 + check_general_purpose %r9 + check_general_purpose %r10 + check_general_purpose %r11 + check_general_purpose %r12 + check_general_purpose %r13 + check_general_purpose %r14 + check_general_purpose %r15 + + # test thread arg + movq $0x1234567890abcdef, %rax + cmpq %rax, %rdi + jne .Lfail + + # Don't check cs/ss since those are set by the kernel explicitly + check_segment %ds + check_segment %es + check_segment %fs + check_segment %gs + + check_xmm %xmm0 + check_xmm %xmm1 + check_xmm %xmm2 + check_xmm %xmm3 + check_xmm %xmm4 + check_xmm %xmm5 + check_xmm %xmm6 + check_xmm %xmm7 + + check_mm %mm0 + check_mm %mm1 + check_mm %mm2 + check_mm %mm3 + check_mm %mm4 + check_mm %mm5 + check_mm %mm6 + check_mm %mm7 + + # TODO: Test ymm registers once they exist + jmp _magenta_thread_exit +.Lfail: + jmp print_fail diff --git a/system/utest/thread-local-storage/BUILD.gn b/system/utest/thread-local-storage/BUILD.gn new file mode 100644 index 000000000..a0178e5eb --- /dev/null +++ b/system/utest/thread-local-storage/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("thread-local-storage") { + output_name = "thread-local-storage-test" + sources = [ + "tls_test.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/thread-local-storage/rules.mk b/system/utest/thread-local-storage/rules.mk new file mode 100644 index 000000000..273201928 --- /dev/null +++ b/system/utest/thread-local-storage/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/tls_test.c \ + +MODULE_NAME := tls-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/thread-local-storage/tls_test.c b/system/utest/thread-local-storage/tls_test.c new file mode 100644 index 000000000..763b3ffbe --- /dev/null +++ b/system/utest/thread-local-storage/tls_test.c @@ -0,0 +1,84 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +static int key_create(pthread_key_t* tsd_key) +{ + int r = pthread_key_create(tsd_key, NULL); + assert(r == 0); + return r; +} + +static int set_key_value(pthread_key_t key, void * value) +{ + int r = pthread_setspecific(key, value); + assert(r == 0); + return r; +} + +static pthread_key_t tsd_key1, tsd_key2; + +static void test_tls(int thread_no) { + int value1 = thread_no; + int value2 = thread_no + 10; + set_key_value(tsd_key1, &value1); + set_key_value(tsd_key2, &value2); + _magenta_nanosleep(100 * 1000 * 1000); + int* v = pthread_getspecific(tsd_key1); + assert(*v == value1); + v = pthread_getspecific(tsd_key2); + assert(*v == value2); + printf("tls_test completed for thread: %d\n", thread_no); +} + +static void* do_work(void* arg) { + printf("do_work for thread: %d\n", *(int*)arg); + test_tls(*(int*)arg); + return NULL; +} + + +int main(void) { +#if defined ARCH_X86_64 || defined ARCH_ARM64 + key_create(&tsd_key1); + key_create(&tsd_key2); + + // Run this 20 times for sanity check + for(int i = 1; i <= 20; i++) { + int main_thread = 1, thread_1 = i*2, thread_2 = i*2+1; + + pthread_t thread2, thread3; + + printf("creating thread: %d\n", thread_1); + pthread_create(&thread2, NULL, do_work, &thread_1); + + printf("creating thread: %d\n", thread_2); + pthread_create(&thread3, NULL, do_work, &thread_2); + + test_tls(main_thread); + + printf("joining thread: %d\n", thread_1); + pthread_join(thread2, NULL); + + printf("joining thread: %d\n", thread_2); + pthread_join(thread3, NULL); + } +#endif + return 0; +} diff --git a/system/utest/threads/BUILD.gn b/system/utest/threads/BUILD.gn new file mode 100644 index 000000000..33f8c7d18 --- /dev/null +++ b/system/utest/threads/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("threads") { + output_name = "threads-test" + sources = [ + "threads.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/threads/rules.mk b/system/utest/threads/rules.mk new file mode 100644 index 000000000..9147245c1 --- /dev/null +++ b/system/utest/threads/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/threads.c + +MODULE_NAME := threads-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta + +include make/module.mk diff --git a/system/utest/threads/threads.c b/system/utest/threads/threads.c new file mode 100644 index 000000000..d48d8fdef --- /dev/null +++ b/system/utest/threads/threads.c @@ -0,0 +1,63 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +static int thread_1(void* arg) +{ + printf("thread 1 sleeping for .1 seconds\n"); + struct timespec t = (struct timespec) { + .tv_sec = 0, + .tv_nsec = 100 * 1000 * 1000, + }; + nanosleep(&t, NULL); + + printf("thread 1 calling _magenta_thread_exit()\n"); + _magenta_thread_exit(); + return 0; +} + +int main(void) +{ + mx_handle_t handle; + printf("Welcome to thread test!\n"); + + for (int i = 0; i != 4; ++i) { + handle = _magenta_thread_create(thread_1, NULL, "thread 1", 9); + printf("thread:%d created handle %d\n", i, handle); + + _magenta_handle_wait_one(handle, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL, NULL); + printf("thread:%d joined\n", i); + + _magenta_handle_close(handle); + } + + printf("Attempting to create thread with a super long name. This should fail\n"); + handle = _magenta_thread_create(thread_1, NULL, + "01234567890123456789012345678901234567890123456789012345678901234567890123456789", 81); + printf("_magenta_thread_create returned %u\n", handle); + + printf("Attempting to create thread with a null. This should succeed\n"); + handle = _magenta_thread_create(thread_1, NULL, NULL, 0); + printf("_magenta_thread_create returned %u\n", handle); + _magenta_handle_close(handle); + + printf("thread test done\n"); + + return 0; +} diff --git a/system/utest/vmo/BUILD.gn b/system/utest/vmo/BUILD.gn new file mode 100644 index 000000000..87280eb3d --- /dev/null +++ b/system/utest/vmo/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//system/utest/test.gni") + +test("vmo") { + output_name = "vmo-test" + sources = [ + "vmo.c", + ] + deps = [ + "//system/ulib/magenta", + "//system/ulib/mxio", + "//system/ulib/mxu", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/system/utest/vmo/rules.mk b/system/utest/vmo/rules.mk new file mode 100644 index 000000000..10125a3d3 --- /dev/null +++ b/system/utest/vmo/rules.mk @@ -0,0 +1,29 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userapp + +MODULE_SRCS += \ + $(LOCAL_DIR)/vmo.c + +MODULE_NAME := vmo-test + +MODULE_DEPS := \ + ulib/musl ulib/mxio ulib/magenta ulib/mxu + +include make/module.mk diff --git a/system/utest/vmo/vmo.c b/system/utest/vmo/vmo.c new file mode 100644 index 000000000..7a8248b59 --- /dev/null +++ b/system/utest/vmo/vmo.c @@ -0,0 +1,146 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +bool vmo_create_test(void) { + BEGIN_TEST; + + mx_status_t status; + mx_handle_t vmo[16]; + + // allocate a bunch of vmos then free them + for (size_t i = 0; i < countof(vmo); i++) { + vmo[i] = _magenta_vm_object_create(i * PAGE_SIZE); + EXPECT_LT(0, vmo[i], "vm_object_create"); + } + + for (size_t i = 0; i < countof(vmo); i++) { + status = _magenta_handle_close(vmo[i]); + EXPECT_EQ(NO_ERROR, status, "handle_close"); + } + + END_TEST; +} + +bool vmo_read_write_test(void) { + BEGIN_TEST; + + mx_status_t status; + mx_ssize_t sstatus; + mx_handle_t vmo; + + // allocate an object and read/write from it + const size_t len = PAGE_SIZE * 4; + vmo = _magenta_vm_object_create(len); + EXPECT_LT(0, vmo, "vm_object_create"); + + char buf[PAGE_SIZE]; + sstatus = _magenta_vm_object_read(vmo, buf, 0, sizeof(buf)); + EXPECT_EQ((mx_ssize_t)sizeof(buf), sstatus, "vm_object_read"); + + memset(buf, 0x99, sizeof(buf)); + sstatus = _magenta_vm_object_write(vmo, buf, 0, sizeof(buf)); + EXPECT_EQ((mx_ssize_t)sizeof(buf), sstatus, "vm_object_write"); + + // map it + uintptr_t ptr; + status = _magenta_process_vm_map(0, vmo, 0, len, &ptr, + MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE); + EXPECT_EQ(NO_ERROR, status, "vm_map"); + EXPECT_NEQ(0u, ptr, "vm_map"); + + // check that it matches what we last wrote into it + EXPECT_BYTES_EQ((void *)buf, (void *)ptr, sizeof(buf), "mapped buffer"); + + status = _magenta_process_vm_unmap(0, ptr, 0); + EXPECT_EQ(NO_ERROR, status, "vm_unmap"); + + // close the handle + status = _magenta_handle_close(vmo); + EXPECT_EQ(NO_ERROR, status, "handle_close"); + + END_TEST; +} + +bool vmo_resize_test(void) { + BEGIN_TEST; + + mx_status_t status; + mx_handle_t vmo; + + // allocate an object + size_t len = PAGE_SIZE * 4; + vmo = _magenta_vm_object_create(len); + EXPECT_LT(0, vmo, "vm_object_create"); + + // get the size that we set it to + uint64_t size = 0x99999999; + status = _magenta_vm_object_get_size(vmo, &size); + EXPECT_EQ(NO_ERROR, status, "vm_object_get_size"); + EXPECT_EQ(len, size, "vm_object_get_size"); + + // set_size is not implemented right now, so test for the failure mode +#if 0 + // try to resize it + len += PAGE_SIZE; + status = _magenta_vm_object_set_size(vmo, len); + EXPECT_EQ(NO_ERROR, status, "vm_object_set_size"); + + // get the size again + size = 0x99999999; + status = _magenta_vm_object_get_size(vmo, &size); + EXPECT_EQ(NO_ERROR, status, "vm_object_get_size"); + EXPECT_EQ(len, size, "vm_object_get_size"); + + // try to resize it to a ludicrous size + status = _magenta_vm_object_set_size(vmo, UINT64_MAX); + EXPECT_EQ(ERR_NO_MEMORY, status, "vm_object_set_size"); +#else + status = _magenta_vm_object_set_size(vmo, len + PAGE_SIZE); + EXPECT_EQ(ERR_NOT_IMPLEMENTED, status, "vm_object_set_size"); +#endif + + // close the handle + status = _magenta_handle_close(vmo); + EXPECT_EQ(NO_ERROR, status, "handle_close"); + + END_TEST; +} + + + +BEGIN_TEST_CASE(vmo_tests) +RUN_TEST(vmo_create_test); +RUN_TEST(vmo_read_write_test); +RUN_TEST(vmo_resize_test); +END_TEST_CASE(vmo_tests) + +int main(int argc, char **argv) { + + // TODO: remove this register once global constructors work + unittest_register_test_case(&_vmo_tests_element); + + bool success = unittest_run_all_tests(); + return success ? 0 : -1; +} diff --git a/third_party/README b/third_party/README new file mode 100644 index 000000000..25fa599fd --- /dev/null +++ b/third_party/README @@ -0,0 +1,2 @@ +This directory contains source modules that are composed of +software originating from external to the lk project. diff --git a/third_party/lib/acpica/.gitignore b/third_party/lib/acpica/.gitignore new file mode 100644 index 000000000..5aafebd8c --- /dev/null +++ b/third_party/lib/acpica/.gitignore @@ -0,0 +1,2 @@ +generate/**/bin +generate/**/obj diff --git a/third_party/lib/acpica/BUILD.gn b/third_party/lib/acpica/BUILD.gn new file mode 100644 index 000000000..ac3f61d5d --- /dev/null +++ b/third_party/lib/acpica/BUILD.gn @@ -0,0 +1,190 @@ +config("_acpica_config") { + visibility = [ ":*" ] + include_dirs = [ "source/include" ] +} + +module("acpica") { + public_configs = [ ":_acpica_config" ] + include_dirs = [ "source/include" ] + cflags_c = [ + # The implementation dereferences type-punned pointers. + "-Wno-strict-aliasing", + ] + if (is_clang) { + cflags_c += [ + # The implementation casts const char * to char *. + "-Wno-ignored-qualifiers", + ] + } else { + cflags_c += [ + # The implementation casts const char * to char *. + "-Wno-discarded-qualifiers", + ] + } + sources = [ + "source/common/ahids.c", + "source/common/ahpredef.c", + "source/common/ahtable.c", + "source/common/getopt.c", + "source/components/dispatcher/dsargs.c", + "source/components/dispatcher/dscontrol.c", + "source/components/dispatcher/dsdebug.c", + "source/components/dispatcher/dsfield.c", + "source/components/dispatcher/dsinit.c", + "source/components/dispatcher/dsmethod.c", + "source/components/dispatcher/dsmthdat.c", + "source/components/dispatcher/dsobject.c", + "source/components/dispatcher/dsopcode.c", + "source/components/dispatcher/dsutils.c", + "source/components/dispatcher/dswexec.c", + "source/components/dispatcher/dswload.c", + "source/components/dispatcher/dswload2.c", + "source/components/dispatcher/dswscope.c", + "source/components/dispatcher/dswstate.c", + "source/components/events/evevent.c", + "source/components/events/evglock.c", + "source/components/events/evgpe.c", + "source/components/events/evgpeblk.c", + "source/components/events/evgpeinit.c", + "source/components/events/evgpeutil.c", + "source/components/events/evhandler.c", + "source/components/events/evmisc.c", + "source/components/events/evregion.c", + "source/components/events/evrgnini.c", + "source/components/events/evsci.c", + "source/components/events/evxface.c", + "source/components/events/evxfevnt.c", + "source/components/events/evxfgpe.c", + "source/components/events/evxfregn.c", + "source/components/executer/exconfig.c", + "source/components/executer/exconvrt.c", + "source/components/executer/excreate.c", + "source/components/executer/exdebug.c", + "source/components/executer/exdump.c", + "source/components/executer/exfield.c", + "source/components/executer/exfldio.c", + "source/components/executer/exmisc.c", + "source/components/executer/exmutex.c", + "source/components/executer/exnames.c", + "source/components/executer/exoparg1.c", + "source/components/executer/exoparg2.c", + "source/components/executer/exoparg3.c", + "source/components/executer/exoparg6.c", + "source/components/executer/exprep.c", + "source/components/executer/exregion.c", + "source/components/executer/exresnte.c", + "source/components/executer/exresolv.c", + "source/components/executer/exresop.c", + "source/components/executer/exstore.c", + "source/components/executer/exstoren.c", + "source/components/executer/exstorob.c", + "source/components/executer/exsystem.c", + "source/components/executer/extrace.c", + "source/components/executer/exutils.c", + "source/components/hardware/hwacpi.c", + "source/components/hardware/hwesleep.c", + "source/components/hardware/hwgpe.c", + "source/components/hardware/hwpci.c", + "source/components/hardware/hwregs.c", + "source/components/hardware/hwsleep.c", + "source/components/hardware/hwtimer.c", + "source/components/hardware/hwvalid.c", + "source/components/hardware/hwxface.c", + "source/components/hardware/hwxfsleep.c", + "source/components/namespace/nsaccess.c", + "source/components/namespace/nsalloc.c", + "source/components/namespace/nsarguments.c", + "source/components/namespace/nsconvert.c", + "source/components/namespace/nsdump.c", + "source/components/namespace/nsdumpdv.c", + "source/components/namespace/nseval.c", + "source/components/namespace/nsinit.c", + "source/components/namespace/nsload.c", + "source/components/namespace/nsnames.c", + "source/components/namespace/nsobject.c", + "source/components/namespace/nsparse.c", + "source/components/namespace/nspredef.c", + "source/components/namespace/nsprepkg.c", + "source/components/namespace/nsrepair.c", + "source/components/namespace/nsrepair2.c", + "source/components/namespace/nssearch.c", + "source/components/namespace/nsutils.c", + "source/components/namespace/nswalk.c", + "source/components/namespace/nsxfeval.c", + "source/components/namespace/nsxfname.c", + "source/components/namespace/nsxfobj.c", + "source/components/parser/psargs.c", + "source/components/parser/psloop.c", + "source/components/parser/psobject.c", + "source/components/parser/psopcode.c", + "source/components/parser/psopinfo.c", + "source/components/parser/psparse.c", + "source/components/parser/psscope.c", + "source/components/parser/pstree.c", + "source/components/parser/psutils.c", + "source/components/parser/pswalk.c", + "source/components/parser/psxface.c", + "source/components/resources/rsaddr.c", + "source/components/resources/rscalc.c", + "source/components/resources/rscreate.c", + "source/components/resources/rsdumpinfo.c", + "source/components/resources/rsinfo.c", + "source/components/resources/rsio.c", + "source/components/resources/rsirq.c", + "source/components/resources/rslist.c", + "source/components/resources/rsmemory.c", + "source/components/resources/rsmisc.c", + "source/components/resources/rsserial.c", + "source/components/resources/rsutils.c", + "source/components/resources/rsxface.c", + "source/components/tables/tbdata.c", + "source/components/tables/tbfadt.c", + "source/components/tables/tbfind.c", + "source/components/tables/tbinstal.c", + "source/components/tables/tbprint.c", + "source/components/tables/tbutils.c", + "source/components/tables/tbxface.c", + "source/components/tables/tbxfload.c", + "source/components/tables/tbxfroot.c", + "source/components/utilities/utaddress.c", + "source/components/utilities/utalloc.c", + "source/components/utilities/utbuffer.c", + "source/components/utilities/utcache.c", + "source/components/utilities/utclib.c", + "source/components/utilities/utcopy.c", + "source/components/utilities/utdebug.c", + "source/components/utilities/utdecode.c", + "source/components/utilities/utdelete.c", + "source/components/utilities/uterror.c", + "source/components/utilities/uteval.c", + "source/components/utilities/utexcep.c", + "source/components/utilities/utglobal.c", + "source/components/utilities/uthex.c", + "source/components/utilities/utids.c", + "source/components/utilities/utinit.c", + "source/components/utilities/utlock.c", + "source/components/utilities/utmath.c", + "source/components/utilities/utmisc.c", + "source/components/utilities/utmutex.c", + "source/components/utilities/utnonansi.c", + "source/components/utilities/utobject.c", + "source/components/utilities/utosi.c", + "source/components/utilities/utownerid.c", + "source/components/utilities/utpredef.c", + "source/components/utilities/utprint.c", + "source/components/utilities/utresrc.c", + "source/components/utilities/utstate.c", + "source/components/utilities/utstring.c", + "source/components/utilities/uttrack.c", + "source/components/utilities/utuuid.c", + "source/components/utilities/utxface.c", + "source/components/utilities/utxferror.c", + "source/components/utilities/utxfinit.c", + "source/components/utilities/utxfmutex.c", + "source/os_specific/service_layers/osmagenta.c", + ] + deps = [ + "//kernel/dev/interrupt", + "//kernel/lib/libc", + ] +} diff --git a/third_party/lib/acpica/LICENSE b/third_party/lib/acpica/LICENSE new file mode 100644 index 000000000..66ed89eed --- /dev/null +++ b/third_party/lib/acpica/LICENSE @@ -0,0 +1,34 @@ + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. diff --git a/third_party/lib/acpica/Makefile b/third_party/lib/acpica/Makefile new file mode 100644 index 000000000..80bf37959 --- /dev/null +++ b/third_party/lib/acpica/Makefile @@ -0,0 +1,22 @@ +# +# Common make for acpica tools and utilities +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under top level acpica directory. +# It specifically places all the object files for each tool in separate +# generate/unix subdirectories, not within the various ACPICA source +# code directories. This prevents collisions between different +# compilations of the same source file with different compile options. +# + +ifeq ($(OS),efi) + BUILD_DIRECTORY_PATH = "generate/efi" + include generate/efi/Makefile.config + include generate/efi/Makefile.common +else + BUILD_DIRECTORY_PATH = "generate/unix" + include generate/unix/Makefile.config + include generate/unix/Makefile.common +endif diff --git a/third_party/lib/acpica/README.fuchsia b/third_party/lib/acpica/README.fuchsia new file mode 100644 index 000000000..73eb25465 --- /dev/null +++ b/third_party/lib/acpica/README.fuchsia @@ -0,0 +1,12 @@ +Source: https://acpica.org/sites/acpica/files/acpica-unix2-20160108.tar.gz +SHA256: dfdb4dd7d35ccb8866dc5028a05330f622fc2742073ed25b4d57362f1317724e +License: Dual-licensed GPLv2/BSD +Version: 20160108 + +Modifications: +- Added README.fuchsia +- Added rules.mk +- Added LICENSE containing copy of source license banner +- Added source/include/platform/acmagenta.h +- Modified source/include/platform/acenv.h to use acmagenta.h +- Added source/os_specific/service_layers/osmagenta.c diff --git a/third_party/lib/acpica/changes.txt b/third_party/lib/acpica/changes.txt new file mode 100644 index 000000000..1d3ec5aa0 --- /dev/null +++ b/third_party/lib/acpica/changes.txt @@ -0,0 +1,16299 @@ +---------------------------------------- +8 January 2016. Summary of changes for version 20160108: + +1) ACPICA kernel-resident subsystem: + +Updated all ACPICA copyrights and signons to 2016: Added the 2016 +copyright to all source code module headers and utility/tool signons. +This includes the standard Linux dual-license header. This affects +virtually every file in the ACPICA core subsystem, iASL compiler, all +ACPICA utilities, and the ACPICA test suite. + +Fixed a regression introduced in version 20151218 concerning the +execution of so-called module-level ASL/AML code. Namespace objects +created under a module-level If() construct were not properly/fully +entered into the namespace and could cause an interpreter fault when +accessed. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + +Current Release: + Non-Debug Version: 102.7K Code, 28.4K Data, 131.1K Total + Debug Version: 200.4K Code, 81.9K Data, 282.4K Total + Previous Release: + Non-Debug Version: 102.6K Code, 28.4K Data, 131.0K Total + Debug Version: 200.3K Code, 81.9K Data, 282.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed a problem with the compilation of the GpioIo and GpioInt resource +descriptors. The _PIN field name was incorrectly defined to be an array +of 32-bit values, but the _PIN values are in fact 16 bits each. This +would cause incorrect bit width warnings when using Word (16-bit) fields +to access the descriptors. + + +---------------------------------------- +18 December 2015. Summary of changes for version 20151218: + +1) ACPICA kernel-resident subsystem: + +Implemented per-AML-table execution of "module-level code" as individual +ACPI tables are loaded into the namespace during ACPICA initialization. +In other words, any module-level code within an AML table is executed +immediately after the table is loaded, instead of batched and executed +after all of the tables have been loaded. This provides compatibility +with other ACPI implementations. ACPICA BZ 1219. Bob Moore, Lv Zheng, +David Box. + +To fully support the feature above, the default operation region handlers +for the SystemMemory, SystemIO, and PCI_Config address spaces are now +installed before any ACPI tables are loaded. This enables module-level +code to access these address spaces during the table load and module- +level code execution phase. ACPICA BZ 1220. Bob Moore, Lv Zheng, David +Box. + +Implemented several changes to the internal _REG support in conjunction +with the changes above. Also, changes to the AcpiExec/AcpiNames/Examples +utilities for the changes above. Although these tools were changed, host +operating systems that simply use the default handlers for SystemMemory, +SystemIO, and PCI_Config spaces should not require any update. Lv Zheng. + +For example, in the code below, DEV1 is conditionally added to the +namespace by the DSDT via module-level code that accesses an operation +region. The SSDT references DEV1 via the Scope operator. DEV1 must be +created immediately after the DSDT is loaded in order for the SSDT to +successfully reference DEV1. Previously, this code would cause an +AE_NOT_EXIST exception during the load of the SSDT. Now, this code is +fully supported by ACPICA. + + DefinitionBlock ("", "DSDT", 2, "Intel", "DSDT1", 1) + { + OperationRegion (OPR1, SystemMemory, 0x400, 32) + Field (OPR1, AnyAcc, NoLock, Preserve) + { + FLD1, 1 + } + If (FLD1) + { + Device (\DEV1) + { + } + } + } + DefinitionBlock ("", "SSDT", 2, "Intel", "SSDT1", 1) + { + External (\DEV1, DeviceObj) + Scope (\DEV1) + { + } + } + +Fixed an AML interpreter problem where control method invocations were +not handled correctly when the invocation was itself a SuperName argument +to another ASL operator. In these cases, the method was not invoked. +ACPICA BZ 1002. Affects the following ASL operators that have a SuperName +argument: + Store + Acquire, Wait + CondRefOf, RefOf + Decrement, Increment + Load, Unload + Notify + Signal, Release, Reset + SizeOf + +Implemented automatic String-to-ObjectReference conversion support for +packages returned by predefined names (such as _DEP). A common BIOS error +is to add double quotes around an ObjectReference namepath, which turns +the reference into an unexpected string object. This support detects the +problem and corrects it before the package is returned to the caller that +invoked the method. Lv Zheng. + +Implemented extensions to the Concatenate operator. Concatenate now +accepts any type of object, it is not restricted to simply +Integer/String/Buffer. For objects other than these 3 basic data types, +the argument is treated as a string containing the name of the object +type. This expands the utility of Concatenate and the Printf/Fprintf +macros. ACPICA BZ 1222. + +Cleaned up the output of the ASL Debug object. The timer() value is now +optional and no longer emitted by default. Also, the basic data types of +Integer/String/Buffer are simply emitted as their values, without a data +type string -- since the data type is obvious from the output. ACPICA BZ +1221. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 102.6K Code, 28.4K Data, 131.0K Total + Debug Version: 200.3K Code, 81.9K Data, 282.3K Total + Previous Release: + Non-Debug Version: 102.0K Code, 28.3K Data, 130.3K Total + Debug Version: 199.6K Code, 81.8K Data, 281.4K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed some issues with the ASL Include() operator. This operator +was incorrectly defined in the iASL parser rules, causing a new scope to +be opened for the code within the include file. This could lead to +several issues, including allowing ASL code that is technically illegal +and not supported by AML interpreters. Note, this does not affect the +related #include preprocessor operator. ACPICA BZ 1212. + +iASL/Disassembler: Implemented support for the ASL ElseIf operator. This +operator is essentially an ASL macro since there is no AML opcode +associated with it. The code emitted by the iASL compiler for ElseIf is +an Else opcode followed immediately by an If opcode. The disassembler +will now emit an ElseIf if it finds an Else immediately followed by an +If. This simplifies the decoded ASL, especially for deeply nested +If..Else and large Switch constructs. Thus, the disassembled code more +closely follows the original source ASL. ACPICA BZ 1211. Example: + + Old disassembly: + Else + { + If (Arg0 == 0x02) + { + Local0 = 0x05 + } + } + + New disassembly: + ElseIf (Arg0 == 0x02) + { + Local0 = 0x05 + } + +AcpiExec: Added support for the new module level code behavior and the +early region installation. This required a small change to the +initialization, since AcpiExec must install its own operation region +handlers. + +AcpiExec: Added support to make the debug object timer optional. Default +is timer disabled. This cleans up the debug object output -- the timer +data is rarely used. + +AcpiExec: Multiple ACPI tables are now loaded in the order that they +appear on the command line. This can be important when there are +interdependencies/references between the tables. + +iASL/Templates. Add support to generate template files with multiple +SSDTs within a single output file. Also added ommand line support to +specify the number of SSDTs (in addition to a single DSDT). ACPICA BZ +1223, 1225. + + +---------------------------------------- +24 November 2015. Summary of changes for version 20151124: + +1) ACPICA kernel-resident subsystem: + +Fixed a possible regression for a previous update to FADT handling. The +FADT no longer has a fixed table ID, causing some issues with code that +was hardwired to a specific ID. Lv Zheng. + +Fixed a problem where the method auto-serialization could interfere with +the current SyncLevel. This change makes the auto-serialization support +transparent to the SyncLevel support and management. + +Removed support for the _SUB predefined name in AcpiGetObjectInfo. This +interface is intended for early access to the namespace during the +initial namespace device discovery walk. The _SUB method has been seen to +access operation regions in some cases, causing errors because the +operation regions are not fully initialized. + +AML Debugger: Fixed some issues with the terminate/quit/exit commands +that can cause faults. Lv Zheng. + +AML Debugger: Add thread ID support so that single-step mode only applies +to the AML Debugger thread. This prevents runtime errors within some +kernels. Lv Zheng. + +Eliminated extraneous warnings from AcpiGetSleepTypeData. Since the _Sx +methods that are invoked by this interface are optional, removed warnings +emitted for the case where one or more of these methods do not exist. +ACPICA BZ 1208, original change by Prarit Bhargava. + +Made a major pass through the entire ACPICA source code base to +standardize formatting that has diverged a bit over time. There are no +functional changes, but this will of course cause quite a few code +differences from the previous ACPICA release. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 102.0K Code, 28.3K Data, 130.3K Total + Debug Version: 199.6K Code, 81.8K Data, 281.4K Total + Previous Release: + Non-Debug Version: 101.7K Code, 27.9K Data, 129.6K Total + Debug Version: 199.3K Code, 81.4K Data, 280.7K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL/acpiexec/acpixtract/disassembler: Added support to allow multiple +definition blocks within a single ASL file and the resulting AML file. +Support for this type of file was also added to the various tools that +use binary AML files: acpiexec, acpixtract, and the AML disassembler. The +example code below shows two definition blocks within the same file: + + DefinitionBlock ("dsdt.aml", "DSDT", 2, "Intel", "Template", +0x12345678) + { + } + DefinitionBlock ("", "SSDT", 2, "Intel", "Template", 0xABCDEF01) + { + } + +iASL: Enhanced typechecking for the Name() operator. All expressions for +the value of the named object must be reduced/folded to a single constant +at compile time, as per the ACPI specification (the AML definition of +Name()). + +iASL: Fixed some code indentation issues for the -ic and -ia options (C +and assembly headers). Now all emitted code correctly begins in column 1. + +iASL: Added an error message for an attempt to open a Scope() on an +object defined in an SSDT. The DSDT is always loaded into the namespace +first, so any attempt to open a Scope on an SSDT object will fail at +runtime. + + +---------------------------------------- +30 September 2015. Summary of changes for version 20150930: + +1) ACPICA kernel-resident subsystem: + +Debugger: Implemented several changes and bug fixes to assist support for +the in-kernel version of the AML debugger. Lv Zheng. +- Fix the "predefined" command for in-kernel debugger. +- Do not enter debug command loop for the help and version commands. +- Disallow "execute" command during execution/single-step of a method. + +Interpreter: Updated runtime typechecking for all operators that have +target operands. The operand is resolved and validated that it is legal. +For example, the target cannot be a non-data object such as a Device, +Mutex, ThermalZone, etc., as per the ACPI specification. + +Debugger: Fixed the double-mutex user I/O handshake to work when local +deadlock detection is enabled. + +Debugger: limited display of method locals and arguments (LocalX and +ArgX) to only those that have actually been initialized. This prevents +lines of extraneous output. + +Updated the definition of the NFIT table to correct the bit polarity of +one flag: ACPI_NFIT_MEM_ARMED --> ACPI_NFIT_MEM_NOT_ARMED + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 101.7K Code, 27.9K Data, 129.6K Total + Debug Version: 199.3K Code, 81.4K Data, 280.7K Total + Previous Release: + Non-Debug Version: 101.3K Code, 27.7K Data, 129.0K Total + Debug Version: 198.6K Code, 80.9K Data, 279.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Improved the compile-time typechecking for operands of many of the +ASL operators: + +-- Added an option to disable compiler operand/operator typechecking (- +ot). + +-- For the following operators, the TermArg operands are now validated +when possible to be Integer data objects: BankField, OperationRegion, +DataTableRegion, Buffer, and Package. + +-- Store (Source, Target): Both the source and target operands are +resolved and checked that the operands are both legal. For example, +neither operand can be a non-data object such as a Device, Mutex, +ThermalZone, etc. Note, as per the ACPI specification, the CopyObject +operator can be used to store an object to any type of target object. + +-- Store (Source, Target): If the source is a Package object, the target +must be a Package object, LocalX, ArgX, or Debug. Likewise, if the target +is a Package, the source must also be a Package. + +-- Store (Source, Target): A warning is issued if the source and target +resolve to the identical named object. + +-- Store (Source, ): An error is generated for the +target method invocation, as this construct is not supported by the AML +interpreter. + +-- For all ASL math and logic operators, the target operand must be a +data object (Integer, String, Buffer, LocalX, ArgX, or Debug). This +includes the function return value also. + +-- External declarations are also included in the typechecking where +possible. External objects defined using the UnknownObj keyword cannot be +typechecked, however. + +iASL and Disassembler: Added symbolic (ASL+) support for the ASL Index +operator: +- Legacy code: Index(PKG1, 3) +- New ASL+ code: PKG1[3] +This completes the ACPI 6.0 ASL+ support as it was the only operator not +supported. + +iASL: Fixed the file suffix for the preprocessor output file (.i). Two +spaces were inadvertently appended to the filename, causing file access +and deletion problems on some systems. + +ASL Test Suite (ASLTS): Updated the master makefile to generate all +possible compiler output files when building the test suite -- thus +exercising these features of the compiler. These files are automatically +deleted when the test suite exits. + + +---------------------------------------- +18 August 2015. Summary of changes for version 20150818: + +1) ACPICA kernel-resident subsystem: + +Fix a regression for AcpiGetTableByIndex interface causing it to fail. Lv +Zheng. ACPICA BZ 1186. + +Completed development to ensure that the ACPICA Disassembler and Debugger +are fully standalone components of ACPICA. Removed cross-component +dependences. Lv Zheng. + +The max-number-of-AML-loops is now runtime configurable (previously was +compile-time only). This is essentially a loop timeout to force-abort +infinite AML loops. ACPCIA BZ 1192. + +Debugger: Cleanup output to dump ACPI names and namepaths without any +trailing underscores. Lv Zheng. ACPICA BZ 1135. + +Removed unnecessary conditional compilations across the Debugger and +Disassembler components where entire modules could be left uncompiled. + +The aapits test is deprecated and has been removed from the ACPICA git +tree. The test has never been completed and has not been maintained, thus +becoming rather useless. ACPICA BZ 1015, 794. + +A batch of small changes to close bugzilla and other reports: +- Remove duplicate code for _PLD processing. ACPICA BZ 1176. +- Correctly cleanup after a ACPI table load failure. ACPICA BZ 1185. +- iASL: Support POSIX yacc again in makefile. Jung-uk Kim. +- ACPI table support: general cleanup and simplification. Lv Zheng, Bob +Moore. +- ACPI table support: fix for a buffer read overrun in AcpiTbFindTable. +ACPICA BZ 1184. +- Enhance parameter validation for DataTableRegion and LoadTable ASL/AML +operators. +- Debugger: Split debugger initialization/termination interfaces. Lv +Zheng. +- AcpiExec: Emit OemTableId for SSDTs during the load phase for table +identification. +- AcpiExec: Add debug message during _REG method phase during table +load/init. +- AcpiNames: Fix a regression where some output was missing and no longer +emitted. +- Debugger: General cleanup and simplification. Lv Zheng. +- Disassembler: Cleanup use of several global option variables. Lv Zheng. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 101.3K Code, 27.7K Data, 129.0K Total + Debug Version: 198.6K Code, 80.9K Data, 279.5K Total + Previous Release: + Non-Debug Version: 100.9K Code, 24.5K Data, 125.4K Total + Debug Version: 197.8K Code, 81.5K Data, 279.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +AcpiExec: Fixed a problem where any more than 32 ACPI tables in the XSDT +were not handled properly and caused load errors. Now, properly invoke +and use the ACPICA auto-reallocate mechanism for ACPI table data +structures. ACPICA BZ 1188 + +AcpiNames: Add command-line wildcard support for ACPI table files. ACPICA +BZ 1190. + +AcpiExec and AcpiNames: Add -l option to load ACPI tables only. For +AcpiExec, this means that no control methods (like _REG/_INI/_STA) are +executed during initialization. ACPICA BZ 1187, 1189. + +iASL/Disassembler: Implemented a prototype "listing" mode that emits AML +that corresponds to each disassembled ASL statement, to simplify +debugging. ACPICA BZ 1191. + +Debugger: Add option to the "objects" command to display a summary of the +current namespace objects (Object type and count). This is displayed if +the command is entered with no arguments. + +AcpiNames: Add -x option to specify debug level, similar to AcpiExec. + + +---------------------------------------- +17 July 2015. Summary of changes for version 20150717: + +1) ACPICA kernel-resident subsystem: + +Improved the partitioning between the Debugger and Disassembler +components. This allows the Debugger to be used standalone within kernel +code without the Disassembler (which is used for single stepping also). +This renames and moves one file, dmobject.c to dbobject.c. Lv Zheng. + +Debugger: Implemented a new command to trace the execution of control +methods (Trace). This is especially useful for the in-kernel version of +the debugger when file I/O may not be available for method trace output. +See the ACPICA reference for more information. Lv Zheng. + +Moved all C library prototypes (used for the local versions of these +functions when requested) to a new header, acclib.h +Cleaned up the use of non-ANSI C library functions. These functions are +implemented locally in ACPICA. Moved all such functions to a common +source file, utnonansi.c + +Debugger: Fixed a problem with the "!!" command (get last command +executed) where the debugger could enter an infinite loop and eventually +crash. + +Removed the use of local macros that were used for some of the standard C +library functions to automatically cast input parameters. This mostly +affected the is* functions where the input parameter is defined to be an +int. This required a few modifications to the main ACPICA source code to +provide casting for these functions and eliminate possible compiler +warnings for these parameters. + +Across the source code, added additional status/error checking to resolve +issues discovered by static source code analysis tools such as Coverity. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 100.9K Code, 24.5K Data, 125.4K Total + Debug Version: 197.8K Code, 81.5K Data, 279.3K Total + Previous Release: + Non-Debug Version: 100.6K Code, 27.6K Data, 128.2K Total + Debug Version: 196.2K Code, 81.0K Data, 277.2K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a regression where the device map file feature no longer +worked properly when used in conjunction with the disassembler. It only +worked properly with the compiler itself. + +iASL: Implemented a new warning for method LocalX variables that are set +but never used (similar to a C compiler such as gcc). This also applies +to ArgX variables that are not defined by the parent method, and are +instead (legally) used as local variables. + +iASL/Preprocessor: Finished the pass-through of line numbers from the +preprocessor to the compiler. This ensures that compiler errors/warnings +have the correct original line numbers and filenames, regardless of any +#include files. + +iASL/Preprocessor: Fixed a couple of issues with comment handling and the +pass-through of comments to the preprocessor output file (which becomes +the compiler input file). Also fixed a problem with // comments that +appear after a math expression. + +iASL: Added support for the TCPA server table to the table compiler and +template generator. (The client table was already previously supported) + +iASL/Preprocessor: Added a permanent #define of the symbol "__IASL__" to +identify the iASL compiler. + +Cleaned up the use of the macros NEGATIVE and POSITIVE which were defined +multiple times. The new names are ACPI_SIGN_NEGATIVE and +ACPI_SIGN_POSITIVE. + +AcpiHelp: Update to expand help messages for the iASL preprocessor +directives. + + +---------------------------------------- +19 June 2015. Summary of changes for version 20150619: + +Two regressions in version 20150616 have been addressed: + +Fixes some problems/issues with the C library macro removal (ACPI_STRLEN, +etc.) This update changes ACPICA to only use the standard headers for +functions, or the prototypes for the local versions of the C library +functions. Across the source code, this required some additional casts +for some Clib invocations for portability. Moved all local prototypes to +a new file, acclib.h + +Fixes several problems with recent changes to the handling of the FACS +table that could cause some systems not to boot. + + +---------------------------------------- +16 June 2015. Summary of changes for version 20150616: + + +1) ACPICA kernel-resident subsystem: + +Across the entire ACPICA source code base, the various macros for the C +library functions (such as ACPI_STRLEN, etc.) have been removed and +replaced by the standard C library names (strlen, etc.) The original +purpose for these macros is no longer applicable. This simplification +reduces the number of macros used in the ACPICA source code +significantly, improving readability and maintainability. + +Implemented support for a new ACPI table, the OSDT. This table, the +"override" SDT, can be loaded directly by the host OS at boot time. It +enables the replacement of existing namespace objects that were installed +via the DSDT and/or SSDTs. The primary purpose for this is to replace +buggy or incorrect ASL/AML code obtained via the BIOS. The OSDT is slated +for inclusion in a future version of the ACPI Specification. Lv Zheng/Bob +Moore. + +Added support for systems with (improperly) two FACS tables -- a "32-bit" +table (via FADT 32-bit legacy field) and a "64-bit" table (via the 64-bit +X field). This change will support both automatically. There continues to +be systems found with this issue. This support requires a change to the +AcpiSetFirmwareWakingVector interface. Also, a public global variable has +been added to allow the host to select which FACS is desired +(AcpiGbl_Use32BitFacsAddresses). See the ACPICA reference for more +details Lv Zheng. + +Added a new feature to allow for systems that do not contain an FACS. +Although this is already supported on hardware-reduced platforms, the +feature has been extended for all platforms. The reasoning is that we do +not want to abort the entire ACPICA initialization just because the +system is seriously buggy and has no FACS. + +Fixed a problem where the GUID strings for NFIT tables (in acuuid.h) were +not correctly transcribed from the ACPI specification in ACPICA version +20150515. + +Implemented support for the _CLS object in the AcpiGetObjectInfo external +interface. + +Updated the definitions of the TCPA and TPM2 ACPI tables to the more +recent TCG ACPI Specification, December 14, 2014. Table disassembler and +compiler also updated. Note: The TCPA "server" table is not supported by +the disassembler/table-compiler at this time. + +ACPI 6.0: Added definitions for the new GIC version field in the MADT. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 100.6K Code, 27.6K Data, 128.2K Total + Debug Version: 196.2K Code, 81.0K Data, 277.2K Total + Previous Release: + Non-Debug Version: 99.9K Code, 27.5K Data, 127.4K Total + Debug Version: 195.2K Code, 80.8K Data, 276.0K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Fixed a problem with the new symbolic operator disassembler +where incorrect ASL code could be emitted in some cases for the "non- +commutative" operators -- Subtract, Divide, Modulo, ShiftLeft, and +ShiftRight. The actual problem cases seem to be rather unusual in common +ASL code, however. David Box. + +Modified the linux version of acpidump to obtain ACPI tables from not +just /dev/mem (which may not exist) and /sys/firmware/acpi/tables. Lv +Zheng. + +iASL: Fixed a problem where the user preprocessor output file (.i) +contained extra data that was not expected. The compiler was using this +file as a temporary file and passed through #line directives in order to +keep compiler error messages in sync with the input file and line number +across multiple include files. The (.i) is no longer a temporary file as +the compiler uses a new, different file for the original purpose. + +iASL: Fixed a problem where comments within the original ASL source code +file were not passed through to the preprocessor output file, nor any +listing files. + +iASL: Fixed some issues for the handling of the "#include" preprocessor +directive and the similar (but not the same) "Include" ASL operator. + +iASL: Add support for the new OSDT in both the disassembler and compiler. + +iASL: Fixed a problem with the constant folding support where a Buffer +object could be incorrectly generated (incorrectly formed) during a +conversion to a Store() operator. + +AcpiHelp: Updated for new NFIT GUIDs, "External" AML opcode, and new +description text for the _REV predefined name. _REV now permanently +returns 2, as per the ACPI 6.0 specification. + +Debugger: Enhanced the output of the Debug ASL object for references +produced by the Index operator. For Buffers and strings, only output the +actual byte pointed to by the index. For packages, only print the single +package element decoded by the index. Previously, the entire +buffer/string/package was emitted. + +iASL/Table-compiler: Fixed a regression where the "generic" data types +were no longer recognized, causing errors. + + +---------------------------------------- +15 May 2015. Summary of changes for version 20150515: + +This release implements most of ACPI 6.0 as described below. + +1) ACPICA kernel-resident subsystem: + +Implemented runtime argument checking and return value checking for all +new ACPI 6.0 predefined names. This includes: _BTH, _CR3, _DSD, _LPI, +_MTL, _PRR, _RDI, _RST, _TFP, _TSN. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 99.9K Code, 27.5K Data, 127.4K Total + Debug Version: 195.2K Code, 80.8K Data, 276.0K Total + Previous Release: + Non-Debug Version: 99.1K Code, 27.3K Data, 126.4K Total + Debug Version: 192.8K Code, 79.9K Data, 272.7K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL compiler: Added compile-time support for all new ACPI 6.0 predefined +names (argument count validation and return value typechecking.) + +iASL disassembler and table compiler: implemented support for all new +ACPI 6.0 tables. This includes: DRTM, IORT, LPIT, NFIT, STAO, WPBT, XENV. + +iASL disassembler and table compiler: Added ACPI 6.0 changes to existing +tables: FADT, MADT. + +iASL preprocessor: Added a new directive to enable inclusion of binary +blobs into ASL code. The new directive is #includebuffer. It takes a +binary file as input and emits a named ascii buffer object into the ASL +code. + +AcpiHelp: Added support for all new ACPI 6.0 predefined names. + +AcpiHelp: Added a new option, -d, to display all iASL preprocessor +directives. + +AcpiHelp: Added a new option, -t, to display all known/supported ACPI +tables. + + +---------------------------------------- +10 April 2015. Summary of changes for version 20150410: + +Reverted a change introduced in version 20150408 that caused +a regression in the disassembler where incorrect operator +symbols could be emitted. + + +---------------------------------------- +08 April 2015. Summary of changes for version 20150408: + + +1) ACPICA kernel-resident subsystem: + +Permanently set the return value for the _REV predefined name. It now +returns 2 (was 5). This matches other ACPI implementations. _REV will be +deprecated in the future, and is now defined to be 1 for ACPI 1.0, and 2 +for ACPI 2.0 and later. It should never be used to differentiate or +identify operating systems. + +Added the "Windows 2015" string to the _OSI support. ACPICA will now +return TRUE to a query with this string. + +Fixed several issues with the local version of the printf function. + +Added the C99 compiler option (-std=c99) to the Unix makefiles. + + Current Release: + Non-Debug Version: 99.9K Code, 27.4K Data, 127.3K Total + Debug Version: 195.2K Code, 80.7K Data, 275.9K Total + Previous Release: + Non-Debug Version: 98.8K Code, 27.3K Data, 126.1K Total + Debug Version: 192.1K Code, 79.8K Data, 271.9K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented an enhancement to the constant folding feature to +transform the parse tree to a simple Store operation whenever possible: + Add (2, 3, X) ==> is converted to: Store (5, X) + X = 2 + 3 ==> is converted to: Store (5, X) + +Updated support for the SLIC table (Software Licensing Description Table) +in both the Data Table compiler and the disassembler. The SLIC table +support now conforms to "Microsoft Software Licensing Tables (SLIC and +MSDM). November 29, 2011. Copyright 2011 Microsoft". Note: Any SLIC data +following the ACPI header is now defined to be "Proprietary Data", and as +such, can only be entered or displayed as a hex data block. + +Implemented full support for the MSDM table as described in the document +above. Note: The format of MSDM is similar to SLIC. Any MSDM data +following the ACPI header is defined to be "Proprietary Data", and can +only be entered or displayed as a hex data block. + +Implemented the -Pn option for the iASL Table Compiler (was only +implemented for the ASL compiler). This option disables the iASL +preprocessor. + +Disassembler: For disassembly of Data Tables, added a comment field +around the Ascii equivalent data that is emitted as part of the "Raw +Table Data" block. This prevents the iASL Preprocessor from possible +confusion if/when the table is compiled. + +Disassembler: Added an option (-df) to force the disassembler to assume +that the table being disassembled contains valid AML. This feature is +useful for disassembling AML files that contain ACPI signatures other +than DSDT or SSDT (such as OEMx or other signatures). + +Changes for the EFI version of the tools: +1) Fixed a build error/issue +2) Fixed a cast warning + +iASL: Fixed a path issue with the __FILE__ operator by making the +directory prefix optional within the internal SplitInputFilename +function. + +Debugger: Removed some unused global variables. + +Tests: Updated the makefile for proper generation of the AAPITS suite. + + +---------------------------------------- +04 February 2015. Summary of changes for version 20150204: + +ACPICA kernel-resident subsystem: + +Updated all ACPICA copyrights and signons to 2014. Added the 2014 +copyright to all module headers and signons, including the standard Linux +header. This affects virtually every file in the ACPICA core subsystem, +iASL compiler, all ACPICA utilities, and the test suites. + +Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix GPE storm issues. +A raw gpe handling mechanism was created to allow better handling of GPE +storms that aren't easily managed by the normal handler. The raw handler +allows disabling/renabling of the the GPE so that interrupt storms can be +avoided in cases where events cannot be timely serviced. In this +scenario, handlers should use the AcpiSetGpe() API to disable/enable the +GPE. This API will leave the reference counts undisturbed, thereby +preventing unintentional clearing of the GPE when the intent in only to +temporarily disable it. Raw handlers allow enabling and disabling of a +GPE by removing GPE register locking. As such, raw handlers much provide +their own locks while using GPE API's to protect access to GPE data +structures. +Lv Zheng + +Events: Always modify GPE registers under the GPE lock. +Applies GPE lock around AcpiFinishGpe() to protect access to GPE register +values. Reported as bug by joe.liu@apple.com. + +Unix makefiles: Separate option to disable optimizations and +_FORTIFY_SOURCE. This change removes the _FORTIFY_SOURCE flag from the +NOOPT disable option and creates a separate flag (NOFORTIFY) for this +purpose. Some toolchains may define _FORTIFY_SOURCE which leads redefined +errors when building ACPICA. This allows disabling the option without +also having to disable optimazations. +David Box + + Current Release: + Non-Debug Version: 101.7K Code, 27.9K Data, 129.6K Total + Debug Version: 199.2K Code, 82.4K Data, 281.6K Total + +-- +-------------------------------------- +07 November 2014. Summary of changes for version 20141107: + +This release is available at https://acpica.org/downloads + +This release introduces and implements language extensions to ASL that +provide support for symbolic ("C-style") operators and expressions. These +language extensions are known collectively as ASL+. + + +1) iASL Compiler/Disassembler and Tools: + +Disassembler: Fixed a problem with disassembly of the UartSerialBus +macro. Changed "StopBitsNone" to the correct "StopBitsZero". David E. +Box. + +Disassembler: Fixed the Unicode macro support to add escape sequences. +All non-printable ASCII values are emitted as escape sequences, as well +as the standard escapes for quote and backslash. Ensures that the +disassembled macro can be correctly recompiled. + +iASL: Added Printf/Fprintf macros for formatted output. These macros are +translated to existing AML Concatenate and Store operations. Printf +writes to the ASL Debug object. Fprintf allows the specification of an +ASL name as the target. Only a single format specifier is required, %o, +since the AML interpreter dynamically converts objects to the required +type. David E. Box. + + (old) Store (Concatenate (Concatenate (Concatenate (Concatenate + (Concatenate (Concatenate (Concatenate ("", Arg0), + ": Unexpected value for "), Arg1), ", "), Arg2), + " at line "), Arg3), Debug) + + (new) Printf ("%o: Unexpected value for %o, %o at line %o", + Arg0, Arg1, Arg2, Arg3) + + (old) Store (Concatenate (Concatenate (Concatenate (Concatenate + ("", Arg1), ": "), Arg0), " Successful"), STR1) + + (new) Fprintf (STR1, "%o: %o Successful", Arg1, Arg0) + +iASL: Added debug options (-bp, -bt) to dynamically prune levels of the +ASL parse tree before the AML code is generated. This allows blocks of +ASL code to be removed in order to help locate and identify problem +devices and/or code. David E. Box. + +AcpiExec: Added support (-fi) for an optional namespace object +initialization file. This file specifies initial values for namespace +objects as necessary for debugging and testing different ASL code paths +that may be taken as a result of BIOS options. + + +2) Overview of symbolic operator support for ASL (ASL+) +------------------------------------------------------- + +As an extension to the ASL language, iASL implements support for symbolic +(C-style) operators for math and logical expressions. This can greatly +simplify ASL code as well as improve both readability and +maintainability. These language extensions can exist concurrently with +all legacy ASL code and expressions. + +The symbolic extensions are 100% compatible with existing AML +interpreters, since no new AML opcodes are created. To implement the +extensions, the iASL compiler transforms the symbolic expressions into +the legacy ASL/AML equivalents at compile time. + +Full symbolic expressions are supported, along with the standard C +precedence and associativity rules. + +Full disassembler support for the symbolic expressions is provided, and +creates an automatic migration path for existing ASL code to ASL+ code +via the disassembly process. By default, the disassembler now emits ASL+ +code with symbolic expressions. An option (-dl) is provided to force the +disassembler to emit legacy ASL code if desired. + +Below is the complete list of the currently supported symbolic operators +with examples. See the iASL User Guide for additional information. + + +ASL+ Syntax Legacy ASL Equivalent +----------- --------------------- + + // Math operators + +Z = X + Y Add (X, Y, Z) +Z = X - Y Subtract (X, Y, Z) +Z = X * Y Multiply (X, Y, Z) +Z = X / Y Divide (X, Y, , Z) +Z = X % Y Mod (X, Y, Z) +Z = X << Y ShiftLeft (X, Y, Z) +Z = X >> Y ShiftRight (X, Y, Z) +Z = X & Y And (X, Y, Z) +Z = X | Y Or (X, Y, Z) +Z = X ^ Y Xor (X, Y, Z) +Z = ~X Not (X, Z) +X++ Increment (X) +X-- Decrement (X) + + // Logical operators + +(X == Y) LEqual (X, Y) +(X != Y) LNotEqual (X, Y) +(X < Y) LLess (X, Y) +(X > Y) LGreater (X, Y) +(X <= Y) LLessEqual (X, Y) +(X >= Y) LGreaterEqual (X, Y) +(X && Y) LAnd (X, Y) +(X || Y) LOr (X, Y) +(!X) LNot (X) + + // Assignment and compound assignment operations + +X = Y Store (Y, X) +X += Y Add (X, Y, X) +X -= Y Subtract (X, Y, X) +X *= Y Multiply (X, Y, X) +X /= Y Divide (X, Y, , X) +X %= Y Mod (X, Y, X) +X <<= Y ShiftLeft (X, Y, X) +X >>= Y ShiftRight (X, Y, X) +X &= Y And (X, Y, X) +X |= Y Or (X, Y, X) +X ^= Y Xor (X, Y, X) + + +3) ASL+ Examples: +----------------- + +Legacy ASL: + If (LOr (LOr (LEqual (And (R510, 0x03FB), 0x02E0), LEqual ( + And (R520, 0x03FB), 0x02E0)), LOr (LEqual (And (R530, +0x03FB), + 0x02E0), LEqual (And (R540, 0x03FB), 0x02E0)))) + { + And (MEMB, 0xFFFFFFF0, SRMB) + Store (MEMB, Local2) + Store (PDBM, Local1) + And (PDBM, 0xFFFFFFFFFFFFFFF9, PDBM) + Store (SRMB, MEMB) + Or (PDBM, 0x02, PDBM) + } + +ASL+ version: + If (((R510 & 0x03FB) == 0x02E0) || + ((R520 & 0x03FB) == 0x02E0) || + ((R530 & 0x03FB) == 0x02E0) || + ((R540 & 0x03FB) == 0x02E0)) + { + SRMB = (MEMB & 0xFFFFFFF0) + Local2 = MEMB + Local1 = PDBM + PDBM &= 0xFFFFFFFFFFFFFFF9 + MEMB = SRMB + PDBM |= 0x02 + } + +Legacy ASL: + Store (0x1234, Local1) + Multiply (Add (Add (Local1, TEST), 0x20), Local2, Local3) + Multiply (Local2, Add (Add (Local1, TEST), 0x20), Local3) + Add (Local1, Add (TEST, Multiply (0x20, Local2)), Local3) + Store (Index (PKG1, 0x03), Local6) + Store (Add (Local3, Local2), Debug) + Add (Local1, 0x0F, Local2) + Add (Local1, Multiply (Local2, Local3), Local2) + Multiply (Add (Add (Local1, TEST), 0x20), ToBCD (Local1), Local3) + +ASL+ version: + Local1 = 0x1234 + Local3 = (((Local1 + TEST) + 0x20) * Local2) + Local3 = (Local2 * ((Local1 + TEST) + 0x20)) + Local3 = (Local1 + (TEST + (0x20 * Local2))) + Local6 = Index (PKG1, 0x03) + Debug = (Local3 + Local2) + Local2 = (Local1 + 0x0F) + Local2 = (Local1 + (Local2 * Local3)) + Local3 = (((Local1 + TEST) + 0x20) * ToBCD (Local1)) + + +---------------------------------------- +26 September 2014. Summary of changes for version 20140926: + +1) ACPICA kernel-resident subsystem: + +Updated the GPIO operation region handler interface (GeneralPurposeIo). +In order to support GPIO Connection objects with multiple pins, along +with the related Field objects, the following changes to the interface +have been made: The Address is now defined to be the offset in bits of +the field unit from the previous invocation of a Connection. It can be +viewed as a "Pin Number Index" into the connection resource descriptor. +The BitWidth is the exact bit width of the field. It is usually one bit, +but not always. See the ACPICA reference guide (section 8.8.6.2.1) for +additional information and examples. + +GPE support: During ACPICA/GPE initialization, ensure that all GPEs with +corresponding _Lxx/_Exx methods are disabled (they may have been enabled +by the firmware), so that they cannot fire until they are enabled via +AcpiUpdateAllGpes. Rafael J. Wysocki. + +Added a new return flag for the Event/GPE status interfaces -- +AcpiGetEventStatus and AcpiGetGpeStatus. The new +ACPI_EVENT_FLAGS_HAS_HANDLER flag is used to indicate that the event or +GPE currently has a handler associated with it, and can thus actually +affect the system. Lv Zheng. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 99.1K Code, 27.3K Data, 126.4K Total + Debug Version: 192.8K Code, 79.9K Data, 272.7K Total + Previous Release: + Non-Debug Version: 98.8K Code, 27.3K Data, 126.1K Total + Debug Version: 192.1K Code, 79.8K Data, 271.9K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a memory allocation/free regression introduced in 20140828 +that could cause the compiler to crash. This was introduced inadvertently +during the effort to eliminate compiler memory leaks. ACPICA BZ 1111, +1113. + +iASL: Removed two error messages that have been found to create false +positives, until they can be fixed and fully validated (ACPICA BZ 1112): +1) Illegal forward reference within a method +2) Illegal reference across two methods + +iASL: Implemented a new option (-lm) to create a hardware mapping file +that summarizes all GPIO, I2C, SPI, and UART connections. This option +works for both the compiler and disassembler. See the iASL compiler user +guide for additional information and examples (section 6.4.6). + +AcpiDump: Added support for the version 1 (ACPI 1.0) RSDP in addition to +version 2. This corrects the AE_BAD_HEADER exception seen on systems with +a version 1 RSDP. Lv Zheng ACPICA BZ 1097. + +AcpiExec: For Unix versions, don't attempt to put STDIN into raw mode +unless STDIN is actually a terminal. Assists with batch-mode processing. +ACPICA BZ 1114. + +Disassembler/AcpiHelp: Added another large group of recognized _HID +values. + + +---------------------------------------- +28 August 2014. Summary of changes for version 20140828: + +1) ACPICA kernel-resident subsystem: + +Fixed a problem related to the internal use of the Timer() operator where +a 64-bit divide could cause an attempted link to a double-precision math +library. This divide is not actually necessary, so the code was +restructured to eliminate it. Lv Zheng. + +ACPI 5.1: Added support for the runtime validation of the _DSD package +(similar to the iASL support). + +ACPI 5.1/Headers: Added support for the GICC affinity subtable to the +SRAT table. Hanjun Guo . + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 98.8K Code, 27.3K Data, 126.1K Total + Debug Version: 192.1K Code, 79.8K Data, 271.9K Total + Previous Release: + Non-Debug Version: 98.7K Code, 27.3K Data, 126.0K Total1 + Debug Version: 192.0K Code, 79.7K Data, 271.7K Total + +2) iASL Compiler/Disassembler and Tools: + +AcpiExec: Fixed a problem on unix systems where the original terminal +state was not always properly restored upon exit. Seen when using the -v +option. ACPICA BZ 1104. + +iASL: Fixed a problem with the validation of the ranges/length within the +Memory24 resource descriptor. There was a boundary condition when the +range was equal to the (length -1) caused by the fact that these values +are defined in 256-byte blocks, not bytes. ACPICA BZ 1098 + +Disassembler: Fixed a problem with the GpioInt descriptor interrupt +polarity +flags. The flags are actually 2 bits, not 1, and the "ActiveBoth" keyword +is +now supported properly. + +ACPI 5.1: Added the GICC affinity subtable to the SRAT table. Supported +in the disassembler, data table compiler, and table template generator. + +iASL: Added a requirement for Device() objects that one of either a _HID +or _ADR must exist within the scope of a Device, as per the ACPI +specification. Remove a similar requirement that was incorrectly in place +for the _DSD object. + +iASL: Added error detection for illegal named references within control +methods that would cause runtime failures. Now trapped as errors are: 1) +References to objects within a non-parent control method. 2) Forward +references (within a method) -- for control methods, AML interpreters use +a one-pass parse of control methods. ACPICA BZ 1008. + +iASL: Added error checking for dependencies related to the _PSx power +methods. ACPICA BZ 1029. +1) For _PS0, one of these must exist within the same scope: _PS1, _PS2, +_PS3. +2) For _PS1, _PS2, and PS3: A _PS0 object must exist within the same +scope. + +iASL and table compiler: Cleanup miscellaneous memory leaks by fully +deploying the existing object and string caches and adding new caches for +the table compiler. + +iASL: Split the huge parser source file into multiple subfiles to improve +manageability. Generation now requires the M4 macro preprocessor, which +is part of the Bison distribution on both unix and windows platforms. + +AcpiSrc: Fixed and removed all extraneous warnings generated during +entire ACPICA source code scan and/or conversion. + + +---------------------------------------- + +24 July 2014. Summary of changes for version 20140724: + +The ACPI 5.1 specification has been released and is available at: +http://uefi.org/specs/access + + +0) ACPI 5.1 support in ACPICA: + +ACPI 5.1 is fully supported in ACPICA as of this release. + +New predefined names. Support includes iASL and runtime ACPICA +validation. + _CCA (Cache Coherency Attribute). + _DSD (Device-Specific Data). David Box. + +Modifications to existing ACPI tables. Support includes headers, iASL +Data Table compiler, disassembler, and the template generator. + FADT - New fields and flags. Graeme Gregory. + GTDT - One new subtable and new fields. Tomasz Nowicki. + MADT - Two new subtables. Tomasz Nowicki. + PCCT - One new subtable. + +Miscellaneous. + New notification type for System Resource Affinity change events. + + +1) ACPICA kernel-resident subsystem: + +Fixed a regression introduced in 20140627 where a fault can happen during +the deletion of Alias AML namespace objects. The problem affected both +the core ACPICA and the ACPICA tools including iASL and AcpiExec. + +Implemented a new GPE public interface, AcpiMarkGpeForWake. Provides a +simple mechanism to enable wake GPEs that have no associated handler or +control method. Rafael Wysocki. + +Updated the AcpiEnableGpe interface to disallow the enable if there is no +handler or control method associated with the particular GPE. This will +help avoid meaningless GPEs and even GPE floods. Rafael Wysocki. + +Updated GPE handling and dispatch by disabling the GPE before clearing +the status bit for edge-triggered GPEs. Lv Zheng. + +Added Timer() support to the AML Debug object. The current timer value is +now displayed with each invocation of (Store to) the debug object to +enable simple generation of execution times for AML code (method +execution for example.) ACPICA BZ 1093. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 98.7K Code, 27.3K Data, 126.0K Total + Debug Version: 192.0K Code, 79.7K Data, 271.7K Total + Previous Release: + Non-Debug Version: 98.7K Code, 27.2K Data, 125.9K Total + Debug Version: 191.7K Code, 79.6K Data, 271.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed an issue with the recently added local printf implementation, +concerning width/precision specifiers that could cause incorrect output. +Lv Zheng. ACPICA BZ 1094. + +Disassembler: Added support to detect buffers that contain UUIDs and +disassemble them to an invocation of the ToUUID operator. Also emit +commented descriptions of known ACPI-related UUIDs. + +AcpiHelp: Added support to display known ACPI-related UUIDs. New option, +-u. Adds three new files. + +iASL: Update table compiler and disassembler for DMAR table changes that +were introduced in September 2013. With assistance by David Woodhouse. + +---------------------------------------- +27 June 2014. Summary of changes for version 20140627: + +1) ACPICA kernel-resident subsystem: + +Formatted Output: Implemented local versions of standard formatted output +utilities such as printf, etc. Over time, it has been discovered that +there are in fact many portability issues with printf, and the addition +of this feature will fix/prevent these issues once and for all. Some +known issues are summarized below: + +1) Output of 64-bit values is not portable. For example, UINT64 is %ull +for the Linux kernel and is %uI64 for some MSVC versions. +2) Invoking printf consistently in a manner that is portable across both +32-bit and 64-bit platforms is difficult at best in many situations. +3) The output format for pointers varies from system to system (leading +zeros especially), and leads to inconsistent output from ACPICA across +platforms. +4) Certain platform-specific printf formats may conflict with ACPICA use. +5) If there is no local C library available, ACPICA now has local support +for printf. + +-- To address these printf issues in a complete manner, ACPICA now +directly implements a small subset of printf format specifiers, only +those that it requires. Adds a new file, utilities/utprint.c. Lv Zheng. + +Implemented support for ACPICA generation within the EFI environment. +Initially, the AcpiDump utility is supported in the UEFI shell +environment. Lv Zheng. + +Added a new external interface, AcpiLogError, to improve ACPICA +portability. This allows the host to redirect error messages from the +ACPICA utilities. Lv Zheng. + +Added and deployed new OSL file I/O interfaces to improve ACPICA +portability: + AcpiOsOpenFile + AcpiOsCloseFile + AcpiOsReadFile + AcpiOsWriteFile + AcpiOsGetFileOffset + AcpiOsSetFileOffset +There are C library implementations of these functions in the new file +service_layers/oslibcfs.c -- however, the functions can be implemented by +the local host in any way necessary. Lv Zheng. + +Implemented a mechanism to disable/enable ACPI table checksum validation +at runtime. This can be useful when loading tables very early during OS +initialization when it may not be possible to map the entire table in +order to compute the checksum. Lv Zheng. + +Fixed a buffer allocation issue for the Generic Serial Bus support. +Originally, a fixed buffer length was used. This change allows for +variable-length buffers based upon the protocol indicated by the field +access attributes. Reported by Lan Tianyu. Lv Zheng. + +Fixed a problem where an object detached from a namespace node was not +properly terminated/cleared and could cause a circular list problem if +reattached. ACPICA BZ 1063. David Box. + +Fixed a possible recursive lock acquisition in hwregs.c. Rakib Mullick. + +Fixed a possible memory leak in an error return path within the function +AcpiUtCopyIobjectToIobject. ACPICA BZ 1087. Colin Ian King. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 98.7K Code, 27.2K Data, 125.9K Total + Debug Version: 191.7K Code, 79.6K Data, 271.3K Total + Previous Release: + Non-Debug Version: 96.8K Code, 27.2K Data, 124.0K Total + Debug Version: 189.5K Code, 79.7K Data, 269.2K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Add dump of ASCII equivalent text within a comment at the +end of each line of the output for the Buffer() ASL operator. + +AcpiDump: Miscellaneous changes: + Fixed repetitive table dump in -n mode. + For older EFI platforms, use the ACPI 1.0 GUID during RSDP search if +the ACPI 2.0 GUID fails. + +iASL: Fixed a problem where the compiler could fault if incorrectly given +an acpidump output file as input. ACPICA BZ 1088. David Box. + +AcpiExec/AcpiNames: Fixed a problem where these utilities could fault if +they are invoked without any arguments. + +Debugger: Fixed a possible memory leak in an error return path. ACPICA BZ +1086. Colin Ian King. + +Disassembler: Cleaned up a block of code that extracts a parent Op +object. Added a comment that explains that the parent is guaranteed to be +valid in this case. ACPICA BZ 1069. + + +---------------------------------------- +24 April 2014. Summary of changes for version 20140424: + +1) ACPICA kernel-resident subsystem: + +Implemented support to skip/ignore NULL address entries in the RSDT/XSDT. +Some of these tables are known to contain a trailing NULL entry. Lv +Zheng. + +Removed an extraneous error message for the case where there are a large +number of system GPEs (> 124). This was the "32-bit FADT register is too +long to convert to GAS struct" message, which is irrelevant for GPEs +since the GPEx_BLK_LEN fields of the FADT are always used instead of the +(limited capacity) GAS bit length. Also, several changes to ensure proper +support for GPE numbers > 255, where some "GPE number" fields were 8-bits +internally. + +Implemented and deployed additional configuration support for the public +ACPICA external interfaces. Entire classes of interfaces can now be +easily modified or configured out, replaced by stubbed inline functions +by default. Lv Zheng. + +Moved all public ACPICA runtime configuration globals to the public +ACPICA external interface file for convenience. Also, removed some +obsolete/unused globals. See the file acpixf.h. Lv Zheng. + +Documentation: Added a new section to the ACPICA reference describing the +maximum number of GPEs that can be supported by the FADT-defined GPEs in +block zero and one. About 1200 total. See section 4.4.1 of the ACPICA +reference. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.8K Code, 27.2K Data, 124.0K Total + Debug Version: 189.5K Code, 79.7K Data, 269.2K Total + Previous Release: + Non-Debug Version: 97.0K Code, 27.2K Data, 124.2K Total + Debug Version: 189.7K Code, 79.5K Data, 269.2K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL and disassembler: Add full support for the LPIT table (Low Power +Idle Table). Includes support in the disassembler, data table compiler, +and template generator. + +AcpiDump utility: +1) Add option to force the use of the RSDT (over the XSDT). +2) Improve validation of the RSDP signature (use 8 chars instead of 4). + +iASL: Add check for predefined packages that are too large. For +predefined names that contain subpackages, check if each subpackage is +too large. (Check for too small already exists.) + +Debugger: Updated the GPE command (which simulates a GPE by executing the +GPE code paths in ACPICA). The GPE device is now optional, and defaults +to the GPE 0/1 FADT-defined blocks. + +Unix application OSL: Update line-editing support. Add additional error +checking and take care not to reset terminal attributes on exit if they +were never set. This should help guarantee that the terminal is always +left in the previous state on program exit. + + +---------------------------------------- +25 March 2014. Summary of changes for version 20140325: + +1) ACPICA kernel-resident subsystem: + +Updated the auto-serialize feature for control methods. This feature +automatically serializes all methods that create named objects in order +to prevent runtime errors. The update adds support to ignore the +currently executing AML SyncLevel when invoking such a method, in order +to prevent disruption of any existing SyncLevel priorities that may exist +in the AML code. Although the use of SyncLevels is relatively rare, this +change fixes a regression where an AE_AML_MUTEX_ORDER exception can +appear on some machines starting with the 20140214 release. + +Added a new external interface to allow the host to install ACPI tables +very early, before the namespace is even created. AcpiInstallTable gives +the host additional flexibility for ACPI table management. Tables can be +installed directly by the host as if they had originally appeared in the +XSDT/RSDT. Installed tables can be SSDTs or other ACPI data tables +(anything except the DSDT and FACS). Adds a new file, tbdata.c, along +with additional internal restructuring and cleanup. See the ACPICA +Reference for interface details. Lv Zheng. + +Added validation of the checksum for all incoming dynamically loaded +tables (via external interfaces or via AML Load/LoadTable operators). Lv +Zheng. + +Updated the use of the AcpiOsWaitEventsComplete interface during Notify +and GPE handler removal. Restructured calls to eliminate possible race +conditions. Lv Zheng. + +Added a warning for the use/execution of the ASL/AML Unload (table) +operator. This will help detect and identify machines that use this +operator if and when it is ever used. This operator has never been seen +in the field and the usage model and possible side-effects of the drastic +runtime action of a full table removal are unknown. + +Reverted the use of #pragma push/pop which was introduced in the 20140214 +release. It appears that push and pop are not implemented by enough +compilers to make the use of this feature feasible for ACPICA at this +time. However, these operators may be deployed in a future ACPICA +release. + +Added the missing EXPORT_SYMBOL macros for the install and remove SCI +handler interfaces. + +Source code generation: +1) Disabled the use of the "strchr" macro for the gcc-specific +generation. For some versions of gcc, this macro can periodically expose +a compiler bug which in turn causes compile-time error(s). +2) Added support for PPC64 compilation. Colin Ian King. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 97.0K Code, 27.2K Data, 124.2K Total + Debug Version: 189.7K Code, 79.5K Data, 269.2K Total + Previous Release: + Non-Debug Version: 96.5K Code, 27.2K Data, 123.7K Total + Debug Version: 188.6K Code, 79.0K Data, 267.6K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Added several new features to improve the readability of +the resulting ASL code. Extra information is emitted within comment +fields in the ASL code: +1) Known _HID/_CID values are decoded to descriptive text. +2) Standard values for the Notify() operator are decoded to descriptive +text. +3) Target operands are expanded to full pathnames (in a comment) when +possible. + +Disassembler: Miscellaneous updates for extern() handling: +1) Abort compiler if file specified by -fe option does not exist. +2) Silence unnecessary warnings about argument count mismatches. +3) Update warning messages concerning unresolved method externals. +4) Emit "UnknownObj" keyword for externals whose type cannot be +determined. + +AcpiHelp utility: +1) Added the -a option to display both the ASL syntax and the AML +encoding for an input ASL operator. This effectively displays all known +information about an ASL operator with one AcpiHelp invocation. +2) Added substring match support (similar to a wildcard) for the -i +(_HID/PNP IDs) option. + +iASL/Disassembler: Since this tool does not yet support execution on big- +endian machines, added detection of endianness and an error message if +execution is attempted on big-endian. Support for big-endian within iASL +is a feature that is on the ACPICA to-be-done list. + +AcpiBin utility: +1) Remove option to extract binary files from an acpidump; this function +is made obsolete by the AcpiXtract utility. +2) General cleanup of open files and allocated buffers. + + +---------------------------------------- +14 February 2014. Summary of changes for version 20140214: + +1) ACPICA kernel-resident subsystem: + +Implemented a new mechanism to proactively prevent problems with ill- +behaved reentrant control methods that create named ACPI objects. This +behavior is illegal as per the ACPI specification, but is nonetheless +frequently seen in the field. Previously, this could lead to an +AE_ALREADY_EXISTS exception if the method was actually entered by more +than one thread. This new mechanism detects such methods at table load +time and marks them "serialized" to prevent reentrancy. A new global +option, AcpiGbl_AutoSerializeMethods, has been added to disable this +feature if desired. This mechanism and global option obsoletes and +supersedes the previous AcpiGbl_SerializeAllMethods option. + +Added the "Windows 2013" string to the _OSI support. ACPICA will now +respond TRUE to _OSI queries with this string. It is the stated policy of +ACPICA to add new strings to the _OSI support as soon as possible after +they are defined. See the full ACPICA _OSI policy which has been added to +the utilities/utosi.c file. + +Hardened/updated the _PRT return value auto-repair code: +1) Do not abort the repair on a single subpackage failure, continue to +check all subpackages. +2) Add check for the minimum subpackage length (4). +3) Properly handle extraneous NULL package elements. + +Added support to avoid the possibility of infinite loops when traversing +object linked lists. Never allow an infinite loop, even in the face of +corrupted object lists. + +ACPICA headers: Deployed the use of #pragma pack(push) and #pragma +pack(pop) directives to ensure that the ACPICA headers are independent of +compiler settings or other host headers. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.5K Code, 27.2K Data, 123.7K Total + Debug Version: 188.6K Code, 79.0K Data, 267.6K Total + Previous Release: + Non-Debug Version: 96.2K Code, 27.0K Data, 123.2K Total + Debug Version: 187.5K Code, 78.3K Data, 265.8K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL/Table-compiler: Fixed a problem with support for the SPMI table. The +first reserved field was incorrectly forced to have a value of zero. This +change correctly forces the field to have a value of one. ACPICA BZ 1081. + +Debugger: Added missing support for the "Extra" and "Data" subobjects +when displaying object data. + +Debugger: Added support to display entire object linked lists when +displaying object data. + +iASL: Removed the obsolete -g option to obtain ACPI tables from the +Windows registry. This feature has been superseded by the acpidump +utility. + + +---------------------------------------- +14 January 2014. Summary of changes for version 20140114: + +1) ACPICA kernel-resident subsystem: + +Updated all ACPICA copyrights and signons to 2014. Added the 2014 +copyright to all module headers and signons, including the standard Linux +header. This affects virtually every file in the ACPICA core subsystem, +iASL compiler, all ACPICA utilities, and the test suites. + +Improved parameter validation for AcpiInstallGpeBlock. Added the +following checks: +1) The incoming device handle refers to type ACPI_TYPE_DEVICE. +2) There is not already a GPE block attached to the device. +Likewise, with AcpiRemoveGpeBlock, ensure that the incoming object is a +device. + +Correctly support "references" in the ACPI_OBJECT. This change fixes the +support to allow references (namespace nodes) to be passed as arguments +to control methods via the evaluate object interface. This is probably +most useful for testing purposes, however. + +Improved support for 32/64 bit physical addresses in printf()-like +output. This change improves the support for physical addresses in printf +debug statements and other output on both 32-bit and 64-bit hosts. It +consistently outputs the appropriate number of bytes for each host. The +%p specifier is unsatisfactory since it does not emit uniform output on +all hosts/clib implementations (on some, leading zeros are not supported, +leading to difficult-to-read output). + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.2K Code, 27.0K Data, 123.2K Total + Debug Version: 187.5K Code, 78.3K Data, 265.8K Total + Previous Release: + Non-Debug Version: 96.1K Code, 27.0K Data, 123.1K Total + Debug Version: 185.6K Code, 77.3K Data, 262.9K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fix a possible fault when using the Connection() operator. Fixes a +problem if the parent Field definition for the Connection operator refers +to an operation region that does not exist. ACPICA BZ 1064. + +AcpiExec: Load of local test tables is now optional. The utility has the +capability to load some various tables to test features of ACPICA. +However, there are enough of them that the output of the utility became +confusing. With this change, only the required local tables are displayed +(RSDP, XSDT, etc.) along with the actual tables loaded via the command +line specification. This makes the default output simler and easier to +understand. The -el command line option restores the original behavior +for testing purposes. + +AcpiExec: Added support for overlapping operation regions. This change +expands the simulation of operation regions by supporting regions that +overlap within the given address space. Supports SystemMemory and +SystemIO. ASLTS test suite updated also. David Box. ACPICA BZ 1031. + +AcpiExec: Added region handler support for PCI_Config and EC spaces. This +allows AcpiExec to simulate these address spaces, similar to the current +support for SystemMemory and SystemIO. + +Debugger: Added new command to read/write/compare all namespace objects. +The command "test objects" will exercise the entire namespace by writing +new values to each data object, and ensuring that the write was +successful. The original value is then restored and verified. + +Debugger: Added the "test predefined" command. This change makes this +test public and puts it under the new "test" command. The test executes +each and every predefined name within the current namespace. + + +---------------------------------------- +18 December 2013. Summary of changes for version 20131218: + +Global note: The ACPI 5.0A specification was released this month. There +are no changes needed for ACPICA since this release of ACPI is an +errata/clarification release. The specification is available at +acpi.info. + + +1) ACPICA kernel-resident subsystem: + +Added validation of the XSDT root table if it is present. Some older +platforms contain an XSDT that is ill-formed or otherwise invalid (such +as containing some or all entries that are NULL pointers). This change +adds a new function to validate the XSDT before actually using it. If the +XSDT is found to be invalid, ACPICA will now automatically fall back to +using the RSDT instead. Original implementation by Zhao Yakui. Ported to +ACPICA and enhanced by Lv Zheng and Bob Moore. + +Added a runtime option to ignore the XSDT and force the use of the RSDT. +This change adds a runtime option that will force ACPICA to use the RSDT +instead of the XSDT (AcpiGbl_DoNotUseXsdt). Although the ACPI spec +requires that an XSDT be used instead of the RSDT, the XSDT has been +found to be corrupt or ill-formed on some machines. Lv Zheng. + +Added a runtime option to favor 32-bit FADT register addresses over the +64-bit addresses. This change adds an option to favor 32-bit FADT +addresses when there is a conflict between the 32-bit and 64-bit versions +of the same register. The default behavior is to use the 64-bit version +in accordance with the ACPI specification. This can now be overridden via +the AcpiGbl_Use32BitFadtAddresses flag. ACPICA BZ 885. Lv Zheng. + +During the change above, the internal "Convert FADT" and "Verify FADT" +functions have been merged to simplify the code, making it easier to +understand and maintain. ACPICA BZ 933. + +Improve exception reporting and handling for GPE block installation. +Return an actual status from AcpiEvGetGpeXruptBlock and don't clobber the +status when exiting AcpiEvInstallGpeBlock. ACPICA BZ 1019. + +Added helper macros to extract bus/segment numbers from the HEST table. +This change adds two macros to extract the encoded bus and segment +numbers from the HEST Bus field - ACPI_HEST_BUS and ACPI_HEST_SEGMENT. +Betty Dall + +Removed the unused ACPI_FREE_BUFFER macro. This macro is no longer used +by ACPICA. It is not a public macro, so it should have no effect on +existing OSV code. Lv Zheng. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.1K Code, 27.0K Data, 123.1K Total + Debug Version: 185.6K Code, 77.3K Data, 262.9K Total + Previous Release: + Non-Debug Version: 95.9K Code, 27.0K Data, 122.9K Total + Debug Version: 185.1K Code, 77.2K Data, 262.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Improved pathname support for emitted External() +statements. This change adds full pathname support for external names +that have been resolved internally by the inclusion of additional ACPI +tables (via the iASL -e option). Without this change, the disassembler +can emit multiple externals for the same object, or it become confused +when the Scope() operator is used on an external object. Overall, greatly +improves the ability to actually recompile the emitted ASL code when +objects a referenced across multiple ACPI tables. Reported by Michael +Tsirkin (mst@redhat.com). + +Tests/ASLTS: Updated functional control suite to execute with no errors. +David Box. Fixed several errors related to the testing of the interpreter +slack mode. Lv Zheng. + +iASL: Added support to detect names that are declared within a control +method, but are unused (these are temporary names that are only valid +during the time the method is executing). A remark is issued for these +cases. ACPICA BZ 1022. + +iASL: Added full support for the DBG2 table. Adds full disassembler, +table compiler, and template generator support for the DBG2 table (Debug +Port 2 table). + +iASL: Added full support for the PCCT table, update the table definition. +Updates the PCCT table definition in the actbl3.h header and adds table +compiler and template generator support. + +iASL: Added an option to emit only error messages (no warnings/remarks). +The -ve option will enable only error messages, warnings and remarks are +suppressed. This can simplify debugging when only the errors are +important, such as when an ACPI table is disassembled and there are many +warnings and remarks -- but only the actual errors are of real interest. + +Example ACPICA code (source/tools/examples): Updated the example code so +that it builds to an actual working program, not just example code. Added +ACPI tables and execution of an example control method in the DSDT. Added +makefile support for Unix generation. + + +---------------------------------------- +15 November 2013. Summary of changes for version 20131115: + +This release is available at https://acpica.org/downloads + + +1) ACPICA kernel-resident subsystem: + +Resource Manager: Fixed loop termination for the "get AML length" +function. The loop previously had an error termination on a NULL resource +pointer, which can never happen since the loop simply increments a valid +resource pointer. This fix changes the loop to terminate with an error on +an invalid end-of-buffer condition. The problem can be seen as an +infinite loop by callers to AcpiSetCurrentResources with an invalid or +corrupted resource descriptor, or a resource descriptor that is missing +an END_TAG descriptor. Reported by Dan Carpenter +. Lv Zheng, Bob Moore. + +Table unload and ACPICA termination: Delete all attached data objects +during namespace node deletion. This fix updates namespace node deletion +to delete the entire list of attached objects (attached via +AcpiAttachObject) instead of just one of the attached items. ACPICA BZ +1024. Tomasz Nowicki (tomasz.nowicki@linaro.org). + +ACPICA termination: Added support to delete all objects attached to the +root namespace node. This fix deletes any and all objects that have been +attached to the root node via AcpiAttachData. Previously, none of these +objects were deleted. Reported by Tomasz Nowicki. ACPICA BZ 1026. + +Debug output: Do not emit the function nesting level for the in-kernel +build. The nesting level is really only useful during a single-thread +execution. Therefore, only enable this output for the AcpiExec utility. +Also, only emit the thread ID when executing under AcpiExec (Context +switches are still always detected and a message is emitted). ACPICA BZ +972. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 95.9K Code, 27.0K Data, 122.9K Total + Debug Version: 185.1K Code, 77.2K Data, 262.3K Total + Previous Release: + Non-Debug Version: 95.8K Code, 27.0K Data, 122.8K Total + Debug Version: 185.2K Code, 77.2K Data, 262.4K Total + + +2) iASL Compiler/Disassembler and Tools: + +AcpiExec/Unix-OSL: Use instead of . This is the +correct portable POSIX header for terminal control functions. + +Disassembler: Fixed control method invocation issues related to the use +of the CondRefOf() operator. The problem is seen in the disassembly where +control method invocations may not be disassembled properly if the +control method name has been used previously as an argument to CondRefOf. +The solution is to not attempt to emit an external declaration for the +CondRefOf target (it is not necessary in the first place). This prevents +disassembler object type confusion. ACPICA BZ 988. + +Unix Makefiles: Added an option to disable compiler optimizations and the +_FORTIFY_SOURCE flag. Some older compilers have problems compiling ACPICA +with optimizations (reportedly, gcc 4.4 for example). This change adds a +command line option for make (NOOPT) that disables all compiler +optimizations and the _FORTIFY_SOURCE compiler flag. The default +optimization is -O2 with the _FORTIFY_SOURCE flag specified. ACPICA BZ +1034. Lv Zheng, Bob Moore. + +Tests/ASLTS: Added options to specify individual test cases and modes. +This allows testers running aslts.sh to optionally specify individual +test modes and test cases. Also added an option to disable the forced +generation of the ACPICA tools from source if desired. Lv Zheng. + +---------------------------------------- +27 September 2013. Summary of changes for version 20130927: + +This release is available at https://acpica.org/downloads + + +1) ACPICA kernel-resident subsystem: + +Fixed a problem with store operations to reference objects. This change +fixes a problem where a Store operation to an ArgX object that contained +a +reference to a field object did not complete the automatic dereference +and +then write to the actual field object. Instead, the object type of the +field object was inadvertently changed to match the type of the source +operand. The new behavior will actually write to the field object (buffer +field or field unit), thus matching the correct ACPI-defined behavior. + +Implemented support to allow the host to redefine individual OSL +prototypes. This change enables the host to redefine OSL prototypes found +in the acpiosxf.h file. This allows the host to implement OSL interfaces +with a macro or inlined function. Further, it allows the host to add any +additional required modifiers such as __iomem, __init, __exit, etc., as +necessary on a per-interface basis. Enables maximum flexibility for the +OSL interfaces. Lv Zheng. + +Hardcoded the access width for the FADT-defined reset register. The ACPI +specification requires the reset register width to be 8 bits. ACPICA now +hardcodes the width to 8 and ignores the FADT width value. This provides +compatibility with other ACPI implementations that have allowed BIOS code +with bad register width values to go unnoticed. Matthew Garett, Bob +Moore, +Lv Zheng. + +Changed the position/use of the ACPI_PRINTF_LIKE macro. This macro is +used +in the OSL header (acpiosxf). The change modifies the position of this +macro in each instance where it is used (AcpiDebugPrint, etc.) to avoid +build issues if the OSL defines the implementation of the interface to be +an inline stub function. Lv Zheng. + +Deployed a new macro ACPI_EXPORT_SYMBOL_INIT for the main ACPICA +initialization interfaces. This change adds a new macro for the main init +and terminate external interfaces in order to support hosts that require +additional or different processing for these functions. Changed from +ACPI_EXPORT_SYMBOL to ACPI_EXPORT_SYMBOL_INIT for these functions. Lv +Zheng, Bob Moore. + +Cleaned up the memory allocation macros for configurability. In the +common +case, the ACPI_ALLOCATE and related macros now resolve directly to their +respective AcpiOs* OSL interfaces. Two options: +1) The ACPI_ALLOCATE_ZEROED macro uses a simple local implementation by +default, unless overridden by the USE_NATIVE_ALLOCATE_ZEROED define. +2) For AcpiExec (and for debugging), the macros can optionally be +resolved +to the local ACPICA interfaces that track each allocation (local tracking +is used to immediately detect memory leaks). +Lv Zheng. + +Simplified the configuration for ACPI_REDUCED_HARDWARE. Allows the kernel +to predefine this macro to either TRUE or FALSE during the system build. + +Replaced __FUNCTION_ with __func__ in the gcc-specific header. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 95.8K Code, 27.0K Data, 122.8K Total + Debug Version: 185.2K Code, 77.2K Data, 262.4K Total + Previous Release: + Non-Debug Version: 96.7K Code, 27.1K Data, 123.9K Total + Debug Version: 184.4K Code, 76.8K Data, 261.2K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented wildcard support for the -e option. This simplifies use +when there are many SSDTs that must be included to resolve external +method +declarations. ACPICA BZ 1041. Example: + iasl -e ssdt*.dat -d dsdt.dat + +AcpiExec: Add history/line-editing for Unix/Linux systems. This change +adds a portable module that implements full history and limited line +editing for Unix and Linux systems. It does not use readline() due to +portability issues. Instead it uses the POSIX termio interface to put the +terminal in raw input mode so that the various special keys can be +trapped +(such as up/down-arrow for history support and left/right-arrow for line +editing). Uses the existing debugger history mechanism. ACPICA BZ 1036. + +AcpiXtract: Add support to handle (ignore) "empty" lines containing only +one or more spaces. This provides compatible with early or different +versions of the AcpiDump utility. ACPICA BZ 1044. + +AcpiDump: Do not ignore tables that contain only an ACPI table header. +Apparently, some BIOSs create SSDTs that contain an ACPI table header but +no other data. This change adds support to dump these tables. Any tables +shorter than the length of an ACPI table header remain in error (an error +message is emitted). Reported by Yi Li. + +Debugger: Echo actual command along with the "unknown command" message. + +---------------------------------------- +23 August 2013. Summary of changes for version 20130823: + +1) ACPICA kernel-resident subsystem: + +Implemented support for host-installed System Control Interrupt (SCI) +handlers. Certain ACPI functionality requires the host to handle raw +SCIs. For example, the "SCI Doorbell" that is defined for memory power +state support requires the host device driver to handle SCIs to examine +if the doorbell has been activated. Multiple SCI handlers can be +installed to allow for future expansion. New external interfaces are +AcpiInstallSciHandler, AcpiRemoveSciHandler; see the ACPICA reference for +details. Lv Zheng, Bob Moore. ACPICA BZ 1032. + +Operation region support: Never locally free the handler "context" +pointer. This change removes some dangerous code that attempts to free +the handler context pointer in some (rare) circumstances. The owner of +the handler owns this pointer and the ACPICA code should never touch it. +Although not seen to be an issue in any kernel, it did show up as a +problem (fault) under AcpiExec. Also, set the internal storage field for +the context pointer to zero when the region is deactivated, simply for +sanity. David Box. ACPICA BZ 1039. + +AcpiRead: On error, do not modify the return value target location. If an +error happens in the middle of a split 32/32 64-bit I/O operation, do not +modify the target of the return value pointer. Makes the code consistent +with the rest of ACPICA. Bjorn Helgaas. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.7K Code, 27.1K Data, 123.9K Total + Debug Version: 184.4K Code, 76.8K Data, 261.2K Total + Previous Release: + Non-Debug Version: 96.2K Code, 27.1K Data, 123.3K Total + Debug Version: 185.4K Code, 77.1K Data, 262.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +AcpiDump: Implemented several new features and fixed some problems: +1) Added support to dump the RSDP, RSDT, and XSDT tables. +2) Added support for multiple table instances (SSDT, UEFI). +3) Added option to dump "customized" (overridden) tables (-c). +4) Fixed a problem where some table filenames were improperly +constructed. +5) Improved some error messages, removed some unnecessary messages. + +iASL: Implemented additional support for disassembly of ACPI tables that +contain invocations of external control methods. The -fe option +allows the import of a file that specifies the external methods along +with the required number of arguments for each -- allowing for the +correct disassembly of the table. This is a workaround for a limitation +of AML code where the disassembler often cannot determine the number of +arguments required for an external control method and generates incorrect +ASL code. See the iASL reference for details. ACPICA BZ 1030. + +Debugger: Implemented a new command (paths) that displays the full +pathnames (namepaths) and object types of all objects in the namespace. +This is an alternative to the namespace command. + +Debugger: Implemented a new command (sci) that invokes the SCI dispatch +mechanism and any installed handlers. + +iASL: Fixed a possible segfault for "too many parent prefixes" condition. +This can occur if there are too many parent prefixes in a namepath (for +example, ^^^^^^PCI0.ECRD). ACPICA BZ 1035. + +Application OSLs: Set the return value for the PCI read functions. These +functions simply return AE_OK, but should set the return value to zero +also. This change implements this. ACPICA BZ 1038. + +Debugger: Prevent possible command line buffer overflow. Increase the +size of a couple of the debugger line buffers, and ensure that overflow +cannot happen. ACPICA BZ 1037. + +iASL: Changed to abort immediately on serious errors during the parsing +phase. Due to the nature of ASL, there is no point in attempting to +compile these types of errors, and they typically end up causing a +cascade of hundreds of errors which obscure the original problem. + +---------------------------------------- +25 July 2013. Summary of changes for version 20130725: + +1) ACPICA kernel-resident subsystem: + +Fixed a problem with the DerefOf operator where references to FieldUnits +and BufferFields incorrectly returned the parent object, not the actual +value of the object. After this change, a dereference of a FieldUnit +reference results in a read operation on the field to get the value, and +likewise, the appropriate BufferField value is extracted from the target +buffer. + +Fixed a problem where the _WAK method could cause a fault under these +circumstances: 1) Interpreter slack mode was not enabled, and 2) the _WAK +method returned no value. The problem is rarely seen because most kernels +run ACPICA in slack mode. + +For the DerefOf operator, a fatal error now results if an attempt is made +to dereference a reference (created by the Index operator) to a NULL +package element. Provides compatibility with other ACPI implementations, +and this behavior will be added to a future version of the ACPI +specification. + +The ACPI Power Management Timer (defined in the FADT) is now optional. +This provides compatibility with other ACPI implementations and will +appear in the next version of the ACPI specification. If there is no PM +Timer on the platform, AcpiGetTimer returns AE_SUPPORT. An address of +zero in the FADT indicates no PM timer. + +Implemented a new interface for _OSI support, AcpiUpdateInterfaces. This +allows the host to globally enable/disable all vendor strings, all +feature strings, or both. Intended to be primarily used for debugging +purposes only. Lv Zheng. + +Expose the collected _OSI data to the host via a global variable. This +data tracks the highest level vendor ID that has been invoked by the BIOS +so that the host (and potentially ACPICA itself) can change behaviors +based upon the age of the BIOS. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.2K Code, 27.1K Data, 123.3K Total + Debug Version: 184.4K Code, 76.8K Data, 261.2K Total + Previous Release: + Non-Debug Version: 95.9K Code, 26.9K Data, 122.8K Total + Debug Version: 184.1K Code, 76.7K Data, 260.8K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Created the following enhancements for the -so option (create +offset table): +1)Add offsets for the last nameseg in each namepath for every supported +object type +2)Add support for Processor, Device, Thermal Zone, and Scope objects +3)Add the actual AML opcode for the parent object of every supported +object type +4)Add support for the ZERO/ONE/ONES AML opcodes for integer objects + +Disassembler: Emit all unresolved external symbols in a single block. +These are external references to control methods that could not be +resolved, and thus, the disassembler had to make a guess at the number of +arguments to parse. + +iASL: The argument to the -T option (create table template) is now +optional. If not specified, the default table is a DSDT, typically the +most common case. + +---------------------------------------- +26 June 2013. Summary of changes for version 20130626: + +1) ACPICA kernel-resident subsystem: + +Fixed an issue with runtime repair of the _CST object. Null or invalid +elements were not always removed properly. Lv Zheng. + +Removed an arbitrary restriction of 256 GPEs per GPE block (such as the +FADT-defined GPE0 and GPE1). For GPE0, GPE1, and each GPE Block Device, +the maximum number of GPEs is 1016. Use of multiple GPE block devices +makes the system-wide number of GPEs essentially unlimited. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 95.9K Code, 26.9K Data, 122.8K Total + Debug Version: 184.1K Code, 76.7K Data, 260.8K Total + Previous Release: + Non-Debug Version: 96.0K Code, 27.0K Data, 123.0K Total + Debug Version: 184.1K Code, 76.8K Data, 260.9K Total + + +2) iASL Compiler/Disassembler and Tools: + +Portable AcpiDump: Implemented full support for the Linux and FreeBSD +hosts. Now supports Linux, FreeBSD, and Windows. + +Disassembler: Added some missing types for the HEST and EINJ tables: "Set +Error Type With Address", "CMCI", "MCE", and "Flush Cacheline". + +iASL/Preprocessor: Implemented full support for nested +#if/#else/#elif/#endif blocks. Allows arbitrary depth of nested blocks. + +Disassembler: Expanded maximum output string length to 64K. Was 256 bytes +max. The original purpose of this constraint was to limit the amount of +debug output. However, the string function in question (UtPrintString) is +now used for the disassembler also, where 256 bytes is insufficient. +Reported by RehabMan@GitHub. + +iASL/DataTables: Fixed some problems and issues with compilation of DMAR +tables. ACPICA BZ 999. Lv Zheng. + +iASL: Fixed a couple of error exit issues that could result in a "Could +not delete " message during ASL compilation. + +AcpiDump: Allow "FADT" and "MADT" as valid table signatures, even though +the actual signatures for these tables are "FACP" and "APIC", +respectively. + +AcpiDump: Added support for multiple UEFI tables. Only SSDT and UEFI +tables are allowed to have multiple instances. + +---------------------------------------- +17 May 2013. Summary of changes for version 20130517: + +1) ACPICA kernel-resident subsystem: + +Fixed a regression introduced in version 20130328 for _INI methods. This +change fixes a problem introduced in 20130328 where _INI methods are no +longer executed properly because of a memory block that was not +initialized correctly. ACPICA BZ 1016. Tomasz Nowicki +. + +Fixed a possible problem with the new extended sleep registers in the +ACPI +5.0 FADT. Do not use these registers (even if populated) unless the HW- +reduced bit is set in the FADT (as per the ACPI specification). ACPICA BZ +1020. Lv Zheng. + +Implemented return value repair code for _CST predefined objects: Sort +the +list and detect/remove invalid entries. ACPICA BZ 890. Lv Zheng. + +Implemented a debug-only option to disable loading of SSDTs from the +RSDT/XSDT during ACPICA initialization. This can be useful for debugging +ACPI problems on some machines. Set AcpiGbl_DisableSsdtTableLoad in +acglobal.h - ACPICA BZ 1005. Lv Zheng. + +Fixed some issues in the ACPICA initialization and termination code: +Tomasz Nowicki +1) Clear events initialized flag upon event component termination. ACPICA +BZ 1013. +2) Fixed a possible memory leak in GPE init error path. ACPICA BZ 1018. +3) Delete global lock pending lock during termination. ACPICA BZ 1012. +4) Clear debug buffer global on termination to prevent possible multiple +delete. ACPICA BZ 1010. + +Standardized all switch() blocks across the entire source base. After +many +years, different formatting for switch() had crept in. This change makes +the formatting of every switch block identical. ACPICA BZ 997. Chao Guan. + +Split some files to enhance ACPICA modularity and configurability: +1) Split buffer dump routines into utilities/utbuffer.c +2) Split internal error message routines into utilities/uterror.c +3) Split table print utilities into tables/tbprint.c +4) Split iASL command-line option processing into asloptions.c + +Makefile enhancements: +1) Support for all new files above. +2) Abort make on errors from any subcomponent. Chao Guan. +3) Add build support for Apple Mac OS X. Liang Qi. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 96.0K Code, 27.0K Data, 123.0K Total + Debug Version: 184.1K Code, 76.8K Data, 260.9K Total + Previous Release: + Non-Debug Version: 95.6K Code, 26.8K Data, 122.4K Total + Debug Version: 183.5K Code, 76.6K Data, 260.1K Total + + +2) iASL Compiler/Disassembler and Tools: + +New utility: Implemented an easily portable version of the acpidump +utility to extract ACPI tables from the system (or a file) in an ASCII +hex +dump format. The top-level code implements the various command line +options, file I/O, and table dump routines. To port to a new host, only +three functions need to be implemented to get tables -- since this +functionality is OS-dependent. See the tools/acpidump/apmain.c module and +the ACPICA reference for porting instructions. ACPICA BZ 859. Notes: +1) The Windows version obtains the ACPI tables from the Registry. +2) The Linux version is under development. +3) Other hosts - If an OS-dependent module is submitted, it will be +distributed with ACPICA. + +iASL: Fixed a regression for -D preprocessor option (define symbol). A +restructuring/change to the initialization sequence caused this option to +no longer work properly. + +iASL: Implemented a mechanism to disable specific warnings and remarks. +Adds a new command line option, "-vw as well as "#pragma +disable ". ACPICA BZ 989. Chao Guan, Bob Moore. + +iASL: Fix for too-strict package object validation. The package object +validation for return values from the predefined names is a bit too +strict, it does not allow names references within the package (which will +be resolved at runtime.) These types of references cannot be validated at +compile time. This change ignores named references within package objects +for names that return or define static packages. + +Debugger: Fixed the 80-character command line limitation for the History +command. Now allows lines of arbitrary length. ACPICA BZ 1000. Chao Guan. + +iASL: Added control method and package support for the -so option +(generates AML offset table for BIOS support.) + +iASL: issue a remark if a non-serialized method creates named objects. If +a thread blocks within the method for any reason, and another thread +enters the method, the method will fail because an attempt will be made +to +create the same (named) object twice. In this case, issue a remark that +the method should be marked serialized. NOTE: may become a warning later. +ACPICA BZ 909. + +---------------------------------------- +18 April 2013. Summary of changes for version 20130418: + +1) ACPICA kernel-resident subsystem: + +Fixed a possible buffer overrun during some rare but specific field unit +read operations. This overrun can only happen if the DSDT version is 1 -- +meaning that all AML integers are 32 bits -- and the field length is +between 33 and 55 bits long. During the read, an internal buffer object +is +created for the field unit because the field is larger than an integer +(32 +bits). However, in this case, the buffer will be incorrectly written +beyond the end because the buffer length is less than the internal +minimum +of 64 bits (8 bytes) long. The buffer will be either 5, 6, or 7 bytes +long, but a full 8 bytes will be written. + +Updated the Embedded Controller "orphan" _REG method support. This refers +to _REG methods under the EC device that have no corresponding operation +region. This is allowed by the ACPI specification. This update removes a +dependency on the existence an ECDT table. It will execute an orphan _REG +method as long as the operation region handler for the EC is installed at +the EC device node and not the namespace root. Rui Zhang (original +update), Bob Moore (update/integrate). + +Implemented run-time argument typechecking for all predefined ACPI names +(_STA, _BIF, etc.) This change performs object typechecking on all +incoming arguments for all predefined names executed via +AcpiEvaluateObject. This ensures that ACPI-related device drivers are +passing correct object types as well as the correct number of arguments +(therefore identifying any issues immediately). Also, the ASL/namespace +definition of the predefined name is checked against the ACPI +specification for the proper argument count. Adds one new file, +nsarguments.c + +Changed an exception code for the ASL UnLoad() operator. Changed the +exception code for the case where the input DdbHandle is invalid, from +AE_BAD_PARAMETER to the more appropriate AE_AML_OPERAND_TYPE. + +Unix/Linux makefiles: Removed the use of the -O2 optimization flag in the +global makefile. The use of this flag causes compiler errors on earlier +versions of GCC, so it has been removed for compatibility. + +Miscellaneous cleanup: +1) Removed some unused/obsolete macros +2) Fixed a possible memory leak in the _OSI support +3) Removed an unused variable in the predefined name support +4) Windows OSL: remove obsolete reference to a memory list field + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Current Release: + Non-Debug Version: 95.2K Code, 26.4K Data, 121.6K Total + Debug Version: 183.0K Code, 76.0K Data, 259.0K Total + Previous Release: + Non-Debug Version: 95.6K Code, 26.8K Data, 122.4K Total + Debug Version: 183.5K Code, 76.6K Data, 260.1K Total + + +2) iASL Compiler/Disassembler and Tools: + +AcpiExec: Added installation of a handler for the SystemCMOS address +space. This prevents control method abort if a method accesses this +space. + +AcpiExec: Added support for multiple EC devices, and now install EC +operation region handler(s) at the actual EC device instead of the +namespace root. This reflects the typical behavior of host operating +systems. + +AcpiExec: Updated to ensure that all operation region handlers are +installed before the _REG methods are executed. This prevents a _REG +method from aborting if it accesses an address space has no handler. +AcpiExec installs a handler for every possible address space. + +Debugger: Enhanced the "handlers" command to display non-root handlers. +This change enhances the handlers command to display handlers associated +with individual devices throughout the namespace, in addition to the +currently supported display of handlers associated with the root +namespace +node. + +ASL Test Suite: Several test suite errors have been identified and +resolved, reducing the total error count during execution. Chao Guan. + +---------------------------------------- +28 March 2013. Summary of changes for version 20130328: + +1) ACPICA kernel-resident subsystem: + +Fixed several possible race conditions with the internal object reference +counting mechanism. Some of the external ACPICA interfaces update object +reference counts without holding the interpreter or namespace lock. This +change adds a spinlock to protect reference count updates on the internal +ACPICA objects. Reported by and with assistance from Andriy Gapon +(avg@FreeBSD.org). + +FADT support: Removed an extraneous warning for very large GPE register +sets. This change removes a size mismatch warning if the legacy length +field for a GPE register set is larger than the 64-bit GAS structure can +accommodate. GPE register sets can be larger than the 255-bit width +limitation of the GAS structure. Linn Crosetto (linn@hp.com). + +_OSI Support: handle any errors from AcpiOsAcquireMutex. Check for error +return from this interface. Handles a possible timeout case if +ACPI_WAIT_FOREVER is modified by the host to be a value less than +"forever". Jung-uk Kim. + +Predefined name support: Add allowed/required argument type information +to +the master predefined info table. This change adds the infrastructure to +enable typechecking on incoming arguments for all predefined +methods/objects. It does not actually contain the code that will fully +utilize this information, this is still under development. Also condenses +some duplicate code for the predefined names into a new module, +utilities/utpredef.c + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Previous Release: + Non-Debug Version: 95.0K Code, 25.9K Data, 120.9K Total + Debug Version: 182.9K Code, 75.6K Data, 258.5K Total + Current Release: + Non-Debug Version: 95.2K Code, 26.4K Data, 121.6K Total + Debug Version: 183.0K Code, 76.0K Data, 259.0K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented a new option to simplify the development of ACPI- +related +BIOS code. Adds support for a new "offset table" output file. The -so +option will create a C table containing the AML table offsets of various +named objects in the namespace so that BIOS code can modify them easily +at +boot time. This can simplify BIOS runtime code by eliminating expensive +searches for "magic values", enhancing boot times and adding greater +reliability. With assistance from Lee Hamel. + +iASL: Allow additional predefined names to return zero-length packages. +Now, all predefined names that are defined by the ACPI specification to +return a "variable-length package of packages" are allowed to return a +zero length top-level package. This allows the BIOS to tell the host that +the requested feature is not supported, and supports existing BIOS/ASL +code and practices. + +iASL: Changed the "result not used" warning to an error. This is the case +where an ASL operator is effectively a NOOP because the result of the +operation is not stored anywhere. For example: + Add (4, Local0) +There is no target (missing 3rd argument), nor is the function return +value used. This is potentially a very serious problem -- since the code +was probably intended to do something, but for whatever reason, the value +was not stored. Therefore, this issue has been upgraded from a warning to +an error. + +AcpiHelp: Added allowable/required argument types to the predefined names +info display. This feature utilizes the recent update to the predefined +names table (above). + +---------------------------------------- +14 February 2013. Summary of changes for version 20130214: + +1) ACPICA Kernel-resident Subsystem: + +Fixed a possible regression on some hosts: Reinstated the safe return +macros (return_ACPI_STATUS, etc.) that ensure that the argument is +evaluated only once. Although these macros are not needed for the ACPICA +code itself, they are often used by ACPI-related host device drivers +where +the safe feature may be necessary. + +Fixed several issues related to the ACPI 5.0 reduced hardware support +(SOC): Now ensure that if the platform declares itself as hardware- +reduced +via the FADT, the following functions become NOOPs (and always return +AE_OK) because ACPI is always enabled by definition on these machines: + AcpiEnable + AcpiDisable + AcpiHwGetMode + AcpiHwSetMode + +Dynamic Object Repair: Implemented additional runtime repairs for +predefined name return values. Both of these repairs can simplify code in +the related device drivers that invoke these methods: +1) For the _STR and _MLS names, automatically repair/convert an ASCII +string to a Unicode buffer. +2) For the _CRS, _PRS, and _DMA names, return a resource descriptor with +a +lone end tag descriptor in the following cases: A Return(0) was executed, +a null buffer was returned, or no object at all was returned (non-slack +mode only). Adds a new file, nsconvert.c +ACPICA BZ 998. Bob Moore, Lv Zheng. + +Resource Manager: Added additional code to prevent possible infinite +loops +while traversing corrupted or ill-formed resource template buffers. Check +for zero-length resource descriptors in all code that loops through +resource templates (the length field is used to index through the +template). This change also hardens the external AcpiWalkResources and +AcpiWalkResourceBuffer interfaces. + +Local Cache Manager: Enhanced the main data structure to eliminate an +unnecessary mechanism to access the next object in the list. Actually +provides a small performance enhancement for hosts that use the local +ACPICA cache manager. Jung-uk Kim. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Previous Release: + Non-Debug Version: 94.5K Code, 25.4K Data, 119.9K Total + Debug Version: 182.3K Code, 75.0K Data, 257.3K Total + Current Release: + Non-Debug Version: 95.0K Code, 25.9K Data, 120.9K Total + Debug Version: 182.9K Code, 75.6K Data, 258.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL/Disassembler: Fixed several issues with the definition of the ACPI +5.0 RASF table (RAS Feature Table). This change incorporates late changes +that were made to the ACPI 5.0 specification. + +iASL/Disassembler: Added full support for the following new ACPI tables: + 1) The MTMR table (MID Timer Table) + 2) The VRTC table (Virtual Real Time Clock Table). +Includes header file, disassembler, table compiler, and template support +for both tables. + +iASL: Implemented compile-time validation of package objects returned by +predefined names. This new feature validates static package objects +returned by the various predefined names defined to return packages. Both +object types and package lengths are validated, for both parent packages +and sub-packages, if any. The code is similar in structure and behavior +to +the runtime repair mechanism within the AML interpreter and uses the +existing predefined name information table. Adds a new file, aslprepkg.c. +ACPICA BZ 938. + +iASL: Implemented auto-detection of binary ACPI tables for disassembly. +This feature detects a binary file with a valid ACPI table header and +invokes the disassembler automatically. Eliminates the need to +specifically invoke the disassembler with the -d option. ACPICA BZ 862. + +iASL/Disassembler: Added several warnings for the case where there are +unresolved control methods during the disassembly. This can potentially +cause errors when the output file is compiled, because the disassembler +assumes zero method arguments in these cases (it cannot determine the +actual number of arguments without resolution/definition of the method). + +Debugger: Added support to display all resources with a single command. +Invocation of the resources command with no arguments will now display +all +resources within the current namespace. + +AcpiHelp: Added descriptive text for each ACPICA exception code displayed +via the -e option. + +---------------------------------------- +17 January 2013. Summary of changes for version 20130117: + +1) ACPICA Kernel-resident Subsystem: + +Updated the AcpiGetSleepTypeData interface: Allow the \_Sx methods to +return either 1 or 2 integers. Although the ACPI spec defines the \_Sx +objects to return a package containing one integer, most BIOS code +returns +two integers and the previous code reflects that. However, we also need +to +support BIOS code that actually implements to the ACPI spec, and this +change reflects this. + +Fixed two issues with the ACPI_DEBUG_PRINT macros: +1) Added the ACPI_DO_WHILE macro to the main DEBUG_PRINT helper macro for +C compilers that require this support. +2) Renamed the internal ACPI_DEBUG macro to ACPI_DO_DEBUG_PRINT since +ACPI_DEBUG is already used by many of the various hosts. + +Updated all ACPICA copyrights and signons to 2013. Added the 2013 +copyright to all module headers and signons, including the standard Linux +header. This affects virtually every file in the ACPICA core subsystem, +iASL compiler, all ACPICA utilities, and the test suites. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Previous Release: + Non-Debug Version: 94.5K Code, 25.5K Data, 120.0K Total + Debug Version: 182.2K Code, 74.9K Data, 257.1K Total + Current Release: + Non-Debug Version: 94.5K Code, 25.4K Data, 119.9K Total + Debug Version: 182.3K Code, 75.0K Data, 257.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +Generic Unix OSL: Use a buffer to eliminate multiple vfprintf()s and +prevent a possible fault on some hosts. Some C libraries modify the arg +pointer parameter to vfprintf making it difficult to call it twice in the +AcpiOsVprintf function. Use a local buffer to workaround this issue. This +does not affect the Windows OSL since the Win C library does not modify +the arg pointer. Chao Guan, Bob Moore. + +iASL: Fixed a possible infinite loop when the maximum error count is +reached. If an output file other than the .AML file is specified (such as +a listing file), and the maximum number of errors is reached, do not +attempt to flush data to the output file(s) as the compiler is aborting. +This can cause an infinite loop as the max error count code essentially +keeps calling itself. + +iASL/Disassembler: Added an option (-in) to ignore NOOP +opcodes/operators. +Implemented for both the compiler and the disassembler. Often, the NOOP +opcode is used as padding for packages that are changed dynamically by +the +BIOS. When disassembled and recompiled, these NOOPs will cause syntax +errors. This option causes the disassembler to ignore all NOOP opcodes +(0xA3), and it also causes the compiler to ignore all ASL source code +NOOP +statements as well. + +Debugger: Enhanced the Sleep command to execute all sleep states. This +change allows Sleep to be invoked with no arguments and causes the +debugger to execute all of the sleep states, 0-5, automatically. + +---------------------------------------- +20 December 2012. Summary of changes for version 20121220: + +1) ACPICA Kernel-resident Subsystem: + +Implemented a new interface, AcpiWalkResourceBuffer. This interface is an +alternate entry point for AcpiWalkResources and improves the usability of +the resource manager by accepting as input a buffer containing the output +of either a _CRS, _PRS, or _AEI method. The key functionality is that the +input buffer is not deleted by this interface so that it can be used by +the host later. See the ACPICA reference for details. + +Interpreter: Add a warning if a 64-bit constant appears in a 32-bit table +(DSDT version < 2). The constant will be truncated and this warning +reflects that behavior. + +Resource Manager: Add support for the new ACPI 5.0 wake bit in the IRQ, +ExtendedInterrupt, and GpioInt descriptors. This change adds support to +both get and set the new wake bit in these descriptors, separately from +the existing share bit. Reported by Aaron Lu. + +Interpreter: Fix Store() when an implicit conversion is not possible. For +example, in the cases such as a store of a string to an existing package +object, implement the store as a CopyObject(). This is a small departure +from the ACPI specification which states that the control method should +be +aborted in this case. However, the ASLTS suite depends on this behavior. + +Performance improvement for the various FUNCTION_TRACE and DEBUG_PRINT +macros: check if debug output is currently enabled as soon as possible to +minimize performance impact if debug is in fact not enabled. + +Source code restructuring: Cleanup to improve modularity. The following +new files have been added: dbconvert.c, evhandler.c, nsprepkg.c, +psopinfo.c, psobject.c, rsdumpinfo.c, utstring.c, and utownerid.c. +Associated makefiles and project files have been updated. + +Changed an exception code for LoadTable operator. For the case where one +of the input strings is too long, change the returned exception code from +AE_BAD_PARAMETER to AE_AML_STRING_LIMIT. + +Fixed a possible memory leak in dispatcher error path. On error, delete +the mutex object created during method mutex creation. Reported by +tim.gardner@canonical.com. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Previous Release: + Non-Debug Version: 94.3K Code, 25.3K Data, 119.6K Total + Debug Version: 175.5K Code, 74.5K Data, 250.0K Total + Current Release: + Non-Debug Version: 94.5K Code, 25.5K Data, 120.0K Total + Debug Version: 182.2K Code, 74.9K Data, 257.1K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Disallow a method call as argument to the ObjectType ASL operator. +This change tracks an errata to the ACPI 5.0 document. The AML grammar +will not allow the interpreter to differentiate between a method and a +method invocation when these are used as an argument to the ObjectType +operator. The ACPI specification change is to disallow a method +invocation +(UserTerm) for the ObjectType operator. + +Finish support for the TPM2 and CSRT tables in the headers, table +compiler, and disassembler. + +Unix user-space OSL: Fix a problem with WaitSemaphore where the timeout +always expires immediately if the semaphore is not available. The +original +code was using a relative-time timeout, but sem_timedwait requires the +use +of an absolute time. + +iASL: Added a remark if the Timer() operator is used within a 32-bit +table. This operator returns a 64-bit time value that will be truncated +within a 32-bit table. + +iASL Source code restructuring: Cleanup to improve modularity. The +following new files have been added: aslhex.c, aslxref.c, aslnamesp.c, +aslmethod.c, and aslfileio.c. Associated makefiles and project files have +been updated. + + +---------------------------------------- +14 November 2012. Summary of changes for version 20121114: + +1) ACPICA Kernel-resident Subsystem: + +Implemented a performance enhancement for ACPI/AML Package objects. This +change greatly increases the performance of Package objects within the +interpreter. It changes the processing of reference counts for packages +by +optimizing for the most common case where the package sub-objects are +either Integers, Strings, or Buffers. Increases the overall performance +of +the ASLTS test suite by 1.5X (Increases the Slack Mode performance by +2X.) +Chao Guan. ACPICA BZ 943. + +Implemented and deployed common macros to extract flag bits from resource +descriptors. Improves readability and maintainability of the code. Fixes +a +problem with the UART serial bus descriptor for the number of data bits +flags (was incorrectly 2 bits, should be 3). + +Enhanced the ACPI_GETx and ACPI_SETx macros. Improved the implementation +of the macros and changed the SETx macros to the style of (destination, +source). Also added ACPI_CASTx companion macros. Lv Zheng. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Previous Release: + Non-Debug Version: 93.9K Code, 25.2K Data, 119.1K Total + Debug Version: 175.5K Code, 74.5K Data, 250.0K Total + Current Release: + Non-Debug Version: 94.3K Code, 25.3K Data, 119.6K Total + Debug Version: 175.5K Code, 74.5K Data, 250.0K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Added the new ACPI 5.0 interrupt sharing flags. This change +adds the ShareAndWake and ExclusiveAndWake flags which were added to the +Irq, Interrupt, and Gpio resource descriptors in ACPI 5.0. ACPICA BZ 986. + +Disassembler: Fixed a problem with external declaration generation. Fixes +a problem where an incorrect pathname could be generated for an external +declaration if the original reference to the object includes leading +carats (^). ACPICA BZ 984. + +Debugger: Completed a major update for the Disassemble command. +This command was out-of-date and did not properly disassemble control +methods that had any reasonable complexity. This fix brings the command +up +to the same level as the rest of the disassembler. Adds one new file, +dmdeferred.c, which is existing code that is now common with the main +disassembler and the debugger disassemble command. ACPICA MZ 978. + +iASL: Moved the parser entry prototype to avoid a duplicate declaration. +Newer versions of Bison emit this prototype, so moved the prototype out +of +the iASL header to where it is actually used in order to avoid a +duplicate +declaration. + +iASL/Tools: Standardized use of the stream I/O functions: + 1) Ensure check for I/O error after every fopen/fread/fwrite + 2) Ensure proper order of size/count arguments for fread/fwrite + 3) Use test of (Actual != Requested) after all fwrite, and most fread + 4) Standardize I/O error messages +Improves reliability and maintainability of the code. Bob Moore, Lv +Zheng. +ACPICA BZ 981. + +Disassembler: Prevent duplicate External() statements. During generation +of external statements, detect similar pathnames that are actually +duplicates such as these: + External (\ABCD) + External (ABCD) +Remove all leading '\' characters from pathnames during the external +statement generation so that duplicates will be detected and tossed. +ACPICA BZ 985. + +Tools: Replace low-level I/O with stream I/O functions. Replace +open/read/write/close with the stream I/O equivalents +fopen/fread/fwrite/fclose for portability and performance. Lv Zheng, Bob +Moore. + +AcpiBin: Fix for the dump-to-hex function. Now correctly output the table +name header so that AcpiXtract recognizes the output file/table. + +iASL: Remove obsolete -2 option flag. Originally intended to force the +compiler/disassembler into an ACPI 2.0 mode, this was never implemented +and the entire concept is now obsolete. + +---------------------------------------- +18 October 2012. Summary of changes for version 20121018: + + +1) ACPICA Kernel-resident Subsystem: + +Updated support for the ACPI 5.0 MPST table. Fixes some problems +introduced by late changes to the table as it was added to the ACPI 5.0 +specification. Includes header, disassembler, and data table compiler +support as well as a new version of the MPST template. + +AcpiGetObjectInfo: Enhanced the device object support to include the ACPI +5.0 _SUB method. Now calls _SUB in addition to the other PNP-related ID +methods: _HID, _CID, and _UID. + +Changed ACPI_DEVICE_ID to ACPI_PNP_DEVICE_ID. Also changed +ACPI_DEVICE_ID_LIST to ACPI_PNP_DEVICE_ID_LIST. These changes prevent +name collisions on hosts that reserve the *_DEVICE_ID (or *DeviceId) +names for their various drivers. Affects the AcpiGetObjectInfo external +interface, and other internal interfaces as well. + +Added and deployed a new macro for ACPI_NAME management: ACPI_MOVE_NAME. +This macro resolves to a simple 32-bit move of the 4-character ACPI_NAME +on machines that support non-aligned transfers. Optimizes for this case +rather than using a strncpy. With assistance from Zheng Lv. + +Resource Manager: Small fix for buffer size calculation. Fixed a one byte +error in the output buffer calculation. Feng Tang. ACPICA BZ 849. + +Added a new debug print message for AML mutex objects that are force- +released. At control method termination, any currently acquired mutex +objects are force-released. Adds a new debug-only message for each one +that is released. + +Audited/updated all ACPICA return macros and the function debug depth +counter: 1) Ensure that all functions that use the various TRACE macros +also use the appropriate ACPICA return macros. 2) Ensure that all normal +return statements surround the return expression (value) with parens to +ensure consistency across the ACPICA code base. Guan Chao, Tang Feng, +Zheng Lv, Bob Moore. ACPICA Bugzilla 972. + +Global source code changes/maintenance: All extra lines at the start and +end of each source file have been removed for consistency. Also, within +comments, all new sentences start with a single space instead of a double +space, again for consistency across the code base. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a much larger code and data size. + + Previous Release: + Non-Debug Version: 93.7K Code, 25.3K Data, 119.0K Total + Debug Version: 175.0K Code, 74.4K Data, 249.4K Total + Current Release: + Non-Debug Version: 93.9K Code, 25.2K Data, 119.1K Total + Debug Version: 175.5K Code, 74.5K Data, 250.0K Total + + +2) iASL Compiler/Disassembler and Tools: + +AcpiExec: Improved the algorithm used for memory leak/corruption +detection. Added some intelligence to the code that maintains the global +list of allocated memory. The list is now ordered by allocated memory +address, significantly improving performance. When running AcpiExec on +the ASLTS test suite, speed improvements of 3X to 5X are seen, depending +on the platform and/or the environment. Note, this performance +enhancement affects the AcpiExec utility only, not the kernel-resident +ACPICA code. + +Enhanced error reporting for invalid AML opcodes and bad ACPI_NAMEs. For +the disassembler, dump the 48 bytes surrounding the invalid opcode. Fix +incorrect table offset reported for invalid opcodes. Report the original +32-bit value for bad ACPI_NAMEs (as well as the repaired name.) + +Disassembler: Enhanced the -vt option to emit the binary table data in +hex format to assist with debugging. + +Fixed a potential filename buffer overflow in osunixdir.c. Increased the +size of file structure. Colin Ian King. + +---------------------------------------- +13 September 2012. Summary of changes for version 20120913: + + +1) ACPICA Kernel-resident Subsystem: + +ACPI 5.0: Added two new notify types for the Hardware Error Notification +Structure within the Hardware Error Source Table (HEST) table -- CMCI(5) +and +MCE(6). + +Table Manager: Merged/removed duplicate code in the root table resize +functions. One function is external, the other is internal. Lv Zheng, +ACPICA +BZ 846. + +Makefiles: Completely removed the obsolete "Linux" makefiles under +acpica/generate/linux. These makefiles are obsolete and have been +replaced +by +the generic unix makefiles under acpica/generate/unix. + +Makefiles: Ensure that binary files always copied properly. Minor rule +change +to ensure that the final binary output files are always copied up to the +appropriate binary directory (bin32 or bin64.) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 93.8K Code, 25.3K Data, 119.1K Total + Debug Version: 175.7K Code, 74.8K Data, 250.5K Total + Current Release: + Non-Debug Version: 93.7K Code, 25.3K Data, 119.0K Total + Debug Version: 175.0K Code, 74.4K Data, 249.4K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Fixed a possible fault during the disassembly of resource +descriptors when a second parse is required because of the invocation of +external control methods within the table. With assistance from +adq@lidskialf.net. ACPICA BZ 976. + +iASL: Fixed a namepath optimization problem. An error can occur if the +parse +node that contains the namepath to be optimized does not have a parent +node +that is a named object. This change fixes the problem. + +iASL: Fixed a regression where the AML file is not deleted on errors. The +AML +output file should be deleted if there are any errors during the +compiler. +The +only exception is if the -f (force output) option is used. ACPICA BZ 974. + +iASL: Added a feature to automatically increase internal line buffer +sizes. +Via realloc(), automatically increase the internal line buffer sizes as +necessary to support very long source code lines. The current version of +the +preprocessor requires a buffer long enough to contain full source code +lines. +This change increases the line buffer(s) if the input lines go beyond the +current buffer size. This eliminates errors that occurred when a source +code +line was longer than the buffer. + +iASL: Fixed a problem with constant folding in method declarations. The +SyncLevel term is a ByteConstExpr, and incorrect code would be generated +if a +Type3 opcode was used. + +Debugger: Improved command help support. For incorrect argument count, +display +full help for the command. For help command itself, allow an argument to +specify a command. + +Test Suites: Several bug fixes for the ASLTS suite reduces the number of +errors during execution of the suite. Guan Chao. + +---------------------------------------- +16 August 2012. Summary of changes for version 20120816: + + +1) ACPICA Kernel-resident Subsystem: + +Removed all use of the deprecated _GTS and _BFS predefined methods. The +_GTS +(Going To Sleep) and _BFS (Back From Sleep) methods are essentially +deprecated and will probably be removed from the ACPI specification. +Windows +does not invoke them, and reportedly never will. The final nail in the +coffin +is that the ACPI specification states that these methods must be run with +interrupts off, which is not going to happen in a kernel interpreter. +Note: +Linux has removed all use of the methods also. It was discovered that +invoking these functions caused failures on some machines, probably +because +they were never tested since Windows does not call them. Affects two +external +interfaces, AcpiEnterSleepState and AcpiLeaveSleepStatePrep. Tang Feng. +ACPICA BZ 969. + +Implemented support for complex bit-packed buffers returned from the _PLD +(Physical Location of Device) predefined method. Adds a new external +interface, AcpiDecodePldBuffer that parses the buffer into a more usable +C +structure. Note: C Bitfields cannot be used for this type of predefined +structure since the memory layout of individual bitfields is not defined +by +the C language. In addition, there are endian concerns where a compiler +will +change the bitfield ordering based on the machine type. The new ACPICA +interface eliminates these issues, and should be called after _PLD is +executed. ACPICA BZ 954. + +Implemented a change to allow a scope change to root (via "Scope (\)") +during +execution of module-level ASL code (code that is executed at table load +time.) Lin Ming. + +Added the Windows8/Server2012 string for the _OSI method. This change +adds +a +new _OSI string, "Windows 2012" for both Windows 8 and Windows Server +2012. + +Added header support for the new ACPI tables DBG2 (Debug Port Table Type +2) +and CSRT (Core System Resource Table). + +Added struct header support for the _FDE, _GRT, _GTM, and _SRT predefined +names. This simplifies access to the buffers returned by these predefined +names. Adds a new file, include/acbuffer.h. ACPICA BZ 956. + +GPE support: Removed an extraneous parameter from the various low-level +internal GPE functions. Tang Feng. + +Removed the linux makefiles from the unix packages. The generate/linux +makefiles are obsolete and have been removed from the unix tarball +release +packages. The replacement makefiles are under generate/unix, and there is +a +top-level makefile under the main acpica directory. ACPICA BZ 967, 912. + +Updates for Unix makefiles: +1) Add -D_FORTIFY_SOURCE=2 for gcc generation. Arjan van de Ven. +2) Update linker flags (move to end of command line) for AcpiExec +utility. +Guan Chao. + +Split ACPICA initialization functions to new file, utxfinit.c. Split from +utxface.c to improve modularity and reduce file size. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 93.5K Code, 25.3K Data, 118.8K Total + Debug Version: 173.7K Code, 74.0K Data, 247.7K Total + Current Release: + Non-Debug Version: 93.8K Code, 25.3K Data, 119.1K Total + Debug Version: 175.7K Code, 74.8K Data, 250.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a problem with constant folding for fixed-length constant +expressions. The constant-folding code was not being invoked for constant +expressions that allow the use of type 3/4/5 opcodes to generate +constants +for expressions such as ByteConstExpr, WordConstExpr, etc. This could +result +in the generation of invalid AML bytecode. ACPICA BZ 970. + +iASL: Fixed a generation issue on newer versions of Bison. Newer versions +apparently automatically emit some of the necessary externals. This +change +handles these versions in order to eliminate generation warnings. + +Disassembler: Added support to decode the DBG2 and CSRT ACPI tables. + +Disassembler: Add support to decode _PLD buffers. The decoded buffer +appears +within comments in the output file. + +Debugger: Fixed a regression with the "Threads" command where +AE_BAD_PARAMETER was always returned. + +---------------------------------------- +11 July 2012. Summary of changes for version 20120711: + +1) ACPICA Kernel-resident Subsystem: + +Fixed a possible fault in the return package object repair code. Fixes a +problem that can occur when a lone package object is wrapped with an +outer +package object in order to force conformance to the ACPI specification. +Can +affect these predefined names: _ALR, _MLS, _PSS, _TRT, _TSS, _PRT, _HPX, +_DLM, +_CSD, _PSD, _TSD. + +Removed code to disable/enable bus master arbitration (ARB_DIS bit in the +PM2_CNT register) in the ACPICA sleep/wake interfaces. Management of the +ARB_DIS bit must be implemented in the host-dependent C3 processor power +state +support. Note, ARB_DIS is obsolete and only applies to older chipsets, +both +Intel and other vendors. (for Intel: ICH4-M and earlier) + +This change removes the code to disable/enable bus master arbitration +during +suspend/resume. Use of the ARB_DIS bit in the optional PM2_CNT register +causes +resume problems on some machines. The change has been in use for over +seven +years within Linux. + +Implemented two new external interfaces to support host-directed dynamic +ACPI +table load and unload. They are intended to simplify the host +implementation +of hot-plug support: + AcpiLoadTable: Load an SSDT from a buffer into the namespace. + AcpiUnloadParentTable: Unload an SSDT via a named object owned by the +table. +See the ACPICA reference for additional details. Adds one new file, +components/tables/tbxfload.c + +Implemented and deployed two new interfaces for errors and warnings that +are +known to be caused by BIOS/firmware issues: + AcpiBiosError: Prints "ACPI Firmware Error" message. + AcpiBiosWarning: Prints "ACPI Firmware Warning" message. +Deployed these new interfaces in the ACPICA Table Manager code for ACPI +table +and FADT errors. Additional deployment to be completed as appropriate in +the +future. The associated conditional macros are ACPI_BIOS_ERROR and +ACPI_BIOS_WARNING. See the ACPICA reference for additional details. +ACPICA +BZ +843. + +Implicit notify support: ensure that no memory allocation occurs within a +critical region. This fix moves a memory allocation outside of the time +that a +spinlock is held. Fixes issues on systems that do not allow this +behavior. +Jung-uk Kim. + +Split exception code utilities and tables into a new file, +utilities/utexcep.c + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 93.1K Code, 25.1K Data, 118.2K Total + Debug Version: 172.9K Code, 73.6K Data, 246.5K Total + Current Release: + Non-Debug Version: 93.5K Code, 25.3K Data, 118.8K Total + Debug Version: 173.7K Code, 74.0K Data, 247.7K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a parser problem for hosts where EOF is defined as -1 instead +of +0. Jung-uk Kim. + +Debugger: Enhanced the "tables" command to emit additional information +about +the current set of ACPI tables, including the owner ID and flags decode. + +Debugger: Reimplemented the "unload" command to use the new +AcpiUnloadParentTable external interface. This command was disable +previously +due to need for an unload interface. + +AcpiHelp: Added a new option to decode ACPICA exception codes. The -e +option +will decode 16-bit hex status codes (ACPI_STATUS) to name strings. + +---------------------------------------- +20 June 2012. Summary of changes for version 20120620: + + +1) ACPICA Kernel-resident Subsystem: + +Implemented support to expand the "implicit notify" feature to allow +multiple +devices to be notified by a single GPE. This feature automatically +generates a +runtime device notification in the absence of a BIOS-provided GPE control +method (_Lxx/_Exx) or a host-installed handler for the GPE. Implicit +notify is +provided by ACPICA for Windows compatibility, and is a workaround for +BIOS +AML +code errors. See the description of the AcpiSetupGpeForWake interface in +the +APCICA reference. Bob Moore, Rafael Wysocki. ACPICA BZ 918. + +Changed some comments and internal function names to simplify and ensure +correctness of the Linux code translation. No functional changes. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 93.0K Code, 25.1K Data, 118.1K Total + Debug Version: 172.7K Code, 73.6K Data, 246.3K Total + Current Release: + Non-Debug Version: 93.1K Code, 25.1K Data, 118.2K Total + Debug Version: 172.9K Code, 73.6K Data, 246.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Added support to emit short, commented descriptions for the +ACPI +predefined names in order to improve the readability of the disassembled +output. ACPICA BZ 959. Changes include: + 1) Emit descriptions for all standard predefined names (_INI, _STA, +_PRW, +etc.) + 2) Emit generic descriptions for the special names (_Exx, _Qxx, etc.) + 3) Emit descriptions for the resource descriptor names (_MIN, _LEN, +etc.) + +AcpiSrc: Fixed several long-standing Linux code translation issues. +Argument +descriptions in function headers are now translated properly to lower +case +and +underscores. ACPICA BZ 961. Also fixes translation problems such as +these: +(old -> new) + i_aSL -> iASL + 00-7_f -> 00-7F + 16_k -> 16K + local_fADT -> local_FADT + execute_oSI -> execute_OSI + +iASL: Fixed a problem where null bytes were inadvertently emitted into +some +listing files. + +iASL: Added the existing debug options to the standard help screen. There +are +no longer two different help screens. ACPICA BZ 957. + +AcpiHelp: Fixed some typos in the various predefined name descriptions. +Also +expand some of the descriptions where appropriate. + +iASL: Fixed the -ot option (display compile times/statistics). Was not +working +properly for standard output; only worked for the debug file case. + +---------------------------------------- +18 May 2012. Summary of changes for version 20120518: + + +1) ACPICA Core Subsystem: + +Added a new OSL interface, AcpiOsWaitEventsComplete. This interface is +defined +to block until asynchronous events such as notifies and GPEs have +completed. +Within ACPICA, it is only called before a notify or GPE handler is +removed/uninstalled. It also may be useful for the host OS within related +drivers such as the Embedded Controller driver. See the ACPICA reference +for +additional information. ACPICA BZ 868. + +ACPI Tables: Added a new error message for a possible overflow failure +during +the conversion of FADT 32-bit legacy register addresses to internal +common +64- +bit GAS structure representation. The GAS has a one-byte "bit length" +field, +thus limiting the register length to 255 bits. ACPICA BZ 953. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 92.9K Code, 25.0K Data, 117.9K Total + Debug Version: 172.6K Code, 73.4K Data, 246.0K Total + Current Release: + Non-Debug Version: 93.0K Code, 25.1K Data, 118.1K Total + Debug Version: 172.7K Code, 73.6K Data, 246.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Added the ACPI 5.0 "PCC" keyword for use in the Register() ASL +macro. +This keyword was added late in the ACPI 5.0 release cycle and was not +implemented until now. + +Disassembler: Added support for Operation Region externals. Adds missing +support for operation regions that are defined in another table, and +referenced locally via a Field or BankField ASL operator. Now generates +the +correct External statement. + +Disassembler: Several additional fixes for the External() statement +generation +related to some ASL operators. Also, order the External() statements +alphabetically in the disassembler output. Fixes the External() +generation +for +the Create* field, Alias, and Scope operators: + 1) Create* buffer field operators - fix type mismatch warning on +disassembly + 2) Alias - implement missing External support + 3) Scope - fix to make sure all necessary externals are emitted. + +iASL: Improved pathname support. For include files, merge the prefix +pathname +with the file pathname and eliminate unnecessary components. Convert +backslashes in all pathnames to forward slashes, for readability. Include +file +pathname changes affect both #include and Include() type operators. + +iASL/DTC/Preprocessor: Gracefully handle early EOF. Handle an EOF at the +end +of a valid line by inserting a newline and then returning the EOF during +the +next call to GetNextLine. Prevents the line from being ignored due to EOF +condition. + +iASL: Implemented some changes to enhance the IDE support (-vi option.) +Error +and Warning messages are now correctly recognized for both the source +code +browser and the global error and warning counts. + +---------------------------------------- +20 April 2012. Summary of changes for version 20120420: + + +1) ACPICA Core Subsystem: + +Implemented support for multiple notify handlers. This change adds +support +to +allow multiple system and device notify handlers on Device, Thermal Zone, +and +Processor objects. This can simplify the host OS notification +implementation. +Also re-worked and restructured the entire notify support code to +simplify +handler installation, handler removal, notify event queuing, and notify +dispatch to handler(s). Note: there can still only be two global notify +handlers - one for system notifies and one for device notifies. There are +no +changes to the existing handler install/remove interfaces. Lin Ming, Bob +Moore, Rafael Wysocki. + +Fixed a regression in the package repair code where the object reference +count was calculated incorrectly. Regression was introduced in the commit +"Support to add Package wrappers". + +Fixed a couple possible memory leaks in the AML parser, in the error +recovery +path. Jesper Juhl, Lin Ming. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 92.9K Code, 25.0K Data, 117.9K Total + Debug Version: 172.5K Code, 73.2K Data, 245.7K Total + Current Release: + Non-Debug Version: 92.9K Code, 25.0K Data, 117.9K Total + Debug Version: 172.6K Code, 73.4K Data, 246.0K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a problem with the resource descriptor support where the +length +of the StartDependentFn and StartDependentFnNoPrio descriptors were not +included in cumulative descriptor offset, resulting in incorrect values +for +resource tags within resource descriptors appearing after a +StartDependent* +descriptor. Reported by Petr Vandrovec. ACPICA BZ 949. + +iASL and Preprocessor: Implemented full support for the #line directive +to +correctly track original source file line numbers through the .i +preprocessor +output file - for error and warning messages. + +iASL: Expand the allowable byte constants for address space IDs. +Previously, +the allowable range was 0x80-0xFF (user-defined spaces), now the range is +0x0A-0xFF to allow for custom and new IDs without changing the compiler. + +iASL: Add option to treat all warnings as errors (-we). ACPICA BZ 948. + +iASL: Add option to completely disable the preprocessor (-Pn). + +iASL: Now emit all error/warning messages to standard error (stderr) by +default (instead of the previous stdout). + +ASL Test Suite (ASLTS): Reduce iASL warnings due to use of Switch(). +Update +for resource descriptor offset fix above. Update/cleanup error output +routines. Enable and send iASL errors/warnings to an error logfile +(error.txt). Send all other iASL output to a logfile (compiler.txt). +Fixed +several extraneous "unrecognized operator" messages. + +---------------------------------------- +20 March 2012. Summary of changes for version 20120320: + + +1) ACPICA Core Subsystem: + +Enhanced the sleep/wake interfaces to optionally execute the _GTS method +(Going To Sleep) and the _BFS method (Back From Sleep). Windows +apparently +does not execute these methods, and therefore these methods are often +untested. It has been seen on some systems where the execution of these +methods causes errors and also prevents the machine from entering S5. It +is +therefore suggested that host operating systems do not execute these +methods +by default. In the future, perhaps these methods can be optionally +executed +based on the age of the system and/or what is the newest version of +Windows +that the BIOS asks for via _OSI. Changed interfaces: AcpiEnterSleepState +and +AcpileaveSleepStatePrep. See the ACPICA reference and Linux BZ 13041. Lin +Ming. + +Fixed a problem where the length of the local/common FADT was set too +early. +The local FADT table length cannot be set to the common length until the +original length has been examined. There is code that checks the table +length +and sets various fields appropriately. This can affect older machines +with +early FADT versions. For example, this can cause inadvertent writes to +the +CST_CNT register. Julian Anastasov. + +Fixed a mapping issue related to a physical table override. Use the +deferred +mapping mechanism for tables loaded via the physical override OSL +interface. +This allows for early mapping before the virtual memory manager is +available. +Thomas Renninger, Bob Moore. + +Enhanced the automatic return-object repair code: Repair a common problem +with +predefined methods that are defined to return a variable-length Package +of +sub-objects. If there is only one sub-object, some BIOS ASL code +mistakenly +simply returns the single object instead of a Package with one sub- +object. +This new support will repair this error by wrapping a Package object +around +the original object, creating the correct and expected Package with one +sub- +object. Names that can be repaired in this manner include: _ALR, _CSD, +_HPX, +_MLS, _PLD, _PRT, _PSS, _TRT, _TSS, _BCL, _DOD, _FIX, and _Sx. ACPICA BZ +939. + +Changed the exception code returned for invalid ACPI paths passed as +parameters to external interfaces such as AcpiEvaluateObject. Was +AE_BAD_PARAMETER, now is the more sensible AE_BAD_PATHNAME. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 93.0K Code, 25.0K Data, 118.0K Total + Debug Version: 172.5K Code, 73.2K Data, 245.7K Total + Current Release: + Non-Debug Version: 92.9K Code, 25.0K Data, 117.9K Total + Debug Version: 172.5K Code, 73.2K Data, 245.7K Total + + +2) iASL Compiler/Disassembler and Tools: + +iASL: Added the infrastructure and initial implementation of a integrated +C- +like preprocessor. This will simplify BIOS development process by +eliminating +the need for a separate preprocessing step during builds. On Windows, it +also +eliminates the need to install a separate C compiler. ACPICA BZ 761. Some +features including full #define() macro support are still under +development. +These preprocessor directives are supported: + #define + #elif + #else + #endif + #error + #if + #ifdef + #ifndef + #include + #pragma message + #undef + #warning +In addition, these new command line options are supported: + -D Define symbol for preprocessor use + -li Create preprocessed output file (*.i) + -P Preprocess only and create preprocessor output file (*.i) + +Table Compiler: Fixed a problem where the equals operator within an +expression +did not work properly. + +Updated iASL to use the current versions of Bison/Flex. Updated the +Windows +project file to invoke these tools from the standard location. ACPICA BZ +904. +Versions supported: + Flex for Windows: V2.5.4 + Bison for Windows: V2.4.1 + +---------------------------------------- +15 February 2012. Summary of changes for version 20120215: + + +1) ACPICA Core Subsystem: + +There have been some major changes to the sleep/wake support code, as +described below (a - e). + +a) The AcpiLeaveSleepState has been split into two interfaces, similar to +AcpiEnterSleepStatePrep and AcpiEnterSleepState. The new interface is +AcpiLeaveSleepStatePrep. This allows the host to perform actions between +the +time the _BFS method is called and the _WAK method is called. NOTE: all +hosts +must update their wake/resume code or else sleep/wake will not work +properly. +Rafael Wysocki. + +b) In AcpiLeaveSleepState, now enable all runtime GPEs before calling the +_WAK +method. Some machines require that the GPEs are enabled before the _WAK +method +is executed. Thomas Renninger. + +c) In AcpiLeaveSleepState, now always clear the WAK_STS (wake status) +bit. +Some BIOS code assumes that WAK_STS will be cleared on resume and use it +to +determine whether the system is rebooting or resuming. Matthew Garrett. + +d) Move the invocations of _GTS (Going To Sleep) and _BFS (Back From +Sleep) to +match the ACPI specification requirement. Rafael Wysocki. + +e) Implemented full support for the ACPI 5.0 SleepStatus and SleepControl +registers within the V5 FADT. This support adds two new files: +hardware/hwesleep.c implements the support for the new registers. Moved +all +sleep/wake external interfaces to hardware/hwxfsleep.c. + + +Added a new OSL interface for ACPI table overrides, +AcpiOsPhysicalTableOverride. This interface allows the host to override a +table via a physical address, instead of the logical address required by +AcpiOsTableOverride. This simplifies the host implementation. Initial +implementation by Thomas Renninger. The ACPICA implementation creates a +single +shared function for table overrides that attempts both a logical and a +physical override. + +Expanded the OSL memory read/write interfaces to 64-bit data +(AcpiOsReadMemory, AcpiOsWriteMemory.) This enables full 64-bit memory +transfer support for GAS register structures passed to AcpiRead and +AcpiWrite. + +Implemented the ACPI_REDUCED_HARDWARE option to allow the creation of a +custom +build of ACPICA that supports only the ACPI 5.0 reduced hardware (SoC) +model. +See the ACPICA reference for details. ACPICA BZ 942. This option removes +about +10% of the code and 5% of the static data, and the following hardware +ACPI +features become unavailable: + PM Event and Control registers + SCI interrupt (and handler) + Fixed Events + General Purpose Events (GPEs) + Global Lock + ACPI PM timer + FACS table (Waking vectors and Global Lock) + +Updated the unix tarball directory structure to match the ACPICA git +source +tree. This ensures that the generic unix makefiles work properly (in +generate/unix). Also updated the Linux makefiles to match. ACPICA BZ +867. + +Updated the return value of the _REV predefined method to integer value 5 +to +reflect ACPI 5.0 support. + +Moved the external ACPI PM timer interface prototypes to the public +acpixf.h +file where they belong. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 92.8K Code, 24.9K Data, 117.7K Total + Debug Version: 171.7K Code, 72.9K Data, 244.5K Total + Current Release: + Non-Debug Version: 93.0K Code, 25.0K Data, 118.0K Total + Debug Version: 172.5K Code, 73.2K Data, 245.7K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Fixed a problem with the new ACPI 5.0 serial resource +descriptors (I2C, SPI, UART) where the resource produce/consumer bit was +incorrectly displayed. + +AcpiHelp: Add display of ACPI/PNP device IDs that are defined in the ACPI +specification. + +---------------------------------------- +11 January 2012. Summary of changes for version 20120111: + + +1) ACPICA Core Subsystem: + +Implemented a new mechanism to allow host device drivers to check for +address +range conflicts with ACPI Operation Regions. Both SystemMemory and +SystemIO +address spaces are supported. A new external interface, +AcpiCheckAddressRange, +allows drivers to check an address range against the ACPI namespace. See +the +ACPICA reference for additional details. Adds one new file, +utilities/utaddress.c. Lin Ming, Bob Moore. + +Fixed several issues with the ACPI 5.0 FADT support: Add the sleep +Control +and +Status registers, update the ACPI 5.0 flags, and update internal data +structures to handle an FADT larger than 256 bytes. The size of the ACPI +5.0 +FADT is 268 bytes. + +Updated all ACPICA copyrights and signons to 2012. Added the 2012 +copyright to +all module headers and signons, including the standard Linux header. This +affects virtually every file in the ACPICA core subsystem, iASL compiler, +and +all ACPICA utilities. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release: + Non-Debug Version: 92.3K Code, 24.9K Data, 117.2K Total + Debug Version: 170.8K Code, 72.6K Data, 243.4K Total + Current Release: + Non-Debug Version: 92.8K Code, 24.9K Data, 117.7K Total + Debug Version: 171.7K Code, 72.9K Data, 244.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: fixed a problem with the automatic resource tag generation +support. Fixes a problem where the resource tags are inadvertently not +constructed if the table being disassembled contains external references +to +control methods. Moved the actual construction of the tags to after the +final +namespace is constructed (after 2nd parse is invoked due to external +control +method references.) ACPICA BZ 941. + +Table Compiler: Make all "generic" operators caseless. These are the +operators +like UINT8, String, etc. Making these caseless improves ease-of-use. +ACPICA BZ +934. + +---------------------------------------- +23 November 2011. Summary of changes for version 20111123: + +0) ACPI 5.0 Support: + +This release contains full support for the ACPI 5.0 specification, as +summarized below. + +Reduced Hardware Support: +------------------------- + +This support allows for ACPI systems without the usual ACPI hardware. +This +support is enabled by a flag in the revision 5 FADT. If it is set, ACPICA +will +not attempt to initialize or use any of the usual ACPI hardware. Note, +when +this flag is set, all of the following ACPI hardware is assumed to be not +present and is not initialized or accessed: + + General Purpose Events (GPEs) + Fixed Events (PM1a/PM1b and PM Control) + Power Management Timer and Console Buttons (power/sleep) + Real-time Clock Alarm + Global Lock + System Control Interrupt (SCI) + The FACS is assumed to be non-existent + +ACPI Tables: +------------ + +All new tables and updates to existing tables are fully supported in the +ACPICA headers (for use by device drivers), the disassembler, and the +iASL +Data Table Compiler. ACPI 5.0 defines these new tables: + + BGRT /* Boot Graphics Resource Table */ + DRTM /* Dynamic Root of Trust for Measurement table */ + FPDT /* Firmware Performance Data Table */ + GTDT /* Generic Timer Description Table */ + MPST /* Memory Power State Table */ + PCCT /* Platform Communications Channel Table */ + PMTT /* Platform Memory Topology Table */ + RASF /* RAS Feature table */ + +Operation Regions/SpaceIDs: +--------------------------- + +All new operation regions are fully supported by the iASL compiler, the +disassembler, and the ACPICA runtime code (for dispatch to region +handlers.) +The new operation region Space IDs are: + + GeneralPurposeIo + GenericSerialBus + +Resource Descriptors: +--------------------- + +All new ASL resource descriptors are fully supported by the iASL +compiler, +the +ASL/AML disassembler, and the ACPICA runtime Resource Manager code +(including +all new predefined resource tags). New descriptors are: + + FixedDma + GpioIo + GpioInt + I2cSerialBus + SpiSerialBus + UartSerialBus + +ASL/AML Operators, New and Modified: +------------------------------------ + +One new operator is added, the Connection operator, which is used to +associate +a GeneralPurposeIo or GenericSerialBus resource descriptor with +individual +field objects within an operation region. Several new protocols are +associated +with the AccessAs operator. All are fully supported by the iASL compiler, +disassembler, and runtime ACPICA AML interpreter: + + Connection // Declare Field Connection +attributes + AccessAs: AttribBytes (n) // Read/Write N-Bytes Protocol + AccessAs: AttribRawBytes (n) // Raw Read/Write N-Bytes +Protocol + AccessAs: AttribRawProcessBytes (n) // Raw Process Call Protocol + RawDataBuffer // Data type for Vendor Data +fields + +Predefined ASL/AML Objects: +--------------------------- + +All new predefined objects/control-methods are supported by the iASL +compiler +and the ACPICA runtime validation/repair (arguments and return values.) +New +predefined names include the following: + +Standard Predefined Names (Objects or Control Methods): + _AEI, _CLS, _CPC, _CWS, _DEP, + _DLM, _EVT, _GCP, _CRT, _GWS, + _HRV, _PRE, _PSE, _SRT, _SUB. + +Resource Tags (Names used to access individual fields within resource +descriptors): + _DBT, _DPL, _DRS, _END, _FLC, + _IOR, _LIN, _MOD, _PAR, _PHA, + _PIN, _PPI, _POL, _RXL, _SLV, + _SPE, _STB, _TXL, _VEN. + +ACPICA External Interfaces: +--------------------------- + +Several new interfaces have been defined for use by ACPI-related device +drivers and other host OS services: + +AcpiAcquireMutex and AcpiReleaseMutex: These interfaces allow the host OS +to +acquire and release AML mutexes that are defined in the DSDT/SSDT tables +provided by the BIOS. They are intended to be used in conjunction with +the +ACPI 5.0 _DLM (Device Lock Method) in order to provide transaction-level +mutual exclusion with the AML code/interpreter. + +AcpiGetEventResources: Returns the (formatted) resource descriptors as +defined +by the ACPI 5.0 _AEI object (ACPI Event Information). This object +provides +resource descriptors associated with hardware-reduced platform events, +similar +to the AcpiGetCurrentResources interface. + +Operation Region Handlers: For General Purpose IO and Generic Serial Bus +operation regions, information about the Connection() object and any +optional +length information is passed to the region handler within the Context +parameter. + +AcpiBufferToResource: This interface converts a raw AML buffer containing +a +resource template or resource descriptor to the ACPI_RESOURCE internal +format +suitable for use by device drivers. Can be used by an operation region +handler +to convert the Connection() buffer object into a ACPI_RESOURCE. + +Miscellaneous/Tools/TestSuites: +------------------------------- + +Support for extended _HID names (Four alpha characters instead of three). +Support for ACPI 5.0 features in the AcpiExec and AcpiHelp utilities. +Support for ACPI 5.0 features in the ASLTS test suite. +Fully updated documentation (ACPICA and iASL reference documents.) + +ACPI Table Definition Language: +------------------------------- + +Support for this language was implemented and released as a subsystem of +the +iASL compiler in 2010. (See the iASL compiler User Guide.) + + +Non-ACPI 5.0 changes for this release: +-------------------------------------- + +1) ACPICA Core Subsystem: + +Fix a problem with operation region declarations where a failure can +occur +if +the region name and an argument that evaluates to an object (such as the +region address) are in different namespace scopes. Lin Ming, ACPICA BZ +937. + +Do not abort an ACPI table load if an invalid space ID is found within. +This +will be caught later if the offending method is executed. ACPICA BZ 925. + +Fixed an issue with the FFixedHW space ID where the ID was not always +recognized properly (Both ACPICA and iASL). ACPICA BZ 926. + +Fixed a problem with the 32-bit generation of the unix-specific OSL +(osunixxf.c). Lin Ming, ACPICA BZ 936. + +Several changes made to enable generation with the GCC 4.6 compiler. +ACPICA BZ +935. + +New error messages: Unsupported I/O requests (not 8/16/32 bit), and +Index/Bank +field registers out-of-range. + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented the __PATH__ operator, which returns the full pathname +of +the current source file. + +AcpiHelp: Automatically display expanded keyword information for all ASL +operators. + +Debugger: Add "Template" command to disassemble/dump resource template +buffers. + +Added a new master script to generate and execute the ASLTS test suite. +Automatically handles 32- and 64-bit generation. See tests/aslts.sh + +iASL: Fix problem with listing generation during processing of the +Switch() +operator where AML listing was disabled until the entire Switch block was +completed. + +iASL: Improve support for semicolon statement terminators. Fix "invalid +character" message for some cases when the semicolon is used. Semicolons +are +now allowed after every grammar element. ACPICA BZ 927. + +iASL: Fixed some possible aliasing warnings during generation. ACPICA BZ +923. + +Disassembler: Fix problem with disassembly of the DataTableRegion +operator +where an inadvertent "Unhandled deferred opcode" message could be +generated. + +3) Example Code and Data Size + +These are the sizes for the OS-independent acpica.lib produced by the +Microsoft Visual C++ 9.0 32-bit compiler. The debug version of the code +includes the debug output trace mechanism and has a much larger code and +data +size. + + Previous Release: + Non-Debug Version: 90.2K Code, 23.9K Data, 114.1K Total + Debug Version: 165.6K Code, 68.4K Data, 234.0K Total + Current Release: + Non-Debug Version: 92.3K Code, 24.9K Data, 117.2K Total + Debug Version: 170.8K Code, 72.6K Data, 243.4K Total + +---------------------------------------- +22 September 2011. Summary of changes for version 20110922: + +0) ACPI 5.0 News: + +Support for ACPI 5.0 in ACPICA has been underway for several months and +will +be released at the same time that ACPI 5.0 is officially released. + +The ACPI 5.0 specification is on track for release in the next few +months. + +1) ACPICA Core Subsystem: + +Fixed a problem where the maximum sleep time for the Sleep() operator was +intended to be limited to two seconds, but was inadvertently limited to +20 +seconds instead. + +Linux and Unix makefiles: Added header file dependencies to ensure +correct +generation of ACPICA core code and utilities. Also simplified the +makefiles +considerably through the use of the vpath variable to specify search +paths. +ACPICA BZ 924. + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented support to check the access length for all fields +created to +access named Resource Descriptor fields. For example, if a resource field +is +defined to be two bits, a warning is issued if a CreateXxxxField() is +used +with an incorrect bit length. This is implemented for all current +resource +descriptor names. ACPICA BZ 930. + +Disassembler: Fixed a byte ordering problem with the output of 24-bit and +56- +bit integers. + +iASL: Fixed a couple of issues associated with variable-length package +objects. 1) properly handle constants like One, Ones, Zero -- do not make +a +VAR_PACKAGE when these are used as a package length. 2) Allow the +VAR_PACKAGE +opcode (in addition to PACKAGE) when validating object types for +predefined +names. + +iASL: Emit statistics for all output files (instead of just the ASL input +and +AML output). Includes listings, hex files, etc. + +iASL: Added -G option to the table compiler to allow the compilation of +custom +ACPI tables. The only part of a table that is required is the standard +36- +byte +ACPI header. + +AcpiXtract: Ported to the standard ACPICA environment (with ACPICA +headers), +which also adds correct 64-bit support. Also, now all output filenames +are +completely lower case. + +AcpiExec: Ignore any non-AML tables (tables other than DSDT or SSDT) when +loading table files. A warning is issued for any such tables. The only +exception is an FADT. This also fixes a possible fault when attempting to +load +non-AML tables. ACPICA BZ 932. + +AcpiHelp: Added the AccessAs and Offset operators. Fixed a problem where +a +missing table terminator could cause a fault when using the -p option. + +AcpiSrc: Fixed a possible divide-by-zero fault when generating file +statistics. + +3) Example Code and Data Size + +These are the sizes for the OS-independent acpica.lib produced by the +Microsoft Visual C++ 9.0 32-bit compiler. The debug version of the code +includes the debug output trace mechanism and has a much larger code and +data +size. + + Previous Release (VC 9.0): + Non-Debug Version: 90.2K Code, 23.9K Data, 114.1K Total + Debug Version: 165.6K Code, 68.4K Data, 234.0K Total + Current Release (VC 9.0): + Non-Debug Version: 90.2K Code, 23.9K Data, 114.1K Total + Debug Version: 165.6K Code, 68.4K Data, 234.0K Total + + +---------------------------------------- +23 June 2011. Summary of changes for version 20110623: + +1) ACPI CA Core Subsystem: + +Updated the predefined name repair mechanism to not attempt repair of a +_TSS +return object if a _PSS object is present. We can only sort the _TSS +return +package if there is no _PSS within the same scope. This is because if +_PSS +is +present, the ACPI specification dictates that the _TSS Power Dissipation +field +is to be ignored, and therefore some BIOSs leave garbage values in the +_TSS +Power field(s). In this case, it is best to just return the _TSS package +as- +is. Reported by, and fixed with assistance from Fenghua Yu. + +Added an option to globally disable the control method return value +validation +and repair. This runtime option can be used to disable return value +repair +if +this is causing a problem on a particular machine. Also added an option +to +AcpiExec (-dr) to set this disable flag. + +All makefiles and project files: Major changes to improve generation of +ACPICA +tools. ACPICA BZ 912: + Reduce default optimization levels to improve compatibility + For Linux, add strict-aliasing=0 for gcc 4 + Cleanup and simplify use of command line defines + Cleanup multithread library support + Improve usage messages + +Linux-specific header: update handling of THREAD_ID and pthread. For the +32- +bit case, improve casting to eliminate possible warnings, especially with +the +acpica tools. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release (VC 9.0): + Non-Debug Version: 90.1K Code, 23.9K Data, 114.0K Total + Debug Version: 165.6K Code, 68.4K Data, 234.0K Total + Current Release (VC 9.0): + Non-Debug Version: 90.2K Code, 23.9K Data, 114.1K Total + Debug Version: 165.6K Code, 68.4K Data, 234.0K Total + +2) iASL Compiler/Disassembler and Tools: + +With this release, a new utility named "acpihelp" has been added to the +ACPICA +package. This utility summarizes the ACPI specification chapters for the +ASL +and AML languages. It generates under Linux/Unix as well as Windows, and +provides the following functionality: + Find/display ASL operator(s) -- with description and syntax. + Find/display ASL keyword(s) -- with exact spelling and descriptions. + Find/display ACPI predefined name(s) -- with description, number + of arguments, and the return value data type. + Find/display AML opcode name(s) -- with opcode, arguments, and +grammar. + Decode/display AML opcode -- with opcode name, arguments, and +grammar. + +Service Layers: Make multi-thread support configurable. Conditionally +compile +the multi-thread support so that threading libraries will not be linked +if +not +necessary. The only tool that requires multi-thread support is AcpiExec. + +iASL: Update yyerrror/AslCompilerError for "const" errors. Newer versions +of +Bison appear to want the interface to yyerror to be a const char * (or at +least this is a problem when generating iASL on some systems.) ACPICA BZ +923 +Pierre Lejeune. + +Tools: Fix for systems where O_BINARY is not defined. Only used for +Windows +versions of the tools. + +---------------------------------------- +27 May 2011. Summary of changes for version 20110527: + +1) ACPI CA Core Subsystem: + +ASL Load() operator: Reinstate most restrictions on the incoming ACPI +table +signature. Now, only allow SSDT, OEMx, and a null signature. History: + 1) Originally, we checked the table signature for "SSDT" or "PSDT". + (PSDT is now obsolete.) + 2) We added support for OEMx tables, signature "OEM" plus a fourth + "don't care" character. + 3) Valid tables were encountered with a null signature, so we just + gave up on validating the signature, (05/2008). + 4) We encountered non-AML tables such as the MADT, which caused + interpreter errors and kernel faults. So now, we once again allow + only SSDT, OEMx, and now, also a null signature. (05/2011). + +Added the missing _TDL predefined name to the global name list in order +to +enable validation. Affects both the core ACPICA code and the iASL +compiler. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug +version of the code includes the debug output trace mechanism and has a +much +larger code and data size. + + Previous Release (VC 9.0): + Non-Debug Version: 90.0K Code, 23.8K Data, 113.8K Total + Debug Version: 164.5K Code, 68.0K Data, 232.5K Total + Current Release (VC 9.0): + Non-Debug Version: 90.1K Code, 23.9K Data, 114.0K Total + Debug Version: 165.6K Code, 68.4K Data, 234.0K Total + +2) iASL Compiler/Disassembler and Tools: + +Debugger/AcpiExec: Implemented support for "complex" method arguments on +the +debugger command line. This adds support beyond simple integers -- +including +Strings, Buffers, and Packages. Includes support for nested packages. +Increased the default command line buffer size to accommodate these +arguments. +See the ACPICA reference for details and syntax. ACPICA BZ 917. + +Debugger/AcpiExec: Implemented support for "default" method arguments for +the +Execute/Debug command. Now, the debugger will always invoke a control +method +with the required number of arguments -- even if the command line +specifies +none or insufficient arguments. It uses default integer values for any +missing +arguments. Also fixes a bug where only six method arguments maximum were +supported instead of the required seven. + +Debugger/AcpiExec: Add a maximum buffer length parameter to AcpiOsGetLine +and +also return status in order to prevent buffer overruns. See the ACPICA +reference for details and syntax. ACPICA BZ 921 + +iASL: Cleaned up support for Berkeley yacc. A general cleanup of code and +makefiles to simplify support for the two different but similar parser +generators, bison and yacc. + +Updated the generic unix makefile for gcc 4. The default gcc version is +now +expected to be 4 or greater, since options specific to gcc 4 are used. + +---------------------------------------- +13 April 2011. Summary of changes for version 20110413: + +1) ACPI CA Core Subsystem: + +Implemented support to execute a so-called "orphan" _REG method under the +EC +device. This change will force the execution of a _REG method underneath +the +EC +device even if there is no corresponding operation region of type +EmbeddedControl. Fixes a problem seen on some machines and apparently is +compatible with Windows behavior. ACPICA BZ 875. + +Added more predefined methods that are eligible for automatic NULL +package +element removal. This change adds another group of predefined names to +the +list +of names that can be repaired by having NULL package elements dynamically +removed. This group are those methods that return a single variable- +length +package containing simple data types such as integers, buffers, strings. +This +includes: _ALx, _BCL, _CID,_ DOD, _EDL, _FIX, _PCL, _PLD, _PMD, _PRx, +_PSL, +_Sx, +and _TZD. ACPICA BZ 914. + +Split and segregated all internal global lock functions to a new file, +evglock.c. + +Updated internal address SpaceID for DataTable regions. Moved this +internal +space +id in preparation for ACPI 5.0 changes that will include some new space +IDs. +This +change should not affect user/host code. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib +produced by the Microsoft Visual C++ 9.0 32-bit compiler. The debug +version of +the code includes the debug output trace mechanism and has a much larger +code +and +data size. + + Previous Release (VC 9.0): + Non-Debug Version: 89.8K Code, 23.8K Data, 113.6K Total + Debug Version: 164.2K Code, 67.9K Data, 232.1K Total + Current Release (VC 9.0): + Non-Debug Version: 90.0K Code, 23.8K Data, 113.8K Total + Debug Version: 164.5K Code, 68.0K Data, 232.5K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL/DTC: Major update for new grammar features. Allow generic data types +in +custom ACPI tables. Field names are now optional. Any line can be split +to +multiple lines using the continuation char (\). Large buffers now use +line- +continuation character(s) and no colon on the continuation lines. See the +grammar +update in the iASL compiler reference. ACPI BZ 910,911. Lin Ming, Bob +Moore. + +iASL: Mark ASL "Return()" and the simple "Return" as "Null" return +statements. +Since the parser stuffs a "zero" as the return value for these statements +(due +to +the underlying AML grammar), they were seen as "return with value" by the +iASL +semantic checking. They are now seen correctly as "null" return +statements. + +iASL: Check if a_REG declaration has a corresponding Operation Region. +Adds a +check for each _REG to ensure that there is in fact a corresponding +operation +region declaration in the same scope. If not, the _REG method is not very +useful +since it probably won't be executed. ACPICA BZ 915. + +iASL/DTC: Finish support for expression evaluation. Added a new +expression +parser +that implements c-style operator precedence and parenthesization. ACPICA +bugzilla +908. + +Disassembler/DTC: Remove support for () and <> style comments in data +tables. +Now +that DTC has full expression support, we don't want to have comment +strings +that +start with a parentheses or a less-than symbol. Now, only the standard /* +and +// +comments are supported, as well as the bracket [] comments. + +AcpiXtract: Fix for RSDP and dynamic SSDT extraction. These tables have +"unusual" +headers in the acpidump file. Update the header validation to support +these +tables. Problem introduced in previous AcpiXtract version in the change +to +support "wrong checksum" error messages emitted by acpidump utility. + +iASL: Add a * option to generate all template files (as a synonym for +ALL) +as +in +"iasl -T *" or "iasl -T ALL". + +iASL/DTC: Do not abort compiler on fatal errors. We do not want to +completely +abort the compiler on "fatal" errors, simply should abort the current +compile. +This allows multiple compiles with a single (possibly wildcard) compiler +invocation. + +---------------------------------------- +16 March 2011. Summary of changes for version 20110316: + +1) ACPI CA Core Subsystem: + +Fixed a problem caused by a _PRW method appearing at the namespace root +scope +during the setup of wake GPEs. A fault could occur if a _PRW directly +under +the +root object was passed to the AcpiSetupGpeForWake interface. Lin Ming. + +Implemented support for "spurious" Global Lock interrupts. On some +systems, a +global lock interrupt can occur without the pending flag being set. Upon +a +GL +interrupt, we now ensure that a thread is actually waiting for the lock +before +signaling GL availability. Rafael Wysocki, Bob Moore. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib +produced by the Microsoft Visual C++ 9.0 32-bit compiler. The debug +version of +the code includes the debug output trace mechanism and has a much larger +code +and +data size. + + Previous Release (VC 9.0): + Non-Debug Version: 89.7K Code, 23.7K Data, 113.4K Total + Debug Version: 163.9K Code, 67.5K Data, 231.4K Total + Current Release (VC 9.0): + Non-Debug Version: 89.8K Code, 23.8K Data, 113.6K Total + Debug Version: 164.2K Code, 67.9K Data, 232.1K Total + +2) iASL Compiler/Disassembler and Tools: + +Implemented full support for the "SLIC" ACPI table. Includes support in +the +header files, disassembler, table compiler, and template generator. Bob +Moore, +Lin Ming. + +AcpiXtract: Correctly handle embedded comments and messages from +AcpiDump. +Apparently some or all versions of acpidump will occasionally emit a +comment +like +"Wrong checksum", etc., into the dump file. This was causing problems for +AcpiXtract. ACPICA BZ 905. + +iASL: Fix the Linux makefile by removing an inadvertent double file +inclusion. +ACPICA BZ 913. + +AcpiExec: Update installation of operation region handlers. Install one +handler +for a user-defined address space. This is used by the ASL test suite +(ASLTS). + +---------------------------------------- +11 February 2011. Summary of changes for version 20110211: + +1) ACPI CA Core Subsystem: + +Added a mechanism to defer _REG methods for some early-installed +handlers. +Most user handlers should be installed before call to +AcpiEnableSubsystem. +However, Event handlers and region handlers should be installed after +AcpiInitializeObjects. Override handlers for the "default" regions should +be +installed early, however. This change executes all _REG methods for the +default regions (Memory/IO/PCI/DataTable) simultaneously to prevent any +chicken/egg issues between them. ACPICA BZ 848. + +Implemented an optimization for GPE detection. This optimization will +simply +ignore GPE registers that contain no enabled GPEs -- there is no need to +read the register since this information is available internally. This +becomes more important on machines with a large GPE space. ACPICA +bugzilla +884. Lin Ming. Suggestion from Joe Liu. + +Removed all use of the highly unreliable FADT revision field. The +revision +number in the FADT has been found to be completely unreliable and cannot +be +trusted. Only the actual table length can be used to infer the version. +This +change updates the ACPICA core and the disassembler so that both no +longer +even look at the FADT version and instead depend solely upon the FADT +length. + +Fix an unresolved name issue for the no-debug and no-error-message source +generation cases. The _AcpiModuleName was left undefined in these cases, +but +it is actually needed as a parameter to some interfaces. Define +_AcpiModuleName as a null string in these cases. ACPICA Bugzilla 888. + +Split several large files (makefiles and project files updated) + utglobal.c -> utdecode.c + dbcomds.c -> dbmethod.c dbnames.c + dsopcode.c -> dsargs.c dscontrol.c + dsload.c -> dsload2.c + aslanalyze.c -> aslbtypes.c aslwalks.c + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release (VC 9.0): + Non-Debug Version: 89.7K Code, 23.7K Data, 113.4K Total + Debug Version: 163.9K Code, 67.5K Data, 231.4K Total + Current Release (VC 9.0): + Non-Debug Version: 89.7K Code, 23.7K Data, 113.4K Total + Debug Version: 163.9K Code, 67.5K Data, 231.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented the predefined macros __LINE__, __FILE__, and __DATE__. +These are useful C-style macros with the standard definitions. ACPICA +bugzilla 898. + +iASL/DTC: Added support for integer expressions and labels. Support for +full +expressions for all integer fields in all ACPI tables. Support for labels +in +"generic" portions of tables such as UEFI. See the iASL reference manual. + +Debugger: Added a command to display the status of global handlers. The +"handlers" command will display op region, fixed event, and miscellaneous +global handlers. installation status -- and for op regions, whether +default +or user-installed handler will be used. + +iASL: Warn if reserved method incorrectly returns a value. Many +predefined +names are defined such that they do not return a value. If implemented as +a +method, issue a warning if such a name explicitly returns a value. ACPICA +Bugzilla 855. + +iASL: Added detection of GPE method name conflicts. Detects a conflict +where +there are two GPE methods of the form _Lxy and _Exy in the same scope. +(For +example, _L1D and _E1D in the same scope.) ACPICA bugzilla 848. + +iASL/DTC: Fixed a couple input scanner issues with comments and line +numbers. Comment remover could get confused and miss a comment ending. +Fixed +a problem with line counter maintenance. + +iASL/DTC: Reduced the severity of some errors from fatal to error. There +is +no need to abort on simple errors within a field definition. + +Debugger: Simplified the output of the help command. All help output now +in +a single screen, instead of help subcommands. ACPICA Bugzilla 897. + +---------------------------------------- +12 January 2011. Summary of changes for version 20110112: + +1) ACPI CA Core Subsystem: + +Fixed a race condition between method execution and namespace walks that +can +possibly cause a fault. The problem was apparently introduced in version +20100528 as a result of a performance optimization that reduces the +number +of +namespace walks upon method exit by using the delete_namespace_subtree +function instead of the delete_namespace_by_owner function used +previously. +Bug is a missing namespace lock in the delete_namespace_subtree function. +dana.myers@oracle.com + +Fixed several issues and a possible fault with the automatic "serialized" +method support. History: This support changes a method to "serialized" on +the +fly if the method generates an AE_ALREADY_EXISTS error, indicating the +possibility that it cannot handle reentrancy. This fix repairs a couple +of +issues seen in the field, especially on machines with many cores: + + 1) Delete method children only upon the exit of the last thread, + so as to not delete objects out from under other running threads + (and possibly causing a fault.) + 2) Set the "serialized" bit for the method only upon the exit of the + Last thread, so as to not cause deadlock when running threads + attempt to exit. + 3) Cleanup the use of the AML "MethodFlags" and internal method flags + so that there is no longer any confusion between the two. + + Lin Ming, Bob Moore. Reported by dana.myers@oracle.com. + +Debugger: Now lock the namespace for duration of a namespace dump. +Prevents +issues if the namespace is changing dynamically underneath the debugger. +Especially affects temporary namespace nodes, since the debugger displays +these also. + +Updated the ordering of include files. The ACPICA headers should appear +before any compiler-specific headers (stdio.h, etc.) so that acenv.h can +set +any necessary compiler-specific defines, etc. Affects the ACPI-related +tools +and utilities. + +Updated all ACPICA copyrights and signons to 2011. Added the 2011 +copyright +to all module headers and signons, including the Linux header. This +affects +virtually every file in the ACPICA core subsystem, iASL compiler, and all +utilities. + +Added project files for MS Visual Studio 2008 (VC++ 9.0). The original +project files for VC++ 6.0 are now obsolete. New project files can be +found +under acpica/generate/msvc9. See acpica/generate/msvc9/readme.txt for +details. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release (VC 6.0): + Non-Debug Version: 89.8K Code, 18.9K Data, 108.7K Total + Debug Version: 166.6K Code, 52.1K Data, 218.7K Total + Current Release (VC 9.0): + Non-Debug Version: 89.7K Code, 23.7K Data, 113.4K Total + Debug Version: 163.9K Code, 67.5K Data, 231.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Added generic data types to the Data Table compiler. Add "generic" +data +types such as UINT32, String, Unicode, etc., to simplify the generation +of +platform-defined tables such as UEFI. Lin Ming. + +iASL: Added listing support for the Data Table Compiler. Adds listing +support +(-l) to display actual binary output for each line of input code. + +---------------------------------------- +09 December 2010. Summary of changes for version 20101209: + +1) ACPI CA Core Subsystem: + +Completed the major overhaul of the GPE support code that was begun in +July +2010. Major features include: removal of _PRW execution in ACPICA (host +executes _PRWs anyway), cleanup of "wake" GPE interfaces and processing, +changes to existing interfaces, simplification of GPE handler operation, +and +a handful of new interfaces: + + AcpiUpdateAllGpes + AcpiFinishGpe + AcpiSetupGpeForWake + AcpiSetGpeWakeMask + One new file, evxfgpe.c to consolidate all external GPE interfaces. + +See the ACPICA Programmer Reference for full details and programming +information. See the new section 4.4 "General Purpose Event (GPE) +Support" +for a full overview, and section 8.7 "ACPI General Purpose Event +Management" +for programming details. ACPICA BZ 858,870,877. Matthew Garrett, Lin +Ming, +Bob Moore, Rafael Wysocki. + +Implemented a new GPE feature for Windows compatibility, the "Implicit +Wake +GPE Notify". This feature will automatically issue a Notify(2) on a +device +when a Wake GPE is received if there is no corresponding GPE method or +handler. ACPICA BZ 870. + +Fixed a problem with the Scope() operator during table parse and load +phase. +During load phase (table load or method execution), the scope operator +should +not enter the target into the namespace. Instead, it should open a new +scope +at the target location. Linux BZ 19462, ACPICA BZ 882. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 89.8K Code, 18.9K Data, 108.7K Total + Debug Version: 166.6K Code, 52.1K Data, 218.7K Total + Current Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Relax the alphanumeric restriction on _CID strings. These strings +are +"bus-specific" per the ACPI specification, and therefore any characters +are +acceptable. The only checks that can be performed are for a null string +and +perhaps for a leading asterisk. ACPICA BZ 886. + +iASL: Fixed a problem where a syntax error that caused a premature EOF +condition on the source file emitted a very confusing error message. The +premature EOF is now detected correctly. ACPICA BZ 891. + +Disassembler: Decode the AccessSize within a Generic Address Structure +(byte +access, word access, etc.) Note, this field does not allow arbitrary bit +access, the size is encoded as 1=byte, 2=word, 3=dword, and 4=qword. + +New: AcpiNames utility - Example namespace dump utility. Shows an example +of +ACPICA configuration for a minimal namespace dump utility. Uses table and +namespace managers, but no AML interpreter. Does not add any +functionality +over AcpiExec, it is a subset of AcpiExec. The purpose is to show how to +partition and configure ACPICA. ACPICA BZ 883. + +AML Debugger: Increased the debugger buffer size for method return +objects. +Was 4K, increased to 16K. Also enhanced error messages for debugger +method +execution, including the buffer overflow case. + +---------------------------------------- +13 October 2010. Summary of changes for version 20101013: + +1) ACPI CA Core Subsystem: + +Added support to clear the PCIEXP_WAKE event. When clearing ACPI events, +now +clear the PCIEXP_WAKE_STS bit in the ACPI PM1 Status Register, via +HwClearAcpiStatus. Original change from Colin King. ACPICA BZ 880. + +Changed the type of the predefined namespace object _TZ from ThermalZone +to +Device. This was found to be confusing to the host software that +processes +the various thermal zones, since _TZ is not really a ThermalZone. +However, +a +Notify() can still be performed on it. ACPICA BZ 876. Suggestion from Rui +Zhang. + +Added Windows Vista SP2 to the list of supported _OSI strings. The actual +string is "Windows 2006 SP2". + +Eliminated duplicate code in AcpiUtExecute* functions. Now that the +nsrepair +code automatically repairs _HID-related strings, this type of code is no +longer needed in Execute_HID, Execute_CID, and Execute_UID. ACPICA BZ +878. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + Current Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented additional compile-time validation for _HID strings. +The +non-hex prefix (such as "PNP" or "ACPI") must be uppercase, and the +length +of +the string must be exactly seven or eight characters. For both _HID and +_CID +strings, all characters must be alphanumeric. ACPICA BZ 874. + +iASL: Allow certain "null" resource descriptors. Some BIOS code creates +descriptors that are mostly or all zeros, with the expectation that they +will +be filled in at runtime. iASL now allows this as long as there is a +"resource +tag" (name) associated with the descriptor, which gives the ASL a handle +needed to modify the descriptor. ACPICA BZ 873. + +Added single-thread support to the generic Unix application OSL. +Primarily +for iASL support, this change removes the use of semaphores in the +single- +threaded ACPICA tools/applications - increasing performance. The +_MULTI_THREADED option was replaced by the (reverse) ACPI_SINGLE_THREADED +option. ACPICA BZ 879. + +AcpiExec: several fixes for the 64-bit version. Adds XSDT support and +support +for 64-bit DSDT/FACS addresses in the FADT. Lin Ming. + +iASL: Moved all compiler messages to a new file, aslmessages.h. + +---------------------------------------- +15 September 2010. Summary of changes for version 20100915: + +1) ACPI CA Core Subsystem: + +Removed the AcpiOsDerivePciId OSL interface. The various host +implementations +of this function were not OS-dependent and are now obsolete and can be +removed from all host OSLs. This function has been replaced by +AcpiHwDerivePciId, which is now part of the ACPICA core code. +AcpiHwDerivePciId has been implemented without recursion. Adds one new +module, hwpci.c. ACPICA BZ 857. + +Implemented a dynamic repair for _HID and _CID strings. The following +problems are now repaired at runtime: 1) Remove a leading asterisk in the +string, and 2) the entire string is uppercased. Both repairs are in +accordance with the ACPI specification and will simplify host driver +code. +ACPICA BZ 871. + +The ACPI_THREAD_ID type is no longer configurable, internally it is now +always UINT64. This simplifies the ACPICA code, especially any printf +output. +UINT64 is the only common data type for all thread_id types across all +operating systems. It is now up to the host OSL to cast the native +thread_id +type to UINT64 before returning the value to ACPICA (via +AcpiOsGetThreadId). +Lin Ming, Bob Moore. + +Added the ACPI_INLINE type to enhance the ACPICA configuration. The +"inline" +keyword is not standard across compilers, and this type allows inline to +be +configured on a per-compiler basis. Lin Ming. + +Made the system global AcpiGbl_SystemAwakeAndRunning publically +available. +Added an extern for this boolean in acpixf.h. Some hosts utilize this +value +during suspend/restore operations. ACPICA BZ 869. + +All code that implements error/warning messages with the "ACPI:" prefix +has +been moved to a new module, utxferror.c. + +The UINT64_OVERLAY was moved to utmath.c, which is the only module where +it +is used. ACPICA BZ 829. Lin Ming, Bob Moore. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 89.1K Code, 19.0K Data, 108.1K Total + Debug Version: 165.1K Code, 51.9K Data, 217.0K Total + Current Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL/Disassembler: Write ACPI errors to stderr instead of the output +file. +This keeps the output files free of random error messages that may +originate +from within the namespace/interpreter code. Used this opportunity to +merge +all ACPI:-style messages into a single new module, utxferror.c. ACPICA BZ +866. Lin Ming, Bob Moore. + +Tools: update some printfs for ansi warnings on size_t. Handle width +change +of size_t on 32-bit versus 64-bit generations. Lin Ming. + +---------------------------------------- +06 August 2010. Summary of changes for version 20100806: + +1) ACPI CA Core Subsystem: + +Designed and implemented a new host interface to the _OSI support code. +This +will allow the host to dynamically add or remove multiple _OSI strings, +as +well as install an optional handler that is called for each _OSI +invocation. +Also added a new AML debugger command, 'osi' to display and modify the +global +_OSI string table, and test support in the AcpiExec utility. See the +ACPICA +reference manual for full details. Lin Ming, Bob Moore. ACPICA BZ 836. +New Functions: + AcpiInstallInterface - Add an _OSI string. + AcpiRemoveInterface - Delete an _OSI string. + AcpiInstallInterfaceHandler - Install optional _OSI handler. +Obsolete Functions: + AcpiOsValidateInterface - no longer used. +New Files: + source/components/utilities/utosi.c + +Re-introduced the support to enable multi-byte transfers for Embedded +Controller (EC) operation regions. A reported problem was found to be a +bug +in the host OS, not in the multi-byte support. Previously, the maximum +data +size passed to the EC operation region handler was a single byte. There +are +often EC Fields larger than one byte that need to be transferred, and it +is +useful for the EC driver to lock these as a single transaction. This +change +enables single transfers larger than 8 bits. This effectively changes the +access to the EC space from ByteAcc to AnyAcc, and will probably require +changes to the host OS Embedded Controller driver to enable 16/32/64/256- +bit +transfers in addition to 8-bit transfers. Alexey Starikovskiy, Lin Ming. + +Fixed a problem with the prototype for AcpiOsReadPciConfiguration. The +prototype in acpiosxf.h had the output value pointer as a (void *). +It should be a (UINT64 *). This may affect some host OSL code. + +Fixed a couple problems with the recently modified Linux makefiles for +iASL +and AcpiExec. These new makefiles place the generated object files in the +local directory so that there can be no collisions between the files that +are +shared between them that are compiled with different options. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 88.3K Code, 18.8K Data, 107.1K Total + Debug Version: 164.0K Code, 51.5K Data, 215.5K Total + Current Release: + Non-Debug Version: 89.1K Code, 19.0K Data, 108.1K Total + Debug Version: 165.1K Code, 51.9K Data, 217.0K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL/Disassembler: Added a new option (-da, "disassemble all") to load +the +namespace from and disassemble an entire group of AML files. Useful for +loading all of the AML tables for a given machine (DSDT, SSDT1...SSDTn) +and +disassembling with one simple command. ACPICA BZ 865. Lin Ming. + +iASL: Allow multiple invocations of -e option. This change allows +multiple +uses of -e on the command line: "-e ssdt1.dat -e ssdt2.dat". ACPICA BZ +834. +Lin Ming. + +---------------------------------------- +02 July 2010. Summary of changes for version 20100702: + +1) ACPI CA Core Subsystem: + +Implemented several updates to the recently added GPE reference count +support. The model for "wake" GPEs is changing to give the host OS +complete +control of these GPEs. Eventually, the ACPICA core will not execute any +_PRW +methods, since the host already must execute them. Also, additional +changes +were made to help ensure that the reference counts are kept in proper +synchronization with reality. Rafael J. Wysocki. + +1) Ensure that GPEs are not enabled twice during initialization. +2) Ensure that GPE enable masks stay in sync with the reference count. +3) Do not inadvertently enable GPEs when writing GPE registers. +4) Remove the internal wake reference counter and add new AcpiGpeWakeup +interface. This interface will set or clear individual GPEs for wakeup. +5) Remove GpeType argument from AcpiEnable and AcpiDisable. These +interfaces +are now used for "runtime" GPEs only. + +Changed the behavior of the GPE install/remove handler interfaces. The +GPE +is +no longer disabled during this process, as it was found to cause problems +on +some machines. Rafael J. Wysocki. + +Reverted a change introduced in version 20100528 to enable Embedded +Controller multi-byte transfers. This change was found to cause problems +with +Index Fields and possibly Bank Fields. It will be reintroduced when these +problems have been resolved. + +Fixed a problem with references to Alias objects within Package Objects. +A +reference to an Alias within the definition of a Package was not always +resolved properly. Aliases to objects like Processors, Thermal zones, +etc. +were resolved to the actual object instead of a reference to the object +as +it +should be. Package objects are only allowed to contain integer, string, +buffer, package, and reference objects. Redhat bugzilla 608648. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 88.3K Code, 18.8K Data, 107.1K Total + Debug Version: 164.1K Code, 51.5K Data, 215.6K Total + Current Release: + Non-Debug Version: 88.3K Code, 18.8K Data, 107.1K Total + Debug Version: 164.0K Code, 51.5K Data, 215.5K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented a new compiler subsystem to allow definition and +compilation of the non-AML ACPI tables such as FADT, MADT, SRAT, etc. +These +are called "ACPI Data Tables", and the new compiler is the "Data Table +Compiler". This compiler is intended to simplify the existing error-prone +process of creating these tables for the BIOS, as well as allowing the +disassembly, modification, recompilation, and override of existing ACPI +data +tables. See the iASL User Guide for detailed information. + +iASL: Implemented a new Template Generator option in support of the new +Data +Table Compiler. This option will create examples of all known ACPI tables +that can be used as the basis for table development. See the iASL +documentation and the -T option. + +Disassembler and headers: Added support for the WDDT ACPI table (Watchdog +Descriptor Table). + +Updated the Linux makefiles for iASL and AcpiExec to place the generated +object files in the local directory so that there can be no collisions +between the shared files between them that are generated with different +options. + +Added support for Mac OS X in the Unix OSL used for iASL and AcpiExec. +Use +the #define __APPLE__ to enable this support. + +---------------------------------------- +28 May 2010. Summary of changes for version 20100528: + +Note: The ACPI 4.0a specification was released on April 5, 2010 and is +available at www.acpi.info. This is primarily an errata release. + +1) ACPI CA Core Subsystem: + +Undefined ACPI tables: We are looking for the definitions for the +following +ACPI tables that have been seen in the field: ATKG, IEIT, GSCI. + +Implemented support to enable multi-byte transfers for Embedded +Controller +(EC) operation regions. Previously, the maximum data size passed to the +EC +operation region handler was a single byte. There are often EC Fields +larger +than one byte that need to be transferred, and it is useful for the EC +driver +to lock these as a single transaction. This change enables single +transfers +larger than 8 bits. This effectively changes the access to the EC space +from +ByteAcc to AnyAcc, and will probably require changes to the host OS +Embedded +Controller driver to enable 16/32/64/256-bit transfers in addition to 8- +bit +transfers. Alexey Starikovskiy, Lin Ming + +Implemented a performance enhancement for namespace search and access. +This +change enhances the performance of namespace searches and walks by adding +a +backpointer to the parent in each namespace node. On large namespaces, +this +change can improve overall ACPI performance by up to 9X. Adding a pointer +to +each namespace node increases the overall size of the internal namespace +by +about 5%, since each namespace entry usually consists of both a namespace +node and an ACPI operand object. However, this is the first growth of the +namespace in ten years. ACPICA bugzilla 817. Alexey Starikovskiy. + +Implemented a performance optimization that reduces the number of +namespace +walks. On control method exit, only walk the namespace if the method is +known +to have created namespace objects outside of its local scope. Previously, +the +entire namespace was traversed on each control method exit. This change +can +improve overall ACPI performance by up to 3X. Alexey Starikovskiy, Bob +Moore. + +Added support to truncate I/O addresses to 16 bits for Windows +compatibility. +Some ASL code has been seen in the field that inadvertently has bits set +above bit 15. This feature is optional and is enabled if the BIOS +requests +any Windows OSI strings. It can also be enabled by the host OS. Matthew +Garrett, Bob Moore. + +Added support to limit the maximum time for the ASL Sleep() operator. To +prevent accidental deep sleeps, limit the maximum time that Sleep() will +actually sleep. Configurable, the default maximum is two seconds. ACPICA +bugzilla 854. + +Added run-time validation support for the _WDG and_WED Microsoft +predefined +methods. These objects are defined by "Windows Instrumentation", and are +not +part of the ACPI spec. ACPICA BZ 860. + +Expanded all statistic counters used during namespace and device +initialization from 16 to 32 bits in order to support very large +namespaces. + +Replaced all instances of %d in printf format specifiers with %u since +nearly +all integers in ACPICA are unsigned. + +Fixed the exception namestring for AE_WAKE_ONLY_GPE. Was incorrectly +returned +as AE_NO_HANDLER. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 88.4K Code, 18.8K Data, 107.2K Total + Debug Version: 164.2K Code, 51.5K Data, 215.7K Total + Current Release: + Non-Debug Version: 88.3K Code, 18.8K Data, 107.1K Total + Debug Version: 164.1K Code, 51.5K Data, 215.6K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Added compiler support for the _WDG and_WED Microsoft predefined +methods. These objects are defined by "Windows Instrumentation", and are +not +part of the ACPI spec. ACPICA BZ 860. + +AcpiExec: added option to disable the memory tracking mechanism. The -dt +option will disable the tracking mechanism, which improves performance +considerably. + +AcpiExec: Restructured the command line options into -d (disable) and -e +(enable) options. + +---------------------------------------- +28 April 2010. Summary of changes for version 20100428: + +1) ACPI CA Core Subsystem: + +Implemented GPE support for dynamically loaded ACPI tables. For all GPEs, +including FADT-based and GPE Block Devices, execute any _PRW methods in +the +new table, and process any _Lxx/_Exx GPE methods in the new table. Any +runtime GPE that is referenced by an _Lxx/_Exx method in the new table is +immediately enabled. Handles the FADT-defined GPEs as well as GPE Block +Devices. Provides compatibility with other ACPI implementations. Two new +files added, evgpeinit.c and evgpeutil.c. ACPICA BZ 833. Lin Ming, Bob +Moore. + +Fixed a regression introduced in version 20100331 within the table +manager +where initial table loading could fail. This was introduced in the fix +for +AcpiReallocateRootTable. Also, renamed some of fields in the table +manager +data structures to clarify their meaning and use. + +Fixed a possible allocation overrun during internal object copy in +AcpiUtCopySimpleObject. The original code did not correctly handle the +case +where the object to be copied was a namespace node. Lin Ming. ACPICA BZ +847. + +Updated the allocation dump routine, AcpiUtDumpAllocation and fixed a +possible access beyond end-of-allocation. Also, now fully validate +descriptor +(size and type) before output. Lin Ming, Bob Moore. ACPICA BZ 847 + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 87.9K Code, 18.6K Data, 106.5K Total + Debug Version: 163.5K Code, 51.3K Data, 214.8K Total + Current Release: + Non-Debug Version: 88.4K Code, 18.8K Data, 107.2K Total + Debug Version: 164.2K Code, 51.5K Data, 215.7K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented Min/Max/Len/Gran validation for address resource +descriptors. This change implements validation for the address fields +that +are common to all address-type resource descriptors. These checks are +implemented: Checks for valid Min/Max, length within the Min/Max window, +valid granularity, Min/Max a multiple of granularity, and _MIF/_MAF as +per +table 6-40 in the ACPI 4.0a specification. Also split the large +aslrestype1.c +and aslrestype2.c files into five new files. ACPICA BZ 840. + +iASL: Added support for the _Wxx predefined names. This support was +missing +and these names were not recognized by the compiler as valid predefined +names. ACPICA BZ 851. + +iASL: Added an error for all predefined names that are defined to return +no +value and thus must be implemented as Control Methods. These include all +of +the _Lxx, _Exx, _Wxx, and _Qxx names, as well as some other miscellaneous +names such as _DIS, _INI, _IRC, _OFF, _ON, and _PSx. ACPICA BZ 850, 856. + +iASL: Implemented the -ts option to emit hex AML data in ASL format, as +an +ASL Buffer. Allows ACPI tables to be easily included within ASL files, to +be +dynamically loaded via the Load() operator. Also cleaned up output for +the +- +ta and -tc options. ACPICA BZ 853. + +Tests: Added a new file with examples of extended iASL error checking. +Demonstrates the advanced error checking ability of the iASL compiler. +Available at tests/misc/badcode.asl. + +---------------------------------------- +31 March 2010. Summary of changes for version 20100331: + +1) ACPI CA Core Subsystem: + +Completed a major update for the GPE support in order to improve support +for +shared GPEs and to simplify both host OS and ACPICA code. Added a +reference +count mechanism to support shared GPEs that require multiple device +drivers. +Several external interfaces have changed. One external interface has been +removed. One new external interface was added. Most of the GPE external +interfaces now use the GPE spinlock instead of the events mutex (and the +Flags parameter for many GPE interfaces has been removed.) See the +updated +ACPICA Programmer Reference for details. Matthew Garrett, Bob Moore, +Rafael +Wysocki. ACPICA BZ 831. + +Changed: + AcpiEnableGpe, AcpiDisableGpe, AcpiClearGpe, AcpiGetGpeStatus +Removed: + AcpiSetGpeType +New: + AcpiSetGpe + +Implemented write support for DataTable operation regions. These regions +are +defined via the DataTableRegion() operator. Previously, only read support +was +implemented. The ACPI specification allows DataTableRegions to be +read/write, +however. + +Implemented a new subsystem option to force a copy of the DSDT to local +memory. Optionally copy the entire DSDT to local memory (instead of +simply +mapping it.) There are some (albeit very rare) BIOSs that corrupt or +replace +the original DSDT, creating the need for this option. Default is FALSE, +do +not copy the DSDT. + +Implemented detection of a corrupted or replaced DSDT. This change adds +support to detect a DSDT that has been corrupted and/or replaced from +outside +the OS (by firmware). This is typically catastrophic for the system, but +has +been seen on some machines. Once this problem has been detected, the DSDT +copy option can be enabled via system configuration. Lin Ming, Bob Moore. + +Fixed two problems with AcpiReallocateRootTable during the root table +copy. +When copying the root table to the new allocation, the length used was +incorrect. The new size was used instead of the current table size, +meaning +too much data was copied. Also, the count of available slots for ACPI +tables +was not set correctly. Alexey Starikovskiy, Bob Moore. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 87.5K Code, 18.4K Data, 105.9K Total + Debug Version: 163.4K Code, 51.1K Data, 214.5K Total + Current Release: + Non-Debug Version: 87.9K Code, 18.6K Data, 106.5K Total + Debug Version: 163.5K Code, 51.3K Data, 214.8K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implement limited typechecking for values returned from predefined +control methods. The type of any returned static (unnamed) object is now +validated. For example, Return(1). ACPICA BZ 786. + +iASL: Fixed a predefined name object verification regression. Fixes a +problem +introduced in version 20100304. An error is incorrectly generated if a +predefined name is declared as a static named object with a value defined +using the keywords "Zero", "One", or "Ones". Lin Ming. + +iASL: Added Windows 7 support for the -g option (get local ACPI tables) +by +reducing the requested registry access rights. ACPICA BZ 842. + +Disassembler: fixed a possible fault when generating External() +statements. +Introduced in commit ae7d6fd: Properly handle externals with parent- +prefix +(carat). Fixes a string length allocation calculation. Lin Ming. + +---------------------------------------- +04 March 2010. Summary of changes for version 20100304: + +1) ACPI CA Core Subsystem: + +Fixed a possible problem with the AML Mutex handling function +AcpiExReleaseMutex where the function could fault under the very rare +condition when the interpreter has blocked, the interpreter lock is +released, +the interpreter is then reentered via the same thread, and attempts to +acquire an AML mutex that was previously acquired. FreeBSD report 140979. +Lin +Ming. + +Implemented additional configuration support for the AML "Debug Object". +Output from the debug object can now be enabled via a global variable, +AcpiGbl_EnableAmlDebugObject. This will assist with remote machine +debugging. +This debug output is now available in the release version of ACPICA +instead +of just the debug version. Also, the entire debug output module can now +be +configured out of the ACPICA build if desired. One new file added, +executer/exdebug.c. Lin Ming, Bob Moore. + +Added header support for the ACPI MCHI table (Management Controller Host +Interface Table). This table was added in ACPI 4.0, but the defining +document +has only recently become available. + +Standardized output of integer values for ACPICA warnings/errors. Always +use +0x prefix for hex output, always use %u for unsigned integer decimal +output. +Affects ACPI_INFO, ACPI_ERROR, ACPI_EXCEPTION, and ACPI_WARNING (about +400 +invocations.) These invocations were converted from the original +ACPI_DEBUG_PRINT invocations and were not consistent. ACPICA BZ 835. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 87.1K Code, 18.0K Data, 105.1K Total + Debug Version: 163.5K Code, 50.9K Data, 214.4K Total + Current Release: + Non-Debug Version: 87.5K Code, 18.4K Data, 105.9K Total + Debug Version: 163.4K Code, 51.1K Data, 214.5K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented typechecking support for static (non-control method) +predefined named objects that are declared with the Name() operator. For +example, the type of this object is now validated to be of type Integer: +Name(_BBN, 1). This change migrates the compiler to using the core +predefined +name table instead of maintaining a local version. Added a new file, +aslpredef.c. ACPICA BZ 832. + +Disassembler: Added support for the ACPI 4.0 MCHI table. + +---------------------------------------- +21 January 2010. Summary of changes for version 20100121: + +1) ACPI CA Core Subsystem: + +Added the 2010 copyright to all module headers and signons. This affects +virtually every file in the ACPICA core subsystem, the iASL compiler, the +tools/utilities, and the test suites. + +Implemented a change to the AcpiGetDevices interface to eliminate +unnecessary +invocations of the _STA method. In the case where a specific _HID is +requested, do not run _STA until a _HID match is found. This eliminates +potentially dozens of _STA calls during a search for a particular +device/HID, +which in turn can improve boot times. ACPICA BZ 828. Lin Ming. + +Implemented an additional repair for predefined method return values. +Attempt +to repair unexpected NULL elements within returned Package objects. +Create +an +Integer of value zero, a NULL String, or a zero-length Buffer as +appropriate. +ACPICA BZ 818. Lin Ming, Bob Moore. + +Removed the obsolete ACPI_INTEGER data type. This type was introduced as +the +code was migrated from ACPI 1.0 (with 32-bit AML integers) to ACPI 2.0 +(with +64-bit AML integers). It is now obsolete and this change removes it from +the +ACPICA code base, replaced by UINT64. The original typedef has been +retained +for now for compatibility with existing device driver code. ACPICA BZ +824. + +Removed the unused UINT32_STRUCT type, and the obsolete Integer64 field +in +the parse tree object. + +Added additional warning options for the gcc-4 generation. Updated the +source +accordingly. This includes some code restructuring to eliminate +unreachable +code, elimination of some gotos, elimination of unused return values, +some +additional casting, and removal of redundant declarations. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 87.0K Code, 18.0K Data, 105.0K Total + Debug Version: 163.4K Code, 50.8K Data, 214.2K Total + Current Release: + Non-Debug Version: 87.1K Code, 18.0K Data, 105.1K Total + Debug Version: 163.5K Code, 50.9K Data, 214.4K Total + +2) iASL Compiler/Disassembler and Tools: + +No functional changes for this release. + +---------------------------------------- +14 December 2009. Summary of changes for version 20091214: + +1) ACPI CA Core Subsystem: + +Enhanced automatic data type conversions for predefined name repairs. +This +change expands the automatic repairs/conversions for predefined name +return +values to make Integers, Strings, and Buffers fully interchangeable. +Also, +a +Buffer can be converted to a Package of Integers if necessary. The +nsrepair.c +module was completely restructured. Lin Ming, Bob Moore. + +Implemented automatic removal of null package elements during predefined +name +repairs. This change will automatically remove embedded and trailing NULL +package elements from returned package objects that are defined to +contain +a +variable number of sub-packages. The driver is then presented with a +package +with no null elements to deal with. ACPICA BZ 819. + +Implemented a repair for the predefined _FDE and _GTM names. The expected +return value for both names is a Buffer of 5 DWORDs. This repair fixes +two +possible problems (both seen in the field), where a package of integers +is +returned, or a buffer of BYTEs is returned. With assistance from Jung-uk +Kim. + +Implemented additional module-level code support. This change will +properly +execute module-level code that is not at the root of the namespace (under +a +Device object, etc.). Now executes the code within the current scope +instead +of the root. ACPICA BZ 762. Lin Ming. + +Fixed possible mutex acquisition errors when running _REG methods. Fixes +a +problem where mutex errors can occur when running a _REG method that is +in +the same scope as a method-defined operation region or an operation +region +under a module-level IF block. This type of code is rare, so the problem +has +not been seen before. ACPICA BZ 826. Lin Ming, Bob Moore. + +Fixed a possible memory leak during module-level code execution. An +object +could be leaked for each block of executed module-level code if the +interpreter slack mode is enabled This change deletes any implicitly +returned +object from the module-level code block. Lin Ming. + +Removed messages for successful predefined repair(s). The repair +mechanism +was considered too wordy. Now, messages are only unconditionally emitted +if +the return object cannot be repaired. Existing messages for successful +repairs were converted to ACPI_DEBUG_PRINT messages for now. ACPICA BZ +827. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 86.6K Code, 18.2K Data, 104.8K Total + Debug Version: 162.7K Code, 50.8K Data, 213.5K Total + Current Release: + Non-Debug Version: 87.0K Code, 18.0K Data, 105.0K Total + Debug Version: 163.4K Code, 50.8K Data, 214.2K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a regression introduced in 20091112 where intermediate .SRC +files +were no longer automatically removed at the termination of the compile. + +acpiexec: Implemented the -f option to specify default region fill value. +This option specifies the value used to initialize buffers that simulate +operation regions. Default value is zero. Useful for debugging problems +that +depend on a specific initial value for a region or field. + +---------------------------------------- +12 November 2009. Summary of changes for version 20091112: + +1) ACPI CA Core Subsystem: + +Implemented a post-order callback to AcpiWalkNamespace. The existing +interface only has a pre-order callback. This change adds an additional +parameter for a post-order callback which will be more useful for bus +scans. +ACPICA BZ 779. Lin Ming. Updated the ACPICA Programmer Reference. + +Modified the behavior of the operation region memory mapping cache for +SystemMemory. Ensure that the memory mappings created for operation +regions +do not cross 4K page boundaries. Crossing a page boundary while mapping +regions can cause kernel warnings on some hosts if the pages have +different +attributes. Such regions are probably BIOS bugs, and this is the +workaround. +Linux BZ 14445. Lin Ming. + +Implemented an automatic repair for predefined methods that must return +sorted lists. This change will repair (by sorting) packages returned by +_ALR, +_PSS, and _TSS. Drivers can now assume that the packages are correctly +sorted +and do not contain NULL package elements. Adds one new file, +namespace/nsrepair2.c. ACPICA BZ 784. Lin Ming, Bob Moore. + +Fixed a possible fault during predefined name validation if a return +Package +object contains NULL elements. Also adds a warning if a NULL element is +followed by any non-null elements. ACPICA BZ 813, 814. Future enhancement +may +include repair or removal of all such NULL elements where possible. + +Implemented additional module-level executable AML code support. This +change +will execute module-level code that is not at the root of the namespace +(under a Device object, etc.) at table load time. Module-level executable +AML +code has been illegal since ACPI 2.0. ACPICA BZ 762. Lin Ming. + +Implemented a new internal function to create Integer objects. This +function +simplifies miscellaneous object creation code. ACPICA BZ 823. + +Reduced the severity of predefined repair messages, Warning to Info. +Since +the object was successfully repaired, a warning is too severe. Reduced to +an +info message for now. These messages may eventually be changed to debug- +only. +ACPICA BZ 812. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 85.8K Code, 18.0K Data, 103.8K Total + Debug Version: 161.8K Code, 50.6K Data, 212.4K Total + Current Release: + Non-Debug Version: 86.6K Code, 18.2K Data, 104.8K Total + Debug Version: 162.7K Code, 50.8K Data, 213.5K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented Switch() with While(1) so that Break works correctly. +This +change correctly implements the Switch operator with a surrounding +While(1) +so that the Break operator works as expected. ACPICA BZ 461. Lin Ming. + +iASL: Added a message if a package initializer list is shorter than +package +length. Adds a new remark for a Package() declaration if an initializer +list +exists, but is shorter than the declared length of the package. Although +technically legal, this is probably a coding error and it is seen in the +field. ACPICA BZ 815. Lin Ming, Bob Moore. + +iASL: Fixed a problem where the compiler could fault after the maximum +number +of errors was reached (200). + +acpixtract: Fixed a possible warning for pointer cast if the compiler +warning +level set very high. + +---------------------------------------- +13 October 2009. Summary of changes for version 20091013: + +1) ACPI CA Core Subsystem: + +Fixed a problem where an Operation Region _REG method could be executed +more +than once. If a custom address space handler is installed by the host +before +the "initialize operation regions" phase of the ACPICA initialization, +any +_REG methods for that address space could be executed twice. This change +fixes the problem. ACPICA BZ 427. Lin Ming. + +Fixed a possible memory leak for the Scope() ASL operator. When the exact +invocation of "Scope(\)" is executed (change scope to root), one internal +operand object was leaked. Lin Ming. + +Implemented a run-time repair for the _MAT predefined method. If the _MAT +return value is defined as a Field object in the AML, and the field +size is less than or equal to the default width of an integer (32 or +64),_MAT +can incorrectly return an Integer instead of a Buffer. ACPICA now +automatically repairs this problem. ACPICA BZ 810. + +Implemented a run-time repair for the _BIF and _BIX predefined methods. +The +"OEM Information" field is often incorrectly returned as an Integer with +value zero if the field is not supported by the platform. This is due to +an +ambiguity in the ACPI specification. The field should always be a string. +ACPICA now automatically repairs this problem by returning a NULL string +within the returned Package. ACPICA BZ 807. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 85.6K Code, 18.0K Data, 103.6K Total + Debug Version: 161.7K Code, 50.9K Data, 212.6K Total + Current Release: + Non-Debug Version: 85.8K Code, 18.0K Data, 103.8K Total + Debug Version: 161.8K Code, 50.6K Data, 212.4K Total + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Fixed a problem where references to external symbols that +contained one or more parent-prefixes (carats) were not handled +correctly, +possibly causing a fault. ACPICA BZ 806. Lin Ming. + +Disassembler: Restructured the code so that all functions that handle +external symbols are in a single module. One new file is added, +common/dmextern.c. + +AML Debugger: Added a max count argument for the Batch command (which +executes multiple predefined methods within the namespace.) + +iASL: Updated the compiler documentation (User Reference.) Available at +http://www.acpica.org/documentation/. ACPICA BZ 750. + +AcpiXtract: Updated for Lint and other formatting changes. Close all open +files. + +---------------------------------------- +03 September 2009. Summary of changes for version 20090903: + +1) ACPI CA Core Subsystem: + +For Windows Vista compatibility, added the automatic execution of an _INI +method located at the namespace root (\_INI). This method is executed at +table load time. This support is in addition to the automatic execution +of +\_SB._INI. Lin Ming. + +Fixed a possible memory leak in the interpreter for AML package objects +if +the package initializer list is longer than the defined size of the +package. +This apparently can only happen if the BIOS changes the package size on +the +fly (seen in a _PSS object), as ASL compilers do not allow this. The +interpreter will truncate the package to the defined size (and issue an +error +message), but previously could leave the extra objects undeleted if they +were +pre-created during the argument processing (such is the case if the +package +consists of a number of sub-packages as in the _PSS.) ACPICA BZ 805. + +Fixed a problem seen when a Buffer or String is stored to itself via ASL. +This has been reported in the field. Previously, ACPICA would zero out +the +buffer/string. Now, the operation is treated as a noop. Provides Windows +compatibility. ACPICA BZ 803. Lin Ming. + +Removed an extraneous error message for ASL constructs of the form +Store(LocalX,LocalX) when LocalX is uninitialized. These curious +statements +are seen in many BIOSs and are once again treated as NOOPs and no error +is +emitted when they are encountered. ACPICA BZ 785. + +Fixed an extraneous warning message if a _DSM reserved method returns a +Package object. _DSM can return any type of object, so validation on the +return type cannot be performed. ACPICA BZ 802. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 85.5K Code, 18.0K Data, 103.5K Total + Debug Version: 161.6K Code, 50.9K Data, 212.5K Total + Current Release: + Non-Debug Version: 85.6K Code, 18.0K Data, 103.6K Total + Debug Version: 161.7K Code, 50.9K Data, 212.6K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a problem with the use of the Alias operator and Resource +Templates. The correct alias is now constructed and no error is emitted. +ACPICA BZ 738. + +iASL: Implemented the -I option to specify additional search directories +for +include files. Allows multiple additional search paths for include files. +Directories are searched in the order specified on the command line +(after +the local directory is searched.) ACPICA BZ 800. + +iASL: Fixed a problem where the full pathname for include files was not +emitted for warnings/errors. This caused the IDE support to not work +properly. ACPICA BZ 765. + +iASL: Implemented the -@ option to specify a Windows-style response file +containing additional command line options. ACPICA BZ 801. + +AcpiExec: Added support to load multiple AML files simultaneously (such +as +a +DSDT and multiple SSDTs). Also added support for wildcards within the AML +pathname. These features allow all machine tables to be easily loaded and +debugged together. ACPICA BZ 804. + +Disassembler: Added missing support for disassembly of HEST table Error +Bank +subtables. + +---------------------------------------- +30 July 2009. Summary of changes for version 20090730: + +The ACPI 4.0 implementation for ACPICA is complete with this release. + +1) ACPI CA Core Subsystem: + +ACPI 4.0: Added header file support for all new and changed ACPI tables. +Completely new tables are: IBFT, IVRS, MSCT, and WAET. Tables that are +new +for ACPI 4.0, but have previously been supported in ACPICA are: CPEP, +BERT, +EINJ, ERST, and HEST. Other newly supported tables are: UEFI and WDAT. +There +have been some ACPI 4.0 changes to other existing tables. Split the large +actbl1.h header into the existing actbl2.h header. ACPICA BZ 774. + +ACPI 4.0: Implemented predefined name validation for all new names. There +are +31 new names in ACPI 4.0. The predefined validation module was split into +two +files. The new file is namespace/nsrepair.c. ACPICA BZ 770. + +Implemented support for so-called "module-level executable code". This is +executable AML code that exists outside of any control method and is +intended +to be executed at table load time. Although illegal since ACPI 2.0, this +type +of code still exists and is apparently still being created. Blocks of +this +code are now detected and executed as intended. Currently, the code +blocks +must exist under either an If, Else, or While construct; these are the +typical cases seen in the field. ACPICA BZ 762. Lin Ming. + +Implemented an automatic dynamic repair for predefined names that return +nested Package objects. This applies to predefined names that are defined +to +return a variable-length Package of sub-packages. If the number of sub- +packages is one, BIOS code is occasionally seen that creates a simple +single +package with no sub-packages. This code attempts to fix the problem by +wrapping a new package object around the existing package. These methods +can +be repaired: _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, and _TSS. ACPICA +BZ +790. + +Fixed a regression introduced in 20090625 for the AcpiGetDevices +interface. +The _HID/_CID matching was broken and no longer matched IDs correctly. +ACPICA +BZ 793. + +Fixed a problem with AcpiReset where the reset would silently fail if the +register was one of the protected I/O ports. AcpiReset now bypasses the +port +validation mechanism. This may eventually be driven into the +AcpiRead/Write +interfaces. + +Fixed a regression related to the recent update of the AcpiRead/Write +interfaces. A sleep/suspend could fail if the optional PM2 Control +register +does not exist during an attempt to write the Bus Master Arbitration bit. +(However, some hosts already delete the code that writes this bit, and +the +code may in fact be obsolete at this date.) ACPICA BZ 799. + +Fixed a problem where AcpiTerminate could fault if inadvertently called +twice +in succession. ACPICA BZ 795. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 84.7K Code, 17.8K Data, 102.5K Total + Debug Version: 160.5K Code, 50.6K Data, 211.1K Total + Current Release: + Non-Debug Version: 85.5K Code, 18.0K Data, 103.5K Total + Debug Version: 161.6K Code, 50.9K Data, 212.5K Total + +2) iASL Compiler/Disassembler and Tools: + +ACPI 4.0: Implemented disassembler support for all new ACPI tables and +changes to existing tables. ACPICA BZ 775. + +---------------------------------------- +25 June 2009. Summary of changes for version 20090625: + +The ACPI 4.0 Specification was released on June 16 and is available at +www.acpi.info. ACPICA implementation of ACPI 4.0 is underway and will +continue for the next few releases. + +1) ACPI CA Core Subsystem: + +ACPI 4.0: Implemented interpreter support for the IPMI operation region +address space. Includes support for bi-directional data buffers and an +IPMI +address space handler (to be installed by an IPMI device driver.) ACPICA +BZ +773. Lin Ming. + +ACPI 4.0: Added changes for existing ACPI tables - FACS and SRAT. +Includes +support in both the header files and the disassembler. + +Completed a major update for the AcpiGetObjectInfo external interface. +Changes include: + - Support for variable, unlimited length HID, UID, and CID strings. + - Support Processor objects the same as Devices (HID,UID,CID,ADR,STA, +etc.) + - Call the _SxW power methods on behalf of a device object. + - Determine if a device is a PCI root bridge. + - Change the ACPI_BUFFER parameter to ACPI_DEVICE_INFO. +These changes will require an update to all callers of this interface. +See +the updated ACPICA Programmer Reference for details. One new source file +has +been added - utilities/utids.c. ACPICA BZ 368, 780. + +Updated the AcpiRead and AcpiWrite external interfaces to support 64-bit +transfers. The Value parameter has been extended from 32 bits to 64 bits +in +order to support new ACPI 4.0 tables. These changes will require an +update +to +all callers of these interfaces. See the ACPICA Programmer Reference for +details. ACPICA BZ 768. + +Fixed several problems with AcpiAttachData. The handler was not invoked +when +the host node was deleted. The data sub-object was not automatically +deleted +when the host node was deleted. The interface to the handler had an +unused +parameter, this was removed. ACPICA BZ 778. + +Enhanced the function that dumps ACPI table headers. All non-printable +characters in the string fields are now replaced with '?' (Signature, +OemId, +OemTableId, and CompilerId.) ACPI tables with non-printable characters in +these fields are occasionally seen in the field. ACPICA BZ 788. + +Fixed a problem with predefined method repair code where the code that +attempts to repair/convert an object of incorrect type is only executed +on +the first time the predefined method is called. The mechanism that +disables +warnings on subsequent calls was interfering with the repair mechanism. +ACPICA BZ 781. + +Fixed a possible memory leak in the predefined validation/repair code +when +a +buffer is automatically converted to an expected string object. + +Removed obsolete 16-bit files from the distribution and from the current +git +tree head. ACPICA BZ 776. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 83.4K Code, 17.5K Data, 100.9K Total + Debug Version: 158.9K Code, 50.0K Data, 208.9K Total + Current Release: + Non-Debug Version: 84.7K Code, 17.8K Data, 102.5K Total + Debug Version: 160.5K Code, 50.6K Data, 211.1K Total + +2) iASL Compiler/Disassembler and Tools: + +ACPI 4.0: iASL and Disassembler - implemented support for the new IPMI +operation region keyword. ACPICA BZ 771, 772. Lin Ming. + +ACPI 4.0: iASL - implemented compile-time validation support for all new +predefined names and control methods (31 total). ACPICA BZ 769. + +---------------------------------------- +21 May 2009. Summary of changes for version 20090521: + +1) ACPI CA Core Subsystem: + +Disabled the preservation of the SCI enable bit in the PM1 control +register. +The SCI enable bit (bit 0, SCI_EN) is defined by the ACPI specification +to +be +a "preserved" bit - "OSPM always preserves this bit position", section +4.7.3.2.1. However, some machines fail if this bit is in fact preserved +because the bit needs to be explicitly set by the OS as a workaround. No +machines fail if the bit is not preserved. Therefore, ACPICA no longer +attempts to preserve this bit. + +Fixed a problem in AcpiRsGetPciRoutingTableLength where an invalid or +incorrectly formed _PRT package could cause a fault. Added validation to +ensure that each package element is actually a sub-package. + +Implemented a new interface to install or override a single control +method, +AcpiInstallMethod. This interface is useful when debugging in order to +repair +an existing method or to install a missing method without having to +override +the entire ACPI table. See the ACPICA Programmer Reference for use and +examples. Lin Ming, Bob Moore. + +Fixed several reference count issues with the DdbHandle object that is +created from a Load or LoadTable operator. Prevent premature deletion of +the +object. Also, mark the object as invalid once the table has been +unloaded. +This is needed because the handle itself may not be deleted after the +table +unload, depending on whether it has been stored in a named object by the +caller. Lin Ming. + +Fixed a problem with Mutex Sync Levels. Fixed a problem where if multiple +mutexes of the same sync level are acquired but then not released in +strict +opposite order, the internally maintained Current Sync Level becomes +confused +and can cause subsequent execution errors. ACPICA BZ 471. + +Changed the allowable release order for ASL mutex objects. The ACPI 4.0 +specification has been changed to make the SyncLevel for mutex objects +more +useful. When releasing a mutex, the SyncLevel of the mutex must now be +the +same as the current sync level. This makes more sense than the previous +rule +(SyncLevel less than or equal). This change updates the code to match the +specification. + +Fixed a problem with the local version of the AcpiOsPurgeCache function. +The +(local) cache must be locked during all cache object deletions. Andrew +Baumann. + +Updated the Load operator to use operation region interfaces. This +replaces +direct memory mapping with region access calls. Now, all region accesses +go +through the installed region handler as they should. + +Simplified and optimized the NsGetNextNode function. Reduced parameter +count +and reduced code for this frequently used function. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 82.8K Code, 17.5K Data, 100.3K Total + Debug Version: 158.0K Code, 49.9K Data, 207.9K Total + Current Release: + Non-Debug Version: 83.4K Code, 17.5K Data, 100.9K Total + Debug Version: 158.9K Code, 50.0K Data, 208.9K Total + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Fixed some issues with DMAR, HEST, MADT tables. Some +problems +with sub-table disassembly and handling invalid sub-tables. Attempt +recovery +after an invalid sub-table ID. + +---------------------------------------- +22 April 2009. Summary of changes for version 20090422: + +1) ACPI CA Core Subsystem: + +Fixed a compatibility issue with the recently released I/O port +protection +mechanism. For windows compatibility, 1) On a port protection violation, +simply ignore the request and do not return an exception (allow the +control +method to continue execution.) 2) If only part of the request overlaps a +protected port, read/write the individual ports that are not protected. +Linux +BZ 13036. Lin Ming + +Enhanced the execution of the ASL/AML BreakPoint operator so that it +actually +breaks into the AML debugger if the debugger is present. This matches the +ACPI-defined behavior. + +Fixed several possible warnings related to the use of the configurable +ACPI_THREAD_ID. This type can now be configured as either an integer or a +pointer with no warnings. Also fixes several warnings in printf-like +statements for the 64-bit build when the type is configured as a pointer. +ACPICA BZ 766, 767. + +Fixed a number of possible warnings when compiling with gcc 4+ (depending +on +warning options.) Examples include printf formats, aliasing, unused +globals, +missing prototypes, missing switch default statements, use of non-ANSI +library functions, use of non-ANSI constructs. See generate/unix/Makefile +for +a list of warning options used with gcc 3 and 4. ACPICA BZ 735. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 82.6K Code, 17.6K Data, 100.2K Total + Debug Version: 157.7K Code, 49.9K Data, 207.6K Total + Current Release: + Non-Debug Version: 82.8K Code, 17.5K Data, 100.3K Total + Debug Version: 158.0K Code, 49.9K Data, 207.9K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Fixed a generation warning from Bison 2.3 and fixed several +warnings +on +the 64-bit build. + +iASL: Fixed a problem where the Unix/Linux versions of the compiler could +not +correctly digest Windows/DOS formatted files (with CR/LF). + +iASL: Added a new option for "quiet mode" (-va) that produces only the +compilation summary, not individual errors and warnings. Useful for large +batch compilations. + +AcpiExec: Implemented a new option (-z) to enable a forced +semaphore/mutex +timeout that can be used to detect hang conditions during execution of +AML +code (includes both internal semaphores and AML-defined mutexes and +events.) + +Added new makefiles for the generation of acpica in a generic unix-like +environment. These makefiles are intended to generate the acpica tools +and +utilities from the original acpica git source tree structure. + +Test Suites: Updated and cleaned up the documentation files. Updated the +copyrights to 2009, affecting all source files. Use the new version of +iASL +with quiet mode. Increased the number of available semaphores in the +Windows +OSL, allowing the aslts to execute fully on Windows. For the Unix OSL, +added +an alternate implementation of the semaphore timeout to allow aslts to +execute fully on Cygwin. + +---------------------------------------- +20 March 2009. Summary of changes for version 20090320: + +1) ACPI CA Core Subsystem: + +Fixed a possible race condition between AcpiWalkNamespace and dynamic +table +unloads. Added a reader/writer locking mechanism to allow multiple +concurrent +namespace walks (readers), but block a dynamic table unload until it can +gain +exclusive write access to the namespace. This fixes a problem where a +table +unload could (possibly catastrophically) delete the portion of the +namespace +that is currently being examined by a walk. Adds a new file, utlock.c, +that +implements the reader/writer lock mechanism. ACPICA BZ 749. + +Fixed a regression introduced in version 20090220 where a change to the +FADT +handling could cause the ACPICA subsystem to access non-existent I/O +ports. + +Modified the handling of FADT register and table (FACS/DSDT) addresses. +The +FADT can contain both 32-bit and 64-bit versions of these addresses. +Previously, the 64-bit versions were favored, meaning that if both 32 and +64 +versions were valid, but not equal, the 64-bit version was used. This was +found to cause some machines to fail. Now, in this case, the 32-bit +version +is used instead. This now matches the Windows behavior. + +Implemented a new mechanism to protect certain I/O ports. Provides +Microsoft +compatibility and protects the standard PC I/O ports from access via AML +code. Adds a new file, hwvalid.c + +Fixed a possible extraneous warning message from the FADT support. The +message warns of a 32/64 length mismatch between the legacy and GAS +definitions for a register. + +Removed the obsolete AcpiOsValidateAddress OSL interface. This interface +is +made obsolete by the port protection mechanism above. It was previously +used +to validate the entire address range of an operation region, which could +be +incorrect if the range included illegal ports, but fields within the +operation region did not actually access those ports. Validation is now +performed on a per-field basis instead of the entire region. + +Modified the handling of the PM1 Status Register ignored bit (bit 11.) +Ignored bits must be "preserved" according to the ACPI spec. Usually, +this +means a read/modify/write when writing to the register. However, for +status +registers, writing a one means clear the event. Writing a zero means +preserve +the event (do not clear.) This behavior is clarified in the ACPI 4.0 +spec, +and the ACPICA code now simply always writes a zero to the ignored bit. + +Modified the handling of ignored bits for the PM1 A/B Control Registers. +As +per the ACPI specification, for the control registers, preserve +(read/modify/write) all bits that are defined as either reserved or +ignored. + +Updated the handling of write-only bits in the PM1 A/B Control Registers. +When reading the register, zero the write-only bits as per the ACPI spec. +ACPICA BZ 443. Lin Ming. + +Removed "Linux" from the list of supported _OSI strings. Linux no longer +wants to reply true to this request. The Windows strings are the only +paths +through the AML that are tested and known to work properly. + + Previous Release: + Non-Debug Version: 82.0K Code, 17.5K Data, 99.5K Total + Debug Version: 156.9K Code, 49.8K Data, 206.7K Total + Current Release: + Non-Debug Version: 82.6K Code, 17.6K Data, 100.2K Total + Debug Version: 157.7K Code, 49.9K Data, 207.6K Total + +2) iASL Compiler/Disassembler and Tools: + +Acpiexec: Split the large aeexec.c file into two new files, aehandlers.c +and +aetables.c + +---------------------------------------- +20 February 2009. Summary of changes for version 20090220: + +1) ACPI CA Core Subsystem: + +Optimized the ACPI register locking. Removed locking for reads from the +ACPI +bit registers in PM1 Status, Enable, Control, and PM2 Control. The lock +is +not required when reading the single-bit registers. The +AcpiGetRegisterUnlocked function is no longer needed and has been +removed. +This will improve performance for reads on these registers. ACPICA BZ +760. + +Fixed the parameter validation for AcpiRead/Write. Now return +AE_BAD_PARAMETER if the input register pointer is null, and +AE_BAD_ADDRESS +if +the register has an address of zero. Previously, these cases simply +returned +AE_OK. For optional registers such as PM1B status/enable/control, the +caller +should check for a valid register address before calling. ACPICA BZ 748. + +Renamed the external ACPI bit register access functions. Renamed +AcpiGetRegister and AcpiSetRegister to clarify the purpose of these +functions. The new names are AcpiReadBitRegister and +AcpiWriteBitRegister. +Also, restructured the code for these functions by simplifying the code +path +and condensing duplicate code to reduce code size. + +Added new functions to transparently handle the possibly split PM1 A/B +registers. AcpiHwReadMultiple and AcpiHwWriteMultiple. These two +functions +now handle the split registers for PM1 Status, Enable, and Control. +ACPICA +BZ +746. + +Added a function to handle the PM1 control registers, +AcpiHwWritePm1Control. +This function writes both of the PM1 control registers (A/B). These +registers +are different than the PM1 A/B status and enable registers in that +different +values can be written to the A/B registers. Most notably, the SLP_TYP +bits +can be different, as per the values returned from the _Sx predefined +methods. + +Removed an extra register write within AcpiHwClearAcpiStatus. This +function +was writing an optional PM1B status register twice. The existing call to +the +low-level AcpiHwRegisterWrite automatically handles a possibly split PM1 +A/B +register. ACPICA BZ 751. + +Split out the PM1 Status registers from the FADT. Added new globals for +these +registers (A/B), similar to the way the PM1 Enable registers are handled. +Instead of overloading the FADT Event Register blocks. This makes the +code +clearer and less prone to error. + +Fixed the warning message for when the platform contains too many ACPI +tables +for the default size of the global root table data structure. The +calculation +for the truncation value was incorrect. + +Removed the ACPI_GET_OBJECT_TYPE macro. Removed all instances of this +obsolete macro, since it is now a simple reference to ->common.type. +There +were about 150 invocations of the macro across 41 files. ACPICA BZ 755. + +Removed the redundant ACPI_BITREG_SLEEP_TYPE_B. This type is the same as +TYPE_A. Removed this and all related instances. Renamed SLEEP_TYPE_A to +simply SLEEP_TYPE. ACPICA BZ 754. + +Conditionally compile the AcpiSetFirmwareWakingVector64 function. This +function is only needed on 64-bit host operating systems and is thus not +included for 32-bit hosts. + +Debug output: print the input and result for invocations of the _OSI +reserved +control method via the ACPI_LV_INFO debug level. Also, reduced some of +the +verbosity of this debug level. Len Brown. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 82.3K Code, 17.5K Data, 99.8K Total + Debug Version: 157.3K Code, 49.8K Data, 207.1K Total + Current Release: + Non-Debug Version: 82.0K Code, 17.5K Data, 99.5K Total + Debug Version: 156.9K Code, 49.8K Data, 206.7K Total + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Decode the FADT PM_Profile field. Emit ascii names for the +various legal performance profiles. + +---------------------------------------- +23 January 2009. Summary of changes for version 20090123: + +1) ACPI CA Core Subsystem: + +Added the 2009 copyright to all module headers and signons. This affects +virtually every file in the ACPICA core subsystem, the iASL compiler, and +the tools/utilities. + +Implemented a change to allow the host to override any ACPI table, +including +dynamically loaded tables. Previously, only the DSDT could be replaced by +the +host. With this change, the AcpiOsTableOverride interface is called for +each +table found in the RSDT/XSDT during ACPICA initialization, and also +whenever +a table is dynamically loaded via the AML Load operator. + +Updated FADT flag definitions, especially the Boot Architecture flags. + +Debugger: For the Find command, automatically pad the input ACPI name +with +underscores if the name is shorter than 4 characters. This enables a +match +with the actual namespace entry which is itself padded with underscores. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 82.3K Code, 17.4K Data, 99.7K Total + Debug Version: 157.1K Code, 49.7K Data, 206.8K Total + Current Release: + Non-Debug Version: 82.3K Code, 17.5K Data, 99.8K Total + Debug Version: 157.3K Code, 49.8K Data, 207.1K Total + +2) iASL Compiler/Disassembler and Tools: + +Fix build error under Bison-2.4. + +Dissasembler: Enhanced FADT support. Added decoding of the Boot +Architecture +flags. Now decode all flags, regardless of the FADT version. Flag output +includes the FADT version which first defined each flag. + +The iASL -g option now dumps the RSDT to a file (in addition to the FADT +and +DSDT). Windows only. + +---------------------------------------- +04 December 2008. Summary of changes for version 20081204: + +1) ACPI CA Core Subsystem: + +The ACPICA Programmer Reference has been completely updated and revamped +for +this release. This includes updates to the external interfaces, OSL +interfaces, the overview sections, and the debugger reference. + +Several new ACPICA interfaces have been implemented and documented in the +programmer reference: +AcpiReset - Writes the reset value to the FADT-defined reset register. +AcpiDisableAllGpes - Disable all available GPEs. +AcpiEnableAllRuntimeGpes - Enable all available runtime GPEs. +AcpiGetGpeDevice - Get the GPE block device associated with a GPE. +AcpiGbl_CurrentGpeCount - Tracks the current number of available GPEs. +AcpiRead - Low-level read ACPI register (was HwLowLevelRead.) +AcpiWrite - Low-level write ACPI register (was HwLowLevelWrite.) + +Most of the public ACPI hardware-related interfaces have been moved to a +new +file, components/hardware/hwxface.c + +Enhanced the FADT parsing and low-level ACPI register access: The ACPI +register lengths within the FADT are now used, and the low level ACPI +register access no longer hardcodes the ACPI register lengths. Given that +there may be some risk in actually trusting the FADT register lengths, a +run- +time option was added to fall back to the default hardcoded lengths if +the +FADT proves to contain incorrect values - UseDefaultRegisterWidths. This +option is set to true for now, and a warning is issued if a suspicious +FADT +register length is overridden with the default value. + +Fixed a reference count issue in NsRepairObject. This problem was +introduced +in version 20081031 as part of a fix to repair Buffer objects within +Packages. Lin Ming. + +Added semaphore support to the Linux/Unix application OS-services layer +(OSL). ACPICA BZ 448. Lin Ming. + +Added the ACPI_MUTEX_TYPE configuration option to select whether mutexes +will +be implemented in the OSL, or will binary semaphores be used instead. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 81.7K Code, 17.3K Data, 99.0K Total + Debug Version: 156.4K Code, 49.4K Data, 205.8K Total + Current Release: + Non-Debug Version: 82.3K Code, 17.4K Data, 99.7K Total + Debug Version: 157.1K Code, 49.7K Data, 206.8K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Completed the '-e' option to include additional ACPI tables in +order +to +aid with disassembly and External statement generation. ACPICA BZ 742. +Lin +Ming. + +iASL: Removed the "named object in while loop" error. The compiler cannot +determine how many times a loop will execute. ACPICA BZ 730. + +Disassembler: Implemented support for FADT revision 2 (MS extension). +ACPICA +BZ 743. + +Disassembler: Updates for several ACPI data tables (HEST, EINJ, and +MCFG). + +---------------------------------------- +31 October 2008. Summary of changes for version 20081031: + +1) ACPI CA Core Subsystem: + +Restructured the ACPICA header files into public/private. acpi.h now +includes +only the "public" acpica headers. All other acpica headers are "private" +and +should not be included by acpica users. One new file, accommon.h is used +to +include the commonly used private headers for acpica code generation. +Future +plans include moving all private headers to a new subdirectory. + +Implemented an automatic Buffer->String return value conversion for +predefined ACPI methods. For these methods (such as _BIF), added +automatic +conversion for return objects that are required to be a String, but a +Buffer +was found instead. This can happen when reading string battery data from +an +operation region, because it used to be difficult to convert the data +from +buffer to string from within the ASL. Ensures that the host OS is +provided +with a valid null-terminated string. Linux BZ 11822. + +Updated the FACS waking vector interfaces. Split +AcpiSetFirmwareWakingVector +into two: one for the 32-bit vector, another for the 64-bit vector. This +is +required because the host OS must setup the wake much differently for +each +vector (real vs. protected mode, etc.) and the interface itself should +not +be +deciding which vector to use. Also, eliminated the +GetFirmwareWakingVector +interface, as it served no purpose (only the firmware reads the vector, +OS +only writes the vector.) ACPICA BZ 731. + +Implemented a mechanism to escape infinite AML While() loops. Added a +loop +counter to force exit from AML While loops if the count becomes too +large. +This can occur in poorly written AML when the hardware does not respond +within a while loop and the loop does not implement a timeout. The +maximum +loop count is configurable. A new exception code is returned when a loop +is +broken, AE_AML_INFINITE_LOOP. Alexey Starikovskiy, Bob Moore. + +Optimized the execution of AML While loops. Previously, a control state +object was allocated and freed for each execution of the loop. The +optimization is to simply reuse the control state for each iteration. +This +speeds up the raw loop execution time by about 5%. + +Enhanced the implicit return mechanism. For Windows compatibility, return +an +implicit integer of value zero for methods that contain no executable +code. +Such methods are seen in the field as stubs (presumably), and can cause +drivers to fail if they expect a return value. Lin Ming. + +Allow multiple backslashes as root prefixes in namepaths. In a fully +qualified namepath, allow multiple backslash prefixes. This can happen +(and +is seen in the field) because of the use of a double-backslash in strings +(since backslash is the escape character) causing confusion. ACPICA BZ +739 +Lin Ming. + +Emit a warning if two different FACS or DSDT tables are discovered in the +FADT. Checks if there are two valid but different addresses for the FACS +and +DSDT within the FADT (mismatch between the 32-bit and 64-bit fields.) + +Consolidated the method argument count validation code. Merged the code +that +validates control method argument counts into the predefined validation +module. Eliminates possible multiple warnings for incorrect argument +counts. + +Implemented ACPICA example code. Includes code for ACPICA initialization, +handler installation, and calling a control method. Available at +source/tools/examples. + +Added a global pointer for FACS table to simplify internal FACS access. +Use +the global pointer instead of using AcpiGetTableByIndex for each FACS +access. +This simplifies the code for the Global Lock and the Firmware Waking +Vector(s). + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 81.2K Code, 17.0K Data, 98.2K Total + Debug Version: 155.8K Code, 49.1K Data, 204.9K Total + Current Release: + Non-Debug Version: 81.7K Code, 17.3K Data, 99.0K Total + Debug Version: 156.4K Code, 49.4K Data, 205.8K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Improved disassembly of external method calls. Added the -e option +to +allow the inclusion of additional ACPI tables to help with the +disassembly +of +method invocations and the generation of external declarations during the +disassembly. Certain external method invocations cannot be disassembled +properly without the actual declaration of the method. Use the -e option +to +include the table where the external method(s) are actually declared. +Most +useful for disassembling SSDTs that make method calls back to the master +DSDT. Lin Ming. Example: To disassemble an SSDT with calls to DSDT: iasl +-d +-e dsdt.aml ssdt1.aml + +iASL: Fix to allow references to aliases within ASL namepaths. Fixes a +problem where the use of an alias within a namepath would result in a not +found error or cause the compiler to fault. Also now allows forward +references from the Alias operator itself. ACPICA BZ 738. + +---------------------------------------- +26 September 2008. Summary of changes for version 20080926: + +1) ACPI CA Core Subsystem: + +Designed and implemented a mechanism to validate predefined ACPI methods +and +objects. This code validates the predefined ACPI objects (objects whose +names +start with underscore) that appear in the namespace, at the time they are +evaluated. The argument count and the type of the returned object are +validated against the ACPI specification. The purpose of this validation +is +to detect problems with the BIOS-implemented predefined ACPI objects +before +the results are returned to the ACPI-related drivers. Future enhancements +may +include actual repair of incorrect return objects where possible. Two new +files are nspredef.c and acpredef.h. + +Fixed a fault in the AML parser if a memory allocation fails during the +Op +completion routine AcpiPsCompleteThisOp. Lin Ming. ACPICA BZ 492. + +Fixed an issue with implicit return compatibility. This change improves +the +implicit return mechanism to be more compatible with the MS interpreter. +Lin +Ming, ACPICA BZ 349. + +Implemented support for zero-length buffer-to-string conversions. Allow +zero +length strings during interpreter buffer-to-string conversions. For +example, +during the ToDecimalString and ToHexString operators, as well as implicit +conversions. Fiodor Suietov, ACPICA BZ 585. + +Fixed two possible memory leaks in the error exit paths of +AcpiUtUpdateObjectReference and AcpiUtWalkPackageTree. These functions +are +similar in that they use a stack of state objects in order to eliminate +recursion. The stack must be fully unwound and deallocated if an error +occurs. Lin Ming. ACPICA BZ 383. + +Removed the unused ACPI_BITREG_WAKE_ENABLE definition and entry in the +global +ACPI register table. This bit does not exist and is unused. Lin Ming, Bob +Moore ACPICA BZ 442. + +Removed the obsolete version number in module headers. Removed the +"$Revision" number that appeared in each module header. This version +number +was useful under SourceSafe and CVS, but has no meaning under git. It is +not +only incorrect, it could also be misleading. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 79.7K Code, 16.4K Data, 96.1K Total + Debug Version: 153.7K Code, 48.2K Data, 201.9K Total + Current Release: + Non-Debug Version: 81.2K Code, 17.0K Data, 98.2K Total + Debug Version: 155.8K Code, 49.1K Data, 204.9K Total + +---------------------------------------- +29 August 2008. Summary of changes for version 20080829: + +1) ACPI CA Core Subsystem: + +Completed a major cleanup of the internal ACPI_OPERAND_OBJECT of type +Reference. Changes include the elimination of cheating on the Object +field +for the DdbHandle subtype, addition of a reference class field to +differentiate the various reference types (instead of an AML opcode), and +the +cleanup of debug output for this object. Lin Ming, Bob Moore. BZ 723 + +Reduce an error to a warning for an incorrect method argument count. +Previously aborted with an error if too few arguments were passed to a +control method via the external ACPICA interface. Now issue a warning +instead +and continue. Handles the case where the method inadvertently declares +too +many arguments, but does not actually use the extra ones. Applies mainly +to +the predefined methods. Lin Ming. Linux BZ 11032. + +Disallow the evaluation of named object types with no intrinsic value. +Return +AE_TYPE for objects that have no value and therefore evaluation is +undefined: +Device, Event, Mutex, Region, Thermal, and Scope. Previously, evaluation +of +these types were allowed, but an exception would be generated at some +point +during the evaluation. Now, the error is generated up front. + +Fixed a possible memory leak in the AcpiNsGetExternalPathname function +(nsnames.c). Fixes a leak in the error exit path. + +Removed the obsolete debug levels ACPI_DB_WARN and ACPI_DB_ERROR. These +debug +levels were made obsolete by the ACPI_WARNING, ACPI_ERROR, and +ACPI_EXCEPTION +interfaces. Also added ACPI_DB_EVENTS to correspond with the existing +ACPI_LV_EVENTS. + +Removed obsolete and/or unused exception codes from the acexcep.h header. +There is the possibility that certain device drivers may be affected if +they +use any of these exceptions. + +The ACPICA documentation has been added to the public git source tree, +under +acpica/documents. Included are the ACPICA programmer reference, the iASL +compiler reference, and the changes.txt release logfile. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 79.7K Code, 16.4K Data, 96.1K Total + Debug Version: 153.9K Code, 48.4K Data, 202.3K Total + Current Release: + Non-Debug Version: 79.7K Code, 16.4K Data, 96.1K Total + Debug Version: 153.7K Code, 48.2K Data, 201.9K Total + +2) iASL Compiler/Disassembler and Tools: + +Allow multiple argument counts for the predefined _SCP method. ACPI 3.0 +defines _SCP with 3 arguments. Previous versions defined it with only 1 +argument. iASL now allows both definitions. + +iASL/disassembler: avoid infinite loop on bad ACPI tables. Check for +zero- +length subtables when disassembling ACPI tables. Also fixed a couple of +errors where a full 16-bit table type field was not extracted from the +input +properly. + +acpisrc: Improve comment counting mechanism for generating source code +statistics. Count first and last lines of multi-line comments as +whitespace, +not comment lines. Handle Linux legal header in addition to standard +acpica +header. + +---------------------------------------- + +29 July 2008. Summary of changes for version 20080729: + +1) ACPI CA Core Subsystem: + +Fix a possible deadlock in the GPE dispatch. Remove call to +AcpiHwDisableAllGpes during wake in AcpiEvGpeDispatch. This call will +attempt +to acquire the GPE lock but can deadlock since the GPE lock is already +held +at dispatch time. This code was introduced in version 20060831 as a +response +to Linux BZ 6881 and has since been removed from Linux. + +Add a function to dereference returned reference objects. Examines the +return +object from a call to AcpiEvaluateObject. Any Index or RefOf references +are +automatically dereferenced in an attempt to return something useful +(these +reference types cannot be converted into an external ACPI_OBJECT.) +Provides +MS compatibility. Lin Ming, Bob Moore. Linux BZ 11105 + +x2APIC support: changes for MADT and SRAT ACPI tables. There are 2 new +subtables for the MADT and one new subtable for the SRAT. Includes +disassembler and AcpiSrc support. Data from the Intel 64 Architecture +x2APIC +Specification, June 2008. + +Additional error checking for pathname utilities. Add error check after +all +calls to AcpiNsGetPathnameLength. Add status return from +AcpiNsBuildExternalPath and check after all calls. Add parameter +validation +to AcpiUtInitializeBuffer. Reported by and initial patch by Ingo Molnar. + +Return status from the global init function AcpiUtGlobalInitialize. This +is +used by both the kernel subsystem and the utilities such as iASL +compiler. +The function could possibly fail when the caches are initialized. Yang +Yi. + +Add a function to decode reference object types to strings. Created for +improved error messages. + +Improve object conversion error messages. Better error messages during +object +conversion from internal to the external ACPI_OBJECT. Used for external +calls +to AcpiEvaluateObject. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 79.6K Code, 16.2K Data, 95.8K Total + Debug Version: 153.5K Code, 48.2K Data, 201.7K Total + Current Release: + Non-Debug Version: 79.7K Code, 16.4K Data, 96.1K Total + Debug Version: 153.9K Code, 48.4K Data, 202.3K Total + +2) iASL Compiler/Disassembler and Tools: + +Debugger: fix a possible hang when evaluating non-methods. Fixes a +problem +introduced in version 20080701. If the object being evaluated (via +execute +command) is not a method, the debugger can hang while trying to obtain +non- +existent parameters. + +iASL: relax error for using reserved "_T_x" identifiers. These names can +appear in a disassembled ASL file if they were emitted by the original +compiler. Instead of issuing an error or warning and forcing the user to +manually change these names, issue a remark instead. + +iASL: error if named object created in while loop. Emit an error if any +named +object is created within a While loop. If allowed, this code will +generate +a +run-time error on the second iteration of the loop when an attempt is +made +to +create the same named object twice. ACPICA bugzilla 730. + +iASL: Support absolute pathnames for include files. Add support for +absolute +pathnames within the Include operator. previously, only relative +pathnames +were supported. + +iASL: Enforce minimum 1 interrupt in interrupt macro and Resource +Descriptor. +The ACPI spec requires one interrupt minimum. BZ 423 + +iASL: Handle a missing ResourceSource arg, with a present SourceIndex. +Handles the case for the Interrupt Resource Descriptor where +the ResourceSource argument is omitted but ResourceSourceIndex +is present. Now leave room for the Index. BZ 426 + +iASL: Prevent error message if CondRefOf target does not exist. Fixes +cases +where an error message is emitted if the target does not exist. BZ 516 + +iASL: Fix broken -g option (get Windows ACPI tables). Fixes the -g option +(get ACPI tables on Windows). This was apparently broken in version +20070919. + +AcpiXtract: Handle EOF while extracting data. Correctly handle the case +where +the EOF happens immediately after the last table in the input file. Print +completion message. Previously, no message was displayed in this case. + +---------------------------------------- +01 July 2008. Summary of changes for version 20080701: + +0) Git source tree / acpica.org + +Fixed a problem where a git-clone from http would not transfer the entire +source tree. + +1) ACPI CA Core Subsystem: + +Implemented a "careful" GPE disable in AcpiEvDisableGpe, only modify one +enable bit. Now performs a read-change-write of the enable register +instead +of simply writing out the cached enable mask. This will prevent +inadvertent +enabling of GPEs if a rogue GPE is received during initialization (before +GPE +handlers are installed.) + +Implemented a copy for dynamically loaded tables. Previously, dynamically +loaded tables were simply mapped - but on some machines this memory is +corrupted after suspend. Now copy the table to a local buffer. For the +OpRegion case, added checksum verify. Use the table length from the table +header, not the region length. For the Buffer case, use the table length +also. Dennis Noordsij, Bob Moore. BZ 10734 + +Fixed a problem where the same ACPI table could not be dynamically loaded +and +unloaded more than once. Without this change, a table cannot be loaded +again +once it has been loaded/unloaded one time. The current mechanism does not +unregister a table upon an unload. During a load, if the same table is +found, +this no longer returns an exception. BZ 722 + +Fixed a problem where the wrong descriptor length was calculated for the +EndTag descriptor in 64-bit mode. The "minimal" descriptors such as +EndTag +are calculated as 12 bytes long, but the actual length in the internal +descriptor is 16 because of the round-up to 8 on the 64-bit build. +Reported +by Linn Crosetto. BZ 728 + +Fixed a possible memory leak in the Unload operator. The DdbHandle +returned +by Load() did not have its reference count decremented during unload, +leading +to a memory leak. Lin Ming. BZ 727 + +Fixed a possible memory leak when deleting thermal/processor objects. Any +associated notify handlers (and objects) were not being deleted. Fiodor +Suietov. BZ 506 + +Fixed the ordering of the ASCII names in the global mutex table to match +the +actual mutex IDs. Used by AcpiUtGetMutexName, a function used for debug +only. +Vegard Nossum. BZ 726 + +Enhanced the AcpiGetObjectInfo interface to return the number of required +arguments if the object is a control method. Added this call to the +debugger +so the proper number of default arguments are passed to a method. This +prevents a warning when executing methods from AcpiExec. + +Added a check for an invalid handle in AcpiGetObjectInfo. Return +AE_BAD_PARAMETER if input handle is invalid. BZ 474 + +Fixed an extraneous warning from exconfig.c on the 64-bit build. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 79.3K Code, 16.2K Data, 95.5K Total + Debug Version: 153.0K Code, 48.2K Data, 201.2K Total + Current Release: + Non-Debug Version: 79.6K Code, 16.2K Data, 95.8K Total + Debug Version: 153.5K Code, 48.2K Data, 201.7K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Added two missing ACPI reserved names. Added _MTP and _ASZ, both +resource descriptor names. + +iASL: Detect invalid ASCII characters in input (windows version). Removed +the +"-CF" flag from the flex compile, enables correct detection of non-ASCII +characters in the input. BZ 441 + +iASL: Eliminate warning when result of LoadTable is not used. Eliminate +the +"result of operation not used" warning when the DDB handle returned from +LoadTable is not used. The warning is not needed. BZ 590 + +AcpiExec: Add support for dynamic table load/unload. Now calls _CFG +method +to +pass address of table to the AML. Added option to disable OpRegion +simulation +to allow creation of an OpRegion with a real address that was passed to +_CFG. +All of this allows testing of the Load and Unload operators from +AcpiExec. + +Debugger: update tables command for unloaded tables. Handle unloaded +tables +and use the standard table header output routine. + +---------------------------------------- +09 June 2008. Summary of changes for version 20080609: + +1) ACPI CA Core Subsystem: + +Implemented a workaround for reversed _PRT entries. A significant number +of +BIOSs erroneously reverse the _PRT SourceName and the SourceIndex. This +change dynamically detects and repairs this problem. Provides +compatibility +with MS ACPI. BZ 6859 + +Simplified the internal ACPI hardware interfaces to eliminate the locking +flag parameter from Register Read/Write. Added a new external interface, +AcpiGetRegisterUnlocked. + +Fixed a problem where the invocation of a GPE control method could hang. +This +was a regression introduced in 20080514. The new method argument count +validation mechanism can enter an infinite loop when a GPE method is +dispatched. Problem fixed by removing the obsolete code that passed GPE +block +information to the notify handler via the control method parameter +pointer. + +Fixed a problem where the _SST execution status was incorrectly returned +to +the caller of AcpiEnterSleepStatePrep. This was a regression introduced +in +20080514. _SST is optional and a NOT_FOUND exception should never be +returned. BZ 716 + +Fixed a problem where a deleted object could be accessed from within the +AML +parser. This was a regression introduced in version 20080123 as a fix for +the +Unload operator. Lin Ming. BZ 10669 + +Cleaned up the debug operand dump mechanism. Eliminated unnecessary +operands +and eliminated the use of a negative index in a loop. Operands are now +displayed in the correct order, not backwards. This also fixes a +regression +introduced in 20080514 on 64-bit systems where the elimination of +ACPI_NATIVE_UINT caused the negative index to go large and positive. BZ +715 + +Fixed a possible memory leak in EvPciConfigRegionSetup where the error +exit +path did not delete a locally allocated structure. + +Updated definitions for the DMAR and SRAT tables to synchronize with the +current specifications. Includes disassembler support. + +Fixed a problem in the mutex debug code (in utmutex.c) where an incorrect +loop termination value was used. Loop terminated on iteration early, +missing +one mutex. Linn Crosetto + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 79.5K Code, 16.2K Data, 95.7K Total + Debug Version: 153.3K Code, 48.3K Data, 201.6K Total + Current Release: + Non-Debug Version: 79.3K Code, 16.2K Data, 95.5K Total + Debug Version: 153.0K Code, 48.2K Data, 201.2K Total + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Implemented support for EisaId() within _CID objects. Now +disassemble integer _CID objects back to EisaId invocations, including +multiple integers within _CID packages. Includes single-step support for +debugger also. + +Disassembler: Added support for DMAR and SRAT table definition changes. + +---------------------------------------- +14 May 2008. Summary of changes for version 20080514: + +1) ACPI CA Core Subsystem: + +Fixed a problem where GPEs were enabled too early during the ACPICA +initialization. This could lead to "handler not installed" errors on some +machines. Moved GPE enable until after _REG/_STA/_INI methods are run. +This +ensures that all operation regions and devices throughout the namespace +have +been initialized before GPEs are enabled. Alexey Starikovskiy, BZ 9916. + +Implemented a change to the enter sleep code. Moved execution of the _GTS +method to just before setting sleep enable bit. The execution was moved +from +AcpiEnterSleepStatePrep to AcpiEnterSleepState. _GTS is now executed +immediately before the SLP_EN bit is set, as per the ACPI specification. +Luming Yu, BZ 1653. + +Implemented a fix to disable unknown GPEs (2nd version). Now always +disable +the GPE, even if ACPICA thinks that that it is already disabled. It is +possible that the AML or some other code has enabled the GPE unbeknownst +to +the ACPICA code. + +Fixed a problem with the Field operator where zero-length fields would +return +an AE_AML_NO_OPERAND exception during table load. Fix enables zero-length +ASL +field declarations in Field(), BankField(), and IndexField(). BZ 10606. + +Implemented a fix for the Load operator, now load the table at the +namespace +root. This reverts a change introduced in version 20071019. The table is +now +loaded at the namespace root even though this goes against the ACPI +specification. This provides compatibility with other ACPI +implementations. +The ACPI specification will be updated to reflect this in ACPI 4.0. Lin +Ming. + +Fixed a problem where ACPICA would not Load() tables with unusual +signatures. +Now ignore ACPI table signature for Load() operator. Only "SSDT" is +acceptable to the ACPI spec, but tables are seen with OEMx and null sigs. +Therefore, signature validation is worthless. Apparently MS ACPI accepts +such +signatures, ACPICA must be compatible. BZ 10454. + +Fixed a possible negative array index in AcpiUtValidateException. Added +NULL +fields to the exception string arrays to eliminate a -1 subtraction on +the +SubStatus field. + +Updated the debug tracking macros to reduce overall code and data size. +Changed ACPI_MODULE_NAME and ACPI_FUNCTION_NAME to use arrays of strings +instead of pointers to static strings. Jan Beulich and Bob Moore. + +Implemented argument count checking in control method invocation via +AcpiEvaluateObject. Now emit an error if too few arguments, warning if +too +many. This applies only to extern programmatic control method execution, +not +method-to-method calls within the AML. Lin Ming. + +Eliminated the ACPI_NATIVE_UINT type across all ACPICA code. This type is +no +longer needed, especially with the removal of 16-bit support. It was +replaced +mostly with UINT32, but also ACPI_SIZE where a type that changes 32/64 +bit +on +32/64-bit platforms is required. + +Added the C const qualifier for appropriate string constants -- mostly +MODULE_NAME and printf format strings. Jan Beulich. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 80.0K Code, 17.4K Data, 97.4K Total + Debug Version: 159.4K Code, 64.4K Data, 223.8K Total + Current Release: + Non-Debug Version: 79.5K Code, 16.2K Data, 95.7K Total + Debug Version: 153.3K Code, 48.3K Data, 201.6K Total + +2) iASL Compiler/Disassembler and Tools: + +Implemented ACPI table revision ID validation in the disassembler. Zero +is +always invalid. For DSDTs, the ID controls the interpreter integer width. +1 +means 32-bit and this is unusual. 2 or greater is 64-bit. + +---------------------------------------- +21 March 2008. Summary of changes for version 20080321: + +1) ACPI CA Core Subsystem: + +Implemented an additional change to the GPE support in order to suppress +spurious or stray GPEs. The AcpiEvDisableGpe function will now +permanently +disable incoming GPEs that are neither enabled nor disabled -- meaning +that +the GPE is unknown to the system. This should prevent future interrupt +floods +from that GPE. BZ 6217 (Zhang Rui) + +Fixed a problem where NULL package elements were not returned to the +AcpiEvaluateObject interface correctly. The element was simply ignored +instead of returning a NULL ACPI_OBJECT package element, potentially +causing +a buffer overflow and/or confusing the caller who expected a fixed number +of +elements. BZ 10132 (Lin Ming, Bob Moore) + +Fixed a problem with the CreateField, CreateXXXField (Bit, Byte, Word, +Dword, +Qword), Field, BankField, and IndexField operators when invoked from +inside +an executing control method. In this case, these operators created +namespace +nodes that were incorrectly left marked as permanent nodes instead of +temporary nodes. This could cause a problem if there is race condition +between an exiting control method and a running namespace walk. (Reported +by +Linn Crosetto) + +Fixed a problem where the CreateField and CreateXXXField operators would +incorrectly allow duplicate names (the name of the field) with no +exception +generated. + +Implemented several changes for Notify handling. Added support for new +Notify +values (ACPI 2.0+) and improved the Notify debug output. Notify on +PowerResource objects is no longer allowed, as per the ACPI +specification. +(Bob Moore, Zhang Rui) + +All Reference Objects returned via the AcpiEvaluateObject interface are +now +marked as type "REFERENCE" instead of "ANY". The type ANY is now reserved +for +NULL objects - either NULL package elements or unresolved named +references. + +Fixed a problem where an extraneous debug message was produced for +package +objects (when debugging enabled). The message "Package List length larger +than NumElements count" is now produced in the correct case, and is now +an +error message rather than a debug message. Added a debug message for the +opposite case, where NumElements is larger than the Package List (the +package +will be padded out with NULL elements as per the ACPI spec.) + +Implemented several improvements for the output of the ASL "Debug" object +to +clarify and keep all data for a given object on one output line. + +Fixed two size calculation issues with the variable-length Start +Dependent +resource descriptor. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 79.7K Code, 17.3K Data, 97.0K Total + Debug Version: 158.9K Code, 64.0K Data, 222.9K Total + Current Release: + Non-Debug Version: 80.0K Code, 17.4K Data, 97.4K Total + Debug Version: 159.4K Code, 64.4K Data, 223.8K Total + +2) iASL Compiler/Disassembler and Tools: + +Fixed a problem with the use of the Switch operator where execution of +the +containing method by multiple concurrent threads could cause an +AE_ALREADY_EXISTS exception. This is caused by the fact that there is no +actual Switch opcode, it must be simulated with local named temporary +variables and if/else pairs. The solution chosen was to mark any method +that +uses Switch as Serialized, thus preventing multiple thread entries. BZ +469. + +---------------------------------------- +13 February 2008. Summary of changes for version 20080213: + +1) ACPI CA Core Subsystem: + +Implemented another MS compatibility design change for GPE/Notify +handling. +GPEs are now cleared/enabled asynchronously to allow all pending notifies +to +complete first. It is expected that the OSL will queue the enable request +behind all pending notify requests (may require changes to the local host +OSL +in AcpiOsExecute). Alexey Starikovskiy. + +Fixed a problem where buffer and package objects passed as arguments to a +control method via the external AcpiEvaluateObject interface could cause +an +AE_AML_INTERNAL exception depending on the order and type of operators +executed by the target control method. + +Fixed a problem where resource descriptor size optimization could cause a +problem when a _CRS resource template is passed to a _SRS method. The +_SRS +resource template must use the same descriptors (with the same size) as +returned from _CRS. This change affects the following resource +descriptors: +IRQ / IRQNoFlags and StartDependendentFn / StartDependentFnNoPri. (BZ +9487) + +Fixed a problem where a CopyObject to RegionField, BankField, and +IndexField +objects did not perform an implicit conversion as it should. These types +must +retain their initial type permanently as per the ACPI specification. +However, +a CopyObject to all other object types should not perform an implicit +conversion, as per the ACPI specification. (Lin Ming, Bob Moore) BZ 388 + +Fixed a problem with the AcpiGetDevices interface where the mechanism to +match device CIDs did not examine the entire list of available CIDs, but +instead aborted on the first non-matching CID. Andrew Patterson. + +Fixed a regression introduced in version 20071114. The ACPI_HIDWORD macro +was +inadvertently changed to return a 16-bit value instead of a 32-bit value, +truncating the upper dword of a 64-bit value. This macro is only used to +display debug output, so no incorrect calculations were made. Also, +reimplemented the macro so that a 64-bit shift is not performed by +inefficient compilers. + +Added missing va_end statements that should correspond with each va_start +statement. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 79.5K Code, 17.2K Data, 96.7K Total + Debug Version: 159.0K Code, 63.8K Data, 222.8K Total + Current Release: + Non-Debug Version: 79.7K Code, 17.3K Data, 97.0K Total + Debug Version: 158.9K Code, 64.0K Data, 222.9K Total + +2) iASL Compiler/Disassembler and Tools: + +Implemented full disassembler support for the following new ACPI tables: +BERT, EINJ, and ERST. Implemented partial disassembler support for the +complicated HEST table. These tables support the Windows Hardware Error +Architecture (WHEA). + +---------------------------------------- +23 January 2008. Summary of changes for version 20080123: + +1) ACPI CA Core Subsystem: + +Added the 2008 copyright to all module headers and signons. This affects +virtually every file in the ACPICA core subsystem, the iASL compiler, and +the tools/utilities. + +Fixed a problem with the SizeOf operator when used with Package and +Buffer +objects. These objects have deferred execution for some arguments, and +the +execution is now completed before the SizeOf is executed. This problem +caused +unexpected AE_PACKAGE_LIMIT errors on some systems (Lin Ming, Bob Moore) +BZ +9558 + +Implemented an enhancement to the interpreter "slack mode". In the +absence +of +an explicit return or an implicitly returned object from the last +executed +opcode, a control method will now implicitly return an integer of value 0 +for +Microsoft compatibility. (Lin Ming) BZ 392 + +Fixed a problem with the Load operator where an exception was not +returned +in +the case where the table is already loaded. (Lin Ming) BZ 463 + +Implemented support for the use of DDBHandles as an Indexed Reference, as +per +the ACPI spec. (Lin Ming) BZ 486 + +Implemented support for UserTerm (Method invocation) for the Unload +operator +as per the ACPI spec. (Lin Ming) BZ 580 + +Fixed a problem with the LoadTable operator where the OemId and +OemTableId +input strings could cause unexpected failures if they were shorter than +the +maximum lengths allowed. (Lin Ming, Bob Moore) BZ 576 + +Implemented support for UserTerm (Method invocation) for the Unload +operator +as per the ACPI spec. (Lin Ming) BZ 580 + +Implemented header file support for new ACPI tables - BERT, ERST, EINJ, +HEST, +IBFT, UEFI, WDAT. Disassembler support is forthcoming. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 79.3K Code, 17.2K Data, 96.5K Total + Debug Version: 158.6K Code, 63.8K Data, 222.4K Total + Current Release: + Non-Debug Version: 79.5K Code, 17.2K Data, 96.7K Total + Debug Version: 159.0K Code, 63.8K Data, 222.8K Total + +2) iASL Compiler/Disassembler and Tools: + +Implemented support in the disassembler for checksum validation on +incoming +binary DSDTs and SSDTs. If incorrect, a message is displayed within the +table +header dump at the start of the disassembly. + +Implemented additional debugging information in the namespace listing +file +created during compilation. In addition to the namespace hierarchy, the +full +pathname to each namespace object is displayed. + +Fixed a problem with the disassembler where invalid ACPI tables could +cause +faults or infinite loops. + +Fixed an unexpected parse error when using the optional "parameter types" +list in a control method declaration. (Lin Ming) BZ 397 + +Fixed a problem where two External declarations with the same name did +not +cause an error (Lin Ming) BZ 509 + +Implemented support for full TermArgs (adding Argx, Localx and method +invocation) for the ParameterData parameter to the LoadTable operator. +(Lin +Ming) BZ 583,587 + +---------------------------------------- +19 December 2007. Summary of changes for version 20071219: + +1) ACPI CA Core Subsystem: + +Implemented full support for deferred execution for the TermArg string +arguments for DataTableRegion. This enables forward references and full +operand resolution for the three string arguments. Similar to +OperationRegion +deferred argument execution.) Lin Ming. BZ 430 + +Implemented full argument resolution support for the BankValue argument +to +BankField. Previously, only constants were supported, now any TermArg may +be +used. Lin Ming BZ 387, 393 + +Fixed a problem with AcpiGetDevices where the search of a branch of the +device tree could be terminated prematurely. In accordance with the ACPI +specification, the search down the current branch is terminated if a +device +is both not present and not functional (instead of just not present.) +Yakui +Zhao. + +Fixed a problem where "unknown" GPEs could be allowed to fire repeatedly +if +the underlying AML code changed the GPE enable registers. Now, any +unknown +incoming GPE (no _Lxx/_Exx method and not the EC GPE) is immediately +disabled +instead of simply ignored. Rui Zhang. + +Fixed a problem with Index Fields where the Index register was +incorrectly +limited to a maximum of 32 bits. Now any size may be used. + +Fixed a couple memory leaks associated with "implicit return" objects +when +the AML Interpreter slack mode is enabled. Lin Ming BZ 349 + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 79.0K Code, 17.2K Data, 96.2K Total + Debug Version: 157.9K Code, 63.6K Data, 221.5K Total + Current Release: + Non-Debug Version: 79.3K Code, 17.2K Data, 96.5K Total + Debug Version: 158.6K Code, 63.8K Data, 222.4K Total + +---------------------------------------- +14 November 2007. Summary of changes for version 20071114: + +1) ACPI CA Core Subsystem: + +Implemented event counters for each of the Fixed Events, the ACPI SCI +(interrupt) itself, and control methods executed. Named +AcpiFixedEventCount[], AcpiSciCount, and AcpiMethodCount respectively. +These +should be useful for debugging and statistics. + +Implemented a new external interface, AcpiGetStatistics, to retrieve the +contents of the various event counters. Returns the current values for +AcpiSciCount, AcpiGpeCount, the AcpiFixedEventCount array, and +AcpiMethodCount. The interface can be expanded in the future if new +counters +are added. Device drivers should use this interface rather than access +the +counters directly. + +Fixed a problem with the FromBCD and ToBCD operators. With some +compilers, +the ShortDivide function worked incorrectly, causing problems with the +BCD +functions with large input values. A truncation from 64-bit to 32-bit +inadvertently occurred. Internal BZ 435. Lin Ming + +Fixed a problem with Index references passed as method arguments. +References +passed as arguments to control methods were dereferenced immediately +(before +control was passed to the called method). The references are now +correctly +passed directly to the called method. BZ 5389. Lin Ming + +Fixed a problem with CopyObject used in conjunction with the Index +operator. +The reference was incorrectly dereferenced before the copy. The reference +is +now correctly copied. BZ 5391. Lin Ming + +Fixed a problem with Control Method references within Package objects. +These +references are now correctly generated. This completes the package +construction overhaul that began in version 20071019. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.8K Code, 17.2K Data, 96.0K Total + Debug Version: 157.2K Code, 63.4K Data, 220.6K Total + Current Release: + Non-Debug Version: 79.0K Code, 17.2K Data, 96.2K Total + Debug Version: 157.9K Code, 63.6K Data, 221.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +The AcpiExec utility now installs handlers for all of the predefined +Operation Region types. New types supported are: PCI_Config, CMOS, and +PCIBARTarget. + +Fixed a problem with the 64-bit version of AcpiExec where the extended +(64- +bit) address fields for the DSDT and FACS within the FADT were not being +used, causing truncation of the upper 32-bits of these addresses. Lin +Ming +and Bob Moore + +---------------------------------------- +19 October 2007. Summary of changes for version 20071019: + +1) ACPI CA Core Subsystem: + +Fixed a problem with the Alias operator when the target of the alias is a +named ASL operator that opens a new scope -- Scope, Device, +PowerResource, +Processor, and ThermalZone. In these cases, any children of the original +operator could not be accessed via the alias, potentially causing +unexpected +AE_NOT_FOUND exceptions. (BZ 9067) + +Fixed a problem with the Package operator where all named references were +created as object references and left otherwise unresolved. According to +the +ACPI specification, a Package can only contain Data Objects or references +to +control methods. The implication is that named references to Data Objects +(Integer, Buffer, String, Package, BufferField, Field) should be resolved +immediately upon package creation. This is the approach taken with this +change. References to all other named objects (Methods, Devices, Scopes, +etc.) are all now properly created as reference objects. (BZ 5328) + +Reverted a change to Notify handling that was introduced in version +20070508. This version changed the Notify handling from asynchronous to +fully synchronous (Device driver Notify handling with respect to the +Notify +ASL operator). It was found that this change caused more problems than it +solved and was removed by most users. + +Fixed a problem with the Increment and Decrement operators where the type +of +the target object could be unexpectedly and incorrectly changed. (BZ 353) +Lin Ming. + +Fixed a problem with the Load and LoadTable operators where the table +location within the namespace was ignored. Instead, the table was always +loaded into the root or current scope. Lin Ming. + +Fixed a problem with the Load operator when loading a table from a buffer +object. The input buffer was prematurely zeroed and/or deleted. (BZ 577) + +Fixed a problem with the Debug object where a store of a DdbHandle +reference +object to the Debug object could cause a fault. + +Added a table checksum verification for the Load operator, in the case +where +the load is from a buffer. (BZ 578). + +Implemented additional parameter validation for the LoadTable operator. +The +length of the input strings SignatureString, OemIdString, and OemTableId +are +now checked for maximum lengths. (BZ 582) Lin Ming. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.5K Code, 17.1K Data, 95.6K Total + Debug Version: 156.7K Code, 63.2K Data, 219.9K Total + Current Release: + Non-Debug Version: 78.8K Code, 17.2K Data, 96.0K Total + Debug Version: 157.2K Code, 63.4K Data, 220.6K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem where if a single file was specified and the file did not +exist, no error message was emitted. (Introduced with wildcard support in +version 20070917.) + +---------------------------------------- +19 September 2007. Summary of changes for version 20070919: + +1) ACPI CA Core Subsystem: + +Designed and implemented new external interfaces to install and remove +handlers for ACPI table-related events. Current events that are defined +are +LOAD and UNLOAD. These interfaces allow the host to track ACPI tables as +they are dynamically loaded and unloaded. See AcpiInstallTableHandler and +AcpiRemoveTableHandler. (Lin Ming and Bob Moore) + +Fixed a problem where the use of the AcpiGbl_AllMethodsSerialized flag +(acpi_serialized option on Linux) could cause some systems to hang during +initialization. (Bob Moore) BZ 8171 + +Fixed a problem where objects of certain types (Device, ThermalZone, +Processor, PowerResource) can be not found if they are declared and +referenced from within the same control method (Lin Ming) BZ 341 + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.3K Code, 17.0K Data, 95.3K Total + Debug Version: 156.3K Code, 63.1K Data, 219.4K Total + Current Release: + Non-Debug Version: 78.5K Code, 17.1K Data, 95.6K Total + Debug Version: 156.7K Code, 63.2K Data, 219.9K Total + + +2) iASL Compiler/Disassembler: + +Implemented support to allow multiple files to be compiled/disassembled +in +a +single invocation. This includes command line wildcard support for both +the +Windows and Unix versions of the compiler. This feature simplifies the +disassembly and compilation of multiple ACPI tables in a single +directory. + +---------------------------------------- +08 May 2007. Summary of changes for version 20070508: + +1) ACPI CA Core Subsystem: + +Implemented a Microsoft compatibility design change for the handling of +the +Notify AML operator. Previously, notify handlers were dispatched and +executed completely asynchronously in a deferred thread. The new design +still executes the notify handlers in a different thread, but the +original +thread that executed the Notify() now waits at a synchronization point +for +the notify handler to complete. Some machines depend on a synchronous +Notify +operator in order to operate correctly. + +Implemented support to allow Package objects to be passed as method +arguments to the external AcpiEvaluateObject interface. Previously, this +would return the AE_NOT_IMPLEMENTED exception. This feature had not been +implemented since there were no reserved control methods that required it +until recently. + +Fixed a problem with the internal FADT conversion where ACPI 1.0 FADTs +that +contained invalid non-zero values in reserved fields could cause later +failures because these fields have meaning in later revisions of the +FADT. +For incoming ACPI 1.0 FADTs, these fields are now always zeroed. (The +fields +are: Preferred_PM_Profile, PSTATE_CNT, CST_CNT, and IAPC_BOOT_FLAGS.) + +Fixed a problem where the Global Lock handle was not properly updated if +a +thread that acquired the Global Lock via executing AML code then +attempted +to acquire the lock via the AcpiAcquireGlobalLock interface. Reported by +Joe +Liu. + +Fixed a problem in AcpiEvDeleteGpeXrupt where the global interrupt list +could be corrupted if the interrupt being removed was at the head of the +list. Reported by Linn Crosetto. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.0K Code, 17.1K Data, 95.1K Total + Debug Version: 155.9K Code, 63.1K Data, 219.0K Total + Current Release: + Non-Debug Version: 78.3K Code, 17.0K Data, 95.3K Total + Debug Version: 156.3K Code, 63.1K Data, 219.4K Total + +---------------------------------------- +20 March 2007. Summary of changes for version 20070320: + +1) ACPI CA Core Subsystem: + +Implemented a change to the order of interpretation and evaluation of AML +operand objects within the AML interpreter. The interpreter now evaluates +operands in the order that they appear in the AML stream (and the +corresponding ASL code), instead of in the reverse order (after the +entire +operand list has been parsed). The previous behavior caused several +subtle +incompatibilities with the Microsoft AML interpreter as well as being +somewhat non-intuitive. BZ 7871, local BZ 263. Valery Podrezov. + +Implemented a change to the ACPI Global Lock support. All interfaces to +the +global lock now allow the same thread to acquire the lock multiple times. +This affects the AcpiAcquireGlobalLock external interface to the global +lock +as well as the internal use of the global lock to support AML fields -- a +control method that is holding the global lock can now simultaneously +access +AML fields that require global lock protection. Previously, in both +cases, +this would have resulted in an AE_ALREADY_ACQUIRED exception. The change +to +AcpiAcquireGlobalLock is of special interest to drivers for the Embedded +Controller. There is no change to the behavior of the AML Acquire +operator, +as this can already be used to acquire a mutex multiple times by the same +thread. BZ 8066. With assistance from Alexey Starikovskiy. + +Fixed a problem where invalid objects could be referenced in the AML +Interpreter after error conditions. During operand evaluation, ensure +that +the internal "Return Object" field is cleared on error and only valid +pointers are stored there. Caused occasional access to deleted objects +that +resulted in "large reference count" warning messages. Valery Podrezov. + +Fixed a problem where an AE_STACK_OVERFLOW internal exception could occur +on +deeply nested control method invocations. BZ 7873, local BZ 487. Valery +Podrezov. + +Fixed an internal problem with the handling of result objects on the +interpreter result stack. BZ 7872. Valery Podrezov. + +Removed obsolete code that handled the case where AML_NAME_OP is the +target +of a reference (Reference.Opcode). This code was no longer necessary. BZ +7874. Valery Podrezov. + +Removed obsolete ACPI_NO_INTEGER64_SUPPORT from two header files. This +was +a +remnant from the previously discontinued 16-bit support. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.0K Code, 17.1K Data, 95.1K Total + Debug Version: 155.8K Code, 63.3K Data, 219.1K Total + Current Release: + Non-Debug Version: 78.0K Code, 17.1K Data, 95.1K Total + Debug Version: 155.9K Code, 63.1K Data, 219.0K Total + +---------------------------------------- +26 January 2007. Summary of changes for version 20070126: + +1) ACPI CA Core Subsystem: + +Added the 2007 copyright to all module headers and signons. This affects +virtually every file in the ACPICA core subsystem, the iASL compiler, and +the utilities. + +Implemented a fix for an incorrect parameter passed to AcpiTbDeleteTable +during a table load. A bad pointer was passed in the case where the DSDT +is +overridden, causing a fault in this case. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.0K Code, 17.1K Data, 95.1K Total + Debug Version: 155.8K Code, 63.3K Data, 219.1K Total + Current Release: + Non-Debug Version: 78.0K Code, 17.1K Data, 95.1K Total + Debug Version: 155.8K Code, 63.3K Data, 219.1K Total + +---------------------------------------- +15 December 2006. Summary of changes for version 20061215: + +1) ACPI CA Core Subsystem: + +Support for 16-bit ACPICA has been completely removed since it is no +longer +necessary and it clutters the code. All 16-bit macros, types, and +conditional compiles have been removed, cleaning up and simplifying the +code +across the entire subsystem. DOS support is no longer needed since the +bootable Linux firmware kit is now available. + +The handler for the Global Lock is now removed during AcpiTerminate to +enable a clean subsystem restart, via the implementation of the +AcpiEvRemoveGlobalLockHandler function. (With assistance from Joel Bretz, +HP) + +Implemented enhancements to the multithreading support within the +debugger +to enable improved multithreading debugging and evaluation of the +subsystem. +(Valery Podrezov) + +Debugger: Enhanced the Statistics/Memory command to emit the total +(maximum) +memory used during the execution, as well as the maximum memory consumed +by +each of the various object types. (Valery Podrezov) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 77.9K Code, 17.0K Data, 94.9K Total + Debug Version: 155.2K Code, 63.1K Data, 218.3K Total + Current Release: + Non-Debug Version: 78.0K Code, 17.1K Data, 95.1K Total + Debug Version: 155.8K Code, 63.3K Data, 219.1K Total + + +2) iASL Compiler/Disassembler and Tools: + +AcpiExec: Implemented a new option (-m) to display full memory use +statistics upon subsystem/program termination. (Valery Podrezov) + +---------------------------------------- +09 November 2006. Summary of changes for version 20061109: + +1) ACPI CA Core Subsystem: + +Optimized the Load ASL operator in the case where the source operand is +an +operation region. Simply map the operation region memory, instead of +performing a bytewise read. (Region must be of type SystemMemory, see +below.) + +Fixed the Load ASL operator for the case where the source operand is a +region field. A buffer object is also allowed as the source operand. BZ +480 + +Fixed a problem where the Load ASL operator allowed the source operand to +be +an operation region of any type. It is now restricted to regions of type +SystemMemory, as per the ACPI specification. BZ 481 + +Additional cleanup and optimizations for the new Table Manager code. + +AcpiEnable will now fail if all of the required ACPI tables are not +loaded +(FADT, FACS, DSDT). BZ 477 + +Added #pragma pack(8/4) to acobject.h to ensure that the structures in +this +header are always compiled as aligned. The ACPI_OPERAND_OBJECT has been +manually optimized to be aligned and will not work if it is byte-packed. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 78.1K Code, 17.1K Data, 95.2K Total + Debug Version: 155.4K Code, 63.1K Data, 218.5K Total + Current Release: + Non-Debug Version: 77.9K Code, 17.0K Data, 94.9K Total + Debug Version: 155.2K Code, 63.1K Data, 218.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed a problem where the presence of the _OSI predefined control method +within complex expressions could cause an internal compiler error. + +AcpiExec: Implemented full region support for multiple address spaces. +SpaceId is now part of the REGION object. BZ 429 + +---------------------------------------- +11 October 2006. Summary of changes for version 20061011: + +1) ACPI CA Core Subsystem: + +Completed an AML interpreter performance enhancement for control method +execution. Previously a 2-pass parse/execution, control methods are now +completely parsed and executed in a single pass. This improves overall +interpreter performance by ~25%, reduces code size, and reduces CPU stack +use. (Valery Podrezov + interpreter changes in version 20051202 that +eliminated namespace loading during the pass one parse.) + +Implemented _CID support for PCI Root Bridge detection. If the _HID does +not +match the predefined PCI Root Bridge IDs, the _CID list (if present) is +now +obtained and also checked for an ID match. + +Implemented additional support for the PCI _ADR execution: upsearch until +a +device scope is found before executing _ADR. This allows PCI_Config +operation regions to be declared locally within control methods +underneath +PCI device objects. + +Fixed a problem with a possible race condition between threads executing +AcpiWalkNamespace and the AML interpreter. This condition was removed by +modifying AcpiWalkNamespace to (by default) ignore all temporary +namespace +entries created during any concurrent control method execution. An +additional namespace race condition is known to exist between +AcpiWalkNamespace and the Load/Unload ASL operators and is still under +investigation. + +Restructured the AML ParseLoop function, breaking it into several +subfunctions in order to reduce CPU stack use and improve +maintainability. +(Mikhail Kouzmich) + +AcpiGetHandle: Fix for parameter validation to detect invalid +combinations +of prefix handle and pathname. BZ 478 + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 77.9K Code, 17.1K Data, 95.0K Total + Debug Version: 154.6K Code, 63.0K Data, 217.6K Total + Current Release: + Non-Debug Version: 78.1K Code, 17.1K Data, 95.2K Total + Debug Version: 155.4K Code, 63.1K Data, 218.5K Total + +2) iASL Compiler/Disassembler and Tools: + +Ported the -g option (get local ACPI tables) to the new ACPICA Table +Manager +to restore original behavior. + +---------------------------------------- +27 September 2006. Summary of changes for version 20060927: + +1) ACPI CA Core Subsystem: + +Removed the "Flags" parameter from AcpiGetRegister and AcpiSetRegister. +These functions now use a spinlock for mutual exclusion and the interrupt +level indication flag is not needed. + +Fixed a problem with the Global Lock where the lock could appear to be +obtained before it is actually obtained. The global lock semaphore was +inadvertently created with one unit instead of zero units. (BZ 464) +Fiodor +Suietov. + +Fixed a possible memory leak and fault in AcpiExResolveObjectToValue +during +a read from a buffer or region field. (BZ 458) Fiodor Suietov. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 77.9K Code, 17.1K Data, 95.0K Total + Debug Version: 154.7K Code, 63.0K Data, 217.7K Total + Current Release: + Non-Debug Version: 77.9K Code, 17.1K Data, 95.0K Total + Debug Version: 154.6K Code, 63.0K Data, 217.6K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed a compilation problem with the pre-defined Resource Descriptor +field +names where an "object does not exist" error could be incorrectly +generated +if the parent ResourceTemplate pathname places the template within a +different namespace scope than the current scope. (BZ 7212) + +Fixed a problem where the compiler could hang after syntax errors +detected +in an ElseIf construct. (BZ 453) + +Fixed a problem with the AmlFilename parameter to the DefinitionBlock() +operator. An incorrect output filename was produced when this parameter +was +a null string (""). Now, the original input filename is used as the AML +output filename, with an ".aml" extension. + +Implemented a generic batch command mode for the AcpiExec utility +(execute +any AML debugger command) (Valery Podrezov). + +---------------------------------------- +12 September 2006. Summary of changes for version 20060912: + +1) ACPI CA Core Subsystem: + +Enhanced the implementation of the "serialized mode" of the interpreter +(enabled via the AcpiGbl_AllMethodsSerialized flag.) When this mode is +specified, instead of creating a serialization semaphore per control +method, +the interpreter lock is simply no longer released before a blocking +operation during control method execution. This effectively makes the AML +Interpreter single-threaded. The overhead of a semaphore per-method is +eliminated. + +Fixed a regression where an error was no longer emitted if a control +method +attempts to create 2 objects of the same name. This once again returns +AE_ALREADY_EXISTS. When this exception occurs, it invokes the mechanism +that +will dynamically serialize the control method to possible prevent future +errors. (BZ 440) + +Integrated a fix for a problem with PCI Express HID detection in the PCI +Config Space setup procedure. (BZ 7145) + +Moved all FADT-related functions to a new file, tbfadt.c. Eliminated the +AcpiHwInitialize function - the FADT registers are now validated when the +table is loaded. + +Added two new warnings during FADT verification - 1) if the FADT is +larger +than the largest known FADT version, and 2) if there is a mismatch +between +a +32-bit block address and the 64-bit X counterpart (when both are non- +zero.) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 77.9K Code, 16.7K Data, 94.6K Total + Debug Version: 154.9K Code, 62.6K Data, 217.5K Total + Current Release: + Non-Debug Version: 77.9K Code, 17.1K Data, 95.0K Total + Debug Version: 154.7K Code, 63.0K Data, 217.7K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed a problem with the implementation of the Switch() operator where +the +temporary variable was declared too close to the actual Switch, instead +of +at method level. This could cause a problem if the Switch() operator is +within a while loop, causing an error on the second iteration. (BZ 460) + +Disassembler - fix for error emitted for unknown type for target of scope +operator. Now, ignore it and continue. + +Disassembly of an FADT now verifies the input FADT and reports any errors +found. Fix for proper disassembly of full-sized (ACPI 2.0) FADTs. + +Disassembly of raw data buffers with byte initialization data now +prefixes +each output line with the current buffer offset. + +Disassembly of ASF! table now includes all variable-length data fields at +the end of some of the subtables. + +The disassembler now emits a comment if a buffer appears to be a +ResourceTemplate, but cannot be disassembled as such because the EndTag +does +not appear at the very end of the buffer. + +AcpiExec - Added the "-t" command line option to enable the serialized +mode +of the AML interpreter. + +---------------------------------------- +31 August 2006. Summary of changes for version 20060831: + +1) ACPI CA Core Subsystem: + +Miscellaneous fixes for the Table Manager: +- Correctly initialize internal common FADT for all 64-bit "X" fields +- Fixed a couple table mapping issues during table load +- Fixed a couple alignment issues for IA64 +- Initialize input array to zero in AcpiInitializeTables +- Additional parameter validation for AcpiGetTable, AcpiGetTableHeader, +AcpiGetTableByIndex + +Change for GPE support: when a "wake" GPE is received, all wake GPEs are +now +immediately disabled to prevent the waking GPE from firing again and to +prevent other wake GPEs from interrupting the wake process. + +Added the AcpiGpeCount global that tracks the number of processed GPEs, +to +be used for debugging systems with a large number of ACPI interrupts. + +Implemented support for the "DMAR" ACPI table (DMA Redirection Table) in +both the ACPICA headers and the disassembler. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 77.8K Code, 16.5K Data, 94.3K Total + Debug Version: 154.6K Code, 62.3K Data, 216.9K Total + Current Release: + Non-Debug Version: 77.9K Code, 16.7K Data, 94.6K Total + Debug Version: 154.9K Code, 62.6K Data, 217.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler support for the DMAR ACPI table. + +---------------------------------------- +23 August 2006. Summary of changes for version 20060823: + +1) ACPI CA Core Subsystem: + +The Table Manager component has been completely redesigned and +reimplemented. The new design is much simpler, and reduces the overall +code +and data size of the kernel-resident ACPICA by approximately 5%. Also, it +is +now possible to obtain the ACPI tables very early during kernel +initialization, even before dynamic memory management is initialized. +(Alexey Starikovskiy, Fiodor Suietov, Bob Moore) + +Obsolete ACPICA interfaces: + +- AcpiGetFirmwareTable: Use AcpiGetTable instead (works at early kernel +init +time). +- AcpiLoadTable: Not needed. +- AcpiUnloadTable: Not needed. + +New ACPICA interfaces: + +- AcpiInitializeTables: Must be called before the table manager can be +used. +- AcpiReallocateRootTable: Used to transfer the root table to dynamically +allocated memory after it becomes available. +- AcpiGetTableByIndex: Allows the host to easily enumerate all ACPI +tables +in the RSDT/XSDT. + +Other ACPICA changes: + +- AcpiGetTableHeader returns the actual mapped table header, not a copy. +Use +AcpiOsUnmapMemory to free this mapping. +- AcpiGetTable returns the actual mapped table. The mapping is managed +internally and must not be deleted by the caller. Use of this interface +causes no additional dynamic memory allocation. +- AcpiFindRootPointer: Support for physical addressing has been +eliminated, +it appeared to be unused. +- The interface to AcpiOsMapMemory has changed to be consistent with the +other allocation interfaces. +- The interface to AcpiOsGetRootPointer has changed to eliminate +unnecessary +parameters. +- ACPI_PHYSICAL_ADDRESS is now 32 bits on 32-bit platforms, 64 bits on +64- +bit platforms. Was previously 64 bits on all platforms. +- The interface to the ACPI Global Lock acquire/release macros have +changed +slightly since ACPICA no longer keeps a local copy of the FACS with a +constructed pointer to the actual global lock. + +Porting to the new table manager: + +- AcpiInitializeTables: Must be called once, and can be called anytime +during the OS initialization process. It allows the host to specify an +area +of memory to be used to store the internal version of the RSDT/XSDT (root +table). This allows the host to access ACPI tables before memory +management +is initialized and running. +- AcpiReallocateRootTable: Can be called after memory management is +running +to copy the root table to a dynamically allocated array, freeing up the +scratch memory specified in the call to AcpiInitializeTables. +- AcpiSubsystemInitialize: This existing interface is independent of the +Table Manager, and does not have to be called before the Table Manager +can +be used, it only must be called before the rest of ACPICA can be used. +- ACPI Tables: Some changes have been made to the names and structure of +the +actbl.h and actbl1.h header files and may require changes to existing +code. +For example, bitfields have been completely removed because of their lack +of +portability across C compilers. +- Update interfaces to the Global Lock acquire/release macros if local +versions are used. (see acwin.h) + +Obsolete files: tbconvrt.c, tbget.c, tbgetall.c, tbrsdt.c + +New files: tbfind.c + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 80.7K Code, 17.9K Data, 98.6K Total + Debug Version: 161.0K Code, 65.1K Data, 226.1K Total + Current Release: + Non-Debug Version: 77.8K Code, 16.5K Data, 94.3K Total + Debug Version: 154.6K Code, 62.3K Data, 216.9K Total + + +2) iASL Compiler/Disassembler and Tools: + +No changes for this release. + +---------------------------------------- +21 July 2006. Summary of changes for version 20060721: + +1) ACPI CA Core Subsystem: + +The full source code for the ASL test suite used to validate the iASL +compiler and the ACPICA core subsystem is being released with the ACPICA +source for the first time. The source is contained in a separate package +and +consists of over 1100 files that exercise all ASL/AML operators. The +package +should appear on the Intel/ACPI web site shortly. (Valery Podrezov, +Fiodor +Suietov) + +Completed a new design and implementation for support of the ACPI Global +Lock. On the OS side, the global lock is now treated as a standard AML +mutex. Previously, multiple OS threads could "acquire" the global lock +simultaneously. However, this could cause the BIOS to be starved out of +the +lock - especially in cases such as the Embedded Controller driver where +there is a tight coupling between the OS and the BIOS. + +Implemented an optimization for the ACPI Global Lock interrupt mechanism. +The Global Lock interrupt handler no longer queues the execution of a +separate thread to signal the global lock semaphore. Instead, the +semaphore +is signaled directly from the interrupt handler. + +Implemented support within the AML interpreter for package objects that +contain a larger AML length (package list length) than the package +element +count. In this case, the length of the package is truncated to match the +package element count. Some BIOS code apparently modifies the package +length +on the fly, and this change supports this behavior. Provides +compatibility +with the MS AML interpreter. (With assistance from Fiodor Suietov) + +Implemented a temporary fix for the BankValue parameter of a Bank Field +to +support all constant values, now including the Zero and One opcodes. +Evaluation of this parameter must eventually be converted to a full +TermArg +evaluation. A not-implemented error is now returned (temporarily) for +non- +constant values for this parameter. + +Fixed problem reports (Fiodor Suietov) integrated: +- Fix for premature object deletion after CopyObject on Operation Region +(BZ +350) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 80.7K Code, 18.0K Data, 98.7K Total + Debug Version: 160.9K Code, 65.1K Data, 226.0K Total + Current Release: + Non-Debug Version: 80.7K Code, 17.9K Data, 98.6K Total + Debug Version: 161.0K Code, 65.1K Data, 226.1K Total + + +2) iASL Compiler/Disassembler and Tools: + +No changes for this release. + +---------------------------------------- +07 July 2006. Summary of changes for version 20060707: + +1) ACPI CA Core Subsystem: + +Added the ACPI_PACKED_POINTERS_NOT_SUPPORTED macro to support C compilers +that do not allow the initialization of address pointers within packed +structures - even though the hardware itself may support misaligned +transfers. Some of the debug data structures are packed by default to +minimize size. + +Added an error message for the case where AcpiOsGetThreadId() returns +zero. +A non-zero value is required by the core ACPICA code to ensure the proper +operation of AML mutexes and recursive control methods. + +The DSDT is now the only ACPI table that determines whether the AML +interpreter is in 32-bit or 64-bit mode. Not really a functional change, +but +the hooks for per-table 32/64 switching have been removed from the code. +A +clarification to the ACPI specification is forthcoming in ACPI 3.0B. + +Fixed a possible leak of an OwnerID in the error path of +AcpiTbInitTableDescriptor (tbinstal.c), and migrated all table OwnerID +deletion to a single place in AcpiTbUninstallTable to correct possible +leaks +when using the AcpiTbDeleteTablesByType interface (with assistance from +Lance Ortiz.) + +Fixed a problem with Serialized control methods where the semaphore +associated with the method could be over-signaled after multiple method +invocations. + +Fixed two issues with the locking of the internal namespace data +structure. +Both the Unload() operator and AcpiUnloadTable interface now lock the +namespace during the namespace deletion associated with the table unload +(with assistance from Linn Crosetto.) + +Fixed problem reports (Valery Podrezov) integrated: +- Eliminate unnecessary memory allocation for CreateXxxxField (BZ 5426) + +Fixed problem reports (Fiodor Suietov) integrated: +- Incomplete cleanup branches in AcpiTbGetTableRsdt (BZ 369) +- On Address Space handler deletion, needless deactivation call (BZ 374) +- AcpiRemoveAddressSpaceHandler: validate Device handle parameter (BZ +375) +- Possible memory leak, Notify sub-objects of Processor, Power, +ThermalZone +(BZ 376) +- AcpiRemoveAddressSpaceHandler: validate Handler parameter (BZ 378) +- Minimum Length of RSDT should be validated (BZ 379) +- AcpiRemoveNotifyHandler: return AE_NOT_EXIST if Processor Obj has no +Handler (BZ (380) +- AcpiUnloadTable: return AE_NOT_EXIST if no table of specified type +loaded +(BZ 381) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 80.5K Code, 17.8K Data, 98.3K Total + Debug Version: 160.8K Code, 64.8K Data, 225.6K Total + Current Release: + Non-Debug Version: 80.7K Code, 17.9K Data, 98.6K Total + Debug Version: 161.0K Code, 65.1K Data, 226.1K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed problem reports: +Compiler segfault when ASL contains a long (>1024) String declaration (BZ +436) + +---------------------------------------- +23 June 2006. Summary of changes for version 20060623: + +1) ACPI CA Core Subsystem: + +Implemented a new ACPI_SPINLOCK type for the OSL lock interfaces. This +allows the type to be customized to the host OS for improved efficiency +(since a spinlock is usually a very small object.) + +Implemented support for "ignored" bits in the ACPI registers. According +to +the ACPI specification, these bits should be preserved when writing the +registers via a read/modify/write cycle. There are 3 bits preserved in +this +manner: PM1_CONTROL[0] (SCI_EN), PM1_CONTROL[9], and PM1_STATUS[11]. + +Implemented the initial deployment of new OSL mutex interfaces. Since +some +host operating systems have separate mutex and semaphore objects, this +feature was requested. The base code now uses mutexes (and the new mutex +interfaces) wherever a binary semaphore was used previously. However, for +the current release, the mutex interfaces are defined as macros to map +them +to the existing semaphore interfaces. Therefore, no OSL changes are +required +at this time. (See acpiosxf.h) + +Fixed several problems with the support for the control method SyncLevel +parameter. The SyncLevel now works according to the ACPI specification +and +in concert with the Mutex SyncLevel parameter, since the current +SyncLevel +is a property of the executing thread. Mutual exclusion for control +methods +is now implemented with a mutex instead of a semaphore. + +Fixed three instances of the use of the C shift operator in the bitfield +support code (exfldio.c) to avoid the use of a shift value larger than +the +target data width. The behavior of C compilers is undefined in this case +and +can cause unpredictable results, and therefore the case must be detected +and +avoided. (Fiodor Suietov) + +Added an info message whenever an SSDT or OEM table is loaded dynamically +via the Load() or LoadTable() ASL operators. This should improve +debugging +capability since it will show exactly what tables have been loaded +(beyond +the tables present in the RSDT/XSDT.) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 80.0K Code, 17.6K Data, 97.6K Total + Debug Version: 160.2K Code, 64.7K Data, 224.9K Total + Current Release: + Non-Debug Version: 80.5K Code, 17.8K Data, 98.3K Total + Debug Version: 160.8K Code, 64.8K Data, 225.6K Total + + +2) iASL Compiler/Disassembler and Tools: + +No changes for this release. + +---------------------------------------- +08 June 2006. Summary of changes for version 20060608: + +1) ACPI CA Core Subsystem: + +Converted the locking mutex used for the ACPI hardware to a spinlock. +This +change should eliminate all problems caused by attempting to acquire a +semaphore at interrupt level, and it means that all ACPICA external +interfaces that directly access the ACPI hardware can be safely called +from +interrupt level. OSL code that implements the semaphore interfaces should +be +able to eliminate any workarounds for being called at interrupt level. + +Fixed a regression introduced in 20060526 where the ACPI device +initialization could be prematurely aborted with an AE_NOT_FOUND if a +device +did not have an optional _INI method. + +Fixed an IndexField issue where a write to the Data Register should be +limited in size to the AccessSize (width) of the IndexField itself. (BZ +433, +Fiodor Suietov) + +Fixed problem reports (Valery Podrezov) integrated: +- Allow store of ThermalZone objects to Debug object (BZ 5369/5370) + +Fixed problem reports (Fiodor Suietov) integrated: +- AcpiGetTableHeader doesn't handle multiple instances correctly (BZ 364) + +Removed four global mutexes that were obsolete and were no longer being +used. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 80.0K Code, 17.7K Data, 97.7K Total + Debug Version: 160.3K Code, 64.9K Data, 225.2K Total + Current Release: + Non-Debug Version: 80.0K Code, 17.6K Data, 97.6K Total + Debug Version: 160.2K Code, 64.7K Data, 224.9K Total + + +2) iASL Compiler/Disassembler and Tools: + +Fixed a fault when using -g option (get tables from registry) on Windows +machines. + +Fixed problem reports integrated: +- Generate error if CreateField NumBits parameter is zero. (BZ 405) +- Fault if Offset/Length in Field unit is very large (BZ 432, Fiodor +Suietov) +- Global table revision override (-r) is ignored (BZ 413) + +---------------------------------------- +26 May 2006. Summary of changes for version 20060526: + +1) ACPI CA Core Subsystem: + +Restructured, flattened, and simplified the internal interfaces for +namespace object evaluation - resulting in smaller code, less CPU stack +use, +and fewer interfaces. (With assistance from Mikhail Kouzmich) + +Fixed a problem with the CopyObject operator where the first parameter +was +not typed correctly for the parser, interpreter, compiler, and +disassembler. +Caused various errors and unexpected behavior. + +Fixed a problem where a ShiftLeft or ShiftRight of more than 64 bits +produced incorrect results with some C compilers. Since the behavior of C +compilers when the shift value is larger than the datatype width is +apparently not well defined, the interpreter now detects this condition +and +simply returns zero as expected in all such cases. (BZ 395) + +Fixed problem reports (Valery Podrezov) integrated: +- Update String-to-Integer conversion to match ACPI 3.0A spec (BZ 5329) +- Allow interpreter to handle nested method declarations (BZ 5361) + +Fixed problem reports (Fiodor Suietov) integrated: +- AcpiTerminate doesn't free debug memory allocation list objects (BZ +355) +- After Core Subsystem shutdown, AcpiSubsystemStatus returns AE_OK (BZ +356) +- AcpiOsUnmapMemory for RSDP can be invoked inconsistently (BZ 357) +- Resource Manager should return AE_TYPE for non-device objects (BZ 358) +- Incomplete cleanup branch in AcpiNsEvaluateRelative (BZ 359) +- Use AcpiOsFree instead of ACPI_FREE in AcpiRsSetSrsMethodData (BZ 360) +- Incomplete cleanup branch in AcpiPsParseAml (BZ 361) +- Incomplete cleanup branch in AcpiDsDeleteWalkState (BZ 362) +- AcpiGetTableHeader returns AE_NO_ACPI_TABLES until DSDT is loaded (BZ +365) +- Status of the Global Initialization Handler call not used (BZ 366) +- Incorrect object parameter to Global Initialization Handler (BZ 367) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 79.8K Code, 17.7K Data, 97.5K Total + Debug Version: 160.5K Code, 65.1K Data, 225.6K Total + Current Release: + Non-Debug Version: 80.0K Code, 17.7K Data, 97.7K Total + Debug Version: 160.3K Code, 64.9K Data, 225.2K Total + + +2) iASL Compiler/Disassembler and Tools: + +Modified the parser to allow the names IO, DMA, and IRQ to be used as +namespace identifiers with no collision with existing resource descriptor +macro names. This provides compatibility with other ASL compilers and is +most useful for disassembly/recompilation of existing tables without +parse +errors. (With assistance from Thomas Renninger) + +Disassembler: fixed an incorrect disassembly problem with the +DataTableRegion and CopyObject operators. Fixed a possible fault during +disassembly of some Alias operators. + +---------------------------------------- +12 May 2006. Summary of changes for version 20060512: + +1) ACPI CA Core Subsystem: + +Replaced the AcpiOsQueueForExecution interface with a new interface named +AcpiOsExecute. The major difference is that the new interface does not +have +a Priority parameter, this appeared to be useless and has been replaced +by +a +Type parameter. The Type tells the host what type of execution is being +requested, such as global lock handler, notify handler, GPE handler, etc. +This allows the host to queue and execute the request as appropriate for +the +request type, possibly using different work queues and different +priorities +for the various request types. This enables fixes for multithreading +deadlock problems such as BZ #5534, and will require changes to all +existing +OS interface layers. (Alexey Starikovskiy and Bob Moore) + +Fixed a possible memory leak associated with the support for the so- +called +"implicit return" ACPI extension. Reported by FreeBSD, BZ #6514. (Fiodor +Suietov) + +Fixed a problem with the Load() operator where a table load from an +operation region could overwrite an internal table buffer by up to 7 +bytes +and cause alignment faults on IPF systems. (With assistance from Luming +Yu) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 79.7K Code, 17.7K Data, 97.4K Total + Debug Version: 160.1K Code, 65.2K Data, 225.3K Total + Current Release: + Non-Debug Version: 79.8K Code, 17.7K Data, 97.5K Total + Debug Version: 160.5K Code, 65.1K Data, 225.6K Total + + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Implemented support to cross reference the internal +namespace +and automatically generate ASL External() statements for symbols not +defined +within the current table being disassembled. This will simplify the +disassembly and recompilation of interdependent tables such as SSDTs +since +these statements will no longer have to be added manually. + +Disassembler: Implemented experimental support to automatically detect +invocations of external control methods and generate appropriate +External() +statements. This is problematic because the AML cannot be correctly +parsed +until the number of arguments for each control method is known. +Currently, +standalone method invocations and invocations as the source operand of a +Store() statement are supported. + +Disassembler: Implemented support for the ASL pseudo-operators LNotEqual, +LLessEqual, and LGreaterEqual. Previously disassembled as LNot(LEqual()), +LNot(LGreater()), and LNot(LLess()), this makes the disassembled ASL code +more readable and likely closer to the original ASL source. + +---------------------------------------- +21 April 2006. Summary of changes for version 20060421: + +1) ACPI CA Core Subsystem: + +Removed a device initialization optimization introduced in 20051216 where +the _STA method was not run unless an _INI was also present for the same +device. This optimization could cause problems because it could allow +_INI +methods to be run within a not-present device subtree. (If a not-present +device had no _INI, _STA would not be run, the not-present status would +not +be discovered, and the children of the device would be incorrectly +traversed.) + +Implemented a new _STA optimization where namespace subtrees that do not +contain _INI are identified and ignored during device initialization. +Selectively running _STA can significantly improve boot time on large +machines (with assistance from Len Brown.) + +Implemented support for the device initialization case where the returned +_STA flags indicate a device not-present but functioning. In this case, +_INI +is not run, but the device children are examined for presence, as per the +ACPI specification. + +Implemented an additional change to the IndexField support in order to +conform to MS behavior. The value written to the Index Register is not +simply a byte offset, it is a byte offset in units of the access width of +the parent Index Field. (Fiodor Suietov) + +Defined and deployed a new OSL interface, AcpiOsValidateAddress. This +interface is called during the creation of all AML operation regions, and +allows the host OS to exert control over what addresses it will allow the +AML code to access. Operation Regions whose addresses are disallowed will +cause a runtime exception when they are actually accessed (will not +affect +or abort table loading.) See oswinxf or osunixxf for an example +implementation. + +Defined and deployed a new OSL interface, AcpiOsValidateInterface. This +interface allows the host OS to match the various "optional" +interface/behavior strings for the _OSI predefined control method as +appropriate (with assistance from Bjorn Helgaas.) See oswinxf or osunixxf +for an example implementation. + +Restructured and corrected various problems in the exception handling +code +paths within DsCallControlMethod and DsTerminateControlMethod in dsmethod +(with assistance from Takayoshi Kochi.) + +Modified the Linux source converter to ignore quoted string literals +while +converting identifiers from mixed to lower case. This will correct +problems +with the disassembler and other areas where such strings must not be +modified. + +The ACPI_FUNCTION_* macros no longer require quotes around the function +name. This allows the Linux source converter to convert the names, now +that +the converter ignores quoted strings. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + + Non-Debug Version: 81.1K Code, 17.7K Data, 98.8K Total + Debug Version: 158.9K Code, 64.9K Data, 223.8K Total + Current Release: + Non-Debug Version: 79.7K Code, 17.7K Data, 97.4K Total + Debug Version: 160.1K Code, 65.2K Data, 225.3K Total + + +2) iASL Compiler/Disassembler and Tools: + +Implemented 3 new warnings for iASL, and implemented multiple warning +levels +(w2 flag). + +1) Ignored timeouts: If the TimeoutValue parameter to Wait or Acquire is +not +WAIT_FOREVER (0xFFFF) and the code does not examine the return value to +check for the possible timeout, a warning is issued. + +2) Useless operators: If an ASL operator does not specify an optional +target +operand and it also does not use the function return value from the +operator, a warning is issued since the operator effectively does +nothing. + +3) Unreferenced objects: If a namespace object is created, but never +referenced, a warning is issued. This is a warning level 2 since there +are +cases where this is ok, such as when a secondary table is loaded that +uses +the unreferenced objects. Even so, care is taken to only flag objects +that +don't look like they will ever be used. For example, the reserved methods +(starting with an underscore) are usually not referenced because it is +expected that the OS will invoke them. + +---------------------------------------- +31 March 2006. Summary of changes for version 20060331: + +1) ACPI CA Core Subsystem: + +Implemented header file support for the following additional ACPI tables: +ASF!, BOOT, CPEP, DBGP, MCFG, SPCR, SPMI, TCPA, and WDRT. With this +support, +all current and known ACPI tables are now defined in the ACPICA headers +and +are available for use by device drivers and other software. + +Implemented support to allow tables that contain ACPI names with invalid +characters to be loaded. Previously, this would cause the table load to +fail, but since there are several known cases of such tables on existing +machines, this change was made to enable ACPI support for them. Also, +this +matches the behavior of the Microsoft ACPI implementation. + +Fixed a couple regressions introduced during the memory optimization in +the +20060317 release. The namespace node definition required additional +reorganization and an internal datatype that had been changed to 8-bit +was +restored to 32-bit. (Valery Podrezov) + +Fixed a problem where a null pointer passed to AcpiUtDeleteGenericState +could be passed through to AcpiOsReleaseObject which is unexpected. Such +null pointers are now trapped and ignored, matching the behavior of the +previous implementation before the deployment of AcpiOsReleaseObject. +(Valery Podrezov, Fiodor Suietov) + +Fixed a memory mapping leak during the deletion of a SystemMemory +operation +region where a cached memory mapping was not deleted. This became a +noticeable problem for operation regions that are defined within +frequently +used control methods. (Dana Meyers) + +Reorganized the ACPI table header files into two main files: one for the +ACPI tables consumed by the ACPICA core, and another for the +miscellaneous +ACPI tables that are consumed by the drivers and other software. The +various +FADT definitions were merged into one common section and three different +tables (ACPI 1.0, 1.0+, and 2.0) + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and +has +a much larger code and data size. + + Previous Release: + Non-Debug Version: 80.9K Code, 17.7K Data, 98.6K Total + Debug Version: 158.7K Code, 64.8K Data, 223.5K Total + Current Release: + Non-Debug Version: 81.1K Code, 17.7K Data, 98.8K Total + Debug Version: 158.9K Code, 64.9K Data, 223.8K Total + + +2) iASL Compiler/Disassembler and Tools: + +Disassembler: Implemented support to decode and format all non-AML ACPI +tables (tables other than DSDTs and SSDTs.) This includes the new tables +added to the ACPICA headers, therefore all current and known ACPI tables +are +supported. + +Disassembler: The change to allow ACPI names with invalid characters also +enables the disassembly of such tables. Invalid characters within names +are +changed to '*' to make the name printable; the iASL compiler will still +generate an error for such names, however, since this is an invalid ACPI +character. + +Implemented an option for AcpiXtract (-a) to extract all tables found in +the +input file. The default invocation extracts only the DSDTs and SSDTs. + +Fixed a couple of gcc generation issues for iASL and AcpiExec and added a +makefile for the AcpiXtract utility. + +---------------------------------------- +17 March 2006. Summary of changes for version 20060317: + +1) ACPI CA Core Subsystem: + +Implemented the use of a cache object for all internal namespace nodes. +Since there are about 1000 static nodes in a typical system, this will +decrease memory use for cache implementations that minimize per- +allocation +overhead (such as a slab allocator.) + +Removed the reference count mechanism for internal namespace nodes, since +it +was deemed unnecessary. This reduces the size of each namespace node by +about 5%-10% on all platforms. Nodes are now 20 bytes for the 32-bit +case, +and 32 bytes for the 64-bit case. + +Optimized several internal data structures to reduce object size on 64- +bit +platforms by packing data within the 64-bit alignment. This includes the +frequently used ACPI_OPERAND_OBJECT, of which there can be ~1000 static +instances corresponding to the namespace objects. + +Added two new strings for the predefined _OSI method: "Windows 2001.1 +SP1" +and "Windows 2006". + +Split the allocation tracking mechanism out to a separate file, from +utalloc.c to uttrack.c. This mechanism appears to be only useful for +application-level code. Kernels may wish to not include uttrack.c in +distributions. + +Removed all remnants of the obsolete ACPI_REPORT_* macros and the +associated +code. (These macros have been replaced by the ACPI_ERROR and ACPI_WARNING +macros.) + +Code and Data Size: These are the sizes for the acpica.lib produced by +the +Microsoft Visual C++ 6.0 32-bit compiler. The values do not include any +ACPI +driver or OSPM code. The debug version of the code includes the debug +output +trace mechanism and has a much larger code and data size. Note that these +values will vary depending on the efficiency of the compiler and the +compiler options used during generation. + + Previous Release: + Non-Debug Version: 81.1K Code, 17.8K Data, 98.9K Total + Debug Version: 161.6K Code, 65.7K Data, 227.3K Total + Current Release: + Non-Debug Version: 80.9K Code, 17.7K Data, 98.6K Total + Debug Version: 158.7K Code, 64.8K Data, 223.5K Total + + +2) iASL Compiler/Disassembler and Tools: + +Implemented an ANSI C version of the acpixtract utility. This version +will +automatically extract the DSDT and all SSDTs from the input acpidump text +file and dump the binary output to separate files. It can also display a +summary of the input file including the headers for each table found and +will extract any single ACPI table, with any signature. (See +source/tools/acpixtract) + +---------------------------------------- +10 March 2006. Summary of changes for version 20060310: + +1) ACPI CA Core Subsystem: + +Tagged all external interfaces to the subsystem with the new +ACPI_EXPORT_SYMBOL macro. This macro can be defined as necessary to +assist +kernel integration. For Linux, the macro resolves to the EXPORT_SYMBOL +macro. The default definition is NULL. + +Added the ACPI_THREAD_ID type for the return value from +AcpiOsGetThreadId. +This allows the host to define this as necessary to simplify kernel +integration. The default definition is ACPI_NATIVE_UINT. + +Fixed two interpreter problems related to error processing, the deletion +of +objects, and placing invalid pointers onto the internal operator result +stack. BZ 6028, 6151 (Valery Podrezov) + +Increased the reference count threshold where a warning is emitted for +large +reference counts in order to eliminate unnecessary warnings on systems +with +large namespaces (especially 64-bit.) Increased the value from 0x400 to +0x800. + +Due to universal disagreement as to the meaning of the 'c' in the +calloc() +function, the ACPI_MEM_CALLOCATE macro has been renamed to +ACPI_ALLOCATE_ZEROED so that the purpose of the interface is 'clear'. +ACPI_MEM_ALLOCATE and ACPI_MEM_FREE are renamed to ACPI_ALLOCATE and +ACPI_FREE. + +Code and Data Size: These are the sizes for the acpica.lib produced by +the +Microsoft Visual C++ 6.0 32-bit compiler. The values do not include any +ACPI +driver or OSPM code. The debug version of the code includes the debug +output +trace mechanism and has a much larger code and data size. Note that these +values will vary depending on the efficiency of the compiler and the +compiler options used during generation. + + Previous Release: + Non-Debug Version: 81.0K Code, 17.8K Data, 98.8K Total + Debug Version: 161.4K Code, 65.7K Data, 227.1K Total + Current Release: + Non-Debug Version: 81.1K Code, 17.8K Data, 98.9K Total + Debug Version: 161.6K Code, 65.7K Data, 227.3K Total + + +2) iASL Compiler/Disassembler: + +Disassembler: implemented support for symbolic resource descriptor +references. If a CreateXxxxField operator references a fixed offset +within +a +resource descriptor, a name is assigned to the descriptor and the offset +is +translated to the appropriate resource tag and pathname. The addition of +this support brings the disassembled code very close to the original ASL +source code and helps eliminate run-time errors when the disassembled +code +is modified (and recompiled) in such a way as to invalidate the original +fixed offsets. + +Implemented support for a Descriptor Name as the last parameter to the +ASL +Register() macro. This parameter was inadvertently left out of the ACPI +specification, and will be added for ACPI 3.0b. + +Fixed a problem where the use of the "_OSI" string (versus the full path +"\_OSI") caused an internal compiler error. ("No back ptr to op") + +Fixed a problem with the error message that occurs when an invalid string +is +used for a _HID object (such as one with an embedded asterisk: +"*PNP010A".) +The correct message is now displayed. + +---------------------------------------- +17 February 2006. Summary of changes for version 20060217: + +1) ACPI CA Core Subsystem: + +Implemented a change to the IndexField support to match the behavior of +the +Microsoft AML interpreter. The value written to the Index register is now +a +byte offset, no longer an index based upon the width of the Data +register. +This should fix IndexField problems seen on some machines where the Data +register is not exactly one byte wide. The ACPI specification will be +clarified on this point. + +Fixed a problem where several resource descriptor types could overrun the +internal descriptor buffer due to size miscalculation: VendorShort, +VendorLong, and Interrupt. This was noticed on IA64 machines, but could +affect all platforms. + +Fixed a problem where individual resource descriptors were misaligned +within +the internal buffer, causing alignment faults on IA64 platforms. + +Code and Data Size: These are the sizes for the acpica.lib produced by +the +Microsoft Visual C++ 6.0 32-bit compiler. The values do not include any +ACPI +driver or OSPM code. The debug version of the code includes the debug +output +trace mechanism and has a much larger code and data size. Note that these +values will vary depending on the efficiency of the compiler and the +compiler options used during generation. + + Previous Release: + Non-Debug Version: 81.1K Code, 17.8K Data, 98.9K Total + Debug Version: 161.3K Code, 65.6K Data, 226.9K Total + Current Release: + Non-Debug Version: 81.0K Code, 17.8K Data, 98.8K Total + Debug Version: 161.4K Code, 65.7K Data, 227.1K Total + + +2) iASL Compiler/Disassembler: + +Implemented support for new reserved names: _WDG and _WED are Microsoft +extensions for Windows Instrumentation Management, _TDL is a new ACPI- +defined method (Throttling Depth Limit.) + +Fixed a problem where a zero-length VendorShort or VendorLong resource +descriptor was incorrectly emitted as a descriptor of length one. + +---------------------------------------- +10 February 2006. Summary of changes for version 20060210: + +1) ACPI CA Core Subsystem: + +Removed a couple of extraneous ACPI_ERROR messages that appeared during +normal execution. These became apparent after the conversion from +ACPI_DEBUG_PRINT. + +Fixed a problem where the CreateField operator could hang if the BitIndex +or +NumBits parameter referred to a named object. (Valery Podrezov, BZ 5359) + +Fixed a problem where a DeRefOf operation on a buffer object incorrectly +failed with an exception. This also fixes a couple of related RefOf and +DeRefOf issues. (Valery Podrezov, BZ 5360/5392/5387) + +Fixed a problem where the AE_BUFFER_LIMIT exception was returned instead +of +AE_STRING_LIMIT on an out-of-bounds Index() operation. (Valery Podrezov, +BZ +5480) + +Implemented a memory cleanup at the end of the execution of each +iteration +of an AML While() loop, preventing the accumulation of outstanding +objects. +(Valery Podrezov, BZ 5427) + +Eliminated a chunk of duplicate code in the object resolution code. +(Valery +Podrezov, BZ 5336) + +Fixed several warnings during the 64-bit code generation. + +The AcpiSrc source code conversion tool now inserts one line of +whitespace +after an if() statement that is followed immediately by a comment, +improving +readability of the Linux code. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 81.0K Code, 17.9K Data, 98.9K Total + Debug Version: 161.3K Code, 65.7K Data, 227.0K Total + Current Release: + Non-Debug Version: 81.1K Code, 17.8K Data, 98.9K Total + Debug Version: 161.3K Code, 65.6K Data, 226.9K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem with the disassembly of a BankField operator with a +complex +expression for the BankValue parameter. + +---------------------------------------- +27 January 2006. Summary of changes for version 20060127: + +1) ACPI CA Core Subsystem: + +Implemented support in the Resource Manager to allow unresolved +namestring +references within resource package objects for the _PRT method. This +support +is in addition to the previously implemented unresolved reference support +within the AML parser. If the interpreter slack mode is enabled, these +unresolved references will be passed through to the caller as a NULL +package +entry. + +Implemented and deployed new macros and functions for error and warning +messages across the subsystem. These macros are simpler and generate less +code than their predecessors. The new macros ACPI_ERROR, ACPI_EXCEPTION, +ACPI_WARNING, and ACPI_INFO replace the ACPI_REPORT_* macros. The older +macros remain defined to allow ACPI drivers time to migrate to the new +macros. + +Implemented the ACPI_CPU_FLAGS type to simplify host OS integration of +the +Acquire/Release Lock OSL interfaces. + +Fixed a problem where Alias ASL operators are sometimes not correctly +resolved, in both the interpreter and the iASL compiler. + +Fixed several problems with the implementation of the +ConcatenateResTemplate +ASL operator. As per the ACPI specification, zero length buffers are now +treated as a single EndTag. One-length buffers always cause a fatal +exception. Non-zero length buffers that do not end with a full 2-byte +EndTag +cause a fatal exception. + +Fixed a possible structure overwrite in the AcpiGetObjectInfo external +interface. (With assistance from Thomas Renninger) + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 83.1K Code, 18.4K Data, 101.5K Total + Debug Version: 163.2K Code, 66.2K Data, 229.4K Total + Current Release: + Non-Debug Version: 81.0K Code, 17.9K Data, 98.9K Total + Debug Version: 161.3K Code, 65.7K Data, 227.0K Total + + +2) iASL Compiler/Disassembler: + +Fixed an internal error that was generated for any forward references to +ASL +Alias objects. + +---------------------------------------- +13 January 2006. Summary of changes for version 20060113: + +1) ACPI CA Core Subsystem: + +Added 2006 copyright to all module headers and signons. This affects +virtually every file in the ACPICA core subsystem, iASL compiler, and the +utilities. + +Enhanced the ACPICA error reporting in order to simplify user migration +to +the non-debug version of ACPICA. Replaced all instances of the +ACPI_DEBUG_PRINT macro invoked at the ACPI_DB_ERROR and ACPI_DB_WARN +debug +levels with the ACPI_REPORT_ERROR and ACPI_REPORT_WARNING macros, +respectively. This preserves all error and warning messages in the non- +debug +version of the ACPICA code (this has been referred to as the "debug lite" +option.) Over 200 cases were converted to create a total of over 380 +error/warning messages across the ACPICA code. This increases the code +and +data size of the default non-debug version of the code somewhat (about +13K), +but all error/warning reporting may be disabled if desired (and code +eliminated) by specifying the ACPI_NO_ERROR_MESSAGES compile-time +configuration option. The size of the debug version of ACPICA remains +about +the same. + +Fixed a memory leak within the AML Debugger "Set" command. One object was +not properly deleted for every successful invocation of the command. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 76.6K Code, 12.3K Data, 88.9K Total + Debug Version: 163.7K Code, 67.5K Data, 231.2K Total + Current Release: + Non-Debug Version: 83.1K Code, 18.4K Data, 101.5K Total + Debug Version: 163.2K Code, 66.2K Data, 229.4K Total + + +2) iASL Compiler/Disassembler: + +The compiler now officially supports the ACPI 3.0a specification that was +released on December 30, 2005. (Specification is available at +www.acpi.info) + +---------------------------------------- +16 December 2005. Summary of changes for version 20051216: + +1) ACPI CA Core Subsystem: + +Implemented optional support to allow unresolved names within ASL Package +objects. A null object is inserted in the package when a named reference +cannot be located in the current namespace. Enabled via the interpreter +slack flag, this should eliminate AE_NOT_FOUND exceptions seen on +machines +that contain such code. + +Implemented an optimization to the initialization sequence that can +improve +boot time. During ACPI device initialization, the _STA method is now run +if +and only if the _INI method exists. The _STA method is used to determine +if +the device is present; An _INI can only be run if _STA returns present, +but +it is a waste of time to run the _STA method if the _INI does not exist. +(Prototype and assistance from Dong Wei) + +Implemented use of the C99 uintptr_t for the pointer casting macros if it +is +available in the current compiler. Otherwise, the default (void *) cast +is +used as before. + +Fixed some possible memory leaks found within the execution path of the +Break, Continue, If, and CreateField operators. (Valery Podrezov) + +Fixed a problem introduced in the 20051202 release where an exception is +generated during method execution if a control method attempts to declare +another method. + +Moved resource descriptor string constants that are used by both the AML +disassembler and AML debugger to the common utilities directory so that +these components are independent. + +Implemented support in the AcpiExec utility (-e switch) to globally +ignore +exceptions during control method execution (method is not aborted.) + +Added the rsinfo.c source file to the AcpiExec makefile for Linux/Unix +generation. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 76.3K Code, 12.3K Data, 88.6K Total + Debug Version: 163.2K Code, 67.4K Data, 230.6K Total + Current Release: + Non-Debug Version: 76.6K Code, 12.3K Data, 88.9K Total + Debug Version: 163.7K Code, 67.5K Data, 231.2K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem where a CPU stack overflow fault could occur if a +recursive +method call was made from within a Return statement. + +---------------------------------------- +02 December 2005. Summary of changes for version 20051202: + +1) ACPI CA Core Subsystem: + +Modified the parsing of control methods to no longer create namespace +objects during the first pass of the parse. Objects are now created only +during the execute phase, at the moment the namespace creation operator +is +encountered in the AML (Name, OperationRegion, CreateByteField, etc.) +This +should eliminate ALREADY_EXISTS exceptions seen on some machines where +reentrant control methods are protected by an AML mutex. The mutex will +now +correctly block multiple threads from attempting to create the same +object +more than once. + +Increased the number of available Owner Ids for namespace object tracking +from 32 to 255. This should eliminate the OWNER_ID_LIMIT exceptions seen +on +some machines with a large number of ACPI tables (either static or +dynamic). + +Fixed a problem with the AcpiExec utility where a fault could occur when +the +-b switch (batch mode) is used. + +Enhanced the namespace dump routine to output the owner ID for each +namespace object. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 76.3K Code, 12.3K Data, 88.6K Total + Debug Version: 163.0K Code, 67.4K Data, 230.4K Total + Current Release: + Non-Debug Version: 76.3K Code, 12.3K Data, 88.6K Total + Debug Version: 163.2K Code, 67.4K Data, 230.6K Total + + +2) iASL Compiler/Disassembler: + +Fixed a parse error during compilation of certain Switch/Case constructs. +To +simplify the parse, the grammar now allows for multiple Default +statements +and this error is now detected and flagged during the analysis phase. + +Disassembler: The disassembly now includes the contents of the original +table header within a comment at the start of the file. This includes the +name and version of the original ASL compiler. + +---------------------------------------- +17 November 2005. Summary of changes for version 20051117: + +1) ACPI CA Core Subsystem: + +Fixed a problem in the AML parser where the method thread count could be +decremented below zero if any errors occurred during the method parse +phase. +This should eliminate AE_AML_METHOD_LIMIT exceptions seen on some +machines. +This also fixed a related regression with the mechanism that detects and +corrects methods that cannot properly handle reentrancy (related to the +deployment of the new OwnerId mechanism.) + +Eliminated the pre-parsing of control methods (to detect errors) during +table load. Related to the problem above, this was causing unwind issues +if +any errors occurred during the parse, and it seemed to be overkill. A +table +load should not be aborted if there are problems with any single control +method, thus rendering this feature rather pointless. + +Fixed a problem with the new table-driven resource manager where an +internal +buffer overflow could occur for small resource templates. + +Implemented a new external interface, AcpiGetVendorResource. This +interface +will find and return a vendor-defined resource descriptor within a _CRS +or +_PRS method via an ACPI 3.0 UUID match. With assistance from Bjorn +Helgaas. + +Removed the length limit (200) on string objects as per the upcoming ACPI +3.0A specification. This affects the following areas of the interpreter: +1) +any implicit conversion of a Buffer to a String, 2) a String object +result +of the ASL Concatentate operator, 3) the String object result of the ASL +ToString operator. + +Fixed a problem in the Windows OS interface layer (OSL) where a +WAIT_FOREVER +on a semaphore object would incorrectly timeout. This allows the +multithreading features of the AcpiExec utility to work properly under +Windows. + +Updated the Linux makefiles for the iASL compiler and AcpiExec to include +the recently added file named "utresrc.c". + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 76.2K Code, 12.3K Data, 88.5K Total + Debug Version: 163.0K Code, 67.4K Data, 230.4K Total + Current Release: + Non-Debug Version: 76.3K Code, 12.3K Data, 88.6K Total + Debug Version: 163.0K Code, 67.4K Data, 230.4K Total + + +2) iASL Compiler/Disassembler: + +Removed the limit (200) on string objects as per the upcoming ACPI 3.0A +specification. For the iASL compiler, this means that string literals +within +the source ASL can be of any length. + +Enhanced the listing output to dump the AML code for resource descriptors +immediately after the ASL code for each descriptor, instead of in a block +at +the end of the entire resource template. + +Enhanced the compiler debug output to dump the entire original parse tree +constructed during the parse phase, before any transforms are applied to +the +tree. The transformed tree is dumped also. + +---------------------------------------- +02 November 2005. Summary of changes for version 20051102: + +1) ACPI CA Core Subsystem: + +Modified the subsystem initialization sequence to improve GPE support. +The +GPE initialization has been split into two parts in order to defer +execution +of the _PRW methods (Power Resources for Wake) until after the hardware +is +fully initialized and the SCI handler is installed. This allows the _PRW +methods to access fields protected by the Global Lock. This will fix +systems +where a NO_GLOBAL_LOCK exception has been seen during initialization. + +Converted the ACPI internal object disassemble and display code within +the +AML debugger to fully table-driven operation, reducing code size and +increasing maintainability. + +Fixed a regression with the ConcatenateResTemplate() ASL operator +introduced +in the 20051021 release. + +Implemented support for "local" internal ACPI object types within the +debugger "Object" command and the AcpiWalkNamespace external interfaces. +These local types include RegionFields, BankFields, IndexFields, Alias, +and +reference objects. + +Moved common AML resource handling code into a new file, "utresrc.c". +This +code is shared by both the Resource Manager and the AML Debugger. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 76.1K Code, 12.2K Data, 88.3K Total + Debug Version: 163.5K Code, 67.0K Data, 230.5K Total + Current Release: + Non-Debug Version: 76.2K Code, 12.3K Data, 88.5K Total + Debug Version: 163.0K Code, 67.4K Data, 230.4K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem with very large initializer lists (more than 4000 +elements) +for both Buffer and Package objects where the parse stack could overflow. + +Enhanced the pre-compile source code scan for non-ASCII characters to +ignore +characters within comment fields. The scan is now always performed and is +no +longer optional, detecting invalid characters within a source file +immediately rather than during the parse phase or later. + +Enhanced the ASL grammar definition to force early reductions on all +list- +style grammar elements so that the overall parse stack usage is greatly +reduced. This should improve performance and reduce the possibility of +parse +stack overflow. + +Eliminated all reduce/reduce conflicts in the iASL parser generation. +Also, +with the addition of a %expected statement, the compiler generates from +source with no warnings. + +Fixed a possible segment fault in the disassembler if the input filename +does not contain a "dot" extension (Thomas Renninger). + +---------------------------------------- +21 October 2005. Summary of changes for version 20051021: + +1) ACPI CA Core Subsystem: + +Implemented support for the EM64T and other x86-64 processors. This +essentially entails recognizing that these processors support non-aligned +memory transfers. Previously, all 64-bit processors were assumed to lack +hardware support for non-aligned transfers. + +Completed conversion of the Resource Manager to nearly full table-driven +operation. Specifically, the resource conversion code (convert AML to +internal format and the reverse) and the debug code to dump internal +resource descriptors are fully table-driven, reducing code and data size +and +improving maintainability. + +The OSL interfaces for Acquire and Release Lock now use a 64-bit flag +word +on 64-bit processors instead of a fixed 32-bit word. (With assistance +from +Alexey Starikovskiy) + +Implemented support within the resource conversion code for the Type- +Specific byte within the various ACPI 3.0 *WordSpace macros. + +Fixed some issues within the resource conversion code for the type- +specific +flags for both Memory and I/O address resource descriptors. For Memory, +implemented support for the MTP and TTP flags. For I/O, split the TRS and +TTP flags into two separate fields. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.1K Code, 12.1K Data, 89.2K Total + Debug Version: 168.0K Code, 68.3K Data, 236.3K Total + Current Release: + Non-Debug Version: 76.1K Code, 12.2K Data, 88.3K Total + Debug Version: 163.5K Code, 67.0K Data, 230.5K Total + + + +2) iASL Compiler/Disassembler: + +Relaxed a compiler restriction that disallowed a ResourceIndex byte if +the +corresponding ResourceSource string was not also present in a resource +descriptor declaration. This restriction caused problems with existing +AML/ASL code that includes the Index byte without the string. When such +AML +was disassembled, it could not be compiled without modification. Further, +the modified code created a resource template with a different size than +the +original, breaking code that used fixed offsets into the resource +template +buffer. + +Removed a recent feature of the disassembler to ignore a lone +ResourceIndex +byte. This byte is now emitted if present so that the exact AML can be +reproduced when the disassembled code is recompiled. + +Improved comments and text alignment for the resource descriptor code +emitted by the disassembler. + +Implemented disassembler support for the ACPI 3.0 AccessSize field within +a +Register() resource descriptor. + +---------------------------------------- +30 September 2005. Summary of changes for version 20050930: + +1) ACPI CA Core Subsystem: + +Completed a major overhaul of the Resource Manager code - specifically, +optimizations in the area of the AML/internal resource conversion code. +The +code has been optimized to simplify and eliminate duplicated code, CPU +stack +use has been decreased by optimizing function parameters and local +variables, and naming conventions across the manager have been +standardized +for clarity and ease of maintenance (this includes function, parameter, +variable, and struct/typedef names.) The update may force changes in some +driver code, depending on how resources are handled by the host OS. + +All Resource Manager dispatch and information tables have been moved to a +single location for clarity and ease of maintenance. One new file was +created, named "rsinfo.c". + +The ACPI return macros (return_ACPI_STATUS, etc.) have been modified to +guarantee that the argument is not evaluated twice, making them less +prone +to macro side-effects. However, since there exists the possibility of +additional stack use if a particular compiler cannot optimize them (such +as +in the debug generation case), the original macros are optionally +available. +Note that some invocations of the return_VALUE macro may now cause size +mismatch warnings; the return_UINT8 and return_UINT32 macros are provided +to +eliminate these. (From Randy Dunlap) + +Implemented a new mechanism to enable debug tracing for individual +control +methods. A new external interface, AcpiDebugTrace, is provided to enable +this mechanism. The intent is to allow the host OS to easily enable and +disable tracing for problematic control methods. This interface can be +easily exposed to a user or debugger interface if desired. See the file +psxface.c for details. + +AcpiUtCallocate will now return a valid pointer if a length of zero is +specified - a length of one is used and a warning is issued. This matches +the behavior of AcpiUtAllocate. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.5K Code, 12.0K Data, 89.5K Total + Debug Version: 168.1K Code, 68.4K Data, 236.5K Total + Current Release: + Non-Debug Version: 77.1K Code, 12.1K Data, 89.2K Total + Debug Version: 168.0K Code, 68.3K Data, 236.3K Total + + +2) iASL Compiler/Disassembler: + +A remark is issued if the effective compile-time length of a package or +buffer is zero. Previously, this was a warning. + +---------------------------------------- +16 September 2005. Summary of changes for version 20050916: + +1) ACPI CA Core Subsystem: + +Fixed a problem within the Resource Manager where support for the Generic +Register descriptor was not fully implemented. This descriptor is now +fully +recognized, parsed, disassembled, and displayed. + +Completely restructured the Resource Manager code to utilize table-driven +dispatch and lookup, eliminating many of the large switch() statements. +This +reduces overall subsystem code size and code complexity. Affects the +resource parsing and construction, disassembly, and debug dump output. + +Cleaned up and restructured the debug dump output for all resource +descriptors. Improved readability of the output and reduced code size. + +Fixed a problem where changes to internal data structures caused the +optional ACPI_MUTEX_DEBUG code to fail compilation if specified. + +Code and Data Size: The current and previous library sizes for the core +subsystem are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. +These +values do not include any ACPI driver or OSPM code. The debug version of +the +code includes the debug output trace mechanism and has a much larger code +and data size. Note that these values will vary depending on the +efficiency +of the compiler and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.4K Code, 11.8K Data, 90.2K Total + Debug Version: 169.6K Code, 69.9K Data, 239.5K Total + Current Release: + Non-Debug Version: 77.5K Code, 12.0K Data, 89.5K Total + Debug Version: 168.1K Code, 68.4K Data, 236.5K Total + + +2) iASL Compiler/Disassembler: + +Updated the disassembler to automatically insert an EndDependentFn() +macro +into the ASL stream if this macro is missing in the original AML code, +simplifying compilation of the resulting ASL module. + +Fixed a problem in the disassembler where a disassembled ResourceSource +string (within a large resource descriptor) was not surrounded by quotes +and +not followed by a comma, causing errors when the resulting ASL module was +compiled. Also, escape sequences within a ResourceSource string are now +handled correctly (especially "\\") + +---------------------------------------- +02 September 2005. Summary of changes for version 20050902: + +1) ACPI CA Core Subsystem: + +Fixed a problem with the internal Owner ID allocation and deallocation +mechanisms for control method execution and recursive method invocation. +This should eliminate the OWNER_ID_LIMIT exceptions and "Invalid OwnerId" +messages seen on some systems. Recursive method invocation depth is +currently limited to 255. (Alexey Starikovskiy) + +Completely eliminated all vestiges of support for the "module-level +executable code" until this support is fully implemented and debugged. +This +should eliminate the NO_RETURN_VALUE exceptions seen during table load on +some systems that invoke this support. + +Fixed a problem within the resource manager code where the transaction +flags +for a 64-bit address descriptor were handled incorrectly in the type- +specific flag byte. + +Consolidated duplicate code within the address descriptor resource +manager +code, reducing overall subsystem code size. + +Fixed a fault when using the AML debugger "disassemble" command to +disassemble individual control methods. + +Removed references to the "release_current" directory within the Unix +release package. + +Code and Data Size: The current and previous core subsystem library sizes +are shown below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler. These values do not +include any ACPI driver or OSPM code. The debug version of the code +includes +the debug output trace mechanism and has a much larger code and data +size. +Note that these values will vary depending on the efficiency of the +compiler +and the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.6K Code, 11.7K Data, 90.3K Total + Debug Version: 170.0K Code, 69.9K Data, 239.9K Total + Current Release: + Non-Debug Version: 78.4K Code, 11.8K Data, 90.2K Total + Debug Version: 169.6K Code, 69.9K Data, 239.5K Total + + +2) iASL Compiler/Disassembler: + +Implemented an error check for illegal duplicate values in the interrupt +and +dma lists for the following ASL macros: Dma(), Irq(), IrqNoFlags(), and +Interrupt(). + +Implemented error checking for the Irq() and IrqNoFlags() macros to +detect +too many values in the interrupt list (16 max) and invalid values in the +list (range 0 - 15) + +The maximum length string literal within an ASL file is now restricted to +200 characters as per the ACPI specification. + +Fixed a fault when using the -ln option (generate namespace listing). + +Implemented an error check to determine if a DescriptorName within a +resource descriptor has already been used within the current scope. + +---------------------------------------- +15 August 2005. Summary of changes for version 20050815: + +1) ACPI CA Core Subsystem: + +Implemented a full bytewise compare to determine if a table load request +is +attempting to load a duplicate table. The compare is performed if the +table +signatures and table lengths match. This will allow different tables with +the same OEM Table ID and revision to be loaded - probably against the +ACPI +specification, but discovered in the field nonetheless. + +Added the changes.txt logfile to each of the zipped release packages. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.6K Code, 11.7K Data, 90.3K Total + Debug Version: 167.0K Code, 69.9K Data, 236.9K Total + Current Release: + Non-Debug Version: 78.6K Code, 11.7K Data, 90.3K Total + Debug Version: 170.0K Code, 69.9K Data, 239.9K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem where incorrect AML code could be generated for Package +objects if optimization is disabled (via the -oa switch). + +Fixed a problem with where incorrect AML code is generated for variable- +length packages when the package length is not specified and the number +of +initializer values is greater than 255. + + +---------------------------------------- +29 July 2005. Summary of changes for version 20050729: + +1) ACPI CA Core Subsystem: + +Implemented support to ignore an attempt to install/load a particular +ACPI +table more than once. Apparently there exists BIOS code that repeatedly +attempts to load the same SSDT upon certain events. With assistance from +Venkatesh Pallipadi. + +Restructured the main interface to the AML parser in order to correctly +handle all exceptional conditions. This will prevent leakage of the +OwnerId +resource and should eliminate the AE_OWNER_ID_LIMIT exceptions seen on +some +machines. With assistance from Alexey Starikovskiy. + +Support for "module level code" has been disabled in this version due to +a +number of issues that have appeared on various machines. The support can +be +enabled by defining ACPI_ENABLE_MODULE_LEVEL_CODE during subsystem +compilation. When the issues are fully resolved, the code will be enabled +by +default again. + +Modified the internal functions for debug print support to define the +FunctionName parameter as a (const char *) for compatibility with +compiler +built-in macros such as __FUNCTION__, etc. + +Linted the entire ACPICA source tree for both 32-bit and 64-bit. + +Implemented support to display an object count summary for the AML +Debugger +commands Object and Methods. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.6K Code, 11.6K Data, 90.2K Total + Debug Version: 170.0K Code, 69.7K Data, 239.7K Total + Current Release: + Non-Debug Version: 78.6K Code, 11.7K Data, 90.3K Total + Debug Version: 167.0K Code, 69.9K Data, 236.9K Total + + +2) iASL Compiler/Disassembler: + +Fixed a regression that appeared in the 20050708 version of the compiler +where an error message was inadvertently emitted for invocations of the +_OSI +reserved control method. + +---------------------------------------- +08 July 2005. Summary of changes for version 20050708: + +1) ACPI CA Core Subsystem: + +The use of the CPU stack in the debug version of the subsystem has been +considerably reduced. Previously, a debug structure was declared in every +function that used the debug macros. This structure has been removed in +favor of declaring the individual elements as parameters to the debug +functions. This reduces the cumulative stack use during nested execution +of +ACPI function calls at the cost of a small increase in the code size of +the +debug version of the subsystem. With assistance from Alexey Starikovskiy +and +Len Brown. + +Added the ACPI_GET_FUNCTION_NAME macro to enable the compiler-dependent +headers to define a macro that will return the current function name at +runtime (such as __FUNCTION__ or _func_, etc.) The function name is used +by +the debug trace output. If ACPI_GET_FUNCTION_NAME is not defined in the +compiler-dependent header, the function name is saved on the CPU stack +(one +pointer per function.) This mechanism is used because apparently there +exists no standard ANSI-C defined macro that that returns the function +name. + +Redesigned and reimplemented the "Owner ID" mechanism used to track +namespace objects created/deleted by ACPI tables and control method +execution. A bitmap is now used to allocate and free the IDs, thus +solving +the wraparound problem present in the previous implementation. The size +of +the namespace node descriptor was reduced by 2 bytes as a result (Alexey +Starikovskiy). + +Removed the UINT32_BIT and UINT16_BIT types that were used for the +bitfield +flag definitions within the headers for the predefined ACPI tables. These +have been replaced by UINT8_BIT in order to increase the code portability +of +the subsystem. If the use of UINT8 remains a problem, we may be forced to +eliminate bitfields entirely because of a lack of portability. + +Enhanced the performance of the AcpiUtUpdateObjectReference procedure. +This +is a frequently used function and this improvement increases the +performance +of the entire subsystem (Alexey Starikovskiy). + +Fixed several possible memory leaks and the inverse - premature object +deletion (Alexey Starikovskiy). + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.6K Code, 11.5K Data, 90.1K Total + Debug Version: 165.2K Code, 69.6K Data, 234.8K Total + Current Release: + Non-Debug Version: 78.6K Code, 11.6K Data, 90.2K Total + Debug Version: 170.0K Code, 69.7K Data, 239.7K Total + +---------------------------------------- +24 June 2005. Summary of changes for version 20050624: + +1) ACPI CA Core Subsystem: + +Modified the new OSL cache interfaces to use ACPI_CACHE_T as the type for +the host-defined cache object. This allows the OSL implementation to +define +and type this object in any manner desired, simplifying the OSL +implementation. For example, ACPI_CACHE_T is defined as kmem_cache_t for +Linux, and should be defined in the OS-specific header file for other +operating systems as required. + +Changed the interface to AcpiOsAcquireObject to directly return the +requested object as the function return (instead of ACPI_STATUS.) This +change was made for performance reasons, since this is the purpose of the +interface in the first place. AcpiOsAcquireObject is now similar to the +AcpiOsAllocate interface. + +Implemented a new AML debugger command named Businfo. This command +displays +information about all devices that have an associate _PRT object. The +_ADR, +_HID, _UID, and _CID are displayed for these devices. + +Modified the initialization sequence in AcpiInitializeSubsystem to call +the +OSL interface AcpiOslInitialize first, before any local initialization. +This +change was required because the global initialization now calls OSL +interfaces. + +Enhanced the Dump command to display the entire contents of Package +objects +(including all sub-objects and their values.) + +Restructured the code base to split some files because of size and/or +because the code logically belonged in a separate file. New files are +listed +below. All makefiles and project files included in the ACPI CA release +have +been updated. + utilities/utcache.c /* Local cache interfaces */ + utilities/utmutex.c /* Local mutex support */ + utilities/utstate.c /* State object support */ + interpreter/parser/psloop.c /* Main AML parse loop */ + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.3K Code, 11.6K Data, 89.9K Total + Debug Version: 164.0K Code, 69.1K Data, 233.1K Total + Current Release: + Non-Debug Version: 78.6K Code, 11.5K Data, 90.1K Total + Debug Version: 165.2K Code, 69.6K Data, 234.8K Total + + +2) iASL Compiler/Disassembler: + +Fixed a regression introduced in version 20050513 where the use of a +Package +object within a Case() statement caused a compile time exception. The +original behavior has been restored (a Match() operator is emitted.) + +---------------------------------------- +17 June 2005. Summary of changes for version 20050617: + +1) ACPI CA Core Subsystem: + +Moved the object cache operations into the OS interface layer (OSL) to +allow +the host OS to handle these operations if desired (for example, the Linux +OSL will invoke the slab allocator). This support is optional; the +compile +time define ACPI_USE_LOCAL_CACHE may be used to utilize the original +cache +code in the ACPI CA core. The new OSL interfaces are shown below. See +utalloc.c for an example implementation, and acpiosxf.h for the exact +interface definitions. With assistance from Alexey Starikovskiy. + AcpiOsCreateCache + AcpiOsDeleteCache + AcpiOsPurgeCache + AcpiOsAcquireObject + AcpiOsReleaseObject + +Modified the interfaces to AcpiOsAcquireLock and AcpiOsReleaseLock to +return +and restore a flags parameter. This fits better with many OS lock models. +Note: the current execution state (interrupt handler or not) is no longer +passed to these interfaces. If necessary, the OSL must determine this +state +by itself, a simple and fast operation. With assistance from Alexey +Starikovskiy. + +Fixed a problem in the ACPI table handling where a valid XSDT was assumed +present if the revision of the RSDP was 2 or greater. According to the +ACPI +specification, the XSDT is optional in all cases, and the table manager +therefore now checks for both an RSDP >=2 and a valid XSDT pointer. +Otherwise, the RSDT pointer is used. Some ACPI 2.0 compliant BIOSs +contain +only the RSDT. + +Fixed an interpreter problem with the Mid() operator in the case of an +input +string where the resulting output string is of zero length. It now +correctly +returns a valid, null terminated string object instead of a string object +with a null pointer. + +Fixed a problem with the control method argument handling to allow a +store +to an Arg object that already contains an object of type Device. The +Device +object is now correctly overwritten. Previously, an error was returned. + + +Enhanced the debugger Find command to emit object values in addition to +the +found object pathnames. The output format is the same as the dump +namespace +command. + +Enhanced the debugger Set command. It now has the ability to set the +value +of any Named integer object in the namespace (Previously, only method +locals +and args could be set.) + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.1K Code, 11.6K Data, 89.7K Total + Debug Version: 164.0K Code, 69.3K Data, 233.3K Total + Current Release: + Non-Debug Version: 78.3K Code, 11.6K Data, 89.9K Total + Debug Version: 164.0K Code, 69.1K Data, 233.1K Total + + +2) iASL Compiler/Disassembler: + +Fixed a regression in the disassembler where if/else/while constructs +were +output incorrectly. This problem was introduced in the previous release +(20050526). This problem also affected the single-step disassembly in the +debugger. + +Fixed a problem where compiling the reserved _OSI method would randomly +(but +rarely) produce compile errors. + +Enhanced the disassembler to emit compilable code in the face of +incorrect +AML resource descriptors. If the optional ResourceSourceIndex is present, +but the ResourceSource is not, do not emit the ResourceSourceIndex in the +disassembly. Otherwise, the resulting code cannot be compiled without +errors. + +---------------------------------------- +26 May 2005. Summary of changes for version 20050526: + +1) ACPI CA Core Subsystem: + +Implemented support to execute Type 1 and Type 2 AML opcodes appearing at +the module level (not within a control method.) These opcodes are +executed +exactly once at the time the table is loaded. This type of code was legal +up +until the release of ACPI 2.0B (2002) and is now supported within ACPI CA +in +order to provide backwards compatibility with earlier BIOS +implementations. +This eliminates the "Encountered executable code at module level" warning +that was previously generated upon detection of such code. + +Fixed a problem in the interpreter where an AE_NOT_FOUND exception could +inadvertently be generated during the lookup of namespace objects in the +second pass parse of ACPI tables and control methods. It appears that +this +problem could occur during the resolution of forward references to +namespace +objects. + +Added the ACPI_MUTEX_DEBUG #ifdef to the AcpiUtReleaseMutex function, +corresponding to the same #ifdef in the AcpiUtAcquireMutex function. This +allows the deadlock detection debug code to be compiled out in the normal +case, improving mutex performance (and overall subsystem performance) +considerably. + +Implemented a handful of miscellaneous fixes for possible memory leaks on +error conditions and error handling control paths. These fixes were +suggested by FreeBSD and the Coverity Prevent source code analysis tool. + +Added a check for a null RSDT pointer in AcpiGetFirmwareTable +(tbxfroot.c) +to prevent a fault in this error case. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.2K Code, 11.6K Data, 89.8K Total + Debug Version: 163.7K Code, 69.3K Data, 233.0K Total + Current Release: + Non-Debug Version: 78.1K Code, 11.6K Data, 89.7K Total + Debug Version: 164.0K Code, 69.3K Data, 233.3K Total + + +2) iASL Compiler/Disassembler: + +Implemented support to allow Type 1 and Type 2 ASL operators to appear at +the module level (not within a control method.) These operators will be +executed once at the time the table is loaded. This type of code was +legal +up until the release of ACPI 2.0B (2002) and is now supported by the iASL +compiler in order to provide backwards compatibility with earlier BIOS +ASL +code. + +The ACPI integer width (specified via the table revision ID or the -r +override, 32 or 64 bits) is now used internally during compile-time +constant +folding to ensure that constants are truncated to 32 bits if necessary. +Previously, the revision ID value was only emitted in the AML table +header. + +An error message is now generated for the Mutex and Method operators if +the +SyncLevel parameter is outside the legal range of 0 through 15. + +Fixed a problem with the Method operator ParameterTypes list handling +(ACPI +3.0). Previously, more than 2 types or 2 arguments generated a syntax +error. +The actual underlying implementation of method argument typechecking is +still under development, however. + +---------------------------------------- +13 May 2005. Summary of changes for version 20050513: + +1) ACPI CA Core Subsystem: + +Implemented support for PCI Express root bridges -- added support for +device +PNP0A08 in the root bridge search within AcpiEvPciConfigRegionSetup. + +The interpreter now automatically truncates incoming 64-bit constants to +32 +bits if currently executing out of a 32-bit ACPI table (Revision < 2). +This +also affects the iASL compiler constant folding. (Note: as per below, the +iASL compiler no longer allows 64-bit constants within 32-bit tables.) + +Fixed a problem where string and buffer objects with "static" pointers +(pointers to initialization data within an ACPI table) were not handled +consistently. The internal object copy operation now always copies the +data +to a newly allocated buffer, regardless of whether the source object is +static or not. + +Fixed a problem with the FromBCD operator where an implicit result +conversion was improperly performed while storing the result to the +target +operand. Since this is an "explicit conversion" operator, the implicit +conversion should never be performed on the output. + +Fixed a problem with the CopyObject operator where a copy to an existing +named object did not always completely overwrite the existing object +stored +at name. Specifically, a buffer-to-buffer copy did not delete the +existing +buffer. + +Replaced "InterruptLevel" with "InterruptNumber" in all GPE interfaces +and +structs for consistency. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.2K Code, 11.6K Data, 89.8K Total + Debug Version: 163.7K Code, 69.3K Data, 233.0K Total + Current Release: (Same sizes) + Non-Debug Version: 78.2K Code, 11.6K Data, 89.8K Total + Debug Version: 163.7K Code, 69.3K Data, 233.0K Total + + +2) iASL Compiler/Disassembler: + +The compiler now emits a warning if an attempt is made to generate a 64- +bit +integer constant from within a 32-bit ACPI table (Revision < 2). The +integer +is truncated to 32 bits. + +Fixed a problem with large package objects: if the static length of the +package is greater than 255, the "variable length package" opcode is +emitted. Previously, this caused an error. This requires an update to the +ACPI spec, since it currently (incorrectly) states that packages larger +than +255 elements are not allowed. + +The disassembler now correctly handles variable length packages and +packages +larger than 255 elements. + +---------------------------------------- +08 April 2005. Summary of changes for version 20050408: + +1) ACPI CA Core Subsystem: + +Fixed three cases in the interpreter where an "index" argument to an ASL +function was still (internally) 32 bits instead of the required 64 bits. +This was the Index argument to the Index, Mid, and Match operators. + +The "strupr" function is now permanently local (AcpiUtStrupr), since this +is +not a POSIX-defined function and not present in most kernel-level C +libraries. All references to the C library strupr function have been +removed +from the headers. + +Completed the deployment of static functions/prototypes. All prototypes +with +the static attribute have been moved from the headers to the owning C +file. + +Implemented an extract option (-e) for the AcpiBin utility (AML binary +utility). This option allows the utility to extract individual ACPI +tables +from the output of AcpiDmp. It provides the same functionality of the +acpixtract.pl perl script without the worry of setting the correct perl +options. AcpiBin runs on Windows and has not yet been generated/validated +in +the Linux/Unix environment (but should be soon). + +Updated and fixed the table dump option for AcpiBin (-d). This option +converts a single ACPI table to a hex/ascii file, similar to the output +of +AcpiDmp. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.0K Code, 11.6K Data, 89.6K Total + Debug Version: 163.5K Code, 69.3K Data, 232.8K Total + Current Release: + Non-Debug Version: 78.2K Code, 11.6K Data, 89.8K Total + Debug Version: 163.7K Code, 69.3K Data, 233.0K Total + + +2) iASL Compiler/Disassembler: + +Disassembler fix: Added a check to ensure that the table length found in +the +ACPI table header within the input file is not longer than the actual +input +file size. This indicates some kind of file or table corruption. + +---------------------------------------- +29 March 2005. Summary of changes for version 20050329: + +1) ACPI CA Core Subsystem: + +An error is now generated if an attempt is made to create a Buffer Field +of +length zero (A CreateField with a length operand of zero.) + +The interpreter now issues a warning whenever executable code at the +module +level is detected during ACPI table load. This will give some idea of the +prevalence of this type of code. + +Implemented support for references to named objects (other than control +methods) within package objects. + +Enhanced package object output for the debug object. Package objects are +now +completely dumped, showing all elements. + +Enhanced miscellaneous object output for the debug object. Any object can +now be written to the debug object (for example, a device object can be +written, and the type of the object will be displayed.) + +The "static" qualifier has been added to all local functions across both +the +core subsystem and the iASL compiler. + +The number of "long" lines (> 80 chars) within the source has been +significantly reduced, by about 1/3. + +Cleaned up all header files to ensure that all CA/iASL functions are +prototyped (even static functions) and the formatting is consistent. + +Two new header files have been added, acopcode.h and acnames.h. + +Removed several obsolete functions that were no longer used. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 165.4K Code, 69.7K Data, 236.1K Total + Current Release: + Non-Debug Version: 78.0K Code, 11.6K Data, 89.6K Total + Debug Version: 163.5K Code, 69.3K Data, 232.8K Total + + + +2) iASL Compiler/Disassembler: + +Fixed a problem with the resource descriptor generation/support. For the +ResourceSourceIndex and the ResourceSource fields, both must be present, +or +both must be not present - can't have one without the other. + +The compiler now returns non-zero from the main procedure if any errors +have +occurred during the compilation. + + +---------------------------------------- +09 March 2005. Summary of changes for version 20050309: + +1) ACPI CA Core Subsystem: + +The string-to-buffer implicit conversion code has been modified again +after +a change to the ACPI specification. In order to match the behavior of +the +other major ACPI implementation, the target buffer is no longer truncated +if +the source string is smaller than an existing target buffer. This change +requires an update to the ACPI spec, and should eliminate the recent +AE_AML_BUFFER_LIMIT issues. + +The "implicit return" support was rewritten to a new algorithm that +solves +the general case. Rather than attempt to determine when a method is about +to +exit, the result of every ASL operator is saved momentarily until the +very +next ASL operator is executed. Therefore, no matter how the method exits, +there will always be a saved implicit return value. This feature is only +enabled with the AcpiGbl_EnableInterpreterSlack flag, and should +eliminate +AE_AML_NO_RETURN_VALUE errors when enabled. + +Implemented implicit conversion support for the predicate (operand) of +the +If, Else, and While operators. String and Buffer arguments are +automatically +converted to Integers. + +Changed the string-to-integer conversion behavior to match the new ACPI +errata: "If no integer object exists, a new integer is created. The ASCII +string is interpreted as a hexadecimal constant. Each string character is +interpreted as a hexadecimal value ('0'-'9', 'A'-'F', 'a', 'f'), starting +with the first character as the most significant digit, and ending with +the +first non-hexadecimal character or end-of-string." This means that the +first +non-hex character terminates the conversion and this is the code that was +changed. + +Fixed a problem where the ObjectType operator would fail (fault) when +used +on an Index of a Package which pointed to a null package element. The +operator now properly returns zero (Uninitialized) in this case. + +Fixed a problem where the While operator used excessive memory by not +properly popping the result stack during execution. There was no memory +leak +after execution, however. (Code provided by Valery Podrezov.) + +Fixed a problem where references to control methods within Package +objects +caused the method to be invoked, instead of producing a reference object +pointing to the method. + +Restructured and simplified the pswalk.c module (AcpiPsDeleteParseTree) +to +improve performance and reduce code size. (Code provided by Alexey +Starikovskiy.) + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 165.4K Code, 69.6K Data, 236.0K Total + Current Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 165.4K Code, 69.7K Data, 236.1K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem with the Return operator with no arguments. Since the AML +grammar for the byte encoding requires an operand for the Return opcode, +the +compiler now emits a Return(Zero) for this case. An ACPI specification +update has been written for this case. + +For tables other than the DSDT, namepath optimization is automatically +disabled. This is because SSDTs can be loaded anywhere in the namespace, +the +compiler has no knowledge of where, and thus cannot optimize namepaths. + +Added "ProcessorObj" to the ObjectTypeKeyword list. This object type was +inadvertently omitted from the ACPI specification, and will require an +update to the spec. + +The source file scan for ASCII characters is now optional (-a). This +change +was made because some vendors place non-ascii characters within comments. +However, the scan is simply a brute-force byte compare to ensure all +characters in the file are in the range 0x00 to 0x7F. + +Fixed a problem with the CondRefOf operator where the compiler was +inappropriately checking for the existence of the target. Since the point +of +the operator is to check for the existence of the target at run-time, the +compiler no longer checks for the target existence. + +Fixed a problem where errors generated from the internal AML interpreter +during constant folding were not handled properly, causing a fault. + +Fixed a problem with overly aggressive range checking for the Stall +operator. The valid range (max 255) is now only checked if the operand is +of +type Integer. All other operand types cannot be statically checked. + +Fixed a problem where control method references within the RefOf, +DeRefOf, +and ObjectType operators were not treated properly. They are now treated +as +actual references, not method invocations. + +Fixed and enhanced the "list namespace" option (-ln). This option was +broken +a number of releases ago. + +Improved error handling for the Field, IndexField, and BankField +operators. +The compiler now cleanly reports and recovers from errors in the field +component (FieldUnit) list. + +Fixed a disassembler problem where the optional ResourceDescriptor fields +TRS and TTP were not always handled correctly. + +Disassembler - Comments in output now use "//" instead of "/*" + +---------------------------------------- +28 February 2005. Summary of changes for version 20050228: + +1) ACPI CA Core Subsystem: + +Fixed a problem where the result of an Index() operator (an object +reference) must increment the reference count on the target object for +the +life of the object reference. + +Implemented AML Interpreter and Debugger support for the new ACPI 3.0 +Extended Address (IO, Memory, Space), QwordSpace, DwordSpace, and +WordSpace +resource descriptors. + +Implemented support in the _OSI method for the ACPI 3.0 "Extended Address +Space Descriptor" string, indicating interpreter support for the +descriptors +above. + +Implemented header support for the new ACPI 3.0 FADT flag bits. + +Implemented header support for the new ACPI 3.0 PCI Express bits for the +PM1 +status/enable registers. + +Updated header support for the MADT processor local Apic struct and MADT +platform interrupt source struct for new ACPI 3.0 fields. + +Implemented header support for the SRAT and SLIT ACPI tables. + +Implemented the -s switch in AcpiExec to enable the "InterpreterSlack" +flag +at runtime. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.2K Code, 11.5K Data, 89.7K Total + Debug Version: 164.9K Code, 69.2K Data, 234.1K Total + Current Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 165.4K Code, 69.6K Data, 236.0K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem with the internal 64-bit String-to-integer conversion +with +strings less than two characters long. + +Fixed a problem with constant folding where the result of the Index() +operator can not be considered a constant. This means that Index() cannot +be +a type3 opcode and this will require an update to the ACPI specification. + +Disassembler: Implemented support for the TTP, MTP, and TRS resource +descriptor fields. These fields were inadvertently ignored and not output +in +the disassembly of the resource descriptor. + + + ---------------------------------------- +11 February 2005. Summary of changes for version 20050211: + +1) ACPI CA Core Subsystem: + +Implemented ACPI 3.0 support for implicit conversion within the Match() +operator. MatchObjects can now be of type integer, buffer, or string +instead +of just type integer. Package elements are implicitly converted to the +type +of the MatchObject. This change aligns the behavior of Match() with the +behavior of the other logical operators (LLess(), etc.) It also requires +an +errata change to the ACPI specification as this support was intended for +ACPI 3.0, but was inadvertently omitted. + +Fixed a problem with the internal implicit "to buffer" conversion. +Strings +that are converted to buffers will cause buffer truncation if the string +is +smaller than the target buffer. Integers that are converted to buffers +will +not cause buffer truncation, only zero extension (both as per the ACPI +spec.) The problem was introduced when code was added to truncate the +buffer, but this should not be performed in all cases, only the string +case. + +Fixed a problem with the Buffer and Package operators where the +interpreter +would get confused if two such operators were used as operands to an ASL +operator (such as LLess(Buffer(1){0},Buffer(1){1}). The internal result +stack was not being popped after the execution of these operators, +resulting +in an AE_NO_RETURN_VALUE exception. + +Fixed a problem with constructs of the form Store(Index(...),...). The +reference object returned from Index was inadvertently resolved to an +actual +value. This problem was introduced in version 20050114 when the behavior +of +Store() was modified to restrict the object types that can be used as the +source operand (to match the ACPI specification.) + +Reduced excessive stack use within the AcpiGetObjectInfo procedure. + +Added a fix to aclinux.h to allow generation of AcpiExec on Linux. + +Updated the AcpiSrc utility to add the FADT_DESCRIPTOR_REV2_MINUS struct. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.1K Code, 11.5K Data, 89.6K Total + Debug Version: 164.8K Code, 69.2K Data, 234.0K Total + Current Release: + Non-Debug Version: 78.2K Code, 11.5K Data, 89.7K Total + Debug Version: 164.9K Code, 69.2K Data, 234.1K Total + + +2) iASL Compiler/Disassembler: + +Fixed a code generation problem in the constant folding optimization code +where incorrect code was generated if a constant was reduced to a buffer +object (i.e., a reduced type 5 opcode.) + +Fixed a typechecking problem for the ToBuffer operator. Caused by an +incorrect return type in the internal opcode information table. + +---------------------------------------- +25 January 2005. Summary of changes for version 20050125: + +1) ACPI CA Core Subsystem: + +Fixed a recently introduced problem with the Global Lock where the +underlying semaphore was not created. This problem was introduced in +version 20050114, and caused an AE_AML_NO_OPERAND exception during an +Acquire() operation on _GL. + +The local object cache is now optional, and is disabled by default. Both +AcpiExec and the iASL compiler enable the cache because they run in user +mode and this enhances their performance. #define +ACPI_ENABLE_OBJECT_CACHE +to enable the local cache. + +Fixed an issue in the internal function AcpiUtEvaluateObject concerning +the +optional "implicit return" support where an error was returned if no +return +object was expected, but one was implicitly returned. AE_OK is now +returned +in this case and the implicitly returned object is deleted. +AcpiUtEvaluateObject is only occasionally used, and only to execute +reserved +methods such as _STA and _INI where the return type is known up front. + +Fixed a few issues with the internal convert-to-integer code. It now +returns +an error if an attempt is made to convert a null string, a string of only +blanks/tabs, or a zero-length buffer. This affects both implicit +conversion +and explicit conversion via the ToInteger() operator. + +The internal debug code in AcpiUtAcquireMutex has been commented out. It +is +not needed for normal operation and should increase the performance of +the +entire subsystem. The code remains in case it is needed for debug +purposes +again. + +The AcpiExec source and makefile are included in the Unix/Linux package +for +the first time. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.4K Code, 11.5K Data, 89.9K Total + Debug Version: 165.4K Code, 69.4K Data, 234.8K Total + Current Release: + Non-Debug Version: 78.1K Code, 11.5K Data, 89.6K Total + Debug Version: 164.8K Code, 69.2K Data, 234.0K Total + +2) iASL Compiler/Disassembler: + +Switch/Case support: A warning is now issued if the type of the Switch +value +cannot be determined at compile time. For example, Switch(Arg0) will +generate the warning, and the type is assumed to be an integer. As per +the +ACPI spec, use a construct such as Switch(ToInteger(Arg0)) to eliminate +the +warning. + +Switch/Case support: Implemented support for buffer and string objects as +the switch value. This is an ACPI 3.0 feature, now that LEqual supports +buffers and strings. + +Switch/Case support: The emitted code for the LEqual() comparisons now +uses +the switch value as the first operand, not the second. The case value is +now +the second operand, and this allows the case value to be implicitly +converted to the type of the switch value, not the other way around. + +Switch/Case support: Temporary variables are now emitted immediately +within +the control method, not at the global level. This means that there are +now +36 temps available per-method, not 36 temps per-module as was the case +with +the earlier implementation (_T_0 through _T_9 and _T_A through _T_Z.) + +---------------------------------------- +14 January 2005. Summary of changes for version 20050114: + +Added 2005 copyright to all module headers. This affects every module in +the core subsystem, iASL compiler, and the utilities. + +1) ACPI CA Core Subsystem: + +Fixed an issue with the String-to-Buffer conversion code where the string +null terminator was not included in the buffer after conversion, but +there +is existing ASL that assumes the string null terminator is included. This +is +the root of the ACPI_AML_BUFFER_LIMIT regression. This problem was +introduced in the previous version when the code was updated to correctly +set the converted buffer size as per the ACPI specification. The ACPI +spec +is ambiguous and will be updated to specify that the null terminator must +be +included in the converted buffer. This also affects the ToBuffer() ASL +operator. + +Fixed a problem with the Mid() ASL/AML operator where it did not work +correctly on Buffer objects. Newly created sub-buffers were not being +marked +as initialized. + + +Fixed a problem in AcpiTbFindTable where incorrect string compares were +performed on the OemId and OemTableId table header fields. These fields +are +not null terminated, so strncmp is now used instead of strcmp. + +Implemented a restriction on the Store() ASL/AML operator to align the +behavior with the ACPI specification. Previously, any object could be +used +as the source operand. Now, the only objects that may be used are +Integers, +Buffers, Strings, Packages, Object References, and DDB Handles. If +necessary, the original behavior can be restored by enabling the +EnableInterpreterSlack flag. + +Enhanced the optional "implicit return" support to allow an implicit +return +value from methods that are invoked externally via the AcpiEvaluateObject +interface. This enables implicit returns from the _STA and _INI methods, +for example. + +Changed the Revision() ASL/AML operator to return the current version of +the +AML interpreter, in the YYYYMMDD format. Previously, it incorrectly +returned +the supported ACPI version (This is the function of the _REV method). + +Updated the _REV predefined method to return the currently supported +version +of ACPI, now 3. + +Implemented batch mode option for the AcpiExec utility (-b). + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 165.3K Code, 69.4K Data, 234.7K Total + Current Release: + Non-Debug Version: 78.4K Code, 11.5K Data, 89.9K Total + Debug Version: 165.4K Code, 69.4K Data, 234.8K Total + +---------------------------------------- +10 December 2004. Summary of changes for version 20041210: + +ACPI 3.0 support is nearing completion in both the iASL compiler and the +ACPI CA core subsystem. + +1) ACPI CA Core Subsystem: + +Fixed a problem in the ToDecimalString operator where the resulting +string +length was incorrectly calculated. The length is now calculated exactly, +eliminating incorrect AE_STRING_LIMIT exceptions. + +Fixed a problem in the ToHexString operator to allow a maximum 200 +character +string to be produced. + +Fixed a problem in the internal string-to-buffer and buffer-to-buffer +copy +routine where the length of the resulting buffer was not truncated to the +new size (if the target buffer already existed). + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 164.7K Code, 68.5K Data, 233.2K Total + Current Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 165.3K Code, 69.4K Data, 234.7K Total + + +2) iASL Compiler/Disassembler: + +Implemented the new ACPI 3.0 resource template macros - DWordSpace, +ExtendedIO, ExtendedMemory, ExtendedSpace, QWordSpace, and WordSpace. +Includes support in the disassembler. + +Implemented support for the new (ACPI 3.0) parameter to the Register +macro, +AccessSize. + +Fixed a problem where the _HE resource name for the Interrupt macro was +referencing bit 0 instead of bit 1. + +Implemented check for maximum 255 interrupts in the Interrupt macro. + +Fixed a problem with the predefined resource descriptor names where +incorrect AML code was generated if the offset within the resource buffer +was 0 or 1. The optimizer shortened the AML code to a single byte opcode +but did not update the surrounding package lengths. + +Changes to the Dma macro: All channels within the channel list must be +in +the range 0-7. Maximum 8 channels can be specified. BusMaster operand is +optional (default is BusMaster). + +Implemented check for maximum 7 data bytes for the VendorShort macro. + +The ReadWrite parameter is now optional for the Memory32 and similar +macros. + +---------------------------------------- +03 December 2004. Summary of changes for version 20041203: + +1) ACPI CA Core Subsystem: + +The low-level field insertion/extraction code (exfldio) has been +completely +rewritten to eliminate unnecessary complexity, bugs, and boundary +conditions. + +Fixed a problem in the ToInteger, ToBuffer, ToHexString, and +ToDecimalString +operators where the input operand could be inadvertently deleted if no +conversion was necessary (e.g., if the input to ToInteger was an Integer +object.) + +Fixed a problem with the ToDecimalString and ToHexString where an +incorrect +exception code was returned if the resulting string would be > 200 chars. +AE_STRING_LIMIT is now returned. + +Fixed a problem with the Concatenate operator where AE_OK was always +returned, even if the operation failed. + +Fixed a problem in oswinxf (used by AcpiExec and iASL) to allow > 128 +semaphores to be allocated. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.5K Code, 11.5K Data, 90.0K Total + Debug Version: 165.2K Code, 68.6K Data, 233.8K Total + Current Release: + Non-Debug Version: 78.3K Code, 11.5K Data, 89.8K Total + Debug Version: 164.7K Code, 68.5K Data, 233.2K Total + + +2) iASL Compiler/Disassembler: + +Fixed typechecking for the ObjectType and SizeOf operators. Problem was +recently introduced in 20041119. + +Fixed a problem with the ToUUID macro where the upper nybble of each +buffer +byte was inadvertently set to zero. + +---------------------------------------- +19 November 2004. Summary of changes for version 20041119: + +1) ACPI CA Core Subsystem: + +Fixed a problem in the internal ConvertToInteger routine where new +integers +were not truncated to 32 bits for 32-bit ACPI tables. This routine +converts +buffers and strings to integers. + +Implemented support to store a value to an Index() on a String object. +This +is an ACPI 2.0 feature that had not yet been implemented. + +Implemented new behavior for storing objects to individual package +elements +(via the Index() operator). The previous behavior was to invoke the +implicit +conversion rules if an object was already present at the index. The new +behavior is to simply delete any existing object and directly store the +new +object. Although the ACPI specification seems unclear on this subject, +other +ACPI implementations behave in this manner. (This is the root of the +AE_BAD_HEX_CONSTANT issue.) + +Modified the RSDP memory scan mechanism to support the extended checksum +for +ACPI 2.0 (and above) RSDPs. Note that the search continues until a valid +RSDP signature is found with a valid checksum. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.5K Code, 11.5K Data, 90.0K Total + Debug Version: 165.2K Code, 68.6K Data, 233.8K Total + Current Release: + Non-Debug Version: 78.5K Code, 11.5K Data, 90.0K Total + Debug Version: 165.2K Code, 68.6K Data, 233.8K Total + + +2) iASL Compiler/Disassembler: + +Fixed a missing semicolon in the aslcompiler.y file. + +---------------------------------------- +05 November 2004. Summary of changes for version 20041105: + +1) ACPI CA Core Subsystem: + +Implemented support for FADT revision 2. This was an interim table +(between +ACPI 1.0 and ACPI 2.0) that adds support for the FADT reset register. + +Implemented optional support to allow uninitialized LocalX and ArgX +variables in a control method. The variables are initialized to an +Integer +object with a value of zero. This support is enabled by setting the +AcpiGbl_EnableInterpreterSlack flag to TRUE. + +Implemented support for Integer objects for the SizeOf operator. Either +4 +or 8 is returned, depending on the current integer size (32-bit or 64- +bit, +depending on the parent table revision). + +Fixed a problem in the implementation of the SizeOf and ObjectType +operators +where the operand was resolved to a value too early, causing incorrect +return values for some objects. + +Fixed some possible memory leaks during exceptional conditions. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.0K Code, 11.5K Data, 89.5K Total + Debug Version: 164.8K Code, 68.6K Data, 233.4K Total + Current Release: + Non-Debug Version: 78.5K Code, 11.5K Data, 90.0K Total + Debug Version: 165.2K Code, 68.6K Data, 233.8K Total + + +2) iASL Compiler/Disassembler: + +Implemented support for all ACPI 3.0 reserved names and methods. + +Implemented all ACPI 3.0 grammar elements in the front-end, including +support for semicolons. + +Implemented the ACPI 3.0 Function() and ToUUID() macros + +Fixed a problem in the disassembler where a Scope() operator would not be +emitted properly if the target of the scope was in another table. + +---------------------------------------- +15 October 2004. Summary of changes for version 20041015: + +Note: ACPI CA is currently undergoing an in-depth and complete formal +evaluation to test/verify the following areas. Other suggestions are +welcome. This will result in an increase in the frequency of releases and +the number of bug fixes in the next few months. + - Functional tests for all ASL/AML operators + - All implicit/explicit type conversions + - Bit fields and operation regions + - 64-bit math support and 32-bit-only "truncated" math support + - Exceptional conditions, both compiler and interpreter + - Dynamic object deletion and memory leaks + - ACPI 3.0 support when implemented + - External interfaces to the ACPI subsystem + + +1) ACPI CA Core Subsystem: + +Fixed two alignment issues on 64-bit platforms - within debug statements +in +AcpiEvGpeDetect and AcpiEvCreateGpeBlock. Removed references to the +Address +field within the non-aligned ACPI generic address structure. + +Fixed a problem in the Increment and Decrement operators where incorrect +operand resolution could result in the inadvertent modification of the +original integer when the integer is passed into another method as an +argument and the arg is then incremented/decremented. + +Fixed a problem in the FromBCD operator where the upper 32-bits of a 64- +bit +BCD number were truncated during conversion. + +Fixed a problem in the ToDecimal operator where the length of the +resulting +string could be set incorrectly too long if the input operand was a +Buffer +object. + +Fixed a problem in the Logical operators (LLess, etc.) where a NULL byte +(0) +within a buffer would prematurely terminate a compare between buffer +objects. + +Added a check for string overflow (>200 characters as per the ACPI +specification) during the Concatenate operator with two string operands. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.8K Code, 11.5K Data, 89.3K Total + Debug Version: 164.6K Code, 68.5K Data, 233.1K Total + Current Release: + Non-Debug Version: 78.0K Code, 11.5K Data, 89.5K Total + Debug Version: 164.8K Code, 68.6K Data, 233.4K Total + + + +2) iASL Compiler/Disassembler: + +Allow the use of the ObjectType operator on uninitialized Locals and Args +(returns 0 as per the ACPI specification). + +Fixed a problem where the compiler would fault if there was a syntax +error +in the FieldName of all of the various CreateXXXField operators. + +Disallow the use of lower case letters within the EISAID macro, as per +the +ACPI specification. All EISAID strings must be of the form "UUUNNNN" +Where +U is an uppercase letter and N is a hex digit. + + +---------------------------------------- +06 October 2004. Summary of changes for version 20041006: + +1) ACPI CA Core Subsystem: + +Implemented support for the ACPI 3.0 Timer operator. This ASL function +implements a 64-bit timer with 100 nanosecond granularity. + +Defined a new OSL interface, AcpiOsGetTimer. This interface is used to +implement the ACPI 3.0 Timer operator. This allows the host OS to +implement +the timer with the best clock available. Also, it keeps the core +subsystem +out of the clock handling business, since the host OS (usually) performs +this function. + +Fixed an alignment issue on 64-bit platforms. The HwLowLevelRead(Write) +functions use a 64-bit address which is part of the packed ACPI Generic +Address Structure. Since the structure is non-aligned, the alignment +macros +are now used to extract the address to a local variable before use. + +Fixed a problem where the ToInteger operator assumed all input strings +were +hexadecimal. The operator now handles both decimal strings and hex +strings +(prefixed with "0x"). + +Fixed a problem where the string length in the string object created as a +result of the internal ConvertToString procedure could be incorrect. This +potentially affected all implicit conversions and also the +ToDecimalString +and ToHexString operators. + +Fixed two problems in the ToString operator. If the length parameter was +zero, an incorrect string object was created and the value of the input +length parameter was inadvertently changed from zero to Ones. + +Fixed a problem where the optional ResourceSource string in the +ExtendedIRQ +resource macro was ignored. + +Simplified the interfaces to the internal division functions, reducing +code +size and complexity. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.9K Code, 11.4K Data, 89.3K Total + Debug Version: 164.5K Code, 68.3K Data, 232.8K Total + Current Release: + Non-Debug Version: 77.8K Code, 11.5K Data, 89.3K Total + Debug Version: 164.6K Code, 68.5K Data, 233.1K Total + + +2) iASL Compiler/Disassembler: + +Implemented support for the ACPI 3.0 Timer operator. + +Fixed a problem where the Default() operator was inadvertently ignored in +a +Switch/Case block. This was a problem in the translation of the Switch +statement to If...Else pairs. + +Added support to allow a standalone Return operator, with no parentheses +(or +operands). + +Fixed a problem with code generation for the ElseIf operator where the +translated Else...If parse tree was improperly constructed leading to the +loss of some code. + +---------------------------------------- +22 September 2004. Summary of changes for version 20040922: + +1) ACPI CA Core Subsystem: + +Fixed a problem with the implementation of the LNot() operator where +"Ones" +was not returned for the TRUE case. Changed the code to return Ones +instead +of (!Arg) which was usually 1. This change affects iASL constant folding +for +this operator also. + +Fixed a problem in AcpiUtInitializeBuffer where an existing buffer was +not +initialized properly -- Now zero the entire buffer in this case where the +buffer already exists. + +Changed the interface to AcpiOsSleep from (UINT32 Seconds, UINT32 +Milliseconds) to simply (ACPI_INTEGER Milliseconds). This simplifies all +related code considerably. This will require changes/updates to all OS +interface layers (OSLs.) + +Implemented a new external interface, AcpiInstallExceptionHandler, to +allow +a system exception handler to be installed. This handler is invoked upon +any +run-time exception that occurs during control method execution. + +Added support for the DSDT in AcpiTbFindTable. This allows the +DataTableRegion() operator to access the local copy of the DSDT. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.8K Code, 11.4K Data, 89.2K Total + Debug Version: 164.2K Code, 68.2K Data, 232.4K Total + Current Release: + Non-Debug Version: 77.9K Code, 11.4K Data, 89.3K Total + Debug Version: 164.5K Code, 68.3K Data, 232.8K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem with constant folding and the LNot operator. LNot was +returning 1 in the TRUE case, not Ones as per the ACPI specification. +This +could result in the generation of an incorrect folded/reduced constant. + +End-Of-File is now allowed within a "//"-style comment. A parse error no +longer occurs if such a comment is at the very end of the input ASL +source +file. + +Implemented the "-r" option to override the Revision in the table header. +The initial use of this option will be to simplify the evaluation of the +AML +interpreter by allowing a single ASL source module to be compiled for +either +32-bit or 64-bit integers. + + +---------------------------------------- +27 August 2004. Summary of changes for version 20040827: + +1) ACPI CA Core Subsystem: + +- Implemented support for implicit object conversion in the non-numeric +logical operators (LEqual, LGreater, LGreaterEqual, LLess, LLessEqual, +and +LNotEqual.) Any combination of Integers/Strings/Buffers may now be used; +the second operand is implicitly converted on the fly to match the type +of +the first operand. For example: + + LEqual (Source1, Source2) + +Source1 and Source2 must each evaluate to an integer, a string, or a +buffer. +The data type of Source1 dictates the required type of Source2. Source2 +is +implicitly converted if necessary to match the type of Source1. + +- Updated and corrected the behavior of the string conversion support. +The +rules concerning conversion of buffers to strings (according to the ACPI +specification) are as follows: + +ToDecimalString - explicit byte-wise conversion of buffer to string of +decimal values (0-255) separated by commas. ToHexString - explicit byte- +wise +conversion of buffer to string of hex values (0-FF) separated by commas. +ToString - explicit byte-wise conversion of buffer to string. Byte-by- +byte +copy with no transform except NULL terminated. Any other implicit buffer- +to- +string conversion - byte-wise conversion of buffer to string of hex +values +(0-FF) separated by spaces. + +- Fixed typo in definition of AcpiGbl_EnableInterpreterSlack. + +- Fixed a problem in AcpiNsGetPathnameLength where the returned length +was +one byte too short in the case of a node in the root scope. This could +cause a fault during debug output. + +- Code and Data Size: Current and previous core subsystem library sizes +are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.9K Code, 11.5K Data, 89.4K Total + Debug Version: 164.1K Code, 68.3K Data, 232.4K Total + Current Release: + Non-Debug Version: 77.8K Code, 11.4K Data, 89.2K Total + Debug Version: 164.2K Code, 68.2K Data, 232.4K Total + + +2) iASL Compiler/Disassembler: + +- Fixed a Linux generation error. + + +---------------------------------------- +16 August 2004. Summary of changes for version 20040816: + +1) ACPI CA Core Subsystem: + +Designed and implemented support within the AML interpreter for the so- +called "implicit return". This support returns the result of the last +ASL +operation within a control method, in the absence of an explicit Return() +operator. A few machines depend on this behavior, even though it is not +explicitly supported by the ASL language. It is optional support that +can +be enabled at runtime via the AcpiGbl_EnableInterpreterSlack flag. + +Removed support for the PCI_Config address space from the internal low +level +hardware interfaces (AcpiHwLowLevelRead and AcpiHwLowLevelWrite). This +support was not used internally, and would not work correctly anyway +because +the PCI bus number and segment number were not supported. There are +separate interfaces for PCI configuration space access because of the +unique +interface. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 78.0K Code, 11.5K Data, 89.5K Total + Debug Version: 164.1K Code, 68.2K Data, 232.3K Total + Current Release: + Non-Debug Version: 77.9K Code, 11.5K Data, 89.4K Total + Debug Version: 164.1K Code, 68.3K Data, 232.4K Total + + +2) iASL Compiler/Disassembler: + +Fixed a problem where constants in ASL expressions at the root level (not +within a control method) could be inadvertently truncated during code +generation. This problem was introduced in the 20040715 release. + + +---------------------------------------- +15 July 2004. Summary of changes for version 20040715: + +1) ACPI CA Core Subsystem: + +Restructured the internal HW GPE interfaces to pass/track the current +state +of interrupts (enabled/disabled) in order to avoid possible deadlock and +increase flexibility of the interfaces. + +Implemented a "lexicographical compare" for String and Buffer objects +within +the logical operators -- LGreater, LLess, LGreaterEqual, and LLessEqual - +- +as per further clarification to the ACPI specification. Behavior is +similar +to C library "strcmp". + +Completed a major reduction in CPU stack use for the AcpiGetFirmwareTable +external function. In the 32-bit non-debug case, the stack use has been +reduced from 168 bytes to 32 bytes. + +Deployed a new run-time configuration flag, +AcpiGbl_EnableInterpreterSlack, +whose purpose is to allow the AML interpreter to forgive certain bad AML +constructs. Default setting is FALSE. + +Implemented the first use of AcpiGbl_EnableInterpreterSlack in the Field +IO +support code. If enabled, it allows field access to go beyond the end of +a +region definition if the field is within the region length rounded up to +the +next access width boundary (a common coding error.) + +Renamed OSD_HANDLER to ACPI_OSD_HANDLER, and OSD_EXECUTION_CALLBACK to +ACPI_OSD_EXEC_CALLBACK for consistency with other ACPI symbols. Also, +these +symbols are lowercased by the latest version of the AcpiSrc tool. + +The prototypes for the PCI interfaces in acpiosxf.h have been updated to +rename "Register" to simply "Reg" to prevent certain compilers from +complaining. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.8K Code, 11.5K Data, 89.3K Total + Debug Version: 163.8K Code, 68.2K Data, 232.0K Total + Current Release: + Non-Debug Version: 78.0K Code, 11.5K Data, 89.5K Total + Debug Version: 164.1K Code, 68.2K Data, 232.3K Total + + +2) iASL Compiler/Disassembler: + +Implemented full support for Package objects within the Case() operator. +Note: The Break() operator is currently not supported within Case blocks +(TermLists) as there is some question about backward compatibility with +ACPI +1.0 interpreters. + + +Fixed a problem where complex terms were not supported properly within +the +Switch() operator. + +Eliminated extraneous warning for compiler-emitted reserved names of the +form "_T_x". (Used in Switch/Case operators.) + +Eliminated optimization messages for "_T_x" objects and small constants +within the DefinitionBlock operator. + + +---------------------------------------- +15 June 2004. Summary of changes for version 20040615: + +1) ACPI CA Core Subsystem: + +Implemented support for Buffer and String objects (as per ACPI 2.0) for +the +following ASL operators: LEqual, LGreater, LLess, LGreaterEqual, and +LLessEqual. + +All directory names in the entire source package are lower case, as they +were in earlier releases. + +Implemented "Disassemble" command in the AML debugger that will +disassemble +a single control method. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.7K Code, 11.5K Data, 89.2K Total + Debug Version: 163.3K Code, 67.2K Data, 230.5K Total + + Current Release: + Non-Debug Version: 77.8K Code, 11.5K Data, 89.3K Total + Debug Version: 163.8K Code, 68.2K Data, 232.0K Total + + +2) iASL Compiler/Disassembler: + +Implemented support for Buffer and String objects (as per ACPI 2.0) for +the +following ASL operators: LEqual, LGreater, LLess, LGreaterEqual, and +LLessEqual. + +All directory names in the entire source package are lower case, as they +were in earlier releases. + +Fixed a fault when using the -g or -d options if the FADT was +not found. + +Fixed an issue with the Windows version of the compiler where later +versions +of Windows place the FADT in the registry under the name "FADT" and not +"FACP" as earlier versions did. This applies when using the -g or - +d options. The compiler now looks for both strings as +necessary. + +Fixed a problem with compiler namepath optimization where a namepath +within +the Scope() operator could not be optimized if the namepath was a subpath +of +the current scope path. + +---------------------------------------- +27 May 2004. Summary of changes for version 20040527: + +1) ACPI CA Core Subsystem: + +Completed a new design and implementation for EBDA (Extended BIOS Data +Area) +support in the RSDP scan code. The original code improperly scanned for +the +EBDA by simply scanning from memory location 0 to 0x400. The correct +method +is to first obtain the EBDA pointer from within the BIOS data area, then +scan 1K of memory starting at the EBDA pointer. There appear to be few +if +any machines that place the RSDP in the EBDA, however. + +Integrated a fix for a possible fault during evaluation of BufferField +arguments. Obsolete code that was causing the problem was removed. + +Found and fixed a problem in the Field Support Code where data could be +corrupted on a bit field read that starts on an aligned boundary but does +not end on an aligned boundary. Merged the read/write "datum length" +calculation code into a common procedure. + +Rolled in a couple of changes to the FreeBSD-specific header. + + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.6K Code, 11.5K Data, 89.1K Total + Debug Version: 163.2K Code, 67.2K Data, 230.4K Total + Current Release: + Non-Debug Version: 77.7K Code, 11.5K Data, 89.2K Total + Debug Version: 163.3K Code, 67.2K Data, 230.5K Total + + +2) iASL Compiler/Disassembler: + +Fixed a generation warning produced by some overly-verbose compilers for +a +64-bit constant. + +---------------------------------------- +14 May 2004. Summary of changes for version 20040514: + +1) ACPI CA Core Subsystem: + +Fixed a problem where hardware GPE enable bits sometimes not set properly +during and after GPE method execution. Result of 04/27 changes. + +Removed extra "clear all GPEs" when sleeping/waking. + +Removed AcpiHwEnableGpe and AcpiHwDisableGpe, replaced by the single +AcpiHwWriteGpeEnableReg. Changed a couple of calls to the functions above +to +the new AcpiEv* calls as appropriate. + +ACPI_OS_NAME was removed from the OS-specific headers. The default name +is +now "Microsoft Windows NT" for maximum compatibility. However this can +be +changed by modifying the acconfig.h file. + +Allow a single invocation of AcpiInstallNotifyHandler for a handler that +traps both types of notifies (System, Device). Use ACPI_ALL_NOTIFY flag. + +Run _INI methods on ThermalZone objects. This is against the ACPI +specification, but there is apparently ASL code in the field that has +these +_INI methods, and apparently "other" AML interpreters execute them. + +Performed a full 16/32/64 bit lint that resulted in some small changes. + +Added a sleep simulation command to the AML debugger to test sleep code. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.6K Code, 11.5K Data, 89.1K Total + Debug Version: 162.9K Code, 67.0K Data, 229.9K Total + Current Release: + Non-Debug Version: 77.6K Code, 11.5K Data, 89.1K Total + Debug Version: 163.2K Code, 67.2K Data, 230.4K Total + +---------------------------------------- +27 April 2004. Summary of changes for version 20040427: + +1) ACPI CA Core Subsystem: + +Completed a major overhaul of the GPE handling within ACPI CA. There are +now three types of GPEs: wake-only, runtime-only, and combination +wake/run. +The only GPEs allowed to be combination wake/run are for button-style +devices such as a control-method power button, control-method sleep +button, +or a notebook lid switch. GPEs that have an _Lxx or _Exx method and are +not +referenced by any _PRW methods are marked for "runtime" and hardware +enabled. Any GPE that is referenced by a _PRW method is marked for +"wake" +(and disabled at runtime). However, at sleep time, only those GPEs that +have been specifically enabled for wake via the AcpiEnableGpe interface +will +actually be hardware enabled. + +A new external interface has been added, AcpiSetGpeType(), that is meant +to +be used by device drivers to force a GPE to a particular type. It will +be +especially useful for the drivers for the button devices mentioned above. + +Completed restructuring of the ACPI CA initialization sequence so that +default operation region handlers are installed before GPEs are +initialized +and the _PRW methods are executed. This will prevent errors when the +_PRW +methods attempt to access system memory or I/O space. + +GPE enable/disable no longer reads the GPE enable register. We now keep +the +enable info for runtime and wake separate and in the GPE_EVENT_INFO. We +thus no longer depend on the hardware to maintain these bits. + +Always clear the wake status and fixed/GPE status bits before sleep, even +for state S5. + +Improved the AML debugger output for displaying the GPE blocks and their +current status. + +Added new strings for the _OSI method, of the form "Windows 2001 SPx" +where +x = 0,1,2,3,4. + +Fixed a problem where the physical address was incorrectly calculated +when +the Load() operator was used to directly load from an Operation Region +(vs. +loading from a Field object.) Also added check for minimum table length +for +this case. + +Fix for multiple mutex acquisition. Restore original thread SyncLevel on +mutex release. + +Added ACPI_VALID_SXDS flag to the AcpiGetObjectInfo interface for +consistency with the other fields returned. + +Shrunk the ACPI_GPE_EVENT_INFO structure by 40%. There is one such +structure for each GPE in the system, so the size of this structure is +important. + +CPU stack requirement reduction: Cleaned up the method execution and +object +evaluation paths so that now a parameter structure is passed, instead of +copying the various method parameters over and over again. + +In evregion.c: Correctly exit and reenter the interpreter region if and +only if dispatching an operation region request to a user-installed +handler. +Do not exit/reenter when dispatching to a default handler (e.g., default +system memory or I/O handlers) + + +Notes for updating drivers for the new GPE support. The following +changes +must be made to ACPI-related device drivers that are attached to one or +more +GPEs: (This information will be added to the ACPI CA Programmer +Reference.) + +1) AcpiInstallGpeHandler no longer automatically enables the GPE, you +must +explicitly call AcpiEnableGpe. +2) There is a new interface called AcpiSetGpeType. This should be called +before enabling the GPE. Also, this interface will automatically disable +the GPE if it is currently enabled. +3) AcpiEnableGpe no longer supports a GPE type flag. + +Specific drivers that must be changed: +1) EC driver: + AcpiInstallGpeHandler (NULL, GpeNum, ACPI_GPE_EDGE_TRIGGERED, +AeGpeHandler, NULL); + AcpiSetGpeType (NULL, GpeNum, ACPI_GPE_TYPE_RUNTIME); + AcpiEnableGpe (NULL, GpeNum, ACPI_NOT_ISR); + +2) Button Drivers (Power, Lid, Sleep): +Run _PRW method under parent device +If _PRW exists: /* This is a control-method button */ + Extract GPE number and possibly GpeDevice + AcpiSetGpeType (GpeDevice, GpeNum, ACPI_GPE_TYPE_WAKE_RUN); + AcpiEnableGpe (GpeDevice, GpeNum, ACPI_NOT_ISR); + +For all other devices that have _PRWs, we automatically set the GPE type +to +ACPI_GPE_TYPE_WAKE, but the GPE is NOT automatically (wake) enabled. +This +must be done on a selective basis, usually requiring some kind of user +app +to allow the user to pick the wake devices. + + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 77.0K Code, 11.4K Data, 88.4K Total + Debug Version: 161.0K Code, 66.3K Data, 227.3K Total + Current Release: + + Non-Debug Version: 77.6K Code, 11.5K Data, 89.1K Total + Debug Version: 162.9K Code, 67.0K Data, 229.9K Total + + + +---------------------------------------- +02 April 2004. Summary of changes for version 20040402: + +1) ACPI CA Core Subsystem: + +Fixed an interpreter problem where an indirect store through an ArgX +parameter was incorrectly applying the "implicit conversion rules" during +the store. From the ACPI specification: "If the target is a method local +or +argument (LocalX or ArgX), no conversion is performed and the result is +stored directly to the target". The new behavior is to disable implicit +conversion during ALL stores to an ArgX. + +Changed the behavior of the _PRW method scan to ignore any and all errors +returned by a given _PRW. This prevents the scan from aborting from the +failure of any single _PRW. + +Moved the runtime configuration parameters from the global init procedure +to +static variables in acglobal.h. This will allow the host to override the +default values easily. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 76.9K Code, 11.4K Data, 88.3K Total + Debug Version: 160.8K Code, 66.1K Data, 226.9K Total + Current Release: + Non-Debug Version: 77.0K Code, 11.4K Data, 88.4K Total + Debug Version: 161.0K Code, 66.3K Data, 227.3K Total + + +2) iASL Compiler/Disassembler: + +iASL now fully disassembles SSDTs. However, External() statements are +not +generated automatically for unresolved symbols at this time. This is a +planned feature for future implementation. + +Fixed a scoping problem in the disassembler that occurs when the type of +the +target of a Scope() operator is overridden. This problem caused an +incorrectly nested internal namespace to be constructed. + +Any warnings or errors that are emitted during disassembly are now +commented +out automatically so that the resulting file can be recompiled without +any +hand editing. + +---------------------------------------- +26 March 2004. Summary of changes for version 20040326: + +1) ACPI CA Core Subsystem: + +Implemented support for "wake" GPEs via interaction between GPEs and the +_PRW methods. Every GPE that is pointed to by one or more _PRWs is +identified as a WAKE GPE and by default will no longer be enabled at +runtime. Previously, we were blindly enabling all GPEs with a +corresponding +_Lxx or _Exx method - but most of these turn out to be WAKE GPEs anyway. +We +believe this has been the cause of thousands of "spurious" GPEs on some +systems. + +This new GPE behavior is can be reverted to the original behavior (enable +ALL GPEs at runtime) via a runtime flag. + +Fixed a problem where aliased control methods could not access objects +properly. The proper scope within the namespace was not initialized +(transferred to the target of the aliased method) before executing the +target method. + +Fixed a potential race condition on internal object deletion on the +return +object in AcpiEvaluateObject. + +Integrated a fix for resource descriptors where both _MEM and _MTP were +being extracted instead of just _MEM. (i.e. bitmask was incorrectly too +wide, 0x0F instead of 0x03.) + +Added a special case for ACPI_ROOT_OBJECT in AcpiUtGetNodeName, +preventing +a +fault in some cases. + +Updated Notify() values for debug statements in evmisc.c + +Return proper status from AcpiUtMutexInitialize, not just simply AE_OK. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + + Non-Debug Version: 76.5K Code, 11.3K Data, 87.8K Total + Debug Version: 160.3K Code, 66.0K Data, 226.3K Total + Current Release: + Non-Debug Version: 76.9K Code, 11.4K Data, 88.3K Total + Debug Version: 160.8K Code, 66.1K Data, 226.9K Total + +---------------------------------------- +11 March 2004. Summary of changes for version 20040311: + +1) ACPI CA Core Subsystem: + +Fixed a problem where errors occurring during the parse phase of control +method execution did not abort cleanly. For example, objects created and +installed in the namespace were not deleted. This caused all subsequent +invocations of the method to return the AE_ALREADY_EXISTS exception. + +Implemented a mechanism to force a control method to "Serialized" +execution +if the method attempts to create namespace objects. (The root of the +AE_ALREADY_EXISTS problem.) + +Implemented support for the predefined _OSI "internal" control method. +Initial supported strings are "Linux", "Windows 2000", "Windows 2001", +and +"Windows 2001.1", and can be easily upgraded for new strings as +necessary. +This feature will allow "other" operating systems to execute the fully +tested, "Windows" code path through the ASL code + +Global Lock Support: Now allows multiple acquires and releases with any +internal thread. Removed concept of "owning thread" for this special +mutex. + +Fixed two functions that were inappropriately declaring large objects on +the +CPU stack: PsParseLoop, NsEvaluateRelative. Reduces the stack usage +during +method execution considerably. + +Fixed a problem in the ACPI 2.0 FACS descriptor (actbl2.h) where the +S4Bios_f field was incorrectly defined as UINT32 instead of UINT32_BIT. + +Fixed a problem where AcpiEvGpeDetect would fault if there were no GPEs +defined on the machine. + +Implemented two runtime options: One to force all control method +execution +to "Serialized" to mimic Windows behavior, another to disable _OSI +support +if it causes problems on a given machine. + +Code and Data Size: Current and previous core subsystem library sizes are +shown below. These are the code and data sizes for the acpica.lib +produced +by the Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code includes the +debug output trace mechanism and has a much larger code and data size. +Note +that these values will vary depending on the efficiency of the compiler +and +the compiler options used during generation. + + Previous Release: + Non-Debug Version: 74.8K Code, 10.1K Data, 84.9K Total + Debug Version: 158.7K Code, 65.1K Data, 223.8K Total + Current Release: + Non-Debug Version: 76.5K Code, 11.3K Data, 87.8K Total + Debug Version: 160.3K Code, 66.0K Data, 226.3K Total + +2) iASL Compiler/Disassembler: + +Fixed an array size problem for FreeBSD that would cause the compiler to +fault. + +---------------------------------------- +20 February 2004. Summary of changes for version 20040220: + + +1) ACPI CA Core Subsystem: + +Implemented execution of _SxD methods for Device objects in the +GetObjectInfo interface. + +Fixed calls to _SST method to pass the correct arguments. + +Added a call to _SST on wake to restore to "working" state. + +Check for End-Of-Buffer failure case in the WalkResources interface. + +Integrated fix for 64-bit alignment issue in acglobal.h by moving two +structures to the beginning of the file. + +After wake, clear GPE status register(s) before enabling GPEs. + +After wake, clear/enable power button. (Perhaps we should clear/enable +all +fixed events upon wake.) + +Fixed a couple of possible memory leaks in the Namespace manager. + +Integrated latest acnetbsd.h file. + +---------------------------------------- +11 February 2004. Summary of changes for version 20040211: + + +1) ACPI CA Core Subsystem: + +Completed investigation and implementation of the call-by-reference +mechanism for control method arguments. + +Fixed a problem where a store of an object into an indexed package could +fail if the store occurs within a different method than the method that +created the package. + +Fixed a problem where the ToDecimal operator could return incorrect +results. + +Fixed a problem where the CopyObject operator could fail on some of the +more +obscure objects (e.g., Reference objects.) + +Improved the output of the Debug object to display buffer, package, and +index objects. + +Fixed a problem where constructs of the form "RefOf (ArgX)" did not +return +the expected result. + +Added permanent ACPI_REPORT_ERROR macros for all instances of the +ACPI_AML_INTERNAL exception. + +Integrated latest version of acfreebsd.h + +---------------------------------------- +16 January 2004. Summary of changes for version 20040116: + +The purpose of this release is primarily to update the copyright years in +each module, thus causing a huge number of diffs. There are a few small +functional changes, however. + +1) ACPI CA Core Subsystem: + +Improved error messages when there is a problem finding one or more of +the +required base ACPI tables + +Reintroduced the definition of APIC_HEADER in actbl.h + +Changed definition of MADT_ADDRESS_OVERRIDE to 64 bits (actbl.h) + +Removed extraneous reference to NewObj in dsmthdat.c + +2) iASL compiler + +Fixed a problem introduced in December that disabled the correct +disassembly +of Resource Templates + + +---------------------------------------- +03 December 2003. Summary of changes for version 20031203: + +1) ACPI CA Core Subsystem: + +Changed the initialization of Operation Regions during subsystem +init to perform two entire walks of the ACPI namespace; The first +to initialize the regions themselves, the second to execute the +_REG methods. This fixed some interdependencies across _REG +methods found on some machines. + +Fixed a problem where a Store(Local0, Local1) could simply update +the object reference count, and not create a new copy of the +object if the Local1 is uninitialized. + +Implemented support for the _SST reserved method during sleep +transitions. + +Implemented support to clear the SLP_TYP and SLP_EN bits when +waking up, this is apparently required by some machines. + +When sleeping, clear the wake status only if SleepState is not S5. + +Fixed a problem in AcpiRsExtendedIrqResource() where an incorrect +pointer arithmetic advanced a string pointer too far. + +Fixed a problem in AcpiTbGetTablePtr() where a garbage pointer +could be returned if the requested table has not been loaded. + +Within the support for IRQ resources, restructured the handling of +the active and edge/level bits. + +Fixed a few problems in AcpiPsxExecute() where memory could be +leaked under certain error conditions. + +Improved error messages for the cases where the ACPI mode could +not be entered. + +Code and Data Size: Current and previous core subsystem library +sizes are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 compiler, and +these values do not include any ACPI driver or OSPM code. The +debug version of the code includes the debug output trace +mechanism and has a much larger code and data size. Note that +these values will vary depending on the efficiency of the compiler +and the compiler options used during generation. + + Previous Release (20031029): + Non-Debug Version: 74.4K Code, 10.1K Data, 84.5K Total + Debug Version: 158.3K Code, 65.0K Data, 223.3K Total + Current Release: + Non-Debug Version: 74.8K Code, 10.1K Data, 84.9K Total + Debug Version: 158.7K Code, 65.1K Data, 223.8K Total + +2) iASL Compiler/Disassembler: + +Implemented a fix for the iASL disassembler where a bad index was +generated. This was most noticeable on 64-bit platforms + + +---------------------------------------- +29 October 2003. Summary of changes for version 20031029: + +1) ACPI CA Core Subsystem: + + +Fixed a problem where a level-triggered GPE with an associated +_Lxx control method was incorrectly cleared twice. + +Fixed a problem with the Field support code where an access can +occur beyond the end-of-region if the field is non-aligned but +extends to the very end of the parent region (resulted in an +AE_AML_REGION_LIMIT exception.) + +Fixed a problem with ACPI Fixed Events where an RT Clock handler +would not get invoked on an RTC event. The RTC event bitmasks for +the PM1 registers were not being initialized properly. + +Implemented support for executing _STA and _INI methods for +Processor objects. Although this is currently not part of the +ACPI specification, there is existing ASL code that depends on the +init-time execution of these methods. + +Implemented and deployed a GetDescriptorName function to decode +the various types of internal descriptors. Guards against null +descriptors during debug output also. + +Implemented and deployed a GetNodeName function to extract the 4- +character namespace node name. This function simplifies the debug +and error output, as well as guarding against null pointers during +output. + +Implemented and deployed the ACPI_FORMAT_UINT64 helper macro to +simplify the debug and error output of 64-bit integers. This +macro replaces the HIDWORD and LODWORD macros for dumping these +integers. + +Updated the implementation of the Stall() operator to only call +AcpiOsStall(), and also return an error if the operand is larger +than 255. This preserves the required behavior of not +relinquishing the processor, as would happen if AcpiOsSleep() was +called for "long stalls". + +Constructs of the form "Store(LocalX,LocalX)" where LocalX is not +initialized are now treated as NOOPs. + +Cleaned up a handful of warnings during 64-bit generation. + +Fixed a reported error where and incorrect GPE number was passed +to the GPE dispatch handler. This value is only used for error +output, however. Used this opportunity to clean up and streamline +the GPE dispatch code. + +Code and Data Size: Current and previous core subsystem library +sizes are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 compiler, and +these values do not include any ACPI driver or OSPM code. The + +debug version of the code includes the debug output trace +mechanism and has a much larger code and data size. Note that +these values will vary depending on the efficiency of the compiler +and the compiler options used during generation. + + Previous Release (20031002): + Non-Debug Version: 74.1K Code, 9.7K Data, 83.8K Total + Debug Version: 157.9K Code, 64.8K Data, 222.7K Total + Current Release: + Non-Debug Version: 74.4K Code, 10.1K Data, 84.5K Total + Debug Version: 158.3K Code, 65.0K Data, 223.3K Total + + +2) iASL Compiler/Disassembler: + +Updated the iASL compiler to return an error if the operand to the +Stall() operator is larger than 255. + + +---------------------------------------- +02 October 2003. Summary of changes for version 20031002: + + +1) ACPI CA Core Subsystem: + +Fixed a problem with Index Fields where the index was not +incremented for fields that require multiple writes to the +index/data registers (Fields that are wider than the data +register.) + +Fixed a problem with all Field objects where a write could go +beyond the end-of-field if the field was larger than the access +granularity and therefore required multiple writes to complete the +request. An extra write beyond the end of the field could happen +inadvertently. + +Fixed a problem with Index Fields where a BUFFER_OVERFLOW error +would incorrectly be returned if the width of the Data Register +was larger than the specified field access width. + +Completed fixes for LoadTable() and Unload() and verified their +operation. Implemented full support for the "DdbHandle" object +throughout the ACPI CA subsystem. + +Implemented full support for the MADT and ECDT tables in the ACPI +CA header files. Even though these tables are not directly +consumed by ACPI CA, the header definitions are useful for ACPI +device drivers. + +Integrated resource descriptor fixes posted to the Linux ACPI +list. This included checks for minimum descriptor length, and +support for trailing NULL strings within descriptors that have +optional string elements. + +Code and Data Size: Current and previous core subsystem library +sizes are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 compiler, and +these values do not include any ACPI driver or OSPM code. The +debug version of the code includes the debug output trace +mechanism and has a much larger code and data size. Note that +these values will vary depending on the efficiency of the compiler +and the compiler options used during generation. + + Previous Release (20030918): + Non-Debug Version: 73.9K Code, 9.7K Data, 83.6K Total + Debug Version: 157.3K Code, 64.5K Data, 221.8K Total + Current Release: + Non-Debug Version: 74.1K Code, 9.7K Data, 83.8K Total + Debug Version: 157.9K Code, 64.8K Data, 222.7K Total + + +2) iASL Compiler: + +Implemented detection of non-ASCII characters within the input +source ASL file. This catches attempts to compile binary (AML) +files early in the compile, with an informative error message. + +Fixed a problem where the disassembler would fault if the output +filename could not be generated or if the output file could not be +opened. + +---------------------------------------- +18 September 2003. Summary of changes for version 20030918: + + +1) ACPI CA Core Subsystem: + +Found and fixed a longstanding problem with the late execution of +the various deferred AML opcodes (such as Operation Regions, +Buffer Fields, Buffers, and Packages). If the name string +specified for the name of the new object placed the object in a +scope other than the current scope, the initialization/execution +of the opcode failed. The solution to this problem was to +implement a mechanism where the late execution of such opcodes +does not attempt to lookup/create the name a second time in an +incorrect scope. This fixes the "region size computed +incorrectly" problem. + +Fixed a call to AcpiHwRegisterWrite in hwregs.c that was causing a +Global Lock AE_BAD_PARAMETER error. + +Fixed several 64-bit issues with prototypes, casting and data +types. + +Removed duplicate prototype from acdisasm.h + +Fixed an issue involving EC Operation Region Detach (Shaohua Li) + +Code and Data Size: Current and previous core subsystem library +sizes are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 compiler, and +these values do not include any ACPI driver or OSPM code. The +debug version of the code includes the debug output trace +mechanism and has a much larger code and data size. Note that +these values will vary depending on the efficiency of the compiler +and the compiler options used during generation. + + Previous Release: + + Non-Debug Version: 73.7K Code, 9.7K Data, 83.4K Total + Debug Version: 156.9K Code, 64.2K Data, 221.1K Total + Current Release: + Non-Debug Version: 73.9K Code, 9.7K Data, 83.6K Total + Debug Version: 157.3K Code, 64.5K Data, 221.8K Total + + +2) Linux: + +Fixed the AcpiOsSleep implementation in osunixxf.c to pass the +correct sleep time in seconds. + +---------------------------------------- +14 July 2003. Summary of changes for version 20030619: + +1) ACPI CA Core Subsystem: + +Parse SSDTs in order discovered, as opposed to reverse order +(Hrvoje Habjanic) + +Fixes from FreeBSD and NetBSD. (Frank van der Linden, Thomas +Klausner, + Nate Lawson) + + +2) Linux: + +Dynamically allocate SDT list (suggested by Andi Kleen) + +proc function return value cleanups (Andi Kleen) + +Correctly handle NMI watchdog during long stalls (Andrew Morton) + +Make it so acpismp=force works (reported by Andrew Morton) + + +---------------------------------------- +19 June 2003. Summary of changes for version 20030619: + +1) ACPI CA Core Subsystem: + +Fix To/FromBCD, eliminating the need for an arch-specific #define. + +Do not acquire a semaphore in the S5 shutdown path. + +Fix ex_digits_needed for 0. (Takayoshi Kochi) + +Fix sleep/stall code reversal. (Andi Kleen) + +Revert a change having to do with control method calling +semantics. + +2) Linux: + +acpiphp update (Takayoshi Kochi) + +Export acpi_disabled for sonypi (Stelian Pop) + +Mention acpismp=force in config help + +Re-add acpitable.c and acpismp=force. This improves backwards + +compatibility and also cleans up the code to a significant degree. + +Add ASUS Value-add driver (Karol Kozimor and Julien Lerouge) + +---------------------------------------- +22 May 2003. Summary of changes for version 20030522: + +1) ACPI CA Core Subsystem: + +Found and fixed a reported problem where an AE_NOT_FOUND error +occurred occasionally during _BST evaluation. This turned out to +be an Owner ID allocation issue where a called method did not get +a new ID assigned to it. Eventually, (after 64k calls), the Owner +ID UINT16 would wraparound so that the ID would be the same as the +caller's and the called method would delete the caller's +namespace. + +Implemented extended error reporting for control methods that are +aborted due to a run-time exception. Output includes the exact +AML instruction that caused the method abort, a dump of the method +locals and arguments at the time of the abort, and a trace of all +nested control method calls. + +Modified the interpreter to allow the creation of buffers of zero +length from the AML code. Implemented new code to ensure that no +attempt is made to actually allocate a memory buffer (of length +zero) - instead, a simple buffer object with a NULL buffer pointer +and length zero is created. A warning is no longer issued when +the AML attempts to create a zero-length buffer. + +Implemented a workaround for the "leading asterisk issue" in +_HIDs, _UIDs, and _CIDs in the AML interpreter. One leading +asterisk is automatically removed if present in any HID, UID, or +CID strings. The iASL compiler will still flag this asterisk as +an error, however. + +Implemented full support for _CID methods that return a package of +multiple CIDs (Compatible IDs). The AcpiGetObjectInfo() interface +now additionally returns a device _CID list if present. This +required a change to the external interface in order to pass an +ACPI_BUFFER object as a parameter since the _CID list is of +variable length. + +Fixed a problem with the new AE_SAME_HANDLER exception where +handler initialization code did not know about this exception. + +Code and Data Size: Current and previous core subsystem library +sizes are shown below. These are the code and data sizes for the +acpica.lib produced by the Microsoft Visual C++ 6.0 compiler, and +these values do not include any ACPI driver or OSPM code. The +debug version of the code includes the debug output trace +mechanism and has a much larger code and data size. Note that +these values will vary depending on the efficiency of the compiler +and the compiler options used during generation. + + Previous Release (20030509): + Non-Debug Version: 73.4K Code, 9.7K Data, 83.1K Total + Debug Version: 156.1K Code, 63.9K Data, 220.0K Total + Current Release: + Non-Debug Version: 73.7K Code, 9.7K Data, 83.4K Total + Debug Version: 156.9K Code, 64.2K Data, 221.1K Total + + +2) Linux: + +Fixed a bug in which we would reinitialize the ACPI interrupt +after it was already working, thus disabling all ACPI and the IRQs +for any other device sharing the interrupt. (Thanks to Stian +Jordet) + +Toshiba driver update (John Belmonte) + +Return only 0 or 1 for our interrupt handler status (Andrew +Morton) + + +3) iASL Compiler: + +Fixed a reported problem where multiple (nested) ElseIf() +statements were not handled correctly by the compiler, resulting +in incorrect warnings and incorrect AML code. This was a problem +in both the ASL parser and the code generator. + + +4) Documentation: + +Added changes to existing interfaces, new exception codes, and new +text concerning reference count object management versus garbage +collection. + +---------------------------------------- +09 May 2003. Summary of changes for version 20030509. + + +1) ACPI CA Core Subsystem: + +Changed the subsystem initialization sequence to hold off +installation of address space handlers until the hardware has been +initialized and the system has entered ACPI mode. This is because +the installation of space handlers can cause _REG methods to be +run. Previously, the _REG methods could potentially be run before +ACPI mode was enabled. + +Fixed some memory leak issues related to address space handler and +notify handler installation. There were some problems with the +reference count mechanism caused by the fact that the handler +objects are shared across several namespace objects. + +Fixed a reported problem where reference counts within the +namespace were not properly updated when named objects created by +method execution were deleted. + +Fixed a reported problem where multiple SSDTs caused a deletion +issue during subsystem termination. Restructured the table data +structures to simplify the linked lists and the related code. + +Fixed a problem where the table ID associated with secondary +tables (SSDTs) was not being propagated into the namespace objects +created by those tables. This would only present a problem for +tables that are unloaded at run-time, however. + +Updated AcpiOsReadable and AcpiOsWritable to use the ACPI_SIZE +type as the length parameter (instead of UINT32). + +Solved a long-standing problem where an ALREADY_EXISTS error +appears on various systems. This problem could happen when there +are multiple PCI_Config operation regions under a single PCI root +bus. This doesn't happen very frequently, but there are some +systems that do this in the ASL. + +Fixed a reported problem where the internal DeleteNode function +was incorrectly handling the case where a namespace node was the +first in the parent's child list, and had additional peers (not +the only child, but first in the list of children.) + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 73.7K Code, 9.5K Data, 83.2K Total + Debug Version: 156.1K Code, 63.6K Data, 219.7K Total + Current Release: + Non-Debug Version: 73.4K Code, 9.7K Data, 83.1K Total + Debug Version: 156.1K Code, 63.9K Data, 220.0K Total + + +2) Linux: + +Allow ":" in OS override string (Ducrot Bruno) + +Kobject fix (Greg KH) + + +3 iASL Compiler/Disassembler: + +Fixed a problem in the generation of the C source code files (AML +is emitted in C source statements for BIOS inclusion) where the +Ascii dump that appears within a C comment at the end of each line +could cause a compile time error if the AML sequence happens to +have an open comment or close comment sequence embedded. + + +---------------------------------------- +24 April 2003. Summary of changes for version 20030424. + + +1) ACPI CA Core Subsystem: + +Support for big-endian systems has been implemented. Most of the +support has been invisibly added behind big-endian versions of the +ACPI_MOVE_* macros. + +Fixed a problem in AcpiHwDisableGpeBlock() and +AcpiHwClearGpeBlock() where an incorrect offset was passed to the +low level hardware write routine. The offset parameter was +actually eliminated from the low level read/write routines because +they had become obsolete. + +Fixed a problem where a handler object was deleted twice during +the removal of a fixed event handler. + + +2) Linux: + +A fix for SMP systems with link devices was contributed by + +Compaq's Dan Zink. + +(2.5) Return whether we handled the interrupt in our IRQ handler. +(Linux ISRs no longer return void, so we can propagate the handler +return value from the ACPI CA core back to the OS.) + + + +3) Documentation: + +The ACPI CA Programmer Reference has been updated to reflect new +interfaces and changes to existing interfaces. + +---------------------------------------- +28 March 2003. Summary of changes for version 20030328. + +1) ACPI CA Core Subsystem: + +The GPE Block Device support has been completed. New interfaces +are AcpiInstallGpeBlock and AcpiRemoveGpeBlock. The Event +interfaces (enable, disable, clear, getstatus) have been split +into separate interfaces for Fixed Events and General Purpose +Events (GPEs) in order to support GPE Block Devices properly. + +Fixed a problem where the error message "Failed to acquire +semaphore" would appear during operations on the embedded +controller (EC). + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 72.3K Code, 9.5K Data, 81.8K Total + Debug Version: 154.0K Code, 63.4K Data, 217.4K Total + Current Release: + Non-Debug Version: 73.7K Code, 9.5K Data, 83.2K Total + Debug Version: 156.1K Code, 63.6K Data, 219.7K Total + + +---------------------------------------- +28 February 2003. Summary of changes for version 20030228. + + +1) ACPI CA Core Subsystem: + +The GPE handling and dispatch code has been completely overhauled +in preparation for support of GPE Block Devices (ID ACPI0006). +This affects internal data structures and code only; there should +be no differences visible externally. One new file has been +added, evgpeblk.c + +The FADT fields GPE0_BLK_LEN and GPE1_BLK_LEN are now the only +fields that are used to determine the GPE block lengths. The +REGISTER_BIT_WIDTH field of the X_GPEx_BLK extended address +structures are ignored. This is per the ACPI specification but it +isn't very clear. The full 256 Block 0/1 GPEs are now supported +(the use of REGISTER_BIT_WIDTH limited the number of GPEs to 128). + +In the SCI interrupt handler, removed the read of the PM1_CONTROL +register to look at the SCI_EN bit. On some machines, this read +causes an SMI event and greatly slows down SCI events. (This may +in fact be the cause of slow battery status response on some +systems.) + +Fixed a problem where a store of a NULL string to a package object +could cause the premature deletion of the object. This was seen +during execution of the battery _BIF method on some systems, +resulting in no battery data being returned. + +Added AcpiWalkResources interface to simplify parsing of resource +lists. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 72.0K Code, 9.5K Data, 81.5K Total + Debug Version: 153.0K Code, 62.9K Data, 215.9K Total + Current Release: + Non-Debug Version: 72.3K Code, 9.5K Data, 81.8K Total + Debug Version: 154.0K Code, 63.4K Data, 217.4K Total + + +2) Linux + +S3 fixes (Ole Rohne) + +Update ACPI PHP driver with to use new acpi_walk_resource API +(Bjorn Helgaas) + +Add S4BIOS support (Pavel Machek) + +Map in entire table before performing checksum (John Stultz) + +Expand the mem= cmdline to allow the specification of reserved and +ACPI DATA blocks (Pavel Machek) + +Never use ACPI on VISWS + +Fix derive_pci_id (Ducrot Bruno, Alvaro Lopez) + +Revert a change that allowed P_BLK lengths to be 4 or 5. This is +causing us to think that some systems support C2 when they really +don't. + +Do not count processor objects for non-present CPUs (Thanks to +Dominik Brodowski) + + +3) iASL Compiler: + +Fixed a problem where ASL include files could not be found and +opened. + +Added support for the _PDC reserved name. + + +---------------------------------------- +22 January 2003. Summary of changes for version 20030122. + + +1) ACPI CA Core Subsystem: + +Added a check for constructs of the form: Store (Local0, Local0) +where Local0 is not initialized. Apparently, some BIOS +programmers believe that this is a NOOP. Since this store doesn't +do anything anyway, the new prototype behavior will ignore this +error. This is a case where we can relax the strict checking in +the interpreter in the name of compatibility. + + +2) Linux + +The AcpiSrc Source Conversion Utility has been released with the +Linux package for the first time. This is the utility that is +used to convert the ACPI CA base source code to the Linux version. + +(Both) Handle P_BLK lengths shorter than 6 more gracefully + +(Both) Move more headers to include/acpi, and delete an unused +header. + +(Both) Move drivers/acpi/include directory to include/acpi + +(Both) Boot functions don't use cmdline, so don't pass it around + +(Both) Remove include of unused header (Adrian Bunk) + +(Both) acpiphp.h includes both linux/acpi.h and acpi_bus.h. Since +the +former now also includes the latter, acpiphp.h only needs the one, +now. + +(2.5) Make it possible to select method of bios restoring after S3 +resume. [=> no more ugly ifdefs] (Pavel Machek) + +(2.5) Make proc write interfaces work (Pavel Machek) + +(2.5) Properly init/clean up in cpufreq/acpi (Dominik Brodowski) + +(2.5) Break out ACPI Perf code into its own module, under cpufreq +(Dominik Brodowski) + +(2.4) S4BIOS support (Ducrot Bruno) + +(2.4) Fix acpiphp_glue.c for latest ACPI struct changes (Sergio +Visinoni) + + +3) iASL Compiler: + +Added support to disassemble SSDT and PSDTs. + +Implemented support to obtain SSDTs from the Windows registry if +available. + + +---------------------------------------- +09 January 2003. Summary of changes for version 20030109. + +1) ACPI CA Core Subsystem: + +Changed the behavior of the internal Buffer-to-String conversion +function. The current ACPI specification states that the contents +of the buffer are "converted to a string of two-character +hexadecimal numbers, each separated by a space". Unfortunately, +this definition is not backwards compatible with existing ACPI 1.0 +implementations (although the behavior was not defined in the ACPI +1.0 specification). The new behavior simply copies data from the +buffer to the string until a null character is found or the end of +the buffer is reached. The new String object is always null +terminated. This problem was seen during the generation of _BIF +battery data where incorrect strings were returned for battery +type, etc. This will also require an errata to the ACPI +specification. + +Renamed all instances of NATIVE_UINT and NATIVE_INT to +ACPI_NATIVE_UINT and ACPI_NATIVE_INT, respectively. + +Copyright in all module headers (both Linux and non-Linux) has be +updated to 2003. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 72.0K Code, 9.5K Data, 81.5K Total + Debug Version: 153.0K Code, 62.9K Data, 215.9K Total + Current Release: + Non-Debug Version: 72.0K Code, 9.5K Data, 81.5K Total + Debug Version: 153.0K Code, 62.9K Data, 215.9K Total + + +2) Linux + +Fixed an oops on module insertion/removal (Matthew Tippett) + +(2.4) Fix to handle dynamic size of mp_irqs (Joerg Prante) + +(2.5) Replace pr_debug (Randy Dunlap) + +(2.5) Remove usage of CPUFREQ_ALL_CPUS (Dominik Brodowski) + +(Both) Eliminate spawning of thread from timer callback, in favor +of schedule_work() + +(Both) Show Lid status in /proc (Zdenek OGAR Skalak) + +(Both) Added define for Fixed Function HW region (Matthew Wilcox) + +(Both) Add missing statics to button.c (Pavel Machek) + +Several changes have been made to the source code translation +utility that generates the Linux Code in order to make the code +more "Linux-like": + +All typedefs on structs and unions have been removed in keeping +with the Linux coding style. + +Removed the non-Linux SourceSafe module revision number from each +module header. + +Completed major overhaul of symbols to be lowercased for linux. +Doubled the number of symbols that are lowercased. + +Fixed a problem where identifiers within procedure headers and +within quotes were not fully lower cased (they were left with a +starting capital.) + +Some C macros whose only purpose is to allow the generation of 16- +bit code are now completely removed in the Linux code, increasing +readability and maintainability. + +---------------------------------------- + +12 December 2002. Summary of changes for version 20021212. + + +1) ACPI CA Core Subsystem: + +Fixed a problem where the creation of a zero-length AML Buffer +would cause a fault. + +Fixed a problem where a Buffer object that pointed to a static AML +buffer (in an ACPI table) could inadvertently be deleted, causing +memory corruption. + +Fixed a problem where a user buffer (passed in to the external +ACPI CA interfaces) could be overwritten if the buffer was too +small to complete the operation, causing memory corruption. + +Fixed a problem in the Buffer-to-String conversion code where a +string of length one was always returned, regardless of the size +of the input Buffer object. + +Removed the NATIVE_CHAR data type across the entire source due to +lack of need and lack of consistent use. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 72.1K Code, 9.5K Data, 81.6K Total + Debug Version: 152.7K Code, 62.7K Data, 215.4K Total + Current Release: + Non-Debug Version: 72.0K Code, 9.5K Data, 81.5K Total + Debug Version: 153.0K Code, 62.9K Data, 215.9K Total + + +---------------------------------------- +05 December 2002. Summary of changes for version 20021205. + +1) ACPI CA Core Subsystem: + +Fixed a problem where a store to a String or Buffer object could +cause corruption of the DSDT if the object type being stored was +the same as the target object type and the length of the object +being stored was equal to or smaller than the original (existing) +target object. This was seen to cause corruption of battery _BIF +buffers if the _BIF method modified the buffer on the fly. + +Fixed a problem where an internal error was generated if a control +method invocation was used in an OperationRegion, Buffer, or +Package declaration. This was caused by the deferred parsing of +the control method and thus the deferred creation of the internal +method object. The solution to this problem was to create the +internal method object at the moment the method is encountered in +the first pass - so that subsequent references to the method will +able to obtain the required parameter count and thus properly +parse the method invocation. This problem presented itself as an +AE_AML_INTERNAL during the pass 1 parse phase during table load. + +Fixed a problem where the internal String object copy routine did +not always allocate sufficient memory for the target String object +and caused memory corruption. This problem was seen to cause +"Allocation already present in list!" errors as memory allocation +became corrupted. + +Implemented a new function for the evaluation of namespace objects +that allows the specification of the allowable return object +types. This simplifies a lot of code that checks for a return +object of one or more specific objects returned from the +evaluation (such as _STA, etc.) This may become and external +function if it would be useful to ACPI-related drivers. + +Completed another round of prefixing #defines with "ACPI_" for +clarity. + +Completed additional code restructuring to allow more modular +linking for iASL compiler and AcpiExec. Several files were split +creating new files. New files: nsparse.c dsinit.c evgpe.c + +Implemented an abort mechanism to terminate an executing control +method via the AML debugger. This feature is useful for debugging +control methods that depend (wait) for specific hardware +responses. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 71.4K Code, 9.0K Data, 80.4K Total + Debug Version: 152.9K Code, 63.3K Data, 216.2K Total + Current Release: + Non-Debug Version: 72.1K Code, 9.5K Data, 81.6K Total + Debug Version: 152.7K Code, 62.7K Data, 215.4K Total + + +2) iASL Compiler/Disassembler + +Fixed a compiler code generation problem for "Interrupt" Resource +Descriptors. If specified in the ASL, the optional "Resource +Source Index" and "Resource Source" fields were not inserted into +the correct location within the AML resource descriptor, creating +an invalid descriptor. + +Fixed a disassembler problem for "Interrupt" resource descriptors. +The optional "Resource Source Index" and "Resource Source" fields +were ignored. + + +---------------------------------------- +22 November 2002. Summary of changes for version 20021122. + + +1) ACPI CA Core Subsystem: + +Fixed a reported problem where an object stored to a Method Local +or Arg was not copied to a new object during the store - the +object pointer was simply copied to the Local/Arg. This caused +all subsequent operations on the Local/Arg to also affect the +original source of the store operation. + +Fixed a problem where a store operation to a Method Local or Arg +was not completed properly if the Local/Arg contained a reference +(from RefOf) to a named field. The general-purpose store-to- +namespace-node code is now used so that this case is handled +automatically. + +Fixed a problem where the internal object copy routine would cause +a protection fault if the object being copied was a Package and +contained either 1) a NULL package element or 2) a nested sub- +package. + +Fixed a problem with the GPE initialization that resulted from an +ambiguity in the ACPI specification. One section of the +specification states that both the address and length of the GPE +block must be zero if the block is not supported. Another section +implies that only the address need be zero if the block is not +supported. The code has been changed so that both the address and +the length must be non-zero to indicate a valid GPE block (i.e., +if either the address or the length is zero, the GPE block is +invalid.) + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 71.3K Code, 9.0K Data, 80.3K Total + Debug Version: 152.7K Code, 63.2K Data, 215.5K Total + Current Release: + Non-Debug Version: 71.4K Code, 9.0K Data, 80.4K Total + Debug Version: 152.9K Code, 63.3K Data, 216.2K Total + + +2) Linux + +Cleaned up EC driver. Exported an external EC read/write +interface. By going through this, other drivers (most notably +sonypi) will be able to serialize access to the EC. + + +3) iASL Compiler/Disassembler + +Implemented support to optionally generate include files for both +ASM and C (the -i switch). This simplifies BIOS development by +automatically creating include files that contain external +declarations for the symbols that are created within the + +(optionally generated) ASM and C AML source files. + + +---------------------------------------- +15 November 2002. Summary of changes for version 20021115. + +1) ACPI CA Core Subsystem: + +Fixed a memory leak problem where an error during resolution of + +method arguments during a method invocation from another method +failed to cleanup properly by deleting all successfully resolved +argument objects. + +Fixed a problem where the target of the Index() operator was not +correctly constructed if the source object was a package. This +problem has not been detected because the use of a target operand +with Index() is very rare. + +Fixed a problem with the Index() operator where an attempt was +made to delete the operand objects twice. + +Fixed a problem where an attempt was made to delete an operand +twice during execution of the CondRefOf() operator if the target +did not exist. + +Implemented the first of perhaps several internal create object +functions that create and initialize a specific object type. This +consolidates duplicated code wherever the object is created, thus +shrinking the size of the subsystem. + +Implemented improved debug/error messages for errors that occur +during nested method invocations. All executing method pathnames +are displayed (with the error) as the call stack is unwound - thus +simplifying debug. + +Fixed a problem introduced in the 10/02 release that caused +premature deletion of a buffer object if a buffer was used as an +ASL operand where an integer operand is required (Thus causing an +implicit object conversion from Buffer to Integer.) The change in +the 10/02 release was attempting to fix a memory leak (albeit +incorrectly.) + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 71.9K Code, 9.1K Data, 81.0K Total + Debug Version: 153.1K Code, 63.3K Data, 216.4K Total + Current Release: + Non-Debug Version: 71.3K Code, 9.0K Data, 80.3K Total + Debug Version: 152.7K Code, 63.2K Data, 215.5K Total + + +2) Linux + +Changed the implementation of the ACPI semaphores to use down() +instead of down_interruptable(). It is important that the +execution of ACPI control methods not be interrupted by signals. +Methods must run to completion, or the system may be left in an +unknown/unstable state. + +Fixed a compilation error when CONFIG_SOFTWARE_SUSPEND is not set. +(Shawn Starr) + + +3) iASL Compiler/Disassembler + + +Changed the default location of output files. All output files +are now placed in the current directory by default instead of in +the directory of the source file. This change may affect some +existing makefiles, but it brings the behavior of the compiler in +line with other similar tools. The location of the output files +can be overridden with the -p command line switch. + + +---------------------------------------- +11 November 2002. Summary of changes for version 20021111. + + +0) ACPI Specification 2.0B is released and is now available at: +http://www.acpi.info/index.html + + +1) ACPI CA Core Subsystem: + +Implemented support for the ACPI 2.0 SMBus Operation Regions. +This includes the early detection and handoff of the request to +the SMBus region handler (avoiding all of the complex field +support code), and support for the bidirectional return packet +from an SMBus write operation. This paves the way for the +development of SMBus drivers in each host operating system. + +Fixed a problem where the semaphore WAIT_FOREVER constant was +defined as 32 bits, but must be 16 bits according to the ACPI +specification. This had the side effect of causing ASL +Mutex/Event timeouts even though the ASL code requested a wait +forever. Changed all internal references to the ACPI timeout +parameter to 16 bits to prevent future problems. Changed the name +of WAIT_FOREVER to ACPI_WAIT_FOREVER. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 71.4K Code, 9.0K Data, 80.4K Total + Debug Version: 152.3K Code, 63.0K Data, 215.3K Total + Current Release: + Non-Debug Version: 71.9K Code, 9.1K Data, 81.0K Total + Debug Version: 153.1K Code, 63.3K Data, 216.4K Total + + +2) Linux + +Module loading/unloading fixes (John Cagle) + + +3) iASL Compiler/Disassembler + +Added support for the SMBBlockProcessCall keyword (ACPI 2.0) + +Implemented support for the disassembly of all SMBus protocol +keywords (SMBQuick, SMBWord, etc.) + +---------------------------------------- +01 November 2002. Summary of changes for version 20021101. + + +1) ACPI CA Core Subsystem: + +Fixed a problem where platforms that have a GPE1 block but no GPE0 +block were not handled correctly. This resulted in a "GPE +overlap" error message. GPE0 is no longer required. + +Removed code added in the previous release that inserted nodes +into the namespace in alphabetical order. This caused some side- +effects on various machines. The root cause of the problem is +still under investigation since in theory, the internal ordering +of the namespace nodes should not matter. + + +Enhanced error reporting for the case where a named object is not +found during control method execution. The full ACPI namepath +(name reference) of the object that was not found is displayed in +this case. + +Note: as a result of the overhaul of the namespace object types in +the previous release, the namespace nodes for the predefined +scopes (_TZ, _PR, etc.) are now of the type ACPI_TYPE_LOCAL_SCOPE +instead of ACPI_TYPE_ANY. This simplifies the namespace +management code but may affect code that walks the namespace tree +looking for specific object types. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a much larger code and data size. Note that these values will +vary depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 70.7K Code, 8.6K Data, 79.3K Total + Debug Version: 151.7K Code, 62.4K Data, 214.1K Total + Current Release: + Non-Debug Version: 71.4K Code, 9.0K Data, 80.4K Total + Debug Version: 152.3K Code, 63.0K Data, 215.3K Total + + +2) Linux + +Fixed a problem introduced in the previous release where the +Processor and Thermal objects were not recognized and installed in +/proc. This was related to the scope type change described above. + + +3) iASL Compiler/Disassembler + +Implemented the -g option to get all of the required ACPI tables +from the registry and save them to files (Windows version of the +compiler only.) The required tables are the FADT, FACS, and DSDT. + +Added ACPI table checksum validation during table disassembly in +order to catch corrupted tables. + + +---------------------------------------- +22 October 2002. Summary of changes for version 20021022. + +1) ACPI CA Core Subsystem: + +Implemented a restriction on the Scope operator that the target +must already exist in the namespace at the time the operator is +encountered (during table load or method execution). In other +words, forward references are not allowed and Scope() cannot +create a new object. This changes the previous behavior where the +interpreter would create the name if not found. This new behavior +correctly enables the search-to-root algorithm during namespace +lookup of the target name. Because of this upsearch, this fixes +the known Compaq _SB_.OKEC problem and makes both the AML +interpreter and iASL compiler compatible with other ACPI +implementations. + +Completed a major overhaul of the internal ACPI object types for +the ACPI Namespace and the associated operand objects. Many of +these types had become obsolete with the introduction of the two- +pass namespace load. This cleanup simplifies the code and makes +the entire namespace load mechanism much clearer and easier to +understand. + +Improved debug output for tracking scope opening/closing to help +diagnose scoping issues. The old scope name as well as the new +scope name are displayed. Also improved error messages for +problems with ASL Mutex objects and error messages for GPE +problems. + +Cleaned up the namespace dump code, removed obsolete code. + +All string output (for all namespace/object dumps) now uses the +common ACPI string output procedure which handles escapes properly +and does not emit non-printable characters. + +Fixed some issues with constants in the 64-bit version of the +local C library (utclib.c) + + +2) Linux + +EC Driver: No longer attempts to acquire the Global Lock at +interrupt level. + + +3) iASL Compiler/Disassembler + +Implemented ACPI 2.0B grammar change that disallows all Type 1 and +2 opcodes outside of a control method. This means that the +"executable" operators (versus the "namespace" operators) cannot +be used at the table level; they can only be used within a control +method. + +Implemented the restriction on the Scope() operator where the +target must already exist in the namespace at the time the +operator is encountered (during ASL compilation). In other words, +forward references are not allowed and Scope() cannot create a new +object. This makes the iASL compiler compatible with other ACPI +implementations and makes the Scope() implementation adhere to the +ACPI specification. + +Fixed a problem where namepath optimization for the Alias operator +was optimizing the wrong path (of the two namepaths.) This caused +a "Missing alias link" error message. + +Fixed a problem where an "unknown reserved name" warning could be +incorrectly generated for names like "_SB" when the trailing +underscore is not used in the original ASL. + +Fixed a problem where the reserved name check did not handle +NamePaths with multiple NameSegs correctly. The first nameseg of +the NamePath was examined instead of the last NameSeg. + + +---------------------------------------- + +02 October 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem version 20021002: + +Fixed a problem where a store/copy of a string to an existing +string did not always set the string length properly in the String +object. + +Fixed a reported problem with the ToString operator where the +behavior was identical to the ToHexString operator instead of just +simply converting a raw buffer to a string data type. + +Fixed a problem where CopyObject and the other "explicit" +conversion operators were not updating the internal namespace node +type as part of the store operation. + +Fixed a memory leak during implicit source operand conversion +where the original object was not deleted if it was converted to a +new object of a different type. + +Enhanced error messages for all problems associated with namespace +lookups. Common procedure generates and prints the lookup name as +well as the formatted status. + +Completed implementation of a new design for the Alias support +within the namespace. The existing design did not handle the case +where a new object was assigned to one of the two names due to the +use of an explicit conversion operator, resulting in the two names +pointing to two different objects. The new design simply points +the Alias name to the original name node - not to the object. +This results in a level of indirection that must be handled in the +name resolution mechanism. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 69.6K Code, 8.3K Data, 77.9K Total + Debug Version: 150.0K Code, 61.7K Data, 211.7K Total + Current Release: + Non-Debug Version: 70.7K Code, 8.6K Data, 79.3K Total + Debug Version: 151.7K Code, 62.4K Data, 214.1K Total + + +2) Linux + +Initialize thermal driver's timer before it is used. (Knut +Neumann) + +Allow handling negative celsius values. (Kochi Takayoshi) + +Fix thermal management and make trip points. R/W (Pavel Machek) + +Fix /proc/acpi/sleep. (P. Christeas) + +IA64 fixes. (David Mosberger) + +Fix reversed logic in blacklist code. (Sergio Monteiro Basto) + +Replace ACPI_DEBUG define with ACPI_DEBUG_OUTPUT. (Dominik +Brodowski) + + +3) iASL Compiler/Disassembler + +Clarified some warning/error messages. + + +---------------------------------------- +18 September 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem version 20020918: + +Fixed a reported problem with reference chaining (via the Index() +and RefOf() operators) in the ObjectType() and SizeOf() operators. +The definition of these operators includes the dereferencing of +all chained references to return information on the base object. + +Fixed a problem with stores to indexed package elements - the +existing code would not complete the store if an "implicit +conversion" was not performed. In other words, if the existing +object (package element) was to be replaced completely, the code +didn't handle this case. + +Relaxed typechecking on the ASL "Scope" operator to allow the +target name to refer to an object of type Integer, String, or +Buffer, in addition to the scoping object types (Device, +predefined Scopes, Processor, PowerResource, and ThermalZone.) +This allows existing AML code that has workarounds for a bug in +Windows to function properly. A warning is issued, however. This +affects both the AML interpreter and the iASL compiler. Below is +an example of this type of ASL code: + + Name(DEB,0x00) + Scope(DEB) + { + +Fixed some reported problems with 64-bit integer support in the +local implementation of C library functions (clib.c) + + +2) Linux + +Use ACPI fix map region instead of IOAPIC region, since it is +undefined in non-SMP. + +Ensure that the SCI has the proper polarity and trigger, even on +systems that do not have an interrupt override entry in the MADT. + +2.5 big driver reorganization (Pat Mochel) + +Use early table mapping code from acpitable.c (Andi Kleen) + +New blacklist entries (Andi Kleen) + +Blacklist improvements. Split blacklist code out into a separate +file. Move checking the blacklist to very early. Previously, we +would use ACPI tables, and then halfway through init, check the +blacklist -- too late. Now, it's early enough to completely fall- +back to non-ACPI. + + +3) iASL Compiler/Disassembler version 20020918: + +Fixed a problem where the typechecking code didn't know that an +alias could point to a method. In other words, aliases were not +being dereferenced during typechecking. + + +---------------------------------------- +29 August 2002. Summary of changes for this release. + +1) ACPI CA Core Subsystem Version 20020829: + +If the target of a Scope() operator already exists, it must be an +object type that actually opens a scope -- such as a Device, +Method, Scope, etc. This is a fatal runtime error. Similar error +check has been added to the iASL compiler also. + +Tightened up the namespace load to disallow multiple names in the +same scope. This previously was allowed if both objects were of +the same type. (i.e., a lookup was the same as entering a new +name). + + +2) Linux + +Ensure that the ACPI interrupt has the proper trigger and +polarity. + +local_irq_disable is extraneous. (Matthew Wilcox) + +Make "acpi=off" actually do what it says, and not use the ACPI +interpreter *or* the tables. + +Added arch-neutral support for parsing SLIT and SRAT tables (Kochi +Takayoshi) + + +3) iASL Compiler/Disassembler Version 20020829: + +Implemented namepath optimization for name declarations. For +example, a declaration like "Method (\_SB_.ABCD)" would get +optimized to "Method (ABCD)" if the declaration is within the +\_SB_ scope. This optimization is in addition to the named +reference path optimization first released in the previous +version. This would seem to complete all possible optimizations +for namepaths within the ASL/AML. + +If the target of a Scope() operator already exists, it must be an +object type that actually opens a scope -- such as a Device, +Method, Scope, etc. + +Implemented a check and warning for unreachable code in the same +block below a Return() statement. + +Fixed a problem where the listing file was not generated if the +compiler aborted if the maximum error count was exceeded (200). + +Fixed a problem where the typechecking of method return values was +broken. This includes the check for a return value when the +method is invoked as a TermArg (a return value is expected.) + +Fixed a reported problem where EOF conditions during a quoted +string or comment caused a fault. + + +---------------------------------------- +15 August 2002. Summary of changes for this release. + +1) ACPI CA Core Subsystem Version 20020815: + +Fixed a reported problem where a Store to a method argument that +contains a reference did not perform the indirect store correctly. +This problem was created during the conversion to the new +reference object model - the indirect store to a method argument +code was not updated to reflect the new model. + +Reworked the ACPI mode change code to better conform to ACPI 2.0, +handle corner cases, and improve code legibility (Kochi Takayoshi) + +Fixed a problem with the pathname parsing for the carat (^) +prefix. The heavy use of the carat operator by the new namepath +optimization in the iASL compiler uncovered a problem with the AML +interpreter handling of this prefix. In the case where one or +more carats precede a single nameseg, the nameseg was treated as +standalone and the search rule (to root) was inadvertently +applied. This could cause both the iASL compiler and the +interpreter to find the wrong object or to miss the error that +should occur if the object does not exist at that exact pathname. + +Found and fixed the problem where the HP Pavilion DSDT would not +load. This was a relatively minor tweak to the table loading code +(a problem caused by the unexpected encounter with a method +invocation not within a control method), but it does not solve the +overall issue of the execution of AML code at the table level. +This investigation is still ongoing. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 69.1K Code, 8.2K Data, 77.3K Total + Debug Version: 149.4K Code, 61.6K Data, 211.0K Total + Current Release: + Non-Debug Version: 69.6K Code, 8.3K Data, 77.9K Total + Debug Version: 150.0K Code, 61.7K Data, 211.7K Total + + +2) Linux + +Remove redundant slab.h include (Brad Hards) + +Fix several bugs in thermal.c (Herbert Nachtnebel) + +Make CONFIG_ACPI_BOOT work properly (Pavel Machek) + +Change acpi_system_suspend to use updated irq functions (Pavel +Machek) + +Export acpi_get_firmware_table (Matthew Wilcox) + +Use proper root proc entry for ACPI (Kochi Takayoshi) + +Fix early-boot table parsing (Bjorn Helgaas) + + +3) iASL Compiler/Disassembler + +Reworked the compiler options to make them more consistent and to +use two-letter options where appropriate. We were running out of +sensible letters. This may break some makefiles, so check the +current options list by invoking the compiler with no parameters. + +Completed the design and implementation of the ASL namepath +optimization option for the compiler. This option optimizes all +references to named objects to the shortest possible path. The +first attempt tries to utilize a single nameseg (4 characters) and +the "search-to-root" algorithm used by the interpreter. If that +cannot be used (because either the name is not in the search path +or there is a conflict with another object with the same name), +the pathname is optimized using the carat prefix (usually a +shorter string than specifying the entire path from the root.) + +Implemented support to obtain the DSDT from the Windows registry +(when the disassembly option is specified with no input file). +Added this code as the implementation for AcpiOsTableOverride in +the Windows OSL. Migrated the 16-bit code (used in the AcpiDump +utility) to scan memory for the DSDT to the AcpiOsTableOverride +function in the DOS OSL to make the disassembler truly OS +independent. + +Implemented a new option to disassemble and compile in one step. +When used without an input filename, this option will grab the +DSDT from the local machine, disassemble it, and compile it in one +step. + +Added a warning message for invalid escapes (a backslash followed +by any character other than the allowable escapes). This catches +the quoted string error "\_SB_" (which should be "\\_SB_" ). + +Also, there are numerous instances in the ACPI specification where +this error occurs. + +Added a compiler option to disable all optimizations. This is +basically the "compatibility mode" because by using this option, +the AML code will come out exactly the same as other ASL +compilers. + +Added error messages for incorrectly ordered dependent resource +functions. This includes: missing EndDependentFn macro at end of +dependent resource list, nested dependent function macros (both +start and end), and missing StartDependentFn macro. These are +common errors that should be caught at compile time. + +Implemented _OSI support for the disassembler and compiler. _OSI +must be included in the namespace for proper disassembly (because +the disassembler must know the number of arguments.) + +Added an "optimization" message type that is optional (off by +default). This message is used for all optimizations - including +constant folding, integer optimization, and namepath optimization. + +---------------------------------------- +25 July 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem Version 20020725: + +The AML Disassembler has been enhanced to produce compilable ASL +code and has been integrated into the iASL compiler (see below) as +well as the single-step disassembly for the AML debugger and the +disassembler for the AcpiDump utility. All ACPI 2.0A opcodes, +resource templates and macros are fully supported. The +disassembler has been tested on over 30 different AML files, +producing identical AML when the resulting disassembled ASL file +is recompiled with the same ASL compiler. + +Modified the Resource Manager to allow zero interrupts and zero +dma channels during the GetCurrentResources call. This was +causing problems on some platforms. + +Added the AcpiOsRedirectOutput interface to the OSL to simplify +output redirection for the AcpiOsPrintf and AcpiOsVprintf +interfaces. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 68.7K Code, 7.4K Data, 76.1K Total + Debug Version: 142.9K Code, 58.7K Data, 201.6K Total + Current Release: + Non-Debug Version: 69.1K Code, 8.2K Data, 77.3K Total + Debug Version: 149.4K Code, 61.6K Data, 211.0K Total + + +2) Linux + +Fixed a panic in the EC driver (Dominik Brodowski) + +Implemented checksum of the R/XSDT itself during Linux table scan +(Richard Schaal) + + +3) iASL compiler + +The AML disassembler is integrated into the compiler. The "-d" +option invokes the disassembler to completely disassemble an +input AML file, producing as output a text ASL file with the +extension ".dsl" (to avoid name collisions with existing .asl +source files.) A future enhancement will allow the disassembler +to obtain the BIOS DSDT from the registry under Windows. + +Fixed a problem with the VendorShort and VendorLong resource +descriptors where an invalid AML sequence was created. + +Implemented a fix for BufferData term in the ASL parser. It was +inadvertently defined twice, allowing invalid syntax to pass and +causing reduction conflicts. + +Fixed a problem where the Ones opcode could get converted to a +value of zero if "Ones" was used where a byte, word or dword value +was expected. The 64-bit value is now truncated to the correct +size with the correct value. + + + +---------------------------------------- +02 July 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem Version 20020702: + +The Table Manager code has been restructured to add several new +features. Tables that are not required by the core subsystem +(other than the FADT, DSDT, FACS, PSDTs, etc.) are no longer +validated in any way and are returned from AcpiGetFirmwareTable if +requested. The AcpiOsTableOverride interface is now called for +each table that is loaded by the subsystem in order to allow the +host to override any table it chooses. Previously, only the DSDT +could be overridden. Added one new files, tbrsdt.c and +tbgetall.c. + +Fixed a problem with the conversion of internal package objects to +external objects (when a package is returned from a control +method.) The return buffer length was set to zero instead of the +proper length of the package object. + +Fixed a reported problem with the use of the RefOf and DeRefOf +operators when passing reference arguments to control methods. A +new type of Reference object is used internally for references +produced by the RefOf operator. + +Added additional error messages in the Resource Manager to explain +AE_BAD_DATA errors when they occur during resource parsing. + +Split the AcpiEnableSubsystem into two primitives to enable a +finer granularity initialization sequence. These two calls should +be called in this order: AcpiEnableSubsystem (flags), +AcpiInitializeObjects (flags). The flags parameter remains the +same. + + +2) Linux + +Updated the ACPI utilities module to understand the new style of +fully resolved package objects that are now returned from the core +subsystem. This eliminates errors of the form: + + ACPI: PCI Interrupt Routing Table [\_SB_.PCI0.PPB_._PRT] + acpi_utils-0430 [145] acpi_evaluate_reference: + Invalid element in package (not a device reference) + +The method evaluation utility uses the new buffer allocation +scheme instead of calling AcpiEvaluate Object twice. + +Added support for ECDT. This allows the use of the Embedded + +Controller before the namespace has been fully initialized, which +is necessary for ACPI 2.0 support, and for some laptops to +initialize properly. (Laptops using ECDT are still rare, so only +limited testing was performed of the added functionality.) + +Fixed memory leaks in the EC driver. + +Eliminated a brittle code structure in acpi_bus_init(). + +Eliminated the acpi_evaluate() helper function in utils.c. It is +no longer needed since acpi_evaluate_object can optionally +allocate memory for the return object. + +Implemented fix for keyboard hang when getting battery readings on +some systems (Stephen White) + +PCI IRQ routing update (Dominik Brodowski) + +Fix an ifdef to allow compilation on UP with LAPIC but no IOAPIC +support + +---------------------------------------- +11 June 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem Version 20020611: + +Fixed a reported problem where constants such as Zero and One +appearing within _PRT packages were not handled correctly within +the resource manager code. Originally reported against the ASL +compiler because the code generator now optimizes integers to +their minimal AML representation (i.e. AML constants if possible.) +The _PRT code now handles all AML constant opcodes correctly +(Zero, One, Ones, Revision). + +Fixed a problem with the Concatenate operator in the AML +interpreter where a buffer result object was incorrectly marked as +not fully evaluated, causing a run-time error of AE_AML_INTERNAL. + +All package sub-objects are now fully resolved before they are +returned from the external ACPI interfaces. This means that name +strings are resolved to object handles, and constant operators +(Zero, One, Ones, Revision) are resolved to Integers. + +Implemented immediate resolution of the AML Constant opcodes +(Zero, One, Ones, Revision) to Integer objects upon detection +within the AML stream. This has simplified and reduced the +generated code size of the subsystem by eliminating about 10 +switch statements for these constants (which previously were +contained in Reference objects.) The complicating issues are that +the Zero opcode is used as a "placeholder" for unspecified +optional target operands and stores to constants are defined to be +no-ops. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 69.3K Code, 7.4K Data, 76.7K Total + Debug Version: 143.8K Code, 58.8K Data, 202.6K Total + Current Release: + Non-Debug Version: 68.7K Code, 7.4K Data, 76.1K Total + Debug Version: 142.9K Code, 58.7K Data, 201.6K Total + + +2) Linux + + +Added preliminary support for obtaining _TRA data for PCI root +bridges (Bjorn Helgaas). + + +3) iASL Compiler Version X2046: + +Fixed a problem where the "_DDN" reserved name was defined to be a +control method with one argument. There are no arguments, and +_DDN does not have to be a control method. + +Fixed a problem with the Linux version of the compiler where the +source lines printed with error messages were the wrong lines. +This turned out to be the "LF versus CR/LF" difference between +Windows and Unix. This appears to be the longstanding issue +concerning listing output and error messages. + +Fixed a problem with the Linux version of compiler where opcode +names within error messages were wrong. This was caused by a +slight difference in the output of the Flex tool on Linux versus +Windows. + +Fixed a problem with the Linux compiler where the hex output files +contained some garbage data caused by an internal buffer overrun. + + +---------------------------------------- +17 May 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem Version 20020517: + +Implemented a workaround to an BIOS bug discovered on the HP +OmniBook where the FADT revision number and the table size are +inconsistent (ACPI 2.0 revision vs. ACPI 1.0 table size). The new +behavior is to fallback to using only the ACPI 1.0 fields of the +FADT if the table is too small to be a ACPI 2.0 table as claimed +by the revision number. Although this is a BIOS bug, this is a +case where the workaround is simple enough and with no side +effects, so it seemed prudent to add it. A warning message is +issued, however. + +Implemented minimum size checks for the fixed-length ACPI tables - +- the FADT and FACS, as well as consistency checks between the +revision number and the table size. + +Fixed a reported problem in the table override support where the +new table pointer was incorrectly treated as a physical address +instead of a logical address. + +Eliminated the use of the AE_AML_ERROR exception and replaced it +with more descriptive codes. + +Fixed a problem where an exception would occur if an ASL Field was +defined with no named Field Units underneath it (used by some +index fields). + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 68.8K Code, 7.1K Data, 75.9K Total + Debug Version: 142.9K Code, 58.4K Data, 201.3K Total + Current Release: + Non-Debug Version: 69.3K Code, 7.4K Data, 76.7K Total + Debug Version: 143.8K Code, 58.8K Data, 202.6K Total + + + +2) Linux + +Much work done on ACPI init (MADT and PCI IRQ routing support). +(Paul D. and Dominik Brodowski) + +Fix PCI IRQ-related panic on boot (Sam Revitch) + +Set BM_ARB_DIS when entering a sleep state (Ducrot Bruno) + +Fix "MHz" typo (Dominik Brodowski) + +Fix RTC year 2000 issue (Dominik Brodowski) + +Preclude multiple button proc entries (Eric Brunet) + +Moved arch-specific code out of include/platform/aclinux.h + +3) iASL Compiler Version X2044: + +Implemented error checking for the string used in the EISAID macro +(Usually used in the definition of the _HID object.) The code now +strictly enforces the PnP format - exactly 7 characters, 3 +uppercase letters and 4 hex digits. + +If a raw string is used in the definition of the _HID object +(instead of the EISAID macro), the string must contain all +alphanumeric characters (e.g., "*PNP0011" is not allowed because +of the asterisk.) + +Implemented checking for invalid use of ACPI reserved names for +most of the name creation operators (Name, Device, Event, Mutex, +OperationRegion, PowerResource, Processor, and ThermalZone.) +Previously, this check was only performed for control methods. + +Implemented an additional check on the Name operator to emit an +error if a reserved name that must be implemented in ASL as a +control method is used. We know that a reserved name must be a +method if it is defined with input arguments. + +The warning emitted when a namespace object reference is not found +during the cross reference phase has been changed into an error. +The "External" directive should be used for names defined in other +modules. + + +4) Tools and Utilities + +The 16-bit tools (adump16 and aexec16) have been regenerated and +tested. + +Fixed a problem with the output of both acpidump and adump16 where +the indentation of closing parentheses and brackets was not + +aligned properly with the parent block. + + +---------------------------------------- +03 May 2002. Summary of changes for this release. + + +1) ACPI CA Core Subsystem Version 20020503: + +Added support a new OSL interface that allows the host operating + +system software to override the DSDT found in the firmware - +AcpiOsTableOverride. With this interface, the OSL can examine the +version of the firmware DSDT and replace it with a different one +if desired. + +Added new external interfaces for accessing ACPI registers from +device drivers and other system software - AcpiGetRegister and +AcpiSetRegister. This was simply an externalization of the +existing AcpiHwBitRegister interfaces. + +Fixed a regression introduced in the previous build where the +ASL/AML CreateField operator always returned an error, +"destination must be a NS Node". + +Extended the maximum time (before failure) to successfully enable +ACPI mode to 3 seconds. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 68.5K Code, 7.0K Data, 75.5K Total + Debug Version: 142.4K Code, 58.3K Data, 200.7K Total + Current Release: + Non-Debug Version: 68.8K Code, 7.1K Data, 75.9K Total + Debug Version: 142.9K Code, 58.4K Data, 201.3K Total + + +2) Linux + +Enhanced ACPI init code for SMP. We are now fully MPS and $PIR- +free. While 3 out of 4 of our in-house systems work fine, the last +one still hangs when testing the LAPIC timer. + +Renamed many files in 2.5 kernel release to omit "acpi_" from the +name. + +Added warning on boot for Presario 711FR. + +Sleep improvements (Pavel Machek) + +ACPI can now be built without CONFIG_PCI enabled. + +IA64: Fixed memory map functions (JI Lee) + + +3) iASL Compiler Version X2043: + +Added support to allow the compiler to be integrated into the MS +VC++ development environment for one-button compilation of single +files or entire projects -- with error-to-source-line mapping. + +Implemented support for compile-time constant folding for the +Type3, Type4, and Type5 opcodes first defined in the ACPI 2.0 +specification. This allows the ASL writer to use expressions +instead of Integer/Buffer/String constants in terms that must +evaluate to constants at compile time and will also simplify the +emitted AML in any such sub-expressions that can be folded +(evaluated at compile-time.) This increases the size of the +compiler significantly because a portion of the ACPI CA AML +interpreter is included within the compiler in order to pre- +evaluate constant expressions. + + +Fixed a problem with the "Unicode" ASL macro that caused the +compiler to fault. (This macro is used in conjunction with the +_STR reserved name.) + +Implemented an AML opcode optimization to use the Zero, One, and +Ones opcodes where possible to further reduce the size of integer +constants and thus reduce the overall size of the generated AML +code. + +Implemented error checking for new reserved terms for ACPI version +2.0A. + +Implemented the -qr option to display the current list of ACPI +reserved names known to the compiler. + +Implemented the -qc option to display the current list of ASL +operators that are allowed within constant expressions and can +therefore be folded at compile time if the operands are constants. + + +4) Documentation + +Updated the Programmer's Reference for new interfaces, data types, +and memory allocation model options. + +Updated the iASL Compiler User Reference to apply new format and +add information about new features and options. + +---------------------------------------- +19 April 2002. Summary of changes for this release. + +1) ACPI CA Core Subsystem Version 20020419: + +The source code base for the Core Subsystem has been completely +cleaned with PC-lint (FlexLint) for both 32-bit and 64-bit +versions. The Lint option files used are included in the +/acpi/generate/lint directory. + +Implemented enhanced status/error checking across the entire +Hardware manager subsystem. Any hardware errors (reported from +the OSL) are now bubbled up and will abort a running control +method. + + +Fixed a problem where the per-ACPI-table integer width (32 or 64) +was stored only with control method nodes, causing a fault when +non-control method code was executed during table loading. The +solution implemented uses a global variable to indicate table +width across the entire ACPI subsystem. Therefore, ACPI CA does +not support mixed integer widths across different ACPI tables +(DSDT, SSDT). + +Fixed a problem where NULL extended fields (X fields) in an ACPI +2.0 ACPI FADT caused the table load to fail. Although the +existing ACPI specification is a bit fuzzy on this topic, the new +behavior is to fall back on a ACPI 1.0 field if the corresponding +ACPI 2.0 X field is zero (even though the table revision indicates +a full ACPI 2.0 table.) The ACPI specification will be updated to +clarify this issue. + +Fixed a problem with the SystemMemory operation region handler +where memory was always accessed byte-wise even if the AML- +specified access width was larger than a byte. This caused +problems on systems with memory-mapped I/O. Memory is now +accessed with the width specified. On systems that do not support +non-aligned transfers, a check is made to guarantee proper address +alignment before proceeding in order to avoid an AML-caused +alignment fault within the kernel. + + +Fixed a problem with the ExtendedIrq resource where only one byte +of the 4-byte Irq field was extracted. + +Fixed the AcpiExDigitsNeeded() procedure to support _UID. This +function was out of date and required a rewrite. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 66.6K Code, 6.5K Data, 73.1K Total + Debug Version: 139.8K Code, 57.4K Data, 197.2K Total + Current Release: + Non-Debug Version: 68.5K Code, 7.0K Data, 75.5K Total + Debug Version: 142.4K Code, 58.3K Data, 200.7K Total + + +2) Linux + +PCI IRQ routing fixes (Dominik Brodowski) + + +3) iASL Compiler Version X2042: + +Implemented an additional compile-time error check for a field +unit whose size + minimum access width would cause a run-time +access beyond the end-of-region. Previously, only the field size +itself was checked. + +The Core subsystem and iASL compiler now share a common parse +object in preparation for compile-time evaluation of the type +3/4/5 ASL operators. + + +---------------------------------------- +Summary of changes for this release: 03_29_02 + +1) ACPI CA Core Subsystem Version 20020329: + +Implemented support for late evaluation of TermArg operands to +Buffer and Package objects. This allows complex expressions to be +used in the declarations of these object types. + +Fixed an ACPI 1.0 compatibility issue when reading Fields. In ACPI +1.0, if the field was larger than 32 bits, it was returned as a +buffer - otherwise it was returned as an integer. In ACPI 2.0, +the field is returned as a buffer only if the field is larger than +64 bits. The TableRevision is now considered when making this +conversion to avoid incompatibility with existing ASL code. + +Implemented logical addressing for AcpiOsGetRootPointer. This +allows an RSDP with either a logical or physical address. With +this support, the host OS can now override all ACPI tables with +one logical RSDP. Includes implementation of "typed" pointer +support to allow a common data type for both physical and logical +pointers internally. This required a change to the +AcpiOsGetRootPointer interface. + +Implemented the use of ACPI 2.0 Generic Address Structures for all +GPE, Fixed Event, and PM Timer I/O. This allows the use of memory +mapped I/O for these ACPI features. + +Initialization now ignores not only non-required tables (All +tables other than the FADT, FACS, DSDT, and SSDTs), but also does +not validate the table headers of unrecognized tables. + +Fixed a problem where a notify handler could only be +installed/removed on an object of type Device. All "notify" + +objects are now supported -- Devices, Processor, Power, and +Thermal. + +Removed most verbosity from the ACPI_DB_INFO debug level. Only +critical information is returned when this debug level is enabled. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release + Non-Debug Version: 65.4K Code, 6.2K Data, 71.6K Total + Debug Version: 138.0K Code, 56.6K Data, 194.6K Total + Current Release: + Non-Debug Version: 66.6K Code, 6.5K Data, 73.1K Total + Debug Version: 139.8K Code, 57.4K Data, 197.2K Total + + +2) Linux: + +The processor driver (acpi_processor.c) now fully supports ACPI +2.0-based processor performance control (e.g. Intel(R) +SpeedStep(TM) technology) Note that older laptops that only have +the Intel "applet" interface are not supported through this. The +'limit' and 'performance' interface (/proc) are fully functional. +[Note that basic policy for controlling performance state +transitions will be included in the next version of ospmd.] The +idle handler was modified to more aggressively use C2, and PIIX4 +errata handling underwent a complete overhaul (big thanks to +Dominik Brodowski). + +Added support for ACPI-PCI device binding (acpi_pci_root.c). _ADR- +based devices in the ACPI namespace are now dynamically bound +(associated) with their PCI counterparts (e.g. PCI1->01:00.0). +This allows, among other things, ACPI to resolve bus numbers for +subordinate PCI bridges. + +Enhanced PCI IRQ routing to get the proper bus number for _PRT +entries defined underneath PCI bridges. + +Added IBM 600E to bad bios list due to invalid _ADR value for +PIIX4 PCI-ISA bridge, resulting in improper PCI IRQ routing. + +In the process of adding full MADT support (e.g. IOAPIC) for IA32 +(acpi.c, mpparse.c) -- stay tuned. + +Added back visual differentiation between fixed-feature and +control-method buttons in dmesg. Buttons are also subtyped (e.g. +button/power/PWRF) to simplify button identification. + +We no longer use -Wno-unused when compiling debug. Please ignore +any "_THIS_MODULE defined but not used" messages. + +Can now shut down the system using "magic sysrq" key. + + +3) iASL Compiler version 2041: + +Fixed a problem where conversion errors for hex/octal/decimal +constants were not reported. + +Implemented a fix for the General Register template Address field. +This field was 8 bits when it should be 64. + +Fixed a problem where errors/warnings were no longer being emitted +within the listing output file. + +Implemented the ACPI 2.0A restriction on ACPI Table Signatures to +exactly 4 characters, alphanumeric only. + + + + +---------------------------------------- +Summary of changes for this release: 03_08_02 + + +1) ACPI CA Core Subsystem Version 20020308: + +Fixed a problem with AML Fields where the use of the "AccessAny" +keyword could cause an interpreter error due to attempting to read +or write beyond the end of the parent Operation Region. + +Fixed a problem in the SystemMemory Operation Region handler where +an attempt was made to map memory beyond the end of the region. +This was the root cause of the "AE_ERROR" and "AE_NO_MEMORY" +errors on some Linux systems. + +Fixed a problem where the interpreter/namespace "search to root" +algorithm was not functioning for some object types. Relaxed the +internal restriction on the search to allow upsearches for all +external object types as well as most internal types. + + +2) Linux: + +We now use safe_halt() macro versus individual calls to sti | hlt. + +Writing to the processor limit interface should now work. "echo 1" +will increase the limit, 2 will decrease, and 0 will reset to the + +default. + + +3) ASL compiler: + +Fixed segfault on Linux version. + + +---------------------------------------- +Summary of changes for this release: 02_25_02 + +1) ACPI CA Core Subsystem: + + +Fixed a problem where the GPE bit masks were not initialized +properly, causing erratic GPE behavior. + +Implemented limited support for multiple calling conventions. The +code can be generated with either the VPL (variable parameter +list, or "C") convention, or the FPL (fixed parameter list, or +"Pascal") convention. The core subsystem is about 3.4% smaller +when generated with FPL. + + +2) Linux + +Re-add some /proc/acpi/event functionality that was lost during +the rewrite + +Resolved issue with /proc events for fixed-feature buttons showing +up as the system device. + +Fixed checks on C2/C3 latencies to be inclusive of maximum values. + +Replaced AE_ERRORs in acpi_osl.c with more specific error codes. + +Changed ACPI PRT option from "pci=noacpi-routing" to "pci=noacpi" + +Fixed limit interface & usage to fix bugs with passive cooling +hysterisis. + +Restructured PRT support. + + +---------------------------------------- +Summary of changes for this label: 02_14_02 + + +1) ACPI CA Core Subsystem: + +Implemented support in AcpiLoadTable to allow loading of FACS and +FADT tables. + +Suport for the now-obsolete interim 0.71 64-bit ACPI tables has +been removed. All 64-bit platforms should be migrated to the ACPI +2.0 tables. The actbl71.h header has been removed from the source +tree. + +All C macros defined within the subsystem have been prefixed with +"ACPI_" to avoid collision with other system include files. + +Removed the return value for the two AcpiOsPrint interfaces, since +it is never used and causes lint warnings for ignoring the return +value. + +Added error checking to all internal mutex acquire and release +calls. Although a failure from one of these interfaces is +probably a fatal system error, these checks will cause the +immediate abort of the currently executing method or interface. + +Fixed a problem where the AcpiSetCurrentResources interface could +fault. This was a side effect of the deployment of the new memory +allocation model. + +Fixed a couple of problems with the Global Lock support introduced +in the last major build. The "common" (1.0/2.0) internal FACS was +being overwritten with the FACS signature and clobbering the +Global Lock pointer. Also, the actual firmware FACS was being +unmapped after construction of the "common" FACS, preventing +access to the actual Global Lock field within it. The "common" +internal FACS is no longer installed as an actual ACPI table; it +is used simply as a global. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release (02_07_01) + Non-Debug Version: 65.2K Code, 6.2K Data, 71.4K Total + Debug Version: 136.9K Code, 56.4K Data, 193.3K Total + Current Release: + Non-Debug Version: 65.4K Code, 6.2K Data, 71.6K Total + Debug Version: 138.0K Code, 56.6K Data, 194.6K Total + + +2) Linux + +Updated Linux-specific code for core macro and OSL interface +changes described above. + +Improved /proc/acpi/event. It now can be opened only once and has +proper poll functionality. + +Fixed and restructured power management (acpi_bus). + +Only create /proc "view by type" when devices of that class exist. + +Fixed "charging/discharging" bug (and others) in acpi_battery. + +Improved thermal zone code. + + +3) ASL Compiler, version X2039: + + +Implemented the new compiler restriction on ASL String hex/octal +escapes to non-null, ASCII values. An error results if an invalid +value is used. (This will require an ACPI 2.0 specification +change.) + +AML object labels that are output to the optional C and ASM source +are now prefixed with both the ACPI table signature and table ID +to help guarantee uniqueness within a large BIOS project. + + +---------------------------------------- +Summary of changes for this label: 02_01_02 + +1) ACPI CA Core Subsystem: + +ACPI 2.0 support is complete in the entire Core Subsystem and the +ASL compiler. All new ACPI 2.0 operators are implemented and all +other changes for ACPI 2.0 support are complete. With +simultaneous code and data optimizations throughout the subsystem, +ACPI 2.0 support has been implemented with almost no additional +cost in terms of code and data size. + +Implemented a new mechanism for allocation of return buffers. If +the buffer length is set to ACPI_ALLOCATE_BUFFER, the buffer will +be allocated on behalf of the caller. Consolidated all return +buffer validation and allocation to a common procedure. Return +buffers will be allocated via the primary OSL allocation interface +since it appears that a separate pool is not needed by most users. +If a separate pool is required for these buffers, the caller can +still use the original mechanism and pre-allocate the buffer(s). + +Implemented support for string operands within the DerefOf +operator. + +Restructured the Hardware and Event managers to be table driven, +simplifying the source code and reducing the amount of generated +code. + +Split the common read/write low-level ACPI register bitfield +procedure into a separate read and write, simplifying the code +considerably. + +Obsoleted the AcpiOsCallocate OSL interface. This interface was +used only a handful of times and didn't have enough critical mass +for a separate interface. Replaced with a common calloc procedure +in the core. + +Fixed a reported problem with the GPE number mapping mechanism +that allows GPE1 numbers to be non-contiguous with GPE0. +Reorganized the GPE information and shrunk a large array that was +originally large enough to hold info for all possible GPEs (256) +to simply large enough to hold all GPEs up to the largest GPE +number on the machine. + +Fixed a reported problem with resource structure alignment on 64- +bit platforms. + +Changed the AcpiEnableEvent and AcpiDisableEvent external +interfaces to not require any flags for the common case of +enabling/disabling a GPE. + +Implemented support to allow a "Notify" on a Processor object. + +Most TBDs in comments within the source code have been resolved +and eliminated. + + +Fixed a problem in the interpreter where a standalone parent +prefix (^) was not handled correctly in the interpreter and +debugger. + +Removed obsolete and unnecessary GPE save/restore code. + +Implemented Field support in the ASL Load operator. This allows a +table to be loaded from a named field, in addition to loading a +table directly from an Operation Region. + +Implemented timeout and handle support in the external Global Lock +interfaces. + +Fixed a problem in the AcpiDump utility where pathnames were no +longer being generated correctly during the dump of named objects. + +Modified the AML debugger to give a full display of if/while +predicates instead of just one AML opcode at a time. (The +predicate can have several nested ASL statements.) The old method +was confusing during single stepping. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release (12_18_01) + Non-Debug Version: 66.1K Code, 5.5K Data, 71.6K Total + Debug Version: 138.3K Code, 55.9K Data, 194.2K Total + Current Release: + Non-Debug Version: 65.2K Code, 6.2K Data, 71.4K Total + Debug Version: 136.9K Code, 56.4K Data, 193.3K Total + +2) Linux + + Implemented fix for PIIX reverse throttling errata (Processor +driver) + +Added new Limit interface (Processor and Thermal drivers) + +New thermal policy (Thermal driver) + +Many updates to /proc + +Battery "low" event support (Battery driver) + +Supports ACPI PCI IRQ routing (PCI Link and PCI root drivers) + +IA32 - IA64 initialization unification, no longer experimental + +Menuconfig options redesigned + +3) ASL Compiler, version X2037: + +Implemented several new output features to simplify integration of +AML code into firmware: 1) Output the AML in C source code with +labels for each named ASL object. The original ASL source code +is interleaved as C comments. 2) Output the AML in ASM source code +with labels and interleaved ASL source. 3) Output the AML in +raw hex table form, in either C or ASM. + +Implemented support for optional string parameters to the +LoadTable operator. + +Completed support for embedded escape sequences within string +literals. The compiler now supports all single character escapes +as well as the Octal and Hex escapes. Note: the insertion of a +null byte into a string literal (via the hex/octal escape) causes +the string to be immediately terminated. A warning is issued. + +Fixed a problem where incorrect AML was generated for the case +where an ASL namepath consists of a single parent prefix ( + +) with no trailing name segments. + +The compiler has been successfully generated with a 64-bit C +compiler. + + + + +---------------------------------------- +Summary of changes for this label: 12_18_01 + +1) Linux + +Enhanced blacklist with reason and severity fields. Any table's +signature may now be used to identify a blacklisted system. + +Call _PIC control method to inform the firmware which interrupt +model the OS is using. Turn on any disabled link devices. + +Cleaned up busmgr /proc error handling (Andreas Dilger) + + 2) ACPI CA Core Subsystem: + +Implemented ACPI 2.0 semantics for the "Break" operator (Exit from +while loop) + +Completed implementation of the ACPI 2.0 "Continue", +"ConcatenateResTemplate", "DataTableRegion", and "LoadTable" +operators. All new ACPI 2.0 operators are now implemented in both +the ASL compiler and the AML interpreter. The only remaining ACPI +2.0 task is support for the String data type in the DerefOf +operator. Fixed a problem with AcquireMutex where the status code +was lost if the caller had to actually wait for the mutex. + +Increased the maximum ASL Field size from 64K bits to 4G bits. + +Completed implementation of the external Global Lock interfaces -- +AcpiAcquireGlobalLock and AcpiReleaseGlobalLock. The Timeout and +Handler parameters were added. + +Completed another pass at removing warnings and issues when +compiling with 64-bit compilers. The code now compiles cleanly +with the Intel 64-bit C/C++ compiler. Most notably, the pointer +add and subtract (diff) macros have changed considerably. + + +Created and deployed a new ACPI_SIZE type that is 64-bits wide on +64-bit platforms, 32-bits on all others. This type is used +wherever memory allocation and/or the C sizeof() operator is used, +and affects the OSL memory allocation interfaces AcpiOsAllocate +and AcpiOsCallocate. + +Implemented sticky user breakpoints in the AML debugger. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release (12_05_01) + Non-Debug Version: 64.7K Code, 5.3K Data, 70.0K Total + Debug Version: 136.2K Code, 55.6K Data, 191.8K Total + Current Release: + Non-Debug Version: 66.1K Code, 5.5K Data, 71.6K Total + Debug Version: 138.3K Code, 55.9K Data, 194.2K Total + + 3) ASL Compiler, version X2034: + +Now checks for (and generates an error if detected) the use of a +Break or Continue statement without an enclosing While statement. + + +Successfully generated the compiler with the Intel 64-bit C +compiler. + + ---------------------------------------- +Summary of changes for this label: 12_05_01 + + 1) ACPI CA Core Subsystem: + +The ACPI 2.0 CopyObject operator is fully implemented. This +operator creates a new copy of an object (and is also used to +bypass the "implicit conversion" mechanism of the Store operator.) + +The ACPI 2.0 semantics for the SizeOf operator are fully +implemented. The change is that performing a SizeOf on a +reference object causes an automatic dereference of the object to +tha actual value before the size is evaluated. This behavior was +undefined in ACPI 1.0. + +The ACPI 2.0 semantics for the Extended IRQ resource descriptor +have been implemented. The interrupt polarity and mode are now +independently set. + +Fixed a problem where ASL Constants (Zero, One, Ones, Revision) +appearing in Package objects were not properly converted to +integers when the internal Package was converted to an external +object (via the AcpiEvaluateObject interface.) + +Fixed a problem with the namespace object deletion mechanism for +objects created by control methods. There were two parts to this +problem: 1) Objects created during the initialization phase method +parse were not being deleted, and 2) The object owner ID mechanism +to track objects was broken. + +Fixed a problem where the use of the ASL Scope operator within a +control method would result in an invalid opcode exception. + +Fixed a problem introduced in the previous label where the buffer +length required for the _PRT structure was not being returned +correctly. + +Code and Data Size: Current core subsystem library sizes are shown +below. These are the code and data sizes for the acpica.lib +produced by the Microsoft Visual C++ 6.0 compiler, and these +values do not include any ACPI driver or OSPM code. The debug +version of the code includes the debug output trace mechanism and +has a larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Release (11_20_01) + Non-Debug Version: 64.1K Code, 5.3K Data, 69.4K Total + Debug Version: 135.1K Code, 55.4K Data, 190.5K Total + + Current Release: + Non-Debug Version: 64.7K Code, 5.3K Data, 70.0K Total + Debug Version: 136.2K Code, 55.6K Data, 191.8K Total + + 2) Linux: + +Updated all files to apply cleanly against 2.4.16. + +Added basic PCI Interrupt Routing Table (PRT) support for IA32 +(acpi_pci.c), and unified the PRT code for IA32 and IA64. This +version supports both static and dyanmic PRT entries, but dynamic +entries are treated as if they were static (not yet +reconfigurable). Architecture- specific code to use this data is +absent on IA32 but should be available shortly. + +Changed the initialization sequence to start the ACPI interpreter +(acpi_init) prior to initialization of the PCI driver (pci_init) +in init/main.c. This ordering is required to support PRT and +facilitate other (future) enhancement. A side effect is that the +ACPI bus driver and certain device drivers can no longer be loaded +as modules. + +Modified the 'make menuconfig' options to allow PCI Interrupt +Routing support to be included without the ACPI Bus and other +device drivers. + + 3) ASL Compiler, version X2033: + +Fixed some issues with the use of the new CopyObject and +DataTableRegion operators. Both are fully functional. + + ---------------------------------------- +Summary of changes for this label: 11_20_01 + + 20 November 2001. Summary of changes for this release. + + 1) ACPI CA Core Subsystem: + +Updated Index support to match ACPI 2.0 semantics. Storing a +Integer, String, or Buffer to an Index of a Buffer will store only +the least-significant byte of the source to the Indexed buffer +byte. Multiple writes are not performed. + +Fixed a problem where the access type used in an AccessAs ASL +operator was not recorded correctly into the field object. + +Fixed a problem where ASL Event objects were created in a +signalled state. Events are now created in an unsignalled state. + +The internal object cache is now purged after table loading and +initialization to reduce the use of dynamic kernel memory -- on +the assumption that object use is greatest during the parse phase +of the entire table (versus the run-time use of individual control +methods.) + +ACPI 2.0 variable-length packages are now fully operational. + +Code and Data Size: Code and Data optimizations have permitted new +feature development with an actual reduction in the library size. +Current core subsystem library sizes are shown below. These are +the code and data sizes for the acpica.lib produced by the +Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code +includes the debug output trace mechanism and has a larger code +and data size. Note that these values will vary depending on the +efficiency of the compiler and the compiler options used during +generation. + + Previous Release (11_09_01): + Non-Debug Version: 63.7K Code, 5.2K Data, 68.9K Total + Debug Version: 134.5K Code, 55.4K Data, 189.9K Total + + Current Release: + Non-Debug Version: 64.1K Code, 5.3K Data, 69.4K Total + Debug Version: 135.1K Code, 55.4K Data, 190.5K Total + + 2) Linux: + +Enhanced the ACPI boot-time initialization code to allow the use +of Local APIC tables for processor enumeration on IA-32, and to +pave the way for a fully MPS-free boot (on SMP systems) in the +near future. This functionality replaces +arch/i386/kernel/acpitables.c, which was introduced in an earlier +2.4.15-preX release. To enable this feature you must add +"acpi_boot=on" to the kernel command line -- see the help entry +for CONFIG_ACPI_BOOT for more information. An IA-64 release is in +the works... + +Restructured the configuration options to allow boot-time table +parsing support without inclusion of the ACPI Interpreter (and +other) code. + +NOTE: This release does not include fixes for the reported events, +power-down, and thermal passive cooling issues (coming soon). + + 3) ASL Compiler: + +Added additional typechecking for Fields within restricted access +Operation Regions. All fields within EC and CMOS regions must be +declared with ByteAcc. All fields withing SMBus regions must be +declared with the BufferAcc access type. + +Fixed a problem where the listing file output of control methods +no longer interleaved the actual AML code with the ASL source +code. + + + + +---------------------------------------- +Summary of changes for this label: 11_09_01 + +1) ACPI CA Core Subsystem: + +Implemented ACPI 2.0-defined support for writes to fields with a +Buffer, String, or Integer source operand that is smaller than the +target field. In these cases, the source operand is zero-extended +to fill the target field. + +Fixed a problem where a Field starting bit offset (within the +parent operation region) was calculated incorrectly if the + +alignment of the field differed from the access width. This +affected CreateWordField, CreateDwordField, CreateQwordField, and +possibly other fields that use the "AccessAny" keyword. + +Fixed a problem introduced in the 11_02_01 release where indirect +stores through method arguments did not operate correctly. + +2) Linux: + +Implemented boot-time ACPI table parsing support +(CONFIG_ACPI_BOOT) for IA32 and IA64 UP/SMP systems. This code +facilitates the use of ACPI tables (e.g. MADT, SRAT) rather than +legacy BIOS interfaces (e.g. MPS) for the configuration of system +processors, memory, and interrupts during setup_arch(). Note that +this patch does not include the required architecture-specific +changes required to apply this information -- subsequent patches +will be posted for both IA32 and IA64 to achieve this. + +Added low-level sleep support for IA32 platforms, courtesy of Pat +Mochel. This allows IA32 systems to transition to/from various +sleeping states (e.g. S1, S3), although the lack of a centralized +driver model and power-manageable drivers will prevent its +(successful) use on most systems. + +Revamped the ACPI 'menuconfig' layout: created new "ACPI Support" +submenu, unified IA32 and IA64 options, added new "Boot using ACPI +tables" option, etc. + +Increased the default timeout for the EC driver from 1ms to 10ms +(1000 cycles of 10us) to try to address AE_TIME errors during EC +transactions. + + ---------------------------------------- +Summary of changes for this label: 11_02_01 + +1) ACPI CA Core Subsystem: + +ACPI 2.0 Support: Implemented ACPI 2.0 64-bit Field access +(QWordAcc keyword). All ACPI 2.0 64-bit support is now +implemented. + +OSL Interfaces: Several of the OSL (AcpiOs*) interfaces required +changes to support ACPI 2.0 Qword field access. Read/Write +PciConfiguration(), Read/Write Memory(), and Read/Write Port() now +accept an ACPI_INTEGER (64 bits) as the value parameter. Also, +the value parameter for the address space handler interface is now +an ACPI_INTEGER. OSL implementations of these interfaces must now +handle the case where the Width parameter is 64. + +Index Fields: Fixed a problem where unaligned bit assembly and +disassembly for IndexFields was not supported correctly. + +Index and Bank Fields: Nested Index and Bank Fields are now +supported. During field access, a check is performed to ensure +that the value written to an Index or Bank register is not out of +the range of the register. The Index (or Bank) register is +written before each access to the field data. Future support will +include allowing individual IndexFields to be wider than the +DataRegister width. + +Fields: Fixed a problem where the AML interpreter was incorrectly +attempting to write beyond the end of a Field/OpRegion. This was +a boundary case that occurred when a DWORD field was written to a +BYTE access OpRegion, forcing multiple writes and causing the +interpreter to write one datum too many. + +Fields: Fixed a problem with Field/OpRegion access where the +starting bit address of a field was incorrectly calculated if the +current access type was wider than a byte (WordAcc, DwordAcc, or +QwordAcc). + +Fields: Fixed a problem where forward references to individual +FieldUnits (individual Field names within a Field definition) were +not resolved during the AML table load. + +Fields: Fixed a problem where forward references from a Field +definition to the parent Operation Region definition were not +resolved during the AML table load. + +Fields: Duplicate FieldUnit names within a scope are now detected +during AML table load. + +Acpi Interfaces: Fixed a problem where the AcpiGetName() interface +returned an incorrect name for the root node. + +Code and Data Size: Code and Data optimizations have permitted new +feature development with an actual reduction in the library size. +Current core subsystem library sizes are shown below. These are +the code and data sizes for the acpica.lib produced by the +Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code +includes the debug output trace mechanism and has a larger code +and data size. Note that these values will vary depending on the +efficiency of the compiler and the compiler options used during +generation. + + Previous Release (10_18_01): + Non-Debug Version: 63.9K Code, 5.1K Data, 69.0K Total + Debug Version: 136.7K Code, 57.4K Data, 194.2K Total + + Current Release: + Non-Debug Version: 63.7K Code, 5.2K Data, 68.9K Total + Debug Version: 134.5K Code, 55.4K Data, 189.9K Total + + 2) Linux: + +Improved /proc processor output (Pavel Machek) Re-added +MODULE_LICENSE("GPL") to all modules. + + 3) ASL Compiler version X2030: + +Duplicate FieldUnit names within a scope are now detected and +flagged as errors. + + 4) Documentation: + +Programmer Reference updated to reflect OSL and address space +handler interface changes described above. + +---------------------------------------- +Summary of changes for this label: 10_18_01 + +ACPI CA Core Subsystem: + +Fixed a problem with the internal object reference count mechanism +that occasionally caused premature object deletion. This resolves +all of the outstanding problem reports where an object is deleted +in the middle of an interpreter evaluation. Although this problem +only showed up in rather obscure cases, the solution to the +problem involved an adjustment of all reference counts involving +objects attached to namespace nodes. + +Fixed a problem with Field support in the interpreter where +writing to an aligned field whose length is an exact multiple (2 +or greater) of the field access granularity would cause an attempt +to write beyond the end of the field. + +The top level AML opcode execution functions within the +interpreter have been renamed with a more meaningful and +consistent naming convention. The modules exmonad.c and +exdyadic.c were eliminated. New modules are exoparg1.c, +exoparg2.c, exoparg3.c, and exoparg6.c. + +Support for the ACPI 2.0 "Mid" ASL operator has been implemented. + +Fixed a problem where the AML debugger was causing some internal +objects to not be deleted during subsystem termination. + +Fixed a problem with the external AcpiEvaluateObject interface +where the subsystem would fault if the named object to be +evaluated refered to a constant such as Zero, Ones, etc. + +Fixed a problem with IndexFields and BankFields where the +subsystem would fault if the index, data, or bank registers were +not defined in the same scope as the field itself. + +Added printf format string checking for compilers that support +this feature. Corrected more than 50 instances of issues with +format specifiers within invocations of ACPI_DEBUG_PRINT +throughout the core subsystem code. + +The ASL "Revision" operator now returns the ACPI support level +implemented in the core - the value "2" since the ACPI 2.0 support +is more than 50% implemented. + +Enhanced the output of the AML debugger "dump namespace" command +to output in a more human-readable form. + +Current core subsystem library code sizes are shown below. These + +are the code and data sizes for the acpica.lib produced by the +Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code +includes the full debug trace mechanism -- leading to a much + +larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Previous Label (09_20_01): + Non-Debug Version: 65K Code, 5K Data, 70K Total + Debug Version: 138K Code, 58K Data, 196K Total + + This Label: + + Non-Debug Version: 63.9K Code, 5.1K Data, 69.0K Total + Debug Version: 136.7K Code, 57.4K Data, 194.2K Total + +Linux: + +Implemented a "Bad BIOS Blacklist" to track machines that have +known ASL/AML problems. + +Enhanced the /proc interface for the thermal zone driver and added +support for _HOT (the critical suspend trip point). The 'info' +file now includes threshold/policy information, and allows setting +of _SCP (cooling preference) and _TZP (polling frequency) values +to the 'info' file. Examples: "echo tzp=5 > info" sets the polling +frequency to 5 seconds, and "echo scp=1 > info" sets the cooling +preference to the passive/quiet mode (if supported by the ASL). + +Implemented a workaround for a gcc bug that resuted in an OOPs +when loading the control method battery driver. + + ---------------------------------------- +Summary of changes for this label: 09_20_01 + + ACPI CA Core Subsystem: + +The AcpiEnableEvent and AcpiDisableEvent interfaces have been +modified to allow individual GPE levels to be flagged as wake- +enabled (i.e., these GPEs are to remain enabled when the platform +sleeps.) + +The AcpiEnterSleepState and AcpiLeaveSleepState interfaces now +support wake-enabled GPEs. This means that upon entering the +sleep state, all GPEs that are not wake-enabled are disabled. +When leaving the sleep state, these GPEs are reenabled. + +A local double-precision divide/modulo module has been added to +enhance portability to OS kernels where a 64-bit math library is +not available. The new module is "utmath.c". + +Several optimizations have been made to reduce the use of CPU +stack. Originally over 2K, the maximum stack usage is now below +2K at 1860 bytes (1.82k) + +Fixed a problem with the AcpiGetFirmwareTable interface where the +root table pointer was not mapped into a logical address properly. + +Fixed a problem where a NULL pointer was being dereferenced in the +interpreter code for the ASL Notify operator. + +Fixed a problem where the use of the ASL Revision operator +returned an error. This operator now returns the current version +of the ACPI CA core subsystem. + +Fixed a problem where objects passed as control method parameters +to AcpiEvaluateObject were always deleted at method termination. +However, these objects may end up being stored into the namespace +by the called method. The object reference count mechanism was +applied to these objects instead of a force delete. + +Fixed a problem where static strings or buffers (contained in the +AML code) that are declared as package elements within the ASL +code could cause a fault because the interpreter would attempt to +delete them. These objects are now marked with the "static +object" flag to prevent any attempt to delete them. + +Implemented an interpreter optimization to use operands directly +from the state object instead of extracting the operands to local +variables. This reduces stack use and code size, and improves +performance. + +The module exxface.c was eliminated as it was an unnecessary extra +layer of code. + +Current core subsystem library code sizes are shown below. These +are the code and data sizes for the acpica.lib produced by the +Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code +includes the full debug trace mechanism -- leading to a much +larger code and data size. Note that these values will vary +depending on the efficiency of the compiler and the compiler +options used during generation. + + Non-Debug Version: 65K Code, 5K Data, 70K Total +(Previously 69K) Debug Version: 138K Code, 58K Data, 196K +Total (Previously 195K) + +Linux: + +Support for ACPI 2.0 64-bit integers has been added. All ACPI +Integer objects are now 64 bits wide + +All Acpi data types and structures are now in lower case. Only +Acpi macros are upper case for differentiation. + + Documentation: + +Changes to the external interfaces as described above. + + ---------------------------------------- +Summary of changes for this label: 08_31_01 + + ACPI CA Core Subsystem: + +A bug with interpreter implementation of the ASL Divide operator +was found and fixed. The implicit function return value (not the +explicit store operands) was returning the remainder instead of +the quotient. This was a longstanding bug and it fixes several +known outstanding issues on various platforms. + +The ACPI_DEBUG_PRINT and function trace entry/exit macros have +been further optimized for size. There are 700 invocations of the +DEBUG_PRINT macro alone, so each optimization reduces the size of +the debug version of the subsystem significantly. + +A stack trace mechanism has been implemented. The maximum stack +usage is about 2K on 32-bit platforms. The debugger command "stat +stack" will display the current maximum stack usage. + +All public symbols and global variables within the subsystem are +now prefixed with the string "Acpi". This keeps all of the +symbols grouped together in a kernel map, and avoids conflicts +with other kernel subsystems. + +Most of the internal fixed lookup tables have been moved into the +code segment via the const operator. + +Several enhancements have been made to the interpreter to both +reduce the code size and improve performance. + +Current core subsystem library code sizes are shown below. These +are the code and data sizes for the acpica.lib produced by the +Microsoft Visual C++ 6.0 compiler, and these values do not include +any ACPI driver or OSPM code. The debug version of the code +includes the full debug trace mechanism which contains over 700 +invocations of the DEBUG_PRINT macro, 500 function entry macro +invocations, and over 900 function exit macro invocations -- +leading to a much larger code and data size. Note that these +values will vary depending on the efficiency of the compiler and +the compiler options used during generation. + + Non-Debug Version: 64K Code, 5K Data, 69K Total +Debug Version: 137K Code, 58K Data, 195K Total + + Linux: + +Implemented wbinvd() macro, pending a kernel-wide definition. + +Fixed /proc/acpi/event to handle poll() and short reads. + + ASL Compiler, version X2026: + +Fixed a problem introduced in the previous label where the AML + +code emitted for package objects produced packages with zero +length. + + ---------------------------------------- +Summary of changes for this label: 08_16_01 + +ACPI CA Core Subsystem: + +The following ACPI 2.0 ASL operators have been implemented in the +AML interpreter (These are already supported by the Intel ASL +compiler): ToDecimalString, ToHexString, ToString, ToInteger, and +ToBuffer. Support for 64-bit AML constants is implemented in the +AML parser, debugger, and disassembler. + +The internal memory tracking mechanism (leak detection code) has +been upgraded to reduce the memory overhead (a separate tracking +block is no longer allocated for each memory allocation), and now +supports all of the internal object caches. + +The data structures and code for the internal object caches have +been coelesced and optimized so that there is a single cache and +memory list data structure and a single group of functions that +implement generic cache management. This has reduced the code +size in both the debug and release versions of the subsystem. + +The DEBUG_PRINT macro(s) have been optimized for size and replaced +by ACPI_DEBUG_PRINT. The syntax for this macro is slightly +different, because it generates a single call to an internal +function. This results in a savings of about 90 bytes per +invocation, resulting in an overall code and data savings of about +16% in the debug version of the subsystem. + + Linux: + +Fixed C3 disk corruption problems and re-enabled C3 on supporting +machines. + +Integrated low-level sleep code by Patrick Mochel. + +Further tweaked source code Linuxization. + +Other minor fixes. + + ASL Compiler: + +Support for ACPI 2.0 variable length packages is fixed/completed. + +Fixed a problem where the optional length parameter for the ACPI +2.0 ToString operator. + +Fixed multiple extraneous error messages when a syntax error is +detected within the declaration line of a control method. + + ---------------------------------------- +Summary of changes for this label: 07_17_01 + +ACPI CA Core Subsystem: + +Added a new interface named AcpiGetFirmwareTable to obtain any +ACPI table via the ACPI signature. The interface can be called at +any time during kernel initialization, even before the kernel +virtual memory manager is initialized and paging is enabled. This +allows kernel subsystems to obtain ACPI tables very early, even +before the ACPI CA subsystem is initialized. + +Fixed a problem where Fields defined with the AnyAcc attribute +could be resolved to the incorrect address under the following +conditions: 1) the field width is larger than 8 bits and 2) the +parent operation region is not defined on a DWORD boundary. + +Fixed a problem where the interpreter is not being locked during +namespace initialization (during execution of the _INI control +methods), causing an error when an attempt is made to release it +later. + +ACPI 2.0 support in the AML Interpreter has begun and will be +ongoing throughout the rest of this year. In this label, The Mod +operator is implemented. + +Added a new data type to contain full PCI addresses named +ACPI_PCI_ID. This structure contains the PCI Segment, Bus, Device, +and Function values. + + Linux: + +Enhanced the Linux version of the source code to change most +capitalized ACPI type names to lowercase. For example, all +instances of ACPI_STATUS are changed to acpi_status. This will +result in a large diff, but the change is strictly cosmetic and +aligns the CA code closer to the Linux coding standard. + +OSL Interfaces: + +The interfaces to the PCI configuration space have been changed to +add the PCI Segment number and to split the single 32-bit combined +DeviceFunction field into two 16-bit fields. This was +accomplished by moving the four values that define an address in +PCI configuration space (segment, bus, device, and function) to +the new ACPI_PCI_ID structure. + +The changes to the PCI configuration space interfaces led to a +reexamination of the complete set of address space access +interfaces for PCI, I/O, and Memory. The previously existing 18 +interfaces have proven difficult to maintain (any small change +must be propagated across at least 6 interfaces) and do not easily +allow for future expansion to 64 bits if necessary. Also, on some +systems, it would not be appropriate to demultiplex the access +width (8, 16, 32,or 64) before calling the OSL if the +corresponding native OS interfaces contain a similar access width +parameter. For these reasons, the 18 address space interfaces +have been replaced by these 6 new ones: + +AcpiOsReadPciConfiguration +AcpiOsWritePciConfiguration +AcpiOsReadMemory +AcpiOsWriteMemory +AcpiOsReadPort +AcpiOsWritePort + +Added a new interface named AcpiOsGetRootPointer to allow the OSL +to perform the platform and/or OS-specific actions necessary to +obtain the ACPI RSDP table pointer. On IA-32 platforms, this +interface will simply call down to the CA core to perform the low- +memory search for the table. On IA-64, the RSDP is obtained from +EFI. Migrating this interface to the OSL allows the CA core to + +remain OS and platform independent. + +Added a new interface named AcpiOsSignal to provide a generic +"function code and pointer" interface for various miscellaneous +signals and notifications that must be made to the host OS. The +first such signals are intended to support the ASL Fatal and +Breakpoint operators. In the latter case, the AcpiOsBreakpoint +interface has been obsoleted. + +The definition of the AcpiFormatException interface has been +changed to simplify its use. The caller no longer must supply a +buffer to the call; A pointer to a const string is now returned +directly. This allows the call to be easily used in printf +statements, etc. since the caller does not have to manage a local +buffer. + + + ASL Compiler, Version X2025: + +The ACPI 2.0 Switch/Case/Default operators have been implemented +and are fully functional. They will work with all ACPI 1.0 +interpreters, since the operators are simply translated to If/Else +pairs. + +The ACPI 2.0 ElseIf operator is implemented and will also work +with 1.0 interpreters, for the same reason. + +Implemented support for ACPI 2.0 variable-length packages. These +packages have a separate opcode, and their size is determined by +the interpreter at run-time. + +Documentation The ACPI CA Programmer Reference has been updated to +reflect the new interfaces and changes to existing interfaces. + + ------------------------------------------ +Summary of changes for this label: 06_15_01 + + ACPI CA Core Subsystem: + +Fixed a problem where a DWORD-accessed field within a Buffer +object would get its byte address inadvertently rounded down to +the nearest DWORD. Buffers are always Byte-accessible. + + ASL Compiler, version X2024: + +Fixed a problem where the Switch() operator would either fault or +hang the compiler. Note however, that the AML code for this ACPI +2.0 operator is not yet implemented. + +Compiler uses the new AcpiOsGetTimer interface to obtain compile +timings. + +Implementation of the CreateField operator automatically converts +a reference to a named field within a resource descriptor from a +byte offset to a bit offset if required. + +Added some missing named fields from the resource descriptor +support. These are the names that are automatically created by the +compiler to reference fields within a descriptor. They are only +valid at compile time and are not passed through to the AML +interpreter. + +Resource descriptor named fields are now typed as Integers and +subject to compile-time typechecking when used in expressions. + + ------------------------------------------ +Summary of changes for this label: 05_18_01 + + ACPI CA Core Subsystem: + +Fixed a couple of problems in the Field support code where bits +from adjacent fields could be returned along with the proper field +bits. Restructured the field support code to improve performance, +readability and maintainability. + +New DEBUG_PRINTP macro automatically inserts the procedure name +into the output, saving hundreds of copies of procedure name +strings within the source, shrinking the memory footprint of the +debug version of the core subsystem. + + Source Code Structure: + +The source code directory tree was restructured to reflect the +current organization of the component architecture. Some files +and directories have been moved and/or renamed. + + Linux: + +Fixed leaking kacpidpc processes. + +Fixed queueing event data even when /proc/acpi/event is not +opened. + + ASL Compiler, version X2020: + +Memory allocation performance enhancement - over 24X compile time +improvement on large ASL files. Parse nodes and namestring +buffers are now allocated from a large internal compiler buffer. + +The temporary .SRC file is deleted unless the "-s" option is +specified + +The "-d" debug output option now sends all output to the .DBG file +instead of the console. + +"External" second parameter is now optional + +"ElseIf" syntax now properly allows the predicate + +Last operand to "Load" now recognized as a Target operand + +Debug object can now be used anywhere as a normal object. + +ResourceTemplate now returns an object of type BUFFER + +EISAID now returns an object of type INTEGER + +"Index" now works with a STRING operand + +"LoadTable" now accepts optional parameters + +"ToString" length parameter is now optional + +"Interrupt (ResourceType," parse error fixed. + +"Register" with a user-defined region space parse error fixed + +Escaped backslash at the end of a string ("\\") scan/parse error +fixed + +"Revision" is now an object of type INTEGER. + + + +------------------------------------------ +Summary of changes for this label: 05_02_01 + +Linux: + +/proc/acpi/event now blocks properly. + +Removed /proc/sys/acpi. You can still dump your DSDT from +/proc/acpi/dsdt. + + ACPI CA Core Subsystem: + +Fixed a problem introduced in the previous label where some of the +"small" resource descriptor types were not recognized. + +Improved error messages for the case where an ASL Field is outside +the range of the parent operation region. + + ASL Compiler, version X2018: + + +Added error detection for ASL Fields that extend beyond the length +of the parent operation region (only if the length of the region +is known at compile time.) This includes fields that have a +minimum access width that is smaller than the parent region, and +individual field units that are partially or entirely beyond the +extent of the parent. + + + +------------------------------------------ +Summary of changes for this label: 04_27_01 + + ACPI CA Core Subsystem: + +Fixed a problem where the namespace mutex could be released at the +wrong time during execution of AcpiRemoveAddressSpaceHandler. + +Added optional thread ID output for debug traces, to simplify +debugging of multiple threads. Added context switch notification +when the debug code realizes that a different thread is now +executing ACPI code. + +Some additional external data types have been prefixed with the +string "ACPI_" for consistency. This may effect existing code. +The data types affected are the external callback typedefs - e.g., + +WALK_CALLBACK becomes ACPI_WALK_CALLBACK. + + Linux: + +Fixed an issue with the OSL semaphore implementation where a +thread was waking up with an error from receiving a SIGCHLD +signal. + +Linux version of ACPI CA now uses the system C library for string +manipulation routines instead of a local implementation. + +Cleaned up comments and removed TBDs. + + ASL Compiler, version X2017: + +Enhanced error detection and reporting for all file I/O +operations. + + Documentation: + +Programmer Reference updated to version 1.06. + + + +------------------------------------------ +Summary of changes for this label: 04_13_01 + + ACPI CA Core Subsystem: + +Restructured support for BufferFields and RegionFields. +BankFields support is now fully operational. All known 32-bit +limitations on field sizes have been removed. Both BufferFields +and (Operation) RegionFields are now supported by the same field +management code. + +Resource support now supports QWORD address and IO resources. The +16/32/64 bit address structures and the Extended IRQ structure +have been changed to properly handle Source Resource strings. + +A ThreadId of -1 is now used to indicate a "mutex not acquired" +condition internally and must never be returned by AcpiOsThreadId. +This reserved value was changed from 0 since Unix systems allow a +thread ID of 0. + +Linux: + +Driver code reorganized to enhance portability + +Added a kernel configuration option to control ACPI_DEBUG + +Fixed the EC driver to honor _GLK. + +ASL Compiler, version X2016: + +Fixed support for the "FixedHw" keyword. Previously, the FixedHw +address space was set to 0, not 0x7f as it should be. + + ------------------------------------------ +Summary of changes for this label: 03_13_01 + + ACPI CA Core Subsystem: + +During ACPI initialization, the _SB_._INI method is now run if +present. + +Notify handler fix - notifies are deferred until the parent method +completes execution. This fixes the "mutex already acquired" +issue seen occasionally. + +Part of the "implicit conversion" rules in ACPI 2.0 have been +found to cause compatibility problems with existing ASL/AML. The +convert "result-to-target-type" implementation has been removed +for stores to method Args and Locals. Source operand conversion +is still fully implemented. Possible changes to ACPI 2.0 +specification pending. + +Fix to AcpiRsCalculatePciRoutingTableLength to return correct +length. + +Fix for compiler warnings for 64-bit compiles. + + Linux: + +/proc output aligned for easier parsing. + +Release-version compile problem fixed. + +New kernel configuration options documented in Configure.help. + +IBM 600E - Fixed Sleep button may generate "Invalid +context" message. + + OSPM: + +Power resource driver integrated with bus manager. + +Fixed kernel fault during active cooling for thermal zones. + +Source Code: + +The source code tree has been restructured. + + + +------------------------------------------ +Summary of changes for this label: 03_02_01 + + Linux OS Services Layer (OSL): + +Major revision of all Linux-specific code. + +Modularized all ACPI-specific drivers. + +Added new thermal zone and power resource drivers. + +Revamped /proc interface (new functionality is under /proc/acpi). + +New kernel configuration options. + + Linux known issues: + +New kernel configuration options not documented in Configure.help +yet. + + +Module dependencies not currently implemented. If used, they +should be loaded in this order: busmgr, power, ec, system, +processor, battery, ac_adapter, button, thermal. + +Modules will not load if CONFIG_MODVERSION is set. + +IBM 600E - entering S5 may reboot instead of shutting down. + +IBM 600E - Sleep button may generate "Invalid context" +message. + +Some systems may fail with "execution mutex already acquired" +message. + + ACPI CA Core Subsystem: + +Added a new OSL Interface, AcpiOsGetThreadId. This was required +for the deadlock detection code. Defined to return a non-zero, 32- +bit thread ID for the currently executing thread. May be a non- +zero constant integer on single-thread systems. + +Implemented deadlock detection for internal subsystem mutexes. We +may add conditional compilation for this code (debug only) later. + +ASL/AML Mutex object semantics are now fully supported. This +includes multiple acquires/releases by owner and support for the + +Mutex SyncLevel parameter. + +A new "Force Release" mechanism automatically frees all ASL +Mutexes that have been acquired but not released when a thread +exits the interpreter. This forces conformance to the ACPI spec +("All mutexes must be released when an invocation exits") and +prevents deadlocked ASL threads. This mechanism can be expanded +(later) to monitor other resource acquisitions if OEM ASL code +continues to misbehave (which it will). + +Several new ACPI exception codes have been added for the Mutex +support. + +Recursive method calls are now allowed and supported (the ACPI +spec does in fact allow recursive method calls.) The number of +recursive calls is subject to the restrictions imposed by the +SERIALIZED method keyword and SyncLevel (ACPI 2.0) method +parameter. + +Implemented support for the SyncLevel parameter for control +methods (ACPI 2.0 feature) + +Fixed a deadlock problem when multiple threads attempted to use +the interpreter. + +Fixed a problem where the string length of a String package +element was not always set in a package returned from +AcpiEvaluateObject. + +Fixed a problem where the length of a String package element was +not always included in the length of the overall package returned +from AcpiEvaluateObject. + +Added external interfaces (Acpi*) to the ACPI debug memory +manager. This manager keeps a list of all outstanding +allocations, and can therefore detect memory leaks and attempts to +free memory blocks more than once. Useful for code such as the +power manager, etc. May not be appropriate for device drivers. +Performance with the debug code enabled is slow. + +The ACPI Global Lock is now an optional hardware element. + + ASL Compiler Version X2015: + +Integrated changes to allow the compiler to be generated on +multiple platforms. + +Linux makefile added to generate the compiler on Linux + + Source Code: + +All platform-specific headers have been moved to their own +subdirectory, Include/Platform. + +New source file added, Interpreter/ammutex.c + +New header file, Include/acstruct.h + + Documentation: + +The programmer reference has been updated for the following new +interfaces: AcpiOsGetThreadId AcpiAllocate AcpiCallocate AcpiFree + + ------------------------------------------ +Summary of changes for this label: 02_08_01 + +Core ACPI CA Subsystem: Fixed a problem where an error was +incorrectly returned if the return resource buffer was larger than +the actual data (in the resource interfaces). + +References to named objects within packages are resolved to the + +full pathname string before packages are returned directly (via +the AcpiEvaluateObject interface) or indirectly via the resource +interfaces. + +Linux OS Services Layer (OSL): + +Improved /proc battery interface. + + +Added C-state debugging output and other miscellaneous fixes. + +ASL Compiler Version X2014: + +All defined method arguments can now be used as local variables, +including the ones that are not actually passed in as parameters. +The compiler tracks initialization of the arguments and issues an +exception if they are used without prior assignment (just like +locals). + +The -o option now specifies a filename prefix that is used for all +output files, including the AML output file. Otherwise, the +default behavior is as follows: 1) the AML goes to the file +specified in the DSDT. 2) all other output files use the input +source filename as the base. + + ------------------------------------------ +Summary of changes for this label: 01_25_01 + +Core ACPI CA Subsystem: Restructured the implementation of object +store support within the interpreter. This includes support for +the Store operator as well as any ASL operators that include a +target operand. + +Partially implemented support for Implicit Result-to-Target +conversion. This is when a result object is converted on the fly +to the type of an existing target object. Completion of this +support is pending further analysis of the ACPI specification +concerning this matter. + +CPU-specific code has been removed from the subsystem (hardware +directory). + +New Power Management Timer functions added + +Linux OS Services Layer (OSL): Moved system state transition code +to the core, fixed it, and modified Linux OSL accordingly. + +Fixed C2 and C3 latency calculations. + + +We no longer use the compilation date for the version message on +initialization, but retrieve the version from AcpiGetSystemInfo(). + +Incorporated for fix Sony VAIO machines. + +Documentation: The Programmer Reference has been updated and +reformatted. + + +ASL Compiler: Version X2013: Fixed a problem where the line +numbering and error reporting could get out of sync in the +presence of multiple include files. + + ------------------------------------------ +Summary of changes for this label: 01_15_01 + +Core ACPI CA Subsystem: + +Implemented support for type conversions in the execution of the +ASL Concatenate operator (The second operand is converted to +match the type of the first operand before concatenation.) + +Support for implicit source operand conversion is partially +implemented. The ASL source operand types Integer, Buffer, and +String are freely interchangeable for most ASL operators and are +converted by the interpreter on the fly as required. Implicit +Target operand conversion (where the result is converted to the +target type before storing) is not yet implemented. + +Support for 32-bit and 64-bit BCD integers is implemented. + +Problem fixed where a field read on an aligned field could cause a +read past the end of the field. + +New exception, AE_AML_NO_RETURN_VALUE, is returned when a method +does not return a value, but the caller expects one. (The ASL +compiler flags this as a warning.) + +ASL Compiler: + +Version X2011: +1. Static typechecking of all operands is implemented. This +prevents the use of invalid objects (such as using a Package where +an Integer is required) at compile time instead of at interpreter +run-time. +2. The ASL source line is printed with ALL errors and warnings. +3. Bug fix for source EOF without final linefeed. +4. Debug option is split into a parse trace and a namespace trace. +5. Namespace output option (-n) includes initial values for +integers and strings. +6. Parse-only option added for quick syntax checking. +7. Compiler checks for duplicate ACPI name declarations + +Version X2012: +1. Relaxed typechecking to allow interchangeability between +strings, integers, and buffers. These types are now converted by +the interpreter at runtime. +2. Compiler reports time taken by each internal subsystem in the +debug output file. + + + ------------------------------------------ +Summary of changes for this label: 12_14_00 + +ASL Compiler: + +This is the first official release of the compiler. Since the +compiler requires elements of the Core Subsystem, this label +synchronizes everything. + +------------------------------------------ +Summary of changes for this label: 12_08_00 + + +Fixed a problem where named references within the ASL definition +of both OperationRegions and CreateXXXFields did not work +properly. The symptom was an AE_AML_OPERAND_TYPE during +initialization of the region/field. This is similar (but not +related internally) to the problem that was fixed in the last +label. + +Implemented both 32-bit and 64-bit support for the BCD ASL +functions ToBCD and FromBCD. + +Updated all legal headers to include "2000" in the copyright +years. + + ------------------------------------------ +Summary of changes for this label: 12_01_00 + +Fixed a problem where method invocations within the ASL definition +of both OperationRegions and CreateXXXFields did not work +properly. The symptom was an AE_AML_OPERAND_TYPE during +initialization of the region/field: + + nsinit-0209: AE_AML_OPERAND_TYPE while getting region arguments +[DEBG] ammonad-0284: Exec_monadic2_r/Not: bad operand(s) +(0x3005) + +Fixed a problem where operators with more than one nested +subexpression would fail. The symptoms were varied, by mostly +AE_AML_OPERAND_TYPE errors. This was actually a rather serious +problem that has gone unnoticed until now. + + Subtract (Add (1,2), Multiply (3,4)) + +Fixed a problem where AcpiGetHandle didn't quite get fixed in the +previous build (The prefix part of a relative path was handled +incorrectly). + +Fixed a problem where Operation Region initialization failed if +the operation region name was a "namepath" instead of a simple +"nameseg". Symptom was an AE_NO_OPERAND error. + +Fixed a problem where an assignment to a local variable via the +indirect RefOf mechanism only worked for the first such +assignment. Subsequent assignments were ignored. + + ------------------------------------------ +Summary of changes for this label: 11_15_00 + +ACPI 2.0 table support with backwards support for ACPI 1.0 and the +0.71 extensions. Note: although we can read ACPI 2.0 BIOS tables, +the AML interpreter does NOT have support for the new 2.0 ASL +grammar terms at this time. + +All ACPI hardware access is via the GAS structures in the ACPI 2.0 +FADT. + +All physical memory addresses across all platforms are now 64 bits +wide. Logical address width remains dependent on the platform +(i.e., "void *"). + +AcpiOsMapMemory interface changed to a 64-bit physical address. + +The AML interpreter integer size is now 64 bits, as per the ACPI +2.0 specification. + +For backwards compatibility with ACPI 1.0, ACPI tables with a +revision number less than 2 use 32-bit integers only. + +Fixed a problem where the evaluation of OpRegion operands did not +always resolve them to numbers properly. + +------------------------------------------ +Summary of changes for this label: 10_20_00 + +Fix for CBN_._STA issue. This fix will allow correct access to +CBN_ OpRegions when the _STA returns 0x8. + +Support to convert ACPI constants (Ones, Zeros, One) to actual +values before a package object is returned + +Fix for method call as predicate to if/while construct causing +incorrect if/while behavior + +Fix for Else block package lengths sometimes calculated wrong (if +block > 63 bytes) + +Fix for Processor object length field, was always zero + +Table load abort if FACP sanity check fails + +Fix for problem with Scope(name) if name already exists + +Warning emitted if a named object referenced cannot be found +(resolved) during method execution. + + + + + +------------------------------------------ +Summary of changes for this label: 9_29_00 + +New table initialization interfaces: AcpiInitializeSubsystem no +longer has any parameters AcpiFindRootPointer - Find the RSDP (if +necessary) AcpiLoadTables (RSDP) - load all tables found at RSDP- +>RSDT Obsolete Interfaces AcpiLoadFirmwareTables - replaced by +AcpiLoadTables + +Note: These interface changes require changes to all existing OSDs + +The PCI_Config default address space handler is always installed +at the root namespace object. + +------------------------------------------- +Summary of changes for this label: 09_15_00 + +The new initialization architecture is implemented. New +interfaces are: AcpiInitializeSubsystem (replaces AcpiInitialize) +AcpiEnableSubsystem Obsolete Interfaces: AcpiLoadNamespace + +(Namespace is automatically loaded when a table is loaded) + +The ACPI_OPERAND_OBJECT has been optimized to shrink its size from +52 bytes to 32 bytes. There is usually one of these for every +namespace object, so the memory savings is significant. + +Implemented just-in-time evaluation of the CreateField operators. + +Bug fixes for IA-64 support have been integrated. + +Additional code review comments have been implemented + +The so-called "third pass parse" has been replaced by a final walk +through the namespace to initialize all operation regions (address +spaces) and fields that have not yet been initialized during the +execution of the various _INI and REG methods. + +New file - namespace/nsinit.c + +------------------------------------------- +Summary of changes for this label: 09_01_00 + +Namespace manager data structures have been reworked to change the +primary object from a table to a single object. This has +resulted in dynamic memory savings of 3X within the namespace and +2X overall in the ACPI CA subsystem. + +Fixed problem where the call to AcpiEvFindPciRootBuses was +inadvertently left commented out. + +Reduced the warning count when generating the source with the GCC +compiler. + +Revision numbers added to each module header showing the +SourceSafe version of the file. Please refer to this version +number when giving us feedback or comments on individual modules. + +The main object types within the subsystem have been renamed to +clarify their purpose: + +ACPI_INTERNAL_OBJECT -> ACPI_OPERAND_OBJECT +ACPI_GENERIC_OP -> ACPI_PARSE_OBJECT +ACPI_NAME_TABLE_ENTRY -> ACPI_NAMESPACE_NODE + +NOTE: no changes to the initialization sequence are included in +this label. + +------------------------------------------- +Summary of changes for this label: 08_23_00 + +Fixed problem where TerminateControlMethod was being called +multiple times per method + +Fixed debugger problem where single stepping caused a semaphore to +be oversignalled + +Improved performance through additional parse object caching - +added ACPI_EXTENDED_OP type + +------------------------------------------- +Summary of changes for this label: 08_10_00 + +Parser/Interpreter integration: Eliminated the creation of +complete parse trees for ACPI tables and control methods. +Instead, parse subtrees are created and then deleted as soon as +they are processed (Either entered into the namespace or executed +by the interpreter). This reduces the use of dynamic kernel +memory significantly. (about 10X) + +Exception codes broken into classes and renumbered. Be sure to +recompile all code that includes acexcep.h. Hopefully we won't +have to renumber the codes again now that they are split into +classes (environment, programmer, AML code, ACPI table, and +internal). + +Fixed some additional alignment issues in the Resource Manager +subcomponent + +Implemented semaphore tracking in the AcpiExec utility, and fixed +several places where mutexes/semaphores were being unlocked +without a corresponding lock operation. There are no known +semaphore or mutex "leaks" at this time. + +Fixed the case where an ASL Return operator is used to return an +unnamed package. + +------------------------------------------- +Summary of changes for this label: 07_28_00 + +Fixed a problem with the way addresses were calculated in +AcpiAmlReadFieldData() and AcpiAmlWriteFieldData(). This problem +manifested itself when a Field was created with WordAccess or +DwordAccess, but the field unit defined within the Field was less + +than a Word or Dword. + +Fixed a problem in AmlDumpOperands() module's loop to pull +operands off of the operand stack to display information. The +problem manifested itself as a TLB error on 64-bit systems when +accessing an operand stack with two or more operands. + +Fixed a problem with the PCI configuration space handlers where +context was getting confused between accesses. This required a +change to the generic address space handler and address space +setup definitions. Handlers now get both a global handler context +(this is the one passed in by the user when executing +AcpiInstallAddressSpaceHandler() and a specific region context +that is unique to each region (For example, the _ADR, _SEG and +_BBN values associated with a specific region). The generic +function definitions have changed to the following: + +typedef ACPI_STATUS (*ADDRESS_SPACE_HANDLER) ( UINT32 Function, +UINT32 Address, UINT32 BitWidth, UINT32 *Value, void +*HandlerContext, // This used to be void *Context void +*RegionContext); // This is an additional parameter + +typedef ACPI_STATUS (*ADDRESS_SPACE_SETUP) ( ACPI_HANDLE +RegionHandle, UINT32 Function, void *HandlerContext, void +**RegionContext); // This used to be **ReturnContext + +------------------------------------------- +Summary of changes for this label: 07_21_00 + +Major file consolidation and rename. All files within the +interpreter have been renamed as well as most header files. This +was done to prevent collisions with existing files in the host +OSs -- filenames such as "config.h" and "global.h" seem to be +quite common. The VC project files have been updated. All +makefiles will require modification. + +The parser/interpreter integration continues in Phase 5 with the +implementation of a complete 2-pass parse (the AML is parsed +twice) for each table; This avoids the construction of a huge +parse tree and therefore reduces the amount of dynamic memory +required by the subsystem. Greater use of the parse object cache +means that performance is unaffected. + +Many comments from the two code reviews have been rolled in. + +The 64-bit alignment support is complete. + +------------------------------------------- +Summary of changes for this label: 06_30_00 + +With a nod and a tip of the hat to the technology of yesteryear, +we've added support in the source code for 80 column output +devices. The code is now mostly constrained to 80 columns or +less to support environments and editors that 1) cannot display +or print more than 80 characters on a single line, and 2) cannot +disable line wrapping. + +A major restructuring of the namespace data structure has been +completed. The result is 1) cleaner and more +understandable/maintainable code, and 2) a significant reduction +in the dynamic memory requirement for each named ACPI object +(almost half). + +------------------------------------------- +Summary of changes for this label: 06_23_00 + +Linux support has been added. In order to obtain approval to get +the ACPI CA subsystem into the Linux kernel, we've had to make +quite a few changes to the base subsystem that will affect all +users (all the changes are generic and OS- independent). The +effects of these global changes have been somewhat far reaching. +Files have been merged and/or renamed and interfaces have been +renamed. The major changes are described below. + +Osd* interfaces renamed to AcpiOs* to eliminate namespace +pollution/confusion within our target kernels. All OSD +interfaces must be modified to match the new naming convention. + +Files merged across the subsystem. A number of the smaller source +and header files have been merged to reduce the file count and +increase the density of the existing files. There are too many +to list here. In general, makefiles that call out individual +files will require rebuilding. + +Interpreter files renamed. All interpreter files now have the +prefix am* instead of ie* and is*. + +Header files renamed: The acapi.h file is now acpixf.h. The +acpiosd.h file is now acpiosxf.h. We are removing references to +the acronym "API" since it is somewhat windowsy. The new name is +"external interface" or xface or xf in the filenames.j + + +All manifest constants have been forced to upper case (some were +mixed case.) Also, the string "ACPI_" has been prepended to many +(not all) of the constants, typedefs, and structs. + +The globals "DebugLevel" and "DebugLayer" have been renamed +"AcpiDbgLevel" and "AcpiDbgLayer" respectively. + +All other globals within the subsystem are now prefixed with +"AcpiGbl_" Internal procedures within the subsystem are now +prefixed with "Acpi" (with only a few exceptions). The original +two-letter abbreviation for the subcomponent remains after "Acpi" +- for example, CmCallocate became AcpiCmCallocate. + +Added a source code translation/conversion utility. Used to +generate the Linux source code, it can be modified to generate +other types of source as well. Can also be used to cleanup +existing source by removing extraneous spaces and blank lines. +Found in tools/acpisrc/* + +OsdUnMapMemory was renamed to OsdUnmapMemory and then +AcpiOsUnmapMemory. (UnMap became Unmap). + +A "MaxUnits" parameter has been added to AcpiOsCreateSemaphore. +When set to one, this indicates that the caller wants to use the + +semaphore as a mutex, not a counting semaphore. ACPI CA uses +both types. However, implementers of this call may want to use +different OS primitives depending on the type of semaphore +requested. For example, some operating systems provide separate + +"mutex" and "semaphore" interfaces - where the mutex interface is +much faster because it doesn't have all the overhead of a full +semaphore implementation. + +Fixed a deadlock problem where a method that accesses the PCI +address space can block forever if it is the first access to the +space. + +------------------------------------------- +Summary of changes for this label: 06_02_00 + +Support for environments that cannot handle unaligned data +accesses (e.g. firmware and OS environments devoid of alignment +handler technology namely SAL/EFI and the IA-64 Linux kernel) has +been added (via configurable macros) in these three areas: - +Transfer of data from the raw AML byte stream is done via byte +moves instead of word/dword/qword moves. - External objects are +aligned within the user buffer, including package elements (sub- +objects). - Conversion of name strings to UINT32 Acpi Names is now +done byte-wise. + +The Store operator was modified to mimic Microsoft's +implementation when storing to a Buffer Field. + +Added a check of the BM_STS bit before entering C3. + +The methods subdirectory has been obsoleted and removed. A new +file, cmeval.c subsumes the functionality. + +A 16-bit (DOS) version of AcpiExec has been developed. The +makefile is under the acpiexec directory. diff --git a/third_party/lib/acpica/generate/lint/files.lnt b/third_party/lib/acpica/generate/lint/files.lnt new file mode 100644 index 000000000..ac0a36e79 --- /dev/null +++ b/third_party/lib/acpica/generate/lint/files.lnt @@ -0,0 +1,15 @@ +// +// Basic ACPICA components +// +..\..\source\components\debugger\*.c +..\..\source\components\disassembler\*.c +..\..\source\components\dispatcher\*.c +..\..\source\components\events\*.c +..\..\source\components\executer\*.c +..\..\source\components\hardware\*.c +..\..\source\components\namespace\*.c +..\..\source\components\parser\*.c +..\..\source\components\resources\*.c +..\..\source\components\tables\*.c +..\..\source\components\utilities\*.c + diff --git a/third_party/lib/acpica/generate/lint/lint.bat b/third_party/lib/acpica/generate/lint/lint.bat new file mode 100644 index 000000000..18fde838d --- /dev/null +++ b/third_party/lib/acpica/generate/lint/lint.bat @@ -0,0 +1,16 @@ +del LintOut.txt +echo Begin 64-bit lint >> LintOut.txt + +"C:\Program Files\Lint\Lint-nt" +v std64.lnt +os(LintOut.txt) files.lnt + +echo 64-bit lint completed >> LintOut.txt +echo -------------------------------------------- >> LintOut.txt +echo Begin 32-bit lint >> LintOut.txt + +"C:\Program Files\Lint\Lint-nt" +v std32.lnt +os(LintOut.txt) files.lnt + +echo 32-bit lint completed >> LintOut.txt +@echo off +echo --- +echo Output placed in LintOut.txt + diff --git a/third_party/lib/acpica/generate/lint/lset.bat b/third_party/lib/acpica/generate/lint/lset.bat new file mode 100644 index 000000000..9f7de30eb --- /dev/null +++ b/third_party/lib/acpica/generate/lint/lset.bat @@ -0,0 +1 @@ +set path=%PATH%;$G diff --git a/third_party/lib/acpica/generate/lint/options.lnt b/third_party/lib/acpica/generate/lint/options.lnt new file mode 100644 index 000000000..614b1dc0e --- /dev/null +++ b/third_party/lib/acpica/generate/lint/options.lnt @@ -0,0 +1,85 @@ +// Please note -- this is a representative set of error suppression +// options. Please adjust to suit your own policies +// See manual (chapter LIVING WITH LINT) +// for further details. + +-i"..\..\source\include" +-i"..\..\source\include\platform" + +/* Global options */ + +-A // ANSI C only ++fie // Enum is integer +-dACPI_USE_DO_WHILE_0 +-dACPI_DEBUG_OUTPUT +//-dACPI_APPLICATION +-dACPI_DEBUGGER +-dACPI_DISASSEMBLER +-dACPI_ENABLE_OBJECT_CACHE +-dACPI_DBG_TRACK_ALLOCATIONS +-dACPI_USE_LOCAL_CACHE +-dACPI_CACHE_T=ACPI_MEMORY_LIST +-d_LINT=1 + +-printf(4, AcpiUtDebugPrint, AcpiUtDebugPrintRaw) +-printf(1, AcpiOsPrintf, AcpiOsVprintf) + +/* Macro exceptions */ + +-emacro( (413), ACPI_OFFSET ) // use of NULL pointer creates a stir +-emacro( (413), ACPI_TO_INTEGER ) // use of NULL pointer creates a stir +-emacro( (413), ACPI_TO_POINTER ) // use of NULL pointer creates a stir +-emacro( (413), ACPI_ADD_PTR ) // use of NULL pointer creates a stir +-emacro( (413), ACPI_PTR_DIFF ) // use of NULL pointer creates a stir +-emacro( (413), ACPI_FADT_OFFSET ) // use of NULL pointer creates a stir +-emacro( (413), ASL_RESDESC_OFFSET ) // use of NULL pointer creates a stir +-emacro( (662), ACPI_ADD_PTR ) // allow pointer overrun for dynamic structs +-emacro( (797), ACPI_ADD_PTR ) // allow pointer overrun for dynamic structs + +-emacro( 826, ACPI_NEXT_RESOURCE) // Pointer cast +-emacro( 826, ACPI_MOVE_UNALIGNED16_TO_16) // Pointer cast +-emacro( 826, ACPI_MOVE_UNALIGNED16_TO_32) // Pointer cast +-emacro( 826, ACPI_MOVE_UNALIGNED32_TO_32) // Pointer cast +-emacro( 826, ACPI_MOVE_32_TO_32) // Pointer cast +-emacro( 950, ACPI_INTERNAL_VAR_XFACE) // Uses non-ANSI +-emacro( 950, ACPI_SYSTEM_XFACE) // Uses non-ANSI +-emacro( 826, ACPI_CAST_PTR) // Pointer cast +-emacro( 826, ACPI_ADD_PTR) // Pointer cast +-emacro( 826, ACPI_LODWORD) // Pointer cast +-emacro( 826, ACPI_HIDWORD) // Pointer cast + +/* Symbol exceptions */ + +-esym( 528, _AcpiModuleName) // Symbol not always used, but always present +-esym( 550, CurrentSp) // Used to track stack use +-esym( 789, CurrentSp) // Used to track stack use +-esym( 534, AcpiDmDumpName) // Return value not always used +-esym( 534, AcpiDmCommaIfListMember) // Return value not always used + +// Suppress warning about redefinition during lint of multiple modules +-esym(767,_COMPONENT) + + +/* Symbol exceptions for generation of iASL compiler */ + +-esym( 534, TrWalkParseTree) // Return value not always used +-esym( 534, AslCompilerparse) // Return value not always used +-esym( 534, OpcSetOptimalIntegerSize) // Return value not always used +-esym( 534, AslCompilererror) // Return value not always used + +/* Global exceptions */ + +-e716 // Allow while(1) +-e717 // Allow do..while(0) +-e801 // Allow judicious use of goto without incurring complaint +-e818 // Don't make suggestions about const to avoid "const" pollution +-e715 // Ignore non-referenced formal parameters +-e750 // Ignore non-referenced local macros (_MODULE_NAME, _COMPONENT, etc.) +-e834 // - followed by + is "confusing" NOT. +-e820 // Allow Boolean test of a parenthesized assignment +-e778 // Allow constant expressions to evaluate to zero +-e662 // Allow "pointer overrun" for dynamic structures +-e831 +-e784 // Allow "Nul character truncated from string" for lookup tables +-e661 // Allow access beyond "end of pointer" for ACPI tables declared with x[1] fields +-e796 // Allow access beyond "end of pointer" for namestrings diff --git a/third_party/lib/acpica/generate/lint/readme.txt b/third_party/lib/acpica/generate/lint/readme.txt new file mode 100644 index 000000000..3f427ad6b --- /dev/null +++ b/third_party/lib/acpica/generate/lint/readme.txt @@ -0,0 +1,14 @@ + +Lint files for PC-Lint (FlexLint) by Gimpel Software, Inc. + +These are the configuration and option files used to lint the +ACPI-CA software. + +lset.bat - adds lint directory to the command line search path +lint.bat - lint batch file for 32 and 64 bit lint +std16.lnt - 16-bit options +std32.lnt - 32-bit options +std64.lnt - 64-bit options +options.lnt - common options +others - windows/dos compiler option files + diff --git a/third_party/lib/acpica/generate/lint/std16.lnt b/third_party/lib/acpica/generate/lint/std16.lnt new file mode 100644 index 000000000..c3a116a6e --- /dev/null +++ b/third_party/lib/acpica/generate/lint/std16.lnt @@ -0,0 +1,16 @@ +// Microsoft C and Visual C++ 4.x, -mL -si2 -spN2 -spF4, lib-win.lnt +// Standard lint options + + +c:\acpi\generate\lint\co-msc40.lnt +//c:\acpi\generate\lint\lib-win.lnt + +-dMSDOS +-dACPI_MACHINE_WIDTH=16 +//-d_MSC_VER + +-e747 // Compiler supports parameter conversions + + +options.lnt -mL -si2 -spN2 -spF4 -sl4 + diff --git a/third_party/lib/acpica/generate/lint/std32.lnt b/third_party/lib/acpica/generate/lint/std32.lnt new file mode 100644 index 000000000..37e5c36be --- /dev/null +++ b/third_party/lib/acpica/generate/lint/std32.lnt @@ -0,0 +1,14 @@ +// Generic Compilers, -si4 -sp4 +// Standard lint options + +-dACPI_MACHINE_WIDTH=32 +-dWIN32=1 +-d_MSC_VER=1 ++fll // enable long long ++rw(__asm) // enable in-line assembly +-esym( 950, __asm) + // Used to track stack use +-si4 -sp4 + +co.lnt +options.lnt diff --git a/third_party/lib/acpica/generate/lint/std64.lnt b/third_party/lib/acpica/generate/lint/std64.lnt new file mode 100644 index 000000000..441c9756a --- /dev/null +++ b/third_party/lib/acpica/generate/lint/std64.lnt @@ -0,0 +1,18 @@ +// Generic Compilers, -si4 -sl4 -sp8 +// Standard lint options + +-dACPI_MACHINE_WIDTH=64 + +-e747 // Compiler supports parameter conversions +-e46 // Compiler supports bitfields other than int +-d_IA64 +-dWIN64 +-d_WIN64 +-d_MAC ++fll // enable long long + +-si4 -sl4 -sp8 -sll8 + +co.lnt +options.lnt + diff --git a/third_party/lib/acpica/generate/release/build.sh b/third_party/lib/acpica/generate/release/build.sh new file mode 100755 index 000000000..a30640868 --- /dev/null +++ b/third_party/lib/acpica/generate/release/build.sh @@ -0,0 +1,480 @@ +#!/bin/bash + +#****************************************************************************** +# +# ACPICA package generation script for Cygwin/Windows execution +# +# Requires cygwin be installed - http://www.cygwin.com +# and its /bin be *first* in your path. +# +# Windows packages require pkzip25 (free, and is available from numerous +# sources - search for "pkzip25" or "pkzip25.exe") +# +# Execute this script from the acpica/generate/release directory. +# +# Constructed packages are placed in the acpica/generate/release/current +# directory. +# +# Line Terminators: Windows source packages leave the CR/LF terminator. +# Unix packages convert the CR/LF terminators to LF only. +# +# Usage: +# +# build +# +# where: +# is one of: +# source - Build an ACPICA source package (core and all tools) +# test - Build an ACPICA test suite package +# binary - Build an ACPICA binary tools package +# +# is one of: +# win - Generate Windows package (Intel license, CRLF line terminators) +# unix - Generate Unix package (Intel license, LF line terminators) +# unix2 - Generate Unix package (dual license, LF line terminators) +# +#****************************************************************************** + +# Configuration + +ZIP_UTILITY="/cygdrive/c/windows/pkzip25.exe" +ACPISRC="libraries/acpisrc.exe" +DOS2UNIX="dos2unix" +UNIX2DOS="unix2dos" + +# Filenames and paths + +TARGET_DIR="generate/release/current" +TEMP_DIR=acpitemp +TEST_PREFIX=acpitests +SOURCE_PREFIX=acpica +BINARY_PREFIX=iasl +PACKAGE_SUFFIX=`date +%Y%m%d` + +NPARAM=$# + + +#****************************************************************************** +# +# Miscellaneous utility functions +# +#****************************************************************************** + +usage() +{ + echo "$1" + echo + echo "Low-level build script for ACPICA release packages" + echo "Usage:" + echo " $0 source " + echo " $0 test " + echo " $0 binary " +} + +banner() +{ + echo + echo "$1" + echo +} + +check_zip_utility_exists() +{ + # + # Need pkzip (or similar) to build the windows packages + # + if [ ! -e "$ZIP_UTILITY" ]; then + echo "ZIP_UTILITY ($ZIP_UTILITY) does not exist!" + exit 1 + fi +} + +convert_to_unix_line_terminators() +{ + # + # Convert all CR/LF pairs to Unix format (LF only) + # + cd $TEMP_DIR + echo "Starting CR/LF to LF (UNIX) full source conversion" + find . -name "*" | xargs $DOS2UNIX -q + echo "Completed CR/LF to LF (UNIX) full source conversion" + cd .. +} + +convert_to_dos_line_terminators() +{ + # + # Convert all lone LF terminators to CR/LF + # Note: Checks shell scripts only (*.sh) + # + cd $TEMP_DIR + echo "Starting LF to CR/LF (DOS) script conversion" + find . -name "*.sh" | xargs $UNIX2DOS -q + echo "Completed LF to CR/LF (DOS) script conversion" + cd .. +} + +insert_dual_license_headers() +{ + # + # Need acpisrc utility to insert the headers + # + if [ ! -e "$ACPISRC" ]; then + echo "acpisrc ($ACPISRC) does not exist!" + exit 1 + fi + + # + # Insert the dual license into *.c and *.h files + # + echo "Inserting dual-license into all source files" + $ACPISRC -h -y $TEMP_DIR +} + +build_unix_package() +{ + convert_to_unix_line_terminators + + # + # Build release package + # + rm -r -f $PACKAGE_FILENAME + mv $TEMP_DIR $PACKAGE_FILENAME + tar czf $PACKAGE_FILENAME.tar.gz $PACKAGE_FILENAME + + # + # Move the completed package + # + mv $PACKAGE_FILENAME.tar.gz $TARGET_DIR + mv $PACKAGE_FILENAME $TEMP_DIR +} + +build_windows_package() +{ + convert_to_dos_line_terminators + + # + # Build release package + # + cd $TEMP_DIR + rm -r -f ../$TARGET_DIR/$PACKAGE_FILENAME + $ZIP_UTILITY -silent -add -max -dir -sort=name ../$TARGET_DIR/$PACKAGE_FILENAME + cd .. +} + + +#****************************************************************************** +# +# generate_source_package +# +# Generates the ACPICA source code packages (core and all tools) +# +# Arguments: +# %1 - Target type (win or unix or unix2) +# +#****************************************************************************** + +generate_source_package () +{ + # + # Parameter evaluation + # + if [ $1 == win ]; then + PACKAGE_NAME=Windows + PACKAGE_TYPE=Win + LICENSE=Intel + check_zip_utility_exists + + elif [ $1 == unix ]; then + PACKAGE_NAME="Unix (Intel License)" + PACKAGE_TYPE=Unix + LICENSE=Intel + + elif [ $1 == unix2 ]; then + PACKAGE_NAME="Unix (Dual License)" + PACKAGE_TYPE=Unix + LICENSE=Dual + + else + usage "Invalid argument ($1)" + exit 1 + fi + + PACKAGE_FILENAME=$SOURCE_PREFIX-$1-$PACKAGE_SUFFIX + banner "ACPICA - Generating $PACKAGE_NAME source code package ($PACKAGE_FILENAME)" + + # + # Make directories common to all source packages + # + mkdir $TEMP_DIR + mkdir $TEMP_DIR/libraries + mkdir $TEMP_DIR/generate + mkdir $TEMP_DIR/generate/lint + mkdir $TEMP_DIR/generate/release + mkdir $TEMP_DIR/generate/unix + mkdir $TEMP_DIR/generate/unix/acpibin + mkdir $TEMP_DIR/generate/unix/acpidump + mkdir $TEMP_DIR/generate/unix/acpiexamples + mkdir $TEMP_DIR/generate/unix/acpiexec + mkdir $TEMP_DIR/generate/unix/acpihelp + mkdir $TEMP_DIR/generate/unix/acpinames + mkdir $TEMP_DIR/generate/unix/acpisrc + mkdir $TEMP_DIR/generate/unix/acpixtract + mkdir $TEMP_DIR/generate/unix/iasl + mkdir $TEMP_DIR/tests + mkdir $TEMP_DIR/tests/misc + mkdir $TEMP_DIR/tests/templates + mkdir -p $TEMP_DIR/source/os_specific/service_layers + + # + # Copy ACPICA subsystem source code + # + cp -r documents/changes.txt $TEMP_DIR/changes.txt + cp -r source/common $TEMP_DIR/source/common + cp -r source/components $TEMP_DIR/source/ + cp -r source/include $TEMP_DIR/source/include + cp -r generate/release/*.sh $TEMP_DIR/generate/release + + # + # Copy iASL compiler and tools source + # + cp -r source/compiler $TEMP_DIR/source/compiler + cp -r source/tools $TEMP_DIR/source/tools + + # + # Copy iASL/ACPICA miscellaneous tests (not full test suites) + # + cp -r tests/misc/*.asl $TEMP_DIR/tests/misc + cp -r tests/templates/Makefile $TEMP_DIR/tests/templates + cp -r tests/templates/templates.sh $TEMP_DIR/tests/templates + + # + # Copy all OS-specific interfaces + # + cp source/os_specific/service_layers/*.c $TEMP_DIR/source/os_specific/service_layers + + # + # Copy generic UNIX makefiles + # + cp Makefile $TEMP_DIR + cp generate/unix/readme.txt $TEMP_DIR/generate/unix/readme.txt + cp generate/unix/Makefile* $TEMP_DIR/generate/unix + cp generate/unix/acpibin/Makefile $TEMP_DIR/generate/unix/acpibin + cp generate/unix/acpidump/Makefile $TEMP_DIR/generate/unix/acpidump + cp generate/unix/acpiexamples/Makefile $TEMP_DIR/generate/unix/acpiexamples + cp generate/unix/acpiexec/Makefile $TEMP_DIR/generate/unix/acpiexec + cp generate/unix/acpihelp/Makefile $TEMP_DIR/generate/unix/acpihelp + cp generate/unix/acpinames/Makefile $TEMP_DIR/generate/unix/acpinames + cp generate/unix/acpisrc/Makefile $TEMP_DIR/generate/unix/acpisrc + cp generate/unix/acpixtract/Makefile $TEMP_DIR/generate/unix/acpixtract + cp generate/unix/iasl/Makefile $TEMP_DIR/generate/unix/iasl + + # + # Copy Lint directory + # + cp -r generate/lint $TEMP_DIR/generate + rm -f $TEMP_DIR/generate/lint/co* + rm -f $TEMP_DIR/generate/lint/env* + rm -f $TEMP_DIR/generate/lint/lib* + rm -f $TEMP_DIR/generate/lint/LintOut.txt + + if [ $PACKAGE_TYPE == Unix ]; then + # + # Unix/Linux-specific activities + # + # For Unix2 case, insert the dual license header into all source files + # + if [ $LICENSE == Dual ]; then + insert_dual_license_headers + fi + + build_unix_package + + else + # + # Windows-specific activities + # + + # Copy project files for MS Visual Studio 2008 (VC++ 9.0) + + mkdir $TEMP_DIR/generate/msvc9 + cp -r generate/msvc9/*.sln $TEMP_DIR/generate/msvc9/ + cp -r generate/msvc9/*.vcproj $TEMP_DIR/generate/msvc9/ + + build_windows_package + fi + + banner "ACPICA - Completed $PACKAGE_NAME source code package ($PACKAGE_FILENAME)" +} + + +#****************************************************************************** +# +# generate_test_package +# +# Generates the ACPICA test suite packages +# +# Arguments: +# %1 - Target type (win or unix) +# +#****************************************************************************** + +generate_test_package() +{ + # + # Parameter evaluation + # + if [ $1 == win ]; then + PACKAGE_NAME=Windows + PACKAGE_TYPE=Win + check_zip_utility_exists + + elif [ $1 == unix ]; then + PACKAGE_NAME="Unix" + PACKAGE_TYPE=Unix + + else + usage "Invalid argument ($1)" + exit 1 + fi + + PACKAGE_FILENAME=$TEST_PREFIX-$1-$PACKAGE_SUFFIX + banner "ACPICA - Generating $PACKAGE_NAME test suite package ($PACKAGE_FILENAME)" + + # + # Copy the ASL Test source + # + mkdir $TEMP_DIR + cp -r tests $TEMP_DIR/tests + + # + # Delete extraneous files + # + cd $TEMP_DIR + find . -name "tmp" | xargs rm -r -f + find . -name "aml" | xargs rm -r -f + find . -name "CVS" | xargs rm -r -f + cd .. + + if [ $PACKAGE_TYPE == Unix ]; then + # + # Unix/Linux-specific activities + # + build_unix_package + + else + # + # Windows-specific activities + # + build_windows_package + fi + + banner "ACPICA - Completed $PACKAGE_NAME test suite package ($PACKAGE_FILENAME)" +} + + +#****************************************************************************** +# +# generate_binary_package +# +# Generates the ACPICA binary package (Currently Windows only) +# +# Arguments: +# %1 - Target type (win) +# +#****************************************************************************** + +generate_binary_package() +{ + # + # Parameter evaluation + # + if [ $1 == win ]; then + PACKAGE_NAME=Windows + PACKAGE_TYPE=Win + check_zip_utility_exists + + else + usage "Invalid argument ($1)" + exit 1 + fi + + PACKAGE_FILENAME=$BINARY_PREFIX-$1-$PACKAGE_SUFFIX + banner "ACPICA - Generating $PACKAGE_NAME binary tools package ($PACKAGE_FILENAME)" + + # + # Copy executables and documentation + # + mkdir $TEMP_DIR + cp -r documents/changes.txt $TEMP_DIR/changes.txt + cp documents/aslcompiler.pdf $TEMP_DIR + cp libraries/acpibin.exe $TEMP_DIR + cp libraries/acpidump.exe $TEMP_DIR + cp libraries/acpiexec.exe $TEMP_DIR + cp libraries/acpihelp.exe $TEMP_DIR + cp libraries/acpinames.exe $TEMP_DIR + cp libraries/acpisrc.exe $TEMP_DIR + cp libraries/acpixtract.exe $TEMP_DIR + cp libraries/iasl.exe $TEMP_DIR + cp tests/misc/badcode.asl $TEMP_DIR + + build_windows_package + banner "ACPICA - Completed $PACKAGE_NAME binary tools package ($PACKAGE_FILENAME)" +} + + +#****************************************************************************** +# +# main +# +# Arguments: +# $1 (package_type) is one of: +# source - Build an ACPICA source package (core and all tools) +# test - Build an ACPICA test suite package +# binary - Build an ACPICA binary tools package +# +# $2 (target_type) is one of: +# win - Generate Windows package (Intel license, CRLF line terminators) +# unix - Generate Unix package (Intel license, LF line terminators) +# unix2 - Generate Unix package (dual license, LF line terminators) +# +#****************************************************************************** + +set -e # Abort on any error + +if [ $NPARAM -ne 2 ]; then + usage "Wrong argument count ($NPARAM)" + exit 1 +fi + +# +# cd from acpica/generate/release to acpica +# +cd ../.. + +# +# Ensure that the temporary directory is created fresh +# +rm -rf $TEMP_DIR + +# +# Parameter evaluation +# +if [ $1 == source ]; then + generate_source_package $2 + +elif [ $1 == test ]; then + generate_test_package $2 + +elif [ $1 == binary ]; then + generate_binary_package $2 + +else + usage "Invalid argument ($1)" + exit 1 +fi + +# +# Remove temporary directory +# +rm -rf $TEMP_DIR diff --git a/third_party/lib/acpica/generate/release/release.sh b/third_party/lib/acpica/generate/release/release.sh new file mode 100755 index 000000000..7bb9c3d49 --- /dev/null +++ b/third_party/lib/acpica/generate/release/release.sh @@ -0,0 +1,146 @@ +#!/bin/bash + +#****************************************************************************** +# +# ACPICA release generation script for Cygwin/Windows execution +# +# front end for build.sh +# +# Copies any existing packages to the archive directory. +# +# Generates 3 types of package: +# 1) Standard ACPICA source, everything except test suites +# 2) ACPICA test suites (very large) +# 3) Windows binary tools (Windows does not include generation tools) +# +# Note: "unix" generation builds the source with the standard Intel license +# in each file header. "unix2" builds the source with the dual license instead. +# this has been requested by some OS vendors, notably FreeBSD. +# +#****************************************************************************** + +# Configuration + +NPARAM=$# +BUILD_TESTS=1 + +# Filenames and paths + +ARCHIVE_DIR=archive +RELEASE_DIR=current + + +#****************************************************************************** +# +# Miscellaneous utility functions +# +#****************************************************************************** + +usage() +{ + echo "$1" + echo + echo "Master script to create ACPICA release packages" + echo "Usage:" + echo " $0 [notest]" +} + +move_all_files_to_archive() +{ + cd $RELEASE_DIR + + for file in * + do + if [ -d $file ]; then + rm -r -f ../$ARCHIVE_DIR/$file + mv -f $file ../$ARCHIVE_DIR + echo "Moved directory $file to $ARCHIVE_DIR directory" + else + cp $file ../$ARCHIVE_DIR + echo "Moved $file ($(ls -al $file | awk '{print $5}') bytes) to $ARCHIVE_DIR directory" + rm $file + fi + done + + cd .. +} + + +#****************************************************************************** +# +# main +# +# Arguments: +# $1 (optional) notest - do not generate the ACPICA test suite packages +# +#****************************************************************************** + +set -e # Abort on any error + +# +# Parameter evaluation +# +if [ $NPARAM -gt 1 ]; then + usage "Wrong argument count ($NPARAM)" + exit 1 + +elif [ $NPARAM -eq 1 ]; then + if [ $1 == notest ]; then + BUILD_TESTS=0 + else + usage "Invalid argument ($1)" + exit 1 + fi +fi + +# +# Move and preserve any previous versions of the various release packages +# +if [ -e $RELEASE_DIR ]; then + + # Create archive directory if necessary + + mkdir -p $ARCHIVE_DIR + + # + # Save any older versions of the release packages + # + if [ "$(ls -A $RELEASE_DIR)" ]; then + echo "Moving previous packages to $ARCHIVE_DIR directory" + + move_all_files_to_archive + echo "Completed move of previous packages to $ARCHIVE_DIR directory" + fi + +else + # Just create the release directory + mkdir -p $RELEASE_DIR +fi + +# ACPICA source code (core subsystem and all tools/utilities) + +bash build.sh source win +bash build.sh source unix +bash build.sh source unix2 + +# Optionally build the test suite packages (built by default) + +if [ $BUILD_TESTS -eq 1 ]; then + + # ACPICA test suites (A unix2 build has not been requested by users) + + bash build.sh test win + bash build.sh test unix + +else + echo "**** Test suites not built because the notest option was used" +fi + +# ACPICA binary tools (Windows only) + +bash build.sh binary win + +echo +echo "ACPICA - Summary of generated packages:" +echo +ls $RELEASE_DIR -g -G -t diff --git a/third_party/lib/acpica/generate/unix/Makefile b/third_party/lib/acpica/generate/unix/Makefile new file mode 100644 index 000000000..5b187d7d0 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/Makefile @@ -0,0 +1,16 @@ +# +# Common make for acpica tools and utilities +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under the generate/unix directory. +# It specifically places all the object files for each tool in separate +# generate/unix subdirectories, not within the various ACPICA source +# code directories. This prevents collisions between different +# compilations of the same source file with different compile options. +# +BUILD_DIRECTORY_PATH = "." + +include Makefile.config +include Makefile.common diff --git a/third_party/lib/acpica/generate/unix/Makefile.common b/third_party/lib/acpica/generate/unix/Makefile.common new file mode 100644 index 000000000..fe5e46bd3 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/Makefile.common @@ -0,0 +1,93 @@ +# +# Common make for acpica tools and utilities +# + +# +# Get the OS machine architecture. Anything with a "64" in the returned +# string will be treated as a 64-bit OS. Otherwise, the default is 32-bit. +# +ifeq ($(HOST), _FreeBSD) +HARDWARE_NAME := $(shell uname -p) +else +HARDWARE_NAME := $(shell uname -m) +endif + +# +# Main rule will only generate versions that are appropriate for the running +# OS, either 64-bit or 32-bit. +# +all: $(PROGS) +$(PROGS): FORCE + @cd $(BUILD_DIRECTORY_PATH)/$@; \ + mkdir -p obj; \ + $(MAKE) || exit "$$?"; \ + if [ $(findstring 64,$(HARDWARE_NAME)) ]; then \ + echo "64-bit version of $@:"; \ + else \ + echo "32-bit version of $@:"; \ + fi; \ + ls -al ../bin/$@; \ + echo ""; + +# +# Simple clean removes all .obj files, but leaves the executables +# in the local bin directory +# +clean: FORCE + @for toolname in $(PROGS); do \ + (cd $(BUILD_DIRECTORY_PATH)/$$toolname; \ + if [ -d "obj" ] ; then \ + echo "Removing $$toolname:"; \ + pwd; \ + $(MAKE) clean; \ + rmdir obj; \ + echo ""; \ + fi; \ + ); \ + done; + +# +# Very clean removes all executables and the local bin directory +# +veryclean: FORCE + @for toolname in $(PROGS); do \ + (cd $(BUILD_DIRECTORY_PATH)/$$toolname; \ + if [ -d "obj" ] ; then \ + echo "Removing $$toolname:"; \ + pwd; \ + $(MAKE) clean; \ + rmdir obj; \ + echo ""; \ + fi; \ + ); \ + if [ -e "$(BUILD_DIRECTORY_PATH)/bin/$$toolname" ] ; then \ + rm $(BUILD_DIRECTORY_PATH)/bin/$$toolname; \ + fi; \ + done; \ + if [ -d "bin" ] ; then \ + rmdir bin; \ + fi; + +# +# Install all tools, either 32-bit or 64-bit as appropriate for the host OS +# +install: FORCE + @for toolname in $(PROGS); do \ + (cd $(BUILD_DIRECTORY_PATH)/$$toolname; \ + pwd; \ + $(MAKE) PROG=$$toolname install; \ + if [ $(findstring 64,$(HARDWARE_NAME)) ]; then \ + echo "Installed 64-bit version of $$toolname"; \ + else \ + echo "Installed 32-bit version of $$toolname"; \ + fi; \ + echo ""; \ + ); \ + done; + +machine: FORCE + @echo "Machine architecture: $(HARDWARE_NAME), $(XBITS)"; + @echo "Findstring: $(findstring 64, $(HARDWARE_NAME))"; + +FORCE: + diff --git a/third_party/lib/acpica/generate/unix/Makefile.config b/third_party/lib/acpica/generate/unix/Makefile.config new file mode 100644 index 000000000..31378215f --- /dev/null +++ b/third_party/lib/acpica/generate/unix/Makefile.config @@ -0,0 +1,251 @@ +# +# Makefile.config +# +# Common configuration and setup file to generate the ACPICA tools and +# utilities: the iASL compiler, acpiexec, acpihelp, acpinames, acpisrc, +# acpixtract, acpibin. +# +# This file is included by the individual makefiles for each tool. +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# + +# +# Configuration +# +# OPT_CFLAGS can be overridden on the make command line by +# adding OPT_CFLAGS="..." to the invocation. +# +# Notes: +# gcc should be version 4 or greater, otherwise some of the options +# used will not be recognized. +# Optional: Set HOST to an appropriate value (_LINUX, _FreeBSD, _APPLE, _CYGWIN, etc.) +# See include/platform/acenv.h for supported values. +# Note: HOST is not nearly as important for applications as it +# is for the kernel-resident version of ACPICA, and it may +# not be necessary to change it. +# +.SUFFIXES : +PROGS = acpibin acpidump acpiexamples acpiexec acpihelp acpinames acpisrc acpixtract iasl +HOST ?= _CYGWIN +CC = gcc + +# +# Common defines +# +OBJDIR = obj +BINDIR = bin +COMPILEOBJ = $(CC) -c $(CFLAGS) $(OPT_CFLAGS) -o $@ $< +LINKPROG = $(CC) $(OBJECTS) -o $(PROG) $(LDFLAGS) +PREFIX ?= /usr +INSTALLDIR = $(PREFIX)/bin +UNAME_S := $(shell uname -s) + +# +# Host detection and configuration +# +ifeq ($(UNAME_S), Darwin) # Mac OS X +HOST = _APPLE +endif + +ifeq ($(UNAME_S), DragonFly) +HOST = _DragonFly +endif + +ifeq ($(UNAME_S), FreeBSD) +HOST = _FreeBSD +endif + +ifeq ($(UNAME_S), NetBSD) +HOST = _NetBSD +endif + +ifeq ($(HOST), _APPLE) +INSTALL = cp +INSTALLFLAGS ?= -f +else +INSTALL = install +INSTALLFLAGS ?= -m 555 -s +endif + +INSTALLPROG = \ + mkdir -p $(DESTDIR)$(INSTALLDIR); \ + $(INSTALL) $(INSTALLFLAGS) ../$(BINDIR)/$(PROG) $(DESTDIR)$(INSTALLDIR)/$(PROG) + +# +# Rename a .exe file if necessary +# +RENAMEPROG = \ + @if [ -e "$(PROG).exe" ] ; then \ + mv $(PROG).exe $(PROG); \ + echo "Renamed $(PROG).exe to $(PROG)"; \ + fi; + +# +# Copy the final executable to the local bin directory +# +COPYPROG = \ + @mkdir -p ../$(BINDIR); \ + cp -f $(PROG) ../$(BINDIR); \ + echo "Copied $(PROG) to $(FINAL_PROG)"; + +# +# Main ACPICA source directories +# +ACPICA_SRC = ../../../source +ACPICA_COMMON = $(ACPICA_SRC)/common +ACPICA_TOOLS = $(ACPICA_SRC)/tools +ACPICA_OSL = $(ACPICA_SRC)/os_specific/service_layers +ACPICA_CORE = $(ACPICA_SRC)/components +ACPICA_INCLUDE = $(ACPICA_SRC)/include +ACPICA_DEBUGGER = $(ACPICA_CORE)/debugger +ACPICA_DISASSEMBLER = $(ACPICA_CORE)/disassembler +ACPICA_DISPATCHER = $(ACPICA_CORE)/dispatcher +ACPICA_EVENTS = $(ACPICA_CORE)/events +ACPICA_EXECUTER = $(ACPICA_CORE)/executer +ACPICA_HARDWARE = $(ACPICA_CORE)/hardware +ACPICA_NAMESPACE = $(ACPICA_CORE)/namespace +ACPICA_PARSER = $(ACPICA_CORE)/parser +ACPICA_RESOURCES = $(ACPICA_CORE)/resources +ACPICA_TABLES = $(ACPICA_CORE)/tables +ACPICA_UTILITIES = $(ACPICA_CORE)/utilities + +# +# ACPICA tool and utility source directories +# +ACPIBIN = $(ACPICA_TOOLS)/acpibin +ACPIDUMP = $(ACPICA_TOOLS)/acpidump +ACPIEXAMPLES = $(ACPICA_TOOLS)/examples +ACPIEXEC = $(ACPICA_TOOLS)/acpiexec +ACPIHELP = $(ACPICA_TOOLS)/acpihelp +ACPINAMES = $(ACPICA_TOOLS)/acpinames +ACPISRC = $(ACPICA_TOOLS)/acpisrc +ACPIXTRACT = $(ACPICA_TOOLS)/acpixtract +ASL_COMPILER = $(ACPICA_SRC)/compiler + +# +# Common ACPICA header files +# +ACPICA_HEADERS = \ + $(wildcard $(ACPICA_INCLUDE)/*.h) \ + $(wildcard $(ACPICA_INCLUDE)/platform/*.h) + +# +# Common compiler flags +# The _GNU_SOURCE symbol is required for many hosts. +# +OPT_CFLAGS ?= $(CWARNINGFLAGS) + +# +# Optionally disable optimizations. Optimization causes problems on +# some compilers such as gcc 4.4 +# +ifneq ($(NOOPT),TRUE) +OPT_CFLAGS += -O2 +endif + +# +# Optionally disable fortify source. This option can cause +# compile errors in toolchains where it is already defined. +# +ifneq ($(NOFORTIFY),TRUE) +OPT_CFLAGS += -D_FORTIFY_SOURCE=2 +endif + +CFLAGS += \ + -D$(HOST)\ + -D_GNU_SOURCE\ + -I$(ACPICA_INCLUDE) + +# +# Common compiler warning flags. The warning flags in addition +# to -Wall are not automatically included in -Wall. +# +CWARNINGFLAGS = \ + -std=c99\ + -Wall\ + -Wbad-function-cast\ + -Wdeclaration-after-statement\ + -Werror\ + -Wformat=2\ + -Wmissing-declarations\ + -Wmissing-prototypes\ + -Wstrict-aliasing=0\ + -Wstrict-prototypes\ + -Wswitch-default\ + -Wpointer-arith\ + -Wundef + +# +# Common gcc 4+ warning flags +# +CWARNINGFLAGS += \ + -Waddress\ + -Waggregate-return\ + -Winit-self\ + -Winline\ + -Wmissing-declarations\ + -Wmissing-field-initializers\ + -Wnested-externs\ + -Wold-style-definition\ + -Wno-format-nonliteral\ + -Wredundant-decls +# +# Per-host flags and exclusions +# +ifneq ($(HOST), _FreeBSD) + CWARNINGFLAGS += \ + -Wempty-body + + ifneq ($(HOST), _APPLE) + CWARNINGFLAGS += \ + -Woverride-init\ + -Wlogical-op\ + -Wmissing-parameter-type\ + -Wold-style-declaration\ + -Wtype-limits + endif +endif + +# +# Extra warning flags (for possible future use) +# +#CWARNINGFLAGS += \ +# -Wcast-qual\ +# -Wconversion\ +# -Wshadow\ + +# +# M4 macro processor is used to build the final parser file +# +# Bison/Flex configuration +# +# -y: act like yacc +# +# -i: generate case insensitive scanner +# -s: suppress default rule, abort on unknown input +# +# Optional for Bison/yacc: +# -v: verbose, produces a .output file +# -d: produces the defines header file +# +# Berkeley yacc configuration +# +#YACC= byacc +#YFLAGS += +# +YACC= bison +YFLAGS += -y + +MACROPROC= m4 +MFLAGS= -P -I$(ASL_COMPILER) + +LEX= flex +LFLAGS += -i -s diff --git a/third_party/lib/acpica/generate/unix/Makefile.rules b/third_party/lib/acpica/generate/unix/Makefile.rules new file mode 100644 index 000000000..b9aa9a9c3 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/Makefile.rules @@ -0,0 +1,24 @@ +# +# Common rules for generation of ACPICA utilities +# +# FINAL_PROG - Copies the utility to the local bin directory +# PROG - Builds the utility (links the object files) +# +# Note: $(INTERMEDIATES) and $(MISC) are used for iASL compiler only. +# + +$(FINAL_PROG) : $(PROG) + $(COPYPROG) + +$(PROG) : $(INTERMEDIATES) $(MISC) $(OBJECTS) + $(LINKPROG) + $(RENAMEPROG) + +$(OBJDIR)/%.o : %.c $(HEADERS) $(ACPICA_HEADERS) + $(COMPILEOBJ) + +clean : + rm -f $(PROG) $(PROG).exe $(OBJECTS) $(OBJDIR)/*.o $(INTERMEDIATES) $(MISC) + +install : + $(INSTALLPROG) diff --git a/third_party/lib/acpica/generate/unix/acpibin/Makefile b/third_party/lib/acpica/generate/unix/acpibin/Makefile new file mode 100644 index 000000000..1be484d56 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpibin/Makefile @@ -0,0 +1,62 @@ +# +# acpibin - Binary ACPI table utility +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpibin +PROG = $(OBJDIR)/acpibin + +# +# Search paths for source files +# +vpath %.c \ + $(ACPIBIN)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPIBIN)/*.h) + +OBJECTS = \ + $(OBJDIR)/abcompare.o\ + $(OBJDIR)/abmain.o\ + $(OBJDIR)/cmfsize.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/utalloc.o\ + $(OBJDIR)/utbuffer.o\ + $(OBJDIR)/utcache.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utdecode.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/utlock.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utmisc.o\ + $(OBJDIR)/utmutex.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utstate.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/utxferror.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixxf.o + +# +# Flags specific to acpibin +# +CFLAGS += \ + -DACPI_BIN_APP\ + -I$(ACPIBIN) + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpidump/Makefile b/third_party/lib/acpica/generate/unix/acpidump/Makefile new file mode 100644 index 000000000..313ad153f --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpidump/Makefile @@ -0,0 +1,85 @@ +# +# acpidump - ACPI table dump utility (binary to ascii hex) +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpidump +PROG = $(OBJDIR)/acpidump + +# +# Search paths for source files +# +vpath %.c \ + $(ACPIDUMP)\ + $(ACPICA_TABLES)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPIDUMP)/*.h) + +OBJECTS = \ + $(OBJDIR)/apdump.o\ + $(OBJDIR)/apfiles.o\ + $(OBJDIR)/apmain.o\ + $(OBJDIR)/cmfsize.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixdir.o\ + $(OBJDIR)/osunixmap.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/tbprint.o\ + $(OBJDIR)/tbxfroot.o\ + $(OBJDIR)/utbuffer.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/utxferror.o + +# +# Per-host interfaces +# +ifeq ($(HOST), _DragonFly) +HOST_FAMILY = BSD +endif + +ifeq ($(HOST), _FreeBSD) +HOST_FAMILY = BSD +endif + +ifeq ($(HOST), _NetBSD) +HOST_FAMILY = BSD +endif + +ifeq ($(HOST_FAMILY), BSD) +OBJECTS += \ + $(OBJDIR)/osbsdtbl.o +else +OBJECTS += \ + $(OBJDIR)/oslinuxtbl.o +endif + +# +# Flags specific to acpidump +# +CFLAGS += \ + -DACPI_DUMP_APP\ + -I$(ACPIDUMP) + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpiexamples/Makefile b/third_party/lib/acpica/generate/unix/acpiexamples/Makefile new file mode 100644 index 000000000..7d9daf395 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpiexamples/Makefile @@ -0,0 +1,173 @@ +# +# acpiexamples - Example ACPICA initialization code and control +# method execution. +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpiexamples +PROG = $(OBJDIR)/acpiexamples + +# +# Search paths for source files +# +vpath %.c \ + $(ACPIEXAMPLES)\ + $(ACPICA_DISPATCHER)\ + $(ACPICA_EVENTS)\ + $(ACPICA_EXECUTER)\ + $(ACPICA_HARDWARE)\ + $(ACPICA_NAMESPACE)\ + $(ACPICA_PARSER)\ + $(ACPICA_TABLES)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPIEXAMPLES)/*.h) + +OBJECTS = \ + $(OBJDIR)/examples.o\ + $(OBJDIR)/exstubs.o\ + $(OBJDIR)/extables.o\ + $(OBJDIR)/dsargs.o\ + $(OBJDIR)/dscontrol.o\ + $(OBJDIR)/dsdebug.o\ + $(OBJDIR)/dsfield.o\ + $(OBJDIR)/dsinit.o\ + $(OBJDIR)/dsmethod.o\ + $(OBJDIR)/dsmthdat.o\ + $(OBJDIR)/dsobject.o\ + $(OBJDIR)/dsopcode.o\ + $(OBJDIR)/dsutils.o\ + $(OBJDIR)/dswexec.o\ + $(OBJDIR)/dswload.o\ + $(OBJDIR)/dswload2.o\ + $(OBJDIR)/dswscope.o\ + $(OBJDIR)/dswstate.o\ + $(OBJDIR)/evhandler.o\ + $(OBJDIR)/evmisc.o\ + $(OBJDIR)/evregion.o\ + $(OBJDIR)/evrgnini.o\ + $(OBJDIR)/evxface.o\ + $(OBJDIR)/evxfregn.o\ + $(OBJDIR)/exconfig.o\ + $(OBJDIR)/exconvrt.o\ + $(OBJDIR)/excreate.o\ + $(OBJDIR)/exdebug.o\ + $(OBJDIR)/exdump.o\ + $(OBJDIR)/exfield.o\ + $(OBJDIR)/exfldio.o\ + $(OBJDIR)/exmisc.o\ + $(OBJDIR)/exmutex.o\ + $(OBJDIR)/exnames.o\ + $(OBJDIR)/exoparg1.o\ + $(OBJDIR)/exoparg2.o\ + $(OBJDIR)/exoparg3.o\ + $(OBJDIR)/exoparg6.o\ + $(OBJDIR)/exprep.o\ + $(OBJDIR)/exregion.o\ + $(OBJDIR)/exresnte.o\ + $(OBJDIR)/exresolv.o\ + $(OBJDIR)/exresop.o\ + $(OBJDIR)/exstore.o\ + $(OBJDIR)/exstoren.o\ + $(OBJDIR)/exstorob.o\ + $(OBJDIR)/exsystem.o\ + $(OBJDIR)/extrace.o\ + $(OBJDIR)/exutils.o\ + $(OBJDIR)/hwpci.o\ + $(OBJDIR)/nsaccess.o\ + $(OBJDIR)/nsalloc.o\ + $(OBJDIR)/nsarguments.o\ + $(OBJDIR)/nsconvert.o\ + $(OBJDIR)/nsdump.o\ + $(OBJDIR)/nseval.o\ + $(OBJDIR)/nsinit.o\ + $(OBJDIR)/nsload.o\ + $(OBJDIR)/nsnames.o\ + $(OBJDIR)/nsobject.o\ + $(OBJDIR)/nsparse.o\ + $(OBJDIR)/nspredef.o\ + $(OBJDIR)/nsprepkg.o\ + $(OBJDIR)/nsrepair.o\ + $(OBJDIR)/nsrepair2.o\ + $(OBJDIR)/nssearch.o\ + $(OBJDIR)/nsutils.o\ + $(OBJDIR)/nswalk.o\ + $(OBJDIR)/nsxfeval.o\ + $(OBJDIR)/nsxfname.o\ + $(OBJDIR)/nsxfobj.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/psargs.o\ + $(OBJDIR)/psloop.o\ + $(OBJDIR)/psobject.o\ + $(OBJDIR)/psopcode.o\ + $(OBJDIR)/psopinfo.o\ + $(OBJDIR)/psparse.o\ + $(OBJDIR)/psscope.o\ + $(OBJDIR)/pstree.o\ + $(OBJDIR)/psutils.o\ + $(OBJDIR)/pswalk.o\ + $(OBJDIR)/psxface.o\ + $(OBJDIR)/tbdata.o\ + $(OBJDIR)/tbfadt.o\ + $(OBJDIR)/tbfind.o\ + $(OBJDIR)/tbinstal.o\ + $(OBJDIR)/tbprint.o\ + $(OBJDIR)/tbutils.o\ + $(OBJDIR)/tbxface.o\ + $(OBJDIR)/tbxfload.o\ + $(OBJDIR)/tbxfroot.o\ + $(OBJDIR)/utaddress.o\ + $(OBJDIR)/utalloc.o\ + $(OBJDIR)/utbuffer.o\ + $(OBJDIR)/utcache.o\ + $(OBJDIR)/utcopy.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utdecode.o\ + $(OBJDIR)/utdelete.o\ + $(OBJDIR)/uterror.o\ + $(OBJDIR)/uteval.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/uthex.o\ + $(OBJDIR)/utids.o\ + $(OBJDIR)/utinit.o\ + $(OBJDIR)/utlock.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utmisc.o\ + $(OBJDIR)/utmutex.o\ + $(OBJDIR)/utobject.o\ + $(OBJDIR)/utosi.o\ + $(OBJDIR)/utownerid.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utpredef.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utresrc.o\ + $(OBJDIR)/utstate.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/utxface.o\ + $(OBJDIR)/utxferror.o\ + $(OBJDIR)/utxfinit.o + +# +# Flags specific to acpinames utility +# +CFLAGS += \ + -DACPI_EXAMPLE_APP\ + -I$(ACPIEXAMPLES) + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpiexec/Makefile b/third_party/lib/acpica/generate/unix/acpiexec/Makefile new file mode 100644 index 000000000..384089cb8 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpiexec/Makefile @@ -0,0 +1,257 @@ +# +# acpiexec: ACPI execution simulator. Runs ACPICA code in user +# space. Loads ACPI tables, displays the namespace, and allows +# execution of control methods. +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpiexec +PROG = $(OBJDIR)/acpiexec + +# +# Search paths for source files +# +vpath %.c \ + $(ACPIEXEC)\ + $(ACPICA_DEBUGGER)\ + $(ACPICA_DISASSEMBLER)\ + $(ACPICA_DISPATCHER)\ + $(ACPICA_EVENTS)\ + $(ACPICA_EXECUTER)\ + $(ACPICA_HARDWARE)\ + $(ACPICA_NAMESPACE)\ + $(ACPICA_PARSER)\ + $(ACPICA_RESOURCES)\ + $(ACPICA_TABLES)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPIEXEC)/*.h) + +OBJECTS = \ + $(OBJDIR)/acgetline.o\ + $(OBJDIR)/acfileio.o\ + $(OBJDIR)/aeexec.o\ + $(OBJDIR)/aehandlers.o\ + $(OBJDIR)/aeinitfile.o\ + $(OBJDIR)/aemain.o\ + $(OBJDIR)/aeregion.o\ + $(OBJDIR)/aetables.o\ + $(OBJDIR)/ahids.o\ + $(OBJDIR)/ahuuids.o\ + $(OBJDIR)/cmfsize.o\ + $(OBJDIR)/dbcmds.o\ + $(OBJDIR)/dbconvert.o\ + $(OBJDIR)/dbdisply.o\ + $(OBJDIR)/dbexec.o\ + $(OBJDIR)/dbfileio.o\ + $(OBJDIR)/dbhistry.o\ + $(OBJDIR)/dbinput.o\ + $(OBJDIR)/dbmethod.o\ + $(OBJDIR)/dbnames.o\ + $(OBJDIR)/dbobject.o\ + $(OBJDIR)/dbstats.o\ + $(OBJDIR)/dbtest.o\ + $(OBJDIR)/dbutils.o\ + $(OBJDIR)/dbxface.o\ + $(OBJDIR)/dmbuffer.o\ + $(OBJDIR)/dmcstyle.o\ + $(OBJDIR)/dmdeferred.o\ + $(OBJDIR)/dmnames.o\ + $(OBJDIR)/dmopcode.o\ + $(OBJDIR)/dmresrc.o\ + $(OBJDIR)/dmresrcl.o\ + $(OBJDIR)/dmresrcl2.o\ + $(OBJDIR)/dmresrcs.o\ + $(OBJDIR)/dmutils.o\ + $(OBJDIR)/dmwalk.o\ + $(OBJDIR)/dsargs.o\ + $(OBJDIR)/dscontrol.o\ + $(OBJDIR)/dsdebug.o\ + $(OBJDIR)/dsfield.o\ + $(OBJDIR)/dsinit.o\ + $(OBJDIR)/dsmethod.o\ + $(OBJDIR)/dsmthdat.o\ + $(OBJDIR)/dsobject.o\ + $(OBJDIR)/dsopcode.o\ + $(OBJDIR)/dsutils.o\ + $(OBJDIR)/dswexec.o\ + $(OBJDIR)/dswload.o\ + $(OBJDIR)/dswload2.o\ + $(OBJDIR)/dswscope.o\ + $(OBJDIR)/dswstate.o\ + $(OBJDIR)/evevent.o\ + $(OBJDIR)/evglock.o\ + $(OBJDIR)/evgpe.o\ + $(OBJDIR)/evgpeblk.o\ + $(OBJDIR)/evgpeinit.o\ + $(OBJDIR)/evgpeutil.o\ + $(OBJDIR)/evhandler.o\ + $(OBJDIR)/evmisc.o\ + $(OBJDIR)/evregion.o\ + $(OBJDIR)/evrgnini.o\ + $(OBJDIR)/evsci.o\ + $(OBJDIR)/evxface.o\ + $(OBJDIR)/evxfevnt.o\ + $(OBJDIR)/evxfgpe.o\ + $(OBJDIR)/evxfregn.o\ + $(OBJDIR)/exconfig.o\ + $(OBJDIR)/exconvrt.o\ + $(OBJDIR)/excreate.o\ + $(OBJDIR)/exdebug.o\ + $(OBJDIR)/exdump.o\ + $(OBJDIR)/exfield.o\ + $(OBJDIR)/exfldio.o\ + $(OBJDIR)/exmisc.o\ + $(OBJDIR)/exmutex.o\ + $(OBJDIR)/exnames.o\ + $(OBJDIR)/exoparg1.o\ + $(OBJDIR)/exoparg2.o\ + $(OBJDIR)/exoparg3.o\ + $(OBJDIR)/exoparg6.o\ + $(OBJDIR)/exprep.o\ + $(OBJDIR)/exregion.o\ + $(OBJDIR)/exresnte.o\ + $(OBJDIR)/exresolv.o\ + $(OBJDIR)/exresop.o\ + $(OBJDIR)/exstore.o\ + $(OBJDIR)/exstoren.o\ + $(OBJDIR)/exstorob.o\ + $(OBJDIR)/exsystem.o\ + $(OBJDIR)/extrace.o\ + $(OBJDIR)/exutils.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/hwacpi.o\ + $(OBJDIR)/hwesleep.o\ + $(OBJDIR)/hwgpe.o\ + $(OBJDIR)/hwpci.o\ + $(OBJDIR)/hwregs.o\ + $(OBJDIR)/hwsleep.o\ + $(OBJDIR)/hwvalid.o\ + $(OBJDIR)/hwxface.o\ + $(OBJDIR)/hwxfsleep.o\ + $(OBJDIR)/nsaccess.o\ + $(OBJDIR)/nsalloc.o\ + $(OBJDIR)/nsarguments.o\ + $(OBJDIR)/nsconvert.o\ + $(OBJDIR)/nsdump.o\ + $(OBJDIR)/nsdumpdv.o\ + $(OBJDIR)/nseval.o\ + $(OBJDIR)/nsinit.o\ + $(OBJDIR)/nsload.o\ + $(OBJDIR)/nsnames.o\ + $(OBJDIR)/nsobject.o\ + $(OBJDIR)/nsparse.o\ + $(OBJDIR)/nspredef.o\ + $(OBJDIR)/nsprepkg.o\ + $(OBJDIR)/nsrepair.o\ + $(OBJDIR)/nsrepair2.o\ + $(OBJDIR)/nssearch.o\ + $(OBJDIR)/nsutils.o\ + $(OBJDIR)/nswalk.o\ + $(OBJDIR)/nsxfeval.o\ + $(OBJDIR)/nsxfname.o\ + $(OBJDIR)/nsxfobj.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/psargs.o\ + $(OBJDIR)/psloop.o\ + $(OBJDIR)/psobject.o\ + $(OBJDIR)/psopcode.o\ + $(OBJDIR)/psopinfo.o\ + $(OBJDIR)/psparse.o\ + $(OBJDIR)/psscope.o\ + $(OBJDIR)/pstree.o\ + $(OBJDIR)/psutils.o\ + $(OBJDIR)/pswalk.o\ + $(OBJDIR)/psxface.o\ + $(OBJDIR)/rsaddr.o\ + $(OBJDIR)/rscalc.o\ + $(OBJDIR)/rscreate.o\ + $(OBJDIR)/rsdump.o\ + $(OBJDIR)/rsdumpinfo.o\ + $(OBJDIR)/rsinfo.o\ + $(OBJDIR)/rsio.o\ + $(OBJDIR)/rsirq.o\ + $(OBJDIR)/rslist.o\ + $(OBJDIR)/rsmemory.o\ + $(OBJDIR)/rsmisc.o\ + $(OBJDIR)/rsserial.o\ + $(OBJDIR)/rsutils.o\ + $(OBJDIR)/rsxface.o\ + $(OBJDIR)/tbdata.o\ + $(OBJDIR)/tbfadt.o\ + $(OBJDIR)/tbfind.o\ + $(OBJDIR)/tbinstal.o\ + $(OBJDIR)/tbprint.o\ + $(OBJDIR)/tbutils.o\ + $(OBJDIR)/tbxface.o\ + $(OBJDIR)/tbxfload.o\ + $(OBJDIR)/tbxfroot.o\ + $(OBJDIR)/utaddress.o\ + $(OBJDIR)/utalloc.o\ + $(OBJDIR)/utbuffer.o\ + $(OBJDIR)/utcache.o\ + $(OBJDIR)/utcopy.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utdecode.o\ + $(OBJDIR)/utdelete.o\ + $(OBJDIR)/uterror.o\ + $(OBJDIR)/uteval.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/uthex.o\ + $(OBJDIR)/utids.o\ + $(OBJDIR)/utinit.o\ + $(OBJDIR)/utlock.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utmisc.o\ + $(OBJDIR)/utmutex.o\ + $(OBJDIR)/utobject.o\ + $(OBJDIR)/utosi.o\ + $(OBJDIR)/utownerid.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utpredef.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utresrc.o\ + $(OBJDIR)/utstate.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/uttrack.o\ + $(OBJDIR)/utuuid.o\ + $(OBJDIR)/utxface.o\ + $(OBJDIR)/utxferror.o\ + $(OBJDIR)/utxfinit.o\ + $(OBJDIR)/utxfmutex.o + +# +# Flags specific to acpiexec utility +# +CFLAGS += \ + -DACPI_EXEC_APP\ + -I$(ACPIEXEC) + +ifeq ($(ASLTS),TRUE) +CFLAGS += \ + -DACPI_CHECKSUM_ABORT=TRUE +endif + +LDFLAGS += -lpthread + +ifneq ($(HOST),_APPLE) +LDFLAGS += -lrt +endif + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpihelp/Makefile b/third_party/lib/acpica/generate/unix/acpihelp/Makefile new file mode 100644 index 000000000..d50e416c8 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpihelp/Makefile @@ -0,0 +1,63 @@ +# +# acpihelp - ACPI Help utility. Displays ASL operator syntax and +# information about ACPI predefined names. +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpihelp +PROG = $(OBJDIR)/acpihelp + +# +# Search paths for source files +# +vpath %.c \ + $(ACPIHELP)\ + $(ACPICA_COMMON)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPIHELP)/*.h) + +OBJECTS = \ + $(OBJDIR)/ahamlops.o\ + $(OBJDIR)/ahaslkey.o\ + $(OBJDIR)/ahaslops.o\ + $(OBJDIR)/ahdecode.o\ + $(OBJDIR)/ahids.o\ + $(OBJDIR)/ahpredef.o\ + $(OBJDIR)/ahmain.o\ + $(OBJDIR)/ahtable.o\ + $(OBJDIR)/ahuuids.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/uthex.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utpredef.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utuuid.o + +# +# Flags specific to acpihelp +# +CFLAGS += \ + -DACPI_HELP_APP\ + -I$(ACPIHELP) + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpinames/Makefile b/third_party/lib/acpica/generate/unix/acpinames/Makefile new file mode 100644 index 000000000..7457b1b41 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpinames/Makefile @@ -0,0 +1,135 @@ +# +# acpinames - Load ACPI table and dump namespace. This is a subset +# of the AcpiExec functionality, it is intended to demonstrate +# the configurability of ACPICA. +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpinames +PROG = $(OBJDIR)/acpinames + +# +# Search paths for source files +# +vpath %.c \ + $(ACPINAMES)\ + $(ACPICA_DISPATCHER)\ + $(ACPICA_EXECUTER)\ + $(ACPICA_NAMESPACE)\ + $(ACPICA_PARSER)\ + $(ACPICA_TABLES)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPINAMES)/*.h) + +OBJECTS = \ + $(OBJDIR)/acfileio.o\ + $(OBJDIR)/anmain.o\ + $(OBJDIR)/anstubs.o\ + $(OBJDIR)/antables.o\ + $(OBJDIR)/cmfsize.o\ + $(OBJDIR)/dsfield.o\ + $(OBJDIR)/dsinit.o\ + $(OBJDIR)/dsmthdat.o\ + $(OBJDIR)/dsobject.o\ + $(OBJDIR)/dsutils.o\ + $(OBJDIR)/dswload.o\ + $(OBJDIR)/dswload2.o\ + $(OBJDIR)/dswscope.o\ + $(OBJDIR)/dswstate.o\ + $(OBJDIR)/excreate.o\ + $(OBJDIR)/exdump.o\ + $(OBJDIR)/exmutex.o\ + $(OBJDIR)/exnames.o\ + $(OBJDIR)/exprep.o\ + $(OBJDIR)/exresnte.o\ + $(OBJDIR)/exresolv.o\ + $(OBJDIR)/exsystem.o\ + $(OBJDIR)/exutils.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/nsaccess.o\ + $(OBJDIR)/nsalloc.o\ + $(OBJDIR)/nsdump.o\ + $(OBJDIR)/nsinit.o\ + $(OBJDIR)/nsload.o\ + $(OBJDIR)/nsnames.o\ + $(OBJDIR)/nsobject.o\ + $(OBJDIR)/nsparse.o\ + $(OBJDIR)/nssearch.o\ + $(OBJDIR)/nsutils.o\ + $(OBJDIR)/nswalk.o\ + $(OBJDIR)/nsxfeval.o\ + $(OBJDIR)/nsxfname.o\ + $(OBJDIR)/nsxfobj.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/psargs.o\ + $(OBJDIR)/psloop.o\ + $(OBJDIR)/psobject.o\ + $(OBJDIR)/psopcode.o\ + $(OBJDIR)/psopinfo.o\ + $(OBJDIR)/psparse.o\ + $(OBJDIR)/psscope.o\ + $(OBJDIR)/pstree.o\ + $(OBJDIR)/psutils.o\ + $(OBJDIR)/pswalk.o\ + $(OBJDIR)/psxface.o\ + $(OBJDIR)/tbdata.o\ + $(OBJDIR)/tbfadt.o\ + $(OBJDIR)/tbfind.o\ + $(OBJDIR)/tbinstal.o\ + $(OBJDIR)/tbprint.o\ + $(OBJDIR)/tbutils.o\ + $(OBJDIR)/tbxface.o\ + $(OBJDIR)/tbxfload.o\ + $(OBJDIR)/tbxfroot.o\ + $(OBJDIR)/utaddress.o\ + $(OBJDIR)/utalloc.o\ + $(OBJDIR)/utbuffer.o\ + $(OBJDIR)/utcache.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utdecode.o\ + $(OBJDIR)/utdelete.o\ + $(OBJDIR)/uterror.o\ + $(OBJDIR)/uteval.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/uthex.o\ + $(OBJDIR)/utids.o\ + $(OBJDIR)/utinit.o\ + $(OBJDIR)/utlock.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utmisc.o\ + $(OBJDIR)/utmutex.o\ + $(OBJDIR)/utobject.o\ + $(OBJDIR)/utosi.o\ + $(OBJDIR)/utownerid.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utstate.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/utxface.o\ + $(OBJDIR)/utxferror.o\ + $(OBJDIR)/utxfinit.o + +# +# Flags specific to acpinames utility +# +CFLAGS += \ + -DACPI_NAMES_APP\ + -I$(ACPINAMES) + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpisrc/Makefile b/third_party/lib/acpica/generate/unix/acpisrc/Makefile new file mode 100644 index 000000000..6511fd740 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpisrc/Makefile @@ -0,0 +1,61 @@ +# +# acpisrc - ACPICA source code conversion utility +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpisrc +PROG = $(OBJDIR)/acpisrc + +# +# Search path for source files and individual source files +# +vpath %.c \ + $(ACPISRC)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPISRC)/*.h) + +OBJECTS = \ + $(OBJDIR)/ascase.o\ + $(OBJDIR)/asconvrt.o\ + $(OBJDIR)/asfile.o\ + $(OBJDIR)/asmain.o\ + $(OBJDIR)/asremove.o\ + $(OBJDIR)/astable.o\ + $(OBJDIR)/asutils.o\ + $(OBJDIR)/cmfsize.o\ + $(OBJDIR)/getopt.o \ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixdir.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/utxferror.o + +# +# Compile flags specific to acpisrc +# +CFLAGS += \ + -DACPI_SRC_APP\ + -I$(ACPISRC) + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/acpixtract/Makefile b/third_party/lib/acpica/generate/unix/acpixtract/Makefile new file mode 100644 index 000000000..58722e822 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/acpixtract/Makefile @@ -0,0 +1,53 @@ +# +# acpixtract - extract binary ACPI tables from acpidump text output +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/acpixtract +PROG = $(OBJDIR)/acpixtract + +# +# Search paths for source files +# +vpath %.c \ + $(ACPIXTRACT)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ACPIXTRACT)/*.h) + +OBJECTS = \ + $(OBJDIR)/acpixtract.o\ + $(OBJDIR)/axmain.o\ + $(OBJDIR)/axutils.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utxferror.o + +# +# Flags specific to acpixtract +# +CFLAGS += \ + -DACPI_XTRACT_APP + +# +# Common Rules +# +include ../Makefile.rules diff --git a/third_party/lib/acpica/generate/unix/iasl/Makefile b/third_party/lib/acpica/generate/unix/iasl/Makefile new file mode 100644 index 000000000..8b71edd03 --- /dev/null +++ b/third_party/lib/acpica/generate/unix/iasl/Makefile @@ -0,0 +1,328 @@ +# +# iASL compiler/disassembler +# + +# +# Note: This makefile is intended to be used from within the native +# ACPICA directory structure, from under generate/unix. It specifically +# places all object files in a generate/unix subdirectory, not within +# the various ACPICA source directories. This prevents collisions +# between different compilations of the same source file with different +# compile options, and prevents pollution of the source code. +# +include ../Makefile.config +FINAL_PROG = ../$(BINDIR)/iasl +PROG = $(OBJDIR)/iasl + +# +# Search paths for source files +# +vpath %.c \ + $(ASL_COMPILER)\ + $(ACPICA_DEBUGGER)\ + $(ACPICA_DISASSEMBLER)\ + $(ACPICA_DISPATCHER)\ + $(ACPICA_EXECUTER)\ + $(ACPICA_NAMESPACE)\ + $(ACPICA_PARSER)\ + $(ACPICA_TABLES)\ + $(ACPICA_UTILITIES)\ + $(ACPICA_COMMON)\ + $(ACPICA_OSL) + +HEADERS = \ + $(wildcard $(ASL_COMPILER)/*.h)\ + $(OBJDIR)/aslcompiler.y.h\ + $(OBJDIR)/dtparser.y.h\ + $(OBJDIR)/prparser.y.h + +OBJECTS = \ + $(OBJDIR)/aslcompilerlex.o\ + $(OBJDIR)/aslcompilerparse.o\ + $(OBJDIR)/dtparserlex.o\ + $(OBJDIR)/dtparserparse.o\ + $(OBJDIR)/prparserlex.o\ + $(OBJDIR)/prparserparse.o\ + $(OBJDIR)/acfileio.o\ + $(OBJDIR)/adfile.o\ + $(OBJDIR)/adisasm.o\ + $(OBJDIR)/adwalk.o\ + $(OBJDIR)/ahids.o\ + $(OBJDIR)/ahpredef.o\ + $(OBJDIR)/ahtable.o\ + $(OBJDIR)/ahuuids.o\ + $(OBJDIR)/aslanalyze.o\ + $(OBJDIR)/aslascii.o\ + $(OBJDIR)/aslbtypes.o\ + $(OBJDIR)/aslcodegen.o\ + $(OBJDIR)/aslcompile.o\ + $(OBJDIR)/aslerror.o\ + $(OBJDIR)/aslfiles.o\ + $(OBJDIR)/aslfileio.o\ + $(OBJDIR)/aslfold.o\ + $(OBJDIR)/aslhex.o\ + $(OBJDIR)/asllength.o\ + $(OBJDIR)/asllisting.o\ + $(OBJDIR)/asllistsup.o\ + $(OBJDIR)/aslload.o\ + $(OBJDIR)/asllookup.o\ + $(OBJDIR)/aslmain.o\ + $(OBJDIR)/aslmap.o\ + $(OBJDIR)/aslmapenter.o\ + $(OBJDIR)/aslmapoutput.o\ + $(OBJDIR)/aslmaputils.o\ + $(OBJDIR)/aslmessages.o\ + $(OBJDIR)/aslmethod.o\ + $(OBJDIR)/aslnamesp.o\ + $(OBJDIR)/asloffset.o\ + $(OBJDIR)/aslopcodes.o\ + $(OBJDIR)/asloperands.o\ + $(OBJDIR)/aslopt.o\ + $(OBJDIR)/asloptions.o\ + $(OBJDIR)/aslpredef.o\ + $(OBJDIR)/aslprepkg.o\ + $(OBJDIR)/aslprintf.o\ + $(OBJDIR)/aslprune.o\ + $(OBJDIR)/aslresource.o\ + $(OBJDIR)/aslrestype1.o\ + $(OBJDIR)/aslrestype1i.o\ + $(OBJDIR)/aslrestype2.o\ + $(OBJDIR)/aslrestype2d.o\ + $(OBJDIR)/aslrestype2e.o\ + $(OBJDIR)/aslrestype2q.o\ + $(OBJDIR)/aslrestype2s.o\ + $(OBJDIR)/aslrestype2w.o\ + $(OBJDIR)/aslstartup.o\ + $(OBJDIR)/aslstubs.o\ + $(OBJDIR)/asltransform.o\ + $(OBJDIR)/asltree.o\ + $(OBJDIR)/aslutils.o\ + $(OBJDIR)/asluuid.o\ + $(OBJDIR)/aslwalks.o\ + $(OBJDIR)/aslxref.o\ + $(OBJDIR)/cmfsize.o\ + $(OBJDIR)/dbfileio.o\ + $(OBJDIR)/dmbuffer.o\ + $(OBJDIR)/dmcstyle.o\ + $(OBJDIR)/dmdeferred.o\ + $(OBJDIR)/dmextern.o\ + $(OBJDIR)/dmnames.o\ + $(OBJDIR)/dmopcode.o\ + $(OBJDIR)/dmresrc.o\ + $(OBJDIR)/dmresrcl.o\ + $(OBJDIR)/dmresrcl2.o\ + $(OBJDIR)/dmresrcs.o\ + $(OBJDIR)/dmrestag.o\ + $(OBJDIR)/dmtable.o\ + $(OBJDIR)/dmtables.o\ + $(OBJDIR)/dmtbdump.o\ + $(OBJDIR)/dmtbinfo.o\ + $(OBJDIR)/dmutils.o\ + $(OBJDIR)/dmwalk.o\ + $(OBJDIR)/dsargs.o\ + $(OBJDIR)/dscontrol.o\ + $(OBJDIR)/dsfield.o\ + $(OBJDIR)/dsobject.o\ + $(OBJDIR)/dsopcode.o\ + $(OBJDIR)/dsutils.o\ + $(OBJDIR)/dswexec.o\ + $(OBJDIR)/dswload.o\ + $(OBJDIR)/dswload2.o\ + $(OBJDIR)/dswscope.o\ + $(OBJDIR)/dswstate.o\ + $(OBJDIR)/dtcompile.o\ + $(OBJDIR)/dtexpress.o\ + $(OBJDIR)/dtfield.o\ + $(OBJDIR)/dtio.o\ + $(OBJDIR)/dtsubtable.o\ + $(OBJDIR)/dttable.o\ + $(OBJDIR)/dttable1.o\ + $(OBJDIR)/dttable2.o\ + $(OBJDIR)/dttemplate.o\ + $(OBJDIR)/dtutils.o\ + $(OBJDIR)/exconvrt.o\ + $(OBJDIR)/excreate.o\ + $(OBJDIR)/exdump.o\ + $(OBJDIR)/exmisc.o\ + $(OBJDIR)/exmutex.o\ + $(OBJDIR)/exnames.o\ + $(OBJDIR)/exoparg1.o\ + $(OBJDIR)/exoparg2.o\ + $(OBJDIR)/exoparg3.o\ + $(OBJDIR)/exoparg6.o\ + $(OBJDIR)/exprep.o\ + $(OBJDIR)/exregion.o\ + $(OBJDIR)/exresnte.o\ + $(OBJDIR)/exresolv.o\ + $(OBJDIR)/exresop.o\ + $(OBJDIR)/exstore.o\ + $(OBJDIR)/exstoren.o\ + $(OBJDIR)/exstorob.o\ + $(OBJDIR)/exsystem.o\ + $(OBJDIR)/exutils.o\ + $(OBJDIR)/getopt.o\ + $(OBJDIR)/nsaccess.o\ + $(OBJDIR)/nsalloc.o\ + $(OBJDIR)/nsdump.o\ + $(OBJDIR)/nsnames.o\ + $(OBJDIR)/nsobject.o\ + $(OBJDIR)/nsparse.o\ + $(OBJDIR)/nssearch.o\ + $(OBJDIR)/nsutils.o\ + $(OBJDIR)/nswalk.o\ + $(OBJDIR)/nsxfobj.o\ + $(OBJDIR)/osunixxf.o\ + $(OBJDIR)/oslibcfs.o\ + $(OBJDIR)/prexpress.o\ + $(OBJDIR)/prmacros.o\ + $(OBJDIR)/prscan.o\ + $(OBJDIR)/prutils.o\ + $(OBJDIR)/psargs.o\ + $(OBJDIR)/psloop.o\ + $(OBJDIR)/psobject.o\ + $(OBJDIR)/psopcode.o\ + $(OBJDIR)/psopinfo.o\ + $(OBJDIR)/psparse.o\ + $(OBJDIR)/psscope.o\ + $(OBJDIR)/pstree.o\ + $(OBJDIR)/psutils.o\ + $(OBJDIR)/pswalk.o\ + $(OBJDIR)/tbdata.o\ + $(OBJDIR)/tbfadt.o\ + $(OBJDIR)/tbinstal.o\ + $(OBJDIR)/tbprint.o\ + $(OBJDIR)/tbutils.o\ + $(OBJDIR)/tbxface.o\ + $(OBJDIR)/tbxfload.o\ + $(OBJDIR)/utaddress.o\ + $(OBJDIR)/utalloc.o\ + $(OBJDIR)/utbuffer.o\ + $(OBJDIR)/utcache.o\ + $(OBJDIR)/utcopy.o\ + $(OBJDIR)/utdebug.o\ + $(OBJDIR)/utdecode.o\ + $(OBJDIR)/utdelete.o\ + $(OBJDIR)/uterror.o\ + $(OBJDIR)/utexcep.o\ + $(OBJDIR)/utglobal.o\ + $(OBJDIR)/uthex.o\ + $(OBJDIR)/utinit.o\ + $(OBJDIR)/utlock.o\ + $(OBJDIR)/utmath.o\ + $(OBJDIR)/utmisc.o\ + $(OBJDIR)/utmutex.o\ + $(OBJDIR)/utnonansi.o\ + $(OBJDIR)/utobject.o\ + $(OBJDIR)/utownerid.o\ + $(OBJDIR)/utpredef.o\ + $(OBJDIR)/utprint.o\ + $(OBJDIR)/utresrc.o\ + $(OBJDIR)/utstate.o\ + $(OBJDIR)/utstring.o\ + $(OBJDIR)/utuuid.o\ + $(OBJDIR)/utxface.o\ + $(OBJDIR)/utxferror.o + +INTERMEDIATES = \ + $(OBJDIR)/aslcompiler.y\ + $(OBJDIR)/aslcompilerlex.c\ + $(OBJDIR)/aslcompilerparse.c\ + $(OBJDIR)/dtparserlex.c\ + $(OBJDIR)/dtparserparse.c\ + $(OBJDIR)/prparserlex.c\ + $(OBJDIR)/prparserparse.c + +MISC = \ + $(OBJDIR)/aslcompiler.y.h\ + $(OBJDIR)/dtparser.y.h\ + $(OBJDIR)/prparser.y.h + +ASL_PARSER = \ + $(ASL_COMPILER)/aslcstyle.y\ + $(ASL_COMPILER)/aslparser.y\ + $(ASL_COMPILER)/aslresources.y\ + $(ASL_COMPILER)/aslsupport.y\ + $(ASL_COMPILER)/asltokens.y\ + $(ASL_COMPILER)/asltypes.y\ + $(ASL_COMPILER)/aslrules.y + +ASL_LEXER = \ + $(ASL_COMPILER)/aslcompiler.l\ + $(ASL_COMPILER)/aslsupport.l\ + $(OBJDIR)/aslcompiler.y.h + + +# +# Flags specific to iASL compiler +# +CFLAGS += \ + -DACPI_ASL_COMPILER\ + -I$(ASL_COMPILER)\ + -I$(OBJDIR) + +# +# Common Rules +# +include ../Makefile.rules + +# +# Function to safely execute yacc +# +safe_yacc = \ + _f=`echo $(1) | tr '[:upper:]' '[:lower:]'` &&\ + _d=`mktemp -d $(OBJDIR)/$$_f.XXXXXX` &&\ + _t=`basename $(3)` &&\ + $(YACC) $(YFLAGS) -p$(1) -o$$_d/$$_f.c -d $(2) &&\ + mv $$_d/$$_f.$${_t\#\#*.} $(3);\ + test -d $$_d && rm -fr $$_d + +# +# Macro processing for iASL .y files +# +$(OBJDIR)/aslcompiler.y : $(ASL_PARSER) + $(MACROPROC) $(MFLAGS) $(ASL_COMPILER)/aslparser.y > $@ + +# +# Parser and Lexer - intermediate C files +# +$(OBJDIR)/aslcompilerlex.c : $(ASL_LEXER) + $(LEX) $(LFLAGS) -PAslCompiler -o$@ $(ASL_COMPILER)/aslcompiler.l + +$(OBJDIR)/aslcompilerparse.c $(OBJDIR)/aslcompiler.y.h : $(OBJDIR)/aslcompiler.y + $(call safe_yacc,AslCompiler,$<,$@) + +$(OBJDIR)/dtparserlex.c : $(ASL_COMPILER)/dtparser.l $(OBJDIR)/dtparser.y.h + $(LEX) $(LFLAGS) -PDtParser -o$@ $< + +$(OBJDIR)/dtparserparse.c $(OBJDIR)/dtparser.y.h : $(ASL_COMPILER)/dtparser.y + $(call safe_yacc,DtParser,$<,$@) + +$(OBJDIR)/prparserlex.c : $(ASL_COMPILER)/prparser.l $(OBJDIR)/prparser.y.h + $(LEX) $(LFLAGS) -PPrParser -o$@ $< + +$(OBJDIR)/prparserparse.c $(OBJDIR)/prparser.y.h : $(ASL_COMPILER)/prparser.y + $(call safe_yacc,PrParser,$<,$@) + +# +# Parsers and Lexers - final object files +# +# Cannot use the common compile warning flags since the C files are created +# by the utilities above and they are not necessarily ANSI C, etc. +# +$(OBJDIR)/aslcompilerlex.o : $(OBJDIR)/aslcompilerlex.c + $(CC) -c $(CFLAGS) -Wall -Werror -o$@ $< + +$(OBJDIR)/aslcompilerparse.o : $(OBJDIR)/aslcompilerparse.c + $(CC) -c $(CFLAGS) -Wall -Werror -o$@ $< + +$(OBJDIR)/dtparserlex.o : $(OBJDIR)/dtparserlex.c + $(CC) -c $(CFLAGS) -Wall -Werror -o$@ $< + +$(OBJDIR)/dtparserparse.o : $(OBJDIR)/dtparserparse.c + $(CC) -c $(CFLAGS) -Wall -Werror -o$@ $< + +$(OBJDIR)/prparserlex.o : $(OBJDIR)/prparserlex.c + $(CC) -c $(CFLAGS) -Wall -Werror -o$@ $< + +$(OBJDIR)/prparserparse.o : $(OBJDIR)/prparserparse.c + $(CC) -c $(CFLAGS) -Wall -Werror -o$@ $< diff --git a/third_party/lib/acpica/generate/unix/readme.txt b/third_party/lib/acpica/generate/unix/readme.txt new file mode 100644 index 000000000..c68b936bb --- /dev/null +++ b/third_party/lib/acpica/generate/unix/readme.txt @@ -0,0 +1,120 @@ +Generic Unix ACPICA makefiles +----------------------------- + +These makefiles are intended to generate the ACPICA utilities in +a Unix-like environment, with the original ACPICA code (not linuxized), +and in the original (git tree) ACPICA directory structure. + +Windows binary versions of these tools are available at: + +http://www.acpica.org/downloads/binary_tools.php + +Documentation is available at acpica.org: + +http://www.acpica.org/documentation/ + +The top level makefile will generate the following utilities: +Note: These utilities are tested and supported as 32-bit versions +only. + +acpibin +acpiexec +acpihelp +acpinames +acpisrc +acpixtract +iasl + +To generate all utilities: + +cd acpica/generate/unix +make +make install /* install all binaries to /usr/bin */ + + +Requirements +------------ + +make +gcc compiler (4+) +bison or yacc +flex or lex + + +Configuration +------------- + +The Makefile.config file contains the configuration information: + +HOST = _CYGWIN /* Host system, must appear in acenv.h */ +CC = gcc /* C compiler */ +ACPICA_SRC = ../../../source /* Location of acpica source tree */ + + +Intermediate Files +------------------ + +The intermediate files for each utility (.o, etc.) are placed in the +subdirectory corresponding to each utility, not in the source code +tree itself. This prevents collisions when different utilities compile +the same source modules with different options. + + +Output +------ + +The executable utilities are copied to the local bin directory. + +"make install" will install the binaries to /usr/bin + + + +1) acpibin, an AML file tool + +acpibin compares AML files, dumps AML binary files to text files, +extracts binary AML from text files, and other AML file +manipulation. + + +2) acpiexec, a user-space AML interpreter + +acpiexec allows the loading of ACPI tables and execution of control +methods from user space. Useful for debugging AML code and testing +the AML interpreter. Hardware access is simulated. + + +3) acpihelp, syntax help for ASL operators and reserved names + +acpihelp displays the syntax for all of the ASL operators, as well +as information about the ASL/ACPI reserved names (4-char names that +start with underscore.) + + +4) acpinames, load and dump acpi namespace + +acpinames loads an ACPI namespace from a binary ACPI table file. +This is a smaller version of acpiexec that loads an acpi table and +dumps the resulting namespace. It is primarily intended to demonstrate +the configurability of ACPICA. + + +5) acpisrc, a source code conversion tool + +acpisrc converts the standard form of the acpica source release (included +here) into a version that meets Linux coding guidelines. This consists +mainly of performing a series of string replacements and transformations +to the code. It can also be used to clean the acpica source and generate +statistics. + + +6) acpixtract, extract binary ACPI tables from an acpidump + +acpixtract is used to extract binary ACPI tables from the ASCII text +output of an acpidump utility (available on several different hosts.) + + +7) iasl, an optimizing ASL compiler/disassembler + +iasl compiles ASL (ACPI Source Language) into AML (ACPI Machine +Language). This AML is suitable for inclusion as a DSDT in system +firmware. It also can disassemble AML, for debugging purposes. diff --git a/third_party/lib/acpica/rules.mk b/third_party/lib/acpica/rules.mk new file mode 100644 index 000000000..6f272f01b --- /dev/null +++ b/third_party/lib/acpica/rules.mk @@ -0,0 +1,209 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +GLOBAL_INCLUDES += $(LOCAL_DIR)/source/include + +# Disable these two warnings to prevent ACPICA from cluttering the +# build output +ifneq ($(CLANG),1) +MODULE_CFLAGS += -Wno-discarded-qualifiers +endif +MODULE_CFLAGS += -Wno-strict-aliasing + +MODULE_SRCS += \ + $(LOCAL_DIR)/source/components/hardware/hwacpi.c \ + $(LOCAL_DIR)/source/components/hardware/hwxfsleep.c \ + $(LOCAL_DIR)/source/components/hardware/hwgpe.c \ + $(LOCAL_DIR)/source/components/hardware/hwxface.c \ + $(LOCAL_DIR)/source/components/hardware/hwregs.c \ + $(LOCAL_DIR)/source/components/hardware/hwpci.c \ + $(LOCAL_DIR)/source/components/hardware/hwvalid.c \ + $(LOCAL_DIR)/source/components/hardware/hwtimer.c \ + $(LOCAL_DIR)/source/components/hardware/hwesleep.c \ + $(LOCAL_DIR)/source/components/hardware/hwsleep.c \ + $(LOCAL_DIR)/source/components/executer/exstore.c \ + $(LOCAL_DIR)/source/components/executer/exoparg3.c \ + $(LOCAL_DIR)/source/components/executer/exutils.c \ + $(LOCAL_DIR)/source/components/executer/exfield.c \ + $(LOCAL_DIR)/source/components/executer/exnames.c \ + $(LOCAL_DIR)/source/components/executer/exstoren.c \ + $(LOCAL_DIR)/source/components/executer/exstorob.c \ + $(LOCAL_DIR)/source/components/executer/exresop.c \ + $(LOCAL_DIR)/source/components/executer/exfldio.c \ + $(LOCAL_DIR)/source/components/executer/exmutex.c \ + $(LOCAL_DIR)/source/components/executer/exdump.c \ + $(LOCAL_DIR)/source/components/executer/exoparg2.c \ + $(LOCAL_DIR)/source/components/executer/exsystem.c \ + $(LOCAL_DIR)/source/components/executer/exmisc.c \ + $(LOCAL_DIR)/source/components/executer/exoparg6.c \ + $(LOCAL_DIR)/source/components/executer/excreate.c \ + $(LOCAL_DIR)/source/components/executer/exresnte.c \ + $(LOCAL_DIR)/source/components/executer/exconfig.c \ + $(LOCAL_DIR)/source/components/executer/exresolv.c \ + $(LOCAL_DIR)/source/components/executer/exregion.c \ + $(LOCAL_DIR)/source/components/executer/exconvrt.c \ + $(LOCAL_DIR)/source/components/executer/exprep.c \ + $(LOCAL_DIR)/source/components/executer/exdebug.c \ + $(LOCAL_DIR)/source/components/executer/extrace.c \ + $(LOCAL_DIR)/source/components/executer/exoparg1.c \ + $(LOCAL_DIR)/source/components/namespace/nsnames.c \ + $(LOCAL_DIR)/source/components/namespace/nspredef.c \ + $(LOCAL_DIR)/source/components/namespace/nsaccess.c \ + $(LOCAL_DIR)/source/components/namespace/nsrepair2.c \ + $(LOCAL_DIR)/source/components/namespace/nsprepkg.c \ + $(LOCAL_DIR)/source/components/namespace/nswalk.c \ + $(LOCAL_DIR)/source/components/namespace/nsxfeval.c \ + $(LOCAL_DIR)/source/components/namespace/nsconvert.c \ + $(LOCAL_DIR)/source/components/namespace/nsdumpdv.c \ + $(LOCAL_DIR)/source/components/namespace/nsparse.c \ + $(LOCAL_DIR)/source/components/namespace/nsxfname.c \ + $(LOCAL_DIR)/source/components/namespace/nsdump.c \ + $(LOCAL_DIR)/source/components/namespace/nsarguments.c \ + $(LOCAL_DIR)/source/components/namespace/nssearch.c \ + $(LOCAL_DIR)/source/components/namespace/nsalloc.c \ + $(LOCAL_DIR)/source/components/namespace/nsutils.c \ + $(LOCAL_DIR)/source/components/namespace/nsinit.c \ + $(LOCAL_DIR)/source/components/namespace/nsobject.c \ + $(LOCAL_DIR)/source/components/namespace/nsload.c \ + $(LOCAL_DIR)/source/components/namespace/nseval.c \ + $(LOCAL_DIR)/source/components/namespace/nsrepair.c \ + $(LOCAL_DIR)/source/components/namespace/nsxfobj.c \ + $(LOCAL_DIR)/source/components/resources/rsaddr.c \ + $(LOCAL_DIR)/source/components/resources/rscalc.c \ + $(LOCAL_DIR)/source/components/resources/rsserial.c \ + $(LOCAL_DIR)/source/components/resources/rscreate.c \ + $(LOCAL_DIR)/source/components/resources/rsutils.c \ + $(LOCAL_DIR)/source/components/resources/rslist.c \ + $(LOCAL_DIR)/source/components/resources/rsmemory.c \ + $(LOCAL_DIR)/source/components/resources/rsinfo.c \ + $(LOCAL_DIR)/source/components/resources/rsxface.c \ + $(LOCAL_DIR)/source/components/resources/rsmisc.c \ + $(LOCAL_DIR)/source/components/resources/rsio.c \ + $(LOCAL_DIR)/source/components/resources/rsdumpinfo.c \ + $(LOCAL_DIR)/source/components/resources/rsirq.c \ + $(LOCAL_DIR)/source/components/tables/tbinstal.c \ + $(LOCAL_DIR)/source/components/tables/tbprint.c \ + $(LOCAL_DIR)/source/components/tables/tbfadt.c \ + $(LOCAL_DIR)/source/components/tables/tbxfroot.c \ + $(LOCAL_DIR)/source/components/tables/tbfind.c \ + $(LOCAL_DIR)/source/components/tables/tbxface.c \ + $(LOCAL_DIR)/source/components/tables/tbxfload.c \ + $(LOCAL_DIR)/source/components/tables/tbdata.c \ + $(LOCAL_DIR)/source/components/tables/tbutils.c \ + $(LOCAL_DIR)/source/components/parser/psloop.c \ + $(LOCAL_DIR)/source/components/parser/psutils.c \ + $(LOCAL_DIR)/source/components/parser/pstree.c \ + $(LOCAL_DIR)/source/components/parser/pswalk.c \ + $(LOCAL_DIR)/source/components/parser/psargs.c \ + $(LOCAL_DIR)/source/components/parser/psopinfo.c \ + $(LOCAL_DIR)/source/components/parser/psxface.c \ + $(LOCAL_DIR)/source/components/parser/psscope.c \ + $(LOCAL_DIR)/source/components/parser/psobject.c \ + $(LOCAL_DIR)/source/components/parser/psparse.c \ + $(LOCAL_DIR)/source/components/parser/psopcode.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsdebug.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsobject.c \ + $(LOCAL_DIR)/source/components/dispatcher/dswexec.c \ + $(LOCAL_DIR)/source/components/dispatcher/dswscope.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsinit.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsutils.c \ + $(LOCAL_DIR)/source/components/dispatcher/dswstate.c \ + $(LOCAL_DIR)/source/components/dispatcher/dswload2.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsfield.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsmthdat.c \ + $(LOCAL_DIR)/source/components/dispatcher/dscontrol.c \ + $(LOCAL_DIR)/source/components/dispatcher/dswload.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsopcode.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsargs.c \ + $(LOCAL_DIR)/source/components/dispatcher/dsmethod.c \ + $(LOCAL_DIR)/source/components/events/evxfevnt.c \ + $(LOCAL_DIR)/source/components/events/evgpeblk.c \ + $(LOCAL_DIR)/source/components/events/evgpe.c \ + $(LOCAL_DIR)/source/components/events/evxfgpe.c \ + $(LOCAL_DIR)/source/components/events/evrgnini.c \ + $(LOCAL_DIR)/source/components/events/evgpeutil.c \ + $(LOCAL_DIR)/source/components/events/evglock.c \ + $(LOCAL_DIR)/source/components/events/evregion.c \ + $(LOCAL_DIR)/source/components/events/evxfregn.c \ + $(LOCAL_DIR)/source/components/events/evevent.c \ + $(LOCAL_DIR)/source/components/events/evsci.c \ + $(LOCAL_DIR)/source/components/events/evgpeinit.c \ + $(LOCAL_DIR)/source/components/events/evhandler.c \ + $(LOCAL_DIR)/source/components/events/evmisc.c \ + $(LOCAL_DIR)/source/components/events/evxface.c \ + $(LOCAL_DIR)/source/components/utilities/utxferror.c \ + $(LOCAL_DIR)/source/components/utilities/utxfmutex.c \ + $(LOCAL_DIR)/source/components/utilities/utmisc.c \ + $(LOCAL_DIR)/source/components/utilities/utmutex.c \ + $(LOCAL_DIR)/source/components/utilities/utbuffer.c \ + $(LOCAL_DIR)/source/components/utilities/utobject.c \ + $(LOCAL_DIR)/source/components/utilities/uterror.c \ + $(LOCAL_DIR)/source/components/utilities/utstring.c \ + $(LOCAL_DIR)/source/components/utilities/utmath.c \ + $(LOCAL_DIR)/source/components/utilities/utpredef.c \ + $(LOCAL_DIR)/source/components/utilities/utprint.c \ + $(LOCAL_DIR)/source/components/utilities/utdecode.c \ + $(LOCAL_DIR)/source/components/utilities/utosi.c \ + $(LOCAL_DIR)/source/components/utilities/utdebug.c \ + $(LOCAL_DIR)/source/components/utilities/utaddress.c \ + $(LOCAL_DIR)/source/components/utilities/utuuid.c \ + $(LOCAL_DIR)/source/components/utilities/utcache.c \ + $(LOCAL_DIR)/source/components/utilities/utexcep.c \ + $(LOCAL_DIR)/source/components/utilities/uttrack.c \ + $(LOCAL_DIR)/source/components/utilities/uthex.c \ + $(LOCAL_DIR)/source/components/utilities/uteval.c \ + $(LOCAL_DIR)/source/components/utilities/utxface.c \ + $(LOCAL_DIR)/source/components/utilities/utownerid.c \ + $(LOCAL_DIR)/source/components/utilities/utstate.c \ + $(LOCAL_DIR)/source/components/utilities/utlock.c \ + $(LOCAL_DIR)/source/components/utilities/utnonansi.c \ + $(LOCAL_DIR)/source/components/utilities/utdelete.c \ + $(LOCAL_DIR)/source/components/utilities/utresrc.c \ + $(LOCAL_DIR)/source/components/utilities/utcopy.c \ + $(LOCAL_DIR)/source/components/utilities/utalloc.c \ + $(LOCAL_DIR)/source/components/utilities/utxfinit.c \ + $(LOCAL_DIR)/source/components/utilities/utglobal.c \ + $(LOCAL_DIR)/source/components/utilities/utinit.c \ + $(LOCAL_DIR)/source/components/utilities/utclib.c \ + $(LOCAL_DIR)/source/components/utilities/utids.c \ + $(LOCAL_DIR)/source/common/getopt.c \ + $(LOCAL_DIR)/source/common/ahpredef.c \ + $(LOCAL_DIR)/source/common/ahids.c \ + $(LOCAL_DIR)/source/common/ahtable.c \ + $(LOCAL_DIR)/source/os_specific/service_layers/osmagenta.c + + # We don't use the disassembler + #$(LOCAL_DIR)/source/components/disassembler/dmopcode.c \ + $(LOCAL_DIR)/source/components/disassembler/dmresrcl2.c \ + $(LOCAL_DIR)/source/components/disassembler/dmresrcl.c \ + $(LOCAL_DIR)/source/components/disassembler/dmresrcs.c \ + $(LOCAL_DIR)/source/components/disassembler/dmbuffer.c \ + $(LOCAL_DIR)/source/components/disassembler/dmcstyle.c \ + $(LOCAL_DIR)/source/components/disassembler/dmutils.c \ + $(LOCAL_DIR)/source/components/disassembler/dmresrc.c \ + $(LOCAL_DIR)/source/components/disassembler/dmdeferred.c \ + $(LOCAL_DIR)/source/components/disassembler/dmnames.c \ + $(LOCAL_DIR)/source/components/disassembler/dmwalk.c \ + # We don't use the debugger + #$(LOCAL_DIR)/source/components/resources/rsdump.c \ + #$(LOCAL_DIR)/source/components/debugger/dbconvert.c \ + $(LOCAL_DIR)/source/components/debugger/dbnames.c \ + $(LOCAL_DIR)/source/components/debugger/dbexec.c \ + $(LOCAL_DIR)/source/components/debugger/dbdisply.c \ + $(LOCAL_DIR)/source/components/debugger/dbhistry.c \ + $(LOCAL_DIR)/source/components/debugger/dbutils.c \ + $(LOCAL_DIR)/source/components/debugger/dbfileio.c \ + $(LOCAL_DIR)/source/components/debugger/dbcmds.c \ + $(LOCAL_DIR)/source/components/debugger/dbtest.c \ + $(LOCAL_DIR)/source/components/debugger/dbinput.c \ + $(LOCAL_DIR)/source/components/debugger/dbmethod.c \ + $(LOCAL_DIR)/source/components/debugger/dbobject.c \ + $(LOCAL_DIR)/source/components/debugger/dbxface.c \ + $(LOCAL_DIR)/source/components/debugger/dbstats.c \ + # These depend on file io + #$(LOCAL_DIR)/source/common/cmfsize.c \ + $(LOCAL_DIR)/source/common/acfileio.c \ + $(LOCAL_DIR)/source/common/acgetline.c \ + +include make/module.mk diff --git a/third_party/lib/acpica/source/common/acfileio.c b/third_party/lib/acpica/source/common/acfileio.c new file mode 100644 index 000000000..2c69c2399 --- /dev/null +++ b/third_party/lib/acpica/source/common/acfileio.c @@ -0,0 +1,535 @@ +/****************************************************************************** + * + * Module Name: acfileio - Get ACPI tables from file + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include "actables.h" +#include "acutils.h" +#include + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("acfileio") + + +/* Local prototypes */ + +static ACPI_STATUS +AcGetOneTableFromFile ( + char *Filename, + FILE *File, + UINT8 GetOnlyAmlTables, + ACPI_TABLE_HEADER **Table); + +static ACPI_STATUS +AcCheckTextModeCorruption ( + ACPI_TABLE_HEADER *Table); + + +/******************************************************************************* + * + * FUNCTION: AcGetAllTablesFromFile + * + * PARAMETERS: Filename - Table filename + * GetOnlyAmlTables - TRUE if the tables must be AML tables + * ReturnListHead - Where table list is returned + * + * RETURN: Status + * + * DESCRIPTION: Get all ACPI tables from within a single file. + * + ******************************************************************************/ + +ACPI_STATUS +AcGetAllTablesFromFile ( + char *Filename, + UINT8 GetOnlyAmlTables, + ACPI_NEW_TABLE_DESC **ReturnListHead) +{ + ACPI_NEW_TABLE_DESC *ListHead = NULL; + ACPI_NEW_TABLE_DESC *ListTail = NULL; + ACPI_NEW_TABLE_DESC *TableDesc; + FILE *File; + ACPI_TABLE_HEADER *Table = NULL; + UINT32 FileSize; + ACPI_STATUS Status = AE_OK; + + + File = fopen (Filename, "rb"); + if (!File) + { + perror ("Could not open input file"); + if (errno == ENOENT) + { + return (AE_NOT_EXIST); + } + + return (AE_ERROR); + } + + /* Get the file size */ + + FileSize = CmGetFileSize (File); + if (FileSize == ACPI_UINT32_MAX) + { + return (AE_ERROR); + } + + fprintf (stderr, + "Input file %s, Length 0x%X (%u) bytes\n", + Filename, FileSize, FileSize); + + /* We must have at least one ACPI table header */ + + if (FileSize < sizeof (ACPI_TABLE_HEADER)) + { + return (AE_BAD_HEADER); + } + + /* Check for an non-binary file */ + + if (!AcIsFileBinary (File)) + { + fprintf (stderr, + " %s: File does not appear to contain a valid AML table\n", + Filename); + return (AE_TYPE); + } + + /* Read all tables within the file */ + + while (ACPI_SUCCESS (Status)) + { + /* Get one entire ACPI table */ + + Status = AcGetOneTableFromFile ( + Filename, File, GetOnlyAmlTables, &Table); + + if (Status == AE_CTRL_TERMINATE) + { + Status = AE_OK; + break; + } + else if (Status == AE_TYPE) + { + return (AE_OK); + } + else if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Print table header for iASL/disassembler only */ + +#ifdef ACPI_ASL_COMPILER + + AcpiTbPrintTableHeader (0, Table); +#endif + + /* Allocate and link a table descriptor */ + + TableDesc = AcpiOsAllocate (sizeof (ACPI_NEW_TABLE_DESC)); + TableDesc->Table = Table; + TableDesc->Next = NULL; + + /* Link at the end of the local table list */ + + if (!ListHead) + { + ListHead = TableDesc; + ListTail = TableDesc; + } + else + { + ListTail->Next = TableDesc; + ListTail = TableDesc; + } + } + + /* Add the local table list to the end of the global list */ + + if (*ReturnListHead) + { + ListTail = *ReturnListHead; + while (ListTail->Next) + { + ListTail = ListTail->Next; + } + + ListTail->Next = ListHead; + } + else + { + *ReturnListHead = ListHead; + } + + fclose(File); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcGetOneTableFromFile + * + * PARAMETERS: Filename - File where table is located + * File - Open FILE pointer to Filename + * GetOnlyAmlTables - TRUE if the tables must be AML tables. + * ReturnTable - Where a pointer to the table is returned + * + * RETURN: Status + * + * DESCRIPTION: Read the next ACPI table from a file. Implements support + * for multiple tables within a single file. File must already + * be open. + * + * Note: Loading an RSDP is not supported. + * + ******************************************************************************/ + +static ACPI_STATUS +AcGetOneTableFromFile ( + char *Filename, + FILE *File, + UINT8 GetOnlyAmlTables, + ACPI_TABLE_HEADER **ReturnTable) +{ + ACPI_STATUS Status = AE_OK; + ACPI_TABLE_HEADER TableHeader; + ACPI_TABLE_HEADER *Table; + INT32 Count; + long TableOffset; + + + *ReturnTable = NULL; + + /* Get the table header to examine signature and length */ + + TableOffset = ftell (File); + Count = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File); + if (Count != sizeof (ACPI_TABLE_HEADER)) + { + return (AE_CTRL_TERMINATE); + } + + /* Validate the table signature/header (limited ASCII chars) */ + + Status = AcValidateTableHeader (File, TableOffset); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (GetOnlyAmlTables) + { + /* Table must be an AML table (DSDT/SSDT) or FADT */ + + if (!ACPI_COMPARE_NAME (TableHeader.Signature, ACPI_SIG_FADT) && + !AcpiUtIsAmlTable (&TableHeader)) + { + fprintf (stderr, + " %s: Table [%4.4s] is not an AML table - ignoring\n", + Filename, TableHeader.Signature); + + return (AE_TYPE); + } + } + + /* Allocate a buffer for the entire table */ + + Table = AcpiOsAllocate ((size_t) TableHeader.Length); + if (!Table) + { + return (AE_NO_MEMORY); + } + + /* Read the entire ACPI table, including header */ + + fseek (File, TableOffset, SEEK_SET); + + Count = fread (Table, 1, TableHeader.Length, File); + if (Count != (INT32) TableHeader.Length) + { + Status = AE_ERROR; + goto ErrorExit; + } + + /* Validate the checksum (just issue a warning) */ + + Status = AcpiTbVerifyChecksum (Table, TableHeader.Length); + if (ACPI_FAILURE (Status)) + { + Status = AcCheckTextModeCorruption (Table); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + } + + *ReturnTable = Table; + return (AE_OK); + + +ErrorExit: + AcpiOsFree (Table); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcIsFileBinary + * + * PARAMETERS: File - Open input file + * + * RETURN: TRUE if file appears to be binary + * + * DESCRIPTION: Scan a file for any non-ASCII bytes. + * + * Note: Maintains current file position. + * + ******************************************************************************/ + +BOOLEAN +AcIsFileBinary ( + FILE *File) +{ + UINT8 Byte; + BOOLEAN IsBinary = FALSE; + long FileOffset; + + + /* Scan entire file for any non-ASCII bytes */ + + FileOffset = ftell (File); + while (fread (&Byte, 1, 1, File) == 1) + { + if (!isprint (Byte) && !isspace (Byte)) + { + IsBinary = TRUE; + goto Exit; + } + } + +Exit: + fseek (File, FileOffset, SEEK_SET); + return (IsBinary); +} + + +/******************************************************************************* + * + * FUNCTION: AcValidateTableHeader + * + * PARAMETERS: File - Open input file + * + * RETURN: Status + * + * DESCRIPTION: Determine if a file seems to contain one or more binary ACPI + * tables, via the + * following checks on what would be the table header: + * 1) File must be at least as long as an ACPI_TABLE_HEADER + * 2) There must be enough room in the file to hold entire table + * 3) Signature, OemId, OemTableId, AslCompilerId must be ASCII + * + * Note: There can be multiple definition blocks per file, so we cannot + * expect/compare the file size to be equal to the table length. 12/2015. + * + * Note: Maintains current file position. + * + ******************************************************************************/ + +ACPI_STATUS +AcValidateTableHeader ( + FILE *File, + long TableOffset) +{ + ACPI_TABLE_HEADER TableHeader; + size_t Actual; + long OriginalOffset; + UINT32 FileSize; + UINT32 i; + + + ACPI_FUNCTION_TRACE ("AcValidateTableHeader"); + + + /* Read a potential table header */ + + OriginalOffset = ftell (File); + fseek (File, TableOffset, SEEK_SET); + + Actual = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File); + fseek (File, OriginalOffset, SEEK_SET); + + if (Actual < sizeof (ACPI_TABLE_HEADER)) + { + return (AE_ERROR); + } + + /* Validate the signature (limited ASCII chars) */ + + if (!AcpiIsValidSignature (TableHeader.Signature)) + { + fprintf (stderr, "Invalid table signature: 0x%8.8X\n", + *ACPI_CAST_PTR (UINT32, TableHeader.Signature)); + return (AE_BAD_SIGNATURE); + } + + /* Validate table length against bytes remaining in the file */ + + FileSize = CmGetFileSize (File); + if (TableHeader.Length > (UINT32) (FileSize - TableOffset)) + { + fprintf (stderr, "Table [%4.4s] is too long for file - " + "needs: 0x%.2X, remaining in file: 0x%.2X\n", + TableHeader.Signature, TableHeader.Length, + (UINT32) (FileSize - TableOffset)); + return (AE_BAD_HEADER); + } + + /* + * These fields must be ASCII: OemId, OemTableId, AslCompilerId. + * We allow a NULL terminator in OemId and OemTableId. + */ + for (i = 0; i < ACPI_NAME_SIZE; i++) + { + if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i])) + { + goto BadCharacters; + } + } + + for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++) + { + if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i])) + { + goto BadCharacters; + } + } + + for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++) + { + if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i])) + { + goto BadCharacters; + } + } + + return (AE_OK); + + +BadCharacters: + + ACPI_WARNING ((AE_INFO, + "Table header for [%4.4s] has invalid ASCII character(s)", + TableHeader.Signature)); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcCheckTextModeCorruption + * + * PARAMETERS: Table - Table buffer starting with table header + * + * RETURN: Status + * + * DESCRIPTION: Check table for text mode file corruption where all linefeed + * characters (LF) have been replaced by carriage return linefeed + * pairs (CR/LF). + * + ******************************************************************************/ + +static ACPI_STATUS +AcCheckTextModeCorruption ( + ACPI_TABLE_HEADER *Table) +{ + UINT32 i; + UINT32 Pairs = 0; + UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Table); + + + /* Scan entire table to determine if each LF has been prefixed with a CR */ + + for (i = 1; i < Table->Length; i++) + { + if (Buffer[i] == 0x0A) + { + if (Buffer[i - 1] != 0x0D) + { + /* The LF does not have a preceding CR, table not corrupted */ + + return (AE_OK); + } + else + { + /* Found a CR/LF pair */ + + Pairs++; + } + + i++; + } + } + + if (!Pairs) + { + return (AE_OK); + } + + /* + * Entire table scanned, each CR is part of a CR/LF pair -- + * meaning that the table was treated as a text file somewhere. + * + * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the + * original table are left untouched by the text conversion process -- + * meaning that we cannot simply replace CR/LF pairs with LFs. + */ + AcpiOsPrintf ("Table has been corrupted by text mode conversion\n"); + AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs); + AcpiOsPrintf ("Table cannot be repaired!\n"); + + return (AE_BAD_VALUE); +} diff --git a/third_party/lib/acpica/source/common/acgetline.c b/third_party/lib/acpica/source/common/acgetline.c new file mode 100644 index 000000000..b08fb637d --- /dev/null +++ b/third_party/lib/acpica/source/common/acgetline.c @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * Module Name: acgetline - local line editing + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acparser.h" +#include "acdebug.h" + +#include + +/* + * This is an os-independent implementation of line-editing services needed + * by the AcpiExec utility. It uses getchar() and putchar() and the existing + * history support provided by the AML debugger. It assumes that the terminal + * is in the correct line-editing mode such as raw and noecho. The OSL + * interface AcpiOsInitialize should do this. AcpiOsTerminate should put the + * terminal back into the original mode. + */ +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("acgetline") + + +/* Local prototypes */ + +static void +AcpiAcClearLine ( + UINT32 EndOfLine, + UINT32 CursorPosition); + +/* Various ASCII constants */ + +#define _ASCII_NUL 0 +#define _ASCII_BACKSPACE 0x08 +#define _ASCII_TAB 0x09 +#define _ASCII_ESCAPE 0x1B +#define _ASCII_SPACE 0x20 +#define _ASCII_LEFT_BRACKET 0x5B +#define _ASCII_DEL 0x7F +#define _ASCII_UP_ARROW 'A' +#define _ASCII_DOWN_ARROW 'B' +#define _ASCII_RIGHT_ARROW 'C' +#define _ASCII_LEFT_ARROW 'D' +#define _ASCII_NEWLINE '\n' + +extern UINT32 AcpiGbl_NextCmdNum; + +/* Erase a single character on the input command line */ + +#define ACPI_CLEAR_CHAR() \ + putchar (_ASCII_BACKSPACE); \ + putchar (_ASCII_SPACE); \ + putchar (_ASCII_BACKSPACE); + +/* Backup cursor by Count positions */ + +#define ACPI_BACKUP_CURSOR(i, Count) \ + for (i = 0; i < (Count); i++) \ + {putchar (_ASCII_BACKSPACE);} + + +/****************************************************************************** + * + * FUNCTION: AcpiAcClearLine + * + * PARAMETERS: EndOfLine - Current end-of-line index + * CursorPosition - Current cursor position within line + * + * RETURN: None + * + * DESCRIPTION: Clear the entire command line the hard way, but probably the + * most portable. + * + *****************************************************************************/ + +static void +AcpiAcClearLine ( + UINT32 EndOfLine, + UINT32 CursorPosition) +{ + UINT32 i; + + + if (CursorPosition < EndOfLine) + { + /* Clear line from current position to end of line */ + + for (i = 0; i < (EndOfLine - CursorPosition); i++) + { + putchar (' '); + } + } + + /* Clear the entire line */ + + for (; EndOfLine > 0; EndOfLine--) + { + ACPI_CLEAR_CHAR (); + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetLine + * + * PARAMETERS: Buffer - Where to return the command line + * BufferLength - Maximum length of Buffer + * BytesRead - Where the actual byte count is returned + * + * RETURN: Status and actual bytes read + * + * DESCRIPTION: Get the next input line from the terminal. NOTE: terminal + * is expected to be in a mode that supports line-editing (raw, + * noecho). This function is intended to be very portable. Also, + * it uses the history support implemented in the AML debugger. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead) +{ + char *NextCommand; + UINT32 MaxCommandIndex = AcpiGbl_NextCmdNum - 1; + UINT32 CurrentCommandIndex = MaxCommandIndex; + UINT32 PreviousCommandIndex = MaxCommandIndex; + int InputChar; + UINT32 CursorPosition = 0; + UINT32 EndOfLine = 0; + UINT32 i; + + + /* Always clear the line buffer before we read a new line */ + + memset (Buffer, 0, BufferLength); + + /* + * This loop gets one character at a time (except for esc sequences) + * until a newline or error is detected. + * + * Note: Don't attempt to write terminal control ESC sequences, even + * though it makes certain things more difficult. + */ + while (1) + { + if (EndOfLine >= (BufferLength - 1)) + { + return (AE_BUFFER_OVERFLOW); + } + + InputChar = getchar (); + switch (InputChar) + { + default: /* This is the normal character case */ + + /* Echo the character (at EOL) and copy it to the line buffer */ + + if (EndOfLine == CursorPosition) + { + putchar (InputChar); + Buffer[EndOfLine] = (char) InputChar; + + EndOfLine++; + CursorPosition++; + Buffer[EndOfLine] = 0; + continue; + } + + /* Insert character into the middle of the buffer */ + + memmove (&Buffer[CursorPosition + 1], &Buffer[CursorPosition], + (EndOfLine - CursorPosition + 1)); + + Buffer [CursorPosition] = (char) InputChar; + Buffer [EndOfLine + 1] = 0; + + /* Display the new part of line starting at the new character */ + + fprintf (stdout, "%s", &Buffer[CursorPosition]); + + /* Restore cursor */ + + ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); + CursorPosition++; + EndOfLine++; + continue; + + case _ASCII_DEL: /* Backspace key */ + + if (!EndOfLine) /* Any characters on the command line? */ + { + continue; + } + + if (EndOfLine == CursorPosition) /* Erase the final character */ + { + ACPI_CLEAR_CHAR (); + EndOfLine--; + CursorPosition--; + continue; + } + + if (!CursorPosition) /* Do not backup beyond start of line */ + { + continue; + } + + /* Remove the character from the line */ + + memmove (&Buffer[CursorPosition - 1], &Buffer[CursorPosition], + (EndOfLine - CursorPosition + 1)); + + /* Display the new part of line starting at the new character */ + + putchar (_ASCII_BACKSPACE); + fprintf (stdout, "%s ", &Buffer[CursorPosition - 1]); + + /* Restore cursor */ + + ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition + 1); + EndOfLine--; + + if (CursorPosition > 0) + { + CursorPosition--; + } + continue; + + case _ASCII_NEWLINE: /* Normal exit case at end of command line */ + case _ASCII_NUL: + + /* Return the number of bytes in the command line string */ + + if (BytesRead) + { + *BytesRead = EndOfLine; + } + + /* Echo, terminate string buffer, and exit */ + + putchar (InputChar); + Buffer[EndOfLine] = 0; + return (AE_OK); + + case _ASCII_TAB: + + /* Ignore */ + + continue; + + case EOF: + + return (AE_ERROR); + + case _ASCII_ESCAPE: + + /* Check for escape sequences of the form "ESC[x" */ + + InputChar = getchar (); + if (InputChar != _ASCII_LEFT_BRACKET) + { + continue; /* Ignore this ESC, does not have the '[' */ + } + + /* Get the code following the ESC [ */ + + InputChar = getchar (); /* Backup one character */ + switch (InputChar) + { + case _ASCII_LEFT_ARROW: + + if (CursorPosition > 0) + { + putchar (_ASCII_BACKSPACE); + CursorPosition--; + } + continue; + + case _ASCII_RIGHT_ARROW: + /* + * Move one character forward. Do this without sending + * ESC sequence to the terminal for max portability. + */ + if (CursorPosition < EndOfLine) + { + /* Backup to start of line and print the entire line */ + + ACPI_BACKUP_CURSOR (i, CursorPosition); + fprintf (stdout, "%s", Buffer); + + /* Backup to where the cursor should be */ + + CursorPosition++; + ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); + } + continue; + + case _ASCII_UP_ARROW: + + /* If no commands available or at start of history list, ignore */ + + if (!CurrentCommandIndex) + { + continue; + } + + /* Manage our up/down progress */ + + if (CurrentCommandIndex > PreviousCommandIndex) + { + CurrentCommandIndex = PreviousCommandIndex; + } + + /* Get the historical command from the debugger */ + + NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); + if (!NextCommand) + { + return (AE_ERROR); + } + + /* Make this the active command and echo it */ + + AcpiAcClearLine (EndOfLine, CursorPosition); + strcpy (Buffer, NextCommand); + fprintf (stdout, "%s", Buffer); + EndOfLine = CursorPosition = strlen (Buffer); + + PreviousCommandIndex = CurrentCommandIndex; + CurrentCommandIndex--; + continue; + + case _ASCII_DOWN_ARROW: + + if (!MaxCommandIndex) /* Any commands available? */ + { + continue; + } + + /* Manage our up/down progress */ + + if (CurrentCommandIndex < PreviousCommandIndex) + { + CurrentCommandIndex = PreviousCommandIndex; + } + + /* If we are the end of the history list, output a clear new line */ + + if ((CurrentCommandIndex + 1) > MaxCommandIndex) + { + AcpiAcClearLine (EndOfLine, CursorPosition); + EndOfLine = CursorPosition = 0; + PreviousCommandIndex = CurrentCommandIndex; + continue; + } + + PreviousCommandIndex = CurrentCommandIndex; + CurrentCommandIndex++; + + /* Get the historical command from the debugger */ + + NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); + if (!NextCommand) + { + return (AE_ERROR); + } + + /* Make this the active command and echo it */ + + AcpiAcClearLine (EndOfLine, CursorPosition); + strcpy (Buffer, NextCommand); + fprintf (stdout, "%s", Buffer); + EndOfLine = CursorPosition = strlen (Buffer); + continue; + + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + /* + * Ignore the various keys like insert/delete/home/end, etc. + * But we must eat the final character of the ESC sequence. + */ + InputChar = getchar (); + continue; + + default: + + /* Ignore random escape sequences that we don't care about */ + + continue; + } + continue; + } + } +} diff --git a/third_party/lib/acpica/source/common/adfile.c b/third_party/lib/acpica/source/common/adfile.c new file mode 100644 index 000000000..78f29fd9f --- /dev/null +++ b/third_party/lib/acpica/source/common/adfile.c @@ -0,0 +1,358 @@ +/****************************************************************************** + * + * Module Name: adfile - Application-level disassembler file support routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" + +#include + + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("adfile") + +/* Local prototypes */ + +static INT32 +AdWriteBuffer ( + char *Filename, + char *Buffer, + UINT32 Length); + +static char FilenameBuf[20]; + + +/****************************************************************************** + * + * FUNCTION: AfGenerateFilename + * + * PARAMETERS: Prefix - prefix string + * TableId - The table ID + * + * RETURN: Pointer to the completed string + * + * DESCRIPTION: Build an output filename from an ACPI table ID string + * + ******************************************************************************/ + +char * +AdGenerateFilename ( + char *Prefix, + char *TableId) +{ + UINT32 i; + UINT32 j; + + + for (i = 0; Prefix[i]; i++) + { + FilenameBuf[i] = Prefix[i]; + } + + FilenameBuf[i] = '_'; + i++; + + for (j = 0; j < 8 && (TableId[j] != ' ') && (TableId[j] != 0); i++, j++) + { + FilenameBuf[i] = TableId[j]; + } + + FilenameBuf[i] = 0; + strcat (FilenameBuf, FILE_SUFFIX_BINARY_TABLE); + return (FilenameBuf); +} + + +/****************************************************************************** + * + * FUNCTION: AfWriteBuffer + * + * PARAMETERS: Filename - name of file + * Buffer - data to write + * Length - length of data + * + * RETURN: Actual number of bytes written + * + * DESCRIPTION: Open a file and write out a single buffer + * + ******************************************************************************/ + +static INT32 +AdWriteBuffer ( + char *Filename, + char *Buffer, + UINT32 Length) +{ + FILE *File; + ACPI_SIZE Actual; + + + File = fopen (Filename, "wb"); + if (!File) + { + printf ("Could not open file %s\n", Filename); + return (-1); + } + + Actual = fwrite (Buffer, 1, (size_t) Length, File); + if (Actual != Length) + { + printf ("Could not write to file %s\n", Filename); + } + + fclose (File); + return ((INT32) Actual); +} + + +/****************************************************************************** + * + * FUNCTION: AfWriteTable + * + * PARAMETERS: Table - pointer to the ACPI table + * Length - length of the table + * TableName - the table signature + * OemTableID - from the table header + * + * RETURN: None + * + * DESCRIPTION: Dump the loaded tables to a file (or files) + * + ******************************************************************************/ + +void +AdWriteTable ( + ACPI_TABLE_HEADER *Table, + UINT32 Length, + char *TableName, + char *OemTableId) +{ + char *Filename; + + + Filename = AdGenerateFilename (TableName, OemTableId); + AdWriteBuffer (Filename, (char *) Table, Length); + + AcpiOsPrintf ("Table [%s] written to \"%s\"\n", TableName, Filename); +} + + +/******************************************************************************* + * + * FUNCTION: FlGenerateFilename + * + * PARAMETERS: InputFilename - Original ASL source filename + * Suffix - New extension. + * + * RETURN: New filename containing the original base + the new suffix + * + * DESCRIPTION: Generate a new filename from the ASL source filename and a new + * extension. Used to create the *.LST, *.TXT, etc. files. + * + ******************************************************************************/ + +char * +FlGenerateFilename ( + char *InputFilename, + char *Suffix) +{ + char *Position; + char *NewFilename; + char *DirectoryPosition; + + + /* + * Copy the original filename to a new buffer. Leave room for the worst + * case where we append the suffix, an added dot and the null terminator. + */ + NewFilename = UtStringCacheCalloc ((ACPI_SIZE) + strlen (InputFilename) + strlen (Suffix) + 2); + if (!NewFilename) + { + return (NULL); + } + + strcpy (NewFilename, InputFilename); + + /* Try to find the last dot in the filename */ + + DirectoryPosition = strrchr (NewFilename, '/'); + Position = strrchr (NewFilename, '.'); + + if (Position && (Position > DirectoryPosition)) + { + /* Tack on the new suffix */ + + Position++; + *Position = 0; + strcat (Position, Suffix); + } + else + { + /* No dot, add one and then the suffix */ + + strcat (NewFilename, "."); + strcat (NewFilename, Suffix); + } + + return (NewFilename); +} + + +/******************************************************************************* + * + * FUNCTION: FlStrdup + * + * DESCRIPTION: Local strdup function + * + ******************************************************************************/ + +static char * +FlStrdup ( + char *String) +{ + char *NewString; + + + NewString = UtStringCacheCalloc ((ACPI_SIZE) strlen (String) + 1); + if (!NewString) + { + return (NULL); + } + + strcpy (NewString, String); + return (NewString); +} + + +/******************************************************************************* + * + * FUNCTION: FlSplitInputPathname + * + * PARAMETERS: InputFilename - The user-specified ASL source file to be + * compiled + * OutDirectoryPath - Where the directory path prefix is + * returned + * OutFilename - Where the filename part is returned + * + * RETURN: Status + * + * DESCRIPTION: Split the input path into a directory and filename part + * 1) Directory part used to open include files + * 2) Filename part used to generate output filenames + * + ******************************************************************************/ + +ACPI_STATUS +FlSplitInputPathname ( + char *InputPath, + char **OutDirectoryPath, + char **OutFilename) +{ + char *Substring; + char *DirectoryPath; + char *Filename; + + + if (OutDirectoryPath) + { + *OutDirectoryPath = NULL; + } + + if (!InputPath) + { + return (AE_OK); + } + + /* Get the path to the input filename's directory */ + + DirectoryPath = FlStrdup (InputPath); + if (!DirectoryPath) + { + return (AE_NO_MEMORY); + } + + /* Convert backslashes to slashes in the entire path */ + + UtConvertBackslashes (DirectoryPath); + + /* Backup to last slash or colon */ + + Substring = strrchr (DirectoryPath, '/'); + if (!Substring) + { + Substring = strrchr (DirectoryPath, ':'); + } + + /* Extract the simple filename */ + + if (!Substring) + { + Filename = FlStrdup (DirectoryPath); + DirectoryPath[0] = 0; + } + else + { + Filename = FlStrdup (Substring + 1); + *(Substring+1) = 0; + } + + if (!Filename) + { + return (AE_NO_MEMORY); + } + + if (OutDirectoryPath) + { + *OutDirectoryPath = DirectoryPath; + } + + if (OutFilename) + { + *OutFilename = Filename; + return (AE_OK); + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/common/adisasm.c b/third_party/lib/acpica/source/common/adisasm.c new file mode 100644 index 000000000..bb83ab6f4 --- /dev/null +++ b/third_party/lib/acpica/source/common/adisasm.c @@ -0,0 +1,656 @@ +/****************************************************************************** + * + * Module Name: adisasm - Application-level disassembler routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "amlcode.h" +#include "acdisasm.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acparser.h" +#include "acapps.h" + +#include + + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("adisasm") + +/* Local prototypes */ + +static ACPI_STATUS +AdDoExternalFileList ( + char *Filename); + +static ACPI_STATUS +AdDisassembleOneTable ( + ACPI_TABLE_HEADER *Table, + FILE *File, + char *Filename, + char *DisasmFilename); + +static ACPI_STATUS +AdReparseOneTable ( + ACPI_TABLE_HEADER *Table, + FILE *File, + ACPI_OWNER_ID OwnerId); + + +ACPI_TABLE_DESC LocalTables[1]; +ACPI_PARSE_OBJECT *AcpiGbl_ParseOpRoot; + + +/* Stubs for everything except ASL compiler */ + +#ifndef ACPI_ASL_COMPILER +BOOLEAN +AcpiDsIsResultUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + return (TRUE); +} + +ACPI_STATUS +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState) +{ + return (Status); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AdInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: ACPICA and local initialization + * + ******************************************************************************/ + +ACPI_STATUS +AdInitialize ( + void) +{ + ACPI_STATUS Status; + + + /* ACPICA subsystem initialization */ + + Status = AcpiOsInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtInitGlobals (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtMutexInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiNsRootInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Setup the Table Manager (cheat - there is no RSDT) */ + + AcpiGbl_RootTableList.MaxTableCount = 1; + AcpiGbl_RootTableList.CurrentTableCount = 0; + AcpiGbl_RootTableList.Tables = LocalTables; + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AdAmlDisassemble + * + * PARAMETERS: Filename - AML input filename + * OutToFile - TRUE if output should go to a file + * Prefix - Path prefix for output + * OutFilename - where the filename is returned + * + * RETURN: Status + * + * DESCRIPTION: Disassembler entry point. Disassemble an entire ACPI table. + * + *****************************************************************************/ + +ACPI_STATUS +AdAmlDisassemble ( + BOOLEAN OutToFile, + char *Filename, + char *Prefix, + char **OutFilename) +{ + ACPI_STATUS Status; + char *DisasmFilename = NULL; + FILE *File = NULL; + ACPI_TABLE_HEADER *Table = NULL; + ACPI_NEW_TABLE_DESC *ListHead = NULL; + + + /* + * Input: AML code from either a file or via GetTables (memory or + * registry) + */ + if (Filename) + { + /* Get the list of all AML tables in the file */ + + Status = AcGetAllTablesFromFile (Filename, + ACPI_GET_ALL_TABLES, &ListHead); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not get ACPI tables from %s, %s\n", + Filename, AcpiFormatException (Status)); + return (Status); + } + + /* Process any user-specified files for external objects */ + + Status = AdDoExternalFileList (Filename); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + Status = AdGetLocalTables (); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not get ACPI tables, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + if (!AcpiGbl_DmOpt_Disasm) + { + return (AE_OK); + } + + /* Obtained the local tables, just disassemble the DSDT */ + + Status = AcpiGetTable (ACPI_SIG_DSDT, 0, &Table); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not get DSDT, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + AcpiOsPrintf ("\nDisassembly of DSDT\n"); + Prefix = AdGenerateFilename ("dsdt", Table->OemTableId); + } + + /* + * Output: ASL code. Redirect to a file if requested + */ + if (OutToFile) + { + /* Create/Open a disassembly output file */ + + DisasmFilename = FlGenerateFilename (Prefix, FILE_SUFFIX_DISASSEMBLY); + if (!DisasmFilename) + { + fprintf (stderr, "Could not generate output filename\n"); + Status = AE_ERROR; + goto Cleanup; + } + + File = fopen (DisasmFilename, "w+"); + if (!File) + { + fprintf (stderr, "Could not open output file %s\n", + DisasmFilename); + Status = AE_ERROR; + goto Cleanup; + } + + AcpiOsRedirectOutput (File); + } + + *OutFilename = DisasmFilename; + + /* Disassemble all AML tables within the file */ + + while (ListHead) + { + Status = AdDisassembleOneTable (ListHead->Table, + File, Filename, DisasmFilename); + if (ACPI_FAILURE (Status)) + { + break; + } + + ListHead = ListHead->Next; + } + +Cleanup: + + if (Table && + !AcpiGbl_ForceAmlDisassembly && + !AcpiUtIsAmlTable (Table)) + { + ACPI_FREE (Table); + } + + if (File) + { + fclose (File); + AcpiOsRedirectOutput (stdout); + } + + AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot); + AcpiGbl_ParseOpRoot = NULL; + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AdDisassembleOneTable + * + * PARAMETERS: Table - Raw AML table + * File - Pointer for the input file + * Filename - AML input filename + * DisasmFilename - Output filename + * + * RETURN: Status + * + * DESCRIPTION: Disassemble a single ACPI table. AML or data table. + * + *****************************************************************************/ + +static ACPI_STATUS +AdDisassembleOneTable ( + ACPI_TABLE_HEADER *Table, + FILE *File, + char *Filename, + char *DisasmFilename) +{ + ACPI_STATUS Status; + ACPI_OWNER_ID OwnerId; + + + /* ForceAmlDisassembly means to assume the table contains valid AML */ + + if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table)) + { + AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE); + + /* This is a "Data Table" (non-AML table) */ + + AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n", + Table->Signature); + AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength] " + "FieldName : FieldValue\n */\n\n"); + + AcpiDmDumpDataTable (Table); + fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n", + Table->Signature); + + if (File) + { + fprintf (stderr, "Formatted output: %s - %u bytes\n", + DisasmFilename, CmGetFileSize (File)); + } + + return (AE_OK); + } + + /* + * This is an AML table (DSDT or SSDT). + * Always parse the tables, only option is what to display + */ + Status = AdParseTable (Table, &OwnerId, TRUE, FALSE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not parse ACPI tables, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + /* Debug output, namespace and parse tree */ + + if (AslCompilerdebug && File) + { + AcpiOsPrintf ("/**** Before second load\n"); + + NsSetupNamespaceListing (File); + NsDisplayNamespace (); + + AcpiOsPrintf ("*****/\n"); + } + + /* Load namespace from names created within control methods */ + + AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot, + AcpiGbl_RootNode, OwnerId); + + /* + * Cross reference the namespace here, in order to + * generate External() statements + */ + AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot, + AcpiGbl_RootNode, OwnerId); + + if (AslCompilerdebug) + { + AcpiDmDumpTree (AcpiGbl_ParseOpRoot); + } + + /* Find possible calls to external control methods */ + + AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot); + + /* + * If we found any external control methods, we must reparse + * the entire tree with the new information (namely, the + * number of arguments per method) + */ + if (AcpiDmGetExternalMethodCount ()) + { + Status = AdReparseOneTable (Table, File, OwnerId); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* + * Now that the namespace is finalized, we can perform namespace + * transforms. + * + * 1) Convert fixed-offset references to resource descriptors + * to symbolic references (Note: modifies namespace) + */ + AcpiDmConvertResourceIndexes (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode); + + /* Optional displays */ + + if (AcpiGbl_DmOpt_Disasm) + { + /* This is the real disassembly */ + + AdDisplayTables (Filename, Table); + + /* Dump hex table if requested (-vt) */ + + AcpiDmDumpDataTable (Table); + + fprintf (stderr, "Disassembly completed\n"); + if (File) + { + fprintf (stderr, "ASL Output: %s - %u bytes\n", + DisasmFilename, CmGetFileSize (File)); + } + + if (Gbl_MapfileFlag) + { + fprintf (stderr, "%14s %s - %u bytes\n", + Gbl_Files[ASL_FILE_MAP_OUTPUT].ShortDescription, + Gbl_Files[ASL_FILE_MAP_OUTPUT].Filename, + FlGetFileSize (ASL_FILE_MAP_OUTPUT)); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AdReparseOneTable + * + * PARAMETERS: Table - Raw AML table + * File - Pointer for the input file + * OwnerId - ID for this table + * + * RETURN: Status + * + * DESCRIPTION: Reparse a table that has already been loaded. Used to + * integrate information about external control methods. + * These methods may have been previously parsed incorrectly. + * + *****************************************************************************/ + +static ACPI_STATUS +AdReparseOneTable ( + ACPI_TABLE_HEADER *Table, + FILE *File, + ACPI_OWNER_ID OwnerId) +{ + ACPI_STATUS Status; + + + fprintf (stderr, + "\nFound %u external control methods, " + "reparsing with new information\n", + AcpiDmGetExternalMethodCount ()); + + /* Reparse, rebuild namespace */ + + AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot); + AcpiGbl_ParseOpRoot = NULL; + AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode); + + AcpiGbl_RootNode = NULL; + AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME; + AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED; + AcpiGbl_RootNodeStruct.Type = ACPI_TYPE_DEVICE; + AcpiGbl_RootNodeStruct.Parent = NULL; + AcpiGbl_RootNodeStruct.Child = NULL; + AcpiGbl_RootNodeStruct.Peer = NULL; + AcpiGbl_RootNodeStruct.Object = NULL; + AcpiGbl_RootNodeStruct.Flags = 0; + + Status = AcpiNsRootInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* New namespace, add the external definitions first */ + + AcpiDmAddExternalsToNamespace (); + + /* Parse the table again. No need to reload it, however */ + + Status = AdParseTable (Table, NULL, FALSE, FALSE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not parse ACPI tables, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + /* Cross reference the namespace again */ + + AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot, + AcpiGbl_RootNode, OwnerId); + + AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot, + AcpiGbl_RootNode, OwnerId); + + /* Debug output - namespace and parse tree */ + + if (AslCompilerdebug) + { + AcpiOsPrintf ("/**** After second load and resource conversion\n"); + if (File) + { + NsSetupNamespaceListing (File); + NsDisplayNamespace (); + } + + AcpiOsPrintf ("*****/\n"); + AcpiDmDumpTree (AcpiGbl_ParseOpRoot); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AdDoExternalFileList + * + * PARAMETERS: Filename - Input file for the table + * + * RETURN: Status + * + * DESCRIPTION: Process all tables found in the -e external files list + * + *****************************************************************************/ + +static ACPI_STATUS +AdDoExternalFileList ( + char *Filename) +{ + ACPI_EXTERNAL_FILE *ExternalFileList; + char *ExternalFilename; + ACPI_NEW_TABLE_DESC *ExternalListHead = NULL; + ACPI_STATUS Status; + ACPI_STATUS GlobalStatus = AE_OK; + ACPI_OWNER_ID OwnerId; + + + /* + * External filenames are specified on the command line like this: + * Example: iasl -e file1,file2,file3 -d xxx.aml + */ + ExternalFileList = AcpiGbl_ExternalFileList; + + /* Process each external file */ + + while (ExternalFileList) + { + ExternalFilename = ExternalFileList->Path; + if (!strcmp (ExternalFilename, Filename)) + { + /* Next external file */ + + ExternalFileList = ExternalFileList->Next; + continue; + } + + AcpiOsPrintf ("External object resolution file %16s\n", + ExternalFilename); + + Status = AcGetAllTablesFromFile ( + ExternalFilename, ACPI_GET_ONLY_AML_TABLES, &ExternalListHead); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_TYPE) + { + ExternalFileList = ExternalFileList->Next; + GlobalStatus = AE_TYPE; + Status = AE_OK; + continue; + } + + return (Status); + } + + /* Load external tables for symbol resolution */ + + while (ExternalListHead) + { + Status = AdParseTable ( + ExternalListHead->Table, &OwnerId, TRUE, TRUE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not parse external ACPI tables, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + /* + * Load namespace from names created within control methods + * Set owner id of nodes in external table + */ + AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot, + AcpiGbl_RootNode, OwnerId); + AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot); + + ExternalListHead = ExternalListHead->Next; + } + + /* Next external file */ + + ExternalFileList = ExternalFileList->Next; + } + + if (ACPI_FAILURE (GlobalStatus)) + { + return (GlobalStatus); + } + + /* Clear external list generated by Scope in external tables */ + + if (AcpiGbl_ExternalFileList) + { + AcpiDmClearExternalList (); + } + + /* Load any externals defined in the optional external ref file */ + + AcpiDmGetExternalsFromFile (); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/common/adwalk.c b/third_party/lib/acpica/source/common/adwalk.c new file mode 100644 index 000000000..daa3929d3 --- /dev/null +++ b/third_party/lib/acpica/source/common/adwalk.c @@ -0,0 +1,1087 @@ +/****************************************************************************** + * + * Module Name: adwalk - Application-level disassembler parse tree walk routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdisasm.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acapps.h" + + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("adwalk") + +/* + * aslmap - opcode mappings and reserved method names + */ +ACPI_OBJECT_TYPE +AslMapNamedOpcodeToDataType ( + UINT16 Opcode); + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDmFindOrphanDescending ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +AcpiDmDumpDescending ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +AcpiDmXrefDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +AcpiDmCommonAscendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +AcpiDmLoadDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static UINT32 +AcpiDmInspectPossibleArgs ( + UINT32 CurrentOpArgCount, + UINT32 TargetCount, + ACPI_PARSE_OBJECT *Op); + +static ACPI_STATUS +AcpiDmResourceDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpTree + * + * PARAMETERS: Origin - Starting object + * + * RETURN: None + * + * DESCRIPTION: Parse tree walk to format and output the nodes + * + ******************************************************************************/ + +void +AcpiDmDumpTree ( + ACPI_PARSE_OBJECT *Origin) +{ + ACPI_OP_WALK_INFO Info; + + + if (!Origin) + { + return; + } + + AcpiOsPrintf ("/*\nAML Parse Tree\n\n"); + Info.Flags = 0; + Info.Count = 0; + Info.Level = 0; + Info.WalkState = NULL; + + AcpiDmWalkParseTree (Origin, AcpiDmDumpDescending, NULL, &Info); + AcpiOsPrintf ("*/\n\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFindOrphanMethods + * + * PARAMETERS: Origin - Starting object + * + * RETURN: None + * + * DESCRIPTION: Parse tree walk to find "orphaned" method invocations -- methods + * that are not resolved in the namespace + * + ******************************************************************************/ + +void +AcpiDmFindOrphanMethods ( + ACPI_PARSE_OBJECT *Origin) +{ + ACPI_OP_WALK_INFO Info; + + + if (!Origin) + { + return; + } + + Info.Flags = 0; + Info.Level = 0; + Info.WalkState = NULL; + + AcpiDmWalkParseTree (Origin, AcpiDmFindOrphanDescending, NULL, &Info); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFinishNamespaceLoad + * + * PARAMETERS: ParseTreeRoot - Root of the parse tree + * NamespaceRoot - Root of the internal namespace + * OwnerId - OwnerId of the table to be disassembled + * + * RETURN: None + * + * DESCRIPTION: Load all namespace items that are created within control + * methods. Used before namespace cross reference + * + ******************************************************************************/ + +void +AcpiDmFinishNamespaceLoad ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot, + ACPI_OWNER_ID OwnerId) +{ + ACPI_STATUS Status; + ACPI_OP_WALK_INFO Info; + ACPI_WALK_STATE *WalkState; + + + if (!ParseTreeRoot) + { + return; + } + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL); + if (!WalkState) + { + return; + } + + Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, + WalkState); + if (ACPI_FAILURE (Status)) + { + return; + } + + Info.Flags = 0; + Info.Level = 0; + Info.WalkState = WalkState; + + AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmLoadDescendingOp, + AcpiDmCommonAscendingOp, &Info); + ACPI_FREE (WalkState); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCrossReferenceNamespace + * + * PARAMETERS: ParseTreeRoot - Root of the parse tree + * NamespaceRoot - Root of the internal namespace + * OwnerId - OwnerId of the table to be disassembled + * + * RETURN: None + * + * DESCRIPTION: Cross reference the namespace to create externals + * + ******************************************************************************/ + +void +AcpiDmCrossReferenceNamespace ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot, + ACPI_OWNER_ID OwnerId) +{ + ACPI_STATUS Status; + ACPI_OP_WALK_INFO Info; + ACPI_WALK_STATE *WalkState; + + + if (!ParseTreeRoot) + { + return; + } + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL); + if (!WalkState) + { + return; + } + + Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, + WalkState); + if (ACPI_FAILURE (Status)) + { + return; + } + + Info.Flags = 0; + Info.Level = 0; + Info.WalkState = WalkState; + + AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmXrefDescendingOp, + AcpiDmCommonAscendingOp, &Info); + ACPI_FREE (WalkState); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmConvertResourceIndexes + * + * PARAMETERS: ParseTreeRoot - Root of the parse tree + * NamespaceRoot - Root of the internal namespace + * + * RETURN: None + * + * DESCRIPTION: Convert fixed-offset references to resource descriptors to + * symbolic references. Should only be called after namespace has + * been cross referenced. + * + ******************************************************************************/ + +void +AcpiDmConvertResourceIndexes ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot) +{ + ACPI_STATUS Status; + ACPI_OP_WALK_INFO Info; + ACPI_WALK_STATE *WalkState; + + + if (!ParseTreeRoot) + { + return; + } + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (0, ParseTreeRoot, NULL, NULL); + if (!WalkState) + { + return; + } + + Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, + WalkState); + if (ACPI_FAILURE (Status)) + { + return; + } + + Info.Flags = 0; + Info.Level = 0; + Info.WalkState = WalkState; + + AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmResourceDescendingOp, + AcpiDmCommonAscendingOp, &Info); + ACPI_FREE (WalkState); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpDescending + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Format and print contents of one parse Op. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmDumpDescending ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + char *Path; + + + if (!Op) + { + return (AE_OK); + } + + /* Most of the information (count, level, name) here */ + + Info->Count++; + AcpiOsPrintf ("% 5d [%2.2d] ", Info->Count, Level); + AcpiDmIndent (Level); + AcpiOsPrintf ("%-28s", AcpiPsGetOpcodeName (Op->Common.AmlOpcode)); + + /* Extra info is helpful */ + + switch (Op->Common.AmlOpcode) + { + case AML_BYTE_OP: + + AcpiOsPrintf ("%2.2X", (UINT32) Op->Common.Value.Integer); + break; + + case AML_WORD_OP: + + AcpiOsPrintf ("%4.4X", (UINT32) Op->Common.Value.Integer); + break; + + case AML_DWORD_OP: + + AcpiOsPrintf ("%8.8X", (UINT32) Op->Common.Value.Integer); + break; + + case AML_QWORD_OP: + + AcpiOsPrintf ("%8.8X%8.8X", ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); + break; + + case AML_INT_NAMEPATH_OP: + + if (Op->Common.Value.String) + { + AcpiNsExternalizeName (ACPI_UINT32_MAX, Op->Common.Value.String, + NULL, &Path); + AcpiOsPrintf ("%s %p", Path, Op->Common.Node); + ACPI_FREE (Path); + } + else + { + AcpiOsPrintf ("[NULL]"); + } + break; + + case AML_NAME_OP: + case AML_METHOD_OP: + case AML_DEVICE_OP: + case AML_INT_NAMEDFIELD_OP: + + AcpiOsPrintf ("%4.4s", ACPI_CAST_PTR (char, &Op->Named.Name)); + break; + + default: + + break; + } + + AcpiOsPrintf ("\n"); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFindOrphanDescending + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Check namepath Ops for orphaned method invocations + * + * Note: Experimental. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmFindOrphanDescending ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + const ACPI_OPCODE_INFO *OpInfo; + ACPI_PARSE_OBJECT *ChildOp; + ACPI_PARSE_OBJECT *NextOp; + ACPI_PARSE_OBJECT *ParentOp; + UINT32 ArgCount; + + + if (!Op) + { + return (AE_OK); + } + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + switch (Op->Common.AmlOpcode) + { +#ifdef ACPI_UNDER_DEVELOPMENT + case AML_ADD_OP: + + ChildOp = Op->Common.Value.Arg; + if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && + !ChildOp->Common.Node) + { + AcpiNsExternalizeName (ACPI_UINT32_MAX, ChildOp->Common.Value.String, + NULL, &Path); + AcpiOsPrintf ("/* %-16s A-NAMEPATH: %s */\n", + Op->Common.AmlOpName, Path); + ACPI_FREE (Path); + + NextOp = Op->Common.Next; + if (!NextOp) + { + /* This NamePath has no args, assume it is an integer */ + + AcpiDmAddOpToExternalList (ChildOp, + ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); + return (AE_OK); + } + + ArgCount = AcpiDmInspectPossibleArgs (3, 1, NextOp); + AcpiOsPrintf ("/* A-CHILDREN: %u Actual %u */\n", + ArgCount, AcpiDmCountChildren (Op)); + + if (ArgCount < 1) + { + /* One Arg means this is just a Store(Name,Target) */ + + AcpiDmAddOpToExternalList (ChildOp, + ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); + return (AE_OK); + } + + AcpiDmAddOpToExternalList (ChildOp, + ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0); + } + break; +#endif + + case AML_STORE_OP: + + ChildOp = Op->Common.Value.Arg; + if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && + !ChildOp->Common.Node) + { + NextOp = Op->Common.Next; + if (!NextOp) + { + /* This NamePath has no args, assume it is an integer */ + + AcpiDmAddOpToExternalList (ChildOp, + ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); + return (AE_OK); + } + + ArgCount = AcpiDmInspectPossibleArgs (2, 1, NextOp); + if (ArgCount <= 1) + { + /* One Arg means this is just a Store(Name,Target) */ + + AcpiDmAddOpToExternalList (ChildOp, + ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); + return (AE_OK); + } + + AcpiDmAddOpToExternalList (ChildOp, + ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0); + } + break; + + case AML_INT_NAMEPATH_OP: + + /* Must examine parent to see if this namepath is an argument */ + + ParentOp = Op->Common.Parent; + OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode); + + if ((OpInfo->Class != AML_CLASS_EXECUTE) && + (OpInfo->Class != AML_CLASS_CREATE) && + (OpInfo->ObjectType != ACPI_TYPE_LOCAL_ALIAS) && + (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) && + !Op->Common.Node) + { + ArgCount = AcpiDmInspectPossibleArgs (0, 0, Op->Common.Next); + + /* + * Check if namepath is a predicate for if/while or lone parameter to + * a return. + */ + if (ArgCount == 0) + { + if (((ParentOp->Common.AmlOpcode == AML_IF_OP) || + (ParentOp->Common.AmlOpcode == AML_WHILE_OP) || + (ParentOp->Common.AmlOpcode == AML_RETURN_OP)) && + + /* And namepath is the first argument */ + (ParentOp->Common.Value.Arg == Op)) + { + AcpiDmAddOpToExternalList (Op, + Op->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); + break; + } + } + + /* + * This is a standalone namestring (not a parameter to another + * operator) - it *must* be a method invocation, nothing else is + * grammatically possible. + */ + AcpiDmAddOpToExternalList (Op, + Op->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0); + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmLoadDescendingOp + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending handler for namespace control method object load + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmLoadDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + const ACPI_OPCODE_INFO *OpInfo; + ACPI_WALK_STATE *WalkState; + ACPI_OBJECT_TYPE ObjectType; + ACPI_STATUS Status; + char *Path = NULL; + ACPI_PARSE_OBJECT *NextOp; + ACPI_NAMESPACE_NODE *Node; + char FieldPath[5]; + BOOLEAN PreDefined = FALSE; + UINT8 PreDefineIndex = 0; + + + WalkState = Info->WalkState; + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + ObjectType = OpInfo->ObjectType; + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + + /* Only interested in operators that create new names */ + + if (!(OpInfo->Flags & AML_NAMED) && + !(OpInfo->Flags & AML_CREATE)) + { + goto Exit; + } + + /* Get the NamePath from the appropriate place */ + + if (OpInfo->Flags & AML_NAMED) + { + /* For all named operators, get the new name */ + + Path = (char *) Op->Named.Path; + + if (!Path && Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) + { + *ACPI_CAST_PTR (UINT32, &FieldPath[0]) = Op->Named.Name; + FieldPath[4] = 0; + Path = FieldPath; + } + } + else if (OpInfo->Flags & AML_CREATE) + { + /* New name is the last child */ + + NextOp = Op->Common.Value.Arg; + + while (NextOp->Common.Next) + { + NextOp = NextOp->Common.Next; + } + + Path = NextOp->Common.Value.String; + } + + if (!Path) + { + goto Exit; + } + + /* Insert the name into the namespace */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, + ACPI_IMODE_LOAD_PASS2, ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &Node); + + Op->Common.Node = Node; + + if (ACPI_SUCCESS (Status)) + { + /* Check if it's a predefined node */ + + while (AcpiGbl_PreDefinedNames[PreDefineIndex].Name) + { + if (ACPI_COMPARE_NAME (Node->Name.Ascii, + AcpiGbl_PreDefinedNames[PreDefineIndex].Name)) + { + PreDefined = TRUE; + break; + } + + PreDefineIndex++; + } + + /* + * Set node owner id if it satisfies all the following conditions: + * 1) Not a predefined node, _SB_ etc + * 2) Not the root node + * 3) Not a node created by Scope + */ + + if (!PreDefined && Node != AcpiGbl_RootNode && + Op->Common.AmlOpcode != AML_SCOPE_OP) + { + Node->OwnerId = WalkState->OwnerId; + } + } + + +Exit: + + if (AcpiNsOpensScope (ObjectType)) + { + if (Op->Common.Node) + { + Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, + WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmXrefDescendingOp + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending handler for namespace cross reference + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmXrefDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + const ACPI_OPCODE_INFO *OpInfo; + ACPI_WALK_STATE *WalkState; + ACPI_OBJECT_TYPE ObjectType; + ACPI_OBJECT_TYPE ObjectType2; + ACPI_STATUS Status; + char *Path = NULL; + ACPI_PARSE_OBJECT *NextOp; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *Object; + UINT32 ParamCount = 0; + char *Pathname; + + + WalkState = Info->WalkState; + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + ObjectType = OpInfo->ObjectType; + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + + if ((!(OpInfo->Flags & AML_NAMED)) && + (!(OpInfo->Flags & AML_CREATE)) && + (Op->Common.AmlOpcode != AML_INT_NAMEPATH_OP) && + (Op->Common.AmlOpcode != AML_NOTIFY_OP)) + { + goto Exit; + } + + + /* Get the NamePath from the appropriate place */ + + if (OpInfo->Flags & AML_NAMED) + { + /* + * Only these two operators (Alias, Scope) refer to an existing + * name, it is the first argument + */ + if (Op->Common.AmlOpcode == AML_ALIAS_OP) + { + ObjectType = ACPI_TYPE_ANY; + + NextOp = Op->Common.Value.Arg; + NextOp = NextOp->Common.Value.Arg; + if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) + { + Path = NextOp->Common.Value.String; + } + } + else if (Op->Common.AmlOpcode == AML_SCOPE_OP) + { + Path = (char *) Op->Named.Path; + } + } + else if (OpInfo->Flags & AML_CREATE) + { + /* Referenced Buffer Name is the first child */ + + ObjectType = ACPI_TYPE_BUFFER; /* Change from TYPE_BUFFER_FIELD */ + + NextOp = Op->Common.Value.Arg; + if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) + { + Path = NextOp->Common.Value.String; + } + } + else if (Op->Common.AmlOpcode == AML_NOTIFY_OP) + { + Path = Op->Common.Value.Arg->Asl.Value.String; + } + else + { + Path = Op->Common.Value.String; + } + + if (!Path) + { + goto Exit; + } + + /* + * Lookup the name in the namespace. Name must exist at this point, or it + * is an invalid reference. + * + * The namespace is also used as a lookup table for references to resource + * descriptors and the fields within them. + */ + Node = NULL; + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &Node); + if (ACPI_SUCCESS (Status) && (Node->Flags & ANOBJ_IS_EXTERNAL)) + { + /* Node was created by an External() statement */ + + Status = AE_NOT_FOUND; + } + + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + /* + * Add this symbol as an external declaration, except if the + * parent is a CondRefOf operator. For this operator, we do not + * need an external, nor do we want one, since this can cause + * disassembly problems if the symbol is actually a control + * method. + */ + if (!(Op->Asl.Parent && + (Op->Asl.Parent->Asl.AmlOpcode == AML_COND_REF_OF_OP))) + { + if (Node) + { + AcpiDmAddNodeToExternalList (Node, + (UINT8) ObjectType, 0, 0); + } + else + { + AcpiDmAddOpToExternalList (Op, Path, + (UINT8) ObjectType, 0, 0); + } + } + } + } + + /* + * Found the node, but check if it came from an external table. + * Add it to external list. Note: Node->OwnerId == 0 indicates + * one of the built-in ACPI Names (_OS_ etc.) which can safely + * be ignored. + */ + else if (Node->OwnerId && + (WalkState->OwnerId != Node->OwnerId)) + { + ObjectType2 = ObjectType; + + Object = AcpiNsGetAttachedObject (Node); + if (Object) + { + ObjectType2 = Object->Common.Type; + if (ObjectType2 == ACPI_TYPE_METHOD) + { + ParamCount = Object->Method.ParamCount; + } + } + + Pathname = AcpiNsGetExternalPathname (Node); + if (!Pathname) + { + return (AE_NO_MEMORY); + } + + AcpiDmAddNodeToExternalList (Node, (UINT8) ObjectType2, + ParamCount, ACPI_EXT_RESOLVED_REFERENCE); + + ACPI_FREE (Pathname); + Op->Common.Node = Node; + } + else + { + Op->Common.Node = Node; + } + + +Exit: + /* Open new scope if necessary */ + + if (AcpiNsOpensScope (ObjectType)) + { + if (Op->Common.Node) + { + Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, + WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmResourceDescendingOp + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: None + * + * DESCRIPTION: Process one parse op during symbolic resource index conversion. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmResourceDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + const ACPI_OPCODE_INFO *OpInfo; + ACPI_WALK_STATE *WalkState; + ACPI_OBJECT_TYPE ObjectType; + ACPI_STATUS Status; + + + WalkState = Info->WalkState; + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + /* Open new scope if necessary */ + + ObjectType = OpInfo->ObjectType; + if (AcpiNsOpensScope (ObjectType)) + { + if (Op->Common.Node) + { + + Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, + WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + /* + * Check if this operator contains a reference to a resource descriptor. + * If so, convert the reference into a symbolic reference. + */ + AcpiDmCheckResourceReference (Op, WalkState); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCommonAscendingOp + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: None + * + * DESCRIPTION: Ascending handler for combined parse/namespace walks. Closes + * scope if necessary. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmCommonAscendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + const ACPI_OPCODE_INFO *OpInfo; + ACPI_OBJECT_TYPE ObjectType; + + + /* Close scope if necessary */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + ObjectType = OpInfo->ObjectType; + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + + if (AcpiNsOpensScope (ObjectType)) + { + (void) AcpiDsScopeStackPop (Info->WalkState); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmInspectPossibleArgs + * + * PARAMETERS: CurrentOpArgCount - Which arg of the current op was the + * possible method invocation found + * TargetCount - Number of targets (0,1,2) for this op + * Op - Parse op + * + * RETURN: Status + * + * DESCRIPTION: Examine following args and next ops for possible arguments + * for an unrecognized method invocation. + * + ******************************************************************************/ + +static UINT32 +AcpiDmInspectPossibleArgs ( + UINT32 CurrentOpArgCount, + UINT32 TargetCount, + ACPI_PARSE_OBJECT *Op) +{ + const ACPI_OPCODE_INFO *OpInfo; + UINT32 i; + UINT32 Last = 0; + UINT32 Lookahead; + + + Lookahead = (ACPI_METHOD_NUM_ARGS + TargetCount) - CurrentOpArgCount; + + /* Lookahead for the maximum number of possible arguments */ + + for (i = 0; i < Lookahead; i++) + { + if (!Op) + { + break; + } + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + /* + * Any one of these operators is "very probably" not a method arg + */ + if ((Op->Common.AmlOpcode == AML_STORE_OP) || + (Op->Common.AmlOpcode == AML_NOTIFY_OP)) + { + break; + } + + if ((OpInfo->Class != AML_CLASS_EXECUTE) && + (OpInfo->Class != AML_CLASS_CONTROL)) + { + Last = i+1; + } + + Op = Op->Common.Next; + } + + return (Last); +} diff --git a/third_party/lib/acpica/source/common/ahids.c b/third_party/lib/acpica/source/common/ahids.c new file mode 100644 index 000000000..2a5fdc7bc --- /dev/null +++ b/third_party/lib/acpica/source/common/ahids.c @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * Module Name: ahids - Table of ACPI/PNP _HID/_CID values + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("ahids") + + +/* + * ACPI/PNP Device IDs with description strings + */ +const AH_DEVICE_ID AslDeviceIds[] = +{ + {"10EC5640", "Realtek I2S Audio Codec"}, + {"80860F09", "Intel PWM Controller"}, + {"80860F0A", "Intel Atom UART Controller"}, + {"80860F0E", "Intel SPI Controller"}, + {"80860F14", "Intel Baytrail SDIO/MMC Host Controller"}, + {"80860F28", "Intel SST Audio DSP"}, + {"80860F41", "Intel Baytrail I2C Host Controller"}, + {"ACPI0001", "SMBus 1.0 Host Controller"}, + {"ACPI0002", "Smart Battery Subsystem"}, + {"ACPI0003", "Power Source Device"}, + {"ACPI0004", "Module Device"}, + {"ACPI0005", "SMBus 2.0 Host Controller"}, + {"ACPI0006", "GPE Block Device"}, + {"ACPI0007", "Processor Device"}, + {"ACPI0008", "Ambient Light Sensor Device"}, + {"ACPI0009", "I/O xAPIC Device"}, + {"ACPI000A", "I/O APIC Device"}, + {"ACPI000B", "I/O SAPIC Device"}, + {"ACPI000C", "Processor Aggregator Device"}, + {"ACPI000D", "Power Meter Device"}, + {"ACPI000E", "Time and Alarm Device"}, + {"ACPI000F", "User Presence Detection Device"}, + {"ADMA0F28", "Intel Audio DMA"}, + {"AMCR0F28", "Intel Audio Machine Driver"}, + {"ATK4001", "Asus Radio Control Button"}, + {"ATML1000", "Atmel Touchscreen Controller"}, + {"AUTH2750", "AuthenTec AES2750"}, + {"BCM2E39", "Broadcom BT Serial Bus Driver over UART Bus Enumerator"}, + {"BCM4752E", "Broadcom GPS Controller"}, + {"BMG0160", "Bosch Gyro Sensor"}, + {"CPLM3218", "Capella Micro CM3218x Ambient Light Sensor"}, + {"DELLABCE", "Dell Airplane Mode Switch Driver"}, + {"DLAC3002", "Qualcomm Atheros Bluetooth UART Transport"}, + {"FTTH5506", "FocalTech 5506 Touch Controller"}, + {"HAD0F28", "Intel HDMI Audio Driver"}, + {"INBC0000", "GPIO Expander"}, + {"INT0002", "Virtual GPIO Controller"}, + {"INT0800", "Intel 82802 Firmware Hub Device"}, + {"INT3394", "ACPI System Fan"}, + {"INT3396", "Standard Power Management Controller"}, + {"INT33A0", "Intel Smart Connect Technology Device"}, + {"INT33A1", "Intel Power Engine"}, + {"INT33BB", "Intel Baytrail SD Host Controller"}, + {"INT33BD", "Intel Baytrail Mailbox Device"}, + {"INT33BE", "Camera Sensor OV5693"}, + {"INT33C0", "Intel Serial I/O SPI Host Controller"}, + {"INT33C1", "Intel Serial I/O SPI Host Controller"}, + {"INT33C2", "Intel Serial I/O I2C Host Controller"}, + {"INT33C3", "Intel Serial I/O I2C Host Controller"}, + {"INT33C4", "Intel Serial I/O UART Host Controller"}, + {"INT33C5", "Intel Serial I/O UART Host Controller"}, + {"INT33C6", "Intel SD Host Controller"}, + {"INT33C7", "Intel Serial I/O GPIO Host Controller"}, + {"INT33C8", "Intel Smart Sound Technology Host Controller"}, + {"INT33C9", "Wolfson Microelectronics Audio WM5102"}, + {"INT33CA", "Intel SPB Peripheral"}, + {"INT33CB", "Intel Smart Sound Technology Audio Codec"}, + {"INT33D1", "Intel GPIO Buttons"}, + {"INT33D2", "Intel GPIO Buttons"}, + {"INT33D3", "Intel GPIO Buttons"}, + {"INT33D4", "Intel GPIO Buttons"}, + {"INT33D6", "Intel Virtual Buttons Device"}, + {"INT33F0", "Camera Sensor MT9M114"}, + {"INT33F4", "XPOWER PMIC Controller"}, + {"INT33F5", "TI PMIC Controller"}, + {"INT33FB", "MIPI-CSI Camera Sensor OV2722"}, + {"INT33FC", "Intel Baytrail GPIO Controller"}, + {"INT33FD", "Intel Baytrail Power Management IC"}, + {"INT33FE", "XPOWER Battery Device"}, + {"INT3400", "Intel Dynamic Power Performance Management"}, + {"INT3401", "Intel Extended Thermal Model CPU"}, + {"INT3403", "DPTF Temperature Sensor"}, + {"INT3406", "Intel Dynamic Platform & Thermal Framework Display Participant"}, + {"INT3407", "DPTF Platform Power Meter"}, + {"INT340E", "Motherboard Resources"}, + {"INT3420", "Intel Bluetooth RF Kill"}, + {"INT3F0D", "ACPI Motherboard Resources"}, + {"INTCF1A", "Sony IMX175 Camera Sensor"}, + {"INTCFD9", "Intel Baytrail SOC GPIO Controller"}, + {"INTL9C60", "Intel Baytrail SOC DMA Controller"}, + {"INVN6500", "InvenSense MPU-6500 Six Axis Gyroscope and Accelerometer"}, + {"LNXCPU", "Linux Logical CPU"}, + {"LNXPOWER", "ACPI Power Resource (power gating)"}, + {"LNXPWRBN", "System Power Button"}, + {"LNXSYBUS", "System Bus"}, + {"LNXSYSTM", "ACPI Root Node"}, + {"LNXTHERM", "ACPI Thermal Zone"}, + {"LNXVIDEO", "ACPI Video Controller"}, + {"MAX17047", "Fuel Gauge Controller"}, + {"MSFT0101", "TPM 2.0 Security Device"}, + {"NXP5442", "NXP 5442 Near Field Communications Controller"}, + {"NXP5472", "NXP NFC"}, + {"PNP0000", "8259-compatible Programmable Interrupt Controller"}, + {"PNP0001", "EISA Interrupt Controller"}, + {"PNP0002", "MCA Interrupt Controller"}, + {"PNP0003", "IO-APIC Interrupt Controller"}, + {"PNP0100", "PC-class System Timer"}, + {"PNP0103", "HPET System Timer"}, + {"PNP0200", "PC-class DMA Controller"}, + {"PNP0300", "IBM PC/XT Keyboard Controller (83 key)"}, + {"PNP0301", "IBM PC/XT Keyboard Controller (86 key)"}, + {"PNP0302", "IBM PC/XT Keyboard Controller (84 key)"}, + {"PNP0303", "IBM Enhanced Keyboard (101/102-key, PS/2 Mouse)"}, + {"PNP0400", "Standard LPT Parallel Port"}, + {"PNP0401", "ECP Parallel Port"}, + {"PNP0500", "Standard PC COM Serial Port"}, + {"PNP0501", "16550A-compatible COM Serial Port"}, + {"PNP0510", "Generic IRDA-compatible Device"}, + {"PNP0800", "Microsoft Sound System Compatible Device"}, + {"PNP0A03", "PCI Bus"}, + {"PNP0A05", "Generic Container Device"}, + {"PNP0A06", "Generic Container Device"}, + {"PNP0A08", "PCI Express Bus"}, + {"PNP0B00", "AT Real-Time Clock"}, + {"PNP0B01", "Intel PIIX4-compatible RTC/CMOS Device"}, + {"PNP0B02", "Dallas Semiconductor-compatible RTC/CMOS Device"}, + {"PNP0C01", "System Board"}, + {"PNP0C02", "PNP Motherboard Resources"}, + {"PNP0C04", "x87-compatible Floating Point Processing Unit"}, + {"PNP0C08", "ACPI Core Hardware"}, + {"PNP0C09", "Embedded Controller Device"}, + {"PNP0C0A", "Control Method Battery"}, + {"PNP0C0B", "Fan (Thermal Solution)"}, + {"PNP0C0C", "Power Button Device"}, + {"PNP0C0D", "Lid Device"}, + {"PNP0C0E", "Sleep Button Device"}, + {"PNP0C0F", "PCI Interrupt Link Device"}, + {"PNP0C10", "System Indicator Device"}, + {"PNP0C11", "Thermal Zone"}, + {"PNP0C12", "Device Bay Controller"}, + {"PNP0C14", "Windows Management Instrumentation Device"}, + {"PNP0C15", "Docking Station"}, + {"PNP0C40", "Standard Button Controller"}, + {"PNP0C50", "HID Protocol Device (I2C bus)"}, + {"PNP0C60", "Display Sensor Device"}, + {"PNP0C70", "Dock Sensor Device"}, + {"PNP0C80", "Memory Device"}, + {"PNP0D10", "XHCI USB Controller with debug"}, + {"PNP0D15", "XHCI USB Controller without debug"}, + {"PNP0D20", "EHCI USB Controller without debug"}, + {"PNP0D25", "EHCI USB Controller with debug"}, + {"PNP0D40", "SDA Standard Compliant SD Host Controller"}, + {"PNP0D80", "Windows-compatible System Power Management Controller"}, + {"PNP0F03", "Microsoft PS/2-style Mouse"}, + {"PNP0F13", "PS/2 Mouse"}, + {"RTL8723", "Realtek Wireless Controller"}, + {"SMB0349", "Charger"}, + {"SMO91D0", "Sensor Hub"}, + {"SMSC3750", "SMSC 3750 USB MUX"}, + {"SSPX0000", "Intel SSP Device"}, + {"TBQ24296", "Charger"}, + + {NULL, NULL} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiAhMatchHardwareId + * + * PARAMETERS: HardwareId - String representation of an _HID or _CID + * + * RETURN: ID info struct. NULL if HardwareId is not found + * + * DESCRIPTION: Lookup an _HID/_CID in the device ID table + * + ******************************************************************************/ + +const AH_DEVICE_ID * +AcpiAhMatchHardwareId ( + char *HardwareId) +{ + const AH_DEVICE_ID *Info; + + + for (Info = AslDeviceIds; Info->Name; Info++) + { + if (!strcmp (HardwareId, Info->Name)) + { + return (Info); + } + } + + return (NULL); +} diff --git a/third_party/lib/acpica/source/common/ahpredef.c b/third_party/lib/acpica/source/common/ahpredef.c new file mode 100644 index 000000000..845e68508 --- /dev/null +++ b/third_party/lib/acpica/source/common/ahpredef.c @@ -0,0 +1,369 @@ +/****************************************************************************** + * + * Module Name: ahpredef - Table of all known ACPI predefined names + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("ahpredef") + +/* + * iASL only needs a partial table (short descriptions only). + * AcpiHelp needs the full table. + */ +#ifdef ACPI_ASL_COMPILER +#define AH_PREDEF(Name, ShortDesc, LongDesc) {Name, ShortDesc} +#else +#define AH_PREDEF(Name, ShortDesc, LongDesc) {Name, ShortDesc, LongDesc} +#endif + +/* + * Predefined ACPI names, with short description and return value. + * This table was extracted directly from the ACPI specification. + */ +const AH_PREDEFINED_NAME AslPredefinedInfo[] = +{ + AH_PREDEF ("_ACx", "Active Cooling", "Returns the active cooling policy threshold values"), + AH_PREDEF ("_ADR", "Address", "Returns address of a device on parent bus, and resource field"), + AH_PREDEF ("_AEI", "ACPI Event Interrupts", "Returns a list of GPIO events to be used as ACPI events"), + AH_PREDEF ("_ALC", "Ambient Light Chromaticity", "Returns the ambient light color chromaticity"), + AH_PREDEF ("_ALI", "Ambient Light Illuminance", "Returns the ambient light brightness"), + AH_PREDEF ("_ALN", "Alignment", "Base alignment, Resource Descriptor field"), + AH_PREDEF ("_ALP", "Ambient Light Polling", "Returns the ambient light sensor polling frequency"), + AH_PREDEF ("_ALR", "Ambient Light Response", "Returns the ambient light brightness to display brightness mappings"), + AH_PREDEF ("_ALT", "Ambient Light Temperature", "Returns the ambient light color temperature"), + AH_PREDEF ("_ALx", "Active List", "Returns a list of active cooling device objects"), + AH_PREDEF ("_ART", "Active Cooling Relationship Table", "Returns thermal relationship information between platform devices and fan devices"), + AH_PREDEF ("_ASI", "Address Space Id", "Resource Descriptor field"), + AH_PREDEF ("_ASZ", "Access Size", "Resource Descriptor field"), + AH_PREDEF ("_ATT", "Type-Specific Attribute", "Resource Descriptor field"), + AH_PREDEF ("_BAS", "Base Address", "Range base address, Resource Descriptor field"), + AH_PREDEF ("_BBN", "BIOS Bus Number", "Returns the PCI bus number returned by the BIOS"), + AH_PREDEF ("_BCL", "Brightness Control Levels", "Returns a list of supported brightness control levels"), + AH_PREDEF ("_BCM", "Brightness Control Method", "Sets the brightness level of the display device"), + AH_PREDEF ("_BCT", "Battery Charge Time", "Returns time remaining to complete charging battery"), + AH_PREDEF ("_BDN", "BIOS Dock Name", "Returns the Dock ID returned by the BIOS"), + AH_PREDEF ("_BFS", "Back From Sleep", "Inform AML of a wake event"), + AH_PREDEF ("_BIF", "Battery Information", "Returns a Control Method Battery information block"), + AH_PREDEF ("_BIX", "Battery Information Extended", "Returns a Control Method Battery extended information block"), + AH_PREDEF ("_BLT", "Battery Level Threshold", "Set battery level threshold preferences"), + AH_PREDEF ("_BM_", "Bus Master", "Resource Descriptor field"), + AH_PREDEF ("_BMA", "Battery Measurement Averaging Interval", "Sets battery measurement averaging interval"), + AH_PREDEF ("_BMC", "Battery Maintenance Control", "Sets battery maintenance and control features"), + AH_PREDEF ("_BMD", "Battery Maintenance Data", "Returns battery maintenance, control, and state data"), + AH_PREDEF ("_BMS", "Battery Measurement Sampling Time", "Sets the battery measurement sampling time"), + AH_PREDEF ("_BQC", "Brightness Query Current", "Returns the current display brightness level"), + AH_PREDEF ("_BST", "Battery Status", "Returns a Control Method Battery status block"), + AH_PREDEF ("_BTH", "Battery Throttle Limit", "Thermal limit for charging and discharging"), + AH_PREDEF ("_BTM", "Battery Time", "Returns the battery runtime"), + AH_PREDEF ("_BTP", "Battery Trip Point", "Sets a Control Method Battery trip point"), + AH_PREDEF ("_CBA", "Configuration Base Address", "Sets the base address for a PCI Express host bridge"), + AH_PREDEF ("_CCA", "Cache Coherency Attribute", "Returns a device's support level for cache coherency"), + AH_PREDEF ("_CDM", "Clock Domain", "Returns a logical processor's clock domain identifier"), + AH_PREDEF ("_CID", "Compatible ID", "Returns a device's Plug and Play Compatible ID list"), + AH_PREDEF ("_CLS", "Class Code", "Returns PCI class code and subclass"), + AH_PREDEF ("_CPC", "Continuous Performance Control", "Returns a list of performance control interfaces"), + AH_PREDEF ("_CR3", "Warm/Standby Temperature", "Temperature for a fast low power state"), + AH_PREDEF ("_CRS", "Current Resource Settings", "Returns the current resource settings for a device"), + AH_PREDEF ("_CRT", "Critical Temperature", "Returns the shutdown critical temperature"), + AH_PREDEF ("_CSD", "C-State Dependencies", "Returns a list of C-state dependencies"), + AH_PREDEF ("_CST", "C-States", "Returns a list of supported C-states"), + AH_PREDEF ("_CWS", "Clear Wake Alarm Status", "Clear the status of wake alarms"), + AH_PREDEF ("_DBT", "Debounce Timeout", "Timeout value, Resource Descriptor field"), + AH_PREDEF ("_DCK", "Dock Present", "Sets docking isolation. Presence indicates device is a docking station"), + AH_PREDEF ("_DCS", "Display Current Status", "Returns status of the display output device"), + AH_PREDEF ("_DDC", "Display Data Current", "Returns the EDID for the display output device"), + AH_PREDEF ("_DDN", "DOS Device Name", "Returns a device logical name"), + AH_PREDEF ("_DEC", "Decode", "Device decoding type, Resource Descriptor field"), + AH_PREDEF ("_DEP", "Dependencies", "Returns a list of operation region dependencies"), + AH_PREDEF ("_DGS", "Display Graphics State", "Return the current state of the output device"), + AH_PREDEF ("_DIS", "Disable Device", "Disables a device"), + AH_PREDEF ("_DLM", "Device Lock Mutex", "Defines mutex for OS/AML sharing"), + AH_PREDEF ("_DMA", "Direct Memory Access", "Returns device current resources for DMA transactions, and resource field"), + AH_PREDEF ("_DOD", "Display Output Devices", "Enumerate all devices attached to the display adapter"), + AH_PREDEF ("_DOS", "Disable Output Switching", "Sets the display output switching mode"), + AH_PREDEF ("_DPL", "Device Selection Polarity", "Polarity of Device Selection signal, Resource Descriptor field"), + AH_PREDEF ("_DRS", "Drive Strength", "Drive Strength setting for GPIO connection, Resource Descriptor field"), + AH_PREDEF ("_DSD", "Device-Specific Data", "Returns a list of device property information"), + AH_PREDEF ("_DSM", "Device-Specific Method", "Executes device-specific functions"), + AH_PREDEF ("_DSS", "Device Set State", "Sets the display device state"), + AH_PREDEF ("_DSW", "Device Sleep Wake", "Sets the sleep and wake transition states for a device"), + AH_PREDEF ("_DTI", "Device Temperature Indication", "Conveys native device temperature to the platform"), + AH_PREDEF ("_Exx", "Edge-Triggered GPE", "Method executed as a result of a general-purpose event"), + AH_PREDEF ("_EC_", "Embedded Controller", "returns EC offset and query information"), + AH_PREDEF ("_EDL", "Eject Device List", "Returns a list of devices that are dependent on a device (docking)"), + AH_PREDEF ("_EJD", "Ejection Dependent Device", "Returns the name of dependent (parent) device (docking)"), + AH_PREDEF ("_EJx", "Eject Device", "Begin or cancel a device ejection request (docking)"), + AH_PREDEF ("_END", "Endianness", "Endian orientation, Resource Descriptor field"), + AH_PREDEF ("_EVT", "Event", "Event method for GPIO events"), + AH_PREDEF ("_FDE", "Floppy Disk Enumerate", "Returns floppy disk configuration information"), + AH_PREDEF ("_FDI", "Floppy Drive Information", "Returns a floppy drive information block"), + AH_PREDEF ("_FDM", "Floppy Drive Mode", "Sets a floppy drive speed"), + AH_PREDEF ("_FIF", "Fan Information", "Returns fan device information"), + AH_PREDEF ("_FIX", "Fixed Register Resource Provider", "Returns a list of devices that implement FADT register blocks"), + AH_PREDEF ("_FLC", "Flow Control", "Flow control, Resource Descriptor field"), + AH_PREDEF ("_FPS", "Fan Performance States", "Returns a list of supported fan performance states"), + AH_PREDEF ("_FSL", "Fan Set Level", "Control method that sets the fan device's speed level (performance state)"), + AH_PREDEF ("_FST", "Fan Status", "Returns current status information for a fan device"), + AH_PREDEF ("_GAI", "Get Averaging Interval", "Returns the power meter averaging interval"), + AH_PREDEF ("_GCP", "Get Capabilities", "Get device time capabilities"), + AH_PREDEF ("_GHL", "Get Hardware Limit", "Returns the hardware limit enforced by the power meter"), + AH_PREDEF ("_GL_", "Global Lock", "OS-defined Global Lock mutex object"), + AH_PREDEF ("_GLK", "Get Global Lock Requirement", "Returns a device's Global Lock requirement for device access"), + AH_PREDEF ("_GPD", "Get Post Data", "Returns the value of the VGA device that will be posted at boot"), + AH_PREDEF ("_GPE", "General Purpose Events", "Predefined scope (\\_GPE) or SCI number for EC"), + AH_PREDEF ("_GRA", "Granularity", "Address space granularity, Resource Descriptor field"), + AH_PREDEF ("_GRT", "Get Real Time", "Returns current time-of-day from a time/alarm device"), + AH_PREDEF ("_GSB", "Global System Interrupt Base", "Returns the GSB for a I/O APIC device"), + AH_PREDEF ("_GTF", "Get Task File", "Returns a list of ATA commands to restore a drive to default state"), + AH_PREDEF ("_GTM", "Get Timing Mode", "Returns a list of IDE controller timing information"), + AH_PREDEF ("_GTS", "Going To Sleep", "Inform AML of pending sleep"), + AH_PREDEF ("_GWS", "Get Wake Status", "Return status of wake alarms"), + AH_PREDEF ("_HE_", "High-Edge", "Interrupt triggering, Resource Descriptor field"), + AH_PREDEF ("_HID", "Hardware ID", "Returns a device's Plug and Play Hardware ID"), + AH_PREDEF ("_HOT", "Hot Temperature", "Returns the critical temperature for sleep (entry to S4)"), + AH_PREDEF ("_HPP", "Hot Plug Parameters", "Returns a list of hot-plug information for a PCI device"), + AH_PREDEF ("_HPX", "Hot Plug Parameter Extensions", "Returns a list of hot-plug information for a PCI device. Supersedes _HPP"), + AH_PREDEF ("_HRV", "Hardware Revision", "Returns a hardware revision value"), + AH_PREDEF ("_IFT", "IPMI Interface Type", "See the Intelligent Platform Management Interface Specification"), + AH_PREDEF ("_INI", "Initialize", "Performs device specific initialization"), + AH_PREDEF ("_INT", "Interrupts", "Interrupt mask bits, Resource Descriptor field"), + AH_PREDEF ("_IOR", "I/O Restriction", "Restriction type, Resource Descriptor field"), + AH_PREDEF ("_IRC", "Inrush Current", "Presence indicates that a device has a significant inrush current draw"), + AH_PREDEF ("_Lxx", "Level-Triggered GPE", "Control method executed as a result of a general-purpose event"), + AH_PREDEF ("_LCK", "Lock Device", "Locks or unlocks a device (docking)"), + AH_PREDEF ("_LEN", "Length", "Range length, Resource Descriptor field"), + AH_PREDEF ("_LID", "Lid Status", "Returns the open/closed status of the lid on a mobile system"), + AH_PREDEF ("_LIN", "Lines In Use", "Handshake lines, Resource Descriptor field"), + AH_PREDEF ("_LL_", "Low Level", "Interrupt polarity, Resource Descriptor field"), + AH_PREDEF ("_LPD", "Low Power Dependencies", "Returns a list of dependencies for low power idle entry"), + AH_PREDEF ("_LPI", "Low Power Idle States", "Returns a list of supported low power idle states"), + AH_PREDEF ("_MAF", "Maximum Address Fixed", "Resource Descriptor field"), + AH_PREDEF ("_MAT", "Multiple APIC Table Entry", "Returns a list of MADT APIC structure entries"), + AH_PREDEF ("_MAX", "Maximum Base Address", "Resource Descriptor field"), + AH_PREDEF ("_MBM", "Memory Bandwidth Monitoring Data", "Returns bandwidth monitoring data for a memory device"), + AH_PREDEF ("_MEM", "Memory Attributes", "Resource Descriptor field"), + AH_PREDEF ("_MIF", "Minimum Address Fixed", "Resource Descriptor field"), + AH_PREDEF ("_MIN", "Minimum Base Address", "Resource Descriptor field"), + AH_PREDEF ("_MLS", "Multiple Language String", "Returns a device description in multiple languages"), + AH_PREDEF ("_MOD", "Mode", "Interrupt mode, Resource Descriptor field"), + AH_PREDEF ("_MSG", "Message", "Sets the system message waiting status indicator"), + AH_PREDEF ("_MSM", "Memory Set Monitoring", "Sets bandwidth monitoring parameters for a memory device"), + AH_PREDEF ("_MTL", "Minimum Throttle Limit", "Returns the minimum throttle limit for a thermal zone"), + AH_PREDEF ("_MTP", "Memory Type", "Resource Descriptor field"), + AH_PREDEF ("_NTT", "Notification Temperature Threshold", "Returns a threshold for device temperature change that requires platform notification"), + AH_PREDEF ("_OFF", "Power Off", "Sets a power resource to the off state"), + AH_PREDEF ("_ON_", "Power On", "Sets a power resource to the on state"), + AH_PREDEF ("_OS_", "Operating System", "Returns a string that identifies the operating system"), + AH_PREDEF ("_OSC", "Operating System Capabilities", "Inform AML of host features and capabilities"), + AH_PREDEF ("_OSI", "Operating System Interfaces", "Returns supported interfaces, behaviors, and features"), + AH_PREDEF ("_OST", "OSPM Status Indication", "Inform AML of event processing status"), + AH_PREDEF ("_PAI", "Power Averaging Interval", "Sets the averaging interval for a power meter"), + AH_PREDEF ("_PAR", "Parity", "Parity bits, Resource Descriptor field"), + AH_PREDEF ("_PCL", "Power Consumer List", "Returns a list of devices powered by a power source"), + AH_PREDEF ("_PCT", "Performance Control", "Returns processor performance control and status registers"), + AH_PREDEF ("_PDC", "Processor Driver Capabilities", "Inform AML of processor driver capabilities"), + AH_PREDEF ("_PDL", "P-state Depth Limit", "Returns the lowest available performance P-state"), + AH_PREDEF ("_PHA", "Clock Phase", "Clock phase, Resource Descriptor field"), + AH_PREDEF ("_PIC", "Interrupt Model", "Inform AML of the interrupt model in use"), + AH_PREDEF ("_PIF", "Power Source Information", "Returns a Power Source information block"), + AH_PREDEF ("_PIN", "Pin List", "Pin list, Resource Descriptor field"), + AH_PREDEF ("_PLD", "Physical Location of Device", "Returns a device's physical location information"), + AH_PREDEF ("_PMC", "Power Meter Capabilities", "Returns a list of Power Meter capabilities info"), + AH_PREDEF ("_PMD", "Power Metered Devices", "Returns a list of devices that are measured by the power meter device"), + AH_PREDEF ("_PMM", "Power Meter Measurement", "Returns the current value of the Power Meter"), + AH_PREDEF ("_POL", "Polarity", "Interrupt polarity, Resource Descriptor field"), + AH_PREDEF ("_PPC", "Performance Present Capabilities", "Returns a list of the performance states currently supported by the platform"), + AH_PREDEF ("_PPE", "Polling for Platform Error", "Returns the polling interval to retrieve Corrected Platform Error information"), + AH_PREDEF ("_PPI", "Pin Configuration", "Resource Descriptor field"), + AH_PREDEF ("_PR", "Processor", "Predefined scope for processor objects"), + AH_PREDEF ("_PR0", "Power Resources for D0", "Returns a list of dependent power resources to enter state D0 (fully on)"), + AH_PREDEF ("_PR1", "Power Resources for D1", "Returns a list of dependent power resources to enter state D1"), + AH_PREDEF ("_PR2", "Power Resources for D2", "Returns a list of dependent power resources to enter state D2"), + AH_PREDEF ("_PR3", "Power Resources for D3hot", "Returns a list of dependent power resources to enter state D3hot"), + AH_PREDEF ("_PRE", "Power Resources for Enumeration", "Returns a list of dependent power resources to enumerate devices on a bus"), + AH_PREDEF ("_PRL", "Power Source Redundancy List", "Returns a list of power source devices in the same redundancy grouping"), + AH_PREDEF ("_PRR", "Power Resource for Reset", "Execute a reset on a device"), + AH_PREDEF ("_PRS", "Possible Resource Settings", "Returns a list of a device's possible resource settings"), + AH_PREDEF ("_PRT", "PCI Routing Table", "Returns a list of PCI interrupt mappings"), + AH_PREDEF ("_PRW", "Power Resources for Wake", "Returns a list of dependent power resources for waking"), + AH_PREDEF ("_PS0", "Power State 0", "Sets a device's power state to D0 (device fully on)"), + AH_PREDEF ("_PS1", "Power State 1", "Sets a device's power state to D1"), + AH_PREDEF ("_PS2", "Power State 2", "Sets a device's power state to D2"), + AH_PREDEF ("_PS3", "Power State 3", "Sets a device's power state to D3 (device off)"), + AH_PREDEF ("_PSC", "Power State Current", "Returns a device's current power state"), + AH_PREDEF ("_PSD", "Power State Dependencies", "Returns processor P-State dependencies"), + AH_PREDEF ("_PSE", "Power State for Enumeration", "Put a bus into enumeration power mode"), + AH_PREDEF ("_PSL", "Passive List", "Returns a list of passive cooling device objects"), + AH_PREDEF ("_PSR", "Power Source", "Returns the power source device currently in use"), + AH_PREDEF ("_PSS", "Performance Supported States", "Returns a list of supported processor performance states"), + AH_PREDEF ("_PSV", "Passive Temperature", "Returns the passive trip point temperature"), + AH_PREDEF ("_PSW", "Power State Wake", "Sets a device's wake function"), + AH_PREDEF ("_PTC", "Processor Throttling Control", "Returns throttling control and status registers"), + AH_PREDEF ("_PTP", "Power Trip Points", "Sets trip points for the Power Meter device"), + AH_PREDEF ("_PTS", "Prepare To Sleep", "Inform the platform of an impending sleep transition"), + AH_PREDEF ("_PUR", "Processor Utilization Request", "Returns the number of processors that the platform would like to idle"), + AH_PREDEF ("_PXM", "Device Proximity", "Returns a device's proximity domain identifier"), + AH_PREDEF ("_Qxx", "EC Query", "Embedded Controller query and SMBus Alarm control method"), + AH_PREDEF ("_RBO", "Register Bit Offset", "Resource Descriptor field"), + AH_PREDEF ("_RBW", "Register Bit Width", "Resource Descriptor field"), + AH_PREDEF ("_RDI", "Resource Dependencies for Idle", "Returns a list of dependencies for idle states"), + AH_PREDEF ("_REG", "Region Availability", "Inform AML code of an operation region availability change"), + AH_PREDEF ("_REV", "Supported Integer Width", "Returns the supported integer width (<= 1: 32 bits only, >=2: both 32 and 64 bits"), + AH_PREDEF ("_RMV", "Removal Status", "Returns a device's removal ability status (docking)"), + AH_PREDEF ("_RNG", "Range", "Memory range type, Resource Descriptor field"), + AH_PREDEF ("_RST", "Device Reset", "Executes a reset on a device"), + AH_PREDEF ("_ROM", "Read-Only Memory", "Returns a copy of the ROM data for a display device"), + AH_PREDEF ("_RT_", "Resource Type", "Resource Descriptor field"), + AH_PREDEF ("_RTV", "Relative Temperature Values", "Returns temperature value information"), + AH_PREDEF ("_RW_", "Read-Write Status", "Resource Descriptor field"), + AH_PREDEF ("_RXL", "Receive Buffer Size", "Serial channel buffer, Resource Descriptor field"), + AH_PREDEF ("_S0_", "S0 System State", "Returns values to enter the system into the S0 state"), + AH_PREDEF ("_S1_", "S1 System State", "Returns values to enter the system into the S1 state"), + AH_PREDEF ("_S2_", "S2 System State", "Returns values to enter the system into the S2 state"), + AH_PREDEF ("_S3_", "S3 System State", "Returns values to enter the system into the S3 state"), + AH_PREDEF ("_S4_", "S4 System State", "Returns values to enter the system into the S4 state"), + AH_PREDEF ("_S5_", "S5 System State", "Returns values to enter the system into the S5 state"), + AH_PREDEF ("_S1D", "S1 Device State", "Returns the highest D-state supported by a device when in the S1 state"), + AH_PREDEF ("_S2D", "S2 Device State", "Returns the highest D-state supported by a device when in the S2 state"), + AH_PREDEF ("_S3D", "S3 Device State", "Returns the highest D-state supported by a device when in the S3 state"), + AH_PREDEF ("_S4D", "S4 Device State", "Returns the highest D-state supported by a device when in the S4 state"), + AH_PREDEF ("_S0W", "S0 Device Wake State", "Returns the lowest D-state that the device can wake itself from S0"), + AH_PREDEF ("_S1W", "S1 Device Wake State", "Returns the lowest D-state for this device that can wake the system from S1"), + AH_PREDEF ("_S2W", "S2 Device Wake State", "Returns the lowest D-state for this device that can wake the system from S2"), + AH_PREDEF ("_S3W", "S3 Device Wake State", "Returns the lowest D-state for this device that can wake the system from S3"), + AH_PREDEF ("_S4W", "S4 Device Wake State", "Returns the lowest D-state for this device that can wake the system from S4"), + AH_PREDEF ("_SB_", "System Bus", "Predefined scope for device and bus objects"), + AH_PREDEF ("_SBS", "Smart Battery Subsystem", "Returns the subsystem configuration"), + AH_PREDEF ("_SCP", "Set Cooling Policy", "Sets the cooling policy (active or passive)"), + AH_PREDEF ("_SDD", "Set Device Data", "Sets data for a SATA device"), + AH_PREDEF ("_SEG", "PCI Segment", "Returns a device's PCI Segment Group number"), + AH_PREDEF ("_SHL", "Set Hardware Limit", "Sets the hardware limit enforced by the Power Meter"), + AH_PREDEF ("_SHR", "Sharable", "Interrupt share status, Resource Descriptor field"), + AH_PREDEF ("_SI_", "System Indicators", "Predefined scope"), + AH_PREDEF ("_SIZ", "Size", "DMA transfer size, Resource Descriptor field"), + AH_PREDEF ("_SLI", "System Locality Information", "Returns a list of NUMA system localities"), + AH_PREDEF ("_SLV", "Slave Mode", "Mode setting, Resource Descriptor field"), + AH_PREDEF ("_SPD", "Set Post Device", "Sets which video device will be posted at boot"), + AH_PREDEF ("_SPE", "Speed", "Connection speed, Resource Descriptor field"), + AH_PREDEF ("_SRS", "Set Resource Settings", "Sets a device's resource allocation"), + AH_PREDEF ("_SRT", "Set Real Time", "Sets the current time for a time/alarm device"), + AH_PREDEF ("_SRV", "IPMI Spec Revision", "See the Intelligent Platform Management Interface Specification"), + AH_PREDEF ("_SST", "System Status", "Sets the system status indicator"), + AH_PREDEF ("_STA", "Status", "Returns the current status of a Device or Power Resource"), + AH_PREDEF ("_STB", "Stop Bits", "Serial channel stop bits, Resource Descriptor field"), + AH_PREDEF ("_STM", "Set Timing Mode", "Sets an IDE controller transfer timings"), + AH_PREDEF ("_STP", "Set Expired Timer Wake Policy", "Sets expired timer policies of the wake alarm device"), + AH_PREDEF ("_STR", "Description String", "Returns a device's description string"), + AH_PREDEF ("_STV", "Set Timer Value", "Set timer values of the wake alarm device"), + AH_PREDEF ("_SUB", "Subsystem ID", "Returns the subsystem ID for a device"), + AH_PREDEF ("_SUN", "Slot User Number", "Returns the slot unique ID number"), + AH_PREDEF ("_SWS", "System Wake Source", "Returns the source event that caused the system to wake"), + AH_PREDEF ("_T_x", "Emitted by ASL Compiler", "Reserved for use by ASL compilers"), + AH_PREDEF ("_TC1", "Thermal Constant 1", "Returns TC1 for the passive cooling formula"), + AH_PREDEF ("_TC2", "Thermal Constant 2", "Returns TC2 for the passive cooling formula"), + AH_PREDEF ("_TDL", "T-State Depth Limit", "Returns the _TSS entry number of the lowest power throttling state"), + AH_PREDEF ("_TFP", "Thermal Fast Sampling Period", "Returns the sampling period for passive cooling"), + AH_PREDEF ("_TIP", "Expired Timer Wake Policy", "Returns timer policies of the wake alarm device"), + AH_PREDEF ("_TIV", "Timer Values", "Returns remaining time of the wake alarm device"), + AH_PREDEF ("_TMP", "Temperature", "Returns a thermal zone's current temperature"), + AH_PREDEF ("_TPC", "Throttling Present Capabilities", "Returns the current number of supported throttling states"), + AH_PREDEF ("_TPT", "Trip Point Temperature", "Inform AML that a device's embedded temperature sensor has crossed a temperature trip point"), + AH_PREDEF ("_TRA", "Translation", "Address translation offset, Resource Descriptor field"), + AH_PREDEF ("_TRS", "Translation Sparse", "Sparse/dense flag, Resource Descriptor field"), + AH_PREDEF ("_TRT", "Thermal Relationship Table", "Returns thermal relationships between platform devices"), + AH_PREDEF ("_TSD", "Throttling State Dependencies", "Returns a list of T-state dependencies"), + AH_PREDEF ("_TSF", "Type-Specific Flags", "Resource Descriptor field"), + AH_PREDEF ("_TSN", "Thermal Sensor Device", "Returns a reference to a thermal sensor"), + AH_PREDEF ("_TSP", "Thermal Sampling Period", "Returns the thermal sampling period for passive cooling"), + AH_PREDEF ("_TSS", "Throttling Supported States", "Returns supported throttling state information"), + AH_PREDEF ("_TST", "Temperature Sensor Threshold", "Returns the minimum separation for a device's temperature trip points"), + AH_PREDEF ("_TTP", "Translation Type", "Translation/static flag, Resource Descriptor field"), + AH_PREDEF ("_TTS", "Transition To State", "Inform AML of an S-state transition"), + AH_PREDEF ("_TXL", "Transmit Buffer Size", "Serial Channel buffer, Resource Descriptor field"), + AH_PREDEF ("_TYP", "Type", "DMA channel type (speed), Resource Descriptor field"), + AH_PREDEF ("_TZ_", "Thermal Zone", "Predefined scope: ACPI 1.0"), + AH_PREDEF ("_TZD", "Thermal Zone Devices", "Returns a list of device names associated with a Thermal Zone"), + AH_PREDEF ("_TZM", "Thermal Zone Member", "Returns a reference to the thermal zone of which a device is a member"), + AH_PREDEF ("_TZP", "Thermal Zone Polling", "Returns a Thermal zone's polling frequency"), + AH_PREDEF ("_UID", "Unique ID", "Return a device's unique persistent ID"), + AH_PREDEF ("_UPC", "USB Port Capabilities", "Returns a list of USB port capabilities"), + AH_PREDEF ("_UPD", "User Presence Detect", "Returns user detection information"), + AH_PREDEF ("_UPP", "User Presence Polling", "Returns the recommended user presence polling interval"), + AH_PREDEF ("_VEN", "Vendor Data", "Resource Descriptor field"), + AH_PREDEF ("_VPO", "Video Post Options", "Returns the implemented video post options"), + AH_PREDEF ("_WAK", "Wake", "Inform AML that the system has just awakened"), + AH_PREDEF ("_Wxx", "Wake Event", "Method executed as a result of a wake event"), + AH_PREDEF (NULL, NULL, NULL) +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiAhMatchPredefinedName + * + * PARAMETERS: Nameseg - Predefined name string + * + * RETURN: ID info struct. NULL if Nameseg not found + * + * DESCRIPTION: Lookup a predefined name. + * + ******************************************************************************/ + +const AH_PREDEFINED_NAME * +AcpiAhMatchPredefinedName ( + char *Nameseg) +{ + const AH_PREDEFINED_NAME *Info; + + + for (Info = AslPredefinedInfo; Info->Name; Info++) + { + if (ACPI_COMPARE_NAME (Nameseg, Info->Name)) + { + return (Info); + } + } + + return (NULL); +} diff --git a/third_party/lib/acpica/source/common/ahtable.c b/third_party/lib/acpica/source/common/ahtable.c new file mode 100644 index 000000000..beb64c85e --- /dev/null +++ b/third_party/lib/acpica/source/common/ahtable.c @@ -0,0 +1,150 @@ +/****************************************************************************** + * + * Module Name: ahtable - Table of known ACPI tables with descriptions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +/* Local prototypes */ + +const AH_TABLE * +AcpiAhGetTableInfo ( + char *Signature); + +extern const AH_TABLE AcpiSupportedTables[]; + + +/******************************************************************************* + * + * FUNCTION: AcpiAhGetTableInfo + * + * PARAMETERS: Signature - ACPI signature (4 chars) to match + * + * RETURN: Pointer to a valid AH_TABLE. Null if no match found. + * + * DESCRIPTION: Find a match in the "help" table of supported ACPI tables + * + ******************************************************************************/ + +const AH_TABLE * +AcpiAhGetTableInfo ( + char *Signature) +{ + const AH_TABLE *Info; + + + for (Info = AcpiSupportedTables; Info->Signature; Info++) + { + if (ACPI_COMPARE_NAME (Signature, Info->Signature)) + { + return (Info); + } + } + + return (NULL); +} + + +/* + * Note: Any tables added here should be duplicated within AcpiDmTableData + * in the file common/dmtable.c + */ +const AH_TABLE AcpiSupportedTables[] = +{ + {ACPI_SIG_ASF, "Alert Standard Format table"}, + {ACPI_SIG_BERT, "Boot Error Record Table"}, + {ACPI_SIG_BGRT, "Boot Graphics Resource Table"}, + {ACPI_SIG_BOOT, "Simple Boot Flag Table"}, + {ACPI_SIG_CPEP, "Corrected Platform Error Polling table"}, + {ACPI_SIG_CSRT, "Core System Resource Table"}, + {ACPI_SIG_DBG2, "Debug Port table type 2"}, + {ACPI_SIG_DBGP, "Debug Port table"}, + {ACPI_SIG_DMAR, "DMA Remapping table"}, + {ACPI_SIG_DRTM, "Dynamic Root of Trust for Measurement table"}, + {ACPI_SIG_DSDT, "Differentiated System Description Table (AML table)"}, + {ACPI_SIG_ECDT, "Embedded Controller Boot Resources Table"}, + {ACPI_SIG_EINJ, "Error Injection table"}, + {ACPI_SIG_ERST, "Error Record Serialization Table"}, + {ACPI_SIG_FACS, "Firmware ACPI Control Structure"}, + {ACPI_SIG_FADT, "Fixed ACPI Description Table (FADT)"}, + {ACPI_SIG_FPDT, "Firmware Performance Data Table"}, + {ACPI_SIG_GTDT, "Generic Timer Description Table"}, + {ACPI_SIG_HEST, "Hardware Error Source Table"}, + {ACPI_SIG_HPET, "High Precision Event Timer table"}, + {ACPI_SIG_IORT, "IO Remapping Table"}, + {ACPI_SIG_IVRS, "I/O Virtualization Reporting Structure"}, + {ACPI_SIG_LPIT, "Low Power Idle Table"}, + {ACPI_SIG_MADT, "Multiple APIC Description Table (MADT)"}, + {ACPI_SIG_MCFG, "Memory Mapped Configuration table"}, + {ACPI_SIG_MCHI, "Management Controller Host Interface table"}, + {ACPI_SIG_MPST, "Memory Power State Table"}, + {ACPI_SIG_MSCT, "Maximum System Characteristics Table"}, + {ACPI_SIG_MSDM, "Microsoft Data Management table"}, + {ACPI_SIG_MTMR, "MID Timer Table"}, + {ACPI_SIG_NFIT, "NVDIMM Firmware Interface Table"}, + {ACPI_SIG_PCCT, "Platform Communications Channel Table"}, + {ACPI_SIG_PMTT, "Platform Memory Topology Table"}, + {ACPI_RSDP_NAME,"Root System Description Pointer"}, + {ACPI_SIG_RSDT, "Root System Description Table"}, + {ACPI_SIG_S3PT, "S3 Performance Table"}, + {ACPI_SIG_SBST, "Smart Battery Specification Table"}, + {ACPI_SIG_SLIC, "Software Licensing Description Table"}, + {ACPI_SIG_SLIT, "System Locality Information Table"}, + {ACPI_SIG_SPCR, "Serial Port Console Redirection table"}, + {ACPI_SIG_SPMI, "Server Platform Management Interface table"}, + {ACPI_SIG_SRAT, "System Resource Affinity Table"}, + {ACPI_SIG_SSDT, "Secondary System Description Table (AML table)"}, + {ACPI_SIG_STAO, "Status Override table"}, + {ACPI_SIG_TCPA, "Trusted Computing Platform Alliance table"}, + {ACPI_SIG_TPM2, "Trusted Platform Module hardware interface table"}, + {ACPI_SIG_UEFI, "UEFI Boot Optimization Table"}, + {ACPI_SIG_VRTC, "Virtual Real-Time Clock Table"}, + {ACPI_SIG_WAET, "Windows ACPI Emulated Devices Table"}, + {ACPI_SIG_WDAT, "Watchdog Action Table"}, + {ACPI_SIG_WDDT, "Watchdog Description Table"}, + {ACPI_SIG_WDRT, "Watchdog Resource Table"}, + {ACPI_SIG_WPBT, "Windows Platform Binary Table"}, + {ACPI_SIG_XENV, "Xen Environment table"}, + {ACPI_SIG_XSDT, "Extended System Description Table"}, + {NULL, NULL} +}; diff --git a/third_party/lib/acpica/source/common/ahuuids.c b/third_party/lib/acpica/source/common/ahuuids.c new file mode 100644 index 000000000..ec75624d4 --- /dev/null +++ b/third_party/lib/acpica/source/common/ahuuids.c @@ -0,0 +1,133 @@ +/****************************************************************************** + * + * Module Name: ahuuids - Table of known ACPI-related UUIDs + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acuuid.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("ahuuids") + + +/* + * Table of "known" (ACPI-related) UUIDs + */ +const AH_UUID AcpiUuids[] = +{ + {"[Controllers]", NULL}, + {"GPIO Controller", UUID_GPIO_CONTROLLER}, + {"USB Controller", UUID_USB_CONTROLLER}, + {"SATA Controller", UUID_SATA_CONTROLLER}, + + {"[Devices]", NULL}, + {"PCI Host Bridge Device", UUID_PCI_HOST_BRIDGE}, + {"HID I2C Device", UUID_I2C_DEVICE}, + {"Power Button Device", UUID_POWER_BUTTON}, + + {"[Interfaces]", NULL}, + {"Device Labeling Interface", UUID_DEVICE_LABELING}, + {"Physical Presence Interface", UUID_PHYSICAL_PRESENCE}, + + {"[Non-volatile DIMM and NFIT table]", NULL}, + {"Volatile Memory Region", UUID_VOLATILE_MEMORY}, + {"Persistent Memory Region", UUID_PERSISTENT_MEMORY}, + {"NVDIMM Control Region", UUID_CONTROL_REGION}, + {"NVDIMM Data Region", UUID_DATA_REGION}, + {"Volatile Virtual Disk", UUID_VOLATILE_VIRTUAL_DISK}, + {"Volatile Virtual CD", UUID_VOLATILE_VIRTUAL_CD}, + {"Persistent Virtual Disk", UUID_PERSISTENT_VIRTUAL_DISK}, + {"Persistent Virtual CD", UUID_PERSISTENT_VIRTUAL_CD}, + + {"[Miscellaneous]", NULL}, + {"Platform-wide Capabilities", UUID_PLATFORM_CAPABILITIES}, + {"Dynamic Enumeration", UUID_DYNAMIC_ENUMERATION}, + {"Battery Thermal Limit", UUID_BATTERY_THERMAL_LIMIT}, + {"Thermal Extensions", UUID_THERMAL_EXTENSIONS}, + {"Device Properties for _DSD", UUID_DEVICE_PROPERTIES}, + + {NULL, NULL} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiAhMatchUuid + * + * PARAMETERS: Data - Data buffer containing a UUID + * + * RETURN: ASCII description string for the UUID if it is found. + * + * DESCRIPTION: Returns a description string for "known" UUIDs, which are + * are UUIDs that are related to ACPI in some way. + * + ******************************************************************************/ + +const char * +AcpiAhMatchUuid ( + UINT8 *Data) +{ + const AH_UUID *Info; + UINT8 UuidBuffer[UUID_BUFFER_LENGTH]; + + + /* Walk the table of known ACPI-related UUIDs */ + + for (Info = AcpiUuids; Info->Description; Info++) + { + /* Null string means desciption is a UUID class */ + + if (!Info->String) + { + continue; + } + + AcpiUtConvertStringToUuid (Info->String, UuidBuffer); + + if (!memcmp (Data, UuidBuffer, UUID_BUFFER_LENGTH)) + { + return (Info->Description); + } + } + + return (NULL); +} diff --git a/third_party/lib/acpica/source/common/cmfsize.c b/third_party/lib/acpica/source/common/cmfsize.c new file mode 100644 index 000000000..d9df6bc06 --- /dev/null +++ b/third_party/lib/acpica/source/common/cmfsize.c @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Module Name: cfsize - Common get file size function + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("cmfsize") + + +/******************************************************************************* + * + * FUNCTION: CmGetFileSize + * + * PARAMETERS: File - Open file descriptor + * + * RETURN: File Size. On error, -1 (ACPI_UINT32_MAX) + * + * DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open. + * Does not disturb the current file pointer. + * + ******************************************************************************/ + +UINT32 +CmGetFileSize ( + ACPI_FILE File) +{ + long FileSize; + long CurrentOffset; + ACPI_STATUS Status; + + + /* Save the current file pointer, seek to EOF to obtain file size */ + + CurrentOffset = AcpiOsGetFileOffset (File); + if (CurrentOffset < 0) + { + goto OffsetError; + } + + Status = AcpiOsSetFileOffset (File, 0, ACPI_FILE_END); + if (ACPI_FAILURE (Status)) + { + goto SeekError; + } + + FileSize = AcpiOsGetFileOffset (File); + if (FileSize < 0) + { + goto OffsetError; + } + + /* Restore original file pointer */ + + Status = AcpiOsSetFileOffset (File, CurrentOffset, ACPI_FILE_BEGIN); + if (ACPI_FAILURE (Status)) + { + goto SeekError; + } + + return ((UINT32) FileSize); + + +OffsetError: + AcpiLogError ("Could not get file offset"); + return (ACPI_UINT32_MAX); + +SeekError: + AcpiLogError ("Could not set file offset"); + return (ACPI_UINT32_MAX); +} diff --git a/third_party/lib/acpica/source/common/dmextern.c b/third_party/lib/acpica/source/common/dmextern.c new file mode 100644 index 000000000..403e684b1 --- /dev/null +++ b/third_party/lib/acpica/source/common/dmextern.c @@ -0,0 +1,1393 @@ +/****************************************************************************** + * + * Module Name: dmextern - Support for External() ASL statements + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdisasm.h" +#include "aslcompiler.h" +#include +#include + + +/* + * This module is used for application-level code (iASL disassembler) only. + * + * It contains the code to create and emit any necessary External() ASL + * statements for the module being disassembled. + */ +#define _COMPONENT ACPI_CA_DISASSEMBLER + ACPI_MODULE_NAME ("dmextern") + + +/* + * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL + * ObjectTypeKeyword. Used to generate typed external declarations + */ +static const char *AcpiGbl_DmTypeNames[] = +{ + /* 00 */ ", UnknownObj", /* Type ANY */ + /* 01 */ ", IntObj", + /* 02 */ ", StrObj", + /* 03 */ ", BuffObj", + /* 04 */ ", PkgObj", + /* 05 */ ", FieldUnitObj", + /* 06 */ ", DeviceObj", + /* 07 */ ", EventObj", + /* 08 */ ", MethodObj", + /* 09 */ ", MutexObj", + /* 10 */ ", OpRegionObj", + /* 11 */ ", PowerResObj", + /* 12 */ ", ProcessorObj", + /* 13 */ ", ThermalZoneObj", + /* 14 */ ", BuffFieldObj", + /* 15 */ ", DDBHandleObj", + /* 16 */ "", /* Debug object */ + /* 17 */ ", FieldUnitObj", + /* 18 */ ", FieldUnitObj", + /* 19 */ ", FieldUnitObj" +}; + +#define METHOD_SEPARATORS " \t,()\n" + + +/* Local prototypes */ + +static const char * +AcpiDmGetObjectTypeName ( + ACPI_OBJECT_TYPE Type); + +static char * +AcpiDmNormalizeParentPrefix ( + ACPI_PARSE_OBJECT *Op, + char *Path); + +static void +AcpiDmAddPathToExternalList ( + char *Path, + UINT8 Type, + UINT32 Value, + UINT16 Flags); + +static ACPI_STATUS +AcpiDmCreateNewExternal ( + char *ExternalPath, + char *InternalPath, + UINT8 Type, + UINT32 Value, + UINT16 Flags); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetObjectTypeName + * + * PARAMETERS: Type - An ACPI_OBJECT_TYPE + * + * RETURN: Pointer to a string + * + * DESCRIPTION: Map an object type to the ASL object type string. + * + ******************************************************************************/ + +static const char * +AcpiDmGetObjectTypeName ( + ACPI_OBJECT_TYPE Type) +{ + + if (Type == ACPI_TYPE_LOCAL_SCOPE) + { + Type = ACPI_TYPE_DEVICE; + } + else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD) + { + return (""); + } + + return (AcpiGbl_DmTypeNames[Type]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmNormalizeParentPrefix + * + * PARAMETERS: Op - Parse op + * Path - Path with parent prefix + * + * RETURN: The full pathname to the object (from the namespace root) + * + * DESCRIPTION: Returns the full pathname of a path with parent prefix + * The caller must free the fullpath returned. + * + ******************************************************************************/ + +static char * +AcpiDmNormalizeParentPrefix ( + ACPI_PARSE_OBJECT *Op, + char *Path) +{ + ACPI_NAMESPACE_NODE *Node; + char *Fullpath; + char *ParentPath; + ACPI_SIZE Length; + UINT32 Index = 0; + + + if (!Op) + { + return (NULL); + } + + /* Search upwards in the parse tree until we reach the next namespace node */ + + Op = Op->Common.Parent; + while (Op) + { + if (Op->Common.Node) + { + break; + } + + Op = Op->Common.Parent; + } + + if (!Op) + { + return (NULL); + } + + /* + * Find the actual parent node for the reference: + * Remove all carat prefixes from the input path. + * There may be multiple parent prefixes (For example, ^^^M000) + */ + Node = Op->Common.Node; + while (Node && (*Path == (UINT8) AML_PARENT_PREFIX)) + { + Node = Node->Parent; + Path++; + } + + if (!Node) + { + return (NULL); + } + + /* Get the full pathname for the parent node */ + + ParentPath = AcpiNsGetExternalPathname (Node); + if (!ParentPath) + { + return (NULL); + } + + Length = (strlen (ParentPath) + strlen (Path) + 1); + if (ParentPath[1]) + { + /* + * If ParentPath is not just a simple '\', increment the length + * for the required dot separator (ParentPath.Path) + */ + Length++; + + /* For External() statements, we do not want a leading '\' */ + + if (*ParentPath == AML_ROOT_PREFIX) + { + Index = 1; + } + } + + Fullpath = ACPI_ALLOCATE_ZEROED (Length); + if (!Fullpath) + { + goto Cleanup; + } + + /* + * Concatenate parent fullpath and path. For example, + * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT" + * + * Copy the parent path + */ + strcpy (Fullpath, &ParentPath[Index]); + + /* + * Add dot separator + * (don't need dot if parent fullpath is a single backslash) + */ + if (ParentPath[1]) + { + strcat (Fullpath, "."); + } + + /* Copy child path (carat parent prefix(es) were skipped above) */ + + strcat (Fullpath, Path); + +Cleanup: + ACPI_FREE (ParentPath); + return (Fullpath); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddToExternalFileList + * + * PARAMETERS: PathList - Single path or list separated by comma + * + * RETURN: None + * + * DESCRIPTION: Add external files to global list + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDmAddToExternalFileList ( + char *Pathname) +{ + ACPI_EXTERNAL_FILE *ExternalFile; + char *LocalPathname; + + + if (!Pathname) + { + return (AE_OK); + } + + LocalPathname = ACPI_ALLOCATE (strlen (Pathname) + 1); + if (!LocalPathname) + { + return (AE_NO_MEMORY); + } + + ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE)); + if (!ExternalFile) + { + ACPI_FREE (LocalPathname); + return (AE_NO_MEMORY); + } + + /* Take a copy of the file pathname */ + + strcpy (LocalPathname, Pathname); + ExternalFile->Path = LocalPathname; + + if (AcpiGbl_ExternalFileList) + { + ExternalFile->Next = AcpiGbl_ExternalFileList; + } + + AcpiGbl_ExternalFileList = ExternalFile; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmClearExternalFileList + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Clear the external file list + * + ******************************************************************************/ + +void +AcpiDmClearExternalFileList ( + void) +{ + ACPI_EXTERNAL_FILE *NextExternal; + + + while (AcpiGbl_ExternalFileList) + { + NextExternal = AcpiGbl_ExternalFileList->Next; + ACPI_FREE (AcpiGbl_ExternalFileList->Path); + ACPI_FREE (AcpiGbl_ExternalFileList); + AcpiGbl_ExternalFileList = NextExternal; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetExternalsFromFile + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Process the optional external reference file. + * + * Each line in the file should be of the form: + * External (, MethodObj, ) + * + * Example: + * External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4) + * + ******************************************************************************/ + +void +AcpiDmGetExternalsFromFile ( + void) +{ + FILE *ExternalRefFile; + char *Token; + char *MethodName; + UINT32 ArgCount; + UINT32 ImportCount = 0; + + + if (!Gbl_ExternalRefFilename) + { + return; + } + + /* Open the file */ + + ExternalRefFile = fopen (Gbl_ExternalRefFilename, "r"); + if (!ExternalRefFile) + { + fprintf (stderr, "Could not open external reference file \"%s\"\n", + Gbl_ExternalRefFilename); + AslAbort (); + return; + } + + /* Each line defines a method */ + + while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile)) + { + Token = strtok (StringBuffer, METHOD_SEPARATORS); /* "External" */ + if (!Token) + { + continue; + } + + if (strcmp (Token, "External")) + { + continue; + } + + MethodName = strtok (NULL, METHOD_SEPARATORS); /* Method namepath */ + if (!MethodName) + { + continue; + } + + Token = strtok (NULL, METHOD_SEPARATORS); /* "MethodObj" */ + if (!Token) + { + continue; + } + + if (strcmp (Token, "MethodObj")) + { + continue; + } + + Token = strtok (NULL, METHOD_SEPARATORS); /* Arg count */ + if (!Token) + { + continue; + } + + /* Convert arg count string to an integer */ + + errno = 0; + ArgCount = strtoul (Token, NULL, 0); + if (errno) + { + fprintf (stderr, "Invalid argument count (%s)\n", Token); + continue; + } + + if (ArgCount > 7) + { + fprintf (stderr, "Invalid argument count (%u)\n", ArgCount); + continue; + } + + /* Add this external to the global list */ + + AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n", + Gbl_ExternalRefFilename, ArgCount, MethodName); + + AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD, + ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE)); + ImportCount++; + } + + if (!ImportCount) + { + fprintf (stderr, + "Did not find any external methods in reference file \"%s\"\n", + Gbl_ExternalRefFilename); + } + else + { + /* Add the external(s) to the namespace */ + + AcpiDmAddExternalsToNamespace (); + + AcpiOsPrintf ("%s: Imported %u external method definitions\n", + Gbl_ExternalRefFilename, ImportCount); + } + + fclose (ExternalRefFile); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddOpToExternalList + * + * PARAMETERS: Op - Current parser Op + * Path - Internal (AML) path to the object + * Type - ACPI object type to be added + * Value - Arg count if adding a Method object + * Flags - To be passed to the external object + * + * RETURN: None + * + * DESCRIPTION: Insert a new name into the global list of Externals which + * will in turn be later emitted as an External() declaration + * in the disassembled output. + * + * This function handles the most common case where the referenced + * name is simply not found in the constructed namespace. + * + ******************************************************************************/ + +void +AcpiDmAddOpToExternalList ( + ACPI_PARSE_OBJECT *Op, + char *Path, + UINT8 Type, + UINT32 Value, + UINT16 Flags) +{ + char *ExternalPath; + char *InternalPath = Path; + char *Temp; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (DmAddOpToExternalList); + + + if (!Path) + { + return_VOID; + } + + /* Remove a root backslash if present */ + + if ((*Path == AML_ROOT_PREFIX) && (Path[1])) + { + Path++; + } + + /* Externalize the pathname */ + + Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path, + NULL, &ExternalPath); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + /* + * Get the full pathname from the root if "Path" has one or more + * parent prefixes (^). Note: path will not contain a leading '\'. + */ + if (*Path == (UINT8) AML_PARENT_PREFIX) + { + Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath); + + /* Set new external path */ + + ACPI_FREE (ExternalPath); + ExternalPath = Temp; + if (!Temp) + { + return_VOID; + } + + /* Create the new internal pathname */ + + Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED; + Status = AcpiNsInternalizeName (ExternalPath, &InternalPath); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (ExternalPath); + return_VOID; + } + } + + /* Create the new External() declaration node */ + + Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, + Type, Value, Flags); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (ExternalPath); + if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) + { + ACPI_FREE (InternalPath); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddNodeToExternalList + * + * PARAMETERS: Node - Namespace node for object to be added + * Type - ACPI object type to be added + * Value - Arg count if adding a Method object + * Flags - To be passed to the external object + * + * RETURN: None + * + * DESCRIPTION: Insert a new name into the global list of Externals which + * will in turn be later emitted as an External() declaration + * in the disassembled output. + * + * This function handles the case where the referenced name has + * been found in the namespace, but the name originated in a + * table other than the one that is being disassembled (such + * as a table that is added via the iASL -e option). + * + ******************************************************************************/ + +void +AcpiDmAddNodeToExternalList ( + ACPI_NAMESPACE_NODE *Node, + UINT8 Type, + UINT32 Value, + UINT16 Flags) +{ + char *ExternalPath; + char *InternalPath; + char *Temp; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (DmAddNodeToExternalList); + + + if (!Node) + { + return_VOID; + } + + /* Get the full external and internal pathnames to the node */ + + ExternalPath = AcpiNsGetExternalPathname (Node); + if (!ExternalPath) + { + return_VOID; + } + + Status = AcpiNsInternalizeName (ExternalPath, &InternalPath); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (ExternalPath); + return_VOID; + } + + /* Remove the root backslash */ + + if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1])) + { + Temp = ACPI_ALLOCATE_ZEROED (strlen (ExternalPath) + 1); + if (!Temp) + { + return_VOID; + } + + strcpy (Temp, &ExternalPath[1]); + ACPI_FREE (ExternalPath); + ExternalPath = Temp; + } + + /* Create the new External() declaration node */ + + Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type, + Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED)); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (ExternalPath); + ACPI_FREE (InternalPath); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddPathToExternalList + * + * PARAMETERS: Path - External name of the object to be added + * Type - ACPI object type to be added + * Value - Arg count if adding a Method object + * Flags - To be passed to the external object + * + * RETURN: None + * + * DESCRIPTION: Insert a new name into the global list of Externals which + * will in turn be later emitted as an External() declaration + * in the disassembled output. + * + * This function currently is used to add externals via a + * reference file (via the -fe iASL option). + * + ******************************************************************************/ + +static void +AcpiDmAddPathToExternalList ( + char *Path, + UINT8 Type, + UINT32 Value, + UINT16 Flags) +{ + char *InternalPath; + char *ExternalPath; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (DmAddPathToExternalList); + + + if (!Path) + { + return_VOID; + } + + /* Remove a root backslash if present */ + + if ((*Path == AML_ROOT_PREFIX) && (Path[1])) + { + Path++; + } + + /* Create the internal and external pathnames */ + + Status = AcpiNsInternalizeName (Path, &InternalPath); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath, + NULL, &ExternalPath); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (InternalPath); + return_VOID; + } + + /* Create the new External() declaration node */ + + Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, + Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED)); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (ExternalPath); + ACPI_FREE (InternalPath); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCreateNewExternal + * + * PARAMETERS: ExternalPath - External path to the object + * InternalPath - Internal (AML) path to the object + * Type - ACPI object type to be added + * Value - Arg count if adding a Method object + * Flags - To be passed to the external object + * + * RETURN: Status + * + * DESCRIPTION: Common low-level function to insert a new name into the global + * list of Externals which will in turn be later emitted as + * External() declarations in the disassembled output. + * + * Note: The external name should not include a root prefix + * (backslash). We do not want External() statements to contain + * a leading '\', as this prevents duplicate external statements + * of the form: + * + * External (\ABCD) + * External (ABCD) + * + * This would cause a compile time error when the disassembled + * output file is recompiled. + * + * There are two cases that are handled here. For both, we emit + * an External() statement: + * 1) The name was simply not found in the namespace. + * 2) The name was found, but it originated in a table other than + * the table that is being disassembled. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmCreateNewExternal ( + char *ExternalPath, + char *InternalPath, + UINT8 Type, + UINT32 Value, + UINT16 Flags) +{ + ACPI_EXTERNAL_LIST *NewExternal; + ACPI_EXTERNAL_LIST *NextExternal; + ACPI_EXTERNAL_LIST *PrevExternal = NULL; + + + ACPI_FUNCTION_TRACE (DmCreateNewExternal); + + + /* Check all existing externals to ensure no duplicates */ + + NextExternal = AcpiGbl_ExternalList; + while (NextExternal) + { + if (!strcmp (ExternalPath, NextExternal->Path)) + { + /* Duplicate method, check that the Value (ArgCount) is the same */ + + if ((NextExternal->Type == ACPI_TYPE_METHOD) && + (NextExternal->Value != Value) && + (Value > 0)) + { + ACPI_ERROR ((AE_INFO, + "External method arg count mismatch %s: " + "Current %u, attempted %u", + NextExternal->Path, NextExternal->Value, Value)); + } + + /* Allow upgrade of type from ANY */ + + else if (NextExternal->Type == ACPI_TYPE_ANY) + { + NextExternal->Type = Type; + NextExternal->Value = Value; + } + + return_ACPI_STATUS (AE_ALREADY_EXISTS); + } + + NextExternal = NextExternal->Next; + } + + /* Allocate and init a new External() descriptor */ + + NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); + if (!NewExternal) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Adding external reference node (%s) type [%s]\n", + ExternalPath, AcpiUtGetTypeName (Type))); + + NewExternal->Flags = Flags; + NewExternal->Value = Value; + NewExternal->Path = ExternalPath; + NewExternal->Type = Type; + NewExternal->Length = (UINT16) strlen (ExternalPath); + NewExternal->InternalPath = InternalPath; + + /* Link the new descriptor into the global list, alphabetically ordered */ + + NextExternal = AcpiGbl_ExternalList; + while (NextExternal) + { + if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) + { + if (PrevExternal) + { + PrevExternal->Next = NewExternal; + } + else + { + AcpiGbl_ExternalList = NewExternal; + } + + NewExternal->Next = NextExternal; + return_ACPI_STATUS (AE_OK); + } + + PrevExternal = NextExternal; + NextExternal = NextExternal->Next; + } + + if (PrevExternal) + { + PrevExternal->Next = NewExternal; + } + else + { + AcpiGbl_ExternalList = NewExternal; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddExternalsToNamespace + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Add all externals to the namespace. Allows externals to be + * "resolved". + * + ******************************************************************************/ + +void +AcpiDmAddExternalsToNamespace ( + void) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; + + + while (External) + { + /* Add the external name (object) into the namespace */ + + Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, + ACPI_IMODE_LOAD_PASS1, + ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &Node); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "while adding external to namespace [%s]", + External->Path)); + } + + else switch (External->Type) + { + case ACPI_TYPE_METHOD: + + /* For methods, we need to save the argument count */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); + ObjDesc->Method.ParamCount = (UINT8) External->Value; + Node->Object = ObjDesc; + break; + + case ACPI_TYPE_REGION: + + /* Regions require a region sub-object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); + ObjDesc->Region.Node = Node; + Node->Object = ObjDesc; + break; + + default: + + break; + } + + External = External->Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetExternalMethodCount + * + * PARAMETERS: None + * + * RETURN: The number of control method externals in the external list + * + * DESCRIPTION: Return the number of method externals that have been generated. + * If any control method externals have been found, we must + * re-parse the entire definition block with the new information + * (number of arguments for the methods.) This is limitation of + * AML, we don't know the number of arguments from the control + * method invocation itself. + * + ******************************************************************************/ + +UINT32 +AcpiDmGetExternalMethodCount ( + void) +{ + ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; + UINT32 Count = 0; + + + while (External) + { + if (External->Type == ACPI_TYPE_METHOD) + { + Count++; + } + + External = External->Next; + } + + return (Count); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmClearExternalList + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Free the entire External info list + * + ******************************************************************************/ + +void +AcpiDmClearExternalList ( + void) +{ + ACPI_EXTERNAL_LIST *NextExternal; + + + while (AcpiGbl_ExternalList) + { + NextExternal = AcpiGbl_ExternalList->Next; + ACPI_FREE (AcpiGbl_ExternalList->Path); + ACPI_FREE (AcpiGbl_ExternalList); + AcpiGbl_ExternalList = NextExternal; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmEmitExternals + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Emit an External() ASL statement for each of the externals in + * the global external info list. + * + ******************************************************************************/ + +void +AcpiDmEmitExternals ( + void) +{ + ACPI_EXTERNAL_LIST *NextExternal; + + + if (!AcpiGbl_ExternalList) + { + return; + } + + /* + * Determine the number of control methods in the external list, and + * also how many of those externals were resolved via the namespace. + */ + NextExternal = AcpiGbl_ExternalList; + while (NextExternal) + { + if (NextExternal->Type == ACPI_TYPE_METHOD) + { + AcpiGbl_NumExternalMethods++; + if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE) + { + AcpiGbl_ResolvedExternalMethods++; + } + } + + NextExternal = NextExternal->Next; + } + + /* Check if any control methods were unresolved */ + + AcpiDmUnresolvedWarning (1); + + /* Emit any unresolved method externals in a single text block */ + + NextExternal = AcpiGbl_ExternalList; + while (NextExternal) + { + if ((NextExternal->Type == ACPI_TYPE_METHOD) && + (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE))) + { + AcpiOsPrintf (" External (%s%s", + NextExternal->Path, + AcpiDmGetObjectTypeName (NextExternal->Type)); + + AcpiOsPrintf (") // Warning: Unresolved method, " + "guessing %u arguments\n", + NextExternal->Value); + + NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; + } + + NextExternal = NextExternal->Next; + } + + AcpiOsPrintf ("\n"); + + + /* Emit externals that were imported from a file */ + + if (Gbl_ExternalRefFilename) + { + AcpiOsPrintf ( + " /*\n * External declarations that were imported from\n" + " * the reference file [%s]\n */\n", + Gbl_ExternalRefFilename); + + NextExternal = AcpiGbl_ExternalList; + while (NextExternal) + { + if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) && + (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE)) + { + AcpiOsPrintf (" External (%s%s", + NextExternal->Path, + AcpiDmGetObjectTypeName (NextExternal->Type)); + + if (NextExternal->Type == ACPI_TYPE_METHOD) + { + AcpiOsPrintf (") // %u Arguments\n", + NextExternal->Value); + } + else + { + AcpiOsPrintf (")\n"); + } + NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; + } + + NextExternal = NextExternal->Next; + } + + AcpiOsPrintf ("\n"); + } + + /* + * Walk the list of externals found during the AML parsing + */ + while (AcpiGbl_ExternalList) + { + if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED)) + { + AcpiOsPrintf (" External (%s%s", + AcpiGbl_ExternalList->Path, + AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); + + /* For methods, add a comment with the number of arguments */ + + if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) + { + AcpiOsPrintf (") // %u Arguments\n", + AcpiGbl_ExternalList->Value); + } + else + { + AcpiOsPrintf (")\n"); + } + } + + /* Free this external info block and move on to next external */ + + NextExternal = AcpiGbl_ExternalList->Next; + if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) + { + ACPI_FREE (AcpiGbl_ExternalList->InternalPath); + } + + ACPI_FREE (AcpiGbl_ExternalList->Path); + ACPI_FREE (AcpiGbl_ExternalList); + AcpiGbl_ExternalList = NextExternal; + } + + AcpiOsPrintf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmUnresolvedWarning + * + * PARAMETERS: Type - Where to output the warning. + * 0 means write to stderr + * 1 means write to AcpiOsPrintf + * + * RETURN: None + * + * DESCRIPTION: Issue warning message if there are unresolved external control + * methods within the disassembly. + * + ******************************************************************************/ + +#if 0 +Summary of the external control method problem: + +When the -e option is used with disassembly, the various SSDTs are simply +loaded into a global namespace for the disassembler to use in order to +resolve control method references (invocations). + +The disassembler tracks any such references, and will emit an External() +statement for these types of methods, with the proper number of arguments . + +Without the SSDTs, the AML does not contain enough information to properly +disassemble the control method invocation -- because the disassembler does +not know how many arguments to parse. + +An example: Assume we have two control methods. ABCD has one argument, and +EFGH has zero arguments. Further, we have two additional control methods +that invoke ABCD and EFGH, named T1 and T2: + + Method (ABCD, 1) + { + } + Method (EFGH, 0) + { + } + Method (T1) + { + ABCD (Add (2, 7, Local0)) + } + Method (T2) + { + EFGH () + Add (2, 7, Local0) + } + +Here is the AML code that is generated for T1 and T2: + + 185: Method (T1) + +0000034C: 14 10 54 31 5F 5F 00 ... "..T1__." + + 186: { + 187: ABCD (Add (2, 7, Local0)) + +00000353: 41 42 43 44 ............ "ABCD" +00000357: 72 0A 02 0A 07 60 ...... "r....`" + + 188: } + + 190: Method (T2) + +0000035D: 14 10 54 32 5F 5F 00 ... "..T2__." + + 191: { + 192: EFGH () + +00000364: 45 46 47 48 ............ "EFGH" + + 193: Add (2, 7, Local0) + +00000368: 72 0A 02 0A 07 60 ...... "r....`" + 194: } + +Note that the AML code for T1 and T2 is essentially identical. When +disassembling this code, the methods ABCD and EFGH must be known to the +disassembler, otherwise it does not know how to handle the method invocations. + +In other words, if ABCD and EFGH are actually external control methods +appearing in an SSDT, the disassembler does not know what to do unless +the owning SSDT has been loaded via the -e option. +#endif + +void +AcpiDmUnresolvedWarning ( + UINT8 Type) +{ + + if (!AcpiGbl_NumExternalMethods) + { + return; + } + + if (Type) + { + if (!AcpiGbl_ExternalFileList) + { + /* The -e option was not specified */ + + AcpiOsPrintf (" /*\n" + " * iASL Warning: There were %u external control methods found during\n" + " * disassembly, but additional ACPI tables to resolve these externals\n" + " * were not specified. This resulting disassembler output file may not\n" + " * compile because the disassembler did not know how many arguments\n" + " * to assign to these methods. To specify the tables needed to resolve\n" + " * external control method references, the -e option can be used to\n" + " * specify the filenames. Note: SSDTs can be dynamically loaded at\n" + " * runtime and may or may not be available via the host OS.\n" + " * Example iASL invocations:\n" + " * iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" + " * iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" + " * iasl -e ssdt*.aml -d dsdt.aml\n" + " *\n" + " * In addition, the -fe option can be used to specify a file containing\n" + " * control method external declarations with the associated method\n" + " * argument counts. Each line of the file must be of the form:\n" + " * External (, MethodObj, )\n" + " * Invocation:\n" + " * iasl -fe refs.txt -d dsdt.aml\n" + " *\n" + " * The following methods were unresolved and many not compile properly\n" + " * because the disassembler had to guess at the number of arguments\n" + " * required for each:\n" + " */\n", + AcpiGbl_NumExternalMethods); + } + else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods) + { + /* The -e option was specified, but there are still some unresolved externals */ + + AcpiOsPrintf (" /*\n" + " * iASL Warning: There were %u external control methods found during\n" + " * disassembly, but only %u %s resolved (%u unresolved). Additional\n" + " * ACPI tables may be required to properly disassemble the code. This\n" + " * resulting disassembler output file may not compile because the\n" + " * disassembler did not know how many arguments to assign to the\n" + " * unresolved methods. Note: SSDTs can be dynamically loaded at\n" + " * runtime and may or may not be available via the host OS.\n" + " *\n" + " * If necessary, the -fe option can be used to specify a file containing\n" + " * control method external declarations with the associated method\n" + " * argument counts. Each line of the file must be of the form:\n" + " * External (, MethodObj, )\n" + " * Invocation:\n" + " * iasl -fe refs.txt -d dsdt.aml\n" + " *\n" + " * The following methods were unresolved and many not compile properly\n" + " * because the disassembler had to guess at the number of arguments\n" + " * required for each:\n" + " */\n", + AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods, + (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), + (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods)); + } + } + else + { + if (!AcpiGbl_ExternalFileList) + { + /* The -e option was not specified */ + + fprintf (stderr, "\n" + "iASL Warning: There were %u external control methods found during\n" + "disassembly, but additional ACPI tables to resolve these externals\n" + "were not specified. The resulting disassembler output file may not\n" + "compile because the disassembler did not know how many arguments\n" + "to assign to these methods. To specify the tables needed to resolve\n" + "external control method references, the -e option can be used to\n" + "specify the filenames. Note: SSDTs can be dynamically loaded at\n" + "runtime and may or may not be available via the host OS.\n" + "Example iASL invocations:\n" + " iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" + " iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" + " iasl -e ssdt*.aml -d dsdt.aml\n" + "\n" + "In addition, the -fe option can be used to specify a file containing\n" + "control method external declarations with the associated method\n" + "argument counts. Each line of the file must be of the form:\n" + " External (, MethodObj, )\n" + "Invocation:\n" + " iasl -fe refs.txt -d dsdt.aml\n", + AcpiGbl_NumExternalMethods); + } + else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods) + { + /* The -e option was specified, but there are still some unresolved externals */ + + fprintf (stderr, "\n" + "iASL Warning: There were %u external control methods found during\n" + "disassembly, but only %u %s resolved (%u unresolved). Additional\n" + "ACPI tables may be required to properly disassemble the code. The\n" + "resulting disassembler output file may not compile because the\n" + "disassembler did not know how many arguments to assign to the\n" + "unresolved methods. Note: SSDTs can be dynamically loaded at\n" + "runtime and may or may not be available via the host OS.\n" + "\n" + "If necessary, the -fe option can be used to specify a file containing\n" + "control method external declarations with the associated method\n" + "argument counts. Each line of the file must be of the form:\n" + " External (, MethodObj, )\n" + "Invocation:\n" + " iasl -fe refs.txt -d dsdt.aml\n", + AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods, + (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), + (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods)); + } + } +} diff --git a/third_party/lib/acpica/source/common/dmrestag.c b/third_party/lib/acpica/source/common/dmrestag.c new file mode 100644 index 000000000..310ddac60 --- /dev/null +++ b/third_party/lib/acpica/source/common/dmrestag.c @@ -0,0 +1,1049 @@ +/****************************************************************************** + * + * Module Name: dmrestag - Add tags to resource descriptors (Application-level) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acdisasm.h" +#include "acnamesp.h" +#include "amlcode.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_CA_DISASSEMBLER + ACPI_MODULE_NAME ("dmrestag") + +/* Local prototypes */ + +static void +AcpiDmUpdateResourceName ( + ACPI_NAMESPACE_NODE *ResourceNode); + +static char * +AcpiDmSearchTagList ( + UINT32 BitIndex, + const ACPI_RESOURCE_TAG *TagList); + +static char * +AcpiDmGetResourceTag ( + UINT32 BitIndex, + AML_RESOURCE *Resource, + UINT8 ResourceIndex); + +static char * +AcpiGetTagPathname ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *BufferNode, + ACPI_NAMESPACE_NODE *ResourceNode, + UINT32 BitIndex); + +static ACPI_NAMESPACE_NODE * +AcpiDmGetResourceNode ( + ACPI_NAMESPACE_NODE *BufferNode, + UINT32 BitIndex); + +static ACPI_STATUS +AcpiDmAddResourceToNamespace ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context); + +static void +AcpiDmAddResourcesToNamespace ( + ACPI_NAMESPACE_NODE *BufferNode, + ACPI_PARSE_OBJECT *Op); + + +/****************************************************************************** + * + * Resource Tag tables + * + * These are the predefined tags that refer to elements of a resource + * descriptor. Each name and offset is defined in the ACPI specification. + * + * Each table entry contains the bit offset of the field and the associated + * name. + * + ******************************************************************************/ + +static const ACPI_RESOURCE_TAG AcpiDmIrqTags[] = +{ + {( 1 * 8), ACPI_RESTAG_INTERRUPT}, + {( 3 * 8) + 0, ACPI_RESTAG_INTERRUPTTYPE}, + {( 3 * 8) + 3, ACPI_RESTAG_INTERRUPTLEVEL}, + {( 3 * 8) + 4, ACPI_RESTAG_INTERRUPTSHARE}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmDmaTags[] = +{ + {( 1 * 8), ACPI_RESTAG_DMA}, + {( 2 * 8) + 0, ACPI_RESTAG_XFERTYPE}, + {( 2 * 8) + 2, ACPI_RESTAG_BUSMASTER}, + {( 2 * 8) + 5, ACPI_RESTAG_DMATYPE}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmIoTags[] = +{ + {( 1 * 8) + 0, ACPI_RESTAG_DECODE}, + {( 2 * 8), ACPI_RESTAG_MINADDR}, + {( 4 * 8), ACPI_RESTAG_MAXADDR}, + {( 6 * 8), ACPI_RESTAG_ALIGNMENT}, + {( 7 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmFixedIoTags[] = +{ + {( 1 * 8), ACPI_RESTAG_BASEADDRESS}, + {( 3 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmFixedDmaTags[] = +{ + {( 1 * 8), ACPI_RESTAG_DMA}, + {( 3 * 8), ACPI_RESTAG_DMATYPE}, + {( 5 * 8), ACPI_RESTAG_XFERTYPE}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmMemory24Tags[] = +{ + {( 3 * 8) + 0, ACPI_RESTAG_READWRITETYPE}, + {( 4 * 8), ACPI_RESTAG_MINADDR}, + {( 6 * 8), ACPI_RESTAG_MAXADDR}, + {( 8 * 8), ACPI_RESTAG_ALIGNMENT}, + {(10 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmRegisterTags[] = +{ + {( 3 * 8), ACPI_RESTAG_ADDRESSSPACE}, + {( 4 * 8), ACPI_RESTAG_REGISTERBITWIDTH}, + {( 5 * 8), ACPI_RESTAG_REGISTERBITOFFSET}, + {( 6 * 8), ACPI_RESTAG_ACCESSSIZE}, + {( 7 * 8), ACPI_RESTAG_ADDRESS}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmMemory32Tags[] = +{ + {( 3 * 8) + 0, ACPI_RESTAG_READWRITETYPE}, + {( 4 * 8), ACPI_RESTAG_MINADDR}, + {( 8 * 8), ACPI_RESTAG_MAXADDR}, + {(12 * 8), ACPI_RESTAG_ALIGNMENT}, + {(16 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmFixedMemory32Tags[] = +{ + {( 3 * 8) + 0, ACPI_RESTAG_READWRITETYPE}, + {( 4 * 8), ACPI_RESTAG_BASEADDRESS}, + {( 8 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmInterruptTags[] = +{ + {( 3 * 8) + 1, ACPI_RESTAG_INTERRUPTTYPE}, + {( 3 * 8) + 2, ACPI_RESTAG_INTERRUPTLEVEL}, + {( 3 * 8) + 3, ACPI_RESTAG_INTERRUPTSHARE}, + {( 5 * 8), ACPI_RESTAG_INTERRUPT}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmAddress16Tags[] = +{ + {( 4 * 8) + 1, ACPI_RESTAG_DECODE}, + {( 4 * 8) + 2, ACPI_RESTAG_MINTYPE}, + {( 4 * 8) + 3, ACPI_RESTAG_MAXTYPE}, + {( 6 * 8), ACPI_RESTAG_GRANULARITY}, + {( 8 * 8), ACPI_RESTAG_MINADDR}, + {(10 * 8), ACPI_RESTAG_MAXADDR}, + {(12 * 8), ACPI_RESTAG_TRANSLATION}, + {(14 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmAddress32Tags[] = +{ + {( 4 * 8) + 1, ACPI_RESTAG_DECODE}, + {( 4 * 8) + 2, ACPI_RESTAG_MINTYPE}, + {( 4 * 8) + 3, ACPI_RESTAG_MAXTYPE}, + {( 6 * 8), ACPI_RESTAG_GRANULARITY}, + {(10 * 8), ACPI_RESTAG_MINADDR}, + {(14 * 8), ACPI_RESTAG_MAXADDR}, + {(18 * 8), ACPI_RESTAG_TRANSLATION}, + {(22 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmAddress64Tags[] = +{ + {( 4 * 8) + 1, ACPI_RESTAG_DECODE}, + {( 4 * 8) + 2, ACPI_RESTAG_MINTYPE}, + {( 4 * 8) + 3, ACPI_RESTAG_MAXTYPE}, + {( 6 * 8), ACPI_RESTAG_GRANULARITY}, + {(14 * 8), ACPI_RESTAG_MINADDR}, + {(22 * 8), ACPI_RESTAG_MAXADDR}, + {(30 * 8), ACPI_RESTAG_TRANSLATION}, + {(38 * 8), ACPI_RESTAG_LENGTH}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmExtendedAddressTags[] = +{ + {( 4 * 8) + 1, ACPI_RESTAG_DECODE}, + {( 4 * 8) + 2, ACPI_RESTAG_MINTYPE}, + {( 4 * 8) + 3, ACPI_RESTAG_MAXTYPE}, + {( 8 * 8), ACPI_RESTAG_GRANULARITY}, + {(16 * 8), ACPI_RESTAG_MINADDR}, + {(24 * 8), ACPI_RESTAG_MAXADDR}, + {(32 * 8), ACPI_RESTAG_TRANSLATION}, + {(40 * 8), ACPI_RESTAG_LENGTH}, + {(48 * 8), ACPI_RESTAG_TYPESPECIFICATTRIBUTES}, + {0, NULL} +}; + +/* Subtype tables for GPIO descriptors */ + +static const ACPI_RESOURCE_TAG AcpiDmGpioIntTags[] = +{ + {( 7 * 8) + 0, ACPI_RESTAG_MODE}, + {( 7 * 8) + 1, ACPI_RESTAG_POLARITY}, + {( 7 * 8) + 3, ACPI_RESTAG_INTERRUPTSHARE}, + {( 9 * 8), ACPI_RESTAG_PINCONFIG}, + {(10 * 8), ACPI_RESTAG_DRIVESTRENGTH}, + {(12 * 8), ACPI_RESTAG_DEBOUNCETIME}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmGpioIoTags[] = +{ + {( 7 * 8) + 0, ACPI_RESTAG_IORESTRICTION}, + {( 7 * 8) + 3, ACPI_RESTAG_INTERRUPTSHARE}, + {( 9 * 8), ACPI_RESTAG_PINCONFIG}, + {(10 * 8), ACPI_RESTAG_DRIVESTRENGTH}, + {(12 * 8), ACPI_RESTAG_DEBOUNCETIME}, + {0, NULL} +}; + +/* Subtype tables for SerialBus descriptors */ + +static const ACPI_RESOURCE_TAG AcpiDmI2cSerialBusTags[] = +{ + {( 6 * 8) + 0, ACPI_RESTAG_SLAVEMODE}, + {( 7 * 8) + 0, ACPI_RESTAG_MODE}, + {(12 * 8), ACPI_RESTAG_SPEED}, + {(16 * 8), ACPI_RESTAG_ADDRESS}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmSpiSerialBusTags[] = +{ + {( 6 * 8) + 0, ACPI_RESTAG_SLAVEMODE}, + {( 7 * 8) + 0, ACPI_RESTAG_MODE}, + {( 7 * 8) + 1, ACPI_RESTAG_DEVICEPOLARITY}, + {(12 * 8), ACPI_RESTAG_SPEED}, + {(16 * 8), ACPI_RESTAG_LENGTH}, + {(17 * 8), ACPI_RESTAG_PHASE}, + {(18 * 8), ACPI_RESTAG_POLARITY}, + {(19 * 8), ACPI_RESTAG_ADDRESS}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmUartSerialBusTags[] = +{ + {( 6 * 8) + 0, ACPI_RESTAG_SLAVEMODE}, /* Note: not part of original macro */ + {( 7 * 8) + 0, ACPI_RESTAG_FLOWCONTROL}, + {( 7 * 8) + 2, ACPI_RESTAG_STOPBITS}, + {( 7 * 8) + 4, ACPI_RESTAG_LENGTH}, + {( 7 * 8) + 7, ACPI_RESTAG_ENDIANNESS}, + {(12 * 8), ACPI_RESTAG_SPEED}, + {(16 * 8), ACPI_RESTAG_LENGTH_RX}, + {(18 * 8), ACPI_RESTAG_LENGTH_TX}, + {(20 * 8), ACPI_RESTAG_PARITY}, + {(21 * 8), ACPI_RESTAG_LINE}, + {0, NULL} +}; + +/* Subtype tables for Address descriptor type-specific flags */ + +static const ACPI_RESOURCE_TAG AcpiDmMemoryFlagTags[] = +{ + {( 5 * 8) + 0, ACPI_RESTAG_READWRITETYPE}, + {( 5 * 8) + 1, ACPI_RESTAG_MEMTYPE}, + {( 5 * 8) + 3, ACPI_RESTAG_MEMATTRIBUTES}, + {( 5 * 8) + 5, ACPI_RESTAG_TYPE}, + {0, NULL} +}; + +static const ACPI_RESOURCE_TAG AcpiDmIoFlagTags[] = +{ + {( 5 * 8) + 0, ACPI_RESTAG_RANGETYPE}, + {( 5 * 8) + 4, ACPI_RESTAG_TYPE}, + {( 5 * 8) + 5, ACPI_RESTAG_TRANSTYPE}, + {0, NULL} +}; + + +/* + * Dispatch table used to obtain the correct tag table for a descriptor. + * + * A NULL in this table means one of three things: + * 1) The descriptor ID is reserved and invalid + * 2) The descriptor has no tags associated with it + * 3) The descriptor has subtypes and a separate table will be used. + */ +static const ACPI_RESOURCE_TAG *AcpiGbl_ResourceTags[] = +{ + /* Small descriptors */ + + NULL, /* 0x00, Reserved */ + NULL, /* 0x01, Reserved */ + NULL, /* 0x02, Reserved */ + NULL, /* 0x03, Reserved */ + AcpiDmIrqTags, /* 0x04, ACPI_RESOURCE_NAME_IRQ_FORMAT */ + AcpiDmDmaTags, /* 0x05, ACPI_RESOURCE_NAME_DMA_FORMAT */ + NULL, /* 0x06, ACPI_RESOURCE_NAME_START_DEPENDENT */ + NULL, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */ + AcpiDmIoTags, /* 0x08, ACPI_RESOURCE_NAME_IO_PORT */ + AcpiDmFixedIoTags, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO_PORT */ + AcpiDmFixedDmaTags, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */ + NULL, /* 0x0B, Reserved */ + NULL, /* 0x0C, Reserved */ + NULL, /* 0x0D, Reserved */ + NULL, /* 0x0E, ACPI_RESOURCE_NAME_SMALL_VENDOR */ + NULL, /* 0x0F, ACPI_RESOURCE_NAME_END_TAG (not used) */ + + /* Large descriptors */ + + NULL, /* 0x00, Reserved */ + AcpiDmMemory24Tags, /* 0x01, ACPI_RESOURCE_NAME_MEMORY_24 */ + AcpiDmRegisterTags, /* 0x02, ACPI_RESOURCE_NAME_GENERIC_REGISTER */ + NULL, /* 0x03, Reserved */ + NULL, /* 0x04, ACPI_RESOURCE_NAME_LARGE_VENDOR */ + AcpiDmMemory32Tags, /* 0x05, ACPI_RESOURCE_NAME_MEMORY_32 */ + AcpiDmFixedMemory32Tags, /* 0x06, ACPI_RESOURCE_NAME_FIXED_MEMORY_32 */ + AcpiDmAddress32Tags, /* 0x07, ACPI_RESOURCE_NAME_DWORD_ADDRESS_SPACE */ + AcpiDmAddress16Tags, /* 0x08, ACPI_RESOURCE_NAME_WORD_ADDRESS_SPACE */ + AcpiDmInterruptTags, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_XRUPT */ + AcpiDmAddress64Tags, /* 0x0A, ACPI_RESOURCE_NAME_QWORD_ADDRESS_SPACE */ + AcpiDmExtendedAddressTags, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS_SPACE */ + NULL, /* 0x0C, ACPI_RESOURCE_NAME_GPIO - Use Subtype table below */ + NULL, /* 0x0D, Reserved */ + NULL /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use Subtype table below */ +}; + +/* GPIO Subtypes */ + +static const ACPI_RESOURCE_TAG *AcpiGbl_GpioResourceTags[] = +{ + AcpiDmGpioIntTags, /* 0x00 Interrupt Connection */ + AcpiDmGpioIoTags /* 0x01 I/O Connection */ +}; + +/* Serial Bus Subtypes */ + +static const ACPI_RESOURCE_TAG *AcpiGbl_SerialResourceTags[] = +{ + NULL, /* 0x00 Reserved */ + AcpiDmI2cSerialBusTags, /* 0x01 I2C SerialBus */ + AcpiDmSpiSerialBusTags, /* 0x02 SPI SerialBus */ + AcpiDmUartSerialBusTags /* 0x03 UART SerialBus */ +}; + +/* + * Globals used to generate unique resource descriptor names. We use names that + * start with underscore and a prefix letter that is not used by other ACPI + * reserved names. To this, we append hex 0x00 through 0xFF. These 5 prefixes + * allow for 5*256 = 1280 unique names, probably sufficient for any single ASL + * file. If this becomes too small, we can use alpha+numerals for a total + * of 5*36*36 = 6480. + */ +#define ACPI_NUM_RES_PREFIX 5 + +static UINT32 AcpiGbl_NextResourceId = 0; +static UINT8 AcpiGbl_NextPrefix = 0; +static char AcpiGbl_Prefix[ACPI_NUM_RES_PREFIX] = + {'Y','Z','J','K','X'}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCheckResourceReference + * + * PARAMETERS: Op - Parse Op for the AML opcode + * WalkState - Current walk state (with valid scope) + * + * RETURN: None + * + * DESCRIPTION: Convert a reference to a resource descriptor to a symbolic + * reference if possible + * + * NOTE: Bit index is used to transparently handle both resource bit + * fields and byte fields. + * + ******************************************************************************/ + +void +AcpiDmCheckResourceReference ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *BufferNameOp; + ACPI_PARSE_OBJECT *IndexOp; + ACPI_NAMESPACE_NODE *BufferNode; + ACPI_NAMESPACE_NODE *ResourceNode; + const ACPI_OPCODE_INFO *OpInfo; + UINT32 BitIndex; + + + /* We are only interested in the CreateXxxxField opcodes */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (OpInfo->Type != AML_TYPE_CREATE_FIELD) + { + return; + } + + /* Get the buffer term operand */ + + BufferNameOp = AcpiPsGetDepthNext (NULL, Op); + + /* Must be a named buffer, not an arg or local or method call */ + + if (BufferNameOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP) + { + return; + } + + /* Get the Index term, must be an integer constant to convert */ + + IndexOp = BufferNameOp->Common.Next; + + /* Major cheat: The Node field is also used for the Tag ptr. Clear it now */ + + IndexOp->Common.Node = NULL; + + OpInfo = AcpiPsGetOpcodeInfo (IndexOp->Common.AmlOpcode); + if (OpInfo->ObjectType != ACPI_TYPE_INTEGER) + { + return; + } + + /* Get the bit offset of the descriptor within the buffer */ + + if ((Op->Common.AmlOpcode == AML_CREATE_BIT_FIELD_OP) || + (Op->Common.AmlOpcode == AML_CREATE_FIELD_OP)) + { + /* Index operand is a bit offset */ + + BitIndex = (UINT32) IndexOp->Common.Value.Integer; + } + else + { + /* Index operand is a byte offset, convert to bits */ + + BitIndex = (UINT32) ACPI_MUL_8 (IndexOp->Common.Value.Integer); + } + + /* Lookup the buffer in the namespace */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, + BufferNameOp->Common.Value.String, ACPI_TYPE_BUFFER, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, WalkState, + &BufferNode); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Validate object type, we must have a buffer */ + + if (BufferNode->Type != ACPI_TYPE_BUFFER) + { + return; + } + + /* Find the resource descriptor node corresponding to the index */ + + ResourceNode = AcpiDmGetResourceNode (BufferNode, BitIndex); + if (!ResourceNode) + { + return; + } + + /* Translate the Index to a resource tag pathname */ + + AcpiGetTagPathname (IndexOp, BufferNode, ResourceNode, BitIndex); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetResourceNode + * + * PARAMETERS: BufferNode - Node for the parent buffer + * BitIndex - Index into the resource descriptor + * + * RETURN: Namespace node for the resource descriptor. NULL if not found + * + * DESCRIPTION: Find a resource descriptor that corresponds to the bit index + * + ******************************************************************************/ + +static ACPI_NAMESPACE_NODE * +AcpiDmGetResourceNode ( + ACPI_NAMESPACE_NODE *BufferNode, + UINT32 BitIndex) +{ + ACPI_NAMESPACE_NODE *Node; + UINT32 ByteIndex = ACPI_DIV_8 (BitIndex); + + + /* + * Child list contains an entry for each resource descriptor. Find + * the descriptor that corresponds to the Index. + * + * If there are no children, this is not a resource template + */ + Node = BufferNode->Child; + while (Node) + { + /* + * Check if the Index falls within this resource. + * + * Value contains the resource offset, Object contains the resource + * length (both in bytes) + */ + if ((ByteIndex >= Node->Value) && + (ByteIndex < (Node->Value + Node->Length))) + { + return (Node); + } + + Node = Node->Peer; + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiGetTagPathname + * + * PARAMETERS: BufferNode - Node for the parent buffer + * ResourceNode - Node for a resource descriptor + * BitIndex - Index into the resource descriptor + * + * RETURN: Full pathname for a resource tag. NULL if no match. + * Path is returned in AML (packed) format. + * + * DESCRIPTION: Convert a BitIndex into a symbolic resource tag (full pathname) + * + ******************************************************************************/ + +static char * +AcpiGetTagPathname ( + ACPI_PARSE_OBJECT *IndexOp, + ACPI_NAMESPACE_NODE *BufferNode, + ACPI_NAMESPACE_NODE *ResourceNode, + UINT32 BitIndex) +{ + ACPI_STATUS Status; + UINT32 ResourceBitIndex; + UINT8 ResourceTableIndex; + ACPI_SIZE RequiredSize; + char *Pathname; + AML_RESOURCE *Aml; + ACPI_PARSE_OBJECT *Op; + char *InternalPath; + char *Tag; + + + /* Get the Op that contains the actual buffer data */ + + Op = BufferNode->Op->Common.Value.Arg; + Op = Op->Common.Next; + if (!Op) + { + return (NULL); + } + + /* Get the individual resource descriptor and validate it */ + + Aml = ACPI_CAST_PTR ( + AML_RESOURCE, &Op->Named.Data[ResourceNode->Value]); + + Status = AcpiUtValidateResource (NULL, Aml, &ResourceTableIndex); + if (ACPI_FAILURE (Status)) + { + return (NULL); + } + + /* Get offset into this descriptor (from offset into entire buffer) */ + + ResourceBitIndex = BitIndex - ACPI_MUL_8 (ResourceNode->Value); + + /* Get the tag associated with this resource descriptor and offset */ + + Tag = AcpiDmGetResourceTag (ResourceBitIndex, Aml, ResourceTableIndex); + if (!Tag) + { + return (NULL); + } + + /* + * Now that we know that we have a reference that can be converted to a + * symbol, change the name of the resource to a unique name. + */ + AcpiDmUpdateResourceName (ResourceNode); + + /* Get the full pathname to the parent buffer */ + + RequiredSize = AcpiNsBuildNormalizedPath (BufferNode, NULL, 0, FALSE); + if (!RequiredSize) + { + return (NULL); + } + + Pathname = ACPI_ALLOCATE_ZEROED (RequiredSize + ACPI_PATH_SEGMENT_LENGTH); + if (!Pathname) + { + return (NULL); + } + + (void) AcpiNsBuildNormalizedPath (BufferNode, Pathname, + RequiredSize, FALSE); + + /* + * Create the full path to the resource and tag by: remove the buffer name, + * append the resource descriptor name, append a dot, append the tag name. + * + * TBD: Always using the full path is a bit brute force, the path can be + * often be optimized with carats (if the original buffer namepath is a + * single nameseg). This doesn't really matter, because these paths do not + * end up in the final compiled AML, it's just an appearance issue for the + * disassembled code. + */ + Pathname[strlen (Pathname) - ACPI_NAME_SIZE] = 0; + strncat (Pathname, ResourceNode->Name.Ascii, ACPI_NAME_SIZE); + strcat (Pathname, "."); + strncat (Pathname, Tag, ACPI_NAME_SIZE); + + /* Internalize the namepath to AML format */ + + AcpiNsInternalizeName (Pathname, &InternalPath); + ACPI_FREE (Pathname); + + /* Update the Op with the symbol */ + + AcpiPsInitOp (IndexOp, AML_INT_NAMEPATH_OP); + IndexOp->Common.Value.String = InternalPath; + + /* We will need the tag later. Cheat by putting it in the Node field */ + + IndexOp->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Tag); + return (InternalPath); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmUpdateResourceName + * + * PARAMETERS: ResourceNode - Node for a resource descriptor + * + * RETURN: Stores new name in the ResourceNode + * + * DESCRIPTION: Create a new, unique name for a resource descriptor. Used by + * both the disassembly of the descriptor itself and any symbolic + * references to the descriptor. Ignored if a unique name has + * already been assigned to the resource. + * + * NOTE: Single threaded, suitable for applications only! + * + ******************************************************************************/ + +static void +AcpiDmUpdateResourceName ( + ACPI_NAMESPACE_NODE *ResourceNode) +{ + char Name[ACPI_NAME_SIZE]; + + + /* Ignore if a unique name has already been assigned */ + + if (ResourceNode->Name.Integer != ACPI_DEFAULT_RESNAME) + { + return; + } + + /* Generate a new ACPI name for the descriptor */ + + Name[0] = '_'; + Name[1] = AcpiGbl_Prefix[AcpiGbl_NextPrefix]; + Name[2] = AcpiUtHexToAsciiChar ((UINT64) AcpiGbl_NextResourceId, 4); + Name[3] = AcpiUtHexToAsciiChar ((UINT64) AcpiGbl_NextResourceId, 0); + + /* Update globals for next name */ + + AcpiGbl_NextResourceId++; + if (AcpiGbl_NextResourceId >= 256) + { + AcpiGbl_NextResourceId = 0; + AcpiGbl_NextPrefix++; + + if (AcpiGbl_NextPrefix > ACPI_NUM_RES_PREFIX) + { + AcpiGbl_NextPrefix = 0; + } + } + + /* Change the resource descriptor name */ + + ResourceNode->Name.Integer = *ACPI_CAST_PTR (UINT32, &Name[0]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetResourceTag + * + * PARAMETERS: BitIndex - Index into the resource descriptor + * Resource - Pointer to the raw resource data + * ResourceIndex - Index correspoinding to the resource type + * + * RETURN: Pointer to the resource tag (ACPI_NAME). NULL if no match. + * + * DESCRIPTION: Convert a BitIndex into a symbolic resource tag. + * + * Note: ResourceIndex should be previously validated and guaranteed to ve + * valid. + * + ******************************************************************************/ + +static char * +AcpiDmGetResourceTag ( + UINT32 BitIndex, + AML_RESOURCE *Resource, + UINT8 ResourceIndex) +{ + const ACPI_RESOURCE_TAG *TagList; + char *Tag = NULL; + + + /* Get the tag list for this resource descriptor type */ + + TagList = AcpiGbl_ResourceTags[ResourceIndex]; + + /* + * Handle descriptors that have multiple subtypes + */ + switch (Resource->DescriptorType) + { + case ACPI_RESOURCE_NAME_ADDRESS16: + case ACPI_RESOURCE_NAME_ADDRESS32: + case ACPI_RESOURCE_NAME_ADDRESS64: + case ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64: + /* + * Subtype differentiation is the flags. + * Kindof brute force, but just blindly search for an index match + */ + if (Resource->Address.ResourceType == ACPI_ADDRESS_TYPE_MEMORY_RANGE) + { + Tag = AcpiDmSearchTagList (BitIndex, AcpiDmMemoryFlagTags); + } + else if (Resource->Address.ResourceType == ACPI_ADDRESS_TYPE_IO_RANGE) + { + Tag = AcpiDmSearchTagList (BitIndex, AcpiDmIoFlagTags); + } + + /* If we found a match, all done. Else, drop to normal search below */ + + if (Tag) + { + return (Tag); + } + break; + + case ACPI_RESOURCE_NAME_GPIO: + + /* GPIO connection has 2 subtypes: Interrupt and I/O */ + + if (Resource->Gpio.ConnectionType > AML_RESOURCE_MAX_GPIOTYPE) + { + return (NULL); + } + + TagList = AcpiGbl_GpioResourceTags[Resource->Gpio.ConnectionType]; + break; + + case ACPI_RESOURCE_NAME_SERIAL_BUS: + + /* SerialBus has 3 subtypes: I2C, SPI, and UART */ + + if ((Resource->CommonSerialBus.Type == 0) || + (Resource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE)) + { + return (NULL); + } + + TagList = AcpiGbl_SerialResourceTags[Resource->CommonSerialBus.Type]; + break; + + default: + + break; + } + + /* Search for a match against the BitIndex */ + + if (TagList) + { + Tag = AcpiDmSearchTagList (BitIndex, TagList); + } + + return (Tag); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmSearchTagList + * + * PARAMETERS: BitIndex - Index into the resource descriptor + * TagList - List to search + * + * RETURN: Pointer to a tag (ACPI_NAME). NULL if no match found. + * + * DESCRIPTION: Search a tag list for a match to the input BitIndex. Matches + * a fixed offset to a symbolic resource tag name. + * + ******************************************************************************/ + +static char * +AcpiDmSearchTagList ( + UINT32 BitIndex, + const ACPI_RESOURCE_TAG *TagList) +{ + + /* + * Walk the null-terminated tag list to find a matching bit offset. + * We are looking for an exact match. + */ + for ( ; TagList->Tag; TagList++) + { + if (BitIndex == TagList->BitIndex) + { + return (TagList->Tag); + } + } + + /* A matching offset was not found */ + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFindResources + * + * PARAMETERS: Root - Root of the parse tree + * + * RETURN: None + * + * DESCRIPTION: Add all ResourceTemplate declarations to the namespace. Each + * resource descriptor in each template is given a node -- used + * for later conversion of resource references to symbolic refs. + * + ******************************************************************************/ + +void +AcpiDmFindResources ( + ACPI_PARSE_OBJECT *Root) +{ + ACPI_PARSE_OBJECT *Op = Root; + ACPI_PARSE_OBJECT *Parent; + + + /* Walk the entire parse tree */ + + while (Op) + { + /* We are interested in Buffer() declarations */ + + if (Op->Common.AmlOpcode == AML_BUFFER_OP) + { + /* And only declarations of the form Name (XXXX, Buffer()... ) */ + + Parent = Op->Common.Parent; + if (Parent->Common.AmlOpcode == AML_NAME_OP) + { + /* + * If the buffer is a resource template, add the individual + * resource descriptors to the namespace, as children of the + * buffer node. + */ + if (ACPI_SUCCESS (AcpiDmIsResourceTemplate (NULL, Op))) + { + Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; + AcpiDmAddResourcesToNamespace (Parent->Common.Node, Op); + } + } + } + + Op = AcpiPsGetDepthNext (Root, Op); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddResourcesToNamespace + * + * PARAMETERS: BufferNode - Node for the parent buffer + * Op - Parse op for the buffer + * + * RETURN: None + * + * DESCRIPTION: Add an entire resource template to the namespace. Each + * resource descriptor is added as a namespace node. + * + ******************************************************************************/ + +static void +AcpiDmAddResourcesToNamespace ( + ACPI_NAMESPACE_NODE *BufferNode, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextOp; + + + /* Get to the ByteData list */ + + NextOp = Op->Common.Value.Arg; + NextOp = NextOp->Common.Next; + if (!NextOp) + { + return; + } + + /* Set Node and Op to point to each other */ + + BufferNode->Op = Op; + Op->Common.Node = BufferNode; + + /* + * Insert each resource into the namespace + * NextOp contains the Aml pointer and the Aml length + */ + AcpiUtWalkAmlResources (NULL, (UINT8 *) NextOp->Named.Data, + (ACPI_SIZE) NextOp->Common.Value.Integer, + AcpiDmAddResourceToNamespace, (void **) BufferNode); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddResourceToNamespace + * + * PARAMETERS: ACPI_WALK_AML_CALLBACK + * BufferNode - Node for the parent buffer + * + * RETURN: Status + * + * DESCRIPTION: Add one resource descriptor to the namespace as a child of the + * parent buffer. The same name is used for each descriptor. This + * is changed later to a unique name if the resource is actually + * referenced by an AML operator. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmAddResourceToNamespace ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context) +{ + ACPI_STATUS Status; + ACPI_GENERIC_STATE ScopeInfo; + ACPI_NAMESPACE_NODE *Node; + + + /* TBD: Don't need to add descriptors that have no tags defined? */ + + /* Add the resource to the namespace, as child of the buffer */ + + ScopeInfo.Scope.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Context); + Status = AcpiNsLookup (&ScopeInfo, "_TMP", ACPI_TYPE_LOCAL_RESOURCE, + ACPI_IMODE_LOAD_PASS2, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_PREFIX_IS_SCOPE, + NULL, &Node); + if (ACPI_FAILURE (Status)) + { + return (AE_OK); + } + + /* Set the name to the default, changed later if resource is referenced */ + + Node->Name.Integer = ACPI_DEFAULT_RESNAME; + + /* Save the offset of the descriptor (within the original buffer) */ + + Node->Value = Offset; + Node->Length = Length; + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/common/dmtable.c b/third_party/lib/acpica/source/common/dmtable.c new file mode 100644 index 000000000..b66f2d808 --- /dev/null +++ b/third_party/lib/acpica/source/common/dmtable.c @@ -0,0 +1,1524 @@ +/****************************************************************************** + * + * Module Name: dmtable - Support for ACPI tables that contain no AML code + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdisasm.h" +#include "actables.h" +#include "aslcompiler.h" +#include "dtcompiler.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_CA_DISASSEMBLER + ACPI_MODULE_NAME ("dmtable") + +const AH_TABLE * +AcpiAhGetTableInfo ( + char *Signature); + + +/* Local Prototypes */ + +static void +AcpiDmCheckAscii ( + UINT8 *Target, + char *RepairedName, + UINT32 Count); + + +/* Common format strings for commented values */ + +#define UINT8_FORMAT "%2.2X [%s]\n" +#define UINT16_FORMAT "%4.4X [%s]\n" +#define UINT32_FORMAT "%8.8X [%s]\n" +#define STRING_FORMAT "[%s]\n" + +/* These tables map a subtable type to a description string */ + +static const char *AcpiDmAsfSubnames[] = +{ + "ASF Information", + "ASF Alerts", + "ASF Remote Control", + "ASF RMCP Boot Options", + "ASF Address", + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmDmarSubnames[] = +{ + "Hardware Unit Definition", + "Reserved Memory Region", + "Root Port ATS Capability", + "Remapping Hardware Static Affinity", + "ACPI Namespace Device Declaration", + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmDmarScope[] = +{ + "Reserved value", + "PCI Endpoint Device", + "PCI Bridge Device", + "IOAPIC Device", + "Message-capable HPET Device", + "Namespace Device", + "Unknown Scope Type" /* Reserved */ +}; + +static const char *AcpiDmEinjActions[] = +{ + "Begin Operation", + "Get Trigger Table", + "Set Error Type", + "Get Error Type", + "End Operation", + "Execute Operation", + "Check Busy Status", + "Get Command Status", + "Set Error Type With Address", + "Unknown Action" +}; + +static const char *AcpiDmEinjInstructions[] = +{ + "Read Register", + "Read Register Value", + "Write Register", + "Write Register Value", + "Noop", + "Flush Cacheline", + "Unknown Instruction" +}; + +static const char *AcpiDmErstActions[] = +{ + "Begin Write Operation", + "Begin Read Operation", + "Begin Clear Operation", + "End Operation", + "Set Record Offset", + "Execute Operation", + "Check Busy Status", + "Get Command Status", + "Get Record Identifier", + "Set Record Identifier", + "Get Record Count", + "Begin Dummy Write", + "Unused/Unknown Action", + "Get Error Address Range", + "Get Error Address Length", + "Get Error Attributes", + "Unknown Action" +}; + +static const char *AcpiDmErstInstructions[] = +{ + "Read Register", + "Read Register Value", + "Write Register", + "Write Register Value", + "Noop", + "Load Var1", + "Load Var2", + "Store Var1", + "Add", + "Subtract", + "Add Value", + "Subtract Value", + "Stall", + "Stall While True", + "Skip Next If True", + "GoTo", + "Set Source Address", + "Set Destination Address", + "Move Data", + "Unknown Instruction" +}; + +static const char *AcpiDmGtdtSubnames[] = +{ + "Generic Timer Block", + "Generic Watchdog Timer", + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmHestSubnames[] = +{ + "IA-32 Machine Check Exception", + "IA-32 Corrected Machine Check", + "IA-32 Non-Maskable Interrupt", + "Unknown SubTable Type", /* 3 - Reserved */ + "Unknown SubTable Type", /* 4 - Reserved */ + "Unknown SubTable Type", /* 5 - Reserved */ + "PCI Express Root Port AER", + "PCI Express AER (AER Endpoint)", + "PCI Express/PCI-X Bridge AER", + "Generic Hardware Error Source", + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmHestNotifySubnames[] = +{ + "Polled", + "External Interrupt", + "Local Interrupt", + "SCI", + "NMI", + "CMCI", /* ACPI 5.0 */ + "MCE", /* ACPI 5.0 */ + "Unknown Notify Type" /* Reserved */ +}; + +static const char *AcpiDmMadtSubnames[] = +{ + "Processor Local APIC", /* ACPI_MADT_TYPE_LOCAL_APIC */ + "I/O APIC", /* ACPI_MADT_TYPE_IO_APIC */ + "Interrupt Source Override", /* ACPI_MADT_TYPE_INTERRUPT_OVERRIDE */ + "NMI Source", /* ACPI_MADT_TYPE_NMI_SOURCE */ + "Local APIC NMI", /* ACPI_MADT_TYPE_LOCAL_APIC_NMI */ + "Local APIC Address Override", /* ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE */ + "I/O SAPIC", /* ACPI_MADT_TYPE_IO_SAPIC */ + "Local SAPIC", /* ACPI_MADT_TYPE_LOCAL_SAPIC */ + "Platform Interrupt Sources", /* ACPI_MADT_TYPE_INTERRUPT_SOURCE */ + "Processor Local x2APIC", /* ACPI_MADT_TYPE_LOCAL_X2APIC */ + "Local x2APIC NMI", /* ACPI_MADT_TYPE_LOCAL_X2APIC_NMI */ + "Generic Interrupt Controller", /* ACPI_MADT_GENERIC_INTERRUPT */ + "Generic Interrupt Distributor", /* ACPI_MADT_GENERIC_DISTRIBUTOR */ + "Generic MSI Frame", /* ACPI_MADT_GENERIC_MSI_FRAME */ + "Generic Interrupt Redistributor", /* ACPI_MADT_GENERIC_REDISTRIBUTOR */ + "Generic Interrupt Translator", /* ACPI_MADT_GENERIC_TRANSLATOR */ + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmNfitSubnames[] = +{ + "System Physical Address Range", /* ACPI_NFIT_TYPE_SYSTEM_ADDRESS */ + "Memory Range Map", /* ACPI_NFIT_TYPE_MEMORY_MAP */ + "Interleave Info", /* ACPI_NFIT_TYPE_INTERLEAVE */ + "SMBIOS Information", /* ACPI_NFIT_TYPE_SMBIOS */ + "NVDIMM Control Region", /* ACPI_NFIT_TYPE_CONTROL_REGION */ + "NVDIMM Block Data Window Region", /* ACPI_NFIT_TYPE_DATA_REGION */ + "Flush Hint Address", /* ACPI_NFIT_TYPE_FLUSH_ADDRESS */ + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmPcctSubnames[] = +{ + "Generic Communications Subspace", /* ACPI_PCCT_TYPE_GENERIC_SUBSPACE */ + "HW-Reduced Comm Subspace", /* ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE */ + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmPmttSubnames[] = +{ + "Socket", /* ACPI_PMTT_TYPE_SOCKET */ + "Memory Controller", /* ACPI_PMTT_TYPE_CONTROLLER */ + "Physical Component (DIMM)", /* ACPI_PMTT_TYPE_DIMM */ + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmSratSubnames[] = +{ + "Processor Local APIC/SAPIC Affinity", + "Memory Affinity", + "Processor Local x2APIC Affinity", + "GICC Affinity", + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmIvrsSubnames[] = +{ + "Hardware Definition Block", + "Memory Definition Block", + "Unknown Subtable Type" /* Reserved */ +}; + +static const char *AcpiDmLpitSubnames[] = +{ + "Native C-state Idle Structure", + "Unknown Subtable Type" /* Reserved */ +}; + +#define ACPI_FADT_PM_RESERVED 9 + +static const char *AcpiDmFadtProfiles[] = +{ + "Unspecified", + "Desktop", + "Mobile", + "Workstation", + "Enterprise Server", + "SOHO Server", + "Appliance PC", + "Performance Server", + "Tablet", + "Unknown Profile Type" +}; + +#define ACPI_GAS_WIDTH_RESERVED 5 + +static const char *AcpiDmGasAccessWidth[] = +{ + "Undefined/Legacy", + "Byte Access:8", + "Word Access:16", + "DWord Access:32", + "QWord Access:64", + "Unknown Width Encoding" +}; + + +/******************************************************************************* + * + * ACPI Table Data, indexed by signature. + * + * Each entry contains: Signature, Table Info, Handler, DtHandler, + * Template, Description + * + * Simple tables have only a TableInfo structure, complex tables have a + * handler. This table must be NULL terminated. RSDP and FACS are + * special-cased elsewhere. + * + * Note: Any tables added here should be duplicated within AcpiSupportedTables + * in the file common/ahtable.c + * + ******************************************************************************/ + +const ACPI_DMTABLE_DATA AcpiDmTableData[] = +{ + {ACPI_SIG_ASF, NULL, AcpiDmDumpAsf, DtCompileAsf, TemplateAsf}, + {ACPI_SIG_BERT, AcpiDmTableInfoBert, NULL, NULL, TemplateBert}, + {ACPI_SIG_BGRT, AcpiDmTableInfoBgrt, NULL, NULL, TemplateBgrt}, + {ACPI_SIG_BOOT, AcpiDmTableInfoBoot, NULL, NULL, TemplateBoot}, + {ACPI_SIG_CPEP, NULL, AcpiDmDumpCpep, DtCompileCpep, TemplateCpep}, + {ACPI_SIG_CSRT, NULL, AcpiDmDumpCsrt, DtCompileCsrt, TemplateCsrt}, + {ACPI_SIG_DBG2, AcpiDmTableInfoDbg2, AcpiDmDumpDbg2, DtCompileDbg2, TemplateDbg2}, + {ACPI_SIG_DBGP, AcpiDmTableInfoDbgp, NULL, NULL, TemplateDbgp}, + {ACPI_SIG_DMAR, NULL, AcpiDmDumpDmar, DtCompileDmar, TemplateDmar}, + {ACPI_SIG_DRTM, NULL, AcpiDmDumpDrtm, DtCompileDrtm, TemplateDrtm}, + {ACPI_SIG_ECDT, AcpiDmTableInfoEcdt, NULL, NULL, TemplateEcdt}, + {ACPI_SIG_EINJ, NULL, AcpiDmDumpEinj, DtCompileEinj, TemplateEinj}, + {ACPI_SIG_ERST, NULL, AcpiDmDumpErst, DtCompileErst, TemplateErst}, + {ACPI_SIG_FADT, NULL, AcpiDmDumpFadt, DtCompileFadt, TemplateFadt}, + {ACPI_SIG_FPDT, NULL, AcpiDmDumpFpdt, DtCompileFpdt, TemplateFpdt}, + {ACPI_SIG_GTDT, NULL, AcpiDmDumpGtdt, DtCompileGtdt, TemplateGtdt}, + {ACPI_SIG_HEST, NULL, AcpiDmDumpHest, DtCompileHest, TemplateHest}, + {ACPI_SIG_HPET, AcpiDmTableInfoHpet, NULL, NULL, TemplateHpet}, + {ACPI_SIG_IORT, NULL, AcpiDmDumpIort, DtCompileIort, TemplateIort}, + {ACPI_SIG_IVRS, NULL, AcpiDmDumpIvrs, DtCompileIvrs, TemplateIvrs}, + {ACPI_SIG_LPIT, NULL, AcpiDmDumpLpit, DtCompileLpit, TemplateLpit}, + {ACPI_SIG_MADT, NULL, AcpiDmDumpMadt, DtCompileMadt, TemplateMadt}, + {ACPI_SIG_MCFG, NULL, AcpiDmDumpMcfg, DtCompileMcfg, TemplateMcfg}, + {ACPI_SIG_MCHI, AcpiDmTableInfoMchi, NULL, NULL, TemplateMchi}, + {ACPI_SIG_MPST, AcpiDmTableInfoMpst, AcpiDmDumpMpst, DtCompileMpst, TemplateMpst}, + {ACPI_SIG_MSCT, NULL, AcpiDmDumpMsct, DtCompileMsct, TemplateMsct}, + {ACPI_SIG_MSDM, NULL, AcpiDmDumpSlic, DtCompileSlic, TemplateMsdm}, + {ACPI_SIG_MTMR, NULL, AcpiDmDumpMtmr, DtCompileMtmr, TemplateMtmr}, + {ACPI_SIG_NFIT, AcpiDmTableInfoNfit, AcpiDmDumpNfit, DtCompileNfit, TemplateNfit}, + {ACPI_SIG_PCCT, AcpiDmTableInfoPcct, AcpiDmDumpPcct, DtCompilePcct, TemplatePcct}, + {ACPI_SIG_PMTT, NULL, AcpiDmDumpPmtt, DtCompilePmtt, TemplatePmtt}, + {ACPI_SIG_RSDT, NULL, AcpiDmDumpRsdt, DtCompileRsdt, TemplateRsdt}, + {ACPI_SIG_S3PT, NULL, NULL, NULL, TemplateS3pt}, + {ACPI_SIG_SBST, AcpiDmTableInfoSbst, NULL, NULL, TemplateSbst}, + {ACPI_SIG_SLIC, NULL, AcpiDmDumpSlic, DtCompileSlic, TemplateSlic}, + {ACPI_SIG_SLIT, NULL, AcpiDmDumpSlit, DtCompileSlit, TemplateSlit}, + {ACPI_SIG_SPCR, AcpiDmTableInfoSpcr, NULL, NULL, TemplateSpcr}, + {ACPI_SIG_SPMI, AcpiDmTableInfoSpmi, NULL, NULL, TemplateSpmi}, + {ACPI_SIG_SRAT, NULL, AcpiDmDumpSrat, DtCompileSrat, TemplateSrat}, + {ACPI_SIG_STAO, NULL, AcpiDmDumpStao, DtCompileStao, TemplateStao}, + {ACPI_SIG_TCPA, NULL, AcpiDmDumpTcpa, DtCompileTcpa, TemplateTcpa}, + {ACPI_SIG_TPM2, AcpiDmTableInfoTpm2, NULL, NULL, TemplateTpm2}, + {ACPI_SIG_UEFI, AcpiDmTableInfoUefi, NULL, DtCompileUefi, TemplateUefi}, + {ACPI_SIG_VRTC, AcpiDmTableInfoVrtc, AcpiDmDumpVrtc, DtCompileVrtc, TemplateVrtc}, + {ACPI_SIG_WAET, AcpiDmTableInfoWaet, NULL, NULL, TemplateWaet}, + {ACPI_SIG_WDAT, NULL, AcpiDmDumpWdat, DtCompileWdat, TemplateWdat}, + {ACPI_SIG_WDDT, AcpiDmTableInfoWddt, NULL, NULL, TemplateWddt}, + {ACPI_SIG_WDRT, AcpiDmTableInfoWdrt, NULL, NULL, TemplateWdrt}, + {ACPI_SIG_WPBT, NULL, AcpiDmDumpWpbt, DtCompileWpbt, TemplateWpbt}, + {ACPI_SIG_XENV, AcpiDmTableInfoXenv, NULL, NULL, TemplateXenv}, + {ACPI_SIG_XSDT, NULL, AcpiDmDumpXsdt, DtCompileXsdt, TemplateXsdt}, + {NULL, NULL, NULL, NULL, NULL} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGenerateChecksum + * + * PARAMETERS: Table - Pointer to table to be checksummed + * Length - Length of the table + * OriginalChecksum - Value of the checksum field + * + * RETURN: 8 bit checksum of buffer + * + * DESCRIPTION: Computes an 8 bit checksum of the table. + * + ******************************************************************************/ + +UINT8 +AcpiDmGenerateChecksum ( + void *Table, + UINT32 Length, + UINT8 OriginalChecksum) +{ + UINT8 Checksum; + + + /* Sum the entire table as-is */ + + Checksum = AcpiTbChecksum ((UINT8 *) Table, Length); + + /* Subtract off the existing checksum value in the table */ + + Checksum = (UINT8) (Checksum - OriginalChecksum); + + /* Compute the final checksum */ + + Checksum = (UINT8) (0 - Checksum); + return (Checksum); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetTableData + * + * PARAMETERS: Signature - ACPI signature (4 chars) to match + * + * RETURN: Pointer to a valid ACPI_DMTABLE_DATA. Null if no match found. + * + * DESCRIPTION: Find a match in the global table of supported ACPI tables + * + ******************************************************************************/ + +const ACPI_DMTABLE_DATA * +AcpiDmGetTableData ( + char *Signature) +{ + const ACPI_DMTABLE_DATA *Info; + + + for (Info = AcpiDmTableData; Info->Signature; Info++) + { + if (ACPI_COMPARE_NAME (Signature, Info->Signature)) + { + return (Info); + } + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpDataTable + * + * PARAMETERS: Table - An ACPI table + * + * RETURN: None. + * + * DESCRIPTION: Format the contents of an ACPI data table (any table other + * than an SSDT or DSDT that does not contain executable AML code) + * + ******************************************************************************/ + +void +AcpiDmDumpDataTable ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + const ACPI_DMTABLE_DATA *TableData; + UINT32 Length; + + + /* Ignore tables that contain AML */ + + if (AcpiUtIsAmlTable (Table)) + { + if (Gbl_VerboseTemplates) + { + /* Dump the raw table data */ + + Length = Table->Length; + + AcpiOsPrintf ("\n/*\n%s: Length %d (0x%X)\n\n", + ACPI_RAW_TABLE_DATA_HEADER, Length, Length); + AcpiUtDumpBuffer (ACPI_CAST_PTR (UINT8, Table), + Length, DB_BYTE_DISPLAY, 0); + AcpiOsPrintf (" */\n"); + } + return; + } + + /* + * Handle tables that don't use the common ACPI table header structure. + * Currently, these are the FACS, RSDP, and S3PT. + */ + if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_FACS)) + { + Length = Table->Length; + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoFacs); + if (ACPI_FAILURE (Status)) + { + return; + } + } + else if (ACPI_VALIDATE_RSDP_SIG (Table->Signature)) + { + Length = AcpiDmDumpRsdp (Table); + } + else if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_S3PT)) + { + Length = AcpiDmDumpS3pt (Table); + } + else + { + /* + * All other tables must use the common ACPI table header, dump it now + */ + Length = Table->Length; + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoHeader); + if (ACPI_FAILURE (Status)) + { + return; + } + AcpiOsPrintf ("\n"); + + /* Match signature and dispatch appropriately */ + + TableData = AcpiDmGetTableData (Table->Signature); + if (!TableData) + { + if (!strncmp (Table->Signature, "OEM", 3)) + { + AcpiOsPrintf ("\n**** OEM-defined ACPI table [%4.4s], unknown contents\n\n", + Table->Signature); + } + else + { + AcpiOsPrintf ("\n**** Unknown ACPI table signature [%4.4s]\n\n", + Table->Signature); + + fprintf (stderr, "Unknown ACPI table signature [%4.4s], ", + Table->Signature); + + if (!AcpiGbl_ForceAmlDisassembly) + { + fprintf (stderr, "decoding ACPI table header only\n"); + } + else + { + fprintf (stderr, "assuming table contains valid AML code\n"); + } + } + } + else if (TableData->TableHandler) + { + /* Complex table, has a handler */ + + TableData->TableHandler (Table); + } + else if (TableData->TableInfo) + { + /* Simple table, just walk the info table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, TableData->TableInfo); + if (ACPI_FAILURE (Status)) + { + return; + } + } + } + + if (!Gbl_DoTemplates || Gbl_VerboseTemplates) + { + /* Dump the raw table data */ + + AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n", + ACPI_RAW_TABLE_DATA_HEADER, Length, Length); + AcpiUtDumpBuffer (ACPI_CAST_PTR (UINT8, Table), + Length, DB_BYTE_DISPLAY, 0); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmLineHeader + * + * PARAMETERS: Offset - Current byte offset, from table start + * ByteLength - Length of the field in bytes, 0 for flags + * Name - Name of this field + * + * RETURN: None + * + * DESCRIPTION: Utility routines for formatting output lines. Displays the + * current table offset in hex and decimal, the field length, + * and the field name. + * + ******************************************************************************/ + +void +AcpiDmLineHeader ( + UINT32 Offset, + UINT32 ByteLength, + char *Name) +{ + + /* Allow a null name for fields that span multiple lines (large buffers) */ + + if (!Name) + { + Name = ""; + } + + if (Gbl_DoTemplates && !Gbl_VerboseTemplates) /* Terse template */ + { + if (ByteLength) + { + AcpiOsPrintf ("[%.4d] %34s : ", ByteLength, Name); + } + else + { + if (*Name) + { + AcpiOsPrintf ("%41s : ", Name); + } + else + { + AcpiOsPrintf ("%41s ", Name); + } + } + } + else /* Normal disassembler or verbose template */ + { + if (ByteLength) + { + AcpiOsPrintf ("[%3.3Xh %4.4d% 4d] %28s : ", + Offset, Offset, ByteLength, Name); + } + else + { + if (*Name) + { + AcpiOsPrintf ("%44s : ", Name); + } + else + { + AcpiOsPrintf ("%44s ", Name); + } + } + } +} + +void +AcpiDmLineHeader2 ( + UINT32 Offset, + UINT32 ByteLength, + char *Name, + UINT32 Value) +{ + + if (Gbl_DoTemplates && !Gbl_VerboseTemplates) /* Terse template */ + { + if (ByteLength) + { + AcpiOsPrintf ("[%.4d] %30s %3d : ", + ByteLength, Name, Value); + } + else + { + AcpiOsPrintf ("%36s % 3d : ", + Name, Value); + } + } + else /* Normal disassembler or verbose template */ + { + if (ByteLength) + { + AcpiOsPrintf ("[%3.3Xh %4.4d %3d] %24s %3d : ", + Offset, Offset, ByteLength, Name, Value); + } + else + { + AcpiOsPrintf ("[%3.3Xh %4.4d ] %24s %3d : ", + Offset, Offset, Name, Value); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpTable + * + * PARAMETERS: TableLength - Length of the entire ACPI table + * TableOffset - Starting offset within the table for this + * sub-descriptor (0 if main table) + * Table - The ACPI table + * SubtableLength - Length of this sub-descriptor + * Info - Info table for this ACPI table + * + * RETURN: Status + * + * DESCRIPTION: Display ACPI table contents by walking the Info table. + * + * Note: This function must remain in sync with DtGetFieldLength. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDmDumpTable ( + UINT32 TableLength, + UINT32 TableOffset, + void *Table, + UINT32 SubtableLength, + ACPI_DMTABLE_INFO *Info) +{ + UINT8 *Target; + UINT32 CurrentOffset; + UINT32 ByteLength; + UINT8 Temp8; + UINT16 Temp16; + UINT32 Temp32; + UINT64 Value; + const AH_TABLE *TableData; + const char *Name; + BOOLEAN LastOutputBlankLine = FALSE; + ACPI_STATUS Status; + char RepairedName[8]; + + + if (!Info) + { + AcpiOsPrintf ("Display not implemented\n"); + return (AE_NOT_IMPLEMENTED); + } + + /* Walk entire Info table; Null name terminates */ + + for (; Info->Name; Info++) + { + /* + * Target points to the field within the ACPI Table. CurrentOffset is + * the offset of the field from the start of the main table. + */ + Target = ACPI_ADD_PTR (UINT8, Table, Info->Offset); + CurrentOffset = TableOffset + Info->Offset; + + /* Check for beyond subtable end or (worse) beyond EOT */ + + if (SubtableLength && (Info->Offset >= SubtableLength)) + { + AcpiOsPrintf ( + "/**** ACPI subtable terminates early - " + "may be older version (dump table) */\n"); + + /* Move on to next subtable */ + + return (AE_OK); + } + + if (CurrentOffset >= TableLength) + { + AcpiOsPrintf ( + "/**** ACPI table terminates " + "in the middle of a data structure! (dump table) */\n"); + return (AE_BAD_DATA); + } + + /* Generate the byte length for this field */ + + switch (Info->Opcode) + { + case ACPI_DMT_UINT8: + case ACPI_DMT_CHKSUM: + case ACPI_DMT_SPACEID: + case ACPI_DMT_ACCWIDTH: + case ACPI_DMT_IVRS: + case ACPI_DMT_GTDT: + case ACPI_DMT_MADT: + case ACPI_DMT_PCCT: + case ACPI_DMT_PMTT: + case ACPI_DMT_SRAT: + case ACPI_DMT_ASF: + case ACPI_DMT_HESTNTYP: + case ACPI_DMT_FADTPM: + case ACPI_DMT_EINJACT: + case ACPI_DMT_EINJINST: + case ACPI_DMT_ERSTACT: + case ACPI_DMT_ERSTINST: + case ACPI_DMT_DMAR_SCOPE: + + ByteLength = 1; + break; + + case ACPI_DMT_UINT16: + case ACPI_DMT_DMAR: + case ACPI_DMT_HEST: + case ACPI_DMT_NFIT: + + ByteLength = 2; + break; + + case ACPI_DMT_UINT24: + + ByteLength = 3; + break; + + case ACPI_DMT_UINT32: + case ACPI_DMT_NAME4: + case ACPI_DMT_SIG: + case ACPI_DMT_LPIT: + + ByteLength = 4; + break; + + case ACPI_DMT_UINT40: + + ByteLength = 5; + break; + + case ACPI_DMT_UINT48: + case ACPI_DMT_NAME6: + + ByteLength = 6; + break; + + case ACPI_DMT_UINT56: + case ACPI_DMT_BUF7: + + ByteLength = 7; + break; + + case ACPI_DMT_UINT64: + case ACPI_DMT_NAME8: + + ByteLength = 8; + break; + + case ACPI_DMT_BUF10: + + ByteLength = 10; + break; + + case ACPI_DMT_BUF16: + case ACPI_DMT_UUID: + + ByteLength = 16; + break; + + case ACPI_DMT_BUF128: + + ByteLength = 128; + break; + + case ACPI_DMT_UNICODE: + case ACPI_DMT_BUFFER: + case ACPI_DMT_RAW_BUFFER: + + ByteLength = SubtableLength; + break; + + case ACPI_DMT_STRING: + + ByteLength = strlen (ACPI_CAST_PTR (char, Target)) + 1; + break; + + case ACPI_DMT_GAS: + + if (!LastOutputBlankLine) + { + AcpiOsPrintf ("\n"); + LastOutputBlankLine = TRUE; + } + + ByteLength = sizeof (ACPI_GENERIC_ADDRESS); + break; + + case ACPI_DMT_HESTNTFY: + + if (!LastOutputBlankLine) + { + AcpiOsPrintf ("\n"); + LastOutputBlankLine = TRUE; + } + + ByteLength = sizeof (ACPI_HEST_NOTIFY); + break; + + case ACPI_DMT_IORTMEM: + + if (!LastOutputBlankLine) + { + LastOutputBlankLine = FALSE; + } + + ByteLength = sizeof (ACPI_IORT_MEMORY_ACCESS); + break; + + default: + + ByteLength = 0; + break; + } + + /* Check if we are beyond a subtable, or (worse) beyond EOT */ + + if (CurrentOffset + ByteLength > TableLength) + { + if (SubtableLength) + { + AcpiOsPrintf ( + "/**** ACPI subtable terminates early - " + "may be older version (dump table) */\n"); + + /* Move on to next subtable */ + + return (AE_OK); + } + + AcpiOsPrintf ( + "/**** ACPI table terminates " + "in the middle of a data structure! */\n"); + return (AE_BAD_DATA); + } + + if (Info->Opcode == ACPI_DMT_EXTRA_TEXT) + { + AcpiOsPrintf ("%s", Info->Name); + continue; + } + + /* Start a new line and decode the opcode */ + + AcpiDmLineHeader (CurrentOffset, ByteLength, Info->Name); + + switch (Info->Opcode) + { + /* Single-bit Flag fields. Note: Opcode is the bit position */ + + case ACPI_DMT_FLAG0: + case ACPI_DMT_FLAG1: + case ACPI_DMT_FLAG2: + case ACPI_DMT_FLAG3: + case ACPI_DMT_FLAG4: + case ACPI_DMT_FLAG5: + case ACPI_DMT_FLAG6: + case ACPI_DMT_FLAG7: + + AcpiOsPrintf ("%1.1X\n", (*Target >> Info->Opcode) & 0x01); + break; + + /* 2-bit Flag fields */ + + case ACPI_DMT_FLAGS0: + + AcpiOsPrintf ("%1.1X\n", *Target & 0x03); + break; + + case ACPI_DMT_FLAGS1: + + AcpiOsPrintf ("%1.1X\n", (*Target >> 1) & 0x03); + break; + + case ACPI_DMT_FLAGS2: + + AcpiOsPrintf ("%1.1X\n", (*Target >> 2) & 0x03); + break; + + case ACPI_DMT_FLAGS4: + + AcpiOsPrintf ("%1.1X\n", (*Target >> 4) & 0x03); + break; + + /* Integer Data Types */ + + case ACPI_DMT_UINT8: + case ACPI_DMT_UINT16: + case ACPI_DMT_UINT24: + case ACPI_DMT_UINT32: + case ACPI_DMT_UINT40: + case ACPI_DMT_UINT48: + case ACPI_DMT_UINT56: + case ACPI_DMT_UINT64: + /* + * Dump bytes - high byte first, low byte last. + * Note: All ACPI tables are little-endian. + */ + Value = 0; + for (Temp8 = (UINT8) ByteLength; Temp8 > 0; Temp8--) + { + AcpiOsPrintf ("%2.2X", Target[Temp8 - 1]); + Value |= Target[Temp8 - 1]; + Value <<= 8; + } + + if (!Value && (Info->Flags & DT_DESCRIBES_OPTIONAL)) + { + AcpiOsPrintf (" [Optional field not present]"); + } + + AcpiOsPrintf ("\n"); + break; + + case ACPI_DMT_BUF7: + case ACPI_DMT_BUF10: + case ACPI_DMT_BUF16: + case ACPI_DMT_BUF128: + /* + * Buffer: Size depends on the opcode and was set above. + * Each hex byte is separated with a space. + * Multiple lines are separated by line continuation char. + */ + for (Temp16 = 0; Temp16 < ByteLength; Temp16++) + { + AcpiOsPrintf ("%2.2X", Target[Temp16]); + if ((UINT32) (Temp16 + 1) < ByteLength) + { + if ((Temp16 > 0) && (!((Temp16+1) % 16))) + { + AcpiOsPrintf (" \\\n"); /* Line continuation */ + AcpiDmLineHeader (0, 0, NULL); + } + else + { + AcpiOsPrintf (" "); + } + } + } + + AcpiOsPrintf ("\n"); + break; + + case ACPI_DMT_UUID: + + /* Convert 16-byte UUID buffer to 36-byte formatted UUID string */ + + (void) AuConvertUuidToString ((char *) Target, MsgBuffer); + + AcpiOsPrintf ("%s\n", MsgBuffer); + break; + + case ACPI_DMT_STRING: + + AcpiOsPrintf ("\"%s\"\n", ACPI_CAST_PTR (char, Target)); + break; + + /* Fixed length ASCII name fields */ + + case ACPI_DMT_SIG: + + AcpiDmCheckAscii (Target, RepairedName, 4); + AcpiOsPrintf ("\"%.4s\" ", RepairedName); + + TableData = AcpiAhGetTableInfo (ACPI_CAST_PTR (char, Target)); + if (TableData) + { + AcpiOsPrintf (STRING_FORMAT, TableData->Description); + } + else + { + AcpiOsPrintf ("\n"); + } + break; + + case ACPI_DMT_NAME4: + + AcpiDmCheckAscii (Target, RepairedName, 4); + AcpiOsPrintf ("\"%.4s\"\n", RepairedName); + break; + + case ACPI_DMT_NAME6: + + AcpiDmCheckAscii (Target, RepairedName, 6); + AcpiOsPrintf ("\"%.6s\"\n", RepairedName); + break; + + case ACPI_DMT_NAME8: + + AcpiDmCheckAscii (Target, RepairedName, 8); + AcpiOsPrintf ("\"%.8s\"\n", RepairedName); + break; + + /* Special Data Types */ + + case ACPI_DMT_CHKSUM: + + /* Checksum, display and validate */ + + AcpiOsPrintf ("%2.2X", *Target); + Temp8 = AcpiDmGenerateChecksum (Table, + ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Length, + ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Checksum); + + if (Temp8 != ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Checksum) + { + AcpiOsPrintf ( + " /* Incorrect checksum, should be %2.2X */", Temp8); + } + + AcpiOsPrintf ("\n"); + break; + + case ACPI_DMT_SPACEID: + + /* Address Space ID */ + + AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiUtGetRegionName (*Target)); + break; + + case ACPI_DMT_ACCWIDTH: + + /* Encoded Access Width */ + + Temp8 = *Target; + if (Temp8 > ACPI_GAS_WIDTH_RESERVED) + { + Temp8 = ACPI_GAS_WIDTH_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmGasAccessWidth[Temp8]); + break; + + case ACPI_DMT_GAS: + + /* Generic Address Structure */ + + AcpiOsPrintf (STRING_FORMAT, "Generic Address Structure"); + Status = AcpiDmDumpTable (TableLength, CurrentOffset, Target, + sizeof (ACPI_GENERIC_ADDRESS), AcpiDmTableInfoGas); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + AcpiOsPrintf ("\n"); + LastOutputBlankLine = TRUE; + break; + + case ACPI_DMT_ASF: + + /* ASF subtable types */ + + Temp16 = (UINT16) ((*Target) & 0x7F); /* Top bit can be zero or one */ + if (Temp16 > ACPI_ASF_TYPE_RESERVED) + { + Temp16 = ACPI_ASF_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmAsfSubnames[Temp16]); + break; + + case ACPI_DMT_DMAR: + + /* DMAR subtable types */ + + Temp16 = ACPI_GET16 (Target); + if (Temp16 > ACPI_DMAR_TYPE_RESERVED) + { + Temp16 = ACPI_DMAR_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target), + AcpiDmDmarSubnames[Temp16]); + break; + + case ACPI_DMT_DMAR_SCOPE: + + /* DMAR device scope types */ + + Temp8 = *Target; + if (Temp8 > ACPI_DMAR_SCOPE_TYPE_RESERVED) + { + Temp8 = ACPI_DMAR_SCOPE_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmDmarScope[Temp8]); + break; + + case ACPI_DMT_EINJACT: + + /* EINJ Action types */ + + Temp8 = *Target; + if (Temp8 > ACPI_EINJ_ACTION_RESERVED) + { + Temp8 = ACPI_EINJ_ACTION_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmEinjActions[Temp8]); + break; + + case ACPI_DMT_EINJINST: + + /* EINJ Instruction types */ + + Temp8 = *Target; + if (Temp8 > ACPI_EINJ_INSTRUCTION_RESERVED) + { + Temp8 = ACPI_EINJ_INSTRUCTION_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmEinjInstructions[Temp8]); + break; + + case ACPI_DMT_ERSTACT: + + /* ERST Action types */ + + Temp8 = *Target; + if (Temp8 > ACPI_ERST_ACTION_RESERVED) + { + Temp8 = ACPI_ERST_ACTION_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmErstActions[Temp8]); + break; + + case ACPI_DMT_ERSTINST: + + /* ERST Instruction types */ + + Temp8 = *Target; + if (Temp8 > ACPI_ERST_INSTRUCTION_RESERVED) + { + Temp8 = ACPI_ERST_INSTRUCTION_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmErstInstructions[Temp8]); + break; + + case ACPI_DMT_GTDT: + + /* GTDT subtable types */ + + Temp8 = *Target; + if (Temp8 > ACPI_GTDT_TYPE_RESERVED) + { + Temp8 = ACPI_GTDT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmGtdtSubnames[Temp8]); + break; + + case ACPI_DMT_HEST: + + /* HEST subtable types */ + + Temp16 = ACPI_GET16 (Target); + if (Temp16 > ACPI_HEST_TYPE_RESERVED) + { + Temp16 = ACPI_HEST_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target), + AcpiDmHestSubnames[Temp16]); + break; + + case ACPI_DMT_HESTNTFY: + + AcpiOsPrintf (STRING_FORMAT, + "Hardware Error Notification Structure"); + + Status = AcpiDmDumpTable (TableLength, CurrentOffset, Target, + sizeof (ACPI_HEST_NOTIFY), AcpiDmTableInfoHestNotify); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + AcpiOsPrintf ("\n"); + LastOutputBlankLine = TRUE; + break; + + case ACPI_DMT_HESTNTYP: + + /* HEST Notify types */ + + Temp8 = *Target; + if (Temp8 > ACPI_HEST_NOTIFY_RESERVED) + { + Temp8 = ACPI_HEST_NOTIFY_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmHestNotifySubnames[Temp8]); + break; + + case ACPI_DMT_IORTMEM: + + AcpiOsPrintf (STRING_FORMAT, + "IORT Memory Access Properties"); + + Status = AcpiDmDumpTable (TableLength, CurrentOffset, Target, + sizeof (ACPI_IORT_MEMORY_ACCESS), AcpiDmTableInfoIortAcc); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + LastOutputBlankLine = TRUE; + break; + + case ACPI_DMT_MADT: + + /* MADT subtable types */ + + Temp8 = *Target; + if (Temp8 > ACPI_MADT_TYPE_RESERVED) + { + Temp8 = ACPI_MADT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmMadtSubnames[Temp8]); + break; + + case ACPI_DMT_NFIT: + + /* NFIT subtable types */ + + Temp16 = ACPI_GET16 (Target); + if (Temp16 > ACPI_NFIT_TYPE_RESERVED) + { + Temp16 = ACPI_NFIT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target), + AcpiDmNfitSubnames[Temp16]); + break; + + case ACPI_DMT_PCCT: + + /* PCCT subtable types */ + + Temp8 = *Target; + if (Temp8 > ACPI_PCCT_TYPE_RESERVED) + { + Temp8 = ACPI_PCCT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmPcctSubnames[Temp8]); + break; + + case ACPI_DMT_PMTT: + + /* PMTT subtable types */ + + Temp8 = *Target; + if (Temp8 > ACPI_PMTT_TYPE_RESERVED) + { + Temp8 = ACPI_PMTT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmPmttSubnames[Temp8]); + break; + + case ACPI_DMT_UNICODE: + + if (ByteLength == 0) + { + AcpiOsPrintf ("/* Zero-length Data */\n"); + break; + } + + AcpiDmDumpUnicode (Table, CurrentOffset, ByteLength); + break; + + case ACPI_DMT_RAW_BUFFER: + + if (ByteLength == 0) + { + AcpiOsPrintf ("/* Zero-length Data */\n"); + break; + } + + AcpiDmDumpBuffer (Table, CurrentOffset, ByteLength, + CurrentOffset, NULL); + break; + + case ACPI_DMT_SRAT: + + /* SRAT subtable types */ + + Temp8 = *Target; + if (Temp8 > ACPI_SRAT_TYPE_RESERVED) + { + Temp8 = ACPI_SRAT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmSratSubnames[Temp8]); + break; + + case ACPI_DMT_FADTPM: + + /* FADT Preferred PM Profile names */ + + Temp8 = *Target; + if (Temp8 > ACPI_FADT_PM_RESERVED) + { + Temp8 = ACPI_FADT_PM_RESERVED; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, + AcpiDmFadtProfiles[Temp8]); + break; + + case ACPI_DMT_IVRS: + + /* IVRS subtable types */ + + Temp8 = *Target; + switch (Temp8) + { + case ACPI_IVRS_TYPE_HARDWARE: + + Name = AcpiDmIvrsSubnames[0]; + break; + + case ACPI_IVRS_TYPE_MEMORY1: + case ACPI_IVRS_TYPE_MEMORY2: + case ACPI_IVRS_TYPE_MEMORY3: + + Name = AcpiDmIvrsSubnames[1]; + break; + + default: + + Name = AcpiDmIvrsSubnames[2]; + break; + } + + AcpiOsPrintf (UINT8_FORMAT, *Target, Name); + break; + + case ACPI_DMT_LPIT: + + /* LPIT subtable types */ + + Temp32 = ACPI_GET32 (Target); + if (Temp32 > ACPI_LPIT_TYPE_RESERVED) + { + Temp32 = ACPI_LPIT_TYPE_RESERVED; + } + + AcpiOsPrintf (UINT32_FORMAT, ACPI_GET32 (Target), + AcpiDmLpitSubnames[Temp32]); + break; + + case ACPI_DMT_EXIT: + + return (AE_OK); + + default: + + ACPI_ERROR ((AE_INFO, + "**** Invalid table opcode [0x%X] ****\n", Info->Opcode)); + return (AE_SUPPORT); + } + } + + if (TableOffset && !SubtableLength) + { + /* + * If this table is not the main table, the subtable must have a + * valid length + */ + AcpiOsPrintf ("Invalid zero length subtable\n"); + return (AE_BAD_DATA); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCheckAscii + * + * PARAMETERS: Name - Ascii string + * Count - Number of characters to check + * + * RETURN: None + * + * DESCRIPTION: Ensure that the requested number of characters are printable + * Ascii characters. Sets non-printable and null chars to . + * + ******************************************************************************/ + +static void +AcpiDmCheckAscii ( + UINT8 *Name, + char *RepairedName, + UINT32 Count) +{ + UINT32 i; + + + for (i = 0; i < Count; i++) + { + RepairedName[i] = (char) Name[i]; + + if (!Name[i]) + { + return; + } + if (!isprint (Name[i])) + { + RepairedName[i] = ' '; + } + } +} diff --git a/third_party/lib/acpica/source/common/dmtables.c b/third_party/lib/acpica/source/common/dmtables.c new file mode 100644 index 000000000..5df445720 --- /dev/null +++ b/third_party/lib/acpica/source/common/dmtables.c @@ -0,0 +1,499 @@ +/****************************************************************************** + * + * Module Name: dmtables - disassembler ACPI table support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acapps.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "actables.h" +#include "acparser.h" + +#include +#include + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("dmtables") + + +/* Local prototypes */ + +static void +AdCreateTableHeader ( + char *Filename, + ACPI_TABLE_HEADER *Table); + +static ACPI_STATUS +AdStoreTable ( + ACPI_TABLE_HEADER *Table, + UINT32 *TableIndex); + + +extern ACPI_TABLE_DESC LocalTables[1]; +extern ACPI_PARSE_OBJECT *AcpiGbl_ParseOpRoot; + + +/****************************************************************************** + * + * FUNCTION: AdDisassemblerHeader + * + * PARAMETERS: Filename - Input file for the table + * TableType - Either AML or DataTable + * + * RETURN: None + * + * DESCRIPTION: Create the disassembler header, including ACPICA signon with + * current time and date. + * + *****************************************************************************/ + +void +AdDisassemblerHeader ( + char *Filename, + UINT8 TableType) +{ + time_t Timer; + + + time (&Timer); + + /* Header and input table info */ + + AcpiOsPrintf ("/*\n"); + AcpiOsPrintf (ACPI_COMMON_HEADER (AML_DISASSEMBLER_NAME, " * ")); + + if (TableType == ACPI_IS_AML_TABLE) + { + if (AcpiGbl_CstyleDisassembly) + { + AcpiOsPrintf ( + " * Disassembling to symbolic ASL+ operators\n" + " *\n"); + } + else + { + AcpiOsPrintf ( + " * Disassembling to non-symbolic legacy ASL operators\n" + " *\n"); + } + } + + AcpiOsPrintf (" * Disassembly of %s, %s", Filename, ctime (&Timer)); + AcpiOsPrintf (" *\n"); +} + + +/****************************************************************************** + * + * FUNCTION: AdCreateTableHeader + * + * PARAMETERS: Filename - Input file for the table + * Table - Pointer to the raw table + * + * RETURN: None + * + * DESCRIPTION: Create the ASL table header, including ACPICA signon with + * current time and date. + * + *****************************************************************************/ + +static void +AdCreateTableHeader ( + char *Filename, + ACPI_TABLE_HEADER *Table) +{ + char *NewFilename; + UINT8 Checksum; + + + /* + * Print file header and dump original table header + */ + AdDisassemblerHeader (Filename, ACPI_IS_AML_TABLE); + + AcpiOsPrintf (" * Original Table Header:\n"); + AcpiOsPrintf (" * Signature \"%4.4s\"\n", Table->Signature); + AcpiOsPrintf (" * Length 0x%8.8X (%u)\n", Table->Length, Table->Length); + + /* Print and validate the revision */ + + AcpiOsPrintf (" * Revision 0x%2.2X", Table->Revision); + + switch (Table->Revision) + { + case 0: + + AcpiOsPrintf (" **** Invalid Revision"); + break; + + case 1: + + /* Revision of DSDT controls the ACPI integer width */ + + if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT)) + { + AcpiOsPrintf (" **** 32-bit table (V1), no 64-bit math support"); + } + break; + + default: + + break; + } + AcpiOsPrintf ("\n"); + + /* Print and validate the table checksum */ + + AcpiOsPrintf (" * Checksum 0x%2.2X", Table->Checksum); + + Checksum = AcpiTbChecksum (ACPI_CAST_PTR (UINT8, Table), Table->Length); + if (Checksum) + { + AcpiOsPrintf (" **** Incorrect checksum, should be 0x%2.2X", + (UINT8) (Table->Checksum - Checksum)); + } + + AcpiOsPrintf ("\n"); + AcpiOsPrintf (" * OEM ID \"%.6s\"\n", Table->OemId); + AcpiOsPrintf (" * OEM Table ID \"%.8s\"\n", Table->OemTableId); + AcpiOsPrintf (" * OEM Revision 0x%8.8X (%u)\n", Table->OemRevision, Table->OemRevision); + AcpiOsPrintf (" * Compiler ID \"%.4s\"\n", Table->AslCompilerId); + AcpiOsPrintf (" * Compiler Version 0x%8.8X (%u)\n", Table->AslCompilerRevision, Table->AslCompilerRevision); + AcpiOsPrintf (" */\n"); + + /* Create AML output filename based on input filename */ + + if (Filename) + { + NewFilename = FlGenerateFilename (Filename, "aml"); + } + else + { + NewFilename = UtStringCacheCalloc (9); + if (NewFilename) + { + strncat (NewFilename, Table->Signature, 4); + strcat (NewFilename, ".aml"); + } + } + + if (!NewFilename) + { + AcpiOsPrintf (" **** Could not generate AML output filename\n"); + return; + } + + /* Open the ASL definition block */ + + AcpiOsPrintf ( + "DefinitionBlock (\"%s\", \"%4.4s\", %hu, \"%.6s\", \"%.8s\", 0x%8.8X)\n", + NewFilename, Table->Signature, Table->Revision, + Table->OemId, Table->OemTableId, Table->OemRevision); +} + + +/****************************************************************************** + * + * FUNCTION: AdDisplayTables + * + * PARAMETERS: Filename - Input file for the table + * Table - Pointer to the raw table + * + * RETURN: Status + * + * DESCRIPTION: Display (disassemble) loaded tables and dump raw tables + * + *****************************************************************************/ + +ACPI_STATUS +AdDisplayTables ( + char *Filename, + ACPI_TABLE_HEADER *Table) +{ + + + if (!AcpiGbl_ParseOpRoot) + { + return (AE_NOT_EXIST); + } + + if (!AcpiGbl_DmOpt_Listing) + { + AdCreateTableHeader (Filename, Table); + } + + AcpiDmDisassemble (NULL, AcpiGbl_ParseOpRoot, ACPI_UINT32_MAX); + MpEmitMappingInfo (); + + if (AcpiGbl_DmOpt_Listing) + { + AcpiOsPrintf ("\n\nTable Header:\n"); + AcpiUtDebugDumpBuffer ((UINT8 *) Table, sizeof (ACPI_TABLE_HEADER), + DB_BYTE_DISPLAY, ACPI_UINT32_MAX); + + AcpiOsPrintf ("Table Body (Length 0x%X)\n", Table->Length); + AcpiUtDebugDumpBuffer (((UINT8 *) Table + sizeof (ACPI_TABLE_HEADER)), + Table->Length, DB_BYTE_DISPLAY, ACPI_UINT32_MAX); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AdStoreTable + * + * PARAMETERS: Table - Table header + * TableIndex - Where the table index is returned + * + * RETURN: Status and table index. + * + * DESCRIPTION: Add an ACPI table to the global table list + * + ******************************************************************************/ + +static ACPI_STATUS +AdStoreTable ( + ACPI_TABLE_HEADER *Table, + UINT32 *TableIndex) +{ + ACPI_STATUS Status; + ACPI_TABLE_DESC *TableDesc; + + + Status = AcpiTbGetNextTableDescriptor (TableIndex, &TableDesc); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Initialize added table */ + + AcpiTbInitTableDescriptor (TableDesc, ACPI_PTR_TO_PHYSADDR (Table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, Table); + Status = AcpiTbValidateTable (TableDesc); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AdGetLocalTables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Get the ACPI tables from either memory or a file + * + *****************************************************************************/ + +ACPI_STATUS +AdGetLocalTables ( + void) +{ + ACPI_STATUS Status; + ACPI_TABLE_HEADER TableHeader; + ACPI_TABLE_HEADER *NewTable; + UINT32 TableIndex; + + + /* Get the DSDT via table override */ + + ACPI_MOVE_32_TO_32 (TableHeader.Signature, ACPI_SIG_DSDT); + AcpiOsTableOverride (&TableHeader, &NewTable); + if (!NewTable) + { + fprintf (stderr, "Could not obtain DSDT\n"); + return (AE_NO_ACPI_TABLES); + } + + AdWriteTable (NewTable, NewTable->Length, + ACPI_SIG_DSDT, NewTable->OemTableId); + + /* Store DSDT in the Table Manager */ + + Status = AdStoreTable (NewTable, &TableIndex); + if (ACPI_FAILURE (Status)) + { + fprintf (stderr, "Could not store DSDT\n"); + return (AE_NO_ACPI_TABLES); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AdParseTable + * + * PARAMETERS: Table - Pointer to the raw table + * OwnerId - Returned OwnerId of the table + * LoadTable - If add table to the global table list + * External - If this is an external table + * + * RETURN: Status + * + * DESCRIPTION: Parse an ACPI AML table + * + *****************************************************************************/ + +ACPI_STATUS +AdParseTable ( + ACPI_TABLE_HEADER *Table, + ACPI_OWNER_ID *OwnerId, + BOOLEAN LoadTable, + BOOLEAN External) +{ + ACPI_STATUS Status = AE_OK; + ACPI_WALK_STATE *WalkState; + UINT8 *AmlStart; + UINT32 AmlLength; + UINT32 TableIndex; + + + if (!Table) + { + return (AE_NOT_EXIST); + } + + /* Pass 1: Parse everything except control method bodies */ + + fprintf (stderr, "Pass 1 parse of [%4.4s]\n", (char *) Table->Signature); + + AmlLength = Table->Length - sizeof (ACPI_TABLE_HEADER); + AmlStart = ((UINT8 *) Table + sizeof (ACPI_TABLE_HEADER)); + + /* Create the root object */ + + AcpiGbl_ParseOpRoot = AcpiPsCreateScopeOp (AmlStart); + if (!AcpiGbl_ParseOpRoot) + { + return (AE_NO_MEMORY); + } + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (0, AcpiGbl_ParseOpRoot, NULL, NULL); + if (!WalkState) + { + return (AE_NO_MEMORY); + } + + Status = AcpiDsInitAmlWalk (WalkState, AcpiGbl_ParseOpRoot, + NULL, AmlStart, AmlLength, NULL, ACPI_IMODE_LOAD_PASS1); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE; + WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE; + + Status = AcpiPsParseAml (WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* If LoadTable is FALSE, we are parsing the last loaded table */ + + TableIndex = AcpiGbl_RootTableList.CurrentTableCount - 1; + + /* Pass 2 */ + + if (LoadTable) + { + Status = AdStoreTable (Table, &TableIndex); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + Status = AcpiTbAllocateOwnerId (TableIndex); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + if (OwnerId) + { + Status = AcpiTbGetOwnerId (TableIndex, OwnerId); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + fprintf (stderr, "Pass 2 parse of [%4.4s]\n", (char *) Table->Signature); + + Status = AcpiNsOneCompleteParse (ACPI_IMODE_LOAD_PASS2, TableIndex, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* No need to parse control methods of external table */ + + if (External) + { + return (AE_OK); + } + + /* + * Pass 3: Parse control methods and link their parse trees + * into the main parse tree + */ + fprintf (stderr, + "Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)\n"); + + Status = AcpiDmParseDeferredOps (AcpiGbl_ParseOpRoot); + fprintf (stderr, "\n"); + + /* Process Resource Templates */ + + AcpiDmFindResources (AcpiGbl_ParseOpRoot); + + fprintf (stderr, "Parsing completed\n"); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/common/dmtbdump.c b/third_party/lib/acpica/source/common/dmtbdump.c new file mode 100644 index 000000000..3c5ce776c --- /dev/null +++ b/third_party/lib/acpica/source/common/dmtbdump.c @@ -0,0 +1,3675 @@ +/****************************************************************************** + * + * Module Name: dmtbdump - Dump ACPI data tables that contain no AML code + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdisasm.h" +#include "actables.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_CA_DISASSEMBLER + ACPI_MODULE_NAME ("dmtbdump") + + +/* Local prototypes */ + +static void +AcpiDmValidateFadtLength ( + UINT32 Revision, + UINT32 Length); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpBuffer + * + * PARAMETERS: Table - ACPI Table or subtable + * BufferOffset - Offset of buffer from Table above + * Length - Length of the buffer + * AbsoluteOffset - Offset of buffer in the main ACPI table + * Header - Name of the buffer field (printed on the + * first line only.) + * + * RETURN: None + * + * DESCRIPTION: Format the contents of an arbitrary length data buffer (in the + * disassembler output format.) + * + ******************************************************************************/ + +void +AcpiDmDumpBuffer ( + void *Table, + UINT32 BufferOffset, + UINT32 Length, + UINT32 AbsoluteOffset, + char *Header) +{ + UINT8 *Buffer; + UINT32 i; + + + if (!Length) + { + return; + } + + Buffer = ACPI_CAST_PTR (UINT8, Table) + BufferOffset; + i = 0; + + while (i < Length) + { + if (!(i % 16)) + { + /* Insert a backslash - line continuation character */ + + if (Length > 16) + { + AcpiOsPrintf ("\\\n "); + } + } + + AcpiOsPrintf ("%.02X ", *Buffer); + i++; + Buffer++; + AbsoluteOffset++; + } + + AcpiOsPrintf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpUnicode + * + * PARAMETERS: Table - ACPI Table or subtable + * BufferOffset - Offset of buffer from Table above + * ByteLength - Length of the buffer + * + * RETURN: None + * + * DESCRIPTION: Validate and dump the contents of a buffer that contains + * unicode data. The output is a standard ASCII string. If it + * appears that the data is not unicode, the buffer is dumped + * as hex characters. + * + ******************************************************************************/ + +void +AcpiDmDumpUnicode ( + void *Table, + UINT32 BufferOffset, + UINT32 ByteLength) +{ + UINT8 *Buffer; + UINT32 Length; + UINT32 i; + + + Buffer = ((UINT8 *) Table) + BufferOffset; + Length = ByteLength - 2; /* Last two bytes are the null terminator */ + + /* Ensure all low bytes are entirely printable ASCII */ + + for (i = 0; i < Length; i += 2) + { + if (!isprint (Buffer[i])) + { + goto DumpRawBuffer; + } + } + + /* Ensure all high bytes are zero */ + + for (i = 1; i < Length; i += 2) + { + if (Buffer[i]) + { + goto DumpRawBuffer; + } + } + + /* Dump the buffer as a normal string */ + + AcpiOsPrintf ("\""); + for (i = 0; i < Length; i += 2) + { + AcpiOsPrintf ("%c", Buffer[i]); + } + + AcpiOsPrintf ("\"\n"); + return; + +DumpRawBuffer: + AcpiDmDumpBuffer (Table, BufferOffset, ByteLength, + BufferOffset, NULL); + AcpiOsPrintf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpRsdp + * + * PARAMETERS: Table - A RSDP + * + * RETURN: Length of the table (there is not always a length field, + * use revision or length if available (ACPI 2.0+)) + * + * DESCRIPTION: Format the contents of a RSDP + * + ******************************************************************************/ + +UINT32 +AcpiDmDumpRsdp ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_TABLE_RSDP *Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table); + UINT32 Length = sizeof (ACPI_RSDP_COMMON); + UINT8 Checksum; + ACPI_STATUS Status; + + + /* Dump the common ACPI 1.0 portion */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoRsdp1); + if (ACPI_FAILURE (Status)) + { + return (Length); + } + + /* Validate the first checksum */ + + Checksum = AcpiDmGenerateChecksum (Rsdp, sizeof (ACPI_RSDP_COMMON), + Rsdp->Checksum); + if (Checksum != Rsdp->Checksum) + { + AcpiOsPrintf ("/* Incorrect Checksum above, should be 0x%2.2X */\n", + Checksum); + } + + /* The RSDP for ACPI 2.0+ contains more data and has a Length field */ + + if (Rsdp->Revision > 0) + { + Length = Rsdp->Length; + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoRsdp2); + if (ACPI_FAILURE (Status)) + { + return (Length); + } + + /* Validate the extended checksum over entire RSDP */ + + Checksum = AcpiDmGenerateChecksum (Rsdp, sizeof (ACPI_TABLE_RSDP), + Rsdp->ExtendedChecksum); + if (Checksum != Rsdp->ExtendedChecksum) + { + AcpiOsPrintf ( + "/* Incorrect Extended Checksum above, should be 0x%2.2X */\n", + Checksum); + } + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpRsdt + * + * PARAMETERS: Table - A RSDT + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a RSDT + * + ******************************************************************************/ + +void +AcpiDmDumpRsdt ( + ACPI_TABLE_HEADER *Table) +{ + UINT32 *Array; + UINT32 Entries; + UINT32 Offset; + UINT32 i; + + + /* Point to start of table pointer array */ + + Array = ACPI_CAST_PTR (ACPI_TABLE_RSDT, Table)->TableOffsetEntry; + Offset = sizeof (ACPI_TABLE_HEADER); + + /* RSDT uses 32-bit pointers */ + + Entries = (Table->Length - sizeof (ACPI_TABLE_HEADER)) / sizeof (UINT32); + + for (i = 0; i < Entries; i++) + { + AcpiDmLineHeader2 (Offset, sizeof (UINT32), "ACPI Table Address", i); + AcpiOsPrintf ("%8.8X\n", Array[i]); + Offset += sizeof (UINT32); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpXsdt + * + * PARAMETERS: Table - A XSDT + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a XSDT + * + ******************************************************************************/ + +void +AcpiDmDumpXsdt ( + ACPI_TABLE_HEADER *Table) +{ + UINT64 *Array; + UINT32 Entries; + UINT32 Offset; + UINT32 i; + + + /* Point to start of table pointer array */ + + Array = ACPI_CAST_PTR (ACPI_TABLE_XSDT, Table)->TableOffsetEntry; + Offset = sizeof (ACPI_TABLE_HEADER); + + /* XSDT uses 64-bit pointers */ + + Entries = (Table->Length - sizeof (ACPI_TABLE_HEADER)) / sizeof (UINT64); + + for (i = 0; i < Entries; i++) + { + AcpiDmLineHeader2 (Offset, sizeof (UINT64), "ACPI Table Address", i); + AcpiOsPrintf ("%8.8X%8.8X\n", ACPI_FORMAT_UINT64 (Array[i])); + Offset += sizeof (UINT64); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpFadt + * + * PARAMETERS: Table - A FADT + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a FADT + * + * NOTE: We cannot depend on the FADT version to indicate the actual + * contents of the FADT because of BIOS bugs. The table length + * is the only reliable indicator. + * + ******************************************************************************/ + +void +AcpiDmDumpFadt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + + + /* Always dump the minimum FADT revision 1 fields (ACPI 1.0) */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, + AcpiDmTableInfoFadt1); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Check for FADT revision 2 fields (ACPI 1.0B MS extensions) */ + + if ((Table->Length > ACPI_FADT_V1_SIZE) && + (Table->Length <= ACPI_FADT_V2_SIZE)) + { + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, + AcpiDmTableInfoFadt2); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + /* Check for FADT revision 3/4 fields and up (ACPI 2.0+ extended data) */ + + else if (Table->Length > ACPI_FADT_V2_SIZE) + { + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, + AcpiDmTableInfoFadt3); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Check for FADT revision 5 fields and up (ACPI 5.0+) */ + + if (Table->Length > ACPI_FADT_V3_SIZE) + { + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, + AcpiDmTableInfoFadt5); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + /* Check for FADT revision 6 fields and up (ACPI 6.0+) */ + + if (Table->Length > ACPI_FADT_V3_SIZE) + { + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, + AcpiDmTableInfoFadt6); + if (ACPI_FAILURE (Status)) + { + return; + } + } + } + + /* Validate various fields in the FADT, including length */ + + AcpiTbCreateLocalFadt (Table, Table->Length); + + /* Validate FADT length against the revision */ + + AcpiDmValidateFadtLength (Table->Revision, Table->Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmValidateFadtLength + * + * PARAMETERS: Revision - FADT revision (Header->Revision) + * Length - FADT length (Header->Length + * + * RETURN: None + * + * DESCRIPTION: Check the FADT revision against the expected table length for + * that revision. Issue a warning if the length is not what was + * expected. This seems to be such a common BIOS bug that the + * FADT revision has been rendered virtually meaningless. + * + ******************************************************************************/ + +static void +AcpiDmValidateFadtLength ( + UINT32 Revision, + UINT32 Length) +{ + UINT32 ExpectedLength; + + + switch (Revision) + { + case 0: + + AcpiOsPrintf ("// ACPI Warning: Invalid FADT revision: 0\n"); + return; + + case 1: + + ExpectedLength = ACPI_FADT_V1_SIZE; + break; + + case 2: + + ExpectedLength = ACPI_FADT_V2_SIZE; + break; + + case 3: + case 4: + + ExpectedLength = ACPI_FADT_V3_SIZE; + break; + + case 5: + + ExpectedLength = ACPI_FADT_V5_SIZE; + break; + + default: + + return; + } + + if (Length == ExpectedLength) + { + return; + } + + AcpiOsPrintf ( + "\n// ACPI Warning: FADT revision %X does not match length: " + "found %X expected %X\n", + Revision, Length, ExpectedLength); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpAsf + * + * PARAMETERS: Table - A ASF table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a ASF table + * + ******************************************************************************/ + +void +AcpiDmDumpAsf ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_HEADER); + ACPI_ASF_INFO *SubTable; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_DMTABLE_INFO *DataInfoTable = NULL; + UINT8 *DataTable = NULL; + UINT32 DataCount = 0; + UINT32 DataLength = 0; + UINT32 DataOffset = 0; + UINT32 i; + UINT8 Type; + + + /* No main table, only subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_ASF_INFO, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Header.Length, AcpiDmTableInfoAsfHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* The actual type is the lower 7 bits of Type */ + + Type = (UINT8) (SubTable->Header.Type & 0x7F); + + switch (Type) + { + case ACPI_ASF_TYPE_INFO: + + InfoTable = AcpiDmTableInfoAsf0; + break; + + case ACPI_ASF_TYPE_ALERT: + + InfoTable = AcpiDmTableInfoAsf1; + DataInfoTable = AcpiDmTableInfoAsf1a; + DataTable = ACPI_ADD_PTR (UINT8, SubTable, sizeof (ACPI_ASF_ALERT)); + DataCount = ACPI_CAST_PTR (ACPI_ASF_ALERT, SubTable)->Alerts; + DataLength = ACPI_CAST_PTR (ACPI_ASF_ALERT, SubTable)->DataLength; + DataOffset = Offset + sizeof (ACPI_ASF_ALERT); + break; + + case ACPI_ASF_TYPE_CONTROL: + + InfoTable = AcpiDmTableInfoAsf2; + DataInfoTable = AcpiDmTableInfoAsf2a; + DataTable = ACPI_ADD_PTR (UINT8, SubTable, sizeof (ACPI_ASF_REMOTE)); + DataCount = ACPI_CAST_PTR (ACPI_ASF_REMOTE, SubTable)->Controls; + DataLength = ACPI_CAST_PTR (ACPI_ASF_REMOTE, SubTable)->DataLength; + DataOffset = Offset + sizeof (ACPI_ASF_REMOTE); + break; + + case ACPI_ASF_TYPE_BOOT: + + InfoTable = AcpiDmTableInfoAsf3; + break; + + case ACPI_ASF_TYPE_ADDRESS: + + InfoTable = AcpiDmTableInfoAsf4; + DataTable = ACPI_ADD_PTR (UINT8, SubTable, sizeof (ACPI_ASF_ADDRESS)); + DataLength = ACPI_CAST_PTR (ACPI_ASF_ADDRESS, SubTable)->Devices; + DataOffset = Offset + sizeof (ACPI_ASF_ADDRESS); + break; + + default: + + AcpiOsPrintf ("\n**** Unknown ASF subtable type 0x%X\n", + SubTable->Header.Type); + return; + } + + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Header.Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Dump variable-length extra data */ + + switch (Type) + { + case ACPI_ASF_TYPE_ALERT: + case ACPI_ASF_TYPE_CONTROL: + + for (i = 0; i < DataCount; i++) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, DataOffset, + DataTable, DataLength, DataInfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + DataTable = ACPI_ADD_PTR (UINT8, DataTable, DataLength); + DataOffset += DataLength; + } + break; + + case ACPI_ASF_TYPE_ADDRESS: + + for (i = 0; i < DataLength; i++) + { + if (!(i % 16)) + { + AcpiDmLineHeader (DataOffset, 1, "Addresses"); + } + + AcpiOsPrintf ("%2.2X ", *DataTable); + DataTable++; + DataOffset++; + + if (DataOffset > Table->Length) + { + AcpiOsPrintf ( + "**** ACPI table terminates in the middle of a " + "data structure! (ASF! table)\n"); + return; + } + } + + AcpiOsPrintf ("\n"); + break; + + default: + + break; + } + + AcpiOsPrintf ("\n"); + + /* Point to next subtable */ + + if (!SubTable->Header.Length) + { + AcpiOsPrintf ("Invalid zero subtable header length\n"); + return; + } + + Offset += SubTable->Header.Length; + SubTable = ACPI_ADD_PTR (ACPI_ASF_INFO, SubTable, + SubTable->Header.Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpCpep + * + * PARAMETERS: Table - A CPEP table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a CPEP. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpCpep ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_CPEP_POLLING *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_CPEP); + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoCpep); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_CPEP_POLLING, Table, Offset); + while (Offset < Table->Length) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Header.Length, AcpiDmTableInfoCpep0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable */ + + Offset += SubTable->Header.Length; + SubTable = ACPI_ADD_PTR (ACPI_CPEP_POLLING, SubTable, + SubTable->Header.Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpCsrt + * + * PARAMETERS: Table - A CSRT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a CSRT. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpCsrt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_CSRT_GROUP *SubTable; + ACPI_CSRT_SHARED_INFO *SharedInfoTable; + ACPI_CSRT_DESCRIPTOR *SubSubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_CSRT); + UINT32 SubOffset; + UINT32 SubSubOffset; + UINT32 InfoLength; + + + /* The main table only contains the ACPI header, thus already handled */ + + /* Subtables (Resource Groups) */ + + SubTable = ACPI_ADD_PTR (ACPI_CSRT_GROUP, Table, Offset); + while (Offset < Table->Length) + { + /* Resource group subtable */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoCsrt0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Shared info subtable (One per resource group) */ + + SubOffset = sizeof (ACPI_CSRT_GROUP); + SharedInfoTable = ACPI_ADD_PTR (ACPI_CSRT_SHARED_INFO, Table, + Offset + SubOffset); + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset + SubOffset, SharedInfoTable, + sizeof (ACPI_CSRT_SHARED_INFO), AcpiDmTableInfoCsrt1); + if (ACPI_FAILURE (Status)) + { + return; + } + + SubOffset += SubTable->SharedInfoLength; + + /* Sub-Subtables (Resource Descriptors) */ + + SubSubTable = ACPI_ADD_PTR (ACPI_CSRT_DESCRIPTOR, Table, + Offset + SubOffset); + + while ((SubOffset < SubTable->Length) && + ((Offset + SubOffset) < Table->Length)) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset + SubOffset, SubSubTable, + SubSubTable->Length, AcpiDmTableInfoCsrt2); + if (ACPI_FAILURE (Status)) + { + return; + } + + SubSubOffset = sizeof (ACPI_CSRT_DESCRIPTOR); + + /* Resource-specific info buffer */ + + InfoLength = SubSubTable->Length - SubSubOffset; + if (InfoLength) + { + Status = AcpiDmDumpTable (Length, + Offset + SubOffset + SubSubOffset, Table, + InfoLength, AcpiDmTableInfoCsrt2a); + if (ACPI_FAILURE (Status)) + { + return; + } + SubSubOffset += InfoLength; + } + + /* Point to next sub-subtable */ + + SubOffset += SubSubTable->Length; + SubSubTable = ACPI_ADD_PTR (ACPI_CSRT_DESCRIPTOR, SubSubTable, + SubSubTable->Length); + } + + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_CSRT_GROUP, SubTable, + SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpDbg2 + * + * PARAMETERS: Table - A DBG2 table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a DBG2. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpDbg2 ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_DBG2_DEVICE *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_DBG2); + UINT32 i; + UINT32 ArrayOffset; + UINT32 AbsoluteOffset; + UINT8 *Array; + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoDbg2); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_DBG2_DEVICE, Table, Offset); + while (Offset < Table->Length) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoDbg2Device); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Dump the BaseAddress array */ + + for (i = 0; i < SubTable->RegisterCount; i++) + { + ArrayOffset = SubTable->BaseAddressOffset + + (sizeof (ACPI_GENERIC_ADDRESS) * i); + AbsoluteOffset = Offset + ArrayOffset; + Array = (UINT8 *) SubTable + ArrayOffset; + + Status = AcpiDmDumpTable (Length, AbsoluteOffset, Array, + SubTable->Length, AcpiDmTableInfoDbg2Addr); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + /* Dump the AddressSize array */ + + for (i = 0; i < SubTable->RegisterCount; i++) + { + ArrayOffset = SubTable->AddressSizeOffset + + (sizeof (UINT32) * i); + AbsoluteOffset = Offset + ArrayOffset; + Array = (UINT8 *) SubTable + ArrayOffset; + + Status = AcpiDmDumpTable (Length, AbsoluteOffset, Array, + SubTable->Length, AcpiDmTableInfoDbg2Size); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + /* Dump the Namestring (required) */ + + AcpiOsPrintf ("\n"); + ArrayOffset = SubTable->NamepathOffset; + AbsoluteOffset = Offset + ArrayOffset; + Array = (UINT8 *) SubTable + ArrayOffset; + + Status = AcpiDmDumpTable (Length, AbsoluteOffset, Array, + SubTable->Length, AcpiDmTableInfoDbg2Name); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Dump the OemData (optional) */ + + if (SubTable->OemDataOffset) + { + Status = AcpiDmDumpTable (Length, Offset + SubTable->OemDataOffset, + Table, SubTable->OemDataLength, + AcpiDmTableInfoDbg2OemData); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_DBG2_DEVICE, SubTable, + SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpDmar + * + * PARAMETERS: Table - A DMAR table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a DMAR. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpDmar ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_DMAR_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_DMAR); + ACPI_DMTABLE_INFO *InfoTable; + ACPI_DMAR_DEVICE_SCOPE *ScopeTable; + UINT32 ScopeOffset; + UINT8 *PciPath; + UINT32 PathOffset; + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoDmar); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_DMAR_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoDmarHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + AcpiOsPrintf ("\n"); + + switch (SubTable->Type) + { + case ACPI_DMAR_TYPE_HARDWARE_UNIT: + + InfoTable = AcpiDmTableInfoDmar0; + ScopeOffset = sizeof (ACPI_DMAR_HARDWARE_UNIT); + break; + + case ACPI_DMAR_TYPE_RESERVED_MEMORY: + + InfoTable = AcpiDmTableInfoDmar1; + ScopeOffset = sizeof (ACPI_DMAR_RESERVED_MEMORY); + break; + + case ACPI_DMAR_TYPE_ROOT_ATS: + + InfoTable = AcpiDmTableInfoDmar2; + ScopeOffset = sizeof (ACPI_DMAR_ATSR); + break; + + case ACPI_DMAR_TYPE_HARDWARE_AFFINITY: + + InfoTable = AcpiDmTableInfoDmar3; + ScopeOffset = sizeof (ACPI_DMAR_RHSA); + break; + + case ACPI_DMAR_TYPE_NAMESPACE: + + InfoTable = AcpiDmTableInfoDmar4; + ScopeOffset = sizeof (ACPI_DMAR_ANDD); + break; + + default: + + AcpiOsPrintf ("\n**** Unknown DMAR subtable type 0x%X\n\n", + SubTable->Type); + return; + } + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* + * Dump the optional device scope entries + */ + if ((SubTable->Type == ACPI_DMAR_TYPE_HARDWARE_AFFINITY) || + (SubTable->Type == ACPI_DMAR_TYPE_NAMESPACE)) + { + /* These types do not support device scopes */ + + goto NextSubtable; + } + + ScopeTable = ACPI_ADD_PTR (ACPI_DMAR_DEVICE_SCOPE, SubTable, ScopeOffset); + while (ScopeOffset < SubTable->Length) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset + ScopeOffset, ScopeTable, + ScopeTable->Length, AcpiDmTableInfoDmarScope); + if (ACPI_FAILURE (Status)) + { + return; + } + AcpiOsPrintf ("\n"); + + /* Dump the PCI Path entries for this device scope */ + + PathOffset = sizeof (ACPI_DMAR_DEVICE_SCOPE); /* Path entries start at this offset */ + + PciPath = ACPI_ADD_PTR (UINT8, ScopeTable, + sizeof (ACPI_DMAR_DEVICE_SCOPE)); + + while (PathOffset < ScopeTable->Length) + { + AcpiDmLineHeader ((PathOffset + ScopeOffset + Offset), 2, + "PCI Path"); + AcpiOsPrintf ("%2.2X,%2.2X\n", PciPath[0], PciPath[1]); + + /* Point to next PCI Path entry */ + + PathOffset += 2; + PciPath += 2; + AcpiOsPrintf ("\n"); + } + + /* Point to next device scope entry */ + + ScopeOffset += ScopeTable->Length; + ScopeTable = ACPI_ADD_PTR (ACPI_DMAR_DEVICE_SCOPE, + ScopeTable, ScopeTable->Length); + } + +NextSubtable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_DMAR_HEADER, SubTable, + SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpDrtm + * + * PARAMETERS: Table - A DRTM table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a DRTM. + * + ******************************************************************************/ + +void +AcpiDmDumpDrtm ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset; + ACPI_DRTM_VTABLE_LIST *DrtmVtl; + ACPI_DRTM_RESOURCE_LIST *DrtmRl; + ACPI_DRTM_DPS_ID *DrtmDps; + UINT32 Count; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, + AcpiDmTableInfoDrtm); + if (ACPI_FAILURE (Status)) + { + return; + } + + Offset = sizeof (ACPI_TABLE_DRTM); + + /* Sub-tables */ + + /* Dump ValidatedTable length */ + + DrtmVtl = ACPI_ADD_PTR (ACPI_DRTM_VTABLE_LIST, Table, Offset); + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, + DrtmVtl, ACPI_OFFSET (ACPI_DRTM_VTABLE_LIST, ValidatedTables), + AcpiDmTableInfoDrtm0); + if (ACPI_FAILURE (Status)) + { + return; + } + + Offset += ACPI_OFFSET (ACPI_DRTM_VTABLE_LIST, ValidatedTables); + + /* Dump Validated table addresses */ + + Count = 0; + while ((Offset < Table->Length) && + (DrtmVtl->ValidatedTableCount > Count)) + { + Status = AcpiDmDumpTable (Table->Length, Offset, + ACPI_ADD_PTR (void, Table, Offset), sizeof (UINT64), + AcpiDmTableInfoDrtm0a); + if (ACPI_FAILURE (Status)) + { + return; + } + + Offset += sizeof (UINT64); + Count++; + } + + /* Dump ResourceList length */ + + DrtmRl = ACPI_ADD_PTR (ACPI_DRTM_RESOURCE_LIST, Table, Offset); + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, + DrtmRl, ACPI_OFFSET (ACPI_DRTM_RESOURCE_LIST, Resources), + AcpiDmTableInfoDrtm1); + if (ACPI_FAILURE (Status)) + { + return; + } + + Offset += ACPI_OFFSET (ACPI_DRTM_RESOURCE_LIST, Resources); + + /* Dump the Resource List */ + + Count = 0; + while ((Offset < Table->Length) && + (DrtmRl->ResourceCount > Count)) + { + Status = AcpiDmDumpTable (Table->Length, Offset, + ACPI_ADD_PTR (void, Table, Offset), + sizeof (ACPI_DRTM_RESOURCE), AcpiDmTableInfoDrtm1a); + if (ACPI_FAILURE (Status)) + { + return; + } + + Offset += sizeof (ACPI_DRTM_RESOURCE); + Count++; + } + + /* Dump DPS */ + + DrtmDps = ACPI_ADD_PTR (ACPI_DRTM_DPS_ID, Table, Offset); + AcpiOsPrintf ("\n"); + (void) AcpiDmDumpTable (Table->Length, Offset, + DrtmDps, sizeof (ACPI_DRTM_DPS_ID), AcpiDmTableInfoDrtm2); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpEinj + * + * PARAMETERS: Table - A EINJ table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a EINJ. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpEinj ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_WHEA_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_EINJ); + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoEinj); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_WHEA_HEADER, Table, Offset); + while (Offset < Table->Length) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + sizeof (ACPI_WHEA_HEADER), AcpiDmTableInfoEinj0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable (each subtable is of fixed length) */ + + Offset += sizeof (ACPI_WHEA_HEADER); + SubTable = ACPI_ADD_PTR (ACPI_WHEA_HEADER, SubTable, + sizeof (ACPI_WHEA_HEADER)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpErst + * + * PARAMETERS: Table - A ERST table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a ERST. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpErst ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_WHEA_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_ERST); + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoErst); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_WHEA_HEADER, Table, Offset); + while (Offset < Table->Length) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + sizeof (ACPI_WHEA_HEADER), AcpiDmTableInfoErst0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable (each subtable is of fixed length) */ + + Offset += sizeof (ACPI_WHEA_HEADER); + SubTable = ACPI_ADD_PTR (ACPI_WHEA_HEADER, SubTable, + sizeof (ACPI_WHEA_HEADER)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpFpdt + * + * PARAMETERS: Table - A FPDT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a FPDT. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpFpdt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_FPDT_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_FPDT); + ACPI_DMTABLE_INFO *InfoTable; + + + /* There is no main table (other than the standard ACPI header) */ + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_FPDT_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoFpdtHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Type) + { + case ACPI_FPDT_TYPE_BOOT: + + InfoTable = AcpiDmTableInfoFpdt0; + break; + + case ACPI_FPDT_TYPE_S3PERF: + + InfoTable = AcpiDmTableInfoFpdt1; + break; + + default: + + AcpiOsPrintf ("\n**** Unknown FPDT subtable type 0x%X\n\n", + SubTable->Type); + + /* Attempt to continue */ + + if (!SubTable->Length) + { + AcpiOsPrintf ("Invalid zero length subtable\n"); + return; + } + goto NextSubTable; + } + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + +NextSubTable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_FPDT_HEADER, SubTable, + SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpGtdt + * + * PARAMETERS: Table - A GTDT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a GTDT. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpGtdt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_GTDT_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_GTDT); + ACPI_DMTABLE_INFO *InfoTable; + UINT32 SubTableLength; + UINT32 GtCount; + ACPI_GTDT_TIMER_ENTRY *GtxTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoGtdt); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_GTDT_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoGtdtHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + GtCount = 0; + switch (SubTable->Type) + { + case ACPI_GTDT_TYPE_TIMER_BLOCK: + + SubTableLength = sizeof (ACPI_GTDT_TIMER_BLOCK); + GtCount = (ACPI_CAST_PTR (ACPI_GTDT_TIMER_BLOCK, + SubTable))->TimerCount; + + InfoTable = AcpiDmTableInfoGtdt0; + break; + + case ACPI_GTDT_TYPE_WATCHDOG: + + SubTableLength = sizeof (ACPI_GTDT_WATCHDOG); + + InfoTable = AcpiDmTableInfoGtdt1; + break; + + default: + + /* Cannot continue on unknown type - no length */ + + AcpiOsPrintf ("\n**** Unknown GTDT subtable type 0x%X\n", + SubTable->Type); + return; + } + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to end of current subtable (each subtable above is of fixed length) */ + + Offset += SubTableLength; + + /* If there are any Gt Timer Blocks from above, dump them now */ + + if (GtCount) + { + GtxTable = ACPI_ADD_PTR ( + ACPI_GTDT_TIMER_ENTRY, SubTable, SubTableLength); + SubTableLength += GtCount * sizeof (ACPI_GTDT_TIMER_ENTRY); + + while (GtCount) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, GtxTable, + sizeof (ACPI_GTDT_TIMER_ENTRY), AcpiDmTableInfoGtdt0a); + if (ACPI_FAILURE (Status)) + { + return; + } + Offset += sizeof (ACPI_GTDT_TIMER_ENTRY); + GtxTable++; + GtCount--; + } + } + + /* Point to next subtable */ + + SubTable = ACPI_ADD_PTR (ACPI_GTDT_HEADER, SubTable, SubTableLength); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpHest + * + * PARAMETERS: Table - A HEST table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a HEST. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpHest ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_HEST_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_HEST); + ACPI_DMTABLE_INFO *InfoTable; + UINT32 SubTableLength; + UINT32 BankCount; + ACPI_HEST_IA_ERROR_BANK *BankTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoHest); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_HEST_HEADER, Table, Offset); + while (Offset < Table->Length) + { + BankCount = 0; + switch (SubTable->Type) + { + case ACPI_HEST_TYPE_IA32_CHECK: + + InfoTable = AcpiDmTableInfoHest0; + SubTableLength = sizeof (ACPI_HEST_IA_MACHINE_CHECK); + BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_MACHINE_CHECK, + SubTable))->NumHardwareBanks; + break; + + case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: + + InfoTable = AcpiDmTableInfoHest1; + SubTableLength = sizeof (ACPI_HEST_IA_CORRECTED); + BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_CORRECTED, + SubTable))->NumHardwareBanks; + break; + + case ACPI_HEST_TYPE_IA32_NMI: + + InfoTable = AcpiDmTableInfoHest2; + SubTableLength = sizeof (ACPI_HEST_IA_NMI); + break; + + case ACPI_HEST_TYPE_AER_ROOT_PORT: + + InfoTable = AcpiDmTableInfoHest6; + SubTableLength = sizeof (ACPI_HEST_AER_ROOT); + break; + + case ACPI_HEST_TYPE_AER_ENDPOINT: + + InfoTable = AcpiDmTableInfoHest7; + SubTableLength = sizeof (ACPI_HEST_AER); + break; + + case ACPI_HEST_TYPE_AER_BRIDGE: + + InfoTable = AcpiDmTableInfoHest8; + SubTableLength = sizeof (ACPI_HEST_AER_BRIDGE); + break; + + case ACPI_HEST_TYPE_GENERIC_ERROR: + + InfoTable = AcpiDmTableInfoHest9; + SubTableLength = sizeof (ACPI_HEST_GENERIC); + break; + + default: + + /* Cannot continue on unknown type - no length */ + + AcpiOsPrintf ("\n**** Unknown HEST subtable type 0x%X\n", + SubTable->Type); + return; + } + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTableLength, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to end of current subtable (each subtable above is of fixed length) */ + + Offset += SubTableLength; + + /* If there are any (fixed-length) Error Banks from above, dump them now */ + + if (BankCount) + { + BankTable = ACPI_ADD_PTR (ACPI_HEST_IA_ERROR_BANK, SubTable, + SubTableLength); + SubTableLength += BankCount * sizeof (ACPI_HEST_IA_ERROR_BANK); + + while (BankCount) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, BankTable, + sizeof (ACPI_HEST_IA_ERROR_BANK), AcpiDmTableInfoHestBank); + if (ACPI_FAILURE (Status)) + { + return; + } + + Offset += sizeof (ACPI_HEST_IA_ERROR_BANK); + BankTable++; + BankCount--; + } + } + + /* Point to next subtable */ + + SubTable = ACPI_ADD_PTR (ACPI_HEST_HEADER, SubTable, SubTableLength); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpIort + * + * PARAMETERS: Table - A IORT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a IORT + * + ******************************************************************************/ + +void +AcpiDmDumpIort ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_TABLE_IORT *Iort; + ACPI_IORT_NODE *IortNode; + ACPI_IORT_ITS_GROUP *IortItsGroup = NULL; + ACPI_IORT_SMMU *IortSmmu = NULL; + UINT32 Offset; + UINT32 NodeOffset; + UINT32 Length; + ACPI_DMTABLE_INFO *InfoTable; + char *String; + UINT32 i; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoIort); + if (ACPI_FAILURE (Status)) + { + return; + } + + Iort = ACPI_CAST_PTR (ACPI_TABLE_IORT, Table); + Offset = sizeof (ACPI_TABLE_IORT); + + /* Dump the OptionalPadding (optional) */ + + if (Iort->NodeOffset > Offset) + { + Status = AcpiDmDumpTable (Table->Length, Offset, Table, + Iort->NodeOffset - Offset, AcpiDmTableInfoIortPad); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + Offset = Iort->NodeOffset; + while (Offset < Table->Length) + { + /* Common subtable header */ + + IortNode = ACPI_ADD_PTR (ACPI_IORT_NODE, Table, Offset); + AcpiOsPrintf ("\n"); + Length = ACPI_OFFSET (ACPI_IORT_NODE, NodeData); + Status = AcpiDmDumpTable (Table->Length, Offset, + IortNode, Length, AcpiDmTableInfoIortHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + NodeOffset = Length; + + switch (IortNode->Type) + { + case ACPI_IORT_NODE_ITS_GROUP: + + InfoTable = AcpiDmTableInfoIort0; + Length = ACPI_OFFSET (ACPI_IORT_ITS_GROUP, Identifiers); + IortItsGroup = ACPI_ADD_PTR (ACPI_IORT_ITS_GROUP, IortNode, NodeOffset); + break; + + case ACPI_IORT_NODE_NAMED_COMPONENT: + + InfoTable = AcpiDmTableInfoIort1; + Length = ACPI_OFFSET (ACPI_IORT_NAMED_COMPONENT, DeviceName); + String = ACPI_ADD_PTR (char, IortNode, NodeOffset + Length); + Length += strlen (String) + 1; + break; + + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX: + + InfoTable = AcpiDmTableInfoIort2; + Length = IortNode->Length - NodeOffset; + break; + + case ACPI_IORT_NODE_SMMU: + + InfoTable = AcpiDmTableInfoIort3; + Length = ACPI_OFFSET (ACPI_IORT_SMMU, Interrupts); + IortSmmu = ACPI_ADD_PTR (ACPI_IORT_SMMU, IortNode, NodeOffset); + break; + + default: + + AcpiOsPrintf ("\n**** Unknown IORT node type 0x%X\n", + IortNode->Type); + + /* Attempt to continue */ + + if (!IortNode->Length) + { + AcpiOsPrintf ("Invalid zero length IORT node\n"); + return; + } + goto NextSubTable; + } + + /* Dump the node subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, NodeOffset), + Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + NodeOffset += Length; + + /* Dump the node specific data */ + + switch (IortNode->Type) + { + case ACPI_IORT_NODE_ITS_GROUP: + + /* Validate IortItsGroup to avoid compiler warnings */ + + if (IortItsGroup) + { + for (i = 0; i < IortItsGroup->ItsCount; i++) + { + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, NodeOffset), + 4, AcpiDmTableInfoIort0a); + NodeOffset += 4; + } + } + break; + + case ACPI_IORT_NODE_NAMED_COMPONENT: + + /* Dump the Padding (optional) */ + + if (IortNode->Length > NodeOffset) + { + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + Table, IortNode->Length - NodeOffset, + AcpiDmTableInfoIort1a); + if (ACPI_FAILURE (Status)) + { + return; + } + } + break; + + case ACPI_IORT_NODE_SMMU: + + AcpiOsPrintf ("\n"); + + /* Validate IortSmmu to avoid compiler warnings */ + + if (IortSmmu) + { + Length = 2 * sizeof (UINT64); + NodeOffset = IortSmmu->GlobalInterruptOffset; + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, NodeOffset), + Length, AcpiDmTableInfoIort3a); + if (ACPI_FAILURE (Status)) + { + return; + } + + NodeOffset = IortSmmu->ContextInterruptOffset; + for (i = 0; i < IortSmmu->ContextInterruptCount; i++) + { + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, NodeOffset), + 8, AcpiDmTableInfoIort3b); + if (ACPI_FAILURE (Status)) + { + return; + } + + NodeOffset += 8; + } + + NodeOffset = IortSmmu->PmuInterruptOffset; + for (i = 0; i < IortSmmu->PmuInterruptCount; i++) + { + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, NodeOffset), + 8, AcpiDmTableInfoIort3c); + if (ACPI_FAILURE (Status)) + { + return; + } + + NodeOffset += 8; + } + } + break; + + default: + + break; + } + + /* Dump the ID mappings */ + + NodeOffset = IortNode->MappingOffset; + for (i = 0; i < IortNode->MappingCount; i++) + { + AcpiOsPrintf ("\n"); + Length = sizeof (ACPI_IORT_ID_MAPPING); + Status = AcpiDmDumpTable (Table->Length, Offset + NodeOffset, + ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, NodeOffset), + Length, AcpiDmTableInfoIortMap); + if (ACPI_FAILURE (Status)) + { + return; + } + + NodeOffset += Length; + } + +NextSubTable: + /* Point to next node subtable */ + + Offset += IortNode->Length; + IortNode = ACPI_ADD_PTR (ACPI_IORT_NODE, IortNode, IortNode->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpIvrs + * + * PARAMETERS: Table - A IVRS table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a IVRS + * + ******************************************************************************/ + +static UINT8 EntrySizes[] = {4,8,16,32}; + +void +AcpiDmDumpIvrs ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_IVRS); + UINT32 EntryOffset; + UINT32 EntryLength; + UINT32 EntryType; + ACPI_IVRS_DE_HEADER *DeviceEntry; + ACPI_IVRS_HEADER *SubTable; + ACPI_DMTABLE_INFO *InfoTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoIvrs); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_IVRS_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoIvrsHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Type) + { + case ACPI_IVRS_TYPE_HARDWARE: + + InfoTable = AcpiDmTableInfoIvrs0; + break; + + case ACPI_IVRS_TYPE_MEMORY1: + case ACPI_IVRS_TYPE_MEMORY2: + case ACPI_IVRS_TYPE_MEMORY3: + + InfoTable = AcpiDmTableInfoIvrs1; + break; + + default: + + AcpiOsPrintf ("\n**** Unknown IVRS subtable type 0x%X\n", + SubTable->Type); + + /* Attempt to continue */ + + if (!SubTable->Length) + { + AcpiOsPrintf ("Invalid zero length subtable\n"); + return; + } + goto NextSubTable; + } + + /* Dump the subtable */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* The hardware subtable can contain multiple device entries */ + + if (SubTable->Type == ACPI_IVRS_TYPE_HARDWARE) + { + EntryOffset = Offset + sizeof (ACPI_IVRS_HARDWARE); + DeviceEntry = ACPI_ADD_PTR (ACPI_IVRS_DE_HEADER, SubTable, + sizeof (ACPI_IVRS_HARDWARE)); + + while (EntryOffset < (Offset + SubTable->Length)) + { + AcpiOsPrintf ("\n"); + /* + * Upper 2 bits of Type encode the length of the device entry + * + * 00 = 4 byte + * 01 = 8 byte + * 10 = 16 byte - currently no entries defined + * 11 = 32 byte - currently no entries defined + */ + EntryType = DeviceEntry->Type; + EntryLength = EntrySizes [EntryType >> 6]; + + switch (EntryType) + { + /* 4-byte device entries */ + + case ACPI_IVRS_TYPE_PAD4: + case ACPI_IVRS_TYPE_ALL: + case ACPI_IVRS_TYPE_SELECT: + case ACPI_IVRS_TYPE_START: + case ACPI_IVRS_TYPE_END: + + InfoTable = AcpiDmTableInfoIvrs4; + break; + + /* 8-byte entries, type A */ + + case ACPI_IVRS_TYPE_ALIAS_SELECT: + case ACPI_IVRS_TYPE_ALIAS_START: + + InfoTable = AcpiDmTableInfoIvrs8a; + break; + + /* 8-byte entries, type B */ + + case ACPI_IVRS_TYPE_PAD8: + case ACPI_IVRS_TYPE_EXT_SELECT: + case ACPI_IVRS_TYPE_EXT_START: + + InfoTable = AcpiDmTableInfoIvrs8b; + break; + + /* 8-byte entries, type C */ + + case ACPI_IVRS_TYPE_SPECIAL: + + InfoTable = AcpiDmTableInfoIvrs8c; + break; + + default: + InfoTable = AcpiDmTableInfoIvrs4; + AcpiOsPrintf ( + "\n**** Unknown IVRS device entry type/length: " + "0x%.2X/0x%X at offset 0x%.4X: (header below)\n", + EntryType, EntryLength, EntryOffset); + break; + } + + /* Dump the Device Entry */ + + Status = AcpiDmDumpTable (Table->Length, EntryOffset, + DeviceEntry, EntryLength, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + EntryOffset += EntryLength; + DeviceEntry = ACPI_ADD_PTR (ACPI_IVRS_DE_HEADER, DeviceEntry, + EntryLength); + } + } + +NextSubTable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_IVRS_HEADER, SubTable, SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpLpit + * + * PARAMETERS: Table - A LPIT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a LPIT. This table type consists + * of an open-ended number of subtables. Note: There are no + * entries in the main table. An LPIT consists of the table + * header and then subtables only. + * + ******************************************************************************/ + +void +AcpiDmDumpLpit ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_LPIT_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_LPIT); + ACPI_DMTABLE_INFO *InfoTable; + UINT32 SubTableLength; + + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_LPIT_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + sizeof (ACPI_LPIT_HEADER), AcpiDmTableInfoLpitHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Type) + { + case ACPI_LPIT_TYPE_NATIVE_CSTATE: + + InfoTable = AcpiDmTableInfoLpit0; + SubTableLength = sizeof (ACPI_LPIT_NATIVE); + break; + + default: + + /* Cannot continue on unknown type - no length */ + + AcpiOsPrintf ("\n**** Unknown LPIT subtable type 0x%X\n", + SubTable->Type); + return; + } + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTableLength, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + AcpiOsPrintf ("\n"); + + /* Point to next subtable */ + + Offset += SubTableLength; + SubTable = ACPI_ADD_PTR (ACPI_LPIT_HEADER, SubTable, SubTableLength); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpMadt + * + * PARAMETERS: Table - A MADT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a MADT. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpMadt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_SUBTABLE_HEADER *SubTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_MADT); + ACPI_DMTABLE_INFO *InfoTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoMadt); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_SUBTABLE_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoMadtHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Type) + { + case ACPI_MADT_TYPE_LOCAL_APIC: + + InfoTable = AcpiDmTableInfoMadt0; + break; + + case ACPI_MADT_TYPE_IO_APIC: + + InfoTable = AcpiDmTableInfoMadt1; + break; + + case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: + + InfoTable = AcpiDmTableInfoMadt2; + break; + + case ACPI_MADT_TYPE_NMI_SOURCE: + + InfoTable = AcpiDmTableInfoMadt3; + break; + + case ACPI_MADT_TYPE_LOCAL_APIC_NMI: + + InfoTable = AcpiDmTableInfoMadt4; + break; + + case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: + + InfoTable = AcpiDmTableInfoMadt5; + break; + + case ACPI_MADT_TYPE_IO_SAPIC: + + InfoTable = AcpiDmTableInfoMadt6; + break; + + case ACPI_MADT_TYPE_LOCAL_SAPIC: + + InfoTable = AcpiDmTableInfoMadt7; + break; + + case ACPI_MADT_TYPE_INTERRUPT_SOURCE: + + InfoTable = AcpiDmTableInfoMadt8; + break; + + case ACPI_MADT_TYPE_LOCAL_X2APIC: + + InfoTable = AcpiDmTableInfoMadt9; + break; + + case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: + + InfoTable = AcpiDmTableInfoMadt10; + break; + + case ACPI_MADT_TYPE_GENERIC_INTERRUPT: + + InfoTable = AcpiDmTableInfoMadt11; + break; + + case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: + + InfoTable = AcpiDmTableInfoMadt12; + break; + + case ACPI_MADT_TYPE_GENERIC_MSI_FRAME: + + InfoTable = AcpiDmTableInfoMadt13; + break; + + case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: + + InfoTable = AcpiDmTableInfoMadt14; + break; + + case ACPI_MADT_TYPE_GENERIC_TRANSLATOR: + + InfoTable = AcpiDmTableInfoMadt15; + break; + + default: + + AcpiOsPrintf ("\n**** Unknown MADT subtable type 0x%X\n\n", + SubTable->Type); + + /* Attempt to continue */ + + if (!SubTable->Length) + { + AcpiOsPrintf ("Invalid zero length subtable\n"); + return; + } + + goto NextSubTable; + } + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + +NextSubTable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_SUBTABLE_HEADER, SubTable, + SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpMcfg + * + * PARAMETERS: Table - A MCFG Table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a MCFG table + * + ******************************************************************************/ + +void +AcpiDmDumpMcfg ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_MCFG); + ACPI_MCFG_ALLOCATION *SubTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoMcfg); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_MCFG_ALLOCATION, Table, Offset); + while (Offset < Table->Length) + { + if (Offset + sizeof (ACPI_MCFG_ALLOCATION) > Table->Length) + { + AcpiOsPrintf ("Warning: there are %u invalid trailing bytes\n", + sizeof (ACPI_MCFG_ALLOCATION) - (Offset - Table->Length)); + return; + } + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + sizeof (ACPI_MCFG_ALLOCATION), AcpiDmTableInfoMcfg0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable (each subtable is of fixed length) */ + + Offset += sizeof (ACPI_MCFG_ALLOCATION); + SubTable = ACPI_ADD_PTR (ACPI_MCFG_ALLOCATION, SubTable, + sizeof (ACPI_MCFG_ALLOCATION)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpMpst + * + * PARAMETERS: Table - A MPST Table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a MPST table + * + ******************************************************************************/ + +void +AcpiDmDumpMpst ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_MPST); + ACPI_MPST_POWER_NODE *SubTable0; + ACPI_MPST_POWER_STATE *SubTable0A; + ACPI_MPST_COMPONENT *SubTable0B; + ACPI_MPST_DATA_HDR *SubTable1; + ACPI_MPST_POWER_DATA *SubTable2; + UINT16 SubtableCount; + UINT32 PowerStateCount; + UINT32 ComponentCount; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoMpst); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtable: Memory Power Node(s) */ + + SubtableCount = (ACPI_CAST_PTR (ACPI_TABLE_MPST, Table))->PowerNodeCount; + SubTable0 = ACPI_ADD_PTR (ACPI_MPST_POWER_NODE, Table, Offset); + + while ((Offset < Table->Length) && SubtableCount) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable0, + sizeof (ACPI_MPST_POWER_NODE), AcpiDmTableInfoMpst0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Extract the sub-subtable counts */ + + PowerStateCount = SubTable0->NumPowerStates; + ComponentCount = SubTable0->NumPhysicalComponents; + Offset += sizeof (ACPI_MPST_POWER_NODE); + + /* Sub-subtables - Memory Power State Structure(s) */ + + SubTable0A = ACPI_ADD_PTR (ACPI_MPST_POWER_STATE, SubTable0, + sizeof (ACPI_MPST_POWER_NODE)); + + while (PowerStateCount) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable0A, + sizeof (ACPI_MPST_POWER_STATE), AcpiDmTableInfoMpst0A); + if (ACPI_FAILURE (Status)) + { + return; + } + + SubTable0A++; + PowerStateCount--; + Offset += sizeof (ACPI_MPST_POWER_STATE); + } + + /* Sub-subtables - Physical Component ID Structure(s) */ + + SubTable0B = ACPI_CAST_PTR (ACPI_MPST_COMPONENT, SubTable0A); + + if (ComponentCount) + { + AcpiOsPrintf ("\n"); + } + + while (ComponentCount) + { + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable0B, + sizeof (ACPI_MPST_COMPONENT), AcpiDmTableInfoMpst0B); + if (ACPI_FAILURE (Status)) + { + return; + } + + SubTable0B++; + ComponentCount--; + Offset += sizeof (ACPI_MPST_COMPONENT); + } + + /* Point to next Memory Power Node subtable */ + + SubtableCount--; + SubTable0 = ACPI_ADD_PTR (ACPI_MPST_POWER_NODE, SubTable0, + sizeof (ACPI_MPST_POWER_NODE) + + (sizeof (ACPI_MPST_POWER_STATE) * SubTable0->NumPowerStates) + + (sizeof (ACPI_MPST_COMPONENT) * SubTable0->NumPhysicalComponents)); + } + + /* Subtable: Count of Memory Power State Characteristic structures */ + + AcpiOsPrintf ("\n"); + SubTable1 = ACPI_CAST_PTR (ACPI_MPST_DATA_HDR, SubTable0); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable1, + sizeof (ACPI_MPST_DATA_HDR), AcpiDmTableInfoMpst1); + if (ACPI_FAILURE (Status)) + { + return; + } + + SubtableCount = SubTable1->CharacteristicsCount; + Offset += sizeof (ACPI_MPST_DATA_HDR); + + /* Subtable: Memory Power State Characteristics structure(s) */ + + SubTable2 = ACPI_ADD_PTR (ACPI_MPST_POWER_DATA, SubTable1, + sizeof (ACPI_MPST_DATA_HDR)); + + while ((Offset < Table->Length) && SubtableCount) + { + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable2, + sizeof (ACPI_MPST_POWER_DATA), AcpiDmTableInfoMpst2); + if (ACPI_FAILURE (Status)) + { + return; + } + + SubTable2++; + SubtableCount--; + Offset += sizeof (ACPI_MPST_POWER_DATA); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpMsct + * + * PARAMETERS: Table - A MSCT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a MSCT + * + ******************************************************************************/ + +void +AcpiDmDumpMsct ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_MSCT); + ACPI_MSCT_PROXIMITY *SubTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoMsct); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_MSCT_PROXIMITY, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + sizeof (ACPI_MSCT_PROXIMITY), AcpiDmTableInfoMsct0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable */ + + Offset += sizeof (ACPI_MSCT_PROXIMITY); + SubTable = ACPI_ADD_PTR (ACPI_MSCT_PROXIMITY, SubTable, + sizeof (ACPI_MSCT_PROXIMITY)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpMtmr + * + * PARAMETERS: Table - A MTMR table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a MTMR + * + ******************************************************************************/ + +void +AcpiDmDumpMtmr ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_MTMR); + ACPI_MTMR_ENTRY *SubTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoMtmr); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_MTMR_ENTRY, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + sizeof (ACPI_MTMR_ENTRY), AcpiDmTableInfoMtmr0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable */ + + Offset += sizeof (ACPI_MTMR_ENTRY); + SubTable = ACPI_ADD_PTR (ACPI_MTMR_ENTRY, SubTable, + sizeof (ACPI_MTMR_ENTRY)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpNfit + * + * PARAMETERS: Table - A NFIT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of an NFIT. + * + ******************************************************************************/ + +void +AcpiDmDumpNfit ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_NFIT); + UINT32 FieldOffset = 0; + UINT32 Length; + ACPI_NFIT_HEADER *SubTable; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_NFIT_INTERLEAVE *Interleave = NULL; + ACPI_NFIT_SMBIOS *SmbiosInfo = NULL; + ACPI_NFIT_FLUSH_ADDRESS *Hint = NULL; + UINT32 i; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoNfit); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_NFIT_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* NFIT subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoNfitHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Type) + { + case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: + + InfoTable = AcpiDmTableInfoNfit0; + break; + + case ACPI_NFIT_TYPE_MEMORY_MAP: + + InfoTable = AcpiDmTableInfoNfit1; + break; + + case ACPI_NFIT_TYPE_INTERLEAVE: + + /* Has a variable number of 32-bit values at the end */ + + InfoTable = AcpiDmTableInfoNfit2; + Interleave = ACPI_CAST_PTR (ACPI_NFIT_INTERLEAVE, SubTable); + FieldOffset = sizeof (ACPI_NFIT_INTERLEAVE); + break; + + case ACPI_NFIT_TYPE_SMBIOS: + + SmbiosInfo = ACPI_CAST_PTR (ACPI_NFIT_SMBIOS, SubTable); + InfoTable = AcpiDmTableInfoNfit3; + break; + + case ACPI_NFIT_TYPE_CONTROL_REGION: + + InfoTable = AcpiDmTableInfoNfit4; + break; + + case ACPI_NFIT_TYPE_DATA_REGION: + + InfoTable = AcpiDmTableInfoNfit5; + break; + + case ACPI_NFIT_TYPE_FLUSH_ADDRESS: + + /* Has a variable number of 64-bit addresses at the end */ + + InfoTable = AcpiDmTableInfoNfit6; + Hint = ACPI_CAST_PTR (ACPI_NFIT_FLUSH_ADDRESS, SubTable); + FieldOffset = sizeof (ACPI_NFIT_FLUSH_ADDRESS) - sizeof (UINT64); + break; + + default: + AcpiOsPrintf ("\n**** Unknown NFIT subtable type 0x%X\n", + SubTable->Type); + + /* Attempt to continue */ + + if (!SubTable->Length) + { + AcpiOsPrintf ("Invalid zero length subtable\n"); + return; + } + goto NextSubTable; + } + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Per-subtable variable-length fields */ + + switch (SubTable->Type) + { + case ACPI_NFIT_TYPE_INTERLEAVE: + + for (i = 0; i < Interleave->LineCount; i++) + { + Status = AcpiDmDumpTable (Table->Length, Offset + FieldOffset, + &Interleave->LineOffset[i], + sizeof (UINT32), AcpiDmTableInfoNfit2a); + if (ACPI_FAILURE (Status)) + { + return; + } + + FieldOffset += sizeof (UINT32); + } + break; + + case ACPI_NFIT_TYPE_SMBIOS: + + Length = SubTable->Length - + sizeof (ACPI_NFIT_SMBIOS) + sizeof (UINT8); + + if (Length) + { + Status = AcpiDmDumpTable (Table->Length, + sizeof (ACPI_NFIT_SMBIOS) - sizeof (UINT8), + SmbiosInfo, + Length, AcpiDmTableInfoNfit3a); + if (ACPI_FAILURE (Status)) + { + return; + } + } + + break; + + case ACPI_NFIT_TYPE_FLUSH_ADDRESS: + + for (i = 0; i < Hint->HintCount; i++) + { + Status = AcpiDmDumpTable (Table->Length, Offset + FieldOffset, + &Hint->HintAddress[i], + sizeof (UINT64), AcpiDmTableInfoNfit6a); + if (ACPI_FAILURE (Status)) + { + return; + } + + FieldOffset += sizeof (UINT64); + } + break; + + default: + break; + } + +NextSubTable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_NFIT_HEADER, SubTable, SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpPcct + * + * PARAMETERS: Table - A PCCT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a PCCT. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpPcct ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_PCCT_SUBSPACE *SubTable; + ACPI_DMTABLE_INFO *InfoTable; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_PCCT); + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoPcct); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_PCCT_SUBSPACE, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Header.Length, AcpiDmTableInfoPcctHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Header.Type) + { + case ACPI_PCCT_TYPE_GENERIC_SUBSPACE: + + InfoTable = AcpiDmTableInfoPcct0; + break; + + case ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE: + + InfoTable = AcpiDmTableInfoPcct1; + break; + + default: + + AcpiOsPrintf ( + "\n**** Unexpected or unknown PCCT subtable type 0x%X\n\n", + SubTable->Header.Type); + return; + } + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Header.Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable */ + + Offset += SubTable->Header.Length; + SubTable = ACPI_ADD_PTR (ACPI_PCCT_SUBSPACE, SubTable, + SubTable->Header.Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpPmtt + * + * PARAMETERS: Table - A PMTT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a PMTT. This table type consists + * of an open-ended number of subtables. + * + ******************************************************************************/ + +void +AcpiDmDumpPmtt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_PMTT_HEADER *SubTable; + ACPI_PMTT_HEADER *MemSubTable; + ACPI_PMTT_HEADER *DimmSubTable; + ACPI_PMTT_DOMAIN *DomainArray; + UINT32 Length = Table->Length; + UINT32 Offset = sizeof (ACPI_TABLE_PMTT); + UINT32 MemOffset; + UINT32 DimmOffset; + UINT32 DomainOffset; + UINT32 DomainCount; + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoPmtt); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_PMTT_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoPmttHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Only Socket subtables are expected at this level */ + + if (SubTable->Type != ACPI_PMTT_TYPE_SOCKET) + { + AcpiOsPrintf ( + "\n**** Unexpected or unknown PMTT subtable type 0x%X\n\n", + SubTable->Type); + return; + } + + /* Dump the fixed-length portion of the subtable */ + + Status = AcpiDmDumpTable (Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoPmtt0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Walk the memory controller subtables */ + + MemOffset = sizeof (ACPI_PMTT_SOCKET); + MemSubTable = ACPI_ADD_PTR (ACPI_PMTT_HEADER, SubTable, + sizeof (ACPI_PMTT_SOCKET)); + + while (((Offset + MemOffset) < Table->Length) && + (MemOffset < SubTable->Length)) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, + Offset + MemOffset, MemSubTable, + MemSubTable->Length, AcpiDmTableInfoPmttHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Only memory controller subtables are expected at this level */ + + if (MemSubTable->Type != ACPI_PMTT_TYPE_CONTROLLER) + { + AcpiOsPrintf ( + "\n**** Unexpected or unknown PMTT subtable type 0x%X\n\n", + MemSubTable->Type); + return; + } + + /* Dump the fixed-length portion of the controller subtable */ + + Status = AcpiDmDumpTable (Length, + Offset + MemOffset, MemSubTable, + MemSubTable->Length, AcpiDmTableInfoPmtt1); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Walk the variable count of proximity domains */ + + DomainCount = ((ACPI_PMTT_CONTROLLER *) MemSubTable)->DomainCount; + DomainOffset = sizeof (ACPI_PMTT_CONTROLLER); + DomainArray = ACPI_ADD_PTR (ACPI_PMTT_DOMAIN, MemSubTable, + sizeof (ACPI_PMTT_CONTROLLER)); + + while (((Offset + MemOffset + DomainOffset) < Table->Length) && + ((MemOffset + DomainOffset) < SubTable->Length) && + DomainCount) + { + Status = AcpiDmDumpTable (Length, + Offset + MemOffset + DomainOffset, DomainArray, + sizeof (ACPI_PMTT_DOMAIN), AcpiDmTableInfoPmtt1a); + if (ACPI_FAILURE (Status)) + { + return; + } + + DomainOffset += sizeof (ACPI_PMTT_DOMAIN); + DomainArray++; + DomainCount--; + } + + if (DomainCount) + { + AcpiOsPrintf ( + "\n**** DomainCount exceeds subtable length\n\n"); + } + + /* Walk the physical component (DIMM) subtables */ + + DimmOffset = DomainOffset; + DimmSubTable = ACPI_ADD_PTR (ACPI_PMTT_HEADER, MemSubTable, + DomainOffset); + + while (((Offset + MemOffset + DimmOffset) < Table->Length) && + (DimmOffset < MemSubTable->Length)) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Length, + Offset + MemOffset + DimmOffset, DimmSubTable, + DimmSubTable->Length, AcpiDmTableInfoPmttHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Only DIMM subtables are expected at this level */ + + if (DimmSubTable->Type != ACPI_PMTT_TYPE_DIMM) + { + AcpiOsPrintf ( + "\n**** Unexpected or unknown PMTT subtable type 0x%X\n\n", + DimmSubTable->Type); + return; + } + + /* Dump the fixed-length DIMM subtable */ + + Status = AcpiDmDumpTable (Length, + Offset + MemOffset + DimmOffset, DimmSubTable, + DimmSubTable->Length, AcpiDmTableInfoPmtt2); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next DIMM subtable */ + + DimmOffset += DimmSubTable->Length; + DimmSubTable = ACPI_ADD_PTR (ACPI_PMTT_HEADER, + DimmSubTable, DimmSubTable->Length); + } + + /* Point to next Controller subtable */ + + MemOffset += MemSubTable->Length; + MemSubTable = ACPI_ADD_PTR (ACPI_PMTT_HEADER, + MemSubTable, MemSubTable->Length); + } + + /* Point to next Socket subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_PMTT_HEADER, + SubTable, SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpS3pt + * + * PARAMETERS: Table - A S3PT table + * + * RETURN: Length of the table + * + * DESCRIPTION: Format the contents of a S3PT + * + ******************************************************************************/ + +UINT32 +AcpiDmDumpS3pt ( + ACPI_TABLE_HEADER *Tables) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_S3PT); + ACPI_S3PT_HEADER *SubTable; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_TABLE_S3PT *S3ptTable = ACPI_CAST_PTR (ACPI_TABLE_S3PT, Tables); + + + /* Main table */ + + Status = AcpiDmDumpTable (Offset, 0, S3ptTable, 0, AcpiDmTableInfoS3pt); + if (ACPI_FAILURE (Status)) + { + return 0; + } + + SubTable = ACPI_ADD_PTR (ACPI_S3PT_HEADER, S3ptTable, Offset); + while (Offset < S3ptTable->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (S3ptTable->Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoS3ptHdr); + if (ACPI_FAILURE (Status)) + { + return 0; + } + + switch (SubTable->Type) + { + case ACPI_S3PT_TYPE_RESUME: + + InfoTable = AcpiDmTableInfoS3pt0; + break; + + case ACPI_S3PT_TYPE_SUSPEND: + + InfoTable = AcpiDmTableInfoS3pt1; + break; + + default: + + AcpiOsPrintf ("\n**** Unknown S3PT subtable type 0x%X\n", + SubTable->Type); + + /* Attempt to continue */ + + if (!SubTable->Length) + { + AcpiOsPrintf ("Invalid zero length subtable\n"); + return 0; + } + goto NextSubTable; + } + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (S3ptTable->Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return 0; + } + +NextSubTable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_S3PT_HEADER, SubTable, SubTable->Length); + } + + return (S3ptTable->Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpSlic + * + * PARAMETERS: Table - A SLIC table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a SLIC + * + ******************************************************************************/ + +void +AcpiDmDumpSlic ( + ACPI_TABLE_HEADER *Table) +{ + + (void) AcpiDmDumpTable (Table->Length, sizeof (ACPI_TABLE_HEADER), Table, + Table->Length - sizeof (*Table), AcpiDmTableInfoSlic); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpSlit + * + * PARAMETERS: Table - An SLIT + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a SLIT + * + ******************************************************************************/ + +void +AcpiDmDumpSlit ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset; + UINT8 *Row; + UINT32 Localities; + UINT32 i; + UINT32 j; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoSlit); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Display the Locality NxN Matrix */ + + Localities = (UINT32) ACPI_CAST_PTR (ACPI_TABLE_SLIT, Table)->LocalityCount; + Offset = ACPI_OFFSET (ACPI_TABLE_SLIT, Entry[0]); + Row = (UINT8 *) ACPI_CAST_PTR (ACPI_TABLE_SLIT, Table)->Entry; + + for (i = 0; i < Localities; i++) + { + /* Display one row of the matrix */ + + AcpiDmLineHeader2 (Offset, Localities, "Locality", i); + for (j = 0; j < Localities; j++) + { + /* Check for beyond EOT */ + + if (Offset >= Table->Length) + { + AcpiOsPrintf ( + "\n**** Not enough room in table for all localities\n"); + return; + } + + AcpiOsPrintf ("%2.2X", Row[j]); + Offset++; + + /* Display up to 16 bytes per output row */ + + if ((j+1) < Localities) + { + AcpiOsPrintf (" "); + + if (j && (((j+1) % 16) == 0)) + { + AcpiOsPrintf ("\\\n"); /* With line continuation char */ + AcpiDmLineHeader (Offset, 0, NULL); + } + } + } + + /* Point to next row */ + + AcpiOsPrintf ("\n"); + Row += Localities; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpSrat + * + * PARAMETERS: Table - A SRAT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a SRAT + * + ******************************************************************************/ + +void +AcpiDmDumpSrat ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_SRAT); + ACPI_SUBTABLE_HEADER *SubTable; + ACPI_DMTABLE_INFO *InfoTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoSrat); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_SUBTABLE_HEADER, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Length, AcpiDmTableInfoSratHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + switch (SubTable->Type) + { + case ACPI_SRAT_TYPE_CPU_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat0; + break; + + case ACPI_SRAT_TYPE_MEMORY_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat1; + break; + + case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat2; + break; + + case ACPI_SRAT_TYPE_GICC_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat3; + break; + + default: + AcpiOsPrintf ("\n**** Unknown SRAT subtable type 0x%X\n", + SubTable->Type); + + /* Attempt to continue */ + + if (!SubTable->Length) + { + AcpiOsPrintf ("Invalid zero length subtable\n"); + return; + } + goto NextSubTable; + } + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + SubTable->Length, InfoTable); + if (ACPI_FAILURE (Status)) + { + return; + } + +NextSubTable: + /* Point to next subtable */ + + Offset += SubTable->Length; + SubTable = ACPI_ADD_PTR (ACPI_SUBTABLE_HEADER, SubTable, + SubTable->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpStao + * + * PARAMETERS: Table - A STAO table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a STAO. This is a variable-length + * table that contains an open-ended number of ASCII strings + * at the end of the table. + * + ******************************************************************************/ + +void +AcpiDmDumpStao ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + char *Namepath; + UINT32 Length = Table->Length; + UINT32 StringLength; + UINT32 Offset = sizeof (ACPI_TABLE_STAO); + + + /* Main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoStao); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* The rest of the table consists of Namepath strings */ + + while (Offset < Table->Length) + { + Namepath = ACPI_ADD_PTR (char, Table, Offset); + StringLength = strlen (Namepath) + 1; + + AcpiDmLineHeader (Offset, StringLength, "Namestring"); + AcpiOsPrintf ("\"%s\"\n", Namepath); + + /* Point to next namepath */ + + Offset += StringLength; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpTcpa + * + * PARAMETERS: Table - A TCPA table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a TCPA. + * + * NOTE: There are two versions of the table with the same signature: + * the client version and the server version. The common + * PlatformClass field is used to differentiate the two types of + * tables. + * + ******************************************************************************/ + +void +AcpiDmDumpTcpa ( + ACPI_TABLE_HEADER *Table) +{ + UINT32 Offset = sizeof (ACPI_TABLE_TCPA_HDR); + ACPI_TABLE_TCPA_HDR *CommonHeader = ACPI_CAST_PTR ( + ACPI_TABLE_TCPA_HDR, Table); + ACPI_TABLE_TCPA_HDR *SubTable = ACPI_ADD_PTR ( + ACPI_TABLE_TCPA_HDR, Table, Offset); + ACPI_STATUS Status; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, + 0, AcpiDmTableInfoTcpaHdr); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* + * Examine the PlatformClass field to determine the table type. + * Either a client or server table. Only one. + */ + switch (CommonHeader->PlatformClass) + { + case ACPI_TCPA_CLIENT_TABLE: + + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + Table->Length - Offset, AcpiDmTableInfoTcpaClient); + break; + + case ACPI_TCPA_SERVER_TABLE: + + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + Table->Length - Offset, AcpiDmTableInfoTcpaServer); + break; + + default: + + AcpiOsPrintf ("\n**** Unknown TCPA Platform Class 0x%X\n", + CommonHeader->PlatformClass); + Status = AE_ERROR; + break; + } + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("\n**** Cannot disassemble TCPA table\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpVrtc + * + * PARAMETERS: Table - A VRTC table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a VRTC + * + ******************************************************************************/ + +void +AcpiDmDumpVrtc ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_VRTC); + ACPI_VRTC_ENTRY *SubTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoVrtc); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_VRTC_ENTRY, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + sizeof (ACPI_VRTC_ENTRY), AcpiDmTableInfoVrtc0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable */ + + Offset += sizeof (ACPI_VRTC_ENTRY); + SubTable = ACPI_ADD_PTR (ACPI_VRTC_ENTRY, SubTable, + sizeof (ACPI_VRTC_ENTRY)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpWdat + * + * PARAMETERS: Table - A WDAT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a WDAT + * + ******************************************************************************/ + +void +AcpiDmDumpWdat ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 Offset = sizeof (ACPI_TABLE_WDAT); + ACPI_WDAT_ENTRY *SubTable; + + + /* Main table */ + + Status = AcpiDmDumpTable (Table->Length, 0, Table, 0, AcpiDmTableInfoWdat); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Subtables */ + + SubTable = ACPI_ADD_PTR (ACPI_WDAT_ENTRY, Table, Offset); + while (Offset < Table->Length) + { + /* Common subtable header */ + + AcpiOsPrintf ("\n"); + Status = AcpiDmDumpTable (Table->Length, Offset, SubTable, + sizeof (ACPI_WDAT_ENTRY), AcpiDmTableInfoWdat0); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Point to next subtable */ + + Offset += sizeof (ACPI_WDAT_ENTRY); + SubTable = ACPI_ADD_PTR (ACPI_WDAT_ENTRY, SubTable, + sizeof (ACPI_WDAT_ENTRY)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpWpbt + * + * PARAMETERS: Table - A WPBT table + * + * RETURN: None + * + * DESCRIPTION: Format the contents of a WPBT. This table type consists + * of an open-ended arguments buffer at the end of the table. + * + ******************************************************************************/ + +void +AcpiDmDumpWpbt ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_TABLE_WPBT *SubTable; + UINT32 Length = Table->Length; + UINT16 ArgumentsLength; + + + /* Dump the main table */ + + Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoWpbt); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Extract the arguments buffer length from the main table */ + + SubTable = ACPI_CAST_PTR (ACPI_TABLE_WPBT, Table); + ArgumentsLength = SubTable->ArgumentsLength; + + /* Dump the arguments buffer */ + + (void) AcpiDmDumpTable (Table->Length, 0, Table, ArgumentsLength, + AcpiDmTableInfoWpbt0); +} diff --git a/third_party/lib/acpica/source/common/dmtbinfo.c b/third_party/lib/acpica/source/common/dmtbinfo.c new file mode 100644 index 000000000..5ccea2a1f --- /dev/null +++ b/third_party/lib/acpica/source/common/dmtbinfo.c @@ -0,0 +1,2918 @@ +/****************************************************************************** + * + * Module Name: dmtbinfo - Table info for non-AML tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdisasm.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_CA_DISASSEMBLER + ACPI_MODULE_NAME ("dmtbinfo") + +/* + * How to add a new table: + * + * - Add the C table definition to the actbl1.h or actbl2.h header. + * - Add ACPI_xxxx_OFFSET macro(s) for the table (and subtables) to list below. + * - Define the table in this file (for the disassembler). If any + * new data types are required (ACPI_DMT_*), see below. + * - Add an external declaration for the new table definition (AcpiDmTableInfo*) + * in acdisam.h + * - Add new table definition to the dispatch table in dmtable.c (AcpiDmTableData) + * If a simple table (with no subtables), no disassembly code is needed. + * Otherwise, create the AcpiDmDump* function for to disassemble the table + * and add it to the dmtbdump.c file. + * - Add an external declaration for the new AcpiDmDump* function in acdisasm.h + * - Add the new AcpiDmDump* function to the dispatch table in dmtable.c + * - Create a template for the new table + * - Add data table compiler support + * + * How to add a new data type (ACPI_DMT_*): + * + * - Add new type at the end of the ACPI_DMT list in acdisasm.h + * - Add length and implementation cases in dmtable.c (disassembler) + * - Add type and length cases in dtutils.c (DT compiler) + */ + +/* + * Macros used to generate offsets to specific table fields + */ +#define ACPI_FACS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_FACS,f) +#define ACPI_GAS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GENERIC_ADDRESS,f) +#define ACPI_HDR_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HEADER,f) +#define ACPI_RSDP_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_RSDP,f) +#define ACPI_BERT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_BERT,f) +#define ACPI_BGRT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_BGRT,f) +#define ACPI_BOOT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_BOOT,f) +#define ACPI_CPEP_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_CPEP,f) +#define ACPI_DBG2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DBG2,f) +#define ACPI_DBGP_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DBGP,f) +#define ACPI_DMAR_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DMAR,f) +#define ACPI_DRTM_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_DRTM,f) +#define ACPI_ECDT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_ECDT,f) +#define ACPI_EINJ_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_EINJ,f) +#define ACPI_ERST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_ERST,f) +#define ACPI_GTDT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_GTDT,f) +#define ACPI_HEST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HEST,f) +#define ACPI_HPET_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_HPET,f) +#define ACPI_IORT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_IORT,f) +#define ACPI_IVRS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_IVRS,f) +#define ACPI_MADT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MADT,f) +#define ACPI_MCFG_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MCFG,f) +#define ACPI_MCHI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MCHI,f) +#define ACPI_MPST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MPST,f) +#define ACPI_MSCT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_MSCT,f) +#define ACPI_NFIT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_NFIT,f) +#define ACPI_PCCT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_PCCT,f) +#define ACPI_PMTT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_PMTT,f) +#define ACPI_S3PT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_S3PT,f) +#define ACPI_SBST_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SBST,f) +#define ACPI_SLIT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SLIT,f) +#define ACPI_SPCR_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SPCR,f) +#define ACPI_SPMI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SPMI,f) +#define ACPI_SRAT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SRAT,f) +#define ACPI_STAO_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_STAO,f) +#define ACPI_TCPA_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TCPA_HDR,f) +#define ACPI_TPM2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TPM2,f) +#define ACPI_UEFI_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_UEFI,f) +#define ACPI_WAET_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WAET,f) +#define ACPI_WDAT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WDAT,f) +#define ACPI_WDDT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WDDT,f) +#define ACPI_WDRT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WDRT,f) +#define ACPI_WPBT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_WPBT,f) +#define ACPI_XENV_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_XENV,f) + +/* Subtables */ + +#define ACPI_ASF0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_INFO,f) +#define ACPI_ASF1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_ALERT,f) +#define ACPI_ASF1a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_ALERT_DATA,f) +#define ACPI_ASF2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_REMOTE,f) +#define ACPI_ASF2a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_CONTROL_DATA,f) +#define ACPI_ASF3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_RMCP,f) +#define ACPI_ASF4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_ASF_ADDRESS,f) +#define ACPI_CPEP0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CPEP_POLLING,f) +#define ACPI_CSRT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CSRT_GROUP,f) +#define ACPI_CSRT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CSRT_SHARED_INFO,f) +#define ACPI_CSRT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_CSRT_DESCRIPTOR,f) +#define ACPI_DBG20_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DBG2_DEVICE,f) +#define ACPI_DMARS_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_DEVICE_SCOPE,f) +#define ACPI_DMAR0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_HARDWARE_UNIT,f) +#define ACPI_DMAR1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_RESERVED_MEMORY,f) +#define ACPI_DMAR2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_ATSR,f) +#define ACPI_DMAR3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_RHSA,f) +#define ACPI_DMAR4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DMAR_ANDD,f) +#define ACPI_DRTM0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_VTABLE_LIST,f) +#define ACPI_DRTM1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_RESOURCE_LIST,f) +#define ACPI_DRTM1a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_RESOURCE,f) +#define ACPI_DRTM2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_DRTM_DPS_ID,f) +#define ACPI_EINJ0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_WHEA_HEADER,f) +#define ACPI_ERST0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_WHEA_HEADER,f) +#define ACPI_FPDTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_HEADER,f) +#define ACPI_FPDT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_BOOT,f) +#define ACPI_FPDT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_FPDT_S3PT_PTR,f) +#define ACPI_GTDT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_TIMER_BLOCK,f) +#define ACPI_GTDT0a_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_TIMER_ENTRY,f) +#define ACPI_GTDT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_WATCHDOG,f) +#define ACPI_GTDTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_GTDT_HEADER,f) +#define ACPI_HEST0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_MACHINE_CHECK,f) +#define ACPI_HEST1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_CORRECTED,f) +#define ACPI_HEST2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_NMI,f) +#define ACPI_HEST6_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_AER_ROOT,f) +#define ACPI_HEST7_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_AER,f) +#define ACPI_HEST8_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_AER_BRIDGE,f) +#define ACPI_HEST9_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_GENERIC,f) +#define ACPI_HESTN_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_NOTIFY,f) +#define ACPI_HESTB_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_HEST_IA_ERROR_BANK,f) +#define ACPI_IORT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_ITS_GROUP,f) +#define ACPI_IORT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_NAMED_COMPONENT,f) +#define ACPI_IORT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_ROOT_COMPLEX,f) +#define ACPI_IORT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_SMMU,f) +#define ACPI_IORTA_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_MEMORY_ACCESS,f) +#define ACPI_IORTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_NODE,f) +#define ACPI_IORTM_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IORT_ID_MAPPING,f) +#define ACPI_IVRSH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_HEADER,f) +#define ACPI_IVRS0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_HARDWARE,f) +#define ACPI_IVRS1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_MEMORY,f) +#define ACPI_IVRSD_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DE_HEADER,f) +#define ACPI_IVRS8A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DEVICE8A,f) +#define ACPI_IVRS8B_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DEVICE8B,f) +#define ACPI_IVRS8C_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_IVRS_DEVICE8C,f) +#define ACPI_LPITH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_LPIT_HEADER,f) +#define ACPI_LPIT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_LPIT_NATIVE,f) +#define ACPI_MADT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_APIC,f) +#define ACPI_MADT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_IO_APIC,f) +#define ACPI_MADT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_INTERRUPT_OVERRIDE,f) +#define ACPI_MADT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_NMI_SOURCE,f) +#define ACPI_MADT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_APIC_NMI,f) +#define ACPI_MADT5_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_APIC_OVERRIDE,f) +#define ACPI_MADT6_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_IO_SAPIC,f) +#define ACPI_MADT7_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_SAPIC,f) +#define ACPI_MADT8_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_INTERRUPT_SOURCE,f) +#define ACPI_MADT9_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_X2APIC,f) +#define ACPI_MADT10_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_LOCAL_X2APIC_NMI,f) +#define ACPI_MADT11_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_INTERRUPT,f) +#define ACPI_MADT12_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_DISTRIBUTOR,f) +#define ACPI_MADT13_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_MSI_FRAME,f) +#define ACPI_MADT14_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_REDISTRIBUTOR,f) +#define ACPI_MADT15_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MADT_GENERIC_TRANSLATOR,f) +#define ACPI_MADTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SUBTABLE_HEADER,f) +#define ACPI_MCFG0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MCFG_ALLOCATION,f) +#define ACPI_MPST0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_POWER_NODE,f) +#define ACPI_MPST0A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_POWER_STATE,f) +#define ACPI_MPST0B_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_COMPONENT,f) +#define ACPI_MPST1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_DATA_HDR,f) +#define ACPI_MPST2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MPST_POWER_DATA,f) +#define ACPI_MSCT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MSCT_PROXIMITY,f) +#define ACPI_MTMR0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_MTMR_ENTRY,f) +#define ACPI_NFITH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_HEADER,f) +#define ACPI_NFIT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_SYSTEM_ADDRESS,f) +#define ACPI_NFIT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_MEMORY_MAP,f) +#define ACPI_NFIT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_INTERLEAVE,f) +#define ACPI_NFIT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_SMBIOS,f) +#define ACPI_NFIT4_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_CONTROL_REGION,f) +#define ACPI_NFIT5_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_DATA_REGION,f) +#define ACPI_NFIT6_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_NFIT_FLUSH_ADDRESS,f) +#define ACPI_PCCT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_SUBSPACE,f) +#define ACPI_PCCT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PCCT_HW_REDUCED,f) +#define ACPI_PMTT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_SOCKET,f) +#define ACPI_PMTT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_CONTROLLER,f) +#define ACPI_PMTT1A_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_DOMAIN,f) +#define ACPI_PMTT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_PHYSICAL_COMPONENT,f) +#define ACPI_PMTTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_PMTT_HEADER,f) +#define ACPI_S3PTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_HEADER,f) +#define ACPI_S3PT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_RESUME,f) +#define ACPI_S3PT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_SUSPEND,f) +#define ACPI_SLIC_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SLIC,f) +#define ACPI_SRATH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SUBTABLE_HEADER,f) +#define ACPI_SRAT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_CPU_AFFINITY,f) +#define ACPI_SRAT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_MEM_AFFINITY,f) +#define ACPI_SRAT2_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_X2APIC_CPU_AFFINITY,f) +#define ACPI_SRAT3_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_GICC_AFFINITY,f) +#define ACPI_TCPA_CLIENT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TCPA_CLIENT,f) +#define ACPI_TCPA_SERVER_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_TCPA_SERVER,f) +#define ACPI_VRTC0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_VRTC_ENTRY,f) +#define ACPI_WDAT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_WDAT_ENTRY,f) + +/* + * Simplify access to flag fields by breaking them up into bytes + */ +#define ACPI_FLAG_OFFSET(d,f,o) (UINT16) (ACPI_OFFSET (d,f) + o) + +/* Flags */ + +#define ACPI_DRTM_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_DRTM,f,o) +#define ACPI_DRTM1a_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_DRTM_RESOURCE,f,o) +#define ACPI_FADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_FADT,f,o) +#define ACPI_FACS_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_FACS,f,o) +#define ACPI_HPET_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_HPET,f,o) +#define ACPI_SRAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_CPU_AFFINITY,f,o) +#define ACPI_SRAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_MEM_AFFINITY,f,o) +#define ACPI_SRAT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_X2APIC_CPU_AFFINITY,f,o) +#define ACPI_SRAT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_SRAT_GICC_AFFINITY,f,o) +#define ACPI_GTDT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_GTDT,f,o) +#define ACPI_GTDT0a_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_GTDT_TIMER_ENTRY,f,o) +#define ACPI_GTDT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_GTDT_WATCHDOG,f,o) +#define ACPI_IORT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_SMMU,f,o) +#define ACPI_IORTA_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_MEMORY_ACCESS,f,o) +#define ACPI_IORTM_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_IORT_ID_MAPPING,f,o) +#define ACPI_LPITH_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_LPIT_HEADER,f,o) +#define ACPI_MADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_MADT,f,o) +#define ACPI_MADT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_APIC,f,o) +#define ACPI_MADT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_INTERRUPT_OVERRIDE,f,o) +#define ACPI_MADT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_NMI_SOURCE,f,o) +#define ACPI_MADT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_APIC_NMI,f,o) +#define ACPI_MADT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_SAPIC,f,o) +#define ACPI_MADT8_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_INTERRUPT_SOURCE,f,o) +#define ACPI_MADT9_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_X2APIC,f,o) +#define ACPI_MADT10_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_LOCAL_X2APIC_NMI,f,o) +#define ACPI_MADT11_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_GENERIC_INTERRUPT,f,o) +#define ACPI_MADT13_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MADT_GENERIC_MSI_FRAME,f,o) +#define ACPI_MPST0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MPST_POWER_NODE,f,o) +#define ACPI_MPST2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_MPST_POWER_DATA,f,o) +#define ACPI_NFIT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_SYSTEM_ADDRESS,f,o) +#define ACPI_NFIT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_MEMORY_MAP,f,o) +#define ACPI_NFIT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_NFIT_CONTROL_REGION,f,o) +#define ACPI_PCCT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_PCCT,f,o) +#define ACPI_PCCT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PCCT_HW_REDUCED,f,o) +#define ACPI_PMTTH_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_PMTT_HEADER,f,o) +#define ACPI_WDDT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_TABLE_WDDT,f,o) +#define ACPI_EINJ0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_WHEA_HEADER,f,o) +#define ACPI_ERST0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_WHEA_HEADER,f,o) +#define ACPI_HEST0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_IA_MACHINE_CHECK,f,o) +#define ACPI_HEST1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_IA_CORRECTED,f,o) +#define ACPI_HEST6_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (ACPI_HEST_AER_ROOT,f,o) + +/* + * Required terminator for all tables below + */ +#define ACPI_DMT_TERMINATOR {ACPI_DMT_EXIT, 0, NULL, 0} +#define ACPI_DMT_NEW_LINE {ACPI_DMT_EXTRA_TEXT, 0, "\n", 0} + + +/* + * ACPI Table Information, used to dump formatted ACPI tables + * + * Each entry is of the form: + */ + +/******************************************************************************* + * + * Common ACPI table header + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHeader[] = +{ + {ACPI_DMT_SIG, ACPI_HDR_OFFSET (Signature[0]), "Signature", 0}, + {ACPI_DMT_UINT32, ACPI_HDR_OFFSET (Length), "Table Length", DT_LENGTH}, + {ACPI_DMT_UINT8, ACPI_HDR_OFFSET (Revision), "Revision", 0}, + {ACPI_DMT_CHKSUM, ACPI_HDR_OFFSET (Checksum), "Checksum", 0}, + {ACPI_DMT_NAME6, ACPI_HDR_OFFSET (OemId[0]), "Oem ID", 0}, + {ACPI_DMT_NAME8, ACPI_HDR_OFFSET (OemTableId[0]), "Oem Table ID", 0}, + {ACPI_DMT_UINT32, ACPI_HDR_OFFSET (OemRevision), "Oem Revision", 0}, + {ACPI_DMT_NAME4, ACPI_HDR_OFFSET (AslCompilerId[0]), "Asl Compiler ID", 0}, + {ACPI_DMT_UINT32, ACPI_HDR_OFFSET (AslCompilerRevision), "Asl Compiler Revision", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * GAS - Generic Address Structure + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoGas[] = +{ + {ACPI_DMT_SPACEID, ACPI_GAS_OFFSET (SpaceId), "Space ID", 0}, + {ACPI_DMT_UINT8, ACPI_GAS_OFFSET (BitWidth), "Bit Width", 0}, + {ACPI_DMT_UINT8, ACPI_GAS_OFFSET (BitOffset), "Bit Offset", 0}, + {ACPI_DMT_ACCWIDTH, ACPI_GAS_OFFSET (AccessWidth), "Encoded Access Width", 0}, + {ACPI_DMT_UINT64, ACPI_GAS_OFFSET (Address), "Address", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * RSDP - Root System Description Pointer (Signature is "RSD PTR ") + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoRsdp1[] = +{ + {ACPI_DMT_NAME8, ACPI_RSDP_OFFSET (Signature[0]), "Signature", 0}, + {ACPI_DMT_UINT8, ACPI_RSDP_OFFSET (Checksum), "Checksum", 0}, + {ACPI_DMT_NAME6, ACPI_RSDP_OFFSET (OemId[0]), "Oem ID", 0}, + {ACPI_DMT_UINT8, ACPI_RSDP_OFFSET (Revision), "Revision", 0}, + {ACPI_DMT_UINT32, ACPI_RSDP_OFFSET (RsdtPhysicalAddress), "RSDT Address", 0}, + ACPI_DMT_TERMINATOR +}; + +/* ACPI 2.0+ Extensions */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoRsdp2[] = +{ + {ACPI_DMT_UINT32, ACPI_RSDP_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT64, ACPI_RSDP_OFFSET (XsdtPhysicalAddress), "XSDT Address", 0}, + {ACPI_DMT_UINT8, ACPI_RSDP_OFFSET (ExtendedChecksum), "Extended Checksum", 0}, + {ACPI_DMT_UINT24, ACPI_RSDP_OFFSET (Reserved[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * FACS - Firmware ACPI Control Structure + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFacs[] = +{ + {ACPI_DMT_NAME4, ACPI_FACS_OFFSET (Signature[0]), "Signature", 0}, + {ACPI_DMT_UINT32, ACPI_FACS_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT32, ACPI_FACS_OFFSET (HardwareSignature), "Hardware Signature", 0}, + {ACPI_DMT_UINT32, ACPI_FACS_OFFSET (FirmwareWakingVector), "32 Firmware Waking Vector", 0}, + {ACPI_DMT_UINT32, ACPI_FACS_OFFSET (GlobalLock), "Global Lock", 0}, + {ACPI_DMT_UINT32, ACPI_FACS_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_FACS_FLAG_OFFSET (Flags,0), "S4BIOS Support Present", 0}, + {ACPI_DMT_FLAG1, ACPI_FACS_FLAG_OFFSET (Flags,0), "64-bit Wake Supported (V2)", 0}, + {ACPI_DMT_UINT64, ACPI_FACS_OFFSET (XFirmwareWakingVector), "64 Firmware Waking Vector", 0}, + {ACPI_DMT_UINT8, ACPI_FACS_OFFSET (Version), "Version", 0}, + {ACPI_DMT_UINT24, ACPI_FACS_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_FACS_OFFSET (OspmFlags), "OspmFlags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_FACS_FLAG_OFFSET (OspmFlags,0), "64-bit Wake Env Required (V2)", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * FADT - Fixed ACPI Description Table (Signature is FACP) + * + ******************************************************************************/ + +/* ACPI 1.0 FADT (Version 1) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFadt1[] = +{ + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Facs), "FACS Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Dsdt), "DSDT Address", DT_NON_ZERO}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Model), "Model", 0}, + {ACPI_DMT_FADTPM, ACPI_FADT_OFFSET (PreferredProfile), "PM Profile", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (SciInterrupt), "SCI Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (SmiCommand), "SMI Command Port", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (AcpiEnable), "ACPI Enable Value", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (AcpiDisable), "ACPI Disable Value", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (S4BiosRequest), "S4BIOS Command", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (PstateControl), "P-State Control", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Pm1aEventBlock), "PM1A Event Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Pm1bEventBlock), "PM1B Event Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Pm1aControlBlock), "PM1A Control Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Pm1bControlBlock), "PM1B Control Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Pm2ControlBlock), "PM2 Control Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (PmTimerBlock), "PM Timer Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Gpe0Block), "GPE0 Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Gpe1Block), "GPE1 Block Address", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Pm1EventLength), "PM1 Event Block Length", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Pm1ControlLength), "PM1 Control Block Length", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Pm2ControlLength), "PM2 Control Block Length", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (PmTimerLength), "PM Timer Block Length", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Gpe0BlockLength), "GPE0 Block Length", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Gpe1BlockLength), "GPE1 Block Length", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Gpe1Base), "GPE1 Base Offset", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (CstControl), "_CST Support", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (C2Latency), "C2 Latency", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (C3Latency), "C3 Latency", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (FlushSize), "CPU Cache Size", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (FlushStride), "Cache Flush Stride", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (DutyOffset), "Duty Cycle Offset", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (DutyWidth), "Duty Cycle Width", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (DayAlarm), "RTC Day Alarm Index", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (MonthAlarm), "RTC Month Alarm Index", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Century), "RTC Century Index", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (BootFlags), "Boot Flags (decoded below)", DT_FLAG}, + + /* Boot Architecture Flags byte 0 */ + + {ACPI_DMT_FLAG0, ACPI_FADT_FLAG_OFFSET (BootFlags,0), "Legacy Devices Supported (V2)", 0}, + {ACPI_DMT_FLAG1, ACPI_FADT_FLAG_OFFSET (BootFlags,0), "8042 Present on ports 60/64 (V2)", 0}, + {ACPI_DMT_FLAG2, ACPI_FADT_FLAG_OFFSET (BootFlags,0), "VGA Not Present (V4)", 0}, + {ACPI_DMT_FLAG3, ACPI_FADT_FLAG_OFFSET (BootFlags,0), "MSI Not Supported (V4)", 0}, + {ACPI_DMT_FLAG4, ACPI_FADT_FLAG_OFFSET (BootFlags,0), "PCIe ASPM Not Supported (V4)", 0}, + {ACPI_DMT_FLAG5, ACPI_FADT_FLAG_OFFSET (BootFlags,0), "CMOS RTC Not Present (V5)", 0}, + + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_FADT_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + + /* Flags byte 0 */ + + {ACPI_DMT_FLAG0, ACPI_FADT_FLAG_OFFSET (Flags,0), "WBINVD instruction is operational (V1)", 0}, + {ACPI_DMT_FLAG1, ACPI_FADT_FLAG_OFFSET (Flags,0), "WBINVD flushes all caches (V1)", 0}, + {ACPI_DMT_FLAG2, ACPI_FADT_FLAG_OFFSET (Flags,0), "All CPUs support C1 (V1)", 0}, + {ACPI_DMT_FLAG3, ACPI_FADT_FLAG_OFFSET (Flags,0), "C2 works on MP system (V1)", 0}, + {ACPI_DMT_FLAG4, ACPI_FADT_FLAG_OFFSET (Flags,0), "Control Method Power Button (V1)", 0}, + {ACPI_DMT_FLAG5, ACPI_FADT_FLAG_OFFSET (Flags,0), "Control Method Sleep Button (V1)", 0}, + {ACPI_DMT_FLAG6, ACPI_FADT_FLAG_OFFSET (Flags,0), "RTC wake not in fixed reg space (V1)", 0}, + {ACPI_DMT_FLAG7, ACPI_FADT_FLAG_OFFSET (Flags,0), "RTC can wake system from S4 (V1)", 0}, + + /* Flags byte 1 */ + + {ACPI_DMT_FLAG0, ACPI_FADT_FLAG_OFFSET (Flags,1), "32-bit PM Timer (V1)", 0}, + {ACPI_DMT_FLAG1, ACPI_FADT_FLAG_OFFSET (Flags,1), "Docking Supported (V1)", 0}, + {ACPI_DMT_FLAG2, ACPI_FADT_FLAG_OFFSET (Flags,1), "Reset Register Supported (V2)", 0}, + {ACPI_DMT_FLAG3, ACPI_FADT_FLAG_OFFSET (Flags,1), "Sealed Case (V3)", 0}, + {ACPI_DMT_FLAG4, ACPI_FADT_FLAG_OFFSET (Flags,1), "Headless - No Video (V3)", 0}, + {ACPI_DMT_FLAG5, ACPI_FADT_FLAG_OFFSET (Flags,1), "Use native instr after SLP_TYPx (V3)", 0}, + {ACPI_DMT_FLAG6, ACPI_FADT_FLAG_OFFSET (Flags,1), "PCIEXP_WAK Bits Supported (V4)", 0}, + {ACPI_DMT_FLAG7, ACPI_FADT_FLAG_OFFSET (Flags,1), "Use Platform Timer (V4)", 0}, + + /* Flags byte 2 */ + + {ACPI_DMT_FLAG0, ACPI_FADT_FLAG_OFFSET (Flags,2), "RTC_STS valid on S4 wake (V4)", 0}, + {ACPI_DMT_FLAG1, ACPI_FADT_FLAG_OFFSET (Flags,2), "Remote Power-on capable (V4)", 0}, + {ACPI_DMT_FLAG2, ACPI_FADT_FLAG_OFFSET (Flags,2), "Use APIC Cluster Model (V4)", 0}, + {ACPI_DMT_FLAG3, ACPI_FADT_FLAG_OFFSET (Flags,2), "Use APIC Physical Destination Mode (V4)", 0}, + {ACPI_DMT_FLAG4, ACPI_FADT_FLAG_OFFSET (Flags,2), "Hardware Reduced (V5)", 0}, + {ACPI_DMT_FLAG5, ACPI_FADT_FLAG_OFFSET (Flags,2), "Low Power S0 Idle (V5)", 0}, + ACPI_DMT_TERMINATOR +}; + +/* ACPI 1.0 MS Extensions (FADT version 2) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFadt2[] = +{ + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (ResetRegister), "Reset Register", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (ResetValue), "Value to cause reset", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (ArmBootFlags), "Reserved", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (MinorRevision), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* ACPI 2.0+ Extensions (FADT version 3, 4, and 5) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFadt3[] = +{ + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (ResetRegister), "Reset Register", 0}, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (ResetValue), "Value to cause reset", 0}, + {ACPI_DMT_UINT16, ACPI_FADT_OFFSET (ArmBootFlags), "ARM Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_FADT_FLAG_OFFSET(ArmBootFlags,0), "PSCI Compliant", 0}, + {ACPI_DMT_FLAG1, ACPI_FADT_FLAG_OFFSET(ArmBootFlags,0), "Must use HVC for PSCI", 0}, + ACPI_DMT_NEW_LINE, + {ACPI_DMT_UINT8, ACPI_FADT_OFFSET (MinorRevision), "FADT Minor Revision", 0}, + {ACPI_DMT_UINT64, ACPI_FADT_OFFSET (XFacs), "FACS Address", 0}, + {ACPI_DMT_UINT64, ACPI_FADT_OFFSET (XDsdt), "DSDT Address", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XPm1aEventBlock), "PM1A Event Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XPm1bEventBlock), "PM1B Event Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XPm1aControlBlock), "PM1A Control Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XPm1bControlBlock), "PM1B Control Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XPm2ControlBlock), "PM2 Control Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XPmTimerBlock), "PM Timer Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XGpe0Block), "GPE0 Block", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (XGpe1Block), "GPE1 Block", 0}, + ACPI_DMT_TERMINATOR +}; + +/* ACPI 5.0 Extensions (FADT version 5) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFadt5[] = +{ + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (SleepControl), "Sleep Control Register", 0}, + {ACPI_DMT_GAS, ACPI_FADT_OFFSET (SleepStatus), "Sleep Status Register", 0}, + ACPI_DMT_TERMINATOR +}; + +/* ACPI 6.0 Extensions (FADT version 6) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFadt6[] = +{ + {ACPI_DMT_UINT64, ACPI_FADT_OFFSET (HypervisorId), "Hypervisor ID", 0}, + ACPI_DMT_TERMINATOR +}; + + +/* + * Remaining tables are not consumed directly by the ACPICA subsystem + */ + +/******************************************************************************* + * + * ASF - Alert Standard Format table (Signature "ASF!") + * + ******************************************************************************/ + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsfHdr[] = +{ + {ACPI_DMT_ASF, ACPI_ASF0_OFFSET (Header.Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_ASF0_OFFSET (Header.Reserved), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_ASF0_OFFSET (Header.Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* 0: ASF Information */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf0[] = +{ + {ACPI_DMT_UINT8, ACPI_ASF0_OFFSET (MinResetValue), "Minimum Reset Value", 0}, + {ACPI_DMT_UINT8, ACPI_ASF0_OFFSET (MinPollInterval), "Minimum Polling Interval", 0}, + {ACPI_DMT_UINT16, ACPI_ASF0_OFFSET (SystemId), "System ID", 0}, + {ACPI_DMT_UINT32, ACPI_ASF0_OFFSET (MfgId), "Manufacturer ID", 0}, + {ACPI_DMT_UINT8, ACPI_ASF0_OFFSET (Flags), "Flags", 0}, + {ACPI_DMT_UINT24, ACPI_ASF0_OFFSET (Reserved2[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: ASF Alerts */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf1[] = +{ + {ACPI_DMT_UINT8, ACPI_ASF1_OFFSET (AssertMask), "AssertMask", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1_OFFSET (DeassertMask), "DeassertMask", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1_OFFSET (Alerts), "Alert Count", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1_OFFSET (DataLength), "Alert Data Length", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1a: ASF Alert data */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf1a[] = +{ + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Address), "Address", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Command), "Command", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Mask), "Mask", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Value), "Value", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (SensorType), "SensorType", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Type), "Type", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Offset), "Offset", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (SourceType), "SourceType", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Severity), "Severity", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (SensorNumber), "SensorNumber", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Entity), "Entity", 0}, + {ACPI_DMT_UINT8, ACPI_ASF1a_OFFSET (Instance), "Instance", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: ASF Remote Control */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf2[] = +{ + {ACPI_DMT_UINT8, ACPI_ASF2_OFFSET (Controls), "Control Count", 0}, + {ACPI_DMT_UINT8, ACPI_ASF2_OFFSET (DataLength), "Control Data Length", 0}, + {ACPI_DMT_UINT16, ACPI_ASF2_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2a: ASF Control data */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf2a[] = +{ + {ACPI_DMT_UINT8, ACPI_ASF2a_OFFSET (Function), "Function", 0}, + {ACPI_DMT_UINT8, ACPI_ASF2a_OFFSET (Address), "Address", 0}, + {ACPI_DMT_UINT8, ACPI_ASF2a_OFFSET (Command), "Command", 0}, + {ACPI_DMT_UINT8, ACPI_ASF2a_OFFSET (Value), "Value", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 3: ASF RMCP Boot Options */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf3[] = +{ + {ACPI_DMT_BUF7, ACPI_ASF3_OFFSET (Capabilities[0]), "Capabilities", 0}, + {ACPI_DMT_UINT8, ACPI_ASF3_OFFSET (CompletionCode), "Completion Code", 0}, + {ACPI_DMT_UINT32, ACPI_ASF3_OFFSET (EnterpriseId), "Enterprise ID", 0}, + {ACPI_DMT_UINT8, ACPI_ASF3_OFFSET (Command), "Command", 0}, + {ACPI_DMT_UINT16, ACPI_ASF3_OFFSET (Parameter), "Parameter", 0}, + {ACPI_DMT_UINT16, ACPI_ASF3_OFFSET (BootOptions), "Boot Options", 0}, + {ACPI_DMT_UINT16, ACPI_ASF3_OFFSET (OemParameters), "Oem Parameters", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 4: ASF Address */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoAsf4[] = +{ + {ACPI_DMT_UINT8, ACPI_ASF4_OFFSET (EpromAddress), "Eprom Address", 0}, + {ACPI_DMT_UINT8, ACPI_ASF4_OFFSET (Devices), "Device Count", DT_COUNT}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * BERT - Boot Error Record table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoBert[] = +{ + {ACPI_DMT_UINT32, ACPI_BERT_OFFSET (RegionLength), "Boot Error Region Length", 0}, + {ACPI_DMT_UINT64, ACPI_BERT_OFFSET (Address), "Boot Error Region Address", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * BGRT - Boot Graphics Resource Table (ACPI 5.0) + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoBgrt[] = +{ + {ACPI_DMT_UINT16, ACPI_BGRT_OFFSET (Version), "Version", 0}, + {ACPI_DMT_UINT8, ACPI_BGRT_OFFSET (Status), "Status", 0}, + {ACPI_DMT_UINT8, ACPI_BGRT_OFFSET (ImageType), "Image Type", 0}, + {ACPI_DMT_UINT64, ACPI_BGRT_OFFSET (ImageAddress), "Image Address", 0}, + {ACPI_DMT_UINT32, ACPI_BGRT_OFFSET (ImageOffsetX), "Image OffsetX", 0}, + {ACPI_DMT_UINT32, ACPI_BGRT_OFFSET (ImageOffsetY), "Image OffsetY", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * BOOT - Simple Boot Flag Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoBoot[] = +{ + {ACPI_DMT_UINT8, ACPI_BOOT_OFFSET (CmosIndex), "Boot Register Index", 0}, + {ACPI_DMT_UINT24, ACPI_BOOT_OFFSET (Reserved[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * CPEP - Corrected Platform Error Polling table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoCpep[] = +{ + {ACPI_DMT_UINT64, ACPI_CPEP_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoCpep0[] = +{ + {ACPI_DMT_UINT8, ACPI_CPEP0_OFFSET (Header.Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_CPEP0_OFFSET (Header.Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT8, ACPI_CPEP0_OFFSET (Id), "Processor ID", 0}, + {ACPI_DMT_UINT8, ACPI_CPEP0_OFFSET (Eid), "Processor EID", 0}, + {ACPI_DMT_UINT32, ACPI_CPEP0_OFFSET (Interval), "Polling Interval", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * CSRT - Core System Resource Table + * + ******************************************************************************/ + +/* Main table consists only of the standard ACPI table header */ + +/* Resource Group subtable */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt0[] = +{ + {ACPI_DMT_UINT32, ACPI_CSRT0_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT32, ACPI_CSRT0_OFFSET (VendorId), "Vendor ID", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT0_OFFSET (SubvendorId), "Subvendor ID", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT0_OFFSET (DeviceId), "Device ID", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT0_OFFSET (SubdeviceId), "Subdevice ID", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT0_OFFSET (Revision), "Revision", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT0_OFFSET (SharedInfoLength), "Shared Info Length", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Shared Info subtable */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt1[] = +{ + {ACPI_DMT_UINT16, ACPI_CSRT1_OFFSET (MajorVersion), "Major Version", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT1_OFFSET (MinorVersion), "Minor Version", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT1_OFFSET (MmioBaseLow), "MMIO Base Address Low", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT1_OFFSET (MmioBaseHigh), "MMIO Base Address High", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT1_OFFSET (GsiInterrupt), "GSI Interrupt", 0}, + {ACPI_DMT_UINT8, ACPI_CSRT1_OFFSET (InterruptPolarity), "Interrupt Polarity", 0}, + {ACPI_DMT_UINT8, ACPI_CSRT1_OFFSET (InterruptMode), "Interrupt Mode", 0}, + {ACPI_DMT_UINT8, ACPI_CSRT1_OFFSET (NumChannels), "Num Channels", 0}, + {ACPI_DMT_UINT8, ACPI_CSRT1_OFFSET (DmaAddressWidth), "DMA Address Width", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT1_OFFSET (BaseRequestLine), "Base Request Line", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT1_OFFSET (NumHandshakeSignals), "Num Handshake Signals", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT1_OFFSET (MaxBlockSize), "Max Block Size", 0}, + ACPI_DMT_TERMINATOR +}; + + +/* Resource Descriptor subtable */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt2[] = +{ + {ACPI_DMT_UINT32, ACPI_CSRT2_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_CSRT2_OFFSET (Type), "Type", 0}, + {ACPI_DMT_UINT16, ACPI_CSRT2_OFFSET (Subtype), "Subtype", 0}, + {ACPI_DMT_UINT32, ACPI_CSRT2_OFFSET (Uid), "UID", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt2a[] = +{ + {ACPI_DMT_RAW_BUFFER, 0, "ResourceInfo", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * DBG2 - Debug Port Table 2 + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2[] = +{ + {ACPI_DMT_UINT32, ACPI_DBG2_OFFSET (InfoOffset), "Info Offset", 0}, + {ACPI_DMT_UINT32, ACPI_DBG2_OFFSET (InfoCount), "Info Count", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Debug Device Information Subtable */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Device[] = +{ + {ACPI_DMT_UINT8, ACPI_DBG20_OFFSET (Revision), "Revision", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT8, ACPI_DBG20_OFFSET (RegisterCount), "Register Count", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (NamepathLength), "Namepath Length", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (NamepathOffset), "Namepath Offset", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (OemDataLength), "OEM Data Length", DT_DESCRIBES_OPTIONAL}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (OemDataOffset), "OEM Data Offset", DT_DESCRIBES_OPTIONAL}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (PortType), "Port Type", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (PortSubtype), "Port Subtype", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (BaseAddressOffset), "Base Address Offset", 0}, + {ACPI_DMT_UINT16, ACPI_DBG20_OFFSET (AddressSizeOffset), "Address Size Offset", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Variable-length data for the subtable */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Addr[] = +{ + {ACPI_DMT_GAS, 0, "Base Address Register", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Size[] = +{ + {ACPI_DMT_UINT32, 0, "Address Size", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Name[] = +{ + {ACPI_DMT_STRING, 0, "Namepath", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2OemData[] = +{ + {ACPI_DMT_RAW_BUFFER, 0, "OEM Data", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * DBGP - Debug Port + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDbgp[] = +{ + {ACPI_DMT_UINT8, ACPI_DBGP_OFFSET (Type), "Interface Type", 0}, + {ACPI_DMT_UINT24, ACPI_DBGP_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_GAS, ACPI_DBGP_OFFSET (DebugPort), "Debug Port Register", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * DMAR - DMA Remapping table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmar[] = +{ + {ACPI_DMT_UINT8, ACPI_DMAR_OFFSET (Width), "Host Address Width", 0}, + {ACPI_DMT_UINT8, ACPI_DMAR_OFFSET (Flags), "Flags", 0}, + {ACPI_DMT_BUF10, ACPI_DMAR_OFFSET (Reserved[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmarHdr[] = +{ + {ACPI_DMT_DMAR, ACPI_DMAR0_OFFSET (Header.Type), "Subtable Type", 0}, + {ACPI_DMT_UINT16, ACPI_DMAR0_OFFSET (Header.Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* Common device scope entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmarScope[] = +{ + {ACPI_DMT_DMAR_SCOPE, ACPI_DMARS_OFFSET (EntryType), "Device Scope Type", 0}, + {ACPI_DMT_UINT8, ACPI_DMARS_OFFSET (Length), "Entry Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_DMARS_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT8, ACPI_DMARS_OFFSET (EnumerationId), "Enumeration ID", 0}, + {ACPI_DMT_UINT8, ACPI_DMARS_OFFSET (Bus), "PCI Bus Number", 0}, + ACPI_DMT_TERMINATOR +}; + +/* DMAR Subtables */ + +/* 0: Hardware Unit Definition */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmar0[] = +{ + {ACPI_DMT_UINT8, ACPI_DMAR0_OFFSET (Flags), "Flags", 0}, + {ACPI_DMT_UINT8, ACPI_DMAR0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_DMAR0_OFFSET (Segment), "PCI Segment Number", 0}, + {ACPI_DMT_UINT64, ACPI_DMAR0_OFFSET (Address), "Register Base Address", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: Reserved Memory Definition */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmar1[] = +{ + {ACPI_DMT_UINT16, ACPI_DMAR1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_DMAR1_OFFSET (Segment), "PCI Segment Number", 0}, + {ACPI_DMT_UINT64, ACPI_DMAR1_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_DMAR1_OFFSET (EndAddress), "End Address (limit)", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: Root Port ATS Capability Definition */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmar2[] = +{ + {ACPI_DMT_UINT8, ACPI_DMAR2_OFFSET (Flags), "Flags", 0}, + {ACPI_DMT_UINT8, ACPI_DMAR2_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_DMAR2_OFFSET (Segment), "PCI Segment Number", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 3: Remapping Hardware Static Affinity Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmar3[] = +{ + {ACPI_DMT_UINT32, ACPI_DMAR3_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_DMAR3_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_DMAR3_OFFSET (ProximityDomain), "Proximity Domain", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 4: ACPI Namespace Device Declaration Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDmar4[] = +{ + {ACPI_DMT_UINT24, ACPI_DMAR4_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT8, ACPI_DMAR4_OFFSET (DeviceNumber), "Device Number", 0}, + {ACPI_DMT_STRING, ACPI_DMAR4_OFFSET (DeviceName[0]), "Device Name", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * DRTM - Dynamic Root of Trust for Measurement table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm[] = +{ + {ACPI_DMT_UINT64, ACPI_DRTM_OFFSET (EntryBaseAddress), "Entry Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_DRTM_OFFSET (EntryLength), "Entry Length", 0}, + {ACPI_DMT_UINT32, ACPI_DRTM_OFFSET (EntryAddress32), "Entry 32", 0}, + {ACPI_DMT_UINT64, ACPI_DRTM_OFFSET (EntryAddress64), "Entry 64", 0}, + {ACPI_DMT_UINT64, ACPI_DRTM_OFFSET (ExitAddress), "Exit Address", 0}, + {ACPI_DMT_UINT64, ACPI_DRTM_OFFSET (LogAreaAddress), "Log Area Start", 0}, + {ACPI_DMT_UINT32, ACPI_DRTM_OFFSET (LogAreaLength), "Log Area Length", 0}, + {ACPI_DMT_UINT64, ACPI_DRTM_OFFSET (ArchDependentAddress), "Arch Dependent Address", 0}, + {ACPI_DMT_UINT32, ACPI_DRTM_OFFSET (Flags), "Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_DRTM_FLAG_OFFSET (Flags, 0), "Namespace in TCB", 0}, + {ACPI_DMT_FLAG1, ACPI_DRTM_FLAG_OFFSET (Flags, 0), "Gap Code on S3 Resume", 0}, + {ACPI_DMT_FLAG2, ACPI_DRTM_FLAG_OFFSET (Flags, 0), "Gap Code on DLME_Exit", 0}, + {ACPI_DMT_FLAG3, ACPI_DRTM_FLAG_OFFSET (Flags, 0), "PCR_Authorities Changed", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm0[] = +{ + {ACPI_DMT_UINT32, ACPI_DRTM0_OFFSET (ValidatedTableCount), "Validated Table Count", DT_COUNT}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm0a[] = +{ + {ACPI_DMT_UINT64, 0, "Table Address", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm1[] = +{ + {ACPI_DMT_UINT32, ACPI_DRTM1_OFFSET (ResourceCount), "Resource Count", DT_COUNT}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm1a[] = +{ + {ACPI_DMT_UINT56, ACPI_DRTM1a_OFFSET (Size[0]), "Size", DT_OPTIONAL}, + {ACPI_DMT_UINT8, ACPI_DRTM1a_OFFSET (Type), "Type", 0}, + {ACPI_DMT_FLAG0, ACPI_DRTM1a_FLAG_OFFSET (Type, 0), "Resource Type", 0}, + {ACPI_DMT_FLAG7, ACPI_DRTM1a_FLAG_OFFSET (Type, 0), "Protections", 0}, + {ACPI_DMT_UINT64, ACPI_DRTM1a_OFFSET (Address), "Address", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm2[] = +{ + {ACPI_DMT_UINT32, ACPI_DRTM2_OFFSET (DpsIdLength), "DLME Platform Id Length", DT_COUNT}, + {ACPI_DMT_BUF16, ACPI_DRTM2_OFFSET (DpsId), "DLME Platform Id", DT_COUNT}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * ECDT - Embedded Controller Boot Resources Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoEcdt[] = +{ + {ACPI_DMT_GAS, ACPI_ECDT_OFFSET (Control), "Command/Status Register", 0}, + {ACPI_DMT_GAS, ACPI_ECDT_OFFSET (Data), "Data Register", 0}, + {ACPI_DMT_UINT32, ACPI_ECDT_OFFSET (Uid), "UID", 0}, + {ACPI_DMT_UINT8, ACPI_ECDT_OFFSET (Gpe), "GPE Number", 0}, + {ACPI_DMT_STRING, ACPI_ECDT_OFFSET (Id[0]), "Namepath", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * EINJ - Error Injection table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoEinj[] = +{ + {ACPI_DMT_UINT32, ACPI_EINJ_OFFSET (HeaderLength), "Injection Header Length", 0}, + {ACPI_DMT_UINT8, ACPI_EINJ_OFFSET (Flags), "Flags", 0}, + {ACPI_DMT_UINT24, ACPI_EINJ_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_EINJ_OFFSET (Entries), "Injection Entry Count", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoEinj0[] = +{ + {ACPI_DMT_EINJACT, ACPI_EINJ0_OFFSET (Action), "Action", 0}, + {ACPI_DMT_EINJINST, ACPI_EINJ0_OFFSET (Instruction), "Instruction", 0}, + {ACPI_DMT_UINT8, ACPI_EINJ0_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_EINJ0_FLAG_OFFSET (Flags,0), "Preserve Register Bits", 0}, + + {ACPI_DMT_UINT8, ACPI_EINJ0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_GAS, ACPI_EINJ0_OFFSET (RegisterRegion), "Register Region", 0}, + {ACPI_DMT_UINT64, ACPI_EINJ0_OFFSET (Value), "Value", 0}, + {ACPI_DMT_UINT64, ACPI_EINJ0_OFFSET (Mask), "Mask", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * ERST - Error Record Serialization table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoErst[] = +{ + {ACPI_DMT_UINT32, ACPI_ERST_OFFSET (HeaderLength), "Serialization Header Length", 0}, + {ACPI_DMT_UINT32, ACPI_ERST_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_ERST_OFFSET (Entries), "Instruction Entry Count", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoErst0[] = +{ + {ACPI_DMT_ERSTACT, ACPI_ERST0_OFFSET (Action), "Action", 0}, + {ACPI_DMT_ERSTINST, ACPI_ERST0_OFFSET (Instruction), "Instruction", 0}, + {ACPI_DMT_UINT8, ACPI_ERST0_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_ERST0_FLAG_OFFSET (Flags,0), "Preserve Register Bits", 0}, + + {ACPI_DMT_UINT8, ACPI_ERST0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_GAS, ACPI_ERST0_OFFSET (RegisterRegion), "Register Region", 0}, + {ACPI_DMT_UINT64, ACPI_ERST0_OFFSET (Value), "Value", 0}, + {ACPI_DMT_UINT64, ACPI_ERST0_OFFSET (Mask), "Mask", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * FPDT - Firmware Performance Data Table (ACPI 5.0) + * + ******************************************************************************/ + +/* Main table consists of only the standard ACPI header - subtables follow */ + +/* FPDT subtable header */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFpdtHdr[] = +{ + {ACPI_DMT_UINT16, ACPI_FPDTH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_FPDTH_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT8, ACPI_FPDTH_OFFSET (Revision), "Revision", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 0: Firmware Basic Boot Performance Record */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt0[] = +{ + {ACPI_DMT_UINT32, ACPI_FPDT0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_FPDT0_OFFSET (ResetEnd), "Reset End", 0}, + {ACPI_DMT_UINT64, ACPI_FPDT0_OFFSET (LoadStart), "Load Image Start", 0}, + {ACPI_DMT_UINT64, ACPI_FPDT0_OFFSET (StartupStart), "Start Image Start", 0}, + {ACPI_DMT_UINT64, ACPI_FPDT0_OFFSET (ExitServicesEntry), "Exit Services Entry", 0}, + {ACPI_DMT_UINT64, ACPI_FPDT0_OFFSET (ExitServicesExit), "Exit Services Exit", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: S3 Performance Table Pointer Record */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt1[] = +{ + {ACPI_DMT_UINT32, ACPI_FPDT1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_FPDT1_OFFSET (Address), "S3PT Address", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * GTDT - Generic Timer Description Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt[] = +{ + {ACPI_DMT_UINT64, ACPI_GTDT_OFFSET (CounterBlockAddresss), "Counter Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_NEW_LINE, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (SecureEl1Interrupt), "Secure EL1 Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (SecureEl1Flags), "EL1 Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_GTDT_FLAG_OFFSET (SecureEl1Flags,0), "Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT_FLAG_OFFSET (SecureEl1Flags,0), "Polarity", 0}, + {ACPI_DMT_FLAG2, ACPI_GTDT_FLAG_OFFSET (SecureEl1Flags,0), "Always On", 0}, + ACPI_DMT_NEW_LINE, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (NonSecureEl1Interrupt), "Non-Secure EL1 Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (NonSecureEl1Flags), "NEL1 Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_GTDT_FLAG_OFFSET (NonSecureEl1Flags,0),"Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT_FLAG_OFFSET (NonSecureEl1Flags,0),"Polarity", 0}, + {ACPI_DMT_FLAG2, ACPI_GTDT_FLAG_OFFSET (NonSecureEl1Flags,0),"Always On", 0}, + ACPI_DMT_NEW_LINE, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (VirtualTimerInterrupt), "Virtual Timer Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (VirtualTimerFlags), "VT Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_GTDT_FLAG_OFFSET (VirtualTimerFlags,0),"Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT_FLAG_OFFSET (VirtualTimerFlags,0),"Polarity", 0}, + {ACPI_DMT_FLAG2, ACPI_GTDT_FLAG_OFFSET (VirtualTimerFlags,0),"Always On", 0}, + ACPI_DMT_NEW_LINE, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (NonSecureEl2Interrupt), "Non-Secure EL2 Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (NonSecureEl2Flags), "NEL2 Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_GTDT_FLAG_OFFSET (NonSecureEl2Flags,0),"Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT_FLAG_OFFSET (NonSecureEl2Flags,0),"Polarity", 0}, + {ACPI_DMT_FLAG2, ACPI_GTDT_FLAG_OFFSET (NonSecureEl2Flags,0),"Always On", 0}, + {ACPI_DMT_UINT64, ACPI_GTDT_OFFSET (CounterReadBlockAddress), "Counter Read Block Address", 0}, + ACPI_DMT_NEW_LINE, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (PlatformTimerCount), "Platform Timer Count", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT_OFFSET (PlatformTimerOffset), "Platform Timer Offset", 0}, + ACPI_DMT_TERMINATOR +}; + +/* GTDT Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoGtdtHdr[] = +{ + {ACPI_DMT_GTDT, ACPI_GTDTH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT16, ACPI_GTDTH_OFFSET (Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* GTDT Subtables */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt0[] = +{ + {ACPI_DMT_UINT8, ACPI_GTDT0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_GTDT0_OFFSET (BlockAddress), "Block Address", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0_OFFSET (TimerCount), "Timer Count", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0_OFFSET (TimerOffset), "Timer Offset", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt0a[] = +{ + {ACPI_DMT_UINT8 , ACPI_GTDT0a_OFFSET (FrameNumber), "Frame Number", 0}, + {ACPI_DMT_UINT24, ACPI_GTDT0a_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_GTDT0a_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_GTDT0a_OFFSET (El0BaseAddress), "EL0 Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0a_OFFSET (TimerInterrupt), "Timer Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0a_OFFSET (TimerFlags), "Timer Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_GTDT0a_FLAG_OFFSET (TimerFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT0a_FLAG_OFFSET (TimerFlags,0), "Polarity", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0a_OFFSET (VirtualTimerInterrupt), "Virtual Timer Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0a_OFFSET (VirtualTimerFlags), "Virtual Timer Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_GTDT0a_FLAG_OFFSET (VirtualTimerFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT0a_FLAG_OFFSET (VirtualTimerFlags,0), "Polarity", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT0a_OFFSET (CommonFlags), "Common Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_GTDT0a_FLAG_OFFSET (CommonFlags,0), "Secure", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT0a_FLAG_OFFSET (CommonFlags,0), "Always On", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt1[] = +{ + {ACPI_DMT_UINT8, ACPI_GTDT1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_GTDT1_OFFSET (RefreshFrameAddress), "Refresh Frame Address", 0}, + {ACPI_DMT_UINT64, ACPI_GTDT1_OFFSET (ControlFrameAddress), "Control Frame Address", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT1_OFFSET (TimerInterrupt), "Timer Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_GTDT1_OFFSET (TimerFlags), "Timer Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_GTDT1_FLAG_OFFSET (TimerFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_GTDT1_FLAG_OFFSET (TimerFlags,0), "Polarity", 0}, + {ACPI_DMT_FLAG2, ACPI_GTDT1_FLAG_OFFSET (TimerFlags,0), "Security", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * HEST - Hardware Error Source table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest[] = +{ + {ACPI_DMT_UINT32, ACPI_HEST_OFFSET (ErrorSourceCount), "Error Source Count", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common HEST structures for subtables */ + +#define ACPI_DM_HEST_HEADER \ + {ACPI_DMT_HEST, ACPI_HEST0_OFFSET (Header.Type), "Subtable Type", 0}, \ + {ACPI_DMT_UINT16, ACPI_HEST0_OFFSET (Header.SourceId), "Source Id", 0} + +#define ACPI_DM_HEST_AER \ + {ACPI_DMT_UINT16, ACPI_HEST6_OFFSET (Aer.Reserved1), "Reserved", 0}, \ + {ACPI_DMT_UINT8, ACPI_HEST6_OFFSET (Aer.Flags), "Flags (decoded below)", DT_FLAG}, \ + {ACPI_DMT_FLAG0, ACPI_HEST6_FLAG_OFFSET (Aer.Flags,0), "Firmware First", 0}, \ + {ACPI_DMT_UINT8, ACPI_HEST6_OFFSET (Aer.Enabled), "Enabled", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.RecordsToPreallocate), "Records To Preallocate", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.MaxSectionsPerRecord), "Max Sections Per Record", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.Bus), "Bus", 0}, \ + {ACPI_DMT_UINT16, ACPI_HEST6_OFFSET (Aer.Device), "Device", 0}, \ + {ACPI_DMT_UINT16, ACPI_HEST6_OFFSET (Aer.Function), "Function", 0}, \ + {ACPI_DMT_UINT16, ACPI_HEST6_OFFSET (Aer.DeviceControl), "DeviceControl", 0}, \ + {ACPI_DMT_UINT16, ACPI_HEST6_OFFSET (Aer.Reserved2), "Reserved", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.UncorrectableMask), "Uncorrectable Mask", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.UncorrectableSeverity), "Uncorrectable Severity", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.CorrectableMask), "Correctable Mask", 0}, \ + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (Aer.AdvancedCapabilities), "Advanced Capabilities", 0} + + +/* HEST Subtables */ + +/* 0: IA32 Machine Check Exception */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest0[] = +{ + ACPI_DM_HEST_HEADER, + {ACPI_DMT_UINT16, ACPI_HEST0_OFFSET (Reserved1), "Reserved1", 0}, + {ACPI_DMT_UINT8, ACPI_HEST0_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_HEST0_FLAG_OFFSET (Flags,0), "Firmware First", 0}, + + {ACPI_DMT_UINT8, ACPI_HEST0_OFFSET (Enabled), "Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_HEST0_OFFSET (RecordsToPreallocate), "Records To Preallocate", 0}, + {ACPI_DMT_UINT32, ACPI_HEST0_OFFSET (MaxSectionsPerRecord), "Max Sections Per Record", 0}, + {ACPI_DMT_UINT64, ACPI_HEST0_OFFSET (GlobalCapabilityData), "Global Capability Data", 0}, + {ACPI_DMT_UINT64, ACPI_HEST0_OFFSET (GlobalControlData), "Global Control Data", 0}, + {ACPI_DMT_UINT8, ACPI_HEST0_OFFSET (NumHardwareBanks), "Num Hardware Banks", 0}, + {ACPI_DMT_UINT56, ACPI_HEST0_OFFSET (Reserved3[0]), "Reserved2", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: IA32 Corrected Machine Check */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest1[] = +{ + ACPI_DM_HEST_HEADER, + {ACPI_DMT_UINT16, ACPI_HEST1_OFFSET (Reserved1), "Reserved1", 0}, + {ACPI_DMT_UINT8, ACPI_HEST1_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_HEST1_FLAG_OFFSET (Flags,0), "Firmware First", 0}, + + {ACPI_DMT_UINT8, ACPI_HEST1_OFFSET (Enabled), "Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_HEST1_OFFSET (RecordsToPreallocate), "Records To Preallocate", 0}, + {ACPI_DMT_UINT32, ACPI_HEST1_OFFSET (MaxSectionsPerRecord), "Max Sections Per Record", 0}, + {ACPI_DMT_HESTNTFY, ACPI_HEST1_OFFSET (Notify), "Notify", 0}, + {ACPI_DMT_UINT8, ACPI_HEST1_OFFSET (NumHardwareBanks), "Num Hardware Banks", 0}, + {ACPI_DMT_UINT24, ACPI_HEST1_OFFSET (Reserved2[0]), "Reserved2", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: IA32 Non-Maskable Interrupt */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest2[] = +{ + ACPI_DM_HEST_HEADER, + {ACPI_DMT_UINT32, ACPI_HEST2_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_HEST2_OFFSET (RecordsToPreallocate), "Records To Preallocate", 0}, + {ACPI_DMT_UINT32, ACPI_HEST2_OFFSET (MaxSectionsPerRecord), "Max Sections Per Record", 0}, + {ACPI_DMT_UINT32, ACPI_HEST2_OFFSET (MaxRawDataLength), "Max Raw Data Length", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 6: PCI Express Root Port AER */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest6[] = +{ + ACPI_DM_HEST_HEADER, + ACPI_DM_HEST_AER, + {ACPI_DMT_UINT32, ACPI_HEST6_OFFSET (RootErrorCommand), "Root Error Command", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 7: PCI Express AER (AER Endpoint) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest7[] = +{ + ACPI_DM_HEST_HEADER, + ACPI_DM_HEST_AER, + ACPI_DMT_TERMINATOR +}; + +/* 8: PCI Express/PCI-X Bridge AER */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest8[] = +{ + ACPI_DM_HEST_HEADER, + ACPI_DM_HEST_AER, + {ACPI_DMT_UINT32, ACPI_HEST8_OFFSET (UncorrectableMask2), "2nd Uncorrectable Mask", 0}, + {ACPI_DMT_UINT32, ACPI_HEST8_OFFSET (UncorrectableSeverity2), "2nd Uncorrectable Severity", 0}, + {ACPI_DMT_UINT32, ACPI_HEST8_OFFSET (AdvancedCapabilities2), "2nd Advanced Capabilities", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 9: Generic Hardware Error Source */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHest9[] = +{ + ACPI_DM_HEST_HEADER, + {ACPI_DMT_UINT16, ACPI_HEST9_OFFSET (RelatedSourceId), "Related Source Id", 0}, + {ACPI_DMT_UINT8, ACPI_HEST9_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT8, ACPI_HEST9_OFFSET (Enabled), "Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_HEST9_OFFSET (RecordsToPreallocate), "Records To Preallocate", 0}, + {ACPI_DMT_UINT32, ACPI_HEST9_OFFSET (MaxSectionsPerRecord), "Max Sections Per Record", 0}, + {ACPI_DMT_UINT32, ACPI_HEST9_OFFSET (MaxRawDataLength), "Max Raw Data Length", 0}, + {ACPI_DMT_GAS, ACPI_HEST9_OFFSET (ErrorStatusAddress), "Error Status Address", 0}, + {ACPI_DMT_HESTNTFY, ACPI_HEST9_OFFSET (Notify), "Notify", 0}, + {ACPI_DMT_UINT32, ACPI_HEST9_OFFSET (ErrorBlockLength), "Error Status Block Length", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoHestNotify[] = +{ + {ACPI_DMT_HESTNTYP, ACPI_HESTN_OFFSET (Type), "Notify Type", 0}, + {ACPI_DMT_UINT8, ACPI_HESTN_OFFSET (Length), "Notify Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_HESTN_OFFSET (ConfigWriteEnable), "Configuration Write Enable", 0}, + {ACPI_DMT_UINT32, ACPI_HESTN_OFFSET (PollInterval), "PollInterval", 0}, + {ACPI_DMT_UINT32, ACPI_HESTN_OFFSET (Vector), "Vector", 0}, + {ACPI_DMT_UINT32, ACPI_HESTN_OFFSET (PollingThresholdValue), "Polling Threshold Value", 0}, + {ACPI_DMT_UINT32, ACPI_HESTN_OFFSET (PollingThresholdWindow), "Polling Threshold Window", 0}, + {ACPI_DMT_UINT32, ACPI_HESTN_OFFSET (ErrorThresholdValue), "Error Threshold Value", 0}, + {ACPI_DMT_UINT32, ACPI_HESTN_OFFSET (ErrorThresholdWindow), "Error Threshold Window", 0}, + ACPI_DMT_TERMINATOR +}; + + +/* + * IA32 Error Bank(s) - Follows the ACPI_HEST_IA_MACHINE_CHECK and + * ACPI_HEST_IA_CORRECTED structures. + */ +ACPI_DMTABLE_INFO AcpiDmTableInfoHestBank[] = +{ + {ACPI_DMT_UINT8, ACPI_HESTB_OFFSET (BankNumber), "Bank Number", 0}, + {ACPI_DMT_UINT8, ACPI_HESTB_OFFSET (ClearStatusOnInit), "Clear Status On Init", 0}, + {ACPI_DMT_UINT8, ACPI_HESTB_OFFSET (StatusFormat), "Status Format", 0}, + {ACPI_DMT_UINT8, ACPI_HESTB_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_HESTB_OFFSET (ControlRegister), "Control Register", 0}, + {ACPI_DMT_UINT64, ACPI_HESTB_OFFSET (ControlData), "Control Data", 0}, + {ACPI_DMT_UINT32, ACPI_HESTB_OFFSET (StatusRegister), "Status Register", 0}, + {ACPI_DMT_UINT32, ACPI_HESTB_OFFSET (AddressRegister), "Address Register", 0}, + {ACPI_DMT_UINT32, ACPI_HESTB_OFFSET (MiscRegister), "Misc Register", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * HPET - High Precision Event Timer table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoHpet[] = +{ + {ACPI_DMT_UINT32, ACPI_HPET_OFFSET (Id), "Hardware Block ID", 0}, + {ACPI_DMT_GAS, ACPI_HPET_OFFSET (Address), "Timer Block Register", 0}, + {ACPI_DMT_UINT8, ACPI_HPET_OFFSET (Sequence), "Sequence Number", 0}, + {ACPI_DMT_UINT16, ACPI_HPET_OFFSET (MinimumTick), "Minimum Clock Ticks", 0}, + {ACPI_DMT_UINT8, ACPI_HPET_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_HPET_FLAG_OFFSET (Flags,0), "4K Page Protect", 0}, + {ACPI_DMT_FLAG1, ACPI_HPET_FLAG_OFFSET (Flags,0), "64K Page Protect", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * IORT - IO Remapping Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort[] = +{ + {ACPI_DMT_UINT32, ACPI_IORT_OFFSET (NodeCount), "Node Count", 0}, + {ACPI_DMT_UINT32, ACPI_IORT_OFFSET (NodeOffset), "Node Offset", 0}, + {ACPI_DMT_UINT32, ACPI_IORT_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Optional padding field */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIortPad[] = +{ + {ACPI_DMT_RAW_BUFFER, 0, "Optional Padding", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIortHdr[] = +{ + {ACPI_DMT_UINT8, ACPI_IORTH_OFFSET (Type), "Type", 0}, + {ACPI_DMT_UINT16, ACPI_IORTH_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT8, ACPI_IORTH_OFFSET (Revision), "Revision", 0}, + {ACPI_DMT_UINT32, ACPI_IORTH_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_IORTH_OFFSET (MappingCount), "Mapping Count", 0}, + {ACPI_DMT_UINT32, ACPI_IORTH_OFFSET (MappingOffset), "Mapping Offset", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIortMap[] = +{ + {ACPI_DMT_UINT32, ACPI_IORTM_OFFSET (InputBase), "Input base", DT_OPTIONAL}, + {ACPI_DMT_UINT32, ACPI_IORTM_OFFSET (IdCount), "ID Count", 0}, + {ACPI_DMT_UINT32, ACPI_IORTM_OFFSET (OutputBase), "Output Base", 0}, + {ACPI_DMT_UINT32, ACPI_IORTM_OFFSET (OutputReference), "Output Reference", 0}, + {ACPI_DMT_UINT32, ACPI_IORTM_OFFSET (Flags), "Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_IORTM_FLAG_OFFSET (Flags, 0), "Single Mapping", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIortAcc[] = +{ + {ACPI_DMT_UINT32, ACPI_IORTA_OFFSET (CacheCoherency), "Cache Coherency", 0}, + {ACPI_DMT_UINT8, ACPI_IORTA_OFFSET (Hints), "Hints (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_IORTA_FLAG_OFFSET (Hints, 0), "Transient", 0}, + {ACPI_DMT_FLAG1, ACPI_IORTA_FLAG_OFFSET (Hints, 0), "Write Allocate", 0}, + {ACPI_DMT_FLAG2, ACPI_IORTA_FLAG_OFFSET (Hints, 0), "Read Allocate", 0}, + {ACPI_DMT_FLAG3, ACPI_IORTA_FLAG_OFFSET (Hints, 0), "Override", 0}, + {ACPI_DMT_UINT16, ACPI_IORTA_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT8, ACPI_IORTA_OFFSET (MemoryFlags), "Memory Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_IORTA_FLAG_OFFSET (MemoryFlags, 0), "Coherency", 0}, + {ACPI_DMT_FLAG1, ACPI_IORTA_FLAG_OFFSET (MemoryFlags, 0), "Device Attribute", 0}, + ACPI_DMT_TERMINATOR +}; + +/* IORT subtables */ + +/* 0x00: ITS Group */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort0[] = +{ + {ACPI_DMT_UINT32, ACPI_IORT0_OFFSET (ItsCount), "ItsCount", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort0a[] = +{ + {ACPI_DMT_UINT32, 0, "Identifiers", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +/* 0x01: Named Component */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort1[] = +{ + {ACPI_DMT_UINT32, ACPI_IORT1_OFFSET (NodeFlags), "Node Flags", 0}, + {ACPI_DMT_IORTMEM, ACPI_IORT1_OFFSET (MemoryProperties), "Memory Properties", 0}, + {ACPI_DMT_UINT8, ACPI_IORT1_OFFSET (MemoryAddressLimit), "Memory Size Limit", 0}, + {ACPI_DMT_STRING, ACPI_IORT1_OFFSET (DeviceName[0]), "Device Name", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort1a[] = +{ + {ACPI_DMT_RAW_BUFFER, 0, "Padding", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +/* 0x02: PCI Root Complex */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort2[] = +{ + {ACPI_DMT_IORTMEM, ACPI_IORT2_OFFSET (MemoryProperties), "Memory Properties", 0}, + {ACPI_DMT_UINT32, ACPI_IORT2_OFFSET (AtsAttribute), "ATS Attribute", 0}, + {ACPI_DMT_UINT32, ACPI_IORT2_OFFSET (PciSegmentNumber), "PCI Segment Number", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 0x03: SMMUv1/2 */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort3[] = +{ + {ACPI_DMT_UINT64, ACPI_IORT3_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_IORT3_OFFSET (Span), "Span", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (Model), "Model", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (Flags), "Flags (decoded below)", 0}, + {ACPI_DMT_FLAG0, ACPI_IORT3_FLAG_OFFSET (Flags, 0), "DVM Supported", 0}, + {ACPI_DMT_FLAG1, ACPI_IORT3_FLAG_OFFSET (Flags, 0), "Coherent Walk", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (GlobalInterruptOffset), "Global Interrupt Offset", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (ContextInterruptCount), "Context Interrupt Count", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (ContextInterruptOffset), "Context Interrupt Offset", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (PmuInterruptCount), "PMU Interrupt Count", 0}, + {ACPI_DMT_UINT32, ACPI_IORT3_OFFSET (PmuInterruptOffset), "PMU Interrupt Offset", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort3a[] = +{ + {ACPI_DMT_UINT64, 0, "SMMU_NSgIrpt Interrupt", 0}, + {ACPI_DMT_UINT64, 0, "SMMU_NSgCfgIrpt Interrupt", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort3b[] = +{ + {ACPI_DMT_UINT64, 0, "Context Interrupt", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoIort3c[] = +{ + {ACPI_DMT_UINT64, 0, "PMU Interrupt", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * IVRS - I/O Virtualization Reporting Structure + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs[] = +{ + {ACPI_DMT_UINT32, ACPI_IVRS_OFFSET (Info), "Virtualization Info", 0}, + {ACPI_DMT_UINT64, ACPI_IVRS_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrsHdr[] = +{ + {ACPI_DMT_IVRS, ACPI_IVRSH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_IVRSH_OFFSET (Flags), "Flags", 0}, + {ACPI_DMT_UINT16, ACPI_IVRSH_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_IVRSH_OFFSET (DeviceId), "DeviceId", 0}, + ACPI_DMT_TERMINATOR +}; + +/* IVRS subtables */ + +/* 0x10: I/O Virtualization Hardware Definition (IVHD) Block */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs0[] = +{ + {ACPI_DMT_UINT16, ACPI_IVRS0_OFFSET (CapabilityOffset), "Capability Offset", 0}, + {ACPI_DMT_UINT64, ACPI_IVRS0_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT16, ACPI_IVRS0_OFFSET (PciSegmentGroup), "PCI Segment Group", 0}, + {ACPI_DMT_UINT16, ACPI_IVRS0_OFFSET (Info), "Virtualization Info", 0}, + {ACPI_DMT_UINT32, ACPI_IVRS0_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 0x20, 0x21, 0x22: I/O Virtualization Memory Definition (IVMD) Block */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs1[] = +{ + {ACPI_DMT_UINT16, ACPI_IVRS1_OFFSET (AuxData), "Auxiliary Data", 0}, + {ACPI_DMT_UINT64, ACPI_IVRS1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_IVRS1_OFFSET (StartAddress), "Start Address", 0}, + {ACPI_DMT_UINT64, ACPI_IVRS1_OFFSET (MemoryLength), "Memory Length", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Device entry header for IVHD block */ + +#define ACPI_DMT_IVRS_DE_HEADER \ + {ACPI_DMT_UINT8, ACPI_IVRSD_OFFSET (Type), "Entry Type", 0}, \ + {ACPI_DMT_UINT16, ACPI_IVRSD_OFFSET (Id), "Device ID", 0}, \ + {ACPI_DMT_UINT8, ACPI_IVRSD_OFFSET (DataSetting), "Data Setting", 0} + +/* 4-byte device entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs4[] = +{ + ACPI_DMT_IVRS_DE_HEADER, + {ACPI_DMT_EXIT, 0, NULL, 0}, +}; + +/* 8-byte device entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8a[] = +{ + ACPI_DMT_IVRS_DE_HEADER, + {ACPI_DMT_UINT8, ACPI_IVRS8A_OFFSET (Reserved1), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_IVRS8A_OFFSET (UsedId), "Source Used Device ID", 0}, + {ACPI_DMT_UINT8, ACPI_IVRS8A_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 8-byte device entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8b[] = +{ + ACPI_DMT_IVRS_DE_HEADER, + {ACPI_DMT_UINT32, ACPI_IVRS8B_OFFSET (ExtendedData), "Extended Data", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 8-byte device entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8c[] = +{ + ACPI_DMT_IVRS_DE_HEADER, + {ACPI_DMT_UINT8, ACPI_IVRS8C_OFFSET (Handle), "Handle", 0}, + {ACPI_DMT_UINT16, ACPI_IVRS8C_OFFSET (UsedId), "Source Used Device ID", 0}, + {ACPI_DMT_UINT8, ACPI_IVRS8C_OFFSET (Variety), "Variety", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * LPIT - Low Power Idle Table + * + ******************************************************************************/ + +/* Main table consists only of the standard ACPI table header */ + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoLpitHdr[] = +{ + {ACPI_DMT_LPIT, ACPI_LPITH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT32, ACPI_LPITH_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_LPITH_OFFSET (UniqueId), "Unique ID", 0}, + {ACPI_DMT_UINT16, ACPI_LPITH_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_LPITH_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_LPITH_FLAG_OFFSET (Flags, 0), "State Disabled", 0}, + {ACPI_DMT_FLAG1, ACPI_LPITH_FLAG_OFFSET (Flags, 0), "No Counter", 0}, + ACPI_DMT_TERMINATOR +}; + +/* LPIT Subtables */ + +/* 0: Native C-state */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoLpit0[] = +{ + {ACPI_DMT_GAS, ACPI_LPIT0_OFFSET (EntryTrigger), "Entry Trigger", 0}, + {ACPI_DMT_UINT32, ACPI_LPIT0_OFFSET (Residency), "Residency", 0}, + {ACPI_DMT_UINT32, ACPI_LPIT0_OFFSET (Latency), "Latency", 0}, + {ACPI_DMT_GAS, ACPI_LPIT0_OFFSET (ResidencyCounter), "Residency Counter", 0}, + {ACPI_DMT_UINT64, ACPI_LPIT0_OFFSET (CounterFrequency), "Counter Frequency", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * MADT - Multiple APIC Description Table and subtables + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt[] = +{ + {ACPI_DMT_UINT32, ACPI_MADT_OFFSET (Address), "Local Apic Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT_FLAG_OFFSET (Flags,0), "PC-AT Compatibility", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadtHdr[] = +{ + {ACPI_DMT_MADT, ACPI_MADTH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_MADTH_OFFSET (Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* MADT Subtables */ + +/* 0: processor APIC */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt0[] = +{ + {ACPI_DMT_UINT8, ACPI_MADT0_OFFSET (ProcessorId), "Processor ID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT0_OFFSET (Id), "Local Apic ID", 0}, + {ACPI_DMT_UINT32, ACPI_MADT0_OFFSET (LapicFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT0_FLAG_OFFSET (LapicFlags,0), "Processor Enabled", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: IO APIC */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt1[] = +{ + {ACPI_DMT_UINT8, ACPI_MADT1_OFFSET (Id), "I/O Apic ID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT1_OFFSET (Address), "Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT1_OFFSET (GlobalIrqBase), "Interrupt", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: Interrupt Override */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt2[] = +{ + {ACPI_DMT_UINT8, ACPI_MADT2_OFFSET (Bus), "Bus", 0}, + {ACPI_DMT_UINT8, ACPI_MADT2_OFFSET (SourceIrq), "Source", 0}, + {ACPI_DMT_UINT32, ACPI_MADT2_OFFSET (GlobalIrq), "Interrupt", 0}, + {ACPI_DMT_UINT16, ACPI_MADT2_OFFSET (IntiFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAGS0, ACPI_MADT2_FLAG_OFFSET (IntiFlags,0), "Polarity", 0}, + {ACPI_DMT_FLAGS2, ACPI_MADT2_FLAG_OFFSET (IntiFlags,0), "Trigger Mode", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 3: NMI Sources */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt3[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT3_OFFSET (IntiFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAGS0, ACPI_MADT3_FLAG_OFFSET (IntiFlags,0), "Polarity", 0}, + {ACPI_DMT_FLAGS2, ACPI_MADT3_FLAG_OFFSET (IntiFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_UINT32, ACPI_MADT3_OFFSET (GlobalIrq), "Interrupt", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 4: Local APIC NMI */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt4[] = +{ + {ACPI_DMT_UINT8, ACPI_MADT4_OFFSET (ProcessorId), "Processor ID", 0}, + {ACPI_DMT_UINT16, ACPI_MADT4_OFFSET (IntiFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAGS0, ACPI_MADT4_FLAG_OFFSET (IntiFlags,0), "Polarity", 0}, + {ACPI_DMT_FLAGS2, ACPI_MADT4_FLAG_OFFSET (IntiFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_UINT8, ACPI_MADT4_OFFSET (Lint), "Interrupt Input LINT", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 5: Address Override */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt5[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT5_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_MADT5_OFFSET (Address), "APIC Address", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 6: I/O Sapic */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt6[] = +{ + {ACPI_DMT_UINT8, ACPI_MADT6_OFFSET (Id), "I/O Sapic ID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT6_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT6_OFFSET (GlobalIrqBase), "Interrupt Base", 0}, + {ACPI_DMT_UINT64, ACPI_MADT6_OFFSET (Address), "Address", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 7: Local Sapic */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt7[] = +{ + {ACPI_DMT_UINT8, ACPI_MADT7_OFFSET (ProcessorId), "Processor ID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT7_OFFSET (Id), "Local Sapic ID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT7_OFFSET (Eid), "Local Sapic EID", 0}, + {ACPI_DMT_UINT24, ACPI_MADT7_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT7_OFFSET (LapicFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT7_FLAG_OFFSET (LapicFlags,0), "Processor Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_MADT7_OFFSET (Uid), "Processor UID", 0}, + {ACPI_DMT_STRING, ACPI_MADT7_OFFSET (UidString[0]), "Processor UID String", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 8: Platform Interrupt Source */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt8[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT8_OFFSET (IntiFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAGS0, ACPI_MADT8_FLAG_OFFSET (IntiFlags,0), "Polarity", 0}, + {ACPI_DMT_FLAGS2, ACPI_MADT8_FLAG_OFFSET (IntiFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_UINT8, ACPI_MADT8_OFFSET (Type), "InterruptType", 0}, + {ACPI_DMT_UINT8, ACPI_MADT8_OFFSET (Id), "Processor ID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT8_OFFSET (Eid), "Processor EID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT8_OFFSET (IoSapicVector), "I/O Sapic Vector", 0}, + {ACPI_DMT_UINT32, ACPI_MADT8_OFFSET (GlobalIrq), "Interrupt", 0}, + {ACPI_DMT_UINT32, ACPI_MADT8_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT8_OFFSET (Flags), "CPEI Override", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 9: Processor Local X2_APIC (ACPI 4.0) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt9[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT9_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT9_OFFSET (LocalApicId), "Processor x2Apic ID", 0}, + {ACPI_DMT_UINT32, ACPI_MADT9_OFFSET (LapicFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT9_FLAG_OFFSET (LapicFlags,0), "Processor Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_MADT9_OFFSET (Uid), "Processor UID", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 10: Local X2_APIC NMI (ACPI 4.0) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt10[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT10_OFFSET (IntiFlags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAGS0, ACPI_MADT10_FLAG_OFFSET (IntiFlags,0), "Polarity", 0}, + {ACPI_DMT_FLAGS2, ACPI_MADT10_FLAG_OFFSET (IntiFlags,0), "Trigger Mode", 0}, + {ACPI_DMT_UINT32, ACPI_MADT10_OFFSET (Uid), "Processor UID", 0}, + {ACPI_DMT_UINT8, ACPI_MADT10_OFFSET (Lint), "Interrupt Input LINT", 0}, + {ACPI_DMT_UINT24, ACPI_MADT10_OFFSET (Reserved[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 11: Generic Interrupt Controller (ACPI 5.0) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt11[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT11_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT11_OFFSET (CpuInterfaceNumber), "CPU Interface Number", 0}, + {ACPI_DMT_UINT32, ACPI_MADT11_OFFSET (Uid), "Processor UID", 0}, + {ACPI_DMT_UINT32, ACPI_MADT11_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT11_FLAG_OFFSET (Flags,0), "Processor Enabled", 0}, + {ACPI_DMT_FLAG1, ACPI_MADT11_FLAG_OFFSET (Flags,0), "Performance Interrupt Trigger Mode", 0}, + {ACPI_DMT_FLAG2, ACPI_MADT11_FLAG_OFFSET (Flags,0), "Virtual GIC Interrupt Trigger Mode", 0}, + {ACPI_DMT_UINT32, ACPI_MADT11_OFFSET (ParkingVersion), "Parking Protocol Version", 0}, + {ACPI_DMT_UINT32, ACPI_MADT11_OFFSET (PerformanceInterrupt), "Performance Interrupt", 0}, + {ACPI_DMT_UINT64, ACPI_MADT11_OFFSET (ParkedAddress), "Parked Address", 0}, + {ACPI_DMT_UINT64, ACPI_MADT11_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_MADT11_OFFSET (GicvBaseAddress), "Virtual GIC Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_MADT11_OFFSET (GichBaseAddress), "Hypervisor GIC Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT11_OFFSET (VgicInterrupt), "Virtual GIC Interrupt", 0}, + {ACPI_DMT_UINT64, ACPI_MADT11_OFFSET (GicrBaseAddress), "Redistributor Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_MADT11_OFFSET (ArmMpidr), "ARM MPIDR", 0}, + {ACPI_DMT_UINT8, ACPI_MADT11_OFFSET (EfficiencyClass), "Efficiency Class", 0}, + {ACPI_DMT_UINT24, ACPI_MADT11_OFFSET (Reserved2[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 12: Generic Interrupt Distributor (ACPI 5.0) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt12[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT12_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT12_OFFSET (GicId), "Local GIC Hardware ID", 0}, + {ACPI_DMT_UINT64, ACPI_MADT12_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT12_OFFSET (GlobalIrqBase), "Interrupt Base", 0}, + {ACPI_DMT_UINT8, ACPI_MADT12_OFFSET (Version), "Version", 0}, + {ACPI_DMT_UINT24, ACPI_MADT12_OFFSET (Reserved2[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 13: Generic MSI Frame (ACPI 5.1) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt13[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT13_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT13_OFFSET (MsiFrameId), "MSI Frame ID", 0}, + {ACPI_DMT_UINT64, ACPI_MADT13_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT13_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MADT13_FLAG_OFFSET (Flags,0), "Select SPI", 0}, + {ACPI_DMT_UINT16, ACPI_MADT13_OFFSET (SpiCount), "SPI Count", 0}, + {ACPI_DMT_UINT16, ACPI_MADT13_OFFSET (SpiBase), "SPI Base", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 14: Generic Redistributor (ACPI 5.1) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt14[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT14_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_MADT14_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT14_OFFSET (Length), "Length", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 15: Generic Translator (ACPI 6.0) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMadt15[] = +{ + {ACPI_DMT_UINT16, ACPI_MADT15_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MADT15_OFFSET (TranslationId), "Translation ID", 0}, + {ACPI_DMT_UINT64, ACPI_MADT15_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT32, ACPI_MADT15_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/******************************************************************************* + * + * MCFG - PCI Memory Mapped Configuration table and Subtable + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMcfg[] = +{ + {ACPI_DMT_UINT64, ACPI_MCFG_OFFSET (Reserved[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoMcfg0[] = +{ + {ACPI_DMT_UINT64, ACPI_MCFG0_OFFSET (Address), "Base Address", 0}, + {ACPI_DMT_UINT16, ACPI_MCFG0_OFFSET (PciSegment), "Segment Group Number", 0}, + {ACPI_DMT_UINT8, ACPI_MCFG0_OFFSET (StartBusNumber), "Start Bus Number", 0}, + {ACPI_DMT_UINT8, ACPI_MCFG0_OFFSET (EndBusNumber), "End Bus Number", 0}, + {ACPI_DMT_UINT32, ACPI_MCFG0_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * MCHI - Management Controller Host Interface table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMchi[] = +{ + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (InterfaceType), "Interface Type", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (Protocol), "Protocol", 0}, + {ACPI_DMT_UINT64, ACPI_MCHI_OFFSET (ProtocolData), "Protocol Data", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (InterruptType), "Interrupt Type", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (Gpe), "Gpe", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (PciDeviceFlag), "Pci Device Flag", 0}, + {ACPI_DMT_UINT32, ACPI_MCHI_OFFSET (GlobalInterrupt), "Global Interrupt", 0}, + {ACPI_DMT_GAS, ACPI_MCHI_OFFSET (ControlRegister), "Control Register", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (PciSegment), "Pci Segment", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (PciBus), "Pci Bus", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (PciDevice), "Pci Device", 0}, + {ACPI_DMT_UINT8, ACPI_MCHI_OFFSET (PciFunction), "Pci Function", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * MPST - Memory Power State Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMpst[] = +{ + {ACPI_DMT_UINT8, ACPI_MPST_OFFSET (ChannelId), "Channel ID", 0}, + {ACPI_DMT_UINT24, ACPI_MPST_OFFSET (Reserved1[0]), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_MPST_OFFSET (PowerNodeCount), "Power Node Count", 0}, + {ACPI_DMT_UINT16, ACPI_MPST_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* MPST subtables */ + +/* 0: Memory Power Node Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0[] = +{ + {ACPI_DMT_UINT8, ACPI_MPST0_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MPST0_FLAG_OFFSET (Flags,0), "Node Enabled", 0}, + {ACPI_DMT_FLAG1, ACPI_MPST0_FLAG_OFFSET (Flags,0), "Power Managed", 0}, + {ACPI_DMT_FLAG2, ACPI_MPST0_FLAG_OFFSET (Flags,0), "Hot Plug Capable", 0}, + + {ACPI_DMT_UINT8, ACPI_MPST0_OFFSET (Reserved1), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_MPST0_OFFSET (NodeId), "Node ID", 0}, + {ACPI_DMT_UINT32, ACPI_MPST0_OFFSET (Length), "Length", 0}, + {ACPI_DMT_UINT64, ACPI_MPST0_OFFSET (RangeAddress), "Range Address", 0}, + {ACPI_DMT_UINT64, ACPI_MPST0_OFFSET (RangeLength), "Range Length", 0}, + {ACPI_DMT_UINT32, ACPI_MPST0_OFFSET (NumPowerStates), "Num Power States", 0}, + {ACPI_DMT_UINT32, ACPI_MPST0_OFFSET (NumPhysicalComponents), "Num Physical Components", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 0A: Sub-subtable - Memory Power State Structure (follows Memory Power Node above) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0A[] = +{ + {ACPI_DMT_UINT8, ACPI_MPST0A_OFFSET (PowerState), "Power State", 0}, + {ACPI_DMT_UINT8, ACPI_MPST0A_OFFSET (InfoIndex), "InfoIndex", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 0B: Sub-subtable - Physical Component ID Structure (follows Memory Power State(s) above) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0B[] = +{ + {ACPI_DMT_UINT16, ACPI_MPST0B_OFFSET (ComponentId), "Component Id", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 01: Power Characteristics Count (follows all Power Node(s) above) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMpst1[] = +{ + {ACPI_DMT_UINT16, ACPI_MPST1_OFFSET (CharacteristicsCount), "Characteristics Count", 0}, + {ACPI_DMT_UINT16, ACPI_MPST1_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 02: Memory Power State Characteristics Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMpst2[] = +{ + {ACPI_DMT_UINT8, ACPI_MPST2_OFFSET (StructureId), "Structure ID", 0}, + {ACPI_DMT_UINT8, ACPI_MPST2_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_MPST2_FLAG_OFFSET (Flags,0), "Memory Preserved", 0}, + {ACPI_DMT_FLAG1, ACPI_MPST2_FLAG_OFFSET (Flags,0), "Auto Entry", 0}, + {ACPI_DMT_FLAG2, ACPI_MPST2_FLAG_OFFSET (Flags,0), "Auto Exit", 0}, + + {ACPI_DMT_UINT16, ACPI_MPST2_OFFSET (Reserved1), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_MPST2_OFFSET (AveragePower), "Average Power", 0}, + {ACPI_DMT_UINT32, ACPI_MPST2_OFFSET (PowerSaving), "Power Saving", 0}, + {ACPI_DMT_UINT64, ACPI_MPST2_OFFSET (ExitLatency), "Exit Latency", 0}, + {ACPI_DMT_UINT64, ACPI_MPST2_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * MSCT - Maximum System Characteristics Table (ACPI 4.0) + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMsct[] = +{ + {ACPI_DMT_UINT32, ACPI_MSCT_OFFSET (ProximityOffset), "Proximity Offset", 0}, + {ACPI_DMT_UINT32, ACPI_MSCT_OFFSET (MaxProximityDomains), "Max Proximity Domains", 0}, + {ACPI_DMT_UINT32, ACPI_MSCT_OFFSET (MaxClockDomains), "Max Clock Domains", 0}, + {ACPI_DMT_UINT64, ACPI_MSCT_OFFSET (MaxAddress), "Max Physical Address", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Subtable - Maximum Proximity Domain Information. Version 1 */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMsct0[] = +{ + {ACPI_DMT_UINT8, ACPI_MSCT0_OFFSET (Revision), "Revision", 0}, + {ACPI_DMT_UINT8, ACPI_MSCT0_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT32, ACPI_MSCT0_OFFSET (RangeStart), "Domain Range Start", 0}, + {ACPI_DMT_UINT32, ACPI_MSCT0_OFFSET (RangeEnd), "Domain Range End", 0}, + {ACPI_DMT_UINT32, ACPI_MSCT0_OFFSET (ProcessorCapacity), "Processor Capacity", 0}, + {ACPI_DMT_UINT64, ACPI_MSCT0_OFFSET (MemoryCapacity), "Memory Capacity", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * MTMR - MID Timer Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMtmr[] = +{ + ACPI_DMT_TERMINATOR +}; + +/* MTMR Subtables - MTMR Entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoMtmr0[] = +{ + {ACPI_DMT_GAS, ACPI_MTMR0_OFFSET (PhysicalAddress), "PhysicalAddress", 0}, + {ACPI_DMT_UINT32, ACPI_MTMR0_OFFSET (Frequency), "Frequency", 0}, + {ACPI_DMT_UINT32, ACPI_MTMR0_OFFSET (Irq), "IRQ", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * NFIT - NVDIMM Firmware Interface Table and Subtables - (ACPI 6.0) + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit[] = +{ + {ACPI_DMT_UINT32, ACPI_NFIT_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfitHdr[] = +{ + {ACPI_DMT_NFIT, ACPI_NFITH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT16, ACPI_NFITH_OFFSET (Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* 0: System Physical Address Range Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit0[] = +{ + {ACPI_DMT_UINT16, ACPI_NFIT0_OFFSET (RangeIndex), "Range Index", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT0_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_NFIT0_FLAG_OFFSET (Flags,0), "Add/Online Operation Only", 0}, + {ACPI_DMT_FLAG1, ACPI_NFIT0_FLAG_OFFSET (Flags,0), "Proximity Domain Valid", 0}, + {ACPI_DMT_UINT32, ACPI_NFIT0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_NFIT0_OFFSET (ProximityDomain), "Proximity Domain", 0}, + {ACPI_DMT_UUID, ACPI_NFIT0_OFFSET (RangeGuid[0]), "Address Range GUID", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT0_OFFSET (Address), "Address Range Base", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT0_OFFSET (Length), "Address Range Length", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT0_OFFSET (MemoryMapping), "Memory Map Attribute", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: Memory Device to System Address Range Map Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit1[] = +{ + {ACPI_DMT_UINT32, ACPI_NFIT1_OFFSET (DeviceHandle), "Device Handle", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (PhysicalId), "Physical Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (RegionId), "Region Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (RangeIndex), "Range Index", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (RegionIndex), "Control Region Index", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT1_OFFSET (RegionSize), "Region Size", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT1_OFFSET (RegionOffset), "Region Offset", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT1_OFFSET (Address), "Address Region Base", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (InterleaveIndex), "Interleave Index", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (InterleaveWays), "Interleave Ways", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (Flags), "Flags", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_NFIT1_FLAG_OFFSET (Flags,0), "Save to device failed", 0}, + {ACPI_DMT_FLAG1, ACPI_NFIT1_FLAG_OFFSET (Flags,0), "Restore from device failed", 0}, + {ACPI_DMT_FLAG2, ACPI_NFIT1_FLAG_OFFSET (Flags,0), "Platform flush failed", 0}, + {ACPI_DMT_FLAG3, ACPI_NFIT1_FLAG_OFFSET (Flags,0), "Device not armed", 0}, + {ACPI_DMT_FLAG4, ACPI_NFIT1_FLAG_OFFSET (Flags,0), "Health events observed", 0}, + {ACPI_DMT_FLAG5, ACPI_NFIT1_FLAG_OFFSET (Flags,0), "Health events enabled", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT1_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: Interleave Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit2[] = +{ + {ACPI_DMT_UINT16, ACPI_NFIT2_OFFSET (InterleaveIndex), "Interleave Index", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT2_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_NFIT2_OFFSET (LineCount), "Line Count", 0}, + {ACPI_DMT_UINT32, ACPI_NFIT2_OFFSET (LineSize), "Line Size", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit2a[] = +{ + {ACPI_DMT_UINT32, 0, "Line Offset", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +/* 3: SMBIOS Management Information Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit3[] = +{ + {ACPI_DMT_UINT32, ACPI_NFIT3_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit3a[] = +{ + {ACPI_DMT_RAW_BUFFER, 0, "SMBIOS Table Entries", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + +/* 4: NVDIMM Control Region Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit4[] = +{ + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (RegionIndex), "Region Index", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (VendorId), "Vendor Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (DeviceId), "Device Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (RevisionId), "Revision Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (SubsystemVendorId), "Subsystem Vendor Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (SubsystemDeviceId), "Subsystem Device Id", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (SubsystemRevisionId), "Subsystem Revision Id", 0}, + {ACPI_DMT_UINT48, ACPI_NFIT4_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_NFIT4_OFFSET (SerialNumber), "Serial Number", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (Code), "Code", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (Windows), "Window Count", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT4_OFFSET (WindowSize), "Window Size", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT4_OFFSET (CommandOffset), "Command Offset", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT4_OFFSET (CommandSize), "Command Size", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT4_OFFSET (StatusOffset), "Status Offset", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT4_OFFSET (StatusSize), "Status Size", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT4_OFFSET (Flags), "Flags", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_NFIT4_FLAG_OFFSET (Flags,0), "Windows buffered", 0}, + {ACPI_DMT_UINT48, ACPI_NFIT4_OFFSET (Reserved1[0]), "Reserved1", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 5: NVDIMM Block Data Window Region Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit5[] = +{ + {ACPI_DMT_UINT16, ACPI_NFIT5_OFFSET (RegionIndex), "Region Index", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT5_OFFSET (Windows), "Window Count", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT5_OFFSET (Offset), "Offset", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT5_OFFSET (Size), "Size", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT5_OFFSET (Capacity), "Capacity", 0}, + {ACPI_DMT_UINT64, ACPI_NFIT5_OFFSET (StartAddress), "Start Address", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 6: Flush Hint Address Structure */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit6[] = +{ + {ACPI_DMT_UINT32, ACPI_NFIT6_OFFSET (DeviceHandle), "Device Handle", 0}, + {ACPI_DMT_UINT16, ACPI_NFIT6_OFFSET (HintCount), "Hint Count", 0}, + {ACPI_DMT_UINT48, ACPI_NFIT6_OFFSET (Reserved[0]), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoNfit6a[] = +{ + {ACPI_DMT_UINT64, 0, "Hint Address", DT_OPTIONAL}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * PCCT - Platform Communications Channel Table (ACPI 5.0) + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPcct[] = +{ + {ACPI_DMT_UINT32, ACPI_PCCT_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_PCCT_FLAG_OFFSET (Flags,0), "Doorbell", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* PCCT subtables */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPcctHdr[] = +{ + {ACPI_DMT_PCCT, ACPI_PCCT0_OFFSET (Header.Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_PCCT0_OFFSET (Header.Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* 0: Generic Communications Subspace */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPcct0[] = +{ + {ACPI_DMT_UINT48, ACPI_PCCT0_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT0_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT0_OFFSET (Length), "Address Length", 0}, + {ACPI_DMT_GAS, ACPI_PCCT0_OFFSET (DoorbellRegister), "Doorbell Register", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT0_OFFSET (PreserveMask), "Preserve Mask", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT0_OFFSET (WriteMask), "Write Mask", 0}, + {ACPI_DMT_UINT32, ACPI_PCCT0_OFFSET (Latency), "Command Latency", 0}, + {ACPI_DMT_UINT32, ACPI_PCCT0_OFFSET (MaxAccessRate), "Maximum Access Rate", 0}, + {ACPI_DMT_UINT16, ACPI_PCCT0_OFFSET (MinTurnaroundTime), "Minimum Turnaround Time", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: HW-reduced Communications Subspace (ACPI 5.1) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPcct1[] = +{ + {ACPI_DMT_UINT32, ACPI_PCCT1_OFFSET (DoorbellInterrupt), "Doorbell Interrupt", 0}, + {ACPI_DMT_UINT8, ACPI_PCCT1_OFFSET (Flags), "Flags (Decoded Below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_PCCT1_FLAG_OFFSET (Flags,0), "Polarity", 0}, + {ACPI_DMT_FLAG1, ACPI_PCCT1_FLAG_OFFSET (Flags,0), "Mode", 0}, + {ACPI_DMT_UINT8, ACPI_PCCT1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT1_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT1_OFFSET (Length), "Address Length", 0}, + {ACPI_DMT_GAS, ACPI_PCCT1_OFFSET (DoorbellRegister), "Doorbell Register", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT1_OFFSET (PreserveMask), "Preserve Mask", 0}, + {ACPI_DMT_UINT64, ACPI_PCCT1_OFFSET (WriteMask), "Write Mask", 0}, + {ACPI_DMT_UINT32, ACPI_PCCT1_OFFSET (Latency), "Command Latency", 0}, + {ACPI_DMT_UINT32, ACPI_PCCT1_OFFSET (MaxAccessRate), "Maximum Access Rate", 0}, + {ACPI_DMT_UINT16, ACPI_PCCT1_OFFSET (MinTurnaroundTime), "Minimum Turnaround Time", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * PMTT - Platform Memory Topology Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt[] = +{ + {ACPI_DMT_UINT32, ACPI_PMTT_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPmttHdr[] = +{ + {ACPI_DMT_PMTT, ACPI_PMTTH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_PMTTH_OFFSET (Reserved1), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_PMTTH_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_PMTTH_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_PMTTH_FLAG_OFFSET (Flags,0), "Top-level Device", 0}, + {ACPI_DMT_FLAG1, ACPI_PMTTH_FLAG_OFFSET (Flags,0), "Physical Element", 0}, + {ACPI_DMT_FLAGS2, ACPI_PMTTH_FLAG_OFFSET (Flags,0), "Memory Type", 0}, + {ACPI_DMT_UINT16, ACPI_PMTTH_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* PMTT Subtables */ + +/* 0: Socket */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt0[] = +{ + {ACPI_DMT_UINT16, ACPI_PMTT0_OFFSET (SocketId), "Socket ID", 0}, + {ACPI_DMT_UINT16, ACPI_PMTT0_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: Memory Controller */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt1[] = +{ + {ACPI_DMT_UINT32, ACPI_PMTT1_OFFSET (ReadLatency), "Read Latency", 0}, + {ACPI_DMT_UINT32, ACPI_PMTT1_OFFSET (WriteLatency), "Write Latency", 0}, + {ACPI_DMT_UINT32, ACPI_PMTT1_OFFSET (ReadBandwidth), "Read Bandwidth", 0}, + {ACPI_DMT_UINT32, ACPI_PMTT1_OFFSET (WriteBandwidth), "Write Bandwidth", 0}, + {ACPI_DMT_UINT16, ACPI_PMTT1_OFFSET (AccessWidth), "Access Width", 0}, + {ACPI_DMT_UINT16, ACPI_PMTT1_OFFSET (Alignment), "Alignment", 0}, + {ACPI_DMT_UINT16, ACPI_PMTT1_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_PMTT1_OFFSET (DomainCount), "Domain Count", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1a: Proximity Domain */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt1a[] = +{ + {ACPI_DMT_UINT32, ACPI_PMTT1A_OFFSET (ProximityDomain), "Proximity Domain", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: Physical Component */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt2[] = +{ + {ACPI_DMT_UINT16, ACPI_PMTT2_OFFSET (ComponentId), "Component ID", 0}, + {ACPI_DMT_UINT16, ACPI_PMTT2_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_PMTT2_OFFSET (MemorySize), "Memory Size", 0}, + {ACPI_DMT_UINT32, ACPI_PMTT2_OFFSET (BiosHandle), "Bios Handle", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * S3PT - S3 Performance Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt[] = +{ + {ACPI_DMT_SIG, ACPI_S3PT_OFFSET (Signature[0]), "Signature", 0}, + {ACPI_DMT_UINT32, ACPI_S3PT_OFFSET (Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* S3PT subtable header */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoS3ptHdr[] = +{ + {ACPI_DMT_UINT16, ACPI_S3PTH_OFFSET (Type), "Type", 0}, + {ACPI_DMT_UINT8, ACPI_S3PTH_OFFSET (Length), "Length", DT_LENGTH}, + {ACPI_DMT_UINT8, ACPI_S3PTH_OFFSET (Revision), "Revision", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 0: Basic S3 Resume Performance Record */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt0[] = +{ + {ACPI_DMT_UINT32, ACPI_S3PT0_OFFSET (ResumeCount), "Resume Count", 0}, + {ACPI_DMT_UINT64, ACPI_S3PT0_OFFSET (FullResume), "Full Resume", 0}, + {ACPI_DMT_UINT64, ACPI_S3PT0_OFFSET (AverageResume), "Average Resume", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: Basic S3 Suspend Performance Record */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt1[] = +{ + {ACPI_DMT_UINT64, ACPI_S3PT1_OFFSET (SuspendStart), "Suspend Start", 0}, + {ACPI_DMT_UINT64, ACPI_S3PT1_OFFSET (SuspendEnd), "Suspend End", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * SBST - Smart Battery Specification Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSbst[] = +{ + {ACPI_DMT_UINT32, ACPI_SBST_OFFSET (WarningLevel), "Warning Level", 0}, + {ACPI_DMT_UINT32, ACPI_SBST_OFFSET (LowLevel), "Low Level", 0}, + {ACPI_DMT_UINT32, ACPI_SBST_OFFSET (CriticalLevel), "Critical Level", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * SLIC - Software Licensing Description Table. This table contains the standard + * ACPI header followed by proprietary data structures + * + ******************************************************************************/ + +/* Single subtable, a proprietary format, so treat it as a buffer */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSlic[] = +{ + {ACPI_DMT_RAW_BUFFER, 0, "Software Licensing Structure", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * SLIT - System Locality Information Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSlit[] = +{ + {ACPI_DMT_UINT64, ACPI_SLIT_OFFSET (LocalityCount), "Localities", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * SPCR - Serial Port Console Redirection table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSpcr[] = +{ + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (InterfaceType), "Interface Type", 0}, + {ACPI_DMT_UINT24, ACPI_SPCR_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_GAS, ACPI_SPCR_OFFSET (SerialPort), "Serial Port Register", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (InterruptType), "Interrupt Type", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (PcInterrupt), "PCAT-compatible IRQ", 0}, + {ACPI_DMT_UINT32, ACPI_SPCR_OFFSET (Interrupt), "Interrupt", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (BaudRate), "Baud Rate", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (Parity), "Parity", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (StopBits), "Stop Bits", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (FlowControl), "Flow Control", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (TerminalType), "Terminal Type", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (Reserved2), "Reserved", 0}, + {ACPI_DMT_UINT16, ACPI_SPCR_OFFSET (PciDeviceId), "PCI Device ID", 0}, + {ACPI_DMT_UINT16, ACPI_SPCR_OFFSET (PciVendorId), "PCI Vendor ID", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (PciBus), "PCI Bus", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (PciDevice), "PCI Device", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (PciFunction), "PCI Function", 0}, + {ACPI_DMT_UINT32, ACPI_SPCR_OFFSET (PciFlags), "PCI Flags", 0}, + {ACPI_DMT_UINT8, ACPI_SPCR_OFFSET (PciSegment), "PCI Segment", 0}, + {ACPI_DMT_UINT32, ACPI_SPCR_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * SPMI - Server Platform Management Interface table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSpmi[] = +{ + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (InterfaceType), "Interface Type", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (Reserved), "Reserved", DT_NON_ZERO}, /* Value must be 1 */ + {ACPI_DMT_UINT16, ACPI_SPMI_OFFSET (SpecRevision), "IPMI Spec Version", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (InterruptType), "Interrupt Type", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (GpeNumber), "GPE Number", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (Reserved1), "Reserved", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (PciDeviceFlag), "PCI Device Flag", 0}, + {ACPI_DMT_UINT32, ACPI_SPMI_OFFSET (Interrupt), "Interrupt", 0}, + {ACPI_DMT_GAS, ACPI_SPMI_OFFSET (IpmiRegister), "IPMI Register", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (PciSegment), "PCI Segment", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (PciBus), "PCI Bus", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (PciDevice), "PCI Device", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (PciFunction), "PCI Function", 0}, + {ACPI_DMT_UINT8, ACPI_SPMI_OFFSET (Reserved2), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * SRAT - System Resource Affinity Table and Subtables + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSrat[] = +{ + {ACPI_DMT_UINT32, ACPI_SRAT_OFFSET (TableRevision), "Table Revision", 0}, + {ACPI_DMT_UINT64, ACPI_SRAT_OFFSET (Reserved), "Reserved", 0}, + ACPI_DMT_TERMINATOR +}; + +/* Common Subtable header (one per Subtable) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSratHdr[] = +{ + {ACPI_DMT_SRAT, ACPI_SRATH_OFFSET (Type), "Subtable Type", 0}, + {ACPI_DMT_UINT8, ACPI_SRATH_OFFSET (Length), "Length", DT_LENGTH}, + ACPI_DMT_TERMINATOR +}; + +/* SRAT Subtables */ + +/* 0: Processor Local APIC/SAPIC Affinity */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSrat0[] = +{ + {ACPI_DMT_UINT8, ACPI_SRAT0_OFFSET (ProximityDomainLo), "Proximity Domain Low(8)", 0}, + {ACPI_DMT_UINT8, ACPI_SRAT0_OFFSET (ApicId), "Apic ID", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT0_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_SRAT0_FLAG_OFFSET (Flags,0), "Enabled", 0}, + {ACPI_DMT_UINT8, ACPI_SRAT0_OFFSET (LocalSapicEid), "Local Sapic EID", 0}, + {ACPI_DMT_UINT24, ACPI_SRAT0_OFFSET (ProximityDomainHi[0]), "Proximity Domain High(24)", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT0_OFFSET (ClockDomain), "Clock Domain", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 1: Memory Affinity */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSrat1[] = +{ + {ACPI_DMT_UINT32, ACPI_SRAT1_OFFSET (ProximityDomain), "Proximity Domain", 0}, + {ACPI_DMT_UINT16, ACPI_SRAT1_OFFSET (Reserved), "Reserved1", 0}, + {ACPI_DMT_UINT64, ACPI_SRAT1_OFFSET (BaseAddress), "Base Address", 0}, + {ACPI_DMT_UINT64, ACPI_SRAT1_OFFSET (Length), "Address Length", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT1_OFFSET (Reserved1), "Reserved2", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT1_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_SRAT1_FLAG_OFFSET (Flags,0), "Enabled", 0}, + {ACPI_DMT_FLAG1, ACPI_SRAT1_FLAG_OFFSET (Flags,0), "Hot Pluggable", 0}, + {ACPI_DMT_FLAG2, ACPI_SRAT1_FLAG_OFFSET (Flags,0), "Non-Volatile", 0}, + {ACPI_DMT_UINT64, ACPI_SRAT1_OFFSET (Reserved2), "Reserved3", 0}, + ACPI_DMT_TERMINATOR +}; + +/* 2: Processor Local X2_APIC Affinity (ACPI 4.0) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSrat2[] = +{ + {ACPI_DMT_UINT16, ACPI_SRAT2_OFFSET (Reserved), "Reserved1", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT2_OFFSET (ProximityDomain), "Proximity Domain", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT2_OFFSET (ApicId), "Apic ID", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT2_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_SRAT2_FLAG_OFFSET (Flags,0), "Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT2_OFFSET (ClockDomain), "Clock Domain", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT2_OFFSET (Reserved2), "Reserved2", 0}, + ACPI_DMT_TERMINATOR +}; + +/* : GICC Affinity (ACPI 5.1) */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoSrat3[] = +{ + {ACPI_DMT_UINT32, ACPI_SRAT3_OFFSET (ProximityDomain), "Proximity Domain", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT3_OFFSET (AcpiProcessorUid), "Acpi Processor UID", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT3_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_SRAT3_FLAG_OFFSET (Flags,0), "Enabled", 0}, + {ACPI_DMT_UINT32, ACPI_SRAT3_OFFSET (ClockDomain), "Clock Domain", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * STAO - Status Override Table (_STA override) - ACPI 6.0 + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoStao[] = +{ + {ACPI_DMT_UINT8, ACPI_STAO_OFFSET (IgnoreUart), "Ignore UART", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoStaoStr[] = +{ + {ACPI_DMT_STRING, 0, "Namepath", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * TCPA - Trusted Computing Platform Alliance table (Client) + * + * NOTE: There are two versions of the table with the same signature -- + * the client version and the server version. The common PlatformClass + * field is used to differentiate the two types of tables. + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaHdr[] = +{ + {ACPI_DMT_UINT16, ACPI_TCPA_OFFSET (PlatformClass), "Platform Class", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaClient[] = +{ + {ACPI_DMT_UINT32, ACPI_TCPA_CLIENT_OFFSET (MinimumLogLength), "Min Event Log Length", 0}, + {ACPI_DMT_UINT64, ACPI_TCPA_CLIENT_OFFSET (LogAddress), "Event Log Address", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaServer[] = +{ + {ACPI_DMT_UINT16, ACPI_TCPA_SERVER_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_TCPA_SERVER_OFFSET (MinimumLogLength), "Min Event Log Length", 0}, + {ACPI_DMT_UINT64, ACPI_TCPA_SERVER_OFFSET (LogAddress), "Event Log Address", 0}, + {ACPI_DMT_UINT16, ACPI_TCPA_SERVER_OFFSET (SpecRevision), "Specification Revision", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (DeviceFlags), "Device Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_TCPA_SERVER_OFFSET (DeviceFlags), "Pci Device", 0}, + {ACPI_DMT_FLAG1, ACPI_TCPA_SERVER_OFFSET (DeviceFlags), "Bus is Pnp", 0}, + {ACPI_DMT_FLAG2, ACPI_TCPA_SERVER_OFFSET (DeviceFlags), "Address Valid", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (InterruptFlags), "Interrupt Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_TCPA_SERVER_OFFSET (InterruptFlags), "Mode", 0}, + {ACPI_DMT_FLAG1, ACPI_TCPA_SERVER_OFFSET (InterruptFlags), "Polarity", 0}, + {ACPI_DMT_FLAG2, ACPI_TCPA_SERVER_OFFSET (InterruptFlags), "GPE SCI Triggered", 0}, + {ACPI_DMT_FLAG3, ACPI_TCPA_SERVER_OFFSET (InterruptFlags), "Global System Interrupt", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (GpeNumber), "Gpe Number", 0}, + {ACPI_DMT_UINT24, ACPI_TCPA_SERVER_OFFSET (Reserved2[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_TCPA_SERVER_OFFSET (GlobalInterrupt), "Global Interrupt", 0}, + {ACPI_DMT_GAS, ACPI_TCPA_SERVER_OFFSET (Address), "Address", 0}, + {ACPI_DMT_UINT32, ACPI_TCPA_SERVER_OFFSET (Reserved3), "Reserved", 0}, + {ACPI_DMT_GAS, ACPI_TCPA_SERVER_OFFSET (ConfigAddress), "Configuration Address", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (Group), "Pci Group", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (Bus), "Pci Bus", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (Device), "Pci Device", 0}, + {ACPI_DMT_UINT8, ACPI_TCPA_SERVER_OFFSET (Function), "Pci Function", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoTpm2[] = +{ + {ACPI_DMT_UINT16, ACPI_TPM2_OFFSET (PlatformClass), "Platform Class", 0}, + {ACPI_DMT_UINT16, ACPI_TPM2_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_UINT64, ACPI_TPM2_OFFSET (ControlAddress), "Control Address", 0}, + {ACPI_DMT_UINT32, ACPI_TPM2_OFFSET (StartMethod), "Start Method", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * UEFI - UEFI Boot optimization Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoUefi[] = +{ + {ACPI_DMT_UUID, ACPI_UEFI_OFFSET (Identifier[0]), "UUID Identifier", 0}, + {ACPI_DMT_UINT16, ACPI_UEFI_OFFSET (DataOffset), "Data Offset", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * VRTC - Virtual Real Time Clock Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoVrtc[] = +{ + ACPI_DMT_TERMINATOR +}; + +/* VRTC Subtables - VRTC Entry */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoVrtc0[] = +{ + {ACPI_DMT_GAS, ACPI_VRTC0_OFFSET (PhysicalAddress), "PhysicalAddress", 0}, + {ACPI_DMT_UINT32, ACPI_VRTC0_OFFSET (Irq), "IRQ", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * WAET - Windows ACPI Emulated devices Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoWaet[] = +{ + {ACPI_DMT_UINT32, ACPI_WAET_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_WAET_OFFSET (Flags), "RTC needs no INT ack", 0}, + {ACPI_DMT_FLAG1, ACPI_WAET_OFFSET (Flags), "PM timer, one read only", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * WDAT - Watchdog Action Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoWdat[] = +{ + {ACPI_DMT_UINT32, ACPI_WDAT_OFFSET (HeaderLength), "Header Length", DT_LENGTH}, + {ACPI_DMT_UINT16, ACPI_WDAT_OFFSET (PciSegment), "PCI Segment", 0}, + {ACPI_DMT_UINT8, ACPI_WDAT_OFFSET (PciBus), "PCI Bus", 0}, + {ACPI_DMT_UINT8, ACPI_WDAT_OFFSET (PciDevice), "PCI Device", 0}, + {ACPI_DMT_UINT8, ACPI_WDAT_OFFSET (PciFunction), "PCI Function", 0}, + {ACPI_DMT_UINT24, ACPI_WDAT_OFFSET (Reserved[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_WDAT_OFFSET (TimerPeriod), "Timer Period", 0}, + {ACPI_DMT_UINT32, ACPI_WDAT_OFFSET (MaxCount), "Max Count", 0}, + {ACPI_DMT_UINT32, ACPI_WDAT_OFFSET (MinCount), "Min Count", 0}, + {ACPI_DMT_UINT8, ACPI_WDAT_OFFSET (Flags), "Flags (decoded below)", DT_FLAG}, + {ACPI_DMT_FLAG0, ACPI_WDAT_OFFSET (Flags), "Enabled", 0}, + {ACPI_DMT_FLAG7, ACPI_WDAT_OFFSET (Flags), "Stopped When Asleep", 0}, + {ACPI_DMT_UINT24, ACPI_WDAT_OFFSET (Reserved2[0]), "Reserved", 0}, + {ACPI_DMT_UINT32, ACPI_WDAT_OFFSET (Entries), "Watchdog Entry Count", 0}, + ACPI_DMT_TERMINATOR +}; + +/* WDAT Subtables - Watchdog Instruction Entries */ + +ACPI_DMTABLE_INFO AcpiDmTableInfoWdat0[] = +{ + {ACPI_DMT_UINT8, ACPI_WDAT0_OFFSET (Action), "Watchdog Action", 0}, + {ACPI_DMT_UINT8, ACPI_WDAT0_OFFSET (Instruction), "Instruction", 0}, + {ACPI_DMT_UINT16, ACPI_WDAT0_OFFSET (Reserved), "Reserved", 0}, + {ACPI_DMT_GAS, ACPI_WDAT0_OFFSET (RegisterRegion), "Register Region", 0}, + {ACPI_DMT_UINT32, ACPI_WDAT0_OFFSET (Value), "Value", 0}, + {ACPI_DMT_UINT32, ACPI_WDAT0_OFFSET (Mask), "Register Mask", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * WDDT - Watchdog Description Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoWddt[] = +{ + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (SpecVersion), "Specification Version", 0}, + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (TableVersion), "Table Version", 0}, + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (PciVendorId), "PCI Vendor ID", 0}, + {ACPI_DMT_GAS, ACPI_WDDT_OFFSET (Address), "Timer Register", 0}, + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (MaxCount), "Max Count", 0}, + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (MinCount), "Min Count", 0}, + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (Period), "Period", 0}, + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (Status), "Status (decoded below)", 0}, + + /* Status Flags byte 0 */ + + {ACPI_DMT_FLAG0, ACPI_WDDT_FLAG_OFFSET (Status,0), "Available", 0}, + {ACPI_DMT_FLAG1, ACPI_WDDT_FLAG_OFFSET (Status,0), "Active", 0}, + {ACPI_DMT_FLAG2, ACPI_WDDT_FLAG_OFFSET (Status,0), "OS Owns", 0}, + + /* Status Flags byte 1 */ + + {ACPI_DMT_FLAG3, ACPI_WDDT_FLAG_OFFSET (Status,1), "User Reset", 0}, + {ACPI_DMT_FLAG4, ACPI_WDDT_FLAG_OFFSET (Status,1), "Timeout Reset", 0}, + {ACPI_DMT_FLAG5, ACPI_WDDT_FLAG_OFFSET (Status,1), "Power Fail Reset", 0}, + {ACPI_DMT_FLAG6, ACPI_WDDT_FLAG_OFFSET (Status,1), "Unknown Reset", 0}, + + {ACPI_DMT_UINT16, ACPI_WDDT_OFFSET (Capability), "Capability (decoded below)", 0}, + + /* Capability Flags byte 0 */ + + {ACPI_DMT_FLAG0, ACPI_WDDT_FLAG_OFFSET (Capability,0), "Auto Reset", 0}, + {ACPI_DMT_FLAG1, ACPI_WDDT_FLAG_OFFSET (Capability,0), "Timeout Alert", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * WDRT - Watchdog Resource Table + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoWdrt[] = +{ + {ACPI_DMT_GAS, ACPI_WDRT_OFFSET (ControlRegister), "Control Register", 0}, + {ACPI_DMT_GAS, ACPI_WDRT_OFFSET (CountRegister), "Count Register", 0}, + {ACPI_DMT_UINT16, ACPI_WDRT_OFFSET (PciDeviceId), "PCI Device ID", 0}, + {ACPI_DMT_UINT16, ACPI_WDRT_OFFSET (PciVendorId), "PCI Vendor ID", 0}, + {ACPI_DMT_UINT8, ACPI_WDRT_OFFSET (PciBus), "PCI Bus", 0}, + {ACPI_DMT_UINT8, ACPI_WDRT_OFFSET (PciDevice), "PCI Device", 0}, + {ACPI_DMT_UINT8, ACPI_WDRT_OFFSET (PciFunction), "PCI Function", 0}, + {ACPI_DMT_UINT8, ACPI_WDRT_OFFSET (PciSegment), "PCI Segment", 0}, + {ACPI_DMT_UINT16, ACPI_WDRT_OFFSET (MaxCount), "Max Count", 0}, + {ACPI_DMT_UINT8, ACPI_WDRT_OFFSET (Units), "Counter Units", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * WPBT - Windows Platform Environment Table (ACPI 6.0) + * Version 1 + * + * Conforms to "Windows Platform Binary Table (WPBT)" 29 November 2011 + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoWpbt[] = +{ + {ACPI_DMT_UINT32, ACPI_WPBT_OFFSET (HandoffSize), "Handoff Size", 0}, + {ACPI_DMT_UINT64, ACPI_WPBT_OFFSET (HandoffAddress), "Handoff Address", 0}, + {ACPI_DMT_UINT8, ACPI_WPBT_OFFSET (Layout), "Layout", 0}, + {ACPI_DMT_UINT8, ACPI_WPBT_OFFSET (Type), "Type", 0}, + {ACPI_DMT_UINT16, ACPI_WPBT_OFFSET (ArgumentsLength), "Arguments Length", 0}, + ACPI_DMT_TERMINATOR +}; + +ACPI_DMTABLE_INFO AcpiDmTableInfoWpbt0[] = +{ + {ACPI_DMT_UNICODE, sizeof (ACPI_TABLE_WPBT), "Command-line Arguments", 0}, + ACPI_DMT_TERMINATOR +}; + + +/******************************************************************************* + * + * XENV - Xen Environment table (ACPI 6.0) + * + ******************************************************************************/ + +ACPI_DMTABLE_INFO AcpiDmTableInfoXenv[] = +{ + {ACPI_DMT_UINT64, ACPI_XENV_OFFSET (GrantTableAddress), "Grant Table Address", 0}, + {ACPI_DMT_UINT64, ACPI_XENV_OFFSET (GrantTableSize), "Grant Table Size", 0}, + {ACPI_DMT_UINT32, ACPI_XENV_OFFSET (EventInterrupt), "Event Interrupt", 0}, + {ACPI_DMT_UINT8, ACPI_XENV_OFFSET (EventFlags), "Event Flags", 0}, + ACPI_DMT_TERMINATOR +}; + + +/*! [Begin] no source code translation */ + +/* + * Generic types (used in UEFI and custom tables) + * + * Examples: + * + * Buffer : cc 04 ff bb + * UINT8 : 11 + * UINT16 : 1122 + * UINT24 : 112233 + * UINT32 : 11223344 + * UINT56 : 11223344556677 + * UINT64 : 1122334455667788 + * + * String : "This is string" + * Unicode : "This string encoded to Unicode" + * + * GUID : 11223344-5566-7788-99aa-bbccddeeff00 + * DevicePath : "\PciRoot(0)\Pci(0x1f,1)\Usb(0,0)" + */ + +#define ACPI_DM_GENERIC_ENTRY(FieldType, FieldName) \ + {{FieldType, 0, FieldName, 0}, ACPI_DMT_TERMINATOR} + +ACPI_DMTABLE_INFO AcpiDmTableInfoGeneric[][2] = +{ + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT8, "UINT8"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT16, "UINT16"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT24, "UINT24"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT32, "UINT32"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT40, "UINT40"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT48, "UINT48"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT56, "UINT56"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT64, "UINT64"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_STRING, "String"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UNICODE, "Unicode"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_BUFFER, "Buffer"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UUID, "GUID"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_STRING, "DevicePath"), + ACPI_DM_GENERIC_ENTRY (ACPI_DMT_LABEL, "Label"), + {ACPI_DMT_TERMINATOR} +}; +/*! [End] no source code translation !*/ diff --git a/third_party/lib/acpica/source/common/getopt.c b/third_party/lib/acpica/source/common/getopt.c new file mode 100644 index 000000000..f747e0d9a --- /dev/null +++ b/third_party/lib/acpica/source/common/getopt.c @@ -0,0 +1,276 @@ +/****************************************************************************** + * + * Module Name: getopt + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * ACPICA getopt() implementation + * + * Option strings: + * "f" - Option has no arguments + * "f:" - Option requires an argument + * "f+" - Option has an optional argument + * "f^" - Option has optional single-char sub-options + * "f|" - Option has required single-char sub-options + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" + +#define ACPI_OPTION_ERROR(msg, badchar) \ + if (AcpiGbl_Opterr) {AcpiLogError ("%s%c\n", msg, badchar);} + + +int AcpiGbl_Opterr = 1; +int AcpiGbl_Optind = 1; +int AcpiGbl_SubOptChar = 0; +char *AcpiGbl_Optarg; + +static int CurrentCharPtr = 1; + + +/******************************************************************************* + * + * FUNCTION: AcpiGetoptArgument + * + * PARAMETERS: argc, argv - from main + * + * RETURN: 0 if an argument was found, -1 otherwise. Sets AcpiGbl_Optarg + * to point to the next argument. + * + * DESCRIPTION: Get the next argument. Used to obtain arguments for the + * two-character options after the original call to AcpiGetopt. + * Note: Either the argument starts at the next character after + * the option, or it is pointed to by the next argv entry. + * (After call to AcpiGetopt, we need to backup to the previous + * argv entry). + * + ******************************************************************************/ + +int +AcpiGetoptArgument ( + int argc, + char **argv) +{ + + AcpiGbl_Optind--; + CurrentCharPtr++; + + if (argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)] != '\0') + { + AcpiGbl_Optarg = &argv[AcpiGbl_Optind++][(int) (CurrentCharPtr+1)]; + } + else if (++AcpiGbl_Optind >= argc) + { + ACPI_OPTION_ERROR ("Option requires an argument: -", 'v'); + + CurrentCharPtr = 1; + return (-1); + } + else + { + AcpiGbl_Optarg = argv[AcpiGbl_Optind++]; + } + + CurrentCharPtr = 1; + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiGetopt + * + * PARAMETERS: argc, argv - from main + * opts - options info list + * + * RETURN: Option character or ACPI_OPT_END + * + * DESCRIPTION: Get the next option + * + ******************************************************************************/ + +int +AcpiGetopt( + int argc, + char **argv, + char *opts) +{ + int CurrentChar; + char *OptsPtr; + + + if (CurrentCharPtr == 1) + { + if (AcpiGbl_Optind >= argc || + argv[AcpiGbl_Optind][0] != '-' || + argv[AcpiGbl_Optind][1] == '\0') + { + return (ACPI_OPT_END); + } + else if (strcmp (argv[AcpiGbl_Optind], "--") == 0) + { + AcpiGbl_Optind++; + return (ACPI_OPT_END); + } + } + + /* Get the option */ + + CurrentChar = argv[AcpiGbl_Optind][CurrentCharPtr]; + + /* Make sure that the option is legal */ + + if (CurrentChar == ':' || + (OptsPtr = strchr (opts, CurrentChar)) == NULL) + { + ACPI_OPTION_ERROR ("Illegal option: -", CurrentChar); + + if (argv[AcpiGbl_Optind][++CurrentCharPtr] == '\0') + { + AcpiGbl_Optind++; + CurrentCharPtr = 1; + } + + return ('?'); + } + + /* Option requires an argument? */ + + if (*++OptsPtr == ':') + { + if (argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)] != '\0') + { + AcpiGbl_Optarg = &argv[AcpiGbl_Optind++][(int) (CurrentCharPtr+1)]; + } + else if (++AcpiGbl_Optind >= argc) + { + ACPI_OPTION_ERROR ( + "Option requires an argument: -", CurrentChar); + + CurrentCharPtr = 1; + return ('?'); + } + else + { + AcpiGbl_Optarg = argv[AcpiGbl_Optind++]; + } + + CurrentCharPtr = 1; + } + + /* Option has an optional argument? */ + + else if (*OptsPtr == '+') + { + if (argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)] != '\0') + { + AcpiGbl_Optarg = &argv[AcpiGbl_Optind++][(int) (CurrentCharPtr+1)]; + } + else if (++AcpiGbl_Optind >= argc) + { + AcpiGbl_Optarg = NULL; + } + else + { + AcpiGbl_Optarg = argv[AcpiGbl_Optind++]; + } + + CurrentCharPtr = 1; + } + + /* Option has optional single-char arguments? */ + + else if (*OptsPtr == '^') + { + if (argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)] != '\0') + { + AcpiGbl_Optarg = &argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)]; + } + else + { + AcpiGbl_Optarg = "^"; + } + + AcpiGbl_SubOptChar = AcpiGbl_Optarg[0]; + AcpiGbl_Optind++; + CurrentCharPtr = 1; + } + + /* Option has a required single-char argument? */ + + else if (*OptsPtr == '|') + { + if (argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)] != '\0') + { + AcpiGbl_Optarg = &argv[AcpiGbl_Optind][(int) (CurrentCharPtr+1)]; + } + else + { + ACPI_OPTION_ERROR ( + "Option requires a single-character suboption: -", + CurrentChar); + + CurrentCharPtr = 1; + return ('?'); + } + + AcpiGbl_SubOptChar = AcpiGbl_Optarg[0]; + AcpiGbl_Optind++; + CurrentCharPtr = 1; + } + + /* Option with no arguments */ + + else + { + if (argv[AcpiGbl_Optind][++CurrentCharPtr] == '\0') + { + CurrentCharPtr = 1; + AcpiGbl_Optind++; + } + + AcpiGbl_Optarg = NULL; + } + + return (CurrentChar); +} diff --git a/third_party/lib/acpica/source/compiler/aslanalyze.c b/third_party/lib/acpica/source/compiler/aslanalyze.c new file mode 100644 index 000000000..45ca35c25 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslanalyze.c @@ -0,0 +1,619 @@ +/****************************************************************************** + * + * Module Name: aslanalyze.c - Support functions for parse tree walks + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslanalyze") + + +/******************************************************************************* + * + * FUNCTION: AnIsInternalMethod + * + * PARAMETERS: Op - Current op + * + * RETURN: Boolean + * + * DESCRIPTION: Check for an internal control method. + * + ******************************************************************************/ + +BOOLEAN +AnIsInternalMethod ( + ACPI_PARSE_OBJECT *Op) +{ + + if ((!strcmp (Op->Asl.ExternalName, "\\_OSI")) || + (!strcmp (Op->Asl.ExternalName, "_OSI"))) + { + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AnGetInternalMethodReturnType + * + * PARAMETERS: Op - Current op + * + * RETURN: Btype + * + * DESCRIPTION: Get the return type of an internal method + * + ******************************************************************************/ + +UINT32 +AnGetInternalMethodReturnType ( + ACPI_PARSE_OBJECT *Op) +{ + + if ((!strcmp (Op->Asl.ExternalName, "\\_OSI")) || + (!strcmp (Op->Asl.ExternalName, "_OSI"))) + { + return (ACPI_BTYPE_STRING); + } + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AnCheckId + * + * PARAMETERS: Op - Current parse op + * Type - HID or CID + * + * RETURN: None + * + * DESCRIPTION: Perform various checks on _HID and _CID strings. Only limited + * checks can be performed on _CID strings. + * + ******************************************************************************/ + +void +AnCheckId ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAME Type) +{ + UINT32 i; + ACPI_SIZE Length; + + + /* Only care about string versions of _HID/_CID (integers are legal) */ + + if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) + { + return; + } + + /* For both _HID and _CID, the string must be non-null */ + + Length = strlen (Op->Asl.Value.String); + if (!Length) + { + AslError (ASL_ERROR, ASL_MSG_NULL_STRING, Op, NULL); + return; + } + + /* + * One of the things we want to catch here is the use of a leading + * asterisk in the string -- an odd construct that certain platform + * manufacturers are fond of. Technically, a leading asterisk is OK + * for _CID, but a valid use of this has not been seen. + */ + if (*Op->Asl.Value.String == '*') + { + AslError (ASL_ERROR, ASL_MSG_LEADING_ASTERISK, + Op, Op->Asl.Value.String); + return; + } + + /* _CID strings are bus-specific, no more checks can be performed */ + + if (Type == ASL_TYPE_CID) + { + return; + } + + /* For _HID, all characters must be alphanumeric */ + + for (i = 0; Op->Asl.Value.String[i]; i++) + { + if (!isalnum ((int) Op->Asl.Value.String[i])) + { + AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, + Op, Op->Asl.Value.String); + return; + } + } + + /* + * _HID String must be one of these forms: + * + * "AAA####" A is an uppercase letter and # is a hex digit + * "ACPI####" # is a hex digit + * "NNNN####" N is an uppercase letter or decimal digit (0-9) + * # is a hex digit (ACPI 5.0) + */ + if ((Length < 7) || (Length > 8)) + { + AslError (ASL_ERROR, ASL_MSG_HID_LENGTH, + Op, Op->Asl.Value.String); + return; + } + + /* _HID Length is valid (7 or 8), now check prefix (first 3 or 4 chars) */ + + if (Length == 7) + { + /* AAA####: Ensure the alphabetic prefix is all uppercase */ + + for (i = 0; i < 3; i++) + { + if (!isupper ((int) Op->Asl.Value.String[i])) + { + AslError (ASL_ERROR, ASL_MSG_UPPER_CASE, + Op, &Op->Asl.Value.String[i]); + return; + } + } + } + else /* Length == 8 */ + { + /* + * ACPI#### or NNNN####: + * Ensure the prefix contains only uppercase alpha or decimal digits + */ + for (i = 0; i < 4; i++) + { + if (!isupper ((int) Op->Asl.Value.String[i]) && + !isdigit ((int) Op->Asl.Value.String[i])) + { + AslError (ASL_ERROR, ASL_MSG_HID_PREFIX, + Op, &Op->Asl.Value.String[i]); + return; + } + } + } + + /* Remaining characters (suffix) must be hex digits */ + + for (; i < Length; i++) + { + if (!isxdigit ((int) Op->Asl.Value.String[i])) + { + AslError (ASL_ERROR, ASL_MSG_HID_SUFFIX, + Op, &Op->Asl.Value.String[i]); + break; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AnLastStatementIsReturn + * + * PARAMETERS: Op - A method parse node + * + * RETURN: TRUE if last statement is an ASL RETURN. False otherwise + * + * DESCRIPTION: Walk down the list of top level statements within a method + * to find the last one. Check if that last statement is in + * fact a RETURN statement. + * + ******************************************************************************/ + +BOOLEAN +AnLastStatementIsReturn ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + /* Check if last statement is a return */ + + Next = ASL_GET_CHILD_NODE (Op); + while (Next) + { + if ((!Next->Asl.Next) && + (Next->Asl.ParseOpcode == PARSEOP_RETURN)) + { + return (TRUE); + } + + Next = ASL_GET_PEER_NODE (Next); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AnCheckMethodReturnValue + * + * PARAMETERS: Op - Parent + * OpInfo - Parent info + * ArgOp - Method invocation op + * RequiredBtypes - What caller requires + * ThisNodeBtype - What this node returns (if anything) + * + * RETURN: None + * + * DESCRIPTION: Check a method invocation for 1) A return value and if it does + * in fact return a value, 2) check the type of the return value. + * + ******************************************************************************/ + +void +AnCheckMethodReturnValue ( + ACPI_PARSE_OBJECT *Op, + const ACPI_OPCODE_INFO *OpInfo, + ACPI_PARSE_OBJECT *ArgOp, + UINT32 RequiredBtypes, + UINT32 ThisNodeBtype) +{ + ACPI_PARSE_OBJECT *OwningOp; + ACPI_NAMESPACE_NODE *Node; + + + Node = ArgOp->Asl.Node; + + + /* Examine the parent op of this method */ + + OwningOp = Node->Op; + if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL) + { + /* Method NEVER returns a value */ + + AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName); + } + else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL) + { + /* Method SOMETIMES returns a value, SOMETIMES not */ + + AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, + Op, Op->Asl.ExternalName); + } + else if (!(ThisNodeBtype & RequiredBtypes)) + { + /* Method returns a value, but the type is wrong */ + + AnFormatBtype (StringBuffer, ThisNodeBtype); + AnFormatBtype (StringBuffer2, RequiredBtypes); + + /* + * The case where the method does not return any value at all + * was already handled in the namespace cross reference + * -- Only issue an error if the method in fact returns a value, + * but it is of the wrong type + */ + if (ThisNodeBtype != 0) + { + sprintf (MsgBuffer, + "Method returns [%s], %s operator requires [%s]", + StringBuffer, OpInfo->Name, StringBuffer2); + + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AnIsResultUsed + * + * PARAMETERS: Op - Parent op for the operator + * + * RETURN: TRUE if result from this operation is actually consumed + * + * DESCRIPTION: Determine if the function result value from an operator is + * used. + * + ******************************************************************************/ + +BOOLEAN +AnIsResultUsed ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Parent; + + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_INCREMENT: + case PARSEOP_DECREMENT: + + /* These are standalone operators, no return value */ + + return (TRUE); + + default: + + break; + } + + /* Examine parent to determine if the return value is used */ + + Parent = Op->Asl.Parent; + switch (Parent->Asl.ParseOpcode) + { + /* If/While - check if the operator is the predicate */ + + case PARSEOP_IF: + case PARSEOP_WHILE: + + /* First child is the predicate */ + + if (Parent->Asl.Child == Op) + { + return (TRUE); + } + + return (FALSE); + + /* Not used if one of these is the parent */ + + case PARSEOP_METHOD: + case PARSEOP_DEFINITION_BLOCK: + case PARSEOP_ELSE: + + return (FALSE); + + default: + + /* Any other type of parent means that the result is used */ + + return (TRUE); + } +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckForGpeNameConflict + * + * PARAMETERS: Op - Current parse op + * + * RETURN: None + * + * DESCRIPTION: Check for a conflict between GPE names within this scope. + * Conflict means two GPE names with the same GPE number, but + * different types -- such as _L1C and _E1C. + * + ******************************************************************************/ + +void +ApCheckForGpeNameConflict ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextOp; + UINT32 GpeNumber; + char Name[ACPI_NAME_SIZE + 1]; + char Target[ACPI_NAME_SIZE]; + + + /* Need a null-terminated string version of NameSeg */ + + ACPI_MOVE_32_TO_32 (Name, &Op->Asl.NameSeg); + Name[ACPI_NAME_SIZE] = 0; + + /* + * For a GPE method: + * 1st char must be underscore + * 2nd char must be L or E + * 3rd/4th chars must be a hex number + */ + if ((Name[0] != '_') || + ((Name[1] != 'L') && (Name[1] != 'E'))) + { + return; + } + + /* Verify 3rd/4th chars are a valid hex value */ + + GpeNumber = strtoul (&Name[2], NULL, 16); + if (GpeNumber == ACPI_UINT32_MAX) + { + return; + } + + /* + * We are now sure we have an _Lxx or _Exx. + * Create the target name that would cause collision (Flip E/L) + */ + ACPI_MOVE_32_TO_32 (Target, Name); + + /* Inject opposite letter ("L" versus "E") */ + + if (Name[1] == 'L') + { + Target[1] = 'E'; + } + else /* Name[1] == 'E' */ + { + Target[1] = 'L'; + } + + /* Search all peers (objects within this scope) for target match */ + + NextOp = Op->Asl.Next; + while (NextOp) + { + /* + * We mostly care about methods, but check Name() constructs also, + * even though they will get another error for not being a method. + * All GPE names must be defined as control methods. + */ + if ((NextOp->Asl.ParseOpcode == PARSEOP_METHOD) || + (NextOp->Asl.ParseOpcode == PARSEOP_NAME)) + { + if (ACPI_COMPARE_NAME (Target, NextOp->Asl.NameSeg)) + { + /* Found both _Exy and _Lxy in the same scope, error */ + + AslError (ASL_ERROR, ASL_MSG_GPE_NAME_CONFLICT, NextOp, + Name); + return; + } + } + + NextOp = NextOp->Asl.Next; + } + + /* OK, no conflict found */ + + return; +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckRegMethod + * + * PARAMETERS: Op - Current parse op + * + * RETURN: None + * + * DESCRIPTION: Ensure that a _REG method has a corresponding Operation + * Region declaration within the same scope. Note: _REG is defined + * to have two arguments and must therefore be defined as a + * control method. + * + ******************************************************************************/ + +void +ApCheckRegMethod ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + ACPI_PARSE_OBJECT *Parent; + + + /* We are only interested in _REG methods */ + + if (!ACPI_COMPARE_NAME (METHOD_NAME__REG, &Op->Asl.NameSeg)) + { + return; + } + + /* Get the start of the current scope */ + + Parent = Op->Asl.Parent; + Next = Parent->Asl.Child; + + /* Search entire scope for an operation region declaration */ + + while (Next) + { + if (Next->Asl.ParseOpcode == PARSEOP_OPERATIONREGION) + { + return; /* Found region, OK */ + } + + Next = Next->Asl.Next; + } + + /* No region found, issue warning */ + + AslError (ASL_WARNING, ASL_MSG_NO_REGION, Op, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: ApFindNameInScope + * + * PARAMETERS: Name - Name to search for + * Op - Current parse op + * + * RETURN: TRUE if name found in the same scope as Op. + * + * DESCRIPTION: Determine if a name appears in the same scope as Op, as either + * a Method() or a Name(). + * + ******************************************************************************/ + +BOOLEAN +ApFindNameInScope ( + char *Name, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + ACPI_PARSE_OBJECT *Parent; + + + /* Get the start of the current scope */ + + Parent = Op->Asl.Parent; + Next = Parent->Asl.Child; + + /* Search entire scope for a match to the name */ + + while (Next) + { + if ((Next->Asl.ParseOpcode == PARSEOP_METHOD) || + (Next->Asl.ParseOpcode == PARSEOP_NAME)) + { + if (ACPI_COMPARE_NAME (Name, Next->Asl.NameSeg)) + { + return (TRUE); + } + } + + Next = Next->Asl.Next; + } + + return (FALSE); +} diff --git a/third_party/lib/acpica/source/compiler/aslascii.c b/third_party/lib/acpica/source/compiler/aslascii.c new file mode 100644 index 000000000..8a1d57dcc --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslascii.c @@ -0,0 +1,288 @@ +/****************************************************************************** + * + * Module Name: aslascii - ASCII detection and support routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include +#include + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslascii") + + +/* Local prototypes */ + +static void +FlConsumeAnsiComment ( + FILE *Handle, + ASL_FILE_STATUS *Status); + +static void +FlConsumeNewComment ( + FILE *Handle, + ASL_FILE_STATUS *Status); + + +/******************************************************************************* + * + * FUNCTION: FlIsFileAsciiSource + * + * PARAMETERS: Filename - Full input filename + * DisplayErrors - TRUE if error messages desired + * + * RETURN: Status + * + * DESCRIPTION: Verify that the input file is entirely ASCII. Ignores characters + * within comments. Note: does not handle nested comments and does + * not handle comment delimiters within string literals. However, + * on the rare chance this happens and an invalid character is + * missed, the parser will catch the error by failing in some + * spectactular manner. + * + ******************************************************************************/ + +ACPI_STATUS +FlIsFileAsciiSource ( + char *Filename, + BOOLEAN DisplayErrors) +{ + UINT8 Byte; + ACPI_SIZE BadBytes = 0; + BOOLEAN OpeningComment = FALSE; + ASL_FILE_STATUS Status; + FILE *Handle; + + + /* Open file in text mode so file offset is always accurate */ + + Handle = fopen (Filename, "rb"); + if (!Handle) + { + perror ("Could not open input file"); + return (AE_ERROR); + } + + Status.Line = 1; + Status.Offset = 0; + + /* Read the entire file */ + + while (fread (&Byte, 1, 1, Handle) == 1) + { + /* Ignore comment fields (allow non-ascii within) */ + + if (OpeningComment) + { + /* Check for second comment open delimiter */ + + if (Byte == '*') + { + FlConsumeAnsiComment (Handle, &Status); + } + + if (Byte == '/') + { + FlConsumeNewComment (Handle, &Status); + } + + /* Reset */ + + OpeningComment = FALSE; + } + else if (Byte == '/') + { + OpeningComment = TRUE; + } + + /* Check for an ASCII character */ + + if (!ACPI_IS_ASCII (Byte)) + { + if ((BadBytes < 10) && (DisplayErrors)) + { + AcpiOsPrintf ( + "Found non-ASCII character in source text: " + "0x%2.2X in line %u, file offset 0x%2.2X\n", + Byte, Status.Line, Status.Offset); + } + BadBytes++; + } + + /* Ensure character is either printable or a "space" char */ + + else if (!isprint (Byte) && !isspace (Byte)) + { + if ((BadBytes < 10) && (DisplayErrors)) + { + AcpiOsPrintf ( + "Found invalid character in source text: " + "0x%2.2X in line %u, file offset 0x%2.2X\n", + Byte, Status.Line, Status.Offset); + } + BadBytes++; + } + + /* Update line counter as necessary */ + + if (Byte == 0x0A) + { + Status.Line++; + } + + Status.Offset++; + } + + fclose (Handle); + + /* Were there any non-ASCII characters in the file? */ + + if (BadBytes) + { + if (DisplayErrors) + { + AcpiOsPrintf ( + "Total %u invalid characters found in input source text, " + "could be a binary file\n", BadBytes); + AslError (ASL_ERROR, ASL_MSG_NON_ASCII, NULL, Filename); + } + + return (AE_BAD_CHARACTER); + } + + /* File is OK (100% ASCII) */ + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: FlConsumeAnsiComment + * + * PARAMETERS: Handle - Open input file + * Status - File current status struct + * + * RETURN: Number of lines consumed + * + * DESCRIPTION: Step over a normal slash-star type comment + * + ******************************************************************************/ + +static void +FlConsumeAnsiComment ( + FILE *Handle, + ASL_FILE_STATUS *Status) +{ + UINT8 Byte; + BOOLEAN ClosingComment = FALSE; + + + while (fread (&Byte, 1, 1, Handle) == 1) + { + /* Scan until comment close is found */ + + if (ClosingComment) + { + if (Byte == '/') + { + Status->Offset++; + return; + } + + if (Byte != '*') + { + /* Reset */ + + ClosingComment = FALSE; + } + } + else if (Byte == '*') + { + ClosingComment = TRUE; + } + + /* Maintain line count */ + + if (Byte == 0x0A) + { + Status->Line++; + } + + Status->Offset++; + } +} + + +/******************************************************************************* + * + * FUNCTION: FlConsumeNewComment + * + * PARAMETERS: Handle - Open input file + * Status - File current status struct + * + * RETURN: Number of lines consumed + * + * DESCRIPTION: Step over a slash-slash type of comment + * + ******************************************************************************/ + +static void +FlConsumeNewComment ( + FILE *Handle, + ASL_FILE_STATUS *Status) +{ + UINT8 Byte; + + + while (fread (&Byte, 1, 1, Handle) == 1) + { + Status->Offset++; + + /* Comment ends at newline */ + + if (Byte == 0x0A) + { + Status->Line++; + return; + } + } +} diff --git a/third_party/lib/acpica/source/compiler/aslbtypes.c b/third_party/lib/acpica/source/compiler/aslbtypes.c new file mode 100644 index 000000000..7ac4ca70e --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslbtypes.c @@ -0,0 +1,582 @@ +/****************************************************************************** + * + * Module Name: aslbtypes - Support for bitfield types + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslbtypes") + +/* Local prototypes */ + +static UINT32 +AnMapEtypeToBtype ( + UINT32 Etype); + + +/******************************************************************************* + * + * FUNCTION: AnMapArgTypeToBtype + * + * PARAMETERS: ArgType - The ARGI required type(s) for this + * argument, from the opcode info table + * + * RETURN: The corresponding Bit-encoded types + * + * DESCRIPTION: Convert an encoded ARGI required argument type code into a + * bitfield type code. Implements the implicit source conversion + * rules. + * + ******************************************************************************/ + +UINT32 +AnMapArgTypeToBtype ( + UINT32 ArgType) +{ + + switch (ArgType) + { + /* Simple types */ + + case ARGI_ANYTYPE: + + return (ACPI_BTYPE_OBJECTS_AND_REFS); + + case ARGI_PACKAGE: + + return (ACPI_BTYPE_PACKAGE); + + case ARGI_EVENT: + + return (ACPI_BTYPE_EVENT); + + case ARGI_MUTEX: + + return (ACPI_BTYPE_MUTEX); + + case ARGI_DDBHANDLE: + /* + * DDBHandleObject := SuperName + * ACPI_BTYPE_REFERENCE_OBJECT: + * Index reference as parameter of Load/Unload + */ + return (ACPI_BTYPE_DDB_HANDLE | ACPI_BTYPE_REFERENCE_OBJECT); + + /* Interchangeable types */ + /* + * Source conversion rules: + * Integer, String, and Buffer are all interchangeable + */ + case ARGI_INTEGER: + case ARGI_STRING: + case ARGI_BUFFER: + case ARGI_BUFFER_OR_STRING: + case ARGI_COMPUTEDATA: + + return (ACPI_BTYPE_COMPUTE_DATA); + + /* References */ + + case ARGI_INTEGER_REF: + + return (ACPI_BTYPE_INTEGER); + + case ARGI_OBJECT_REF: + + return (ACPI_BTYPE_ALL_OBJECTS); + + case ARGI_DEVICE_REF: + + return (ACPI_BTYPE_DEVICE_OBJECTS); + + case ARGI_REFERENCE: + + return (ACPI_BTYPE_NAMED_REFERENCE); /* Name or Namestring */ + + case ARGI_TARGETREF: + + /* + * Target operand for most math and logic operators. + * Package objects not allowed as target. + */ + return (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_DEBUG_OBJECT | + ACPI_BTYPE_REFERENCE_OBJECT); + + case ARGI_STORE_TARGET: + + /* Special target for Store(), includes packages */ + + return (ACPI_BTYPE_DATA | ACPI_BTYPE_DEBUG_OBJECT | + ACPI_BTYPE_REFERENCE_OBJECT); + + case ARGI_FIXED_TARGET: + case ARGI_SIMPLE_TARGET: + + return (ACPI_BTYPE_OBJECTS_AND_REFS); + + /* Complex types */ + + case ARGI_DATAOBJECT: + /* + * Buffer, string, package or reference to a Op - + * Used only by SizeOf operator + */ + return (ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER | + ACPI_BTYPE_PACKAGE | ACPI_BTYPE_REFERENCE_OBJECT); + + case ARGI_COMPLEXOBJ: + + /* Buffer, String, or package */ + + return (ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER | + ACPI_BTYPE_PACKAGE); + + case ARGI_REF_OR_STRING: + + /* Used by DeRefOf operator only */ + + return (ACPI_BTYPE_STRING | ACPI_BTYPE_REFERENCE_OBJECT); + + case ARGI_REGION_OR_BUFFER: + + /* Used by Load() only. Allow buffers in addition to regions/fields */ + + return (ACPI_BTYPE_REGION | ACPI_BTYPE_BUFFER | + ACPI_BTYPE_FIELD_UNIT); + + case ARGI_DATAREFOBJ: + + /* Used by Store() only, as the source operand */ + + return (ACPI_BTYPE_DATA_REFERENCE | ACPI_BTYPE_REFERENCE_OBJECT); + + default: + + break; + } + + return (ACPI_BTYPE_OBJECTS_AND_REFS); +} + + +/******************************************************************************* + * + * FUNCTION: AnMapEtypeToBtype + * + * PARAMETERS: Etype - Encoded ACPI Type + * + * RETURN: Btype corresponding to the Etype + * + * DESCRIPTION: Convert an encoded ACPI type to a bitfield type applying the + * operand conversion rules. In other words, returns the type(s) + * this Etype is implicitly converted to during interpretation. + * + ******************************************************************************/ + +static UINT32 +AnMapEtypeToBtype ( + UINT32 Etype) +{ + + if (Etype == ACPI_TYPE_ANY) + { + return (ACPI_BTYPE_OBJECTS_AND_REFS); + } + + /* Try the standard ACPI data types */ + + if (Etype <= ACPI_TYPE_EXTERNAL_MAX) + { + /* + * This switch statement implements the allowed operand conversion + * rules as per the "ASL Data Types" section of the ACPI + * specification. + */ + switch (Etype) + { + case ACPI_TYPE_INTEGER: + + return (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_DDB_HANDLE); + + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + return (ACPI_BTYPE_COMPUTE_DATA); + + case ACPI_TYPE_PACKAGE: + + return (ACPI_BTYPE_PACKAGE); + + case ACPI_TYPE_FIELD_UNIT: + + return (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_FIELD_UNIT); + + case ACPI_TYPE_BUFFER_FIELD: + + return (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_BUFFER_FIELD); + + case ACPI_TYPE_DDB_HANDLE: + + return (ACPI_BTYPE_INTEGER | ACPI_BTYPE_DDB_HANDLE); + + case ACPI_TYPE_DEBUG_OBJECT: + + /* Cannot be used as a source operand */ + + return (0); + + default: + + return (1 << (Etype - 1)); + } + } + + /* Try the internal data types */ + + switch (Etype) + { + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + /* Named fields can be either Integer/Buffer/String */ + + return (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_FIELD_UNIT); + + case ACPI_TYPE_LOCAL_ALIAS: + + return (ACPI_BTYPE_INTEGER); + + + case ACPI_TYPE_LOCAL_RESOURCE: + case ACPI_TYPE_LOCAL_RESOURCE_FIELD: + + return (ACPI_BTYPE_REFERENCE_OBJECT); + + default: + + printf ("Unhandled encoded type: %X\n", Etype); + return (0); + } +} + + +/******************************************************************************* + * + * FUNCTION: AnFormatBtype + * + * PARAMETERS: Btype - Bitfield of ACPI types + * Buffer - Where to put the ascii string + * + * RETURN: None. + * + * DESCRIPTION: Convert a Btype to a string of ACPI types + * + ******************************************************************************/ + +void +AnFormatBtype ( + char *Buffer, + UINT32 Btype) +{ + UINT32 Type; + BOOLEAN First = TRUE; + + + *Buffer = 0; + if (Btype == 0) + { + strcat (Buffer, "NoReturnValue"); + return; + } + + for (Type = 1; Type <= ACPI_TYPE_EXTERNAL_MAX; Type++) + { + if (Btype & 0x00000001) + { + if (!First) + { + strcat (Buffer, "|"); + } + + First = FALSE; + strcat (Buffer, AcpiUtGetTypeName (Type)); + } + Btype >>= 1; + } + + if (Btype & 0x00000001) + { + if (!First) + { + strcat (Buffer, "|"); + } + + First = FALSE; + strcat (Buffer, "Reference"); + } + + Btype >>= 1; + if (Btype & 0x00000001) + { + if (!First) + { + strcat (Buffer, "|"); + } + + First = FALSE; + strcat (Buffer, "Resource"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AnGetBtype + * + * PARAMETERS: Op - Parse node whose type will be returned. + * + * RETURN: The Btype associated with the Op. + * + * DESCRIPTION: Get the (bitfield) ACPI type associated with the parse node. + * Handles the case where the node is a name or method call and + * the actual type must be obtained from the namespace node. + * + ******************************************************************************/ + +UINT32 +AnGetBtype ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *ReferencedNode; + UINT32 ThisNodeBtype = 0; + + + if (!Op) + { + AcpiOsPrintf ("Null Op in AnGetBtype\n"); + return (ACPI_UINT32_MAX); + } + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || + (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) + { + Node = Op->Asl.Node; + if (!Node) + { + DbgPrint (ASL_DEBUG_OUTPUT, + "No attached Nsnode: [%s] at line %u name [%s], " + "ignoring typecheck\n", + Op->Asl.ParseOpName, Op->Asl.LineNumber, + Op->Asl.ExternalName); + return (ACPI_UINT32_MAX); + } + + ThisNodeBtype = AnMapEtypeToBtype (Node->Type); + if (!ThisNodeBtype) + { + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, + "could not map type"); + } + + if (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) + { + ReferencedNode = Node->Op; + if (!ReferencedNode) + { + /* Check for an internal method */ + + if (AnIsInternalMethod (Op)) + { + return (AnGetInternalMethodReturnType (Op)); + } + + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, + "null Op pointer"); + return (ACPI_UINT32_MAX); + } + + if (ReferencedNode->Asl.CompileFlags & NODE_METHOD_TYPED) + { + ThisNodeBtype = ReferencedNode->Asl.AcpiBtype; + } + else + { + return (ACPI_UINT32_MAX -1); + } + } + } + else + { + ThisNodeBtype = Op->Asl.AcpiBtype; + } + + return (ThisNodeBtype); +} + + +/******************************************************************************* + * + * FUNCTION: AnMapObjTypeToBtype + * + * PARAMETERS: Op - A parse node + * + * RETURN: A Btype + * + * DESCRIPTION: Map object to the associated "Btype" + * + ******************************************************************************/ + +UINT32 +AnMapObjTypeToBtype ( + ACPI_PARSE_OBJECT *Op) +{ + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_OBJECTTYPE_BFF: /* "BuffFieldObj" */ + + return (ACPI_BTYPE_BUFFER_FIELD); + + case PARSEOP_OBJECTTYPE_BUF: /* "BuffObj" */ + + return (ACPI_BTYPE_BUFFER); + + case PARSEOP_OBJECTTYPE_DDB: /* "DDBHandleObj" */ + + return (ACPI_BTYPE_DDB_HANDLE); + + case PARSEOP_OBJECTTYPE_DEV: /* "DeviceObj" */ + + return (ACPI_BTYPE_DEVICE); + + case PARSEOP_OBJECTTYPE_EVT: /* "EventObj" */ + + return (ACPI_BTYPE_EVENT); + + case PARSEOP_OBJECTTYPE_FLD: /* "FieldUnitObj" */ + + return (ACPI_BTYPE_FIELD_UNIT); + + case PARSEOP_OBJECTTYPE_INT: /* "IntObj" */ + + return (ACPI_BTYPE_INTEGER); + + case PARSEOP_OBJECTTYPE_MTH: /* "MethodObj" */ + + return (ACPI_BTYPE_METHOD); + + case PARSEOP_OBJECTTYPE_MTX: /* "MutexObj" */ + + return (ACPI_BTYPE_MUTEX); + + case PARSEOP_OBJECTTYPE_OPR: /* "OpRegionObj" */ + + return (ACPI_BTYPE_REGION); + + case PARSEOP_OBJECTTYPE_PKG: /* "PkgObj" */ + + return (ACPI_BTYPE_PACKAGE); + + case PARSEOP_OBJECTTYPE_POW: /* "PowerResObj" */ + + return (ACPI_BTYPE_POWER); + + case PARSEOP_OBJECTTYPE_STR: /* "StrObj" */ + + return (ACPI_BTYPE_STRING); + + case PARSEOP_OBJECTTYPE_THZ: /* "ThermalZoneObj" */ + + return (ACPI_BTYPE_THERMAL); + + case PARSEOP_OBJECTTYPE_UNK: /* "UnknownObj" */ + + return (ACPI_BTYPE_OBJECTS_AND_REFS); + + default: + + return (0); + } +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: AnMapBtypeToEtype + * + * PARAMETERS: Btype - Bitfield of ACPI types + * + * RETURN: The Etype corresponding the the Btype + * + * DESCRIPTION: Convert a bitfield type to an encoded type + * + ******************************************************************************/ + +UINT32 +AnMapBtypeToEtype ( + UINT32 Btype) +{ + UINT32 i; + UINT32 Etype; + + + if (Btype == 0) + { + return (0); + } + + Etype = 1; + for (i = 1; i < Btype; i *= 2) + { + Etype++; + } + + return (Etype); +} +#endif diff --git a/third_party/lib/acpica/source/compiler/aslcodegen.c b/third_party/lib/acpica/source/compiler/aslcodegen.c new file mode 100644 index 000000000..08fcc3748 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslcodegen.c @@ -0,0 +1,659 @@ +/****************************************************************************** + * + * Module Name: aslcodegen - AML code generation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslcodegen") + +/* Local prototypes */ + +static ACPI_STATUS +CgAmlWriteWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static void +CgLocalWriteAmlData ( + ACPI_PARSE_OBJECT *Op, + void *Buffer, + UINT32 Length); + +static void +CgWriteAmlOpcode ( + ACPI_PARSE_OBJECT *Op); + +static void +CgWriteTableHeader ( + ACPI_PARSE_OBJECT *Op); + +static void +CgCloseTable ( + void); + +static void +CgWriteNode ( + ACPI_PARSE_OBJECT *Op); + + +/******************************************************************************* + * + * FUNCTION: CgGenerateAmlOutput + * + * PARAMETERS: None. + * + * RETURN: None + * + * DESCRIPTION: Generate AML code. Currently generates the listing file + * simultaneously. + * + ******************************************************************************/ + +void +CgGenerateAmlOutput ( + void) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, "\nWriting AML\n\n"); + + /* Generate the AML output file */ + + FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0); + Gbl_SourceLine = 0; + Gbl_NextError = Gbl_ErrorLog; + + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + CgAmlWriteWalk, NULL, NULL); + + DbgPrint (ASL_TREE_OUTPUT, + "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr" + " Parent Child Next Flags AcTyp Final Col L# EL# LL# ELL#\n", + 76, " "); + + CgCloseTable (); +} + + +/******************************************************************************* + * + * FUNCTION: CgAmlWriteWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Parse tree walk to generate the AML code. + * + ******************************************************************************/ + +static ACPI_STATUS +CgAmlWriteWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + /* + * Print header at level 0. Alignment assumes 32-bit pointers + */ + if (!Level) + { + DbgPrint (ASL_TREE_OUTPUT, + "Final parse tree used for AML output:\n"); + DbgPrint (ASL_TREE_OUTPUT, + "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr" + " Parent Child Next Flags AcTyp Final Col L# EL# LL# ELL#\n", + 76, " "); + } + + /* Debug output */ + + DbgPrint (ASL_TREE_OUTPUT, + "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level); + UtPrintFormattedName (Op->Asl.ParseOpcode, Level); + + if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG || + Op->Asl.ParseOpcode == PARSEOP_NAMESTRING || + Op->Asl.ParseOpcode == PARSEOP_METHODCALL) + { + DbgPrint (ASL_TREE_OUTPUT, + "%10.32s ", Op->Asl.ExternalName); + } + else + { + DbgPrint (ASL_TREE_OUTPUT, " "); + } + + DbgPrint (ASL_TREE_OUTPUT, + "%08X %04X %04X %01X %04X %04X %04X %04X " + "%08X %08X %08X %08X %08X %08X %04X %02d %02d %02d %02d %02d\n", + /* 1 */ (UINT32) Op->Asl.Value.Integer, + /* 2 */ Op->Asl.ParseOpcode, + /* 3 */ Op->Asl.AmlOpcode, + /* 4 */ Op->Asl.AmlOpcodeLength, + /* 5 */ Op->Asl.AmlPkgLenBytes, + /* 6 */ Op->Asl.AmlLength, + /* 7 */ Op->Asl.AmlSubtreeLength, + /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0, + /* 9 */ Op, + /* 10 */ Op->Asl.Parent, + /* 11 */ Op->Asl.Child, + /* 12 */ Op->Asl.Next, + /* 13 */ Op->Asl.CompileFlags, + /* 14 */ Op->Asl.AcpiBtype, + /* 15 */ Op->Asl.FinalAmlLength, + /* 16 */ Op->Asl.Column, + /* 17 */ Op->Asl.LineNumber, + /* 18 */ Op->Asl.EndLine, + /* 19 */ Op->Asl.LogicalLineNumber, + /* 20 */ Op->Asl.EndLogicalLine); + + /* Generate the AML for this node */ + + CgWriteNode (Op); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: CgLocalWriteAmlData + * + * PARAMETERS: Op - Current parse op + * Buffer - Buffer to write + * Length - Size of data in buffer + * + * RETURN: None + * + * DESCRIPTION: Write a buffer of AML data to the AML output file. + * + ******************************************************************************/ + +static void +CgLocalWriteAmlData ( + ACPI_PARSE_OBJECT *Op, + void *Buffer, + UINT32 Length) +{ + + /* Write the raw data to the AML file */ + + FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length); + + /* Update the final AML length for this node (used for listings) */ + + if (Op) + { + Op->Asl.FinalAmlLength += Length; + } +} + + +/******************************************************************************* + * + * FUNCTION: CgWriteAmlOpcode + * + * PARAMETERS: Op - Parse node with an AML opcode + * + * RETURN: None. + * + * DESCRIPTION: Write the AML opcode corresponding to a parse node. + * + ******************************************************************************/ + +static void +CgWriteAmlOpcode ( + ACPI_PARSE_OBJECT *Op) +{ + UINT8 PkgLenFirstByte; + UINT32 i; + union { + UINT16 Opcode; + UINT8 OpcodeBytes[2]; + } Aml; + union { + UINT32 Len; + UINT8 LenBytes[4]; + } PkgLen; + + + /* We expect some DEFAULT_ARGs, just ignore them */ + + if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + return; + } + + switch (Op->Asl.AmlOpcode) + { + case AML_UNASSIGNED_OPCODE: + + /* These opcodes should not get here */ + + printf ("Found a node with an unassigned AML opcode\n"); + FlPrintFile (ASL_FILE_STDERR, + "Found a node with an unassigned AML opcode\n"); + return; + + case AML_INT_RESERVEDFIELD_OP: + + /* Special opcodes for within a field definition */ + + Aml.Opcode = AML_FIELD_OFFSET_OP; + break; + + case AML_INT_ACCESSFIELD_OP: + + Aml.Opcode = AML_FIELD_ACCESS_OP; + break; + + case AML_INT_CONNECTION_OP: + + Aml.Opcode = AML_FIELD_CONNECTION_OP; + break; + + default: + + Aml.Opcode = Op->Asl.AmlOpcode; + break; + } + + + switch (Aml.Opcode) + { + case AML_PACKAGE_LENGTH: + + /* Value is the length to be encoded (Used in field definitions) */ + + PkgLen.Len = (UINT32) Op->Asl.Value.Integer; + break; + + default: + + /* Check for two-byte opcode */ + + if (Aml.Opcode > 0x00FF) + { + /* Write the high byte first */ + + CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); + } + + CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); + + /* Subtreelength doesn't include length of package length bytes */ + + PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; + break; + } + + /* Does this opcode have an associated "PackageLength" field? */ + + if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) + { + if (Op->Asl.AmlPkgLenBytes == 1) + { + /* Simplest case -- no bytes to follow, just write the count */ + + CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); + } + else if (Op->Asl.AmlPkgLenBytes != 0) + { + /* + * Encode the "bytes to follow" in the first byte, top two bits. + * The low-order nybble of the length is in the bottom 4 bits + */ + PkgLenFirstByte = (UINT8) + (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | + (PkgLen.LenBytes[0] & 0x0F)); + + CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); + + /* + * Shift the length over by the 4 bits we just stuffed + * in the first byte + */ + PkgLen.Len >>= 4; + + /* + * Now we can write the remaining bytes - + * either 1, 2, or 3 bytes + */ + for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++) + { + CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1); + } + } + } + + switch (Aml.Opcode) + { + case AML_BYTE_OP: + + CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1); + break; + + case AML_WORD_OP: + + CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2); + break; + + case AML_DWORD_OP: + + CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4); + break; + + case AML_QWORD_OP: + + CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8); + break; + + case AML_STRING_OP: + + CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); + break; + + default: + + /* All data opcodes must appear above */ + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: CgWriteTableHeader + * + * PARAMETERS: Op - The DEFINITIONBLOCK node + * + * RETURN: None + * + * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK + * + ******************************************************************************/ + +static void +CgWriteTableHeader ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Child; + + + /* AML filename */ + + Child = Op->Asl.Child; + + /* Signature */ + + Child = Child->Asl.Next; + strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); + + /* Revision */ + + Child = Child->Asl.Next; + TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; + + /* Command-line Revision override */ + + if (Gbl_RevisionOverride) + { + TableHeader.Revision = Gbl_RevisionOverride; + } + + /* OEMID */ + + Child = Child->Asl.Next; + strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); + + /* OEM TableID */ + + Child = Child->Asl.Next; + strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); + + /* OEM Revision */ + + Child = Child->Asl.Next; + TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; + + /* Compiler ID */ + + ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); + + /* Compiler version */ + + TableHeader.AslCompilerRevision = ACPI_CA_VERSION; + + /* Table length. Checksum zero for now, will rewrite later */ + + TableHeader.Length = sizeof (ACPI_TABLE_HEADER) + + Op->Asl.AmlSubtreeLength; + TableHeader.Checksum = 0; + + Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); + + /* Write entire header and clear the table header global */ + + CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); + memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER)); +} + + +/******************************************************************************* + * + * FUNCTION: CgUpdateHeader + * + * PARAMETERS: Op - Op for the Definition Block + * + * RETURN: None. + * + * DESCRIPTION: Complete the ACPI table by calculating the checksum and + * re-writing the header for the input definition block + * + ******************************************************************************/ + +static void +CgUpdateHeader ( + ACPI_PARSE_OBJECT *Op) +{ + signed char Sum; + UINT32 i; + UINT32 Length; + UINT8 FileByte; + UINT8 Checksum; + + + /* Calculate the checksum over the entire definition block */ + + Sum = 0; + Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength; + FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset); + + for (i = 0; i < Length; i++) + { + if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK) + { + printf ("EOF while reading checksum bytes\n"); + return; + } + + Sum = (signed char) (Sum + FileByte); + } + + Checksum = (UINT8) (0 - Sum); + + /* Re-write the the checksum byte */ + + FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset + + ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum)); + + FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1); +} + + +/******************************************************************************* + * + * FUNCTION: CgCloseTable + * + * PARAMETERS: None. + * + * RETURN: None. + * + * DESCRIPTION: Complete the ACPI table by calculating the checksum and + * re-writing each table header. This allows support for + * multiple definition blocks in a single source file. + * + ******************************************************************************/ + +static void +CgCloseTable ( + void) +{ + ACPI_PARSE_OBJECT *Op; + + + /* Process all definition blocks */ + + Op = RootNode->Asl.Child; + while (Op) + { + CgUpdateHeader (Op); + Op = Op->Asl.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: CgWriteNode + * + * PARAMETERS: Op - Parse node to write. + * + * RETURN: None. + * + * DESCRIPTION: Write the AML that corresponds to a parse node. + * + ******************************************************************************/ + +static void +CgWriteNode ( + ACPI_PARSE_OBJECT *Op) +{ + ASL_RESOURCE_NODE *Rnode; + + + /* Always check for DEFAULT_ARG and other "Noop" nodes */ + /* TBD: this may not be the best place for this check */ + + if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || + (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || + (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || + (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) + { + return; + } + + Op->Asl.FinalAmlLength = 0; + + switch (Op->Asl.AmlOpcode) + { + case AML_RAW_DATA_BYTE: + case AML_RAW_DATA_WORD: + case AML_RAW_DATA_DWORD: + case AML_RAW_DATA_QWORD: + + CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); + return; + + + case AML_RAW_DATA_BUFFER: + + CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); + return; + + + case AML_RAW_DATA_CHAIN: + + Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); + while (Rnode) + { + CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); + Rnode = Rnode->Next; + } + return; + + default: + + /* Internal data opcodes must all appear above */ + + break; + } + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_DEFAULT_ARG: + + break; + + case PARSEOP_DEFINITION_BLOCK: + + CgWriteTableHeader (Op); + break; + + case PARSEOP_NAMESEG: + case PARSEOP_NAMESTRING: + case PARSEOP_METHODCALL: + + CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); + break; + + default: + + CgWriteAmlOpcode (Op); + break; + } +} diff --git a/third_party/lib/acpica/source/compiler/aslcompile.c b/third_party/lib/acpica/source/compiler/aslcompile.c new file mode 100644 index 000000000..4b8f15ed5 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslcompile.c @@ -0,0 +1,840 @@ +/****************************************************************************** + * + * Module Name: aslcompile - top level compile module + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" +#include "acnamesp.h" + +#include +#include +#include + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslcompile") + +/* + * Main parser entry + * External is here in case the parser emits the same external in the + * generated header. (Newer versions of Bison) + */ +int +AslCompilerparse( + void); + +/* Local prototypes */ + +static void +CmFlushSourceCode ( + void); + +static void +CmDumpAllEvents ( + void); + + +/******************************************************************************* + * + * FUNCTION: CmDoCompile + * + * PARAMETERS: None + * + * RETURN: Status (0 = OK) + * + * DESCRIPTION: This procedure performs the entire compile + * + ******************************************************************************/ + +int +CmDoCompile ( + void) +{ + ACPI_STATUS Status; + UINT8 FullCompile; + UINT8 Event; + + + FullCompile = UtBeginEvent ("*** Total Compile time ***"); + Event = UtBeginEvent ("Open input and output files"); + UtEndEvent (Event); + + Event = UtBeginEvent ("Preprocess input file"); + if (Gbl_PreprocessFlag) + { + /* Enter compiler name as a #define */ + + PrAddDefine (ASL_DEFINE, "", FALSE); + + /* Preprocessor */ + + PrDoPreprocess (); + Gbl_CurrentLineNumber = 1; + Gbl_LogicalLineNumber = 1; + + if (Gbl_PreprocessOnly) + { + UtEndEvent (Event); + CmCleanupAndExit (); + return (0); + } + } + UtEndEvent (Event); + + + /* Build the parse tree */ + + Event = UtBeginEvent ("Parse source code and build parse tree"); + AslCompilerparse(); + UtEndEvent (Event); + + /* Check for parser-detected syntax errors */ + + if (Gbl_SyntaxError) + { + fprintf (stderr, + "Compiler aborting due to parser-detected syntax error(s)\n"); + LsDumpParseTree (); + goto ErrorExit; + } + + /* Did the parse tree get successfully constructed? */ + + if (!RootNode) + { + /* + * If there are no errors, then we have some sort of + * internal problem. + */ + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, + NULL, "- Could not resolve parse tree root node"); + + goto ErrorExit; + } + + /* Flush out any remaining source after parse tree is complete */ + + Event = UtBeginEvent ("Flush source input"); + CmFlushSourceCode (); + + /* Prune the parse tree if requested (debug purposes only) */ + + if (Gbl_PruneParseTree) + { + AslPruneParseTree (Gbl_PruneDepth, Gbl_PruneType); + } + + /* Optional parse tree dump, compiler debug output only */ + + LsDumpParseTree (); + + OpcGetIntegerWidth (RootNode->Asl.Child); + UtEndEvent (Event); + + /* Pre-process parse tree for any operator transforms */ + + Event = UtBeginEvent ("Parse tree transforms"); + DbgPrint (ASL_DEBUG_OUTPUT, "\nParse tree transforms\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + TrAmlTransformWalk, NULL, NULL); + UtEndEvent (Event); + + /* Generate AML opcodes corresponding to the parse tokens */ + + Event = UtBeginEvent ("Generate AML opcodes"); + DbgPrint (ASL_DEBUG_OUTPUT, "\nGenerating AML opcodes\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, NULL, + OpcAmlOpcodeWalk, NULL); + UtEndEvent (Event); + + /* + * Now that the input is parsed, we can open the AML output file. + * Note: by default, the name of this file comes from the table + * descriptor within the input file. + */ + Event = UtBeginEvent ("Open AML output file"); + Status = FlOpenAmlOutputFile (Gbl_OutputFilenamePrefix); + UtEndEvent (Event); + if (ACPI_FAILURE (Status)) + { + AePrintErrorLog (ASL_FILE_STDERR); + return (-1); + } + + /* Interpret and generate all compile-time constants */ + + Event = UtBeginEvent ("Constant folding via AML interpreter"); + DbgPrint (ASL_DEBUG_OUTPUT, + "\nInterpreting compile-time constant expressions\n\n"); + + if (Gbl_FoldConstants) + { + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + OpcAmlConstantWalk, NULL, NULL); + } + else + { + DbgPrint (ASL_PARSE_OUTPUT, " Optional folding disabled\n"); + } + UtEndEvent (Event); + + /* Update AML opcodes if necessary, after constant folding */ + + Event = UtBeginEvent ("Updating AML opcodes after constant folding"); + DbgPrint (ASL_DEBUG_OUTPUT, + "\nUpdating AML opcodes after constant folding\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, + NULL, OpcAmlOpcodeUpdateWalk, NULL); + UtEndEvent (Event); + + /* Calculate all AML package lengths */ + + Event = UtBeginEvent ("Generate AML package lengths"); + DbgPrint (ASL_DEBUG_OUTPUT, "\nGenerating Package lengths\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, NULL, + LnPackageLengthWalk, NULL); + UtEndEvent (Event); + + if (Gbl_ParseOnlyFlag) + { + AePrintErrorLog (ASL_FILE_STDERR); + UtDisplaySummary (ASL_FILE_STDERR); + if (Gbl_DebugFlag) + { + /* Print error summary to the stdout also */ + + AePrintErrorLog (ASL_FILE_STDOUT); + UtDisplaySummary (ASL_FILE_STDOUT); + } + UtEndEvent (FullCompile); + return (0); + } + + /* + * Create an internal namespace and use it as a symbol table + */ + + /* Namespace loading */ + + Event = UtBeginEvent ("Create ACPI Namespace"); + Status = LdLoadNamespace (RootNode); + UtEndEvent (Event); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* Namespace cross-reference */ + + AslGbl_NamespaceEvent = UtBeginEvent ( + "Cross reference parse tree and Namespace"); + Status = XfCrossReferenceNamespace (); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* Namespace - Check for non-referenced objects */ + + LkFindUnreferencedObjects (); + UtEndEvent (AslGbl_NamespaceEvent); + + /* + * Semantic analysis. This can happen only after the + * namespace has been loaded and cross-referenced. + * + * part one - check control methods + */ + Event = UtBeginEvent ("Analyze control method return types"); + AnalysisWalkInfo.MethodStack = NULL; + + DbgPrint (ASL_DEBUG_OUTPUT, "\nSemantic analysis - Method analysis\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_TWICE, + MtMethodAnalysisWalkBegin, + MtMethodAnalysisWalkEnd, &AnalysisWalkInfo); + UtEndEvent (Event); + + /* Semantic error checking part two - typing of method returns */ + + Event = UtBeginEvent ("Determine object types returned by methods"); + DbgPrint (ASL_DEBUG_OUTPUT, "\nSemantic analysis - Method typing\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, + NULL, AnMethodTypingWalkEnd, NULL); + UtEndEvent (Event); + + /* Semantic error checking part three - operand type checking */ + + Event = UtBeginEvent ("Analyze AML operand types"); + DbgPrint (ASL_DEBUG_OUTPUT, + "\nSemantic analysis - Operand type checking\n\n"); + if (Gbl_DoTypechecking) + { + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, + NULL, AnOperandTypecheckWalkEnd, &AnalysisWalkInfo); + } + UtEndEvent (Event); + + /* Semantic error checking part four - other miscellaneous checks */ + + Event = UtBeginEvent ("Miscellaneous analysis"); + DbgPrint (ASL_DEBUG_OUTPUT, "\nSemantic analysis - miscellaneous\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + AnOtherSemanticAnalysisWalkBegin, + NULL, &AnalysisWalkInfo); + UtEndEvent (Event); + + /* Calculate all AML package lengths */ + + Event = UtBeginEvent ("Finish AML package length generation"); + DbgPrint (ASL_DEBUG_OUTPUT, "\nGenerating Package lengths\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, NULL, + LnInitLengthsWalk, NULL); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_UPWARD, NULL, + LnPackageLengthWalk, NULL); + UtEndEvent (Event); + + /* Code generation - emit the AML */ + + Event = UtBeginEvent ("Generate AML code and write output files"); + CgGenerateAmlOutput (); + UtEndEvent (Event); + + Event = UtBeginEvent ("Write optional output files"); + CmDoOutputFiles (); + UtEndEvent (Event); + + UtEndEvent (FullCompile); + CmCleanupAndExit (); + return (0); + +ErrorExit: + UtEndEvent (FullCompile); + CmCleanupAndExit (); + return (-1); +} + + +/******************************************************************************* + * + * FUNCTION: AslCompilerSignon + * + * PARAMETERS: FileId - ID of the output file + * + * RETURN: None + * + * DESCRIPTION: Display compiler signon + * + ******************************************************************************/ + +void +AslCompilerSignon ( + UINT32 FileId) +{ + char *Prefix = ""; + char *UtilityName; + + + /* Set line prefix depending on the destination file type */ + + switch (FileId) + { + case ASL_FILE_ASM_SOURCE_OUTPUT: + case ASL_FILE_ASM_INCLUDE_OUTPUT: + + Prefix = "; "; + break; + + case ASL_FILE_HEX_OUTPUT: + + if (Gbl_HexOutputFlag == HEX_OUTPUT_ASM) + { + Prefix = "; "; + } + else if ((Gbl_HexOutputFlag == HEX_OUTPUT_C) || + (Gbl_HexOutputFlag == HEX_OUTPUT_ASL)) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, "/*\n"); + Prefix = " * "; + } + break; + + case ASL_FILE_C_SOURCE_OUTPUT: + case ASL_FILE_C_OFFSET_OUTPUT: + case ASL_FILE_C_INCLUDE_OUTPUT: + + Prefix = " * "; + break; + + default: + + /* No other output types supported */ + + break; + } + + /* Running compiler or disassembler? */ + + if (Gbl_DisasmFlag) + { + UtilityName = AML_DISASSEMBLER_NAME; + } + else + { + UtilityName = ASL_COMPILER_NAME; + } + + /* Compiler signon with copyright */ + + FlPrintFile (FileId, "%s\n", Prefix); + FlPrintFile (FileId, ACPI_COMMON_HEADER (UtilityName, Prefix)); +} + + +/******************************************************************************* + * + * FUNCTION: AslCompilerFileHeader + * + * PARAMETERS: FileId - ID of the output file + * + * RETURN: None + * + * DESCRIPTION: Header used at the beginning of output files + * + ******************************************************************************/ + +void +AslCompilerFileHeader ( + UINT32 FileId) +{ + struct tm *NewTime; + time_t Aclock; + char *Prefix = ""; + + + /* Set line prefix depending on the destination file type */ + + switch (FileId) + { + case ASL_FILE_ASM_SOURCE_OUTPUT: + case ASL_FILE_ASM_INCLUDE_OUTPUT: + + Prefix = "; "; + break; + + case ASL_FILE_HEX_OUTPUT: + + if (Gbl_HexOutputFlag == HEX_OUTPUT_ASM) + { + Prefix = "; "; + } + else if ((Gbl_HexOutputFlag == HEX_OUTPUT_C) || + (Gbl_HexOutputFlag == HEX_OUTPUT_ASL)) + { + Prefix = " * "; + } + break; + + case ASL_FILE_C_SOURCE_OUTPUT: + case ASL_FILE_C_OFFSET_OUTPUT: + case ASL_FILE_C_INCLUDE_OUTPUT: + + Prefix = " * "; + break; + + default: + + /* No other output types supported */ + + break; + } + + /* Compilation header with timestamp */ + + (void) time (&Aclock); + NewTime = localtime (&Aclock); + + FlPrintFile (FileId, + "%sCompilation of \"%s\" - %s%s\n", + Prefix, Gbl_Files[ASL_FILE_INPUT].Filename, asctime (NewTime), + Prefix); + + switch (FileId) + { + case ASL_FILE_C_SOURCE_OUTPUT: + case ASL_FILE_C_OFFSET_OUTPUT: + case ASL_FILE_C_INCLUDE_OUTPUT: + + FlPrintFile (FileId, " */\n"); + break; + + default: + + /* Nothing to do for other output types */ + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: CmFlushSourceCode + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Read in any remaining source code after the parse tree + * has been constructed. + * + ******************************************************************************/ + +static void +CmFlushSourceCode ( + void) +{ + char Buffer; + + + while (FlReadFile (ASL_FILE_INPUT, &Buffer, 1) != AE_ERROR) + { + AslInsertLineBuffer ((int) Buffer); + } + + AslResetCurrentLineBuffer (); +} + + +/******************************************************************************* + * + * FUNCTION: CmDoOutputFiles + * + * PARAMETERS: None + * + * RETURN: None. + * + * DESCRIPTION: Create all "listing" type files + * + ******************************************************************************/ + +void +CmDoOutputFiles ( + void) +{ + + /* Create listings and hex files */ + + LsDoListings (); + HxDoHexOutput (); + + /* Dump the namespace to the .nsp file if requested */ + + (void) NsDisplayNamespace (); + + /* Dump the device mapping file */ + + MpEmitMappingInfo (); +} + + +/******************************************************************************* + * + * FUNCTION: CmDumpAllEvents + * + * PARAMETERS: None + * + * RETURN: None. + * + * DESCRIPTION: Dump all compiler events + * + ******************************************************************************/ + +static void +CmDumpAllEvents ( + void) +{ + ASL_EVENT_INFO *Event; + UINT32 Delta; + UINT32 MicroSeconds; + UINT32 MilliSeconds; + UINT32 i; + + + Event = AslGbl_Events; + + DbgPrint (ASL_DEBUG_OUTPUT, "\n\nElapsed time for major events\n\n"); + if (Gbl_CompileTimesFlag) + { + printf ("\nElapsed time for major events\n\n"); + } + + for (i = 0; i < AslGbl_NextEvent; i++) + { + if (Event->Valid) + { + /* Delta will be in 100-nanosecond units */ + + Delta = (UINT32) (Event->EndTime - Event->StartTime); + + MicroSeconds = Delta / ACPI_100NSEC_PER_USEC; + MilliSeconds = Delta / ACPI_100NSEC_PER_MSEC; + + /* Round milliseconds up */ + + if ((MicroSeconds - (MilliSeconds * ACPI_USEC_PER_MSEC)) >= 500) + { + MilliSeconds++; + } + + DbgPrint (ASL_DEBUG_OUTPUT, "%8u usec %8u msec - %s\n", + MicroSeconds, MilliSeconds, Event->EventName); + + if (Gbl_CompileTimesFlag) + { + printf ("%8u usec %8u msec - %s\n", + MicroSeconds, MilliSeconds, Event->EventName); + } + } + + Event++; + } +} + + +/******************************************************************************* + * + * FUNCTION: CmCleanupAndExit + * + * PARAMETERS: None + * + * RETURN: None. + * + * DESCRIPTION: Close all open files and exit the compiler + * + ******************************************************************************/ + +void +CmCleanupAndExit ( + void) +{ + UINT32 i; + BOOLEAN DeleteAmlFile = FALSE; + + + AePrintErrorLog (ASL_FILE_STDERR); + if (Gbl_DebugFlag) + { + /* Print error summary to stdout also */ + + AePrintErrorLog (ASL_FILE_STDOUT); + } + + /* Emit compile times if enabled */ + + CmDumpAllEvents (); + + if (Gbl_CompileTimesFlag) + { + printf ("\nMiscellaneous compile statistics\n\n"); + printf ("%11u : %s\n", TotalParseNodes, "Parse nodes"); + printf ("%11u : %s\n", Gbl_NsLookupCount, "Namespace searches"); + printf ("%11u : %s\n", TotalNamedObjects, "Named objects"); + printf ("%11u : %s\n", TotalMethods, "Control methods"); + printf ("%11u : %s\n", TotalAllocations, "Memory Allocations"); + printf ("%11u : %s\n", TotalAllocated, "Total allocated memory"); + printf ("%11u : %s\n", TotalFolds, "Constant subtrees folded"); + printf ("\n"); + } + + if (Gbl_NsLookupCount) + { + DbgPrint (ASL_DEBUG_OUTPUT, + "\n\nMiscellaneous compile statistics\n\n"); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%32s : %u\n", "Total Namespace searches", + Gbl_NsLookupCount); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%32s : %u usec\n", "Time per search", ((UINT32) + (AslGbl_Events[AslGbl_NamespaceEvent].EndTime - + AslGbl_Events[AslGbl_NamespaceEvent].StartTime) / 10) / + Gbl_NsLookupCount); + } + + if (Gbl_ExceptionCount[ASL_ERROR] > ASL_MAX_ERROR_COUNT) + { + printf ("\nMaximum error count (%u) exceeded\n", + ASL_MAX_ERROR_COUNT); + } + + UtDisplaySummary (ASL_FILE_STDOUT); + + /* + * We will delete the AML file if there are errors and the + * force AML output option has not been used. + */ + if ((Gbl_ExceptionCount[ASL_ERROR] > 0) && + (!Gbl_IgnoreErrors) && + Gbl_Files[ASL_FILE_AML_OUTPUT].Handle) + { + DeleteAmlFile = TRUE; + } + + /* Close all open files */ + + /* + * Take care with the preprocessor file (.pre), it might be the same + * as the "input" file, depending on where the compiler has terminated + * or aborted. Prevent attempt to close the same file twice in + * loop below. + */ + if (Gbl_Files[ASL_FILE_PREPROCESSOR].Handle == + Gbl_Files[ASL_FILE_INPUT].Handle) + { + Gbl_Files[ASL_FILE_PREPROCESSOR].Handle = NULL; + } + + /* Close the standard I/O files */ + + for (i = ASL_FILE_INPUT; i < ASL_MAX_FILE_TYPE; i++) + { + FlCloseFile (i); + } + + /* Delete AML file if there are errors */ + + if (DeleteAmlFile) + { + FlDeleteFile (ASL_FILE_AML_OUTPUT); + } + + /* Delete the preprocessor temp file unless full debug was specified */ + + if (Gbl_PreprocessFlag && !Gbl_KeepPreprocessorTempFile) + { + FlDeleteFile (ASL_FILE_PREPROCESSOR); + } + + /* + * Delete intermediate ("combined") source file (if -ls flag not set) + * This file is created during normal ASL/AML compiles. It is not + * created by the data table compiler. + * + * If the -ls flag is set, then the .SRC file should not be deleted. + * In this case, Gbl_SourceOutputFlag is set to TRUE. + * + * Note: Handles are cleared by FlCloseFile above, so we look at the + * filename instead, to determine if the .SRC file was actually + * created. + */ + if (!Gbl_SourceOutputFlag) + { + FlDeleteFile (ASL_FILE_SOURCE_OUTPUT); + } + + /* Final cleanup after compiling one file */ + + CmDeleteCaches (); +} + + +/******************************************************************************* + * + * FUNCTION: CmDeleteCaches + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all local cache buffer blocks + * + ******************************************************************************/ + +void +CmDeleteCaches ( + void) +{ + UINT32 BufferCount; + ASL_CACHE_INFO *Next; + + + /* Parse Op cache */ + + BufferCount = 0; + while (Gbl_ParseOpCacheList) + { + Next = Gbl_ParseOpCacheList->Next; + ACPI_FREE (Gbl_ParseOpCacheList); + Gbl_ParseOpCacheList = Next; + BufferCount++; + } + + DbgPrint (ASL_DEBUG_OUTPUT, + "%u ParseOps, Buffer size: %u ops (%u bytes), %u Buffers\n", + Gbl_ParseOpCount, ASL_PARSEOP_CACHE_SIZE, + (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE), BufferCount); + + Gbl_ParseOpCount = 0; + Gbl_ParseOpCacheNext = NULL; + Gbl_ParseOpCacheLast = NULL; + RootNode = NULL; + + /* Generic string cache */ + + BufferCount = 0; + while (Gbl_StringCacheList) + { + Next = Gbl_StringCacheList->Next; + ACPI_FREE (Gbl_StringCacheList); + Gbl_StringCacheList = Next; + BufferCount++; + } + + DbgPrint (ASL_DEBUG_OUTPUT, + "%u Strings (%u bytes), Buffer size: %u bytes, %u Buffers\n", + Gbl_StringCount, Gbl_StringSize, ASL_STRING_CACHE_SIZE, BufferCount); + + Gbl_StringSize = 0; + Gbl_StringCount = 0; + Gbl_StringCacheNext = NULL; + Gbl_StringCacheLast = NULL; +} diff --git a/third_party/lib/acpica/source/compiler/aslcompiler.h b/third_party/lib/acpica/source/compiler/aslcompiler.h new file mode 100644 index 000000000..721abe46f --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslcompiler.h @@ -0,0 +1,1290 @@ +/****************************************************************************** + * + * Module Name: aslcompiler.h - common include file for iASL + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ASLCOMPILER_H +#define __ASLCOMPILER_H + +#include "acpi.h" +#include "accommon.h" +#include "amlresrc.h" +#include "acdebug.h" + +/* Microsoft-specific */ + +#if (defined WIN32 || defined WIN64) + +/* warn : used #pragma pack */ +#pragma warning(disable:4103) + +/* warn : named type definition in parentheses */ +#pragma warning(disable:4115) +#endif + +#include +#include +#include +#include +#include +#include + +/* Compiler headers */ + +#include "asldefine.h" +#include "asltypes.h" +#include "aslmessages.h" +#include "aslglobal.h" +#include "preprocess.h" + + +/******************************************************************************* + * + * Compiler prototypes + * + ******************************************************************************/ + +/* + * Main ASL parser - generated from flex/bison, lex/yacc, etc. + */ +ACPI_PARSE_OBJECT * +AslDoError ( + void); + +int +AslCompilerlex( + void); + +void +AslResetCurrentLineBuffer ( + void); + +void +AslInsertLineBuffer ( + int SourceChar); + +int +AslPopInputFileStack ( + void); + +void +AslPushInputFileStack ( + FILE *InputFile, + char *Filename); + +void +AslParserCleanup ( + void); + + +/* + * aslstartup - entered from main() + */ +void +AslInitializeGlobals ( + void); + +typedef +ACPI_STATUS (*ASL_PATHNAME_CALLBACK) ( + char *); + +ACPI_STATUS +AslDoOneFile ( + char *Filename); + +ACPI_STATUS +AslCheckForErrorExit ( + void); + + +/* + * aslcompile - compile mainline + */ +void +AslCompilerSignon ( + UINT32 FileId); + +void +AslCompilerFileHeader ( + UINT32 FileId); + +int +CmDoCompile ( + void); + +void +CmDoOutputFiles ( + void); + +void +CmCleanupAndExit ( + void); + +void +CmDeleteCaches ( + void); + + +/* + * aslascii - ascii support + */ +ACPI_STATUS +FlIsFileAsciiSource ( + char *Filename, + BOOLEAN DisplayErrors); + + +/* + * aslwalks - semantic analysis and parse tree walks + */ +ACPI_STATUS +AnOtherSemanticAnalysisWalkBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +ACPI_STATUS +AnOtherSemanticAnalysisWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +ACPI_STATUS +AnOperandTypecheckWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +ACPI_STATUS +AnMethodTypingWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/* + * aslmethod - Control method analysis walk + */ +ACPI_STATUS +MtMethodAnalysisWalkBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +ACPI_STATUS +MtMethodAnalysisWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/* + * aslbtypes - bitfield data types + */ +UINT32 +AnMapObjTypeToBtype ( + ACPI_PARSE_OBJECT *Op); + +UINT32 +AnMapArgTypeToBtype ( + UINT32 ArgType); + +UINT32 +AnGetBtype ( + ACPI_PARSE_OBJECT *Op); + +void +AnFormatBtype ( + char *Buffer, + UINT32 Btype); + + +/* + * aslanalyze - Support functions for parse tree walks + */ +void +AnCheckId ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAME Type); + +/* Values for Type argument above */ + +#define ASL_TYPE_HID 0 +#define ASL_TYPE_CID 1 + +BOOLEAN +AnIsInternalMethod ( + ACPI_PARSE_OBJECT *Op); + +UINT32 +AnGetInternalMethodReturnType ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AnLastStatementIsReturn ( + ACPI_PARSE_OBJECT *Op); + +void +AnCheckMethodReturnValue ( + ACPI_PARSE_OBJECT *Op, + const ACPI_OPCODE_INFO *OpInfo, + ACPI_PARSE_OBJECT *ArgOp, + UINT32 RequiredBtypes, + UINT32 ThisNodeBtype); + +BOOLEAN +AnIsResultUsed ( + ACPI_PARSE_OBJECT *Op); + +void +ApCheckForGpeNameConflict ( + ACPI_PARSE_OBJECT *Op); + +void +ApCheckRegMethod ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +ApFindNameInScope ( + char *Name, + ACPI_PARSE_OBJECT *Op); + + +/* + * aslerror - error handling/reporting + */ +void +AslAbort ( + void); + +void +AslError ( + UINT8 Level, + UINT16 MessageId, + ACPI_PARSE_OBJECT *Op, + char *ExtraMessage); + +ACPI_STATUS +AslDisableException ( + char *MessageIdString); + +BOOLEAN +AslIsExceptionDisabled ( + UINT8 Level, + UINT16 MessageId); + +void +AslCoreSubsystemError ( + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS Status, + char *ExtraMessage, + BOOLEAN Abort); + +int +AslCompilererror( + const char *s); + +void +AslCommonError ( + UINT8 Level, + UINT16 MessageId, + UINT32 CurrentLineNumber, + UINT32 LogicalLineNumber, + UINT32 LogicalByteOffset, + UINT32 Column, + char *Filename, + char *ExtraMessage); + +void +AslCommonError2 ( + UINT8 Level, + UINT16 MessageId, + UINT32 LineNumber, + UINT32 Column, + char *SourceLine, + char *Filename, + char *ExtraMessage); + +void +AePrintException ( + UINT32 FileId, + ASL_ERROR_MSG *Enode, + char *Header); + +void +AePrintErrorLog ( + UINT32 FileId); + +void +AeClearErrorLog ( + void); + + +/* + * asllisting - generate all "listing" type files + */ +void +LsDoListings ( + void); + +void +LsWriteNodeToAsmListing ( + ACPI_PARSE_OBJECT *Op); + +void +LsWriteNode ( + ACPI_PARSE_OBJECT *Op, + UINT32 FileId); + +void +LsDumpParseTree ( + void); + + +/* + * asllistsup - Listing file support utilities + */ +void +LsDumpAscii ( + UINT32 FileId, + UINT32 Count, + UINT8 *Buffer); + +void +LsDumpAsciiInComment ( + UINT32 FileId, + UINT32 Count, + UINT8 *Buffer); + +void +LsCheckException ( + UINT32 LineNumber, + UINT32 FileId); + +void +LsFlushListingBuffer ( + UINT32 FileId); + +void +LsWriteListingHexBytes ( + UINT8 *Buffer, + UINT32 Length, + UINT32 FileId); + +void +LsWriteSourceLines ( + UINT32 ToLineNumber, + UINT32 ToLogicalLineNumber, + UINT32 FileId); + +UINT32 +LsWriteOneSourceLine ( + UINT32 FileId); + +void +LsPushNode ( + char *Filename); + +ASL_LISTING_NODE * +LsPopNode ( + void); + + +/* + * aslhex - generate all "hex" output files (C, ASM, ASL) + */ +void +HxDoHexOutput ( + void); + + +/* + * aslfold - constant folding + */ +ACPI_STATUS +OpcAmlConstantWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/* + * aslmessages - exception strings + */ +const char * +AeDecodeMessageId ( + UINT16 MessageId); + +const char * +AeDecodeExceptionLevel ( + UINT8 Level); + +UINT16 +AeBuildFullExceptionCode ( + UINT8 Level, + UINT16 MessageId); + +/* + * asloffset - generate C offset file for BIOS support + */ +ACPI_STATUS +LsAmlOffsetWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +void +LsDoOffsetTableHeader ( + UINT32 FileId); + +void +LsDoOffsetTableFooter ( + UINT32 FileId); + + +/* + * aslopcodes - generate AML opcodes + */ +ACPI_STATUS +OpcAmlOpcodeWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +ACPI_STATUS +OpcAmlOpcodeUpdateWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +void +OpcGenerateAmlOpcode ( + ACPI_PARSE_OBJECT *Op); + +UINT32 +OpcSetOptimalIntegerSize ( + ACPI_PARSE_OBJECT *Op); + +void +OpcGetIntegerWidth ( + ACPI_PARSE_OBJECT *Op); + + +/* + * asloperands - generate AML operands for the AML opcodes + */ +ACPI_PARSE_OBJECT * +UtGetArg ( + ACPI_PARSE_OBJECT *Op, + UINT32 Argn); + +void +OpnGenerateAmlOperands ( + ACPI_PARSE_OBJECT *Op); + +void +OpnDoPackage ( + ACPI_PARSE_OBJECT *Op); + + +/* + * aslopt - optmization + */ +void +OptOptimizeNamePath ( + ACPI_PARSE_OBJECT *Op, + UINT32 Flags, + ACPI_WALK_STATE *WalkState, + char *AmlNameString, + ACPI_NAMESPACE_NODE *TargetNode); + + +/* + * aslprintf - Printf/Fprintf macros + */ +void +OpcDoPrintf ( + ACPI_PARSE_OBJECT *Op); + +void +OpcDoFprintf ( + ACPI_PARSE_OBJECT *Op); + + +/* + * aslprune - parse tree pruner + */ +void +AslPruneParseTree ( + UINT32 PruneDepth, + UINT32 Type); + + +/* + * aslcodegen - code generation + */ +void +CgGenerateAmlOutput ( + void); + + +/* + * aslfile + */ +void +FlOpenFile ( + UINT32 FileId, + char *Filename, + char *Mode); + + +/* + * asllength - calculate/adjust AML package lengths + */ +ACPI_STATUS +LnPackageLengthWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +ACPI_STATUS +LnInitLengthsWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +void +CgGenerateAmlLengths ( + ACPI_PARSE_OBJECT *Op); + + +/* + * aslmap - opcode mappings and reserved method names + */ +ACPI_OBJECT_TYPE +AslMapNamedOpcodeToDataType ( + UINT16 Opcode); + + +/* + * aslpredef - ACPI predefined names support + */ +BOOLEAN +ApCheckForPredefinedMethod ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo); + +void +ApCheckPredefinedReturnValue ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo); + +UINT32 +ApCheckForPredefinedName ( + ACPI_PARSE_OBJECT *Op, + char *Name); + +void +ApCheckForPredefinedObject ( + ACPI_PARSE_OBJECT *Op, + char *Name); + +ACPI_STATUS +ApCheckObjectType ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT32 ExpectedBtypes, + UINT32 PackageIndex); + +void +ApDisplayReservedNames ( + void); + + +/* + * aslprepkg - ACPI predefined names support for packages + */ +void +ApCheckPackage ( + ACPI_PARSE_OBJECT *ParentOp, + const ACPI_PREDEFINED_INFO *Predefined); + + +/* + * asltransform - parse tree transformations + */ +ACPI_STATUS +TrAmlTransformWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/* + * asltree - parse tree support + */ +ACPI_STATUS +TrWalkParseTree ( + ACPI_PARSE_OBJECT *Op, + UINT32 Visitation, + ASL_WALK_CALLBACK DescendingCallback, + ASL_WALK_CALLBACK AscendingCallback, + void *Context); + +/* Values for "Visitation" parameter above */ + +#define ASL_WALK_VISIT_DOWNWARD 0x01 +#define ASL_WALK_VISIT_UPWARD 0x02 +#define ASL_WALK_VISIT_TWICE (ASL_WALK_VISIT_DOWNWARD | ASL_WALK_VISIT_UPWARD) + + +ACPI_PARSE_OBJECT * +TrAllocateNode ( + UINT32 ParseOpcode); + +void +TrPrintNodeCompileFlags ( + UINT32 Flags); + +void +TrReleaseNode ( + ACPI_PARSE_OBJECT *Op); + +ACPI_PARSE_OBJECT * +TrUpdateNode ( + UINT32 ParseOpcode, + ACPI_PARSE_OBJECT *Op); + +ACPI_PARSE_OBJECT * +TrCreateNode ( + UINT32 ParseOpcode, + UINT32 NumChildren, + ...); + +ACPI_PARSE_OBJECT * +TrCreateLeafNode ( + UINT32 ParseOpcode); + +ACPI_PARSE_OBJECT * +TrCreateNullTarget ( + void); + +ACPI_PARSE_OBJECT * +TrCreateAssignmentNode ( + ACPI_PARSE_OBJECT *Target, + ACPI_PARSE_OBJECT *Source); + +ACPI_PARSE_OBJECT * +TrCreateTargetOperand ( + ACPI_PARSE_OBJECT *OriginalOp, + ACPI_PARSE_OBJECT *ParentOp); + +ACPI_PARSE_OBJECT * +TrCreateValuedLeafNode ( + UINT32 ParseOpcode, + UINT64 Value); + +ACPI_PARSE_OBJECT * +TrCreateConstantLeafNode ( + UINT32 ParseOpcode); + +ACPI_PARSE_OBJECT * +TrLinkChildren ( + ACPI_PARSE_OBJECT *Op, + UINT32 NumChildren, + ...); + +void +TrSetEndLineNumber ( + ACPI_PARSE_OBJECT *Op); + +void +TrSetCurrentFilename ( + ACPI_PARSE_OBJECT *Op); + +void +TrWalkTree ( + void); + +ACPI_PARSE_OBJECT * +TrLinkPeerNode ( + ACPI_PARSE_OBJECT *Op1, + ACPI_PARSE_OBJECT *Op2); + +ACPI_PARSE_OBJECT * +TrLinkChildNode ( + ACPI_PARSE_OBJECT *Op1, + ACPI_PARSE_OBJECT *Op2); + +ACPI_PARSE_OBJECT * +TrSetNodeFlags ( + ACPI_PARSE_OBJECT *Op, + UINT32 Flags); + +ACPI_PARSE_OBJECT * +TrSetNodeAmlLength ( + ACPI_PARSE_OBJECT *Op, + UINT32 Length); + +ACPI_PARSE_OBJECT * +TrLinkPeerNodes ( + UINT32 NumPeers, + ...); + + +/* + * aslfiles - File I/O support + */ +void +FlAddIncludeDirectory ( + char *Dir); + +char * +FlMergePathnames ( + char *PrefixDir, + char *FilePathname); + +void +FlOpenIncludeFile ( + ACPI_PARSE_OBJECT *Op); + +void +FlFileError ( + UINT32 FileId, + UINT8 ErrorId); + +UINT32 +FlGetFileSize ( + UINT32 FileId); + +ACPI_STATUS +FlReadFile ( + UINT32 FileId, + void *Buffer, + UINT32 Length); + +void +FlWriteFile ( + UINT32 FileId, + void *Buffer, + UINT32 Length); + +void +FlSeekFile ( + UINT32 FileId, + long Offset); + +void +FlCloseFile ( + UINT32 FileId); + +void +FlPrintFile ( + UINT32 FileId, + char *Format, + ...); + +void +FlDeleteFile ( + UINT32 FileId); + +void +FlSetLineNumber ( + UINT32 LineNumber); + +void +FlSetFilename ( + char *Filename); + +ACPI_STATUS +FlOpenInputFile ( + char *InputFilename); + +ACPI_STATUS +FlOpenAmlOutputFile ( + char *InputFilename); + +ACPI_STATUS +FlOpenMiscOutputFiles ( + char *InputFilename); + +/* + * aslhwmap - hardware map summary + */ +void +MpEmitMappingInfo ( + void); + + +/* + * asload - load namespace in prep for cross reference + */ +ACPI_STATUS +LdLoadNamespace ( + ACPI_PARSE_OBJECT *RootOp); + + +/* + * asllookup - namespace lookup functions + */ +void +LkFindUnreferencedObjects ( + void); + +/* + * aslmain - startup + */ +void +Usage ( + void); + +void +AslFilenameHelp ( + void); + + +/* + * aslnamesp - namespace output file generation + */ +ACPI_STATUS +NsDisplayNamespace ( + void); + +void +NsSetupNamespaceListing ( + void *Handle); + +/* + * asloptions - command line processing + */ +int +AslCommandLine ( + int argc, + char **argv); + +/* + * aslxref - namespace cross reference + */ +ACPI_STATUS +XfCrossReferenceNamespace ( + void); + + +/* + * aslutils - common compiler utilites + */ +void +DbgPrint ( + UINT32 Type, + char *Format, + ...); + +/* Type values for above */ + +#define ASL_DEBUG_OUTPUT 0 +#define ASL_PARSE_OUTPUT 1 +#define ASL_TREE_OUTPUT 2 + +BOOLEAN +UtQueryForOverwrite ( + char *Pathname); + +void +UtDisplaySupportedTables ( + void); + +void +UtDisplayConstantOpcodes ( + void); + +UINT8 +UtBeginEvent ( + char *Name); + +void +UtEndEvent ( + UINT8 Event); + +void * +UtLocalCalloc ( + UINT32 Size); + +void +UtPrintFormattedName ( + UINT16 ParseOpcode, + UINT32 Level); + +void +UtDisplaySummary ( + UINT32 FileId); + +void +UtConvertByteToHex ( + UINT8 RawByte, + UINT8 *Buffer); + +void +UtConvertByteToAsmHex ( + UINT8 RawByte, + UINT8 *Buffer); + +char * +UtGetOpName ( + UINT32 ParseOpcode); + +void +UtSetParseOpName ( + ACPI_PARSE_OBJECT *Op); + +char * +UtStringCacheCalloc ( + UINT32 Length); + +void +UtExpandLineBuffers ( + void); + +void +UtFreeLineBuffers ( + void); + +ACPI_STATUS +UtInternalizeName ( + char *ExternalName, + char **ConvertedName); + +void +UtAttachNamepathToOwner ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *NameNode); + +ACPI_PARSE_OBJECT * +UtCheckIntegerRange ( + ACPI_PARSE_OBJECT *Op, + UINT32 LowValue, + UINT32 HighValue); + +UINT64 +UtDoConstant ( + char *String); + +ACPI_STATUS +stroul64 ( + char *String, + UINT32 Base, + UINT64 *RetInteger); + + +/* + * asluuid - UUID support + */ +ACPI_STATUS +AuValidateUuid ( + char *InString); + +ACPI_STATUS +AuConvertUuidToString ( + char *UuIdBuffer, + char *OutString); + +/* + * aslresource - Resource template generation utilities + */ +void +RsSmallAddressCheck ( + UINT8 Type, + UINT32 Minimum, + UINT32 Maximum, + UINT32 Length, + UINT32 Alignment, + ACPI_PARSE_OBJECT *MinOp, + ACPI_PARSE_OBJECT *MaxOp, + ACPI_PARSE_OBJECT *LengthOp, + ACPI_PARSE_OBJECT *AlignOp, + ACPI_PARSE_OBJECT *Op); + +void +RsLargeAddressCheck ( + UINT64 Minimum, + UINT64 Maximum, + UINT64 Length, + UINT64 Granularity, + UINT8 Flags, + ACPI_PARSE_OBJECT *MinOp, + ACPI_PARSE_OBJECT *MaxOp, + ACPI_PARSE_OBJECT *LengthOp, + ACPI_PARSE_OBJECT *GranOp, + ACPI_PARSE_OBJECT *Op); + +UINT16 +RsGetStringDataLength ( + ACPI_PARSE_OBJECT *InitializerOp); + +ASL_RESOURCE_NODE * +RsAllocateResourceNode ( + UINT32 Size); + +void +RsCreateResourceField ( + ACPI_PARSE_OBJECT *Op, + char *Name, + UINT32 ByteOffset, + UINT32 BitOffset, + UINT32 BitLength); + +void +RsSetFlagBits ( + UINT8 *Flags, + ACPI_PARSE_OBJECT *Op, + UINT8 Position, + UINT8 DefaultBit); + +void +RsSetFlagBits16 ( + UINT16 *Flags, + ACPI_PARSE_OBJECT *Op, + UINT8 Position, + UINT8 DefaultBit); + +ACPI_PARSE_OBJECT * +RsCompleteNodeAndGetNext ( + ACPI_PARSE_OBJECT *Op); + +void +RsCheckListForDuplicates ( + ACPI_PARSE_OBJECT *Op); + +ASL_RESOURCE_NODE * +RsDoOneResourceDescriptor ( + ASL_RESOURCE_INFO *Info, + UINT8 *State); + +/* Values for State above */ + +#define ACPI_RSTATE_NORMAL 0 +#define ACPI_RSTATE_START_DEPENDENT 1 +#define ACPI_RSTATE_DEPENDENT_LIST 2 + +UINT32 +RsLinkDescriptorChain ( + ASL_RESOURCE_NODE **PreviousRnode, + ASL_RESOURCE_NODE *Rnode); + +void +RsDoResourceTemplate ( + ACPI_PARSE_OBJECT *Op); + + +/* + * aslrestype1 - Miscellaneous Small descriptors + */ +ASL_RESOURCE_NODE * +RsDoEndTagDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoEndDependentDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoMemory24Descriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoMemory32Descriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoMemory32FixedDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoStartDependentDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoStartDependentNoPriDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoVendorSmallDescriptor ( + ASL_RESOURCE_INFO *Info); + + +/* + * aslrestype1i - I/O-related Small descriptors + */ +ASL_RESOURCE_NODE * +RsDoDmaDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoFixedDmaDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoFixedIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoIrqDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoIrqNoFlagsDescriptor ( + ASL_RESOURCE_INFO *Info); + + +/* + * aslrestype2 - Large resource descriptors + */ +ASL_RESOURCE_NODE * +RsDoInterruptDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoVendorLargeDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoGeneralRegisterDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoGpioIntDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoGpioIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoI2cSerialBusDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoSpiSerialBusDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoUartSerialBusDescriptor ( + ASL_RESOURCE_INFO *Info); + +/* + * aslrestype2d - DWord address descriptors + */ +ASL_RESOURCE_NODE * +RsDoDwordIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoDwordMemoryDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoDwordSpaceDescriptor ( + ASL_RESOURCE_INFO *Info); + + +/* + * aslrestype2e - Extended address descriptors + */ +ASL_RESOURCE_NODE * +RsDoExtendedIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoExtendedMemoryDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoExtendedSpaceDescriptor ( + ASL_RESOURCE_INFO *Info); + + +/* + * aslrestype2q - QWord address descriptors + */ +ASL_RESOURCE_NODE * +RsDoQwordIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoQwordMemoryDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoQwordSpaceDescriptor ( + ASL_RESOURCE_INFO *Info); + + +/* + * aslrestype2w - Word address descriptors + */ +ASL_RESOURCE_NODE * +RsDoWordIoDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoWordSpaceDescriptor ( + ASL_RESOURCE_INFO *Info); + +ASL_RESOURCE_NODE * +RsDoWordBusNumberDescriptor ( + ASL_RESOURCE_INFO *Info); + + +/* + * Entry to data table compiler subsystem + */ +ACPI_STATUS +DtDoCompile( + void); + +ACPI_STATUS +DtCreateTemplates ( + char **argv); + +#endif /* __ASLCOMPILER_H */ diff --git a/third_party/lib/acpica/source/compiler/aslcompiler.l b/third_party/lib/acpica/source/compiler/aslcompiler.l new file mode 100644 index 000000000..a34387c39 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslcompiler.l @@ -0,0 +1,741 @@ +%{ +/****************************************************************************** + * + * Module Name: aslcompiler.l - Flex/lex input file + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#include +#include +YYSTYPE AslCompilerlval; + +/* + * Generation: Use the following command line: + * + * flex.exe -PAslCompiler -i -o$(InputPath).c $(InputPath) + * + * -i: Scanner must be case-insensitive + */ + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslscanner") + + +/* Local prototypes */ + +static void +AslDoLineDirective (void); + +static char +AslDoComment (void); + +static char +AslDoCommentType2 (void); + +static char +AslDoStringLiteral (void); + +static void +count (int type); + + +/*! [Begin] no source code translation */ + +%} + /* Definitions */ + +LeadNameChar [A-Za-z_] +DigitChar [0-9] +HexDigitChar [A-Fa-f0-9] +RootChar [\\] +Nothing [] + +NameChar [A-Za-z_0-9] +NameSeg1 {LeadNameChar}{NameChar} +NameSeg2 {LeadNameChar}{NameChar}{NameChar} +NameSeg3 {LeadNameChar}{NameChar}{NameChar}{NameChar} +NameSeg {LeadNameChar}|{NameSeg1}|{NameSeg2}|{NameSeg3} + +NameString {RootChar}|{RootChar}{NamePath}|[\^]+{NamePath}|{NonEmptyNamePath} +NamePath {NonEmptyNamePath}? +NonEmptyNamePath {NameSeg}{NamePathTail}* +NamePathTail [.]{NameSeg} + +%% + /* Rules */ + +[ ] { count (0); } +[\n] { count (0); } /* Handle files with both LF and CR/LF */ +[\r] { count (0); } /* termination on both Unix and Windows */ +[ \t] { count (0); } + + +"/*" { if (!AslDoComment ()) {yyterminate ();} } +"//" { if (!AslDoCommentType2 ()) {yyterminate ();} } + +"\"" { if (AslDoStringLiteral ()) {return (PARSEOP_STRING_LITERAL);} + else {yyterminate ();} } +";" { count (0); return(';'); } + + /* ASL Extension: Standard C operators */ + +"~" { count (3); return (PARSEOP_EXP_NOT); } +"!" { count (3); return (PARSEOP_EXP_LOGICAL_NOT); } +"*" { count (3); return (PARSEOP_EXP_MULTIPLY); } +"/" { count (3); return (PARSEOP_EXP_DIVIDE); } +"%" { count (3); return (PARSEOP_EXP_MODULO); } +"+" { count (3); return (PARSEOP_EXP_ADD); } +"-" { count (3); return (PARSEOP_EXP_SUBTRACT); } +">>" { count (3); return (PARSEOP_EXP_SHIFT_RIGHT); } +"<<" { count (3); return (PARSEOP_EXP_SHIFT_LEFT); } +"<" { count (3); return (PARSEOP_EXP_LESS); } +">" { count (3); return (PARSEOP_EXP_GREATER); } +"&" { count (3); return (PARSEOP_EXP_AND); } +"<=" { count (3); return (PARSEOP_EXP_LESS_EQUAL); } +">=" { count (3); return (PARSEOP_EXP_GREATER_EQUAL); } +"==" { count (3); return (PARSEOP_EXP_EQUAL); } +"!=" { count (3); return (PARSEOP_EXP_NOT_EQUAL); } +"|" { count (3); return (PARSEOP_EXP_OR); } +"&&" { count (3); return (PARSEOP_EXP_LOGICAL_AND); } +"||" { count (3); return (PARSEOP_EXP_LOGICAL_OR); } +"++" { count (3); return (PARSEOP_EXP_INCREMENT); } +"--" { count (3); return (PARSEOP_EXP_DECREMENT); } +"^ " { count (3); return (PARSEOP_EXP_XOR); } + + /* ASL Extension: Standard C assignment operators */ + +"=" { count (3); return (PARSEOP_EXP_EQUALS); } +"+=" { count (3); return (PARSEOP_EXP_ADD_EQ); } +"-=" { count (3); return (PARSEOP_EXP_SUB_EQ); } +"*=" { count (3); return (PARSEOP_EXP_MUL_EQ); } +"/=" { count (3); return (PARSEOP_EXP_DIV_EQ); } +"%=" { count (3); return (PARSEOP_EXP_MOD_EQ); } +"<<=" { count (3); return (PARSEOP_EXP_SHL_EQ); } +">>=" { count (3); return (PARSEOP_EXP_SHR_EQ); } +"&=" { count (3); return (PARSEOP_EXP_AND_EQ); } +"^=" { count (3); return (PARSEOP_EXP_XOR_EQ); } +"|=" { count (3); return (PARSEOP_EXP_OR_EQ); } + +"[" { count (3); return(PARSEOP_EXP_INDEX_LEFT); } +"]" { count (0); return(PARSEOP_EXP_INDEX_RIGHT); } + + + /* + * Begin standard ASL grammar + */ +0[xX]{HexDigitChar}+ | +{DigitChar}+ { AslCompilerlval.i = UtDoConstant ((char *) AslCompilertext); + count (1); return (PARSEOP_INTEGER); } + +"Include" { count (1); return (PARSEOP_INCLUDE); } +"External" { count (1); return (PARSEOP_EXTERNAL); } + + /* + * The #line directive is emitted by the preprocessor and handled + * here in the main iASL lexer - simply set the line number and + * optionally the current filename. + */ +"#line" { AslDoLineDirective ();} + + + /**************************************************************************** + * + * Main ASL operators + * + ****************************************************************************/ + +"AccessAs" { count (1); return (PARSEOP_ACCESSAS); } +"Acquire" { count (3); return (PARSEOP_ACQUIRE); } +"Add" { count (3); return (PARSEOP_ADD); } +"Alias" { count (2); return (PARSEOP_ALIAS); } +"And" { count (3); return (PARSEOP_AND); } +"BankField" { count (2); return (PARSEOP_BANKFIELD); } +"Break" { count (3); return (PARSEOP_BREAK); } +"BreakPoint" { count (3); return (PARSEOP_BREAKPOINT); } +"Buffer" { count (1); return (PARSEOP_BUFFER); } +"Case" { count (3); return (PARSEOP_CASE); } +"Concatenate" { count (3); return (PARSEOP_CONCATENATE); } +"ConcatenateResTemplate" { count (3); return (PARSEOP_CONCATENATERESTEMPLATE); } +"CondRefOf" { count (3); return (PARSEOP_CONDREFOF); } +"Connection" { count (2); return (PARSEOP_CONNECTION); } +"Continue" { count (3); return (PARSEOP_CONTINUE); } +"CopyObject" { count (3); return (PARSEOP_COPYOBJECT); } +"CreateBitField" { count (2); return (PARSEOP_CREATEBITFIELD); } +"CreateByteField" { count (2); return (PARSEOP_CREATEBYTEFIELD); } +"CreateDWordField" { count (2); return (PARSEOP_CREATEDWORDFIELD); } +"CreateField" { count (2); return (PARSEOP_CREATEFIELD); } +"CreateQWordField" { count (2); return (PARSEOP_CREATEQWORDFIELD); } +"CreateWordField" { count (2); return (PARSEOP_CREATEWORDFIELD); } +"DataTableRegion" { count (2); return (PARSEOP_DATATABLEREGION); } +"Debug" { count (1); return (PARSEOP_DEBUG); } +"Decrement" { count (3); return (PARSEOP_DECREMENT); } +"Default" { count (3); return (PARSEOP_DEFAULT); } +"DefinitionBlock" { count (1); return (PARSEOP_DEFINITION_BLOCK); } +"DeRefOf" { count (3); return (PARSEOP_DEREFOF); } +"Device" { count (2); return (PARSEOP_DEVICE); } +"Divide" { count (3); return (PARSEOP_DIVIDE); } +"Eisaid" { count (1); return (PARSEOP_EISAID); } +"Else" { count (3); return (PARSEOP_ELSE); } +"ElseIf" { count (3); return (PARSEOP_ELSEIF); } +"Event" { count (2); return (PARSEOP_EVENT); } +"Fatal" { count (3); return (PARSEOP_FATAL); } +"Field" { count (2); return (PARSEOP_FIELD); } +"FindSetLeftBit" { count (3); return (PARSEOP_FINDSETLEFTBIT); } +"FindSetRightBit" { count (3); return (PARSEOP_FINDSETRIGHTBIT); } +"FromBcd" { count (3); return (PARSEOP_FROMBCD); } +"Function" { count (2); return (PARSEOP_FUNCTION); } +"If" { count (3); return (PARSEOP_IF); } +"Increment" { count (3); return (PARSEOP_INCREMENT); } +"Index" { count (3); return (PARSEOP_INDEX); } +"IndexField" { count (2); return (PARSEOP_INDEXFIELD); } +"LAnd" { count (3); return (PARSEOP_LAND); } +"LEqual" { count (3); return (PARSEOP_LEQUAL); } +"LGreater" { count (3); return (PARSEOP_LGREATER); } +"LGreaterEqual" { count (3); return (PARSEOP_LGREATEREQUAL); } +"LLess" { count (3); return (PARSEOP_LLESS); } +"LLessEqual" { count (3); return (PARSEOP_LLESSEQUAL); } +"LNot" { count (3); return (PARSEOP_LNOT); } +"LNotEqual" { count (3); return (PARSEOP_LNOTEQUAL); } +"Load" { count (3); return (PARSEOP_LOAD); } +"LoadTable" { count (3); return (PARSEOP_LOADTABLE); } +"LOr" { count (3); return (PARSEOP_LOR); } +"Match" { count (3); return (PARSEOP_MATCH); } +"Method" { count (2); return (PARSEOP_METHOD); } +"Mid" { count (3); return (PARSEOP_MID); } +"Mod" { count (3); return (PARSEOP_MOD); } +"Multiply" { count (3); return (PARSEOP_MULTIPLY); } +"Mutex" { count (2); return (PARSEOP_MUTEX); } +"Name" { count (2); return (PARSEOP_NAME); } +"NAnd" { count (3); return (PARSEOP_NAND); } +"Noop" { if (!AcpiGbl_IgnoreNoopOperator) {count (3); return (PARSEOP_NOOP);} } +"NOr" { count (3); return (PARSEOP_NOR); } +"Not" { count (3); return (PARSEOP_NOT); } +"Notify" { count (3); return (PARSEOP_NOTIFY); } +"ObjectType" { count (3); return (PARSEOP_OBJECTTYPE); } +"Offset" { count (1); return (PARSEOP_OFFSET); } +"One" { count (1); return (PARSEOP_ONE); } +"Ones" { count (1); return (PARSEOP_ONES); } +"OperationRegion" { count (2); return (PARSEOP_OPERATIONREGION); } +"Or" { count (3); return (PARSEOP_OR); } +"Package" { count (1); return (PARSEOP_PACKAGE); } +"PowerResource" { count (2); return (PARSEOP_POWERRESOURCE); } +"Processor" { count (2); return (PARSEOP_PROCESSOR); } +"RefOf" { count (3); return (PARSEOP_REFOF); } +"Release" { count (3); return (PARSEOP_RELEASE); } +"Reset" { count (3); return (PARSEOP_RESET); } +"Return" { count (3); return (PARSEOP_RETURN); } +"Revision" { count (1); return (PARSEOP_REVISION); } +"Scope" { count (2); return (PARSEOP_SCOPE); } +"ShiftLeft" { count (3); return (PARSEOP_SHIFTLEFT); } +"ShiftRight" { count (3); return (PARSEOP_SHIFTRIGHT); } +"Signal" { count (3); return (PARSEOP_SIGNAL); } +"SizeOf" { count (3); return (PARSEOP_SIZEOF); } +"Sleep" { count (3); return (PARSEOP_SLEEP); } +"Stall" { count (3); return (PARSEOP_STALL); } +"Store" { count (3); return (PARSEOP_STORE); } +"Subtract" { count (3); return (PARSEOP_SUBTRACT); } +"Switch" { count (3); return (PARSEOP_SWITCH); } +"ThermalZone" { count (2); return (PARSEOP_THERMALZONE); } +"Timer" { count (3); return (PARSEOP_TIMER); } +"ToBcd" { count (3); return (PARSEOP_TOBCD); } +"ToBuffer" { count (3); return (PARSEOP_TOBUFFER); } +"ToDecimalString" { count (3); return (PARSEOP_TODECIMALSTRING); } +"ToHexString" { count (3); return (PARSEOP_TOHEXSTRING); } +"ToInteger" { count (3); return (PARSEOP_TOINTEGER); } +"ToString" { count (3); return (PARSEOP_TOSTRING); } +"ToUuid" { count (1); return (PARSEOP_TOUUID); } +"Unicode" { count (1); return (PARSEOP_UNICODE); } +"Unload" { count (3); return (PARSEOP_UNLOAD); } +"Wait" { count (3); return (PARSEOP_WAIT); } +"While" { count (3); return (PARSEOP_WHILE); } +"XOr" { count (3); return (PARSEOP_XOR); } +"Zero" { count (1); return (PARSEOP_ZERO); } + + /* Control method arguments and locals */ + +"Arg0" { count (1); return (PARSEOP_ARG0); } +"Arg1" { count (1); return (PARSEOP_ARG1); } +"Arg2" { count (1); return (PARSEOP_ARG2); } +"Arg3" { count (1); return (PARSEOP_ARG3); } +"Arg4" { count (1); return (PARSEOP_ARG4); } +"Arg5" { count (1); return (PARSEOP_ARG5); } +"Arg6" { count (1); return (PARSEOP_ARG6); } +"Local0" { count (1); return (PARSEOP_LOCAL0); } +"Local1" { count (1); return (PARSEOP_LOCAL1); } +"Local2" { count (1); return (PARSEOP_LOCAL2); } +"Local3" { count (1); return (PARSEOP_LOCAL3); } +"Local4" { count (1); return (PARSEOP_LOCAL4); } +"Local5" { count (1); return (PARSEOP_LOCAL5); } +"Local6" { count (1); return (PARSEOP_LOCAL6); } +"Local7" { count (1); return (PARSEOP_LOCAL7); } + + + /**************************************************************************** + * + * Resource Descriptor macros + * + ****************************************************************************/ + +"ResourceTemplate" { count (1); return (PARSEOP_RESOURCETEMPLATE); } +"RawDataBuffer" { count (1); return (PARSEOP_DATABUFFER); } + +"DMA" { count (1); return (PARSEOP_DMA); } +"DWordIO" { count (1); return (PARSEOP_DWORDIO); } +"DWordMemory" { count (1); return (PARSEOP_DWORDMEMORY); } +"DWordSpace" { count (1); return (PARSEOP_DWORDSPACE); } +"EndDependentFn" { count (1); return (PARSEOP_ENDDEPENDENTFN); } +"ExtendedIO" { count (1); return (PARSEOP_EXTENDEDIO); } +"ExtendedMemory" { count (1); return (PARSEOP_EXTENDEDMEMORY); } +"ExtendedSpace" { count (1); return (PARSEOP_EXTENDEDSPACE); } +"FixedDma" { count (1); return (PARSEOP_FIXEDDMA); } +"FixedIO" { count (1); return (PARSEOP_FIXEDIO); } +"GpioInt" { count (1); return (PARSEOP_GPIO_INT); } +"GpioIo" { count (1); return (PARSEOP_GPIO_IO); } +"I2cSerialBus" { count (1); return (PARSEOP_I2C_SERIALBUS); } +"Interrupt" { count (1); return (PARSEOP_INTERRUPT); } +"IO" { count (1); return (PARSEOP_IO); } +"IRQ" { count (1); return (PARSEOP_IRQ); } +"IRQNoFlags" { count (1); return (PARSEOP_IRQNOFLAGS); } +"Memory24" { count (1); return (PARSEOP_MEMORY24); } +"Memory32" { count (1); return (PARSEOP_MEMORY32); } +"Memory32Fixed" { count (1); return (PARSEOP_MEMORY32FIXED); } +"QWordIO" { count (1); return (PARSEOP_QWORDIO); } +"QWordMemory" { count (1); return (PARSEOP_QWORDMEMORY); } +"QWordSpace" { count (1); return (PARSEOP_QWORDSPACE); } +"Register" { count (1); return (PARSEOP_REGISTER); } +"SpiSerialBus" { count (1); return (PARSEOP_SPI_SERIALBUS); } +"StartDependentFn" { count (1); return (PARSEOP_STARTDEPENDENTFN); } +"StartDependentFnNoPri" { count (1); return (PARSEOP_STARTDEPENDENTFN_NOPRI); } +"UartSerialBus" { count (1); return (PARSEOP_UART_SERIALBUS); } +"VendorLong" { count (1); return (PARSEOP_VENDORLONG); } +"VendorShort" { count (1); return (PARSEOP_VENDORSHORT); } +"WordBusNumber" { count (1); return (PARSEOP_WORDBUSNUMBER); } +"WordIO" { count (1); return (PARSEOP_WORDIO); } +"WordSpace" { count (1); return (PARSEOP_WORDSPACE); } + + + /**************************************************************************** + * + * Keywords used as arguments to ASL operators and macros + * + ****************************************************************************/ + + /* AccessAttribKeyword: Serial Bus Attributes (ACPI 5.0) */ + +"AttribQuick" { count (0); return (PARSEOP_ACCESSATTRIB_QUICK); } +"AttribSendReceive" { count (0); return (PARSEOP_ACCESSATTRIB_SND_RCV); } +"AttribByte" { count (0); return (PARSEOP_ACCESSATTRIB_BYTE); } +"AttribWord" { count (0); return (PARSEOP_ACCESSATTRIB_WORD); } +"AttribBlock" { count (0); return (PARSEOP_ACCESSATTRIB_BLOCK); } +"AttribProcessCall" { count (0); return (PARSEOP_ACCESSATTRIB_WORD_CALL); } +"AttribBlockProcessCall" { count (0); return (PARSEOP_ACCESSATTRIB_BLOCK_CALL); } + + /* AccessAttribKeyword: Legacy synonyms for above (pre-ACPI 5.0) */ + +"SMBQuick" { count (0); return (PARSEOP_ACCESSATTRIB_QUICK); } +"SMBSendReceive" { count (0); return (PARSEOP_ACCESSATTRIB_SND_RCV); } +"SMBByte" { count (0); return (PARSEOP_ACCESSATTRIB_BYTE); } +"SMBWord" { count (0); return (PARSEOP_ACCESSATTRIB_WORD); } +"SMBBlock" { count (0); return (PARSEOP_ACCESSATTRIB_BLOCK); } +"SMBProcessCall" { count (0); return (PARSEOP_ACCESSATTRIB_WORD_CALL); } +"SMBBlockProcessCall" { count (0); return (PARSEOP_ACCESSATTRIB_BLOCK_CALL); } + + /* AccessTypeKeyword: Field Access Types */ + +"AnyAcc" { count (0); return (PARSEOP_ACCESSTYPE_ANY); } +"ByteAcc" { count (0); return (PARSEOP_ACCESSTYPE_BYTE); } +"WordAcc" { count (0); return (PARSEOP_ACCESSTYPE_WORD); } +"DWordAcc" { count (0); return (PARSEOP_ACCESSTYPE_DWORD); } +"QWordAcc" { count (0); return (PARSEOP_ACCESSTYPE_QWORD); } +"BufferAcc" { count (0); return (PARSEOP_ACCESSTYPE_BUF); } + + /* AddressingModeKeyword: Mode - Resource Descriptors (ACPI 5.0) */ + +"AddressingMode7Bit" { count (0); return (PARSEOP_ADDRESSINGMODE_7BIT); } +"AddressingMode10Bit" { count (0); return (PARSEOP_ADDRESSINGMODE_10BIT); } + + /* AddressKeyword: ACPI memory range types */ + +"AddressRangeMemory" { count (0); return (PARSEOP_ADDRESSTYPE_MEMORY); } +"AddressRangeReserved" { count (0); return (PARSEOP_ADDRESSTYPE_RESERVED); } +"AddressRangeNVS" { count (0); return (PARSEOP_ADDRESSTYPE_NVS); } +"AddressRangeACPI" { count (0); return (PARSEOP_ADDRESSTYPE_ACPI); } + + /* BusMasterKeyword: DMA Bus Mastering */ + +"BusMaster" { count (0); return (PARSEOP_BUSMASTERTYPE_MASTER); } +"NotBusMaster" { count (0); return (PARSEOP_BUSMASTERTYPE_NOTMASTER); } + + /* ByteLengthKeyword: Bits per Byte - Resource Descriptors (ACPI 5.0) */ + +"DataBitsFive" { count (0); return (PARSEOP_BITSPERBYTE_FIVE); } +"DataBitsSix" { count (0); return (PARSEOP_BITSPERBYTE_SIX); } +"DataBitsSeven" { count (0); return (PARSEOP_BITSPERBYTE_SEVEN); } +"DataBitsEight" { count (0); return (PARSEOP_BITSPERBYTE_EIGHT); } +"DataBitsNine" { count (0); return (PARSEOP_BITSPERBYTE_NINE); } + + /* ClockPhaseKeyword: Resource Descriptors (ACPI 5.0) */ + +"ClockPhaseFirst" { count (0); return (PARSEOP_CLOCKPHASE_FIRST); } +"ClockPhaseSecond" { count (0); return (PARSEOP_CLOCKPHASE_SECOND); } + + /* ClockPolarityKeyword: Resource Descriptors (ACPI 5.0) */ + +"ClockPolarityLow" { count (0); return (PARSEOP_CLOCKPOLARITY_LOW); } +"ClockPolarityHigh" { count (0); return (PARSEOP_CLOCKPOLARITY_HIGH); } + + /* DecodeKeyword: Type of Memory Decoding - Resource Descriptors */ + +"PosDecode" { count (0); return (PARSEOP_DECODETYPE_POS); } +"SubDecode" { count (0); return (PARSEOP_DECODETYPE_SUB); } + + /* DmaTypeKeyword: DMA Types - DMA Resource Descriptor */ + +"Compatibility" { count (0); return (PARSEOP_DMATYPE_COMPATIBILITY); } +"TypeA" { count (0); return (PARSEOP_DMATYPE_A); } +"TypeB" { count (0); return (PARSEOP_DMATYPE_B); } +"TypeF" { count (0); return (PARSEOP_DMATYPE_F); } + + /* EndianKeyword: Endian type - Resource Descriptor (ACPI 5.0) */ + +"LittleEndian" { count (0); return (PARSEOP_ENDIAN_LITTLE); } +"BigEndian" { count (0); return (PARSEOP_ENDIAN_BIG); } + + /* ExtendedAttribKeyword: Bus attributes, AccessAs operator (ACPI 5.0) */ + +"AttribBytes" { count (0); return (PARSEOP_ACCESSATTRIB_MULTIBYTE); } +"AttribRawBytes" { count (0); return (PARSEOP_ACCESSATTRIB_RAW_BYTES); } +"AttribRawProcessBytes" { count (0); return (PARSEOP_ACCESSATTRIB_RAW_PROCESS); } + + /* FlowControlKeyword: Resource Descriptors (ACPI 5.0) */ + +"FlowControlHardware" { count (0); return (PARSEOP_FLOWCONTROL_HW); } +"FlowControlNone" { count (0); return (PARSEOP_FLOWCONTROL_NONE); } +"FlowControlXon" { count (0); return (PARSEOP_FLOWCONTROL_SW); } + + /* InterruptLevelKeyword: Interrupt Active Types */ + +"ActiveBoth" { count (0); return (PARSEOP_INTLEVEL_ACTIVEBOTH); } +"ActiveHigh" { count (0); return (PARSEOP_INTLEVEL_ACTIVEHIGH); } +"ActiveLow" { count (0); return (PARSEOP_INTLEVEL_ACTIVELOW); } + + /* InterruptTypeKeyword: Interrupt Types */ + +"Edge" { count (0); return (PARSEOP_INTTYPE_EDGE); } +"Level" { count (0); return (PARSEOP_INTTYPE_LEVEL); } + + /* IoDecodeKeyword: Type of Memory Decoding - Resource Descriptors */ + +"Decode10" { count (0); return (PARSEOP_IODECODETYPE_10); } +"Decode16" { count (0); return (PARSEOP_IODECODETYPE_16); } + + /* IoRestrictionKeyword: I/O Restriction - GPIO Resource Descriptors (ACPI 5.0) */ + +"IoRestrictionNone" { count (0); return (PARSEOP_IORESTRICT_NONE); } +"IoRestrictionInputOnly" { count (0); return (PARSEOP_IORESTRICT_IN); } +"IoRestrictionOutputOnly" { count (0); return (PARSEOP_IORESTRICT_OUT); } +"IoRestrictionNoneAndPreserve" { count (0); return (PARSEOP_IORESTRICT_PRESERVE); } + + /* LockRuleKeyword: Global Lock use for Field Operator */ + +"Lock" { count (0); return (PARSEOP_LOCKRULE_LOCK); } +"NoLock" { count (0); return (PARSEOP_LOCKRULE_NOLOCK); } + + /* MatchOpKeyword: Types for Match Operator */ + +"MTR" { count (0); return (PARSEOP_MATCHTYPE_MTR); } +"MEQ" { count (0); return (PARSEOP_MATCHTYPE_MEQ); } +"MLE" { count (0); return (PARSEOP_MATCHTYPE_MLE); } +"MLT" { count (0); return (PARSEOP_MATCHTYPE_MLT); } +"MGE" { count (0); return (PARSEOP_MATCHTYPE_MGE); } +"MGT" { count (0); return (PARSEOP_MATCHTYPE_MGT); } + + /* MaxKeyword: Max Range Type - Resource Descriptors */ + +"MaxFixed" { count (0); return (PARSEOP_MAXTYPE_FIXED); } +"MaxNotFixed" { count (0); return (PARSEOP_MAXTYPE_NOTFIXED); } + + /* MemTypeKeyword: Memory Types - Resource Descriptors */ + +"Cacheable" { count (0); return (PARSEOP_MEMTYPE_CACHEABLE); } +"WriteCombining" { count (0); return (PARSEOP_MEMTYPE_WRITECOMBINING); } +"Prefetchable" { count (0); return (PARSEOP_MEMTYPE_PREFETCHABLE); } +"NonCacheable" { count (0); return (PARSEOP_MEMTYPE_NONCACHEABLE); } + + /* MinKeyword: Min Range Type - Resource Descriptors */ + +"MinFixed" { count (0); return (PARSEOP_MINTYPE_FIXED); } +"MinNotFixed" { count (0); return (PARSEOP_MINTYPE_NOTFIXED); } + + /* ObjectTypeKeyword: ACPI Object Types */ + +"UnknownObj" { count (0); return (PARSEOP_OBJECTTYPE_UNK); } +"IntObj" { count (0); return (PARSEOP_OBJECTTYPE_INT); } +"StrObj" { count (0); return (PARSEOP_OBJECTTYPE_STR); } +"BuffObj" { count (0); return (PARSEOP_OBJECTTYPE_BUF); } +"PkgObj" { count (0); return (PARSEOP_OBJECTTYPE_PKG); } +"FieldUnitObj" { count (0); return (PARSEOP_OBJECTTYPE_FLD); } +"DeviceObj" { count (0); return (PARSEOP_OBJECTTYPE_DEV); } +"EventObj" { count (0); return (PARSEOP_OBJECTTYPE_EVT); } +"MethodObj" { count (0); return (PARSEOP_OBJECTTYPE_MTH); } +"MutexObj" { count (0); return (PARSEOP_OBJECTTYPE_MTX); } +"OpRegionObj" { count (0); return (PARSEOP_OBJECTTYPE_OPR); } +"PowerResObj" { count (0); return (PARSEOP_OBJECTTYPE_POW); } +"ProcessorObj" { count (0); return (PARSEOP_OBJECTTYPE_PRO); } +"ThermalZoneObj" { count (0); return (PARSEOP_OBJECTTYPE_THZ); } +"BuffFieldObj" { count (0); return (PARSEOP_OBJECTTYPE_BFF); } +"DDBHandleObj" { count (0); return (PARSEOP_OBJECTTYPE_DDB); } + + /* ParityKeyword: Resource Descriptors (ACPI 5.0) */ + +"ParityTypeSpace" { count (0); return (PARSEOP_PARITYTYPE_SPACE); } +"ParityTypeMark" { count (0); return (PARSEOP_PARITYTYPE_MARK); } +"ParityTypeOdd" { count (0); return (PARSEOP_PARITYTYPE_ODD); } +"ParityTypeEven" { count (0); return (PARSEOP_PARITYTYPE_EVEN); } +"ParityTypeNone" { count (0); return (PARSEOP_PARITYTYPE_NONE); } + + /* PinConfigKeyword: Pin Configuration - GPIO Resource Descriptors (ACPI 5.0) */ + +"PullDefault" { count (0); return (PARSEOP_PIN_PULLDEFAULT); } +"PullUp" { count (0); return (PARSEOP_PIN_PULLUP); } +"PullDown" { count (0); return (PARSEOP_PIN_PULLDOWN); } +"PullNone" { count (0); return (PARSEOP_PIN_NOPULL); } + + /* PolarityKeyword: Resource Descriptors (ACPI 5.0) */ + +"PolarityLow" { count (0); return (PARSEOP_DEVICEPOLARITY_LOW); } +"PolarityHigh" { count (0); return (PARSEOP_DEVICEPOLARITY_HIGH); } + + /* RangeTypeKeyword: I/O Range Types - Resource Descriptors */ + +"ISAOnlyRanges" { count (0); return (PARSEOP_RANGETYPE_ISAONLY); } +"NonISAOnlyRanges" { count (0); return (PARSEOP_RANGETYPE_NONISAONLY); } +"EntireRange" { count (0); return (PARSEOP_RANGETYPE_ENTIRE); } + + /* ReadWriteKeyword: Memory Access Types - Resource Descriptors */ + +"ReadWrite" { count (0); return (PARSEOP_READWRITETYPE_BOTH); } +"ReadOnly" { count (0); return (PARSEOP_READWRITETYPE_READONLY); } + + /* RegionSpaceKeyword: Operation Region Address Space Types */ + +"SystemIO" { count (0); return (PARSEOP_REGIONSPACE_IO); } +"SystemMemory" { count (0); return (PARSEOP_REGIONSPACE_MEM); } +"PCI_Config" { count (0); return (PARSEOP_REGIONSPACE_PCI); } +"EmbeddedControl" { count (0); return (PARSEOP_REGIONSPACE_EC); } +"SMBus" { count (0); return (PARSEOP_REGIONSPACE_SMBUS); } +"SystemCMOS" { count (0); return (PARSEOP_REGIONSPACE_CMOS); } +"PciBarTarget" { count (0); return (PARSEOP_REGIONSPACE_PCIBAR); } +"IPMI" { count (0); return (PARSEOP_REGIONSPACE_IPMI); } +"GeneralPurposeIo" { count (0); return (PARSEOP_REGIONSPACE_GPIO); } /* ACPI 5.0 */ +"GenericSerialBus" { count (0); return (PARSEOP_REGIONSPACE_GSBUS); } /* ACPI 5.0 */ +"PCC" { count (0); return (PARSEOP_REGIONSPACE_PCC); } /* ACPI 5.0 */ +"FFixedHW" { count (0); return (PARSEOP_REGIONSPACE_FFIXEDHW); } + + /* ResourceTypeKeyword: Resource Usage - Resource Descriptors */ + +"ResourceConsumer" { count (0); return (PARSEOP_RESOURCETYPE_CONSUMER); } +"ResourceProducer" { count (0); return (PARSEOP_RESOURCETYPE_PRODUCER); } + + /* SerializeRuleKeyword: Control Method Serialization */ + +"Serialized" { count (0); return (PARSEOP_SERIALIZERULE_SERIAL); } +"NotSerialized" { count (0); return (PARSEOP_SERIALIZERULE_NOTSERIAL); } + + /* ShareTypeKeyword: Interrupt Sharing - Resource Descriptors */ + +"Shared" { count (0); return (PARSEOP_SHARETYPE_SHARED); } +"Exclusive" { count (0); return (PARSEOP_SHARETYPE_EXCLUSIVE); } +"SharedAndWake" { count (0); return (PARSEOP_SHARETYPE_SHAREDWAKE); } /* ACPI 5.0 */ +"ExclusiveAndWake" { count (0); return (PARSEOP_SHARETYPE_EXCLUSIVEWAKE); } /* ACPI 5.0 */ + + /* SlaveModeKeyword: Resource Descriptors (ACPI 5.0) */ + +"ControllerInitiated" { count (0); return (PARSEOP_SLAVEMODE_CONTROLLERINIT); } +"DeviceInitiated" { count (0); return (PARSEOP_SLAVEMODE_DEVICEINIT); } + + /* StopBitsKeyword: Resource Descriptors (ACPI 5.0) */ + +"StopBitsOne" { count (0); return (PARSEOP_STOPBITS_ONE); } +"StopBitsOnePlusHalf" { count (0); return (PARSEOP_STOPBITS_ONEPLUSHALF); } +"StopBitsTwo" { count (0); return (PARSEOP_STOPBITS_TWO); } +"StopBitsZero" { count (0); return (PARSEOP_STOPBITS_ZERO); } + + /* TransferWidthKeyword: DMA Widths - Fixed DMA Resource Descriptor (ACPI 5.0) */ + +"Width8bit" { count (0); return (PARSEOP_XFERSIZE_8); } +"Width16bit" { count (0); return (PARSEOP_XFERSIZE_16); } +"Width32bit" { count (0); return (PARSEOP_XFERSIZE_32); } +"Width64bit" { count (0); return (PARSEOP_XFERSIZE_64); } +"Width128bit" { count (0); return (PARSEOP_XFERSIZE_128); } +"Width256bit" { count (0); return (PARSEOP_XFERSIZE_256); } + + /* TranslationKeyword: Translation Density Types - Resource Descriptors */ + +"SparseTranslation" { count (0); return (PARSEOP_TRANSLATIONTYPE_SPARSE); } +"DenseTranslation" { count (0); return (PARSEOP_TRANSLATIONTYPE_DENSE); } + + /* TypeKeyword: Translation Types - Resource Descriptors */ + +"TypeTranslation" { count (0); return (PARSEOP_TYPE_TRANSLATION); } +"TypeStatic" { count (0); return (PARSEOP_TYPE_STATIC); } + + /* UpdateRuleKeyword: Field Update Rules */ + +"Preserve" { count (0); return (PARSEOP_UPDATERULE_PRESERVE); } +"WriteAsOnes" { count (0); return (PARSEOP_UPDATERULE_ONES); } +"WriteAsZeros" { count (0); return (PARSEOP_UPDATERULE_ZEROS); } + + /* WireModeKeyword: SPI Wire Mode - Resource Descriptors (ACPI 5.0) */ + +"FourWireMode" { count (0); return (PARSEOP_WIREMODE_FOUR); } +"ThreeWireMode" { count (0); return (PARSEOP_WIREMODE_THREE); } + + /* XferTypeKeyword: DMA Transfer Types */ + +"Transfer8" { count (0); return (PARSEOP_XFERTYPE_8); } +"Transfer8_16" { count (0); return (PARSEOP_XFERTYPE_8_16); } +"Transfer16" { count (0); return (PARSEOP_XFERTYPE_16); } + + /* ToPld macro */ + +"ToPLD" { count (0); return (PARSEOP_TOPLD); } + +"PLD_Revision" { count (0); return (PARSEOP_PLD_REVISION); } +"PLD_IgnoreColor" { count (0); return (PARSEOP_PLD_IGNORECOLOR); } +"PLD_Red" { count (0); return (PARSEOP_PLD_RED); } +"PLD_Green" { count (0); return (PARSEOP_PLD_GREEN); } +"PLD_Blue" { count (0); return (PARSEOP_PLD_BLUE); } +"PLD_Width" { count (0); return (PARSEOP_PLD_WIDTH); } +"PLD_Height" { count (0); return (PARSEOP_PLD_HEIGHT); } +"PLD_UserVisible" { count (0); return (PARSEOP_PLD_USERVISIBLE); } +"PLD_Dock" { count (0); return (PARSEOP_PLD_DOCK); } +"PLD_Lid" { count (0); return (PARSEOP_PLD_LID); } +"PLD_Panel" { count (0); return (PARSEOP_PLD_PANEL); } +"PLD_VerticalPosition" { count (0); return (PARSEOP_PLD_VERTICALPOSITION); } +"PLD_HorizontalPosition" { count (0); return (PARSEOP_PLD_HORIZONTALPOSITION); } +"PLD_Shape" { count (0); return (PARSEOP_PLD_SHAPE); } +"PLD_GroupOrientation" { count (0); return (PARSEOP_PLD_GROUPORIENTATION); } +"PLD_GroupToken" { count (0); return (PARSEOP_PLD_GROUPTOKEN); } +"PLD_GroupPosition" { count (0); return (PARSEOP_PLD_GROUPPOSITION); } +"PLD_Bay" { count (0); return (PARSEOP_PLD_BAY); } +"PLD_Ejectable" { count (0); return (PARSEOP_PLD_EJECTABLE); } +"PLD_EjectRequired" { count (0); return (PARSEOP_PLD_EJECTREQUIRED); } +"PLD_CabinetNumber" { count (0); return (PARSEOP_PLD_CABINETNUMBER); } +"PLD_CardCageNumber" { count (0); return (PARSEOP_PLD_CARDCAGENUMBER); } +"PLD_Reference" { count (0); return (PARSEOP_PLD_REFERENCE); } +"PLD_Rotation" { count (0); return (PARSEOP_PLD_ROTATION); } +"PLD_Order" { count (0); return (PARSEOP_PLD_ORDER); } +"PLD_Reserved" { count (0); return (PARSEOP_PLD_RESERVED); } +"PLD_VerticalOffset" { count (0); return (PARSEOP_PLD_VERTICALOFFSET); } +"PLD_HorizontalOffset" { count (0); return (PARSEOP_PLD_HORIZONTALOFFSET); } + + + /* printf debug macros */ +"printf" { count (0); return (PARSEOP_PRINTF); } +"fprintf" { count (0); return (PARSEOP_FPRINTF); } + + /* Predefined compiler names */ + +"__DATE__" { count (0); return (PARSEOP___DATE__); } +"__FILE__" { count (0); return (PARSEOP___FILE__); } +"__LINE__" { count (0); return (PARSEOP___LINE__); } +"__PATH__" { count (0); return (PARSEOP___PATH__); } + + +"{" { count (0); return('{'); } +"}" { count (0); return('}'); } +"," { count (0); return(','); } +"(" { count (0); return('('); } +")" { count (0); return(')'); } + +{NameSeg} { char *s; + count (0); + s=UtStringCacheCalloc (ACPI_NAME_SIZE + 1); + if (strcmp (AslCompilertext, "\\")) + { + strcpy (s, "____"); + AcpiUtStrupr (AslCompilertext); + } + memcpy (s, AslCompilertext, strlen (AslCompilertext)); + AslCompilerlval.s = s; + DbgPrint (ASL_PARSE_OUTPUT, "NameSeg: %s\n", s); + return (PARSEOP_NAMESEG); } + +{NameString} { char *s; + count (0); + s=UtStringCacheCalloc (strlen (AslCompilertext)+1); + AcpiUtStrupr (AslCompilertext); + strcpy (s, AslCompilertext); + AslCompilerlval.s = s; + DbgPrint (ASL_PARSE_OUTPUT, "NameString: %s\n", s); + return (PARSEOP_NAMESTRING); } + +. { count (1); + if (isprint ((int) *AslCompilertext)) + { + sprintf (MsgBuffer, + "Invalid character (%c), expecting ASL keyword or name", + *AslCompilertext); + } + else + { + sprintf (MsgBuffer, + "Invalid character (0x%2.2X), expecting ASL keyword or name", + *AslCompilertext); + } + AslCompilererror (MsgBuffer);} + +<> { if (AslPopInputFileStack ()) + {yyterminate();} + else + {return (PARSEOP_INCLUDE_END);} }; + +%% + +/*! [End] no source code translation !*/ + +/* + * Bring in the scanner support routines + */ +#include "aslsupport.l" diff --git a/third_party/lib/acpica/source/compiler/aslcstyle.y b/third_party/lib/acpica/source/compiler/aslcstyle.y new file mode 100644 index 000000000..62a7b65f7 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslcstyle.y @@ -0,0 +1,209 @@ +NoEcho(' +/****************************************************************************** + * + * Module Name: aslcstyle.y - Production rules for symbolic operators + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +') + +/******************************************************************************* + * + * Production rules for the symbolic (c-style) operators + * + ******************************************************************************/ + +/* + * ASL Extensions: C-style math/logical operators and expressions. + * The implementation transforms these operators into the standard + * AML opcodes and syntax. + * + * Supported operators and precedence rules (high-to-low) + * + * NOTE: The operator precedence and associativity rules are + * implemented by the tokens in asltokens.y + * + * (left-to-right): + * 1) ( ) expr++ expr-- + * + * (right-to-left): + * 2) ! ~ + * + * (left-to-right): + * 3) * / % + * 4) + - + * 5) >> << + * 6) < > <= >= + * 7) == != + * 8) & + * 9) ^ + * 10) | + * 11) && + * 12) || + * + * (right-to-left): + * 13) = += -= *= /= %= <<= >>= &= ^= |= + */ + +Expression + + /* Unary operators */ + + : PARSEOP_EXP_LOGICAL_NOT {$$ = TrCreateLeafNode (PARSEOP_LNOT);} + TermArg {$$ = TrLinkChildren ($2,1,$3);} + | PARSEOP_EXP_NOT {$$ = TrCreateLeafNode (PARSEOP_NOT);} + TermArg {$$ = TrLinkChildren ($2,2,$3,TrCreateNullTarget ());} + + | SuperName PARSEOP_EXP_INCREMENT {$$ = TrCreateLeafNode (PARSEOP_INCREMENT);} + {$$ = TrLinkChildren ($3,1,$1);} + | SuperName PARSEOP_EXP_DECREMENT {$$ = TrCreateLeafNode (PARSEOP_DECREMENT);} + {$$ = TrLinkChildren ($3,1,$1);} + + /* Binary operators: math and logical */ + + | TermArg PARSEOP_EXP_ADD {$$ = TrCreateLeafNode (PARSEOP_ADD);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_DIVIDE {$$ = TrCreateLeafNode (PARSEOP_DIVIDE);} + TermArg {$$ = TrLinkChildren ($3,4,$1,$4,TrCreateNullTarget (), + TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_MODULO {$$ = TrCreateLeafNode (PARSEOP_MOD);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_MULTIPLY {$$ = TrCreateLeafNode (PARSEOP_MULTIPLY);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_SHIFT_LEFT {$$ = TrCreateLeafNode (PARSEOP_SHIFTLEFT);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_SHIFT_RIGHT {$$ = TrCreateLeafNode (PARSEOP_SHIFTRIGHT);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_SUBTRACT {$$ = TrCreateLeafNode (PARSEOP_SUBTRACT);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + + | TermArg PARSEOP_EXP_AND {$$ = TrCreateLeafNode (PARSEOP_AND);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_OR {$$ = TrCreateLeafNode (PARSEOP_OR);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + | TermArg PARSEOP_EXP_XOR {$$ = TrCreateLeafNode (PARSEOP_XOR);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4,TrCreateNullTarget ());} + + | TermArg PARSEOP_EXP_GREATER {$$ = TrCreateLeafNode (PARSEOP_LGREATER);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + | TermArg PARSEOP_EXP_GREATER_EQUAL {$$ = TrCreateLeafNode (PARSEOP_LGREATEREQUAL);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + | TermArg PARSEOP_EXP_LESS {$$ = TrCreateLeafNode (PARSEOP_LLESS);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + | TermArg PARSEOP_EXP_LESS_EQUAL {$$ = TrCreateLeafNode (PARSEOP_LLESSEQUAL);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + + | TermArg PARSEOP_EXP_EQUAL {$$ = TrCreateLeafNode (PARSEOP_LEQUAL);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + | TermArg PARSEOP_EXP_NOT_EQUAL {$$ = TrCreateLeafNode (PARSEOP_LNOTEQUAL);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + + | TermArg PARSEOP_EXP_LOGICAL_AND {$$ = TrCreateLeafNode (PARSEOP_LAND);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + | TermArg PARSEOP_EXP_LOGICAL_OR {$$ = TrCreateLeafNode (PARSEOP_LOR);} + TermArg {$$ = TrLinkChildren ($3,2,$1,$4);} + + /* Parentheses */ + + | '(' TermArg ')' { $$ = $2;} + + /* Index term -- "= BUF1[5]" on right-hand side of an equals (source) */ + + | SuperName PARSEOP_EXP_INDEX_LEFT TermArg PARSEOP_EXP_INDEX_RIGHT + {$$ = TrCreateLeafNode (PARSEOP_INDEX); + TrLinkChildren ($$,3,$1,$3,TrCreateNullTarget ());} + ; + + /* Index term -- "BUF1[5] = " on left-hand side of an equals (target) */ + +IndexExpTerm + + : SuperName PARSEOP_EXP_INDEX_LEFT TermArg PARSEOP_EXP_INDEX_RIGHT + {$$ = TrCreateLeafNode (PARSEOP_INDEX); + TrLinkChildren ($$,3,$1,$3,TrCreateNullTarget ());} + ; + +EqualsTerm + + /* All assignment-type operations */ + + : SuperName PARSEOP_EXP_EQUALS + TermArg {$$ = TrCreateAssignmentNode ($1, $3);} + + | TermArg PARSEOP_EXP_ADD_EQ {$$ = TrCreateLeafNode (PARSEOP_ADD);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_DIV_EQ {$$ = TrCreateLeafNode (PARSEOP_DIVIDE);} + TermArg {$$ = TrLinkChildren ($3,4,$1,$4,TrCreateNullTarget (), + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_MOD_EQ {$$ = TrCreateLeafNode (PARSEOP_MOD);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_MUL_EQ {$$ = TrCreateLeafNode (PARSEOP_MULTIPLY);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_SHL_EQ {$$ = TrCreateLeafNode (PARSEOP_SHIFTLEFT);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_SHR_EQ {$$ = TrCreateLeafNode (PARSEOP_SHIFTRIGHT);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_SUB_EQ {$$ = TrCreateLeafNode (PARSEOP_SUBTRACT);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_AND_EQ {$$ = TrCreateLeafNode (PARSEOP_AND);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_OR_EQ {$$ = TrCreateLeafNode (PARSEOP_OR);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + + | TermArg PARSEOP_EXP_XOR_EQ {$$ = TrCreateLeafNode (PARSEOP_XOR);} + TermArg {$$ = TrLinkChildren ($3,3,$1,$4, + TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));} + ; diff --git a/third_party/lib/acpica/source/compiler/asldefine.h b/third_party/lib/acpica/source/compiler/asldefine.h new file mode 100644 index 000000000..b42bae2ef --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asldefine.h @@ -0,0 +1,159 @@ +/****************************************************************************** + * + * Module Name: asldefine.h - Common defines for the iASL compiler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ASLDEFINE_H +#define __ASLDEFINE_H + + +/* + * Compiler versions and names + */ +#define ASL_COMPILER_NAME "ASL+ Optimizing Compiler" +#define AML_DISASSEMBLER_NAME "AML/ASL+ Disassembler" +#define ASL_INVOCATION_NAME "iasl" +#define ASL_CREATOR_ID "INTL" +#define ASL_DEFINE "__IASL__" + +#define ASL_COMPLIANCE "Supports ACPI Specification Revision 6.0" + + +/* Configuration constants */ + +#define ASL_MAX_ERROR_COUNT 200 +#define ASL_PARSEOP_CACHE_SIZE (1024 * 16) +#define ASL_STRING_CACHE_SIZE (1024 * 64) + +#define ASL_FIRST_PARSE_OPCODE PARSEOP_ACCESSAS +#define ASL_PARSE_OPCODE_BASE PARSEOP_ACCESSAS /* First Lex type */ + + +/* + * Per-parser-generator configuration. These values are used to cheat and + * directly access the bison/yacc token name table (yyname or yytname). + * Note: These values are the index in yyname for the first lex token + * (PARSEOP_ACCCESSAS). + */ +#if defined (YYBISON) +#define ASL_YYTNAME_START 3 /* Bison */ +#elif defined (YYBYACC) +#define ASL_YYTNAME_START 257 /* Berkeley yacc */ +#endif + + +/* + * Macros + */ +#define ASL_RESDESC_OFFSET(m) ACPI_OFFSET (AML_RESOURCE, m) +#define ASL_PTR_DIFF(a,b) ((UINT8 *)(b) - (UINT8 *)(a)) +#define ASL_PTR_ADD(a,b) ((UINT8 *)(a) = ((UINT8 *)(a) + (b))) +#define ASL_GET_CHILD_NODE(a) (a)->Asl.Child +#define ASL_GET_PEER_NODE(a) (a)->Asl.Next +#define OP_TABLE_ENTRY(a,b,c,d) {b,d,a,c} + + +/* Internal AML opcodes */ + +#define AML_RAW_DATA_BYTE (UINT16) 0xAA01 /* write one raw byte */ +#define AML_RAW_DATA_WORD (UINT16) 0xAA02 /* write 2 raw bytes */ +#define AML_RAW_DATA_DWORD (UINT16) 0xAA04 /* write 4 raw bytes */ +#define AML_RAW_DATA_QWORD (UINT16) 0xAA08 /* write 8 raw bytes */ +#define AML_RAW_DATA_BUFFER (UINT16) 0xAA0B /* raw buffer with length */ +#define AML_RAW_DATA_CHAIN (UINT16) 0xAA0C /* chain of raw buffers */ +#define AML_PACKAGE_LENGTH (UINT16) 0xAA10 +#define AML_UNASSIGNED_OPCODE (UINT16) 0xEEEE +#define AML_DEFAULT_ARG_OP (UINT16) 0xDDDD + + +/* Types for input files */ + +#define ASL_INPUT_TYPE_BINARY 0 +#define ASL_INPUT_TYPE_BINARY_ACPI_TABLE 1 +#define ASL_INPUT_TYPE_ASCII_ASL 2 +#define ASL_INPUT_TYPE_ASCII_DATA 3 + + +/* Misc */ + +#define ASL_EXTERNAL_METHOD 255 +#define ASL_ABORT TRUE +#define ASL_NO_ABORT FALSE +#define ASL_EOF ACPI_UINT32_MAX +#define ASL_WITHIN_COMMENT (ACPI_UINT32_MAX -1) +#define ASL_BLANK_LINE (ACPI_UINT32_MAX -1) + + +/* Listings */ + +#define ASL_LISTING_LINE_PREFIX ": " + + +/* Support for reserved method names */ + +#define ACPI_VALID_RESERVED_NAME_MAX 0x80000000 +#define ACPI_NOT_RESERVED_NAME ACPI_UINT32_MAX +#define ACPI_PREDEFINED_NAME (ACPI_UINT32_MAX - 1) +#define ACPI_EVENT_RESERVED_NAME (ACPI_UINT32_MAX - 2) +#define ACPI_COMPILER_RESERVED_NAME (ACPI_UINT32_MAX - 3) + + +/* Helper macros for resource tag creation */ + +#define RsCreateMultiBitField \ + RsCreateResourceField + +#define RsCreateBitField(Op, Name, ByteOffset, BitOffset) \ + RsCreateResourceField (Op, Name, ByteOffset, BitOffset, 1) + +#define RsCreateByteField(Op, Name, ByteOffset) \ + RsCreateResourceField (Op, Name, ByteOffset, 0, 8); + +#define RsCreateWordField(Op, Name, ByteOffset) \ + RsCreateResourceField (Op, Name, ByteOffset, 0, 16); + +#define RsCreateDwordField(Op, Name, ByteOffset) \ + RsCreateResourceField (Op, Name, ByteOffset, 0, 32); + +#define RsCreateQwordField(Op, Name, ByteOffset) \ + RsCreateResourceField (Op, Name, ByteOffset, 0, 64); + +#endif /* ASLDEFINE.H */ diff --git a/third_party/lib/acpica/source/compiler/aslerror.c b/third_party/lib/acpica/source/compiler/aslerror.c new file mode 100644 index 000000000..dfb6676f1 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslerror.c @@ -0,0 +1,932 @@ +/****************************************************************************** + * + * Module Name: aslerror - Error handling and statistics + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslerror") + +/* Local prototypes */ + +static void +AeAddToErrorLog ( + ASL_ERROR_MSG *Enode); + + +/******************************************************************************* + * + * FUNCTION: AslAbort + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump the error log and abort the compiler. Used for serious + * I/O errors. + * + ******************************************************************************/ + +void +AslAbort ( + void) +{ + + AePrintErrorLog (ASL_FILE_STDERR); + if (Gbl_DebugFlag) + { + /* Print error summary to stdout also */ + + AePrintErrorLog (ASL_FILE_STDOUT); + } + + exit (1); +} + + +/******************************************************************************* + * + * FUNCTION: AeClearErrorLog + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Empty the error list + * + ******************************************************************************/ + +void +AeClearErrorLog ( + void) +{ + ASL_ERROR_MSG *Enode = Gbl_ErrorLog; + ASL_ERROR_MSG *Next; + + /* Walk the error node list */ + + while (Enode) + { + Next = Enode->Next; + ACPI_FREE (Enode); + Enode = Next; + } + + Gbl_ErrorLog = NULL; +} + + +/******************************************************************************* + * + * FUNCTION: AeAddToErrorLog + * + * PARAMETERS: Enode - An error node to add to the log + * + * RETURN: None + * + * DESCRIPTION: Add a new error node to the error log. The error log is + * ordered by the "logical" line number (cumulative line number + * including all include files.) + * + ******************************************************************************/ + +static void +AeAddToErrorLog ( + ASL_ERROR_MSG *Enode) +{ + ASL_ERROR_MSG *Next; + ASL_ERROR_MSG *Prev; + + + /* If Gbl_ErrorLog is null, this is the first error node */ + + if (!Gbl_ErrorLog) + { + Gbl_ErrorLog = Enode; + return; + } + + /* + * Walk error list until we find a line number greater than ours. + * List is sorted according to line number. + */ + Prev = NULL; + Next = Gbl_ErrorLog; + + while ((Next) && + (Next->LogicalLineNumber <= Enode->LogicalLineNumber)) + { + Prev = Next; + Next = Next->Next; + } + + /* Found our place in the list */ + + Enode->Next = Next; + + if (Prev) + { + Prev->Next = Enode; + } + else + { + Gbl_ErrorLog = Enode; + } +} + + +/******************************************************************************* + * + * FUNCTION: AePrintException + * + * PARAMETERS: FileId - ID of output file + * Enode - Error node to print + * Header - Additional text before each message + * + * RETURN: None + * + * DESCRIPTION: Print the contents of an error node. + * + * NOTE: We don't use the FlxxxFile I/O functions here because on error + * they abort the compiler and call this function! Since we + * are reporting errors here, we ignore most output errors and + * just try to get out as much as we can. + * + ******************************************************************************/ + +void +AePrintException ( + UINT32 FileId, + ASL_ERROR_MSG *Enode, + char *Header) +{ + UINT8 SourceByte; + int Actual; + size_t RActual; + UINT32 MsgLength; + const char *MainMessage; + char *ExtraMessage; + UINT32 SourceColumn; + UINT32 ErrorColumn; + FILE *OutputFile; + FILE *SourceFile = NULL; + long FileSize; + BOOLEAN PrematureEOF = FALSE; + UINT32 Total = 0; + + + if (Gbl_NoErrors) + { + return; + } + + /* + * Only listing files have a header, and remarks/optimizations + * are always output + */ + if (!Header) + { + /* Ignore remarks if requested */ + + switch (Enode->Level) + { + case ASL_WARNING: + case ASL_WARNING2: + case ASL_WARNING3: + + if (!Gbl_DisplayWarnings) + { + return; + } + break; + + case ASL_REMARK: + + if (!Gbl_DisplayRemarks) + { + return; + } + break; + + case ASL_OPTIMIZATION: + + if (!Gbl_DisplayOptimizations) + { + return; + } + break; + + default: + + break; + } + } + + /* Get the various required file handles */ + + OutputFile = Gbl_Files[FileId].Handle; + + if (!Enode->SourceLine) + { + /* + * Use the merged header/source file if present, otherwise + * use input file + */ + SourceFile = Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Handle; + if (!SourceFile) + { + SourceFile = Gbl_Files[ASL_FILE_INPUT].Handle; + } + + if (SourceFile) + { + /* Determine if the error occurred at source file EOF */ + + fseek (SourceFile, 0, SEEK_END); + FileSize = ftell (SourceFile); + + if ((long) Enode->LogicalByteOffset >= FileSize) + { + PrematureEOF = TRUE; + } + } + } + + if (Header) + { + fprintf (OutputFile, "%s", Header); + } + + /* Print filename and line number if present and valid */ + + if (Enode->Filename) + { + if (Gbl_VerboseErrors) + { + fprintf (OutputFile, "%-8s", Enode->Filename); + + if (Enode->LineNumber) + { + if (Enode->SourceLine) + { + fprintf (OutputFile, " %6u: %s", + Enode->LineNumber, Enode->SourceLine); + } + else + { + fprintf (OutputFile, " %6u: ", Enode->LineNumber); + + /* + * If not at EOF, get the corresponding source code line + * and display it. Don't attempt this if we have a + * premature EOF condition. + */ + if (!PrematureEOF) + { + /* + * Seek to the offset in the combined source file, + * read the source line, and write it to the output. + */ + Actual = fseek (SourceFile, + (long) Enode->LogicalByteOffset, (int) SEEK_SET); + if (Actual) + { + fprintf (OutputFile, + "[*** iASL: Seek error on source code temp file %s ***]", + Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename); + } + else + { + RActual = fread (&SourceByte, 1, 1, SourceFile); + if (RActual != 1) + { + fprintf (OutputFile, + "[*** iASL: Read error on source code temp file %s ***]", + Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename); + } + else + { + /* Read/write the source line, up to the maximum line length */ + + while (RActual && SourceByte && (SourceByte != '\n')) + { + if (Total < 256) + { + /* After the max line length, we will just read the line, no write */ + + if (fwrite (&SourceByte, 1, 1, OutputFile) != 1) + { + printf ("[*** iASL: Write error on output file ***]\n"); + return; + } + } + else if (Total == 256) + { + fprintf (OutputFile, + "\n[*** iASL: Very long input line, message below refers to column %u ***]", + Enode->Column); + } + + RActual = fread (&SourceByte, 1, 1, SourceFile); + if (RActual != 1) + { + fprintf (OutputFile, + "[*** iASL: Read error on source code temp file %s ***]", + Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename); + return; + } + Total++; + } + } + } + } + + fprintf (OutputFile, "\n"); + } + } + } + else + { + /* + * Less verbose version of the error message, enabled via the + * -vi switch. The format is compatible with MS Visual Studio. + */ + fprintf (OutputFile, "%s", Enode->Filename); + + if (Enode->LineNumber) + { + fprintf (OutputFile, "(%u) : ", + Enode->LineNumber); + } + } + } + + /* If a NULL message ID, just print the raw message */ + + if (Enode->MessageId == 0) + { + fprintf (OutputFile, "%s\n", Enode->Message); + return; + } + + /* Decode the message ID */ + + fprintf (OutputFile, "%s %4.4d -", + AeDecodeExceptionLevel (Enode->Level), + AeBuildFullExceptionCode (Enode->Level, Enode->MessageId)); + + MainMessage = AeDecodeMessageId (Enode->MessageId); + ExtraMessage = Enode->Message; + + /* If a NULL line number, just print the decoded message */ + + if (!Enode->LineNumber) + { + fprintf (OutputFile, " %s %s\n\n", MainMessage, ExtraMessage); + return; + } + + MsgLength = strlen (MainMessage); + if (MsgLength == 0) + { + /* Use the secondary/extra message as main message */ + + MainMessage = Enode->Message; + if (!MainMessage) + { + MainMessage = ""; + } + + MsgLength = strlen (MainMessage); + ExtraMessage = NULL; + } + + if (Gbl_VerboseErrors && !PrematureEOF) + { + if (Total >= 256) + { + fprintf (OutputFile, " %s", + MainMessage); + } + else + { + SourceColumn = Enode->Column + Enode->FilenameLength + 6 + 2; + ErrorColumn = ASL_ERROR_LEVEL_LENGTH + 5 + 2 + 1; + + if ((MsgLength + ErrorColumn) < (SourceColumn - 1)) + { + fprintf (OutputFile, "%*s%s", + (int) ((SourceColumn - 1) - ErrorColumn), + MainMessage, " ^ "); + } + else + { + fprintf (OutputFile, "%*s %s", + (int) ((SourceColumn - ErrorColumn) + 1), "^", + MainMessage); + } + } + } + else + { + fprintf (OutputFile, " %s", MainMessage); + } + + /* Print the extra info message if present */ + + if (ExtraMessage) + { + fprintf (OutputFile, " (%s)", ExtraMessage); + } + + if (PrematureEOF) + { + fprintf (OutputFile, " and premature End-Of-File"); + } + + fprintf (OutputFile, "\n"); + if (Gbl_VerboseErrors) + { + fprintf (OutputFile, "\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AePrintErrorLog + * + * PARAMETERS: FileId - Where to output the error log + * + * RETURN: None + * + * DESCRIPTION: Print the entire contents of the error log + * + ******************************************************************************/ + +void +AePrintErrorLog ( + UINT32 FileId) +{ + ASL_ERROR_MSG *Enode = Gbl_ErrorLog; + + + /* Walk the error node list */ + + while (Enode) + { + AePrintException (FileId, Enode, NULL); + Enode = Enode->Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: AslCommonError2 + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * LineNumber - Actual file line number + * Column - Column in current line + * SourceLine - Actual source code line + * Filename - source filename + * ExtraMessage - additional error message + * + * RETURN: None + * + * DESCRIPTION: Create a new error node and add it to the error log + * + ******************************************************************************/ + +void +AslCommonError2 ( + UINT8 Level, + UINT16 MessageId, + UINT32 LineNumber, + UINT32 Column, + char *SourceLine, + char *Filename, + char *ExtraMessage) +{ + char *MessageBuffer = NULL; + char *LineBuffer; + ASL_ERROR_MSG *Enode; + + + Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG)); + + if (ExtraMessage) + { + /* Allocate a buffer for the message and a new error node */ + + MessageBuffer = UtStringCacheCalloc (strlen (ExtraMessage) + 1); + + /* Keep a copy of the extra message */ + + strcpy (MessageBuffer, ExtraMessage); + } + + LineBuffer = UtLocalCalloc (strlen (SourceLine) + 1); + strcpy (LineBuffer, SourceLine); + + /* Initialize the error node */ + + if (Filename) + { + Enode->Filename = Filename; + Enode->FilenameLength = strlen (Filename); + if (Enode->FilenameLength < 6) + { + Enode->FilenameLength = 6; + } + } + + Enode->MessageId = MessageId; + Enode->Level = Level; + Enode->LineNumber = LineNumber; + Enode->LogicalLineNumber = LineNumber; + Enode->LogicalByteOffset = 0; + Enode->Column = Column; + Enode->Message = MessageBuffer; + Enode->SourceLine = LineBuffer; + + /* Add the new node to the error node list */ + + AeAddToErrorLog (Enode); + + if (Gbl_DebugFlag) + { + /* stderr is a file, send error to it immediately */ + + AePrintException (ASL_FILE_STDERR, Enode, NULL); + } + + Gbl_ExceptionCount[Level]++; +} + + +/******************************************************************************* + * + * FUNCTION: AslCommonError + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * CurrentLineNumber - Actual file line number + * LogicalLineNumber - Cumulative line number + * LogicalByteOffset - Byte offset in source file + * Column - Column in current line + * Filename - source filename + * ExtraMessage - additional error message + * + * RETURN: None + * + * DESCRIPTION: Create a new error node and add it to the error log + * + ******************************************************************************/ + +void +AslCommonError ( + UINT8 Level, + UINT16 MessageId, + UINT32 CurrentLineNumber, + UINT32 LogicalLineNumber, + UINT32 LogicalByteOffset, + UINT32 Column, + char *Filename, + char *ExtraMessage) +{ + char *MessageBuffer = NULL; + ASL_ERROR_MSG *Enode; + + + Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG)); + + if (ExtraMessage) + { + /* Allocate a buffer for the message and a new error node */ + + MessageBuffer = UtStringCacheCalloc (strlen (ExtraMessage) + 1); + + /* Keep a copy of the extra message */ + + strcpy (MessageBuffer, ExtraMessage); + } + + /* Initialize the error node */ + + if (Filename) + { + Enode->Filename = Filename; + Enode->FilenameLength = strlen (Filename); + if (Enode->FilenameLength < 6) + { + Enode->FilenameLength = 6; + } + } + + Enode->MessageId = MessageId; + Enode->Level = Level; + Enode->LineNumber = CurrentLineNumber; + Enode->LogicalLineNumber = LogicalLineNumber; + Enode->LogicalByteOffset = LogicalByteOffset; + Enode->Column = Column; + Enode->Message = MessageBuffer; + Enode->SourceLine = NULL; + + /* Add the new node to the error node list */ + + AeAddToErrorLog (Enode); + + if (Gbl_DebugFlag) + { + /* stderr is a file, send error to it immediately */ + + AePrintException (ASL_FILE_STDERR, Enode, NULL); + } + + Gbl_ExceptionCount[Level]++; + if (Gbl_ExceptionCount[ASL_ERROR] > ASL_MAX_ERROR_COUNT) + { + printf ("\nMaximum error count (%u) exceeded\n", ASL_MAX_ERROR_COUNT); + + Gbl_SourceLine = 0; + Gbl_NextError = Gbl_ErrorLog; + CmCleanupAndExit (); + exit(1); + } + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AslDisableException + * + * PARAMETERS: MessageIdString - ID to be disabled + * + * RETURN: Status + * + * DESCRIPTION: Enter a message ID into the global disabled messages table + * + ******************************************************************************/ + +ACPI_STATUS +AslDisableException ( + char *MessageIdString) +{ + UINT32 MessageId; + + + /* Convert argument to an integer and validate it */ + + MessageId = (UINT32) strtoul (MessageIdString, NULL, 0); + + if ((MessageId < 2000) || (MessageId > 5999)) + { + printf ("\"%s\" is not a valid warning/remark ID\n", + MessageIdString); + return (AE_BAD_PARAMETER); + } + + /* Insert value into the global disabled message array */ + + if (Gbl_DisabledMessagesIndex >= ASL_MAX_DISABLED_MESSAGES) + { + printf ("Too many messages have been disabled (max %u)\n", + ASL_MAX_DISABLED_MESSAGES); + return (AE_LIMIT); + } + + Gbl_DisabledMessages[Gbl_DisabledMessagesIndex] = MessageId; + Gbl_DisabledMessagesIndex++; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AslIsExceptionDisabled + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * + * RETURN: TRUE if exception/message should be ignored + * + * DESCRIPTION: Check if the user has specified options such that this + * exception should be ignored + * + ******************************************************************************/ + +BOOLEAN +AslIsExceptionDisabled ( + UINT8 Level, + UINT16 MessageId) +{ + UINT32 EncodedMessageId; + UINT32 i; + + + switch (Level) + { + case ASL_WARNING2: + case ASL_WARNING3: + + /* Check for global disable via -w1/-w2/-w3 options */ + + if (Level > Gbl_WarningLevel) + { + return (TRUE); + } + /* Fall through */ + + case ASL_WARNING: + case ASL_REMARK: + /* + * Ignore this warning/remark if it has been disabled by + * the user (-vw option) + */ + EncodedMessageId = AeBuildFullExceptionCode (Level, MessageId); + for (i = 0; i < Gbl_DisabledMessagesIndex; i++) + { + /* Simple implementation via fixed array */ + + if (EncodedMessageId == Gbl_DisabledMessages[i]) + { + return (TRUE); + } + } + break; + + default: + break; + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AslError + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * Op - Parse node where error happened + * ExtraMessage - additional error message + * + * RETURN: None + * + * DESCRIPTION: Main error reporting routine for the ASL compiler (all code + * except the parser.) + * + ******************************************************************************/ + +void +AslError ( + UINT8 Level, + UINT16 MessageId, + ACPI_PARSE_OBJECT *Op, + char *ExtraMessage) +{ + + /* Check if user wants to ignore this exception */ + + if (Gbl_AllExceptionsDisabled || + AslIsExceptionDisabled (Level, MessageId)) + { + return; + } + + if (Op) + { + AslCommonError (Level, MessageId, Op->Asl.LineNumber, + Op->Asl.LogicalLineNumber, + Op->Asl.LogicalByteOffset, + Op->Asl.Column, + Op->Asl.Filename, ExtraMessage); + } + else + { + AslCommonError (Level, MessageId, 0, + 0, 0, 0, NULL, ExtraMessage); + } +} + + +/******************************************************************************* + * + * FUNCTION: AslCoreSubsystemError + * + * PARAMETERS: Op - Parse node where error happened + * Status - The ACPICA Exception + * ExtraMessage - additional error message + * Abort - TRUE -> Abort compilation + * + * RETURN: None + * + * DESCRIPTION: Error reporting routine for exceptions returned by the ACPICA + * core subsystem. + * + ******************************************************************************/ + +void +AslCoreSubsystemError ( + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS Status, + char *ExtraMessage, + BOOLEAN Abort) +{ + + sprintf (MsgBuffer, "%s %s", AcpiFormatException (Status), ExtraMessage); + + if (Op) + { + AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, + Op->Asl.LineNumber, + Op->Asl.LogicalLineNumber, + Op->Asl.LogicalByteOffset, + Op->Asl.Column, + Op->Asl.Filename, MsgBuffer); + } + else + { + AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, + 0, 0, 0, 0, NULL, MsgBuffer); + } + + if (Abort) + { + AslAbort (); + } +} + + +/******************************************************************************* + * + * FUNCTION: AslCompilererror + * + * PARAMETERS: CompilerMessage - Error message from the parser + * + * RETURN: Status (0 for now) + * + * DESCRIPTION: Report an error situation discovered in a production + * NOTE: don't change the name of this function, it is called + * from the auto-generated parser. + * + ******************************************************************************/ + +int +AslCompilererror ( + const char *CompilerMessage) +{ + + Gbl_SyntaxError++; + + AslCommonError (ASL_ERROR, ASL_MSG_SYNTAX, Gbl_CurrentLineNumber, + Gbl_LogicalLineNumber, Gbl_CurrentLineOffset, + Gbl_CurrentColumn, Gbl_Files[ASL_FILE_INPUT].Filename, + ACPI_CAST_PTR (char, CompilerMessage)); + + return (0); +} diff --git a/third_party/lib/acpica/source/compiler/aslfileio.c b/third_party/lib/acpica/source/compiler/aslfileio.c new file mode 100644 index 000000000..40f3562c0 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslfileio.c @@ -0,0 +1,401 @@ +/****************************************************************************** + * + * Module Name: aslfileio - File I/O support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acapps.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslfileio") + + +/******************************************************************************* + * + * FUNCTION: FlFileError + * + * PARAMETERS: FileId - Index into file info array + * ErrorId - Index into error message array + * + * RETURN: None + * + * DESCRIPTION: Decode errno to an error message and add the entire error + * to the error log. + * + ******************************************************************************/ + +void +FlFileError ( + UINT32 FileId, + UINT8 ErrorId) +{ + + sprintf (MsgBuffer, "\"%s\" (%s) - %s", Gbl_Files[FileId].Filename, + Gbl_Files[FileId].Description, strerror (errno)); + + AslCommonError (ASL_ERROR, ErrorId, 0, 0, 0, 0, NULL, MsgBuffer); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenFile + * + * PARAMETERS: FileId - Index into file info array + * Filename - file pathname to open + * Mode - Open mode for fopen + * + * RETURN: None + * + * DESCRIPTION: Open a file. + * NOTE: Aborts compiler on any error. + * + ******************************************************************************/ + +void +FlOpenFile ( + UINT32 FileId, + char *Filename, + char *Mode) +{ + FILE *File; + + + Gbl_Files[FileId].Filename = Filename; + Gbl_Files[FileId].Handle = NULL; + + File = fopen (Filename, Mode); + if (!File) + { + FlFileError (FileId, ASL_MSG_OPEN); + AslAbort (); + } + + Gbl_Files[FileId].Handle = File; +} + + +/******************************************************************************* + * + * FUNCTION: FlGetFileSize + * + * PARAMETERS: FileId - Index into file info array + * + * RETURN: File Size + * + * DESCRIPTION: Get current file size. Uses common seek-to-EOF function. + * File must be open. Aborts compiler on error. + * + ******************************************************************************/ + +UINT32 +FlGetFileSize ( + UINT32 FileId) +{ + UINT32 FileSize; + + + FileSize = CmGetFileSize (Gbl_Files[FileId].Handle); + if (FileSize == ACPI_UINT32_MAX) + { + AslAbort(); + } + + return (FileSize); +} + + +/******************************************************************************* + * + * FUNCTION: FlReadFile + * + * PARAMETERS: FileId - Index into file info array + * Buffer - Where to place the data + * Length - Amount to read + * + * RETURN: Status. AE_ERROR indicates EOF. + * + * DESCRIPTION: Read data from an open file. + * NOTE: Aborts compiler on any error. + * + ******************************************************************************/ + +ACPI_STATUS +FlReadFile ( + UINT32 FileId, + void *Buffer, + UINT32 Length) +{ + UINT32 Actual; + + + /* Read and check for error */ + + Actual = fread (Buffer, 1, Length, Gbl_Files[FileId].Handle); + if (Actual < Length) + { + if (feof (Gbl_Files[FileId].Handle)) + { + /* End-of-file, just return error */ + + return (AE_ERROR); + } + + FlFileError (FileId, ASL_MSG_READ); + AslAbort (); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: FlWriteFile + * + * PARAMETERS: FileId - Index into file info array + * Buffer - Data to write + * Length - Amount of data to write + * + * RETURN: None + * + * DESCRIPTION: Write data to an open file. + * NOTE: Aborts compiler on any error. + * + ******************************************************************************/ + +void +FlWriteFile ( + UINT32 FileId, + void *Buffer, + UINT32 Length) +{ + UINT32 Actual; + + + /* Write and check for error */ + + Actual = fwrite ((char *) Buffer, 1, Length, Gbl_Files[FileId].Handle); + if (Actual != Length) + { + FlFileError (FileId, ASL_MSG_WRITE); + AslAbort (); + } + + if ((FileId == ASL_FILE_PREPROCESSOR) && Gbl_PreprocessorOutputFlag) + { + /* Duplicate the output to the user preprocessor (.i) file */ + + Actual = fwrite ((char *) Buffer, 1, Length, + Gbl_Files[ASL_FILE_PREPROCESSOR_USER].Handle); + if (Actual != Length) + { + FlFileError (FileId, ASL_MSG_WRITE); + AslAbort (); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: FlPrintFile + * + * PARAMETERS: FileId - Index into file info array + * Format - Printf format string + * ... - Printf arguments + * + * RETURN: None + * + * DESCRIPTION: Formatted write to an open file. + * NOTE: Aborts compiler on any error. + * + ******************************************************************************/ + +void +FlPrintFile ( + UINT32 FileId, + char *Format, + ...) +{ + INT32 Actual; + va_list Args; + + + va_start (Args, Format); + Actual = vfprintf (Gbl_Files[FileId].Handle, Format, Args); + va_end (Args); + + if (Actual == -1) + { + FlFileError (FileId, ASL_MSG_WRITE); + AslAbort (); + } + + if ((FileId == ASL_FILE_PREPROCESSOR) && + Gbl_PreprocessorOutputFlag) + { + /* + * Duplicate the output to the user preprocessor (.i) file, + * except: no #line directives. + */ + if (!strncmp (Format, "#line", 5)) + { + return; + } + + va_start (Args, Format); + Actual = vfprintf (Gbl_Files[ASL_FILE_PREPROCESSOR_USER].Handle, + Format, Args); + va_end (Args); + + if (Actual == -1) + { + FlFileError (FileId, ASL_MSG_WRITE); + AslAbort (); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: FlSeekFile + * + * PARAMETERS: FileId - Index into file info array + * Offset - Absolute byte offset in file + * + * RETURN: None + * + * DESCRIPTION: Seek to absolute offset. + * NOTE: Aborts compiler on any error. + * + ******************************************************************************/ + +void +FlSeekFile ( + UINT32 FileId, + long Offset) +{ + int Error; + + + Error = fseek (Gbl_Files[FileId].Handle, Offset, SEEK_SET); + if (Error) + { + FlFileError (FileId, ASL_MSG_SEEK); + AslAbort (); + } +} + + +/******************************************************************************* + * + * FUNCTION: FlCloseFile + * + * PARAMETERS: FileId - Index into file info array + * + * RETURN: None + * + * DESCRIPTION: Close an open file. Aborts compiler on error + * + ******************************************************************************/ + +void +FlCloseFile ( + UINT32 FileId) +{ + int Error; + + + if (!Gbl_Files[FileId].Handle) + { + return; + } + + Error = fclose (Gbl_Files[FileId].Handle); + if (Error) + { + FlFileError (FileId, ASL_MSG_CLOSE); + AslAbort (); + } + + /* Do not clear/free the filename string */ + + Gbl_Files[FileId].Handle = NULL; + return; +} + + +/******************************************************************************* + * + * FUNCTION: FlDeleteFile + * + * PARAMETERS: FileId - Index into file info array + * + * RETURN: None + * + * DESCRIPTION: Delete a file. + * + ******************************************************************************/ + +void +FlDeleteFile ( + UINT32 FileId) +{ + ASL_FILE_INFO *Info = &Gbl_Files[FileId]; + + + if (!Info->Filename) + { + return; + } + + if (remove (Info->Filename)) + { + printf ("%s (%s file) ", + Info->Filename, Info->Description); + perror ("Could not delete"); + } + + Info->Filename = NULL; + return; +} diff --git a/third_party/lib/acpica/source/compiler/aslfiles.c b/third_party/lib/acpica/source/compiler/aslfiles.c new file mode 100644 index 000000000..0d1c794e7 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslfiles.c @@ -0,0 +1,909 @@ +/****************************************************************************** + * + * Module Name: aslfiles - File support functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acapps.h" +#include "dtcompiler.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslfiles") + +/* Local prototypes */ + +static FILE * +FlOpenIncludeWithPrefix ( + char *PrefixDir, + ACPI_PARSE_OBJECT *Op, + char *Filename); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +ACPI_STATUS +FlParseInputPathname ( + char *InputFilename); +#endif + + +/******************************************************************************* + * + * FUNCTION: FlSetLineNumber + * + * PARAMETERS: Op - Parse node for the LINE asl statement + * + * RETURN: None. + * + * DESCRIPTION: Set the current line number + * + ******************************************************************************/ + +void +FlSetLineNumber ( + UINT32 LineNumber) +{ + + DbgPrint (ASL_PARSE_OUTPUT, "\n#line: New line number %u (old %u)\n", + LineNumber, Gbl_LogicalLineNumber); + + Gbl_CurrentLineNumber = LineNumber; +} + + +/******************************************************************************* + * + * FUNCTION: FlSetFilename + * + * PARAMETERS: Op - Parse node for the LINE asl statement + * + * RETURN: None. + * + * DESCRIPTION: Set the current filename + * + ******************************************************************************/ + +void +FlSetFilename ( + char *Filename) +{ + + DbgPrint (ASL_PARSE_OUTPUT, "\n#line: New filename %s (old %s)\n", + Filename, Gbl_Files[ASL_FILE_INPUT].Filename); + + /* No need to free any existing filename */ + + Gbl_Files[ASL_FILE_INPUT].Filename = Filename; +} + + +/******************************************************************************* + * + * FUNCTION: FlAddIncludeDirectory + * + * PARAMETERS: Dir - Directory pathname string + * + * RETURN: None + * + * DESCRIPTION: Add a directory the list of include prefix directories. + * + ******************************************************************************/ + +void +FlAddIncludeDirectory ( + char *Dir) +{ + ASL_INCLUDE_DIR *NewDir; + ASL_INCLUDE_DIR *NextDir; + ASL_INCLUDE_DIR *PrevDir = NULL; + UINT32 NeedsSeparator = 0; + size_t DirLength; + + + DirLength = strlen (Dir); + if (!DirLength) + { + return; + } + + /* Make sure that the pathname ends with a path separator */ + + if ((Dir[DirLength-1] != '/') && + (Dir[DirLength-1] != '\\')) + { + NeedsSeparator = 1; + } + + NewDir = ACPI_ALLOCATE_ZEROED (sizeof (ASL_INCLUDE_DIR)); + NewDir->Dir = ACPI_ALLOCATE (DirLength + 1 + NeedsSeparator); + strcpy (NewDir->Dir, Dir); + if (NeedsSeparator) + { + strcat (NewDir->Dir, "/"); + } + + /* + * Preserve command line ordering of -I options by adding new elements + * at the end of the list + */ + NextDir = Gbl_IncludeDirList; + while (NextDir) + { + PrevDir = NextDir; + NextDir = NextDir->Next; + } + + if (PrevDir) + { + PrevDir->Next = NewDir; + } + else + { + Gbl_IncludeDirList = NewDir; + } +} + + +/******************************************************************************* + * + * FUNCTION: FlMergePathnames + * + * PARAMETERS: PrefixDir - Prefix directory pathname. Can be NULL or + * a zero length string. + * FilePathname - The include filename from the source ASL. + * + * RETURN: Merged pathname string + * + * DESCRIPTION: Merge two pathnames that (probably) have common elements, to + * arrive at a minimal length string. Merge can occur if the + * FilePathname is relative to the PrefixDir. + * + ******************************************************************************/ + +char * +FlMergePathnames ( + char *PrefixDir, + char *FilePathname) +{ + char *CommonPath; + char *Pathname; + char *LastElement; + + + DbgPrint (ASL_PARSE_OUTPUT, "Include: Prefix path - \"%s\"\n" + "Include: FilePathname - \"%s\"\n", + PrefixDir, FilePathname); + + /* + * If there is no prefix directory or if the file pathname is absolute, + * just return the original file pathname + */ + if (!PrefixDir || (!*PrefixDir) || + (*FilePathname == '/') || + (FilePathname[1] == ':')) + { + Pathname = UtStringCacheCalloc (strlen (FilePathname) + 1); + strcpy (Pathname, FilePathname); + goto ConvertBackslashes; + } + + /* Need a local copy of the prefix directory path */ + + CommonPath = UtStringCacheCalloc (strlen (PrefixDir) + 1); + strcpy (CommonPath, PrefixDir); + + /* + * Walk forward through the file path, and simultaneously backward + * through the prefix directory path until there are no more + * relative references at the start of the file path. + */ + while (*FilePathname && (!strncmp (FilePathname, "../", 3))) + { + /* Remove last element of the prefix directory path */ + + LastElement = strrchr (CommonPath, '/'); + if (!LastElement) + { + goto ConcatenatePaths; + } + + *LastElement = 0; /* Terminate CommonPath string */ + FilePathname += 3; /* Point to next path element */ + } + + /* + * Remove the last element of the prefix directory path (it is the same as + * the first element of the file pathname), and build the final merged + * pathname. + */ + LastElement = strrchr (CommonPath, '/'); + if (LastElement) + { + *LastElement = 0; + } + + /* Build the final merged pathname */ + +ConcatenatePaths: + Pathname = UtStringCacheCalloc ( + strlen (CommonPath) + strlen (FilePathname) + 2); + if (LastElement && *CommonPath) + { + strcpy (Pathname, CommonPath); + strcat (Pathname, "/"); + } + strcat (Pathname, FilePathname); + + /* Convert all backslashes to normal slashes */ + +ConvertBackslashes: + UtConvertBackslashes (Pathname); + + DbgPrint (ASL_PARSE_OUTPUT, "Include: Merged Pathname - \"%s\"\n", + Pathname); + return (Pathname); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenIncludeWithPrefix + * + * PARAMETERS: PrefixDir - Prefix directory pathname. Can be a zero + * length string. + * Filename - The include filename from the source ASL. + * + * RETURN: Valid file descriptor if successful. Null otherwise. + * + * DESCRIPTION: Open an include file and push it on the input file stack. + * + ******************************************************************************/ + +static FILE * +FlOpenIncludeWithPrefix ( + char *PrefixDir, + ACPI_PARSE_OBJECT *Op, + char *Filename) +{ + FILE *IncludeFile; + char *Pathname; + UINT32 OriginalLineNumber; + + + /* Build the full pathname to the file */ + + Pathname = FlMergePathnames (PrefixDir, Filename); + + DbgPrint (ASL_PARSE_OUTPUT, "Include: Opening file - \"%s\"\n\n", + Pathname); + + /* Attempt to open the file, push if successful */ + + IncludeFile = fopen (Pathname, "r"); + if (!IncludeFile) + { + fprintf (stderr, "Could not open include file %s\n", Pathname); + ACPI_FREE (Pathname); + return (NULL); + } + + /* + * Check the entire include file for any # preprocessor directives. + * This is because there may be some confusion between the #include + * preprocessor directive and the ASL Include statement. A file included + * by the ASL include cannot contain preprocessor directives because + * the preprocessor has already run by the time the ASL include is + * recognized (by the compiler, not the preprocessor.) + * + * Note: DtGetNextLine strips/ignores comments. + * Save current line number since DtGetNextLine modifies it. + */ + Gbl_CurrentLineNumber--; + OriginalLineNumber = Gbl_CurrentLineNumber; + + while (DtGetNextLine (IncludeFile, DT_ALLOW_MULTILINE_QUOTES) != ASL_EOF) + { + if (Gbl_CurrentLineBuffer[0] == '#') + { + AslError (ASL_ERROR, ASL_MSG_INCLUDE_FILE, + Op, "use #include instead"); + } + } + + Gbl_CurrentLineNumber = OriginalLineNumber; + + /* Must seek back to the start of the file */ + + fseek (IncludeFile, 0, SEEK_SET); + + /* Push the include file on the open input file stack */ + + AslPushInputFileStack (IncludeFile, Pathname); + return (IncludeFile); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenIncludeFile + * + * PARAMETERS: Op - Parse node for the INCLUDE ASL statement + * + * RETURN: None. + * + * DESCRIPTION: Open an include file and push it on the input file stack. + * + ******************************************************************************/ + +void +FlOpenIncludeFile ( + ACPI_PARSE_OBJECT *Op) +{ + FILE *IncludeFile; + ASL_INCLUDE_DIR *NextDir; + + + /* Op must be valid */ + + if (!Op) + { + AslCommonError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_InputByteCount, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, " - Null parse node"); + + return; + } + + /* + * Flush out the "include ()" statement on this line, start + * the actual include file on the next line + */ + AslResetCurrentLineBuffer (); + FlPrintFile (ASL_FILE_SOURCE_OUTPUT, "\n"); + Gbl_CurrentLineOffset++; + + + /* Attempt to open the include file */ + + /* If the file specifies an absolute path, just open it */ + + if ((Op->Asl.Value.String[0] == '/') || + (Op->Asl.Value.String[0] == '\\') || + (Op->Asl.Value.String[1] == ':')) + { + IncludeFile = FlOpenIncludeWithPrefix ("", Op, Op->Asl.Value.String); + if (!IncludeFile) + { + goto ErrorExit; + } + return; + } + + /* + * The include filename is not an absolute path. + * + * First, search for the file within the "local" directory -- meaning + * the same directory that contains the source file. + * + * Construct the file pathname from the global directory name. + */ + IncludeFile = FlOpenIncludeWithPrefix ( + Gbl_DirectoryPath, Op, Op->Asl.Value.String); + if (IncludeFile) + { + return; + } + + /* + * Second, search for the file within the (possibly multiple) directories + * specified by the -I option on the command line. + */ + NextDir = Gbl_IncludeDirList; + while (NextDir) + { + IncludeFile = FlOpenIncludeWithPrefix ( + NextDir->Dir, Op, Op->Asl.Value.String); + if (IncludeFile) + { + return; + } + + NextDir = NextDir->Next; + } + + /* We could not open the include file after trying very hard */ + +ErrorExit: + sprintf (MsgBuffer, "%s, %s", Op->Asl.Value.String, strerror (errno)); + AslError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, Op, MsgBuffer); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenInputFile + * + * PARAMETERS: InputFilename - The user-specified ASL source file to be + * compiled + * + * RETURN: Status + * + * DESCRIPTION: Open the specified input file, and save the directory path to + * the file so that include files can be opened in + * the same directory. + * + ******************************************************************************/ + +ACPI_STATUS +FlOpenInputFile ( + char *InputFilename) +{ + + /* Open the input ASL file, text mode */ + + FlOpenFile (ASL_FILE_INPUT, InputFilename, "rt"); + AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle; + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenAmlOutputFile + * + * PARAMETERS: FilenamePrefix - The user-specified ASL source file + * + * RETURN: Status + * + * DESCRIPTION: Create the output filename (*.AML) and open the file. The file + * is created in the same directory as the parent input file. + * + ******************************************************************************/ + +ACPI_STATUS +FlOpenAmlOutputFile ( + char *FilenamePrefix) +{ + char *Filename; + + + /* Output filename usually comes from the ASL itself */ + + Filename = Gbl_Files[ASL_FILE_AML_OUTPUT].Filename; + if (!Filename) + { + /* Create the output AML filename */ + + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_AML_CODE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_OUTPUT_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + Gbl_Files[ASL_FILE_AML_OUTPUT].Filename = Filename; + } + + /* Open the output AML file in binary mode */ + + FlOpenFile (ASL_FILE_AML_OUTPUT, Filename, "w+b"); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenMiscOutputFiles + * + * PARAMETERS: FilenamePrefix - The user-specified ASL source file + * + * RETURN: Status + * + * DESCRIPTION: Create and open the various output files needed, depending on + * the command line options + * + ******************************************************************************/ + +ACPI_STATUS +FlOpenMiscOutputFiles ( + char *FilenamePrefix) +{ + char *Filename; + + + /* Create/Open a map file if requested */ + + if (Gbl_MapfileFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_MAP); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the hex file, text mode (closed at compiler exit) */ + + FlOpenFile (ASL_FILE_MAP_OUTPUT, Filename, "w+t"); + + AslCompilerSignon (ASL_FILE_MAP_OUTPUT); + AslCompilerFileHeader (ASL_FILE_MAP_OUTPUT); + } + + /* All done for disassembler */ + + if (Gbl_FileType == ASL_INPUT_TYPE_BINARY_ACPI_TABLE) + { + return (AE_OK); + } + + /* Create/Open a hex output file if asked */ + + if (Gbl_HexOutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_HEX_DUMP); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the hex file, text mode */ + + FlOpenFile (ASL_FILE_HEX_OUTPUT, Filename, "w+t"); + + AslCompilerSignon (ASL_FILE_HEX_OUTPUT); + AslCompilerFileHeader (ASL_FILE_HEX_OUTPUT); + } + + /* Create/Open a debug output file if asked */ + + if (Gbl_DebugFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_DEBUG); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_DEBUG_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the debug file as STDERR, text mode */ + + Gbl_Files[ASL_FILE_DEBUG_OUTPUT].Filename = Filename; + Gbl_Files[ASL_FILE_DEBUG_OUTPUT].Handle = + freopen (Filename, "w+t", stderr); + + if (!Gbl_Files[ASL_FILE_DEBUG_OUTPUT].Handle) + { + /* + * A problem with freopen is that on error, we no longer + * have stderr and cannot emit normal error messages. + * Emit error to stdout, close files, and exit. + */ + fprintf (stdout, + "\nCould not open debug output file: %s\n\n", Filename); + + CmCleanupAndExit (); + exit (1); + } + + AslCompilerSignon (ASL_FILE_DEBUG_OUTPUT); + AslCompilerFileHeader (ASL_FILE_DEBUG_OUTPUT); + } + + /* Create/Open a listing output file if asked */ + + if (Gbl_ListingFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_LISTING); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the listing file, text mode */ + + FlOpenFile (ASL_FILE_LISTING_OUTPUT, Filename, "w+t"); + + AslCompilerSignon (ASL_FILE_LISTING_OUTPUT); + AslCompilerFileHeader (ASL_FILE_LISTING_OUTPUT); + } + + /* Create the preprocessor output temp file if preprocessor enabled */ + + if (Gbl_PreprocessFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_PREPROCESSOR); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_PREPROCESSOR_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + FlOpenFile (ASL_FILE_PREPROCESSOR, Filename, "w+t"); + } + + /* + * Create the "user" preprocessor output file if -li flag set. + * Note, this file contains no embedded #line directives. + */ + if (Gbl_PreprocessorOutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_PREPROC_USER); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_PREPROCESSOR_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + FlOpenFile (ASL_FILE_PREPROCESSOR_USER, Filename, "w+t"); + } + + /* All done for data table compiler */ + + if (Gbl_FileType == ASL_INPUT_TYPE_ASCII_DATA) + { + return (AE_OK); + } + + /* Create/Open a combined source output file */ + + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_SOURCE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* + * Open the source output file, binary mode (so that LF does not get + * expanded to CR/LF on some systems, messing up our seek + * calculations.) + */ + FlOpenFile (ASL_FILE_SOURCE_OUTPUT, Filename, "w+b"); + +/* +// TBD: TEMP +// AslCompilerin = Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Handle; +*/ + /* Create/Open a assembly code source output file if asked */ + + if (Gbl_AsmOutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_ASM_SOURCE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the assembly code source file, text mode */ + + FlOpenFile (ASL_FILE_ASM_SOURCE_OUTPUT, Filename, "w+t"); + + AslCompilerSignon (ASL_FILE_ASM_SOURCE_OUTPUT); + AslCompilerFileHeader (ASL_FILE_ASM_SOURCE_OUTPUT); + } + + /* Create/Open a C code source output file if asked */ + + if (Gbl_C_OutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_C_SOURCE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the C code source file, text mode */ + + FlOpenFile (ASL_FILE_C_SOURCE_OUTPUT, Filename, "w+t"); + + FlPrintFile (ASL_FILE_C_SOURCE_OUTPUT, "/*\n"); + AslCompilerSignon (ASL_FILE_C_SOURCE_OUTPUT); + AslCompilerFileHeader (ASL_FILE_C_SOURCE_OUTPUT); + } + + /* Create/Open a C code source output file for the offset table if asked */ + + if (Gbl_C_OffsetTableFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_C_OFFSET); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the C code source file, text mode */ + + FlOpenFile (ASL_FILE_C_OFFSET_OUTPUT, Filename, "w+t"); + + FlPrintFile (ASL_FILE_C_OFFSET_OUTPUT, "/*\n"); + AslCompilerSignon (ASL_FILE_C_OFFSET_OUTPUT); + AslCompilerFileHeader (ASL_FILE_C_OFFSET_OUTPUT); + } + + /* Create/Open a assembly include output file if asked */ + + if (Gbl_AsmIncludeOutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_ASM_INCLUDE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the assembly include file, text mode */ + + FlOpenFile (ASL_FILE_ASM_INCLUDE_OUTPUT, Filename, "w+t"); + + AslCompilerSignon (ASL_FILE_ASM_INCLUDE_OUTPUT); + AslCompilerFileHeader (ASL_FILE_ASM_INCLUDE_OUTPUT); + } + + /* Create/Open a C include output file if asked */ + + if (Gbl_C_IncludeOutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_C_INCLUDE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the C include file, text mode */ + + FlOpenFile (ASL_FILE_C_INCLUDE_OUTPUT, Filename, "w+t"); + + FlPrintFile (ASL_FILE_C_INCLUDE_OUTPUT, "/*\n"); + AslCompilerSignon (ASL_FILE_C_INCLUDE_OUTPUT); + AslCompilerFileHeader (ASL_FILE_C_INCLUDE_OUTPUT); + } + + /* Create a namespace output file if asked */ + + if (Gbl_NsOutputFlag) + { + Filename = FlGenerateFilename (FilenamePrefix, FILE_SUFFIX_NAMESPACE); + if (!Filename) + { + AslCommonError (ASL_ERROR, ASL_MSG_LISTING_FILENAME, + 0, 0, 0, 0, NULL, NULL); + return (AE_ERROR); + } + + /* Open the namespace file, text mode */ + + FlOpenFile (ASL_FILE_NAMESPACE_OUTPUT, Filename, "w+t"); + + AslCompilerSignon (ASL_FILE_NAMESPACE_OUTPUT); + AslCompilerFileHeader (ASL_FILE_NAMESPACE_OUTPUT); + } + + return (AE_OK); +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: FlParseInputPathname + * + * PARAMETERS: InputFilename - The user-specified ASL source file to be + * compiled + * + * RETURN: Status + * + * DESCRIPTION: Split the input path into a directory and filename part + * 1) Directory part used to open include files + * 2) Filename part used to generate output filenames + * + ******************************************************************************/ + +ACPI_STATUS +FlParseInputPathname ( + char *InputFilename) +{ + char *Substring; + + + if (!InputFilename) + { + return (AE_OK); + } + + /* Get the path to the input filename's directory */ + + Gbl_DirectoryPath = strdup (InputFilename); + if (!Gbl_DirectoryPath) + { + return (AE_NO_MEMORY); + } + + Substring = strrchr (Gbl_DirectoryPath, '\\'); + if (!Substring) + { + Substring = strrchr (Gbl_DirectoryPath, '/'); + if (!Substring) + { + Substring = strrchr (Gbl_DirectoryPath, ':'); + } + } + + if (!Substring) + { + Gbl_DirectoryPath[0] = 0; + if (Gbl_UseDefaultAmlFilename) + { + Gbl_OutputFilenamePrefix = strdup (InputFilename); + } + } + else + { + if (Gbl_UseDefaultAmlFilename) + { + Gbl_OutputFilenamePrefix = strdup (Substring + 1); + } + *(Substring+1) = 0; + } + + UtConvertBackslashes (Gbl_OutputFilenamePrefix); + return (AE_OK); +} +#endif diff --git a/third_party/lib/acpica/source/compiler/aslfold.c b/third_party/lib/acpica/source/compiler/aslfold.c new file mode 100644 index 000000000..9f219d9f9 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslfold.c @@ -0,0 +1,885 @@ +/****************************************************************************** + * + * Module Name: aslfold - Constant folding + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#include "acdispat.h" +#include "acparser.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslfold") + +/* Local prototypes */ + +static ACPI_STATUS +OpcAmlEvaluationWalk1 ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +OpcAmlEvaluationWalk2 ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +OpcAmlCheckForConstant ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static void +OpcUpdateIntegerNode ( + ACPI_PARSE_OBJECT *Op, + UINT64 Value); + +static ACPI_STATUS +TrTransformToStoreOp ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +static ACPI_STATUS +TrSimpleConstantReduction ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +static void +TrInstallReducedConstant ( + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ObjDesc); + + +/******************************************************************************* + * + * FUNCTION: OpcAmlConstantWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Reduce an Op and its subtree to a constant if possible. + * + ******************************************************************************/ + +ACPI_STATUS +OpcAmlConstantWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState; + ACPI_STATUS Status = AE_OK; + + + if (Op->Asl.CompileFlags == 0) + { + return (AE_OK); + } + + /* + * Only interested in subtrees that could possibly contain + * expressions that can be evaluated at this time + */ + if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) || + (Op->Asl.CompileFlags & NODE_IS_TARGET)) + { + return (AE_OK); + } + + /* Create a new walk state */ + + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + if (!WalkState) + { + return (AE_NO_MEMORY); + } + + WalkState->NextOp = NULL; + WalkState->Params = NULL; + + /* + * Examine the entire subtree -- all nodes must be constants + * or type 3/4/5 opcodes + */ + Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD, + OpcAmlCheckForConstant, NULL, WalkState); + + /* + * Did we find an entire subtree that contains all constants + * and type 3/4/5 opcodes? + */ + switch (Status) + { + case AE_OK: + + /* Simple case, like Add(3,4) -> 7 */ + + Status = TrSimpleConstantReduction (Op, WalkState); + break; + + case AE_CTRL_RETURN_VALUE: + + /* More complex case, like Add(3,4,Local0) -> Store(7,Local0) */ + + Status = TrTransformToStoreOp (Op, WalkState); + break; + + case AE_TYPE: + + AcpiDsDeleteWalkState (WalkState); + return (AE_OK); + + default: + AcpiDsDeleteWalkState (WalkState); + break; + } + + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, "Cannot resolve, %s\n", + AcpiFormatException (Status)); + + /* We could not resolve the subtree for some reason */ + + AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op, + (char *) AcpiFormatException (Status)); + + /* Set the subtree value to ZERO anyway. Eliminates further errors */ + + OpcUpdateIntegerNode (Op, 0); + } + + /* Abort the walk of this subtree, we are done with it */ + + return (AE_CTRL_DEPTH); +} + + +/******************************************************************************* + * + * FUNCTION: OpcAmlCheckForConstant + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Check one Op for a reducible type 3/4/5 AML opcode. + * This is performed via a downward walk of the parse subtree. + * + ******************************************************************************/ + +static ACPI_STATUS +OpcAmlCheckForConstant ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = Context; + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *NextOp; + const ACPI_OPCODE_INFO *OpInfo; + + + WalkState->Op = Op; + WalkState->Opcode = Op->Common.AmlOpcode; + WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ", + Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName); + + /* + * These opcodes do not appear in the OpcodeInfo table, but + * they represent constants, so abort the constant walk now. + */ + if ((WalkState->Opcode == AML_RAW_DATA_BYTE) || + (WalkState->Opcode == AML_RAW_DATA_WORD) || + (WalkState->Opcode == AML_RAW_DATA_DWORD) || + (WalkState->Opcode == AML_RAW_DATA_QWORD)) + { + DbgPrint (ASL_PARSE_OUTPUT, "RAW DATA"); + Status = AE_TYPE; + goto CleanupAndExit; + } + + /* + * Search upwards for a possible Name() operator. This is done + * because a type 3/4/5 opcode within a Name() expression + * MUST be reduced to a simple constant. + */ + NextOp = Op->Asl.Parent; + while (NextOp) + { + /* Finished if we find a Name() opcode */ + + if (NextOp->Asl.AmlOpcode == AML_NAME_OP) + { + break; + } + + /* + * Any "deferred" opcodes contain one or more TermArg parameters, + * and thus are not required to be folded to constants at compile + * time. This affects things like Buffer() and Package() objects. + * We just ignore them here. However, any sub-expressions can and + * will still be typechecked. Note: These are called the + * "deferred" opcodes in the AML interpreter. + */ + OpInfo = AcpiPsGetOpcodeInfo (NextOp->Common.AmlOpcode); + if (OpInfo->Flags & AML_DEFER) + { + NextOp = NULL; + break; + } + + NextOp = NextOp->Asl.Parent; + } + + /* Type 3/4/5 opcodes have the AML_CONSTANT flag set */ + + if (!(WalkState->OpInfo->Flags & AML_CONSTANT)) + { + /* + * From the ACPI specification: + * + * "The Type 3/4/5 opcodes return a value and can be used in an + * expression that evaluates to a constant. These opcodes may be + * evaluated at ASL compile-time. To ensure that these opcodes + * will evaluate to a constant, the following rules apply: The + * term cannot have a destination (target) operand, and must have + * either a Type3Opcode, Type4Opcode, Type5Opcode, ConstExprTerm, + * Integer, BufferTerm, Package, or String for all arguments." + */ + + /* + * The value (second) operand for the Name() operator MUST + * reduce to a single constant, as per the ACPI specification + * (the operand is a DataObject). This also implies that there + * can be no target operand. Name() is the only ASL operator + * with a "DataObject" as an operand and is thus special- + * cased here. + */ + if (NextOp) /* Inspect a Name() operator */ + { + /* Error if there is a target operand */ + + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op, NULL); + Status = AE_TYPE; + } + + /* Error if expression cannot be reduced (folded) */ + + if (!(NextOp->Asl.CompileFlags & NODE_COULD_NOT_REDUCE)) + { + /* Ensure only one error message per statement */ + + NextOp->Asl.CompileFlags |= NODE_COULD_NOT_REDUCE; + DbgPrint (ASL_PARSE_OUTPUT, + "**** Could not reduce operands for NAME opcode ****\n"); + + AslError (ASL_ERROR, ASL_MSG_CONSTANT_REQUIRED, Op, + "Constant is required for Name operator"); + Status = AE_TYPE; + } + } + + if (ACPI_FAILURE (Status)) + { + goto CleanupAndExit; + } + + /* This is not a 3/4/5 opcode, but maybe can convert to STORE */ + + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + DbgPrint (ASL_PARSE_OUTPUT, + "**** Valid Target, transform to Store ****\n"); + return (AE_CTRL_RETURN_VALUE); + } + + /* Expression cannot be reduced */ + + DbgPrint (ASL_PARSE_OUTPUT, + "**** Not a Type 3/4/5 opcode or cannot reduce/fold (%s) ****\n", + Op->Asl.ParseOpName); + + Status = AE_TYPE; + goto CleanupAndExit; + } + + /* + * TBD: Ignore buffer constants for now. The problem is that these + * constants have been transformed into RAW_DATA at this point, from + * the parse tree transform process which currently happens before + * the constant folding process. We may need to defer this transform + * for buffer until after the constant folding. + */ + if (WalkState->Opcode == AML_BUFFER_OP) + { + DbgPrint (ASL_PARSE_OUTPUT, + "\nBuffer constant reduction is not supported yet\n"); + + if (NextOp) /* Found a Name() operator, error */ + { + AslError (ASL_ERROR, ASL_MSG_UNSUPPORTED, Op, + "Buffer expression cannot be reduced"); + } + + Status = AE_TYPE; + goto CleanupAndExit; + } + + + /* Debug output */ + + DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345"); + + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + if (Op->Asl.ParseOpcode == PARSEOP_ZERO) + { + DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " NULL TARGET"); + } + else + { + DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " VALID TARGET"); + } + } + + if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG) + { + DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " TERMARG"); + } + +CleanupAndExit: + + /* Dump the node compile flags also */ + + TrPrintNodeCompileFlags (Op->Asl.CompileFlags); + DbgPrint (ASL_PARSE_OUTPUT, "\n"); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: TrSimpleConstantReduction + * + * PARAMETERS: Op - Parent operator to be transformed + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Reduce an entire AML operation to a single constant. The + * operation must not have a target operand. + * + * Add (32,64) --> 96 + * + ******************************************************************************/ + +static ACPI_STATUS +TrSimpleConstantReduction ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *RootOp; + ACPI_PARSE_OBJECT *OriginalParentOp; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + DbgPrint (ASL_PARSE_OUTPUT, + "Simple subtree constant reduction, operator to constant\n"); + + /* Allocate a new temporary root for this subtree */ + + RootOp = TrAllocateNode (PARSEOP_INTEGER); + if (!RootOp) + { + return (AE_NO_MEMORY); + } + + RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP; + + OriginalParentOp = Op->Common.Parent; + Op->Common.Parent = RootOp; + + /* Hand off the subtree to the AML interpreter */ + + WalkState->CallerReturnDesc = &ObjDesc; + + Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE, + OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState); + + /* Restore original parse tree */ + + Op->Common.Parent = OriginalParentOp; + + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, + "Constant Subtree evaluation(1), %s\n", + AcpiFormatException (Status)); + return (Status); + } + + /* Get the final result */ + + Status = AcpiDsResultPop (&ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, + "Constant Subtree evaluation(2), %s\n", + AcpiFormatException (Status)); + return (Status); + } + + /* Disconnect any existing children, install new constant */ + + Op->Asl.Child = NULL; + TrInstallReducedConstant (Op, ObjDesc); + + UtSetParseOpName (Op); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: TrTransformToStoreOp + * + * PARAMETERS: Op - Parent operator to be transformed + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Transforms a single AML operation with a constant and target + * to a simple store operation: + * + * Add (32,64,DATA) --> Store (96,DATA) + * + ******************************************************************************/ + +static ACPI_STATUS +TrTransformToStoreOp ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *OriginalTarget; + ACPI_PARSE_OBJECT *NewTarget; + ACPI_PARSE_OBJECT *Child1; + ACPI_PARSE_OBJECT *Child2; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PARSE_OBJECT *NewParent; + ACPI_PARSE_OBJECT *OriginalParent; + ACPI_STATUS Status; + + + DbgPrint (ASL_PARSE_OUTPUT, + "Reduction/Transform to StoreOp: Store(Constant, Target)\n"); + + /* Extract the operands */ + + Child1 = Op->Asl.Child; + Child2 = Child1->Asl.Next; + + /* + * Special case for DIVIDE -- it has two targets. The first + * is for the remainder and if present, we will not attempt + * to reduce the expression. + */ + if (Op->Asl.ParseOpcode == PARSEOP_DIVIDE) + { + Child2 = Child2->Asl.Next; + if (Child2->Asl.ParseOpcode != PARSEOP_ZERO) + { + DbgPrint (ASL_PARSE_OUTPUT, + "Cannot reduce DIVIDE - has two targets\n\n"); + return (AE_OK); + } + } + + /* + * Create a NULL (zero) target so that we can use the + * interpreter to evaluate the expression. + */ + NewTarget = TrCreateNullTarget (); + NewTarget->Common.AmlOpcode = AML_INT_NAMEPATH_OP; + + /* Handle one-operand cases (NOT, TOBCD, etc.) */ + + if (!Child2->Asl.Next) + { + Child2 = Child1; + } + + /* Link in new NULL target as the last operand */ + + OriginalTarget = Child2->Asl.Next; + Child2->Asl.Next = NewTarget; + NewTarget->Asl.Parent = OriginalTarget->Asl.Parent; + + NewParent = TrAllocateNode (PARSEOP_INTEGER); + NewParent->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP; + + OriginalParent = Op->Common.Parent; + Op->Common.Parent = NewParent; + + /* Hand off the subtree to the AML interpreter */ + + WalkState->CallerReturnDesc = &ObjDesc; + + Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE, + OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState); + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, + "Constant Subtree evaluation(3), %s\n", + AcpiFormatException (Status)); + goto EvalError; + } + + /* Get the final result */ + + Status = AcpiDsResultPop (&ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, + "Constant Subtree evaluation(4), %s\n", + AcpiFormatException (Status)); + goto EvalError; + } + + /* Truncate any subtree expressions, they have been evaluated */ + + Child1->Asl.Child = NULL; + + /* Folded constant is in ObjDesc, store into Child1 */ + + TrInstallReducedConstant (Child1, ObjDesc); + + /* Convert operator to STORE */ + + Op->Asl.ParseOpcode = PARSEOP_STORE; + Op->Asl.AmlOpcode = AML_STORE_OP; + UtSetParseOpName (Op); + Op->Common.Parent = OriginalParent; + + /* First child is the folded constant */ + + /* Second child will be the target */ + + Child1->Asl.Next = OriginalTarget; + return (AE_OK); + + +EvalError: + + /* Restore original links */ + + Op->Common.Parent = OriginalParent; + Child2->Asl.Next = OriginalTarget; + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: TrInstallReducedConstant + * + * PARAMETERS: Op - Parent operator to be transformed + * ObjDesc - Reduced constant to be installed + * + * RETURN: None + * + * DESCRIPTION: Transform the original operator to a simple constant. + * Handles Integers, Strings, and Buffers. + * + ******************************************************************************/ + +static void +TrInstallReducedConstant ( + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_PARSE_OBJECT *LengthOp; + ACPI_PARSE_OBJECT *DataOp; + + + TotalFolds++; + AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op, + Op->Asl.ParseOpName); + + /* + * Because we know we executed type 3/4/5 opcodes above, we know that + * the result must be either an Integer, String, or Buffer. + */ + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value); + + DbgPrint (ASL_PARSE_OUTPUT, + "Constant expression reduced to (%s) %8.8X%8.8X\n\n", + Op->Asl.ParseOpName, + ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); + break; + + case ACPI_TYPE_STRING: + + Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; + Op->Common.AmlOpcode = AML_STRING_OP; + Op->Asl.AmlLength = strlen (ObjDesc->String.Pointer) + 1; + Op->Common.Value.String = ObjDesc->String.Pointer; + + DbgPrint (ASL_PARSE_OUTPUT, + "Constant expression reduced to (STRING) %s\n\n", + Op->Common.Value.String); + break; + + case ACPI_TYPE_BUFFER: + /* + * Create a new parse subtree of the form: + * + * BUFFER (Buffer AML opcode) + * INTEGER (Buffer length in bytes) + * RAW_DATA (Buffer byte data) + */ + Op->Asl.ParseOpcode = PARSEOP_BUFFER; + Op->Common.AmlOpcode = AML_BUFFER_OP; + Op->Asl.CompileFlags = NODE_AML_PACKAGE; + UtSetParseOpName (Op); + + /* Child node is the buffer length */ + + LengthOp = TrAllocateNode (PARSEOP_INTEGER); + + LengthOp->Asl.AmlOpcode = AML_DWORD_OP; + LengthOp->Asl.Value.Integer = ObjDesc->Buffer.Length; + LengthOp->Asl.Parent = Op; + (void) OpcSetOptimalIntegerSize (LengthOp); + + Op->Asl.Child = LengthOp; + + /* Next child is the raw buffer data */ + + DataOp = TrAllocateNode (PARSEOP_RAW_DATA); + DataOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; + DataOp->Asl.AmlLength = ObjDesc->Buffer.Length; + DataOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer; + DataOp->Asl.Parent = Op; + + LengthOp->Asl.Next = DataOp; + + DbgPrint (ASL_PARSE_OUTPUT, + "Constant expression reduced to (BUFFER) length %X\n\n", + ObjDesc->Buffer.Length); + break; + + default: + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: OpcUpdateIntegerNode + * + * PARAMETERS: Op - Current parse object + * Value - Value for the integer op + * + * RETURN: None + * + * DESCRIPTION: Update node to the correct Integer type and value + * + ******************************************************************************/ + +static void +OpcUpdateIntegerNode ( + ACPI_PARSE_OBJECT *Op, + UINT64 Value) +{ + + Op->Common.Value.Integer = Value; + + /* + * The AmlLength is used by the parser to indicate a constant, + * (if non-zero). Length is either (1/2/4/8) + */ + switch (Op->Asl.AmlLength) + { + case 1: + + TrUpdateNode (PARSEOP_BYTECONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + break; + + case 2: + + TrUpdateNode (PARSEOP_WORDCONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_WORD; + break; + + case 4: + + TrUpdateNode (PARSEOP_DWORDCONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD; + break; + + case 8: + + TrUpdateNode (PARSEOP_QWORDCONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD; + break; + + case 0: + default: + + OpcSetOptimalIntegerSize (Op); + TrUpdateNode (PARSEOP_INTEGER, Op); + break; + } + + Op->Asl.AmlLength = 0; +} + + +/******************************************************************************* + * + * FUNCTION: OpcAmlEvaluationWalk1 + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback for AML execution of constant subtrees + * + ******************************************************************************/ + +static ACPI_STATUS +OpcAmlEvaluationWalk1 ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = Context; + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *OutOp; + + + WalkState->Op = Op; + WalkState->Opcode = Op->Common.AmlOpcode; + WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + /* Copy child pointer to Arg for compatibility with Interpreter */ + + if (Op->Asl.Child) + { + Op->Common.Value.Arg = Op->Asl.Child; + } + + /* Call AML dispatcher */ + + Status = AcpiDsExecBeginOp (WalkState, &OutOp); + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, + "%s Constant interpretation failed (1) - %s\n", + Op->Asl.ParseOpName, AcpiFormatException (Status)); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: OpcAmlEvaluationWalk2 + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback for AML execution of constant subtrees + * + ******************************************************************************/ + +static ACPI_STATUS +OpcAmlEvaluationWalk2 ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = Context; + ACPI_STATUS Status; + + + WalkState->Op = Op; + WalkState->Opcode = Op->Common.AmlOpcode; + WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + /* Copy child pointer to Arg for compatibility with Interpreter */ + + if (Op->Asl.Child) + { + Op->Common.Value.Arg = Op->Asl.Child; + } + + /* Call AML dispatcher */ + + Status = AcpiDsExecEndOp (WalkState); + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_PARSE_OUTPUT, + "%s: Constant interpretation failed (2) - %s\n", + Op->Asl.ParseOpName, AcpiFormatException (Status)); + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/compiler/aslglobal.h b/third_party/lib/acpica/source/compiler/aslglobal.h new file mode 100644 index 000000000..1fb793524 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslglobal.h @@ -0,0 +1,285 @@ +/****************************************************************************** + * + * Module Name: aslglobal.h - Global variable definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ASLGLOBAL_H +#define __ASLGLOBAL_H + + +/* + * Global variables. Defined in aslmain.c only, externed in all other files + */ + +#undef ASL_EXTERN + +#ifdef _DECLARE_GLOBALS +#define ASL_EXTERN +#define ASL_INIT_GLOBAL(a,b) (a)=(b) +#else +#define ASL_EXTERN extern +#define ASL_INIT_GLOBAL(a,b) (a) +#endif + + +#ifdef _DECLARE_GLOBALS +UINT32 Gbl_ExceptionCount[ASL_NUM_REPORT_LEVELS] = {0,0,0,0,0,0}; + +/* Table below must match ASL_FILE_TYPES in asltypes.h */ + +ASL_FILE_INFO Gbl_Files [ASL_NUM_FILES] = +{ + {NULL, NULL, "stdout: ", "Standard Output"}, + {NULL, NULL, "stderr: ", "Standard Error"}, + {NULL, NULL, "Table Input: ", "Source Input"}, + {NULL, NULL, "Binary Output:", "AML Output"}, + {NULL, NULL, "Source Output:", "Source Output"}, + {NULL, NULL, "Preprocessor: ", "Preprocessor Output"}, + {NULL, NULL, "Preprocessor: ", "Preprocessor Temp File"}, + {NULL, NULL, "Listing File: ", "Listing Output"}, + {NULL, NULL, "Hex Dump: ", "Hex Table Output"}, + {NULL, NULL, "Namespace: ", "Namespace Output"}, + {NULL, NULL, "Debug File: ", "Debug Output"}, + {NULL, NULL, "ASM Source: ", "Assembly Code Output"}, + {NULL, NULL, "C Source: ", "C Code Output"}, + {NULL, NULL, "ASM Include: ", "Assembly Header Output"}, + {NULL, NULL, "C Include: ", "C Header Output"}, + {NULL, NULL, "Offset Table: ", "C Offset Table Output"}, + {NULL, NULL, "Device Map: ", "Device Map Output"} +}; + +#else +extern UINT32 Gbl_ExceptionCount[ASL_NUM_REPORT_LEVELS]; +extern ASL_FILE_INFO Gbl_Files [ASL_NUM_FILES]; +#endif + + +/* + * Parser and other externals + */ +extern int yydebug; +extern FILE *AslCompilerin; +extern int DtParserdebug; +extern int PrParserdebug; +extern const ASL_MAPPING_ENTRY AslKeywordMapping[]; +extern char *AslCompilertext; + +/* + * Older versions of Bison won't emit this external in the generated header. + * Newer versions do emit the external, so we don't need to do it. + */ +#ifndef ASLCOMPILER_ASLCOMPILERPARSE_H +extern int AslCompilerdebug; +#endif + + +#define ASL_DEFAULT_LINE_BUFFER_SIZE (1024 * 32) /* 32K */ +#define ASL_MSG_BUFFER_SIZE 4096 +#define ASL_MAX_DISABLED_MESSAGES 32 +#define HEX_TABLE_LINE_SIZE 8 +#define HEX_LISTING_LINE_SIZE 8 + + +/* Source code buffers and pointers for error reporting */ + +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_CurrentLineBuffer, NULL); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_LineBufPtr, NULL); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_LineBufferSize, ASL_DEFAULT_LINE_BUFFER_SIZE); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentColumn, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentLineNumber, 1); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_LogicalLineNumber, 1); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentLineOffset, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_OriginalInputFileSize, 0); +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_SyntaxError, 0); + +/* Exception reporting */ + +ASL_EXTERN ASL_ERROR_MSG ASL_INIT_GLOBAL (*Gbl_ErrorLog,NULL); +ASL_EXTERN ASL_ERROR_MSG ASL_INIT_GLOBAL (*Gbl_NextError,NULL); + +/* Option flags */ + +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DoCompile, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DoSignon, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_PreprocessOnly, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_PreprocessFlag, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DisassembleAll, FALSE); + +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_UseDefaultAmlFilename, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_MapfileFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_NsOutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_PreprocessorOutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_KeepPreprocessorTempFile, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DebugFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_AsmOutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_C_OutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_C_OffsetTableFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_AsmIncludeOutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_C_IncludeOutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_ListingFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_IgnoreErrors, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_SourceOutputFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_ParseOnlyFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_CompileTimesFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_FoldConstants, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_VerboseErrors, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_NoErrors, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_WarningsAsErrors, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_NoResourceChecking, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DisasmFlag, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_IntegerOptimizationFlag, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_ReferenceOptimizationFlag, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DisplayRemarks, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DisplayWarnings, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DisplayOptimizations, FALSE); +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_WarningLevel, ASL_WARNING); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_UseOriginalCompilerId, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_VerboseTemplates, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DoTemplates, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_CompileGeneric, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_AllExceptionsDisabled, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_PruneParseTree, FALSE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_DoTypechecking, TRUE); +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_EnableReferenceTypechecking, FALSE); + + +#define HEX_OUTPUT_NONE 0 +#define HEX_OUTPUT_C 1 +#define HEX_OUTPUT_ASM 2 +#define HEX_OUTPUT_ASL 3 + +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_HexOutputFlag, HEX_OUTPUT_NONE); + + +/* Files */ + +ASL_EXTERN char *Gbl_DirectoryPath; +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_IncludeFilename, NULL); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_OutputFilenamePrefix, NULL); +ASL_EXTERN ASL_INCLUDE_DIR ASL_INIT_GLOBAL (*Gbl_IncludeDirList, NULL); +ASL_EXTERN char *Gbl_CurrentInputFilename; +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_ExternalRefFilename, NULL); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_PreviousIncludeFilename, NULL); + +ASL_EXTERN BOOLEAN ASL_INIT_GLOBAL (Gbl_HasIncludeFiles, FALSE); + + +/* Statistics */ + +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_InputByteCount, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_InputFieldCount, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_NsLookupCount, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalKeywords, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalNamedObjects, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalExecutableOpcodes, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalParseNodes, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalMethods, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalAllocations, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalAllocated, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (TotalFolds, 0); + + +/* Local caches */ + +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_ParseOpCount, 0); +ASL_EXTERN ASL_CACHE_INFO ASL_INIT_GLOBAL (*Gbl_ParseOpCacheList, NULL); +ASL_EXTERN ACPI_PARSE_OBJECT ASL_INIT_GLOBAL (*Gbl_ParseOpCacheNext, NULL); +ASL_EXTERN ACPI_PARSE_OBJECT ASL_INIT_GLOBAL (*Gbl_ParseOpCacheLast, NULL); + +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_StringCount, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_StringSize, 0); +ASL_EXTERN ASL_CACHE_INFO ASL_INIT_GLOBAL (*Gbl_StringCacheList, NULL); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_StringCacheNext, NULL); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_StringCacheLast, NULL); + +/* Map file */ + +ASL_EXTERN ACPI_GPIO_INFO ASL_INIT_GLOBAL (*Gbl_GpioList, NULL); +ASL_EXTERN ACPI_SERIAL_INFO ASL_INIT_GLOBAL (*Gbl_SerialList, NULL); + + +/* Misc */ + +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_RevisionOverride, 0); +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_TempCount, 0); +ASL_EXTERN ACPI_PARSE_OBJECT ASL_INIT_GLOBAL (*RootNode, NULL); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_TableLength, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_SourceLine, 0); +ASL_EXTERN ASL_LISTING_NODE ASL_INIT_GLOBAL (*Gbl_ListingNode, NULL); +ASL_EXTERN ACPI_PARSE_OBJECT *Gbl_FirstLevelInsertionNode; +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_FileType, 0); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_Signature, NULL); + +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentHexColumn, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentAmlOffset, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentLine, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_DisabledMessagesIndex, 0); +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_HexBytesWereWritten, FALSE); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_NumNamespaceObjects, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_ReservedMethods, 0); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_TableSignature, "NO_SIG"); +ASL_EXTERN char ASL_INIT_GLOBAL (*Gbl_TableId, "NO_ID"); +ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_PruneDepth, 0); +ASL_EXTERN UINT16 ASL_INIT_GLOBAL (Gbl_PruneType, 0); + + +/* Static structures */ + +ASL_EXTERN ASL_ANALYSIS_WALK_INFO AnalysisWalkInfo; +ASL_EXTERN ACPI_TABLE_HEADER TableHeader; + +/* Event timing */ + +#define ASL_NUM_EVENTS 20 +ASL_EXTERN ASL_EVENT_INFO AslGbl_Events[ASL_NUM_EVENTS]; +ASL_EXTERN UINT8 AslGbl_NextEvent; +ASL_EXTERN UINT8 AslGbl_NamespaceEvent; + +/* Scratch buffers */ + +ASL_EXTERN UINT8 Gbl_AmlBuffer[HEX_LISTING_LINE_SIZE]; +ASL_EXTERN char MsgBuffer[ASL_MSG_BUFFER_SIZE]; +ASL_EXTERN char StringBuffer[ASL_MSG_BUFFER_SIZE]; +ASL_EXTERN char StringBuffer2[ASL_MSG_BUFFER_SIZE]; +ASL_EXTERN UINT32 Gbl_DisabledMessages[ASL_MAX_DISABLED_MESSAGES]; + + +#endif /* __ASLGLOBAL_H */ diff --git a/third_party/lib/acpica/source/compiler/aslhex.c b/third_party/lib/acpica/source/compiler/aslhex.c new file mode 100644 index 000000000..afa395e97 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslhex.c @@ -0,0 +1,404 @@ +/****************************************************************************** + * + * Module Name: aslhex - ASCII hex output file generation (C, ASM, and ASL) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("ashex") + +/* + * This module emits ASCII hex output files in either C, ASM, or ASL format + */ + +/* Local prototypes */ + +static void +HxDoHexOutputC ( + void); + +static void +HxDoHexOutputAsl ( + void); + +static void +HxDoHexOutputAsm ( + void); + +static UINT32 +HxReadAmlOutputFile ( + UINT8 *Buffer); + + +/******************************************************************************* + * + * FUNCTION: HxDoHexOutput + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Create the hex output file. Note: data is obtained by reading + * the entire AML output file that was previously generated. + * + ******************************************************************************/ + +void +HxDoHexOutput ( + void) +{ + + switch (Gbl_HexOutputFlag) + { + case HEX_OUTPUT_C: + + HxDoHexOutputC (); + break; + + case HEX_OUTPUT_ASM: + + HxDoHexOutputAsm (); + break; + + case HEX_OUTPUT_ASL: + + HxDoHexOutputAsl (); + break; + + default: + + /* No other output types supported */ + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: HxReadAmlOutputFile + * + * PARAMETERS: Buffer - Where to return data + * + * RETURN: None + * + * DESCRIPTION: Read a line of the AML output prior to formatting the data + * + ******************************************************************************/ + +static UINT32 +HxReadAmlOutputFile ( + UINT8 *Buffer) +{ + UINT32 Actual; + + + Actual = fread (Buffer, 1, HEX_TABLE_LINE_SIZE, + Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); + + if (ferror (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle)) + { + FlFileError (ASL_FILE_AML_OUTPUT, ASL_MSG_READ); + AslAbort (); + } + + return (Actual); +} + + +/******************************************************************************* + * + * FUNCTION: HxDoHexOutputC + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Create the hex output file. This is the same data as the AML + * output file, but formatted into hex/ascii bytes suitable for + * inclusion into a C source file. + * + ******************************************************************************/ + +static void +HxDoHexOutputC ( + void) +{ + UINT8 FileData[HEX_TABLE_LINE_SIZE]; + UINT32 LineLength; + UINT32 Offset = 0; + UINT32 AmlFileSize; + UINT32 i; + + + /* Get AML size, seek back to start */ + + AmlFileSize = FlGetFileSize (ASL_FILE_AML_OUTPUT); + FlSeekFile (ASL_FILE_AML_OUTPUT, 0); + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " * C source code output\n"); + FlPrintFile (ASL_FILE_HEX_OUTPUT, " * AML code block contains 0x%X bytes\n *\n */\n", + AmlFileSize); + FlPrintFile (ASL_FILE_HEX_OUTPUT, "unsigned char AmlCode[] =\n{\n"); + + while (Offset < AmlFileSize) + { + /* Read enough bytes needed for one output line */ + + LineLength = HxReadAmlOutputFile (FileData); + if (!LineLength) + { + break; + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " "); + + for (i = 0; i < LineLength; i++) + { + /* + * Print each hex byte. + * Add a comma until the very last byte of the AML file + * (Some C compilers complain about a trailing comma) + */ + FlPrintFile (ASL_FILE_HEX_OUTPUT, "0x%2.2X", FileData[i]); + if ((Offset + i + 1) < AmlFileSize) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, ","); + } + else + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, " "); + } + } + + /* Add fill spaces if needed for last line */ + + if (LineLength < HEX_TABLE_LINE_SIZE) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, "%*s", + 5 * (HEX_TABLE_LINE_SIZE - LineLength), " "); + } + + /* Emit the offset and ascii dump for the entire line */ + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " /* %8.8X", Offset); + LsDumpAsciiInComment (ASL_FILE_HEX_OUTPUT, LineLength, FileData); + + FlPrintFile (ASL_FILE_HEX_OUTPUT, "%*s*/\n", + HEX_TABLE_LINE_SIZE - LineLength + 1, " "); + + Offset += LineLength; + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, "};\n"); +} + + +/******************************************************************************* + * + * FUNCTION: HxDoHexOutputAsl + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Create the hex output file. This is the same data as the AML + * output file, but formatted into hex/ascii bytes suitable for + * inclusion into a C source file. + * + ******************************************************************************/ + +static void +HxDoHexOutputAsl ( + void) +{ + UINT8 FileData[HEX_TABLE_LINE_SIZE]; + UINT32 LineLength; + UINT32 Offset = 0; + UINT32 AmlFileSize; + UINT32 i; + + + /* Get AML size, seek back to start */ + + AmlFileSize = FlGetFileSize (ASL_FILE_AML_OUTPUT); + FlSeekFile (ASL_FILE_AML_OUTPUT, 0); + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " * ASL source code output\n"); + FlPrintFile (ASL_FILE_HEX_OUTPUT, " * AML code block contains 0x%X bytes\n *\n */\n", + AmlFileSize); + FlPrintFile (ASL_FILE_HEX_OUTPUT, " Name (BUF1, Buffer()\n {\n"); + + while (Offset < AmlFileSize) + { + /* Read enough bytes needed for one output line */ + + LineLength = HxReadAmlOutputFile (FileData); + if (!LineLength) + { + break; + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " "); + + for (i = 0; i < LineLength; i++) + { + /* + * Print each hex byte. + * Add a comma until the very last byte of the AML file + * (Some C compilers complain about a trailing comma) + */ + FlPrintFile (ASL_FILE_HEX_OUTPUT, "0x%2.2X", FileData[i]); + if ((Offset + i + 1) < AmlFileSize) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, ","); + } + else + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, " "); + } + } + + /* Add fill spaces if needed for last line */ + + if (LineLength < HEX_TABLE_LINE_SIZE) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, "%*s", + 5 * (HEX_TABLE_LINE_SIZE - LineLength), " "); + } + + /* Emit the offset and ascii dump for the entire line */ + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " /* %8.8X", Offset); + LsDumpAsciiInComment (ASL_FILE_HEX_OUTPUT, LineLength, FileData); + + FlPrintFile (ASL_FILE_HEX_OUTPUT, "%*s*/\n", + HEX_TABLE_LINE_SIZE - LineLength + 1, " "); + + Offset += LineLength; + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " })\n"); +} + + +/******************************************************************************* + * + * FUNCTION: HxDoHexOutputAsm + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Create the hex output file. This is the same data as the AML + * output file, but formatted into hex/ascii bytes suitable for + * inclusion into a ASM source file. + * + ******************************************************************************/ + +static void +HxDoHexOutputAsm ( + void) +{ + UINT8 FileData[HEX_TABLE_LINE_SIZE]; + UINT32 LineLength; + UINT32 Offset = 0; + UINT32 AmlFileSize; + UINT32 i; + + + /* Get AML size, seek back to start */ + + AmlFileSize = FlGetFileSize (ASL_FILE_AML_OUTPUT); + FlSeekFile (ASL_FILE_AML_OUTPUT, 0); + + FlPrintFile (ASL_FILE_HEX_OUTPUT, "; Assembly code source output\n"); + FlPrintFile (ASL_FILE_HEX_OUTPUT, "; AML code block contains 0x%X bytes\n;\n", + AmlFileSize); + + while (Offset < AmlFileSize) + { + /* Read enough bytes needed for one output line */ + + LineLength = HxReadAmlOutputFile (FileData); + if (!LineLength) + { + break; + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " db "); + + for (i = 0; i < LineLength; i++) + { + /* + * Print each hex byte. + * Add a comma until the last byte of the line + */ + FlPrintFile (ASL_FILE_HEX_OUTPUT, "0%2.2Xh", FileData[i]); + if ((i + 1) < LineLength) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, ","); + } + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " "); + + /* Add fill spaces if needed for last line */ + + if (LineLength < HEX_TABLE_LINE_SIZE) + { + FlPrintFile (ASL_FILE_HEX_OUTPUT, "%*s", + 5 * (HEX_TABLE_LINE_SIZE - LineLength), " "); + } + + /* Emit the offset and ascii dump for the entire line */ + + FlPrintFile (ASL_FILE_HEX_OUTPUT, " ; %8.8X", Offset); + LsDumpAsciiInComment (ASL_FILE_HEX_OUTPUT, LineLength, FileData); + + FlPrintFile (ASL_FILE_HEX_OUTPUT, "\n"); + + Offset += LineLength; + } + + FlPrintFile (ASL_FILE_HEX_OUTPUT, "\n"); +} diff --git a/third_party/lib/acpica/source/compiler/asllength.c b/third_party/lib/acpica/source/compiler/asllength.c new file mode 100644 index 000000000..0cea63cd6 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asllength.c @@ -0,0 +1,455 @@ +/****************************************************************************** + * + * Module Name: asllength - Tree walk to determine package and opcode lengths + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asllength") + +/* Local prototypes */ + +static UINT8 +CgGetPackageLenByteCount ( + ACPI_PARSE_OBJECT *Op, + UINT32 PackageLength); + +static void +CgGenerateAmlOpcodeLength ( + ACPI_PARSE_OBJECT *Op); + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +void +LnAdjustLengthToRoot ( + ACPI_PARSE_OBJECT *Op, + UINT32 LengthDelta); +#endif + + +/******************************************************************************* + * + * FUNCTION: LnInitLengthsWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Walk callback to initialize (and re-initialize) the node + * subtree length(s) to zero. The Subtree lengths are bubbled + * up to the root node in order to get a total AML length. + * + ******************************************************************************/ + +ACPI_STATUS +LnInitLengthsWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + Op->Asl.AmlSubtreeLength = 0; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LnPackageLengthWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Walk callback to calculate the total AML length. + * 1) Calculate the AML lengths (opcode, package length, etc.) for + * THIS node. + * 2) Bubbble up all of these lengths to the parent node by summing + * them all into the parent subtree length. + * + * Note: The SubtreeLength represents the total AML length of all child nodes + * in all subtrees under a given node. Therefore, once this walk is + * complete, the Root Node subtree length is the AML length of the entire + * tree (and thus, the entire ACPI table) + * + ******************************************************************************/ + +ACPI_STATUS +LnPackageLengthWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + /* Generate the AML lengths for this node */ + + CgGenerateAmlLengths (Op); + + /* Bubble up all lengths (this node and all below it) to the parent */ + + if ((Op->Asl.Parent) && + (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) + { + Op->Asl.Parent->Asl.AmlSubtreeLength += ( + Op->Asl.AmlLength + + Op->Asl.AmlOpcodeLength + + Op->Asl.AmlPkgLenBytes + + Op->Asl.AmlSubtreeLength); + } + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: CgGetPackageLenByteCount + * + * PARAMETERS: Op - Parse node + * PackageLength - Length to be encoded + * + * RETURN: Required length of the package length encoding + * + * DESCRIPTION: Calculate the number of bytes required to encode the given + * package length. + * + ******************************************************************************/ + +static UINT8 +CgGetPackageLenByteCount ( + ACPI_PARSE_OBJECT *Op, + UINT32 PackageLength) +{ + + /* + * Determine the number of bytes required to encode the package length + * Note: the package length includes the number of bytes used to encode + * the package length, so we must account for this also. + */ + if (PackageLength <= (0x0000003F - 1)) + { + return (1); + } + else if (PackageLength <= (0x00000FFF - 2)) + { + return (2); + } + else if (PackageLength <= (0x000FFFFF - 3)) + { + return (3); + } + else if (PackageLength <= (0x0FFFFFFF - 4)) + { + return (4); + } + else + { + /* Fatal error - the package length is too large to encode */ + + AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL); + } + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: CgGenerateAmlOpcodeLength + * + * PARAMETERS: Op - Parse node whose AML opcode lengths will be + * calculated + * + * RETURN: None. + * + * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength + * fields for this node. + * + ******************************************************************************/ + +static void +CgGenerateAmlOpcodeLength ( + ACPI_PARSE_OBJECT *Op) +{ + + /* Check for two-byte opcode */ + + if (Op->Asl.AmlOpcode > 0x00FF) + { + Op->Asl.AmlOpcodeLength = 2; + } + else + { + Op->Asl.AmlOpcodeLength = 1; + } + + /* Does this opcode have an associated "PackageLength" field? */ + + Op->Asl.AmlPkgLenBytes = 0; + if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) + { + Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount ( + Op, Op->Asl.AmlSubtreeLength); + } + + /* Data opcode lengths are easy */ + + switch (Op->Asl.AmlOpcode) + { + case AML_BYTE_OP: + + Op->Asl.AmlLength = 1; + break; + + case AML_WORD_OP: + + Op->Asl.AmlLength = 2; + break; + + case AML_DWORD_OP: + + Op->Asl.AmlLength = 4; + break; + + case AML_QWORD_OP: + + Op->Asl.AmlLength = 8; + break; + + default: + + /* All data opcodes must be above */ + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: CgGenerateAmlLengths + * + * PARAMETERS: Op - Parse node + * + * RETURN: None. + * + * DESCRIPTION: Generate internal length fields based on the AML opcode or + * parse opcode. + * + ******************************************************************************/ + +void +CgGenerateAmlLengths ( + ACPI_PARSE_OBJECT *Op) +{ + char *Buffer; + ACPI_STATUS Status; + + + switch (Op->Asl.AmlOpcode) + { + case AML_RAW_DATA_BYTE: + + Op->Asl.AmlOpcodeLength = 0; + Op->Asl.AmlLength = 1; + return; + + case AML_RAW_DATA_WORD: + + Op->Asl.AmlOpcodeLength = 0; + Op->Asl.AmlLength = 2; + return; + + case AML_RAW_DATA_DWORD: + + Op->Asl.AmlOpcodeLength = 0; + Op->Asl.AmlLength = 4; + return; + + case AML_RAW_DATA_QWORD: + + Op->Asl.AmlOpcodeLength = 0; + Op->Asl.AmlLength = 8; + return; + + case AML_RAW_DATA_BUFFER: + + /* Aml length is/was set by creator */ + + Op->Asl.AmlOpcodeLength = 0; + return; + + case AML_RAW_DATA_CHAIN: + + /* Aml length is/was set by creator */ + + Op->Asl.AmlOpcodeLength = 0; + return; + + default: + + break; + } + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_DEFINITION_BLOCK: + + Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength; + break; + + case PARSEOP_NAMESEG: + + Op->Asl.AmlOpcodeLength = 0; + Op->Asl.AmlLength = 4; + Op->Asl.ExternalName = Op->Asl.Value.String; + break; + + case PARSEOP_NAMESTRING: + case PARSEOP_METHODCALL: + + if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED) + { + break; + } + + Op->Asl.AmlOpcodeLength = 0; + Status = UtInternalizeName (Op->Asl.Value.String, &Buffer); + if (ACPI_FAILURE (Status)) + { + DbgPrint (ASL_DEBUG_OUTPUT, + "Failure from internalize name %X\n", Status); + break; + } + + Op->Asl.ExternalName = Op->Asl.Value.String; + Op->Asl.Value.String = Buffer; + Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED; + Op->Asl.AmlLength = strlen (Buffer); + + /* + * Check for single backslash reference to root, + * make it a null terminated string in the AML + */ + if (Op->Asl.AmlLength == 1) + { + Op->Asl.AmlLength = 2; + } + break; + + case PARSEOP_STRING_LITERAL: + + Op->Asl.AmlOpcodeLength = 1; + + /* Get null terminator */ + + Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1; + break; + + case PARSEOP_PACKAGE_LENGTH: + + Op->Asl.AmlOpcodeLength = 0; + Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op, + (UINT32) Op->Asl.Value.Integer); + break; + + case PARSEOP_RAW_DATA: + + Op->Asl.AmlOpcodeLength = 0; + break; + + case PARSEOP_DEFAULT_ARG: + case PARSEOP_EXTERNAL: + case PARSEOP_INCLUDE: + case PARSEOP_INCLUDE_END: + + /* Ignore the "default arg" nodes, they are extraneous at this point */ + + break; + + default: + + CgGenerateAmlOpcodeLength (Op); + break; + } +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: LnAdjustLengthToRoot + * + * PARAMETERS: Op - Node whose Length was changed + * + * RETURN: None. + * + * DESCRIPTION: Change the Subtree length of the given node, and bubble the + * change all the way up to the root node. This allows for + * last second changes to a package length (for example, if the + * package length encoding gets shorter or longer.) + * + ******************************************************************************/ + +void +LnAdjustLengthToRoot ( + ACPI_PARSE_OBJECT *SubtreeOp, + UINT32 LengthDelta) +{ + ACPI_PARSE_OBJECT *Op; + + + /* Adjust all subtree lengths up to the root */ + + Op = SubtreeOp->Asl.Parent; + while (Op) + { + Op->Asl.AmlSubtreeLength -= LengthDelta; + Op = Op->Asl.Parent; + } + + /* Adjust the global table length */ + + Gbl_TableLength -= LengthDelta; +} +#endif diff --git a/third_party/lib/acpica/source/compiler/asllisting.c b/third_party/lib/acpica/source/compiler/asllisting.c new file mode 100644 index 000000000..4923b7374 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asllisting.c @@ -0,0 +1,712 @@ +/****************************************************************************** + * + * Module Name: asllisting - Listing file generation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" +#include "acparser.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asllisting") + + +/* Local prototypes */ + +static void +LsGenerateListing ( + UINT32 FileId); + +static ACPI_STATUS +LsAmlListingWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +LsTreeWriteWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static void +LsWriteNodeToListing ( + ACPI_PARSE_OBJECT *Op, + UINT32 FileId); + +static void +LsFinishSourceListing ( + UINT32 FileId); + + +/******************************************************************************* + * + * FUNCTION: LsDoListings + * + * PARAMETERS: None. Examines the various output file global flags. + * + * RETURN: None + * + * DESCRIPTION: Generate all requested listing files. + * + ******************************************************************************/ + +void +LsDoListings ( + void) +{ + + if (Gbl_C_OutputFlag) + { + LsGenerateListing (ASL_FILE_C_SOURCE_OUTPUT); + } + + if (Gbl_ListingFlag) + { + LsGenerateListing (ASL_FILE_LISTING_OUTPUT); + } + + if (Gbl_AsmOutputFlag) + { + LsGenerateListing (ASL_FILE_ASM_SOURCE_OUTPUT); + } + + if (Gbl_C_IncludeOutputFlag) + { + LsGenerateListing (ASL_FILE_C_INCLUDE_OUTPUT); + } + + if (Gbl_AsmIncludeOutputFlag) + { + LsGenerateListing (ASL_FILE_ASM_INCLUDE_OUTPUT); + } + + if (Gbl_C_OffsetTableFlag) + { + LsGenerateListing (ASL_FILE_C_OFFSET_OUTPUT); + } +} + + +/******************************************************************************* + * + * FUNCTION: LsGenerateListing + * + * PARAMETERS: FileId - ID of listing file + * + * RETURN: None + * + * DESCRIPTION: Generate a listing file. This can be one of the several types + * of "listings" supported. + * + ******************************************************************************/ + +static void +LsGenerateListing ( + UINT32 FileId) +{ + + /* Start at the beginning of both the source and AML files */ + + FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0); + FlSeekFile (ASL_FILE_AML_OUTPUT, 0); + Gbl_SourceLine = 0; + Gbl_CurrentHexColumn = 0; + LsPushNode (Gbl_Files[ASL_FILE_INPUT].Filename); + + if (FileId == ASL_FILE_C_OFFSET_OUTPUT) + { + Gbl_CurrentAmlOffset = 0; + + /* Offset table file has a special header and footer */ + + LsDoOffsetTableHeader (FileId); + + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, LsAmlOffsetWalk, + NULL, (void *) ACPI_TO_POINTER (FileId)); + LsDoOffsetTableFooter (FileId); + return; + } + + /* Process all parse nodes */ + + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, LsAmlListingWalk, + NULL, (void *) ACPI_TO_POINTER (FileId)); + + /* Final processing */ + + LsFinishSourceListing (FileId); +} + + +/******************************************************************************* + * + * FUNCTION: LsAmlListingWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Process one node during a listing file generation. + * + ******************************************************************************/ + +static ACPI_STATUS +LsAmlListingWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + UINT8 FileByte; + UINT32 i; + UINT32 FileId = (UINT32) ACPI_TO_INTEGER (Context); + + + LsWriteNodeToListing (Op, FileId); + + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DATA) + { + /* Buffer is a resource template, don't dump the data all at once */ + + return (AE_OK); + } + + if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) || + (FileId == ASL_FILE_C_INCLUDE_OUTPUT)) + { + return (AE_OK); + } + + /* Write the hex bytes to the listing file(s) (if requested) */ + + for (i = 0; i < Op->Asl.FinalAmlLength; i++) + { + if (ACPI_FAILURE (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1))) + { + FlFileError (ASL_FILE_AML_OUTPUT, ASL_MSG_READ); + AslAbort (); + } + + LsWriteListingHexBytes (&FileByte, 1, FileId); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LsDumpParseTree, LsTreeWriteWalk + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump entire parse tree, for compiler debug only + * + ******************************************************************************/ + +void +LsDumpParseTree ( + void) +{ + + if (!Gbl_DebugFlag) + { + return; + } + + DbgPrint (ASL_TREE_OUTPUT, "\nOriginal parse tree from parser:\n\n"); + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + LsTreeWriteWalk, NULL, NULL); +} + + +static ACPI_STATUS +LsTreeWriteWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + /* Debug output */ + + DbgPrint (ASL_TREE_OUTPUT, + "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level); + + UtPrintFormattedName (Op->Asl.ParseOpcode, Level); + + if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) + { + DbgPrint (ASL_TREE_OUTPUT, + "%10.4s ", Op->Asl.Value.Name); + } + else if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || + (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) + { + DbgPrint (ASL_TREE_OUTPUT, + "%10.32s ", Op->Asl.Value.String); + } + else if (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) + { + DbgPrint (ASL_TREE_OUTPUT, + "Open: %s\n", Op->Asl.Value.String); + return (AE_OK); + } + else if (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END) + { + DbgPrint (ASL_TREE_OUTPUT, + "Close: %s\n", Op->Asl.Filename); + return (AE_OK); + } + else + { + DbgPrint (ASL_TREE_OUTPUT, " "); + } + + DbgPrint (ASL_TREE_OUTPUT, " (%.4X) Flags %8.8X", + Op->Asl.ParseOpcode, Op->Asl.CompileFlags); + TrPrintNodeCompileFlags (Op->Asl.CompileFlags); + DbgPrint (ASL_TREE_OUTPUT, "\n"); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LsWriteNodeToListing + * + * PARAMETERS: Op - Parse node to write to the listing file. + * FileId - ID of current listing file + * + * RETURN: None. + * + * DESCRIPTION: Write "a node" to the listing file. This means to + * 1) Write out all of the source text associated with the node + * 2) Write out all of the AML bytes associated with the node + * 3) Write any compiler exceptions associated with the node + * + ******************************************************************************/ + +static void +LsWriteNodeToListing ( + ACPI_PARSE_OBJECT *Op, + UINT32 FileId) +{ + const ACPI_OPCODE_INFO *OpInfo; + UINT32 OpClass; + char *Pathname; + UINT32 Length; + UINT32 i; + + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + OpClass = OpInfo->Class; + + /* TBD: clean this up with a single flag that says: + * I start a named output block + */ + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_DEFINITION_BLOCK: + case PARSEOP_METHODCALL: + case PARSEOP_INCLUDE: + case PARSEOP_INCLUDE_END: + case PARSEOP_DEFAULT_ARG: + + break; + + default: + + switch (OpClass) + { + case AML_CLASS_NAMED_OBJECT: + + switch (Op->Asl.AmlOpcode) + { + case AML_SCOPE_OP: + case AML_ALIAS_OP: + + break; + + default: + + if (Op->Asl.ExternalName) + { + LsFlushListingBuffer (FileId); + FlPrintFile (FileId, " };\n"); + } + break; + } + break; + + default: + + /* Don't care about other objects */ + + break; + } + break; + } + } + + /* These cases do not have a corresponding AML opcode */ + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_DEFINITION_BLOCK: + + LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine, FileId); + + /* Use the table Signature and TableId to build a unique name */ + + switch (FileId) + { + case ASL_FILE_ASM_SOURCE_OUTPUT: + + FlPrintFile (FileId, + "%s_%s_Header \\\n", + Gbl_TableSignature, Gbl_TableId); + break; + + case ASL_FILE_C_SOURCE_OUTPUT: + + FlPrintFile (FileId, + " unsigned char %s_%s_Header [] =\n {\n", + Gbl_TableSignature, Gbl_TableId); + break; + + case ASL_FILE_ASM_INCLUDE_OUTPUT: + + FlPrintFile (FileId, + "extrn %s_%s_Header : byte\n", + Gbl_TableSignature, Gbl_TableId); + break; + + case ASL_FILE_C_INCLUDE_OUTPUT: + + FlPrintFile (FileId, + "extern unsigned char %s_%s_Header [];\n", + Gbl_TableSignature, Gbl_TableId); + break; + + default: + break; + } + + return; + + + case PARSEOP_METHODCALL: + + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber, + FileId); + return; + + + case PARSEOP_INCLUDE: + + /* Flush everything up to and including the include source line */ + + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber, + FileId); + + /* Create a new listing node and push it */ + + LsPushNode (Op->Asl.Value.String); + return; + + + case PARSEOP_INCLUDE_END: + + /* Flush out the rest of the include file */ + + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber, + FileId); + + /* Pop off this listing node and go back to the parent file */ + + (void) LsPopNode (); + return; + + + case PARSEOP_DEFAULT_ARG: + + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC) + { + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.EndLogicalLine, + FileId); + } + return; + + + default: + + /* All other opcodes have an AML opcode */ + + break; + } + + /* + * Otherwise, we look at the AML opcode because we can + * switch on the opcode type, getting an entire class + * at once + */ + switch (OpClass) + { + case AML_CLASS_ARGUMENT: /* argument type only */ + case AML_CLASS_INTERNAL: + + break; + + case AML_CLASS_NAMED_OBJECT: + + switch (Op->Asl.AmlOpcode) + { + case AML_FIELD_OP: + case AML_INDEX_FIELD_OP: + case AML_BANK_FIELD_OP: + /* + * For fields, we want to dump all the AML after the + * entire definition + */ + LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine, + FileId); + break; + + case AML_NAME_OP: + + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC) + { + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber, + FileId); + } + else + { + /* + * For fields, we want to dump all the AML after the + * entire definition + */ + LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine, + FileId); + } + break; + + default: + + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber, + FileId); + break; + } + + switch (Op->Asl.AmlOpcode) + { + case AML_SCOPE_OP: + case AML_ALIAS_OP: + + /* These opcodes do not declare a new object, ignore them */ + + break; + + default: + + /* All other named object opcodes come here */ + + switch (FileId) + { + case ASL_FILE_ASM_SOURCE_OUTPUT: + case ASL_FILE_C_SOURCE_OUTPUT: + case ASL_FILE_ASM_INCLUDE_OUTPUT: + case ASL_FILE_C_INCLUDE_OUTPUT: + /* + * For named objects, we will create a valid symbol so that the + * AML code can be referenced from C or ASM + */ + if (Op->Asl.ExternalName) + { + /* Get the full pathname associated with this node */ + + Pathname = AcpiNsGetExternalPathname (Op->Asl.Node); + Length = strlen (Pathname); + if (Length >= 4) + { + /* Convert all dots in the path to underscores */ + + for (i = 0; i < Length; i++) + { + if (Pathname[i] == '.') + { + Pathname[i] = '_'; + } + } + + /* Create the appropriate symbol in the output file */ + + switch (FileId) + { + case ASL_FILE_ASM_SOURCE_OUTPUT: + + FlPrintFile (FileId, + "%s_%s_%s \\\n", + Gbl_TableSignature, Gbl_TableId, &Pathname[1]); + break; + + case ASL_FILE_C_SOURCE_OUTPUT: + + FlPrintFile (FileId, + " unsigned char %s_%s_%s [] =\n {\n", + Gbl_TableSignature, Gbl_TableId, &Pathname[1]); + break; + + case ASL_FILE_ASM_INCLUDE_OUTPUT: + + FlPrintFile (FileId, + "extrn %s_%s_%s : byte\n", + Gbl_TableSignature, Gbl_TableId, &Pathname[1]); + break; + + case ASL_FILE_C_INCLUDE_OUTPUT: + + FlPrintFile (FileId, + "extern unsigned char %s_%s_%s [];\n", + Gbl_TableSignature, Gbl_TableId, &Pathname[1]); + break; + + default: + break; + } + } + + ACPI_FREE (Pathname); + } + break; + + default: + + /* Nothing to do for listing file */ + + break; + } + } + break; + + case AML_CLASS_EXECUTE: + case AML_CLASS_CREATE: + default: + + if ((Op->Asl.ParseOpcode == PARSEOP_BUFFER) && + (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC)) + { + return; + } + + LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber, + FileId); + break; + + case AML_CLASS_UNKNOWN: + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: LsFinishSourceListing + * + * PARAMETERS: FileId - ID of current listing file. + * + * RETURN: None + * + * DESCRIPTION: Cleanup routine for the listing file. Flush the hex AML + * listing buffer, and flush out any remaining lines in the + * source input file. + * + ******************************************************************************/ + +static void +LsFinishSourceListing ( + UINT32 FileId) +{ + + if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) || + (FileId == ASL_FILE_C_INCLUDE_OUTPUT)) + { + return; + } + + LsFlushListingBuffer (FileId); + Gbl_CurrentAmlOffset = 0; + + /* Flush any remaining text in the source file */ + + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + FlPrintFile (FileId, " /*\n"); + } + + while (LsWriteOneSourceLine (FileId)) + { ; } + + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + FlPrintFile (FileId, "\n */\n };\n"); + } + + FlPrintFile (FileId, "\n"); + + if (FileId == ASL_FILE_LISTING_OUTPUT) + { + /* Print a summary of the compile exceptions */ + + FlPrintFile (FileId, "\n\nSummary of errors and warnings\n\n"); + AePrintErrorLog (FileId); + FlPrintFile (FileId, "\n"); + UtDisplaySummary (FileId); + FlPrintFile (FileId, "\n"); + } +} diff --git a/third_party/lib/acpica/source/compiler/asllistsup.c b/third_party/lib/acpica/source/compiler/asllistsup.c new file mode 100644 index 000000000..daae21b95 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asllistsup.c @@ -0,0 +1,711 @@ +/****************************************************************************** + * + * Module Name: asllistsup - Listing file support utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslistsup") + + +/******************************************************************************* + * + * FUNCTION: LsDumpAscii + * + * PARAMETERS: FileId - ID of current listing file + * Count - Number of bytes to convert + * Buffer - Buffer of bytes to convert + * + * RETURN: None + * + * DESCRIPTION: Convert hex bytes to ascii + * + ******************************************************************************/ + +void +LsDumpAscii ( + UINT32 FileId, + UINT32 Count, + UINT8 *Buffer) +{ + UINT8 BufChar; + UINT32 i; + + + FlPrintFile (FileId, " \""); + for (i = 0; i < Count; i++) + { + BufChar = Buffer[i]; + if (isprint (BufChar)) + { + FlPrintFile (FileId, "%c", BufChar); + } + else + { + /* Not a printable character, just put out a dot */ + + FlPrintFile (FileId, "."); + } + } + + FlPrintFile (FileId, "\""); +} + + +/******************************************************************************* + * + * FUNCTION: LsDumpAsciiInComment + * + * PARAMETERS: FileId - ID of current listing file + * Count - Number of bytes to convert + * Buffer - Buffer of bytes to convert + * + * RETURN: None + * + * DESCRIPTION: Convert hex bytes to ascii + * + ******************************************************************************/ + +void +LsDumpAsciiInComment ( + UINT32 FileId, + UINT32 Count, + UINT8 *Buffer) +{ + UINT8 BufChar = 0; + UINT8 LastChar; + UINT32 i; + + + FlPrintFile (FileId, " \""); + for (i = 0; i < Count; i++) + { + LastChar = BufChar; + BufChar = Buffer[i]; + + if (isprint (BufChar)) + { + /* Handle embedded C comment sequences */ + + if (((LastChar == '*') && (BufChar == '/')) || + ((LastChar == '/') && (BufChar == '*'))) + { + /* Insert a space to break the sequence */ + + FlPrintFile (FileId, ".", BufChar); + } + + FlPrintFile (FileId, "%c", BufChar); + } + else + { + /* Not a printable character, just put out a dot */ + + FlPrintFile (FileId, "."); + } + } + + FlPrintFile (FileId, "\""); +} + + +/******************************************************************************* + * + * FUNCTION: LsCheckException + * + * PARAMETERS: LineNumber - Current logical (cumulative) line # + * FileId - ID of output listing file + * + * RETURN: None + * + * DESCRIPTION: Check if there is an exception for this line, and if there is, + * put it in the listing immediately. Handles multiple errors + * per line. Gbl_NextError points to the next error in the + * sorted (by line #) list of compile errors/warnings. + * + ******************************************************************************/ + +void +LsCheckException ( + UINT32 LineNumber, + UINT32 FileId) +{ + + if ((!Gbl_NextError) || + (LineNumber < Gbl_NextError->LogicalLineNumber )) + { + return; + } + + /* Handle multiple errors per line */ + + if (FileId == ASL_FILE_LISTING_OUTPUT) + { + while (Gbl_NextError && + (LineNumber >= Gbl_NextError->LogicalLineNumber)) + { + AePrintException (FileId, Gbl_NextError, "\n[****iasl****]\n"); + Gbl_NextError = Gbl_NextError->Next; + } + + FlPrintFile (FileId, "\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: LsWriteListingHexBytes + * + * PARAMETERS: Buffer - AML code buffer + * Length - Number of AML bytes to write + * FileId - ID of current listing file. + * + * RETURN: None + * + * DESCRIPTION: Write the contents of the AML buffer to the listing file via + * the listing buffer. The listing buffer is flushed every 16 + * AML bytes. + * + ******************************************************************************/ + +void +LsWriteListingHexBytes ( + UINT8 *Buffer, + UINT32 Length, + UINT32 FileId) +{ + UINT32 i; + + + /* Transfer all requested bytes */ + + for (i = 0; i < Length; i++) + { + /* Print line header when buffer is empty */ + + if (Gbl_CurrentHexColumn == 0) + { + if (Gbl_HasIncludeFiles) + { + FlPrintFile (FileId, "%*s", 10, " "); + } + + switch (FileId) + { + case ASL_FILE_LISTING_OUTPUT: + + FlPrintFile (FileId, "%8.8X%s", Gbl_CurrentAmlOffset, + ASL_LISTING_LINE_PREFIX); + break; + + case ASL_FILE_ASM_SOURCE_OUTPUT: + + FlPrintFile (FileId, " db "); + break; + + case ASL_FILE_C_SOURCE_OUTPUT: + + FlPrintFile (FileId, " "); + break; + + default: + + /* No other types supported */ + + return; + } + } + + /* Transfer AML byte and update counts */ + + Gbl_AmlBuffer[Gbl_CurrentHexColumn] = Buffer[i]; + + Gbl_CurrentHexColumn++; + Gbl_CurrentAmlOffset++; + + /* Flush buffer when it is full */ + + if (Gbl_CurrentHexColumn >= HEX_LISTING_LINE_SIZE) + { + LsFlushListingBuffer (FileId); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: LsWriteSourceLines + * + * PARAMETERS: ToLineNumber - + * ToLogicalLineNumber - Write up to this source line number + * FileId - ID of current listing file + * + * RETURN: None + * + * DESCRIPTION: Read then write source lines to the listing file until we have + * reached the specified logical (cumulative) line number. This + * automatically echos out comment blocks and other non-AML + * generating text until we get to the actual AML-generating line + * of ASL code specified by the logical line number. + * + ******************************************************************************/ + +void +LsWriteSourceLines ( + UINT32 ToLineNumber, + UINT32 ToLogicalLineNumber, + UINT32 FileId) +{ + + /* Nothing to do for these file types */ + + if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) || + (FileId == ASL_FILE_C_INCLUDE_OUTPUT)) + { + return; + } + + Gbl_CurrentLine = ToLogicalLineNumber; + + /* Flush any hex bytes remaining from the last opcode */ + + LsFlushListingBuffer (FileId); + + /* Read lines and write them as long as we are not caught up */ + + if (Gbl_SourceLine < Gbl_CurrentLine) + { + /* + * If we just completed writing some AML hex bytes, output a linefeed + * to add some whitespace for readability. + */ + if (Gbl_HexBytesWereWritten) + { + FlPrintFile (FileId, "\n"); + Gbl_HexBytesWereWritten = FALSE; + } + + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + FlPrintFile (FileId, " /*\n"); + } + + /* Write one line at a time until we have reached the target line # */ + + while ((Gbl_SourceLine < Gbl_CurrentLine) && + LsWriteOneSourceLine (FileId)) + { ; } + + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + FlPrintFile (FileId, " */"); + } + + FlPrintFile (FileId, "\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: LsWriteOneSourceLine + * + * PARAMETERS: FileId - ID of current listing file + * + * RETURN: FALSE on EOF (input source file), TRUE otherwise + * + * DESCRIPTION: Read one line from the input source file and echo it to the + * listing file, prefixed with the line number, and if the source + * file contains include files, prefixed with the current filename + * + ******************************************************************************/ + +UINT32 +LsWriteOneSourceLine ( + UINT32 FileId) +{ + UINT8 FileByte; + UINT32 Column = 0; + UINT32 Index = 16; + BOOLEAN StartOfLine = FALSE; + BOOLEAN ProcessLongLine = FALSE; + + + Gbl_SourceLine++; + Gbl_ListingNode->LineNumber++; + + /* Ignore lines that are completely blank (but count the line above) */ + + if (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) != AE_OK) + { + return (0); + } + if (FileByte == '\n') + { + return (1); + } + + /* + * This is a non-empty line, we will print the entire line with + * the line number and possibly other prefixes and transforms. + */ + + /* Line prefixes for special files, C and ASM output */ + + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + FlPrintFile (FileId, " *"); + } + if (FileId == ASL_FILE_ASM_SOURCE_OUTPUT) + { + FlPrintFile (FileId, "; "); + } + + if (Gbl_HasIncludeFiles) + { + /* + * This file contains "include" statements, print the current + * filename and line number within the current file + */ + FlPrintFile (FileId, "%12s %5d%s", + Gbl_ListingNode->Filename, Gbl_ListingNode->LineNumber, + ASL_LISTING_LINE_PREFIX); + } + else + { + /* No include files, just print the line number */ + + FlPrintFile (FileId, "%8u%s", Gbl_SourceLine, + ASL_LISTING_LINE_PREFIX); + } + + /* Read the rest of this line (up to a newline or EOF) */ + + do + { + if (FileId == ASL_FILE_C_SOURCE_OUTPUT) + { + if (FileByte == '/') + { + FileByte = '*'; + } + } + + /* Split long input lines for readability in the listing */ + + Column++; + if (Column >= 128) + { + if (!ProcessLongLine) + { + if ((FileByte != '}') && + (FileByte != '{')) + { + goto WriteByte; + } + + ProcessLongLine = TRUE; + } + + if (FileByte == '{') + { + FlPrintFile (FileId, "\n%*s{\n", Index, " "); + StartOfLine = TRUE; + Index += 4; + continue; + } + + else if (FileByte == '}') + { + if (!StartOfLine) + { + FlPrintFile (FileId, "\n"); + } + + StartOfLine = TRUE; + Index -= 4; + FlPrintFile (FileId, "%*s}\n", Index, " "); + continue; + } + + /* Ignore spaces/tabs at the start of line */ + + else if ((FileByte == ' ') && StartOfLine) + { + continue; + } + + else if (StartOfLine) + { + StartOfLine = FALSE; + FlPrintFile (FileId, "%*s", Index, " "); + } + +WriteByte: + FlWriteFile (FileId, &FileByte, 1); + if (FileByte == '\n') + { + /* + * This line has been completed. + * Check if an error occurred on this source line during the compile. + * If so, we print the error message after the source line. + */ + LsCheckException (Gbl_SourceLine, FileId); + return (1); + } + } + else + { + FlWriteFile (FileId, &FileByte, 1); + if (FileByte == '\n') + { + /* + * This line has been completed. + * Check if an error occurred on this source line during the compile. + * If so, we print the error message after the source line. + */ + LsCheckException (Gbl_SourceLine, FileId); + return (1); + } + } + + } while (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) == AE_OK); + + /* EOF on the input file was reached */ + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: LsFlushListingBuffer + * + * PARAMETERS: FileId - ID of the listing file + * + * RETURN: None + * + * DESCRIPTION: Flush out the current contents of the 16-byte hex AML code + * buffer. Usually called at the termination of a single line + * of source code or when the buffer is full. + * + ******************************************************************************/ + +void +LsFlushListingBuffer ( + UINT32 FileId) +{ + UINT32 i; + + + if (Gbl_CurrentHexColumn == 0) + { + return; + } + + /* Write the hex bytes */ + + switch (FileId) + { + case ASL_FILE_LISTING_OUTPUT: + + for (i = 0; i < Gbl_CurrentHexColumn; i++) + { + FlPrintFile (FileId, "%2.2X ", Gbl_AmlBuffer[i]); + } + + for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 3); i++) + { + FlWriteFile (FileId, ".", 1); + } + + /* Write the ASCII character associated with each of the bytes */ + + LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer); + break; + + + case ASL_FILE_ASM_SOURCE_OUTPUT: + + for (i = 0; i < Gbl_CurrentHexColumn; i++) + { + if (i > 0) + { + FlPrintFile (FileId, ","); + } + + FlPrintFile (FileId, "0%2.2Xh", Gbl_AmlBuffer[i]); + } + + for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++) + { + FlWriteFile (FileId, " ", 1); + } + + FlPrintFile (FileId, " ;%8.8X", + Gbl_CurrentAmlOffset - HEX_LISTING_LINE_SIZE); + + /* Write the ASCII character associated with each of the bytes */ + + LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer); + break; + + + case ASL_FILE_C_SOURCE_OUTPUT: + + for (i = 0; i < Gbl_CurrentHexColumn; i++) + { + FlPrintFile (FileId, "0x%2.2X,", Gbl_AmlBuffer[i]); + } + + /* Pad hex output with spaces if line is shorter than max line size */ + + for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++) + { + FlWriteFile (FileId, " ", 1); + } + + /* AML offset for the start of the line */ + + FlPrintFile (FileId, " /* %8.8X", + Gbl_CurrentAmlOffset - Gbl_CurrentHexColumn); + + /* Write the ASCII character associated with each of the bytes */ + + LsDumpAsciiInComment (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer); + FlPrintFile (FileId, " */"); + break; + + default: + + /* No other types supported */ + + return; + } + + FlPrintFile (FileId, "\n"); + + Gbl_CurrentHexColumn = 0; + Gbl_HexBytesWereWritten = TRUE; +} + + +/******************************************************************************* + * + * FUNCTION: LsPushNode + * + * PARAMETERS: Filename - Pointer to the include filename + * + * RETURN: None + * + * DESCRIPTION: Push a listing node on the listing/include file stack. This + * stack enables tracking of include files (infinitely nested) + * and resumption of the listing of the parent file when the + * include file is finished. + * + ******************************************************************************/ + +void +LsPushNode ( + char *Filename) +{ + ASL_LISTING_NODE *Lnode; + + + /* Create a new node */ + + Lnode = UtLocalCalloc (sizeof (ASL_LISTING_NODE)); + + /* Initialize */ + + Lnode->Filename = Filename; + Lnode->LineNumber = 0; + + /* Link (push) */ + + Lnode->Next = Gbl_ListingNode; + Gbl_ListingNode = Lnode; +} + + +/******************************************************************************* + * + * FUNCTION: LsPopNode + * + * PARAMETERS: None + * + * RETURN: List head after current head is popped off + * + * DESCRIPTION: Pop the current head of the list, free it, and return the + * next node on the stack (the new current node). + * + ******************************************************************************/ + +ASL_LISTING_NODE * +LsPopNode ( + void) +{ + ASL_LISTING_NODE *Lnode; + + + /* Just grab the node at the head of the list */ + + Lnode = Gbl_ListingNode; + if ((!Lnode) || + (!Lnode->Next)) + { + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, NULL, + "Could not pop empty listing stack"); + return (Gbl_ListingNode); + } + + Gbl_ListingNode = Lnode->Next; + ACPI_FREE (Lnode); + + /* New "Current" node is the new head */ + + return (Gbl_ListingNode); +} diff --git a/third_party/lib/acpica/source/compiler/aslload.c b/third_party/lib/acpica/source/compiler/aslload.c new file mode 100644 index 000000000..f36bee8f3 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslload.c @@ -0,0 +1,965 @@ +/****************************************************************************** + * + * Module Name: dswload - Dispatcher namespace load callbacks + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" + +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslload") + +/* Local prototypes */ + +static ACPI_STATUS +LdLoadFieldElements ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +static ACPI_STATUS +LdLoadResourceElements ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +static ACPI_STATUS +LdNamespace1Begin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +LdNamespace2Begin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +LdCommonNamespaceEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/******************************************************************************* + * + * FUNCTION: LdLoadNamespace + * + * PARAMETERS: RootOp - Root of the parse tree + * + * RETURN: Status + * + * DESCRIPTION: Perform a walk of the parse tree that in turn loads all of the + * named ASL/AML objects into the namespace. The namespace is + * constructed in order to resolve named references and references + * to named fields within resource templates/descriptors. + * + ******************************************************************************/ + +ACPI_STATUS +LdLoadNamespace ( + ACPI_PARSE_OBJECT *RootOp) +{ + ACPI_WALK_STATE *WalkState; + + + DbgPrint (ASL_DEBUG_OUTPUT, "\nCreating namespace\n\n"); + + /* Create a new walk state */ + + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + if (!WalkState) + { + return (AE_NO_MEMORY); + } + + /* Walk the entire parse tree, first pass */ + + TrWalkParseTree (RootOp, ASL_WALK_VISIT_TWICE, LdNamespace1Begin, + LdCommonNamespaceEnd, WalkState); + + /* Second pass to handle forward references */ + + TrWalkParseTree (RootOp, ASL_WALK_VISIT_TWICE, LdNamespace2Begin, + LdCommonNamespaceEnd, WalkState); + + /* Dump the namespace if debug is enabled */ + + AcpiNsDumpTables (ACPI_NS_ALL, ACPI_UINT32_MAX); + ACPI_FREE (WalkState); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LdLoadFieldElements + * + * PARAMETERS: Op - Parent node (Field) + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Enter the named elements of the field (children of the parent) + * into the namespace. + * + ******************************************************************************/ + +static ACPI_STATUS +LdLoadFieldElements ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *Child = NULL; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Get the first named field element */ + + switch (Op->Asl.AmlOpcode) + { + case AML_BANK_FIELD_OP: + + Child = UtGetArg (Op, 6); + break; + + case AML_INDEX_FIELD_OP: + + Child = UtGetArg (Op, 5); + break; + + case AML_FIELD_OP: + + Child = UtGetArg (Op, 4); + break; + + default: + + /* No other opcodes should arrive here */ + + return (AE_BAD_PARAMETER); + } + + /* Enter all elements into the namespace */ + + while (Child) + { + switch (Child->Asl.AmlOpcode) + { + case AML_INT_RESERVEDFIELD_OP: + case AML_INT_ACCESSFIELD_OP: + case AML_INT_CONNECTION_OP: + break; + + default: + + Status = AcpiNsLookup (WalkState->ScopeInfo, + Child->Asl.Value.String, + ACPI_TYPE_LOCAL_REGION_FIELD, + ACPI_IMODE_LOAD_PASS1, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND, NULL, &Node); + if (ACPI_FAILURE (Status)) + { + if (Status != AE_ALREADY_EXISTS) + { + AslError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, Child, + Child->Asl.Value.String); + return (Status); + } + + /* + * The name already exists in this scope + * But continue processing the elements + */ + AslError (ASL_ERROR, ASL_MSG_NAME_EXISTS, Child, + Child->Asl.Value.String); + } + else + { + Child->Asl.Node = Node; + Node->Op = Child; + } + break; + } + + Child = Child->Asl.Next; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LdLoadResourceElements + * + * PARAMETERS: Op - Parent node (Resource Descriptor) + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Enter the named elements of the resource descriptor (children + * of the parent) into the namespace. + * + * NOTE: In the real AML namespace, these named elements never exist. But + * we simply use the namespace here as a symbol table so we can look + * them up as they are referenced. + * + ******************************************************************************/ + +static ACPI_STATUS +LdLoadResourceElements ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *InitializerOp = NULL; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* + * Enter the resource name into the namespace. Name must not already exist. + * This opens a scope, so later field names are guaranteed to be new/unique. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Op->Asl.Namepath, + ACPI_TYPE_LOCAL_RESOURCE, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_NO_UPSEARCH | ACPI_NS_ERROR_IF_FOUND, + WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_ALREADY_EXISTS) + { + /* Actual node causing the error was saved in ParentMethod */ + + AslError (ASL_ERROR, ASL_MSG_NAME_EXISTS, + (ACPI_PARSE_OBJECT *) Op->Asl.ParentMethod, Op->Asl.Namepath); + return (AE_OK); + } + return (Status); + } + + Node->Value = (UINT32) Op->Asl.Value.Integer; + Node->Op = Op; + Op->Asl.Node = Node; + + /* + * Now enter the predefined fields, for easy lookup when referenced + * by the source ASL + */ + InitializerOp = ASL_GET_CHILD_NODE (Op); + while (InitializerOp) + { + if (InitializerOp->Asl.ExternalName) + { + Status = AcpiNsLookup (WalkState->ScopeInfo, + InitializerOp->Asl.ExternalName, + ACPI_TYPE_LOCAL_RESOURCE_FIELD, + ACPI_IMODE_LOAD_PASS1, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &Node); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Store the field offset and length in the namespace node + * so it can be used when the field is referenced + */ + Node->Value = InitializerOp->Asl.Value.Tag.BitOffset; + Node->Length = InitializerOp->Asl.Value.Tag.BitLength; + InitializerOp->Asl.Node = Node; + Node->Op = InitializerOp; + } + + InitializerOp = ASL_GET_PEER_NODE (InitializerOp); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LdNamespace1Begin + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the parse tree walk. If this + * is a named AML opcode, enter into the namespace + * + ******************************************************************************/ + +static ACPI_STATUS +LdNamespace1Begin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *MethodOp; + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + ACPI_OBJECT_TYPE ActualObjectType = ACPI_TYPE_ANY; + char *Path; + UINT32 Flags = ACPI_NS_NO_UPSEARCH; + ACPI_PARSE_OBJECT *Arg; + UINT32 i; + BOOLEAN ForceNewScope = FALSE; + + + ACPI_FUNCTION_NAME (LdNamespace1Begin); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op %p [%s]\n", + Op, Op->Asl.ParseOpName)); + + /* + * We are only interested in opcodes that have an associated name + * (or multiple names) + */ + switch (Op->Asl.AmlOpcode) + { + case AML_BANK_FIELD_OP: + case AML_INDEX_FIELD_OP: + case AML_FIELD_OP: + + Status = LdLoadFieldElements (Op, WalkState); + return (Status); + + case AML_INT_CONNECTION_OP: + + + if (Op->Asl.Child->Asl.AmlOpcode != AML_INT_NAMEPATH_OP) + { + break; + } + Arg = Op->Asl.Child; + + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Asl.ExternalName, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + break; + } + + if (Node->Type == ACPI_TYPE_BUFFER) + { + Arg->Asl.Node = Node; + + Arg = Node->Op->Asl.Child; /* Get namepath */ + Arg = Arg->Asl.Next; /* Get actual buffer */ + Arg = Arg->Asl.Child; /* Buffer length */ + Arg = Arg->Asl.Next; /* RAW_DATA buffer */ + } + break; + + default: + + /* All other opcodes go below */ + + break; + } + + /* Check if this object has already been installed in the namespace */ + + if (Op->Asl.Node) + { + return (AE_OK); + } + + Path = Op->Asl.Namepath; + if (!Path) + { + return (AE_OK); + } + + /* Map the raw opcode into an internal object type */ + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_NAME: + + Arg = Op->Asl.Child; /* Get the NameSeg/NameString node */ + Arg = Arg->Asl.Next; /* First peer is the object to be associated with the name */ + + /* + * If this name refers to a ResourceTemplate, we will need to open + * a new scope so that the resource subfield names can be entered into + * the namespace underneath this name + */ + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC) + { + ForceNewScope = TRUE; + } + + /* Get the data type associated with the named object, not the name itself */ + + /* Log2 loop to convert from Btype (binary) to Etype (encoded) */ + + ObjectType = 1; + for (i = 1; i < Arg->Asl.AcpiBtype; i *= 2) + { + ObjectType++; + } + break; + + + case PARSEOP_EXTERNAL: + /* + * "External" simply enters a name and type into the namespace. + * We must be careful to not open a new scope, however, no matter + * what type the external name refers to (e.g., a method) + * + * first child is name, next child is ObjectType + */ + ActualObjectType = (UINT8) Op->Asl.Child->Asl.Next->Asl.Value.Integer; + ObjectType = ACPI_TYPE_ANY; + + /* + * We will mark every new node along the path as "External". This + * allows some or all of the nodes to be created later in the ASL + * code. Handles cases like this: + * + * External (\_SB_.PCI0.ABCD, IntObj) + * Scope (_SB_) + * { + * Device (PCI0) + * { + * } + * } + * Method (X) + * { + * Store (\_SB_.PCI0.ABCD, Local0) + * } + */ + Flags |= ACPI_NS_EXTERNAL; + break; + + case PARSEOP_DEFAULT_ARG: + + if (Op->Asl.CompileFlags == NODE_IS_RESOURCE_DESC) + { + Status = LdLoadResourceElements (Op, WalkState); + return_ACPI_STATUS (Status); + } + + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + break; + + case PARSEOP_SCOPE: + /* + * The name referenced by Scope(Name) must already exist at this point. + * In other words, forward references for Scope() are not supported. + * The only real reason for this is that the MS interpreter cannot + * handle this case. Perhaps someday this case can go away. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + WalkState, &(Node)); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + /* The name was not found, go ahead and create it */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, + ACPI_TYPE_LOCAL_SCOPE, + ACPI_IMODE_LOAD_PASS1, Flags, + WalkState, &(Node)); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * However, this is an error -- primarily because the MS + * interpreter can't handle a forward reference from the + * Scope() operator. + */ + AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op, + Op->Asl.ExternalName); + AslError (ASL_ERROR, ASL_MSG_SCOPE_FWD_REF, Op, + Op->Asl.ExternalName); + goto FinishNode; + } + + AslCoreSubsystemError (Op, Status, + "Failure from namespace lookup", FALSE); + + return_ACPI_STATUS (Status); + } + else /* Status AE_OK */ + { + /* + * Do not allow references to external scopes from the DSDT. + * This is because the DSDT is always loaded first, and the + * external reference cannot be resolved -- causing a runtime + * error because Scope() must be resolved immediately. + * 10/2015. + */ + if ((Node->Flags & ANOBJ_IS_EXTERNAL) && + (ACPI_COMPARE_NAME (Gbl_TableSignature, "DSDT"))) + { + /* However, allowed if the reference is within a method */ + + MethodOp = Op->Asl.Parent; + while (MethodOp && + (MethodOp->Asl.ParseOpcode != PARSEOP_METHOD)) + { + MethodOp = MethodOp->Asl.Parent; + } + + if (!MethodOp) + { + /* Not in a control method, error */ + + AslError (ASL_ERROR, ASL_MSG_CROSS_TABLE_SCOPE, Op, NULL); + } + } + } + + /* We found a node with this name, now check the type */ + + switch (Node->Type) + { + case ACPI_TYPE_LOCAL_SCOPE: + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types - they all open a new scope */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + /* + * These types we will allow, but we will change the type. + * This enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + * + * Which is used to workaround the fact that the MS interpreter + * does not allow Scope() forward references. + */ + sprintf (MsgBuffer, "%s [%s], changing type to [Scope]", + Op->Asl.ExternalName, AcpiUtGetTypeName (Node->Type)); + AslError (ASL_REMARK, ASL_MSG_SCOPE_TYPE, Op, MsgBuffer); + + /* Switch the type to scope, open the new scope */ + + Node->Type = ACPI_TYPE_LOCAL_SCOPE; + Status = AcpiDsScopeStackPush (Node, ACPI_TYPE_LOCAL_SCOPE, + WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + break; + + default: + + /* All other types are an error */ + + sprintf (MsgBuffer, "%s [%s]", Op->Asl.ExternalName, + AcpiUtGetTypeName (Node->Type)); + AslError (ASL_ERROR, ASL_MSG_SCOPE_TYPE, Op, MsgBuffer); + + /* + * However, switch the type to be an actual scope so + * that compilation can continue without generating a whole + * cascade of additional errors. Open the new scope. + */ + Node->Type = ACPI_TYPE_LOCAL_SCOPE; + Status = AcpiDsScopeStackPush (Node, ACPI_TYPE_LOCAL_SCOPE, + WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + break; + } + + Status = AE_OK; + goto FinishNode; + + + default: + + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + break; + } + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Loading name: %s, (%s)\n", + Op->Asl.ExternalName, AcpiUtGetTypeName (ObjectType))); + + /* The name must not already exist */ + + Flags |= ACPI_NS_ERROR_IF_FOUND; + + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, + ACPI_IMODE_LOAD_PASS1, Flags, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_ALREADY_EXISTS) + { + /* The name already exists in this scope */ + + if (Node->Type == ACPI_TYPE_LOCAL_SCOPE) + { + /* Allow multiple references to the same scope */ + + Node->Type = (UINT8) ObjectType; + Status = AE_OK; + } + else if ((Node->Flags & ANOBJ_IS_EXTERNAL) && + (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL)) + { + /* + * Allow one create on an object or segment that was + * previously declared External + */ + Node->Flags &= ~ANOBJ_IS_EXTERNAL; + Node->Type = (UINT8) ObjectType; + + /* Just retyped a node, probably will need to open a scope */ + + if (AcpiNsOpensScope (ObjectType)) + { + Status = AcpiDsScopeStackPush (Node, ObjectType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + Status = AE_OK; + } + else if (!(Node->Flags & ANOBJ_IS_EXTERNAL) && + (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)) + { + /* + * Allow externals in same scope as the definition of the + * actual object. Similar to C. Allows multiple definition + * blocks that refer to each other in the same file. + */ + Status = AE_OK; + } + else + { + /* Valid error, object already exists */ + + AslError (ASL_ERROR, ASL_MSG_NAME_EXISTS, Op, + Op->Asl.ExternalName); + return_ACPI_STATUS (AE_OK); + } + } + else + { + AslCoreSubsystemError (Op, Status, + "Failure from namespace lookup", FALSE); + return_ACPI_STATUS (Status); + } + } + + if (ForceNewScope) + { + Status = AcpiDsScopeStackPush (Node, ObjectType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + +FinishNode: + /* + * Point the parse node to the new namespace node, and point + * the Node back to the original Parse node + */ + Op->Asl.Node = Node; + Node->Op = Op; + + /* Set the actual data type if appropriate (EXTERNAL term only) */ + + if (ActualObjectType != ACPI_TYPE_ANY) + { + Node->Type = (UINT8) ActualObjectType; + Node->Value = ASL_EXTERNAL_METHOD; + } + + if (Op->Asl.ParseOpcode == PARSEOP_METHOD) + { + /* + * Get the method argument count from "Extra" and save + * it in the namespace node + */ + Node->Value = (UINT32) Op->Asl.Extra; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: LdNamespace2Begin + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the pass 2 parse tree walk. + * Second pass resolves some forward references. + * + * Notes: + * Currently only needs to handle the Alias operator. + * Could be used to allow forward references from the Scope() operator, but + * the MS interpreter does not allow this, so this compiler does not either. + * + ******************************************************************************/ + +static ACPI_STATUS +LdNamespace2Begin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_OBJECT_TYPE ObjectType; + BOOLEAN ForceNewScope = FALSE; + ACPI_PARSE_OBJECT *Arg; + char *Path; + ACPI_NAMESPACE_NODE *TargetNode; + + + ACPI_FUNCTION_NAME (LdNamespace2Begin); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op %p [%s]\n", + Op, Op->Asl.ParseOpName)); + + + /* Ignore Ops with no namespace node */ + + Node = Op->Asl.Node; + if (!Node) + { + return (AE_OK); + } + + /* Get the type to determine if we should push the scope */ + + if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) && + (Op->Asl.CompileFlags == NODE_IS_RESOURCE_DESC)) + { + ObjectType = ACPI_TYPE_LOCAL_RESOURCE; + } + else + { + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + } + + /* Push scope for Resource Templates */ + + if (Op->Asl.ParseOpcode == PARSEOP_NAME) + { + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC) + { + ForceNewScope = TRUE; + } + } + + /* Push the scope stack */ + + if (ForceNewScope || AcpiNsOpensScope (ObjectType)) + { + Status = AcpiDsScopeStackPush (Node, ObjectType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + if (Op->Asl.ParseOpcode == PARSEOP_ALIAS) + { + /* Complete the alias node by getting and saving the target node */ + + /* First child is the alias target */ + + Arg = Op->Asl.Child; + + /* Get the target pathname */ + + Path = Arg->Asl.Namepath; + if (!Path) + { + Status = UtInternalizeName (Arg->Asl.ExternalName, &Path); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Get the NS node associated with the target. It must exist. */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &TargetNode); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op, + Op->Asl.ExternalName); + + /* + * The name was not found, go ahead and create it. + * This prevents more errors later. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, + ACPI_TYPE_ANY, + ACPI_IMODE_LOAD_PASS1, ACPI_NS_NO_UPSEARCH, + WalkState, &(Node)); + return (AE_OK); + } + + AslCoreSubsystemError (Op, Status, + "Failure from namespace lookup", FALSE); + return (AE_OK); + } + + /* Save the target node within the alias node */ + + Node->Object = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, TargetNode); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LdCommonNamespaceEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * We only need to worry about managing the scope stack here. + * + ******************************************************************************/ + +static ACPI_STATUS +LdCommonNamespaceEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; + ACPI_OBJECT_TYPE ObjectType; + BOOLEAN ForceNewScope = FALSE; + + + ACPI_FUNCTION_NAME (LdCommonNamespaceEnd); + + + /* We are only interested in opcodes that have an associated name */ + + if (!Op->Asl.Namepath) + { + return (AE_OK); + } + + /* Get the type to determine if we should pop the scope */ + + if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) && + (Op->Asl.CompileFlags == NODE_IS_RESOURCE_DESC)) + { + /* TBD: Merge into AcpiDsMapNamedOpcodeToDataType */ + + ObjectType = ACPI_TYPE_LOCAL_RESOURCE; + } + else + { + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + } + + /* Pop scope that was pushed for Resource Templates */ + + if (Op->Asl.ParseOpcode == PARSEOP_NAME) + { + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC) + { + ForceNewScope = TRUE; + } + } + + /* Pop the scope stack */ + + if (ForceNewScope || AcpiNsOpensScope (ObjectType)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "(%s): Popping scope for Op [%s] %p\n", + AcpiUtGetTypeName (ObjectType), Op->Asl.ParseOpName, Op)); + + (void) AcpiDsScopeStackPop (WalkState); + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/asllookup.c b/third_party/lib/acpica/source/compiler/asllookup.c new file mode 100644 index 000000000..c10959fb1 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asllookup.c @@ -0,0 +1,314 @@ +/****************************************************************************** + * + * Module Name: asllookup- Namespace lookup functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asllookup") + +/* Local prototypes */ + +static ACPI_STATUS +LkIsObjectUsed ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +static ACPI_PARSE_OBJECT * +LkGetNameOp ( + ACPI_PARSE_OBJECT *Op); + + +/******************************************************************************* + * + * FUNCTION: LkFindUnreferencedObjects + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Namespace walk to find objects that are not referenced in any + * way. Must be called after the namespace has been cross + * referenced. + * + ******************************************************************************/ + +void +LkFindUnreferencedObjects ( + void) +{ + + /* Walk entire namespace from the supplied root */ + + (void) AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, LkIsObjectUsed, NULL, + NULL, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: LkIsObjectUsed + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Check for an unreferenced namespace object and emit a warning. + * We have to be careful, because some types and names are + * typically or always unreferenced, we don't want to issue + * excessive warnings. Note: Names that are declared within a + * control method are temporary, so we always issue a remark + * if they are not referenced. + * + ******************************************************************************/ + +static ACPI_STATUS +LkIsObjectUsed ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + ACPI_NAMESPACE_NODE *Next; + ASL_METHOD_LOCAL *MethodLocals; + ASL_METHOD_LOCAL *MethodArgs; + UINT32 i; + + + if (Node->Type == ACPI_TYPE_METHOD) + { + if (!Node->Op || !Node->MethodLocals) + { + return (AE_OK); + } + + MethodLocals = (ASL_METHOD_LOCAL *) Node->MethodLocals; + MethodArgs = (ASL_METHOD_LOCAL *) Node->MethodArgs; + + /* + * Analysis of LocalX variables + */ + for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) + { + /* Warn for Locals that are set but never referenced */ + + if ((MethodLocals[i].Flags & ASL_LOCAL_INITIALIZED) && + (!(MethodLocals[i].Flags & ASL_LOCAL_REFERENCED))) + { + sprintf (MsgBuffer, "Local%u", i); + AslError (ASL_WARNING, ASL_MSG_LOCAL_NOT_USED, + MethodLocals[i].Op, MsgBuffer); + } + } + + /* + * Analysis of ArgX variables (standard method arguments, + * and remaining unused ArgX can also be used as locals) + */ + for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) + { + if (MethodArgs[i].Flags & ASL_ARG_IS_LOCAL) + { + /* Warn if ArgX is being used as a local, but not referenced */ + + if ((MethodArgs[i].Flags & ASL_ARG_INITIALIZED) && + (!(MethodArgs[i].Flags & ASL_ARG_REFERENCED))) + { + sprintf (MsgBuffer, "Arg%u", i); + AslError (ASL_WARNING, ASL_MSG_ARG_AS_LOCAL_NOT_USED, + MethodArgs[i].Op, MsgBuffer); + } + } + else + { + /* + * Remark if a normal method ArgX is not referenced. + * We ignore the predefined methods since often, not + * all arguments are needed or used. + */ + if ((Node->Name.Ascii[0] != '_') && + (!(MethodArgs[i].Flags & ASL_ARG_REFERENCED))) + { + sprintf (MsgBuffer, "Arg%u", i); + AslError (ASL_REMARK, ASL_MSG_ARG_NOT_USED, + MethodArgs[i].Op, MsgBuffer); + } + } + } + } + + /* Referenced flag is set during the namespace xref */ + + if (Node->Flags & ANOBJ_IS_REFERENCED) + { + return (AE_OK); + } + + if (!Node->Op) + { + return (AE_OK); + } + + /* These types are typically never directly referenced, ignore them */ + + switch (Node->Type) + { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + case ACPI_TYPE_THERMAL: + case ACPI_TYPE_LOCAL_RESOURCE: + + return (AE_OK); + + default: + + break; + } + + /* Determine if the name is within a control method */ + + Next = Node->Parent; + while (Next) + { + if (Next->Type == ACPI_TYPE_METHOD) + { + /* + * Name is within a method, therefore it is temporary. + * Issue a remark even if it is a reserved name (starts + * with an underscore). + */ + sprintf (MsgBuffer, "Name is within method [%4.4s]", + Next->Name.Ascii); + AslError (ASL_REMARK, ASL_MSG_NOT_REFERENCED, + LkGetNameOp (Node->Op), MsgBuffer); + return (AE_OK); + } + + Next = Next->Parent; + } + + /* The name is not within a control method */ + + /* + * Ignore names that start with an underscore. These are the reserved + * ACPI names and are typically not referenced since they are meant + * to be called by the host OS. + */ + if (Node->Name.Ascii[0] == '_') + { + return (AE_OK); + } + + /* + * What remains is an unresolved user name that is not within a method. + * However, the object could be referenced via another table, so issue + * the warning at level 2. + */ + AslError (ASL_WARNING2, ASL_MSG_NOT_REFERENCED, + LkGetNameOp (Node->Op), NULL); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LkGetNameOp + * + * PARAMETERS: Op - Current Op + * + * RETURN: NameOp associated with the input op + * + * DESCRIPTION: Find the name declaration op associated with the operator + * + ******************************************************************************/ + +static ACPI_PARSE_OBJECT * +LkGetNameOp ( + ACPI_PARSE_OBJECT *Op) +{ + const ACPI_OPCODE_INFO *OpInfo; + ACPI_PARSE_OBJECT *NameOp = Op; + + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + + + /* Get the NamePath from the appropriate place */ + + if (OpInfo->Flags & AML_NAMED) + { + /* For nearly all NAMED operators, the name reference is the first child */ + + NameOp = Op->Asl.Child; + if (Op->Asl.AmlOpcode == AML_ALIAS_OP) + { + /* + * ALIAS is the only oddball opcode, the name declaration + * (alias name) is the second operand + */ + NameOp = Op->Asl.Child->Asl.Next; + } + } + else if (OpInfo->Flags & AML_CREATE) + { + /* Name must appear as the last parameter */ + + NameOp = Op->Asl.Child; + while (!(NameOp->Asl.CompileFlags & NODE_IS_NAME_DECLARATION)) + { + NameOp = NameOp->Asl.Next; + } + } + + return (NameOp); +} diff --git a/third_party/lib/acpica/source/compiler/aslmain.c b/third_party/lib/acpica/source/compiler/aslmain.c new file mode 100644 index 000000000..cc7764a7f --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmain.c @@ -0,0 +1,426 @@ +/****************************************************************************** + * + * Module Name: aslmain - compiler main and utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define _DECLARE_GLOBALS + +#include "aslcompiler.h" +#include "acapps.h" +#include "acdisasm.h" +#include + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmain") + +/* + * Main routine for the iASL compiler. + * + * Portability note: The compiler depends upon the host for command-line + * wildcard support - it is not implemented locally. For example: + * + * Linux/Unix systems: Shell expands wildcards automatically. + * + * Windows: The setargv.obj module must be linked in to automatically + * expand wildcards. + */ + +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +AslSignalHandler ( + int Sig); + +static void +AslInitialize ( + void); + +UINT8 +AcpiIsBigEndianMachine ( + void); + + +/******************************************************************************* + * + * FUNCTION: AcpiIsBigEndianMachine + * + * PARAMETERS: None + * + * RETURN: TRUE if machine is big endian + * FALSE if machine is little endian + * + * DESCRIPTION: Detect whether machine is little endian or big endian. + * + ******************************************************************************/ + +UINT8 +AcpiIsBigEndianMachine ( + void) +{ + union { + UINT32 Integer; + UINT8 Bytes[4]; + } Overlay = {0xFF000000}; + + return (Overlay.Bytes[0]); /* Returns 0xFF (TRUE) for big endian */ +} + + +/******************************************************************************* + * + * FUNCTION: Usage + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display option help message. + * Optional items in square brackets. + * + ******************************************************************************/ + +void +Usage ( + void) +{ + printf ("%s\n\n", ASL_COMPLIANCE); + ACPI_USAGE_HEADER ("iasl [Options] [Files]"); + + printf ("\nGeneral:\n"); + ACPI_OPTION ("-@ ", "Specify command file"); + ACPI_OPTION ("-I ", "Specify additional include directory"); + ACPI_OPTION ("-T |ALL", "Create ACPI table template/example files"); + ACPI_OPTION ("-T ", "Emit DSDT and SSDTs to same file"); + ACPI_OPTION ("-p ", "Specify path/filename prefix for all output files"); + ACPI_OPTION ("-v", "Display compiler version"); + ACPI_OPTION ("-vo", "Enable optimization comments"); + ACPI_OPTION ("-vs", "Disable signon"); + + printf ("\nHelp:\n"); + ACPI_OPTION ("-h", "This message"); + ACPI_OPTION ("-hc", "Display operators allowed in constant expressions"); + ACPI_OPTION ("-hf", "Display help for output filename generation"); + ACPI_OPTION ("-hr", "Display ACPI reserved method names"); + ACPI_OPTION ("-ht", "Display currently supported ACPI table names"); + + printf ("\nPreprocessor:\n"); + ACPI_OPTION ("-D ", "Define symbol for preprocessor use"); + ACPI_OPTION ("-li", "Create preprocessed output file (*.i)"); + ACPI_OPTION ("-P", "Preprocess only and create preprocessor output file (*.i)"); + ACPI_OPTION ("-Pn", "Disable preprocessor"); + + printf ("\nErrors, Warnings, and Remarks:\n"); + ACPI_OPTION ("-va", "Disable all errors/warnings/remarks"); + ACPI_OPTION ("-ve", "Report only errors (ignore warnings and remarks)"); + ACPI_OPTION ("-vi", "Less verbose errors and warnings for use with IDEs"); + ACPI_OPTION ("-vr", "Disable remarks"); + ACPI_OPTION ("-vw ", "Disable specific warning or remark"); + ACPI_OPTION ("-w1 -w2 -w3", "Set warning reporting level"); + ACPI_OPTION ("-we", "Report warnings as errors"); + + printf ("\nAML Code Generation (*.aml):\n"); + ACPI_OPTION ("-oa", "Disable all optimizations (compatibility mode)"); + ACPI_OPTION ("-of", "Disable constant folding"); + ACPI_OPTION ("-oi", "Disable integer optimization to Zero/One/Ones"); + ACPI_OPTION ("-on", "Disable named reference string optimization"); + ACPI_OPTION ("-ot", "Disable typechecking"); + ACPI_OPTION ("-cr", "Disable Resource Descriptor error checking"); + ACPI_OPTION ("-in", "Ignore NoOp operators"); + ACPI_OPTION ("-r ", "Override table header Revision (1-255)"); + + printf ("\nOptional Source Code Output Files:\n"); + ACPI_OPTION ("-sc -sa", "Create source file in C or assembler (*.c or *.asm)"); + ACPI_OPTION ("-ic -ia", "Create include file in C or assembler (*.h or *.inc)"); + ACPI_OPTION ("-tc -ta -ts", "Create hex AML table in C, assembler, or ASL (*.hex)"); + ACPI_OPTION ("-so", "Create offset table in C (*.offset.h)"); + + printf ("\nOptional Listing Files:\n"); + ACPI_OPTION ("-l", "Create mixed listing file (ASL source and AML) (*.lst)"); + ACPI_OPTION ("-lm", "Create hardware summary map file (*.map)"); + ACPI_OPTION ("-ln", "Create namespace file (*.nsp)"); + ACPI_OPTION ("-ls", "Create combined source file (expanded includes) (*.src)"); + + printf ("\nData Table Compiler:\n"); + ACPI_OPTION ("-G", "Compile custom table that contains generic operators"); + ACPI_OPTION ("-vt", "Create verbose template files (full disassembly)"); + + printf ("\nAML Disassembler:\n"); + ACPI_OPTION ("-d ", "Disassemble or decode binary ACPI tables to file (*.dsl)"); + ACPI_OPTION ("", " (Optional, file type is automatically detected)"); + ACPI_OPTION ("-da ", "Disassemble multiple tables from single namespace"); + ACPI_OPTION ("-db", "Do not translate Buffers to Resource Templates"); + ACPI_OPTION ("-dc ", "Disassemble AML and immediately compile it"); + ACPI_OPTION ("", " (Obtain DSDT from current system if no input file)"); + ACPI_OPTION ("-df", "Force disassembler to assume table contains valid AML"); + ACPI_OPTION ("-dl", "Emit legacy ASL code only (no C-style operators)"); + ACPI_OPTION ("-e ", "Include ACPI table(s) for external symbol resolution"); + ACPI_OPTION ("-fe ", "Specify external symbol declaration file"); + ACPI_OPTION ("-in", "Ignore NoOp opcodes"); + ACPI_OPTION ("-l", "Disassemble to mixed ASL and AML code"); + ACPI_OPTION ("-vt", "Dump binary table data in hex format within output file"); + + printf ("\nDebug Options:\n"); + ACPI_OPTION ("-bf", "Create debug file (full output) (*.txt)"); + ACPI_OPTION ("-bs", "Create debug file (parse tree only) (*.txt)"); + ACPI_OPTION ("-bp ", "Prune ASL parse tree"); + ACPI_OPTION ("-bt ", "Object type to be pruned from the parse tree"); + ACPI_OPTION ("-f", "Ignore errors, force creation of AML output file(s)"); + ACPI_OPTION ("-m ", "Set internal line buffer size (in Kbytes)"); + ACPI_OPTION ("-n", "Parse only, no output generation"); + ACPI_OPTION ("-oc", "Display compile times and statistics"); + ACPI_OPTION ("-x ", "Set debug level for trace output"); + ACPI_OPTION ("-z", "Do not insert new compiler ID for DataTables"); +} + + +/******************************************************************************* + * + * FUNCTION: FilenameHelp + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display help message for output filename generation + * + ******************************************************************************/ + +void +AslFilenameHelp ( + void) +{ + + printf ("\nAML output filename generation:\n"); + printf (" Output filenames are generated by appending an extension to a common\n"); + printf (" filename prefix. The filename prefix is obtained via one of the\n"); + printf (" following methods (in priority order):\n"); + printf (" 1) The -p option specifies the prefix\n"); + printf (" 2) The prefix of the AMLFileName in the ASL Definition Block\n"); + printf (" 3) The prefix of the input filename\n"); + printf ("\n"); +} + + +/****************************************************************************** + * + * FUNCTION: AslSignalHandler + * + * PARAMETERS: Sig - Signal that invoked this handler + * + * RETURN: None + * + * DESCRIPTION: Control-C handler. Delete any intermediate files and any + * output files that may be left in an indeterminate state. + * + *****************************************************************************/ + +static void ACPI_SYSTEM_XFACE +AslSignalHandler ( + int Sig) +{ + UINT32 i; + + + signal (Sig, SIG_IGN); + printf ("Aborting\n\n"); + + /* Close all open files */ + + Gbl_Files[ASL_FILE_PREPROCESSOR].Handle = NULL; /* the .pre file is same as source file */ + + for (i = ASL_FILE_INPUT; i < ASL_MAX_FILE_TYPE; i++) + { + FlCloseFile (i); + } + + /* Delete any output files */ + + for (i = ASL_FILE_AML_OUTPUT; i < ASL_MAX_FILE_TYPE; i++) + { + FlDeleteFile (i); + } + + exit (0); +} + + +/******************************************************************************* + * + * FUNCTION: AslInitialize + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Initialize compiler globals + * + ******************************************************************************/ + +static void +AslInitialize ( + void) +{ + UINT32 i; + + + AcpiGbl_DmOpt_Verbose = FALSE; + + for (i = 0; i < ASL_NUM_FILES; i++) + { + Gbl_Files[i].Handle = NULL; + Gbl_Files[i].Filename = NULL; + } + + Gbl_Files[ASL_FILE_STDOUT].Handle = stdout; + Gbl_Files[ASL_FILE_STDOUT].Filename = "STDOUT"; + + Gbl_Files[ASL_FILE_STDERR].Handle = stderr; + Gbl_Files[ASL_FILE_STDERR].Filename = "STDERR"; +} + + +/******************************************************************************* + * + * FUNCTION: main + * + * PARAMETERS: Standard argc/argv + * + * RETURN: Program termination code + * + * DESCRIPTION: C main routine for the Asl Compiler. Handle command line + * options and begin the compile for each file on the command line + * + ******************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char **argv) +{ + ACPI_STATUS Status; + int Index1; + int Index2; + int ReturnStatus = 0; + + + /* + * Big-endian machines are not currently supported. ACPI tables must + * be little-endian, and support for big-endian machines needs to + * be implemented. + */ + if (AcpiIsBigEndianMachine ()) + { + fprintf (stderr, + "iASL is not currently supported on big-endian machines.\n"); + return (-1); + } + + AcpiOsInitialize (); + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + + /* Initialize preprocessor and compiler before command line processing */ + + signal (SIGINT, AslSignalHandler); + AcpiGbl_ExternalFileList = NULL; + AcpiDbgLevel = 0; + PrInitializePreprocessor (); + AslInitialize (); + + Index1 = Index2 = AslCommandLine (argc, argv); + + /* Allocate the line buffer(s), must be after command line */ + + Gbl_LineBufferSize /= 2; + UtExpandLineBuffers (); + + /* Perform global actions first/only */ + + if (Gbl_DisassembleAll) + { + while (argv[Index1]) + { + Status = AcpiDmAddToExternalFileList (argv[Index1]); + if (ACPI_FAILURE (Status)) + { + return (-1); + } + + Index1++; + } + } + + /* Process each pathname/filename in the list, with possible wildcards */ + + while (argv[Index2]) + { + /* + * If -p not specified, we will use the input filename as the + * output filename prefix + */ + if (Gbl_UseDefaultAmlFilename) + { + Gbl_OutputFilenamePrefix = argv[Index2]; + UtConvertBackslashes (Gbl_OutputFilenamePrefix); + } + + Status = AslDoOneFile (argv[Index2]); + if (ACPI_FAILURE (Status)) + { + ReturnStatus = -1; + goto CleanupAndExit; + } + + Index2++; + } + + +CleanupAndExit: + + UtFreeLineBuffers (); + AslParserCleanup (); + + if (AcpiGbl_ExternalFileList) + { + AcpiDmClearExternalFileList(); + } + + return (ReturnStatus); +} diff --git a/third_party/lib/acpica/source/compiler/aslmap.c b/third_party/lib/acpica/source/compiler/aslmap.c new file mode 100644 index 000000000..dec63209d --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmap.c @@ -0,0 +1,485 @@ +/****************************************************************************** + * + * Module Name: aslmap - parser to AML opcode mapping table + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "amlcode.h" +#include "acparser.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmap") + + +/******************************************************************************* + * + * FUNCTION: AslMapNamedOpcodeToDataType + * + * PARAMETERS: Opcode - The Named AML opcode to map + * + * RETURN: The ACPI type associated with the named opcode + * + * DESCRIPTION: Convert a raw Named AML opcode to the associated data type. + * Named opcodes are a subset of the AML opcodes. + * + ******************************************************************************/ + +ACPI_OBJECT_TYPE +AslMapNamedOpcodeToDataType ( + UINT16 Opcode) +{ + const ACPI_OPCODE_INFO *OpInfo; + + + /* + * There are some differences from the opcode table types, we + * catch them here. + */ + OpInfo = AcpiPsGetOpcodeInfo (Opcode); + + if (Opcode == AML_INT_NAMEPATH_OP) + { + return (ACPI_TYPE_ANY); + } + + if (Opcode == AML_INT_METHODCALL_OP) + { + return (ACPI_TYPE_ANY); + } + + if (OpInfo->Flags & AML_NSOBJECT) + { + return (OpInfo->ObjectType); + } + + return (ACPI_TYPE_ANY); +} + + +/******************************************************************************* + * + * DATA STRUCTURE: AslKeywordMapping + * + * DESCRIPTION: Maps the ParseOpcode to the actual AML opcode. The parse + * opcodes are generated from Bison, and this table must + * track any additions to them. + * + * Each entry in the table contains the following items: + * + * AML opcode - Opcode that is written to the AML file + * Value - Value of the object to be written (if applicable) + * Flags - 1) Whether this opcode opens an AML "package". + * + ******************************************************************************/ +/* + * TBD: + * AccessAttrib + * AccessType + * AMlop for DMA? + * ObjectType keywords + * Register + */ + +const ASL_MAPPING_ENTRY AslKeywordMapping [] = +{ +/*! [Begin] no source code translation (keep the table structure) */ + + /* AML Opcode Value Flags Btype */ + +/* ACCESSAS */ OP_TABLE_ENTRY (AML_INT_ACCESSFIELD_OP, 0, 0, 0), +/* ACCESSATTRIB_BLOCK */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_BLOCK, 0, 0), +/* ACCESSATTRIB_BLOCK_CALL */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_BLOCK_CALL, 0, 0), +/* ACCESSATTRIB_BYTE */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_BYTE, 0, 0), +/* ACCESSATTRIB_MULTIBYTE */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_MULTIBYTE, 0, 0), +/* ACCESSATTRIB_QUICK */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_QUICK, 0, 0), +/* ACCESSATTRIB_RAW_BYTES */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_RAW_BYTES, 0, 0), +/* ACCESSATTRIB_RAW_PROCESS */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_RAW_PROCESS, 0, 0), +/* ACCESSATTRIB_SND_RCV */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_SEND_RCV, 0, 0), +/* ACCESSATTRIB_WORD */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_WORD, 0, 0), +/* ACCESSATTRIB_WORD_CALL */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ATTRIB_WORD_CALL, 0, 0), +/* ACCESSTYPE_ANY */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ACCESS_ANY, 0, 0), +/* ACCESSTYPE_BUF */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ACCESS_BUFFER, 0, 0), +/* ACCESSTYPE_BYTE */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ACCESS_BYTE, 0, 0), +/* ACCESSTYPE_DWORD */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ACCESS_DWORD, 0, 0), +/* ACCESSTYPE_QWORD */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ACCESS_QWORD, 0, 0), +/* ACCESSTYPE_WORD */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_ACCESS_WORD, 0, 0), +/* ACQUIRE */ OP_TABLE_ENTRY (AML_ACQUIRE_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* ADD */ OP_TABLE_ENTRY (AML_ADD_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* ADDRESSINGMODE_7BIT */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* ADDRESSINGMODE_10BIT */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* ADDRESSTYPE_ACPI */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* ADDRESSTYPE_MEMORY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* ADDRESSTYPE_NVS */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* ADDRESSTYPE_RESERVED */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* ALIAS */ OP_TABLE_ENTRY (AML_ALIAS_OP, 0, 0, 0), +/* AND */ OP_TABLE_ENTRY (AML_BIT_AND_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* ARG0 */ OP_TABLE_ENTRY (AML_ARG0, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* ARG1 */ OP_TABLE_ENTRY (AML_ARG1, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* ARG2 */ OP_TABLE_ENTRY (AML_ARG2, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* ARG3 */ OP_TABLE_ENTRY (AML_ARG3, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* ARG4 */ OP_TABLE_ENTRY (AML_ARG4, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* ARG5 */ OP_TABLE_ENTRY (AML_ARG5, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* ARG6 */ OP_TABLE_ENTRY (AML_ARG6, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* BANKFIELD */ OP_TABLE_ENTRY (AML_BANK_FIELD_OP, 0, NODE_AML_PACKAGE, 0), +/* BITSPERBYTE_EIGHT */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* BITSPERBYTE_FIVE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* BITSPERBYTE_NINE */ OP_TABLE_ENTRY (AML_BYTE_OP, 4, 0, 0), +/* BITSPERBYTE_SEVEN */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* BITSPERBYTE_SIX */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* BREAK */ OP_TABLE_ENTRY (AML_BREAK_OP, 0, 0, 0), +/* BREAKPOINT */ OP_TABLE_ENTRY (AML_BREAK_POINT_OP, 0, 0, 0), +/* BUFFER */ OP_TABLE_ENTRY (AML_BUFFER_OP, 0, NODE_AML_PACKAGE, ACPI_BTYPE_BUFFER), +/* BUSMASTERTYPE_MASTER */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* BUSMASTERTYPE_NOTMASTER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* BYTECONST */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, 0, 0, ACPI_BTYPE_INTEGER), +/* CASE */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* CLOCKPHASE_FIRST */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* CLOCKPHASE_SECOND */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* CLOCKPOLARITY_HIGH */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* CLOCKPOLARITY_LOW */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* CONCATENATE */ OP_TABLE_ENTRY (AML_CONCAT_OP, 0, 0, ACPI_BTYPE_COMPUTE_DATA), +/* CONCATENATERESTEMPLATE */ OP_TABLE_ENTRY (AML_CONCAT_RES_OP, 0, 0, ACPI_BTYPE_BUFFER), +/* CONDREFOF */ OP_TABLE_ENTRY (AML_COND_REF_OF_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* CONNECTION */ OP_TABLE_ENTRY (AML_INT_CONNECTION_OP, 0, 0, 0), +/* CONTINUE */ OP_TABLE_ENTRY (AML_CONTINUE_OP, 0, 0, 0), +/* COPY */ OP_TABLE_ENTRY (AML_COPY_OP, 0, 0, ACPI_BTYPE_DATA_REFERENCE), +/* CREATEBITFIELD */ OP_TABLE_ENTRY (AML_CREATE_BIT_FIELD_OP, 0, 0, 0), +/* CREATEBYTEFIELD */ OP_TABLE_ENTRY (AML_CREATE_BYTE_FIELD_OP, 0, 0, 0), +/* CREATEDWORDFIELD */ OP_TABLE_ENTRY (AML_CREATE_DWORD_FIELD_OP, 0, 0, 0), +/* CREATEFIELD */ OP_TABLE_ENTRY (AML_CREATE_FIELD_OP, 0, 0, 0), +/* CREATEQWORDFIELD */ OP_TABLE_ENTRY (AML_CREATE_QWORD_FIELD_OP, 0, 0, 0), +/* CREATEWORDFIELD */ OP_TABLE_ENTRY (AML_CREATE_WORD_FIELD_OP, 0, 0, 0), +/* DATABUFFER */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DATATABLEREGION */ OP_TABLE_ENTRY (AML_DATA_REGION_OP, 0, 0, 0), +/* DEBUG */ OP_TABLE_ENTRY (AML_DEBUG_OP, 0, 0, ACPI_BTYPE_DEBUG_OBJECT), +/* DECODETYPE_POS */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* DECODETYPE_SUB */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* DECREMENT */ OP_TABLE_ENTRY (AML_DECREMENT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* DEFAULT */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DEFAULT_ARG */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DEFINITIONBLOCK */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DEREFOF */ OP_TABLE_ENTRY (AML_DEREF_OF_OP, 0, 0, ACPI_BTYPE_DATA_REFERENCE | ACPI_BTYPE_STRING), +/* DEVICE */ OP_TABLE_ENTRY (AML_DEVICE_OP, 0, NODE_AML_PACKAGE, 0), +/* DEVICEPOLARITY_HIGH */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* DEVICEPOLARITY_LOW */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* DIVIDE */ OP_TABLE_ENTRY (AML_DIVIDE_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* DMA */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DMATYPE_A */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* DMATYPE_COMPATIBILITY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* DMATYPE_B */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* DMATYPE_F */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* DWORDCONST */ OP_TABLE_ENTRY (AML_RAW_DATA_DWORD, 0, 0, ACPI_BTYPE_INTEGER), +/* DWORDIO */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DWORDMEMORY */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* DWORDSPACE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* EISAID */ OP_TABLE_ENTRY (AML_DWORD_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* ELSE */ OP_TABLE_ENTRY (AML_ELSE_OP, 0, NODE_AML_PACKAGE, 0), +/* ELSEIF */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, NODE_AML_PACKAGE, 0), +/* ENDDEPENDENTFN */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* ENDIAN_BIG */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* ENDIAN_LITTLE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* ENDTAG */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* ERRORNODE */ OP_TABLE_ENTRY (AML_NOOP_OP, 0, 0, 0), +/* EVENT */ OP_TABLE_ENTRY (AML_EVENT_OP, 0, 0, 0), +/* EXTENDEDIO */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* EXTENDEDMEMORY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* EXTENDEDSPACE */ OP_TABLE_ENTRY (AML_RAW_DATA_QWORD, 0, 0, ACPI_BTYPE_INTEGER), +/* EXTERNAL */ OP_TABLE_ENTRY (AML_EXTERNAL_OP, 0, 0, 0), +/* FATAL */ OP_TABLE_ENTRY (AML_FATAL_OP, 0, 0, 0), +/* FIELD */ OP_TABLE_ENTRY (AML_FIELD_OP, 0, NODE_AML_PACKAGE, 0), +/* FINDSETLEFTBIT */ OP_TABLE_ENTRY (AML_FIND_SET_LEFT_BIT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* FINDSETRIGHTBIT */ OP_TABLE_ENTRY (AML_FIND_SET_RIGHT_BIT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* FIXEDDMA */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* FIXEDIO */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* FLOWCONTROL_HW */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* FLOWCONTROL_NONE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* FLOWCONTROL_SW */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* FROMBCD */ OP_TABLE_ENTRY (AML_FROM_BCD_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* FUNCTION */ OP_TABLE_ENTRY (AML_METHOD_OP, 0, NODE_AML_PACKAGE, 0), +/* GPIOINT */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* GPIOIO */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* I2CSERIALBUS */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* IF */ OP_TABLE_ENTRY (AML_IF_OP, 0, NODE_AML_PACKAGE, 0), +/* INCLUDE */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* INCLUDE_END */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* INCREMENT */ OP_TABLE_ENTRY (AML_INCREMENT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* INDEX */ OP_TABLE_ENTRY (AML_INDEX_OP, 0, 0, ACPI_BTYPE_REFERENCE_OBJECT), +/* INDEXFIELD */ OP_TABLE_ENTRY (AML_INDEX_FIELD_OP, 0, NODE_AML_PACKAGE, 0), +/* INTEGER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* INTERRUPT */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* INTLEVEL_ACTIVEBOTH */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* INTLEVEL_ACTIVEHIGH */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* INTLEVEL_ACTIVELOW */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* INTTYPE_EDGE */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* INTTYPE_LEVEL */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* IO */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* IODECODETYPE_10 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* IODECODETYPE_16 */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* IORESTRICT_IN */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* IORESTRICT_NONE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* IORESTRICT_OUT */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* IORESTRICT_PRESERVE */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* IRQ */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* IRQNOFLAGS */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* LAND */ OP_TABLE_ENTRY (AML_LAND_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LEQUAL */ OP_TABLE_ENTRY (AML_LEQUAL_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LGREATER */ OP_TABLE_ENTRY (AML_LGREATER_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LGREATEREQUAL */ OP_TABLE_ENTRY (AML_LGREATEREQUAL_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LLESS */ OP_TABLE_ENTRY (AML_LLESS_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LLESSEQUAL */ OP_TABLE_ENTRY (AML_LLESSEQUAL_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LNOT */ OP_TABLE_ENTRY (AML_LNOT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LNOTEQUAL */ OP_TABLE_ENTRY (AML_LNOTEQUAL_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* LOAD */ OP_TABLE_ENTRY (AML_LOAD_OP, 0, 0, 0), +/* LOADTABLE */ OP_TABLE_ENTRY (AML_LOAD_TABLE_OP, 0, 0, ACPI_BTYPE_DDB_HANDLE), +/* LOCAL0 */ OP_TABLE_ENTRY (AML_LOCAL0, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL1 */ OP_TABLE_ENTRY (AML_LOCAL1, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL2 */ OP_TABLE_ENTRY (AML_LOCAL2, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL3 */ OP_TABLE_ENTRY (AML_LOCAL3, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL4 */ OP_TABLE_ENTRY (AML_LOCAL4, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL5 */ OP_TABLE_ENTRY (AML_LOCAL5, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL6 */ OP_TABLE_ENTRY (AML_LOCAL6, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCAL7 */ OP_TABLE_ENTRY (AML_LOCAL7, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* LOCKRULE_LOCK */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_LOCK_ALWAYS, 0, 0), +/* LOCKRULE_NOLOCK */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_LOCK_NEVER, 0, 0), +/* LOR */ OP_TABLE_ENTRY (AML_LOR_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* MATCH */ OP_TABLE_ENTRY (AML_MATCH_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* MATCHTYPE_MEQ */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, MATCH_MEQ, 0, ACPI_BTYPE_INTEGER), +/* MATCHTYPE_MGE */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, MATCH_MGE, 0, ACPI_BTYPE_INTEGER), +/* MATCHTYPE_MGT */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, MATCH_MGT, 0, ACPI_BTYPE_INTEGER), +/* MATCHTYPE_MLE */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, MATCH_MLE, 0, ACPI_BTYPE_INTEGER), +/* MATCHTYPE_MLT */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, MATCH_MLT, 0, ACPI_BTYPE_INTEGER), +/* MATCHTYPE_MTR */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, MATCH_MTR, 0, ACPI_BTYPE_INTEGER), +/* MAXTYPE_FIXED */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* MAXTYPE_NOTFIXED */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* MEMORY24 */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* MEMORY32 */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* MEMORY32FIXED */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* MEMTYPE_CACHEABLE */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* MEMTYPE_NONCACHEABLE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* MEMTYPE_PREFETCHABLE */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* MEMTYPE_WRITECOMBINING */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* METHOD */ OP_TABLE_ENTRY (AML_METHOD_OP, 0, NODE_AML_PACKAGE, 0), +/* METHODCALL */ OP_TABLE_ENTRY (AML_INT_METHODCALL_OP, 0, 0, ACPI_BTYPE_OBJECTS_AND_REFS), +/* MID */ OP_TABLE_ENTRY (AML_MID_OP, 0, 0, ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER), +/* MINTYPE_FIXED */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* MINTYPE_NOTFIXED */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* MOD */ OP_TABLE_ENTRY (AML_MOD_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* MULTIPLY */ OP_TABLE_ENTRY (AML_MULTIPLY_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* MUTEX */ OP_TABLE_ENTRY (AML_MUTEX_OP, 0, 0, 0), +/* NAME */ OP_TABLE_ENTRY (AML_NAME_OP, 0, 0, 0), +/* NAMESEG */ OP_TABLE_ENTRY (AML_INT_NAMEPATH_OP, 0, 0, 0), +/* NAMESTRING */ OP_TABLE_ENTRY (AML_INT_NAMEPATH_OP, 0, 0, 0), +/* NAND */ OP_TABLE_ENTRY (AML_BIT_NAND_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* NOOP */ OP_TABLE_ENTRY (AML_NOOP_OP, 0, 0, 0), +/* NOR */ OP_TABLE_ENTRY (AML_BIT_NOR_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* NOT */ OP_TABLE_ENTRY (AML_BIT_NOT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* NOTIFY */ OP_TABLE_ENTRY (AML_NOTIFY_OP, 0, 0, 0), +/* OBJECTTYPE */ OP_TABLE_ENTRY (AML_OBJECT_TYPE_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* OBJECTTYPE_BFF */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_BUFFER_FIELD, 0, 0), +/* OBJECTTYPE_BUF */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_BUFFER, 0, 0), +/* OBJECTTYPE_DDB */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_DDB_HANDLE, 0, 0), +/* OBJECTTYPE_DEV */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_DEVICE, 0, 0), +/* OBJECTTYPE_EVT */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_EVENT, 0, 0), +/* OBJECTTYPE_FLD */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_FIELD_UNIT, 0, 0), +/* OBJECTTYPE_INT */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_INTEGER, 0, 0), +/* OBJECTTYPE_MTH */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_METHOD, 0, 0), +/* OBJECTTYPE_MTX */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_MUTEX, 0, 0), +/* OBJECTTYPE_OPR */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_REGION, 0, 0), +/* OBJECTTYPE_PKG */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_PACKAGE, 0, 0), +/* OBJECTTYPE_POW */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_POWER, 0, 0), +/* OBJECTTYPE_PRO */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_PROCESSOR, 0, 0), +/* OBJECTTYPE_STR */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_STRING, 0, 0), +/* OBJECTTYPE_THZ */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_THERMAL, 0, 0), +/* OBJECTTYPE_UNK */ OP_TABLE_ENTRY (AML_BYTE_OP, ACPI_TYPE_ANY, 0, 0), +/* OFFSET */ OP_TABLE_ENTRY (AML_INT_RESERVEDFIELD_OP, 0, 0, 0), +/* ONE */ OP_TABLE_ENTRY (AML_ONE_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* ONES */ OP_TABLE_ENTRY (AML_ONES_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* OPERATIONREGION */ OP_TABLE_ENTRY (AML_REGION_OP, 0, 0, 0), +/* OR */ OP_TABLE_ENTRY (AML_BIT_OR_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* PACKAGE */ OP_TABLE_ENTRY (AML_PACKAGE_OP, 0, NODE_AML_PACKAGE, ACPI_BTYPE_PACKAGE), +/* PACKAGEP_LENGTH */ OP_TABLE_ENTRY (AML_PACKAGE_LENGTH, 0, NODE_AML_PACKAGE, 0), +/* PARITYTYPE_EVEN */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* PARITYTYPE_MARK */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* PARITYTYPE_NONE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* PARITYTYPE_ODD */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* PARITYTYPE_SPACE */ OP_TABLE_ENTRY (AML_BYTE_OP, 4, 0, 0), +/* PIN_NOPULL */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* PIN_PULLDEFAULT */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* PIN_PULLDOWN */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* PIN_PULLUP */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* POWERRESOURCE */ OP_TABLE_ENTRY (AML_POWER_RES_OP, 0, NODE_AML_PACKAGE, 0), +/* PROCESSOR */ OP_TABLE_ENTRY (AML_PROCESSOR_OP, 0, NODE_AML_PACKAGE, 0), +/* QWORDCONST */ OP_TABLE_ENTRY (AML_RAW_DATA_QWORD, 0, 0, ACPI_BTYPE_INTEGER), +/* QWORDIO */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* QWORDMEMORY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* QWORDSPACE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* RANGE_TYPE_ENTIRE */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* RANGE_TYPE_ISAONLY */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* RANGE_TYPE_NONISAONLY */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* RAW_DATA */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* READWRITETYPE_BOTH */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* READWRITETYPE_READONLY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* REFOF */ OP_TABLE_ENTRY (AML_REF_OF_OP, 0, 0, ACPI_BTYPE_REFERENCE_OBJECT), +/* REGIONSPACE_CMOS */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_CMOS, 0, 0), +/* REGIONSPACE_EC */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_EC, 0, 0), +/* REGIONSPACE_FFIXEDHW */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_FIXED_HARDWARE, 0, 0), +/* REGIONSPACE_GPIO */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_GPIO, 0, 0), +/* REGIONSPACE_GSBUS */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_GSBUS, 0, 0), +/* REGIONSPACE_IO */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0), +/* REGIONSPACE_IPMI */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_IPMI, 0, 0), +/* REGIONSPACE_MEM */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_SYSTEM_MEMORY, 0, 0), +/* REGIONSPACE_PCC */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_PLATFORM_COMM, 0, 0), +/* REGIONSPACE_PCI */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_PCI_CONFIG, 0, 0), +/* REGIONSPACE_PCIBAR */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_PCI_BAR_TARGET, 0, 0), +/* REGIONSPACE_SMBUS */ OP_TABLE_ENTRY (AML_RAW_DATA_BYTE, ACPI_ADR_SPACE_SMBUS, 0, 0), +/* REGISTER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* RELEASE */ OP_TABLE_ENTRY (AML_RELEASE_OP, 0, 0, 0), +/* RESERVED_BYTES */ OP_TABLE_ENTRY (AML_INT_RESERVEDFIELD_OP, 0, 0, 0), +/* RESET */ OP_TABLE_ENTRY (AML_RESET_OP, 0, 0, 0), +/* RESOURCETEMPLATE */ OP_TABLE_ENTRY (AML_BUFFER_OP, 0, 0, ACPI_BTYPE_BUFFER), +/* RESOURCETYPE_CONSUMER */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* RESOURCETYPE_PRODUCER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* RETURN */ OP_TABLE_ENTRY (AML_RETURN_OP, 0, 0, 0), +/* REVISION */ OP_TABLE_ENTRY (AML_REVISION_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* SCOPE */ OP_TABLE_ENTRY (AML_SCOPE_OP, 0, NODE_AML_PACKAGE, 0), +/* SERIALIZERULE_NOTSERIAL */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* SERIALIZERULE_SERIAL */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* SHARETYPE_EXCLUSIVE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* SHARETYPE_EXCLUSIVEWAKE */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* SHARETYPE_SHARED */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* SHARETYPE_SHAREDWAKE */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* SHIFTLEFT */ OP_TABLE_ENTRY (AML_SHIFT_LEFT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* SHIFTRIGHT */ OP_TABLE_ENTRY (AML_SHIFT_RIGHT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* SIGNAL */ OP_TABLE_ENTRY (AML_SIGNAL_OP, 0, 0, 0), +/* SIZEOF */ OP_TABLE_ENTRY (AML_SIZE_OF_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* SLAVEMODE_CONTROLLERINIT */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* SLAVEMODE_DEVICEINIT */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* SLEEP */ OP_TABLE_ENTRY (AML_SLEEP_OP, 0, 0, 0), +/* SPISERIALBUS */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* STALL */ OP_TABLE_ENTRY (AML_STALL_OP, 0, 0, 0), +/* STARTDEPENDENTFN */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* STARTDEPENDENTFN_NOPRI */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* STOPBITS_ONE */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* STOPBITS_ONEPLUSHALF */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* STOPBITS_TWO */ OP_TABLE_ENTRY (AML_BYTE_OP, 3, 0, 0), +/* STOPBITS_ZERO */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* STORE */ OP_TABLE_ENTRY (AML_STORE_OP, 0, 0, ACPI_BTYPE_DATA_REFERENCE), +/* STRING_LITERAL */ OP_TABLE_ENTRY (AML_STRING_OP, 0, 0, ACPI_BTYPE_STRING), +/* SUBTRACT */ OP_TABLE_ENTRY (AML_SUBTRACT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* SWITCH */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* THERMALZONE */ OP_TABLE_ENTRY (AML_THERMAL_ZONE_OP, 0, NODE_AML_PACKAGE, 0), +/* TIMER */ OP_TABLE_ENTRY (AML_TIMER_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* TOBCD */ OP_TABLE_ENTRY (AML_TO_BCD_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* TOBUFFER */ OP_TABLE_ENTRY (AML_TO_BUFFER_OP, 0, 0, ACPI_BTYPE_BUFFER), +/* TODECIMALSTRING */ OP_TABLE_ENTRY (AML_TO_DECSTRING_OP, 0, 0, ACPI_BTYPE_STRING), +/* TOHEXSTRING */ OP_TABLE_ENTRY (AML_TO_HEXSTRING_OP, 0, 0, ACPI_BTYPE_STRING), +/* TOINTEGER */ OP_TABLE_ENTRY (AML_TO_INTEGER_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* TOSTRING */ OP_TABLE_ENTRY (AML_TO_STRING_OP, 0, 0, ACPI_BTYPE_STRING), +/* TOUUID */ OP_TABLE_ENTRY (AML_DWORD_OP, 0, NODE_AML_PACKAGE, ACPI_BTYPE_INTEGER), +/* TRANSLATIONTYPE_DENSE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* TRANSLATIONTYPE_SPARSE */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* TYPE_STATIC */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* TYPE_TRANSLATION */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* UART_SERIALBUS */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0), +/* UNICODE */ OP_TABLE_ENTRY (AML_BUFFER_OP, 0, NODE_AML_PACKAGE, 0), +/* UNLOAD */ OP_TABLE_ENTRY (AML_UNLOAD_OP, 0, 0, 0), +/* UPDATERULE_ONES */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_UPDATE_WRITE_AS_ONES, 0, 0), +/* UPDATERULE_PRESERVE */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_UPDATE_PRESERVE, 0, 0), +/* UPDATERULE_ZEROS */ OP_TABLE_ENTRY (AML_BYTE_OP, AML_FIELD_UPDATE_WRITE_AS_ZEROS,0, 0), +/* VAR_PACKAGE */ OP_TABLE_ENTRY (AML_VAR_PACKAGE_OP, 0, NODE_AML_PACKAGE, ACPI_BTYPE_PACKAGE), +/* VENDORLONG */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* VENDORSHORT */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* WAIT */ OP_TABLE_ENTRY (AML_WAIT_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* WHILE */ OP_TABLE_ENTRY (AML_WHILE_OP, 0, NODE_AML_PACKAGE, 0), +/* WIREMODE_FOUR */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* WIREMODE_THREE */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* WORDBUSNUMBER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* WORDCONST */ OP_TABLE_ENTRY (AML_RAW_DATA_WORD, 0, 0, ACPI_BTYPE_INTEGER), +/* WORDIO */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* WORDSPACE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERSIZE_8 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERSIZE_16 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERSIZE_32 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERSIZE_64 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERSIZE_128 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERSIZE_256 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERTYPE_8 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* XFERTYPE_8_16 */ OP_TABLE_ENTRY (AML_BYTE_OP, 1, 0, 0), +/* XFERTYPE_16 */ OP_TABLE_ENTRY (AML_BYTE_OP, 2, 0, 0), +/* XOR */ OP_TABLE_ENTRY (AML_BIT_XOR_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* ZERO */ OP_TABLE_ENTRY (AML_ZERO_OP, 0, 0, ACPI_BTYPE_INTEGER), +/* TOPLD */ OP_TABLE_ENTRY (AML_DWORD_OP, 0, NODE_AML_PACKAGE, ACPI_BTYPE_INTEGER), +/* XFERSIZE_128 */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* REVISION */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* IGNORECOLOR */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* RED */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* GREEN */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* BLUE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* WIDTH */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* HEIGHT */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* USERVISIBLE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* DOCK */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* LID */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* PANEL */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* VERTICALPOSITION */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* HORIZONTALPOSITION */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* SHAPE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* GROUPORIENTATION */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* GROUPTOKEN */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* GROUPPOSITION */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* BAY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* EJECTABLE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* EJECTREQUIRED */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* CABINETNUMBER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* CARDCAGENUMBER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* REFERENCE */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* ROTATION */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* ORDER */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* RESERVED */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* VERTICALOFFSET */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* HORIZONTALOFFSET */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0), +/* PRINTF */ OP_TABLE_ENTRY (AML_STORE_OP, 0, 0, ACPI_BTYPE_DATA_REFERENCE), +/* FPRINTF */ OP_TABLE_ENTRY (AML_STORE_OP, 0, 0, ACPI_BTYPE_DATA_REFERENCE), +/* ASLCODE */ OP_TABLE_ENTRY (0, 0, 0, 0) +/*! [End] no source code translation !*/ + +}; diff --git a/third_party/lib/acpica/source/compiler/aslmapenter.c b/third_party/lib/acpica/source/compiler/aslmapenter.c new file mode 100644 index 000000000..e4ab4f25d --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmapenter.c @@ -0,0 +1,348 @@ +/****************************************************************************** + * + * Module Name: aslmapenter - Build resource descriptor/device maps + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include "aslcompiler.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmapenter") + +/* Local prototypes */ + +static ACPI_GPIO_INFO * +MpCreateGpioInfo ( + UINT16 PinNumber, + char *DeviceName); + +static ACPI_SERIAL_INFO * +MpCreateSerialInfo ( + char *DeviceName, + UINT16 Address); + + +/******************************************************************************* + * + * FUNCTION: MpSaveGpioInfo + * + * PARAMETERS: Resource - GPIO resource descriptor + * PinCount - From GPIO descriptor + * PinList - From GPIO descriptor + * DeviceName - The "ResourceSource" name + * + * RETURN: None + * + * DESCRIPTION: External Interface. + * Save GPIO resource descriptor information. + * Creates new GPIO info blocks, one for each pin defined by the + * GPIO descriptor. + * + ******************************************************************************/ + +void +MpSaveGpioInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + UINT32 PinCount, + UINT16 *PinList, + char *DeviceName) +{ + ACPI_GPIO_INFO *Info; + UINT32 i; + + + /* Mapfile option enabled? */ + + if (!Gbl_MapfileFlag) + { + return; + } + + /* Create an info block for each pin defined in the descriptor */ + + for (i = 0; i < PinCount; i++) + { + Info = MpCreateGpioInfo (PinList[i], DeviceName); + + Info->Op = Op; + Info->DeviceName = DeviceName; + Info->PinCount = PinCount; + Info->PinIndex = i; + Info->PinNumber = PinList[i]; + Info->Type = Resource->Gpio.ConnectionType; + Info->Direction = (UINT8) (Resource->Gpio.IntFlags & 0x0003); /* _IOR, for IO descriptor */ + Info->Polarity = (UINT8) ((Resource->Gpio.IntFlags >> 1) & 0x0003); /* _POL, for INT descriptor */ + } +} + + +/******************************************************************************* + * + * FUNCTION: MpSaveSerialInfo + * + * PARAMETERS: Resource - A Serial resource descriptor + * DeviceName - The "ResourceSource" name. + * + * RETURN: None + * + * DESCRIPTION: External Interface. + * Save serial resource descriptor information. + * Creates a new serial info block. + * + ******************************************************************************/ + +void +MpSaveSerialInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + char *DeviceName) +{ + ACPI_SERIAL_INFO *Info; + UINT16 Address; + UINT32 Speed; + + + /* Mapfile option enabled? */ + + if (!Gbl_MapfileFlag) + { + return; + } + + if (Resource->DescriptorType != ACPI_RESOURCE_NAME_SERIAL_BUS) + { + return; + } + + /* Extract address and speed from the resource descriptor */ + + switch (Resource->CommonSerialBus.Type) + { + case AML_RESOURCE_I2C_SERIALBUSTYPE: + + Address = Resource->I2cSerialBus.SlaveAddress; + Speed = Resource->I2cSerialBus.ConnectionSpeed; + break; + + case AML_RESOURCE_SPI_SERIALBUSTYPE: + + Address = Resource->SpiSerialBus.DeviceSelection; + Speed = Resource->SpiSerialBus.ConnectionSpeed; + break; + + case AML_RESOURCE_UART_SERIALBUSTYPE: + + Address = 0; + Speed = Resource->UartSerialBus.DefaultBaudRate; + break; + + default: /* Invalid bus subtype */ + return; + } + + Info = MpCreateSerialInfo (DeviceName, Address); + + Info->Op = Op; + Info->DeviceName = DeviceName; + Info->Resource = Resource; + Info->Address = Address; + Info->Speed = Speed; +} + + +/******************************************************************************* + * + * FUNCTION: MpCreateGpioInfo + * + * PARAMETERS: PinNumber - GPIO pin number + * DeviceName - The "ResourceSource" name + * + * RETURN: New GPIO info block. + * + * DESCRIPTION: Create a new GPIO info block and place it on the global list. + * The list is sorted by GPIO device names first, and pin numbers + * secondarily. + * + ******************************************************************************/ + +static ACPI_GPIO_INFO * +MpCreateGpioInfo ( + UINT16 PinNumber, + char *DeviceName) +{ + ACPI_GPIO_INFO *Info; + ACPI_GPIO_INFO *NextGpio; + ACPI_GPIO_INFO *PrevGpio; + char *Buffer; + + + /* + * Allocate a new info block and insert it into the global GPIO list + * sorted by both source device name and then the pin number. There is + * one block per pin. + */ + Buffer = UtStringCacheCalloc (sizeof (ACPI_GPIO_INFO)); + Info = ACPI_CAST_PTR (ACPI_GPIO_INFO, Buffer); + + NextGpio = Gbl_GpioList; + PrevGpio = NULL; + if (!Gbl_GpioList) + { + Gbl_GpioList = Info; + Info->Next = NULL; + return (Info); + } + + /* Sort on source DeviceName first */ + + while (NextGpio && + (strcmp (DeviceName, NextGpio->DeviceName) > 0)) + { + PrevGpio = NextGpio; + NextGpio = NextGpio->Next; + } + + /* Now sort on the PinNumber */ + + while (NextGpio && + (NextGpio->PinNumber < PinNumber) && + !strcmp (DeviceName, NextGpio->DeviceName)) + { + PrevGpio = NextGpio; + NextGpio = NextGpio->Next; + } + + /* Finish the list insertion */ + + if (PrevGpio) + { + PrevGpio->Next = Info; + } + else + { + Gbl_GpioList = Info; + } + + Info->Next = NextGpio; + return (Info); +} + + +/******************************************************************************* + * + * FUNCTION: MpCreateSerialInfo + * + * PARAMETERS: DeviceName - The "ResourceSource" name. + * Address - Physical address for the device + * + * RETURN: New Serial info block. + * + * DESCRIPTION: Create a new Serial info block and place it on the global list. + * The list is sorted by Serial device names first, and addresses + * secondarily. + * + ******************************************************************************/ + +static ACPI_SERIAL_INFO * +MpCreateSerialInfo ( + char *DeviceName, + UINT16 Address) +{ + ACPI_SERIAL_INFO *Info; + ACPI_SERIAL_INFO *NextSerial; + ACPI_SERIAL_INFO *PrevSerial; + char *Buffer; + + + /* + * Allocate a new info block and insert it into the global Serial list + * sorted by both source device name and then the address. + */ + Buffer = UtStringCacheCalloc (sizeof (ACPI_SERIAL_INFO)); + Info = ACPI_CAST_PTR (ACPI_SERIAL_INFO, Buffer); + + NextSerial = Gbl_SerialList; + PrevSerial = NULL; + if (!Gbl_SerialList) + { + Gbl_SerialList = Info; + Info->Next = NULL; + return (Info); + } + + /* Sort on source DeviceName */ + + while (NextSerial && + (strcmp (DeviceName, NextSerial->DeviceName) > 0)) + { + PrevSerial = NextSerial; + NextSerial = NextSerial->Next; + } + + /* Now sort on the Address */ + + while (NextSerial && + (NextSerial->Address < Address) && + !strcmp (DeviceName, NextSerial->DeviceName)) + { + PrevSerial = NextSerial; + NextSerial = NextSerial->Next; + } + + /* Finish the list insertion */ + + if (PrevSerial) + { + PrevSerial->Next = Info; + } + else + { + Gbl_SerialList = Info; + } + + Info->Next = NextSerial; + return (Info); +} diff --git a/third_party/lib/acpica/source/compiler/aslmapoutput.c b/third_party/lib/acpica/source/compiler/aslmapoutput.c new file mode 100644 index 000000000..c17b69c0b --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmapoutput.c @@ -0,0 +1,642 @@ +/****************************************************************************** + * + * Module Name: aslmapoutput - Output/emit the resource descriptor/device maps + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acinterp.h" +#include "acparser.h" +#include "acnamesp.h" +#include "amlcode.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmapoutput") + +/* Local prototypes */ + +static void +MpEmitGpioInfo ( + void); + +static void +MpEmitSerialInfo ( + void); + +static void +MpEmitDeviceTree ( + void); + +static ACPI_STATUS +MpEmitOneDevice ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static void +MpXrefDevices ( + ACPI_GPIO_INFO *Info); + +static ACPI_STATUS +MpNamespaceXrefBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + + +/* Strings used to decode flag bits */ + +const char *DirectionDecode[] = +{ + "Both I/O ", + "InputOnly ", + "OutputOnly ", + "Preserve " +}; + +const char *PolarityDecode[] = +{ + "ActiveHigh", + "ActiveLow ", + "ActiveBoth", + "Reserved " +}; + + +/******************************************************************************* + * + * FUNCTION: MpEmitMappingInfo + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: External interface. + * Map file has already been opened. Emit all of the collected + * hardware mapping information. Includes: GPIO information, + * Serial information, and a dump of the entire ACPI device tree. + * + ******************************************************************************/ + +void +MpEmitMappingInfo ( + void) +{ + + /* Mapfile option enabled? */ + + if (!Gbl_MapfileFlag) + { + return; + } + + if (!Gbl_GpioList) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, + "\nNo GPIO devices found\n"); + } + + if (!Gbl_SerialList) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, + "\nNo Serial devices found (I2C/SPI/UART)\n"); + } + + if (!Gbl_GpioList && !Gbl_SerialList) + { + return; + } + + /* Headers */ + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\nResource Descriptor Connectivity Map\n"); + FlPrintFile (ASL_FILE_MAP_OUTPUT, "------------------------------------\n"); + + /* Emit GPIO and Serial descriptors, then entire ACPI device tree */ + + MpEmitGpioInfo (); + MpEmitSerialInfo (); + MpEmitDeviceTree (); + + /* Clear the lists - no need to free memory here */ + + Gbl_SerialList = NULL; + Gbl_GpioList = NULL; +} + + +/******************************************************************************* + * + * FUNCTION: MpEmitGpioInfo + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Emit the info about all GPIO devices found during the + * compile or disassembly. + * + ******************************************************************************/ + +static void +MpEmitGpioInfo ( + void) +{ + ACPI_GPIO_INFO *Info; + char *Type; + char *PrevDeviceName = NULL; + const char *Direction; + const char *Polarity; + char *ParentPathname; + const char *Description; + char *HidString; + const AH_DEVICE_ID *HidInfo; + + + /* Walk the GPIO descriptor list */ + + Info = Gbl_GpioList; + while (Info) + { + HidString = MpGetHidViaNamestring (Info->DeviceName); + + /* Print header info for the controller itself */ + + if (!PrevDeviceName || + strcmp (PrevDeviceName, Info->DeviceName)) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, + "\n\nGPIO Controller: %-8s %-28s", + HidString, Info->DeviceName); + + HidInfo = AcpiAhMatchHardwareId (HidString); + if (HidInfo) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s", + HidInfo->Description); + } + + FlPrintFile (ASL_FILE_MAP_OUTPUT, + "\n\nPin Type Direction Polarity" + " Dest _HID Destination\n"); + } + + PrevDeviceName = Info->DeviceName; + + /* Setup various strings based upon the type (GpioInt or GpioIo) */ + + switch (Info->Type) + { + case AML_RESOURCE_GPIO_TYPE_INT: + + Type = "GpioInt"; + Direction = "-Interrupt-"; + Polarity = PolarityDecode[Info->Polarity]; + break; + + case AML_RESOURCE_GPIO_TYPE_IO: + + Type = "GpioIo "; + Direction = DirectionDecode[Info->Direction]; + Polarity = " "; + break; + + default: + continue; + } + + /* Emit the GPIO info */ + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%4.4X %s %s %s ", + Info->PinNumber, Type, Direction, Polarity); + + ParentPathname = NULL; + HidString = MpGetConnectionInfo (Info->Op, Info->PinIndex, + &Info->TargetNode, &ParentPathname); + if (HidString) + { + /* + * This is a Connection() field + * Attempt to find all references to the field. + */ + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%8s %-28s", + HidString, ParentPathname); + + MpXrefDevices (Info); + } + else + { + /* + * For Devices, attempt to get the _HID description string. + * Failing that (many _HIDs are not recognized), attempt to + * get the _DDN description string. + */ + HidString = MpGetParentDeviceHid (Info->Op, &Info->TargetNode, + &ParentPathname); + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%8s %-28s", + HidString, ParentPathname); + + /* Get the _HID description or _DDN string */ + + HidInfo = AcpiAhMatchHardwareId (HidString); + if (HidInfo) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s", + HidInfo->Description); + } + else if ((Description = MpGetDdnValue (ParentPathname))) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s (_DDN)", + Description); + } + } + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\n"); + ACPI_FREE (ParentPathname); + Info = Info->Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: MpEmitSerialInfo + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Emit the info about all Serial devices found during the + * compile or disassembly. + * + ******************************************************************************/ + +static void +MpEmitSerialInfo ( + void) +{ + ACPI_SERIAL_INFO *Info; + char *Type; + char *ParentPathname; + char *PrevDeviceName = NULL; + char *HidString; + const AH_DEVICE_ID *HidInfo; + const char *Description; + AML_RESOURCE *Resource; + + + /* Walk the constructed serial descriptor list */ + + Info = Gbl_SerialList; + while (Info) + { + Resource = Info->Resource; + switch (Resource->CommonSerialBus.Type) + { + case AML_RESOURCE_I2C_SERIALBUSTYPE: + Type = "I2C "; + break; + + case AML_RESOURCE_SPI_SERIALBUSTYPE: + Type = "SPI "; + break; + + case AML_RESOURCE_UART_SERIALBUSTYPE: + Type = "UART"; + break; + + default: + Type = "UNKN"; + break; + } + + HidString = MpGetHidViaNamestring (Info->DeviceName); + + /* Print header info for the controller itself */ + + if (!PrevDeviceName || + strcmp (PrevDeviceName, Info->DeviceName)) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\n\n%s Controller: ", + Type); + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%-8s %-28s", + HidString, Info->DeviceName); + + HidInfo = AcpiAhMatchHardwareId (HidString); + if (HidInfo) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s", + HidInfo->Description); + } + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\n\n"); + FlPrintFile (ASL_FILE_MAP_OUTPUT, + "Type Address Speed Dest _HID Destination\n"); + } + + PrevDeviceName = Info->DeviceName; + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%s %4.4X %8.8X ", + Type, Info->Address, Info->Speed); + + ParentPathname = NULL; + HidString = MpGetConnectionInfo (Info->Op, 0, &Info->TargetNode, + &ParentPathname); + if (HidString) + { + /* + * This is a Connection() field + * Attempt to find all references to the field. + */ + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%8s %-28s", + HidString, ParentPathname); + } + else + { + /* Normal resource template */ + + HidString = MpGetParentDeviceHid (Info->Op, &Info->TargetNode, + &ParentPathname); + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%8s %-28s", + HidString, ParentPathname); + + /* Get the _HID description or _DDN string */ + + HidInfo = AcpiAhMatchHardwareId (HidString); + if (HidInfo) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s", + HidInfo->Description); + } + else if ((Description = MpGetDdnValue (ParentPathname))) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s (_DDN)", + Description); + } + } + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\n"); + ACPI_FREE (ParentPathname); + Info = Info->Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: MpEmitDeviceTree + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Emit information about all devices within the ACPI namespace. + * + ******************************************************************************/ + +static void +MpEmitDeviceTree ( + void) +{ + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\n\nACPI Device Tree\n"); + FlPrintFile (ASL_FILE_MAP_OUTPUT, "----------------\n\n"); + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "Device Pathname " + "_HID Description\n\n"); + + /* Walk the namespace from the root */ + + (void) AcpiNsWalkNamespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, MpEmitOneDevice, NULL, NULL, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: MpEmitOneDevice + * + * PARAMETERS: ACPI_NAMESPACE_WALK callback + * + * RETURN: Status + * + * DESCRIPTION: Emit information about one ACPI device in the namespace. Used + * during dump of all device objects within the namespace. + * + ******************************************************************************/ + +static ACPI_STATUS +MpEmitOneDevice ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + char *DevicePathname; + char *DdnString; + char *HidString; + const AH_DEVICE_ID *HidInfo; + + + /* Device pathname */ + + DevicePathname = AcpiNsGetExternalPathname ( + ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle)); + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%-32s", DevicePathname); + + /* _HID or _DDN */ + + HidString = MpGetHidValue ( + ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle)); + FlPrintFile (ASL_FILE_MAP_OUTPUT, "%8s", HidString); + + HidInfo = AcpiAhMatchHardwareId (HidString); + if (HidInfo) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s", + HidInfo->Description); + } + else if ((DdnString = MpGetDdnValue (DevicePathname))) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // %s (_DDN)", DdnString); + } + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "\n"); + ACPI_FREE (DevicePathname); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: MpXrefDevices + * + * PARAMETERS: Info - A GPIO Info block + * + * RETURN: None + * + * DESCRIPTION: Cross-reference the parse tree and find all references to the + * specified GPIO device. + * + ******************************************************************************/ + +static void +MpXrefDevices ( + ACPI_GPIO_INFO *Info) +{ + + /* Walk the entire parse tree */ + + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + MpNamespaceXrefBegin, NULL, Info); + + if (!Info->References) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // **** No references in table"); + } +} + + +/******************************************************************************* + * + * FUNCTION: MpNamespaceXrefBegin + * + * PARAMETERS: WALK_PARSE_TREE callback + * + * RETURN: Status + * + * DESCRIPTION: Walk parse tree callback used to cross-reference GPIO pins. + * + ******************************************************************************/ + +static ACPI_STATUS +MpNamespaceXrefBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_GPIO_INFO *Info = ACPI_CAST_PTR (ACPI_GPIO_INFO, Context); + const ACPI_OPCODE_INFO *OpInfo; + char *DevicePathname; + ACPI_PARSE_OBJECT *ParentOp; + char *HidString; + + + ACPI_FUNCTION_TRACE_PTR (MpNamespaceXrefBegin, Op); + + /* + * If this node is the actual declaration of a name + * [such as the XXXX name in "Method (XXXX)"], + * we are not interested in it here. We only care about names that + * are references to other objects within the namespace and the + * parent objects of name declarations + */ + if (Op->Asl.CompileFlags & NODE_IS_NAME_DECLARATION) + { + return (AE_OK); + } + + /* We are only interested in opcodes that have an associated name */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + + if ((OpInfo->Flags & AML_NAMED) || + (OpInfo->Flags & AML_CREATE)) + { + return (AE_OK); + } + + if ((Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) && + (Op->Asl.ParseOpcode != PARSEOP_NAMESEG) && + (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)) + { + return (AE_OK); + } + + if (!Op->Asl.Node) + { + return (AE_OK); + } + + ParentOp = Op->Asl.Parent; + if (ParentOp->Asl.ParseOpcode == PARSEOP_FIELD) + { + return (AE_OK); + } + + if (Op->Asl.Node == Info->TargetNode) + { + while (ParentOp && (!ParentOp->Asl.Node)) + { + ParentOp = ParentOp->Asl.Parent; + } + + if (ParentOp) + { + DevicePathname = AcpiNsGetExternalPathname ( + ParentOp->Asl.Node); + + if (!Info->References) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " // References:"); + } + + HidString = MpGetHidViaNamestring (DevicePathname); + + FlPrintFile (ASL_FILE_MAP_OUTPUT, " %s [%s]", + DevicePathname, HidString); + + Info->References++; + + ACPI_FREE (DevicePathname); + } + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/aslmaputils.c b/third_party/lib/acpica/source/compiler/aslmaputils.c new file mode 100644 index 000000000..ebdab7daa --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmaputils.c @@ -0,0 +1,402 @@ +/****************************************************************************** + * + * Module Name: aslmaputils - Utilities for the resource descriptor/device maps + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "amlcode.h" + +/* This module used for application-level code only */ + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmaputils") + + +/******************************************************************************* + * + * FUNCTION: MpGetHidFromParseTree + * + * PARAMETERS: HidNode - Node for a _HID object + * + * RETURN: An _HID string value. Automatically converts _HID integers + * to strings. Never NULL. + * + * DESCRIPTION: Extract a _HID value from the parse tree, not the namespace. + * Used when a fully initialized namespace is not available. + * + ******************************************************************************/ + +char * +MpGetHidFromParseTree ( + ACPI_NAMESPACE_NODE *HidNode) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_PARSE_OBJECT *Arg; + char *HidString; + + + Op = HidNode->Op; + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_NAME: + + Arg = Op->Asl.Child; /* Get the NameSeg/NameString node */ + Arg = Arg->Asl.Next; /* First peer is the object to be associated with the name */ + + switch (Arg->Asl.ParseOpcode) + { + case PARSEOP_STRING_LITERAL: + + return (Arg->Asl.Value.String); + + case PARSEOP_INTEGER: + + /* Convert EISAID to a string */ + + HidString = UtStringCacheCalloc (ACPI_EISAID_STRING_SIZE); + AcpiExEisaIdToString (HidString, Arg->Asl.Value.Integer); + return (HidString); + + default: + + return ("UNKNOWN"); + } + + default: + return ("-No HID-"); + } +} + + +/******************************************************************************* + * + * FUNCTION: MpGetHidValue + * + * PARAMETERS: DeviceNode - Node for parent device + * + * RETURN: An _HID string value. Automatically converts _HID integers + * to strings. Never NULL. + * + * DESCRIPTION: Extract _HID value from within a device scope. Does not + * actually execute a method, just gets the string or integer + * value for the _HID. + * + ******************************************************************************/ + +char * +MpGetHidValue ( + ACPI_NAMESPACE_NODE *DeviceNode) +{ + ACPI_NAMESPACE_NODE *HidNode; + char *HidString; + ACPI_STATUS Status; + + + Status = AcpiNsGetNode (DeviceNode, METHOD_NAME__HID, + ACPI_NS_NO_UPSEARCH, &HidNode); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* If only partial namespace, get the _HID from the parse tree */ + + if (!HidNode->Object) + { + return (MpGetHidFromParseTree (HidNode)); + } + + /* Handle the different _HID flavors */ + + switch (HidNode->Type) + { + case ACPI_TYPE_STRING: + + return (HidNode->Object->String.Pointer); + + case ACPI_TYPE_INTEGER: + + /* Convert EISAID to a string */ + + HidString = UtStringCacheCalloc (ACPI_EISAID_STRING_SIZE); + AcpiExEisaIdToString (HidString, HidNode->Object->Integer.Value); + return (HidString); + + case ACPI_TYPE_METHOD: + + return ("-Method-"); + + default: + + FlPrintFile (ASL_FILE_MAP_OUTPUT, "BAD HID TYPE: %u", HidNode->Type); + break; + } + + +ErrorExit: + return ("-No HID-"); +} + + +/******************************************************************************* + * + * FUNCTION: MpGetHidViaNamestring + * + * PARAMETERS: DeviceName - Namepath for parent device + * + * RETURN: _HID string. Never NULL. + * + * DESCRIPTION: Get a _HID value via a device pathname (instead of just simply + * a device node.) + * + ******************************************************************************/ + +char * +MpGetHidViaNamestring ( + char *DeviceName) +{ + ACPI_NAMESPACE_NODE *DeviceNode; + ACPI_STATUS Status; + + + Status = AcpiNsGetNode (NULL, DeviceName, ACPI_NS_NO_UPSEARCH, + &DeviceNode); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + return (MpGetHidValue (DeviceNode)); + + +ErrorExit: + return ("-No HID-"); +} + + +/******************************************************************************* + * + * FUNCTION: MpGetParentDeviceHid + * + * PARAMETERS: Op - Parse Op to be examined + * TargetNode - Where the field node is returned + * ParentDeviceName - Where the node path is returned + * + * RETURN: _HID string. Never NULL. + * + * DESCRIPTION: Find the parent Device or Scope Op, get the full pathname to + * the parent, and get the _HID associated with the parent. + * + ******************************************************************************/ + +char * +MpGetParentDeviceHid ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE **TargetNode, + char **ParentDeviceName) +{ + ACPI_NAMESPACE_NODE *DeviceNode; + + + /* Find parent Device() or Scope() Op */ + + while (Op && + (Op->Asl.AmlOpcode != AML_DEVICE_OP) && + (Op->Asl.AmlOpcode != AML_SCOPE_OP)) + { + Op = Op->Asl.Parent; + } + + if (!Op) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " No_Parent_Device "); + goto ErrorExit; + } + + /* Get the full pathname to the device and the _HID */ + + DeviceNode = Op->Asl.Node; + if (!DeviceNode) + { + FlPrintFile (ASL_FILE_MAP_OUTPUT, " No_Device_Node "); + goto ErrorExit; + } + + *ParentDeviceName = AcpiNsGetExternalPathname (DeviceNode); + return (MpGetHidValue (DeviceNode)); + + +ErrorExit: + return ("-No HID-"); +} + + +/******************************************************************************* + * + * FUNCTION: MpGetDdnValue + * + * PARAMETERS: DeviceName - Namepath for parent device + * + * RETURN: _DDN description string. NULL on failure. + * + * DESCRIPTION: Execute the _DDN method for the device. + * + ******************************************************************************/ + +char * +MpGetDdnValue ( + char *DeviceName) +{ + ACPI_NAMESPACE_NODE *DeviceNode; + ACPI_NAMESPACE_NODE *DdnNode; + ACPI_STATUS Status; + + + Status = AcpiNsGetNode (NULL, DeviceName, ACPI_NS_NO_UPSEARCH, + &DeviceNode); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + Status = AcpiNsGetNode (DeviceNode, METHOD_NAME__DDN, ACPI_NS_NO_UPSEARCH, + &DdnNode); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + if ((DdnNode->Type != ACPI_TYPE_STRING) || + !DdnNode->Object) + { + goto ErrorExit; + } + + return (DdnNode->Object->String.Pointer); + + +ErrorExit: + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: MpGetConnectionInfo + * + * PARAMETERS: Op - Parse Op to be examined + * PinIndex - Index into GPIO PinList + * TargetNode - Where the field node is returned + * TargetName - Where the node path is returned + * + * RETURN: A substitute _HID string, indicating that the name is actually + * a field. NULL if the Op does not refer to a Connection. + * + * DESCRIPTION: Get the Field Unit that corresponds to the PinIndex after + * a Connection() invocation. + * + ******************************************************************************/ + +char * +MpGetConnectionInfo ( + ACPI_PARSE_OBJECT *Op, + UINT32 PinIndex, + ACPI_NAMESPACE_NODE **TargetNode, + char **TargetName) +{ + ACPI_PARSE_OBJECT *NextOp; + UINT32 i; + + + /* + * Handle Connection() here. Find the next named FieldUnit. + * Note: we look at the ParseOpcode for the compiler, look + * at the AmlOpcode for the disassembler. + */ + if ((Op->Asl.AmlOpcode == AML_INT_CONNECTION_OP) || + (Op->Asl.ParseOpcode == PARSEOP_CONNECTION)) + { + /* Find the correct field unit definition */ + + NextOp = Op; + for (i = 0; i <= PinIndex;) + { + NextOp = NextOp->Asl.Next; + while (NextOp && + (NextOp->Asl.ParseOpcode != PARSEOP_NAMESEG) && + (NextOp->Asl.AmlOpcode != AML_INT_NAMEDFIELD_OP)) + { + NextOp = NextOp->Asl.Next; + } + + if (!NextOp) + { + return ("UNKNOWN"); + } + + /* Add length of this field to the current pin index */ + + if (NextOp->Asl.ParseOpcode == PARSEOP_NAMESEG) + { + i += (UINT32) NextOp->Asl.Child->Asl.Value.Integer; + } + else /* AML_INT_NAMEDFIELD_OP */ + { + i += (UINT32) NextOp->Asl.Value.Integer; + } + } + + /* Return the node and pathname for the field unit */ + + *TargetNode = NextOp->Asl.Node; + *TargetName = AcpiNsGetExternalPathname (*TargetNode); + return ("-Field-"); + } + + return (NULL); +} diff --git a/third_party/lib/acpica/source/compiler/aslmessages.c b/third_party/lib/acpica/source/compiler/aslmessages.c new file mode 100644 index 000000000..8cf0e784d --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmessages.c @@ -0,0 +1,415 @@ +/****************************************************************************** + * + * Module Name: aslmessages.c - Compiler error/warning message strings + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmessages") + + +/* + * Strings for message reporting levels, must match error + * type string tables in aslmessages.c + */ +const char *AslErrorLevel [ASL_NUM_REPORT_LEVELS] = { + "Optimize", + "Remark ", + "Warning ", + "Warning ", + "Warning ", + "Error " +}; + +/* All lowercase versions for IDEs */ + +const char *AslErrorLevelIde [ASL_NUM_REPORT_LEVELS] = { + "optimize", + "remark ", + "warning ", + "warning ", + "warning ", + "error " +}; + + +/* + * Actual message strings for each compiler message ID. There are currently + * three distinct blocks of error messages (so that they can be expanded + * individually): + * Main ASL compiler + * Data Table compiler + * Preprocessor + * + * NOTE1: These tables must match the enum list of message IDs in the file + * aslmessages.h exactly. + * + * NOTE2: With the introduction of the -vw option to disable specific messages, + * new messages should only be added to the end of this list, so that values + * for existing messages are not disturbed. + */ + +/* ASL compiler */ + +const char *AslCompilerMsgs [] = +{ +/* The zeroth message is reserved */ "", +/* ASL_MSG_ALIGNMENT */ "Must be a multiple of alignment/granularity value", +/* ASL_MSG_ALPHANUMERIC_STRING */ "String must be entirely alphanumeric", +/* ASL_MSG_AML_NOT_IMPLEMENTED */ "Opcode is not implemented in compiler AML code generator", +/* ASL_MSG_ARG_COUNT_HI */ "Too many arguments", +/* ASL_MSG_ARG_COUNT_LO */ "Too few arguments", +/* ASL_MSG_ARG_INIT */ "Method argument is not initialized", +/* ASL_MSG_BACKWARDS_OFFSET */ "Invalid backwards offset", +/* ASL_MSG_BUFFER_LENGTH */ "Effective AML buffer length is zero", +/* ASL_MSG_CLOSE */ "Could not close file", +/* ASL_MSG_COMPILER_INTERNAL */ "Internal compiler error", +/* ASL_MSG_COMPILER_RESERVED */ "Use of compiler reserved name", +/* ASL_MSG_CONNECTION_MISSING */ "A Connection operator is required for this field SpaceId", +/* ASL_MSG_CONNECTION_INVALID */ "Invalid OpRegion SpaceId for use of Connection operator", +/* ASL_MSG_CONSTANT_EVALUATION */ "Could not evaluate constant expression", +/* ASL_MSG_CONSTANT_FOLDED */ "Constant expression evaluated and reduced", +/* ASL_MSG_CORE_EXCEPTION */ "From ACPICA Subsystem", +/* ASL_MSG_DEBUG_FILE_OPEN */ "Could not open debug file", +/* ASL_MSG_DEBUG_FILENAME */ "Could not create debug filename", +/* ASL_MSG_DEPENDENT_NESTING */ "Dependent function macros cannot be nested", +/* ASL_MSG_DMA_CHANNEL */ "Invalid DMA channel (must be 0-7)", +/* ASL_MSG_DMA_LIST */ "Too many DMA channels (8 max)", +/* ASL_MSG_DUPLICATE_CASE */ "Case value already specified", +/* ASL_MSG_DUPLICATE_ITEM */ "Duplicate value in list", +/* ASL_MSG_EARLY_EOF */ "Premature end-of-file reached", +/* ASL_MSG_ENCODING_LENGTH */ "Package length too long to encode", +/* ASL_MSG_EX_INTERRUPT_LIST */ "Too many interrupts (255 max)", +/* ASL_MSG_EX_INTERRUPT_LIST_MIN */ "Too few interrupts (1 minimum required)", +/* ASL_MSG_EX_INTERRUPT_NUMBER */ "Invalid interrupt number (must be 32 bits)", +/* ASL_MSG_FIELD_ACCESS_WIDTH */ "Access width is greater than region size", +/* ASL_MSG_FIELD_UNIT_ACCESS_WIDTH */ "Access width of Field Unit extends beyond region limit", +/* ASL_MSG_FIELD_UNIT_OFFSET */ "Field Unit extends beyond region limit", +/* ASL_MSG_GPE_NAME_CONFLICT */ "Name conflicts with a previous GPE method", +/* ASL_MSG_HID_LENGTH */ "_HID string must be exactly 7 or 8 characters", +/* ASL_MSG_HID_PREFIX */ "_HID prefix must be all uppercase or decimal digits", +/* ASL_MSG_HID_SUFFIX */ "_HID suffix must be all hex digits", +/* ASL_MSG_INCLUDE_FILE_OPEN */ "Could not open include file", +/* ASL_MSG_INPUT_FILE_OPEN */ "Could not open input file", +/* ASL_MSG_INTEGER_LENGTH */ "64-bit integer in 32-bit table, truncating (DSDT version < 2)", +/* ASL_MSG_INTEGER_OPTIMIZATION */ "Integer optimized to single-byte AML opcode", +/* ASL_MSG_INTERRUPT_LIST */ "Too many interrupts (16 max)", +/* ASL_MSG_INTERRUPT_NUMBER */ "Invalid interrupt number (must be 0-15)", +/* ASL_MSG_INVALID_ACCESS_SIZE */ "Invalid AccessSize (Maximum is 4 - QWord access)", +/* ASL_MSG_INVALID_ADDR_FLAGS */ "Invalid combination of Length and Min/Max fixed flags", +/* ASL_MSG_INVALID_CONSTANT_OP */ "Invalid operator in constant expression (not type 3/4/5)", +/* ASL_MSG_INVALID_EISAID */ "EISAID string must be of the form \"UUUXXXX\" (3 uppercase, 4 hex digits)", +/* ASL_MSG_INVALID_ESCAPE */ "Invalid or unknown escape sequence", +/* ASL_MSG_INVALID_GRAN_FIXED */ "Granularity must be zero for fixed Min/Max", +/* ASL_MSG_INVALID_GRANULARITY */ "Granularity must be zero or a power of two minus one", +/* ASL_MSG_INVALID_LENGTH */ "Length is larger than Min/Max window", +/* ASL_MSG_INVALID_LENGTH_FIXED */ "Length is not equal to fixed Min/Max window", +/* ASL_MSG_INVALID_MIN_MAX */ "Address Min is greater than Address Max", +/* ASL_MSG_INVALID_OPERAND */ "Invalid operand", +/* ASL_MSG_INVALID_PERFORMANCE */ "Invalid performance/robustness value", +/* ASL_MSG_INVALID_PRIORITY */ "Invalid priority value", +/* ASL_MSG_INVALID_STRING */ "Invalid Hex/Octal Escape - Non-ASCII or NULL", +/* ASL_MSG_INVALID_TARGET */ "Target operand not allowed in constant expression", +/* ASL_MSG_INVALID_TIME */ "Time parameter too long (255 max)", +/* ASL_MSG_INVALID_TYPE */ "Invalid type", +/* ASL_MSG_INVALID_UUID */ "UUID string must be of the form \"aabbccdd-eeff-gghh-iijj-kkllmmnnoopp\"", +/* ASL_MSG_ISA_ADDRESS */ "Maximum 10-bit ISA address (0x3FF)", +/* ASL_MSG_LEADING_ASTERISK */ "Invalid leading asterisk", +/* ASL_MSG_LIST_LENGTH_LONG */ "Initializer list longer than declared package length", +/* ASL_MSG_LIST_LENGTH_SHORT */ "Initializer list shorter than declared package length", +/* ASL_MSG_LISTING_FILE_OPEN */ "Could not open listing file", +/* ASL_MSG_LISTING_FILENAME */ "Could not create listing filename", +/* ASL_MSG_LOCAL_INIT */ "Method local variable is not initialized", +/* ASL_MSG_LOCAL_OUTSIDE_METHOD */ "Local or Arg used outside a control method", +/* ASL_MSG_LONG_LINE */ "Splitting long input line", +/* ASL_MSG_MEMORY_ALLOCATION */ "Memory allocation failure", +/* ASL_MSG_MISSING_ENDDEPENDENT */ "Missing EndDependentFn() macro in dependent resource list", +/* ASL_MSG_MISSING_STARTDEPENDENT */ "Missing StartDependentFn() macro in dependent resource list", +/* ASL_MSG_MULTIPLE_DEFAULT */ "More than one Default statement within Switch construct", +/* ASL_MSG_MULTIPLE_TYPES */ "Multiple types", +/* ASL_MSG_NAME_EXISTS */ "Name already exists in scope", +/* ASL_MSG_NAME_OPTIMIZATION */ "NamePath optimized", +/* ASL_MSG_NAMED_OBJECT_IN_WHILE */ "Creating a named object in a While loop", +/* ASL_MSG_NESTED_COMMENT */ "Nested comment found", +/* ASL_MSG_NO_CASES */ "No Case statements under Switch", +/* ASL_MSG_NO_REGION */ "_REG has no corresponding Operation Region", +/* ASL_MSG_NO_RETVAL */ "Called method returns no value", +/* ASL_MSG_NO_WHILE */ "No enclosing While statement", +/* ASL_MSG_NON_ASCII */ "Invalid characters found in file", +/* ASL_MSG_NON_ZERO */ "Operand evaluates to zero", +/* ASL_MSG_NOT_EXIST */ "Object does not exist", +/* ASL_MSG_NOT_FOUND */ "Object not found or not accessible from scope", +/* ASL_MSG_NOT_METHOD */ "Not a control method, cannot invoke", +/* ASL_MSG_NOT_PARAMETER */ "Not a parameter, used as local only", +/* ASL_MSG_NOT_REACHABLE */ "Object is not accessible from this scope", +/* ASL_MSG_NOT_REFERENCED */ "Object is not referenced", +/* ASL_MSG_NULL_DESCRIPTOR */ "Min/Max/Length/Gran are all zero, but no resource tag", +/* ASL_MSG_NULL_STRING */ "Invalid zero-length (null) string", +/* ASL_MSG_OPEN */ "Could not open file", +/* ASL_MSG_OUTPUT_FILE_OPEN */ "Could not open output AML file", +/* ASL_MSG_OUTPUT_FILENAME */ "Could not create output filename", +/* ASL_MSG_PACKAGE_LENGTH */ "Effective AML package length is zero", +/* ASL_MSG_PREPROCESSOR_FILENAME */ "Could not create preprocessor filename", +/* ASL_MSG_READ */ "Could not read file", +/* ASL_MSG_RECURSION */ "Recursive method call", +/* ASL_MSG_REGION_BUFFER_ACCESS */ "Host Operation Region requires BufferAcc access", +/* ASL_MSG_REGION_BYTE_ACCESS */ "Host Operation Region requires ByteAcc access", +/* ASL_MSG_RESERVED_ARG_COUNT_HI */ "Reserved method has too many arguments", +/* ASL_MSG_RESERVED_ARG_COUNT_LO */ "Reserved method has too few arguments", +/* ASL_MSG_RESERVED_METHOD */ "Reserved name must be a control method", +/* ASL_MSG_RESERVED_NO_RETURN_VAL */ "Reserved method should not return a value", +/* ASL_MSG_RESERVED_OPERAND_TYPE */ "Invalid object type for reserved name", +/* ASL_MSG_RESERVED_PACKAGE_LENGTH */ "Invalid package length for reserved name", +/* ASL_MSG_RESERVED_RETURN_VALUE */ "Reserved method must return a value", +/* ASL_MSG_RESERVED_USE */ "Invalid use of reserved name", +/* ASL_MSG_RESERVED_WORD */ "Use of reserved name", +/* ASL_MSG_RESOURCE_FIELD */ "Resource field name cannot be used as a target", +/* ASL_MSG_RESOURCE_INDEX */ "Missing ResourceSourceIndex (required)", +/* ASL_MSG_RESOURCE_LIST */ "Too many resource items (internal error)", +/* ASL_MSG_RESOURCE_SOURCE */ "Missing ResourceSource string (required)", +/* ASL_MSG_RESULT_NOT_USED */ "Result is not used, operator has no effect", +/* ASL_MSG_RETURN_TYPES */ "Not all control paths return a value", +/* ASL_MSG_SCOPE_FWD_REF */ "Forward references from Scope operator not allowed", +/* ASL_MSG_SCOPE_TYPE */ "Existing object has invalid type for Scope operator", +/* ASL_MSG_SEEK */ "Could not seek file", +/* ASL_MSG_SERIALIZED */ "Control Method marked Serialized", +/* ASL_MSG_SERIALIZED_REQUIRED */ "Control Method should be made Serialized", +/* ASL_MSG_SINGLE_NAME_OPTIMIZATION */ "NamePath optimized to NameSeg (uses run-time search path)", +/* ASL_MSG_SOME_NO_RETVAL */ "Called method may not always return a value", +/* ASL_MSG_STRING_LENGTH */ "String literal too long", +/* ASL_MSG_SWITCH_TYPE */ "Switch expression is not a static Integer/Buffer/String data type, defaulting to Integer", +/* ASL_MSG_SYNC_LEVEL */ "SyncLevel must be in the range 0-15", +/* ASL_MSG_SYNTAX */ "", +/* ASL_MSG_TABLE_SIGNATURE */ "Invalid Table Signature", +/* ASL_MSG_TAG_LARGER */ "ResourceTag larger than Field", +/* ASL_MSG_TAG_SMALLER */ "ResourceTag smaller than Field", +/* ASL_MSG_TIMEOUT */ "Result is not used, possible operator timeout will be missed", +/* ASL_MSG_TOO_MANY_TEMPS */ "Method requires too many temporary variables (_T_x)", +/* ASL_MSG_TRUNCATION */ "64-bit return value will be truncated to 32 bits (DSDT version < 2)", +/* ASL_MSG_UNKNOWN_RESERVED_NAME */ "Unknown reserved name", +/* ASL_MSG_UNREACHABLE_CODE */ "Statement is unreachable", +/* ASL_MSG_UNSUPPORTED */ "Unsupported feature", +/* ASL_MSG_UPPER_CASE */ "Non-hex letters must be upper case", +/* ASL_MSG_VENDOR_LIST */ "Too many vendor data bytes (7 max)", +/* ASL_MSG_WRITE */ "Could not write file", +/* ASL_MSG_RANGE */ "Constant out of range", +/* ASL_MSG_BUFFER_ALLOCATION */ "Could not allocate line buffer", +/* ASL_MSG_MISSING_DEPENDENCY */ "Missing dependency", +/* ASL_MSG_ILLEGAL_FORWARD_REF */ "Illegal forward reference within a method", +/* ASL_MSG_ILLEGAL_METHOD_REF */ "Illegal reference across two methods", +/* ASL_MSG_LOCAL_NOT_USED */ "Method Local is set but never used", +/* ASL_MSG_ARG_AS_LOCAL_NOT_USED */ "Method Argument (as a local) is set but never used", +/* ASL_MSG_ARG_NOT_USED */ "Method Argument is never used", +/* ASL_MSG_CONSTANT_REQUIRED */ "Non-reducible expression", +/* ASL_MSG_CROSS_TABLE_SCOPE */ "Illegal open scope on external object from within DSDT" +}; + +/* Table compiler */ + +const char *AslTableCompilerMsgs [] = +{ +/* ASL_MSG_BUFFER_ELEMENT */ "Invalid element in buffer initializer list", +/* ASL_MSG_DIVIDE_BY_ZERO */ "Expression contains divide-by-zero", +/* ASL_MSG_FLAG_VALUE */ "Flag value is too large", +/* ASL_MSG_INTEGER_SIZE */ "Integer too large for target", +/* ASL_MSG_INVALID_EXPRESSION */ "Invalid expression", +/* ASL_MSG_INVALID_FIELD_NAME */ "Invalid Field Name", +/* ASL_MSG_INVALID_HEX_INTEGER */ "Invalid hex integer constant", +/* ASL_MSG_OEM_TABLE */ "OEM table - unknown contents", +/* ASL_MSG_RESERVED_VALUE */ "Reserved field", +/* ASL_MSG_UNKNOWN_LABEL */ "Label is undefined", +/* ASL_MSG_UNKNOWN_SUBTABLE */ "Unknown subtable type", +/* ASL_MSG_UNKNOWN_TABLE */ "Unknown ACPI table signature", +/* ASL_MSG_ZERO_VALUE */ "Value must be non-zero" +}; + +/* Preprocessor */ + +const char *AslPreprocessorMsgs [] = +{ +/* ASL_MSG_DIRECTIVE_SYNTAX */ "Invalid directive syntax", +/* ASL_MSG_ENDIF_MISMATCH */ "Mismatched #endif", +/* ASL_MSG_ERROR_DIRECTIVE */ "#error", +/* ASL_MSG_EXISTING_NAME */ "Name is already defined", +/* ASL_MSG_INVALID_INVOCATION */ "Invalid macro invocation", +/* ASL_MSG_MACRO_SYNTAX */ "Invalid macro syntax", +/* ASL_MSG_TOO_MANY_ARGUMENTS */ "Too many macro arguments", +/* ASL_MSG_UNKNOWN_DIRECTIVE */ "Unknown directive", +/* ASL_MSG_UNKNOWN_PRAGMA */ "Unknown pragma", +/* ASL_MSG_WARNING_DIRECTIVE */ "#warning", +/* ASL_MSG_INCLUDE_FILE */ "Found a # preprocessor directive in ASL Include() file" +}; + + +/******************************************************************************* + * + * FUNCTION: AeDecodeMessageId + * + * PARAMETERS: MessageId - ASL message ID (exception code) to be + * formatted. Possibly fully encoded. + * + * RETURN: A string containing the exception message text. + * + * DESCRIPTION: This function validates and translates an ASL message ID into + * an ASCII string. + * + ******************************************************************************/ + +const char * +AeDecodeMessageId ( + UINT16 MessageId) +{ + UINT32 Index; + const char **MessageTable; + + + /* Main ASL Compiler messages */ + + if (MessageId <= ASL_MSG_MAIN_COMPILER_END) + { + MessageTable = AslCompilerMsgs; + Index = MessageId; + + if (Index >= ACPI_ARRAY_LENGTH (AslCompilerMsgs)) + { + return ("[Unknown ASL Compiler exception ID]"); + } + } + + /* Data Table Compiler messages */ + + else if (MessageId <= ASL_MSG_TABLE_COMPILER_END) + { + MessageTable = AslTableCompilerMsgs; + Index = MessageId - ASL_MSG_TABLE_COMPILER; + + if (Index >= ACPI_ARRAY_LENGTH (AslTableCompilerMsgs)) + { + return ("[Unknown Table Compiler exception ID]"); + } + } + + /* Preprocessor messages */ + + else if (MessageId <= ASL_MSG_PREPROCESSOR_END) + { + MessageTable = AslPreprocessorMsgs; + Index = MessageId - ASL_MSG_PREPROCESSOR; + + if (Index >= ACPI_ARRAY_LENGTH (AslPreprocessorMsgs)) + { + return ("[Unknown Preprocessor exception ID]"); + } + } + + /* Everything else is unknown */ + + else + { + return ("[Unknown exception/component ID]"); + } + + return (MessageTable[Index]); +} + + +/******************************************************************************* + * + * FUNCTION: AeDecodeExceptionLevel + * + * PARAMETERS: Level - The ASL error level to be decoded + * + * RETURN: A string containing the error level text + * + * DESCRIPTION: This function validates and translates an ASL error level into + * an ASCII string. + * + ******************************************************************************/ + +const char * +AeDecodeExceptionLevel ( + UINT8 Level) +{ + /* Range check on Level */ + + if (Level >= ACPI_ARRAY_LENGTH (AslErrorLevel)) + { + return ("Unknown exception level"); + } + + /* Differentiate the string type to be used (IDE is all lower case) */ + + if (Gbl_VerboseErrors) + { + return (AslErrorLevel[Level]); + } + + return (AslErrorLevelIde[Level]); +} + + +/******************************************************************************* + * + * FUNCTION: AeBuildFullExceptionCode + * + * PARAMETERS: Level - ASL error level + * MessageId - ASL exception code to be formatted + * + * RETURN: Fully encoded exception code + * + * DESCRIPTION: Build the full exception code from the error level and the + * actual message ID. + * + ******************************************************************************/ + +UINT16 +AeBuildFullExceptionCode ( + UINT8 Level, + UINT16 MessageId) +{ + + /* + * Error level is in the thousands slot (error/warning/remark, etc.) + * Error codes are 0 - 999 + */ + return (((Level + 1) * 1000) + MessageId); +} diff --git a/third_party/lib/acpica/source/compiler/aslmessages.h b/third_party/lib/acpica/source/compiler/aslmessages.h new file mode 100644 index 000000000..0ee063fa5 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmessages.h @@ -0,0 +1,280 @@ +/****************************************************************************** + * + * Module Name: aslmessages.h - Compiler error/warning messages + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ASLMESSAGES_H +#define __ASLMESSAGES_H + + +/* These values must match error type string tables in aslmessages.c */ + +typedef enum +{ + ASL_OPTIMIZATION = 0, + ASL_REMARK, + ASL_WARNING, + ASL_WARNING2, + ASL_WARNING3, + ASL_ERROR, + ASL_NUM_REPORT_LEVELS + +} ASL_MESSAGE_TYPES; + + +#define ASL_ERROR_LEVEL_LENGTH 8 /* Length of strings for types above */ + +/* + * Exception code blocks, 0 - 999 + * Available for new exception blocks: 600 - 999 + */ +#define ASL_MSG_MAIN_COMPILER 0 /* 0 - 299 */ +#define ASL_MSG_MAIN_COMPILER_END 299 + +#define ASL_MSG_TABLE_COMPILER 300 /* 300 - 499 */ +#define ASL_MSG_TABLE_COMPILER_END 499 + +#define ASL_MSG_PREPROCESSOR 500 /* 500 - 599 */ +#define ASL_MSG_PREPROCESSOR_END 599 + + +/* + * Values (message IDs) for all compiler messages. There are currently + * three distinct blocks of error messages (so that they can be expanded + * individually): + * Main ASL compiler + * Data Table compiler + * Preprocessor + * + * NOTE1: This list must match the tables of message strings in the file + * aslmessages.c exactly. + * + * NOTE2: With the introduction of the -vw option to disable specific + * messages, new messages should only be added to the end of these + * lists, so that values for existing messages are not disturbed. + */ +typedef enum +{ + ASL_MSG_RESERVED = ASL_MSG_MAIN_COMPILER, + + ASL_MSG_ALIGNMENT, + ASL_MSG_ALPHANUMERIC_STRING, + ASL_MSG_AML_NOT_IMPLEMENTED, + ASL_MSG_ARG_COUNT_HI, + ASL_MSG_ARG_COUNT_LO, + ASL_MSG_ARG_INIT, + ASL_MSG_BACKWARDS_OFFSET, + ASL_MSG_BUFFER_LENGTH, + ASL_MSG_CLOSE, + ASL_MSG_COMPILER_INTERNAL, + ASL_MSG_COMPILER_RESERVED, + ASL_MSG_CONNECTION_MISSING, + ASL_MSG_CONNECTION_INVALID, + ASL_MSG_CONSTANT_EVALUATION, + ASL_MSG_CONSTANT_FOLDED, + ASL_MSG_CORE_EXCEPTION, + ASL_MSG_DEBUG_FILE_OPEN, + ASL_MSG_DEBUG_FILENAME, + ASL_MSG_DEPENDENT_NESTING, + ASL_MSG_DMA_CHANNEL, + ASL_MSG_DMA_LIST, + ASL_MSG_DUPLICATE_CASE, + ASL_MSG_DUPLICATE_ITEM, + ASL_MSG_EARLY_EOF, + ASL_MSG_ENCODING_LENGTH, + ASL_MSG_EX_INTERRUPT_LIST, + ASL_MSG_EX_INTERRUPT_LIST_MIN, + ASL_MSG_EX_INTERRUPT_NUMBER, + ASL_MSG_FIELD_ACCESS_WIDTH, + ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, + ASL_MSG_FIELD_UNIT_OFFSET, + ASL_MSG_GPE_NAME_CONFLICT, + ASL_MSG_HID_LENGTH, + ASL_MSG_HID_PREFIX, + ASL_MSG_HID_SUFFIX, + ASL_MSG_INCLUDE_FILE_OPEN, + ASL_MSG_INPUT_FILE_OPEN, + ASL_MSG_INTEGER_LENGTH, + ASL_MSG_INTEGER_OPTIMIZATION, + ASL_MSG_INTERRUPT_LIST, + ASL_MSG_INTERRUPT_NUMBER, + ASL_MSG_INVALID_ACCESS_SIZE, + ASL_MSG_INVALID_ADDR_FLAGS, + ASL_MSG_INVALID_CONSTANT_OP, + ASL_MSG_INVALID_EISAID, + ASL_MSG_INVALID_ESCAPE, + ASL_MSG_INVALID_GRAN_FIXED, + ASL_MSG_INVALID_GRANULARITY, + ASL_MSG_INVALID_LENGTH, + ASL_MSG_INVALID_LENGTH_FIXED, + ASL_MSG_INVALID_MIN_MAX, + ASL_MSG_INVALID_OPERAND, + ASL_MSG_INVALID_PERFORMANCE, + ASL_MSG_INVALID_PRIORITY, + ASL_MSG_INVALID_STRING, + ASL_MSG_INVALID_TARGET, + ASL_MSG_INVALID_TIME, + ASL_MSG_INVALID_TYPE, + ASL_MSG_INVALID_UUID, + ASL_MSG_ISA_ADDRESS, + ASL_MSG_LEADING_ASTERISK, + ASL_MSG_LIST_LENGTH_LONG, + ASL_MSG_LIST_LENGTH_SHORT, + ASL_MSG_LISTING_FILE_OPEN, + ASL_MSG_LISTING_FILENAME, + ASL_MSG_LOCAL_INIT, + ASL_MSG_LOCAL_OUTSIDE_METHOD, + ASL_MSG_LONG_LINE, + ASL_MSG_MEMORY_ALLOCATION, + ASL_MSG_MISSING_ENDDEPENDENT, + ASL_MSG_MISSING_STARTDEPENDENT, + ASL_MSG_MULTIPLE_DEFAULT, + ASL_MSG_MULTIPLE_TYPES, + ASL_MSG_NAME_EXISTS, + ASL_MSG_NAME_OPTIMIZATION, + ASL_MSG_NAMED_OBJECT_IN_WHILE, + ASL_MSG_NESTED_COMMENT, + ASL_MSG_NO_CASES, + ASL_MSG_NO_REGION, + ASL_MSG_NO_RETVAL, + ASL_MSG_NO_WHILE, + ASL_MSG_NON_ASCII, + ASL_MSG_NON_ZERO, + ASL_MSG_NOT_EXIST, + ASL_MSG_NOT_FOUND, + ASL_MSG_NOT_METHOD, + ASL_MSG_NOT_PARAMETER, + ASL_MSG_NOT_REACHABLE, + ASL_MSG_NOT_REFERENCED, + ASL_MSG_NULL_DESCRIPTOR, + ASL_MSG_NULL_STRING, + ASL_MSG_OPEN, + ASL_MSG_OUTPUT_FILE_OPEN, + ASL_MSG_OUTPUT_FILENAME, + ASL_MSG_PACKAGE_LENGTH, + ASL_MSG_PREPROCESSOR_FILENAME, + ASL_MSG_READ, + ASL_MSG_RECURSION, + ASL_MSG_REGION_BUFFER_ACCESS, + ASL_MSG_REGION_BYTE_ACCESS, + ASL_MSG_RESERVED_ARG_COUNT_HI, + ASL_MSG_RESERVED_ARG_COUNT_LO, + ASL_MSG_RESERVED_METHOD, + ASL_MSG_RESERVED_NO_RETURN_VAL, + ASL_MSG_RESERVED_OPERAND_TYPE, + ASL_MSG_RESERVED_PACKAGE_LENGTH, + ASL_MSG_RESERVED_RETURN_VALUE, + ASL_MSG_RESERVED_USE, + ASL_MSG_RESERVED_WORD, + ASL_MSG_RESOURCE_FIELD, + ASL_MSG_RESOURCE_INDEX, + ASL_MSG_RESOURCE_LIST, + ASL_MSG_RESOURCE_SOURCE, + ASL_MSG_RESULT_NOT_USED, + ASL_MSG_RETURN_TYPES, + ASL_MSG_SCOPE_FWD_REF, + ASL_MSG_SCOPE_TYPE, + ASL_MSG_SEEK, + ASL_MSG_SERIALIZED, + ASL_MSG_SERIALIZED_REQUIRED, + ASL_MSG_SINGLE_NAME_OPTIMIZATION, + ASL_MSG_SOME_NO_RETVAL, + ASL_MSG_STRING_LENGTH, + ASL_MSG_SWITCH_TYPE, + ASL_MSG_SYNC_LEVEL, + ASL_MSG_SYNTAX, + ASL_MSG_TABLE_SIGNATURE, + ASL_MSG_TAG_LARGER, + ASL_MSG_TAG_SMALLER, + ASL_MSG_TIMEOUT, + ASL_MSG_TOO_MANY_TEMPS, + ASL_MSG_TRUNCATION, + ASL_MSG_UNKNOWN_RESERVED_NAME, + ASL_MSG_UNREACHABLE_CODE, + ASL_MSG_UNSUPPORTED, + ASL_MSG_UPPER_CASE, + ASL_MSG_VENDOR_LIST, + ASL_MSG_WRITE, + ASL_MSG_RANGE, + ASL_MSG_BUFFER_ALLOCATION, + ASL_MSG_MISSING_DEPENDENCY, + ASL_MSG_ILLEGAL_FORWARD_REF, + ASL_MSG_ILLEGAL_METHOD_REF, + ASL_MSG_LOCAL_NOT_USED, + ASL_MSG_ARG_AS_LOCAL_NOT_USED, + ASL_MSG_ARG_NOT_USED, + ASL_MSG_CONSTANT_REQUIRED, + ASL_MSG_CROSS_TABLE_SCOPE, + + /* These messages are used by the Data Table compiler only */ + + ASL_MSG_BUFFER_ELEMENT = ASL_MSG_TABLE_COMPILER, + ASL_MSG_DIVIDE_BY_ZERO, + ASL_MSG_FLAG_VALUE, + ASL_MSG_INTEGER_SIZE, + ASL_MSG_INVALID_EXPRESSION, + ASL_MSG_INVALID_FIELD_NAME, + ASL_MSG_INVALID_HEX_INTEGER, + ASL_MSG_OEM_TABLE, + ASL_MSG_RESERVED_VALUE, + ASL_MSG_UNKNOWN_LABEL, + ASL_MSG_UNKNOWN_SUBTABLE, + ASL_MSG_UNKNOWN_TABLE, + ASL_MSG_ZERO_VALUE, + + /* These messages are used by the Preprocessor only */ + + ASL_MSG_DIRECTIVE_SYNTAX = ASL_MSG_PREPROCESSOR, + ASL_MSG_ENDIF_MISMATCH, + ASL_MSG_ERROR_DIRECTIVE, + ASL_MSG_EXISTING_NAME, + ASL_MSG_INVALID_INVOCATION, + ASL_MSG_MACRO_SYNTAX, + ASL_MSG_TOO_MANY_ARGUMENTS, + ASL_MSG_UNKNOWN_DIRECTIVE, + ASL_MSG_UNKNOWN_PRAGMA, + ASL_MSG_WARNING_DIRECTIVE, + ASL_MSG_INCLUDE_FILE + +} ASL_MESSAGE_IDS; + + +#endif /* __ASLMESSAGES_H */ diff --git a/third_party/lib/acpica/source/compiler/aslmethod.c b/third_party/lib/acpica/source/compiler/aslmethod.c new file mode 100644 index 000000000..a5c02b1cf --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslmethod.c @@ -0,0 +1,734 @@ +/****************************************************************************** + * + * Module Name: aslmethod.c - Control method analysis walk + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acparser.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslmethod") + + +/* Local prototypes */ + +void +MtCheckNamedObjectInMethod ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo); + + +/******************************************************************************* + * + * FUNCTION: MtMethodAnalysisWalkBegin + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback for the analysis walk. Check methods for: + * 1) Initialized local variables + * 2) Valid arguments + * 3) Return types + * + ******************************************************************************/ + +ACPI_STATUS +MtMethodAnalysisWalkBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; + ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; + ACPI_PARSE_OBJECT *Next; + UINT32 RegisterNumber; + UINT32 i; + char LocalName[] = "Local0"; + char ArgName[] = "Arg0"; + ACPI_PARSE_OBJECT *ArgNode; + ACPI_PARSE_OBJECT *NextType; + ACPI_PARSE_OBJECT *NextParamType; + UINT8 ActualArgs = 0; + + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_METHOD: + + TotalMethods++; + + /* Create and init method info */ + + MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO)); + MethodInfo->Next = WalkInfo->MethodStack; + MethodInfo->Op = Op; + + WalkInfo->MethodStack = MethodInfo; + + /* + * Special handling for _PSx methods. Dependency rules (same scope): + * + * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3 + * 2) _PS1/_PS2/_PS3: A _PS0 must exist + */ + if (ACPI_COMPARE_NAME (METHOD_NAME__PS0, Op->Asl.NameSeg)) + { + /* For _PS0, one of _PS1/_PS2/_PS3 must exist */ + + if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) && + (!ApFindNameInScope (METHOD_NAME__PS2, Op)) && + (!ApFindNameInScope (METHOD_NAME__PS3, Op))) + { + AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, + "_PS0 requires one of _PS1/_PS2/_PS3 in same scope"); + } + } + else if ( + ACPI_COMPARE_NAME (METHOD_NAME__PS1, Op->Asl.NameSeg) || + ACPI_COMPARE_NAME (METHOD_NAME__PS2, Op->Asl.NameSeg) || + ACPI_COMPARE_NAME (METHOD_NAME__PS3, Op->Asl.NameSeg)) + { + /* For _PS1/_PS2/_PS3, a _PS0 must exist */ + + if (!ApFindNameInScope (METHOD_NAME__PS0, Op)) + { + sprintf (MsgBuffer, + "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg); + + AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, + MsgBuffer); + } + } + + /* Get the name node */ + + Next = Op->Asl.Child; + + /* Get the NumArguments node */ + + Next = Next->Asl.Next; + MethodInfo->NumArguments = (UINT8) + (((UINT8) Next->Asl.Value.Integer) & 0x07); + + /* Get the SerializeRule and SyncLevel nodes, ignored here */ + + Next = Next->Asl.Next; + MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer; + + Next = Next->Asl.Next; + ArgNode = Next; + + /* Get the ReturnType node */ + + Next = Next->Asl.Next; + + NextType = Next->Asl.Child; + while (NextType) + { + /* Get and map each of the ReturnTypes */ + + MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType); + NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + NextType = NextType->Asl.Next; + } + + /* Get the ParameterType node */ + + Next = Next->Asl.Next; + + NextType = Next->Asl.Child; + while (NextType) + { + if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + NextParamType = NextType->Asl.Child; + while (NextParamType) + { + MethodInfo->ValidArgTypes[ActualArgs] |= + AnMapObjTypeToBtype (NextParamType); + + NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + NextParamType = NextParamType->Asl.Next; + } + } + else + { + MethodInfo->ValidArgTypes[ActualArgs] = + AnMapObjTypeToBtype (NextType); + + NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + ActualArgs++; + } + + NextType = NextType->Asl.Next; + } + + if ((MethodInfo->NumArguments) && + (MethodInfo->NumArguments != ActualArgs)) + { + /* error: Param list did not match number of args */ + } + + /* Allow numarguments == 0 for Function() */ + + if ((!MethodInfo->NumArguments) && (ActualArgs)) + { + MethodInfo->NumArguments = ActualArgs; + ArgNode->Asl.Value.Integer |= ActualArgs; + } + + /* + * Actual arguments are initialized at method entry. + * All other ArgX "registers" can be used as locals, so we + * track their initialization. + */ + for (i = 0; i < MethodInfo->NumArguments; i++) + { + MethodInfo->ArgInitialized[i] = TRUE; + } + break; + + case PARSEOP_METHODCALL: + + if (MethodInfo && + (Op->Asl.Node == MethodInfo->Op->Asl.Node)) + { + AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName); + } + break; + + case PARSEOP_LOCAL0: + case PARSEOP_LOCAL1: + case PARSEOP_LOCAL2: + case PARSEOP_LOCAL3: + case PARSEOP_LOCAL4: + case PARSEOP_LOCAL5: + case PARSEOP_LOCAL6: + case PARSEOP_LOCAL7: + + if (!MethodInfo) + { + /* + * Local was used outside a control method, or there was an error + * in the method declaration. + */ + AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, + Op, Op->Asl.ExternalName); + return (AE_ERROR); + } + + RegisterNumber = (Op->Asl.AmlOpcode & 0x0007); + + /* + * If the local is being used as a target, mark the local + * initialized + */ + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + MethodInfo->LocalInitialized[RegisterNumber] = TRUE; + } + + /* + * Otherwise, this is a reference, check if the local + * has been previously initialized. + * + * The only operator that accepts an uninitialized value is ObjectType() + */ + else if ((!MethodInfo->LocalInitialized[RegisterNumber]) && + (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) + { + LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30); + AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName); + } + break; + + case PARSEOP_ARG0: + case PARSEOP_ARG1: + case PARSEOP_ARG2: + case PARSEOP_ARG3: + case PARSEOP_ARG4: + case PARSEOP_ARG5: + case PARSEOP_ARG6: + + if (!MethodInfo) + { + /* + * Arg was used outside a control method, or there was an error + * in the method declaration. + */ + AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, + Op, Op->Asl.ExternalName); + return (AE_ERROR); + } + + RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8; + ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30); + + /* + * If the Arg is being used as a target, mark the local + * initialized + */ + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + MethodInfo->ArgInitialized[RegisterNumber] = TRUE; + } + + /* + * Otherwise, this is a reference, check if the Arg + * has been previously initialized. + * + * The only operator that accepts an uninitialized value is ObjectType() + */ + else if ((!MethodInfo->ArgInitialized[RegisterNumber]) && + (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) + { + AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName); + } + + /* Flag this arg if it is not a "real" argument to the method */ + + if (RegisterNumber >= MethodInfo->NumArguments) + { + AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName); + } + break; + + case PARSEOP_RETURN: + + if (!MethodInfo) + { + /* + * Probably was an error in the method declaration, + * no additional error here + */ + ACPI_WARNING ((AE_INFO, "%p, No parent method", Op)); + return (AE_ERROR); + } + + /* + * A child indicates a possible return value. A simple Return or + * Return() is marked with NODE_IS_NULL_RETURN by the parser so + * that it is not counted as a "real" return-with-value, although + * the AML code that is actually emitted is Return(0). The AML + * definition of Return has a required parameter, so we are + * forced to convert a null return to Return(0). + */ + if ((Op->Asl.Child) && + (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN))) + { + MethodInfo->NumReturnWithValue++; + } + else + { + MethodInfo->NumReturnNoValue++; + } + break; + + case PARSEOP_BREAK: + case PARSEOP_CONTINUE: + + Next = Op->Asl.Parent; + while (Next) + { + if (Next->Asl.ParseOpcode == PARSEOP_WHILE) + { + break; + } + Next = Next->Asl.Parent; + } + + if (!Next) + { + AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL); + } + break; + + case PARSEOP_STALL: + + /* We can range check if the argument is an integer */ + + if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && + (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL); + } + break; + + case PARSEOP_DEVICE: + + Next = Op->Asl.Child; + + if (!ApFindNameInScope (METHOD_NAME__HID, Next) && + !ApFindNameInScope (METHOD_NAME__ADR, Next)) + { + AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, + "Device object requires a _HID or _ADR in same scope"); + } + break; + + case PARSEOP_EVENT: + case PARSEOP_MUTEX: + case PARSEOP_OPERATIONREGION: + case PARSEOP_POWERRESOURCE: + case PARSEOP_PROCESSOR: + case PARSEOP_THERMALZONE: + + /* + * The first operand is a name to be created in the namespace. + * Check against the reserved list. + */ + i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); + if (i < ACPI_VALID_RESERVED_NAME_MAX) + { + AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, + Op, Op->Asl.ExternalName); + } + break; + + case PARSEOP_NAME: + + /* Typecheck any predefined names statically defined with Name() */ + + ApCheckForPredefinedObject (Op, Op->Asl.NameSeg); + + /* Special typechecking for _HID */ + + if (!strcmp (METHOD_NAME__HID, Op->Asl.NameSeg)) + { + Next = Op->Asl.Child->Asl.Next; + AnCheckId (Next, ASL_TYPE_HID); + } + + /* Special typechecking for _CID */ + + else if (!strcmp (METHOD_NAME__CID, Op->Asl.NameSeg)) + { + Next = Op->Asl.Child->Asl.Next; + + if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || + (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) + { + Next = Next->Asl.Child; + while (Next) + { + AnCheckId (Next, ASL_TYPE_CID); + Next = Next->Asl.Next; + } + } + else + { + AnCheckId (Next, ASL_TYPE_CID); + } + } + + break; + + default: + + break; + } + + /* Check for named object creation within a non-serialized method */ + + MtCheckNamedObjectInMethod (Op, MethodInfo); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: MtCheckNamedObjectInMethod + * + * PARAMETERS: Op - Current parser op + * MethodInfo - Info for method being parsed + * + * RETURN: None + * + * DESCRIPTION: Detect if a non-serialized method is creating a named object, + * which could possibly cause problems if two threads execute + * the method concurrently. Emit a remark in this case. + * + ******************************************************************************/ + +void +MtCheckNamedObjectInMethod ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo) +{ + const ACPI_OPCODE_INFO *OpInfo; + + + /* We don't care about actual method declarations or scopes */ + + if ((Op->Asl.AmlOpcode == AML_METHOD_OP) || + (Op->Asl.AmlOpcode == AML_SCOPE_OP)) + { + return; + } + + /* Determine if we are creating a named object */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + if (OpInfo->Class == AML_CLASS_NAMED_OBJECT) + { + /* + * If we have a named object created within a non-serialized method, + * emit a remark that the method should be serialized. + * + * Reason: If a thread blocks within the method for any reason, and + * another thread enters the method, the method will fail because an + * attempt will be made to create the same object twice. + */ + if (MethodInfo && !MethodInfo->ShouldBeSerialized) + { + AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op, + "due to creation of named objects within"); + + /* Emit message only ONCE per method */ + + MethodInfo->ShouldBeSerialized = TRUE; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: MtMethodAnalysisWalkEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback for analysis walk. Complete method + * return analysis. + * + ******************************************************************************/ + +ACPI_STATUS +MtMethodAnalysisWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; + ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; + + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_METHOD: + case PARSEOP_RETURN: + + if (!MethodInfo) + { + printf ("No method info for method! [%s]\n", Op->Asl.Namepath); + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, + "No method info for this method"); + + CmCleanupAndExit (); + return (AE_AML_INTERNAL); + } + break; + + default: + + break; + } + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_METHOD: + + WalkInfo->MethodStack = MethodInfo->Next; + + /* + * Check if there is no return statement at the end of the + * method AND we can actually get there -- i.e., the execution + * of the method can possibly terminate without a return statement. + */ + if ((!AnLastStatementIsReturn (Op)) && + (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT))) + { + /* + * No return statement, and execution can possibly exit + * via this path. This is equivalent to Return () + */ + MethodInfo->NumReturnNoValue++; + } + + /* + * Check for case where some return statements have a return value + * and some do not. Exit without a return statement is a return with + * no value + */ + if (MethodInfo->NumReturnNoValue && + MethodInfo->NumReturnWithValue) + { + AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op, + Op->Asl.ExternalName); + } + + /* + * If there are any RETURN() statements with no value, or there is a + * control path that allows the method to exit without a return value, + * we mark the method as a method that does not return a value. This + * knowledge can be used to check method invocations that expect a + * returned value. + */ + if (MethodInfo->NumReturnNoValue) + { + if (MethodInfo->NumReturnWithValue) + { + Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL; + } + else + { + Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL; + } + } + + /* + * Check predefined method names for correct return behavior + * and correct number of arguments. Also, some special checks + * For GPE and _REG methods. + */ + if (ApCheckForPredefinedMethod (Op, MethodInfo)) + { + /* Special check for two names like _L01 and _E01 in same scope */ + + ApCheckForGpeNameConflict (Op); + + /* + * Special check for _REG: Must have an operation region definition + * within the same scope! + */ + ApCheckRegMethod (Op); + } + + ACPI_FREE (MethodInfo); + break; + + case PARSEOP_NAME: + + /* Special check for two names like _L01 and _E01 in same scope */ + + ApCheckForGpeNameConflict (Op); + break; + + case PARSEOP_RETURN: + + /* + * If the parent is a predefined method name, attempt to typecheck + * the return value. Only static types can be validated. + */ + ApCheckPredefinedReturnValue (Op, MethodInfo); + + /* + * The parent block does not "exit" and continue execution -- the + * method is terminated here with the Return() statement. + */ + Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; + + /* Used in the "typing" pass later */ + + Op->Asl.ParentMethod = MethodInfo->Op; + + /* + * If there is a peer node after the return statement, then this + * node is unreachable code -- i.e., it won't be executed because of + * the preceding Return() statement. + */ + if (Op->Asl.Next) + { + AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, + Op->Asl.Next, NULL); + } + break; + + case PARSEOP_IF: + + if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && + (Op->Asl.Next) && + (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE)) + { + /* + * This IF has a corresponding ELSE. The IF block has no exit, + * (it contains an unconditional Return) + * mark the ELSE block to remember this fact. + */ + Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT; + } + break; + + case PARSEOP_ELSE: + + if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && + (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT)) + { + /* + * This ELSE block has no exit and the corresponding IF block + * has no exit either. Therefore, the parent node has no exit. + */ + Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; + } + break; + + + default: + + if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && + (Op->Asl.Parent)) + { + /* If this node has no exit, then the parent has no exit either */ + + Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; + } + break; + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/aslnamesp.c b/third_party/lib/acpica/source/compiler/aslnamesp.c new file mode 100644 index 000000000..9a2bc1497 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslnamesp.c @@ -0,0 +1,429 @@ +/****************************************************************************** + * + * Module Name: aslnamesp - Namespace output file generation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslnamesp") + +/* Local prototypes */ + +static ACPI_STATUS +NsDoOneNamespaceObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +NsDoOnePathname ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/******************************************************************************* + * + * FUNCTION: NsSetupNamespaceListing + * + * PARAMETERS: Handle - local file handle + * + * RETURN: None + * + * DESCRIPTION: Set the namespace output file to the input handle + * + ******************************************************************************/ + +void +NsSetupNamespaceListing ( + void *Handle) +{ + + Gbl_NsOutputFlag = TRUE; + Gbl_Files[ASL_FILE_NAMESPACE_OUTPUT].Handle = Handle; +} + + +/******************************************************************************* + * + * FUNCTION: NsDisplayNamespace + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Walk the namespace an display information about each node + * in the tree. Information is written to the optional + * namespace output file. + * + ******************************************************************************/ + +ACPI_STATUS +NsDisplayNamespace ( + void) +{ + ACPI_STATUS Status; + + + if (!Gbl_NsOutputFlag) + { + return (AE_OK); + } + + Gbl_NumNamespaceObjects = 0; + + /* File header */ + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "Contents of ACPI Namespace\n\n"); + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "Count Depth Name - Type\n\n"); + + /* Walk entire namespace from the root */ + + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, NsDoOneNamespaceObject, NULL, + NULL, NULL); + + /* Print the full pathname for each namespace node */ + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "\nNamespace pathnames\n\n"); + + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, NsDoOnePathname, NULL, + NULL, NULL); + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: NsDoOneNamespaceObject + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Dump a namespace object to the namespace output file. + * Called during the walk of the namespace to dump all objects. + * + ******************************************************************************/ + +static ACPI_STATUS +NsDoOneNamespaceObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PARSE_OBJECT *Op; + + + Gbl_NumNamespaceObjects++; + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "%5u [%u] %*s %4.4s - %s", + Gbl_NumNamespaceObjects, Level, (Level * 3), " ", + &Node->Name, AcpiUtGetTypeName (Node->Type)); + + Op = Node->Op; + ObjDesc = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Node->Object); + + if (!Op) + { + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "\n"); + return (AE_OK); + } + + + if ((ObjDesc) && + (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_OPERAND)) + { + switch (Node->Type) + { + case ACPI_TYPE_INTEGER: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Initial Value 0x%8.8X%8.8X]", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_STRING: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Initial Value \"%s\"]", + ObjDesc->String.Pointer); + break; + + default: + + /* Nothing to do for other types */ + + break; + } + + } + else + { + switch (Node->Type) + { + case ACPI_TYPE_INTEGER: + + if (Op->Asl.ParseOpcode == PARSEOP_NAME) + { + Op = Op->Asl.Child; + } + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESTRING)) + { + Op = Op->Asl.Next; + } + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Initial Value 0x%8.8X%8.8X]", + ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); + break; + + case ACPI_TYPE_STRING: + + if (Op->Asl.ParseOpcode == PARSEOP_NAME) + { + Op = Op->Asl.Child; + } + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESTRING)) + { + Op = Op->Asl.Next; + } + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Initial Value \"%s\"]", + Op->Asl.Value.String); + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESTRING)) + { + Op = Op->Asl.Child; + } + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Offset 0x%04X Length 0x%04X bits]", + Op->Asl.Parent->Asl.ExtraValue, (UINT32) Op->Asl.Value.Integer); + break; + + case ACPI_TYPE_BUFFER_FIELD: + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_CREATEBYTEFIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, " [BYTE ( 8 bit)]"); + break; + + case PARSEOP_CREATEDWORDFIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, " [DWORD (32 bit)]"); + break; + + case PARSEOP_CREATEQWORDFIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, " [QWORD (64 bit)]"); + break; + + case PARSEOP_CREATEWORDFIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, " [WORD (16 bit)]"); + break; + + case PARSEOP_CREATEBITFIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, " [BIT ( 1 bit)]"); + break; + + case PARSEOP_CREATEFIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, " [Arbitrary Bit Field]"); + break; + + default: + + break; + + } + break; + + case ACPI_TYPE_PACKAGE: + + if (Op->Asl.ParseOpcode == PARSEOP_NAME) + { + Op = Op->Asl.Child; + } + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESTRING)) + { + Op = Op->Asl.Next; + } + + Op = Op->Asl.Child; + + if ((Op->Asl.ParseOpcode == PARSEOP_BYTECONST) || + (Op->Asl.ParseOpcode == PARSEOP_RAW_DATA)) + { + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Initial Length 0x%.2X elements]", + Op->Asl.Value.Integer); + } + break; + + case ACPI_TYPE_BUFFER: + + if (Op->Asl.ParseOpcode == PARSEOP_NAME) + { + Op = Op->Asl.Child; + } + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESTRING)) + { + Op = Op->Asl.Next; + } + + Op = Op->Asl.Child; + + if (Op && (Op->Asl.ParseOpcode == PARSEOP_INTEGER)) + { + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Initial Length 0x%.2X bytes]", + Op->Asl.Value.Integer); + } + break; + + case ACPI_TYPE_METHOD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Code Length 0x%.4X bytes]", + Op->Asl.AmlSubtreeLength); + break; + + case ACPI_TYPE_LOCAL_RESOURCE: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Desc Offset 0x%.4X Bytes]", Node->Value); + break; + + case ACPI_TYPE_LOCAL_RESOURCE_FIELD: + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + " [Field Offset 0x%.4X Bits 0x%.4X Bytes] ", + Node->Value, Node->Value / 8); + + if (Node->Flags & ANOBJ_IS_REFERENCED) + { + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + "Referenced"); + } + else + { + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, + "Name not referenced"); + } + break; + + default: + + /* Nothing to do for other types */ + + break; + } + } + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "\n"); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: NsDoOnePathname + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Print the full pathname for a namespace node. + * + ******************************************************************************/ + +static ACPI_STATUS +NsDoOnePathname ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_STATUS Status; + ACPI_BUFFER TargetPath; + + + TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (Node, &TargetPath, FALSE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + FlPrintFile (ASL_FILE_NAMESPACE_OUTPUT, "%s\n", TargetPath.Pointer); + ACPI_FREE (TargetPath.Pointer); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/asloffset.c b/third_party/lib/acpica/source/compiler/asloffset.c new file mode 100644 index 000000000..0e55c6b85 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asloffset.c @@ -0,0 +1,472 @@ +/****************************************************************************** + * + * Module Name: asloffset - Generate a C "offset table" for BIOS use. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asloffset") + + +/* Local prototypes */ + +static void +LsEmitOffsetTableEntry ( + UINT32 FileId, + ACPI_NAMESPACE_NODE *Node, + UINT32 NamepathOffset, + UINT32 Offset, + char *OpName, + UINT64 Value, + UINT8 AmlOpcode, + UINT16 ParentOpcode); + + +/******************************************************************************* + * + * FUNCTION: LsAmlOffsetWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Process one node during a offset table file generation. + * + * Three types of objects are currently emitted to the offset table: + * 1) Tagged (named) resource descriptors + * 2) Named integer objects with constant integer values + * 3) Named package objects + * 4) Operation Regions that have constant Offset (address) parameters + * 5) Control methods + * + * The offset table allows the BIOS to dynamically update the values of these + * objects at boot time. + * + ******************************************************************************/ + +ACPI_STATUS +LsAmlOffsetWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + UINT32 FileId = (UINT32) ACPI_TO_INTEGER (Context); + ACPI_NAMESPACE_NODE *Node; + UINT32 Length; + UINT32 NamepathOffset; + UINT32 DataOffset; + ACPI_PARSE_OBJECT *NextOp; + + + /* Ignore actual data blocks for resource descriptors */ + + if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DATA) + { + return (AE_OK); /* Do NOT update the global AML offset */ + } + + /* We are only interested in named objects (have a namespace node) */ + + Node = Op->Asl.Node; + if (!Node) + { + Gbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; + return (AE_OK); + } + + /* Named resource descriptor (has a descriptor tag) */ + + if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE) && + (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC)) + { + LsEmitOffsetTableEntry (FileId, Node, 0, Gbl_CurrentAmlOffset, + Op->Asl.ParseOpName, 0, Op->Asl.Extra, AML_BUFFER_OP); + + Gbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; + return (AE_OK); + } + + switch (Op->Asl.AmlOpcode) + { + case AML_NAME_OP: + + /* Named object -- Name (NameString, DataRefObject) */ + + if (!Op->Asl.Child) + { + FlPrintFile (FileId, "%s NO CHILD!\n", MsgBuffer); + return (AE_OK); + } + + Length = Op->Asl.FinalAmlLength; + NamepathOffset = Gbl_CurrentAmlOffset + Length; + + /* Get to the NameSeg/NamePath Op (and length of the name) */ + + Op = Op->Asl.Child; + + /* Get offset of last nameseg and the actual data */ + + NamepathOffset = Gbl_CurrentAmlOffset + Length + + (Op->Asl.FinalAmlLength - ACPI_NAME_SIZE); + + DataOffset = Gbl_CurrentAmlOffset + Length + + Op->Asl.FinalAmlLength; + + /* Get actual value associated with the name */ + + Op = Op->Asl.Next; + switch (Op->Asl.AmlOpcode) + { + case AML_BYTE_OP: + case AML_WORD_OP: + case AML_DWORD_OP: + case AML_QWORD_OP: + + /* The +1 is to handle the integer size prefix (opcode) */ + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1), + Op->Asl.ParseOpName, Op->Asl.Value.Integer, + (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); + break; + + case AML_ONE_OP: + case AML_ONES_OP: + case AML_ZERO_OP: + + /* For these, offset will point to the opcode */ + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, + Op->Asl.ParseOpName, Op->Asl.Value.Integer, + (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); + break; + + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + /* Get the package element count */ + + NextOp = Op->Asl.Child; + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, + Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, + (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP); + break; + + default: + break; + } + + Gbl_CurrentAmlOffset += Length; + return (AE_OK); + + case AML_REGION_OP: + + /* OperationRegion (NameString, RegionSpace, RegionOffset, RegionLength) */ + + Length = Op->Asl.FinalAmlLength; + + /* Get the name/namepath node */ + + NextOp = Op->Asl.Child; + + /* Get offset of last nameseg and the actual data */ + + NamepathOffset = Gbl_CurrentAmlOffset + Length + + (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); + + DataOffset = Gbl_CurrentAmlOffset + Length + + (NextOp->Asl.FinalAmlLength + 1); + + /* Get the SpaceId node, then the Offset (address) node */ + + NextOp = NextOp->Asl.Next; + NextOp = NextOp->Asl.Next; + + switch (NextOp->Asl.AmlOpcode) + { + /* + * We are only interested in integer constants that can be changed + * at boot time. Note, the One/Ones/Zero opcodes are considered + * non-changeable, so we ignore them here. + */ + case AML_BYTE_OP: + case AML_WORD_OP: + case AML_DWORD_OP: + case AML_QWORD_OP: + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1), + Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, + (UINT8) NextOp->Asl.AmlOpcode, AML_REGION_OP); + + Gbl_CurrentAmlOffset += Length; + return (AE_OK); + + default: + break; + } + break; + + case AML_METHOD_OP: + + /* Method (Namepath, ...) */ + + Length = Op->Asl.FinalAmlLength; + + /* Get the NameSeg/NamePath Op */ + + NextOp = Op->Asl.Child; + + /* Get offset of last nameseg and the actual data (flags byte) */ + + NamepathOffset = Gbl_CurrentAmlOffset + Length + + (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); + + DataOffset = Gbl_CurrentAmlOffset + Length + + NextOp->Asl.FinalAmlLength; + + /* Get the flags byte Op */ + + NextOp = NextOp->Asl.Next; + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, + Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, + (UINT8) Op->Asl.AmlOpcode, AML_METHOD_OP); + break; + + case AML_PROCESSOR_OP: + + /* Processor (Namepath, ProcessorId, Address, Length) */ + + Length = Op->Asl.FinalAmlLength; + NextOp = Op->Asl.Child; /* Get Namepath */ + + /* Get offset of last nameseg and the actual data (PBlock address) */ + + NamepathOffset = Gbl_CurrentAmlOffset + Length + + (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); + + DataOffset = Gbl_CurrentAmlOffset + Length + + (NextOp->Asl.FinalAmlLength + 1); + + NextOp = NextOp->Asl.Next; /* Get ProcessorID (BYTE) */ + NextOp = NextOp->Asl.Next; /* Get Address (DWORD) */ + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset, + Op->Asl.ParseOpName, NextOp->Asl.Value.Integer, + (UINT8) AML_DWORD_OP, AML_PROCESSOR_OP); + break; + + case AML_DEVICE_OP: + case AML_SCOPE_OP: + case AML_THERMAL_ZONE_OP: + + /* Device/Scope/ThermalZone (Namepath) */ + + Length = Op->Asl.FinalAmlLength; + NextOp = Op->Asl.Child; /* Get Namepath */ + + /* Get offset of last nameseg */ + + NamepathOffset = Gbl_CurrentAmlOffset + Length + + (NextOp->Asl.FinalAmlLength - ACPI_NAME_SIZE); + + LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, 0, + Op->Asl.ParseOpName, 0, (UINT8) 0, Op->Asl.AmlOpcode); + break; + + default: + break; + } + + Gbl_CurrentAmlOffset += Op->Asl.FinalAmlLength; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: LsEmitOffsetTableEntry + * + * PARAMETERS: FileId - ID of current listing file + * Node - Namespace node associated with the name + * Offset - Offset of the value within the AML table + * OpName - Name of the AML opcode + * Value - Current value of the AML field + * AmlOpcode - Opcode associated with the field + * ObjectType - ACPI object type + * + * RETURN: None + * + * DESCRIPTION: Emit a line of the offset table (-so option) + * + ******************************************************************************/ + +static void +LsEmitOffsetTableEntry ( + UINT32 FileId, + ACPI_NAMESPACE_NODE *Node, + UINT32 NamepathOffset, + UINT32 Offset, + char *OpName, + UINT64 Value, + UINT8 AmlOpcode, + UINT16 ParentOpcode) +{ + ACPI_BUFFER TargetPath; + ACPI_STATUS Status; + + + /* Get the full pathname to the namespace node */ + + TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (Node, &TargetPath, FALSE); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* [1] - Skip the opening backslash for the path */ + + strcpy (MsgBuffer, "\""); + strcat (MsgBuffer, &((char *) TargetPath.Pointer)[1]); + strcat (MsgBuffer, "\","); + ACPI_FREE (TargetPath.Pointer); + + /* + * Max offset is 4G, constrained by 32-bit ACPI table length. + * Max Length for Integers is 8 bytes. + */ + FlPrintFile (FileId, + " {%-29s 0x%4.4X, 0x%8.8X, 0x%2.2X, 0x%8.8X, 0x%8.8X%8.8X}, /* %s */\n", + MsgBuffer, ParentOpcode, NamepathOffset, AmlOpcode, + Offset, ACPI_FORMAT_UINT64 (Value), OpName); +} + + +/******************************************************************************* + * + * FUNCTION: LsDoOffsetTableHeader, LsDoOffsetTableFooter + * + * PARAMETERS: FileId - ID of current listing file + * + * RETURN: None + * + * DESCRIPTION: Header and footer for the offset table file. + * + ******************************************************************************/ + +void +LsDoOffsetTableHeader ( + UINT32 FileId) +{ + + FlPrintFile (FileId, + "#ifndef __AML_OFFSET_TABLE_H\n" + "#define __AML_OFFSET_TABLE_H\n\n"); + + FlPrintFile (FileId, "typedef struct {\n" + " char *Pathname; /* Full pathname (from root) to the object */\n" + " unsigned short ParentOpcode; /* AML opcode for the parent object */\n" + " unsigned long NamesegOffset; /* Offset of last nameseg in the parent namepath */\n" + " unsigned char Opcode; /* AML opcode for the data */\n" + " unsigned long Offset; /* Offset for the data */\n" + " unsigned long long Value; /* Original value of the data (as applicable) */\n" + "} AML_OFFSET_TABLE_ENTRY;\n\n"); + + FlPrintFile (FileId, + "#endif /* __AML_OFFSET_TABLE_H */\n\n"); + + FlPrintFile (FileId, + "/*\n" + " * Information specific to the supported object types:\n" + " *\n" + " * Integers:\n" + " * Opcode is the integer prefix, indicates length of the data\n" + " * (One of: BYTE, WORD, DWORD, QWORD, ZERO, ONE, ONES)\n" + " * Offset points to the actual integer data\n" + " * Value is the existing value in the AML\n" + " *\n" + " * Packages:\n" + " * Opcode is the package or var_package opcode\n" + " * Offset points to the package opcode\n" + " * Value is the package element count\n" + " *\n" + " * Operation Regions:\n" + " * Opcode is the address integer prefix, indicates length of the data\n" + " * Offset points to the region address\n" + " * Value is the existing address value in the AML\n" + " *\n" + " * Control Methods:\n" + " * Offset points to the method flags byte\n" + " * Value is the existing flags value in the AML\n" + " *\n" + " * Processors:\n" + " * Offset points to the first byte of the PBlock Address\n" + " *\n" + " * Resource Descriptors:\n" + " * Opcode is the descriptor type\n" + " * Offset points to the start of the descriptor\n" + " *\n" + " * Scopes/Devices/ThermalZones:\n" + " * Nameseg offset only\n" + " */\n"); + + FlPrintFile (FileId, + "AML_OFFSET_TABLE_ENTRY %s_%s_OffsetTable[] =\n{\n", + Gbl_TableSignature, Gbl_TableId); +} + + +void +LsDoOffsetTableFooter ( + UINT32 FileId) +{ + + FlPrintFile (FileId, + " {NULL,0,0,0,0,0} /* Table terminator */\n};\n\n"); + Gbl_CurrentAmlOffset = 0; +} diff --git a/third_party/lib/acpica/source/compiler/aslopcodes.c b/third_party/lib/acpica/source/compiler/aslopcodes.c new file mode 100644 index 000000000..fcc61135f --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslopcodes.c @@ -0,0 +1,1538 @@ +/****************************************************************************** + * + * Module Name: aslopcode - AML opcode generation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslopcodes") + + +/* Local prototypes */ + +static void +OpcDoAccessAs ( + ACPI_PARSE_OBJECT *Op); + +static void +OpcDoConnection ( + ACPI_PARSE_OBJECT *Op); + +static void +OpcDoUnicode ( + ACPI_PARSE_OBJECT *Op); + +static void +OpcDoEisaId ( + ACPI_PARSE_OBJECT *Op); + +static void +OpcDoPld ( + ACPI_PARSE_OBJECT *Op); + +static void +OpcDoUuId ( + ACPI_PARSE_OBJECT *Op); + +static UINT8 * +OpcEncodePldBuffer ( + ACPI_PLD_INFO *PldInfo); + + +/* ToPld strings */ + +static char *AslPldPanelList[] = +{ + "TOP", + "BOTTOM", + "LEFT", + "RIGHT", + "FRONT", + "BACK", + "UNKNOWN", + NULL +}; + +static char *AslPldVerticalPositionList[] = +{ + "UPPER", + "CENTER", + "LOWER", + NULL +}; + +static char *AslPldHorizontalPositionList[] = +{ + "LEFT", + "CENTER", + "RIGHT", + NULL +}; + +static char *AslPldShapeList[] = +{ + "ROUND", + "OVAL", + "SQUARE", + "VERTICALRECTANGLE", + "HORIZONTALRECTANGLE", + "VERTICALTRAPEZOID", + "HORIZONTALTRAPEZOID", + "UNKNOWN", + "CHAMFERED", + NULL +}; + + +/******************************************************************************* + * + * FUNCTION: OpcAmlOpcodeUpdateWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Opcode update walk, ascending callback + * + ******************************************************************************/ + +ACPI_STATUS +OpcAmlOpcodeUpdateWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + /* + * Handle the Package() case where the actual opcode cannot be determined + * until the PackageLength operand has been folded and minimized. + * (PackageOp versus VarPackageOp) + * + * This is (as of ACPI 3.0) the only case where the AML opcode can change + * based upon the value of a parameter. + * + * The parser always inserts a VarPackage opcode, which can possibly be + * optimized to a Package opcode. + */ + if (Op->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE) + { + OpnDoPackage (Op); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: OpcAmlOpcodeWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML + * operands. + * + ******************************************************************************/ + +ACPI_STATUS +OpcAmlOpcodeWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + TotalParseNodes++; + + OpcGenerateAmlOpcode (Op); + OpnGenerateAmlOperands (Op); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: OpcGetIntegerWidth + * + * PARAMETERS: Op - DEFINITION BLOCK op + * + * RETURN: none + * + * DESCRIPTION: Extract integer width from the table revision + * + ******************************************************************************/ + +void +OpcGetIntegerWidth ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Child; + + + if (!Op) + { + return; + } + + if (Gbl_RevisionOverride) + { + AcpiUtSetIntegerWidth (Gbl_RevisionOverride); + } + else + { + Child = Op->Asl.Child; + Child = Child->Asl.Next; + Child = Child->Asl.Next; + + /* Use the revision to set the integer width */ + + AcpiUtSetIntegerWidth ((UINT8) Child->Asl.Value.Integer); + } +} + + +/******************************************************************************* + * + * FUNCTION: OpcSetOptimalIntegerSize + * + * PARAMETERS: Op - A parse tree node + * + * RETURN: Integer width, in bytes. Also sets the node AML opcode to the + * optimal integer AML prefix opcode. + * + * DESCRIPTION: Determine the optimal AML encoding of an integer. All leading + * zeros can be truncated to squeeze the integer into the + * minimal number of AML bytes. + * + ******************************************************************************/ + +UINT32 +OpcSetOptimalIntegerSize ( + ACPI_PARSE_OBJECT *Op) +{ + +#if 0 + /* + * TBD: - we don't want to optimize integers in the block header, but the + * code below does not work correctly. + */ + if (Op->Asl.Parent && + Op->Asl.Parent->Asl.Parent && + (Op->Asl.Parent->Asl.Parent->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)) + { + return (0); + } +#endif + + /* + * Check for the special AML integers first - Zero, One, Ones. + * These are single-byte opcodes that are the smallest possible + * representation of an integer. + * + * This optimization is optional. + */ + if (Gbl_IntegerOptimizationFlag) + { + switch (Op->Asl.Value.Integer) + { + case 0: + + Op->Asl.AmlOpcode = AML_ZERO_OP; + AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, + Op, "Zero"); + return (1); + + case 1: + + Op->Asl.AmlOpcode = AML_ONE_OP; + AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, + Op, "One"); + return (1); + + case ACPI_UINT32_MAX: + + /* Check for table integer width (32 or 64) */ + + if (AcpiGbl_IntegerByteWidth == 4) + { + Op->Asl.AmlOpcode = AML_ONES_OP; + AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, + Op, "Ones"); + return (1); + } + break; + + case ACPI_UINT64_MAX: + + /* Check for table integer width (32 or 64) */ + + if (AcpiGbl_IntegerByteWidth == 8) + { + Op->Asl.AmlOpcode = AML_ONES_OP; + AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, + Op, "Ones"); + return (1); + } + break; + + default: + + break; + } + } + + /* Find the best fit using the various AML integer prefixes */ + + if (Op->Asl.Value.Integer <= ACPI_UINT8_MAX) + { + Op->Asl.AmlOpcode = AML_BYTE_OP; + return (1); + } + + if (Op->Asl.Value.Integer <= ACPI_UINT16_MAX) + { + Op->Asl.AmlOpcode = AML_WORD_OP; + return (2); + } + + if (Op->Asl.Value.Integer <= ACPI_UINT32_MAX) + { + Op->Asl.AmlOpcode = AML_DWORD_OP; + return (4); + } + else + { + if (AcpiGbl_IntegerByteWidth == 4) + { + AslError (ASL_WARNING, ASL_MSG_INTEGER_LENGTH, + Op, NULL); + + if (!Gbl_IgnoreErrors) + { + /* Truncate the integer to 32-bit */ + Op->Asl.AmlOpcode = AML_DWORD_OP; + return (4); + } + } + + Op->Asl.AmlOpcode = AML_QWORD_OP; + return (8); + } +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoAccessAs + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Implement the ACCESS_AS ASL keyword. + * + ******************************************************************************/ + +static void +OpcDoAccessAs ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *TypeOp; + ACPI_PARSE_OBJECT *AttribOp; + ACPI_PARSE_OBJECT *LengthOp; + UINT8 Attribute; + + + Op->Asl.AmlOpcodeLength = 1; + TypeOp = Op->Asl.Child; + + /* First child is the access type */ + + TypeOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + TypeOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + + /* Second child is the optional access attribute */ + + AttribOp = TypeOp->Asl.Next; + if (AttribOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + AttribOp->Asl.Value.Integer = 0; + } + + AttribOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + AttribOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + + /* Only a few AccessAttributes support AccessLength */ + + Attribute = (UINT8) AttribOp->Asl.Value.Integer; + if ((Attribute != AML_FIELD_ATTRIB_MULTIBYTE) && + (Attribute != AML_FIELD_ATTRIB_RAW_BYTES) && + (Attribute != AML_FIELD_ATTRIB_RAW_PROCESS)) + { + return; + } + + Op->Asl.AmlOpcode = AML_FIELD_EXT_ACCESS_OP; + + /* + * Child of Attributes is the AccessLength (required for Multibyte, + * RawBytes, RawProcess.) + */ + LengthOp = AttribOp->Asl.Child; + if (!LengthOp) + { + return; + } + + /* TBD: probably can remove */ + + if (LengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + LengthOp->Asl.Value.Integer = 16; + } + + LengthOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + LengthOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoConnection + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Implement the Connection ASL keyword. + * + ******************************************************************************/ + +static void +OpcDoConnection ( + ACPI_PARSE_OBJECT *Op) +{ + ASL_RESOURCE_NODE *Rnode; + ACPI_PARSE_OBJECT *BufferOp; + ACPI_PARSE_OBJECT *BufferLengthOp; + ACPI_PARSE_OBJECT *BufferDataOp; + ASL_RESOURCE_INFO Info; + UINT8 State; + + + Op->Asl.AmlOpcodeLength = 1; + + if (Op->Asl.Child->Asl.AmlOpcode == AML_INT_NAMEPATH_OP) + { + return; + } + + BufferOp = Op->Asl.Child; + BufferLengthOp = BufferOp->Asl.Child; + BufferDataOp = BufferLengthOp->Asl.Next; + + Info.DescriptorTypeOp = BufferDataOp->Asl.Next; + Info.CurrentByteOffset = 0; + State = ACPI_RSTATE_NORMAL; + Rnode = RsDoOneResourceDescriptor (&Info, &State); + if (!Rnode) + { + return; /* error */ + } + + /* + * Transform the nodes into the following + * + * Op -> AML_BUFFER_OP + * First Child -> BufferLength + * Second Child -> Descriptor Buffer (raw byte data) + */ + BufferOp->Asl.ParseOpcode = PARSEOP_BUFFER; + BufferOp->Asl.AmlOpcode = AML_BUFFER_OP; + BufferOp->Asl.CompileFlags = NODE_AML_PACKAGE | NODE_IS_RESOURCE_DESC; + UtSetParseOpName (BufferOp); + + BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER; + BufferLengthOp->Asl.Value.Integer = Rnode->BufferLength; + (void) OpcSetOptimalIntegerSize (BufferLengthOp); + UtSetParseOpName (BufferLengthOp); + + BufferDataOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + BufferDataOp->Asl.AmlOpcode = AML_RAW_DATA_CHAIN; + BufferDataOp->Asl.AmlOpcodeLength = 0; + BufferDataOp->Asl.AmlLength = Rnode->BufferLength; + BufferDataOp->Asl.Value.Buffer = (UINT8 *) Rnode; + UtSetParseOpName (BufferDataOp); +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoUnicode + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Implement the UNICODE ASL "macro". Convert the input string + * to a unicode buffer. There is no Unicode AML opcode. + * + * Note: The Unicode string is 16 bits per character, no leading signature, + * with a 16-bit terminating NULL. + * + ******************************************************************************/ + +static void +OpcDoUnicode ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *InitializerOp; + UINT32 Length; + UINT32 Count; + UINT32 i; + UINT8 *AsciiString; + UINT16 *UnicodeString; + ACPI_PARSE_OBJECT *BufferLengthOp; + + + /* Change op into a buffer object */ + + Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; + Op->Asl.ParseOpcode = PARSEOP_BUFFER; + UtSetParseOpName (Op); + + /* Buffer Length is first, followed by the string */ + + BufferLengthOp = Op->Asl.Child; + InitializerOp = BufferLengthOp->Asl.Next; + + AsciiString = (UINT8 *) InitializerOp->Asl.Value.String; + + /* Create a new buffer for the Unicode string */ + + Count = strlen (InitializerOp->Asl.Value.String) + 1; + Length = Count * sizeof (UINT16); + UnicodeString = UtLocalCalloc (Length); + + /* Convert to Unicode string (including null terminator) */ + + for (i = 0; i < Count; i++) + { + UnicodeString[i] = (UINT16) AsciiString[i]; + } + + /* + * Just set the buffer size node to be the buffer length, regardless + * of whether it was previously an integer or a default_arg placeholder + */ + BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER; + BufferLengthOp->Asl.AmlOpcode = AML_DWORD_OP; + BufferLengthOp->Asl.Value.Integer = Length; + UtSetParseOpName (BufferLengthOp); + + (void) OpcSetOptimalIntegerSize (BufferLengthOp); + + /* The Unicode string is a raw data buffer */ + + InitializerOp->Asl.Value.Buffer = (UINT8 *) UnicodeString; + InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; + InitializerOp->Asl.AmlLength = Length; + InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + InitializerOp->Asl.Child = NULL; + UtSetParseOpName (InitializerOp); +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoEisaId + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Convert a string EISA ID to numeric representation. See the + * Pnp BIOS Specification for details. Here is an excerpt: + * + * A seven character ASCII representation of the product + * identifier compressed into a 32-bit identifier. The seven + * character ID consists of a three character manufacturer code, + * a three character hexadecimal product identifier, and a one + * character hexadecimal revision number. The manufacturer code + * is a 3 uppercase character code that is compressed into 3 5-bit + * values as follows: + * 1) Find hex ASCII value for each letter + * 2) Subtract 40h from each ASCII value + * 3) Retain 5 least significant bits for each letter by + * discarding upper 3 bits because they are always 0. + * 4) Compressed code = concatenate 0 and the 3 5-bit values + * + * The format of the compressed product identifier is as follows: + * Byte 0: Bit 7 - Reserved (0) + * Bits 6-2: - 1st character of compressed mfg code + * Bits 1-0 - Upper 2 bits of 2nd character of mfg code + * Byte 1: Bits 7-5 - Lower 3 bits of 2nd character of mfg code + * Bits 4-0 - 3rd character of mfg code + * Byte 2: Bits 7-4 - 1st hex digit of product number + * Bits 3-0 - 2nd hex digit of product number + * Byte 3: Bits 7-4 - 3st hex digit of product number + * Bits 3-0 - Hex digit of the revision number + * + ******************************************************************************/ + +static void +OpcDoEisaId ( + ACPI_PARSE_OBJECT *Op) +{ + UINT32 EisaId = 0; + UINT32 BigEndianId; + char *InString; + ACPI_STATUS Status = AE_OK; + UINT32 i; + + + InString = (char *) Op->Asl.Value.String; + + /* + * The EISAID string must be exactly 7 characters and of the form + * "UUUXXXX" -- 3 uppercase letters and 4 hex digits (e.g., "PNP0001") + */ + if (strlen (InString) != 7) + { + Status = AE_BAD_PARAMETER; + } + else + { + /* Check all 7 characters for correct format */ + + for (i = 0; i < 7; i++) + { + /* First 3 characters must be uppercase letters */ + + if (i < 3) + { + if (!isupper ((int) InString[i])) + { + Status = AE_BAD_PARAMETER; + } + } + + /* Last 4 characters must be hex digits */ + + else if (!isxdigit ((int) InString[i])) + { + Status = AE_BAD_PARAMETER; + } + } + } + + if (ACPI_FAILURE (Status)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_EISAID, Op, Op->Asl.Value.String); + } + else + { + /* Create ID big-endian first (bits are contiguous) */ + + BigEndianId = + (UINT32) ((UINT8) (InString[0] - 0x40)) << 26 | + (UINT32) ((UINT8) (InString[1] - 0x40)) << 21 | + (UINT32) ((UINT8) (InString[2] - 0x40)) << 16 | + + (AcpiUtAsciiCharToHex (InString[3])) << 12 | + (AcpiUtAsciiCharToHex (InString[4])) << 8 | + (AcpiUtAsciiCharToHex (InString[5])) << 4 | + AcpiUtAsciiCharToHex (InString[6]); + + /* Swap to little-endian to get final ID (see function header) */ + + EisaId = AcpiUtDwordByteSwap (BigEndianId); + } + + /* + * Morph the Op into an integer, regardless of whether there + * was an error in the EISAID string + */ + Op->Asl.Value.Integer = EisaId; + + Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; + Op->Asl.ParseOpcode = PARSEOP_INTEGER; + (void) OpcSetOptimalIntegerSize (Op); + + /* Op is now an integer */ + + UtSetParseOpName (Op); +} + + +/******************************************************************************* + * + * FUNCTION: OpcEncodePldBuffer + * + * PARAMETERS: PldInfo - _PLD buffer struct (Using local struct) + * + * RETURN: Encode _PLD buffer suitable for return value from _PLD + * + * DESCRIPTION: Bit-packs a _PLD buffer struct. + * + ******************************************************************************/ + +static UINT8 * +OpcEncodePldBuffer ( + ACPI_PLD_INFO *PldInfo) +{ + UINT32 *Buffer; + UINT32 Dword; + + + Buffer = ACPI_ALLOCATE_ZEROED (ACPI_PLD_BUFFER_SIZE); + if (!Buffer) + { + return (NULL); + } + + /* First 32 bits */ + + Dword = 0; + ACPI_PLD_SET_REVISION (&Dword, PldInfo->Revision); + ACPI_PLD_SET_IGNORE_COLOR (&Dword, PldInfo->IgnoreColor); + ACPI_PLD_SET_RED (&Dword, PldInfo->Red); + ACPI_PLD_SET_GREEN (&Dword, PldInfo->Green); + ACPI_PLD_SET_BLUE (&Dword, PldInfo->Blue); + ACPI_MOVE_32_TO_32 (&Buffer[0], &Dword); + + /* Second 32 bits */ + + Dword = 0; + ACPI_PLD_SET_WIDTH (&Dword, PldInfo->Width); + ACPI_PLD_SET_HEIGHT (&Dword, PldInfo->Height); + ACPI_MOVE_32_TO_32 (&Buffer[1], &Dword); + + /* Third 32 bits */ + + Dword = 0; + ACPI_PLD_SET_USER_VISIBLE (&Dword, PldInfo->UserVisible); + ACPI_PLD_SET_DOCK (&Dword, PldInfo->Dock); + ACPI_PLD_SET_LID (&Dword, PldInfo->Lid); + ACPI_PLD_SET_PANEL (&Dword, PldInfo->Panel); + ACPI_PLD_SET_VERTICAL (&Dword, PldInfo->VerticalPosition); + ACPI_PLD_SET_HORIZONTAL (&Dword, PldInfo->HorizontalPosition); + ACPI_PLD_SET_SHAPE (&Dword, PldInfo->Shape); + ACPI_PLD_SET_ORIENTATION (&Dword, PldInfo->GroupOrientation); + ACPI_PLD_SET_TOKEN (&Dword, PldInfo->GroupToken); + ACPI_PLD_SET_POSITION (&Dword, PldInfo->GroupPosition); + ACPI_PLD_SET_BAY (&Dword, PldInfo->Bay); + ACPI_MOVE_32_TO_32 (&Buffer[2], &Dword); + + /* Fourth 32 bits */ + + Dword = 0; + ACPI_PLD_SET_EJECTABLE (&Dword, PldInfo->Ejectable); + ACPI_PLD_SET_OSPM_EJECT (&Dword, PldInfo->OspmEjectRequired); + ACPI_PLD_SET_CABINET (&Dword, PldInfo->CabinetNumber); + ACPI_PLD_SET_CARD_CAGE (&Dword, PldInfo->CardCageNumber); + ACPI_PLD_SET_REFERENCE (&Dword, PldInfo->Reference); + ACPI_PLD_SET_ROTATION (&Dword, PldInfo->Rotation); + ACPI_PLD_SET_ORDER (&Dword, PldInfo->Order); + ACPI_MOVE_32_TO_32 (&Buffer[3], &Dword); + + if (PldInfo->Revision >= 2) + { + /* Fifth 32 bits */ + + Dword = 0; + ACPI_PLD_SET_VERT_OFFSET (&Dword, PldInfo->VerticalOffset); + ACPI_PLD_SET_HORIZ_OFFSET (&Dword, PldInfo->HorizontalOffset); + ACPI_MOVE_32_TO_32 (&Buffer[4], &Dword); + } + + return (ACPI_CAST_PTR (UINT8, Buffer)); +} + + +/******************************************************************************* + * + * FUNCTION: OpcFindName + * + * PARAMETERS: List - Array of char strings to be searched + * Name - Char string to string for + * Index - Index value to set if found + * + * RETURN: TRUE if any names matched, FALSE otherwise + * + * DESCRIPTION: Match PLD name to value in lookup table. Sets Value to + * equivalent parameter value. + * + ******************************************************************************/ + +static BOOLEAN +OpcFindName ( + char **List, + char *Name, + UINT64 *Index) +{ + char *Str; + UINT32 i; + + + AcpiUtStrupr (Name); + + for (i = 0, Str = List[0]; Str; i++, Str = List[i]) + { + if (!(strncmp (Str, Name, strlen (Name)))) + { + *Index = i; + return (TRUE); + } + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoPld + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Convert ToPLD macro to 20-byte buffer + * + ******************************************************************************/ + +static void +OpcDoPld ( + ACPI_PARSE_OBJECT *Op) +{ + UINT8 *Buffer; + ACPI_PARSE_OBJECT *Node; + ACPI_PLD_INFO PldInfo; + ACPI_PARSE_OBJECT *NewOp; + + + if (!Op) + { + AslError(ASL_ERROR, ASL_MSG_NOT_EXIST, Op, NULL); + return; + } + + if (Op->Asl.ParseOpcode != PARSEOP_TOPLD) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Op, NULL); + return; + } + + memset (&PldInfo, 0, sizeof (ACPI_PLD_INFO)); + + Node = Op->Asl.Child; + while (Node) + { + switch (Node->Asl.ParseOpcode) + { + case PARSEOP_PLD_REVISION: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 127) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + PldInfo.Revision = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_IGNORECOLOR: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 1) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + PldInfo.IgnoreColor = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_RED: + case PARSEOP_PLD_GREEN: + case PARSEOP_PLD_BLUE: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 255) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_RED) + { + PldInfo.Red = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else if (Node->Asl.ParseOpcode == PARSEOP_PLD_GREEN) + { + PldInfo.Green = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else /* PARSEOP_PLD_BLUE */ + { + PldInfo.Blue = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + break; + + case PARSEOP_PLD_WIDTH: + case PARSEOP_PLD_HEIGHT: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 65535) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_WIDTH) + { + PldInfo.Width = (UINT16) Node->Asl.Child->Asl.Value.Integer; + } + else /* PARSEOP_PLD_HEIGHT */ + { + PldInfo.Height = (UINT16) Node->Asl.Child->Asl.Value.Integer; + } + + break; + + case PARSEOP_PLD_USERVISIBLE: + case PARSEOP_PLD_DOCK: + case PARSEOP_PLD_LID: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 1) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_USERVISIBLE) + { + PldInfo.UserVisible = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else if (Node->Asl.ParseOpcode == PARSEOP_PLD_DOCK) + { + PldInfo.Dock = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else + { + PldInfo.Lid = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + + break; + + case PARSEOP_PLD_PANEL: + + if (Node->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) + { + if (Node->Asl.Child->Asl.Value.Integer > 6) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + } + else /* PARSEOP_STRING */ + { + if (!OpcFindName(AslPldPanelList, + Node->Asl.Child->Asl.Value.String, + &Node->Asl.Child->Asl.Value.Integer)) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Node, NULL); + break; + } + } + + PldInfo.Panel = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_VERTICALPOSITION: + + if (Node->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) + { + if (Node->Asl.Child->Asl.Value.Integer > 2) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + } + else /* PARSEOP_STRING */ + { + if (!OpcFindName(AslPldVerticalPositionList, + Node->Asl.Child->Asl.Value.String, + &Node->Asl.Child->Asl.Value.Integer)) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Node, NULL); + break; + } + } + + PldInfo.VerticalPosition = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_HORIZONTALPOSITION: + + if (Node->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) + { + if (Node->Asl.Child->Asl.Value.Integer > 2) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + } + else /* PARSEOP_STRING */ + { + if (!OpcFindName(AslPldHorizontalPositionList, + Node->Asl.Child->Asl.Value.String, + &Node->Asl.Child->Asl.Value.Integer)) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Node, NULL); + break; + } + } + + PldInfo.HorizontalPosition = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_SHAPE: + + if (Node->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) + { + if (Node->Asl.Child->Asl.Value.Integer > 8) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + } + else /* PARSEOP_STRING */ + { + if (!OpcFindName(AslPldShapeList, + Node->Asl.Child->Asl.Value.String, + &Node->Asl.Child->Asl.Value.Integer)) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Node, NULL); + break; + } + } + + PldInfo.Shape = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_GROUPORIENTATION: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 1) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + PldInfo.GroupOrientation = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_GROUPTOKEN: + case PARSEOP_PLD_GROUPPOSITION: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 255) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_GROUPTOKEN) + { + PldInfo.GroupToken = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else /* PARSEOP_PLD_GROUPPOSITION */ + { + PldInfo.GroupPosition = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + + break; + + case PARSEOP_PLD_BAY: + case PARSEOP_PLD_EJECTABLE: + case PARSEOP_PLD_EJECTREQUIRED: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 1) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_BAY) + { + PldInfo.Bay = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else if (Node->Asl.ParseOpcode == PARSEOP_PLD_EJECTABLE) + { + PldInfo.Ejectable = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else /* PARSEOP_PLD_EJECTREQUIRED */ + { + PldInfo.OspmEjectRequired = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + + break; + + case PARSEOP_PLD_CABINETNUMBER: + case PARSEOP_PLD_CARDCAGENUMBER: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 255) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_CABINETNUMBER) + { + PldInfo.CabinetNumber = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + else /* PARSEOP_PLD_CARDCAGENUMBER */ + { + PldInfo.CardCageNumber = (UINT8) Node->Asl.Child->Asl.Value.Integer; + } + + break; + + case PARSEOP_PLD_REFERENCE: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 1) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + PldInfo.Reference = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_ROTATION: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 7) + { + switch (Node->Asl.Child->Asl.Value.Integer) + { + case 45: + + Node->Asl.Child->Asl.Value.Integer = 1; + break; + + case 90: + + Node->Asl.Child->Asl.Value.Integer = 2; + break; + + case 135: + + Node->Asl.Child->Asl.Value.Integer = 3; + break; + + case 180: + + Node->Asl.Child->Asl.Value.Integer = 4; + break; + + case 225: + + Node->Asl.Child->Asl.Value.Integer = 5; + break; + + case 270: + + Node->Asl.Child->Asl.Value.Integer = 6; + break; + + case 315: + + Node->Asl.Child->Asl.Value.Integer = 7; + break; + + default: + + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + } + + PldInfo.Rotation = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_ORDER: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 31) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + PldInfo.Order = (UINT8) Node->Asl.Child->Asl.Value.Integer; + break; + + case PARSEOP_PLD_VERTICALOFFSET: + case PARSEOP_PLD_HORIZONTALOFFSET: + + if (Node->Asl.Child->Asl.ParseOpcode != PARSEOP_INTEGER) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + if (Node->Asl.Child->Asl.Value.Integer > 65535) + { + AslError(ASL_ERROR, ASL_MSG_RANGE, Node, NULL); + break; + } + + if (Node->Asl.ParseOpcode == PARSEOP_PLD_VERTICALOFFSET) + { + PldInfo.VerticalOffset = (UINT16) Node->Asl.Child->Asl.Value.Integer; + } + else /* PARSEOP_PLD_HORIZONTALOFFSET */ + { + PldInfo.HorizontalOffset = (UINT16) Node->Asl.Child->Asl.Value.Integer; + } + + break; + + default: + + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, Node, NULL); + break; + } + + Node = Node->Asl.Next; + } + + Buffer = OpcEncodePldBuffer(&PldInfo); + + /* Change Op to a Buffer */ + + Op->Asl.ParseOpcode = PARSEOP_BUFFER; + Op->Common.AmlOpcode = AML_BUFFER_OP; + + /* Disable further optimization */ + + Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; + UtSetParseOpName (Op); + + /* Child node is the buffer length */ + + NewOp = TrAllocateNode (PARSEOP_INTEGER); + + NewOp->Asl.AmlOpcode = AML_BYTE_OP; + NewOp->Asl.Value.Integer = 20; + NewOp->Asl.Parent = Op; + + Op->Asl.Child = NewOp; + Op = NewOp; + + /* Peer to the child is the raw buffer data */ + + NewOp = TrAllocateNode (PARSEOP_RAW_DATA); + NewOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; + NewOp->Asl.AmlLength = 20; + NewOp->Asl.Value.String = ACPI_CAST_PTR (char, Buffer); + NewOp->Asl.Parent = Op->Asl.Parent; + + Op->Asl.Next = NewOp; +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoUuId + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Convert UUID string to 16-byte buffer + * + ******************************************************************************/ + +static void +OpcDoUuId ( + ACPI_PARSE_OBJECT *Op) +{ + char *InString; + UINT8 *Buffer; + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *NewOp; + + + InString = ACPI_CAST_PTR (char, Op->Asl.Value.String); + Buffer = UtLocalCalloc (16); + + Status = AuValidateUuid (InString); + if (ACPI_FAILURE (Status)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_UUID, Op, Op->Asl.Value.String); + } + else + { + AcpiUtConvertStringToUuid (InString, Buffer); + } + + /* Change Op to a Buffer */ + + Op->Asl.ParseOpcode = PARSEOP_BUFFER; + Op->Common.AmlOpcode = AML_BUFFER_OP; + + /* Disable further optimization */ + + Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; + UtSetParseOpName (Op); + + /* Child node is the buffer length */ + + NewOp = TrAllocateNode (PARSEOP_INTEGER); + + NewOp->Asl.AmlOpcode = AML_BYTE_OP; + NewOp->Asl.Value.Integer = 16; + NewOp->Asl.Parent = Op; + + Op->Asl.Child = NewOp; + Op = NewOp; + + /* Peer to the child is the raw buffer data */ + + NewOp = TrAllocateNode (PARSEOP_RAW_DATA); + NewOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; + NewOp->Asl.AmlLength = 16; + NewOp->Asl.Value.String = ACPI_CAST_PTR (char, Buffer); + NewOp->Asl.Parent = Op->Asl.Parent; + + Op->Asl.Next = NewOp; +} + + +/******************************************************************************* + * + * FUNCTION: OpcGenerateAmlOpcode + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Generate the AML opcode associated with the node and its + * parse (lex/flex) keyword opcode. Essentially implements + * a mapping between the parse opcodes and the actual AML opcodes. + * + ******************************************************************************/ + +void +OpcGenerateAmlOpcode ( + ACPI_PARSE_OBJECT *Op) +{ + UINT16 Index; + + + Index = (UINT16) (Op->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); + + Op->Asl.AmlOpcode = AslKeywordMapping[Index].AmlOpcode; + Op->Asl.AcpiBtype = AslKeywordMapping[Index].AcpiBtype; + Op->Asl.CompileFlags |= AslKeywordMapping[Index].Flags; + + if (!Op->Asl.Value.Integer) + { + Op->Asl.Value.Integer = AslKeywordMapping[Index].Value; + } + + /* Special handling for some opcodes */ + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_INTEGER: + /* + * Set the opcode based on the size of the integer + */ + (void) OpcSetOptimalIntegerSize (Op); + break; + + case PARSEOP_OFFSET: + + Op->Asl.AmlOpcodeLength = 1; + break; + + case PARSEOP_ACCESSAS: + + OpcDoAccessAs (Op); + break; + + case PARSEOP_CONNECTION: + + OpcDoConnection (Op); + break; + + case PARSEOP_EISAID: + + OpcDoEisaId (Op); + break; + + case PARSEOP_PRINTF: + + OpcDoPrintf (Op); + break; + + case PARSEOP_FPRINTF: + + OpcDoFprintf (Op); + break; + + case PARSEOP_TOPLD: + + OpcDoPld (Op); + break; + + case PARSEOP_TOUUID: + + OpcDoUuId (Op); + break; + + case PARSEOP_UNICODE: + + OpcDoUnicode (Op); + break; + + case PARSEOP_INCLUDE: + + Gbl_HasIncludeFiles = TRUE; + break; + + case PARSEOP_EXTERNAL: + + Op->Asl.Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + Op->Asl.Child->Asl.Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + break; + + case PARSEOP_TIMER: + + if (AcpiGbl_IntegerBitWidth == 32) + { + AslError (ASL_REMARK, ASL_MSG_TRUNCATION, Op, NULL); + } + break; + + default: + + /* Nothing to do for other opcodes */ + + break; + } + + return; +} diff --git a/third_party/lib/acpica/source/compiler/asloperands.c b/third_party/lib/acpica/source/compiler/asloperands.c new file mode 100644 index 000000000..2d33514f6 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asloperands.c @@ -0,0 +1,1202 @@ +/****************************************************************************** + * + * Module Name: asloperands - AML operand processing + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asloperands") + +/* Local prototypes */ + +static void +OpnDoField ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoBankField ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoBuffer ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoDefinitionBlock ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoFieldCommon ( + ACPI_PARSE_OBJECT *FieldOp, + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoIndexField ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoLoadTable ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoMethod ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoMutex ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnDoRegion ( + ACPI_PARSE_OBJECT *Op); + +static void +OpnAttachNameToNode ( + ACPI_PARSE_OBJECT *Op); + + +/******************************************************************************* + * + * FUNCTION: OpnDoMutex + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the operands for the MUTEX ASL keyword. + * + ******************************************************************************/ + +static void +OpnDoMutex ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + Next = Op->Asl.Child; + Next = Next->Asl.Next; + + if (Next->Asl.Value.Integer > 15) + { + AslError (ASL_ERROR, ASL_MSG_SYNC_LEVEL, Next, NULL); + } + return; +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoMethod + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the operands for the METHOD ASL keyword. + * + ******************************************************************************/ + +static void +OpnDoMethod ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + /* Optional arguments for this opcode with defaults */ + + UINT8 NumArgs = 0; + UINT8 Serialized = 0; + UINT8 Concurrency = 0; + UINT8 MethodFlags; + + + /* Opcode and package length first */ + /* Method name */ + + Next = Op->Asl.Child; + + /* Num args */ + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + NumArgs = (UINT8) Next->Asl.Value.Integer; + Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + } + + /* Serialized Flag */ + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + Serialized = (UINT8) Next->Asl.Value.Integer; + Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + } + + /* Concurrency value (valid values are 0-15) */ + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* This is a ByteConstExpr, so eval the constant now */ + + OpcAmlConstantWalk (Next, 0, NULL); + + if (Next->Asl.Value.Integer > 15) + { + AslError (ASL_ERROR, ASL_MSG_SYNC_LEVEL, Next, NULL); + } + + Concurrency = (UINT8) Next->Asl.Value.Integer; + } + + /* Put the bits in their proper places */ + + MethodFlags = (UINT8) + ((NumArgs & 0x7) | + ((Serialized & 0x1) << 3) | + ((Concurrency & 0xF) << 4)); + + /* Use the last node for the combined flags byte */ + + Next->Asl.Value.Integer = MethodFlags; + Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + Next->Asl.AmlLength = 1; + Next->Asl.ParseOpcode = PARSEOP_RAW_DATA; + + /* Save the arg count in the first node */ + + Op->Asl.Extra = NumArgs; +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoFieldCommon + * + * PARAMETERS: FieldOp - Node for an ASL field + * Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the various field keywords, + * FIELD, BANKFIELD, INDEXFIELD + * + ******************************************************************************/ + +static void +OpnDoFieldCommon ( + ACPI_PARSE_OBJECT *FieldOp, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + ACPI_PARSE_OBJECT *PkgLengthNode; + UINT32 CurrentBitOffset; + UINT32 NewBitOffset; + UINT8 AccessType; + UINT8 LockRule; + UINT8 UpdateRule; + UINT8 FieldFlags; + UINT32 MinimumLength; + + + /* AccessType -- not optional, so no need to check for DEFAULT_ARG */ + + AccessType = (UINT8) Op->Asl.Value.Integer; + Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + + /* Set the access type in the parent (field) node for use later */ + + FieldOp->Asl.Value.Integer = AccessType; + + /* LockRule -- not optional, so no need to check for DEFAULT_ARG */ + + Next = Op->Asl.Next; + LockRule = (UINT8) Next->Asl.Value.Integer; + Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + + /* UpdateRule -- not optional, so no need to check for DEFAULT_ARG */ + + Next = Next->Asl.Next; + UpdateRule = (UINT8) Next->Asl.Value.Integer; + + /* + * Generate the flags byte. The various fields are already + * in the right bit position via translation from the + * keywords by the parser. + */ + FieldFlags = (UINT8) (AccessType | LockRule | UpdateRule); + + /* Use the previous node to be the FieldFlags node */ + + /* Set the node to RAW_DATA */ + + Next->Asl.Value.Integer = FieldFlags; + Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + Next->Asl.AmlLength = 1; + Next->Asl.ParseOpcode = PARSEOP_RAW_DATA; + + /* Process the FieldUnitList */ + + Next = Next->Asl.Next; + CurrentBitOffset = 0; + + while (Next) + { + /* Save the offset of this field unit */ + + Next->Asl.ExtraValue = CurrentBitOffset; + + switch (Next->Asl.ParseOpcode) + { + case PARSEOP_ACCESSAS: + + PkgLengthNode = Next->Asl.Child; + AccessType = (UINT8) PkgLengthNode->Asl.Value.Integer; + + /* Nothing additional to do */ + break; + + case PARSEOP_OFFSET: + + /* New offset into the field */ + + PkgLengthNode = Next->Asl.Child; + NewBitOffset = ((UINT32) PkgLengthNode->Asl.Value.Integer) * 8; + + /* + * Examine the specified offset in relation to the + * current offset counter. + */ + if (NewBitOffset < CurrentBitOffset) + { + /* + * Not allowed to specify a backwards offset! + * Issue error and ignore this node. + */ + AslError (ASL_ERROR, ASL_MSG_BACKWARDS_OFFSET, PkgLengthNode, + NULL); + Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + } + else if (NewBitOffset == CurrentBitOffset) + { + /* + * Offset is redundant; we don't need to output an + * offset opcode. Just set these nodes to default + */ + Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + } + else + { + /* + * Valid new offset - set the value to be inserted into the AML + * and update the offset counter. + */ + PkgLengthNode->Asl.Value.Integer = + NewBitOffset - CurrentBitOffset; + CurrentBitOffset = NewBitOffset; + } + break; + + case PARSEOP_NAMESEG: + case PARSEOP_RESERVED_BYTES: + + /* Named or reserved field entry */ + + PkgLengthNode = Next->Asl.Child; + NewBitOffset = (UINT32) PkgLengthNode->Asl.Value.Integer; + CurrentBitOffset += NewBitOffset; + + /* Save the current AccessAs value for error checking later */ + + switch (AccessType) + { + case AML_FIELD_ACCESS_ANY: + case AML_FIELD_ACCESS_BYTE: + case AML_FIELD_ACCESS_BUFFER: + default: + + MinimumLength = 8; + break; + + case AML_FIELD_ACCESS_WORD: + MinimumLength = 16; + break; + + case AML_FIELD_ACCESS_DWORD: + MinimumLength = 32; + break; + + case AML_FIELD_ACCESS_QWORD: + MinimumLength = 64; + break; + } + + PkgLengthNode->Asl.ExtraValue = MinimumLength; + break; + + default: + + /* All supported field opcodes must appear above */ + + break; + } + + /* Move on to next entry in the field list */ + + Next = Next->Asl.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoField + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the FIELD ASL keyword + * + ******************************************************************************/ + +static void +OpnDoField ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + /* Opcode is parent node */ + /* First child is field name */ + + Next = Op->Asl.Child; + + /* Second child is the AccessType */ + + OpnDoFieldCommon (Op, Next->Asl.Next); +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoIndexField + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the INDEXFIELD ASL keyword + * + ******************************************************************************/ + +static void +OpnDoIndexField ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + /* Opcode is parent node */ + /* First child is the index name */ + + Next = Op->Asl.Child; + + /* Second child is the data name */ + + Next = Next->Asl.Next; + + /* Third child is the AccessType */ + + OpnDoFieldCommon (Op, Next->Asl.Next); +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoBankField + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the BANKFIELD ASL keyword + * + ******************************************************************************/ + +static void +OpnDoBankField ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + /* Opcode is parent node */ + /* First child is the region name */ + + Next = Op->Asl.Child; + + /* Second child is the bank name */ + + Next = Next->Asl.Next; + + /* Third child is the bank value */ + + Next = Next->Asl.Next; + + /* Fourth child is the AccessType */ + + OpnDoFieldCommon (Op, Next->Asl.Next); +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoRegion + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Tries to get the length of the region. Can only do this at + * compile time if the length is a constant. + * + ******************************************************************************/ + +static void +OpnDoRegion ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + /* Opcode is parent node */ + /* First child is the region name */ + + Next = Op->Asl.Child; + + /* Second child is the space ID*/ + + Next = Next->Asl.Next; + + /* Third child is the region offset */ + + Next = Next->Asl.Next; + + /* Fourth child is the region length */ + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode == PARSEOP_INTEGER) + { + Op->Asl.Value.Integer = Next->Asl.Value.Integer; + } + else + { + Op->Asl.Value.Integer = ACPI_UINT64_MAX; + } +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoBuffer + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the BUFFER ASL keyword. We + * build a single raw byte buffer from the initialization nodes, + * each parse node contains a buffer byte. + * + ******************************************************************************/ + +static void +OpnDoBuffer ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *BufferLengthOp; + + /* Optional arguments for this opcode with defaults */ + + UINT32 BufferLength = 0; + + + /* Opcode and package length first */ + /* Buffer Length is next, followed by the initializer list */ + + BufferLengthOp = Op->Asl.Child; + InitializerOp = BufferLengthOp->Asl.Next; + + /* + * If the BufferLength is not an INTEGER or was not specified in the ASL + * (DEFAULT_ARG), it is a TermArg that is + * evaluated at run-time, and we are therefore finished. + */ + if ((BufferLengthOp->Asl.ParseOpcode != PARSEOP_INTEGER) && + (BufferLengthOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) + { + return; + } + + /* + * We want to count the number of items in the initializer list, because if + * it is larger than the buffer length, we will define the buffer size + * to be the size of the initializer list (as per the ACPI Specification) + */ + switch (InitializerOp->Asl.ParseOpcode) + { + case PARSEOP_INTEGER: + case PARSEOP_BYTECONST: + case PARSEOP_WORDCONST: + case PARSEOP_DWORDCONST: + + /* The peer list contains the byte list (if any...) */ + + while (InitializerOp) + { + /* For buffers, this is a list of raw bytes */ + + InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + InitializerOp->Asl.AmlLength = 1; + InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + + BufferLength++; + InitializerOp = ASL_GET_PEER_NODE (InitializerOp); + } + break; + + case PARSEOP_STRING_LITERAL: + + /* + * Only one initializer, the string. Buffer must be big enough to hold + * the string plus the null termination byte + */ + BufferLength = strlen (InitializerOp->Asl.Value.String) + 1; + + InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; + InitializerOp->Asl.AmlLength = BufferLength; + InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + break; + + case PARSEOP_RAW_DATA: + + /* Buffer nodes are already initialized (e.g. Unicode operator) */ + return; + + case PARSEOP_DEFAULT_ARG: + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_INVALID_OPERAND, InitializerOp, + "Unknown buffer initializer opcode"); + printf ("Unknown buffer initializer opcode [%s]\n", + UtGetOpName (InitializerOp->Asl.ParseOpcode)); + return; + } + + /* Check if initializer list is longer than the buffer length */ + + if (BufferLengthOp->Asl.Value.Integer > BufferLength) + { + BufferLength = (UINT32) BufferLengthOp->Asl.Value.Integer; + } + + if (!BufferLength) + { + /* No length AND no items -- issue notice */ + + AslError (ASL_REMARK, ASL_MSG_BUFFER_LENGTH, BufferLengthOp, NULL); + + /* But go ahead and put the buffer length of zero into the AML */ + } + + /* + * Just set the buffer size node to be the buffer length, regardless + * of whether it was previously an integer or a default_arg placeholder + */ + BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER; + BufferLengthOp->Asl.AmlOpcode = AML_DWORD_OP; + BufferLengthOp->Asl.Value.Integer = BufferLength; + + (void) OpcSetOptimalIntegerSize (BufferLengthOp); + + /* Remaining nodes are handled via the tree walk */ +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoPackage + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the PACKAGE ASL keyword. NOTE: + * can only be called after constants have been folded, to ensure + * that the PackageLength operand has been fully reduced. + * + ******************************************************************************/ + +void +OpnDoPackage ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *PackageLengthOp; + UINT32 PackageLength = 0; + + + /* Opcode and package length first, followed by the initializer list */ + + PackageLengthOp = Op->Asl.Child; + InitializerOp = PackageLengthOp->Asl.Next; + + /* Count the number of items in the initializer list */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* The peer list contains the byte list (if any...) */ + + while (InitializerOp) + { + PackageLength++; + InitializerOp = InitializerOp->Asl.Next; + } + } + + /* If package length is a constant, compare to the initializer list */ + + if ((PackageLengthOp->Asl.ParseOpcode == PARSEOP_INTEGER) || + (PackageLengthOp->Asl.ParseOpcode == PARSEOP_QWORDCONST)) + { + if (PackageLengthOp->Asl.Value.Integer > PackageLength) + { + /* + * Allow package length to be longer than the initializer + * list -- but if the length of initializer list is nonzero, + * issue a message since this is probably a coding error, + * even though technically legal. + */ + if (PackageLength > 0) + { + AslError (ASL_REMARK, ASL_MSG_LIST_LENGTH_SHORT, + PackageLengthOp, NULL); + } + + PackageLength = (UINT32) PackageLengthOp->Asl.Value.Integer; + } + else if (PackageLengthOp->Asl.Value.Integer < PackageLength) + { + /* + * The package length is smaller than the length of the + * initializer list. This is an error as per the ACPI spec. + */ + AslError (ASL_ERROR, ASL_MSG_LIST_LENGTH_LONG, + PackageLengthOp, NULL); + } + } + + if (PackageLengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + /* + * This is the case if the PackageLength was left empty - Package() + * The package length becomes the length of the initializer list + */ + Op->Asl.Child->Asl.ParseOpcode = PARSEOP_INTEGER; + Op->Asl.Child->Asl.Value.Integer = PackageLength; + + /* Set the AML opcode */ + + (void) OpcSetOptimalIntegerSize (Op->Asl.Child); + } + + /* If not a variable-length package, check for a zero package length */ + + if ((PackageLengthOp->Asl.ParseOpcode == PARSEOP_INTEGER) || + (PackageLengthOp->Asl.ParseOpcode == PARSEOP_QWORDCONST) || + (PackageLengthOp->Asl.ParseOpcode == PARSEOP_ZERO) || + (PackageLengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)) + { + if (!PackageLength) + { + /* No length AND no initializer list -- issue a remark */ + + AslError (ASL_REMARK, ASL_MSG_PACKAGE_LENGTH, + PackageLengthOp, NULL); + + /* But go ahead and put the buffer length of zero into the AML */ + } + } + + /* + * If the PackageLength is a constant <= 255, we can change the + * AML opcode from VarPackage to a simple (ACPI 1.0) Package opcode. + */ + if (((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && + (Op->Asl.Child->Asl.Value.Integer <= 255)) || + (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ONE) || + (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ONES)|| + (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ZERO)) + { + Op->Asl.AmlOpcode = AML_PACKAGE_OP; + Op->Asl.ParseOpcode = PARSEOP_PACKAGE; + + /* + * Just set the package size node to be the package length, regardless + * of whether it was previously an integer or a default_arg placeholder + */ + PackageLengthOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + PackageLengthOp->Asl.AmlLength = 1; + PackageLengthOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + PackageLengthOp->Asl.Value.Integer = PackageLength; + } + + /* Remaining nodes are handled via the tree walk */ +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoLoadTable + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the LOADTABLE ASL keyword. + * + ******************************************************************************/ + +static void +OpnDoLoadTable ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + + + /* Opcode is parent node */ + /* First child is the table signature */ + + Next = Op->Asl.Child; + + /* Second child is the OEM ID*/ + + Next = Next->Asl.Next; + + /* Third child is the OEM table ID */ + + Next = Next->Asl.Next; + + /* Fourth child is the RootPath string */ + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode == PARSEOP_ZERO) + { + Next->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; + Next->Asl.Value.String = "\\"; + Next->Asl.AmlLength = 2; + OpcGenerateAmlOpcode (Next); + } + +#ifdef ASL_FUTURE_IMPLEMENTATION + + /* TBD: NOT IMPLEMENTED */ + /* Fifth child is the [optional] ParameterPathString */ + /* Sixth child is the [optional] ParameterData */ + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode == DEFAULT_ARG) + { + Next->Asl.AmlLength = 1; + Next->Asl.ParseOpcode = ZERO; + OpcGenerateAmlOpcode (Next); + } + + + Next = Next->Asl.Next; + if (Next->Asl.ParseOpcode == DEFAULT_ARG) + { + Next->Asl.AmlLength = 1; + Next->Asl.ParseOpcode = ZERO; + OpcGenerateAmlOpcode (Next); + } +#endif +} + + +/******************************************************************************* + * + * FUNCTION: OpnDoDefinitionBlock + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Construct the AML operands for the DEFINITIONBLOCK ASL keyword + * + ******************************************************************************/ + +static void +OpnDoDefinitionBlock ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Child; + ACPI_SIZE Length; + UINT32 i; + char *Filename; + + + /* + * These nodes get stuffed into the table header. They are special + * cased when the table is written to the output file. + * + * Mark all of these nodes as non-usable so they won't get output + * as AML opcodes! + */ + + /* Get AML filename. Use it if non-null */ + + Child = Op->Asl.Child; + if (Child->Asl.Value.Buffer && + *Child->Asl.Value.Buffer && + (Gbl_UseDefaultAmlFilename)) + { + /* + * We will use the AML filename that is embedded in the source file + * for the output filename. + */ + Filename = UtStringCacheCalloc (strlen (Gbl_DirectoryPath) + + strlen ((char *) Child->Asl.Value.Buffer) + 1); + + /* Prepend the current directory path */ + + strcpy (Filename, Gbl_DirectoryPath); + strcat (Filename, (char *) Child->Asl.Value.Buffer); + + Gbl_OutputFilenamePrefix = Filename; + UtConvertBackslashes (Gbl_OutputFilenamePrefix); + } + + Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + + /* Signature */ + + Child = Child->Asl.Next; + Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + if (Child->Asl.Value.String) + { + Gbl_TableSignature = Child->Asl.Value.String; + if (strlen (Gbl_TableSignature) != ACPI_NAME_SIZE) + { + AslError (ASL_ERROR, ASL_MSG_TABLE_SIGNATURE, Child, + "Length is not exactly 4"); + } + + for (i = 0; i < ACPI_NAME_SIZE; i++) + { + if (!isalnum ((int) Gbl_TableSignature[i])) + { + AslError (ASL_ERROR, ASL_MSG_TABLE_SIGNATURE, Child, + "Contains non-alphanumeric characters"); + } + } + } + + /* Revision */ + + Child = Child->Asl.Next; + Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + /* + * We used the revision to set the integer width earlier + */ + + /* OEMID */ + + Child = Child->Asl.Next; + Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + + /* OEM TableID */ + + Child = Child->Asl.Next; + Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + if (Child->Asl.Value.String) + { + Length = strlen (Child->Asl.Value.String); + Gbl_TableId = UtStringCacheCalloc (Length + 1); + strcpy (Gbl_TableId, Child->Asl.Value.String); + + /* + * Convert anything non-alphanumeric to an underscore. This + * allows us to use the TableID to generate unique C symbols. + */ + for (i = 0; i < Length; i++) + { + if (!isalnum ((int) Gbl_TableId[i])) + { + Gbl_TableId[i] = '_'; + } + } + } + + /* OEM Revision */ + + Child = Child->Asl.Next; + Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; +} + + +/******************************************************************************* + * + * FUNCTION: UtGetArg + * + * PARAMETERS: Op - Get an argument for this op + * Argn - Nth argument to get + * + * RETURN: The argument (as an Op object). NULL if argument does not exist + * + * DESCRIPTION: Get the specified op's argument (peer) + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +UtGetArg ( + ACPI_PARSE_OBJECT *Op, + UINT32 Argn) +{ + ACPI_PARSE_OBJECT *Arg = NULL; + + + /* Get the requested argument object */ + + Arg = Op->Asl.Child; + while (Arg && Argn) + { + Argn--; + Arg = Arg->Asl.Next; + } + + return (Arg); +} + + +/******************************************************************************* + * + * FUNCTION: OpnAttachNameToNode + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: For the named ASL/AML operators, get the actual name from the + * argument list and attach it to the parent node so that we + * can get to it quickly later. + * + ******************************************************************************/ + +static void +OpnAttachNameToNode ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Child = NULL; + + + if (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) + { + Child = UtGetArg (Op, 0); + } + else switch (Op->Asl.AmlOpcode) + { + case AML_DATA_REGION_OP: + case AML_DEVICE_OP: + case AML_EVENT_OP: + case AML_METHOD_OP: + case AML_MUTEX_OP: + case AML_REGION_OP: + case AML_POWER_RES_OP: + case AML_PROCESSOR_OP: + case AML_THERMAL_ZONE_OP: + case AML_NAME_OP: + case AML_SCOPE_OP: + + Child = UtGetArg (Op, 0); + break; + + case AML_ALIAS_OP: + + Child = UtGetArg (Op, 1); + break; + + case AML_CREATE_BIT_FIELD_OP: + case AML_CREATE_BYTE_FIELD_OP: + case AML_CREATE_WORD_FIELD_OP: + case AML_CREATE_DWORD_FIELD_OP: + case AML_CREATE_QWORD_FIELD_OP: + + Child = UtGetArg (Op, 2); + break; + + case AML_CREATE_FIELD_OP: + + Child = UtGetArg (Op, 3); + break; + + case AML_BANK_FIELD_OP: + case AML_INDEX_FIELD_OP: + case AML_FIELD_OP: + + return; + + default: + + return; + } + + if (Child) + { + UtAttachNamepathToOwner (Op, Child); + } +} + + +/******************************************************************************* + * + * FUNCTION: OpnGenerateAmlOperands + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more + * complex AML opcodes require processing of the child nodes + * (arguments/operands). + * + ******************************************************************************/ + +void +OpnGenerateAmlOperands ( + ACPI_PARSE_OBJECT *Op) +{ + + + if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) + { + return; + } + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_DEFINITION_BLOCK: + + OpnDoDefinitionBlock (Op); + break; + + case PARSEOP_METHOD: + + OpnDoMethod (Op); + break; + + case PARSEOP_MUTEX: + + OpnDoMutex (Op); + break; + + case PARSEOP_FIELD: + + OpnDoField (Op); + break; + + case PARSEOP_INDEXFIELD: + + OpnDoIndexField (Op); + break; + + case PARSEOP_BANKFIELD: + + OpnDoBankField (Op); + break; + + case PARSEOP_BUFFER: + + OpnDoBuffer (Op); + break; + + case PARSEOP_LOADTABLE: + + OpnDoLoadTable (Op); + break; + + case PARSEOP_OPERATIONREGION: + + OpnDoRegion (Op); + break; + + case PARSEOP_RESOURCETEMPLATE: + + RsDoResourceTemplate (Op); + break; + + case PARSEOP_NAMESEG: + case PARSEOP_NAMESTRING: + case PARSEOP_METHODCALL: + case PARSEOP_STRING_LITERAL: + + break; + + default: + + break; + } + + /* TBD: move */ + + OpnAttachNameToNode (Op); +} diff --git a/third_party/lib/acpica/source/compiler/aslopt.c b/third_party/lib/acpica/source/compiler/aslopt.c new file mode 100644 index 000000000..d39e2cb07 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslopt.c @@ -0,0 +1,809 @@ +/****************************************************************************** + * + * Module Name: aslopt- Compiler optimizations + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslopt") + + +static UINT32 OptTotal = 0; + +/* Local prototypes */ + +static ACPI_STATUS +OptSearchToRoot ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *CurrentNode, + ACPI_NAMESPACE_NODE *TargetNode, + ACPI_BUFFER *TargetPath, + char **NewPath); + +static ACPI_STATUS +OptBuildShortestPath ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *CurrentNode, + ACPI_NAMESPACE_NODE *TargetNode, + ACPI_BUFFER *CurrentPath, + ACPI_BUFFER *TargetPath, + ACPI_SIZE AmlNameStringLength, + UINT8 IsDeclaration, + char **ReturnNewPath); + +static ACPI_STATUS +OptOptimizeNameDeclaration ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *CurrentNode, + ACPI_NAMESPACE_NODE *TargetNode, + char *AmlNameString, + char **NewPath); + + +/******************************************************************************* + * + * FUNCTION: OptSearchToRoot + * + * PARAMETERS: Op - Current parser op + * WalkState - Current state + * CurrentNode - Where we are in the namespace + * TargetNode - Node to which we are referring + * TargetPath - External full path to the target node + * NewPath - Where the optimized path is returned + * + * RETURN: Status + * + * DESCRIPTION: Attempt to optimize a reference to a single 4-character ACPI + * name utilizing the search-to-root name resolution algorithm + * that is used by AML interpreters. + * + ******************************************************************************/ + +static ACPI_STATUS +OptSearchToRoot ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *CurrentNode, + ACPI_NAMESPACE_NODE *TargetNode, + ACPI_BUFFER *TargetPath, + char **NewPath) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_GENERIC_STATE ScopeInfo; + ACPI_STATUS Status; + char *Path; + + + ACPI_FUNCTION_NAME (OptSearchToRoot); + + + /* + * Check if search-to-root can be utilized. Use the last NameSeg of + * the NamePath and 1) See if can be found and 2) If found, make + * sure that it is the same node that we want. If there is another + * name in the search path before the one we want, the nodes will + * not match, and we cannot use this optimization. + */ + Path = &(((char *) TargetPath->Pointer)[ + TargetPath->Length - ACPI_NAME_SIZE]), + ScopeInfo.Scope.Node = CurrentNode; + + /* Lookup the NameSeg using SEARCH_PARENT (search-to-root) */ + + Status = AcpiNsLookup (&ScopeInfo, Path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &(Node)); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * We found the name, but we must check to make sure that the node + * matches. Otherwise, there is another identical name in the search + * path that precludes the use of this optimization. + */ + if (Node != TargetNode) + { + /* + * This means that another object with the same name was found first, + * and we cannot use this optimization. + */ + return (AE_NOT_FOUND); + } + + /* Found the node, we can use this optimization */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + "NAMESEG: %-24s", Path)); + + /* We must allocate a new string for the name (TargetPath gets deleted) */ + + *NewPath = UtStringCacheCalloc (ACPI_NAME_SIZE + 1); + strcpy (*NewPath, Path); + + if (strncmp (*NewPath, "_T_", 3)) + { + AslError (ASL_OPTIMIZATION, ASL_MSG_SINGLE_NAME_OPTIMIZATION, + Op, *NewPath); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: OptBuildShortestPath + * + * PARAMETERS: Op - Current parser op + * WalkState - Current state + * CurrentNode - Where we are in the namespace + * TargetNode - Node to which we are referring + * CurrentPath - External full path to the current node + * TargetPath - External full path to the target node + * AmlNameStringLength - Length of the original namepath + * IsDeclaration - TRUE for declaration, FALSE for reference + * ReturnNewPath - Where the optimized path is returned + * + * RETURN: Status + * + * DESCRIPTION: Build an optimal NamePath using carats + * + ******************************************************************************/ + +static ACPI_STATUS +OptBuildShortestPath ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *CurrentNode, + ACPI_NAMESPACE_NODE *TargetNode, + ACPI_BUFFER *CurrentPath, + ACPI_BUFFER *TargetPath, + ACPI_SIZE AmlNameStringLength, + UINT8 IsDeclaration, + char **ReturnNewPath) +{ + UINT32 NumCommonSegments; + UINT32 MaxCommonSegments; + UINT32 Index; + UINT32 NumCarats; + UINT32 i; + char *NewPath; + char *NewPathExternal; + ACPI_NAMESPACE_NODE *Node; + ACPI_GENERIC_STATE ScopeInfo; + ACPI_STATUS Status; + BOOLEAN SubPath = FALSE; + + + ACPI_FUNCTION_NAME (OptBuildShortestPath); + + + ScopeInfo.Scope.Node = CurrentNode; + + /* + * Determine the maximum number of NameSegs that the Target and Current paths + * can possibly have in common. (To optimize, we have to have at least 1) + * + * Note: The external NamePath string lengths are always a multiple of 5 + * (ACPI_NAME_SIZE + separator) + */ + MaxCommonSegments = TargetPath->Length / ACPI_PATH_SEGMENT_LENGTH; + if (CurrentPath->Length < TargetPath->Length) + { + MaxCommonSegments = CurrentPath->Length / ACPI_PATH_SEGMENT_LENGTH; + } + + /* + * Determine how many NameSegs the two paths have in common. + * (Starting from the root) + */ + for (NumCommonSegments = 0; + NumCommonSegments < MaxCommonSegments; + NumCommonSegments++) + { + /* Compare two single NameSegs */ + + if (!ACPI_COMPARE_NAME ( + &((char *) TargetPath->Pointer)[ + (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1], + &((char *) CurrentPath->Pointer)[ + (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1])) + { + /* Mismatch */ + + break; + } + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " COMMON: %u", + NumCommonSegments)); + + /* There must be at least 1 common NameSeg in order to optimize */ + + if (NumCommonSegments == 0) + { + return (AE_NOT_FOUND); + } + + if (NumCommonSegments == MaxCommonSegments) + { + if (CurrentPath->Length == TargetPath->Length) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " SAME PATH")); + return (AE_NOT_FOUND); + } + else + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " SUBPATH")); + SubPath = TRUE; + } + } + + /* Determine how many prefix Carats are required */ + + NumCarats = (CurrentPath->Length / ACPI_PATH_SEGMENT_LENGTH) - + NumCommonSegments; + + /* + * Construct a new target string + */ + NewPathExternal = ACPI_ALLOCATE_ZEROED ( + TargetPath->Length + NumCarats + 1); + + /* Insert the Carats into the Target string */ + + for (i = 0; i < NumCarats; i++) + { + NewPathExternal[i] = AML_PARENT_PREFIX; + } + + /* + * Copy only the necessary (optimal) segments from the original + * target string + */ + Index = (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1; + + /* Special handling for exact subpath in a name declaration */ + + if (IsDeclaration && SubPath && (CurrentPath->Length > TargetPath->Length)) + { + /* + * The current path is longer than the target, and the target is a + * subpath of the current path. We must include one more NameSeg of + * the target path + */ + Index -= ACPI_PATH_SEGMENT_LENGTH; + + /* Special handling for Scope() operator */ + + if (Op->Asl.AmlOpcode == AML_SCOPE_OP) + { + NewPathExternal[i] = AML_PARENT_PREFIX; + i++; + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "(EXTRA ^)")); + } + } + + /* Make sure we haven't gone off the end of the target path */ + + if (Index > TargetPath->Length) + { + Index = TargetPath->Length; + } + + strcpy (&NewPathExternal[i], &((char *) TargetPath->Pointer)[Index]); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " %-24s", NewPathExternal)); + + /* + * Internalize the new target string and check it against the original + * string to make sure that this is in fact an optimization. If the + * original string is already optimal, there is no point in continuing. + */ + Status = AcpiNsInternalizeName (NewPathExternal, &NewPath); + if (ACPI_FAILURE (Status)) + { + AslCoreSubsystemError (Op, Status, "Internalizing new NamePath", + ASL_NO_ABORT); + ACPI_FREE (NewPathExternal); + return (Status); + } + + if (strlen (NewPath) >= AmlNameStringLength) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + " NOT SHORTER (New %u old %u)", + (UINT32) strlen (NewPath), (UINT32) AmlNameStringLength)); + ACPI_FREE (NewPathExternal); + return (AE_NOT_FOUND); + } + + /* + * Check to make sure that the optimization finds the node we are + * looking for. This is simply a sanity check on the new + * path that has been created. + */ + Status = AcpiNsLookup (&ScopeInfo, NewPath, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_DONT_OPEN_SCOPE, WalkState, &(Node)); + if (ACPI_SUCCESS (Status)) + { + /* Found the namepath, but make sure the node is correct */ + + if (Node == TargetNode) + { + /* The lookup matched the node, accept this optimization */ + + AslError (ASL_OPTIMIZATION, ASL_MSG_NAME_OPTIMIZATION, + Op, NewPathExternal); + *ReturnNewPath = NewPath; + } + else + { + /* Node is not correct, do not use this optimization */ + + Status = AE_NOT_FOUND; + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ***** WRONG NODE")); + AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, + "Not using optimized name - found wrong node"); + } + } + else + { + /* The lookup failed, we obviously cannot use this optimization */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ***** NOT FOUND")); + AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, + "Not using optimized name - did not find node"); + } + + ACPI_FREE (NewPathExternal); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: OptOptimizeNameDeclaration + * + * PARAMETERS: Op - Current parser op + * WalkState - Current state + * CurrentNode - Where we are in the namespace + * AmlNameString - Unoptimized namepath + * NewPath - Where the optimized path is returned + * + * RETURN: Status. AE_OK If path is optimized + * + * DESCRIPTION: Perform a simple optimization of removing an extraneous + * backslash prefix if we are already at the root scope. + * + ******************************************************************************/ + +static ACPI_STATUS +OptOptimizeNameDeclaration ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *CurrentNode, + ACPI_NAMESPACE_NODE *TargetNode, + char *AmlNameString, + char **NewPath) +{ + ACPI_STATUS Status; + char *NewPathExternal; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (OptOptimizeNameDeclaration); + + + if (((CurrentNode == AcpiGbl_RootNode) || + (Op->Common.Parent->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)) && + (ACPI_IS_ROOT_PREFIX (AmlNameString[0]))) + { + /* + * The current scope is the root, and the namepath has a root prefix + * that is therefore extraneous. Remove it. + */ + *NewPath = &AmlNameString[1]; + + /* Debug output */ + + Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, *NewPath, + NULL, &NewPathExternal); + if (ACPI_FAILURE (Status)) + { + AslCoreSubsystemError (Op, Status, "Externalizing NamePath", + ASL_NO_ABORT); + return (Status); + } + + /* + * Check to make sure that the optimization finds the node we are + * looking for. This is simply a sanity check on the new + * path that has been created. + * + * We know that we are at the root, so NULL is used for the scope. + */ + Status = AcpiNsLookup (NULL, *NewPath, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_DONT_OPEN_SCOPE, WalkState, &(Node)); + if (ACPI_SUCCESS (Status)) + { + /* Found the namepath, but make sure the node is correct */ + + if (Node == TargetNode) + { + /* The lookup matched the node, accept this optimization */ + + AslError (ASL_OPTIMIZATION, ASL_MSG_NAME_OPTIMIZATION, + Op, NewPathExternal); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + "AT ROOT: %-24s", NewPathExternal)); + } + else + { + /* Node is not correct, do not use this optimization */ + + Status = AE_NOT_FOUND; + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + " ***** WRONG NODE")); + AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, + "Not using optimized name - found wrong node"); + } + } + else + { + /* The lookup failed, we obviously cannot use this optimization */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + " ***** NOT FOUND")); + AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, + "Not using optimized name - did not find node"); + } + + ACPI_FREE (NewPathExternal); + return (Status); + } + + /* Could not optimize */ + + return (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: OptOptimizeNamePath + * + * PARAMETERS: Op - Current parser op + * Flags - Opcode info flags + * WalkState - Current state + * AmlNameString - Unoptimized namepath + * TargetNode - Node to which AmlNameString refers + * + * RETURN: None. If path is optimized, the Op is updated with new path + * + * DESCRIPTION: Optimize a Named Declaration or Reference to the minimal length. + * Must take into account both the current location in the + * namespace and the actual reference path. + * + ******************************************************************************/ + +void +OptOptimizeNamePath ( + ACPI_PARSE_OBJECT *Op, + UINT32 Flags, + ACPI_WALK_STATE *WalkState, + char *AmlNameString, + ACPI_NAMESPACE_NODE *TargetNode) +{ + ACPI_STATUS Status; + ACPI_BUFFER TargetPath; + ACPI_BUFFER CurrentPath; + ACPI_SIZE AmlNameStringLength; + ACPI_NAMESPACE_NODE *CurrentNode; + char *ExternalNameString; + char *NewPath = NULL; + ACPI_SIZE HowMuchShorter; + ACPI_PARSE_OBJECT *NextOp; + + + ACPI_FUNCTION_TRACE (OptOptimizeNamePath); + + + /* This is an optional optimization */ + + if (!Gbl_ReferenceOptimizationFlag) + { + return_VOID; + } + + /* Various required items */ + + if (!TargetNode || !WalkState || !AmlNameString || !Op->Common.Parent) + { + return_VOID; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + "PATH OPTIMIZE: Line %5d ParentOp [%12.12s] ThisOp [%12.12s] ", + Op->Asl.LogicalLineNumber, + AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), + AcpiPsGetOpcodeName (Op->Common.AmlOpcode))); + + if (!(Flags & (AML_NAMED | AML_CREATE))) + { + if (Op->Asl.CompileFlags & NODE_IS_NAME_DECLARATION) + { + /* We don't want to fuss with actual name declaration nodes here */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + "******* NAME DECLARATION\n")); + return_VOID; + } + } + + /* + * The original path must be longer than one NameSeg (4 chars) for there + * to be any possibility that it can be optimized to a shorter string + */ + AmlNameStringLength = strlen (AmlNameString); + if (AmlNameStringLength <= ACPI_NAME_SIZE) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + "NAMESEG %4.4s\n", AmlNameString)); + return_VOID; + } + + /* + * We need to obtain the node that represents the current scope -- where + * we are right now in the namespace. We will compare this path + * against the Namepath, looking for commonality. + */ + CurrentNode = AcpiGbl_RootNode; + if (WalkState->ScopeInfo) + { + CurrentNode = WalkState->ScopeInfo->Scope.Node; + } + + if (Flags & (AML_NAMED | AML_CREATE)) + { + /* This is the declaration of a new name */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "NAME\n")); + + /* + * The node of interest is the parent of this node (the containing + * scope). The actual namespace node may be up more than one level + * of parse op or it may not exist at all (if we traverse back + * up to the root.) + */ + NextOp = Op->Asl.Parent; + while (NextOp && (!NextOp->Asl.Node)) + { + NextOp = NextOp->Asl.Parent; + } + + if (NextOp && NextOp->Asl.Node) + { + CurrentNode = NextOp->Asl.Node; + } + else + { + CurrentNode = AcpiGbl_RootNode; + } + } + else + { + /* This is a reference to an existing named object */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "REFERENCE\n")); + } + + /* + * Obtain the full paths to the two nodes that we are interested in + * (Target and current namespace location) in external + * format -- something we can easily manipulate + */ + TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (TargetNode, &TargetPath, FALSE); + if (ACPI_FAILURE (Status)) + { + AslCoreSubsystemError (Op, Status, "Getting Target NamePath", + ASL_NO_ABORT); + return_VOID; + } + + TargetPath.Length--; /* Subtract one for null terminator */ + + /* CurrentPath is the path to this scope (where we are in the namespace) */ + + CurrentPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (CurrentNode, &CurrentPath, FALSE); + if (ACPI_FAILURE (Status)) + { + AslCoreSubsystemError (Op, Status, "Getting Current NamePath", + ASL_NO_ABORT); + return_VOID; + } + + CurrentPath.Length--; /* Subtract one for null terminator */ + + /* Debug output only */ + + Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, AmlNameString, + NULL, &ExternalNameString); + if (ACPI_FAILURE (Status)) + { + AslCoreSubsystemError (Op, Status, "Externalizing NamePath", + ASL_NO_ABORT); + return_VOID; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + "CURRENT SCOPE: (%2u) %-37s FULL PATH TO NAME: (%2u) %-32s ACTUAL AML:%-32s\n", + (UINT32) CurrentPath.Length, (char *) CurrentPath.Pointer, + (UINT32) TargetPath.Length, (char *) TargetPath.Pointer, + ExternalNameString)); + + ACPI_FREE (ExternalNameString); + + /* + * Attempt an optmization depending on the type of namepath + */ + if (Flags & (AML_NAMED | AML_CREATE)) + { + /* + * This is a named opcode and the namepath is a name declaration, not + * a reference. + */ + Status = OptOptimizeNameDeclaration (Op, WalkState, CurrentNode, + TargetNode, AmlNameString, &NewPath); + if (ACPI_FAILURE (Status)) + { + /* + * 2) now attempt to + * optimize the namestring with carats (up-arrow) + */ + Status = OptBuildShortestPath (Op, WalkState, CurrentNode, + TargetNode, &CurrentPath, &TargetPath, + AmlNameStringLength, 1, &NewPath); + } + } + else + { + /* + * This is a reference to an existing named object + * + * 1) Check if search-to-root can be utilized using the last + * NameSeg of the NamePath + */ + Status = OptSearchToRoot (Op, WalkState, CurrentNode, + TargetNode, &TargetPath, &NewPath); + if (ACPI_FAILURE (Status)) + { + /* + * 2) Search-to-root could not be used, now attempt to + * optimize the namestring with carats (up-arrow) + */ + Status = OptBuildShortestPath (Op, WalkState, CurrentNode, + TargetNode, &CurrentPath, &TargetPath, + AmlNameStringLength, 0, &NewPath); + } + } + + /* + * Success from above indicates that the NamePath was successfully + * optimized. We need to update the parse op with the new name + */ + if (ACPI_SUCCESS (Status)) + { + HowMuchShorter = (AmlNameStringLength - strlen (NewPath)); + OptTotal += HowMuchShorter; + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, + " REDUCED BY %2u (TOTAL SAVED %2u)", + (UINT32) HowMuchShorter, OptTotal)); + + if (Flags & AML_NAMED) + { + if (Op->Asl.AmlOpcode == AML_ALIAS_OP) + { + /* + * ALIAS is the only oddball opcode, the name declaration + * (alias name) is the second operand + */ + Op->Asl.Child->Asl.Next->Asl.Value.String = NewPath; + Op->Asl.Child->Asl.Next->Asl.AmlLength = strlen (NewPath); + } + else + { + Op->Asl.Child->Asl.Value.String = NewPath; + Op->Asl.Child->Asl.AmlLength = strlen (NewPath); + } + } + else if (Flags & AML_CREATE) + { + /* Name must appear as the last parameter */ + + NextOp = Op->Asl.Child; + while (!(NextOp->Asl.CompileFlags & NODE_IS_NAME_DECLARATION)) + { + NextOp = NextOp->Asl.Next; + } + /* Update the parse node with the new NamePath */ + + NextOp->Asl.Value.String = NewPath; + NextOp->Asl.AmlLength = strlen (NewPath); + } + else + { + /* Update the parse node with the new NamePath */ + + Op->Asl.Value.String = NewPath; + Op->Asl.AmlLength = strlen (NewPath); + } + } + else + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ALREADY OPTIMAL")); + } + + /* Cleanup path buffers */ + + ACPI_FREE (TargetPath.Pointer); + ACPI_FREE (CurrentPath.Pointer); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "\n")); + return_VOID; +} diff --git a/third_party/lib/acpica/source/compiler/asloptions.c b/third_party/lib/acpica/source/compiler/asloptions.c new file mode 100644 index 000000000..ca392b68c --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asloptions.c @@ -0,0 +1,898 @@ +/****************************************************************************** + * + * Module Name: asloptions - compiler command line processing + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acapps.h" +#include "acdisasm.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asloption") + + +/* Local prototypes */ + +static int +AslDoOptions ( + int argc, + char **argv, + BOOLEAN IsResponseFile); + +static void +AslMergeOptionTokens ( + char *InBuffer, + char *OutBuffer); + +static int +AslDoResponseFile ( + char *Filename); + + +#define ASL_TOKEN_SEPARATORS " \t\n" +#define ASL_SUPPORTED_OPTIONS "@:a:b|c|d^D:e:f^gh^i|I:l^m:no|p:P^r:s|t|T+G^v^w|x:z" + + +/******************************************************************************* + * + * FUNCTION: AslCommandLine + * + * PARAMETERS: argc/argv + * + * RETURN: Last argv index + * + * DESCRIPTION: Command line processing + * + ******************************************************************************/ + +int +AslCommandLine ( + int argc, + char **argv) +{ + int BadCommandLine = 0; + ACPI_STATUS Status; + + + /* Minimum command line contains at least the command and an input file */ + + if (argc < 2) + { + printf (ACPI_COMMON_SIGNON (ASL_COMPILER_NAME)); + Usage (); + exit (1); + } + + /* Process all command line options */ + + BadCommandLine = AslDoOptions (argc, argv, FALSE); + + if (Gbl_DoTemplates) + { + Status = DtCreateTemplates (argv); + if (ACPI_FAILURE (Status)) + { + exit (-1); + } + exit (1); + } + + /* Next parameter must be the input filename */ + + if (!argv[AcpiGbl_Optind] && + !Gbl_DisasmFlag) + { + printf ("Missing input filename\n"); + BadCommandLine = TRUE; + } + + if (Gbl_DoSignon) + { + printf (ACPI_COMMON_SIGNON (ASL_COMPILER_NAME)); + if (Gbl_IgnoreErrors) + { + printf ("Ignoring all errors, forcing AML file generation\n\n"); + } + } + + if (BadCommandLine) + { + printf ("Use -h option for help information\n"); + exit (1); + } + + return (AcpiGbl_Optind); +} + + +/******************************************************************************* + * + * FUNCTION: AslDoOptions + * + * PARAMETERS: argc/argv - Standard argc/argv + * IsResponseFile - TRUE if executing a response file. + * + * RETURN: Status + * + * DESCRIPTION: Command line option processing + * + ******************************************************************************/ + +static int +AslDoOptions ( + int argc, + char **argv, + BOOLEAN IsResponseFile) +{ + ACPI_STATUS Status; + UINT32 j; + + + /* Get the command line options */ + + while ((j = AcpiGetopt (argc, argv, ASL_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch (j) + { + case '@': /* Begin a response file */ + + if (IsResponseFile) + { + printf ("Nested command files are not supported\n"); + return (-1); + } + + if (AslDoResponseFile (AcpiGbl_Optarg)) + { + return (-1); + } + break; + + case 'a': /* Debug options */ + + switch (AcpiGbl_Optarg[0]) + { + case 'r': + + Gbl_EnableReferenceTypechecking = TRUE; + break; + + default: + + printf ("Unknown option: -a%s\n", AcpiGbl_Optarg); + return (-1); + } + + break; + + + case 'b': /* Debug options */ + + switch (AcpiGbl_Optarg[0]) + { + case 'f': + + AslCompilerdebug = 1; /* same as yydebug */ + DtParserdebug = 1; + PrParserdebug = 1; + Gbl_DebugFlag = TRUE; + Gbl_KeepPreprocessorTempFile = TRUE; + break; + + case 'p': /* Prune ASL parse tree */ + + /* Get the required argument */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + Gbl_PruneParseTree = TRUE; + Gbl_PruneDepth = (UINT8) strtoul (AcpiGbl_Optarg, NULL, 0); + break; + + case 's': + + Gbl_DebugFlag = TRUE; + break; + + case 't': + + /* Get the required argument */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + Gbl_PruneType = (UINT8) strtoul (AcpiGbl_Optarg, NULL, 0); + break; + + default: + + printf ("Unknown option: -b%s\n", AcpiGbl_Optarg); + return (-1); + } + + break; + + case 'c': + + switch (AcpiGbl_Optarg[0]) + { + case 'r': + + Gbl_NoResourceChecking = TRUE; + break; + + default: + + printf ("Unknown option: -c%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'd': /* Disassembler */ + + switch (AcpiGbl_Optarg[0]) + { + case '^': + + Gbl_DoCompile = FALSE; + break; + + case 'a': + + Gbl_DoCompile = FALSE; + Gbl_DisassembleAll = TRUE; + break; + + case 'b': /* Do not convert buffers to resource descriptors */ + + AcpiGbl_NoResourceDisassembly = TRUE; + break; + + case 'c': + + break; + + case 'f': + + AcpiGbl_ForceAmlDisassembly = TRUE; + break; + + case 'l': /* Use legacy ASL code (not ASL+) for disassembly */ + + Gbl_DoCompile = FALSE; + AcpiGbl_CstyleDisassembly = FALSE; + break; + + default: + + printf ("Unknown option: -d%s\n", AcpiGbl_Optarg); + return (-1); + } + + Gbl_DisasmFlag = TRUE; + break; + + case 'D': /* Define a symbol */ + + PrAddDefine (AcpiGbl_Optarg, NULL, TRUE); + break; + + case 'e': /* External files for disassembler */ + + /* Get entire list of external files */ + + AcpiGbl_Optind--; + argv[AcpiGbl_Optind] = AcpiGbl_Optarg; + + while (argv[AcpiGbl_Optind] && + (argv[AcpiGbl_Optind][0] != '-')) + { + Status = AcpiDmAddToExternalFileList (argv[AcpiGbl_Optind]); + if (ACPI_FAILURE (Status)) + { + printf ("Could not add %s to external list\n", + argv[AcpiGbl_Optind]); + return (-1); + } + + AcpiGbl_Optind++; + } + break; + + case 'f': + + switch (AcpiGbl_Optarg[0]) + { + case '^': /* Ignore errors and force creation of aml file */ + + Gbl_IgnoreErrors = TRUE; + break; + + case 'e': /* Disassembler: Get external declaration file */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + Gbl_ExternalRefFilename = AcpiGbl_Optarg; + break; + + default: + + printf ("Unknown option: -f%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'G': + + Gbl_CompileGeneric = TRUE; + break; + + case 'g': /* Get all ACPI tables */ + + printf ("-g option is deprecated, use acpidump utility instead\n"); + exit (1); + + case 'h': + + switch (AcpiGbl_Optarg[0]) + { + case '^': + + Usage (); + exit (0); + + case 'c': + + UtDisplayConstantOpcodes (); + exit (0); + + case 'f': + + AslFilenameHelp (); + exit (0); + + case 'r': + + /* reserved names */ + + ApDisplayReservedNames (); + exit (0); + + case 't': + + UtDisplaySupportedTables (); + exit (0); + + default: + + printf ("Unknown option: -h%s\n", AcpiGbl_Optarg); + return (-1); + } + + case 'I': /* Add an include file search directory */ + + FlAddIncludeDirectory (AcpiGbl_Optarg); + break; + + case 'i': /* Output AML as an include file */ + + switch (AcpiGbl_Optarg[0]) + { + case 'a': + + /* Produce assembly code include file */ + + Gbl_AsmIncludeOutputFlag = TRUE; + break; + + case 'c': + + /* Produce C include file */ + + Gbl_C_IncludeOutputFlag = TRUE; + break; + + case 'n': + + /* Compiler/Disassembler: Ignore the NOOP operator */ + + AcpiGbl_IgnoreNoopOperator = TRUE; + break; + + default: + + printf ("Unknown option: -i%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'l': /* Listing files */ + + switch (AcpiGbl_Optarg[0]) + { + case '^': + + /* Produce listing file (Mixed source/aml) */ + + Gbl_ListingFlag = TRUE; + AcpiGbl_DmOpt_Listing = TRUE; + break; + + case 'i': + + /* Produce preprocessor output file */ + + Gbl_PreprocessorOutputFlag = TRUE; + break; + + case 'm': + + /* Produce hardware map summary file */ + + Gbl_MapfileFlag = TRUE; + break; + + case 'n': + + /* Produce namespace file */ + + Gbl_NsOutputFlag = TRUE; + break; + + case 's': + + /* Produce combined source file */ + + Gbl_SourceOutputFlag = TRUE; + break; + + default: + + printf ("Unknown option: -l%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'm': /* Set line buffer size */ + + Gbl_LineBufferSize = (UINT32) strtoul (AcpiGbl_Optarg, NULL, 0) * 1024; + if (Gbl_LineBufferSize < ASL_DEFAULT_LINE_BUFFER_SIZE) + { + Gbl_LineBufferSize = ASL_DEFAULT_LINE_BUFFER_SIZE; + } + printf ("Line Buffer Size: %u\n", Gbl_LineBufferSize); + break; + + case 'n': /* Parse only */ + + Gbl_ParseOnlyFlag = TRUE; + break; + + case 'o': /* Control compiler AML optimizations */ + + switch (AcpiGbl_Optarg[0]) + { + case 'a': + + /* Disable all optimizations */ + + Gbl_FoldConstants = FALSE; + Gbl_IntegerOptimizationFlag = FALSE; + Gbl_ReferenceOptimizationFlag = FALSE; + break; + + case 'c': + + /* Display compile time(s) */ + + Gbl_CompileTimesFlag = TRUE; + break; + + case 'f': + + /* Disable folding on "normal" expressions */ + + Gbl_FoldConstants = FALSE; + break; + + case 'i': + + /* Disable integer optimization to constants */ + + Gbl_IntegerOptimizationFlag = FALSE; + break; + + case 'n': + + /* Disable named reference optimization */ + + Gbl_ReferenceOptimizationFlag = FALSE; + break; + + case 't': + + /* Disable heavy typechecking */ + + Gbl_DoTypechecking = FALSE; + break; + + default: + + printf ("Unknown option: -c%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'P': /* Preprocessor options */ + + switch (AcpiGbl_Optarg[0]) + { + case '^': /* Proprocess only, emit (.i) file */ + + Gbl_PreprocessOnly = TRUE; + Gbl_PreprocessorOutputFlag = TRUE; + break; + + case 'n': /* Disable preprocessor */ + + Gbl_PreprocessFlag = FALSE; + break; + + default: + + printf ("Unknown option: -P%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'p': /* Override default AML output filename */ + + Gbl_OutputFilenamePrefix = AcpiGbl_Optarg; + UtConvertBackslashes (Gbl_OutputFilenamePrefix); + Gbl_UseDefaultAmlFilename = FALSE; + break; + + case 'r': /* Override revision found in table header */ + + Gbl_RevisionOverride = (UINT8) strtoul (AcpiGbl_Optarg, NULL, 0); + break; + + case 's': /* Create AML in a source code file */ + + switch (AcpiGbl_Optarg[0]) + { + case 'a': + + /* Produce assembly code output file */ + + Gbl_AsmOutputFlag = TRUE; + break; + + case 'c': + + /* Produce C hex output file */ + + Gbl_C_OutputFlag = TRUE; + break; + + case 'o': + + /* Produce AML offset table in C */ + + Gbl_C_OffsetTableFlag = TRUE; + break; + + default: + + printf ("Unknown option: -s%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 't': /* Produce hex table output file */ + + switch (AcpiGbl_Optarg[0]) + { + case 'a': + + Gbl_HexOutputFlag = HEX_OUTPUT_ASM; + break; + + case 'c': + + Gbl_HexOutputFlag = HEX_OUTPUT_C; + break; + + case 's': + + Gbl_HexOutputFlag = HEX_OUTPUT_ASL; + break; + + default: + + printf ("Unknown option: -t%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'T': /* Create a ACPI table template file */ + + Gbl_DoTemplates = TRUE; + break; + + case 'v': /* Version and verbosity settings */ + + switch (AcpiGbl_Optarg[0]) + { + case '^': + + printf (ACPI_COMMON_SIGNON (ASL_COMPILER_NAME)); + exit (0); + + case 'a': + + /* Disable all error/warning/remark messages */ + + Gbl_NoErrors = TRUE; + break; + + case 'e': + + /* Disable all warning/remark messages (errors only) */ + + Gbl_DisplayRemarks = FALSE; + Gbl_DisplayWarnings = FALSE; + break; + + case 'i': + /* + * Support for integrated development environment(s). + * + * 1) No compiler signon + * 2) Send stderr messages to stdout + * 3) Less verbose error messages (single line only for each) + * 4) Error/warning messages are formatted appropriately to + * be recognized by MS Visual Studio + */ + Gbl_VerboseErrors = FALSE; + Gbl_DoSignon = FALSE; + Gbl_Files[ASL_FILE_STDERR].Handle = stdout; + break; + + case 'o': + + Gbl_DisplayOptimizations = TRUE; + break; + + case 'r': + + Gbl_DisplayRemarks = FALSE; + break; + + case 's': + + Gbl_DoSignon = FALSE; + break; + + case 't': + + Gbl_VerboseTemplates = TRUE; + break; + + case 'w': + + /* Get the required argument */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + Status = AslDisableException (AcpiGbl_Optarg); + if (ACPI_FAILURE (Status)) + { + return (-1); + } + break; + + default: + + printf ("Unknown option: -v%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'w': /* Set warning levels */ + + switch (AcpiGbl_Optarg[0]) + { + case '1': + + Gbl_WarningLevel = ASL_WARNING; + break; + + case '2': + + Gbl_WarningLevel = ASL_WARNING2; + break; + + case '3': + + Gbl_WarningLevel = ASL_WARNING3; + break; + + case 'e': + + Gbl_WarningsAsErrors = TRUE; + break; + + default: + + printf ("Unknown option: -w%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'x': /* Set debug print output level */ + + AcpiDbgLevel = strtoul (AcpiGbl_Optarg, NULL, 16); + break; + + case 'z': + + Gbl_UseOriginalCompilerId = TRUE; + break; + + default: + + return (-1); + } + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AslMergeOptionTokens + * + * PARAMETERS: InBuffer - Input containing an option string + * OutBuffer - Merged output buffer + * + * RETURN: None + * + * DESCRIPTION: Remove all whitespace from an option string. + * + ******************************************************************************/ + +static void +AslMergeOptionTokens ( + char *InBuffer, + char *OutBuffer) +{ + char *Token; + + + *OutBuffer = 0; + + Token = strtok (InBuffer, ASL_TOKEN_SEPARATORS); + while (Token) + { + strcat (OutBuffer, Token); + Token = strtok (NULL, ASL_TOKEN_SEPARATORS); + } +} + + +/******************************************************************************* + * + * FUNCTION: AslDoResponseFile + * + * PARAMETERS: Filename - Name of the response file + * + * RETURN: Status + * + * DESCRIPTION: Open a response file and process all options within. + * + ******************************************************************************/ + +static int +AslDoResponseFile ( + char *Filename) +{ + char *argv = StringBuffer2; + FILE *ResponseFile; + int OptStatus = 0; + int Opterr; + int Optind; + + + ResponseFile = fopen (Filename, "r"); + if (!ResponseFile) + { + printf ("Could not open command file %s, %s\n", + Filename, strerror (errno)); + return (-1); + } + + /* Must save the current GetOpt globals */ + + Opterr = AcpiGbl_Opterr; + Optind = AcpiGbl_Optind; + + /* + * Process all lines in the response file. There must be one complete + * option per line + */ + while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ResponseFile)) + { + /* Compress all tokens, allowing us to use a single argv entry */ + + AslMergeOptionTokens (StringBuffer, StringBuffer2); + + /* Process the option */ + + AcpiGbl_Opterr = 0; + AcpiGbl_Optind = 0; + + OptStatus = AslDoOptions (1, &argv, TRUE); + if (OptStatus) + { + printf ("Invalid option in command file %s: %s\n", + Filename, StringBuffer); + break; + } + } + + /* Restore the GetOpt globals */ + + AcpiGbl_Opterr = Opterr; + AcpiGbl_Optind = Optind; + + fclose (ResponseFile); + return (OptStatus); +} diff --git a/third_party/lib/acpica/source/compiler/aslparser.y b/third_party/lib/acpica/source/compiler/aslparser.y new file mode 100644 index 000000000..00718e4bc --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslparser.y @@ -0,0 +1,133 @@ +%{ +/****************************************************************************** + * + * Module Name: aslparser.y - Master Bison/Yacc input file for iASL + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslparse") + +/* + * Global Notes: + * + * October 2005: The following list terms have been optimized (from the + * original ASL grammar in the ACPI specification) to force the immediate + * reduction of each list item so that the parse stack use doesn't increase on + * each list element and possibly overflow on very large lists (>4000 items). + * This dramatically reduces use of the parse stack overall. + * + * ArgList, TermList, Objectlist, ByteList, DWordList, PackageList, + * ResourceMacroList, and FieldUnitList + */ + +void * +AslLocalAllocate ( + unsigned int Size); + +/* Bison/yacc configuration */ + +#define static +#undef malloc +#define malloc AslLocalAllocate +#undef alloca +#define alloca AslLocalAllocate +#define yytname AslCompilername + +#define YYINITDEPTH 600 /* State stack depth */ +#define YYDEBUG 1 /* Enable debug output */ +#define YYERROR_VERBOSE 1 /* Verbose error messages */ +#define YYFLAG -32768 + +/* Define YYMALLOC/YYFREE to prevent redefinition errors */ + +#define YYMALLOC AslLocalAllocate +#define YYFREE ACPI_FREE +%} + +/* + * Declare the type of values in the grammar + */ +%union { + UINT64 i; + char *s; + ACPI_PARSE_OBJECT *n; +} + +/* + * These shift/reduce conflicts are expected. There should be zero + * reduce/reduce conflicts. + */ +%expect 89 + +/*! [Begin] no source code translation */ + +/* + * The M4 macro processor is used to bring in the parser items, + * in order to keep this master file smaller, and to break up + * the various parser items. + */ +m4_define(NoEcho) + +/* Token types */ + +m4_include(asltokens.y) + +/* Production types/names */ + +m4_include(asltypes.y) +%% + +/* Production rules */ + +m4_include(aslrules.y) +m4_include(aslcstyle.y) +m4_include(aslresources.y) +%% + +/*! [End] no source code translation !*/ + +/* Local support functions in C */ + +m4_include(aslsupport.y) diff --git a/third_party/lib/acpica/source/compiler/aslpredef.c b/third_party/lib/acpica/source/compiler/aslpredef.c new file mode 100644 index 000000000..f18befa88 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslpredef.c @@ -0,0 +1,788 @@ +/****************************************************************************** + * + * Module Name: aslpredef - support for ACPI predefined names + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define ACPI_CREATE_PREDEFINED_TABLE +#define ACPI_CREATE_RESOURCE_TABLE + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acpredef.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslpredef") + + +/* Local prototypes */ + +static void +ApCheckForUnexpectedReturnValue ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo); + +static UINT32 +ApCheckForSpecialName ( + ACPI_PARSE_OBJECT *Op, + char *Name); + + +/******************************************************************************* + * + * FUNCTION: ApCheckForPredefinedMethod + * + * PARAMETERS: Op - A parse node of type "METHOD". + * MethodInfo - Saved info about this method + * + * RETURN: None + * + * DESCRIPTION: If method is a predefined name, check that the number of + * arguments and the return type (returns a value or not) + * is correct. + * + ******************************************************************************/ + +BOOLEAN +ApCheckForPredefinedMethod ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo) +{ + UINT32 Index; + UINT32 RequiredArgCount; + const ACPI_PREDEFINED_INFO *ThisName; + + + /* Check for a match against the predefined name list */ + + Index = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); + + switch (Index) + { + case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ + case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ + case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ + + /* Just return, nothing to do */ + return (FALSE); + + + case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ + + Gbl_ReservedMethods++; + + /* NumArguments must be zero for all _Lxx/_Exx/_Wxx/_Qxx methods */ + + if (MethodInfo->NumArguments != 0) + { + sprintf (MsgBuffer, "%s requires %u", Op->Asl.ExternalName, 0); + + AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_HI, Op, + MsgBuffer); + } + break; + + + default: + /* + * Matched a predefined method name - validate the ASL-defined + * argument count against the ACPI specification. + * + * Some methods are allowed to have a "minimum" number of args + * (_SCP) because their definition in ACPI has changed over time. + */ + Gbl_ReservedMethods++; + ThisName = &AcpiGbl_PredefinedMethods[Index]; + RequiredArgCount = METHOD_GET_ARG_COUNT (ThisName->Info.ArgumentList); + + if (MethodInfo->NumArguments != RequiredArgCount) + { + sprintf (MsgBuffer, "%4.4s requires %u", + ThisName->Info.Name, RequiredArgCount); + + if (MethodInfo->NumArguments < RequiredArgCount) + { + AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_LO, Op, + MsgBuffer); + } + else if ((MethodInfo->NumArguments > RequiredArgCount) && + !(ThisName->Info.ArgumentList & ARG_COUNT_IS_MINIMUM)) + { + AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_HI, Op, + MsgBuffer); + } + } + + /* + * Check if method returns no value, but the predefined name is + * required to return a value + */ + if (MethodInfo->NumReturnNoValue && + ThisName->Info.ExpectedBtypes) + { + AcpiUtGetExpectedReturnTypes (StringBuffer, + ThisName->Info.ExpectedBtypes); + + sprintf (MsgBuffer, "%s required for %4.4s", + StringBuffer, ThisName->Info.Name); + + AslError (ASL_WARNING, ASL_MSG_RESERVED_RETURN_VALUE, Op, + MsgBuffer); + } + break; + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckForUnexpectedReturnValue + * + * PARAMETERS: Op - A parse node of type "RETURN". + * MethodInfo - Saved info about this method + * + * RETURN: None + * + * DESCRIPTION: Check for an unexpected return value from a predefined method. + * Invoked for predefined methods that are defined to not return + * any value. If there is a return value, issue a remark, since + * the ASL writer may be confused as to the method definition + * and/or functionality. + * + * Note: We ignore all return values of "Zero", since this is what a standalone + * Return() statement will always generate -- so we ignore it here -- + * i.e., there is no difference between Return() and Return(Zero). + * Also, a null Return() will be disassembled to return(Zero) -- so, we + * don't want to generate extraneous remarks/warnings for a disassembled + * ASL file. + * + ******************************************************************************/ + +static void +ApCheckForUnexpectedReturnValue ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo) +{ + ACPI_PARSE_OBJECT *ReturnValueOp; + + + /* Ignore Return() and Return(Zero) (they are the same) */ + + ReturnValueOp = Op->Asl.Child; + if (ReturnValueOp->Asl.ParseOpcode == PARSEOP_ZERO) + { + return; + } + + /* We have a valid return value, but the reserved name did not expect it */ + + AslError (ASL_WARNING, ASL_MSG_RESERVED_NO_RETURN_VAL, + Op, MethodInfo->Op->Asl.ExternalName); +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckPredefinedReturnValue + * + * PARAMETERS: Op - A parse node of type "RETURN". + * MethodInfo - Saved info about this method + * + * RETURN: None + * + * DESCRIPTION: If method is a predefined name, attempt to validate the return + * value. Only "static" types can be validated - a simple return + * of an integer/string/buffer/package or a named reference to + * a static object. Values such as a Localx or Argx or a control + * method invocation are not checked. Issue a warning if there is + * a valid return value, but the reserved method defines no + * return value. + * + ******************************************************************************/ + +void +ApCheckPredefinedReturnValue ( + ACPI_PARSE_OBJECT *Op, + ASL_METHOD_INFO *MethodInfo) +{ + UINT32 Index; + ACPI_PARSE_OBJECT *ReturnValueOp; + const ACPI_PREDEFINED_INFO *ThisName; + + + /* + * Check parent method for a match against the predefined name list. + * + * Note: Disable compiler errors/warnings because any errors will be + * caught when analyzing the parent method. Eliminates duplicate errors. + */ + Gbl_AllExceptionsDisabled = TRUE; + Index = ApCheckForPredefinedName (MethodInfo->Op, + MethodInfo->Op->Asl.NameSeg); + Gbl_AllExceptionsDisabled = FALSE; + + switch (Index) + { + case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ + + /* No return value expected, warn if there is one */ + + ApCheckForUnexpectedReturnValue (Op, MethodInfo); + return; + + case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ + case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ + case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ + + /* Just return, nothing to do */ + return; + + default: /* A standard predefined ACPI name */ + + ThisName = &AcpiGbl_PredefinedMethods[Index]; + if (!ThisName->Info.ExpectedBtypes) + { + /* No return value expected, warn if there is one */ + + ApCheckForUnexpectedReturnValue (Op, MethodInfo); + return; + } + + /* Get the object returned, it is the next argument */ + + ReturnValueOp = Op->Asl.Child; + switch (ReturnValueOp->Asl.ParseOpcode) + { + case PARSEOP_ZERO: + case PARSEOP_ONE: + case PARSEOP_ONES: + case PARSEOP_INTEGER: + case PARSEOP_STRING_LITERAL: + case PARSEOP_BUFFER: + case PARSEOP_PACKAGE: + + /* Static data return object - check against expected type */ + + ApCheckObjectType (ThisName->Info.Name, ReturnValueOp, + ThisName->Info.ExpectedBtypes, ACPI_NOT_PACKAGE_ELEMENT); + + /* For packages, check the individual package elements */ + + if (ReturnValueOp->Asl.ParseOpcode == PARSEOP_PACKAGE) + { + ApCheckPackage (ReturnValueOp, ThisName); + } + break; + + default: + /* + * All other ops are very difficult or impossible to typecheck at + * compile time. These include all Localx, Argx, and method + * invocations. Also, NAMESEG and NAMESTRING because the type of + * any named object can be changed at runtime (for example, + * CopyObject will change the type of the target object.) + */ + break; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckForPredefinedObject + * + * PARAMETERS: Op - A parse node + * Name - The ACPI name to be checked + * + * RETURN: None + * + * DESCRIPTION: Check for a predefined name for a static object (created via + * the ASL Name operator). If it is a predefined ACPI name, ensure + * that the name does not require any arguments (which would + * require a control method implemenation of the name), and that + * the type of the object is one of the expected types for the + * predefined name. + * + ******************************************************************************/ + +void +ApCheckForPredefinedObject ( + ACPI_PARSE_OBJECT *Op, + char *Name) +{ + UINT32 Index; + ACPI_PARSE_OBJECT *ObjectOp; + const ACPI_PREDEFINED_INFO *ThisName; + + + /* + * Check for a real predefined name -- not a resource descriptor name + * or a predefined scope name + */ + Index = ApCheckForPredefinedName (Op, Name); + + switch (Index) + { + case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ + case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ + case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ + + /* Nothing to do */ + return; + + case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ + + /* + * These names must be control methods, by definition in ACPI spec. + * Also because they are defined to return no value. None of them + * require any arguments. + */ + AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, + "with zero arguments"); + return; + + default: + + break; + } + + /* A standard predefined ACPI name */ + + /* + * If this predefined name requires input arguments, then + * it must be implemented as a control method + */ + ThisName = &AcpiGbl_PredefinedMethods[Index]; + if (METHOD_GET_ARG_COUNT (ThisName->Info.ArgumentList) > 0) + { + AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, + "with arguments"); + return; + } + + /* + * If no return value is expected from this predefined name, then + * it follows that it must be implemented as a control method + * (with zero args, because the args > 0 case was handled above) + * Examples are: _DIS, _INI, _IRC, _OFF, _ON, _PSx + */ + if (!ThisName->Info.ExpectedBtypes) + { + AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, + "with zero arguments"); + return; + } + + /* Typecheck the actual object, it is the next argument */ + + ObjectOp = Op->Asl.Child->Asl.Next; + ApCheckObjectType (ThisName->Info.Name, Op->Asl.Child->Asl.Next, + ThisName->Info.ExpectedBtypes, ACPI_NOT_PACKAGE_ELEMENT); + + /* For packages, check the individual package elements */ + + if (ObjectOp->Asl.ParseOpcode == PARSEOP_PACKAGE) + { + ApCheckPackage (ObjectOp, ThisName); + } +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckForPredefinedName + * + * PARAMETERS: Op - A parse node + * Name - NameSeg to check + * + * RETURN: None + * + * DESCRIPTION: Check a NameSeg against the reserved list. + * + ******************************************************************************/ + +UINT32 +ApCheckForPredefinedName ( + ACPI_PARSE_OBJECT *Op, + char *Name) +{ + UINT32 i; + const ACPI_PREDEFINED_INFO *ThisName; + + + if (Name[0] == 0) + { + AcpiOsPrintf ("Found a null name, external = %s\n", + Op->Asl.ExternalName); + } + + /* All reserved names are prefixed with a single underscore */ + + if (Name[0] != '_') + { + return (ACPI_NOT_RESERVED_NAME); + } + + /* Check for a standard predefined method name */ + + ThisName = AcpiGbl_PredefinedMethods; + for (i = 0; ThisName->Info.Name[0]; i++) + { + if (ACPI_COMPARE_NAME (Name, ThisName->Info.Name)) + { + /* Return index into predefined array */ + return (i); + } + + ThisName++; /* Does not account for extra package data, but is OK */ + } + + /* Check for resource names and predefined scope names */ + + ThisName = AcpiGbl_ResourceNames; + while (ThisName->Info.Name[0]) + { + if (ACPI_COMPARE_NAME (Name, ThisName->Info.Name)) + { + return (ACPI_PREDEFINED_NAME); + } + + ThisName++; + } + + ThisName = AcpiGbl_ScopeNames; + while (ThisName->Info.Name[0]) + { + if (ACPI_COMPARE_NAME (Name, ThisName->Info.Name)) + { + return (ACPI_PREDEFINED_NAME); + } + + ThisName++; + } + + /* Check for _Lxx/_Exx/_Wxx/_Qxx/_T_x. Warning if unknown predefined name */ + + return (ApCheckForSpecialName (Op, Name)); +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckForSpecialName + * + * PARAMETERS: Op - A parse node + * Name - NameSeg to check + * + * RETURN: None + * + * DESCRIPTION: Check for the "special" predefined names - + * _Lxx, _Exx, _Qxx, _Wxx, and _T_x + * + ******************************************************************************/ + +static UINT32 +ApCheckForSpecialName ( + ACPI_PARSE_OBJECT *Op, + char *Name) +{ + + /* + * Check for the "special" predefined names. We already know that the + * first character is an underscore. + * GPE: _Lxx + * GPE: _Exx + * GPE: _Wxx + * EC: _Qxx + */ + if ((Name[1] == 'L') || + (Name[1] == 'E') || + (Name[1] == 'W') || + (Name[1] == 'Q')) + { + /* The next two characters must be hex digits */ + + if ((isxdigit ((int) Name[2])) && + (isxdigit ((int) Name[3]))) + { + return (ACPI_EVENT_RESERVED_NAME); + } + } + + /* Check for the names reserved for the compiler itself: _T_x */ + + else if ((Op->Asl.ExternalName[1] == 'T') && + (Op->Asl.ExternalName[2] == '_')) + { + /* Ignore if actually emitted by the compiler */ + + if (Op->Asl.CompileFlags & NODE_COMPILER_EMITTED) + { + return (ACPI_NOT_RESERVED_NAME); + } + + /* + * Was not actually emitted by the compiler. This is a special case, + * however. If the ASL code being compiled was the result of a + * dissasembly, it may possibly contain valid compiler-emitted names + * of the form "_T_x". We don't want to issue an error or even a + * warning and force the user to manually change the names. So, we + * will issue a remark instead. + */ + AslError (ASL_REMARK, ASL_MSG_COMPILER_RESERVED, + Op, Op->Asl.ExternalName); + return (ACPI_COMPILER_RESERVED_NAME); + } + + /* + * The name didn't match any of the known predefined names. Flag it as a + * warning, since the entire namespace starting with an underscore is + * reserved by the ACPI spec. + */ + AslError (ASL_WARNING, ASL_MSG_UNKNOWN_RESERVED_NAME, + Op, Op->Asl.ExternalName); + + return (ACPI_NOT_RESERVED_NAME); +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckObjectType + * + * PARAMETERS: PredefinedName - Name of the predefined object we are checking + * Op - Current parse node + * ExpectedBtypes - Bitmap of expected return type(s) + * PackageIndex - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * + * RETURN: None + * + * DESCRIPTION: Check if the object type is one of the types that is expected + * by the predefined name. Only a limited number of object types + * can be returned by the predefined names. + * + ******************************************************************************/ + +ACPI_STATUS +ApCheckObjectType ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT32 ExpectedBtypes, + UINT32 PackageIndex) +{ + UINT32 ReturnBtype; + char *TypeName; + + + if (!Op) + { + return (AE_TYPE); + } + + /* Map the parse opcode to a bitmapped return type (RTYPE) */ + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_ZERO: + case PARSEOP_ONE: + case PARSEOP_ONES: + case PARSEOP_INTEGER: + + ReturnBtype = ACPI_RTYPE_INTEGER; + TypeName = "Integer"; + break; + + case PARSEOP_STRING_LITERAL: + + ReturnBtype = ACPI_RTYPE_STRING; + TypeName = "String"; + break; + + case PARSEOP_BUFFER: + + ReturnBtype = ACPI_RTYPE_BUFFER; + TypeName = "Buffer"; + break; + + case PARSEOP_PACKAGE: + case PARSEOP_VAR_PACKAGE: + + ReturnBtype = ACPI_RTYPE_PACKAGE; + TypeName = "Package"; + break; + + case PARSEOP_NAMESEG: + case PARSEOP_NAMESTRING: + /* + * Ignore any named references within a package object. + * + * For Package objects, references are allowed instead of any of the + * standard data types (Integer/String/Buffer/Package). These + * references are resolved at runtime. NAMESEG and NAMESTRING are + * impossible to typecheck at compile time because the type of + * any named object can be changed at runtime (for example, + * CopyObject will change the type of the target object). + */ + if (PackageIndex != ACPI_NOT_PACKAGE_ELEMENT) + { + return (AE_OK); + } + + ReturnBtype = ACPI_RTYPE_REFERENCE; + TypeName = "Reference"; + break; + + default: + + /* Not one of the supported object types */ + + TypeName = UtGetOpName (Op->Asl.ParseOpcode); + goto TypeErrorExit; + } + + /* Exit if the object is one of the expected types */ + + if (ReturnBtype & ExpectedBtypes) + { + return (AE_OK); + } + + +TypeErrorExit: + + /* Format the expected types and emit an error message */ + + AcpiUtGetExpectedReturnTypes (StringBuffer, ExpectedBtypes); + + if (PackageIndex == ACPI_NOT_PACKAGE_ELEMENT) + { + sprintf (MsgBuffer, "%4.4s: found %s, %s required", + PredefinedName, TypeName, StringBuffer); + } + else + { + sprintf (MsgBuffer, "%4.4s: found %s at index %u, %s required", + PredefinedName, TypeName, PackageIndex, StringBuffer); + } + + AslError (ASL_ERROR, ASL_MSG_RESERVED_OPERAND_TYPE, Op, MsgBuffer); + return (AE_TYPE); +} + + +/******************************************************************************* + * + * FUNCTION: ApDisplayReservedNames + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump information about the ACPI predefined names and predefined + * resource descriptor names. + * + ******************************************************************************/ + +void +ApDisplayReservedNames ( + void) +{ + const ACPI_PREDEFINED_INFO *ThisName; + UINT32 Count; + UINT32 NumTypes; + + + /* + * Predefined names/methods + */ + printf ("\nPredefined Name Information\n\n"); + + Count = 0; + ThisName = AcpiGbl_PredefinedMethods; + while (ThisName->Info.Name[0]) + { + AcpiUtDisplayPredefinedMethod (MsgBuffer, ThisName, FALSE); + Count++; + ThisName = AcpiUtGetNextPredefinedMethod (ThisName); + } + + printf ("%u Predefined Names are recognized\n", Count); + + /* + * Resource Descriptor names + */ + printf ("\nPredefined Names for Resource Descriptor Fields\n\n"); + + Count = 0; + ThisName = AcpiGbl_ResourceNames; + while (ThisName->Info.Name[0]) + { + NumTypes = AcpiUtGetResourceBitWidth (MsgBuffer, + ThisName->Info.ArgumentList); + + printf ("%4.4s Field is %s bits wide%s\n", + ThisName->Info.Name, MsgBuffer, + (NumTypes > 1) ? " (depending on descriptor type)" : ""); + + Count++; + ThisName++; + } + + printf ("%u Resource Descriptor Field Names are recognized\n", Count); + + /* + * Predefined scope names + */ + printf ("\nPredefined Scope/Device Names (automatically created at root)\n\n"); + + ThisName = AcpiGbl_ScopeNames; + while (ThisName->Info.Name[0]) + { + printf ("%4.4s Scope/Device\n", ThisName->Info.Name); + ThisName++; + } +} diff --git a/third_party/lib/acpica/source/compiler/aslprepkg.c b/third_party/lib/acpica/source/compiler/aslprepkg.c new file mode 100644 index 000000000..f82b4e31c --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslprepkg.c @@ -0,0 +1,780 @@ +/****************************************************************************** + * + * Module Name: aslprepkg - support for ACPI predefined name package objects + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslprepkg") + + +/* Local prototypes */ + +static void +ApCheckPackageElements ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT8 Type1, + UINT32 Count1, + UINT8 Type2, + UINT32 Count2); + +static void +ApCheckPackageList ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *ParentOp, + const ACPI_PREDEFINED_INFO *Package, + UINT32 StartIndex, + UINT32 Count); + +static void +ApPackageTooSmall ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT32 Count, + UINT32 ExpectedCount); + +static void +ApZeroLengthPackage ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op); + +static void +ApPackageTooLarge ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT32 Count, + UINT32 ExpectedCount); + + +/******************************************************************************* + * + * FUNCTION: ApCheckPackage + * + * PARAMETERS: ParentOp - Parser op for the package + * Predefined - Pointer to package-specific info for + * the method + * + * RETURN: None + * + * DESCRIPTION: Top-level validation for predefined name return package + * objects. + * + ******************************************************************************/ + +void +ApCheckPackage ( + ACPI_PARSE_OBJECT *ParentOp, + const ACPI_PREDEFINED_INFO *Predefined) +{ + ACPI_PARSE_OBJECT *Op; + const ACPI_PREDEFINED_INFO *Package; + ACPI_STATUS Status; + UINT32 ExpectedCount; + UINT32 Count; + UINT32 i; + + + /* The package info for this name is in the next table entry */ + + Package = Predefined + 1; + + /* First child is the package length */ + + Op = ParentOp->Asl.Child; + Count = (UINT32) Op->Asl.Value.Integer; + + /* + * Many of the variable-length top-level packages are allowed to simply + * have zero elements. This allows the BIOS to tell the host that even + * though the predefined name/method exists, the feature is not supported. + * Other package types require one or more elements. In any case, there + * is no need to continue validation. + */ + if (!Count) + { + switch (Package->RetInfo.Type) + { + case ACPI_PTYPE1_FIXED: + case ACPI_PTYPE1_OPTION: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_REV_FIXED: + + ApZeroLengthPackage (Predefined->Info.Name, ParentOp); + break; + + case ACPI_PTYPE1_VAR: + case ACPI_PTYPE2: + case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_FIXED: + case ACPI_PTYPE2_MIN: + case ACPI_PTYPE2_FIX_VAR: + case ACPI_PTYPE2_VAR_VAR: + default: + + break; + } + + return; + } + + /* Get the first element of the package */ + + Op = Op->Asl.Next; + + /* Decode the package type */ + + switch (Package->RetInfo.Type) + { + case ACPI_PTYPE1_FIXED: + /* + * The package count is fixed and there are no subpackages + * + * If package is too small, exit. + * If package is larger than expected, issue warning but continue + */ + ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; + if (Count < ExpectedCount) + { + goto PackageTooSmall; + } + else if (Count > ExpectedCount) + { + ApPackageTooLarge (Predefined->Info.Name, ParentOp, + Count, ExpectedCount); + } + + /* Validate all elements of the package */ + + ApCheckPackageElements (Predefined->Info.Name, Op, + Package->RetInfo.ObjectType1, Package->RetInfo.Count1, + Package->RetInfo.ObjectType2, Package->RetInfo.Count2); + break; + + case ACPI_PTYPE1_VAR: + /* + * The package count is variable, there are no subpackages, + * and all elements must be of the same type + */ + for (i = 0; i < Count; i++) + { + ApCheckObjectType (Predefined->Info.Name, Op, + Package->RetInfo.ObjectType1, i); + Op = Op->Asl.Next; + } + break; + + case ACPI_PTYPE1_OPTION: + /* + * The package count is variable, there are no subpackages. + * There are a fixed number of required elements, and a variable + * number of optional elements. + * + * Check if package is at least as large as the minimum required + */ + ExpectedCount = Package->RetInfo3.Count; + if (Count < ExpectedCount) + { + goto PackageTooSmall; + } + + /* Variable number of sub-objects */ + + for (i = 0; i < Count; i++) + { + if (i < Package->RetInfo3.Count) + { + /* These are the required package elements (0, 1, or 2) */ + + ApCheckObjectType (Predefined->Info.Name, Op, + Package->RetInfo3.ObjectType[i], i); + } + else + { + /* These are the optional package elements */ + + ApCheckObjectType (Predefined->Info.Name, Op, + Package->RetInfo3.TailObjectType, i); + } + + Op = Op->Asl.Next; + } + break; + + case ACPI_PTYPE2_REV_FIXED: + + /* First element is the (Integer) revision */ + + ApCheckObjectType (Predefined->Info.Name, Op, + ACPI_RTYPE_INTEGER, 0); + + Op = Op->Asl.Next; + Count--; + + /* Examine the subpackages */ + + ApCheckPackageList (Predefined->Info.Name, Op, + Package, 1, Count); + break; + + case ACPI_PTYPE2_PKG_COUNT: + + /* First element is the (Integer) count of subpackages to follow */ + + Status = ApCheckObjectType (Predefined->Info.Name, Op, + ACPI_RTYPE_INTEGER, 0); + + /* We must have an integer count from above (otherwise, use Count) */ + + if (ACPI_SUCCESS (Status)) + { + /* + * Count cannot be larger than the parent package length, but + * allow it to be smaller. The >= accounts for the Integer above. + */ + ExpectedCount = (UINT32) Op->Asl.Value.Integer; + if (ExpectedCount >= Count) + { + goto PackageTooSmall; + } + + Count = ExpectedCount; + } + + Op = Op->Asl.Next; + + /* Examine the subpackages */ + + ApCheckPackageList (Predefined->Info.Name, Op, + Package, 1, Count); + break; + + case ACPI_PTYPE2_UUID_PAIR: + + /* The package contains a variable list of UUID Buffer/Package pairs */ + + /* The length of the package must be even */ + + if (Count & 1) + { + sprintf (MsgBuffer, "%4.4s: Package length, %d, must be even.", + Predefined->Info.Name, Count); + + AslError (ASL_ERROR, ASL_MSG_RESERVED_PACKAGE_LENGTH, + ParentOp->Asl.Child, MsgBuffer); + } + + /* Validate the alternating types */ + + for (i = 0; i < Count; ++i) + { + if (i & 1) + { + ApCheckObjectType (Predefined->Info.Name, Op, + Package->RetInfo.ObjectType2, i); + } + else + { + ApCheckObjectType (Predefined->Info.Name, Op, + Package->RetInfo.ObjectType1, i); + } + + Op = Op->Asl.Next; + } + + break; + + case ACPI_PTYPE2_VAR_VAR: + + /* Check for minimum size (ints at beginning + 1 subpackage) */ + + ExpectedCount = Package->RetInfo4.Count1 + 1; + if (Count < ExpectedCount) + { + goto PackageTooSmall; + } + + /* Check the non-package elements at beginning of main package */ + + for (i = 0; i < Package->RetInfo4.Count1; ++i) + { + Status = ApCheckObjectType (Predefined->Info.Name, Op, + Package->RetInfo4.ObjectType1, i); + Op = Op->Asl.Next; + } + + /* Examine the variable-length list of subpackages */ + + ApCheckPackageList (Predefined->Info.Name, Op, + Package, Package->RetInfo4.Count1, Count); + + break; + + case ACPI_PTYPE2: + case ACPI_PTYPE2_FIXED: + case ACPI_PTYPE2_MIN: + case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_FIX_VAR: + /* + * These types all return a single Package that consists of a + * variable number of subpackages. + */ + + /* Examine the subpackages */ + + ApCheckPackageList (Predefined->Info.Name, Op, + Package, 0, Count); + break; + + default: + return; + } + + return; + +PackageTooSmall: + ApPackageTooSmall (Predefined->Info.Name, ParentOp, + Count, ExpectedCount); +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckPackageElements + * + * PARAMETERS: PredefinedName - Name of the predefined object + * Op - Parser op for the package + * Type1 - Object type for first group + * Count1 - Count for first group + * Type2 - Object type for second group + * Count2 - Count for second group + * + * RETURN: None + * + * DESCRIPTION: Validate all elements of a package. Works with packages that + * are defined to contain up to two groups of different object + * types. + * + ******************************************************************************/ + +static void +ApCheckPackageElements ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT8 Type1, + UINT32 Count1, + UINT8 Type2, + UINT32 Count2) +{ + UINT32 i; + + + /* + * Up to two groups of package elements are supported by the data + * structure. All elements in each group must be of the same type. + * The second group can have a count of zero. + * + * Aborts check upon a NULL package element, as this means (at compile + * time) that the remainder of the package elements are also NULL + * (This is the only way to create NULL package elements.) + */ + for (i = 0; (i < Count1) && Op; i++) + { + ApCheckObjectType (PredefinedName, Op, Type1, i); + Op = Op->Asl.Next; + } + + for (i = 0; (i < Count2) && Op; i++) + { + ApCheckObjectType (PredefinedName, Op, Type2, (i + Count1)); + Op = Op->Asl.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: ApCheckPackageList + * + * PARAMETERS: PredefinedName - Name of the predefined object + * ParentOp - Parser op of the parent package + * Package - Package info for this predefined name + * StartIndex - Index in parent package where list begins + * ParentCount - Element count of parent package + * + * RETURN: None + * + * DESCRIPTION: Validate the individual package elements for a predefined name. + * Handles the cases where the predefined name is defined as a + * Package of Packages (subpackages). These are the types: + * + * ACPI_PTYPE2 + * ACPI_PTYPE2_FIXED + * ACPI_PTYPE2_MIN + * ACPI_PTYPE2_COUNT + * ACPI_PTYPE2_FIX_VAR + * ACPI_PTYPE2_VAR_VAR + * + ******************************************************************************/ + +static void +ApCheckPackageList ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *ParentOp, + const ACPI_PREDEFINED_INFO *Package, + UINT32 StartIndex, + UINT32 ParentCount) +{ + ACPI_PARSE_OBJECT *SubPackageOp = ParentOp; + ACPI_PARSE_OBJECT *Op; + ACPI_STATUS Status; + UINT32 Count; + UINT32 ExpectedCount; + UINT32 i; + UINT32 j; + + + /* + * Validate each subpackage in the parent Package + * + * Note: We ignore NULL package elements on the assumption that + * they will be initialized by the BIOS or other ASL code. + */ + for (i = 0; (i < ParentCount) && SubPackageOp; i++) + { + /* Each object in the list must be of type Package */ + + Status = ApCheckObjectType (PredefinedName, SubPackageOp, + ACPI_RTYPE_PACKAGE, i + StartIndex); + if (ACPI_FAILURE (Status)) + { + goto NextSubpackage; + } + + /* Examine the different types of expected subpackages */ + + Op = SubPackageOp->Asl.Child; + + /* First child is the package length */ + + Count = (UINT32) Op->Asl.Value.Integer; + Op = Op->Asl.Next; + + /* + * Most subpackage must have at least one element, with + * only rare exceptions. (_RDI) + */ + if (!Count && + (Package->RetInfo.Type != ACPI_PTYPE2_VAR_VAR)) + { + ApZeroLengthPackage (PredefinedName, SubPackageOp); + goto NextSubpackage; + } + + /* + * Decode the package type. + * PTYPE2 indicates that a "package of packages" is expected for + * this name. The various flavors of PTYPE2 indicate the number + * and format of the subpackages. + */ + switch (Package->RetInfo.Type) + { + case ACPI_PTYPE2: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_REV_FIXED: + + /* Each subpackage has a fixed number of elements */ + + ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; + if (Count < ExpectedCount) + { + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + if (Count > ExpectedCount) + { + ApPackageTooLarge (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + + ApCheckPackageElements (PredefinedName, Op, + Package->RetInfo.ObjectType1, Package->RetInfo.Count1, + Package->RetInfo.ObjectType2, Package->RetInfo.Count2); + break; + + case ACPI_PTYPE2_FIX_VAR: + /* + * Each subpackage has a fixed number of elements and an + * optional element + */ + ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; + if (Count < ExpectedCount) + { + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + + ApCheckPackageElements (PredefinedName, Op, + Package->RetInfo.ObjectType1, Package->RetInfo.Count1, + Package->RetInfo.ObjectType2, + Count - Package->RetInfo.Count1); + break; + + case ACPI_PTYPE2_VAR_VAR: + /* + * Must have at least the minimum number elements. + * A zero PkgCount means the number of elements is variable. + */ + ExpectedCount = Package->RetInfo4.PkgCount; + if (ExpectedCount && (Count < ExpectedCount)) + { + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, 1); + break; + } + + ApCheckPackageElements (PredefinedName, Op, + Package->RetInfo4.SubObjectTypes, + Package->RetInfo4.PkgCount, + 0, 0); + break; + + case ACPI_PTYPE2_FIXED: + + /* Each subpackage has a fixed length */ + + ExpectedCount = Package->RetInfo2.Count; + if (Count < ExpectedCount) + { + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + if (Count > ExpectedCount) + { + ApPackageTooLarge (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + + /* Check each object/type combination */ + + for (j = 0; j < ExpectedCount; j++) + { + ApCheckObjectType (PredefinedName, Op, + Package->RetInfo2.ObjectType[j], j); + + Op = Op->Asl.Next; + } + break; + + case ACPI_PTYPE2_MIN: + + /* Each subpackage has a variable but minimum length */ + + ExpectedCount = Package->RetInfo.Count1; + if (Count < ExpectedCount) + { + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + + /* Check the type of each subpackage element */ + + ApCheckPackageElements (PredefinedName, Op, + Package->RetInfo.ObjectType1, Count, 0, 0); + break; + + case ACPI_PTYPE2_COUNT: + /* + * First element is the (Integer) count of elements, including + * the count field (the ACPI name is NumElements) + */ + Status = ApCheckObjectType (PredefinedName, Op, + ACPI_RTYPE_INTEGER, 0); + + /* We must have an integer count from above (otherwise, use Count) */ + + if (ACPI_SUCCESS (Status)) + { + /* + * Make sure package is large enough for the Count and is + * is as large as the minimum size + */ + ExpectedCount = (UINT32) Op->Asl.Value.Integer; + + if (Count < ExpectedCount) + { + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + else if (Count > ExpectedCount) + { + ApPackageTooLarge (PredefinedName, SubPackageOp, + Count, ExpectedCount); + } + + /* Some names of this type have a minimum length */ + + if (Count < Package->RetInfo.Count1) + { + ExpectedCount = Package->RetInfo.Count1; + ApPackageTooSmall (PredefinedName, SubPackageOp, + Count, ExpectedCount); + break; + } + + Count = ExpectedCount; + } + + /* Check the type of each subpackage element */ + + Op = Op->Asl.Next; + ApCheckPackageElements (PredefinedName, Op, + Package->RetInfo.ObjectType1, (Count - 1), 0, 0); + break; + + default: + break; + } + +NextSubpackage: + SubPackageOp = SubPackageOp->Asl.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: ApPackageTooSmall + * + * PARAMETERS: PredefinedName - Name of the predefined object + * Op - Current parser op + * Count - Actual package element count + * ExpectedCount - Expected package element count + * + * RETURN: None + * + * DESCRIPTION: Issue error message for a package that is smaller than + * required. + * + ******************************************************************************/ + +static void +ApPackageTooSmall ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT32 Count, + UINT32 ExpectedCount) +{ + + sprintf (MsgBuffer, "%s: length %u, required minimum is %u", + PredefinedName, Count, ExpectedCount); + + AslError (ASL_ERROR, ASL_MSG_RESERVED_PACKAGE_LENGTH, Op, MsgBuffer); +} + + +/******************************************************************************* + * + * FUNCTION: ApZeroLengthPackage + * + * PARAMETERS: PredefinedName - Name of the predefined object + * Op - Current parser op + * + * RETURN: None + * + * DESCRIPTION: Issue error message for a zero-length package (a package that + * is required to have a non-zero length). Variable length + * packages seem to be allowed to have zero length, however. + * Even if not allowed, BIOS code does it. + * + ******************************************************************************/ + +static void +ApZeroLengthPackage ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op) +{ + + sprintf (MsgBuffer, "%s: length is zero", PredefinedName); + + AslError (ASL_ERROR, ASL_MSG_RESERVED_PACKAGE_LENGTH, Op, MsgBuffer); +} + + +/******************************************************************************* + * + * FUNCTION: ApPackageTooLarge + * + * PARAMETERS: PredefinedName - Name of the predefined object + * Op - Current parser op + * Count - Actual package element count + * ExpectedCount - Expected package element count + * + * RETURN: None + * + * DESCRIPTION: Issue a remark for a package that is larger than expected. + * + ******************************************************************************/ + +static void +ApPackageTooLarge ( + const char *PredefinedName, + ACPI_PARSE_OBJECT *Op, + UINT32 Count, + UINT32 ExpectedCount) +{ + + sprintf (MsgBuffer, "%s: length is %u, only %u required", + PredefinedName, Count, ExpectedCount); + + AslError (ASL_REMARK, ASL_MSG_RESERVED_PACKAGE_LENGTH, Op, MsgBuffer); +} diff --git a/third_party/lib/acpica/source/compiler/aslprintf.c b/third_party/lib/acpica/source/compiler/aslprintf.c new file mode 100644 index 000000000..c27114cf3 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslprintf.c @@ -0,0 +1,380 @@ +/****************************************************************************** + * + * Module Name: aslprintf - ASL Printf/Fprintf macro support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslprintf") + + +/* Local prototypes */ + +static void +OpcCreateConcatenateNode ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Node); + +static void +OpcParsePrintf ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *DestOp); + + +/******************************************************************************* + * + * FUNCTION: OpcDoPrintf + * + * PARAMETERS: Op - printf parse node + * + * RETURN: None + * + * DESCRIPTION: Convert printf macro to a Store(..., Debug) AML operation. + * + ******************************************************************************/ + +void +OpcDoPrintf ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *DestOp; + + + /* Store destination is the Debug op */ + + DestOp = TrAllocateNode (PARSEOP_DEBUG); + DestOp->Asl.AmlOpcode = AML_DEBUG_OP; + DestOp->Asl.Parent = Op; + DestOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; + + OpcParsePrintf (Op, DestOp); +} + + +/******************************************************************************* + * + * FUNCTION: OpcDoFprintf + * + * PARAMETERS: Op - fprintf parse node + * + * RETURN: None + * + * DESCRIPTION: Convert fprintf macro to a Store AML operation. + * + ******************************************************************************/ + +void +OpcDoFprintf ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *DestOp; + + + /* Store destination is the first argument of fprintf */ + + DestOp = Op->Asl.Child; + Op->Asl.Child = DestOp->Asl.Next; + DestOp->Asl.Next = NULL; + + OpcParsePrintf (Op, DestOp); +} + + +/******************************************************************************* + * + * FUNCTION: OpcParsePrintf + * + * PARAMETERS: Op - Printf parse node + * DestOp - Destination of Store operation + * + * RETURN: None + * + * DESCRIPTION: Convert printf macro to a Store AML operation. The printf + * macro parse tree is layed out as follows: + * + * Op - printf parse op + * Op->Child - Format string + * Op->Next - Format string arguments + * + ******************************************************************************/ + +static void +OpcParsePrintf ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *DestOp) +{ + char *Format; + char *StartPosition = NULL; + ACPI_PARSE_OBJECT *ArgNode; + ACPI_PARSE_OBJECT *NextNode; + UINT32 StringLength = 0; + char *NewString; + BOOLEAN StringToProcess = FALSE; + ACPI_PARSE_OBJECT *NewOp; + + + /* Get format string */ + + Format = ACPI_CAST_PTR (char, Op->Asl.Child->Asl.Value.String); + ArgNode = Op->Asl.Child->Asl.Next; + + /* + * Detach argument list so that we can use a NULL check to distinguish + * the first concatenation operation we need to make + */ + Op->Asl.Child = NULL; + + for (; *Format; ++Format) + { + if (*Format != '%') + { + if (!StringToProcess) + { + /* Mark the beginning of a string */ + + StartPosition = Format; + StringToProcess = TRUE; + } + + ++StringLength; + continue; + } + + /* Save string, if any, to new string object and concat it */ + + if (StringToProcess) + { + NewString = UtStringCacheCalloc (StringLength + 1); + strncpy (NewString, StartPosition, StringLength); + + NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL); + NewOp->Asl.Value.String = NewString; + NewOp->Asl.AmlOpcode = AML_STRING_OP; + NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING; + NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; + + OpcCreateConcatenateNode(Op, NewOp); + + StringLength = 0; + StringToProcess = FALSE; + } + + ++Format; + + /* + * We have a format parameter and will need an argument to go + * with it + */ + if (!ArgNode || + ArgNode->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + AslError(ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, NULL); + return; + } + + /* + * We do not support sub-specifiers of printf (flags, width, + * precision, length). For specifiers we only support %x/%X for + * hex or %s for strings. Also, %o for generic "acpi object". + */ + switch (*Format) + { + case 's': + + if (ArgNode->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) + { + AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgNode, + "String required"); + return; + } + + NextNode = ArgNode->Asl.Next; + ArgNode->Asl.Next = NULL; + OpcCreateConcatenateNode(Op, ArgNode); + ArgNode = NextNode; + continue; + + case 'X': + case 'x': + case 'o': + + NextNode = ArgNode->Asl.Next; + ArgNode->Asl.Next = NULL; + + /* + * Append an empty string if the first argument is + * not a string. This will implicitly conver the 2nd + * concat source to a string per the ACPI specification. + */ + if (!Op->Asl.Child) + { + NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL); + NewOp->Asl.Value.String = ""; + NewOp->Asl.AmlOpcode = AML_STRING_OP; + NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING; + NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; + + OpcCreateConcatenateNode(Op, NewOp); + } + + OpcCreateConcatenateNode(Op, ArgNode); + ArgNode = NextNode; + break; + + default: + + AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Op, + "Unrecognized format specifier"); + continue; + } + } + + /* Process any remaining string */ + + if (StringToProcess) + { + NewString = UtStringCacheCalloc (StringLength + 1); + strncpy (NewString, StartPosition, StringLength); + + NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL); + NewOp->Asl.Value.String = NewString; + NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING; + NewOp->Asl.AmlOpcode = AML_STRING_OP; + NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; + + OpcCreateConcatenateNode(Op, NewOp); + } + + /* + * If we get here and there's no child node then Format + * was an empty string. Just make a no op. + */ + if (!Op->Asl.Child) + { + Op->Asl.ParseOpcode = PARSEOP_NOOP; + AslError(ASL_WARNING, ASL_MSG_NULL_STRING, Op, + "Converted to NOOP"); + return; + } + + /* Check for erroneous extra arguments */ + + if (ArgNode && + ArgNode->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + AslError(ASL_WARNING, ASL_MSG_ARG_COUNT_HI, ArgNode, + "Extra arguments ignored"); + } + + /* Change Op to a Store */ + + Op->Asl.ParseOpcode = PARSEOP_STORE; + Op->Common.AmlOpcode = AML_STORE_OP; + Op->Asl.CompileFlags = 0; + + /* Disable further optimization */ + + Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; + UtSetParseOpName (Op); + + /* Set Store destination */ + + Op->Asl.Child->Asl.Next = DestOp; +} + + +/******************************************************************************* + * + * FUNCTION: OpcCreateConcatenateNode + * + * PARAMETERS: Op - Parse node + * Node - Parse node to be concatenated + * + * RETURN: None + * + * DESCRIPTION: Make Node the child of Op. If child node already exists, then + * concat child with Node and makes concat node the child of Op. + * + ******************************************************************************/ + +static void +OpcCreateConcatenateNode ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Node) +{ + ACPI_PARSE_OBJECT *NewConcatOp; + + + if (!Op->Asl.Child) + { + Op->Asl.Child = Node; + Node->Asl.Parent = Op; + return; + } + + NewConcatOp = TrAllocateNode (PARSEOP_CONCATENATE); + NewConcatOp->Asl.AmlOpcode = AML_CONCAT_OP; + NewConcatOp->Asl.AcpiBtype = 0x7; + NewConcatOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; + + /* First arg is child of Op*/ + + NewConcatOp->Asl.Child = Op->Asl.Child; + Op->Asl.Child->Asl.Parent = NewConcatOp; + + /* Second arg is Node */ + + NewConcatOp->Asl.Child->Asl.Next = Node; + Node->Asl.Parent = NewConcatOp; + + /* Third arg is Zero (not used) */ + + NewConcatOp->Asl.Child->Asl.Next->Asl.Next = + TrAllocateNode (PARSEOP_ZERO); + NewConcatOp->Asl.Child->Asl.Next->Asl.Next->Asl.Parent = + NewConcatOp; + + Op->Asl.Child = NewConcatOp; + NewConcatOp->Asl.Parent = Op; +} diff --git a/third_party/lib/acpica/source/compiler/aslprune.c b/third_party/lib/acpica/source/compiler/aslprune.c new file mode 100644 index 000000000..f15c17a91 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslprune.c @@ -0,0 +1,241 @@ +/****************************************************************************** + * + * Module Name: aslprune - Parse tree prune utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acapps.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslprune") + + +/* Local prototypes */ + +static ACPI_STATUS +PrTreePruneWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static void +PrPrintObjectAtLevel ( + UINT32 Level, + const char *ObjectName); + + +/* Structure used for the pruning parse tree walk */ + +typedef struct acpi_prune_info +{ + UINT32 PruneLevel; + UINT16 ParseOpcode; + UINT16 Count; + +} ACPI_PRUNE_INFO; + + +/******************************************************************************* + * + * FUNCTION: AslPruneParseTree + * + * PARAMETERS: PruneDepth - Number of levels to prune + * Type - Prune type (Device, Method, etc.) + * + * RETURN: None + * + * DESCRIPTION: Prune off one or more levels of the ASL parse tree + * + ******************************************************************************/ + +void +AslPruneParseTree ( + UINT32 PruneDepth, + UINT32 Type) +{ + ACPI_PRUNE_INFO PruneObj; + + + PruneObj.PruneLevel = PruneDepth; + PruneObj.Count = 0; + + switch (Type) + { + case 0: + PruneObj.ParseOpcode = (UINT16) PARSEOP_DEVICE; + break; + + case 1: + PruneObj.ParseOpcode = (UINT16) PARSEOP_METHOD; + break; + + case 2: + PruneObj.ParseOpcode = (UINT16) PARSEOP_IF; + break; + + default: + AcpiOsPrintf ("Unsupported type: %u\n", Type); + return; + } + + AcpiOsPrintf ("Pruning parse tree, from depth %u\n", + PruneDepth); + + AcpiOsPrintf ("\nRemoving Objects:\n"); + + TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, + PrTreePruneWalk, NULL, ACPI_CAST_PTR (void, &PruneObj)); + + AcpiOsPrintf ("\n%u Total Objects Removed\n", PruneObj.Count); +} + + +/******************************************************************************* + * + * FUNCTION: PrPrintObjectAtLevel + * + * PARAMETERS: Level - Current nesting level + * ObjectName - ACPI name for the object + * + * RETURN: None + * + * DESCRIPTION: Print object name with indent + * + ******************************************************************************/ + +static void +PrPrintObjectAtLevel ( + UINT32 Level, + const char *ObjectName) +{ + UINT32 i; + + + for (i = 0; i < Level; i++) + { + AcpiOsPrintf (" "); + } + + AcpiOsPrintf ("[%s] at Level [%u]\n", ObjectName, Level); +} + + +/******************************************************************************* + * + * FUNCTION: PrTreePruneWalk + * + * PARAMETERS: Parse tree walk callback + * + * RETURN: Status + * + * DESCRIPTION: Prune off one or more levels of the ASL parse tree + * + * Current objects that can be pruned are: Devices, Methods, and If/Else + * blocks. + * + ******************************************************************************/ + +static ACPI_STATUS +PrTreePruneWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_PRUNE_INFO *PruneObj = (ACPI_PRUNE_INFO *) Context; + + + /* We only care about objects below the Prune Level threshold */ + + if (Level <= PruneObj->PruneLevel) + { + return (AE_OK); + } + + if ((Op->Asl.ParseOpcode != PruneObj->ParseOpcode) && + !(Op->Asl.ParseOpcode == PARSEOP_ELSE && + PruneObj->ParseOpcode == PARSEOP_IF)) + { + return (AE_OK); + } + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_METHOD: + + AcpiOsPrintf ("Method"); + PrPrintObjectAtLevel (Level, Op->Asl.Child->Asl.Value.Name); + Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next->Asl.Next->Asl.Next->Asl.Next = NULL; + PruneObj->Count++; + break; + + case PARSEOP_DEVICE: + + AcpiOsPrintf ("Device"); + PrPrintObjectAtLevel (Level, Op->Asl.Child->Asl.Value.Name); + Op->Asl.Child->Asl.Next = NULL; + PruneObj->Count++; + break; + + case PARSEOP_IF: + case PARSEOP_ELSE: + + if (Op->Asl.ParseOpcode == PARSEOP_ELSE) + { + PrPrintObjectAtLevel(Level, "Else"); + Op->Asl.Child = NULL; + } + else + { + PrPrintObjectAtLevel(Level, "If"); + Op->Asl.Child->Asl.Next = NULL; + } + + PruneObj->Count++; + break; + + default: + + break; + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/aslresource.c b/third_party/lib/acpica/source/compiler/aslresource.c new file mode 100644 index 000000000..001d1102d --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslresource.c @@ -0,0 +1,1090 @@ +/****************************************************************************** + * + * Module Name: aslresource - Resource template/descriptor utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslresource") + + +/******************************************************************************* + * + * FUNCTION: RsSmallAddressCheck + * + * PARAMETERS: Minimum - Address Min value + * Maximum - Address Max value + * Length - Address range value + * Alignment - Address alignment value + * MinOp - Original Op for Address Min + * MaxOp - Original Op for Address Max + * LengthOp - Original Op for address range + * AlignOp - Original Op for address alignment. If + * NULL, means "zero value for alignment is + * OK, and means 64K alignment" (for + * Memory24 descriptor) + * Op - Parent Op for entire construct + * + * RETURN: None. Adds error messages to error log if necessary + * + * DESCRIPTION: Perform common value checks for "small" address descriptors. + * Currently: + * Io, Memory24, Memory32 + * + ******************************************************************************/ + +void +RsSmallAddressCheck ( + UINT8 Type, + UINT32 Minimum, + UINT32 Maximum, + UINT32 Length, + UINT32 Alignment, + ACPI_PARSE_OBJECT *MinOp, + ACPI_PARSE_OBJECT *MaxOp, + ACPI_PARSE_OBJECT *LengthOp, + ACPI_PARSE_OBJECT *AlignOp, + ACPI_PARSE_OBJECT *Op) +{ + + if (Gbl_NoResourceChecking) + { + return; + } + + /* + * Check for a so-called "null descriptor". These are descriptors that are + * created with most fields set to zero. The intent is that the descriptor + * will be updated/completed at runtime via a BufferField. + * + * If the descriptor does NOT have a resource tag, it cannot be referenced + * by a BufferField and we will flag this as an error. Conversely, if + * the descriptor has a resource tag, we will assume that a BufferField + * will be used to dynamically update it, so no error. + * + * A possible enhancement to this check would be to verify that in fact + * a BufferField is created using the resource tag, and perhaps even + * verify that a Store is performed to the BufferField. + * + * Note: for these descriptors, Alignment is allowed to be zero + */ + if (!Minimum && !Maximum && !Length) + { + if (!Op->Asl.ExternalName) + { + /* No resource tag. Descriptor is fixed and is also illegal */ + + AslError (ASL_ERROR, ASL_MSG_NULL_DESCRIPTOR, Op, NULL); + } + + return; + } + + /* + * Range checks for Memory24 and Memory32. + * IO descriptor has different definition of min/max, don't check. + */ + if (Type != ACPI_RESOURCE_NAME_IO) + { + /* Basic checks on Min/Max/Length */ + + if (Minimum > Maximum) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_MIN_MAX, MinOp, NULL); + } + else if (Length > (Maximum - Minimum + 1)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_LENGTH, LengthOp, NULL); + } + + /* Special case for Memory24, min/max values are compressed */ + + if (Type == ACPI_RESOURCE_NAME_MEMORY24) + { + if (!Alignment) /* Alignment==0 means 64K alignment */ + { + Alignment = ACPI_UINT16_MAX + 1; + } + + Minimum <<= 8; + Maximum <<= 8; + } + } + + /* Alignment of zero is not in ACPI spec, but is used to mean byte acc */ + + if (!Alignment) + { + Alignment = 1; + } + + /* Addresses must be an exact multiple of the alignment value */ + + if (Minimum % Alignment) + { + AslError (ASL_ERROR, ASL_MSG_ALIGNMENT, MinOp, NULL); + } + if (Maximum % Alignment) + { + AslError (ASL_ERROR, ASL_MSG_ALIGNMENT, MaxOp, NULL); + } +} + + +/******************************************************************************* + * + * FUNCTION: RsLargeAddressCheck + * + * PARAMETERS: Minimum - Address Min value + * Maximum - Address Max value + * Length - Address range value + * Granularity - Address granularity value + * Flags - General flags for address descriptors: + * _MIF, _MAF, _DEC + * MinOp - Original Op for Address Min + * MaxOp - Original Op for Address Max + * LengthOp - Original Op for address range + * GranOp - Original Op for address granularity + * Op - Parent Op for entire construct + * + * RETURN: None. Adds error messages to error log if necessary + * + * DESCRIPTION: Perform common value checks for "large" address descriptors. + * Currently: + * WordIo, WordBusNumber, WordSpace + * DWordIo, DWordMemory, DWordSpace + * QWordIo, QWordMemory, QWordSpace + * ExtendedIo, ExtendedMemory, ExtendedSpace + * + * _MIF flag set means that the minimum address is fixed and is not relocatable + * _MAF flag set means that the maximum address is fixed and is not relocatable + * Length of zero means that the record size is variable + * + * This function implements the LEN/MIF/MAF/MIN/MAX/GRA rules within Table 6-40 + * of the ACPI 4.0a specification. Added 04/2010. + * + ******************************************************************************/ + +void +RsLargeAddressCheck ( + UINT64 Minimum, + UINT64 Maximum, + UINT64 Length, + UINT64 Granularity, + UINT8 Flags, + ACPI_PARSE_OBJECT *MinOp, + ACPI_PARSE_OBJECT *MaxOp, + ACPI_PARSE_OBJECT *LengthOp, + ACPI_PARSE_OBJECT *GranOp, + ACPI_PARSE_OBJECT *Op) +{ + + if (Gbl_NoResourceChecking) + { + return; + } + + /* + * Check for a so-called "null descriptor". These are descriptors that are + * created with most fields set to zero. The intent is that the descriptor + * will be updated/completed at runtime via a BufferField. + * + * If the descriptor does NOT have a resource tag, it cannot be referenced + * by a BufferField and we will flag this as an error. Conversely, if + * the descriptor has a resource tag, we will assume that a BufferField + * will be used to dynamically update it, so no error. + * + * A possible enhancement to this check would be to verify that in fact + * a BufferField is created using the resource tag, and perhaps even + * verify that a Store is performed to the BufferField. + */ + if (!Minimum && !Maximum && !Length && !Granularity) + { + if (!Op->Asl.ExternalName) + { + /* No resource tag. Descriptor is fixed and is also illegal */ + + AslError (ASL_ERROR, ASL_MSG_NULL_DESCRIPTOR, Op, NULL); + } + + return; + } + + /* Basic checks on Min/Max/Length */ + + if (Minimum > Maximum) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_MIN_MAX, MinOp, NULL); + return; + } + else if (Length > (Maximum - Minimum + 1)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_LENGTH, LengthOp, NULL); + return; + } + + /* If specified (non-zero), ensure granularity is a power-of-two minus one */ + + if (Granularity) + { + if ((Granularity + 1) & + Granularity) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_GRANULARITY, GranOp, NULL); + return; + } + } + + /* + * Check the various combinations of Length, MinFixed, and MaxFixed + */ + if (Length) + { + /* Fixed non-zero length */ + + switch (Flags & (ACPI_RESOURCE_FLAG_MIF | ACPI_RESOURCE_FLAG_MAF)) + { + case 0: + /* + * Fixed length, variable locations (both _MIN and _MAX). + * Length must be a multiple of granularity + */ + if (Granularity & Length) + { + AslError (ASL_ERROR, ASL_MSG_ALIGNMENT, LengthOp, NULL); + } + break; + + case (ACPI_RESOURCE_FLAG_MIF | ACPI_RESOURCE_FLAG_MAF): + + /* Fixed length, fixed location. Granularity must be zero */ + + if (Granularity != 0) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_GRAN_FIXED, GranOp, NULL); + } + + /* Length must be exactly the size of the min/max window */ + + if (Length != (Maximum - Minimum + 1)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_LENGTH_FIXED, LengthOp, NULL); + } + break; + + /* All other combinations are invalid */ + + case ACPI_RESOURCE_FLAG_MIF: + case ACPI_RESOURCE_FLAG_MAF: + default: + + AslError (ASL_ERROR, ASL_MSG_INVALID_ADDR_FLAGS, LengthOp, NULL); + } + } + else + { + /* Variable length (length==0) */ + + switch (Flags & (ACPI_RESOURCE_FLAG_MIF | ACPI_RESOURCE_FLAG_MAF)) + { + case 0: + /* + * Both _MIN and _MAX are variable. + * No additional requirements, just exit + */ + break; + + case ACPI_RESOURCE_FLAG_MIF: + + /* _MIN is fixed. _MIN must be multiple of _GRA */ + + /* + * The granularity is defined by the ACPI specification to be a + * power-of-two minus one, therefore the granularity is a + * bitmask which can be used to easily validate the addresses. + */ + if (Granularity & Minimum) + { + AslError (ASL_ERROR, ASL_MSG_ALIGNMENT, MinOp, NULL); + } + break; + + case ACPI_RESOURCE_FLAG_MAF: + + /* _MAX is fixed. (_MAX + 1) must be multiple of _GRA */ + + if (Granularity & (Maximum + 1)) + { + AslError (ASL_ERROR, ASL_MSG_ALIGNMENT, MaxOp, "-1"); + } + break; + + /* Both MIF/MAF set is invalid if length is zero */ + + case (ACPI_RESOURCE_FLAG_MIF | ACPI_RESOURCE_FLAG_MAF): + default: + + AslError (ASL_ERROR, ASL_MSG_INVALID_ADDR_FLAGS, LengthOp, NULL); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: RsGetStringDataLength + * + * PARAMETERS: InitializerOp - Start of a subtree of init nodes + * + * RETURN: Valid string length if a string node is found (otherwise 0) + * + * DESCRIPTION: In a list of peer nodes, find the first one that contains a + * string and return the length of the string. + * + ******************************************************************************/ + +UINT16 +RsGetStringDataLength ( + ACPI_PARSE_OBJECT *InitializerOp) +{ + + while (InitializerOp) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) + { + return ((UINT16) (strlen (InitializerOp->Asl.Value.String) + 1)); + } + + InitializerOp = ASL_GET_PEER_NODE (InitializerOp); + } + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: RsAllocateResourceNode + * + * PARAMETERS: Size - Size of node in bytes + * + * RETURN: The allocated node - aborts on allocation failure + * + * DESCRIPTION: Allocate a resource description node and the resource + * descriptor itself (the nodes are used to link descriptors). + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsAllocateResourceNode ( + UINT32 Size) +{ + ASL_RESOURCE_NODE *Rnode; + + + /* Allocate the node */ + + Rnode = UtLocalCalloc (sizeof (ASL_RESOURCE_NODE)); + + /* Allocate the resource descriptor itself */ + + Rnode->Buffer = UtLocalCalloc (Size); + Rnode->BufferLength = Size; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsCreateResourceField + * + * PARAMETERS: Op - Resource field node + * Name - Name of the field (Used only to reference + * the field in the ASL, not in the AML) + * ByteOffset - Offset from the field start + * BitOffset - Additional bit offset + * BitLength - Number of bits in the field + * + * RETURN: None, sets fields within the input node + * + * DESCRIPTION: Utility function to generate a named bit field within a + * resource descriptor. Mark a node as 1) a field in a resource + * descriptor, and 2) set the value to be a BIT offset + * + ******************************************************************************/ + +void +RsCreateResourceField ( + ACPI_PARSE_OBJECT *Op, + char *Name, + UINT32 ByteOffset, + UINT32 BitOffset, + UINT32 BitLength) +{ + + Op->Asl.ExternalName = Name; + Op->Asl.CompileFlags |= NODE_IS_RESOURCE_FIELD; + + Op->Asl.Value.Tag.BitOffset = (ByteOffset * 8) + BitOffset; + Op->Asl.Value.Tag.BitLength = BitLength; +} + + +/******************************************************************************* + * + * FUNCTION: RsSetFlagBits + * + * PARAMETERS: *Flags - Pointer to the flag byte + * Op - Flag initialization node + * Position - Bit position within the flag byte + * Default - Used if the node is DEFAULT. + * + * RETURN: Sets bits within the *Flags output byte. + * + * DESCRIPTION: Set a bit in a cumulative flags word from an initialization + * node. Will use a default value if the node is DEFAULT, meaning + * that no value was specified in the ASL. Used to merge multiple + * keywords into a single flags byte. + * + ******************************************************************************/ + +void +RsSetFlagBits ( + UINT8 *Flags, + ACPI_PARSE_OBJECT *Op, + UINT8 Position, + UINT8 DefaultBit) +{ + + if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + /* Use the default bit */ + + *Flags |= (DefaultBit << Position); + } + else + { + /* Use the bit specified in the initialization node */ + + *Flags |= (((UINT8) Op->Asl.Value.Integer) << Position); + } +} + + +void +RsSetFlagBits16 ( + UINT16 *Flags, + ACPI_PARSE_OBJECT *Op, + UINT8 Position, + UINT8 DefaultBit) +{ + + if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + /* Use the default bit */ + + *Flags |= (DefaultBit << Position); + } + else + { + /* Use the bit specified in the initialization node */ + + *Flags |= (((UINT16) Op->Asl.Value.Integer) << Position); + } +} + + +/******************************************************************************* + * + * FUNCTION: RsCompleteNodeAndGetNext + * + * PARAMETERS: Op - Resource node to be completed + * + * RETURN: The next peer to the input node. + * + * DESCRIPTION: Mark the current node completed and return the next peer. + * The node ParseOpcode is set to DEFAULT_ARG, meaning that + * this node is to be ignored from now on. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +RsCompleteNodeAndGetNext ( + ACPI_PARSE_OBJECT *Op) +{ + + /* Mark this node unused */ + + Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + + /* Move on to the next peer node in the initializer list */ + + return (ASL_GET_PEER_NODE (Op)); +} + + +/******************************************************************************* + * + * FUNCTION: RsCheckListForDuplicates + * + * PARAMETERS: Op - First op in the initializer list + * + * RETURN: None + * + * DESCRIPTION: Check an initializer list for duplicate values. Emits an error + * if any duplicates are found. + * + ******************************************************************************/ + +void +RsCheckListForDuplicates ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextValueOp = Op; + ACPI_PARSE_OBJECT *NextOp; + UINT32 Value; + + + if (!Op) + { + return; + } + + /* Search list once for each value in the list */ + + while (NextValueOp) + { + Value = (UINT32) NextValueOp->Asl.Value.Integer; + + /* Compare this value to all remaining values in the list */ + + NextOp = ASL_GET_PEER_NODE (NextValueOp); + while (NextOp) + { + if (NextOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* Compare values */ + + if (Value == (UINT32) NextOp->Asl.Value.Integer) + { + /* Emit error only once per duplicate node */ + + if (!(NextOp->Asl.CompileFlags & NODE_IS_DUPLICATE)) + { + NextOp->Asl.CompileFlags |= NODE_IS_DUPLICATE; + AslError (ASL_ERROR, ASL_MSG_DUPLICATE_ITEM, + NextOp, NULL); + } + } + } + + NextOp = ASL_GET_PEER_NODE (NextOp); + } + + NextValueOp = ASL_GET_PEER_NODE (NextValueOp); + } +} + + +/******************************************************************************* + * + * FUNCTION: RsDoOneResourceDescriptor + * + * PARAMETERS: DescriptorTypeOp - Parent parse node of the descriptor + * CurrentByteOffset - Offset in the resource descriptor + * buffer. + * + * RETURN: A valid resource node for the descriptor + * + * DESCRIPTION: Dispatches the processing of one resource descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoOneResourceDescriptor ( + ASL_RESOURCE_INFO *Info, + UINT8 *State) +{ + ASL_RESOURCE_NODE *Rnode = NULL; + + + /* Construct the resource */ + + switch (Info->DescriptorTypeOp->Asl.ParseOpcode) + { + case PARSEOP_DMA: + + Rnode = RsDoDmaDescriptor (Info); + break; + + case PARSEOP_FIXEDDMA: + + Rnode = RsDoFixedDmaDescriptor (Info); + break; + + case PARSEOP_DWORDIO: + + Rnode = RsDoDwordIoDescriptor (Info); + break; + + case PARSEOP_DWORDMEMORY: + + Rnode = RsDoDwordMemoryDescriptor (Info); + break; + + case PARSEOP_DWORDSPACE: + + Rnode = RsDoDwordSpaceDescriptor (Info); + break; + + case PARSEOP_ENDDEPENDENTFN: + + switch (*State) + { + case ACPI_RSTATE_NORMAL: + + AslError (ASL_ERROR, ASL_MSG_MISSING_STARTDEPENDENT, + Info->DescriptorTypeOp, NULL); + break; + + case ACPI_RSTATE_START_DEPENDENT: + + AslError (ASL_ERROR, ASL_MSG_DEPENDENT_NESTING, + Info->DescriptorTypeOp, NULL); + break; + + case ACPI_RSTATE_DEPENDENT_LIST: + default: + + break; + } + + *State = ACPI_RSTATE_NORMAL; + Rnode = RsDoEndDependentDescriptor (Info); + break; + + case PARSEOP_ENDTAG: + + Rnode = RsDoEndTagDescriptor (Info); + break; + + case PARSEOP_EXTENDEDIO: + + Rnode = RsDoExtendedIoDescriptor (Info); + break; + + case PARSEOP_EXTENDEDMEMORY: + + Rnode = RsDoExtendedMemoryDescriptor (Info); + break; + + case PARSEOP_EXTENDEDSPACE: + + Rnode = RsDoExtendedSpaceDescriptor (Info); + break; + + case PARSEOP_FIXEDIO: + + Rnode = RsDoFixedIoDescriptor (Info); + break; + + case PARSEOP_INTERRUPT: + + Rnode = RsDoInterruptDescriptor (Info); + break; + + case PARSEOP_IO: + + Rnode = RsDoIoDescriptor (Info); + break; + + case PARSEOP_IRQ: + + Rnode = RsDoIrqDescriptor (Info); + break; + + case PARSEOP_IRQNOFLAGS: + + Rnode = RsDoIrqNoFlagsDescriptor (Info); + break; + + case PARSEOP_MEMORY24: + + Rnode = RsDoMemory24Descriptor (Info); + break; + + case PARSEOP_MEMORY32: + + Rnode = RsDoMemory32Descriptor (Info); + break; + + case PARSEOP_MEMORY32FIXED: + + Rnode = RsDoMemory32FixedDescriptor (Info); + break; + + case PARSEOP_QWORDIO: + + Rnode = RsDoQwordIoDescriptor (Info); + break; + + case PARSEOP_QWORDMEMORY: + + Rnode = RsDoQwordMemoryDescriptor (Info); + break; + + case PARSEOP_QWORDSPACE: + + Rnode = RsDoQwordSpaceDescriptor (Info); + break; + + case PARSEOP_REGISTER: + + Rnode = RsDoGeneralRegisterDescriptor (Info); + break; + + case PARSEOP_STARTDEPENDENTFN: + + switch (*State) + { + case ACPI_RSTATE_START_DEPENDENT: + + AslError (ASL_ERROR, ASL_MSG_DEPENDENT_NESTING, + Info->DescriptorTypeOp, NULL); + break; + + case ACPI_RSTATE_NORMAL: + case ACPI_RSTATE_DEPENDENT_LIST: + default: + + break; + } + + *State = ACPI_RSTATE_START_DEPENDENT; + Rnode = RsDoStartDependentDescriptor (Info); + *State = ACPI_RSTATE_DEPENDENT_LIST; + break; + + case PARSEOP_STARTDEPENDENTFN_NOPRI: + + switch (*State) + { + case ACPI_RSTATE_START_DEPENDENT: + + AslError (ASL_ERROR, ASL_MSG_DEPENDENT_NESTING, + Info->DescriptorTypeOp, NULL); + break; + + case ACPI_RSTATE_NORMAL: + case ACPI_RSTATE_DEPENDENT_LIST: + default: + + break; + } + + *State = ACPI_RSTATE_START_DEPENDENT; + Rnode = RsDoStartDependentNoPriDescriptor (Info); + *State = ACPI_RSTATE_DEPENDENT_LIST; + break; + + case PARSEOP_VENDORLONG: + + Rnode = RsDoVendorLargeDescriptor (Info); + break; + + case PARSEOP_VENDORSHORT: + + Rnode = RsDoVendorSmallDescriptor (Info); + break; + + case PARSEOP_WORDBUSNUMBER: + + Rnode = RsDoWordBusNumberDescriptor (Info); + break; + + case PARSEOP_WORDIO: + + Rnode = RsDoWordIoDescriptor (Info); + break; + + case PARSEOP_WORDSPACE: + + Rnode = RsDoWordSpaceDescriptor (Info); + break; + + case PARSEOP_GPIO_INT: + + Rnode = RsDoGpioIntDescriptor (Info); + break; + + case PARSEOP_GPIO_IO: + + Rnode = RsDoGpioIoDescriptor (Info); + break; + + case PARSEOP_I2C_SERIALBUS: + + Rnode = RsDoI2cSerialBusDescriptor (Info); + break; + + case PARSEOP_SPI_SERIALBUS: + + Rnode = RsDoSpiSerialBusDescriptor (Info); + break; + + case PARSEOP_UART_SERIALBUS: + + Rnode = RsDoUartSerialBusDescriptor (Info); + break; + + case PARSEOP_DEFAULT_ARG: + + /* Just ignore any of these, they are used as fillers/placeholders */ + break; + + default: + + printf ("Unknown resource descriptor type [%s]\n", + Info->DescriptorTypeOp->Asl.ParseOpName); + break; + } + + /* + * Mark original node as unused, but head of a resource descriptor. + * This allows the resource to be installed in the namespace so that + * references to the descriptor can be resolved. + */ + Info->DescriptorTypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + Info->DescriptorTypeOp->Asl.CompileFlags = NODE_IS_RESOURCE_DESC; + Info->DescriptorTypeOp->Asl.Value.Integer = Info->CurrentByteOffset; + + if (Rnode) + { + Info->DescriptorTypeOp->Asl.FinalAmlLength = Rnode->BufferLength; + Info->DescriptorTypeOp->Asl.Extra = + ((AML_RESOURCE *) Rnode->Buffer)->DescriptorType; + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsLinkDescriptorChain + * + * PARAMETERS: PreviousRnode - Pointer to the node that will be previous + * to the linked node, At exit, set to the + * last node in the new chain. + * Rnode - Resource node to link into the list + * + * RETURN: Cumulative buffer byte offset of the new segment of chain + * + * DESCRIPTION: Link a descriptor chain at the end of an existing chain. + * + ******************************************************************************/ + +UINT32 +RsLinkDescriptorChain ( + ASL_RESOURCE_NODE **PreviousRnode, + ASL_RESOURCE_NODE *Rnode) +{ + ASL_RESOURCE_NODE *LastRnode; + UINT32 CurrentByteOffset; + + + /* Anything to do? */ + + if (!Rnode) + { + return (0); + } + + /* Point the previous node to the new node */ + + (*PreviousRnode)->Next = Rnode; + CurrentByteOffset = Rnode->BufferLength; + + /* Walk to the end of the chain headed by Rnode */ + + LastRnode = Rnode; + while (LastRnode->Next) + { + LastRnode = LastRnode->Next; + CurrentByteOffset += LastRnode->BufferLength; + } + + /* Previous node becomes the last node in the chain */ + + *PreviousRnode = LastRnode; + return (CurrentByteOffset); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoResourceTemplate + * + * PARAMETERS: Op - Parent of a resource template list + * + * RETURN: None. Sets input node to point to a list of AML code + * + * DESCRIPTION: Merge a list of resource descriptors into a single AML buffer, + * in preparation for output to the AML output file. + * + ******************************************************************************/ + +void +RsDoResourceTemplate ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *BufferLengthOp; + ACPI_PARSE_OBJECT *BufferOp; + ACPI_PARSE_OBJECT *DescriptorTypeOp; + ACPI_PARSE_OBJECT *LastOp = NULL; + UINT32 CurrentByteOffset = 0; + ASL_RESOURCE_NODE HeadRnode; + ASL_RESOURCE_NODE *PreviousRnode; + ASL_RESOURCE_NODE *Rnode; + ASL_RESOURCE_INFO Info; + UINT8 State; + + + /* Mark parent as containing a resource template */ + + if (Op->Asl.Parent) + { + Op->Asl.Parent->Asl.CompileFlags |= NODE_IS_RESOURCE_DESC; + } + + /* ResourceTemplate Opcode is first (Op) */ + /* Buffer Length node is first child */ + + BufferLengthOp = ASL_GET_CHILD_NODE (Op); + + /* Buffer Op is first peer */ + + BufferOp = ASL_GET_PEER_NODE (BufferLengthOp); + + /* First Descriptor type is next */ + + DescriptorTypeOp = ASL_GET_PEER_NODE (BufferOp); + + /* + * Process all resource descriptors in the list + * Note: It is assumed that the EndTag node has been automatically + * inserted at the end of the template by the parser. + */ + State = ACPI_RSTATE_NORMAL; + PreviousRnode = &HeadRnode; + while (DescriptorTypeOp) + { + /* Save information for optional mapfile */ + + if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONNECTION) + { + Info.MappingOp = Op->Asl.Parent; + } + else + { + Info.MappingOp = DescriptorTypeOp; + } + + Info.DescriptorTypeOp = DescriptorTypeOp; + Info.CurrentByteOffset = CurrentByteOffset; + + DescriptorTypeOp->Asl.CompileFlags |= NODE_IS_RESOURCE_DESC; + Rnode = RsDoOneResourceDescriptor (&Info, &State); + + /* + * Update current byte offset to indicate the number of bytes from the + * start of the buffer. Buffer can include multiple descriptors, we + * must keep track of the offset of not only each descriptor, but each + * element (field) within each descriptor as well. + */ + CurrentByteOffset += RsLinkDescriptorChain (&PreviousRnode, Rnode); + + /* Get the next descriptor in the list */ + + LastOp = DescriptorTypeOp; + DescriptorTypeOp = ASL_GET_PEER_NODE (DescriptorTypeOp); + } + + if (State == ACPI_RSTATE_DEPENDENT_LIST) + { + if (LastOp) + { + LastOp = LastOp->Asl.Parent; + } + AslError (ASL_ERROR, ASL_MSG_MISSING_ENDDEPENDENT, LastOp, NULL); + } + + /* + * Transform the nodes into the following + * + * Op -> AML_BUFFER_OP + * First Child -> BufferLength + * Second Child -> Descriptor Buffer (raw byte data) + */ + Op->Asl.ParseOpcode = PARSEOP_BUFFER; + Op->Asl.AmlOpcode = AML_BUFFER_OP; + Op->Asl.CompileFlags = NODE_AML_PACKAGE | NODE_IS_RESOURCE_DESC; + UtSetParseOpName (Op); + + BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER; + BufferLengthOp->Asl.Value.Integer = CurrentByteOffset; + (void) OpcSetOptimalIntegerSize (BufferLengthOp); + UtSetParseOpName (BufferLengthOp); + + BufferOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; + BufferOp->Asl.AmlOpcode = AML_RAW_DATA_CHAIN; + BufferOp->Asl.AmlOpcodeLength = 0; + BufferOp->Asl.AmlLength = CurrentByteOffset; + BufferOp->Asl.Value.Buffer = (UINT8 *) HeadRnode.Next; + BufferOp->Asl.CompileFlags |= NODE_IS_RESOURCE_DATA; + UtSetParseOpName (BufferOp); + + return; +} diff --git a/third_party/lib/acpica/source/compiler/aslresources.y b/third_party/lib/acpica/source/compiler/aslresources.y new file mode 100644 index 000000000..fcde7e559 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslresources.y @@ -0,0 +1,1179 @@ +NoEcho(' +/****************************************************************************** + * + * Module Name: aslresources.y - Bison/Yacc production rules for resources + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +') + +/******************************************************************************* + * + * ASL Parameter Keyword Terms + * + ******************************************************************************/ + +AccessAttribKeyword + : PARSEOP_ACCESSATTRIB_BLOCK {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_BLOCK);} + | PARSEOP_ACCESSATTRIB_BLOCK_CALL {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_BLOCK_CALL);} + | PARSEOP_ACCESSATTRIB_BYTE {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_BYTE);} + | PARSEOP_ACCESSATTRIB_QUICK {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_QUICK );} + | PARSEOP_ACCESSATTRIB_SND_RCV {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_SND_RCV);} + | PARSEOP_ACCESSATTRIB_WORD {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_WORD);} + | PARSEOP_ACCESSATTRIB_WORD_CALL {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_WORD_CALL);} + | PARSEOP_ACCESSATTRIB_MULTIBYTE '(' {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_MULTIBYTE);} + ByteConst + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_ACCESSATTRIB_RAW_BYTES '(' {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_RAW_BYTES);} + ByteConst + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_ACCESSATTRIB_RAW_PROCESS '(' {$$ = TrCreateLeafNode (PARSEOP_ACCESSATTRIB_RAW_PROCESS);} + ByteConst + ')' {$$ = TrLinkChildren ($3,1,$4);} + ; + +AccessTypeKeyword + : PARSEOP_ACCESSTYPE_ANY {$$ = TrCreateLeafNode (PARSEOP_ACCESSTYPE_ANY);} + | PARSEOP_ACCESSTYPE_BYTE {$$ = TrCreateLeafNode (PARSEOP_ACCESSTYPE_BYTE);} + | PARSEOP_ACCESSTYPE_WORD {$$ = TrCreateLeafNode (PARSEOP_ACCESSTYPE_WORD);} + | PARSEOP_ACCESSTYPE_DWORD {$$ = TrCreateLeafNode (PARSEOP_ACCESSTYPE_DWORD);} + | PARSEOP_ACCESSTYPE_QWORD {$$ = TrCreateLeafNode (PARSEOP_ACCESSTYPE_QWORD);} + | PARSEOP_ACCESSTYPE_BUF {$$ = TrCreateLeafNode (PARSEOP_ACCESSTYPE_BUF);} + ; + +AddressingModeKeyword + : PARSEOP_ADDRESSINGMODE_7BIT {$$ = TrCreateLeafNode (PARSEOP_ADDRESSINGMODE_7BIT);} + | PARSEOP_ADDRESSINGMODE_10BIT {$$ = TrCreateLeafNode (PARSEOP_ADDRESSINGMODE_10BIT);} + ; + +AddressKeyword + : PARSEOP_ADDRESSTYPE_MEMORY {$$ = TrCreateLeafNode (PARSEOP_ADDRESSTYPE_MEMORY);} + | PARSEOP_ADDRESSTYPE_RESERVED {$$ = TrCreateLeafNode (PARSEOP_ADDRESSTYPE_RESERVED);} + | PARSEOP_ADDRESSTYPE_NVS {$$ = TrCreateLeafNode (PARSEOP_ADDRESSTYPE_NVS);} + | PARSEOP_ADDRESSTYPE_ACPI {$$ = TrCreateLeafNode (PARSEOP_ADDRESSTYPE_ACPI);} + ; + +AddressSpaceKeyword + : ByteConst {$$ = UtCheckIntegerRange ($1, 0x0A, 0xFF);} + | RegionSpaceKeyword {} + ; + +BitsPerByteKeyword + : PARSEOP_BITSPERBYTE_FIVE {$$ = TrCreateLeafNode (PARSEOP_BITSPERBYTE_FIVE);} + | PARSEOP_BITSPERBYTE_SIX {$$ = TrCreateLeafNode (PARSEOP_BITSPERBYTE_SIX);} + | PARSEOP_BITSPERBYTE_SEVEN {$$ = TrCreateLeafNode (PARSEOP_BITSPERBYTE_SEVEN);} + | PARSEOP_BITSPERBYTE_EIGHT {$$ = TrCreateLeafNode (PARSEOP_BITSPERBYTE_EIGHT);} + | PARSEOP_BITSPERBYTE_NINE {$$ = TrCreateLeafNode (PARSEOP_BITSPERBYTE_NINE);} + ; + +ClockPhaseKeyword + : PARSEOP_CLOCKPHASE_FIRST {$$ = TrCreateLeafNode (PARSEOP_CLOCKPHASE_FIRST);} + | PARSEOP_CLOCKPHASE_SECOND {$$ = TrCreateLeafNode (PARSEOP_CLOCKPHASE_SECOND);} + ; + +ClockPolarityKeyword + : PARSEOP_CLOCKPOLARITY_LOW {$$ = TrCreateLeafNode (PARSEOP_CLOCKPOLARITY_LOW);} + | PARSEOP_CLOCKPOLARITY_HIGH {$$ = TrCreateLeafNode (PARSEOP_CLOCKPOLARITY_HIGH);} + ; + +DecodeKeyword + : PARSEOP_DECODETYPE_POS {$$ = TrCreateLeafNode (PARSEOP_DECODETYPE_POS);} + | PARSEOP_DECODETYPE_SUB {$$ = TrCreateLeafNode (PARSEOP_DECODETYPE_SUB);} + ; + +DevicePolarityKeyword + : PARSEOP_DEVICEPOLARITY_LOW {$$ = TrCreateLeafNode (PARSEOP_DEVICEPOLARITY_LOW);} + | PARSEOP_DEVICEPOLARITY_HIGH {$$ = TrCreateLeafNode (PARSEOP_DEVICEPOLARITY_HIGH);} + ; + +DMATypeKeyword + : PARSEOP_DMATYPE_A {$$ = TrCreateLeafNode (PARSEOP_DMATYPE_A);} + | PARSEOP_DMATYPE_COMPATIBILITY {$$ = TrCreateLeafNode (PARSEOP_DMATYPE_COMPATIBILITY);} + | PARSEOP_DMATYPE_B {$$ = TrCreateLeafNode (PARSEOP_DMATYPE_B);} + | PARSEOP_DMATYPE_F {$$ = TrCreateLeafNode (PARSEOP_DMATYPE_F);} + ; + +EndianKeyword + : PARSEOP_ENDIAN_LITTLE {$$ = TrCreateLeafNode (PARSEOP_ENDIAN_LITTLE);} + | PARSEOP_ENDIAN_BIG {$$ = TrCreateLeafNode (PARSEOP_ENDIAN_BIG);} + ; + +FlowControlKeyword + : PARSEOP_FLOWCONTROL_HW {$$ = TrCreateLeafNode (PARSEOP_FLOWCONTROL_HW);} + | PARSEOP_FLOWCONTROL_NONE {$$ = TrCreateLeafNode (PARSEOP_FLOWCONTROL_NONE);} + | PARSEOP_FLOWCONTROL_SW {$$ = TrCreateLeafNode (PARSEOP_FLOWCONTROL_SW);} + ; + +InterruptLevel + : PARSEOP_INTLEVEL_ACTIVEBOTH {$$ = TrCreateLeafNode (PARSEOP_INTLEVEL_ACTIVEBOTH);} + | PARSEOP_INTLEVEL_ACTIVEHIGH {$$ = TrCreateLeafNode (PARSEOP_INTLEVEL_ACTIVEHIGH);} + | PARSEOP_INTLEVEL_ACTIVELOW {$$ = TrCreateLeafNode (PARSEOP_INTLEVEL_ACTIVELOW);} + ; + +InterruptTypeKeyword + : PARSEOP_INTTYPE_EDGE {$$ = TrCreateLeafNode (PARSEOP_INTTYPE_EDGE);} + | PARSEOP_INTTYPE_LEVEL {$$ = TrCreateLeafNode (PARSEOP_INTTYPE_LEVEL);} + ; + +IODecodeKeyword + : PARSEOP_IODECODETYPE_16 {$$ = TrCreateLeafNode (PARSEOP_IODECODETYPE_16);} + | PARSEOP_IODECODETYPE_10 {$$ = TrCreateLeafNode (PARSEOP_IODECODETYPE_10);} + ; + +IoRestrictionKeyword + : PARSEOP_IORESTRICT_IN {$$ = TrCreateLeafNode (PARSEOP_IORESTRICT_IN);} + | PARSEOP_IORESTRICT_OUT {$$ = TrCreateLeafNode (PARSEOP_IORESTRICT_OUT);} + | PARSEOP_IORESTRICT_NONE {$$ = TrCreateLeafNode (PARSEOP_IORESTRICT_NONE);} + | PARSEOP_IORESTRICT_PRESERVE {$$ = TrCreateLeafNode (PARSEOP_IORESTRICT_PRESERVE);} + ; + +LockRuleKeyword + : PARSEOP_LOCKRULE_LOCK {$$ = TrCreateLeafNode (PARSEOP_LOCKRULE_LOCK);} + | PARSEOP_LOCKRULE_NOLOCK {$$ = TrCreateLeafNode (PARSEOP_LOCKRULE_NOLOCK);} + ; + +MatchOpKeyword + : PARSEOP_MATCHTYPE_MTR {$$ = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR);} + | PARSEOP_MATCHTYPE_MEQ {$$ = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ);} + | PARSEOP_MATCHTYPE_MLE {$$ = TrCreateLeafNode (PARSEOP_MATCHTYPE_MLE);} + | PARSEOP_MATCHTYPE_MLT {$$ = TrCreateLeafNode (PARSEOP_MATCHTYPE_MLT);} + | PARSEOP_MATCHTYPE_MGE {$$ = TrCreateLeafNode (PARSEOP_MATCHTYPE_MGE);} + | PARSEOP_MATCHTYPE_MGT {$$ = TrCreateLeafNode (PARSEOP_MATCHTYPE_MGT);} + ; + +MaxKeyword + : PARSEOP_MAXTYPE_FIXED {$$ = TrCreateLeafNode (PARSEOP_MAXTYPE_FIXED);} + | PARSEOP_MAXTYPE_NOTFIXED {$$ = TrCreateLeafNode (PARSEOP_MAXTYPE_NOTFIXED);} + ; + +MemTypeKeyword + : PARSEOP_MEMTYPE_CACHEABLE {$$ = TrCreateLeafNode (PARSEOP_MEMTYPE_CACHEABLE);} + | PARSEOP_MEMTYPE_WRITECOMBINING {$$ = TrCreateLeafNode (PARSEOP_MEMTYPE_WRITECOMBINING);} + | PARSEOP_MEMTYPE_PREFETCHABLE {$$ = TrCreateLeafNode (PARSEOP_MEMTYPE_PREFETCHABLE);} + | PARSEOP_MEMTYPE_NONCACHEABLE {$$ = TrCreateLeafNode (PARSEOP_MEMTYPE_NONCACHEABLE);} + ; + +MinKeyword + : PARSEOP_MINTYPE_FIXED {$$ = TrCreateLeafNode (PARSEOP_MINTYPE_FIXED);} + | PARSEOP_MINTYPE_NOTFIXED {$$ = TrCreateLeafNode (PARSEOP_MINTYPE_NOTFIXED);} + ; + +ObjectTypeKeyword + : PARSEOP_OBJECTTYPE_UNK {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_UNK);} + | PARSEOP_OBJECTTYPE_INT {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_INT);} + | PARSEOP_OBJECTTYPE_STR {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_STR);} + | PARSEOP_OBJECTTYPE_BUF {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_BUF);} + | PARSEOP_OBJECTTYPE_PKG {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_PKG);} + | PARSEOP_OBJECTTYPE_FLD {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_FLD);} + | PARSEOP_OBJECTTYPE_DEV {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_DEV);} + | PARSEOP_OBJECTTYPE_EVT {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_EVT);} + | PARSEOP_OBJECTTYPE_MTH {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_MTH);} + | PARSEOP_OBJECTTYPE_MTX {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_MTX);} + | PARSEOP_OBJECTTYPE_OPR {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_OPR);} + | PARSEOP_OBJECTTYPE_POW {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_POW);} + | PARSEOP_OBJECTTYPE_PRO {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_PRO);} + | PARSEOP_OBJECTTYPE_THZ {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_THZ);} + | PARSEOP_OBJECTTYPE_BFF {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_BFF);} + | PARSEOP_OBJECTTYPE_DDB {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_DDB);} + ; + +ParityTypeKeyword + : PARSEOP_PARITYTYPE_SPACE {$$ = TrCreateLeafNode (PARSEOP_PARITYTYPE_SPACE);} + | PARSEOP_PARITYTYPE_MARK {$$ = TrCreateLeafNode (PARSEOP_PARITYTYPE_MARK);} + | PARSEOP_PARITYTYPE_ODD {$$ = TrCreateLeafNode (PARSEOP_PARITYTYPE_ODD);} + | PARSEOP_PARITYTYPE_EVEN {$$ = TrCreateLeafNode (PARSEOP_PARITYTYPE_EVEN);} + | PARSEOP_PARITYTYPE_NONE {$$ = TrCreateLeafNode (PARSEOP_PARITYTYPE_NONE);} + ; + +PinConfigByte + : PinConfigKeyword {$$ = $1;} + | ByteConstExpr {$$ = UtCheckIntegerRange ($1, 0x80, 0xFF);} + ; + +PinConfigKeyword + : PARSEOP_PIN_NOPULL {$$ = TrCreateLeafNode (PARSEOP_PIN_NOPULL);} + | PARSEOP_PIN_PULLDOWN {$$ = TrCreateLeafNode (PARSEOP_PIN_PULLDOWN);} + | PARSEOP_PIN_PULLUP {$$ = TrCreateLeafNode (PARSEOP_PIN_PULLUP);} + | PARSEOP_PIN_PULLDEFAULT {$$ = TrCreateLeafNode (PARSEOP_PIN_PULLDEFAULT);} + ; + +PldKeyword + : PARSEOP_PLD_REVISION {$$ = TrCreateLeafNode (PARSEOP_PLD_REVISION);} + | PARSEOP_PLD_IGNORECOLOR {$$ = TrCreateLeafNode (PARSEOP_PLD_IGNORECOLOR);} + | PARSEOP_PLD_RED {$$ = TrCreateLeafNode (PARSEOP_PLD_RED);} + | PARSEOP_PLD_GREEN {$$ = TrCreateLeafNode (PARSEOP_PLD_GREEN);} + | PARSEOP_PLD_BLUE {$$ = TrCreateLeafNode (PARSEOP_PLD_BLUE);} + | PARSEOP_PLD_WIDTH {$$ = TrCreateLeafNode (PARSEOP_PLD_WIDTH);} + | PARSEOP_PLD_HEIGHT {$$ = TrCreateLeafNode (PARSEOP_PLD_HEIGHT);} + | PARSEOP_PLD_USERVISIBLE {$$ = TrCreateLeafNode (PARSEOP_PLD_USERVISIBLE);} + | PARSEOP_PLD_DOCK {$$ = TrCreateLeafNode (PARSEOP_PLD_DOCK);} + | PARSEOP_PLD_LID {$$ = TrCreateLeafNode (PARSEOP_PLD_LID);} + | PARSEOP_PLD_PANEL {$$ = TrCreateLeafNode (PARSEOP_PLD_PANEL);} + | PARSEOP_PLD_VERTICALPOSITION {$$ = TrCreateLeafNode (PARSEOP_PLD_VERTICALPOSITION);} + | PARSEOP_PLD_HORIZONTALPOSITION {$$ = TrCreateLeafNode (PARSEOP_PLD_HORIZONTALPOSITION);} + | PARSEOP_PLD_SHAPE {$$ = TrCreateLeafNode (PARSEOP_PLD_SHAPE);} + | PARSEOP_PLD_GROUPORIENTATION {$$ = TrCreateLeafNode (PARSEOP_PLD_GROUPORIENTATION);} + | PARSEOP_PLD_GROUPTOKEN {$$ = TrCreateLeafNode (PARSEOP_PLD_GROUPTOKEN);} + | PARSEOP_PLD_GROUPPOSITION {$$ = TrCreateLeafNode (PARSEOP_PLD_GROUPPOSITION);} + | PARSEOP_PLD_BAY {$$ = TrCreateLeafNode (PARSEOP_PLD_BAY);} + | PARSEOP_PLD_EJECTABLE {$$ = TrCreateLeafNode (PARSEOP_PLD_EJECTABLE);} + | PARSEOP_PLD_EJECTREQUIRED {$$ = TrCreateLeafNode (PARSEOP_PLD_EJECTREQUIRED);} + | PARSEOP_PLD_CABINETNUMBER {$$ = TrCreateLeafNode (PARSEOP_PLD_CABINETNUMBER);} + | PARSEOP_PLD_CARDCAGENUMBER {$$ = TrCreateLeafNode (PARSEOP_PLD_CARDCAGENUMBER);} + | PARSEOP_PLD_REFERENCE {$$ = TrCreateLeafNode (PARSEOP_PLD_REFERENCE);} + | PARSEOP_PLD_ROTATION {$$ = TrCreateLeafNode (PARSEOP_PLD_ROTATION);} + | PARSEOP_PLD_ORDER {$$ = TrCreateLeafNode (PARSEOP_PLD_ORDER);} + | PARSEOP_PLD_RESERVED {$$ = TrCreateLeafNode (PARSEOP_PLD_RESERVED);} + | PARSEOP_PLD_VERTICALOFFSET {$$ = TrCreateLeafNode (PARSEOP_PLD_VERTICALOFFSET);} + | PARSEOP_PLD_HORIZONTALOFFSET {$$ = TrCreateLeafNode (PARSEOP_PLD_HORIZONTALOFFSET);} + ; + +RangeTypeKeyword + : PARSEOP_RANGETYPE_ISAONLY {$$ = TrCreateLeafNode (PARSEOP_RANGETYPE_ISAONLY);} + | PARSEOP_RANGETYPE_NONISAONLY {$$ = TrCreateLeafNode (PARSEOP_RANGETYPE_NONISAONLY);} + | PARSEOP_RANGETYPE_ENTIRE {$$ = TrCreateLeafNode (PARSEOP_RANGETYPE_ENTIRE);} + ; + +RegionSpaceKeyword + : PARSEOP_REGIONSPACE_IO {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_IO);} + | PARSEOP_REGIONSPACE_MEM {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_MEM);} + | PARSEOP_REGIONSPACE_PCI {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_PCI);} + | PARSEOP_REGIONSPACE_EC {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_EC);} + | PARSEOP_REGIONSPACE_SMBUS {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_SMBUS);} + | PARSEOP_REGIONSPACE_CMOS {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_CMOS);} + | PARSEOP_REGIONSPACE_PCIBAR {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_PCIBAR);} + | PARSEOP_REGIONSPACE_IPMI {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_IPMI);} + | PARSEOP_REGIONSPACE_GPIO {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_GPIO);} + | PARSEOP_REGIONSPACE_GSBUS {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_GSBUS);} + | PARSEOP_REGIONSPACE_PCC {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_PCC);} + | PARSEOP_REGIONSPACE_FFIXEDHW {$$ = TrCreateLeafNode (PARSEOP_REGIONSPACE_FFIXEDHW);} + ; + +ResourceTypeKeyword + : PARSEOP_RESOURCETYPE_CONSUMER {$$ = TrCreateLeafNode (PARSEOP_RESOURCETYPE_CONSUMER);} + | PARSEOP_RESOURCETYPE_PRODUCER {$$ = TrCreateLeafNode (PARSEOP_RESOURCETYPE_PRODUCER);} + ; + +SerializeRuleKeyword + : PARSEOP_SERIALIZERULE_SERIAL {$$ = TrCreateLeafNode (PARSEOP_SERIALIZERULE_SERIAL);} + | PARSEOP_SERIALIZERULE_NOTSERIAL {$$ = TrCreateLeafNode (PARSEOP_SERIALIZERULE_NOTSERIAL);} + ; + +ShareTypeKeyword + : PARSEOP_SHARETYPE_SHARED {$$ = TrCreateLeafNode (PARSEOP_SHARETYPE_SHARED);} + | PARSEOP_SHARETYPE_EXCLUSIVE {$$ = TrCreateLeafNode (PARSEOP_SHARETYPE_EXCLUSIVE);} + | PARSEOP_SHARETYPE_SHAREDWAKE {$$ = TrCreateLeafNode (PARSEOP_SHARETYPE_SHAREDWAKE);} + | PARSEOP_SHARETYPE_EXCLUSIVEWAKE {$$ = TrCreateLeafNode (PARSEOP_SHARETYPE_EXCLUSIVEWAKE);} + ; + +SlaveModeKeyword + : PARSEOP_SLAVEMODE_CONTROLLERINIT {$$ = TrCreateLeafNode (PARSEOP_SLAVEMODE_CONTROLLERINIT);} + | PARSEOP_SLAVEMODE_DEVICEINIT {$$ = TrCreateLeafNode (PARSEOP_SLAVEMODE_DEVICEINIT);} + ; + +StopBitsKeyword + : PARSEOP_STOPBITS_TWO {$$ = TrCreateLeafNode (PARSEOP_STOPBITS_TWO);} + | PARSEOP_STOPBITS_ONEPLUSHALF {$$ = TrCreateLeafNode (PARSEOP_STOPBITS_ONEPLUSHALF);} + | PARSEOP_STOPBITS_ONE {$$ = TrCreateLeafNode (PARSEOP_STOPBITS_ONE);} + | PARSEOP_STOPBITS_ZERO {$$ = TrCreateLeafNode (PARSEOP_STOPBITS_ZERO);} + ; + +TranslationKeyword + : PARSEOP_TRANSLATIONTYPE_SPARSE {$$ = TrCreateLeafNode (PARSEOP_TRANSLATIONTYPE_SPARSE);} + | PARSEOP_TRANSLATIONTYPE_DENSE {$$ = TrCreateLeafNode (PARSEOP_TRANSLATIONTYPE_DENSE);} + ; + +TypeKeyword + : PARSEOP_TYPE_TRANSLATION {$$ = TrCreateLeafNode (PARSEOP_TYPE_TRANSLATION);} + | PARSEOP_TYPE_STATIC {$$ = TrCreateLeafNode (PARSEOP_TYPE_STATIC);} + ; + +UpdateRuleKeyword + : PARSEOP_UPDATERULE_PRESERVE {$$ = TrCreateLeafNode (PARSEOP_UPDATERULE_PRESERVE);} + | PARSEOP_UPDATERULE_ONES {$$ = TrCreateLeafNode (PARSEOP_UPDATERULE_ONES);} + | PARSEOP_UPDATERULE_ZEROS {$$ = TrCreateLeafNode (PARSEOP_UPDATERULE_ZEROS);} + ; + +WireModeKeyword + : PARSEOP_WIREMODE_FOUR {$$ = TrCreateLeafNode (PARSEOP_WIREMODE_FOUR);} + | PARSEOP_WIREMODE_THREE {$$ = TrCreateLeafNode (PARSEOP_WIREMODE_THREE);} + ; + +XferSizeKeyword + : PARSEOP_XFERSIZE_8 {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_8, 0);} + | PARSEOP_XFERSIZE_16 {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_16, 1);} + | PARSEOP_XFERSIZE_32 {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_32, 2);} + | PARSEOP_XFERSIZE_64 {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_64, 3);} + | PARSEOP_XFERSIZE_128 {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_128, 4);} + | PARSEOP_XFERSIZE_256 {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_256, 5);} + ; + +XferTypeKeyword + : PARSEOP_XFERTYPE_8 {$$ = TrCreateLeafNode (PARSEOP_XFERTYPE_8);} + | PARSEOP_XFERTYPE_8_16 {$$ = TrCreateLeafNode (PARSEOP_XFERTYPE_8_16);} + | PARSEOP_XFERTYPE_16 {$$ = TrCreateLeafNode (PARSEOP_XFERTYPE_16);} + ; + + +/******************************************************************************* + * + * ASL Resource Template Terms + * + ******************************************************************************/ + +/* + * Note: Create two default nodes to allow conversion to a Buffer AML opcode + * Also, insert the EndTag at the end of the template. + */ +ResourceTemplateTerm + : PARSEOP_RESOURCETEMPLATE '(' ')' + '{' + ResourceMacroList '}' {$$ = TrCreateNode (PARSEOP_RESOURCETEMPLATE,4, + TrCreateLeafNode (PARSEOP_DEFAULT_ARG), + TrCreateLeafNode (PARSEOP_DEFAULT_ARG), + $5, + TrCreateLeafNode (PARSEOP_ENDTAG));} + ; + +ResourceMacroList + : {$$ = NULL;} + | ResourceMacroList + ResourceMacroTerm {$$ = TrLinkPeerNode ($1,$2);} + ; + +ResourceMacroTerm + : DMATerm {} + | DWordIOTerm {} + | DWordMemoryTerm {} + | DWordSpaceTerm {} + | EndDependentFnTerm {} + | ExtendedIOTerm {} + | ExtendedMemoryTerm {} + | ExtendedSpaceTerm {} + | FixedDmaTerm {} + | FixedIOTerm {} + | GpioIntTerm {} + | GpioIoTerm {} + | I2cSerialBusTerm {} + | InterruptTerm {} + | IOTerm {} + | IRQNoFlagsTerm {} + | IRQTerm {} + | Memory24Term {} + | Memory32FixedTerm {} + | Memory32Term {} + | QWordIOTerm {} + | QWordMemoryTerm {} + | QWordSpaceTerm {} + | RegisterTerm {} + | SpiSerialBusTerm {} + | StartDependentFnNoPriTerm {} + | StartDependentFnTerm {} + | UartSerialBusTerm {} + | VendorLongTerm {} + | VendorShortTerm {} + | WordBusNumberTerm {} + | WordIOTerm {} + | WordSpaceTerm {} + ; + +DMATerm + : PARSEOP_DMA '(' {$$ = TrCreateLeafNode (PARSEOP_DMA);} + DMATypeKeyword + OptionalBusMasterKeyword + ',' XferTypeKeyword + OptionalNameString_Last + ')' '{' + ByteList '}' {$$ = TrLinkChildren ($3,5,$4,$5,$7,$8,$11);} + | PARSEOP_DMA '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DWordIOTerm + : PARSEOP_DWORDIO '(' {$$ = TrCreateLeafNode (PARSEOP_DWORDIO);} + OptionalResourceType_First + OptionalMinType + OptionalMaxType + OptionalDecodeType + OptionalRangeType + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString + OptionalType + OptionalTranslationType_Last + ')' {$$ = TrLinkChildren ($3,15,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$19,$20,$21,$22,$23);} + | PARSEOP_DWORDIO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DWordMemoryTerm + : PARSEOP_DWORDMEMORY '(' {$$ = TrCreateLeafNode (PARSEOP_DWORDMEMORY);} + OptionalResourceType_First + OptionalDecodeType + OptionalMinType + OptionalMaxType + OptionalMemType + ',' OptionalReadWriteKeyword + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString + OptionalAddressRange + OptionalType_Last + ')' {$$ = TrLinkChildren ($3,16,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$20,$21,$22,$23,$24,$25);} + | PARSEOP_DWORDMEMORY '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DWordSpaceTerm + : PARSEOP_DWORDSPACE '(' {$$ = TrCreateLeafNode (PARSEOP_DWORDSPACE);} + ByteConstExpr {UtCheckIntegerRange ($4, 0xC0, 0xFF);} + OptionalResourceType + OptionalDecodeType + OptionalMinType + OptionalMaxType + ',' ByteConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,14,$4,$6,$7,$8,$9,$11,$13,$15,$17,$19,$21,$22,$23,$24);} + | PARSEOP_DWORDSPACE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +EndDependentFnTerm + : PARSEOP_ENDDEPENDENTFN '(' + ')' {$$ = TrCreateLeafNode (PARSEOP_ENDDEPENDENTFN);} + | PARSEOP_ENDDEPENDENTFN '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ExtendedIOTerm + : PARSEOP_EXTENDEDIO '(' {$$ = TrCreateLeafNode (PARSEOP_EXTENDEDIO);} + OptionalResourceType_First + OptionalMinType + OptionalMaxType + OptionalDecodeType + OptionalRangeType + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + OptionalQWordConstExpr + OptionalNameString + OptionalType + OptionalTranslationType_Last + ')' {$$ = TrLinkChildren ($3,14,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$19,$20,$21,$22);} + | PARSEOP_EXTENDEDIO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ExtendedMemoryTerm + : PARSEOP_EXTENDEDMEMORY '(' {$$ = TrCreateLeafNode (PARSEOP_EXTENDEDMEMORY);} + OptionalResourceType_First + OptionalDecodeType + OptionalMinType + OptionalMaxType + OptionalMemType + ',' OptionalReadWriteKeyword + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + OptionalQWordConstExpr + OptionalNameString + OptionalAddressRange + OptionalType_Last + ')' {$$ = TrLinkChildren ($3,15,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$20,$21,$22,$23,$24);} + | PARSEOP_EXTENDEDMEMORY '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ExtendedSpaceTerm + : PARSEOP_EXTENDEDSPACE '(' {$$ = TrCreateLeafNode (PARSEOP_EXTENDEDSPACE);} + ByteConstExpr {UtCheckIntegerRange ($4, 0xC0, 0xFF);} + OptionalResourceType + OptionalDecodeType + OptionalMinType + OptionalMaxType + ',' ByteConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + OptionalQWordConstExpr + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,13,$4,$6,$7,$8,$9,$11,$13,$15,$17,$19,$21,$22,$23);} + | PARSEOP_EXTENDEDSPACE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FixedDmaTerm + : PARSEOP_FIXEDDMA '(' {$$ = TrCreateLeafNode (PARSEOP_FIXEDDMA);} + WordConstExpr /* 04: DMA RequestLines */ + ',' WordConstExpr /* 06: DMA Channels */ + OptionalXferSize /* 07: DMA TransferSize */ + OptionalNameString /* 08: DescriptorName */ + ')' {$$ = TrLinkChildren ($3,4,$4,$6,$7,$8);} + | PARSEOP_FIXEDDMA '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FixedIOTerm + : PARSEOP_FIXEDIO '(' {$$ = TrCreateLeafNode (PARSEOP_FIXEDIO);} + WordConstExpr + ',' ByteConstExpr + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,3,$4,$6,$7);} + | PARSEOP_FIXEDIO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +GpioIntTerm + : PARSEOP_GPIO_INT '(' {$$ = TrCreateLeafNode (PARSEOP_GPIO_INT);} + InterruptTypeKeyword /* 04: InterruptType */ + ',' InterruptLevel /* 06: InterruptLevel */ + OptionalShareType /* 07: SharedType */ + ',' PinConfigByte /* 09: PinConfig */ + OptionalWordConstExpr /* 10: DebounceTimeout */ + ',' StringData /* 12: ResourceSource */ + OptionalByteConstExpr /* 13: ResourceSourceIndex */ + OptionalResourceType /* 14: ResourceType */ + OptionalNameString /* 15: DescriptorName */ + OptionalBuffer_Last /* 16: VendorData */ + ')' '{' + DWordConstExpr '}' {$$ = TrLinkChildren ($3,11,$4,$6,$7,$9,$10,$12,$13,$14,$15,$16,$19);} + | PARSEOP_GPIO_INT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +GpioIoTerm + : PARSEOP_GPIO_IO '(' {$$ = TrCreateLeafNode (PARSEOP_GPIO_IO);} + OptionalShareType_First /* 04: SharedType */ + ',' PinConfigByte /* 06: PinConfig */ + OptionalWordConstExpr /* 07: DebounceTimeout */ + OptionalWordConstExpr /* 08: DriveStrength */ + OptionalIoRestriction /* 09: IoRestriction */ + ',' StringData /* 11: ResourceSource */ + OptionalByteConstExpr /* 12: ResourceSourceIndex */ + OptionalResourceType /* 13: ResourceType */ + OptionalNameString /* 14: DescriptorName */ + OptionalBuffer_Last /* 15: VendorData */ + ')' '{' + DWordList '}' {$$ = TrLinkChildren ($3,11,$4,$6,$7,$8,$9,$11,$12,$13,$14,$15,$18);} + | PARSEOP_GPIO_IO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +I2cSerialBusTerm + : PARSEOP_I2C_SERIALBUS '(' {$$ = TrCreateLeafNode (PARSEOP_I2C_SERIALBUS);} + WordConstExpr /* 04: SlaveAddress */ + OptionalSlaveMode /* 05: SlaveMode */ + ',' DWordConstExpr /* 07: ConnectionSpeed */ + OptionalAddressingMode /* 08: AddressingMode */ + ',' StringData /* 10: ResourceSource */ + OptionalByteConstExpr /* 11: ResourceSourceIndex */ + OptionalResourceType /* 12: ResourceType */ + OptionalNameString /* 13: DescriptorName */ + OptionalBuffer_Last /* 14: VendorData */ + ')' {$$ = TrLinkChildren ($3,9,$4,$5,$7,$8,$10,$11,$12,$13,$14);} + | PARSEOP_I2C_SERIALBUS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +InterruptTerm + : PARSEOP_INTERRUPT '(' {$$ = TrCreateLeafNode (PARSEOP_INTERRUPT);} + OptionalResourceType_First + ',' InterruptTypeKeyword + ',' InterruptLevel + OptionalShareType + OptionalByteConstExpr + OptionalStringData + OptionalNameString_Last + ')' '{' + DWordList '}' {$$ = TrLinkChildren ($3,8,$4,$6,$8,$9,$10,$11,$12,$15);} + | PARSEOP_INTERRUPT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +IOTerm + : PARSEOP_IO '(' {$$ = TrCreateLeafNode (PARSEOP_IO);} + IODecodeKeyword + ',' WordConstExpr + ',' WordConstExpr + ',' ByteConstExpr + ',' ByteConstExpr + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,6,$4,$6,$8,$10,$12,$13);} + | PARSEOP_IO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +IRQNoFlagsTerm + : PARSEOP_IRQNOFLAGS '(' {$$ = TrCreateLeafNode (PARSEOP_IRQNOFLAGS);} + OptionalNameString_First + ')' '{' + ByteList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_IRQNOFLAGS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +IRQTerm + : PARSEOP_IRQ '(' {$$ = TrCreateLeafNode (PARSEOP_IRQ);} + InterruptTypeKeyword + ',' InterruptLevel + OptionalShareType + OptionalNameString_Last + ')' '{' + ByteList '}' {$$ = TrLinkChildren ($3,5,$4,$6,$7,$8,$11);} + | PARSEOP_IRQ '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +Memory24Term + : PARSEOP_MEMORY24 '(' {$$ = TrCreateLeafNode (PARSEOP_MEMORY24);} + OptionalReadWriteKeyword + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,6,$4,$6,$8,$10,$12,$13);} + | PARSEOP_MEMORY24 '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +Memory32FixedTerm + : PARSEOP_MEMORY32FIXED '(' {$$ = TrCreateLeafNode (PARSEOP_MEMORY32FIXED);} + OptionalReadWriteKeyword + ',' DWordConstExpr + ',' DWordConstExpr + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,4,$4,$6,$8,$9);} + | PARSEOP_MEMORY32FIXED '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +Memory32Term + : PARSEOP_MEMORY32 '(' {$$ = TrCreateLeafNode (PARSEOP_MEMORY32);} + OptionalReadWriteKeyword + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + ',' DWordConstExpr + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,6,$4,$6,$8,$10,$12,$13);} + | PARSEOP_MEMORY32 '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +QWordIOTerm + : PARSEOP_QWORDIO '(' {$$ = TrCreateLeafNode (PARSEOP_QWORDIO);} + OptionalResourceType_First + OptionalMinType + OptionalMaxType + OptionalDecodeType + OptionalRangeType + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString + OptionalType + OptionalTranslationType_Last + ')' {$$ = TrLinkChildren ($3,15,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$19,$20,$21,$22,$23);} + | PARSEOP_QWORDIO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +QWordMemoryTerm + : PARSEOP_QWORDMEMORY '(' {$$ = TrCreateLeafNode (PARSEOP_QWORDMEMORY);} + OptionalResourceType_First + OptionalDecodeType + OptionalMinType + OptionalMaxType + OptionalMemType + ',' OptionalReadWriteKeyword + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString + OptionalAddressRange + OptionalType_Last + ')' {$$ = TrLinkChildren ($3,16,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$20,$21,$22,$23,$24,$25);} + | PARSEOP_QWORDMEMORY '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +QWordSpaceTerm + : PARSEOP_QWORDSPACE '(' {$$ = TrCreateLeafNode (PARSEOP_QWORDSPACE);} + ByteConstExpr {UtCheckIntegerRange ($4, 0xC0, 0xFF);} + OptionalResourceType + OptionalDecodeType + OptionalMinType + OptionalMaxType + ',' ByteConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + ',' QWordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,14,$4,$6,$7,$8,$9,$11,$13,$15,$17,$19,$21,$22,$23,$24);} + | PARSEOP_QWORDSPACE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +RegisterTerm + : PARSEOP_REGISTER '(' {$$ = TrCreateLeafNode (PARSEOP_REGISTER);} + AddressSpaceKeyword + ',' ByteConstExpr + ',' ByteConstExpr + ',' QWordConstExpr + OptionalAccessSize + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,6,$4,$6,$8,$10,$11,$12);} + | PARSEOP_REGISTER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +SpiSerialBusTerm + : PARSEOP_SPI_SERIALBUS '(' {$$ = TrCreateLeafNode (PARSEOP_SPI_SERIALBUS);} + WordConstExpr /* 04: DeviceSelection */ + OptionalDevicePolarity /* 05: DevicePolarity */ + OptionalWireMode /* 06: WireMode */ + ',' ByteConstExpr /* 08: DataBitLength */ + OptionalSlaveMode /* 09: SlaveMode */ + ',' DWordConstExpr /* 11: ConnectionSpeed */ + ',' ClockPolarityKeyword /* 13: ClockPolarity */ + ',' ClockPhaseKeyword /* 15: ClockPhase */ + ',' StringData /* 17: ResourceSource */ + OptionalByteConstExpr /* 18: ResourceSourceIndex */ + OptionalResourceType /* 19: ResourceType */ + OptionalNameString /* 20: DescriptorName */ + OptionalBuffer_Last /* 21: VendorData */ + ')' {$$ = TrLinkChildren ($3,13,$4,$5,$6,$8,$9,$11,$13,$15,$17,$18,$19,$20,$21);} + | PARSEOP_SPI_SERIALBUS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +StartDependentFnNoPriTerm + : PARSEOP_STARTDEPENDENTFN_NOPRI '(' {$$ = TrCreateLeafNode (PARSEOP_STARTDEPENDENTFN_NOPRI);} + ')' '{' + ResourceMacroList '}' {$$ = TrLinkChildren ($3,1,$6);} + | PARSEOP_STARTDEPENDENTFN_NOPRI '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +StartDependentFnTerm + : PARSEOP_STARTDEPENDENTFN '(' {$$ = TrCreateLeafNode (PARSEOP_STARTDEPENDENTFN);} + ByteConstExpr + ',' ByteConstExpr + ')' '{' + ResourceMacroList '}' {$$ = TrLinkChildren ($3,3,$4,$6,$9);} + | PARSEOP_STARTDEPENDENTFN '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +UartSerialBusTerm + : PARSEOP_UART_SERIALBUS '(' {$$ = TrCreateLeafNode (PARSEOP_UART_SERIALBUS);} + DWordConstExpr /* 04: ConnectionSpeed */ + OptionalBitsPerByte /* 05: BitsPerByte */ + OptionalStopBits /* 06: StopBits */ + ',' ByteConstExpr /* 08: LinesInUse */ + OptionalEndian /* 09: Endianess */ + OptionalParityType /* 10: Parity */ + OptionalFlowControl /* 11: FlowControl */ + ',' WordConstExpr /* 13: Rx BufferSize */ + ',' WordConstExpr /* 15: Tx BufferSize */ + ',' StringData /* 17: ResourceSource */ + OptionalByteConstExpr /* 18: ResourceSourceIndex */ + OptionalResourceType /* 19: ResourceType */ + OptionalNameString /* 20: DescriptorName */ + OptionalBuffer_Last /* 21: VendorData */ + ')' {$$ = TrLinkChildren ($3,14,$4,$5,$6,$8,$9,$10,$11,$13,$15,$17,$18,$19,$20,$21);} + | PARSEOP_UART_SERIALBUS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +VendorLongTerm + : PARSEOP_VENDORLONG '(' {$$ = TrCreateLeafNode (PARSEOP_VENDORLONG);} + OptionalNameString_First + ')' '{' + ByteList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_VENDORLONG '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +VendorShortTerm + : PARSEOP_VENDORSHORT '(' {$$ = TrCreateLeafNode (PARSEOP_VENDORSHORT);} + OptionalNameString_First + ')' '{' + ByteList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_VENDORSHORT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +WordBusNumberTerm + : PARSEOP_WORDBUSNUMBER '(' {$$ = TrCreateLeafNode (PARSEOP_WORDBUSNUMBER);} + OptionalResourceType_First + OptionalMinType + OptionalMaxType + OptionalDecodeType + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,12,$4,$5,$6,$7,$9,$11,$13,$15,$17,$18,$19,$20);} + | PARSEOP_WORDBUSNUMBER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +WordIOTerm + : PARSEOP_WORDIO '(' {$$ = TrCreateLeafNode (PARSEOP_WORDIO);} + OptionalResourceType_First + OptionalMinType + OptionalMaxType + OptionalDecodeType + OptionalRangeType + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString + OptionalType + OptionalTranslationType_Last + ')' {$$ = TrLinkChildren ($3,15,$4,$5,$6,$7,$8,$10,$12,$14,$16,$18,$19,$20,$21,$22,$23);} + | PARSEOP_WORDIO '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +WordSpaceTerm + : PARSEOP_WORDSPACE '(' {$$ = TrCreateLeafNode (PARSEOP_WORDSPACE);} + ByteConstExpr {UtCheckIntegerRange ($4, 0xC0, 0xFF);} + OptionalResourceType + OptionalDecodeType + OptionalMinType + OptionalMaxType + ',' ByteConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + ',' WordConstExpr + OptionalByteConstExpr + OptionalStringData + OptionalNameString_Last + ')' {$$ = TrLinkChildren ($3,14,$4,$6,$7,$8,$9,$11,$13,$15,$17,$19,$21,$22,$23,$24);} + | PARSEOP_WORDSPACE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + + +/******* Object References ***********************************************/ + +/* Allow IO, DMA, IRQ Resource macro names to also be used as identifiers */ + +NameString + : NameSeg {} + | PARSEOP_NAMESTRING {$$ = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, (ACPI_NATIVE_INT) AslCompilerlval.s);} + | PARSEOP_IO {$$ = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, (ACPI_NATIVE_INT) "IO");} + | PARSEOP_DMA {$$ = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, (ACPI_NATIVE_INT) "DMA");} + | PARSEOP_IRQ {$$ = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, (ACPI_NATIVE_INT) "IRQ");} + ; + +NameSeg + : PARSEOP_NAMESEG {$$ = TrCreateValuedLeafNode (PARSEOP_NAMESEG, (ACPI_NATIVE_INT) AslCompilerlval.s);} + ; + + +/******************************************************************************* + * + * ASL Helper Terms + * + ******************************************************************************/ + +OptionalBusMasterKeyword + : ',' {$$ = TrCreateLeafNode (PARSEOP_BUSMASTERTYPE_MASTER);} + | ',' PARSEOP_BUSMASTERTYPE_MASTER {$$ = TrCreateLeafNode (PARSEOP_BUSMASTERTYPE_MASTER);} + | ',' PARSEOP_BUSMASTERTYPE_NOTMASTER {$$ = TrCreateLeafNode (PARSEOP_BUSMASTERTYPE_NOTMASTER);} + ; + +OptionalAccessAttribTerm + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' ByteConstExpr {$$ = $2;} + | ',' AccessAttribKeyword {$$ = $2;} + ; + +OptionalAccessSize + : {$$ = TrCreateValuedLeafNode (PARSEOP_BYTECONST, 0);} + | ',' {$$ = TrCreateValuedLeafNode (PARSEOP_BYTECONST, 0);} + | ',' ByteConstExpr {$$ = $2;} + ; + +OptionalAddressingMode + : ',' {$$ = NULL;} + | ',' AddressingModeKeyword {$$ = $2;} + ; + +OptionalAddressRange + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' AddressKeyword {$$ = $2;} + ; + +OptionalBitsPerByte + : ',' {$$ = NULL;} + | ',' BitsPerByteKeyword {$$ = $2;} + ; + +OptionalBuffer_Last + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' RawDataBufferTerm {$$ = $2;} + ; + +OptionalByteConstExpr + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' ByteConstExpr {$$ = $2;} + ; + +OptionalDecodeType + : ',' {$$ = NULL;} + | ',' DecodeKeyword {$$ = $2;} + ; + +OptionalDevicePolarity + : ',' {$$ = NULL;} + | ',' DevicePolarityKeyword {$$ = $2;} + ; + +OptionalDWordConstExpr + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' DWordConstExpr {$$ = $2;} + ; + +OptionalEndian + : ',' {$$ = NULL;} + | ',' EndianKeyword {$$ = $2;} + ; + +OptionalFlowControl + : ',' {$$ = NULL;} + | ',' FlowControlKeyword {$$ = $2;} + ; + +OptionalIoRestriction + : ',' {$$ = NULL;} + | ',' IoRestrictionKeyword {$$ = $2;} + ; + +OptionalListString + : {$$ = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, ACPI_TO_INTEGER (""));} /* Placeholder is a NULL string */ + | ',' {$$ = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, ACPI_TO_INTEGER (""));} /* Placeholder is a NULL string */ + | ',' TermArg {$$ = $2;} + ; + +OptionalMaxType + : ',' {$$ = NULL;} + | ',' MaxKeyword {$$ = $2;} + ; + +OptionalMemType + : ',' {$$ = NULL;} + | ',' MemTypeKeyword {$$ = $2;} + ; + +OptionalMinType + : ',' {$$ = NULL;} + | ',' MinKeyword {$$ = $2;} + ; + +OptionalNameString + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' NameString {$$ = $2;} + ; + +OptionalNameString_Last + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' NameString {$$ = $2;} + ; + +OptionalNameString_First + : {$$ = TrCreateLeafNode (PARSEOP_ZERO);} + | NameString {$$ = $1;} + ; + +OptionalObjectTypeKeyword + : {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE_UNK);} + | ',' ObjectTypeKeyword {$$ = $2;} + ; + +OptionalParityType + : ',' {$$ = NULL;} + | ',' ParityTypeKeyword {$$ = $2;} + ; + +OptionalQWordConstExpr + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' QWordConstExpr {$$ = $2;} + ; + +OptionalRangeType + : ',' {$$ = NULL;} + | ',' RangeTypeKeyword {$$ = $2;} + ; + +OptionalReadWriteKeyword + : {$$ = TrCreateLeafNode (PARSEOP_READWRITETYPE_BOTH);} + | PARSEOP_READWRITETYPE_BOTH {$$ = TrCreateLeafNode (PARSEOP_READWRITETYPE_BOTH);} + | PARSEOP_READWRITETYPE_READONLY {$$ = TrCreateLeafNode (PARSEOP_READWRITETYPE_READONLY);} + ; + +OptionalResourceType_First + : {$$ = TrCreateLeafNode (PARSEOP_RESOURCETYPE_CONSUMER);} + | ResourceTypeKeyword {$$ = $1;} + ; + +OptionalResourceType + : {$$ = TrCreateLeafNode (PARSEOP_RESOURCETYPE_CONSUMER);} + | ',' {$$ = TrCreateLeafNode (PARSEOP_RESOURCETYPE_CONSUMER);} + | ',' ResourceTypeKeyword {$$ = $2;} + ; + +OptionalSlaveMode + : ',' {$$ = NULL;} + | ',' SlaveModeKeyword {$$ = $2;} + ; + +OptionalShareType + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' ShareTypeKeyword {$$ = $2;} + ; + +OptionalShareType_First + : {$$ = NULL;} + | ShareTypeKeyword {$$ = $1;} + ; + +OptionalStopBits + : ',' {$$ = NULL;} + | ',' StopBitsKeyword {$$ = $2;} + ; + +OptionalStringData + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' StringData {$$ = $2;} + ; + +OptionalTranslationType_Last + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' TranslationKeyword {$$ = $2;} + ; + +OptionalType + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' TypeKeyword {$$ = $2;} + ; + +OptionalType_Last + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' TypeKeyword {$$ = $2;} + ; + +OptionalWireMode + : ',' {$$ = NULL;} + | ',' WireModeKeyword {$$ = $2;} + ; + +OptionalWordConstExpr + : ',' {$$ = NULL;} + | ',' WordConstExpr {$$ = $2;} + ; + +OptionalXferSize + : {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_32, 2);} + | ',' {$$ = TrCreateValuedLeafNode (PARSEOP_XFERSIZE_32, 2);} + | ',' XferSizeKeyword {$$ = $2;} + ; diff --git a/third_party/lib/acpica/source/compiler/aslrestype1.c b/third_party/lib/acpica/source/compiler/aslrestype1.c new file mode 100644 index 000000000..4bd905978 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype1.c @@ -0,0 +1,641 @@ +/****************************************************************************** + * + * Module Name: aslrestype1 - Miscellaneous small resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype1") + +/* + * This module contains miscellaneous small resource descriptors: + * + * EndTag + * EndDependentFn + * Memory24 + * Memory32 + * Memory32Fixed + * StartDependentFn + * StartDependentFnNoPri + * VendorShort + */ + +/******************************************************************************* + * + * FUNCTION: RsDoEndTagDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "EndDependentFn" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoEndTagDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ASL_RESOURCE_NODE *Rnode; + + + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_END_TAG)); + + Descriptor = Rnode->Buffer; + Descriptor->EndTag.DescriptorType = ACPI_RESOURCE_NAME_END_TAG | + ASL_RDESC_END_TAG_SIZE; + Descriptor->EndTag.Checksum = 0; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoEndDependentDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "EndDependentFn" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoEndDependentDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ASL_RESOURCE_NODE *Rnode; + + + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_END_DEPENDENT)); + + Descriptor = Rnode->Buffer; + Descriptor->EndDpf.DescriptorType = + ACPI_RESOURCE_NAME_END_DEPENDENT | ASL_RDESC_END_DEPEND_SIZE; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoMemory24Descriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "Memory24" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoMemory24Descriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_MEMORY24)); + + Descriptor = Rnode->Buffer; + Descriptor->Memory24.DescriptorType = ACPI_RESOURCE_NAME_MEMORY24; + Descriptor->Memory24.ResourceLength = 9; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Read/Write type */ + + RsSetFlagBits (&Descriptor->Memory24.Flags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_READWRITETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory24.Flags), 0); + break; + + case 1: /* Min Address */ + + Descriptor->Memory24.Minimum = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory24.Minimum)); + MinOp = InitializerOp; + break; + + case 2: /* Max Address */ + + Descriptor->Memory24.Maximum = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory24.Maximum)); + MaxOp = InitializerOp; + break; + + case 3: /* Alignment */ + + Descriptor->Memory24.Alignment = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_ALIGNMENT, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory24.Alignment)); + break; + + case 4: /* Length */ + + Descriptor->Memory24.AddressLength = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory24.AddressLength)); + LengthOp = InitializerOp; + break; + + case 5: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Align values (Alignment==0 means 64K) */ + + RsSmallAddressCheck (ACPI_RESOURCE_NAME_MEMORY24, + Descriptor->Memory24.Minimum, + Descriptor->Memory24.Maximum, + Descriptor->Memory24.AddressLength, + Descriptor->Memory24.Alignment, + MinOp, MaxOp, LengthOp, NULL, Info->DescriptorTypeOp); + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoMemory32Descriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "Memory32" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoMemory32Descriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *AlignOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_MEMORY32)); + + Descriptor = Rnode->Buffer; + Descriptor->Memory32.DescriptorType = ACPI_RESOURCE_NAME_MEMORY32; + Descriptor->Memory32.ResourceLength = 17; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Read/Write type */ + + RsSetFlagBits (&Descriptor->Memory32.Flags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_READWRITETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory32.Flags), 0); + break; + + case 1: /* Min Address */ + + Descriptor->Memory32.Minimum = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory32.Minimum)); + MinOp = InitializerOp; + break; + + case 2: /* Max Address */ + + Descriptor->Memory32.Maximum = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory32.Maximum)); + MaxOp = InitializerOp; + break; + + case 3: /* Alignment */ + + Descriptor->Memory32.Alignment = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_ALIGNMENT, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory32.Alignment)); + AlignOp = InitializerOp; + break; + + case 4: /* Length */ + + Descriptor->Memory32.AddressLength = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Memory32.AddressLength)); + LengthOp = InitializerOp; + break; + + case 5: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Align values */ + + RsSmallAddressCheck (ACPI_RESOURCE_NAME_MEMORY32, + Descriptor->Memory32.Minimum, + Descriptor->Memory32.Maximum, + Descriptor->Memory32.AddressLength, + Descriptor->Memory32.Alignment, + MinOp, MaxOp, LengthOp, AlignOp, Info->DescriptorTypeOp); + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoMemory32FixedDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "Memory32Fixed" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoMemory32FixedDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_FIXED_MEMORY32)); + + Descriptor = Rnode->Buffer; + Descriptor->FixedMemory32.DescriptorType = ACPI_RESOURCE_NAME_FIXED_MEMORY32; + Descriptor->FixedMemory32.ResourceLength = 9; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Read/Write type */ + + RsSetFlagBits (&Descriptor->FixedMemory32.Flags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_READWRITETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedMemory32.Flags), 0); + break; + + case 1: /* Address */ + + Descriptor->FixedMemory32.Address = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_BASEADDRESS, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedMemory32.Address)); + break; + + case 2: /* Length */ + + Descriptor->FixedMemory32.AddressLength = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedMemory32.AddressLength)); + break; + + case 3: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoStartDependentDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "StartDependentFn" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoStartDependentDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + ASL_RESOURCE_NODE *PreviousRnode; + ASL_RESOURCE_NODE *NextRnode; + ASL_RESOURCE_INFO NextInfo; + UINT32 CurrentByteOffset; + UINT32 i; + UINT8 State; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_START_DEPENDENT)); + + PreviousRnode = Rnode; + Descriptor = Rnode->Buffer; + + /* Increment offset past StartDependent descriptor */ + + CurrentByteOffset += sizeof (AML_RESOURCE_START_DEPENDENT); + + /* Descriptor has priority byte */ + + Descriptor->StartDpf.DescriptorType = + ACPI_RESOURCE_NAME_START_DEPENDENT | (ASL_RDESC_ST_DEPEND_SIZE + 0x01); + + /* Process all child initialization nodes */ + + State = ACPI_RSTATE_START_DEPENDENT; + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Compatibility Priority */ + + if ((UINT8) InitializerOp->Asl.Value.Integer > 2) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_PRIORITY, + InitializerOp, NULL); + } + + RsSetFlagBits (&Descriptor->StartDpf.Flags, InitializerOp, 0, 0); + break; + + case 1: /* Performance/Robustness Priority */ + + if ((UINT8) InitializerOp->Asl.Value.Integer > 2) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_PERFORMANCE, + InitializerOp, NULL); + } + + RsSetFlagBits (&Descriptor->StartDpf.Flags, InitializerOp, 2, 0); + break; + + default: + + NextInfo.CurrentByteOffset = CurrentByteOffset; + NextInfo.DescriptorTypeOp = InitializerOp; + + NextRnode = RsDoOneResourceDescriptor (&NextInfo, &State); + + /* + * Update current byte offset to indicate the number of bytes from the + * start of the buffer. Buffer can include multiple descriptors, we + * must keep track of the offset of not only each descriptor, but each + * element (field) within each descriptor as well. + */ + CurrentByteOffset += RsLinkDescriptorChain ( + &PreviousRnode, NextRnode); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoStartDependentNoPriDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "StartDependentNoPri" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoStartDependentNoPriDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + ASL_RESOURCE_NODE *PreviousRnode; + ASL_RESOURCE_NODE *NextRnode; + ASL_RESOURCE_INFO NextInfo; + UINT32 CurrentByteOffset; + UINT8 State; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_START_DEPENDENT_NOPRIO)); + + Descriptor = Rnode->Buffer; + Descriptor->StartDpf.DescriptorType = + ACPI_RESOURCE_NAME_START_DEPENDENT | ASL_RDESC_ST_DEPEND_SIZE; + PreviousRnode = Rnode; + + /* Increment offset past StartDependentNoPri descriptor */ + + CurrentByteOffset += sizeof (AML_RESOURCE_START_DEPENDENT_NOPRIO); + + /* Process all child initialization nodes */ + + State = ACPI_RSTATE_START_DEPENDENT; + while (InitializerOp) + { + NextInfo.CurrentByteOffset = CurrentByteOffset; + NextInfo.DescriptorTypeOp = InitializerOp; + + NextRnode = RsDoOneResourceDescriptor (&NextInfo, &State); + + /* + * Update current byte offset to indicate the number of bytes from the + * start of the buffer. Buffer can include multiple descriptors, we + * must keep track of the offset of not only each descriptor, but each + * element (field) within each descriptor as well. + */ + CurrentByteOffset += RsLinkDescriptorChain (&PreviousRnode, NextRnode); + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoVendorSmallDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "VendorShort" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoVendorSmallDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT8 *VendorData; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + + /* Allocate worst case - 7 vendor bytes */ + + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_VENDOR_SMALL) + 7); + + Descriptor = Rnode->Buffer; + Descriptor->VendorSmall.DescriptorType = ACPI_RESOURCE_NAME_VENDOR_SMALL; + VendorData = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_SMALL_HEADER); + + /* Process all child initialization nodes */ + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + for (i = 0; InitializerOp; i++) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + break; + } + + /* Maximum 7 vendor data bytes allowed (0-6) */ + + if (i >= 7) + { + AslError (ASL_ERROR, ASL_MSG_VENDOR_LIST, InitializerOp, NULL); + + /* Eat the excess initializers */ + + while (InitializerOp) + { + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + break; + } + + VendorData[i] = (UINT8) InitializerOp->Asl.Value.Integer; + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Adjust the Rnode buffer size, so correct number of bytes are emitted */ + + Rnode->BufferLength -= (7 - i); + + /* Set the length in the Type Tag */ + + Descriptor->VendorSmall.DescriptorType |= (UINT8) i; + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype1i.c b/third_party/lib/acpica/source/compiler/aslrestype1i.c new file mode 100644 index 000000000..0f38e40da --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype1i.c @@ -0,0 +1,665 @@ +/****************************************************************************** + * + * Module Name: aslrestype1i - Small I/O-related resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype1i") + +/* + * This module contains the I/O-related small resource descriptors: + * + * DMA + * FixedDMA + * FixedIO + * IO + * IRQ + * IRQNoFlags + */ + +/******************************************************************************* + * + * FUNCTION: RsDoDmaDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "DMA" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoDmaDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + UINT8 DmaChannelMask = 0; + UINT8 DmaChannels = 0; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_DMA)); + + Descriptor = Rnode->Buffer; + Descriptor->Dma.DescriptorType = + ACPI_RESOURCE_NAME_DMA | ASL_RDESC_DMA_SIZE; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* DMA type */ + + RsSetFlagBits (&Descriptor->Dma.Flags, InitializerOp, 5, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_DMATYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Dma.Flags), 5, 2); + break; + + case 1: /* Bus Master */ + + RsSetFlagBits (&Descriptor->Dma.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_BUSMASTER, + CurrentByteOffset + ASL_RESDESC_OFFSET (Dma.Flags), 2); + break; + + case 2: /* Xfer Type (transfer width) */ + + RsSetFlagBits (&Descriptor->Dma.Flags, InitializerOp, 0, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_XFERTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Dma.Flags), 0, 2); + break; + + case 3: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + /* All DMA channel bytes are handled here, after flags and name */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* Up to 8 channels can be specified in the list */ + + DmaChannels++; + if (DmaChannels > 8) + { + AslError (ASL_ERROR, ASL_MSG_DMA_LIST, + InitializerOp, NULL); + return (Rnode); + } + + /* Only DMA channels 0-7 are allowed (mask is 8 bits) */ + + if (InitializerOp->Asl.Value.Integer > 7) + { + AslError (ASL_ERROR, ASL_MSG_DMA_CHANNEL, + InitializerOp, NULL); + } + + /* Build the mask */ + + DmaChannelMask |= + (1 << ((UINT8) InitializerOp->Asl.Value.Integer)); + } + + if (i == 4) /* case 4: First DMA byte */ + { + /* Check now for duplicates in list */ + + RsCheckListForDuplicates (InitializerOp); + + /* Create a named field at the start of the list */ + + RsCreateByteField (InitializerOp, ACPI_RESTAG_DMA, + CurrentByteOffset + + ASL_RESDESC_OFFSET (Dma.DmaChannelMask)); + } + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Now we can set the channel mask */ + + Descriptor->Dma.DmaChannelMask = DmaChannelMask; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoFixedDmaDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "FixedDMA" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoFixedDmaDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_FIXED_DMA)); + + Descriptor = Rnode->Buffer; + Descriptor->FixedDma.DescriptorType = + ACPI_RESOURCE_NAME_FIXED_DMA | ASL_RDESC_FIXED_DMA_SIZE; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* DMA Request Lines [WORD] (_DMA) */ + + Descriptor->FixedDma.RequestLines = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_DMA, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedDma.RequestLines)); + break; + + case 1: /* DMA Channel [WORD] (_TYP) */ + + Descriptor->FixedDma.Channels = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_DMATYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedDma.Channels)); + break; + + case 2: /* Transfer Width [BYTE] (_SIZ) */ + + Descriptor->FixedDma.Width = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_XFERTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedDma.Width)); + break; + + case 3: /* Descriptor Name (optional) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: /* Ignore any extra nodes */ + + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoFixedIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "FixedIO" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoFixedIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *AddressOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_FIXED_IO)); + + Descriptor = Rnode->Buffer; + Descriptor->Io.DescriptorType = + ACPI_RESOURCE_NAME_FIXED_IO | ASL_RDESC_FIXED_IO_SIZE; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Base Address */ + + Descriptor->FixedIo.Address = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_BASEADDRESS, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedIo.Address)); + AddressOp = InitializerOp; + break; + + case 1: /* Length */ + + Descriptor->FixedIo.AddressLength = + (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (FixedIo.AddressLength)); + break; + + case 2: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Error checks */ + + if (Descriptor->FixedIo.Address > 0x03FF) + { + AslError (ASL_WARNING, ASL_MSG_ISA_ADDRESS, AddressOp, NULL); + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "IO" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *AlignOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_IO)); + + Descriptor = Rnode->Buffer; + Descriptor->Io.DescriptorType = + ACPI_RESOURCE_NAME_IO | ASL_RDESC_IO_SIZE; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Decode size */ + + RsSetFlagBits (&Descriptor->Io.Flags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Flags), 0); + break; + + case 1: /* Min Address */ + + Descriptor->Io.Minimum = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Minimum)); + MinOp = InitializerOp; + break; + + case 2: /* Max Address */ + + Descriptor->Io.Maximum = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Maximum)); + MaxOp = InitializerOp; + break; + + case 3: /* Alignment */ + + Descriptor->Io.Alignment = + (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_ALIGNMENT, + CurrentByteOffset + ASL_RESDESC_OFFSET (Io.Alignment)); + AlignOp = InitializerOp; + break; + + case 4: /* Length */ + + Descriptor->Io.AddressLength = + (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Io.AddressLength)); + LengthOp = InitializerOp; + break; + + case 5: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Align values */ + + RsSmallAddressCheck (ACPI_RESOURCE_NAME_IO, + Descriptor->Io.Minimum, + Descriptor->Io.Maximum, + Descriptor->Io.AddressLength, + Descriptor->Io.Alignment, + MinOp, MaxOp, LengthOp, AlignOp, Info->DescriptorTypeOp); + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoIrqDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "IRQ" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoIrqDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT32 Interrupts = 0; + UINT16 IrqMask = 0; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_IRQ)); + + /* Length = 3 (with flag byte) */ + + Descriptor = Rnode->Buffer; + Descriptor->Irq.DescriptorType = + ACPI_RESOURCE_NAME_IRQ | (ASL_RDESC_IRQ_SIZE + 0x01); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Interrupt Type (or Mode - edge/level) */ + + RsSetFlagBits (&Descriptor->Irq.Flags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.Flags), 0); + break; + + case 1: /* Interrupt Level (or Polarity - Active high/low) */ + + RsSetFlagBits (&Descriptor->Irq.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTLEVEL, + CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.Flags), 3); + break; + + case 2: /* Share Type - Default: exclusive (0) */ + + RsSetFlagBits (&Descriptor->Irq.Flags, InitializerOp, 4, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTSHARE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.Flags), 4); + break; + + case 3: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + /* All IRQ bytes are handled here, after the flags and name */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* Up to 16 interrupts can be specified in the list */ + + Interrupts++; + if (Interrupts > 16) + { + AslError (ASL_ERROR, ASL_MSG_INTERRUPT_LIST, + InitializerOp, NULL); + return (Rnode); + } + + /* Only interrupts 0-15 are allowed (mask is 16 bits) */ + + if (InitializerOp->Asl.Value.Integer > 15) + { + AslError (ASL_ERROR, ASL_MSG_INTERRUPT_NUMBER, + InitializerOp, NULL); + } + else + { + IrqMask |= (1 << (UINT8) InitializerOp->Asl.Value.Integer); + } + } + + /* Case 4: First IRQ value in list */ + + if (i == 4) + { + /* Check now for duplicates in list */ + + RsCheckListForDuplicates (InitializerOp); + + /* Create a named field at the start of the list */ + + RsCreateWordField (InitializerOp, ACPI_RESTAG_INTERRUPT, + CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.IrqMask)); + } + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Now we can set the channel mask */ + + Descriptor->Irq.IrqMask = IrqMask; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoIrqNoFlagsDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a short "IRQNoFlags" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoIrqNoFlagsDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT16 IrqMask = 0; + UINT32 Interrupts = 0; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_IRQ_NOFLAGS)); + + Descriptor = Rnode->Buffer; + Descriptor->Irq.DescriptorType = + ACPI_RESOURCE_NAME_IRQ | ASL_RDESC_IRQ_SIZE; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Name */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + /* IRQ bytes are handled here, after the flags and name */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* Up to 16 interrupts can be specified in the list */ + + Interrupts++; + if (Interrupts > 16) + { + AslError (ASL_ERROR, ASL_MSG_INTERRUPT_LIST, + InitializerOp, NULL); + return (Rnode); + } + + /* Only interrupts 0-15 are allowed (mask is 16 bits) */ + + if (InitializerOp->Asl.Value.Integer > 15) + { + AslError (ASL_ERROR, ASL_MSG_INTERRUPT_NUMBER, + InitializerOp, NULL); + } + else + { + IrqMask |= (1 << ((UINT8) InitializerOp->Asl.Value.Integer)); + } + } + + /* Case 1: First IRQ value in list */ + + if (i == 1) + { + /* Check now for duplicates in list */ + + RsCheckListForDuplicates (InitializerOp); + + /* Create a named field at the start of the list */ + + RsCreateWordField (InitializerOp, ACPI_RESTAG_INTERRUPT, + CurrentByteOffset + ASL_RESDESC_OFFSET (Irq.IrqMask)); + } + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Now we can set the interrupt mask */ + + Descriptor->Irq.IrqMask = IrqMask; + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype2.c b/third_party/lib/acpica/source/compiler/aslrestype2.c new file mode 100644 index 000000000..b75c1184e --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype2.c @@ -0,0 +1,457 @@ +/****************************************************************************** + * + * Module Name: aslrestype2 - Miscellaneous Large resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype2") + +/* + * This module contains miscellaneous large resource descriptors: + * + * Register + * Interrupt + * VendorLong + */ + +/******************************************************************************* + * + * FUNCTION: RsDoGeneralRegisterDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "Register" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoGeneralRegisterDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_GENERIC_REGISTER)); + + Descriptor = Rnode->Buffer; + Descriptor->GenericReg.DescriptorType = ACPI_RESOURCE_NAME_GENERIC_REGISTER; + Descriptor->GenericReg.ResourceLength = 12; + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Address space */ + + Descriptor->GenericReg.AddressSpaceId = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_ADDRESSSPACE, + CurrentByteOffset + ASL_RESDESC_OFFSET (GenericReg.AddressSpaceId)); + break; + + case 1: /* Register Bit Width */ + + Descriptor->GenericReg.BitWidth = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_REGISTERBITWIDTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (GenericReg.BitWidth)); + break; + + case 2: /* Register Bit Offset */ + + Descriptor->GenericReg.BitOffset = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_REGISTERBITOFFSET, + CurrentByteOffset + ASL_RESDESC_OFFSET (GenericReg.BitOffset)); + break; + + case 3: /* Register Address */ + + Descriptor->GenericReg.Address = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_ADDRESS, + CurrentByteOffset + ASL_RESDESC_OFFSET (GenericReg.Address)); + break; + + case 4: /* Access Size (ACPI 3.0) */ + + Descriptor->GenericReg.AccessSize = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_ACCESSSIZE, + CurrentByteOffset + ASL_RESDESC_OFFSET (GenericReg.AccessSize)); + + if (Descriptor->GenericReg.AccessSize > AML_FIELD_ACCESS_QWORD) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_ACCESS_SIZE, + InitializerOp, NULL); + } + break; + + case 5: /* ResourceTag (ACPI 3.0b) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoInterruptDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "Interrupt" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoInterruptDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + AML_RESOURCE *Rover = NULL; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN HasResSourceIndex = FALSE; + UINT8 ResSourceIndex = 0; + UINT8 *ResSourceString = NULL; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + StringLength = RsGetStringDataLength (InitializerOp); + + /* Count the interrupt numbers */ + + for (i = 0; InitializerOp; i++) + { + InitializerOp = ASL_GET_PEER_NODE (InitializerOp); + + if (i <= 6) + { + if (i == 3 && + InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* + * ResourceSourceIndex was specified, always make room for + * it, even if the ResourceSource was omitted. + */ + OptionIndex++; + } + + continue; + } + + OptionIndex += 4; + } + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_EXTENDED_IRQ) + + 1 + OptionIndex + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->ExtendedIrq.DescriptorType = ACPI_RESOURCE_NAME_EXTENDED_IRQ; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + Descriptor->ExtendedIrq.ResourceLength = 2; /* Flags and table length byte */ + Descriptor->ExtendedIrq.InterruptCount = 0; + + Rover = ACPI_CAST_PTR (AML_RESOURCE, + (&(Descriptor->ExtendedIrq.Interrupts[0]))); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage (Default: consumer (1) */ + + RsSetFlagBits (&Descriptor->ExtendedIrq.Flags, InitializerOp, 0, 1); + break; + + case 1: /* Interrupt Type (or Mode - edge/level) */ + + RsSetFlagBits (&Descriptor->ExtendedIrq.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtendedIrq.Flags), 1); + break; + + case 2: /* Interrupt Level (or Polarity - Active high/low) */ + + RsSetFlagBits (&Descriptor->ExtendedIrq.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTLEVEL, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtendedIrq.Flags), 2); + break; + + case 3: /* Share Type - Default: exclusive (0) */ + + RsSetFlagBits (&Descriptor->ExtendedIrq.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTSHARE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtendedIrq.Flags), 3); + break; + + case 4: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + HasResSourceIndex = TRUE; + ResSourceIndex = (UINT8) InitializerOp->Asl.Value.Integer; + } + break; + + case 5: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + ResSourceString = (UINT8 *) InitializerOp->Asl.Value.String; + } + + /* ResourceSourceIndex must also be valid */ + + if (!HasResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (HasResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 6: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + /* + * Interrupt Numbers come through here, repeatedly + */ + + /* Maximum 255 interrupts allowed for this descriptor */ + + if (Descriptor->ExtendedIrq.InterruptCount == 255) + { + AslError (ASL_ERROR, ASL_MSG_EX_INTERRUPT_LIST, + InitializerOp, NULL); + return (Rnode); + } + + /* Each interrupt number must be a 32-bit value */ + + if (InitializerOp->Asl.Value.Integer > ACPI_UINT32_MAX) + { + AslError (ASL_ERROR, ASL_MSG_EX_INTERRUPT_NUMBER, + InitializerOp, NULL); + } + + /* Save the integer and move pointer to the next one */ + + Rover->DwordItem = (UINT32) InitializerOp->Asl.Value.Integer; + Rover = ACPI_ADD_PTR (AML_RESOURCE, &(Rover->DwordItem), 4); + Descriptor->ExtendedIrq.InterruptCount++; + Descriptor->ExtendedIrq.ResourceLength += 4; + + /* Case 7: First interrupt number in list */ + + if (i == 7) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + /* Must be at least one interrupt */ + + AslError (ASL_ERROR, ASL_MSG_EX_INTERRUPT_LIST_MIN, + InitializerOp, NULL); + } + + /* Check now for duplicates in list */ + + RsCheckListForDuplicates (InitializerOp); + + /* Create a named field at the start of the list */ + + RsCreateDwordField (InitializerOp, ACPI_RESTAG_INTERRUPT, + CurrentByteOffset + + ASL_RESDESC_OFFSET (ExtendedIrq.Interrupts[0])); + } + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + + /* Add optional ResSourceIndex if present */ + + if (HasResSourceIndex) + { + Rover->ByteItem = ResSourceIndex; + Rover = ACPI_ADD_PTR (AML_RESOURCE, &(Rover->ByteItem), 1); + Descriptor->ExtendedIrq.ResourceLength += 1; + } + + /* Add optional ResSource string if present */ + + if (StringLength && ResSourceString) + { + + strcpy ((char *) Rover, (char *) ResSourceString); + Rover = ACPI_ADD_PTR ( + AML_RESOURCE, &(Rover->ByteItem), StringLength); + + Descriptor->ExtendedIrq.ResourceLength = (UINT16) + (Descriptor->ExtendedIrq.ResourceLength + StringLength); + } + + Rnode->BufferLength = + (ASL_RESDESC_OFFSET (ExtendedIrq.Interrupts[0]) - + ASL_RESDESC_OFFSET (ExtendedIrq.DescriptorType)) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoVendorLargeDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "VendorLong" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoVendorLargeDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + UINT8 *VendorData; + UINT32 i; + + + /* Count the number of data bytes */ + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + + for (i = 0; InitializerOp; i++) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + break; + } + InitializerOp = InitializerOp->Asl.Next; + } + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + Rnode = RsAllocateResourceNode (sizeof (AML_RESOURCE_VENDOR_LARGE) + i); + + Descriptor = Rnode->Buffer; + Descriptor->VendorLarge.DescriptorType = ACPI_RESOURCE_NAME_VENDOR_LARGE; + Descriptor->VendorLarge.ResourceLength = (UINT16) i; + + /* Point to end-of-descriptor for vendor data */ + + VendorData = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_LARGE_HEADER); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + break; + } + + VendorData[i] = (UINT8) InitializerOp->Asl.Value.Integer; + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype2d.c b/third_party/lib/acpica/source/compiler/aslrestype2d.c new file mode 100644 index 000000000..c7841b0fc --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype2d.c @@ -0,0 +1,737 @@ +/****************************************************************************** + * + * Module Name: aslrestype2d - Large DWord address resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype2d") + +/* + * This module contains the Dword (32-bit) address space descriptors: + * + * DwordIO + * DwordMemory + * DwordSpace + */ + +/******************************************************************************* + * + * FUNCTION: RsDoDwordIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "DwordIO" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoDwordIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT8 *OptionalFields; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS32) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address32.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS32; + Descriptor->Address32.ResourceType = ACPI_ADDRESS_TYPE_IO_RANGE; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS32); + Descriptor->Address32.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS32) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 0, 1); + break; + + case 1: /* MinType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 2); + break; + + case 2: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 3); + break; + + case 3: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 1); + break; + + case 4: /* Range Type */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 0, 3); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_RANGETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 0, 2); + break; + + case 5: /* Address Granularity */ + + Descriptor->Address32.Granularity = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Granularity)); + GranOp = InitializerOp; + break; + + case 6: /* Address Min */ + + Descriptor->Address32.Minimum = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Minimum)); + MinOp = InitializerOp; + break; + + case 7: /* Address Max */ + + Descriptor->Address32.Maximum = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Maximum)); + MaxOp = InitializerOp; + break; + + case 8: /* Translation Offset */ + + Descriptor->Address32.TranslationOffset = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.TranslationOffset)); + break; + + case 9: /* Address Length */ + + Descriptor->Address32.AddressLength = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.AddressLength)); + LengthOp = InitializerOp; + break; + + case 10: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* Found a valid ResourceSourceIndex */ + + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address32.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 11: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + /* Found a valid ResourceSource */ + + Descriptor->Address32.ResourceLength = (UINT16) + (Descriptor->Address32.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 12: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 13: /* Type */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 4, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 4); + break; + + case 14: /* Translation Type */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TRANSTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + (UINT64) Descriptor->Address32.Minimum, + (UINT64) Descriptor->Address32.Maximum, + (UINT64) Descriptor->Address32.AddressLength, + (UINT64) Descriptor->Address32.Granularity, + Descriptor->Address32.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS32) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoDwordMemoryDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "DwordMemory" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoDwordMemoryDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS32) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address32.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS32; + Descriptor->Address32.ResourceType = ACPI_ADDRESS_TYPE_MEMORY_RANGE; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS32); + Descriptor->Address32.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS32) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 0, 1); + break; + + case 1: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 1); + break; + + case 2: /* MinType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 2); + break; + + case 3: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 3); + break; + + case 4: /* Memory Type */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 1, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_MEMTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 1, 2); + break; + + case 5: /* Read/Write Type */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_READWRITETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 0); + break; + + case 6: /* Address Granularity */ + + Descriptor->Address32.Granularity = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->Address32.Minimum = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->Address32.Maximum = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->Address32.TranslationOffset = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->Address32.AddressLength = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address32.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 12: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address32.ResourceLength = (UINT16) + (Descriptor->Address32.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 13: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + + case 14: /* Address Range */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 3, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_MEMATTRIBUTES, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 3, 2); + break; + + case 15: /* Type */ + + RsSetFlagBits (&Descriptor->Address32.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + (UINT64) Descriptor->Address32.Minimum, + (UINT64) Descriptor->Address32.Maximum, + (UINT64) Descriptor->Address32.AddressLength, + (UINT64) Descriptor->Address32.Granularity, + Descriptor->Address32.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS32) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoDwordSpaceDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "DwordSpace" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoDwordSpaceDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS32) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address32.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS32; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS32); + Descriptor->Address32.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS32) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Type */ + + Descriptor->Address32.ResourceType = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 1: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 0, 1); + break; + + case 2: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 1); + break; + + case 3: /* MinType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 2); + break; + + case 4: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address32.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Flags), 3); + break; + + case 5: /* Type-Specific flags */ + + Descriptor->Address32.SpecificFlags = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 6: /* Address Granularity */ + + Descriptor->Address32.Granularity = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->Address32.Minimum = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->Address32.Maximum = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->Address32.TranslationOffset = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->Address32.AddressLength = + (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address32.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address32.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 12: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address32.ResourceLength = (UINT16) + (Descriptor->Address32.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 13: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, + InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + (UINT64) Descriptor->Address32.Minimum, + (UINT64) Descriptor->Address32.Maximum, + (UINT64) Descriptor->Address32.AddressLength, + (UINT64) Descriptor->Address32.Granularity, + Descriptor->Address32.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS32) + + OptionIndex + StringLength; + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype2e.c b/third_party/lib/acpica/source/compiler/aslrestype2e.c new file mode 100644 index 000000000..fc07366d4 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype2e.c @@ -0,0 +1,571 @@ +/****************************************************************************** + * + * Module Name: aslrestype2e - Large Extended address resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype2e") + +/* + * This module contains the Extended (64-bit) address space descriptors: + * + * ExtendedIO + * ExtendedMemory + * ExtendedSpace + */ + +/******************************************************************************* + * + * FUNCTION: RsDoExtendedIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "ExtendedIO" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoExtendedIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT16 StringLength = 0; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->ExtAddress64.DescriptorType = ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64; + Descriptor->ExtAddress64.ResourceType = ACPI_ADDRESS_TYPE_IO_RANGE; + Descriptor->ExtAddress64.RevisionID = AML_RESOURCE_EXTENDED_ADDRESS_REVISION; + + Descriptor->ExtAddress64.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 0, 1); + break; + + case 1: /* MinType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 2); + break; + + case 2: /* MaxType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 3); + break; + + case 3: /* DecodeType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 1); + break; + + case 4: /* Range Type */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 0, 3); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_RANGETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 0, 2); + break; + + case 5: /* Address Granularity */ + + Descriptor->ExtAddress64.Granularity = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Granularity)); + GranOp = InitializerOp; + break; + + case 6: /* Address Min */ + + Descriptor->ExtAddress64.Minimum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Minimum)); + MinOp = InitializerOp; + break; + + case 7: /* Address Max */ + + Descriptor->ExtAddress64.Maximum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Maximum)); + MaxOp = InitializerOp; + break; + + case 8: /* Translation Offset */ + + Descriptor->ExtAddress64.TranslationOffset = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.TranslationOffset)); + break; + + case 9: /* Address Length */ + + Descriptor->ExtAddress64.AddressLength = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.AddressLength)); + LengthOp = InitializerOp; + break; + + case 10: /* Type-Specific Attributes */ + + Descriptor->ExtAddress64.TypeSpecific = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TYPESPECIFICATTRIBUTES, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.TypeSpecific)); + break; + + case 11: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 12: /* Type */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 4, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 4); + break; + + case 13: /* Translation Type */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TRANSTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + Descriptor->ExtAddress64.Minimum, + Descriptor->ExtAddress64.Maximum, + Descriptor->ExtAddress64.AddressLength, + Descriptor->ExtAddress64.Granularity, + Descriptor->ExtAddress64.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoExtendedMemoryDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "ExtendedMemory" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoExtendedMemoryDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT16 StringLength = 0; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->ExtAddress64.DescriptorType = ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64; + Descriptor->ExtAddress64.ResourceType = ACPI_ADDRESS_TYPE_MEMORY_RANGE; + Descriptor->ExtAddress64.RevisionID = AML_RESOURCE_EXTENDED_ADDRESS_REVISION; + + Descriptor->ExtAddress64.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 0, 1); + break; + + case 1: /* DecodeType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 1); + break; + + case 2: /* MinType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 2); + break; + + case 3: /* MaxType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 3); + break; + + case 4: /* Memory Type */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 1, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_MEMTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 1, 2); + break; + + case 5: /* Read/Write Type */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_READWRITETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 0); + break; + + case 6: /* Address Granularity */ + + Descriptor->ExtAddress64.Granularity = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->ExtAddress64.Minimum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->ExtAddress64.Maximum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->ExtAddress64.TranslationOffset = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->ExtAddress64.AddressLength = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* Type-Specific Attributes */ + + Descriptor->ExtAddress64.TypeSpecific = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TYPESPECIFICATTRIBUTES, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.TypeSpecific)); + break; + + case 12: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + + case 13: /* Address Range */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 3, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_MEMATTRIBUTES, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 3, 2); + break; + + case 14: /* Type */ + + RsSetFlagBits (&Descriptor->ExtAddress64.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + Descriptor->ExtAddress64.Minimum, + Descriptor->ExtAddress64.Maximum, + Descriptor->ExtAddress64.AddressLength, + Descriptor->ExtAddress64.Granularity, + Descriptor->ExtAddress64.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoExtendedSpaceDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "ExtendedSpace" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoExtendedSpaceDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT16 StringLength = 0; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->ExtAddress64.DescriptorType = ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64; + Descriptor->ExtAddress64.RevisionID = AML_RESOURCE_EXTENDED_ADDRESS_REVISION; + + Descriptor->ExtAddress64.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Type */ + + Descriptor->ExtAddress64.ResourceType = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 1: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 0, 1); + break; + + case 2: /* DecodeType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 1); + break; + + case 3: /* MinType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 2); + break; + + case 4: /* MaxType */ + + RsSetFlagBits (&Descriptor->ExtAddress64.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Flags), 3); + break; + + case 5: /* Type-Specific flags */ + + Descriptor->ExtAddress64.SpecificFlags = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 6: /* Address Granularity */ + + Descriptor->ExtAddress64.Granularity = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->ExtAddress64.Minimum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->ExtAddress64.Maximum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->ExtAddress64.TranslationOffset = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->ExtAddress64.AddressLength = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* Type-Specific Attributes */ + + Descriptor->ExtAddress64.TypeSpecific = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TYPESPECIFICATTRIBUTES, + CurrentByteOffset + ASL_RESDESC_OFFSET (ExtAddress64.TypeSpecific)); + break; + + case 12: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + Descriptor->ExtAddress64.Minimum, + Descriptor->ExtAddress64.Maximum, + Descriptor->ExtAddress64.AddressLength, + Descriptor->ExtAddress64.Granularity, + Descriptor->ExtAddress64.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + + StringLength; + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype2q.c b/third_party/lib/acpica/source/compiler/aslrestype2q.c new file mode 100644 index 000000000..c8d8cabea --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype2q.c @@ -0,0 +1,716 @@ +/****************************************************************************** + * + * Module Name: aslrestype2q - Large QWord address resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype2q") + +/* + * This module contains the QWord (64-bit) address space descriptors: + * + * QWordIO + * QWordMemory + * QWordSpace + */ + +/******************************************************************************* + * + * FUNCTION: RsDoQwordIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "QwordIO" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoQwordIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS64) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address64.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS64; + Descriptor->Address64.ResourceType = ACPI_ADDRESS_TYPE_IO_RANGE; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS64); + Descriptor->Address64.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS64) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 0, 1); + break; + + case 1: /* MinType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 2); + break; + + case 2: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 3); + break; + + case 3: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 1); + break; + + case 4: /* Range Type */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 0, 3); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_RANGETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 0, 2); + break; + + case 5: /* Address Granularity */ + + Descriptor->Address64.Granularity = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Granularity)); + GranOp = InitializerOp; + break; + + case 6: /* Address Min */ + + Descriptor->Address64.Minimum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Minimum)); + MinOp = InitializerOp; + break; + + case 7: /* Address Max */ + + Descriptor->Address64.Maximum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Maximum)); + MaxOp = InitializerOp; + break; + + case 8: /* Translation Offset */ + + Descriptor->Address64.TranslationOffset = InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.TranslationOffset)); + break; + + case 9: /* Address Length */ + + Descriptor->Address64.AddressLength = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.AddressLength)); + LengthOp = InitializerOp; + break; + + case 10: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address64.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 11: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address64.ResourceLength = (UINT16) + (Descriptor->Address64.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 12: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 13: /* Type */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 4, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 4); + break; + + case 14: /* Translation Type */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TRANSTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + Descriptor->Address64.Minimum, + Descriptor->Address64.Maximum, + Descriptor->Address64.AddressLength, + Descriptor->Address64.Granularity, + Descriptor->Address64.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS64) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoQwordMemoryDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "QwordMemory" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoQwordMemoryDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS64) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address64.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS64; + Descriptor->Address64.ResourceType = ACPI_ADDRESS_TYPE_MEMORY_RANGE; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS64); + Descriptor->Address64.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS64) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 0, 1); + break; + + case 1: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 1); + break; + + case 2: /* MinType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 2); + break; + + case 3: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 3); + break; + + case 4: /* Memory Type */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 1, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_MEMTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 1, 2); + break; + + case 5: /* Read/Write Type */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 0, 1); + RsCreateBitField (InitializerOp, ACPI_RESTAG_READWRITETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 0); + break; + + case 6: /* Address Granularity */ + + Descriptor->Address64.Granularity = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->Address64.Minimum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->Address64.Maximum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->Address64.TranslationOffset = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->Address64.AddressLength = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address64.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 12: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address64.ResourceLength = (UINT16) + (Descriptor->Address64.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 13: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + + case 14: /* Address Range */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 3, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_MEMATTRIBUTES, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 3, 2); + break; + + case 15: /* Type */ + + RsSetFlagBits (&Descriptor->Address64.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + Descriptor->Address64.Minimum, + Descriptor->Address64.Maximum, + Descriptor->Address64.AddressLength, + Descriptor->Address64.Granularity, + Descriptor->Address64.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS64) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoQwordSpaceDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "QwordSpace" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoQwordSpaceDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS64) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address64.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS64; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS64); + Descriptor->Address64.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS64) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Type */ + + Descriptor->Address64.ResourceType = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 1: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 0, 1); + break; + + case 2: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 1); + break; + + case 3: /* MinType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 2); + break; + + case 4: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address64.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Flags), 3); + break; + + case 5: /* Type-Specific flags */ + + Descriptor->Address64.SpecificFlags = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 6: /* Address Granularity */ + + Descriptor->Address64.Granularity = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->Address64.Minimum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->Address64.Maximum = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->Address64.TranslationOffset = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->Address64.AddressLength = InitializerOp->Asl.Value.Integer; + RsCreateQwordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address64.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address64.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 12: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address64.ResourceLength = (UINT16) + (Descriptor->Address64.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 13: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + Descriptor->Address64.Minimum, + Descriptor->Address64.Maximum, + Descriptor->Address64.AddressLength, + Descriptor->Address64.Granularity, + Descriptor->Address64.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS64) + + OptionIndex + StringLength; + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype2s.c b/third_party/lib/acpica/source/compiler/aslrestype2s.c new file mode 100644 index 000000000..dcf0d7b23 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype2s.c @@ -0,0 +1,1217 @@ +/****************************************************************************** + * + * Module Name: aslrestype2s - Serial Large resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype2s") + + +static UINT16 +RsGetBufferDataLength ( + ACPI_PARSE_OBJECT *InitializerOp); + +static UINT16 +RsGetInterruptDataLength ( + ACPI_PARSE_OBJECT *InitializerOp); + +static BOOLEAN +RsGetVendorData ( + ACPI_PARSE_OBJECT *InitializerOp, + UINT8 *VendorData, + ACPI_SIZE DescriptorOffset); + +/* + * This module contains descriptors for serial buses and GPIO: + * + * GpioInt + * GpioIo + * I2cSerialBus + * SpiSerialBus + * UartSerialBus + */ + + +/******************************************************************************* + * + * FUNCTION: RsGetBufferDataLength + * + * PARAMETERS: InitializerOp - Current parse op, start of the resource + * descriptor + * + * RETURN: Length of the data buffer + * + * DESCRIPTION: Get the length of a RawDataBuffer, used for vendor data. + * + ******************************************************************************/ + +static UINT16 +RsGetBufferDataLength ( + ACPI_PARSE_OBJECT *InitializerOp) +{ + UINT16 ExtraDataSize = 0; + ACPI_PARSE_OBJECT *DataList; + + + /* Find the byte-initializer list */ + + while (InitializerOp) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DATABUFFER) + { + /* First child is the optional length (ignore it here) */ + + DataList = InitializerOp->Asl.Child; + DataList = ASL_GET_PEER_NODE (DataList); + + /* Count the data items (each one is a byte of data) */ + + while (DataList) + { + ExtraDataSize++; + DataList = ASL_GET_PEER_NODE (DataList); + } + + return (ExtraDataSize); + } + + InitializerOp = ASL_GET_PEER_NODE (InitializerOp); + } + + return (ExtraDataSize); +} + + +/******************************************************************************* + * + * FUNCTION: RsGetInterruptDataLength + * + * PARAMETERS: InitializerOp - Current parse op, start of the resource + * descriptor + * + * RETURN: Length of the interrupt data list + * + * DESCRIPTION: Get the length of a list of interrupt DWORDs for the GPIO + * descriptors. + * + ******************************************************************************/ + +static UINT16 +RsGetInterruptDataLength ( + ACPI_PARSE_OBJECT *InitializerOp) +{ + UINT16 InterruptLength; + UINT32 i; + + + /* Count the interrupt numbers */ + + InterruptLength = 0; + for (i = 0; InitializerOp; i++) + { + InitializerOp = ASL_GET_PEER_NODE (InitializerOp); + + /* Interrupt list starts at offset 10 (Gpio descriptors) */ + + if (i >= 10) + { + InterruptLength += 2; + } + } + + return (InterruptLength); +} + + +/******************************************************************************* + * + * FUNCTION: RsGetVendorData + * + * PARAMETERS: InitializerOp - Current parse op, start of the resource + * descriptor. + * VendorData - Where the vendor data is returned + * DescriptorOffset - Where vendor data begins in descriptor + * + * RETURN: TRUE if valid vendor data was returned, FALSE otherwise. + * + * DESCRIPTION: Extract the vendor data and construct a vendor data buffer. + * + ******************************************************************************/ + +static BOOLEAN +RsGetVendorData ( + ACPI_PARSE_OBJECT *InitializerOp, + UINT8 *VendorData, + ACPI_SIZE DescriptorOffset) +{ + ACPI_PARSE_OBJECT *BufferOp; + UINT32 SpecifiedLength = ACPI_UINT32_MAX; + UINT16 ActualLength = 0; + + + /* Vendor Data field is always optional */ + + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + return (FALSE); + } + + BufferOp = InitializerOp->Asl.Child; + if (!BufferOp) + { + AslError (ASL_ERROR, ASL_MSG_SYNTAX, InitializerOp, ""); + return (FALSE); + } + + /* First child is the optional buffer length (WORD) */ + + if (BufferOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + SpecifiedLength = (UINT16) BufferOp->Asl.Value.Integer; + } + + /* Insert field tag _VEN */ + + RsCreateByteField (InitializerOp, ACPI_RESTAG_VENDORDATA, + (UINT16) DescriptorOffset); + + /* Walk the list of buffer initializers (each is one byte) */ + + BufferOp = RsCompleteNodeAndGetNext (BufferOp); + if (BufferOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + while (BufferOp) + { + *VendorData = (UINT8) BufferOp->Asl.Value.Integer; + VendorData++; + ActualLength++; + BufferOp = RsCompleteNodeAndGetNext (BufferOp); + } + } + + /* Length validation. Buffer cannot be of zero length */ + + if ((SpecifiedLength == 0) || + ((SpecifiedLength == ACPI_UINT32_MAX) && (ActualLength == 0))) + { + AslError (ASL_ERROR, ASL_MSG_BUFFER_LENGTH, InitializerOp, NULL); + return (FALSE); + } + + if (SpecifiedLength != ACPI_UINT32_MAX) + { + /* ActualLength > SpecifiedLength -> error */ + + if (ActualLength > SpecifiedLength) + { + AslError (ASL_ERROR, ASL_MSG_LIST_LENGTH_LONG, InitializerOp, NULL); + return (FALSE); + } + + /* ActualLength < SpecifiedLength -> remark */ + + else if (ActualLength < SpecifiedLength) + { + AslError (ASL_REMARK, ASL_MSG_LIST_LENGTH_SHORT, InitializerOp, NULL); + return (FALSE); + } + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoGpioIntDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "GpioInt" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoGpioIntDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + char *ResourceSource = NULL; + UINT8 *VendorData = NULL; + UINT16 *InterruptList = NULL; + UINT16 *PinList = NULL; + UINT16 ResSourceLength; + UINT16 VendorLength; + UINT16 InterruptLength; + UINT16 DescriptorSize; + UINT32 CurrentByteOffset; + UINT32 PinCount = 0; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + + /* + * Calculate lengths for fields that have variable length: + * 1) Resource Source string + * 2) Vendor Data buffer + * 3) PIN (interrupt) list + */ + ResSourceLength = RsGetStringDataLength (InitializerOp); + VendorLength = RsGetBufferDataLength (InitializerOp); + InterruptLength = RsGetInterruptDataLength (InitializerOp); + + DescriptorSize = ACPI_AML_SIZE_LARGE (AML_RESOURCE_GPIO) + + ResSourceLength + VendorLength + InterruptLength; + + /* Allocate the local resource node and initialize */ + + Rnode = RsAllocateResourceNode (DescriptorSize + + sizeof (AML_RESOURCE_LARGE_HEADER)); + + Descriptor = Rnode->Buffer; + Descriptor->Gpio.ResourceLength = DescriptorSize; + Descriptor->Gpio.DescriptorType = ACPI_RESOURCE_NAME_GPIO; + Descriptor->Gpio.RevisionId = AML_RESOURCE_GPIO_REVISION; + Descriptor->Gpio.ConnectionType = AML_RESOURCE_GPIO_TYPE_INT; + + /* Build pointers to optional areas */ + + InterruptList = ACPI_ADD_PTR (UINT16, Descriptor, + sizeof (AML_RESOURCE_GPIO)); + PinList = InterruptList; + ResourceSource = ACPI_ADD_PTR (char, InterruptList, InterruptLength); + VendorData = ACPI_ADD_PTR (UINT8, ResourceSource, ResSourceLength); + + /* Setup offsets within the descriptor */ + + Descriptor->Gpio.PinTableOffset = (UINT16) + ACPI_PTR_DIFF (InterruptList, Descriptor); + + Descriptor->Gpio.ResSourceOffset = (UINT16) + ACPI_PTR_DIFF (ResourceSource, Descriptor); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%16s - Actual: %.2X, Base: %.2X, ResLen: " + "%.2X, VendLen: %.2X, IntLen: %.2X\n", + "GpioInt", Descriptor->Gpio.ResourceLength, + (UINT16) sizeof (AML_RESOURCE_GPIO), + ResSourceLength, VendorLength, InterruptLength); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Interrupt Mode - edge/level [Flag] (_MOD) */ + + RsSetFlagBits16 (&Descriptor->Gpio.IntFlags, InitializerOp, 0, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.IntFlags), 0); + break; + + case 1: /* Interrupt Polarity - Active high/low [Flags] (_POL) */ + + RsSetFlagBits16 (&Descriptor->Gpio.IntFlags, InitializerOp, 1, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_POLARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.IntFlags), 1, 2); + break; + + case 2: /* Share Type - Default: exclusive (0) [Flags] (_SHR) */ + + RsSetFlagBits16 (&Descriptor->Gpio.IntFlags, InitializerOp, 3, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_INTERRUPTSHARE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.IntFlags), 3, 2); + break; + + case 3: /* Pin Config [BYTE] (_PPI) */ + + Descriptor->Gpio.PinConfig = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_PINCONFIG, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.PinConfig)); + break; + + case 4: /* Debounce Timeout [WORD] (_DBT) */ + + Descriptor->Gpio.DebounceTimeout = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_DEBOUNCETIME, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.DebounceTimeout)); + break; + + case 5: /* ResSource [Optional Field - STRING] */ + + if (ResSourceLength) + { + /* Copy string to the descriptor */ + + strcpy (ResourceSource, + InitializerOp->Asl.Value.String); + } + break; + + case 6: /* Resource Index */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + Descriptor->Gpio.ResSourceIndex = + (UINT8) InitializerOp->Asl.Value.Integer; + } + break; + + case 7: /* Resource Usage (consumer/producer) */ + + RsSetFlagBits16 (&Descriptor->Gpio.Flags, InitializerOp, 0, 1); + break; + + case 8: /* Resource Tag (Descriptor Name) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 9: /* Vendor Data (Optional - Buffer of BYTEs) (_VEN) */ + + /* + * Always set the VendorOffset even if there is no Vendor Data. + * This field is required in order to calculate the length + * of the ResourceSource at runtime. + */ + Descriptor->Gpio.VendorOffset = (UINT16) + ACPI_PTR_DIFF (VendorData, Descriptor); + + if (RsGetVendorData (InitializerOp, VendorData, + (CurrentByteOffset + Descriptor->Gpio.VendorOffset))) + { + Descriptor->Gpio.VendorLength = VendorLength; + } + break; + + default: + /* + * PINs come through here, repeatedly. Each PIN must be a WORD. + * NOTE: there is no "length" field for this, so from ACPI spec: + * The number of pins in the table can be calculated from: + * PinCount = (Resource Source Name Offset - Pin Table Offset) / 2 + * (implies resource source must immediately follow the pin list.) + * Name: _PIN + */ + *InterruptList = (UINT16) InitializerOp->Asl.Value.Integer; + InterruptList++; + PinCount++; + + /* Case 10: First interrupt number in list */ + + if (i == 10) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + /* Must be at least one interrupt */ + + AslError (ASL_ERROR, ASL_MSG_EX_INTERRUPT_LIST_MIN, + InitializerOp, NULL); + } + + /* Check now for duplicates in list */ + + RsCheckListForDuplicates (InitializerOp); + + /* Create a named field at the start of the list */ + + RsCreateWordField (InitializerOp, ACPI_RESTAG_PIN, + CurrentByteOffset + Descriptor->Gpio.PinTableOffset); + } + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + MpSaveGpioInfo (Info->MappingOp, Descriptor, + PinCount, PinList, ResourceSource); + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoGpioIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "GpioIo" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoGpioIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + char *ResourceSource = NULL; + UINT8 *VendorData = NULL; + UINT16 *InterruptList = NULL; + UINT16 *PinList = NULL; + UINT16 ResSourceLength; + UINT16 VendorLength; + UINT16 InterruptLength; + UINT16 DescriptorSize; + UINT32 CurrentByteOffset; + UINT32 PinCount = 0; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + + /* + * Calculate lengths for fields that have variable length: + * 1) Resource Source string + * 2) Vendor Data buffer + * 3) PIN (interrupt) list + */ + ResSourceLength = RsGetStringDataLength (InitializerOp); + VendorLength = RsGetBufferDataLength (InitializerOp); + InterruptLength = RsGetInterruptDataLength (InitializerOp); + PinList = InterruptList; + + DescriptorSize = ACPI_AML_SIZE_LARGE (AML_RESOURCE_GPIO) + + ResSourceLength + VendorLength + InterruptLength; + + /* Allocate the local resource node and initialize */ + + Rnode = RsAllocateResourceNode (DescriptorSize + + sizeof (AML_RESOURCE_LARGE_HEADER)); + + Descriptor = Rnode->Buffer; + Descriptor->Gpio.ResourceLength = DescriptorSize; + Descriptor->Gpio.DescriptorType = ACPI_RESOURCE_NAME_GPIO; + Descriptor->Gpio.RevisionId = AML_RESOURCE_GPIO_REVISION; + Descriptor->Gpio.ConnectionType = AML_RESOURCE_GPIO_TYPE_IO; + + /* Build pointers to optional areas */ + + InterruptList = ACPI_ADD_PTR (UINT16, Descriptor, sizeof (AML_RESOURCE_GPIO)); + PinList = InterruptList; + ResourceSource = ACPI_ADD_PTR (char, InterruptList, InterruptLength); + VendorData = ACPI_ADD_PTR (UINT8, ResourceSource, ResSourceLength); + + /* Setup offsets within the descriptor */ + + Descriptor->Gpio.PinTableOffset = (UINT16) + ACPI_PTR_DIFF (InterruptList, Descriptor); + + Descriptor->Gpio.ResSourceOffset = (UINT16) + ACPI_PTR_DIFF (ResourceSource, Descriptor); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%16s - Actual: %.2X, Base: %.2X, ResLen: " + "%.2X, VendLen: %.2X, IntLen: %.2X\n", + "GpioIo", Descriptor->Gpio.ResourceLength, + (UINT16) sizeof (AML_RESOURCE_GPIO), + ResSourceLength, VendorLength, InterruptLength); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Share Type [Flags] (_SHR) */ + + RsSetFlagBits16 (&Descriptor->Gpio.IntFlags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_INTERRUPTSHARE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.IntFlags), 3); + break; + + case 1: /* Pin Config [BYTE] (_PPI) */ + + Descriptor->Gpio.PinConfig = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_PINCONFIG, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.PinConfig)); + break; + + case 2: /* Debounce Timeout [WORD] (_DBT) */ + + Descriptor->Gpio.DebounceTimeout = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_DEBOUNCETIME, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.DebounceTimeout)); + break; + + case 3: /* Drive Strength [WORD] (_DRS) */ + + Descriptor->Gpio.DriveStrength = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_DRIVESTRENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.DriveStrength)); + break; + + case 4: /* I/O Restriction [Flag] (_IOR) */ + + RsSetFlagBits16 (&Descriptor->Gpio.IntFlags, InitializerOp, 0, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_IORESTRICTION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Gpio.IntFlags), 0, 2); + break; + + case 5: /* ResSource [Optional Field - STRING] */ + + if (ResSourceLength) + { + /* Copy string to the descriptor */ + + strcpy (ResourceSource, + InitializerOp->Asl.Value.String); + } + break; + + case 6: /* Resource Index */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + Descriptor->Gpio.ResSourceIndex = (UINT8) InitializerOp->Asl.Value.Integer; + } + break; + + case 7: /* Resource Usage (consumer/producer) */ + + RsSetFlagBits16 (&Descriptor->Gpio.Flags, InitializerOp, 0, 1); + break; + + case 8: /* Resource Tag (Descriptor Name) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 9: /* Vendor Data (Optional - Buffer of BYTEs) (_VEN) */ + /* + * Always set the VendorOffset even if there is no Vendor Data. + * This field is required in order to calculate the length + * of the ResourceSource at runtime. + */ + Descriptor->Gpio.VendorOffset = (UINT16) + ACPI_PTR_DIFF (VendorData, Descriptor); + + if (RsGetVendorData (InitializerOp, VendorData, + (CurrentByteOffset + Descriptor->Gpio.VendorOffset))) + { + Descriptor->Gpio.VendorLength = VendorLength; + } + break; + + default: + /* + * PINs come through here, repeatedly. Each PIN must be a WORD. + * NOTE: there is no "length" field for this, so from ACPI spec: + * The number of pins in the table can be calculated from: + * PinCount = (Resource Source Name Offset - Pin Table Offset) / 2 + * (implies resource source must immediately follow the pin list.) + * Name: _PIN + */ + *InterruptList = (UINT16) InitializerOp->Asl.Value.Integer; + InterruptList++; + PinCount++; + + /* Case 10: First interrupt number in list */ + + if (i == 10) + { + if (InitializerOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) + { + /* Must be at least one interrupt */ + + AslError (ASL_ERROR, ASL_MSG_EX_INTERRUPT_LIST_MIN, + InitializerOp, NULL); + } + + /* Check now for duplicates in list */ + + RsCheckListForDuplicates (InitializerOp); + + /* Create a named field at the start of the list */ + + RsCreateWordField (InitializerOp, ACPI_RESTAG_PIN, + CurrentByteOffset + Descriptor->Gpio.PinTableOffset); + } + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + MpSaveGpioInfo (Info->MappingOp, Descriptor, + PinCount, PinList, ResourceSource); + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoI2cSerialBusDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "I2cSerialBus" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoI2cSerialBusDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + char *ResourceSource = NULL; + UINT8 *VendorData = NULL; + UINT16 ResSourceLength; + UINT16 VendorLength; + UINT16 DescriptorSize; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + + /* + * Calculate lengths for fields that have variable length: + * 1) Resource Source string + * 2) Vendor Data buffer + */ + ResSourceLength = RsGetStringDataLength (InitializerOp); + VendorLength = RsGetBufferDataLength (InitializerOp); + + DescriptorSize = ACPI_AML_SIZE_LARGE (AML_RESOURCE_I2C_SERIALBUS) + + ResSourceLength + VendorLength; + + /* Allocate the local resource node and initialize */ + + Rnode = RsAllocateResourceNode (DescriptorSize + + sizeof (AML_RESOURCE_LARGE_HEADER)); + + Descriptor = Rnode->Buffer; + Descriptor->I2cSerialBus.ResourceLength = DescriptorSize; + Descriptor->I2cSerialBus.DescriptorType = ACPI_RESOURCE_NAME_SERIAL_BUS; + Descriptor->I2cSerialBus.RevisionId = AML_RESOURCE_I2C_REVISION; + Descriptor->I2cSerialBus.TypeRevisionId = AML_RESOURCE_I2C_TYPE_REVISION; + Descriptor->I2cSerialBus.Type = AML_RESOURCE_I2C_SERIALBUSTYPE; + Descriptor->I2cSerialBus.TypeDataLength = AML_RESOURCE_I2C_MIN_DATA_LEN + VendorLength; + + /* Build pointers to optional areas */ + + VendorData = ACPI_ADD_PTR (UINT8, Descriptor, sizeof (AML_RESOURCE_I2C_SERIALBUS)); + ResourceSource = ACPI_ADD_PTR (char, VendorData, VendorLength); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%16s - Actual: %.2X, Base: %.2X, ResLen: " + "%.2X, VendLen: %.2X, TypLen: %.2X\n", + "I2cSerialBus", Descriptor->I2cSerialBus.ResourceLength, + (UINT16) sizeof (AML_RESOURCE_I2C_SERIALBUS), ResSourceLength, + VendorLength, Descriptor->I2cSerialBus.TypeDataLength); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Slave Address [WORD] (_ADR) */ + + Descriptor->I2cSerialBus.SlaveAddress = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_ADDRESS, + CurrentByteOffset + ASL_RESDESC_OFFSET (I2cSerialBus.SlaveAddress)); + break; + + case 1: /* Slave Mode [Flag] (_SLV) */ + + RsSetFlagBits (&Descriptor->I2cSerialBus.Flags, InitializerOp, 0, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_SLAVEMODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (I2cSerialBus.Flags), 0); + break; + + case 2: /* Connection Speed [DWORD] (_SPE) */ + + Descriptor->I2cSerialBus.ConnectionSpeed = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_SPEED, + CurrentByteOffset + ASL_RESDESC_OFFSET (I2cSerialBus.ConnectionSpeed)); + break; + + case 3: /* Addressing Mode [Flag] (_MOD) */ + + RsSetFlagBits16 (&Descriptor->I2cSerialBus.TypeSpecificFlags, InitializerOp, 0, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (I2cSerialBus.TypeSpecificFlags), 0); + break; + + case 4: /* ResSource [Optional Field - STRING] */ + + if (ResSourceLength) + { + /* Copy string to the descriptor */ + + strcpy (ResourceSource, + InitializerOp->Asl.Value.String); + } + break; + + case 5: /* Resource Index */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + Descriptor->I2cSerialBus.ResSourceIndex = + (UINT8) InitializerOp->Asl.Value.Integer; + } + break; + + case 6: /* Resource Usage (consumer/producer) */ + + RsSetFlagBits (&Descriptor->I2cSerialBus.Flags, InitializerOp, 1, 1); + break; + + case 7: /* Resource Tag (Descriptor Name) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 8: /* Vendor Data (Optional - Buffer of BYTEs) (_VEN) */ + + RsGetVendorData (InitializerOp, VendorData, + CurrentByteOffset + sizeof (AML_RESOURCE_I2C_SERIALBUS)); + break; + + default: /* Ignore any extra nodes */ + + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + MpSaveSerialInfo (Info->MappingOp, Descriptor, ResourceSource); + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoSpiSerialBusDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "SPI Serial Bus" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoSpiSerialBusDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + char *ResourceSource = NULL; + UINT8 *VendorData = NULL; + UINT16 ResSourceLength; + UINT16 VendorLength; + UINT16 DescriptorSize; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + + /* + * Calculate lengths for fields that have variable length: + * 1) Resource Source string + * 2) Vendor Data buffer + */ + ResSourceLength = RsGetStringDataLength (InitializerOp); + VendorLength = RsGetBufferDataLength (InitializerOp); + + DescriptorSize = ACPI_AML_SIZE_LARGE (AML_RESOURCE_SPI_SERIALBUS) + + ResSourceLength + VendorLength; + + /* Allocate the local resource node and initialize */ + + Rnode = RsAllocateResourceNode (DescriptorSize + + sizeof (AML_RESOURCE_LARGE_HEADER)); + + Descriptor = Rnode->Buffer; + Descriptor->SpiSerialBus.ResourceLength = DescriptorSize; + Descriptor->SpiSerialBus.DescriptorType = ACPI_RESOURCE_NAME_SERIAL_BUS; + Descriptor->SpiSerialBus.RevisionId = AML_RESOURCE_SPI_REVISION; + Descriptor->SpiSerialBus.TypeRevisionId = AML_RESOURCE_SPI_TYPE_REVISION; + Descriptor->SpiSerialBus.Type = AML_RESOURCE_SPI_SERIALBUSTYPE; + Descriptor->SpiSerialBus.TypeDataLength = AML_RESOURCE_SPI_MIN_DATA_LEN + VendorLength; + + /* Build pointers to optional areas */ + + VendorData = ACPI_ADD_PTR (UINT8, Descriptor, + sizeof (AML_RESOURCE_SPI_SERIALBUS)); + ResourceSource = ACPI_ADD_PTR (char, VendorData, VendorLength); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%16s - Actual: %.2X, Base: %.2X, ResLen: " + "%.2X, VendLen: %.2X, TypLen: %.2X\n", + "SpiSerialBus", Descriptor->SpiSerialBus.ResourceLength, + (UINT16) sizeof (AML_RESOURCE_SPI_SERIALBUS), ResSourceLength, + VendorLength, Descriptor->SpiSerialBus.TypeDataLength); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Device Selection [WORD] (_ADR) */ + + Descriptor->SpiSerialBus.DeviceSelection = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_ADDRESS, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.DeviceSelection)); + break; + + case 1: /* Device Polarity [Flag] (_DPL) */ + + RsSetFlagBits16 (&Descriptor->SpiSerialBus.TypeSpecificFlags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DEVICEPOLARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.TypeSpecificFlags), 1); + break; + + case 2: /* Wire Mode [Flag] (_MOD) */ + + RsSetFlagBits16 (&Descriptor->SpiSerialBus.TypeSpecificFlags, InitializerOp, 0, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.TypeSpecificFlags), 0); + break; + + case 3: /* Device Bit Length [BYTE] (_LEN) */ + + Descriptor->SpiSerialBus.DataBitLength = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.DataBitLength)); + break; + + case 4: /* Slave Mode [Flag] (_SLV) */ + + RsSetFlagBits (&Descriptor->SpiSerialBus.Flags, InitializerOp, 0, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_SLAVEMODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.Flags), 0); + break; + + case 5: /* Connection Speed [DWORD] (_SPE) */ + + Descriptor->SpiSerialBus.ConnectionSpeed = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_SPEED, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.ConnectionSpeed)); + break; + + case 6: /* Clock Polarity [BYTE] (_POL) */ + + Descriptor->SpiSerialBus.ClockPolarity = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_POLARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.ClockPolarity)); + break; + + case 7: /* Clock Phase [BYTE] (_PHA) */ + + Descriptor->SpiSerialBus.ClockPhase = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_PHASE, + CurrentByteOffset + ASL_RESDESC_OFFSET (SpiSerialBus.ClockPhase)); + break; + + case 8: /* ResSource [Optional Field - STRING] */ + + if (ResSourceLength) + { + /* Copy string to the descriptor */ + + strcpy (ResourceSource, + InitializerOp->Asl.Value.String); + } + break; + + case 9: /* Resource Index */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + Descriptor->SpiSerialBus.ResSourceIndex = + (UINT8) InitializerOp->Asl.Value.Integer; + } + break; + + case 10: /* Resource Usage (consumer/producer) */ + + RsSetFlagBits (&Descriptor->SpiSerialBus.Flags, InitializerOp, 1, 1); + break; + + case 11: /* Resource Tag (Descriptor Name) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 12: /* Vendor Data (Optional - Buffer of BYTEs) (_VEN) */ + + RsGetVendorData (InitializerOp, VendorData, + CurrentByteOffset + sizeof (AML_RESOURCE_SPI_SERIALBUS)); + break; + + default: /* Ignore any extra nodes */ + + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + MpSaveSerialInfo (Info->MappingOp, Descriptor, ResourceSource); + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoUartSerialBusDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "UART Serial Bus" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoUartSerialBusDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ASL_RESOURCE_NODE *Rnode; + char *ResourceSource = NULL; + UINT8 *VendorData = NULL; + UINT16 ResSourceLength; + UINT16 VendorLength; + UINT16 DescriptorSize; + UINT32 CurrentByteOffset; + UINT32 i; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + CurrentByteOffset = Info->CurrentByteOffset; + + /* + * Calculate lengths for fields that have variable length: + * 1) Resource Source string + * 2) Vendor Data buffer + */ + ResSourceLength = RsGetStringDataLength (InitializerOp); + VendorLength = RsGetBufferDataLength (InitializerOp); + + DescriptorSize = ACPI_AML_SIZE_LARGE (AML_RESOURCE_UART_SERIALBUS) + + ResSourceLength + VendorLength; + + /* Allocate the local resource node and initialize */ + + Rnode = RsAllocateResourceNode (DescriptorSize + + sizeof (AML_RESOURCE_LARGE_HEADER)); + + Descriptor = Rnode->Buffer; + Descriptor->UartSerialBus.ResourceLength = DescriptorSize; + Descriptor->UartSerialBus.DescriptorType = ACPI_RESOURCE_NAME_SERIAL_BUS; + Descriptor->UartSerialBus.RevisionId = AML_RESOURCE_UART_REVISION; + Descriptor->UartSerialBus.TypeRevisionId = AML_RESOURCE_UART_TYPE_REVISION; + Descriptor->UartSerialBus.Type = AML_RESOURCE_UART_SERIALBUSTYPE; + Descriptor->UartSerialBus.TypeDataLength = AML_RESOURCE_UART_MIN_DATA_LEN + VendorLength; + + /* Build pointers to optional areas */ + + VendorData = ACPI_ADD_PTR (UINT8, Descriptor, sizeof (AML_RESOURCE_UART_SERIALBUS)); + ResourceSource = ACPI_ADD_PTR (char, VendorData, VendorLength); + + DbgPrint (ASL_DEBUG_OUTPUT, + "%16s - Actual: %.2X, Base: %.2X, ResLen: " + "%.2X, VendLen: %.2X, TypLen: %.2X\n", + "UartSerialBus", Descriptor->UartSerialBus.ResourceLength, + (UINT16) sizeof (AML_RESOURCE_UART_SERIALBUS), ResSourceLength, + VendorLength, Descriptor->UartSerialBus.TypeDataLength); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Connection Speed (Baud Rate) [DWORD] (_SPE) */ + + Descriptor->UartSerialBus.DefaultBaudRate = (UINT32) InitializerOp->Asl.Value.Integer; + RsCreateDwordField (InitializerOp, ACPI_RESTAG_SPEED, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.DefaultBaudRate)); + break; + + case 1: /* Bits Per Byte [Flags] (_LEN) */ + + RsSetFlagBits16 (&Descriptor->UartSerialBus.TypeSpecificFlags, InitializerOp, 4, 3); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.TypeSpecificFlags), 4, 3); + break; + + case 2: /* Stop Bits [Flags] (_STB) */ + + RsSetFlagBits16 (&Descriptor->UartSerialBus.TypeSpecificFlags, InitializerOp, 2, 1); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_STOPBITS, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.TypeSpecificFlags), 2, 2); + break; + + case 3: /* Lines In Use [BYTE] (_LIN) */ + + Descriptor->UartSerialBus.LinesEnabled = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_LINE, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.LinesEnabled)); + break; + + case 4: /* Endianness [Flag] (_END) */ + + RsSetFlagBits16 (&Descriptor->UartSerialBus.TypeSpecificFlags, InitializerOp, 7, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_ENDIANNESS, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.TypeSpecificFlags), 7); + break; + + case 5: /* Parity [BYTE] (_PAR) */ + + Descriptor->UartSerialBus.Parity = (UINT8) InitializerOp->Asl.Value.Integer; + RsCreateByteField (InitializerOp, ACPI_RESTAG_PARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.Parity)); + break; + + case 6: /* Flow Control [Flags] (_FLC) */ + + RsSetFlagBits16 (&Descriptor->UartSerialBus.TypeSpecificFlags, InitializerOp, 0, 0); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_FLOWCONTROL, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.TypeSpecificFlags), 0, 2); + break; + + case 7: /* Rx Buffer Size [WORD] (_RXL) */ + + Descriptor->UartSerialBus.RxFifoSize = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_LENGTH_RX, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.RxFifoSize)); + break; + + case 8: /* Tx Buffer Size [WORD] (_TXL) */ + + Descriptor->UartSerialBus.TxFifoSize = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_LENGTH_TX, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.TxFifoSize)); + break; + + case 9: /* ResSource [Optional Field - STRING] */ + + if (ResSourceLength) + { + /* Copy string to the descriptor */ + + strcpy (ResourceSource, + InitializerOp->Asl.Value.String); + } + break; + + case 10: /* Resource Index */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + Descriptor->UartSerialBus.ResSourceIndex = + (UINT8) InitializerOp->Asl.Value.Integer; + } + break; + + case 11: /* Resource Usage (consumer/producer) */ + + RsSetFlagBits (&Descriptor->UartSerialBus.Flags, InitializerOp, 1, 1); + + /* + * Slave Mode [Flag] (_SLV) + * + * Note: There is no SlaveMode argument to the UartSerialBus macro, but + * we add this name anyway to allow the flag to be set by ASL in the + * rare case where there is a slave mode associated with the UART. + */ + RsCreateBitField (InitializerOp, ACPI_RESTAG_SLAVEMODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (UartSerialBus.Flags), 0); + break; + + case 12: /* Resource Tag (Descriptor Name) */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 13: /* Vendor Data (Optional - Buffer of BYTEs) (_VEN) */ + + RsGetVendorData (InitializerOp, VendorData, + CurrentByteOffset + sizeof (AML_RESOURCE_UART_SERIALBUS)); + break; + + default: /* Ignore any extra nodes */ + + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + MpSaveSerialInfo (Info->MappingOp, Descriptor, ResourceSource); + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrestype2w.c b/third_party/lib/acpica/source/compiler/aslrestype2w.c new file mode 100644 index 000000000..0b88c70ac --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrestype2w.c @@ -0,0 +1,697 @@ +/****************************************************************************** + * + * Module Name: aslrestype2w - Large Word address resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslrestype2w") + +/* + * This module contains the Word (16-bit) address space descriptors: + * + * WordIO + * WordMemory + * WordSpace + */ + +/******************************************************************************* + * + * FUNCTION: RsDoWordIoDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "WordIO" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoWordIoDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS16) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address16.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS16; + Descriptor->Address16.ResourceType = ACPI_ADDRESS_TYPE_IO_RANGE; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS16); + Descriptor->Address16.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS16) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 0, 1); + break; + + case 1: /* MinType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 2); + break; + + case 2: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 3); + break; + + case 3: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 1); + break; + + case 4: /* Range Type */ + + RsSetFlagBits (&Descriptor->Address16.SpecificFlags, InitializerOp, 0, 3); + RsCreateMultiBitField (InitializerOp, ACPI_RESTAG_RANGETYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.SpecificFlags), 0, 2); + break; + + case 5: /* Address Granularity */ + + Descriptor->Address16.Granularity = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Granularity)); + GranOp = InitializerOp; + break; + + case 6: /* Address Min */ + + Descriptor->Address16.Minimum = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Minimum)); + MinOp = InitializerOp; + break; + + case 7: /* Address Max */ + + Descriptor->Address16.Maximum = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Maximum)); + MaxOp = InitializerOp; + break; + + case 8: /* Translation Offset */ + + Descriptor->Address16.TranslationOffset = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.TranslationOffset)); + break; + + case 9: /* Address Length */ + + Descriptor->Address16.AddressLength = (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.AddressLength)); + LengthOp = InitializerOp; + break; + + case 10: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address16.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 11: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address16.ResourceLength = (UINT16) + (Descriptor->Address16.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 12: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + case 13: /* Type */ + + RsSetFlagBits (&Descriptor->Address16.SpecificFlags, InitializerOp, 4, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.SpecificFlags), 4); + break; + + case 14: /* Translation Type */ + + RsSetFlagBits (&Descriptor->Address16.SpecificFlags, InitializerOp, 5, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_TRANSTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.SpecificFlags), 5); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + (UINT64) Descriptor->Address16.Minimum, + (UINT64) Descriptor->Address16.Maximum, + (UINT64) Descriptor->Address16.AddressLength, + (UINT64) Descriptor->Address16.Granularity, + Descriptor->Address16.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS16) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoWordBusNumberDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "WordBusNumber" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoWordBusNumberDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS16) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address16.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS16; + Descriptor->Address16.ResourceType = ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS16); + Descriptor->Address16.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS16) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 0, 1); + break; + + case 1: /* MinType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 2); + break; + + case 2: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 3); + break; + + case 3: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 1); + break; + + case 4: /* Address Granularity */ + + Descriptor->Address16.Granularity = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Granularity)); + GranOp = InitializerOp; + break; + + case 5: /* Min Address */ + + Descriptor->Address16.Minimum = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Minimum)); + MinOp = InitializerOp; + break; + + case 6: /* Max Address */ + + Descriptor->Address16.Maximum = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Maximum)); + MaxOp = InitializerOp; + break; + + case 7: /* Translation Offset */ + + Descriptor->Address16.TranslationOffset = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.TranslationOffset)); + break; + + case 8: /* Address Length */ + + Descriptor->Address16.AddressLength = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.AddressLength)); + LengthOp = InitializerOp; + break; + + case 9: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address16.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 10: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address16.ResourceLength = (UINT16) + (Descriptor->Address16.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 11: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + (UINT64) Descriptor->Address16.Minimum, + (UINT64) Descriptor->Address16.Maximum, + (UINT64) Descriptor->Address16.AddressLength, + (UINT64) Descriptor->Address16.Granularity, + Descriptor->Address16.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS16) + + OptionIndex + StringLength; + return (Rnode); +} + + +/******************************************************************************* + * + * FUNCTION: RsDoWordSpaceDescriptor + * + * PARAMETERS: Info - Parse Op and resource template offset + * + * RETURN: Completed resource node + * + * DESCRIPTION: Construct a long "WordSpace" descriptor + * + ******************************************************************************/ + +ASL_RESOURCE_NODE * +RsDoWordSpaceDescriptor ( + ASL_RESOURCE_INFO *Info) +{ + AML_RESOURCE *Descriptor; + ACPI_PARSE_OBJECT *InitializerOp; + ACPI_PARSE_OBJECT *MinOp = NULL; + ACPI_PARSE_OBJECT *MaxOp = NULL; + ACPI_PARSE_OBJECT *LengthOp = NULL; + ACPI_PARSE_OBJECT *GranOp = NULL; + ASL_RESOURCE_NODE *Rnode; + UINT8 *OptionalFields; + UINT16 StringLength = 0; + UINT32 OptionIndex = 0; + UINT32 CurrentByteOffset; + UINT32 i; + BOOLEAN ResSourceIndex = FALSE; + + + InitializerOp = Info->DescriptorTypeOp->Asl.Child; + StringLength = RsGetStringDataLength (InitializerOp); + CurrentByteOffset = Info->CurrentByteOffset; + + Rnode = RsAllocateResourceNode ( + sizeof (AML_RESOURCE_ADDRESS16) + 1 + StringLength); + + Descriptor = Rnode->Buffer; + Descriptor->Address16.DescriptorType = ACPI_RESOURCE_NAME_ADDRESS16; + + /* + * Initial descriptor length -- may be enlarged if there are + * optional fields present + */ + OptionalFields = ((UINT8 *) Descriptor) + sizeof (AML_RESOURCE_ADDRESS16); + Descriptor->Address16.ResourceLength = (UINT16) + (sizeof (AML_RESOURCE_ADDRESS16) - + sizeof (AML_RESOURCE_LARGE_HEADER)); + + /* Process all child initialization nodes */ + + for (i = 0; InitializerOp; i++) + { + switch (i) + { + case 0: /* Resource Type */ + + Descriptor->Address16.ResourceType = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 1: /* Resource Usage */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 0, 1); + break; + + case 2: /* DecodeType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 1, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_DECODE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 1); + break; + + case 3: /* MinType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 2, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MINTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 2); + break; + + case 4: /* MaxType */ + + RsSetFlagBits (&Descriptor->Address16.Flags, InitializerOp, 3, 0); + RsCreateBitField (InitializerOp, ACPI_RESTAG_MAXTYPE, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Flags), 3); + break; + + case 5: /* Type-Specific flags */ + + Descriptor->Address16.SpecificFlags = + (UINT8) InitializerOp->Asl.Value.Integer; + break; + + case 6: /* Address Granularity */ + + Descriptor->Address16.Granularity = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_GRANULARITY, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Granularity)); + GranOp = InitializerOp; + break; + + case 7: /* Min Address */ + + Descriptor->Address16.Minimum = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MINADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Minimum)); + MinOp = InitializerOp; + break; + + case 8: /* Max Address */ + + Descriptor->Address16.Maximum = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_MAXADDR, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.Maximum)); + MaxOp = InitializerOp; + break; + + case 9: /* Translation Offset */ + + Descriptor->Address16.TranslationOffset = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_TRANSLATION, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.TranslationOffset)); + break; + + case 10: /* Address Length */ + + Descriptor->Address16.AddressLength = + (UINT16) InitializerOp->Asl.Value.Integer; + RsCreateWordField (InitializerOp, ACPI_RESTAG_LENGTH, + CurrentByteOffset + ASL_RESDESC_OFFSET (Address16.AddressLength)); + LengthOp = InitializerOp; + break; + + case 11: /* ResSourceIndex [Optional Field - BYTE] */ + + if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + OptionalFields[0] = (UINT8) InitializerOp->Asl.Value.Integer; + OptionIndex++; + Descriptor->Address16.ResourceLength++; + ResSourceIndex = TRUE; + } + break; + + case 12: /* ResSource [Optional Field - STRING] */ + + if ((InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && + (InitializerOp->Asl.Value.String)) + { + if (StringLength) + { + Descriptor->Address16.ResourceLength = (UINT16) + (Descriptor->Address16.ResourceLength + StringLength); + + strcpy ((char *) + &OptionalFields[OptionIndex], + InitializerOp->Asl.Value.String); + + /* ResourceSourceIndex must also be valid */ + + if (!ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_INDEX, + InitializerOp, NULL); + } + } + } + +#if 0 + /* + * Not a valid ResourceSource, ResourceSourceIndex must also + * be invalid + */ + else if (ResSourceIndex) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_SOURCE, + InitializerOp, NULL); + } +#endif + break; + + case 13: /* ResourceTag */ + + UtAttachNamepathToOwner (Info->DescriptorTypeOp, InitializerOp); + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESOURCE_LIST, InitializerOp, NULL); + break; + } + + InitializerOp = RsCompleteNodeAndGetNext (InitializerOp); + } + + /* Validate the Min/Max/Len/Gran values */ + + RsLargeAddressCheck ( + (UINT64) Descriptor->Address16.Minimum, + (UINT64) Descriptor->Address16.Maximum, + (UINT64) Descriptor->Address16.AddressLength, + (UINT64) Descriptor->Address16.Granularity, + Descriptor->Address16.Flags, + MinOp, MaxOp, LengthOp, GranOp, Info->DescriptorTypeOp); + + Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS16) + + OptionIndex + StringLength; + return (Rnode); +} diff --git a/third_party/lib/acpica/source/compiler/aslrules.y b/third_party/lib/acpica/source/compiler/aslrules.y new file mode 100644 index 000000000..dcf3c22d8 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslrules.y @@ -0,0 +1,1726 @@ +NoEcho(' +/****************************************************************************** + * + * Module Name: aslrules.y - Main Bison/Yacc production rules + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +') + +/******************************************************************************* + * + * ASL Root and Secondary Terms + * + ******************************************************************************/ + +/* + * Root term. Allow multiple #line directives before the definition block + * to handle output from preprocessors + */ +AslCode + : DefinitionBlockList {$$ = TrLinkChildren (TrCreateLeafNode (PARSEOP_ASL_CODE),1, $1);} + | error {YYABORT; $$ = NULL;} + ; + + +/* + * Note concerning support for "module-level code". + * + * ACPI 1.0 allowed Type1 and Type2 executable opcodes outside of control + * methods (the so-called module-level code.) This support was explicitly + * removed in ACPI 2.0, but this type of code continues to be created by + * BIOS vendors. In order to support the disassembly and recompilation of + * such code (and the porting of ASL code to iASL), iASL supports this + * code in violation of the current ACPI specification. + * + * The grammar change to support module-level code is to revert the + * {ObjectList} portion of the DefinitionBlockTerm in ACPI 2.0 to the + * original use of {TermList} instead (see below.) This allows the use + * of Type1 and Type2 opcodes at module level. + */ +DefinitionBlockTerm + : PARSEOP_DEFINITION_BLOCK '(' {$$ = TrCreateLeafNode (PARSEOP_DEFINITION_BLOCK);} + String ',' + String ',' + ByteConst ',' + String ',' + String ',' + DWordConst + ')' {TrSetEndLineNumber ($3);} + '{' TermList '}' {$$ = TrLinkChildren ($3,7,$4,$6,$8,$10,$12,$14,$18);} + ; + +DefinitionBlockList + : DefinitionBlockTerm + | DefinitionBlockTerm + DefinitionBlockList {$$ = TrLinkPeerNodes (2, $1,$2);} + ; + +SuperName + : NameString {} + | ArgTerm {} + | LocalTerm {} + | DebugTerm {} + | Type6Opcode {} + +Target + : {$$ = TrCreateNullTarget ();} /* Placeholder is a ZeroOp object */ + | ',' {$$ = TrCreateNullTarget ();} /* Placeholder is a ZeroOp object */ + | ',' SuperName {$$ = TrSetNodeFlags ($2, NODE_IS_TARGET);} + ; + +TermArg + : Type2Opcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | DataObject {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | NameString {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | ArgTerm {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | LocalTerm {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + ; + +/* + NOTE: Removed from TermArg due to reduce/reduce conflicts: + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | Type2StringOpcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | Type2BufferOpcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + | Type2BufferOrStringOpcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);} + +*/ + +MethodInvocationTerm + : NameString '(' {TrUpdateNode (PARSEOP_METHODCALL, $1);} + ArgList ')' {$$ = TrLinkChildNode ($1,$4);} + ; + +/* OptionalCount must appear before ByteList or an incorrect reduction will result */ + +OptionalCount + : {$$ = TrCreateLeafNode (PARSEOP_ONES);} /* Placeholder is a OnesOp object */ + | ',' {$$ = TrCreateLeafNode (PARSEOP_ONES);} /* Placeholder is a OnesOp object */ + | ',' TermArg {$$ = $2;} + ; + +VarPackageLengthTerm + : {$$ = TrCreateLeafNode (PARSEOP_DEFAULT_ARG);} + | TermArg {$$ = $1;} + ; + + +/******* List Terms **************************************************/ + +ArgList + : {$$ = NULL;} + | TermArg + | ArgList ',' /* Allows a trailing comma at list end */ + | ArgList ',' + TermArg {$$ = TrLinkPeerNode ($1,$3);} + ; + +ByteList + : {$$ = NULL;} + | ByteConstExpr + | ByteList ',' /* Allows a trailing comma at list end */ + | ByteList ',' + ByteConstExpr {$$ = TrLinkPeerNode ($1,$3);} + ; + +DWordList + : {$$ = NULL;} + | DWordConstExpr + | DWordList ',' /* Allows a trailing comma at list end */ + | DWordList ',' + DWordConstExpr {$$ = TrLinkPeerNode ($1,$3);} + ; + +FieldUnitList + : {$$ = NULL;} + | FieldUnit + | FieldUnitList ',' /* Allows a trailing comma at list end */ + | FieldUnitList ',' + FieldUnit {$$ = TrLinkPeerNode ($1,$3);} + ; + +FieldUnit + : FieldUnitEntry {} + | OffsetTerm {} + | AccessAsTerm {} + | ConnectionTerm {} + ; + +FieldUnitEntry + : ',' AmlPackageLengthTerm {$$ = TrCreateNode (PARSEOP_RESERVED_BYTES,1,$2);} + | NameSeg ',' + AmlPackageLengthTerm {$$ = TrLinkChildNode ($1,$3);} + ; + +ObjectList + : {$$ = NULL;} + | ObjectList Object {$$ = TrLinkPeerNode ($1,$2);} + | error {$$ = AslDoError(); yyclearin;} + ; + +Object + : CompilerDirective {} + | NamedObject {} + | NameSpaceModifier {} + ; + +PackageList + : {$$ = NULL;} + | PackageElement + | PackageList ',' /* Allows a trailing comma at list end */ + | PackageList ',' + PackageElement {$$ = TrLinkPeerNode ($1,$3);} + ; + +PackageElement + : DataObject {} + | NameString {} + ; + + /* Rules for specifying the type of one method argument or return value */ + +ParameterTypePackage + : {$$ = NULL;} + | ObjectTypeKeyword {$$ = $1;} + | ParameterTypePackage ',' + ObjectTypeKeyword {$$ = TrLinkPeerNodes (2,$1,$3);} + ; + +ParameterTypePackageList + : {$$ = NULL;} + | ObjectTypeKeyword {$$ = $1;} + | '{' ParameterTypePackage '}' {$$ = $2;} + ; + +OptionalParameterTypePackage + : {$$ = TrCreateLeafNode (PARSEOP_DEFAULT_ARG);} + | ',' ParameterTypePackageList {$$ = TrLinkChildren (TrCreateLeafNode (PARSEOP_DEFAULT_ARG),1,$2);} + ; + + /* Rules for specifying the types for method arguments */ + +ParameterTypesPackage + : ParameterTypePackageList {$$ = $1;} + | ParameterTypesPackage ',' + ParameterTypePackageList {$$ = TrLinkPeerNodes (2,$1,$3);} + ; + +ParameterTypesPackageList + : {$$ = NULL;} + | ObjectTypeKeyword {$$ = $1;} + | '{' ParameterTypesPackage '}' {$$ = $2;} + ; + +OptionalParameterTypesPackage + : {$$ = TrCreateLeafNode (PARSEOP_DEFAULT_ARG);} + | ',' ParameterTypesPackageList {$$ = TrLinkChildren (TrCreateLeafNode (PARSEOP_DEFAULT_ARG),1,$2);} + ; + + /* ACPI 3.0 -- allow semicolons between terms */ + +TermList + : {$$ = NULL;} + | TermList Term {$$ = TrLinkPeerNode (TrSetNodeFlags ($1, NODE_RESULT_NOT_USED),$2);} + | TermList Term ';' {$$ = TrLinkPeerNode (TrSetNodeFlags ($1, NODE_RESULT_NOT_USED),$2);} + | TermList ';' Term {$$ = TrLinkPeerNode (TrSetNodeFlags ($1, NODE_RESULT_NOT_USED),$3);} + | TermList ';' Term ';' {$$ = TrLinkPeerNode (TrSetNodeFlags ($1, NODE_RESULT_NOT_USED),$3);} + ; + +Term + : Object {} + | Type1Opcode {} + | Type2Opcode {} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | Type2StringOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | Type2BufferOpcode {} + | Type2BufferOrStringOpcode {} + | error {$$ = AslDoError(); yyclearin;} + ; + +/* + * Case-Default list; allow only one Default term and unlimited Case terms + */ +CaseDefaultTermList + : {$$ = NULL;} + | CaseTerm {} + | DefaultTerm {} + | CaseDefaultTermList + CaseTerm {$$ = TrLinkPeerNode ($1,$2);} + | CaseDefaultTermList + DefaultTerm {$$ = TrLinkPeerNode ($1,$2);} + +/* Original - attempts to force zero or one default term within the switch */ + +/* +CaseDefaultTermList + : {$$ = NULL;} + | CaseTermList + DefaultTerm + CaseTermList {$$ = TrLinkPeerNode ($1,TrLinkPeerNode ($2, $3));} + | CaseTermList + CaseTerm {$$ = TrLinkPeerNode ($1,$2);} + ; + +CaseTermList + : {$$ = NULL;} + | CaseTerm {} + | CaseTermList + CaseTerm {$$ = TrLinkPeerNode ($1,$2);} + ; +*/ + + +/******************************************************************************* + * + * ASL Data and Constant Terms + * + ******************************************************************************/ + +DataObject + : BufferData {} + | PackageData {} + | IntegerData {} + | StringData {} + ; + +BufferData + : Type5Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | Type2BufferOrStringOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | Type2BufferOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | BufferTerm {} + ; + +PackageData + : PackageTerm {} + ; + +IntegerData + : Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | Integer {} + | ConstTerm {} + ; + +StringData + : Type2StringOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | String {} + ; + +ByteConst + : Integer {$$ = TrUpdateNode (PARSEOP_BYTECONST, $1);} + ; + +WordConst + : Integer {$$ = TrUpdateNode (PARSEOP_WORDCONST, $1);} + ; + +DWordConst + : Integer {$$ = TrUpdateNode (PARSEOP_DWORDCONST, $1);} + ; + +QWordConst + : Integer {$$ = TrUpdateNode (PARSEOP_QWORDCONST, $1);} + ; + +/* + * The NODE_COMPILE_TIME_CONST flag in the following constant expressions + * enables compile-time constant folding to reduce the Type3Opcodes/Type2IntegerOpcodes + * to simple integers. It is an error if these types of expressions cannot be + * reduced, since the AML grammar for ****ConstExpr requires a simple constant. + * Note: The required byte length of the constant is passed through to the + * constant folding code in the node AmlLength field. + */ +ByteConstExpr + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 1);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 1);} + | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_BYTECONST, $1);} + | ByteConst {} + ; + +WordConstExpr + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 2);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 2);} + | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_WORDCONST, $1);} + | WordConst {} + ; + +DWordConstExpr + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 4);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 4);} + | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_DWORDCONST, $1);} + | DWordConst {} + ; + +QWordConstExpr + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 8);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 8);} + | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_QWORDCONST, $1);} + | QWordConst {} + ; + +ConstTerm + : ConstExprTerm {} + | PARSEOP_REVISION {$$ = TrCreateLeafNode (PARSEOP_REVISION);} + ; + +ConstExprTerm + : PARSEOP_ZERO {$$ = TrCreateValuedLeafNode (PARSEOP_ZERO, 0);} + | PARSEOP_ONE {$$ = TrCreateValuedLeafNode (PARSEOP_ONE, 1);} + | PARSEOP_ONES {$$ = TrCreateValuedLeafNode (PARSEOP_ONES, ACPI_UINT64_MAX);} + | PARSEOP___DATE__ {$$ = TrCreateConstantLeafNode (PARSEOP___DATE__);} + | PARSEOP___FILE__ {$$ = TrCreateConstantLeafNode (PARSEOP___FILE__);} + | PARSEOP___LINE__ {$$ = TrCreateConstantLeafNode (PARSEOP___LINE__);} + | PARSEOP___PATH__ {$$ = TrCreateConstantLeafNode (PARSEOP___PATH__);} + ; + +Integer + : PARSEOP_INTEGER {$$ = TrCreateValuedLeafNode (PARSEOP_INTEGER, AslCompilerlval.i);} + ; + +String + : PARSEOP_STRING_LITERAL {$$ = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, (ACPI_NATIVE_INT) AslCompilerlval.s);} + ; + + +/******************************************************************************* + * + * ASL Opcode Terms + * + ******************************************************************************/ + +CompilerDirective + : IncludeTerm {} + | IncludeEndTerm {} + | ExternalTerm {} + ; + +NamedObject + : BankFieldTerm {} + | CreateBitFieldTerm {} + | CreateByteFieldTerm {} + | CreateDWordFieldTerm {} + | CreateFieldTerm {} + | CreateQWordFieldTerm {} + | CreateWordFieldTerm {} + | DataRegionTerm {} + | DeviceTerm {} + | EventTerm {} + | FieldTerm {} + | FunctionTerm {} + | IndexFieldTerm {} + | MethodTerm {} + | MutexTerm {} + | OpRegionTerm {} + | PowerResTerm {} + | ProcessorTerm {} + | ThermalZoneTerm {} + ; + +NameSpaceModifier + : AliasTerm {} + | NameTerm {} + | ScopeTerm {} + ; + +/* For ObjectType: SuperName except for MethodInvocationTerm */ + +ObjectTypeName + : NameString {} + | ArgTerm {} + | LocalTerm {} + | DebugTerm {} + | RefOfTerm {} + | DerefOfTerm {} + | IndexTerm {} + +/* | MethodInvocationTerm {} */ /* Caused reduce/reduce with Type6Opcode->MethodInvocationTerm */ + ; + +RequiredTarget + : ',' SuperName {$$ = TrSetNodeFlags ($2, NODE_IS_TARGET);} + ; + +SimpleTarget + : NameString {} + | LocalTerm {} + | ArgTerm {} + ; + +/* Opcode types */ + +Type1Opcode + : BreakTerm {} + | BreakPointTerm {} + | ContinueTerm {} + | FatalTerm {} + | ElseIfTerm {} + | LoadTerm {} + | NoOpTerm {} + | NotifyTerm {} + | ReleaseTerm {} + | ResetTerm {} + | ReturnTerm {} + | SignalTerm {} + | SleepTerm {} + | StallTerm {} + | SwitchTerm {} + | UnloadTerm {} + | WhileTerm {} + ; + +Type2Opcode + : AcquireTerm {} + | CondRefOfTerm {} + | CopyObjectTerm {} + | DerefOfTerm {} + | ObjectTypeTerm {} + | RefOfTerm {} + | SizeOfTerm {} + | StoreTerm {} + | EqualsTerm {} + | TimerTerm {} + | WaitTerm {} + | MethodInvocationTerm {} + ; + +/* + * Type 3/4/5 opcodes + */ +Type2IntegerOpcode /* "Type3" opcodes */ + : Expression {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | AddTerm {} + | AndTerm {} + | DecTerm {} + | DivideTerm {} + | FindSetLeftBitTerm {} + | FindSetRightBitTerm {} + | FromBCDTerm {} + | IncTerm {} + | IndexTerm {} + | LAndTerm {} + | LEqualTerm {} + | LGreaterTerm {} + | LGreaterEqualTerm {} + | LLessTerm {} + | LLessEqualTerm {} + | LNotTerm {} + | LNotEqualTerm {} + | LoadTableTerm {} + | LOrTerm {} + | MatchTerm {} + | ModTerm {} + | MultiplyTerm {} + | NAndTerm {} + | NOrTerm {} + | NotTerm {} + | OrTerm {} + | ShiftLeftTerm {} + | ShiftRightTerm {} + | SubtractTerm {} + | ToBCDTerm {} + | ToIntegerTerm {} + | XOrTerm {} + ; + +Type2StringOpcode /* "Type4" Opcodes */ + : ToDecimalStringTerm {} + | ToHexStringTerm {} + | ToStringTerm {} + ; + +Type2BufferOpcode /* "Type5" Opcodes */ + : ToBufferTerm {} + | ConcatResTerm {} + ; + +Type2BufferOrStringOpcode + : ConcatTerm {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);} + | PrintfTerm {} + | FprintfTerm {} + | MidTerm {} + ; + +/* + * A type 3 opcode evaluates to an Integer and cannot have a destination operand + */ +Type3Opcode + : EISAIDTerm {} + ; + +/* Obsolete +Type4Opcode + : ConcatTerm {} + | ToDecimalStringTerm {} + | ToHexStringTerm {} + | MidTerm {} + | ToStringTerm {} + ; +*/ + +Type5Opcode + : ResourceTemplateTerm {} + | UnicodeTerm {} + | ToPLDTerm {} + | ToUUIDTerm {} + ; + +Type6Opcode + : RefOfTerm {} + | DerefOfTerm {} + | IndexTerm {} + | IndexExpTerm {} + | MethodInvocationTerm {} + ; + + +/******************************************************************************* + * + * ASL Primary Terms + * + ******************************************************************************/ + +AccessAsTerm + : PARSEOP_ACCESSAS '(' + AccessTypeKeyword + OptionalAccessAttribTerm + ')' {$$ = TrCreateNode (PARSEOP_ACCESSAS,2,$3,$4);} + | PARSEOP_ACCESSAS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +AcquireTerm + : PARSEOP_ACQUIRE '(' {$$ = TrCreateLeafNode (PARSEOP_ACQUIRE);} + SuperName + ',' WordConstExpr + ')' {$$ = TrLinkChildren ($3,2,$4,$6);} + | PARSEOP_ACQUIRE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +AddTerm + : PARSEOP_ADD '(' {$$ = TrCreateLeafNode (PARSEOP_ADD);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_ADD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +AliasTerm + : PARSEOP_ALIAS '(' {$$ = TrCreateLeafNode (PARSEOP_ALIAS);} + NameString + NameStringItem + ')' {$$ = TrLinkChildren ($3,2,$4, + TrSetNodeFlags ($5, NODE_IS_NAME_DECLARATION));} + | PARSEOP_ALIAS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +AndTerm + : PARSEOP_AND '(' {$$ = TrCreateLeafNode (PARSEOP_AND);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_AND '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ArgTerm + : PARSEOP_ARG0 {$$ = TrCreateLeafNode (PARSEOP_ARG0);} + | PARSEOP_ARG1 {$$ = TrCreateLeafNode (PARSEOP_ARG1);} + | PARSEOP_ARG2 {$$ = TrCreateLeafNode (PARSEOP_ARG2);} + | PARSEOP_ARG3 {$$ = TrCreateLeafNode (PARSEOP_ARG3);} + | PARSEOP_ARG4 {$$ = TrCreateLeafNode (PARSEOP_ARG4);} + | PARSEOP_ARG5 {$$ = TrCreateLeafNode (PARSEOP_ARG5);} + | PARSEOP_ARG6 {$$ = TrCreateLeafNode (PARSEOP_ARG6);} + ; + +BankFieldTerm + : PARSEOP_BANKFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_BANKFIELD);} + NameString + NameStringItem + TermArgItem + ',' AccessTypeKeyword + ',' LockRuleKeyword + ',' UpdateRuleKeyword + ')' '{' + FieldUnitList '}' {$$ = TrLinkChildren ($3,7,$4,$5,$6,$8,$10,$12,$15);} + | PARSEOP_BANKFIELD '(' + error ')' '{' error '}' {$$ = AslDoError(); yyclearin;} + ; + +BreakTerm + : PARSEOP_BREAK {$$ = TrCreateNode (PARSEOP_BREAK, 0);} + ; + +BreakPointTerm + : PARSEOP_BREAKPOINT {$$ = TrCreateNode (PARSEOP_BREAKPOINT, 0);} + ; + +BufferTerm + : PARSEOP_BUFFER '(' {$$ = TrCreateLeafNode (PARSEOP_BUFFER);} + OptionalTermArg + ')' '{' + BufferTermData '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_BUFFER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +BufferTermData + : ByteList {} + | StringData {} + ; + +CaseTerm + : PARSEOP_CASE '(' {$$ = TrCreateLeafNode (PARSEOP_CASE);} + DataObject + ')' '{' + TermList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_CASE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ConcatTerm + : PARSEOP_CONCATENATE '(' {$$ = TrCreateLeafNode (PARSEOP_CONCATENATE);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_CONCATENATE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ConcatResTerm + : PARSEOP_CONCATENATERESTEMPLATE '(' {$$ = TrCreateLeafNode (PARSEOP_CONCATENATERESTEMPLATE);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_CONCATENATERESTEMPLATE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ConnectionTerm + : PARSEOP_CONNECTION '(' + NameString + ')' {$$ = TrCreateNode (PARSEOP_CONNECTION,1,$3);} + | PARSEOP_CONNECTION '(' {$$ = TrCreateLeafNode (PARSEOP_CONNECTION);} + ResourceMacroTerm + ')' {$$ = TrLinkChildren ($3, 1, + TrLinkChildren (TrCreateLeafNode (PARSEOP_RESOURCETEMPLATE), 3, + TrCreateLeafNode (PARSEOP_DEFAULT_ARG), + TrCreateLeafNode (PARSEOP_DEFAULT_ARG), + $4));} + | PARSEOP_CONNECTION '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CondRefOfTerm + : PARSEOP_CONDREFOF '(' {$$ = TrCreateLeafNode (PARSEOP_CONDREFOF);} + SuperName + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_CONDREFOF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ContinueTerm + : PARSEOP_CONTINUE {$$ = TrCreateNode (PARSEOP_CONTINUE, 0);} + ; + +CopyObjectTerm + : PARSEOP_COPYOBJECT '(' {$$ = TrCreateLeafNode (PARSEOP_COPYOBJECT);} + TermArg + ',' SimpleTarget + ')' {$$ = TrLinkChildren ($3,2,$4,TrSetNodeFlags ($6, NODE_IS_TARGET));} + | PARSEOP_COPYOBJECT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CreateBitFieldTerm + : PARSEOP_CREATEBITFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_CREATEBITFIELD);} + TermArg + TermArgItem + NameStringItem + ')' {$$ = TrLinkChildren ($3,3,$4,$5,TrSetNodeFlags ($6, NODE_IS_NAME_DECLARATION));} + | PARSEOP_CREATEBITFIELD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CreateByteFieldTerm + : PARSEOP_CREATEBYTEFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_CREATEBYTEFIELD);} + TermArg + TermArgItem + NameStringItem + ')' {$$ = TrLinkChildren ($3,3,$4,$5,TrSetNodeFlags ($6, NODE_IS_NAME_DECLARATION));} + | PARSEOP_CREATEBYTEFIELD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CreateDWordFieldTerm + : PARSEOP_CREATEDWORDFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_CREATEDWORDFIELD);} + TermArg + TermArgItem + NameStringItem + ')' {$$ = TrLinkChildren ($3,3,$4,$5,TrSetNodeFlags ($6, NODE_IS_NAME_DECLARATION));} + | PARSEOP_CREATEDWORDFIELD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CreateFieldTerm + : PARSEOP_CREATEFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_CREATEFIELD);} + TermArg + TermArgItem + TermArgItem + NameStringItem + ')' {$$ = TrLinkChildren ($3,4,$4,$5,$6,TrSetNodeFlags ($7, NODE_IS_NAME_DECLARATION));} + | PARSEOP_CREATEFIELD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CreateQWordFieldTerm + : PARSEOP_CREATEQWORDFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_CREATEQWORDFIELD);} + TermArg + TermArgItem + NameStringItem + ')' {$$ = TrLinkChildren ($3,3,$4,$5,TrSetNodeFlags ($6, NODE_IS_NAME_DECLARATION));} + | PARSEOP_CREATEQWORDFIELD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +CreateWordFieldTerm + : PARSEOP_CREATEWORDFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_CREATEWORDFIELD);} + TermArg + TermArgItem + NameStringItem + ')' {$$ = TrLinkChildren ($3,3,$4,$5,TrSetNodeFlags ($6, NODE_IS_NAME_DECLARATION));} + | PARSEOP_CREATEWORDFIELD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DataRegionTerm + : PARSEOP_DATATABLEREGION '(' {$$ = TrCreateLeafNode (PARSEOP_DATATABLEREGION);} + NameString + TermArgItem + TermArgItem + TermArgItem + ')' {$$ = TrLinkChildren ($3,4,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$5,$6,$7);} + | PARSEOP_DATATABLEREGION '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DebugTerm + : PARSEOP_DEBUG {$$ = TrCreateLeafNode (PARSEOP_DEBUG);} + ; + +DecTerm + : PARSEOP_DECREMENT '(' {$$ = TrCreateLeafNode (PARSEOP_DECREMENT);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_DECREMENT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DefaultTerm + : PARSEOP_DEFAULT '{' {$$ = TrCreateLeafNode (PARSEOP_DEFAULT);} + TermList '}' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_DEFAULT '{' + error '}' {$$ = AslDoError(); yyclearin;} + ; + +DerefOfTerm + : PARSEOP_DEREFOF '(' {$$ = TrCreateLeafNode (PARSEOP_DEREFOF);} + TermArg + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_DEREFOF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DeviceTerm + : PARSEOP_DEVICE '(' {$$ = TrCreateLeafNode (PARSEOP_DEVICE);} + NameString + ')' '{' + ObjectList '}' {$$ = TrLinkChildren ($3,2,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$7);} + | PARSEOP_DEVICE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +DivideTerm + : PARSEOP_DIVIDE '(' {$$ = TrCreateLeafNode (PARSEOP_DIVIDE);} + TermArg + TermArgItem + Target + Target + ')' {$$ = TrLinkChildren ($3,4,$4,$5,$6,$7);} + | PARSEOP_DIVIDE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +EISAIDTerm + : PARSEOP_EISAID '(' + StringData ')' {$$ = TrUpdateNode (PARSEOP_EISAID, $3);} + | PARSEOP_EISAID '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ElseIfTerm + : IfTerm ElseTerm {$$ = TrLinkPeerNode ($1,$2);} + ; + +ElseTerm + : {$$ = NULL;} + | PARSEOP_ELSE '{' {$$ = TrCreateLeafNode (PARSEOP_ELSE);} + TermList '}' {$$ = TrLinkChildren ($3,1,$4);} + + | PARSEOP_ELSE '{' + error '}' {$$ = AslDoError(); yyclearin;} + + | PARSEOP_ELSE + error {$$ = AslDoError(); yyclearin;} + + | PARSEOP_ELSEIF '(' {$$ = TrCreateLeafNode (PARSEOP_ELSE);} + TermArg {$$ = TrCreateLeafNode (PARSEOP_IF);} + ')' '{' + TermList '}' {TrLinkChildren ($5,2,$4,$8);} + ElseTerm {TrLinkPeerNode ($5,$11);} + {$$ = TrLinkChildren ($3,1,$5);} + + | PARSEOP_ELSEIF '(' + error ')' {$$ = AslDoError(); yyclearin;} + + | PARSEOP_ELSEIF + error {$$ = AslDoError(); yyclearin;} + ; + +EventTerm + : PARSEOP_EVENT '(' {$$ = TrCreateLeafNode (PARSEOP_EVENT);} + NameString + ')' {$$ = TrLinkChildren ($3,1,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION));} + | PARSEOP_EVENT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ExternalTerm + : PARSEOP_EXTERNAL '(' + NameString + OptionalObjectTypeKeyword + OptionalParameterTypePackage + OptionalParameterTypesPackage + ')' {$$ = TrCreateNode (PARSEOP_EXTERNAL,4,$3,$4,$5,$6);} + | PARSEOP_EXTERNAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FatalTerm + : PARSEOP_FATAL '(' {$$ = TrCreateLeafNode (PARSEOP_FATAL);} + ByteConstExpr + ',' DWordConstExpr + TermArgItem + ')' {$$ = TrLinkChildren ($3,3,$4,$6,$7);} + | PARSEOP_FATAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FieldTerm + : PARSEOP_FIELD '(' {$$ = TrCreateLeafNode (PARSEOP_FIELD);} + NameString + ',' AccessTypeKeyword + ',' LockRuleKeyword + ',' UpdateRuleKeyword + ')' '{' + FieldUnitList '}' {$$ = TrLinkChildren ($3,5,$4,$6,$8,$10,$13);} + | PARSEOP_FIELD '(' + error ')' '{' error '}' {$$ = AslDoError(); yyclearin;} + ; + +FindSetLeftBitTerm + : PARSEOP_FINDSETLEFTBIT '(' {$$ = TrCreateLeafNode (PARSEOP_FINDSETLEFTBIT);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_FINDSETLEFTBIT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FindSetRightBitTerm + : PARSEOP_FINDSETRIGHTBIT '(' {$$ = TrCreateLeafNode (PARSEOP_FINDSETRIGHTBIT);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_FINDSETRIGHTBIT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FprintfTerm + : PARSEOP_FPRINTF '(' {$$ = TrCreateLeafNode (PARSEOP_FPRINTF);} + TermArg ',' + StringData + PrintfArgList + ')' {$$ = TrLinkChildren ($3,3,$4,$6,$7);} + | PARSEOP_FPRINTF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FromBCDTerm + : PARSEOP_FROMBCD '(' {$$ = TrCreateLeafNode (PARSEOP_FROMBCD);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_FROMBCD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +FunctionTerm + : PARSEOP_FUNCTION '(' {$$ = TrCreateLeafNode (PARSEOP_METHOD);} + NameString + OptionalParameterTypePackage + OptionalParameterTypesPackage + ')' '{' + TermList '}' {$$ = TrLinkChildren ($3,7,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION), + TrCreateValuedLeafNode (PARSEOP_BYTECONST, 0), + TrCreateLeafNode (PARSEOP_SERIALIZERULE_NOTSERIAL), + TrCreateValuedLeafNode (PARSEOP_BYTECONST, 0),$5,$6,$9);} + | PARSEOP_FUNCTION '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +IfTerm + : PARSEOP_IF '(' {$$ = TrCreateLeafNode (PARSEOP_IF);} + TermArg + ')' '{' + TermList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + + | PARSEOP_IF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +IncludeTerm + : PARSEOP_INCLUDE '(' + String ')' {$$ = TrUpdateNode (PARSEOP_INCLUDE, $3); + FlOpenIncludeFile ($3);} + ; + +IncludeEndTerm + : PARSEOP_INCLUDE_END {$$ = TrCreateLeafNode (PARSEOP_INCLUDE_END); TrSetCurrentFilename ($$);} + ; + +IncTerm + : PARSEOP_INCREMENT '(' {$$ = TrCreateLeafNode (PARSEOP_INCREMENT);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_INCREMENT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +IndexFieldTerm + : PARSEOP_INDEXFIELD '(' {$$ = TrCreateLeafNode (PARSEOP_INDEXFIELD);} + NameString + NameStringItem + ',' AccessTypeKeyword + ',' LockRuleKeyword + ',' UpdateRuleKeyword + ')' '{' + FieldUnitList '}' {$$ = TrLinkChildren ($3,6,$4,$5,$7,$9,$11,$14);} + | PARSEOP_INDEXFIELD '(' + error ')' '{' error '}' {$$ = AslDoError(); yyclearin;} + ; + +IndexTerm + : PARSEOP_INDEX '(' {$$ = TrCreateLeafNode (PARSEOP_INDEX);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_INDEX '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LAndTerm + : PARSEOP_LAND '(' {$$ = TrCreateLeafNode (PARSEOP_LAND);} + TermArg + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_LAND '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LEqualTerm + : PARSEOP_LEQUAL '(' {$$ = TrCreateLeafNode (PARSEOP_LEQUAL);} + TermArg + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_LEQUAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LGreaterEqualTerm + : PARSEOP_LGREATEREQUAL '(' {$$ = TrCreateLeafNode (PARSEOP_LLESS);} + TermArg + TermArgItem + ')' {$$ = TrCreateNode (PARSEOP_LNOT, 1, TrLinkChildren ($3,2,$4,$5));} + | PARSEOP_LGREATEREQUAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LGreaterTerm + : PARSEOP_LGREATER '(' {$$ = TrCreateLeafNode (PARSEOP_LGREATER);} + TermArg + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_LGREATER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LLessEqualTerm + : PARSEOP_LLESSEQUAL '(' {$$ = TrCreateLeafNode (PARSEOP_LGREATER);} + TermArg + TermArgItem + ')' {$$ = TrCreateNode (PARSEOP_LNOT, 1, TrLinkChildren ($3,2,$4,$5));} + | PARSEOP_LLESSEQUAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LLessTerm + : PARSEOP_LLESS '(' {$$ = TrCreateLeafNode (PARSEOP_LLESS);} + TermArg + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_LLESS '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LNotEqualTerm + : PARSEOP_LNOTEQUAL '(' {$$ = TrCreateLeafNode (PARSEOP_LEQUAL);} + TermArg + TermArgItem + ')' {$$ = TrCreateNode (PARSEOP_LNOT, 1, TrLinkChildren ($3,2,$4,$5));} + | PARSEOP_LNOTEQUAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LNotTerm + : PARSEOP_LNOT '(' {$$ = TrCreateLeafNode (PARSEOP_LNOT);} + TermArg + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_LNOT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LoadTableTerm + : PARSEOP_LOADTABLE '(' {$$ = TrCreateLeafNode (PARSEOP_LOADTABLE);} + TermArg + TermArgItem + TermArgItem + OptionalListString + OptionalListString + OptionalReference + ')' {$$ = TrLinkChildren ($3,6,$4,$5,$6,$7,$8,$9);} + | PARSEOP_LOADTABLE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LoadTerm + : PARSEOP_LOAD '(' {$$ = TrCreateLeafNode (PARSEOP_LOAD);} + NameString + RequiredTarget + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_LOAD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +LocalTerm + : PARSEOP_LOCAL0 {$$ = TrCreateLeafNode (PARSEOP_LOCAL0);} + | PARSEOP_LOCAL1 {$$ = TrCreateLeafNode (PARSEOP_LOCAL1);} + | PARSEOP_LOCAL2 {$$ = TrCreateLeafNode (PARSEOP_LOCAL2);} + | PARSEOP_LOCAL3 {$$ = TrCreateLeafNode (PARSEOP_LOCAL3);} + | PARSEOP_LOCAL4 {$$ = TrCreateLeafNode (PARSEOP_LOCAL4);} + | PARSEOP_LOCAL5 {$$ = TrCreateLeafNode (PARSEOP_LOCAL5);} + | PARSEOP_LOCAL6 {$$ = TrCreateLeafNode (PARSEOP_LOCAL6);} + | PARSEOP_LOCAL7 {$$ = TrCreateLeafNode (PARSEOP_LOCAL7);} + ; + +LOrTerm + : PARSEOP_LOR '(' {$$ = TrCreateLeafNode (PARSEOP_LOR);} + TermArg + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_LOR '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +MatchTerm + : PARSEOP_MATCH '(' {$$ = TrCreateLeafNode (PARSEOP_MATCH);} + TermArg + ',' MatchOpKeyword + TermArgItem + ',' MatchOpKeyword + TermArgItem + TermArgItem + ')' {$$ = TrLinkChildren ($3,6,$4,$6,$7,$9,$10,$11);} + | PARSEOP_MATCH '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +MethodTerm + : PARSEOP_METHOD '(' {$$ = TrCreateLeafNode (PARSEOP_METHOD);} + NameString + OptionalByteConstExpr {UtCheckIntegerRange ($5, 0, 7);} + OptionalSerializeRuleKeyword + OptionalByteConstExpr + OptionalParameterTypePackage + OptionalParameterTypesPackage + ')' '{' + TermList '}' {$$ = TrLinkChildren ($3,7,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$5,$7,$8,$9,$10,$13);} + | PARSEOP_METHOD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +MidTerm + : PARSEOP_MID '(' {$$ = TrCreateLeafNode (PARSEOP_MID);} + TermArg + TermArgItem + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,4,$4,$5,$6,$7);} + | PARSEOP_MID '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ModTerm + : PARSEOP_MOD '(' {$$ = TrCreateLeafNode (PARSEOP_MOD);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_MOD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +MultiplyTerm + : PARSEOP_MULTIPLY '(' {$$ = TrCreateLeafNode (PARSEOP_MULTIPLY);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_MULTIPLY '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +MutexTerm + : PARSEOP_MUTEX '(' {$$ = TrCreateLeafNode (PARSEOP_MUTEX);} + NameString + ',' ByteConstExpr + ')' {$$ = TrLinkChildren ($3,2,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$6);} + | PARSEOP_MUTEX '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +NameTerm + : PARSEOP_NAME '(' {$$ = TrCreateLeafNode (PARSEOP_NAME);} + NameString + ',' DataObject + ')' {$$ = TrLinkChildren ($3,2,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$6);} + | PARSEOP_NAME '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +NAndTerm + : PARSEOP_NAND '(' {$$ = TrCreateLeafNode (PARSEOP_NAND);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_NAND '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +NoOpTerm + : PARSEOP_NOOP {$$ = TrCreateNode (PARSEOP_NOOP, 0);} + ; + +NOrTerm + : PARSEOP_NOR '(' {$$ = TrCreateLeafNode (PARSEOP_NOR);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_NOR '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +NotifyTerm + : PARSEOP_NOTIFY '(' {$$ = TrCreateLeafNode (PARSEOP_NOTIFY);} + SuperName + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_NOTIFY '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +NotTerm + : PARSEOP_NOT '(' {$$ = TrCreateLeafNode (PARSEOP_NOT);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_NOT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ObjectTypeTerm + : PARSEOP_OBJECTTYPE '(' {$$ = TrCreateLeafNode (PARSEOP_OBJECTTYPE);} + ObjectTypeName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_OBJECTTYPE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +OffsetTerm + : PARSEOP_OFFSET '(' + AmlPackageLengthTerm + ')' {$$ = TrCreateNode (PARSEOP_OFFSET,1,$3);} + | PARSEOP_OFFSET '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +OpRegionTerm + : PARSEOP_OPERATIONREGION '(' {$$ = TrCreateLeafNode (PARSEOP_OPERATIONREGION);} + NameString + ',' OpRegionSpaceIdTerm + TermArgItem + TermArgItem + ')' {$$ = TrLinkChildren ($3,4,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$6,$7,$8);} + | PARSEOP_OPERATIONREGION '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +OpRegionSpaceIdTerm + : RegionSpaceKeyword {} + | ByteConst {$$ = UtCheckIntegerRange ($1, 0x80, 0xFF);} + ; + +OrTerm + : PARSEOP_OR '(' {$$ = TrCreateLeafNode (PARSEOP_OR);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_OR '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +PackageTerm + : PARSEOP_PACKAGE '(' {$$ = TrCreateLeafNode (PARSEOP_VAR_PACKAGE);} + VarPackageLengthTerm + ')' '{' + PackageList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_PACKAGE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +PowerResTerm + : PARSEOP_POWERRESOURCE '(' {$$ = TrCreateLeafNode (PARSEOP_POWERRESOURCE);} + NameString + ',' ByteConstExpr + ',' WordConstExpr + ')' '{' + ObjectList '}' {$$ = TrLinkChildren ($3,4,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$6,$8,$11);} + | PARSEOP_POWERRESOURCE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +PrintfTerm + : PARSEOP_PRINTF '(' {$$ = TrCreateLeafNode (PARSEOP_PRINTF);} + StringData + PrintfArgList + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_PRINTF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +PrintfArgList + : {$$ = NULL;} + | TermArg {$$ = $1;} + | PrintfArgList ',' + TermArg {$$ = TrLinkPeerNode ($1, $3);} + ; + +ProcessorTerm + : PARSEOP_PROCESSOR '(' {$$ = TrCreateLeafNode (PARSEOP_PROCESSOR);} + NameString + ',' ByteConstExpr + OptionalDWordConstExpr + OptionalByteConstExpr + ')' '{' + ObjectList '}' {$$ = TrLinkChildren ($3,5,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$6,$7,$8,$11);} + | PARSEOP_PROCESSOR '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +RawDataBufferTerm + : PARSEOP_DATABUFFER '(' {$$ = TrCreateLeafNode (PARSEOP_DATABUFFER);} + OptionalWordConst + ')' '{' + ByteList '}' {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_DATABUFFER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +/* + * In RefOf, the node isn't really a target, but we can't keep track of it after + * we've taken a pointer to it. (hard to tell if a local becomes initialized this way.) + */ +RefOfTerm + : PARSEOP_REFOF '(' {$$ = TrCreateLeafNode (PARSEOP_REFOF);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,TrSetNodeFlags ($4, NODE_IS_TARGET));} + | PARSEOP_REFOF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ReleaseTerm + : PARSEOP_RELEASE '(' {$$ = TrCreateLeafNode (PARSEOP_RELEASE);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_RELEASE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ResetTerm + : PARSEOP_RESET '(' {$$ = TrCreateLeafNode (PARSEOP_RESET);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_RESET '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ReturnTerm + : PARSEOP_RETURN '(' {$$ = TrCreateLeafNode (PARSEOP_RETURN);} + OptionalReturnArg + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_RETURN {$$ = TrLinkChildren (TrCreateLeafNode (PARSEOP_RETURN),1,TrSetNodeFlags (TrCreateLeafNode (PARSEOP_ZERO), NODE_IS_NULL_RETURN));} + | PARSEOP_RETURN '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ScopeTerm + : PARSEOP_SCOPE '(' {$$ = TrCreateLeafNode (PARSEOP_SCOPE);} + NameString + ')' '{' + ObjectList '}' {$$ = TrLinkChildren ($3,2,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$7);} + | PARSEOP_SCOPE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ShiftLeftTerm + : PARSEOP_SHIFTLEFT '(' {$$ = TrCreateLeafNode (PARSEOP_SHIFTLEFT);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_SHIFTLEFT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ShiftRightTerm + : PARSEOP_SHIFTRIGHT '(' {$$ = TrCreateLeafNode (PARSEOP_SHIFTRIGHT);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_SHIFTRIGHT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +SignalTerm + : PARSEOP_SIGNAL '(' {$$ = TrCreateLeafNode (PARSEOP_SIGNAL);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_SIGNAL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +SizeOfTerm + : PARSEOP_SIZEOF '(' {$$ = TrCreateLeafNode (PARSEOP_SIZEOF);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_SIZEOF '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +SleepTerm + : PARSEOP_SLEEP '(' {$$ = TrCreateLeafNode (PARSEOP_SLEEP);} + TermArg + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_SLEEP '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +StallTerm + : PARSEOP_STALL '(' {$$ = TrCreateLeafNode (PARSEOP_STALL);} + TermArg + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_STALL '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +StoreTerm + : PARSEOP_STORE '(' {$$ = TrCreateLeafNode (PARSEOP_STORE);} + TermArg + ',' SuperName + ')' {$$ = TrLinkChildren ($3,2,$4,TrSetNodeFlags ($6, NODE_IS_TARGET));} + | PARSEOP_STORE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +SubtractTerm + : PARSEOP_SUBTRACT '(' {$$ = TrCreateLeafNode (PARSEOP_SUBTRACT);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_SUBTRACT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; +SwitchTerm + : PARSEOP_SWITCH '(' {$$ = TrCreateLeafNode (PARSEOP_SWITCH);} + TermArg + ')' '{' + CaseDefaultTermList '}' + {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_SWITCH '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ThermalZoneTerm + : PARSEOP_THERMALZONE '(' {$$ = TrCreateLeafNode (PARSEOP_THERMALZONE);} + NameString + ')' '{' + ObjectList '}' {$$ = TrLinkChildren ($3,2,TrSetNodeFlags ($4, NODE_IS_NAME_DECLARATION),$7);} + | PARSEOP_THERMALZONE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +TimerTerm + : PARSEOP_TIMER '(' {$$ = TrCreateLeafNode (PARSEOP_TIMER);} + ')' {$$ = TrLinkChildren ($3,0);} + | PARSEOP_TIMER {$$ = TrLinkChildren (TrCreateLeafNode (PARSEOP_TIMER),0);} + | PARSEOP_TIMER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToBCDTerm + : PARSEOP_TOBCD '(' {$$ = TrCreateLeafNode (PARSEOP_TOBCD);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_TOBCD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToBufferTerm + : PARSEOP_TOBUFFER '(' {$$ = TrCreateLeafNode (PARSEOP_TOBUFFER);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_TOBUFFER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToDecimalStringTerm + : PARSEOP_TODECIMALSTRING '(' {$$ = TrCreateLeafNode (PARSEOP_TODECIMALSTRING);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_TODECIMALSTRING '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToHexStringTerm + : PARSEOP_TOHEXSTRING '(' {$$ = TrCreateLeafNode (PARSEOP_TOHEXSTRING);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_TOHEXSTRING '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToIntegerTerm + : PARSEOP_TOINTEGER '(' {$$ = TrCreateLeafNode (PARSEOP_TOINTEGER);} + TermArg + Target + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_TOINTEGER '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToPLDTerm + : PARSEOP_TOPLD '(' {$$ = TrCreateLeafNode (PARSEOP_TOPLD);} + PldKeywordList + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_TOPLD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +PldKeywordList + : {$$ = NULL;} + | PldKeyword + PARSEOP_EXP_EQUALS Integer {$$ = TrLinkChildren ($1,1,$3);} + | PldKeyword + PARSEOP_EXP_EQUALS String {$$ = TrLinkChildren ($1,1,$3);} + | PldKeywordList ',' /* Allows a trailing comma at list end */ + | PldKeywordList ',' + PldKeyword + PARSEOP_EXP_EQUALS Integer {$$ = TrLinkPeerNode ($1,TrLinkChildren ($3,1,$5));} + | PldKeywordList ',' + PldKeyword + PARSEOP_EXP_EQUALS String {$$ = TrLinkPeerNode ($1,TrLinkChildren ($3,1,$5));} + ; + + +ToStringTerm + : PARSEOP_TOSTRING '(' {$$ = TrCreateLeafNode (PARSEOP_TOSTRING);} + TermArg + OptionalCount + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_TOSTRING '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +ToUUIDTerm + : PARSEOP_TOUUID '(' + StringData ')' {$$ = TrUpdateNode (PARSEOP_TOUUID, $3);} + | PARSEOP_TOUUID '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +UnicodeTerm + : PARSEOP_UNICODE '(' {$$ = TrCreateLeafNode (PARSEOP_UNICODE);} + StringData + ')' {$$ = TrLinkChildren ($3,2,0,$4);} + | PARSEOP_UNICODE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +UnloadTerm + : PARSEOP_UNLOAD '(' {$$ = TrCreateLeafNode (PARSEOP_UNLOAD);} + SuperName + ')' {$$ = TrLinkChildren ($3,1,$4);} + | PARSEOP_UNLOAD '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +WaitTerm + : PARSEOP_WAIT '(' {$$ = TrCreateLeafNode (PARSEOP_WAIT);} + SuperName + TermArgItem + ')' {$$ = TrLinkChildren ($3,2,$4,$5);} + | PARSEOP_WAIT '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +XOrTerm + : PARSEOP_XOR '(' {$$ = TrCreateLeafNode (PARSEOP_XOR);} + TermArg + TermArgItem + Target + ')' {$$ = TrLinkChildren ($3,3,$4,$5,$6);} + | PARSEOP_XOR '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + +WhileTerm + : PARSEOP_WHILE '(' {$$ = TrCreateLeafNode (PARSEOP_WHILE);} + TermArg + ')' '{' TermList '}' + {$$ = TrLinkChildren ($3,2,$4,$7);} + | PARSEOP_WHILE '(' + error ')' {$$ = AslDoError(); yyclearin;} + ; + + +/******************************************************************************* + * + * ASL Helper Terms + * + ******************************************************************************/ + +AmlPackageLengthTerm + : Integer {$$ = TrUpdateNode (PARSEOP_PACKAGE_LENGTH,(ACPI_PARSE_OBJECT *) $1);} + ; + +NameStringItem + : ',' NameString {$$ = $2;} + | ',' error {$$ = AslDoError (); yyclearin;} + ; + +TermArgItem + : ',' TermArg {$$ = $2;} + | ',' error {$$ = AslDoError (); yyclearin;} + ; + +OptionalReference + : {$$ = TrCreateLeafNode (PARSEOP_ZERO);} /* Placeholder is a ZeroOp object */ + | ',' {$$ = TrCreateLeafNode (PARSEOP_ZERO);} /* Placeholder is a ZeroOp object */ + | ',' TermArg {$$ = $2;} + ; + +OptionalReturnArg + : {$$ = TrSetNodeFlags (TrCreateLeafNode (PARSEOP_ZERO), NODE_IS_NULL_RETURN);} /* Placeholder is a ZeroOp object */ + | TermArg {$$ = $1;} + ; + +OptionalSerializeRuleKeyword + : {$$ = NULL;} + | ',' {$$ = NULL;} + | ',' SerializeRuleKeyword {$$ = $2;} + ; + +OptionalTermArg + : {$$ = NULL;} + | TermArg {$$ = $1;} + ; + +OptionalWordConst + : {$$ = NULL;} + | WordConst {$$ = $1;} + ; diff --git a/third_party/lib/acpica/source/compiler/aslstartup.c b/third_party/lib/acpica/source/compiler/aslstartup.c new file mode 100644 index 000000000..df90ae5fe --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslstartup.c @@ -0,0 +1,525 @@ +/****************************************************************************** + * + * Module Name: aslstartup - Compiler startup routines, called from main + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "actables.h" +#include "acdisasm.h" +#include "acapps.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslstartup") + + +/* Local prototypes */ + +static UINT8 +AslDetectSourceFileType ( + ASL_FILE_INFO *Info); + +static ACPI_STATUS +AslDoDisassembly ( + void); + + +/* Globals */ + +static BOOLEAN AslToFile = TRUE; + + +/******************************************************************************* + * + * FUNCTION: AslInitializeGlobals + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Re-initialize globals needed to restart the compiler. This + * allows multiple files to be disassembled and/or compiled. + * + ******************************************************************************/ + +void +AslInitializeGlobals ( + void) +{ + UINT32 i; + + + /* Init compiler globals */ + + Gbl_SyntaxError = 0; + Gbl_CurrentColumn = 0; + Gbl_CurrentLineNumber = 1; + Gbl_LogicalLineNumber = 1; + Gbl_CurrentLineOffset = 0; + Gbl_InputFieldCount = 0; + Gbl_InputByteCount = 0; + Gbl_NsLookupCount = 0; + Gbl_LineBufPtr = Gbl_CurrentLineBuffer; + + Gbl_ErrorLog = NULL; + Gbl_NextError = NULL; + Gbl_Signature = NULL; + Gbl_FileType = 0; + + TotalExecutableOpcodes = 0; + TotalNamedObjects = 0; + TotalKeywords = 0; + TotalParseNodes = 0; + TotalMethods = 0; + TotalAllocations = 0; + TotalAllocated = 0; + TotalFolds = 0; + + AslGbl_NextEvent = 0; + for (i = 0; i < ASL_NUM_REPORT_LEVELS; i++) + { + Gbl_ExceptionCount[i] = 0; + } + + for (i = ASL_FILE_INPUT; i <= ASL_MAX_FILE_TYPE; i++) + { + Gbl_Files[i].Handle = NULL; + Gbl_Files[i].Filename = NULL; + } +} + + +/******************************************************************************* + * + * FUNCTION: AslDetectSourceFileType + * + * PARAMETERS: Info - Name/Handle for the file (must be open) + * + * RETURN: File Type + * + * DESCRIPTION: Determine the type of the input file. Either binary (contains + * non-ASCII characters), ASL file, or an ACPI Data Table file. + * + ******************************************************************************/ + +static UINT8 +AslDetectSourceFileType ( + ASL_FILE_INFO *Info) +{ + char *FileChar; + UINT8 Type = ASL_INPUT_TYPE_ASCII_DATA; /* default */ + ACPI_STATUS Status; + + + /* Check for 100% ASCII source file (comments are ignored) */ + + Status = FlIsFileAsciiSource (Info->Filename, FALSE); + if (ACPI_SUCCESS (Status)) + { + /* + * File contains ASCII source code. Determine if this is an ASL + * file or an ACPI data table file. + */ + while (fgets (Gbl_CurrentLineBuffer, Gbl_LineBufferSize, Info->Handle)) + { + /* Uppercase the buffer for caseless compare */ + + FileChar = Gbl_CurrentLineBuffer; + while (*FileChar) + { + *FileChar = (char) toupper ((int) *FileChar); + FileChar++; + } + + /* Presence of "DefinitionBlock" indicates actual ASL code */ + + if (strstr (Gbl_CurrentLineBuffer, "DEFINITIONBLOCK")) + { + /* Appears to be an ASL file */ + + Type = ASL_INPUT_TYPE_ASCII_ASL; + goto Cleanup; + } + } + + /* Appears to be an ASCII data table source file */ + + Type = ASL_INPUT_TYPE_ASCII_DATA; + goto Cleanup; + } + + /* We have some sort of binary table, check for valid ACPI table */ + + fseek (Info->Handle, 0, SEEK_SET); + + Status = AcValidateTableHeader (Info->Handle, 0); + if (ACPI_SUCCESS (Status)) + { + fprintf (stderr, + "Binary file appears to be a valid ACPI table, disassembling\n"); + + Type = ASL_INPUT_TYPE_BINARY_ACPI_TABLE; + goto Cleanup; + } + + Type = ASL_INPUT_TYPE_BINARY; + + +Cleanup: + + /* Must seek back to the start of the file */ + + fseek (Info->Handle, 0, SEEK_SET); + return (Type); +} + + +/******************************************************************************* + * + * FUNCTION: AslDoDisassembly + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initiate AML file disassembly. Uses ACPICA subsystem to build + * namespace. + * + ******************************************************************************/ + +static ACPI_STATUS +AslDoDisassembly ( + void) +{ + ACPI_STATUS Status; + + + /* ACPICA subsystem initialization */ + + Status = AdInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiAllocateRootTable (4); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not initialize ACPI Table Manager, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + /* Handle additional output files for disassembler */ + + Gbl_FileType = ASL_INPUT_TYPE_BINARY_ACPI_TABLE; + Status = FlOpenMiscOutputFiles (Gbl_OutputFilenamePrefix); + + /* This is where the disassembly happens */ + + AcpiGbl_DmOpt_Disasm = TRUE; + Status = AdAmlDisassemble (AslToFile, + Gbl_Files[ASL_FILE_INPUT].Filename, Gbl_OutputFilenamePrefix, + &Gbl_Files[ASL_FILE_INPUT].Filename); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Check if any control methods were unresolved */ + + AcpiDmUnresolvedWarning (0); + + /* Shutdown compiler and ACPICA subsystem */ + + AeClearErrorLog (); + (void) AcpiTerminate (); + + /* + * Gbl_Files[ASL_FILE_INPUT].Filename was replaced with the + * .DSL disassembly file, which can now be compiled if requested + */ + if (Gbl_DoCompile) + { + AcpiOsPrintf ("\nCompiling \"%s\"\n", + Gbl_Files[ASL_FILE_INPUT].Filename); + return (AE_CTRL_CONTINUE); + } + + /* No need to free the filename string */ + + Gbl_Files[ASL_FILE_INPUT].Filename = NULL; + + CmDeleteCaches (); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AslDoOneFile + * + * PARAMETERS: Filename - Name of the file + * + * RETURN: Status + * + * DESCRIPTION: Process a single file - either disassemble, compile, or both + * + ******************************************************************************/ + +ACPI_STATUS +AslDoOneFile ( + char *Filename) +{ + ACPI_STATUS Status; + + + /* Re-initialize "some" compiler/preprocessor globals */ + + AslInitializeGlobals (); + PrInitializeGlobals (); + + /* + * Extract the directory path. This path is used for possible include + * files and the optional AML filename embedded in the input file + * DefinitionBlock declaration. + */ + Status = FlSplitInputPathname (Filename, &Gbl_DirectoryPath, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Take a copy of the input filename, convert any backslashes */ + + Gbl_Files[ASL_FILE_INPUT].Filename = + UtStringCacheCalloc (strlen (Filename) + 1); + + strcpy (Gbl_Files[ASL_FILE_INPUT].Filename, Filename); + UtConvertBackslashes (Gbl_Files[ASL_FILE_INPUT].Filename); + + /* + * AML Disassembly (Optional) + */ + if (Gbl_DisasmFlag) + { + Status = AslDoDisassembly (); + if (Status != AE_CTRL_CONTINUE) + { + return (Status); + } + } + + /* + * Open the input file. Here, this should be an ASCII source file, + * either an ASL file or a Data Table file + */ + Status = FlOpenInputFile (Gbl_Files[ASL_FILE_INPUT].Filename); + if (ACPI_FAILURE (Status)) + { + AePrintErrorLog (ASL_FILE_STDERR); + return (AE_ERROR); + } + + Gbl_OriginalInputFileSize = FlGetFileSize (ASL_FILE_INPUT); + + /* Determine input file type */ + + Gbl_FileType = AslDetectSourceFileType (&Gbl_Files[ASL_FILE_INPUT]); + if (Gbl_FileType == ASL_INPUT_TYPE_BINARY) + { + return (AE_ERROR); + } + + /* + * If -p not specified, we will use the input filename as the + * output filename prefix + */ + if (Gbl_UseDefaultAmlFilename) + { + Gbl_OutputFilenamePrefix = Gbl_Files[ASL_FILE_INPUT].Filename; + } + + /* Open the optional output files (listings, etc.) */ + + Status = FlOpenMiscOutputFiles (Gbl_OutputFilenamePrefix); + if (ACPI_FAILURE (Status)) + { + AePrintErrorLog (ASL_FILE_STDERR); + return (AE_ERROR); + } + + /* + * Compilation of ASL source versus DataTable source uses different + * compiler subsystems + */ + switch (Gbl_FileType) + { + /* + * Data Table Compilation + */ + case ASL_INPUT_TYPE_ASCII_DATA: + + Status = DtDoCompile (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Gbl_Signature) + { + Gbl_Signature = NULL; + } + + /* Check if any errors occurred during compile */ + + Status = AslCheckForErrorExit (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Cleanup (for next source file) and exit */ + + AeClearErrorLog (); + PrTerminatePreprocessor (); + return (Status); + + /* + * ASL Compilation + */ + case ASL_INPUT_TYPE_ASCII_ASL: + + /* ACPICA subsystem initialization */ + + Status = AdInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + (void) CmDoCompile (); + (void) AcpiTerminate (); + + /* Check if any errors occurred during compile */ + + Status = AslCheckForErrorExit (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Cleanup (for next source file) and exit */ + + AeClearErrorLog (); + PrTerminatePreprocessor (); + return (AE_OK); + + /* + * Binary ACPI table was auto-detected, disassemble it + */ + case ASL_INPUT_TYPE_BINARY_ACPI_TABLE: + + /* We have what appears to be an ACPI table, disassemble it */ + + FlCloseFile (ASL_FILE_INPUT); + Gbl_DoCompile = FALSE; + Gbl_DisasmFlag = TRUE; + Status = AslDoDisassembly (); + return (Status); + + /* Unknown binary table */ + + case ASL_INPUT_TYPE_BINARY: + + AePrintErrorLog (ASL_FILE_STDERR); + return (AE_ERROR); + + default: + + printf ("Unknown file type %X\n", Gbl_FileType); + return (AE_ERROR); + } +} + + +/******************************************************************************* + * + * FUNCTION: AslCheckForErrorExit + * + * PARAMETERS: None. Examines global exception count array + * + * RETURN: Status + * + * DESCRIPTION: Determine if compiler should abort with error status + * + ******************************************************************************/ + +ACPI_STATUS +AslCheckForErrorExit ( + void) +{ + + /* + * Return non-zero exit code if there have been errors, unless the + * global ignore error flag has been set + */ + if (!Gbl_IgnoreErrors) + { + if (Gbl_ExceptionCount[ASL_ERROR] > 0) + { + return (AE_ERROR); + } + + /* Optionally treat warnings as errors */ + + if (Gbl_WarningsAsErrors) + { + if ((Gbl_ExceptionCount[ASL_WARNING] > 0) || + (Gbl_ExceptionCount[ASL_WARNING2] > 0) || + (Gbl_ExceptionCount[ASL_WARNING3] > 0)) + { + return (AE_ERROR); + } + } + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/aslstubs.c b/third_party/lib/acpica/source/compiler/aslstubs.c new file mode 100644 index 000000000..e57df5e69 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslstubs.c @@ -0,0 +1,314 @@ +/****************************************************************************** + * + * Module Name: aslstubs - Stubs used to link to Aml interpreter + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acdispat.h" +#include "actables.h" +#include "acevents.h" +#include "acinterp.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslstubs") + + +/* + * Stubs to simplify linkage to the ACPICA core subsystem. + * Things like Events, Global Lock, etc. are not used + * by the compiler, so they are stubbed out here. + */ +void +AcpiNsExecModuleCodeList ( + void) +{ +} + +ACPI_STATUS +AcpiHwReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiHwWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState) +{ + return (Status); +} + +ACPI_STATUS +AcpiDsMethodDataGetValue ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **DestDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsMethodDataGetNode ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **Node) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsStoreObjectToLocal ( + UINT8 Type, + UINT32 Index, + ACPI_OPERAND_OBJECT *SrcDesc, + ACPI_WALK_STATE *WalkState) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvQueueNotifyRequest ( + ACPI_NAMESPACE_NODE *Node, + UINT32 NotifyValue) +{ + return (AE_OK); +} + +BOOLEAN +AcpiEvIsNotifyObject ( + ACPI_NAMESPACE_NODE *Node) +{ + return (FALSE); +} + +#if (!ACPI_REDUCED_HARDWARE) +ACPI_STATUS +AcpiEvDeleteGpeBlock ( + ACPI_GPE_BLOCK_INFO *GpeBlock) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvAcquireGlobalLock ( + UINT16 Timeout) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvReleaseGlobalLock ( + void) +{ + return (AE_OK); +} +#endif /* !ACPI_REDUCED_HARDWARE */ + +ACPI_STATUS +AcpiEvInitializeRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsLocked) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiExReadDataFromField ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **RetBufferDesc) +{ + return (AE_SUPPORT); +} + +ACPI_STATUS +AcpiExWriteDataToField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc) +{ + return (AE_SUPPORT); +} + +ACPI_STATUS +AcpiExLoadTableOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **ReturnDesc) +{ + return (AE_SUPPORT); +} + +ACPI_STATUS +AcpiExUnloadTable ( + ACPI_OPERAND_OBJECT *DdbHandle) +{ + return (AE_SUPPORT); +} + +ACPI_STATUS +AcpiExLoadOp ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *Target, + ACPI_WALK_STATE *WalkState) +{ + return (AE_SUPPORT); +} + +void +AcpiExDoDebugObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + UINT32 Level, + UINT32 Index) +{ + return; +} + +void +AcpiExStartTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +void +AcpiExStopTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +void +AcpiExStartTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +void +AcpiExStopTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) + +{ + return; +} + +void +AcpiExTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname) +{ + return; +} + +ACPI_STATUS +AcpiTbFindTable ( + char *Signature, + char *OemId, + char *OemTableId, + UINT32 *TableIndex) +{ + return (AE_SUPPORT); +} + +ACPI_STATUS +AcpiNsLoadTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *Node) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiDsRestartControlMethod ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ReturnDesc) +{ + return (AE_OK); +} + +void +AcpiDsTerminateControlMethod ( + ACPI_OPERAND_OBJECT *MethodDesc, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +ACPI_STATUS +AcpiDsCallControlMethod ( + ACPI_THREAD_STATE *Thread, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsMethodDataInitArgs ( + ACPI_OPERAND_OBJECT **Params, + UINT32 MaxParamCount, + ACPI_WALK_STATE *WalkState) +{ + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/aslsupport.l b/third_party/lib/acpica/source/compiler/aslsupport.l new file mode 100644 index 000000000..deb9e9a31 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslsupport.l @@ -0,0 +1,852 @@ +/****************************************************************************** + * + * Module Name: aslsupport.l - Flex/lex scanner C support routines. + * NOTE: Included into aslcompile.l, not compiled by itself. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* Configuration */ + +#define ASL_SPACES_PER_TAB 4 + +#define ASL_NORMAL_CHAR 0 +#define ASL_ESCAPE_SEQUENCE 1 +#define ASL_OCTAL_CONSTANT 2 +#define ASL_HEX_CONSTANT 3 + + +/* File node - used for "Include" operator file stack */ + +typedef struct asl_file_node +{ + FILE *File; + UINT32 CurrentLineNumber; + YY_BUFFER_STATE State; + char *Filename; + struct asl_file_node *Next; + +} ASL_FILE_NODE; + +/* File stack for the "Include" operator (NOT #include operator) */ + +ASL_FILE_NODE *Gbl_IncludeFileStack = NULL; + + +/******************************************************************************* + * + * FUNCTION: AslParserCleanup + * + * Used to delete the current buffer + * + ******************************************************************************/ + +void +AslParserCleanup ( + void) +{ + + yy_delete_buffer (YY_CURRENT_BUFFER); +} + + +/******************************************************************************* + * + * FUNCTION: AslDoLineDirective + * + * PARAMETERS: None. Uses input() to access current source code line + * + * RETURN: Updates global line number and filename + * + * DESCRIPTION: Handle #line directives emitted by the preprocessor. + * + * The #line directive is emitted by the preprocesser, and is used to + * pass through line numbers from the original source code file to the + * preprocessor output file (.i). This allows any compiler-generated + * error messages to be displayed with the correct line number. + * + ******************************************************************************/ + +static void +AslDoLineDirective ( + void) +{ + int c; + char *Token; + UINT32 LineNumber; + char *Filename; + UINT32 i; + + Gbl_HasIncludeFiles = TRUE; + + /* Eat the entire line that contains the #line directive */ + + Gbl_LineBufPtr = Gbl_CurrentLineBuffer; + + while ((c = input()) != '\n' && c != EOF) + { + *Gbl_LineBufPtr = c; + Gbl_LineBufPtr++; + } + *Gbl_LineBufPtr = 0; + + /* First argument is the actual line number */ + + Token = strtok (Gbl_CurrentLineBuffer, " "); + if (!Token) + { + goto ResetAndExit; + } + + /* First argument is the line number */ + + LineNumber = (UINT32) UtDoConstant (Token); + + /* Emit the appropriate number of newlines */ + + Gbl_CurrentColumn = 0; + if (LineNumber > Gbl_CurrentLineNumber) + { + for (i = 0; i < (LineNumber - Gbl_CurrentLineNumber); i++) + { + FlWriteFile (ASL_FILE_SOURCE_OUTPUT, "\n", 1); + Gbl_CurrentColumn++; + } + } + + FlSetLineNumber (LineNumber); + + /* Second argument is the optional filename (in double quotes) */ + + Token = strtok (NULL, " \""); + if (Token) + { + Filename = ACPI_ALLOCATE_ZEROED (strlen (Token) + 1); + strcpy (Filename, Token); + FlSetFilename (Filename); + } + + /* Third argument is not supported at this time */ + +ResetAndExit: + + /* Reset globals for a new line */ + + Gbl_CurrentLineOffset += Gbl_CurrentColumn; + Gbl_CurrentColumn = 0; + Gbl_LineBufPtr = Gbl_CurrentLineBuffer; +} + + +/******************************************************************************* + * + * FUNCTION: AslPopInputFileStack + * + * PARAMETERS: None + * + * RETURN: 0 if a node was popped, -1 otherwise + * + * DESCRIPTION: Pop the top of the input file stack and point the parser to + * the saved parse buffer contained in the fnode. Also, set the + * global line counters to the saved values. This function is + * called when an include file reaches EOF. + * + ******************************************************************************/ + +int +AslPopInputFileStack ( + void) +{ + ASL_FILE_NODE *Fnode; + + + Gbl_PreviousIncludeFilename = Gbl_Files[ASL_FILE_INPUT].Filename; + Fnode = Gbl_IncludeFileStack; + DbgPrint (ASL_PARSE_OUTPUT, + "\nPop InputFile Stack, Fnode %p\n", Fnode); + + DbgPrint (ASL_PARSE_OUTPUT, + "Include: Closing \"%s\"\n\n", Gbl_Files[ASL_FILE_INPUT].Filename); + + if (!Fnode) + { + return (-1); + } + + /* Close the current include file */ + + fclose (yyin); + + /* Update the top-of-stack */ + + Gbl_IncludeFileStack = Fnode->Next; + + /* Reset global line counter and filename */ + + Gbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename; + Gbl_CurrentLineNumber = Fnode->CurrentLineNumber; + + /* Point the parser to the popped file */ + + yy_delete_buffer (YY_CURRENT_BUFFER); + yy_switch_to_buffer (Fnode->State); + + /* All done with this node */ + + ACPI_FREE (Fnode); + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AslPushInputFileStack + * + * PARAMETERS: InputFile - Open file pointer + * Filename - Name of the file + * + * RETURN: None + * + * DESCRIPTION: Push the InputFile onto the file stack, and point the parser + * to this file. Called when an include file is successfully + * opened. + * + ******************************************************************************/ + +void +AslPushInputFileStack ( + FILE *InputFile, + char *Filename) +{ + ASL_FILE_NODE *Fnode; + YY_BUFFER_STATE State; + + + /* Save the current state in an Fnode */ + + Fnode = UtLocalCalloc (sizeof (ASL_FILE_NODE)); + + Fnode->File = yyin; + Fnode->Next = Gbl_IncludeFileStack; + Fnode->State = YY_CURRENT_BUFFER; + Fnode->Filename = Gbl_Files[ASL_FILE_INPUT].Filename; + Fnode->CurrentLineNumber = Gbl_CurrentLineNumber; + + /* Push it on the stack */ + + Gbl_IncludeFileStack = Fnode; + + /* Point the parser to this file */ + + State = yy_create_buffer (InputFile, YY_BUF_SIZE); + yy_switch_to_buffer (State); + + DbgPrint (ASL_PARSE_OUTPUT, + "\nPush InputFile Stack, returning %p\n\n", InputFile); + + /* Reset the global line count and filename */ + + Gbl_Files[ASL_FILE_INPUT].Filename = + UtStringCacheCalloc (strlen (Filename) + 1); + + strcpy (Gbl_Files[ASL_FILE_INPUT].Filename, Filename); + + Gbl_CurrentLineNumber = 1; + yyin = InputFile; +} + + +/******************************************************************************* + * + * FUNCTION: AslResetCurrentLineBuffer + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Reset the Line Buffer to zero, increment global line numbers. + * + ******************************************************************************/ + +void +AslResetCurrentLineBuffer ( + void) +{ + + if (Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Handle) + { + FlWriteFile (ASL_FILE_SOURCE_OUTPUT, Gbl_CurrentLineBuffer, + Gbl_LineBufPtr - Gbl_CurrentLineBuffer); + } + + Gbl_CurrentLineOffset += Gbl_CurrentColumn; + Gbl_CurrentColumn = 0; + + Gbl_CurrentLineNumber++; + Gbl_LogicalLineNumber++; + Gbl_LineBufPtr = Gbl_CurrentLineBuffer; +} + + +/******************************************************************************* + * + * FUNCTION: AslInsertLineBuffer + * + * PARAMETERS: SourceChar - One char from the input ASL source file + * + * RETURN: None + * + * DESCRIPTION: Put one character of the source file into the temp line buffer + * + ******************************************************************************/ + +void +AslInsertLineBuffer ( + int SourceChar) +{ + UINT32 i; + UINT32 Count = 1; + + + if (SourceChar == EOF) + { + return; + } + + Gbl_InputByteCount++; + + /* Handle tabs. Convert to spaces */ + + if (SourceChar == '\t') + { + SourceChar = ' '; + Count = ASL_SPACES_PER_TAB - + (Gbl_CurrentColumn & (ASL_SPACES_PER_TAB-1)); + } + + for (i = 0; i < Count; i++) + { + Gbl_CurrentColumn++; + + /* Insert the character into the line buffer */ + + *Gbl_LineBufPtr = (UINT8) SourceChar; + Gbl_LineBufPtr++; + + if (Gbl_LineBufPtr > + (Gbl_CurrentLineBuffer + (Gbl_LineBufferSize - 1))) + { +#if 0 + /* + * Warning if we have split a long source line. + * + */ + sprintf (MsgBuffer, "Max %u", Gbl_LineBufferSize); + AslCommonError (ASL_WARNING, ASL_MSG_LONG_LINE, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, MsgBuffer); +#endif + + AslResetCurrentLineBuffer (); + } + else if (SourceChar == '\n') + { + /* End of line */ + + AslResetCurrentLineBuffer (); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: count + * + * PARAMETERS: yytext - Contains the matched keyword. + * Type - Keyword/Character type: + * 0 = anything except a keyword + * 1 = pseudo-keywords + * 2 = non-executable ASL keywords + * 3 = executable ASL keywords + * + * RETURN: None + * + * DESCRIPTION: Count keywords and put them into the line buffer + * + ******************************************************************************/ + +static void +count ( + int Type) +{ + int i; + + + switch (Type) + { + case 2: + + TotalKeywords++; + TotalNamedObjects++; + break; + + case 3: + + TotalKeywords++; + TotalExecutableOpcodes++; + break; + + default: + + break; + } + + for (i = 0; (yytext[i] != 0) && (yytext[i] != EOF); i++) + { + AslInsertLineBuffer (yytext[i]); + *Gbl_LineBufPtr = 0; + } +} + + +/******************************************************************************* + * + * FUNCTION: AslDoComment + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Process a standard comment. + * + ******************************************************************************/ + +static char +AslDoComment ( + void) +{ + int c; + int c1 = 0; + + + AslInsertLineBuffer ('/'); + AslInsertLineBuffer ('*'); + +loop: + + /* Eat chars until end-of-comment */ + + while (((c = input ()) != '*') && (c != EOF)) + { + AslInsertLineBuffer (c); + c1 = c; + } + + if (c == EOF) + { + goto EarlyEOF; + } + + /* + * Check for nested comment -- can help catch cases where a previous + * comment was accidently left unterminated + */ + if ((c1 == '/') && (c == '*')) + { + AslCommonError (ASL_WARNING, ASL_MSG_NESTED_COMMENT, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_InputByteCount, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + } + + /* Comment is closed only if the NEXT character is a slash */ + + AslInsertLineBuffer (c); + + if (((c1 = input ()) != '/') && (c1 != EOF)) + { + unput(c1); + goto loop; + } + + if (c1 == EOF) + { + goto EarlyEOF; + } + + AslInsertLineBuffer (c1); + return (TRUE); + + +EarlyEOF: + /* + * Premature End-Of-File + */ + AslCommonError (ASL_ERROR, ASL_MSG_EARLY_EOF, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AslDoCommentType2 + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Process a new "//" comment. + * + ******************************************************************************/ + +static char +AslDoCommentType2 ( + void) +{ + int c; + + + AslInsertLineBuffer ('/'); + AslInsertLineBuffer ('/'); + + while (((c = input ()) != '\n') && (c != EOF)) + { + AslInsertLineBuffer (c); + } + + if (c == EOF) + { + /* End of file is OK, change to newline. Let parser detect EOF later */ + + c = '\n'; + } + + AslInsertLineBuffer (c); + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AslDoStringLiteral + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Process a string literal (surrounded by quotes) + * + ******************************************************************************/ + +static char +AslDoStringLiteral ( + void) +{ + char *StringBuffer = MsgBuffer; + char *EndBuffer = MsgBuffer + ASL_MSG_BUFFER_SIZE; + char *CleanString; + int StringChar; + UINT32 State = ASL_NORMAL_CHAR; + UINT32 i = 0; + UINT8 Digit; + char ConvertBuffer[4]; + + + /* + * Eat chars until end-of-literal. + * NOTE: Put back the original surrounding quotes into the + * source line buffer. + */ + AslInsertLineBuffer ('\"'); + while ((StringChar = input()) != EOF) + { + AslInsertLineBuffer (StringChar); + +DoCharacter: + switch (State) + { + case ASL_NORMAL_CHAR: + + switch (StringChar) + { + case '\\': + /* + * Special handling for backslash-escape sequence. We will + * toss the backslash and translate the escape char(s). + */ + State = ASL_ESCAPE_SEQUENCE; + continue; + + case '\"': + + /* String terminator */ + + goto CompletedString; + + default: + + break; + } + break; + + + case ASL_ESCAPE_SEQUENCE: + + State = ASL_NORMAL_CHAR; + switch (StringChar) + { + case 'a': + + StringChar = 0x07; /* BELL */ + break; + + case 'b': + + StringChar = 0x08; /* BACKSPACE */ + break; + + case 'f': + + StringChar = 0x0C; /* FORMFEED */ + break; + + case 'n': + + StringChar = 0x0A; /* LINEFEED */ + break; + + case 'r': + + StringChar = 0x0D; /* CARRIAGE RETURN*/ + break; + + case 't': + + StringChar = 0x09; /* HORIZONTAL TAB */ + break; + + case 'v': + + StringChar = 0x0B; /* VERTICAL TAB */ + break; + + case 'x': + + State = ASL_HEX_CONSTANT; + i = 0; + continue; + + case '\'': /* Single Quote */ + case '\"': /* Double Quote */ + case '\\': /* Backslash */ + + break; + + default: + + /* Check for an octal digit (0-7) */ + + if (ACPI_IS_OCTAL_DIGIT (StringChar)) + { + State = ASL_OCTAL_CONSTANT; + ConvertBuffer[0] = StringChar; + i = 1; + continue; + } + + /* Unknown escape sequence issue warning, but use the character */ + + AslCommonError (ASL_WARNING, ASL_MSG_INVALID_ESCAPE, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + break; + } + break; + + + case ASL_OCTAL_CONSTANT: + + /* Up to three octal digits allowed */ + + if (!ACPI_IS_OCTAL_DIGIT (StringChar) || + (i > 2)) + { + /* + * Reached end of the constant. Convert the assembled ASCII + * string and resume processing of the next character + */ + ConvertBuffer[i] = 0; + Digit = (UINT8) strtoul (ConvertBuffer, NULL, 8); + + /* Check for NULL or non-ascii character (ignore if so) */ + + if ((Digit == 0) || (Digit > ACPI_ASCII_MAX)) + { + AslCommonError (ASL_WARNING, ASL_MSG_INVALID_STRING, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + } + else + { + *StringBuffer = (char) Digit; + StringBuffer++; + if (StringBuffer >= EndBuffer) + { + goto BufferOverflow; + } + } + + State = ASL_NORMAL_CHAR; + goto DoCharacter; + break; + } + + /* Append another digit of the constant */ + + ConvertBuffer[i] = StringChar; + i++; + continue; + + case ASL_HEX_CONSTANT: + + /* Up to two hex digits allowed */ + + if (!isxdigit (StringChar) || + (i > 1)) + { + /* + * Reached end of the constant. Convert the assembled ASCII + * string and resume processing of the next character + */ + ConvertBuffer[i] = 0; + Digit = (UINT8) strtoul (ConvertBuffer, NULL, 16); + + /* Check for NULL or non-ascii character (ignore if so) */ + + if ((Digit == 0) || (Digit > ACPI_ASCII_MAX)) + { + AslCommonError (ASL_WARNING, ASL_MSG_INVALID_STRING, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + } + else + { + *StringBuffer = (char) Digit; + StringBuffer++; + if (StringBuffer >= EndBuffer) + { + goto BufferOverflow; + } + } + + State = ASL_NORMAL_CHAR; + goto DoCharacter; + break; + } + + /* Append another digit of the constant */ + + ConvertBuffer[i] = StringChar; + i++; + continue; + + default: + + break; + } + + /* Save the finished character */ + + *StringBuffer = StringChar; + StringBuffer++; + if (StringBuffer >= EndBuffer) + { + goto BufferOverflow; + } + } + + /* + * Premature End-Of-File + */ + AslCommonError (ASL_ERROR, ASL_MSG_EARLY_EOF, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + return (FALSE); + + +CompletedString: + /* + * Null terminate the input string and copy string to a new buffer + */ + *StringBuffer = 0; + + CleanString = UtStringCacheCalloc (strlen (MsgBuffer) + 1); + if (!CleanString) + { + AslCommonError (ASL_ERROR, ASL_MSG_MEMORY_ALLOCATION, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + return (FALSE); + } + + strcpy (CleanString, MsgBuffer); + AslCompilerlval.s = CleanString; + return (TRUE); + + +BufferOverflow: + + /* Literal was too long */ + + AslCommonError (ASL_ERROR, ASL_MSG_STRING_LENGTH, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_CurrentLineOffset, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, "Max length 4096"); + return (FALSE); +} diff --git a/third_party/lib/acpica/source/compiler/aslsupport.y b/third_party/lib/acpica/source/compiler/aslsupport.y new file mode 100644 index 000000000..cd2605b83 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslsupport.y @@ -0,0 +1,120 @@ +NoEcho(' +/****************************************************************************** + * + * Module Name: aslsupport.y - Bison/Yacc C support functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +') + +/****************************************************************************** + * + * Local support functions + * + *****************************************************************************/ + +/*! [Begin] no source code translation */ +int +AslCompilerwrap(void) +{ + return (1); +} +/*! [End] no source code translation !*/ + + +void * +AslLocalAllocate ( + unsigned int Size) +{ + void *Mem; + + + DbgPrint (ASL_PARSE_OUTPUT, + "\nAslLocalAllocate: Expanding Stack to %u\n\n", Size); + + Mem = ACPI_ALLOCATE_ZEROED (Size); + if (!Mem) + { + AslCommonError (ASL_ERROR, ASL_MSG_MEMORY_ALLOCATION, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_InputByteCount, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + exit (1); + } + + return (Mem); +} + +ACPI_PARSE_OBJECT * +AslDoError ( + void) +{ + + return (TrCreateLeafNode (PARSEOP_ERRORNODE)); +} + + +/******************************************************************************* + * + * FUNCTION: UtGetOpName + * + * PARAMETERS: ParseOpcode - Parser keyword ID + * + * RETURN: Pointer to the opcode name + * + * DESCRIPTION: Get the ascii name of the parse opcode + * + ******************************************************************************/ + +char * +UtGetOpName ( + UINT32 ParseOpcode) +{ +#ifdef ASL_YYTNAME_START + /* + * First entries (ASL_YYTNAME_START) in yytname are special reserved names. + * Ignore first 8 characters of the name + */ + return ((char *) yytname + [(ParseOpcode - ASL_FIRST_PARSE_OPCODE) + ASL_YYTNAME_START] + 8); +#else + return ("[Unknown parser generator]"); +#endif +} diff --git a/third_party/lib/acpica/source/compiler/asltokens.y b/third_party/lib/acpica/source/compiler/asltokens.y new file mode 100644 index 000000000..e7b161eeb --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asltokens.y @@ -0,0 +1,477 @@ +NoEcho(' +/****************************************************************************** + * + * Module Name: asltokens.y - Bison/Yacc token types + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +') + +/****************************************************************************** + * + * Token types: These are returned by the lexer + * + * NOTE: This list MUST match the AslKeywordMapping table found + * in aslmap.c EXACTLY! Double check any changes! + * + *****************************************************************************/ + +%token PARSEOP_ACCESSAS +%token PARSEOP_ACCESSATTRIB_BLOCK +%token PARSEOP_ACCESSATTRIB_BLOCK_CALL +%token PARSEOP_ACCESSATTRIB_BYTE +%token PARSEOP_ACCESSATTRIB_MULTIBYTE +%token PARSEOP_ACCESSATTRIB_QUICK +%token PARSEOP_ACCESSATTRIB_RAW_BYTES +%token PARSEOP_ACCESSATTRIB_RAW_PROCESS +%token PARSEOP_ACCESSATTRIB_SND_RCV +%token PARSEOP_ACCESSATTRIB_WORD +%token PARSEOP_ACCESSATTRIB_WORD_CALL +%token PARSEOP_ACCESSTYPE_ANY +%token PARSEOP_ACCESSTYPE_BUF +%token PARSEOP_ACCESSTYPE_BYTE +%token PARSEOP_ACCESSTYPE_DWORD +%token PARSEOP_ACCESSTYPE_QWORD +%token PARSEOP_ACCESSTYPE_WORD +%token PARSEOP_ACQUIRE +%token PARSEOP_ADD +%token PARSEOP_ADDRESSINGMODE_7BIT +%token PARSEOP_ADDRESSINGMODE_10BIT +%token PARSEOP_ADDRESSTYPE_ACPI +%token PARSEOP_ADDRESSTYPE_MEMORY +%token PARSEOP_ADDRESSTYPE_NVS +%token PARSEOP_ADDRESSTYPE_RESERVED +%token PARSEOP_ALIAS +%token PARSEOP_AND +%token PARSEOP_ARG0 +%token PARSEOP_ARG1 +%token PARSEOP_ARG2 +%token PARSEOP_ARG3 +%token PARSEOP_ARG4 +%token PARSEOP_ARG5 +%token PARSEOP_ARG6 +%token PARSEOP_BANKFIELD +%token PARSEOP_BITSPERBYTE_EIGHT +%token PARSEOP_BITSPERBYTE_FIVE +%token PARSEOP_BITSPERBYTE_NINE +%token PARSEOP_BITSPERBYTE_SEVEN +%token PARSEOP_BITSPERBYTE_SIX +%token PARSEOP_BREAK +%token PARSEOP_BREAKPOINT +%token PARSEOP_BUFFER +%token PARSEOP_BUSMASTERTYPE_MASTER +%token PARSEOP_BUSMASTERTYPE_NOTMASTER +%token PARSEOP_BYTECONST +%token PARSEOP_CASE +%token PARSEOP_CLOCKPHASE_FIRST +%token PARSEOP_CLOCKPHASE_SECOND +%token PARSEOP_CLOCKPOLARITY_HIGH +%token PARSEOP_CLOCKPOLARITY_LOW +%token PARSEOP_CONCATENATE +%token PARSEOP_CONCATENATERESTEMPLATE +%token PARSEOP_CONDREFOF +%token PARSEOP_CONNECTION +%token PARSEOP_CONTINUE +%token PARSEOP_COPYOBJECT +%token PARSEOP_CREATEBITFIELD +%token PARSEOP_CREATEBYTEFIELD +%token PARSEOP_CREATEDWORDFIELD +%token PARSEOP_CREATEFIELD +%token PARSEOP_CREATEQWORDFIELD +%token PARSEOP_CREATEWORDFIELD +%token PARSEOP_DATABUFFER +%token PARSEOP_DATATABLEREGION +%token PARSEOP_DEBUG +%token PARSEOP_DECODETYPE_POS +%token PARSEOP_DECODETYPE_SUB +%token PARSEOP_DECREMENT +%token PARSEOP_DEFAULT +%token PARSEOP_DEFAULT_ARG +%token PARSEOP_DEFINITION_BLOCK +%token PARSEOP_DEREFOF +%token PARSEOP_DEVICE +%token PARSEOP_DEVICEPOLARITY_HIGH +%token PARSEOP_DEVICEPOLARITY_LOW +%token PARSEOP_DIVIDE +%token PARSEOP_DMA +%token PARSEOP_DMATYPE_A +%token PARSEOP_DMATYPE_COMPATIBILITY +%token PARSEOP_DMATYPE_B +%token PARSEOP_DMATYPE_F +%token PARSEOP_DWORDCONST +%token PARSEOP_DWORDIO +%token PARSEOP_DWORDMEMORY +%token PARSEOP_DWORDSPACE +%token PARSEOP_EISAID +%token PARSEOP_ELSE +%token PARSEOP_ELSEIF +%token PARSEOP_ENDDEPENDENTFN +%token PARSEOP_ENDIAN_BIG +%token PARSEOP_ENDIAN_LITTLE +%token PARSEOP_ENDTAG +%token PARSEOP_ERRORNODE +%token PARSEOP_EVENT +%token PARSEOP_EXTENDEDIO +%token PARSEOP_EXTENDEDMEMORY +%token PARSEOP_EXTENDEDSPACE +%token PARSEOP_EXTERNAL +%token PARSEOP_FATAL +%token PARSEOP_FIELD +%token PARSEOP_FINDSETLEFTBIT +%token PARSEOP_FINDSETRIGHTBIT +%token PARSEOP_FIXEDDMA +%token PARSEOP_FIXEDIO +%token PARSEOP_FLOWCONTROL_HW +%token PARSEOP_FLOWCONTROL_NONE +%token PARSEOP_FLOWCONTROL_SW +%token PARSEOP_FROMBCD +%token PARSEOP_FUNCTION +%token PARSEOP_GPIO_INT +%token PARSEOP_GPIO_IO +%token PARSEOP_I2C_SERIALBUS +%token PARSEOP_IF +%token PARSEOP_INCLUDE +%token PARSEOP_INCLUDE_END +%token PARSEOP_INCREMENT +%token PARSEOP_INDEX +%token PARSEOP_INDEXFIELD +%token PARSEOP_INTEGER +%token PARSEOP_INTERRUPT +%token PARSEOP_INTLEVEL_ACTIVEBOTH +%token PARSEOP_INTLEVEL_ACTIVEHIGH +%token PARSEOP_INTLEVEL_ACTIVELOW +%token PARSEOP_INTTYPE_EDGE +%token PARSEOP_INTTYPE_LEVEL +%token PARSEOP_IO +%token PARSEOP_IODECODETYPE_10 +%token PARSEOP_IODECODETYPE_16 +%token PARSEOP_IORESTRICT_IN +%token PARSEOP_IORESTRICT_NONE +%token PARSEOP_IORESTRICT_OUT +%token PARSEOP_IORESTRICT_PRESERVE +%token PARSEOP_IRQ +%token PARSEOP_IRQNOFLAGS +%token PARSEOP_LAND +%token PARSEOP_LEQUAL +%token PARSEOP_LGREATER +%token PARSEOP_LGREATEREQUAL +%token PARSEOP_LLESS +%token PARSEOP_LLESSEQUAL +%token PARSEOP_LNOT +%token PARSEOP_LNOTEQUAL +%token PARSEOP_LOAD +%token PARSEOP_LOADTABLE +%token PARSEOP_LOCAL0 +%token PARSEOP_LOCAL1 +%token PARSEOP_LOCAL2 +%token PARSEOP_LOCAL3 +%token PARSEOP_LOCAL4 +%token PARSEOP_LOCAL5 +%token PARSEOP_LOCAL6 +%token PARSEOP_LOCAL7 +%token PARSEOP_LOCKRULE_LOCK +%token PARSEOP_LOCKRULE_NOLOCK +%token PARSEOP_LOR +%token PARSEOP_MATCH +%token PARSEOP_MATCHTYPE_MEQ +%token PARSEOP_MATCHTYPE_MGE +%token PARSEOP_MATCHTYPE_MGT +%token PARSEOP_MATCHTYPE_MLE +%token PARSEOP_MATCHTYPE_MLT +%token PARSEOP_MATCHTYPE_MTR +%token PARSEOP_MAXTYPE_FIXED +%token PARSEOP_MAXTYPE_NOTFIXED +%token PARSEOP_MEMORY24 +%token PARSEOP_MEMORY32 +%token PARSEOP_MEMORY32FIXED +%token PARSEOP_MEMTYPE_CACHEABLE +%token PARSEOP_MEMTYPE_NONCACHEABLE +%token PARSEOP_MEMTYPE_PREFETCHABLE +%token PARSEOP_MEMTYPE_WRITECOMBINING +%token PARSEOP_METHOD +%token PARSEOP_METHODCALL +%token PARSEOP_MID +%token PARSEOP_MINTYPE_FIXED +%token PARSEOP_MINTYPE_NOTFIXED +%token PARSEOP_MOD +%token PARSEOP_MULTIPLY +%token PARSEOP_MUTEX +%token PARSEOP_NAME +%token PARSEOP_NAMESEG +%token PARSEOP_NAMESTRING +%token PARSEOP_NAND +%token PARSEOP_NOOP +%token PARSEOP_NOR +%token PARSEOP_NOT +%token PARSEOP_NOTIFY +%token PARSEOP_OBJECTTYPE +%token PARSEOP_OBJECTTYPE_BFF +%token PARSEOP_OBJECTTYPE_BUF +%token PARSEOP_OBJECTTYPE_DDB +%token PARSEOP_OBJECTTYPE_DEV +%token PARSEOP_OBJECTTYPE_EVT +%token PARSEOP_OBJECTTYPE_FLD +%token PARSEOP_OBJECTTYPE_INT +%token PARSEOP_OBJECTTYPE_MTH +%token PARSEOP_OBJECTTYPE_MTX +%token PARSEOP_OBJECTTYPE_OPR +%token PARSEOP_OBJECTTYPE_PKG +%token PARSEOP_OBJECTTYPE_POW +%token PARSEOP_OBJECTTYPE_PRO +%token PARSEOP_OBJECTTYPE_STR +%token PARSEOP_OBJECTTYPE_THZ +%token PARSEOP_OBJECTTYPE_UNK +%token PARSEOP_OFFSET +%token PARSEOP_ONE +%token PARSEOP_ONES +%token PARSEOP_OPERATIONREGION +%token PARSEOP_OR +%token PARSEOP_PACKAGE +%token PARSEOP_PACKAGE_LENGTH +%token PARSEOP_PARITYTYPE_EVEN +%token PARSEOP_PARITYTYPE_MARK +%token PARSEOP_PARITYTYPE_NONE +%token PARSEOP_PARITYTYPE_ODD +%token PARSEOP_PARITYTYPE_SPACE +%token PARSEOP_PIN_NOPULL +%token PARSEOP_PIN_PULLDEFAULT +%token PARSEOP_PIN_PULLDOWN +%token PARSEOP_PIN_PULLUP +%token PARSEOP_POWERRESOURCE +%token PARSEOP_PROCESSOR +%token PARSEOP_QWORDCONST +%token PARSEOP_QWORDIO +%token PARSEOP_QWORDMEMORY +%token PARSEOP_QWORDSPACE +%token PARSEOP_RANGETYPE_ENTIRE +%token PARSEOP_RANGETYPE_ISAONLY +%token PARSEOP_RANGETYPE_NONISAONLY +%token PARSEOP_RAW_DATA +%token PARSEOP_READWRITETYPE_BOTH +%token PARSEOP_READWRITETYPE_READONLY +%token PARSEOP_REFOF +%token PARSEOP_REGIONSPACE_CMOS +%token PARSEOP_REGIONSPACE_EC +%token PARSEOP_REGIONSPACE_FFIXEDHW +%token PARSEOP_REGIONSPACE_GPIO +%token PARSEOP_REGIONSPACE_GSBUS +%token PARSEOP_REGIONSPACE_IO +%token PARSEOP_REGIONSPACE_IPMI +%token PARSEOP_REGIONSPACE_MEM +%token PARSEOP_REGIONSPACE_PCC +%token PARSEOP_REGIONSPACE_PCI +%token PARSEOP_REGIONSPACE_PCIBAR +%token PARSEOP_REGIONSPACE_SMBUS +%token PARSEOP_REGISTER +%token PARSEOP_RELEASE +%token PARSEOP_RESERVED_BYTES +%token PARSEOP_RESET +%token PARSEOP_RESOURCETEMPLATE +%token PARSEOP_RESOURCETYPE_CONSUMER +%token PARSEOP_RESOURCETYPE_PRODUCER +%token PARSEOP_RETURN +%token PARSEOP_REVISION +%token PARSEOP_SCOPE +%token PARSEOP_SERIALIZERULE_NOTSERIAL +%token PARSEOP_SERIALIZERULE_SERIAL +%token PARSEOP_SHARETYPE_EXCLUSIVE +%token PARSEOP_SHARETYPE_EXCLUSIVEWAKE +%token PARSEOP_SHARETYPE_SHARED +%token PARSEOP_SHARETYPE_SHAREDWAKE +%token PARSEOP_SHIFTLEFT +%token PARSEOP_SHIFTRIGHT +%token PARSEOP_SIGNAL +%token PARSEOP_SIZEOF +%token PARSEOP_SLAVEMODE_CONTROLLERINIT +%token PARSEOP_SLAVEMODE_DEVICEINIT +%token PARSEOP_SLEEP +%token PARSEOP_SPI_SERIALBUS +%token PARSEOP_STALL +%token PARSEOP_STARTDEPENDENTFN +%token PARSEOP_STARTDEPENDENTFN_NOPRI +%token PARSEOP_STOPBITS_ONE +%token PARSEOP_STOPBITS_ONEPLUSHALF +%token PARSEOP_STOPBITS_TWO +%token PARSEOP_STOPBITS_ZERO +%token PARSEOP_STORE +%token PARSEOP_STRING_LITERAL +%token PARSEOP_SUBTRACT +%token PARSEOP_SWITCH +%token PARSEOP_THERMALZONE +%token PARSEOP_TIMER +%token PARSEOP_TOBCD +%token PARSEOP_TOBUFFER +%token PARSEOP_TODECIMALSTRING +%token PARSEOP_TOHEXSTRING +%token PARSEOP_TOINTEGER +%token PARSEOP_TOSTRING +%token PARSEOP_TOUUID +%token PARSEOP_TRANSLATIONTYPE_DENSE +%token PARSEOP_TRANSLATIONTYPE_SPARSE +%token PARSEOP_TYPE_STATIC +%token PARSEOP_TYPE_TRANSLATION +%token PARSEOP_UART_SERIALBUS +%token PARSEOP_UNICODE +%token PARSEOP_UNLOAD +%token PARSEOP_UPDATERULE_ONES +%token PARSEOP_UPDATERULE_PRESERVE +%token PARSEOP_UPDATERULE_ZEROS +%token PARSEOP_VAR_PACKAGE +%token PARSEOP_VENDORLONG +%token PARSEOP_VENDORSHORT +%token PARSEOP_WAIT +%token PARSEOP_WHILE +%token PARSEOP_WIREMODE_FOUR +%token PARSEOP_WIREMODE_THREE +%token PARSEOP_WORDBUSNUMBER +%token PARSEOP_WORDCONST +%token PARSEOP_WORDIO +%token PARSEOP_WORDSPACE +%token PARSEOP_XFERSIZE_8 +%token PARSEOP_XFERSIZE_16 +%token PARSEOP_XFERSIZE_32 +%token PARSEOP_XFERSIZE_64 +%token PARSEOP_XFERSIZE_128 +%token PARSEOP_XFERSIZE_256 +%token PARSEOP_XFERTYPE_8 +%token PARSEOP_XFERTYPE_8_16 +%token PARSEOP_XFERTYPE_16 +%token PARSEOP_XOR +%token PARSEOP_ZERO + +/* ToPld macro */ + +%token PARSEOP_TOPLD +%token PARSEOP_PLD_REVISION +%token PARSEOP_PLD_IGNORECOLOR +%token PARSEOP_PLD_RED +%token PARSEOP_PLD_GREEN +%token PARSEOP_PLD_BLUE +%token PARSEOP_PLD_WIDTH +%token PARSEOP_PLD_HEIGHT +%token PARSEOP_PLD_USERVISIBLE +%token PARSEOP_PLD_DOCK +%token PARSEOP_PLD_LID +%token PARSEOP_PLD_PANEL +%token PARSEOP_PLD_VERTICALPOSITION +%token PARSEOP_PLD_HORIZONTALPOSITION +%token PARSEOP_PLD_SHAPE +%token PARSEOP_PLD_GROUPORIENTATION +%token PARSEOP_PLD_GROUPTOKEN +%token PARSEOP_PLD_GROUPPOSITION +%token PARSEOP_PLD_BAY +%token PARSEOP_PLD_EJECTABLE +%token PARSEOP_PLD_EJECTREQUIRED +%token PARSEOP_PLD_CABINETNUMBER +%token PARSEOP_PLD_CARDCAGENUMBER +%token PARSEOP_PLD_REFERENCE +%token PARSEOP_PLD_ROTATION +%token PARSEOP_PLD_ORDER +%token PARSEOP_PLD_RESERVED +%token PARSEOP_PLD_VERTICALOFFSET +%token PARSEOP_PLD_HORIZONTALOFFSET + +/* + * C-style expression parser. These must appear after all of the + * standard ASL operators and keywords. + * + * Note: The order of these tokens implements the precedence rules + * (low precedence to high). See aslrules.y for an exhaustive list. + */ +%right PARSEOP_EXP_EQUALS + PARSEOP_EXP_ADD_EQ + PARSEOP_EXP_SUB_EQ + PARSEOP_EXP_MUL_EQ + PARSEOP_EXP_DIV_EQ + PARSEOP_EXP_MOD_EQ + PARSEOP_EXP_SHL_EQ + PARSEOP_EXP_SHR_EQ + PARSEOP_EXP_AND_EQ + PARSEOP_EXP_XOR_EQ + PARSEOP_EXP_OR_EQ + +%left PARSEOP_EXP_LOGICAL_OR +%left PARSEOP_EXP_LOGICAL_AND +%left PARSEOP_EXP_OR +%left PARSEOP_EXP_XOR +%left PARSEOP_EXP_AND +%left PARSEOP_EXP_EQUAL + PARSEOP_EXP_NOT_EQUAL +%left PARSEOP_EXP_GREATER + PARSEOP_EXP_LESS + PARSEOP_EXP_GREATER_EQUAL + PARSEOP_EXP_LESS_EQUAL +%left PARSEOP_EXP_SHIFT_RIGHT + PARSEOP_EXP_SHIFT_LEFT +%left PARSEOP_EXP_ADD + PARSEOP_EXP_SUBTRACT +%left PARSEOP_EXP_MULTIPLY + PARSEOP_EXP_DIVIDE + PARSEOP_EXP_MODULO + +%right PARSEOP_EXP_NOT + PARSEOP_EXP_LOGICAL_NOT + +%left PARSEOP_EXP_INCREMENT + PARSEOP_EXP_DECREMENT + +/* Brackets for Index() support */ + +%left PARSEOP_EXP_INDEX_LEFT +%right PARSEOP_EXP_INDEX_RIGHT + +%token PARSEOP_PRINTF +%token PARSEOP_FPRINTF + +/* Specific parentheses tokens are not used at this time */ + /* PARSEOP_EXP_PAREN_OPEN */ + /* PARSEOP_EXP_PAREN_CLOSE */ + + +%token PARSEOP_ASL_CODE + +/* + * Special functions. These should probably stay at the end of this + * table. + */ +%token PARSEOP___DATE__ +%token PARSEOP___FILE__ +%token PARSEOP___LINE__ +%token PARSEOP___PATH__ diff --git a/third_party/lib/acpica/source/compiler/asltransform.c b/third_party/lib/acpica/source/compiler/asltransform.c new file mode 100644 index 000000000..607b1bbbb --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asltransform.c @@ -0,0 +1,777 @@ +/****************************************************************************** + * + * Module Name: asltransform - Parse tree transforms + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asltransform") + +/* Local prototypes */ + +static void +TrTransformSubtree ( + ACPI_PARSE_OBJECT *Op); + +static char * +TrAmlGetNextTempName ( + ACPI_PARSE_OBJECT *Op, + UINT8 *TempCount); + +static void +TrAmlInitLineNumbers ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Neighbor); + +static void +TrAmlInitNode ( + ACPI_PARSE_OBJECT *Op, + UINT16 ParseOpcode); + +static void +TrAmlSetSubtreeParent ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Parent); + +static void +TrAmlInsertPeer ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *NewPeer); + +static void +TrDoDefinitionBlock ( + ACPI_PARSE_OBJECT *Op); + +static void +TrDoSwitch ( + ACPI_PARSE_OBJECT *StartNode); + + +/******************************************************************************* + * + * FUNCTION: TrAmlGetNextTempName + * + * PARAMETERS: Op - Current parse op + * TempCount - Current temporary counter. Was originally + * per-module; Currently per method, could be + * expanded to per-scope. + * + * RETURN: A pointer to name (allocated here). + * + * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are + * reserved for use by the ASL compiler. (_T_0 through _T_Z) + * + ******************************************************************************/ + +static char * +TrAmlGetNextTempName ( + ACPI_PARSE_OBJECT *Op, + UINT8 *TempCount) +{ + char *TempName; + + + if (*TempCount >= (10 + 26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ + { + /* Too many temps */ + + AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); + return (NULL); + } + + TempName = UtLocalCalloc (5); + + if (*TempCount < 10) /* 0-9 */ + { + TempName[3] = (char) (*TempCount + '0'); + } + else /* 10-35: A-Z */ + { + TempName[3] = (char) (*TempCount + ('A' - 10)); + } + + (*TempCount)++; + + /* First three characters are always "_T_" */ + + TempName[0] = '_'; + TempName[1] = 'T'; + TempName[2] = '_'; + + return (TempName); +} + + +/******************************************************************************* + * + * FUNCTION: TrAmlInitLineNumbers + * + * PARAMETERS: Op - Op to be initialized + * Neighbor - Op used for initialization values + * + * RETURN: None + * + * DESCRIPTION: Initialized the various line numbers for a parse node. + * + ******************************************************************************/ + +static void +TrAmlInitLineNumbers ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Neighbor) +{ + + Op->Asl.EndLine = Neighbor->Asl.EndLine; + Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; + Op->Asl.LineNumber = Neighbor->Asl.LineNumber; + Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; + Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; +} + + +/******************************************************************************* + * + * FUNCTION: TrAmlInitNode + * + * PARAMETERS: Op - Op to be initialized + * ParseOpcode - Opcode for this node + * + * RETURN: None + * + * DESCRIPTION: Initialize a node with the parse opcode and opcode name. + * + ******************************************************************************/ + +static void +TrAmlInitNode ( + ACPI_PARSE_OBJECT *Op, + UINT16 ParseOpcode) +{ + + Op->Asl.ParseOpcode = ParseOpcode; + UtSetParseOpName (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrAmlSetSubtreeParent + * + * PARAMETERS: Op - First node in a list of peer nodes + * Parent - Parent of the subtree + * + * RETURN: None + * + * DESCRIPTION: Set the parent for all peer nodes in a subtree + * + ******************************************************************************/ + +static void +TrAmlSetSubtreeParent ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Parent) +{ + ACPI_PARSE_OBJECT *Next; + + + Next = Op; + while (Next) + { + Next->Asl.Parent = Parent; + Next = Next->Asl.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: TrAmlInsertPeer + * + * PARAMETERS: Op - First node in a list of peer nodes + * NewPeer - Peer node to insert + * + * RETURN: None + * + * DESCRIPTION: Insert a new peer node into a list of peers. + * + ******************************************************************************/ + +static void +TrAmlInsertPeer ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *NewPeer) +{ + + NewPeer->Asl.Next = Op->Asl.Next; + Op->Asl.Next = NewPeer; +} + + +/******************************************************************************* + * + * FUNCTION: TrAmlTransformWalk + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: None + * + * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML + * operands. + * + ******************************************************************************/ + +ACPI_STATUS +TrAmlTransformWalk ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + + TrTransformSubtree (Op); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: TrTransformSubtree + * + * PARAMETERS: Op - The parent parse node + * + * RETURN: None + * + * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more + * complex AML opcodes require processing of the child nodes + * (arguments/operands). + * + ******************************************************************************/ + +static void +TrTransformSubtree ( + ACPI_PARSE_OBJECT *Op) +{ + + if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) + { + return; + } + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_DEFINITION_BLOCK: + + TrDoDefinitionBlock (Op); + break; + + case PARSEOP_SWITCH: + + TrDoSwitch (Op); + break; + + case PARSEOP_METHOD: + /* + * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, + * however + */ + Gbl_TempCount = 0; + break; + + default: + + /* Nothing to do here for other opcodes */ + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: TrDoDefinitionBlock + * + * PARAMETERS: Op - Parse node + * + * RETURN: None + * + * DESCRIPTION: Find the end of the definition block and set a global to this + * node. It is used by the compiler to insert compiler-generated + * names at the root level of the namespace. + * + ******************************************************************************/ + +static void +TrDoDefinitionBlock ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + UINT32 i; + + + Next = Op->Asl.Child; + for (i = 0; i < 5; i++) + { + Next = Next->Asl.Next; + if (i == 0) + { + /* + * This is the table signature. Only the DSDT can be assumed + * to be at the root of the namespace; Therefore, namepath + * optimization can only be performed on the DSDT. + */ + if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT)) + { + Gbl_ReferenceOptimizationFlag = FALSE; + } + } + } + + Gbl_FirstLevelInsertionNode = Next; +} + + +/******************************************************************************* + * + * FUNCTION: TrDoSwitch + * + * PARAMETERS: StartNode - Parse node for SWITCH + * + * RETURN: None + * + * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is + * no actual AML opcode for SWITCH -- it must be simulated. + * + ******************************************************************************/ + +static void +TrDoSwitch ( + ACPI_PARSE_OBJECT *StartNode) +{ + ACPI_PARSE_OBJECT *Next; + ACPI_PARSE_OBJECT *CaseOp = NULL; + ACPI_PARSE_OBJECT *CaseBlock = NULL; + ACPI_PARSE_OBJECT *DefaultOp = NULL; + ACPI_PARSE_OBJECT *CurrentParentNode; + ACPI_PARSE_OBJECT *Conditional = NULL; + ACPI_PARSE_OBJECT *Predicate; + ACPI_PARSE_OBJECT *Peer; + ACPI_PARSE_OBJECT *NewOp; + ACPI_PARSE_OBJECT *NewOp2; + ACPI_PARSE_OBJECT *MethodOp; + ACPI_PARSE_OBJECT *StoreOp; + ACPI_PARSE_OBJECT *BreakOp; + ACPI_PARSE_OBJECT *BufferOp; + char *PredicateValueName; + UINT16 Index; + UINT32 Btype; + + + /* Start node is the Switch() node */ + + CurrentParentNode = StartNode; + + /* Create a new temp name of the form _T_x */ + + PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount); + if (!PredicateValueName) + { + return; + } + + /* First child is the Switch() predicate */ + + Next = StartNode->Asl.Child; + + /* + * Examine the return type of the Switch Value - + * must be Integer/Buffer/String + */ + Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); + Btype = AslKeywordMapping[Index].AcpiBtype; + if ((Btype != ACPI_BTYPE_INTEGER) && + (Btype != ACPI_BTYPE_STRING) && + (Btype != ACPI_BTYPE_BUFFER)) + { + AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); + Btype = ACPI_BTYPE_INTEGER; + } + + /* CASE statements start at next child */ + + Peer = Next->Asl.Next; + while (Peer) + { + Next = Peer; + Peer = Next->Asl.Next; + + if (Next->Asl.ParseOpcode == PARSEOP_CASE) + { + if (CaseOp) + { + /* Add an ELSE to complete the previous CASE */ + + NewOp = TrCreateLeafNode (PARSEOP_ELSE); + NewOp->Asl.Parent = Conditional->Asl.Parent; + TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); + + /* Link ELSE node as a peer to the previous IF */ + + TrAmlInsertPeer (Conditional, NewOp); + CurrentParentNode = NewOp; + } + + CaseOp = Next; + Conditional = CaseOp; + CaseBlock = CaseOp->Asl.Child->Asl.Next; + Conditional->Asl.Child->Asl.Next = NULL; + Predicate = CaseOp->Asl.Child; + + if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || + (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) + { + /* + * Convert the package declaration to this form: + * + * If (LNotEqual (Match (Package(){}, + * MEQ, _T_x, MTR, Zero, Zero), Ones)) + */ + NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ); + Predicate->Asl.Next = NewOp2; + TrAmlInitLineNumbers (NewOp2, Conditional); + + NewOp = NewOp2; + NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, + (UINT64) ACPI_TO_INTEGER (PredicateValueName)); + NewOp->Asl.Next = NewOp2; + TrAmlInitLineNumbers (NewOp2, Predicate); + + NewOp = NewOp2; + NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR); + NewOp->Asl.Next = NewOp2; + TrAmlInitLineNumbers (NewOp2, Predicate); + + NewOp = NewOp2; + NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); + NewOp->Asl.Next = NewOp2; + TrAmlInitLineNumbers (NewOp2, Predicate); + + NewOp = NewOp2; + NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); + NewOp->Asl.Next = NewOp2; + TrAmlInitLineNumbers (NewOp2, Predicate); + + NewOp2 = TrCreateLeafNode (PARSEOP_MATCH); + NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ + TrAmlInitLineNumbers (NewOp2, Conditional); + TrAmlSetSubtreeParent (Predicate, NewOp2); + + NewOp = NewOp2; + NewOp2 = TrCreateLeafNode (PARSEOP_ONES); + NewOp->Asl.Next = NewOp2; + TrAmlInitLineNumbers (NewOp2, Conditional); + + NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); + NewOp2->Asl.Child = NewOp; + NewOp->Asl.Parent = NewOp2; + TrAmlInitLineNumbers (NewOp2, Conditional); + TrAmlSetSubtreeParent (NewOp, NewOp2); + + NewOp = NewOp2; + NewOp2 = TrCreateLeafNode (PARSEOP_LNOT); + NewOp2->Asl.Child = NewOp; + NewOp2->Asl.Parent = Conditional; + NewOp->Asl.Parent = NewOp2; + TrAmlInitLineNumbers (NewOp2, Conditional); + + Conditional->Asl.Child = NewOp2; + NewOp2->Asl.Next = CaseBlock; + } + else + { + /* + * Integer and Buffer case. + * + * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} + * Note: SwitchValue is first to allow the CaseValue to be implicitly + * converted to the type of SwitchValue if necessary. + * + * CaseOp->Child is the case value + * CaseOp->Child->Peer is the beginning of the case block + */ + NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, + (UINT64) ACPI_TO_INTEGER (PredicateValueName)); + NewOp->Asl.Next = Predicate; + TrAmlInitLineNumbers (NewOp, Predicate); + + NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); + NewOp2->Asl.Parent = Conditional; + NewOp2->Asl.Child = NewOp; + TrAmlInitLineNumbers (NewOp2, Conditional); + + TrAmlSetSubtreeParent (NewOp, NewOp2); + + Predicate = NewOp2; + Predicate->Asl.Next = CaseBlock; + + TrAmlSetSubtreeParent (Predicate, Conditional); + Conditional->Asl.Child = Predicate; + } + + /* Reinitialize the CASE node to an IF node */ + + TrAmlInitNode (Conditional, PARSEOP_IF); + + /* + * The first CASE(IF) is not nested under an ELSE. + * All other CASEs are children of a parent ELSE. + */ + if (CurrentParentNode == StartNode) + { + Conditional->Asl.Next = NULL; + } + else + { + /* + * The IF is a child of previous IF/ELSE. It + * is therefore without peer. + */ + CurrentParentNode->Asl.Child = Conditional; + Conditional->Asl.Parent = CurrentParentNode; + Conditional->Asl.Next = NULL; + } + } + else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) + { + if (DefaultOp) + { + /* + * More than one Default + * (Parser does not catch this, must check here) + */ + AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); + } + else + { + /* Save the DEFAULT node for later, after CASEs */ + + DefaultOp = Next; + } + } + else + { + /* Unknown peer opcode */ + + AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", + Next->Asl.ParseOpName, Next->Asl.ParseOpcode); + } + } + + /* Add the default case at the end of the if/else construct */ + + if (DefaultOp) + { + /* If no CASE statements, this is an error - see below */ + + if (CaseOp) + { + /* Convert the DEFAULT node to an ELSE */ + + TrAmlInitNode (DefaultOp, PARSEOP_ELSE); + DefaultOp->Asl.Parent = Conditional->Asl.Parent; + + /* Link ELSE node as a peer to the previous IF */ + + TrAmlInsertPeer (Conditional, DefaultOp); + } + } + + if (!CaseOp) + { + AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); + } + + + /* + * Create a Name(_T_x, ...) statement. This statement must appear at the + * method level, in case a loop surrounds the switch statement and could + * cause the name to be created twice (error). + */ + + /* Create the Name node */ + + Predicate = StartNode->Asl.Child; + NewOp = TrCreateLeafNode (PARSEOP_NAME); + TrAmlInitLineNumbers (NewOp, StartNode); + + /* Find the parent method */ + + Next = StartNode; + while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && + (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK)) + { + Next = Next->Asl.Parent; + } + MethodOp = Next; + + NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED; + NewOp->Asl.Parent = Next; + + /* Insert name after the method name and arguments */ + + Next = Next->Asl.Child; /* Name */ + Next = Next->Asl.Next; /* NumArgs */ + Next = Next->Asl.Next; /* SerializeRule */ + + /* + * If method is not Serialized, we must make is so, because of the way + * that Switch() must be implemented -- we cannot allow multiple threads + * to execute this method concurrently since we need to create local + * temporary name(s). + */ + if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) + { + AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, + "Due to use of Switch operator"); + Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; + } + + Next = Next->Asl.Next; /* SyncLevel */ + Next = Next->Asl.Next; /* ReturnType */ + Next = Next->Asl.Next; /* ParameterTypes */ + + TrAmlInsertPeer (Next, NewOp); + TrAmlInitLineNumbers (NewOp, Next); + + /* Create the NameSeg child for the Name node */ + + NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG, + (UINT64) ACPI_TO_INTEGER (PredicateValueName)); + TrAmlInitLineNumbers (NewOp2, NewOp); + NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION; + NewOp->Asl.Child = NewOp2; + + /* Create the initial value for the Name. Btype was already validated above */ + + switch (Btype) + { + case ACPI_BTYPE_INTEGER: + + NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO, + (UINT64) 0); + TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); + break; + + case ACPI_BTYPE_STRING: + + NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, + (UINT64) ACPI_TO_INTEGER ("")); + TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); + break; + + case ACPI_BTYPE_BUFFER: + + (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER, + (UINT64) 0)); + Next = NewOp2->Asl.Next; + TrAmlInitLineNumbers (Next, NewOp2); + (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO, + (UINT64) 1)); + TrAmlInitLineNumbers (Next->Asl.Child, Next); + + BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0); + TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); + (void) TrLinkPeerNode (Next->Asl.Child, BufferOp); + + TrAmlSetSubtreeParent (Next->Asl.Child, Next); + break; + + default: + + break; + } + + TrAmlSetSubtreeParent (NewOp2, NewOp); + + /* + * Transform the Switch() into a While(One)-Break node. + * And create a Store() node which will be used to save the + * Switch() value. The store is of the form: Store (Value, _T_x) + * where _T_x is the temp variable. + */ + TrAmlInitNode (StartNode, PARSEOP_WHILE); + NewOp = TrCreateLeafNode (PARSEOP_ONE); + TrAmlInitLineNumbers (NewOp, StartNode); + NewOp->Asl.Next = Predicate->Asl.Next; + NewOp->Asl.Parent = StartNode; + StartNode->Asl.Child = NewOp; + + /* Create a Store() node */ + + StoreOp = TrCreateLeafNode (PARSEOP_STORE); + TrAmlInitLineNumbers (StoreOp, NewOp); + StoreOp->Asl.Parent = StartNode; + TrAmlInsertPeer (NewOp, StoreOp); + + /* Complete the Store subtree */ + + StoreOp->Asl.Child = Predicate; + Predicate->Asl.Parent = StoreOp; + + NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG, + (UINT64) ACPI_TO_INTEGER (PredicateValueName)); + TrAmlInitLineNumbers (NewOp, StoreOp); + NewOp->Asl.Parent = StoreOp; + Predicate->Asl.Next = NewOp; + + /* Create a Break() node and insert it into the end of While() */ + + Conditional = StartNode->Asl.Child; + while (Conditional->Asl.Next) + { + Conditional = Conditional->Asl.Next; + } + + BreakOp = TrCreateLeafNode (PARSEOP_BREAK); + TrAmlInitLineNumbers (BreakOp, NewOp); + BreakOp->Asl.Parent = StartNode; + TrAmlInsertPeer (Conditional, BreakOp); +} diff --git a/third_party/lib/acpica/source/compiler/asltree.c b/third_party/lib/acpica/source/compiler/asltree.c new file mode 100644 index 000000000..c6eb57b9a --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asltree.c @@ -0,0 +1,1612 @@ +/****************************************************************************** + * + * Module Name: asltree - parse tree management + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acapps.h" +#include + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asltree") + +/* Local prototypes */ + +static ACPI_PARSE_OBJECT * +TrGetNextNode ( + void); + + +/******************************************************************************* + * + * FUNCTION: TrGetNextNode + * + * PARAMETERS: None + * + * RETURN: New parse node. Aborts on allocation failure + * + * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local + * dynamic memory manager for performance reasons (This has a + * major impact on the speed of the compiler.) + * + ******************************************************************************/ + +static ACPI_PARSE_OBJECT * +TrGetNextNode ( + void) +{ + ASL_CACHE_INFO *Cache; + + + if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast) + { + /* Allocate a new buffer */ + + Cache = UtLocalCalloc (sizeof (Cache->Next) + + (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE)); + + /* Link new cache buffer to head of list */ + + Cache->Next = Gbl_ParseOpCacheList; + Gbl_ParseOpCacheList = Cache; + + /* Setup cache management pointers */ + + Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer); + Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE; + } + + Gbl_ParseOpCount++; + return (Gbl_ParseOpCacheNext++); +} + + +/******************************************************************************* + * + * FUNCTION: TrAllocateNode + * + * PARAMETERS: ParseOpcode - Opcode to be assigned to the node + * + * RETURN: New parse node. Aborts on allocation failure + * + * DESCRIPTION: Allocate and initialize a new parse node for the parse tree + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrAllocateNode ( + UINT32 ParseOpcode) +{ + ACPI_PARSE_OBJECT *Op; + + + Op = TrGetNextNode (); + + Op->Asl.ParseOpcode = (UINT16) ParseOpcode; + Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename; + Op->Asl.LineNumber = Gbl_CurrentLineNumber; + Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber; + Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset; + Op->Asl.Column = Gbl_CurrentColumn; + + UtSetParseOpName (Op); + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrReleaseNode + * + * PARAMETERS: Op - Op to be released + * + * RETURN: None + * + * DESCRIPTION: "release" a node. In truth, nothing is done since the node + * is part of a larger buffer + * + ******************************************************************************/ + +void +TrReleaseNode ( + ACPI_PARSE_OBJECT *Op) +{ + + return; +} + + +/******************************************************************************* + * + * FUNCTION: TrSetCurrentFilename + * + * PARAMETERS: Op - An existing parse node + * + * RETURN: None + * + * DESCRIPTION: Save the include file filename. Used for debug output only. + * + ******************************************************************************/ + +void +TrSetCurrentFilename ( + ACPI_PARSE_OBJECT *Op) +{ + Op->Asl.Filename = Gbl_PreviousIncludeFilename; +} + + +/******************************************************************************* + * + * FUNCTION: TrUpdateNode + * + * PARAMETERS: ParseOpcode - New opcode to be assigned to the node + * Op - An existing parse node + * + * RETURN: The updated node + * + * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to + * change an opcode to DEFAULT_ARG so that the node is ignored + * during the code generation. Also used to set generic integers + * to a specific size (8, 16, 32, or 64 bits) + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrUpdateNode ( + UINT32 ParseOpcode, + ACPI_PARSE_OBJECT *Op) +{ + + if (!Op) + { + return (NULL); + } + + DbgPrint (ASL_PARSE_OUTPUT, + "\nUpdateNode: Old - %s, New - %s\n", + UtGetOpName (Op->Asl.ParseOpcode), + UtGetOpName (ParseOpcode)); + + /* Assign new opcode and name */ + + if (Op->Asl.ParseOpcode == PARSEOP_ONES) + { + switch (ParseOpcode) + { + case PARSEOP_BYTECONST: + + Op->Asl.Value.Integer = ACPI_UINT8_MAX; + break; + + case PARSEOP_WORDCONST: + + Op->Asl.Value.Integer = ACPI_UINT16_MAX; + break; + + case PARSEOP_DWORDCONST: + + Op->Asl.Value.Integer = ACPI_UINT32_MAX; + break; + + /* Don't need to do the QWORD case */ + + default: + + /* Don't care about others */ + break; + } + } + + Op->Asl.ParseOpcode = (UINT16) ParseOpcode; + UtSetParseOpName (Op); + + /* + * For the BYTE, WORD, and DWORD constants, make sure that the integer + * that was passed in will actually fit into the data type + */ + switch (ParseOpcode) + { + case PARSEOP_BYTECONST: + + UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); + Op->Asl.Value.Integer &= ACPI_UINT8_MAX; + break; + + case PARSEOP_WORDCONST: + + UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); + Op->Asl.Value.Integer &= ACPI_UINT16_MAX; + break; + + case PARSEOP_DWORDCONST: + + UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); + Op->Asl.Value.Integer &= ACPI_UINT32_MAX; + break; + + default: + + /* Don't care about others, don't need to check QWORD */ + + break; + } + + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrPrintNodeCompileFlags + * + * PARAMETERS: Flags - Flags word to be decoded + * + * RETURN: None + * + * DESCRIPTION: Decode a flags word to text. Displays all flags that are set. + * + ******************************************************************************/ + +void +TrPrintNodeCompileFlags ( + UINT32 Flags) +{ + UINT32 i; + UINT32 FlagBit = 1; + char *FlagName = NULL; + + + for (i = 0; i < 32; i++) + { + switch (Flags & FlagBit) + { + case NODE_VISITED: + + FlagName = "NODE_VISITED"; + break; + + case NODE_AML_PACKAGE: + + FlagName = "NODE_AML_PACKAGE"; + break; + + case NODE_IS_TARGET: + + FlagName = "NODE_IS_TARGET"; + break; + + case NODE_IS_RESOURCE_DESC: + + FlagName = "NODE_IS_RESOURCE_DESC"; + break; + + case NODE_IS_RESOURCE_FIELD: + + FlagName = "NODE_IS_RESOURCE_FIELD"; + break; + + case NODE_HAS_NO_EXIT: + + FlagName = "NODE_HAS_NO_EXIT"; + break; + + case NODE_IF_HAS_NO_EXIT: + + FlagName = "NODE_IF_HAS_NO_EXIT"; + break; + + case NODE_NAME_INTERNALIZED: + + FlagName = "NODE_NAME_INTERNALIZED"; + break; + + case NODE_METHOD_NO_RETVAL: + + FlagName = "NODE_METHOD_NO_RETVAL"; + break; + + case NODE_METHOD_SOME_NO_RETVAL: + + FlagName = "NODE_METHOD_SOME_NO_RETVAL"; + break; + + case NODE_RESULT_NOT_USED: + + FlagName = "NODE_RESULT_NOT_USED"; + break; + + case NODE_METHOD_TYPED: + + FlagName = "NODE_METHOD_TYPED"; + break; + + case NODE_COULD_NOT_REDUCE: + + FlagName = "NODE_COULD_NOT_REDUCE"; + break; + + case NODE_COMPILE_TIME_CONST: + + FlagName = "NODE_COMPILE_TIME_CONST"; + break; + + case NODE_IS_TERM_ARG: + + FlagName = "NODE_IS_TERM_ARG"; + break; + + case NODE_WAS_ONES_OP: + + FlagName = "NODE_WAS_ONES_OP"; + break; + + case NODE_IS_NAME_DECLARATION: + + FlagName = "NODE_IS_NAME_DECLARATION"; + break; + + case NODE_COMPILER_EMITTED: + + FlagName = "NODE_COMPILER_EMITTED"; + break; + + case NODE_IS_DUPLICATE: + + FlagName = "NODE_IS_DUPLICATE"; + break; + + case NODE_IS_RESOURCE_DATA: + + FlagName = "NODE_IS_RESOURCE_DATA"; + break; + + case NODE_IS_NULL_RETURN: + + FlagName = "NODE_IS_NULL_RETURN"; + break; + + default: + break; + } + + if (FlagName) + { + DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName); + FlagName = NULL; + } + + FlagBit <<= 1; + } +} + + +/******************************************************************************* + * + * FUNCTION: TrSetNodeFlags + * + * PARAMETERS: Op - An existing parse node + * Flags - New flags word + * + * RETURN: The updated parser op + * + * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrSetNodeFlags ( + ACPI_PARSE_OBJECT *Op, + UINT32 Flags) +{ + + if (!Op) + { + return (NULL); + } + + DbgPrint (ASL_PARSE_OUTPUT, + "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags); + + TrPrintNodeCompileFlags (Flags); + DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); + + Op->Asl.CompileFlags |= Flags; + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrSetNodeAmlLength + * + * PARAMETERS: Op - An existing parse node + * Length - AML Length + * + * RETURN: The updated parser op + * + * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate + * the presence of a node that must be reduced to a fixed length + * constant. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrSetNodeAmlLength ( + ACPI_PARSE_OBJECT *Op, + UINT32 Length) +{ + + DbgPrint (ASL_PARSE_OUTPUT, + "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); + + if (!Op) + { + return (NULL); + } + + Op->Asl.AmlLength = Length; + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrSetEndLineNumber + * + * PARAMETERS: Op - An existing parse node + * + * RETURN: None. + * + * DESCRIPTION: Set the ending line numbers (file line and logical line) of a + * parse node to the current line numbers. + * + ******************************************************************************/ + +void +TrSetEndLineNumber ( + ACPI_PARSE_OBJECT *Op) +{ + + /* If the end line # is already set, just return */ + + if (Op->Asl.EndLine) + { + return; + } + + Op->Asl.EndLine = Gbl_CurrentLineNumber; + Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber; +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateAssignmentNode + * + * PARAMETERS: Target - Assignment target + * Source - Assignment source + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Implements the C-style '=' operator. It changes the parse + * tree if possible to utilize the last argument of the math + * operators which is a target operand -- thus saving invocation + * of and additional Store() operator. An optimization. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateAssignmentNode ( + ACPI_PARSE_OBJECT *Target, + ACPI_PARSE_OBJECT *Source) +{ + ACPI_PARSE_OBJECT *TargetOp; + ACPI_PARSE_OBJECT *SourceOp1; + ACPI_PARSE_OBJECT *SourceOp2; + ACPI_PARSE_OBJECT *Operator; + + + DbgPrint (ASL_PARSE_OUTPUT, + "\nTrCreateAssignmentNode Line [%u to %u] Source %s Target %s\n", + Source->Asl.LineNumber, Source->Asl.EndLine, + UtGetOpName (Source->Asl.ParseOpcode), + UtGetOpName (Target->Asl.ParseOpcode)); + + TrSetNodeFlags (Target, NODE_IS_TARGET); + + switch (Source->Asl.ParseOpcode) + { + /* + * Only these operators can be optimized because they have + * a target operand + */ + case PARSEOP_ADD: + case PARSEOP_AND: + case PARSEOP_DIVIDE: + case PARSEOP_INDEX: + case PARSEOP_MOD: + case PARSEOP_MULTIPLY: + case PARSEOP_NOT: + case PARSEOP_OR: + case PARSEOP_SHIFTLEFT: + case PARSEOP_SHIFTRIGHT: + case PARSEOP_SUBTRACT: + case PARSEOP_XOR: + + break; + + /* Otherwise, just create a normal Store operator */ + + default: + + goto CannotOptimize; + } + + /* + * Transform the parse tree such that the target is moved to the + * last operand of the operator + */ + SourceOp1 = Source->Asl.Child; + SourceOp2 = SourceOp1->Asl.Next; + + /* NOT only has one operand, but has a target */ + + if (Source->Asl.ParseOpcode == PARSEOP_NOT) + { + SourceOp2 = SourceOp1; + } + + /* DIVIDE has an extra target operand (remainder) */ + + if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE) + { + SourceOp2 = SourceOp2->Asl.Next; + } + + TargetOp = SourceOp2->Asl.Next; + + /* + * Can't perform this optimization if there already is a target + * for the operator (ZERO is a "no target" placeholder). + */ + if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO) + { + goto CannotOptimize; + } + + /* Link in the target as the final operand */ + + SourceOp2->Asl.Next = Target; + Target->Asl.Parent = Source; + + return (Source); + + +CannotOptimize: + + Operator = TrAllocateNode (PARSEOP_STORE); + TrLinkChildren (Operator, 2, Source, Target); + + /* Set the appropriate line numbers for the new node */ + + Operator->Asl.LineNumber = Target->Asl.LineNumber; + Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber; + Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset; + Operator->Asl.Column = Target->Asl.Column; + + return (Operator); +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateLeafNode + * + * PARAMETERS: ParseOpcode - New opcode to be assigned to the node + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Create a simple leaf node (no children or peers, and no value + * assigned to the node) + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateLeafNode ( + UINT32 ParseOpcode) +{ + ACPI_PARSE_OBJECT *Op; + + + Op = TrAllocateNode (ParseOpcode); + + DbgPrint (ASL_PARSE_OUTPUT, + "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n", + Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode)); + + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateNullTarget + * + * PARAMETERS: None + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Create a "null" target node. This is defined by the ACPI + * specification to be a zero AML opcode, and indicates that + * no target has been specified for the parent operation + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateNullTarget ( + void) +{ + ACPI_PARSE_OBJECT *Op; + + + Op = TrAllocateNode (PARSEOP_ZERO); + Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST); + + DbgPrint (ASL_PARSE_OUTPUT, + "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n", + Op->Asl.LineNumber, Op->Asl.Column, Op, + UtGetOpName (Op->Asl.ParseOpcode)); + + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateConstantLeafNode + * + * PARAMETERS: ParseOpcode - The constant opcode + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Create a leaf node (no children or peers) for one of the + * special constants - __LINE__, __FILE__, and __DATE__. + * + * Note: An implemenation of __FUNC__ cannot happen here because we don't + * have a full parse tree at this time and cannot find the parent control + * method. If it is ever needed, __FUNC__ must be implemented later, after + * the parse tree has been fully constructed. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateConstantLeafNode ( + UINT32 ParseOpcode) +{ + ACPI_PARSE_OBJECT *Op = NULL; + time_t CurrentTime; + char *StaticTimeString; + char *TimeString; + char *Filename; + + + switch (ParseOpcode) + { + case PARSEOP___LINE__: + + Op = TrAllocateNode (PARSEOP_INTEGER); + Op->Asl.Value.Integer = Op->Asl.LineNumber; + break; + + case PARSEOP___PATH__: + + Op = TrAllocateNode (PARSEOP_STRING_LITERAL); + + /* Op.Asl.Filename contains the full pathname to the file */ + + Op->Asl.Value.String = Op->Asl.Filename; + break; + + case PARSEOP___FILE__: + + Op = TrAllocateNode (PARSEOP_STRING_LITERAL); + + /* Get the simple filename from the full path */ + + FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename); + Op->Asl.Value.String = Filename; + break; + + case PARSEOP___DATE__: + + Op = TrAllocateNode (PARSEOP_STRING_LITERAL); + + /* Get a copy of the current time */ + + CurrentTime = time (NULL); + StaticTimeString = ctime (&CurrentTime); + TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1); + strcpy (TimeString, StaticTimeString); + + TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */ + Op->Asl.Value.String = TimeString; + break; + + default: /* This would be an internal error */ + + return (NULL); + } + + DbgPrint (ASL_PARSE_OUTPUT, + "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p " + "Op %s Value %8.8X%8.8X \n", + Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode), + ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateTargetOperand + * + * PARAMETERS: OriginalOp - Op to be copied + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style) + * expressions where the target is the same as one of the + * operands. A new node and subtree must be created from the + * original so that the parse tree can be linked properly. + * + * NOTE: This code is specific to target operands that are the last + * operand in an ASL/AML operator. Meaning that the top-level + * parse Op in a possible subtree has a NULL Next pointer. + * This simplifies the recursion. + * + * Subtree example: + * DeRefOf (Local1) += 32 + * + * This gets converted to: + * Add (DeRefOf (Local1), 32, DeRefOf (Local1)) + * + * Each DeRefOf has a single child, Local1. Even more complex + * subtrees can be created via the Index and DeRefOf operators. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateTargetOperand ( + ACPI_PARSE_OBJECT *OriginalOp, + ACPI_PARSE_OBJECT *ParentOp) +{ + ACPI_PARSE_OBJECT *Op; + + + if (!OriginalOp) + { + return (NULL); + } + + Op = TrGetNextNode (); + + /* Copy the pertinent values (omit link pointer fields) */ + + Op->Asl.Value = OriginalOp->Asl.Value; + Op->Asl.Filename = OriginalOp->Asl.Filename; + Op->Asl.LineNumber = OriginalOp->Asl.LineNumber; + Op->Asl.LogicalLineNumber = OriginalOp->Asl.LogicalLineNumber; + Op->Asl.LogicalByteOffset = OriginalOp->Asl.LogicalByteOffset; + Op->Asl.Column = OriginalOp->Asl.Column; + Op->Asl.Flags = OriginalOp->Asl.Flags; + Op->Asl.CompileFlags = OriginalOp->Asl.CompileFlags; + Op->Asl.AmlOpcode = OriginalOp->Asl.AmlOpcode; + Op->Asl.ParseOpcode = OriginalOp->Asl.ParseOpcode; + Op->Asl.Parent = ParentOp; + UtSetParseOpName (Op); + + /* Copy a possible subtree below this node */ + + if (OriginalOp->Asl.Child) + { + Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op); + } + + if (OriginalOp->Asl.Next) /* Null for top-level node */ + { + Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp); + } + + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateValuedLeafNode + * + * PARAMETERS: ParseOpcode - New opcode to be assigned to the node + * Value - Value to be assigned to the node + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Create a leaf node (no children or peers) with a value + * assigned to it + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateValuedLeafNode ( + UINT32 ParseOpcode, + UINT64 Value) +{ + ACPI_PARSE_OBJECT *Op; + + + Op = TrAllocateNode (ParseOpcode); + + DbgPrint (ASL_PARSE_OUTPUT, + "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p " + "Op %s Value %8.8X%8.8X ", + Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode), + ACPI_FORMAT_UINT64 (Value)); + Op->Asl.Value.Integer = Value; + + switch (ParseOpcode) + { + case PARSEOP_STRING_LITERAL: + + DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value); + break; + + case PARSEOP_NAMESEG: + + DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value); + break; + + case PARSEOP_NAMESTRING: + + DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value); + break; + + case PARSEOP_EISAID: + + DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value); + break; + + case PARSEOP_METHOD: + + DbgPrint (ASL_PARSE_OUTPUT, "METHOD"); + break; + + case PARSEOP_INTEGER: + + DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X", + ACPI_FORMAT_UINT64 (Value)); + break; + + default: + + break; + } + + DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrCreateNode + * + * PARAMETERS: ParseOpcode - Opcode to be assigned to the node + * NumChildren - Number of children to follow + * ... - A list of child nodes to link to the new + * node. NumChildren long. + * + * RETURN: Pointer to the new node. Aborts on allocation failure + * + * DESCRIPTION: Create a new parse node and link together a list of child + * nodes underneath the new node. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrCreateNode ( + UINT32 ParseOpcode, + UINT32 NumChildren, + ...) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_PARSE_OBJECT *Child; + ACPI_PARSE_OBJECT *PrevChild; + va_list ap; + UINT32 i; + BOOLEAN FirstChild; + + + va_start (ap, NumChildren); + + /* Allocate one new node */ + + Op = TrAllocateNode (ParseOpcode); + + DbgPrint (ASL_PARSE_OUTPUT, + "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ", + Op->Asl.LineNumber, Op->Asl.Column, Op, + NumChildren, UtGetOpName(ParseOpcode)); + + /* Some extra debug output based on the parse opcode */ + + switch (ParseOpcode) + { + case PARSEOP_ASL_CODE: + + RootNode = Op; + Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); + break; + + case PARSEOP_DEFINITION_BLOCK: + + DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); + break; + + case PARSEOP_OPERATIONREGION: + + DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); + break; + + case PARSEOP_OR: + + DbgPrint (ASL_PARSE_OUTPUT, "OR->"); + break; + + default: + + /* Nothing to do for other opcodes */ + + break; + } + + /* Link the new node to its children */ + + PrevChild = NULL; + FirstChild = TRUE; + for (i = 0; i < NumChildren; i++) + { + /* Get the next child */ + + Child = va_arg (ap, ACPI_PARSE_OBJECT *); + DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); + + /* + * If child is NULL, this means that an optional argument + * was omitted. We must create a placeholder with a special + * opcode (DEFAULT_ARG) so that the code generator will know + * that it must emit the correct default for this argument + */ + if (!Child) + { + Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); + } + + /* Link first child to parent */ + + if (FirstChild) + { + FirstChild = FALSE; + Op->Asl.Child = Child; + } + + /* Point all children to parent */ + + Child->Asl.Parent = Op; + + /* Link children in a peer list */ + + if (PrevChild) + { + PrevChild->Asl.Next = Child; + }; + + /* + * This child might be a list, point all nodes in the list + * to the same parent + */ + while (Child->Asl.Next) + { + Child = Child->Asl.Next; + Child->Asl.Parent = Op; + } + + PrevChild = Child; + } + va_end(ap); + + DbgPrint (ASL_PARSE_OUTPUT, "\n"); + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrLinkChildren + * + * PARAMETERS: Op - An existing parse node + * NumChildren - Number of children to follow + * ... - A list of child nodes to link to the new + * node. NumChildren long. + * + * RETURN: The updated (linked) node + * + * DESCRIPTION: Link a group of nodes to an existing parse node + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrLinkChildren ( + ACPI_PARSE_OBJECT *Op, + UINT32 NumChildren, + ...) +{ + ACPI_PARSE_OBJECT *Child; + ACPI_PARSE_OBJECT *PrevChild; + va_list ap; + UINT32 i; + BOOLEAN FirstChild; + + + va_start (ap, NumChildren); + + + TrSetEndLineNumber (Op); + + DbgPrint (ASL_PARSE_OUTPUT, + "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", + Op->Asl.LineNumber, Op->Asl.EndLine, + Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_ASL_CODE: + + RootNode = Op; + Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; + DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); + break; + + case PARSEOP_DEFINITION_BLOCK: + + DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); + break; + + case PARSEOP_OPERATIONREGION: + + DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); + break; + + case PARSEOP_OR: + + DbgPrint (ASL_PARSE_OUTPUT, "OR->"); + break; + + default: + + /* Nothing to do for other opcodes */ + + break; + } + + /* Link the new node to it's children */ + + PrevChild = NULL; + FirstChild = TRUE; + for (i = 0; i < NumChildren; i++) + { + Child = va_arg (ap, ACPI_PARSE_OBJECT *); + + if ((Child == PrevChild) && (Child != NULL)) + { + AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, + "Child node list invalid"); + va_end(ap); + return (Op); + } + + DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); + + /* + * If child is NULL, this means that an optional argument + * was omitted. We must create a placeholder with a special + * opcode (DEFAULT_ARG) so that the code generator will know + * that it must emit the correct default for this argument + */ + if (!Child) + { + Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); + } + + /* Link first child to parent */ + + if (FirstChild) + { + FirstChild = FALSE; + Op->Asl.Child = Child; + } + + /* Point all children to parent */ + + Child->Asl.Parent = Op; + + /* Link children in a peer list */ + + if (PrevChild) + { + PrevChild->Asl.Next = Child; + }; + + /* + * This child might be a list, point all nodes in the list + * to the same parent + */ + while (Child->Asl.Next) + { + Child = Child->Asl.Next; + Child->Asl.Parent = Op; + } + + PrevChild = Child; + } + + va_end(ap); + DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: TrLinkPeerNode + * + * PARAMETERS: Op1 - First peer + * Op2 - Second peer + * + * RETURN: Op1 or the non-null node. + * + * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrLinkPeerNode ( + ACPI_PARSE_OBJECT *Op1, + ACPI_PARSE_OBJECT *Op2) +{ + ACPI_PARSE_OBJECT *Next; + + + DbgPrint (ASL_PARSE_OUTPUT, + "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n", + Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, + Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); + + + if ((!Op1) && (!Op2)) + { + DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n"); + return (Op1); + } + + /* If one of the nodes is null, just return the non-null node */ + + if (!Op2) + { + return (Op1); + } + + if (!Op1) + { + return (Op2); + } + + if (Op1 == Op2) + { + DbgPrint (ASL_DEBUG_OUTPUT, + "\n************* Internal error, linking node to itself %p\n", + Op1); + AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, + "Linking node to itself"); + return (Op1); + } + + Op1->Asl.Parent = Op2->Asl.Parent; + + /* + * Op 1 may already have a peer list (such as an IF/ELSE pair), + * so we must walk to the end of the list and attach the new + * peer at the end + */ + Next = Op1; + while (Next->Asl.Next) + { + Next = Next->Asl.Next; + } + + Next->Asl.Next = Op2; + return (Op1); +} + + +/******************************************************************************* + * + * FUNCTION: TrLinkPeerNodes + * + * PARAMETERS: NumPeers - The number of nodes in the list to follow + * ... - A list of nodes to link together as peers + * + * RETURN: The first node in the list (head of the peer list) + * + * DESCRIPTION: Link together an arbitrary number of peer nodes. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrLinkPeerNodes ( + UINT32 NumPeers, + ...) +{ + ACPI_PARSE_OBJECT *This; + ACPI_PARSE_OBJECT *Next; + va_list ap; + UINT32 i; + ACPI_PARSE_OBJECT *Start; + + + DbgPrint (ASL_PARSE_OUTPUT, + "\nLinkPeerNodes: (%u) ", NumPeers); + + va_start (ap, NumPeers); + This = va_arg (ap, ACPI_PARSE_OBJECT *); + Start = This; + + /* + * Link all peers + */ + for (i = 0; i < (NumPeers -1); i++) + { + DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); + + while (This->Asl.Next) + { + This = This->Asl.Next; + } + + /* Get another peer node */ + + Next = va_arg (ap, ACPI_PARSE_OBJECT *); + if (!Next) + { + Next = TrAllocateNode (PARSEOP_DEFAULT_ARG); + } + + /* link new node to the current node */ + + This->Asl.Next = Next; + This = Next; + } + va_end (ap); + + DbgPrint (ASL_PARSE_OUTPUT,"\n"); + return (Start); +} + + +/******************************************************************************* + * + * FUNCTION: TrLinkChildNode + * + * PARAMETERS: Op1 - Parent node + * Op2 - Op to become a child + * + * RETURN: The parent node + * + * DESCRIPTION: Link two nodes together as a parent and child + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrLinkChildNode ( + ACPI_PARSE_OBJECT *Op1, + ACPI_PARSE_OBJECT *Op2) +{ + ACPI_PARSE_OBJECT *Next; + + + DbgPrint (ASL_PARSE_OUTPUT, + "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n", + Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, + Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); + + if (!Op1 || !Op2) + { + return (Op1); + } + + Op1->Asl.Child = Op2; + + /* Set the child and all peers of the child to point to the parent */ + + Next = Op2; + while (Next) + { + Next->Asl.Parent = Op1; + Next = Next->Asl.Next; + } + + return (Op1); +} + + +/******************************************************************************* + * + * FUNCTION: TrWalkParseTree + * + * PARAMETERS: Visitation - Type of walk + * DescendingCallback - Called during tree descent + * AscendingCallback - Called during tree ascent + * Context - To be passed to the callbacks + * + * RETURN: Status from callback(s) + * + * DESCRIPTION: Walk the entire parse tree. + * + ******************************************************************************/ + +ACPI_STATUS +TrWalkParseTree ( + ACPI_PARSE_OBJECT *Op, + UINT32 Visitation, + ASL_WALK_CALLBACK DescendingCallback, + ASL_WALK_CALLBACK AscendingCallback, + void *Context) +{ + UINT32 Level; + BOOLEAN NodePreviouslyVisited; + ACPI_PARSE_OBJECT *StartOp = Op; + ACPI_STATUS Status; + + + if (!RootNode) + { + return (AE_OK); + } + + Level = 0; + NodePreviouslyVisited = FALSE; + + switch (Visitation) + { + case ASL_WALK_VISIT_DOWNWARD: + + while (Op) + { + if (!NodePreviouslyVisited) + { + /* Let the callback process the node. */ + + Status = DescendingCallback (Op, Level, Context); + if (ACPI_SUCCESS (Status)) + { + /* Visit children first, once */ + + if (Op->Asl.Child) + { + Level++; + Op = Op->Asl.Child; + continue; + } + } + else if (Status != AE_CTRL_DEPTH) + { + /* Exit immediately on any error */ + + return (Status); + } + } + + /* Terminate walk at start op */ + + if (Op == StartOp) + { + break; + } + + /* No more children, visit peers */ + + if (Op->Asl.Next) + { + Op = Op->Asl.Next; + NodePreviouslyVisited = FALSE; + } + else + { + /* No children or peers, re-visit parent */ + + if (Level != 0 ) + { + Level--; + } + Op = Op->Asl.Parent; + NodePreviouslyVisited = TRUE; + } + } + break; + + case ASL_WALK_VISIT_UPWARD: + + while (Op) + { + /* Visit leaf node (no children) or parent node on return trip */ + + if ((!Op->Asl.Child) || + (NodePreviouslyVisited)) + { + /* Let the callback process the node. */ + + Status = AscendingCallback (Op, Level, Context); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* Visit children first, once */ + + Level++; + Op = Op->Asl.Child; + continue; + } + + /* Terminate walk at start op */ + + if (Op == StartOp) + { + break; + } + + /* No more children, visit peers */ + + if (Op->Asl.Next) + { + Op = Op->Asl.Next; + NodePreviouslyVisited = FALSE; + } + else + { + /* No children or peers, re-visit parent */ + + if (Level != 0 ) + { + Level--; + } + Op = Op->Asl.Parent; + NodePreviouslyVisited = TRUE; + } + } + break; + + case ASL_WALK_VISIT_TWICE: + + while (Op) + { + if (NodePreviouslyVisited) + { + Status = AscendingCallback (Op, Level, Context); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* Let the callback process the node. */ + + Status = DescendingCallback (Op, Level, Context); + if (ACPI_SUCCESS (Status)) + { + /* Visit children first, once */ + + if (Op->Asl.Child) + { + Level++; + Op = Op->Asl.Child; + continue; + } + } + else if (Status != AE_CTRL_DEPTH) + { + /* Exit immediately on any error */ + + return (Status); + } + } + + /* Terminate walk at start op */ + + if (Op == StartOp) + { + break; + } + + /* No more children, visit peers */ + + if (Op->Asl.Next) + { + Op = Op->Asl.Next; + NodePreviouslyVisited = FALSE; + } + else + { + /* No children or peers, re-visit parent */ + + if (Level != 0 ) + { + Level--; + } + Op = Op->Asl.Parent; + NodePreviouslyVisited = TRUE; + } + } + break; + + default: + /* No other types supported */ + break; + } + + /* If we get here, the walk completed with no errors */ + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/asltypes.h b/third_party/lib/acpica/source/compiler/asltypes.h new file mode 100644 index 000000000..a3a714b8e --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asltypes.h @@ -0,0 +1,319 @@ +/****************************************************************************** + * + * Module Name: asltypes.h - compiler data types and struct definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ASLTYPES_H +#define __ASLTYPES_H + + +/******************************************************************************* + * + * Structure definitions + * + ******************************************************************************/ + + +/* Op flags for the ACPI_PARSE_OBJECT */ + +#define NODE_VISITED 0x00000001 +#define NODE_AML_PACKAGE 0x00000002 +#define NODE_IS_TARGET 0x00000004 +#define NODE_IS_RESOURCE_DESC 0x00000008 +#define NODE_IS_RESOURCE_FIELD 0x00000010 +#define NODE_HAS_NO_EXIT 0x00000020 +#define NODE_IF_HAS_NO_EXIT 0x00000040 +#define NODE_NAME_INTERNALIZED 0x00000080 +#define NODE_METHOD_NO_RETVAL 0x00000100 +#define NODE_METHOD_SOME_NO_RETVAL 0x00000200 +#define NODE_RESULT_NOT_USED 0x00000400 +#define NODE_METHOD_TYPED 0x00000800 +#define NODE_COULD_NOT_REDUCE 0x00001000 +#define NODE_COMPILE_TIME_CONST 0x00002000 +#define NODE_IS_TERM_ARG 0x00004000 +#define NODE_WAS_ONES_OP 0x00008000 +#define NODE_IS_NAME_DECLARATION 0x00010000 +#define NODE_COMPILER_EMITTED 0x00020000 +#define NODE_IS_DUPLICATE 0x00040000 +#define NODE_IS_RESOURCE_DATA 0x00080000 +#define NODE_IS_NULL_RETURN 0x00100000 + +/* Keeps information about individual control methods */ + +typedef struct asl_method_info +{ + ACPI_PARSE_OBJECT *Op; + struct asl_method_info *Next; + UINT32 ValidArgTypes[ACPI_METHOD_NUM_ARGS]; + UINT32 ValidReturnTypes; + UINT32 NumReturnNoValue; + UINT32 NumReturnWithValue; + UINT8 NumArguments; + UINT8 LocalInitialized[ACPI_METHOD_NUM_LOCALS]; + UINT8 ArgInitialized[ACPI_METHOD_NUM_ARGS]; + UINT8 HasBeenTyped; + UINT8 ShouldBeSerialized; + +} ASL_METHOD_INFO; + + +/* Parse tree walk info for control method analysis */ + +typedef struct asl_analysis_walk_info +{ + ASL_METHOD_INFO *MethodStack; + +} ASL_ANALYSIS_WALK_INFO; + + +/* An entry in the ParseOpcode to AmlOpcode mapping table */ + +typedef struct asl_mapping_entry +{ + UINT32 Value; + UINT32 AcpiBtype; /* Object type or return type */ + UINT16 AmlOpcode; + UINT8 Flags; + +} ASL_MAPPING_ENTRY; + + +/* Parse tree walk info structure */ + +typedef struct asl_walk_info +{ + ACPI_PARSE_OBJECT **NodePtr; + UINT32 *LevelPtr; + +} ASL_WALK_INFO; + + +/* File info */ + +typedef struct asl_file_info +{ + FILE *Handle; + char *Filename; + const char *ShortDescription; + const char *Description; + +} ASL_FILE_INFO; + +typedef struct asl_file_status +{ + UINT32 Line; + UINT32 Offset; + +} ASL_FILE_STATUS; + + +/* + * File types. Note: Any changes to this table must also be reflected + * in the Gbl_Files array. + * + * Corresponding filename suffixes are in comments + * + * NOTE: Don't move the first 4 file types + */ +typedef enum +{ + ASL_FILE_STDOUT = 0, + ASL_FILE_STDERR, + ASL_FILE_INPUT, /* .asl */ + ASL_FILE_AML_OUTPUT, /* .aml */ + ASL_FILE_SOURCE_OUTPUT, /* .src */ + ASL_FILE_PREPROCESSOR, /* .pre */ + ASL_FILE_PREPROCESSOR_USER, /* .i */ + ASL_FILE_LISTING_OUTPUT, /* .lst */ + ASL_FILE_HEX_OUTPUT, /* .hex */ + ASL_FILE_NAMESPACE_OUTPUT, /* .nsp */ + ASL_FILE_DEBUG_OUTPUT, /* .txt */ + ASL_FILE_ASM_SOURCE_OUTPUT, /* .asm */ + ASL_FILE_C_SOURCE_OUTPUT, /* .c */ + ASL_FILE_ASM_INCLUDE_OUTPUT,/* .inc */ + ASL_FILE_C_INCLUDE_OUTPUT, /* .h */ + ASL_FILE_C_OFFSET_OUTPUT, /* .offset.h */ + ASL_FILE_MAP_OUTPUT /* .map */ + +} ASL_FILE_TYPES; + + +#define ASL_MAX_FILE_TYPE 16 +#define ASL_NUM_FILES (ASL_MAX_FILE_TYPE + 1) + +/* Name suffixes used to create filenames for output files */ + +#define FILE_SUFFIX_ASL_CODE "asl" +#define FILE_SUFFIX_AML_CODE "aml" +#define FILE_SUFFIX_SOURCE "src" +#define FILE_SUFFIX_PREPROCESSOR "pre" +#define FILE_SUFFIX_PREPROC_USER "i" +#define FILE_SUFFIX_LISTING "lst" +#define FILE_SUFFIX_HEX_DUMP "hex" +#define FILE_SUFFIX_NAMESPACE "nsp" +#define FILE_SUFFIX_DEBUG "txt" +#define FILE_SUFFIX_ASM_SOURCE "asm" +#define FILE_SUFFIX_C_SOURCE "c" +#define FILE_SUFFIX_ASM_INCLUDE "inc" +#define FILE_SUFFIX_C_INCLUDE "h" +#define FILE_SUFFIX_C_OFFSET "offset.h" +#define FILE_SUFFIX_MAP "map" + + +/* Cache block structure for ParseOps and Strings */ + +typedef struct asl_cache_info +{ + void *Next; + char Buffer[1]; + +} ASL_CACHE_INFO; + + +typedef struct asl_include_dir +{ + char *Dir; + struct asl_include_dir *Next; + +} ASL_INCLUDE_DIR; + + +/* An entry in the exception list, one for each error/warning */ + +typedef struct asl_error_msg +{ + UINT32 LineNumber; + UINT32 LogicalLineNumber; + UINT32 LogicalByteOffset; + UINT32 Column; + char *Message; + struct asl_error_msg *Next; + char *Filename; + char *SourceLine; + UINT32 FilenameLength; + UINT16 MessageId; + UINT8 Level; + +} ASL_ERROR_MSG; + + +/* An entry in the listing file stack (for include files) */ + +typedef struct asl_listing_node +{ + char *Filename; + UINT32 LineNumber; + struct asl_listing_node *Next; + +} ASL_LISTING_NODE; + + +/* Callback interface for a parse tree walk */ + +/* + * TBD - another copy of this is in adisasm.h, fix + */ +#ifndef ASL_WALK_CALLBACK_DEFINED +typedef +ACPI_STATUS (*ASL_WALK_CALLBACK) ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); +#define ASL_WALK_CALLBACK_DEFINED +#endif + + +typedef struct asl_event_info +{ + UINT64 StartTime; + UINT64 EndTime; + char *EventName; + BOOLEAN Valid; + +} ASL_EVENT_INFO; + + +/* Hardware mapping file structures */ + +typedef struct acpi_gpio_info +{ + struct acpi_gpio_info *Next; + ACPI_PARSE_OBJECT *Op; + char *DeviceName; + ACPI_NAMESPACE_NODE *TargetNode; + UINT32 References; + UINT32 PinCount; + UINT32 PinIndex; + UINT16 PinNumber; + UINT8 Type; + UINT8 Direction; + UINT8 Polarity; + +} ACPI_GPIO_INFO; + +typedef struct acpi_serial_info +{ + struct acpi_serial_info *Next; + ACPI_PARSE_OBJECT *Op; + char *DeviceName; + ACPI_NAMESPACE_NODE *TargetNode; + AML_RESOURCE *Resource; + UINT32 Speed; + UINT16 Address; + +} ACPI_SERIAL_INFO; + +typedef struct asl_method_local +{ + ACPI_PARSE_OBJECT *Op; + UINT8 Flags; + +} ASL_METHOD_LOCAL; + +/* Values for Flags field above */ + +#define ASL_LOCAL_INITIALIZED (1) +#define ASL_LOCAL_REFERENCED (1<<1) +#define ASL_ARG_IS_LOCAL (1<<2) +#define ASL_ARG_INITIALIZED (1<<3) +#define ASL_ARG_REFERENCED (1<<4) + +#endif /* __ASLTYPES_H */ diff --git a/third_party/lib/acpica/source/compiler/asltypes.y b/third_party/lib/acpica/source/compiler/asltypes.y new file mode 100644 index 000000000..8d9c4d28b --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asltypes.y @@ -0,0 +1,395 @@ +NoEcho(' +/****************************************************************************** + * + * Module Name: asltypes.y - Bison/Yacc production types/names + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +') + +/****************************************************************************** + * + * Production names + * + *****************************************************************************/ + +%type ArgList +%type AslCode +%type BufferData +%type BufferTermData +%type CompilerDirective +%type DataObject +%type DefinitionBlockTerm +%type DefinitionBlockList +%type IntegerData +%type NamedObject +%type NameSpaceModifier +%type Object +%type ObjectList +%type PackageData +%type ParameterTypePackage +%type ParameterTypePackageList +%type ParameterTypesPackage +%type ParameterTypesPackageList +%type RequiredTarget +%type SimpleTarget +%type StringData +%type Target +%type Term +%type TermArg +%type TermList +%type MethodInvocationTerm + +/* Type4Opcode is obsolete */ + +%type Type1Opcode +%type Type2BufferOpcode +%type Type2BufferOrStringOpcode +%type Type2IntegerOpcode +%type Type2Opcode +%type Type2StringOpcode +%type Type3Opcode +%type Type5Opcode +%type Type6Opcode + +%type AccessAsTerm +%type ExternalTerm +%type FieldUnit +%type FieldUnitEntry +%type FieldUnitList +%type IncludeTerm +%type OffsetTerm +%type OptionalAccessAttribTerm + +/* Named Objects */ + +%type BankFieldTerm +%type CreateBitFieldTerm +%type CreateByteFieldTerm +%type CreateDWordFieldTerm +%type CreateFieldTerm +%type CreateQWordFieldTerm +%type CreateWordFieldTerm +%type DataRegionTerm +%type DeviceTerm +%type EventTerm +%type FieldTerm +%type FunctionTerm +%type IndexFieldTerm +%type MethodTerm +%type MutexTerm +%type OpRegionTerm +%type OpRegionSpaceIdTerm +%type PowerResTerm +%type ProcessorTerm +%type ThermalZoneTerm + +/* Namespace modifiers */ + +%type AliasTerm +%type NameTerm +%type ScopeTerm + +/* Type 1 opcodes */ + +%type BreakPointTerm +%type BreakTerm +%type CaseDefaultTermList +%type CaseTerm +%type ContinueTerm +%type DefaultTerm +%type ElseTerm +%type FatalTerm +%type ElseIfTerm +%type IfTerm +%type LoadTerm +%type NoOpTerm +%type NotifyTerm +%type ReleaseTerm +%type ResetTerm +%type ReturnTerm +%type SignalTerm +%type SleepTerm +%type StallTerm +%type SwitchTerm +%type UnloadTerm +%type WhileTerm +/* %type CaseTermList */ + +/* Type 2 opcodes */ + +%type AcquireTerm +%type AddTerm +%type AndTerm +%type ConcatResTerm +%type ConcatTerm +%type CondRefOfTerm +%type CopyObjectTerm +%type DecTerm +%type DerefOfTerm +%type DivideTerm +%type FindSetLeftBitTerm +%type FindSetRightBitTerm +%type FromBCDTerm +%type IncTerm +%type IndexTerm +%type LAndTerm +%type LEqualTerm +%type LGreaterEqualTerm +%type LGreaterTerm +%type LLessEqualTerm +%type LLessTerm +%type LNotEqualTerm +%type LNotTerm +%type LoadTableTerm +%type LOrTerm +%type MatchTerm +%type MidTerm +%type ModTerm +%type MultiplyTerm +%type NAndTerm +%type NOrTerm +%type NotTerm +%type ObjectTypeTerm +%type OrTerm +%type RawDataBufferTerm +%type RefOfTerm +%type ShiftLeftTerm +%type ShiftRightTerm +%type SizeOfTerm +%type StoreTerm +%type SubtractTerm +%type TimerTerm +%type ToBCDTerm +%type ToBufferTerm +%type ToDecimalStringTerm +%type ToHexStringTerm +%type ToIntegerTerm +%type ToStringTerm +%type WaitTerm +%type XOrTerm + +/* Keywords */ + +%type AccessAttribKeyword +%type AccessTypeKeyword +%type AddressingModeKeyword +%type AddressKeyword +%type AddressSpaceKeyword +%type BitsPerByteKeyword +%type ClockPhaseKeyword +%type ClockPolarityKeyword +%type DecodeKeyword +%type DevicePolarityKeyword +%type DMATypeKeyword +%type EndianKeyword +%type FlowControlKeyword +%type InterruptLevel +%type InterruptTypeKeyword +%type IODecodeKeyword +%type IoRestrictionKeyword +%type LockRuleKeyword +%type MatchOpKeyword +%type MaxKeyword +%type MemTypeKeyword +%type MinKeyword +%type ObjectTypeKeyword +%type OptionalBusMasterKeyword +%type OptionalReadWriteKeyword +%type ParityTypeKeyword +%type PinConfigByte +%type PinConfigKeyword +%type RangeTypeKeyword +%type RegionSpaceKeyword +%type ResourceTypeKeyword +%type SerializeRuleKeyword +%type ShareTypeKeyword +%type SlaveModeKeyword +%type StopBitsKeyword +%type TranslationKeyword +%type TypeKeyword +%type UpdateRuleKeyword +%type WireModeKeyword +%type XferSizeKeyword +%type XferTypeKeyword + +/* Types */ + +%type SuperName +%type ObjectTypeName +%type ArgTerm +%type LocalTerm +%type DebugTerm + +%type Integer +%type ByteConst +%type WordConst +%type DWordConst +%type QWordConst +%type String + +%type ConstTerm +%type ConstExprTerm +%type ByteConstExpr +%type WordConstExpr +%type DWordConstExpr +%type QWordConstExpr + +%type DWordList +%type BufferTerm +%type ByteList + +%type PackageElement +%type PackageList +%type PackageTerm +%type VarPackageLengthTerm + +/* Macros */ + +%type EISAIDTerm +%type ResourceMacroList +%type ResourceMacroTerm +%type ResourceTemplateTerm +%type PldKeyword +%type PldKeywordList +%type ToPLDTerm +%type ToUUIDTerm +%type UnicodeTerm +%type PrintfArgList +%type PrintfTerm +%type FprintfTerm + +/* Resource Descriptors */ + +%type ConnectionTerm +%type DMATerm +%type DWordIOTerm +%type DWordMemoryTerm +%type DWordSpaceTerm +%type EndDependentFnTerm +%type ExtendedIOTerm +%type ExtendedMemoryTerm +%type ExtendedSpaceTerm +%type FixedDmaTerm +%type FixedIOTerm +%type GpioIntTerm +%type GpioIoTerm +%type I2cSerialBusTerm +%type InterruptTerm +%type IOTerm +%type IRQNoFlagsTerm +%type IRQTerm +%type Memory24Term +%type Memory32FixedTerm +%type Memory32Term +%type NameSeg +%type NameString +%type QWordIOTerm +%type QWordMemoryTerm +%type QWordSpaceTerm +%type RegisterTerm +%type SpiSerialBusTerm +%type StartDependentFnNoPriTerm +%type StartDependentFnTerm +%type UartSerialBusTerm +%type VendorLongTerm +%type VendorShortTerm +%type WordBusNumberTerm +%type WordIOTerm +%type WordSpaceTerm + +/* Local types that help construct the AML, not in ACPI spec */ + +%type AmlPackageLengthTerm +%type IncludeEndTerm +%type NameStringItem +%type TermArgItem + +%type OptionalAccessSize +%type OptionalAddressingMode +%type OptionalAddressRange +%type OptionalBitsPerByte +%type OptionalBuffer_Last +%type OptionalByteConstExpr +%type OptionalCount +%type OptionalDecodeType +%type OptionalDevicePolarity +%type OptionalDWordConstExpr +%type OptionalEndian +%type OptionalFlowControl +%type OptionalIoRestriction +%type OptionalListString +%type OptionalMaxType +%type OptionalMemType +%type OptionalMinType +%type OptionalNameString +%type OptionalNameString_First +%type OptionalNameString_Last +%type OptionalObjectTypeKeyword +%type OptionalParameterTypePackage +%type OptionalParameterTypesPackage +%type OptionalParityType +%type OptionalQWordConstExpr +%type OptionalRangeType +%type OptionalReference +%type OptionalResourceType +%type OptionalResourceType_First +%type OptionalReturnArg +%type OptionalSerializeRuleKeyword +%type OptionalShareType +%type OptionalShareType_First +%type OptionalSlaveMode +%type OptionalStopBits +%type OptionalStringData +%type OptionalTermArg +%type OptionalTranslationType_Last +%type OptionalType +%type OptionalType_Last +%type OptionalWireMode +%type OptionalWordConst +%type OptionalWordConstExpr +%type OptionalXferSize + +/* + * C-style expression parser + */ +%type Expression +%type EqualsTerm +%type IndexExpTerm diff --git a/third_party/lib/acpica/source/compiler/aslutils.c b/third_party/lib/acpica/source/compiler/aslutils.c new file mode 100644 index 000000000..82862afcf --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslutils.c @@ -0,0 +1,1182 @@ +/****************************************************************************** + * + * Module Name: aslutils -- compiler utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acdisasm.h" +#include "acnamesp.h" +#include "amlcode.h" +#include "acapps.h" +#include + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslutils") + + +/* Local prototypes */ + +static void +UtPadNameWithUnderscores ( + char *NameSeg, + char *PaddedNameSeg); + +static void +UtAttachNameseg ( + ACPI_PARSE_OBJECT *Op, + char *Name); + + +/****************************************************************************** + * + * FUNCTION: UtQueryForOverwrite + * + * PARAMETERS: Pathname - Output filename + * + * RETURN: TRUE if file does not exist or overwrite is authorized + * + * DESCRIPTION: Query for file overwrite if it already exists. + * + ******************************************************************************/ + +BOOLEAN +UtQueryForOverwrite ( + char *Pathname) +{ + struct stat StatInfo; + + + if (!stat (Pathname, &StatInfo)) + { + fprintf (stderr, "Target file \"%s\" already exists, overwrite? [y|n] ", + Pathname); + + if (getchar () != 'y') + { + return (FALSE); + } + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: UtDisplaySupportedTables + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Print all supported ACPI table names. + * + ******************************************************************************/ + +void +UtDisplaySupportedTables ( + void) +{ + const AH_TABLE *TableData; + UINT32 i; + + + printf ("\nACPI tables supported by iASL version %8.8X:\n" + " (Compiler, Disassembler, Template Generator)\n\n", + ACPI_CA_VERSION); + + /* All ACPI tables with the common table header */ + + printf ("\n Supported ACPI tables:\n"); + for (TableData = AcpiSupportedTables, i = 1; + TableData->Signature; TableData++, i++) + { + printf ("%8u) %s %s\n", i, + TableData->Signature, TableData->Description); + } +} + + +/******************************************************************************* + * + * FUNCTION: UtDisplayConstantOpcodes + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Print AML opcodes that can be used in constant expressions. + * + ******************************************************************************/ + +void +UtDisplayConstantOpcodes ( + void) +{ + UINT32 i; + + + printf ("Constant expression opcode information\n\n"); + + for (i = 0; i < sizeof (AcpiGbl_AmlOpInfo) / sizeof (ACPI_OPCODE_INFO); i++) + { + if (AcpiGbl_AmlOpInfo[i].Flags & AML_CONSTANT) + { + printf ("%s\n", AcpiGbl_AmlOpInfo[i].Name); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: UtLocalCalloc + * + * PARAMETERS: Size - Bytes to be allocated + * + * RETURN: Pointer to the allocated memory. Guaranteed to be valid. + * + * DESCRIPTION: Allocate zero-initialized memory. Aborts the compile on an + * allocation failure, on the assumption that nothing more can be + * accomplished. + * + ******************************************************************************/ + +void * +UtLocalCalloc ( + UINT32 Size) +{ + void *Allocated; + + + Allocated = ACPI_ALLOCATE_ZEROED (Size); + if (!Allocated) + { + AslCommonError (ASL_ERROR, ASL_MSG_MEMORY_ALLOCATION, + Gbl_CurrentLineNumber, Gbl_LogicalLineNumber, + Gbl_InputByteCount, Gbl_CurrentColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, NULL); + + CmCleanupAndExit (); + exit (1); + } + + TotalAllocations++; + TotalAllocated += Size; + return (Allocated); +} + + +/******************************************************************************* + * + * FUNCTION: UtBeginEvent + * + * PARAMETERS: Name - Ascii name of this event + * + * RETURN: Event number (integer index) + * + * DESCRIPTION: Saves the current time with this event + * + ******************************************************************************/ + +UINT8 +UtBeginEvent ( + char *Name) +{ + + if (AslGbl_NextEvent >= ASL_NUM_EVENTS) + { + AcpiOsPrintf ("Ran out of compiler event structs!\n"); + return (AslGbl_NextEvent); + } + + /* Init event with current (start) time */ + + AslGbl_Events[AslGbl_NextEvent].StartTime = AcpiOsGetTimer (); + AslGbl_Events[AslGbl_NextEvent].EventName = Name; + AslGbl_Events[AslGbl_NextEvent].Valid = TRUE; + return (AslGbl_NextEvent++); +} + + +/******************************************************************************* + * + * FUNCTION: UtEndEvent + * + * PARAMETERS: Event - Event number (integer index) + * + * RETURN: None + * + * DESCRIPTION: Saves the current time (end time) with this event + * + ******************************************************************************/ + +void +UtEndEvent ( + UINT8 Event) +{ + + if (Event >= ASL_NUM_EVENTS) + { + return; + } + + /* Insert end time for event */ + + AslGbl_Events[Event].EndTime = AcpiOsGetTimer (); +} + + +/******************************************************************************* + * + * FUNCTION: UtConvertByteToHex + * + * PARAMETERS: RawByte - Binary data + * Buffer - Pointer to where the hex bytes will be + * stored + * + * RETURN: Ascii hex byte is stored in Buffer. + * + * DESCRIPTION: Perform hex-to-ascii translation. The return data is prefixed + * with "0x" + * + ******************************************************************************/ + +void +UtConvertByteToHex ( + UINT8 RawByte, + UINT8 *Buffer) +{ + + Buffer[0] = '0'; + Buffer[1] = 'x'; + + Buffer[2] = (UINT8) AcpiUtHexToAsciiChar (RawByte, 4); + Buffer[3] = (UINT8) AcpiUtHexToAsciiChar (RawByte, 0); +} + + +/******************************************************************************* + * + * FUNCTION: UtConvertByteToAsmHex + * + * PARAMETERS: RawByte - Binary data + * Buffer - Pointer to where the hex bytes will be + * stored + * + * RETURN: Ascii hex byte is stored in Buffer. + * + * DESCRIPTION: Perform hex-to-ascii translation. The return data is prefixed + * with '0', and a trailing 'h' is added. + * + ******************************************************************************/ + +void +UtConvertByteToAsmHex ( + UINT8 RawByte, + UINT8 *Buffer) +{ + + Buffer[0] = '0'; + Buffer[1] = (UINT8) AcpiUtHexToAsciiChar (RawByte, 4); + Buffer[2] = (UINT8) AcpiUtHexToAsciiChar (RawByte, 0); + Buffer[3] = 'h'; +} + + +/******************************************************************************* + * + * FUNCTION: DbgPrint + * + * PARAMETERS: Type - Type of output + * Fmt - Printf format string + * ... - variable printf list + * + * RETURN: None + * + * DESCRIPTION: Conditional print statement. Prints to stderr only if the + * debug flag is set. + * + ******************************************************************************/ + +void +DbgPrint ( + UINT32 Type, + char *Fmt, + ...) +{ + va_list Args; + + + if (!Gbl_DebugFlag) + { + return; + } + + if ((Type == ASL_PARSE_OUTPUT) && + (!(AslCompilerdebug))) + { + return; + } + + va_start (Args, Fmt); + (void) vfprintf (stderr, Fmt, Args); + va_end (Args); + return; +} + + +/******************************************************************************* + * + * FUNCTION: UtPrintFormattedName + * + * PARAMETERS: ParseOpcode - Parser keyword ID + * Level - Indentation level + * + * RETURN: None + * + * DESCRIPTION: Print the ascii name of the parse opcode. + * + ******************************************************************************/ + +#define TEXT_OFFSET 10 + +void +UtPrintFormattedName ( + UINT16 ParseOpcode, + UINT32 Level) +{ + + if (Level) + { + DbgPrint (ASL_TREE_OUTPUT, + "%*s", (3 * Level), " "); + } + DbgPrint (ASL_TREE_OUTPUT, + " %-20.20s", UtGetOpName (ParseOpcode)); + + if (Level < TEXT_OFFSET) + { + DbgPrint (ASL_TREE_OUTPUT, + "%*s", (TEXT_OFFSET - Level) * 3, " "); + } +} + + +/******************************************************************************* + * + * FUNCTION: UtSetParseOpName + * + * PARAMETERS: Op - Parse op to be named. + * + * RETURN: None + * + * DESCRIPTION: Insert the ascii name of the parse opcode + * + ******************************************************************************/ + +void +UtSetParseOpName ( + ACPI_PARSE_OBJECT *Op) +{ + + strncpy (Op->Asl.ParseOpName, UtGetOpName (Op->Asl.ParseOpcode), + ACPI_MAX_PARSEOP_NAME); +} + + +/******************************************************************************* + * + * FUNCTION: UtDisplaySummary + * + * PARAMETERS: FileID - ID of outpout file + * + * RETURN: None + * + * DESCRIPTION: Display compilation statistics + * + ******************************************************************************/ + +void +UtDisplaySummary ( + UINT32 FileId) +{ + UINT32 i; + + + if (FileId != ASL_FILE_STDOUT) + { + /* Compiler name and version number */ + + FlPrintFile (FileId, "%s version %X%s [%s]\n\n", + ASL_COMPILER_NAME, (UINT32) ACPI_CA_VERSION, ACPI_WIDTH, __DATE__); + } + + /* Summary of main input and output files */ + + if (Gbl_FileType == ASL_INPUT_TYPE_ASCII_DATA) + { + FlPrintFile (FileId, + "%-14s %s - %u lines, %u bytes, %u fields\n", + "Table Input:", + Gbl_Files[ASL_FILE_INPUT].Filename, Gbl_CurrentLineNumber, + Gbl_InputByteCount, Gbl_InputFieldCount); + + if ((Gbl_ExceptionCount[ASL_ERROR] == 0) || (Gbl_IgnoreErrors)) + { + FlPrintFile (FileId, + "%-14s %s - %u bytes\n", + "Binary Output:", + Gbl_Files[ASL_FILE_AML_OUTPUT].Filename, Gbl_TableLength); + } + } + else + { + FlPrintFile (FileId, + "%-14s %s - %u lines, %u bytes, %u keywords\n", + "ASL Input:", + Gbl_Files[ASL_FILE_INPUT].Filename, Gbl_CurrentLineNumber, + Gbl_OriginalInputFileSize, TotalKeywords); + + /* AML summary */ + + if ((Gbl_ExceptionCount[ASL_ERROR] == 0) || (Gbl_IgnoreErrors)) + { + if (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle) + { + FlPrintFile (FileId, + "%-14s %s - %u bytes, %u named objects, " + "%u executable opcodes\n", + "AML Output:", + Gbl_Files[ASL_FILE_AML_OUTPUT].Filename, + FlGetFileSize (ASL_FILE_AML_OUTPUT), + TotalNamedObjects, TotalExecutableOpcodes); + } + } + } + + /* Display summary of any optional files */ + + for (i = ASL_FILE_SOURCE_OUTPUT; i <= ASL_MAX_FILE_TYPE; i++) + { + if (!Gbl_Files[i].Filename || !Gbl_Files[i].Handle) + { + continue; + } + + /* .SRC is a temp file unless specifically requested */ + + if ((i == ASL_FILE_SOURCE_OUTPUT) && (!Gbl_SourceOutputFlag)) + { + continue; + } + + /* .PRE is the preprocessor intermediate file */ + + if ((i == ASL_FILE_PREPROCESSOR) && (!Gbl_KeepPreprocessorTempFile)) + { + continue; + } + + FlPrintFile (FileId, "%14s %s - %u bytes\n", + Gbl_Files[i].ShortDescription, + Gbl_Files[i].Filename, FlGetFileSize (i)); + } + + /* Error summary */ + + FlPrintFile (FileId, + "\nCompilation complete. %u Errors, %u Warnings, %u Remarks", + Gbl_ExceptionCount[ASL_ERROR], + Gbl_ExceptionCount[ASL_WARNING] + + Gbl_ExceptionCount[ASL_WARNING2] + + Gbl_ExceptionCount[ASL_WARNING3], + Gbl_ExceptionCount[ASL_REMARK]); + + if (Gbl_FileType != ASL_INPUT_TYPE_ASCII_DATA) + { + FlPrintFile (FileId, ", %u Optimizations", + Gbl_ExceptionCount[ASL_OPTIMIZATION]); + + if (TotalFolds) + { + FlPrintFile (FileId, ", %u Constants Folded", TotalFolds); + } + } + + FlPrintFile (FileId, "\n"); +} + + +/******************************************************************************* + * + * FUNCTION: UtCheckIntegerRange + * + * PARAMETERS: Op - Integer parse node + * LowValue - Smallest allowed value + * HighValue - Largest allowed value + * + * RETURN: Op if OK, otherwise NULL + * + * DESCRIPTION: Check integer for an allowable range + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +UtCheckIntegerRange ( + ACPI_PARSE_OBJECT *Op, + UINT32 LowValue, + UINT32 HighValue) +{ + + if (!Op) + { + return (NULL); + } + + if ((Op->Asl.Value.Integer < LowValue) || + (Op->Asl.Value.Integer > HighValue)) + { + sprintf (MsgBuffer, "0x%X, allowable: 0x%X-0x%X", + (UINT32) Op->Asl.Value.Integer, LowValue, HighValue); + + AslError (ASL_ERROR, ASL_MSG_RANGE, Op, MsgBuffer); + return (NULL); + } + + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: UtStringCacheCalloc + * + * PARAMETERS: Length - Size of buffer requested + * + * RETURN: Pointer to the buffer. Aborts on allocation failure + * + * DESCRIPTION: Allocate a string buffer. Bypass the local + * dynamic memory manager for performance reasons (This has a + * major impact on the speed of the compiler.) + * + ******************************************************************************/ + +char * +UtStringCacheCalloc ( + UINT32 Length) +{ + char *Buffer; + ASL_CACHE_INFO *Cache; + UINT32 CacheSize = ASL_STRING_CACHE_SIZE; + + + if (Length > CacheSize) + { + CacheSize = Length; + + if (Gbl_StringCacheList) + { + Cache = UtLocalCalloc (sizeof (Cache->Next) + CacheSize); + + /* Link new cache buffer just following head of list */ + + Cache->Next = Gbl_StringCacheList->Next; + Gbl_StringCacheList->Next = Cache; + + /* Leave cache management pointers alone as they pertain to head */ + + Gbl_StringCount++; + Gbl_StringSize += Length; + + return (Cache->Buffer); + } + } + + if ((Gbl_StringCacheNext + Length) >= Gbl_StringCacheLast) + { + /* Allocate a new buffer */ + + Cache = UtLocalCalloc (sizeof (Cache->Next) + CacheSize); + + /* Link new cache buffer to head of list */ + + Cache->Next = Gbl_StringCacheList; + Gbl_StringCacheList = Cache; + + /* Setup cache management pointers */ + + Gbl_StringCacheNext = Cache->Buffer; + Gbl_StringCacheLast = Gbl_StringCacheNext + CacheSize; + } + + Gbl_StringCount++; + Gbl_StringSize += Length; + + Buffer = Gbl_StringCacheNext; + Gbl_StringCacheNext += Length; + return (Buffer); +} + + +/****************************************************************************** + * + * FUNCTION: UtExpandLineBuffers + * + * PARAMETERS: None. Updates global line buffer pointers. + * + * RETURN: None. Reallocates the global line buffers + * + * DESCRIPTION: Called if the current line buffer becomes filled. Reallocates + * all global line buffers and updates Gbl_LineBufferSize. NOTE: + * Also used for the initial allocation of the buffers, when + * all of the buffer pointers are NULL. Initial allocations are + * of size ASL_DEFAULT_LINE_BUFFER_SIZE + * + *****************************************************************************/ + +void +UtExpandLineBuffers ( + void) +{ + UINT32 NewSize; + + + /* Attempt to double the size of all line buffers */ + + NewSize = Gbl_LineBufferSize * 2; + if (Gbl_CurrentLineBuffer) + { + DbgPrint (ASL_DEBUG_OUTPUT, + "Increasing line buffer size from %u to %u\n", + Gbl_LineBufferSize, NewSize); + } + + Gbl_CurrentLineBuffer = realloc (Gbl_CurrentLineBuffer, NewSize); + Gbl_LineBufPtr = Gbl_CurrentLineBuffer; + if (!Gbl_CurrentLineBuffer) + { + goto ErrorExit; + } + + Gbl_MainTokenBuffer = realloc (Gbl_MainTokenBuffer, NewSize); + if (!Gbl_MainTokenBuffer) + { + goto ErrorExit; + } + + Gbl_MacroTokenBuffer = realloc (Gbl_MacroTokenBuffer, NewSize); + if (!Gbl_MacroTokenBuffer) + { + goto ErrorExit; + } + + Gbl_ExpressionTokenBuffer = realloc (Gbl_ExpressionTokenBuffer, NewSize); + if (!Gbl_ExpressionTokenBuffer) + { + goto ErrorExit; + } + + Gbl_LineBufferSize = NewSize; + return; + + + /* On error above, simply issue error messages and abort, cannot continue */ + +ErrorExit: + printf ("Could not increase line buffer size from %u to %u\n", + Gbl_LineBufferSize, Gbl_LineBufferSize * 2); + + AslError (ASL_ERROR, ASL_MSG_BUFFER_ALLOCATION, + NULL, NULL); + AslAbort (); +} + + +/****************************************************************************** + * + * FUNCTION: UtFreeLineBuffers + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Free all line buffers + * + *****************************************************************************/ + +void +UtFreeLineBuffers ( + void) +{ + + free (Gbl_CurrentLineBuffer); + free (Gbl_MainTokenBuffer); + free (Gbl_MacroTokenBuffer); + free (Gbl_ExpressionTokenBuffer); +} + + +/******************************************************************************* + * + * FUNCTION: UtInternalizeName + * + * PARAMETERS: ExternalName - Name to convert + * ConvertedName - Where the converted name is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert an external (ASL) name to an internal (AML) name + * + ******************************************************************************/ + +ACPI_STATUS +UtInternalizeName ( + char *ExternalName, + char **ConvertedName) +{ + ACPI_NAMESTRING_INFO Info; + ACPI_STATUS Status; + + + if (!ExternalName) + { + return (AE_OK); + } + + /* Get the length of the new internal name */ + + Info.ExternalName = ExternalName; + AcpiNsGetInternalNameLength (&Info); + + /* We need a segment to store the internal name */ + + Info.InternalName = UtStringCacheCalloc (Info.Length); + if (!Info.InternalName) + { + return (AE_NO_MEMORY); + } + + /* Build the name */ + + Status = AcpiNsBuildInternalName (&Info); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *ConvertedName = Info.InternalName; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: UtPadNameWithUnderscores + * + * PARAMETERS: NameSeg - Input nameseg + * PaddedNameSeg - Output padded nameseg + * + * RETURN: Padded nameseg. + * + * DESCRIPTION: Pads a NameSeg with underscores if necessary to form a full + * ACPI_NAME. + * + ******************************************************************************/ + +static void +UtPadNameWithUnderscores ( + char *NameSeg, + char *PaddedNameSeg) +{ + UINT32 i; + + + for (i = 0; (i < ACPI_NAME_SIZE); i++) + { + if (*NameSeg) + { + *PaddedNameSeg = *NameSeg; + NameSeg++; + } + else + { + *PaddedNameSeg = '_'; + } + + PaddedNameSeg++; + } +} + + +/******************************************************************************* + * + * FUNCTION: UtAttachNameseg + * + * PARAMETERS: Op - Parent parse node + * Name - Full ExternalName + * + * RETURN: None; Sets the NameSeg field in parent node + * + * DESCRIPTION: Extract the last nameseg of the ExternalName and store it + * in the NameSeg field of the Op. + * + ******************************************************************************/ + +static void +UtAttachNameseg ( + ACPI_PARSE_OBJECT *Op, + char *Name) +{ + char *NameSeg; + char PaddedNameSeg[4]; + + + if (!Name) + { + return; + } + + /* Look for the last dot in the namepath */ + + NameSeg = strrchr (Name, '.'); + if (NameSeg) + { + /* Found last dot, we have also found the final nameseg */ + + NameSeg++; + UtPadNameWithUnderscores (NameSeg, PaddedNameSeg); + } + else + { + /* No dots in the namepath, there is only a single nameseg. */ + /* Handle prefixes */ + + while (ACPI_IS_ROOT_PREFIX (*Name) || + ACPI_IS_PARENT_PREFIX (*Name)) + { + Name++; + } + + /* Remaining string should be one single nameseg */ + + UtPadNameWithUnderscores (Name, PaddedNameSeg); + } + + ACPI_MOVE_NAME (Op->Asl.NameSeg, PaddedNameSeg); +} + + +/******************************************************************************* + * + * FUNCTION: UtAttachNamepathToOwner + * + * PARAMETERS: Op - Parent parse node + * NameOp - Node that contains the name + * + * RETURN: Sets the ExternalName and Namepath in the parent node + * + * DESCRIPTION: Store the name in two forms in the parent node: The original + * (external) name, and the internalized name that is used within + * the ACPI namespace manager. + * + ******************************************************************************/ + +void +UtAttachNamepathToOwner ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *NameOp) +{ + ACPI_STATUS Status; + + + /* Full external path */ + + Op->Asl.ExternalName = NameOp->Asl.Value.String; + + /* Save the NameOp for possible error reporting later */ + + Op->Asl.ParentMethod = (void *) NameOp; + + /* Last nameseg of the path */ + + UtAttachNameseg (Op, Op->Asl.ExternalName); + + /* Create internalized path */ + + Status = UtInternalizeName (NameOp->Asl.Value.String, &Op->Asl.Namepath); + if (ACPI_FAILURE (Status)) + { + /* TBD: abort on no memory */ + } +} + + +/******************************************************************************* + * + * FUNCTION: UtDoConstant + * + * PARAMETERS: String - Hex, Octal, or Decimal string + * + * RETURN: Converted Integer + * + * DESCRIPTION: Convert a string to an integer, with error checking. + * + ******************************************************************************/ + +UINT64 +UtDoConstant ( + char *String) +{ + ACPI_STATUS Status; + UINT64 Converted; + char ErrBuf[64]; + + + Status = stroul64 (String, 0, &Converted); + if (ACPI_FAILURE (Status)) + { + sprintf (ErrBuf, "%s %s\n", "Conversion error:", + AcpiFormatException (Status)); + AslCompilererror (ErrBuf); + } + + return (Converted); +} + + +/* TBD: use version in ACPICA main code base? */ + +/******************************************************************************* + * + * FUNCTION: stroul64 + * + * PARAMETERS: String - Null terminated string + * Terminater - Where a pointer to the terminating byte + * is returned + * Base - Radix of the string + * + * RETURN: Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. + * + ******************************************************************************/ + +ACPI_STATUS +stroul64 ( + char *String, + UINT32 Base, + UINT64 *RetInteger) +{ + UINT32 Index; + UINT32 Sign; + UINT64 ReturnValue = 0; + ACPI_STATUS Status = AE_OK; + + + *RetInteger = 0; + + switch (Base) + { + case 0: + case 8: + case 10: + case 16: + + break; + + default: + /* + * The specified Base parameter is not in the domain of + * this function: + */ + return (AE_BAD_PARAMETER); + } + + /* Skip over any white space in the buffer: */ + + while (isspace ((int) *String) || *String == '\t') + { + ++String; + } + + /* + * The buffer may contain an optional plus or minus sign. + * If it does, then skip over it but remember what is was: + */ + if (*String == '-') + { + Sign = ACPI_SIGN_NEGATIVE; + ++String; + } + else if (*String == '+') + { + ++String; + Sign = ACPI_SIGN_POSITIVE; + } + else + { + Sign = ACPI_SIGN_POSITIVE; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is octal, decimal, or hexadecimal: + */ + if (Base == 0) + { + if (*String == '0') + { + if (tolower ((int) *(++String)) == 'x') + { + Base = 16; + ++String; + } + else + { + Base = 8; + } + } + else + { + Base = 10; + } + } + + /* + * For octal and hexadecimal bases, skip over the leading + * 0 or 0x, if they are present. + */ + if (Base == 8 && *String == '0') + { + String++; + } + + if (Base == 16 && + *String == '0' && + tolower ((int) *(++String)) == 'x') + { + String++; + } + + /* Main loop: convert the string to an unsigned long */ + + while (*String) + { + if (isdigit ((int) *String)) + { + Index = ((UINT8) *String) - '0'; + } + else + { + Index = (UINT8) toupper ((int) *String); + if (isupper ((int) Index)) + { + Index = Index - 'A' + 10; + } + else + { + goto ErrorExit; + } + } + + if (Index >= Base) + { + goto ErrorExit; + } + + /* Check to see if value is out of range: */ + + if (ReturnValue > ((ACPI_UINT64_MAX - (UINT64) Index) / + (UINT64) Base)) + { + goto ErrorExit; + } + else + { + ReturnValue *= Base; + ReturnValue += Index; + } + + ++String; + } + + + /* If a minus sign was present, then "the conversion is negated": */ + + if (Sign == ACPI_SIGN_NEGATIVE) + { + ReturnValue = (ACPI_UINT32_MAX - ReturnValue) + 1; + } + + *RetInteger = ReturnValue; + return (Status); + + +ErrorExit: + switch (Base) + { + case 8: + + Status = AE_BAD_OCTAL_CONSTANT; + break; + + case 10: + + Status = AE_BAD_DECIMAL_CONSTANT; + break; + + case 16: + + Status = AE_BAD_HEX_CONSTANT; + break; + + default: + + /* Base validated above */ + + break; + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/compiler/asluuid.c b/third_party/lib/acpica/source/compiler/asluuid.c new file mode 100644 index 000000000..9a0fc5c0e --- /dev/null +++ b/third_party/lib/acpica/source/compiler/asluuid.c @@ -0,0 +1,153 @@ +/****************************************************************************** + * + * Module Name: asluuid-- compiler UUID support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("asluuid") + + +extern UINT8 AcpiGbl_MapToUuidOffset[UUID_BUFFER_LENGTH]; + + +/******************************************************************************* + * + * FUNCTION: AuValiduateUuid + * + * PARAMETERS: InString - 36-byte formatted UUID string + * + * RETURN: Status + * + * DESCRIPTION: Check all 36 characters for correct format + * + ******************************************************************************/ + +ACPI_STATUS +AuValidateUuid ( + char *InString) +{ + UINT32 i; + + + if (!InString || (strlen (InString) != UUID_STRING_LENGTH)) + { + return (AE_BAD_PARAMETER); + } + + /* Check all 36 characters for correct format */ + + for (i = 0; i < UUID_STRING_LENGTH; i++) + { + /* Must have 4 hyphens (dashes) in these positions: */ + + if ((i == UUID_HYPHEN1_OFFSET) || + (i == UUID_HYPHEN2_OFFSET) || + (i == UUID_HYPHEN3_OFFSET) || + (i == UUID_HYPHEN4_OFFSET)) + { + if (InString[i] != '-') + { + return (AE_BAD_PARAMETER); + } + } + else + { + /* All other positions must contain hex digits */ + + if (!isxdigit ((int) InString[i])) + { + return (AE_BAD_PARAMETER); + } + } + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AuConvertUuidToString + * + * PARAMETERS: UuidBuffer - 16-byte UUID buffer + * OutString - 36-byte formatted UUID string + * + * RETURN: Status + * + * DESCRIPTION: Convert 16-byte UUID buffer to 36-byte formatted UUID string + * OutString must be 37 bytes to include null terminator. + * + ******************************************************************************/ + +ACPI_STATUS +AuConvertUuidToString ( + char *UuidBuffer, + char *OutString) +{ + UINT32 i; + + + if (!UuidBuffer || !OutString) + { + return (AE_BAD_PARAMETER); + } + + for (i = 0; i < UUID_BUFFER_LENGTH; i++) + { + OutString[AcpiGbl_MapToUuidOffset[i]] = + AcpiUtHexToAsciiChar (UuidBuffer[i], 4); + + OutString[AcpiGbl_MapToUuidOffset[i] + 1] = + AcpiUtHexToAsciiChar (UuidBuffer[i], 0); + } + + /* Insert required hyphens (dashes) */ + + OutString[UUID_HYPHEN1_OFFSET] = + OutString[UUID_HYPHEN2_OFFSET] = + OutString[UUID_HYPHEN3_OFFSET] = + OutString[UUID_HYPHEN4_OFFSET] = '-'; + + OutString[UUID_STRING_LENGTH] = 0; /* Null terminate */ + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/aslwalks.c b/third_party/lib/acpica/source/compiler/aslwalks.c new file mode 100644 index 000000000..aa4f6eab3 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslwalks.c @@ -0,0 +1,963 @@ +/****************************************************************************** + * + * Module Name: aslwalks.c - Miscellaneous analytical parse tree walks + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acparser.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslwalks") + + +/* Local prototypes */ + +static void +AnAnalyzeStoreOperator ( + ACPI_PARSE_OBJECT *Op); + + +/******************************************************************************* + * + * FUNCTION: AnMethodTypingWalkEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback for typing walk. Complete the method + * return analysis. Check methods for: + * 1) Initialized local variables + * 2) Valid arguments + * 3) Return types + * + ******************************************************************************/ + +ACPI_STATUS +AnMethodTypingWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + UINT32 ThisOpBtype; + + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_METHOD: + + Op->Asl.CompileFlags |= NODE_METHOD_TYPED; + break; + + case PARSEOP_RETURN: + + if ((Op->Asl.Child) && + (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) + { + ThisOpBtype = AnGetBtype (Op->Asl.Child); + + if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) && + (ThisOpBtype == (ACPI_UINT32_MAX -1))) + { + /* + * The called method is untyped at this time (typically a + * forward reference). + * + * Check for a recursive method call first. + */ + if (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op) + { + /* We must type the method here */ + + TrWalkParseTree (Op->Asl.Child->Asl.Node->Op, + ASL_WALK_VISIT_UPWARD, NULL, + AnMethodTypingWalkEnd, NULL); + + ThisOpBtype = AnGetBtype (Op->Asl.Child); + } + } + + /* Returns a value, save the value type */ + + if (Op->Asl.ParentMethod) + { + Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisOpBtype; + } + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AnOperandTypecheckWalkEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback for analysis walk. Complete method + * return analysis. + * + ******************************************************************************/ + +ACPI_STATUS +AnOperandTypecheckWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + const ACPI_OPCODE_INFO *OpInfo; + UINT32 RuntimeArgTypes; + UINT32 RuntimeArgTypes2; + UINT32 RequiredBtypes; + UINT32 ThisNodeBtype; + UINT32 CommonBtypes; + UINT32 OpcodeClass; + ACPI_PARSE_OBJECT *ArgOp; + UINT32 ArgType; + + + switch (Op->Asl.AmlOpcode) + { + case AML_RAW_DATA_BYTE: + case AML_RAW_DATA_WORD: + case AML_RAW_DATA_DWORD: + case AML_RAW_DATA_QWORD: + case AML_RAW_DATA_BUFFER: + case AML_RAW_DATA_CHAIN: + case AML_PACKAGE_LENGTH: + case AML_UNASSIGNED_OPCODE: + case AML_DEFAULT_ARG_OP: + + /* Ignore the internal (compiler-only) AML opcodes */ + + return (AE_OK); + + default: + + break; + } + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + if (!OpInfo) + { + return (AE_OK); + } + + ArgOp = Op->Asl.Child; + OpcodeClass = OpInfo->Class; + RuntimeArgTypes = OpInfo->RuntimeArgs; + +#ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE + /* + * Update 11/2008: In practice, we can't perform this check. A simple + * analysis is not sufficient. Also, it can cause errors when compiling + * disassembled code because of the way Switch operators are implemented + * (a While(One) loop with a named temp variable created within.) + */ + + /* + * If we are creating a named object, check if we are within a while loop + * by checking if the parent is a WHILE op. This is a simple analysis, but + * probably sufficient for many cases. + * + * Allow Scope(), Buffer(), and Package(). + */ + if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) || + ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE))) + { + if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP) + { + AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL); + } + } +#endif + + /* + * Special case for control opcodes IF/RETURN/WHILE since they + * have no runtime arg list (at this time) + */ + switch (Op->Asl.AmlOpcode) + { + case AML_IF_OP: + case AML_WHILE_OP: + case AML_RETURN_OP: + + if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) + { + /* Check for an internal method */ + + if (AnIsInternalMethod (ArgOp)) + { + return (AE_OK); + } + + /* The lone arg is a method call, check it */ + + RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER); + if (Op->Asl.AmlOpcode == AML_RETURN_OP) + { + RequiredBtypes = 0xFFFFFFFF; + } + + ThisNodeBtype = AnGetBtype (ArgOp); + if (ThisNodeBtype == ACPI_UINT32_MAX) + { + return (AE_OK); + } + + AnCheckMethodReturnValue (Op, OpInfo, ArgOp, + RequiredBtypes, ThisNodeBtype); + } + return (AE_OK); + + case AML_EXTERNAL_OP: + /* + * Not really a "runtime" opcode since it used by disassembler only. + * The parser will find any issues with the operands. + */ + return (AE_OK); + + default: + + break; + } + + /* Ignore the non-executable opcodes */ + + if (RuntimeArgTypes == ARGI_INVALID_OPCODE) + { + return (AE_OK); + } + + /* + * Special handling for certain opcodes. + */ + switch (Op->Asl.AmlOpcode) + { + /* BankField has one TermArg */ + + case AML_BANK_FIELD_OP: + + OpcodeClass = AML_CLASS_EXECUTE; + ArgOp = ArgOp->Asl.Next; + ArgOp = ArgOp->Asl.Next; + break; + + /* Operation Region has 2 TermArgs */ + + case AML_REGION_OP: + + OpcodeClass = AML_CLASS_EXECUTE; + ArgOp = ArgOp->Asl.Next; + ArgOp = ArgOp->Asl.Next; + break; + + /* DataTableRegion has 3 TermArgs */ + + case AML_DATA_REGION_OP: + + OpcodeClass = AML_CLASS_EXECUTE; + ArgOp = ArgOp->Asl.Next; + break; + + /* Buffers/Packages have a length that is a TermArg */ + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + /* If length is a constant, we are done */ + + if ((ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) || + (ArgOp->Asl.ParseOpcode == PARSEOP_RAW_DATA)) + { + return (AE_OK); + } + break; + + /* Store can write any object to the Debug object */ + + case AML_STORE_OP: + /* + * If this is a Store() to the Debug object, we don't need + * to perform any further validation -- because a Store of + * any object to Debug is permitted and supported. + */ + if (ArgOp->Asl.Next->Asl.AmlOpcode == AML_DEBUG_OP) + { + return (AE_OK); + } + break; + + default: + break; + } + + switch (OpcodeClass) + { + case AML_CLASS_EXECUTE: + case AML_CLASS_CREATE: + case AML_CLASS_CONTROL: + case AML_CLASS_RETURN_VALUE: + + /* Reverse the runtime argument list */ + + RuntimeArgTypes2 = 0; + while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes))) + { + RuntimeArgTypes2 <<= ARG_TYPE_WIDTH; + RuntimeArgTypes2 |= ArgType; + INCREMENT_ARG_LIST (RuntimeArgTypes); + } + + /* Typecheck each argument */ + + while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2))) + { + /* Get the required type(s) for the argument */ + + RequiredBtypes = AnMapArgTypeToBtype (ArgType); + + if (!ArgOp) + { + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, + "Null ArgOp in argument loop"); + AslAbort (); + } + + /* Get the actual type of the argument */ + + ThisNodeBtype = AnGetBtype (ArgOp); + if (ThisNodeBtype == ACPI_UINT32_MAX) + { + goto NextArgument; + } + + /* Examine the arg based on the required type of the arg */ + + switch (ArgType) + { + case ARGI_TARGETREF: + + if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) + { + /* ZERO is the placeholder for "don't store result" */ + + ThisNodeBtype = RequiredBtypes; + break; + } + + /* Fallthrough */ + + case ARGI_STORE_TARGET: + + if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) + { + /* + * This is the case where an original reference to a resource + * descriptor field has been replaced by an (Integer) offset. + * These named fields are supported at compile-time only; + * the names are not passed to the interpreter (via the AML). + */ + if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || + (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, + ArgOp, NULL); + } + else + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, + ArgOp, NULL); + } + } + break; + + +#ifdef __FUTURE_IMPLEMENTATION +/* + * Possible future typechecking support + */ + case ARGI_REFERENCE: /* References */ + case ARGI_INTEGER_REF: + case ARGI_OBJECT_REF: + case ARGI_DEVICE_REF: + + switch (ArgOp->Asl.ParseOpcode) + { + case PARSEOP_LOCAL0: + case PARSEOP_LOCAL1: + case PARSEOP_LOCAL2: + case PARSEOP_LOCAL3: + case PARSEOP_LOCAL4: + case PARSEOP_LOCAL5: + case PARSEOP_LOCAL6: + case PARSEOP_LOCAL7: + + /* TBD: implement analysis of current value (type) of the local */ + /* For now, just treat any local as a typematch */ + + /*ThisNodeBtype = RequiredBtypes;*/ + break; + + case PARSEOP_ARG0: + case PARSEOP_ARG1: + case PARSEOP_ARG2: + case PARSEOP_ARG3: + case PARSEOP_ARG4: + case PARSEOP_ARG5: + case PARSEOP_ARG6: + + /* Hard to analyze argument types, so we won't */ + /* for now. Just treat any arg as a typematch */ + + /* ThisNodeBtype = RequiredBtypes; */ + break; + + case PARSEOP_DEBUG: + case PARSEOP_REFOF: + case PARSEOP_INDEX: + default: + + break; + } + break; +#endif + case ARGI_INTEGER: + default: + + break; + } + + + /* Check for a type mismatch (required versus actual) */ + + CommonBtypes = ThisNodeBtype & RequiredBtypes; + + if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) + { + if (AnIsInternalMethod (ArgOp)) + { + return (AE_OK); + } + + /* Check a method call for a valid return value */ + + AnCheckMethodReturnValue (Op, OpInfo, ArgOp, + RequiredBtypes, ThisNodeBtype); + } + + /* + * Now check if the actual type(s) match at least one + * bit to the required type + */ + else if (!CommonBtypes) + { + /* No match -- this is a type mismatch error */ + + AnFormatBtype (StringBuffer, ThisNodeBtype); + AnFormatBtype (StringBuffer2, RequiredBtypes); + + sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]", + StringBuffer, OpInfo->Name, StringBuffer2); + + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, + ArgOp, MsgBuffer); + } + + NextArgument: + ArgOp = ArgOp->Asl.Next; + INCREMENT_ARG_LIST (RuntimeArgTypes2); + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AnOtherSemanticAnalysisWalkBegin + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback for the analysis walk. Checks for + * miscellaneous issues in the code. + * + ******************************************************************************/ + +ACPI_STATUS +AnOtherSemanticAnalysisWalkBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_PARSE_OBJECT *ArgOp; + ACPI_PARSE_OBJECT *PrevArgOp = NULL; + const ACPI_OPCODE_INFO *OpInfo; + ACPI_NAMESPACE_NODE *Node; + + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + + + /* + * Determine if an execution class operator actually does something by + * checking if it has a target and/or the function return value is used. + * (Target is optional, so a standalone statement can actually do nothing.) + */ + if ((OpInfo->Class == AML_CLASS_EXECUTE) && + (OpInfo->Flags & AML_HAS_RETVAL) && + (!AnIsResultUsed (Op))) + { + if (OpInfo->Flags & AML_HAS_TARGET) + { + /* + * Find the target node, it is always the last child. If the target + * is not specified in the ASL, a default node of type Zero was + * created by the parser. + */ + ArgOp = Op->Asl.Child; + while (ArgOp->Asl.Next) + { + PrevArgOp = ArgOp; + ArgOp = ArgOp->Asl.Next; + } + + /* Divide() is the only weird case, it has two targets */ + + if (Op->Asl.AmlOpcode == AML_DIVIDE_OP) + { + if ((ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) && + (PrevArgOp) && + (PrevArgOp->Asl.ParseOpcode == PARSEOP_ZERO)) + { + AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, + Op, Op->Asl.ExternalName); + } + } + + else if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) + { + AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, + Op, Op->Asl.ExternalName); + } + } + else + { + /* + * Has no target and the result is not used. Only a couple opcodes + * can have this combination. + */ + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_ACQUIRE: + case PARSEOP_WAIT: + case PARSEOP_LOADTABLE: + + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, + Op, Op->Asl.ExternalName); + break; + } + } + } + + + /* + * Semantic checks for individual ASL operators + */ + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_STORE: + + if (Gbl_DoTypechecking) + { + AnAnalyzeStoreOperator (Op); + } + break; + + + case PARSEOP_ACQUIRE: + case PARSEOP_WAIT: + /* + * Emit a warning if the timeout parameter for these operators is not + * ACPI_WAIT_FOREVER, and the result value from the operator is not + * checked, meaning that a timeout could happen, but the code + * would not know about it. + */ + + /* First child is the namepath, 2nd child is timeout */ + + ArgOp = Op->Asl.Child; + ArgOp = ArgOp->Asl.Next; + + /* + * Check for the WAIT_FOREVER case - defined by the ACPI spec to be + * 0xFFFF or greater + */ + if (((ArgOp->Asl.ParseOpcode == PARSEOP_WORDCONST) || + (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)) && + (ArgOp->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER)) + { + break; + } + + /* + * The operation could timeout. If the return value is not used + * (indicates timeout occurred), issue a warning + */ + if (!AnIsResultUsed (Op)) + { + AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgOp, + Op->Asl.ExternalName); + } + break; + + case PARSEOP_CREATEFIELD: + /* + * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand + */ + ArgOp = Op->Asl.Child; + ArgOp = ArgOp->Asl.Next; + ArgOp = ArgOp->Asl.Next; + + if ((ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) || + ((ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) && + (ArgOp->Asl.Value.Integer == 0))) + { + AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgOp, NULL); + } + break; + + case PARSEOP_CONNECTION: + /* + * Ensure that the referenced operation region has the correct SPACE_ID. + * From the grammar/parser, we know the parent is a FIELD definition. + */ + ArgOp = Op->Asl.Parent; /* Field definition */ + ArgOp = ArgOp->Asl.Child; /* First child is the OpRegion Name */ + Node = ArgOp->Asl.Node; /* OpRegion namespace node */ + if (!Node) + { + break; + } + + ArgOp = Node->Op; /* OpRegion definition */ + ArgOp = ArgOp->Asl.Child; /* First child is the OpRegion Name */ + ArgOp = ArgOp->Asl.Next; /* Next peer is the SPACE_ID (what we want) */ + + /* + * The Connection() operator is only valid for the following operation + * region SpaceIds: GeneralPurposeIo and GenericSerialBus. + */ + if ((ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) && + (ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS)) + { + AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL); + } + break; + + case PARSEOP_FIELD: + /* + * Ensure that fields for GeneralPurposeIo and GenericSerialBus + * contain at least one Connection() operator + */ + ArgOp = Op->Asl.Child; /* 1st child is the OpRegion Name */ + Node = ArgOp->Asl.Node; /* OpRegion namespace node */ + if (!Node) + { + break; + } + + ArgOp = Node->Op; /* OpRegion definition */ + ArgOp = ArgOp->Asl.Child; /* First child is the OpRegion Name */ + ArgOp = ArgOp->Asl.Next; /* Next peer is the SPACE_ID (what we want) */ + + /* We are only interested in GeneralPurposeIo and GenericSerialBus */ + + if ((ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) && + (ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS)) + { + break; + } + + ArgOp = Op->Asl.Child; /* 1st child is the OpRegion Name */ + ArgOp = ArgOp->Asl.Next; /* AccessType */ + ArgOp = ArgOp->Asl.Next; /* LockRule */ + ArgOp = ArgOp->Asl.Next; /* UpdateRule */ + ArgOp = ArgOp->Asl.Next; /* Start of FieldUnitList */ + + /* Walk the FieldUnitList */ + + while (ArgOp) + { + if (ArgOp->Asl.ParseOpcode == PARSEOP_CONNECTION) + { + break; + } + else if (ArgOp->Asl.ParseOpcode == PARSEOP_NAMESEG) + { + AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgOp, NULL); + break; + } + + ArgOp = ArgOp->Asl.Next; + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AnAnalyzeStoreOperator + * + * PARAMETERS: Op - Store() operator + * + * RETURN: None + * + * DESCRIPTION: Analyze a store operator. Mostly for stores to/from package + * objects where there are more restrictions than other data + * types. + * + ******************************************************************************/ + +static void +AnAnalyzeStoreOperator ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_NAMESPACE_NODE *SourceNode; + ACPI_NAMESPACE_NODE *TargetNode; + ACPI_PARSE_OBJECT *SourceOperandOp; + ACPI_PARSE_OBJECT *TargetOperandOp; + UINT32 SourceOperandBtype; + UINT32 TargetOperandBtype; + + + /* Extract the two operands for STORE */ + + SourceOperandOp = Op->Asl.Child; + TargetOperandOp = SourceOperandOp->Asl.Next; + + /* + * Ignore these Source operand opcodes, they cannot be typechecked, + * the actual result is unknown here. + */ + switch (SourceOperandOp->Asl.ParseOpcode) + { + /* For these, type of the returned value is unknown at compile time */ + + case PARSEOP_DEREFOF: + case PARSEOP_METHODCALL: + case PARSEOP_STORE: + case PARSEOP_COPYOBJECT: + + return; + + case PARSEOP_INDEX: + case PARSEOP_REFOF: + + if (!Gbl_EnableReferenceTypechecking) + { + return; + } + + /* + * These opcodes always return an object reference, and thus + * the result can only be stored to a Local, Arg, or Debug. + */ + if (TargetOperandOp->Asl.AmlOpcode == AML_DEBUG_OP) + { + return; + } + + if ((TargetOperandOp->Asl.AmlOpcode < AML_LOCAL0) || + (TargetOperandOp->Asl.AmlOpcode > AML_ARG6)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, TargetOperandOp, + "Source [Reference], Target must be [Local/Arg/Debug]"); + } + return; + + default: + break; + } + + /* + * Ignore these Target operand opcodes, they cannot be typechecked + */ + switch (TargetOperandOp->Asl.ParseOpcode) + { + case PARSEOP_DEBUG: + case PARSEOP_DEREFOF: + case PARSEOP_REFOF: + case PARSEOP_INDEX: + case PARSEOP_METHODCALL: + + return; + + default: + break; + } + + /* + * Ignore typecheck for External() operands of type "UnknownObj", + * we don't know the actual type (source or target). + */ + SourceNode = SourceOperandOp->Asl.Node; + if (SourceNode && + (SourceNode->Flags & ANOBJ_IS_EXTERNAL) && + (SourceNode->Type == ACPI_TYPE_ANY)) + { + return; + } + + TargetNode = TargetOperandOp->Asl.Node; + if (TargetNode && + (TargetNode->Flags & ANOBJ_IS_EXTERNAL) && + (TargetNode->Type == ACPI_TYPE_ANY)) + { + return; + } + + /* + * A NULL node with a namepath AML opcode indicates non-existent + * name. Just return, the error message is generated elsewhere. + */ + if ((!SourceNode && (SourceOperandOp->Asl.AmlOpcode == AML_INT_NAMEPATH_OP)) || + (!TargetNode && (TargetOperandOp->Asl.AmlOpcode == AML_INT_NAMEPATH_OP))) + { + return; + } + + /* + * Simple check for source same as target via NS node. + * -- Could be expanded to locals and args. + */ + if (SourceNode && TargetNode) + { + if (SourceNode == TargetNode) + { + AslError (ASL_WARNING, ASL_MSG_DUPLICATE_ITEM, + TargetOperandOp, "Source is the same as Target"); + return; + } + } + + /* Ignore typecheck if either source or target is a local or arg */ + + if ((SourceOperandOp->Asl.AmlOpcode >= AML_LOCAL0) && + (SourceOperandOp->Asl.AmlOpcode <= AML_ARG6)) + { + return; /* Cannot type a local/arg at compile time */ + } + + if ((TargetOperandOp->Asl.AmlOpcode >= AML_LOCAL0) && + (TargetOperandOp->Asl.AmlOpcode <= AML_ARG6)) + { + return; /* Cannot type a local/arg at compile time */ + } + + /* + * Package objects are a special case because they cannot by implicitly + * converted to/from anything. Check for these two illegal cases: + * + * Store (non-package, package) + * Store (package, non-package) + */ + SourceOperandBtype = AnGetBtype (SourceOperandOp); + TargetOperandBtype = AnGetBtype (TargetOperandOp); + + /* Check source first for (package, non-package) case */ + + if (SourceOperandBtype & ACPI_BTYPE_PACKAGE) + { + /* If Source is PACKAGE-->Target must be PACKAGE */ + + if (!(TargetOperandBtype & ACPI_BTYPE_PACKAGE)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, TargetOperandOp, + "Source is [Package], Target must be a package also"); + } + } + + /* Else check target for (non-package, package) case */ + + else if (TargetOperandBtype & ACPI_BTYPE_PACKAGE) + { + /* If Target is PACKAGE, Source must be PACKAGE */ + + if (!(SourceOperandBtype & ACPI_BTYPE_PACKAGE)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, SourceOperandOp, + "Target is [Package], Source must be a package also"); + } + } +} diff --git a/third_party/lib/acpica/source/compiler/aslxref.c b/third_party/lib/acpica/source/compiler/aslxref.c new file mode 100644 index 000000000..74038d9af --- /dev/null +++ b/third_party/lib/acpica/source/compiler/aslxref.c @@ -0,0 +1,1273 @@ +/****************************************************************************** + * + * Module Name: aslxref - Namespace cross-reference + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "aslcompiler.y.h" +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslxref") + +/* Local prototypes */ + +static ACPI_STATUS +XfNamespaceLocateBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +XfNamespaceLocateEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_PARSE_OBJECT * +XfGetParentMethod ( + ACPI_PARSE_OBJECT *Op); + +static BOOLEAN +XfObjectExists ( + char *Name); + +static ACPI_STATUS +XfCompareOneNamespaceObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +static void +XfCheckFieldRange ( + ACPI_PARSE_OBJECT *Op, + UINT32 RegionBitLength, + UINT32 FieldBitOffset, + UINT32 FieldBitLength, + UINT32 AccessBitWidth); + +#ifdef __UNDER_DEVELOPMENT +static ACPI_PARSE_OBJECT * +XfGetParentMethod ( + ACPI_PARSE_OBJECT *Op); + +static void +XfCheckIllegalReference ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *Node); + +static BOOLEAN +XfIsObjectParental ( + ACPI_PARSE_OBJECT *MethodOp1, + ACPI_PARSE_OBJECT *MethodOp2); +#endif + + +/******************************************************************************* + * + * FUNCTION: XfCrossReferenceNamespace + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Perform a cross reference check of the parse tree against the + * namespace. Every named referenced within the parse tree + * should be get resolved with a namespace lookup. If not, the + * original reference in the ASL code is invalid -- i.e., refers + * to a non-existent object. + * + * NOTE: The ASL "External" operator causes the name to be inserted into the + * namespace so that references to the external name will be resolved + * correctly here. + * + ******************************************************************************/ + +ACPI_STATUS +XfCrossReferenceNamespace ( + void) +{ + ACPI_WALK_STATE *WalkState; + + + DbgPrint (ASL_DEBUG_OUTPUT, "\nCross referencing namespace\n\n"); + + /* + * Create a new walk state for use when looking up names + * within the namespace (Passed as context to the callbacks) + */ + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + if (!WalkState) + { + return (AE_NO_MEMORY); + } + + /* Walk the entire parse tree */ + + TrWalkParseTree (RootNode, ASL_WALK_VISIT_TWICE, XfNamespaceLocateBegin, + XfNamespaceLocateEnd, WalkState); + + ACPI_FREE (WalkState); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: XfObjectExists + * + * PARAMETERS: Name - 4 char ACPI name + * + * RETURN: TRUE if name exists in namespace + * + * DESCRIPTION: Walk the namespace to find an object + * + ******************************************************************************/ + +static BOOLEAN +XfObjectExists ( + char *Name) +{ + ACPI_STATUS Status; + + + /* Walk entire namespace from the supplied root */ + + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, XfCompareOneNamespaceObject, NULL, + Name, NULL); + if (Status == AE_CTRL_TRUE) + { + /* At least one instance of the name was found */ + + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: XfCompareOneNamespaceObject + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Compare name of one object. + * + ******************************************************************************/ + +static ACPI_STATUS +XfCompareOneNamespaceObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + + + /* Simply check the name */ + + if (*((UINT32 *) (Context)) == Node->Name.Integer) + { + /* Abort walk if we found one instance */ + + return (AE_CTRL_TRUE); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: XfCheckFieldRange + * + * PARAMETERS: RegionBitLength - Length of entire parent region + * FieldBitOffset - Start of the field unit (within region) + * FieldBitLength - Entire length of field unit + * AccessBitWidth - Access width of the field unit + * + * RETURN: None + * + * DESCRIPTION: Check one field unit to make sure it fits in the parent + * op region. + * + * Note: AccessBitWidth must be either 8,16,32, or 64 + * + ******************************************************************************/ + +static void +XfCheckFieldRange ( + ACPI_PARSE_OBJECT *Op, + UINT32 RegionBitLength, + UINT32 FieldBitOffset, + UINT32 FieldBitLength, + UINT32 AccessBitWidth) +{ + UINT32 FieldEndBitOffset; + + + /* + * Check each field unit against the region size. The entire + * field unit (start offset plus length) must fit within the + * region. + */ + FieldEndBitOffset = FieldBitOffset + FieldBitLength; + + if (FieldEndBitOffset > RegionBitLength) + { + /* Field definition itself is beyond the end-of-region */ + + AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_OFFSET, Op, NULL); + return; + } + + /* + * Now check that the field plus AccessWidth doesn't go beyond + * the end-of-region. Assumes AccessBitWidth is a power of 2 + */ + FieldEndBitOffset = ACPI_ROUND_UP (FieldEndBitOffset, AccessBitWidth); + + if (FieldEndBitOffset > RegionBitLength) + { + /* Field definition combined with the access is beyond EOR */ + + AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, Op, NULL); + } +} + + +/******************************************************************************* + * + * FUNCTION: XfGetParentMethod + * + * PARAMETERS: Op - Parse Op to be checked + * + * RETURN: Control method Op if found. NULL otherwise + * + * DESCRIPTION: Find the control method parent of a parse op. Returns NULL if + * the input Op is not within a control method. + * + ******************************************************************************/ + +static ACPI_PARSE_OBJECT * +XfGetParentMethod ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextOp; + + + NextOp = Op->Asl.Parent; + while (NextOp) + { + if (NextOp->Asl.AmlOpcode == AML_METHOD_OP) + { + return (NextOp); + } + + NextOp = NextOp->Asl.Parent; + } + + return (NULL); /* No parent method found */ +} + +/******************************************************************************* + * + * FUNCTION: XfNamespaceLocateBegin + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during cross-reference. For named + * object references, attempt to locate the name in the + * namespace. + * + * NOTE: ASL references to named fields within resource descriptors are + * resolved to integer values here. Therefore, this step is an + * important part of the code generation. We don't know that the + * name refers to a resource descriptor until now. + * + ******************************************************************************/ + +static ACPI_STATUS +XfNamespaceLocateBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + char *Path; + UINT8 PassedArgs; + ACPI_PARSE_OBJECT *NextOp; + ACPI_PARSE_OBJECT *OwningOp; + ACPI_PARSE_OBJECT *SpaceIdOp; + UINT32 MinimumLength; + UINT32 Offset; + UINT32 FieldBitLength; + UINT32 TagBitLength; + UINT8 Message = 0; + const ACPI_OPCODE_INFO *OpInfo; + UINT32 Flags; + ASL_METHOD_LOCAL *MethodLocals = NULL; + ASL_METHOD_LOCAL *MethodArgs = NULL; + int RegisterNumber; + UINT32 i; + + + ACPI_FUNCTION_TRACE_PTR (XfNamespaceLocateBegin, Op); + + + if ((Op->Asl.AmlOpcode == AML_METHOD_OP) && Op->Asl.Node) + { + Node = Op->Asl.Node; + + /* Support for method LocalX/ArgX analysis */ + + if (!Node->MethodLocals) + { + /* Create local/arg info blocks */ + + MethodLocals = UtLocalCalloc ( + sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_LOCALS); + Node->MethodLocals = MethodLocals; + + MethodArgs = UtLocalCalloc ( + sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_ARGS); + Node->MethodArgs = MethodArgs; + + /* + * Get the method argument count + * First, get the name node + */ + NextOp = Op->Asl.Child; + + /* Get the NumArguments node */ + + NextOp = NextOp->Asl.Next; + Node->ArgCount = (UINT8) + (((UINT8) NextOp->Asl.Value.Integer) & 0x07); + + /* We will track all posible ArgXs */ + + for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) + { + if (i < Node->ArgCount) + { + /* Real Args are always "initialized" */ + + MethodArgs[i].Flags = ASL_ARG_INITIALIZED; + } + else + { + /* Other ArgXs can be used as locals */ + + MethodArgs[i].Flags = ASL_ARG_IS_LOCAL; + } + + MethodArgs[i].Op = Op; + } + } + } + + /* + * If this node is the actual declaration of a name + * [such as the XXXX name in "Method (XXXX)"], + * we are not interested in it here. We only care about names that are + * references to other objects within the namespace and the parent objects + * of name declarations + */ + if (Op->Asl.CompileFlags & NODE_IS_NAME_DECLARATION) + { + return_ACPI_STATUS (AE_OK); + } + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + + /* Check method LocalX variables */ + + if (OpInfo->Type == AML_TYPE_LOCAL_VARIABLE) + { + /* Find parent method Op */ + + NextOp = XfGetParentMethod (Op); + if (!NextOp) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get method node */ + + Node = NextOp->Asl.Node; + + RegisterNumber = Op->Asl.AmlOpcode & 0x0007; /* 0x60 through 0x67 */ + MethodLocals = Node->MethodLocals; + + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + /* Local is being initialized */ + + MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_INITIALIZED; + MethodLocals[RegisterNumber].Op = Op; + + return_ACPI_STATUS (AE_OK); + } + + /* Mark this Local as referenced */ + + MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_REFERENCED; + MethodLocals[RegisterNumber].Op = Op; + + return_ACPI_STATUS (AE_OK); + } + + /* Check method ArgX variables */ + + if (OpInfo->Type == AML_TYPE_METHOD_ARGUMENT) + { + /* Find parent method Op */ + + NextOp = XfGetParentMethod (Op); + if (!NextOp) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get method node */ + + Node = NextOp->Asl.Node; + + /* Get Arg # */ + + RegisterNumber = Op->Asl.AmlOpcode - AML_ARG0; /* 0x68 through 0x6F */ + MethodArgs = Node->MethodArgs; + + if (Op->Asl.CompileFlags & NODE_IS_TARGET) + { + /* Arg is being initialized */ + + MethodArgs[RegisterNumber].Flags |= ASL_ARG_INITIALIZED; + MethodArgs[RegisterNumber].Op = Op; + + return_ACPI_STATUS (AE_OK); + } + + /* Mark this Arg as referenced */ + + MethodArgs[RegisterNumber].Flags |= ASL_ARG_REFERENCED; + MethodArgs[RegisterNumber].Op = Op; + + return_ACPI_STATUS (AE_OK); + } + + /* + * After method ArgX and LocalX, we are only interested in opcodes + * that have an associated name + */ + if ((!(OpInfo->Flags & AML_NAMED)) && + (!(OpInfo->Flags & AML_CREATE)) && + (Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) && + (Op->Asl.ParseOpcode != PARSEOP_NAMESEG) && + (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * One special case: CondRefOf operator - we don't care if the name exists + * or not at this point, just ignore it, the point of the operator is to + * determine if the name exists at runtime. + */ + if ((Op->Asl.Parent) && + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF)) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * We must enable the "search-to-root" for single NameSegs, but + * we have to be very careful about opening up scopes + */ + Flags = ACPI_NS_SEARCH_PARENT; + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) + { + /* + * These are name references, do not push the scope stack + * for them. + */ + Flags |= ACPI_NS_DONT_OPEN_SCOPE; + } + + /* Get the NamePath from the appropriate place */ + + if (OpInfo->Flags & AML_NAMED) + { + /* For nearly all NAMED operators, the name reference is the first child */ + + Path = Op->Asl.Child->Asl.Value.String; + if (Op->Asl.AmlOpcode == AML_ALIAS_OP) + { + /* + * ALIAS is the only oddball opcode, the name declaration + * (alias name) is the second operand + */ + Path = Op->Asl.Child->Asl.Next->Asl.Value.String; + } + } + else if (OpInfo->Flags & AML_CREATE) + { + /* Name must appear as the last parameter */ + + NextOp = Op->Asl.Child; + while (!(NextOp->Asl.CompileFlags & NODE_IS_NAME_DECLARATION)) + { + NextOp = NextOp->Asl.Next; + } + + Path = NextOp->Asl.Value.String; + } + else + { + Path = Op->Asl.Value.String; + } + + ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Type=%s\n", AcpiUtGetTypeName (ObjectType))); + + /* + * Lookup the name in the namespace. Name must exist at this point, or it + * is an invalid reference. + * + * The namespace is also used as a lookup table for references to resource + * descriptors and the fields within them. + */ + Gbl_NsLookupCount++; + + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, + ACPI_IMODE_EXECUTE, Flags, WalkState, &(Node)); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + /* + * We didn't find the name reference by path -- we can qualify this + * a little better before we print an error message + */ + if (strlen (Path) == ACPI_NAME_SIZE) + { + /* A simple, one-segment ACPI name */ + + if (XfObjectExists (Path)) + { + /* + * There exists such a name, but we couldn't get to it + * from this scope + */ + AslError (ASL_ERROR, ASL_MSG_NOT_REACHABLE, Op, + Op->Asl.ExternalName); + } + else + { + /* The name doesn't exist, period */ + + AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, + Op, Op->Asl.ExternalName); + } + } + else + { + /* Check for a fully qualified path */ + + if (Path[0] == AML_ROOT_PREFIX) + { + /* Gave full path, the object does not exist */ + + AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, Op, + Op->Asl.ExternalName); + } + else + { + /* + * We can't tell whether it doesn't exist or just + * can't be reached. + */ + AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op, + Op->Asl.ExternalName); + } + } + + Status = AE_OK; + } + + return_ACPI_STATUS (Status); + } + + /* Check for a reference vs. name declaration */ + + if (!(OpInfo->Flags & AML_NAMED) && + !(OpInfo->Flags & AML_CREATE)) + { + /* This node has been referenced, mark it for reference check */ + + Node->Flags |= ANOBJ_IS_REFERENCED; + +#ifdef __UNDER_DEVELOPMENT + + /* Check for an illegal reference */ + + XfCheckIllegalReference (Op, Node); +#endif + } + + /* Attempt to optimize the NamePath */ + + OptOptimizeNamePath (Op, OpInfo->Flags, WalkState, Path, Node); + + /* + * 1) Dereference an alias (A name reference that is an alias) + * Aliases are not nested, the alias always points to the final object + */ + if ((Op->Asl.ParseOpcode != PARSEOP_ALIAS) && + (Node->Type == ACPI_TYPE_LOCAL_ALIAS)) + { + /* This node points back to the original PARSEOP_ALIAS */ + + NextOp = Node->Op; + + /* The first child is the alias target op */ + + NextOp = NextOp->Asl.Child; + + /* That in turn points back to original target alias node */ + + if (NextOp->Asl.Node) + { + Node = NextOp->Asl.Node; + } + + /* Else - forward reference to alias, will be resolved later */ + } + + /* 2) Check for a reference to a resource descriptor */ + + if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || + (Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) + { + /* + * This was a reference to a field within a resource descriptor. + * Extract the associated field offset (either a bit or byte + * offset depending on the field type) and change the named + * reference into an integer for AML code generation + */ + Offset = Node->Value; + TagBitLength = Node->Length; + + /* + * If a field is being created, generate the length (in bits) of + * the field. Note: Opcodes other than CreateXxxField and Index + * can come through here. For other opcodes, we just need to + * convert the resource tag reference to an integer offset. + */ + switch (Op->Asl.Parent->Asl.AmlOpcode) + { + case AML_CREATE_FIELD_OP: /* Variable "Length" field, in bits */ + /* + * We know the length operand is an integer constant because + * we know that it contains a reference to a resource + * descriptor tag. + */ + FieldBitLength = (UINT32) Op->Asl.Next->Asl.Value.Integer; + break; + + case AML_CREATE_BIT_FIELD_OP: + + FieldBitLength = 1; + break; + + case AML_CREATE_BYTE_FIELD_OP: + case AML_INDEX_OP: + + FieldBitLength = 8; + break; + + case AML_CREATE_WORD_FIELD_OP: + + FieldBitLength = 16; + break; + + case AML_CREATE_DWORD_FIELD_OP: + + FieldBitLength = 32; + break; + + case AML_CREATE_QWORD_FIELD_OP: + + FieldBitLength = 64; + break; + + default: + + FieldBitLength = 0; + break; + } + + /* Check the field length against the length of the resource tag */ + + if (FieldBitLength) + { + if (TagBitLength < FieldBitLength) + { + Message = ASL_MSG_TAG_SMALLER; + } + else if (TagBitLength > FieldBitLength) + { + Message = ASL_MSG_TAG_LARGER; + } + + if (Message) + { + sprintf (MsgBuffer, + "Size mismatch, Tag: %u bit%s, Field: %u bit%s", + TagBitLength, (TagBitLength > 1) ? "s" : "", + FieldBitLength, (FieldBitLength > 1) ? "s" : ""); + + AslError (ASL_WARNING, Message, Op, MsgBuffer); + } + } + + /* Convert the BitOffset to a ByteOffset for certain opcodes */ + + switch (Op->Asl.Parent->Asl.AmlOpcode) + { + case AML_CREATE_BYTE_FIELD_OP: + case AML_CREATE_WORD_FIELD_OP: + case AML_CREATE_DWORD_FIELD_OP: + case AML_CREATE_QWORD_FIELD_OP: + case AML_INDEX_OP: + + Offset = ACPI_DIV_8 (Offset); + break; + + default: + + break; + } + + /* Now convert this node to an integer whose value is the field offset */ + + Op->Asl.AmlLength = 0; + Op->Asl.ParseOpcode = PARSEOP_INTEGER; + Op->Asl.Value.Integer = (UINT64) Offset; + Op->Asl.CompileFlags |= NODE_IS_RESOURCE_FIELD; + + OpcGenerateAmlOpcode (Op); + } + + /* 3) Check for a method invocation */ + + else if ((((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || (Op->Asl.ParseOpcode == PARSEOP_NAMESEG)) && + (Node->Type == ACPI_TYPE_METHOD) && + (Op->Asl.Parent) && + (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_METHOD)) || + + (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) + { + /* + * A reference to a method within one of these opcodes is not an + * invocation of the method, it is simply a reference to the method. + */ + if ((Op->Asl.Parent) && + ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_REFOF) || + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_DEREFOF) || + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_PACKAGE) || + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)|| + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE))) + { + return_ACPI_STATUS (AE_OK); + } + /* + * There are two types of method invocation: + * 1) Invocation with arguments -- the parser recognizes this + * as a METHODCALL. + * 2) Invocation with no arguments --the parser cannot determine that + * this is a method invocation, therefore we have to figure it out + * here. + */ + if (Node->Type != ACPI_TYPE_METHOD) + { + sprintf (MsgBuffer, "%s is a %s", + Op->Asl.ExternalName, AcpiUtGetTypeName (Node->Type)); + + AslError (ASL_ERROR, ASL_MSG_NOT_METHOD, Op, MsgBuffer); + return_ACPI_STATUS (AE_OK); + } + + /* Save the method node in the caller's op */ + + Op->Asl.Node = Node; + if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * This is a method invocation, with or without arguments. + * Count the number of arguments, each appears as a child + * under the parent node + */ + Op->Asl.ParseOpcode = PARSEOP_METHODCALL; + UtSetParseOpName (Op); + + PassedArgs = 0; + NextOp = Op->Asl.Child; + + while (NextOp) + { + PassedArgs++; + NextOp = NextOp->Asl.Next; + } + + if (Node->Value != ASL_EXTERNAL_METHOD) + { + /* + * Check the parsed arguments with the number expected by the + * method declaration itself + */ + if (PassedArgs != Node->Value) + { + sprintf (MsgBuffer, "%s requires %u", Op->Asl.ExternalName, + Node->Value); + + if (PassedArgs < Node->Value) + { + AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, MsgBuffer); + } + else + { + AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_HI, Op, MsgBuffer); + } + } + } + } + + /* 4) Check for an ASL Field definition */ + + else if ((Op->Asl.Parent) && + ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_FIELD) || + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_BANKFIELD))) + { + /* + * Offset checking for fields. If the parent operation region has a + * constant length (known at compile time), we can check fields + * defined in that region against the region length. This will catch + * fields and field units that cannot possibly fit within the region. + * + * Note: Index fields do not directly reference an operation region, + * thus they are not included in this check. + */ + if (Op == Op->Asl.Parent->Asl.Child) + { + /* + * This is the first child of the field node, which is + * the name of the region. Get the parse node for the + * region -- which contains the length of the region. + */ + OwningOp = Node->Op; + Op->Asl.Parent->Asl.ExtraValue = + ACPI_MUL_8 ((UINT32) OwningOp->Asl.Value.Integer); + + /* Examine the field access width */ + + switch ((UINT8) Op->Asl.Parent->Asl.Value.Integer) + { + case AML_FIELD_ACCESS_ANY: + case AML_FIELD_ACCESS_BYTE: + case AML_FIELD_ACCESS_BUFFER: + default: + + MinimumLength = 1; + break; + + case AML_FIELD_ACCESS_WORD: + + MinimumLength = 2; + break; + + case AML_FIELD_ACCESS_DWORD: + + MinimumLength = 4; + break; + + case AML_FIELD_ACCESS_QWORD: + + MinimumLength = 8; + break; + } + + /* + * Is the region at least as big as the access width? + * Note: DataTableRegions have 0 length + */ + if (((UINT32) OwningOp->Asl.Value.Integer) && + ((UINT32) OwningOp->Asl.Value.Integer < MinimumLength)) + { + AslError (ASL_ERROR, ASL_MSG_FIELD_ACCESS_WIDTH, Op, NULL); + } + + /* + * Check EC/CMOS/SMBUS fields to make sure that the correct + * access type is used (BYTE for EC/CMOS, BUFFER for SMBUS) + */ + SpaceIdOp = OwningOp->Asl.Child->Asl.Next; + switch ((UINT32) SpaceIdOp->Asl.Value.Integer) + { + case ACPI_ADR_SPACE_EC: + case ACPI_ADR_SPACE_CMOS: + case ACPI_ADR_SPACE_GPIO: + + if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != + AML_FIELD_ACCESS_BYTE) + { + AslError (ASL_ERROR, ASL_MSG_REGION_BYTE_ACCESS, Op, NULL); + } + break; + + case ACPI_ADR_SPACE_SMBUS: + case ACPI_ADR_SPACE_IPMI: + case ACPI_ADR_SPACE_GSBUS: + + if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != + AML_FIELD_ACCESS_BUFFER) + { + AslError (ASL_ERROR, ASL_MSG_REGION_BUFFER_ACCESS, Op, NULL); + } + break; + + default: + + /* Nothing to do for other address spaces */ + + break; + } + } + else + { + /* + * This is one element of the field list. Check to make sure + * that it does not go beyond the end of the parent operation region. + * + * In the code below: + * Op->Asl.Parent->Asl.ExtraValue - Region Length (bits) + * Op->Asl.ExtraValue - Field start offset (bits) + * Op->Asl.Child->Asl.Value.Integer32 - Field length (bits) + * Op->Asl.Child->Asl.ExtraValue - Field access width (bits) + */ + if (Op->Asl.Parent->Asl.ExtraValue && Op->Asl.Child) + { + XfCheckFieldRange (Op, + Op->Asl.Parent->Asl.ExtraValue, + Op->Asl.ExtraValue, + (UINT32) Op->Asl.Child->Asl.Value.Integer, + Op->Asl.Child->Asl.ExtraValue); + } + } + } + + /* 5) Check for a connection object */ +#if 0 + else if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONNECTION) + { + return_ACPI_STATUS (Status); + } +#endif + + Op->Asl.Node = Node; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: XfNamespaceLocateEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during cross reference. We only + * need to worry about scope management here. + * + ******************************************************************************/ + +static ACPI_STATUS +XfNamespaceLocateEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; + const ACPI_OPCODE_INFO *OpInfo; + + + ACPI_FUNCTION_TRACE (XfNamespaceLocateEnd); + + + /* We are only interested in opcodes that have an associated name */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + if (!(OpInfo->Flags & AML_NAMED)) + { + return_ACPI_STATUS (AE_OK); + } + + /* Not interested in name references, we did not open a scope for them */ + + if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || + (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || + (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) + { + return_ACPI_STATUS (AE_OK); + } + + /* Pop the scope stack if necessary */ + + if (AcpiNsOpensScope (AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode))) + { + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "%s: Popping scope for Op %p\n", + AcpiUtGetTypeName (OpInfo->ObjectType), Op)); + + (void) AcpiDsScopeStackPop (WalkState); + } + + return_ACPI_STATUS (AE_OK); +} + + +#ifdef __UNDER_DEVELOPMENT +/******************************************************************************* + * + * FUNCTION: XfIsObjectParental + * + * PARAMETERS: ChildOp - Op to be checked + * PossibleParentOp - Determine if this op is in the family + * + * RETURN: TRUE if ChildOp is a descendent of PossibleParentOp + * + * DESCRIPTION: Determine if an Op is a descendent of another Op. Used to + * detect if a method is declared within another method. + * + ******************************************************************************/ + +static BOOLEAN +XfIsObjectParental ( + ACPI_PARSE_OBJECT *ChildOp, + ACPI_PARSE_OBJECT *PossibleParentOp) +{ + ACPI_PARSE_OBJECT *ParentOp; + + + /* Search upwards through the tree for possible parent */ + + ParentOp = ChildOp; + while (ParentOp) + { + if (ParentOp == PossibleParentOp) + { + return (TRUE); + } + + ParentOp = ParentOp->Asl.Parent; + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: XfGetParentMethod + * + * PARAMETERS: Op - Op to be checked + * + * RETURN: Op for parent method. NULL if object is not within a method. + * + * DESCRIPTION: Determine if an object is within a control method. Used to + * implement special rules for named references from within a + * control method. + * + * NOTE: It would be better to have the parser set a flag in the Op if possible. + * + ******************************************************************************/ + +static ACPI_PARSE_OBJECT * +XfGetParentMethod ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *ParentOp; + + + if (!Op) + { + return (NULL); + } + + if (Op->Asl.ParseOpcode == PARSEOP_METHOD) + { + return (NULL); + } + + /* Walk upwards through the parse tree, up to the root if necessary */ + + ParentOp = Op; + while (ParentOp) + { + if (ParentOp->Asl.ParseOpcode == PARSEOP_METHOD) + { + return (ParentOp); + } + + ParentOp = ParentOp->Asl.Parent; + } + + /* Object is not within a method */ + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: XfCheckIllegalReference + * + * PARAMETERS: Op - Op referring to the target + * TargetNode - Target of the reference + * + * RETURN: None. Emits error message for an illegal reference + * + * DESCRIPTION: Determine if a named reference is legal. A "named" reference + * is something like: Store(ABCD, ...), where ABCD is an AML + * Nameseg or Namepath. + * + * NOTE: Caller must ensure that the name Op is in fact a reference, and not + * an actual name declaration (creation of a named object). + * + ******************************************************************************/ + +static void +XfCheckIllegalReference ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *TargetNode) +{ + ACPI_PARSE_OBJECT *MethodOp1; + ACPI_PARSE_OBJECT *MethodOp2; + ACPI_PARSE_OBJECT *TargetOp; + + + /* + * Check for an illegal reference to a named object: + * + * 1) References from one control method to another, non-parent + * method are not allowed, they will fail at runtime. + * + * 2) Forward references within a control method are not allowed. + * AML interpreters use a one-pass parse of control methods + * so these forward references will fail at runtime. + */ + TargetOp = TargetNode->Op; + + MethodOp1 = XfGetParentMethod (Op); + MethodOp2 = XfGetParentMethod (TargetOp); + + /* Are both objects within control method(s)? */ + + if (!MethodOp1 || !MethodOp2) + { + return; + } + + /* Objects not in the same method? */ + + if (MethodOp1 != MethodOp2) + { + /* + * 1) Cross-method named reference + * + * This is OK if and only if the target reference is within in a + * method that is a parent of current method + */ + if (!XfIsObjectParental (MethodOp1, MethodOp2)) + { + AslError (ASL_ERROR, ASL_MSG_ILLEGAL_METHOD_REF, Op, + Op->Asl.ExternalName); + } + } + + /* + * 2) Both reference and target are in the same method. Check if this is + * an (illegal) forward reference by examining the exact source code + * location of each (the referenced object and the object declaration). + * This is a bit nasty, yet effective. + */ + else if (Op->Asl.LogicalByteOffset < TargetOp->Asl.LogicalByteOffset) + { + AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op, + Op->Asl.ExternalName); + } + +} +#endif diff --git a/third_party/lib/acpica/source/compiler/dtcompile.c b/third_party/lib/acpica/source/compiler/dtcompile.c new file mode 100644 index 000000000..704b55f87 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtcompile.c @@ -0,0 +1,728 @@ +/****************************************************************************** + * + * Module Name: dtcompile.c - Front-end for data table compiler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define _DECLARE_DT_GLOBALS + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtcompile") + +static char VersionString[9]; + + +/* Local prototypes */ + +static ACPI_STATUS +DtInitialize ( + void); + +static ACPI_STATUS +DtCompileDataTable ( + DT_FIELD **Field); + +static void +DtInsertCompilerIds ( + DT_FIELD *FieldList); + + +/****************************************************************************** + * + * FUNCTION: DtDoCompile + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Main entry point for the data table compiler. + * + * Note: Assumes Gbl_Files[ASL_FILE_INPUT] is initialized and the file is + * open at seek offset zero. + * + *****************************************************************************/ + +ACPI_STATUS +DtDoCompile ( + void) +{ + ACPI_STATUS Status; + UINT8 Event; + DT_FIELD *FieldList; + + + /* Initialize globals */ + + Status = DtInitialize (); + if (ACPI_FAILURE (Status)) + { + printf ("Error during compiler initialization, 0x%X\n", Status); + return (Status); + } + + /* Preprocessor */ + + if (Gbl_PreprocessFlag) + { + /* Preprocessor */ + + Event = UtBeginEvent ("Preprocess input file"); + PrDoPreprocess (); + UtEndEvent (Event); + + if (Gbl_PreprocessOnly) + { + return (AE_OK); + } + } + + /* + * Scan the input file (file is already open) and + * build the parse tree + */ + Event = UtBeginEvent ("Scan and parse input file"); + FieldList = DtScanFile (Gbl_Files[ASL_FILE_INPUT].Handle); + UtEndEvent (Event); + + /* Did the parse tree get successfully constructed? */ + + if (!FieldList) + { + /* TBD: temporary error message. Msgs should come from function above */ + + DtError (ASL_ERROR, ASL_MSG_SYNTAX, NULL, + "Input file does not appear to be an ASL or data table source file"); + + Status = AE_ERROR; + goto CleanupAndExit; + } + + Event = UtBeginEvent ("Compile parse tree"); + + /* + * Compile the parse tree + */ + Status = DtCompileDataTable (&FieldList); + UtEndEvent (Event); + + if (ACPI_FAILURE (Status)) + { + /* TBD: temporary error message. Msgs should come from function above */ + + DtError (ASL_ERROR, ASL_MSG_SYNTAX, NULL, + "Could not compile input file"); + + goto CleanupAndExit; + } + + /* Create/open the binary output file */ + + Gbl_Files[ASL_FILE_AML_OUTPUT].Filename = NULL; + Status = FlOpenAmlOutputFile (Gbl_OutputFilenamePrefix); + if (ACPI_FAILURE (Status)) + { + goto CleanupAndExit; + } + + /* Write the binary, then the optional hex file */ + + DtOutputBinary (Gbl_RootTable); + HxDoHexOutput (); + DtWriteTableToListing (); + +CleanupAndExit: + + AcpiUtDeleteCaches (); + DtDeleteCaches (); + CmCleanupAndExit (); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize data table compiler globals. Enables multiple + * compiles per invocation. + * + *****************************************************************************/ + +static ACPI_STATUS +DtInitialize ( + void) +{ + ACPI_STATUS Status; + + + Status = AcpiOsInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtInitGlobals (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_FieldList = NULL; + Gbl_RootTable = NULL; + Gbl_SubtableStack = NULL; + + sprintf (VersionString, "%X", (UINT32) ACPI_CA_VERSION); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtInsertCompilerIds + * + * PARAMETERS: FieldList - Current field list pointer + * + * RETURN: None + * + * DESCRIPTION: Insert the IDs (Name, Version) of the current compiler into + * the original ACPI table header. + * + *****************************************************************************/ + +static void +DtInsertCompilerIds ( + DT_FIELD *FieldList) +{ + DT_FIELD *Next; + UINT32 i; + + + /* + * Don't insert current compiler ID if requested. Used for compiler + * debug/validation only. + */ + if (Gbl_UseOriginalCompilerId) + { + return; + } + + /* Walk to the Compiler fields at the end of the header */ + + Next = FieldList; + for (i = 0; i < 7; i++) + { + Next = Next->Next; + } + + Next->Value = ASL_CREATOR_ID; + Next->Flags = DT_FIELD_NOT_ALLOCATED; + + Next = Next->Next; + Next->Value = VersionString; + Next->Flags = DT_FIELD_NOT_ALLOCATED; +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileDataTable + * + * PARAMETERS: FieldList - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Entry point to compile one data table + * + *****************************************************************************/ + +static ACPI_STATUS +DtCompileDataTable ( + DT_FIELD **FieldList) +{ + const ACPI_DMTABLE_DATA *TableData; + DT_SUBTABLE *Subtable; + char *Signature; + ACPI_TABLE_HEADER *AcpiTableHeader; + ACPI_STATUS Status; + DT_FIELD *RootField = *FieldList; + + + /* Verify that we at least have a table signature and save it */ + + Signature = DtGetFieldValue (*FieldList); + if (!Signature) + { + sprintf (MsgBuffer, "Expected \"%s\"", "Signature"); + DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME, + *FieldList, MsgBuffer); + return (AE_ERROR); + } + + Gbl_Signature = UtStringCacheCalloc (strlen (Signature) + 1); + strcpy (Gbl_Signature, Signature); + + /* + * Handle tables that don't use the common ACPI table header structure. + * Currently, these are the FACS and RSDP. Also check for an OEMx table, + * these tables have user-defined contents. + */ + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + Status = DtCompileFacs (FieldList); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtSetTableLength (); + return (Status); + } + else if (ACPI_VALIDATE_RSDP_SIG (Signature)) + { + Status = DtCompileRsdp (FieldList); + return (Status); + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_S3PT)) + { + Status = DtCompileS3pt (FieldList); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtSetTableLength (); + return (Status); + } + + /* + * All other tables must use the common ACPI table header. Insert the + * current iASL IDs (name, version), and compile the header now. + */ + DtInsertCompilerIds (*FieldList); + + Status = DtCompileTable (FieldList, AcpiDmTableInfoHeader, + &Gbl_RootTable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtPushSubtable (Gbl_RootTable); + + /* Validate the signature via the ACPI table list */ + + TableData = AcpiDmGetTableData (Signature); + if (!TableData || Gbl_CompileGeneric) + { + /* Unknown table signature and/or force generic compile */ + + DtCompileGeneric ((void **) FieldList, NULL, NULL); + goto FinishHeader; + } + + /* Dispatch to per-table compile */ + + if (TableData->CmTableHandler) + { + /* Complex table, has a handler */ + + Status = TableData->CmTableHandler ((void **) FieldList); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else if (TableData->TableInfo) + { + /* Simple table, just walk the info table */ + + Subtable = NULL; + Status = DtCompileTable (FieldList, TableData->TableInfo, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (Gbl_RootTable, Subtable); + DtPopSubtable (); + } + else + { + DtFatal (ASL_MSG_COMPILER_INTERNAL, *FieldList, + "Missing table dispatch info"); + return (AE_ERROR); + } + +FinishHeader: + + /* Set the final table length and then the checksum */ + + DtSetTableLength (); + AcpiTableHeader = ACPI_CAST_PTR ( + ACPI_TABLE_HEADER, Gbl_RootTable->Buffer); + DtSetTableChecksum (&AcpiTableHeader->Checksum); + + DtDumpFieldList (RootField); + DtDumpSubtableList (); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileTable + * + * PARAMETERS: Field - Current field list pointer + * Info - Info table for this ACPI table + * RetSubtable - Compile result of table + * Required - If this subtable must exist + * + * RETURN: Status + * + * DESCRIPTION: Compile a subtable + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileTable ( + DT_FIELD **Field, + ACPI_DMTABLE_INFO *Info, + DT_SUBTABLE **RetSubtable, + BOOLEAN Required) +{ + DT_FIELD *LocalField; + UINT32 Length; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *InlineSubtable = NULL; + UINT32 FieldLength = 0; + UINT8 FieldType; + UINT8 *Buffer; + UINT8 *FlagBuffer = NULL; + char *String; + UINT32 CurrentFlagByteOffset = 0; + ACPI_STATUS Status = AE_OK; + + + if (!Field || !*Field) + { + return (AE_BAD_PARAMETER); + } + + /* Ignore optional subtable if name does not match */ + + if ((Info->Flags & DT_OPTIONAL) && + strcmp ((*Field)->Name, Info->Name)) + { + *RetSubtable = NULL; + return (AE_OK); + } + + Length = DtGetSubtableLength (*Field, Info); + if (Length == ASL_EOF) + { + return (AE_ERROR); + } + + Subtable = UtSubtableCacheCalloc (); + + if (Length > 0) + { + String = UtStringCacheCalloc (Length); + Subtable->Buffer = ACPI_CAST_PTR (UINT8, String); + } + + Subtable->Length = Length; + Subtable->TotalLength = Length; + Buffer = Subtable->Buffer; + + LocalField = *Field; + Subtable->Name = LocalField->Name; + + /* + * Main loop walks the info table for this ACPI table or subtable + */ + for (; Info->Name; Info++) + { + if (Info->Opcode == ACPI_DMT_EXTRA_TEXT) + { + continue; + } + + if (!LocalField) + { + sprintf (MsgBuffer, "Found NULL field - Field name \"%s\" needed", + Info->Name); + DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); + Status = AE_BAD_DATA; + goto Error; + } + + /* Maintain table offsets */ + + LocalField->TableOffset = Gbl_CurrentTableOffset; + FieldLength = DtGetFieldLength (LocalField, Info); + Gbl_CurrentTableOffset += FieldLength; + + FieldType = DtGetFieldType (Info); + Gbl_InputFieldCount++; + + switch (FieldType) + { + case DT_FIELD_TYPE_FLAGS_INTEGER: + /* + * Start of the definition of a flags field. + * This master flags integer starts at value zero, in preparation + * to compile and insert the flag fields from the individual bits + */ + LocalField = LocalField->Next; + *Field = LocalField; + + FlagBuffer = Buffer; + CurrentFlagByteOffset = Info->Offset; + break; + + case DT_FIELD_TYPE_FLAG: + + /* Individual Flag field, can be multiple bits */ + + if (FlagBuffer) + { + /* + * We must increment the FlagBuffer when we have crossed + * into the next flags byte within the flags field + * of type DT_FIELD_TYPE_FLAGS_INTEGER. + */ + FlagBuffer += (Info->Offset - CurrentFlagByteOffset); + CurrentFlagByteOffset = Info->Offset; + + DtCompileFlag (FlagBuffer, LocalField, Info); + } + else + { + /* TBD - this is an internal error */ + } + + LocalField = LocalField->Next; + *Field = LocalField; + break; + + case DT_FIELD_TYPE_INLINE_SUBTABLE: + /* + * Recursion (one level max): compile GAS (Generic Address) + * or Notify in-line subtable + */ + *Field = LocalField; + + switch (Info->Opcode) + { + case ACPI_DMT_GAS: + + Status = DtCompileTable (Field, AcpiDmTableInfoGas, + &InlineSubtable, TRUE); + break; + + case ACPI_DMT_HESTNTFY: + + Status = DtCompileTable (Field, AcpiDmTableInfoHestNotify, + &InlineSubtable, TRUE); + break; + + case ACPI_DMT_IORTMEM: + + Status = DtCompileTable (Field, AcpiDmTableInfoIortAcc, + &InlineSubtable, TRUE); + break; + + default: + sprintf (MsgBuffer, "Invalid DMT opcode: 0x%.2X", + Info->Opcode); + DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); + Status = AE_BAD_DATA; + break; + } + + if (ACPI_FAILURE (Status)) + { + goto Error; + } + + DtSetSubtableLength (InlineSubtable); + + memcpy (Buffer, InlineSubtable->Buffer, FieldLength); + LocalField = *Field; + break; + + case DT_FIELD_TYPE_LABEL: + + DtWriteFieldToListing (Buffer, LocalField, 0); + LocalField = LocalField->Next; + break; + + default: + + /* Normal case for most field types (Integer, String, etc.) */ + + DtCompileOneField (Buffer, LocalField, + FieldLength, FieldType, Info->Flags); + + DtWriteFieldToListing (Buffer, LocalField, FieldLength); + LocalField = LocalField->Next; + + if (Info->Flags & DT_LENGTH) + { + /* Field is an Integer that will contain a subtable length */ + + Subtable->LengthField = Buffer; + Subtable->SizeOfLengthField = FieldLength; + } + break; + } + + Buffer += FieldLength; + } + + *Field = LocalField; + *RetSubtable = Subtable; + return (AE_OK); + +Error: + ACPI_FREE (Subtable->Buffer); + ACPI_FREE (Subtable); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileTwoSubtables + * + * PARAMETERS: List - Current field list pointer + * TableInfo1 - Info table 1 + * TableInfo1 - Info table 2 + * + * RETURN: Status + * + * DESCRIPTION: Compile tables with a header and one or more same subtables. + * Include CPEP, EINJ, ERST, MCFG, MSCT, WDAT + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileTwoSubtables ( + void **List, + ACPI_DMTABLE_INFO *TableInfo1, + ACPI_DMTABLE_INFO *TableInfo2) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + + + Status = DtCompileTable (PFieldList, TableInfo1, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, TableInfo2, &Subtable, FALSE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompilePadding + * + * PARAMETERS: Length - Padding field size + * RetSubtable - Compile result of table + * + * RETURN: Status + * + * DESCRIPTION: Compile a subtable for padding purpose + * + *****************************************************************************/ + +ACPI_STATUS +DtCompilePadding ( + UINT32 Length, + DT_SUBTABLE **RetSubtable) +{ + DT_SUBTABLE *Subtable; + /* UINT8 *Buffer; */ + char *String; + + + Subtable = UtSubtableCacheCalloc (); + + if (Length > 0) + { + String = UtStringCacheCalloc (Length); + Subtable->Buffer = ACPI_CAST_PTR (UINT8, String); + } + + Subtable->Length = Length; + Subtable->TotalLength = Length; + /* Buffer = Subtable->Buffer; */ + + *RetSubtable = Subtable; + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/dtcompiler.h b/third_party/lib/acpica/source/compiler/dtcompiler.h new file mode 100644 index 000000000..8102e8203 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtcompiler.h @@ -0,0 +1,633 @@ +/****************************************************************************** + * + * Module Name: dtcompiler.h - header for data table compiler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __DTCOMPILER_H__ + +#ifndef _DTCOMPILER +#define _DTCOMPILER + +#include +#include "acdisasm.h" + + +#define ASL_FIELD_CACHE_SIZE 512 +#define ASL_SUBTABLE_CACHE_SIZE 128 + + +#undef DT_EXTERN + +#ifdef _DECLARE_DT_GLOBALS +#define DT_EXTERN +#define DT_INIT_GLOBAL(a,b) (a)=(b) +#else +#define DT_EXTERN extern +#define DT_INIT_GLOBAL(a,b) (a) +#endif + + +/* Types for individual fields (one per input line) */ + +#define DT_FIELD_TYPE_STRING 0 +#define DT_FIELD_TYPE_INTEGER 1 +#define DT_FIELD_TYPE_BUFFER 2 +#define DT_FIELD_TYPE_PCI_PATH 3 +#define DT_FIELD_TYPE_FLAG 4 +#define DT_FIELD_TYPE_FLAGS_INTEGER 5 +#define DT_FIELD_TYPE_INLINE_SUBTABLE 6 +#define DT_FIELD_TYPE_UUID 7 +#define DT_FIELD_TYPE_UNICODE 8 +#define DT_FIELD_TYPE_DEVICE_PATH 9 +#define DT_FIELD_TYPE_LABEL 10 + + +/* + * Structure used for each individual field within an ACPI table + */ +typedef struct dt_field +{ + char *Name; /* Field name (from name : value) */ + char *Value; /* Field value (from name : value) */ + UINT32 StringLength;/* Length of Value */ + struct dt_field *Next; /* Next field */ + struct dt_field *NextLabel; /* If field is a label, next label */ + UINT32 Line; /* Line number for this field */ + UINT32 ByteOffset; /* Offset in source file for field */ + UINT32 NameColumn; /* Start column for field name */ + UINT32 Column; /* Start column for field value */ + UINT32 TableOffset; /* Binary offset within ACPI table */ + UINT8 Flags; + +} DT_FIELD; + +/* Flags for above */ + +#define DT_FIELD_NOT_ALLOCATED 1 + + +/* + * Structure used for individual subtables within an ACPI table + */ +typedef struct dt_subtable +{ + struct dt_subtable *Parent; + struct dt_subtable *Child; + struct dt_subtable *Peer; + struct dt_subtable *StackTop; + UINT8 *Buffer; + UINT8 *LengthField; + char *Name; + UINT32 Length; + UINT32 TotalLength; + UINT32 SizeOfLengthField; + UINT16 Depth; + UINT8 Flags; + +} DT_SUBTABLE; + + +/* + * Globals + */ + +/* List of all field names and values from the input source */ + +DT_EXTERN DT_FIELD DT_INIT_GLOBAL (*Gbl_FieldList, NULL); + +/* List of all compiled tables and subtables */ + +DT_EXTERN DT_SUBTABLE DT_INIT_GLOBAL (*Gbl_RootTable, NULL); + +/* Stack for subtables */ + +DT_EXTERN DT_SUBTABLE DT_INIT_GLOBAL (*Gbl_SubtableStack, NULL); + +/* List for defined labels */ + +DT_EXTERN DT_FIELD DT_INIT_GLOBAL (*Gbl_LabelList, NULL); + +/* Current offset within the binary output table */ + +DT_EXTERN UINT32 DT_INIT_GLOBAL (Gbl_CurrentTableOffset, 0); + +/* Local caches */ + +DT_EXTERN UINT32 DT_INIT_GLOBAL (Gbl_SubtableCount, 0); +DT_EXTERN ASL_CACHE_INFO DT_INIT_GLOBAL (*Gbl_SubtableCacheList, NULL); +DT_EXTERN DT_SUBTABLE DT_INIT_GLOBAL (*Gbl_SubtableCacheNext, NULL); +DT_EXTERN DT_SUBTABLE DT_INIT_GLOBAL (*Gbl_SubtableCacheLast, NULL); + +DT_EXTERN UINT32 DT_INIT_GLOBAL (Gbl_FieldCount, 0); +DT_EXTERN ASL_CACHE_INFO DT_INIT_GLOBAL (*Gbl_FieldCacheList, NULL); +DT_EXTERN DT_FIELD DT_INIT_GLOBAL (*Gbl_FieldCacheNext, NULL); +DT_EXTERN DT_FIELD DT_INIT_GLOBAL (*Gbl_FieldCacheLast, NULL); + + +/* dtcompiler - main module */ + +ACPI_STATUS +DtCompileTable ( + DT_FIELD **Field, + ACPI_DMTABLE_INFO *Info, + DT_SUBTABLE **RetSubtable, + BOOLEAN Required); + +ACPI_STATUS +DtCompileTwoSubtables ( + void **List, + ACPI_DMTABLE_INFO *TableInfo1, + ACPI_DMTABLE_INFO *TableInfo2); + +ACPI_STATUS +DtCompilePadding ( + UINT32 Length, + DT_SUBTABLE **RetSubtable); + + +/* dtio - binary and text input/output */ + +UINT32 +DtGetNextLine ( + FILE *Handle, + UINT32 Flags); + +/* Flags for DtGetNextLine */ + +#define DT_ALLOW_MULTILINE_QUOTES 0x01 + + +DT_FIELD * +DtScanFile ( + FILE *Handle); + +void +DtOutputBinary ( + DT_SUBTABLE *RootTable); + +void +DtDumpSubtableList ( + void); + +void +DtDumpFieldList ( + DT_FIELD *Field); + +void +DtWriteFieldToListing ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 Length); + +void +DtWriteTableToListing ( + void); + + +/* dtsubtable - compile subtables */ + +void +DtCreateSubtable ( + UINT8 *Buffer, + UINT32 Length, + DT_SUBTABLE **RetSubtable); + +UINT32 +DtGetSubtableLength ( + DT_FIELD *Field, + ACPI_DMTABLE_INFO *Info); + +void +DtSetSubtableLength ( + DT_SUBTABLE *Subtable); + +void +DtPushSubtable ( + DT_SUBTABLE *Subtable); + +void +DtPopSubtable ( + void); + +DT_SUBTABLE * +DtPeekSubtable ( + void); + +void +DtInsertSubtable ( + DT_SUBTABLE *ParentTable, + DT_SUBTABLE *Subtable); + +DT_SUBTABLE * +DtGetNextSubtable ( + DT_SUBTABLE *ParentTable, + DT_SUBTABLE *ChildTable); + +DT_SUBTABLE * +DtGetParentSubtable ( + DT_SUBTABLE *Subtable); + + +/* dtexpress - Integer expressions and labels */ + +ACPI_STATUS +DtResolveIntegerExpression ( + DT_FIELD *Field, + UINT64 *ReturnValue); + +UINT64 +DtDoOperator ( + UINT64 LeftValue, + UINT32 Operator, + UINT64 RightValue); + +UINT64 +DtResolveLabel ( + char *LabelString); + +void +DtDetectAllLabels ( + DT_FIELD *FieldList); + + +/* dtfield - Compile individual fields within a table */ + +void +DtCompileOneField ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength, + UINT8 Type, + UINT8 Flags); + +void +DtCompileInteger ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength, + UINT8 Flags); + +UINT32 +DtCompileBuffer ( + UINT8 *Buffer, + char *Value, + DT_FIELD *Field, + UINT32 ByteLength); + +void +DtCompileFlag ( + UINT8 *Buffer, + DT_FIELD *Field, + ACPI_DMTABLE_INFO *Info); + + +/* dtparser - lex/yacc files */ + +UINT64 +DtEvaluateExpression ( + char *ExprString); + +int +DtInitLexer ( + char *String); + +void +DtTerminateLexer ( + void); + +char * +DtGetOpName ( + UINT32 ParseOpcode); + + +/* dtutils - Miscellaneous utilities */ + +typedef +void (*DT_WALK_CALLBACK) ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue); + +void +DtWalkTableTree ( + DT_SUBTABLE *StartTable, + DT_WALK_CALLBACK UserFunction, + void *Context, + void *ReturnValue); + +void +DtError ( + UINT8 Level, + UINT16 MessageId, + DT_FIELD *FieldObject, + char *ExtraMessage); + +void +DtNameError ( + UINT8 Level, + UINT16 MessageId, + DT_FIELD *FieldObject, + char *ExtraMessage); + +void +DtFatal ( + UINT16 MessageId, + DT_FIELD *FieldObject, + char *ExtraMessage); + +ACPI_STATUS +DtStrtoul64 ( + char *String, + UINT64 *ReturnInteger); + +char* +DtGetFieldValue ( + DT_FIELD *Field); + +UINT8 +DtGetFieldType ( + ACPI_DMTABLE_INFO *Info); + +UINT32 +DtGetBufferLength ( + char *Buffer); + +UINT32 +DtGetFieldLength ( + DT_FIELD *Field, + ACPI_DMTABLE_INFO *Info); + +void +DtSetTableChecksum ( + UINT8 *ChecksumPointer); + +void +DtSetTableLength( + void); + +DT_SUBTABLE * +UtSubtableCacheCalloc ( + void); + +DT_FIELD * +UtFieldCacheCalloc ( + void); + +void +DtDeleteCaches ( + void); + + +/* dttable - individual table compilation */ + +ACPI_STATUS +DtCompileFacs ( + DT_FIELD **PFieldList); + +ACPI_STATUS +DtCompileRsdp ( + DT_FIELD **PFieldList); + +ACPI_STATUS +DtCompileAsf ( + void **PFieldList); + +ACPI_STATUS +DtCompileCpep ( + void **PFieldList); + +ACPI_STATUS +DtCompileCsrt ( + void **PFieldList); + +ACPI_STATUS +DtCompileDbg2 ( + void **PFieldList); + +ACPI_STATUS +DtCompileDmar ( + void **PFieldList); + +ACPI_STATUS +DtCompileDrtm ( + void **PFieldList); + +ACPI_STATUS +DtCompileEinj ( + void **PFieldList); + +ACPI_STATUS +DtCompileErst ( + void **PFieldList); + +ACPI_STATUS +DtCompileFadt ( + void **PFieldList); + +ACPI_STATUS +DtCompileFpdt ( + void **PFieldList); + +ACPI_STATUS +DtCompileGtdt ( + void **PFieldList); + +ACPI_STATUS +DtCompileHest ( + void **PFieldList); + +ACPI_STATUS +DtCompileIort ( + void **PFieldList); + +ACPI_STATUS +DtCompileIvrs ( + void **PFieldList); + +ACPI_STATUS +DtCompileLpit ( + void **PFieldList); + +ACPI_STATUS +DtCompileMadt ( + void **PFieldList); + +ACPI_STATUS +DtCompileMcfg ( + void **PFieldList); + +ACPI_STATUS +DtCompileMpst ( + void **PFieldList); + +ACPI_STATUS +DtCompileMsct ( + void **PFieldList); + +ACPI_STATUS +DtCompileMtmr ( + void **PFieldList); + +ACPI_STATUS +DtCompileNfit ( + void **PFieldList); + +ACPI_STATUS +DtCompilePmtt ( + void **PFieldList); + +ACPI_STATUS +DtCompilePcct ( + void **PFieldList); + +ACPI_STATUS +DtCompileRsdt ( + void **PFieldList); + +ACPI_STATUS +DtCompileS3pt ( + DT_FIELD **PFieldList); + +ACPI_STATUS +DtCompileSlic ( + void **PFieldList); + +ACPI_STATUS +DtCompileSlit ( + void **PFieldList); + +ACPI_STATUS +DtCompileSrat ( + void **PFieldList); + +ACPI_STATUS +DtCompileStao ( + void **PFieldList); + +ACPI_STATUS +DtCompileTcpa ( + void **PFieldList); + +ACPI_STATUS +DtCompileUefi ( + void **PFieldList); + +ACPI_STATUS +DtCompileVrtc ( + void **PFieldList); + +ACPI_STATUS +DtCompileWdat ( + void **PFieldList); + +ACPI_STATUS +DtCompileWpbt ( + void **PFieldList); + +ACPI_STATUS +DtCompileXsdt ( + void **PFieldList); + +ACPI_STATUS +DtCompileGeneric ( + void **PFieldList, + char *TermFieldName, + UINT32 *PFieldLength); + +ACPI_DMTABLE_INFO * +DtGetGenericTableInfo ( + char *Name); + +/* ACPI Table templates */ + +extern const unsigned char TemplateAsf[]; +extern const unsigned char TemplateBoot[]; +extern const unsigned char TemplateBert[]; +extern const unsigned char TemplateBgrt[]; +extern const unsigned char TemplateCpep[]; +extern const unsigned char TemplateCsrt[]; +extern const unsigned char TemplateDbg2[]; +extern const unsigned char TemplateDbgp[]; +extern const unsigned char TemplateDmar[]; +extern const unsigned char TemplateDrtm[]; +extern const unsigned char TemplateEcdt[]; +extern const unsigned char TemplateEinj[]; +extern const unsigned char TemplateErst[]; +extern const unsigned char TemplateFadt[]; +extern const unsigned char TemplateFpdt[]; +extern const unsigned char TemplateGtdt[]; +extern const unsigned char TemplateHest[]; +extern const unsigned char TemplateHpet[]; +extern const unsigned char TemplateIort[]; +extern const unsigned char TemplateIvrs[]; +extern const unsigned char TemplateLpit[]; +extern const unsigned char TemplateMadt[]; +extern const unsigned char TemplateMcfg[]; +extern const unsigned char TemplateMchi[]; +extern const unsigned char TemplateMpst[]; +extern const unsigned char TemplateMsct[]; +extern const unsigned char TemplateMsdm[]; +extern const unsigned char TemplateMtmr[]; +extern const unsigned char TemplateNfit[]; +extern const unsigned char TemplatePcct[]; +extern const unsigned char TemplatePmtt[]; +extern const unsigned char TemplateRsdt[]; +extern const unsigned char TemplateS3pt[]; +extern const unsigned char TemplateSbst[]; +extern const unsigned char TemplateSlic[]; +extern const unsigned char TemplateSlit[]; +extern const unsigned char TemplateSpcr[]; +extern const unsigned char TemplateSpmi[]; +extern const unsigned char TemplateSrat[]; +extern const unsigned char TemplateStao[]; +extern const unsigned char TemplateTcpa[]; +extern const unsigned char TemplateTpm2[]; +extern const unsigned char TemplateUefi[]; +extern const unsigned char TemplateVrtc[]; +extern const unsigned char TemplateWaet[]; +extern const unsigned char TemplateWdat[]; +extern const unsigned char TemplateWddt[]; +extern const unsigned char TemplateWdrt[]; +extern const unsigned char TemplateWpbt[]; +extern const unsigned char TemplateXenv[]; +extern const unsigned char TemplateXsdt[]; + +#endif diff --git a/third_party/lib/acpica/source/compiler/dtexpress.c b/third_party/lib/acpica/source/compiler/dtexpress.c new file mode 100644 index 000000000..278b14f33 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtexpress.c @@ -0,0 +1,427 @@ +/****************************************************************************** + * + * Module Name: dtexpress.c - Support for integer expressions and labels + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" +#include "dtparser.y.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtexpress") + + +/* Local prototypes */ + +static void +DtInsertLabelField ( + DT_FIELD *Field); + +static DT_FIELD * +DtLookupLabel ( + char *Name); + +/* Global used for errors during parse and related functions */ + +DT_FIELD *Gbl_CurrentField; + + +/****************************************************************************** + * + * FUNCTION: DtResolveIntegerExpression + * + * PARAMETERS: Field - Field object with Integer expression + * ReturnValue - Where the integer is returned + * + * RETURN: Status, and the resolved 64-bit integer value + * + * DESCRIPTION: Resolve an integer expression to a single value. Supports + * both integer constants and labels. + * + *****************************************************************************/ + +ACPI_STATUS +DtResolveIntegerExpression ( + DT_FIELD *Field, + UINT64 *ReturnValue) +{ + UINT64 Result; + + + DbgPrint (ASL_DEBUG_OUTPUT, "Full Integer expression: %s\n", + Field->Value); + + Gbl_CurrentField = Field; + + Result = DtEvaluateExpression (Field->Value); + *ReturnValue = Result; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtDoOperator + * + * PARAMETERS: LeftValue - First 64-bit operand + * Operator - Parse token for the operator (EXPOP_*) + * RightValue - Second 64-bit operand + * + * RETURN: 64-bit result of the requested operation + * + * DESCRIPTION: Perform the various 64-bit integer math functions + * + *****************************************************************************/ + +UINT64 +DtDoOperator ( + UINT64 LeftValue, + UINT32 Operator, + UINT64 RightValue) +{ + UINT64 Result; + + + /* Perform the requested operation */ + + switch (Operator) + { + case EXPOP_ONES_COMPLIMENT: + + Result = ~RightValue; + break; + + case EXPOP_LOGICAL_NOT: + + Result = !RightValue; + break; + + case EXPOP_MULTIPLY: + + Result = LeftValue * RightValue; + break; + + case EXPOP_DIVIDE: + + if (!RightValue) + { + DtError (ASL_ERROR, ASL_MSG_DIVIDE_BY_ZERO, + Gbl_CurrentField, NULL); + return (0); + } + + Result = LeftValue / RightValue; + break; + + case EXPOP_MODULO: + + if (!RightValue) + { + DtError (ASL_ERROR, ASL_MSG_DIVIDE_BY_ZERO, + Gbl_CurrentField, NULL); + return (0); + } + + Result = LeftValue % RightValue; + break; + + case EXPOP_ADD: + Result = LeftValue + RightValue; + break; + + case EXPOP_SUBTRACT: + + Result = LeftValue - RightValue; + break; + + case EXPOP_SHIFT_RIGHT: + + Result = LeftValue >> RightValue; + break; + + case EXPOP_SHIFT_LEFT: + + Result = LeftValue << RightValue; + break; + + case EXPOP_LESS: + + Result = LeftValue < RightValue; + break; + + case EXPOP_GREATER: + + Result = LeftValue > RightValue; + break; + + case EXPOP_LESS_EQUAL: + + Result = LeftValue <= RightValue; + break; + + case EXPOP_GREATER_EQUAL: + + Result = LeftValue >= RightValue; + break; + + case EXPOP_EQUAL: + + Result = LeftValue == RightValue; + break; + + case EXPOP_NOT_EQUAL: + + Result = LeftValue != RightValue; + break; + + case EXPOP_AND: + + Result = LeftValue & RightValue; + break; + + case EXPOP_XOR: + + Result = LeftValue ^ RightValue; + break; + + case EXPOP_OR: + + Result = LeftValue | RightValue; + break; + + case EXPOP_LOGICAL_AND: + + Result = LeftValue && RightValue; + break; + + case EXPOP_LOGICAL_OR: + + Result = LeftValue || RightValue; + break; + + default: + + /* Unknown operator */ + + DtFatal (ASL_MSG_INVALID_EXPRESSION, + Gbl_CurrentField, NULL); + return (0); + } + + DbgPrint (ASL_DEBUG_OUTPUT, + "IntegerEval: (%8.8X%8.8X %s %8.8X%8.8X) = %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (LeftValue), + DtGetOpName (Operator), + ACPI_FORMAT_UINT64 (RightValue), + ACPI_FORMAT_UINT64 (Result)); + + return (Result); +} + + +/****************************************************************************** + * + * FUNCTION: DtResolveLabel + * + * PARAMETERS: LabelString - Contains the label + * + * RETURN: Table offset associated with the label + * + * DESCRIPTION: Lookup a lable and return its value. + * + *****************************************************************************/ + +UINT64 +DtResolveLabel ( + char *LabelString) +{ + DT_FIELD *LabelField; + + + DbgPrint (ASL_DEBUG_OUTPUT, "Resolve Label: %s\n", LabelString); + + /* Resolve a label reference to an integer (table offset) */ + + if (*LabelString != '$') + { + return (0); + } + + LabelField = DtLookupLabel (LabelString); + if (!LabelField) + { + DtError (ASL_ERROR, ASL_MSG_UNKNOWN_LABEL, + Gbl_CurrentField, LabelString); + return (0); + } + + /* All we need from the label is the offset in the table */ + + DbgPrint (ASL_DEBUG_OUTPUT, "Resolved Label: 0x%8.8X\n", + LabelField->TableOffset); + + return (LabelField->TableOffset); +} + + +/****************************************************************************** + * + * FUNCTION: DtDetectAllLabels + * + * PARAMETERS: FieldList - Field object at start of generic list + * + * RETURN: None + * + * DESCRIPTION: Detect all labels in a list of "generic" opcodes (such as + * a UEFI table.) and insert them into the global label list. + * + *****************************************************************************/ + +void +DtDetectAllLabels ( + DT_FIELD *FieldList) +{ + ACPI_DMTABLE_INFO *Info; + DT_FIELD *GenericField; + UINT32 TableOffset; + + + TableOffset = Gbl_CurrentTableOffset; + GenericField = FieldList; + + /* + * Process all "Label:" fields within the parse tree. We need + * to know the offsets for all labels before we can compile + * the parse tree in order to handle forward references. Traverse + * tree and get/set all field lengths of all operators in order to + * determine the label offsets. + */ + while (GenericField) + { + Info = DtGetGenericTableInfo (GenericField->Name); + if (Info) + { + /* Maintain table offsets */ + + GenericField->TableOffset = TableOffset; + TableOffset += DtGetFieldLength (GenericField, Info); + + /* Insert all labels in the global label list */ + + if (Info->Opcode == ACPI_DMT_LABEL) + { + DtInsertLabelField (GenericField); + } + } + + GenericField = GenericField->Next; + } +} + + +/****************************************************************************** + * + * FUNCTION: DtInsertLabelField + * + * PARAMETERS: Field - Field object with Label to be inserted + * + * RETURN: None + * + * DESCRIPTION: Insert a label field into the global label list + * + *****************************************************************************/ + +static void +DtInsertLabelField ( + DT_FIELD *Field) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, + "DtInsertLabelField: Found Label : %s at output table offset %X\n", + Field->Value, Field->TableOffset); + + Field->NextLabel = Gbl_LabelList; + Gbl_LabelList = Field; +} + + +/****************************************************************************** + * + * FUNCTION: DtLookupLabel + * + * PARAMETERS: Name - Label to be resolved + * + * RETURN: Field object associated with the label + * + * DESCRIPTION: Lookup a label in the global label list. Used during the + * resolution of integer expressions. + * + *****************************************************************************/ + +static DT_FIELD * +DtLookupLabel ( + char *Name) +{ + DT_FIELD *LabelField; + + + /* Skip a leading $ */ + + if (*Name == '$') + { + Name++; + } + + /* Search global list */ + + LabelField = Gbl_LabelList; + while (LabelField) + { + if (!strcmp (Name, LabelField->Value)) + { + return (LabelField); + } + + LabelField = LabelField->NextLabel; + } + + return (NULL); +} diff --git a/third_party/lib/acpica/source/compiler/dtfield.c b/third_party/lib/acpica/source/compiler/dtfield.c new file mode 100644 index 000000000..a34b8e16a --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtfield.c @@ -0,0 +1,587 @@ +/****************************************************************************** + * + * Module Name: dtfield.c - Code generation for individual source fields + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtfield") + + +/* Local prototypes */ + +static void +DtCompileString ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength); + +static void +DtCompileUnicode ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength); + +static ACPI_STATUS +DtCompileUuid ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength); + +static char * +DtNormalizeBuffer ( + char *Buffer, + UINT32 *Count); + + +/****************************************************************************** + * + * FUNCTION: DtCompileOneField + * + * PARAMETERS: Buffer - Output buffer + * Field - Field to be compiled + * ByteLength - Byte length of the field + * Type - Field type + * + * RETURN: None + * + * DESCRIPTION: Compile a field value to binary + * + *****************************************************************************/ + +void +DtCompileOneField ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength, + UINT8 Type, + UINT8 Flags) +{ + ACPI_STATUS Status; + + + switch (Type) + { + case DT_FIELD_TYPE_INTEGER: + + DtCompileInteger (Buffer, Field, ByteLength, Flags); + break; + + case DT_FIELD_TYPE_STRING: + + DtCompileString (Buffer, Field, ByteLength); + break; + + case DT_FIELD_TYPE_UUID: + + Status = DtCompileUuid (Buffer, Field, ByteLength); + if (ACPI_SUCCESS (Status)) + { + break; + } + + /* Fall through. */ + + case DT_FIELD_TYPE_BUFFER: + + DtCompileBuffer (Buffer, Field->Value, Field, ByteLength); + break; + + case DT_FIELD_TYPE_UNICODE: + + DtCompileUnicode (Buffer, Field, ByteLength); + break; + + case DT_FIELD_TYPE_DEVICE_PATH: + + break; + + default: + + DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid field type"); + break; + } +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileString + * + * PARAMETERS: Buffer - Output buffer + * Field - String to be copied to buffer + * ByteLength - Maximum length of string + * + * RETURN: None + * + * DESCRIPTION: Copy string to the buffer + * + *****************************************************************************/ + +static void +DtCompileString ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength) +{ + UINT32 Length; + + + Length = strlen (Field->Value); + + /* Check if the string is too long for the field */ + + if (Length > ByteLength) + { + sprintf (MsgBuffer, "Maximum %u characters", ByteLength); + DtError (ASL_ERROR, ASL_MSG_STRING_LENGTH, Field, MsgBuffer); + Length = ByteLength; + } + + memcpy (Buffer, Field->Value, Length); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileUnicode + * + * PARAMETERS: Buffer - Output buffer + * Field - String to be copied to buffer + * ByteLength - Maximum length of string + * + * RETURN: None + * + * DESCRIPTION: Convert ASCII string to Unicode string + * + * Note: The Unicode string is 16 bits per character, no leading signature, + * with a 16-bit terminating NULL. + * + *****************************************************************************/ + +static void +DtCompileUnicode ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength) +{ + UINT32 Count; + UINT32 i; + char *AsciiString; + UINT16 *UnicodeString; + + + AsciiString = Field->Value; + UnicodeString = (UINT16 *) Buffer; + Count = strlen (AsciiString) + 1; + + /* Convert to Unicode string (including null terminator) */ + + for (i = 0; i < Count; i++) + { + UnicodeString[i] = (UINT16) AsciiString[i]; + } +} + + +/******************************************************************************* + * + * FUNCTION: DtCompileUuid + * + * PARAMETERS: Buffer - Output buffer + * Field - String to be copied to buffer + * ByteLength - Maximum length of string + * + * RETURN: None + * + * DESCRIPTION: Convert UUID string to 16-byte buffer + * + ******************************************************************************/ + +static ACPI_STATUS +DtCompileUuid ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength) +{ + char *InString; + ACPI_STATUS Status; + + + InString = Field->Value; + + Status = AuValidateUuid (InString); + if (ACPI_FAILURE (Status)) + { + sprintf (MsgBuffer, "%s", Field->Value); + DtNameError (ASL_ERROR, ASL_MSG_INVALID_UUID, Field, MsgBuffer); + } + else + { + AcpiUtConvertStringToUuid (InString, Buffer); + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileInteger + * + * PARAMETERS: Buffer - Output buffer + * Field - Field obj with Integer to be compiled + * ByteLength - Byte length of the integer + * Flags - Additional compile info + * + * RETURN: None + * + * DESCRIPTION: Compile an integer. Supports integer expressions with C-style + * operators. + * + *****************************************************************************/ + +void +DtCompileInteger ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 ByteLength, + UINT8 Flags) +{ + UINT64 Value; + UINT64 MaxValue; + ACPI_STATUS Status; + + + /* Output buffer byte length must be in range 1-8 */ + + if ((ByteLength > 8) || (ByteLength == 0)) + { + DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, + "Invalid internal Byte length"); + return; + } + + /* Resolve integer expression to a single integer value */ + + Status = DtResolveIntegerExpression (Field, &Value); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* + * Ensure that reserved fields are set properly. Note: uses + * the DT_NON_ZERO flag to indicate that the reserved value + * must be exactly one. Otherwise, the value must be zero. + * This is sufficient for now. + */ + + /* TBD: Should use a flag rather than compare "Reserved" */ + + if (!strcmp (Field->Name, "Reserved")) + { + if (Flags & DT_NON_ZERO) + { + if (Value != 1) + { + DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field, + "Must be one, setting to one"); + Value = 1; + } + } + else if (Value != 0) + { + DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field, + "Must be zero, setting to zero"); + Value = 0; + } + } + + /* Check if the value must be non-zero */ + + else if ((Flags & DT_NON_ZERO) && (Value == 0)) + { + DtError (ASL_ERROR, ASL_MSG_ZERO_VALUE, Field, NULL); + } + + /* + * Generate the maximum value for the data type (ByteLength) + * Note: construct chosen for maximum portability + */ + MaxValue = ((UINT64) (-1)) >> (64 - (ByteLength * 8)); + + /* Validate that the input value is within range of the target */ + + if (Value > MaxValue) + { + sprintf (MsgBuffer, "%8.8X%8.8X - max %u bytes", + ACPI_FORMAT_UINT64 (Value), ByteLength); + DtError (ASL_ERROR, ASL_MSG_INTEGER_SIZE, Field, MsgBuffer); + } + + memcpy (Buffer, &Value, ByteLength); + return; +} + + +/****************************************************************************** + * + * FUNCTION: DtNormalizeBuffer + * + * PARAMETERS: Buffer - Input buffer + * Count - Output the count of hex number in + * the Buffer + * + * RETURN: The normalized buffer, freed by caller + * + * DESCRIPTION: [1A,2B,3C,4D] or 1A, 2B, 3C, 4D will be normalized + * to 1A 2B 3C 4D + * + *****************************************************************************/ + +static char * +DtNormalizeBuffer ( + char *Buffer, + UINT32 *Count) +{ + char *NewBuffer; + char *TmpBuffer; + UINT32 BufferCount = 0; + BOOLEAN Separator = TRUE; + char c; + + + NewBuffer = UtLocalCalloc (strlen (Buffer) + 1); + TmpBuffer = NewBuffer; + + while ((c = *Buffer++)) + { + switch (c) + { + /* Valid separators */ + + case '[': + case ']': + case ' ': + case ',': + + Separator = TRUE; + break; + + default: + + if (Separator) + { + /* Insert blank as the standard separator */ + + if (NewBuffer[0]) + { + *TmpBuffer++ = ' '; + BufferCount++; + } + + Separator = FALSE; + } + + *TmpBuffer++ = c; + break; + } + } + + *Count = BufferCount + 1; + return (NewBuffer); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileBuffer + * + * PARAMETERS: Buffer - Output buffer + * StringValue - Integer list to be compiled + * Field - Current field object + * ByteLength - Byte length of the integer list + * + * RETURN: Count of remaining data in the input list + * + * DESCRIPTION: Compile and pack an integer list, for example + * "AA 1F 20 3B" ==> Buffer[] = {0xAA,0x1F,0x20,0x3B} + * + *****************************************************************************/ + +UINT32 +DtCompileBuffer ( + UINT8 *Buffer, + char *StringValue, + DT_FIELD *Field, + UINT32 ByteLength) +{ + ACPI_STATUS Status; + char Hex[3]; + UINT64 Value; + UINT32 i; + UINT32 Count; + + + /* Allow several different types of value separators */ + + StringValue = DtNormalizeBuffer (StringValue, &Count); + + Hex[2] = 0; + for (i = 0; i < Count; i++) + { + /* Each element of StringValue is three chars */ + + Hex[0] = StringValue[(3 * i)]; + Hex[1] = StringValue[(3 * i) + 1]; + + /* Convert one hex byte */ + + Value = 0; + Status = DtStrtoul64 (Hex, &Value); + if (ACPI_FAILURE (Status)) + { + DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, MsgBuffer); + goto Exit; + } + + Buffer[i] = (UINT8) Value; + } + +Exit: + ACPI_FREE (StringValue); + return (ByteLength - Count); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileFlag + * + * PARAMETERS: Buffer - Output buffer + * Field - Field to be compiled + * Info - Flag info + * + * RETURN: + * + * DESCRIPTION: Compile a flag + * + *****************************************************************************/ + +void +DtCompileFlag ( + UINT8 *Buffer, + DT_FIELD *Field, + ACPI_DMTABLE_INFO *Info) +{ + UINT64 Value = 0; + UINT32 BitLength = 1; + UINT8 BitPosition = 0; + ACPI_STATUS Status; + + + Status = DtStrtoul64 (Field->Value, &Value); + if (ACPI_FAILURE (Status)) + { + DtError (ASL_ERROR, ASL_MSG_INVALID_HEX_INTEGER, Field, NULL); + } + + switch (Info->Opcode) + { + case ACPI_DMT_FLAG0: + case ACPI_DMT_FLAG1: + case ACPI_DMT_FLAG2: + case ACPI_DMT_FLAG3: + case ACPI_DMT_FLAG4: + case ACPI_DMT_FLAG5: + case ACPI_DMT_FLAG6: + case ACPI_DMT_FLAG7: + + BitPosition = Info->Opcode; + BitLength = 1; + break; + + case ACPI_DMT_FLAGS0: + + BitPosition = 0; + BitLength = 2; + break; + + + case ACPI_DMT_FLAGS1: + + BitPosition = 1; + BitLength = 2; + break; + + + case ACPI_DMT_FLAGS2: + + BitPosition = 2; + BitLength = 2; + break; + + case ACPI_DMT_FLAGS4: + + BitPosition = 4; + BitLength = 2; + break; + + default: + + DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode"); + break; + } + + /* Check range of the input flag value */ + + if (Value >= ((UINT64) 1 << BitLength)) + { + sprintf (MsgBuffer, "Maximum %u bit", BitLength); + DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, MsgBuffer); + Value = 0; + } + + *Buffer |= (UINT8) (Value << BitPosition); +} diff --git a/third_party/lib/acpica/source/compiler/dtio.c b/third_party/lib/acpica/source/compiler/dtio.c new file mode 100644 index 000000000..a24ad3442 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtio.c @@ -0,0 +1,1149 @@ +/****************************************************************************** + * + * Module Name: dtio.c - File I/O support for data table compiler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" +#include "acapps.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtio") + + +/* Local prototypes */ + +static char * +DtTrim ( + char *String); + +static void +DtLinkField ( + DT_FIELD *Field); + +static ACPI_STATUS +DtParseLine ( + char *LineBuffer, + UINT32 Line, + UINT32 Offset); + +static void +DtWriteBinary ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue); + +static void +DtDumpBuffer ( + UINT32 FileId, + UINT8 *Buffer, + UINT32 Offset, + UINT32 Length); + +static void +DtDumpSubtableInfo ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue); + +static void +DtDumpSubtableTree ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue); + + +/* States for DtGetNextLine */ + +#define DT_NORMAL_TEXT 0 +#define DT_START_QUOTED_STRING 1 +#define DT_START_COMMENT 2 +#define DT_SLASH_ASTERISK_COMMENT 3 +#define DT_SLASH_SLASH_COMMENT 4 +#define DT_END_COMMENT 5 +#define DT_MERGE_LINES 6 +#define DT_ESCAPE_SEQUENCE 7 + +static UINT32 Gbl_NextLineOffset; + + +/****************************************************************************** + * + * FUNCTION: DtTrim + * + * PARAMETERS: String - Current source code line to trim + * + * RETURN: Trimmed line. Must be freed by caller. + * + * DESCRIPTION: Trim left and right spaces + * + *****************************************************************************/ + +static char * +DtTrim ( + char *String) +{ + char *Start; + char *End; + char *ReturnString; + ACPI_SIZE Length; + + + /* Skip lines that start with a space */ + + if (!strcmp (String, " ")) + { + ReturnString = UtStringCacheCalloc (1); + return (ReturnString); + } + + /* Setup pointers to start and end of input string */ + + Start = String; + End = String + strlen (String) - 1; + + /* Find first non-whitespace character */ + + while ((Start <= End) && ((*Start == ' ') || (*Start == '\t'))) + { + Start++; + } + + /* Find last non-space character */ + + while (End >= Start) + { + if (*End == '\r' || *End == '\n') + { + End--; + continue; + } + + if (*End != ' ') + { + break; + } + + End--; + } + + /* Remove any quotes around the string */ + + if (*Start == '\"') + { + Start++; + } + if (*End == '\"') + { + End--; + } + + /* Create the trimmed return string */ + + Length = ACPI_PTR_DIFF (End, Start) + 1; + ReturnString = UtStringCacheCalloc (Length + 1); + if (strlen (Start)) + { + strncpy (ReturnString, Start, Length); + } + + ReturnString[Length] = 0; + return (ReturnString); +} + + +/****************************************************************************** + * + * FUNCTION: DtLinkField + * + * PARAMETERS: Field - New field object to link + * + * RETURN: None + * + * DESCRIPTION: Link one field name and value to the list + * + *****************************************************************************/ + +static void +DtLinkField ( + DT_FIELD *Field) +{ + DT_FIELD *Prev; + DT_FIELD *Next; + + + Prev = Next = Gbl_FieldList; + + while (Next) + { + Prev = Next; + Next = Next->Next; + } + + if (Prev) + { + Prev->Next = Field; + } + else + { + Gbl_FieldList = Field; + } +} + + +/****************************************************************************** + * + * FUNCTION: DtParseLine + * + * PARAMETERS: LineBuffer - Current source code line + * Line - Current line number in the source + * Offset - Current byte offset of the line + * + * RETURN: Status + * + * DESCRIPTION: Parse one source line + * + *****************************************************************************/ + +static ACPI_STATUS +DtParseLine ( + char *LineBuffer, + UINT32 Line, + UINT32 Offset) +{ + char *Start; + char *End; + char *TmpName; + char *TmpValue; + char *Name; + char *Value; + char *Colon; + UINT32 Length; + DT_FIELD *Field; + UINT32 Column; + UINT32 NameColumn; + BOOLEAN IsNullString = FALSE; + + + if (!LineBuffer) + { + return (AE_OK); + } + + /* All lines after "Raw Table Data" are ingored */ + + if (strstr (LineBuffer, ACPI_RAW_TABLE_DATA_HEADER)) + { + return (AE_NOT_FOUND); + } + + Colon = strchr (LineBuffer, ':'); + if (!Colon) + { + return (AE_OK); + } + + Start = LineBuffer; + End = Colon; + + while (Start < Colon) + { + if (*Start == '[') + { + /* Found left bracket, go to the right bracket */ + + while (Start < Colon && *Start != ']') + { + Start++; + } + } + else if (*Start != ' ') + { + break; + } + + Start++; + } + + /* + * There are two column values. One for the field name, + * and one for the field value. + */ + Column = ACPI_PTR_DIFF (Colon, LineBuffer) + 3; + NameColumn = ACPI_PTR_DIFF (Start, LineBuffer) + 1; + + Length = ACPI_PTR_DIFF (End, Start); + + TmpName = UtLocalCalloc (Length + 1); + strncpy (TmpName, Start, Length); + Name = DtTrim (TmpName); + ACPI_FREE (TmpName); + + Start = End = (Colon + 1); + while (*End) + { + /* Found left quotation, go to the right quotation and break */ + + if (*End == '"') + { + End++; + + /* Check for an explicit null string */ + + if (*End == '"') + { + IsNullString = TRUE; + } + while (*End && (*End != '"')) + { + End++; + } + + End++; + break; + } + + /* + * Special "comment" fields at line end, ignore them. + * Note: normal slash-slash and slash-asterisk comments are + * stripped already by the DtGetNextLine parser. + * + * TBD: Perhaps DtGetNextLine should parse the following type + * of comments also. + */ + if (*End == '[') + { + End--; + break; + } + + End++; + } + + Length = ACPI_PTR_DIFF (End, Start); + TmpValue = UtLocalCalloc (Length + 1); + + strncpy (TmpValue, Start, Length); + Value = DtTrim (TmpValue); + ACPI_FREE (TmpValue); + + /* Create a new field object only if we have a valid value field */ + + if ((Value && *Value) || IsNullString) + { + Field = UtFieldCacheCalloc (); + Field->Name = Name; + Field->Value = Value; + Field->Line = Line; + Field->ByteOffset = Offset; + Field->NameColumn = NameColumn; + Field->Column = Column; + Field->StringLength = Length; + + DtLinkField (Field); + } + /* Else -- Ignore this field, it has no valid data */ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetNextLine + * + * PARAMETERS: Handle - Open file handle for the source file + * + * RETURN: Filled line buffer and offset of start-of-line (ASL_EOF on EOF) + * + * DESCRIPTION: Get the next valid source line. Removes all comments. + * Ignores empty lines. + * + * Handles both slash-asterisk and slash-slash comments. + * Also, quoted strings, but no escapes within. + * + * Line is returned in Gbl_CurrentLineBuffer. + * Line number in original file is returned in Gbl_CurrentLineNumber. + * + *****************************************************************************/ + +UINT32 +DtGetNextLine ( + FILE *Handle, + UINT32 Flags) +{ + BOOLEAN LineNotAllBlanks = FALSE; + UINT32 State = DT_NORMAL_TEXT; + UINT32 CurrentLineOffset; + UINT32 i; + int c; + + + memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize); + for (i = 0; ;) + { + /* + * If line is too long, expand the line buffers. Also increases + * Gbl_LineBufferSize. + */ + if (i >= Gbl_LineBufferSize) + { + UtExpandLineBuffers (); + } + + c = getc (Handle); + if (c == EOF) + { + switch (State) + { + case DT_START_QUOTED_STRING: + case DT_SLASH_ASTERISK_COMMENT: + + AcpiOsPrintf ("**** EOF within comment/string %u\n", State); + break; + + default: + + break; + } + + /* Standalone EOF is OK */ + + if (i == 0) + { + return (ASL_EOF); + } + + /* + * Received an EOF in the middle of a line. Terminate the + * line with a newline. The next call to this function will + * return a standalone EOF. Thus, the upper parsing software + * never has to deal with an EOF within a valid line (or + * the last line does not get tossed on the floor.) + */ + c = '\n'; + State = DT_NORMAL_TEXT; + } + + switch (State) + { + case DT_NORMAL_TEXT: + + /* Normal text, insert char into line buffer */ + + Gbl_CurrentLineBuffer[i] = (char) c; + switch (c) + { + case '/': + + State = DT_START_COMMENT; + break; + + case '"': + + State = DT_START_QUOTED_STRING; + LineNotAllBlanks = TRUE; + i++; + break; + + case '\\': + /* + * The continuation char MUST be last char on this line. + * Otherwise, it will be assumed to be a valid ASL char. + */ + State = DT_MERGE_LINES; + break; + + case '\n': + + CurrentLineOffset = Gbl_NextLineOffset; + Gbl_NextLineOffset = (UINT32) ftell (Handle); + Gbl_CurrentLineNumber++; + + /* + * Exit if line is complete. Ignore empty lines (only \n) + * or lines that contain nothing but blanks. + */ + if ((i != 0) && LineNotAllBlanks) + { + if ((i + 1) >= Gbl_LineBufferSize) + { + UtExpandLineBuffers (); + } + + Gbl_CurrentLineBuffer[i+1] = 0; /* Terminate string */ + return (CurrentLineOffset); + } + + /* Toss this line and start a new one */ + + i = 0; + LineNotAllBlanks = FALSE; + break; + + default: + + if (c != ' ') + { + LineNotAllBlanks = TRUE; + } + + i++; + break; + } + break; + + case DT_START_QUOTED_STRING: + + /* Insert raw chars until end of quoted string */ + + Gbl_CurrentLineBuffer[i] = (char) c; + i++; + + switch (c) + { + case '"': + + State = DT_NORMAL_TEXT; + break; + + case '\\': + + State = DT_ESCAPE_SEQUENCE; + break; + + case '\n': + + if (!(Flags & DT_ALLOW_MULTILINE_QUOTES)) + { + AcpiOsPrintf ( + "ERROR at line %u: Unterminated quoted string\n", + Gbl_CurrentLineNumber++); + State = DT_NORMAL_TEXT; + } + break; + + default: /* Get next character */ + + break; + } + break; + + case DT_ESCAPE_SEQUENCE: + + /* Just copy the escaped character. TBD: sufficient for table compiler? */ + + Gbl_CurrentLineBuffer[i] = (char) c; + i++; + State = DT_START_QUOTED_STRING; + break; + + case DT_START_COMMENT: + + /* Open comment if this character is an asterisk or slash */ + + switch (c) + { + case '*': + + State = DT_SLASH_ASTERISK_COMMENT; + break; + + case '/': + + State = DT_SLASH_SLASH_COMMENT; + break; + + default: /* Not a comment */ + + i++; /* Save the preceding slash */ + if (i >= Gbl_LineBufferSize) + { + UtExpandLineBuffers (); + } + + Gbl_CurrentLineBuffer[i] = (char) c; + i++; + State = DT_NORMAL_TEXT; + break; + } + break; + + case DT_SLASH_ASTERISK_COMMENT: + + /* Ignore chars until an asterisk-slash is found */ + + switch (c) + { + case '\n': + + Gbl_NextLineOffset = (UINT32) ftell (Handle); + Gbl_CurrentLineNumber++; + break; + + case '*': + + State = DT_END_COMMENT; + break; + + default: + + break; + } + break; + + case DT_SLASH_SLASH_COMMENT: + + /* Ignore chars until end-of-line */ + + if (c == '\n') + { + /* We will exit via the NORMAL_TEXT path */ + + ungetc (c, Handle); + State = DT_NORMAL_TEXT; + } + break; + + case DT_END_COMMENT: + + /* End comment if this char is a slash */ + + switch (c) + { + case '/': + + State = DT_NORMAL_TEXT; + break; + + case '\n': + + CurrentLineOffset = Gbl_NextLineOffset; + Gbl_NextLineOffset = (UINT32) ftell (Handle); + Gbl_CurrentLineNumber++; + break; + + case '*': + + /* Consume all adjacent asterisks */ + break; + + default: + + State = DT_SLASH_ASTERISK_COMMENT; + break; + } + break; + + case DT_MERGE_LINES: + + if (c != '\n') + { + /* + * This is not a continuation backslash, it is a normal + * normal ASL backslash - for example: Scope(\_SB_) + */ + i++; /* Keep the backslash that is already in the buffer */ + + ungetc (c, Handle); + State = DT_NORMAL_TEXT; + } + else + { + /* + * This is a continuation line -- a backlash followed + * immediately by a newline. Insert a space between the + * lines (overwrite the backslash) + */ + Gbl_CurrentLineBuffer[i] = ' '; + i++; + + /* Ignore newline, this will merge the lines */ + + CurrentLineOffset = Gbl_NextLineOffset; + Gbl_NextLineOffset = (UINT32) ftell (Handle); + Gbl_CurrentLineNumber++; + State = DT_NORMAL_TEXT; + } + break; + + default: + + DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, "Unknown input state"); + return (ASL_EOF); + } + } +} + + +/****************************************************************************** + * + * FUNCTION: DtScanFile + * + * PARAMETERS: Handle - Open file handle for the source file + * + * RETURN: Pointer to start of the constructed parse tree. + * + * DESCRIPTION: Scan source file, link all field names and values + * to the global parse tree: Gbl_FieldList + * + *****************************************************************************/ + +DT_FIELD * +DtScanFile ( + FILE *Handle) +{ + ACPI_STATUS Status; + UINT32 Offset; + + + ACPI_FUNCTION_NAME (DtScanFile); + + + /* Get the file size */ + + Gbl_InputByteCount = CmGetFileSize (Handle); + if (Gbl_InputByteCount == ACPI_UINT32_MAX) + { + AslAbort (); + } + + Gbl_CurrentLineNumber = 0; + Gbl_CurrentLineOffset = 0; + Gbl_NextLineOffset = 0; + + /* Scan line-by-line */ + + while ((Offset = DtGetNextLine (Handle, 0)) != ASL_EOF) + { + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Line %2.2u/%4.4X - %s", + Gbl_CurrentLineNumber, Offset, Gbl_CurrentLineBuffer)); + + Status = DtParseLine (Gbl_CurrentLineBuffer, + Gbl_CurrentLineNumber, Offset); + if (Status == AE_NOT_FOUND) + { + break; + } + } + + /* Dump the parse tree if debug enabled */ + + DtDumpFieldList (Gbl_FieldList); + return (Gbl_FieldList); +} + + +/* + * Output functions + */ + +/****************************************************************************** + * + * FUNCTION: DtWriteBinary + * + * PARAMETERS: DT_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Write one subtable of a binary ACPI table + * + *****************************************************************************/ + +static void +DtWriteBinary ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue) +{ + + FlWriteFile (ASL_FILE_AML_OUTPUT, Subtable->Buffer, Subtable->Length); +} + + +/****************************************************************************** + * + * FUNCTION: DtOutputBinary + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: Write entire binary ACPI table (result of compilation) + * + *****************************************************************************/ + +void +DtOutputBinary ( + DT_SUBTABLE *RootTable) +{ + + if (!RootTable) + { + return; + } + + /* Walk the entire parse tree, emitting the binary data */ + + DtWalkTableTree (RootTable, DtWriteBinary, NULL, NULL); + + Gbl_TableLength = CmGetFileSize (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); + if (Gbl_TableLength == ACPI_UINT32_MAX) + { + AslAbort (); + } +} + + +/* + * Listing support + */ + +/****************************************************************************** + * + * FUNCTION: DtDumpBuffer + * + * PARAMETERS: FileID - Where to write buffer data + * Buffer - Buffer to dump + * Offset - Offset in current table + * Length - Buffer Length + * + * RETURN: None + * + * DESCRIPTION: Another copy of DumpBuffer routine (unfortunately). + * + * TBD: merge dump buffer routines + * + *****************************************************************************/ + +static void +DtDumpBuffer ( + UINT32 FileId, + UINT8 *Buffer, + UINT32 Offset, + UINT32 Length) +{ + UINT32 i; + UINT32 j; + UINT8 BufChar; + + + FlPrintFile (FileId, "Output: [%3.3Xh %4.4d %3d] ", + Offset, Offset, Length); + + i = 0; + while (i < Length) + { + if (i >= 16) + { + FlPrintFile (FileId, "%24s", ""); + } + + /* Print 16 hex chars */ + + for (j = 0; j < 16;) + { + if (i + j >= Length) + { + /* Dump fill spaces */ + + FlPrintFile (FileId, " "); + j++; + continue; + } + + FlPrintFile (FileId, "%02X ", Buffer[i+j]); + j++; + } + + FlPrintFile (FileId, " "); + for (j = 0; j < 16; j++) + { + if (i + j >= Length) + { + FlPrintFile (FileId, "\n\n"); + return; + } + + BufChar = Buffer[(ACPI_SIZE) i + j]; + if (isprint (BufChar)) + { + FlPrintFile (FileId, "%c", BufChar); + } + else + { + FlPrintFile (FileId, "."); + } + } + + /* Done with that line. */ + + FlPrintFile (FileId, "\n"); + i += 16; + } + + FlPrintFile (FileId, "\n\n"); +} + + +/****************************************************************************** + * + * FUNCTION: DtDumpFieldList + * + * PARAMETERS: Field - Root field + * + * RETURN: None + * + * DESCRIPTION: Dump the entire field list + * + *****************************************************************************/ + +void +DtDumpFieldList ( + DT_FIELD *Field) +{ + + if (!Gbl_DebugFlag || !Field) + { + return; + } + + DbgPrint (ASL_DEBUG_OUTPUT, "\nField List:\n" + "LineNo ByteOff NameCol Column TableOff " + "Flags %32s : %s\n\n", "Name", "Value"); + + while (Field) + { + DbgPrint (ASL_DEBUG_OUTPUT, + "%.08X %.08X %.08X %.08X %.08X %2.2X %32s : %s\n", + Field->Line, Field->ByteOffset, Field->NameColumn, + Field->Column, Field->TableOffset, Field->Flags, + Field->Name, Field->Value); + + Field = Field->Next; + } + + DbgPrint (ASL_DEBUG_OUTPUT, "\n\n"); +} + + +/****************************************************************************** + * + * FUNCTION: DtDumpSubtableInfo, DtDumpSubtableTree + * + * PARAMETERS: DT_WALK_CALLBACK + * + * RETURN: None + * + * DESCRIPTION: Info - dump a subtable tree entry with extra information. + * Tree - dump a subtable tree formatted by depth indentation. + * + *****************************************************************************/ + +static void +DtDumpSubtableInfo ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, + "[%.04X] %24s %.08X %.08X %.08X %.08X %.08X %p %p %p\n", + Subtable->Depth, Subtable->Name, Subtable->Length, Subtable->TotalLength, + Subtable->SizeOfLengthField, Subtable->Flags, Subtable, + Subtable->Parent, Subtable->Child, Subtable->Peer); +} + +static void +DtDumpSubtableTree ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, + "[%.04X] %24s %*s%08X (%.02X) - (%.02X)\n", + Subtable->Depth, Subtable->Name, (4 * Subtable->Depth), " ", + Subtable, Subtable->Length, Subtable->TotalLength); +} + + +/****************************************************************************** + * + * FUNCTION: DtDumpSubtableList + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump the raw list of subtables with information, and also + * dump the subtable list in formatted tree format. Assists with + * the development of new table code. + * + *****************************************************************************/ + +void +DtDumpSubtableList ( + void) +{ + + if (!Gbl_DebugFlag || !Gbl_RootTable) + { + return; + } + + DbgPrint (ASL_DEBUG_OUTPUT, + "Subtable Info:\n" + "Depth Name Length TotalLen LenSize Flags " + "This Parent Child Peer\n\n"); + DtWalkTableTree (Gbl_RootTable, DtDumpSubtableInfo, NULL, NULL); + + DbgPrint (ASL_DEBUG_OUTPUT, + "\nSubtable Tree: (Depth, Name, Subtable, Length, TotalLength)\n\n"); + DtWalkTableTree (Gbl_RootTable, DtDumpSubtableTree, NULL, NULL); + + DbgPrint (ASL_DEBUG_OUTPUT, "\n"); +} + + +/****************************************************************************** + * + * FUNCTION: DtWriteFieldToListing + * + * PARAMETERS: Buffer - Contains the compiled data + * Field - Field node for the input line + * Length - Length of the output data + * + * RETURN: None + * + * DESCRIPTION: Write one field to the listing file (if listing is enabled). + * + *****************************************************************************/ + +void +DtWriteFieldToListing ( + UINT8 *Buffer, + DT_FIELD *Field, + UINT32 Length) +{ + UINT8 FileByte; + + + if (!Gbl_ListingFlag || !Field) + { + return; + } + + /* Dump the original source line */ + + FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Input: "); + FlSeekFile (ASL_FILE_INPUT, Field->ByteOffset); + + while (FlReadFile (ASL_FILE_INPUT, &FileByte, 1) == AE_OK) + { + FlWriteFile (ASL_FILE_LISTING_OUTPUT, &FileByte, 1); + if (FileByte == '\n') + { + break; + } + } + + /* Dump the line as parsed and represented internally */ + + FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Parsed: %*s : %.64s", + Field->Column-4, Field->Name, Field->Value); + + if (strlen (Field->Value) > 64) + { + FlPrintFile (ASL_FILE_LISTING_OUTPUT, "...Additional data, length 0x%X\n", + strlen (Field->Value)); + } + + FlPrintFile (ASL_FILE_LISTING_OUTPUT, "\n"); + + /* Dump the hex data that will be output for this field */ + + DtDumpBuffer (ASL_FILE_LISTING_OUTPUT, Buffer, Field->TableOffset, Length); +} + + +/****************************************************************************** + * + * FUNCTION: DtWriteTableToListing + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Write the entire compiled table to the listing file + * in hex format + * + *****************************************************************************/ + +void +DtWriteTableToListing ( + void) +{ + UINT8 *Buffer; + + + if (!Gbl_ListingFlag) + { + return; + } + + /* Read the entire table from the output file */ + + Buffer = UtLocalCalloc (Gbl_TableLength); + FlSeekFile (ASL_FILE_AML_OUTPUT, 0); + FlReadFile (ASL_FILE_AML_OUTPUT, Buffer, Gbl_TableLength); + + /* Dump the raw table data */ + + AcpiOsRedirectOutput (Gbl_Files[ASL_FILE_LISTING_OUTPUT].Handle); + + AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n", + ACPI_RAW_TABLE_DATA_HEADER, Gbl_TableLength, Gbl_TableLength); + AcpiUtDumpBuffer (Buffer, Gbl_TableLength, DB_BYTE_DISPLAY, 0); + + AcpiOsRedirectOutput (stdout); + ACPI_FREE (Buffer); +} diff --git a/third_party/lib/acpica/source/compiler/dtparser.l b/third_party/lib/acpica/source/compiler/dtparser.l new file mode 100644 index 000000000..f3a307a2d --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtparser.l @@ -0,0 +1,133 @@ +%{ +/****************************************************************************** + * + * Module Name: dtparser.l - Flex input file for table compiler lexer + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtparser.y.h" + +#define YY_NO_INPUT /* No file input, we use strings only */ + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("dtscanner") +%} + +%option noyywrap +%option nounput + +Number [0-9a-fA-F]+ +HexNumber 0[xX][0-9a-fA-F]+ +DecimalNumber 0[dD][0-9]+ +LabelRef $[a-zA-Z][0-9a-zA-Z]* +WhiteSpace [ \t\v\r]+ +NewLine [\n] + +%% + +\( return (EXPOP_PAREN_OPEN); +\) return (EXPOP_PAREN_CLOSE); +\~ return (EXPOP_ONES_COMPLIMENT); +\! return (EXPOP_LOGICAL_NOT); +\* return (EXPOP_MULTIPLY); +\/ return (EXPOP_DIVIDE); +\% return (EXPOP_MODULO); +\+ return (EXPOP_ADD); +\- return (EXPOP_SUBTRACT); +">>" return (EXPOP_SHIFT_RIGHT); +"<<" return (EXPOP_SHIFT_LEFT); +\< return (EXPOP_LESS); +\> return (EXPOP_GREATER); +"<=" return (EXPOP_LESS_EQUAL); +">=" return (EXPOP_GREATER_EQUAL); +"==" return (EXPOP_EQUAL); +"!=" return (EXPOP_NOT_EQUAL); +\& return (EXPOP_AND); +\^ return (EXPOP_XOR); +\| return (EXPOP_OR); +"&&" return (EXPOP_LOGICAL_AND); +"||" return (EXPOP_LOGICAL_OR); +<> return (EXPOP_EOF); /* null end-of-string */ + +{LabelRef} return (EXPOP_LABEL); +{Number} return (EXPOP_NUMBER); +{HexNumber} return (EXPOP_HEX_NUMBER); +{NewLine} return (EXPOP_NEW_LINE); +{WhiteSpace} /* Ignore */ + +. return (EXPOP_EOF); + +%% + +/* + * Local support functions + */ +YY_BUFFER_STATE LexBuffer; + +/****************************************************************************** + * + * FUNCTION: DtInitLexer, DtTerminateLexer + * + * PARAMETERS: String - Input string to be parsed + * + * RETURN: None + * + * DESCRIPTION: Initialization and termination routines for lexer. Lexer needs + * a buffer to handle strings instead of a file. + * + *****************************************************************************/ + +int +DtInitLexer ( + char *String) +{ + + LexBuffer = yy_scan_string (String); + return (LexBuffer == NULL); +} + +void +DtTerminateLexer ( + void) +{ + + yy_delete_buffer (LexBuffer); +} diff --git a/third_party/lib/acpica/source/compiler/dtparser.y b/third_party/lib/acpica/source/compiler/dtparser.y new file mode 100644 index 000000000..c4578e14e --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtparser.y @@ -0,0 +1,284 @@ +%{ +/****************************************************************************** + * + * Module Name: dtparser.y - Bison input file for table compiler parser + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtparser") + +void * AslLocalAllocate (unsigned int Size); + +/* Bison/yacc configuration */ + +#undef alloca +#define alloca AslLocalAllocate + +int DtParserlex (void); +int DtParserparse (void); +void DtParsererror (char const *msg); +extern char *DtParsertext; +extern DT_FIELD *Gbl_CurrentField; + +UINT64 DtParserResult; /* Expression return value */ + +/* Bison/yacc configuration */ + +#define yytname DtParsername +#define YYDEBUG 1 /* Enable debug output */ +#define YYERROR_VERBOSE 1 /* Verbose error messages */ +#define YYFLAG -32768 + +/* Define YYMALLOC/YYFREE to prevent redefinition errors */ + +#define YYMALLOC malloc +#define YYFREE free +%} + +%union +{ + UINT64 value; + UINT32 op; +} + +/*! [Begin] no source code translation */ + +%type Expression + +%token EXPOP_EOF +%token EXPOP_NEW_LINE +%token EXPOP_NUMBER +%token EXPOP_HEX_NUMBER +%token EXPOP_DECIMAL_NUMBER +%token EXPOP_LABEL +%token EXPOP_PAREN_OPEN +%token EXPOP_PAREN_CLOSE + +%left EXPOP_LOGICAL_OR +%left EXPOP_LOGICAL_AND +%left EXPOP_OR +%left EXPOP_XOR +%left EXPOP_AND +%left EXPOP_EQUAL EXPOP_NOT_EQUAL +%left EXPOP_GREATER EXPOP_LESS EXPOP_GREATER_EQUAL EXPOP_LESS_EQUAL +%left EXPOP_SHIFT_RIGHT EXPOP_SHIFT_LEFT +%left EXPOP_ADD EXPOP_SUBTRACT +%left EXPOP_MULTIPLY EXPOP_DIVIDE EXPOP_MODULO +%right EXPOP_ONES_COMPLIMENT EXPOP_LOGICAL_NOT + +%% + +/* + * Operator precedence rules (from K&R) + * + * 1) ( ) + * 2) ! ~ (unary operators that are supported here) + * 3) * / % + * 4) + - + * 5) >> << + * 6) < > <= >= + * 7) == != + * 8) & + * 9) ^ + * 10) | + * 11) && + * 12) || + */ +Value + : Expression EXPOP_NEW_LINE { DtParserResult=$1; return 0; } /* End of line (newline) */ + | Expression EXPOP_EOF { DtParserResult=$1; return 0; } /* End of string (0) */ + ; + +Expression + + /* Unary operators */ + + : EXPOP_LOGICAL_NOT Expression { $$ = DtDoOperator ($2, EXPOP_LOGICAL_NOT, $2);} + | EXPOP_ONES_COMPLIMENT Expression { $$ = DtDoOperator ($2, EXPOP_ONES_COMPLIMENT, $2);} + + /* Binary operators */ + + | Expression EXPOP_MULTIPLY Expression { $$ = DtDoOperator ($1, EXPOP_MULTIPLY, $3);} + | Expression EXPOP_DIVIDE Expression { $$ = DtDoOperator ($1, EXPOP_DIVIDE, $3);} + | Expression EXPOP_MODULO Expression { $$ = DtDoOperator ($1, EXPOP_MODULO, $3);} + | Expression EXPOP_ADD Expression { $$ = DtDoOperator ($1, EXPOP_ADD, $3);} + | Expression EXPOP_SUBTRACT Expression { $$ = DtDoOperator ($1, EXPOP_SUBTRACT, $3);} + | Expression EXPOP_SHIFT_RIGHT Expression { $$ = DtDoOperator ($1, EXPOP_SHIFT_RIGHT, $3);} + | Expression EXPOP_SHIFT_LEFT Expression { $$ = DtDoOperator ($1, EXPOP_SHIFT_LEFT, $3);} + | Expression EXPOP_GREATER Expression { $$ = DtDoOperator ($1, EXPOP_GREATER, $3);} + | Expression EXPOP_LESS Expression { $$ = DtDoOperator ($1, EXPOP_LESS, $3);} + | Expression EXPOP_GREATER_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_GREATER_EQUAL, $3);} + | Expression EXPOP_LESS_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_LESS_EQUAL, $3);} + | Expression EXPOP_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_EQUAL, $3);} + | Expression EXPOP_NOT_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_NOT_EQUAL, $3);} + | Expression EXPOP_AND Expression { $$ = DtDoOperator ($1, EXPOP_AND, $3);} + | Expression EXPOP_XOR Expression { $$ = DtDoOperator ($1, EXPOP_XOR, $3);} + | Expression EXPOP_OR Expression { $$ = DtDoOperator ($1, EXPOP_OR, $3);} + | Expression EXPOP_LOGICAL_AND Expression { $$ = DtDoOperator ($1, EXPOP_LOGICAL_AND, $3);} + | Expression EXPOP_LOGICAL_OR Expression { $$ = DtDoOperator ($1, EXPOP_LOGICAL_OR, $3);} + + /* Parentheses: '(' Expression ')' */ + + | EXPOP_PAREN_OPEN Expression + EXPOP_PAREN_CLOSE { $$ = $2;} + + /* Label references (prefixed with $) */ + + | EXPOP_LABEL { $$ = DtResolveLabel (DtParsertext);} + + /* Default base for a non-prefixed integer is 16 */ + + | EXPOP_NUMBER { stroul64 (DtParsertext, 16, &$$);} + + /* Standard hex number (0x1234) */ + + | EXPOP_HEX_NUMBER { stroul64 (DtParsertext, 16, &$$);} + + /* TBD: Decimal number with prefix (0d1234) - Not supported by stroul64 at this time */ + + | EXPOP_DECIMAL_NUMBER { stroul64 (DtParsertext, 10, &$$);} + ; +%% + +/*! [End] no source code translation !*/ + +/* + * Local support functions, including parser entry point + */ +#define PR_FIRST_PARSE_OPCODE EXPOP_EOF +#define PR_YYTNAME_START 3 + + +/****************************************************************************** + * + * FUNCTION: DtParsererror + * + * PARAMETERS: Message - Parser-generated error message + * + * RETURN: None + * + * DESCRIPTION: Handler for parser errors + * + *****************************************************************************/ + +void +DtParsererror ( + char const *Message) +{ + DtError (ASL_ERROR, ASL_MSG_SYNTAX, + Gbl_CurrentField, (char *) Message); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetOpName + * + * PARAMETERS: ParseOpcode - Parser token (EXPOP_*) + * + * RETURN: Pointer to the opcode name + * + * DESCRIPTION: Get the ascii name of the parse opcode for debug output + * + *****************************************************************************/ + +char * +DtGetOpName ( + UINT32 ParseOpcode) +{ +#ifdef ASL_YYTNAME_START + /* + * First entries (PR_YYTNAME_START) in yytname are special reserved names. + * Ignore first 6 characters of name (EXPOP_) + */ + return ((char *) yytname + [(ParseOpcode - PR_FIRST_PARSE_OPCODE) + PR_YYTNAME_START] + 6); +#else + return ("[Unknown parser generator]"); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: DtEvaluateExpression + * + * PARAMETERS: ExprString - Expression to be evaluated. Must be + * terminated by either a newline or a NUL + * string terminator + * + * RETURN: 64-bit value for the expression + * + * DESCRIPTION: Main entry point for the DT expression parser + * + *****************************************************************************/ + +UINT64 +DtEvaluateExpression ( + char *ExprString) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, + "**** Input expression: %s (Base 16)\n", ExprString); + + /* Point lexer to the input string */ + + if (DtInitLexer (ExprString)) + { + DtError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, + Gbl_CurrentField, "Could not initialize lexer"); + return (0); + } + + /* Parse/Evaluate the input string (value returned in DtParserResult) */ + + DtParserparse (); + DtTerminateLexer (); + + DbgPrint (ASL_DEBUG_OUTPUT, + "**** Parser returned value: %u (%8.8X%8.8X)\n", + (UINT32) DtParserResult, ACPI_FORMAT_UINT64 (DtParserResult)); + + return (DtParserResult); +} diff --git a/third_party/lib/acpica/source/compiler/dtsubtable.c b/third_party/lib/acpica/source/compiler/dtsubtable.c new file mode 100644 index 000000000..f63082a36 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtsubtable.c @@ -0,0 +1,384 @@ +/****************************************************************************** + * + * Module Name: dtsubtable.c - handling of subtables within ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtsubtable") + + +/****************************************************************************** + * + * FUNCTION: DtCreateSubtable + * + * PARAMETERS: Buffer - Input buffer + * Length - Buffer length + * RetSubtable - Returned newly created subtable + * + * RETURN: None + * + * DESCRIPTION: Create a subtable that is not listed with ACPI_DMTABLE_INFO + * For example, FACS has 24 bytes reserved at the end + * and it's not listed at AcpiDmTableInfoFacs + * + *****************************************************************************/ + +void +DtCreateSubtable ( + UINT8 *Buffer, + UINT32 Length, + DT_SUBTABLE **RetSubtable) +{ + DT_SUBTABLE *Subtable; + char *String; + + + Subtable = UtSubtableCacheCalloc (); + + /* Create a new buffer for the subtable data */ + + String = UtStringCacheCalloc (Length); + Subtable->Buffer = ACPI_CAST_PTR (UINT8, String); + memcpy (Subtable->Buffer, Buffer, Length); + + Subtable->Length = Length; + Subtable->TotalLength = Length; + + *RetSubtable = Subtable; +} + + +/****************************************************************************** + * + * FUNCTION: DtInsertSubtable + * + * PARAMETERS: ParentTable - The Parent of the new subtable + * Subtable - The new subtable to insert + * + * RETURN: None + * + * DESCRIPTION: Insert the new subtable to the parent table + * + *****************************************************************************/ + +void +DtInsertSubtable ( + DT_SUBTABLE *ParentTable, + DT_SUBTABLE *Subtable) +{ + DT_SUBTABLE *ChildTable; + + + Subtable->Peer = NULL; + Subtable->Parent = ParentTable; + Subtable->Depth = ParentTable->Depth + 1; + + /* Link the new entry into the child list */ + + if (!ParentTable->Child) + { + ParentTable->Child = Subtable; + } + else + { + /* Walk to the end of the child list */ + + ChildTable = ParentTable->Child; + while (ChildTable->Peer) + { + ChildTable = ChildTable->Peer; + } + + /* Add new subtable at the end of the child list */ + + ChildTable->Peer = Subtable; + } +} + + +/****************************************************************************** + * + * FUNCTION: DtPushSubtable + * + * PARAMETERS: Subtable - Subtable to push + * + * RETURN: None + * + * DESCRIPTION: Push a subtable onto a subtable stack + * + *****************************************************************************/ + +void +DtPushSubtable ( + DT_SUBTABLE *Subtable) +{ + + Subtable->StackTop = Gbl_SubtableStack; + Gbl_SubtableStack = Subtable; +} + + +/****************************************************************************** + * + * FUNCTION: DtPopSubtable + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Pop a subtable from a subtable stack. Uses global SubtableStack + * + *****************************************************************************/ + +void +DtPopSubtable ( + void) +{ + DT_SUBTABLE *Subtable; + + + Subtable = Gbl_SubtableStack; + + if (Subtable) + { + Gbl_SubtableStack = Subtable->StackTop; + } +} + + +/****************************************************************************** + * + * FUNCTION: DtPeekSubtable + * + * PARAMETERS: None + * + * RETURN: The subtable on top of stack + * + * DESCRIPTION: Get the subtable on top of stack + * + *****************************************************************************/ + +DT_SUBTABLE * +DtPeekSubtable ( + void) +{ + + return (Gbl_SubtableStack); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetNextSubtable + * + * PARAMETERS: ParentTable - Parent table whose children we are + * getting + * ChildTable - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: Pointer to the NEXT child or NULL if none is found. + * + * DESCRIPTION: Return the next peer subtable within the tree. + * + *****************************************************************************/ + +DT_SUBTABLE * +DtGetNextSubtable ( + DT_SUBTABLE *ParentTable, + DT_SUBTABLE *ChildTable) +{ + ACPI_FUNCTION_ENTRY (); + + + if (!ChildTable) + { + /* It's really the parent's _scope_ that we want */ + + return (ParentTable->Child); + } + + /* Otherwise just return the next peer (NULL if at end-of-list) */ + + return (ChildTable->Peer); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetParentSubtable + * + * PARAMETERS: Subtable - Current subtable + * + * RETURN: Parent of the given subtable + * + * DESCRIPTION: Get the parent of the given subtable in the tree + * + *****************************************************************************/ + +DT_SUBTABLE * +DtGetParentSubtable ( + DT_SUBTABLE *Subtable) +{ + + if (!Subtable) + { + return (NULL); + } + + return (Subtable->Parent); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetSubtableLength + * + * PARAMETERS: Field - Current field list pointer + * Info - Data table info + * + * RETURN: Subtable length + * + * DESCRIPTION: Get length of bytes needed to compile the subtable + * + *****************************************************************************/ + +UINT32 +DtGetSubtableLength ( + DT_FIELD *Field, + ACPI_DMTABLE_INFO *Info) +{ + UINT32 ByteLength = 0; + UINT8 Step; + UINT8 i; + + + /* Walk entire Info table; Null name terminates */ + + for (; Info->Name; Info++) + { + if (Info->Opcode == ACPI_DMT_EXTRA_TEXT) + { + continue; + } + + if (!Field) + { + goto Error; + } + + ByteLength += DtGetFieldLength (Field, Info); + + switch (Info->Opcode) + { + case ACPI_DMT_GAS: + + Step = 5; + break; + + case ACPI_DMT_HESTNTFY: + + Step = 9; + break; + + case ACPI_DMT_IORTMEM: + + Step = 10; + break; + + default: + + Step = 1; + break; + } + + for (i = 0; i < Step; i++) + { + if (!Field) + { + goto Error; + } + + Field = Field->Next; + } + } + + return (ByteLength); + +Error: + if (!Field) + { + sprintf (MsgBuffer, "Found NULL field - Field name \"%s\" needed", + Info->Name); + DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); + } + + return (ASL_EOF); +} + + +/****************************************************************************** + * + * FUNCTION: DtSetSubtableLength + * + * PARAMETERS: Subtable - Subtable + * + * RETURN: None + * + * DESCRIPTION: Set length of the subtable into its length field + * + *****************************************************************************/ + +void +DtSetSubtableLength ( + DT_SUBTABLE *Subtable) +{ + + if (!Subtable->LengthField) + { + return; + } + + memcpy (Subtable->LengthField, &Subtable->TotalLength, + Subtable->SizeOfLengthField); +} diff --git a/third_party/lib/acpica/source/compiler/dttable.c b/third_party/lib/acpica/source/compiler/dttable.c new file mode 100644 index 000000000..7b33e4d23 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dttable.c @@ -0,0 +1,238 @@ +/****************************************************************************** + * + * Module Name: dttable.c - handling for specific ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* Compile routines for the basic ACPI tables */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dttable") + + +/****************************************************************************** + * + * FUNCTION: DtCompileRsdp + * + * PARAMETERS: PFieldList - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile RSDP. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileRsdp ( + DT_FIELD **PFieldList) +{ + DT_SUBTABLE *Subtable; + ACPI_TABLE_RSDP *Rsdp; + ACPI_RSDP_EXTENSION *RsdpExtension; + ACPI_STATUS Status; + + + /* Compile the "common" RSDP (ACPI 1.0) */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoRsdp1, + &Gbl_RootTable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Gbl_RootTable->Buffer); + DtSetTableChecksum (&Rsdp->Checksum); + + if (Rsdp->Revision > 0) + { + /* Compile the "extended" part of the RSDP as a subtable */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoRsdp2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (Gbl_RootTable, Subtable); + + /* Set length and extended checksum for entire RSDP */ + + RsdpExtension = ACPI_CAST_PTR (ACPI_RSDP_EXTENSION, Subtable->Buffer); + RsdpExtension->Length = Gbl_RootTable->Length + Subtable->Length; + DtSetTableChecksum (&RsdpExtension->ExtendedChecksum); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileFadt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile FADT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileFadt ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + ACPI_TABLE_HEADER *Table; + UINT8 Revision; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFadt1, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ParentTable->Buffer); + Revision = Table->Revision; + + if (Revision == 2) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFadt2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + } + else if (Revision >= 2) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFadt3, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + + if (Revision >= 5) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFadt5, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + } + + if (Revision >= 6) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFadt6, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileFacs + * + * PARAMETERS: PFieldList - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile FACS. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileFacs ( + DT_FIELD **PFieldList) +{ + DT_SUBTABLE *Subtable; + UINT8 *ReservedBuffer; + ACPI_STATUS Status; + UINT32 ReservedSize; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFacs, + &Gbl_RootTable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Large FACS reserved area at the end of the table */ + + ReservedSize = (UINT32) sizeof (((ACPI_TABLE_FACS *) NULL)->Reserved1); + ReservedBuffer = UtLocalCalloc (ReservedSize); + + DtCreateSubtable (ReservedBuffer, ReservedSize, &Subtable); + + ACPI_FREE (ReservedBuffer); + DtInsertSubtable (Gbl_RootTable, Subtable); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/dttable1.c b/third_party/lib/acpica/source/compiler/dttable1.c new file mode 100644 index 000000000..353d84af7 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dttable1.c @@ -0,0 +1,1671 @@ +/****************************************************************************** + * + * Module Name: dttable1.c - handling for specific ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* Compile all complex data tables, signatures starting with A-I */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dttable1") + + +static ACPI_DMTABLE_INFO TableInfoAsfAddress[] = +{ + {ACPI_DMT_BUFFER, 0, "Addresses", 0}, + {ACPI_DMT_EXIT, 0, NULL, 0} +}; + +static ACPI_DMTABLE_INFO TableInfoDmarPciPath[] = +{ + {ACPI_DMT_PCI_PATH, 0, "PCI Path", 0}, + {ACPI_DMT_EXIT, 0, NULL, 0} +}; + + +/****************************************************************************** + * + * FUNCTION: DtCompileAsf + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile ASF!. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileAsf ( + void **List) +{ + ACPI_ASF_INFO *AsfTable; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_DMTABLE_INFO *DataInfoTable = NULL; + UINT32 DataCount = 0; + ACPI_STATUS Status; + UINT32 i; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoAsfHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + AsfTable = ACPI_CAST_PTR (ACPI_ASF_INFO, Subtable->Buffer); + + switch (AsfTable->Header.Type & 0x7F) /* Mask off top bit */ + { + case ACPI_ASF_TYPE_INFO: + + InfoTable = AcpiDmTableInfoAsf0; + break; + + case ACPI_ASF_TYPE_ALERT: + + InfoTable = AcpiDmTableInfoAsf1; + break; + + case ACPI_ASF_TYPE_CONTROL: + + InfoTable = AcpiDmTableInfoAsf2; + break; + + case ACPI_ASF_TYPE_BOOT: + + InfoTable = AcpiDmTableInfoAsf3; + break; + + case ACPI_ASF_TYPE_ADDRESS: + + InfoTable = AcpiDmTableInfoAsf4; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "ASF!"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + switch (AsfTable->Header.Type & 0x7F) /* Mask off top bit */ + { + case ACPI_ASF_TYPE_INFO: + + DataInfoTable = NULL; + break; + + case ACPI_ASF_TYPE_ALERT: + + DataInfoTable = AcpiDmTableInfoAsf1a; + DataCount = ACPI_CAST_PTR (ACPI_ASF_ALERT, + ACPI_SUB_PTR (UINT8, Subtable->Buffer, + sizeof (ACPI_ASF_HEADER)))->Alerts; + break; + + case ACPI_ASF_TYPE_CONTROL: + + DataInfoTable = AcpiDmTableInfoAsf2a; + DataCount = ACPI_CAST_PTR (ACPI_ASF_REMOTE, + ACPI_SUB_PTR (UINT8, Subtable->Buffer, + sizeof (ACPI_ASF_HEADER)))->Controls; + break; + + case ACPI_ASF_TYPE_BOOT: + + DataInfoTable = NULL; + break; + + case ACPI_ASF_TYPE_ADDRESS: + + DataInfoTable = TableInfoAsfAddress; + DataCount = ACPI_CAST_PTR (ACPI_ASF_ADDRESS, + ACPI_SUB_PTR (UINT8, Subtable->Buffer, + sizeof (ACPI_ASF_HEADER)))->Devices; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "ASF!"); + return (AE_ERROR); + } + + if (DataInfoTable) + { + switch (AsfTable->Header.Type & 0x7F) + { + case ACPI_ASF_TYPE_ADDRESS: + + while (DataCount > 0) + { + Status = DtCompileTable (PFieldList, DataInfoTable, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + DataCount = DataCount - Subtable->Length; + } + break; + + default: + + for (i = 0; i < DataCount; i++) + { + Status = DtCompileTable (PFieldList, DataInfoTable, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + } + break; + } + } + + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileCpep + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile CPEP. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileCpep ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoCpep, AcpiDmTableInfoCpep0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileCsrt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile CSRT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileCsrt ( + void **List) +{ + ACPI_STATUS Status = AE_OK; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + UINT32 DescriptorCount; + UINT32 GroupLength; + + + /* Subtables (Resource Groups) */ + + ParentTable = DtPeekSubtable (); + while (*PFieldList) + { + /* Resource group subtable */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt0, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Compute the number of resource descriptors */ + + GroupLength = + (ACPI_CAST_PTR (ACPI_CSRT_GROUP, + Subtable->Buffer))->Length - + (ACPI_CAST_PTR (ACPI_CSRT_GROUP, + Subtable->Buffer))->SharedInfoLength - + sizeof (ACPI_CSRT_GROUP); + + DescriptorCount = (GroupLength / + sizeof (ACPI_CSRT_DESCRIPTOR)); + + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + ParentTable = DtPeekSubtable (); + + /* Shared info subtable (One per resource group) */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt1, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + + /* Sub-Subtables (Resource Descriptors) */ + + while (*PFieldList && DescriptorCount) + { + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + + DtPushSubtable (Subtable); + ParentTable = DtPeekSubtable (); + if (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt2a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + if (Subtable) + { + DtInsertSubtable (ParentTable, Subtable); + } + } + + DtPopSubtable (); + ParentTable = DtPeekSubtable (); + DescriptorCount--; + } + + DtPopSubtable (); + ParentTable = DtPeekSubtable (); + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileDbg2 + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile DBG2. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileDbg2 ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + UINT32 SubtableCount; + ACPI_DBG2_HEADER *Dbg2Header; + ACPI_DBG2_DEVICE *DeviceInfo; + UINT16 CurrentOffset; + UINT32 i; + + + /* Main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* Main table fields */ + + Dbg2Header = ACPI_CAST_PTR (ACPI_DBG2_HEADER, Subtable->Buffer); + Dbg2Header->InfoOffset = sizeof (ACPI_TABLE_HEADER) + ACPI_PTR_DIFF ( + ACPI_ADD_PTR (UINT8, Dbg2Header, sizeof (ACPI_DBG2_HEADER)), Dbg2Header); + + SubtableCount = Dbg2Header->InfoCount; + DtPushSubtable (Subtable); + + /* Process all Device Information subtables (Count = InfoCount) */ + + while (*PFieldList && SubtableCount) + { + /* Subtable: Debug Device Information */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Device, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DeviceInfo = ACPI_CAST_PTR (ACPI_DBG2_DEVICE, Subtable->Buffer); + CurrentOffset = (UINT16) sizeof (ACPI_DBG2_DEVICE); + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + ParentTable = DtPeekSubtable (); + + /* BaseAddressRegister GAS array (Required, size is RegisterCount) */ + + DeviceInfo->BaseAddressOffset = CurrentOffset; + for (i = 0; *PFieldList && (i < DeviceInfo->RegisterCount); i++) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Addr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + CurrentOffset += (UINT16) sizeof (ACPI_GENERIC_ADDRESS); + DtInsertSubtable (ParentTable, Subtable); + } + + /* AddressSize array (Required, size = RegisterCount) */ + + DeviceInfo->AddressSizeOffset = CurrentOffset; + for (i = 0; *PFieldList && (i < DeviceInfo->RegisterCount); i++) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Size, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + CurrentOffset += (UINT16) sizeof (UINT32); + DtInsertSubtable (ParentTable, Subtable); + } + + /* NamespaceString device identifier (Required, size = NamePathLength) */ + + DeviceInfo->NamepathOffset = CurrentOffset; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Name, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Update the device info header */ + + DeviceInfo->NamepathLength = (UINT16) Subtable->Length; + CurrentOffset += (UINT16) DeviceInfo->NamepathLength; + DtInsertSubtable (ParentTable, Subtable); + + /* OemData - Variable-length data (Optional, size = OemDataLength) */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2OemData, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Update the device info header (zeros if no OEM data present) */ + + DeviceInfo->OemDataOffset = 0; + DeviceInfo->OemDataLength = 0; + + /* Optional subtable (OemData) */ + + if (Subtable && Subtable->Length) + { + DeviceInfo->OemDataOffset = CurrentOffset; + DeviceInfo->OemDataLength = (UINT16) Subtable->Length; + + DtInsertSubtable (ParentTable, Subtable); + } + + SubtableCount--; + DtPopSubtable (); /* Get next Device Information subtable */ + } + + DtPopSubtable (); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileDmar + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile DMAR. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileDmar ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_DMAR_HEADER *DmarHeader; + ACPI_DMAR_DEVICE_SCOPE *DmarDeviceScope; + UINT32 DeviceScopeLength; + UINT32 PciPathLength; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDmar, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + while (*PFieldList) + { + /* DMAR Header */ + + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDmarHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + DmarHeader = ACPI_CAST_PTR (ACPI_DMAR_HEADER, Subtable->Buffer); + + switch (DmarHeader->Type) + { + case ACPI_DMAR_TYPE_HARDWARE_UNIT: + + InfoTable = AcpiDmTableInfoDmar0; + break; + + case ACPI_DMAR_TYPE_RESERVED_MEMORY: + + InfoTable = AcpiDmTableInfoDmar1; + break; + + case ACPI_DMAR_TYPE_ROOT_ATS: + + InfoTable = AcpiDmTableInfoDmar2; + break; + + case ACPI_DMAR_TYPE_HARDWARE_AFFINITY: + + InfoTable = AcpiDmTableInfoDmar3; + break; + + case ACPI_DMAR_TYPE_NAMESPACE: + + InfoTable = AcpiDmTableInfoDmar4; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "DMAR"); + return (AE_ERROR); + } + + /* DMAR Subtable */ + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* + * Optional Device Scope subtables + */ + if ((DmarHeader->Type == ACPI_DMAR_TYPE_HARDWARE_AFFINITY) || + (DmarHeader->Type == ACPI_DMAR_TYPE_NAMESPACE)) + { + /* These types do not support device scopes */ + + DtPopSubtable (); + continue; + } + + DtPushSubtable (Subtable); + DeviceScopeLength = DmarHeader->Length - Subtable->Length - + ParentTable->Length; + while (DeviceScopeLength) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDmarScope, + &Subtable, FALSE); + if (Status == AE_NOT_FOUND) + { + break; + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + DmarDeviceScope = ACPI_CAST_PTR (ACPI_DMAR_DEVICE_SCOPE, Subtable->Buffer); + + /* Optional PCI Paths */ + + PciPathLength = DmarDeviceScope->Length - Subtable->Length; + while (PciPathLength) + { + Status = DtCompileTable (PFieldList, TableInfoDmarPciPath, + &Subtable, FALSE); + if (Status == AE_NOT_FOUND) + { + DtPopSubtable (); + break; + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + PciPathLength -= Subtable->Length; + } + + DtPopSubtable (); + DeviceScopeLength -= DmarDeviceScope->Length; + } + + DtPopSubtable (); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileDrtm + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile DRTM. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileDrtm ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + UINT32 Count; + /* ACPI_TABLE_DRTM *Drtm; */ + ACPI_DRTM_VTABLE_LIST *DrtmVtl; + ACPI_DRTM_RESOURCE_LIST *DrtmRl; + /* ACPI_DRTM_DPS_ID *DrtmDps; */ + + + ParentTable = DtPeekSubtable (); + + /* Compile DRTM header */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + DtInsertSubtable (ParentTable, Subtable); + + /* + * Using ACPI_SUB_PTR, We needn't define a seperate structure. Care + * should be taken to avoid accessing ACPI_TABLE_HADER fields. + */ +#if 0 + Drtm = ACPI_SUB_PTR (ACPI_TABLE_DRTM, + Subtable->Buffer, sizeof (ACPI_TABLE_HEADER)); +#endif + /* Compile VTL */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm0, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + DrtmVtl = ACPI_CAST_PTR (ACPI_DRTM_VTABLE_LIST, Subtable->Buffer); + + DtPushSubtable (Subtable); + ParentTable = DtPeekSubtable (); + Count = 0; + + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm0a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + if (!Subtable) + { + break; + } + DtInsertSubtable (ParentTable, Subtable); + Count++; + } + + DrtmVtl->ValidatedTableCount = Count; + DtPopSubtable (); + ParentTable = DtPeekSubtable (); + + /* Compile RL */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm1, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + DrtmRl = ACPI_CAST_PTR (ACPI_DRTM_RESOURCE_LIST, Subtable->Buffer); + + DtPushSubtable (Subtable); + ParentTable = DtPeekSubtable (); + Count = 0; + + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm1a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Subtable) + { + break; + } + + DtInsertSubtable (ParentTable, Subtable); + Count++; + } + + DrtmRl->ResourceCount = Count; + DtPopSubtable (); + ParentTable = DtPeekSubtable (); + + /* Compile DPS */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + DtInsertSubtable (ParentTable, Subtable); + /* DrtmDps = ACPI_CAST_PTR (ACPI_DRTM_DPS_ID, Subtable->Buffer);*/ + + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileEinj + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile EINJ. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileEinj ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoEinj, AcpiDmTableInfoEinj0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileErst + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile ERST. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileErst ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoErst, AcpiDmTableInfoEinj0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileGtdt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile GTDT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileGtdt ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_SUBTABLE_HEADER *GtdtHeader; + ACPI_DMTABLE_INFO *InfoTable; + UINT32 GtCount; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdt, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdtHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + GtdtHeader = ACPI_CAST_PTR (ACPI_SUBTABLE_HEADER, Subtable->Buffer); + + switch (GtdtHeader->Type) + { + case ACPI_GTDT_TYPE_TIMER_BLOCK: + + InfoTable = AcpiDmTableInfoGtdt0; + break; + + case ACPI_GTDT_TYPE_WATCHDOG: + + InfoTable = AcpiDmTableInfoGtdt1; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "GTDT"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* + * Additional GT block subtable data + */ + + switch (GtdtHeader->Type) + { + case ACPI_GTDT_TYPE_TIMER_BLOCK: + + DtPushSubtable (Subtable); + ParentTable = DtPeekSubtable (); + + GtCount = (ACPI_CAST_PTR (ACPI_GTDT_TIMER_BLOCK, + Subtable->Buffer - sizeof(ACPI_GTDT_HEADER)))->TimerCount; + + while (GtCount) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdt0a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + GtCount--; + } + + DtPopSubtable (); + break; + + default: + + break; + } + + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileFpdt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile FPDT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileFpdt ( + void **List) +{ + ACPI_STATUS Status; + ACPI_FPDT_HEADER *FpdtHeader; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + ACPI_DMTABLE_INFO *InfoTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoFpdtHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + FpdtHeader = ACPI_CAST_PTR (ACPI_FPDT_HEADER, Subtable->Buffer); + + switch (FpdtHeader->Type) + { + case ACPI_FPDT_TYPE_BOOT: + + InfoTable = AcpiDmTableInfoFpdt0; + break; + + case ACPI_FPDT_TYPE_S3PERF: + + InfoTable = AcpiDmTableInfoFpdt1; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "FPDT"); + return (AE_ERROR); + break; + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileHest + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile HEST. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileHest ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_DMTABLE_INFO *InfoTable; + UINT16 Type; + UINT32 BankCount; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoHest, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + while (*PFieldList) + { + /* Get subtable type */ + + SubtableStart = *PFieldList; + DtCompileInteger ((UINT8 *) &Type, *PFieldList, 2, 0); + + switch (Type) + { + case ACPI_HEST_TYPE_IA32_CHECK: + + InfoTable = AcpiDmTableInfoHest0; + break; + + case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: + + InfoTable = AcpiDmTableInfoHest1; + break; + + case ACPI_HEST_TYPE_IA32_NMI: + + InfoTable = AcpiDmTableInfoHest2; + break; + + case ACPI_HEST_TYPE_AER_ROOT_PORT: + + InfoTable = AcpiDmTableInfoHest6; + break; + + case ACPI_HEST_TYPE_AER_ENDPOINT: + + InfoTable = AcpiDmTableInfoHest7; + break; + + case ACPI_HEST_TYPE_AER_BRIDGE: + + InfoTable = AcpiDmTableInfoHest8; + break; + + case ACPI_HEST_TYPE_GENERIC_ERROR: + + InfoTable = AcpiDmTableInfoHest9; + break; + + default: + + /* Cannot continue on unknown type */ + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "HEST"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + + /* + * Additional subtable data - IA32 Error Bank(s) + */ + BankCount = 0; + switch (Type) + { + case ACPI_HEST_TYPE_IA32_CHECK: + + BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_MACHINE_CHECK, + Subtable->Buffer))->NumHardwareBanks; + break; + + case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: + + BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_CORRECTED, + Subtable->Buffer))->NumHardwareBanks; + break; + + default: + + break; + } + + while (BankCount) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoHestBank, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + BankCount--; + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileIort + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile IORT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileIort ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_TABLE_IORT *Iort; + ACPI_IORT_NODE *IortNode; + ACPI_IORT_ITS_GROUP *IortItsGroup; + ACPI_IORT_SMMU *IortSmmu; + UINT32 NodeNumber; + UINT32 NodeLength; + UINT32 IdMappingNumber; + UINT32 ItsNumber; + UINT32 ContextIrptNumber; + UINT32 PmuIrptNumber; + UINT32 PaddingLength; + + + ParentTable = DtPeekSubtable (); + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + DtInsertSubtable (ParentTable, Subtable); + + /* + * Using ACPI_SUB_PTR, We needn't define a seperate structure. Care + * should be taken to avoid accessing ACPI_TABLE_HADER fields. + */ + Iort = ACPI_SUB_PTR (ACPI_TABLE_IORT, + Subtable->Buffer, sizeof (ACPI_TABLE_HEADER)); + + /* + * OptionalPadding - Variable-length data + * (Optional, size = OffsetToNodes - sizeof (ACPI_TABLE_IORT)) + * Optionally allows the generic data types to be used for filling + * this field. + */ + Iort->NodeOffset = sizeof (ACPI_TABLE_IORT); + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortPad, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + if (Subtable) + { + DtInsertSubtable (ParentTable, Subtable); + Iort->NodeOffset += Subtable->Length; + } + else + { + Status = DtCompileGeneric (ACPI_CAST_PTR (void *, PFieldList), + AcpiDmTableInfoIortHdr[0].Name, &PaddingLength); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + Iort->NodeOffset += PaddingLength; + } + + NodeNumber = 0; + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + IortNode = ACPI_CAST_PTR (ACPI_IORT_NODE, Subtable->Buffer); + NodeLength = ACPI_OFFSET (ACPI_IORT_NODE, NodeData); + + DtPushSubtable (Subtable); + ParentTable = DtPeekSubtable (); + + switch (IortNode->Type) + { + case ACPI_IORT_NODE_ITS_GROUP: + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort0, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + IortItsGroup = ACPI_CAST_PTR (ACPI_IORT_ITS_GROUP, Subtable->Buffer); + NodeLength += Subtable->Length; + + ItsNumber = 0; + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort0a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + if (!Subtable) + { + break; + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + ItsNumber++; + } + + IortItsGroup->ItsCount = ItsNumber; + break; + + case ACPI_IORT_NODE_NAMED_COMPONENT: + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort1, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + + /* + * Padding - Variable-length data + * Optionally allows the offset of the ID mappings to be used + * for filling this field. + */ + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort1a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Subtable) + { + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + } + else + { + if (NodeLength > IortNode->MappingOffset) + { + return (AE_BAD_DATA); + } + + if (NodeLength < IortNode->MappingOffset) + { + Status = DtCompilePadding ( + IortNode->MappingOffset - NodeLength, + &Subtable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength = IortNode->MappingOffset; + } + } + break; + + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX: + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + break; + + case ACPI_IORT_NODE_SMMU: + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + IortSmmu = ACPI_CAST_PTR (ACPI_IORT_SMMU, Subtable->Buffer); + NodeLength += Subtable->Length; + + /* Compile global interrupt array */ + + IortSmmu->GlobalInterruptOffset = NodeLength; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + + /* Compile context interrupt array */ + + ContextIrptNumber = 0; + IortSmmu->ContextInterruptOffset = NodeLength; + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3b, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Subtable) + { + break; + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + ContextIrptNumber++; + } + + IortSmmu->ContextInterruptCount = ContextIrptNumber; + + /* Compile PMU interrupt array */ + + PmuIrptNumber = 0; + IortSmmu->PmuInterruptOffset = NodeLength; + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3c, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Subtable) + { + break; + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += Subtable->Length; + PmuIrptNumber++; + } + + IortSmmu->PmuInterruptCount = PmuIrptNumber; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "IORT"); + return (AE_ERROR); + } + + /* Compile Array of ID mappings */ + + IortNode->MappingOffset = NodeLength; + IdMappingNumber = 0; + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortMap, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Subtable) + { + break; + } + + DtInsertSubtable (ParentTable, Subtable); + NodeLength += sizeof (ACPI_IORT_ID_MAPPING); + IdMappingNumber++; + } + + IortNode->MappingCount = IdMappingNumber; + + /* + * Node length can be determined by DT_LENGTH option + * IortNode->Length = NodeLength; + */ + DtPopSubtable (); + ParentTable = DtPeekSubtable (); + NodeNumber++; + } + + Iort->NodeCount = NodeNumber; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileIvrs + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile IVRS. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileIvrs ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_IVRS_HEADER *IvrsHeader; + UINT8 EntryType; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrs, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + IvrsHeader = ACPI_CAST_PTR (ACPI_IVRS_HEADER, Subtable->Buffer); + + switch (IvrsHeader->Type) + { + case ACPI_IVRS_TYPE_HARDWARE: + + InfoTable = AcpiDmTableInfoIvrs0; + break; + + case ACPI_IVRS_TYPE_MEMORY1: + case ACPI_IVRS_TYPE_MEMORY2: + case ACPI_IVRS_TYPE_MEMORY3: + + InfoTable = AcpiDmTableInfoIvrs1; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "IVRS"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + if (IvrsHeader->Type == ACPI_IVRS_TYPE_HARDWARE) + { + while (*PFieldList && + !strcmp ((*PFieldList)->Name, "Entry Type")) + { + SubtableStart = *PFieldList; + DtCompileInteger (&EntryType, *PFieldList, 1, 0); + + switch (EntryType) + { + /* 4-byte device entries */ + + case ACPI_IVRS_TYPE_PAD4: + case ACPI_IVRS_TYPE_ALL: + case ACPI_IVRS_TYPE_SELECT: + case ACPI_IVRS_TYPE_START: + case ACPI_IVRS_TYPE_END: + + InfoTable = AcpiDmTableInfoIvrs4; + break; + + /* 8-byte entries, type A */ + + case ACPI_IVRS_TYPE_ALIAS_SELECT: + case ACPI_IVRS_TYPE_ALIAS_START: + + InfoTable = AcpiDmTableInfoIvrs8a; + break; + + /* 8-byte entries, type B */ + + case ACPI_IVRS_TYPE_PAD8: + case ACPI_IVRS_TYPE_EXT_SELECT: + case ACPI_IVRS_TYPE_EXT_START: + + InfoTable = AcpiDmTableInfoIvrs8b; + break; + + /* 8-byte entries, type C */ + + case ACPI_IVRS_TYPE_SPECIAL: + + InfoTable = AcpiDmTableInfoIvrs8c; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, + "IVRS Device Entry"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + } + } + + DtPopSubtable (); + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/dttable2.c b/third_party/lib/acpica/source/compiler/dttable2.c new file mode 100644 index 000000000..9ebe3e59a --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dttable2.c @@ -0,0 +1,1686 @@ +/****************************************************************************** + * + * Module Name: dttable2.c - handling for specific ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* Compile all complex data tables, signatures starting with L-Z */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dttable2") + + +/****************************************************************************** + * + * FUNCTION: DtCompileLpit + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile LPIT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileLpit ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_DMTABLE_INFO *InfoTable; + ACPI_LPIT_HEADER *LpitHeader; + + + /* Note: Main table consists only of the standard ACPI table header */ + + while (*PFieldList) + { + SubtableStart = *PFieldList; + + /* LPIT Subtable header */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoLpitHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + LpitHeader = ACPI_CAST_PTR (ACPI_LPIT_HEADER, Subtable->Buffer); + + switch (LpitHeader->Type) + { + case ACPI_LPIT_TYPE_NATIVE_CSTATE: + + InfoTable = AcpiDmTableInfoLpit0; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "LPIT"); + return (AE_ERROR); + } + + /* LPIT Subtable */ + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileMadt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile MADT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileMadt ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_SUBTABLE_HEADER *MadtHeader; + ACPI_DMTABLE_INFO *InfoTable; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMadt, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMadtHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + MadtHeader = ACPI_CAST_PTR (ACPI_SUBTABLE_HEADER, Subtable->Buffer); + + switch (MadtHeader->Type) + { + case ACPI_MADT_TYPE_LOCAL_APIC: + + InfoTable = AcpiDmTableInfoMadt0; + break; + + case ACPI_MADT_TYPE_IO_APIC: + + InfoTable = AcpiDmTableInfoMadt1; + break; + + case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: + + InfoTable = AcpiDmTableInfoMadt2; + break; + + case ACPI_MADT_TYPE_NMI_SOURCE: + + InfoTable = AcpiDmTableInfoMadt3; + break; + + case ACPI_MADT_TYPE_LOCAL_APIC_NMI: + + InfoTable = AcpiDmTableInfoMadt4; + break; + + case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: + + InfoTable = AcpiDmTableInfoMadt5; + break; + + case ACPI_MADT_TYPE_IO_SAPIC: + + InfoTable = AcpiDmTableInfoMadt6; + break; + + case ACPI_MADT_TYPE_LOCAL_SAPIC: + + InfoTable = AcpiDmTableInfoMadt7; + break; + + case ACPI_MADT_TYPE_INTERRUPT_SOURCE: + + InfoTable = AcpiDmTableInfoMadt8; + break; + + case ACPI_MADT_TYPE_LOCAL_X2APIC: + + InfoTable = AcpiDmTableInfoMadt9; + break; + + case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: + + InfoTable = AcpiDmTableInfoMadt10; + break; + + case ACPI_MADT_TYPE_GENERIC_INTERRUPT: + + InfoTable = AcpiDmTableInfoMadt11; + break; + + case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: + + InfoTable = AcpiDmTableInfoMadt12; + break; + + case ACPI_MADT_TYPE_GENERIC_MSI_FRAME: + + InfoTable = AcpiDmTableInfoMadt13; + break; + + case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: + + InfoTable = AcpiDmTableInfoMadt14; + break; + + case ACPI_MADT_TYPE_GENERIC_TRANSLATOR: + + InfoTable = AcpiDmTableInfoMadt15; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "MADT"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileMcfg + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile MCFG. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileMcfg ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoMcfg, AcpiDmTableInfoMcfg0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileMpst + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile MPST. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileMpst ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + ACPI_MPST_CHANNEL *MpstChannelInfo; + ACPI_MPST_POWER_NODE *MpstPowerNode; + ACPI_MPST_DATA_HDR *MpstDataHeader; + UINT16 SubtableCount; + UINT32 PowerStateCount; + UINT32 ComponentCount; + + + /* Main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMpst, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + MpstChannelInfo = ACPI_CAST_PTR (ACPI_MPST_CHANNEL, Subtable->Buffer); + SubtableCount = MpstChannelInfo->PowerNodeCount; + + while (*PFieldList && SubtableCount) + { + /* Subtable: Memory Power Node(s) */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMpst0, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + MpstPowerNode = ACPI_CAST_PTR (ACPI_MPST_POWER_NODE, Subtable->Buffer); + PowerStateCount = MpstPowerNode->NumPowerStates; + ComponentCount = MpstPowerNode->NumPhysicalComponents; + + ParentTable = DtPeekSubtable (); + + /* Sub-subtables - Memory Power State Structure(s) */ + + while (*PFieldList && PowerStateCount) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMpst0A, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + PowerStateCount--; + } + + /* Sub-subtables - Physical Component ID Structure(s) */ + + while (*PFieldList && ComponentCount) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMpst0B, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + ComponentCount--; + } + + SubtableCount--; + DtPopSubtable (); + } + + /* Subtable: Count of Memory Power State Characteristic structures */ + + DtPopSubtable (); + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMpst1, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + MpstDataHeader = ACPI_CAST_PTR (ACPI_MPST_DATA_HDR, Subtable->Buffer); + SubtableCount = MpstDataHeader->CharacteristicsCount; + + ParentTable = DtPeekSubtable (); + + /* Subtable: Memory Power State Characteristics structure(s) */ + + while (*PFieldList && SubtableCount) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoMpst2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + SubtableCount--; + } + + DtPopSubtable (); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileMsct + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile MSCT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileMsct ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoMsct, AcpiDmTableInfoMsct0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileMtmr + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile MTMR. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileMtmr ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoMtmr, AcpiDmTableInfoMtmr0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileNfit + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile NFIT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileNfit ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_NFIT_HEADER *NfitHeader; + ACPI_DMTABLE_INFO *InfoTable; + UINT32 Count; + ACPI_NFIT_INTERLEAVE *Interleave = NULL; + ACPI_NFIT_FLUSH_ADDRESS *Hint = NULL; + + + /* Main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoNfit, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + /* Subtables */ + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoNfitHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + NfitHeader = ACPI_CAST_PTR (ACPI_NFIT_HEADER, Subtable->Buffer); + + switch (NfitHeader->Type) + { + case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: + + InfoTable = AcpiDmTableInfoNfit0; + break; + + case ACPI_NFIT_TYPE_MEMORY_MAP: + + InfoTable = AcpiDmTableInfoNfit1; + break; + + case ACPI_NFIT_TYPE_INTERLEAVE: + + Interleave = ACPI_CAST_PTR (ACPI_NFIT_INTERLEAVE, Subtable->Buffer); + InfoTable = AcpiDmTableInfoNfit2; + break; + + case ACPI_NFIT_TYPE_SMBIOS: + + InfoTable = AcpiDmTableInfoNfit3; + break; + + case ACPI_NFIT_TYPE_CONTROL_REGION: + + InfoTable = AcpiDmTableInfoNfit4; + break; + + case ACPI_NFIT_TYPE_DATA_REGION: + + InfoTable = AcpiDmTableInfoNfit5; + break; + + case ACPI_NFIT_TYPE_FLUSH_ADDRESS: + + Hint = ACPI_CAST_PTR (ACPI_NFIT_FLUSH_ADDRESS, Subtable->Buffer); + InfoTable = AcpiDmTableInfoNfit6; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "NFIT"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + + switch (NfitHeader->Type) + { + case ACPI_NFIT_TYPE_INTERLEAVE: + + Count = 0; + DtPushSubtable (Subtable); + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoNfit2a, + &Subtable, FALSE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Subtable) + { + DtPopSubtable (); + break; + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + Count++; + } + + Interleave->LineCount = Count; + DtPopSubtable (); + break; + + case ACPI_NFIT_TYPE_SMBIOS: + + if (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoNfit3a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Subtable) + { + DtInsertSubtable (ParentTable, Subtable); + } + } + break; + + case ACPI_NFIT_TYPE_FLUSH_ADDRESS: + + Count = 0; + DtPushSubtable (Subtable); + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoNfit6a, + &Subtable, FALSE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Subtable) + { + DtPopSubtable (); + break; + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + Count++; + } + + Hint->HintCount = (UINT16) Count; + DtPopSubtable (); + break; + + default: + break; + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompilePcct + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile PCCT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompilePcct ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_SUBTABLE_HEADER *PcctHeader; + ACPI_DMTABLE_INFO *InfoTable; + + + /* Main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPcct, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* Subtables */ + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPcctHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + PcctHeader = ACPI_CAST_PTR (ACPI_SUBTABLE_HEADER, Subtable->Buffer); + + switch (PcctHeader->Type) + { + case ACPI_PCCT_TYPE_GENERIC_SUBSPACE: + + InfoTable = AcpiDmTableInfoPcct0; + break; + + case ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE: + + InfoTable = AcpiDmTableInfoPcct1; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "PCCT"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompilePmtt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile PMTT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompilePmtt ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_PMTT_HEADER *PmttHeader; + ACPI_PMTT_CONTROLLER *PmttController; + UINT16 DomainCount; + UINT8 PrevType = ACPI_PMTT_TYPE_SOCKET; + + + /* Main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPmtt, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPmttHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + PmttHeader = ACPI_CAST_PTR (ACPI_PMTT_HEADER, Subtable->Buffer); + while (PrevType >= PmttHeader->Type) + { + DtPopSubtable (); + + if (PrevType == ACPI_PMTT_TYPE_SOCKET) + { + break; + } + + PrevType--; + } + + PrevType = PmttHeader->Type; + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + switch (PmttHeader->Type) + { + case ACPI_PMTT_TYPE_SOCKET: + + /* Subtable: Socket Structure */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPmtt0, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + break; + + case ACPI_PMTT_TYPE_CONTROLLER: + + /* Subtable: Memory Controller Structure */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPmtt1, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + PmttController = ACPI_CAST_PTR (ACPI_PMTT_CONTROLLER, + (Subtable->Buffer - sizeof (ACPI_PMTT_HEADER))); + DomainCount = PmttController->DomainCount; + + while (DomainCount) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPmtt1a, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtInsertSubtable (ParentTable, Subtable); + DomainCount--; + } + break; + + case ACPI_PMTT_TYPE_DIMM: + + /* Subtable: Physical Component Structure */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoPmtt2, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "PMTT"); + return (AE_ERROR); + } + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileRsdt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile RSDT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileRsdt ( + void **List) +{ + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD *FieldList = *(DT_FIELD **) List; + UINT32 Address; + + + ParentTable = DtPeekSubtable (); + + while (FieldList) + { + DtCompileInteger ((UINT8 *) &Address, FieldList, 4, DT_NON_ZERO); + + DtCreateSubtable ((UINT8 *) &Address, 4, &Subtable); + DtInsertSubtable (ParentTable, Subtable); + FieldList = FieldList->Next; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileS3pt + * + * PARAMETERS: PFieldList - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile S3PT (Pointed to by FPDT) + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileS3pt ( + DT_FIELD **PFieldList) +{ + ACPI_STATUS Status; + ACPI_S3PT_HEADER *S3ptHeader; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + ACPI_DMTABLE_INFO *InfoTable; + DT_FIELD *SubtableStart; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoS3pt, + &Gbl_RootTable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DtPushSubtable (Gbl_RootTable); + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoS3ptHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + S3ptHeader = ACPI_CAST_PTR (ACPI_S3PT_HEADER, Subtable->Buffer); + + switch (S3ptHeader->Type) + { + case ACPI_S3PT_TYPE_RESUME: + + InfoTable = AcpiDmTableInfoS3pt0; + break; + + case ACPI_S3PT_TYPE_SUSPEND: + + InfoTable = AcpiDmTableInfoS3pt1; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "S3PT"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileSlic + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile SLIC. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileSlic ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + + + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoSlic, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileSlit + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile SLIT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileSlit ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *FieldList; + UINT32 Localities; + UINT8 *LocalityBuffer; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoSlit, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + Localities = *ACPI_CAST_PTR (UINT32, Subtable->Buffer); + LocalityBuffer = UtLocalCalloc (Localities); + + /* Compile each locality buffer */ + + FieldList = *PFieldList; + while (FieldList) + { + DtCompileBuffer (LocalityBuffer, + FieldList->Value, FieldList, Localities); + + DtCreateSubtable (LocalityBuffer, Localities, &Subtable); + DtInsertSubtable (ParentTable, Subtable); + FieldList = FieldList->Next; + } + + ACPI_FREE (LocalityBuffer); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileSrat + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile SRAT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileSrat ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_FIELD *SubtableStart; + ACPI_SUBTABLE_HEADER *SratHeader; + ACPI_DMTABLE_INFO *InfoTable; + + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoSrat, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + while (*PFieldList) + { + SubtableStart = *PFieldList; + Status = DtCompileTable (PFieldList, AcpiDmTableInfoSratHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPushSubtable (Subtable); + + SratHeader = ACPI_CAST_PTR (ACPI_SUBTABLE_HEADER, Subtable->Buffer); + + switch (SratHeader->Type) + { + case ACPI_SRAT_TYPE_CPU_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat0; + break; + + case ACPI_SRAT_TYPE_MEMORY_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat1; + break; + + case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat2; + break; + + case ACPI_SRAT_TYPE_GICC_AFFINITY: + + InfoTable = AcpiDmTableInfoSrat3; + break; + + default: + + DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "SRAT"); + return (AE_ERROR); + } + + Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + DtPopSubtable (); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileStao + * + * PARAMETERS: PFieldList - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile STAO. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileStao ( + void **List) +{ + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + ACPI_STATUS Status; + + + /* Compile the main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoStao, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* Compile each ASCII namestring as a subtable */ + + while (*PFieldList) + { + Status = DtCompileTable (PFieldList, AcpiDmTableInfoStaoStr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileTcpa + * + * PARAMETERS: PFieldList - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile TCPA. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileTcpa ( + void **List) +{ + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_SUBTABLE *Subtable; + ACPI_TABLE_TCPA_HDR *TcpaHeader; + DT_SUBTABLE *ParentTable; + ACPI_STATUS Status; + + + /* Compile the main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoTcpaHdr, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* + * Examine the PlatformClass field to determine the table type. + * Either a client or server table. Only one. + */ + TcpaHeader = ACPI_CAST_PTR (ACPI_TABLE_TCPA_HDR, ParentTable->Buffer); + + switch (TcpaHeader->PlatformClass) + { + case ACPI_TCPA_CLIENT_TABLE: + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoTcpaClient, + &Subtable, TRUE); + break; + + case ACPI_TCPA_SERVER_TABLE: + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoTcpaServer, + &Subtable, TRUE); + break; + + default: + + AcpiOsPrintf ("\n**** Unknown TCPA Platform Class 0x%X\n", + TcpaHeader->PlatformClass); + Status = AE_ERROR; + break; + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetGenericTableInfo + * + * PARAMETERS: Name - Generic type name + * + * RETURN: Info entry + * + * DESCRIPTION: Obtain table info for a generic name entry + * + *****************************************************************************/ + +ACPI_DMTABLE_INFO * +DtGetGenericTableInfo ( + char *Name) +{ + ACPI_DMTABLE_INFO *Info; + UINT32 i; + + + if (!Name) + { + return (NULL); + } + + /* Search info table for name match */ + + for (i = 0; ; i++) + { + Info = AcpiDmTableInfoGeneric[i]; + if (Info->Opcode == ACPI_DMT_EXIT) + { + Info = NULL; + break; + } + + /* Use caseless compare for generic keywords */ + + if (!AcpiUtStricmp (Name, Info->Name)) + { + break; + } + } + + return (Info); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileUefi + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile UEFI. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileUefi ( + void **List) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + UINT16 *DataOffset; + + + /* Compile the predefined portion of the UEFI table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoUefi, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + DataOffset = (UINT16 *) (Subtable->Buffer + 16); + *DataOffset = sizeof (ACPI_TABLE_UEFI); + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* + * Compile the "generic" portion of the UEFI table. This + * part of the table is not predefined and any of the generic + * operators may be used. + */ + DtCompileGeneric ((void **) PFieldList, NULL, NULL); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileVrtc + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile VRTC. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileVrtc ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoVrtc, AcpiDmTableInfoVrtc0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileWdat + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile WDAT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileWdat ( + void **List) +{ + ACPI_STATUS Status; + + + Status = DtCompileTwoSubtables (List, + AcpiDmTableInfoWdat, AcpiDmTableInfoWdat0); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileWpbt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile WPBT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileWpbt ( + void **List) +{ + DT_FIELD **PFieldList = (DT_FIELD **) List; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + ACPI_TABLE_WPBT *Table; + ACPI_STATUS Status; + UINT16 Length; + + + /* Compile the main table */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoWpbt, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + + /* Compile the argument list subtable */ + + Status = DtCompileTable (PFieldList, AcpiDmTableInfoWpbt0, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Extract the length of the Arguments buffer, insert into main table */ + + Length = (UINT16) Subtable->TotalLength; + Table = ACPI_CAST_PTR (ACPI_TABLE_WPBT, ParentTable->Buffer); + Table->ArgumentsLength = Length; + + ParentTable = DtPeekSubtable (); + DtInsertSubtable (ParentTable, Subtable); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileXsdt + * + * PARAMETERS: List - Current field list pointer + * + * RETURN: Status + * + * DESCRIPTION: Compile XSDT. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileXsdt ( + void **List) +{ + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD *FieldList = *(DT_FIELD **) List; + UINT64 Address; + + + ParentTable = DtPeekSubtable (); + + while (FieldList) + { + DtCompileInteger ((UINT8 *) &Address, FieldList, 8, DT_NON_ZERO); + + DtCreateSubtable ((UINT8 *) &Address, 8, &Subtable); + DtInsertSubtable (ParentTable, Subtable); + FieldList = FieldList->Next; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtCompileGeneric + * + * PARAMETERS: List - Current field list pointer + * Name - Field name to end generic compiling + * Length - Compiled table length to return + * + * RETURN: Status + * + * DESCRIPTION: Compile generic unknown table. + * + *****************************************************************************/ + +ACPI_STATUS +DtCompileGeneric ( + void **List, + char *Name, + UINT32 *Length) +{ + ACPI_STATUS Status; + DT_SUBTABLE *Subtable; + DT_SUBTABLE *ParentTable; + DT_FIELD **PFieldList = (DT_FIELD **) List; + ACPI_DMTABLE_INFO *Info; + + + ParentTable = DtPeekSubtable (); + + /* + * Compile the "generic" portion of the table. This + * part of the table is not predefined and any of the generic + * operators may be used. + */ + + /* Find any and all labels in the entire generic portion */ + + DtDetectAllLabels (*PFieldList); + + /* Now we can actually compile the parse tree */ + + if (Length && *Length) + { + *Length = 0; + } + while (*PFieldList) + { + if (Name && !strcmp ((*PFieldList)->Name, Name)) + { + break; + } + + Info = DtGetGenericTableInfo ((*PFieldList)->Name); + if (!Info) + { + sprintf (MsgBuffer, "Generic data type \"%s\" not found", + (*PFieldList)->Name); + DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME, + (*PFieldList), MsgBuffer); + + *PFieldList = (*PFieldList)->Next; + continue; + } + + Status = DtCompileTable (PFieldList, Info, + &Subtable, TRUE); + if (ACPI_SUCCESS (Status)) + { + DtInsertSubtable (ParentTable, Subtable); + if (Length) + { + *Length += Subtable->Length; + } + } + else + { + *PFieldList = (*PFieldList)->Next; + + if (Status == AE_NOT_FOUND) + { + sprintf (MsgBuffer, "Generic data type \"%s\" not found", + (*PFieldList)->Name); + DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME, + (*PFieldList), MsgBuffer); + } + } + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/compiler/dttemplate.c b/third_party/lib/acpica/source/compiler/dttemplate.c new file mode 100644 index 000000000..0d286c0e1 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dttemplate.c @@ -0,0 +1,593 @@ +/****************************************************************************** + * + * Module Name: dttemplate - ACPI table template generation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "acapps.h" +#include "dtcompiler.h" +#include "dttemplate.h" /* Contains the hex ACPI table templates */ + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dttemplate") + + +/* Local prototypes */ + +static BOOLEAN +AcpiUtIsSpecialTable ( + char *Signature); + +static ACPI_STATUS +DtCreateOneTemplateFile ( + char *Signature, + UINT32 TableCount); + +static ACPI_STATUS +DtCreateOneTemplate ( + char *Signature, + UINT32 TableCount, + const ACPI_DMTABLE_DATA *TableData); + +static ACPI_STATUS +DtCreateAllTemplates ( + void); + +static int +DtEmitDefinitionBlock ( + FILE *File, + char *Filename, + char *Signature, + UINT32 Instance); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtIsSpecialTable + * + * PARAMETERS: Signature - ACPI table signature + * + * RETURN: TRUE if signature is a special ACPI table + * + * DESCRIPTION: Check for valid ACPI tables that are not in the main ACPI + * table data structure (AcpiDmTableData). + * + ******************************************************************************/ + +static BOOLEAN +AcpiUtIsSpecialTable ( + char *Signature) +{ + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_OSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS) || + ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME)) + { + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: DtCreateTemplates + * + * PARAMETERS: argv - Standard command line arguments + * + * RETURN: Status + * + * DESCRIPTION: Create one or more template files. + * + ******************************************************************************/ + +ACPI_STATUS +DtCreateTemplates ( + char **argv) +{ + char *Signature; + char *End; + unsigned long TableCount; + ACPI_STATUS Status = AE_OK; + + + AslInitializeGlobals (); + + Status = AdInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Special cases for DSDT, ALL, and '*' + */ + + /* Default (no signature option) is DSDT */ + + if (AcpiGbl_Optind < 3) + { + Status = DtCreateOneTemplateFile (ACPI_SIG_DSDT, 0); + goto Exit; + } + + AcpiGbl_Optind--; + Signature = argv[AcpiGbl_Optind]; + AcpiUtStrupr (Signature); + + /* + * Multiple SSDT support (-T ) + */ + TableCount = strtoul (Signature, &End, 0); + if (Signature != End) + { + /* The count is used for table ID and method name - max is 254(+1) */ + + if (TableCount > 254) + { + fprintf (stderr, "%u SSDTs requested, maximum is 254\n", + (unsigned int) TableCount); + + Status = AE_LIMIT; + goto Exit; + } + + Status = DtCreateOneTemplateFile (ACPI_SIG_DSDT, TableCount); + goto Exit; + } + + if (!strcmp (Signature, "ALL")) + { + /* Create all available/known templates */ + + Status = DtCreateAllTemplates (); + goto Exit; + } + + /* + * Normal case: Create template for each signature + */ + while (argv[AcpiGbl_Optind]) + { + Signature = argv[AcpiGbl_Optind]; + AcpiUtStrupr (Signature); + + Status = DtCreateOneTemplateFile (Signature, 0); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + AcpiGbl_Optind++; + } + + +Exit: + /* Shutdown ACPICA subsystem */ + + (void) AcpiTerminate (); + CmDeleteCaches (); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: DtCreateOneTemplateFile + * + * PARAMETERS: Signature - ACPI table signature + * + * RETURN: Status + * + * DESCRIPTION: Create one template file of the requested signature. + * + ******************************************************************************/ + +static ACPI_STATUS +DtCreateOneTemplateFile ( + char *Signature, + UINT32 TableCount) +{ + const ACPI_DMTABLE_DATA *TableData; + ACPI_STATUS Status; + + + /* + * Validate signature and get the template data: + * 1) Signature must be 4 characters + * 2) Signature must be a recognized ACPI table + * 3) There must be a template associated with the signature + */ + if (strlen (Signature) != ACPI_NAME_SIZE) + { + fprintf (stderr, + "%s: Invalid ACPI table signature " + "(length must be 4 characters)\n", Signature); + return (AE_ERROR); + } + + /* + * Some slack for the two strange tables whose name is different than + * their signatures: MADT->APIC and FADT->FACP. + */ + if (!strcmp (Signature, "MADT")) + { + Signature = "APIC"; + } + else if (!strcmp (Signature, "FADT")) + { + Signature = "FACP"; + } + + /* TableData will point to the template */ + + TableData = AcpiDmGetTableData (Signature); + if (TableData) + { + if (!TableData->Template) + { + fprintf (stderr, "%4.4s: No template available\n", Signature); + return (AE_ERROR); + } + } + else if (!AcpiUtIsSpecialTable (Signature)) + { + fprintf (stderr, + "%4.4s: Unrecognized ACPI table signature\n", Signature); + return (AE_ERROR); + } + + Status = DtCreateOneTemplate (Signature, TableCount, TableData); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: DtCreateAllTemplates + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create all currently defined template files + * + ******************************************************************************/ + +static ACPI_STATUS +DtCreateAllTemplates ( + void) +{ + const ACPI_DMTABLE_DATA *TableData; + ACPI_STATUS Status; + + + fprintf (stderr, "Creating all supported Template files\n"); + + /* Walk entire ACPI table data structure */ + + for (TableData = AcpiDmTableData; TableData->Signature; TableData++) + { + /* If table has a template, create the template file */ + + if (TableData->Template) + { + Status = DtCreateOneTemplate (TableData->Signature, + 0, TableData); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + /* + * Create the special ACPI tables: + * 1) DSDT/SSDT are AML tables, not data tables + * 2) FACS and RSDP have non-standard headers + */ + Status = DtCreateOneTemplate (ACPI_SIG_DSDT, 0, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = DtCreateOneTemplate (ACPI_SIG_SSDT, 0, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = DtCreateOneTemplate (ACPI_SIG_OSDT, 0, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = DtCreateOneTemplate (ACPI_SIG_FACS, 0, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = DtCreateOneTemplate (ACPI_RSDP_NAME, 0, NULL); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: DtCreateOneTemplate + * + * PARAMETERS: Signature - ACPI signature, NULL terminated. + * TableCount - Used for SSDTs in same file as DSDT + * TableData - Entry in ACPI table data structure. + * NULL if a special ACPI table. + * + * RETURN: Status + * + * DESCRIPTION: Create one template source file for the requested ACPI table. + * + ******************************************************************************/ + +static ACPI_STATUS +DtCreateOneTemplate ( + char *Signature, + UINT32 TableCount, + const ACPI_DMTABLE_DATA *TableData) +{ + char *DisasmFilename; + FILE *File; + ACPI_STATUS Status = AE_OK; + int Actual; + UINT32 i; + + + /* New file will have a .asl suffix */ + + DisasmFilename = FlGenerateFilename ( + Signature, FILE_SUFFIX_ASL_CODE); + if (!DisasmFilename) + { + fprintf (stderr, "Could not generate output filename\n"); + return (AE_ERROR); + } + + AcpiUtStrlwr (DisasmFilename); + if (!UtQueryForOverwrite (DisasmFilename)) + { + return (AE_ERROR); + } + + File = fopen (DisasmFilename, "w+"); + if (!File) + { + fprintf (stderr, "Could not open output file %s\n", + DisasmFilename); + return (AE_ERROR); + } + + /* Emit the common file header */ + + AcpiOsRedirectOutput (File); + + AcpiOsPrintf ("/*\n"); + AcpiOsPrintf (ACPI_COMMON_HEADER ("iASL Compiler/Disassembler", " * ")); + + if (TableCount == 0) + { + AcpiOsPrintf (" * Template for [%4.4s] ACPI Table", + Signature); + } + else + { + AcpiOsPrintf (" * Template for [%4.4s] and %u [SSDT] ACPI Tables", + Signature, TableCount); + } + + /* Dump the actual ACPI table */ + + if (TableData) + { + /* Normal case, tables that appear in AcpiDmTableData */ + + AcpiOsPrintf (" (static data table)\n"); + + if (Gbl_VerboseTemplates) + { + AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]" + " FieldName : HexFieldValue\n */\n\n"); + } + else + { + AcpiOsPrintf (" * Format: [ByteLength]" + " FieldName : HexFieldValue\n */\n"); + } + + AcpiDmDumpDataTable (ACPI_CAST_PTR (ACPI_TABLE_HEADER, + TableData->Template)); + } + else + { + /* Special ACPI tables - DSDT, SSDT, OSDT, FACS, RSDP */ + + AcpiOsPrintf (" (AML byte code table)\n"); + AcpiOsPrintf (" */\n"); + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT)) + { + Actual = DtEmitDefinitionBlock ( + File, DisasmFilename, ACPI_SIG_DSDT, 1); + if (Actual < 0) + { + Status = AE_ERROR; + goto Cleanup; + } + + /* Emit any requested SSDTs into the same file */ + + for (i = 1; i <= TableCount; i++) + { + Actual = DtEmitDefinitionBlock ( + File, DisasmFilename, ACPI_SIG_SSDT, i + 1); + if (Actual < 0) + { + Status = AE_ERROR; + goto Cleanup; + } + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT)) + { + Actual = DtEmitDefinitionBlock ( + File, DisasmFilename, ACPI_SIG_SSDT, 1); + if (Actual < 0) + { + Status = AE_ERROR; + goto Cleanup; + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_OSDT)) + { + Actual = DtEmitDefinitionBlock ( + File, DisasmFilename, ACPI_SIG_OSDT, 1); + if (Actual < 0) + { + Status = AE_ERROR; + goto Cleanup; + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + AcpiDmDumpDataTable (ACPI_CAST_PTR (ACPI_TABLE_HEADER, + TemplateFacs)); + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME)) + { + AcpiDmDumpDataTable (ACPI_CAST_PTR (ACPI_TABLE_HEADER, + TemplateRsdp)); + } + else + { + fprintf (stderr, + "%4.4s, Unrecognized ACPI table signature\n", Signature); + Status = AE_ERROR; + goto Cleanup; + } + } + + if (TableCount == 0) + { + fprintf (stderr, + "Created ACPI table template for [%4.4s], " + "written to \"%s\"\n", + Signature, DisasmFilename); + } + else + { + fprintf (stderr, + "Created ACPI table templates for [%4.4s] " + "and %u [SSDT], written to \"%s\"\n", + Signature, TableCount, DisasmFilename); + } + +Cleanup: + fclose (File); + AcpiOsRedirectOutput (stdout); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: DtEmitDefinitionBlock + * + * PARAMETERS: File - An open file for the block + * Filename - Filename for same, for error msg(s) + * Signature - ACPI signature for the block + * Instance - Used for multiple SSDTs in the same file + * + * RETURN: Status from fprintf + * + * DESCRIPTION: Emit the raw ASL for a complete Definition Block (DSDT or SSDT) + * + * Note: The AMLFileName parameter for DefinitionBlock is left as a NULL + * string. This allows the compiler to create the output AML filename from + * the input filename. + * + ******************************************************************************/ + +static int +DtEmitDefinitionBlock ( + FILE *File, + char *Filename, + char *Signature, + UINT32 Instance) +{ + int Status; + + + Status = fprintf (File, + "DefinitionBlock (\"\", \"%4.4s\", 2, \"Intel\", \"_%4.4s_%.2X\", 0x00000001)\n" + "{\n" + " Method (%2.2s%.2X)\n" + " {\n" + " }\n" + "}\n\n", + Signature, Signature, Instance, Signature, Instance); + + if (Status < 0) + { + fprintf (stderr, + "Could not write %4.4s to output file %s\n", + Signature, Filename); + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/compiler/dttemplate.h b/third_party/lib/acpica/source/compiler/dttemplate.h new file mode 100644 index 000000000..c93b76140 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dttemplate.h @@ -0,0 +1,1269 @@ +/****************************************************************************** + * + * Module Name: dttemplate.h - ACPI table template definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __DTTEMPLATE_H +#define __DTTEMPLATE_H + + +/* Templates for ACPI data tables */ + +const unsigned char TemplateAsf[] = +{ + 0x41,0x53,0x46,0x21,0x72,0x00,0x00,0x00, /* 00000000 "ASF!r..." */ + 0x10,0x0B,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x10,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x14,0x00, /* 00000030 "........" */ + 0x00,0x00,0x01,0x0C,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x02,0x00,0x0C,0x00,0x01,0x04,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x03,0x00,0x17,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x84,0x00,0x07,0x00,0x00, /* 00000068 "........" */ + 0x01,0x00 /* 00000070 ".." */ +}; + +const unsigned char TemplateBgrt[] = +{ + 0x42,0x47,0x52,0x54,0x38,0x00,0x00,0x00, /* 00000000 "BGRT8..." */ + 0x01,0x0D,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x23,0x06,0x11,0x20,0x01,0x00,0x00,0x00, /* 00000020 "#.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000030 "........" */ +}; + +const unsigned char TemplateBert[] = +{ + 0x42,0x45,0x52,0x54,0x30,0x00,0x00,0x00, /* 00000000 "BERT0..." */ + 0x01,0x15,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000028 "........" */ +}; + +const unsigned char TemplateBoot[] = +{ + 0x42,0x4F,0x4F,0x54,0x28,0x00,0x00,0x00, /* 00000000 "BOOT(..." */ + 0x01,0x0D,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x04,0x06,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00 /* 00000020 "(.. ...." */ +}; + +const unsigned char TemplateCpep[] = +{ + 0x43,0x50,0x45,0x50,0x34,0x00,0x00,0x00, /* 00000000 "CPEP4..." */ + 0x01,0x0F,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00 /* 00000030 "...." */ +}; + +const unsigned char TemplateCsrt[] = +{ + 0x43,0x53,0x52,0x54,0x4C,0x01,0x00,0x00, /* 00000000 "CSRTL..." */ + 0x01,0x0D,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x14,0x11,0x12,0x20,0x88,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x49,0x4E,0x54,0x4C,0x00,0x00,0x00,0x00, /* 00000028 "INTL...." */ + 0x60,0x9C,0x00,0x00,0x02,0x00,0x00,0x00, /* 00000030 "`......." */ + 0x1C,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0xA0,0xB3,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x2A,0x00,0x00,0x00,0x02,0x00,0x06,0x20, /* 00000048 "*...... " */ + 0x00,0x00,0x10,0x00,0xFF,0x0F,0x00,0x00, /* 00000050 "........" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x01,0x00, /* 00000058 "........" */ + 0x53,0x50,0x49,0x20,0x0C,0x00,0x00,0x00, /* 00000060 "SPI ...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x30, /* 00000068 "....CHA0" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 00000070 "........" */ + 0x43,0x48,0x41,0x31,0x0C,0x00,0x00,0x00, /* 00000078 "CHA1...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x32, /* 00000080 "....CHA2" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 00000088 "........" */ + 0x43,0x48,0x41,0x33,0x0C,0x00,0x00,0x00, /* 00000090 "CHA3...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x34, /* 00000098 "....CHA4" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x43,0x48,0x41,0x35,0xA0,0x00,0x00,0x00, /* 000000A8 "CHA5...." */ + 0x49,0x4E,0x54,0x4C,0x00,0x00,0x00,0x00, /* 000000B0 "INTL...." */ + 0x60,0x9C,0x00,0x00,0x03,0x00,0x00,0x00, /* 000000B8 "`......." */ + 0x1C,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000C0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x2B,0x00,0x00,0x00,0x02,0x00,0x08,0x20, /* 000000D0 "+...... " */ + 0x10,0x00,0x10,0x00,0xFF,0x0F,0x00,0x00, /* 000000D8 "........" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x01,0x00, /* 000000E0 "........" */ + 0x49,0x32,0x43,0x20,0x0C,0x00,0x00,0x00, /* 000000E8 "I2C ...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x30, /* 000000F0 "....CHA0" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x43,0x48,0x41,0x31,0x0C,0x00,0x00,0x00, /* 00000100 "CHA1...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x32, /* 00000108 "....CHA2" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 00000110 "........" */ + 0x43,0x48,0x41,0x33,0x0C,0x00,0x00,0x00, /* 00000118 "CHA3...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x34, /* 00000120 "....CHA4" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 00000128 "........" */ + 0x43,0x48,0x41,0x35,0x0C,0x00,0x00,0x00, /* 00000130 "CHA5...." */ + 0x03,0x00,0x00,0x00,0x43,0x48,0x41,0x36, /* 00000138 "....CHA6" */ + 0x0C,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 00000140 "........" */ + 0x43,0x48,0x41,0x37 /* 00000148 "CHA7" */ +}; + +const unsigned char TemplateDbg2[] = +{ + 0x44,0x42,0x47,0x32,0xB2,0x00,0x00,0x00, /* 00000000 "DBG2...." */ + 0x01,0xBA,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x15,0x11,0x13,0x20,0x2C,0x00,0x00,0x00, /* 00000020 "... ,..." */ + 0x02,0x00,0x00,0x00,0xEE,0x3F,0x00,0x02, /* 00000028 ".....?.." */ + 0x09,0x00,0x36,0x00,0x00,0x00,0x00,0x00, /* 00000030 "..6....." */ + 0x00,0x80,0x00,0x00,0x00,0x00,0x16,0x00, /* 00000038 "........" */ + 0x2E,0x00,0x01,0x32,0x00,0x03,0x88,0x77, /* 00000040 "...2...w" */ + 0x66,0x55,0x44,0x33,0x22,0x11,0x01,0x64, /* 00000048 "fUD3"..d" */ + 0x00,0x04,0x11,0x00,0xFF,0xEE,0xDD,0xCC, /* 00000050 "........" */ + 0xBB,0xAA,0x10,0x32,0x54,0x76,0x98,0xBA, /* 00000058 "...2Tv.." */ + 0xDC,0xFE,0x4D,0x79,0x44,0x65,0x76,0x69, /* 00000060 "..MyDevi" */ + 0x63,0x65,0x00,0xEE,0x47,0x00,0x01,0x11, /* 00000068 "ce..G..." */ + 0x00,0x26,0x00,0x10,0x00,0x37,0x00,0x00, /* 00000070 ".&...7.." */ + 0x80,0x00,0x00,0x00,0x00,0x16,0x00,0x22, /* 00000078 "......."" */ + 0x00,0x01,0x64,0x00,0x04,0x11,0x00,0xFF, /* 00000080 "..d....." */ + 0xEE,0xDD,0xCC,0xBB,0xAA,0x98,0xBA,0xDC, /* 00000088 "........" */ + 0xFE,0x5C,0x5C,0x5F,0x53,0x42,0x5F,0x2E, /* 00000090 ".\\_SB_." */ + 0x50,0x43,0x49,0x30,0x2E,0x44,0x42,0x47, /* 00000098 "PCI0.DBG" */ + 0x50,0x00,0x41,0x42,0x43,0x44,0x45,0x46, /* 000000A0 "P.ABCDEF" */ + 0x47,0x48,0x49,0x50,0x51,0x52,0x53,0x54, /* 000000A8 "GHIPQRST" */ + 0x55,0x56 /* 000000B0 "UV" */ +}; + +const unsigned char TemplateDbgp[] = +{ + 0x44,0x42,0x47,0x50,0x34,0x00,0x00,0x00, /* 00000000 "DBGP4..." */ + 0x01,0x1A,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00 /* 00000030 "...." */ +}; + +const unsigned char TemplateDmar[] = +{ + 0x44,0x4D,0x41,0x52,0x8C,0x00,0x00,0x00, /* 00000000 "DMAR...." */ + 0x01,0x03,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x17,0x05,0x13,0x20,0x2F,0x01,0x00,0x00, /* 00000020 "... /..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x18,0x00,0x01,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x03,0x08,0x00,0x00,0x08,0x00,0x00,0x01, /* 00000040 "........" */ + 0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x00, /* 00000048 ".. ....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x02, /* 00000060 "........" */ + 0x02,0x00,0x10,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x02,0x08,0x00,0x00,0x00,0x00,0x00,0x03, /* 00000070 "........" */ + 0x03,0x00,0x14,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00 /* 00000088 "...." */ +}; + +const unsigned char TemplateDrtm[] = +{ + 0x44,0x52,0x54,0x4D,0x94,0x00,0x00,0x00, /* 00000000 "DRTM...." */ + 0x01,0xB9,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00 /* 00000090 "...." */ +}; + +const unsigned char TemplateEcdt[] = +{ + 0x45,0x43,0x44,0x54,0x42,0x00,0x00,0x00, /* 00000000 "ECDTB..." */ + 0x01,0x2D,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".-INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x01,0x08,0x00,0x00, /* 00000020 "(.. ...." */ + 0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "f......." */ + 0x01,0x08,0x00,0x00,0x62,0x00,0x00,0x00, /* 00000030 "....b..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x09,0x00 /* 00000040 ".." */ +}; + +const unsigned char TemplateEinj[] = +{ + 0x45,0x49,0x4E,0x4A,0x30,0x01,0x00,0x00, /* 00000000 "EINJ0..." */ + 0x01,0x09,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x30,0x00,0x00,0x00, /* 00000020 "(.. 0..." */ + 0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000030 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000048 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000050 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000068 "........" */ + 0x02,0x02,0x01,0x00,0x00,0x40,0x00,0x04, /* 00000070 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000088 "........" */ + 0x03,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000090 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000000A8 "........" */ + 0x04,0x03,0x01,0x00,0x00,0x40,0x00,0x04, /* 000000B0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000000C8 "........" */ + 0x05,0x03,0x01,0x00,0x01,0x10,0x00,0x02, /* 000000D0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000000E8 "........" */ + 0x06,0x01,0x00,0x00,0x00,0x40,0x00,0x04, /* 000000F0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000108 "........" */ + 0x07,0x00,0x01,0x00,0x00,0x40,0x00,0x04, /* 00000110 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000118 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000120 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF /* 00000128 "........" */ +}; + +const unsigned char TemplateErst[] = +{ + 0x45,0x52,0x53,0x54,0x30,0x02,0x00,0x00, /* 00000000 "ERST0..." */ + 0x01,0xAB,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x30,0x00,0x00,0x00, /* 00000020 "(.. 0..." */ + 0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x03,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000030 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000048 "........" */ + 0x01,0x03,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000050 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000068 "........" */ + 0x02,0x03,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000070 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000088 "........" */ + 0x03,0x04,0x01,0x00,0x00,0x40,0x00,0x04, /* 00000090 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000000A8 "........" */ + 0x04,0x02,0x00,0x00,0x00,0x40,0x00,0x04, /* 000000B0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000000C8 "........" */ + 0x05,0x03,0x00,0x00,0x01,0x08,0x00,0x01, /* 000000D0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000000E8 "........" */ + 0x06,0x01,0x00,0x00,0x00,0x40,0x00,0x04, /* 000000F0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000108 "........" */ + 0x07,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000110 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000118 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000120 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000128 "........" */ + 0x08,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000130 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000138 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000140 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000148 "........" */ + 0x09,0x02,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000150 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000158 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000160 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000168 "........" */ + 0x0A,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000170 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000178 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000180 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000188 "........" */ + 0x0B,0x03,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000190 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000198 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001A0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000001A8 "........" */ + 0x0C,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 000001B0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001B8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001C0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000001C8 "........" */ + 0x0D,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 000001D0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001E0 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 000001E8 "........" */ + 0x0E,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 000001F0 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000200 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000208 "........" */ + 0x0F,0x00,0x00,0x00,0x00,0x40,0x00,0x04, /* 00000210 ".....@.." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000218 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000220 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF /* 00000228 "........" */ +}; + +const unsigned char TemplateFacs[] = +{ + 0x46,0x41,0x43,0x53,0x40,0x00,0x00,0x00, /* 00000000 "FACS@..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000008 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000010 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000018 "........" */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000020 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000038 "........" */ +}; + +/* Version 5 FADT */ + +const unsigned char TemplateFadt[] = +{ + 0x46,0x41,0x43,0x50,0x14,0x01,0x00,0x00, /* 00000000 "FACP...." */ + 0x06,0x8A,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x01,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000048 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x04,0x02,0x01,0x04,0x08,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 00000070 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x02, /* 00000090 "..... .." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x10,0x00,0x02, /* 000000A8 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x00, /* 000000C0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x01,0x20,0x00,0x03,0x01,0x00,0x00,0x00, /* 000000D0 ". ......" */ + 0x00,0x00,0x00,0x00,0x01,0x40,0x00,0x01, /* 000000D8 ".....@.." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x01,0x08,0x00,0x01,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000108 "........" */ + 0x00,0x00,0x00,0x00 /* 00000110 "...." */ +}; + +const unsigned char TemplateFpdt[] = +{ + 0x46,0x50,0x44,0x54,0x64,0x00,0x00,0x00, /* 00000000 "FPDTd..." */ + 0x01,0xBD,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x04,0x08,0x11,0x20,0x00,0x00,0x30,0x01, /* 00000020 "... ..0." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x01, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00 /* 00000060 "...." */ +}; + +const unsigned char TemplateGtdt[] = +{ + 0x47,0x54,0x44,0x54,0xe0,0x00,0x00,0x00, /* 00000000 "GTDT...." */ + 0x02,0xb0,0x4c,0x49,0x4e,0x41,0x52,0x4f, /* 00000008 "..LINARO" */ + 0x52,0x54,0x53,0x4d,0x56,0x45,0x56,0x38, /* 00000010 "RTSMVEV8" */ + 0x01,0x00,0x00,0x00,0x49,0x4e,0x54,0x4c, /* 00000018 "....INTL" */ + 0x24,0x04,0x14,0x20,0x00,0x00,0x00,0x00, /* 00000020 "$.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x1d,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000030 "........" */ + 0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000038 "........" */ + 0x1b,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000040 "........" */ + 0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00, /* 00000058 "....`..." */ + 0x00,0x64,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 ".d......" */ + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, /* 00000068 "........" */ + 0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000a0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000a8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000b0 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000b8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x1c,0x00,0x00, /* 000000c0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000c8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000d0 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000d8 "........" */ +}; + +const unsigned char TemplateHest[] = +{ + 0x48,0x45,0x53,0x54,0xD4,0x01,0x00,0x00, /* 00000000 "HEST...." */ + 0x01,0x20,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ". INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x04,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, /* 00000028 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x01, /* 00000088 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, /* 000000B0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000D0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x01, /* 000000F0 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000108 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000110 "........" */ + 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, /* 00000118 "........" */ + 0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00, /* 00000120 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000128 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000130 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000138 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000140 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000148 "........" */ + 0x00,0x00,0x00,0x00,0x09,0x00,0x02,0x00, /* 00000150 "........" */ + 0xFF,0xFF,0x00,0x01,0x01,0x00,0x00,0x00, /* 00000158 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x00, /* 00000160 "........" */ + 0x00,0x40,0x00,0x04,0x00,0x00,0x00,0x00, /* 00000168 ".@......" */ + 0x00,0x00,0x00,0x00,0x03,0x1C,0x00,0x00, /* 00000170 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000178 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000180 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000188 "........" */ + 0x00,0x10,0x00,0x00,0x09,0x00,0x03,0x00, /* 00000190 "........" */ + 0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00, /* 00000198 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x00, /* 000001A0 "........" */ + 0x00,0x40,0x00,0x04,0x00,0x00,0x00,0x00, /* 000001A8 ".@......" */ + 0x00,0x00,0x00,0x00,0x04,0x1C,0x00,0x00, /* 000001B0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001B8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001C0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001C8 "........" */ + 0x00,0x10,0x00,0x00 /* 000001D0 "...." */ +}; + +const unsigned char TemplateHpet[] = +{ + 0x48,0x50,0x45,0x54,0x38,0x00,0x00,0x00, /* 00000000 "HPET8..." */ + 0x01,0x09,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000030 "........" */ +}; + +const unsigned char TemplateIort[] = +{ + 0x49,0x4F,0x52,0x54,0x0C,0x01,0x00,0x00, /* 00000000 "IORT...." */ + 0x00,0xBC,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x04,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "4......." */ + 0x00,0x00,0x00,0x00,0x00,0x2C,0x00,0x00, /* 00000030 ".....,.." */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000038 "........" */ + 0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x01,0x30,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 ".0......" */ + 0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00, /* 00000068 "....0..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x5C,0x5F,0x53, /* 00000078 ".....\_S" */ + 0x42,0x2E,0x50,0x43,0x49,0x30,0x2E,0x44, /* 00000080 "B.PCI0.D" */ + 0x45,0x56,0x30,0x00,0x00,0x00,0x00,0x00, /* 00000088 "EV0....." */ + 0x02,0x20,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000090 ". ......" */ + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, /* 00000098 ".... ..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x03,0x5C,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B0 ".\......" */ + 0x00,0x00,0x00,0x00,0x5C,0x00,0x00,0x00, /* 000000B8 "....\..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D0 "........" */ + 0x3C,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000D8 "<......." */ + 0x4C,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 000000E0 "L......." */ + 0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "T......." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00 /* 00000108 "...." */ +}; + +const unsigned char TemplateIvrs[] = +{ + 0x49,0x56,0x52,0x53,0xBC,0x00,0x00,0x00, /* 00000000 "IVRS...." */ + 0x01,0x87,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x10,0x14,0x34,0x00,0x00,0x00,0x00,0x00, /* 00000030 "..4....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00, /* 00000048 "....@..." */ + 0x00,0x00,0x00,0x00,0x42,0x00,0x00,0x00, /* 00000050 "....B..." */ + 0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00, /* 00000058 "....H..." */ + 0x00,0x00,0x00,0x00,0x20,0x08,0x20,0x00, /* 00000060 ".... . ." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x21,0x04,0x20,0x00, /* 00000080 "....!. ." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x10,0x14,0x18,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B0 "........" */ + 0x00,0x00,0x00,0x00 /* 000000B8 "...." */ +}; + +const unsigned char TemplateLpit[] = +{ + 0x4C,0x50,0x49,0x54,0x94,0x00,0x00,0x00, /* 00000000 "LPIT...." */ + 0x00,0xD8,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "8......." */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x7F,0x40,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 ".@......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "8......." */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x7F,0x40,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 ".@......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00 /* 00000090 "...." */ +}; + +/* MADT with ACPI 6.0 subtables */ + +const unsigned char TemplateMadt[] = +{ + 0x41,0x50,0x49,0x43,0x5A,0x01,0x00,0x00, /* 00000000 "APICZ..." */ + 0x03,0xEA,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x01,0x00,0x00,0x00,0x00,0x08,0x00,0x00, /* 00000028 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x0C,0x01,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x02,0x0A,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x03,0x08,0x0D,0x00,0x01,0x00, /* 00000048 "........" */ + 0x00,0x00,0x04,0x06,0x00,0x05,0x00,0x01, /* 00000050 "........" */ + 0x05,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x06,0x10,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x07,0x16,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x5C,0x43,0x50,0x55, /* 00000080 "....\CPU" */ + 0x30,0x00,0x08,0x10,0x05,0x00,0x00,0x00, /* 00000088 "0......." */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, /* 00000090 "........" */ + 0x00,0x00,0x09,0x10,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x0A,0x0C,0x05,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x50, /* 000000B0 ".......P" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, /* 000000C0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x18, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000108 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000110 "........" */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x0D,0x18, /* 00000118 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000120 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, /* 00000128 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x10, /* 00000130 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000138 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x14, /* 00000140 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000148 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000150 "........" */ + 0x00,0x00 /* 00000158 ".." */ +}; + +const unsigned char TemplateMcfg[] = +{ + 0x4D,0x43,0x46,0x47,0x3C,0x00,0x00,0x00, /* 00000000 "MCFG<..." */ + 0x01,0x19,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00 /* 00000038 "...." */ +}; + +const unsigned char TemplateMchi[] = +{ + 0x4D,0x43,0x48,0x49,0x45,0x00,0x00,0x00, /* 00000000 "MCHIE..." */ + 0x01,0xE4,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x15,0x07,0x00,0x02,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x01,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x02,0x08,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00 /* 00000040 "....." */ +}; + +const unsigned char TemplateMsdm[] = +{ + 0x4D,0x53,0x44,0x4D,0x64,0x00,0x00,0x00, /* 00000000 "MSDMd..." */ + 0x01,0x34,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 ".4Intel." */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x03,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x04,0x02,0x15,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x0A,0x10,0x16,0x17,0x18,0x19,0x1A,0x1B, /* 00000028 "........" */ + 0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23, /* 00000030 ".... !"#" */ + 0x24,0x25,0x26,0x27,0x10,0x0A,0x15,0x16, /* 00000038 "$%&'...." */ + 0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E, /* 00000040 "........" */ + 0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26, /* 00000048 ". !"#$%&" */ + 0x16,0x15,0x0A,0x10,0x16,0x17,0x18,0x19, /* 00000050 "........" */ + 0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21, /* 00000058 "...... !" */ + 0x22,0x23,0x24,0x25 /* 00000060 ""#$%" */ +}; + +const unsigned char TemplateMpst[] = +{ + 0x4D,0x50,0x53,0x54,0xB6,0x00,0x00,0x00, /* 00000000 "MPST...." */ + 0x01,0x77,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".wINTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x13,0x09,0x12,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, /* 00000040 "........" */ + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, /* 00000068 "........" */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00 /* 000000B0 "......" */ +}; + +const unsigned char TemplateMsct[] = +{ + 0x4D,0x53,0x43,0x54,0x90,0x00,0x00,0x00, /* 00000000 "MSCT...." */ + 0x01,0xB7,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x38,0x00,0x00,0x00, /* 00000020 "(.. 8..." */ + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00, /* 00000030 "........" */ + 0x01,0x16,0x00,0x00,0x00,0x00,0x03,0x00, /* 00000038 "........" */ + 0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x40,0x00,0x00,0x00,0x01,0x16, /* 00000048 "..@....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x16,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x01,0x16,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000088 "........" */ +}; + +const unsigned char TemplateNfit[] = +{ + 0x4E,0x46,0x49,0x54,0x70,0x01,0x00,0x00, /* 00000000 "NFITp..." */ + 0x01,0x53,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".SINTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x38,0x00,0x01,0x00,0x00,0x00, /* 00000028 "..8....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x30,0x05,0xAF,0x91,0x86,0x5D,0x0E,0x47, /* 00000038 "0....].G" */ + 0xA6,0xB0,0x0A,0x2D,0xB9,0x40,0x82,0x49, /* 00000040 "...-.@.I" */ + 0x00,0x00,0x00,0x7C,0x03,0x00,0x00,0x00, /* 00000048 "...|...." */ + 0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x01,0x00,0x30,0x00,0x01,0x00,0x00,0x00, /* 00000060 "..0....." */ + 0x04,0x00,0x00,0x00,0x01,0x00,0x01,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x01,0x00,0x03,0x00,0x2A,0x00,0x00,0x00, /* 00000088 "....*..." */ + 0x02,0x00,0x20,0x00,0x01,0x00,0x00,0x00, /* 00000090 ".. ....." */ + 0x04,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x06,0x00,0x00,0x00,0x09,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x03,0x00,0x28,0x00,0x00,0x00,0x00,0x00, /* 000000B0 "..(....." */ + 0xB4,0x13,0x5D,0x40,0x91,0x0B,0x29,0x93, /* 000000B8 "..]@..)." */ + 0x67,0xE8,0x23,0x4C,0x00,0x00,0x00,0x88, /* 000000C0 "g.#L...." */ + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, /* 000000C8 ".."3DUfw" */ + 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, /* 000000D0 "........" */ + 0x04,0x00,0x50,0x00,0x01,0x00,0x86,0x80, /* 000000D8 "..P....." */ + 0x17,0x20,0x01,0x00,0x86,0x80,0x17,0x20, /* 000000E0 ". ..... " */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x89,0x00,0x54,0x76,0x01,0x03,0x00,0x01, /* 000000F0 "..Tv...." */ + 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 ". ......" */ + 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000108 "........" */ + 0x00,0x10,0x80,0x00,0x00,0x00,0x00,0x00, /* 00000110 "........" */ + 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000118 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000120 "........" */ + 0x05,0x00,0x28,0x00,0x01,0x00,0x00,0x01, /* 00000128 "..(....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000130 "........" */ + 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000138 ". ......" */ + 0x00,0x00,0x00,0xE0,0x0F,0x00,0x00,0x00, /* 00000140 "........" */ + 0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00, /* 00000148 "........" */ + 0x06,0x00,0x20,0x00,0x01,0x00,0x00,0x00, /* 00000150 ".. ....." */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000158 "........" */ + 0x00,0x00,0x00,0x18,0x04,0x00,0x00,0x00, /* 00000160 "........" */ + 0x00,0x00,0x00,0x18,0x06,0x00,0x00,0x00 /* 00000168 "........" */ +}; + +const unsigned char TemplateMtmr[] = +{ + 0x4D,0x54,0x4D,0x52,0x4C,0x00,0x00,0x00, /* 00000000 "MTMRL..." */ + 0x01,0xB0,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x03,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x17,0x01,0x13,0x20,0x00,0x20,0x00,0x03, /* 00000020 "... . .." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x20,0x00,0x03,0x00,0x00,0x00,0x00, /* 00000038 ". ......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00 /* 00000048 "...." */ +}; + +const unsigned char TemplatePcct[] = +{ + 0x50,0x43,0x43,0x54,0xAC,0x00,0x00,0x00, /* 00000000 "PCCT...." */ + 0x01,0xCF,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x27,0x06,0x14,0x20,0x01,0x00,0x00,0x00, /* 00000020 "'.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 ".>......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x01,0x32,0x00,0x03,0x00,0x00,0x00,0x00, /* 00000048 ".2......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, /* 00000058 "........" */ + 0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00, /* 00000060 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x3E, /* 00000068 ".......>" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x32, /* 00000080 ".......2" */ + 0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* 00000098 "........" */ + 0xFF,0xFF,0x01,0x00,0x00,0x00,0x01,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x01,0x00 /* 000000A8 "...." */ +}; + +const unsigned char TemplatePmtt[] = +{ + 0x50,0x4D,0x54,0x54,0xB4,0x00,0x00,0x00, /* 00000000 "PMTT...." */ + 0x01,0x3A,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".:INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x26,0x08,0x11,0x20,0x00,0x00,0x00,0x00, /* 00000020 "&.. ...." */ + 0x00,0x00,0x80,0x00,0x01,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x00, /* 00000030 "......T." */ + 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x02,0x00,0x14,0x00,0x02,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x02,0x00,0x14,0x00, /* 00000070 "........" */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x01,0x00,0x20,0x00,0x01,0x00,0x00,0x00, /* 00000088 ".. ....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x0C,0x00,0x01,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00 /* 000000B0 "...." */ +}; + +const unsigned char TemplateRsdp[] = +{ + 0x52,0x53,0x44,0x20,0x50,0x54,0x52,0x20, /* 00000000 "RSD PTR " */ + 0x43,0x49,0x4E,0x54,0x45,0x4C,0x20,0x02, /* 00000008 "CINTEL ." */ + 0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x00, /* 00000010 "....$..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000018 "........" */ + 0xDC,0x00,0x00,0x00 /* 00000020 "...." */ +}; + +const unsigned char TemplateRsdt[] = +{ + 0x52,0x53,0x44,0x54,0x44,0x00,0x00,0x00, /* 00000000 "RSDTD..." */ + 0x01,0xB1,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x10,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x20,0x00,0x00,0x00,0x30,0x00,0x00,0x00, /* 00000028 " ...0..." */ + 0x40,0x00,0x00,0x00,0x50,0x00,0x00,0x00, /* 00000030 "@...P..." */ + 0x60,0x00,0x00,0x00,0x70,0x00,0x00,0x00, /* 00000038 "`...p..." */ + 0x80,0x00,0x00,0x00 /* 00000040 "...." */ +}; + +const unsigned char TemplateS3pt[] = +{ + 0x53,0x33,0x50,0x54,0x34,0x00,0x00,0x00, /* 00000000 "S3PT4..." */ + 0x00,0x00,0x18,0x01,0x00,0x00,0x00,0x00, /* 00000008 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000010 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000018 "........" */ + 0x01,0x00,0x14,0x01,0x00,0x00,0x00,0x00, /* 00000020 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00 /* 00000030 "...." */ +}; + +const unsigned char TemplateSbst[] = +{ + 0x53,0x42,0x53,0x54,0x30,0x00,0x00,0x00, /* 00000000 "SBST0..." */ + 0x01,0x06,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000028 "........" */ +}; + +const unsigned char TemplateSlic[] = +{ + 0x53,0x4C,0x49,0x43,0x76,0x01,0x00,0x00, /* 00000000 "SLICv..." */ + 0x01,0x07,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x11,0x02,0x11,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x9C,0x00,0x00,0x00,0x06,0x02,0x00,0x00, /* 00000028 "........" */ + 0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31, /* 00000030 ".$..RSA1" */ + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000090 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x01,0x00,0x00,0x00,0xB6,0x00,0x00,0x00, /* 000000C0 "........" */ + 0x00,0x00,0x02,0x00,0x49,0x4E,0x54,0x45, /* 000000C8 "....INTE" */ + 0x4C,0x20,0x54,0x45,0x4D,0x50,0x4C,0x41, /* 000000D0 "L TEMPLA" */ + 0x54,0x45,0x57,0x49,0x4E,0x44,0x4F,0x57, /* 000000D8 "TEWINDOW" */ + 0x53,0x20,0x01,0x00,0x02,0x00,0x00,0x00, /* 000000E0 "S ......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000108 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000110 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000118 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000120 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000128 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000130 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000138 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000140 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000148 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000150 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000158 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000160 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000168 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00 /* 00000170 "......" */ +}; + +const unsigned char TemplateSlit[] = +{ + 0x53,0x4C,0x49,0x54,0xBC,0x01,0x00,0x00, /* 00000000 "SLIT...." */ + 0x01,0x00,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x16,0x03,0x11,0x20,0x14,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x00,0x0A,0x10,0x16,0x17, /* 00000028 "........" */ + 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, /* 00000030 "........" */ + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, /* 00000038 " !"#$%&'" */ + 0x10,0x0A,0x15,0x16,0x17,0x18,0x19,0x1A, /* 00000040 "........" */ + 0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22, /* 00000048 "..... !"" */ + 0x23,0x24,0x25,0x26,0x16,0x15,0x0A,0x10, /* 00000050 "#$%&...." */ + 0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D, /* 00000058 "........" */ + 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25, /* 00000060 ".. !"#$%" */ + 0x17,0x16,0x10,0x0A,0x15,0x16,0x17,0x18, /* 00000068 "........" */ + 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20, /* 00000070 "....... " */ + 0x21,0x22,0x23,0x24,0x18,0x17,0x16,0x15, /* 00000078 "!"#$...." */ + 0x0A,0x10,0x16,0x17,0x18,0x19,0x1A,0x1B, /* 00000080 "........" */ + 0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23, /* 00000088 ".... !"#" */ + 0x19,0x18,0x17,0x16,0x10,0x0A,0x15,0x16, /* 00000090 "........" */ + 0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E, /* 00000098 "........" */ + 0x1F,0x20,0x21,0x22,0x1A,0x19,0x18,0x17, /* 000000A0 ". !"...." */ + 0x16,0x15,0x0A,0x10,0x16,0x17,0x18,0x19, /* 000000A8 "........" */ + 0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21, /* 000000B0 "...... !" */ + 0x1B,0x1A,0x19,0x18,0x17,0x16,0x10,0x0A, /* 000000B8 "........" */ + 0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C, /* 000000C0 "........" */ + 0x1D,0x1E,0x1F,0x20,0x1C,0x1B,0x1A,0x19, /* 000000C8 "... ...." */ + 0x18,0x17,0x16,0x15,0x0A,0x10,0x16,0x17, /* 000000D0 "........" */ + 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, /* 000000D8 "........" */ + 0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17,0x16, /* 000000E0 "........" */ + 0x10,0x0A,0x15,0x16,0x17,0x18,0x19,0x1A, /* 000000E8 "........" */ + 0x1B,0x1C,0x1D,0x1E,0x1E,0x1D,0x1C,0x1B, /* 000000F0 "........" */ + 0x1A,0x19,0x18,0x17,0x16,0x15,0x0A,0x10, /* 000000F8 "........" */ + 0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D, /* 00000100 "........" */ + 0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18, /* 00000108 "........" */ + 0x17,0x16,0x10,0x0A,0x15,0x16,0x17,0x18, /* 00000110 "........" */ + 0x19,0x1A,0x1B,0x1C,0x20,0x1F,0x1E,0x1D, /* 00000118 ".... ..." */ + 0x1C,0x1B,0x1A,0x19,0x18,0x17,0x16,0x15, /* 00000120 "........" */ + 0x0A,0x10,0x16,0x17,0x18,0x19,0x1A,0x1B, /* 00000128 "........" */ + 0x21,0x20,0x1F,0x1E,0x1D,0x1C,0x1B,0x1A, /* 00000130 "! ......" */ + 0x19,0x18,0x17,0x16,0x10,0x0A,0x15,0x16, /* 00000138 "........" */ + 0x17,0x18,0x19,0x1A,0x22,0x21,0x20,0x1F, /* 00000140 "...."! ." */ + 0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17, /* 00000148 "........" */ + 0x16,0x15,0x0A,0x10,0x16,0x17,0x18,0x19, /* 00000150 "........" */ + 0x23,0x22,0x21,0x20,0x1F,0x1E,0x1D,0x1C, /* 00000158 "#"! ...." */ + 0x1B,0x1A,0x19,0x18,0x17,0x16,0x10,0x0A, /* 00000160 "........" */ + 0x15,0x16,0x17,0x18,0x24,0x23,0x22,0x21, /* 00000168 "....$#"!" */ + 0x20,0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19, /* 00000170 " ......." */ + 0x18,0x17,0x16,0x15,0x0A,0x10,0x16,0x17, /* 00000178 "........" */ + 0x25,0x24,0x23,0x22,0x21,0x20,0x1F,0x1E, /* 00000180 "%$#"! .." */ + 0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17,0x16, /* 00000188 "........" */ + 0x10,0x0A,0x15,0x16,0x26,0x25,0x24,0x23, /* 00000190 "....&%$#" */ + 0x22,0x21,0x20,0x1F,0x1E,0x1D,0x1C,0x1B, /* 00000198 ""! ....." */ + 0x1A,0x19,0x18,0x17,0x16,0x15,0x0A,0x10, /* 000001A0 "........" */ + 0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20, /* 000001A8 "'&%$#"! " */ + 0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18, /* 000001B0 "........" */ + 0x17,0x16,0x10,0x0A /* 000001B8 "...." */ +}; + +const unsigned char TemplateSpcr[] = +{ + 0x53,0x50,0x43,0x52,0x50,0x00,0x00,0x00, /* 00000000 "SPCRP..." */ + 0x01,0xE3,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000048 "........" */ +}; + +const unsigned char TemplateSpmi[] = +{ + 0x53,0x50,0x4D,0x49,0x41,0x00,0x00,0x00, /* 00000000 "SPMIA..." */ + 0x04,0x00,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x14,0x01,0x14,0x20,0x00,0x01,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x08,0x00,0x01,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00 /* 00000040 "." */ +}; + +const unsigned char TemplateSrat[] = +{ + 0x53,0x52,0x41,0x54,0x92,0x00,0x00,0x00, /* 00000000 "SRAT...." */ + 0x03,0x50,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".PINTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x24,0x07,0x14,0x20,0x01,0x00,0x00,0x00, /* 00000020 "$.. ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x10,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x01,0x28,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 ".(......" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0xFC,0x09,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x02,0x18,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000070 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x03,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00 /* 00000090 ".." */ +}; + +const unsigned char TemplateStao[] = +{ + 0x53,0x54,0x41,0x4F,0x7E,0x00,0x00,0x00, /* 00000000 "STAO~..." */ + 0x01,0x7F,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x01,0x5C,0x5F,0x53, /* 00000020 "... .\_S" */ + 0x42,0x30,0x2E,0x42,0x55,0x53,0x30,0x2E, /* 00000028 "B0.BUS0." */ + 0x44,0x45,0x56,0x31,0x00,0x5C,0x5F,0x53, /* 00000030 "DEV1.\_S" */ + 0x42,0x30,0x2E,0x42,0x55,0x53,0x30,0x2E, /* 00000038 "B0.BUS0." */ + 0x44,0x45,0x56,0x32,0x00,0x5C,0x5F,0x53, /* 00000040 "DEV2.\_S" */ + 0x42,0x30,0x2E,0x42,0x55,0x53,0x31,0x2E, /* 00000048 "B0.BUS1." */ + 0x44,0x45,0x56,0x31,0x2E,0x44,0x45,0x56, /* 00000050 "DEV1.DEV" */ + 0x32,0x00,0x5C,0x5F,0x53,0x42,0x30,0x2E, /* 00000058 "2.\_SB0." */ + 0x42,0x55,0x53,0x31,0x2E,0x44,0x45,0x56, /* 00000060 "BUS1.DEV" */ + 0x32,0x2E,0x44,0x45,0x56,0x32,0x00,0x5C, /* 00000068 "2.DEV2.\" */ + 0x55,0x53,0x42,0x31,0x2E,0x48,0x55,0x42, /* 00000070 "USB1.HUB" */ + 0x31,0x2E,0x50,0x54,0x31,0x00 /* 00000078 "1.PT1." */ +}; + +const unsigned char TemplateTcpa[] = +{ + 0x54,0x43,0x50,0x41,0x64,0x00,0x00,0x00, /* 00000000 "TCPAd..." */ + 0x02,0xFF,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x80,0x31,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 ".1..INTL" */ + 0x19,0x06,0x15,0x20,0x01,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x11,0x00,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA, /* 00000030 "........" */ + 0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x03, /* 00000040 "..... .." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x03, /* 00000050 "..... .." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x01,0x01,0x01,0x01 /* 00000060 "...." */ +}; + +const unsigned char TemplateTpm2[] = +{ + 0x54,0x50,0x4D,0x32,0x34,0x00,0x00,0x00, /* 00000000 "TPM24..." */ + 0x03,0x42,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".BINTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x14,0x11,0x12,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x00, /* 00000028 "wfUD3".." */ + 0x01,0x00,0x00,0x00 /* 00000030 "...." */ +}; + +const unsigned char TemplateUefi[] = +{ + 0x55,0x45,0x46,0x49,0x36,0x00,0x00,0x00, /* 00000000 "UEFI6..." */ + 0x01,0x9B,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x01,0x02,0x03, /* 00000020 "(.. ...." */ + 0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B, /* 00000028 "........" */ + 0x0C,0x0D,0x0E,0x0F,0x00,0x00 /* 00000030 "......" */ +}; + +const unsigned char TemplateVrtc[] = +{ + 0x56,0x52,0x54,0x43,0x44,0x00,0x00,0x00, /* 00000000 "VRTCD..." */ + 0x01,0xEF,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x03,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x17,0x01,0x13,0x20,0x00,0x08,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00 /* 00000040 "...." */ +}; + +const unsigned char TemplateWaet[] = +{ + 0x57,0x41,0x45,0x54,0x28,0x00,0x00,0x00, /* 00000000 "WAET(..." */ + 0x01,0x19,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00 /* 00000020 "(.. ...." */ +}; + +const unsigned char TemplateWdat[] = +{ + 0x57,0x44,0x41,0x54,0x5C,0x00,0x00,0x00, /* 00000000 "WDAT\..." */ + 0x01,0xE3,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x20,0x00,0x00,0x00, /* 00000020 "(.. ..." */ + 0xFF,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00, /* 00000028 "........" */ + 0x58,0x02,0x00,0x00,0xFF,0x03,0x00,0x00, /* 00000030 "X......." */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x0E,0x00,0x00,0x00,0x01,0x02,0x00,0x00, /* 00000040 "........" */ + 0x01,0x10,0x00,0x02,0x60,0x04,0x00,0x00, /* 00000048 "....`..." */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000050 "........" */ + 0x01,0x00,0x00,0x00 /* 00000058 "...." */ +}; + +const unsigned char TemplateWddt[] = +{ + 0x57,0x44,0x44,0x54,0x40,0x00,0x00,0x00, /* 00000000 "WDDT@..." */ + 0x01,0x00,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x01,0xFF,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000038 "........" */ +}; + +const unsigned char TemplateWdrt[] = +{ + 0x57,0x44,0x52,0x54,0x47,0x00,0x00,0x00, /* 00000000 "WDRTG..." */ + 0x01,0xB0,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x00,0x20,0x00,0x00, /* 00000020 "(.. . .." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 ". ......" */ + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00 /* 00000040 "......." */ +}; + +const unsigned char TemplateWpbt[] = +{ + 0x57,0x50,0x42,0x54,0x98,0x00,0x00,0x00, /* 00000000 "WPBT...." */ + 0x01,0x83,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x78,0x56,0x34,0x12, /* 00000020 "... xV4." */ + 0x00,0x00,0x00,0xBB,0x00,0x00,0x00,0xAA, /* 00000028 "........" */ + 0x33,0x88,0x64,0x00,0x34,0x00,0x20,0x00, /* 00000030 "3.d.4. ." */ + 0x73,0x00,0x63,0x00,0x6F,0x00,0x72,0x00, /* 00000038 "s.c.o.r." */ + 0x65,0x00,0x20,0x00,0x61,0x00,0x6E,0x00, /* 00000040 "e. .a.n." */ + 0x64,0x00,0x20,0x00,0x37,0x00,0x20,0x00, /* 00000048 "d. .7. ." */ + 0x79,0x00,0x65,0x00,0x61,0x00,0x72,0x00, /* 00000050 "y.e.a.r." */ + 0x73,0x00,0x20,0x00,0x61,0x00,0x67,0x00, /* 00000058 "s. .a.g." */ + 0x6F,0x00,0x20,0x00,0x6F,0x00,0x75,0x00, /* 00000060 "o. .o.u." */ + 0x72,0x00,0x20,0x00,0x66,0x00,0x61,0x00, /* 00000068 "r. .f.a." */ + 0x74,0x00,0x68,0x00,0x65,0x00,0x72,0x00, /* 00000070 "t.h.e.r." */ + 0x73,0x00,0x20,0x00,0x62,0x00,0x72,0x00, /* 00000078 "s. .b.r." */ + 0x6F,0x00,0x75,0x00,0x67,0x00,0x68,0x00, /* 00000080 "o.u.g.h." */ + 0x74,0x00,0x20,0x00,0x66,0x00,0x6F,0x00, /* 00000088 "t. .f.o." */ + 0x72,0x00,0x74,0x00,0x68,0x00,0x00,0x00 /* 00000090 "r.t.h..." */ +}; + +const unsigned char TemplateXenv[] = +{ + 0x58,0x45,0x4E,0x56,0x39,0x00,0x00,0x00, /* 00000000 "XENV9..." */ + 0x01,0x3A,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".:INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x10,0x04,0x15,0x20,0x00,0x00,0x00,0x10, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x0A,0x00,0x20,0x00,0x00, /* 00000028 "..... .." */ + 0x00,0x00,0x00,0x0B,0x25,0x00,0xBB,0xAA, /* 00000030 "....%..." */ + 0x03 /* 00000038 "." */ +}; + +const unsigned char TemplateXsdt[] = +{ + 0x58,0x53,0x44,0x54,0x64,0x00,0x00,0x00, /* 00000000 "XSDTd..." */ + 0x01,0x8B,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x28,0x05,0x10,0x20,0x10,0x00,0x00,0x00, /* 00000020 "(.. ...." */ + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, /* 00000028 ".... ..." */ + 0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00, /* 00000030 "....0..." */ + 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00, /* 00000038 "....@..." */ + 0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00, /* 00000040 "....P..." */ + 0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00, /* 00000048 "....`..." */ + 0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00, /* 00000050 "....p..." */ + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00 /* 00000060 "...." */ +}; + +#endif diff --git a/third_party/lib/acpica/source/compiler/dtutils.c b/third_party/lib/acpica/source/compiler/dtutils.c new file mode 100644 index 000000000..c9756da9c --- /dev/null +++ b/third_party/lib/acpica/source/compiler/dtutils.c @@ -0,0 +1,1001 @@ +/****************************************************************************** + * + * Module Name: dtutils.c - Utility routines for the data table compiler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" +#include "actables.h" + +#define _COMPONENT DT_COMPILER + ACPI_MODULE_NAME ("dtutils") + +/* Local prototypes */ + +static void +DtSum ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue); + + +/****************************************************************************** + * + * FUNCTION: DtError + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * Op - Parse node where error happened + * ExtraMessage - additional error message + * + * RETURN: None + * + * DESCRIPTION: Common error interface for data table compiler + * + *****************************************************************************/ + +void +DtError ( + UINT8 Level, + UINT16 MessageId, + DT_FIELD *FieldObject, + char *ExtraMessage) +{ + + /* Check if user wants to ignore this exception */ + + if (AslIsExceptionDisabled (Level, MessageId)) + { + return; + } + + if (FieldObject) + { + AslCommonError (Level, MessageId, + FieldObject->Line, + FieldObject->Line, + FieldObject->ByteOffset, + FieldObject->Column, + Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage); + } + else + { + AslCommonError (Level, MessageId, 0, + 0, 0, 0, 0, ExtraMessage); + } +} + + +/****************************************************************************** + * + * FUNCTION: DtNameError + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * Op - Parse node where error happened + * ExtraMessage - additional error message + * + * RETURN: None + * + * DESCRIPTION: Error interface for named objects + * + *****************************************************************************/ + +void +DtNameError ( + UINT8 Level, + UINT16 MessageId, + DT_FIELD *FieldObject, + char *ExtraMessage) +{ + + switch (Level) + { + case ASL_WARNING2: + case ASL_WARNING3: + + if (Gbl_WarningLevel < Level) + { + return; + } + break; + + default: + + break; + } + + if (FieldObject) + { + AslCommonError (Level, MessageId, + FieldObject->Line, + FieldObject->Line, + FieldObject->ByteOffset, + FieldObject->NameColumn, + Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage); + } + else + { + AslCommonError (Level, MessageId, 0, + 0, 0, 0, 0, ExtraMessage); + } +} + + +/******************************************************************************* + * + * FUNCTION: DtFatal + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump the error log and abort the compiler. Used for serious + * compile or I/O errors + * + ******************************************************************************/ + +void +DtFatal ( + UINT16 MessageId, + DT_FIELD *FieldObject, + char *ExtraMessage) +{ + + DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage); + +/* + * TBD: remove this entire function, DtFatal + * + * We cannot abort the compiler on error, because we may be compiling a + * list of files. We must move on to the next file. + */ +#ifdef __OBSOLETE + CmCleanupAndExit (); + exit (1); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: DtStrtoul64 + * + * PARAMETERS: String - Null terminated string + * ReturnInteger - Where the converted integer is returned + * + * RETURN: Status + * + * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned + * value. Assumes no leading "0x" for the constant. + * + * Portability note: The reason this function exists is because a 64-bit + * sscanf is not available in all environments. + * + *****************************************************************************/ + +ACPI_STATUS +DtStrtoul64 ( + char *String, + UINT64 *ReturnInteger) +{ + char *ThisChar = String; + UINT32 ThisDigit; + UINT64 ReturnValue = 0; + int DigitCount = 0; + + + /* Skip over any white space in the buffer */ + + while ((*ThisChar == ' ') || (*ThisChar == '\t')) + { + ThisChar++; + } + + /* Skip leading zeros */ + + while ((*ThisChar) == '0') + { + ThisChar++; + } + + /* Convert character-by-character */ + + while (*ThisChar) + { + if (isdigit ((int) *ThisChar)) + { + /* Convert ASCII 0-9 to Decimal value */ + + ThisDigit = ((UINT8) *ThisChar) - '0'; + } + else /* Letter */ + { + ThisDigit = (UINT32) toupper ((int) *ThisChar); + if (!isxdigit ((int) ThisDigit)) + { + /* Not A-F */ + + return (AE_BAD_CHARACTER); + } + + /* Convert ASCII Hex char (A-F) to value */ + + ThisDigit = (ThisDigit - 'A') + 10; + } + + /* Insert the 4-bit hex digit */ + + ReturnValue <<= 4; + ReturnValue += ThisDigit; + + ThisChar++; + DigitCount++; + if (DigitCount > 16) + { + /* Value is too large (> 64 bits/8 bytes/16 hex digits) */ + + return (AE_LIMIT); + } + } + + *ReturnInteger = ReturnValue; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetFieldValue + * + * PARAMETERS: Field - Current field list pointer + * + * RETURN: Field value + * + * DESCRIPTION: Get field value + * + *****************************************************************************/ + +char * +DtGetFieldValue ( + DT_FIELD *Field) +{ + if (!Field) + { + return (NULL); + } + + return (Field->Value); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetFieldType + * + * PARAMETERS: Info - Data table info + * + * RETURN: Field type + * + * DESCRIPTION: Get field type + * + *****************************************************************************/ + +UINT8 +DtGetFieldType ( + ACPI_DMTABLE_INFO *Info) +{ + UINT8 Type; + + + /* DT_FLAG means that this is the start of a block of flag bits */ + /* TBD - we can make these a separate opcode later */ + + if (Info->Flags & DT_FLAG) + { + return (DT_FIELD_TYPE_FLAGS_INTEGER); + } + + /* Type is based upon the opcode for this field in the info table */ + + switch (Info->Opcode) + { + case ACPI_DMT_FLAG0: + case ACPI_DMT_FLAG1: + case ACPI_DMT_FLAG2: + case ACPI_DMT_FLAG3: + case ACPI_DMT_FLAG4: + case ACPI_DMT_FLAG5: + case ACPI_DMT_FLAG6: + case ACPI_DMT_FLAG7: + case ACPI_DMT_FLAGS0: + case ACPI_DMT_FLAGS1: + case ACPI_DMT_FLAGS2: + case ACPI_DMT_FLAGS4: + + Type = DT_FIELD_TYPE_FLAG; + break; + + case ACPI_DMT_NAME4: + case ACPI_DMT_SIG: + case ACPI_DMT_NAME6: + case ACPI_DMT_NAME8: + case ACPI_DMT_STRING: + + Type = DT_FIELD_TYPE_STRING; + break; + + case ACPI_DMT_BUFFER: + case ACPI_DMT_RAW_BUFFER: + case ACPI_DMT_BUF7: + case ACPI_DMT_BUF10: + case ACPI_DMT_BUF16: + case ACPI_DMT_BUF128: + case ACPI_DMT_PCI_PATH: + + Type = DT_FIELD_TYPE_BUFFER; + break; + + case ACPI_DMT_GAS: + case ACPI_DMT_HESTNTFY: + case ACPI_DMT_IORTMEM: + + Type = DT_FIELD_TYPE_INLINE_SUBTABLE; + break; + + case ACPI_DMT_UNICODE: + + Type = DT_FIELD_TYPE_UNICODE; + break; + + case ACPI_DMT_UUID: + + Type = DT_FIELD_TYPE_UUID; + break; + + case ACPI_DMT_DEVICE_PATH: + + Type = DT_FIELD_TYPE_DEVICE_PATH; + break; + + case ACPI_DMT_LABEL: + + Type = DT_FIELD_TYPE_LABEL; + break; + + default: + + Type = DT_FIELD_TYPE_INTEGER; + break; + } + + return (Type); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetBufferLength + * + * PARAMETERS: Buffer - List of integers, + * for example "10 3A 4F 2E" + * + * RETURN: Count of integer + * + * DESCRIPTION: Get length of bytes needed to store the integers + * + *****************************************************************************/ + +UINT32 +DtGetBufferLength ( + char *Buffer) +{ + UINT32 ByteLength = 0; + + + while (*Buffer) + { + if (*Buffer == ' ') + { + ByteLength++; + + while (*Buffer == ' ') + { + Buffer++; + } + } + + Buffer++; + } + + return (++ByteLength); +} + + +/****************************************************************************** + * + * FUNCTION: DtGetFieldLength + * + * PARAMETERS: Field - Current field + * Info - Data table info + * + * RETURN: Field length + * + * DESCRIPTION: Get length of bytes needed to compile the field + * + * Note: This function must remain in sync with AcpiDmDumpTable. + * + *****************************************************************************/ + +UINT32 +DtGetFieldLength ( + DT_FIELD *Field, + ACPI_DMTABLE_INFO *Info) +{ + UINT32 ByteLength = 0; + char *Value; + + + /* Length is based upon the opcode for this field in the info table */ + + switch (Info->Opcode) + { + case ACPI_DMT_FLAG0: + case ACPI_DMT_FLAG1: + case ACPI_DMT_FLAG2: + case ACPI_DMT_FLAG3: + case ACPI_DMT_FLAG4: + case ACPI_DMT_FLAG5: + case ACPI_DMT_FLAG6: + case ACPI_DMT_FLAG7: + case ACPI_DMT_FLAGS0: + case ACPI_DMT_FLAGS1: + case ACPI_DMT_FLAGS2: + case ACPI_DMT_FLAGS4: + case ACPI_DMT_LABEL: + case ACPI_DMT_EXTRA_TEXT: + + ByteLength = 0; + break; + + case ACPI_DMT_UINT8: + case ACPI_DMT_CHKSUM: + case ACPI_DMT_SPACEID: + case ACPI_DMT_ACCWIDTH: + case ACPI_DMT_IVRS: + case ACPI_DMT_GTDT: + case ACPI_DMT_MADT: + case ACPI_DMT_PCCT: + case ACPI_DMT_PMTT: + case ACPI_DMT_SRAT: + case ACPI_DMT_ASF: + case ACPI_DMT_HESTNTYP: + case ACPI_DMT_FADTPM: + case ACPI_DMT_EINJACT: + case ACPI_DMT_EINJINST: + case ACPI_DMT_ERSTACT: + case ACPI_DMT_ERSTINST: + case ACPI_DMT_DMAR_SCOPE: + + ByteLength = 1; + break; + + case ACPI_DMT_UINT16: + case ACPI_DMT_DMAR: + case ACPI_DMT_HEST: + case ACPI_DMT_NFIT: + case ACPI_DMT_PCI_PATH: + + ByteLength = 2; + break; + + case ACPI_DMT_UINT24: + + ByteLength = 3; + break; + + case ACPI_DMT_UINT32: + case ACPI_DMT_NAME4: + case ACPI_DMT_SIG: + case ACPI_DMT_LPIT: + + ByteLength = 4; + break; + + case ACPI_DMT_UINT40: + + ByteLength = 5; + break; + + case ACPI_DMT_UINT48: + case ACPI_DMT_NAME6: + + ByteLength = 6; + break; + + case ACPI_DMT_UINT56: + case ACPI_DMT_BUF7: + + ByteLength = 7; + break; + + case ACPI_DMT_UINT64: + case ACPI_DMT_NAME8: + + ByteLength = 8; + break; + + case ACPI_DMT_STRING: + + Value = DtGetFieldValue (Field); + if (Value) + { + ByteLength = strlen (Value) + 1; + } + else + { /* At this point, this is a fatal error */ + + sprintf (MsgBuffer, "Expected \"%s\"", Info->Name); + DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); + return (0); + } + break; + + case ACPI_DMT_GAS: + + ByteLength = sizeof (ACPI_GENERIC_ADDRESS); + break; + + case ACPI_DMT_HESTNTFY: + + ByteLength = sizeof (ACPI_HEST_NOTIFY); + break; + + case ACPI_DMT_IORTMEM: + + ByteLength = sizeof (ACPI_IORT_MEMORY_ACCESS); + break; + + case ACPI_DMT_BUFFER: + case ACPI_DMT_RAW_BUFFER: + + Value = DtGetFieldValue (Field); + if (Value) + { + ByteLength = DtGetBufferLength (Value); + } + else + { /* At this point, this is a fatal error */ + + sprintf (MsgBuffer, "Expected \"%s\"", Info->Name); + DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); + return (0); + } + break; + + case ACPI_DMT_BUF10: + + ByteLength = 10; + break; + + case ACPI_DMT_BUF16: + case ACPI_DMT_UUID: + + ByteLength = 16; + break; + + case ACPI_DMT_BUF128: + + ByteLength = 128; + break; + + case ACPI_DMT_UNICODE: + + Value = DtGetFieldValue (Field); + + /* TBD: error if Value is NULL? (as below?) */ + + ByteLength = (strlen (Value) + 1) * sizeof(UINT16); + break; + + default: + + DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode"); + return (0); + } + + return (ByteLength); +} + + +/****************************************************************************** + * + * FUNCTION: DtSum + * + * PARAMETERS: DT_WALK_CALLBACK: + * Subtable - Subtable + * Context - Unused + * ReturnValue - Store the checksum of subtable + * + * RETURN: Status + * + * DESCRIPTION: Get the checksum of subtable + * + *****************************************************************************/ + +static void +DtSum ( + DT_SUBTABLE *Subtable, + void *Context, + void *ReturnValue) +{ + UINT8 Checksum; + UINT8 *Sum = ReturnValue; + + + Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length); + *Sum = (UINT8) (*Sum + Checksum); +} + + +/****************************************************************************** + * + * FUNCTION: DtSetTableChecksum + * + * PARAMETERS: ChecksumPointer - Where to return the checksum + * + * RETURN: None + * + * DESCRIPTION: Set checksum of the whole data table into the checksum field + * + *****************************************************************************/ + +void +DtSetTableChecksum ( + UINT8 *ChecksumPointer) +{ + UINT8 Checksum = 0; + UINT8 OldSum; + + + DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum); + + OldSum = *ChecksumPointer; + Checksum = (UINT8) (Checksum - OldSum); + + /* Compute the final checksum */ + + Checksum = (UINT8) (0 - Checksum); + *ChecksumPointer = Checksum; +} + + +/****************************************************************************** + * + * FUNCTION: DtSetTableLength + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Walk the subtables and set all the length fields + * + *****************************************************************************/ + +void +DtSetTableLength ( + void) +{ + DT_SUBTABLE *ParentTable; + DT_SUBTABLE *ChildTable; + + + ParentTable = Gbl_RootTable; + ChildTable = NULL; + + if (!ParentTable) + { + return; + } + + DtSetSubtableLength (ParentTable); + + while (1) + { + ChildTable = DtGetNextSubtable (ParentTable, ChildTable); + if (ChildTable) + { + if (ChildTable->LengthField) + { + DtSetSubtableLength (ChildTable); + } + + if (ChildTable->Child) + { + ParentTable = ChildTable; + ChildTable = NULL; + } + else + { + ParentTable->TotalLength += ChildTable->TotalLength; + if (ParentTable->LengthField) + { + DtSetSubtableLength (ParentTable); + } + } + } + else + { + ChildTable = ParentTable; + + if (ChildTable == Gbl_RootTable) + { + break; + } + + ParentTable = DtGetParentSubtable (ParentTable); + + ParentTable->TotalLength += ChildTable->TotalLength; + if (ParentTable->LengthField) + { + DtSetSubtableLength (ParentTable); + } + } + } +} + + +/****************************************************************************** + * + * FUNCTION: DtWalkTableTree + * + * PARAMETERS: StartTable - Subtable in the tree where walking begins + * UserFunction - Called during the walk + * Context - Passed to user function + * ReturnValue - The return value of UserFunction + * + * RETURN: None + * + * DESCRIPTION: Performs a depth-first walk of the subtable tree + * + *****************************************************************************/ + +void +DtWalkTableTree ( + DT_SUBTABLE *StartTable, + DT_WALK_CALLBACK UserFunction, + void *Context, + void *ReturnValue) +{ + DT_SUBTABLE *ParentTable; + DT_SUBTABLE *ChildTable; + + + ParentTable = StartTable; + ChildTable = NULL; + + if (!ParentTable) + { + return; + } + + UserFunction (ParentTable, Context, ReturnValue); + + while (1) + { + ChildTable = DtGetNextSubtable (ParentTable, ChildTable); + if (ChildTable) + { + UserFunction (ChildTable, Context, ReturnValue); + + if (ChildTable->Child) + { + ParentTable = ChildTable; + ChildTable = NULL; + } + } + else + { + ChildTable = ParentTable; + if (ChildTable == Gbl_RootTable) + { + break; + } + + ParentTable = DtGetParentSubtable (ParentTable); + + if (ChildTable->Peer == StartTable) + { + break; + } + } + } +} + + +/******************************************************************************* + * + * FUNCTION: UtSubtableCacheCalloc + * + * PARAMETERS: None + * + * RETURN: Pointer to the buffer. Aborts on allocation failure + * + * DESCRIPTION: Allocate a subtable object buffer. Bypass the local + * dynamic memory manager for performance reasons (This has a + * major impact on the speed of the compiler.) + * + ******************************************************************************/ + +DT_SUBTABLE * +UtSubtableCacheCalloc ( + void) +{ + ASL_CACHE_INFO *Cache; + + + if (Gbl_SubtableCacheNext >= Gbl_SubtableCacheLast) + { + /* Allocate a new buffer */ + + Cache = UtLocalCalloc (sizeof (Cache->Next) + + (sizeof (DT_SUBTABLE) * ASL_SUBTABLE_CACHE_SIZE)); + + /* Link new cache buffer to head of list */ + + Cache->Next = Gbl_SubtableCacheList; + Gbl_SubtableCacheList = Cache; + + /* Setup cache management pointers */ + + Gbl_SubtableCacheNext = ACPI_CAST_PTR (DT_SUBTABLE, Cache->Buffer); + Gbl_SubtableCacheLast = Gbl_SubtableCacheNext + ASL_SUBTABLE_CACHE_SIZE; + } + + Gbl_SubtableCount++; + return (Gbl_SubtableCacheNext++); +} + + +/******************************************************************************* + * + * FUNCTION: UtFieldCacheCalloc + * + * PARAMETERS: None + * + * RETURN: Pointer to the buffer. Aborts on allocation failure + * + * DESCRIPTION: Allocate a field object buffer. Bypass the local + * dynamic memory manager for performance reasons (This has a + * major impact on the speed of the compiler.) + * + ******************************************************************************/ + +DT_FIELD * +UtFieldCacheCalloc ( + void) +{ + ASL_CACHE_INFO *Cache; + + + if (Gbl_FieldCacheNext >= Gbl_FieldCacheLast) + { + /* Allocate a new buffer */ + + Cache = UtLocalCalloc (sizeof (Cache->Next) + + (sizeof (DT_FIELD) * ASL_FIELD_CACHE_SIZE)); + + /* Link new cache buffer to head of list */ + + Cache->Next = Gbl_FieldCacheList; + Gbl_FieldCacheList = Cache; + + /* Setup cache management pointers */ + + Gbl_FieldCacheNext = ACPI_CAST_PTR (DT_FIELD, Cache->Buffer); + Gbl_FieldCacheLast = Gbl_FieldCacheNext + ASL_FIELD_CACHE_SIZE; + } + + Gbl_FieldCount++; + return (Gbl_FieldCacheNext++); +} + + +/******************************************************************************* + * + * FUNCTION: DtDeleteCaches + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all local cache buffer blocks + * + ******************************************************************************/ + +void +DtDeleteCaches ( + void) +{ + UINT32 BufferCount; + ASL_CACHE_INFO *Next; + + + /* Field cache */ + + BufferCount = 0; + while (Gbl_FieldCacheList) + { + Next = Gbl_FieldCacheList->Next; + ACPI_FREE (Gbl_FieldCacheList); + Gbl_FieldCacheList = Next; + BufferCount++; + } + + DbgPrint (ASL_DEBUG_OUTPUT, + "%u Fields, Buffer size: %u fields (%u bytes), %u Buffers\n", + Gbl_FieldCount, ASL_FIELD_CACHE_SIZE, + (sizeof (DT_FIELD) * ASL_FIELD_CACHE_SIZE), BufferCount); + + Gbl_FieldCount = 0; + Gbl_FieldCacheNext = NULL; + Gbl_FieldCacheLast = NULL; + + /* Subtable cache */ + + BufferCount = 0; + while (Gbl_SubtableCacheList) + { + Next = Gbl_SubtableCacheList->Next; + ACPI_FREE (Gbl_SubtableCacheList); + Gbl_SubtableCacheList = Next; + BufferCount++; + } + + DbgPrint (ASL_DEBUG_OUTPUT, + "%u Subtables, Buffer size: %u subtables (%u bytes), %u Buffers\n", + Gbl_SubtableCount, ASL_SUBTABLE_CACHE_SIZE, + (sizeof (DT_SUBTABLE) * ASL_SUBTABLE_CACHE_SIZE), BufferCount); + + Gbl_SubtableCount = 0; + Gbl_SubtableCacheNext = NULL; + Gbl_SubtableCacheLast = NULL; +} diff --git a/third_party/lib/acpica/source/compiler/new_table.txt b/third_party/lib/acpica/source/compiler/new_table.txt new file mode 100644 index 000000000..1e48d385b --- /dev/null +++ b/third_party/lib/acpica/source/compiler/new_table.txt @@ -0,0 +1,88 @@ +How to add a new ACPI table to ACPICA and the iASL compiler. +------------------------------------------------------------ + +There are four main tasks that are needed to provide support for a +new ACPI table: + 1) Create a full definition of the table and any subtables + in the ACPICA headers. + 2) Add disassembler support for the new table + 3) Add iASL table compiler support for the new table + 4) Create a default template for the new table for iASL -T + option. + +Notes for each of these tasks provided below. + + +1) Header Support +----------------- + +New tables should be added to the appropriate header: + actbl2.h: Used for new tables that are not defined in the ACPI spec. + actbl3.h: Used for new tables that are defined in the ACPI spec. + +Use ACPI_TABLE_HEADER for the common ACPI table header. +Subtables should be defined separately from the main table. +Don't add placeholder fields for subtables and other multiple data items. + (Don't use xxxxx[1] for a field that can have multiple items.) + The disassembler and data table compiler depends on this. +For tables not defined in the ACPI spec, add a comment to indicate where + the table came from. +Use other table definitions for additional guidance. + + +2) iASL Disassembler Support +---------------------------- + +Add definition of the table (and subtables) in common/dmtbinfo.c +Add table access macro(s) of the form ACPI_xxxx_OFFSET +Add ACPI_DMT_TERMINATOR at the end of every table/subtable definition + +Add externals for the table/subtable definitions in acdisasm.h +Add an entry for the new table in the AcpiDmTableData in common/dmtable.c + +If there are no subtables, add the AcpiDmTableInfoXXXX name to the + AcpiDmTableData and it will automatically be disassembled. + +If there are subtables, a dump routine must be written: +Add an AcpiDmDumpXXXX function to dmtbdump.c -- note, code for another + similar table can often be ported for the new table. +Add an external for this function to acdisasm.h +Add this function to the AcpiDmTableData entry for the new ACPI table + +Debug/Test: Either find an existing example of the new ACPI table, or + create one using the "generic ACPI table support" included in the + iASL data table compiler. Use the -G option to force a + generic compile. It is often best to create the table from scratch, + since this clearly exposes the dependencies (lengths, offsets, etc.) + that the Table Compiler support will need to generate. + + +3) iASL Table Compiler Support +------------------------------ + +Simple tables do not require a compile routine. The definition of the + table in common/dmtbinfo.c (created in step 2 above) will suffice. + +Complex tables with subtables will require a compile routine with a name + of the form DtCompileXXXX. +Add a DtCompileXXXX function to the dttable.c module. +Add an external for this function in dtcompiler.h +Add this function to the AcpiDmTableData entry for the new ACPI table + in common/dmtable.c + + +4) Template Support (-T iASL option) +------------------------------------ + +Create an example of the new ACPI table. This example should create + multiple subtables (if supported), and multiple instances of any + variable length data. + +Compile the example file with the -sc option. This will create a C + array that contains the table contents. + +Add this array to the dttemplate.h file. Name the array TemplateXXXX. +Add this array name to the AcpiDmTableData entry for the new ACPI table + +Debug/Test: Create the template file. Compile the file. Disassemble the file. + Compile the disassembly file. diff --git a/third_party/lib/acpica/source/compiler/preprocess.h b/third_party/lib/acpica/source/compiler/preprocess.h new file mode 100644 index 000000000..50759b546 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/preprocess.h @@ -0,0 +1,292 @@ +/****************************************************************************** + * + * Module Name: preprocess.h - header for iASL Preprocessor + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __PREPROCESS_H__ + +#ifndef _PREPROCESS +#define _PREPROCESS + +#undef PR_EXTERN + +#ifdef _DECLARE_PR_GLOBALS +#define PR_EXTERN +#define PR_INIT_GLOBAL(a,b) (a)=(b) +#else +#define PR_EXTERN extern +#define PR_INIT_GLOBAL(a,b) (a) +#endif + + +/* + * Configuration + */ +#define PR_MAX_MACRO_ARGS 32 /* Max number of macro args */ +#define PR_MAX_ARG_INSTANCES 24 /* Max instances of any one arg */ +#define PR_LINES_PER_BLOCK 4096 /* Max input source lines per block */ + + +/* + * Local defines and macros + */ +#define PR_TOKEN_SEPARATORS " ,(){}\t\n" +#define PR_MACRO_SEPARATORS " ,(){}~!*/%+-<>=&^|\"\t\n" +#define PR_MACRO_ARGUMENTS " ,\t\n" +#define PR_EXPR_SEPARATORS " ,(){}~!*/%+-<>=&^|\"\t\n" + +#define PR_PREFIX_ID "Pr(%.4u) - " /* Used for debug output */ + +#define THIS_TOKEN_OFFSET(t) ((t-Gbl_MainTokenBuffer) + 1) + + +/* + * Preprocessor structures + */ +typedef struct pr_macro_arg +{ + char *Name; + UINT32 Offset[PR_MAX_ARG_INSTANCES]; + UINT16 UseCount; + +} PR_MACRO_ARG; + +typedef struct pr_define_info +{ + struct pr_define_info *Previous; + struct pr_define_info *Next; + char *Identifier; + char *Replacement; + char *Body; /* Macro body */ + PR_MACRO_ARG *Args; /* Macro arg list */ + UINT16 ArgCount; /* Macro arg count */ + BOOLEAN Persist; /* Keep for entire compiler run */ + +} PR_DEFINE_INFO; + +typedef struct pr_directive_info +{ + char *Name; /* Directive name */ + UINT8 ArgCount; /* Required # of args */ + +} PR_DIRECTIVE_INFO; + +typedef struct pr_operator_info +{ + char *Op; + +} PR_OPERATOR_INFO; + +typedef struct pr_file_node +{ + struct pr_file_node *Next; + FILE *File; + char *Filename; + UINT32 CurrentLineNumber; + +} PR_FILE_NODE; + +#define MAX_ARGUMENT_LENGTH 24 + +typedef struct directive_info +{ + struct directive_info *Next; + char Argument[MAX_ARGUMENT_LENGTH]; + int Directive; + BOOLEAN IgnoringThisCodeBlock; + +} DIRECTIVE_INFO; + + +/* + * Globals + */ +#if 0 /* TBD for macros */ +PR_EXTERN char PR_INIT_GLOBAL (*XXXEvalBuffer, NULL); /* [ASL_LINE_BUFFER_SIZE]; */ +#endif + +PR_EXTERN char PR_INIT_GLOBAL (*Gbl_MainTokenBuffer, NULL); /* [ASL_LINE_BUFFER_SIZE]; */ +PR_EXTERN char PR_INIT_GLOBAL (*Gbl_MacroTokenBuffer, NULL); /* [ASL_LINE_BUFFER_SIZE]; */ +PR_EXTERN char PR_INIT_GLOBAL (*Gbl_ExpressionTokenBuffer, NULL); /* [ASL_LINE_BUFFER_SIZE]; */ + +PR_EXTERN UINT32 Gbl_PreprocessorLineNumber; +PR_EXTERN int Gbl_IfDepth; +PR_EXTERN PR_FILE_NODE *Gbl_InputFileList; +PR_EXTERN PR_DEFINE_INFO PR_INIT_GLOBAL (*Gbl_DefineList, NULL); +PR_EXTERN BOOLEAN PR_INIT_GLOBAL (Gbl_PreprocessorError, FALSE); +PR_EXTERN BOOLEAN PR_INIT_GLOBAL (Gbl_IgnoringThisCodeBlock, FALSE); +PR_EXTERN DIRECTIVE_INFO PR_INIT_GLOBAL (*Gbl_DirectiveStack, NULL); + +/* + * prscan - Preprocessor entry + */ +void +PrInitializePreprocessor ( + void); + +void +PrInitializeGlobals ( + void); + +void +PrTerminatePreprocessor ( + void); + +void +PrDoPreprocess ( + void); + +UINT64 +PrIsDefined ( + char *Identifier); + +UINT64 +PrResolveDefine ( + char *Identifier); + +int +PrInitLexer ( + char *String); + +void +PrTerminateLexer ( + void); + + +/* + * prmacros - Support for #defines and macros + */ +void +PrDumpPredefinedNames ( + void); + +PR_DEFINE_INFO * +PrAddDefine ( + char *Token, + char *Token2, + BOOLEAN Persist); + +void +PrRemoveDefine ( + char *DefineName); + +PR_DEFINE_INFO * +PrMatchDefine ( + char *MatchString); + +void +PrAddMacro ( + char *Name, + char **Next); + +void +PrDoMacroInvocation ( + char *TokenBuffer, + char *MacroStart, + PR_DEFINE_INFO *DefineInfo, + char **Next); + + +/* + * prexpress - #if expression support + */ +ACPI_STATUS +PrResolveIntegerExpression ( + char *Line, + UINT64 *ReturnValue); + +char * +PrPrioritizeExpression ( + char *OriginalLine); + +/* + * prparser - lex/yacc expression parser + */ +UINT64 +PrEvaluateExpression ( + char *ExprString); + + +/* + * prutils - Preprocesor utilities + */ +char * +PrGetNextToken ( + char *Buffer, + char *MatchString, + char **Next); + +void +PrError ( + UINT8 Level, + UINT16 MessageId, + UINT32 Column); + +void +PrReplaceData ( + char *Buffer, + UINT32 LengthToRemove, + char *BufferToAdd, + UINT32 LengthToAdd); + +FILE * +PrOpenIncludeFile ( + char *Filename, + char *OpenMode, + char **FullPathname); + +FILE * +PrOpenIncludeWithPrefix ( + char *PrefixDir, + char *Filename, + char *OpenMode, + char **FullPathname); + +void +PrPushInputFileStack ( + FILE *InputFile, + char *Filename); + +BOOLEAN +PrPopInputFileStack ( + void); + +#endif diff --git a/third_party/lib/acpica/source/compiler/prexpress.c b/third_party/lib/acpica/source/compiler/prexpress.c new file mode 100644 index 000000000..b6bc801f2 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/prexpress.c @@ -0,0 +1,306 @@ +/****************************************************************************** + * + * Module Name: prexpress - Preprocessor #if expression support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + + +#define _COMPONENT ASL_PREPROCESSOR + ACPI_MODULE_NAME ("prexpress") + +/* Local prototypes */ + +static char * +PrExpandMacros ( + char *Line); + + +#ifdef _UNDER_DEVELOPMENT +/****************************************************************************** + * + * FUNCTION: PrUnTokenize + * + * PARAMETERS: Buffer - Token Buffer + * Next - "Next" buffer from GetNextToken + * + * RETURN: None + * + * DESCRIPTION: Un-tokenized the current token buffer. The implementation is + * to simply set the null inserted by GetNextToken to a blank. + * If Next is NULL, there were no tokens found in the Buffer, + * so there is nothing to do. + * + *****************************************************************************/ + +static void +PrUnTokenize ( + char *Buffer, + char *Next) +{ + UINT32 Length = strlen (Buffer); + + + if (!Next) + { + return; + } + + if (Buffer[Length] != '\n') + { + Buffer[strlen(Buffer)] = ' '; + } +} +#endif + + +/****************************************************************************** + * + * FUNCTION: PrExpandMacros + * + * PARAMETERS: Line - Pointer into the current line + * + * RETURN: Updated pointer into the current line + * + * DESCRIPTION: Expand any macros found in the current line buffer. + * + *****************************************************************************/ + +static char * +PrExpandMacros ( + char *Line) +{ + char *Token; + char *ReplaceString; + PR_DEFINE_INFO *DefineInfo; + ACPI_SIZE TokenOffset; + char *Next; + int OffsetAdjust; + + + strcpy (Gbl_ExpressionTokenBuffer, Gbl_CurrentLineBuffer); + Token = PrGetNextToken (Gbl_ExpressionTokenBuffer, PR_EXPR_SEPARATORS, &Next); + OffsetAdjust = 0; + + while (Token) + { + DefineInfo = PrMatchDefine (Token); + if (DefineInfo) + { + if (DefineInfo->Body) + { + /* This is a macro. TBD: Is this allowed? */ + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Matched Macro: %s->%s\n", + Gbl_CurrentLineNumber, DefineInfo->Identifier, + DefineInfo->Replacement); + + PrDoMacroInvocation (Gbl_ExpressionTokenBuffer, Token, + DefineInfo, &Next); + } + else + { + ReplaceString = DefineInfo->Replacement; + + /* Replace the name in the original line buffer */ + + TokenOffset = Token - Gbl_ExpressionTokenBuffer + OffsetAdjust; + PrReplaceData ( + &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token), + ReplaceString, strlen (ReplaceString)); + + /* Adjust for length difference between old and new name length */ + + OffsetAdjust += strlen (ReplaceString) - strlen (Token); + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Matched #define within expression: %s->%s\n", + Gbl_CurrentLineNumber, Token, + *ReplaceString ? ReplaceString : "(NULL STRING)"); + } + } + + Token = PrGetNextToken (NULL, PR_EXPR_SEPARATORS, &Next); + } + + return (Line); +} + + +/****************************************************************************** + * + * FUNCTION: PrIsDefined + * + * PARAMETERS: Identifier - Name to be resolved + * + * RETURN: 64-bit boolean integer value + * + * DESCRIPTION: Returns TRUE if the name is defined, FALSE otherwise (0). + * + *****************************************************************************/ + +UINT64 +PrIsDefined ( + char *Identifier) +{ + UINT64 Value; + PR_DEFINE_INFO *DefineInfo; + + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "**** Is defined?: %s\n", Gbl_CurrentLineNumber, Identifier); + + Value = 0; /* Default is "Not defined" -- FALSE */ + + DefineInfo = PrMatchDefine (Identifier); + if (DefineInfo) + { + Value = ACPI_UINT64_MAX; /* TRUE */ + } + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "[#if defined %s] resolved to: %8.8X%8.8X\n", + Gbl_CurrentLineNumber, Identifier, ACPI_FORMAT_UINT64 (Value)); + + return (Value); +} + + +/****************************************************************************** + * + * FUNCTION: PrResolveDefine + * + * PARAMETERS: Identifier - Name to be resolved + * + * RETURN: A 64-bit boolean integer value + * + * DESCRIPTION: Returns TRUE if the name is defined, FALSE otherwise (0). + * + *****************************************************************************/ + +UINT64 +PrResolveDefine ( + char *Identifier) +{ + UINT64 Value; + PR_DEFINE_INFO *DefineInfo; + + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "**** Resolve #define: %s\n", Gbl_CurrentLineNumber, Identifier); + + Value = 0; /* Default is "Not defined" -- FALSE */ + + DefineInfo = PrMatchDefine (Identifier); + if (DefineInfo) + { + Value = ACPI_UINT64_MAX; /* TRUE */ + } + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "[#if defined %s] resolved to: %8.8X%8.8X\n", + Gbl_CurrentLineNumber, Identifier, ACPI_FORMAT_UINT64 (Value)); + + return (Value); +} + + +/****************************************************************************** + * + * FUNCTION: PrResolveIntegerExpression + * + * PARAMETERS: Line - Pointer to integer expression + * ReturnValue - Where the resolved 64-bit integer is + * returned. + * + * RETURN: Status + * + * DESCRIPTION: Resolve an integer expression to a single value. Supports + * both integer constants and labels. + * + *****************************************************************************/ + +ACPI_STATUS +PrResolveIntegerExpression ( + char *Line, + UINT64 *ReturnValue) +{ + UINT64 Result; + char *ExpandedLine; + + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "**** Resolve #if: %s\n", Gbl_CurrentLineNumber, Line); + + /* Expand all macros within the expression first */ + + ExpandedLine = PrExpandMacros (Line); + + /* Now we can evaluate the expression */ + + Result = PrEvaluateExpression (ExpandedLine); + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "**** Expression Resolved to: %8.8X%8.8X\n", + Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Result)); + + *ReturnValue = Result; + return (AE_OK); + +#if 0 +InvalidExpression: + + ACPI_FREE (EvalBuffer); + PrError (ASL_ERROR, ASL_MSG_INVALID_EXPRESSION, 0); + return (AE_ERROR); + + +NormalExit: + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "**** Expression Resolved to: %8.8X%8.8X\n", + Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value1)); + + *ReturnValue = Value1; + return (AE_OK); +#endif +} diff --git a/third_party/lib/acpica/source/compiler/prmacros.c b/third_party/lib/acpica/source/compiler/prmacros.c new file mode 100644 index 000000000..8ad923613 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/prmacros.c @@ -0,0 +1,582 @@ +/****************************************************************************** + * + * Module Name: prmacros - Preprocessor #define macro support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + + +#define _COMPONENT ASL_PREPROCESSOR + ACPI_MODULE_NAME ("prmacros") + + +/******************************************************************************* + * + * FUNCTION: PrDumpPredefinedNames + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump the list of #defines. Used as the preprocessor starts, to + * display the names that were defined on the command line. + * Debug information only. + * + ******************************************************************************/ + +void +PrDumpPredefinedNames ( + void) +{ + PR_DEFINE_INFO *DefineInfo; + + + DefineInfo = Gbl_DefineList; + while (DefineInfo) + { + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Predefined #define: %s->%s\n", + 0, DefineInfo->Identifier, DefineInfo->Replacement); + + DefineInfo = DefineInfo->Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: PrAddDefine + * + * PARAMETERS: Identifier - Name to be replaced + * Replacement - Replacement for Identifier + * Persist - Keep define across multiple compiles? + * + * RETURN: A new define_info struct. NULL on error. + * + * DESCRIPTION: Add a new #define to the global list + * + ******************************************************************************/ + +PR_DEFINE_INFO * +PrAddDefine ( + char *Identifier, + char *Replacement, + BOOLEAN Persist) +{ + char *IdentifierString; + char *ReplacementString; + PR_DEFINE_INFO *DefineInfo; + + + if (!Replacement) + { + Replacement = ""; + } + + /* Check for already-defined first */ + + DefineInfo = PrMatchDefine (Identifier); + if (DefineInfo) + { + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID, + "#define: name already exists: %s\n", + Gbl_CurrentLineNumber, Identifier); + + /* + * Name already exists. This is only an error if the target name + * is different. + */ + if (strcmp (Replacement, DefineInfo->Replacement)) + { + PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME, + THIS_TOKEN_OFFSET (Identifier)); + + return (NULL); + } + + return (DefineInfo); + } + + /* Copy input strings */ + + IdentifierString = UtLocalCalloc (strlen (Identifier) + 1); + strcpy (IdentifierString, Identifier); + + ReplacementString = UtLocalCalloc (strlen (Replacement) + 1); + strcpy (ReplacementString, Replacement); + + /* Init and link new define info struct */ + + DefineInfo = UtLocalCalloc (sizeof (PR_DEFINE_INFO)); + DefineInfo->Replacement = ReplacementString; + DefineInfo->Identifier = IdentifierString; + DefineInfo->Persist = Persist; + + if (Gbl_DefineList) + { + Gbl_DefineList->Previous = DefineInfo; + } + + DefineInfo->Next = Gbl_DefineList; + Gbl_DefineList = DefineInfo; + return (DefineInfo); +} + + +/******************************************************************************* + * + * FUNCTION: PrRemoveDefine + * + * PARAMETERS: DefineName - Name of define to be removed + * + * RETURN: None + * + * DESCRIPTION: Implements #undef. Remove a #define if found in the global + * list. No error if the target of the #undef does not exist, + * as per the C #undef definition. + * + ******************************************************************************/ + +void +PrRemoveDefine ( + char *DefineName) +{ + PR_DEFINE_INFO *DefineInfo; + + + /* Match name and delete the node */ + + DefineInfo = Gbl_DefineList; + while (DefineInfo) + { + if (!strcmp (DefineName, DefineInfo->Identifier)) + { + /* Remove from linked list */ + + if (DefineInfo->Previous) + { + (DefineInfo->Previous)->Next = DefineInfo->Next; + } + else + { + Gbl_DefineList = DefineInfo->Next; + } + + if (DefineInfo->Next) + { + (DefineInfo->Next)->Previous = DefineInfo->Previous; + } + + free (DefineInfo); + return; + } + + DefineInfo = DefineInfo->Next; + } + + /* + * Name was not found. By definition of #undef, this is not + * an error, however. + */ + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "#undef: could not find %s\n", + Gbl_CurrentLineNumber, DefineName); +} + + +/******************************************************************************* + * + * FUNCTION: PrMatchDefine + * + * PARAMETERS: MatchString - Name associated with the #define + * + * RETURN: Matched string if found. NULL otherwise. + * + * DESCRIPTION: Find a name in global #define list + * + ******************************************************************************/ + +PR_DEFINE_INFO * +PrMatchDefine ( + char *MatchString) +{ + PR_DEFINE_INFO *DefineInfo; + + + DefineInfo = Gbl_DefineList; + while (DefineInfo) + { + if (!strcmp (MatchString, DefineInfo->Identifier)) + { + return (DefineInfo); + } + + DefineInfo = DefineInfo->Next; + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: PrAddMacro + * + * PARAMETERS: Name - Start of the macro definition + * Next - "Next" buffer from GetNextToken + * + * RETURN: None + * + * DESCRIPTION: Add a new macro to the list of #defines. Handles argument + * processing. + * + ******************************************************************************/ + +void +PrAddMacro ( + char *Name, + char **Next) +{ + char *Token = NULL; + ACPI_SIZE TokenOffset; + ACPI_SIZE MacroBodyOffset; + PR_DEFINE_INFO *DefineInfo; + PR_MACRO_ARG *Args; + char *Body; + char *BodyInSource; + UINT32 i; + UINT16 UseCount = 0; + UINT16 ArgCount = 0; + UINT32 Depth = 1; + UINT32 EndOfArgList; + char BufferChar; + + + /* Find the end of the arguments list */ + + TokenOffset = Name - Gbl_MainTokenBuffer + strlen (Name) + 1; + while (1) + { + BufferChar = Gbl_CurrentLineBuffer[TokenOffset]; + if (BufferChar == '(') + { + Depth++; + } + else if (BufferChar == ')') + { + Depth--; + } + else if (BufferChar == 0) + { + PrError (ASL_ERROR, ASL_MSG_MACRO_SYNTAX, TokenOffset); + return; + } + + if (Depth == 0) + { + /* Found arg list end */ + + EndOfArgList = TokenOffset; + break; + } + + TokenOffset++; + } + + /* At this point, we know that we have a reasonable argument list */ + + Args = UtLocalCalloc (sizeof (PR_MACRO_ARG) * PR_MAX_MACRO_ARGS); + + /* Get the macro argument names */ + + for (i = 0; i < PR_MAX_MACRO_ARGS; i++) + { + Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); + if (!Token) + { + /* This is the case for a NULL macro body */ + + BodyInSource = ""; + goto AddMacroToList; + } + + /* Don't go beyond the argument list */ + + TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token); + if (TokenOffset > EndOfArgList) + { + break; + } + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Macro arg: %s \n", + Gbl_CurrentLineNumber, Token); + + Args[i].Name = UtLocalCalloc (strlen (Token) + 1); + strcpy (Args[i].Name, Token); + + Args[i].UseCount = 0; + + ArgCount++; + if (ArgCount >= PR_MAX_MACRO_ARGS) + { + PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, TokenOffset); + goto ErrorExit; + } + } + + /* Get the macro body. Token now points to start of body */ + + MacroBodyOffset = Token - Gbl_MainTokenBuffer; + + /* Match each method arg in the macro body for later use */ + + Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); + while (Token) + { + /* Search the macro arg list for matching arg */ + + for (i = 0; Args[i].Name && (i < PR_MAX_MACRO_ARGS); i++) + { + /* + * Save argument offset within macro body. This is the mechanism + * used to expand the macro upon invocation. + * + * Handles multiple instances of the same argument + */ + if (!strcmp (Token, Args[i].Name)) + { + UseCount = Args[i].UseCount; + + Args[i].Offset[UseCount] = + (Token - Gbl_MainTokenBuffer) - MacroBodyOffset; + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Macro Arg #%u: %s UseCount %u Offset %u \n", + Gbl_CurrentLineNumber, i, Token, + UseCount+1, Args[i].Offset[UseCount]); + + Args[i].UseCount++; + if (Args[i].UseCount >= PR_MAX_ARG_INSTANCES) + { + PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, + THIS_TOKEN_OFFSET (Token)); + + goto ErrorExit; + } + break; + } + } + + Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); + } + + BodyInSource = &Gbl_CurrentLineBuffer[MacroBodyOffset]; + + +AddMacroToList: + + /* Check if name is already defined first */ + + DefineInfo = PrMatchDefine (Name); + if (DefineInfo) + { + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "#define: macro name already exists: %s\n", + Gbl_CurrentLineNumber, Name); + + /* Error only if not exactly the same macro */ + + if (strcmp (DefineInfo->Body, BodyInSource) || + (DefineInfo->ArgCount != ArgCount)) + { + PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME, + THIS_TOKEN_OFFSET (Name)); + } + + goto ErrorExit; + } + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Macro body: %s \n", + Gbl_CurrentLineNumber, BodyInSource); + + /* Add macro to the #define list */ + + DefineInfo = PrAddDefine (Name, BodyInSource, FALSE); + if (DefineInfo) + { + Body = UtLocalCalloc (strlen (BodyInSource) + 1); + strcpy (Body, BodyInSource); + + DefineInfo->Body = Body; + DefineInfo->Args = Args; + DefineInfo->ArgCount = ArgCount; + } + + return; + + +ErrorExit: + ACPI_FREE (Args); + return; +} + + +/******************************************************************************* + * + * FUNCTION: PrDoMacroInvocation + * + * PARAMETERS: TokenBuffer - Current line buffer + * MacroStart - Start of the macro invocation within + * the token buffer + * DefineInfo - Info for this macro + * Next - "Next" buffer from GetNextToken + * + * RETURN: None + * + * DESCRIPTION: Expand a macro invocation + * + ******************************************************************************/ + +void +PrDoMacroInvocation ( + char *TokenBuffer, + char *MacroStart, + PR_DEFINE_INFO *DefineInfo, + char **Next) +{ + PR_MACRO_ARG *Args; + char *Token = NULL; + UINT32 TokenOffset; + UINT32 Length; + UINT32 i; + + + /* Take a copy of the macro body for expansion */ + + strcpy (Gbl_MacroTokenBuffer, DefineInfo->Body); + + /* Replace each argument within the prototype body */ + + Args = DefineInfo->Args; + if (!Args->Name) + { + /* This macro has no arguments */ + + Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next); + if (!Token) + { + goto BadInvocation; + } + + TokenOffset = (MacroStart - TokenBuffer); + Length = Token - MacroStart + strlen (Token) + 1; + + PrReplaceData ( + &Gbl_CurrentLineBuffer[TokenOffset], Length, + Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer)); + return; + } + + while (Args->Name) + { + /* Get the next argument from macro invocation */ + + Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); + if (!Token) + { + goto BadInvocation; + } + + /* Replace all instances of this argument */ + + for (i = 0; i < Args->UseCount; i++) + { + /* Offset zero indicates "arg not used" */ + /* TBD: Not really needed now, with UseCount available */ + + if (Args->Offset[i] == 0) + { + break; + } + + PrReplaceData ( + &Gbl_MacroTokenBuffer[Args->Offset[i]], strlen (Args->Name), + Token, strlen (Token)); + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "ExpandArg: %s \n", + Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer); + } + + Args++; + } + + /* TBD: need to make sure macro was not invoked with too many arguments */ + + if (!Token) + { + return; + } + + /* Replace the entire macro invocation with the expanded macro */ + + TokenOffset = (MacroStart - TokenBuffer); + Length = Token - MacroStart + strlen (Token) + 1; + + PrReplaceData ( + &Gbl_CurrentLineBuffer[TokenOffset], Length, + Gbl_MacroTokenBuffer, strlen (Gbl_MacroTokenBuffer)); + + return; + + +BadInvocation: + PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION, + THIS_TOKEN_OFFSET (MacroStart)); + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Bad macro invocation: %s \n", + Gbl_CurrentLineNumber, Gbl_MacroTokenBuffer); + return; +} diff --git a/third_party/lib/acpica/source/compiler/prparser.l b/third_party/lib/acpica/source/compiler/prparser.l new file mode 100644 index 000000000..305669911 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/prparser.l @@ -0,0 +1,236 @@ +%{ +/****************************************************************************** + * + * Module Name: prparser.l - Flex input file for preprocessor lexer + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "prparser.y.h" + +/* Buffer to pass strings to the parser */ + +#define STRING_SETUP strcpy (StringBuffer, PrParsertext);\ + PrParserlval.str = StringBuffer + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("prscanner") + + +/* Local prototypes */ + +static char +PrDoCommentType1 ( + void); + +static char +PrDoCommentType2 ( + void); +%} + +%option noyywrap + +Number [0-9a-fA-F]+ +HexNumber 0[xX][0-9a-fA-F]+ +WhiteSpace [ \t\v\r]+ +NewLine [\n] +Identifier [a-zA-Z][0-9a-zA-Z]* + +%% +"/*" { if (!PrDoCommentType1 ()) {yyterminate ();} } +"//" { if (!PrDoCommentType2 ()) {yyterminate ();} } + +\( return (EXPOP_PAREN_OPEN); +\) return (EXPOP_PAREN_CLOSE); +\~ return (EXPOP_ONES_COMPLIMENT); +\! return (EXPOP_LOGICAL_NOT); +\* return (EXPOP_MULTIPLY); +\/ return (EXPOP_DIVIDE); +\% return (EXPOP_MODULO); +\+ return (EXPOP_ADD); +\- return (EXPOP_SUBTRACT); +">>" return (EXPOP_SHIFT_RIGHT); +"<<" return (EXPOP_SHIFT_LEFT); +\< return (EXPOP_LESS); +\> return (EXPOP_GREATER); +"<=" return (EXPOP_LESS_EQUAL); +">=" return (EXPOP_GREATER_EQUAL); +"==" return (EXPOP_EQUAL); +"!=" return (EXPOP_NOT_EQUAL); +\& return (EXPOP_AND); +\^ return (EXPOP_XOR); +\| return (EXPOP_OR); +"&&" return (EXPOP_LOGICAL_AND); +"||" return (EXPOP_LOGICAL_OR); + +"defined" return (EXPOP_DEFINE); +{Identifier} {STRING_SETUP; return (EXPOP_IDENTIFIER);} + +<> return (EXPOP_EOF); /* null end-of-string */ + +{Number} return (EXPOP_NUMBER); +{HexNumber} return (EXPOP_HEX_NUMBER); +{NewLine} return (EXPOP_NEW_LINE); +{WhiteSpace} /* Ignore */ + +. return (EXPOP_EOF); +%% + +/* + * Local support functions + */ +YY_BUFFER_STATE LexBuffer; + + +/****************************************************************************** + * + * FUNCTION: PrInitLexer + * + * PARAMETERS: String - Input string to be parsed + * + * RETURN: TRUE if parser returns NULL. FALSE otherwise. + * + * DESCRIPTION: Initialization routine for lexer. The lexer needs + * a buffer to handle strings instead of a file. + * + *****************************************************************************/ + +int +PrInitLexer ( + char *String) +{ + + LexBuffer = yy_scan_string (String); + return (LexBuffer == NULL); +} + + +/****************************************************************************** + * + * FUNCTION: PrTerminateLexer + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Termination routine for thelexer. + * + *****************************************************************************/ + +void +PrTerminateLexer ( + void) +{ + + yy_delete_buffer (LexBuffer); +} + + +/******************************************************************************** + * + * FUNCTION: PrDoCommentType1 + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Process a new legacy comment. Just toss it. + * + ******************************************************************************/ + +static char +PrDoCommentType1 ( + void) +{ + int c; + + +Loop: + while (((c = input ()) != '*') && (c != EOF)) + { + } + if (c == EOF) + { + return (FALSE); + } + + if (((c = input ()) != '/') && (c != EOF)) + { + unput (c); + goto Loop; + } + if (c == EOF) + { + return (FALSE); + } + + return (TRUE); +} + + +/******************************************************************************** + * + * FUNCTION: PrDoCommentType2 + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Process a new "//" comment. Just toss it. + * + ******************************************************************************/ + +static char +PrDoCommentType2 ( + void) +{ + int c; + + + while (((c = input ()) != '\n') && (c != EOF)) + { + } + if (c == EOF) + { + return (FALSE); + } + + return (TRUE); +} diff --git a/third_party/lib/acpica/source/compiler/prparser.y b/third_party/lib/acpica/source/compiler/prparser.y new file mode 100644 index 000000000..081976920 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/prparser.y @@ -0,0 +1,294 @@ +%{ +/****************************************************************************** + * + * Module Name: prparser.y - Bison input file for preprocessor parser + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + +#define _COMPONENT ASL_PREPROCESSOR + ACPI_MODULE_NAME ("prparser") + +void * AslLocalAllocate (unsigned int Size); + +/* Bison/yacc configuration */ + +#undef alloca +#define alloca AslLocalAllocate + +int PrParserlex (void); +int PrParserparse (void); +void PrParsererror (char const *msg); +extern char *PrParsertext; + +UINT64 PrParserResult; /* Expression return value */ + +/* Bison/yacc configuration */ + +#define yytname PrParsername +#define YYDEBUG 1 /* Enable debug output */ +#define YYERROR_VERBOSE 1 /* Verbose error messages */ +#define YYFLAG -32768 + +/* Define YYMALLOC/YYFREE to prevent redefinition errors */ + +#define YYMALLOC malloc +#define YYFREE free +%} + +%union +{ + UINT64 value; + UINT32 op; + char *str; +} + +/*! [Begin] no source code translation */ + +%type Expression + +%token EXPOP_EOF +%token EXPOP_NEW_LINE +%token EXPOP_NUMBER +%token EXPOP_HEX_NUMBER +%token EXPOP_RESERVED1 +%token EXPOP_RESERVED2 +%token EXPOP_PAREN_OPEN +%token EXPOP_PAREN_CLOSE + +%left EXPOP_LOGICAL_OR +%left EXPOP_LOGICAL_AND +%left EXPOP_OR +%left EXPOP_XOR +%left EXPOP_AND +%left EXPOP_EQUAL EXPOP_NOT_EQUAL +%left EXPOP_GREATER EXPOP_LESS EXPOP_GREATER_EQUAL EXPOP_LESS_EQUAL +%left EXPOP_SHIFT_RIGHT EXPOP_SHIFT_LEFT +%left EXPOP_ADD EXPOP_SUBTRACT +%left EXPOP_MULTIPLY EXPOP_DIVIDE EXPOP_MODULO +%right EXPOP_ONES_COMPLIMENT EXPOP_LOGICAL_NOT + +/* Tokens above must be kept in synch with dtparser.y */ + +%token EXPOP_DEFINE +%token EXPOP_IDENTIFIER + +%% + +/* + * Operator precedence rules (from K&R) + * + * 1) ( ) + * 2) ! ~ (unary operators that are supported here) + * 3) * / % + * 4) + - + * 5) >> << + * 6) < > <= >= + * 7) == != + * 8) & + * 9) ^ + * 10) | + * 11) && + * 12) || + */ + +/*! [End] no source code translation !*/ + +Value + : Expression EXPOP_NEW_LINE { PrParserResult=$1; return 0; } /* End of line (newline) */ + | Expression EXPOP_EOF { PrParserResult=$1; return 0; } /* End of string (0) */ + ; + +Expression + + /* Unary operators */ + + : EXPOP_LOGICAL_NOT Expression { $$ = DtDoOperator ($2, EXPOP_LOGICAL_NOT, $2);} + | EXPOP_ONES_COMPLIMENT Expression { $$ = DtDoOperator ($2, EXPOP_ONES_COMPLIMENT, $2);} + + /* Binary operators */ + + | Expression EXPOP_MULTIPLY Expression { $$ = DtDoOperator ($1, EXPOP_MULTIPLY, $3);} + | Expression EXPOP_DIVIDE Expression { $$ = DtDoOperator ($1, EXPOP_DIVIDE, $3);} + | Expression EXPOP_MODULO Expression { $$ = DtDoOperator ($1, EXPOP_MODULO, $3);} + | Expression EXPOP_ADD Expression { $$ = DtDoOperator ($1, EXPOP_ADD, $3);} + | Expression EXPOP_SUBTRACT Expression { $$ = DtDoOperator ($1, EXPOP_SUBTRACT, $3);} + | Expression EXPOP_SHIFT_RIGHT Expression { $$ = DtDoOperator ($1, EXPOP_SHIFT_RIGHT, $3);} + | Expression EXPOP_SHIFT_LEFT Expression { $$ = DtDoOperator ($1, EXPOP_SHIFT_LEFT, $3);} + | Expression EXPOP_GREATER Expression { $$ = DtDoOperator ($1, EXPOP_GREATER, $3);} + | Expression EXPOP_LESS Expression { $$ = DtDoOperator ($1, EXPOP_LESS, $3);} + | Expression EXPOP_GREATER_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_GREATER_EQUAL, $3);} + | Expression EXPOP_LESS_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_LESS_EQUAL, $3);} + | Expression EXPOP_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_EQUAL, $3);} + | Expression EXPOP_NOT_EQUAL Expression { $$ = DtDoOperator ($1, EXPOP_NOT_EQUAL, $3);} + | Expression EXPOP_AND Expression { $$ = DtDoOperator ($1, EXPOP_AND, $3);} + | Expression EXPOP_XOR Expression { $$ = DtDoOperator ($1, EXPOP_XOR, $3);} + | Expression EXPOP_OR Expression { $$ = DtDoOperator ($1, EXPOP_OR, $3);} + | Expression EXPOP_LOGICAL_AND Expression { $$ = DtDoOperator ($1, EXPOP_LOGICAL_AND, $3);} + | Expression EXPOP_LOGICAL_OR Expression { $$ = DtDoOperator ($1, EXPOP_LOGICAL_OR, $3);} + + /* Parentheses: '(' Expression ')' */ + + | EXPOP_PAREN_OPEN Expression + EXPOP_PAREN_CLOSE { $$ = $2;} + + /* #if defined (ID) or #if defined ID */ + + | EXPOP_DEFINE EXPOP_PAREN_OPEN EXPOP_IDENTIFIER + EXPOP_PAREN_CLOSE { $$ = PrIsDefined (PrParserlval.str);} + + | EXPOP_DEFINE EXPOP_IDENTIFIER { $$ = PrIsDefined (PrParserlval.str);} + + | EXPOP_IDENTIFIER { $$ = PrResolveDefine (PrParserlval.str);} + + /* Default base for a non-prefixed integer is 10 */ + + | EXPOP_NUMBER { stroul64 (PrParsertext, 10, &$$);} + + /* Standard hex number (0x1234) */ + + | EXPOP_HEX_NUMBER { stroul64 (PrParsertext, 16, &$$);} + ; +%% + +/* + * Local support functions, including parser entry point + */ +#define PR_FIRST_PARSE_OPCODE EXPOP_EOF +#define PR_YYTNAME_START 3 + + +/****************************************************************************** + * + * FUNCTION: PrParsererror + * + * PARAMETERS: Message - Parser-generated error message + * + * RETURN: None + * + * DESCRIPTION: Handler for parser errors + * + *****************************************************************************/ + +void +PrParsererror ( + char const *Message) +{ + + sprintf (StringBuffer, "Preprocessor Parser : %s (near line %u)", + Message, Gbl_CurrentLineNumber); + DtError (ASL_ERROR, ASL_MSG_SYNTAX, + NULL, (char *) StringBuffer); +} + + +/****************************************************************************** + * + * FUNCTION: PrGetOpName + * + * PARAMETERS: ParseOpcode - Parser token (EXPOP_*) + * + * RETURN: Pointer to the opcode name + * + * DESCRIPTION: Get the ascii name of the parse opcode for debug output + * + *****************************************************************************/ + +char * +PrGetOpName ( + UINT32 ParseOpcode) +{ +#ifdef ASL_YYTNAME_START + /* + * First entries (PR_YYTNAME_START) in yytname are special reserved names. + * Ignore first 6 characters of name (EXPOP_) + */ + return ((char *) yytname + [(ParseOpcode - PR_FIRST_PARSE_OPCODE) + PR_YYTNAME_START] + 6); +#else + return ("[Unknown parser generator]"); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: PrEvaluateExpression + * + * PARAMETERS: ExprString - Expression to be evaluated. Must be + * terminated by either a newline or a NUL + * string terminator + * + * RETURN: 64-bit value for the expression + * + * DESCRIPTION: Main entry point for the DT expression parser + * + *****************************************************************************/ + +UINT64 +PrEvaluateExpression ( + char *ExprString) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, + "**** Input expression: %s\n", ExprString); + + /* Point lexer to the input string */ + + if (PrInitLexer (ExprString)) + { + DtError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, + NULL, "Could not initialize lexer"); + return (0); + } + + /* Parse/Evaluate the input string (value returned in PrParserResult) */ + + PrParserparse (); + PrTerminateLexer (); + + DbgPrint (ASL_DEBUG_OUTPUT, + "**** Parser returned value: %u (%8.8X%8.8X)\n", + (UINT32) PrParserResult, ACPI_FORMAT_UINT64 (PrParserResult)); + + return (PrParserResult); +} diff --git a/third_party/lib/acpica/source/compiler/prscan.c b/third_party/lib/acpica/source/compiler/prscan.c new file mode 100644 index 000000000..e96fba5c3 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/prscan.c @@ -0,0 +1,1256 @@ +/****************************************************************************** + * + * Module Name: prscan - Preprocessor start-up and file scan module + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define _DECLARE_PR_GLOBALS + +#include "aslcompiler.h" +#include "dtcompiler.h" + +/* + * TBDs: + * + * No nested macros, maybe never + * Implement ASL "Include" as well as "#include" here? + */ +#define _COMPONENT ASL_PREPROCESSOR + ACPI_MODULE_NAME ("prscan") + + +/* Local prototypes */ + +static void +PrPreprocessInputFile ( + void); + +static void +PrDoDirective ( + char *DirectiveToken, + char **Next); + +static void +PrGetNextLineInit ( + void); + +static UINT32 +PrGetNextLine ( + FILE *Handle); + +static int +PrMatchDirective ( + char *Directive); + +static void +PrPushDirective ( + int Directive, + char *Argument); + +static ACPI_STATUS +PrPopDirective ( + void); + +static void +PrDbgPrint ( + char *Action, + char *DirectiveName); + +static void +PrDoIncludeBuffer ( + char *Pathname, + char *BufferName); + +static void +PrDoIncludeFile ( + char *Pathname); + + +/* + * Supported preprocessor directives + * Each entry is of the form "Name, ArgumentCount" + */ +static const PR_DIRECTIVE_INFO Gbl_DirectiveInfo[] = +{ + {"define", 1}, + {"elif", 0}, /* Converted to #else..#if internally */ + {"else", 0}, + {"endif", 0}, + {"error", 1}, + {"if", 1}, + {"ifdef", 1}, + {"ifndef", 1}, + {"include", 0}, /* Argument is not standard format, so just use 0 here */ + {"includebuffer", 0}, /* Argument is not standard format, so just use 0 here */ + {"line", 1}, + {"pragma", 1}, + {"undef", 1}, + {"warning", 1}, + {NULL, 0} +}; + +/* This table must match ordering of above table exactly */ + +enum Gbl_DirectiveIndexes +{ + PR_DIRECTIVE_DEFINE = 0, + PR_DIRECTIVE_ELIF, + PR_DIRECTIVE_ELSE, + PR_DIRECTIVE_ENDIF, + PR_DIRECTIVE_ERROR, + PR_DIRECTIVE_IF, + PR_DIRECTIVE_IFDEF, + PR_DIRECTIVE_IFNDEF, + PR_DIRECTIVE_INCLUDE, + PR_DIRECTIVE_INCLUDEBUFFER, + PR_DIRECTIVE_LINE, + PR_DIRECTIVE_PRAGMA, + PR_DIRECTIVE_UNDEF, + PR_DIRECTIVE_WARNING +}; + +#define ASL_DIRECTIVE_NOT_FOUND -1 + + +/******************************************************************************* + * + * FUNCTION: PrInitializePreprocessor + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Startup initialization for the Preprocessor. + * + ******************************************************************************/ + +void +PrInitializePreprocessor ( + void) +{ + /* Init globals and the list of #defines */ + + PrInitializeGlobals (); + Gbl_DefineList = NULL; +} + + +/******************************************************************************* + * + * FUNCTION: PrInitializeGlobals + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup + * initialization and re-initialization between compiles during + * a multiple source file compile. + * + ******************************************************************************/ + +void +PrInitializeGlobals ( + void) +{ + /* Init globals */ + + Gbl_InputFileList = NULL; + Gbl_CurrentLineNumber = 1; + Gbl_PreprocessorLineNumber = 1; + Gbl_PreprocessorError = FALSE; + + /* These are used to track #if/#else blocks (possibly nested) */ + + Gbl_IfDepth = 0; + Gbl_IgnoringThisCodeBlock = FALSE; + Gbl_DirectiveStack = NULL; +} + + +/******************************************************************************* + * + * FUNCTION: PrTerminatePreprocessor + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any + * defines that were specified on the command line, in order to + * support multiple compiles with a single compiler invocation. + * + ******************************************************************************/ + +void +PrTerminatePreprocessor ( + void) +{ + PR_DEFINE_INFO *DefineInfo; + + + /* + * The persistent defines (created on the command line) are always at the + * end of the list. We save them. + */ + while ((Gbl_DefineList) && (!Gbl_DefineList->Persist)) + { + DefineInfo = Gbl_DefineList; + Gbl_DefineList = DefineInfo->Next; + + ACPI_FREE (DefineInfo->Replacement); + ACPI_FREE (DefineInfo->Identifier); + ACPI_FREE (DefineInfo); + } +} + + +/******************************************************************************* + * + * FUNCTION: PrDoPreprocess + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must + * be already open. Handles multiple input files via the + * #include directive. + * + ******************************************************************************/ + +void +PrDoPreprocess ( + void) +{ + BOOLEAN MoreInputFiles; + + + DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n"); + + + FlSeekFile (ASL_FILE_INPUT, 0); + PrDumpPredefinedNames (); + + /* Main preprocessor loop, handles include files */ + + do + { + PrPreprocessInputFile (); + MoreInputFiles = PrPopInputFileStack (); + + } while (MoreInputFiles); + + /* Point compiler input to the new preprocessor output file (.pre) */ + + FlCloseFile (ASL_FILE_INPUT); + Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle; + AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle; + + /* Reset globals to allow compiler to run */ + + FlSeekFile (ASL_FILE_INPUT, 0); + if (!Gbl_PreprocessOnly) + { + Gbl_CurrentLineNumber = 0; + } + + DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n"); +} + + +/******************************************************************************* + * + * FUNCTION: PrPreprocessInputFile + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Preprocess one entire file, line-by-line. + * + * Input: Raw user ASL from ASL_FILE_INPUT + * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR and + * (optionally) ASL_FILE_PREPROCESSOR_USER + * + ******************************************************************************/ + +static void +PrPreprocessInputFile ( + void) +{ + UINT32 Status; + char *Token; + char *ReplaceString; + PR_DEFINE_INFO *DefineInfo; + ACPI_SIZE TokenOffset; + char *Next; + int OffsetAdjust; + + + PrGetNextLineInit (); + + /* Scan source line-by-line and process directives. Then write the .i file */ + + while ((Status = PrGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF) + { + Gbl_CurrentLineNumber++; + Gbl_LogicalLineNumber++; + + if ((Status == ASL_WITHIN_COMMENT) || + (Status == ASL_BLANK_LINE)) + { + goto WriteEntireLine; + } + + /* Need a copy of the input line for strok() */ + + strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer); + Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next); + OffsetAdjust = 0; + + /* All preprocessor directives must begin with '#' */ + + if (Token && (*Token == '#')) + { + if (strlen (Token) == 1) + { + Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next); + } + else + { + Token++; /* Skip leading # */ + } + + /* Execute the directive, do not write line to output file */ + + PrDoDirective (Token, &Next); + continue; + } + + /* + * If we are currently within the part of an IF/ELSE block that is + * FALSE, ignore the line and do not write it to the output file. + * This continues until an #else or #endif is encountered. + */ + if (Gbl_IgnoringThisCodeBlock) + { + continue; + } + + /* Match and replace all #defined names within this source line */ + + while (Token) + { + DefineInfo = PrMatchDefine (Token); + if (DefineInfo) + { + if (DefineInfo->Body) + { + /* This is a macro */ + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Matched Macro: %s->%s\n", + Gbl_CurrentLineNumber, DefineInfo->Identifier, + DefineInfo->Replacement); + + PrDoMacroInvocation (Gbl_MainTokenBuffer, Token, + DefineInfo, &Next); + } + else + { + ReplaceString = DefineInfo->Replacement; + + /* Replace the name in the original line buffer */ + + TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust; + PrReplaceData ( + &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token), + ReplaceString, strlen (ReplaceString)); + + /* Adjust for length difference between old and new name length */ + + OffsetAdjust += strlen (ReplaceString) - strlen (Token); + + DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID + "Matched #define: %s->%s\n", + Gbl_CurrentLineNumber, Token, + *ReplaceString ? ReplaceString : "(NULL STRING)"); + } + } + + Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next); + } + + Gbl_PreprocessorLineNumber++; + + +WriteEntireLine: + /* + * Now we can write the possibly modified source line to the + * preprocessor file(s). + */ + FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer, + strlen (Gbl_CurrentLineBuffer)); + } +} + + +/******************************************************************************* + * + * FUNCTION: PrDoDirective + * + * PARAMETERS: Directive - Pointer to directive name token + * Next - "Next" buffer from GetNextToken + * + * RETURN: None. + * + * DESCRIPTION: Main processing for all preprocessor directives + * + ******************************************************************************/ + +static void +PrDoDirective ( + char *DirectiveToken, + char **Next) +{ + char *Token = Gbl_MainTokenBuffer; + char *Token2 = NULL; + char *End; + UINT64 Value; + ACPI_SIZE TokenOffset; + int Directive; + ACPI_STATUS Status; + + + if (!DirectiveToken) + { + goto SyntaxError; + } + + Directive = PrMatchDirective (DirectiveToken); + if (Directive == ASL_DIRECTIVE_NOT_FOUND) + { + PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE, + THIS_TOKEN_OFFSET (DirectiveToken)); + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "#%s: Unknown directive\n", + Gbl_CurrentLineNumber, DirectiveToken); + return; + } + + /* + * Emit a line directive into the preprocessor file (.pre) after + * every matched directive. This is passed through to the compiler + * so that error/warning messages are kept in sync with the + * original source file. + */ + FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\" // #%s\n", + Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename, + Gbl_DirectiveInfo[Directive].Name); + + /* + * If we are currently ignoring this block and we encounter a #else or + * #elif, we must ignore their blocks also if the parent block is also + * being ignored. + */ + if (Gbl_IgnoringThisCodeBlock) + { + switch (Directive) + { + case PR_DIRECTIVE_ELSE: + case PR_DIRECTIVE_ELIF: + + if (Gbl_DirectiveStack && + Gbl_DirectiveStack->IgnoringThisCodeBlock) + { + PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name); + return; + } + break; + + default: + break; + } + } + + /* + * Need to always check for #else, #elif, #endif regardless of + * whether we are ignoring the current code block, since these + * are conditional code block terminators. + */ + switch (Directive) + { + case PR_DIRECTIVE_ELSE: + + Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock); + PrDbgPrint ("Executing", "else block"); + return; + + case PR_DIRECTIVE_ELIF: + + Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock); + Directive = PR_DIRECTIVE_IF; + + if (Gbl_IgnoringThisCodeBlock == TRUE) + { + /* Not executing the ELSE part -- all done here */ + PrDbgPrint ("Ignoring", "elif block"); + return; + } + + /* + * After this, we will execute the IF part further below. + * First, however, pop off the original #if directive. + */ + if (ACPI_FAILURE (PrPopDirective ())) + { + PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, + THIS_TOKEN_OFFSET (DirectiveToken)); + } + + PrDbgPrint ("Executing", "elif block"); + break; + + case PR_DIRECTIVE_ENDIF: + + PrDbgPrint ("Executing", "endif"); + + /* Pop the owning #if/#ifdef/#ifndef */ + + if (ACPI_FAILURE (PrPopDirective ())) + { + PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH, + THIS_TOKEN_OFFSET (DirectiveToken)); + } + return; + + default: + break; + } + + /* Most directives have at least one argument */ + + if (Gbl_DirectiveInfo[Directive].ArgCount >= 1) + { + Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); + if (!Token) + { + goto SyntaxError; + } + } + + if (Gbl_DirectiveInfo[Directive].ArgCount >= 2) + { + Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); + if (!Token2) + { + goto SyntaxError; + } + } + + /* + * At this point, if we are ignoring the current code block, + * do not process any more directives (i.e., ignore them also.) + * For "if" style directives, open/push a new block anyway. We + * must do this to keep track of #endif directives + */ + if (Gbl_IgnoringThisCodeBlock) + { + switch (Directive) + { + case PR_DIRECTIVE_IF: + case PR_DIRECTIVE_IFDEF: + case PR_DIRECTIVE_IFNDEF: + + PrPushDirective (Directive, Token); + PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name); + break; + + default: + break; + } + + return; + } + + /* + * Execute the directive + */ + PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name); + + switch (Directive) + { + case PR_DIRECTIVE_IF: + + TokenOffset = Token - Gbl_MainTokenBuffer; + + /* Need to expand #define macros in the expression string first */ + + Status = PrResolveIntegerExpression ( + &Gbl_CurrentLineBuffer[TokenOffset-1], &Value); + if (ACPI_FAILURE (Status)) + { + return; + } + + PrPushDirective (Directive, Token); + if (!Value) + { + Gbl_IgnoringThisCodeBlock = TRUE; + } + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "Resolved #if: %8.8X%8.8X %s\n", + Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value), + Gbl_IgnoringThisCodeBlock ? "" : ""); + break; + + case PR_DIRECTIVE_IFDEF: + + PrPushDirective (Directive, Token); + if (!PrMatchDefine (Token)) + { + Gbl_IgnoringThisCodeBlock = TRUE; + } + + PrDbgPrint ("Evaluated", "ifdef"); + break; + + case PR_DIRECTIVE_IFNDEF: + + PrPushDirective (Directive, Token); + if (PrMatchDefine (Token)) + { + Gbl_IgnoringThisCodeBlock = TRUE; + } + + PrDbgPrint ("Evaluated", "ifndef"); + break; + + case PR_DIRECTIVE_DEFINE: + /* + * By definition, if first char after the name is a paren, + * this is a function macro. + */ + TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token); + if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(') + { +#ifndef MACROS_SUPPORTED + AcpiOsPrintf ( + "%s ERROR - line %u: #define macros are not supported yet\n", + Gbl_CurrentLineBuffer, Gbl_LogicalLineNumber); + exit(1); +#else + PrAddMacro (Token, Next); +#endif + } + else + { + /* Use the remainder of the line for the #define */ + + Token2 = *Next; + if (Token2) + { + while ((*Token2 == ' ') || (*Token2 == '\t')) + { + Token2++; + } + + End = Token2; + while (*End != '\n') + { + End++; + } + + *End = 0; + } + else + { + Token2 = ""; + } +#if 0 + Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next); + if (!Token2) + { + Token2 = ""; + } +#endif + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "New #define: %s->%s\n", + Gbl_LogicalLineNumber, Token, Token2); + + PrAddDefine (Token, Token2, FALSE); + } + break; + + case PR_DIRECTIVE_ERROR: + + /* Note: No macro expansion */ + + PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE, + THIS_TOKEN_OFFSET (Token)); + + Gbl_SourceLine = 0; + Gbl_NextError = Gbl_ErrorLog; + CmCleanupAndExit (); + exit(1); + + case PR_DIRECTIVE_INCLUDE: + + Token = PrGetNextToken (NULL, " \"<>", Next); + if (!Token) + { + goto SyntaxError; + } + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "Start #include file \"%s\"\n", Gbl_CurrentLineNumber, + Token, Gbl_CurrentLineNumber); + + PrDoIncludeFile (Token); + break; + + case PR_DIRECTIVE_INCLUDEBUFFER: + + Token = PrGetNextToken (NULL, " \"<>", Next); + if (!Token) + { + goto SyntaxError; + } + + Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); + if (!Token2) + { + goto SyntaxError; + } + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "Start #includebuffer input from file \"%s\", buffer name %s\n", + Gbl_CurrentLineNumber, Token, Token2); + + PrDoIncludeBuffer (Token, Token2); + break; + + case PR_DIRECTIVE_LINE: + + TokenOffset = Token - Gbl_MainTokenBuffer; + + Status = PrResolveIntegerExpression ( + &Gbl_CurrentLineBuffer[TokenOffset-1], &Value); + if (ACPI_FAILURE (Status)) + { + return; + } + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "User #line invocation %s\n", Gbl_CurrentLineNumber, + Token); + + Gbl_CurrentLineNumber = (UINT32) Value; + + /* Emit #line into the preprocessor file */ + + FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", + Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename); + break; + + case PR_DIRECTIVE_PRAGMA: + + if (!strcmp (Token, "disable")) + { + Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); + if (!Token) + { + goto SyntaxError; + } + + TokenOffset = Token - Gbl_MainTokenBuffer; + AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]); + } + else if (!strcmp (Token, "message")) + { + Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next); + if (!Token) + { + goto SyntaxError; + } + + TokenOffset = Token - Gbl_MainTokenBuffer; + AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]); + } + else + { + PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA, + THIS_TOKEN_OFFSET (Token)); + return; + } + + break; + + case PR_DIRECTIVE_UNDEF: + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "#undef: %s\n", Gbl_CurrentLineNumber, Token); + + PrRemoveDefine (Token); + break; + + case PR_DIRECTIVE_WARNING: + + PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE, + THIS_TOKEN_OFFSET (Token)); + + Gbl_SourceLine = 0; + Gbl_NextError = Gbl_ErrorLog; + break; + + default: + + /* Should never get here */ + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "Unrecognized directive: %u\n", + Gbl_CurrentLineNumber, Directive); + break; + } + + return; + +SyntaxError: + + PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX, + THIS_TOKEN_OFFSET (DirectiveToken)); + return; +} + + +/******************************************************************************* + * + * FUNCTION: PrGetNextLine, PrGetNextLineInit + * + * PARAMETERS: Handle - Open file handle for the source file + * + * RETURN: Status of the GetLine operation: + * AE_OK - Normal line, OK status + * ASL_WITHIN_COMMENT - Line is part of a multi-line comment + * ASL_EOF - End-of-file reached + * + * DESCRIPTION: Get the next text line from the input file. Does not strip + * comments. + * + ******************************************************************************/ + +#define PR_NORMAL_TEXT 0 +#define PR_MULTI_LINE_COMMENT 1 +#define PR_SINGLE_LINE_COMMENT 2 +#define PR_QUOTED_STRING 3 + +static UINT8 AcpiGbl_LineScanState = PR_NORMAL_TEXT; + +static void +PrGetNextLineInit ( + void) +{ + AcpiGbl_LineScanState = 0; +} + +static UINT32 +PrGetNextLine ( + FILE *Handle) +{ + UINT32 i; + int c = 0; + int PreviousChar; + + + /* Always clear the global line buffer */ + + memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize); + for (i = 0; ;) + { + /* + * If line is too long, expand the line buffers. Also increases + * Gbl_LineBufferSize. + */ + if (i >= Gbl_LineBufferSize) + { + UtExpandLineBuffers (); + } + + PreviousChar = c; + c = getc (Handle); + if (c == EOF) + { + return (ASL_EOF); + } + + /* Update state machine as necessary */ + + switch (AcpiGbl_LineScanState) + { + case PR_NORMAL_TEXT: + + /* Check for multi-line comment start */ + + if ((PreviousChar == '/') && (c == '*')) + { + AcpiGbl_LineScanState = PR_MULTI_LINE_COMMENT; + } + + /* Check for single-line comment start */ + + else if ((PreviousChar == '/') && (c == '/')) + { + AcpiGbl_LineScanState = PR_SINGLE_LINE_COMMENT; + } + + /* Check for quoted string start */ + + else if (PreviousChar == '"') + { + AcpiGbl_LineScanState = PR_QUOTED_STRING; + } + break; + + case PR_QUOTED_STRING: + + if (PreviousChar == '"') + { + AcpiGbl_LineScanState = PR_NORMAL_TEXT; + } + break; + + case PR_MULTI_LINE_COMMENT: + + /* Check for multi-line comment end */ + + if ((PreviousChar == '*') && (c == '/')) + { + AcpiGbl_LineScanState = PR_NORMAL_TEXT; + } + break; + + case PR_SINGLE_LINE_COMMENT: /* Just ignore text until EOL */ + default: + break; + } + + /* Always copy the character into line buffer */ + + Gbl_CurrentLineBuffer[i] = (char) c; + i++; + + /* Always exit on end-of-line */ + + if (c == '\n') + { + /* Handle multi-line comments */ + + if (AcpiGbl_LineScanState == PR_MULTI_LINE_COMMENT) + { + return (ASL_WITHIN_COMMENT); + } + + /* End of single-line comment */ + + if (AcpiGbl_LineScanState == PR_SINGLE_LINE_COMMENT) + { + AcpiGbl_LineScanState = PR_NORMAL_TEXT; + return (AE_OK); + } + + /* Blank line */ + + if (i == 1) + { + return (ASL_BLANK_LINE); + } + + return (AE_OK); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: PrMatchDirective + * + * PARAMETERS: Directive - Pointer to directive name token + * + * RETURN: Index into command array, -1 if not found + * + * DESCRIPTION: Lookup the incoming directive in the known directives table. + * + ******************************************************************************/ + +static int +PrMatchDirective ( + char *Directive) +{ + int i; + + + if (!Directive || Directive[0] == 0) + { + return (ASL_DIRECTIVE_NOT_FOUND); + } + + for (i = 0; Gbl_DirectiveInfo[i].Name; i++) + { + if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive)) + { + return (i); + } + } + + return (ASL_DIRECTIVE_NOT_FOUND); /* Command not recognized */ +} + + +/******************************************************************************* + * + * FUNCTION: PrPushDirective + * + * PARAMETERS: Directive - Encoded directive ID + * Argument - String containing argument to the + * directive + * + * RETURN: None + * + * DESCRIPTION: Push an item onto the directive stack. Used for processing + * nested #if/#else type conditional compilation directives. + * Specifically: Used on detection of #if/#ifdef/#ifndef to open + * a block. + * + ******************************************************************************/ + +static void +PrPushDirective ( + int Directive, + char *Argument) +{ + DIRECTIVE_INFO *Info; + + + /* Allocate and populate a stack info item */ + + Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO)); + + Info->Next = Gbl_DirectiveStack; + Info->Directive = Directive; + Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock; + strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH); + + DbgPrint (ASL_DEBUG_OUTPUT, + "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n", + Gbl_CurrentLineNumber, Gbl_IfDepth, + Gbl_IgnoringThisCodeBlock ? "I" : "E", + Gbl_IfDepth * 4, " ", + Gbl_DirectiveInfo[Directive].Name, + Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE"); + + /* Push new item */ + + Gbl_DirectiveStack = Info; + Gbl_IfDepth++; +} + + +/******************************************************************************* + * + * FUNCTION: PrPopDirective + * + * PARAMETERS: None + * + * RETURN: Status. Error if the stack is empty. + * + * DESCRIPTION: Pop an item off the directive stack. Used for processing + * nested #if/#else type conditional compilation directives. + * Specifically: Used on detection of #elif and #endif to remove + * the original #if/#ifdef/#ifndef from the stack and close + * the block. + * + ******************************************************************************/ + +static ACPI_STATUS +PrPopDirective ( + void) +{ + DIRECTIVE_INFO *Info; + + + /* Check for empty stack */ + + Info = Gbl_DirectiveStack; + if (!Info) + { + return (AE_ERROR); + } + + /* Pop one item, keep globals up-to-date */ + + Gbl_IfDepth--; + Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock; + Gbl_DirectiveStack = Info->Next; + + DbgPrint (ASL_DEBUG_OUTPUT, + "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n", + Gbl_CurrentLineNumber, Gbl_IfDepth, + Gbl_IgnoringThisCodeBlock ? "I" : "E", + Gbl_IfDepth * 4, " ", + Gbl_DirectiveInfo[Info->Directive].Name, + Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE"); + + ACPI_FREE (Info); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: PrDbgPrint + * + * PARAMETERS: Action - Action being performed + * DirectiveName - Directive being processed + * + * RETURN: None + * + * DESCRIPTION: Special debug print for directive processing. + * + ******************************************************************************/ + +static void +PrDbgPrint ( + char *Action, + char *DirectiveName) +{ + + DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] " + "%*s %s #%s, IfDepth %u\n", + Gbl_CurrentLineNumber, Gbl_IfDepth, + Gbl_IgnoringThisCodeBlock ? "I" : "E", + Gbl_IfDepth * 4, " ", + Action, DirectiveName, Gbl_IfDepth); +} + + +/******************************************************************************* + * + * FUNCTION: PrDoIncludeFile + * + * PARAMETERS: Pathname - Name of the input file + * + * RETURN: None. + * + * DESCRIPTION: Open an include file, from #include. + * + ******************************************************************************/ + +static void +PrDoIncludeFile ( + char *Pathname) +{ + char *FullPathname; + + + (void) PrOpenIncludeFile (Pathname, "r", &FullPathname); +} + + +/******************************************************************************* + * + * FUNCTION: PrDoIncludeBuffer + * + * PARAMETERS: Pathname - Name of the input binary file + * BufferName - ACPI namepath of the buffer + * + * RETURN: None. + * + * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents + * of the file are emitted into the buffer object as ascii + * hex data. From #includebuffer. + * + ******************************************************************************/ + +static void +PrDoIncludeBuffer ( + char *Pathname, + char *BufferName) +{ + char *FullPathname; + FILE *BinaryBufferFile; + UINT32 i = 0; + UINT8 c; + + + BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname); + if (!BinaryBufferFile) + { + return; + } + + /* Emit "Name (XXXX, Buffer() {" header */ + + FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName); + + /* Dump the entire file in ascii hex format */ + + while (fread (&c, 1, 1, BinaryBufferFile)) + { + if (!(i % 8)) + { + FlPrintFile (ASL_FILE_PREPROCESSOR, "\n ", c); + } + + FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c); + i++; + } + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "#includebuffer: read %u bytes from %s\n", + Gbl_CurrentLineNumber, i, FullPathname); + + /* Close the Name() operator */ + + FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName); + fclose (BinaryBufferFile); +} diff --git a/third_party/lib/acpica/source/compiler/prutils.c b/third_party/lib/acpica/source/compiler/prutils.c new file mode 100644 index 000000000..ec9bf6664 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/prutils.c @@ -0,0 +1,476 @@ +/****************************************************************************** + * + * Module Name: prutils - Preprocessor utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aslcompiler.h" +#include "dtcompiler.h" + + +#define _COMPONENT ASL_PREPROCESSOR + ACPI_MODULE_NAME ("prutils") + + +/****************************************************************************** + * + * FUNCTION: PrGetNextToken + * + * PARAMETERS: Buffer - Current line buffer + * MatchString - String with valid token delimiters + * Next - Set to next possible token in buffer + * + * RETURN: Next token (null-terminated). Modifies the input line. + * Remainder of line is stored in *Next. + * + * DESCRIPTION: Local implementation of strtok() with local storage for the + * next pointer. Not only thread-safe, but allows multiple + * parsing of substrings such as expressions. + * + *****************************************************************************/ + +char * +PrGetNextToken ( + char *Buffer, + char *MatchString, + char **Next) +{ + char *TokenStart; + + + if (!Buffer) + { + /* Use Next if it is valid */ + + Buffer = *Next; + if (!(*Next)) + { + return (NULL); + } + } + + /* Skip any leading delimiters */ + + while (*Buffer) + { + if (strchr (MatchString, *Buffer)) + { + Buffer++; + } + else + { + break; + } + } + + /* Anything left on the line? */ + + if (!(*Buffer)) + { + *Next = NULL; + return (NULL); + } + + TokenStart = Buffer; + + /* Find the end of this token */ + + while (*Buffer) + { + if (strchr (MatchString, *Buffer)) + { + *Buffer = 0; + *Next = Buffer+1; + if (!**Next) + { + *Next = NULL; + } + + return (TokenStart); + } + + Buffer++; + } + + *Next = NULL; + return (TokenStart); +} + + +/******************************************************************************* + * + * FUNCTION: PrError + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * Column - Column in current line + * + * RETURN: None + * + * DESCRIPTION: Preprocessor error reporting. Front end to AslCommonError2 + * + ******************************************************************************/ + +void +PrError ( + UINT8 Level, + UINT16 MessageId, + UINT32 Column) +{ +#if 0 + AcpiOsPrintf ("%s (%u) : %s", Gbl_Files[ASL_FILE_INPUT].Filename, + Gbl_CurrentLineNumber, Gbl_CurrentLineBuffer); +#endif + + + if (Column > 120) + { + Column = 0; + } + + /* TBD: Need Logical line number? */ + + AslCommonError2 (Level, MessageId, + Gbl_CurrentLineNumber, Column, + Gbl_CurrentLineBuffer, + Gbl_Files[ASL_FILE_INPUT].Filename, "Preprocessor"); + + Gbl_PreprocessorError = TRUE; +} + + +/******************************************************************************* + * + * FUNCTION: PrReplaceData + * + * PARAMETERS: Buffer - Original(target) buffer pointer + * LengthToRemove - Length to be removed from target buffer + * BufferToAdd - Data to be inserted into target buffer + * LengthToAdd - Length of BufferToAdd + * + * RETURN: None + * + * DESCRIPTION: Generic buffer data replacement. + * + ******************************************************************************/ + +void +PrReplaceData ( + char *Buffer, + UINT32 LengthToRemove, + char *BufferToAdd, + UINT32 LengthToAdd) +{ + UINT32 BufferLength; + + + /* Buffer is a string, so the length must include the terminating zero */ + + BufferLength = strlen (Buffer) + 1; + + if (LengthToRemove != LengthToAdd) + { + /* + * Move some of the existing data + * 1) If adding more bytes than removing, make room for the new data + * 2) if removing more bytes than adding, delete the extra space + */ + if (LengthToRemove > 0) + { + memmove ((Buffer + LengthToAdd), (Buffer + LengthToRemove), + (BufferLength - LengthToRemove)); + } + } + + /* Now we can move in the new data */ + + if (LengthToAdd > 0) + { + memmove (Buffer, BufferToAdd, LengthToAdd); + } +} + + +/******************************************************************************* + * + * FUNCTION: PrOpenIncludeFile + * + * PARAMETERS: Filename - Filename or pathname for include file + * + * RETURN: None. + * + * DESCRIPTION: Open an include file and push it on the input file stack. + * + ******************************************************************************/ + +FILE * +PrOpenIncludeFile ( + char *Filename, + char *OpenMode, + char **FullPathname) +{ + FILE *IncludeFile; + ASL_INCLUDE_DIR *NextDir; + + + /* Start the actual include file on the next line */ + + Gbl_CurrentLineOffset++; + + /* Attempt to open the include file */ + /* If the file specifies an absolute path, just open it */ + + if ((Filename[0] == '/') || + (Filename[0] == '\\') || + (Filename[1] == ':')) + { + IncludeFile = PrOpenIncludeWithPrefix ( + "", Filename, OpenMode, FullPathname); + if (!IncludeFile) + { + goto ErrorExit; + } + return (IncludeFile); + } + + /* + * The include filename is not an absolute path. + * + * First, search for the file within the "local" directory -- meaning + * the same directory that contains the source file. + * + * Construct the file pathname from the global directory name. + */ + IncludeFile = PrOpenIncludeWithPrefix ( + Gbl_DirectoryPath, Filename, OpenMode, FullPathname); + if (IncludeFile) + { + return (IncludeFile); + } + + /* + * Second, search for the file within the (possibly multiple) + * directories specified by the -I option on the command line. + */ + NextDir = Gbl_IncludeDirList; + while (NextDir) + { + IncludeFile = PrOpenIncludeWithPrefix ( + NextDir->Dir, Filename, OpenMode, FullPathname); + if (IncludeFile) + { + return (IncludeFile); + } + + NextDir = NextDir->Next; + } + + /* We could not open the include file after trying very hard */ + +ErrorExit: + sprintf (Gbl_MainTokenBuffer, "%s, %s", Filename, strerror (errno)); + PrError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, 0); + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: FlOpenIncludeWithPrefix + * + * PARAMETERS: PrefixDir - Prefix directory pathname. Can be a zero + * length string. + * Filename - The include filename from the source ASL. + * + * RETURN: Valid file descriptor if successful. Null otherwise. + * + * DESCRIPTION: Open an include file and push it on the input file stack. + * + ******************************************************************************/ + +FILE * +PrOpenIncludeWithPrefix ( + char *PrefixDir, + char *Filename, + char *OpenMode, + char **FullPathname) +{ + FILE *IncludeFile; + char *Pathname; + + + /* Build the full pathname to the file */ + + Pathname = FlMergePathnames (PrefixDir, Filename); + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "Include: Opening file - \"%s\"\n", + Gbl_CurrentLineNumber, Pathname); + + /* Attempt to open the file, push if successful */ + + IncludeFile = fopen (Pathname, OpenMode); + if (!IncludeFile) + { + fprintf (stderr, "Could not open include file %s\n", Pathname); + return (NULL); + } + + /* Push the include file on the open input file stack */ + + PrPushInputFileStack (IncludeFile, Pathname); + *FullPathname = Pathname; + return (IncludeFile); +} + + +/******************************************************************************* + * + * FUNCTION: AslPushInputFileStack + * + * PARAMETERS: InputFile - Open file pointer + * Filename - Name of the file + * + * RETURN: None + * + * DESCRIPTION: Push the InputFile onto the file stack, and point the parser + * to this file. Called when an include file is successfully + * opened. + * + ******************************************************************************/ + +void +PrPushInputFileStack ( + FILE *InputFile, + char *Filename) +{ + PR_FILE_NODE *Fnode; + + + Gbl_HasIncludeFiles = TRUE; + + /* Save the current state in an Fnode */ + + Fnode = UtLocalCalloc (sizeof (PR_FILE_NODE)); + + Fnode->File = Gbl_Files[ASL_FILE_INPUT].Handle; + Fnode->Next = Gbl_InputFileList; + Fnode->Filename = Gbl_Files[ASL_FILE_INPUT].Filename; + Fnode->CurrentLineNumber = Gbl_CurrentLineNumber; + + /* Push it on the stack */ + + Gbl_InputFileList = Fnode; + + DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID + "Push InputFile Stack: handle %p\n\n", + Gbl_CurrentLineNumber, InputFile); + + /* Reset the global line count and filename */ + + Gbl_Files[ASL_FILE_INPUT].Filename = + UtStringCacheCalloc (strlen (Filename) + 1); + strcpy (Gbl_Files[ASL_FILE_INPUT].Filename, Filename); + + Gbl_Files[ASL_FILE_INPUT].Handle = InputFile; + Gbl_CurrentLineNumber = 1; + + /* Emit a new #line directive for the include file */ + + FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 1, Filename); +} + + +/******************************************************************************* + * + * FUNCTION: AslPopInputFileStack + * + * PARAMETERS: None + * + * RETURN: 0 if a node was popped, -1 otherwise + * + * DESCRIPTION: Pop the top of the input file stack and point the parser to + * the saved parse buffer contained in the fnode. Also, set the + * global line counters to the saved values. This function is + * called when an include file reaches EOF. + * + ******************************************************************************/ + +BOOLEAN +PrPopInputFileStack ( + void) +{ + PR_FILE_NODE *Fnode; + + + Fnode = Gbl_InputFileList; + DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID + "Pop InputFile Stack, Fnode %p\n\n", + Gbl_CurrentLineNumber, Fnode); + + if (!Fnode) + { + return (FALSE); + } + + /* Close the current include file */ + + fclose (Gbl_Files[ASL_FILE_INPUT].Handle); + + /* Update the top-of-stack */ + + Gbl_InputFileList = Fnode->Next; + + /* Reset global line counter and filename */ + + Gbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename; + Gbl_Files[ASL_FILE_INPUT].Handle = Fnode->File; + Gbl_CurrentLineNumber = Fnode->CurrentLineNumber; + + /* Emit a new #line directive after the include file */ + + FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", + Gbl_CurrentLineNumber, Fnode->Filename); + + /* All done with this node */ + + ACPI_FREE (Fnode); + return (TRUE); +} diff --git a/third_party/lib/acpica/source/compiler/readme.txt b/third_party/lib/acpica/source/compiler/readme.txt new file mode 100644 index 000000000..12f4cd0f8 --- /dev/null +++ b/third_party/lib/acpica/source/compiler/readme.txt @@ -0,0 +1,139 @@ +/* + * Miscellaneous instructions for building and using the iASL compiler. + */ +Last update 9 December 2013. + + +1) Generating iASL from source +------------------------------ + +Generation of the ASL compiler from source code requires these items: + + 1) The ACPICA source code tree. + 2) An ANSI C compiler. + 3) The Flex (or Lex) lexical analyzer generator. + 4) The Bison (or Yacc) parser generator. + +There are three major ACPICA source code components that are required to +generate the compiler (Basically, the entire ACPICA source tree should +be installed): + + 1) The ASL compiler source. + 2) The ACPICA Core Subsystem source. In particular, the Namespace + Manager component is used to create an internal ACPI namespace + and symbol table, and the AML Interpreter is used to evaluate + constant expressions. + 3) The "common" source directory that is used for all ACPI components. + + +1a) Notes for Linux/Unix generation +----------------------------------- + +iASL has been generated with these versions of Flex/Bison: + + flex: Version 2.5.32 + bison: Version 2.6.2 + +Other required packages: + + make + gcc C compiler + m4 (macro processor required by bison) + +On Linux/Unix systems, the following commands will build the compiler: + + cd acpica (or cd acpica/generate/unix) + make clean + make iasl + + +1b) Notes for Windows generation +-------------------------------- + +On Windows, the Visual Studio 2008 project file appears in this directory: + + generate/msvc9/AcpiComponents.sln + +The Windows versions of GNU Flex/Bison must be installed, and they must +be installed in a directory that contains no embedded spaces in the +pathname. They cannot be installed in the default "c:\Program Files" +directory. This is a bug in Bison. The default Windows project file for +iASL assumes that these tools are installed at this location: + + c:\GnuWin32 + +Once the tools are installed, ensure that this path is added to the +default system $Path environment variable: + + c:\GnuWin32\bin + +Goto: ControlPanel/System/AdvancedSystemSettings/EnvironmentVariables + +Important: Now Windows must be rebooted to make the system aware of +the updated $Path. Otherwise, Bison will not be able to find the M4 +interpreter library and will fail. + +iASL has been generated with these versions of Flex/Bison for Windows: + + Flex for Windows: V2.5.4a + Bison for Windows: V2.4.1 + +Flex is available at: http://gnuwin32.sourceforge.net/packages/flex.htm +Bison is available at: http://gnuwin32.sourceforge.net/packages/bison.htm + + + +2) Integration as a custom tool for Visual Studio +------------------------------------------------- + +This procedure adds the iASL compiler as a custom tool that can be used +to compile ASL source files. The output is sent to the VC output +window. + +a) Select Tools->Customize. + +b) Select the "Tools" tab. + +c) Scroll down to the bottom of the "Menu Contents" window. There you + will see an empty rectangle. Click in the rectangle to enter a + name for this tool. + +d) Type "iASL Compiler" in the box and hit enter. You can now edit + the other fields for this new custom tool. + +e) Enter the following into the fields: + + Command: C:\Acpi\iasl.exe + Arguments: -vi "$(FilePath)" + Initial Directory "$(FileDir)" + Use Output Window + + "Command" must be the path to wherever you copied the compiler. + "-vi" instructs the compiler to produce messages appropriate for VC. + Quotes around FilePath and FileDir enable spaces in filenames. + +f) Select "Close". + +These steps will add the compiler to the tools menu as a custom tool. +By enabling "Use Output Window", you can click on error messages in +the output window and the source file and source line will be +automatically displayed by VC. Also, you can use F4 to step through +the messages and the corresponding source line(s). + + + +3) Integrating iASL into a Visual Studio ASL project build +---------------------------------------------------------- + +This procedure creates a project that compiles ASL files to AML. + +a) Create a new, empty project and add your .ASL files to the project + +b) For all ASL files in the project, specify a custom build (under +Project/Settings/CustomBuild with the following settings (or similar): + +Commands: + c:\acpi\libraries\iasl.exe -vs -vi "$(InputPath)" + +Output: + $(InputDir)\$(InputPath).aml diff --git a/third_party/lib/acpica/source/components/debugger/dbcmds.c b/third_party/lib/acpica/source/components/debugger/dbcmds.c new file mode 100644 index 000000000..3b5c266e7 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbcmds.c @@ -0,0 +1,1342 @@ +/******************************************************************************* + * + * Module Name: dbcmds - Miscellaneous debug commands and output routines + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acdebug.h" +#include "acnamesp.h" +#include "acresrc.h" +#include "actables.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbcmds") + + +/* Local prototypes */ + +static void +AcpiDmCompareAmlResources ( + UINT8 *Aml1Buffer, + ACPI_RSDESC_SIZE Aml1BufferLength, + UINT8 *Aml2Buffer, + ACPI_RSDESC_SIZE Aml2BufferLength); + +static ACPI_STATUS +AcpiDmTestResourceConversion ( + ACPI_NAMESPACE_NODE *Node, + char *Name); + +static ACPI_STATUS +AcpiDbResourceCallback ( + ACPI_RESOURCE *Resource, + void *Context); + +static ACPI_STATUS +AcpiDbDeviceResources ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static void +AcpiDbDoOneSleepState ( + UINT8 SleepState); + + +static char *AcpiDbTraceMethodName = NULL; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbConvertToNode + * + * PARAMETERS: InString - String to convert + * + * RETURN: Pointer to a NS node + * + * DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or + * alphanumeric strings. + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +AcpiDbConvertToNode ( + char *InString) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_SIZE Address; + + + if ((*InString >= 0x30) && (*InString <= 0x39)) + { + /* Numeric argument, convert */ + + Address = strtoul (InString, NULL, 16); + Node = ACPI_TO_POINTER (Address); + if (!AcpiOsReadable (Node, sizeof (ACPI_NAMESPACE_NODE))) + { + AcpiOsPrintf ("Address %p is invalid", Node); + return (NULL); + } + + /* Make sure pointer is valid NS node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) + { + AcpiOsPrintf ("Address %p is not a valid namespace node [%s]\n", + Node, AcpiUtGetDescriptorName (Node)); + return (NULL); + } + } + else + { + /* + * Alpha argument: The parameter is a name string that must be + * resolved to a Namespace object. + */ + Node = AcpiDbLocalNsLookup (InString); + if (!Node) + { + AcpiOsPrintf ( + "Could not find [%s] in namespace, defaulting to root node\n", + InString); + Node = AcpiGbl_RootNode; + } + } + + return (Node); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSleep + * + * PARAMETERS: ObjectArg - Desired sleep state (0-5). NULL means + * invoke all possible sleep states. + * + * RETURN: Status + * + * DESCRIPTION: Simulate sleep/wake sequences + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbSleep ( + char *ObjectArg) +{ + UINT8 SleepState; + UINT32 i; + + + ACPI_FUNCTION_TRACE (AcpiDbSleep); + + + /* Null input (no arguments) means to invoke all sleep states */ + + if (!ObjectArg) + { + AcpiOsPrintf ("Invoking all possible sleep states, 0-%d\n", + ACPI_S_STATES_MAX); + + for (i = 0; i <= ACPI_S_STATES_MAX; i++) + { + AcpiDbDoOneSleepState ((UINT8) i); + } + + return_ACPI_STATUS (AE_OK); + } + + /* Convert argument to binary and invoke the sleep state */ + + SleepState = (UINT8) strtoul (ObjectArg, NULL, 0); + AcpiDbDoOneSleepState (SleepState); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDoOneSleepState + * + * PARAMETERS: SleepState - Desired sleep state (0-5) + * + * RETURN: None + * + * DESCRIPTION: Simulate a sleep/wake sequence + * + ******************************************************************************/ + +static void +AcpiDbDoOneSleepState ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + UINT8 SleepTypeA; + UINT8 SleepTypeB; + + + /* Validate parameter */ + + if (SleepState > ACPI_S_STATES_MAX) + { + AcpiOsPrintf ("Sleep state %d out of range (%d max)\n", + SleepState, ACPI_S_STATES_MAX); + return; + } + + AcpiOsPrintf ("\n---- Invoking sleep state S%d (%s):\n", + SleepState, AcpiGbl_SleepStateNames[SleepState]); + + /* Get the values for the sleep type registers (for display only) */ + + Status = AcpiGetSleepTypeData (SleepState, &SleepTypeA, &SleepTypeB); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not evaluate [%s] method, %s\n", + AcpiGbl_SleepStateNames[SleepState], + AcpiFormatException (Status)); + return; + } + + AcpiOsPrintf ( + "Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n", + SleepState, SleepTypeA, SleepTypeB); + + /* Invoke the various sleep/wake interfaces */ + + AcpiOsPrintf ("**** Sleep: Prepare to sleep (S%d) ****\n", + SleepState); + Status = AcpiEnterSleepStatePrep (SleepState); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + AcpiOsPrintf ("**** Sleep: Going to sleep (S%d) ****\n", + SleepState); + Status = AcpiEnterSleepState (SleepState); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + AcpiOsPrintf ("**** Wake: Prepare to return from sleep (S%d) ****\n", + SleepState); + Status = AcpiLeaveSleepStatePrep (SleepState); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + AcpiOsPrintf ("**** Wake: Return from sleep (S%d) ****\n", + SleepState); + Status = AcpiLeaveSleepState (SleepState); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + return; + + +ErrorExit: + ACPI_EXCEPTION ((AE_INFO, Status, "During invocation of sleep state S%d", + SleepState)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayLocks + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display information about internal mutexes. + * + ******************************************************************************/ + +void +AcpiDbDisplayLocks ( + void) +{ + UINT32 i; + + + for (i = 0; i < ACPI_MAX_MUTEX; i++) + { + AcpiOsPrintf ("%26s : %s\n", AcpiUtGetMutexName (i), + AcpiGbl_MutexInfo[i].ThreadId == ACPI_MUTEX_NOT_ACQUIRED + ? "Locked" : "Unlocked"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayTableInfo + * + * PARAMETERS: TableArg - Name of table to be displayed + * + * RETURN: None + * + * DESCRIPTION: Display information about loaded tables. Current + * implementation displays all loaded tables. + * + ******************************************************************************/ + +void +AcpiDbDisplayTableInfo ( + char *TableArg) +{ + UINT32 i; + ACPI_TABLE_DESC *TableDesc; + ACPI_STATUS Status; + + + /* Header */ + + AcpiOsPrintf ("Idx ID Status Type " + "TableHeader (Sig, Address, Length, Misc)\n"); + + /* Walk the entire root table list */ + + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++) + { + TableDesc = &AcpiGbl_RootTableList.Tables[i]; + + /* Index and Table ID */ + + AcpiOsPrintf ("%3u %.2u ", i, TableDesc->OwnerId); + + /* Decode the table flags */ + + if (!(TableDesc->Flags & ACPI_TABLE_IS_LOADED)) + { + AcpiOsPrintf ("NotLoaded "); + } + else + { + AcpiOsPrintf (" Loaded "); + } + + switch (TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK) + { + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + AcpiOsPrintf ("External/virtual "); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + AcpiOsPrintf ("Internal/physical "); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + + AcpiOsPrintf ("Internal/virtual "); + break; + + default: + + AcpiOsPrintf ("INVALID TYPE "); + break; + } + + /* Make sure that the table is mapped */ + + Status = AcpiTbValidateTable (TableDesc); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Dump the table header */ + + if (TableDesc->Pointer) + { + AcpiTbPrintTableHeader (TableDesc->Address, TableDesc->Pointer); + } + else + { + /* If the pointer is null, the table has been unloaded */ + + ACPI_INFO ((AE_INFO, "%4.4s - Table has been unloaded", + TableDesc->Signature.Ascii)); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbUnloadAcpiTable + * + * PARAMETERS: ObjectName - Namespace pathname for an object that + * is owned by the table to be unloaded + * + * RETURN: None + * + * DESCRIPTION: Unload an ACPI table, via any namespace node that is owned + * by the table. + * + ******************************************************************************/ + +void +AcpiDbUnloadAcpiTable ( + char *ObjectName) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Translate name to an Named object */ + + Node = AcpiDbConvertToNode (ObjectName); + if (!Node) + { + return; + } + + Status = AcpiUnloadParentTable (ACPI_CAST_PTR (ACPI_HANDLE, Node)); + if (ACPI_SUCCESS (Status)) + { + AcpiOsPrintf ("Parent of [%s] (%p) unloaded and uninstalled\n", + ObjectName, Node); + } + else + { + AcpiOsPrintf ("%s, while unloading parent table of [%s]\n", + AcpiFormatException (Status), ObjectName); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSendNotify + * + * PARAMETERS: Name - Name of ACPI object where to send notify + * Value - Value of the notify to send. + * + * RETURN: None + * + * DESCRIPTION: Send an ACPI notification. The value specified is sent to the + * named object as an ACPI notify. + * + ******************************************************************************/ + +void +AcpiDbSendNotify ( + char *Name, + UINT32 Value) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Translate name to an Named object */ + + Node = AcpiDbConvertToNode (Name); + if (!Node) + { + return; + } + + /* Dispatch the notify if legal */ + + if (AcpiEvIsNotifyObject (Node)) + { + Status = AcpiEvQueueNotifyRequest (Node, Value); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not queue notify\n"); + } + } + else + { + AcpiOsPrintf ( + "Named object [%4.4s] Type %s, " + "must be Device/Thermal/Processor type\n", + AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayInterfaces + * + * PARAMETERS: ActionArg - Null, "install", or "remove" + * InterfaceNameArg - Name for install/remove options + * + * RETURN: None + * + * DESCRIPTION: Display or modify the global _OSI interface list + * + ******************************************************************************/ + +void +AcpiDbDisplayInterfaces ( + char *ActionArg, + char *InterfaceNameArg) +{ + ACPI_INTERFACE_INFO *NextInterface; + char *SubString; + ACPI_STATUS Status; + + + /* If no arguments, just display current interface list */ + + if (!ActionArg) + { + (void) AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + + NextInterface = AcpiGbl_SupportedInterfaces; + while (NextInterface) + { + if (!(NextInterface->Flags & ACPI_OSI_INVALID)) + { + AcpiOsPrintf ("%s\n", NextInterface->Name); + } + + NextInterface = NextInterface->Next; + } + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return; + } + + /* If ActionArg exists, so must InterfaceNameArg */ + + if (!InterfaceNameArg) + { + AcpiOsPrintf ("Missing Interface Name argument\n"); + return; + } + + /* Uppercase the action for match below */ + + AcpiUtStrupr (ActionArg); + + /* Install - install an interface */ + + SubString = strstr ("INSTALL", ActionArg); + if (SubString) + { + Status = AcpiInstallInterface (InterfaceNameArg); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, while installing \"%s\"\n", + AcpiFormatException (Status), InterfaceNameArg); + } + return; + } + + /* Remove - remove an interface */ + + SubString = strstr ("REMOVE", ActionArg); + if (SubString) + { + Status = AcpiRemoveInterface (InterfaceNameArg); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, while removing \"%s\"\n", + AcpiFormatException (Status), InterfaceNameArg); + } + return; + } + + /* Invalid ActionArg */ + + AcpiOsPrintf ("Invalid action argument: %s\n", ActionArg); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayTemplate + * + * PARAMETERS: BufferArg - Buffer name or address + * + * RETURN: None + * + * DESCRIPTION: Dump a buffer that contains a resource template + * + ******************************************************************************/ + +void +AcpiDbDisplayTemplate ( + char *BufferArg) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_BUFFER ReturnBuffer; + + + /* Translate BufferArg to an Named object */ + + Node = AcpiDbConvertToNode (BufferArg); + if (!Node || (Node == AcpiGbl_RootNode)) + { + AcpiOsPrintf ("Invalid argument: %s\n", BufferArg); + return; + } + + /* We must have a buffer object */ + + if (Node->Type != ACPI_TYPE_BUFFER) + { + AcpiOsPrintf ("Not a Buffer object, cannot be a template: %s\n", + BufferArg); + return; + } + + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + + /* Attempt to convert the raw buffer to a resource list */ + + Status = AcpiRsCreateResourceList (Node->Object, &ReturnBuffer); + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + AcpiDbgLevel |= ACPI_LV_RESOURCES; + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ( + "Could not convert Buffer to a resource list: %s, %s\n", + BufferArg, AcpiFormatException (Status)); + goto DumpBuffer; + } + + /* Now we can dump the resource list */ + + AcpiRsDumpResourceList (ACPI_CAST_PTR (ACPI_RESOURCE, + ReturnBuffer.Pointer)); + +DumpBuffer: + AcpiOsPrintf ("\nRaw data buffer:\n"); + AcpiUtDebugDumpBuffer ((UINT8 *) Node->Object->Buffer.Pointer, + Node->Object->Buffer.Length, + DB_BYTE_DISPLAY, ACPI_UINT32_MAX); + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCompareAmlResources + * + * PARAMETERS: Aml1Buffer - Contains first resource list + * Aml1BufferLength - Length of first resource list + * Aml2Buffer - Contains second resource list + * Aml2BufferLength - Length of second resource list + * + * RETURN: None + * + * DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in + * order to isolate a miscompare to an individual resource) + * + ******************************************************************************/ + +static void +AcpiDmCompareAmlResources ( + UINT8 *Aml1Buffer, + ACPI_RSDESC_SIZE Aml1BufferLength, + UINT8 *Aml2Buffer, + ACPI_RSDESC_SIZE Aml2BufferLength) +{ + UINT8 *Aml1; + UINT8 *Aml2; + UINT8 *Aml1End; + UINT8 *Aml2End; + ACPI_RSDESC_SIZE Aml1Length; + ACPI_RSDESC_SIZE Aml2Length; + ACPI_RSDESC_SIZE Offset = 0; + UINT8 ResourceType; + UINT32 Count = 0; + UINT32 i; + + + /* Compare overall buffer sizes (may be different due to size rounding) */ + + if (Aml1BufferLength != Aml2BufferLength) + { + AcpiOsPrintf ( + "**** Buffer length mismatch in converted " + "AML: Original %X, New %X ****\n", + Aml1BufferLength, Aml2BufferLength); + } + + Aml1 = Aml1Buffer; + Aml2 = Aml2Buffer; + Aml1End = Aml1Buffer + Aml1BufferLength; + Aml2End = Aml2Buffer + Aml2BufferLength; + + /* Walk the descriptor lists, comparing each descriptor */ + + while ((Aml1 < Aml1End) && (Aml2 < Aml2End)) + { + /* Get the lengths of each descriptor */ + + Aml1Length = AcpiUtGetDescriptorLength (Aml1); + Aml2Length = AcpiUtGetDescriptorLength (Aml2); + ResourceType = AcpiUtGetResourceType (Aml1); + + /* Check for descriptor length match */ + + if (Aml1Length != Aml2Length) + { + AcpiOsPrintf ( + "**** Length mismatch in descriptor [%.2X] type %2.2X, " + "Offset %8.8X Len1 %X, Len2 %X ****\n", + Count, ResourceType, Offset, Aml1Length, Aml2Length); + } + + /* Check for descriptor byte match */ + + else if (memcmp (Aml1, Aml2, Aml1Length)) + { + AcpiOsPrintf ( + "**** Data mismatch in descriptor [%.2X] type %2.2X, " + "Offset %8.8X ****\n", + Count, ResourceType, Offset); + + for (i = 0; i < Aml1Length; i++) + { + if (Aml1[i] != Aml2[i]) + { + AcpiOsPrintf ( + "Mismatch at byte offset %.2X: is %2.2X, " + "should be %2.2X\n", + i, Aml2[i], Aml1[i]); + } + } + } + + /* Exit on EndTag descriptor */ + + if (ResourceType == ACPI_RESOURCE_NAME_END_TAG) + { + return; + } + + /* Point to next descriptor in each buffer */ + + Count++; + Offset += Aml1Length; + Aml1 += Aml1Length; + Aml2 += Aml2Length; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmTestResourceConversion + * + * PARAMETERS: Node - Parent device node + * Name - resource method name (_CRS) + * + * RETURN: Status + * + * DESCRIPTION: Compare the original AML with a conversion of the AML to + * internal resource list, then back to AML. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmTestResourceConversion ( + ACPI_NAMESPACE_NODE *Node, + char *Name) +{ + ACPI_STATUS Status; + ACPI_BUFFER ReturnBuffer; + ACPI_BUFFER ResourceBuffer; + ACPI_BUFFER NewAml; + ACPI_OBJECT *OriginalAml; + + + AcpiOsPrintf ("Resource Conversion Comparison:\n"); + + NewAml.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + ReturnBuffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + ResourceBuffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + /* Get the original _CRS AML resource template */ + + Status = AcpiEvaluateObject (Node, Name, NULL, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not obtain %s: %s\n", + Name, AcpiFormatException (Status)); + return (Status); + } + + /* Get the AML resource template, converted to internal resource structs */ + + Status = AcpiGetCurrentResources (Node, &ResourceBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiGetCurrentResources failed: %s\n", + AcpiFormatException (Status)); + goto Exit1; + } + + /* Convert internal resource list to external AML resource template */ + + Status = AcpiRsCreateAmlResources (&ResourceBuffer, &NewAml); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiRsCreateAmlResources failed: %s\n", + AcpiFormatException (Status)); + goto Exit2; + } + + /* Compare original AML to the newly created AML resource list */ + + OriginalAml = ReturnBuffer.Pointer; + + AcpiDmCompareAmlResources (OriginalAml->Buffer.Pointer, + (ACPI_RSDESC_SIZE) OriginalAml->Buffer.Length, + NewAml.Pointer, (ACPI_RSDESC_SIZE) NewAml.Length); + + /* Cleanup and exit */ + + ACPI_FREE (NewAml.Pointer); +Exit2: + ACPI_FREE (ResourceBuffer.Pointer); +Exit1: + ACPI_FREE (ReturnBuffer.Pointer); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbResourceCallback + * + * PARAMETERS: ACPI_WALK_RESOURCE_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Simple callback to exercise AcpiWalkResources and + * AcpiWalkResourceBuffer. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbResourceCallback ( + ACPI_RESOURCE *Resource, + void *Context) +{ + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDeviceResources + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbDeviceResources ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_NAMESPACE_NODE *PrtNode = NULL; + ACPI_NAMESPACE_NODE *CrsNode = NULL; + ACPI_NAMESPACE_NODE *PrsNode = NULL; + ACPI_NAMESPACE_NODE *AeiNode = NULL; + char *ParentPath; + ACPI_BUFFER ReturnBuffer; + ACPI_STATUS Status; + + + Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + ParentPath = AcpiNsGetNormalizedPathname (Node, TRUE); + if (!ParentPath) + { + return (AE_NO_MEMORY); + } + + /* Get handles to the resource methods for this device */ + + (void) AcpiGetHandle (Node, METHOD_NAME__PRT, + ACPI_CAST_PTR (ACPI_HANDLE, &PrtNode)); + (void) AcpiGetHandle (Node, METHOD_NAME__CRS, + ACPI_CAST_PTR (ACPI_HANDLE, &CrsNode)); + (void) AcpiGetHandle (Node, METHOD_NAME__PRS, + ACPI_CAST_PTR (ACPI_HANDLE, &PrsNode)); + (void) AcpiGetHandle (Node, METHOD_NAME__AEI, + ACPI_CAST_PTR (ACPI_HANDLE, &AeiNode)); + + if (!PrtNode && !CrsNode && !PrsNode && !AeiNode) + { + goto Cleanup; /* Nothing to do */ + } + + AcpiOsPrintf ("\nDevice: %s\n", ParentPath); + + /* Prepare for a return object of arbitrary size */ + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + + /* _PRT */ + + if (PrtNode) + { + AcpiOsPrintf ("Evaluating _PRT\n"); + + Status = AcpiEvaluateObject (PrtNode, NULL, NULL, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not evaluate _PRT: %s\n", + AcpiFormatException (Status)); + goto GetCrs; + } + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + Status = AcpiGetIrqRoutingTable (Node, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("GetIrqRoutingTable failed: %s\n", + AcpiFormatException (Status)); + goto GetCrs; + } + + AcpiRsDumpIrqList (ACPI_CAST_PTR (UINT8, AcpiGbl_DbBuffer)); + } + + + /* _CRS */ + +GetCrs: + if (CrsNode) + { + AcpiOsPrintf ("Evaluating _CRS\n"); + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + Status = AcpiEvaluateObject (CrsNode, NULL, NULL, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not evaluate _CRS: %s\n", + AcpiFormatException (Status)); + goto GetPrs; + } + + /* This code exercises the AcpiWalkResources interface */ + + Status = AcpiWalkResources (Node, METHOD_NAME__CRS, + AcpiDbResourceCallback, NULL); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiWalkResources failed: %s\n", + AcpiFormatException (Status)); + goto GetPrs; + } + + /* Get the _CRS resource list (test ALLOCATE buffer) */ + + ReturnBuffer.Pointer = NULL; + ReturnBuffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + Status = AcpiGetCurrentResources (Node, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiGetCurrentResources failed: %s\n", + AcpiFormatException (Status)); + goto GetPrs; + } + + /* This code exercises the AcpiWalkResourceBuffer interface */ + + Status = AcpiWalkResourceBuffer (&ReturnBuffer, + AcpiDbResourceCallback, NULL); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiWalkResourceBuffer failed: %s\n", + AcpiFormatException (Status)); + goto EndCrs; + } + + /* Dump the _CRS resource list */ + + AcpiRsDumpResourceList (ACPI_CAST_PTR (ACPI_RESOURCE, + ReturnBuffer.Pointer)); + + /* + * Perform comparison of original AML to newly created AML. This + * tests both the AML->Resource conversion and the Resource->AML + * conversion. + */ + (void) AcpiDmTestResourceConversion (Node, METHOD_NAME__CRS); + + /* Execute _SRS with the resource list */ + + AcpiOsPrintf ("Evaluating _SRS\n"); + + Status = AcpiSetCurrentResources (Node, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiSetCurrentResources failed: %s\n", + AcpiFormatException (Status)); + goto EndCrs; + } + +EndCrs: + ACPI_FREE (ReturnBuffer.Pointer); + } + + + /* _PRS */ + +GetPrs: + if (PrsNode) + { + AcpiOsPrintf ("Evaluating _PRS\n"); + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + Status = AcpiEvaluateObject (PrsNode, NULL, NULL, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not evaluate _PRS: %s\n", + AcpiFormatException (Status)); + goto GetAei; + } + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + Status = AcpiGetPossibleResources (Node, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiGetPossibleResources failed: %s\n", + AcpiFormatException (Status)); + goto GetAei; + } + + AcpiRsDumpResourceList (ACPI_CAST_PTR ( + ACPI_RESOURCE, AcpiGbl_DbBuffer)); + } + + + /* _AEI */ + +GetAei: + if (AeiNode) + { + AcpiOsPrintf ("Evaluating _AEI\n"); + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + Status = AcpiEvaluateObject (AeiNode, NULL, NULL, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not evaluate _AEI: %s\n", + AcpiFormatException (Status)); + goto Cleanup; + } + + ReturnBuffer.Pointer = AcpiGbl_DbBuffer; + ReturnBuffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + Status = AcpiGetEventResources (Node, &ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("AcpiGetEventResources failed: %s\n", + AcpiFormatException (Status)); + goto Cleanup; + } + + AcpiRsDumpResourceList (ACPI_CAST_PTR ( + ACPI_RESOURCE, AcpiGbl_DbBuffer)); + } + + +Cleanup: + ACPI_FREE (ParentPath); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayResources + * + * PARAMETERS: ObjectArg - String object name or object pointer. + * NULL or "*" means "display resources for + * all devices" + * + * RETURN: None + * + * DESCRIPTION: Display the resource objects associated with a device. + * + ******************************************************************************/ + +void +AcpiDbDisplayResources ( + char *ObjectArg) +{ + ACPI_NAMESPACE_NODE *Node; + + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + AcpiDbgLevel |= ACPI_LV_RESOURCES; + + /* Asterisk means "display resources for all devices" */ + + if (!ObjectArg || (!strcmp (ObjectArg, "*"))) + { + (void) AcpiWalkNamespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbDeviceResources, NULL, NULL, NULL); + } + else + { + /* Convert string to object pointer */ + + Node = AcpiDbConvertToNode (ObjectArg); + if (Node) + { + if (Node->Type != ACPI_TYPE_DEVICE) + { + AcpiOsPrintf ( + "%4.4s: Name is not a device object (%s)\n", + Node->Name.Ascii, AcpiUtGetTypeName (Node->Type)); + } + else + { + (void) AcpiDbDeviceResources (Node, 0, NULL, NULL); + } + } + } + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiDbGenerateGpe + * + * PARAMETERS: GpeArg - Raw GPE number, ascii string + * BlockArg - GPE block number, ascii string + * 0 or 1 for FADT GPE blocks + * + * RETURN: None + * + * DESCRIPTION: Simulate firing of a GPE + * + ******************************************************************************/ + +void +AcpiDbGenerateGpe ( + char *GpeArg, + char *BlockArg) +{ + UINT32 BlockNumber = 0; + UINT32 GpeNumber; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + + + GpeNumber = strtoul (GpeArg, NULL, 0); + + /* + * If no block arg, or block arg == 0 or 1, use the FADT-defined + * GPE blocks. + */ + if (BlockArg) + { + BlockNumber = strtoul (BlockArg, NULL, 0); + if (BlockNumber == 1) + { + BlockNumber = 0; + } + } + + GpeEventInfo = AcpiEvGetGpeEventInfo ( + ACPI_TO_POINTER (BlockNumber), GpeNumber); + if (!GpeEventInfo) + { + AcpiOsPrintf ("Invalid GPE\n"); + return; + } + + (void) AcpiEvGpeDispatch (NULL, GpeEventInfo, GpeNumber); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGenerateSci + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Simulate an SCI -- just call the SCI dispatch. + * + ******************************************************************************/ + +void +AcpiDbGenerateSci ( + void) +{ + AcpiEvSciDispatch (); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiDbTrace + * + * PARAMETERS: EnableArg - ENABLE/AML to enable tracer + * DISABLE to disable tracer + * MethodArg - Method to trace + * OnceArg - Whether trace once + * + * RETURN: None + * + * DESCRIPTION: Control method tracing facility + * + ******************************************************************************/ + +void +AcpiDbTrace ( + char *EnableArg, + char *MethodArg, + char *OnceArg) +{ + UINT32 DebugLevel = 0; + UINT32 DebugLayer = 0; + UINT32 Flags = 0; + + + AcpiUtStrupr (EnableArg); + AcpiUtStrupr (OnceArg); + + if (MethodArg) + { + if (AcpiDbTraceMethodName) + { + ACPI_FREE (AcpiDbTraceMethodName); + AcpiDbTraceMethodName = NULL; + } + + AcpiDbTraceMethodName = ACPI_ALLOCATE (strlen (MethodArg) + 1); + if (!AcpiDbTraceMethodName) + { + AcpiOsPrintf ("Failed to allocate method name (%s)\n", + MethodArg); + return; + } + + strcpy (AcpiDbTraceMethodName, MethodArg); + } + + if (!strcmp (EnableArg, "ENABLE") || + !strcmp (EnableArg, "METHOD") || + !strcmp (EnableArg, "OPCODE")) + { + if (!strcmp (EnableArg, "ENABLE")) + { + /* Inherit current console settings */ + + DebugLevel = AcpiGbl_DbConsoleDebugLevel; + DebugLayer = AcpiDbgLayer; + } + else + { + /* Restrict console output to trace points only */ + + DebugLevel = ACPI_LV_TRACE_POINT; + DebugLayer = ACPI_EXECUTER; + } + + Flags = ACPI_TRACE_ENABLED; + + if (!strcmp (EnableArg, "OPCODE")) + { + Flags |= ACPI_TRACE_OPCODE; + } + + if (OnceArg && !strcmp (OnceArg, "ONCE")) + { + Flags |= ACPI_TRACE_ONESHOT; + } + } + + (void) AcpiDebugTrace (AcpiDbTraceMethodName, + DebugLevel, DebugLayer, Flags); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbconvert.c b/third_party/lib/acpica/source/components/debugger/dbconvert.c new file mode 100644 index 000000000..fc3bbda8a --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbconvert.c @@ -0,0 +1,529 @@ +/******************************************************************************* + * + * Module Name: dbconvert - debugger miscellaneous conversion routines + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbconvert") + + +#define DB_DEFAULT_PKG_ELEMENTS 33 + + +/******************************************************************************* + * + * FUNCTION: AcpiDbHexCharToValue + * + * PARAMETERS: HexChar - Ascii Hex digit, 0-9|a-f|A-F + * ReturnValue - Where the converted value is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbHexCharToValue ( + int HexChar, + UINT8 *ReturnValue) +{ + UINT8 Value; + + + /* Digit must be ascii [0-9a-fA-F] */ + + if (!isxdigit (HexChar)) + { + return (AE_BAD_HEX_CONSTANT); + } + + if (HexChar <= 0x39) + { + Value = (UINT8) (HexChar - 0x30); + } + else + { + Value = (UINT8) (toupper (HexChar) - 0x37); + } + + *ReturnValue = Value; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbHexByteToBinary + * + * PARAMETERS: HexByte - Double hex digit (0x00 - 0xFF) in format: + * HiByte then LoByte. + * ReturnValue - Where the converted value is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255). + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbHexByteToBinary ( + char *HexByte, + UINT8 *ReturnValue) +{ + UINT8 Local0; + UINT8 Local1; + ACPI_STATUS Status; + + + /* High byte */ + + Status = AcpiDbHexCharToValue (HexByte[0], &Local0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Low byte */ + + Status = AcpiDbHexCharToValue (HexByte[1], &Local1); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *ReturnValue = (UINT8) ((Local0 << 4) | Local1); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbConvertToBuffer + * + * PARAMETERS: String - Input string to be converted + * Object - Where the buffer object is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a string to a buffer object. String is treated a list + * of buffer elements, each separated by a space or comma. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbConvertToBuffer ( + char *String, + ACPI_OBJECT *Object) +{ + UINT32 i; + UINT32 j; + UINT32 Length; + UINT8 *Buffer; + ACPI_STATUS Status; + + + /* Generate the final buffer length */ + + for (i = 0, Length = 0; String[i];) + { + i+=2; + Length++; + + while (String[i] && + ((String[i] == ',') || (String[i] == ' '))) + { + i++; + } + } + + Buffer = ACPI_ALLOCATE (Length); + if (!Buffer) + { + return (AE_NO_MEMORY); + } + + /* Convert the command line bytes to the buffer */ + + for (i = 0, j = 0; String[i];) + { + Status = AcpiDbHexByteToBinary (&String[i], &Buffer[j]); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (Buffer); + return (Status); + } + + j++; + i += 2; + while (String[i] && + ((String[i] == ',') || (String[i] == ' '))) + { + i++; + } + } + + Object->Type = ACPI_TYPE_BUFFER; + Object->Buffer.Pointer = Buffer; + Object->Buffer.Length = Length; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbConvertToPackage + * + * PARAMETERS: String - Input string to be converted + * Object - Where the package object is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a string to a package object. Handles nested packages + * via recursion with AcpiDbConvertToObject. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbConvertToPackage ( + char *String, + ACPI_OBJECT *Object) +{ + char *This; + char *Next; + UINT32 i; + ACPI_OBJECT_TYPE Type; + ACPI_OBJECT *Elements; + ACPI_STATUS Status; + + + Elements = ACPI_ALLOCATE_ZEROED ( + DB_DEFAULT_PKG_ELEMENTS * sizeof (ACPI_OBJECT)); + + This = String; + for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) + { + This = AcpiDbGetNextToken (This, &Next, &Type); + if (!This) + { + break; + } + + /* Recursive call to convert each package element */ + + Status = AcpiDbConvertToObject (Type, This, &Elements[i]); + if (ACPI_FAILURE (Status)) + { + AcpiDbDeleteObjects (i + 1, Elements); + ACPI_FREE (Elements); + return (Status); + } + + This = Next; + } + + Object->Type = ACPI_TYPE_PACKAGE; + Object->Package.Count = i; + Object->Package.Elements = Elements; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbConvertToObject + * + * PARAMETERS: Type - Object type as determined by parser + * String - Input string to be converted + * Object - Where the new object is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a typed and tokenized string to an ACPI_OBJECT. Typing: + * 1) String objects were surrounded by quotes. + * 2) Buffer objects were surrounded by parentheses. + * 3) Package objects were surrounded by brackets "[]". + * 4) All standalone tokens are treated as integers. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbConvertToObject ( + ACPI_OBJECT_TYPE Type, + char *String, + ACPI_OBJECT *Object) +{ + ACPI_STATUS Status = AE_OK; + + + switch (Type) + { + case ACPI_TYPE_STRING: + + Object->Type = ACPI_TYPE_STRING; + Object->String.Pointer = String; + Object->String.Length = (UINT32) strlen (String); + break; + + case ACPI_TYPE_BUFFER: + + Status = AcpiDbConvertToBuffer (String, Object); + break; + + case ACPI_TYPE_PACKAGE: + + Status = AcpiDbConvertToPackage (String, Object); + break; + + default: + + Object->Type = ACPI_TYPE_INTEGER; + Status = AcpiUtStrtoul64 (String, 16, &Object->Integer.Value); + break; + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbEncodePldBuffer + * + * PARAMETERS: PldInfo - _PLD buffer struct (Using local struct) + * + * RETURN: Encode _PLD buffer suitable for return value from _PLD + * + * DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros + * + ******************************************************************************/ + +UINT8 * +AcpiDbEncodePldBuffer ( + ACPI_PLD_INFO *PldInfo) +{ + UINT32 *Buffer; + UINT32 Dword; + + + Buffer = ACPI_ALLOCATE_ZEROED (ACPI_PLD_BUFFER_SIZE); + if (!Buffer) + { + return (NULL); + } + + /* First 32 bits */ + + Dword = 0; + ACPI_PLD_SET_REVISION (&Dword, PldInfo->Revision); + ACPI_PLD_SET_IGNORE_COLOR (&Dword, PldInfo->IgnoreColor); + ACPI_PLD_SET_RED (&Dword, PldInfo->Red); + ACPI_PLD_SET_GREEN (&Dword, PldInfo->Green); + ACPI_PLD_SET_BLUE (&Dword, PldInfo->Blue); + ACPI_MOVE_32_TO_32 (&Buffer[0], &Dword); + + /* Second 32 bits */ + + Dword = 0; + ACPI_PLD_SET_WIDTH (&Dword, PldInfo->Width); + ACPI_PLD_SET_HEIGHT (&Dword, PldInfo->Height); + ACPI_MOVE_32_TO_32 (&Buffer[1], &Dword); + + /* Third 32 bits */ + + Dword = 0; + ACPI_PLD_SET_USER_VISIBLE (&Dword, PldInfo->UserVisible); + ACPI_PLD_SET_DOCK (&Dword, PldInfo->Dock); + ACPI_PLD_SET_LID (&Dword, PldInfo->Lid); + ACPI_PLD_SET_PANEL (&Dword, PldInfo->Panel); + ACPI_PLD_SET_VERTICAL (&Dword, PldInfo->VerticalPosition); + ACPI_PLD_SET_HORIZONTAL (&Dword, PldInfo->HorizontalPosition); + ACPI_PLD_SET_SHAPE (&Dword, PldInfo->Shape); + ACPI_PLD_SET_ORIENTATION (&Dword, PldInfo->GroupOrientation); + ACPI_PLD_SET_TOKEN (&Dword, PldInfo->GroupToken); + ACPI_PLD_SET_POSITION (&Dword, PldInfo->GroupPosition); + ACPI_PLD_SET_BAY (&Dword, PldInfo->Bay); + ACPI_MOVE_32_TO_32 (&Buffer[2], &Dword); + + /* Fourth 32 bits */ + + Dword = 0; + ACPI_PLD_SET_EJECTABLE (&Dword, PldInfo->Ejectable); + ACPI_PLD_SET_OSPM_EJECT (&Dword, PldInfo->OspmEjectRequired); + ACPI_PLD_SET_CABINET (&Dword, PldInfo->CabinetNumber); + ACPI_PLD_SET_CARD_CAGE (&Dword, PldInfo->CardCageNumber); + ACPI_PLD_SET_REFERENCE (&Dword, PldInfo->Reference); + ACPI_PLD_SET_ROTATION (&Dword, PldInfo->Rotation); + ACPI_PLD_SET_ORDER (&Dword, PldInfo->Order); + ACPI_MOVE_32_TO_32 (&Buffer[3], &Dword); + + if (PldInfo->Revision >= 2) + { + /* Fifth 32 bits */ + + Dword = 0; + ACPI_PLD_SET_VERT_OFFSET (&Dword, PldInfo->VerticalOffset); + ACPI_PLD_SET_HORIZ_OFFSET (&Dword, PldInfo->HorizontalOffset); + ACPI_MOVE_32_TO_32 (&Buffer[4], &Dword); + } + + return (ACPI_CAST_PTR (UINT8, Buffer)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpPldBuffer + * + * PARAMETERS: ObjDesc - Object returned from _PLD method + * + * RETURN: None. + * + * DESCRIPTION: Dumps formatted contents of a _PLD return buffer. + * + ******************************************************************************/ + +#define ACPI_PLD_OUTPUT "%20s : %-6X\n" + +void +AcpiDbDumpPldBuffer ( + ACPI_OBJECT *ObjDesc) +{ + ACPI_OBJECT *BufferDesc; + ACPI_PLD_INFO *PldInfo; + UINT8 *NewBuffer; + ACPI_STATUS Status; + + + /* Object must be of type Package with at least one Buffer element */ + + if (ObjDesc->Type != ACPI_TYPE_PACKAGE) + { + return; + } + + BufferDesc = &ObjDesc->Package.Elements[0]; + if (BufferDesc->Type != ACPI_TYPE_BUFFER) + { + return; + } + + /* Convert _PLD buffer to local _PLD struct */ + + Status = AcpiDecodePldBuffer (BufferDesc->Buffer.Pointer, + BufferDesc->Buffer.Length, &PldInfo); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Encode local _PLD struct back to a _PLD buffer */ + + NewBuffer = AcpiDbEncodePldBuffer (PldInfo); + if (!NewBuffer) + { + return; + } + + /* The two bit-packed buffers should match */ + + if (memcmp (NewBuffer, BufferDesc->Buffer.Pointer, + BufferDesc->Buffer.Length)) + { + AcpiOsPrintf ("Converted _PLD buffer does not compare. New:\n"); + + AcpiUtDumpBuffer (NewBuffer, + BufferDesc->Buffer.Length, DB_BYTE_DISPLAY, 0); + } + + /* First 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Revision", PldInfo->Revision); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_IgnoreColor", PldInfo->IgnoreColor); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Red", PldInfo->Red); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Green", PldInfo->Green); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Blue", PldInfo->Blue); + + /* Second 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Width", PldInfo->Width); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Height", PldInfo->Height); + + /* Third 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_UserVisible", PldInfo->UserVisible); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Dock", PldInfo->Dock); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Lid", PldInfo->Lid); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Panel", PldInfo->Panel); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_VerticalPosition", PldInfo->VerticalPosition); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_HorizontalPosition", PldInfo->HorizontalPosition); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Shape", PldInfo->Shape); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_GroupOrientation", PldInfo->GroupOrientation); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_GroupToken", PldInfo->GroupToken); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_GroupPosition", PldInfo->GroupPosition); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Bay", PldInfo->Bay); + + /* Fourth 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Ejectable", PldInfo->Ejectable); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_EjectRequired", PldInfo->OspmEjectRequired); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_CabinetNumber", PldInfo->CabinetNumber); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_CardCageNumber", PldInfo->CardCageNumber); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Reference", PldInfo->Reference); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Rotation", PldInfo->Rotation); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_Order", PldInfo->Order); + + /* Fifth 32-bit dword */ + + if (BufferDesc->Buffer.Length > 16) + { + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_VerticalOffset", PldInfo->VerticalOffset); + AcpiOsPrintf (ACPI_PLD_OUTPUT, "PLD_HorizontalOffset", PldInfo->HorizontalOffset); + } + + ACPI_FREE (PldInfo); + ACPI_FREE (NewBuffer); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbdisply.c b/third_party/lib/acpica/source/components/debugger/dbdisply.c new file mode 100644 index 000000000..073874109 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbdisply.c @@ -0,0 +1,1196 @@ +/******************************************************************************* + * + * Module Name: dbdisply - debug display commands + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acparser.h" +#include "acinterp.h" +#include "acevents.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbdisply") + +/* Local prototypes */ + +static void +AcpiDbDumpParserDescriptor ( + ACPI_PARSE_OBJECT *Op); + +static void * +AcpiDbGetPointer ( + void *Target); + +static ACPI_STATUS +AcpiDbDisplayNonRootHandlers ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +/* + * System handler information. + * Used for Handlers command, in AcpiDbDisplayHandlers. + */ +#define ACPI_PREDEFINED_PREFIX "%25s (%.2X) : " +#define ACPI_HANDLER_NAME_STRING "%30s : " +#define ACPI_HANDLER_PRESENT_STRING "%-9s (%p)\n" +#define ACPI_HANDLER_PRESENT_STRING2 "%-9s (%p)" +#define ACPI_HANDLER_NOT_PRESENT_STRING "%-9s\n" + +/* All predefined Address Space IDs */ + +static ACPI_ADR_SPACE_TYPE AcpiGbl_SpaceIdList[] = +{ + ACPI_ADR_SPACE_SYSTEM_MEMORY, + ACPI_ADR_SPACE_SYSTEM_IO, + ACPI_ADR_SPACE_PCI_CONFIG, + ACPI_ADR_SPACE_EC, + ACPI_ADR_SPACE_SMBUS, + ACPI_ADR_SPACE_CMOS, + ACPI_ADR_SPACE_PCI_BAR_TARGET, + ACPI_ADR_SPACE_IPMI, + ACPI_ADR_SPACE_GPIO, + ACPI_ADR_SPACE_GSBUS, + ACPI_ADR_SPACE_DATA_TABLE, + ACPI_ADR_SPACE_FIXED_HARDWARE +}; + +/* Global handler information */ + +typedef struct acpi_handler_info +{ + void *Handler; + char *Name; + +} ACPI_HANDLER_INFO; + +static ACPI_HANDLER_INFO AcpiGbl_HandlerList[] = +{ + {&AcpiGbl_GlobalNotify[0].Handler, "System Notifications"}, + {&AcpiGbl_GlobalNotify[1].Handler, "Device Notifications"}, + {&AcpiGbl_TableHandler, "ACPI Table Events"}, + {&AcpiGbl_ExceptionHandler, "Control Method Exceptions"}, + {&AcpiGbl_InterfaceHandler, "OSI Invocations"} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetPointer + * + * PARAMETERS: Target - Pointer to string to be converted + * + * RETURN: Converted pointer + * + * DESCRIPTION: Convert an ascii pointer value to a real value + * + ******************************************************************************/ + +static void * +AcpiDbGetPointer ( + void *Target) +{ + void *ObjPtr; + ACPI_SIZE Address; + + + Address = strtoul (Target, NULL, 16); + ObjPtr = ACPI_TO_POINTER (Address); + return (ObjPtr); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpParserDescriptor + * + * PARAMETERS: Op - A parser Op descriptor + * + * RETURN: None + * + * DESCRIPTION: Display a formatted parser object + * + ******************************************************************************/ + +static void +AcpiDbDumpParserDescriptor ( + ACPI_PARSE_OBJECT *Op) +{ + const ACPI_OPCODE_INFO *Info; + + + Info = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + AcpiOsPrintf ("Parser Op Descriptor:\n"); + AcpiOsPrintf ("%20.20s : %4.4X\n", "Opcode", Op->Common.AmlOpcode); + + ACPI_DEBUG_ONLY_MEMBERS (AcpiOsPrintf ("%20.20s : %s\n", "Opcode Name", + Info->Name)); + + AcpiOsPrintf ("%20.20s : %p\n", "Value/ArgList", Op->Common.Value.Arg); + AcpiOsPrintf ("%20.20s : %p\n", "Parent", Op->Common.Parent); + AcpiOsPrintf ("%20.20s : %p\n", "NextOp", Op->Common.Next); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDecodeAndDisplayObject + * + * PARAMETERS: Target - String with object to be displayed. Names + * and hex pointers are supported. + * OutputType - Byte, Word, Dword, or Qword (B|W|D|Q) + * + * RETURN: None + * + * DESCRIPTION: Display a formatted ACPI object + * + ******************************************************************************/ + +void +AcpiDbDecodeAndDisplayObject ( + char *Target, + char *OutputType) +{ + void *ObjPtr; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 Display = DB_BYTE_DISPLAY; + char Buffer[80]; + ACPI_BUFFER RetBuf; + ACPI_STATUS Status; + UINT32 Size; + + + if (!Target) + { + return; + } + + /* Decode the output type */ + + if (OutputType) + { + AcpiUtStrupr (OutputType); + if (OutputType[0] == 'W') + { + Display = DB_WORD_DISPLAY; + } + else if (OutputType[0] == 'D') + { + Display = DB_DWORD_DISPLAY; + } + else if (OutputType[0] == 'Q') + { + Display = DB_QWORD_DISPLAY; + } + } + + RetBuf.Length = sizeof (Buffer); + RetBuf.Pointer = Buffer; + + /* Differentiate between a number and a name */ + + if ((Target[0] >= 0x30) && (Target[0] <= 0x39)) + { + ObjPtr = AcpiDbGetPointer (Target); + if (!AcpiOsReadable (ObjPtr, 16)) + { + AcpiOsPrintf ( + "Address %p is invalid in this address space\n", + ObjPtr); + return; + } + + /* Decode the object type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjPtr)) + { + case ACPI_DESC_TYPE_NAMED: + + /* This is a namespace Node */ + + if (!AcpiOsReadable (ObjPtr, sizeof (ACPI_NAMESPACE_NODE))) + { + AcpiOsPrintf ( + "Cannot read entire Named object at address %p\n", + ObjPtr); + return; + } + + Node = ObjPtr; + goto DumpNode; + + case ACPI_DESC_TYPE_OPERAND: + + /* This is a ACPI OPERAND OBJECT */ + + if (!AcpiOsReadable (ObjPtr, sizeof (ACPI_OPERAND_OBJECT))) + { + AcpiOsPrintf ( + "Cannot read entire ACPI object at address %p\n", + ObjPtr); + return; + } + + AcpiUtDebugDumpBuffer (ObjPtr, sizeof (ACPI_OPERAND_OBJECT), + Display, ACPI_UINT32_MAX); + AcpiExDumpObjectDescriptor (ObjPtr, 1); + break; + + case ACPI_DESC_TYPE_PARSER: + + /* This is a Parser Op object */ + + if (!AcpiOsReadable (ObjPtr, sizeof (ACPI_PARSE_OBJECT))) + { + AcpiOsPrintf ( + "Cannot read entire Parser object at address %p\n", + ObjPtr); + return; + } + + AcpiUtDebugDumpBuffer (ObjPtr, sizeof (ACPI_PARSE_OBJECT), + Display, ACPI_UINT32_MAX); + AcpiDbDumpParserDescriptor ((ACPI_PARSE_OBJECT *) ObjPtr); + break; + + default: + + /* Is not a recognizeable object */ + + AcpiOsPrintf ( + "Not a known ACPI internal object, descriptor type %2.2X\n", + ACPI_GET_DESCRIPTOR_TYPE (ObjPtr)); + + Size = 16; + if (AcpiOsReadable (ObjPtr, 64)) + { + Size = 64; + } + + /* Just dump some memory */ + + AcpiUtDebugDumpBuffer (ObjPtr, Size, Display, ACPI_UINT32_MAX); + break; + } + + return; + } + + /* The parameter is a name string that must be resolved to a Named obj */ + + Node = AcpiDbLocalNsLookup (Target); + if (!Node) + { + return; + } + + +DumpNode: + /* Now dump the NS node */ + + Status = AcpiGetName (Node, ACPI_FULL_PATHNAME_NO_TRAILING, &RetBuf); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not convert name to pathname\n"); + } + + else + { + AcpiOsPrintf ("Object (%p) Pathname: %s\n", + Node, (char *) RetBuf.Pointer); + } + + if (!AcpiOsReadable (Node, sizeof (ACPI_NAMESPACE_NODE))) + { + AcpiOsPrintf ("Invalid Named object at address %p\n", Node); + return; + } + + AcpiUtDebugDumpBuffer ((void *) Node, sizeof (ACPI_NAMESPACE_NODE), + Display, ACPI_UINT32_MAX); + AcpiExDumpNamespaceNode (Node, 1); + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc) + { + AcpiOsPrintf ("\nAttached Object (%p):\n", ObjDesc); + if (!AcpiOsReadable (ObjDesc, sizeof (ACPI_OPERAND_OBJECT))) + { + AcpiOsPrintf ("Invalid internal ACPI Object at address %p\n", + ObjDesc); + return; + } + + AcpiUtDebugDumpBuffer ((void *) ObjDesc, + sizeof (ACPI_OPERAND_OBJECT), Display, ACPI_UINT32_MAX); + AcpiExDumpObjectDescriptor (ObjDesc, 1); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayMethodInfo + * + * PARAMETERS: StartOp - Root of the control method parse tree + * + * RETURN: None + * + * DESCRIPTION: Display information about the current method + * + ******************************************************************************/ + +void +AcpiDbDisplayMethodInfo ( + ACPI_PARSE_OBJECT *StartOp) +{ + ACPI_WALK_STATE *WalkState; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *RootOp; + ACPI_PARSE_OBJECT *Op; + const ACPI_OPCODE_INFO *OpInfo; + UINT32 NumOps = 0; + UINT32 NumOperands = 0; + UINT32 NumOperators = 0; + UINT32 NumRemainingOps = 0; + UINT32 NumRemainingOperands = 0; + UINT32 NumRemainingOperators = 0; + BOOLEAN CountRemaining = FALSE; + + + WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); + if (!WalkState) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + ObjDesc = WalkState->MethodDesc; + Node = WalkState->MethodNode; + + AcpiOsPrintf ("Currently executing control method is [%4.4s]\n", + AcpiUtGetNodeName (Node)); + AcpiOsPrintf ("%X Arguments, SyncLevel = %X\n", + (UINT32) ObjDesc->Method.ParamCount, + (UINT32) ObjDesc->Method.SyncLevel); + + RootOp = StartOp; + while (RootOp->Common.Parent) + { + RootOp = RootOp->Common.Parent; + } + + Op = RootOp; + + while (Op) + { + if (Op == StartOp) + { + CountRemaining = TRUE; + } + + NumOps++; + if (CountRemaining) + { + NumRemainingOps++; + } + + /* Decode the opcode */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + switch (OpInfo->Class) + { + case AML_CLASS_ARGUMENT: + + if (CountRemaining) + { + NumRemainingOperands++; + } + + NumOperands++; + break; + + case AML_CLASS_UNKNOWN: + + /* Bad opcode or ASCII character */ + + continue; + + default: + + if (CountRemaining) + { + NumRemainingOperators++; + } + + NumOperators++; + break; + } + + Op = AcpiPsGetDepthNext (StartOp, Op); + } + + AcpiOsPrintf ( + "Method contains: %X AML Opcodes - %X Operators, %X Operands\n", + NumOps, NumOperators, NumOperands); + + AcpiOsPrintf ( + "Remaining to execute: %X AML Opcodes - %X Operators, %X Operands\n", + NumRemainingOps, NumRemainingOperators, NumRemainingOperands); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayLocals + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display all locals for the currently running control method + * + ******************************************************************************/ + +void +AcpiDbDisplayLocals ( + void) +{ + ACPI_WALK_STATE *WalkState; + + + WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); + if (!WalkState) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + AcpiDbDecodeLocals (WalkState); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayArguments + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display all arguments for the currently running control method + * + ******************************************************************************/ + +void +AcpiDbDisplayArguments ( + void) +{ + ACPI_WALK_STATE *WalkState; + + + WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); + if (!WalkState) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + AcpiDbDecodeArguments (WalkState); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayResults + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display current contents of a method result stack + * + ******************************************************************************/ + +void +AcpiDbDisplayResults ( + void) +{ + UINT32 i; + ACPI_WALK_STATE *WalkState; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 ResultCount = 0; + ACPI_NAMESPACE_NODE *Node; + ACPI_GENERIC_STATE *Frame; + UINT32 Index; /* Index onto current frame */ + + + WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); + if (!WalkState) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + ObjDesc = WalkState->MethodDesc; + Node = WalkState->MethodNode; + + if (WalkState->Results) + { + ResultCount = WalkState->ResultCount; + } + + AcpiOsPrintf ("Method [%4.4s] has %X stacked result objects\n", + AcpiUtGetNodeName (Node), ResultCount); + + /* From the top element of result stack */ + + Frame = WalkState->Results; + Index = (ResultCount - 1) % ACPI_RESULTS_FRAME_OBJ_NUM; + + for (i = 0; i < ResultCount; i++) + { + ObjDesc = Frame->Results.ObjDesc[Index]; + AcpiOsPrintf ("Result%u: ", i); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); + + if (Index == 0) + { + Frame = Frame->Results.Next; + Index = ACPI_RESULTS_FRAME_OBJ_NUM; + } + + Index--; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayCallingTree + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display current calling tree of nested control methods + * + ******************************************************************************/ + +void +AcpiDbDisplayCallingTree ( + void) +{ + ACPI_WALK_STATE *WalkState; + ACPI_NAMESPACE_NODE *Node; + + + WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); + if (!WalkState) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + Node = WalkState->MethodNode; + AcpiOsPrintf ("Current Control Method Call Tree\n"); + + while (WalkState) + { + Node = WalkState->MethodNode; + AcpiOsPrintf (" [%4.4s]\n", AcpiUtGetNodeName (Node)); + + WalkState = WalkState->Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayObjectType + * + * PARAMETERS: ObjectArg - User entered NS node handle + * + * RETURN: None + * + * DESCRIPTION: Display type of an arbitrary NS node + * + ******************************************************************************/ + +void +AcpiDbDisplayObjectType ( + char *ObjectArg) +{ + ACPI_SIZE Arg; + ACPI_HANDLE Handle; + ACPI_DEVICE_INFO *Info; + ACPI_STATUS Status; + UINT32 i; + + + Arg = strtoul (ObjectArg, NULL, 16); + Handle = ACPI_TO_POINTER (Arg); + + Status = AcpiGetObjectInfo (Handle, &Info); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not get object info, %s\n", + AcpiFormatException (Status)); + return; + } + + AcpiOsPrintf ("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n", + ACPI_FORMAT_UINT64 (Info->Address), + Info->CurrentStatus, Info->Flags); + + AcpiOsPrintf ("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n", + Info->HighestDstates[0], Info->HighestDstates[1], + Info->HighestDstates[2], Info->HighestDstates[3]); + + AcpiOsPrintf ("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n", + Info->LowestDstates[0], Info->LowestDstates[1], + Info->LowestDstates[2], Info->LowestDstates[3], + Info->LowestDstates[4]); + + if (Info->Valid & ACPI_VALID_HID) + { + AcpiOsPrintf ("HID: %s\n", Info->HardwareId.String); + } + + if (Info->Valid & ACPI_VALID_UID) + { + AcpiOsPrintf ("UID: %s\n", Info->UniqueId.String); + } + + if (Info->Valid & ACPI_VALID_CID) + { + for (i = 0; i < Info->CompatibleIdList.Count; i++) + { + AcpiOsPrintf ("CID %u: %s\n", i, + Info->CompatibleIdList.Ids[i].String); + } + } + + ACPI_FREE (Info); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayResultObject + * + * PARAMETERS: ObjDesc - Object to be displayed + * WalkState - Current walk state + * + * RETURN: None + * + * DESCRIPTION: Display the result of an AML opcode + * + * Note: Curently only displays the result object if we are single stepping. + * However, this output may be useful in other contexts and could be enabled + * to do so if needed. + * + ******************************************************************************/ + +void +AcpiDbDisplayResultObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + +#ifndef ACPI_APPLICATION + if (AcpiGbl_DbThreadId != AcpiOsGetThreadId()) + { + return; + } +#endif + + /* Only display if single stepping */ + + if (!AcpiGbl_CmSingleStep) + { + return; + } + + AcpiOsPrintf ("ResultObj: "); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); + AcpiOsPrintf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayArgumentObject + * + * PARAMETERS: ObjDesc - Object to be displayed + * WalkState - Current walk state + * + * RETURN: None + * + * DESCRIPTION: Display the result of an AML opcode + * + ******************************************************************************/ + +void +AcpiDbDisplayArgumentObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + +#ifndef ACPI_APPLICATION + if (AcpiGbl_DbThreadId != AcpiOsGetThreadId()) + { + return; + } +#endif + + if (!AcpiGbl_CmSingleStep) + { + return; + } + + AcpiOsPrintf ("ArgObj: "); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayGpes + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display the current GPE structures + * + ******************************************************************************/ + +void +AcpiDbDisplayGpes ( + void) +{ + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_GPE_XRUPT_INFO *GpeXruptInfo; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + char *GpeType; + ACPI_GPE_NOTIFY_INFO *Notify; + UINT32 GpeIndex; + UINT32 Block = 0; + UINT32 i; + UINT32 j; + UINT32 Count; + char Buffer[80]; + ACPI_BUFFER RetBuf; + ACPI_STATUS Status; + + + RetBuf.Length = sizeof (Buffer); + RetBuf.Pointer = Buffer; + + Block = 0; + + /* Walk the GPE lists */ + + GpeXruptInfo = AcpiGbl_GpeXruptListHead; + while (GpeXruptInfo) + { + GpeBlock = GpeXruptInfo->GpeBlockListHead; + while (GpeBlock) + { + Status = AcpiGetName (GpeBlock->Node, + ACPI_FULL_PATHNAME_NO_TRAILING, &RetBuf); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not convert name to pathname\n"); + } + + if (GpeBlock->Node == AcpiGbl_FadtGpeDevice) + { + GpeType = "FADT-defined GPE block"; + } + else + { + GpeType = "GPE Block Device"; + } + + AcpiOsPrintf ( + "\nBlock %u - Info %p DeviceNode %p [%s] - %s\n", + Block, GpeBlock, GpeBlock->Node, Buffer, GpeType); + + AcpiOsPrintf ( + " Registers: %u (%u GPEs)\n", + GpeBlock->RegisterCount, GpeBlock->GpeCount); + + AcpiOsPrintf ( + " GPE range: 0x%X to 0x%X on interrupt %u\n", + GpeBlock->BlockBaseNumber, + GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1), + GpeXruptInfo->InterruptNumber); + + AcpiOsPrintf ( + " RegisterInfo: %p Status %8.8X%8.8X Enable %8.8X%8.8X\n", + GpeBlock->RegisterInfo, + ACPI_FORMAT_UINT64 ( + GpeBlock->RegisterInfo->StatusAddress.Address), + ACPI_FORMAT_UINT64 ( + GpeBlock->RegisterInfo->EnableAddress.Address)); + + AcpiOsPrintf (" EventInfo: %p\n", GpeBlock->EventInfo); + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; + + AcpiOsPrintf ( + " Reg %u: (GPE %.2X-%.2X) " + "RunEnable %2.2X WakeEnable %2.2X" + " Status %8.8X%8.8X Enable %8.8X%8.8X\n", + i, GpeRegisterInfo->BaseGpeNumber, + GpeRegisterInfo->BaseGpeNumber + + (ACPI_GPE_REGISTER_WIDTH - 1), + GpeRegisterInfo->EnableForRun, + GpeRegisterInfo->EnableForWake, + ACPI_FORMAT_UINT64 ( + GpeRegisterInfo->StatusAddress.Address), + ACPI_FORMAT_UINT64 ( + GpeRegisterInfo->EnableAddress.Address)); + + /* Now look at the individual GPEs in this byte register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) + { + GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j; + GpeEventInfo = &GpeBlock->EventInfo[GpeIndex]; + + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_NONE) + { + /* This GPE is not used (no method or handler), ignore it */ + + continue; + } + + AcpiOsPrintf ( + " GPE %.2X: %p RunRefs %2.2X Flags %2.2X (", + GpeBlock->BlockBaseNumber + GpeIndex, GpeEventInfo, + GpeEventInfo->RuntimeCount, GpeEventInfo->Flags); + + /* Decode the flags byte */ + + if (GpeEventInfo->Flags & ACPI_GPE_LEVEL_TRIGGERED) + { + AcpiOsPrintf ("Level, "); + } + else + { + AcpiOsPrintf ("Edge, "); + } + + if (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE) + { + AcpiOsPrintf ("CanWake, "); + } + else + { + AcpiOsPrintf ("RunOnly, "); + } + + switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) + { + case ACPI_GPE_DISPATCH_NONE: + + AcpiOsPrintf ("NotUsed"); + break; + + case ACPI_GPE_DISPATCH_METHOD: + + AcpiOsPrintf ("Method"); + break; + + case ACPI_GPE_DISPATCH_HANDLER: + + AcpiOsPrintf ("Handler"); + break; + + case ACPI_GPE_DISPATCH_NOTIFY: + + Count = 0; + Notify = GpeEventInfo->Dispatch.NotifyList; + while (Notify) + { + Count++; + Notify = Notify->Next; + } + + AcpiOsPrintf ("Implicit Notify on %u devices", + Count); + break; + + case ACPI_GPE_DISPATCH_RAW_HANDLER: + + AcpiOsPrintf ("RawHandler"); + break; + + default: + + AcpiOsPrintf ("UNKNOWN: %X", + ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)); + break; + } + + AcpiOsPrintf (")\n"); + } + } + + Block++; + GpeBlock = GpeBlock->Next; + } + + GpeXruptInfo = GpeXruptInfo->Next; + } +} +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayHandlers + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display the currently installed global handlers + * + ******************************************************************************/ + +void +AcpiDbDisplayHandlers ( + void) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_ADR_SPACE_TYPE SpaceId; + UINT32 i; + + + /* Operation region handlers */ + + AcpiOsPrintf ("\nOperation Region Handlers at the namespace root:\n"); + + ObjDesc = AcpiNsGetAttachedObject (AcpiGbl_RootNode); + if (ObjDesc) + { + for (i = 0; i < ACPI_ARRAY_LENGTH (AcpiGbl_SpaceIdList); i++) + { + SpaceId = AcpiGbl_SpaceIdList[i]; + + AcpiOsPrintf (ACPI_PREDEFINED_PREFIX, + AcpiUtGetRegionName ((UINT8) SpaceId), SpaceId); + + HandlerObj = AcpiEvFindRegionHandler ( + SpaceId, ObjDesc->CommonNotify.Handler); + if (HandlerObj) + { + AcpiOsPrintf (ACPI_HANDLER_PRESENT_STRING, + (HandlerObj->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? + "Default" : "User", + HandlerObj->AddressSpace.Handler); + + goto FoundHandler; + } + + /* There is no handler for this SpaceId */ + + AcpiOsPrintf ("None\n"); + + FoundHandler:; + } + + /* Find all handlers for user-defined SpaceIDs */ + + HandlerObj = ObjDesc->CommonNotify.Handler; + while (HandlerObj) + { + if (HandlerObj->AddressSpace.SpaceId >= ACPI_USER_REGION_BEGIN) + { + AcpiOsPrintf (ACPI_PREDEFINED_PREFIX, + "User-defined ID", HandlerObj->AddressSpace.SpaceId); + AcpiOsPrintf (ACPI_HANDLER_PRESENT_STRING, + (HandlerObj->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? + "Default" : "User", + HandlerObj->AddressSpace.Handler); + } + + HandlerObj = HandlerObj->AddressSpace.Next; + } + } + +#if (!ACPI_REDUCED_HARDWARE) + + /* Fixed event handlers */ + + AcpiOsPrintf ("\nFixed Event Handlers:\n"); + + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) + { + AcpiOsPrintf (ACPI_PREDEFINED_PREFIX, AcpiUtGetEventName (i), i); + if (AcpiGbl_FixedEventHandlers[i].Handler) + { + AcpiOsPrintf (ACPI_HANDLER_PRESENT_STRING, "User", + AcpiGbl_FixedEventHandlers[i].Handler); + } + else + { + AcpiOsPrintf (ACPI_HANDLER_NOT_PRESENT_STRING, "None"); + } + } + +#endif /* !ACPI_REDUCED_HARDWARE */ + + /* Miscellaneous global handlers */ + + AcpiOsPrintf ("\nMiscellaneous Global Handlers:\n"); + + for (i = 0; i < ACPI_ARRAY_LENGTH (AcpiGbl_HandlerList); i++) + { + AcpiOsPrintf (ACPI_HANDLER_NAME_STRING, + AcpiGbl_HandlerList[i].Name); + + if (AcpiGbl_HandlerList[i].Handler) + { + AcpiOsPrintf (ACPI_HANDLER_PRESENT_STRING, "User", + AcpiGbl_HandlerList[i].Handler); + } + else + { + AcpiOsPrintf (ACPI_HANDLER_NOT_PRESENT_STRING, "None"); + } + } + + + /* Other handlers that are installed throughout the namespace */ + + AcpiOsPrintf ("\nOperation Region Handlers for specific devices:\n"); + + (void) AcpiWalkNamespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbDisplayNonRootHandlers, + NULL, NULL, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayNonRootHandlers + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Display information about all handlers installed for a + * device object. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbDisplayNonRootHandlers ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + char *Pathname; + + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + return (AE_OK); + } + + Pathname = AcpiNsGetNormalizedPathname (Node, TRUE); + if (!Pathname) + { + return (AE_OK); + } + + /* Display all handlers associated with this device */ + + HandlerObj = ObjDesc->CommonNotify.Handler; + while (HandlerObj) + { + AcpiOsPrintf (ACPI_PREDEFINED_PREFIX, + AcpiUtGetRegionName ((UINT8) HandlerObj->AddressSpace.SpaceId), + HandlerObj->AddressSpace.SpaceId); + + AcpiOsPrintf (ACPI_HANDLER_PRESENT_STRING2, + (HandlerObj->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default" : "User", + HandlerObj->AddressSpace.Handler); + + AcpiOsPrintf (" Device Name: %s (%p)\n", Pathname, Node); + + HandlerObj = HandlerObj->AddressSpace.Next; + } + + ACPI_FREE (Pathname); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbexec.c b/third_party/lib/acpica/source/components/debugger/dbexec.c new file mode 100644 index 000000000..b3c6cf9fa --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbexec.c @@ -0,0 +1,840 @@ +/******************************************************************************* + * + * Module Name: dbexec - debugger control method execution + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbexec") + + +static ACPI_DB_METHOD_INFO AcpiGbl_DbMethodInfo; + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDbExecuteMethod ( + ACPI_DB_METHOD_INFO *Info, + ACPI_BUFFER *ReturnObj); + +static ACPI_STATUS +AcpiDbExecuteSetup ( + ACPI_DB_METHOD_INFO *Info); + +static UINT32 +AcpiDbGetOutstandingAllocations ( + void); + +static void ACPI_SYSTEM_XFACE +AcpiDbMethodThread ( + void *Context); + +static ACPI_STATUS +AcpiDbExecutionWalk ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDeleteObjects + * + * PARAMETERS: Count - Count of objects in the list + * Objects - Array of ACPI_OBJECTs to be deleted + * + * RETURN: None + * + * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested + * packages via recursion. + * + ******************************************************************************/ + +void +AcpiDbDeleteObjects ( + UINT32 Count, + ACPI_OBJECT *Objects) +{ + UINT32 i; + + + for (i = 0; i < Count; i++) + { + switch (Objects[i].Type) + { + case ACPI_TYPE_BUFFER: + + ACPI_FREE (Objects[i].Buffer.Pointer); + break; + + case ACPI_TYPE_PACKAGE: + + /* Recursive call to delete package elements */ + + AcpiDbDeleteObjects (Objects[i].Package.Count, + Objects[i].Package.Elements); + + /* Free the elements array */ + + ACPI_FREE (Objects[i].Package.Elements); + break; + + default: + + break; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbExecuteMethod + * + * PARAMETERS: Info - Valid info segment + * ReturnObj - Where to put return object + * + * RETURN: Status + * + * DESCRIPTION: Execute a control method. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbExecuteMethod ( + ACPI_DB_METHOD_INFO *Info, + ACPI_BUFFER *ReturnObj) +{ + ACPI_STATUS Status; + ACPI_OBJECT_LIST ParamObjects; + ACPI_OBJECT Params[ACPI_DEBUGGER_MAX_ARGS + 1]; + UINT32 i; + + + ACPI_FUNCTION_TRACE (DbExecuteMethod); + + + if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel) + { + AcpiOsPrintf ("Warning: debug output is not enabled!\n"); + } + + ParamObjects.Count = 0; + ParamObjects.Pointer = NULL; + + /* Pass through any command-line arguments */ + + if (Info->Args && Info->Args[0]) + { + /* Get arguments passed on the command line */ + + for (i = 0; (Info->Args[i] && *(Info->Args[i])); i++) + { + /* Convert input string (token) to an actual ACPI_OBJECT */ + + Status = AcpiDbConvertToObject (Info->Types[i], + Info->Args[i], &Params[i]); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While parsing method arguments")); + goto Cleanup; + } + } + + ParamObjects.Count = i; + ParamObjects.Pointer = Params; + } + + /* Prepare for a return object of arbitrary size */ + + ReturnObj->Pointer = AcpiGbl_DbBuffer; + ReturnObj->Length = ACPI_DEBUG_BUFFER_SIZE; + + /* Do the actual method execution */ + + AcpiGbl_MethodExecuting = TRUE; + Status = AcpiEvaluateObject (NULL, Info->Pathname, + &ParamObjects, ReturnObj); + + AcpiGbl_CmSingleStep = FALSE; + AcpiGbl_MethodExecuting = FALSE; + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "while executing %s from debugger", Info->Pathname)); + + if (Status == AE_BUFFER_OVERFLOW) + { + ACPI_ERROR ((AE_INFO, + "Possible overflow of internal debugger " + "buffer (size 0x%X needed 0x%X)", + ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length)); + } + } + +Cleanup: + AcpiDbDeleteObjects (ParamObjects.Count, Params); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbExecuteSetup + * + * PARAMETERS: Info - Valid method info + * + * RETURN: None + * + * DESCRIPTION: Setup info segment prior to method execution + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbExecuteSetup ( + ACPI_DB_METHOD_INFO *Info) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (DbExecuteSetup); + + + /* Catenate the current scope to the supplied name */ + + Info->Pathname[0] = 0; + if ((Info->Name[0] != '\\') && + (Info->Name[0] != '/')) + { + if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname), + AcpiGbl_DbScopeBuf)) + { + Status = AE_BUFFER_OVERFLOW; + goto ErrorExit; + } + } + + if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname), + Info->Name)) + { + Status = AE_BUFFER_OVERFLOW; + goto ErrorExit; + } + + AcpiDbPrepNamestring (Info->Pathname); + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + AcpiOsPrintf ("Evaluating %s\n", Info->Pathname); + + if (Info->Flags & EX_SINGLE_STEP) + { + AcpiGbl_CmSingleStep = TRUE; + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + } + + else + { + /* No single step, allow redirection to a file */ + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + } + + return (AE_OK); + +ErrorExit: + + ACPI_EXCEPTION ((AE_INFO, Status, "During setup for method execution")); + return (Status); +} + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +UINT32 +AcpiDbGetCacheInfo ( + ACPI_MEMORY_LIST *Cache) +{ + + return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth); +} +#endif + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetOutstandingAllocations + * + * PARAMETERS: None + * + * RETURN: Current global allocation count minus cache entries + * + * DESCRIPTION: Determine the current number of "outstanding" allocations -- + * those allocations that have not been freed and also are not + * in one of the various object caches. + * + ******************************************************************************/ + +static UINT32 +AcpiDbGetOutstandingAllocations ( + void) +{ + UINT32 Outstanding = 0; + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache); + Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache); + Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache); + Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache); +#endif + + return (Outstanding); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbExecutionWalk + * + * PARAMETERS: WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Execute a control method. Name is relative to the current + * scope. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbExecutionWalk ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_BUFFER ReturnObj; + ACPI_STATUS Status; + + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc->Method.ParamCount) + { + return (AE_OK); + } + + ReturnObj.Pointer = NULL; + ReturnObj.Length = ACPI_ALLOCATE_BUFFER; + + AcpiNsPrintNodePathname (Node, "Evaluating"); + + /* Do the actual method execution */ + + AcpiOsPrintf ("\n"); + AcpiGbl_MethodExecuting = TRUE; + + Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj); + + AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n", + AcpiUtGetNodeName (Node), + AcpiFormatException (Status)); + + AcpiGbl_MethodExecuting = FALSE; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbExecute + * + * PARAMETERS: Name - Name of method to execute + * Args - Parameters to the method + * Types - + * Flags - single step/no single step + * + * RETURN: None + * + * DESCRIPTION: Execute a control method. Name is relative to the current + * scope. + * + ******************************************************************************/ + +void +AcpiDbExecute ( + char *Name, + char **Args, + ACPI_OBJECT_TYPE *Types, + UINT32 Flags) +{ + ACPI_STATUS Status; + ACPI_BUFFER ReturnObj; + char *NameString; + +#ifdef ACPI_DEBUG_OUTPUT + UINT32 PreviousAllocations; + UINT32 Allocations; +#endif + + + /* + * Allow one execution to be performed by debugger or single step + * execution will be dead locked by the interpreter mutexes. + */ + if (AcpiGbl_MethodExecuting) + { + AcpiOsPrintf ("Only one debugger execution is allowed.\n"); + return; + } + +#ifdef ACPI_DEBUG_OUTPUT + /* Memory allocation tracking */ + + PreviousAllocations = AcpiDbGetOutstandingAllocations (); +#endif + + if (*Name == '*') + { + (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL); + return; + } + else + { + NameString = ACPI_ALLOCATE (strlen (Name) + 1); + if (!NameString) + { + return; + } + + memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO)); + + strcpy (NameString, Name); + AcpiUtStrupr (NameString); + AcpiGbl_DbMethodInfo.Name = NameString; + AcpiGbl_DbMethodInfo.Args = Args; + AcpiGbl_DbMethodInfo.Types = Types; + AcpiGbl_DbMethodInfo.Flags = Flags; + + ReturnObj.Pointer = NULL; + ReturnObj.Length = ACPI_ALLOCATE_BUFFER; + + Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (NameString); + return; + } + + /* Get the NS node, determines existence also */ + + Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname, + &AcpiGbl_DbMethodInfo.Method); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo, + &ReturnObj); + } + ACPI_FREE (NameString); + } + + /* + * Allow any handlers in separate threads to complete. + * (Such as Notify handlers invoked from AML executed above). + */ + AcpiOsSleep ((UINT64) 10); + +#ifdef ACPI_DEBUG_OUTPUT + + /* Memory allocation tracking */ + + Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations; + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + + if (Allocations > 0) + { + AcpiOsPrintf ( + "0x%X Outstanding allocations after evaluation of %s\n", + Allocations, AcpiGbl_DbMethodInfo.Pathname); + } +#endif + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Evaluation of %s failed with status %s\n", + AcpiGbl_DbMethodInfo.Pathname, + AcpiFormatException (Status)); + } + else + { + /* Display a return object, if any */ + + if (ReturnObj.Length) + { + AcpiOsPrintf ( + "Evaluation of %s returned object %p, " + "external buffer length %X\n", + AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer, + (UINT32) ReturnObj.Length); + + AcpiDbDumpExternalObject (ReturnObj.Pointer, 1); + + /* Dump a _PLD buffer if present */ + + if (ACPI_COMPARE_NAME ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, + AcpiGbl_DbMethodInfo.Method)->Name.Ascii), + METHOD_NAME__PLD)) + { + AcpiDbDumpPldBuffer (ReturnObj.Pointer); + } + } + else + { + AcpiOsPrintf ("No object was returned from evaluation of %s\n", + AcpiGbl_DbMethodInfo.Pathname); + } + } + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbMethodThread + * + * PARAMETERS: Context - Execution info segment + * + * RETURN: None + * + * DESCRIPTION: Debugger execute thread. Waits for a command line, then + * simply dispatches it. + * + ******************************************************************************/ + +static void ACPI_SYSTEM_XFACE +AcpiDbMethodThread ( + void *Context) +{ + ACPI_STATUS Status; + ACPI_DB_METHOD_INFO *Info = Context; + ACPI_DB_METHOD_INFO LocalInfo; + UINT32 i; + UINT8 Allow; + ACPI_BUFFER ReturnObj; + + + /* + * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments. + * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads + * concurrently. + * + * Note: The arguments we are passing are used by the ASL test suite + * (aslts). Do not change them without updating the tests. + */ + (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER); + + if (Info->InitArgs) + { + AcpiDbUint32ToHexString (Info->NumCreated, + Info->IndexOfThreadStr); + AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (), + Info->IdOfThreadStr); + } + + if (Info->Threads && (Info->NumCreated < Info->NumThreads)) + { + Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId(); + } + + LocalInfo = *Info; + LocalInfo.Args = LocalInfo.Arguments; + LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr; + LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr; + LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr; + LocalInfo.Arguments[3] = NULL; + + LocalInfo.Types = LocalInfo.ArgTypes; + + (void) AcpiOsSignalSemaphore (Info->InfoGate, 1); + + for (i = 0; i < Info->NumLoops; i++) + { + Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n", + AcpiFormatException (Status), Info->Pathname, i); + if (Status == AE_ABORT_METHOD) + { + break; + } + } + +#if 0 + if ((i % 100) == 0) + { + AcpiOsPrintf ("%u loops, Thread 0x%x\n", + i, AcpiOsGetThreadId ()); + } + + if (ReturnObj.Length) + { + AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n", + Info->Pathname, ReturnObj.Pointer, + (UINT32) ReturnObj.Length); + AcpiDbDumpExternalObject (ReturnObj.Pointer, 1); + } +#endif + } + + /* Signal our completion */ + + Allow = 0; + (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate, + 1, ACPI_WAIT_FOREVER); + Info->NumCompleted++; + + if (Info->NumCompleted == Info->NumThreads) + { + /* Do signal for main thread once only */ + Allow = 1; + } + + (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1); + + if (Allow) + { + Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ( + "Could not signal debugger thread sync semaphore, %s\n", + AcpiFormatException (Status)); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbCreateExecutionThreads + * + * PARAMETERS: NumThreadsArg - Number of threads to create + * NumLoopsArg - Loop count for the thread(s) + * MethodNameArg - Control method to execute + * + * RETURN: None + * + * DESCRIPTION: Create threads to execute method(s) + * + ******************************************************************************/ + +void +AcpiDbCreateExecutionThreads ( + char *NumThreadsArg, + char *NumLoopsArg, + char *MethodNameArg) +{ + ACPI_STATUS Status; + UINT32 NumThreads; + UINT32 NumLoops; + UINT32 i; + UINT32 Size; + ACPI_MUTEX MainThreadGate; + ACPI_MUTEX ThreadCompleteGate; + ACPI_MUTEX InfoGate; + + + /* Get the arguments */ + + NumThreads = strtoul (NumThreadsArg, NULL, 0); + NumLoops = strtoul (NumLoopsArg, NULL, 0); + + if (!NumThreads || !NumLoops) + { + AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n", + NumThreads, NumLoops); + return; + } + + /* + * Create the semaphore for synchronization of + * the created threads with the main thread. + */ + Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not create semaphore for " + "synchronization with the main thread, %s\n", + AcpiFormatException (Status)); + return; + } + + /* + * Create the semaphore for synchronization + * between the created threads. + */ + Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not create semaphore for " + "synchronization between the created threads, %s\n", + AcpiFormatException (Status)); + + (void) AcpiOsDeleteSemaphore (MainThreadGate); + return; + } + + Status = AcpiOsCreateSemaphore (1, 1, &InfoGate); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not create semaphore for " + "synchronization of AcpiGbl_DbMethodInfo, %s\n", + AcpiFormatException (Status)); + + (void) AcpiOsDeleteSemaphore (ThreadCompleteGate); + (void) AcpiOsDeleteSemaphore (MainThreadGate); + return; + } + + memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO)); + + /* Array to store IDs of threads */ + + AcpiGbl_DbMethodInfo.NumThreads = NumThreads; + Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads; + + AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size); + if (AcpiGbl_DbMethodInfo.Threads == NULL) + { + AcpiOsPrintf ("No memory for thread IDs array\n"); + (void) AcpiOsDeleteSemaphore (MainThreadGate); + (void) AcpiOsDeleteSemaphore (ThreadCompleteGate); + (void) AcpiOsDeleteSemaphore (InfoGate); + return; + } + memset (AcpiGbl_DbMethodInfo.Threads, 0, Size); + + /* Setup the context to be passed to each thread */ + + AcpiGbl_DbMethodInfo.Name = MethodNameArg; + AcpiGbl_DbMethodInfo.Flags = 0; + AcpiGbl_DbMethodInfo.NumLoops = NumLoops; + AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate; + AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate; + AcpiGbl_DbMethodInfo.InfoGate = InfoGate; + + /* Init arguments to be passed to method */ + + AcpiGbl_DbMethodInfo.InitArgs = 1; + AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments; + AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr; + AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr; + AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr; + AcpiGbl_DbMethodInfo.Arguments[3] = NULL; + + AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes; + AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER; + AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER; + AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER; + + AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr); + + Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo); + if (ACPI_FAILURE (Status)) + { + goto CleanupAndExit; + } + + /* Get the NS node, determines existence also */ + + Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname, + &AcpiGbl_DbMethodInfo.Method); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s Could not get handle for %s\n", + AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname); + goto CleanupAndExit; + } + + /* Create the threads */ + + AcpiOsPrintf ("Creating %X threads to execute %X times each\n", + NumThreads, NumLoops); + + for (i = 0; i < (NumThreads); i++) + { + Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, AcpiDbMethodThread, + &AcpiGbl_DbMethodInfo); + if (ACPI_FAILURE (Status)) + { + break; + } + } + + /* Wait for all threads to complete */ + + (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER); + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads); + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + +CleanupAndExit: + + /* Cleanup and exit */ + + (void) AcpiOsDeleteSemaphore (MainThreadGate); + (void) AcpiOsDeleteSemaphore (ThreadCompleteGate); + (void) AcpiOsDeleteSemaphore (InfoGate); + + AcpiOsFree (AcpiGbl_DbMethodInfo.Threads); + AcpiGbl_DbMethodInfo.Threads = NULL; +} diff --git a/third_party/lib/acpica/source/components/debugger/dbfileio.c b/third_party/lib/acpica/source/components/debugger/dbfileio.c new file mode 100644 index 000000000..e90a138e5 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbfileio.c @@ -0,0 +1,180 @@ +/******************************************************************************* + * + * Module Name: dbfileio - Debugger file I/O commands. These can't usually + * be used when running the debugger in Ring 0 (Kernel mode) + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" +#include "actables.h" +#include +#ifdef ACPI_APPLICATION +#include "acapps.h" +#endif + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbfileio") + + +#ifdef ACPI_DEBUGGER +/******************************************************************************* + * + * FUNCTION: AcpiDbCloseDebugFile + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: If open, close the current debug output file + * + ******************************************************************************/ + +void +AcpiDbCloseDebugFile ( + void) +{ + +#ifdef ACPI_APPLICATION + + if (AcpiGbl_DebugFile) + { + fclose (AcpiGbl_DebugFile); + AcpiGbl_DebugFile = NULL; + AcpiGbl_DbOutputToFile = FALSE; + AcpiOsPrintf ("Debug output file %s closed\n", + AcpiGbl_DbDebugFilename); + } +#endif +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbOpenDebugFile + * + * PARAMETERS: Name - Filename to open + * + * RETURN: None + * + * DESCRIPTION: Open a file where debug output will be directed. + * + ******************************************************************************/ + +void +AcpiDbOpenDebugFile ( + char *Name) +{ + +#ifdef ACPI_APPLICATION + + AcpiDbCloseDebugFile (); + AcpiGbl_DebugFile = fopen (Name, "w+"); + if (!AcpiGbl_DebugFile) + { + AcpiOsPrintf ("Could not open debug file %s\n", Name); + return; + } + + AcpiOsPrintf ("Debug output file %s opened\n", Name); + strncpy (AcpiGbl_DbDebugFilename, Name, + sizeof (AcpiGbl_DbDebugFilename)); + AcpiGbl_DbOutputToFile = TRUE; + +#endif +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDbLoadTables + * + * PARAMETERS: ListHead - List of ACPI tables to load + * + * RETURN: Status + * + * DESCRIPTION: Load ACPI tables from a previously constructed table list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbLoadTables ( + ACPI_NEW_TABLE_DESC *ListHead) +{ + ACPI_STATUS Status; + ACPI_NEW_TABLE_DESC *TableListHead; + ACPI_TABLE_HEADER *Table; + + + /* Load all ACPI tables in the list */ + + TableListHead = ListHead; + while (TableListHead) + { + Table = TableListHead->Table; + + Status = AcpiLoadTable (Table); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_ALREADY_EXISTS) + { + AcpiOsPrintf ("Table %4.4s is already installed\n", + Table->Signature); + } + else + { + AcpiOsPrintf ("Could not install table, %s\n", + AcpiFormatException (Status)); + } + + return (Status); + } + + fprintf (stderr, + "Acpi table [%4.4s] successfully installed and loaded\n", + Table->Signature); + + TableListHead = TableListHead->Next; + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbhistry.c b/third_party/lib/acpica/source/components/debugger/dbhistry.c new file mode 100644 index 000000000..3efb1cd1b --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbhistry.c @@ -0,0 +1,271 @@ +/****************************************************************************** + * + * Module Name: dbhistry - debugger HISTORY command + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbhistry") + + +#define HI_NO_HISTORY 0 +#define HI_RECORD_HISTORY 1 +#define HISTORY_SIZE 40 + + +typedef struct HistoryInfo +{ + char *Command; + UINT32 CmdNum; + +} HISTORY_INFO; + + +static HISTORY_INFO AcpiGbl_HistoryBuffer[HISTORY_SIZE]; +static UINT16 AcpiGbl_LoHistory = 0; +static UINT16 AcpiGbl_NumHistory = 0; +static UINT16 AcpiGbl_NextHistoryIndex = 0; +UINT32 AcpiGbl_NextCmdNum = 1; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbAddToHistory + * + * PARAMETERS: CommandLine - Command to add + * + * RETURN: None + * + * DESCRIPTION: Add a command line to the history buffer. + * + ******************************************************************************/ + +void +AcpiDbAddToHistory ( + char *CommandLine) +{ + UINT16 CmdLen; + UINT16 BufferLen; + + /* Put command into the next available slot */ + + CmdLen = (UINT16) strlen (CommandLine); + if (!CmdLen) + { + return; + } + + if (AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex].Command != NULL) + { + BufferLen = (UINT16) strlen ( + AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex].Command); + + if (CmdLen > BufferLen) + { + AcpiOsFree (AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex]. + Command); + AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex].Command = + AcpiOsAllocate (CmdLen + 1); + } + } + else + { + AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex].Command = + AcpiOsAllocate (CmdLen + 1); + } + + strcpy (AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex].Command, + CommandLine); + + AcpiGbl_HistoryBuffer[AcpiGbl_NextHistoryIndex].CmdNum = + AcpiGbl_NextCmdNum; + + /* Adjust indexes */ + + if ((AcpiGbl_NumHistory == HISTORY_SIZE) && + (AcpiGbl_NextHistoryIndex == AcpiGbl_LoHistory)) + { + AcpiGbl_LoHistory++; + if (AcpiGbl_LoHistory >= HISTORY_SIZE) + { + AcpiGbl_LoHistory = 0; + } + } + + AcpiGbl_NextHistoryIndex++; + if (AcpiGbl_NextHistoryIndex >= HISTORY_SIZE) + { + AcpiGbl_NextHistoryIndex = 0; + } + + AcpiGbl_NextCmdNum++; + if (AcpiGbl_NumHistory < HISTORY_SIZE) + { + AcpiGbl_NumHistory++; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayHistory + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display the contents of the history buffer + * + ******************************************************************************/ + +void +AcpiDbDisplayHistory ( + void) +{ + UINT32 i; + UINT16 HistoryIndex; + + + HistoryIndex = AcpiGbl_LoHistory; + + /* Dump entire history buffer */ + + for (i = 0; i < AcpiGbl_NumHistory; i++) + { + if (AcpiGbl_HistoryBuffer[HistoryIndex].Command) + { + AcpiOsPrintf ("%3ld %s\n", + AcpiGbl_HistoryBuffer[HistoryIndex].CmdNum, + AcpiGbl_HistoryBuffer[HistoryIndex].Command); + } + + HistoryIndex++; + if (HistoryIndex >= HISTORY_SIZE) + { + HistoryIndex = 0; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetFromHistory + * + * PARAMETERS: CommandNumArg - String containing the number of the + * command to be retrieved + * + * RETURN: Pointer to the retrieved command. Null on error. + * + * DESCRIPTION: Get a command from the history buffer + * + ******************************************************************************/ + +char * +AcpiDbGetFromHistory ( + char *CommandNumArg) +{ + UINT32 CmdNum; + + + if (CommandNumArg == NULL) + { + CmdNum = AcpiGbl_NextCmdNum - 1; + } + + else + { + CmdNum = strtoul (CommandNumArg, NULL, 0); + } + + return (AcpiDbGetHistoryByIndex (CmdNum)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetHistoryByIndex + * + * PARAMETERS: CmdNum - Index of the desired history entry. + * Values are 0...(AcpiGbl_NextCmdNum - 1) + * + * RETURN: Pointer to the retrieved command. Null on error. + * + * DESCRIPTION: Get a command from the history buffer + * + ******************************************************************************/ + +char * +AcpiDbGetHistoryByIndex ( + UINT32 CmdNum) +{ + UINT32 i; + UINT16 HistoryIndex; + + + /* Search history buffer */ + + HistoryIndex = AcpiGbl_LoHistory; + for (i = 0; i < AcpiGbl_NumHistory; i++) + { + if (AcpiGbl_HistoryBuffer[HistoryIndex].CmdNum == CmdNum) + { + /* Found the command, return it */ + + return (AcpiGbl_HistoryBuffer[HistoryIndex].Command); + } + + /* History buffer is circular */ + + HistoryIndex++; + if (HistoryIndex >= HISTORY_SIZE) + { + HistoryIndex = 0; + } + } + + AcpiOsPrintf ("Invalid history number: %u\n", HistoryIndex); + return (NULL); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbinput.c b/third_party/lib/acpica/source/components/debugger/dbinput.c new file mode 100644 index 000000000..06d066cef --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbinput.c @@ -0,0 +1,1360 @@ +/******************************************************************************* + * + * Module Name: dbinput - user front-end to the AML debugger + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" + +#ifdef ACPI_APPLICATION +#include "acapps.h" +#endif + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbinput") + + +/* Local prototypes */ + +static UINT32 +AcpiDbGetLine ( + char *InputBuffer); + +static UINT32 +AcpiDbMatchCommand ( + char *UserCommand); + +static void +AcpiDbSingleThread ( + void); + +static void +AcpiDbDisplayCommandInfo ( + char *Command, + BOOLEAN DisplayAll); + +static void +AcpiDbDisplayHelp ( + char *Command); + +static BOOLEAN +AcpiDbMatchCommandHelp ( + char *Command, + const ACPI_DB_COMMAND_HELP *Help); + + +/* + * Top-level debugger commands. + * + * This list of commands must match the string table below it + */ +enum AcpiExDebuggerCommands +{ + CMD_NOT_FOUND = 0, + CMD_NULL, + CMD_ALLOCATIONS, + CMD_ARGS, + CMD_ARGUMENTS, + CMD_BREAKPOINT, + CMD_BUSINFO, + CMD_CALL, + CMD_DEBUG, + CMD_DISASSEMBLE, + CMD_DISASM, + CMD_DUMP, + CMD_EVALUATE, + CMD_EXECUTE, + CMD_EXIT, + CMD_FIND, + CMD_GO, + CMD_HANDLERS, + CMD_HELP, + CMD_HELP2, + CMD_HISTORY, + CMD_HISTORY_EXE, + CMD_HISTORY_LAST, + CMD_INFORMATION, + CMD_INTEGRITY, + CMD_INTO, + CMD_LEVEL, + CMD_LIST, + CMD_LOCALS, + CMD_LOCKS, + CMD_METHODS, + CMD_NAMESPACE, + CMD_NOTIFY, + CMD_OBJECTS, + CMD_OSI, + CMD_OWNER, + CMD_PATHS, + CMD_PREDEFINED, + CMD_PREFIX, + CMD_QUIT, + CMD_REFERENCES, + CMD_RESOURCES, + CMD_RESULTS, + CMD_SET, + CMD_STATS, + CMD_STOP, + CMD_TABLES, + CMD_TEMPLATE, + CMD_TRACE, + CMD_TREE, + CMD_TYPE, +#ifdef ACPI_APPLICATION + CMD_ENABLEACPI, + CMD_EVENT, + CMD_GPE, + CMD_GPES, + CMD_SCI, + CMD_SLEEP, + + CMD_CLOSE, + CMD_LOAD, + CMD_OPEN, + CMD_UNLOAD, + + CMD_TERMINATE, + CMD_THREADS, + + CMD_TEST, +#endif +}; + +#define CMD_FIRST_VALID 2 + + +/* Second parameter is the required argument count */ + +static const ACPI_DB_COMMAND_INFO AcpiGbl_DbCommands[] = +{ + {"", 0}, + {"", 0}, + {"ALLOCATIONS", 0}, + {"ARGS", 0}, + {"ARGUMENTS", 0}, + {"BREAKPOINT", 1}, + {"BUSINFO", 0}, + {"CALL", 0}, + {"DEBUG", 1}, + {"DISASSEMBLE", 1}, + {"DISASM", 1}, + {"DUMP", 1}, + {"EVALUATE", 1}, + {"EXECUTE", 1}, + {"EXIT", 0}, + {"FIND", 1}, + {"GO", 0}, + {"HANDLERS", 0}, + {"HELP", 0}, + {"?", 0}, + {"HISTORY", 0}, + {"!", 1}, + {"!!", 0}, + {"INFORMATION", 0}, + {"INTEGRITY", 0}, + {"INTO", 0}, + {"LEVEL", 0}, + {"LIST", 0}, + {"LOCALS", 0}, + {"LOCKS", 0}, + {"METHODS", 0}, + {"NAMESPACE", 0}, + {"NOTIFY", 2}, + {"OBJECTS", 0}, + {"OSI", 0}, + {"OWNER", 1}, + {"PATHS", 0}, + {"PREDEFINED", 0}, + {"PREFIX", 0}, + {"QUIT", 0}, + {"REFERENCES", 1}, + {"RESOURCES", 0}, + {"RESULTS", 0}, + {"SET", 3}, + {"STATS", 1}, + {"STOP", 0}, + {"TABLES", 0}, + {"TEMPLATE", 1}, + {"TRACE", 1}, + {"TREE", 0}, + {"TYPE", 1}, +#ifdef ACPI_APPLICATION + {"ENABLEACPI", 0}, + {"EVENT", 1}, + {"GPE", 1}, + {"GPES", 0}, + {"SCI", 0}, + {"SLEEP", 0}, + + {"CLOSE", 0}, + {"LOAD", 1}, + {"OPEN", 1}, + {"UNLOAD", 1}, + + {"TERMINATE", 0}, + {"THREADS", 3}, + + {"TEST", 1}, +#endif + {NULL, 0} +}; + +/* + * Help for all debugger commands. First argument is the number of lines + * of help to output for the command. + */ +static const ACPI_DB_COMMAND_HELP AcpiGbl_DbCommandHelp[] = +{ + {0, "\nGeneral-Purpose Commands:", "\n"}, + {1, " Allocations", "Display list of current memory allocations\n"}, + {2, " Dump
|", "\n"}, + {0, " [Byte|Word|Dword|Qword]", "Display ACPI objects or memory\n"}, + {1, " Handlers", "Info about global handlers\n"}, + {1, " Help [Command]", "This help screen or individual command\n"}, + {1, " History", "Display command history buffer\n"}, + {1, " Level ] [console]", "Get/Set debug level for file or console\n"}, + {1, " Locks", "Current status of internal mutexes\n"}, + {1, " Osi [Install|Remove ]", "Display or modify global _OSI list\n"}, + {1, " Quit or Exit", "Exit this command\n"}, + {8, " Stats ", "Display namespace and memory statistics\n"}, + {1, " Allocations", "Display list of current memory allocations\n"}, + {1, " Memory", "Dump internal memory lists\n"}, + {1, " Misc", "Namespace search and mutex stats\n"}, + {1, " Objects", "Summary of namespace objects\n"}, + {1, " Sizes", "Sizes for each of the internal objects\n"}, + {1, " Stack", "Display CPU stack usage\n"}, + {1, " Tables", "Info about current ACPI table(s)\n"}, + {1, " Tables", "Display info about loaded ACPI tables\n"}, + {1, " ! ", "Execute command from history buffer\n"}, + {1, " !!", "Execute last command again\n"}, + + {0, "\nNamespace Access Commands:", "\n"}, + {1, " Businfo", "Display system bus info\n"}, + {1, " Disassemble ", "Disassemble a control method\n"}, + {1, " Find (? is wildcard)", "Find ACPI name(s) with wildcards\n"}, + {1, " Integrity", "Validate namespace integrity\n"}, + {1, " Methods", "Display list of loaded control methods\n"}, + {1, " Namespace [Object] [Depth]", "Display loaded namespace tree/subtree\n"}, + {1, " Notify ", "Send a notification on Object\n"}, + {1, " Objects [ObjectType]", "Display summary of all objects or just given type\n"}, + {1, " Owner [Depth]", "Display loaded namespace by object owner\n"}, + {1, " Paths", "Display full pathnames of namespace objects\n"}, + {1, " Predefined", "Check all predefined names\n"}, + {1, " Prefix []", "Set or Get current execution prefix\n"}, + {1, " References ", "Find all references to object at addr\n"}, + {1, " Resources [DeviceName]", "Display Device resources (no arg = all devices)\n"}, + {1, " Set N ", "Set value for named integer\n"}, + {1, " Template ", "Format/dump a Buffer/ResourceTemplate\n"}, + {1, " Type ", "Display object type\n"}, + + {0, "\nControl Method Execution Commands:","\n"}, + {1, " Arguments (or Args)", "Display method arguments\n"}, + {1, " Breakpoint ", "Set an AML execution breakpoint\n"}, + {1, " Call", "Run to next control method invocation\n"}, + {1, " Debug [Arguments]", "Single Step a control method\n"}, + {6, " Evaluate", "Synonym for Execute\n"}, + {5, " Execute [Arguments]", "Execute control method\n"}, + {1, " Hex Integer", "Integer method argument\n"}, + {1, " \"Ascii String\"", "String method argument\n"}, + {1, " (Hex Byte List)", "Buffer method argument\n"}, + {1, " [Package Element List]", "Package method argument\n"}, + {1, " Go", "Allow method to run to completion\n"}, + {1, " Information", "Display info about the current method\n"}, + {1, " Into", "Step into (not over) a method call\n"}, + {1, " List [# of Aml Opcodes]", "Display method ASL statements\n"}, + {1, " Locals", "Display method local variables\n"}, + {1, " Results", "Display method result stack\n"}, + {1, " Set <#> ", "Set method data (Arguments/Locals)\n"}, + {1, " Stop", "Terminate control method\n"}, + {5, " Trace [] [Once]", "Trace control method execution\n"}, + {1, " Enable", "Enable all messages\n"}, + {1, " Disable", "Disable tracing\n"}, + {1, " Method", "Enable method execution messages\n"}, + {1, " Opcode", "Enable opcode execution messages\n"}, + {1, " Tree", "Display control method calling tree\n"}, + {1, " ", "Single step next AML opcode (over calls)\n"}, + +#ifdef ACPI_APPLICATION + {0, "\nHardware Simulation Commands:", "\n"}, + {1, " EnableAcpi", "Enable ACPI (hardware) mode\n"}, + {1, " Event ", "Generate AcpiEvent (Fixed/GPE)\n"}, + {1, " Gpe [GpeBlockDevice]", "Simulate a GPE\n"}, + {1, " Gpes", "Display info on all GPE devices\n"}, + {1, " Sci", "Generate an SCI\n"}, + {1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, + + {0, "\nFile I/O Commands:", "\n"}, + {1, " Close", "Close debug output file\n"}, + {1, " Load ", "Load ACPI table from a file\n"}, + {1, " Open ", "Open a file for debug output\n"}, + {1, " Unload ", "Unload an ACPI table via namespace object\n"}, + + {0, "\nUser Space Commands:", "\n"}, + {1, " Terminate", "Delete namespace and all internal objects\n"}, + {1, " Thread ", "Spawn threads to execute method(s)\n"}, + + {0, "\nDebug Test Commands:", "\n"}, + {3, " Test ", "Invoke a debug test\n"}, + {1, " Objects", "Read/write/compare all namespace data objects\n"}, + {1, " Predefined", "Execute all ACPI predefined names (_STA, etc.)\n"}, +#endif + {0, NULL, NULL} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbMatchCommandHelp + * + * PARAMETERS: Command - Command string to match + * Help - Help table entry to attempt match + * + * RETURN: TRUE if command matched, FALSE otherwise + * + * DESCRIPTION: Attempt to match a command in the help table in order to + * print help information for a single command. + * + ******************************************************************************/ + +static BOOLEAN +AcpiDbMatchCommandHelp ( + char *Command, + const ACPI_DB_COMMAND_HELP *Help) +{ + char *Invocation = Help->Invocation; + UINT32 LineCount; + + + /* Valid commands in the help table begin with a couple of spaces */ + + if (*Invocation != ' ') + { + return (FALSE); + } + + while (*Invocation == ' ') + { + Invocation++; + } + + /* Match command name (full command or substring) */ + + while ((*Command) && (*Invocation) && (*Invocation != ' ')) + { + if (tolower ((int) *Command) != tolower ((int) *Invocation)) + { + return (FALSE); + } + + Invocation++; + Command++; + } + + /* Print the appropriate number of help lines */ + + LineCount = Help->LineCount; + while (LineCount) + { + AcpiOsPrintf ("%-38s : %s", Help->Invocation, Help->Description); + Help++; + LineCount--; + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayCommandInfo + * + * PARAMETERS: Command - Command string to match + * DisplayAll - Display all matching commands, or just + * the first one (substring match) + * + * RETURN: None + * + * DESCRIPTION: Display help information for a Debugger command. + * + ******************************************************************************/ + +static void +AcpiDbDisplayCommandInfo ( + char *Command, + BOOLEAN DisplayAll) +{ + const ACPI_DB_COMMAND_HELP *Next; + BOOLEAN Matched; + + + Next = AcpiGbl_DbCommandHelp; + while (Next->Invocation) + { + Matched = AcpiDbMatchCommandHelp (Command, Next); + if (!DisplayAll && Matched) + { + return; + } + + Next++; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayHelp + * + * PARAMETERS: Command - Optional command string to display help. + * if not specified, all debugger command + * help strings are displayed + * + * RETURN: None + * + * DESCRIPTION: Display help for a single debugger command, or all of them. + * + ******************************************************************************/ + +static void +AcpiDbDisplayHelp ( + char *Command) +{ + const ACPI_DB_COMMAND_HELP *Next = AcpiGbl_DbCommandHelp; + + + if (!Command) + { + /* No argument to help, display help for all commands */ + + while (Next->Invocation) + { + AcpiOsPrintf ("%-38s%s", Next->Invocation, Next->Description); + Next++; + } + } + else + { + /* Display help for all commands that match the subtring */ + + AcpiDbDisplayCommandInfo (Command, TRUE); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetNextToken + * + * PARAMETERS: String - Command buffer + * Next - Return value, end of next token + * + * RETURN: Pointer to the start of the next token. + * + * DESCRIPTION: Command line parsing. Get the next token on the command line + * + ******************************************************************************/ + +char * +AcpiDbGetNextToken ( + char *String, + char **Next, + ACPI_OBJECT_TYPE *ReturnType) +{ + char *Start; + UINT32 Depth; + ACPI_OBJECT_TYPE Type = ACPI_TYPE_INTEGER; + + + /* At end of buffer? */ + + if (!String || !(*String)) + { + return (NULL); + } + + /* Remove any spaces at the beginning */ + + if (*String == ' ') + { + while (*String && (*String == ' ')) + { + String++; + } + + if (!(*String)) + { + return (NULL); + } + } + + switch (*String) + { + case '"': + + /* This is a quoted string, scan until closing quote */ + + String++; + Start = String; + Type = ACPI_TYPE_STRING; + + /* Find end of string */ + + while (*String && (*String != '"')) + { + String++; + } + break; + + case '(': + + /* This is the start of a buffer, scan until closing paren */ + + String++; + Start = String; + Type = ACPI_TYPE_BUFFER; + + /* Find end of buffer */ + + while (*String && (*String != ')')) + { + String++; + } + break; + + case '[': + + /* This is the start of a package, scan until closing bracket */ + + String++; + Depth = 1; + Start = String; + Type = ACPI_TYPE_PACKAGE; + + /* Find end of package (closing bracket) */ + + while (*String) + { + /* Handle String package elements */ + + if (*String == '"') + { + /* Find end of string */ + + String++; + while (*String && (*String != '"')) + { + String++; + } + if (!(*String)) + { + break; + } + } + else if (*String == '[') + { + Depth++; /* A nested package declaration */ + } + else if (*String == ']') + { + Depth--; + if (Depth == 0) /* Found final package closing bracket */ + { + break; + } + } + + String++; + } + break; + + default: + + Start = String; + + /* Find end of token */ + + while (*String && (*String != ' ')) + { + String++; + } + break; + } + + if (!(*String)) + { + *Next = NULL; + } + else + { + *String = 0; + *Next = String + 1; + } + + *ReturnType = Type; + return (Start); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetLine + * + * PARAMETERS: InputBuffer - Command line buffer + * + * RETURN: Count of arguments to the command + * + * DESCRIPTION: Get the next command line from the user. Gets entire line + * up to the next newline + * + ******************************************************************************/ + +static UINT32 +AcpiDbGetLine ( + char *InputBuffer) +{ + UINT32 i; + UINT32 Count; + char *Next; + char *This; + + + if (AcpiUtSafeStrcpy (AcpiGbl_DbParsedBuf, sizeof (AcpiGbl_DbParsedBuf), + InputBuffer)) + { + AcpiOsPrintf ( + "Buffer overflow while parsing input line (max %u characters)\n", + sizeof (AcpiGbl_DbParsedBuf)); + return (0); + } + + This = AcpiGbl_DbParsedBuf; + for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) + { + AcpiGbl_DbArgs[i] = AcpiDbGetNextToken (This, &Next, + &AcpiGbl_DbArgTypes[i]); + if (!AcpiGbl_DbArgs[i]) + { + break; + } + + This = Next; + } + + /* Uppercase the actual command */ + + AcpiUtStrupr (AcpiGbl_DbArgs[0]); + + Count = i; + if (Count) + { + Count--; /* Number of args only */ + } + + return (Count); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbMatchCommand + * + * PARAMETERS: UserCommand - User command line + * + * RETURN: Index into command array, -1 if not found + * + * DESCRIPTION: Search command array for a command match + * + ******************************************************************************/ + +static UINT32 +AcpiDbMatchCommand ( + char *UserCommand) +{ + UINT32 i; + + + if (!UserCommand || UserCommand[0] == 0) + { + return (CMD_NULL); + } + + for (i = CMD_FIRST_VALID; AcpiGbl_DbCommands[i].Name; i++) + { + if (strstr (AcpiGbl_DbCommands[i].Name, UserCommand) == + AcpiGbl_DbCommands[i].Name) + { + return (i); + } + } + + /* Command not recognized */ + + return (CMD_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbCommandDispatch + * + * PARAMETERS: InputBuffer - Command line buffer + * WalkState - Current walk + * Op - Current (executing) parse op + * + * RETURN: Status + * + * DESCRIPTION: Command dispatcher. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbCommandDispatch ( + char *InputBuffer, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + UINT32 Temp; + UINT32 CommandIndex; + UINT32 ParamCount; + char *CommandLine; + ACPI_STATUS Status = AE_CTRL_TRUE; + + + /* If AcpiTerminate has been called, terminate this thread */ + + if (AcpiGbl_DbTerminateLoop) + { + return (AE_CTRL_TERMINATE); + } + + /* Find command and add to the history buffer */ + + ParamCount = AcpiDbGetLine (InputBuffer); + CommandIndex = AcpiDbMatchCommand (AcpiGbl_DbArgs[0]); + Temp = 0; + + /* + * We don't want to add the !! command to the history buffer. It + * would cause an infinite loop because it would always be the + * previous command. + */ + if (CommandIndex != CMD_HISTORY_LAST) + { + AcpiDbAddToHistory (InputBuffer); + } + + /* Verify that we have the minimum number of params */ + + if (ParamCount < AcpiGbl_DbCommands[CommandIndex].MinArgs) + { + AcpiOsPrintf ("%u parameters entered, [%s] requires %u parameters\n", + ParamCount, AcpiGbl_DbCommands[CommandIndex].Name, + AcpiGbl_DbCommands[CommandIndex].MinArgs); + + AcpiDbDisplayCommandInfo ( + AcpiGbl_DbCommands[CommandIndex].Name, FALSE); + return (AE_CTRL_TRUE); + } + + /* Decode and dispatch the command */ + + switch (CommandIndex) + { + case CMD_NULL: + + if (Op) + { + return (AE_OK); + } + break; + + case CMD_ALLOCATIONS: + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + AcpiUtDumpAllocations ((UINT32) -1, NULL); +#endif + break; + + case CMD_ARGS: + case CMD_ARGUMENTS: + + AcpiDbDisplayArguments (); + break; + + case CMD_BREAKPOINT: + + AcpiDbSetMethodBreakpoint (AcpiGbl_DbArgs[1], WalkState, Op); + break; + + case CMD_BUSINFO: + + AcpiDbGetBusInfo (); + break; + + case CMD_CALL: + + AcpiDbSetMethodCallBreakpoint (Op); + Status = AE_OK; + break; + + case CMD_DEBUG: + + AcpiDbExecute (AcpiGbl_DbArgs[1], + &AcpiGbl_DbArgs[2], &AcpiGbl_DbArgTypes[2], EX_SINGLE_STEP); + break; + + case CMD_DISASSEMBLE: + case CMD_DISASM: + + (void) AcpiDbDisassembleMethod (AcpiGbl_DbArgs[1]); + break; + + case CMD_DUMP: + + AcpiDbDecodeAndDisplayObject (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2]); + break; + + case CMD_EVALUATE: + case CMD_EXECUTE: + + AcpiDbExecute (AcpiGbl_DbArgs[1], + &AcpiGbl_DbArgs[2], &AcpiGbl_DbArgTypes[2], EX_NO_SINGLE_STEP); + break; + + case CMD_FIND: + + Status = AcpiDbFindNameInNamespace (AcpiGbl_DbArgs[1]); + break; + + case CMD_GO: + + AcpiGbl_CmSingleStep = FALSE; + return (AE_OK); + + case CMD_HANDLERS: + + AcpiDbDisplayHandlers (); + break; + + case CMD_HELP: + case CMD_HELP2: + + AcpiDbDisplayHelp (AcpiGbl_DbArgs[1]); + break; + + case CMD_HISTORY: + + AcpiDbDisplayHistory (); + break; + + case CMD_HISTORY_EXE: /* ! command */ + + CommandLine = AcpiDbGetFromHistory (AcpiGbl_DbArgs[1]); + if (!CommandLine) + { + return (AE_CTRL_TRUE); + } + + Status = AcpiDbCommandDispatch (CommandLine, WalkState, Op); + return (Status); + + case CMD_HISTORY_LAST: /* !! command */ + + CommandLine = AcpiDbGetFromHistory (NULL); + if (!CommandLine) + { + return (AE_CTRL_TRUE); + } + + Status = AcpiDbCommandDispatch (CommandLine, WalkState, Op); + return (Status); + + case CMD_INFORMATION: + + AcpiDbDisplayMethodInfo (Op); + break; + + case CMD_INTEGRITY: + + AcpiDbCheckIntegrity (); + break; + + case CMD_INTO: + + if (Op) + { + AcpiGbl_CmSingleStep = TRUE; + return (AE_OK); + } + break; + + case CMD_LEVEL: + + if (ParamCount == 0) + { + AcpiOsPrintf ( + "Current debug level for file output is: %8.8lX\n", + AcpiGbl_DbDebugLevel); + AcpiOsPrintf ( + "Current debug level for console output is: %8.8lX\n", + AcpiGbl_DbConsoleDebugLevel); + } + else if (ParamCount == 2) + { + Temp = AcpiGbl_DbConsoleDebugLevel; + AcpiGbl_DbConsoleDebugLevel = + strtoul (AcpiGbl_DbArgs[1], NULL, 16); + AcpiOsPrintf ( + "Debug Level for console output was %8.8lX, now %8.8lX\n", + Temp, AcpiGbl_DbConsoleDebugLevel); + } + else + { + Temp = AcpiGbl_DbDebugLevel; + AcpiGbl_DbDebugLevel = strtoul (AcpiGbl_DbArgs[1], NULL, 16); + AcpiOsPrintf ( + "Debug Level for file output was %8.8lX, now %8.8lX\n", + Temp, AcpiGbl_DbDebugLevel); + } + break; + + case CMD_LIST: + + AcpiDbDisassembleAml (AcpiGbl_DbArgs[1], Op); + break; + + case CMD_LOCKS: + + AcpiDbDisplayLocks (); + break; + + case CMD_LOCALS: + + AcpiDbDisplayLocals (); + break; + + case CMD_METHODS: + + Status = AcpiDbDisplayObjects ("METHOD", AcpiGbl_DbArgs[1]); + break; + + case CMD_NAMESPACE: + + AcpiDbDumpNamespace (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2]); + break; + + case CMD_NOTIFY: + + Temp = strtoul (AcpiGbl_DbArgs[2], NULL, 0); + AcpiDbSendNotify (AcpiGbl_DbArgs[1], Temp); + break; + + case CMD_OBJECTS: + + AcpiUtStrupr (AcpiGbl_DbArgs[1]); + Status = AcpiDbDisplayObjects (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2]); + break; + + case CMD_OSI: + + AcpiDbDisplayInterfaces (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2]); + break; + + case CMD_OWNER: + + AcpiDbDumpNamespaceByOwner (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2]); + break; + + case CMD_PATHS: + + AcpiDbDumpNamespacePaths (); + break; + + case CMD_PREFIX: + + AcpiDbSetScope (AcpiGbl_DbArgs[1]); + break; + + case CMD_REFERENCES: + + AcpiDbFindReferences (AcpiGbl_DbArgs[1]); + break; + + case CMD_RESOURCES: + + AcpiDbDisplayResources (AcpiGbl_DbArgs[1]); + break; + + case CMD_RESULTS: + + AcpiDbDisplayResults (); + break; + + case CMD_SET: + + AcpiDbSetMethodData (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2], + AcpiGbl_DbArgs[3]); + break; + + case CMD_STATS: + + Status = AcpiDbDisplayStatistics (AcpiGbl_DbArgs[1]); + break; + + case CMD_STOP: + + return (AE_NOT_IMPLEMENTED); + + case CMD_TABLES: + + AcpiDbDisplayTableInfo (AcpiGbl_DbArgs[1]); + break; + + case CMD_TEMPLATE: + + AcpiDbDisplayTemplate (AcpiGbl_DbArgs[1]); + break; + + case CMD_TRACE: + + AcpiDbTrace (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2], AcpiGbl_DbArgs[3]); + break; + + case CMD_TREE: + + AcpiDbDisplayCallingTree (); + break; + + case CMD_TYPE: + + AcpiDbDisplayObjectType (AcpiGbl_DbArgs[1]); + break; + +#ifdef ACPI_APPLICATION + + /* Hardware simulation commands. */ + + case CMD_ENABLEACPI: +#if (!ACPI_REDUCED_HARDWARE) + + Status = AcpiEnable(); + if (ACPI_FAILURE(Status)) + { + AcpiOsPrintf("AcpiEnable failed (Status=%X)\n", Status); + return (Status); + } +#endif /* !ACPI_REDUCED_HARDWARE */ + break; + + case CMD_EVENT: + + AcpiOsPrintf ("Event command not implemented\n"); + break; + + case CMD_GPE: + + AcpiDbGenerateGpe (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2]); + break; + + case CMD_GPES: + + AcpiDbDisplayGpes (); + break; + + case CMD_SCI: + + AcpiDbGenerateSci (); + break; + + case CMD_SLEEP: + + Status = AcpiDbSleep (AcpiGbl_DbArgs[1]); + break; + + /* File I/O commands. */ + + case CMD_CLOSE: + + AcpiDbCloseDebugFile (); + break; + + case CMD_LOAD: + { + ACPI_NEW_TABLE_DESC *ListHead = NULL; + + Status = AcGetAllTablesFromFile (AcpiGbl_DbArgs[1], + ACPI_GET_ALL_TABLES, &ListHead); + if (ACPI_SUCCESS (Status)) + { + AcpiDbLoadTables (ListHead); + } + } + break; + + case CMD_OPEN: + + AcpiDbOpenDebugFile (AcpiGbl_DbArgs[1]); + break; + + /* User space commands. */ + + case CMD_TERMINATE: + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + AcpiUtSubsystemShutdown (); + + /* + * TBD: [Restructure] Need some way to re-initialize without + * re-creating the semaphores! + */ + + AcpiGbl_DbTerminateLoop = TRUE; + /* AcpiInitialize (NULL); */ + break; + + case CMD_THREADS: + + AcpiDbCreateExecutionThreads (AcpiGbl_DbArgs[1], AcpiGbl_DbArgs[2], + AcpiGbl_DbArgs[3]); + break; + + /* Debug test commands. */ + + case CMD_PREDEFINED: + + AcpiDbCheckPredefinedNames (); + break; + + case CMD_TEST: + + AcpiDbExecuteTest (AcpiGbl_DbArgs[1]); + break; + + case CMD_UNLOAD: + + AcpiDbUnloadAcpiTable (AcpiGbl_DbArgs[1]); + break; +#endif + + case CMD_EXIT: + case CMD_QUIT: + + if (Op) + { + AcpiOsPrintf ("Method execution terminated\n"); + return (AE_CTRL_TERMINATE); + } + + if (!AcpiGbl_DbOutputToFile) + { + AcpiDbgLevel = ACPI_DEBUG_DEFAULT; + } + +#ifdef ACPI_APPLICATION + AcpiDbCloseDebugFile (); +#endif + AcpiGbl_DbTerminateLoop = TRUE; + return (AE_CTRL_TERMINATE); + + case CMD_NOT_FOUND: + default: + + AcpiOsPrintf ("%s: unknown command\n", AcpiGbl_DbArgs[0]); + return (AE_CTRL_TRUE); + } + + if (ACPI_SUCCESS (Status)) + { + Status = AE_CTRL_TRUE; + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbExecuteThread + * + * PARAMETERS: Context - Not used + * + * RETURN: None + * + * DESCRIPTION: Debugger execute thread. Waits for a command line, then + * simply dispatches it. + * + ******************************************************************************/ + +void ACPI_SYSTEM_XFACE +AcpiDbExecuteThread ( + void *Context) +{ + ACPI_STATUS Status = AE_OK; + ACPI_STATUS MStatus; + + + while (Status != AE_CTRL_TERMINATE && !AcpiGbl_DbTerminateLoop) + { + AcpiGbl_MethodExecuting = FALSE; + AcpiGbl_StepToNextCall = FALSE; + + MStatus = AcpiOsAcquireMutex (AcpiGbl_DbCommandReady, + ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (MStatus)) + { + return; + } + + Status = AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, NULL, NULL); + + AcpiOsReleaseMutex (AcpiGbl_DbCommandComplete); + } + AcpiGbl_DbThreadsTerminated = TRUE; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSingleThread + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Debugger execute thread. Waits for a command line, then + * simply dispatches it. + * + ******************************************************************************/ + +static void +AcpiDbSingleThread ( + void) +{ + + AcpiGbl_MethodExecuting = FALSE; + AcpiGbl_StepToNextCall = FALSE; + + (void) AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, NULL, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbUserCommands + * + * PARAMETERS: Prompt - User prompt (depends on mode) + * Op - Current executing parse op + * + * RETURN: None + * + * DESCRIPTION: Command line execution for the AML debugger. Commands are + * matched and dispatched here. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbUserCommands ( + char Prompt, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status = AE_OK; + + + AcpiOsPrintf ("\n"); + + /* TBD: [Restructure] Need a separate command line buffer for step mode */ + + while (!AcpiGbl_DbTerminateLoop) + { + /* Force output to console until a command is entered */ + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + + /* Different prompt if method is executing */ + + if (!AcpiGbl_MethodExecuting) + { + AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); + } + else + { + AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); + } + + /* Get the user input line */ + + Status = AcpiOsGetLine (AcpiGbl_DbLineBuf, + ACPI_DB_LINE_BUFFER_SIZE, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While parsing command line")); + return (Status); + } + + /* Check for single or multithreaded debug */ + + if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) + { + /* + * Signal the debug thread that we have a command to execute, + * and wait for the command to complete. + */ + AcpiOsReleaseMutex (AcpiGbl_DbCommandReady); + + Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandComplete, + ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* Just call to the command line interpreter */ + + AcpiDbSingleThread (); + } + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbmethod.c b/third_party/lib/acpica/source/components/debugger/dbmethod.c new file mode 100644 index 000000000..740dcf9a3 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbmethod.c @@ -0,0 +1,416 @@ +/******************************************************************************* + * + * Module Name: dbmethod - Debug commands for control methods + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acdebug.h" +#include "acparser.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbmethod") + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSetMethodBreakpoint + * + * PARAMETERS: Location - AML offset of breakpoint + * WalkState - Current walk info + * Op - Current Op (from parse walk) + * + * RETURN: None + * + * DESCRIPTION: Set a breakpoint in a control method at the specified + * AML offset + * + ******************************************************************************/ + +void +AcpiDbSetMethodBreakpoint ( + char *Location, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + UINT32 Address; + UINT32 AmlOffset; + + + if (!Op) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + /* Get and verify the breakpoint address */ + + Address = strtoul (Location, NULL, 16); + AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml, + WalkState->ParserState.AmlStart); + if (Address <= AmlOffset) + { + AcpiOsPrintf ("Breakpoint %X is beyond current address %X\n", + Address, AmlOffset); + } + + /* Save breakpoint in current walk */ + + WalkState->UserBreakpoint = Address; + AcpiOsPrintf ("Breakpoint set at AML offset %X\n", Address); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSetMethodCallBreakpoint + * + * PARAMETERS: Op - Current Op (from parse walk) + * + * RETURN: None + * + * DESCRIPTION: Set a breakpoint in a control method at the specified + * AML offset + * + ******************************************************************************/ + +void +AcpiDbSetMethodCallBreakpoint ( + ACPI_PARSE_OBJECT *Op) +{ + + + if (!Op) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + AcpiGbl_StepToNextCall = TRUE; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSetMethodData + * + * PARAMETERS: TypeArg - L for local, A for argument + * IndexArg - which one + * ValueArg - Value to set. + * + * RETURN: None + * + * DESCRIPTION: Set a local or argument for the running control method. + * NOTE: only object supported is Number. + * + ******************************************************************************/ + +void +AcpiDbSetMethodData ( + char *TypeArg, + char *IndexArg, + char *ValueArg) +{ + char Type; + UINT32 Index; + UINT32 Value; + ACPI_WALK_STATE *WalkState; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + /* Validate TypeArg */ + + AcpiUtStrupr (TypeArg); + Type = TypeArg[0]; + if ((Type != 'L') && + (Type != 'A') && + (Type != 'N')) + { + AcpiOsPrintf ("Invalid SET operand: %s\n", TypeArg); + return; + } + + Value = strtoul (ValueArg, NULL, 16); + + if (Type == 'N') + { + Node = AcpiDbConvertToNode (IndexArg); + if (!Node) + { + return; + } + + if (Node->Type != ACPI_TYPE_INTEGER) + { + AcpiOsPrintf ("Can only set Integer nodes\n"); + return; + } + ObjDesc = Node->Object; + ObjDesc->Integer.Value = Value; + return; + } + + /* Get the index and value */ + + Index = strtoul (IndexArg, NULL, 16); + + WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); + if (!WalkState) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + /* Create and initialize the new object */ + + ObjDesc = AcpiUtCreateIntegerObject ((UINT64) Value); + if (!ObjDesc) + { + AcpiOsPrintf ("Could not create an internal object\n"); + return; + } + + /* Store the new object into the target */ + + switch (Type) + { + case 'A': + + /* Set a method argument */ + + if (Index > ACPI_METHOD_MAX_ARG) + { + AcpiOsPrintf ("Arg%u - Invalid argument name\n", + Index); + goto Cleanup; + } + + Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_ARG, + Index, ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + ObjDesc = WalkState->Arguments[Index].Object; + + AcpiOsPrintf ("Arg%u: ", Index); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); + break; + + case 'L': + + /* Set a method local */ + + if (Index > ACPI_METHOD_MAX_LOCAL) + { + AcpiOsPrintf ("Local%u - Invalid local variable name\n", + Index); + goto Cleanup; + } + + Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_LOCAL, + Index, ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + ObjDesc = WalkState->LocalVariables[Index].Object; + + AcpiOsPrintf ("Local%u: ", Index); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); + break; + + default: + + break; + } + +Cleanup: + AcpiUtRemoveReference (ObjDesc); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisassembleAml + * + * PARAMETERS: Statements - Number of statements to disassemble + * Op - Current Op (from parse walk) + * + * RETURN: None + * + * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number + * of statements specified. + * + ******************************************************************************/ + +void +AcpiDbDisassembleAml ( + char *Statements, + ACPI_PARSE_OBJECT *Op) +{ + UINT32 NumStatements = 8; + + + if (!Op) + { + AcpiOsPrintf ("There is no method currently executing\n"); + return; + } + + if (Statements) + { + NumStatements = strtoul (Statements, NULL, 0); + } + +#ifdef ACPI_DISASSEMBLER + AcpiDmDisassemble (NULL, Op, NumStatements); +#endif +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisassembleMethod + * + * PARAMETERS: Name - Name of control method + * + * RETURN: None + * + * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number + * of statements specified. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbDisassembleMethod ( + char *Name) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Op; + ACPI_WALK_STATE *WalkState; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Method; + + + Method = AcpiDbConvertToNode (Name); + if (!Method) + { + return (AE_BAD_PARAMETER); + } + + if (Method->Type != ACPI_TYPE_METHOD) + { + ACPI_ERROR ((AE_INFO, "%s (%s): Object must be a control method", + Name, AcpiUtGetTypeName (Method->Type))); + return (AE_BAD_PARAMETER); + } + + ObjDesc = Method->Object; + + Op = AcpiPsCreateScopeOp (ObjDesc->Method.AmlStart); + if (!Op) + { + return (AE_NO_MEMORY); + } + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL); + if (!WalkState) + { + return (AE_NO_MEMORY); + } + + Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, + ObjDesc->Method.AmlStart, + ObjDesc->Method.AmlLength, NULL, ACPI_IMODE_LOAD_PASS1); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); + WalkState->OwnerId = ObjDesc->Method.OwnerId; + + /* Push start scope on scope stack and make it current */ + + Status = AcpiDsScopeStackPush (Method, + Method->Type, WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Parse the entire method AML including deferred operators */ + + WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE; + WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE; + + Status = AcpiPsParseAml (WalkState); + +#ifdef ACPI_DISASSEMBLER + (void) AcpiDmParseDeferredOps (Op); + + /* Now we can disassemble the method */ + + AcpiGbl_DmOpt_Verbose = FALSE; + AcpiDmDisassemble (NULL, Op, 0); + AcpiGbl_DmOpt_Verbose = TRUE; +#endif + + AcpiPsDeleteParseTree (Op); + + /* Method cleanup */ + + AcpiNsDeleteNamespaceSubtree (Method); + AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId); + AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbnames.c b/third_party/lib/acpica/source/components/debugger/dbnames.c new file mode 100644 index 000000000..f7cbb91d6 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbnames.c @@ -0,0 +1,1072 @@ +/******************************************************************************* + * + * Module Name: dbnames - Debugger commands for the acpi namespace + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acdebug.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbnames") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDbWalkAndMatchName ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbWalkForPredefinedNames ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbWalkForSpecificObjects ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbWalkForObjectCounts ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbIntegrityWalk ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbWalkForReferences ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbBusWalk ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +/* + * Arguments for the Objects command + * These object types map directly to the ACPI_TYPES + */ +static ACPI_DB_ARGUMENT_INFO AcpiDbObjectTypes [] = +{ + {"ANY"}, + {"INTEGERS"}, + {"STRINGS"}, + {"BUFFERS"}, + {"PACKAGES"}, + {"FIELDS"}, + {"DEVICES"}, + {"EVENTS"}, + {"METHODS"}, + {"MUTEXES"}, + {"REGIONS"}, + {"POWERRESOURCES"}, + {"PROCESSORS"}, + {"THERMALZONES"}, + {"BUFFERFIELDS"}, + {"DDBHANDLES"}, + {"DEBUG"}, + {"REGIONFIELDS"}, + {"BANKFIELDS"}, + {"INDEXFIELDS"}, + {"REFERENCES"}, + {"ALIASES"}, + {"METHODALIASES"}, + {"NOTIFY"}, + {"ADDRESSHANDLER"}, + {"RESOURCE"}, + {"RESOURCEFIELD"}, + {"SCOPES"}, + {NULL} /* Must be null terminated */ +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSetScope + * + * PARAMETERS: Name - New scope path + * + * RETURN: Status + * + * DESCRIPTION: Set the "current scope" as maintained by this utility. + * The scope is used as a prefix to ACPI paths. + * + ******************************************************************************/ + +void +AcpiDbSetScope ( + char *Name) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + if (!Name || Name[0] == 0) + { + AcpiOsPrintf ("Current scope: %s\n", AcpiGbl_DbScopeBuf); + return; + } + + AcpiDbPrepNamestring (Name); + + if (ACPI_IS_ROOT_PREFIX (Name[0])) + { + /* Validate new scope from the root */ + + Status = AcpiNsGetNode (AcpiGbl_RootNode, Name, + ACPI_NS_NO_UPSEARCH, &Node); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + AcpiGbl_DbScopeBuf[0] = 0; + } + else + { + /* Validate new scope relative to old scope */ + + Status = AcpiNsGetNode (AcpiGbl_DbScopeNode, Name, + ACPI_NS_NO_UPSEARCH, &Node); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + } + + /* Build the final pathname */ + + if (AcpiUtSafeStrcat (AcpiGbl_DbScopeBuf, sizeof (AcpiGbl_DbScopeBuf), + Name)) + { + Status = AE_BUFFER_OVERFLOW; + goto ErrorExit; + } + + if (AcpiUtSafeStrcat (AcpiGbl_DbScopeBuf, sizeof (AcpiGbl_DbScopeBuf), + "\\")) + { + Status = AE_BUFFER_OVERFLOW; + goto ErrorExit; + } + + AcpiGbl_DbScopeNode = Node; + AcpiOsPrintf ("New scope: %s\n", AcpiGbl_DbScopeBuf); + return; + +ErrorExit: + + AcpiOsPrintf ("Could not attach scope: %s, %s\n", + Name, AcpiFormatException (Status)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpNamespace + * + * PARAMETERS: StartArg - Node to begin namespace dump + * DepthArg - Maximum tree depth to be dumped + * + * RETURN: None + * + * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed + * with type and other information. + * + ******************************************************************************/ + +void +AcpiDbDumpNamespace ( + char *StartArg, + char *DepthArg) +{ + ACPI_HANDLE SubtreeEntry = AcpiGbl_RootNode; + UINT32 MaxDepth = ACPI_UINT32_MAX; + + + /* No argument given, just start at the root and dump entire namespace */ + + if (StartArg) + { + SubtreeEntry = AcpiDbConvertToNode (StartArg); + if (!SubtreeEntry) + { + return; + } + + /* Now we can check for the depth argument */ + + if (DepthArg) + { + MaxDepth = strtoul (DepthArg, NULL, 0); + } + } + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + AcpiOsPrintf ("ACPI Namespace (from %4.4s (%p) subtree):\n", + ((ACPI_NAMESPACE_NODE *) SubtreeEntry)->Name.Ascii, SubtreeEntry); + + /* Display the subtree */ + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + AcpiNsDumpObjects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, MaxDepth, + ACPI_OWNER_ID_MAX, SubtreeEntry); + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpNamespacePaths + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump entire namespace with full object pathnames and object + * type information. Alternative to "namespace" command. + * + ******************************************************************************/ + +void +AcpiDbDumpNamespacePaths ( + void) +{ + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + AcpiOsPrintf ("ACPI Namespace (from root):\n"); + + /* Display the entire namespace */ + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + AcpiNsDumpObjectPaths (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, + ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX, AcpiGbl_RootNode); + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpNamespaceByOwner + * + * PARAMETERS: OwnerArg - Owner ID whose nodes will be displayed + * DepthArg - Maximum tree depth to be dumped + * + * RETURN: None + * + * DESCRIPTION: Dump elements of the namespace that are owned by the OwnerId. + * + ******************************************************************************/ + +void +AcpiDbDumpNamespaceByOwner ( + char *OwnerArg, + char *DepthArg) +{ + ACPI_HANDLE SubtreeEntry = AcpiGbl_RootNode; + UINT32 MaxDepth = ACPI_UINT32_MAX; + ACPI_OWNER_ID OwnerId; + + + OwnerId = (ACPI_OWNER_ID) strtoul (OwnerArg, NULL, 0); + + /* Now we can check for the depth argument */ + + if (DepthArg) + { + MaxDepth = strtoul (DepthArg, NULL, 0); + } + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + AcpiOsPrintf ("ACPI Namespace by owner %X:\n", OwnerId); + + /* Display the subtree */ + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + AcpiNsDumpObjects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, MaxDepth, + OwnerId, SubtreeEntry); + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbWalkAndMatchName + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Find a particular name/names within the namespace. Wildcards + * are supported -- '?' matches any character. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbWalkAndMatchName ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_STATUS Status; + char *RequestedName = (char *) Context; + UINT32 i; + ACPI_BUFFER Buffer; + ACPI_WALK_INFO Info; + + + /* Check for a name match */ + + for (i = 0; i < 4; i++) + { + /* Wildcard support */ + + if ((RequestedName[i] != '?') && + (RequestedName[i] != ((ACPI_NAMESPACE_NODE *) + ObjHandle)->Name.Ascii[i])) + { + /* No match, just exit */ + + return (AE_OK); + } + } + + /* Get the full pathname to this object */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (ObjHandle, &Buffer, TRUE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could Not get pathname for object %p\n", + ObjHandle); + } + else + { + Info.OwnerId = ACPI_OWNER_ID_MAX; + Info.DebugLevel = ACPI_UINT32_MAX; + Info.DisplayType = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; + + AcpiOsPrintf ("%32s", (char *) Buffer.Pointer); + (void) AcpiNsDumpOneObject (ObjHandle, NestingLevel, &Info, NULL); + ACPI_FREE (Buffer.Pointer); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbFindNameInNamespace + * + * PARAMETERS: NameArg - The 4-character ACPI name to find. + * wildcards are supported. + * + * RETURN: None + * + * DESCRIPTION: Search the namespace for a given name (with wildcards) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbFindNameInNamespace ( + char *NameArg) +{ + char AcpiName[5] = "____"; + char *AcpiNamePtr = AcpiName; + + + if (strlen (NameArg) > ACPI_NAME_SIZE) + { + AcpiOsPrintf ("Name must be no longer than 4 characters\n"); + return (AE_OK); + } + + /* Pad out name with underscores as necessary to create a 4-char name */ + + AcpiUtStrupr (NameArg); + while (*NameArg) + { + *AcpiNamePtr = *NameArg; + AcpiNamePtr++; + NameArg++; + } + + /* Walk the namespace from the root */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbWalkAndMatchName, NULL, AcpiName, NULL); + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbWalkForPredefinedNames + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Detect and display predefined ACPI names (names that start with + * an underscore) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbWalkForPredefinedNames ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + UINT32 *Count = (UINT32 *) Context; + const ACPI_PREDEFINED_INFO *Predefined; + const ACPI_PREDEFINED_INFO *Package = NULL; + char *Pathname; + char StringBuffer[48]; + + + Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii); + if (!Predefined) + { + return (AE_OK); + } + + Pathname = AcpiNsGetNormalizedPathname (Node, TRUE); + if (!Pathname) + { + return (AE_OK); + } + + /* If method returns a package, the info is in the next table entry */ + + if (Predefined->Info.ExpectedBtypes & ACPI_RTYPE_PACKAGE) + { + Package = Predefined + 1; + } + + AcpiUtGetExpectedReturnTypes (StringBuffer, + Predefined->Info.ExpectedBtypes); + + AcpiOsPrintf ("%-32s Arguments %X, Return Types: %s", Pathname, + METHOD_GET_ARG_COUNT (Predefined->Info.ArgumentList), + StringBuffer); + + if (Package) + { + AcpiOsPrintf (" (PkgType %2.2X, ObjType %2.2X, Count %2.2X)", + Package->RetInfo.Type, Package->RetInfo.ObjectType1, + Package->RetInfo.Count1); + } + + AcpiOsPrintf("\n"); + + /* Check that the declared argument count matches the ACPI spec */ + + AcpiNsCheckAcpiCompliance (Pathname, Node, Predefined); + + ACPI_FREE (Pathname); + (*Count)++; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbCheckPredefinedNames + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Validate all predefined names in the namespace + * + ******************************************************************************/ + +void +AcpiDbCheckPredefinedNames ( + void) +{ + UINT32 Count = 0; + + + /* Search all nodes in namespace */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbWalkForPredefinedNames, + NULL, (void *) &Count, NULL); + + AcpiOsPrintf ("Found %u predefined names in the namespace\n", Count); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbWalkForObjectCounts + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Display short info about objects in the namespace + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbWalkForObjectCounts ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_OBJECT_INFO *Info = (ACPI_OBJECT_INFO *) Context; + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + + + if (Node->Type > ACPI_TYPE_NS_NODE_MAX) + { + AcpiOsPrintf ("[%4.4s]: Unknown object type %X\n", + Node->Name.Ascii, Node->Type); + } + else + { + Info->Types[Node->Type]++; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbWalkForSpecificObjects + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Display short info about objects in the namespace + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbWalkForSpecificObjects ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_WALK_INFO *Info = (ACPI_WALK_INFO *) Context; + ACPI_BUFFER Buffer; + ACPI_STATUS Status; + + + Info->Count++; + + /* Get and display the full pathname to this object */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (ObjHandle, &Buffer, TRUE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could Not get pathname for object %p\n", ObjHandle); + return (AE_OK); + } + + AcpiOsPrintf ("%32s", (char *) Buffer.Pointer); + ACPI_FREE (Buffer.Pointer); + + /* Dump short info about the object */ + + (void) AcpiNsDumpOneObject (ObjHandle, NestingLevel, Info, NULL); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayObjects + * + * PARAMETERS: ObjTypeArg - Type of object to display + * DisplayCountArg - Max depth to display + * + * RETURN: None + * + * DESCRIPTION: Display objects in the namespace of the requested type + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbDisplayObjects ( + char *ObjTypeArg, + char *DisplayCountArg) +{ + ACPI_WALK_INFO Info; + ACPI_OBJECT_TYPE Type; + ACPI_OBJECT_INFO *ObjectInfo; + UINT32 i; + UINT32 TotalObjects = 0; + + + /* No argument means display summary/count of all object types */ + + if (!ObjTypeArg) + { + ObjectInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_OBJECT_INFO)); + + /* Walk the namespace from the root */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbWalkForObjectCounts, NULL, + (void *) ObjectInfo, NULL); + + AcpiOsPrintf ("\nSummary of namespace objects:\n\n"); + + for (i = 0; i < ACPI_TOTAL_TYPES; i++) + { + AcpiOsPrintf ("%8u %s\n", ObjectInfo->Types[i], + AcpiUtGetTypeName (i)); + + TotalObjects += ObjectInfo->Types[i]; + } + + AcpiOsPrintf ("\n%8u Total namespace objects\n\n", + TotalObjects); + + ACPI_FREE (ObjectInfo); + return (AE_OK); + } + + /* Get the object type */ + + Type = AcpiDbMatchArgument (ObjTypeArg, AcpiDbObjectTypes); + if (Type == ACPI_TYPE_NOT_FOUND) + { + AcpiOsPrintf ("Invalid or unsupported argument\n"); + return (AE_OK); + } + + AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); + AcpiOsPrintf ( + "Objects of type [%s] defined in the current ACPI Namespace:\n", + AcpiUtGetTypeName (Type)); + + AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); + + Info.Count = 0; + Info.OwnerId = ACPI_OWNER_ID_MAX; + Info.DebugLevel = ACPI_UINT32_MAX; + Info.DisplayType = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; + + /* Walk the namespace from the root */ + + (void) AcpiWalkNamespace (Type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + AcpiDbWalkForSpecificObjects, NULL, (void *) &Info, NULL); + + AcpiOsPrintf ( + "\nFound %u objects of type [%s] in the current ACPI Namespace\n", + Info.Count, AcpiUtGetTypeName (Type)); + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbIntegrityWalk + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Examine one NS node for valid values. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbIntegrityWalk ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_INTEGRITY_INFO *Info = (ACPI_INTEGRITY_INFO *) Context; + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_OPERAND_OBJECT *Object; + BOOLEAN Alias = TRUE; + + + Info->Nodes++; + + /* Verify the NS node, and dereference aliases */ + + while (Alias) + { + if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) + { + AcpiOsPrintf ( + "Invalid Descriptor Type for Node %p [%s] - " + "is %2.2X should be %2.2X\n", + Node, AcpiUtGetDescriptorName (Node), + ACPI_GET_DESCRIPTOR_TYPE (Node), ACPI_DESC_TYPE_NAMED); + return (AE_OK); + } + + if ((Node->Type == ACPI_TYPE_LOCAL_ALIAS) || + (Node->Type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) + { + Node = (ACPI_NAMESPACE_NODE *) Node->Object; + } + else + { + Alias = FALSE; + } + } + + if (Node->Type > ACPI_TYPE_LOCAL_MAX) + { + AcpiOsPrintf ("Invalid Object Type for Node %p, Type = %X\n", + Node, Node->Type); + return (AE_OK); + } + + if (!AcpiUtValidAcpiName (Node->Name.Ascii)) + { + AcpiOsPrintf ("Invalid AcpiName for Node %p\n", Node); + return (AE_OK); + } + + Object = AcpiNsGetAttachedObject (Node); + if (Object) + { + Info->Objects++; + if (ACPI_GET_DESCRIPTOR_TYPE (Object) != ACPI_DESC_TYPE_OPERAND) + { + AcpiOsPrintf ("Invalid Descriptor Type for Object %p [%s]\n", + Object, AcpiUtGetDescriptorName (Object)); + } + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbCheckIntegrity + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Check entire namespace for data structure integrity + * + ******************************************************************************/ + +void +AcpiDbCheckIntegrity ( + void) +{ + ACPI_INTEGRITY_INFO Info = {0,0}; + + /* Search all nodes in namespace */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbIntegrityWalk, NULL, (void *) &Info, NULL); + + AcpiOsPrintf ("Verified %u namespace nodes with %u Objects\n", + Info.Nodes, Info.Objects); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbWalkForReferences + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Check if this namespace object refers to the target object + * that is passed in as the context value. + * + * Note: Currently doesn't check subobjects within the Node's object + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbWalkForReferences ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_OPERAND_OBJECT *ObjDesc = (ACPI_OPERAND_OBJECT *) Context; + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + + + /* Check for match against the namespace node itself */ + + if (Node == (void *) ObjDesc) + { + AcpiOsPrintf ("Object is a Node [%4.4s]\n", + AcpiUtGetNodeName (Node)); + } + + /* Check for match against the object attached to the node */ + + if (AcpiNsGetAttachedObject (Node) == ObjDesc) + { + AcpiOsPrintf ("Reference at Node->Object %p [%4.4s]\n", + Node, AcpiUtGetNodeName (Node)); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbFindReferences + * + * PARAMETERS: ObjectArg - String with hex value of the object + * + * RETURN: None + * + * DESCRIPTION: Search namespace for all references to the input object + * + ******************************************************************************/ + +void +AcpiDbFindReferences ( + char *ObjectArg) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_SIZE Address; + + + /* Convert string to object pointer */ + + Address = strtoul (ObjectArg, NULL, 16); + ObjDesc = ACPI_TO_POINTER (Address); + + /* Search all nodes in namespace */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbWalkForReferences, NULL, + (void *) ObjDesc, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbBusWalk + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Display info about device objects that have a corresponding + * _PRT method. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbBusWalk ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_STATUS Status; + ACPI_BUFFER Buffer; + ACPI_NAMESPACE_NODE *TempNode; + ACPI_DEVICE_INFO *Info; + UINT32 i; + + + if ((Node->Type != ACPI_TYPE_DEVICE) && + (Node->Type != ACPI_TYPE_PROCESSOR)) + { + return (AE_OK); + } + + /* Exit if there is no _PRT under this device */ + + Status = AcpiGetHandle (Node, METHOD_NAME__PRT, + ACPI_CAST_PTR (ACPI_HANDLE, &TempNode)); + if (ACPI_FAILURE (Status)) + { + return (AE_OK); + } + + /* Get the full path to this device object */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (ObjHandle, &Buffer, TRUE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could Not get pathname for object %p\n", + ObjHandle); + return (AE_OK); + } + + Status = AcpiGetObjectInfo (ObjHandle, &Info); + if (ACPI_FAILURE (Status)) + { + return (AE_OK); + } + + /* Display the full path */ + + AcpiOsPrintf ("%-32s Type %X", (char *) Buffer.Pointer, Node->Type); + ACPI_FREE (Buffer.Pointer); + + if (Info->Flags & ACPI_PCI_ROOT_BRIDGE) + { + AcpiOsPrintf (" - Is PCI Root Bridge"); + } + AcpiOsPrintf ("\n"); + + /* _PRT info */ + + AcpiOsPrintf ("_PRT: %p\n", TempNode); + + /* Dump _ADR, _HID, _UID, _CID */ + + if (Info->Valid & ACPI_VALID_ADR) + { + AcpiOsPrintf ("_ADR: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Info->Address)); + } + else + { + AcpiOsPrintf ("_ADR: \n"); + } + + if (Info->Valid & ACPI_VALID_HID) + { + AcpiOsPrintf ("_HID: %s\n", Info->HardwareId.String); + } + else + { + AcpiOsPrintf ("_HID: \n"); + } + + if (Info->Valid & ACPI_VALID_UID) + { + AcpiOsPrintf ("_UID: %s\n", Info->UniqueId.String); + } + else + { + AcpiOsPrintf ("_UID: \n"); + } + + if (Info->Valid & ACPI_VALID_CID) + { + for (i = 0; i < Info->CompatibleIdList.Count; i++) + { + AcpiOsPrintf ("_CID: %s\n", + Info->CompatibleIdList.Ids[i].String); + } + } + else + { + AcpiOsPrintf ("_CID: \n"); + } + + ACPI_FREE (Info); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbGetBusInfo + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display info about system busses. + * + ******************************************************************************/ + +void +AcpiDbGetBusInfo ( + void) +{ + /* Search all nodes in namespace */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbBusWalk, NULL, NULL, NULL); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbobject.c b/third_party/lib/acpica/source/components/debugger/dbobject.c new file mode 100644 index 000000000..58022b8fd --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbobject.c @@ -0,0 +1,580 @@ +/******************************************************************************* + * + * Module Name: dbobject - ACPI object decode and display + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbobject") + + +/* Local prototypes */ + +static void +AcpiDbDecodeNode ( + ACPI_NAMESPACE_NODE *Node); + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpMethodInfo + * + * PARAMETERS: Status - Method execution status + * WalkState - Current state of the parse tree walk + * + * RETURN: None + * + * DESCRIPTION: Called when a method has been aborted because of an error. + * Dumps the method execution stack, and the method locals/args, + * and disassembles the AML opcode that failed. + * + ******************************************************************************/ + +void +AcpiDbDumpMethodInfo ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState) +{ + ACPI_THREAD_STATE *Thread; + + + /* Ignore control codes, they are not errors */ + + if ((Status & AE_CODE_MASK) == AE_CODE_CONTROL) + { + return; + } + + /* We may be executing a deferred opcode */ + + if (WalkState->DeferredNode) + { + AcpiOsPrintf ("Executing subtree for Buffer/Package/Region\n"); + return; + } + + /* + * If there is no Thread, we are not actually executing a method. + * This can happen when the iASL compiler calls the interpreter + * to perform constant folding. + */ + Thread = WalkState->Thread; + if (!Thread) + { + return; + } + + /* Display the method locals and arguments */ + + AcpiOsPrintf ("\n"); + AcpiDbDecodeLocals (WalkState); + AcpiOsPrintf ("\n"); + AcpiDbDecodeArguments (WalkState); + AcpiOsPrintf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDecodeInternalObject + * + * PARAMETERS: ObjDesc - Object to be displayed + * + * RETURN: None + * + * DESCRIPTION: Short display of an internal object. Numbers/Strings/Buffers. + * + ******************************************************************************/ + +void +AcpiDbDecodeInternalObject ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + UINT32 i; + + + if (!ObjDesc) + { + AcpiOsPrintf (" Uninitialized"); + return; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) + { + AcpiOsPrintf (" %p [%s]", ObjDesc, + AcpiUtGetDescriptorName (ObjDesc)); + return; + } + + AcpiOsPrintf (" %s", AcpiUtGetObjectTypeName (ObjDesc)); + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + AcpiOsPrintf (" %8.8X%8.8X", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("(%u) \"%.24s", + ObjDesc->String.Length, ObjDesc->String.Pointer); + + if (ObjDesc->String.Length > 24) + { + AcpiOsPrintf ("..."); + } + else + { + AcpiOsPrintf ("\""); + } + break; + + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf ("(%u)", ObjDesc->Buffer.Length); + for (i = 0; (i < 8) && (i < ObjDesc->Buffer.Length); i++) + { + AcpiOsPrintf (" %2.2X", ObjDesc->Buffer.Pointer[i]); + } + break; + + default: + + AcpiOsPrintf (" %p", ObjDesc); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDecodeNode + * + * PARAMETERS: Node - Object to be displayed + * + * RETURN: None + * + * DESCRIPTION: Short display of a namespace node + * + ******************************************************************************/ + +static void +AcpiDbDecodeNode ( + ACPI_NAMESPACE_NODE *Node) +{ + + AcpiOsPrintf (" Name %4.4s", + AcpiUtGetNodeName (Node)); + + if (Node->Flags & ANOBJ_METHOD_ARG) + { + AcpiOsPrintf (" [Method Arg]"); + } + if (Node->Flags & ANOBJ_METHOD_LOCAL) + { + AcpiOsPrintf (" [Method Local]"); + } + + switch (Node->Type) + { + /* These types have no attached object */ + + case ACPI_TYPE_DEVICE: + + AcpiOsPrintf (" Device"); + break; + + case ACPI_TYPE_THERMAL: + + AcpiOsPrintf (" Thermal Zone"); + break; + + default: + + AcpiDbDecodeInternalObject (AcpiNsGetAttachedObject (Node)); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayInternalObject + * + * PARAMETERS: ObjDesc - Object to be displayed + * WalkState - Current walk state + * + * RETURN: None + * + * DESCRIPTION: Short display of an internal object + * + ******************************************************************************/ + +void +AcpiDbDisplayInternalObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + UINT8 Type; + + + AcpiOsPrintf ("%p ", ObjDesc); + + if (!ObjDesc) + { + AcpiOsPrintf ("\n"); + return; + } + + /* Decode the object type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) + { + case ACPI_DESC_TYPE_PARSER: + + AcpiOsPrintf (" "); + break; + + case ACPI_DESC_TYPE_NAMED: + + AcpiDbDecodeNode ((ACPI_NAMESPACE_NODE *) ObjDesc); + break; + + case ACPI_DESC_TYPE_OPERAND: + + Type = ObjDesc->Common.Type; + if (Type > ACPI_TYPE_LOCAL_MAX) + { + AcpiOsPrintf (" Type %X [Invalid Type]", (UINT32) Type); + return; + } + + /* Decode the ACPI object type */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_LOCAL_REFERENCE: + + AcpiOsPrintf ("[%s] ", AcpiUtGetReferenceName (ObjDesc)); + + /* Decode the refererence */ + + switch (ObjDesc->Reference.Class) + { + case ACPI_REFCLASS_LOCAL: + + AcpiOsPrintf ("%X ", ObjDesc->Reference.Value); + if (WalkState) + { + ObjDesc = WalkState->LocalVariables + [ObjDesc->Reference.Value].Object; + AcpiOsPrintf ("%p", ObjDesc); + AcpiDbDecodeInternalObject (ObjDesc); + } + break; + + case ACPI_REFCLASS_ARG: + + AcpiOsPrintf ("%X ", ObjDesc->Reference.Value); + if (WalkState) + { + ObjDesc = WalkState->Arguments + [ObjDesc->Reference.Value].Object; + AcpiOsPrintf ("%p", ObjDesc); + AcpiDbDecodeInternalObject (ObjDesc); + } + break; + + case ACPI_REFCLASS_INDEX: + + switch (ObjDesc->Reference.TargetType) + { + case ACPI_TYPE_BUFFER_FIELD: + + AcpiOsPrintf ("%p", ObjDesc->Reference.Object); + AcpiDbDecodeInternalObject (ObjDesc->Reference.Object); + break; + + case ACPI_TYPE_PACKAGE: + + AcpiOsPrintf ("%p", ObjDesc->Reference.Where); + if (!ObjDesc->Reference.Where) + { + AcpiOsPrintf (" Uninitialized WHERE pointer"); + } + else + { + AcpiDbDecodeInternalObject ( + *(ObjDesc->Reference.Where)); + } + break; + + default: + + AcpiOsPrintf ("Unknown index target type"); + break; + } + break; + + case ACPI_REFCLASS_REFOF: + + if (!ObjDesc->Reference.Object) + { + AcpiOsPrintf ( + "Uninitialized reference subobject pointer"); + break; + } + + /* Reference can be to a Node or an Operand object */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc->Reference.Object)) + { + case ACPI_DESC_TYPE_NAMED: + + AcpiDbDecodeNode (ObjDesc->Reference.Object); + break; + + case ACPI_DESC_TYPE_OPERAND: + + AcpiDbDecodeInternalObject (ObjDesc->Reference.Object); + break; + + default: + break; + } + break; + + case ACPI_REFCLASS_NAME: + + AcpiDbDecodeNode (ObjDesc->Reference.Node); + break; + + case ACPI_REFCLASS_DEBUG: + case ACPI_REFCLASS_TABLE: + + AcpiOsPrintf ("\n"); + break; + + default: /* Unknown reference class */ + + AcpiOsPrintf ("%2.2X\n", ObjDesc->Reference.Class); + break; + } + break; + + default: + + AcpiOsPrintf (" "); + AcpiDbDecodeInternalObject (ObjDesc); + break; + } + break; + + default: + + AcpiOsPrintf (" [%s]", + AcpiUtGetDescriptorName (ObjDesc)); + break; + } + + AcpiOsPrintf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDecodeLocals + * + * PARAMETERS: WalkState - State for current method + * + * RETURN: None + * + * DESCRIPTION: Display all locals for the currently running control method + * + ******************************************************************************/ + +void +AcpiDbDecodeLocals ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 i; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + BOOLEAN DisplayLocals = FALSE; + + + ObjDesc = WalkState->MethodDesc; + Node = WalkState->MethodNode; + + if (!Node) + { + AcpiOsPrintf ( + "No method node (Executing subtree for buffer or opregion)\n"); + return; + } + + if (Node->Type != ACPI_TYPE_METHOD) + { + AcpiOsPrintf ("Executing subtree for Buffer/Package/Region\n"); + return; + } + + /* Are any locals actually set? */ + + for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) + { + ObjDesc = WalkState->LocalVariables[i].Object; + if (ObjDesc) + { + DisplayLocals = TRUE; + break; + } + } + + /* If any are set, only display the ones that are set */ + + if (DisplayLocals) + { + AcpiOsPrintf ("\nInitialized Local Variables for method [%4.4s]:\n", + AcpiUtGetNodeName (Node)); + + for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) + { + ObjDesc = WalkState->LocalVariables[i].Object; + if (ObjDesc) + { + AcpiOsPrintf (" Local%X: ", i); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); + } + } + } + else + { + AcpiOsPrintf ( + "No Local Variables are initialized for method [%4.4s]\n", + AcpiUtGetNodeName (Node)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDecodeArguments + * + * PARAMETERS: WalkState - State for current method + * + * RETURN: None + * + * DESCRIPTION: Display all arguments for the currently running control method + * + ******************************************************************************/ + +void +AcpiDbDecodeArguments ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 i; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + BOOLEAN DisplayArgs = FALSE; + + + Node = WalkState->MethodNode; + ObjDesc = WalkState->MethodDesc; + + if (!Node) + { + AcpiOsPrintf ( + "No method node (Executing subtree for buffer or opregion)\n"); + return; + } + + if (Node->Type != ACPI_TYPE_METHOD) + { + AcpiOsPrintf ("Executing subtree for Buffer/Package/Region\n"); + return; + } + + /* Are any arguments actually set? */ + + for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) + { + ObjDesc = WalkState->Arguments[i].Object; + if (ObjDesc) + { + DisplayArgs = TRUE; + break; + } + } + + /* If any are set, only display the ones that are set */ + + if (DisplayArgs) + { + AcpiOsPrintf ( + "Initialized Arguments for Method [%4.4s]: " + "(%X arguments defined for method invocation)\n", + AcpiUtGetNodeName (Node), ObjDesc->Method.ParamCount); + + for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) + { + ObjDesc = WalkState->Arguments[i].Object; + if (ObjDesc) + { + AcpiOsPrintf (" Arg%u: ", i); + AcpiDbDisplayInternalObject (ObjDesc, WalkState); + } + } + } + else + { + AcpiOsPrintf ( + "No Arguments are initialized for method [%4.4s]\n", + AcpiUtGetNodeName (Node)); + } +} diff --git a/third_party/lib/acpica/source/components/debugger/dbstats.c b/third_party/lib/acpica/source/components/debugger/dbstats.c new file mode 100644 index 000000000..d893ba0d0 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbstats.c @@ -0,0 +1,558 @@ +/******************************************************************************* + * + * Module Name: dbstats - Generation and display of ACPI table statistics + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbstats") + + +/* Local prototypes */ + +static void +AcpiDbCountNamespaceObjects ( + void); + +static void +AcpiDbEnumerateObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +static ACPI_STATUS +AcpiDbClassifyOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE +static void +AcpiDbListInfo ( + ACPI_MEMORY_LIST *List); +#endif + + +/* + * Statistics subcommands + */ +static ACPI_DB_ARGUMENT_INFO AcpiDbStatTypes [] = +{ + {"ALLOCATIONS"}, + {"OBJECTS"}, + {"MEMORY"}, + {"MISC"}, + {"TABLES"}, + {"SIZES"}, + {"STACK"}, + {NULL} /* Must be null terminated */ +}; + +#define CMD_STAT_ALLOCATIONS 0 +#define CMD_STAT_OBJECTS 1 +#define CMD_STAT_MEMORY 2 +#define CMD_STAT_MISC 3 +#define CMD_STAT_TABLES 4 +#define CMD_STAT_SIZES 5 +#define CMD_STAT_STACK 6 + + +#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE +/******************************************************************************* + * + * FUNCTION: AcpiDbListInfo + * + * PARAMETERS: List - Memory list/cache to be displayed + * + * RETURN: None + * + * DESCRIPTION: Display information about the input memory list or cache. + * + ******************************************************************************/ + +static void +AcpiDbListInfo ( + ACPI_MEMORY_LIST *List) +{ +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + UINT32 Outstanding; +#endif + + AcpiOsPrintf ("\n%s\n", List->ListName); + + /* MaxDepth > 0 indicates a cache object */ + + if (List->MaxDepth > 0) + { + AcpiOsPrintf ( + " Cache: [Depth MaxD Avail Size] " + "%8.2X %8.2X %8.2X %8.2X\n", + List->CurrentDepth, + List->MaxDepth, + List->MaxDepth - List->CurrentDepth, + (List->CurrentDepth * List->ObjectSize)); + } + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + if (List->MaxDepth > 0) + { + AcpiOsPrintf ( + " Cache: [Requests Hits Misses ObjSize] " + "%8.2X %8.2X %8.2X %8.2X\n", + List->Requests, + List->Hits, + List->Requests - List->Hits, + List->ObjectSize); + } + + Outstanding = AcpiDbGetCacheInfo (List); + + if (List->ObjectSize) + { + AcpiOsPrintf ( + " Mem: [Alloc Free Max CurSize Outstanding] " + "%8.2X %8.2X %8.2X %8.2X %8.2X\n", + List->TotalAllocated, + List->TotalFreed, + List->MaxOccupied, + Outstanding * List->ObjectSize, + Outstanding); + } + else + { + AcpiOsPrintf ( + " Mem: [Alloc Free Max CurSize Outstanding Total] " + "%8.2X %8.2X %8.2X %8.2X %8.2X %8.2X\n", + List->TotalAllocated, + List->TotalFreed, + List->MaxOccupied, + List->CurrentTotalSize, + Outstanding, + List->TotalSize); + } +#endif +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDbEnumerateObject + * + * PARAMETERS: ObjDesc - Object to be counted + * + * RETURN: None + * + * DESCRIPTION: Add this object to the global counts, by object type. + * Limited recursion handles subobjects and packages, and this + * is probably acceptable within the AML debugger only. + * + ******************************************************************************/ + +static void +AcpiDbEnumerateObject ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + UINT32 i; + + + if (!ObjDesc) + { + return; + } + + /* Enumerate this object first */ + + AcpiGbl_NumObjects++; + + if (ObjDesc->Common.Type > ACPI_TYPE_NS_NODE_MAX) + { + AcpiGbl_ObjTypeCountMisc++; + } + else + { + AcpiGbl_ObjTypeCount [ObjDesc->Common.Type]++; + } + + /* Count the sub-objects */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_PACKAGE: + + for (i = 0; i < ObjDesc->Package.Count; i++) + { + AcpiDbEnumerateObject (ObjDesc->Package.Elements[i]); + } + break; + + case ACPI_TYPE_DEVICE: + + AcpiDbEnumerateObject (ObjDesc->Device.NotifyList[0]); + AcpiDbEnumerateObject (ObjDesc->Device.NotifyList[1]); + AcpiDbEnumerateObject (ObjDesc->Device.Handler); + break; + + case ACPI_TYPE_BUFFER_FIELD: + + if (AcpiNsGetSecondaryObject (ObjDesc)) + { + AcpiGbl_ObjTypeCount [ACPI_TYPE_BUFFER_FIELD]++; + } + break; + + case ACPI_TYPE_REGION: + + AcpiGbl_ObjTypeCount [ACPI_TYPE_LOCAL_REGION_FIELD ]++; + AcpiDbEnumerateObject (ObjDesc->Region.Handler); + break; + + case ACPI_TYPE_POWER: + + AcpiDbEnumerateObject (ObjDesc->PowerResource.NotifyList[0]); + AcpiDbEnumerateObject (ObjDesc->PowerResource.NotifyList[1]); + break; + + case ACPI_TYPE_PROCESSOR: + + AcpiDbEnumerateObject (ObjDesc->Processor.NotifyList[0]); + AcpiDbEnumerateObject (ObjDesc->Processor.NotifyList[1]); + AcpiDbEnumerateObject (ObjDesc->Processor.Handler); + break; + + case ACPI_TYPE_THERMAL: + + AcpiDbEnumerateObject (ObjDesc->ThermalZone.NotifyList[0]); + AcpiDbEnumerateObject (ObjDesc->ThermalZone.NotifyList[1]); + AcpiDbEnumerateObject (ObjDesc->ThermalZone.Handler); + break; + + default: + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbClassifyOneObject + * + * PARAMETERS: Callback for WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Enumerate both the object descriptor (including subobjects) and + * the parent namespace node. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbClassifyOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 Type; + + + AcpiGbl_NumNodes++; + + Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ObjDesc = AcpiNsGetAttachedObject (Node); + + AcpiDbEnumerateObject (ObjDesc); + + Type = Node->Type; + if (Type > ACPI_TYPE_NS_NODE_MAX) + { + AcpiGbl_NodeTypeCountMisc++; + } + else + { + AcpiGbl_NodeTypeCount [Type]++; + } + + return (AE_OK); + + +#ifdef ACPI_FUTURE_IMPLEMENTATION + + /* TBD: These need to be counted during the initial parsing phase */ + + if (AcpiPsIsNamedOp (Op->Opcode)) + { + NumNodes++; + } + + if (IsMethod) + { + NumMethodElements++; + } + + NumGrammarElements++; + Op = AcpiPsGetDepthNext (Root, Op); + + SizeOfParseTree = (NumGrammarElements - NumMethodElements) * + (UINT32) sizeof (ACPI_PARSE_OBJECT); + SizeOfMethodTrees = NumMethodElements * (UINT32) sizeof (ACPI_PARSE_OBJECT); + SizeOfNodeEntries = NumNodes * (UINT32) sizeof (ACPI_NAMESPACE_NODE); + SizeOfAcpiObjects = NumNodes * (UINT32) sizeof (ACPI_OPERAND_OBJECT); +#endif +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbCountNamespaceObjects + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Count and classify the entire namespace, including all + * namespace nodes and attached objects. + * + ******************************************************************************/ + +static void +AcpiDbCountNamespaceObjects ( + void) +{ + UINT32 i; + + + AcpiGbl_NumNodes = 0; + AcpiGbl_NumObjects = 0; + + AcpiGbl_ObjTypeCountMisc = 0; + for (i = 0; i < (ACPI_TYPE_NS_NODE_MAX -1); i++) + { + AcpiGbl_ObjTypeCount [i] = 0; + AcpiGbl_NodeTypeCount [i] = 0; + } + + (void) AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, AcpiDbClassifyOneObject, NULL, NULL, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDisplayStatistics + * + * PARAMETERS: TypeArg - Subcommand + * + * RETURN: Status + * + * DESCRIPTION: Display various statistics + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbDisplayStatistics ( + char *TypeArg) +{ + UINT32 i; + UINT32 Temp; + + + AcpiUtStrupr (TypeArg); + Temp = AcpiDbMatchArgument (TypeArg, AcpiDbStatTypes); + if (Temp == ACPI_TYPE_NOT_FOUND) + { + AcpiOsPrintf ("Invalid or unsupported argument\n"); + return (AE_OK); + } + + + switch (Temp) + { + case CMD_STAT_ALLOCATIONS: + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + AcpiUtDumpAllocationInfo (); +#endif + break; + + case CMD_STAT_TABLES: + + AcpiOsPrintf ("ACPI Table Information (not implemented):\n\n"); + break; + + case CMD_STAT_OBJECTS: + + AcpiDbCountNamespaceObjects (); + + AcpiOsPrintf ("\nObjects defined in the current namespace:\n\n"); + + AcpiOsPrintf ("%16.16s %10.10s %10.10s\n", + "ACPI_TYPE", "NODES", "OBJECTS"); + + for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) + { + AcpiOsPrintf ("%16.16s % 10ld% 10ld\n", AcpiUtGetTypeName (i), + AcpiGbl_NodeTypeCount [i], AcpiGbl_ObjTypeCount [i]); + } + + AcpiOsPrintf ("%16.16s % 10ld% 10ld\n", "Misc/Unknown", + AcpiGbl_NodeTypeCountMisc, AcpiGbl_ObjTypeCountMisc); + + AcpiOsPrintf ("%16.16s % 10ld% 10ld\n", "TOTALS:", + AcpiGbl_NumNodes, AcpiGbl_NumObjects); + break; + + case CMD_STAT_MEMORY: + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + AcpiOsPrintf ("\n----Object Statistics (all in hex)---------\n"); + + AcpiDbListInfo (AcpiGbl_GlobalList); + AcpiDbListInfo (AcpiGbl_NsNodeList); +#endif + +#ifdef ACPI_USE_LOCAL_CACHE + AcpiOsPrintf ("\n----Cache Statistics (all in hex)---------\n"); + AcpiDbListInfo (AcpiGbl_OperandCache); + AcpiDbListInfo (AcpiGbl_PsNodeCache); + AcpiDbListInfo (AcpiGbl_PsNodeExtCache); + AcpiDbListInfo (AcpiGbl_StateCache); +#endif + + break; + + case CMD_STAT_MISC: + + AcpiOsPrintf ("\nMiscellaneous Statistics:\n\n"); + AcpiOsPrintf ("Calls to AcpiPsFind:.. ........% 7ld\n", + AcpiGbl_PsFindCount); + AcpiOsPrintf ("Calls to AcpiNsLookup:..........% 7ld\n", + AcpiGbl_NsLookupCount); + + AcpiOsPrintf ("\n"); + + AcpiOsPrintf ("Mutex usage:\n\n"); + for (i = 0; i < ACPI_NUM_MUTEX; i++) + { + AcpiOsPrintf ("%-28s: % 7ld\n", + AcpiUtGetMutexName (i), AcpiGbl_MutexInfo[i].UseCount); + } + break; + + case CMD_STAT_SIZES: + + AcpiOsPrintf ("\nInternal object sizes:\n\n"); + + AcpiOsPrintf ("Common %3d\n", sizeof (ACPI_OBJECT_COMMON)); + AcpiOsPrintf ("Number %3d\n", sizeof (ACPI_OBJECT_INTEGER)); + AcpiOsPrintf ("String %3d\n", sizeof (ACPI_OBJECT_STRING)); + AcpiOsPrintf ("Buffer %3d\n", sizeof (ACPI_OBJECT_BUFFER)); + AcpiOsPrintf ("Package %3d\n", sizeof (ACPI_OBJECT_PACKAGE)); + AcpiOsPrintf ("BufferField %3d\n", sizeof (ACPI_OBJECT_BUFFER_FIELD)); + AcpiOsPrintf ("Device %3d\n", sizeof (ACPI_OBJECT_DEVICE)); + AcpiOsPrintf ("Event %3d\n", sizeof (ACPI_OBJECT_EVENT)); + AcpiOsPrintf ("Method %3d\n", sizeof (ACPI_OBJECT_METHOD)); + AcpiOsPrintf ("Mutex %3d\n", sizeof (ACPI_OBJECT_MUTEX)); + AcpiOsPrintf ("Region %3d\n", sizeof (ACPI_OBJECT_REGION)); + AcpiOsPrintf ("PowerResource %3d\n", sizeof (ACPI_OBJECT_POWER_RESOURCE)); + AcpiOsPrintf ("Processor %3d\n", sizeof (ACPI_OBJECT_PROCESSOR)); + AcpiOsPrintf ("ThermalZone %3d\n", sizeof (ACPI_OBJECT_THERMAL_ZONE)); + AcpiOsPrintf ("RegionField %3d\n", sizeof (ACPI_OBJECT_REGION_FIELD)); + AcpiOsPrintf ("BankField %3d\n", sizeof (ACPI_OBJECT_BANK_FIELD)); + AcpiOsPrintf ("IndexField %3d\n", sizeof (ACPI_OBJECT_INDEX_FIELD)); + AcpiOsPrintf ("Reference %3d\n", sizeof (ACPI_OBJECT_REFERENCE)); + AcpiOsPrintf ("Notify %3d\n", sizeof (ACPI_OBJECT_NOTIFY_HANDLER)); + AcpiOsPrintf ("AddressSpace %3d\n", sizeof (ACPI_OBJECT_ADDR_HANDLER)); + AcpiOsPrintf ("Extra %3d\n", sizeof (ACPI_OBJECT_EXTRA)); + AcpiOsPrintf ("Data %3d\n", sizeof (ACPI_OBJECT_DATA)); + + AcpiOsPrintf ("\n"); + + AcpiOsPrintf ("ParseObject %3d\n", sizeof (ACPI_PARSE_OBJ_COMMON)); + AcpiOsPrintf ("ParseObjectNamed %3d\n", sizeof (ACPI_PARSE_OBJ_NAMED)); + AcpiOsPrintf ("ParseObjectAsl %3d\n", sizeof (ACPI_PARSE_OBJ_ASL)); + AcpiOsPrintf ("OperandObject %3d\n", sizeof (ACPI_OPERAND_OBJECT)); + AcpiOsPrintf ("NamespaceNode %3d\n", sizeof (ACPI_NAMESPACE_NODE)); + AcpiOsPrintf ("AcpiObject %3d\n", sizeof (ACPI_OBJECT)); + + AcpiOsPrintf ("\n"); + + AcpiOsPrintf ("Generic State %3d\n", sizeof (ACPI_GENERIC_STATE)); + AcpiOsPrintf ("Common State %3d\n", sizeof (ACPI_COMMON_STATE)); + AcpiOsPrintf ("Control State %3d\n", sizeof (ACPI_CONTROL_STATE)); + AcpiOsPrintf ("Update State %3d\n", sizeof (ACPI_UPDATE_STATE)); + AcpiOsPrintf ("Scope State %3d\n", sizeof (ACPI_SCOPE_STATE)); + AcpiOsPrintf ("Parse Scope %3d\n", sizeof (ACPI_PSCOPE_STATE)); + AcpiOsPrintf ("Package State %3d\n", sizeof (ACPI_PKG_STATE)); + AcpiOsPrintf ("Thread State %3d\n", sizeof (ACPI_THREAD_STATE)); + AcpiOsPrintf ("Result Values %3d\n", sizeof (ACPI_RESULT_VALUES)); + AcpiOsPrintf ("Notify Info %3d\n", sizeof (ACPI_NOTIFY_INFO)); + break; + + case CMD_STAT_STACK: +#if defined(ACPI_DEBUG_OUTPUT) + + Temp = (UINT32) ACPI_PTR_DIFF ( + AcpiGbl_EntryStackPointer, AcpiGbl_LowestStackPointer); + + AcpiOsPrintf ("\nSubsystem Stack Usage:\n\n"); + AcpiOsPrintf ("Entry Stack Pointer %p\n", AcpiGbl_EntryStackPointer); + AcpiOsPrintf ("Lowest Stack Pointer %p\n", AcpiGbl_LowestStackPointer); + AcpiOsPrintf ("Stack Use %X (%u)\n", Temp, Temp); + AcpiOsPrintf ("Deepest Procedure Nesting %u\n", AcpiGbl_DeepestNesting); +#endif + break; + + default: + + break; + } + + AcpiOsPrintf ("\n"); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbtest.c b/third_party/lib/acpica/source/components/debugger/dbtest.c new file mode 100644 index 000000000..c5031f58a --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbtest.c @@ -0,0 +1,1142 @@ +/******************************************************************************* + * + * Module Name: dbtest - Various debug-related tests + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" +#include "acnamesp.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbtest") + + +/* Local prototypes */ + +static void +AcpiDbTestAllObjects ( + void); + +static ACPI_STATUS +AcpiDbTestOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiDbTestIntegerType ( + ACPI_NAMESPACE_NODE *Node, + UINT32 BitLength); + +static ACPI_STATUS +AcpiDbTestBufferType ( + ACPI_NAMESPACE_NODE *Node, + UINT32 BitLength); + +static ACPI_STATUS +AcpiDbTestStringType ( + ACPI_NAMESPACE_NODE *Node, + UINT32 ByteLength); + +static ACPI_STATUS +AcpiDbReadFromObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE ExpectedType, + ACPI_OBJECT **Value); + +static ACPI_STATUS +AcpiDbWriteToObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT *Value); + +static void +AcpiDbEvaluateAllPredefinedNames ( + char *CountArg); + +static ACPI_STATUS +AcpiDbEvaluateOnePredefinedName ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +/* + * Test subcommands + */ +static ACPI_DB_ARGUMENT_INFO AcpiDbTestTypes [] = +{ + {"OBJECTS"}, + {"PREDEFINED"}, + {NULL} /* Must be null terminated */ +}; + +#define CMD_TEST_OBJECTS 0 +#define CMD_TEST_PREDEFINED 1 + +#define BUFFER_FILL_VALUE 0xFF + +/* + * Support for the special debugger read/write control methods. + * These methods are installed into the current namespace and are + * used to read and write the various namespace objects. The point + * is to force the AML interpreter do all of the work. + */ +#define ACPI_DB_READ_METHOD "\\_T98" +#define ACPI_DB_WRITE_METHOD "\\_T99" + +static ACPI_HANDLE ReadHandle = NULL; +static ACPI_HANDLE WriteHandle = NULL; + +/* ASL Definitions of the debugger read/write control methods */ + +#if 0 +DefinitionBlock ("ssdt.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001) +{ + Method (_T98, 1, NotSerialized) /* Read */ + { + Return (DeRefOf (Arg0)) + } +} +DefinitionBlock ("ssdt2.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001) +{ + Method (_T99, 2, NotSerialized) /* Write */ + { + Store (Arg1, Arg0) + } +} +#endif + +static unsigned char ReadMethodCode[] = +{ + 0x53,0x53,0x44,0x54,0x2E,0x00,0x00,0x00, /* 00000000 "SSDT...." */ + 0x02,0xC9,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x44,0x45,0x42,0x55,0x47,0x00,0x00,0x00, /* 00000010 "DEBUG..." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x18,0x12,0x13,0x20,0x14,0x09,0x5F,0x54, /* 00000020 "... .._T" */ + 0x39,0x38,0x01,0xA4,0x83,0x68 /* 00000028 "98...h" */ +}; + +static unsigned char WriteMethodCode[] = +{ + 0x53,0x53,0x44,0x54,0x2E,0x00,0x00,0x00, /* 00000000 "SSDT...." */ + 0x02,0x15,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x44,0x45,0x42,0x55,0x47,0x00,0x00,0x00, /* 00000010 "DEBUG..." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x18,0x12,0x13,0x20,0x14,0x09,0x5F,0x54, /* 00000020 "... .._T" */ + 0x39,0x39,0x02,0x70,0x69,0x68 /* 00000028 "99.pih" */ +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbExecuteTest + * + * PARAMETERS: TypeArg - Subcommand + * + * RETURN: None + * + * DESCRIPTION: Execute various debug tests. + * + * Note: Code is prepared for future expansion of the TEST command. + * + ******************************************************************************/ + +void +AcpiDbExecuteTest ( + char *TypeArg) +{ + UINT32 Temp; + + + AcpiUtStrupr (TypeArg); + Temp = AcpiDbMatchArgument (TypeArg, AcpiDbTestTypes); + if (Temp == ACPI_TYPE_NOT_FOUND) + { + AcpiOsPrintf ("Invalid or unsupported argument\n"); + return; + } + + switch (Temp) + { + case CMD_TEST_OBJECTS: + + AcpiDbTestAllObjects (); + break; + + case CMD_TEST_PREDEFINED: + + AcpiDbEvaluateAllPredefinedNames (NULL); + break; + + default: + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbTestAllObjects + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: This test implements the OBJECTS subcommand. It exercises the + * namespace by reading/writing/comparing all data objects such + * as integers, strings, buffers, fields, buffer fields, etc. + * + ******************************************************************************/ + +static void +AcpiDbTestAllObjects ( + void) +{ + ACPI_STATUS Status; + + + /* Install the debugger read-object control method if necessary */ + + if (!ReadHandle) + { + Status = AcpiInstallMethod (ReadMethodCode); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, Could not install debugger read method\n", + AcpiFormatException (Status)); + return; + } + + Status = AcpiGetHandle (NULL, ACPI_DB_READ_METHOD, &ReadHandle); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not obtain handle for debug method %s\n", + ACPI_DB_READ_METHOD); + return; + } + } + + /* Install the debugger write-object control method if necessary */ + + if (!WriteHandle) + { + Status = AcpiInstallMethod (WriteMethodCode); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, Could not install debugger write method\n", + AcpiFormatException (Status)); + return; + } + + Status = AcpiGetHandle (NULL, ACPI_DB_WRITE_METHOD, &WriteHandle); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not obtain handle for debug method %s\n", + ACPI_DB_WRITE_METHOD); + return; + } + } + + /* Walk the entire namespace, testing each supported named data object */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbTestOneObject, NULL, NULL, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbTestOneObject + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Test one namespace object. Supported types are Integer, + * String, Buffer, BufferField, and FieldUnit. All other object + * types are simply ignored. + * + * Note: Support for Packages is not implemented. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbTestOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *RegionObj; + ACPI_OBJECT_TYPE LocalType; + UINT32 BitLength = 0; + UINT32 ByteLength = 0; + ACPI_STATUS Status = AE_OK; + + + Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + ObjDesc = Node->Object; + + /* + * For the supported types, get the actual bit length or + * byte length. Map the type to one of Integer/String/Buffer. + */ + switch (Node->Type) + { + case ACPI_TYPE_INTEGER: + + /* Integer width is either 32 or 64 */ + + LocalType = ACPI_TYPE_INTEGER; + BitLength = AcpiGbl_IntegerBitWidth; + break; + + case ACPI_TYPE_STRING: + + LocalType = ACPI_TYPE_STRING; + ByteLength = ObjDesc->String.Length; + break; + + case ACPI_TYPE_BUFFER: + + LocalType = ACPI_TYPE_BUFFER; + ByteLength = ObjDesc->Buffer.Length; + BitLength = ByteLength * 8; + break; + + case ACPI_TYPE_FIELD_UNIT: + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + + LocalType = ACPI_TYPE_INTEGER; + if (ObjDesc) + { + /* + * Returned object will be a Buffer if the field length + * is larger than the size of an Integer (32 or 64 bits + * depending on the DSDT version). + */ + BitLength = ObjDesc->CommonField.BitLength; + ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength); + if (BitLength > AcpiGbl_IntegerBitWidth) + { + LocalType = ACPI_TYPE_BUFFER; + } + } + break; + + default: + + /* Ignore all other types */ + + return (AE_OK); + } + + /* Emit the common prefix: Type:Name */ + + AcpiOsPrintf ("%14s: %4.4s", + AcpiUtGetTypeName (Node->Type), Node->Name.Ascii); + if (!ObjDesc) + { + AcpiOsPrintf (" Ignoring, no attached object\n"); + return (AE_OK); + } + + /* + * Check for unsupported region types. Note: AcpiExec simulates + * access to SystemMemory, SystemIO, PCI_Config, and EC. + */ + switch (Node->Type) + { + case ACPI_TYPE_LOCAL_REGION_FIELD: + + RegionObj = ObjDesc->Field.RegionObj; + switch (RegionObj->Region.SpaceId) + { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + case ACPI_ADR_SPACE_SYSTEM_IO: + case ACPI_ADR_SPACE_PCI_CONFIG: + case ACPI_ADR_SPACE_EC: + + break; + + default: + + AcpiOsPrintf (" %s space is not supported [%4.4s]\n", + AcpiUtGetRegionName (RegionObj->Region.SpaceId), + RegionObj->Region.Node->Name.Ascii); + return (AE_OK); + } + break; + + default: + break; + } + + /* At this point, we have resolved the object to one of the major types */ + + switch (LocalType) + { + case ACPI_TYPE_INTEGER: + + Status = AcpiDbTestIntegerType (Node, BitLength); + break; + + case ACPI_TYPE_STRING: + + Status = AcpiDbTestStringType (Node, ByteLength); + break; + + case ACPI_TYPE_BUFFER: + + Status = AcpiDbTestBufferType (Node, BitLength); + break; + + default: + + AcpiOsPrintf (" Ignoring, type not implemented (%2.2X)", + LocalType); + break; + } + + switch (Node->Type) + { + case ACPI_TYPE_LOCAL_REGION_FIELD: + + RegionObj = ObjDesc->Field.RegionObj; + AcpiOsPrintf (" (%s)", + AcpiUtGetRegionName (RegionObj->Region.SpaceId)); + break; + + default: + break; + } + + AcpiOsPrintf ("\n"); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbTestIntegerType + * + * PARAMETERS: Node - Parent NS node for the object + * BitLength - Actual length of the object. Used for + * support of arbitrary length FieldUnit + * and BufferField objects. + * + * RETURN: Status + * + * DESCRIPTION: Test read/write for an Integer-valued object. Performs a + * write/read/compare of an arbitrary new value, then performs + * a write/read/compare of the original value. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbTestIntegerType ( + ACPI_NAMESPACE_NODE *Node, + UINT32 BitLength) +{ + ACPI_OBJECT *Temp1 = NULL; + ACPI_OBJECT *Temp2 = NULL; + ACPI_OBJECT *Temp3 = NULL; + ACPI_OBJECT WriteValue; + UINT64 ValueToWrite; + ACPI_STATUS Status; + + + if (BitLength > 64) + { + AcpiOsPrintf (" Invalid length for an Integer: %u", BitLength); + return (AE_OK); + } + + /* Read the original value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp1); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + AcpiOsPrintf (" (%4.4X/%3.3X) %8.8X%8.8X", + BitLength, ACPI_ROUND_BITS_UP_TO_BYTES (BitLength), + ACPI_FORMAT_UINT64 (Temp1->Integer.Value)); + + ValueToWrite = ACPI_UINT64_MAX >> (64 - BitLength); + if (Temp1->Integer.Value == ValueToWrite) + { + ValueToWrite = 0; + } + + /* Write a new value */ + + WriteValue.Type = ACPI_TYPE_INTEGER; + WriteValue.Integer.Value = ValueToWrite; + Status = AcpiDbWriteToObject (Node, &WriteValue); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Ensure that we can read back the new value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp2); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (Temp2->Integer.Value != ValueToWrite) + { + AcpiOsPrintf (" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X", + ACPI_FORMAT_UINT64 (Temp2->Integer.Value), + ACPI_FORMAT_UINT64 (ValueToWrite)); + } + + /* Write back the original value */ + + WriteValue.Integer.Value = Temp1->Integer.Value; + Status = AcpiDbWriteToObject (Node, &WriteValue); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Ensure that we can read back the original value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp3); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (Temp3->Integer.Value != Temp1->Integer.Value) + { + AcpiOsPrintf (" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X", + ACPI_FORMAT_UINT64 (Temp3->Integer.Value), + ACPI_FORMAT_UINT64 (Temp1->Integer.Value)); + } + +Exit: + if (Temp1) {AcpiOsFree (Temp1);} + if (Temp2) {AcpiOsFree (Temp2);} + if (Temp3) {AcpiOsFree (Temp3);} + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbTestBufferType + * + * PARAMETERS: Node - Parent NS node for the object + * BitLength - Actual length of the object. + * + * RETURN: Status + * + * DESCRIPTION: Test read/write for an Buffer-valued object. Performs a + * write/read/compare of an arbitrary new value, then performs + * a write/read/compare of the original value. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbTestBufferType ( + ACPI_NAMESPACE_NODE *Node, + UINT32 BitLength) +{ + ACPI_OBJECT *Temp1 = NULL; + ACPI_OBJECT *Temp2 = NULL; + ACPI_OBJECT *Temp3 = NULL; + UINT8 *Buffer; + ACPI_OBJECT WriteValue; + ACPI_STATUS Status; + UINT32 ByteLength; + UINT32 i; + UINT8 ExtraBits; + + + ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength); + if (ByteLength == 0) + { + AcpiOsPrintf (" Ignoring zero length buffer"); + return (AE_OK); + } + + /* Allocate a local buffer */ + + Buffer = ACPI_ALLOCATE_ZEROED (ByteLength); + if (!Buffer) + { + return (AE_NO_MEMORY); + } + + /* Read the original value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp1); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Emit a few bytes of the buffer */ + + AcpiOsPrintf (" (%4.4X/%3.3X)", BitLength, Temp1->Buffer.Length); + for (i = 0; ((i < 4) && (i < ByteLength)); i++) + { + AcpiOsPrintf (" %2.2X", Temp1->Buffer.Pointer[i]); + } + AcpiOsPrintf ("... "); + + /* + * Write a new value. + * + * Handle possible extra bits at the end of the buffer. Can + * happen for FieldUnits larger than an integer, but the bit + * count is not an integral number of bytes. Zero out the + * unused bits. + */ + memset (Buffer, BUFFER_FILL_VALUE, ByteLength); + ExtraBits = BitLength % 8; + if (ExtraBits) + { + Buffer [ByteLength - 1] = ACPI_MASK_BITS_ABOVE (ExtraBits); + } + + WriteValue.Type = ACPI_TYPE_BUFFER; + WriteValue.Buffer.Length = ByteLength; + WriteValue.Buffer.Pointer = Buffer; + + Status = AcpiDbWriteToObject (Node, &WriteValue); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Ensure that we can read back the new value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp2); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (memcmp (Temp2->Buffer.Pointer, Buffer, ByteLength)) + { + AcpiOsPrintf (" MISMATCH 2: New buffer value"); + } + + /* Write back the original value */ + + WriteValue.Buffer.Length = ByteLength; + WriteValue.Buffer.Pointer = Temp1->Buffer.Pointer; + + Status = AcpiDbWriteToObject (Node, &WriteValue); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Ensure that we can read back the original value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp3); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (memcmp (Temp1->Buffer.Pointer, + Temp3->Buffer.Pointer, ByteLength)) + { + AcpiOsPrintf (" MISMATCH 3: While restoring original buffer"); + } + +Exit: + ACPI_FREE (Buffer); + if (Temp1) {AcpiOsFree (Temp1);} + if (Temp2) {AcpiOsFree (Temp2);} + if (Temp3) {AcpiOsFree (Temp3);} + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbTestStringType + * + * PARAMETERS: Node - Parent NS node for the object + * ByteLength - Actual length of the object. + * + * RETURN: Status + * + * DESCRIPTION: Test read/write for an String-valued object. Performs a + * write/read/compare of an arbitrary new value, then performs + * a write/read/compare of the original value. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbTestStringType ( + ACPI_NAMESPACE_NODE *Node, + UINT32 ByteLength) +{ + ACPI_OBJECT *Temp1 = NULL; + ACPI_OBJECT *Temp2 = NULL; + ACPI_OBJECT *Temp3 = NULL; + char *ValueToWrite = "Test String from AML Debugger"; + ACPI_OBJECT WriteValue; + ACPI_STATUS Status; + + + /* Read the original value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_STRING, &Temp1); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + AcpiOsPrintf (" (%4.4X/%3.3X) \"%s\"", (Temp1->String.Length * 8), + Temp1->String.Length, Temp1->String.Pointer); + + /* Write a new value */ + + WriteValue.Type = ACPI_TYPE_STRING; + WriteValue.String.Length = strlen (ValueToWrite); + WriteValue.String.Pointer = ValueToWrite; + + Status = AcpiDbWriteToObject (Node, &WriteValue); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Ensure that we can read back the new value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_STRING, &Temp2); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (strcmp (Temp2->String.Pointer, ValueToWrite)) + { + AcpiOsPrintf (" MISMATCH 2: %s, expecting %s", + Temp2->String.Pointer, ValueToWrite); + } + + /* Write back the original value */ + + WriteValue.String.Length = strlen (Temp1->String.Pointer); + WriteValue.String.Pointer = Temp1->String.Pointer; + + Status = AcpiDbWriteToObject (Node, &WriteValue); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Ensure that we can read back the original value */ + + Status = AcpiDbReadFromObject (Node, ACPI_TYPE_STRING, &Temp3); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (strcmp (Temp1->String.Pointer, Temp3->String.Pointer)) + { + AcpiOsPrintf (" MISMATCH 3: %s, expecting %s", + Temp3->String.Pointer, Temp1->String.Pointer); + } + +Exit: + if (Temp1) {AcpiOsFree (Temp1);} + if (Temp2) {AcpiOsFree (Temp2);} + if (Temp3) {AcpiOsFree (Temp3);} + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbReadFromObject + * + * PARAMETERS: Node - Parent NS node for the object + * ExpectedType - Object type expected from the read + * Value - Where the value read is returned + * + * RETURN: Status + * + * DESCRIPTION: Performs a read from the specified object by invoking the + * special debugger control method that reads the object. Thus, + * the AML interpreter is doing all of the work, increasing the + * validity of the test. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbReadFromObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE ExpectedType, + ACPI_OBJECT **Value) +{ + ACPI_OBJECT *RetValue; + ACPI_OBJECT_LIST ParamObjects; + ACPI_OBJECT Params[2]; + ACPI_BUFFER ReturnObj; + ACPI_STATUS Status; + + + Params[0].Type = ACPI_TYPE_LOCAL_REFERENCE; + Params[0].Reference.ActualType = Node->Type; + Params[0].Reference.Handle = ACPI_CAST_PTR (ACPI_HANDLE, Node); + + ParamObjects.Count = 1; + ParamObjects.Pointer = Params; + + ReturnObj.Length = ACPI_ALLOCATE_BUFFER; + + AcpiGbl_MethodExecuting = TRUE; + Status = AcpiEvaluateObject (ReadHandle, NULL, + &ParamObjects, &ReturnObj); + AcpiGbl_MethodExecuting = FALSE; + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not read from object, %s", + AcpiFormatException (Status)); + return (Status); + } + + RetValue = (ACPI_OBJECT *) ReturnObj.Pointer; + + switch (RetValue->Type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + /* + * Did we receive the type we wanted? Most important for the + * Integer/Buffer case (when a field is larger than an Integer, + * it should return a Buffer). + */ + if (RetValue->Type != ExpectedType) + { + AcpiOsPrintf (" Type mismatch: Expected %s, Received %s", + AcpiUtGetTypeName (ExpectedType), + AcpiUtGetTypeName (RetValue->Type)); + + return (AE_TYPE); + } + + *Value = RetValue; + break; + + default: + + AcpiOsPrintf (" Unsupported return object type, %s", + AcpiUtGetTypeName (RetValue->Type)); + + AcpiOsFree (ReturnObj.Pointer); + return (AE_TYPE); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbWriteToObject + * + * PARAMETERS: Node - Parent NS node for the object + * Value - Value to be written + * + * RETURN: Status + * + * DESCRIPTION: Performs a write to the specified object by invoking the + * special debugger control method that writes the object. Thus, + * the AML interpreter is doing all of the work, increasing the + * validity of the test. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbWriteToObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT *Value) +{ + ACPI_OBJECT_LIST ParamObjects; + ACPI_OBJECT Params[2]; + ACPI_STATUS Status; + + + Params[0].Type = ACPI_TYPE_LOCAL_REFERENCE; + Params[0].Reference.ActualType = Node->Type; + Params[0].Reference.Handle = ACPI_CAST_PTR (ACPI_HANDLE, Node); + + /* Copy the incoming user parameter */ + + memcpy (&Params[1], Value, sizeof (ACPI_OBJECT)); + + ParamObjects.Count = 2; + ParamObjects.Pointer = Params; + + AcpiGbl_MethodExecuting = TRUE; + Status = AcpiEvaluateObject (WriteHandle, NULL, &ParamObjects, NULL); + AcpiGbl_MethodExecuting = FALSE; + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not write to object, %s", + AcpiFormatException (Status)); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbEvaluateAllPredefinedNames + * + * PARAMETERS: CountArg - Max number of methods to execute + * + * RETURN: None + * + * DESCRIPTION: Namespace batch execution. Execute predefined names in the + * namespace, up to the max count, if specified. + * + ******************************************************************************/ + +static void +AcpiDbEvaluateAllPredefinedNames ( + char *CountArg) +{ + ACPI_DB_EXECUTE_WALK Info; + + + Info.Count = 0; + Info.MaxCount = ACPI_UINT32_MAX; + + if (CountArg) + { + Info.MaxCount = strtoul (CountArg, NULL, 0); + } + + /* Search all nodes in namespace */ + + (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiDbEvaluateOnePredefinedName, NULL, + (void *) &Info, NULL); + + AcpiOsPrintf ( + "Evaluated %u predefined names in the namespace\n", Info.Count); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbEvaluateOnePredefinedName + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Batch execution module. Currently only executes predefined + * ACPI names. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbEvaluateOnePredefinedName ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_DB_EXECUTE_WALK *Info = (ACPI_DB_EXECUTE_WALK *) Context; + char *Pathname; + const ACPI_PREDEFINED_INFO *Predefined; + ACPI_DEVICE_INFO *ObjInfo; + ACPI_OBJECT_LIST ParamObjects; + ACPI_OBJECT Params[ACPI_METHOD_NUM_ARGS]; + ACPI_OBJECT *ThisParam; + ACPI_BUFFER ReturnObj; + ACPI_STATUS Status; + UINT16 ArgTypeList; + UINT8 ArgCount; + UINT8 ArgType; + UINT32 i; + + + /* The name must be a predefined ACPI name */ + + Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii); + if (!Predefined) + { + return (AE_OK); + } + + if (Node->Type == ACPI_TYPE_LOCAL_SCOPE) + { + return (AE_OK); + } + + Pathname = AcpiNsGetNormalizedPathname (Node, TRUE); + if (!Pathname) + { + return (AE_OK); + } + + /* Get the object info for number of method parameters */ + + Status = AcpiGetObjectInfo (ObjHandle, &ObjInfo); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (Pathname); + return (Status); + } + + ParamObjects.Count = 0; + ParamObjects.Pointer = NULL; + + if (ObjInfo->Type == ACPI_TYPE_METHOD) + { + /* Setup default parameters (with proper types) */ + + ArgTypeList = Predefined->Info.ArgumentList; + ArgCount = METHOD_GET_ARG_COUNT (ArgTypeList); + + /* + * Setup the ACPI-required number of arguments, regardless of what + * the actual method defines. If there is a difference, then the + * method is wrong and a warning will be issued during execution. + */ + ThisParam = Params; + for (i = 0; i < ArgCount; i++) + { + ArgType = METHOD_GET_NEXT_TYPE (ArgTypeList); + ThisParam->Type = ArgType; + + switch (ArgType) + { + case ACPI_TYPE_INTEGER: + + ThisParam->Integer.Value = 1; + break; + + case ACPI_TYPE_STRING: + + ThisParam->String.Pointer = + "This is the default argument string"; + ThisParam->String.Length = + strlen (ThisParam->String.Pointer); + break; + + case ACPI_TYPE_BUFFER: + + ThisParam->Buffer.Pointer = (UINT8 *) Params; /* just a garbage buffer */ + ThisParam->Buffer.Length = 48; + break; + + case ACPI_TYPE_PACKAGE: + + ThisParam->Package.Elements = NULL; + ThisParam->Package.Count = 0; + break; + + default: + + AcpiOsPrintf ("%s: Unsupported argument type: %u\n", + Pathname, ArgType); + break; + } + + ThisParam++; + } + + ParamObjects.Count = ArgCount; + ParamObjects.Pointer = Params; + } + + ACPI_FREE (ObjInfo); + ReturnObj.Pointer = NULL; + ReturnObj.Length = ACPI_ALLOCATE_BUFFER; + + /* Do the actual method execution */ + + AcpiGbl_MethodExecuting = TRUE; + + Status = AcpiEvaluateObject (Node, NULL, &ParamObjects, &ReturnObj); + + AcpiOsPrintf ("%-32s returned %s\n", + Pathname, AcpiFormatException (Status)); + AcpiGbl_MethodExecuting = FALSE; + ACPI_FREE (Pathname); + + /* Ignore status from method execution */ + + Status = AE_OK; + + /* Update count, check if we have executed enough methods */ + + Info->Count++; + if (Info->Count >= Info->MaxCount) + { + Status = AE_CTRL_TERMINATE; + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/components/debugger/dbutils.c b/third_party/lib/acpica/source/components/debugger/dbutils.c new file mode 100644 index 000000000..4cabc8b18 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbutils.c @@ -0,0 +1,513 @@ +/******************************************************************************* + * + * Module Name: dbutils - AML debugger utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbutils") + + +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +ACPI_STATUS +AcpiDbSecondPassParse ( + ACPI_PARSE_OBJECT *Root); + +void +AcpiDbDumpBuffer ( + UINT32 Address); +#endif + +static char *Gbl_HexToAscii = "0123456789ABCDEF"; + + +/******************************************************************************* + * + * FUNCTION: AcpiDbMatchArgument + * + * PARAMETERS: UserArgument - User command line + * Arguments - Array of commands to match against + * + * RETURN: Index into command array or ACPI_TYPE_NOT_FOUND if not found + * + * DESCRIPTION: Search command array for a command match + * + ******************************************************************************/ + +ACPI_OBJECT_TYPE +AcpiDbMatchArgument ( + char *UserArgument, + ACPI_DB_ARGUMENT_INFO *Arguments) +{ + UINT32 i; + + + if (!UserArgument || UserArgument[0] == 0) + { + return (ACPI_TYPE_NOT_FOUND); + } + + for (i = 0; Arguments[i].Name; i++) + { + if (strstr (Arguments[i].Name, UserArgument) == Arguments[i].Name) + { + return (i); + } + } + + /* Argument not recognized */ + + return (ACPI_TYPE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSetOutputDestination + * + * PARAMETERS: OutputFlags - Current flags word + * + * RETURN: None + * + * DESCRIPTION: Set the current destination for debugger output. Also sets + * the debug output level accordingly. + * + ******************************************************************************/ + +void +AcpiDbSetOutputDestination ( + UINT32 OutputFlags) +{ + + AcpiGbl_DbOutputFlags = (UINT8) OutputFlags; + + if ((OutputFlags & ACPI_DB_REDIRECTABLE_OUTPUT) && + AcpiGbl_DbOutputToFile) + { + AcpiDbgLevel = AcpiGbl_DbDebugLevel; + } + else + { + AcpiDbgLevel = AcpiGbl_DbConsoleDebugLevel; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpExternalObject + * + * PARAMETERS: ObjDesc - External ACPI object to dump + * Level - Nesting level. + * + * RETURN: None + * + * DESCRIPTION: Dump the contents of an ACPI external object + * + ******************************************************************************/ + +void +AcpiDbDumpExternalObject ( + ACPI_OBJECT *ObjDesc, + UINT32 Level) +{ + UINT32 i; + + + if (!ObjDesc) + { + AcpiOsPrintf ("[Null Object]\n"); + return; + } + + for (i = 0; i < Level; i++) + { + AcpiOsPrintf (" "); + } + + switch (ObjDesc->Type) + { + case ACPI_TYPE_ANY: + + AcpiOsPrintf ("[Null Object] (Type=0)\n"); + break; + + case ACPI_TYPE_INTEGER: + + AcpiOsPrintf ("[Integer] = %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("[String] Length %.2X = ", ObjDesc->String.Length); + AcpiUtPrintString (ObjDesc->String.Pointer, ACPI_UINT8_MAX); + AcpiOsPrintf ("\n"); + break; + + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf ("[Buffer] Length %.2X = ", ObjDesc->Buffer.Length); + if (ObjDesc->Buffer.Length) + { + if (ObjDesc->Buffer.Length > 16) + { + AcpiOsPrintf ("\n"); + } + + AcpiUtDebugDumpBuffer ( + ACPI_CAST_PTR (UINT8, ObjDesc->Buffer.Pointer), + ObjDesc->Buffer.Length, DB_BYTE_DISPLAY, _COMPONENT); + } + else + { + AcpiOsPrintf ("\n"); + } + break; + + case ACPI_TYPE_PACKAGE: + + AcpiOsPrintf ("[Package] Contains %u Elements:\n", + ObjDesc->Package.Count); + + for (i = 0; i < ObjDesc->Package.Count; i++) + { + AcpiDbDumpExternalObject ( + &ObjDesc->Package.Elements[i], Level+1); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + AcpiOsPrintf ("[Object Reference] = "); + AcpiDbDisplayInternalObject (ObjDesc->Reference.Handle, NULL); + break; + + case ACPI_TYPE_PROCESSOR: + + AcpiOsPrintf ("[Processor]\n"); + break; + + case ACPI_TYPE_POWER: + + AcpiOsPrintf ("[Power Resource]\n"); + break; + + default: + + AcpiOsPrintf ("[Unknown Type] %X\n", ObjDesc->Type); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbPrepNamestring + * + * PARAMETERS: Name - String to prepare + * + * RETURN: None + * + * DESCRIPTION: Translate all forward slashes and dots to backslashes. + * + ******************************************************************************/ + +void +AcpiDbPrepNamestring ( + char *Name) +{ + + if (!Name) + { + return; + } + + AcpiUtStrupr (Name); + + /* Convert a leading forward slash to a backslash */ + + if (*Name == '/') + { + *Name = '\\'; + } + + /* Ignore a leading backslash, this is the root prefix */ + + if (ACPI_IS_ROOT_PREFIX (*Name)) + { + Name++; + } + + /* Convert all slash path separators to dots */ + + while (*Name) + { + if ((*Name == '/') || + (*Name == '\\')) + { + *Name = '.'; + } + + Name++; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbLocalNsLookup + * + * PARAMETERS: Name - Name to lookup + * + * RETURN: Pointer to a namespace node, null on failure + * + * DESCRIPTION: Lookup a name in the ACPI namespace + * + * Note: Currently begins search from the root. Could be enhanced to use + * the current prefix (scope) node as the search beginning point. + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +AcpiDbLocalNsLookup ( + char *Name) +{ + char *InternalPath; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node = NULL; + + + AcpiDbPrepNamestring (Name); + + /* Build an internal namestring */ + + Status = AcpiNsInternalizeName (Name, &InternalPath); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Invalid namestring: %s\n", Name); + return (NULL); + } + + /* + * Lookup the name. + * (Uses root node as the search starting point) + */ + Status = AcpiNsLookup (NULL, InternalPath, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &Node); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not locate name: %s, %s\n", + Name, AcpiFormatException (Status)); + } + + ACPI_FREE (InternalPath); + return (Node); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbUint32ToHexString + * + * PARAMETERS: Value - The value to be converted to string + * Buffer - Buffer for result (not less than 11 bytes) + * + * RETURN: None + * + * DESCRIPTION: Convert the unsigned 32-bit value to the hexadecimal image + * + * NOTE: It is the caller's responsibility to ensure that the length of buffer + * is sufficient. + * + ******************************************************************************/ + +void +AcpiDbUint32ToHexString ( + UINT32 Value, + char *Buffer) +{ + int i; + + + if (Value == 0) + { + strcpy (Buffer, "0"); + return; + } + + Buffer[8] = '\0'; + + for (i = 7; i >= 0; i--) + { + Buffer[i] = Gbl_HexToAscii [Value & 0x0F]; + Value = Value >> 4; + } +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: AcpiDbSecondPassParse + * + * PARAMETERS: Root - Root of the parse tree + * + * RETURN: Status + * + * DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until + * second pass to parse the control methods + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbSecondPassParse ( + ACPI_PARSE_OBJECT *Root) +{ + ACPI_PARSE_OBJECT *Op = Root; + ACPI_PARSE_OBJECT *Method; + ACPI_PARSE_OBJECT *SearchOp; + ACPI_PARSE_OBJECT *StartOp; + ACPI_STATUS Status = AE_OK; + UINT32 BaseAmlOffset; + ACPI_WALK_STATE *WalkState; + + + ACPI_FUNCTION_ENTRY (); + + + AcpiOsPrintf ("Pass two parse ....\n"); + + while (Op) + { + if (Op->Common.AmlOpcode == AML_METHOD_OP) + { + Method = Op; + + /* Create a new walk state for the parse */ + + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + if (!WalkState) + { + return (AE_NO_MEMORY); + } + + /* Init the Walk State */ + + WalkState->ParserState.Aml = + WalkState->ParserState.AmlStart = Method->Named.Data; + WalkState->ParserState.AmlEnd = + WalkState->ParserState.PkgEnd = Method->Named.Data + + Method->Named.Length; + WalkState->ParserState.StartScope = Op; + + WalkState->DescendingCallback = AcpiDsLoad1BeginOp; + WalkState->AscendingCallback = AcpiDsLoad1EndOp; + + /* Perform the AML parse */ + + Status = AcpiPsParseAml (WalkState); + + BaseAmlOffset = (Method->Common.Value.Arg)->Common.AmlOffset + 1; + StartOp = (Method->Common.Value.Arg)->Common.Next; + SearchOp = StartOp; + + while (SearchOp) + { + SearchOp->Common.AmlOffset += BaseAmlOffset; + SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp); + } + } + + if (Op->Common.AmlOpcode == AML_REGION_OP) + { + /* TBD: [Investigate] this isn't quite the right thing to do! */ + /* + * + * Method = (ACPI_DEFERRED_OP *) Op; + * Status = AcpiPsParseAml (Op, Method->Body, Method->BodyLength); + */ + } + + if (ACPI_FAILURE (Status)) + { + break; + } + + Op = AcpiPsGetDepthNext (Root, Op); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbDumpBuffer + * + * PARAMETERS: Address - Pointer to the buffer + * + * RETURN: None + * + * DESCRIPTION: Print a portion of a buffer + * + ******************************************************************************/ + +void +AcpiDbDumpBuffer ( + UINT32 Address) +{ + + AcpiOsPrintf ("\nLocation %X:\n", Address); + + AcpiDbgLevel |= ACPI_LV_TABLES; + AcpiUtDebugDumpBuffer (ACPI_TO_POINTER (Address), 64, DB_BYTE_DISPLAY, + ACPI_UINT32_MAX); +} +#endif diff --git a/third_party/lib/acpica/source/components/debugger/dbxface.c b/third_party/lib/acpica/source/components/debugger/dbxface.c new file mode 100644 index 000000000..7fdd2a145 --- /dev/null +++ b/third_party/lib/acpica/source/components/debugger/dbxface.c @@ -0,0 +1,602 @@ +/******************************************************************************* + * + * Module Name: dbxface - AML Debugger external interfaces + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbxface") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDbStartCommand ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +void +AcpiDbMethodEnd ( + ACPI_WALK_STATE *WalkState); +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDbStartCommand + * + * PARAMETERS: WalkState - Current walk + * Op - Current executing Op, from AML interpreter + * + * RETURN: Status + * + * DESCRIPTION: Enter debugger command loop + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDbStartCommand ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + + + /* TBD: [Investigate] are there namespace locking issues here? */ + + /* AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); */ + + /* Go into the command loop and await next user command */ + + + AcpiGbl_MethodExecuting = TRUE; + Status = AE_CTRL_TRUE; + while (Status == AE_CTRL_TRUE) + { + if (AcpiGbl_DebuggerConfiguration == DEBUGGER_MULTI_THREADED) + { + /* Handshake with the front-end that gets user command lines */ + + AcpiOsReleaseMutex (AcpiGbl_DbCommandComplete); + + Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandReady, + ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* Single threaded, we must get a command line ourselves */ + + /* Force output to console until a command is entered */ + + AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); + + /* Different prompt if method is executing */ + + if (!AcpiGbl_MethodExecuting) + { + AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); + } + else + { + AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); + } + + /* Get the user input line */ + + Status = AcpiOsGetLine (AcpiGbl_DbLineBuf, + ACPI_DB_LINE_BUFFER_SIZE, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While parsing command line")); + return (Status); + } + } + + Status = AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, WalkState, Op); + } + + /* AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); */ + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSignalBreakPoint + * + * PARAMETERS: WalkState - Current walk + * + * RETURN: Status + * + * DESCRIPTION: Called for AML_BREAK_POINT_OP + * + ******************************************************************************/ + +void +AcpiDbSignalBreakPoint ( + ACPI_WALK_STATE *WalkState) +{ + +#ifndef ACPI_APPLICATION + if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ()) + { + return; + } +#endif + + /* + * Set the single-step flag. This will cause the debugger (if present) + * to break to the console within the AML debugger at the start of the + * next AML instruction. + */ + AcpiGbl_CmSingleStep = TRUE; + AcpiOsPrintf ("**break** Executed AML BreakPoint opcode\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDbSingleStep + * + * PARAMETERS: WalkState - Current walk + * Op - Current executing op (from aml interpreter) + * OpcodeClass - Class of the current AML Opcode + * + * RETURN: Status + * + * DESCRIPTION: Called just before execution of an AML opcode. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDbSingleStep ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 OpcodeClass) +{ + ACPI_PARSE_OBJECT *Next; + ACPI_STATUS Status = AE_OK; + UINT32 OriginalDebugLevel; + ACPI_PARSE_OBJECT *DisplayOp; + ACPI_PARSE_OBJECT *ParentOp; + UINT32 AmlOffset; + + + ACPI_FUNCTION_ENTRY (); + + +#ifndef ACPI_APPLICATION + if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ()) + { + return (AE_OK); + } +#endif + + /* Check the abort flag */ + + if (AcpiGbl_AbortMethod) + { + AcpiGbl_AbortMethod = FALSE; + return (AE_ABORT_METHOD); + } + + AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml, + WalkState->ParserState.AmlStart); + + /* Check for single-step breakpoint */ + + if (WalkState->MethodBreakpoint && + (WalkState->MethodBreakpoint <= AmlOffset)) + { + /* Check if the breakpoint has been reached or passed */ + /* Hit the breakpoint, resume single step, reset breakpoint */ + + AcpiOsPrintf ("***Break*** at AML offset %X\n", AmlOffset); + AcpiGbl_CmSingleStep = TRUE; + AcpiGbl_StepToNextCall = FALSE; + WalkState->MethodBreakpoint = 0; + } + + /* Check for user breakpoint (Must be on exact Aml offset) */ + + else if (WalkState->UserBreakpoint && + (WalkState->UserBreakpoint == AmlOffset)) + { + AcpiOsPrintf ("***UserBreakpoint*** at AML offset %X\n", + AmlOffset); + AcpiGbl_CmSingleStep = TRUE; + AcpiGbl_StepToNextCall = FALSE; + WalkState->MethodBreakpoint = 0; + } + + /* + * Check if this is an opcode that we are interested in -- + * namely, opcodes that have arguments + */ + if (Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) + { + return (AE_OK); + } + + switch (OpcodeClass) + { + case AML_CLASS_UNKNOWN: + case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ + + return (AE_OK); + + default: + + /* All other opcodes -- continue */ + break; + } + + /* + * Under certain debug conditions, display this opcode and its operands + */ + if ((AcpiGbl_DbOutputToFile) || + (AcpiGbl_CmSingleStep) || + (AcpiDbgLevel & ACPI_LV_PARSE)) + { + if ((AcpiGbl_DbOutputToFile) || + (AcpiDbgLevel & ACPI_LV_PARSE)) + { + AcpiOsPrintf ("\n[AmlDebug] Next AML Opcode to execute:\n"); + } + + /* + * Display this op (and only this op - zero out the NEXT field + * temporarily, and disable parser trace output for the duration of + * the display because we don't want the extraneous debug output) + */ + OriginalDebugLevel = AcpiDbgLevel; + AcpiDbgLevel &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS); + Next = Op->Common.Next; + Op->Common.Next = NULL; + + + DisplayOp = Op; + ParentOp = Op->Common.Parent; + if (ParentOp) + { + if ((WalkState->ControlState) && + (WalkState->ControlState->Common.State == + ACPI_CONTROL_PREDICATE_EXECUTING)) + { + /* + * We are executing the predicate of an IF or WHILE statement + * Search upwards for the containing IF or WHILE so that the + * entire predicate can be displayed. + */ + while (ParentOp) + { + if ((ParentOp->Common.AmlOpcode == AML_IF_OP) || + (ParentOp->Common.AmlOpcode == AML_WHILE_OP)) + { + DisplayOp = ParentOp; + break; + } + ParentOp = ParentOp->Common.Parent; + } + } + else + { + while (ParentOp) + { + if ((ParentOp->Common.AmlOpcode == AML_IF_OP) || + (ParentOp->Common.AmlOpcode == AML_ELSE_OP) || + (ParentOp->Common.AmlOpcode == AML_SCOPE_OP) || + (ParentOp->Common.AmlOpcode == AML_METHOD_OP) || + (ParentOp->Common.AmlOpcode == AML_WHILE_OP)) + { + break; + } + DisplayOp = ParentOp; + ParentOp = ParentOp->Common.Parent; + } + } + } + + /* Now we can display it */ + +#ifdef ACPI_DISASSEMBLER + AcpiDmDisassemble (WalkState, DisplayOp, ACPI_UINT32_MAX); +#endif + + if ((Op->Common.AmlOpcode == AML_IF_OP) || + (Op->Common.AmlOpcode == AML_WHILE_OP)) + { + if (WalkState->ControlState->Common.Value) + { + AcpiOsPrintf ("Predicate = [True], IF block was executed\n"); + } + else + { + AcpiOsPrintf ("Predicate = [False], Skipping IF block\n"); + } + } + else if (Op->Common.AmlOpcode == AML_ELSE_OP) + { + AcpiOsPrintf ("Predicate = [False], ELSE block was executed\n"); + } + + /* Restore everything */ + + Op->Common.Next = Next; + AcpiOsPrintf ("\n"); + if ((AcpiGbl_DbOutputToFile) || + (AcpiDbgLevel & ACPI_LV_PARSE)) + { + AcpiOsPrintf ("\n"); + } + AcpiDbgLevel = OriginalDebugLevel; + } + + /* If we are not single stepping, just continue executing the method */ + + if (!AcpiGbl_CmSingleStep) + { + return (AE_OK); + } + + /* + * If we are executing a step-to-call command, + * Check if this is a method call. + */ + if (AcpiGbl_StepToNextCall) + { + if (Op->Common.AmlOpcode != AML_INT_METHODCALL_OP) + { + /* Not a method call, just keep executing */ + + return (AE_OK); + } + + /* Found a method call, stop executing */ + + AcpiGbl_StepToNextCall = FALSE; + } + + /* + * If the next opcode is a method call, we will "step over" it + * by default. + */ + if (Op->Common.AmlOpcode == AML_INT_METHODCALL_OP) + { + /* Force no more single stepping while executing called method */ + + AcpiGbl_CmSingleStep = FALSE; + + /* + * Set the breakpoint on/before the call, it will stop execution + * as soon as we return + */ + WalkState->MethodBreakpoint = 1; /* Must be non-zero! */ + } + + + Status = AcpiDbStartCommand (WalkState, Op); + + /* User commands complete, continue execution of the interrupted method */ + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiInitializeDebugger + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Init and start debugger + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInitializeDebugger ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInitializeDebugger); + + + /* Init globals */ + + AcpiGbl_DbBuffer = NULL; + AcpiGbl_DbFilename = NULL; + AcpiGbl_DbOutputToFile = FALSE; + + AcpiGbl_DbDebugLevel = ACPI_LV_VERBOSITY2; + AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; + AcpiGbl_DbOutputFlags = ACPI_DB_CONSOLE_OUTPUT; + + AcpiGbl_DbOpt_NoIniMethods = FALSE; + + AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE); + if (!AcpiGbl_DbBuffer) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE); + + /* Initial scope is the root */ + + AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX; + AcpiGbl_DbScopeBuf [1] = 0; + AcpiGbl_DbScopeNode = AcpiGbl_RootNode; + + /* Initialize user commands loop */ + + AcpiGbl_DbTerminateLoop = FALSE; + + /* + * If configured for multi-thread support, the debug executor runs in + * a separate thread so that the front end can be in another address + * space, environment, or even another machine. + */ + if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) + { + /* These were created with one unit, grab it */ + + Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandComplete, + ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not get debugger mutex\n"); + return_ACPI_STATUS (Status); + } + + Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandReady, + ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not get debugger mutex\n"); + return_ACPI_STATUS (Status); + } + + /* Create the debug execution thread to execute commands */ + + AcpiGbl_DbThreadsTerminated = FALSE; + Status = AcpiOsExecute (OSL_DEBUGGER_MAIN_THREAD, + AcpiDbExecuteThread, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not start debugger thread")); + AcpiGbl_DbThreadsTerminated = TRUE; + return_ACPI_STATUS (Status); + } + } + else + { + AcpiGbl_DbThreadId = AcpiOsGetThreadId (); + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiInitializeDebugger) + + +/******************************************************************************* + * + * FUNCTION: AcpiTerminateDebugger + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Stop debugger + * + ******************************************************************************/ + +void +AcpiTerminateDebugger ( + void) +{ + + /* Terminate the AML Debugger */ + + AcpiGbl_DbTerminateLoop = TRUE; + + if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) + { + AcpiOsReleaseMutex (AcpiGbl_DbCommandReady); + + /* Wait the AML Debugger threads */ + + while (!AcpiGbl_DbThreadsTerminated) + { + AcpiOsSleep (100); + } + } + + if (AcpiGbl_DbBuffer) + { + AcpiOsFree (AcpiGbl_DbBuffer); + AcpiGbl_DbBuffer = NULL; + } + + /* Ensure that debug output is now disabled */ + + AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT; +} + +ACPI_EXPORT_SYMBOL (AcpiTerminateDebugger) + + +/******************************************************************************* + * + * FUNCTION: AcpiSetDebuggerThreadId + * + * PARAMETERS: ThreadId - Debugger thread ID + * + * RETURN: None + * + * DESCRIPTION: Set debugger thread ID + * + ******************************************************************************/ + +void +AcpiSetDebuggerThreadId ( + ACPI_THREAD_ID ThreadId) +{ + AcpiGbl_DbThreadId = ThreadId; +} + +ACPI_EXPORT_SYMBOL (AcpiSetDebuggerThreadId) diff --git a/third_party/lib/acpica/source/components/disassembler/dmbuffer.c b/third_party/lib/acpica/source/components/disassembler/dmbuffer.c new file mode 100644 index 000000000..f8fdbaa5d --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmbuffer.c @@ -0,0 +1,1032 @@ +/******************************************************************************* + * + * Module Name: dmbuffer - AML disassembler, buffer and string support + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acutils.h" +#include "acdisasm.h" +#include "acparser.h" +#include "amlcode.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dmbuffer") + +/* Local prototypes */ + +static void +AcpiDmUuid ( + ACPI_PARSE_OBJECT *Op); + +static void +AcpiDmUnicode ( + ACPI_PARSE_OBJECT *Op); + +static void +AcpiDmGetHardwareIdType ( + ACPI_PARSE_OBJECT *Op); + +static void +AcpiDmPldBuffer ( + UINT32 Level, + UINT8 *ByteData, + UINT32 ByteCount); + + +#define ACPI_BUFFER_BYTES_PER_LINE 8 + + +/* Strings for ToPld */ + +static char *DmPanelList[] = +{ + "TOP", + "BOTTOM", + "LEFT", + "RIGHT", + "FRONT", + "BACK", + "UNKNOWN", + NULL +}; + +static char *DmVerticalPositionList[] = +{ + "UPPER", + "CENTER", + "LOWER", + NULL +}; + +static char *DmHorizontalPositionList[] = +{ + "LEFT", + "CENTER", + "RIGHT", + NULL +}; + +static char *DmShapeList[] = +{ + "ROUND", + "OVAL", + "SQUARE", + "VERTICALRECTANGLE", + "HORIZONTALRECTANGLE", + "VERTICALTRAPEZOID", + "HORIZONTALTRAPEZOID", + "UNKNOWN", + "CHAMFERED", + NULL +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDisasmByteList + * + * PARAMETERS: Level - Current source code indentation level + * ByteData - Pointer to the byte list + * ByteCount - Length of the byte list + * + * RETURN: None + * + * DESCRIPTION: Dump an AML "ByteList" in Hex format. 8 bytes per line, prefixed + * with the hex buffer offset. + * + ******************************************************************************/ + +void +AcpiDmDisasmByteList ( + UINT32 Level, + UINT8 *ByteData, + UINT32 ByteCount) +{ + UINT32 i; + UINT32 j; + UINT32 CurrentIndex; + UINT8 BufChar; + + + if (!ByteCount) + { + return; + } + + for (i = 0; i < ByteCount; i += ACPI_BUFFER_BYTES_PER_LINE) + { + /* Line indent and offset prefix for each new line */ + + AcpiDmIndent (Level); + if (ByteCount > ACPI_BUFFER_BYTES_PER_LINE) + { + AcpiOsPrintf ("/* %04X */ ", i); + } + + /* Dump the actual hex values */ + + for (j = 0; j < ACPI_BUFFER_BYTES_PER_LINE; j++) + { + CurrentIndex = i + j; + if (CurrentIndex >= ByteCount) + { + /* Dump fill spaces */ + + AcpiOsPrintf (" "); + continue; + } + + AcpiOsPrintf (" 0x%2.2X", ByteData[CurrentIndex]); + + /* Add comma if there are more bytes to display */ + + if (CurrentIndex < (ByteCount - 1)) + { + AcpiOsPrintf (","); + } + else + { + AcpiOsPrintf (" "); + } + } + + /* Dump the ASCII equivalents within a comment */ + + AcpiOsPrintf (" /* "); + for (j = 0; j < ACPI_BUFFER_BYTES_PER_LINE; j++) + { + CurrentIndex = i + j; + if (CurrentIndex >= ByteCount) + { + break; + } + + BufChar = ByteData[CurrentIndex]; + if (isprint (BufChar)) + { + AcpiOsPrintf ("%c", BufChar); + } + else + { + AcpiOsPrintf ("."); + } + } + + /* Finished with this line */ + + AcpiOsPrintf (" */\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmByteList + * + * PARAMETERS: Info - Parse tree walk info + * Op - Byte list op + * + * RETURN: None + * + * DESCRIPTION: Dump a buffer byte list, handling the various types of buffers. + * Buffer type must be already set in the Op DisasmOpcode. + * + ******************************************************************************/ + +void +AcpiDmByteList ( + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op) +{ + UINT8 *ByteData; + UINT32 ByteCount; + + + ByteData = Op->Named.Data; + ByteCount = (UINT32) Op->Common.Value.Integer; + + /* + * The byte list belongs to a buffer, and can be produced by either + * a ResourceTemplate, Unicode, quoted string, or a plain byte list. + */ + switch (Op->Common.Parent->Common.DisasmOpcode) + { + case ACPI_DASM_RESOURCE: + + AcpiDmResourceTemplate ( + Info, Op->Common.Parent, ByteData, ByteCount); + break; + + case ACPI_DASM_STRING: + + AcpiDmIndent (Info->Level); + AcpiUtPrintString ((char *) ByteData, ACPI_UINT16_MAX); + AcpiOsPrintf ("\n"); + break; + + case ACPI_DASM_UUID: + + AcpiDmUuid (Op); + break; + + case ACPI_DASM_UNICODE: + + AcpiDmUnicode (Op); + break; + + case ACPI_DASM_PLD_METHOD: +#if 0 + AcpiDmDisasmByteList (Info->Level, ByteData, ByteCount); +#endif + AcpiDmPldBuffer (Info->Level, ByteData, ByteCount); + break; + + case ACPI_DASM_BUFFER: + default: + /* + * Not a resource, string, or unicode string. + * Just dump the buffer + */ + AcpiDmDisasmByteList (Info->Level, ByteData, ByteCount); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsUuidBuffer + * + * PARAMETERS: Op - Buffer Object to be examined + * + * RETURN: TRUE if buffer contains a UUID + * + * DESCRIPTION: Determine if a buffer Op contains a UUID + * + * To help determine whether the buffer is a UUID versus a raw data buffer, + * there a are a couple bytes we can look at: + * + * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx + * + * The variant covered by the UUID specification is indicated by the two most + * significant bits of N being 1 0 (i.e., the hexadecimal N will always be + * 8, 9, A, or B). + * + * The variant covered by the UUID specification has five versions. For this + * variant, the four bits of M indicates the UUID version (i.e., the + * hexadecimal M will be either 1, 2, 3, 4, or 5). + * + ******************************************************************************/ + +BOOLEAN +AcpiDmIsUuidBuffer ( + ACPI_PARSE_OBJECT *Op) +{ + UINT8 *ByteData; + UINT32 ByteCount; + ACPI_PARSE_OBJECT *SizeOp; + ACPI_PARSE_OBJECT *NextOp; + + + /* Buffer size is the buffer argument */ + + SizeOp = Op->Common.Value.Arg; + + /* Next, the initializer byte list to examine */ + + NextOp = SizeOp->Common.Next; + if (!NextOp) + { + return (FALSE); + } + + /* Extract the byte list info */ + + ByteData = NextOp->Named.Data; + ByteCount = (UINT32) NextOp->Common.Value.Integer; + + /* Byte count must be exactly 16 */ + + if (ByteCount != UUID_BUFFER_LENGTH) + { + return (FALSE); + } + + /* Check for valid "M" and "N" values (see function header above) */ + + if (((ByteData[7] & 0xF0) == 0x00) || /* M={1,2,3,4,5} */ + ((ByteData[7] & 0xF0) > 0x50) || + ((ByteData[8] & 0xF0) < 0x80) || /* N={8,9,A,B} */ + ((ByteData[8] & 0xF0) > 0xB0)) + { + return (FALSE); + } + + /* Ignore the Size argument in the disassembly of this buffer op */ + + SizeOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmUuid + * + * PARAMETERS: Op - Byte List op containing a UUID + * + * RETURN: None + * + * DESCRIPTION: Dump a buffer containing a UUID as a standard ASCII string. + * + * Output Format: + * In its canonical form, the UUID is represented by a string containing 32 + * lowercase hexadecimal digits, displayed in 5 groups separated by hyphens. + * The complete form is 8-4-4-4-12 for a total of 36 characters (32 + * alphanumeric characters representing hex digits and 4 hyphens). In bytes, + * 4-2-2-2-6. Example: + * + * ToUUID ("107ededd-d381-4fd7-8da9-08e9a6c79644") + * + ******************************************************************************/ + +static void +AcpiDmUuid ( + ACPI_PARSE_OBJECT *Op) +{ + UINT8 *Data; + const char *Description; + + + Data = ACPI_CAST_PTR (UINT8, Op->Named.Data); + + /* Emit the 36-byte UUID string in the proper format/order */ + + AcpiOsPrintf ( + "\"%2.2x%2.2x%2.2x%2.2x-" + "%2.2x%2.2x-" + "%2.2x%2.2x-" + "%2.2x%2.2x-" + "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\")", + Data[3], Data[2], Data[1], Data[0], + Data[5], Data[4], + Data[7], Data[6], + Data[8], Data[9], + Data[10], Data[11], Data[12], Data[13], Data[14], Data[15]); + + /* Dump the UUID description string if available */ + + Description = AcpiAhMatchUuid (Data); + if (Description) + { + AcpiOsPrintf (" /* %s */", Description); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsUnicodeBuffer + * + * PARAMETERS: Op - Buffer Object to be examined + * + * RETURN: TRUE if buffer contains a UNICODE string + * + * DESCRIPTION: Determine if a buffer Op contains a Unicode string + * + ******************************************************************************/ + +BOOLEAN +AcpiDmIsUnicodeBuffer ( + ACPI_PARSE_OBJECT *Op) +{ + UINT8 *ByteData; + UINT32 ByteCount; + UINT32 WordCount; + ACPI_PARSE_OBJECT *SizeOp; + ACPI_PARSE_OBJECT *NextOp; + UINT32 i; + + + /* Buffer size is the buffer argument */ + + SizeOp = Op->Common.Value.Arg; + + /* Next, the initializer byte list to examine */ + + NextOp = SizeOp->Common.Next; + if (!NextOp) + { + return (FALSE); + } + + /* Extract the byte list info */ + + ByteData = NextOp->Named.Data; + ByteCount = (UINT32) NextOp->Common.Value.Integer; + WordCount = ACPI_DIV_2 (ByteCount); + + /* + * Unicode string must have an even number of bytes and last + * word must be zero + */ + if ((!ByteCount) || + (ByteCount < 4) || + (ByteCount & 1) || + ((UINT16 *) (void *) ByteData)[WordCount - 1] != 0) + { + return (FALSE); + } + + /* For each word, 1st byte must be ascii (1-0x7F), 2nd byte must be zero */ + + for (i = 0; i < (ByteCount - 2); i += 2) + { + if ((ByteData[i] == 0) || + (ByteData[i] > 0x7F) || + (ByteData[(ACPI_SIZE) i + 1] != 0)) + { + return (FALSE); + } + } + + /* Ignore the Size argument in the disassembly of this buffer op */ + + SizeOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsStringBuffer + * + * PARAMETERS: Op - Buffer Object to be examined + * + * RETURN: TRUE if buffer contains a ASCII string, FALSE otherwise + * + * DESCRIPTION: Determine if a buffer Op contains a ASCII string + * + ******************************************************************************/ + +BOOLEAN +AcpiDmIsStringBuffer ( + ACPI_PARSE_OBJECT *Op) +{ + UINT8 *ByteData; + UINT32 ByteCount; + ACPI_PARSE_OBJECT *SizeOp; + ACPI_PARSE_OBJECT *NextOp; + UINT32 i; + + + /* Buffer size is the buffer argument */ + + SizeOp = Op->Common.Value.Arg; + + /* Next, the initializer byte list to examine */ + + NextOp = SizeOp->Common.Next; + if (!NextOp) + { + return (FALSE); + } + + /* Extract the byte list info */ + + ByteData = NextOp->Named.Data; + ByteCount = (UINT32) NextOp->Common.Value.Integer; + + /* Last byte must be the null terminator */ + + if ((!ByteCount) || + (ByteCount < 2) || + (ByteData[ByteCount-1] != 0)) + { + return (FALSE); + } + + for (i = 0; i < (ByteCount - 1); i++) + { + /* TBD: allow some escapes (non-ascii chars). + * they will be handled in the string output routine + */ + + if (!isprint (ByteData[i])) + { + return (FALSE); + } + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsPldBuffer + * + * PARAMETERS: Op - Buffer Object to be examined + * + * RETURN: TRUE if buffer contains a ASCII string, FALSE otherwise + * + * DESCRIPTION: Determine if a buffer Op contains a _PLD structure + * + ******************************************************************************/ + +BOOLEAN +AcpiDmIsPldBuffer ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *SizeOp; + ACPI_PARSE_OBJECT *ParentOp; + + + /* Buffer size is the buffer argument */ + + SizeOp = Op->Common.Value.Arg; + + ParentOp = Op->Common.Parent; + if (!ParentOp) + { + return (FALSE); + } + + /* Check for form: Name(_PLD, Buffer() {}). Not legal, however */ + + if (ParentOp->Common.AmlOpcode == AML_NAME_OP) + { + Node = ParentOp->Common.Node; + + if (ACPI_COMPARE_NAME (Node->Name.Ascii, METHOD_NAME__PLD)) + { + /* Ignore the Size argument in the disassembly of this buffer op */ + + SizeOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + return (TRUE); + } + + return (FALSE); + } + + /* Check for proper form: Name(_PLD, Package() {Buffer() {}}) */ + + if (ParentOp->Common.AmlOpcode == AML_PACKAGE_OP) + { + ParentOp = ParentOp->Common.Parent; + if (!ParentOp) + { + return (FALSE); + } + + if (ParentOp->Common.AmlOpcode == AML_NAME_OP) + { + Node = ParentOp->Common.Node; + + if (ACPI_COMPARE_NAME (Node->Name.Ascii, METHOD_NAME__PLD)) + { + /* Ignore the Size argument in the disassembly of this buffer op */ + + SizeOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + return (TRUE); + } + } + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFindNameByIndex + * + * PARAMETERS: Index - Index of array to check + * List - Array to reference + * + * RETURN: String from List or empty string + * + * DESCRIPTION: Finds and returns the char string located at the given index + * position in List. + * + ******************************************************************************/ + +static char * +AcpiDmFindNameByIndex ( + UINT64 Index, + char **List) +{ + char *Str; + UINT32 i; + + + /* Bounds check */ + + Str = List[0]; + i = 0; + + while(Str) + { + i++; + Str = List[i]; + } + + if (Index >= i) + { + /* TBD: Add error msg */ + + return (""); + } + + return (List[Index]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmPldBuffer + * + * PARAMETERS: Level - Current source code indentation level + * ByteData - Pointer to the byte list + * ByteCount - Length of the byte list + * + * RETURN: None + * + * DESCRIPTION: Dump and format the contents of a _PLD buffer object + * + ******************************************************************************/ + +#define ACPI_PLD_OUTPUT08 "%*.s%-18s = 0x%X,\n", ACPI_MUL_4 (Level), " " +#define ACPI_PLD_OUTPUT08P "%*.s%-18s = 0x%X)\n", ACPI_MUL_4 (Level), " " +#define ACPI_PLD_OUTPUT16 "%*.s%-18s = 0x%X,\n", ACPI_MUL_4 (Level), " " +#define ACPI_PLD_OUTPUT16P "%*.s%-18s = 0x%X)\n", ACPI_MUL_4 (Level), " " +#define ACPI_PLD_OUTPUT24 "%*.s%-18s = 0x%X,\n", ACPI_MUL_4 (Level), " " +#define ACPI_PLD_OUTPUTSTR "%*.s%-18s = \"%s\",\n", ACPI_MUL_4 (Level), " " + +static void +AcpiDmPldBuffer ( + UINT32 Level, + UINT8 *ByteData, + UINT32 ByteCount) +{ + ACPI_PLD_INFO *PldInfo; + ACPI_STATUS Status; + + + /* Check for valid byte count */ + + if (ByteCount < ACPI_PLD_REV1_BUFFER_SIZE) + { + return; + } + + /* Convert _PLD buffer to local _PLD struct */ + + Status = AcpiDecodePldBuffer (ByteData, ByteCount, &PldInfo); + if (ACPI_FAILURE (Status)) + { + return; + } + + AcpiOsPrintf ("\n"); + + /* First 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Revision", PldInfo->Revision); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_IgnoreColor", PldInfo->IgnoreColor); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Red", PldInfo->Red); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Green", PldInfo->Green); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Blue", PldInfo->Blue); + + /* Second 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT16, "PLD_Width", PldInfo->Width); + AcpiOsPrintf (ACPI_PLD_OUTPUT16, "PLD_Height", PldInfo->Height); + + /* Third 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_UserVisible", PldInfo->UserVisible); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Dock", PldInfo->Dock); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Lid", PldInfo->Lid); + AcpiOsPrintf (ACPI_PLD_OUTPUTSTR, "PLD_Panel", + AcpiDmFindNameByIndex(PldInfo->Panel, DmPanelList)); + + AcpiOsPrintf (ACPI_PLD_OUTPUTSTR, "PLD_VerticalPosition", + AcpiDmFindNameByIndex(PldInfo->VerticalPosition, DmVerticalPositionList)); + + AcpiOsPrintf (ACPI_PLD_OUTPUTSTR, "PLD_HorizontalPosition", + AcpiDmFindNameByIndex(PldInfo->HorizontalPosition, DmHorizontalPositionList)); + + AcpiOsPrintf (ACPI_PLD_OUTPUTSTR, "PLD_Shape", + AcpiDmFindNameByIndex(PldInfo->Shape, DmShapeList)); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_GroupOrientation", PldInfo->GroupOrientation); + + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_GroupToken", PldInfo->GroupToken); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_GroupPosition", PldInfo->GroupPosition); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Bay", PldInfo->Bay); + + /* Fourth 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Ejectable", PldInfo->Ejectable); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_EjectRequired", PldInfo->OspmEjectRequired); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_CabinetNumber", PldInfo->CabinetNumber); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_CardCageNumber", PldInfo->CardCageNumber); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Reference", PldInfo->Reference); + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Rotation", PldInfo->Rotation); + + if (ByteCount >= ACPI_PLD_REV2_BUFFER_SIZE) + { + AcpiOsPrintf (ACPI_PLD_OUTPUT08, "PLD_Order", PldInfo->Order); + + /* Fifth 32-bit dword */ + + AcpiOsPrintf (ACPI_PLD_OUTPUT16, "PLD_VerticalOffset", PldInfo->VerticalOffset); + AcpiOsPrintf (ACPI_PLD_OUTPUT16P, "PLD_HorizontalOffset", PldInfo->HorizontalOffset); + } + else /* Rev 1 buffer */ + { + AcpiOsPrintf (ACPI_PLD_OUTPUT08P, "PLD_Order", PldInfo->Order); + } + + ACPI_FREE (PldInfo); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmUnicode + * + * PARAMETERS: Op - Byte List op containing Unicode string + * + * RETURN: None + * + * DESCRIPTION: Dump Unicode string as a standard ASCII string. (Remove + * the extra zero bytes). + * + ******************************************************************************/ + +static void +AcpiDmUnicode ( + ACPI_PARSE_OBJECT *Op) +{ + UINT16 *WordData; + UINT32 WordCount; + UINT32 i; + int OutputValue; + + + /* Extract the buffer info as a WORD buffer */ + + WordData = ACPI_CAST_PTR (UINT16, Op->Named.Data); + WordCount = ACPI_DIV_2 (((UINT32) Op->Common.Value.Integer)); + + /* Write every other byte as an ASCII character */ + + AcpiOsPrintf ("\""); + for (i = 0; i < (WordCount - 1); i++) + { + OutputValue = (int) WordData[i]; + + /* Handle values that must be escaped */ + + if ((OutputValue == '\"') || + (OutputValue == '\\')) + { + AcpiOsPrintf ("\\%c", OutputValue); + } + else if (!isprint (OutputValue)) + { + AcpiOsPrintf ("\\x%2.2X", OutputValue); + } + else + { + AcpiOsPrintf ("%c", OutputValue); + } + } + + AcpiOsPrintf ("\")"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetHardwareIdType + * + * PARAMETERS: Op - Op to be examined + * + * RETURN: None + * + * DESCRIPTION: Determine the type of the argument to a _HID or _CID + * 1) Strings are allowed + * 2) If Integer, determine if it is a valid EISAID + * + ******************************************************************************/ + +static void +AcpiDmGetHardwareIdType ( + ACPI_PARSE_OBJECT *Op) +{ + UINT32 BigEndianId; + UINT32 Prefix[3]; + UINT32 i; + + + switch (Op->Common.AmlOpcode) + { + case AML_STRING_OP: + + /* Mark this string as an _HID/_CID string */ + + Op->Common.DisasmOpcode = ACPI_DASM_HID_STRING; + break; + + case AML_WORD_OP: + case AML_DWORD_OP: + + /* Determine if a Word/Dword is a valid encoded EISAID */ + + /* Swap from little-endian to big-endian to simplify conversion */ + + BigEndianId = AcpiUtDwordByteSwap ((UINT32) Op->Common.Value.Integer); + + /* Create the 3 leading ASCII letters */ + + Prefix[0] = ((BigEndianId >> 26) & 0x1F) + 0x40; + Prefix[1] = ((BigEndianId >> 21) & 0x1F) + 0x40; + Prefix[2] = ((BigEndianId >> 16) & 0x1F) + 0x40; + + /* Verify that all 3 are ascii and alpha */ + + for (i = 0; i < 3; i++) + { + if (!ACPI_IS_ASCII (Prefix[i]) || + !isalpha (Prefix[i])) + { + return; + } + } + + /* Mark this node as convertable to an EISA ID string */ + + Op->Common.DisasmOpcode = ACPI_DASM_EISAID; + break; + + default: + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCheckForHardwareId + * + * PARAMETERS: Op - Op to be examined + * + * RETURN: None + * + * DESCRIPTION: Determine if a Name() Op is a _HID/_CID. + * + ******************************************************************************/ + +void +AcpiDmCheckForHardwareId ( + ACPI_PARSE_OBJECT *Op) +{ + UINT32 Name; + ACPI_PARSE_OBJECT *NextOp; + + + /* Get the NameSegment */ + + Name = AcpiPsGetName (Op); + if (!Name) + { + return; + } + + NextOp = AcpiPsGetDepthNext (NULL, Op); + if (!NextOp) + { + return; + } + + /* Check for _HID - has one argument */ + + if (ACPI_COMPARE_NAME (&Name, METHOD_NAME__HID)) + { + AcpiDmGetHardwareIdType (NextOp); + return; + } + + /* Exit if not _CID */ + + if (!ACPI_COMPARE_NAME (&Name, METHOD_NAME__CID)) + { + return; + } + + /* _CID can contain a single argument or a package */ + + if (NextOp->Common.AmlOpcode != AML_PACKAGE_OP) + { + AcpiDmGetHardwareIdType (NextOp); + return; + } + + /* _CID with Package: get the package length, check all elements */ + + NextOp = AcpiPsGetDepthNext (NULL, NextOp); + if (!NextOp) + { + return; + } + + /* Don't need to use the length, just walk the peer list */ + + NextOp = NextOp->Common.Next; + while (NextOp) + { + AcpiDmGetHardwareIdType (NextOp); + NextOp = NextOp->Common.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDecompressEisaId + * + * PARAMETERS: EncodedId - Raw encoded EISA ID. + * + * RETURN: None + * + * DESCRIPTION: Convert an encoded EISAID back to the original ASCII String + * and emit the correct ASL statement. If the ID is known, emit + * a description of the ID as a comment. + * + ******************************************************************************/ + +void +AcpiDmDecompressEisaId ( + UINT32 EncodedId) +{ + char IdBuffer[ACPI_EISAID_STRING_SIZE]; + const AH_DEVICE_ID *Info; + + + /* Convert EISAID to a string an emit the statement */ + + AcpiExEisaIdToString (IdBuffer, EncodedId); + AcpiOsPrintf ("EisaId (\"%s\")", IdBuffer); + + /* If we know about the ID, emit the description */ + + Info = AcpiAhMatchHardwareId (IdBuffer); + if (Info) + { + AcpiOsPrintf (" /* %s */", Info->Description); + } +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmcstyle.c b/third_party/lib/acpica/source/components/disassembler/dmcstyle.c new file mode 100644 index 000000000..32ab5be75 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmcstyle.c @@ -0,0 +1,846 @@ +/******************************************************************************* + * + * Module Name: dmcstyle - Support for C-style operator disassembly + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dmcstyle") + + +/* Local prototypes */ + +static char * +AcpiDmGetCompoundSymbol ( + UINT16 AslOpcode); + +static void +AcpiDmPromoteTarget ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Target); + +static BOOLEAN +AcpiDmIsValidTarget ( + ACPI_PARSE_OBJECT *Op); + +static BOOLEAN +AcpiDmIsTargetAnOperand ( + ACPI_PARSE_OBJECT *Target, + ACPI_PARSE_OBJECT *Operand, + BOOLEAN TopLevel); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCheckForSymbolicOpcode + * + * PARAMETERS: Op - Current parse object + * Walk - Current parse tree walk info + * + * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise + * + * DESCRIPTION: This is the main code that implements disassembly of AML code + * to C-style operators. Called during descending phase of the + * parse tree walk. + * + ******************************************************************************/ + +BOOLEAN +AcpiDmCheckForSymbolicOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_OP_WALK_INFO *Info) +{ + char *OperatorSymbol = NULL; + ACPI_PARSE_OBJECT *Child1; + ACPI_PARSE_OBJECT *Child2; + ACPI_PARSE_OBJECT *Target; + + + /* Exit immediately if ASL+ not enabled */ + + if (!AcpiGbl_CstyleDisassembly) + { + return (FALSE); + } + + /* Get the first operand */ + + Child1 = AcpiPsGetArg (Op, 0); + if (!Child1) + { + return (FALSE); + } + + /* Get the second operand */ + + Child2 = Child1->Common.Next; + + /* Setup the operator string for this opcode */ + + switch (Op->Common.AmlOpcode) + { + case AML_ADD_OP: + OperatorSymbol = " + "; + break; + + case AML_SUBTRACT_OP: + OperatorSymbol = " - "; + break; + + case AML_MULTIPLY_OP: + OperatorSymbol = " * "; + break; + + case AML_DIVIDE_OP: + OperatorSymbol = " / "; + break; + + case AML_MOD_OP: + OperatorSymbol = " % "; + break; + + case AML_SHIFT_LEFT_OP: + OperatorSymbol = " << "; + break; + + case AML_SHIFT_RIGHT_OP: + OperatorSymbol = " >> "; + break; + + case AML_BIT_AND_OP: + OperatorSymbol = " & "; + break; + + case AML_BIT_OR_OP: + OperatorSymbol = " | "; + break; + + case AML_BIT_XOR_OP: + OperatorSymbol = " ^ "; + break; + + /* Logical operators, no target */ + + case AML_LAND_OP: + OperatorSymbol = " && "; + break; + + case AML_LEQUAL_OP: + OperatorSymbol = " == "; + break; + + case AML_LGREATER_OP: + OperatorSymbol = " > "; + break; + + case AML_LLESS_OP: + OperatorSymbol = " < "; + break; + + case AML_LOR_OP: + OperatorSymbol = " || "; + break; + + case AML_LNOT_OP: + /* + * Check for the LNOT sub-opcodes. These correspond to + * LNotEqual, LLessEqual, and LGreaterEqual. There are + * no actual AML opcodes for these operators. + */ + switch (Child1->Common.AmlOpcode) + { + case AML_LEQUAL_OP: + OperatorSymbol = " != "; + break; + + case AML_LGREATER_OP: + OperatorSymbol = " <= "; + break; + + case AML_LLESS_OP: + OperatorSymbol = " >= "; + break; + + default: + + /* Unary LNOT case, emit "!" immediately */ + + AcpiOsPrintf ("!"); + return (TRUE); + } + + Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; + Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; + + /* Save symbol string in the next child (not peer) */ + + Child2 = AcpiPsGetArg (Child1, 0); + if (!Child2) + { + return (FALSE); + } + + Child2->Common.OperatorSymbol = OperatorSymbol; + return (TRUE); + + case AML_INDEX_OP: + /* + * Check for constant source operand. Note: although technically + * legal syntax, the iASL compiler does not support this with + * the symbolic operators for Index(). It doesn't make sense to + * use Index() with a constant anyway. + */ + if ((Child1->Common.AmlOpcode == AML_STRING_OP) || + (Child1->Common.AmlOpcode == AML_BUFFER_OP) || + (Child1->Common.AmlOpcode == AML_PACKAGE_OP) || + (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) + { + Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN; + return (FALSE); + } + + /* Index operator is [] */ + + Child1->Common.OperatorSymbol = " ["; + Child2->Common.OperatorSymbol = "]"; + break; + + /* Unary operators */ + + case AML_DECREMENT_OP: + OperatorSymbol = "--"; + break; + + case AML_INCREMENT_OP: + OperatorSymbol = "++"; + break; + + case AML_BIT_NOT_OP: + case AML_STORE_OP: + OperatorSymbol = NULL; + break; + + default: + return (FALSE); + } + + if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX) + { + return (TRUE); + } + + /* + * This is the key to how the disassembly of the C-style operators + * works. We save the operator symbol in the first child, thus + * deferring symbol output until after the first operand has been + * emitted. + */ + if (!Child1->Common.OperatorSymbol) + { + Child1->Common.OperatorSymbol = OperatorSymbol; + } + + /* + * Check for a valid target as the 3rd (or sometimes 2nd) operand + * + * Compound assignment operator support: + * Attempt to optimize constructs of the form: + * Add (Local1, 0xFF, Local1) + * to: + * Local1 += 0xFF + * + * Only the math operators and Store() have a target. + * Logicals have no target. + */ + switch (Op->Common.AmlOpcode) + { + case AML_ADD_OP: + case AML_SUBTRACT_OP: + case AML_MULTIPLY_OP: + case AML_DIVIDE_OP: + case AML_MOD_OP: + case AML_SHIFT_LEFT_OP: + case AML_SHIFT_RIGHT_OP: + case AML_BIT_AND_OP: + case AML_BIT_OR_OP: + case AML_BIT_XOR_OP: + + /* Target is 3rd operand */ + + Target = Child2->Common.Next; + if (Op->Common.AmlOpcode == AML_DIVIDE_OP) + { + /* + * Divide has an extra target operand (Remainder). + * If this extra target is specified, it cannot be converted + * to a C-style operator + */ + if (AcpiDmIsValidTarget (Target)) + { + Child1->Common.OperatorSymbol = NULL; + return (FALSE); + } + + Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + Target = Target->Common.Next; + } + + /* Parser should ensure there is at least a placeholder target */ + + if (!Target) + { + return (FALSE); + } + + if (!AcpiDmIsValidTarget (Target)) + { + /* Not a valid target (placeholder only, from parser) */ + break; + } + + /* + * Promote the target up to the first child in the parse + * tree. This is done because the target will be output + * first, in the form: + * = Operands... + */ + AcpiDmPromoteTarget (Op, Target); + + /* Check operands for conversion to a "Compound Assignment" */ + + switch (Op->Common.AmlOpcode) + { + /* Commutative operators */ + + case AML_ADD_OP: + case AML_MULTIPLY_OP: + case AML_BIT_AND_OP: + case AML_BIT_OR_OP: + case AML_BIT_XOR_OP: + /* + * For the commutative operators, we can convert to a + * compound statement only if at least one (either) operand + * is the same as the target. + * + * Add (A, B, A) --> A += B + * Add (B, A, A) --> A += B + * Add (B, C, A) --> A = (B + C) + */ + if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) || + (AcpiDmIsTargetAnOperand (Target, Child2, TRUE))) + { + Target->Common.OperatorSymbol = + AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); + + /* Convert operator to compound assignment */ + + Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND; + Child1->Common.OperatorSymbol = NULL; + return (TRUE); + } + break; + + /* Non-commutative operators */ + + case AML_SUBTRACT_OP: + case AML_DIVIDE_OP: + case AML_MOD_OP: + case AML_SHIFT_LEFT_OP: + case AML_SHIFT_RIGHT_OP: + /* + * For the non-commutative operators, we can convert to a + * compound statement only if the target is the same as the + * first operand. + * + * Subtract (A, B, A) --> A -= B + * Subtract (B, A, A) --> A = (B - A) + */ + if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE))) + { + Target->Common.OperatorSymbol = + AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); + + /* Convert operator to compound assignment */ + + Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND; + Child1->Common.OperatorSymbol = NULL; + return (TRUE); + } + break; + + default: + break; + } + + /* + * If we are within a C-style expression, emit an extra open + * paren. Implemented by examining the parent op. + */ + switch (Op->Common.Parent->Common.AmlOpcode) + { + case AML_ADD_OP: + case AML_SUBTRACT_OP: + case AML_MULTIPLY_OP: + case AML_DIVIDE_OP: + case AML_MOD_OP: + case AML_SHIFT_LEFT_OP: + case AML_SHIFT_RIGHT_OP: + case AML_BIT_AND_OP: + case AML_BIT_OR_OP: + case AML_BIT_XOR_OP: + case AML_LAND_OP: + case AML_LEQUAL_OP: + case AML_LGREATER_OP: + case AML_LLESS_OP: + case AML_LOR_OP: + + Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT; + AcpiOsPrintf ("("); + break; + + default: + break; + } + + /* Normal output for ASL/AML operators with a target operand */ + + Target->Common.OperatorSymbol = " = ("; + return (TRUE); + + /* Binary operators, no parens */ + + case AML_DECREMENT_OP: + case AML_INCREMENT_OP: + return (TRUE); + + case AML_INDEX_OP: + + /* Target is optional, 3rd operand */ + + Target = Child2->Common.Next; + if (AcpiDmIsValidTarget (Target)) + { + AcpiDmPromoteTarget (Op, Target); + + if (!Target->Common.OperatorSymbol) + { + Target->Common.OperatorSymbol = " = "; + } + } + return (TRUE); + + case AML_STORE_OP: + /* + * Target is the 2nd operand. + * We know the target is valid, it is not optional. + * In the parse tree, simply swap the target with the + * source so that the target is processed first. + */ + Target = Child1->Common.Next; + if (!Target) + { + return (FALSE); + } + + AcpiDmPromoteTarget (Op, Target); + if (!Target->Common.OperatorSymbol) + { + Target->Common.OperatorSymbol = " = "; + } + return (TRUE); + + case AML_BIT_NOT_OP: + + /* Target is optional, 2nd operand */ + + Target = Child1->Common.Next; + if (!Target) + { + return (FALSE); + } + + if (AcpiDmIsValidTarget (Target)) + { + /* Valid target, not a placeholder */ + + AcpiDmPromoteTarget (Op, Target); + Target->Common.OperatorSymbol = " = ~"; + } + else + { + /* No target. Emit this prefix operator immediately */ + + AcpiOsPrintf ("~"); + } + return (TRUE); + + default: + break; + } + + /* All other operators, emit an open paren */ + + AcpiOsPrintf ("("); + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCloseOperator + * + * PARAMETERS: Op - Current parse object + * + * RETURN: None + * + * DESCRIPTION: Closes an operator by adding a closing parentheses if and + * when necessary. Called during ascending phase of the + * parse tree walk. + * + ******************************************************************************/ + +void +AcpiDmCloseOperator ( + ACPI_PARSE_OBJECT *Op) +{ + + /* Always emit paren if ASL+ disassembly disabled */ + + if (!AcpiGbl_CstyleDisassembly) + { + AcpiOsPrintf (")"); + return; + } + + /* Check if we need to add an additional closing paren */ + + switch (Op->Common.AmlOpcode) + { + case AML_ADD_OP: + case AML_SUBTRACT_OP: + case AML_MULTIPLY_OP: + case AML_DIVIDE_OP: + case AML_MOD_OP: + case AML_SHIFT_LEFT_OP: + case AML_SHIFT_RIGHT_OP: + case AML_BIT_AND_OP: + case AML_BIT_OR_OP: + case AML_BIT_XOR_OP: + case AML_LAND_OP: + case AML_LEQUAL_OP: + case AML_LGREATER_OP: + case AML_LLESS_OP: + case AML_LOR_OP: + + /* Emit paren only if this is not a compound assignment */ + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND) + { + return; + } + + /* Emit extra close paren for assignment within an expression */ + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT) + { + AcpiOsPrintf (")"); + } + break; + + case AML_INDEX_OP: + + /* This is case for unsupported Index() source constants */ + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN) + { + AcpiOsPrintf (")"); + } + return; + + /* No need for parens for these */ + + case AML_DECREMENT_OP: + case AML_INCREMENT_OP: + case AML_LNOT_OP: + case AML_BIT_NOT_OP: + case AML_STORE_OP: + return; + + default: + + /* Always emit paren for non-ASL+ operators */ + break; + } + + AcpiOsPrintf (")"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGetCompoundSymbol + * + * PARAMETERS: AslOpcode + * + * RETURN: String containing the compound assignment symbol + * + * DESCRIPTION: Detect opcodes that can be converted to compound assignment, + * return the appropriate operator string. + * + ******************************************************************************/ + +static char * +AcpiDmGetCompoundSymbol ( + UINT16 AmlOpcode) +{ + char *Symbol; + + + switch (AmlOpcode) + { + case AML_ADD_OP: + Symbol = " += "; + break; + + case AML_SUBTRACT_OP: + Symbol = " -= "; + break; + + case AML_MULTIPLY_OP: + Symbol = " *= "; + break; + + case AML_DIVIDE_OP: + Symbol = " /= "; + break; + + case AML_MOD_OP: + Symbol = " %= "; + break; + + case AML_SHIFT_LEFT_OP: + Symbol = " <<= "; + break; + + case AML_SHIFT_RIGHT_OP: + Symbol = " >>= "; + break; + + case AML_BIT_AND_OP: + Symbol = " &= "; + break; + + case AML_BIT_OR_OP: + Symbol = " |= "; + break; + + case AML_BIT_XOR_OP: + Symbol = " ^= "; + break; + + default: + + /* No operator string for all other opcodes */ + + return (NULL); + } + + return (Symbol); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmPromoteTarget + * + * PARAMETERS: Op - Operator parse object + * Target - Target associate with the Op + * + * RETURN: None + * + * DESCRIPTION: Transform the parse tree by moving the target up to the first + * child of the Op. + * + ******************************************************************************/ + +static void +AcpiDmPromoteTarget ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Target) +{ + ACPI_PARSE_OBJECT *Child; + + + /* Link target directly to the Op as first child */ + + Child = Op->Common.Value.Arg; + Op->Common.Value.Arg = Target; + Target->Common.Next = Child; + + /* Find the last peer, it is linked to the target. Unlink it. */ + + while (Child->Common.Next != Target) + { + Child = Child->Common.Next; + } + + Child->Common.Next = NULL; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsValidTarget + * + * PARAMETERS: Target - Target Op from the parse tree + * + * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder + * Op that was inserted by the parser. + * + * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target. + * In other words, determine if the optional target is used or + * not. Note: If Target is NULL, something is seriously wrong, + * probably with the parse tree. + * + ******************************************************************************/ + +static BOOLEAN +AcpiDmIsValidTarget ( + ACPI_PARSE_OBJECT *Target) +{ + + if (!Target) + { + return (FALSE); + } + + if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && + (Target->Common.Value.Arg == NULL)) + { + return (FALSE); + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsTargetAnOperand + * + * PARAMETERS: Target - Target associated with the expression + * Operand - An operand associated with expression + * + * RETURN: TRUE if expression can be converted to a compound assignment. + * FALSE otherwise. + * + * DESCRIPTION: Determine if the Target duplicates the operand, in order to + * detect if the expression can be converted to a compound + * assigment. (+=, *=, etc.) + * + ******************************************************************************/ + +static BOOLEAN +AcpiDmIsTargetAnOperand ( + ACPI_PARSE_OBJECT *Target, + ACPI_PARSE_OBJECT *Operand, + BOOLEAN TopLevel) +{ + const ACPI_OPCODE_INFO *OpInfo; + BOOLEAN Same; + + + /* + * Opcodes must match. Note: ignoring the difference between nameseg + * and namepath for now. May be needed later. + */ + if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode) + { + return (FALSE); + } + + /* Nodes should match, even if they are NULL */ + + if (Target->Common.Node != Operand->Common.Node) + { + return (FALSE); + } + + /* Determine if a child exists */ + + OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode); + if (OpInfo->Flags & AML_HAS_ARGS) + { + Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg, + Operand->Common.Value.Arg, FALSE); + if (!Same) + { + return (FALSE); + } + } + + /* Check the next peer, as long as we are not at the top level */ + + if ((!TopLevel) && + Target->Common.Next) + { + Same = AcpiDmIsTargetAnOperand (Target->Common.Next, + Operand->Common.Next, FALSE); + if (!Same) + { + return (FALSE); + } + } + + /* Supress the duplicate operand at the top-level */ + + if (TopLevel) + { + Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + } + return (TRUE); +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmdeferred.c b/third_party/lib/acpica/source/components/disassembler/dmdeferred.c new file mode 100644 index 000000000..387980b89 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmdeferred.c @@ -0,0 +1,264 @@ +/****************************************************************************** + * + * Module Name: dmdeferred - Disassembly of deferred AML opcodes + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "amlcode.h" +#include "acdisasm.h" +#include "acparser.h" + +#define _COMPONENT ACPI_CA_DISASSEMBLER + ACPI_MODULE_NAME ("dmdeferred") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDmDeferredParse ( + ACPI_PARSE_OBJECT *Op, + UINT8 *Aml, + UINT32 AmlLength); + + +/****************************************************************************** + * + * FUNCTION: AcpiDmParseDeferredOps + * + * PARAMETERS: Root - Root of the parse tree + * + * RETURN: Status + * + * DESCRIPTION: Parse the deferred opcodes (Methods, regions, etc.) + * + *****************************************************************************/ + +ACPI_STATUS +AcpiDmParseDeferredOps ( + ACPI_PARSE_OBJECT *Root) +{ + const ACPI_OPCODE_INFO *OpInfo; + ACPI_PARSE_OBJECT *Op = Root; + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + /* Traverse the entire parse tree */ + + while (Op) + { + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (!(OpInfo->Flags & AML_DEFER)) + { + Op = AcpiPsGetDepthNext (Root, Op); + continue; + } + + /* Now we know we have a deferred opcode */ + + switch (Op->Common.AmlOpcode) + { + case AML_METHOD_OP: + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + Status = AcpiDmDeferredParse ( + Op, Op->Named.Data, Op->Named.Length); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + /* We don't need to do anything for these deferred opcodes */ + + case AML_REGION_OP: + case AML_DATA_REGION_OP: + case AML_CREATE_QWORD_FIELD_OP: + case AML_CREATE_DWORD_FIELD_OP: + case AML_CREATE_WORD_FIELD_OP: + case AML_CREATE_BYTE_FIELD_OP: + case AML_CREATE_BIT_FIELD_OP: + case AML_CREATE_FIELD_OP: + case AML_BANK_FIELD_OP: + + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unhandled deferred AML opcode [0x%.4X]", + Op->Common.AmlOpcode)); + break; + } + + Op = AcpiPsGetDepthNext (Root, Op); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiDmDeferredParse + * + * PARAMETERS: Op - Root Op of the deferred opcode + * Aml - Pointer to the raw AML + * AmlLength - Length of the AML + * + * RETURN: Status + * + * DESCRIPTION: Parse one deferred opcode + * (Methods, operation regions, etc.) + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiDmDeferredParse ( + ACPI_PARSE_OBJECT *Op, + UINT8 *Aml, + UINT32 AmlLength) +{ + ACPI_WALK_STATE *WalkState; + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *SearchOp; + ACPI_PARSE_OBJECT *StartOp; + ACPI_PARSE_OBJECT *NewRootOp; + ACPI_PARSE_OBJECT *ExtraOp; + + + ACPI_FUNCTION_TRACE (DmDeferredParse); + + + if (!Aml || !AmlLength) + { + return_ACPI_STATUS (AE_OK); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Parsing deferred opcode %s [%4.4s]\n", + Op->Common.AmlOpName, (char *) &Op->Named.Name)); + + /* Need a new walk state to parse the AML */ + + WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL); + if (!WalkState) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, Aml, + AmlLength, NULL, ACPI_IMODE_LOAD_PASS1); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Parse the AML for this deferred opcode */ + + WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE; + WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE; + Status = AcpiPsParseAml (WalkState); + + StartOp = (Op->Common.Value.Arg)->Common.Next; + SearchOp = StartOp; + while (SearchOp) + { + SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp); + } + + /* + * For Buffer and Package opcodes, link the newly parsed subtree + * into the main parse tree + */ + switch (Op->Common.AmlOpcode) + { + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + switch (Op->Common.AmlOpcode) + { + case AML_PACKAGE_OP: + + ExtraOp = Op->Common.Value.Arg; + NewRootOp = ExtraOp->Common.Next; + ACPI_FREE (ExtraOp); + break; + + case AML_VAR_PACKAGE_OP: + case AML_BUFFER_OP: + default: + + NewRootOp = Op->Common.Value.Arg; + break; + } + + Op->Common.Value.Arg = NewRootOp->Common.Value.Arg; + + /* Must point all parents to the main tree */ + + StartOp = Op; + SearchOp = StartOp; + while (SearchOp) + { + if (SearchOp->Common.Parent == NewRootOp) + { + SearchOp->Common.Parent = Op; + } + + SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp); + } + + ACPI_FREE (NewRootOp); + break; + + default: + + break; + } + + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmnames.c b/third_party/lib/acpica/source/components/disassembler/dmnames.c new file mode 100644 index 000000000..89cfb2e98 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmnames.c @@ -0,0 +1,450 @@ +/******************************************************************************* + * + * Module Name: dmnames - AML disassembler, names, namestrings, pathnames + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdisasm.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dmnames") + +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +void +AcpiDmDisplayPath ( + ACPI_PARSE_OBJECT *Op); +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpName + * + * PARAMETERS: Name - 4 character ACPI name + * + * RETURN: Final length of name + * + * DESCRIPTION: Dump an ACPI name, minus any trailing underscores. + * + ******************************************************************************/ + +UINT32 +AcpiDmDumpName ( + UINT32 Name) +{ + UINT32 i; + UINT32 Length; + char NewName[4]; + + + /* Copy name locally in case the original name is not writeable */ + + *ACPI_CAST_PTR (UINT32, &NewName[0]) = Name; + + /* Ensure that the name is printable, even if we have to fix it */ + + AcpiUtRepairName (NewName); + + /* Remove all trailing underscores from the name */ + + Length = ACPI_NAME_SIZE; + for (i = (ACPI_NAME_SIZE - 1); i != 0; i--) + { + if (NewName[i] == '_') + { + Length--; + } + else + { + break; + } + } + + /* Dump the name, up to the start of the trailing underscores */ + + for (i = 0; i < Length; i++) + { + AcpiOsPrintf ("%c", NewName[i]); + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsDisplayObjectPathname + * + * PARAMETERS: WalkState - Current walk state + * Op - Object whose pathname is to be obtained + * + * RETURN: Status + * + * DESCRIPTION: Diplay the pathname associated with a named object. Two + * versions. One searches the parse tree (for parser-only + * applications suchas AcpiDump), and the other searches the + * ACPI namespace (the parse tree is probably deleted) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsDisplayObjectPathname ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_BUFFER Buffer; + UINT32 DebugLevel; + + + /* Save current debug level so we don't get extraneous debug output */ + + DebugLevel = AcpiDbgLevel; + AcpiDbgLevel = 0; + + /* Just get the Node out of the Op object */ + + Node = Op->Common.Node; + if (!Node) + { + /* Node not defined in this scope, look it up */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, Op->Common.Value.String, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + WalkState, &(Node)); + + if (ACPI_FAILURE (Status)) + { + /* + * We can't get the pathname since the object is not in the + * namespace. This can happen during single stepping + * where a dynamic named object is *about* to be created. + */ + AcpiOsPrintf (" [Path not found]"); + goto Exit; + } + + /* Save it for next time. */ + + Op->Common.Node = Node; + } + + /* Convert NamedDesc/handle to a full pathname */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (Node, &Buffer, FALSE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("****Could not get pathname****)"); + goto Exit; + } + + AcpiOsPrintf (" (Path %s)", (char *) Buffer.Pointer); + ACPI_FREE (Buffer.Pointer); + + +Exit: + /* Restore the debug level */ + + AcpiDbgLevel = DebugLevel; + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmNamestring + * + * PARAMETERS: Name - ACPI Name string to store + * + * RETURN: None + * + * DESCRIPTION: Decode and dump an ACPI namestring. Handles prefix characters + * + ******************************************************************************/ + +void +AcpiDmNamestring ( + char *Name) +{ + UINT32 SegCount; + + + if (!Name) + { + return; + } + + /* Handle all Scope Prefix operators */ + + while (ACPI_IS_ROOT_PREFIX (ACPI_GET8 (Name)) || + ACPI_IS_PARENT_PREFIX (ACPI_GET8 (Name))) + { + /* Append prefix character */ + + AcpiOsPrintf ("%1c", ACPI_GET8 (Name)); + Name++; + } + + switch (ACPI_GET8 (Name)) + { + case 0: + + SegCount = 0; + break; + + case AML_DUAL_NAME_PREFIX: + + SegCount = 2; + Name++; + break; + + case AML_MULTI_NAME_PREFIX_OP: + + SegCount = (UINT32) ACPI_GET8 (Name + 1); + Name += 2; + break; + + default: + + SegCount = 1; + break; + } + + while (SegCount) + { + /* Append Name segment */ + + AcpiDmDumpName (*ACPI_CAST_PTR (UINT32, Name)); + + SegCount--; + if (SegCount) + { + /* Not last name, append dot separator */ + + AcpiOsPrintf ("."); + } + + Name += ACPI_NAME_SIZE; + } +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: AcpiDmDisplayPath + * + * PARAMETERS: Op - Named Op whose path is to be constructed + * + * RETURN: None + * + * DESCRIPTION: Walk backwards from current scope and display the name + * of each previous level of scope up to the root scope + * (like "pwd" does with file systems) + * + ******************************************************************************/ + +void +AcpiDmDisplayPath ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Prev; + ACPI_PARSE_OBJECT *Search; + UINT32 Name; + BOOLEAN DoDot = FALSE; + ACPI_PARSE_OBJECT *NamePath; + const ACPI_OPCODE_INFO *OpInfo; + + + /* We are only interested in named objects */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (!(OpInfo->Flags & AML_NSNODE)) + { + return; + } + + if (OpInfo->Flags & AML_CREATE) + { + /* Field creation - check for a fully qualified namepath */ + + if (Op->Common.AmlOpcode == AML_CREATE_FIELD_OP) + { + NamePath = AcpiPsGetArg (Op, 3); + } + else + { + NamePath = AcpiPsGetArg (Op, 2); + } + + if ((NamePath) && + (NamePath->Common.Value.String) && + (ACPI_IS_ROOT_PREFIX (NamePath->Common.Value.String[0]))) + { + AcpiDmNamestring (NamePath->Common.Value.String); + return; + } + } + + Prev = NULL; /* Start with Root Node */ + while (Prev != Op) + { + /* Search upwards in the tree to find scope with "prev" as its parent */ + + Search = Op; + for (; ;) + { + if (Search->Common.Parent == Prev) + { + break; + } + + /* Go up one level */ + + Search = Search->Common.Parent; + } + + if (Prev) + { + OpInfo = AcpiPsGetOpcodeInfo (Search->Common.AmlOpcode); + if (!(OpInfo->Flags & AML_FIELD)) + { + /* Below root scope, append scope name */ + + if (DoDot) + { + /* Append dot */ + + AcpiOsPrintf ("."); + } + + if (OpInfo->Flags & AML_CREATE) + { + if (Op->Common.AmlOpcode == AML_CREATE_FIELD_OP) + { + NamePath = AcpiPsGetArg (Op, 3); + } + else + { + NamePath = AcpiPsGetArg (Op, 2); + } + + if ((NamePath) && + (NamePath->Common.Value.String)) + { + AcpiDmDumpName (NamePath->Common.Value.String); + } + } + else + { + Name = AcpiPsGetName (Search); + AcpiDmDumpName ((char *) &Name); + } + + DoDot = TRUE; + } + } + + Prev = Search; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmValidateName + * + * PARAMETERS: Name - 4 character ACPI name + * + * RETURN: None + * + * DESCRIPTION: Lookup the name + * + ******************************************************************************/ + +void +AcpiDmValidateName ( + char *Name, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *TargetOp; + + + if ((!Name) || + (!Op->Common.Parent)) + { + return; + } + + if (!Op->Common.Node) + { + AcpiOsPrintf ( + " /**** Name not found or not accessible from this scope ****/ "); + } + + if ((!Name) || + (!Op->Common.Parent)) + { + return; + } + + TargetOp = AcpiPsFind (Op, Name, 0, 0); + if (!TargetOp) + { + /* + * Didn't find the name in the parse tree. This may be + * a problem, or it may simply be one of the predefined names + * (such as _OS_). Rather than worry about looking up all + * the predefined names, just display the name as given + */ + AcpiOsPrintf ( + " /**** Name not found or not accessible from this scope ****/ "); + } +} +#endif diff --git a/third_party/lib/acpica/source/components/disassembler/dmopcode.c b/third_party/lib/acpica/source/components/disassembler/dmopcode.c new file mode 100644 index 000000000..dd5a0d40a --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmopcode.c @@ -0,0 +1,1105 @@ +/******************************************************************************* + * + * Module Name: dmopcode - AML disassembler, specific AML opcodes + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dmopcode") + + +/* Local prototypes */ + +static void +AcpiDmMatchKeyword ( + ACPI_PARSE_OBJECT *Op); + +static void +AcpiDmConvertToElseIf ( + ACPI_PARSE_OBJECT *Op); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDisplayTargetPathname + * + * PARAMETERS: Op - Parse object + * + * RETURN: None + * + * DESCRIPTION: For AML opcodes that have a target operand, display the full + * pathname for the target, in a comment field. Handles Return() + * statements also. + * + ******************************************************************************/ + +void +AcpiDmDisplayTargetPathname ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextOp; + ACPI_PARSE_OBJECT *PrevOp = NULL; + char *Pathname; + const ACPI_OPCODE_INFO *OpInfo; + + + if (Op->Common.AmlOpcode == AML_RETURN_OP) + { + PrevOp = Op->Asl.Value.Arg; + } + else + { + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (!(OpInfo->Flags & AML_HAS_TARGET)) + { + return; + } + + /* Target is the last Op in the arg list */ + + NextOp = Op->Asl.Value.Arg; + while (NextOp) + { + PrevOp = NextOp; + NextOp = PrevOp->Asl.Next; + } + } + + if (!PrevOp) + { + return; + } + + /* We must have a namepath AML opcode */ + + if (PrevOp->Asl.AmlOpcode != AML_INT_NAMEPATH_OP) + { + return; + } + + /* A null string is the "no target specified" case */ + + if (!PrevOp->Asl.Value.String) + { + return; + } + + /* No node means "unresolved external reference" */ + + if (!PrevOp->Asl.Node) + { + AcpiOsPrintf (" /* External reference */"); + return; + } + + /* Ignore if path is already from the root */ + + if (*PrevOp->Asl.Value.String == '\\') + { + return; + } + + /* Now: we can get the full pathname */ + + Pathname = AcpiNsGetExternalPathname (PrevOp->Asl.Node); + if (!Pathname) + { + return; + } + + AcpiOsPrintf (" /* %s */", Pathname); + ACPI_FREE (Pathname); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmNotifyDescription + * + * PARAMETERS: Op - Name() parse object + * + * RETURN: None + * + * DESCRIPTION: Emit a description comment for the value associated with a + * Notify() operator. + * + ******************************************************************************/ + +void +AcpiDmNotifyDescription ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextOp; + ACPI_NAMESPACE_NODE *Node; + UINT8 NotifyValue; + UINT8 Type = ACPI_TYPE_ANY; + + + /* The notify value is the second argument */ + + NextOp = Op->Asl.Value.Arg; + NextOp = NextOp->Asl.Next; + + switch (NextOp->Common.AmlOpcode) + { + case AML_ZERO_OP: + case AML_ONE_OP: + + NotifyValue = (UINT8) NextOp->Common.AmlOpcode; + break; + + case AML_BYTE_OP: + + NotifyValue = (UINT8) NextOp->Asl.Value.Integer; + break; + + default: + return; + } + + /* + * Attempt to get the namespace node so we can determine the object type. + * Some notify values are dependent on the object type (Device, Thermal, + * or Processor). + */ + Node = Op->Asl.Node; + if (Node) + { + Type = Node->Type; + } + + AcpiOsPrintf (" // %s", AcpiUtGetNotifyName (NotifyValue, Type)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmPredefinedDescription + * + * PARAMETERS: Op - Name() parse object + * + * RETURN: None + * + * DESCRIPTION: Emit a description comment for a predefined ACPI name. + * Used for iASL compiler only. + * + ******************************************************************************/ + +void +AcpiDmPredefinedDescription ( + ACPI_PARSE_OBJECT *Op) +{ +#ifdef ACPI_ASL_COMPILER + const AH_PREDEFINED_NAME *Info; + char *NameString; + int LastCharIsDigit; + int LastCharsAreHex; + + + if (!Op) + { + return; + } + + /* Ensure that the comment field is emitted only once */ + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEF_CHECKED) + { + return; + } + Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEF_CHECKED; + + /* Predefined name must start with an underscore */ + + NameString = ACPI_CAST_PTR (char, &Op->Named.Name); + if (NameString[0] != '_') + { + return; + } + + /* + * Check for the special ACPI names: + * _ACd, _ALd, _EJd, _Exx, _Lxx, _Qxx, _Wxx, _T_a + * (where d=decimal_digit, x=hex_digit, a=anything) + * + * Convert these to the generic name for table lookup. + * Note: NameString is guaranteed to be upper case here. + */ + LastCharIsDigit = + (isdigit ((int) NameString[3])); /* d */ + LastCharsAreHex = + (isxdigit ((int) NameString[2]) && /* xx */ + isxdigit ((int) NameString[3])); + + switch (NameString[1]) + { + case 'A': + + if ((NameString[2] == 'C') && (LastCharIsDigit)) + { + NameString = "_ACx"; + } + else if ((NameString[2] == 'L') && (LastCharIsDigit)) + { + NameString = "_ALx"; + } + break; + + case 'E': + + if ((NameString[2] == 'J') && (LastCharIsDigit)) + { + NameString = "_EJx"; + } + else if (LastCharsAreHex) + { + NameString = "_Exx"; + } + break; + + case 'L': + + if (LastCharsAreHex) + { + NameString = "_Lxx"; + } + break; + + case 'Q': + + if (LastCharsAreHex) + { + NameString = "_Qxx"; + } + break; + + case 'T': + + if (NameString[2] == '_') + { + NameString = "_T_x"; + } + break; + + case 'W': + + if (LastCharsAreHex) + { + NameString = "_Wxx"; + } + break; + + default: + + break; + } + + /* Match the name in the info table */ + + Info = AcpiAhMatchPredefinedName (NameString); + if (Info) + { + AcpiOsPrintf (" // %4.4s: %s", + NameString, ACPI_CAST_PTR (char, Info->Description)); + } + +#endif + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFieldPredefinedDescription + * + * PARAMETERS: Op - Parse object + * + * RETURN: None + * + * DESCRIPTION: Emit a description comment for a resource descriptor tag + * (which is a predefined ACPI name.) Used for iASL compiler only. + * + ******************************************************************************/ + +void +AcpiDmFieldPredefinedDescription ( + ACPI_PARSE_OBJECT *Op) +{ +#ifdef ACPI_ASL_COMPILER + ACPI_PARSE_OBJECT *IndexOp; + char *Tag; + const ACPI_OPCODE_INFO *OpInfo; + const AH_PREDEFINED_NAME *Info; + + + if (!Op) + { + return; + } + + /* Ensure that the comment field is emitted only once */ + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEF_CHECKED) + { + return; + } + Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEF_CHECKED; + + /* + * Op must be one of the Create* operators: CreateField, CreateBitField, + * CreateByteField, CreateWordField, CreateDwordField, CreateQwordField + */ + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (!(OpInfo->Flags & AML_CREATE)) + { + return; + } + + /* Second argument is the Index argument */ + + IndexOp = Op->Common.Value.Arg; + IndexOp = IndexOp->Common.Next; + + /* Index argument must be a namepath */ + + if (IndexOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP) + { + return; + } + + /* Major cheat: We previously put the Tag ptr in the Node field */ + + Tag = ACPI_CAST_PTR (char, IndexOp->Common.Node); + if (!Tag) + { + return; + } + + /* Match the name in the info table */ + + Info = AcpiAhMatchPredefinedName (Tag); + if (Info) + { + AcpiOsPrintf (" // %4.4s: %s", Tag, + ACPI_CAST_PTR (char, Info->Description)); + } + +#endif + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMethodFlags + * + * PARAMETERS: Op - Method Object to be examined + * + * RETURN: None + * + * DESCRIPTION: Decode control method flags + * + ******************************************************************************/ + +void +AcpiDmMethodFlags ( + ACPI_PARSE_OBJECT *Op) +{ + UINT32 Flags; + UINT32 Args; + + + /* The next Op contains the flags */ + + Op = AcpiPsGetDepthNext (NULL, Op); + Flags = (UINT8) Op->Common.Value.Integer; + Args = Flags & 0x07; + + /* Mark the Op as completed */ + + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + + /* 1) Method argument count */ + + AcpiOsPrintf (", %u, ", Args); + + /* 2) Serialize rule */ + + if (!(Flags & 0x08)) + { + AcpiOsPrintf ("Not"); + } + + AcpiOsPrintf ("Serialized"); + + /* 3) SyncLevel */ + + if (Flags & 0xF0) + { + AcpiOsPrintf (", %u", Flags >> 4); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFieldFlags + * + * PARAMETERS: Op - Field Object to be examined + * + * RETURN: None + * + * DESCRIPTION: Decode Field definition flags + * + ******************************************************************************/ + +void +AcpiDmFieldFlags ( + ACPI_PARSE_OBJECT *Op) +{ + UINT32 Flags; + + + Op = Op->Common.Next; + Flags = (UINT8) Op->Common.Value.Integer; + + /* Mark the Op as completed */ + + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + + AcpiOsPrintf ("%s, ", AcpiGbl_AccessTypes [Flags & 0x07]); + AcpiOsPrintf ("%s, ", AcpiGbl_LockRule [(Flags & 0x10) >> 4]); + AcpiOsPrintf ("%s)", AcpiGbl_UpdateRules [(Flags & 0x60) >> 5]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddressSpace + * + * PARAMETERS: SpaceId - ID to be translated + * + * RETURN: None + * + * DESCRIPTION: Decode a SpaceId to an AddressSpaceKeyword + * + ******************************************************************************/ + +void +AcpiDmAddressSpace ( + UINT8 SpaceId) +{ + + if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) + { + if (SpaceId == 0x7F) + { + AcpiOsPrintf ("FFixedHW, "); + } + else + { + AcpiOsPrintf ("0x%.2X, ", SpaceId); + } + } + else + { + AcpiOsPrintf ("%s, ", AcpiGbl_RegionTypes [SpaceId]); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmRegionFlags + * + * PARAMETERS: Op - Object to be examined + * + * RETURN: None + * + * DESCRIPTION: Decode OperationRegion flags + * + ******************************************************************************/ + +void +AcpiDmRegionFlags ( + ACPI_PARSE_OBJECT *Op) +{ + + /* The next Op contains the SpaceId */ + + Op = AcpiPsGetDepthNext (NULL, Op); + + /* Mark the Op as completed */ + + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + + AcpiOsPrintf (", "); + AcpiDmAddressSpace ((UINT8) Op->Common.Value.Integer); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMatchOp + * + * PARAMETERS: Op - Match Object to be examined + * + * RETURN: None + * + * DESCRIPTION: Decode Match opcode operands + * + ******************************************************************************/ + +void +AcpiDmMatchOp ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *NextOp; + + + NextOp = AcpiPsGetDepthNext (NULL, Op); + NextOp = NextOp->Common.Next; + + if (!NextOp) + { + /* Handle partial tree during single-step */ + + return; + } + + /* Mark the two nodes that contain the encoding for the match keywords */ + + NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; + + NextOp = NextOp->Common.Next; + NextOp = NextOp->Common.Next; + NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMatchKeyword + * + * PARAMETERS: Op - Match Object to be examined + * + * RETURN: None + * + * DESCRIPTION: Decode Match opcode operands + * + ******************************************************************************/ + +static void +AcpiDmMatchKeyword ( + ACPI_PARSE_OBJECT *Op) +{ + + if (((UINT32) Op->Common.Value.Integer) > ACPI_MAX_MATCH_OPCODE) + { + AcpiOsPrintf ("/* Unknown Match Keyword encoding */"); + } + else + { + AcpiOsPrintf ("%s", ACPI_CAST_PTR (char, + AcpiGbl_MatchOps[(ACPI_SIZE) Op->Common.Value.Integer])); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDisassembleOneOp + * + * PARAMETERS: WalkState - Current walk info + * Info - Parse tree walk info + * Op - Op that is to be printed + * + * RETURN: None + * + * DESCRIPTION: Disassemble a single AML opcode + * + ******************************************************************************/ + +void +AcpiDmDisassembleOneOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op) +{ + const ACPI_OPCODE_INFO *OpInfo = NULL; + UINT32 Offset; + UINT32 Length; + ACPI_PARSE_OBJECT *Child; + ACPI_STATUS Status; + UINT8 *Aml; + const AH_DEVICE_ID *IdInfo; + + + if (!Op) + { + AcpiOsPrintf (""); + return; + } + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF) + { + return; /* ElseIf macro was already emitted */ + } + + switch (Op->Common.DisasmOpcode) + { + case ACPI_DASM_MATCHOP: + + AcpiDmMatchKeyword (Op); + return; + + case ACPI_DASM_LNOT_SUFFIX: + + if (!AcpiGbl_CstyleDisassembly) + { + switch (Op->Common.AmlOpcode) + { + case AML_LEQUAL_OP: + AcpiOsPrintf ("LNotEqual"); + break; + + case AML_LGREATER_OP: + AcpiOsPrintf ("LLessEqual"); + break; + + case AML_LLESS_OP: + AcpiOsPrintf ("LGreaterEqual"); + break; + + default: + break; + } + } + + Op->Common.DisasmOpcode = 0; + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + return; + + default: + break; + } + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + /* The op and arguments */ + + switch (Op->Common.AmlOpcode) + { + case AML_LNOT_OP: + + Child = Op->Common.Value.Arg; + if ((Child->Common.AmlOpcode == AML_LEQUAL_OP) || + (Child->Common.AmlOpcode == AML_LGREATER_OP) || + (Child->Common.AmlOpcode == AML_LLESS_OP)) + { + Child->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; + Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; + } + else + { + AcpiOsPrintf ("%s", OpInfo->Name); + } + break; + + case AML_BYTE_OP: + + AcpiOsPrintf ("0x%2.2X", (UINT32) Op->Common.Value.Integer); + break; + + case AML_WORD_OP: + + if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) + { + AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); + } + else + { + AcpiOsPrintf ("0x%4.4X", (UINT32) Op->Common.Value.Integer); + } + break; + + case AML_DWORD_OP: + + if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) + { + AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); + } + else + { + AcpiOsPrintf ("0x%8.8X", (UINT32) Op->Common.Value.Integer); + } + break; + + case AML_QWORD_OP: + + AcpiOsPrintf ("0x%8.8X%8.8X", + ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); + break; + + case AML_STRING_OP: + + AcpiUtPrintString (Op->Common.Value.String, ACPI_UINT16_MAX); + + /* For _HID/_CID strings, attempt to output a descriptive comment */ + + if (Op->Common.DisasmOpcode == ACPI_DASM_HID_STRING) + { + /* If we know about the ID, emit the description */ + + IdInfo = AcpiAhMatchHardwareId (Op->Common.Value.String); + if (IdInfo) + { + AcpiOsPrintf (" /* %s */", IdInfo->Description); + } + } + break; + + case AML_BUFFER_OP: + /* + * Determine the type of buffer. We can have one of the following: + * + * 1) ResourceTemplate containing Resource Descriptors. + * 2) Unicode String buffer + * 3) ASCII String buffer + * 4) Raw data buffer (if none of the above) + * + * Since there are no special AML opcodes to differentiate these + * types of buffers, we have to closely look at the data in the + * buffer to determine the type. + */ + if (!AcpiGbl_NoResourceDisassembly) + { + Status = AcpiDmIsResourceTemplate (WalkState, Op); + if (ACPI_SUCCESS (Status)) + { + Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; + AcpiOsPrintf ("ResourceTemplate"); + break; + } + else if (Status == AE_AML_NO_RESOURCE_END_TAG) + { + AcpiOsPrintf ( + "/**** Is ResourceTemplate, " + "but EndTag not at buffer end ****/ "); + } + } + + if (AcpiDmIsUuidBuffer (Op)) + { + Op->Common.DisasmOpcode = ACPI_DASM_UUID; + AcpiOsPrintf ("ToUUID ("); + } + else if (AcpiDmIsUnicodeBuffer (Op)) + { + Op->Common.DisasmOpcode = ACPI_DASM_UNICODE; + AcpiOsPrintf ("Unicode ("); + } + else if (AcpiDmIsStringBuffer (Op)) + { + Op->Common.DisasmOpcode = ACPI_DASM_STRING; + AcpiOsPrintf ("Buffer"); + } + else if (AcpiDmIsPldBuffer (Op)) + { + Op->Common.DisasmOpcode = ACPI_DASM_PLD_METHOD; + AcpiOsPrintf ("ToPLD ("); + } + else + { + Op->Common.DisasmOpcode = ACPI_DASM_BUFFER; + AcpiOsPrintf ("Buffer"); + } + break; + + case AML_INT_NAMEPATH_OP: + + AcpiDmNamestring (Op->Common.Value.Name); + break; + + case AML_INT_NAMEDFIELD_OP: + + Length = AcpiDmDumpName (Op->Named.Name); + AcpiOsPrintf (",%*.s %u", (unsigned) (5 - Length), " ", + (UINT32) Op->Common.Value.Integer); + AcpiDmCommaIfFieldMember (Op); + + Info->BitOffset += (UINT32) Op->Common.Value.Integer; + break; + + case AML_INT_RESERVEDFIELD_OP: + + /* Offset() -- Must account for previous offsets */ + + Offset = (UINT32) Op->Common.Value.Integer; + Info->BitOffset += Offset; + + if (Info->BitOffset % 8 == 0) + { + AcpiOsPrintf ("Offset (0x%.2X)", ACPI_DIV_8 (Info->BitOffset)); + } + else + { + AcpiOsPrintf (" , %u", Offset); + } + + AcpiDmCommaIfFieldMember (Op); + break; + + case AML_INT_ACCESSFIELD_OP: + case AML_INT_EXTACCESSFIELD_OP: + + AcpiOsPrintf ("AccessAs (%s, ", + AcpiGbl_AccessTypes [(UINT32) (Op->Common.Value.Integer & 0x7)]); + + AcpiDmDecodeAttribute ((UINT8) (Op->Common.Value.Integer >> 8)); + + if (Op->Common.AmlOpcode == AML_INT_EXTACCESSFIELD_OP) + { + AcpiOsPrintf (" (0x%2.2X)", (unsigned) + ((Op->Common.Value.Integer >> 16) & 0xFF)); + } + + AcpiOsPrintf (")"); + AcpiDmCommaIfFieldMember (Op); + break; + + case AML_INT_CONNECTION_OP: + /* + * Two types of Connection() - one with a buffer object, the + * other with a namestring that points to a buffer object. + */ + AcpiOsPrintf ("Connection ("); + Child = Op->Common.Value.Arg; + + if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP) + { + AcpiOsPrintf ("\n"); + + Aml = Child->Named.Data; + Length = (UINT32) Child->Common.Value.Integer; + + Info->Level += 1; + Info->MappingOp = Op; + Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; + + AcpiDmResourceTemplate (Info, Op->Common.Parent, Aml, Length); + + Info->Level -= 1; + AcpiDmIndent (Info->Level); + } + else + { + AcpiDmNamestring (Child->Common.Value.Name); + } + + AcpiOsPrintf (")"); + AcpiDmCommaIfFieldMember (Op); + AcpiOsPrintf ("\n"); + + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; /* for now, ignore in AcpiDmAscendingOp */ + Child->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + break; + + case AML_INT_BYTELIST_OP: + + AcpiDmByteList (Info, Op); + break; + + case AML_INT_METHODCALL_OP: + + Op = AcpiPsGetDepthNext (NULL, Op); + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + + AcpiDmNamestring (Op->Common.Value.Name); + break; + + case AML_ELSE_OP: + + AcpiDmConvertToElseIf (Op); + break; + + default: + + /* Just get the opcode name and print it */ + + AcpiOsPrintf ("%s", OpInfo->Name); + + +#ifdef ACPI_DEBUGGER + + if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) && + (WalkState) && + (WalkState->Results) && + (WalkState->ResultCount)) + { + AcpiDbDecodeInternalObject ( + WalkState->Results->Results.ObjDesc [ + (WalkState->ResultCount - 1) % + ACPI_RESULTS_FRAME_OBJ_NUM]); + } +#endif + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmConvertToElseIf + * + * PARAMETERS: OriginalElseOp - ELSE Object to be examined + * + * RETURN: None. Emits either an "Else" or an "ElseIf" ASL operator. + * + * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf + * + * EXAMPLE: + * + * This If..Else..If nested sequence: + * + * If (Arg0 == 1) + * { + * Local0 = 4 + * } + * Else + * { + * If (Arg0 == 2) + * { + * Local0 = 5 + * } + * } + * + * Is converted to this simpler If..ElseIf sequence: + * + * If (Arg0 == 1) + * { + * Local0 = 4 + * } + * ElseIf (Arg0 == 2) + * { + * Local0 = 5 + * } + * + * NOTE: There is no actual ElseIf AML opcode. ElseIf is essentially an ASL + * macro that emits an Else opcode followed by an If opcode. This function + * reverses these AML sequences back to an ElseIf macro where possible. This + * can make the disassembled ASL code simpler and more like the original code. + * + ******************************************************************************/ + +static void +AcpiDmConvertToElseIf ( + ACPI_PARSE_OBJECT *OriginalElseOp) +{ + ACPI_PARSE_OBJECT *IfOp; + ACPI_PARSE_OBJECT *ElseOp; + + + /* Examine the first child of the Else */ + + IfOp = OriginalElseOp->Common.Value.Arg; + if (!IfOp || (IfOp->Common.AmlOpcode != AML_IF_OP)) + { + /* Not an Else..If sequence, cannot convert to ElseIf */ + + AcpiOsPrintf ("%s", "Else"); + return; + } + + /* Emit ElseIf, mark the IF as now an ELSEIF */ + + AcpiOsPrintf ("%s", "ElseIf"); + IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF; + + /* The IF parent will now be the same as the original ELSE parent */ + + IfOp->Common.Parent = OriginalElseOp->Common.Parent; + + /* + * Update the NEXT pointers to restructure the parse tree, essentially + * promoting an If..Else block up to the same level as the original + * Else. + * + * Check if the IF has a corresponding ELSE peer + */ + ElseOp = IfOp->Common.Next; + if (ElseOp && + (ElseOp->Common.AmlOpcode == AML_ELSE_OP)) + { + /* If an ELSE matches the IF, promote it also */ + + ElseOp->Common.Parent = OriginalElseOp->Common.Parent; + ElseOp->Common.Next = OriginalElseOp->Common.Next; + } + else + { + /* Otherwise, set the IF NEXT to the original ELSE NEXT */ + + IfOp->Common.Next = OriginalElseOp->Common.Next; + } + + /* Detach the child IF block from the original ELSE */ + + OriginalElseOp->Common.Value.Arg = NULL; + + /* Ignore the original ELSE from now on */ + + OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; + + /* Insert IF (now ELSEIF) as next peer of the original ELSE */ + + OriginalElseOp->Common.Next = IfOp; +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmresrc.c b/third_party/lib/acpica/source/components/disassembler/dmresrc.c new file mode 100644 index 000000000..8bfab9904 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmresrc.c @@ -0,0 +1,448 @@ +/******************************************************************************* + * + * Module Name: dmresrc.c - Resource Descriptor disassembly + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdisasm.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbresrc") + + +/* Dispatch tables for Resource disassembly functions */ + +static ACPI_RESOURCE_HANDLER AcpiGbl_DmResourceDispatch [] = +{ + /* Small descriptors */ + + NULL, /* 0x00, Reserved */ + NULL, /* 0x01, Reserved */ + NULL, /* 0x02, Reserved */ + NULL, /* 0x03, Reserved */ + AcpiDmIrqDescriptor, /* 0x04, ACPI_RESOURCE_NAME_IRQ_FORMAT */ + AcpiDmDmaDescriptor, /* 0x05, ACPI_RESOURCE_NAME_DMA_FORMAT */ + AcpiDmStartDependentDescriptor, /* 0x06, ACPI_RESOURCE_NAME_START_DEPENDENT */ + AcpiDmEndDependentDescriptor, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */ + AcpiDmIoDescriptor, /* 0x08, ACPI_RESOURCE_NAME_IO_PORT */ + AcpiDmFixedIoDescriptor, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO_PORT */ + AcpiDmFixedDmaDescriptor, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */ + NULL, /* 0x0B, Reserved */ + NULL, /* 0x0C, Reserved */ + NULL, /* 0x0D, Reserved */ + AcpiDmVendorSmallDescriptor, /* 0x0E, ACPI_RESOURCE_NAME_SMALL_VENDOR */ + NULL, /* 0x0F, ACPI_RESOURCE_NAME_END_TAG (not used) */ + + /* Large descriptors */ + + NULL, /* 0x00, Reserved */ + AcpiDmMemory24Descriptor, /* 0x01, ACPI_RESOURCE_NAME_MEMORY_24 */ + AcpiDmGenericRegisterDescriptor,/* 0x02, ACPI_RESOURCE_NAME_GENERIC_REGISTER */ + NULL, /* 0x03, Reserved */ + AcpiDmVendorLargeDescriptor, /* 0x04, ACPI_RESOURCE_NAME_LARGE_VENDOR */ + AcpiDmMemory32Descriptor, /* 0x05, ACPI_RESOURCE_NAME_MEMORY_32 */ + AcpiDmFixedMemory32Descriptor, /* 0x06, ACPI_RESOURCE_NAME_FIXED_MEMORY_32 */ + AcpiDmDwordDescriptor, /* 0x07, ACPI_RESOURCE_NAME_DWORD_ADDRESS_SPACE */ + AcpiDmWordDescriptor, /* 0x08, ACPI_RESOURCE_NAME_WORD_ADDRESS_SPACE */ + AcpiDmInterruptDescriptor, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_XRUPT */ + AcpiDmQwordDescriptor, /* 0x0A, ACPI_RESOURCE_NAME_QWORD_ADDRESS_SPACE */ + AcpiDmExtendedDescriptor, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS_SPACE */ + AcpiDmGpioDescriptor, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ + NULL, /* 0x0D, Reserved */ + AcpiDmSerialBusDescriptor /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS */ +}; + + +/* Only used for single-threaded applications */ +/* TBD: remove when name is passed as parameter to the dump functions */ + +static UINT32 ResourceName; + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDescriptorName + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Emit a name for the descriptor if one is present (indicated + * by the name being changed from the default name.) A name is only + * emitted if a reference to the descriptor has been made somewhere + * in the original ASL code. + * + ******************************************************************************/ + +void +AcpiDmDescriptorName ( + void) +{ + + if (ResourceName == ACPI_DEFAULT_RESNAME) + { + return; + } + + AcpiOsPrintf ("%4.4s", (char *) &ResourceName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpInteger* + * + * PARAMETERS: Value - Value to emit + * Name - Associated name (emitted as a comment) + * + * RETURN: None + * + * DESCRIPTION: Integer output helper functions + * + ******************************************************************************/ + +void +AcpiDmDumpInteger8 ( + UINT8 Value, + char *Name) +{ + AcpiOsPrintf ("0x%2.2X, // %s\n", Value, Name); +} + +void +AcpiDmDumpInteger16 ( + UINT16 Value, + char *Name) +{ + AcpiOsPrintf ("0x%4.4X, // %s\n", Value, Name); +} + +void +AcpiDmDumpInteger32 ( + UINT32 Value, + char *Name) +{ + AcpiOsPrintf ("0x%8.8X, // %s\n", Value, Name); +} + +void +AcpiDmDumpInteger64 ( + UINT64 Value, + char *Name) +{ + AcpiOsPrintf ("0x%8.8X%8.8X, // %s\n", ACPI_FORMAT_UINT64 (Value), Name); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmBitList + * + * PARAMETERS: Mask - 16-bit value corresponding to 16 interrupt + * or DMA values + * + * RETURN: None + * + * DESCRIPTION: Dump a bit mask as a list of individual interrupt/DMA levels. + * + ******************************************************************************/ + +void +AcpiDmBitList ( + UINT16 Mask) +{ + UINT32 i; + BOOLEAN Previous = FALSE; + + + /* Open the initializer list */ + + AcpiOsPrintf ("{"); + + /* Examine each bit */ + + for (i = 0; i < 16; i++) + { + /* Only interested in bits that are set to 1 */ + + if (Mask & 1) + { + if (Previous) + { + AcpiOsPrintf (","); + } + + Previous = TRUE; + AcpiOsPrintf ("%u", i); + } + + Mask >>= 1; + } + + /* Close list */ + + AcpiOsPrintf ("}\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmResourceTemplate + * + * PARAMETERS: Info - Curent parse tree walk info + * ByteData - Pointer to the byte list data + * ByteCount - Length of the byte list + * + * RETURN: None + * + * DESCRIPTION: Dump the contents of a Resource Template containing a set of + * Resource Descriptors. + * + ******************************************************************************/ + +void +AcpiDmResourceTemplate ( + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op, + UINT8 *ByteData, + UINT32 ByteCount) +{ + ACPI_STATUS Status; + UINT32 CurrentByteOffset; + UINT8 ResourceType; + UINT32 ResourceLength; + void *Aml; + UINT32 Level; + BOOLEAN DependentFns = FALSE; + UINT8 ResourceIndex; + ACPI_NAMESPACE_NODE *Node; + + + if (Op->Asl.AmlOpcode != AML_FIELD_OP) + { + Info->MappingOp = Op; + } + + Level = Info->Level; + ResourceName = ACPI_DEFAULT_RESNAME; + Node = Op->Common.Node; + if (Node) + { + Node = Node->Child; + } + + for (CurrentByteOffset = 0; CurrentByteOffset < ByteCount;) + { + Aml = &ByteData[CurrentByteOffset]; + + /* Get the descriptor type and length */ + + ResourceType = AcpiUtGetResourceType (Aml); + ResourceLength = AcpiUtGetResourceLength (Aml); + + /* Validate the Resource Type and Resource Length */ + + Status = AcpiUtValidateResource (NULL, Aml, &ResourceIndex); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ( + "/*** Could not validate Resource, type (%X) %s***/\n", + ResourceType, AcpiFormatException (Status)); + return; + } + + /* Point to next descriptor */ + + CurrentByteOffset += AcpiUtGetDescriptorLength (Aml); + + /* Descriptor pre-processing */ + + switch (ResourceType) + { + case ACPI_RESOURCE_NAME_START_DEPENDENT: + + /* Finish a previous StartDependentFns */ + + if (DependentFns) + { + Level--; + AcpiDmIndent (Level); + AcpiOsPrintf ("}\n"); + } + break; + + case ACPI_RESOURCE_NAME_END_DEPENDENT: + + Level--; + DependentFns = FALSE; + break; + + case ACPI_RESOURCE_NAME_END_TAG: + + /* Normal exit, the resource list is finished */ + + if (DependentFns) + { + /* + * Close an open StartDependentDescriptor. This indicates a + * missing EndDependentDescriptor. + */ + Level--; + DependentFns = FALSE; + + /* Go ahead and insert EndDependentFn() */ + + AcpiDmEndDependentDescriptor (Info, Aml, ResourceLength, Level); + + AcpiDmIndent (Level); + AcpiOsPrintf ( + "/*** Disassembler: inserted " + "missing EndDependentFn () ***/\n"); + } + return; + + default: + + break; + } + + /* Disassemble the resource structure */ + + if (Node) + { + ResourceName = Node->Name.Integer; + Node = Node->Peer; + } + + AcpiGbl_DmResourceDispatch [ResourceIndex] ( + Info, Aml, ResourceLength, Level); + + /* Descriptor post-processing */ + + if (ResourceType == ACPI_RESOURCE_NAME_START_DEPENDENT) + { + DependentFns = TRUE; + Level++; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIsResourceTemplate + * + * PARAMETERS: WalkState - Current walk info + * Op - Buffer Op to be examined + * + * RETURN: Status. AE_OK if valid template + * + * DESCRIPTION: Walk a byte list to determine if it consists of a valid set + * of resource descriptors. Nothing is output. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDmIsResourceTemplate ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *NextOp; + UINT8 *Aml; + UINT8 *EndAml; + ACPI_SIZE Length; + + + /* This op must be a buffer */ + + if (Op->Common.AmlOpcode != AML_BUFFER_OP) + { + return (AE_TYPE); + } + + /* Get the ByteData list and length */ + + NextOp = Op->Common.Value.Arg; + if (!NextOp) + { + AcpiOsPrintf ("NULL byte list in buffer\n"); + return (AE_TYPE); + } + + NextOp = NextOp->Common.Next; + if (!NextOp) + { + return (AE_TYPE); + } + + Aml = NextOp->Named.Data; + Length = (ACPI_SIZE) NextOp->Common.Value.Integer; + + /* Walk the byte list, abort on any invalid descriptor type or length */ + + Status = AcpiUtWalkAmlResources (WalkState, Aml, Length, + NULL, ACPI_CAST_INDIRECT_PTR (void, &EndAml)); + if (ACPI_FAILURE (Status)) + { + return (AE_TYPE); + } + + /* + * For the resource template to be valid, one EndTag must appear + * at the very end of the ByteList, not before. (For proper disassembly + * of a ResourceTemplate, the buffer must not have any extra data after + * the EndTag.) + */ + if ((Aml + Length - sizeof (AML_RESOURCE_END_TAG)) != EndAml) + { + return (AE_AML_NO_RESOURCE_END_TAG); + } + + /* + * All resource descriptors are valid, therefore this list appears + * to be a valid resource template + */ + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmresrcl.c b/third_party/lib/acpica/source/components/disassembler/dmresrcl.c new file mode 100644 index 000000000..89071c649 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmresrcl.c @@ -0,0 +1,1085 @@ +/******************************************************************************* + * + * Module Name: dmresrcl.c - "Large" Resource Descriptor disassembly + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdisasm.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbresrcl") + + +/* Common names for address and memory descriptors */ + +static char *AcpiDmAddressNames[] = +{ + "Granularity", + "Range Minimum", + "Range Maximum", + "Translation Offset", + "Length" +}; + +static char *AcpiDmMemoryNames[] = +{ + "Range Minimum", + "Range Maximum", + "Alignment", + "Length" +}; + + +/* Local prototypes */ + +static void +AcpiDmSpaceFlags ( + UINT8 Flags); + +static void +AcpiDmIoFlags ( + UINT8 Flags); + +static void +AcpiDmIoFlags2 ( + UINT8 SpecificFlags); + +static void +AcpiDmMemoryFlags ( + UINT8 Flags, + UINT8 SpecificFlags); + +static void +AcpiDmMemoryFlags2 ( + UINT8 SpecificFlags); + +static void +AcpiDmResourceSource ( + AML_RESOURCE *Resource, + ACPI_SIZE MinimumLength, + UINT32 Length); + +static void +AcpiDmAddressFields ( + void *Source, + UINT8 Type, + UINT32 Level); + +static void +AcpiDmAddressPrefix ( + UINT8 Type); + +static void +AcpiDmAddressCommon ( + AML_RESOURCE *Resource, + UINT8 Type, + UINT32 Level); + +static void +AcpiDmAddressFlags ( + AML_RESOURCE *Resource); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMemoryFields + * + * PARAMETERS: Source - Pointer to the contiguous data fields + * Type - 16 or 32 (bit) + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode fields common to Memory24 and Memory32 descriptors + * + ******************************************************************************/ + +static void +AcpiDmMemoryFields ( + void *Source, + UINT8 Type, + UINT32 Level) +{ + UINT32 i; + + + for (i = 0; i < 4; i++) + { + AcpiDmIndent (Level + 1); + + switch (Type) + { + case 16: + + AcpiDmDumpInteger16 (ACPI_CAST_PTR (UINT16, Source)[i], + AcpiDmMemoryNames[i]); + break; + + case 32: + + AcpiDmDumpInteger32 (ACPI_CAST_PTR (UINT32, Source)[i], + AcpiDmMemoryNames[i]); + break; + + default: + + return; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddressFields + * + * PARAMETERS: Source - Pointer to the contiguous data fields + * Type - 16, 32, or 64 (bit) + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode fields common to address descriptors + * + ******************************************************************************/ + +static void +AcpiDmAddressFields ( + void *Source, + UINT8 Type, + UINT32 Level) +{ + UINT32 i; + + + AcpiOsPrintf ("\n"); + + for (i = 0; i < 5; i++) + { + AcpiDmIndent (Level + 1); + + switch (Type) + { + case 16: + + AcpiDmDumpInteger16 (ACPI_CAST_PTR (UINT16, Source)[i], + AcpiDmAddressNames[i]); + break; + + case 32: + + AcpiDmDumpInteger32 (ACPI_CAST_PTR (UINT32, Source)[i], + AcpiDmAddressNames[i]); + break; + + case 64: + + AcpiDmDumpInteger64 (ACPI_CAST_PTR (UINT64, Source)[i], + AcpiDmAddressNames[i]); + break; + + default: + + return; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddressPrefix + * + * PARAMETERS: Type - Descriptor type + * + * RETURN: None + * + * DESCRIPTION: Emit name prefix representing the address descriptor type + * + ******************************************************************************/ + +static void +AcpiDmAddressPrefix ( + UINT8 Type) +{ + + switch (Type) + { + case ACPI_RESOURCE_TYPE_ADDRESS16: + + AcpiOsPrintf ("Word"); + break; + + case ACPI_RESOURCE_TYPE_ADDRESS32: + + AcpiOsPrintf ("DWord"); + break; + + case ACPI_RESOURCE_TYPE_ADDRESS64: + + AcpiOsPrintf ("QWord"); + break; + + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + + AcpiOsPrintf ("Extended"); + break; + + default: + + return; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddressCommon + * + * PARAMETERS: Resource - Raw AML descriptor + * Type - Descriptor type + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Emit common name and flag fields common to address descriptors + * + ******************************************************************************/ + +static void +AcpiDmAddressCommon ( + AML_RESOURCE *Resource, + UINT8 Type, + UINT32 Level) +{ + UINT8 ResourceType; + UINT8 SpecificFlags; + UINT8 Flags; + + + ResourceType = Resource->Address.ResourceType; + SpecificFlags = Resource->Address.SpecificFlags; + Flags = Resource->Address.Flags; + + AcpiDmIndent (Level); + + /* Validate ResourceType */ + + if ((ResourceType > 2) && (ResourceType < 0xC0)) + { + AcpiOsPrintf ( + "/**** Invalid Resource Type: 0x%X ****/", ResourceType); + return; + } + + /* Prefix is either Word, DWord, QWord, or Extended */ + + AcpiDmAddressPrefix (Type); + + /* Resource Types above 0xC0 are vendor-defined */ + + if (ResourceType > 2) + { + AcpiOsPrintf ("Space (0x%2.2X, ", ResourceType); + AcpiDmSpaceFlags (Flags); + AcpiOsPrintf (" 0x%2.2X,", SpecificFlags); + return; + } + + /* This is either a Memory, IO, or BusNumber descriptor (0,1,2) */ + + AcpiOsPrintf ("%s (", + AcpiGbl_WordDecode [ACPI_GET_2BIT_FLAG (ResourceType)]); + + /* Decode the general and type-specific flags */ + + if (ResourceType == ACPI_MEMORY_RANGE) + { + AcpiDmMemoryFlags (Flags, SpecificFlags); + } + else /* IO range or BusNumberRange */ + { + AcpiDmIoFlags (Flags); + if (ResourceType == ACPI_IO_RANGE) + { + AcpiOsPrintf (" %s,", + AcpiGbl_RngDecode [ACPI_GET_2BIT_FLAG (SpecificFlags)]); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAddressFlags + * + * PARAMETERS: Resource - Raw AML descriptor + * + * RETURN: None + * + * DESCRIPTION: Emit flags common to address descriptors + * + ******************************************************************************/ + +static void +AcpiDmAddressFlags ( + AML_RESOURCE *Resource) +{ + + if (Resource->Address.ResourceType == ACPI_IO_RANGE) + { + AcpiDmIoFlags2 (Resource->Address.SpecificFlags); + } + else if (Resource->Address.ResourceType == ACPI_MEMORY_RANGE) + { + AcpiDmMemoryFlags2 (Resource->Address.SpecificFlags); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmSpaceFlags + * + * PARAMETERS: Flags - Flag byte to be decoded + * + * RETURN: None + * + * DESCRIPTION: Decode the flags specific to Space Address space descriptors + * + ******************************************************************************/ + +static void +AcpiDmSpaceFlags ( + UINT8 Flags) +{ + + AcpiOsPrintf ("%s, %s, %s, %s,", + AcpiGbl_ConsumeDecode [ACPI_GET_1BIT_FLAG (Flags)], + AcpiGbl_DecDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 1)], + AcpiGbl_MinDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 2)], + AcpiGbl_MaxDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 3)]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIoFlags + * + * PARAMETERS: Flags - Flag byte to be decoded + * + * RETURN: None + * + * DESCRIPTION: Decode the flags specific to IO Address space descriptors + * + ******************************************************************************/ + +static void +AcpiDmIoFlags ( + UINT8 Flags) +{ + AcpiOsPrintf ("%s, %s, %s, %s,", + AcpiGbl_ConsumeDecode [ACPI_GET_1BIT_FLAG (Flags)], + AcpiGbl_MinDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 2)], + AcpiGbl_MaxDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 3)], + AcpiGbl_DecDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 1)]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIoFlags2 + * + * PARAMETERS: SpecificFlags - "Specific" flag byte to be decoded + * + * RETURN: None + * + * DESCRIPTION: Decode the flags specific to IO Address space descriptors + * + ******************************************************************************/ + +static void +AcpiDmIoFlags2 ( + UINT8 SpecificFlags) +{ + + AcpiOsPrintf (", %s", + AcpiGbl_TtpDecode [ACPI_EXTRACT_1BIT_FLAG (SpecificFlags, 4)]); + + /* TRS is only used if TTP is TypeTranslation */ + + if (SpecificFlags & 0x10) + { + AcpiOsPrintf (", %s", + AcpiGbl_TrsDecode [ACPI_EXTRACT_1BIT_FLAG (SpecificFlags, 5)]); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMemoryFlags + * + * PARAMETERS: Flags - Flag byte to be decoded + * SpecificFlags - "Specific" flag byte to be decoded + * + * RETURN: None + * + * DESCRIPTION: Decode flags specific to Memory Address Space descriptors + * + ******************************************************************************/ + +static void +AcpiDmMemoryFlags ( + UINT8 Flags, + UINT8 SpecificFlags) +{ + + AcpiOsPrintf ("%s, %s, %s, %s, %s, %s,", + AcpiGbl_ConsumeDecode [ACPI_GET_1BIT_FLAG (Flags)], + AcpiGbl_DecDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 1)], + AcpiGbl_MinDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 2)], + AcpiGbl_MaxDecode [ACPI_EXTRACT_1BIT_FLAG (Flags, 3)], + AcpiGbl_MemDecode [ACPI_EXTRACT_2BIT_FLAG (SpecificFlags, 1)], + AcpiGbl_RwDecode [ACPI_GET_1BIT_FLAG (SpecificFlags)]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMemoryFlags2 + * + * PARAMETERS: SpecificFlags - "Specific" flag byte to be decoded + * + * RETURN: None + * + * DESCRIPTION: Decode flags specific to Memory Address Space descriptors + * + ******************************************************************************/ + +static void +AcpiDmMemoryFlags2 ( + UINT8 SpecificFlags) +{ + + AcpiOsPrintf (", %s, %s", + AcpiGbl_MtpDecode [ACPI_EXTRACT_2BIT_FLAG (SpecificFlags, 3)], + AcpiGbl_TtpDecode [ACPI_EXTRACT_1BIT_FLAG (SpecificFlags, 5)]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmResourceSource + * + * PARAMETERS: Resource - Raw AML descriptor + * MinimumLength - descriptor length without optional fields + * ResourceLength + * + * RETURN: None + * + * DESCRIPTION: Dump optional ResourceSource fields of an address descriptor + * + ******************************************************************************/ + +static void +AcpiDmResourceSource ( + AML_RESOURCE *Resource, + ACPI_SIZE MinimumTotalLength, + UINT32 ResourceLength) +{ + UINT8 *AmlResourceSource; + UINT32 TotalLength; + + + TotalLength = ResourceLength + sizeof (AML_RESOURCE_LARGE_HEADER); + + /* Check if the optional ResourceSource fields are present */ + + if (TotalLength <= MinimumTotalLength) + { + /* The two optional fields are not used */ + + AcpiOsPrintf (",, "); + return; + } + + /* Get a pointer to the ResourceSource */ + + AmlResourceSource = ACPI_ADD_PTR (UINT8, Resource, MinimumTotalLength); + + /* + * Always emit the ResourceSourceIndex (Byte) + * + * NOTE: Some ASL compilers always create a 0 byte (in the AML) for the + * Index even if the String does not exist. Although this is in violation + * of the ACPI specification, it is very important to emit ASL code that + * can be compiled back to the identical AML. There may be fields and/or + * indexes into the resource template buffer that are compiled to absolute + * offsets, and these will be broken if the AML length is changed. + */ + AcpiOsPrintf ("0x%2.2X,", (UINT32) AmlResourceSource[0]); + + /* Make sure that the ResourceSource string exists before dumping it */ + + if (TotalLength > (MinimumTotalLength + 1)) + { + AcpiOsPrintf (" "); + AcpiUtPrintString ((char *) &AmlResourceSource[1], ACPI_UINT16_MAX); + } + + AcpiOsPrintf (", "); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmWordDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Word Address Space descriptor + * + ******************************************************************************/ + +void +AcpiDmWordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump resource name and flags */ + + AcpiDmAddressCommon (Resource, ACPI_RESOURCE_TYPE_ADDRESS16, Level); + + /* Dump the 5 contiguous WORD values */ + + AcpiDmAddressFields (&Resource->Address16.Granularity, 16, Level); + + /* The ResourceSource fields are optional */ + + AcpiDmIndent (Level + 1); + AcpiDmResourceSource (Resource, sizeof (AML_RESOURCE_ADDRESS16), Length); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + + /* Type-specific flags */ + + AcpiDmAddressFlags (Resource); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDwordDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a DWord Address Space descriptor + * + ******************************************************************************/ + +void +AcpiDmDwordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump resource name and flags */ + + AcpiDmAddressCommon (Resource, ACPI_RESOURCE_TYPE_ADDRESS32, Level); + + /* Dump the 5 contiguous DWORD values */ + + AcpiDmAddressFields (&Resource->Address32.Granularity, 32, Level); + + /* The ResourceSource fields are optional */ + + AcpiDmIndent (Level + 1); + AcpiDmResourceSource (Resource, sizeof (AML_RESOURCE_ADDRESS32), Length); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + + /* Type-specific flags */ + + AcpiDmAddressFlags (Resource); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmQwordDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a QWord Address Space descriptor + * + ******************************************************************************/ + +void +AcpiDmQwordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump resource name and flags */ + + AcpiDmAddressCommon (Resource, ACPI_RESOURCE_TYPE_ADDRESS64, Level); + + /* Dump the 5 contiguous QWORD values */ + + AcpiDmAddressFields (&Resource->Address64.Granularity, 64, Level); + + /* The ResourceSource fields are optional */ + + AcpiDmIndent (Level + 1); + AcpiDmResourceSource (Resource, sizeof (AML_RESOURCE_ADDRESS64), Length); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + + /* Type-specific flags */ + + AcpiDmAddressFlags (Resource); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmExtendedDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Extended Address Space descriptor + * + ******************************************************************************/ + +void +AcpiDmExtendedDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump resource name and flags */ + + AcpiDmAddressCommon ( + Resource, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64, Level); + + /* Dump the 5 contiguous QWORD values */ + + AcpiDmAddressFields (&Resource->ExtAddress64.Granularity, 64, Level); + + /* Extra field for this descriptor only */ + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger64 (Resource->ExtAddress64.TypeSpecific, + "Type-Specific Attributes"); + + /* Insert a descriptor name */ + + AcpiDmIndent (Level + 1); + AcpiDmDescriptorName (); + + /* Type-specific flags */ + + AcpiDmAddressFlags (Resource); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMemory24Descriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Memory24 descriptor + * + ******************************************************************************/ + +void +AcpiDmMemory24Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump name and read/write flag */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("Memory24 (%s,\n", + AcpiGbl_RwDecode [ACPI_GET_1BIT_FLAG (Resource->Memory24.Flags)]); + + /* Dump the 4 contiguous WORD values */ + + AcpiDmMemoryFields (&Resource->Memory24.Minimum, 16, Level); + + /* Insert a descriptor name */ + + AcpiDmIndent (Level + 1); + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmMemory32Descriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Memory32 descriptor + * + ******************************************************************************/ + +void +AcpiDmMemory32Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump name and read/write flag */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("Memory32 (%s,\n", + AcpiGbl_RwDecode [ACPI_GET_1BIT_FLAG (Resource->Memory32.Flags)]); + + /* Dump the 4 contiguous DWORD values */ + + AcpiDmMemoryFields (&Resource->Memory32.Minimum, 32, Level); + + /* Insert a descriptor name */ + + AcpiDmIndent (Level + 1); + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFixedMemory32Descriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Fixed Memory32 descriptor + * + ******************************************************************************/ + +void +AcpiDmFixedMemory32Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump name and read/write flag */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("Memory32Fixed (%s,\n", + AcpiGbl_RwDecode [ACPI_GET_1BIT_FLAG (Resource->FixedMemory32.Flags)]); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger32 (Resource->FixedMemory32.Address, + "Address Base"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger32 (Resource->FixedMemory32.AddressLength, + "Address Length"); + + /* Insert a descriptor name */ + + AcpiDmIndent (Level + 1); + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGenericRegisterDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Generic Register descriptor + * + ******************************************************************************/ + +void +AcpiDmGenericRegisterDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("Register ("); + AcpiDmAddressSpace (Resource->GenericReg.AddressSpaceId); + AcpiOsPrintf ("\n"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger8 (Resource->GenericReg.BitWidth, "Bit Width"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger8 (Resource->GenericReg.BitOffset, "Bit Offset"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger64 (Resource->GenericReg.Address, "Address"); + + /* Optional field for ACPI 3.0 */ + + AcpiDmIndent (Level + 1); + if (Resource->GenericReg.AccessSize) + { + AcpiOsPrintf ("0x%2.2X, // %s\n", + Resource->GenericReg.AccessSize, "Access Size"); + AcpiDmIndent (Level + 1); + } + else + { + AcpiOsPrintf (","); + } + + /* DescriptorName was added for ACPI 3.0+ */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmInterruptDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a extended Interrupt descriptor + * + ******************************************************************************/ + +void +AcpiDmInterruptDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + UINT32 i; + + + AcpiDmIndent (Level); + AcpiOsPrintf ("Interrupt (%s, %s, %s, %s, ", + AcpiGbl_ConsumeDecode [ACPI_GET_1BIT_FLAG (Resource->ExtendedIrq.Flags)], + AcpiGbl_HeDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->ExtendedIrq.Flags, 1)], + AcpiGbl_LlDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->ExtendedIrq.Flags, 2)], + AcpiGbl_ShrDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->ExtendedIrq.Flags, 3)]); + + /* + * The ResourceSource fields are optional and appear after the interrupt + * list. Must compute length based on length of the list. First xrupt + * is included in the struct (reason for -1 below) + */ + AcpiDmResourceSource (Resource, + sizeof (AML_RESOURCE_EXTENDED_IRQ) + + ((UINT32) Resource->ExtendedIrq.InterruptCount - 1) * sizeof (UINT32), + Resource->ExtendedIrq.ResourceLength); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); + + /* Dump the interrupt list */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("{\n"); + for (i = 0; i < Resource->ExtendedIrq.InterruptCount; i++) + { + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("0x%8.8X,\n", + (UINT32) Resource->ExtendedIrq.Interrupts[i]); + } + + AcpiDmIndent (Level); + AcpiOsPrintf ("}\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmVendorCommon + * + * PARAMETERS: Name - Descriptor name suffix + * ByteData - Pointer to the vendor byte data + * Length - Length of the byte data + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Vendor descriptor, both Large and Small + * + ******************************************************************************/ + +void +AcpiDmVendorCommon ( + char *Name, + UINT8 *ByteData, + UINT32 Length, + UINT32 Level) +{ + + /* Dump macro name */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("Vendor%s (", Name); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (") // Length = 0x%.2X\n", Length); + + /* Dump the vendor bytes */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("{\n"); + + AcpiDmDisasmByteList (Level + 1, ByteData, Length); + + AcpiDmIndent (Level); + AcpiOsPrintf ("}\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmVendorLargeDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Vendor Large descriptor + * + ******************************************************************************/ + +void +AcpiDmVendorLargeDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmVendorCommon ("Long ", + ACPI_ADD_PTR (UINT8, Resource, sizeof (AML_RESOURCE_LARGE_HEADER)), + Length, Level); +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmresrcl2.c b/third_party/lib/acpica/source/components/disassembler/dmresrcl2.c new file mode 100644 index 000000000..da56e4f1a --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmresrcl2.c @@ -0,0 +1,730 @@ +/******************************************************************************* + * + * Module Name: dmresrcl2.c - "Large" Resource Descriptor disassembly (#2) + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdisasm.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbresrcl2") + +/* Local prototypes */ + +static void +AcpiDmI2cSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +static void +AcpiDmSpiSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +static void +AcpiDmUartSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +static void +AcpiDmGpioCommon ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Level); + +static void +AcpiDmDumpRawDataBuffer ( + UINT8 *Buffer, + UINT32 Length, + UINT32 Level); + + +/* Dispatch table for the serial bus descriptors */ + +static ACPI_RESOURCE_HANDLER SerialBusResourceDispatch [] = +{ + NULL, + AcpiDmI2cSerialBusDescriptor, + AcpiDmSpiSerialBusDescriptor, + AcpiDmUartSerialBusDescriptor +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpRawDataBuffer + * + * PARAMETERS: Buffer - Pointer to the data bytes + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Dump a data buffer as a RawDataBuffer() object. Used for + * vendor data bytes. + * + ******************************************************************************/ + +static void +AcpiDmDumpRawDataBuffer ( + UINT8 *Buffer, + UINT32 Length, + UINT32 Level) +{ + UINT32 Index; + UINT32 i; + UINT32 j; + + + if (!Length) + { + return; + } + + AcpiOsPrintf ("RawDataBuffer (0x%.2X) // Vendor Data", Length); + + AcpiOsPrintf ("\n"); + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("{\n"); + AcpiDmIndent (Level + 2); + + for (i = 0; i < Length;) + { + for (j = 0; j < 8; j++) + { + Index = i + j; + if (Index >= Length) + { + goto Finish; + } + + AcpiOsPrintf ("0x%2.2X", Buffer[Index]); + if ((Index + 1) >= Length) + { + goto Finish; + } + + AcpiOsPrintf (", "); + } + + AcpiOsPrintf ("\n"); + AcpiDmIndent (Level + 2); + + i += 8; + } + +Finish: + AcpiOsPrintf ("\n"); + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("}"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGpioCommon + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode common parts of a GPIO Interrupt descriptor + * + ******************************************************************************/ + +static void +AcpiDmGpioCommon ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Level) +{ + UINT16 *PinList; + UINT8 *VendorData; + char *DeviceName = NULL; + UINT32 PinCount; + UINT32 i; + + + /* ResourceSource, ResourceSourceIndex, ResourceType */ + + AcpiDmIndent (Level + 1); + if (Resource->Gpio.ResSourceOffset) + { + DeviceName = ACPI_ADD_PTR (char, + Resource, Resource->Gpio.ResSourceOffset), + AcpiUtPrintString (DeviceName, ACPI_UINT16_MAX); + } + + AcpiOsPrintf (", "); + AcpiOsPrintf ("0x%2.2X, ", Resource->Gpio.ResSourceIndex); + AcpiOsPrintf ("%s, ", + AcpiGbl_ConsumeDecode [ACPI_GET_1BIT_FLAG (Resource->Gpio.Flags)]); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (","); + + /* Dump the vendor data */ + + if (Resource->Gpio.VendorOffset) + { + AcpiOsPrintf ("\n"); + AcpiDmIndent (Level + 1); + VendorData = ACPI_ADD_PTR (UINT8, Resource, + Resource->Gpio.VendorOffset); + + AcpiDmDumpRawDataBuffer (VendorData, + Resource->Gpio.VendorLength, Level); + } + + AcpiOsPrintf (")\n"); + + /* Dump the interrupt list */ + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("{ // Pin list\n"); + + PinCount = ((UINT32) (Resource->Gpio.ResSourceOffset - + Resource->Gpio.PinTableOffset)) / + sizeof (UINT16); + + PinList = (UINT16 *) ACPI_ADD_PTR (char, Resource, + Resource->Gpio.PinTableOffset); + + for (i = 0; i < PinCount; i++) + { + AcpiDmIndent (Level + 2); + AcpiOsPrintf ("0x%4.4X%s\n", PinList[i], + ((i + 1) < PinCount) ? "," : ""); + } + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("}\n"); + + MpSaveGpioInfo (Info->MappingOp, Resource, + PinCount, PinList, DeviceName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGpioIntDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a GPIO Interrupt descriptor + * + ******************************************************************************/ + +static void +AcpiDmGpioIntDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump the GpioInt-specific portion of the descriptor */ + + /* EdgeLevel, ActiveLevel, Shared */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("GpioInt (%s, %s, %s, ", + AcpiGbl_HeDecode [ACPI_GET_1BIT_FLAG (Resource->Gpio.IntFlags)], + AcpiGbl_LlDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->Gpio.IntFlags, 1)], + AcpiGbl_ShrDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->Gpio.IntFlags, 3)]); + + /* PinConfig, DebounceTimeout */ + + if (Resource->Gpio.PinConfig <= 3) + { + AcpiOsPrintf ("%s, ", + AcpiGbl_PpcDecode[Resource->Gpio.PinConfig]); + } + else + { + AcpiOsPrintf ("0x%2.2X, ", Resource->Gpio.PinConfig); + } + AcpiOsPrintf ("0x%4.4X,\n", Resource->Gpio.DebounceTimeout); + + /* Dump the GpioInt/GpioIo common portion of the descriptor */ + + AcpiDmGpioCommon (Info, Resource, Level); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGpioIoDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a GPIO I/O descriptor + * + ******************************************************************************/ + +static void +AcpiDmGpioIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + /* Dump the GpioIo-specific portion of the descriptor */ + + /* Shared, PinConfig */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("GpioIo (%s, ", + AcpiGbl_ShrDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->Gpio.IntFlags, 3)]); + + if (Resource->Gpio.PinConfig <= 3) + { + AcpiOsPrintf ("%s, ", + AcpiGbl_PpcDecode[Resource->Gpio.PinConfig]); + } + else + { + AcpiOsPrintf ("0x%2.2X, ", Resource->Gpio.PinConfig); + } + + /* DebounceTimeout, DriveStrength, IoRestriction */ + + AcpiOsPrintf ("0x%4.4X, ", Resource->Gpio.DebounceTimeout); + AcpiOsPrintf ("0x%4.4X, ", Resource->Gpio.DriveStrength); + AcpiOsPrintf ("%s,\n", + AcpiGbl_IorDecode [ACPI_GET_2BIT_FLAG (Resource->Gpio.IntFlags)]); + + /* Dump the GpioInt/GpioIo common portion of the descriptor */ + + AcpiDmGpioCommon (Info, Resource, Level); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmGpioDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a GpioInt/GpioIo GPIO Interrupt/IO descriptor + * + ******************************************************************************/ + +void +AcpiDmGpioDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + UINT8 ConnectionType; + + + ConnectionType = Resource->Gpio.ConnectionType; + + switch (ConnectionType) + { + case AML_RESOURCE_GPIO_TYPE_INT: + + AcpiDmGpioIntDescriptor (Info, Resource, Length, Level); + break; + + case AML_RESOURCE_GPIO_TYPE_IO: + + AcpiDmGpioIoDescriptor (Info, Resource, Length, Level); + break; + + default: + + AcpiOsPrintf ("Unknown GPIO type\n"); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDumpSerialBusVendorData + * + * PARAMETERS: Resource - Pointer to the resource descriptor + * + * RETURN: None + * + * DESCRIPTION: Dump optional serial bus vendor data + * + ******************************************************************************/ + +static void +AcpiDmDumpSerialBusVendorData ( + AML_RESOURCE *Resource, + UINT32 Level) +{ + UINT8 *VendorData; + UINT32 VendorLength; + + + /* Get the (optional) vendor data and length */ + + switch (Resource->CommonSerialBus.Type) + { + case AML_RESOURCE_I2C_SERIALBUSTYPE: + + VendorLength = Resource->CommonSerialBus.TypeDataLength - + AML_RESOURCE_I2C_MIN_DATA_LEN; + + VendorData = ACPI_ADD_PTR (UINT8, Resource, + sizeof (AML_RESOURCE_I2C_SERIALBUS)); + break; + + case AML_RESOURCE_SPI_SERIALBUSTYPE: + + VendorLength = Resource->CommonSerialBus.TypeDataLength - + AML_RESOURCE_SPI_MIN_DATA_LEN; + + VendorData = ACPI_ADD_PTR (UINT8, Resource, + sizeof (AML_RESOURCE_SPI_SERIALBUS)); + break; + + case AML_RESOURCE_UART_SERIALBUSTYPE: + + VendorLength = Resource->CommonSerialBus.TypeDataLength - + AML_RESOURCE_UART_MIN_DATA_LEN; + + VendorData = ACPI_ADD_PTR (UINT8, Resource, + sizeof (AML_RESOURCE_UART_SERIALBUS)); + break; + + default: + + return; + } + + /* Dump the vendor bytes as a RawDataBuffer object */ + + AcpiDmDumpRawDataBuffer (VendorData, VendorLength, Level); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmI2cSerialBusDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a I2C serial bus descriptor + * + ******************************************************************************/ + +static void +AcpiDmI2cSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + UINT32 ResourceSourceOffset; + char *DeviceName; + + + /* SlaveAddress, SlaveMode, ConnectionSpeed, AddressingMode */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("I2cSerialBus (0x%4.4X, %s, 0x%8.8X,\n", + Resource->I2cSerialBus.SlaveAddress, + AcpiGbl_SmDecode [ACPI_GET_1BIT_FLAG (Resource->I2cSerialBus.Flags)], + Resource->I2cSerialBus.ConnectionSpeed); + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("%s, ", + AcpiGbl_AmDecode [ACPI_GET_1BIT_FLAG (Resource->I2cSerialBus.TypeSpecificFlags)]); + + /* ResourceSource is a required field */ + + ResourceSourceOffset = sizeof (AML_RESOURCE_COMMON_SERIALBUS) + + Resource->CommonSerialBus.TypeDataLength; + + DeviceName = ACPI_ADD_PTR (char, Resource, ResourceSourceOffset), + AcpiUtPrintString (DeviceName, ACPI_UINT16_MAX); + + /* ResourceSourceIndex, ResourceUsage */ + + AcpiOsPrintf (",\n"); + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("0x%2.2X, ", Resource->I2cSerialBus.ResSourceIndex); + + AcpiOsPrintf ("%s, ", + AcpiGbl_ConsumeDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->I2cSerialBus.Flags, 1)]); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (",\n"); + + /* Dump the vendor data */ + + AcpiDmIndent (Level + 1); + AcpiDmDumpSerialBusVendorData (Resource, Level); + AcpiOsPrintf (")\n"); + + MpSaveSerialInfo (Info->MappingOp, Resource, DeviceName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmSpiSerialBusDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a SPI serial bus descriptor + * + ******************************************************************************/ + +static void +AcpiDmSpiSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + UINT32 ResourceSourceOffset; + char *DeviceName; + + + /* DeviceSelection, DeviceSelectionPolarity, WireMode, DataBitLength */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("SpiSerialBus (0x%4.4X, %s, %s, 0x%2.2X,\n", + Resource->SpiSerialBus.DeviceSelection, + AcpiGbl_DpDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->SpiSerialBus.TypeSpecificFlags, 1)], + AcpiGbl_WmDecode [ACPI_GET_1BIT_FLAG (Resource->SpiSerialBus.TypeSpecificFlags)], + Resource->SpiSerialBus.DataBitLength); + + /* SlaveMode, ConnectionSpeed, ClockPolarity, ClockPhase */ + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("%s, 0x%8.8X, %s,\n", + AcpiGbl_SmDecode [ACPI_GET_1BIT_FLAG (Resource->SpiSerialBus.Flags)], + Resource->SpiSerialBus.ConnectionSpeed, + AcpiGbl_CpoDecode [ACPI_GET_1BIT_FLAG (Resource->SpiSerialBus.ClockPolarity)]); + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("%s, ", + AcpiGbl_CphDecode [ACPI_GET_1BIT_FLAG (Resource->SpiSerialBus.ClockPhase)]); + + /* ResourceSource is a required field */ + + ResourceSourceOffset = sizeof (AML_RESOURCE_COMMON_SERIALBUS) + + Resource->CommonSerialBus.TypeDataLength; + + DeviceName = ACPI_ADD_PTR (char, Resource, ResourceSourceOffset), + AcpiUtPrintString (DeviceName, ACPI_UINT16_MAX); + + /* ResourceSourceIndex, ResourceUsage */ + + AcpiOsPrintf (",\n"); + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("0x%2.2X, ", Resource->SpiSerialBus.ResSourceIndex); + + AcpiOsPrintf ("%s, ", + AcpiGbl_ConsumeDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->SpiSerialBus.Flags, 1)]); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (",\n"); + + /* Dump the vendor data */ + + AcpiDmIndent (Level + 1); + AcpiDmDumpSerialBusVendorData (Resource, Level); + AcpiOsPrintf (")\n"); + + MpSaveSerialInfo (Info->MappingOp, Resource, DeviceName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmUartSerialBusDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a UART serial bus descriptor + * + ******************************************************************************/ + +static void +AcpiDmUartSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + UINT32 ResourceSourceOffset; + char *DeviceName; + + + /* ConnectionSpeed, BitsPerByte, StopBits */ + + AcpiDmIndent (Level); + AcpiOsPrintf ("UartSerialBus (0x%8.8X, %s, %s,\n", + Resource->UartSerialBus.DefaultBaudRate, + AcpiGbl_BpbDecode [ACPI_EXTRACT_3BIT_FLAG (Resource->UartSerialBus.TypeSpecificFlags, 4)], + AcpiGbl_SbDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->UartSerialBus.TypeSpecificFlags, 2)]); + + /* LinesInUse, IsBigEndian, Parity, FlowControl */ + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("0x%2.2X, %s, %s, %s,\n", + Resource->UartSerialBus.LinesEnabled, + AcpiGbl_EdDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->UartSerialBus.TypeSpecificFlags, 7)], + AcpiGbl_PtDecode [ACPI_GET_3BIT_FLAG (Resource->UartSerialBus.Parity)], + AcpiGbl_FcDecode [ACPI_GET_2BIT_FLAG (Resource->UartSerialBus.TypeSpecificFlags)]); + + /* ReceiveBufferSize, TransmitBufferSize */ + + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("0x%4.4X, 0x%4.4X, ", + Resource->UartSerialBus.RxFifoSize, + Resource->UartSerialBus.TxFifoSize); + + /* ResourceSource is a required field */ + + ResourceSourceOffset = sizeof (AML_RESOURCE_COMMON_SERIALBUS) + + Resource->CommonSerialBus.TypeDataLength; + + DeviceName = ACPI_ADD_PTR (char, Resource, ResourceSourceOffset), + AcpiUtPrintString (DeviceName, ACPI_UINT16_MAX); + + /* ResourceSourceIndex, ResourceUsage */ + + AcpiOsPrintf (",\n"); + AcpiDmIndent (Level + 1); + AcpiOsPrintf ("0x%2.2X, ", Resource->UartSerialBus.ResSourceIndex); + + AcpiOsPrintf ("%s, ", + AcpiGbl_ConsumeDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->UartSerialBus.Flags, 1)]); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (",\n"); + + /* Dump the vendor data */ + + AcpiDmIndent (Level + 1); + AcpiDmDumpSerialBusVendorData (Resource, Level); + AcpiOsPrintf (")\n"); + + MpSaveSerialInfo (Info->MappingOp, Resource, DeviceName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmSerialBusDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a I2C/SPI/UART serial bus descriptor + * + ******************************************************************************/ + +void +AcpiDmSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + SerialBusResourceDispatch [Resource->CommonSerialBus.Type] ( + Info, Resource, Length, Level); +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmresrcs.c b/third_party/lib/acpica/source/components/disassembler/dmresrcs.c new file mode 100644 index 000000000..c601f3649 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmresrcs.c @@ -0,0 +1,369 @@ +/******************************************************************************* + * + * Module Name: dmresrcs.c - "Small" Resource Descriptor disassembly + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdisasm.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dbresrcs") + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIrqDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a IRQ descriptor, either Irq() or IrqNoFlags() + * + ******************************************************************************/ + +void +AcpiDmIrqDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("%s (", + AcpiGbl_IrqDecode [ACPI_GET_1BIT_FLAG (Length)]); + + /* Decode flags byte if present */ + + if (Length & 1) + { + AcpiOsPrintf ("%s, %s, %s, ", + AcpiGbl_HeDecode [ACPI_GET_1BIT_FLAG (Resource->Irq.Flags)], + AcpiGbl_LlDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->Irq.Flags, 3)], + AcpiGbl_ShrDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->Irq.Flags, 4)]); + } + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); + + AcpiDmIndent (Level + 1); + AcpiDmBitList (Resource->Irq.IrqMask); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDmaDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a DMA descriptor + * + ******************************************************************************/ + +void +AcpiDmDmaDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("DMA (%s, %s, %s, ", + AcpiGbl_TypDecode [ACPI_EXTRACT_2BIT_FLAG (Resource->Dma.Flags, 5)], + AcpiGbl_BmDecode [ACPI_EXTRACT_1BIT_FLAG (Resource->Dma.Flags, 2)], + AcpiGbl_SizDecode [ACPI_GET_2BIT_FLAG (Resource->Dma.Flags)]); + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); + + AcpiDmIndent (Level + 1); + AcpiDmBitList (Resource->Dma.DmaChannelMask); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFixedDmaDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a FixedDMA descriptor + * + ******************************************************************************/ + +void +AcpiDmFixedDmaDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("FixedDMA (0x%4.4X, 0x%4.4X, ", + Resource->FixedDma.RequestLines, + Resource->FixedDma.Channels); + + if (Resource->FixedDma.Width <= 5) + { + AcpiOsPrintf ("%s, ", + AcpiGbl_DtsDecode [Resource->FixedDma.Width]); + } + else + { + AcpiOsPrintf ("%X /* INVALID DMA WIDTH */, ", + Resource->FixedDma.Width); + } + + /* Insert a descriptor name */ + + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIoDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode an IO descriptor + * + ******************************************************************************/ + +void +AcpiDmIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("IO (%s,\n", + AcpiGbl_IoDecode [ACPI_GET_1BIT_FLAG (Resource->Io.Flags)]); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger16 (Resource->Io.Minimum, "Range Minimum"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger16 (Resource->Io.Maximum, "Range Maximum"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger8 (Resource->Io.Alignment, "Alignment"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger8 (Resource->Io.AddressLength, "Length"); + + /* Insert a descriptor name */ + + AcpiDmIndent (Level + 1); + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmFixedIoDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Fixed IO descriptor + * + ******************************************************************************/ + +void +AcpiDmFixedIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("FixedIO (\n"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger16 (Resource->FixedIo.Address, "Address"); + + AcpiDmIndent (Level + 1); + AcpiDmDumpInteger8 (Resource->FixedIo.AddressLength, "Length"); + + /* Insert a descriptor name */ + + AcpiDmIndent (Level + 1); + AcpiDmDescriptorName (); + AcpiOsPrintf (")\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmStartDependentDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Start Dependendent functions descriptor + * + ******************************************************************************/ + +void +AcpiDmStartDependentDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + + if (Length & 1) + { + AcpiOsPrintf ("StartDependentFn (0x%2.2X, 0x%2.2X)\n", + (UINT32) ACPI_GET_2BIT_FLAG (Resource->StartDpf.Flags), + (UINT32) ACPI_EXTRACT_2BIT_FLAG (Resource->StartDpf.Flags, 2)); + } + else + { + AcpiOsPrintf ("StartDependentFnNoPri ()\n"); + } + + AcpiDmIndent (Level); + AcpiOsPrintf ("{\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmEndDependentDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode an End Dependent functions descriptor + * + ******************************************************************************/ + +void +AcpiDmEndDependentDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmIndent (Level); + AcpiOsPrintf ("}\n"); + AcpiDmIndent (Level); + AcpiOsPrintf ("EndDependentFn ()\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmVendorSmallDescriptor + * + * PARAMETERS: Info - Extra resource info + * Resource - Pointer to the resource descriptor + * Length - Length of the descriptor in bytes + * Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Decode a Vendor Small Descriptor + * + ******************************************************************************/ + +void +AcpiDmVendorSmallDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level) +{ + + AcpiDmVendorCommon ("Short", + ACPI_ADD_PTR (UINT8, Resource, sizeof (AML_RESOURCE_SMALL_HEADER)), + Length, Level); +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmutils.c b/third_party/lib/acpica/source/components/disassembler/dmutils.c new file mode 100644 index 000000000..9e2371b85 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmutils.c @@ -0,0 +1,330 @@ +/******************************************************************************* + * + * Module Name: dmutils - AML disassembler utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdisasm.h" + +#ifdef ACPI_ASL_COMPILER +#include +#endif + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dmutils") + + +/* Data used in keeping track of fields */ +#if 0 +const char *AcpiGbl_FENames[] = +{ + "skip", + "?access?" +}; /* FE = Field Element */ +#endif + +/* Operators for Match() */ + +const char *AcpiGbl_MatchOps[] = +{ + "MTR", + "MEQ", + "MLE", + "MLT", + "MGE", + "MGT" +}; + +/* Access type decoding */ + +const char *AcpiGbl_AccessTypes[] = +{ + "AnyAcc", + "ByteAcc", + "WordAcc", + "DWordAcc", + "QWordAcc", + "BufferAcc", + "InvalidAccType", + "InvalidAccType" +}; + +/* Lock rule decoding */ + +const char *AcpiGbl_LockRule[] = +{ + "NoLock", + "Lock" +}; + +/* Update rule decoding */ + +const char *AcpiGbl_UpdateRules[] = +{ + "Preserve", + "WriteAsOnes", + "WriteAsZeros", + "InvalidUpdateRule" +}; + +/* Strings used to decode resource descriptors */ + +const char *AcpiGbl_WordDecode[] = +{ + "Memory", + "IO", + "BusNumber", + "UnknownResourceType" +}; + +const char *AcpiGbl_IrqDecode[] = +{ + "IRQNoFlags", + "IRQ" +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDecodeAttribute + * + * PARAMETERS: Attribute - Attribute field of AccessAs keyword + * + * RETURN: None + * + * DESCRIPTION: Decode the AccessAs attribute byte. (Mostly SMBus and + * GenericSerialBus stuff.) + * + ******************************************************************************/ + +void +AcpiDmDecodeAttribute ( + UINT8 Attribute) +{ + + switch (Attribute) + { + case AML_FIELD_ATTRIB_QUICK: + + AcpiOsPrintf ("AttribQuick"); + break; + + case AML_FIELD_ATTRIB_SEND_RCV: + + AcpiOsPrintf ("AttribSendReceive"); + break; + + case AML_FIELD_ATTRIB_BYTE: + + AcpiOsPrintf ("AttribByte"); + break; + + case AML_FIELD_ATTRIB_WORD: + + AcpiOsPrintf ("AttribWord"); + break; + + case AML_FIELD_ATTRIB_BLOCK: + + AcpiOsPrintf ("AttribBlock"); + break; + + case AML_FIELD_ATTRIB_MULTIBYTE: + + AcpiOsPrintf ("AttribBytes"); + break; + + case AML_FIELD_ATTRIB_WORD_CALL: + + AcpiOsPrintf ("AttribProcessCall"); + break; + + case AML_FIELD_ATTRIB_BLOCK_CALL: + + AcpiOsPrintf ("AttribBlockProcessCall"); + break; + + case AML_FIELD_ATTRIB_RAW_BYTES: + + AcpiOsPrintf ("AttribRawBytes"); + break; + + case AML_FIELD_ATTRIB_RAW_PROCESS: + + AcpiOsPrintf ("AttribRawProcessBytes"); + break; + + default: + + /* A ByteConst is allowed by the grammar */ + + AcpiOsPrintf ("0x%2.2X", Attribute); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmIndent + * + * PARAMETERS: Level - Current source code indentation level + * + * RETURN: None + * + * DESCRIPTION: Indent 4 spaces per indentation level. + * + ******************************************************************************/ + +void +AcpiDmIndent ( + UINT32 Level) +{ + + if (!Level) + { + return; + } + + AcpiOsPrintf ("%*.s", ACPI_MUL_4 (Level), " "); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCommaIfListMember + * + * PARAMETERS: Op - Current operator/operand + * + * RETURN: TRUE if a comma was inserted + * + * DESCRIPTION: Insert a comma if this Op is a member of an argument list. + * + ******************************************************************************/ + +BOOLEAN +AcpiDmCommaIfListMember ( + ACPI_PARSE_OBJECT *Op) +{ + + if (!Op->Common.Next) + { + return (FALSE); + } + + if (AcpiDmListType (Op->Common.Parent) & BLOCK_COMMA_LIST) + { + /* Exit if Target has been marked IGNORE */ + + if (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_IGNORE) + { + return (FALSE); + } + + /* Check for a NULL target operand */ + + if ((Op->Common.Next->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && + (!Op->Common.Next->Common.Value.String)) + { + /* + * To handle the Divide() case where there are two optional + * targets, look ahead one more op. If null, this null target + * is the one and only target -- no comma needed. Otherwise, + * we need a comma to prepare for the next target. + */ + if (!Op->Common.Next->Common.Next) + { + return (FALSE); + } + } + + if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST) && + (!(Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))) + { + return (FALSE); + } + + /* Emit comma only if this is not a C-style operator */ + + if (!Op->Common.OperatorSymbol) + { + AcpiOsPrintf (", "); + } + + return (TRUE); + } + + else if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST) && + (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) + { + AcpiOsPrintf (", "); + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmCommaIfFieldMember + * + * PARAMETERS: Op - Current operator/operand + * + * RETURN: None + * + * DESCRIPTION: Insert a comma if this Op is a member of a Field argument list. + * + ******************************************************************************/ + +void +AcpiDmCommaIfFieldMember ( + ACPI_PARSE_OBJECT *Op) +{ + + if (Op->Common.Next) + { + AcpiOsPrintf (", "); + } +} diff --git a/third_party/lib/acpica/source/components/disassembler/dmwalk.c b/third_party/lib/acpica/source/components/disassembler/dmwalk.c new file mode 100644 index 000000000..8dd001108 --- /dev/null +++ b/third_party/lib/acpica/source/components/disassembler/dmwalk.c @@ -0,0 +1,1068 @@ +/******************************************************************************* + * + * Module Name: dmwalk - AML disassembly tree walk + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_CA_DEBUGGER + ACPI_MODULE_NAME ("dmwalk") + + +#define DB_FULL_OP_INFO "[%4.4s] @%5.5X #%4.4X: " + +/* Stub for non-compiler code */ + +#ifndef ACPI_ASL_COMPILER +void +AcpiDmEmitExternals ( + void) +{ + return; +} +#endif + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDmDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static ACPI_STATUS +AcpiDmAscendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); + +static UINT32 +AcpiDmBlockType ( + ACPI_PARSE_OBJECT *Op); + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDisassemble + * + * PARAMETERS: WalkState - Current state + * Origin - Starting object + * NumOpcodes - Max number of opcodes to be displayed + * + * RETURN: None + * + * DESCRIPTION: Disassemble parser object and its children. This is the + * main entry point of the disassembler. + * + ******************************************************************************/ + +void +AcpiDmDisassemble ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Origin, + UINT32 NumOpcodes) +{ + ACPI_PARSE_OBJECT *Op = Origin; + ACPI_OP_WALK_INFO Info; + + + if (!Op) + { + return; + } + + memset (&Info, 0, sizeof (ACPI_OP_WALK_INFO)); + Info.WalkState = WalkState; + Info.StartAml = Op->Common.Aml - sizeof (ACPI_TABLE_HEADER); + Info.AmlOffset = Op->Common.Aml - Info.StartAml; + + AcpiDmWalkParseTree (Op, AcpiDmDescendingOp, AcpiDmAscendingOp, &Info); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmWalkParseTree + * + * PARAMETERS: Op - Root Op object + * DescendingCallback - Called during tree descent + * AscendingCallback - Called during tree ascent + * Context - To be passed to the callbacks + * + * RETURN: Status from callback(s) + * + * DESCRIPTION: Walk the entire parse tree. + * + ******************************************************************************/ + +void +AcpiDmWalkParseTree ( + ACPI_PARSE_OBJECT *Op, + ASL_WALK_CALLBACK DescendingCallback, + ASL_WALK_CALLBACK AscendingCallback, + void *Context) +{ + BOOLEAN NodePreviouslyVisited; + ACPI_PARSE_OBJECT *StartOp = Op; + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Next; + ACPI_OP_WALK_INFO *Info = Context; + + + Info->Level = 0; + NodePreviouslyVisited = FALSE; + + while (Op) + { + if (NodePreviouslyVisited) + { + if (AscendingCallback) + { + Status = AscendingCallback (Op, Info->Level, Context); + if (ACPI_FAILURE (Status)) + { + return; + } + } + } + else + { + /* Let the callback process the node */ + + Status = DescendingCallback (Op, Info->Level, Context); + if (ACPI_SUCCESS (Status)) + { + /* Visit children first, once */ + + Next = AcpiPsGetArg (Op, 0); + if (Next) + { + Info->Level++; + Op = Next; + continue; + } + } + else if (Status != AE_CTRL_DEPTH) + { + /* Exit immediately on any error */ + + return; + } + } + + /* Terminate walk at start op */ + + if (Op == StartOp) + { + break; + } + + /* No more children, re-visit this node */ + + if (!NodePreviouslyVisited) + { + NodePreviouslyVisited = TRUE; + continue; + } + + /* No more children, visit peers */ + + if (Op->Common.Next) + { + Op = Op->Common.Next; + NodePreviouslyVisited = FALSE; + } + else + { + /* No peers, re-visit parent */ + + if (Info->Level != 0 ) + { + Info->Level--; + } + + Op = Op->Common.Parent; + NodePreviouslyVisited = TRUE; + } + } + + /* If we get here, the walk completed with no errors */ + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmBlockType + * + * PARAMETERS: Op - Object to be examined + * + * RETURN: BlockType - not a block, parens, braces, or even both. + * + * DESCRIPTION: Type of block for this op (parens or braces) + * + ******************************************************************************/ + +static UINT32 +AcpiDmBlockType ( + ACPI_PARSE_OBJECT *Op) +{ + const ACPI_OPCODE_INFO *OpInfo; + + + if (!Op) + { + return (BLOCK_NONE); + } + + switch (Op->Common.AmlOpcode) + { + case AML_ELSE_OP: + + return (BLOCK_BRACE); + + case AML_METHOD_OP: + case AML_DEVICE_OP: + case AML_SCOPE_OP: + case AML_PROCESSOR_OP: + case AML_POWER_RES_OP: + case AML_THERMAL_ZONE_OP: + case AML_IF_OP: + case AML_WHILE_OP: + case AML_FIELD_OP: + case AML_INDEX_FIELD_OP: + case AML_BANK_FIELD_OP: + + return (BLOCK_PAREN | BLOCK_BRACE); + + case AML_BUFFER_OP: + + if ((Op->Common.DisasmOpcode == ACPI_DASM_UNICODE) || + (Op->Common.DisasmOpcode == ACPI_DASM_UUID) || + (Op->Common.DisasmOpcode == ACPI_DASM_PLD_METHOD)) + { + return (BLOCK_NONE); + } + + /*lint -fallthrough */ + + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + return (BLOCK_PAREN | BLOCK_BRACE); + + case AML_EVENT_OP: + + return (BLOCK_PAREN); + + case AML_INT_METHODCALL_OP: + + if (Op->Common.Parent && + ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP))) + { + /* This is a reference to a method, not an invocation */ + + return (BLOCK_NONE); + } + + /*lint -fallthrough */ + + default: + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (OpInfo->Flags & AML_HAS_ARGS) + { + return (BLOCK_PAREN); + } + + return (BLOCK_NONE); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmListType + * + * PARAMETERS: Op - Object to be examined + * + * RETURN: ListType - has commas or not. + * + * DESCRIPTION: Type of block for this op (parens or braces) + * + ******************************************************************************/ + +UINT32 +AcpiDmListType ( + ACPI_PARSE_OBJECT *Op) +{ + const ACPI_OPCODE_INFO *OpInfo; + + + if (!Op) + { + return (BLOCK_NONE); + } + + switch (Op->Common.AmlOpcode) + { + + case AML_ELSE_OP: + case AML_METHOD_OP: + case AML_DEVICE_OP: + case AML_SCOPE_OP: + case AML_POWER_RES_OP: + case AML_PROCESSOR_OP: + case AML_THERMAL_ZONE_OP: + case AML_IF_OP: + case AML_WHILE_OP: + case AML_FIELD_OP: + case AML_INDEX_FIELD_OP: + case AML_BANK_FIELD_OP: + + return (BLOCK_NONE); + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + return (BLOCK_COMMA_LIST); + + default: + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (OpInfo->Flags & AML_HAS_ARGS) + { + return (BLOCK_COMMA_LIST); + } + + return (BLOCK_NONE); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmDescendingOp + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: First visitation of a parse object during tree descent. + * Decode opcode name and begin parameter list(s), if any. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmDescendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + const ACPI_OPCODE_INFO *OpInfo; + UINT32 Name; + ACPI_PARSE_OBJECT *NextOp; + UINT32 AmlOffset; + + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + /* Listing support to dump the AML code after the ASL statement */ + + if (AcpiGbl_DmOpt_Listing) + { + /* We only care about these classes of objects */ + + if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) || + (OpInfo->Class == AML_CLASS_CONTROL) || + (OpInfo->Class == AML_CLASS_CREATE) || + ((OpInfo->Class == AML_CLASS_EXECUTE) && (!Op->Common.Next))) + { + if (AcpiGbl_DmOpt_Listing && Info->PreviousAml) + { + /* Dump the AML byte code for the previous Op */ + + if (Op->Common.Aml > Info->PreviousAml) + { + AcpiOsPrintf ("\n"); + AcpiUtDumpBuffer ( + (Info->StartAml + Info->AmlOffset), + (Op->Common.Aml - Info->PreviousAml), + DB_BYTE_DISPLAY, + Info->AmlOffset); + AcpiOsPrintf ("\n"); + } + + Info->AmlOffset = (Op->Common.Aml - Info->StartAml); + } + + Info->PreviousAml = Op->Common.Aml; + } + } + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE) + { + /* Ignore this op -- it was handled elsewhere */ + + return (AE_CTRL_DEPTH); + } + + /* Level 0 is at the Definition Block level */ + + if (Level == 0) + { + /* In verbose mode, print the AML offset, opcode and depth count */ + + if (Info->WalkState) + { + AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml, + Info->WalkState->ParserState.AmlStart); + if (AcpiGbl_DmOpt_Verbose) + { + AcpiOsPrintf (DB_FULL_OP_INFO, + (Info->WalkState->MethodNode ? + Info->WalkState->MethodNode->Name.Ascii : " "), + AmlOffset, (UINT32) Op->Common.AmlOpcode); + } + } + + if (Op->Common.AmlOpcode == AML_SCOPE_OP) + { + /* This is the beginning of the Definition Block */ + + AcpiOsPrintf ("{\n"); + + /* Emit all External() declarations here */ + + AcpiDmEmitExternals (); + return (AE_OK); + } + } + else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) && + (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) && + (!(Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)) && + (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP)) + { + /* + * This is a first-level element of a term list, + * indent a new line + */ + switch (Op->Common.AmlOpcode) + { + case AML_NOOP_OP: + /* + * Optionally just ignore this opcode. Some tables use + * NoOp opcodes for "padding" out packages that the BIOS + * changes dynamically. This can leave hundreds or + * thousands of NoOp opcodes that if disassembled, + * cannot be compiled because they are syntactically + * incorrect. + */ + if (AcpiGbl_IgnoreNoopOperator) + { + Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + return (AE_OK); + } + + /* Fallthrough */ + + default: + + AcpiDmIndent (Level); + break; + } + + Info->LastLevel = Level; + Info->Count = 0; + } + + /* + * This is an inexpensive mechanism to try and keep lines from getting + * too long. When the limit is hit, start a new line at the previous + * indent plus one. A better but more expensive mechanism would be to + * keep track of the current column. + */ + Info->Count++; + if (Info->Count /* +Info->LastLevel */ > 12) + { + Info->Count = 0; + AcpiOsPrintf ("\n"); + AcpiDmIndent (Info->LastLevel + 1); + } + + /* If ASL+ is enabled, check for a C-style operator */ + + if (AcpiDmCheckForSymbolicOpcode (Op, Info)) + { + return (AE_OK); + } + + /* Print the opcode name */ + + AcpiDmDisassembleOneOp (NULL, Info, Op); + + if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) || + (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP)) + { + return (AE_OK); + } + + if ((Op->Common.AmlOpcode == AML_NAME_OP) || + (Op->Common.AmlOpcode == AML_RETURN_OP)) + { + Info->Level--; + } + + /* Start the opcode argument list if necessary */ + + if ((OpInfo->Flags & AML_HAS_ARGS) || + (Op->Common.AmlOpcode == AML_EVENT_OP)) + { + /* This opcode has an argument list */ + + if (AcpiDmBlockType (Op) & BLOCK_PAREN) + { + AcpiOsPrintf (" ("); + } + + /* If this is a named opcode, print the associated name value */ + + if (OpInfo->Flags & AML_NAMED) + { + switch (Op->Common.AmlOpcode) + { + case AML_ALIAS_OP: + + NextOp = AcpiPsGetDepthNext (NULL, Op); + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + AcpiDmNamestring (NextOp->Common.Value.Name); + AcpiOsPrintf (", "); + + /*lint -fallthrough */ + + default: + + Name = AcpiPsGetName (Op); + if (Op->Named.Path) + { + AcpiDmNamestring ((char *) Op->Named.Path); + } + else + { + AcpiDmDumpName (Name); + } + + if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP) + { + if (AcpiGbl_DmOpt_Verbose) + { + (void) AcpiPsDisplayObjectPathname (NULL, Op); + } + } + break; + } + + switch (Op->Common.AmlOpcode) + { + case AML_METHOD_OP: + + AcpiDmMethodFlags (Op); + AcpiOsPrintf (")"); + + /* Emit description comment for Method() with a predefined ACPI name */ + + AcpiDmPredefinedDescription (Op); + break; + + case AML_NAME_OP: + + /* Check for _HID and related EISAID() */ + + AcpiDmCheckForHardwareId (Op); + AcpiOsPrintf (", "); + break; + + case AML_REGION_OP: + + AcpiDmRegionFlags (Op); + break; + + case AML_POWER_RES_OP: + + /* Mark the next two Ops as part of the parameter list */ + + AcpiOsPrintf (", "); + NextOp = AcpiPsGetDepthNext (NULL, Op); + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + + NextOp = NextOp->Common.Next; + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + return (AE_OK); + + case AML_PROCESSOR_OP: + + /* Mark the next three Ops as part of the parameter list */ + + AcpiOsPrintf (", "); + NextOp = AcpiPsGetDepthNext (NULL, Op); + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + + NextOp = NextOp->Common.Next; + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + + NextOp = NextOp->Common.Next; + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + return (AE_OK); + + case AML_MUTEX_OP: + case AML_DATA_REGION_OP: + + AcpiOsPrintf (", "); + return (AE_OK); + + case AML_EVENT_OP: + case AML_ALIAS_OP: + + return (AE_OK); + + case AML_SCOPE_OP: + case AML_DEVICE_OP: + case AML_THERMAL_ZONE_OP: + + AcpiOsPrintf (")"); + break; + + default: + + AcpiOsPrintf ("*** Unhandled named opcode %X\n", + Op->Common.AmlOpcode); + break; + } + } + + else switch (Op->Common.AmlOpcode) + { + case AML_FIELD_OP: + case AML_BANK_FIELD_OP: + case AML_INDEX_FIELD_OP: + + Info->BitOffset = 0; + + /* Name of the parent OperationRegion */ + + NextOp = AcpiPsGetDepthNext (NULL, Op); + AcpiDmNamestring (NextOp->Common.Value.Name); + AcpiOsPrintf (", "); + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + + switch (Op->Common.AmlOpcode) + { + case AML_BANK_FIELD_OP: + + /* Namestring - Bank Name */ + + NextOp = AcpiPsGetDepthNext (NULL, NextOp); + AcpiDmNamestring (NextOp->Common.Value.Name); + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + AcpiOsPrintf (", "); + + /* + * Bank Value. This is a TermArg in the middle of the parameter + * list, must handle it here. + * + * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMLIST + * eliminates newline in the output. + */ + NextOp = NextOp->Common.Next; + + Info->Flags = ACPI_PARSEOP_PARAMLIST; + AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp, + AcpiDmAscendingOp, Info); + Info->Flags = 0; + Info->Level = Level; + + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + AcpiOsPrintf (", "); + break; + + case AML_INDEX_FIELD_OP: + + /* Namestring - Data Name */ + + NextOp = AcpiPsGetDepthNext (NULL, NextOp); + AcpiDmNamestring (NextOp->Common.Value.Name); + AcpiOsPrintf (", "); + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + break; + + default: + + break; + } + + AcpiDmFieldFlags (NextOp); + break; + + case AML_BUFFER_OP: + + /* The next op is the size parameter */ + + NextOp = AcpiPsGetDepthNext (NULL, Op); + if (!NextOp) + { + /* Single-step support */ + + return (AE_OK); + } + + if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE) + { + /* + * We have a resource list. Don't need to output + * the buffer size Op. Open up a new block + */ + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; + NextOp = NextOp->Common.Next; + AcpiOsPrintf (")"); + + /* Emit description comment for Name() with a predefined ACPI name */ + + AcpiDmPredefinedDescription (Op->Asl.Parent); + + AcpiOsPrintf ("\n"); + AcpiDmIndent (Info->Level); + AcpiOsPrintf ("{\n"); + return (AE_OK); + } + + /* Normal Buffer, mark size as in the parameter list */ + + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + return (AE_OK); + + case AML_VAR_PACKAGE_OP: + case AML_IF_OP: + case AML_WHILE_OP: + + /* The next op is the size or predicate parameter */ + + NextOp = AcpiPsGetDepthNext (NULL, Op); + if (NextOp) + { + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + } + return (AE_OK); + + case AML_PACKAGE_OP: + + /* The next op is the size parameter */ + + NextOp = AcpiPsGetDepthNext (NULL, Op); + if (NextOp) + { + NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST; + } + return (AE_OK); + + case AML_MATCH_OP: + + AcpiDmMatchOp (Op); + break; + + default: + + break; + } + + if (AcpiDmBlockType (Op) & BLOCK_BRACE) + { + AcpiOsPrintf ("\n"); + AcpiDmIndent (Level); + AcpiOsPrintf ("{\n"); + } + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDmAscendingOp + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Second visitation of a parse object, during ascent of parse + * tree. Close out any parameter lists and complete the opcode. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDmAscendingOp ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_OP_WALK_INFO *Info = Context; + ACPI_PARSE_OBJECT *ParentOp; + + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE) + { + /* Ignore this op -- it was handled elsewhere */ + + return (AE_OK); + } + + if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP)) + { + /* Indicates the end of the current descriptor block (table) */ + + AcpiOsPrintf ("}\n\n"); + return (AE_OK); + } + + switch (AcpiDmBlockType (Op)) + { + case BLOCK_PAREN: + + /* Completed an op that has arguments, add closing paren if needed */ + + AcpiDmCloseOperator (Op); + + if (Op->Common.AmlOpcode == AML_NAME_OP) + { + /* Emit description comment for Name() with a predefined ACPI name */ + + AcpiDmPredefinedDescription (Op); + } + else + { + /* For Create* operators, attempt to emit resource tag description */ + + AcpiDmFieldPredefinedDescription (Op); + } + + /* Decode Notify() values */ + + if (Op->Common.AmlOpcode == AML_NOTIFY_OP) + { + AcpiDmNotifyDescription (Op); + } + + AcpiDmDisplayTargetPathname (Op); + + /* Could be a nested operator, check if comma required */ + + if (!AcpiDmCommaIfListMember (Op)) + { + if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) && + (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) && + (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP)) + { + /* + * This is a first-level element of a term list + * start a new line + */ + if (!(Info->Flags & ACPI_PARSEOP_PARAMLIST)) + { + AcpiOsPrintf ("\n"); + } + } + } + break; + + case BLOCK_BRACE: + case (BLOCK_BRACE | BLOCK_PAREN): + + /* Completed an op that has a term list, add closing brace */ + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST) + { + AcpiOsPrintf ("}"); + } + else + { + AcpiDmIndent (Level); + AcpiOsPrintf ("}"); + } + + AcpiDmCommaIfListMember (Op); + + if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN) + { + AcpiOsPrintf ("\n"); + if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)) + { + if ((Op->Common.AmlOpcode == AML_IF_OP) && + (Op->Common.Next) && + (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP)) + { + break; + } + + if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) && + (!Op->Common.Next)) + { + break; + } + AcpiOsPrintf ("\n"); + } + } + break; + + case BLOCK_NONE: + default: + + /* Could be a nested operator, check if comma required */ + + if (!AcpiDmCommaIfListMember (Op)) + { + if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) && + (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) && + (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP)) + { + /* + * This is a first-level element of a term list + * start a new line + */ + AcpiOsPrintf ("\n"); + } + } + else if (Op->Common.Parent) + { + switch (Op->Common.Parent->Common.AmlOpcode) + { + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) + { + AcpiOsPrintf ("\n"); + } + break; + + default: + + break; + } + } + break; + } + + if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST) + { + if ((Op->Common.Next) && + (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) + { + return (AE_OK); + } + + /* + * The parent Op is guaranteed to be valid because of the flag + * ACPI_PARSEOP_PARAMLIST -- which means that this op is part of + * a parameter list and thus has a valid parent. + */ + ParentOp = Op->Common.Parent; + + /* + * Just completed a parameter node for something like "Buffer (param)". + * Close the paren and open up the term list block with a brace + */ + if (Op->Common.Next) + { + AcpiOsPrintf (")"); + + /* + * Emit a description comment for a Name() operator that is a + * predefined ACPI name. Must check the grandparent. + */ + ParentOp = ParentOp->Common.Parent; + if (ParentOp && + (ParentOp->Asl.AmlOpcode == AML_NAME_OP)) + { + AcpiDmPredefinedDescription (ParentOp); + } + + AcpiOsPrintf ("\n"); + AcpiDmIndent (Level - 1); + AcpiOsPrintf ("{\n"); + } + else + { + ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST; + AcpiOsPrintf (") {"); + } + } + + if ((Op->Common.AmlOpcode == AML_NAME_OP) || + (Op->Common.AmlOpcode == AML_RETURN_OP)) + { + Info->Level++; + } + + /* + * For ASL+, check for and emit a C-style symbol. If valid, the + * symbol string has been deferred until after the first operand + */ + if (AcpiGbl_CstyleDisassembly) + { + if (Op->Asl.OperatorSymbol) + { + AcpiOsPrintf ("%s", Op->Asl.OperatorSymbol); + Op->Asl.OperatorSymbol = NULL; + } + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsargs.c b/third_party/lib/acpica/source/components/dispatcher/dsargs.c new file mode 100644 index 000000000..5e5e93b4e --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsargs.c @@ -0,0 +1,438 @@ +/****************************************************************************** + * + * Module Name: dsargs - Support for execution of dynamic arguments for static + * objects (regions, fields, buffer fields, etc.) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsargs") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsExecuteArguments ( + ACPI_NAMESPACE_NODE *Node, + ACPI_NAMESPACE_NODE *ScopeNode, + UINT32 AmlLength, + UINT8 *AmlStart); + + +/******************************************************************************* + * + * FUNCTION: AcpiDsExecuteArguments + * + * PARAMETERS: Node - Object NS node + * ScopeNode - Parent NS node + * AmlLength - Length of executable AML + * AmlStart - Pointer to the AML + * + * RETURN: Status. + * + * DESCRIPTION: Late (deferred) execution of region or field arguments + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsExecuteArguments ( + ACPI_NAMESPACE_NODE *Node, + ACPI_NAMESPACE_NODE *ScopeNode, + UINT32 AmlLength, + UINT8 *AmlStart) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Op; + ACPI_WALK_STATE *WalkState; + + + ACPI_FUNCTION_TRACE (DsExecuteArguments); + + + /* Allocate a new parser op to be the root of the parsed tree */ + + Op = AcpiPsAllocOp (AML_INT_EVAL_SUBTREE_OP, AmlStart); + if (!Op) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Save the Node for use in AcpiPsParseAml */ + + Op->Common.Node = ScopeNode; + + /* Create and initialize a new parser state */ + + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + if (!WalkState) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, AmlStart, + AmlLength, NULL, ACPI_IMODE_LOAD_PASS1); + if (ACPI_FAILURE (Status)) + { + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + + /* Mark this parse as a deferred opcode */ + + WalkState->ParseFlags = ACPI_PARSE_DEFERRED_OP; + WalkState->DeferredNode = Node; + + /* Pass1: Parse the entire declaration */ + + Status = AcpiPsParseAml (WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Get and init the Op created above */ + + Op->Common.Node = Node; + AcpiPsDeleteParseTree (Op); + + /* Evaluate the deferred arguments */ + + Op = AcpiPsAllocOp (AML_INT_EVAL_SUBTREE_OP, AmlStart); + if (!Op) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Op->Common.Node = ScopeNode; + + /* Create and initialize a new parser state */ + + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + if (!WalkState) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Execute the opcode and arguments */ + + Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, AmlStart, + AmlLength, NULL, ACPI_IMODE_EXECUTE); + if (ACPI_FAILURE (Status)) + { + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + + /* Mark this execution as a deferred opcode */ + + WalkState->DeferredNode = Node; + Status = AcpiPsParseAml (WalkState); + +Cleanup: + AcpiPsDeleteParseTree (Op); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetBufferFieldArguments + * + * PARAMETERS: ObjDesc - A valid BufferField object + * + * RETURN: Status. + * + * DESCRIPTION: Get BufferField Buffer and Index. This implements the late + * evaluation of these field attributes. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsGetBufferFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_OPERAND_OBJECT *ExtraDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (DsGetBufferFieldArguments, ObjDesc); + + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get the AML pointer (method object) and BufferField node */ + + ExtraDesc = AcpiNsGetSecondaryObject (ObjDesc); + Node = ObjDesc->BufferField.Node; + + ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( + ACPI_TYPE_BUFFER_FIELD, Node, NULL)); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", + AcpiUtGetNodeName (Node))); + + /* Execute the AML code for the TermArg arguments */ + + Status = AcpiDsExecuteArguments (Node, Node->Parent, + ExtraDesc->Extra.AmlLength, ExtraDesc->Extra.AmlStart); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetBankFieldArguments + * + * PARAMETERS: ObjDesc - A valid BankField object + * + * RETURN: Status. + * + * DESCRIPTION: Get BankField BankValue. This implements the late + * evaluation of these field attributes. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsGetBankFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_OPERAND_OBJECT *ExtraDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (DsGetBankFieldArguments, ObjDesc); + + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get the AML pointer (method object) and BankField node */ + + ExtraDesc = AcpiNsGetSecondaryObject (ObjDesc); + Node = ObjDesc->BankField.Node; + + ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( + ACPI_TYPE_LOCAL_BANK_FIELD, Node, NULL)); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n", + AcpiUtGetNodeName (Node))); + + /* Execute the AML code for the TermArg arguments */ + + Status = AcpiDsExecuteArguments (Node, Node->Parent, + ExtraDesc->Extra.AmlLength, ExtraDesc->Extra.AmlStart); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetBufferArguments + * + * PARAMETERS: ObjDesc - A valid Buffer object + * + * RETURN: Status. + * + * DESCRIPTION: Get Buffer length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsGetBufferArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (DsGetBufferArguments, ObjDesc); + + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get the Buffer node */ + + Node = ObjDesc->Buffer.Node; + if (!Node) + { + ACPI_ERROR ((AE_INFO, + "No pointer back to namespace node in buffer object %p", + ObjDesc)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer Arg Init\n")); + + /* Execute the AML code for the TermArg arguments */ + + Status = AcpiDsExecuteArguments (Node, Node, + ObjDesc->Buffer.AmlLength, ObjDesc->Buffer.AmlStart); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetPackageArguments + * + * PARAMETERS: ObjDesc - A valid Package object + * + * RETURN: Status. + * + * DESCRIPTION: Get Package length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsGetPackageArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (DsGetPackageArguments, ObjDesc); + + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get the Package node */ + + Node = ObjDesc->Package.Node; + if (!Node) + { + ACPI_ERROR ((AE_INFO, + "No pointer back to namespace node in package %p", ObjDesc)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package Arg Init\n")); + + /* Execute the AML code for the TermArg arguments */ + + Status = AcpiDsExecuteArguments (Node, Node, + ObjDesc->Package.AmlLength, ObjDesc->Package.AmlStart); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetRegionArguments + * + * PARAMETERS: ObjDesc - A valid region object + * + * RETURN: Status. + * + * DESCRIPTION: Get region address and length. This implements the late + * evaluation of these region attributes. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsGetRegionArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ExtraDesc; + + + ACPI_FUNCTION_TRACE_PTR (DsGetRegionArguments, ObjDesc); + + + if (ObjDesc->Region.Flags & AOPOBJ_DATA_VALID) + { + return_ACPI_STATUS (AE_OK); + } + + ExtraDesc = AcpiNsGetSecondaryObject (ObjDesc); + if (!ExtraDesc) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Get the Region node */ + + Node = ObjDesc->Region.Node; + + ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( + ACPI_TYPE_REGION, Node, NULL)); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[%4.4s] OpRegion Arg Init at AML %p\n", + AcpiUtGetNodeName (Node), ExtraDesc->Extra.AmlStart)); + + /* Execute the argument AML */ + + Status = AcpiDsExecuteArguments (Node, ExtraDesc->Extra.ScopeNode, + ExtraDesc->Extra.AmlLength, ExtraDesc->Extra.AmlStart); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiUtAddAddressRange (ObjDesc->Region.SpaceId, + ObjDesc->Region.Address, ObjDesc->Region.Length, Node); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dscontrol.c b/third_party/lib/acpica/source/components/dispatcher/dscontrol.c new file mode 100644 index 000000000..3509f16f9 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dscontrol.c @@ -0,0 +1,417 @@ +/****************************************************************************** + * + * Module Name: dscontrol - Support for execution control opcodes - + * if/else/while/return + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acdebug.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dscontrol") + + +/******************************************************************************* + * + * FUNCTION: AcpiDsExecBeginControlOp + * + * PARAMETERS: WalkList - The list that owns the walk stack + * Op - The control Op + * + * RETURN: Status + * + * DESCRIPTION: Handles all control ops encountered during control method + * execution. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsExecBeginControlOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GENERIC_STATE *ControlState; + + + ACPI_FUNCTION_NAME (DsExecBeginControlOp); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", + Op, Op->Common.AmlOpcode, WalkState)); + + switch (Op->Common.AmlOpcode) + { + case AML_WHILE_OP: + /* + * If this is an additional iteration of a while loop, continue. + * There is no need to allocate a new control state. + */ + if (WalkState->ControlState) + { + if (WalkState->ControlState->Control.AmlPredicateStart == + (WalkState->ParserState.Aml - 1)) + { + /* Reset the state to start-of-loop */ + + WalkState->ControlState->Common.State = + ACPI_CONTROL_CONDITIONAL_EXECUTING; + break; + } + } + + /*lint -fallthrough */ + + case AML_IF_OP: + /* + * IF/WHILE: Create a new control state to manage these + * constructs. We need to manage these as a stack, in order + * to handle nesting. + */ + ControlState = AcpiUtCreateControlState (); + if (!ControlState) + { + Status = AE_NO_MEMORY; + break; + } + /* + * Save a pointer to the predicate for multiple executions + * of a loop + */ + ControlState->Control.AmlPredicateStart = + WalkState->ParserState.Aml - 1; + ControlState->Control.PackageEnd = + WalkState->ParserState.PkgEnd; + ControlState->Control.Opcode = + Op->Common.AmlOpcode; + + + /* Push the control state on this walk's control stack */ + + AcpiUtPushGenericState (&WalkState->ControlState, ControlState); + break; + + case AML_ELSE_OP: + + /* Predicate is in the state object */ + /* If predicate is true, the IF was executed, ignore ELSE part */ + + if (WalkState->LastPredicate) + { + Status = AE_CTRL_TRUE; + } + + break; + + case AML_RETURN_OP: + + break; + + default: + + break; + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsExecEndControlOp + * + * PARAMETERS: WalkList - The list that owns the walk stack + * Op - The control Op + * + * RETURN: Status + * + * DESCRIPTION: Handles all control ops encountered during control method + * execution. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsExecEndControlOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GENERIC_STATE *ControlState; + + + ACPI_FUNCTION_NAME (DsExecEndControlOp); + + + switch (Op->Common.AmlOpcode) + { + case AML_IF_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", Op)); + + /* + * Save the result of the predicate in case there is an + * ELSE to come + */ + WalkState->LastPredicate = + (BOOLEAN) WalkState->ControlState->Common.Value; + + /* + * Pop the control state that was created at the start + * of the IF and free it + */ + ControlState = AcpiUtPopGenericState (&WalkState->ControlState); + AcpiUtDeleteGenericState (ControlState); + break; + + case AML_ELSE_OP: + + break; + + case AML_WHILE_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", Op)); + + ControlState = WalkState->ControlState; + if (ControlState->Common.Value) + { + /* Predicate was true, the body of the loop was just executed */ + + /* + * This loop counter mechanism allows the interpreter to escape + * possibly infinite loops. This can occur in poorly written AML + * when the hardware does not respond within a while loop and the + * loop does not implement a timeout. + */ + ControlState->Control.LoopCount++; + if (ControlState->Control.LoopCount > AcpiGbl_MaxLoopIterations) + { + Status = AE_AML_INFINITE_LOOP; + break; + } + + /* + * Go back and evaluate the predicate and maybe execute the loop + * another time + */ + Status = AE_CTRL_PENDING; + WalkState->AmlLastWhile = + ControlState->Control.AmlPredicateStart; + break; + } + + /* Predicate was false, terminate this while loop */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[WHILE_OP] termination! Op=%p\n",Op)); + + /* Pop this control state and free it */ + + ControlState = AcpiUtPopGenericState (&WalkState->ControlState); + AcpiUtDeleteGenericState (ControlState); + break; + + case AML_RETURN_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[RETURN_OP] Op=%p Arg=%p\n",Op, Op->Common.Value.Arg)); + + /* + * One optional operand -- the return value + * It can be either an immediate operand or a result that + * has been bubbled up the tree + */ + if (Op->Common.Value.Arg) + { + /* Since we have a real Return(), delete any implicit return */ + + AcpiDsClearImplicitReturn (WalkState); + + /* Return statement has an immediate operand */ + + Status = AcpiDsCreateOperands (WalkState, Op->Common.Value.Arg); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + */ + Status = AcpiExResolveToValue ( + &WalkState->Operands [0], WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Get the return value and save as the last result + * value. This is the only place where WalkState->ReturnDesc + * is set to anything other than zero! + */ + WalkState->ReturnDesc = WalkState->Operands[0]; + } + else if (WalkState->ResultCount) + { + /* Since we have a real Return(), delete any implicit return */ + + AcpiDsClearImplicitReturn (WalkState); + + /* + * The return value has come from a previous calculation. + * + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + * + * Allow references created by the Index operator to return + * unchanged. + */ + if ((ACPI_GET_DESCRIPTOR_TYPE (WalkState->Results->Results.ObjDesc[0]) == + ACPI_DESC_TYPE_OPERAND) && + ((WalkState->Results->Results.ObjDesc [0])->Common.Type == + ACPI_TYPE_LOCAL_REFERENCE) && + ((WalkState->Results->Results.ObjDesc [0])->Reference.Class != + ACPI_REFCLASS_INDEX)) + { + Status = AcpiExResolveToValue ( + &WalkState->Results->Results.ObjDesc [0], WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + WalkState->ReturnDesc = WalkState->Results->Results.ObjDesc [0]; + } + else + { + /* No return operand */ + + if (WalkState->NumOperands) + { + AcpiUtRemoveReference (WalkState->Operands [0]); + } + + WalkState->Operands[0] = NULL; + WalkState->NumOperands = 0; + WalkState->ReturnDesc = NULL; + } + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Completed RETURN_OP State=%p, RetVal=%p\n", + WalkState, WalkState->ReturnDesc)); + + /* End the control method execution right now */ + + Status = AE_CTRL_TERMINATE; + break; + + case AML_NOOP_OP: + + /* Just do nothing! */ + + break; + + case AML_BREAK_POINT_OP: + + AcpiDbSignalBreakPoint (WalkState); + + /* Call to the OSL in case OS wants a piece of the action */ + + Status = AcpiOsSignal (ACPI_SIGNAL_BREAKPOINT, + "Executed AML Breakpoint opcode"); + break; + + case AML_BREAK_OP: + case AML_CONTINUE_OP: /* ACPI 2.0 */ + + /* Pop and delete control states until we find a while */ + + while (WalkState->ControlState && + (WalkState->ControlState->Control.Opcode != AML_WHILE_OP)) + { + ControlState = AcpiUtPopGenericState (&WalkState->ControlState); + AcpiUtDeleteGenericState (ControlState); + } + + /* No while found? */ + + if (!WalkState->ControlState) + { + return (AE_AML_NO_WHILE); + } + + /* Was: WalkState->AmlLastWhile = WalkState->ControlState->Control.AmlPredicateStart; */ + + WalkState->AmlLastWhile = + WalkState->ControlState->Control.PackageEnd; + + /* Return status depending on opcode */ + + if (Op->Common.AmlOpcode == AML_BREAK_OP) + { + Status = AE_CTRL_BREAK; + } + else + { + Status = AE_CTRL_CONTINUE; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown control opcode=0x%X Op=%p", + Op->Common.AmlOpcode, Op)); + + Status = AE_AML_BAD_OPCODE; + break; + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsdebug.c b/third_party/lib/acpica/source/components/dispatcher/dsdebug.c new file mode 100644 index 000000000..adeb448c4 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsdebug.c @@ -0,0 +1,250 @@ +/****************************************************************************** + * + * Module Name: dsdebug - Parser/Interpreter interface - debugging + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acdisasm.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsdebug") + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/* Local prototypes */ + +static void +AcpiDsPrintNodePathname ( + ACPI_NAMESPACE_NODE *Node, + const char *Message); + + +/******************************************************************************* + * + * FUNCTION: AcpiDsPrintNodePathname + * + * PARAMETERS: Node - Object + * Message - Prefix message + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +static void +AcpiDsPrintNodePathname ( + ACPI_NAMESPACE_NODE *Node, + const char *Message) +{ + ACPI_BUFFER Buffer; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (DsPrintNodePathname); + + if (!Node) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "[NULL NAME]")); + return_VOID; + } + + /* Convert handle to full pathname and print it (with supplied message) */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + Status = AcpiNsHandleToPathname (Node, &Buffer, TRUE); + if (ACPI_SUCCESS (Status)) + { + if (Message) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "%s ", Message)); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "[%s] (Node %p)", + (char *) Buffer.Pointer, Node)); + ACPI_FREE (Buffer.Pointer); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsDumpMethodStack + * + * PARAMETERS: Status - Method execution status + * WalkState - Current state of the parse tree walk + * Op - Executing parse op + * + * RETURN: None + * + * DESCRIPTION: Called when a method has been aborted because of an error. + * Dumps the method execution stack. + * + ******************************************************************************/ + +void +AcpiDsDumpMethodStack ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next; + ACPI_THREAD_STATE *Thread; + ACPI_WALK_STATE *NextWalkState; + ACPI_NAMESPACE_NODE *PreviousMethod = NULL; + ACPI_OPERAND_OBJECT *MethodDesc; + + + ACPI_FUNCTION_TRACE (DsDumpMethodStack); + + /* Ignore control codes, they are not errors */ + + if ((Status & AE_CODE_MASK) == AE_CODE_CONTROL) + { + return_VOID; + } + + /* We may be executing a deferred opcode */ + + if (WalkState->DeferredNode) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Executing subtree for Buffer/Package/Region\n")); + return_VOID; + } + + /* + * If there is no Thread, we are not actually executing a method. + * This can happen when the iASL compiler calls the interpreter + * to perform constant folding. + */ + Thread = WalkState->Thread; + if (!Thread) + { + return_VOID; + } + + /* Display exception and method name */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "\n**** Exception %s during execution of method ", + AcpiFormatException (Status))); + + AcpiDsPrintNodePathname (WalkState->MethodNode, NULL); + + /* Display stack of executing methods */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, + "\n\nMethod Execution Stack:\n")); + NextWalkState = Thread->WalkStateList; + + /* Walk list of linked walk states */ + + while (NextWalkState) + { + MethodDesc = NextWalkState->MethodDesc; + if (MethodDesc) + { + AcpiExStopTraceMethod ( + (ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node, + MethodDesc, WalkState); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + " Method [%4.4s] executing: ", + AcpiUtGetNodeName (NextWalkState->MethodNode))); + + /* First method is the currently executing method */ + + if (NextWalkState == WalkState) + { + if (Op) + { + /* Display currently executing ASL statement */ + + Next = Op->Common.Next; + Op->Common.Next = NULL; + +#ifdef ACPI_DISASSEMBLER + AcpiDmDisassemble (NextWalkState, Op, ACPI_UINT32_MAX); +#endif + Op->Common.Next = Next; + } + } + else + { + /* + * This method has called another method + * NOTE: the method call parse subtree is already deleted at + * this point, so we cannot disassemble the method invocation. + */ + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Call to method ")); + AcpiDsPrintNodePathname (PreviousMethod, NULL); + } + + PreviousMethod = NextWalkState->MethodNode; + NextWalkState = NextWalkState->Next; + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "\n")); + } + + return_VOID; +} + +#else + +void +AcpiDsDumpMethodStack ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + return; +} + +#endif diff --git a/third_party/lib/acpica/source/components/dispatcher/dsfield.c b/third_party/lib/acpica/source/components/dispatcher/dsfield.c new file mode 100644 index 000000000..2516c131d --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsfield.c @@ -0,0 +1,839 @@ +/****************************************************************************** + * + * Module Name: dsfield - Dispatcher field routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acparser.h" + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsfield") + +/* Local prototypes */ + +#ifdef ACPI_ASL_COMPILER +#include "acdisasm.h" + +static ACPI_STATUS +AcpiDsCreateExternalRegion ( + ACPI_STATUS LookupStatus, + ACPI_PARSE_OBJECT *Op, + char *Path, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **Node); +#endif + +static ACPI_STATUS +AcpiDsGetFieldNames ( + ACPI_CREATE_FIELD_INFO *Info, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Arg); + + +#ifdef ACPI_ASL_COMPILER +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateExternalRegion (iASL Disassembler only) + * + * PARAMETERS: LookupStatus - Status from NsLookup operation + * Op - Op containing the Field definition and args + * Path - Pathname of the region + * ` WalkState - Current method state + * Node - Where the new region node is returned + * + * RETURN: Status + * + * DESCRIPTION: Add region to the external list if NOT_FOUND. Create a new + * region node/object. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsCreateExternalRegion ( + ACPI_STATUS LookupStatus, + ACPI_PARSE_OBJECT *Op, + char *Path, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **Node) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + + + if (LookupStatus != AE_NOT_FOUND) + { + return (LookupStatus); + } + + /* + * Table disassembly: + * OperationRegion not found. Generate an External for it, and + * insert the name into the namespace. + */ + AcpiDmAddOpToExternalList (Op, Path, ACPI_TYPE_REGION, 0, 0); + + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_REGION, + ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, WalkState, Node); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Must create and install a region object for the new node */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); + if (!ObjDesc) + { + return (AE_NO_MEMORY); + } + + ObjDesc->Region.Node = *Node; + Status = AcpiNsAttachObject (*Node, ObjDesc, ACPI_TYPE_REGION); + return (Status); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateBufferField + * + * PARAMETERS: Op - Current parse op (CreateXXField) + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Execute the CreateField operators: + * CreateBitFieldOp, + * CreateByteFieldOp, + * CreateWordFieldOp, + * CreateDwordFieldOp, + * CreateQwordFieldOp, + * CreateFieldOp (all of which define a field in a buffer) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateBufferField ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *Arg; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *SecondDesc = NULL; + UINT32 Flags; + + + ACPI_FUNCTION_TRACE (DsCreateBufferField); + + + /* + * Get the NameString argument (name of the new BufferField) + */ + if (Op->Common.AmlOpcode == AML_CREATE_FIELD_OP) + { + /* For CreateField, name is the 4th argument */ + + Arg = AcpiPsGetArg (Op, 3); + } + else + { + /* For all other CreateXXXField operators, name is the 3rd argument */ + + Arg = AcpiPsGetArg (Op, 2); + } + + if (!Arg) + { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + if (WalkState->DeferredNode) + { + Node = WalkState->DeferredNode; + Status = AE_OK; + } + else + { + /* Execute flag should always be set when this function is entered */ + + if (!(WalkState->ParseFlags & ACPI_PARSE_EXECUTE)) + { + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Creating new namespace node, should not already exist */ + + Flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND; + + /* + * Mark node temporary if we are executing a normal control + * method. (Don't mark if this is a module-level code method) + */ + if (WalkState->MethodNode && + !(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) + { + Flags |= ACPI_NS_TEMPORARY; + } + + /* Enter the NameString into the namespace */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, + Arg->Common.Value.String, ACPI_TYPE_ANY, + ACPI_IMODE_LOAD_PASS1, Flags, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.String, Status); + return_ACPI_STATUS (Status); + } + } + + /* + * We could put the returned object (Node) on the object stack for later, + * but for now, we will put it in the "op" object that the parser uses, + * so we can get it again at the end of this scope. + */ + Op->Common.Node = Node; + + /* + * If there is no object attached to the node, this node was just created + * and we need to create the field object. Otherwise, this was a lookup + * of an existing node and we don't want to create the field object again. + */ + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * The Field definition is not fully parsed at this time. + * (We must save the address of the AML for the buffer and index operands) + */ + + /* Create the buffer field object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_BUFFER_FIELD); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * Remember location in AML stream of the field unit opcode and operands + * -- since the buffer and index operands must be evaluated. + */ + SecondDesc = ObjDesc->Common.NextObject; + SecondDesc->Extra.AmlStart = Op->Named.Data; + SecondDesc->Extra.AmlLength = Op->Named.Length; + ObjDesc->BufferField.Node = Node; + + /* Attach constructed field descriptors to parent node */ + + Status = AcpiNsAttachObject (Node, ObjDesc, ACPI_TYPE_BUFFER_FIELD); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + +Cleanup: + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetFieldNames + * + * PARAMETERS: Info - CreateField info structure + * ` WalkState - Current method state + * Arg - First parser arg for the field name list + * + * RETURN: Status + * + * DESCRIPTION: Process all named fields in a field declaration. Names are + * entered into the namespace. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsGetFieldNames ( + ACPI_CREATE_FIELD_INFO *Info, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Arg) +{ + ACPI_STATUS Status; + UINT64 Position; + ACPI_PARSE_OBJECT *Child; + + + ACPI_FUNCTION_TRACE_PTR (DsGetFieldNames, Info); + + + /* First field starts at bit zero */ + + Info->FieldBitPosition = 0; + + /* Process all elements in the field list (of parse nodes) */ + + while (Arg) + { + /* + * Four types of field elements are handled: + * 1) Name - Enters a new named field into the namespace + * 2) Offset - specifies a bit offset + * 3) AccessAs - changes the access mode/attributes + * 4) Connection - Associate a resource template with the field + */ + switch (Arg->Common.AmlOpcode) + { + case AML_INT_RESERVEDFIELD_OP: + + Position = (UINT64) Info->FieldBitPosition + + (UINT64) Arg->Common.Value.Size; + + if (Position > ACPI_UINT32_MAX) + { + ACPI_ERROR ((AE_INFO, + "Bit offset within field too large (> 0xFFFFFFFF)")); + return_ACPI_STATUS (AE_SUPPORT); + } + + Info->FieldBitPosition = (UINT32) Position; + break; + + case AML_INT_ACCESSFIELD_OP: + case AML_INT_EXTACCESSFIELD_OP: + /* + * Get new AccessType, AccessAttribute, and AccessLength fields + * -- to be used for all field units that follow, until the + * end-of-field or another AccessAs keyword is encountered. + * NOTE. These three bytes are encoded in the integer value + * of the parseop for convenience. + * + * In FieldFlags, preserve the flag bits other than the + * ACCESS_TYPE bits. + */ + + /* AccessType (ByteAcc, WordAcc, etc.) */ + + Info->FieldFlags = (UINT8) + ((Info->FieldFlags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | + ((UINT8) ((UINT32) (Arg->Common.Value.Integer & 0x07)))); + + /* AccessAttribute (AttribQuick, AttribByte, etc.) */ + + Info->Attribute = (UINT8) + ((Arg->Common.Value.Integer >> 8) & 0xFF); + + /* AccessLength (for serial/buffer protocols) */ + + Info->AccessLength = (UINT8) + ((Arg->Common.Value.Integer >> 16) & 0xFF); + break; + + case AML_INT_CONNECTION_OP: + /* + * Clear any previous connection. New connection is used for all + * fields that follow, similar to AccessAs + */ + Info->ResourceBuffer = NULL; + Info->ConnectionNode = NULL; + Info->PinNumberIndex = 0; + + /* + * A Connection() is either an actual resource descriptor (buffer) + * or a named reference to a resource template + */ + Child = Arg->Common.Value.Arg; + if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP) + { + Info->ResourceBuffer = Child->Named.Data; + Info->ResourceLength = (UINT16) Child->Named.Value.Integer; + } + else + { + /* Lookup the Connection() namepath, it should already exist */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, + Child->Common.Value.Name, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &Info->ConnectionNode); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Child->Common.Value.Name, Status); + return_ACPI_STATUS (Status); + } + } + break; + + case AML_INT_NAMEDFIELD_OP: + + /* Lookup the name, it should already exist */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, + (char *) &Arg->Named.Name, Info->FieldType, + ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &Info->FieldNode); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE ((char *) &Arg->Named.Name, Status); + return_ACPI_STATUS (Status); + } + else + { + Arg->Common.Node = Info->FieldNode; + Info->FieldBitLength = Arg->Common.Value.Size; + + /* + * If there is no object attached to the node, this node was + * just created and we need to create the field object. + * Otherwise, this was a lookup of an existing node and we + * don't want to create the field object again. + */ + if (!AcpiNsGetAttachedObject (Info->FieldNode)) + { + Status = AcpiExPrepFieldValue (Info); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + + /* Keep track of bit position for the next field */ + + Position = (UINT64) Info->FieldBitPosition + + (UINT64) Arg->Common.Value.Size; + + if (Position > ACPI_UINT32_MAX) + { + ACPI_ERROR ((AE_INFO, + "Field [%4.4s] bit offset too large (> 0xFFFFFFFF)", + ACPI_CAST_PTR (char, &Info->FieldNode->Name))); + return_ACPI_STATUS (AE_SUPPORT); + } + + Info->FieldBitPosition += Info->FieldBitLength; + Info->PinNumberIndex++; /* Index relative to previous Connection() */ + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Invalid opcode in field list: 0x%X", + Arg->Common.AmlOpcode)); + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + Arg = Arg->Common.Next; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateField + * + * PARAMETERS: Op - Op containing the Field definition and args + * RegionNode - Object for the containing Operation Region + * ` WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Create a new field in the specified operation region + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Arg; + ACPI_CREATE_FIELD_INFO Info; + + + ACPI_FUNCTION_TRACE_PTR (DsCreateField, Op); + + + /* First arg is the name of the parent OpRegion (must already exist) */ + + Arg = Op->Common.Value.Arg; + + if (!RegionNode) + { + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Common.Value.Name, + ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, WalkState, &RegionNode); +#ifdef ACPI_ASL_COMPILER + Status = AcpiDsCreateExternalRegion (Status, Arg, + Arg->Common.Value.Name, WalkState, &RegionNode); +#endif + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.Name, Status); + return_ACPI_STATUS (Status); + } + } + + memset (&Info, 0, sizeof (ACPI_CREATE_FIELD_INFO)); + + /* Second arg is the field flags */ + + Arg = Arg->Common.Next; + Info.FieldFlags = (UINT8) Arg->Common.Value.Integer; + Info.Attribute = 0; + + /* Each remaining arg is a Named Field */ + + Info.FieldType = ACPI_TYPE_LOCAL_REGION_FIELD; + Info.RegionNode = RegionNode; + + Status = AcpiDsGetFieldNames (&Info, WalkState, Arg->Common.Next); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitFieldObjects + * + * PARAMETERS: Op - Op containing the Field definition and args + * ` WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: For each "Field Unit" name in the argument list that is + * part of the field declaration, enter the name into the + * namespace. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsInitFieldObjects ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Arg = NULL; + ACPI_NAMESPACE_NODE *Node; + UINT8 Type = 0; + UINT32 Flags; + + + ACPI_FUNCTION_TRACE_PTR (DsInitFieldObjects, Op); + + + /* Execute flag should always be set when this function is entered */ + + if (!(WalkState->ParseFlags & ACPI_PARSE_EXECUTE)) + { + if (WalkState->ParseFlags & ACPI_PARSE_DEFERRED_OP) + { + /* BankField Op is deferred, just return OK */ + + return_ACPI_STATUS (AE_OK); + } + + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * Get the FieldList argument for this opcode. This is the start of the + * list of field elements. + */ + switch (WalkState->Opcode) + { + case AML_FIELD_OP: + + Arg = AcpiPsGetArg (Op, 2); + Type = ACPI_TYPE_LOCAL_REGION_FIELD; + break; + + case AML_BANK_FIELD_OP: + + Arg = AcpiPsGetArg (Op, 4); + Type = ACPI_TYPE_LOCAL_BANK_FIELD; + break; + + case AML_INDEX_FIELD_OP: + + Arg = AcpiPsGetArg (Op, 3); + Type = ACPI_TYPE_LOCAL_INDEX_FIELD; + break; + + default: + + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Creating new namespace node(s), should not already exist */ + + Flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND; + + /* + * Mark node(s) temporary if we are executing a normal control + * method. (Don't mark if this is a module-level code method) + */ + if (WalkState->MethodNode && + !(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) + { + Flags |= ACPI_NS_TEMPORARY; + } + + /* + * Walk the list of entries in the FieldList + * Note: FieldList can be of zero length. In this case, Arg will be NULL. + */ + while (Arg) + { + /* + * Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested + * in the field names in order to enter them into the namespace. + */ + if (Arg->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) + { + Status = AcpiNsLookup (WalkState->ScopeInfo, + (char *) &Arg->Named.Name, Type, ACPI_IMODE_LOAD_PASS1, + Flags, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE ((char *) &Arg->Named.Name, Status); + if (Status != AE_ALREADY_EXISTS) + { + return_ACPI_STATUS (Status); + } + + /* Name already exists, just ignore this error */ + + Status = AE_OK; + } + + Arg->Common.Node = Node; + } + + /* Get the next field element in the list */ + + Arg = Arg->Common.Next; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateBankField + * + * PARAMETERS: Op - Op containing the Field definition and args + * RegionNode - Object for the containing Operation Region + * WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Create a new bank field in the specified operation region + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateBankField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Arg; + ACPI_CREATE_FIELD_INFO Info; + + + ACPI_FUNCTION_TRACE_PTR (DsCreateBankField, Op); + + + /* First arg is the name of the parent OpRegion (must already exist) */ + + Arg = Op->Common.Value.Arg; + if (!RegionNode) + { + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Common.Value.Name, + ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, WalkState, &RegionNode); +#ifdef ACPI_ASL_COMPILER + Status = AcpiDsCreateExternalRegion (Status, Arg, + Arg->Common.Value.Name, WalkState, &RegionNode); +#endif + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.Name, Status); + return_ACPI_STATUS (Status); + } + } + + /* Second arg is the Bank Register (Field) (must already exist) */ + + Arg = Arg->Common.Next; + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Common.Value.String, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, WalkState, &Info.RegisterNode); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.String, Status); + return_ACPI_STATUS (Status); + } + + /* + * Third arg is the BankValue + * This arg is a TermArg, not a constant + * It will be evaluated later, by AcpiDsEvalBankFieldOperands + */ + Arg = Arg->Common.Next; + + /* Fourth arg is the field flags */ + + Arg = Arg->Common.Next; + Info.FieldFlags = (UINT8) Arg->Common.Value.Integer; + + /* Each remaining arg is a Named Field */ + + Info.FieldType = ACPI_TYPE_LOCAL_BANK_FIELD; + Info.RegionNode = RegionNode; + + /* + * Use Info.DataRegisterNode to store BankField Op + * It's safe because DataRegisterNode will never be used when create + * bank field \we store AmlStart and AmlLength in the BankField Op for + * late evaluation. Used in AcpiExPrepFieldValue(Info) + * + * TBD: Or, should we add a field in ACPI_CREATE_FIELD_INFO, like + * "void *ParentOp"? + */ + Info.DataRegisterNode = (ACPI_NAMESPACE_NODE*) Op; + + Status = AcpiDsGetFieldNames (&Info, WalkState, Arg->Common.Next); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateIndexField + * + * PARAMETERS: Op - Op containing the Field definition and args + * RegionNode - Object for the containing Operation Region + * ` WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Create a new index field in the specified operation region + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateIndexField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Arg; + ACPI_CREATE_FIELD_INFO Info; + + + ACPI_FUNCTION_TRACE_PTR (DsCreateIndexField, Op); + + + /* First arg is the name of the Index register (must already exist) */ + + Arg = Op->Common.Value.Arg; + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Common.Value.String, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, WalkState, &Info.RegisterNode); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.String, Status); + return_ACPI_STATUS (Status); + } + + /* Second arg is the data register (must already exist) */ + + Arg = Arg->Common.Next; + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Common.Value.String, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, WalkState, &Info.DataRegisterNode); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.String, Status); + return_ACPI_STATUS (Status); + } + + /* Next arg is the field flags */ + + Arg = Arg->Common.Next; + Info.FieldFlags = (UINT8) Arg->Common.Value.Integer; + + /* Each remaining arg is a Named Field */ + + Info.FieldType = ACPI_TYPE_LOCAL_INDEX_FIELD; + Info.RegionNode = RegionNode; + + Status = AcpiDsGetFieldNames (&Info, WalkState, Arg->Common.Next); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsinit.c b/third_party/lib/acpica/source/components/dispatcher/dsinit.c new file mode 100644 index 000000000..74e974da0 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsinit.c @@ -0,0 +1,280 @@ +/****************************************************************************** + * + * Module Name: dsinit - Object initialization namespace walk + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "actables.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsinit") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsInitOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitOneObject + * + * PARAMETERS: ObjHandle - Node for the object + * Level - Current nesting level + * Context - Points to a init info struct + * ReturnValue - Not used + * + * RETURN: Status + * + * DESCRIPTION: Callback from AcpiWalkNamespace. Invoked for every object + * within the namespace. + * + * Currently, the only objects that require initialization are: + * 1) Methods + * 2) Operation Regions + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsInitOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_INIT_WALK_INFO *Info = (ACPI_INIT_WALK_INFO *) Context; + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * We are only interested in NS nodes owned by the table that + * was just loaded + */ + if (Node->OwnerId != Info->OwnerId) + { + return (AE_OK); + } + + Info->ObjectCount++; + + /* And even then, we are only interested in a few object types */ + + switch (AcpiNsGetType (ObjHandle)) + { + case ACPI_TYPE_REGION: + + Status = AcpiDsInitializeRegion (ObjHandle); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "During Region initialization %p [%4.4s]", + ObjHandle, AcpiUtGetNodeName (ObjHandle))); + } + + Info->OpRegionCount++; + break; + + case ACPI_TYPE_METHOD: + /* + * Auto-serialization support. We will examine each method that is + * NotSerialized to determine if it creates any Named objects. If + * it does, it will be marked serialized to prevent problems if + * the method is entered by two or more threads and an attempt is + * made to create the same named object twice -- which results in + * an AE_ALREADY_EXISTS exception and method abort. + */ + Info->MethodCount++; + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + break; + } + + /* Ignore if already serialized */ + + if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) + { + Info->SerialMethodCount++; + break; + } + + if (AcpiGbl_AutoSerializeMethods) + { + /* Parse/scan method and serialize it if necessary */ + + AcpiDsAutoSerializeMethod (Node, ObjDesc); + if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) + { + /* Method was just converted to Serialized */ + + Info->SerialMethodCount++; + Info->SerializedMethodCount++; + break; + } + } + + Info->NonSerialMethodCount++; + break; + + case ACPI_TYPE_DEVICE: + + Info->DeviceCount++; + break; + + default: + + break; + } + + /* + * We ignore errors from above, and always return OK, since + * we don't want to abort the walk on a single error. + */ + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitializeObjects + * + * PARAMETERS: TableDesc - Descriptor for parent ACPI table + * StartNode - Root of subtree to be initialized. + * + * RETURN: Status + * + * DESCRIPTION: Walk the namespace starting at "StartNode" and perform any + * necessary initialization on the objects found therein + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsInitializeObjects ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode) +{ + ACPI_STATUS Status; + ACPI_INIT_WALK_INFO Info; + ACPI_TABLE_HEADER *Table; + ACPI_OWNER_ID OwnerId; + + + ACPI_FUNCTION_TRACE (DsInitializeObjects); + + + Status = AcpiTbGetOwnerId (TableIndex, &OwnerId); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "**** Starting initialization of namespace objects ****\n")); + + /* Set all init info to zero */ + + memset (&Info, 0, sizeof (ACPI_INIT_WALK_INFO)); + + Info.OwnerId = OwnerId; + Info.TableIndex = TableIndex; + + /* Walk entire namespace from the supplied root */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * We don't use AcpiWalkNamespace since we do not want to acquire + * the namespace reader lock. + */ + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, StartNode, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, AcpiDsInitOneObject, NULL, &Info, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During WalkNamespace")); + } + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + Status = AcpiGetTableByIndex (TableIndex, &Table); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* DSDT is always the first AML table */ + + if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT)) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "\nInitializing Namespace objects:\n")); + } + + /* Summary of objects initialized */ + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Table [%4.4s: %-8.8s] (id %.2X) - %4u Objects with %3u Devices, " + "%3u Regions, %4u Methods (%u/%u/%u Serial/Non/Cvt)\n", + Table->Signature, Table->OemTableId, OwnerId, Info.ObjectCount, + Info.DeviceCount,Info.OpRegionCount, Info.MethodCount, + Info.SerialMethodCount, Info.NonSerialMethodCount, + Info.SerializedMethodCount)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "%u Methods, %u Regions\n", + Info.MethodCount, Info.OpRegionCount)); + + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsmethod.c b/third_party/lib/acpica/source/components/dispatcher/dsmethod.c new file mode 100644 index 000000000..356739ac2 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsmethod.c @@ -0,0 +1,907 @@ +/****************************************************************************** + * + * Module Name: dsmethod - Parser/Interpreter interface - control method parsing + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsmethod") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsDetectNamedOpcodes ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +static ACPI_STATUS +AcpiDsCreateMethodMutex ( + ACPI_OPERAND_OBJECT *MethodDesc); + + +/******************************************************************************* + * + * FUNCTION: AcpiDsAutoSerializeMethod + * + * PARAMETERS: Node - Namespace Node of the method + * ObjDesc - Method object attached to node + * + * RETURN: Status + * + * DESCRIPTION: Parse a control method AML to scan for control methods that + * need serialization due to the creation of named objects. + * + * NOTE: It is a bit of overkill to mark all such methods serialized, since + * there is only a problem if the method actually blocks during execution. + * A blocking operation is, for example, a Sleep() operation, or any access + * to an operation region. However, it is probably not possible to easily + * detect whether a method will block or not, so we simply mark all suspicious + * methods as serialized. + * + * NOTE2: This code is essentially a generic routine for parsing a single + * control method. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsAutoSerializeMethod ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Op = NULL; + ACPI_WALK_STATE *WalkState; + + + ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node); + + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Method auto-serialization parse [%4.4s] %p\n", + AcpiUtGetNodeName (Node), Node)); + + /* Create/Init a root op for the method parse tree */ + + Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart); + if (!Op) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + AcpiPsSetName (Op, Node->Name.Integer); + Op->Common.Node = Node; + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL); + if (!WalkState) + { + AcpiPsFreeOp (Op); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Status = AcpiDsInitAmlWalk (WalkState, Op, Node, + ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0); + if (ACPI_FAILURE (Status)) + { + AcpiDsDeleteWalkState (WalkState); + AcpiPsFreeOp (Op); + return_ACPI_STATUS (Status); + } + + WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes; + + /* Parse the method, scan for creation of named objects */ + + Status = AcpiPsParseAml (WalkState); + + AcpiPsDeleteParseTree (Op); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsDetectNamedOpcodes + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * OutOp - Unused, required for parser interface + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * Currently used to detect methods that must be marked serialized + * in order to avoid problems with the creation of named objects. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsDetectNamedOpcodes ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp) +{ + + ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes); + + + /* We are only interested in opcodes that create a new name */ + + if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD))) + { + return (AE_OK); + } + + /* + * At this point, we know we have a Named object opcode. + * Mark the method as serialized. Later code will create a mutex for + * this method to enforce serialization. + * + * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the + * Sync Level mechanism for this method, even though it is now serialized. + * Otherwise, there can be conflicts with existing ASL code that actually + * uses sync levels. + */ + WalkState->MethodDesc->Method.SyncLevel = 0; + WalkState->MethodDesc->Method.InfoFlags |= + (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", + WalkState->MethodNode->Name.Ascii, WalkState->MethodNode, + WalkState->OpInfo->Name, WalkState->Opcode)); + + /* Abort the parse, no need to examine this method any further */ + + return (AE_CTRL_TERMINATE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodError + * + * PARAMETERS: Status - Execution status + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Called on method error. Invoke the global exception handler if + * present, dump the method data if the debugger is configured + * + * Note: Allows the exception handler to change the status code + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState) +{ + UINT32 AmlOffset; + + + ACPI_FUNCTION_ENTRY (); + + + /* Ignore AE_OK and control exception codes */ + + if (ACPI_SUCCESS (Status) || + (Status & AE_CODE_CONTROL)) + { + return (Status); + } + + /* Invoke the global exception handler */ + + if (AcpiGbl_ExceptionHandler) + { + /* Exit the interpreter, allow handler to execute methods */ + + AcpiExExitInterpreter (); + + /* + * Handler can map the exception code to anything it wants, including + * AE_OK, in which case the executing method will not be aborted. + */ + AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml, + WalkState->ParserState.AmlStart); + + Status = AcpiGbl_ExceptionHandler (Status, + WalkState->MethodNode ? + WalkState->MethodNode->Name.Integer : 0, + WalkState->Opcode, AmlOffset, NULL); + AcpiExEnterInterpreter (); + } + + AcpiDsClearImplicitReturn (WalkState); + + if (ACPI_FAILURE (Status)) + { + AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op); + + /* Display method locals/args if debugger is present */ + +#ifdef ACPI_DEBUGGER + AcpiDbDumpMethodInfo (Status, WalkState); +#endif + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateMethodMutex + * + * PARAMETERS: ObjDesc - The method object + * + * RETURN: Status + * + * DESCRIPTION: Create a mutex object for a serialized control method + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsCreateMethodMutex ( + ACPI_OPERAND_OBJECT *MethodDesc) +{ + ACPI_OPERAND_OBJECT *MutexDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (DsCreateMethodMutex); + + + /* Create the new mutex object */ + + MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); + if (!MutexDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Create the actual OS Mutex */ + + Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex); + if (ACPI_FAILURE (Status)) + { + AcpiUtDeleteObjectDesc (MutexDesc); + return_ACPI_STATUS (Status); + } + + MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel; + MethodDesc->Method.Mutex = MutexDesc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsBeginMethodExecution + * + * PARAMETERS: MethodNode - Node of the method + * ObjDesc - The method object + * WalkState - current state, NULL if not yet executing + * a method. + * + * RETURN: Status + * + * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, + * increments the thread count, and waits at the method semaphore + * for clearance to execute. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsBeginMethodExecution ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode); + + + if (!MethodNode) + { + return_ACPI_STATUS (AE_NULL_ENTRY); + } + + AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState); + + /* Prevent wraparound of thread count */ + + if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX) + { + ACPI_ERROR ((AE_INFO, + "Method reached maximum reentrancy limit (255)")); + return_ACPI_STATUS (AE_AML_METHOD_LIMIT); + } + + /* + * If this method is serialized, we need to acquire the method mutex. + */ + if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) + { + /* + * Create a mutex for the method if it is defined to be Serialized + * and a mutex has not already been created. We defer the mutex creation + * until a method is actually executed, to minimize the object count + */ + if (!ObjDesc->Method.Mutex) + { + Status = AcpiDsCreateMethodMutex (ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * The CurrentSyncLevel (per-thread) must be less than or equal to + * the sync level of the method. This mechanism provides some + * deadlock prevention. + * + * If the method was auto-serialized, we just ignore the sync level + * mechanism, because auto-serialization of methods can interfere + * with ASL code that actually uses sync levels. + * + * Top-level method invocation has no walk state at this point + */ + if (WalkState && + (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) && + (WalkState->Thread->CurrentSyncLevel > + ObjDesc->Method.Mutex->Mutex.SyncLevel)) + { + ACPI_ERROR ((AE_INFO, + "Cannot acquire Mutex for method [%4.4s]" + ", current SyncLevel is too large (%u)", + AcpiUtGetNodeName (MethodNode), + WalkState->Thread->CurrentSyncLevel)); + + return_ACPI_STATUS (AE_AML_MUTEX_ORDER); + } + + /* + * Obtain the method mutex if necessary. Do not acquire mutex for a + * recursive call. + */ + if (!WalkState || + !ObjDesc->Method.Mutex->Mutex.ThreadId || + (WalkState->Thread->ThreadId != + ObjDesc->Method.Mutex->Mutex.ThreadId)) + { + /* + * Acquire the method mutex. This releases the interpreter if we + * block (and reacquires it before it returns) + */ + Status = AcpiExSystemWaitMutex ( + ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Update the mutex and walk info and save the original SyncLevel */ + + if (WalkState) + { + ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = + WalkState->Thread->CurrentSyncLevel; + + ObjDesc->Method.Mutex->Mutex.ThreadId = + WalkState->Thread->ThreadId; + + /* + * Update the current SyncLevel only if this is not an auto- + * serialized method. In the auto case, we have to ignore + * the sync level for the method mutex (created for the + * auto-serialization) because we have no idea of what the + * sync level should be. Therefore, just ignore it. + */ + if (!(ObjDesc->Method.InfoFlags & + ACPI_METHOD_IGNORE_SYNC_LEVEL)) + { + WalkState->Thread->CurrentSyncLevel = + ObjDesc->Method.SyncLevel; + } + } + else + { + ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = + ObjDesc->Method.Mutex->Mutex.SyncLevel; + } + } + + /* Always increase acquisition depth */ + + ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; + } + + /* + * Allocate an Owner ID for this method, only if this is the first thread + * to begin concurrent execution. We only need one OwnerId, even if the + * method is invoked recursively. + */ + if (!ObjDesc->Method.OwnerId) + { + Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + } + + /* + * Increment the method parse tree thread count since it has been + * reentered one more time (even if it is the same thread) + */ + ObjDesc->Method.ThreadCount++; + AcpiMethodCount++; + return_ACPI_STATUS (Status); + + +Cleanup: + /* On error, must release the method mutex (if present) */ + + if (ObjDesc->Method.Mutex) + { + AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); + } + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCallControlMethod + * + * PARAMETERS: Thread - Info for this thread + * ThisWalkState - Current walk state + * Op - Current Op to be walked + * + * RETURN: Status + * + * DESCRIPTION: Transfer execution to a called control method + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCallControlMethod ( + ACPI_THREAD_STATE *Thread, + ACPI_WALK_STATE *ThisWalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *MethodNode; + ACPI_WALK_STATE *NextWalkState = NULL; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_EVALUATE_INFO *Info; + UINT32 i; + + + ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Calling method %p, currentstate=%p\n", + ThisWalkState->PrevOp, ThisWalkState)); + + /* + * Get the namespace entry for the control method we are about to call + */ + MethodNode = ThisWalkState->MethodCallNode; + if (!MethodNode) + { + return_ACPI_STATUS (AE_NULL_ENTRY); + } + + ObjDesc = AcpiNsGetAttachedObject (MethodNode); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Init for new method, possibly wait on method mutex */ + + Status = AcpiDsBeginMethodExecution ( + MethodNode, ObjDesc, ThisWalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Begin method parse/execution. Create a new walk state */ + + NextWalkState = AcpiDsCreateWalkState ( + ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread); + if (!NextWalkState) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * The resolved arguments were put on the previous walk state's operand + * stack. Operands on the previous walk state stack always + * start at index 0. Also, null terminate the list of arguments + */ + ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; + + /* + * Allocate and initialize the evaluation information block + * TBD: this is somewhat inefficient, should change interface to + * DsInitAmlWalk. For now, keeps this struct off the CPU stack + */ + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + Info->Parameters = &ThisWalkState->Operands[0]; + + Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, + ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, + Info, ACPI_IMODE_EXECUTE); + + ACPI_FREE (Info); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * Delete the operands on the previous walkstate operand stack + * (they were copied to new objects) + */ + for (i = 0; i < ObjDesc->Method.ParamCount; i++) + { + AcpiUtRemoveReference (ThisWalkState->Operands [i]); + ThisWalkState->Operands [i] = NULL; + } + + /* Clear the operand stack */ + + ThisWalkState->NumOperands = 0; + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", + MethodNode->Name.Ascii, NextWalkState)); + + /* Invoke an internal method if necessary */ + + if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) + { + Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); + if (Status == AE_OK) + { + Status = AE_CTRL_TERMINATE; + } + } + + return_ACPI_STATUS (Status); + + +Cleanup: + + /* On error, we must terminate the method properly */ + + AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); + AcpiDsDeleteWalkState (NextWalkState); + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsRestartControlMethod + * + * PARAMETERS: WalkState - State for preempted method (caller) + * ReturnDesc - Return value from the called method + * + * RETURN: Status + * + * DESCRIPTION: Restart a method that was preempted by another (nested) method + * invocation. Handle the return value (if any) from the callee. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsRestartControlMethod ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ReturnDesc) +{ + ACPI_STATUS Status; + int SameAsImplicitReturn; + + + ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", + AcpiUtGetNodeName (WalkState->MethodNode), + WalkState->MethodCallOp, ReturnDesc)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", + WalkState->ReturnUsed, + WalkState->Results, WalkState)); + + /* Did the called method return a value? */ + + if (ReturnDesc) + { + /* Is the implicit return object the same as the return desc? */ + + SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); + + /* Are we actually going to use the return value? */ + + if (WalkState->ReturnUsed) + { + /* Save the return value from the previous method */ + + Status = AcpiDsResultPush (ReturnDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + return_ACPI_STATUS (Status); + } + + /* + * Save as THIS method's return value in case it is returned + * immediately to yet another method + */ + WalkState->ReturnDesc = ReturnDesc; + } + + /* + * The following code is the optional support for the so-called + * "implicit return". Some AML code assumes that the last value of the + * method is "implicitly" returned to the caller, in the absence of an + * explicit return value. + * + * Just save the last result of the method as the return value. + * + * NOTE: this is optional because the ASL language does not actually + * support this behavior. + */ + else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || + SameAsImplicitReturn) + { + /* + * Delete the return value if it will not be used by the + * calling method or remove one reference if the explicit return + * is the same as the implicit return value. + */ + AcpiUtRemoveReference (ReturnDesc); + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsTerminateControlMethod + * + * PARAMETERS: MethodDesc - Method object + * WalkState - State associated with the method + * + * RETURN: None + * + * DESCRIPTION: Terminate a control method. Delete everything that the method + * created, delete all locals and arguments, and delete the parse + * tree if requested. + * + * MUTEX: Interpreter is locked + * + ******************************************************************************/ + +void +AcpiDsTerminateControlMethod ( + ACPI_OPERAND_OBJECT *MethodDesc, + ACPI_WALK_STATE *WalkState) +{ + + ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); + + + /* MethodDesc is required, WalkState is optional */ + + if (!MethodDesc) + { + return_VOID; + } + + if (WalkState) + { + /* Delete all arguments and locals */ + + AcpiDsMethodDataDeleteAll (WalkState); + + /* + * If method is serialized, release the mutex and restore the + * current sync level for this thread + */ + if (MethodDesc->Method.Mutex) + { + /* Acquisition Depth handles recursive calls */ + + MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; + if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) + { + WalkState->Thread->CurrentSyncLevel = + MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; + + AcpiOsReleaseMutex ( + MethodDesc->Method.Mutex->Mutex.OsMutex); + MethodDesc->Method.Mutex->Mutex.ThreadId = 0; + } + } + + /* + * Delete any namespace objects created anywhere within the + * namespace by the execution of this method. Unless: + * 1) This method is a module-level executable code method, in which + * case we want make the objects permanent. + * 2) There are other threads executing the method, in which case we + * will wait until the last thread has completed. + */ + if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && + (MethodDesc->Method.ThreadCount == 1)) + { + /* Delete any direct children of (created by) this method */ + + AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); + + /* + * Delete any objects that were created by this method + * elsewhere in the namespace (if any were created). + * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the + * deletion such that we don't have to perform an entire + * namespace walk for every control method execution. + */ + if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) + { + AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); + MethodDesc->Method.InfoFlags &= + ~ACPI_METHOD_MODIFIED_NAMESPACE; + } + } + } + + /* Decrement the thread count on the method */ + + if (MethodDesc->Method.ThreadCount) + { + MethodDesc->Method.ThreadCount--; + } + else + { + ACPI_ERROR ((AE_INFO, + "Invalid zero thread count in method")); + } + + /* Are there any other threads currently executing this method? */ + + if (MethodDesc->Method.ThreadCount) + { + /* + * Additional threads. Do not release the OwnerId in this case, + * we immediately reuse it for the next thread executing this method + */ + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "*** Completed execution of one thread, %u threads remaining\n", + MethodDesc->Method.ThreadCount)); + } + else + { + /* This is the only executing thread for this method */ + + /* + * Support to dynamically change a method from NotSerialized to + * Serialized if it appears that the method is incorrectly written and + * does not support multiple thread execution. The best example of this + * is if such a method creates namespace objects and blocks. A second + * thread will fail with an AE_ALREADY_EXISTS exception. + * + * This code is here because we must wait until the last thread exits + * before marking the method as serialized. + */ + if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) + { + if (WalkState) + { + ACPI_INFO ((AE_INFO, + "Marking method %4.4s as Serialized " + "because of AE_ALREADY_EXISTS error", + WalkState->MethodNode->Name.Ascii)); + } + + /* + * Method tried to create an object twice and was marked as + * "pending serialized". The probable cause is that the method + * cannot handle reentrancy. + * + * The method was created as NotSerialized, but it tried to create + * a named object and then blocked, causing the second thread + * entrance to begin and then fail. Workaround this problem by + * marking the method permanently as Serialized when the last + * thread exits here. + */ + MethodDesc->Method.InfoFlags &= + ~ACPI_METHOD_SERIALIZED_PENDING; + + MethodDesc->Method.InfoFlags |= + (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); + MethodDesc->Method.SyncLevel = 0; + } + + /* No more threads, we can free the OwnerId */ + + if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) + { + AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); + } + } + + AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node, + MethodDesc, WalkState); + + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsmthdat.c b/third_party/lib/acpica/source/components/dispatcher/dsmthdat.c new file mode 100644 index 000000000..32f9850a7 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsmthdat.c @@ -0,0 +1,777 @@ +/******************************************************************************* + * + * Module Name: dsmthdat - control method arguments and local variables + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsmthdat") + +/* Local prototypes */ + +static void +AcpiDsMethodDataDeleteValue ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState); + +static ACPI_STATUS +AcpiDsMethodDataSetValue ( + UINT8 Type, + UINT32 Index, + ACPI_OPERAND_OBJECT *Object, + ACPI_WALK_STATE *WalkState); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +ACPI_OBJECT_TYPE +AcpiDsMethodDataGetType ( + UINT16 Opcode, + UINT32 Index, + ACPI_WALK_STATE *WalkState); +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataInit + * + * PARAMETERS: WalkState - Current walk state object + * + * RETURN: Status + * + * DESCRIPTION: Initialize the data structures that hold the method's arguments + * and locals. The data struct is an array of namespace nodes for + * each - this allows RefOf and DeRefOf to work properly for these + * special data types. + * + * NOTES: WalkState fields are initialized to zero by the + * ACPI_ALLOCATE_ZEROED(). + * + * A pseudo-Namespace Node is assigned to each argument and local + * so that RefOf() can return a pointer to the Node. + * + ******************************************************************************/ + +void +AcpiDsMethodDataInit ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 i; + + + ACPI_FUNCTION_TRACE (DsMethodDataInit); + + + /* Init the method arguments */ + + for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) + { + ACPI_MOVE_32_TO_32 (&WalkState->Arguments[i].Name, + NAMEOF_ARG_NTE); + + WalkState->Arguments[i].Name.Integer |= (i << 24); + WalkState->Arguments[i].DescriptorType = ACPI_DESC_TYPE_NAMED; + WalkState->Arguments[i].Type = ACPI_TYPE_ANY; + WalkState->Arguments[i].Flags = ANOBJ_METHOD_ARG; + } + + /* Init the method locals */ + + for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) + { + ACPI_MOVE_32_TO_32 (&WalkState->LocalVariables[i].Name, + NAMEOF_LOCAL_NTE); + + WalkState->LocalVariables[i].Name.Integer |= (i << 24); + WalkState->LocalVariables[i].DescriptorType = ACPI_DESC_TYPE_NAMED; + WalkState->LocalVariables[i].Type = ACPI_TYPE_ANY; + WalkState->LocalVariables[i].Flags = ANOBJ_METHOD_LOCAL; + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataDeleteAll + * + * PARAMETERS: WalkState - Current walk state object + * + * RETURN: None + * + * DESCRIPTION: Delete method locals and arguments. Arguments are only + * deleted if this method was called from another method. + * + ******************************************************************************/ + +void +AcpiDsMethodDataDeleteAll ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 Index; + + + ACPI_FUNCTION_TRACE (DsMethodDataDeleteAll); + + + /* Detach the locals */ + + for (Index = 0; Index < ACPI_METHOD_NUM_LOCALS; Index++) + { + if (WalkState->LocalVariables[Index].Object) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%u=%p\n", + Index, WalkState->LocalVariables[Index].Object)); + + /* Detach object (if present) and remove a reference */ + + AcpiNsDetachObject (&WalkState->LocalVariables[Index]); + } + } + + /* Detach the arguments */ + + for (Index = 0; Index < ACPI_METHOD_NUM_ARGS; Index++) + { + if (WalkState->Arguments[Index].Object) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%u=%p\n", + Index, WalkState->Arguments[Index].Object)); + + /* Detach object (if present) and remove a reference */ + + AcpiNsDetachObject (&WalkState->Arguments[Index]); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataInitArgs + * + * PARAMETERS: *Params - Pointer to a parameter list for the method + * MaxParamCount - The arg count for this method + * WalkState - Current walk state object + * + * RETURN: Status + * + * DESCRIPTION: Initialize arguments for a method. The parameter list is a list + * of ACPI operand objects, either null terminated or whose length + * is defined by MaxParamCount. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsMethodDataInitArgs ( + ACPI_OPERAND_OBJECT **Params, + UINT32 MaxParamCount, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + UINT32 Index = 0; + + + ACPI_FUNCTION_TRACE_PTR (DsMethodDataInitArgs, Params); + + + if (!Params) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "No parameter list passed to method\n")); + return_ACPI_STATUS (AE_OK); + } + + /* Copy passed parameters into the new method stack frame */ + + while ((Index < ACPI_METHOD_NUM_ARGS) && + (Index < MaxParamCount) && + Params[Index]) + { + /* + * A valid parameter. + * Store the argument in the method/walk descriptor. + * Do not copy the arg in order to implement call by reference + */ + Status = AcpiDsMethodDataSetValue ( + ACPI_REFCLASS_ARG, Index, Params[Index], WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Index++; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%u args passed to method\n", Index)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataGetNode + * + * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or + * ACPI_REFCLASS_ARG + * Index - Which Local or Arg whose type to get + * WalkState - Current walk state object + * Node - Where the node is returned. + * + * RETURN: Status and node + * + * DESCRIPTION: Get the Node associated with a local or arg. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsMethodDataGetNode ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **Node) +{ + ACPI_FUNCTION_TRACE (DsMethodDataGetNode); + + + /* + * Method Locals and Arguments are supported + */ + switch (Type) + { + case ACPI_REFCLASS_LOCAL: + + if (Index > ACPI_METHOD_MAX_LOCAL) + { + ACPI_ERROR ((AE_INFO, + "Local index %u is invalid (max %u)", + Index, ACPI_METHOD_MAX_LOCAL)); + return_ACPI_STATUS (AE_AML_INVALID_INDEX); + } + + /* Return a pointer to the pseudo-node */ + + *Node = &WalkState->LocalVariables[Index]; + break; + + case ACPI_REFCLASS_ARG: + + if (Index > ACPI_METHOD_MAX_ARG) + { + ACPI_ERROR ((AE_INFO, + "Arg index %u is invalid (max %u)", + Index, ACPI_METHOD_MAX_ARG)); + return_ACPI_STATUS (AE_AML_INVALID_INDEX); + } + + /* Return a pointer to the pseudo-node */ + + *Node = &WalkState->Arguments[Index]; + break; + + default: + + ACPI_ERROR ((AE_INFO, "Type %u is invalid", Type)); + return_ACPI_STATUS (AE_TYPE); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataSetValue + * + * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or + * ACPI_REFCLASS_ARG + * Index - Which Local or Arg to get + * Object - Object to be inserted into the stack entry + * WalkState - Current walk state object + * + * RETURN: Status + * + * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index. + * Note: There is no "implicit conversion" for locals. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsMethodDataSetValue ( + UINT8 Type, + UINT32 Index, + ACPI_OPERAND_OBJECT *Object, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (DsMethodDataSetValue); + + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "NewObj %p Type %2.2X, Refs=%u [%s]\n", Object, + Type, Object->Common.ReferenceCount, + AcpiUtGetTypeName (Object->Common.Type))); + + /* Get the namespace node for the arg/local */ + + Status = AcpiDsMethodDataGetNode (Type, Index, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Increment ref count so object can't be deleted while installed. + * NOTE: We do not copy the object in order to preserve the call by + * reference semantics of ACPI Control Method invocation. + * (See ACPI Specification 2.0C) + */ + AcpiUtAddReference (Object); + + /* Install the object */ + + Node->Object = Object; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataGetValue + * + * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or + * ACPI_REFCLASS_ARG + * Index - Which localVar or argument to get + * WalkState - Current walk state object + * DestDesc - Where Arg or Local value is returned + * + * RETURN: Status + * + * DESCRIPTION: Retrieve value of selected Arg or Local for this method + * Used only in AcpiExResolveToValue(). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsMethodDataGetValue ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **DestDesc) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *Object; + + + ACPI_FUNCTION_TRACE (DsMethodDataGetValue); + + + /* Validate the object descriptor */ + + if (!DestDesc) + { + ACPI_ERROR ((AE_INFO, "Null object descriptor pointer")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the namespace node for the arg/local */ + + Status = AcpiDsMethodDataGetNode (Type, Index, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get the object from the node */ + + Object = Node->Object; + + /* Examine the returned object, it must be valid. */ + + if (!Object) + { + /* + * Index points to uninitialized object. + * This means that either 1) The expected argument was + * not passed to the method, or 2) A local variable + * was referenced by the method (via the ASL) + * before it was initialized. Either case is an error. + */ + + /* If slack enabled, init the LocalX/ArgX to an Integer of value zero */ + + if (AcpiGbl_EnableInterpreterSlack) + { + Object = AcpiUtCreateIntegerObject ((UINT64) 0); + if (!Object) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Node->Object = Object; + } + + /* Otherwise, return the error */ + + else switch (Type) + { + case ACPI_REFCLASS_ARG: + + ACPI_ERROR ((AE_INFO, + "Uninitialized Arg[%u] at node %p", + Index, Node)); + + return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG); + + case ACPI_REFCLASS_LOCAL: + /* + * No error message for this case, will be trapped again later to + * detect and ignore cases of Store(LocalX,LocalX) + */ + return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); + + default: + + ACPI_ERROR ((AE_INFO, "Not a Arg/Local opcode: 0x%X", Type)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + } + + /* + * The Index points to an initialized and valid object. + * Return an additional reference to the object + */ + *DestDesc = Object; + AcpiUtAddReference (Object); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataDeleteValue + * + * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or + * ACPI_REFCLASS_ARG + * Index - Which localVar or argument to delete + * WalkState - Current walk state object + * + * RETURN: None + * + * DESCRIPTION: Delete the entry at Opcode:Index. Inserts + * a null into the stack slot after the object is deleted. + * + ******************************************************************************/ + +static void +AcpiDsMethodDataDeleteValue ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *Object; + + + ACPI_FUNCTION_TRACE (DsMethodDataDeleteValue); + + + /* Get the namespace node for the arg/local */ + + Status = AcpiDsMethodDataGetNode (Type, Index, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + /* Get the associated object */ + + Object = AcpiNsGetAttachedObject (Node); + + /* + * Undefine the Arg or Local by setting its descriptor + * pointer to NULL. Locals/Args can contain both + * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs + */ + Node->Object = NULL; + + if ((Object) && + (ACPI_GET_DESCRIPTOR_TYPE (Object) == ACPI_DESC_TYPE_OPERAND)) + { + /* + * There is a valid object. + * Decrement the reference count by one to balance the + * increment when the object was stored. + */ + AcpiUtRemoveReference (Object); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsStoreObjectToLocal + * + * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or + * ACPI_REFCLASS_ARG + * Index - Which Local or Arg to set + * ObjDesc - Value to be stored + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Store a value in an Arg or Local. The ObjDesc is installed + * as the new value for the Arg or Local and the reference count + * for ObjDesc is incremented. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsStoreObjectToLocal ( + UINT8 Type, + UINT32 Index, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *CurrentObjDesc; + ACPI_OPERAND_OBJECT *NewObjDesc; + + + ACPI_FUNCTION_TRACE (DsStoreObjectToLocal); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n", + Type, Index, ObjDesc)); + + /* Parameter validation */ + + if (!ObjDesc) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the namespace node for the arg/local */ + + Status = AcpiDsMethodDataGetNode (Type, Index, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + CurrentObjDesc = AcpiNsGetAttachedObject (Node); + if (CurrentObjDesc == ObjDesc) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", + ObjDesc)); + return_ACPI_STATUS (Status); + } + + /* + * If the reference count on the object is more than one, we must + * take a copy of the object before we store. A reference count + * of exactly 1 means that the object was just created during the + * evaluation of an expression, and we can safely use it since it + * is not used anywhere else. + */ + NewObjDesc = ObjDesc; + if (ObjDesc->Common.ReferenceCount > 1) + { + Status = AcpiUtCopyIobjectToIobject ( + ObjDesc, &NewObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * If there is an object already in this slot, we either + * have to delete it, or if this is an argument and there + * is an object reference stored there, we have to do + * an indirect store! + */ + if (CurrentObjDesc) + { + /* + * Check for an indirect store if an argument + * contains an object reference (stored as an Node). + * We don't allow this automatic dereferencing for + * locals, since a store to a local should overwrite + * anything there, including an object reference. + * + * If both Arg0 and Local0 contain RefOf (Local4): + * + * Store (1, Arg0) - Causes indirect store to local4 + * Store (1, Local0) - Stores 1 in local0, overwriting + * the reference to local4 + * Store (1, DeRefof (Local0)) - Causes indirect store to local4 + * + * Weird, but true. + */ + if (Type == ACPI_REFCLASS_ARG) + { + /* + * If we have a valid reference object that came from RefOf(), + * do the indirect store + */ + if ((ACPI_GET_DESCRIPTOR_TYPE (CurrentObjDesc) == + ACPI_DESC_TYPE_OPERAND) && + (CurrentObjDesc->Common.Type == + ACPI_TYPE_LOCAL_REFERENCE) && + (CurrentObjDesc->Reference.Class == + ACPI_REFCLASS_REFOF)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Arg (%p) is an ObjRef(Node), storing in node %p\n", + NewObjDesc, CurrentObjDesc)); + + /* + * Store this object to the Node (perform the indirect store) + * NOTE: No implicit conversion is performed, as per the ACPI + * specification rules on storing to Locals/Args. + */ + Status = AcpiExStoreObjectToNode (NewObjDesc, + CurrentObjDesc->Reference.Object, WalkState, + ACPI_NO_IMPLICIT_CONVERSION); + + /* Remove local reference if we copied the object above */ + + if (NewObjDesc != ObjDesc) + { + AcpiUtRemoveReference (NewObjDesc); + } + + return_ACPI_STATUS (Status); + } + } + + /* Delete the existing object before storing the new one */ + + AcpiDsMethodDataDeleteValue (Type, Index, WalkState); + } + + /* + * Install the Obj descriptor (*NewObjDesc) into + * the descriptor for the Arg or Local. + * (increments the object reference count by one) + */ + Status = AcpiDsMethodDataSetValue (Type, Index, NewObjDesc, WalkState); + + /* Remove local reference if we copied the object above */ + + if (NewObjDesc != ObjDesc) + { + AcpiUtRemoveReference (NewObjDesc); + } + + return_ACPI_STATUS (Status); +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: AcpiDsMethodDataGetType + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which Local or Arg whose type to get + * WalkState - Current walk state object + * + * RETURN: Data type of current value of the selected Arg or Local + * + * DESCRIPTION: Get the type of the object stored in the Local or Arg + * + ******************************************************************************/ + +ACPI_OBJECT_TYPE +AcpiDsMethodDataGetType ( + UINT16 Opcode, + UINT32 Index, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *Object; + + + ACPI_FUNCTION_TRACE (DsMethodDataGetType); + + + /* Get the namespace node for the arg/local */ + + Status = AcpiDsMethodDataGetNode (Opcode, Index, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + return_VALUE ((ACPI_TYPE_NOT_FOUND)); + } + + /* Get the object */ + + Object = AcpiNsGetAttachedObject (Node); + if (!Object) + { + /* Uninitialized local/arg, return TYPE_ANY */ + + return_VALUE (ACPI_TYPE_ANY); + } + + /* Get the object type */ + + return_VALUE (Object->Type); +} +#endif diff --git a/third_party/lib/acpica/source/components/dispatcher/dsobject.c b/third_party/lib/acpica/source/components/dispatcher/dsobject.c new file mode 100644 index 000000000..452c66bce --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsobject.c @@ -0,0 +1,864 @@ +/****************************************************************************** + * + * Module Name: dsobject - Dispatcher object management routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsobject") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsBuildInternalObject ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT **ObjDescPtr); + + +#ifndef ACPI_NO_METHOD_EXECUTION +/******************************************************************************* + * + * FUNCTION: AcpiDsBuildInternalObject + * + * PARAMETERS: WalkState - Current walk state + * Op - Parser object to be translated + * ObjDescPtr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op object to the equivalent namespace object + * Simple objects are any objects other than a package object! + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsBuildInternalObject ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT **ObjDescPtr) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + ACPI_OBJECT_TYPE Type; + + + ACPI_FUNCTION_TRACE (DsBuildInternalObject); + + + *ObjDescPtr = NULL; + if (Op->Common.AmlOpcode == AML_INT_NAMEPATH_OP) + { + /* + * This is a named object reference. If this name was + * previously looked up in the namespace, it was stored in this op. + * Otherwise, go ahead and look it up now + */ + if (!Op->Common.Node) + { + Status = AcpiNsLookup (WalkState->ScopeInfo, + Op->Common.Value.String, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, + ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, &(Op->Common.Node))); + if (ACPI_FAILURE (Status)) + { + /* Check if we are resolving a named reference within a package */ + + if ((Status == AE_NOT_FOUND) && (AcpiGbl_EnableInterpreterSlack) && + + ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP))) + { + /* + * We didn't find the target and we are populating elements + * of a package - ignore if slack enabled. Some ASL code + * contains dangling invalid references in packages and + * expects that no exception will be issued. Leave the + * element as a null element. It cannot be used, but it + * can be overwritten by subsequent ASL code - this is + * typically the case. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Ignoring unresolved reference in package [%4.4s]\n", + WalkState->ScopeInfo->Scope.Node->Name.Ascii)); + + return_ACPI_STATUS (AE_OK); + } + else + { + ACPI_ERROR_NAMESPACE (Op->Common.Value.String, Status); + } + + return_ACPI_STATUS (Status); + } + } + + /* Special object resolution for elements of a package */ + + if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) + { + /* + * Attempt to resolve the node to a value before we insert it into + * the package. If this is a reference to a common data type, + * resolve it immediately. According to the ACPI spec, package + * elements can only be "data objects" or method references. + * Attempt to resolve to an Integer, Buffer, String or Package. + * If cannot, return the named reference (for things like Devices, + * Methods, etc.) Buffer Fields and Fields will resolve to simple + * objects (int/buf/str/pkg). + * + * NOTE: References to things like Devices, Methods, Mutexes, etc. + * will remain as named references. This behavior is not described + * in the ACPI spec, but it appears to be an oversight. + */ + ObjDesc = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Op->Common.Node); + + Status = AcpiExResolveNodeToValue ( + ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, &ObjDesc), + WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Special handling for Alias objects. We need to setup the type + * and the Op->Common.Node to point to the Alias target. Note, + * Alias has at most one level of indirection internally. + */ + Type = Op->Common.Node->Type; + if (Type == ACPI_TYPE_LOCAL_ALIAS) + { + Type = ObjDesc->Common.Type; + Op->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, + Op->Common.Node->Object); + } + + switch (Type) + { + /* + * For these types, we need the actual node, not the subobject. + * However, the subobject did not get an extra reference count above. + * + * TBD: should ExResolveNodeToValue be changed to fix this? + */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + AcpiUtAddReference (Op->Common.Node->Object); + + /*lint -fallthrough */ + /* + * For these types, we need the actual node, not the subobject. + * The subobject got an extra reference count in ExResolveNodeToValue. + */ + case ACPI_TYPE_MUTEX: + case ACPI_TYPE_METHOD: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_EVENT: + case ACPI_TYPE_REGION: + + /* We will create a reference object for these types below */ + break; + + default: + /* + * All other types - the node was resolved to an actual + * object, we are done. + */ + goto Exit; + } + } + } + + /* Create and init a new internal ACPI object */ + + ObjDesc = AcpiUtCreateInternalObject ( + (AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode))->ObjectType); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Status = AcpiDsInitObjectFromOp ( + WalkState, Op, Op->Common.AmlOpcode, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); + } + +Exit: + *ObjDescPtr = ObjDesc; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsBuildInternalBufferObj + * + * PARAMETERS: WalkState - Current walk state + * Op - Parser object to be translated + * BufferLength - Length of the buffer + * ObjDescPtr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op package object to the equivalent + * namespace object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsBuildInternalBufferObj ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 BufferLength, + ACPI_OPERAND_OBJECT **ObjDescPtr) +{ + ACPI_PARSE_OBJECT *Arg; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PARSE_OBJECT *ByteList; + UINT32 ByteListLength = 0; + + + ACPI_FUNCTION_TRACE (DsBuildInternalBufferObj); + + + /* + * If we are evaluating a Named buffer object "Name (xxxx, Buffer)". + * The buffer object already exists (from the NS node), otherwise it must + * be created. + */ + ObjDesc = *ObjDescPtr; + if (!ObjDesc) + { + /* Create a new buffer object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_BUFFER); + *ObjDescPtr = ObjDesc; + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + + /* + * Second arg is the buffer data (optional) ByteList can be either + * individual bytes or a string initializer. In either case, a + * ByteList appears in the AML. + */ + Arg = Op->Common.Value.Arg; /* skip first arg */ + + ByteList = Arg->Named.Next; + if (ByteList) + { + if (ByteList->Common.AmlOpcode != AML_INT_BYTELIST_OP) + { + ACPI_ERROR ((AE_INFO, + "Expecting bytelist, found AML opcode 0x%X in op %p", + ByteList->Common.AmlOpcode, ByteList)); + + AcpiUtRemoveReference (ObjDesc); + return (AE_TYPE); + } + + ByteListLength = (UINT32) ByteList->Common.Value.Integer; + } + + /* + * The buffer length (number of bytes) will be the larger of: + * 1) The specified buffer length and + * 2) The length of the initializer byte list + */ + ObjDesc->Buffer.Length = BufferLength; + if (ByteListLength > BufferLength) + { + ObjDesc->Buffer.Length = ByteListLength; + } + + /* Allocate the buffer */ + + if (ObjDesc->Buffer.Length == 0) + { + ObjDesc->Buffer.Pointer = NULL; + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Buffer defined with zero length in AML, creating\n")); + } + else + { + ObjDesc->Buffer.Pointer = + ACPI_ALLOCATE_ZEROED (ObjDesc->Buffer.Length); + if (!ObjDesc->Buffer.Pointer) + { + AcpiUtDeleteObjectDesc (ObjDesc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize buffer from the ByteList (if present) */ + + if (ByteList) + { + memcpy (ObjDesc->Buffer.Pointer, ByteList->Named.Data, + ByteListLength); + } + } + + ObjDesc->Buffer.Flags |= AOPOBJ_DATA_VALID; + Op->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjDesc); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsBuildInternalPackageObj + * + * PARAMETERS: WalkState - Current walk state + * Op - Parser object to be translated + * ElementCount - Number of elements in the package - this is + * the NumElements argument to Package() + * ObjDescPtr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op package object to the equivalent + * namespace object + * + * NOTE: The number of elements in the package will be always be the NumElements + * count, regardless of the number of elements in the package list. If + * NumElements is smaller, only that many package list elements are used. + * if NumElements is larger, the Package object is padded out with + * objects of type Uninitialized (as per ACPI spec.) + * + * Even though the ASL compilers do not allow NumElements to be smaller + * than the Package list length (for the fixed length package opcode), some + * BIOS code modifies the AML on the fly to adjust the NumElements, and + * this code compensates for that. This also provides compatibility with + * other AML interpreters. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsBuildInternalPackageObj ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 ElementCount, + ACPI_OPERAND_OBJECT **ObjDescPtr) +{ + ACPI_PARSE_OBJECT *Arg; + ACPI_PARSE_OBJECT *Parent; + ACPI_OPERAND_OBJECT *ObjDesc = NULL; + ACPI_STATUS Status = AE_OK; + UINT32 i; + UINT16 Index; + UINT16 ReferenceCount; + + + ACPI_FUNCTION_TRACE (DsBuildInternalPackageObj); + + + /* Find the parent of a possibly nested package */ + + Parent = Op->Common.Parent; + while ((Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) + { + Parent = Parent->Common.Parent; + } + + /* + * If we are evaluating a Named package object "Name (xxxx, Package)", + * the package object already exists, otherwise it must be created. + */ + ObjDesc = *ObjDescPtr; + if (!ObjDesc) + { + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_PACKAGE); + *ObjDescPtr = ObjDesc; + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ObjDesc->Package.Node = Parent->Common.Node; + } + + /* + * Allocate the element array (array of pointers to the individual + * objects) based on the NumElements parameter. Add an extra pointer slot + * so that the list is always null terminated. + */ + ObjDesc->Package.Elements = ACPI_ALLOCATE_ZEROED ( + ((ACPI_SIZE) ElementCount + 1) * sizeof (void *)); + + if (!ObjDesc->Package.Elements) + { + AcpiUtDeleteObjectDesc (ObjDesc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ObjDesc->Package.Count = ElementCount; + + /* + * Initialize the elements of the package, up to the NumElements count. + * Package is automatically padded with uninitialized (NULL) elements + * if NumElements is greater than the package list length. Likewise, + * Package is truncated if NumElements is less than the list length. + */ + Arg = Op->Common.Value.Arg; + Arg = Arg->Common.Next; + for (i = 0; Arg && (i < ElementCount); i++) + { + if (Arg->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) + { + if (Arg->Common.Node->Type == ACPI_TYPE_METHOD) + { + /* + * A method reference "looks" to the parser to be a method + * invocation, so we special case it here + */ + Arg->Common.AmlOpcode = AML_INT_NAMEPATH_OP; + Status = AcpiDsBuildInternalObject ( + WalkState, Arg, &ObjDesc->Package.Elements[i]); + } + else + { + /* This package element is already built, just get it */ + + ObjDesc->Package.Elements[i] = + ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Arg->Common.Node); + } + } + else + { + Status = AcpiDsBuildInternalObject ( + WalkState, Arg, &ObjDesc->Package.Elements[i]); + } + + if (*ObjDescPtr) + { + /* Existing package, get existing reference count */ + + ReferenceCount = (*ObjDescPtr)->Common.ReferenceCount; + if (ReferenceCount > 1) + { + /* Make new element ref count match original ref count */ + + for (Index = 0; Index < (ReferenceCount - 1); Index++) + { + AcpiUtAddReference ((ObjDesc->Package.Elements[i])); + } + } + } + + Arg = Arg->Common.Next; + } + + /* Check for match between NumElements and actual length of PackageList */ + + if (Arg) + { + /* + * NumElements was exhausted, but there are remaining elements in the + * PackageList. Truncate the package to NumElements. + * + * Note: technically, this is an error, from ACPI spec: "It is an error + * for NumElements to be less than the number of elements in the + * PackageList". However, we just print a message and + * no exception is returned. This provides Windows compatibility. Some + * BIOSs will alter the NumElements on the fly, creating this type + * of ill-formed package object. + */ + while (Arg) + { + /* + * We must delete any package elements that were created earlier + * and are not going to be used because of the package truncation. + */ + if (Arg->Common.Node) + { + AcpiUtRemoveReference ( + ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Arg->Common.Node)); + Arg->Common.Node = NULL; + } + + /* Find out how many elements there really are */ + + i++; + Arg = Arg->Common.Next; + } + + ACPI_INFO ((AE_INFO, + "Actual Package length (%u) is larger than " + "NumElements field (%u), truncated", + i, ElementCount)); + } + else if (i < ElementCount) + { + /* + * Arg list (elements) was exhausted, but we did not reach NumElements count. + * Note: this is not an error, the package is padded out with NULLs. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Package List length (%u) smaller than NumElements " + "count (%u), padded with null elements\n", + i, ElementCount)); + } + + ObjDesc->Package.Flags |= AOPOBJ_DATA_VALID; + Op->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateNode + * + * PARAMETERS: WalkState - Current walk state + * Node - NS Node to be initialized + * Op - Parser object to be translated + * + * RETURN: Status + * + * DESCRIPTION: Create the object to be associated with a namespace node + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateNode ( + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *Node, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_TRACE_PTR (DsCreateNode, Op); + + + /* + * Because of the execution pass through the non-control-method + * parts of the table, we can arrive here twice. Only init + * the named object node the first time through + */ + if (AcpiNsGetAttachedObject (Node)) + { + return_ACPI_STATUS (AE_OK); + } + + if (!Op->Common.Value.Arg) + { + /* No arguments, there is nothing to do */ + + return_ACPI_STATUS (AE_OK); + } + + /* Build an internal object for the argument(s) */ + + Status = AcpiDsBuildInternalObject ( + WalkState, Op->Common.Value.Arg, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Re-type the object according to its argument */ + + Node->Type = ObjDesc->Common.Type; + + /* Attach obj to node */ + + Status = AcpiNsAttachObject (Node, ObjDesc, Node->Type); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + +#endif /* ACPI_NO_METHOD_EXECUTION */ + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitObjectFromOp + * + * PARAMETERS: WalkState - Current walk state + * Op - Parser op used to init the internal object + * Opcode - AML opcode associated with the object + * RetObjDesc - Namespace object to be initialized + * + * RETURN: Status + * + * DESCRIPTION: Initialize a namespace object from a parser Op and its + * associated arguments. The namespace object is a more compact + * representation of the Op and its arguments. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsInitObjectFromOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT16 Opcode, + ACPI_OPERAND_OBJECT **RetObjDesc) +{ + const ACPI_OPCODE_INFO *OpInfo; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (DsInitObjectFromOp); + + + ObjDesc = *RetObjDesc; + OpInfo = AcpiPsGetOpcodeInfo (Opcode); + if (OpInfo->Class == AML_CLASS_UNKNOWN) + { + /* Unknown opcode */ + + return_ACPI_STATUS (AE_TYPE); + } + + /* Perform per-object initialization */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_BUFFER: + /* + * Defer evaluation of Buffer TermArg operand + */ + ObjDesc->Buffer.Node = ACPI_CAST_PTR ( + ACPI_NAMESPACE_NODE, WalkState->Operands[0]); + ObjDesc->Buffer.AmlStart = Op->Named.Data; + ObjDesc->Buffer.AmlLength = Op->Named.Length; + break; + + case ACPI_TYPE_PACKAGE: + /* + * Defer evaluation of Package TermArg operand + */ + ObjDesc->Package.Node = ACPI_CAST_PTR ( + ACPI_NAMESPACE_NODE, WalkState->Operands[0]); + ObjDesc->Package.AmlStart = Op->Named.Data; + ObjDesc->Package.AmlLength = Op->Named.Length; + break; + + case ACPI_TYPE_INTEGER: + + switch (OpInfo->Type) + { + case AML_TYPE_CONSTANT: + /* + * Resolve AML Constants here - AND ONLY HERE! + * All constants are integers. + * We mark the integer with a flag that indicates that it started + * life as a constant -- so that stores to constants will perform + * as expected (noop). ZeroOp is used as a placeholder for optional + * target operands. + */ + ObjDesc->Common.Flags = AOPOBJ_AML_CONSTANT; + + switch (Opcode) + { + case AML_ZERO_OP: + + ObjDesc->Integer.Value = 0; + break; + + case AML_ONE_OP: + + ObjDesc->Integer.Value = 1; + break; + + case AML_ONES_OP: + + ObjDesc->Integer.Value = ACPI_UINT64_MAX; + + /* Truncate value if we are executing from a 32-bit ACPI table */ + +#ifndef ACPI_NO_METHOD_EXECUTION + (void) AcpiExTruncateFor32bitTable (ObjDesc); +#endif + break; + + case AML_REVISION_OP: + + ObjDesc->Integer.Value = ACPI_CA_VERSION; + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown constant opcode 0x%X", Opcode)); + Status = AE_AML_OPERAND_TYPE; + break; + } + break; + + case AML_TYPE_LITERAL: + + ObjDesc->Integer.Value = Op->Common.Value.Integer; + +#ifndef ACPI_NO_METHOD_EXECUTION + if (AcpiExTruncateFor32bitTable (ObjDesc)) + { + /* Warn if we found a 64-bit constant in a 32-bit table */ + + ACPI_WARNING ((AE_INFO, + "Truncated 64-bit constant found in 32-bit table: %8.8X%8.8X => %8.8X", + ACPI_FORMAT_UINT64 (Op->Common.Value.Integer), + (UINT32) ObjDesc->Integer.Value)); + } +#endif + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown Integer type 0x%X", + OpInfo->Type)); + Status = AE_AML_OPERAND_TYPE; + break; + } + break; + + case ACPI_TYPE_STRING: + + ObjDesc->String.Pointer = Op->Common.Value.String; + ObjDesc->String.Length = (UINT32) strlen (Op->Common.Value.String); + + /* + * The string is contained in the ACPI table, don't ever try + * to delete it + */ + ObjDesc->Common.Flags |= AOPOBJ_STATIC_POINTER; + break; + + case ACPI_TYPE_METHOD: + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (OpInfo->Type) + { + case AML_TYPE_LOCAL_VARIABLE: + + /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ + + ObjDesc->Reference.Value = ((UINT32) Opcode) - AML_LOCAL_OP; + ObjDesc->Reference.Class = ACPI_REFCLASS_LOCAL; + +#ifndef ACPI_NO_METHOD_EXECUTION + Status = AcpiDsMethodDataGetNode (ACPI_REFCLASS_LOCAL, + ObjDesc->Reference.Value, WalkState, + ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, + &ObjDesc->Reference.Object)); +#endif + break; + + case AML_TYPE_METHOD_ARGUMENT: + + /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ + + ObjDesc->Reference.Value = ((UINT32) Opcode) - AML_ARG_OP; + ObjDesc->Reference.Class = ACPI_REFCLASS_ARG; + +#ifndef ACPI_NO_METHOD_EXECUTION + Status = AcpiDsMethodDataGetNode (ACPI_REFCLASS_ARG, + ObjDesc->Reference.Value, WalkState, + ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, + &ObjDesc->Reference.Object)); +#endif + break; + + default: /* Object name or Debug object */ + + switch (Op->Common.AmlOpcode) + { + case AML_INT_NAMEPATH_OP: + + /* Node was saved in Op */ + + ObjDesc->Reference.Node = Op->Common.Node; + ObjDesc->Reference.Object = Op->Common.Node->Object; + ObjDesc->Reference.Class = ACPI_REFCLASS_NAME; + break; + + case AML_DEBUG_OP: + + ObjDesc->Reference.Class = ACPI_REFCLASS_DEBUG; + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unimplemented reference type for AML opcode: 0x%4.4X", Opcode)); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + break; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unimplemented data type: 0x%X", + ObjDesc->Common.Type)); + + Status = AE_AML_OPERAND_TYPE; + break; + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsopcode.c b/third_party/lib/acpica/source/components/dispatcher/dsopcode.c new file mode 100644 index 000000000..1c6b34257 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsopcode.c @@ -0,0 +1,817 @@ +/****************************************************************************** + * + * Module Name: dsopcode - Dispatcher support for regions and fields + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsopcode") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsInitBufferField ( + UINT16 AmlOpcode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *BufferDesc, + ACPI_OPERAND_OBJECT *OffsetDesc, + ACPI_OPERAND_OBJECT *LengthDesc, + ACPI_OPERAND_OBJECT *ResultDesc); + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitializeRegion + * + * PARAMETERS: ObjHandle - Region namespace node + * + * RETURN: Status + * + * DESCRIPTION: Front end to EvInitializeRegion + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsInitializeRegion ( + ACPI_HANDLE ObjHandle) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ObjDesc = AcpiNsGetAttachedObject (ObjHandle); + + /* Namespace is NOT locked */ + + Status = AcpiEvInitializeRegion (ObjDesc, FALSE); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitBufferField + * + * PARAMETERS: AmlOpcode - CreateXxxField + * ObjDesc - BufferField object + * BufferDesc - Host Buffer + * OffsetDesc - Offset into buffer + * LengthDesc - Length of field (CREATE_FIELD_OP only) + * ResultDesc - Where to store the result + * + * RETURN: Status + * + * DESCRIPTION: Perform actual initialization of a buffer field + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsInitBufferField ( + UINT16 AmlOpcode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *BufferDesc, + ACPI_OPERAND_OBJECT *OffsetDesc, + ACPI_OPERAND_OBJECT *LengthDesc, + ACPI_OPERAND_OBJECT *ResultDesc) +{ + UINT32 Offset; + UINT32 BitOffset; + UINT32 BitCount; + UINT8 FieldFlags; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (DsInitBufferField, ObjDesc); + + + /* Host object must be a Buffer */ + + if (BufferDesc->Common.Type != ACPI_TYPE_BUFFER) + { + ACPI_ERROR ((AE_INFO, + "Target of Create Field is not a Buffer object - %s", + AcpiUtGetObjectTypeName (BufferDesc))); + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + + /* + * The last parameter to all of these opcodes (ResultDesc) started + * out as a NameString, and should therefore now be a NS node + * after resolution in AcpiExResolveOperands(). + */ + if (ACPI_GET_DESCRIPTOR_TYPE (ResultDesc) != ACPI_DESC_TYPE_NAMED) + { + ACPI_ERROR ((AE_INFO, + "(%s) destination not a NS Node [%s]", + AcpiPsGetOpcodeName (AmlOpcode), + AcpiUtGetDescriptorName (ResultDesc))); + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + + Offset = (UINT32) OffsetDesc->Integer.Value; + + /* + * Setup the Bit offsets and counts, according to the opcode + */ + switch (AmlOpcode) + { + case AML_CREATE_FIELD_OP: + + /* Offset is in bits, count is in bits */ + + FieldFlags = AML_FIELD_ACCESS_BYTE; + BitOffset = Offset; + BitCount = (UINT32) LengthDesc->Integer.Value; + + /* Must have a valid (>0) bit count */ + + if (BitCount == 0) + { + ACPI_ERROR ((AE_INFO, + "Attempt to CreateField of length zero")); + Status = AE_AML_OPERAND_VALUE; + goto Cleanup; + } + break; + + case AML_CREATE_BIT_FIELD_OP: + + /* Offset is in bits, Field is one bit */ + + BitOffset = Offset; + BitCount = 1; + FieldFlags = AML_FIELD_ACCESS_BYTE; + break; + + case AML_CREATE_BYTE_FIELD_OP: + + /* Offset is in bytes, field is one byte */ + + BitOffset = 8 * Offset; + BitCount = 8; + FieldFlags = AML_FIELD_ACCESS_BYTE; + break; + + case AML_CREATE_WORD_FIELD_OP: + + /* Offset is in bytes, field is one word */ + + BitOffset = 8 * Offset; + BitCount = 16; + FieldFlags = AML_FIELD_ACCESS_WORD; + break; + + case AML_CREATE_DWORD_FIELD_OP: + + /* Offset is in bytes, field is one dword */ + + BitOffset = 8 * Offset; + BitCount = 32; + FieldFlags = AML_FIELD_ACCESS_DWORD; + break; + + case AML_CREATE_QWORD_FIELD_OP: + + /* Offset is in bytes, field is one qword */ + + BitOffset = 8 * Offset; + BitCount = 64; + FieldFlags = AML_FIELD_ACCESS_QWORD; + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown field creation opcode 0x%02X", + AmlOpcode)); + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + /* Entire field must fit within the current length of the buffer */ + + if ((BitOffset + BitCount) > + (8 * (UINT32) BufferDesc->Buffer.Length)) + { + ACPI_ERROR ((AE_INFO, + "Field [%4.4s] at %u exceeds Buffer [%4.4s] size %u (bits)", + AcpiUtGetNodeName (ResultDesc), + BitOffset + BitCount, + AcpiUtGetNodeName (BufferDesc->Buffer.Node), + 8 * (UINT32) BufferDesc->Buffer.Length)); + Status = AE_AML_BUFFER_LIMIT; + goto Cleanup; + } + + /* + * Initialize areas of the field object that are common to all fields + * For FieldFlags, use LOCK_RULE = 0 (NO_LOCK), + * UPDATE_RULE = 0 (UPDATE_PRESERVE) + */ + Status = AcpiExPrepCommonFieldObject ( + ObjDesc, FieldFlags, 0, BitOffset, BitCount); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + ObjDesc->BufferField.BufferObj = BufferDesc; + + /* Reference count for BufferDesc inherits ObjDesc count */ + + BufferDesc->Common.ReferenceCount = (UINT16) + (BufferDesc->Common.ReferenceCount + ObjDesc->Common.ReferenceCount); + + +Cleanup: + + /* Always delete the operands */ + + AcpiUtRemoveReference (OffsetDesc); + AcpiUtRemoveReference (BufferDesc); + + if (AmlOpcode == AML_CREATE_FIELD_OP) + { + AcpiUtRemoveReference (LengthDesc); + } + + /* On failure, delete the result descriptor */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ResultDesc); /* Result descriptor */ + } + else + { + /* Now the address and length are valid for this BufferField */ + + ObjDesc->BufferField.Flags |= AOPOBJ_DATA_VALID; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsEvalBufferFieldOperands + * + * PARAMETERS: WalkState - Current walk + * Op - A valid BufferField Op object + * + * RETURN: Status + * + * DESCRIPTION: Get BufferField Buffer and Index + * Called from AcpiDsExecEndOp during BufferField parse tree walk + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsEvalBufferFieldOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *NextOp; + + + ACPI_FUNCTION_TRACE_PTR (DsEvalBufferFieldOperands, Op); + + + /* + * This is where we evaluate the address and length fields of the + * CreateXxxField declaration + */ + Node = Op->Common.Node; + + /* NextOp points to the op that holds the Buffer */ + + NextOp = Op->Common.Value.Arg; + + /* Evaluate/create the address and length operands */ + + Status = AcpiDsCreateOperands (WalkState, NextOp); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Resolve the operands */ + + Status = AcpiExResolveOperands ( + Op->Common.AmlOpcode, ACPI_WALK_OPERANDS, WalkState); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "(%s) bad operand(s), status 0x%X", + AcpiPsGetOpcodeName (Op->Common.AmlOpcode), Status)); + + return_ACPI_STATUS (Status); + } + + /* Initialize the Buffer Field */ + + if (Op->Common.AmlOpcode == AML_CREATE_FIELD_OP) + { + /* NOTE: Slightly different operands for this opcode */ + + Status = AcpiDsInitBufferField (Op->Common.AmlOpcode, ObjDesc, + WalkState->Operands[0], WalkState->Operands[1], + WalkState->Operands[2], WalkState->Operands[3]); + } + else + { + /* All other, CreateXxxField opcodes */ + + Status = AcpiDsInitBufferField (Op->Common.AmlOpcode, ObjDesc, + WalkState->Operands[0], WalkState->Operands[1], + NULL, WalkState->Operands[2]); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsEvalRegionOperands + * + * PARAMETERS: WalkState - Current walk + * Op - A valid region Op object + * + * RETURN: Status + * + * DESCRIPTION: Get region address and length + * Called from AcpiDsExecEndOp during OpRegion parse tree walk + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsEvalRegionOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *OperandDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *NextOp; + + + ACPI_FUNCTION_TRACE_PTR (DsEvalRegionOperands, Op); + + + /* + * This is where we evaluate the address and length fields of the + * OpRegion declaration + */ + Node = Op->Common.Node; + + /* NextOp points to the op that holds the SpaceID */ + + NextOp = Op->Common.Value.Arg; + + /* NextOp points to address op */ + + NextOp = NextOp->Common.Next; + + /* Evaluate/create the address and length operands */ + + Status = AcpiDsCreateOperands (WalkState, NextOp); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Resolve the length and address operands to numbers */ + + Status = AcpiExResolveOperands ( + Op->Common.AmlOpcode, ACPI_WALK_OPERANDS, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* + * Get the length operand and save it + * (at Top of stack) + */ + OperandDesc = WalkState->Operands[WalkState->NumOperands - 1]; + + ObjDesc->Region.Length = (UINT32) OperandDesc->Integer.Value; + AcpiUtRemoveReference (OperandDesc); + + /* + * Get the address and save it + * (at top of stack - 1) + */ + OperandDesc = WalkState->Operands[WalkState->NumOperands - 2]; + + ObjDesc->Region.Address = (ACPI_PHYSICAL_ADDRESS) + OperandDesc->Integer.Value; + AcpiUtRemoveReference (OperandDesc); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", + ObjDesc, ACPI_FORMAT_UINT64 (ObjDesc->Region.Address), + ObjDesc->Region.Length)); + + /* Now the address and length are valid for this opregion */ + + ObjDesc->Region.Flags |= AOPOBJ_DATA_VALID; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsEvalTableRegionOperands + * + * PARAMETERS: WalkState - Current walk + * Op - A valid region Op object + * + * RETURN: Status + * + * DESCRIPTION: Get region address and length. + * Called from AcpiDsExecEndOp during DataTableRegion parse + * tree walk. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsEvalTableRegionOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT **Operand; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *NextOp; + ACPI_TABLE_HEADER *Table; + UINT32 TableIndex; + + + ACPI_FUNCTION_TRACE_PTR (DsEvalTableRegionOperands, Op); + + + /* + * This is where we evaluate the Signature string, OemId string, + * and OemTableId string of the Data Table Region declaration + */ + Node = Op->Common.Node; + + /* NextOp points to Signature string op */ + + NextOp = Op->Common.Value.Arg; + + /* + * Evaluate/create the Signature string, OemId string, + * and OemTableId string operands + */ + Status = AcpiDsCreateOperands (WalkState, NextOp); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Operand = &WalkState->Operands[0]; + + /* + * Resolve the Signature string, OemId string, + * and OemTableId string operands + */ + Status = AcpiExResolveOperands ( + Op->Common.AmlOpcode, ACPI_WALK_OPERANDS, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Find the ACPI table */ + + Status = AcpiTbFindTable ( + Operand[0]->String.Pointer, + Operand[1]->String.Pointer, + Operand[2]->String.Pointer, &TableIndex); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + ACPI_ERROR ((AE_INFO, + "ACPI Table [%4.4s] OEM:(%s, %s) not found in RSDT/XSDT", + Operand[0]->String.Pointer, + Operand[1]->String.Pointer, + Operand[2]->String.Pointer)); + } + goto Cleanup; + } + + Status = AcpiGetTableByIndex (TableIndex, &Table); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + Status = AE_NOT_EXIST; + goto Cleanup; + } + + ObjDesc->Region.Address = ACPI_PTR_TO_PHYSADDR (Table); + ObjDesc->Region.Length = Table->Length; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", + ObjDesc, ACPI_FORMAT_UINT64 (ObjDesc->Region.Address), + ObjDesc->Region.Length)); + + /* Now the address and length are valid for this opregion */ + + ObjDesc->Region.Flags |= AOPOBJ_DATA_VALID; + +Cleanup: + AcpiUtRemoveReference (Operand[0]); + AcpiUtRemoveReference (Operand[1]); + AcpiUtRemoveReference (Operand[2]); + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsEvalDataObjectOperands + * + * PARAMETERS: WalkState - Current walk + * Op - A valid DataObject Op object + * ObjDesc - DataObject + * + * RETURN: Status + * + * DESCRIPTION: Get the operands and complete the following data object types: + * Buffer, Package. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsEvalDataObjectOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ArgDesc; + UINT32 Length; + + + ACPI_FUNCTION_TRACE (DsEvalDataObjectOperands); + + + /* The first operand (for all of these data objects) is the length */ + + /* + * Set proper index into operand stack for AcpiDsObjStackPush + * invoked inside AcpiDsCreateOperand. + */ + WalkState->OperandIndex = WalkState->NumOperands; + + Status = AcpiDsCreateOperand (WalkState, Op->Common.Value.Arg, 1); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiExResolveOperands (WalkState->Opcode, + &(WalkState->Operands [WalkState->NumOperands -1]), + WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Extract length operand */ + + ArgDesc = WalkState->Operands [WalkState->NumOperands - 1]; + Length = (UINT32) ArgDesc->Integer.Value; + + /* Cleanup for length operand */ + + Status = AcpiDsObjStackPop (1, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiUtRemoveReference (ArgDesc); + + /* + * Create the actual data object + */ + switch (Op->Common.AmlOpcode) + { + case AML_BUFFER_OP: + + Status = AcpiDsBuildInternalBufferObj ( + WalkState, Op, Length, &ObjDesc); + break; + + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + Status = AcpiDsBuildInternalPackageObj ( + WalkState, Op, Length, &ObjDesc); + break; + + default: + + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + if (ACPI_SUCCESS (Status)) + { + /* + * Return the object in the WalkState, unless the parent is a package - + * in this case, the return object will be stored in the parse tree + * for the package. + */ + if ((!Op->Common.Parent) || + ((Op->Common.Parent->Common.AmlOpcode != AML_PACKAGE_OP) && + (Op->Common.Parent->Common.AmlOpcode != AML_VAR_PACKAGE_OP) && + (Op->Common.Parent->Common.AmlOpcode != AML_NAME_OP))) + { + WalkState->ResultObj = ObjDesc; + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsEvalBankFieldOperands + * + * PARAMETERS: WalkState - Current walk + * Op - A valid BankField Op object + * + * RETURN: Status + * + * DESCRIPTION: Get BankField BankValue + * Called from AcpiDsExecEndOp during BankField parse tree walk + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsEvalBankFieldOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *OperandDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *NextOp; + ACPI_PARSE_OBJECT *Arg; + + + ACPI_FUNCTION_TRACE_PTR (DsEvalBankFieldOperands, Op); + + + /* + * This is where we evaluate the BankValue field of the + * BankField declaration + */ + + /* NextOp points to the op that holds the Region */ + + NextOp = Op->Common.Value.Arg; + + /* NextOp points to the op that holds the Bank Register */ + + NextOp = NextOp->Common.Next; + + /* NextOp points to the op that holds the Bank Value */ + + NextOp = NextOp->Common.Next; + + /* + * Set proper index into operand stack for AcpiDsObjStackPush + * invoked inside AcpiDsCreateOperand. + * + * We use WalkState->Operands[0] to store the evaluated BankValue + */ + WalkState->OperandIndex = 0; + + Status = AcpiDsCreateOperand (WalkState, NextOp, 0); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiExResolveToValue (&WalkState->Operands[0], WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, + AcpiPsGetOpcodeName (Op->Common.AmlOpcode), 1); + /* + * Get the BankValue operand and save it + * (at Top of stack) + */ + OperandDesc = WalkState->Operands[0]; + + /* Arg points to the start Bank Field */ + + Arg = AcpiPsGetArg (Op, 4); + while (Arg) + { + /* Ignore OFFSET and ACCESSAS terms here */ + + if (Arg->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) + { + Node = Arg->Common.Node; + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + ObjDesc->BankField.Value = (UINT32) OperandDesc->Integer.Value; + } + + /* Move to next field in the list */ + + Arg = Arg->Common.Next; + } + + AcpiUtRemoveReference (OperandDesc); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dsutils.c b/third_party/lib/acpica/source/components/dispatcher/dsutils.c new file mode 100644 index 000000000..f41f6b2b2 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dsutils.c @@ -0,0 +1,945 @@ +/******************************************************************************* + * + * Module Name: dsutils - Dispatcher utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsutils") + + +/******************************************************************************* + * + * FUNCTION: AcpiDsClearImplicitReturn + * + * PARAMETERS: WalkState - Current State + * + * RETURN: None. + * + * DESCRIPTION: Clear and remove a reference on an implicit return value. Used + * to delete "stale" return values (if enabled, the return value + * from every operator is saved at least momentarily, in case the + * parent method exits.) + * + ******************************************************************************/ + +void +AcpiDsClearImplicitReturn ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_FUNCTION_NAME (DsClearImplicitReturn); + + + /* + * Slack must be enabled for this feature + */ + if (!AcpiGbl_EnableInterpreterSlack) + { + return; + } + + if (WalkState->ImplicitReturnObj) + { + /* + * Delete any "stale" implicit return. However, in + * complex statements, the implicit return value can be + * bubbled up several levels. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Removing reference on stale implicit return obj %p\n", + WalkState->ImplicitReturnObj)); + + AcpiUtRemoveReference (WalkState->ImplicitReturnObj); + WalkState->ImplicitReturnObj = NULL; + } +} + + +#ifndef ACPI_NO_METHOD_EXECUTION +/******************************************************************************* + * + * FUNCTION: AcpiDsDoImplicitReturn + * + * PARAMETERS: ReturnDesc - The return value + * WalkState - Current State + * AddReference - True if a reference should be added to the + * return object + * + * RETURN: TRUE if implicit return enabled, FALSE otherwise + * + * DESCRIPTION: Implements the optional "implicit return". We save the result + * of every ASL operator and control method invocation in case the + * parent method exit. Before storing a new return value, we + * delete the previous return value. + * + ******************************************************************************/ + +BOOLEAN +AcpiDsDoImplicitReturn ( + ACPI_OPERAND_OBJECT *ReturnDesc, + ACPI_WALK_STATE *WalkState, + BOOLEAN AddReference) +{ + ACPI_FUNCTION_NAME (DsDoImplicitReturn); + + + /* + * Slack must be enabled for this feature, and we must + * have a valid return object + */ + if ((!AcpiGbl_EnableInterpreterSlack) || + (!ReturnDesc)) + { + return (FALSE); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result %p will be implicitly returned; Prev=%p\n", + ReturnDesc, + WalkState->ImplicitReturnObj)); + + /* + * Delete any "stale" implicit return value first. However, in + * complex statements, the implicit return value can be + * bubbled up several levels, so we don't clear the value if it + * is the same as the ReturnDesc. + */ + if (WalkState->ImplicitReturnObj) + { + if (WalkState->ImplicitReturnObj == ReturnDesc) + { + return (TRUE); + } + AcpiDsClearImplicitReturn (WalkState); + } + + /* Save the implicit return value, add a reference if requested */ + + WalkState->ImplicitReturnObj = ReturnDesc; + if (AddReference) + { + AcpiUtAddReference (ReturnDesc); + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsIsResultUsed + * + * PARAMETERS: Op - Current Op + * WalkState - Current State + * + * RETURN: TRUE if result is used, FALSE otherwise + * + * DESCRIPTION: Check if a result object will be used by the parent + * + ******************************************************************************/ + +BOOLEAN +AcpiDsIsResultUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + const ACPI_OPCODE_INFO *ParentInfo; + + ACPI_FUNCTION_TRACE_PTR (DsIsResultUsed, Op); + + + /* Must have both an Op and a Result Object */ + + if (!Op) + { + ACPI_ERROR ((AE_INFO, "Null Op")); + return_UINT8 (TRUE); + } + + /* + * We know that this operator is not a + * Return() operator (would not come here.) The following code is the + * optional support for a so-called "implicit return". Some AML code + * assumes that the last value of the method is "implicitly" returned + * to the caller. Just save the last result as the return value. + * NOTE: this is optional because the ASL language does not actually + * support this behavior. + */ + (void) AcpiDsDoImplicitReturn (WalkState->ResultObj, WalkState, TRUE); + + /* + * Now determine if the parent will use the result + * + * If there is no parent, or the parent is a ScopeOp, we are executing + * at the method level. An executing method typically has no parent, + * since each method is parsed separately. A method invoked externally + * via ExecuteControlMethod has a ScopeOp as the parent. + */ + if ((!Op->Common.Parent) || + (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) + { + /* No parent, the return value cannot possibly be used */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "At Method level, result of [%s] not used\n", + AcpiPsGetOpcodeName (Op->Common.AmlOpcode))); + return_UINT8 (FALSE); + } + + /* Get info on the parent. The RootOp is AML_SCOPE */ + + ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); + if (ParentInfo->Class == AML_CLASS_UNKNOWN) + { + ACPI_ERROR ((AE_INFO, + "Unknown parent opcode Op=%p", Op)); + return_UINT8 (FALSE); + } + + /* + * Decide what to do with the result based on the parent. If + * the parent opcode will not use the result, delete the object. + * Otherwise leave it as is, it will be deleted when it is used + * as an operand later. + */ + switch (ParentInfo->Class) + { + case AML_CLASS_CONTROL: + + switch (Op->Common.Parent->Common.AmlOpcode) + { + case AML_RETURN_OP: + + /* Never delete the return value associated with a return opcode */ + + goto ResultUsed; + + case AML_IF_OP: + case AML_WHILE_OP: + /* + * If we are executing the predicate AND this is the predicate op, + * we will use the return value + */ + if ((WalkState->ControlState->Common.State == + ACPI_CONTROL_PREDICATE_EXECUTING) && + (WalkState->ControlState->Control.PredicateOp == Op)) + { + goto ResultUsed; + } + break; + + default: + + /* Ignore other control opcodes */ + + break; + } + + /* The general control opcode returns no result */ + + goto ResultNotUsed; + + case AML_CLASS_CREATE: + /* + * These opcodes allow TermArg(s) as operands and therefore + * the operands can be method calls. The result is used. + */ + goto ResultUsed; + + case AML_CLASS_NAMED_OBJECT: + + if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_INT_EVAL_SUBTREE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP)) + { + /* + * These opcodes allow TermArg(s) as operands and therefore + * the operands can be method calls. The result is used. + */ + goto ResultUsed; + } + + goto ResultNotUsed; + + default: + /* + * In all other cases. the parent will actually use the return + * object, so keep it. + */ + goto ResultUsed; + } + + +ResultUsed: + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] used by Parent [%s] Op=%p\n", + AcpiPsGetOpcodeName (Op->Common.AmlOpcode), + AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op)); + + return_UINT8 (TRUE); + + +ResultNotUsed: + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] not used by Parent [%s] Op=%p\n", + AcpiPsGetOpcodeName (Op->Common.AmlOpcode), + AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op)); + + return_UINT8 (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsDeleteResultIfNotUsed + * + * PARAMETERS: Op - Current parse Op + * ResultObj - Result of the operation + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Used after interpretation of an opcode. If there is an internal + * result descriptor, check if the parent opcode will actually use + * this result. If not, delete the result now so that it will + * not become orphaned. + * + ******************************************************************************/ + +void +AcpiDsDeleteResultIfNotUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ResultObj, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (DsDeleteResultIfNotUsed, ResultObj); + + + if (!Op) + { + ACPI_ERROR ((AE_INFO, "Null Op")); + return_VOID; + } + + if (!ResultObj) + { + return_VOID; + } + + if (!AcpiDsIsResultUsed (Op, WalkState)) + { + /* Must pop the result stack (ObjDesc should be equal to ResultObj) */ + + Status = AcpiDsResultPop (&ObjDesc, WalkState); + if (ACPI_SUCCESS (Status)) + { + AcpiUtRemoveReference (ResultObj); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsResolveOperands + * + * PARAMETERS: WalkState - Current walk state with operands on stack + * + * RETURN: Status + * + * DESCRIPTION: Resolve all operands to their values. Used to prepare + * arguments to a control method invocation (a call from one + * method to another.) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsResolveOperands ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 i; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (DsResolveOperands, WalkState); + + + /* + * Attempt to resolve each of the valid operands + * Method arguments are passed by reference, not by value. This means + * that the actual objects are passed, not copies of the objects. + */ + for (i = 0; i < WalkState->NumOperands; i++) + { + Status = AcpiExResolveToValue (&WalkState->Operands[i], WalkState); + if (ACPI_FAILURE (Status)) + { + break; + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsClearOperands + * + * PARAMETERS: WalkState - Current walk state with operands on stack + * + * RETURN: None + * + * DESCRIPTION: Clear all operands on the current walk state operand stack. + * + ******************************************************************************/ + +void +AcpiDsClearOperands ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 i; + + + ACPI_FUNCTION_TRACE_PTR (DsClearOperands, WalkState); + + + /* Remove a reference on each operand on the stack */ + + for (i = 0; i < WalkState->NumOperands; i++) + { + /* + * Remove a reference to all operands, including both + * "Arguments" and "Targets". + */ + AcpiUtRemoveReference (WalkState->Operands[i]); + WalkState->Operands[i] = NULL; + } + + WalkState->NumOperands = 0; + return_VOID; +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateOperand + * + * PARAMETERS: WalkState - Current walk state + * Arg - Parse object for the argument + * ArgIndex - Which argument (zero based) + * + * RETURN: Status + * + * DESCRIPTION: Translate a parse tree object that is an argument to an AML + * opcode to the equivalent interpreter object. This may include + * looking up a name or entering a new name into the internal + * namespace. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateOperand ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Arg, + UINT32 ArgIndex) +{ + ACPI_STATUS Status = AE_OK; + char *NameString; + UINT32 NameLength; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PARSE_OBJECT *ParentOp; + UINT16 Opcode; + ACPI_INTERPRETER_MODE InterpreterMode; + const ACPI_OPCODE_INFO *OpInfo; + + + ACPI_FUNCTION_TRACE_PTR (DsCreateOperand, Arg); + + + /* A valid name must be looked up in the namespace */ + + if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && + (Arg->Common.Value.String) && + !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", Arg)); + + /* Get the entire name string from the AML stream */ + + Status = AcpiExGetNameString (ACPI_TYPE_ANY, + Arg->Common.Value.Buffer, &NameString, &NameLength); + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* All prefixes have been handled, and the name is in NameString */ + + /* + * Special handling for BufferField declarations. This is a deferred + * opcode that unfortunately defines the field name as the last + * parameter instead of the first. We get here when we are performing + * the deferred execution, so the actual name of the field is already + * in the namespace. We don't want to attempt to look it up again + * because we may be executing in a different scope than where the + * actual opcode exists. + */ + if ((WalkState->DeferredNode) && + (WalkState->DeferredNode->Type == ACPI_TYPE_BUFFER_FIELD) && + (ArgIndex == (UINT32) + ((WalkState->Opcode == AML_CREATE_FIELD_OP) ? 3 : 2))) + { + ObjDesc = ACPI_CAST_PTR ( + ACPI_OPERAND_OBJECT, WalkState->DeferredNode); + Status = AE_OK; + } + else /* All other opcodes */ + { + /* + * Differentiate between a namespace "create" operation + * versus a "lookup" operation (IMODE_LOAD_PASS2 vs. + * IMODE_EXECUTE) in order to support the creation of + * namespace objects during the execution of control methods. + */ + ParentOp = Arg->Common.Parent; + OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode); + + if ((OpInfo->Flags & AML_NSNODE) && + (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) && + (ParentOp->Common.AmlOpcode != AML_REGION_OP) && + (ParentOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP)) + { + /* Enter name into namespace if not found */ + + InterpreterMode = ACPI_IMODE_LOAD_PASS2; + } + else + { + /* Return a failure if name not found */ + + InterpreterMode = ACPI_IMODE_EXECUTE; + } + + Status = AcpiNsLookup (WalkState->ScopeInfo, NameString, + ACPI_TYPE_ANY, InterpreterMode, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, WalkState, + ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, &ObjDesc)); + /* + * The only case where we pass through (ignore) a NOT_FOUND + * error is for the CondRefOf opcode. + */ + if (Status == AE_NOT_FOUND) + { + if (ParentOp->Common.AmlOpcode == AML_COND_REF_OF_OP) + { + /* + * For the Conditional Reference op, it's OK if + * the name is not found; We just need a way to + * indicate this to the interpreter, set the + * object to the root + */ + ObjDesc = ACPI_CAST_PTR ( + ACPI_OPERAND_OBJECT, AcpiGbl_RootNode); + Status = AE_OK; + } + else if (ParentOp->Common.AmlOpcode == AML_EXTERNAL_OP) + { + /* TBD: May only be temporary */ + + ObjDesc = AcpiUtCreateStringObject ((ACPI_SIZE) NameLength); + + strncpy (ObjDesc->String.Pointer, NameString, NameLength); + Status = AE_OK; + } + else + { + /* + * We just plain didn't find it -- which is a + * very serious error at this point + */ + Status = AE_AML_NAME_NOT_FOUND; + } + } + + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (NameString, Status); + } + } + + /* Free the namestring created above */ + + ACPI_FREE (NameString); + + /* Check status from the lookup */ + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Put the resulting object onto the current object stack */ + + Status = AcpiDsObjStackPush (ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiDbDisplayArgumentObject (ObjDesc, WalkState); + } + else + { + /* Check for null name case */ + + if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && + !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK)) + { + /* + * If the name is null, this means that this is an + * optional result parameter that was not specified + * in the original ASL. Create a Zero Constant for a + * placeholder. (Store to a constant is a Noop.) + */ + Opcode = AML_ZERO_OP; /* Has no arguments! */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Null namepath: Arg=%p\n", Arg)); + } + else + { + Opcode = Arg->Common.AmlOpcode; + } + + /* Get the object type of the argument */ + + OpInfo = AcpiPsGetOpcodeInfo (Opcode); + if (OpInfo->ObjectType == ACPI_TYPE_INVALID) + { + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + } + + if ((OpInfo->Flags & AML_HAS_RETVAL) || + (Arg->Common.Flags & ACPI_PARSEOP_IN_STACK)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Argument previously created, already stacked\n")); + + AcpiDbDisplayArgumentObject ( + WalkState->Operands [WalkState->NumOperands - 1], WalkState); + + /* + * Use value that was already previously returned + * by the evaluation of this argument + */ + Status = AcpiDsResultPop (&ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + /* + * Only error is underflow, and this indicates + * a missing or null operand! + */ + ACPI_EXCEPTION ((AE_INFO, Status, + "Missing or null operand")); + return_ACPI_STATUS (Status); + } + } + else + { + /* Create an ACPI_INTERNAL_OBJECT for the argument */ + + ObjDesc = AcpiUtCreateInternalObject (OpInfo->ObjectType); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the new object */ + + Status = AcpiDsInitObjectFromOp ( + WalkState, Arg, Opcode, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + AcpiUtDeleteObjectDesc (ObjDesc); + return_ACPI_STATUS (Status); + } + } + + /* Put the operand object on the object stack */ + + Status = AcpiDsObjStackPush (ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiDbDisplayArgumentObject (ObjDesc, WalkState); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateOperands + * + * PARAMETERS: WalkState - Current state + * FirstArg - First argument of a parser argument tree + * + * RETURN: Status + * + * DESCRIPTION: Convert an operator's arguments from a parse tree format to + * namespace objects and place those argument object on the object + * stack in preparation for evaluation by the interpreter. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsCreateOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *FirstArg) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *Arg; + ACPI_PARSE_OBJECT *Arguments[ACPI_OBJ_NUM_OPERANDS]; + UINT32 ArgCount = 0; + UINT32 Index = WalkState->NumOperands; + UINT32 i; + + + ACPI_FUNCTION_TRACE_PTR (DsCreateOperands, FirstArg); + + + /* Get all arguments in the list */ + + Arg = FirstArg; + while (Arg) + { + if (Index >= ACPI_OBJ_NUM_OPERANDS) + { + return_ACPI_STATUS (AE_BAD_DATA); + } + + Arguments[Index] = Arg; + WalkState->Operands [Index] = NULL; + + /* Move on to next argument, if any */ + + Arg = Arg->Common.Next; + ArgCount++; + Index++; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "NumOperands %d, ArgCount %d, Index %d\n", + WalkState->NumOperands, ArgCount, Index)); + + /* Create the interpreter arguments, in reverse order */ + + Index--; + for (i = 0; i < ArgCount; i++) + { + Arg = Arguments[Index]; + WalkState->OperandIndex = (UINT8) Index; + + Status = AcpiDsCreateOperand (WalkState, Arg, Index); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Created Arg #%u (%p) %u args total\n", + Index, Arg, ArgCount)); + Index--; + } + + return_ACPI_STATUS (Status); + + +Cleanup: + /* + * We must undo everything done above; meaning that we must + * pop everything off of the operand stack and delete those + * objects + */ + AcpiDsObjStackPopAndDelete (ArgCount, WalkState); + + ACPI_EXCEPTION ((AE_INFO, Status, "While creating Arg %u", Index)); + return_ACPI_STATUS (Status); +} + + +/***************************************************************************** + * + * FUNCTION: AcpiDsEvaluateNamePath + * + * PARAMETERS: WalkState - Current state of the parse tree walk, + * the opcode of current operation should be + * AML_INT_NAMEPATH_OP + * + * RETURN: Status + * + * DESCRIPTION: Translate the -NamePath- parse tree object to the equivalent + * interpreter object, convert it to value, if needed, duplicate + * it, if needed, and push it onto the current result stack. + * + ****************************************************************************/ + +ACPI_STATUS +AcpiDsEvaluateNamePath ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *Op = WalkState->Op; + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *NewObjDesc; + UINT8 Type; + + + ACPI_FUNCTION_TRACE_PTR (DsEvaluateNamePath, WalkState); + + + if (!Op->Common.Parent) + { + /* This happens after certain exception processing */ + + goto Exit; + } + + if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_REF_OF_OP)) + { + /* TBD: Should we specify this feature as a bit of OpInfo->Flags of these opcodes? */ + + goto Exit; + } + + Status = AcpiDsCreateOperand (WalkState, Op, 0); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (Op->Common.Flags & ACPI_PARSEOP_TARGET) + { + NewObjDesc = *Operand; + goto PushResult; + } + + Type = (*Operand)->Common.Type; + + Status = AcpiExResolveToValue (Operand, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + if (Type == ACPI_TYPE_INTEGER) + { + /* It was incremented by AcpiExResolveToValue */ + + AcpiUtRemoveReference (*Operand); + + Status = AcpiUtCopyIobjectToIobject ( + *Operand, &NewObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + } + else + { + /* + * The object either was anew created or is + * a Namespace node - don't decrement it. + */ + NewObjDesc = *Operand; + } + + /* Cleanup for name-path operand */ + + Status = AcpiDsObjStackPop (1, WalkState); + if (ACPI_FAILURE (Status)) + { + WalkState->ResultObj = NewObjDesc; + goto Exit; + } + +PushResult: + + WalkState->ResultObj = NewObjDesc; + + Status = AcpiDsResultPush (WalkState->ResultObj, WalkState); + if (ACPI_SUCCESS (Status)) + { + /* Force to take it from stack */ + + Op->Common.Flags |= ACPI_PARSEOP_IN_STACK; + } + +Exit: + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dswexec.c b/third_party/lib/acpica/source/components/dispatcher/dswexec.c new file mode 100644 index 000000000..307af607a --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dswexec.c @@ -0,0 +1,789 @@ +/****************************************************************************** + * + * Module Name: dswexec - Dispatcher method execution callbacks; + * dispatch to interpreter. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswexec") + +/* + * Dispatch table for opcode classes + */ +static ACPI_EXECUTE_OP AcpiGbl_OpTypeDispatch [] = +{ + AcpiExOpcode_0A_0T_1R, + AcpiExOpcode_1A_0T_0R, + AcpiExOpcode_1A_0T_1R, + AcpiExOpcode_1A_1T_0R, + AcpiExOpcode_1A_1T_1R, + AcpiExOpcode_2A_0T_0R, + AcpiExOpcode_2A_0T_1R, + AcpiExOpcode_2A_1T_1R, + AcpiExOpcode_2A_2T_1R, + AcpiExOpcode_3A_0T_0R, + AcpiExOpcode_3A_1T_1R, + AcpiExOpcode_6A_0T_1R +}; + + +/***************************************************************************** + * + * FUNCTION: AcpiDsGetPredicateValue + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * ResultObj - if non-zero, pop result from result stack + * + * RETURN: Status + * + * DESCRIPTION: Get the result of a predicate evaluation + * + ****************************************************************************/ + +ACPI_STATUS +AcpiDsGetPredicateValue ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ResultObj) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *LocalObjDesc = NULL; + + + ACPI_FUNCTION_TRACE_PTR (DsGetPredicateValue, WalkState); + + + WalkState->ControlState->Common.State = 0; + + if (ResultObj) + { + Status = AcpiDsResultPop (&ObjDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not get result from predicate evaluation")); + + return_ACPI_STATUS (Status); + } + } + else + { + Status = AcpiDsCreateOperand (WalkState, WalkState->Op, 0); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiExResolveToValue (&WalkState->Operands [0], WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ObjDesc = WalkState->Operands [0]; + } + + if (!ObjDesc) + { + ACPI_ERROR ((AE_INFO, + "No predicate ObjDesc=%p State=%p", + ObjDesc, WalkState)); + + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* + * Result of predicate evaluation must be an Integer + * object. Implicitly convert the argument if necessary. + */ + Status = AcpiExConvertToInteger (ObjDesc, &LocalObjDesc, 16); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + if (LocalObjDesc->Common.Type != ACPI_TYPE_INTEGER) + { + ACPI_ERROR ((AE_INFO, + "Bad predicate (not an integer) ObjDesc=%p State=%p Type=0x%X", + ObjDesc, WalkState, ObjDesc->Common.Type)); + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + + /* Truncate the predicate to 32-bits if necessary */ + + (void) AcpiExTruncateFor32bitTable (LocalObjDesc); + + /* + * Save the result of the predicate evaluation on + * the control stack + */ + if (LocalObjDesc->Integer.Value) + { + WalkState->ControlState->Common.Value = TRUE; + } + else + { + /* + * Predicate is FALSE, we will just toss the + * rest of the package + */ + WalkState->ControlState->Common.Value = FALSE; + Status = AE_CTRL_FALSE; + } + + /* Predicate can be used for an implicit return value */ + + (void) AcpiDsDoImplicitReturn (LocalObjDesc, WalkState, TRUE); + + +Cleanup: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Completed a predicate eval=%X Op=%p\n", + WalkState->ControlState->Common.Value, WalkState->Op)); + + /* Break to debugger to display result */ + + AcpiDbDisplayResultObject (LocalObjDesc, WalkState); + + /* + * Delete the predicate result object (we know that + * we don't need it anymore) + */ + if (LocalObjDesc != ObjDesc) + { + AcpiUtRemoveReference (LocalObjDesc); + } + AcpiUtRemoveReference (ObjDesc); + + WalkState->ControlState->Common.State = ACPI_CONTROL_NORMAL; + return_ACPI_STATUS (Status); +} + + +/***************************************************************************** + * + * FUNCTION: AcpiDsExecBeginOp + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * OutOp - Where to return op if a new one is created + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the execution of control + * methods. This is where most operators and operands are + * dispatched to the interpreter. + * + ****************************************************************************/ + +ACPI_STATUS +AcpiDsExecBeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_STATUS Status = AE_OK; + UINT32 OpcodeClass; + + + ACPI_FUNCTION_TRACE_PTR (DsExecBeginOp, WalkState); + + + Op = WalkState->Op; + if (!Op) + { + Status = AcpiDsLoad2BeginOp (WalkState, OutOp); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + Op = *OutOp; + WalkState->Op = Op; + WalkState->Opcode = Op->Common.AmlOpcode; + WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + + if (AcpiNsOpensScope (WalkState->OpInfo->ObjectType)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "(%s) Popping scope for Op %p\n", + AcpiUtGetTypeName (WalkState->OpInfo->ObjectType), Op)); + + Status = AcpiDsScopeStackPop (WalkState); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + } + } + + if (Op == WalkState->Origin) + { + if (OutOp) + { + *OutOp = Op; + } + + return_ACPI_STATUS (AE_OK); + } + + /* + * If the previous opcode was a conditional, this opcode + * must be the beginning of the associated predicate. + * Save this knowledge in the current scope descriptor + */ + if ((WalkState->ControlState) && + (WalkState->ControlState->Common.State == + ACPI_CONTROL_CONDITIONAL_EXECUTING)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Exec predicate Op=%p State=%p\n", + Op, WalkState)); + + WalkState->ControlState->Common.State = + ACPI_CONTROL_PREDICATE_EXECUTING; + + /* Save start of predicate */ + + WalkState->ControlState->Control.PredicateOp = Op; + } + + + OpcodeClass = WalkState->OpInfo->Class; + + /* We want to send namepaths to the load code */ + + if (Op->Common.AmlOpcode == AML_INT_NAMEPATH_OP) + { + OpcodeClass = AML_CLASS_NAMED_OBJECT; + } + + /* + * Handle the opcode based upon the opcode type + */ + switch (OpcodeClass) + { + case AML_CLASS_CONTROL: + + Status = AcpiDsExecBeginControlOp (WalkState, Op); + break; + + case AML_CLASS_NAMED_OBJECT: + + if (WalkState->WalkType & ACPI_WALK_METHOD) + { + /* + * Found a named object declaration during method execution; + * we must enter this object into the namespace. The created + * object is temporary and will be deleted upon completion of + * the execution of this method. + * + * Note 10/2010: Except for the Scope() op. This opcode does + * not actually create a new object, it refers to an existing + * object. However, for Scope(), we want to indeed open a + * new scope. + */ + if (Op->Common.AmlOpcode != AML_SCOPE_OP) + { + Status = AcpiDsLoad2BeginOp (WalkState, NULL); + } + else + { + Status = AcpiDsScopeStackPush ( + Op->Named.Node, Op->Named.Node->Type, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + break; + + case AML_CLASS_EXECUTE: + case AML_CLASS_CREATE: + + break; + + default: + + break; + } + + /* Nothing to do here during method execution */ + + return_ACPI_STATUS (Status); + + +ErrorExit: + Status = AcpiDsMethodError (Status, WalkState); + return_ACPI_STATUS (Status); +} + + +/***************************************************************************** + * + * FUNCTION: AcpiDsExecEndOp + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the execution of control + * methods. The only thing we really need to do here is to + * notice the beginning of IF, ELSE, and WHILE blocks. + * + ****************************************************************************/ + +ACPI_STATUS +AcpiDsExecEndOp ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_STATUS Status = AE_OK; + UINT32 OpType; + UINT32 OpClass; + ACPI_PARSE_OBJECT *NextOp; + ACPI_PARSE_OBJECT *FirstArg; + + + ACPI_FUNCTION_TRACE_PTR (DsExecEndOp, WalkState); + + + Op = WalkState->Op; + OpType = WalkState->OpInfo->Type; + OpClass = WalkState->OpInfo->Class; + + if (OpClass == AML_CLASS_UNKNOWN) + { + ACPI_ERROR ((AE_INFO, "Unknown opcode 0x%X", Op->Common.AmlOpcode)); + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + } + + FirstArg = Op->Common.Value.Arg; + + /* Init the walk state */ + + WalkState->NumOperands = 0; + WalkState->OperandIndex = 0; + WalkState->ReturnDesc = NULL; + WalkState->ResultObj = NULL; + + /* Call debugger for single step support (DEBUG build only) */ + + Status = AcpiDbSingleStep (WalkState, Op, OpClass); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Decode the Opcode Class */ + + switch (OpClass) + { + case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */ + + if (WalkState->Opcode == AML_INT_NAMEPATH_OP) + { + Status = AcpiDsEvaluateNamePath (WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + } + break; + + case AML_CLASS_EXECUTE: /* Most operators with arguments */ + + /* Build resolved operand stack */ + + Status = AcpiDsCreateOperands (WalkState, FirstArg); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * All opcodes require operand resolution, with the only exceptions + * being the ObjectType and SizeOf operators. + */ + if (!(WalkState->OpInfo->Flags & AML_NO_OPERAND_RESOLVE)) + { + /* Resolve all operands */ + + Status = AcpiExResolveOperands (WalkState->Opcode, + &(WalkState->Operands [WalkState->NumOperands -1]), + WalkState); + } + + if (ACPI_SUCCESS (Status)) + { + /* + * Dispatch the request to the appropriate interpreter handler + * routine. There is one routine per opcode "type" based upon the + * number of opcode arguments and return type. + */ + Status = AcpiGbl_OpTypeDispatch[OpType] (WalkState); + } + else + { + /* + * Treat constructs of the form "Store(LocalX,LocalX)" as noops when the + * Local is uninitialized. + */ + if ((Status == AE_AML_UNINITIALIZED_LOCAL) && + (WalkState->Opcode == AML_STORE_OP) && + (WalkState->Operands[0]->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) && + (WalkState->Operands[1]->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) && + (WalkState->Operands[0]->Reference.Class == + WalkState->Operands[1]->Reference.Class) && + (WalkState->Operands[0]->Reference.Value == + WalkState->Operands[1]->Reference.Value)) + { + Status = AE_OK; + } + else + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While resolving operands for [%s]", + AcpiPsGetOpcodeName (WalkState->Opcode))); + } + } + + /* Always delete the argument objects and clear the operand stack */ + + AcpiDsClearOperands (WalkState); + + /* + * If a result object was returned from above, push it on the + * current result stack + */ + if (ACPI_SUCCESS (Status) && + WalkState->ResultObj) + { + Status = AcpiDsResultPush (WalkState->ResultObj, WalkState); + } + break; + + default: + + switch (OpType) + { + case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */ + + /* 1 Operand, 0 ExternalResult, 0 InternalResult */ + + Status = AcpiDsExecEndControlOp (WalkState, Op); + + break; + + case AML_TYPE_METHOD_CALL: + /* + * If the method is referenced from within a package + * declaration, it is not a invocation of the method, just + * a reference to it. + */ + if ((Op->Asl.Parent) && + ((Op->Asl.Parent->Asl.AmlOpcode == AML_PACKAGE_OP) || + (Op->Asl.Parent->Asl.AmlOpcode == AML_VAR_PACKAGE_OP))) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Method Reference in a Package, Op=%p\n", Op)); + + Op->Common.Node = (ACPI_NAMESPACE_NODE *) + Op->Asl.Value.Arg->Asl.Node; + AcpiUtAddReference (Op->Asl.Value.Arg->Asl.Node->Object); + return_ACPI_STATUS (AE_OK); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Method invocation, Op=%p\n", Op)); + + /* + * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains + * the method Node pointer + */ + /* NextOp points to the op that holds the method name */ + + NextOp = FirstArg; + + /* NextOp points to first argument op */ + + NextOp = NextOp->Common.Next; + + /* + * Get the method's arguments and put them on the operand stack + */ + Status = AcpiDsCreateOperands (WalkState, NextOp); + if (ACPI_FAILURE (Status)) + { + break; + } + + /* + * Since the operands will be passed to another control method, + * we must resolve all local references here (Local variables, + * arguments to *this* method, etc.) + */ + Status = AcpiDsResolveOperands (WalkState); + if (ACPI_FAILURE (Status)) + { + /* On error, clear all resolved operands */ + + AcpiDsClearOperands (WalkState); + break; + } + + /* + * Tell the walk loop to preempt this running method and + * execute the new method + */ + Status = AE_CTRL_TRANSFER; + + /* + * Return now; we don't want to disturb anything, + * especially the operand count! + */ + return_ACPI_STATUS (Status); + + case AML_TYPE_CREATE_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing CreateField Buffer/Index Op=%p\n", Op)); + + Status = AcpiDsLoad2EndOp (WalkState); + if (ACPI_FAILURE (Status)) + { + break; + } + + Status = AcpiDsEvalBufferFieldOperands (WalkState, Op); + break; + + + case AML_TYPE_CREATE_OBJECT: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing CreateObject (Buffer/Package) Op=%p\n", Op)); + + switch (Op->Common.Parent->Common.AmlOpcode) + { + case AML_NAME_OP: + /* + * Put the Node on the object stack (Contains the ACPI Name + * of this object) + */ + WalkState->Operands[0] = (void *) + Op->Common.Parent->Common.Node; + WalkState->NumOperands = 1; + + Status = AcpiDsCreateNode (WalkState, + Op->Common.Parent->Common.Node, Op->Common.Parent); + if (ACPI_FAILURE (Status)) + { + break; + } + + /* Fall through */ + /*lint -fallthrough */ + + case AML_INT_EVAL_SUBTREE_OP: + + Status = AcpiDsEvalDataObjectOperands (WalkState, Op, + AcpiNsGetAttachedObject (Op->Common.Parent->Common.Node)); + break; + + default: + + Status = AcpiDsEvalDataObjectOperands (WalkState, Op, NULL); + break; + } + + /* + * If a result object was returned from above, push it on the + * current result stack + */ + if (WalkState->ResultObj) + { + Status = AcpiDsResultPush (WalkState->ResultObj, WalkState); + } + break; + + case AML_TYPE_NAMED_FIELD: + case AML_TYPE_NAMED_COMPLEX: + case AML_TYPE_NAMED_SIMPLE: + case AML_TYPE_NAMED_NO_OBJ: + + Status = AcpiDsLoad2EndOp (WalkState); + if (ACPI_FAILURE (Status)) + { + break; + } + + if (Op->Common.AmlOpcode == AML_REGION_OP) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing OpRegion Address/Length Op=%p\n", Op)); + + Status = AcpiDsEvalRegionOperands (WalkState, Op); + if (ACPI_FAILURE (Status)) + { + break; + } + } + else if (Op->Common.AmlOpcode == AML_DATA_REGION_OP) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing DataTableRegion Strings Op=%p\n", Op)); + + Status = AcpiDsEvalTableRegionOperands (WalkState, Op); + if (ACPI_FAILURE (Status)) + { + break; + } + } + else if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing BankField Op=%p\n", Op)); + + Status = AcpiDsEvalBankFieldOperands (WalkState, Op); + if (ACPI_FAILURE (Status)) + { + break; + } + } + break; + + case AML_TYPE_UNDEFINED: + + ACPI_ERROR ((AE_INFO, + "Undefined opcode type Op=%p", Op)); + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + + case AML_TYPE_BOGUS: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Internal opcode=%X type Op=%p\n", + WalkState->Opcode, Op)); + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unimplemented opcode, class=0x%X " + "type=0x%X Opcode=0x%X Op=%p", + OpClass, OpType, Op->Common.AmlOpcode, Op)); + + Status = AE_NOT_IMPLEMENTED; + break; + } + } + + /* + * ACPI 2.0 support for 64-bit integers: Truncate numeric + * result value if we are executing from a 32-bit ACPI table + */ + (void) AcpiExTruncateFor32bitTable (WalkState->ResultObj); + + /* + * Check if we just completed the evaluation of a + * conditional predicate + */ + if ((ACPI_SUCCESS (Status)) && + (WalkState->ControlState) && + (WalkState->ControlState->Common.State == + ACPI_CONTROL_PREDICATE_EXECUTING) && + (WalkState->ControlState->Control.PredicateOp == Op)) + { + Status = AcpiDsGetPredicateValue (WalkState, WalkState->ResultObj); + WalkState->ResultObj = NULL; + } + + +Cleanup: + + if (WalkState->ResultObj) + { + /* Break to debugger to display result */ + + AcpiDbDisplayResultObject (WalkState->ResultObj,WalkState); + + /* + * Delete the result op if and only if: + * Parent will not use the result -- such as any + * non-nested type2 op in a method (parent will be method) + */ + AcpiDsDeleteResultIfNotUsed (Op, WalkState->ResultObj, WalkState); + } + +#ifdef _UNDER_DEVELOPMENT + + if (WalkState->ParserState.Aml == WalkState->ParserState.AmlEnd) + { + AcpiDbMethodEnd (WalkState); + } +#endif + + /* Invoke exception handler on error */ + + if (ACPI_FAILURE (Status)) + { + Status = AcpiDsMethodError (Status, WalkState); + } + + /* Always clear the object stack */ + + WalkState->NumOperands = 0; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dswload.c b/third_party/lib/acpica/source/components/dispatcher/dswload.c new file mode 100644 index 000000000..db5566120 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dswload.c @@ -0,0 +1,593 @@ +/****************************************************************************** + * + * Module Name: dswload - Dispatcher first pass namespace load callbacks + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" + +#ifdef ACPI_ASL_COMPILER +#include "acdisasm.h" +#endif + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswload") + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitCallbacks + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * PassNumber - 1, 2, or 3 + * + * RETURN: Status + * + * DESCRIPTION: Init walk state callbacks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsInitCallbacks ( + ACPI_WALK_STATE *WalkState, + UINT32 PassNumber) +{ + + switch (PassNumber) + { + case 0: + + /* Parse only - caller will setup callbacks */ + + WalkState->ParseFlags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE | + ACPI_PARSE_DISASSEMBLE; + WalkState->DescendingCallback = NULL; + WalkState->AscendingCallback = NULL; + break; + + case 1: + + /* Load pass 1 */ + + WalkState->ParseFlags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE; + WalkState->DescendingCallback = AcpiDsLoad1BeginOp; + WalkState->AscendingCallback = AcpiDsLoad1EndOp; + break; + + case 2: + + /* Load pass 2 */ + + WalkState->ParseFlags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE; + WalkState->DescendingCallback = AcpiDsLoad2BeginOp; + WalkState->AscendingCallback = AcpiDsLoad2EndOp; + break; + + case 3: + + /* Execution pass */ + +#ifndef ACPI_NO_METHOD_EXECUTION + WalkState->ParseFlags |= ACPI_PARSE_EXECUTE | + ACPI_PARSE_DELETE_TREE; + WalkState->DescendingCallback = AcpiDsExecBeginOp; + WalkState->AscendingCallback = AcpiDsExecEndOp; +#endif + break; + + default: + + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsLoad1BeginOp + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * OutOp - Where to return op if a new one is created + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsLoad1BeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + char *Path; + UINT32 Flags; + + + ACPI_FUNCTION_TRACE (DsLoad1BeginOp); + + + Op = WalkState->Op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", Op, WalkState)); + + /* We are only interested in opcodes that have an associated name */ + + if (Op) + { + if (!(WalkState->OpInfo->Flags & AML_NAMED)) + { + *OutOp = Op; + return_ACPI_STATUS (AE_OK); + } + + /* Check if this object has already been installed in the namespace */ + + if (Op->Common.Node) + { + *OutOp = Op; + return_ACPI_STATUS (AE_OK); + } + } + + Path = AcpiPsGetNextNamestring (&WalkState->ParserState); + + /* Map the raw opcode into an internal object type */ + + ObjectType = WalkState->OpInfo->ObjectType; + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "State=%p Op=%p [%s]\n", WalkState, Op, + AcpiUtGetTypeName (ObjectType))); + + switch (WalkState->Opcode) + { + case AML_SCOPE_OP: + /* + * The target name of the Scope() operator must exist at this point so + * that we can actually open the scope to enter new names underneath it. + * Allow search-to-root for single namesegs. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, WalkState, &(Node)); +#ifdef ACPI_ASL_COMPILER + if (Status == AE_NOT_FOUND) + { + /* + * Table disassembly: + * Target of Scope() not found. Generate an External for it, and + * insert the name into the namespace. + */ + AcpiDmAddOpToExternalList (Op, Path, ACPI_TYPE_DEVICE, 0, 0); + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, + ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, + WalkState, &Node); + } +#endif + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Path, Status); + return_ACPI_STATUS (Status); + } + + /* + * Check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + switch (Node->Type) + { + case ACPI_TYPE_ANY: + case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + /* + * These types we will allow, but we will change the type. + * This enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + * + * Note: silently change the type here. On the second pass, + * we will report a warning + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Type override - [%4.4s] had invalid type (%s) " + "for Scope operator, changed to type ANY\n", + AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type))); + + Node->Type = ACPI_TYPE_ANY; + WalkState->ScopeInfo->Common.Value = ACPI_TYPE_ANY; + break; + + case ACPI_TYPE_METHOD: + /* + * Allow scope change to root during execution of module-level + * code. Root is typed METHOD during this time. + */ + if ((Node == AcpiGbl_RootNode) && + (WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) + { + break; + } + + /*lint -fallthrough */ + + default: + + /* All other types are an error */ + + ACPI_ERROR ((AE_INFO, + "Invalid type (%s) for target of " + "Scope operator [%4.4s] (Cannot override)", + AcpiUtGetTypeName (Node->Type), AcpiUtGetNodeName (Node))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + break; + + default: + /* + * For all other named opcodes, we will enter the name into + * the namespace. + * + * Setup the search flags. + * Since we are entering a name into the namespace, we do not want to + * enable the search-to-root upsearch. + * + * There are only two conditions where it is acceptable that the name + * already exists: + * 1) the Scope() operator can reopen a scoping object that was + * previously defined (Scope, Method, Device, etc.) + * 2) Whenever we are parsing a deferred opcode (OpRegion, Buffer, + * BufferField, or Package), the name of the object is already + * in the namespace. + */ + if (WalkState->DeferredNode) + { + /* This name is already in the namespace, get the node */ + + Node = WalkState->DeferredNode; + Status = AE_OK; + break; + } + + /* + * If we are executing a method, do not create any namespace objects + * during the load phase, only during execution. + */ + if (WalkState->MethodNode) + { + Node = NULL; + Status = AE_OK; + break; + } + + Flags = ACPI_NS_NO_UPSEARCH; + if ((WalkState->Opcode != AML_SCOPE_OP) && + (!(WalkState->ParseFlags & ACPI_PARSE_DEFERRED_OP))) + { + if (WalkState->NamespaceOverride) + { + Flags |= ACPI_NS_OVERRIDE_IF_FOUND; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Override allowed\n", + AcpiUtGetTypeName (ObjectType))); + } + else + { + Flags |= ACPI_NS_ERROR_IF_FOUND; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n", + AcpiUtGetTypeName (ObjectType))); + } + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[%s] Both Find or Create allowed\n", + AcpiUtGetTypeName (ObjectType))); + } + + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, + ACPI_IMODE_LOAD_PASS1, Flags, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_ALREADY_EXISTS) + { + /* The name already exists in this scope */ + + if (Node->Flags & ANOBJ_IS_EXTERNAL) + { + /* + * Allow one create on an object or segment that was + * previously declared External + */ + Node->Flags &= ~ANOBJ_IS_EXTERNAL; + Node->Type = (UINT8) ObjectType; + + /* Just retyped a node, probably will need to open a scope */ + + if (AcpiNsOpensScope (ObjectType)) + { + Status = AcpiDsScopeStackPush ( + Node, ObjectType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + Status = AE_OK; + } + } + + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Path, Status); + return_ACPI_STATUS (Status); + } + } + break; + } + + /* Common exit */ + + if (!Op) + { + /* Create a new op */ + + Op = AcpiPsAllocOp (WalkState->Opcode, WalkState->Aml); + if (!Op) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + + /* Initialize the op */ + +#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) + Op->Named.Path = ACPI_CAST_PTR (UINT8, Path); +#endif + + if (Node) + { + /* + * Put the Node in the "op" object that the parser uses, so we + * can get it again quickly when this scope is closed + */ + Op->Common.Node = Node; + Op->Named.Name = Node->Name.Integer; + } + + AcpiPsAppendArg (AcpiPsGetParentScope (&WalkState->ParserState), Op); + *OutOp = Op; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsLoad1EndOp + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsLoad1EndOp ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_OBJECT_TYPE ObjectType; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (DsLoad1EndOp); + + + Op = WalkState->Op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", Op, WalkState)); + + /* We are only interested in opcodes that have an associated name */ + + if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_FIELD))) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get the object type to determine if we should pop the scope */ + + ObjectType = WalkState->OpInfo->ObjectType; + +#ifndef ACPI_NO_METHOD_EXECUTION + if (WalkState->OpInfo->Flags & AML_FIELD) + { + /* + * If we are executing a method, do not create any namespace objects + * during the load phase, only during execution. + */ + if (!WalkState->MethodNode) + { + if (WalkState->Opcode == AML_FIELD_OP || + WalkState->Opcode == AML_BANK_FIELD_OP || + WalkState->Opcode == AML_INDEX_FIELD_OP) + { + Status = AcpiDsInitFieldObjects (Op, WalkState); + } + } + return_ACPI_STATUS (Status); + } + + /* + * If we are executing a method, do not create any namespace objects + * during the load phase, only during execution. + */ + if (!WalkState->MethodNode) + { + if (Op->Common.AmlOpcode == AML_REGION_OP) + { + Status = AcpiExCreateRegion (Op->Named.Data, Op->Named.Length, + (ACPI_ADR_SPACE_TYPE) + ((Op->Common.Value.Arg)->Common.Value.Integer), + WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + else if (Op->Common.AmlOpcode == AML_DATA_REGION_OP) + { + Status = AcpiExCreateRegion (Op->Named.Data, Op->Named.Length, + ACPI_ADR_SPACE_DATA_TABLE, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } +#endif + + if (Op->Common.AmlOpcode == AML_NAME_OP) + { + /* For Name opcode, get the object type from the argument */ + + if (Op->Common.Value.Arg) + { + ObjectType = (AcpiPsGetOpcodeInfo ( + (Op->Common.Value.Arg)->Common.AmlOpcode))->ObjectType; + + /* Set node type if we have a namespace node */ + + if (Op->Common.Node) + { + Op->Common.Node->Type = (UINT8) ObjectType; + } + } + } + + /* + * If we are executing a method, do not create any namespace objects + * during the load phase, only during execution. + */ + if (!WalkState->MethodNode) + { + if (Op->Common.AmlOpcode == AML_METHOD_OP) + { + /* + * MethodOp PkgLength NameString MethodFlags TermList + * + * Note: We must create the method node/object pair as soon as we + * see the method declaration. This allows later pass1 parsing + * of invocations of the method (need to know the number of + * arguments.) + */ + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "LOADING-Method: State=%p Op=%p NamedObj=%p\n", + WalkState, Op, Op->Named.Node)); + + if (!AcpiNsGetAttachedObject (Op->Named.Node)) + { + WalkState->Operands[0] = ACPI_CAST_PTR (void, Op->Named.Node); + WalkState->NumOperands = 1; + + Status = AcpiDsCreateOperands ( + WalkState, Op->Common.Value.Arg); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiExCreateMethod (Op->Named.Data, + Op->Named.Length, WalkState); + } + + WalkState->Operands[0] = NULL; + WalkState->NumOperands = 0; + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + } + + /* Pop the scope stack (only if loading a table) */ + + if (!WalkState->MethodNode && + AcpiNsOpensScope (ObjectType)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n", + AcpiUtGetTypeName (ObjectType), Op)); + + Status = AcpiDsScopeStackPop (WalkState); + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dswload2.c b/third_party/lib/acpica/source/components/dispatcher/dswload2.c new file mode 100644 index 000000000..2c099ef0f --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dswload2.c @@ -0,0 +1,757 @@ +/****************************************************************************** + * + * Module Name: dswload2 - Dispatcher second pass namespace load callbacks + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswload2") + + +/******************************************************************************* + * + * FUNCTION: AcpiDsLoad2BeginOp + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * OutOp - Wher to return op if a new one is created + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsLoad2BeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + char *BufferPtr; + UINT32 Flags; + + + ACPI_FUNCTION_TRACE (DsLoad2BeginOp); + + + Op = WalkState->Op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", Op, WalkState)); + + if (Op) + { + if ((WalkState->ControlState) && + (WalkState->ControlState->Common.State == + ACPI_CONTROL_CONDITIONAL_EXECUTING)) + { + /* We are executing a while loop outside of a method */ + + Status = AcpiDsExecBeginOp (WalkState, OutOp); + return_ACPI_STATUS (Status); + } + + /* We only care about Namespace opcodes here */ + + if ((!(WalkState->OpInfo->Flags & AML_NSOPCODE) && + (WalkState->Opcode != AML_INT_NAMEPATH_OP)) || + (!(WalkState->OpInfo->Flags & AML_NAMED))) + { + return_ACPI_STATUS (AE_OK); + } + + /* Get the name we are going to enter or lookup in the namespace */ + + if (WalkState->Opcode == AML_INT_NAMEPATH_OP) + { + /* For Namepath op, get the path string */ + + BufferPtr = Op->Common.Value.String; + if (!BufferPtr) + { + /* No name, just exit */ + + return_ACPI_STATUS (AE_OK); + } + } + else + { + /* Get name from the op */ + + BufferPtr = ACPI_CAST_PTR (char, &Op->Named.Name); + } + } + else + { + /* Get the namestring from the raw AML */ + + BufferPtr = AcpiPsGetNextNamestring (&WalkState->ParserState); + } + + /* Map the opcode into an internal object type */ + + ObjectType = WalkState->OpInfo->ObjectType; + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "State=%p Op=%p Type=%X\n", WalkState, Op, ObjectType)); + + switch (WalkState->Opcode) + { + case AML_FIELD_OP: + case AML_BANK_FIELD_OP: + case AML_INDEX_FIELD_OP: + + Node = NULL; + Status = AE_OK; + break; + + case AML_INT_NAMEPATH_OP: + /* + * The NamePath is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, BufferPtr, ObjectType, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + WalkState, &(Node)); + break; + + case AML_SCOPE_OP: + + /* Special case for Scope(\) -> refers to the Root node */ + + if (Op && (Op->Named.Node == AcpiGbl_RootNode)) + { + Node = Op->Named.Node; + + Status = AcpiDsScopeStackPush (Node, ObjectType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + else + { + /* + * The Path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, BufferPtr, ObjectType, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + WalkState, &(Node)); + if (ACPI_FAILURE (Status)) + { +#ifdef ACPI_ASL_COMPILER + if (Status == AE_NOT_FOUND) + { + Status = AE_OK; + } + else + { + ACPI_ERROR_NAMESPACE (BufferPtr, Status); + } +#else + ACPI_ERROR_NAMESPACE (BufferPtr, Status); +#endif + return_ACPI_STATUS (Status); + } + } + + /* + * We must check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + switch (Node->Type) + { + case ACPI_TYPE_ANY: + case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These types we will allow, but we will change the type. + * This enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + */ + ACPI_WARNING ((AE_INFO, + "Type override - [%4.4s] had invalid type (%s) " + "for Scope operator, changed to type ANY", + AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type))); + + Node->Type = ACPI_TYPE_ANY; + WalkState->ScopeInfo->Common.Value = ACPI_TYPE_ANY; + break; + + case ACPI_TYPE_METHOD: + + /* + * Allow scope change to root during execution of module-level + * code. Root is typed METHOD during this time. + */ + if ((Node == AcpiGbl_RootNode) && + (WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) + { + break; + } + + /*lint -fallthrough */ + + default: + + /* All other types are an error */ + + ACPI_ERROR ((AE_INFO, + "Invalid type (%s) for target of " + "Scope operator [%4.4s] (Cannot override)", + AcpiUtGetTypeName (Node->Type), AcpiUtGetNodeName (Node))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + break; + + default: + + /* All other opcodes */ + + if (Op && Op->Common.Node) + { + /* This op/node was previously entered into the namespace */ + + Node = Op->Common.Node; + + if (AcpiNsOpensScope (ObjectType)) + { + Status = AcpiDsScopeStackPush (Node, ObjectType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + return_ACPI_STATUS (AE_OK); + } + + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. + * + * Note: Name may already exist if we are executing a deferred opcode. + */ + if (WalkState->DeferredNode) + { + /* This name is already in the namespace, get the node */ + + Node = WalkState->DeferredNode; + Status = AE_OK; + break; + } + + Flags = ACPI_NS_NO_UPSEARCH; + if (WalkState->PassNumber == ACPI_IMODE_EXECUTE) + { + /* Execution mode, node cannot already exist, node is temporary */ + + Flags |= ACPI_NS_ERROR_IF_FOUND; + + if (!(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) + { + Flags |= ACPI_NS_TEMPORARY; + } + } + + /* Add new entry or lookup existing entry */ + + Status = AcpiNsLookup (WalkState->ScopeInfo, BufferPtr, ObjectType, + ACPI_IMODE_LOAD_PASS2, Flags, WalkState, &Node); + + if (ACPI_SUCCESS (Status) && (Flags & ACPI_NS_TEMPORARY)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "***New Node [%4.4s] %p is temporary\n", + AcpiUtGetNodeName (Node), Node)); + } + break; + } + + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (BufferPtr, Status); + return_ACPI_STATUS (Status); + } + + if (!Op) + { + /* Create a new op */ + + Op = AcpiPsAllocOp (WalkState->Opcode, WalkState->Aml); + if (!Op) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the new op */ + + if (Node) + { + Op->Named.Name = Node->Name.Integer; + } + *OutOp = Op; + } + + /* + * Put the Node in the "op" object that the parser uses, so we + * can get it again quickly when this scope is closed + */ + Op->Common.Node = Node; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsLoad2EndOp + * + * PARAMETERS: WalkState - Current state of the parse tree walk + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsLoad2EndOp ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_PARSE_OBJECT *Op; + ACPI_STATUS Status = AE_OK; + ACPI_OBJECT_TYPE ObjectType; + ACPI_NAMESPACE_NODE *Node; + ACPI_PARSE_OBJECT *Arg; + ACPI_NAMESPACE_NODE *NewNode; +#ifndef ACPI_NO_METHOD_EXECUTION + UINT32 i; + UINT8 RegionSpace; +#endif + + + ACPI_FUNCTION_TRACE (DsLoad2EndOp); + + Op = WalkState->Op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", + WalkState->OpInfo->Name, Op, WalkState)); + + /* Check if opcode had an associated namespace object */ + + if (!(WalkState->OpInfo->Flags & AML_NSOBJECT)) + { + return_ACPI_STATUS (AE_OK); + } + + if (Op->Common.AmlOpcode == AML_SCOPE_OP) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Ending scope Op=%p State=%p\n", Op, WalkState)); + } + + ObjectType = WalkState->OpInfo->ObjectType; + + /* + * Get the Node/name from the earlier lookup + * (It was saved in the *op structure) + */ + Node = Op->Common.Node; + + /* + * Put the Node on the object stack (Contains the ACPI Name of + * this object) + */ + WalkState->Operands[0] = (void *) Node; + WalkState->NumOperands = 1; + + /* Pop the scope stack */ + + if (AcpiNsOpensScope (ObjectType) && + (Op->Common.AmlOpcode != AML_INT_METHODCALL_OP)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", + AcpiUtGetTypeName (ObjectType), Op)); + + Status = AcpiDsScopeStackPop (WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + } + + /* + * Named operations are as follows: + * + * AML_ALIAS + * AML_BANKFIELD + * AML_CREATEBITFIELD + * AML_CREATEBYTEFIELD + * AML_CREATEDWORDFIELD + * AML_CREATEFIELD + * AML_CREATEQWORDFIELD + * AML_CREATEWORDFIELD + * AML_DATA_REGION + * AML_DEVICE + * AML_EVENT + * AML_FIELD + * AML_INDEXFIELD + * AML_METHOD + * AML_METHODCALL + * AML_MUTEX + * AML_NAME + * AML_NAMEDFIELD + * AML_OPREGION + * AML_POWERRES + * AML_PROCESSOR + * AML_SCOPE + * AML_THERMALZONE + */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Create-Load [%s] State=%p Op=%p NamedObj=%p\n", + AcpiPsGetOpcodeName (Op->Common.AmlOpcode), WalkState, Op, Node)); + + /* Decode the opcode */ + + Arg = Op->Common.Value.Arg; + + switch (WalkState->OpInfo->Type) + { +#ifndef ACPI_NO_METHOD_EXECUTION + + case AML_TYPE_CREATE_FIELD: + /* + * Create the field object, but the field buffer and index must + * be evaluated later during the execution phase + */ + Status = AcpiDsCreateBufferField (Op, WalkState); + break; + + case AML_TYPE_NAMED_FIELD: + /* + * If we are executing a method, initialize the field + */ + if (WalkState->MethodNode) + { + Status = AcpiDsInitFieldObjects (Op, WalkState); + } + + switch (Op->Common.AmlOpcode) + { + case AML_INDEX_FIELD_OP: + + Status = AcpiDsCreateIndexField ( + Op, (ACPI_HANDLE) Arg->Common.Node, WalkState); + break; + + case AML_BANK_FIELD_OP: + + Status = AcpiDsCreateBankField (Op, Arg->Common.Node, WalkState); + break; + + case AML_FIELD_OP: + + Status = AcpiDsCreateField (Op, Arg->Common.Node, WalkState); + break; + + default: + + /* All NAMED_FIELD opcodes must be handled above */ + break; + } + break; + + case AML_TYPE_NAMED_SIMPLE: + + Status = AcpiDsCreateOperands (WalkState, Arg); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + switch (Op->Common.AmlOpcode) + { + case AML_PROCESSOR_OP: + + Status = AcpiExCreateProcessor (WalkState); + break; + + case AML_POWER_RES_OP: + + Status = AcpiExCreatePowerResource (WalkState); + break; + + case AML_MUTEX_OP: + + Status = AcpiExCreateMutex (WalkState); + break; + + case AML_EVENT_OP: + + Status = AcpiExCreateEvent (WalkState); + break; + + case AML_ALIAS_OP: + + Status = AcpiExCreateAlias (WalkState); + break; + + default: + + /* Unknown opcode */ + + Status = AE_OK; + goto Cleanup; + } + + /* Delete operands */ + + for (i = 1; i < WalkState->NumOperands; i++) + { + AcpiUtRemoveReference (WalkState->Operands[i]); + WalkState->Operands[i] = NULL; + } + + break; +#endif /* ACPI_NO_METHOD_EXECUTION */ + + case AML_TYPE_NAMED_COMPLEX: + + switch (Op->Common.AmlOpcode) + { +#ifndef ACPI_NO_METHOD_EXECUTION + case AML_REGION_OP: + case AML_DATA_REGION_OP: + + if (Op->Common.AmlOpcode == AML_REGION_OP) + { + RegionSpace = (ACPI_ADR_SPACE_TYPE) + ((Op->Common.Value.Arg)->Common.Value.Integer); + } + else + { + RegionSpace = ACPI_ADR_SPACE_DATA_TABLE; + } + + /* + * The OpRegion is not fully parsed at this time. The only valid + * argument is the SpaceId. (We must save the address of the + * AML of the address and length operands) + * + * If we have a valid region, initialize it. The namespace is + * unlocked at this point. + * + * Need to unlock interpreter if it is locked (if we are running + * a control method), in order to allow _REG methods to be run + * during AcpiEvInitializeRegion. + */ + if (WalkState->MethodNode) + { + /* + * Executing a method: initialize the region and unlock + * the interpreter + */ + Status = AcpiExCreateRegion (Op->Named.Data, + Op->Named.Length, RegionSpace, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiExExitInterpreter (); + } + + Status = AcpiEvInitializeRegion ( + AcpiNsGetAttachedObject (Node), FALSE); + if (WalkState->MethodNode) + { + AcpiExEnterInterpreter (); + } + + if (ACPI_FAILURE (Status)) + { + /* + * If AE_NOT_EXIST is returned, it is not fatal + * because many regions get created before a handler + * is installed for said region. + */ + if (AE_NOT_EXIST == Status) + { + Status = AE_OK; + } + } + break; + + case AML_NAME_OP: + + Status = AcpiDsCreateNode (WalkState, Node, Op); + break; + + case AML_METHOD_OP: + /* + * MethodOp PkgLength NameString MethodFlags TermList + * + * Note: We must create the method node/object pair as soon as we + * see the method declaration. This allows later pass1 parsing + * of invocations of the method (need to know the number of + * arguments.) + */ + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "LOADING-Method: State=%p Op=%p NamedObj=%p\n", + WalkState, Op, Op->Named.Node)); + + if (!AcpiNsGetAttachedObject (Op->Named.Node)) + { + WalkState->Operands[0] = ACPI_CAST_PTR (void, Op->Named.Node); + WalkState->NumOperands = 1; + + Status = AcpiDsCreateOperands ( + WalkState, Op->Common.Value.Arg); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiExCreateMethod ( + Op->Named.Data, Op->Named.Length, WalkState); + } + + WalkState->Operands[0] = NULL; + WalkState->NumOperands = 0; + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + break; + +#endif /* ACPI_NO_METHOD_EXECUTION */ + + default: + + /* All NAMED_COMPLEX opcodes must be handled above */ + break; + } + break; + + case AML_CLASS_INTERNAL: + + /* case AML_INT_NAMEPATH_OP: */ + break; + + case AML_CLASS_METHOD_CALL: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n", + WalkState, Op, Node)); + + /* + * Lookup the method name and save the Node + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Arg->Common.Value.String, + ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS2, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + WalkState, &(NewNode)); + if (ACPI_SUCCESS (Status)) + { + /* + * Make sure that what we found is indeed a method + * We didn't search for a method on purpose, to see if the name + * would resolve + */ + if (NewNode->Type != ACPI_TYPE_METHOD) + { + Status = AE_AML_OPERAND_TYPE; + } + + /* We could put the returned object (Node) on the object stack for + * later, but for now, we will put it in the "op" object that the + * parser uses, so we can get it again at the end of this scope + */ + Op->Common.Node = NewNode; + } + else + { + ACPI_ERROR_NAMESPACE (Arg->Common.Value.String, Status); + } + break; + + + default: + + break; + } + +Cleanup: + + /* Remove the Node pushed at the very beginning */ + + WalkState->Operands[0] = NULL; + WalkState->NumOperands = 0; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dswscope.c b/third_party/lib/acpica/source/components/dispatcher/dswscope.c new file mode 100644 index 000000000..a2497cfa3 --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dswscope.c @@ -0,0 +1,236 @@ +/****************************************************************************** + * + * Module Name: dswscope - Scope stack manipulation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswscope") + + +/**************************************************************************** + * + * FUNCTION: AcpiDsScopeStackClear + * + * PARAMETERS: WalkState - Current state + * + * RETURN: None + * + * DESCRIPTION: Pop (and free) everything on the scope stack except the + * root scope object (which remains at the stack top.) + * + ***************************************************************************/ + +void +AcpiDsScopeStackClear ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *ScopeInfo; + + ACPI_FUNCTION_NAME (DsScopeStackClear); + + + while (WalkState->ScopeInfo) + { + /* Pop a scope off the stack */ + + ScopeInfo = WalkState->ScopeInfo; + WalkState->ScopeInfo = ScopeInfo->Scope.Next; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Popped object type (%s)\n", + AcpiUtGetTypeName (ScopeInfo->Common.Value))); + + AcpiUtDeleteGenericState (ScopeInfo); + } +} + + +/**************************************************************************** + * + * FUNCTION: AcpiDsScopeStackPush + * + * PARAMETERS: Node - Name to be made current + * Type - Type of frame being pushed + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Push the current scope on the scope stack, and make the + * passed Node current. + * + ***************************************************************************/ + +ACPI_STATUS +AcpiDsScopeStackPush ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *ScopeInfo; + ACPI_GENERIC_STATE *OldScopeInfo; + + + ACPI_FUNCTION_TRACE (DsScopeStackPush); + + + if (!Node) + { + /* Invalid scope */ + + ACPI_ERROR ((AE_INFO, "Null scope parameter")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Make sure object type is valid */ + + if (!AcpiUtValidObjectType (Type)) + { + ACPI_WARNING ((AE_INFO, + "Invalid object type: 0x%X", Type)); + } + + /* Allocate a new scope object */ + + ScopeInfo = AcpiUtCreateGenericState (); + if (!ScopeInfo) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Init new scope object */ + + ScopeInfo->Common.DescriptorType = ACPI_DESC_TYPE_STATE_WSCOPE; + ScopeInfo->Scope.Node = Node; + ScopeInfo->Common.Value = (UINT16) Type; + + WalkState->ScopeDepth++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[%.2d] Pushed scope ", (UINT32) WalkState->ScopeDepth)); + + OldScopeInfo = WalkState->ScopeInfo; + if (OldScopeInfo) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[%4.4s] (%s)", + AcpiUtGetNodeName (OldScopeInfo->Scope.Node), + AcpiUtGetTypeName (OldScopeInfo->Common.Value))); + } + else + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[\\___] (%s)", "ROOT")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + ", New scope -> [%4.4s] (%s)\n", + AcpiUtGetNodeName (ScopeInfo->Scope.Node), + AcpiUtGetTypeName (ScopeInfo->Common.Value))); + + /* Push new scope object onto stack */ + + AcpiUtPushGenericState (&WalkState->ScopeInfo, ScopeInfo); + return_ACPI_STATUS (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: AcpiDsScopeStackPop + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Pop the scope stack once. + * + ***************************************************************************/ + +ACPI_STATUS +AcpiDsScopeStackPop ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *ScopeInfo; + ACPI_GENERIC_STATE *NewScopeInfo; + + + ACPI_FUNCTION_TRACE (DsScopeStackPop); + + + /* + * Pop scope info object off the stack. + */ + ScopeInfo = AcpiUtPopGenericState (&WalkState->ScopeInfo); + if (!ScopeInfo) + { + return_ACPI_STATUS (AE_STACK_UNDERFLOW); + } + + WalkState->ScopeDepth--; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[%.2d] Popped scope [%4.4s] (%s), New scope -> ", + (UINT32) WalkState->ScopeDepth, + AcpiUtGetNodeName (ScopeInfo->Scope.Node), + AcpiUtGetTypeName (ScopeInfo->Common.Value))); + + NewScopeInfo = WalkState->ScopeInfo; + if (NewScopeInfo) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[%4.4s] (%s)\n", + AcpiUtGetNodeName (NewScopeInfo->Scope.Node), + AcpiUtGetTypeName (NewScopeInfo->Common.Value))); + } + else + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[\\___] (ROOT)\n")); + } + + AcpiUtDeleteGenericState (ScopeInfo); + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/dispatcher/dswstate.c b/third_party/lib/acpica/source/components/dispatcher/dswstate.c new file mode 100644 index 000000000..f56f393aa --- /dev/null +++ b/third_party/lib/acpica/source/components/dispatcher/dswstate.c @@ -0,0 +1,842 @@ +/****************************************************************************** + * + * Module Name: dswstate - Dispatcher parse tree walk management routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswstate") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsResultStackPush ( + ACPI_WALK_STATE *WalkState); + +static ACPI_STATUS +AcpiDsResultStackPop ( + ACPI_WALK_STATE *WalkState); + + +/******************************************************************************* + * + * FUNCTION: AcpiDsResultPop + * + * PARAMETERS: Object - Where to return the popped object + * WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop an object off the top of this walk's result stack + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsResultPop ( + ACPI_OPERAND_OBJECT **Object, + ACPI_WALK_STATE *WalkState) +{ + UINT32 Index; + ACPI_GENERIC_STATE *State; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (DsResultPop); + + + State = WalkState->Results; + + /* Incorrect state of result stack */ + + if (State && !WalkState->ResultCount) + { + ACPI_ERROR ((AE_INFO, "No results on result stack")); + return (AE_AML_INTERNAL); + } + + if (!State && WalkState->ResultCount) + { + ACPI_ERROR ((AE_INFO, "No result state for result stack")); + return (AE_AML_INTERNAL); + } + + /* Empty result stack */ + + if (!State) + { + ACPI_ERROR ((AE_INFO, "Result stack is empty! State=%p", WalkState)); + return (AE_AML_NO_RETURN_VALUE); + } + + /* Return object of the top element and clean that top element result stack */ + + WalkState->ResultCount--; + Index = (UINT32) WalkState->ResultCount % ACPI_RESULTS_FRAME_OBJ_NUM; + + *Object = State->Results.ObjDesc [Index]; + if (!*Object) + { + ACPI_ERROR ((AE_INFO, "No result objects on result stack, State=%p", + WalkState)); + return (AE_AML_NO_RETURN_VALUE); + } + + State->Results.ObjDesc [Index] = NULL; + if (Index == 0) + { + Status = AcpiDsResultStackPop (WalkState); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] Index=%X State=%p Num=%X\n", *Object, + AcpiUtGetObjectTypeName (*Object), + Index, WalkState, WalkState->ResultCount)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsResultPush + * + * PARAMETERS: Object - Where to return the popped object + * WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Push an object onto the current result stack + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsResultPush ( + ACPI_OPERAND_OBJECT *Object, + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *State; + ACPI_STATUS Status; + UINT32 Index; + + + ACPI_FUNCTION_NAME (DsResultPush); + + + if (WalkState->ResultCount > WalkState->ResultSize) + { + ACPI_ERROR ((AE_INFO, "Result stack is full")); + return (AE_AML_INTERNAL); + } + else if (WalkState->ResultCount == WalkState->ResultSize) + { + /* Extend the result stack */ + + Status = AcpiDsResultStackPush (WalkState); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "Failed to extend the result stack")); + return (Status); + } + } + + if (!(WalkState->ResultCount < WalkState->ResultSize)) + { + ACPI_ERROR ((AE_INFO, "No free elements in result stack")); + return (AE_AML_INTERNAL); + } + + State = WalkState->Results; + if (!State) + { + ACPI_ERROR ((AE_INFO, "No result stack frame during push")); + return (AE_AML_INTERNAL); + } + + if (!Object) + { + ACPI_ERROR ((AE_INFO, + "Null Object! Obj=%p State=%p Num=%u", + Object, WalkState, WalkState->ResultCount)); + return (AE_BAD_PARAMETER); + } + + /* Assign the address of object to the top free element of result stack */ + + Index = (UINT32) WalkState->ResultCount % ACPI_RESULTS_FRAME_OBJ_NUM; + State->Results.ObjDesc [Index] = Object; + WalkState->ResultCount++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n", + Object, AcpiUtGetObjectTypeName ((ACPI_OPERAND_OBJECT *) Object), + WalkState, WalkState->ResultCount, WalkState->CurrentResult)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsResultStackPush + * + * PARAMETERS: WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Push an object onto the WalkState result stack + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsResultStackPush ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_NAME (DsResultStackPush); + + + /* Check for stack overflow */ + + if (((UINT32) WalkState->ResultSize + ACPI_RESULTS_FRAME_OBJ_NUM) > + ACPI_RESULTS_OBJ_NUM_MAX) + { + ACPI_ERROR ((AE_INFO, "Result stack overflow: State=%p Num=%u", + WalkState, WalkState->ResultSize)); + return (AE_STACK_OVERFLOW); + } + + State = AcpiUtCreateGenericState (); + if (!State) + { + return (AE_NO_MEMORY); + } + + State->Common.DescriptorType = ACPI_DESC_TYPE_STATE_RESULT; + AcpiUtPushGenericState (&WalkState->Results, State); + + /* Increase the length of the result stack by the length of frame */ + + WalkState->ResultSize += ACPI_RESULTS_FRAME_OBJ_NUM; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Results=%p State=%p\n", + State, WalkState)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsResultStackPop + * + * PARAMETERS: WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop an object off of the WalkState result stack + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiDsResultStackPop ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_NAME (DsResultStackPop); + + + /* Check for stack underflow */ + + if (WalkState->Results == NULL) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Result stack underflow - State=%p\n", WalkState)); + return (AE_AML_NO_OPERAND); + } + + if (WalkState->ResultSize < ACPI_RESULTS_FRAME_OBJ_NUM) + { + ACPI_ERROR ((AE_INFO, "Insufficient result stack size")); + return (AE_AML_INTERNAL); + } + + State = AcpiUtPopGenericState (&WalkState->Results); + AcpiUtDeleteGenericState (State); + + /* Decrease the length of result stack by the length of frame */ + + WalkState->ResultSize -= ACPI_RESULTS_FRAME_OBJ_NUM; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Result=%p RemainingResults=%X State=%p\n", + State, WalkState->ResultCount, WalkState)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsObjStackPush + * + * PARAMETERS: Object - Object to push + * WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Push an object onto this walk's object/operand stack + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsObjStackPush ( + void *Object, + ACPI_WALK_STATE *WalkState) +{ + ACPI_FUNCTION_NAME (DsObjStackPush); + + + /* Check for stack overflow */ + + if (WalkState->NumOperands >= ACPI_OBJ_NUM_OPERANDS) + { + ACPI_ERROR ((AE_INFO, + "Object stack overflow! Obj=%p State=%p #Ops=%u", + Object, WalkState, WalkState->NumOperands)); + return (AE_STACK_OVERFLOW); + } + + /* Put the object onto the stack */ + + WalkState->Operands [WalkState->OperandIndex] = Object; + WalkState->NumOperands++; + + /* For the usual order of filling the operand stack */ + + WalkState->OperandIndex++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", + Object, AcpiUtGetObjectTypeName ((ACPI_OPERAND_OBJECT *) Object), + WalkState, WalkState->NumOperands)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsObjStackPop + * + * PARAMETERS: PopCount - Number of objects/entries to pop + * WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * deleted by this routine. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsObjStackPop ( + UINT32 PopCount, + ACPI_WALK_STATE *WalkState) +{ + UINT32 i; + + + ACPI_FUNCTION_NAME (DsObjStackPop); + + + for (i = 0; i < PopCount; i++) + { + /* Check for stack underflow */ + + if (WalkState->NumOperands == 0) + { + ACPI_ERROR ((AE_INFO, + "Object stack underflow! Count=%X State=%p #Ops=%u", + PopCount, WalkState, WalkState->NumOperands)); + return (AE_STACK_UNDERFLOW); + } + + /* Just set the stack entry to null */ + + WalkState->NumOperands--; + WalkState->Operands [WalkState->NumOperands] = NULL; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%u\n", + PopCount, WalkState, WalkState->NumOperands)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsObjStackPopAndDelete + * + * PARAMETERS: PopCount - Number of objects/entries to pop + * WalkState - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack and delete each object that is + * popped off. + * + ******************************************************************************/ + +void +AcpiDsObjStackPopAndDelete ( + UINT32 PopCount, + ACPI_WALK_STATE *WalkState) +{ + INT32 i; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_NAME (DsObjStackPopAndDelete); + + + if (PopCount == 0) + { + return; + } + + for (i = (INT32) PopCount - 1; i >= 0; i--) + { + if (WalkState->NumOperands == 0) + { + return; + } + + /* Pop the stack and delete an object if present in this stack entry */ + + WalkState->NumOperands--; + ObjDesc = WalkState->Operands [i]; + if (ObjDesc) + { + AcpiUtRemoveReference (WalkState->Operands [i]); + WalkState->Operands [i] = NULL; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", + PopCount, WalkState, WalkState->NumOperands)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsGetCurrentWalkState + * + * PARAMETERS: Thread - Get current active state for this Thread + * + * RETURN: Pointer to the current walk state + * + * DESCRIPTION: Get the walk state that is at the head of the list (the "current" + * walk state.) + * + ******************************************************************************/ + +ACPI_WALK_STATE * +AcpiDsGetCurrentWalkState ( + ACPI_THREAD_STATE *Thread) +{ + ACPI_FUNCTION_NAME (DsGetCurrentWalkState); + + + if (!Thread) + { + return (NULL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Current WalkState %p\n", + Thread->WalkStateList)); + + return (Thread->WalkStateList); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsPushWalkState + * + * PARAMETERS: WalkState - State to push + * Thread - Thread state object + * + * RETURN: None + * + * DESCRIPTION: Place the Thread state at the head of the state list + * + ******************************************************************************/ + +void +AcpiDsPushWalkState ( + ACPI_WALK_STATE *WalkState, + ACPI_THREAD_STATE *Thread) +{ + ACPI_FUNCTION_TRACE (DsPushWalkState); + + + WalkState->Next = Thread->WalkStateList; + Thread->WalkStateList = WalkState; + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsPopWalkState + * + * PARAMETERS: Thread - Current thread state + * + * RETURN: A WalkState object popped from the thread's stack + * + * DESCRIPTION: Remove and return the walkstate object that is at the head of + * the walk stack for the given walk list. NULL indicates that + * the list is empty. + * + ******************************************************************************/ + +ACPI_WALK_STATE * +AcpiDsPopWalkState ( + ACPI_THREAD_STATE *Thread) +{ + ACPI_WALK_STATE *WalkState; + + + ACPI_FUNCTION_TRACE (DsPopWalkState); + + + WalkState = Thread->WalkStateList; + + if (WalkState) + { + /* Next walk state becomes the current walk state */ + + Thread->WalkStateList = WalkState->Next; + + /* + * Don't clear the NEXT field, this serves as an indicator + * that there is a parent WALK STATE + * Do Not: WalkState->Next = NULL; + */ + } + + return_PTR (WalkState); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateWalkState + * + * PARAMETERS: OwnerId - ID for object creation + * Origin - Starting point for this walk + * MethodDesc - Method object + * Thread - Current thread state + * + * RETURN: Pointer to the new walk state. + * + * DESCRIPTION: Allocate and initialize a new walk state. The current walk + * state is set to this new state. + * + ******************************************************************************/ + +ACPI_WALK_STATE * +AcpiDsCreateWalkState ( + ACPI_OWNER_ID OwnerId, + ACPI_PARSE_OBJECT *Origin, + ACPI_OPERAND_OBJECT *MethodDesc, + ACPI_THREAD_STATE *Thread) +{ + ACPI_WALK_STATE *WalkState; + + + ACPI_FUNCTION_TRACE (DsCreateWalkState); + + + WalkState = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_WALK_STATE)); + if (!WalkState) + { + return_PTR (NULL); + } + + WalkState->DescriptorType = ACPI_DESC_TYPE_WALK; + WalkState->MethodDesc = MethodDesc; + WalkState->OwnerId = OwnerId; + WalkState->Origin = Origin; + WalkState->Thread = Thread; + + WalkState->ParserState.StartOp = Origin; + + /* Init the method args/local */ + +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + AcpiDsMethodDataInit (WalkState); +#endif + + /* Put the new state at the head of the walk list */ + + if (Thread) + { + AcpiDsPushWalkState (WalkState, Thread); + } + + return_PTR (WalkState); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsInitAmlWalk + * + * PARAMETERS: WalkState - New state to be initialized + * Op - Current parse op + * MethodNode - Control method NS node, if any + * AmlStart - Start of AML + * AmlLength - Length of AML + * Info - Method info block (params, etc.) + * PassNumber - 1, 2, or 3 + * + * RETURN: Status + * + * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDsInitAmlWalk ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *MethodNode, + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_EVALUATE_INFO *Info, + UINT8 PassNumber) +{ + ACPI_STATUS Status; + ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; + ACPI_PARSE_OBJECT *ExtraOp; + + + ACPI_FUNCTION_TRACE (DsInitAmlWalk); + + + WalkState->ParserState.Aml = + WalkState->ParserState.AmlStart = AmlStart; + WalkState->ParserState.AmlEnd = + WalkState->ParserState.PkgEnd = AmlStart + AmlLength; + + /* The NextOp of the NextWalk will be the beginning of the method */ + + WalkState->NextOp = NULL; + WalkState->PassNumber = PassNumber; + + if (Info) + { + WalkState->Params = Info->Parameters; + WalkState->CallerReturnDesc = &Info->ReturnObject; + } + + Status = AcpiPsInitScope (&WalkState->ParserState, Op); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (MethodNode) + { + WalkState->ParserState.StartNode = MethodNode; + WalkState->WalkType = ACPI_WALK_METHOD; + WalkState->MethodNode = MethodNode; + WalkState->MethodDesc = AcpiNsGetAttachedObject (MethodNode); + + /* Push start scope on scope stack and make it current */ + + Status = AcpiDsScopeStackPush ( + MethodNode, ACPI_TYPE_METHOD, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Init the method arguments */ + + Status = AcpiDsMethodDataInitArgs (WalkState->Params, + ACPI_METHOD_NUM_ARGS, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + else + { + /* + * Setup the current scope. + * Find a Named Op that has a namespace node associated with it. + * search upwards from this Op. Current scope is the first + * Op with a namespace node. + */ + ExtraOp = ParserState->StartOp; + while (ExtraOp && !ExtraOp->Common.Node) + { + ExtraOp = ExtraOp->Common.Parent; + } + + if (!ExtraOp) + { + ParserState->StartNode = NULL; + } + else + { + ParserState->StartNode = ExtraOp->Common.Node; + } + + if (ParserState->StartNode) + { + /* Push start scope on scope stack and make it current */ + + Status = AcpiDsScopeStackPush (ParserState->StartNode, + ParserState->StartNode->Type, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + + Status = AcpiDsInitCallbacks (WalkState, PassNumber); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDsDeleteWalkState + * + * PARAMETERS: WalkState - State to delete + * + * RETURN: Status + * + * DESCRIPTION: Delete a walk state including all internal data structures + * + ******************************************************************************/ + +void +AcpiDsDeleteWalkState ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_TRACE_PTR (DsDeleteWalkState, WalkState); + + + if (!WalkState) + { + return_VOID; + } + + if (WalkState->DescriptorType != ACPI_DESC_TYPE_WALK) + { + ACPI_ERROR ((AE_INFO, "%p is not a valid walk state", + WalkState)); + return_VOID; + } + + /* There should not be any open scopes */ + + if (WalkState->ParserState.Scope) + { + ACPI_ERROR ((AE_INFO, "%p walk still has a scope list", + WalkState)); + AcpiPsCleanupScope (&WalkState->ParserState); + } + + /* Always must free any linked control states */ + + while (WalkState->ControlState) + { + State = WalkState->ControlState; + WalkState->ControlState = State->Common.Next; + + AcpiUtDeleteGenericState (State); + } + + /* Always must free any linked parse states */ + + while (WalkState->ScopeInfo) + { + State = WalkState->ScopeInfo; + WalkState->ScopeInfo = State->Common.Next; + + AcpiUtDeleteGenericState (State); + } + + /* Always must free any stacked result states */ + + while (WalkState->Results) + { + State = WalkState->Results; + WalkState->Results = State->Common.Next; + + AcpiUtDeleteGenericState (State); + } + + ACPI_FREE (WalkState); + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/events/evevent.c b/third_party/lib/acpica/source/components/events/evevent.c new file mode 100644 index 000000000..98b3da506 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evevent.c @@ -0,0 +1,336 @@ +/****************************************************************************** + * + * Module Name: evevent - Fixed Event handling and dispatch + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evevent") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static ACPI_STATUS +AcpiEvFixedEventInitialize ( + void); + +static UINT32 +AcpiEvFixedEventDispatch ( + UINT32 Event); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInitializeEvents + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInitializeEvents ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvInitializeEvents); + + + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (AcpiGbl_ReducedHardware) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * Initialize the Fixed and General Purpose Events. This is done prior to + * enabling SCIs to prevent interrupts from occurring before the handlers + * are installed. + */ + Status = AcpiEvFixedEventInitialize (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to initialize fixed events")); + return_ACPI_STATUS (Status); + } + + Status = AcpiEvGpeInitialize (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to initialize general purpose events")); + return_ACPI_STATUS (Status); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInstallXruptHandlers + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install interrupt handlers for the SCI and Global Lock + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInstallXruptHandlers ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvInstallXruptHandlers); + + + /* If Hardware Reduced flag is set, there is no ACPI h/w */ + + if (AcpiGbl_ReducedHardware) + { + return_ACPI_STATUS (AE_OK); + } + + /* Install the SCI handler */ + + Status = AcpiEvInstallSciHandler (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to install System Control Interrupt handler")); + return_ACPI_STATUS (Status); + } + + /* Install the handler for the Global Lock */ + + Status = AcpiEvInitGlobalLockHandler (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to initialize Global Lock handler")); + return_ACPI_STATUS (Status); + } + + AcpiGbl_EventsInitialized = TRUE; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvFixedEventInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install the fixed event handlers and disable all fixed events. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvFixedEventInitialize ( + void) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* + * Initialize the structure that keeps track of fixed event handlers and + * enable the fixed events. + */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) + { + AcpiGbl_FixedEventHandlers[i].Handler = NULL; + AcpiGbl_FixedEventHandlers[i].Context = NULL; + + /* Disable the fixed event */ + + if (AcpiGbl_FixedEventInfo[i].EnableRegisterId != 0xFF) + { + Status = AcpiWriteBitRegister ( + AcpiGbl_FixedEventInfo[i].EnableRegisterId, + ACPI_DISABLE_EVENT); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvFixedEventDetect + * + * PARAMETERS: None + * + * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED + * + * DESCRIPTION: Checks the PM status register for active fixed events + * + ******************************************************************************/ + +UINT32 +AcpiEvFixedEventDetect ( + void) +{ + UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; + UINT32 FixedStatus; + UINT32 FixedEnable; + UINT32 i; + + + ACPI_FUNCTION_NAME (EvFixedEventDetect); + + + /* + * Read the fixed feature status and enable registers, as all the cases + * depend on their values. Ignore errors here. + */ + (void) AcpiHwRegisterRead (ACPI_REGISTER_PM1_STATUS, &FixedStatus); + (void) AcpiHwRegisterRead (ACPI_REGISTER_PM1_ENABLE, &FixedEnable); + + ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, + "Fixed Event Block: Enable %08X Status %08X\n", + FixedEnable, FixedStatus)); + + /* + * Check for all possible Fixed Events and dispatch those that are active + */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) + { + /* Both the status and enable bits must be on for this event */ + + if ((FixedStatus & AcpiGbl_FixedEventInfo[i].StatusBitMask) && + (FixedEnable & AcpiGbl_FixedEventInfo[i].EnableBitMask)) + { + /* + * Found an active (signalled) event. Invoke global event + * handler if present. + */ + AcpiFixedEventCount[i]++; + if (AcpiGbl_GlobalEventHandler) + { + AcpiGbl_GlobalEventHandler (ACPI_EVENT_TYPE_FIXED, NULL, + i, AcpiGbl_GlobalEventHandlerContext); + } + + IntStatus |= AcpiEvFixedEventDispatch (i); + } + } + + return (IntStatus); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvFixedEventDispatch + * + * PARAMETERS: Event - Event type + * + * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED + * + * DESCRIPTION: Clears the status bit for the requested event, calls the + * handler that previously registered for the event. + * NOTE: If there is no handler for the event, the event is + * disabled to prevent further interrupts. + * + ******************************************************************************/ + +static UINT32 +AcpiEvFixedEventDispatch ( + UINT32 Event) +{ + + ACPI_FUNCTION_ENTRY (); + + + /* Clear the status bit */ + + (void) AcpiWriteBitRegister ( + AcpiGbl_FixedEventInfo[Event].StatusRegisterId, + ACPI_CLEAR_STATUS); + + /* + * Make sure that a handler exists. If not, report an error + * and disable the event to prevent further interrupts. + */ + if (!AcpiGbl_FixedEventHandlers[Event].Handler) + { + (void) AcpiWriteBitRegister ( + AcpiGbl_FixedEventInfo[Event].EnableRegisterId, + ACPI_DISABLE_EVENT); + + ACPI_ERROR ((AE_INFO, + "No installed handler for fixed event - %s (%u), disabling", + AcpiUtGetEventName (Event), Event)); + + return (ACPI_INTERRUPT_NOT_HANDLED); + } + + /* Invoke the Fixed Event handler */ + + return ((AcpiGbl_FixedEventHandlers[Event].Handler)( + AcpiGbl_FixedEventHandlers[Event].Context)); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evglock.c b/third_party/lib/acpica/source/components/events/evglock.c new file mode 100644 index 000000000..caafa977b --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evglock.c @@ -0,0 +1,379 @@ +/****************************************************************************** + * + * Module Name: evglock - Global Lock support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evglock") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static UINT32 +AcpiEvGlobalLockHandler ( + void *Context); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInitGlobalLockHandler + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for the global lock release event + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInitGlobalLockHandler ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvInitGlobalLockHandler); + + + /* If Hardware Reduced flag is set, there is no global lock */ + + if (AcpiGbl_ReducedHardware) + { + return_ACPI_STATUS (AE_OK); + } + + /* Attempt installation of the global lock handler */ + + Status = AcpiInstallFixedEventHandler (ACPI_EVENT_GLOBAL, + AcpiEvGlobalLockHandler, NULL); + + /* + * If the global lock does not exist on this platform, the attempt to + * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick). + * Map to AE_OK, but mark global lock as not present. Any attempt to + * actually use the global lock will be flagged with an error. + */ + AcpiGbl_GlobalLockPresent = FALSE; + if (Status == AE_NO_HARDWARE_RESPONSE) + { + ACPI_ERROR ((AE_INFO, + "No response from Global Lock hardware, disabling lock")); + + return_ACPI_STATUS (AE_OK); + } + + Status = AcpiOsCreateLock (&AcpiGbl_GlobalLockPendingLock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiGbl_GlobalLockPending = FALSE; + AcpiGbl_GlobalLockPresent = TRUE; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvRemoveGlobalLockHandler + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Remove the handler for the Global Lock + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvRemoveGlobalLockHandler ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvRemoveGlobalLockHandler); + + + AcpiGbl_GlobalLockPresent = FALSE; + Status = AcpiRemoveFixedEventHandler (ACPI_EVENT_GLOBAL, + AcpiEvGlobalLockHandler); + + AcpiOsDeleteLock (AcpiGbl_GlobalLockPendingLock); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGlobalLockHandler + * + * PARAMETERS: Context - From thread interface, not used + * + * RETURN: ACPI_INTERRUPT_HANDLED + * + * DESCRIPTION: Invoked directly from the SCI handler when a global lock + * release interrupt occurs. If there is actually a pending + * request for the lock, signal the waiting thread. + * + ******************************************************************************/ + +static UINT32 +AcpiEvGlobalLockHandler ( + void *Context) +{ + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + Flags = AcpiOsAcquireLock (AcpiGbl_GlobalLockPendingLock); + + /* + * If a request for the global lock is not actually pending, + * we are done. This handles "spurious" global lock interrupts + * which are possible (and have been seen) with bad BIOSs. + */ + if (!AcpiGbl_GlobalLockPending) + { + goto CleanupAndExit; + } + + /* + * Send a unit to the global lock semaphore. The actual acquisition + * of the global lock will be performed by the waiting thread. + */ + Status = AcpiOsSignalSemaphore (AcpiGbl_GlobalLockSemaphore, 1); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "Could not signal Global Lock semaphore")); + } + + AcpiGbl_GlobalLockPending = FALSE; + + +CleanupAndExit: + + AcpiOsReleaseLock (AcpiGbl_GlobalLockPendingLock, Flags); + return (ACPI_INTERRUPT_HANDLED); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiEvAcquireGlobalLock + * + * PARAMETERS: Timeout - Max time to wait for the lock, in millisec. + * + * RETURN: Status + * + * DESCRIPTION: Attempt to gain ownership of the Global Lock. + * + * MUTEX: Interpreter must be locked + * + * Note: The original implementation allowed multiple threads to "acquire" the + * Global Lock, and the OS would hold the lock until the last thread had + * released it. However, this could potentially starve the BIOS out of the + * lock, especially in the case where there is a tight handshake between the + * Embedded Controller driver and the BIOS. Therefore, this implementation + * allows only one thread to acquire the HW Global Lock at a time, and makes + * the global lock appear as a standard mutex on the OS side. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiEvAcquireGlobalLock ( + UINT16 Timeout) +{ + ACPI_CPU_FLAGS Flags; + ACPI_STATUS Status; + BOOLEAN Acquired = FALSE; + + + ACPI_FUNCTION_TRACE (EvAcquireGlobalLock); + + + /* + * Only one thread can acquire the GL at a time, the GlobalLockMutex + * enforces this. This interface releases the interpreter if we must wait. + */ + Status = AcpiExSystemWaitMutex (AcpiGbl_GlobalLockMutex->Mutex.OsMutex, + Timeout); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Update the global lock handle and check for wraparound. The handle is + * only used for the external global lock interfaces, but it is updated + * here to properly handle the case where a single thread may acquire the + * lock via both the AML and the AcpiAcquireGlobalLock interfaces. The + * handle is therefore updated on the first acquire from a given thread + * regardless of where the acquisition request originated. + */ + AcpiGbl_GlobalLockHandle++; + if (AcpiGbl_GlobalLockHandle == 0) + { + AcpiGbl_GlobalLockHandle = 1; + } + + /* + * Make sure that a global lock actually exists. If not, just + * treat the lock as a standard mutex. + */ + if (!AcpiGbl_GlobalLockPresent) + { + AcpiGbl_GlobalLockAcquired = TRUE; + return_ACPI_STATUS (AE_OK); + } + + Flags = AcpiOsAcquireLock (AcpiGbl_GlobalLockPendingLock); + + do + { + /* Attempt to acquire the actual hardware lock */ + + ACPI_ACQUIRE_GLOBAL_LOCK (AcpiGbl_FACS, Acquired); + if (Acquired) + { + AcpiGbl_GlobalLockAcquired = TRUE; + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Acquired hardware Global Lock\n")); + break; + } + + /* + * Did not get the lock. The pending bit was set above, and + * we must now wait until we receive the global lock + * released interrupt. + */ + AcpiGbl_GlobalLockPending = TRUE; + AcpiOsReleaseLock (AcpiGbl_GlobalLockPendingLock, Flags); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Waiting for hardware Global Lock\n")); + + /* + * Wait for handshake with the global lock interrupt handler. + * This interface releases the interpreter if we must wait. + */ + Status = AcpiExSystemWaitSemaphore ( + AcpiGbl_GlobalLockSemaphore, ACPI_WAIT_FOREVER); + + Flags = AcpiOsAcquireLock (AcpiGbl_GlobalLockPendingLock); + + } while (ACPI_SUCCESS (Status)); + + AcpiGbl_GlobalLockPending = FALSE; + AcpiOsReleaseLock (AcpiGbl_GlobalLockPendingLock, Flags); + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvReleaseGlobalLock + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Releases ownership of the Global Lock. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvReleaseGlobalLock ( + void) +{ + BOOLEAN Pending = FALSE; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (EvReleaseGlobalLock); + + + /* Lock must be already acquired */ + + if (!AcpiGbl_GlobalLockAcquired) + { + ACPI_WARNING ((AE_INFO, + "Cannot release the ACPI Global Lock, it has not been acquired")); + return_ACPI_STATUS (AE_NOT_ACQUIRED); + } + + if (AcpiGbl_GlobalLockPresent) + { + /* Allow any thread to release the lock */ + + ACPI_RELEASE_GLOBAL_LOCK (AcpiGbl_FACS, Pending); + + /* + * If the pending bit was set, we must write GBL_RLS to the control + * register + */ + if (Pending) + { + Status = AcpiWriteBitRegister ( + ACPI_BITREG_GLOBAL_LOCK_RELEASE, ACPI_ENABLE_EVENT); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Released hardware Global Lock\n")); + } + + AcpiGbl_GlobalLockAcquired = FALSE; + + /* Release the local GL mutex */ + + AcpiOsReleaseMutex (AcpiGbl_GlobalLockMutex->Mutex.OsMutex); + return_ACPI_STATUS (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evgpe.c b/third_party/lib/acpica/source/components/events/evgpe.c new file mode 100644 index 000000000..d683bfdfa --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evgpe.c @@ -0,0 +1,843 @@ +/****************************************************************************** + * + * Module Name: evgpe - General Purpose Event handling and dispatch + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evgpe") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +AcpiEvAsynchExecuteGpeMethod ( + void *Context); + +static void ACPI_SYSTEM_XFACE +AcpiEvAsynchEnableGpe ( + void *Context); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvUpdateGpeEnableMask + * + * PARAMETERS: GpeEventInfo - GPE to update + * + * RETURN: Status + * + * DESCRIPTION: Updates GPE register enable mask based upon whether there are + * runtime references to this GPE + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvUpdateGpeEnableMask ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + UINT32 RegisterBit; + + + ACPI_FUNCTION_TRACE (EvUpdateGpeEnableMask); + + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + if (!GpeRegisterInfo) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); + + /* Clear the run bit up front */ + + ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit); + + /* Set the mask bit only if there are references to this GPE */ + + if (GpeEventInfo->RuntimeCount) + { + ACPI_SET_BIT (GpeRegisterInfo->EnableForRun, (UINT8) RegisterBit); + } + + GpeRegisterInfo->EnableMask = GpeRegisterInfo->EnableForRun; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvEnableGpe + * + * PARAMETERS: GpeEventInfo - GPE to enable + * + * RETURN: Status + * + * DESCRIPTION: Clear a GPE of stale events and enable it. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvEnableGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvEnableGpe); + + + /* Clear the GPE (of stale events) */ + + Status = AcpiHwClearGpe (GpeEventInfo); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Enable the requested GPE */ + + Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvAddGpeReference + * + * PARAMETERS: GpeEventInfo - Add a reference to this GPE + * + * RETURN: Status + * + * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is + * hardware-enabled. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvAddGpeReference ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (EvAddGpeReference); + + + if (GpeEventInfo->RuntimeCount == ACPI_UINT8_MAX) + { + return_ACPI_STATUS (AE_LIMIT); + } + + GpeEventInfo->RuntimeCount++; + if (GpeEventInfo->RuntimeCount == 1) + { + /* Enable on first reference */ + + Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiEvEnableGpe (GpeEventInfo); + } + + if (ACPI_FAILURE (Status)) + { + GpeEventInfo->RuntimeCount--; + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvRemoveGpeReference + * + * PARAMETERS: GpeEventInfo - Remove a reference to this GPE + * + * RETURN: Status + * + * DESCRIPTION: Remove a reference to a GPE. When the last reference is + * removed, the GPE is hardware-disabled. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvRemoveGpeReference ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (EvRemoveGpeReference); + + + if (!GpeEventInfo->RuntimeCount) + { + return_ACPI_STATUS (AE_LIMIT); + } + + GpeEventInfo->RuntimeCount--; + if (!GpeEventInfo->RuntimeCount) + { + /* Disable on last reference */ + + Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); + } + + if (ACPI_FAILURE (Status)) + { + GpeEventInfo->RuntimeCount++; + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvLowGetGpeInfo + * + * PARAMETERS: GpeNumber - Raw GPE number + * GpeBlock - A GPE info block + * + * RETURN: A GPE EventInfo struct. NULL if not a valid GPE (The GpeNumber + * is not within the specified GPE block) + * + * DESCRIPTION: Returns the EventInfo struct associated with this GPE. This is + * the low-level implementation of EvGetGpeEventInfo. + * + ******************************************************************************/ + +ACPI_GPE_EVENT_INFO * +AcpiEvLowGetGpeInfo ( + UINT32 GpeNumber, + ACPI_GPE_BLOCK_INFO *GpeBlock) +{ + UINT32 GpeIndex; + + + /* + * Validate that the GpeNumber is within the specified GpeBlock. + * (Two steps) + */ + if (!GpeBlock || + (GpeNumber < GpeBlock->BlockBaseNumber)) + { + return (NULL); + } + + GpeIndex = GpeNumber - GpeBlock->BlockBaseNumber; + if (GpeIndex >= GpeBlock->GpeCount) + { + return (NULL); + } + + return (&GpeBlock->EventInfo[GpeIndex]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGetGpeEventInfo + * + * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 + * GpeNumber - Raw GPE number + * + * RETURN: A GPE EventInfo struct. NULL if not a valid GPE + * + * DESCRIPTION: Returns the EventInfo struct associated with this GPE. + * Validates the GpeBlock and the GpeNumber + * + * Should be called only when the GPE lists are semaphore locked + * and not subject to change. + * + ******************************************************************************/ + +ACPI_GPE_EVENT_INFO * +AcpiEvGetGpeEventInfo ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_GPE_EVENT_INFO *GpeInfo; + UINT32 i; + + + ACPI_FUNCTION_ENTRY (); + + + /* A NULL GpeDevice means use the FADT-defined GPE block(s) */ + + if (!GpeDevice) + { + /* Examine GPE Block 0 and 1 (These blocks are permanent) */ + + for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) + { + GpeInfo = AcpiEvLowGetGpeInfo (GpeNumber, + AcpiGbl_GpeFadtBlocks[i]); + if (GpeInfo) + { + return (GpeInfo); + } + } + + /* The GpeNumber was not in the range of either FADT GPE block */ + + return (NULL); + } + + /* A Non-NULL GpeDevice means this is a GPE Block Device */ + + ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice); + if (!ObjDesc || + !ObjDesc->Device.GpeBlock) + { + return (NULL); + } + + return (AcpiEvLowGetGpeInfo (GpeNumber, ObjDesc->Device.GpeBlock)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGpeDetect + * + * PARAMETERS: GpeXruptList - Interrupt block for this interrupt. + * Can have multiple GPE blocks attached. + * + * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED + * + * DESCRIPTION: Detect if any GP events have occurred. This function is + * executed at interrupt level. + * + ******************************************************************************/ + +UINT32 +AcpiEvGpeDetect ( + ACPI_GPE_XRUPT_INFO *GpeXruptList) +{ + ACPI_STATUS Status; + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_NAMESPACE_NODE *GpeDevice; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + UINT32 GpeNumber; + ACPI_GPE_HANDLER_INFO *GpeHandlerInfo; + UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; + UINT8 EnabledStatusByte; + UINT32 StatusReg; + UINT32 EnableReg; + ACPI_CPU_FLAGS Flags; + UINT32 i; + UINT32 j; + + + ACPI_FUNCTION_NAME (EvGpeDetect); + + /* Check for the case where there are no GPEs */ + + if (!GpeXruptList) + { + return (IntStatus); + } + + /* + * We need to obtain the GPE lock for both the data structs and registers + * Note: Not necessary to obtain the hardware lock, since the GPE + * registers are owned by the GpeLock. + */ + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Examine all GPE blocks attached to this interrupt level */ + + GpeBlock = GpeXruptList->GpeBlockListHead; + while (GpeBlock) + { + GpeDevice = GpeBlock->Node; + + /* + * Read all of the 8-bit GPE status and enable registers in this GPE + * block, saving all of them. Find all currently active GP events. + */ + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Get the next status/enable pair */ + + GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; + + /* + * Optimization: If there are no GPEs enabled within this + * register, we can safely ignore the entire register. + */ + if (!(GpeRegisterInfo->EnableForRun | + GpeRegisterInfo->EnableForWake)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, + "Ignore disabled registers for GPE %02X-%02X: " + "RunEnable=%02X, WakeEnable=%02X\n", + GpeRegisterInfo->BaseGpeNumber, + GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1), + GpeRegisterInfo->EnableForRun, + GpeRegisterInfo->EnableForWake)); + continue; + } + + /* Read the Status Register */ + + Status = AcpiHwRead (&StatusReg, &GpeRegisterInfo->StatusAddress); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Read the Enable Register */ + + Status = AcpiHwRead (&EnableReg, &GpeRegisterInfo->EnableAddress); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, + "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " + "RunEnable=%02X, WakeEnable=%02X\n", + GpeRegisterInfo->BaseGpeNumber, + GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1), + StatusReg, EnableReg, + GpeRegisterInfo->EnableForRun, + GpeRegisterInfo->EnableForWake)); + + /* Check if there is anything active at all in this register */ + + EnabledStatusByte = (UINT8) (StatusReg & EnableReg); + if (!EnabledStatusByte) + { + /* No active GPEs in this register, move on */ + + continue; + } + + /* Now look at the individual GPEs in this byte register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) + { + /* Examine one GPE bit */ + + GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * + ACPI_GPE_REGISTER_WIDTH) + j]; + GpeNumber = j + GpeRegisterInfo->BaseGpeNumber; + + if (EnabledStatusByte & (1 << j)) + { + /* Invoke global event handler if present */ + + AcpiGpeCount++; + if (AcpiGbl_GlobalEventHandler) + { + AcpiGbl_GlobalEventHandler (ACPI_EVENT_TYPE_GPE, + GpeDevice, GpeNumber, + AcpiGbl_GlobalEventHandlerContext); + } + + /* Found an active GPE */ + + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER) + { + /* Dispatch the event to a raw handler */ + + GpeHandlerInfo = GpeEventInfo->Dispatch.Handler; + + /* + * There is no protection around the namespace node + * and the GPE handler to ensure a safe destruction + * because: + * 1. The namespace node is expected to always + * exist after loading a table. + * 2. The GPE handler is expected to be flushed by + * AcpiOsWaitEventsComplete() before the + * destruction. + */ + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + IntStatus |= GpeHandlerInfo->Address ( + GpeDevice, GpeNumber, GpeHandlerInfo->Context); + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + } + else + { + /* + * Dispatch the event to a standard handler or + * method. + */ + IntStatus |= AcpiEvGpeDispatch (GpeDevice, + GpeEventInfo, GpeNumber); + } + } + } + } + + GpeBlock = GpeBlock->Next; + } + +UnlockAndExit: + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return (IntStatus); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvAsynchExecuteGpeMethod + * + * PARAMETERS: Context (GpeEventInfo) - Info for this GPE + * + * RETURN: None + * + * DESCRIPTION: Perform the actual execution of a GPE control method. This + * function is called from an invocation of AcpiOsExecute and + * therefore does NOT execute at interrupt level - so that + * the control method itself is not executed in the context of + * an interrupt handler. + * + ******************************************************************************/ + +static void ACPI_SYSTEM_XFACE +AcpiEvAsynchExecuteGpeMethod ( + void *Context) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; + ACPI_STATUS Status = AE_OK; + ACPI_EVALUATE_INFO *Info; + ACPI_GPE_NOTIFY_INFO *Notify; + + + ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod); + + + /* Do the correct dispatch - normal method or implicit notify */ + + switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) + { + case ACPI_GPE_DISPATCH_NOTIFY: + /* + * Implicit notify. + * Dispatch a DEVICE_WAKE notify to the appropriate handler. + * NOTE: the request is queued for execution after this method + * completes. The notify handlers are NOT invoked synchronously + * from this thread -- because handlers may in turn run other + * control methods. + * + * June 2012: Expand implicit notify mechanism to support + * notifies on multiple device objects. + */ + Notify = GpeEventInfo->Dispatch.NotifyList; + while (ACPI_SUCCESS (Status) && Notify) + { + Status = AcpiEvQueueNotifyRequest ( + Notify->DeviceNode, ACPI_NOTIFY_DEVICE_WAKE); + + Notify = Notify->Next; + } + break; + + case ACPI_GPE_DISPATCH_METHOD: + + /* Allocate the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + Status = AE_NO_MEMORY; + } + else + { + /* + * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the + * _Lxx/_Exx control method that corresponds to this GPE + */ + Info->PrefixNode = GpeEventInfo->Dispatch.MethodNode; + Info->Flags = ACPI_IGNORE_RETURN_VALUE; + + Status = AcpiNsEvaluate (Info); + ACPI_FREE (Info); + } + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "while evaluating GPE method [%4.4s]", + AcpiUtGetNodeName (GpeEventInfo->Dispatch.MethodNode))); + } + break; + + default: + + goto ErrorExit; /* Should never happen */ + } + + /* Defer enabling of GPE until all notify handlers are done */ + + Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, + AcpiEvAsynchEnableGpe, GpeEventInfo); + if (ACPI_SUCCESS (Status)) + { + return_VOID; + } + +ErrorExit: + AcpiEvAsynchEnableGpe (GpeEventInfo); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvAsynchEnableGpe + * + * PARAMETERS: Context (GpeEventInfo) - Info for this GPE + * Callback from AcpiOsExecute + * + * RETURN: None + * + * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to + * complete (i.e., finish execution of Notify) + * + ******************************************************************************/ + +static void ACPI_SYSTEM_XFACE +AcpiEvAsynchEnableGpe ( + void *Context) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; + ACPI_CPU_FLAGS Flags; + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + (void) AcpiEvFinishGpe (GpeEventInfo); + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvFinishGpe + * + * PARAMETERS: GpeEventInfo - Info for this GPE + * + * RETURN: Status + * + * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution + * of a GPE method or a synchronous or asynchronous GPE handler. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvFinishGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_STATUS Status; + + + if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_LEVEL_TRIGGERED) + { + /* + * GPE is level-triggered, we clear the GPE status bit after + * handling the event. + */ + Status = AcpiHwClearGpe (GpeEventInfo); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* + * Enable this GPE, conditionally. This means that the GPE will + * only be physically enabled if the EnableMask bit is set + * in the EventInfo. + */ + (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGpeDispatch + * + * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 + * GpeEventInfo - Info for this GPE + * GpeNumber - Number relative to the parent GPE block + * + * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED + * + * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) + * or method (e.g. _Lxx/_Exx) handler. + * + * This function executes at interrupt level. + * + ******************************************************************************/ + +UINT32 +AcpiEvGpeDispatch ( + ACPI_NAMESPACE_NODE *GpeDevice, + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 GpeNumber) +{ + ACPI_STATUS Status; + UINT32 ReturnValue; + + + ACPI_FUNCTION_TRACE (EvGpeDispatch); + + + /* + * Always disable the GPE so that it does not keep firing before + * any asynchronous activity completes (either from the execution + * of a GPE method or an asynchronous GPE handler.) + * + * If there is no handler or method to run, just disable the + * GPE and leave it disabled permanently to prevent further such + * pointless events from firing. + */ + Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to disable GPE %02X", GpeNumber)); + return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); + } + + /* + * If edge-triggered, clear the GPE status bit now. Note that + * level-triggered events are cleared after the GPE is serviced. + */ + if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_EDGE_TRIGGERED) + { + Status = AcpiHwClearGpe (GpeEventInfo); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to clear GPE %02X", GpeNumber)); + (void) AcpiHwLowSetGpe ( + GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); + return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); + } + } + + /* + * Dispatch the GPE to either an installed handler or the control + * method associated with this GPE (_Lxx or _Exx). If a handler + * exists, we invoke it and do not attempt to run the method. + * If there is neither a handler nor a method, leave the GPE + * disabled. + */ + switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) + { + case ACPI_GPE_DISPATCH_HANDLER: + + /* Invoke the installed handler (at interrupt level) */ + + ReturnValue = GpeEventInfo->Dispatch.Handler->Address ( + GpeDevice, GpeNumber, + GpeEventInfo->Dispatch.Handler->Context); + + /* If requested, clear (if level-triggered) and reenable the GPE */ + + if (ReturnValue & ACPI_REENABLE_GPE) + { + (void) AcpiEvFinishGpe (GpeEventInfo); + } + break; + + case ACPI_GPE_DISPATCH_METHOD: + case ACPI_GPE_DISPATCH_NOTIFY: + /* + * Execute the method associated with the GPE + * NOTE: Level-triggered GPEs are cleared after the method completes. + */ + Status = AcpiOsExecute (OSL_GPE_HANDLER, + AcpiEvAsynchExecuteGpeMethod, GpeEventInfo); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Unable to queue handler for GPE %02X - event disabled", + GpeNumber)); + } + break; + + default: + /* + * No handler or method to run! + * 03/2010: This case should no longer be possible. We will not allow + * a GPE to be enabled if it has no handler or method. + */ + ACPI_ERROR ((AE_INFO, + "No handler or method for GPE %02X, disabling event", + GpeNumber)); + break; + } + + return_UINT32 (ACPI_INTERRUPT_HANDLED); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evgpeblk.c b/third_party/lib/acpica/source/components/events/evgpeblk.c new file mode 100644 index 000000000..21f069272 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evgpeblk.c @@ -0,0 +1,555 @@ +/****************************************************************************** + * + * Module Name: evgpeblk - GPE block creation and initialization. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evgpeblk") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static ACPI_STATUS +AcpiEvInstallGpeBlock ( + ACPI_GPE_BLOCK_INFO *GpeBlock, + UINT32 InterruptNumber); + +static ACPI_STATUS +AcpiEvCreateGpeInfoBlocks ( + ACPI_GPE_BLOCK_INFO *GpeBlock); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInstallGpeBlock + * + * PARAMETERS: GpeBlock - New GPE block + * InterruptNumber - Xrupt to be associated with this + * GPE block + * + * RETURN: Status + * + * DESCRIPTION: Install new GPE block with mutex support + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvInstallGpeBlock ( + ACPI_GPE_BLOCK_INFO *GpeBlock, + UINT32 InterruptNumber) +{ + ACPI_GPE_BLOCK_INFO *NextGpeBlock; + ACPI_GPE_XRUPT_INFO *GpeXruptBlock; + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (EvInstallGpeBlock); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiEvGetGpeXruptBlock (InterruptNumber, &GpeXruptBlock); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Install the new block at the end of the list with lock */ + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + if (GpeXruptBlock->GpeBlockListHead) + { + NextGpeBlock = GpeXruptBlock->GpeBlockListHead; + while (NextGpeBlock->Next) + { + NextGpeBlock = NextGpeBlock->Next; + } + + NextGpeBlock->Next = GpeBlock; + GpeBlock->Previous = NextGpeBlock; + } + else + { + GpeXruptBlock->GpeBlockListHead = GpeBlock; + } + + GpeBlock->XruptBlock = GpeXruptBlock; + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvDeleteGpeBlock + * + * PARAMETERS: GpeBlock - Existing GPE block + * + * RETURN: Status + * + * DESCRIPTION: Remove a GPE block + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvDeleteGpeBlock ( + ACPI_GPE_BLOCK_INFO *GpeBlock) +{ + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (EvInstallGpeBlock); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Disable all GPEs in this block */ + + Status = AcpiHwDisableGpeBlock (GpeBlock->XruptBlock, GpeBlock, NULL); + + if (!GpeBlock->Previous && !GpeBlock->Next) + { + /* This is the last GpeBlock on this interrupt */ + + Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + } + else + { + /* Remove the block on this interrupt with lock */ + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + if (GpeBlock->Previous) + { + GpeBlock->Previous->Next = GpeBlock->Next; + } + else + { + GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next; + } + + if (GpeBlock->Next) + { + GpeBlock->Next->Previous = GpeBlock->Previous; + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + } + + AcpiCurrentGpeCount -= GpeBlock->GpeCount; + + /* Free the GpeBlock */ + + ACPI_FREE (GpeBlock->RegisterInfo); + ACPI_FREE (GpeBlock->EventInfo); + ACPI_FREE (GpeBlock); + +UnlockAndExit: + Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvCreateGpeInfoBlocks + * + * PARAMETERS: GpeBlock - New GPE block + * + * RETURN: Status + * + * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvCreateGpeInfoBlocks ( + ACPI_GPE_BLOCK_INFO *GpeBlock) +{ + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo = NULL; + ACPI_GPE_EVENT_INFO *GpeEventInfo = NULL; + ACPI_GPE_EVENT_INFO *ThisEvent; + ACPI_GPE_REGISTER_INFO *ThisRegister; + UINT32 i; + UINT32 j; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks); + + + /* Allocate the GPE register information block */ + + GpeRegisterInfo = ACPI_ALLOCATE_ZEROED ( + (ACPI_SIZE) GpeBlock->RegisterCount * + sizeof (ACPI_GPE_REGISTER_INFO)); + if (!GpeRegisterInfo) + { + ACPI_ERROR ((AE_INFO, + "Could not allocate the GpeRegisterInfo table")); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Allocate the GPE EventInfo block. There are eight distinct GPEs + * per register. Initialization to zeros is sufficient. + */ + GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount * + sizeof (ACPI_GPE_EVENT_INFO)); + if (!GpeEventInfo) + { + ACPI_ERROR ((AE_INFO, + "Could not allocate the GpeEventInfo table")); + Status = AE_NO_MEMORY; + goto ErrorExit; + } + + /* Save the new Info arrays in the GPE block */ + + GpeBlock->RegisterInfo = GpeRegisterInfo; + GpeBlock->EventInfo = GpeEventInfo; + + /* + * Initialize the GPE Register and Event structures. A goal of these + * tables is to hide the fact that there are two separate GPE register + * sets in a given GPE hardware block, the status registers occupy the + * first half, and the enable registers occupy the second half. + */ + ThisRegister = GpeRegisterInfo; + ThisEvent = GpeEventInfo; + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Init the RegisterInfo for this GPE register (8 GPEs) */ + + ThisRegister->BaseGpeNumber = (UINT16) + (GpeBlock->BlockBaseNumber + (i * ACPI_GPE_REGISTER_WIDTH)); + + ThisRegister->StatusAddress.Address = + GpeBlock->Address + i; + + ThisRegister->EnableAddress.Address = + GpeBlock->Address + i + GpeBlock->RegisterCount; + + ThisRegister->StatusAddress.SpaceId = GpeBlock->SpaceId; + ThisRegister->EnableAddress.SpaceId = GpeBlock->SpaceId; + ThisRegister->StatusAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; + ThisRegister->EnableAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; + ThisRegister->StatusAddress.BitOffset = 0; + ThisRegister->EnableAddress.BitOffset = 0; + + /* Init the EventInfo for each GPE within this register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) + { + ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j); + ThisEvent->RegisterInfo = ThisRegister; + ThisEvent++; + } + + /* Disable all GPEs within this register */ + + Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* Clear any pending GPE events within this register */ + + Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + ThisRegister++; + } + + return_ACPI_STATUS (AE_OK); + + +ErrorExit: + if (GpeRegisterInfo) + { + ACPI_FREE (GpeRegisterInfo); + } + if (GpeEventInfo) + { + ACPI_FREE (GpeEventInfo); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvCreateGpeBlock + * + * PARAMETERS: GpeDevice - Handle to the parent GPE block + * GpeBlockAddress - Address and SpaceID + * RegisterCount - Number of GPE register pairs in the block + * GpeBlockBaseNumber - Starting GPE number for the block + * InterruptNumber - H/W interrupt for the block + * ReturnGpeBlock - Where the new block descriptor is returned + * + * RETURN: Status + * + * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within + * the block are disabled at exit. + * Note: Assumes namespace is locked. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvCreateGpeBlock ( + ACPI_NAMESPACE_NODE *GpeDevice, + UINT64 Address, + UINT8 SpaceId, + UINT32 RegisterCount, + UINT16 GpeBlockBaseNumber, + UINT32 InterruptNumber, + ACPI_GPE_BLOCK_INFO **ReturnGpeBlock) +{ + ACPI_STATUS Status; + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_GPE_WALK_INFO WalkInfo; + + + ACPI_FUNCTION_TRACE (EvCreateGpeBlock); + + + if (!RegisterCount) + { + return_ACPI_STATUS (AE_OK); + } + + /* Allocate a new GPE block */ + + GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO)); + if (!GpeBlock) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the new GPE block */ + + GpeBlock->Address = Address; + GpeBlock->SpaceId = SpaceId; + GpeBlock->Node = GpeDevice; + GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH); + GpeBlock->Initialized = FALSE; + GpeBlock->RegisterCount = RegisterCount; + GpeBlock->BlockBaseNumber = GpeBlockBaseNumber; + + /* + * Create the RegisterInfo and EventInfo sub-structures + * Note: disables and clears all GPEs in the block + */ + Status = AcpiEvCreateGpeInfoBlocks (GpeBlock); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (GpeBlock); + return_ACPI_STATUS (Status); + } + + /* Install the new block in the global lists */ + + Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (GpeBlock->RegisterInfo); + ACPI_FREE (GpeBlock->EventInfo); + ACPI_FREE (GpeBlock); + return_ACPI_STATUS (Status); + } + + AcpiGbl_AllGpesInitialized = FALSE; + + /* Find all GPE methods (_Lxx or_Exx) for this block */ + + WalkInfo.GpeBlock = GpeBlock; + WalkInfo.GpeDevice = GpeDevice; + WalkInfo.ExecuteByOwnerId = FALSE; + + Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice, + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, + AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL); + + /* Return the new block */ + + if (ReturnGpeBlock) + { + (*ReturnGpeBlock) = GpeBlock; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n", + (UINT32) GpeBlock->BlockBaseNumber, + (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)), + GpeDevice->Name.Ascii, GpeBlock->RegisterCount, InterruptNumber, + InterruptNumber == AcpiGbl_FADT.SciInterrupt ? " (SCI)" : "")); + + /* Update global count of currently available GPEs */ + + AcpiCurrentGpeCount += GpeBlock->GpeCount; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInitializeGpeBlock + * + * PARAMETERS: ACPI_GPE_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have + * associated methods. + * Note: Assumes namespace is locked. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInitializeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Ignored) +{ + ACPI_STATUS Status; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + UINT32 GpeEnabledCount; + UINT32 GpeIndex; + UINT32 i; + UINT32 j; + + + ACPI_FUNCTION_TRACE (EvInitializeGpeBlock); + + + /* + * Ignore a null GPE block (e.g., if no GPE block 1 exists), and + * any GPE blocks that have been initialized already. + */ + if (!GpeBlock || GpeBlock->Initialized) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * Enable all GPEs that have a corresponding method and have the + * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block + * must be enabled via the acpi_enable_gpe() interface. + */ + GpeEnabledCount = 0; + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) + { + /* Get the info block for this particular GPE */ + + GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j; + GpeEventInfo = &GpeBlock->EventInfo[GpeIndex]; + + /* + * Ignore GPEs that have no corresponding _Lxx/_Exx method + * and GPEs that are used to wake the system + */ + if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_NONE) || + (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_RAW_HANDLER) || + (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE)) + { + continue; + } + + Status = AcpiEvAddGpeReference (GpeEventInfo); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not enable GPE 0x%02X", + GpeIndex + GpeBlock->BlockBaseNumber)); + continue; + } + + GpeEnabledCount++; + } + } + + if (GpeEnabledCount) + { + ACPI_INFO ((AE_INFO, + "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount, + (UINT32) GpeBlock->BlockBaseNumber, + (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)))); + } + + GpeBlock->Initialized = TRUE; + return_ACPI_STATUS (AE_OK); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evgpeinit.c b/third_party/lib/acpica/source/components/events/evgpeinit.c new file mode 100644 index 000000000..b62f91ad1 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evgpeinit.c @@ -0,0 +1,466 @@ +/****************************************************************************** + * + * Module Name: evgpeinit - System GPE initialization and update + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evgpeinit") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* + * Note: History of _PRW support in ACPICA + * + * Originally (2000 - 2010), the GPE initialization code performed a walk of + * the entire namespace to execute the _PRW methods and detect all GPEs + * capable of waking the system. + * + * As of 10/2010, the _PRW method execution has been removed since it is + * actually unnecessary. The host OS must in fact execute all _PRW methods + * in order to identify the device/power-resource dependencies. We now put + * the onus on the host OS to identify the wake GPEs as part of this process + * and to inform ACPICA of these GPEs via the AcpiSetupGpeForWake interface. This + * not only reduces the complexity of the ACPICA initialization code, but in + * some cases (on systems with very large namespaces) it should reduce the + * kernel boot time as well. + */ + +/******************************************************************************* + * + * FUNCTION: AcpiEvGpeInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize the GPE data structures and the FADT GPE 0/1 blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvGpeInitialize ( + void) +{ + UINT32 RegisterCount0 = 0; + UINT32 RegisterCount1 = 0; + UINT32 GpeNumberMax = 0; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvGpeInitialize); + + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Initializing General Purpose Events (GPEs):\n")); + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Initialize the GPE Block(s) defined in the FADT + * + * Why the GPE register block lengths are divided by 2: From the ACPI + * Spec, section "General-Purpose Event Registers", we have: + * + * "Each register block contains two registers of equal length + * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the + * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN + * The length of the GPE1_STS and GPE1_EN registers is equal to + * half the GPE1_LEN. If a generic register block is not supported + * then its respective block pointer and block length values in the + * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need + * to be the same size." + */ + + /* + * Determine the maximum GPE number for this machine. + * + * Note: both GPE0 and GPE1 are optional, and either can exist without + * the other. + * + * If EITHER the register length OR the block address are zero, then that + * particular block is not supported. + */ + if (AcpiGbl_FADT.Gpe0BlockLength && + AcpiGbl_FADT.XGpe0Block.Address) + { + /* GPE block 0 exists (has both length and address > 0) */ + + RegisterCount0 = (UINT16) (AcpiGbl_FADT.Gpe0BlockLength / 2); + GpeNumberMax = (RegisterCount0 * ACPI_GPE_REGISTER_WIDTH) - 1; + + /* Install GPE Block 0 */ + + Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice, + AcpiGbl_FADT.XGpe0Block.Address, + AcpiGbl_FADT.XGpe0Block.SpaceId, + RegisterCount0, 0, + AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[0]); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not create GPE Block 0")); + } + } + + if (AcpiGbl_FADT.Gpe1BlockLength && + AcpiGbl_FADT.XGpe1Block.Address) + { + /* GPE block 1 exists (has both length and address > 0) */ + + RegisterCount1 = (UINT16) (AcpiGbl_FADT.Gpe1BlockLength / 2); + + /* Check for GPE0/GPE1 overlap (if both banks exist) */ + + if ((RegisterCount0) && + (GpeNumberMax >= AcpiGbl_FADT.Gpe1Base)) + { + ACPI_ERROR ((AE_INFO, + "GPE0 block (GPE 0 to %u) overlaps the GPE1 block " + "(GPE %u to %u) - Ignoring GPE1", + GpeNumberMax, AcpiGbl_FADT.Gpe1Base, + AcpiGbl_FADT.Gpe1Base + + ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1))); + + /* Ignore GPE1 block by setting the register count to zero */ + + RegisterCount1 = 0; + } + else + { + /* Install GPE Block 1 */ + + Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice, + AcpiGbl_FADT.XGpe1Block.Address, + AcpiGbl_FADT.XGpe1Block.SpaceId, + RegisterCount1, + AcpiGbl_FADT.Gpe1Base, + AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[1]); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not create GPE Block 1")); + } + + /* + * GPE0 and GPE1 do not have to be contiguous in the GPE number + * space. However, GPE0 always starts at GPE number zero. + */ + GpeNumberMax = AcpiGbl_FADT.Gpe1Base + + ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1); + } + } + + /* Exit if there are no GPE registers */ + + if ((RegisterCount0 + RegisterCount1) == 0) + { + /* GPEs are not required by ACPI, this is OK */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "There are no GPE blocks defined in the FADT\n")); + Status = AE_OK; + goto Cleanup; + } + + +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvUpdateGpes + * + * PARAMETERS: TableOwnerId - ID of the newly-loaded ACPI table + * + * RETURN: None + * + * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a + * result of a Load() or LoadTable() operation. If new GPE + * methods have been installed, register the new methods. + * + ******************************************************************************/ + +void +AcpiEvUpdateGpes ( + ACPI_OWNER_ID TableOwnerId) +{ + ACPI_GPE_XRUPT_INFO *GpeXruptInfo; + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_GPE_WALK_INFO WalkInfo; + ACPI_STATUS Status = AE_OK; + + + /* + * Find any _Lxx/_Exx GPE methods that have just been loaded. + * + * Any GPEs that correspond to new _Lxx/_Exx methods are immediately + * enabled. + * + * Examine the namespace underneath each GpeDevice within the + * GpeBlock lists. + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return; + } + + WalkInfo.Count = 0; + WalkInfo.OwnerId = TableOwnerId; + WalkInfo.ExecuteByOwnerId = TRUE; + + /* Walk the interrupt level descriptor list */ + + GpeXruptInfo = AcpiGbl_GpeXruptListHead; + while (GpeXruptInfo) + { + /* Walk all Gpe Blocks attached to this interrupt level */ + + GpeBlock = GpeXruptInfo->GpeBlockListHead; + while (GpeBlock) + { + WalkInfo.GpeBlock = GpeBlock; + WalkInfo.GpeDevice = GpeBlock->Node; + + Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, + WalkInfo.GpeDevice, ACPI_UINT32_MAX, + ACPI_NS_WALK_NO_UNLOCK, AcpiEvMatchGpeMethod, + NULL, &WalkInfo, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While decoding _Lxx/_Exx methods")); + } + + GpeBlock = GpeBlock->Next; + } + + GpeXruptInfo = GpeXruptInfo->Next; + } + + if (WalkInfo.Count) + { + ACPI_INFO ((AE_INFO, "Enabled %u new GPEs", WalkInfo.Count)); + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvMatchGpeMethod + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Called from AcpiWalkNamespace. Expects each object to be a + * control method under the _GPE portion of the namespace. + * Extract the name and GPE type from the object, saving this + * information for quick lookup during GPE dispatch. Allows a + * per-OwnerId evaluation if ExecuteByOwnerId is TRUE in the + * WalkInfo parameter block. + * + * The name of each GPE control method is of the form: + * "_Lxx" or "_Exx", where: + * L - means that the GPE is level triggered + * E - means that the GPE is edge triggered + * xx - is the GPE number [in HEX] + * + * If WalkInfo->ExecuteByOwnerId is TRUE, we only execute examine GPE methods + * with that owner. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvMatchGpeMethod ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_NAMESPACE_NODE *MethodNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + ACPI_GPE_WALK_INFO *WalkInfo = ACPI_CAST_PTR (ACPI_GPE_WALK_INFO, Context); + ACPI_GPE_EVENT_INFO *GpeEventInfo; + UINT32 GpeNumber; + char Name[ACPI_NAME_SIZE + 1]; + UINT8 Type; + + + ACPI_FUNCTION_TRACE (EvMatchGpeMethod); + + + /* Check if requested OwnerId matches this OwnerId */ + + if ((WalkInfo->ExecuteByOwnerId) && + (MethodNode->OwnerId != WalkInfo->OwnerId)) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * Match and decode the _Lxx and _Exx GPE method names + * + * 1) Extract the method name and null terminate it + */ + ACPI_MOVE_32_TO_32 (Name, &MethodNode->Name.Integer); + Name[ACPI_NAME_SIZE] = 0; + + /* 2) Name must begin with an underscore */ + + if (Name[0] != '_') + { + return_ACPI_STATUS (AE_OK); /* Ignore this method */ + } + + /* + * 3) Edge/Level determination is based on the 2nd character + * of the method name + */ + switch (Name[1]) + { + case 'L': + + Type = ACPI_GPE_LEVEL_TRIGGERED; + break; + + case 'E': + + Type = ACPI_GPE_EDGE_TRIGGERED; + break; + + default: + + /* Unknown method type, just ignore it */ + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, + "Ignoring unknown GPE method type: %s " + "(name not of form _Lxx or _Exx)", Name)); + return_ACPI_STATUS (AE_OK); + } + + /* 4) The last two characters of the name are the hex GPE Number */ + + GpeNumber = strtoul (&Name[2], NULL, 16); + if (GpeNumber == ACPI_UINT32_MAX) + { + /* Conversion failed; invalid method, just ignore it */ + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, + "Could not extract GPE number from name: %s " + "(name is not of form _Lxx or _Exx)", Name)); + return_ACPI_STATUS (AE_OK); + } + + /* Ensure that we have a valid GPE number for this GPE block */ + + GpeEventInfo = AcpiEvLowGetGpeInfo (GpeNumber, WalkInfo->GpeBlock); + if (!GpeEventInfo) + { + /* + * This GpeNumber is not valid for this GPE block, just ignore it. + * However, it may be valid for a different GPE block, since GPE0 + * and GPE1 methods both appear under \_GPE. + */ + return_ACPI_STATUS (AE_OK); + } + + if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) + { + /* If there is already a handler, ignore this GPE method */ + + return_ACPI_STATUS (AE_OK); + } + + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_METHOD) + { + /* + * If there is already a method, ignore this method. But check + * for a type mismatch (if both the _Lxx AND _Exx exist) + */ + if (Type != (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK)) + { + ACPI_ERROR ((AE_INFO, + "For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods", + GpeNumber, GpeNumber, GpeNumber)); + } + return_ACPI_STATUS (AE_OK); + } + + /* Disable the GPE in case it's been enabled already. */ + + (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); + + /* + * Add the GPE information from above to the GpeEventInfo block for + * use during dispatch of this GPE. + */ + GpeEventInfo->Flags &= ~(ACPI_GPE_DISPATCH_MASK); + GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_METHOD); + GpeEventInfo->Dispatch.MethodNode = MethodNode; + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, + "Registered GPE method %s as GPE number 0x%.2X\n", + Name, GpeNumber)); + return_ACPI_STATUS (AE_OK); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evgpeutil.c b/third_party/lib/acpica/source/components/events/evgpeutil.c new file mode 100644 index 000000000..ff4b1cddc --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evgpeutil.c @@ -0,0 +1,398 @@ +/****************************************************************************** + * + * Module Name: evgpeutil - GPE utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evgpeutil") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/******************************************************************************* + * + * FUNCTION: AcpiEvWalkGpeList + * + * PARAMETERS: GpeWalkCallback - Routine called for each GPE block + * Context - Value passed to callback + * + * RETURN: Status + * + * DESCRIPTION: Walk the GPE lists. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvWalkGpeList ( + ACPI_GPE_CALLBACK GpeWalkCallback, + void *Context) +{ + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_GPE_XRUPT_INFO *GpeXruptInfo; + ACPI_STATUS Status = AE_OK; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (EvWalkGpeList); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Walk the interrupt level descriptor list */ + + GpeXruptInfo = AcpiGbl_GpeXruptListHead; + while (GpeXruptInfo) + { + /* Walk all Gpe Blocks attached to this interrupt level */ + + GpeBlock = GpeXruptInfo->GpeBlockListHead; + while (GpeBlock) + { + /* One callback per GPE block */ + + Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_CTRL_END) /* Callback abort */ + { + Status = AE_OK; + } + goto UnlockAndExit; + } + + GpeBlock = GpeBlock->Next; + } + + GpeXruptInfo = GpeXruptInfo->Next; + } + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGetGpeDevice + * + * PARAMETERS: GPE_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE + * block device. NULL if the GPE is one of the FADT-defined GPEs. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvGetGpeDevice ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + ACPI_GPE_DEVICE_INFO *Info = Context; + + + /* Increment Index by the number of GPEs in this block */ + + Info->NextBlockBaseIndex += GpeBlock->GpeCount; + + if (Info->Index < Info->NextBlockBaseIndex) + { + /* + * The GPE index is within this block, get the node. Leave the node + * NULL for the FADT-defined GPEs + */ + if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE) + { + Info->GpeDevice = GpeBlock->Node; + } + + Info->Status = AE_OK; + return (AE_CTRL_END); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGetGpeXruptBlock + * + * PARAMETERS: InterruptNumber - Interrupt for a GPE block + * GpeXruptBlock - Where the block is returned + * + * RETURN: Status + * + * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt + * block per unique interrupt level used for GPEs. Should be + * called only when the GPE lists are semaphore locked and not + * subject to change. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvGetGpeXruptBlock ( + UINT32 InterruptNumber, + ACPI_GPE_XRUPT_INFO **GpeXruptBlock) +{ + ACPI_GPE_XRUPT_INFO *NextGpeXrupt; + ACPI_GPE_XRUPT_INFO *GpeXrupt; + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock); + + + /* No need for lock since we are not changing any list elements here */ + + NextGpeXrupt = AcpiGbl_GpeXruptListHead; + while (NextGpeXrupt) + { + if (NextGpeXrupt->InterruptNumber == InterruptNumber) + { + *GpeXruptBlock = NextGpeXrupt; + return_ACPI_STATUS (AE_OK); + } + + NextGpeXrupt = NextGpeXrupt->Next; + } + + /* Not found, must allocate a new xrupt descriptor */ + + GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO)); + if (!GpeXrupt) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + GpeXrupt->InterruptNumber = InterruptNumber; + + /* Install new interrupt descriptor with spin lock */ + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + if (AcpiGbl_GpeXruptListHead) + { + NextGpeXrupt = AcpiGbl_GpeXruptListHead; + while (NextGpeXrupt->Next) + { + NextGpeXrupt = NextGpeXrupt->Next; + } + + NextGpeXrupt->Next = GpeXrupt; + GpeXrupt->Previous = NextGpeXrupt; + } + else + { + AcpiGbl_GpeXruptListHead = GpeXrupt; + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + + /* Install new interrupt handler if not SCI_INT */ + + if (InterruptNumber != AcpiGbl_FADT.SciInterrupt) + { + Status = AcpiOsInstallInterruptHandler (InterruptNumber, + AcpiEvGpeXruptHandler, GpeXrupt); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install GPE interrupt handler at level 0x%X", + InterruptNumber)); + return_ACPI_STATUS (Status); + } + } + + *GpeXruptBlock = GpeXrupt; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvDeleteGpeXrupt + * + * PARAMETERS: GpeXrupt - A GPE interrupt info block + * + * RETURN: Status + * + * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated + * interrupt handler if not the SCI interrupt. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvDeleteGpeXrupt ( + ACPI_GPE_XRUPT_INFO *GpeXrupt) +{ + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt); + + + /* We never want to remove the SCI interrupt handler */ + + if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt) + { + GpeXrupt->GpeBlockListHead = NULL; + return_ACPI_STATUS (AE_OK); + } + + /* Disable this interrupt */ + + Status = AcpiOsRemoveInterruptHandler ( + GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Unlink the interrupt block with lock */ + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + if (GpeXrupt->Previous) + { + GpeXrupt->Previous->Next = GpeXrupt->Next; + } + else + { + /* No previous, update list head */ + + AcpiGbl_GpeXruptListHead = GpeXrupt->Next; + } + + if (GpeXrupt->Next) + { + GpeXrupt->Next->Previous = GpeXrupt->Previous; + } + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + + /* Free the block */ + + ACPI_FREE (GpeXrupt); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvDeleteGpeHandlers + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Delete all Handler objects found in the GPE data structs. + * Used only prior to termination. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvDeleteGpeHandlers ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_GPE_NOTIFY_INFO *Notify; + ACPI_GPE_NOTIFY_INFO *Next; + UINT32 i; + UINT32 j; + + + ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers); + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Now look at the individual GPEs in this byte register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) + { + GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * + ACPI_GPE_REGISTER_WIDTH) + j]; + + if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) + { + /* Delete an installed handler block */ + + ACPI_FREE (GpeEventInfo->Dispatch.Handler); + GpeEventInfo->Dispatch.Handler = NULL; + GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; + } + else if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_NOTIFY) + { + /* Delete the implicit notification device list */ + + Notify = GpeEventInfo->Dispatch.NotifyList; + while (Notify) + { + Next = Notify->Next; + ACPI_FREE (Notify); + Notify = Next; + } + + GpeEventInfo->Dispatch.NotifyList = NULL; + GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; + } + } + } + + return_ACPI_STATUS (AE_OK); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evhandler.c b/third_party/lib/acpica/source/components/events/evhandler.c new file mode 100644 index 000000000..d63cad8d2 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evhandler.c @@ -0,0 +1,606 @@ +/****************************************************************************** + * + * Module Name: evhandler - Support for Address Space handlers + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evhandler") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiEvInstallHandler ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/* These are the address spaces that will get default handlers */ + +UINT8 AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] = +{ + ACPI_ADR_SPACE_SYSTEM_MEMORY, + ACPI_ADR_SPACE_SYSTEM_IO, + ACPI_ADR_SPACE_PCI_CONFIG, + ACPI_ADR_SPACE_DATA_TABLE +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInstallRegionHandlers + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Installs the core subsystem default address space handlers. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInstallRegionHandlers ( + void) +{ + ACPI_STATUS Status; + UINT32 i; + + + ACPI_FUNCTION_TRACE (EvInstallRegionHandlers); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * All address spaces (PCI Config, EC, SMBus) are scope dependent and + * registration must occur for a specific device. + * + * In the case of the system memory and IO address spaces there is + * currently no device associated with the address space. For these we + * use the root. + * + * We install the default PCI config space handler at the root so that + * this space is immediately available even though the we have not + * enumerated all the PCI Root Buses yet. This is to conform to the ACPI + * specification which states that the PCI config space must be always + * available -- even though we are nowhere near ready to find the PCI root + * buses at this point. + * + * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler + * has already been installed (via AcpiInstallAddressSpaceHandler). + * Similar for AE_SAME_HANDLER. + */ + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) + { + Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode, + AcpiGbl_DefaultAddressSpaces[i], + ACPI_DEFAULT_HANDLER, NULL, NULL); + switch (Status) + { + case AE_OK: + case AE_SAME_HANDLER: + case AE_ALREADY_EXISTS: + + /* These exceptions are all OK */ + + Status = AE_OK; + break; + + default: + + goto UnlockAndExit; + } + } + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvHasDefaultHandler + * + * PARAMETERS: Node - Namespace node for the device + * SpaceId - The address space ID + * + * RETURN: TRUE if default handler is installed, FALSE otherwise + * + * DESCRIPTION: Check if the default handler is installed for the requested + * space ID. + * + ******************************************************************************/ + +BOOLEAN +AcpiEvHasDefaultHandler ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + + + /* Must have an existing internal object */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc) + { + HandlerObj = ObjDesc->CommonNotify.Handler; + + /* Walk the linked list of handlers for this object */ + + while (HandlerObj) + { + if (HandlerObj->AddressSpace.SpaceId == SpaceId) + { + if (HandlerObj->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) + { + return (TRUE); + } + } + + HandlerObj = HandlerObj->AddressSpace.Next; + } + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInstallHandler + * + * PARAMETERS: WalkNamespace callback + * + * DESCRIPTION: This routine installs an address handler into objects that are + * of type Region or Device. + * + * If the Object is a Device, and the device has a handler of + * the same type then the search is terminated in that branch. + * + * This is because the existing handler is closer in proximity + * to any more regions than the one we are trying to install. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvInstallHandler ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_OPERAND_OBJECT *NextHandlerObj; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (EvInstallHandler); + + + HandlerObj = (ACPI_OPERAND_OBJECT *) Context; + + /* Parameter validation */ + + if (!HandlerObj) + { + return (AE_OK); + } + + /* Convert and validate the device handle */ + + Node = AcpiNsValidateHandle (ObjHandle); + if (!Node) + { + return (AE_BAD_PARAMETER); + } + + /* + * We only care about regions and objects that are allowed to have + * address space handlers + */ + if ((Node->Type != ACPI_TYPE_DEVICE) && + (Node->Type != ACPI_TYPE_REGION) && + (Node != AcpiGbl_RootNode)) + { + return (AE_OK); + } + + /* Check for an existing internal object */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + /* No object, just exit */ + + return (AE_OK); + } + + /* Devices are handled different than regions */ + + if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE) + { + /* Check if this Device already has a handler for this address space */ + + NextHandlerObj = AcpiEvFindRegionHandler ( + HandlerObj->AddressSpace.SpaceId, ObjDesc->CommonNotify.Handler); + if (NextHandlerObj) + { + /* Found a handler, is it for the same address space? */ + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Found handler for region [%s] in device %p(%p) handler %p\n", + AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId), + ObjDesc, NextHandlerObj, HandlerObj)); + + /* + * Since the object we found it on was a device, then it means + * that someone has already installed a handler for the branch + * of the namespace from this device on. Just bail out telling + * the walk routine to not traverse this branch. This preserves + * the scoping rule for handlers. + */ + return (AE_CTRL_DEPTH); + } + + /* + * As long as the device didn't have a handler for this space we + * don't care about it. We just ignore it and proceed. + */ + return (AE_OK); + } + + /* Object is a Region */ + + if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId) + { + /* This region is for a different address space, just ignore it */ + + return (AE_OK); + } + + /* + * Now we have a region and it is for the handler's address space type. + * + * First disconnect region for any previous handler (if any) + */ + AcpiEvDetachRegion (ObjDesc, FALSE); + + /* Connect the region to the new handler */ + + Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvFindRegionHandler + * + * PARAMETERS: SpaceId - The address space ID + * HandlerObj - Head of the handler object list + * + * RETURN: Matching handler object. NULL if space ID not matched + * + * DESCRIPTION: Search a handler object list for a match on the address + * space ID. + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiEvFindRegionHandler ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_OPERAND_OBJECT *HandlerObj) +{ + + /* Walk the handler list for this device */ + + while (HandlerObj) + { + /* Same SpaceId indicates a handler is installed */ + + if (HandlerObj->AddressSpace.SpaceId == SpaceId) + { + return (HandlerObj); + } + + /* Next handler object */ + + HandlerObj = HandlerObj->AddressSpace.Next; + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInstallSpaceHandler + * + * PARAMETERS: Node - Namespace node for the device + * SpaceId - The address space ID + * Handler - Address of the handler + * Setup - Address of the setup function + * Context - Value passed to the handler on each access + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. + * Assumes namespace is locked + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInstallSpaceHandler ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_STATUS Status = AE_OK; + ACPI_OBJECT_TYPE Type; + UINT8 Flags = 0; + + + ACPI_FUNCTION_TRACE (EvInstallSpaceHandler); + + + /* + * This registration is valid for only the types below and the root. + * The root node is where the default handlers get installed. + */ + if ((Node->Type != ACPI_TYPE_DEVICE) && + (Node->Type != ACPI_TYPE_PROCESSOR) && + (Node->Type != ACPI_TYPE_THERMAL) && + (Node != AcpiGbl_RootNode)) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + if (Handler == ACPI_DEFAULT_HANDLER) + { + Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; + + switch (SpaceId) + { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + + Handler = AcpiExSystemMemorySpaceHandler; + Setup = AcpiEvSystemMemoryRegionSetup; + break; + + case ACPI_ADR_SPACE_SYSTEM_IO: + + Handler = AcpiExSystemIoSpaceHandler; + Setup = AcpiEvIoSpaceRegionSetup; + break; + + case ACPI_ADR_SPACE_PCI_CONFIG: + + Handler = AcpiExPciConfigSpaceHandler; + Setup = AcpiEvPciConfigRegionSetup; + break; + + case ACPI_ADR_SPACE_CMOS: + + Handler = AcpiExCmosSpaceHandler; + Setup = AcpiEvCmosRegionSetup; + break; + + case ACPI_ADR_SPACE_PCI_BAR_TARGET: + + Handler = AcpiExPciBarSpaceHandler; + Setup = AcpiEvPciBarRegionSetup; + break; + + case ACPI_ADR_SPACE_DATA_TABLE: + + Handler = AcpiExDataTableSpaceHandler; + Setup = NULL; + break; + + default: + + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + } + + /* If the caller hasn't specified a setup routine, use the default */ + + if (!Setup) + { + Setup = AcpiEvDefaultRegionSetup; + } + + /* Check for an existing internal object */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc) + { + /* + * The attached device object already exists. Now make sure + * the handler is not already installed. + */ + HandlerObj = AcpiEvFindRegionHandler (SpaceId, + ObjDesc->CommonNotify.Handler); + + if (HandlerObj) + { + if (HandlerObj->AddressSpace.Handler == Handler) + { + /* + * It is (relatively) OK to attempt to install the SAME + * handler twice. This can easily happen with the + * PCI_Config space. + */ + Status = AE_SAME_HANDLER; + goto UnlockAndExit; + } + else + { + /* A handler is already installed */ + + Status = AE_ALREADY_EXISTS; + } + + goto UnlockAndExit; + } + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Creating object on Device %p while installing handler\n", + Node)); + + /* ObjDesc does not exist, create one */ + + if (Node->Type == ACPI_TYPE_ANY) + { + Type = ACPI_TYPE_DEVICE; + } + else + { + Type = Node->Type; + } + + ObjDesc = AcpiUtCreateInternalObject (Type); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + /* Init new descriptor */ + + ObjDesc->Common.Type = (UINT8) Type; + + /* Attach the new object to the Node */ + + Status = AcpiNsAttachObject (Node, ObjDesc, Type); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Installing address handler for region %s(%X) " + "on Device %4.4s %p(%p)\n", + AcpiUtGetRegionName (SpaceId), SpaceId, + AcpiUtGetNodeName (Node), Node, ObjDesc)); + + /* + * Install the handler + * + * At this point there is no existing handler. Just allocate the object + * for the handler and link it into the list. + */ + HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); + if (!HandlerObj) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + /* Init handler obj */ + + HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId; + HandlerObj->AddressSpace.HandlerFlags = Flags; + HandlerObj->AddressSpace.RegionList = NULL; + HandlerObj->AddressSpace.Node = Node; + HandlerObj->AddressSpace.Handler = Handler; + HandlerObj->AddressSpace.Context = Context; + HandlerObj->AddressSpace.Setup = Setup; + + /* Install at head of Device.AddressSpace list */ + + HandlerObj->AddressSpace.Next = ObjDesc->CommonNotify.Handler; + + /* + * The Device object is the first reference on the HandlerObj. + * Each region that uses the handler adds a reference. + */ + ObjDesc->CommonNotify.Handler = HandlerObj; + + /* + * Walk the namespace finding all of the regions this handler will + * manage. + * + * Start at the device and search the branch toward the leaf nodes + * until either the leaf is encountered or a device is detected that + * has an address handler of the same type. + * + * In either case, back up and search down the remainder of the branch + */ + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, + AcpiEvInstallHandler, NULL, HandlerObj, NULL); + +UnlockAndExit: + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/events/evmisc.c b/third_party/lib/acpica/source/components/events/evmisc.c new file mode 100644 index 000000000..30fc6f0c2 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evmisc.c @@ -0,0 +1,332 @@ +/****************************************************************************** + * + * Module Name: evmisc - Miscellaneous event manager support functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evmisc") + + +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +AcpiEvNotifyDispatch ( + void *Context); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvIsNotifyObject + * + * PARAMETERS: Node - Node to check + * + * RETURN: TRUE if notifies allowed on this object + * + * DESCRIPTION: Check type of node for a object that supports notifies. + * + * TBD: This could be replaced by a flag bit in the node. + * + ******************************************************************************/ + +BOOLEAN +AcpiEvIsNotifyObject ( + ACPI_NAMESPACE_NODE *Node) +{ + + switch (Node->Type) + { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + /* + * These are the ONLY objects that can receive ACPI notifications + */ + return (TRUE); + + default: + + return (FALSE); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvQueueNotifyRequest + * + * PARAMETERS: Node - NS node for the notified object + * NotifyValue - Value from the Notify() request + * + * RETURN: Status + * + * DESCRIPTION: Dispatch a device notification event to a previously + * installed handler. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvQueueNotifyRequest ( + ACPI_NAMESPACE_NODE *Node, + UINT32 NotifyValue) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerListHead = NULL; + ACPI_GENERIC_STATE *Info; + UINT8 HandlerListId = 0; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_NAME (EvQueueNotifyRequest); + + + /* Are Notifies allowed on this object? */ + + if (!AcpiEvIsNotifyObject (Node)) + { + return (AE_TYPE); + } + + /* Get the correct notify list type (System or Device) */ + + if (NotifyValue <= ACPI_MAX_SYS_NOTIFY) + { + HandlerListId = ACPI_SYSTEM_HANDLER_LIST; + } + else + { + HandlerListId = ACPI_DEVICE_HANDLER_LIST; + } + + /* Get the notify object attached to the namespace Node */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc) + { + /* We have an attached object, Get the correct handler list */ + + HandlerListHead = ObjDesc->CommonNotify.NotifyList[HandlerListId]; + } + + /* + * If there is no notify handler (Global or Local) + * for this object, just ignore the notify + */ + if (!AcpiGbl_GlobalNotify[HandlerListId].Handler && !HandlerListHead) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n", + AcpiUtGetNodeName (Node), NotifyValue, Node)); + + return (AE_OK); + } + + /* Setup notify info and schedule the notify dispatcher */ + + Info = AcpiUtCreateGenericState (); + if (!Info) + { + return (AE_NO_MEMORY); + } + + Info->Common.DescriptorType = ACPI_DESC_TYPE_STATE_NOTIFY; + + Info->Notify.Node = Node; + Info->Notify.Value = (UINT16) NotifyValue; + Info->Notify.HandlerListId = HandlerListId; + Info->Notify.HandlerListHead = HandlerListHead; + Info->Notify.Global = &AcpiGbl_GlobalNotify[HandlerListId]; + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n", + AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type), + NotifyValue, AcpiUtGetNotifyName (NotifyValue, ACPI_TYPE_ANY), Node)); + + Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, + AcpiEvNotifyDispatch, Info); + if (ACPI_FAILURE (Status)) + { + AcpiUtDeleteGenericState (Info); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvNotifyDispatch + * + * PARAMETERS: Context - To be passed to the notify handler + * + * RETURN: None. + * + * DESCRIPTION: Dispatch a device notification event to a previously + * installed handler. + * + ******************************************************************************/ + +static void ACPI_SYSTEM_XFACE +AcpiEvNotifyDispatch ( + void *Context) +{ + ACPI_GENERIC_STATE *Info = (ACPI_GENERIC_STATE *) Context; + ACPI_OPERAND_OBJECT *HandlerObj; + + + ACPI_FUNCTION_ENTRY (); + + + /* Invoke a global notify handler if installed */ + + if (Info->Notify.Global->Handler) + { + Info->Notify.Global->Handler (Info->Notify.Node, + Info->Notify.Value, + Info->Notify.Global->Context); + } + + /* Now invoke the local notify handler(s) if any are installed */ + + HandlerObj = Info->Notify.HandlerListHead; + while (HandlerObj) + { + HandlerObj->Notify.Handler (Info->Notify.Node, + Info->Notify.Value, + HandlerObj->Notify.Context); + + HandlerObj = HandlerObj->Notify.Next[Info->Notify.HandlerListId]; + } + + /* All done with the info object */ + + AcpiUtDeleteGenericState (Info); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/****************************************************************************** + * + * FUNCTION: AcpiEvTerminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Disable events and free memory allocated for table storage. + * + ******************************************************************************/ + +void +AcpiEvTerminate ( + void) +{ + UINT32 i; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvTerminate); + + + if (AcpiGbl_EventsInitialized) + { + /* + * Disable all event-related functionality. In all cases, on error, + * print a message but obviously we don't abort. + */ + + /* Disable all fixed events */ + + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) + { + Status = AcpiDisableEvent (i, 0); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, + "Could not disable fixed event %u", (UINT32) i)); + } + } + + /* Disable all GPEs in all GPE blocks */ + + Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL); + + Status = AcpiEvRemoveGlobalLockHandler (); + if (ACPI_FAILURE(Status)) + { + ACPI_ERROR ((AE_INFO, + "Could not remove Global Lock handler")); + } + + AcpiGbl_EventsInitialized = FALSE; + } + + /* Remove SCI handlers */ + + Status = AcpiEvRemoveAllSciHandlers (); + if (ACPI_FAILURE(Status)) + { + ACPI_ERROR ((AE_INFO, + "Could not remove SCI handler")); + } + + /* Deallocate all handler objects installed within GPE info structs */ + + Status = AcpiEvWalkGpeList (AcpiEvDeleteGpeHandlers, NULL); + + /* Return to original mode if necessary */ + + if (AcpiGbl_OriginalMode == ACPI_SYS_MODE_LEGACY) + { + Status = AcpiDisable (); + if (ACPI_FAILURE (Status)) + { + ACPI_WARNING ((AE_INFO, "AcpiDisable failed")); + } + } + return_VOID; +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evregion.c b/third_party/lib/acpica/source/components/events/evregion.c new file mode 100644 index 000000000..db4080a9d --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evregion.c @@ -0,0 +1,943 @@ +/****************************************************************************** + * + * Module Name: evregion - Operation Region support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evregion") + + +extern UINT8 AcpiGbl_DefaultAddressSpaces[]; + +/* Local prototypes */ + +static void +AcpiEvOrphanEcRegMethod ( + ACPI_NAMESPACE_NODE *EcDeviceNode); + +static ACPI_STATUS +AcpiEvRegRun ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInitializeOpRegions + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Execute _REG methods for all Operation Regions that have + * an installed default region handler. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInitializeOpRegions ( + void) +{ + ACPI_STATUS Status; + UINT32 i; + + + ACPI_FUNCTION_TRACE (EvInitializeOpRegions); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Run the _REG methods for OpRegions in each default address space */ + + AcpiGbl_RegMethodsEnabled = TRUE; + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) + { + /* + * Make sure the installed handler is the DEFAULT handler. If not the + * default, the _REG methods will have already been run (when the + * handler was installed) + */ + if (AcpiEvHasDefaultHandler (AcpiGbl_RootNode, + AcpiGbl_DefaultAddressSpaces[i])) + { + AcpiEvExecuteRegMethods (AcpiGbl_RootNode, + AcpiGbl_DefaultAddressSpaces[i], ACPI_REG_CONNECT); + } + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvAddressSpaceDispatch + * + * PARAMETERS: RegionObj - Internal region object + * FieldObj - Corresponding field. Can be NULL. + * Function - Read or Write operation + * RegionOffset - Where in the region to read or write + * BitWidth - Field width in bits (8, 16, 32, or 64) + * Value - Pointer to in or out value, must be + * a full 64-bit integer + * + * RETURN: Status + * + * DESCRIPTION: Dispatch an address space or operation region access to + * a previously installed handler. + * + * NOTE: During early initialization, we always install the default region + * handlers for Memory, I/O and PCI_Config. This ensures that these operation + * region address spaces are always available as per the ACPI specification. + * This is especially needed in order to support the execution of + * module-level AML code during loading of the ACPI tables. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvAddressSpaceDispatch ( + ACPI_OPERAND_OBJECT *RegionObj, + ACPI_OPERAND_OBJECT *FieldObj, + UINT32 Function, + UINT32 RegionOffset, + UINT32 BitWidth, + UINT64 *Value) +{ + ACPI_STATUS Status; + ACPI_ADR_SPACE_HANDLER Handler; + ACPI_ADR_SPACE_SETUP RegionSetup; + ACPI_OPERAND_OBJECT *HandlerDesc; + ACPI_OPERAND_OBJECT *RegionObj2; + void *RegionContext = NULL; + ACPI_CONNECTION_INFO *Context; + ACPI_PHYSICAL_ADDRESS Address; + + + ACPI_FUNCTION_TRACE (EvAddressSpaceDispatch); + + + RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); + if (!RegionObj2) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Ensure that there is a handler associated with this region */ + + HandlerDesc = RegionObj->Region.Handler; + if (!HandlerDesc) + { + ACPI_ERROR ((AE_INFO, + "No handler for Region [%4.4s] (%p) [%s]", + AcpiUtGetNodeName (RegionObj->Region.Node), + RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + + return_ACPI_STATUS (AE_NOT_EXIST); + } + + Context = HandlerDesc->AddressSpace.Context; + + /* + * It may be the case that the region has never been initialized. + * Some types of regions require special init code + */ + if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)) + { + /* This region has not been initialized yet, do it */ + + RegionSetup = HandlerDesc->AddressSpace.Setup; + if (!RegionSetup) + { + /* No initialization routine, exit with error */ + + ACPI_ERROR ((AE_INFO, + "No init routine for region(%p) [%s]", + RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* + * We must exit the interpreter because the region setup will + * potentially execute control methods (for example, the _REG method + * for this region) + */ + AcpiExExitInterpreter (); + + Status = RegionSetup (RegionObj, ACPI_REGION_ACTIVATE, + Context, &RegionContext); + + /* Re-enter the interpreter */ + + AcpiExEnterInterpreter (); + + /* Check for failure of the Region Setup */ + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "During region initialization: [%s]", + AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + return_ACPI_STATUS (Status); + } + + /* Region initialization may have been completed by RegionSetup */ + + if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)) + { + RegionObj->Region.Flags |= AOPOBJ_SETUP_COMPLETE; + + /* + * Save the returned context for use in all accesses to + * the handler for this particular region + */ + if (!(RegionObj2->Extra.RegionContext)) + { + RegionObj2->Extra.RegionContext = RegionContext; + } + } + } + + /* We have everything we need, we can invoke the address space handler */ + + Handler = HandlerDesc->AddressSpace.Handler; + Address = (RegionObj->Region.Address + RegionOffset); + + /* + * Special handling for GenericSerialBus and GeneralPurposeIo: + * There are three extra parameters that must be passed to the + * handler via the context: + * 1) Connection buffer, a resource template from Connection() op + * 2) Length of the above buffer + * 3) Actual access length from the AccessAs() op + * + * In addition, for GeneralPurposeIo, the Address and BitWidth fields + * are defined as follows: + * 1) Address is the pin number index of the field (bit offset from + * the previous Connection) + * 2) BitWidth is the actual bit length of the field (number of pins) + */ + if ((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) && + Context && + FieldObj) + { + /* Get the Connection (ResourceTemplate) buffer */ + + Context->Connection = FieldObj->Field.ResourceBuffer; + Context->Length = FieldObj->Field.ResourceLength; + Context->AccessLength = FieldObj->Field.AccessLength; + } + if ((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO) && + Context && + FieldObj) + { + /* Get the Connection (ResourceTemplate) buffer */ + + Context->Connection = FieldObj->Field.ResourceBuffer; + Context->Length = FieldObj->Field.ResourceLength; + Context->AccessLength = FieldObj->Field.AccessLength; + Address = FieldObj->Field.PinNumberIndex; + BitWidth = FieldObj->Field.BitLength; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", + &RegionObj->Region.Handler->AddressSpace, Handler, + ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + + if (!(HandlerDesc->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) + { + /* + * For handlers other than the default (supplied) handlers, we must + * exit the interpreter because the handler *might* block -- we don't + * know what it will do, so we can't hold the lock on the intepreter. + */ + AcpiExExitInterpreter(); + } + + /* Call the handler */ + + Status = Handler (Function, Address, BitWidth, Value, Context, + RegionObj2->Extra.RegionContext); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "Returned by Handler for [%s]", + AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + } + + if (!(HandlerDesc->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) + { + /* + * We just returned from a non-default handler, we must re-enter the + * interpreter + */ + AcpiExEnterInterpreter (); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvDetachRegion + * + * PARAMETERS: RegionObj - Region Object + * AcpiNsIsLocked - Namespace Region Already Locked? + * + * RETURN: None + * + * DESCRIPTION: Break the association between the handler and the region + * this is a two way association. + * + ******************************************************************************/ + +void +AcpiEvDetachRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsIsLocked) +{ + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *StartDesc; + ACPI_OPERAND_OBJECT **LastObjPtr; + ACPI_ADR_SPACE_SETUP RegionSetup; + void **RegionContext; + ACPI_OPERAND_OBJECT *RegionObj2; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvDetachRegion); + + + RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); + if (!RegionObj2) + { + return_VOID; + } + RegionContext = &RegionObj2->Extra.RegionContext; + + /* Get the address handler from the region object */ + + HandlerObj = RegionObj->Region.Handler; + if (!HandlerObj) + { + /* This region has no handler, all done */ + + return_VOID; + } + + /* Find this region in the handler's list */ + + ObjDesc = HandlerObj->AddressSpace.RegionList; + StartDesc = ObjDesc; + LastObjPtr = &HandlerObj->AddressSpace.RegionList; + + while (ObjDesc) + { + /* Is this the correct Region? */ + + if (ObjDesc == RegionObj) + { + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Removing Region %p from address handler %p\n", + RegionObj, HandlerObj)); + + /* This is it, remove it from the handler's list */ + + *LastObjPtr = ObjDesc->Region.Next; + ObjDesc->Region.Next = NULL; /* Must clear field */ + + if (AcpiNsIsLocked) + { + Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + } + + /* Now stop region accesses by executing the _REG method */ + + Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_DISCONNECT); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "from region _REG, [%s]", + AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + } + + if (AcpiNsIsLocked) + { + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + } + + /* + * If the region has been activated, call the setup handler with + * the deactivate notification + */ + if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE) + { + RegionSetup = HandlerObj->AddressSpace.Setup; + Status = RegionSetup (RegionObj, ACPI_REGION_DEACTIVATE, + HandlerObj->AddressSpace.Context, RegionContext); + + /* + * RegionContext should have been released by the deactivate + * operation. We don't need access to it anymore here. + */ + if (RegionContext) + { + *RegionContext = NULL; + } + + /* Init routine may fail, Just ignore errors */ + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "from region handler - deactivate, [%s]", + AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + } + + RegionObj->Region.Flags &= ~(AOPOBJ_SETUP_COMPLETE); + } + + /* + * Remove handler reference in the region + * + * NOTE: this doesn't mean that the region goes away, the region + * is just inaccessible as indicated to the _REG method + * + * If the region is on the handler's list, this must be the + * region's handler + */ + RegionObj->Region.Handler = NULL; + AcpiUtRemoveReference (HandlerObj); + + return_VOID; + } + + /* Walk the linked list of handlers */ + + LastObjPtr = &ObjDesc->Region.Next; + ObjDesc = ObjDesc->Region.Next; + + /* Prevent infinite loop if list is corrupted */ + + if (ObjDesc == StartDesc) + { + ACPI_ERROR ((AE_INFO, + "Circular handler list in region object %p", + RegionObj)); + return_VOID; + } + } + + /* If we get here, the region was not in the handler's region list */ + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Cannot remove region %p from address handler %p\n", + RegionObj, HandlerObj)); + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvAttachRegion + * + * PARAMETERS: HandlerObj - Handler Object + * RegionObj - Region Object + * AcpiNsIsLocked - Namespace Region Already Locked? + * + * RETURN: None + * + * DESCRIPTION: Create the association between the handler and the region + * this is a two way association. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvAttachRegion ( + ACPI_OPERAND_OBJECT *HandlerObj, + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsIsLocked) +{ + + ACPI_FUNCTION_TRACE (EvAttachRegion); + + + /* Install the region's handler */ + + if (RegionObj->Region.Handler) + { + return_ACPI_STATUS (AE_ALREADY_EXISTS); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Adding Region [%4.4s] %p to address handler %p [%s]\n", + AcpiUtGetNodeName (RegionObj->Region.Node), + RegionObj, HandlerObj, + AcpiUtGetRegionName (RegionObj->Region.SpaceId))); + + /* Link this region to the front of the handler's list */ + + RegionObj->Region.Next = HandlerObj->AddressSpace.RegionList; + HandlerObj->AddressSpace.RegionList = RegionObj; + RegionObj->Region.Handler = HandlerObj; + AcpiUtAddReference (HandlerObj); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvAssociateRegMethod + * + * PARAMETERS: RegionObj - Region object + * + * RETURN: Status + * + * DESCRIPTION: Find and associate _REG method to a region + * + ******************************************************************************/ + +void +AcpiEvAssociateRegMethod ( + ACPI_OPERAND_OBJECT *RegionObj) +{ + ACPI_NAME *RegNamePtr = (ACPI_NAME *) METHOD_NAME__REG; + ACPI_NAMESPACE_NODE *MethodNode; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *RegionObj2; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvAssociateRegMethod); + + + RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); + if (!RegionObj2) + { + return_VOID; + } + + Node = RegionObj->Region.Node->Parent; + + /* Find any "_REG" method associated with this region definition */ + + Status = AcpiNsSearchOneScope ( + *RegNamePtr, Node, ACPI_TYPE_METHOD, &MethodNode); + if (ACPI_SUCCESS (Status)) + { + /* + * The _REG method is optional and there can be only one per region + * definition. This will be executed when the handler is attached + * or removed + */ + RegionObj2->Extra.Method_REG = MethodNode; + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvExecuteRegMethod + * + * PARAMETERS: RegionObj - Region object + * Function - Passed to _REG: On (1) or Off (0) + * + * RETURN: Status + * + * DESCRIPTION: Execute _REG method for a region + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvExecuteRegMethod ( + ACPI_OPERAND_OBJECT *RegionObj, + UINT32 Function) +{ + ACPI_EVALUATE_INFO *Info; + ACPI_OPERAND_OBJECT *Args[3]; + ACPI_OPERAND_OBJECT *RegionObj2; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvExecuteRegMethod); + + + RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); + if (!RegionObj2) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + if (RegionObj2->Extra.Method_REG == NULL || + RegionObj->Region.Handler == NULL || + !AcpiGbl_RegMethodsEnabled) + { + return_ACPI_STATUS (AE_OK); + } + + /* _REG(DISCONNECT) should be paired with _REG(CONNECT) */ + + if ((Function == ACPI_REG_CONNECT && + RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED) || + (Function == ACPI_REG_DISCONNECT && + !(RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED))) + { + return_ACPI_STATUS (AE_OK); + } + + /* Allocate and initialize the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Info->PrefixNode = RegionObj2->Extra.Method_REG; + Info->RelativePathname = NULL; + Info->Parameters = Args; + Info->Flags = ACPI_IGNORE_RETURN_VALUE; + + /* + * The _REG method has two arguments: + * + * Arg0 - Integer: + * Operation region space ID Same value as RegionObj->Region.SpaceId + * + * Arg1 - Integer: + * connection status 1 for connecting the handler, 0 for disconnecting + * the handler (Passed as a parameter) + */ + Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId); + if (!Args[0]) + { + Status = AE_NO_MEMORY; + goto Cleanup1; + } + + Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function); + if (!Args[1]) + { + Status = AE_NO_MEMORY; + goto Cleanup2; + } + + Args[2] = NULL; /* Terminate list */ + + /* Execute the method, no return value */ + + ACPI_DEBUG_EXEC ( + AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL)); + + Status = AcpiNsEvaluate (Info); + AcpiUtRemoveReference (Args[1]); + + if (ACPI_FAILURE (Status)) + { + goto Cleanup2; + } + + if (Function == ACPI_REG_CONNECT) + { + RegionObj->Common.Flags |= AOPOBJ_REG_CONNECTED; + } + else + { + RegionObj->Common.Flags &= ~AOPOBJ_REG_CONNECTED; + } + +Cleanup2: + AcpiUtRemoveReference (Args[0]); + +Cleanup1: + ACPI_FREE (Info); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvExecuteRegMethods + * + * PARAMETERS: Node - Namespace node for the device + * SpaceId - The address space ID + * Function - Passed to _REG: On (1) or Off (0) + * + * RETURN: None + * + * DESCRIPTION: Run all _REG methods for the input Space ID; + * Note: assumes namespace is locked, or system init time. + * + ******************************************************************************/ + +void +AcpiEvExecuteRegMethods ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId, + UINT32 Function) +{ + ACPI_REG_WALK_INFO Info; + + + ACPI_FUNCTION_TRACE (EvExecuteRegMethods); + + Info.SpaceId = SpaceId; + Info.Function = Function; + Info.RegRunCount = 0; + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, + " Running _REG methods for SpaceId %s\n", + AcpiUtGetRegionName (Info.SpaceId))); + + /* + * Run all _REG methods for all Operation Regions for this space ID. This + * is a separate walk in order to handle any interdependencies between + * regions and _REG methods. (i.e. handlers must be installed for all + * regions of this Space ID before we can run any _REG methods) + */ + (void) AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, AcpiEvRegRun, NULL, &Info, NULL); + + /* Special case for EC: handle "orphan" _REG methods with no region */ + + if (SpaceId == ACPI_ADR_SPACE_EC) + { + AcpiEvOrphanEcRegMethod (Node); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, + " Executed %u _REG methods for SpaceId %s\n", + Info.RegRunCount, AcpiUtGetRegionName (Info.SpaceId))); + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvRegRun + * + * PARAMETERS: WalkNamespace callback + * + * DESCRIPTION: Run _REG method for region objects of the requested spaceID + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvRegRun ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_REG_WALK_INFO *Info; + + + Info = ACPI_CAST_PTR (ACPI_REG_WALK_INFO, Context); + + /* Convert and validate the device handle */ + + Node = AcpiNsValidateHandle (ObjHandle); + if (!Node) + { + return (AE_BAD_PARAMETER); + } + + /* + * We only care about regions.and objects that are allowed to have address + * space handlers + */ + if ((Node->Type != ACPI_TYPE_REGION) && + (Node != AcpiGbl_RootNode)) + { + return (AE_OK); + } + + /* Check for an existing internal object */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + /* No object, just exit */ + + return (AE_OK); + } + + /* Object is a Region */ + + if (ObjDesc->Region.SpaceId != Info->SpaceId) + { + /* This region is for a different address space, just ignore it */ + + return (AE_OK); + } + + Info->RegRunCount++; + Status = AcpiEvExecuteRegMethod (ObjDesc, Info->Function); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvOrphanEcRegMethod + * + * PARAMETERS: EcDeviceNode - Namespace node for an EC device + * + * RETURN: None + * + * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC + * device. This is a _REG method that has no corresponding region + * within the EC device scope. The orphan _REG method appears to + * have been enabled by the description of the ECDT in the ACPI + * specification: "The availability of the region space can be + * detected by providing a _REG method object underneath the + * Embedded Controller device." + * + * To quickly access the EC device, we use the EcDeviceNode used + * during EC handler installation. Otherwise, we would need to + * perform a time consuming namespace walk, executing _HID + * methods to find the EC device. + * + * MUTEX: Assumes the namespace is locked + * + ******************************************************************************/ + +static void +AcpiEvOrphanEcRegMethod ( + ACPI_NAMESPACE_NODE *EcDeviceNode) +{ + ACPI_HANDLE RegMethod; + ACPI_NAMESPACE_NODE *NextNode; + ACPI_STATUS Status; + ACPI_OBJECT_LIST Args; + ACPI_OBJECT Objects[2]; + + + ACPI_FUNCTION_TRACE (EvOrphanEcRegMethod); + + + if (!EcDeviceNode) + { + return_VOID; + } + + /* Namespace is currently locked, must release */ + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + /* Get a handle to a _REG method immediately under the EC device */ + + Status = AcpiGetHandle (EcDeviceNode, METHOD_NAME__REG, &RegMethod); + if (ACPI_FAILURE (Status)) + { + goto Exit; /* There is no _REG method present */ + } + + /* + * Execute the _REG method only if there is no Operation Region in + * this scope with the Embedded Controller space ID. Otherwise, it + * will already have been executed. Note, this allows for Regions + * with other space IDs to be present; but the code below will then + * execute the _REG method with the EmbeddedControl SpaceID argument. + */ + NextNode = AcpiNsGetNextNode (EcDeviceNode, NULL); + while (NextNode) + { + if ((NextNode->Type == ACPI_TYPE_REGION) && + (NextNode->Object) && + (NextNode->Object->Region.SpaceId == ACPI_ADR_SPACE_EC)) + { + goto Exit; /* Do not execute the _REG */ + } + + NextNode = AcpiNsGetNextNode (EcDeviceNode, NextNode); + } + + /* Evaluate the _REG(EmbeddedControl,Connect) method */ + + Args.Count = 2; + Args.Pointer = Objects; + Objects[0].Type = ACPI_TYPE_INTEGER; + Objects[0].Integer.Value = ACPI_ADR_SPACE_EC; + Objects[1].Type = ACPI_TYPE_INTEGER; + Objects[1].Integer.Value = ACPI_REG_CONNECT; + + Status = AcpiEvaluateObject (RegMethod, NULL, &Args, NULL); + +Exit: + /* We ignore all errors from above, don't care */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/events/evrgnini.c b/third_party/lib/acpica/source/components/events/evrgnini.c new file mode 100644 index 000000000..5bb177a20 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evrgnini.c @@ -0,0 +1,687 @@ +/****************************************************************************** + * + * Module Name: evrgnini- ACPI AddressSpace (OpRegion) init + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evrgnini") + +/* Local prototypes */ + +static BOOLEAN +AcpiEvIsPciRootBridge ( + ACPI_NAMESPACE_NODE *Node); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvSystemMemoryRegionSetup + * + * PARAMETERS: Handle - Region we are interested in + * Function - Start or stop + * HandlerContext - Address space handler context + * RegionContext - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Setup a SystemMemory operation region + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvSystemMemoryRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + ACPI_OPERAND_OBJECT *RegionDesc = (ACPI_OPERAND_OBJECT *) Handle; + ACPI_MEM_SPACE_CONTEXT *LocalRegionContext; + + + ACPI_FUNCTION_TRACE (EvSystemMemoryRegionSetup); + + + if (Function == ACPI_REGION_DEACTIVATE) + { + if (*RegionContext) + { + LocalRegionContext = (ACPI_MEM_SPACE_CONTEXT *) *RegionContext; + + /* Delete a cached mapping if present */ + + if (LocalRegionContext->MappedLength) + { + AcpiOsUnmapMemory (LocalRegionContext->MappedLogicalAddress, + LocalRegionContext->MappedLength); + } + ACPI_FREE (LocalRegionContext); + *RegionContext = NULL; + } + return_ACPI_STATUS (AE_OK); + } + + /* Create a new context */ + + LocalRegionContext = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_MEM_SPACE_CONTEXT)); + if (!(LocalRegionContext)) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Save the region length and address for use in the handler */ + + LocalRegionContext->Length = RegionDesc->Region.Length; + LocalRegionContext->Address = RegionDesc->Region.Address; + + *RegionContext = LocalRegionContext; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvIoSpaceRegionSetup + * + * PARAMETERS: Handle - Region we are interested in + * Function - Start or stop + * HandlerContext - Address space handler context + * RegionContext - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Setup a IO operation region + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvIoSpaceRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + ACPI_FUNCTION_TRACE (EvIoSpaceRegionSetup); + + + if (Function == ACPI_REGION_DEACTIVATE) + { + *RegionContext = NULL; + } + else + { + *RegionContext = HandlerContext; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvPciConfigRegionSetup + * + * PARAMETERS: Handle - Region we are interested in + * Function - Start or stop + * HandlerContext - Address space handler context + * RegionContext - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Setup a PCI_Config operation region + * + * MUTEX: Assumes namespace is not locked + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvPciConfigRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + ACPI_STATUS Status = AE_OK; + UINT64 PciValue; + ACPI_PCI_ID *PciId = *RegionContext; + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_NAMESPACE_NODE *ParentNode; + ACPI_NAMESPACE_NODE *PciRootNode; + ACPI_NAMESPACE_NODE *PciDeviceNode; + ACPI_OPERAND_OBJECT *RegionObj = (ACPI_OPERAND_OBJECT *) Handle; + + + ACPI_FUNCTION_TRACE (EvPciConfigRegionSetup); + + + HandlerObj = RegionObj->Region.Handler; + if (!HandlerObj) + { + /* + * No installed handler. This shouldn't happen because the dispatch + * routine checks before we get here, but we check again just in case. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Attempting to init a region %p, with no handler\n", RegionObj)); + return_ACPI_STATUS (AE_NOT_EXIST); + } + + *RegionContext = NULL; + if (Function == ACPI_REGION_DEACTIVATE) + { + if (PciId) + { + ACPI_FREE (PciId); + } + return_ACPI_STATUS (Status); + } + + ParentNode = RegionObj->Region.Node->Parent; + + /* + * Get the _SEG and _BBN values from the device upon which the handler + * is installed. + * + * We need to get the _SEG and _BBN objects relative to the PCI BUS device. + * This is the device the handler has been registered to handle. + */ + + /* + * If the AddressSpace.Node is still pointing to the root, we need + * to scan upward for a PCI Root bridge and re-associate the OpRegion + * handlers with that device. + */ + if (HandlerObj->AddressSpace.Node == AcpiGbl_RootNode) + { + /* Start search from the parent object */ + + PciRootNode = ParentNode; + while (PciRootNode != AcpiGbl_RootNode) + { + /* Get the _HID/_CID in order to detect a RootBridge */ + + if (AcpiEvIsPciRootBridge (PciRootNode)) + { + /* Install a handler for this PCI root bridge */ + + Status = AcpiInstallAddressSpaceHandler ( + (ACPI_HANDLE) PciRootNode, + ACPI_ADR_SPACE_PCI_CONFIG, + ACPI_DEFAULT_HANDLER, NULL, NULL); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_SAME_HANDLER) + { + /* + * It is OK if the handler is already installed on the + * root bridge. Still need to return a context object + * for the new PCI_Config operation region, however. + */ + Status = AE_OK; + } + else + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install PciConfig handler " + "for Root Bridge %4.4s", + AcpiUtGetNodeName (PciRootNode))); + } + } + break; + } + + PciRootNode = PciRootNode->Parent; + } + + /* PCI root bridge not found, use namespace root node */ + } + else + { + PciRootNode = HandlerObj->AddressSpace.Node; + } + + /* + * If this region is now initialized, we are done. + * (InstallAddressSpaceHandler could have initialized it) + */ + if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE) + { + return_ACPI_STATUS (AE_OK); + } + + /* Region is still not initialized. Create a new context */ + + PciId = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PCI_ID)); + if (!PciId) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * For PCI_Config space access, we need the segment, bus, device and + * function numbers. Acquire them here. + * + * Find the parent device object. (This allows the operation region to be + * within a subscope under the device, such as a control method.) + */ + PciDeviceNode = RegionObj->Region.Node; + while (PciDeviceNode && (PciDeviceNode->Type != ACPI_TYPE_DEVICE)) + { + PciDeviceNode = PciDeviceNode->Parent; + } + + if (!PciDeviceNode) + { + ACPI_FREE (PciId); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * Get the PCI device and function numbers from the _ADR object + * contained in the parent's scope. + */ + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, + PciDeviceNode, &PciValue); + + /* + * The default is zero, and since the allocation above zeroed the data, + * just do nothing on failure. + */ + if (ACPI_SUCCESS (Status)) + { + PciId->Device = ACPI_HIWORD (ACPI_LODWORD (PciValue)); + PciId->Function = ACPI_LOWORD (ACPI_LODWORD (PciValue)); + } + + /* The PCI segment number comes from the _SEG method */ + + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__SEG, + PciRootNode, &PciValue); + if (ACPI_SUCCESS (Status)) + { + PciId->Segment = ACPI_LOWORD (PciValue); + } + + /* The PCI bus number comes from the _BBN method */ + + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__BBN, + PciRootNode, &PciValue); + if (ACPI_SUCCESS (Status)) + { + PciId->Bus = ACPI_LOWORD (PciValue); + } + + /* Complete/update the PCI ID for this device */ + + Status = AcpiHwDerivePciId (PciId, PciRootNode, RegionObj->Region.Node); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (PciId); + return_ACPI_STATUS (Status); + } + + *RegionContext = PciId; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvIsPciRootBridge + * + * PARAMETERS: Node - Device node being examined + * + * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by + * examining the _HID and _CID for the device. + * + ******************************************************************************/ + +static BOOLEAN +AcpiEvIsPciRootBridge ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_STATUS Status; + ACPI_PNP_DEVICE_ID *Hid; + ACPI_PNP_DEVICE_ID_LIST *Cid; + UINT32 i; + BOOLEAN Match; + + + /* Get the _HID and check for a PCI Root Bridge */ + + Status = AcpiUtExecute_HID (Node, &Hid); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + + Match = AcpiUtIsPciRootBridge (Hid->String); + ACPI_FREE (Hid); + + if (Match) + { + return (TRUE); + } + + /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ + + Status = AcpiUtExecute_CID (Node, &Cid); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + + /* Check all _CIDs in the returned list */ + + for (i = 0; i < Cid->Count; i++) + { + if (AcpiUtIsPciRootBridge (Cid->Ids[i].String)) + { + ACPI_FREE (Cid); + return (TRUE); + } + } + + ACPI_FREE (Cid); + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvPciBarRegionSetup + * + * PARAMETERS: Handle - Region we are interested in + * Function - Start or stop + * HandlerContext - Address space handler context + * RegionContext - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Setup a PciBAR operation region + * + * MUTEX: Assumes namespace is not locked + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvPciBarRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + ACPI_FUNCTION_TRACE (EvPciBarRegionSetup); + + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvCmosRegionSetup + * + * PARAMETERS: Handle - Region we are interested in + * Function - Start or stop + * HandlerContext - Address space handler context + * RegionContext - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Setup a CMOS operation region + * + * MUTEX: Assumes namespace is not locked + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvCmosRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + ACPI_FUNCTION_TRACE (EvCmosRegionSetup); + + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvDefaultRegionSetup + * + * PARAMETERS: Handle - Region we are interested in + * Function - Start or stop + * HandlerContext - Address space handler context + * RegionContext - Region specific context + * + * RETURN: Status + * + * DESCRIPTION: Default region initialization + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvDefaultRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + ACPI_FUNCTION_TRACE (EvDefaultRegionSetup); + + + if (Function == ACPI_REGION_DEACTIVATE) + { + *RegionContext = NULL; + } + else + { + *RegionContext = HandlerContext; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInitializeRegion + * + * PARAMETERS: RegionObj - Region we are initializing + * AcpiNsLocked - Is namespace locked? + * + * RETURN: Status + * + * DESCRIPTION: Initializes the region, finds any _REG methods and saves them + * for execution at a later time + * + * Get the appropriate address space handler for a newly + * created region. + * + * This also performs address space specific initialization. For + * example, PCI regions must have an _ADR object that contains + * a PCI address in the scope of the definition. This address is + * required to perform an access to PCI config space. + * + * MUTEX: Interpreter should be unlocked, because we may run the _REG + * method for this region. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInitializeRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsLocked) +{ + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_ADR_SPACE_TYPE SpaceId; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_U32 (EvInitializeRegion, AcpiNsLocked); + + + if (!RegionObj) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (RegionObj->Common.Flags & AOPOBJ_OBJECT_INITIALIZED) + { + return_ACPI_STATUS (AE_OK); + } + + AcpiEvAssociateRegMethod (RegionObj); + RegionObj->Common.Flags |= AOPOBJ_OBJECT_INITIALIZED; + + Node = RegionObj->Region.Node->Parent; + SpaceId = RegionObj->Region.SpaceId; + + /* + * The following loop depends upon the root Node having no parent + * ie: AcpiGbl_RootNode->Parent being set to NULL + */ + while (Node) + { + /* Check to see if a handler exists */ + + HandlerObj = NULL; + ObjDesc = AcpiNsGetAttachedObject (Node); + if (ObjDesc) + { + /* Can only be a handler if the object exists */ + + switch (Node->Type) + { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + HandlerObj = ObjDesc->CommonNotify.Handler; + break; + + case ACPI_TYPE_METHOD: + /* + * If we are executing module level code, the original + * Node's object was replaced by this Method object and we + * saved the handler in the method object. + * + * See AcpiNsExecModuleCode + */ + if (ObjDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) + { + HandlerObj = ObjDesc->Method.Dispatch.Handler; + } + break; + + default: + + /* Ignore other objects */ + + break; + } + + HandlerObj = AcpiEvFindRegionHandler (SpaceId, HandlerObj); + if (HandlerObj) + { + /* Found correct handler */ + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Found handler %p for region %p in obj %p\n", + HandlerObj, RegionObj, ObjDesc)); + + Status = AcpiEvAttachRegion (HandlerObj, RegionObj, + AcpiNsLocked); + + /* + * Tell all users that this region is usable by + * running the _REG method + */ + if (AcpiNsLocked) + { + Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_CONNECT); + + if (AcpiNsLocked) + { + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + return_ACPI_STATUS (AE_OK); + } + } + + /* This node does not have the handler we need; Pop up one level */ + + Node = Node->Parent; + } + + /* If we get here, there is no handler for this region */ + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "No handler for RegionType %s(%X) (RegionObj %p)\n", + AcpiUtGetRegionName (SpaceId), SpaceId, RegionObj)); + + return_ACPI_STATUS (AE_NOT_EXIST); +} diff --git a/third_party/lib/acpica/source/components/events/evsci.c b/third_party/lib/acpica/source/components/events/evsci.c new file mode 100644 index 000000000..c35cba702 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evsci.c @@ -0,0 +1,282 @@ +/******************************************************************************* + * + * Module Name: evsci - System Control Interrupt configuration and + * legacy to ACPI mode state transition functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evsci") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static UINT32 ACPI_SYSTEM_XFACE +AcpiEvSciXruptHandler ( + void *Context); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvSciDispatch + * + * PARAMETERS: None + * + * RETURN: Status code indicates whether interrupt was handled. + * + * DESCRIPTION: Dispatch the SCI to all host-installed SCI handlers. + * + ******************************************************************************/ + +UINT32 +AcpiEvSciDispatch ( + void) +{ + ACPI_SCI_HANDLER_INFO *SciHandler; + ACPI_CPU_FLAGS Flags; + UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; + + + ACPI_FUNCTION_NAME (EvSciDispatch); + + + /* Are there any host-installed SCI handlers? */ + + if (!AcpiGbl_SciHandlerList) + { + return (IntStatus); + } + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Invoke all host-installed SCI handlers */ + + SciHandler = AcpiGbl_SciHandlerList; + while (SciHandler) + { + /* Invoke the installed handler (at interrupt level) */ + + IntStatus |= SciHandler->Address ( + SciHandler->Context); + + SciHandler = SciHandler->Next; + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return (IntStatus); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvSciXruptHandler + * + * PARAMETERS: Context - Calling Context + * + * RETURN: Status code indicates whether interrupt was handled. + * + * DESCRIPTION: Interrupt handler that will figure out what function or + * control method to call to deal with a SCI. + * + ******************************************************************************/ + +static UINT32 ACPI_SYSTEM_XFACE +AcpiEvSciXruptHandler ( + void *Context) +{ + ACPI_GPE_XRUPT_INFO *GpeXruptList = Context; + UINT32 InterruptHandled = ACPI_INTERRUPT_NOT_HANDLED; + + + ACPI_FUNCTION_TRACE (EvSciXruptHandler); + + + /* + * We are guaranteed by the ACPICA initialization/shutdown code that + * if this interrupt handler is installed, ACPI is enabled. + */ + + /* + * Fixed Events: + * Check for and dispatch any Fixed Events that have occurred + */ + InterruptHandled |= AcpiEvFixedEventDetect (); + + /* + * General Purpose Events: + * Check for and dispatch any GPEs that have occurred + */ + InterruptHandled |= AcpiEvGpeDetect (GpeXruptList); + + /* Invoke all host-installed SCI handlers */ + + InterruptHandled |= AcpiEvSciDispatch (); + + AcpiSciCount++; + return_UINT32 (InterruptHandled); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGpeXruptHandler + * + * PARAMETERS: Context - Calling Context + * + * RETURN: Status code indicates whether interrupt was handled. + * + * DESCRIPTION: Handler for GPE Block Device interrupts + * + ******************************************************************************/ + +UINT32 ACPI_SYSTEM_XFACE +AcpiEvGpeXruptHandler ( + void *Context) +{ + ACPI_GPE_XRUPT_INFO *GpeXruptList = Context; + UINT32 InterruptHandled = ACPI_INTERRUPT_NOT_HANDLED; + + + ACPI_FUNCTION_TRACE (EvGpeXruptHandler); + + + /* + * We are guaranteed by the ACPICA initialization/shutdown code that + * if this interrupt handler is installed, ACPI is enabled. + */ + + /* GPEs: Check for and dispatch any GPEs that have occurred */ + + InterruptHandled |= AcpiEvGpeDetect (GpeXruptList); + return_UINT32 (InterruptHandled); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiEvInstallSciHandler + * + * PARAMETERS: none + * + * RETURN: Status + * + * DESCRIPTION: Installs SCI handler. + * + ******************************************************************************/ + +UINT32 +AcpiEvInstallSciHandler ( + void) +{ + UINT32 Status = AE_OK; + + + ACPI_FUNCTION_TRACE (EvInstallSciHandler); + + + Status = AcpiOsInstallInterruptHandler ((UINT32) AcpiGbl_FADT.SciInterrupt, + AcpiEvSciXruptHandler, AcpiGbl_GpeXruptListHead); + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiEvRemoveAllSciHandlers + * + * PARAMETERS: none + * + * RETURN: AE_OK if handler uninstalled, AE_ERROR if handler was not + * installed to begin with + * + * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be + * taken. Remove all host-installed SCI handlers. + * + * Note: It doesn't seem important to disable all events or set the event + * enable registers to their original values. The OS should disable + * the SCI interrupt level when the handler is removed, so no more + * events will come in. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvRemoveAllSciHandlers ( + void) +{ + ACPI_SCI_HANDLER_INFO *SciHandler; + ACPI_CPU_FLAGS Flags; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (EvRemoveAllSciHandlers); + + + /* Just let the OS remove the handler and disable the level */ + + Status = AcpiOsRemoveInterruptHandler ((UINT32) AcpiGbl_FADT.SciInterrupt, + AcpiEvSciXruptHandler); + + if (!AcpiGbl_SciHandlerList) + { + return (Status); + } + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Free all host-installed SCI handlers */ + + while (AcpiGbl_SciHandlerList) + { + SciHandler = AcpiGbl_SciHandlerList; + AcpiGbl_SciHandlerList = SciHandler->Next; + ACPI_FREE (SciHandler); + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evxface.c b/third_party/lib/acpica/source/components/events/evxface.c new file mode 100644 index 000000000..edace7964 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evxface.c @@ -0,0 +1,1259 @@ +/****************************************************************************** + * + * Module Name: evxface - External interfaces for ACPI events + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evxface") + +#if (!ACPI_REDUCED_HARDWARE) + +/* Local prototypes */ + +static ACPI_STATUS +AcpiEvInstallGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + BOOLEAN IsRawHandler, + ACPI_GPE_HANDLER Address, + void *Context); + +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallNotifyHandler + * + * PARAMETERS: Device - The device for which notifies will be handled + * HandlerType - The type of handler: + * ACPI_SYSTEM_NOTIFY: System Handler (00-7F) + * ACPI_DEVICE_NOTIFY: Device Handler (80-FF) + * ACPI_ALL_NOTIFY: Both System and Device + * Handler - Address of the handler + * Context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for notifications on an ACPI Device, + * ThermalZone, or Processor object. + * + * NOTES: The Root namespace object may have only one handler for each + * type of notify (System/Device). Device/Thermal/Processor objects + * may have one device notify handler, and multiple system notify + * handlers. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallNotifyHandler ( + ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler, + void *Context) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device); + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_STATUS Status; + UINT32 i; + + + ACPI_FUNCTION_TRACE (AcpiInstallNotifyHandler); + + + /* Parameter validation */ + + if ((!Device) || (!Handler) || (!HandlerType) || + (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Root Object: + * Registering a notify handler on the root object indicates that the + * caller wishes to receive notifications for all objects. Note that + * only one global handler can be registered per notify type. + * Ensure that a handler is not already installed. + */ + if (Device == ACPI_ROOT_OBJECT) + { + for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) + { + if (HandlerType & (i+1)) + { + if (AcpiGbl_GlobalNotify[i].Handler) + { + Status = AE_ALREADY_EXISTS; + goto UnlockAndExit; + } + + AcpiGbl_GlobalNotify[i].Handler = Handler; + AcpiGbl_GlobalNotify[i].Context = Context; + } + } + + goto UnlockAndExit; /* Global notify handler installed, all done */ + } + + /* + * All Other Objects: + * Caller will only receive notifications specific to the target + * object. Note that only certain object types are allowed to + * receive notifications. + */ + + /* Are Notifies allowed on this object? */ + + if (!AcpiEvIsNotifyObject (Node)) + { + Status = AE_TYPE; + goto UnlockAndExit; + } + + /* Check for an existing internal object, might not exist */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + /* Create a new object */ + + ObjDesc = AcpiUtCreateInternalObject (Node->Type); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + /* Attach new object to the Node, remove local reference */ + + Status = AcpiNsAttachObject (Device, ObjDesc, Node->Type); + AcpiUtRemoveReference (ObjDesc); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + } + + /* Ensure that the handler is not already installed in the lists */ + + for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) + { + if (HandlerType & (i+1)) + { + HandlerObj = ObjDesc->CommonNotify.NotifyList[i]; + while (HandlerObj) + { + if (HandlerObj->Notify.Handler == Handler) + { + Status = AE_ALREADY_EXISTS; + goto UnlockAndExit; + } + + HandlerObj = HandlerObj->Notify.Next[i]; + } + } + } + + /* Create and populate a new notify handler object */ + + HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_NOTIFY); + if (!HandlerObj) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + HandlerObj->Notify.Node = Node; + HandlerObj->Notify.HandlerType = HandlerType; + HandlerObj->Notify.Handler = Handler; + HandlerObj->Notify.Context = Context; + + /* Install the handler at the list head(s) */ + + for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) + { + if (HandlerType & (i+1)) + { + HandlerObj->Notify.Next[i] = + ObjDesc->CommonNotify.NotifyList[i]; + + ObjDesc->CommonNotify.NotifyList[i] = HandlerObj; + } + } + + /* Add an extra reference if handler was installed in both lists */ + + if (HandlerType == ACPI_ALL_NOTIFY) + { + AcpiUtAddReference (HandlerObj); + } + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallNotifyHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveNotifyHandler + * + * PARAMETERS: Device - The device for which the handler is installed + * HandlerType - The type of handler: + * ACPI_SYSTEM_NOTIFY: System Handler (00-7F) + * ACPI_DEVICE_NOTIFY: Device Handler (80-FF) + * ACPI_ALL_NOTIFY: Both System and Device + * Handler - Address of the handler + * + * RETURN: Status + * + * DESCRIPTION: Remove a handler for notifies on an ACPI device + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveNotifyHandler ( + ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device); + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_OPERAND_OBJECT *PreviousHandlerObj; + ACPI_STATUS Status = AE_OK; + UINT32 i; + + + ACPI_FUNCTION_TRACE (AcpiRemoveNotifyHandler); + + + /* Parameter validation */ + + if ((!Device) || (!Handler) || (!HandlerType) || + (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Root Object. Global handlers are removed here */ + + if (Device == ACPI_ROOT_OBJECT) + { + for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) + { + if (HandlerType & (i+1)) + { + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (!AcpiGbl_GlobalNotify[i].Handler || + (AcpiGbl_GlobalNotify[i].Handler != Handler)) + { + Status = AE_NOT_EXIST; + goto UnlockAndExit; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Removing global notify handler\n")); + + AcpiGbl_GlobalNotify[i].Handler = NULL; + AcpiGbl_GlobalNotify[i].Context = NULL; + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + /* Make sure all deferred notify tasks are completed */ + + AcpiOsWaitEventsComplete (); + } + } + + return_ACPI_STATUS (AE_OK); + } + + /* All other objects: Are Notifies allowed on this object? */ + + if (!AcpiEvIsNotifyObject (Node)) + { + return_ACPI_STATUS (AE_TYPE); + } + + /* Must have an existing internal object */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Internal object exists. Find the handler and remove it */ + + for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) + { + if (HandlerType & (i+1)) + { + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + HandlerObj = ObjDesc->CommonNotify.NotifyList[i]; + PreviousHandlerObj = NULL; + + /* Attempt to find the handler in the handler list */ + + while (HandlerObj && + (HandlerObj->Notify.Handler != Handler)) + { + PreviousHandlerObj = HandlerObj; + HandlerObj = HandlerObj->Notify.Next[i]; + } + + if (!HandlerObj) + { + Status = AE_NOT_EXIST; + goto UnlockAndExit; + } + + /* Remove the handler object from the list */ + + if (PreviousHandlerObj) /* Handler is not at the list head */ + { + PreviousHandlerObj->Notify.Next[i] = + HandlerObj->Notify.Next[i]; + } + else /* Handler is at the list head */ + { + ObjDesc->CommonNotify.NotifyList[i] = + HandlerObj->Notify.Next[i]; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + /* Make sure all deferred notify tasks are completed */ + + AcpiOsWaitEventsComplete (); + AcpiUtRemoveReference (HandlerObj); + } + } + + return_ACPI_STATUS (Status); + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallExceptionHandler + * + * PARAMETERS: Handler - Pointer to the handler function for the + * event + * + * RETURN: Status + * + * DESCRIPTION: Saves the pointer to the handler function + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallExceptionHandler ( + ACPI_EXCEPTION_HANDLER Handler) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallExceptionHandler); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Don't allow two handlers. */ + + if (AcpiGbl_ExceptionHandler) + { + Status = AE_ALREADY_EXISTS; + goto Cleanup; + } + + /* Install the handler */ + + AcpiGbl_ExceptionHandler = Handler; + +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler) + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiInstallSciHandler + * + * PARAMETERS: Address - Address of the handler + * Context - Value passed to the handler on each SCI + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a System Control Interrupt. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallSciHandler ( + ACPI_SCI_HANDLER Address, + void *Context) +{ + ACPI_SCI_HANDLER_INFO *NewSciHandler; + ACPI_SCI_HANDLER_INFO *SciHandler; + ACPI_CPU_FLAGS Flags; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallSciHandler); + + + if (!Address) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Allocate and init a handler object */ + + NewSciHandler = ACPI_ALLOCATE (sizeof (ACPI_SCI_HANDLER_INFO)); + if (!NewSciHandler) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + NewSciHandler->Address = Address; + NewSciHandler->Context = Context; + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Lock list during installation */ + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + SciHandler = AcpiGbl_SciHandlerList; + + /* Ensure handler does not already exist */ + + while (SciHandler) + { + if (Address == SciHandler->Address) + { + Status = AE_ALREADY_EXISTS; + goto UnlockAndExit; + } + + SciHandler = SciHandler->Next; + } + + /* Install the new handler into the global list (at head) */ + + NewSciHandler->Next = AcpiGbl_SciHandlerList; + AcpiGbl_SciHandlerList = NewSciHandler; + + +UnlockAndExit: + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + +Exit: + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (NewSciHandler); + } + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallSciHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveSciHandler + * + * PARAMETERS: Address - Address of the handler + * + * RETURN: Status + * + * DESCRIPTION: Remove a handler for a System Control Interrupt. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveSciHandler ( + ACPI_SCI_HANDLER Address) +{ + ACPI_SCI_HANDLER_INFO *PrevSciHandler; + ACPI_SCI_HANDLER_INFO *NextSciHandler; + ACPI_CPU_FLAGS Flags; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiRemoveSciHandler); + + + if (!Address) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Remove the SCI handler with lock */ + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + PrevSciHandler = NULL; + NextSciHandler = AcpiGbl_SciHandlerList; + while (NextSciHandler) + { + if (NextSciHandler->Address == Address) + { + /* Unlink and free the SCI handler info block */ + + if (PrevSciHandler) + { + PrevSciHandler->Next = NextSciHandler->Next; + } + else + { + AcpiGbl_SciHandlerList = NextSciHandler->Next; + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + ACPI_FREE (NextSciHandler); + goto UnlockAndExit; + } + + PrevSciHandler = NextSciHandler; + NextSciHandler = NextSciHandler->Next; + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + Status = AE_NOT_EXIST; + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveSciHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallGlobalEventHandler + * + * PARAMETERS: Handler - Pointer to the global event handler function + * Context - Value passed to the handler on each event + * + * RETURN: Status + * + * DESCRIPTION: Saves the pointer to the handler function. The global handler + * is invoked upon each incoming GPE and Fixed Event. It is + * invoked at interrupt level at the time of the event dispatch. + * Can be used to update event counters, etc. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallGlobalEventHandler ( + ACPI_GBL_EVENT_HANDLER Handler, + void *Context) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler); + + + /* Parameter validation */ + + if (!Handler) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Don't allow two handlers. */ + + if (AcpiGbl_GlobalEventHandler) + { + Status = AE_ALREADY_EXISTS; + goto Cleanup; + } + + AcpiGbl_GlobalEventHandler = Handler; + AcpiGbl_GlobalEventHandlerContext = Context; + + +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallFixedEventHandler + * + * PARAMETERS: Event - Event type to enable. + * Handler - Pointer to the handler function for the + * event + * Context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Saves the pointer to the handler function and then enables the + * event. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallFixedEventHandler ( + UINT32 Event, + ACPI_EVENT_HANDLER Handler, + void *Context) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler); + + + /* Parameter validation */ + + if (Event > ACPI_EVENT_MAX) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Do not allow multiple handlers */ + + if (AcpiGbl_FixedEventHandlers[Event].Handler) + { + Status = AE_ALREADY_EXISTS; + goto Cleanup; + } + + /* Install the handler before enabling the event */ + + AcpiGbl_FixedEventHandlers[Event].Handler = Handler; + AcpiGbl_FixedEventHandlers[Event].Context = Context; + + Status = AcpiEnableEvent (Event, 0); + if (ACPI_FAILURE (Status)) + { + ACPI_WARNING ((AE_INFO, + "Could not enable fixed event - %s (%u)", + AcpiUtGetEventName (Event), Event)); + + /* Remove the handler */ + + AcpiGbl_FixedEventHandlers[Event].Handler = NULL; + AcpiGbl_FixedEventHandlers[Event].Context = NULL; + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Enabled fixed event %s (%X), Handler=%p\n", + AcpiUtGetEventName (Event), Event, Handler)); + } + + +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveFixedEventHandler + * + * PARAMETERS: Event - Event type to disable. + * Handler - Address of the handler + * + * RETURN: Status + * + * DESCRIPTION: Disables the event and unregisters the event handler. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveFixedEventHandler ( + UINT32 Event, + ACPI_EVENT_HANDLER Handler) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler); + + + /* Parameter validation */ + + if (Event > ACPI_EVENT_MAX) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Disable the event before removing the handler */ + + Status = AcpiDisableEvent (Event, 0); + + /* Always Remove the handler */ + + AcpiGbl_FixedEventHandlers[Event].Handler = NULL; + AcpiGbl_FixedEventHandlers[Event].Context = NULL; + + if (ACPI_FAILURE (Status)) + { + ACPI_WARNING ((AE_INFO, + "Could not disable fixed event - %s (%u)", + AcpiUtGetEventName (Event), Event)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Disabled fixed event - %s (%X)\n", + AcpiUtGetEventName (Event), Event)); + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiEvInstallGpeHandler + * + * PARAMETERS: GpeDevice - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * GpeNumber - The GPE number within the GPE block + * Type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * IsRawHandler - Whether this GPE should be handled using + * the special GPE handler mode. + * Address - Address of the handler + * Context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Internal function to install a handler for a General Purpose + * Event. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvInstallGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + BOOLEAN IsRawHandler, + ACPI_GPE_HANDLER Address, + void *Context) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_GPE_HANDLER_INFO *Handler; + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (EvInstallGpeHandler); + + + /* Parameter validation */ + + if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Allocate and init handler object (before lock) */ + + Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO)); + if (!Handler) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto FreeAndExit; + } + + /* Make sure that there isn't a handler there already */ + + if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) + { + Status = AE_ALREADY_EXISTS; + goto FreeAndExit; + } + + Handler->Address = Address; + Handler->Context = Context; + Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode; + Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags & + (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK)); + + /* + * If the GPE is associated with a method, it may have been enabled + * automatically during initialization, in which case it has to be + * disabled now to avoid spurious execution of the handler. + */ + if (((ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) == + ACPI_GPE_DISPATCH_METHOD) || + (ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) == + ACPI_GPE_DISPATCH_NOTIFY)) && + GpeEventInfo->RuntimeCount) + { + Handler->OriginallyEnabled = TRUE; + (void) AcpiEvRemoveGpeReference (GpeEventInfo); + + /* Sanity check of original type against new type */ + + if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK)) + { + ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)")); + } + } + + /* Install the handler */ + + GpeEventInfo->Dispatch.Handler = Handler; + + /* Setup up dispatch flags to indicate handler (vs. method/notify) */ + + GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); + GpeEventInfo->Flags |= (UINT8) (Type | (IsRawHandler ? + ACPI_GPE_DISPATCH_RAW_HANDLER : ACPI_GPE_DISPATCH_HANDLER)); + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); + +FreeAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + ACPI_FREE (Handler); + goto UnlockAndExit; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallGpeHandler + * + * PARAMETERS: GpeDevice - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * GpeNumber - The GPE number within the GPE block + * Type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * Address - Address of the handler + * Context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a General Purpose Event. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + ACPI_GPE_HANDLER Address, + void *Context) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler); + + + Status = AcpiEvInstallGpeHandler (GpeDevice, GpeNumber, Type, + FALSE, Address, Context); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallGpeRawHandler + * + * PARAMETERS: GpeDevice - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * GpeNumber - The GPE number within the GPE block + * Type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * Address - Address of the handler + * Context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a General Purpose Event. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallGpeRawHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + ACPI_GPE_HANDLER Address, + void *Context) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallGpeRawHandler); + + + Status = AcpiEvInstallGpeHandler (GpeDevice, GpeNumber, Type, + TRUE, Address, Context); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallGpeRawHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveGpeHandler + * + * PARAMETERS: GpeDevice - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * GpeNumber - The event to remove a handler + * Address - Address of the handler + * + * RETURN: Status + * + * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + ACPI_GPE_HANDLER Address) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_GPE_HANDLER_INFO *Handler; + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler); + + + /* Parameter validation */ + + if (!Address) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Make sure that a handler is indeed installed */ + + if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != + ACPI_GPE_DISPATCH_HANDLER) && + (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != + ACPI_GPE_DISPATCH_RAW_HANDLER)) + { + Status = AE_NOT_EXIST; + goto UnlockAndExit; + } + + /* Make sure that the installed handler is the same */ + + if (GpeEventInfo->Dispatch.Handler->Address != Address) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Remove the handler */ + + Handler = GpeEventInfo->Dispatch.Handler; + GpeEventInfo->Dispatch.Handler = NULL; + + /* Restore Method node (if any), set dispatch flags */ + + GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode; + GpeEventInfo->Flags &= + ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); + GpeEventInfo->Flags |= Handler->OriginalFlags; + + /* + * If the GPE was previously associated with a method and it was + * enabled, it should be enabled at this point to restore the + * post-initialization configuration. + */ + if (((ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) == + ACPI_GPE_DISPATCH_METHOD) || + (ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) == + ACPI_GPE_DISPATCH_NOTIFY)) && + Handler->OriginallyEnabled) + { + (void) AcpiEvAddGpeReference (GpeEventInfo); + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + + /* Make sure all deferred GPE tasks are completed */ + + AcpiOsWaitEventsComplete (); + + /* Now we can free the handler object */ + + ACPI_FREE (Handler); + return_ACPI_STATUS (Status); + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiAcquireGlobalLock + * + * PARAMETERS: Timeout - How long the caller is willing to wait + * Handle - Where the handle to the lock is returned + * (if acquired) + * + * RETURN: Status + * + * DESCRIPTION: Acquire the ACPI Global Lock + * + * Note: Allows callers with the same thread ID to acquire the global lock + * multiple times. In other words, externally, the behavior of the global lock + * is identical to an AML mutex. On the first acquire, a new handle is + * returned. On any subsequent calls to acquire by the same thread, the same + * handle is returned. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiAcquireGlobalLock ( + UINT16 Timeout, + UINT32 *Handle) +{ + ACPI_STATUS Status; + + + if (!Handle) + { + return (AE_BAD_PARAMETER); + } + + /* Must lock interpreter to prevent race conditions */ + + AcpiExEnterInterpreter (); + + Status = AcpiExAcquireMutexObject (Timeout, + AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ()); + + if (ACPI_SUCCESS (Status)) + { + /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */ + + *Handle = AcpiGbl_GlobalLockHandle; + } + + AcpiExExitInterpreter (); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock) + + +/******************************************************************************* + * + * FUNCTION: AcpiReleaseGlobalLock + * + * PARAMETERS: Handle - Returned from AcpiAcquireGlobalLock + * + * RETURN: Status + * + * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReleaseGlobalLock ( + UINT32 Handle) +{ + ACPI_STATUS Status; + + + if (!Handle || (Handle != AcpiGbl_GlobalLockHandle)) + { + return (AE_NOT_ACQUIRED); + } + + Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock) + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evxfevnt.c b/third_party/lib/acpica/source/components/events/evxfevnt.c new file mode 100644 index 000000000..9991751c6 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evxfevnt.c @@ -0,0 +1,430 @@ +/****************************************************************************** + * + * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evxfevnt") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/******************************************************************************* + * + * FUNCTION: AcpiEnable + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Transfers the system into ACPI mode. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnable ( + void) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (AcpiEnable); + + + /* ACPI tables must be present */ + + if (AcpiGbl_FadtIndex == ACPI_INVALID_TABLE_INDEX) + { + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* If the Hardware Reduced flag is set, machine is always in acpi mode */ + + if (AcpiGbl_ReducedHardware) + { + return_ACPI_STATUS (AE_OK); + } + + /* Check current mode */ + + if (AcpiHwGetMode() == ACPI_SYS_MODE_ACPI) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "System is already in ACPI mode\n")); + } + else + { + /* Transition to ACPI mode */ + + Status = AcpiHwSetMode (ACPI_SYS_MODE_ACPI); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "Could not transition to ACPI mode")); + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Transition to ACPI mode successful\n")); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnable) + + +/******************************************************************************* + * + * FUNCTION: AcpiDisable + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDisable ( + void) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (AcpiDisable); + + + /* If the Hardware Reduced flag is set, machine is always in acpi mode */ + + if (AcpiGbl_ReducedHardware) + { + return_ACPI_STATUS (AE_OK); + } + + if (AcpiHwGetMode() == ACPI_SYS_MODE_LEGACY) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "System is already in legacy (non-ACPI) mode\n")); + } + else + { + /* Transition to LEGACY mode */ + + Status = AcpiHwSetMode (ACPI_SYS_MODE_LEGACY); + + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, + "Could not exit ACPI mode to legacy mode")); + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "ACPI mode disabled\n")); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiDisable) + + +/******************************************************************************* + * + * FUNCTION: AcpiEnableEvent + * + * PARAMETERS: Event - The fixed eventto be enabled + * Flags - Reserved + * + * RETURN: Status + * + * DESCRIPTION: Enable an ACPI event (fixed) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnableEvent ( + UINT32 Event, + UINT32 Flags) +{ + ACPI_STATUS Status = AE_OK; + UINT32 Value; + + + ACPI_FUNCTION_TRACE (AcpiEnableEvent); + + + /* Decode the Fixed Event */ + + if (Event > ACPI_EVENT_MAX) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Enable the requested fixed event (by writing a one to the enable + * register bit) + */ + Status = AcpiWriteBitRegister ( + AcpiGbl_FixedEventInfo[Event].EnableRegisterId, + ACPI_ENABLE_EVENT); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Make sure that the hardware responded */ + + Status = AcpiReadBitRegister ( + AcpiGbl_FixedEventInfo[Event].EnableRegisterId, &Value); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (Value != 1) + { + ACPI_ERROR ((AE_INFO, + "Could not enable %s event", AcpiUtGetEventName (Event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnableEvent) + + +/******************************************************************************* + * + * FUNCTION: AcpiDisableEvent + * + * PARAMETERS: Event - The fixed event to be disabled + * Flags - Reserved + * + * RETURN: Status + * + * DESCRIPTION: Disable an ACPI event (fixed) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDisableEvent ( + UINT32 Event, + UINT32 Flags) +{ + ACPI_STATUS Status = AE_OK; + UINT32 Value; + + + ACPI_FUNCTION_TRACE (AcpiDisableEvent); + + + /* Decode the Fixed Event */ + + if (Event > ACPI_EVENT_MAX) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Disable the requested fixed event (by writing a zero to the enable + * register bit) + */ + Status = AcpiWriteBitRegister ( + AcpiGbl_FixedEventInfo[Event].EnableRegisterId, + ACPI_DISABLE_EVENT); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiReadBitRegister ( + AcpiGbl_FixedEventInfo[Event].EnableRegisterId, &Value); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (Value != 0) + { + ACPI_ERROR ((AE_INFO, + "Could not disable %s events", AcpiUtGetEventName (Event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiDisableEvent) + + +/******************************************************************************* + * + * FUNCTION: AcpiClearEvent + * + * PARAMETERS: Event - The fixed event to be cleared + * + * RETURN: Status + * + * DESCRIPTION: Clear an ACPI event (fixed) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiClearEvent ( + UINT32 Event) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (AcpiClearEvent); + + + /* Decode the Fixed Event */ + + if (Event > ACPI_EVENT_MAX) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Clear the requested fixed event (By writing a one to the status + * register bit) + */ + Status = AcpiWriteBitRegister ( + AcpiGbl_FixedEventInfo[Event].StatusRegisterId, + ACPI_CLEAR_STATUS); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiClearEvent) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetEventStatus + * + * PARAMETERS: Event - The fixed event + * EventStatus - Where the current status of the event will + * be returned + * + * RETURN: Status + * + * DESCRIPTION: Obtains and returns the current status of the event + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetEventStatus ( + UINT32 Event, + ACPI_EVENT_STATUS *EventStatus) +{ + ACPI_STATUS Status; + ACPI_EVENT_STATUS LocalEventStatus = 0; + UINT32 InByte; + + + ACPI_FUNCTION_TRACE (AcpiGetEventStatus); + + + if (!EventStatus) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Decode the Fixed Event */ + + if (Event > ACPI_EVENT_MAX) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Fixed event currently can be dispatched? */ + + if (AcpiGbl_FixedEventHandlers[Event].Handler) + { + LocalEventStatus |= ACPI_EVENT_FLAG_HAS_HANDLER; + } + + /* Fixed event currently enabled? */ + + Status = AcpiReadBitRegister ( + AcpiGbl_FixedEventInfo[Event].EnableRegisterId, &InByte); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (InByte) + { + LocalEventStatus |= + (ACPI_EVENT_FLAG_ENABLED | ACPI_EVENT_FLAG_ENABLE_SET); + } + + /* Fixed event currently active? */ + + Status = AcpiReadBitRegister ( + AcpiGbl_FixedEventInfo[Event].StatusRegisterId, &InByte); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (InByte) + { + LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET; + } + + (*EventStatus) = LocalEventStatus; + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiGetEventStatus) + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evxfgpe.c b/third_party/lib/acpica/source/components/events/evxfgpe.c new file mode 100644 index 000000000..1d467d9ab --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evxfgpe.c @@ -0,0 +1,1101 @@ +/****************************************************************************** + * + * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evxfgpe") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/******************************************************************************* + * + * FUNCTION: AcpiUpdateAllGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Complete GPE initialization and enable all GPEs that have + * associated _Lxx or _Exx methods and are not pointed to by any + * device _PRW methods (this indicates that these GPEs are + * generally intended for system or device wakeup. Such GPEs + * have to be enabled directly when the devices whose _PRW + * methods point to them are set up for wakeup signaling.) + * + * NOTE: Should be called after any GPEs are added to the system. Primarily, + * after the system _PRW methods have been run, but also after a GPE Block + * Device has been added or if any new GPE methods have been added via a + * dynamic table load. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUpdateAllGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiUpdateAllGpes); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (AcpiGbl_AllGpesInitialized) + { + goto UnlockAndExit; + } + + Status = AcpiEvWalkGpeList (AcpiEvInitializeGpeBlock, NULL); + if (ACPI_SUCCESS (Status)) + { + AcpiGbl_AllGpesInitialized = TRUE; + } + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiUpdateAllGpes) + + +/******************************************************************************* + * + * FUNCTION: AcpiEnableGpe + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is + * hardware-enabled. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnableGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_STATUS Status = AE_BAD_PARAMETER; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiEnableGpe); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* + * Ensure that we have a valid GPE number and that there is some way + * of handling the GPE (handler or a GPE method). In other words, we + * won't allow a valid GPE to be enabled if there is no way to handle it. + */ + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (GpeEventInfo) + { + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != + ACPI_GPE_DISPATCH_NONE) + { + Status = AcpiEvAddGpeReference (GpeEventInfo); + } + else + { + Status = AE_NO_HANDLER; + } + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnableGpe) + + +/******************************************************************************* + * + * FUNCTION: AcpiDisableGpe + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Remove a reference to a GPE. When the last reference is + * removed, only then is the GPE disabled (for runtime GPEs), or + * the GPE mask bit disabled (for wake GPEs) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDisableGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_STATUS Status = AE_BAD_PARAMETER; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiDisableGpe); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (GpeEventInfo) + { + Status = AcpiEvRemoveGpeReference (GpeEventInfo); + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiDisableGpe) + + +/******************************************************************************* + * + * FUNCTION: AcpiSetGpe + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * Action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE + * + * RETURN: Status + * + * DESCRIPTION: Enable or disable an individual GPE. This function bypasses + * the reference count mechanism used in the AcpiEnableGpe(), + * AcpiDisableGpe() interfaces. + * This API is typically used by the GPE raw handler mode driver + * to switch between the polling mode and the interrupt mode after + * the driver has enabled the GPE. + * The APIs should be invoked in this order: + * AcpiEnableGpe() <- Ensure the reference count > 0 + * AcpiSetGpe(ACPI_GPE_DISABLE) <- Enter polling mode + * AcpiSetGpe(ACPI_GPE_ENABLE) <- Leave polling mode + * AcpiDisableGpe() <- Decrease the reference count + * + * Note: If a GPE is shared by 2 silicon components, then both the drivers + * should support GPE polling mode or disabling the GPE for long period + * for one driver may break the other. So use it with care since all + * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT8 Action) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiSetGpe); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Perform the action */ + + switch (Action) + { + case ACPI_GPE_ENABLE: + + Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); + break; + + case ACPI_GPE_DISABLE: + + Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); + break; + + default: + + Status = AE_BAD_PARAMETER; + break; + } + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiSetGpe) + + +/******************************************************************************* + * + * FUNCTION: AcpiMarkGpeForWake + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Mark a GPE as having the ability to wake the system. Simply + * sets the ACPI_GPE_CAN_WAKE flag. + * + * Some potential callers of AcpiSetupGpeForWake may know in advance that + * there won't be any notify handlers installed for device wake notifications + * from the given GPE (one example is a button GPE in Linux). For these cases, + * AcpiMarkGpeForWake should be used instead of AcpiSetupGpeForWake. + * This will set the ACPI_GPE_CAN_WAKE flag for the GPE without trying to + * setup implicit wake notification for it (since there's no handler method). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiMarkGpeForWake ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_STATUS Status = AE_BAD_PARAMETER; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiMarkGpeForWake); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (GpeEventInfo) + { + /* Mark the GPE as a possible wake event */ + + GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE; + Status = AE_OK; + } + + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiMarkGpeForWake) + + +/******************************************************************************* + * + * FUNCTION: AcpiSetupGpeForWake + * + * PARAMETERS: WakeDevice - Device associated with the GPE (via _PRW) + * GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Mark a GPE as having the ability to wake the system. This + * interface is intended to be used as the host executes the + * _PRW methods (Power Resources for Wake) in the system tables. + * Each _PRW appears under a Device Object (The WakeDevice), and + * contains the info for the wake GPE associated with the + * WakeDevice. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetupGpeForWake ( + ACPI_HANDLE WakeDevice, + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_STATUS Status; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_NAMESPACE_NODE *DeviceNode; + ACPI_GPE_NOTIFY_INFO *Notify; + ACPI_GPE_NOTIFY_INFO *NewNotify; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiSetupGpeForWake); + + + /* Parameter Validation */ + + if (!WakeDevice) + { + /* + * By forcing WakeDevice to be valid, we automatically enable the + * implicit notify feature on all hosts. + */ + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Handle root object case */ + + if (WakeDevice == ACPI_ROOT_OBJECT) + { + DeviceNode = AcpiGbl_RootNode; + } + else + { + DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, WakeDevice); + } + + /* Validate WakeDevice is of type Device */ + + if (DeviceNode->Type != ACPI_TYPE_DEVICE) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Allocate a new notify object up front, in case it is needed. + * Memory allocation while holding a spinlock is a big no-no + * on some hosts. + */ + NewNotify = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_NOTIFY_INFO)); + if (!NewNotify) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* + * If there is no method or handler for this GPE, then the + * WakeDevice will be notified whenever this GPE fires. This is + * known as an "implicit notify". Note: The GPE is assumed to be + * level-triggered (for windows compatibility). + */ + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_NONE) + { + /* + * This is the first device for implicit notify on this GPE. + * Just set the flags here, and enter the NOTIFY block below. + */ + GpeEventInfo->Flags = + (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); + } + + /* + * If we already have an implicit notify on this GPE, add + * this device to the notify list. + */ + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == + ACPI_GPE_DISPATCH_NOTIFY) + { + /* Ensure that the device is not already in the list */ + + Notify = GpeEventInfo->Dispatch.NotifyList; + while (Notify) + { + if (Notify->DeviceNode == DeviceNode) + { + Status = AE_ALREADY_EXISTS; + goto UnlockAndExit; + } + Notify = Notify->Next; + } + + /* Add this device to the notify list for this GPE */ + + NewNotify->DeviceNode = DeviceNode; + NewNotify->Next = GpeEventInfo->Dispatch.NotifyList; + GpeEventInfo->Dispatch.NotifyList = NewNotify; + NewNotify = NULL; + } + + /* Mark the GPE as a possible wake event */ + + GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE; + Status = AE_OK; + + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + + /* Delete the notify object if it was not used above */ + + if (NewNotify) + { + ACPI_FREE (NewNotify); + } + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiSetupGpeForWake) + + +/******************************************************************************* + * + * FUNCTION: AcpiSetGpeWakeMask + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * Action - Enable or Disable + * + * RETURN: Status + * + * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must + * already be marked as a WAKE GPE. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetGpeWakeMask ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT8 Action) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_CPU_FLAGS Flags; + UINT32 RegisterBit; + + + ACPI_FUNCTION_TRACE (AcpiSetGpeWakeMask); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* + * Ensure that we have a valid GPE number and that this GPE is in + * fact a wake GPE + */ + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + if (!(GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE)) + { + Status = AE_TYPE; + goto UnlockAndExit; + } + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + if (!GpeRegisterInfo) + { + Status = AE_NOT_EXIST; + goto UnlockAndExit; + } + + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); + + /* Perform the action */ + + switch (Action) + { + case ACPI_GPE_ENABLE: + + ACPI_SET_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit); + break; + + case ACPI_GPE_DISABLE: + + ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit); + break; + + default: + + ACPI_ERROR ((AE_INFO, "%u, Invalid action", Action)); + Status = AE_BAD_PARAMETER; + break; + } + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiSetGpeWakeMask) + + +/******************************************************************************* + * + * FUNCTION: AcpiClearGpe + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Clear an ACPI event (general purpose) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiClearGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiClearGpe); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + Status = AcpiHwClearGpe (GpeEventInfo); + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiClearGpe) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetGpeStatus + * + * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 + * GpeNumber - GPE level within the GPE block + * EventStatus - Where the current status of the event + * will be returned + * + * RETURN: Status + * + * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetGpeStatus ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + ACPI_EVENT_STATUS *EventStatus) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiGetGpeStatus); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Obtain status on the requested GPE number */ + + Status = AcpiHwGetGpeStatus (GpeEventInfo, EventStatus); + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetGpeStatus) + + +/******************************************************************************* + * + * FUNCTION: AcpiFinishGpe + * + * PARAMETERS: GpeDevice - Namespace node for the GPE Block + * (NULL for FADT defined GPEs) + * GpeNumber - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE + * processing. Intended for use by asynchronous host-installed + * GPE handlers. The GPE is only reenabled if the EnableForRun bit + * is set in the GPE info. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiFinishGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber) +{ + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_STATUS Status; + ACPI_CPU_FLAGS Flags; + + + ACPI_FUNCTION_TRACE (AcpiFinishGpe); + + + Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); + + /* Ensure that we have a valid GPE number */ + + GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); + if (!GpeEventInfo) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + Status = AcpiEvFinishGpe (GpeEventInfo); + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiFinishGpe) + + +/****************************************************************************** + * + * FUNCTION: AcpiDisableAllGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDisableAllGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiDisableAllGpes); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwDisableAllGpes (); + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiDisableAllGpes) + + +/****************************************************************************** + * + * FUNCTION: AcpiEnableAllRuntimeGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnableAllRuntimeGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiEnableAllRuntimeGpes); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwEnableAllRuntimeGpes (); + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnableAllRuntimeGpes) + + +/****************************************************************************** + * + * FUNCTION: AcpiEnableAllWakeupGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "wakeup" GPEs and disable all of the other GPEs, in + * all GPE blocks. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnableAllWakeupGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiEnableAllWakeupGpes); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwEnableAllWakeupGpes (); + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnableAllWakeupGpes) + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallGpeBlock + * + * PARAMETERS: GpeDevice - Handle to the parent GPE Block Device + * GpeBlockAddress - Address and SpaceID + * RegisterCount - Number of GPE register pairs in the block + * InterruptNumber - H/W interrupt for the block + * + * RETURN: Status + * + * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not + * enabled here. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallGpeBlock ( + ACPI_HANDLE GpeDevice, + ACPI_GENERIC_ADDRESS *GpeBlockAddress, + UINT32 RegisterCount, + UINT32 InterruptNumber) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_GPE_BLOCK_INFO *GpeBlock; + + + ACPI_FUNCTION_TRACE (AcpiInstallGpeBlock); + + + if ((!GpeDevice) || + (!GpeBlockAddress) || + (!RegisterCount)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Node = AcpiNsValidateHandle (GpeDevice); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Validate the parent device */ + + if (Node->Type != ACPI_TYPE_DEVICE) + { + Status = AE_TYPE; + goto UnlockAndExit; + } + + if (Node->Object) + { + Status = AE_ALREADY_EXISTS; + goto UnlockAndExit; + } + + /* + * For user-installed GPE Block Devices, the GpeBlockBaseNumber + * is always zero + */ + Status = AcpiEvCreateGpeBlock (Node, GpeBlockAddress->Address, + GpeBlockAddress->SpaceId, RegisterCount, + 0, InterruptNumber, &GpeBlock); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Install block in the DeviceObject attached to the node */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + /* + * No object, create a new one (Device nodes do not always have + * an attached object) + */ + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_DEVICE); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + Status = AcpiNsAttachObject (Node, ObjDesc, ACPI_TYPE_DEVICE); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + } + + /* Now install the GPE block in the DeviceObject */ + + ObjDesc->Device.GpeBlock = GpeBlock; + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallGpeBlock) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveGpeBlock + * + * PARAMETERS: GpeDevice - Handle to the parent GPE Block Device + * + * RETURN: Status + * + * DESCRIPTION: Remove a previously installed block of GPE registers + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveGpeBlock ( + ACPI_HANDLE GpeDevice) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (AcpiRemoveGpeBlock); + + + if (!GpeDevice) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Node = AcpiNsValidateHandle (GpeDevice); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Validate the parent device */ + + if (Node->Type != ACPI_TYPE_DEVICE) + { + Status = AE_TYPE; + goto UnlockAndExit; + } + + /* Get the DeviceObject attached to the node */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc || + !ObjDesc->Device.GpeBlock) + { + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Delete the GPE block (but not the DeviceObject) */ + + Status = AcpiEvDeleteGpeBlock (ObjDesc->Device.GpeBlock); + if (ACPI_SUCCESS (Status)) + { + ObjDesc->Device.GpeBlock = NULL; + } + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveGpeBlock) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetGpeDevice + * + * PARAMETERS: Index - System GPE index (0-CurrentGpeCount) + * GpeDevice - Where the parent GPE Device is returned + * + * RETURN: Status + * + * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL + * gpe device indicates that the gpe number is contained in one of + * the FADT-defined gpe blocks. Otherwise, the GPE block device. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetGpeDevice ( + UINT32 Index, + ACPI_HANDLE *GpeDevice) +{ + ACPI_GPE_DEVICE_INFO Info; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiGetGpeDevice); + + + if (!GpeDevice) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (Index >= AcpiCurrentGpeCount) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Setup and walk the GPE list */ + + Info.Index = Index; + Info.Status = AE_NOT_EXIST; + Info.GpeDevice = NULL; + Info.NextBlockBaseIndex = 0; + + Status = AcpiEvWalkGpeList (AcpiEvGetGpeDevice, &Info); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + *GpeDevice = ACPI_CAST_PTR (ACPI_HANDLE, Info.GpeDevice); + return_ACPI_STATUS (Info.Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetGpeDevice) + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/events/evxfregn.c b/third_party/lib/acpica/source/components/events/evxfregn.c new file mode 100644 index 000000000..8537640d6 --- /dev/null +++ b/third_party/lib/acpica/source/components/events/evxfregn.c @@ -0,0 +1,281 @@ +/****************************************************************************** + * + * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and + * Address Spaces. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" + +#define _COMPONENT ACPI_EVENTS + ACPI_MODULE_NAME ("evxfregn") + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallAddressSpaceHandler + * + * PARAMETERS: Device - Handle for the device + * SpaceId - The address space ID + * Handler - Address of the handler + * Setup - Address of the setup function + * Context - Value passed to the handler on each access + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. + * + * NOTE: This function should only be called after AcpiEnableSubsystem has + * been called. This is because any _REG methods associated with the Space ID + * are executed here, and these methods can only be safely executed after + * the default handlers have been installed and the hardware has been + * initialized (via AcpiEnableSubsystem.) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallAddressSpaceHandler); + + + /* Parameter validation */ + + if (!Device) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Convert and validate the device handle */ + + Node = AcpiNsValidateHandle (Device); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Install the handler for all Regions for this Space ID */ + + Status = AcpiEvInstallSpaceHandler ( + Node, SpaceId, Handler, Setup, Context); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Run all _REG methods for this address space */ + + AcpiEvExecuteRegMethods (Node, SpaceId, ACPI_REG_CONNECT); + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallAddressSpaceHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveAddressSpaceHandler + * + * PARAMETERS: Device - Handle for the device + * SpaceId - The address space ID + * Handler - Address of the handler + * + * RETURN: Status + * + * DESCRIPTION: Remove a previously installed handler. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *HandlerObj; + ACPI_OPERAND_OBJECT *RegionObj; + ACPI_OPERAND_OBJECT **LastObjPtr; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiRemoveAddressSpaceHandler); + + + /* Parameter validation */ + + if (!Device) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Convert and validate the device handle */ + + Node = AcpiNsValidateHandle (Device); + if (!Node || + ((Node->Type != ACPI_TYPE_DEVICE) && + (Node->Type != ACPI_TYPE_PROCESSOR) && + (Node->Type != ACPI_TYPE_THERMAL) && + (Node != AcpiGbl_RootNode))) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Make sure the internal object exists */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + Status = AE_NOT_EXIST; + goto UnlockAndExit; + } + + /* Find the address handler the user requested */ + + HandlerObj = ObjDesc->CommonNotify.Handler; + LastObjPtr = &ObjDesc->CommonNotify.Handler; + while (HandlerObj) + { + /* We have a handler, see if user requested this one */ + + if (HandlerObj->AddressSpace.SpaceId == SpaceId) + { + /* Handler must be the same as the installed handler */ + + if (HandlerObj->AddressSpace.Handler != Handler) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Matched SpaceId, first dereference this in the Regions */ + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Removing address handler %p(%p) for region %s " + "on Device %p(%p)\n", + HandlerObj, Handler, AcpiUtGetRegionName (SpaceId), + Node, ObjDesc)); + + RegionObj = HandlerObj->AddressSpace.RegionList; + + /* Walk the handler's region list */ + + while (RegionObj) + { + /* + * First disassociate the handler from the region. + * + * NOTE: this doesn't mean that the region goes away + * The region is just inaccessible as indicated to + * the _REG method + */ + AcpiEvDetachRegion (RegionObj, TRUE); + + /* + * Walk the list: Just grab the head because the + * DetachRegion removed the previous head. + */ + RegionObj = HandlerObj->AddressSpace.RegionList; + + } + + /* Remove this Handler object from the list */ + + *LastObjPtr = HandlerObj->AddressSpace.Next; + + /* Now we can delete the handler object */ + + AcpiUtRemoveReference (HandlerObj); + goto UnlockAndExit; + } + + /* Walk the linked list of handlers */ + + LastObjPtr = &HandlerObj->AddressSpace.Next; + HandlerObj = HandlerObj->AddressSpace.Next; + } + + /* The handler does not exist */ + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n", + Handler, AcpiUtGetRegionName (SpaceId), SpaceId, Node, ObjDesc)); + + Status = AE_NOT_EXIST; + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveAddressSpaceHandler) diff --git a/third_party/lib/acpica/source/components/executer/exconfig.c b/third_party/lib/acpica/source/components/executer/exconfig.c new file mode 100644 index 000000000..60aea38c6 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exconfig.c @@ -0,0 +1,681 @@ +/****************************************************************************** + * + * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acdispat.h" +#include "acevents.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exconfig") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiExAddTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_OPERAND_OBJECT **DdbHandle); + +static ACPI_STATUS +AcpiExRegionRead ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Length, + UINT8 *Buffer); + + +/******************************************************************************* + * + * FUNCTION: AcpiExAddTable + * + * PARAMETERS: Table - Pointer to raw table + * ParentNode - Where to load the table (scope) + * DdbHandle - Where to return the table handle. + * + * RETURN: Status + * + * DESCRIPTION: Common function to Install and Load an ACPI table with a + * returned table handle. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExAddTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_OPERAND_OBJECT **DdbHandle) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + ACPI_OWNER_ID OwnerId; + + + ACPI_FUNCTION_TRACE (ExAddTable); + + + /* Create an object to be the table handle */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Init the table handle */ + + ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID; + ObjDesc->Reference.Class = ACPI_REFCLASS_TABLE; + *DdbHandle = ObjDesc; + + /* Install the new table into the local data structures */ + + ObjDesc->Reference.Value = TableIndex; + + /* Add the table to the namespace */ + + Status = AcpiNsLoadTable (TableIndex, ParentNode); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ObjDesc); + *DdbHandle = NULL; + return_ACPI_STATUS (Status); + } + + /* Execute any module-level code that was found in the table */ + + AcpiExExitInterpreter (); + AcpiNsExecModuleCodeList (); + AcpiExEnterInterpreter (); + + /* + * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is + * responsible for discovering any new wake GPEs by running _PRW methods + * that may have been loaded by this table. + */ + Status = AcpiTbGetOwnerId (TableIndex, &OwnerId); + if (ACPI_SUCCESS (Status)) + { + AcpiEvUpdateGpes (OwnerId); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExLoadTableOp + * + * PARAMETERS: WalkState - Current state with operands + * ReturnDesc - Where to store the return object + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table from the RSDT/XSDT + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExLoadTableOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **ReturnDesc) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_NAMESPACE_NODE *ParentNode; + ACPI_NAMESPACE_NODE *StartNode; + ACPI_NAMESPACE_NODE *ParameterNode = NULL; + ACPI_OPERAND_OBJECT *DdbHandle; + ACPI_TABLE_HEADER *Table; + UINT32 TableIndex; + + + ACPI_FUNCTION_TRACE (ExLoadTableOp); + + + /* Find the ACPI table in the RSDT/XSDT */ + + Status = AcpiTbFindTable ( + Operand[0]->String.Pointer, + Operand[1]->String.Pointer, + Operand[2]->String.Pointer, &TableIndex); + if (ACPI_FAILURE (Status)) + { + if (Status != AE_NOT_FOUND) + { + return_ACPI_STATUS (Status); + } + + /* Table not found, return an Integer=0 and AE_OK */ + + DdbHandle = AcpiUtCreateIntegerObject ((UINT64) 0); + if (!DdbHandle) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + *ReturnDesc = DdbHandle; + return_ACPI_STATUS (AE_OK); + } + + /* Default nodes */ + + StartNode = WalkState->ScopeInfo->Scope.Node; + ParentNode = AcpiGbl_RootNode; + + /* RootPath (optional parameter) */ + + if (Operand[3]->String.Length > 0) + { + /* + * Find the node referenced by the RootPathString. This is the + * location within the namespace where the table will be loaded. + */ + Status = AcpiNsGetNode (StartNode, Operand[3]->String.Pointer, + ACPI_NS_SEARCH_PARENT, &ParentNode); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* ParameterPath (optional parameter) */ + + if (Operand[4]->String.Length > 0) + { + if ((Operand[4]->String.Pointer[0] != AML_ROOT_PREFIX) && + (Operand[4]->String.Pointer[0] != AML_PARENT_PREFIX)) + { + /* + * Path is not absolute, so it will be relative to the node + * referenced by the RootPathString (or the NS root if omitted) + */ + StartNode = ParentNode; + } + + /* Find the node referenced by the ParameterPathString */ + + Status = AcpiNsGetNode (StartNode, Operand[4]->String.Pointer, + ACPI_NS_SEARCH_PARENT, &ParameterNode); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* Load the table into the namespace */ + + Status = AcpiExAddTable (TableIndex, ParentNode, &DdbHandle); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Parameter Data (optional) */ + + if (ParameterNode) + { + /* Store the parameter data into the optional parameter object */ + + Status = AcpiExStore (Operand[5], + ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode), WalkState); + if (ACPI_FAILURE (Status)) + { + (void) AcpiExUnloadTable (DdbHandle); + + AcpiUtRemoveReference (DdbHandle); + return_ACPI_STATUS (Status); + } + } + + Status = AcpiGetTableByIndex (TableIndex, &Table); + if (ACPI_SUCCESS (Status)) + { + ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:")); + AcpiTbPrintTableHeader (0, Table); + } + + /* Invoke table handler if present */ + + if (AcpiGbl_TableHandler) + { + (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table, + AcpiGbl_TableHandlerContext); + } + + *ReturnDesc = DdbHandle; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExRegionRead + * + * PARAMETERS: ObjDesc - Region descriptor + * Length - Number of bytes to read + * Buffer - Pointer to where to put the data + * + * RETURN: Status + * + * DESCRIPTION: Read data from an operation region. The read starts from the + * beginning of the region. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExRegionRead ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Length, + UINT8 *Buffer) +{ + ACPI_STATUS Status; + UINT64 Value; + UINT32 RegionOffset = 0; + UINT32 i; + + + /* Bytewise reads */ + + for (i = 0; i < Length; i++) + { + Status = AcpiEvAddressSpaceDispatch (ObjDesc, NULL, ACPI_READ, + RegionOffset, 8, &Value); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *Buffer = (UINT8) Value; + Buffer++; + RegionOffset++; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExLoadOp + * + * PARAMETERS: ObjDesc - Region or Buffer/Field where the table will be + * obtained + * Target - Where a handle to the table will be stored + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table from a field or operation region + * + * NOTE: Region Fields (Field, BankField, IndexFields) are resolved to buffer + * objects before this code is reached. + * + * If source is an operation region, it must refer to SystemMemory, as + * per the ACPI specification. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExLoadOp ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *Target, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *DdbHandle; + ACPI_TABLE_HEADER *TableHeader; + ACPI_TABLE_HEADER *Table; + UINT32 TableIndex; + ACPI_STATUS Status; + UINT32 Length; + + + ACPI_FUNCTION_TRACE (ExLoadOp); + + + /* Source Object can be either an OpRegion or a Buffer/Field */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_REGION: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Load table from Region %p\n", ObjDesc)); + + /* Region must be SystemMemory (from ACPI spec) */ + + if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * If the Region Address and Length have not been previously + * evaluated, evaluate them now and save the results. + */ + if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + Status = AcpiDsGetRegionArguments (ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* Get the table header first so we can get the table length */ + + TableHeader = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); + if (!TableHeader) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), + ACPI_CAST_PTR (UINT8, TableHeader)); + Length = TableHeader->Length; + ACPI_FREE (TableHeader); + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Must have at least an ACPI table header */ + + if (Length < sizeof (ACPI_TABLE_HEADER)) + { + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } + + /* + * The original implementation simply mapped the table, with no copy. + * However, the memory region is not guaranteed to remain stable and + * we must copy the table to a local buffer. For example, the memory + * region is corrupted after suspend on some machines. Dynamically + * loaded tables are usually small, so this overhead is minimal. + * + * The latest implementation (5/2009) does not use a mapping at all. + * We use the low-level operation region interface to read the table + * instead of the obvious optimization of using a direct mapping. + * This maintains a consistent use of operation regions across the + * entire subsystem. This is important if additional processing must + * be performed in the (possibly user-installed) operation region + * handler. For example, AcpiExec and ASLTS depend on this. + */ + + /* Allocate a buffer for the table */ + + Table = ACPI_ALLOCATE (Length); + if (!Table) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Read the entire table */ + + Status = AcpiExRegionRead (ObjDesc, Length, + ACPI_CAST_PTR (UINT8, Table)); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (Table); + return_ACPI_STATUS (Status); + } + break; + + case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Load table from Buffer or Field %p\n", ObjDesc)); + + /* Must have at least an ACPI table header */ + + if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) + { + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } + + /* Get the actual table length from the table header */ + + TableHeader = ACPI_CAST_PTR ( + ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer); + Length = TableHeader->Length; + + /* Table cannot extend beyond the buffer */ + + if (Length > ObjDesc->Buffer.Length) + { + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); + } + if (Length < sizeof (ACPI_TABLE_HEADER)) + { + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } + + /* + * Copy the table from the buffer because the buffer could be + * modified or even deleted in the future + */ + Table = ACPI_ALLOCATE (Length); + if (!Table) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + memcpy (Table, TableHeader, Length); + break; + + default: + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Install the new table into the local data structures */ + + ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:")); + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + + Status = AcpiTbInstallStandardTable (ACPI_PTR_TO_PHYSADDR (Table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, TRUE, TRUE, + &TableIndex); + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (Status)) + { + /* Delete allocated table buffer */ + + ACPI_FREE (Table); + return_ACPI_STATUS (Status); + } + + /* + * Note: Now table is "INSTALLED", it must be validated before + * loading. + */ + Status = AcpiTbValidateTable ( + &AcpiGbl_RootTableList.Tables[TableIndex]); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Add the table to the namespace. + * + * Note: Load the table objects relative to the root of the namespace. + * This appears to go against the ACPI specification, but we do it for + * compatibility with other ACPI implementations. + */ + Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle); + if (ACPI_FAILURE (Status)) + { + /* On error, TablePtr was deallocated above */ + + return_ACPI_STATUS (Status); + } + + /* Store the DdbHandle into the Target operand */ + + Status = AcpiExStore (DdbHandle, Target, WalkState); + if (ACPI_FAILURE (Status)) + { + (void) AcpiExUnloadTable (DdbHandle); + + /* TablePtr was deallocated above */ + + AcpiUtRemoveReference (DdbHandle); + return_ACPI_STATUS (Status); + } + + /* Remove the reference by added by AcpiExStore above */ + + AcpiUtRemoveReference (DdbHandle); + + /* Invoke table handler if present */ + + if (AcpiGbl_TableHandler) + { + (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table, + AcpiGbl_TableHandlerContext); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExUnloadTable + * + * PARAMETERS: DdbHandle - Handle to a previously loaded table + * + * RETURN: Status + * + * DESCRIPTION: Unload an ACPI table + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExUnloadTable ( + ACPI_OPERAND_OBJECT *DdbHandle) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *TableDesc = DdbHandle; + UINT32 TableIndex; + ACPI_TABLE_HEADER *Table; + + + ACPI_FUNCTION_TRACE (ExUnloadTable); + + + /* + * Temporarily emit a warning so that the ASL for the machine can be + * hopefully obtained. This is to say that the Unload() operator is + * extremely rare if not completely unused. + */ + ACPI_WARNING ((AE_INFO, + "Received request to unload an ACPI table")); + + /* + * Validate the handle + * Although the handle is partially validated in AcpiExReconfiguration() + * when it calls AcpiExResolveOperands(), the handle is more completely + * validated here. + * + * Handle must be a valid operand object of type reference. Also, the + * DdbHandle must still be marked valid (table has not been previously + * unloaded) + */ + if ((!DdbHandle) || + (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) || + (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) || + (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID))) + { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Get the table index from the DdbHandle */ + + TableIndex = TableDesc->Reference.Value; + + /* Ensure the table is still loaded */ + + if (!AcpiTbIsTableLoaded (TableIndex)) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Invoke table handler if present */ + + if (AcpiGbl_TableHandler) + { + Status = AcpiGetTableByIndex (TableIndex, &Table); + if (ACPI_SUCCESS (Status)) + { + (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, Table, + AcpiGbl_TableHandlerContext); + } + } + + /* Delete the portion of the namespace owned by this table */ + + Status = AcpiTbDeleteNamespaceByOwner (TableIndex); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + (void) AcpiTbReleaseOwnerId (TableIndex); + AcpiTbSetTableLoadedFlag (TableIndex, FALSE); + + /* + * Invalidate the handle. We do this because the handle may be stored + * in a named object and may not be actually deleted until much later. + */ + DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID; + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/executer/exconvrt.c b/third_party/lib/acpica/source/components/executer/exconvrt.c new file mode 100644 index 000000000..6f756d7e5 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exconvrt.c @@ -0,0 +1,743 @@ +/****************************************************************************** + * + * Module Name: exconvrt - Object conversion routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exconvrt") + +/* Local prototypes */ + +static UINT32 +AcpiExConvertToAscii ( + UINT64 Integer, + UINT16 Base, + UINT8 *String, + UINT8 MaxLength); + + +/******************************************************************************* + * + * FUNCTION: AcpiExConvertToInteger + * + * PARAMETERS: ObjDesc - Object to be converted. Must be an + * Integer, Buffer, or String + * ResultDesc - Where the new Integer object is returned + * Flags - Used for string conversion + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to an integer. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExConvertToInteger ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + UINT32 Flags) +{ + ACPI_OPERAND_OBJECT *ReturnDesc; + UINT8 *Pointer; + UINT64 Result; + UINT32 i; + UINT32 Count; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (ExConvertToInteger, ObjDesc); + + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + /* No conversion necessary */ + + *ResultDesc = ObjDesc; + return_ACPI_STATUS (AE_OK); + + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + + /* Note: Takes advantage of common buffer/string fields */ + + Pointer = ObjDesc->Buffer.Pointer; + Count = ObjDesc->Buffer.Length; + break; + + default: + + return_ACPI_STATUS (AE_TYPE); + } + + /* + * Convert the buffer/string to an integer. Note that both buffers and + * strings are treated as raw data - we don't convert ascii to hex for + * strings. + * + * There are two terminating conditions for the loop: + * 1) The size of an integer has been reached, or + * 2) The end of the buffer or string has been reached + */ + Result = 0; + + /* String conversion is different than Buffer conversion */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_STRING: + /* + * Convert string to an integer - for most cases, the string must be + * hexadecimal as per the ACPI specification. The only exception (as + * of ACPI 3.0) is that the ToInteger() operator allows both decimal + * and hexadecimal strings (hex prefixed with "0x"). + */ + Status = AcpiUtStrtoul64 ((char *) Pointer, Flags, &Result); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + break; + + case ACPI_TYPE_BUFFER: + + /* Check for zero-length buffer */ + + if (!Count) + { + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); + } + + /* Transfer no more than an integer's worth of data */ + + if (Count > AcpiGbl_IntegerByteWidth) + { + Count = AcpiGbl_IntegerByteWidth; + } + + /* + * Convert buffer to an integer - we simply grab enough raw data + * from the buffer to fill an integer + */ + for (i = 0; i < Count; i++) + { + /* + * Get next byte and shift it into the Result. + * Little endian is used, meaning that the first byte of the buffer + * is the LSB of the integer + */ + Result |= (((UINT64) Pointer[i]) << (i * 8)); + } + break; + + default: + + /* No other types can get here */ + + break; + } + + /* Create a new integer */ + + ReturnDesc = AcpiUtCreateIntegerObject (Result); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Result))); + + /* Save the Result */ + + (void) AcpiExTruncateFor32bitTable (ReturnDesc); + *ResultDesc = ReturnDesc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExConvertToBuffer + * + * PARAMETERS: ObjDesc - Object to be converted. Must be an + * Integer, Buffer, or String + * ResultDesc - Where the new buffer object is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to a Buffer + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExConvertToBuffer ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc) +{ + ACPI_OPERAND_OBJECT *ReturnDesc; + UINT8 *NewBuf; + + + ACPI_FUNCTION_TRACE_PTR (ExConvertToBuffer, ObjDesc); + + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_BUFFER: + + /* No conversion necessary */ + + *ResultDesc = ObjDesc; + return_ACPI_STATUS (AE_OK); + + + case ACPI_TYPE_INTEGER: + /* + * Create a new Buffer object. + * Need enough space for one integer + */ + ReturnDesc = AcpiUtCreateBufferObject (AcpiGbl_IntegerByteWidth); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the integer to the buffer, LSB first */ + + NewBuf = ReturnDesc->Buffer.Pointer; + memcpy (NewBuf, &ObjDesc->Integer.Value, AcpiGbl_IntegerByteWidth); + break; + + case ACPI_TYPE_STRING: + /* + * Create a new Buffer object + * Size will be the string length + * + * NOTE: Add one to the string length to include the null terminator. + * The ACPI spec is unclear on this subject, but there is existing + * ASL/AML code that depends on the null being transferred to the new + * buffer. + */ + ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE) + ObjDesc->String.Length + 1); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the string to the buffer */ + + NewBuf = ReturnDesc->Buffer.Pointer; + strncpy ((char *) NewBuf, (char *) ObjDesc->String.Pointer, + ObjDesc->String.Length); + break; + + default: + + return_ACPI_STATUS (AE_TYPE); + } + + /* Mark buffer initialized */ + + ReturnDesc->Common.Flags |= AOPOBJ_DATA_VALID; + *ResultDesc = ReturnDesc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExConvertToAscii + * + * PARAMETERS: Integer - Value to be converted + * Base - ACPI_STRING_DECIMAL or ACPI_STRING_HEX + * String - Where the string is returned + * DataWidth - Size of data item to be converted, in bytes + * + * RETURN: Actual string length + * + * DESCRIPTION: Convert an ACPI Integer to a hex or decimal string + * + ******************************************************************************/ + +static UINT32 +AcpiExConvertToAscii ( + UINT64 Integer, + UINT16 Base, + UINT8 *String, + UINT8 DataWidth) +{ + UINT64 Digit; + UINT32 i; + UINT32 j; + UINT32 k = 0; + UINT32 HexLength; + UINT32 DecimalLength; + UINT32 Remainder; + BOOLEAN SupressZeros; + + + ACPI_FUNCTION_ENTRY (); + + + switch (Base) + { + case 10: + + /* Setup max length for the decimal number */ + + switch (DataWidth) + { + case 1: + + DecimalLength = ACPI_MAX8_DECIMAL_DIGITS; + break; + + case 4: + + DecimalLength = ACPI_MAX32_DECIMAL_DIGITS; + break; + + case 8: + default: + + DecimalLength = ACPI_MAX64_DECIMAL_DIGITS; + break; + } + + SupressZeros = TRUE; /* No leading zeros */ + Remainder = 0; + + for (i = DecimalLength; i > 0; i--) + { + /* Divide by nth factor of 10 */ + + Digit = Integer; + for (j = 0; j < i; j++) + { + (void) AcpiUtShortDivide (Digit, 10, &Digit, &Remainder); + } + + /* Handle leading zeros */ + + if (Remainder != 0) + { + SupressZeros = FALSE; + } + + if (!SupressZeros) + { + String[k] = (UINT8) (ACPI_ASCII_ZERO + Remainder); + k++; + } + } + break; + + case 16: + + /* HexLength: 2 ascii hex chars per data byte */ + + HexLength = ACPI_MUL_2 (DataWidth); + for (i = 0, j = (HexLength-1); i < HexLength; i++, j--) + { + /* Get one hex digit, most significant digits first */ + + String[k] = (UINT8) + AcpiUtHexToAsciiChar (Integer, ACPI_MUL_4 (j)); + k++; + } + break; + + default: + return (0); + } + + /* + * Since leading zeros are suppressed, we must check for the case where + * the integer equals 0 + * + * Finally, null terminate the string and return the length + */ + if (!k) + { + String [0] = ACPI_ASCII_ZERO; + k = 1; + } + + String [k] = 0; + return ((UINT32) k); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExConvertToString + * + * PARAMETERS: ObjDesc - Object to be converted. Must be an + * Integer, Buffer, or String + * ResultDesc - Where the string object is returned + * Type - String flags (base and conversion type) + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to a string + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExConvertToString ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + UINT32 Type) +{ + ACPI_OPERAND_OBJECT *ReturnDesc; + UINT8 *NewBuf; + UINT32 i; + UINT32 StringLength = 0; + UINT16 Base = 16; + UINT8 Separator = ','; + + + ACPI_FUNCTION_TRACE_PTR (ExConvertToString, ObjDesc); + + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_STRING: + + /* No conversion necessary */ + + *ResultDesc = ObjDesc; + return_ACPI_STATUS (AE_OK); + + case ACPI_TYPE_INTEGER: + + switch (Type) + { + case ACPI_EXPLICIT_CONVERT_DECIMAL: + + /* Make room for maximum decimal number */ + + StringLength = ACPI_MAX_DECIMAL_DIGITS; + Base = 10; + break; + + default: + + /* Two hex string characters for each integer byte */ + + StringLength = ACPI_MUL_2 (AcpiGbl_IntegerByteWidth); + break; + } + + /* + * Create a new String + * Need enough space for one ASCII integer (plus null terminator) + */ + ReturnDesc = AcpiUtCreateStringObject ((ACPI_SIZE) StringLength); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + NewBuf = ReturnDesc->Buffer.Pointer; + + /* Convert integer to string */ + + StringLength = AcpiExConvertToAscii ( + ObjDesc->Integer.Value, Base, NewBuf, AcpiGbl_IntegerByteWidth); + + /* Null terminate at the correct place */ + + ReturnDesc->String.Length = StringLength; + NewBuf [StringLength] = 0; + break; + + case ACPI_TYPE_BUFFER: + + /* Setup string length, base, and separator */ + + switch (Type) + { + case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by ToDecimalString */ + /* + * From ACPI: "If Data is a buffer, it is converted to a string of + * decimal values separated by commas." + */ + Base = 10; + + /* + * Calculate the final string length. Individual string values + * are variable length (include separator for each) + */ + for (i = 0; i < ObjDesc->Buffer.Length; i++) + { + if (ObjDesc->Buffer.Pointer[i] >= 100) + { + StringLength += 4; + } + else if (ObjDesc->Buffer.Pointer[i] >= 10) + { + StringLength += 3; + } + else + { + StringLength += 2; + } + } + break; + + case ACPI_IMPLICIT_CONVERT_HEX: + /* + * From the ACPI spec: + *"The entire contents of the buffer are converted to a string of + * two-character hexadecimal numbers, each separated by a space." + */ + Separator = ' '; + StringLength = (ObjDesc->Buffer.Length * 3); + break; + + case ACPI_EXPLICIT_CONVERT_HEX: /* Used by ToHexString */ + /* + * From ACPI: "If Data is a buffer, it is converted to a string of + * hexadecimal values separated by commas." + */ + StringLength = (ObjDesc->Buffer.Length * 3); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Create a new string object and string buffer + * (-1 because of extra separator included in StringLength from above) + * Allow creation of zero-length strings from zero-length buffers. + */ + if (StringLength) + { + StringLength--; + } + + ReturnDesc = AcpiUtCreateStringObject ((ACPI_SIZE) StringLength); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + NewBuf = ReturnDesc->Buffer.Pointer; + + /* + * Convert buffer bytes to hex or decimal values + * (separated by commas or spaces) + */ + for (i = 0; i < ObjDesc->Buffer.Length; i++) + { + NewBuf += AcpiExConvertToAscii ( + (UINT64) ObjDesc->Buffer.Pointer[i], Base, NewBuf, 1); + *NewBuf++ = Separator; /* each separated by a comma or space */ + } + + /* + * Null terminate the string + * (overwrites final comma/space from above) + */ + if (ObjDesc->Buffer.Length) + { + NewBuf--; + } + *NewBuf = 0; + break; + + default: + + return_ACPI_STATUS (AE_TYPE); + } + + *ResultDesc = ReturnDesc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExConvertToTargetType + * + * PARAMETERS: DestinationType - Current type of the destination + * SourceDesc - Source object to be converted. + * ResultDesc - Where the converted object is returned + * WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Implements "implicit conversion" rules for storing an object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExConvertToTargetType ( + ACPI_OBJECT_TYPE DestinationType, + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExConvertToTargetType); + + + /* Default behavior */ + + *ResultDesc = SourceDesc; + + /* + * If required by the target, + * perform implicit conversion on the source before we store it. + */ + switch (GET_CURRENT_ARG_TYPE (WalkState->OpInfo->RuntimeArgs)) + { + case ARGI_SIMPLE_TARGET: + case ARGI_FIXED_TARGET: + case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ + + switch (DestinationType) + { + case ACPI_TYPE_LOCAL_REGION_FIELD: + /* + * Named field can always handle conversions + */ + break; + + default: + + /* No conversion allowed for these types */ + + if (DestinationType != SourceDesc->Common.Type) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Explicit operator, will store (%s) over existing type (%s)\n", + AcpiUtGetObjectTypeName (SourceDesc), + AcpiUtGetTypeName (DestinationType))); + Status = AE_TYPE; + } + } + break; + + case ARGI_TARGETREF: + case ARGI_STORE_TARGET: + + switch (DestinationType) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * These types require an Integer operand. We can convert + * a Buffer or a String to an Integer if necessary. + */ + Status = AcpiExConvertToInteger (SourceDesc, ResultDesc, 16); + break; + + case ACPI_TYPE_STRING: + /* + * The operand must be a String. We can convert an + * Integer or Buffer if necessary + */ + Status = AcpiExConvertToString (SourceDesc, ResultDesc, + ACPI_IMPLICIT_CONVERT_HEX); + break; + + case ACPI_TYPE_BUFFER: + /* + * The operand must be a Buffer. We can convert an + * Integer or String if necessary + */ + Status = AcpiExConvertToBuffer (SourceDesc, ResultDesc); + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Bad destination type during conversion: 0x%X", + DestinationType)); + Status = AE_AML_INTERNAL; + break; + } + break; + + case ARGI_REFERENCE: + /* + * CreateXxxxField cases - we are storing the field object into the name + */ + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown Target type ID 0x%X AmlOpcode 0x%X DestType %s", + GET_CURRENT_ARG_TYPE (WalkState->OpInfo->RuntimeArgs), + WalkState->Opcode, AcpiUtGetTypeName (DestinationType))); + Status = AE_AML_INTERNAL; + } + + /* + * Source-to-Target conversion semantics: + * + * If conversion to the target type cannot be performed, then simply + * overwrite the target with the new object and type. + */ + if (Status == AE_TYPE) + { + Status = AE_OK; + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/excreate.c b/third_party/lib/acpica/source/components/executer/excreate.c new file mode 100644 index 000000000..26dd872a3 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/excreate.c @@ -0,0 +1,577 @@ +/****************************************************************************** + * + * Module Name: excreate - Named object creation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("excreate") + + +#ifndef ACPI_NO_METHOD_EXECUTION +/******************************************************************************* + * + * FUNCTION: AcpiExCreateAlias + * + * PARAMETERS: WalkState - Current state, contains operands + * + * RETURN: Status + * + * DESCRIPTION: Create a new named alias + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreateAlias ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_NAMESPACE_NODE *TargetNode; + ACPI_NAMESPACE_NODE *AliasNode; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExCreateAlias); + + + /* Get the source/alias operands (both namespace nodes) */ + + AliasNode = (ACPI_NAMESPACE_NODE *) WalkState->Operands[0]; + TargetNode = (ACPI_NAMESPACE_NODE *) WalkState->Operands[1]; + + if ((TargetNode->Type == ACPI_TYPE_LOCAL_ALIAS) || + (TargetNode->Type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) + { + /* + * Dereference an existing alias so that we don't create a chain + * of aliases. With this code, we guarantee that an alias is + * always exactly one level of indirection away from the + * actual aliased name. + */ + TargetNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, TargetNode->Object); + } + + /* + * For objects that can never change (i.e., the NS node will + * permanently point to the same object), we can simply attach + * the object to the new NS node. For other objects (such as + * Integers, buffers, etc.), we have to point the Alias node + * to the original Node. + */ + switch (TargetNode->Type) + { + + /* For these types, the sub-object can change dynamically via a Store */ + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_BUFFER_FIELD: + /* + * These types open a new scope, so we need the NS node in order to access + * any children. + */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + case ACPI_TYPE_LOCAL_SCOPE: + /* + * The new alias has the type ALIAS and points to the original + * NS node, not the object itself. + */ + AliasNode->Type = ACPI_TYPE_LOCAL_ALIAS; + AliasNode->Object = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, TargetNode); + break; + + case ACPI_TYPE_METHOD: + /* + * Control method aliases need to be differentiated + */ + AliasNode->Type = ACPI_TYPE_LOCAL_METHOD_ALIAS; + AliasNode->Object = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, TargetNode); + break; + + default: + + /* Attach the original source object to the new Alias Node */ + + /* + * The new alias assumes the type of the target, and it points + * to the same object. The reference count of the object has an + * additional reference to prevent deletion out from under either the + * target node or the alias Node + */ + Status = AcpiNsAttachObject (AliasNode, + AcpiNsGetAttachedObject (TargetNode), TargetNode->Type); + break; + } + + /* Since both operands are Nodes, we don't need to delete them */ + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExCreateEvent + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new event object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreateEvent ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_TRACE (ExCreateEvent); + + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_EVENT); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * Create the actual OS semaphore, with zero initial units -- meaning + * that the event is created in an unsignalled state + */ + Status = AcpiOsCreateSemaphore (ACPI_NO_UNIT_LIMIT, 0, + &ObjDesc->Event.OsSemaphore); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Attach object to the Node */ + + Status = AcpiNsAttachObject ( + (ACPI_NAMESPACE_NODE *) WalkState->Operands[0], + ObjDesc, ACPI_TYPE_EVENT); + +Cleanup: + /* + * Remove local reference to the object (on error, will cause deletion + * of both object and semaphore if present.) + */ + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExCreateMutex + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new mutex object + * + * Mutex (Name[0], SyncLevel[1]) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreateMutex ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_TRACE_PTR (ExCreateMutex, ACPI_WALK_OPERANDS); + + + /* Create the new mutex object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Create the actual OS Mutex */ + + Status = AcpiOsCreateMutex (&ObjDesc->Mutex.OsMutex); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Init object and attach to NS node */ + + ObjDesc->Mutex.SyncLevel = (UINT8) WalkState->Operands[1]->Integer.Value; + ObjDesc->Mutex.Node = (ACPI_NAMESPACE_NODE *) WalkState->Operands[0]; + + Status = AcpiNsAttachObject ( + ObjDesc->Mutex.Node, ObjDesc, ACPI_TYPE_MUTEX); + + +Cleanup: + /* + * Remove local reference to the object (on error, will cause deletion + * of both object and semaphore if present.) + */ + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExCreateRegion + * + * PARAMETERS: AmlStart - Pointer to the region declaration AML + * AmlLength - Max length of the declaration AML + * SpaceId - Address space ID for the region + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new operation region object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreateRegion ( + UINT8 *AmlStart, + UINT32 AmlLength, + UINT8 SpaceId, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *RegionObj2; + + + ACPI_FUNCTION_TRACE (ExCreateRegion); + + + /* Get the Namespace Node */ + + Node = WalkState->Op->Common.Node; + + /* + * If the region object is already attached to this node, + * just return + */ + if (AcpiNsGetAttachedObject (Node)) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * Space ID must be one of the predefined IDs, or in the user-defined + * range + */ + if (!AcpiIsValidSpaceId (SpaceId)) + { + /* + * Print an error message, but continue. We don't want to abort + * a table load for this exception. Instead, if the region is + * actually used at runtime, abort the executing method. + */ + ACPI_ERROR ((AE_INFO, + "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId)); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n", + AcpiUtGetRegionName (SpaceId), SpaceId)); + + /* Create the region descriptor */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * Remember location in AML stream of address & length + * operands since they need to be evaluated at run time. + */ + RegionObj2 = AcpiNsGetSecondaryObject (ObjDesc); + RegionObj2->Extra.AmlStart = AmlStart; + RegionObj2->Extra.AmlLength = AmlLength; + RegionObj2->Extra.Method_REG = NULL; + if (WalkState->ScopeInfo) + { + RegionObj2->Extra.ScopeNode = WalkState->ScopeInfo->Scope.Node; + } + else + { + RegionObj2->Extra.ScopeNode = Node; + } + + /* Init the region from the operands */ + + ObjDesc->Region.SpaceId = SpaceId; + ObjDesc->Region.Address = 0; + ObjDesc->Region.Length = 0; + ObjDesc->Region.Node = Node; + ObjDesc->Region.Handler = NULL; + ObjDesc->Common.Flags &= + ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_REG_CONNECTED | + AOPOBJ_OBJECT_INITIALIZED); + + /* Install the new region object in the parent Node */ + + Status = AcpiNsAttachObject (Node, ObjDesc, ACPI_TYPE_REGION); + + +Cleanup: + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExCreateProcessor + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new processor object and populate the fields + * + * Processor (Name[0], CpuID[1], PblockAddr[2], PblockLength[3]) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreateProcessor ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (ExCreateProcessor, WalkState); + + + /* Create the processor object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_PROCESSOR); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the processor object from the operands */ + + ObjDesc->Processor.ProcId = (UINT8) Operand[1]->Integer.Value; + ObjDesc->Processor.Length = (UINT8) Operand[3]->Integer.Value; + ObjDesc->Processor.Address = (ACPI_IO_ADDRESS) Operand[2]->Integer.Value; + + /* Install the processor object in the parent Node */ + + Status = AcpiNsAttachObject ((ACPI_NAMESPACE_NODE *) Operand[0], + ObjDesc, ACPI_TYPE_PROCESSOR); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExCreatePowerResource + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new PowerResource object and populate the fields + * + * PowerResource (Name[0], SystemLevel[1], ResourceOrder[2]) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreatePowerResource ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_TRACE_PTR (ExCreatePowerResource, WalkState); + + + /* Create the power resource object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_POWER); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the power object from the operands */ + + ObjDesc->PowerResource.SystemLevel = (UINT8) Operand[1]->Integer.Value; + ObjDesc->PowerResource.ResourceOrder = (UINT16) Operand[2]->Integer.Value; + + /* Install the power resource object in the parent Node */ + + Status = AcpiNsAttachObject ((ACPI_NAMESPACE_NODE *) Operand[0], + ObjDesc, ACPI_TYPE_POWER); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiExCreateMethod + * + * PARAMETERS: AmlStart - First byte of the method's AML + * AmlLength - AML byte count for this method + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new method object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCreateMethod ( + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + UINT8 MethodFlags; + + + ACPI_FUNCTION_TRACE_PTR (ExCreateMethod, WalkState); + + + /* Create a new method object */ + + ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto Exit; + } + + /* Save the method's AML pointer and length */ + + ObjDesc->Method.AmlStart = AmlStart; + ObjDesc->Method.AmlLength = AmlLength; + ObjDesc->Method.Node = Operand[0]; + + /* + * Disassemble the method flags. Split off the ArgCount, Serialized + * flag, and SyncLevel for efficiency. + */ + MethodFlags = (UINT8) Operand[1]->Integer.Value; + ObjDesc->Method.ParamCount = (UINT8) + (MethodFlags & AML_METHOD_ARG_COUNT); + + /* + * Get the SyncLevel. If method is serialized, a mutex will be + * created for this method when it is parsed. + */ + if (MethodFlags & AML_METHOD_SERIALIZED) + { + ObjDesc->Method.InfoFlags = ACPI_METHOD_SERIALIZED; + + /* + * ACPI 1.0: SyncLevel = 0 + * ACPI 2.0: SyncLevel = SyncLevel in method declaration + */ + ObjDesc->Method.SyncLevel = (UINT8) + ((MethodFlags & AML_METHOD_SYNC_LEVEL) >> 4); + } + + /* Attach the new object to the method Node */ + + Status = AcpiNsAttachObject ((ACPI_NAMESPACE_NODE *) Operand[0], + ObjDesc, ACPI_TYPE_METHOD); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + +Exit: + /* Remove a reference to the operand */ + + AcpiUtRemoveReference (Operand[1]); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exdebug.c b/third_party/lib/acpica/source/components/executer/exdebug.c new file mode 100644 index 000000000..0832337e4 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exdebug.c @@ -0,0 +1,354 @@ +/****************************************************************************** + * + * Module Name: exdebug - Support for stores to the AML Debug Object + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exdebug") + + +#ifndef ACPI_NO_ERROR_MESSAGES +/******************************************************************************* + * + * FUNCTION: AcpiExDoDebugObject + * + * PARAMETERS: SourceDesc - Object to be output to "Debug Object" + * Level - Indentation level (used for packages) + * Index - Current package element, zero if not pkg + * + * RETURN: None + * + * DESCRIPTION: Handles stores to the AML Debug Object. For example: + * Store(INT1, Debug) + * + * This function is not compiled if ACPI_NO_ERROR_MESSAGES is set. + * + * This function is only enabled if AcpiGbl_EnableAmlDebugObject is set, or + * if ACPI_LV_DEBUG_OBJECT is set in the AcpiDbgLevel. Thus, in the normal + * operational case, stores to the debug object are ignored but can be easily + * enabled if necessary. + * + ******************************************************************************/ + +void +AcpiExDoDebugObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + UINT32 Level, + UINT32 Index) +{ + UINT32 i; + UINT32 Timer; + ACPI_OPERAND_OBJECT *ObjectDesc; + UINT32 Value; + + + ACPI_FUNCTION_TRACE_PTR (ExDoDebugObject, SourceDesc); + + + /* Output must be enabled via the DebugObject global or the DbgLevel */ + + if (!AcpiGbl_EnableAmlDebugObject && + !(AcpiDbgLevel & ACPI_LV_DEBUG_OBJECT)) + { + return_VOID; + } + + /* Null string or newline -- don't emit the line header */ + + if (SourceDesc && + (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc) == ACPI_DESC_TYPE_OPERAND) && + (SourceDesc->Common.Type == ACPI_TYPE_STRING)) + { + if ((SourceDesc->String.Length == 0) || + ((SourceDesc->String.Length == 1) && + (*SourceDesc->String.Pointer == '\n'))) + { + AcpiOsPrintf ("\n"); + return_VOID; + } + } + + /* + * Print line header as long as we are not in the middle of an + * object display + */ + if (!((Level > 0) && Index == 0)) + { + if (AcpiGbl_DisplayDebugTimer) + { + /* + * We will emit the current timer value (in microseconds) with each + * debug output. Only need the lower 26 bits. This allows for 67 + * million microseconds or 67 seconds before rollover. + * + * Convert 100 nanosecond units to microseconds + */ + Timer = ((UINT32) AcpiOsGetTimer () / 10); + Timer &= 0x03FFFFFF; + + AcpiOsPrintf ("[ACPI Debug T=0x%8.8X] %*s", Timer, Level, " "); + } + else + { + AcpiOsPrintf ("[ACPI Debug] %*s", Level, " "); + } + } + + /* Display the index for package output only */ + + if (Index > 0) + { + AcpiOsPrintf ("(%.2u) ", Index - 1); + } + + if (!SourceDesc) + { + AcpiOsPrintf ("[Null Object]\n"); + return_VOID; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc) == ACPI_DESC_TYPE_OPERAND) + { + /* No object type prefix needed for integers and strings */ + + if ((SourceDesc->Common.Type != ACPI_TYPE_INTEGER) && + (SourceDesc->Common.Type != ACPI_TYPE_STRING)) + { + AcpiOsPrintf ("%s ", AcpiUtGetObjectTypeName (SourceDesc)); + } + + if (!AcpiUtValidInternalObject (SourceDesc)) + { + AcpiOsPrintf ("%p, Invalid Internal Object!\n", SourceDesc); + return_VOID; + } + } + else if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc) == ACPI_DESC_TYPE_NAMED) + { + AcpiOsPrintf ("%s (Node %p)\n", + AcpiUtGetTypeName (((ACPI_NAMESPACE_NODE *) SourceDesc)->Type), + SourceDesc); + return_VOID; + } + else + { + return_VOID; + } + + /* SourceDesc is of type ACPI_DESC_TYPE_OPERAND */ + + switch (SourceDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + /* Output correct integer width */ + + if (AcpiGbl_IntegerByteWidth == 4) + { + AcpiOsPrintf ("0x%8.8X\n", + (UINT32) SourceDesc->Integer.Value); + } + else + { + AcpiOsPrintf ("0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (SourceDesc->Integer.Value)); + } + break; + + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf ("[0x%.2X]\n", (UINT32) SourceDesc->Buffer.Length); + AcpiUtDumpBuffer (SourceDesc->Buffer.Pointer, + (SourceDesc->Buffer.Length < 256) ? + SourceDesc->Buffer.Length : 256, DB_BYTE_DISPLAY, 0); + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("\"%s\"\n", SourceDesc->String.Pointer); + break; + + case ACPI_TYPE_PACKAGE: + + AcpiOsPrintf ("(Contains 0x%.2X Elements):\n", + SourceDesc->Package.Count); + + /* Output the entire contents of the package */ + + for (i = 0; i < SourceDesc->Package.Count; i++) + { + AcpiExDoDebugObject (SourceDesc->Package.Elements[i], + Level + 4, i + 1); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + AcpiOsPrintf ("[%s] ", AcpiUtGetReferenceName (SourceDesc)); + + /* Decode the reference */ + + switch (SourceDesc->Reference.Class) + { + case ACPI_REFCLASS_INDEX: + + AcpiOsPrintf ("0x%X\n", SourceDesc->Reference.Value); + break; + + case ACPI_REFCLASS_TABLE: + + /* Case for DdbHandle */ + + AcpiOsPrintf ("Table Index 0x%X\n", SourceDesc->Reference.Value); + return_VOID; + + default: + + break; + } + + AcpiOsPrintf (" "); + + /* Check for valid node first, then valid object */ + + if (SourceDesc->Reference.Node) + { + if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc->Reference.Node) != + ACPI_DESC_TYPE_NAMED) + { + AcpiOsPrintf (" %p - Not a valid namespace node\n", + SourceDesc->Reference.Node); + } + else + { + AcpiOsPrintf ("Node %p [%4.4s] ", SourceDesc->Reference.Node, + (SourceDesc->Reference.Node)->Name.Ascii); + + switch ((SourceDesc->Reference.Node)->Type) + { + /* These types have no attached object */ + + case ACPI_TYPE_DEVICE: + AcpiOsPrintf ("Device\n"); + break; + + case ACPI_TYPE_THERMAL: + AcpiOsPrintf ("Thermal Zone\n"); + break; + + default: + + AcpiExDoDebugObject ((SourceDesc->Reference.Node)->Object, + Level + 4, 0); + break; + } + } + } + else if (SourceDesc->Reference.Object) + { + if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc->Reference.Object) == + ACPI_DESC_TYPE_NAMED) + { + /* Reference object is a namespace node */ + + AcpiExDoDebugObject (ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, + SourceDesc->Reference.Object), + Level + 4, 0); + } + else + { + ObjectDesc = SourceDesc->Reference.Object; + Value = SourceDesc->Reference.Value; + + switch (ObjectDesc->Common.Type) + { + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf ("Buffer[%u] = 0x%2.2X\n", + Value, *SourceDesc->Reference.IndexPointer); + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("String[%u] = \"%c\" (0x%2.2X)\n", + Value, *SourceDesc->Reference.IndexPointer, + *SourceDesc->Reference.IndexPointer); + break; + + case ACPI_TYPE_PACKAGE: + + AcpiOsPrintf ("Package[%u] = ", Value); + if (!(*SourceDesc->Reference.Where)) + { + AcpiOsPrintf ("[Uninitialized Package Element]\n"); + } + else + { + AcpiExDoDebugObject (*SourceDesc->Reference.Where, + Level+4, 0); + } + break; + + default: + + AcpiOsPrintf ("Unknown Reference object type %X\n", + ObjectDesc->Common.Type); + break; + } + } + } + break; + + default: + + AcpiOsPrintf ("(Descriptor %p)\n", SourceDesc); + break; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); + return_VOID; +} +#endif diff --git a/third_party/lib/acpica/source/components/executer/exdump.c b/third_party/lib/acpica/source/components/executer/exdump.c new file mode 100644 index 000000000..5dae1f4bc --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exdump.c @@ -0,0 +1,1285 @@ +/****************************************************************************** + * + * Module Name: exdump - Interpreter debug output routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exdump") + +/* + * The following routines are used for debug output only + */ +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/* Local prototypes */ + +static void +AcpiExOutString ( + char *Title, + char *Value); + +static void +AcpiExOutPointer ( + char *Title, + void *Value); + +static void +AcpiExDumpObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_EXDUMP_INFO *Info); + +static void +AcpiExDumpReferenceObj ( + ACPI_OPERAND_OBJECT *ObjDesc); + +static void +AcpiExDumpPackageObj ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Level, + UINT32 Index); + + +/******************************************************************************* + * + * Object Descriptor info tables + * + * Note: The first table entry must be an INIT opcode and must contain + * the table length (number of table entries) + * + ******************************************************************************/ + +static ACPI_EXDUMP_INFO AcpiExDumpInteger[2] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpInteger), NULL}, + {ACPI_EXD_UINT64, ACPI_EXD_OFFSET (Integer.Value), "Value"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpString[4] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpString), NULL}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (String.Length), "Length"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (String.Pointer), "Pointer"}, + {ACPI_EXD_STRING, 0, NULL} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpBuffer[5] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpBuffer), NULL}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Buffer.Length), "Length"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Buffer.Pointer), "Pointer"}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (Buffer.Node), "Parent Node"}, + {ACPI_EXD_BUFFER, 0, NULL} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpPackage[6] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpPackage), NULL}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (Package.Node), "Parent Node"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Package.Flags), "Flags"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Package.Count), "Elements"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Package.Elements), "Element List"}, + {ACPI_EXD_PACKAGE, 0, NULL} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpDevice[4] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpDevice), NULL}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Device.NotifyList[0]), "System Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Device.NotifyList[1]), "Device Notify"}, + {ACPI_EXD_HDLR_LIST,ACPI_EXD_OFFSET (Device.Handler), "Handler"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpEvent[2] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpEvent), NULL}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Event.OsSemaphore), "OsSemaphore"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpMethod[9] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpMethod), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.InfoFlags), "Info Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.ParamCount), "Parameter Count"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.SyncLevel), "Sync Level"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Method.Mutex), "Mutex"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.OwnerId), "Owner Id"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.ThreadCount), "Thread Count"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Method.AmlLength), "Aml Length"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Method.AmlStart), "Aml Start"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpMutex[6] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpMutex), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Mutex.SyncLevel), "Sync Level"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Mutex.OriginalSyncLevel), "Original Sync Level"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Mutex.OwnerThread), "Owner Thread"}, + {ACPI_EXD_UINT16, ACPI_EXD_OFFSET (Mutex.AcquisitionDepth), "Acquire Depth"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Mutex.OsMutex), "OsMutex"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpRegion[8] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpRegion), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Region.SpaceId), "Space Id"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Region.Flags), "Flags"}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (Region.Node), "Parent Node"}, + {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET (Region.Address), "Address"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Region.Length), "Length"}, + {ACPI_EXD_HDLR_LIST,ACPI_EXD_OFFSET (Region.Handler), "Handler"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Region.Next), "Next"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpPower[6] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpPower), NULL}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (PowerResource.SystemLevel), "System Level"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (PowerResource.ResourceOrder), "Resource Order"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (PowerResource.NotifyList[0]), "System Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (PowerResource.NotifyList[1]), "Device Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (PowerResource.Handler), "Handler"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpProcessor[7] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpProcessor), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Processor.ProcId), "Processor ID"}, + {ACPI_EXD_UINT8 , ACPI_EXD_OFFSET (Processor.Length), "Length"}, + {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET (Processor.Address), "Address"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Processor.NotifyList[0]), "System Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Processor.NotifyList[1]), "Device Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Processor.Handler), "Handler"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpThermal[4] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpThermal), NULL}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (ThermalZone.NotifyList[0]), "System Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (ThermalZone.NotifyList[1]), "Device Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (ThermalZone.Handler), "Handler"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpBufferField[3] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpBufferField), NULL}, + {ACPI_EXD_FIELD, 0, NULL}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (BufferField.BufferObj), "Buffer Object"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpRegionField[5] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpRegionField), NULL}, + {ACPI_EXD_FIELD, 0, NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Field.AccessLength), "AccessLength"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Field.RegionObj), "Region Object"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Field.ResourceBuffer), "ResourceBuffer"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpBankField[5] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpBankField), NULL}, + {ACPI_EXD_FIELD, 0, NULL}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (BankField.Value), "Value"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (BankField.RegionObj), "Region Object"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (BankField.BankObj), "Bank Object"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpIndexField[5] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpBankField), NULL}, + {ACPI_EXD_FIELD, 0, NULL}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (IndexField.Value), "Value"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (IndexField.IndexObj), "Index Object"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (IndexField.DataObj), "Data Object"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpReference[9] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpReference), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Reference.Class), "Class"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Reference.TargetType), "Target Type"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Reference.Value), "Value"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Reference.Object), "Object Desc"}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (Reference.Node), "Node"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Reference.Where), "Where"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Reference.IndexPointer), "Index Pointer"}, + {ACPI_EXD_REFERENCE,0, NULL} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpAddressHandler[6] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpAddressHandler), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (AddressSpace.SpaceId), "Space Id"}, + {ACPI_EXD_HDLR_LIST,ACPI_EXD_OFFSET (AddressSpace.Next), "Next"}, + {ACPI_EXD_RGN_LIST, ACPI_EXD_OFFSET (AddressSpace.RegionList), "Region List"}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (AddressSpace.Node), "Node"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (AddressSpace.Context), "Context"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpNotify[7] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpNotify), NULL}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (Notify.Node), "Node"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Notify.HandlerType), "Handler Type"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Notify.Handler), "Handler"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Notify.Context), "Context"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Notify.Next[0]), "Next System Notify"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Notify.Next[1]), "Next Device Notify"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpExtra[6] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpExtra), NULL}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Extra.Method_REG), "_REG Method"}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (Extra.ScopeNode), "Scope Node"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Extra.RegionContext), "Region Context"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Extra.AmlStart), "Aml Start"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (Extra.AmlLength), "Aml Length"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpData[3] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpData), NULL}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Data.Handler), "Handler"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Data.Pointer), "Raw Data"} +}; + +/* Miscellaneous tables */ + +static ACPI_EXDUMP_INFO AcpiExDumpCommon[5] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpCommon), NULL}, + {ACPI_EXD_TYPE , 0, NULL}, + {ACPI_EXD_UINT16, ACPI_EXD_OFFSET (Common.ReferenceCount), "Reference Count"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Common.Flags), "Flags"}, + {ACPI_EXD_LIST, ACPI_EXD_OFFSET (Common.NextObject), "Object List"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpFieldCommon[7] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpFieldCommon), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (CommonField.FieldFlags), "Field Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (CommonField.AccessByteWidth), "Access Byte Width"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (CommonField.BitLength), "Bit Length"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (CommonField.StartFieldBitOffset),"Field Bit Offset"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET (CommonField.BaseByteOffset), "Base Byte Offset"}, + {ACPI_EXD_NODE, ACPI_EXD_OFFSET (CommonField.Node), "Parent Node"} +}; + +static ACPI_EXDUMP_INFO AcpiExDumpNode[7] = +{ + {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpNode), NULL}, + {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET (Flags), "Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET (OwnerId), "Owner Id"}, + {ACPI_EXD_LIST, ACPI_EXD_NSOFFSET (Object), "Object List"}, + {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET (Parent), "Parent"}, + {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET (Child), "Child"}, + {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET (Peer), "Peer"} +}; + + +/* Dispatch table, indexed by object type */ + +static ACPI_EXDUMP_INFO *AcpiExDumpInfo[] = +{ + NULL, + AcpiExDumpInteger, + AcpiExDumpString, + AcpiExDumpBuffer, + AcpiExDumpPackage, + NULL, + AcpiExDumpDevice, + AcpiExDumpEvent, + AcpiExDumpMethod, + AcpiExDumpMutex, + AcpiExDumpRegion, + AcpiExDumpPower, + AcpiExDumpProcessor, + AcpiExDumpThermal, + AcpiExDumpBufferField, + NULL, + NULL, + AcpiExDumpRegionField, + AcpiExDumpBankField, + AcpiExDumpIndexField, + AcpiExDumpReference, + NULL, + NULL, + AcpiExDumpNotify, + AcpiExDumpAddressHandler, + NULL, + NULL, + NULL, + AcpiExDumpExtra, + AcpiExDumpData +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpObject + * + * PARAMETERS: ObjDesc - Descriptor to dump + * Info - Info table corresponding to this object + * type + * + * RETURN: None + * + * DESCRIPTION: Walk the info table for this object + * + ******************************************************************************/ + +static void +AcpiExDumpObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_EXDUMP_INFO *Info) +{ + UINT8 *Target; + char *Name; + const char *ReferenceName; + UINT8 Count; + ACPI_OPERAND_OBJECT *Start; + ACPI_OPERAND_OBJECT *Data = NULL; + ACPI_OPERAND_OBJECT *Next; + ACPI_NAMESPACE_NODE *Node; + + + if (!Info) + { + AcpiOsPrintf ( + "ExDumpObject: Display not implemented for object type %s\n", + AcpiUtGetObjectTypeName (ObjDesc)); + return; + } + + /* First table entry must contain the table length (# of table entries) */ + + Count = Info->Offset; + + while (Count) + { + Target = ACPI_ADD_PTR (UINT8, ObjDesc, Info->Offset); + Name = Info->Name; + + switch (Info->Opcode) + { + case ACPI_EXD_INIT: + + break; + + case ACPI_EXD_TYPE: + + AcpiOsPrintf ("%20s : %2.2X [%s]\n", "Type", + ObjDesc->Common.Type, AcpiUtGetObjectTypeName (ObjDesc)); + break; + + case ACPI_EXD_UINT8: + + AcpiOsPrintf ("%20s : %2.2X\n", Name, *Target); + break; + + case ACPI_EXD_UINT16: + + AcpiOsPrintf ("%20s : %4.4X\n", Name, ACPI_GET16 (Target)); + break; + + case ACPI_EXD_UINT32: + + AcpiOsPrintf ("%20s : %8.8X\n", Name, ACPI_GET32 (Target)); + break; + + case ACPI_EXD_UINT64: + + AcpiOsPrintf ("%20s : %8.8X%8.8X\n", "Value", + ACPI_FORMAT_UINT64 (ACPI_GET64 (Target))); + break; + + case ACPI_EXD_POINTER: + case ACPI_EXD_ADDRESS: + + AcpiExOutPointer (Name, *ACPI_CAST_PTR (void *, Target)); + break; + + case ACPI_EXD_STRING: + + AcpiUtPrintString (ObjDesc->String.Pointer, ACPI_UINT8_MAX); + AcpiOsPrintf ("\n"); + break; + + case ACPI_EXD_BUFFER: + + ACPI_DUMP_BUFFER ( + ObjDesc->Buffer.Pointer, ObjDesc->Buffer.Length); + break; + + case ACPI_EXD_PACKAGE: + + /* Dump the package contents */ + + AcpiOsPrintf ("\nPackage Contents:\n"); + AcpiExDumpPackageObj (ObjDesc, 0, 0); + break; + + case ACPI_EXD_FIELD: + + AcpiExDumpObject (ObjDesc, AcpiExDumpFieldCommon); + break; + + case ACPI_EXD_REFERENCE: + + ReferenceName = AcpiUtGetReferenceName (ObjDesc); + AcpiExOutString ( + "Class Name", ACPI_CAST_PTR (char, ReferenceName)); + AcpiExDumpReferenceObj (ObjDesc); + break; + + case ACPI_EXD_LIST: + + Start = *ACPI_CAST_PTR (void *, Target); + Next = Start; + + AcpiOsPrintf ("%20s : %p", Name, Next); + if (Next) + { + AcpiOsPrintf ("(%s %2.2X)", + AcpiUtGetObjectTypeName (Next), Next->Common.Type); + + while (Next->Common.NextObject) + { + if ((Next->Common.Type == ACPI_TYPE_LOCAL_DATA) && + !Data) + { + Data = Next; + } + + Next = Next->Common.NextObject; + AcpiOsPrintf ("->%p(%s %2.2X)", Next, + AcpiUtGetObjectTypeName (Next), Next->Common.Type); + + if ((Next == Start) || (Next == Data)) + { + AcpiOsPrintf ( + "\n**** Error: Object list appears to be circular linked"); + break; + } + } + } + + AcpiOsPrintf ("\n"); + break; + + case ACPI_EXD_HDLR_LIST: + + Start = *ACPI_CAST_PTR (void *, Target); + Next = Start; + + AcpiOsPrintf ("%20s : %p", Name, Next); + if (Next) + { + AcpiOsPrintf ("(%s %2.2X)", + AcpiUtGetObjectTypeName (Next), + Next->AddressSpace.SpaceId); + + while (Next->AddressSpace.Next) + { + if ((Next->Common.Type == ACPI_TYPE_LOCAL_DATA) && + !Data) + { + Data = Next; + } + + Next = Next->AddressSpace.Next; + AcpiOsPrintf ("->%p(%s %2.2X)", Next, + AcpiUtGetObjectTypeName (Next), + Next->AddressSpace.SpaceId); + + if ((Next == Start) || (Next == Data)) + { + AcpiOsPrintf ( + "\n**** Error: Handler list appears to be circular linked"); + break; + } + } + } + + AcpiOsPrintf ("\n"); + break; + + case ACPI_EXD_RGN_LIST: + + Start = *ACPI_CAST_PTR (void *, Target); + Next = Start; + + AcpiOsPrintf ("%20s : %p", Name, Next); + if (Next) + { + AcpiOsPrintf ("(%s %2.2X)", + AcpiUtGetObjectTypeName (Next), Next->Common.Type); + + while (Next->Region.Next) + { + if ((Next->Common.Type == ACPI_TYPE_LOCAL_DATA) && + !Data) + { + Data = Next; + } + + Next = Next->Region.Next; + AcpiOsPrintf ("->%p(%s %2.2X)", Next, + AcpiUtGetObjectTypeName (Next), Next->Common.Type); + + if ((Next == Start) || (Next == Data)) + { + AcpiOsPrintf ( + "\n**** Error: Region list appears to be circular linked"); + break; + } + } + } + + AcpiOsPrintf ("\n"); + break; + + case ACPI_EXD_NODE: + + Node = *ACPI_CAST_PTR (ACPI_NAMESPACE_NODE *, Target); + + AcpiOsPrintf ("%20s : %p", Name, Node); + if (Node) + { + AcpiOsPrintf (" [%4.4s]", Node->Name.Ascii); + } + AcpiOsPrintf ("\n"); + break; + + default: + + AcpiOsPrintf ("**** Invalid table opcode [%X] ****\n", + Info->Opcode); + return; + } + + Info++; + Count--; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpOperand + * + * PARAMETERS: *ObjDesc - Pointer to entry to be dumped + * Depth - Current nesting depth + * + * RETURN: None + * + * DESCRIPTION: Dump an operand object + * + ******************************************************************************/ + +void +AcpiExDumpOperand ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Depth) +{ + UINT32 Length; + UINT32 Index; + + + ACPI_FUNCTION_NAME (ExDumpOperand) + + + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_EXEC, _COMPONENT)) + { + return; + } + + if (!ObjDesc) + { + /* This could be a null element of a package */ + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n")); + return; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_NAMED) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p Namespace Node: ", ObjDesc)); + ACPI_DUMP_ENTRY (ObjDesc, ACPI_LV_EXEC); + return; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%p is not a node or operand object: [%s]\n", + ObjDesc, AcpiUtGetDescriptorName (ObjDesc))); + ACPI_DUMP_BUFFER (ObjDesc, sizeof (ACPI_OPERAND_OBJECT)); + return; + } + + /* ObjDesc is a valid object */ + + if (Depth > 0) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%*s[%u] %p ", + Depth, " ", Depth, ObjDesc)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", ObjDesc)); + } + + /* Decode object type */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_LOCAL_REFERENCE: + + AcpiOsPrintf ("Reference: [%s] ", + AcpiUtGetReferenceName (ObjDesc)); + + switch (ObjDesc->Reference.Class) + { + case ACPI_REFCLASS_DEBUG: + + AcpiOsPrintf ("\n"); + break; + + case ACPI_REFCLASS_INDEX: + + AcpiOsPrintf ("%p\n", ObjDesc->Reference.Object); + break; + + case ACPI_REFCLASS_TABLE: + + AcpiOsPrintf ("Table Index %X\n", ObjDesc->Reference.Value); + break; + + case ACPI_REFCLASS_REFOF: + + AcpiOsPrintf ("%p [%s]\n", ObjDesc->Reference.Object, + AcpiUtGetTypeName (((ACPI_OPERAND_OBJECT *) + ObjDesc->Reference.Object)->Common.Type)); + break; + + case ACPI_REFCLASS_NAME: + + AcpiOsPrintf ("- [%4.4s]\n", + ObjDesc->Reference.Node->Name.Ascii); + break; + + case ACPI_REFCLASS_ARG: + case ACPI_REFCLASS_LOCAL: + + AcpiOsPrintf ("%X\n", ObjDesc->Reference.Value); + break; + + default: /* Unknown reference class */ + + AcpiOsPrintf ("%2.2X\n", ObjDesc->Reference.Class); + break; + } + break; + + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf ("Buffer length %.2X @ %p\n", + ObjDesc->Buffer.Length, ObjDesc->Buffer.Pointer); + + /* Debug only -- dump the buffer contents */ + + if (ObjDesc->Buffer.Pointer) + { + Length = ObjDesc->Buffer.Length; + if (Length > 128) + { + Length = 128; + } + + AcpiOsPrintf ( + "Buffer Contents: (displaying length 0x%.2X)\n", Length); + ACPI_DUMP_BUFFER (ObjDesc->Buffer.Pointer, Length); + } + break; + + case ACPI_TYPE_INTEGER: + + AcpiOsPrintf ("Integer %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_PACKAGE: + + AcpiOsPrintf ("Package [Len %X] ElementArray %p\n", + ObjDesc->Package.Count, ObjDesc->Package.Elements); + + /* + * If elements exist, package element pointer is valid, + * and debug_level exceeds 1, dump package's elements. + */ + if (ObjDesc->Package.Count && + ObjDesc->Package.Elements && + AcpiDbgLevel > 1) + { + for (Index = 0; Index < ObjDesc->Package.Count; Index++) + { + AcpiExDumpOperand ( + ObjDesc->Package.Elements[Index], Depth + 1); + } + } + break; + + case ACPI_TYPE_REGION: + + AcpiOsPrintf ("Region %s (%X)", + AcpiUtGetRegionName (ObjDesc->Region.SpaceId), + ObjDesc->Region.SpaceId); + + /* + * If the address and length have not been evaluated, + * don't print them. + */ + if (!(ObjDesc->Region.Flags & AOPOBJ_DATA_VALID)) + { + AcpiOsPrintf ("\n"); + } + else + { + AcpiOsPrintf (" base %8.8X%8.8X Length %X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Region.Address), + ObjDesc->Region.Length); + } + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("String length %X @ %p ", + ObjDesc->String.Length, + ObjDesc->String.Pointer); + + AcpiUtPrintString (ObjDesc->String.Pointer, ACPI_UINT8_MAX); + AcpiOsPrintf ("\n"); + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + AcpiOsPrintf ("BankField\n"); + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + AcpiOsPrintf ("RegionField: Bits=%X AccWidth=%X Lock=%X Update=%X at " + "byte=%X bit=%X of below:\n", + ObjDesc->Field.BitLength, + ObjDesc->Field.AccessByteWidth, + ObjDesc->Field.FieldFlags & AML_FIELD_LOCK_RULE_MASK, + ObjDesc->Field.FieldFlags & AML_FIELD_UPDATE_RULE_MASK, + ObjDesc->Field.BaseByteOffset, + ObjDesc->Field.StartFieldBitOffset); + + AcpiExDumpOperand (ObjDesc->Field.RegionObj, Depth + 1); + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + AcpiOsPrintf ("IndexField\n"); + break; + + case ACPI_TYPE_BUFFER_FIELD: + + AcpiOsPrintf ("BufferField: %X bits at byte %X bit %X of\n", + ObjDesc->BufferField.BitLength, + ObjDesc->BufferField.BaseByteOffset, + ObjDesc->BufferField.StartFieldBitOffset); + + if (!ObjDesc->BufferField.BufferObj) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL*\n")); + } + else if ((ObjDesc->BufferField.BufferObj)->Common.Type != + ACPI_TYPE_BUFFER) + { + AcpiOsPrintf ("*not a Buffer*\n"); + } + else + { + AcpiExDumpOperand (ObjDesc->BufferField.BufferObj, Depth + 1); + } + break; + + case ACPI_TYPE_EVENT: + + AcpiOsPrintf ("Event\n"); + break; + + case ACPI_TYPE_METHOD: + + AcpiOsPrintf ("Method(%X) @ %p:%X\n", + ObjDesc->Method.ParamCount, + ObjDesc->Method.AmlStart, + ObjDesc->Method.AmlLength); + break; + + case ACPI_TYPE_MUTEX: + + AcpiOsPrintf ("Mutex\n"); + break; + + case ACPI_TYPE_DEVICE: + + AcpiOsPrintf ("Device\n"); + break; + + case ACPI_TYPE_POWER: + + AcpiOsPrintf ("Power\n"); + break; + + case ACPI_TYPE_PROCESSOR: + + AcpiOsPrintf ("Processor\n"); + break; + + case ACPI_TYPE_THERMAL: + + AcpiOsPrintf ("Thermal\n"); + break; + + default: + + /* Unknown Type */ + + AcpiOsPrintf ("Unknown Type %X\n", ObjDesc->Common.Type); + break; + } + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpOperands + * + * PARAMETERS: Operands - A list of Operand objects + * OpcodeName - AML opcode name + * NumOperands - Operand count for this opcode + * + * DESCRIPTION: Dump the operands associated with the opcode + * + ******************************************************************************/ + +void +AcpiExDumpOperands ( + ACPI_OPERAND_OBJECT **Operands, + const char *OpcodeName, + UINT32 NumOperands) +{ + ACPI_FUNCTION_NAME (ExDumpOperands); + + + if (!OpcodeName) + { + OpcodeName = "UNKNOWN"; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "**** Start operand dump for opcode [%s], %u operands\n", + OpcodeName, NumOperands)); + + if (NumOperands == 0) + { + NumOperands = 1; + } + + /* Dump the individual operands */ + + while (NumOperands) + { + AcpiExDumpOperand (*Operands, 0); + Operands++; + NumOperands--; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "**** End operand dump for [%s]\n", OpcodeName)); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOut* functions + * + * PARAMETERS: Title - Descriptive text + * Value - Value to be displayed + * + * DESCRIPTION: Object dump output formatting functions. These functions + * reduce the number of format strings required and keeps them + * all in one place for easy modification. + * + ******************************************************************************/ + +static void +AcpiExOutString ( + char *Title, + char *Value) +{ + AcpiOsPrintf ("%20s : %s\n", Title, Value); +} + +static void +AcpiExOutPointer ( + char *Title, + void *Value) +{ + AcpiOsPrintf ("%20s : %p\n", Title, Value); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpNamespaceNode + * + * PARAMETERS: Node - Descriptor to dump + * Flags - Force display if TRUE + * + * DESCRIPTION: Dumps the members of the given.Node + * + ******************************************************************************/ + +void +AcpiExDumpNamespaceNode ( + ACPI_NAMESPACE_NODE *Node, + UINT32 Flags) +{ + + ACPI_FUNCTION_ENTRY (); + + + if (!Flags) + { + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_OBJECTS, _COMPONENT)) + { + return; + } + } + + AcpiOsPrintf ("%20s : %4.4s\n", "Name", AcpiUtGetNodeName (Node)); + AcpiOsPrintf ("%20s : %2.2X [%s]\n", "Type", + Node->Type, AcpiUtGetTypeName (Node->Type)); + + AcpiExDumpObject (ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Node), + AcpiExDumpNode); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpReferenceObj + * + * PARAMETERS: Object - Descriptor to dump + * + * DESCRIPTION: Dumps a reference object + * + ******************************************************************************/ + +static void +AcpiExDumpReferenceObj ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_BUFFER RetBuf; + ACPI_STATUS Status; + + + RetBuf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + if (ObjDesc->Reference.Class == ACPI_REFCLASS_NAME) + { + AcpiOsPrintf (" %p ", ObjDesc->Reference.Node); + + Status = AcpiNsHandleToPathname (ObjDesc->Reference.Node, + &RetBuf, TRUE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf (" Could not convert name to pathname\n"); + } + else + { + AcpiOsPrintf ("%s\n", (char *) RetBuf.Pointer); + ACPI_FREE (RetBuf.Pointer); + } + } + else if (ObjDesc->Reference.Object) + { + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_OPERAND) + { + AcpiOsPrintf ("%22s %p", "Target :", + ObjDesc->Reference.Object); + if (ObjDesc->Reference.Class == ACPI_REFCLASS_TABLE) + { + AcpiOsPrintf (" Table Index: %X\n", + ObjDesc->Reference.Value); + } + else + { + AcpiOsPrintf (" [%s]\n", + AcpiUtGetTypeName (((ACPI_OPERAND_OBJECT *) + ObjDesc->Reference.Object)->Common.Type)); + } + } + else + { + AcpiOsPrintf (" Target: %p\n", ObjDesc->Reference.Object); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpPackageObj + * + * PARAMETERS: ObjDesc - Descriptor to dump + * Level - Indentation Level + * Index - Package index for this object + * + * DESCRIPTION: Dumps the elements of the package + * + ******************************************************************************/ + +static void +AcpiExDumpPackageObj ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Level, + UINT32 Index) +{ + UINT32 i; + + + /* Indentation and index output */ + + if (Level > 0) + { + for (i = 0; i < Level; i++) + { + AcpiOsPrintf (" "); + } + + AcpiOsPrintf ("[%.2d] ", Index); + } + + AcpiOsPrintf ("%p ", ObjDesc); + + /* Null package elements are allowed */ + + if (!ObjDesc) + { + AcpiOsPrintf ("[Null Object]\n"); + return; + } + + /* Packages may only contain a few object types */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + AcpiOsPrintf ("[Integer] = %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("[String] Value: "); + AcpiUtPrintString (ObjDesc->String.Pointer, ACPI_UINT8_MAX); + AcpiOsPrintf ("\n"); + break; + + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf ("[Buffer] Length %.2X = ", ObjDesc->Buffer.Length); + if (ObjDesc->Buffer.Length) + { + AcpiUtDebugDumpBuffer ( + ACPI_CAST_PTR (UINT8, ObjDesc->Buffer.Pointer), + ObjDesc->Buffer.Length, DB_DWORD_DISPLAY, _COMPONENT); + } + else + { + AcpiOsPrintf ("\n"); + } + break; + + case ACPI_TYPE_PACKAGE: + + AcpiOsPrintf ("[Package] Contains %u Elements:\n", + ObjDesc->Package.Count); + + for (i = 0; i < ObjDesc->Package.Count; i++) + { + AcpiExDumpPackageObj ( + ObjDesc->Package.Elements[i], Level + 1, i); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + AcpiOsPrintf ("[Object Reference] Type [%s] %2.2X", + AcpiUtGetReferenceName (ObjDesc), + ObjDesc->Reference.Class); + AcpiExDumpReferenceObj (ObjDesc); + break; + + default: + + AcpiOsPrintf ("[Unknown Type] %X\n", ObjDesc->Common.Type); + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDumpObjectDescriptor + * + * PARAMETERS: ObjDesc - Descriptor to dump + * Flags - Force display if TRUE + * + * DESCRIPTION: Dumps the members of the object descriptor given. + * + ******************************************************************************/ + +void +AcpiExDumpObjectDescriptor ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Flags) +{ + ACPI_FUNCTION_TRACE (ExDumpObjectDescriptor); + + + if (!ObjDesc) + { + return_VOID; + } + + if (!Flags) + { + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_OBJECTS, _COMPONENT)) + { + return_VOID; + } + } + + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_NAMED) + { + AcpiExDumpNamespaceNode ((ACPI_NAMESPACE_NODE *) ObjDesc, Flags); + + AcpiOsPrintf ("\nAttached Object (%p):\n", + ((ACPI_NAMESPACE_NODE *) ObjDesc)->Object); + + ObjDesc = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Object; + goto DumpObject; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) + { + AcpiOsPrintf ( + "%p is not an ACPI operand object: [%s]\n", + ObjDesc, AcpiUtGetDescriptorName (ObjDesc)); + return_VOID; + } + + /* Validate the object type */ + + if (ObjDesc->Common.Type > ACPI_TYPE_LOCAL_MAX) + { + AcpiOsPrintf ("Not a known object type: %2.2X\n", + ObjDesc->Common.Type); + return_VOID; + } + + +DumpObject: + + /* Common Fields */ + + AcpiExDumpObject (ObjDesc, AcpiExDumpCommon); + + /* Object-specific fields */ + + AcpiExDumpObject (ObjDesc, AcpiExDumpInfo[ObjDesc->Common.Type]); + + if (ObjDesc->Common.Type == ACPI_TYPE_REGION) + { + ObjDesc = ObjDesc->Common.NextObject; + if (ObjDesc->Common.Type > ACPI_TYPE_LOCAL_MAX) + { + AcpiOsPrintf ( + "Secondary object is not a known object type: %2.2X\n", + ObjDesc->Common.Type); + + return_VOID; + } + + AcpiOsPrintf ("\nExtra attached Object (%p):\n", ObjDesc); + AcpiExDumpObject (ObjDesc, AcpiExDumpInfo[ObjDesc->Common.Type]); + } + + return_VOID; +} + +#endif diff --git a/third_party/lib/acpica/source/components/executer/exfield.c b/third_party/lib/acpica/source/components/executer/exfield.c new file mode 100644 index 000000000..208af6379 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exfield.c @@ -0,0 +1,578 @@ +/****************************************************************************** + * + * Module Name: exfield - ACPI AML (p-code) execution - field manipulation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exfield") + +/* Local prototypes */ + +static UINT32 +AcpiExGetSerialAccessLength ( + UINT32 AccessorType, + UINT32 AccessLength); + + +/******************************************************************************* + * + * FUNCTION: AcpiExGetSerialAccessLength + * + * PARAMETERS: AccessorType - The type of the protocol indicated by region + * field access attributes + * AccessLength - The access length of the region field + * + * RETURN: Decoded access length + * + * DESCRIPTION: This routine returns the length of the GenericSerialBus + * protocol bytes + * + ******************************************************************************/ + +static UINT32 +AcpiExGetSerialAccessLength ( + UINT32 AccessorType, + UINT32 AccessLength) +{ + UINT32 Length; + + + switch (AccessorType) + { + case AML_FIELD_ATTRIB_QUICK: + + Length = 0; + break; + + case AML_FIELD_ATTRIB_SEND_RCV: + case AML_FIELD_ATTRIB_BYTE: + + Length = 1; + break; + + case AML_FIELD_ATTRIB_WORD: + case AML_FIELD_ATTRIB_WORD_CALL: + + Length = 2; + break; + + case AML_FIELD_ATTRIB_MULTIBYTE: + case AML_FIELD_ATTRIB_RAW_BYTES: + case AML_FIELD_ATTRIB_RAW_PROCESS: + + Length = AccessLength; + break; + + case AML_FIELD_ATTRIB_BLOCK: + case AML_FIELD_ATTRIB_BLOCK_CALL: + default: + + Length = ACPI_GSBUS_BUFFER_SIZE - 2; + break; + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExReadDataFromField + * + * PARAMETERS: WalkState - Current execution state + * ObjDesc - The named field + * RetBufferDesc - Where the return data object is stored + * + * RETURN: Status + * + * DESCRIPTION: Read from a named field. Returns either an Integer or a + * Buffer, depending on the size of the field. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExReadDataFromField ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **RetBufferDesc) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *BufferDesc; + ACPI_SIZE Length; + void *Buffer; + UINT32 Function; + UINT16 AccessorType; + + + ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc); + + + /* Parameter validation */ + + if (!ObjDesc) + { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + if (!RetBufferDesc) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) + { + /* + * If the BufferField arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + Status = AcpiDsGetBufferFieldArguments (ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || + ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || + ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) + { + /* + * This is an SMBus, GSBus or IPMI read. We must create a buffer to + * hold the data and then directly access the region handler. + * + * Note: SMBus and GSBus protocol value is passed in upper 16-bits + * of Function + */ + if (ObjDesc->Field.RegionObj->Region.SpaceId == + ACPI_ADR_SPACE_SMBUS) + { + Length = ACPI_SMBUS_BUFFER_SIZE; + Function = ACPI_READ | (ObjDesc->Field.Attribute << 16); + } + else if (ObjDesc->Field.RegionObj->Region.SpaceId == + ACPI_ADR_SPACE_GSBUS) + { + AccessorType = ObjDesc->Field.Attribute; + Length = AcpiExGetSerialAccessLength ( + AccessorType, ObjDesc->Field.AccessLength); + + /* + * Add additional 2 bytes for the GenericSerialBus data buffer: + * + * Status; (Byte 0 of the data buffer) + * Length; (Byte 1 of the data buffer) + * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) + */ + Length += 2; + Function = ACPI_READ | (AccessorType << 16); + } + else /* IPMI */ + { + Length = ACPI_IPMI_BUFFER_SIZE; + Function = ACPI_READ; + } + + BufferDesc = AcpiUtCreateBufferObject (Length); + if (!BufferDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Lock entire transaction if requested */ + + AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); + + /* Call the region handler for the read */ + + Status = AcpiExAccessRegion (ObjDesc, 0, + ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function); + + AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); + goto Exit; + } + + /* + * Allocate a buffer for the contents of the field. + * + * If the field is larger than the current integer width, create + * a BUFFER to hold it. Otherwise, use an INTEGER. This allows + * the use of arithmetic operators on the returned value if the + * field size is equal or smaller than an Integer. + * + * Note: Field.length is in bits. + */ + Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->Field.BitLength); + + if (Length > AcpiGbl_IntegerByteWidth) + { + /* Field is too large for an Integer, create a Buffer instead */ + + BufferDesc = AcpiUtCreateBufferObject (Length); + if (!BufferDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + Buffer = BufferDesc->Buffer.Pointer; + } + else + { + /* Field will fit within an Integer (normal case) */ + + BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0); + if (!BufferDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Length = AcpiGbl_IntegerByteWidth; + Buffer = &BufferDesc->Integer.Value; + } + + if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO)) + { + /* + * For GPIO (GeneralPurposeIo), the Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The BitLength is the length of the field, which + * is thus the number of pins. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "GPIO FieldRead [FROM]: Pin %u Bits %u\n", + ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength)); + + /* Lock entire transaction if requested */ + + AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); + + /* Perform the write */ + + Status = AcpiExAccessRegion ( + ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ); + + AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (BufferDesc); + } + else + { + *RetBufferDesc = BufferDesc; + } + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", + ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", + ObjDesc->CommonField.BitLength, + ObjDesc->CommonField.StartFieldBitOffset, + ObjDesc->CommonField.BaseByteOffset)); + + /* Lock entire transaction if requested */ + + AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); + + /* Read from the field */ + + Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length); + AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); + + +Exit: + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (BufferDesc); + } + else + { + *RetBufferDesc = BufferDesc; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExWriteDataToField + * + * PARAMETERS: SourceDesc - Contains data to write + * ObjDesc - The named field + * ResultDesc - Where the return value is returned, if any + * + * RETURN: Status + * + * DESCRIPTION: Write to a named field + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExWriteDataToField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc) +{ + ACPI_STATUS Status; + UINT32 Length; + void *Buffer; + ACPI_OPERAND_OBJECT *BufferDesc; + UINT32 Function; + UINT16 AccessorType; + + + ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc); + + + /* Parameter validation */ + + if (!SourceDesc || !ObjDesc) + { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) + { + /* + * If the BufferField arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + Status = AcpiDsGetBufferFieldArguments (ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || + ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || + ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) + { + /* + * This is an SMBus, GSBus or IPMI write. We will bypass the entire + * field mechanism and handoff the buffer directly to the handler. + * For these address spaces, the buffer is bi-directional; on a + * write, return data is returned in the same buffer. + * + * Source must be a buffer of sufficient size: + * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or + * ACPI_IPMI_BUFFER_SIZE. + * + * Note: SMBus and GSBus protocol type is passed in upper 16-bits + * of Function + */ + if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) + { + ACPI_ERROR ((AE_INFO, + "SMBus/IPMI/GenericSerialBus write requires " + "Buffer, found type %s", + AcpiUtGetObjectTypeName (SourceDesc))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + if (ObjDesc->Field.RegionObj->Region.SpaceId == + ACPI_ADR_SPACE_SMBUS) + { + Length = ACPI_SMBUS_BUFFER_SIZE; + Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16); + } + else if (ObjDesc->Field.RegionObj->Region.SpaceId == + ACPI_ADR_SPACE_GSBUS) + { + AccessorType = ObjDesc->Field.Attribute; + Length = AcpiExGetSerialAccessLength ( + AccessorType, ObjDesc->Field.AccessLength); + + /* + * Add additional 2 bytes for the GenericSerialBus data buffer: + * + * Status; (Byte 0 of the data buffer) + * Length; (Byte 1 of the data buffer) + * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) + */ + Length += 2; + Function = ACPI_WRITE | (AccessorType << 16); + } + else /* IPMI */ + { + Length = ACPI_IPMI_BUFFER_SIZE; + Function = ACPI_WRITE; + } + + if (SourceDesc->Buffer.Length < Length) + { + ACPI_ERROR ((AE_INFO, + "SMBus/IPMI/GenericSerialBus write requires " + "Buffer of length %u, found length %u", + Length, SourceDesc->Buffer.Length)); + + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); + } + + /* Create the bi-directional buffer */ + + BufferDesc = AcpiUtCreateBufferObject (Length); + if (!BufferDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Buffer = BufferDesc->Buffer.Pointer; + memcpy (Buffer, SourceDesc->Buffer.Pointer, Length); + + /* Lock entire transaction if requested */ + + AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); + + /* + * Perform the write (returns status and perhaps data in the + * same buffer) + */ + Status = AcpiExAccessRegion ( + ObjDesc, 0, (UINT64 *) Buffer, Function); + AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); + + *ResultDesc = BufferDesc; + return_ACPI_STATUS (Status); + } + else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO)) + { + /* + * For GPIO (GeneralPurposeIo), we will bypass the entire field + * mechanism and handoff the bit address and bit width directly to + * the handler. The Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The BitLength is the length of the field, which + * is thus the number of pins. + */ + if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER) + { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", + AcpiUtGetTypeName (SourceDesc->Common.Type), + SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value, + ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength)); + + Buffer = &SourceDesc->Integer.Value; + + /* Lock entire transaction if requested */ + + AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); + + /* Perform the write */ + + Status = AcpiExAccessRegion ( + ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE); + AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); + return_ACPI_STATUS (Status); + } + + /* Get a pointer to the data to be written */ + + switch (SourceDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + Buffer = &SourceDesc->Integer.Value; + Length = sizeof (SourceDesc->Integer.Value); + break; + + case ACPI_TYPE_BUFFER: + + Buffer = SourceDesc->Buffer.Pointer; + Length = SourceDesc->Buffer.Length; + break; + + case ACPI_TYPE_STRING: + + Buffer = SourceDesc->String.Pointer; + Length = SourceDesc->String.Length; + break; + + default: + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", + SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type), + SourceDesc->Common.Type, Buffer, Length)); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", + ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type), + ObjDesc->Common.Type, + ObjDesc->CommonField.BitLength, + ObjDesc->CommonField.StartFieldBitOffset, + ObjDesc->CommonField.BaseByteOffset)); + + /* Lock entire transaction if requested */ + + AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); + + /* Write to the field */ + + Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length); + AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exfldio.c b/third_party/lib/acpica/source/components/executer/exfldio.c new file mode 100644 index 000000000..fd46a0c02 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exfldio.c @@ -0,0 +1,1059 @@ +/****************************************************************************** + * + * Module Name: exfldio - Aml Field I/O + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acevents.h" +#include "acdispat.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exfldio") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiExFieldDatumIo ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset, + UINT64 *Value, + UINT32 ReadWrite); + +static BOOLEAN +AcpiExRegisterOverflow ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT64 Value); + +static ACPI_STATUS +AcpiExSetupRegion ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset); + + +/******************************************************************************* + * + * FUNCTION: AcpiExSetupRegion + * + * PARAMETERS: ObjDesc - Field to be read or written + * FieldDatumByteOffset - Byte offset of this datum within the + * parent field + * + * RETURN: Status + * + * DESCRIPTION: Common processing for AcpiExExtractFromField and + * AcpiExInsertIntoField. Initialize the Region if necessary and + * validate the request. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExSetupRegion ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *RgnDesc; + UINT8 SpaceId; + + + ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset); + + + RgnDesc = ObjDesc->CommonField.RegionObj; + + /* We must have a valid region */ + + if (RgnDesc->Common.Type != ACPI_TYPE_REGION) + { + ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", + RgnDesc->Common.Type, + AcpiUtGetObjectTypeName (RgnDesc))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + SpaceId = RgnDesc->Region.SpaceId; + + /* Validate the Space ID */ + + if (!AcpiIsValidSpaceId (SpaceId)) + { + ACPI_ERROR ((AE_INFO, + "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId)); + return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID); + } + + /* + * If the Region Address and Length have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + Status = AcpiDsGetRegionArguments (RgnDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear + * address space and the request cannot be directly validated + */ + if (SpaceId == ACPI_ADR_SPACE_SMBUS || + SpaceId == ACPI_ADR_SPACE_GSBUS || + SpaceId == ACPI_ADR_SPACE_IPMI) + { + /* SMBus or IPMI has a non-linear address space */ + + return_ACPI_STATUS (AE_OK); + } + +#ifdef ACPI_UNDER_DEVELOPMENT + /* + * If the Field access is AnyAcc, we can now compute the optimal + * access (because we know know the length of the parent region) + */ + if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } +#endif + + /* + * Validate the request. The entire request from the byte offset for a + * length of one field datum (access width) must fit within the region. + * (Region length is specified in bytes) + */ + if (RgnDesc->Region.Length < + (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset + + ObjDesc->CommonField.AccessByteWidth)) + { + if (AcpiGbl_EnableInterpreterSlack) + { + /* + * Slack mode only: We will go ahead and allow access to this + * field if it is within the region length rounded up to the next + * access width boundary. ACPI_SIZE cast for 64-bit compile. + */ + if (ACPI_ROUND_UP (RgnDesc->Region.Length, + ObjDesc->CommonField.AccessByteWidth) >= + ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset + + ObjDesc->CommonField.AccessByteWidth + + FieldDatumByteOffset)) + { + return_ACPI_STATUS (AE_OK); + } + } + + if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) + { + /* + * This is the case where the AccessType (AccWord, etc.) is wider + * than the region itself. For example, a region of length one + * byte, and a field with Dword access specified. + */ + ACPI_ERROR ((AE_INFO, + "Field [%4.4s] access width (%u bytes) " + "too large for region [%4.4s] (length %u)", + AcpiUtGetNodeName (ObjDesc->CommonField.Node), + ObjDesc->CommonField.AccessByteWidth, + AcpiUtGetNodeName (RgnDesc->Region.Node), + RgnDesc->Region.Length)); + } + + /* + * Offset rounded up to next multiple of field width + * exceeds region length, indicate an error + */ + ACPI_ERROR ((AE_INFO, + "Field [%4.4s] Base+Offset+Width %u+%u+%u " + "is beyond end of region [%4.4s] (length %u)", + AcpiUtGetNodeName (ObjDesc->CommonField.Node), + ObjDesc->CommonField.BaseByteOffset, + FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, + AcpiUtGetNodeName (RgnDesc->Region.Node), + RgnDesc->Region.Length)); + + return_ACPI_STATUS (AE_AML_REGION_LIMIT); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExAccessRegion + * + * PARAMETERS: ObjDesc - Field to be read + * FieldDatumByteOffset - Byte offset of this datum within the + * parent field + * Value - Where to store value (must at least + * 64 bits) + * Function - Read or Write flag plus other region- + * dependent flags + * + * RETURN: Status + * + * DESCRIPTION: Read or Write a single field datum to an Operation Region. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExAccessRegion ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset, + UINT64 *Value, + UINT32 Function) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *RgnDesc; + UINT32 RegionOffset; + + + ACPI_FUNCTION_TRACE (ExAccessRegion); + + + /* + * Ensure that the region operands are fully evaluated and verify + * the validity of the request + */ + Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * The physical address of this field datum is: + * + * 1) The base of the region, plus + * 2) The base offset of the field, plus + * 3) The current offset into the field + */ + RgnDesc = ObjDesc->CommonField.RegionObj; + RegionOffset = + ObjDesc->CommonField.BaseByteOffset + + FieldDatumByteOffset; + + if ((Function & ACPI_IO_MASK) == ACPI_READ) + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, + " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", + AcpiUtGetRegionName (RgnDesc->Region.SpaceId), + RgnDesc->Region.SpaceId, + ObjDesc->CommonField.AccessByteWidth, + ObjDesc->CommonField.BaseByteOffset, + FieldDatumByteOffset, + ACPI_FORMAT_UINT64 (RgnDesc->Region.Address + RegionOffset))); + + /* Invoke the appropriate AddressSpace/OpRegion handler */ + + Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc, + Function, RegionOffset, + ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); + + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_IMPLEMENTED) + { + ACPI_ERROR ((AE_INFO, + "Region %s (ID=%u) not implemented", + AcpiUtGetRegionName (RgnDesc->Region.SpaceId), + RgnDesc->Region.SpaceId)); + } + else if (Status == AE_NOT_EXIST) + { + ACPI_ERROR ((AE_INFO, + "Region %s (ID=%u) has no handler", + AcpiUtGetRegionName (RgnDesc->Region.SpaceId), + RgnDesc->Region.SpaceId)); + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExRegisterOverflow + * + * PARAMETERS: ObjDesc - Register(Field) to be written + * Value - Value to be stored + * + * RETURN: TRUE if value overflows the field, FALSE otherwise + * + * DESCRIPTION: Check if a value is out of range of the field being written. + * Used to check if the values written to Index and Bank registers + * are out of range. Normally, the value is simply truncated + * to fit the field, but this case is most likely a serious + * coding error in the ASL. + * + ******************************************************************************/ + +static BOOLEAN +AcpiExRegisterOverflow ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT64 Value) +{ + + if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) + { + /* + * The field is large enough to hold the maximum integer, so we can + * never overflow it. + */ + return (FALSE); + } + + if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength)) + { + /* + * The Value is larger than the maximum value that can fit into + * the register. + */ + ACPI_ERROR ((AE_INFO, + "Index value 0x%8.8X%8.8X overflows field width 0x%X", + ACPI_FORMAT_UINT64 (Value), + ObjDesc->CommonField.BitLength)); + + return (TRUE); + } + + /* The Value will fit into the field with no truncation */ + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExFieldDatumIo + * + * PARAMETERS: ObjDesc - Field to be read + * FieldDatumByteOffset - Byte offset of this datum within the + * parent field + * Value - Where to store value (must be 64 bits) + * ReadWrite - Read or Write flag + * + * RETURN: Status + * + * DESCRIPTION: Read or Write a single datum of a field. The FieldType is + * demultiplexed here to handle the different types of fields + * (BufferField, RegionField, IndexField, BankField) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExFieldDatumIo ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset, + UINT64 *Value, + UINT32 ReadWrite) +{ + ACPI_STATUS Status; + UINT64 LocalValue; + + + ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset); + + + if (ReadWrite == ACPI_READ) + { + if (!Value) + { + LocalValue = 0; + + /* To support reads without saving return value */ + Value = &LocalValue; + } + + /* Clear the entire return buffer first, [Very Important!] */ + + *Value = 0; + } + + /* + * The four types of fields are: + * + * BufferField - Read/write from/to a Buffer + * RegionField - Read/write from/to a Operation Region. + * BankField - Write to a Bank Register, then read/write from/to an + * OperationRegion + * IndexField - Write to an Index Register, then read/write from/to a + * Data Register + */ + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_BUFFER_FIELD: + /* + * If the BufferField arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + Status = AcpiDsGetBufferFieldArguments (ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + if (ReadWrite == ACPI_READ) + { + /* + * Copy the data from the source buffer. + * Length is the field width in bytes. + */ + memcpy (Value, + (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + + ObjDesc->BufferField.BaseByteOffset + + FieldDatumByteOffset, + ObjDesc->CommonField.AccessByteWidth); + } + else + { + /* + * Copy the data to the target buffer. + * Length is the field width in bytes. + */ + memcpy ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + + ObjDesc->BufferField.BaseByteOffset + + FieldDatumByteOffset, + Value, ObjDesc->CommonField.AccessByteWidth); + } + + Status = AE_OK; + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + /* + * Ensure that the BankValue is not beyond the capacity of + * the register + */ + if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, + (UINT64) ObjDesc->BankField.Value)) + { + return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); + } + + /* + * For BankFields, we must write the BankValue to the BankRegister + * (itself a RegionField) before we can access the data. + */ + Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, + &ObjDesc->BankField.Value, + sizeof (ObjDesc->BankField.Value)); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Now that the Bank has been selected, fall through to the + * RegionField case and write the datum to the Operation Region + */ + + /*lint -fallthrough */ + + case ACPI_TYPE_LOCAL_REGION_FIELD: + /* + * For simple RegionFields, we just directly access the owning + * Operation Region. + */ + Status = AcpiExAccessRegion ( + ObjDesc, FieldDatumByteOffset, Value, ReadWrite); + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * Ensure that the IndexValue is not beyond the capacity of + * the register + */ + if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, + (UINT64) ObjDesc->IndexField.Value)) + { + return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); + } + + /* Write the index value to the IndexRegister (itself a RegionField) */ + + FieldDatumByteOffset += ObjDesc->IndexField.Value; + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Write to Index Register: Value %8.8X\n", + FieldDatumByteOffset)); + + Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, + &FieldDatumByteOffset, sizeof (FieldDatumByteOffset)); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (ReadWrite == ACPI_READ) + { + /* Read the datum from the DataRegister */ + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Read from Data Register\n")); + + Status = AcpiExExtractFromField ( + ObjDesc->IndexField.DataObj, Value, sizeof (UINT64)); + } + else + { + /* Write the datum to the DataRegister */ + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Write to Data Register: Value %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (*Value))); + + Status = AcpiExInsertIntoField ( + ObjDesc->IndexField.DataObj, Value, sizeof (UINT64)); + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", + ObjDesc->Common.Type)); + Status = AE_AML_INTERNAL; + break; + } + + if (ACPI_SUCCESS (Status)) + { + if (ReadWrite == ACPI_READ) + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Read %8.8X%8.8X, Width %u\n", + ACPI_FORMAT_UINT64 (*Value), + ObjDesc->CommonField.AccessByteWidth)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Written %8.8X%8.8X, Width %u\n", + ACPI_FORMAT_UINT64 (*Value), + ObjDesc->CommonField.AccessByteWidth)); + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExWriteWithUpdateRule + * + * PARAMETERS: ObjDesc - Field to be written + * Mask - bitmask within field datum + * FieldValue - Value to write + * FieldDatumByteOffset - Offset of datum within field + * + * RETURN: Status + * + * DESCRIPTION: Apply the field update rule to a field write + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExWriteWithUpdateRule ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT64 Mask, + UINT64 FieldValue, + UINT32 FieldDatumByteOffset) +{ + ACPI_STATUS Status = AE_OK; + UINT64 MergedValue; + UINT64 CurrentValue; + + + ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); + + + /* Start with the new bits */ + + MergedValue = FieldValue; + + /* If the mask is all ones, we don't need to worry about the update rule */ + + if (Mask != ACPI_UINT64_MAX) + { + /* Decode the update rule */ + + switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) + { + case AML_FIELD_UPDATE_PRESERVE: + /* + * Check if update rule needs to be applied (not if mask is all + * ones) The left shift drops the bits we want to ignore. + */ + if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - + ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) + { + /* + * Read the current contents of the byte/word/dword containing + * the field, and merge with the new field value. + */ + Status = AcpiExFieldDatumIo ( + ObjDesc, FieldDatumByteOffset, &CurrentValue, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + MergedValue |= (CurrentValue & ~Mask); + } + break; + + case AML_FIELD_UPDATE_WRITE_AS_ONES: + + /* Set positions outside the field to all ones */ + + MergedValue |= ~Mask; + break; + + case AML_FIELD_UPDATE_WRITE_AS_ZEROS: + + /* Set positions outside the field to all zeros */ + + MergedValue &= Mask; + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown UpdateRule value: 0x%X", + (ObjDesc->CommonField.FieldFlags & + AML_FIELD_UPDATE_RULE_MASK))); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Mask %8.8X%8.8X, DatumOffset %X, Width %X, " + "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Mask), + FieldDatumByteOffset, + ObjDesc->CommonField.AccessByteWidth, + ACPI_FORMAT_UINT64 (FieldValue), + ACPI_FORMAT_UINT64 (MergedValue))); + + /* Write the merged value */ + + Status = AcpiExFieldDatumIo ( + ObjDesc, FieldDatumByteOffset, &MergedValue, ACPI_WRITE); + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExExtractFromField + * + * PARAMETERS: ObjDesc - Field to be read + * Buffer - Where to store the field data + * BufferLength - Length of Buffer + * + * RETURN: Status + * + * DESCRIPTION: Retrieve the current value of the given field + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExExtractFromField ( + ACPI_OPERAND_OBJECT *ObjDesc, + void *Buffer, + UINT32 BufferLength) +{ + ACPI_STATUS Status; + UINT64 RawDatum; + UINT64 MergedDatum; + UINT32 FieldOffset = 0; + UINT32 BufferOffset = 0; + UINT32 BufferTailBits; + UINT32 DatumCount; + UINT32 FieldDatumCount; + UINT32 AccessBitWidth; + UINT32 i; + + + ACPI_FUNCTION_TRACE (ExExtractFromField); + + + /* Validate target buffer and clear it */ + + if (BufferLength < + ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) + { + ACPI_ERROR ((AE_INFO, + "Field size %u (bits) is too large for buffer (%u)", + ObjDesc->CommonField.BitLength, BufferLength)); + + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } + + memset (Buffer, 0, BufferLength); + AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); + + /* Handle the simple case here */ + + if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && + (ObjDesc->CommonField.BitLength == AccessBitWidth)) + { + if (BufferLength >= sizeof (UINT64)) + { + Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); + } + else + { + /* Use RawDatum (UINT64) to handle buffers < 64 bits */ + + Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ); + memcpy (Buffer, &RawDatum, BufferLength); + } + + return_ACPI_STATUS (Status); + } + +/* TBD: Move to common setup code */ + + /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ + + if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) + { + ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); + AccessBitWidth = sizeof (UINT64) * 8; + } + + /* Compute the number of datums (access width data items) */ + + DatumCount = ACPI_ROUND_UP_TO ( + ObjDesc->CommonField.BitLength, AccessBitWidth); + + FieldDatumCount = ACPI_ROUND_UP_TO ( + ObjDesc->CommonField.BitLength + + ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); + + /* Priming read from the field */ + + Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; + + /* Read the rest of the field */ + + for (i = 1; i < FieldDatumCount; i++) + { + /* Get next input datum from the field */ + + FieldOffset += ObjDesc->CommonField.AccessByteWidth; + Status = AcpiExFieldDatumIo ( + ObjDesc, FieldOffset, &RawDatum, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Merge with previous datum if necessary. + * + * Note: Before the shift, check if the shift value will be larger than + * the integer size. If so, there is no need to perform the operation. + * This avoids the differences in behavior between different compilers + * concerning shift values larger than the target data width. + */ + if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < + ACPI_INTEGER_BIT_SIZE) + { + MergedDatum |= RawDatum << + (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); + } + + if (i == DatumCount) + { + break; + } + + /* Write merged datum to target buffer */ + + memcpy (((char *) Buffer) + BufferOffset, &MergedDatum, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); + + BufferOffset += ObjDesc->CommonField.AccessByteWidth; + MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; + } + + /* Mask off any extra bits in the last datum */ + + BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; + if (BufferTailBits) + { + MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); + } + + /* Write the last datum to the buffer */ + + memcpy (((char *) Buffer) + BufferOffset, &MergedDatum, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExInsertIntoField + * + * PARAMETERS: ObjDesc - Field to be written + * Buffer - Data to be written + * BufferLength - Length of Buffer + * + * RETURN: Status + * + * DESCRIPTION: Store the Buffer contents into the given field + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExInsertIntoField ( + ACPI_OPERAND_OBJECT *ObjDesc, + void *Buffer, + UINT32 BufferLength) +{ + void *NewBuffer; + ACPI_STATUS Status; + UINT64 Mask; + UINT64 WidthMask; + UINT64 MergedDatum; + UINT64 RawDatum = 0; + UINT32 FieldOffset = 0; + UINT32 BufferOffset = 0; + UINT32 BufferTailBits; + UINT32 DatumCount; + UINT32 FieldDatumCount; + UINT32 AccessBitWidth; + UINT32 RequiredLength; + UINT32 i; + + + ACPI_FUNCTION_TRACE (ExInsertIntoField); + + + /* Validate input buffer */ + + NewBuffer = NULL; + RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->CommonField.BitLength); + + /* + * We must have a buffer that is at least as long as the field + * we are writing to. This is because individual fields are + * indivisible and partial writes are not supported -- as per + * the ACPI specification. + */ + if (BufferLength < RequiredLength) + { + /* We need to create a new buffer */ + + NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); + if (!NewBuffer) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Copy the original data to the new buffer, starting + * at Byte zero. All unused (upper) bytes of the + * buffer will be 0. + */ + memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength); + Buffer = NewBuffer; + BufferLength = RequiredLength; + } + +/* TBD: Move to common setup code */ + + /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ + if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) + { + ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); + } + + AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); + + /* + * Create the bitmasks used for bit insertion. + * Note: This if/else is used to bypass compiler differences with the + * shift operator + */ + if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) + { + WidthMask = ACPI_UINT64_MAX; + } + else + { + WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); + } + + Mask = WidthMask & + ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); + + /* Compute the number of datums (access width data items) */ + + DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, + AccessBitWidth); + + FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + + ObjDesc->CommonField.StartFieldBitOffset, + AccessBitWidth); + + /* Get initial Datum from the input buffer */ + + memcpy (&RawDatum, Buffer, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); + + MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; + + /* Write the entire field */ + + for (i = 1; i < FieldDatumCount; i++) + { + /* Write merged datum to the target field */ + + MergedDatum &= Mask; + Status = AcpiExWriteWithUpdateRule ( + ObjDesc, Mask, MergedDatum, FieldOffset); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + FieldOffset += ObjDesc->CommonField.AccessByteWidth; + + /* + * Start new output datum by merging with previous input datum + * if necessary. + * + * Note: Before the shift, check if the shift value will be larger than + * the integer size. If so, there is no need to perform the operation. + * This avoids the differences in behavior between different compilers + * concerning shift values larger than the target data width. + */ + if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < + ACPI_INTEGER_BIT_SIZE) + { + MergedDatum = RawDatum >> + (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); + } + else + { + MergedDatum = 0; + } + + Mask = WidthMask; + + if (i == DatumCount) + { + break; + } + + /* Get the next input datum from the buffer */ + + BufferOffset += ObjDesc->CommonField.AccessByteWidth; + memcpy (&RawDatum, ((char *) Buffer) + BufferOffset, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); + + MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; + } + + /* Mask off any extra bits in the last datum */ + + BufferTailBits = (ObjDesc->CommonField.BitLength + + ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth; + if (BufferTailBits) + { + Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); + } + + /* Write the last datum to the field */ + + MergedDatum &= Mask; + Status = AcpiExWriteWithUpdateRule ( + ObjDesc, Mask, MergedDatum, FieldOffset); + +Exit: + /* Free temporary buffer if we used one */ + + if (NewBuffer) + { + ACPI_FREE (NewBuffer); + } + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exmisc.c b/third_party/lib/acpica/source/components/executer/exmisc.c new file mode 100644 index 000000000..c1dd227b3 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exmisc.c @@ -0,0 +1,826 @@ +/****************************************************************************** + * + * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "amlresrc.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exmisc") + + +/******************************************************************************* + * + * FUNCTION: AcpiExGetObjectReference + * + * PARAMETERS: ObjDesc - Create a reference to this object + * ReturnDesc - Where to store the reference + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Obtain and return a "reference" to the target object + * Common code for the RefOfOp and the CondRefOfOp. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExGetObjectReference ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ReturnDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *ReferenceObj; + ACPI_OPERAND_OBJECT *ReferencedObj; + + + ACPI_FUNCTION_TRACE_PTR (ExGetObjectReference, ObjDesc); + + + *ReturnDesc = NULL; + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) + { + case ACPI_DESC_TYPE_OPERAND: + + if (ObjDesc->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) + { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * Must be a reference to a Local or Arg + */ + switch (ObjDesc->Reference.Class) + { + case ACPI_REFCLASS_LOCAL: + case ACPI_REFCLASS_ARG: + case ACPI_REFCLASS_DEBUG: + + /* The referenced object is the pseudo-node for the local/arg */ + + ReferencedObj = ObjDesc->Reference.Object; + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid Reference Class 0x%2.2X", + ObjDesc->Reference.Class)); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + break; + + case ACPI_DESC_TYPE_NAMED: + /* + * A named reference that has already been resolved to a Node + */ + ReferencedObj = ObjDesc; + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X", + ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))); + return_ACPI_STATUS (AE_TYPE); + } + + + /* Create a new reference object */ + + ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); + if (!ReferenceObj) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF; + ReferenceObj->Reference.Object = ReferencedObj; + *ReturnDesc = ReferenceObj; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Object %p Type [%s], returning Reference %p\n", + ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExConcatTemplate + * + * PARAMETERS: Operand0 - First source object + * Operand1 - Second source object + * ActualReturnDesc - Where to place the return object + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Concatenate two resource templates + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExConcatTemplate ( + ACPI_OPERAND_OBJECT *Operand0, + ACPI_OPERAND_OBJECT *Operand1, + ACPI_OPERAND_OBJECT **ActualReturnDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ReturnDesc; + UINT8 *NewBuf; + UINT8 *EndTag; + ACPI_SIZE Length0; + ACPI_SIZE Length1; + ACPI_SIZE NewLength; + + + ACPI_FUNCTION_TRACE (ExConcatTemplate); + + + /* + * Find the EndTag descriptor in each resource template. + * Note1: returned pointers point TO the EndTag, not past it. + * Note2: zero-length buffers are allowed; treated like one EndTag + */ + + /* Get the length of the first resource template */ + + Status = AcpiUtGetResourceEndTag (Operand0, &EndTag); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer); + + /* Get the length of the second resource template */ + + Status = AcpiUtGetResourceEndTag (Operand1, &EndTag); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer); + + /* Combine both lengths, minimum size will be 2 for EndTag */ + + NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG); + + /* Create a new buffer object for the result (with one EndTag) */ + + ReturnDesc = AcpiUtCreateBufferObject (NewLength); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Copy the templates to the new buffer, 0 first, then 1 follows. One + * EndTag descriptor is copied from Operand1. + */ + NewBuf = ReturnDesc->Buffer.Pointer; + memcpy (NewBuf, Operand0->Buffer.Pointer, Length0); + memcpy (NewBuf + Length0, Operand1->Buffer.Pointer, Length1); + + /* Insert EndTag and set the checksum to zero, means "ignore checksum" */ + + NewBuf[NewLength - 1] = 0; + NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; + + /* Return the completed resource template */ + + *ActualReturnDesc = ReturnDesc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDoConcatenate + * + * PARAMETERS: Operand0 - First source object + * Operand1 - Second source object + * ActualReturnDesc - Where to place the return object + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Concatenate two objects OF THE SAME TYPE. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExDoConcatenate ( + ACPI_OPERAND_OBJECT *Operand0, + ACPI_OPERAND_OBJECT *Operand1, + ACPI_OPERAND_OBJECT **ActualReturnDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; + ACPI_OPERAND_OBJECT *ReturnDesc; + char *NewBuf; + const char *TypeString; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExDoConcatenate); + + + /* + * Convert the second operand if necessary. The first operand + * determines the type of the second operand, (See the Data Types + * section of the ACPI specification.) Both object types are + * guaranteed to be either Integer/String/Buffer by the operand + * resolution mechanism. + */ + switch (Operand0->Common.Type) + { + case ACPI_TYPE_INTEGER: + + Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16); + break; + + case ACPI_TYPE_STRING: + /* + * Per the ACPI spec, Concatenate only supports int/str/buf. + * However, we support all objects here as an extension. + * This improves the usefulness of the Printf() macro. + * 12/2015. + */ + switch (Operand1->Common.Type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + Status = AcpiExConvertToString ( + Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX); + break; + + default: + /* + * Just emit a string containing the object type. + */ + TypeString = AcpiUtGetTypeName (Operand1->Common.Type); + + LocalOperand1 = AcpiUtCreateStringObject ( + ((ACPI_SIZE) strlen (TypeString) + 9)); /* 9 For "[Object]" */ + if (!LocalOperand1) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + strcpy (LocalOperand1->String.Pointer, "["); + strcat (LocalOperand1->String.Pointer, TypeString); + strcat (LocalOperand1->String.Pointer, " Object]"); + Status = AE_OK; + break; + } + break; + + case ACPI_TYPE_BUFFER: + + Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", + Operand0->Common.Type)); + Status = AE_AML_INTERNAL; + } + + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * Both operands are now known to be the same object type + * (Both are Integer, String, or Buffer), and we can now perform the + * concatenation. + */ + + /* + * There are three cases to handle: + * + * 1) Two Integers concatenated to produce a new Buffer + * 2) Two Strings concatenated to produce a new String + * 3) Two Buffers concatenated to produce a new Buffer + */ + switch (Operand0->Common.Type) + { + case ACPI_TYPE_INTEGER: + + /* Result of two Integers is a Buffer */ + /* Need enough buffer space for two integers */ + + ReturnDesc = AcpiUtCreateBufferObject ( + (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth)); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + NewBuf = (char *) ReturnDesc->Buffer.Pointer; + + /* Copy the first integer, LSB first */ + + memcpy (NewBuf, &Operand0->Integer.Value, + AcpiGbl_IntegerByteWidth); + + /* Copy the second integer (LSB first) after the first */ + + memcpy (NewBuf + AcpiGbl_IntegerByteWidth, + &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth); + break; + + case ACPI_TYPE_STRING: + + /* Result of two Strings is a String */ + + ReturnDesc = AcpiUtCreateStringObject ( + ((ACPI_SIZE) Operand0->String.Length + + LocalOperand1->String.Length)); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + NewBuf = ReturnDesc->String.Pointer; + + /* Concatenate the strings */ + + strcpy (NewBuf, Operand0->String.Pointer); + strcat (NewBuf, LocalOperand1->String.Pointer); + break; + + case ACPI_TYPE_BUFFER: + + /* Result of two Buffers is a Buffer */ + + ReturnDesc = AcpiUtCreateBufferObject ( + ((ACPI_SIZE) Operand0->Buffer.Length + + LocalOperand1->Buffer.Length)); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + NewBuf = (char *) ReturnDesc->Buffer.Pointer; + + /* Concatenate the buffers */ + + memcpy (NewBuf, Operand0->Buffer.Pointer, + Operand0->Buffer.Length); + memcpy (NewBuf + Operand0->Buffer.Length, + LocalOperand1->Buffer.Pointer, + LocalOperand1->Buffer.Length); + break; + + default: + + /* Invalid object type, should not happen here */ + + ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X", + Operand0->Common.Type)); + Status =AE_AML_INTERNAL; + goto Cleanup; + } + + *ActualReturnDesc = ReturnDesc; + +Cleanup: + if (LocalOperand1 != Operand1) + { + AcpiUtRemoveReference (LocalOperand1); + } + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDoMathOp + * + * PARAMETERS: Opcode - AML opcode + * Integer0 - Integer operand #0 + * Integer1 - Integer operand #1 + * + * RETURN: Integer result of the operation + * + * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the + * math functions here is to prevent a lot of pointer dereferencing + * to obtain the operands. + * + ******************************************************************************/ + +UINT64 +AcpiExDoMathOp ( + UINT16 Opcode, + UINT64 Integer0, + UINT64 Integer1) +{ + + ACPI_FUNCTION_ENTRY (); + + + switch (Opcode) + { + case AML_ADD_OP: /* Add (Integer0, Integer1, Result) */ + + return (Integer0 + Integer1); + + case AML_BIT_AND_OP: /* And (Integer0, Integer1, Result) */ + + return (Integer0 & Integer1); + + case AML_BIT_NAND_OP: /* NAnd (Integer0, Integer1, Result) */ + + return (~(Integer0 & Integer1)); + + case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */ + + return (Integer0 | Integer1); + + case AML_BIT_NOR_OP: /* NOr (Integer0, Integer1, Result) */ + + return (~(Integer0 | Integer1)); + + case AML_BIT_XOR_OP: /* XOr (Integer0, Integer1, Result) */ + + return (Integer0 ^ Integer1); + + case AML_MULTIPLY_OP: /* Multiply (Integer0, Integer1, Result) */ + + return (Integer0 * Integer1); + + case AML_SHIFT_LEFT_OP: /* ShiftLeft (Operand, ShiftCount, Result)*/ + + /* + * We need to check if the shiftcount is larger than the integer bit + * width since the behavior of this is not well-defined in the C language. + */ + if (Integer1 >= AcpiGbl_IntegerBitWidth) + { + return (0); + } + return (Integer0 << Integer1); + + case AML_SHIFT_RIGHT_OP: /* ShiftRight (Operand, ShiftCount, Result) */ + + /* + * We need to check if the shiftcount is larger than the integer bit + * width since the behavior of this is not well-defined in the C language. + */ + if (Integer1 >= AcpiGbl_IntegerBitWidth) + { + return (0); + } + return (Integer0 >> Integer1); + + case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */ + + return (Integer0 - Integer1); + + default: + + return (0); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDoLogicalNumericOp + * + * PARAMETERS: Opcode - AML opcode + * Integer0 - Integer operand #0 + * Integer1 - Integer operand #1 + * LogicalResult - TRUE/FALSE result of the operation + * + * RETURN: Status + * + * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric + * operators (LAnd and LOr), both operands must be integers. + * + * Note: cleanest machine code seems to be produced by the code + * below, rather than using statements of the form: + * Result = (Integer0 && Integer1); + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExDoLogicalNumericOp ( + UINT16 Opcode, + UINT64 Integer0, + UINT64 Integer1, + BOOLEAN *LogicalResult) +{ + ACPI_STATUS Status = AE_OK; + BOOLEAN LocalResult = FALSE; + + + ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp); + + + switch (Opcode) + { + case AML_LAND_OP: /* LAnd (Integer0, Integer1) */ + + if (Integer0 && Integer1) + { + LocalResult = TRUE; + } + break; + + case AML_LOR_OP: /* LOr (Integer0, Integer1) */ + + if (Integer0 || Integer1) + { + LocalResult = TRUE; + } + break; + + default: + + Status = AE_AML_INTERNAL; + break; + } + + /* Return the logical result and status */ + + *LogicalResult = LocalResult; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDoLogicalOp + * + * PARAMETERS: Opcode - AML opcode + * Operand0 - operand #0 + * Operand1 - operand #1 + * LogicalResult - TRUE/FALSE result of the operation + * + * RETURN: Status + * + * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the + * functions here is to prevent a lot of pointer dereferencing + * to obtain the operands and to simplify the generation of the + * logical value. For the Numeric operators (LAnd and LOr), both + * operands must be integers. For the other logical operators, + * operands can be any combination of Integer/String/Buffer. The + * first operand determines the type to which the second operand + * will be converted. + * + * Note: cleanest machine code seems to be produced by the code + * below, rather than using statements of the form: + * Result = (Operand0 == Operand1); + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExDoLogicalOp ( + UINT16 Opcode, + ACPI_OPERAND_OBJECT *Operand0, + ACPI_OPERAND_OBJECT *Operand1, + BOOLEAN *LogicalResult) +{ + ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; + UINT64 Integer0; + UINT64 Integer1; + UINT32 Length0; + UINT32 Length1; + ACPI_STATUS Status = AE_OK; + BOOLEAN LocalResult = FALSE; + int Compare; + + + ACPI_FUNCTION_TRACE (ExDoLogicalOp); + + + /* + * Convert the second operand if necessary. The first operand + * determines the type of the second operand, (See the Data Types + * section of the ACPI 3.0+ specification.) Both object types are + * guaranteed to be either Integer/String/Buffer by the operand + * resolution mechanism. + */ + switch (Operand0->Common.Type) + { + case ACPI_TYPE_INTEGER: + + Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16); + break; + + case ACPI_TYPE_STRING: + + Status = AcpiExConvertToString ( + Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX); + break; + + case ACPI_TYPE_BUFFER: + + Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1); + break; + + default: + + Status = AE_AML_INTERNAL; + break; + } + + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * Two cases: 1) Both Integers, 2) Both Strings or Buffers + */ + if (Operand0->Common.Type == ACPI_TYPE_INTEGER) + { + /* + * 1) Both operands are of type integer + * Note: LocalOperand1 may have changed above + */ + Integer0 = Operand0->Integer.Value; + Integer1 = LocalOperand1->Integer.Value; + + switch (Opcode) + { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + + if (Integer0 == Integer1) + { + LocalResult = TRUE; + } + break; + + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + if (Integer0 > Integer1) + { + LocalResult = TRUE; + } + break; + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + if (Integer0 < Integer1) + { + LocalResult = TRUE; + } + break; + + default: + + Status = AE_AML_INTERNAL; + break; + } + } + else + { + /* + * 2) Both operands are Strings or both are Buffers + * Note: Code below takes advantage of common Buffer/String + * object fields. LocalOperand1 may have changed above. Use + * memcmp to handle nulls in buffers. + */ + Length0 = Operand0->Buffer.Length; + Length1 = LocalOperand1->Buffer.Length; + + /* Lexicographic compare: compare the data bytes */ + + Compare = memcmp (Operand0->Buffer.Pointer, + LocalOperand1->Buffer.Pointer, + (Length0 > Length1) ? Length1 : Length0); + + switch (Opcode) + { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + + /* Length and all bytes must be equal */ + + if ((Length0 == Length1) && + (Compare == 0)) + { + /* Length and all bytes match ==> TRUE */ + + LocalResult = TRUE; + } + break; + + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + if (Compare > 0) + { + LocalResult = TRUE; + goto Cleanup; /* TRUE */ + } + if (Compare < 0) + { + goto Cleanup; /* FALSE */ + } + + /* Bytes match (to shortest length), compare lengths */ + + if (Length0 > Length1) + { + LocalResult = TRUE; + } + break; + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + if (Compare > 0) + { + goto Cleanup; /* FALSE */ + } + if (Compare < 0) + { + LocalResult = TRUE; + goto Cleanup; /* TRUE */ + } + + /* Bytes match (to shortest length), compare lengths */ + + if (Length0 < Length1) + { + LocalResult = TRUE; + } + break; + + default: + + Status = AE_AML_INTERNAL; + break; + } + } + +Cleanup: + + /* New object was created if implicit conversion performed - delete */ + + if (LocalOperand1 != Operand1) + { + AcpiUtRemoveReference (LocalOperand1); + } + + /* Return the logical result and status */ + + *LogicalResult = LocalResult; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exmutex.c b/third_party/lib/acpica/source/components/executer/exmutex.c new file mode 100644 index 000000000..30e10af38 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exmutex.c @@ -0,0 +1,585 @@ +/****************************************************************************** + * + * Module Name: exmutex - ASL Mutex Acquire/Release functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "acevents.h" + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exmutex") + +/* Local prototypes */ + +static void +AcpiExLinkMutex ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_THREAD_STATE *Thread); + + +/******************************************************************************* + * + * FUNCTION: AcpiExUnlinkMutex + * + * PARAMETERS: ObjDesc - The mutex to be unlinked + * + * RETURN: None + * + * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list + * + ******************************************************************************/ + +void +AcpiExUnlinkMutex ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_THREAD_STATE *Thread = ObjDesc->Mutex.OwnerThread; + + + if (!Thread) + { + return; + } + + /* Doubly linked list */ + + if (ObjDesc->Mutex.Next) + { + (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev; + } + + if (ObjDesc->Mutex.Prev) + { + (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next; + + /* + * Migrate the previous sync level associated with this mutex to + * the previous mutex on the list so that it may be preserved. + * This handles the case where several mutexes have been acquired + * at the same level, but are not released in opposite order. + */ + (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel = + ObjDesc->Mutex.OriginalSyncLevel; + } + else + { + Thread->AcquiredMutexList = ObjDesc->Mutex.Next; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExLinkMutex + * + * PARAMETERS: ObjDesc - The mutex to be linked + * Thread - Current executing thread object + * + * RETURN: None + * + * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk + * + ******************************************************************************/ + +static void +AcpiExLinkMutex ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_THREAD_STATE *Thread) +{ + ACPI_OPERAND_OBJECT *ListHead; + + + ListHead = Thread->AcquiredMutexList; + + /* This object will be the first object in the list */ + + ObjDesc->Mutex.Prev = NULL; + ObjDesc->Mutex.Next = ListHead; + + /* Update old first object to point back to this object */ + + if (ListHead) + { + ListHead->Mutex.Prev = ObjDesc; + } + + /* Update list head */ + + Thread->AcquiredMutexList = ObjDesc; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExAcquireMutexObject + * + * PARAMETERS: Timeout - Timeout in milliseconds + * ObjDesc - Mutex object + * ThreadId - Current thread state + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common + * path that supports multiple acquires by the same thread. + * + * MUTEX: Interpreter must be locked + * + * NOTE: This interface is called from three places: + * 1) From AcpiExAcquireMutex, via an AML Acquire() operator + * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the + * global lock + * 3) From the external interface, AcpiAcquireGlobalLock + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExAcquireMutexObject ( + UINT16 Timeout, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_THREAD_ID ThreadId) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc); + + + if (!ObjDesc) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Support for multiple acquires by the owning thread */ + + if (ObjDesc->Mutex.ThreadId == ThreadId) + { + /* + * The mutex is already owned by this thread, just increment the + * acquisition depth + */ + ObjDesc->Mutex.AcquisitionDepth++; + return_ACPI_STATUS (AE_OK); + } + + /* Acquire the mutex, wait if necessary. Special case for Global Lock */ + + if (ObjDesc == AcpiGbl_GlobalLockMutex) + { + Status = AcpiEvAcquireGlobalLock (Timeout); + } + else + { + Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, Timeout); + } + + if (ACPI_FAILURE (Status)) + { + /* Includes failure from a timeout on TimeDesc */ + + return_ACPI_STATUS (Status); + } + + /* Acquired the mutex: update mutex object */ + + ObjDesc->Mutex.ThreadId = ThreadId; + ObjDesc->Mutex.AcquisitionDepth = 1; + ObjDesc->Mutex.OriginalSyncLevel = 0; + ObjDesc->Mutex.OwnerThread = NULL; /* Used only for AML Acquire() */ + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExAcquireMutex + * + * PARAMETERS: TimeDesc - Timeout integer + * ObjDesc - Mutex object + * WalkState - Current method execution state + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExAcquireMutex ( + ACPI_OPERAND_OBJECT *TimeDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc); + + + if (!ObjDesc) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Must have a valid thread state struct */ + + if (!WalkState->Thread) + { + ACPI_ERROR ((AE_INFO, + "Cannot acquire Mutex [%4.4s], null thread info", + AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * Current sync level must be less than or equal to the sync level + * of the mutex. This mechanism provides some deadlock prevention. + */ + if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel) + { + ACPI_ERROR ((AE_INFO, + "Cannot acquire Mutex [%4.4s], " + "current SyncLevel is too large (%u)", + AcpiUtGetNodeName (ObjDesc->Mutex.Node), + WalkState->Thread->CurrentSyncLevel)); + return_ACPI_STATUS (AE_AML_MUTEX_ORDER); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, " + "Depth %u TID %p\n", + ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, + ObjDesc->Mutex.AcquisitionDepth, WalkState->Thread)); + + Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value, + ObjDesc, WalkState->Thread->ThreadId); + + if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1) + { + /* Save Thread object, original/current sync levels */ + + ObjDesc->Mutex.OwnerThread = WalkState->Thread; + ObjDesc->Mutex.OriginalSyncLevel = + WalkState->Thread->CurrentSyncLevel; + WalkState->Thread->CurrentSyncLevel = + ObjDesc->Mutex.SyncLevel; + + /* Link the mutex to the current thread for force-unlock at method exit */ + + AcpiExLinkMutex (ObjDesc, WalkState->Thread); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n", + ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, + ObjDesc->Mutex.AcquisitionDepth)); + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExReleaseMutexObject + * + * PARAMETERS: ObjDesc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Release a previously acquired Mutex, low level interface. + * Provides a common path that supports multiple releases (after + * previous multiple acquires) by the same thread. + * + * MUTEX: Interpreter must be locked + * + * NOTE: This interface is called from three places: + * 1) From AcpiExReleaseMutex, via an AML Acquire() operator + * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the + * global lock + * 3) From the external interface, AcpiReleaseGlobalLock + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExReleaseMutexObject ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExReleaseMutexObject); + + + if (ObjDesc->Mutex.AcquisitionDepth == 0) + { + return_ACPI_STATUS (AE_NOT_ACQUIRED); + } + + /* Match multiple Acquires with multiple Releases */ + + ObjDesc->Mutex.AcquisitionDepth--; + if (ObjDesc->Mutex.AcquisitionDepth != 0) + { + /* Just decrement the depth and return */ + + return_ACPI_STATUS (AE_OK); + } + + if (ObjDesc->Mutex.OwnerThread) + { + /* Unlink the mutex from the owner's list */ + + AcpiExUnlinkMutex (ObjDesc); + ObjDesc->Mutex.OwnerThread = NULL; + } + + /* Release the mutex, special case for Global Lock */ + + if (ObjDesc == AcpiGbl_GlobalLockMutex) + { + Status = AcpiEvReleaseGlobalLock (); + } + else + { + AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); + } + + /* Clear mutex info */ + + ObjDesc->Mutex.ThreadId = 0; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExReleaseMutex + * + * PARAMETERS: ObjDesc - The object descriptor for this op + * WalkState - Current method execution state + * + * RETURN: Status + * + * DESCRIPTION: Release a previously acquired Mutex. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExReleaseMutex ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + UINT8 PreviousSyncLevel; + ACPI_THREAD_STATE *OwnerThread; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExReleaseMutex); + + + if (!ObjDesc) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + OwnerThread = ObjDesc->Mutex.OwnerThread; + + /* The mutex must have been previously acquired in order to release it */ + + if (!OwnerThread) + { + ACPI_ERROR ((AE_INFO, + "Cannot release Mutex [%4.4s], not acquired", + AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); + } + + /* Must have a valid thread ID */ + + if (!WalkState->Thread) + { + ACPI_ERROR ((AE_INFO, + "Cannot release Mutex [%4.4s], null thread info", + AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * The Mutex is owned, but this thread must be the owner. + * Special case for Global Lock, any thread can release + */ + if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) && + (ObjDesc != AcpiGbl_GlobalLockMutex)) + { + ACPI_ERROR ((AE_INFO, + "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", + (UINT32) WalkState->Thread->ThreadId, + AcpiUtGetNodeName (ObjDesc->Mutex.Node), + (UINT32) OwnerThread->ThreadId)); + return_ACPI_STATUS (AE_AML_NOT_OWNER); + } + + /* + * The sync level of the mutex must be equal to the current sync level. In + * other words, the current level means that at least one mutex at that + * level is currently being held. Attempting to release a mutex of a + * different level can only mean that the mutex ordering rule is being + * violated. This behavior is clarified in ACPI 4.0 specification. + */ + if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel) + { + ACPI_ERROR ((AE_INFO, + "Cannot release Mutex [%4.4s], SyncLevel mismatch: " + "mutex %u current %u", + AcpiUtGetNodeName (ObjDesc->Mutex.Node), + ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel)); + return_ACPI_STATUS (AE_AML_MUTEX_ORDER); + } + + /* + * Get the previous SyncLevel from the head of the acquired mutex list. + * This handles the case where several mutexes at the same level have been + * acquired, but are not released in reverse order. + */ + PreviousSyncLevel = + OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Releasing: Object SyncLevel %u, Thread SyncLevel %u, " + "Prev SyncLevel %u, Depth %u TID %p\n", + ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, + PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth, + WalkState->Thread)); + + Status = AcpiExReleaseMutexObject (ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (ObjDesc->Mutex.AcquisitionDepth == 0) + { + /* Restore the previous SyncLevel */ + + OwnerThread->CurrentSyncLevel = PreviousSyncLevel; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Released: Object SyncLevel %u, Thread SyncLevel, %u, " + "Prev SyncLevel %u, Depth %u\n", + ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, + PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth)); + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExReleaseAllMutexes + * + * PARAMETERS: Thread - Current executing thread object + * + * RETURN: Status + * + * DESCRIPTION: Release all mutexes held by this thread + * + * NOTE: This function is called as the thread is exiting the interpreter. + * Mutexes are not released when an individual control method is exited, but + * only when the parent thread actually exits the interpreter. This allows one + * method to acquire a mutex, and a different method to release it, as long as + * this is performed underneath a single parent control method. + * + ******************************************************************************/ + +void +AcpiExReleaseAllMutexes ( + ACPI_THREAD_STATE *Thread) +{ + ACPI_OPERAND_OBJECT *Next = Thread->AcquiredMutexList; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_TRACE (ExReleaseAllMutexes); + + + /* Traverse the list of owned mutexes, releasing each one */ + + while (Next) + { + ObjDesc = Next; + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n", + ObjDesc->Mutex.Node->Name.Ascii, ObjDesc->Mutex.SyncLevel, + ObjDesc->Mutex.AcquisitionDepth)); + + /* Release the mutex, special case for Global Lock */ + + if (ObjDesc == AcpiGbl_GlobalLockMutex) + { + /* Ignore errors */ + + (void) AcpiEvReleaseGlobalLock (); + } + else + { + AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); + } + + /* Update Thread SyncLevel (Last mutex is the important one) */ + + Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel; + + /* Mark mutex unowned */ + + Next = ObjDesc->Mutex.Next; + + ObjDesc->Mutex.Prev = NULL; + ObjDesc->Mutex.Next = NULL; + ObjDesc->Mutex.AcquisitionDepth = 0; + ObjDesc->Mutex.OwnerThread = NULL; + ObjDesc->Mutex.ThreadId = 0; + } + + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/executer/exnames.c b/third_party/lib/acpica/source/components/executer/exnames.c new file mode 100644 index 000000000..4ed16649b --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exnames.c @@ -0,0 +1,480 @@ +/****************************************************************************** + * + * Module Name: exnames - interpreter/scanner name load/execute + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exnames") + +/* Local prototypes */ + +static char * +AcpiExAllocateNameString ( + UINT32 PrefixCount, + UINT32 NumNameSegs); + +static ACPI_STATUS +AcpiExNameSegment ( + UINT8 **InAmlAddress, + char *NameString); + + +/******************************************************************************* + * + * FUNCTION: AcpiExAllocateNameString + * + * PARAMETERS: PrefixCount - Count of parent levels. Special cases: + * (-1)==root, 0==none + * NumNameSegs - count of 4-character name segments + * + * RETURN: A pointer to the allocated string segment. This segment must + * be deleted by the caller. + * + * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name + * string is long enough, and set up prefix if any. + * + ******************************************************************************/ + +static char * +AcpiExAllocateNameString ( + UINT32 PrefixCount, + UINT32 NumNameSegs) +{ + char *TempPtr; + char *NameString; + UINT32 SizeNeeded; + + ACPI_FUNCTION_TRACE (ExAllocateNameString); + + + /* + * Allow room for all \ and ^ prefixes, all segments and a MultiNamePrefix. + * Also, one byte for the null terminator. + * This may actually be somewhat longer than needed. + */ + if (PrefixCount == ACPI_UINT32_MAX) + { + /* Special case for root */ + + SizeNeeded = 1 + (ACPI_NAME_SIZE * NumNameSegs) + 2 + 1; + } + else + { + SizeNeeded = PrefixCount + (ACPI_NAME_SIZE * NumNameSegs) + 2 + 1; + } + + /* + * Allocate a buffer for the name. + * This buffer must be deleted by the caller! + */ + NameString = ACPI_ALLOCATE (SizeNeeded); + if (!NameString) + { + ACPI_ERROR ((AE_INFO, + "Could not allocate size %u", SizeNeeded)); + return_PTR (NULL); + } + + TempPtr = NameString; + + /* Set up Root or Parent prefixes if needed */ + + if (PrefixCount == ACPI_UINT32_MAX) + { + *TempPtr++ = AML_ROOT_PREFIX; + } + else + { + while (PrefixCount--) + { + *TempPtr++ = AML_PARENT_PREFIX; + } + } + + + /* Set up Dual or Multi prefixes if needed */ + + if (NumNameSegs > 2) + { + /* Set up multi prefixes */ + + *TempPtr++ = AML_MULTI_NAME_PREFIX_OP; + *TempPtr++ = (char) NumNameSegs; + } + else if (2 == NumNameSegs) + { + /* Set up dual prefixes */ + + *TempPtr++ = AML_DUAL_NAME_PREFIX; + } + + /* + * Terminate string following prefixes. AcpiExNameSegment() will + * append the segment(s) + */ + *TempPtr = 0; + + return_PTR (NameString); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExNameSegment + * + * PARAMETERS: InAmlAddress - Pointer to the name in the AML code + * NameString - Where to return the name. The name is appended + * to any existing string to form a namepath + * + * RETURN: Status + * + * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExNameSegment ( + UINT8 **InAmlAddress, + char *NameString) +{ + char *AmlAddress = (void *) *InAmlAddress; + ACPI_STATUS Status = AE_OK; + UINT32 Index; + char CharBuf[5]; + + + ACPI_FUNCTION_TRACE (ExNameSegment); + + + /* + * If first character is a digit, then we know that we aren't looking + * at a valid name segment + */ + CharBuf[0] = *AmlAddress; + + if ('0' <= CharBuf[0] && CharBuf[0] <= '9') + { + ACPI_ERROR ((AE_INFO, "Invalid leading digit: %c", CharBuf[0])); + return_ACPI_STATUS (AE_CTRL_PENDING); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Bytes from stream:\n")); + + for (Index = 0; + (Index < ACPI_NAME_SIZE) && (AcpiUtValidAcpiChar (*AmlAddress, 0)); + Index++) + { + CharBuf[Index] = *AmlAddress++; + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "%c\n", CharBuf[Index])); + } + + + /* Valid name segment */ + + if (Index == 4) + { + /* Found 4 valid characters */ + + CharBuf[4] = '\0'; + + if (NameString) + { + strcat (NameString, CharBuf); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Appended to - %s\n", NameString)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "No Name string - %s\n", CharBuf)); + } + } + else if (Index == 0) + { + /* + * First character was not a valid name character, + * so we are looking at something other than a name. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Leading character is not alpha: %02Xh (not a name)\n", + CharBuf[0])); + Status = AE_CTRL_PENDING; + } + else + { + /* + * Segment started with one or more valid characters, but fewer than + * the required 4 + */ + Status = AE_AML_BAD_NAME; + ACPI_ERROR ((AE_INFO, + "Bad character 0x%02x in name, at %p", + *AmlAddress, AmlAddress)); + } + + *InAmlAddress = ACPI_CAST_PTR (UINT8, AmlAddress); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExGetNameString + * + * PARAMETERS: DataType - Object type to be associated with this + * name + * InAmlAddress - Pointer to the namestring in the AML code + * OutNameString - Where the namestring is returned + * OutNameLength - Length of the returned string + * + * RETURN: Status, namestring and length + * + * DESCRIPTION: Extract a full namepath from the AML byte stream, + * including any prefixes. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExGetNameString ( + ACPI_OBJECT_TYPE DataType, + UINT8 *InAmlAddress, + char **OutNameString, + UINT32 *OutNameLength) +{ + ACPI_STATUS Status = AE_OK; + UINT8 *AmlAddress = InAmlAddress; + char *NameString = NULL; + UINT32 NumSegments; + UINT32 PrefixCount = 0; + BOOLEAN HasPrefix = FALSE; + + + ACPI_FUNCTION_TRACE_PTR (ExGetNameString, AmlAddress); + + + if (ACPI_TYPE_LOCAL_REGION_FIELD == DataType || + ACPI_TYPE_LOCAL_BANK_FIELD == DataType || + ACPI_TYPE_LOCAL_INDEX_FIELD == DataType) + { + /* Disallow prefixes for types associated with FieldUnit names */ + + NameString = AcpiExAllocateNameString (0, 1); + if (!NameString) + { + Status = AE_NO_MEMORY; + } + else + { + Status = AcpiExNameSegment (&AmlAddress, NameString); + } + } + else + { + /* + * DataType is not a field name. + * Examine first character of name for root or parent prefix operators + */ + switch (*AmlAddress) + { + case AML_ROOT_PREFIX: + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "RootPrefix(\\) at %p\n", + AmlAddress)); + + /* + * Remember that we have a RootPrefix -- + * see comment in AcpiExAllocateNameString() + */ + AmlAddress++; + PrefixCount = ACPI_UINT32_MAX; + HasPrefix = TRUE; + break; + + case AML_PARENT_PREFIX: + + /* Increment past possibly multiple parent prefixes */ + + do + { + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "ParentPrefix (^) at %p\n", + AmlAddress)); + + AmlAddress++; + PrefixCount++; + + } while (*AmlAddress == AML_PARENT_PREFIX); + + HasPrefix = TRUE; + break; + + default: + + /* Not a prefix character */ + + break; + } + + /* Examine first character of name for name segment prefix operator */ + + switch (*AmlAddress) + { + case AML_DUAL_NAME_PREFIX: + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "DualNamePrefix at %p\n", + AmlAddress)); + + AmlAddress++; + NameString = AcpiExAllocateNameString (PrefixCount, 2); + if (!NameString) + { + Status = AE_NO_MEMORY; + break; + } + + /* Indicate that we processed a prefix */ + + HasPrefix = TRUE; + + Status = AcpiExNameSegment (&AmlAddress, NameString); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiExNameSegment (&AmlAddress, NameString); + } + break; + + case AML_MULTI_NAME_PREFIX_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "MultiNamePrefix at %p\n", + AmlAddress)); + + /* Fetch count of segments remaining in name path */ + + AmlAddress++; + NumSegments = *AmlAddress; + + NameString = AcpiExAllocateNameString ( + PrefixCount, NumSegments); + if (!NameString) + { + Status = AE_NO_MEMORY; + break; + } + + /* Indicate that we processed a prefix */ + + AmlAddress++; + HasPrefix = TRUE; + + while (NumSegments && + (Status = AcpiExNameSegment (&AmlAddress, NameString)) == + AE_OK) + { + NumSegments--; + } + + break; + + case 0: + + /* NullName valid as of 8-12-98 ASL/AML Grammar Update */ + + if (PrefixCount == ACPI_UINT32_MAX) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "NameSeg is \"\\\" followed by NULL\n")); + } + + /* Consume the NULL byte */ + + AmlAddress++; + NameString = AcpiExAllocateNameString (PrefixCount, 0); + if (!NameString) + { + Status = AE_NO_MEMORY; + break; + } + + break; + + default: + + /* Name segment string */ + + NameString = AcpiExAllocateNameString (PrefixCount, 1); + if (!NameString) + { + Status = AE_NO_MEMORY; + break; + } + + Status = AcpiExNameSegment (&AmlAddress, NameString); + break; + } + } + + if (AE_CTRL_PENDING == Status && HasPrefix) + { + /* Ran out of segments after processing a prefix */ + + ACPI_ERROR ((AE_INFO, + "Malformed Name at %p", NameString)); + Status = AE_AML_BAD_NAME; + } + + if (ACPI_FAILURE (Status)) + { + if (NameString) + { + ACPI_FREE (NameString); + } + return_ACPI_STATUS (Status); + } + + *OutNameString = NameString; + *OutNameLength = (UINT32) (AmlAddress - InAmlAddress); + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exoparg1.c b/third_party/lib/acpica/source/components/executer/exoparg1.c new file mode 100644 index 000000000..5a45bead0 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exoparg1.c @@ -0,0 +1,1125 @@ +/****************************************************************************** + * + * Module Name: exoparg1 - AML execution - opcodes with 1 argument + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg1") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (0 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_0A_0T_1R + * + * PARAMETERS: WalkState - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute operator with no operands, one return value + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_0A_0T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_0A_0T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Examine the AML opcode */ + + switch (WalkState->Opcode) + { + case AML_TIMER_OP: /* Timer () */ + + /* Create a return object of type Integer */ + + ReturnDesc = AcpiUtCreateIntegerObject (AcpiOsGetTimer ()); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + break; + + default: /* Unknown opcode */ + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + Status = AE_AML_BAD_OPCODE; + break; + } + +Cleanup: + + /* Delete return object on error */ + + if ((ACPI_FAILURE (Status)) || WalkState->ResultObj) + { + AcpiUtRemoveReference (ReturnDesc); + WalkState->ResultObj = NULL; + } + else + { + /* Save the return value */ + + WalkState->ResultObj = ReturnDesc; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_1A_0T_0R + * + * PARAMETERS: WalkState - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on + * object stack + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_1A_0T_0R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_0T_0R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Examine the AML opcode */ + + switch (WalkState->Opcode) + { + case AML_RELEASE_OP: /* Release (MutexObject) */ + + Status = AcpiExReleaseMutex (Operand[0], WalkState); + break; + + case AML_RESET_OP: /* Reset (EventObject) */ + + Status = AcpiExSystemResetEvent (Operand[0]); + break; + + case AML_SIGNAL_OP: /* Signal (EventObject) */ + + Status = AcpiExSystemSignalEvent (Operand[0]); + break; + + case AML_SLEEP_OP: /* Sleep (MsecTime) */ + + Status = AcpiExSystemDoSleep (Operand[0]->Integer.Value); + break; + + case AML_STALL_OP: /* Stall (UsecTime) */ + + Status = AcpiExSystemDoStall ((UINT32) Operand[0]->Integer.Value); + break; + + case AML_UNLOAD_OP: /* Unload (Handle) */ + + Status = AcpiExUnloadTable (Operand[0]); + break; + + default: /* Unknown opcode */ + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + Status = AE_AML_BAD_OPCODE; + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_1A_1T_0R + * + * PARAMETERS: WalkState - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with one argument, one target, and no + * return value. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_1A_1T_0R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_1T_0R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Examine the AML opcode */ + + switch (WalkState->Opcode) + { + case AML_LOAD_OP: + + Status = AcpiExLoadOp (Operand[0], Operand[1], WalkState); + break; + + default: /* Unknown opcode */ + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + +Cleanup: + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_1A_1T_1R + * + * PARAMETERS: WalkState - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with one argument, one target, and a + * return value. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_1A_1T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + ACPI_OPERAND_OBJECT *ReturnDesc2 = NULL; + UINT32 Temp32; + UINT32 i; + UINT64 PowerOfTen; + UINT64 Digit; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_1T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Examine the AML opcode */ + + switch (WalkState->Opcode) + { + case AML_BIT_NOT_OP: + case AML_FIND_SET_LEFT_BIT_OP: + case AML_FIND_SET_RIGHT_BIT_OP: + case AML_FROM_BCD_OP: + case AML_TO_BCD_OP: + case AML_COND_REF_OF_OP: + + /* Create a return object of type Integer for these opcodes */ + + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + switch (WalkState->Opcode) + { + case AML_BIT_NOT_OP: /* Not (Operand, Result) */ + + ReturnDesc->Integer.Value = ~Operand[0]->Integer.Value; + break; + + case AML_FIND_SET_LEFT_BIT_OP: /* FindSetLeftBit (Operand, Result) */ + + ReturnDesc->Integer.Value = Operand[0]->Integer.Value; + + /* + * Acpi specification describes Integer type as a little + * endian unsigned value, so this boundary condition is valid. + */ + for (Temp32 = 0; ReturnDesc->Integer.Value && + Temp32 < ACPI_INTEGER_BIT_SIZE; ++Temp32) + { + ReturnDesc->Integer.Value >>= 1; + } + + ReturnDesc->Integer.Value = Temp32; + break; + + case AML_FIND_SET_RIGHT_BIT_OP: /* FindSetRightBit (Operand, Result) */ + + ReturnDesc->Integer.Value = Operand[0]->Integer.Value; + + /* + * The Acpi specification describes Integer type as a little + * endian unsigned value, so this boundary condition is valid. + */ + for (Temp32 = 0; ReturnDesc->Integer.Value && + Temp32 < ACPI_INTEGER_BIT_SIZE; ++Temp32) + { + ReturnDesc->Integer.Value <<= 1; + } + + /* Since the bit position is one-based, subtract from 33 (65) */ + + ReturnDesc->Integer.Value = + Temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - Temp32; + break; + + case AML_FROM_BCD_OP: /* FromBcd (BCDValue, Result) */ + /* + * The 64-bit ACPI integer can hold 16 4-bit BCD characters + * (if table is 32-bit, integer can hold 8 BCD characters) + * Convert each 4-bit BCD value + */ + PowerOfTen = 1; + ReturnDesc->Integer.Value = 0; + Digit = Operand[0]->Integer.Value; + + /* Convert each BCD digit (each is one nybble wide) */ + + for (i = 0; (i < AcpiGbl_IntegerNybbleWidth) && (Digit > 0); i++) + { + /* Get the least significant 4-bit BCD digit */ + + Temp32 = ((UINT32) Digit) & 0xF; + + /* Check the range of the digit */ + + if (Temp32 > 9) + { + ACPI_ERROR ((AE_INFO, + "BCD digit too large (not decimal): 0x%X", + Temp32)); + + Status = AE_AML_NUMERIC_OVERFLOW; + goto Cleanup; + } + + /* Sum the digit into the result with the current power of 10 */ + + ReturnDesc->Integer.Value += + (((UINT64) Temp32) * PowerOfTen); + + /* Shift to next BCD digit */ + + Digit >>= 4; + + /* Next power of 10 */ + + PowerOfTen *= 10; + } + break; + + case AML_TO_BCD_OP: /* ToBcd (Operand, Result) */ + + ReturnDesc->Integer.Value = 0; + Digit = Operand[0]->Integer.Value; + + /* Each BCD digit is one nybble wide */ + + for (i = 0; (i < AcpiGbl_IntegerNybbleWidth) && (Digit > 0); i++) + { + (void) AcpiUtShortDivide (Digit, 10, &Digit, &Temp32); + + /* + * Insert the BCD digit that resides in the + * remainder from above + */ + ReturnDesc->Integer.Value |= + (((UINT64) Temp32) << ACPI_MUL_4 (i)); + } + + /* Overflow if there is any data left in Digit */ + + if (Digit > 0) + { + ACPI_ERROR ((AE_INFO, + "Integer too large to convert to BCD: 0x%8.8X%8.8X", + ACPI_FORMAT_UINT64 (Operand[0]->Integer.Value))); + Status = AE_AML_NUMERIC_OVERFLOW; + goto Cleanup; + } + break; + + case AML_COND_REF_OF_OP: /* CondRefOf (SourceObject, Result) */ + /* + * This op is a little strange because the internal return value is + * different than the return value stored in the result descriptor + * (There are really two return values) + */ + if ((ACPI_NAMESPACE_NODE *) Operand[0] == AcpiGbl_RootNode) + { + /* + * This means that the object does not exist in the namespace, + * return FALSE + */ + ReturnDesc->Integer.Value = 0; + goto Cleanup; + } + + /* Get the object reference, store it, and remove our reference */ + + Status = AcpiExGetObjectReference (Operand[0], + &ReturnDesc2, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + Status = AcpiExStore (ReturnDesc2, Operand[1], WalkState); + AcpiUtRemoveReference (ReturnDesc2); + + /* The object exists in the namespace, return TRUE */ + + ReturnDesc->Integer.Value = ACPI_UINT64_MAX; + goto Cleanup; + + + default: + + /* No other opcodes get here */ + + break; + } + break; + + case AML_STORE_OP: /* Store (Source, Target) */ + /* + * A store operand is typically a number, string, buffer or lvalue + * Be careful about deleting the source object, + * since the object itself may have been stored. + */ + Status = AcpiExStore (Operand[0], Operand[1], WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* It is possible that the Store already produced a return object */ + + if (!WalkState->ResultObj) + { + /* + * Normally, we would remove a reference on the Operand[0] + * parameter; But since it is being used as the internal return + * object (meaning we would normally increment it), the two + * cancel out, and we simply don't do anything. + */ + WalkState->ResultObj = Operand[0]; + WalkState->Operands[0] = NULL; /* Prevent deletion */ + } + return_ACPI_STATUS (Status); + + /* + * ACPI 2.0 Opcodes + */ + case AML_COPY_OP: /* Copy (Source, Target) */ + + Status = AcpiUtCopyIobjectToIobject ( + Operand[0], &ReturnDesc, WalkState); + break; + + case AML_TO_DECSTRING_OP: /* ToDecimalString (Data, Result) */ + + Status = AcpiExConvertToString ( + Operand[0], &ReturnDesc, ACPI_EXPLICIT_CONVERT_DECIMAL); + if (ReturnDesc == Operand[0]) + { + /* No conversion performed, add ref to handle return value */ + + AcpiUtAddReference (ReturnDesc); + } + break; + + case AML_TO_HEXSTRING_OP: /* ToHexString (Data, Result) */ + + Status = AcpiExConvertToString ( + Operand[0], &ReturnDesc, ACPI_EXPLICIT_CONVERT_HEX); + if (ReturnDesc == Operand[0]) + { + /* No conversion performed, add ref to handle return value */ + + AcpiUtAddReference (ReturnDesc); + } + break; + + case AML_TO_BUFFER_OP: /* ToBuffer (Data, Result) */ + + Status = AcpiExConvertToBuffer (Operand[0], &ReturnDesc); + if (ReturnDesc == Operand[0]) + { + /* No conversion performed, add ref to handle return value */ + + AcpiUtAddReference (ReturnDesc); + } + break; + + case AML_TO_INTEGER_OP: /* ToInteger (Data, Result) */ + + Status = AcpiExConvertToInteger ( + Operand[0], &ReturnDesc, ACPI_ANY_BASE); + if (ReturnDesc == Operand[0]) + { + /* No conversion performed, add ref to handle return value */ + + AcpiUtAddReference (ReturnDesc); + } + break; + + case AML_SHIFT_LEFT_BIT_OP: /* ShiftLeftBit (Source, BitNum) */ + case AML_SHIFT_RIGHT_BIT_OP: /* ShiftRightBit (Source, BitNum) */ + + /* These are two obsolete opcodes */ + + ACPI_ERROR ((AE_INFO, + "%s is obsolete and not implemented", + AcpiPsGetOpcodeName (WalkState->Opcode))); + Status = AE_SUPPORT; + goto Cleanup; + + default: /* Unknown opcode */ + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + if (ACPI_SUCCESS (Status)) + { + /* Store the return value computed above into the target object */ + + Status = AcpiExStore (ReturnDesc, Operand[1], WalkState); + } + + +Cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + } + + /* Save return object on success */ + + else if (!WalkState->ResultObj) + { + WalkState->ResultObj = ReturnDesc; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_1A_0T_1R + * + * PARAMETERS: WalkState - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with one argument, no target, and a return value + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_1A_0T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *TempDesc; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + ACPI_STATUS Status = AE_OK; + UINT32 Type; + UINT64 Value; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_0T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Examine the AML opcode */ + + switch (WalkState->Opcode) + { + case AML_LNOT_OP: /* LNot (Operand) */ + + ReturnDesc = AcpiUtCreateIntegerObject ((UINT64) 0); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * Set result to ONES (TRUE) if Value == 0. Note: + * ReturnDesc->Integer.Value is initially == 0 (FALSE) from above. + */ + if (!Operand[0]->Integer.Value) + { + ReturnDesc->Integer.Value = ACPI_UINT64_MAX; + } + break; + + case AML_DECREMENT_OP: /* Decrement (Operand) */ + case AML_INCREMENT_OP: /* Increment (Operand) */ + /* + * Create a new integer. Can't just get the base integer and + * increment it because it may be an Arg or Field. + */ + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * Since we are expecting a Reference operand, it can be either a + * NS Node or an internal object. + */ + TempDesc = Operand[0]; + if (ACPI_GET_DESCRIPTOR_TYPE (TempDesc) == ACPI_DESC_TYPE_OPERAND) + { + /* Internal reference object - prevent deletion */ + + AcpiUtAddReference (TempDesc); + } + + /* + * Convert the Reference operand to an Integer (This removes a + * reference on the Operand[0] object) + * + * NOTE: We use LNOT_OP here in order to force resolution of the + * reference operand to an actual integer. + */ + Status = AcpiExResolveOperands (AML_LNOT_OP, &TempDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While resolving operands for [%s]", + AcpiPsGetOpcodeName (WalkState->Opcode))); + + goto Cleanup; + } + + /* + * TempDesc is now guaranteed to be an Integer object -- + * Perform the actual increment or decrement + */ + if (WalkState->Opcode == AML_INCREMENT_OP) + { + ReturnDesc->Integer.Value = TempDesc->Integer.Value + 1; + } + else + { + ReturnDesc->Integer.Value = TempDesc->Integer.Value - 1; + } + + /* Finished with this Integer object */ + + AcpiUtRemoveReference (TempDesc); + + /* + * Store the result back (indirectly) through the original + * Reference object + */ + Status = AcpiExStore (ReturnDesc, Operand[0], WalkState); + break; + + case AML_OBJECT_TYPE_OP: /* ObjectType (SourceObject) */ + /* + * Note: The operand is not resolved at this point because we want to + * get the associated object, not its value. For example, we don't + * want to resolve a FieldUnit to its value, we want the actual + * FieldUnit object. + */ + + /* Get the type of the base object */ + + Status = AcpiExResolveMultiple (WalkState, Operand[0], &Type, NULL); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Allocate a descriptor to hold the type. */ + + ReturnDesc = AcpiUtCreateIntegerObject ((UINT64) Type); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + break; + + case AML_SIZE_OF_OP: /* SizeOf (SourceObject) */ + /* + * Note: The operand is not resolved at this point because we want to + * get the associated object, not its value. + */ + + /* Get the base object */ + + Status = AcpiExResolveMultiple ( + WalkState, Operand[0], &Type, &TempDesc); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * The type of the base object must be integer, buffer, string, or + * package. All others are not supported. + * + * NOTE: Integer is not specifically supported by the ACPI spec, + * but is supported implicitly via implicit operand conversion. + * rather than bother with conversion, we just use the byte width + * global (4 or 8 bytes). + */ + switch (Type) + { + case ACPI_TYPE_INTEGER: + + Value = AcpiGbl_IntegerByteWidth; + break; + + case ACPI_TYPE_STRING: + + Value = TempDesc->String.Length; + break; + + case ACPI_TYPE_BUFFER: + + /* Buffer arguments may not be evaluated at this point */ + + Status = AcpiDsGetBufferArguments (TempDesc); + Value = TempDesc->Buffer.Length; + break; + + case ACPI_TYPE_PACKAGE: + + /* Package arguments may not be evaluated at this point */ + + Status = AcpiDsGetPackageArguments (TempDesc); + Value = TempDesc->Package.Count; + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Operand must be Buffer/Integer/String/Package" + " - found type %s", + AcpiUtGetTypeName (Type))); + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * Now that we have the size of the object, create a result + * object to hold the value + */ + ReturnDesc = AcpiUtCreateIntegerObject (Value); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + break; + + + case AML_REF_OF_OP: /* RefOf (SourceObject) */ + + Status = AcpiExGetObjectReference ( + Operand[0], &ReturnDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + break; + + + case AML_DEREF_OF_OP: /* DerefOf (ObjReference | String) */ + + /* Check for a method local or argument, or standalone String */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Operand[0]) == ACPI_DESC_TYPE_NAMED) + { + TempDesc = AcpiNsGetAttachedObject ( + (ACPI_NAMESPACE_NODE *) Operand[0]); + if (TempDesc && + ((TempDesc->Common.Type == ACPI_TYPE_STRING) || + (TempDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE))) + { + Operand[0] = TempDesc; + AcpiUtAddReference (TempDesc); + } + else + { + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + } + else + { + switch ((Operand[0])->Common.Type) + { + case ACPI_TYPE_LOCAL_REFERENCE: + /* + * This is a DerefOf (LocalX | ArgX) + * + * Must resolve/dereference the local/arg reference first + */ + switch (Operand[0]->Reference.Class) + { + case ACPI_REFCLASS_LOCAL: + case ACPI_REFCLASS_ARG: + + /* Set Operand[0] to the value of the local/arg */ + + Status = AcpiDsMethodDataGetValue ( + Operand[0]->Reference.Class, + Operand[0]->Reference.Value, + WalkState, &TempDesc); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* + * Delete our reference to the input object and + * point to the object just retrieved + */ + AcpiUtRemoveReference (Operand[0]); + Operand[0] = TempDesc; + break; + + case ACPI_REFCLASS_REFOF: + + /* Get the object to which the reference refers */ + + TempDesc = Operand[0]->Reference.Object; + AcpiUtRemoveReference (Operand[0]); + Operand[0] = TempDesc; + break; + + default: + + /* Must be an Index op - handled below */ + break; + } + break; + + case ACPI_TYPE_STRING: + + break; + + default: + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + } + + if (ACPI_GET_DESCRIPTOR_TYPE (Operand[0]) != ACPI_DESC_TYPE_NAMED) + { + if ((Operand[0])->Common.Type == ACPI_TYPE_STRING) + { + /* + * This is a DerefOf (String). The string is a reference + * to a named ACPI object. + * + * 1) Find the owning Node + * 2) Dereference the node to an actual object. Could be a + * Field, so we need to resolve the node to a value. + */ + Status = AcpiNsGetNode (WalkState->ScopeInfo->Scope.Node, + Operand[0]->String.Pointer, + ACPI_NS_SEARCH_PARENT, + ACPI_CAST_INDIRECT_PTR ( + ACPI_NAMESPACE_NODE, &ReturnDesc)); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + Status = AcpiExResolveNodeToValue ( + ACPI_CAST_INDIRECT_PTR ( + ACPI_NAMESPACE_NODE, &ReturnDesc), + WalkState); + goto Cleanup; + } + } + + /* Operand[0] may have changed from the code above */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Operand[0]) == ACPI_DESC_TYPE_NAMED) + { + /* + * This is a DerefOf (ObjectReference) + * Get the actual object from the Node (This is the dereference). + * This case may only happen when a LocalX or ArgX is + * dereferenced above. + */ + ReturnDesc = AcpiNsGetAttachedObject ( + (ACPI_NAMESPACE_NODE *) Operand[0]); + AcpiUtAddReference (ReturnDesc); + } + else + { + /* + * This must be a reference object produced by either the + * Index() or RefOf() operator + */ + switch (Operand[0]->Reference.Class) + { + case ACPI_REFCLASS_INDEX: + /* + * The target type for the Index operator must be + * either a Buffer or a Package + */ + switch (Operand[0]->Reference.TargetType) + { + case ACPI_TYPE_BUFFER_FIELD: + + TempDesc = Operand[0]->Reference.Object; + + /* + * Create a new object that contains one element of the + * buffer -- the element pointed to by the index. + * + * NOTE: index into a buffer is NOT a pointer to a + * sub-buffer of the main buffer, it is only a pointer to a + * single element (byte) of the buffer! + * + * Since we are returning the value of the buffer at the + * indexed location, we don't need to add an additional + * reference to the buffer itself. + */ + ReturnDesc = AcpiUtCreateIntegerObject ((UINT64) + TempDesc->Buffer.Pointer[Operand[0]->Reference.Value]); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + break; + + case ACPI_TYPE_PACKAGE: + /* + * Return the referenced element of the package. We must + * add another reference to the referenced object, however. + */ + ReturnDesc = *(Operand[0]->Reference.Where); + if (!ReturnDesc) + { + /* + * Element is NULL, do not allow the dereference. + * This provides compatibility with other ACPI + * implementations. + */ + return_ACPI_STATUS (AE_AML_UNINITIALIZED_ELEMENT); + } + + AcpiUtAddReference (ReturnDesc); + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown Index TargetType 0x%X in reference object %p", + Operand[0]->Reference.TargetType, Operand[0])); + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + break; + + case ACPI_REFCLASS_REFOF: + + ReturnDesc = Operand[0]->Reference.Object; + + if (ACPI_GET_DESCRIPTOR_TYPE (ReturnDesc) == + ACPI_DESC_TYPE_NAMED) + { + ReturnDesc = AcpiNsGetAttachedObject ( + (ACPI_NAMESPACE_NODE *) ReturnDesc); + if (!ReturnDesc) + { + break; + } + + /* + * June 2013: + * BufferFields/FieldUnits require additional resolution + */ + switch (ReturnDesc->Common.Type) + { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + Status = AcpiExReadDataFromField ( + WalkState, ReturnDesc, &TempDesc); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + ReturnDesc = TempDesc; + break; + + default: + + /* Add another reference to the object */ + + AcpiUtAddReference (ReturnDesc); + break; + } + } + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown class in reference(%p) - 0x%2.2X", + Operand[0], Operand[0]->Reference.Class)); + + Status = AE_TYPE; + goto Cleanup; + } + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + +Cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + } + + /* Save return object on success */ + + else + { + WalkState->ResultObj = ReturnDesc; + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exoparg2.c b/third_party/lib/acpica/source/components/executer/exoparg2.c new file mode 100644 index 000000000..7fe91a818 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exoparg2.c @@ -0,0 +1,640 @@ +/****************************************************************************** + * + * Module Name: exoparg2 - AML execution - opcodes with 2 arguments + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acinterp.h" +#include "acevents.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg2") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (1 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_2A_0T_0R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with two arguments, no target, and no return + * value. + * + * ALLOCATION: Deletes both operands + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_2A_0T_0R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_NAMESPACE_NODE *Node; + UINT32 Value; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_0T_0R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Examine the opcode */ + + switch (WalkState->Opcode) + { + case AML_NOTIFY_OP: /* Notify (NotifyObject, NotifyValue) */ + + /* The first operand is a namespace node */ + + Node = (ACPI_NAMESPACE_NODE *) Operand[0]; + + /* Second value is the notify value */ + + Value = (UINT32) Operand[1]->Integer.Value; + + /* Are notifies allowed on this object? */ + + if (!AcpiEvIsNotifyObject (Node)) + { + ACPI_ERROR ((AE_INFO, + "Unexpected notify object type [%s]", + AcpiUtGetTypeName (Node->Type))); + + Status = AE_AML_OPERAND_TYPE; + break; + } + + /* + * Dispatch the notify to the appropriate handler + * NOTE: the request is queued for execution after this method + * completes. The notify handlers are NOT invoked synchronously + * from this thread -- because handlers may in turn run other + * control methods. + */ + Status = AcpiEvQueueNotifyRequest (Node, Value); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + Status = AE_AML_BAD_OPCODE; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_2A_2T_1R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets + * and one implicit return value. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_2A_2T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ReturnDesc1 = NULL; + ACPI_OPERAND_OBJECT *ReturnDesc2 = NULL; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_2T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Execute the opcode */ + + switch (WalkState->Opcode) + { + case AML_DIVIDE_OP: + + /* Divide (Dividend, Divisor, RemainderResult QuotientResult) */ + + ReturnDesc1 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc1) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + ReturnDesc2 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc2) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Quotient to ReturnDesc1, remainder to ReturnDesc2 */ + + Status = AcpiUtDivide ( + Operand[0]->Integer.Value, + Operand[1]->Integer.Value, + &ReturnDesc1->Integer.Value, + &ReturnDesc2->Integer.Value); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + /* Store the results to the target reference operands */ + + Status = AcpiExStore (ReturnDesc2, Operand[2], WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + Status = AcpiExStore (ReturnDesc1, Operand[3], WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + +Cleanup: + /* + * Since the remainder is not returned indirectly, remove a reference to + * it. Only the quotient is returned indirectly. + */ + AcpiUtRemoveReference (ReturnDesc2); + + if (ACPI_FAILURE (Status)) + { + /* Delete the return object */ + + AcpiUtRemoveReference (ReturnDesc1); + } + + /* Save return object (the remainder) on success */ + + else + { + WalkState->ResultObj = ReturnDesc1; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_2A_1T_1R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with two arguments, one target, and a return + * value. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_2A_1T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + UINT64 Index; + ACPI_STATUS Status = AE_OK; + ACPI_SIZE Length = 0; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_1T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Execute the opcode */ + + if (WalkState->OpInfo->Flags & AML_MATH) + { + /* All simple math opcodes (add, etc.) */ + + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + ReturnDesc->Integer.Value = AcpiExDoMathOp ( + WalkState->Opcode, + Operand[0]->Integer.Value, + Operand[1]->Integer.Value); + goto StoreResultToTarget; + } + + switch (WalkState->Opcode) + { + case AML_MOD_OP: /* Mod (Dividend, Divisor, RemainderResult (ACPI 2.0) */ + + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* ReturnDesc will contain the remainder */ + + Status = AcpiUtDivide ( + Operand[0]->Integer.Value, + Operand[1]->Integer.Value, + NULL, + &ReturnDesc->Integer.Value); + break; + + case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ + + Status = AcpiExDoConcatenate ( + Operand[0], Operand[1], &ReturnDesc, WalkState); + break; + + case AML_TO_STRING_OP: /* ToString (Buffer, Length, Result) (ACPI 2.0) */ + /* + * Input object is guaranteed to be a buffer at this point (it may have + * been converted.) Copy the raw buffer data to a new object of + * type String. + */ + + /* + * Get the length of the new string. It is the smallest of: + * 1) Length of the input buffer + * 2) Max length as specified in the ToString operator + * 3) Length of input buffer up to a zero byte (null terminator) + * + * NOTE: A length of zero is ok, and will create a zero-length, null + * terminated string. + */ + while ((Length < Operand[0]->Buffer.Length) && + (Length < Operand[1]->Integer.Value) && + (Operand[0]->Buffer.Pointer[Length])) + { + Length++; + } + + /* Allocate a new string object */ + + ReturnDesc = AcpiUtCreateStringObject (Length); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* + * Copy the raw buffer data with no transform. + * (NULL terminated already) + */ + memcpy (ReturnDesc->String.Pointer, + Operand[0]->Buffer.Pointer, Length); + break; + + case AML_CONCAT_RES_OP: + + /* ConcatenateResTemplate (Buffer, Buffer, Result) (ACPI 2.0) */ + + Status = AcpiExConcatTemplate ( + Operand[0], Operand[1], &ReturnDesc, WalkState); + break; + + case AML_INDEX_OP: /* Index (Source Index Result) */ + + /* Create the internal return object */ + + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Initialize the Index reference object */ + + Index = Operand[1]->Integer.Value; + ReturnDesc->Reference.Value = (UINT32) Index; + ReturnDesc->Reference.Class = ACPI_REFCLASS_INDEX; + + /* + * At this point, the Source operand is a String, Buffer, or Package. + * Verify that the index is within range. + */ + switch ((Operand[0])->Common.Type) + { + case ACPI_TYPE_STRING: + + if (Index >= Operand[0]->String.Length) + { + Length = Operand[0]->String.Length; + Status = AE_AML_STRING_LIMIT; + } + + ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; + ReturnDesc->Reference.IndexPointer = + &(Operand[0]->Buffer.Pointer [Index]); + break; + + case ACPI_TYPE_BUFFER: + + if (Index >= Operand[0]->Buffer.Length) + { + Length = Operand[0]->Buffer.Length; + Status = AE_AML_BUFFER_LIMIT; + } + + ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; + ReturnDesc->Reference.IndexPointer = + &(Operand[0]->Buffer.Pointer [Index]); + break; + + case ACPI_TYPE_PACKAGE: + + if (Index >= Operand[0]->Package.Count) + { + Length = Operand[0]->Package.Count; + Status = AE_AML_PACKAGE_LIMIT; + } + + ReturnDesc->Reference.TargetType = ACPI_TYPE_PACKAGE; + ReturnDesc->Reference.Where = + &Operand[0]->Package.Elements [Index]; + break; + + default: + + Status = AE_AML_INTERNAL; + goto Cleanup; + } + + /* Failure means that the Index was beyond the end of the object */ + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Index (0x%X%8.8X) is beyond end of object (length 0x%X)", + ACPI_FORMAT_UINT64 (Index), (UINT32) Length)); + goto Cleanup; + } + + /* + * Save the target object and add a reference to it for the life + * of the index + */ + ReturnDesc->Reference.Object = Operand[0]; + AcpiUtAddReference (Operand[0]); + + /* Store the reference to the Target */ + + Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); + + /* Return the reference */ + + WalkState->ResultObj = ReturnDesc; + goto Cleanup; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + Status = AE_AML_BAD_OPCODE; + break; + } + + +StoreResultToTarget: + + if (ACPI_SUCCESS (Status)) + { + /* + * Store the result of the operation (which is now in ReturnDesc) into + * the Target descriptor. + */ + Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + if (!WalkState->ResultObj) + { + WalkState->ResultObj = ReturnDesc; + } + } + + +Cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + WalkState->ResultObj = NULL; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_2A_0T_1R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_2A_0T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + ACPI_STATUS Status = AE_OK; + BOOLEAN LogicalResult = FALSE; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_0T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + /* Create the internal return object */ + + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Execute the Opcode */ + + if (WalkState->OpInfo->Flags & AML_LOGICAL_NUMERIC) + { + /* LogicalOp (Operand0, Operand1) */ + + Status = AcpiExDoLogicalNumericOp (WalkState->Opcode, + Operand[0]->Integer.Value, Operand[1]->Integer.Value, + &LogicalResult); + goto StoreLogicalResult; + } + else if (WalkState->OpInfo->Flags & AML_LOGICAL) + { + /* LogicalOp (Operand0, Operand1) */ + + Status = AcpiExDoLogicalOp (WalkState->Opcode, Operand[0], + Operand[1], &LogicalResult); + goto StoreLogicalResult; + } + + switch (WalkState->Opcode) + { + case AML_ACQUIRE_OP: /* Acquire (MutexObject, Timeout) */ + + Status = AcpiExAcquireMutex (Operand[1], Operand[0], WalkState); + if (Status == AE_TIME) + { + LogicalResult = TRUE; /* TRUE = Acquire timed out */ + Status = AE_OK; + } + break; + + + case AML_WAIT_OP: /* Wait (EventObject, Timeout) */ + + Status = AcpiExSystemWaitEvent (Operand[1], Operand[0]); + if (Status == AE_TIME) + { + LogicalResult = TRUE; /* TRUE, Wait timed out */ + Status = AE_OK; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + +StoreLogicalResult: + /* + * Set return value to according to LogicalResult. logical TRUE (all ones) + * Default is FALSE (zero) + */ + if (LogicalResult) + { + ReturnDesc->Integer.Value = ACPI_UINT64_MAX; + } + +Cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + } + + /* Save return object on success */ + + else + { + WalkState->ResultObj = ReturnDesc; + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exoparg3.c b/third_party/lib/acpica/source/components/executer/exoparg3.c new file mode 100644 index 000000000..db9fd11f9 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exoparg3.c @@ -0,0 +1,310 @@ +/****************************************************************************** + * + * Module Name: exoparg3 - AML execution - opcodes with 3 arguments + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg3") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (1 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_3A_0T_0R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute Triadic operator (3 operands) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_3A_0T_0R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_SIGNAL_FATAL_INFO *Fatal; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_3A_0T_0R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + switch (WalkState->Opcode) + { + case AML_FATAL_OP: /* Fatal (FatalType FatalCode FatalArg) */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "FatalOp: Type %X Code %X Arg %X " + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + (UINT32) Operand[0]->Integer.Value, + (UINT32) Operand[1]->Integer.Value, + (UINT32) Operand[2]->Integer.Value)); + + Fatal = ACPI_ALLOCATE (sizeof (ACPI_SIGNAL_FATAL_INFO)); + if (Fatal) + { + Fatal->Type = (UINT32) Operand[0]->Integer.Value; + Fatal->Code = (UINT32) Operand[1]->Integer.Value; + Fatal->Argument = (UINT32) Operand[2]->Integer.Value; + } + + /* Always signal the OS! */ + + Status = AcpiOsSignal (ACPI_SIGNAL_FATAL, Fatal); + + /* Might return while OS is shutting down, just continue */ + + ACPI_FREE (Fatal); + goto Cleanup; + + case AML_EXTERNAL_OP: + /* + * If the interpreter sees this opcode, just ignore it. The External + * op is intended for use by disassemblers in order to properly + * disassemble control method invocations. The opcode or group of + * opcodes should be surrounded by an "if (0)" clause to ensure that + * AML interpreters never see the opcode. + */ + Status = AE_OK; + goto Cleanup; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + +Cleanup: + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_3A_1T_1R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute Triadic operator (3 operands) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_3A_1T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + char *Buffer = NULL; + ACPI_STATUS Status = AE_OK; + UINT64 Index; + ACPI_SIZE Length; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_3A_1T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + switch (WalkState->Opcode) + { + case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ + /* + * Create the return object. The Source operand is guaranteed to be + * either a String or a Buffer, so just use its type. + */ + ReturnDesc = AcpiUtCreateInternalObject ( + (Operand[0])->Common.Type); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Get the Integer values from the objects */ + + Index = Operand[1]->Integer.Value; + Length = (ACPI_SIZE) Operand[2]->Integer.Value; + + /* + * If the index is beyond the length of the String/Buffer, or if the + * requested length is zero, return a zero-length String/Buffer + */ + if (Index >= Operand[0]->String.Length) + { + Length = 0; + } + + /* Truncate request if larger than the actual String/Buffer */ + + else if ((Index + Length) > Operand[0]->String.Length) + { + Length = + (ACPI_SIZE) Operand[0]->String.Length - (ACPI_SIZE) Index; + } + + /* Strings always have a sub-pointer, not so for buffers */ + + switch ((Operand[0])->Common.Type) + { + case ACPI_TYPE_STRING: + + /* Always allocate a new buffer for the String */ + + Buffer = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) Length + 1); + if (!Buffer) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + break; + + case ACPI_TYPE_BUFFER: + + /* If the requested length is zero, don't allocate a buffer */ + + if (Length > 0) + { + /* Allocate a new buffer for the Buffer */ + + Buffer = ACPI_ALLOCATE_ZEROED (Length); + if (!Buffer) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + } + break; + + default: /* Should not happen */ + + Status = AE_AML_OPERAND_TYPE; + goto Cleanup; + } + + if (Buffer) + { + /* We have a buffer, copy the portion requested */ + + memcpy (Buffer, + Operand[0]->String.Pointer + Index, Length); + } + + /* Set the length of the new String/Buffer */ + + ReturnDesc->String.Pointer = Buffer; + ReturnDesc->String.Length = (UINT32) Length; + + /* Mark buffer initialized */ + + ReturnDesc->Buffer.Flags |= AOPOBJ_DATA_VALID; + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + /* Store the result in the target */ + + Status = AcpiExStore (ReturnDesc, Operand[3], WalkState); + +Cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (Status) || WalkState->ResultObj) + { + AcpiUtRemoveReference (ReturnDesc); + WalkState->ResultObj = NULL; + } + else + { + /* Set the return object and exit */ + + WalkState->ResultObj = ReturnDesc; + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exoparg6.c b/third_party/lib/acpica/source/components/executer/exoparg6.c new file mode 100644 index 000000000..2cc8f59bb --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exoparg6.c @@ -0,0 +1,356 @@ +/****************************************************************************** + * + * Module Name: exoparg6 - AML execution - opcodes with 6 arguments + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg6") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (1 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + +/* Local prototypes */ + +static BOOLEAN +AcpiExDoMatch ( + UINT32 MatchOp, + ACPI_OPERAND_OBJECT *PackageObj, + ACPI_OPERAND_OBJECT *MatchObj); + + +/******************************************************************************* + * + * FUNCTION: AcpiExDoMatch + * + * PARAMETERS: MatchOp - The AML match operand + * PackageObj - Object from the target package + * MatchObj - Object to be matched + * + * RETURN: TRUE if the match is successful, FALSE otherwise + * + * DESCRIPTION: Implements the low-level match for the ASL Match operator. + * Package elements will be implicitly converted to the type of + * the match object (Integer/Buffer/String). + * + ******************************************************************************/ + +static BOOLEAN +AcpiExDoMatch ( + UINT32 MatchOp, + ACPI_OPERAND_OBJECT *PackageObj, + ACPI_OPERAND_OBJECT *MatchObj) +{ + BOOLEAN LogicalResult = TRUE; + ACPI_STATUS Status; + + + /* + * Note: Since the PackageObj/MatchObj ordering is opposite to that of + * the standard logical operators, we have to reverse them when we call + * DoLogicalOp in order to make the implicit conversion rules work + * correctly. However, this means we have to flip the entire equation + * also. A bit ugly perhaps, but overall, better than fussing the + * parameters around at runtime, over and over again. + * + * Below, P[i] refers to the package element, M refers to the Match object. + */ + switch (MatchOp) + { + case MATCH_MTR: + + /* Always true */ + + break; + + case MATCH_MEQ: + /* + * True if equal: (P[i] == M) + * Change to: (M == P[i]) + */ + Status = AcpiExDoLogicalOp ( + AML_LEQUAL_OP, MatchObj, PackageObj, &LogicalResult); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + break; + + case MATCH_MLE: + /* + * True if less than or equal: (P[i] <= M) (P[i] NotGreater than M) + * Change to: (M >= P[i]) (M NotLess than P[i]) + */ + Status = AcpiExDoLogicalOp ( + AML_LLESS_OP, MatchObj, PackageObj, &LogicalResult); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + LogicalResult = (BOOLEAN) !LogicalResult; + break; + + case MATCH_MLT: + /* + * True if less than: (P[i] < M) + * Change to: (M > P[i]) + */ + Status = AcpiExDoLogicalOp ( + AML_LGREATER_OP, MatchObj, PackageObj, &LogicalResult); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + break; + + case MATCH_MGE: + /* + * True if greater than or equal: (P[i] >= M) (P[i] NotLess than M) + * Change to: (M <= P[i]) (M NotGreater than P[i]) + */ + Status = AcpiExDoLogicalOp ( + AML_LGREATER_OP, MatchObj, PackageObj, &LogicalResult); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + LogicalResult = (BOOLEAN)!LogicalResult; + break; + + case MATCH_MGT: + /* + * True if greater than: (P[i] > M) + * Change to: (M < P[i]) + */ + Status = AcpiExDoLogicalOp ( + AML_LLESS_OP, MatchObj, PackageObj, &LogicalResult); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + break; + + default: + + /* Undefined */ + + return (FALSE); + } + + return (LogicalResult); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExOpcode_6A_0T_1R + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with 6 arguments, no target, and a return value + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExOpcode_6A_0T_1R ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; + ACPI_OPERAND_OBJECT *ReturnDesc = NULL; + ACPI_STATUS Status = AE_OK; + UINT64 Index; + ACPI_OPERAND_OBJECT *ThisElement; + + + ACPI_FUNCTION_TRACE_STR (ExOpcode_6A_0T_1R, + AcpiPsGetOpcodeName (WalkState->Opcode)); + + + switch (WalkState->Opcode) + { + case AML_MATCH_OP: + /* + * Match (SearchPkg[0], MatchOp1[1], MatchObj1[2], + * MatchOp2[3], MatchObj2[4], StartIndex[5]) + */ + + /* Validate both Match Term Operators (MTR, MEQ, etc.) */ + + if ((Operand[1]->Integer.Value > MAX_MATCH_OPERATOR) || + (Operand[3]->Integer.Value > MAX_MATCH_OPERATOR)) + { + ACPI_ERROR ((AE_INFO, "Match operator out of range")); + Status = AE_AML_OPERAND_VALUE; + goto Cleanup; + } + + /* Get the package StartIndex, validate against the package length */ + + Index = Operand[5]->Integer.Value; + if (Index >= Operand[0]->Package.Count) + { + ACPI_ERROR ((AE_INFO, + "Index (0x%8.8X%8.8X) beyond package end (0x%X)", + ACPI_FORMAT_UINT64 (Index), Operand[0]->Package.Count)); + Status = AE_AML_PACKAGE_LIMIT; + goto Cleanup; + } + + /* Create an integer for the return value */ + /* Default return value is ACPI_UINT64_MAX if no match found */ + + ReturnDesc = AcpiUtCreateIntegerObject (ACPI_UINT64_MAX); + if (!ReturnDesc) + { + Status = AE_NO_MEMORY; + goto Cleanup; + + } + + /* + * Examine each element until a match is found. Both match conditions + * must be satisfied for a match to occur. Within the loop, + * "continue" signifies that the current element does not match + * and the next should be examined. + * + * Upon finding a match, the loop will terminate via "break" at + * the bottom. If it terminates "normally", MatchValue will be + * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no + * match was found. + */ + for ( ; Index < Operand[0]->Package.Count; Index++) + { + /* Get the current package element */ + + ThisElement = Operand[0]->Package.Elements[Index]; + + /* Treat any uninitialized (NULL) elements as non-matching */ + + if (!ThisElement) + { + continue; + } + + /* + * Both match conditions must be satisfied. Execution of a continue + * (proceed to next iteration of enclosing for loop) signifies a + * non-match. + */ + if (!AcpiExDoMatch ((UINT32) Operand[1]->Integer.Value, + ThisElement, Operand[2])) + { + continue; + } + + if (!AcpiExDoMatch ((UINT32) Operand[3]->Integer.Value, + ThisElement, Operand[4])) + { + continue; + } + + /* Match found: Index is the return value */ + + ReturnDesc->Integer.Value = Index; + break; + } + break; + + case AML_LOAD_TABLE_OP: + + Status = AcpiExLoadTableOp (WalkState, &ReturnDesc); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + WalkState->Opcode)); + + Status = AE_AML_BAD_OPCODE; + goto Cleanup; + } + + +Cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + } + + /* Save return object on success */ + + else + { + WalkState->ResultObj = ReturnDesc; + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exprep.c b/third_party/lib/acpica/source/components/executer/exprep.c new file mode 100644 index 000000000..51f2714ab --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exprep.c @@ -0,0 +1,667 @@ +/****************************************************************************** + * + * Module Name: exprep - ACPI AML field prep utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exprep") + +/* Local prototypes */ + +static UINT32 +AcpiExDecodeFieldAccess ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 FieldFlags, + UINT32 *ReturnByteAlignment); + + +#ifdef ACPI_UNDER_DEVELOPMENT + +static UINT32 +AcpiExGenerateAccess ( + UINT32 FieldBitOffset, + UINT32 FieldBitLength, + UINT32 RegionLength); + + +/******************************************************************************* + * + * FUNCTION: AcpiExGenerateAccess + * + * PARAMETERS: FieldBitOffset - Start of field within parent region/buffer + * FieldBitLength - Length of field in bits + * RegionLength - Length of parent in bytes + * + * RETURN: Field granularity (8, 16, 32 or 64) and + * ByteAlignment (1, 2, 3, or 4) + * + * DESCRIPTION: Generate an optimal access width for fields defined with the + * AnyAcc keyword. + * + * NOTE: Need to have the RegionLength in order to check for boundary + * conditions (end-of-region). However, the RegionLength is a deferred + * operation. Therefore, to complete this implementation, the generation + * of this access width must be deferred until the region length has + * been evaluated. + * + ******************************************************************************/ + +static UINT32 +AcpiExGenerateAccess ( + UINT32 FieldBitOffset, + UINT32 FieldBitLength, + UINT32 RegionLength) +{ + UINT32 FieldByteLength; + UINT32 FieldByteOffset; + UINT32 FieldByteEndOffset; + UINT32 AccessByteWidth; + UINT32 FieldStartOffset; + UINT32 FieldEndOffset; + UINT32 MinimumAccessWidth = 0xFFFFFFFF; + UINT32 MinimumAccesses = 0xFFFFFFFF; + UINT32 Accesses; + + + ACPI_FUNCTION_TRACE (ExGenerateAccess); + + + /* Round Field start offset and length to "minimal" byte boundaries */ + + FieldByteOffset = ACPI_DIV_8 ( + ACPI_ROUND_DOWN (FieldBitOffset, 8)); + + FieldByteEndOffset = ACPI_DIV_8 ( + ACPI_ROUND_UP (FieldBitLength + FieldBitOffset, 8)); + + FieldByteLength = FieldByteEndOffset - FieldByteOffset; + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Bit length %u, Bit offset %u\n", + FieldBitLength, FieldBitOffset)); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Byte Length %u, Byte Offset %u, End Offset %u\n", + FieldByteLength, FieldByteOffset, FieldByteEndOffset)); + + /* + * Iterative search for the maximum access width that is both aligned + * and does not go beyond the end of the region + * + * Start at ByteAcc and work upwards to QwordAcc max. (1,2,4,8 bytes) + */ + for (AccessByteWidth = 1; AccessByteWidth <= 8; AccessByteWidth <<= 1) + { + /* + * 1) Round end offset up to next access boundary and make sure that + * this does not go beyond the end of the parent region. + * 2) When the Access width is greater than the FieldByteLength, we + * are done. (This does not optimize for the perfectly aligned + * case yet). + */ + if (ACPI_ROUND_UP (FieldByteEndOffset, AccessByteWidth) <= + RegionLength) + { + FieldStartOffset = + ACPI_ROUND_DOWN (FieldByteOffset, AccessByteWidth) / + AccessByteWidth; + + FieldEndOffset = + ACPI_ROUND_UP ((FieldByteLength + FieldByteOffset), + AccessByteWidth) / AccessByteWidth; + + Accesses = FieldEndOffset - FieldStartOffset; + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "AccessWidth %u end is within region\n", AccessByteWidth)); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field Start %u, Field End %u -- requires %u accesses\n", + FieldStartOffset, FieldEndOffset, Accesses)); + + /* Single access is optimal */ + + if (Accesses <= 1) + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Entire field can be accessed " + "with one operation of size %u\n", + AccessByteWidth)); + return_VALUE (AccessByteWidth); + } + + /* + * Fits in the region, but requires more than one read/write. + * try the next wider access on next iteration + */ + if (Accesses < MinimumAccesses) + { + MinimumAccesses = Accesses; + MinimumAccessWidth = AccessByteWidth; + } + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "AccessWidth %u end is NOT within region\n", + AccessByteWidth)); + if (AccessByteWidth == 1) + { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field goes beyond end-of-region!\n")); + + /* Field does not fit in the region at all */ + + return_VALUE (0); + } + + /* + * This width goes beyond the end-of-region, back off to + * previous access + */ + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Backing off to previous optimal access width of %u\n", + MinimumAccessWidth)); + return_VALUE (MinimumAccessWidth); + } + } + + /* + * Could not read/write field with one operation, + * just use max access width + */ + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Cannot access field in one operation, using width 8\n")); + + return_VALUE (8); +} +#endif /* ACPI_UNDER_DEVELOPMENT */ + + +/******************************************************************************* + * + * FUNCTION: AcpiExDecodeFieldAccess + * + * PARAMETERS: ObjDesc - Field object + * FieldFlags - Encoded fieldflags (contains access bits) + * ReturnByteAlignment - Where the byte alignment is returned + * + * RETURN: Field granularity (8, 16, 32 or 64) and + * ByteAlignment (1, 2, 3, or 4) + * + * DESCRIPTION: Decode the AccessType bits of a field definition. + * + ******************************************************************************/ + +static UINT32 +AcpiExDecodeFieldAccess ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 FieldFlags, + UINT32 *ReturnByteAlignment) +{ + UINT32 Access; + UINT32 ByteAlignment; + UINT32 BitLength; + + + ACPI_FUNCTION_TRACE (ExDecodeFieldAccess); + + + Access = (FieldFlags & AML_FIELD_ACCESS_TYPE_MASK); + + switch (Access) + { + case AML_FIELD_ACCESS_ANY: + +#ifdef ACPI_UNDER_DEVELOPMENT + ByteAlignment = + AcpiExGenerateAccess (ObjDesc->CommonField.StartFieldBitOffset, + ObjDesc->CommonField.BitLength, + 0xFFFFFFFF /* Temp until we pass RegionLength as parameter */); + BitLength = ByteAlignment * 8; +#endif + + ByteAlignment = 1; + BitLength = 8; + break; + + case AML_FIELD_ACCESS_BYTE: + case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */ + + ByteAlignment = 1; + BitLength = 8; + break; + + case AML_FIELD_ACCESS_WORD: + + ByteAlignment = 2; + BitLength = 16; + break; + + case AML_FIELD_ACCESS_DWORD: + + ByteAlignment = 4; + BitLength = 32; + break; + + case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ + + ByteAlignment = 8; + BitLength = 64; + break; + + default: + + /* Invalid field access type */ + + ACPI_ERROR ((AE_INFO, + "Unknown field access type 0x%X", + Access)); + + return_UINT32 (0); + } + + if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) + { + /* + * BufferField access can be on any byte boundary, so the + * ByteAlignment is always 1 byte -- regardless of any ByteAlignment + * implied by the field access type. + */ + ByteAlignment = 1; + } + + *ReturnByteAlignment = ByteAlignment; + return_UINT32 (BitLength); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExPrepCommonFieldObject + * + * PARAMETERS: ObjDesc - The field object + * FieldFlags - Access, LockRule, and UpdateRule. + * The format of a FieldFlag is described + * in the ACPI specification + * FieldAttribute - Special attributes (not used) + * FieldBitPosition - Field start position + * FieldBitLength - Field length in number of bits + * + * RETURN: Status + * + * DESCRIPTION: Initialize the areas of the field object that are common + * to the various types of fields. Note: This is very "sensitive" + * code because we are solving the general case for field + * alignment. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExPrepCommonFieldObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 FieldFlags, + UINT8 FieldAttribute, + UINT32 FieldBitPosition, + UINT32 FieldBitLength) +{ + UINT32 AccessBitWidth; + UINT32 ByteAlignment; + UINT32 NearestByteAddress; + + + ACPI_FUNCTION_TRACE (ExPrepCommonFieldObject); + + + /* + * Note: the structure being initialized is the + * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common + * area are initialized by this procedure. + */ + ObjDesc->CommonField.FieldFlags = FieldFlags; + ObjDesc->CommonField.Attribute = FieldAttribute; + ObjDesc->CommonField.BitLength = FieldBitLength; + + /* + * Decode the access type so we can compute offsets. The access type gives + * two pieces of information - the width of each field access and the + * necessary ByteAlignment (address granularity) of the access. + * + * For AnyAcc, the AccessBitWidth is the largest width that is both + * necessary and possible in an attempt to access the whole field in one + * I/O operation. However, for AnyAcc, the ByteAlignment is always one + * byte. + * + * For all Buffer Fields, the ByteAlignment is always one byte. + * + * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is + * the same (equivalent) as the ByteAlignment. + */ + AccessBitWidth = AcpiExDecodeFieldAccess ( + ObjDesc, FieldFlags, &ByteAlignment); + if (!AccessBitWidth) + { + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + + /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */ + + ObjDesc->CommonField.AccessByteWidth = (UINT8) + ACPI_DIV_8 (AccessBitWidth); + + /* + * BaseByteOffset is the address of the start of the field within the + * region. It is the byte address of the first *datum* (field-width data + * unit) of the field. (i.e., the first datum that contains at least the + * first *bit* of the field.) + * + * Note: ByteAlignment is always either equal to the AccessBitWidth or 8 + * (Byte access), and it defines the addressing granularity of the parent + * region or buffer. + */ + NearestByteAddress = + ACPI_ROUND_BITS_DOWN_TO_BYTES (FieldBitPosition); + ObjDesc->CommonField.BaseByteOffset = (UINT32) + ACPI_ROUND_DOWN (NearestByteAddress, ByteAlignment); + + /* + * StartFieldBitOffset is the offset of the first bit of the field within + * a field datum. + */ + ObjDesc->CommonField.StartFieldBitOffset = (UINT8) + (FieldBitPosition - ACPI_MUL_8 (ObjDesc->CommonField.BaseByteOffset)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExPrepFieldValue + * + * PARAMETERS: Info - Contains all field creation info + * + * RETURN: Status + * + * DESCRIPTION: Construct an object of type ACPI_OPERAND_OBJECT with a + * subtype of DefField and connect it to the parent Node. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExPrepFieldValue ( + ACPI_CREATE_FIELD_INFO *Info) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *SecondDesc = NULL; + ACPI_STATUS Status; + UINT32 AccessByteWidth; + UINT32 Type; + + + ACPI_FUNCTION_TRACE (ExPrepFieldValue); + + + /* Parameter validation */ + + if (Info->FieldType != ACPI_TYPE_LOCAL_INDEX_FIELD) + { + if (!Info->RegionNode) + { + ACPI_ERROR ((AE_INFO, "Null RegionNode")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + Type = AcpiNsGetType (Info->RegionNode); + if (Type != ACPI_TYPE_REGION) + { + ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", + Type, AcpiUtGetTypeName (Type))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + } + + /* Allocate a new field object */ + + ObjDesc = AcpiUtCreateInternalObject (Info->FieldType); + if (!ObjDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize areas of the object that are common to all fields */ + + ObjDesc->CommonField.Node = Info->FieldNode; + Status = AcpiExPrepCommonFieldObject (ObjDesc, + Info->FieldFlags, Info->Attribute, + Info->FieldBitPosition, Info->FieldBitLength); + if (ACPI_FAILURE (Status)) + { + AcpiUtDeleteObjectDesc (ObjDesc); + return_ACPI_STATUS (Status); + } + + /* Initialize areas of the object that are specific to the field type */ + + switch (Info->FieldType) + { + case ACPI_TYPE_LOCAL_REGION_FIELD: + + ObjDesc->Field.RegionObj = AcpiNsGetAttachedObject (Info->RegionNode); + + /* Fields specific to GenericSerialBus fields */ + + ObjDesc->Field.AccessLength = Info->AccessLength; + + if (Info->ConnectionNode) + { + SecondDesc = Info->ConnectionNode->Object; + if (!(SecondDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + Status = AcpiDsGetBufferArguments (SecondDesc); + if (ACPI_FAILURE (Status)) + { + AcpiUtDeleteObjectDesc (ObjDesc); + return_ACPI_STATUS (Status); + } + } + + ObjDesc->Field.ResourceBuffer = + SecondDesc->Buffer.Pointer; + ObjDesc->Field.ResourceLength = + (UINT16) SecondDesc->Buffer.Length; + } + else if (Info->ResourceBuffer) + { + ObjDesc->Field.ResourceBuffer = Info->ResourceBuffer; + ObjDesc->Field.ResourceLength = Info->ResourceLength; + } + + ObjDesc->Field.PinNumberIndex = Info->PinNumberIndex; + + /* Allow full data read from EC address space */ + + if ((ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_EC) && + (ObjDesc->CommonField.BitLength > 8)) + { + AccessByteWidth = ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->CommonField.BitLength); + + /* Maximum byte width supported is 255 */ + + if (AccessByteWidth < 256) + { + ObjDesc->CommonField.AccessByteWidth = + (UINT8) AccessByteWidth; + } + } + + /* An additional reference for the container */ + + AcpiUtAddReference (ObjDesc->Field.RegionObj); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", + ObjDesc->Field.StartFieldBitOffset, + ObjDesc->Field.BaseByteOffset, + ObjDesc->Field.AccessByteWidth, + ObjDesc->Field.RegionObj)); + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + ObjDesc->BankField.Value = Info->BankValue; + ObjDesc->BankField.RegionObj = + AcpiNsGetAttachedObject (Info->RegionNode); + ObjDesc->BankField.BankObj = + AcpiNsGetAttachedObject (Info->RegisterNode); + + /* An additional reference for the attached objects */ + + AcpiUtAddReference (ObjDesc->BankField.RegionObj); + AcpiUtAddReference (ObjDesc->BankField.BankObj); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", + ObjDesc->BankField.StartFieldBitOffset, + ObjDesc->BankField.BaseByteOffset, + ObjDesc->Field.AccessByteWidth, + ObjDesc->BankField.RegionObj, + ObjDesc->BankField.BankObj)); + + /* + * Remember location in AML stream of the field unit + * opcode and operands -- since the BankValue + * operands must be evaluated. + */ + SecondDesc = ObjDesc->Common.NextObject; + SecondDesc->Extra.AmlStart = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, + Info->DataRegisterNode)->Named.Data; + SecondDesc->Extra.AmlLength = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, + Info->DataRegisterNode)->Named.Length; + + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + /* Get the Index and Data registers */ + + ObjDesc->IndexField.IndexObj = + AcpiNsGetAttachedObject (Info->RegisterNode); + ObjDesc->IndexField.DataObj = + AcpiNsGetAttachedObject (Info->DataRegisterNode); + + if (!ObjDesc->IndexField.DataObj || !ObjDesc->IndexField.IndexObj) + { + ACPI_ERROR ((AE_INFO, "Null Index Object during field prep")); + AcpiUtDeleteObjectDesc (ObjDesc); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* An additional reference for the attached objects */ + + AcpiUtAddReference (ObjDesc->IndexField.DataObj); + AcpiUtAddReference (ObjDesc->IndexField.IndexObj); + + /* + * April 2006: Changed to match MS behavior + * + * The value written to the Index register is the byte offset of the + * target field in units of the granularity of the IndexField + * + * Previously, the value was calculated as an index in terms of the + * width of the Data register, as below: + * + * ObjDesc->IndexField.Value = (UINT32) + * (Info->FieldBitPosition / ACPI_MUL_8 ( + * ObjDesc->Field.AccessByteWidth)); + * + * February 2006: Tried value as a byte offset: + * ObjDesc->IndexField.Value = (UINT32) + * ACPI_DIV_8 (Info->FieldBitPosition); + */ + ObjDesc->IndexField.Value = (UINT32) ACPI_ROUND_DOWN ( + ACPI_DIV_8 (Info->FieldBitPosition), + ObjDesc->IndexField.AccessByteWidth); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "IndexField: BitOff %X, Off %X, Value %X, " + "Gran %X, Index %p, Data %p\n", + ObjDesc->IndexField.StartFieldBitOffset, + ObjDesc->IndexField.BaseByteOffset, + ObjDesc->IndexField.Value, + ObjDesc->Field.AccessByteWidth, + ObjDesc->IndexField.IndexObj, + ObjDesc->IndexField.DataObj)); + break; + + default: + + /* No other types should get here */ + + break; + } + + /* + * Store the constructed descriptor (ObjDesc) into the parent Node, + * preserving the current type of that NamedObj. + */ + Status = AcpiNsAttachObject ( + Info->FieldNode, ObjDesc, AcpiNsGetType (Info->FieldNode)); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Set NamedObj %p [%4.4s], ObjDesc %p\n", + Info->FieldNode, AcpiUtGetNodeName (Info->FieldNode), ObjDesc)); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exregion.c b/third_party/lib/acpica/source/components/executer/exregion.c new file mode 100644 index 000000000..58d3a0c24 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exregion.c @@ -0,0 +1,578 @@ +/****************************************************************************** + * + * Module Name: exregion - ACPI default OpRegion (address space) handlers + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exregion") + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemMemorySpaceHandler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * BitWidth - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * HandlerContext - Pointer to Handler's context + * RegionContext - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the System Memory address space (Op Region) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemMemorySpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + ACPI_STATUS Status = AE_OK; + void *LogicalAddrPtr = NULL; + ACPI_MEM_SPACE_CONTEXT *MemInfo = RegionContext; + UINT32 Length; + ACPI_SIZE MapLength; + ACPI_SIZE PageBoundaryMapLength; +#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED + UINT32 Remainder; +#endif + + + ACPI_FUNCTION_TRACE (ExSystemMemorySpaceHandler); + + + /* Validate and translate the bit width */ + + switch (BitWidth) + { + case 8: + + Length = 1; + break; + + case 16: + + Length = 2; + break; + + case 32: + + Length = 4; + break; + + case 64: + + Length = 8; + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid SystemMemory width %u", + BitWidth)); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + +#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED + /* + * Hardware does not support non-aligned data transfers, we must verify + * the request. + */ + (void) AcpiUtShortDivide ((UINT64) Address, Length, NULL, &Remainder); + if (Remainder != 0) + { + return_ACPI_STATUS (AE_AML_ALIGNMENT); + } +#endif + + /* + * Does the request fit into the cached memory mapping? + * Is 1) Address below the current mapping? OR + * 2) Address beyond the current mapping? + */ + if ((Address < MemInfo->MappedPhysicalAddress) || + (((UINT64) Address + Length) > + ((UINT64) + MemInfo->MappedPhysicalAddress + MemInfo->MappedLength))) + { + /* + * The request cannot be resolved by the current memory mapping; + * Delete the existing mapping and create a new one. + */ + if (MemInfo->MappedLength) + { + /* Valid mapping, delete it */ + + AcpiOsUnmapMemory (MemInfo->MappedLogicalAddress, + MemInfo->MappedLength); + } + + /* + * October 2009: Attempt to map from the requested address to the + * end of the region. However, we will never map more than one + * page, nor will we cross a page boundary. + */ + MapLength = (ACPI_SIZE) + ((MemInfo->Address + MemInfo->Length) - Address); + + /* + * If mapping the entire remaining portion of the region will cross + * a page boundary, just map up to the page boundary, do not cross. + * On some systems, crossing a page boundary while mapping regions + * can cause warnings if the pages have different attributes + * due to resource management. + * + * This has the added benefit of constraining a single mapping to + * one page, which is similar to the original code that used a 4k + * maximum window. + */ + PageBoundaryMapLength = (ACPI_SIZE) + (ACPI_ROUND_UP (Address, ACPI_DEFAULT_PAGE_SIZE) - Address); + if (PageBoundaryMapLength == 0) + { + PageBoundaryMapLength = ACPI_DEFAULT_PAGE_SIZE; + } + + if (MapLength > PageBoundaryMapLength) + { + MapLength = PageBoundaryMapLength; + } + + /* Create a new mapping starting at the address given */ + + MemInfo->MappedLogicalAddress = AcpiOsMapMemory (Address, MapLength); + if (!MemInfo->MappedLogicalAddress) + { + ACPI_ERROR ((AE_INFO, + "Could not map memory at 0x%8.8X%8.8X, size %u", + ACPI_FORMAT_UINT64 (Address), (UINT32) MapLength)); + MemInfo->MappedLength = 0; + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Save the physical address and mapping size */ + + MemInfo->MappedPhysicalAddress = Address; + MemInfo->MappedLength = MapLength; + } + + /* + * Generate a logical pointer corresponding to the address we want to + * access + */ + LogicalAddrPtr = MemInfo->MappedLogicalAddress + + ((UINT64) Address - (UINT64) MemInfo->MappedPhysicalAddress); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", + BitWidth, Function, ACPI_FORMAT_UINT64 (Address))); + + /* + * Perform the memory read or write + * + * Note: For machines that do not support non-aligned transfers, the target + * address was checked for alignment above. We do not attempt to break the + * transfer up into smaller (byte-size) chunks because the AML specifically + * asked for a transfer width that the hardware may require. + */ + switch (Function) + { + case ACPI_READ: + + *Value = 0; + switch (BitWidth) + { + case 8: + + *Value = (UINT64) ACPI_GET8 (LogicalAddrPtr); + break; + + case 16: + + *Value = (UINT64) ACPI_GET16 (LogicalAddrPtr); + break; + + case 32: + + *Value = (UINT64) ACPI_GET32 (LogicalAddrPtr); + break; + + case 64: + + *Value = (UINT64) ACPI_GET64 (LogicalAddrPtr); + break; + + default: + + /* BitWidth was already validated */ + + break; + } + break; + + case ACPI_WRITE: + + switch (BitWidth) + { + case 8: + + ACPI_SET8 (LogicalAddrPtr, *Value); + break; + + case 16: + + ACPI_SET16 (LogicalAddrPtr, *Value); + break; + + case 32: + + ACPI_SET32 (LogicalAddrPtr, *Value); + break; + + case 64: + + ACPI_SET64 (LogicalAddrPtr, *Value); + break; + + default: + + /* BitWidth was already validated */ + + break; + } + break; + + default: + + Status = AE_BAD_PARAMETER; + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemIoSpaceHandler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * BitWidth - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * HandlerContext - Pointer to Handler's context + * RegionContext - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the System IO address space (Op Region) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemIoSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + ACPI_STATUS Status = AE_OK; + UINT32 Value32; + + + ACPI_FUNCTION_TRACE (ExSystemIoSpaceHandler); + + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n", + BitWidth, Function, ACPI_FORMAT_UINT64 (Address))); + + /* Decode the function parameter */ + + switch (Function) + { + case ACPI_READ: + + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) Address, + &Value32, BitWidth); + *Value = Value32; + break; + + case ACPI_WRITE: + + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) Address, + (UINT32) *Value, BitWidth); + break; + + default: + + Status = AE_BAD_PARAMETER; + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExPciConfigSpaceHandler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * BitWidth - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * HandlerContext - Pointer to Handler's context + * RegionContext - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the PCI Config address space (Op Region) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExPciConfigSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PCI_ID *PciId; + UINT16 PciRegister; + + + ACPI_FUNCTION_TRACE (ExPciConfigSpaceHandler); + + + /* + * The arguments to AcpiOs(Read|Write)PciConfiguration are: + * + * PciSegment is the PCI bus segment range 0-31 + * PciBus is the PCI bus number range 0-255 + * PciDevice is the PCI device number range 0-31 + * PciFunction is the PCI device function number + * PciRegister is the Config space register range 0-255 bytes + * + * Value - input value for write, output address for read + * + */ + PciId = (ACPI_PCI_ID *) RegionContext; + PciRegister = (UINT16) (UINT32) Address; + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Pci-Config %u (%u) Seg(%04x) Bus(%04x) " + "Dev(%04x) Func(%04x) Reg(%04x)\n", + Function, BitWidth, PciId->Segment, PciId->Bus, PciId->Device, + PciId->Function, PciRegister)); + + switch (Function) + { + case ACPI_READ: + + *Value = 0; + Status = AcpiOsReadPciConfiguration ( + PciId, PciRegister, Value, BitWidth); + break; + + case ACPI_WRITE: + + Status = AcpiOsWritePciConfiguration ( + PciId, PciRegister, *Value, BitWidth); + break; + + default: + + Status = AE_BAD_PARAMETER; + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExCmosSpaceHandler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * BitWidth - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * HandlerContext - Pointer to Handler's context + * RegionContext - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the CMOS address space (Op Region) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExCmosSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExCmosSpaceHandler); + + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExPciBarSpaceHandler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * BitWidth - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * HandlerContext - Pointer to Handler's context + * RegionContext - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the PCI BarTarget address space (Op Region) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExPciBarSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExPciBarSpaceHandler); + + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDataTableSpaceHandler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * BitWidth - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * HandlerContext - Pointer to Handler's context + * RegionContext - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the Data Table address space (Op Region) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExDataTableSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + ACPI_FUNCTION_TRACE (ExDataTableSpaceHandler); + + + /* + * Perform the memory read or write. The BitWidth was already + * validated. + */ + switch (Function) + { + case ACPI_READ: + + memcpy (ACPI_CAST_PTR (char, Value), ACPI_PHYSADDR_TO_PTR (Address), + ACPI_DIV_8 (BitWidth)); + break; + + case ACPI_WRITE: + + memcpy (ACPI_PHYSADDR_TO_PTR (Address), ACPI_CAST_PTR (char, Value), + ACPI_DIV_8 (BitWidth)); + break; + + default: + + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/executer/exresnte.c b/third_party/lib/acpica/source/components/executer/exresnte.c new file mode 100644 index 000000000..9a85450de --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exresnte.c @@ -0,0 +1,292 @@ +/****************************************************************************** + * + * Module Name: exresnte - AML Interpreter object resolution + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exresnte") + + +/******************************************************************************* + * + * FUNCTION: AcpiExResolveNodeToValue + * + * PARAMETERS: ObjectPtr - Pointer to a location that contains + * a pointer to a NS node, and will receive a + * pointer to the resolved object. + * WalkState - Current state. Valid only if executing AML + * code. NULL if simply resolving an object + * + * RETURN: Status + * + * DESCRIPTION: Resolve a Namespace node to a valued object + * + * Note: for some of the data types, the pointer attached to the Node + * can be either a pointer to an actual internal object or a pointer into the + * AML stream itself. These types are currently: + * + * ACPI_TYPE_INTEGER + * ACPI_TYPE_STRING + * ACPI_TYPE_BUFFER + * ACPI_TYPE_MUTEX + * ACPI_TYPE_PACKAGE + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExResolveNodeToValue ( + ACPI_NAMESPACE_NODE **ObjectPtr, + ACPI_WALK_STATE *WalkState) + +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *SourceDesc; + ACPI_OPERAND_OBJECT *ObjDesc = NULL; + ACPI_NAMESPACE_NODE *Node; + ACPI_OBJECT_TYPE EntryType; + + + ACPI_FUNCTION_TRACE (ExResolveNodeToValue); + + + /* + * The stack pointer points to a ACPI_NAMESPACE_NODE (Node). Get the + * object that is attached to the Node. + */ + Node = *ObjectPtr; + SourceDesc = AcpiNsGetAttachedObject (Node); + EntryType = AcpiNsGetType ((ACPI_HANDLE) Node); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p SourceDesc=%p [%s]\n", + Node, SourceDesc, AcpiUtGetTypeName (EntryType))); + + if ((EntryType == ACPI_TYPE_LOCAL_ALIAS) || + (EntryType == ACPI_TYPE_LOCAL_METHOD_ALIAS)) + { + /* There is always exactly one level of indirection */ + + Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Node->Object); + SourceDesc = AcpiNsGetAttachedObject (Node); + EntryType = AcpiNsGetType ((ACPI_HANDLE) Node); + *ObjectPtr = Node; + } + + /* + * Several object types require no further processing: + * 1) Device/Thermal objects don't have a "real" subobject, return Node + * 2) Method locals and arguments have a pseudo-Node + * 3) 10/2007: Added method type to assist with Package construction. + */ + if ((EntryType == ACPI_TYPE_DEVICE) || + (EntryType == ACPI_TYPE_THERMAL) || + (EntryType == ACPI_TYPE_METHOD) || + (Node->Flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) + { + return_ACPI_STATUS (AE_OK); + } + + if (!SourceDesc) + { + ACPI_ERROR ((AE_INFO, "No object attached to node [%4.4s] %p", + Node->Name.Ascii, Node)); + return_ACPI_STATUS (AE_AML_UNINITIALIZED_NODE); + } + + /* + * Action is based on the type of the Node, which indicates the type + * of the attached object or pointer + */ + switch (EntryType) + { + case ACPI_TYPE_PACKAGE: + + if (SourceDesc->Common.Type != ACPI_TYPE_PACKAGE) + { + ACPI_ERROR ((AE_INFO, "Object not a Package, type %s", + AcpiUtGetObjectTypeName (SourceDesc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + Status = AcpiDsGetPackageArguments (SourceDesc); + if (ACPI_SUCCESS (Status)) + { + /* Return an additional reference to the object */ + + ObjDesc = SourceDesc; + AcpiUtAddReference (ObjDesc); + } + break; + + case ACPI_TYPE_BUFFER: + + if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) + { + ACPI_ERROR ((AE_INFO, "Object not a Buffer, type %s", + AcpiUtGetObjectTypeName (SourceDesc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + Status = AcpiDsGetBufferArguments (SourceDesc); + if (ACPI_SUCCESS (Status)) + { + /* Return an additional reference to the object */ + + ObjDesc = SourceDesc; + AcpiUtAddReference (ObjDesc); + } + break; + + case ACPI_TYPE_STRING: + + if (SourceDesc->Common.Type != ACPI_TYPE_STRING) + { + ACPI_ERROR ((AE_INFO, "Object not a String, type %s", + AcpiUtGetObjectTypeName (SourceDesc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Return an additional reference to the object */ + + ObjDesc = SourceDesc; + AcpiUtAddReference (ObjDesc); + break; + + case ACPI_TYPE_INTEGER: + + if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER) + { + ACPI_ERROR ((AE_INFO, "Object not a Integer, type %s", + AcpiUtGetObjectTypeName (SourceDesc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Return an additional reference to the object */ + + ObjDesc = SourceDesc; + AcpiUtAddReference (ObjDesc); + break; + + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "FieldRead Node=%p SourceDesc=%p Type=%X\n", + Node, SourceDesc, EntryType)); + + Status = AcpiExReadDataFromField (WalkState, SourceDesc, &ObjDesc); + break; + + /* For these objects, just return the object attached to the Node */ + + case ACPI_TYPE_MUTEX: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_EVENT: + case ACPI_TYPE_REGION: + + /* Return an additional reference to the object */ + + ObjDesc = SourceDesc; + AcpiUtAddReference (ObjDesc); + break; + + /* TYPE_ANY is untyped, and thus there is no object associated with it */ + + case ACPI_TYPE_ANY: + + ACPI_ERROR ((AE_INFO, + "Untyped entry %p, no attached object!", Node)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ + + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (SourceDesc->Reference.Class) + { + case ACPI_REFCLASS_TABLE: /* This is a DdbHandle */ + case ACPI_REFCLASS_REFOF: + case ACPI_REFCLASS_INDEX: + + /* Return an additional reference to the object */ + + ObjDesc = SourceDesc; + AcpiUtAddReference (ObjDesc); + break; + + default: + + /* No named references are allowed here */ + + ACPI_ERROR ((AE_INFO, + "Unsupported Reference type 0x%X", + SourceDesc->Reference.Class)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + break; + + default: + + /* Default case is for unknown types */ + + ACPI_ERROR ((AE_INFO, + "Node %p - Unknown object type 0x%X", + Node, EntryType)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + + } /* switch (EntryType) */ + + + /* Return the object descriptor */ + + *ObjectPtr = (void *) ObjDesc; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exresolv.c b/third_party/lib/acpica/source/components/executer/exresolv.c new file mode 100644 index 000000000..4b6202f4f --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exresolv.c @@ -0,0 +1,579 @@ +/****************************************************************************** + * + * Module Name: exresolv - AML Interpreter object resolution + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exresolv") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiExResolveObjectToValue ( + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState); + + +/******************************************************************************* + * + * FUNCTION: AcpiExResolveToValue + * + * PARAMETERS: **StackPtr - Points to entry on ObjStack, which can + * be either an (ACPI_OPERAND_OBJECT *) + * or an ACPI_HANDLE. + * WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Convert Reference objects to values + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExResolveToValue ( + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (ExResolveToValue, StackPtr); + + + if (!StackPtr || !*StackPtr) + { + ACPI_ERROR ((AE_INFO, "Internal - null pointer")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* + * The entity pointed to by the StackPtr can be either + * 1) A valid ACPI_OPERAND_OBJECT, or + * 2) A ACPI_NAMESPACE_NODE (NamedObj) + */ + if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_OPERAND) + { + Status = AcpiExResolveObjectToValue (StackPtr, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (!*StackPtr) + { + ACPI_ERROR ((AE_INFO, "Internal - null pointer")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + } + + /* + * Object on the stack may have changed if AcpiExResolveObjectToValue() + * was called (i.e., we can't use an _else_ here.) + */ + if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_NAMED) + { + Status = AcpiExResolveNodeToValue ( + ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, StackPtr), + WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *StackPtr)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExResolveObjectToValue + * + * PARAMETERS: StackPtr - Pointer to an internal object + * WalkState - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Retrieve the value from an internal object. The Reference type + * uses the associated AML opcode to determine the value. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExResolveObjectToValue ( + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *StackDesc; + ACPI_OPERAND_OBJECT *ObjDesc = NULL; + UINT8 RefType; + + + ACPI_FUNCTION_TRACE (ExResolveObjectToValue); + + + StackDesc = *StackPtr; + + /* This is an object of type ACPI_OPERAND_OBJECT */ + + switch (StackDesc->Common.Type) + { + case ACPI_TYPE_LOCAL_REFERENCE: + + RefType = StackDesc->Reference.Class; + + switch (RefType) + { + case ACPI_REFCLASS_LOCAL: + case ACPI_REFCLASS_ARG: + /* + * Get the local from the method's state info + * Note: this increments the local's object reference count + */ + Status = AcpiDsMethodDataGetValue (RefType, + StackDesc->Reference.Value, WalkState, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] ValueObj is %p\n", + StackDesc->Reference.Value, ObjDesc)); + + /* + * Now we can delete the original Reference Object and + * replace it with the resolved value + */ + AcpiUtRemoveReference (StackDesc); + *StackPtr = ObjDesc; + break; + + case ACPI_REFCLASS_INDEX: + + switch (StackDesc->Reference.TargetType) + { + case ACPI_TYPE_BUFFER_FIELD: + + /* Just return - do not dereference */ + break; + + case ACPI_TYPE_PACKAGE: + + /* If method call or CopyObject - do not dereference */ + + if ((WalkState->Opcode == AML_INT_METHODCALL_OP) || + (WalkState->Opcode == AML_COPY_OP)) + { + break; + } + + /* Otherwise, dereference the PackageIndex to a package element */ + + ObjDesc = *StackDesc->Reference.Where; + if (ObjDesc) + { + /* + * Valid object descriptor, copy pointer to return value + * (i.e., dereference the package index) + * Delete the ref object, increment the returned object + */ + AcpiUtAddReference (ObjDesc); + *StackPtr = ObjDesc; + } + else + { + /* + * A NULL object descriptor means an uninitialized element of + * the package, can't dereference it + */ + ACPI_ERROR ((AE_INFO, + "Attempt to dereference an Index to " + "NULL package element Idx=%p", + StackDesc)); + Status = AE_AML_UNINITIALIZED_ELEMENT; + } + break; + + default: + + /* Invalid reference object */ + + ACPI_ERROR ((AE_INFO, + "Unknown TargetType 0x%X in Index/Reference object %p", + StackDesc->Reference.TargetType, StackDesc)); + Status = AE_AML_INTERNAL; + break; + } + break; + + case ACPI_REFCLASS_REFOF: + case ACPI_REFCLASS_DEBUG: + case ACPI_REFCLASS_TABLE: + + /* Just leave the object as-is, do not dereference */ + + break; + + case ACPI_REFCLASS_NAME: /* Reference to a named object */ + + /* Dereference the name */ + + if ((StackDesc->Reference.Node->Type == ACPI_TYPE_DEVICE) || + (StackDesc->Reference.Node->Type == ACPI_TYPE_THERMAL)) + { + /* These node types do not have 'real' subobjects */ + + *StackPtr = (void *) StackDesc->Reference.Node; + } + else + { + /* Get the object pointed to by the namespace node */ + + *StackPtr = (StackDesc->Reference.Node)->Object; + AcpiUtAddReference (*StackPtr); + } + + AcpiUtRemoveReference (StackDesc); + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown Reference type 0x%X in %p", + RefType, StackDesc)); + Status = AE_AML_INTERNAL; + break; + } + break; + + case ACPI_TYPE_BUFFER: + + Status = AcpiDsGetBufferArguments (StackDesc); + break; + + case ACPI_TYPE_PACKAGE: + + Status = AcpiDsGetPackageArguments (StackDesc); + break; + + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "FieldRead SourceDesc=%p Type=%X\n", + StackDesc, StackDesc->Common.Type)); + + Status = AcpiExReadDataFromField (WalkState, StackDesc, &ObjDesc); + + /* Remove a reference to the original operand, then override */ + + AcpiUtRemoveReference (*StackPtr); + *StackPtr = (void *) ObjDesc; + break; + + default: + + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExResolveMultiple + * + * PARAMETERS: WalkState - Current state (contains AML opcode) + * Operand - Starting point for resolution + * ReturnType - Where the object type is returned + * ReturnDesc - Where the resolved object is returned + * + * RETURN: Status + * + * DESCRIPTION: Return the base object and type. Traverse a reference list if + * necessary to get to the base object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExResolveMultiple ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *Operand, + ACPI_OBJECT_TYPE *ReturnType, + ACPI_OPERAND_OBJECT **ReturnDesc) +{ + ACPI_OPERAND_OBJECT *ObjDesc = ACPI_CAST_PTR (void, Operand); + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Operand); + ACPI_OBJECT_TYPE Type; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiExResolveMultiple); + + + /* Operand can be either a namespace node or an operand descriptor */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) + { + case ACPI_DESC_TYPE_OPERAND: + + Type = ObjDesc->Common.Type; + break; + + case ACPI_DESC_TYPE_NAMED: + + Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type; + ObjDesc = AcpiNsGetAttachedObject (Node); + + /* If we had an Alias node, use the attached object for type info */ + + if (Type == ACPI_TYPE_LOCAL_ALIAS) + { + Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type; + ObjDesc = AcpiNsGetAttachedObject ( + (ACPI_NAMESPACE_NODE *) ObjDesc); + } + + if (!ObjDesc) + { + ACPI_ERROR ((AE_INFO, + "[%4.4s] Node is unresolved or uninitialized", + AcpiUtGetNodeName (Node))); + return_ACPI_STATUS (AE_AML_UNINITIALIZED_NODE); + } + break; + + default: + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* If type is anything other than a reference, we are done */ + + if (Type != ACPI_TYPE_LOCAL_REFERENCE) + { + goto Exit; + } + + /* + * For reference objects created via the RefOf, Index, or Load/LoadTable + * operators, we need to get to the base object (as per the ACPI + * specification of the ObjectType and SizeOf operators). This means + * traversing the list of possibly many nested references. + */ + while (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) + { + switch (ObjDesc->Reference.Class) + { + case ACPI_REFCLASS_REFOF: + case ACPI_REFCLASS_NAME: + + /* Dereference the reference pointer */ + + if (ObjDesc->Reference.Class == ACPI_REFCLASS_REFOF) + { + Node = ObjDesc->Reference.Object; + } + else /* AML_INT_NAMEPATH_OP */ + { + Node = ObjDesc->Reference.Node; + } + + /* All "References" point to a NS node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) + { + ACPI_ERROR ((AE_INFO, + "Not a namespace node %p [%s]", + Node, AcpiUtGetDescriptorName (Node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Get the attached object */ + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + /* No object, use the NS node type */ + + Type = AcpiNsGetType (Node); + goto Exit; + } + + /* Check for circular references */ + + if (ObjDesc == Operand) + { + return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE); + } + break; + + case ACPI_REFCLASS_INDEX: + + /* Get the type of this reference (index into another object) */ + + Type = ObjDesc->Reference.TargetType; + if (Type != ACPI_TYPE_PACKAGE) + { + goto Exit; + } + + /* + * The main object is a package, we want to get the type + * of the individual package element that is referenced by + * the index. + * + * This could of course in turn be another reference object. + */ + ObjDesc = *(ObjDesc->Reference.Where); + if (!ObjDesc) + { + /* NULL package elements are allowed */ + + Type = 0; /* Uninitialized */ + goto Exit; + } + break; + + case ACPI_REFCLASS_TABLE: + + Type = ACPI_TYPE_DDB_HANDLE; + goto Exit; + + case ACPI_REFCLASS_LOCAL: + case ACPI_REFCLASS_ARG: + + if (ReturnDesc) + { + Status = AcpiDsMethodDataGetValue (ObjDesc->Reference.Class, + ObjDesc->Reference.Value, WalkState, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + AcpiUtRemoveReference (ObjDesc); + } + else + { + Status = AcpiDsMethodDataGetNode (ObjDesc->Reference.Class, + ObjDesc->Reference.Value, WalkState, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + Type = ACPI_TYPE_ANY; + goto Exit; + } + } + break; + + case ACPI_REFCLASS_DEBUG: + + /* The Debug Object is of type "DebugObject" */ + + Type = ACPI_TYPE_DEBUG_OBJECT; + goto Exit; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown Reference Class 0x%2.2X", + ObjDesc->Reference.Class)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + } + + /* + * Now we are guaranteed to have an object that has not been created + * via the RefOf or Index operators. + */ + Type = ObjDesc->Common.Type; + + +Exit: + /* Convert internal types to external types */ + + switch (Type) + { + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + Type = ACPI_TYPE_FIELD_UNIT; + break; + + case ACPI_TYPE_LOCAL_SCOPE: + + /* Per ACPI Specification, Scope is untyped */ + + Type = ACPI_TYPE_ANY; + break; + + default: + + /* No change to Type required */ + + break; + } + + *ReturnType = Type; + if (ReturnDesc) + { + *ReturnDesc = ObjDesc; + } + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/executer/exresop.c b/third_party/lib/acpica/source/components/executer/exresop.c new file mode 100644 index 000000000..32ceb6f02 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exresop.c @@ -0,0 +1,730 @@ +/****************************************************************************** + * + * Module Name: exresop - AML Interpreter operand/object resolution + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exresop") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiExCheckObjectType ( + ACPI_OBJECT_TYPE TypeNeeded, + ACPI_OBJECT_TYPE ThisType, + void *Object); + + +/******************************************************************************* + * + * FUNCTION: AcpiExCheckObjectType + * + * PARAMETERS: TypeNeeded Object type needed + * ThisType Actual object type + * Object Object pointer + * + * RETURN: Status + * + * DESCRIPTION: Check required type against actual type + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExCheckObjectType ( + ACPI_OBJECT_TYPE TypeNeeded, + ACPI_OBJECT_TYPE ThisType, + void *Object) +{ + ACPI_FUNCTION_ENTRY (); + + + if (TypeNeeded == ACPI_TYPE_ANY) + { + /* All types OK, so we don't perform any typechecks */ + + return (AE_OK); + } + + if (TypeNeeded == ACPI_TYPE_LOCAL_REFERENCE) + { + /* + * Allow the AML "Constant" opcodes (Zero, One, etc.) to be reference + * objects and thus allow them to be targets. (As per the ACPI + * specification, a store to a constant is a noop.) + */ + if ((ThisType == ACPI_TYPE_INTEGER) && + (((ACPI_OPERAND_OBJECT *) Object)->Common.Flags & + AOPOBJ_AML_CONSTANT)) + { + return (AE_OK); + } + } + + if (TypeNeeded != ThisType) + { + ACPI_ERROR ((AE_INFO, + "Needed type [%s], found [%s] %p", + AcpiUtGetTypeName (TypeNeeded), + AcpiUtGetTypeName (ThisType), Object)); + + return (AE_AML_OPERAND_TYPE); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExResolveOperands + * + * PARAMETERS: Opcode - Opcode being interpreted + * StackPtr - Pointer to the operand stack to be + * resolved + * WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Convert multiple input operands to the types required by the + * target operator. + * + * Each 5-bit group in ArgTypes represents one required + * operand and indicates the required Type. The corresponding operand + * will be converted to the required type if possible, otherwise we + * abort with an exception. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExResolveOperands ( + UINT16 Opcode, + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status = AE_OK; + UINT8 ObjectType; + UINT32 ArgTypes; + const ACPI_OPCODE_INFO *OpInfo; + UINT32 ThisArgType; + ACPI_OBJECT_TYPE TypeNeeded; + UINT16 TargetOp = 0; + + + ACPI_FUNCTION_TRACE_U32 (ExResolveOperands, Opcode); + + + OpInfo = AcpiPsGetOpcodeInfo (Opcode); + if (OpInfo->Class == AML_CLASS_UNKNOWN) + { + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + ArgTypes = OpInfo->RuntimeArgs; + if (ArgTypes == ARGI_INVALID_OPCODE) + { + ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", + Opcode)); + + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Opcode %X [%s] RequiredOperandTypes=%8.8X\n", + Opcode, OpInfo->Name, ArgTypes)); + + /* + * Normal exit is with (ArgTypes == 0) at end of argument list. + * Function will return an exception from within the loop upon + * finding an entry which is not (or cannot be converted + * to) the required type; if stack underflows; or upon + * finding a NULL stack entry (which should not happen). + */ + while (GET_CURRENT_ARG_TYPE (ArgTypes)) + { + if (!StackPtr || !*StackPtr) + { + ACPI_ERROR ((AE_INFO, "Null stack entry at %p", + StackPtr)); + + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Extract useful items */ + + ObjDesc = *StackPtr; + + /* Decode the descriptor type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) + { + case ACPI_DESC_TYPE_NAMED: + + /* Namespace Node */ + + ObjectType = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type; + + /* + * Resolve an alias object. The construction of these objects + * guarantees that there is only one level of alias indirection; + * thus, the attached object is always the aliased namespace node + */ + if (ObjectType == ACPI_TYPE_LOCAL_ALIAS) + { + ObjDesc = AcpiNsGetAttachedObject ( + (ACPI_NAMESPACE_NODE *) ObjDesc); + *StackPtr = ObjDesc; + ObjectType = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type; + } + break; + + case ACPI_DESC_TYPE_OPERAND: + + /* ACPI internal object */ + + ObjectType = ObjDesc->Common.Type; + + /* Check for bad ACPI_OBJECT_TYPE */ + + if (!AcpiUtValidObjectType (ObjectType)) + { + ACPI_ERROR ((AE_INFO, + "Bad operand object type [0x%X]", ObjectType)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + if (ObjectType == (UINT8) ACPI_TYPE_LOCAL_REFERENCE) + { + /* Validate the Reference */ + + switch (ObjDesc->Reference.Class) + { + case ACPI_REFCLASS_DEBUG: + + TargetOp = AML_DEBUG_OP; + + /*lint -fallthrough */ + + case ACPI_REFCLASS_ARG: + case ACPI_REFCLASS_LOCAL: + case ACPI_REFCLASS_INDEX: + case ACPI_REFCLASS_REFOF: + case ACPI_REFCLASS_TABLE: /* DdbHandle from LOAD_OP or LOAD_TABLE_OP */ + case ACPI_REFCLASS_NAME: /* Reference to a named object */ + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Operand is a Reference, Class [%s] %2.2X\n", + AcpiUtGetReferenceName (ObjDesc), + ObjDesc->Reference.Class)); + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Unknown Reference Class 0x%2.2X in %p", + ObjDesc->Reference.Class, ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + } + break; + + default: + + /* Invalid descriptor */ + + ACPI_ERROR ((AE_INFO, "Invalid descriptor %p [%s]", + ObjDesc, AcpiUtGetDescriptorName (ObjDesc))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Get one argument type, point to the next */ + + ThisArgType = GET_CURRENT_ARG_TYPE (ArgTypes); + INCREMENT_ARG_LIST (ArgTypes); + + /* + * Handle cases where the object does not need to be + * resolved to a value + */ + switch (ThisArgType) + { + case ARGI_REF_OR_STRING: /* Can be a String or Reference */ + + if ((ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == + ACPI_DESC_TYPE_OPERAND) && + (ObjDesc->Common.Type == ACPI_TYPE_STRING)) + { + /* + * String found - the string references a named object and + * must be resolved to a node + */ + goto NextOperand; + } + + /* + * Else not a string - fall through to the normal Reference + * case below + */ + /*lint -fallthrough */ + + case ARGI_REFERENCE: /* References: */ + case ARGI_INTEGER_REF: + case ARGI_OBJECT_REF: + case ARGI_DEVICE_REF: + case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ + case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ + case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ + case ARGI_STORE_TARGET: + + /* + * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE + * A Namespace Node is OK as-is + */ + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_NAMED) + { + goto NextOperand; + } + + Status = AcpiExCheckObjectType ( + ACPI_TYPE_LOCAL_REFERENCE, ObjectType, ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + goto NextOperand; + + case ARGI_DATAREFOBJ: /* Store operator only */ + /* + * We don't want to resolve IndexOp reference objects during + * a store because this would be an implicit DeRefOf operation. + * Instead, we just want to store the reference object. + * -- All others must be resolved below. + */ + if ((Opcode == AML_STORE_OP) && + ((*StackPtr)->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) && + ((*StackPtr)->Reference.Class == ACPI_REFCLASS_INDEX)) + { + goto NextOperand; + } + break; + + default: + + /* All cases covered above */ + + break; + } + + /* + * Resolve this object to a value + */ + Status = AcpiExResolveToValue (StackPtr, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get the resolved object */ + + ObjDesc = *StackPtr; + + /* + * Check the resulting object (value) type + */ + switch (ThisArgType) + { + /* + * For the simple cases, only one type of resolved object + * is allowed + */ + case ARGI_MUTEX: + + /* Need an operand of type ACPI_TYPE_MUTEX */ + + TypeNeeded = ACPI_TYPE_MUTEX; + break; + + case ARGI_EVENT: + + /* Need an operand of type ACPI_TYPE_EVENT */ + + TypeNeeded = ACPI_TYPE_EVENT; + break; + + case ARGI_PACKAGE: /* Package */ + + /* Need an operand of type ACPI_TYPE_PACKAGE */ + + TypeNeeded = ACPI_TYPE_PACKAGE; + break; + + case ARGI_ANYTYPE: + + /* Any operand type will do */ + + TypeNeeded = ACPI_TYPE_ANY; + break; + + case ARGI_DDBHANDLE: + + /* Need an operand of type ACPI_TYPE_DDB_HANDLE */ + + TypeNeeded = ACPI_TYPE_LOCAL_REFERENCE; + break; + + + /* + * The more complex cases allow multiple resolved object types + */ + case ARGI_INTEGER: + + /* + * Need an operand of type ACPI_TYPE_INTEGER, + * But we can implicitly convert from a STRING or BUFFER + * Aka - "Implicit Source Operand Conversion" + */ + Status = AcpiExConvertToInteger (ObjDesc, StackPtr, 16); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_TYPE) + { + ACPI_ERROR ((AE_INFO, + "Needed [Integer/String/Buffer], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + return_ACPI_STATUS (Status); + } + + if (ObjDesc != *StackPtr) + { + AcpiUtRemoveReference (ObjDesc); + } + goto NextOperand; + + case ARGI_BUFFER: + /* + * Need an operand of type ACPI_TYPE_BUFFER, + * But we can implicitly convert from a STRING or INTEGER + * Aka - "Implicit Source Operand Conversion" + */ + Status = AcpiExConvertToBuffer (ObjDesc, StackPtr); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_TYPE) + { + ACPI_ERROR ((AE_INFO, + "Needed [Integer/String/Buffer], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + return_ACPI_STATUS (Status); + } + + if (ObjDesc != *StackPtr) + { + AcpiUtRemoveReference (ObjDesc); + } + goto NextOperand; + + case ARGI_STRING: + /* + * Need an operand of type ACPI_TYPE_STRING, + * But we can implicitly convert from a BUFFER or INTEGER + * Aka - "Implicit Source Operand Conversion" + */ + Status = AcpiExConvertToString ( + ObjDesc, StackPtr, ACPI_IMPLICIT_CONVERT_HEX); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_TYPE) + { + ACPI_ERROR ((AE_INFO, + "Needed [Integer/String/Buffer], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + return_ACPI_STATUS (Status); + } + + if (ObjDesc != *StackPtr) + { + AcpiUtRemoveReference (ObjDesc); + } + goto NextOperand; + + case ARGI_COMPUTEDATA: + + /* Need an operand of type INTEGER, STRING or BUFFER */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + ACPI_ERROR ((AE_INFO, + "Needed [Integer/String/Buffer], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto NextOperand; + + case ARGI_BUFFER_OR_STRING: + + /* Need an operand of type STRING or BUFFER */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + case ACPI_TYPE_INTEGER: + + /* Highest priority conversion is to type Buffer */ + + Status = AcpiExConvertToBuffer (ObjDesc, StackPtr); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (ObjDesc != *StackPtr) + { + AcpiUtRemoveReference (ObjDesc); + } + break; + + default: + ACPI_ERROR ((AE_INFO, + "Needed [Integer/String/Buffer], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto NextOperand; + + case ARGI_DATAOBJECT: + /* + * ARGI_DATAOBJECT is only used by the SizeOf operator. + * Need a buffer, string, package, or RefOf reference. + * + * The only reference allowed here is a direct reference to + * a namespace node. + */ + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_LOCAL_REFERENCE: + + /* Valid operand */ + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Needed [Buffer/String/Package/Reference], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto NextOperand; + + case ARGI_COMPLEXOBJ: + + /* Need a buffer or package or (ACPI 2.0) String */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Needed [Buffer/String/Package], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto NextOperand; + + case ARGI_REGION_OR_BUFFER: /* Used by Load() only */ + + /* + * Need an operand of type REGION or a BUFFER + * (which could be a resolved region field) + */ + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_REGION: + + /* Valid operand */ + break; + + default: + + ACPI_ERROR ((AE_INFO, + "Needed [Region/Buffer], found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto NextOperand; + + case ARGI_DATAREFOBJ: + + /* Used by the Store() operator only */ + + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REFERENCE: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + case ACPI_TYPE_DDB_HANDLE: + + /* Valid operand */ + break; + + default: + + if (AcpiGbl_EnableInterpreterSlack) + { + /* + * Enable original behavior of Store(), allowing any + * and all objects as the source operand. The ACPI + * spec does not allow this, however. + */ + break; + } + + if (TargetOp == AML_DEBUG_OP) + { + /* Allow store of any object to the Debug object */ + + break; + } + + ACPI_ERROR ((AE_INFO, + "Needed Integer/Buffer/String/Package/Ref/Ddb]" + ", found [%s] %p", + AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto NextOperand; + + default: + + /* Unknown type */ + + ACPI_ERROR ((AE_INFO, + "Internal - Unknown ARGI (required operand) type 0x%X", + ThisArgType)); + + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Make sure that the original object was resolved to the + * required object type (Simple cases only). + */ + Status = AcpiExCheckObjectType ( + TypeNeeded, (*StackPtr)->Common.Type, *StackPtr); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + +NextOperand: + /* + * If more operands needed, decrement StackPtr to point + * to next operand on stack + */ + if (GET_CURRENT_ARG_TYPE (ArgTypes)) + { + StackPtr--; + } + } + + ACPI_DUMP_OPERANDS (WalkState->Operands, + AcpiPsGetOpcodeName (Opcode), WalkState->NumOperands); + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exstore.c b/third_party/lib/acpica/source/components/executer/exstore.c new file mode 100644 index 000000000..cb18c036c --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exstore.c @@ -0,0 +1,644 @@ +/****************************************************************************** + * + * Module Name: exstore - AML Interpreter object store support + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exstore") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiExStoreObjectToIndex ( + ACPI_OPERAND_OBJECT *ValDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_WALK_STATE *WalkState); + +static ACPI_STATUS +AcpiExStoreDirectToNode ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node, + ACPI_WALK_STATE *WalkState); + + +/******************************************************************************* + * + * FUNCTION: AcpiExStore + * + * PARAMETERS: *SourceDesc - Value to be stored + * *DestDesc - Where to store it. Must be an NS node + * or ACPI_OPERAND_OBJECT of type + * Reference; + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Store the value described by SourceDesc into the location + * described by DestDesc. Called by various interpreter + * functions to store the result of an operation into + * the destination operand -- not just simply the actual "Store" + * ASL operator. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExStore ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *RefDesc = DestDesc; + + + ACPI_FUNCTION_TRACE_PTR (ExStore, DestDesc); + + + /* Validate parameters */ + + if (!SourceDesc || !DestDesc) + { + ACPI_ERROR ((AE_INFO, "Null parameter")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* DestDesc can be either a namespace node or an ACPI object */ + + if (ACPI_GET_DESCRIPTOR_TYPE (DestDesc) == ACPI_DESC_TYPE_NAMED) + { + /* + * Dest is a namespace node, + * Storing an object into a Named node. + */ + Status = AcpiExStoreObjectToNode (SourceDesc, + (ACPI_NAMESPACE_NODE *) DestDesc, WalkState, + ACPI_IMPLICIT_CONVERSION); + + return_ACPI_STATUS (Status); + } + + /* Destination object must be a Reference or a Constant object */ + + switch (DestDesc->Common.Type) + { + case ACPI_TYPE_LOCAL_REFERENCE: + + break; + + case ACPI_TYPE_INTEGER: + + /* Allow stores to Constants -- a Noop as per ACPI spec */ + + if (DestDesc->Common.Flags & AOPOBJ_AML_CONSTANT) + { + return_ACPI_STATUS (AE_OK); + } + + /*lint -fallthrough */ + + default: + + /* Destination is not a Reference object */ + + ACPI_ERROR ((AE_INFO, + "Target is not a Reference or Constant object - [%s] %p", + AcpiUtGetObjectTypeName (DestDesc), DestDesc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * Examine the Reference class. These cases are handled: + * + * 1) Store to Name (Change the object associated with a name) + * 2) Store to an indexed area of a Buffer or Package + * 3) Store to a Method Local or Arg + * 4) Store to the debug object + */ + switch (RefDesc->Reference.Class) + { + case ACPI_REFCLASS_REFOF: + + /* Storing an object into a Name "container" */ + + Status = AcpiExStoreObjectToNode (SourceDesc, + RefDesc->Reference.Object, + WalkState, ACPI_IMPLICIT_CONVERSION); + break; + + case ACPI_REFCLASS_INDEX: + + /* Storing to an Index (pointer into a packager or buffer) */ + + Status = AcpiExStoreObjectToIndex (SourceDesc, RefDesc, WalkState); + break; + + case ACPI_REFCLASS_LOCAL: + case ACPI_REFCLASS_ARG: + + /* Store to a method local/arg */ + + Status = AcpiDsStoreObjectToLocal (RefDesc->Reference.Class, + RefDesc->Reference.Value, SourceDesc, WalkState); + break; + + case ACPI_REFCLASS_DEBUG: + /* + * Storing to the Debug object causes the value stored to be + * displayed and otherwise has no effect -- see ACPI Specification + */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "**** Write to Debug Object: Object %p [%s] ****:\n\n", + SourceDesc, AcpiUtGetObjectTypeName (SourceDesc))); + + ACPI_DEBUG_OBJECT (SourceDesc, 0, 0); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X", + RefDesc->Reference.Class)); + ACPI_DUMP_ENTRY (RefDesc, ACPI_LV_INFO); + + Status = AE_AML_INTERNAL; + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStoreObjectToIndex + * + * PARAMETERS: *SourceDesc - Value to be stored + * *DestDesc - Named object to receive the value + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Store the object to indexed Buffer or Package element + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExStoreObjectToIndex ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *IndexDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *NewDesc; + UINT8 Value = 0; + UINT32 i; + + + ACPI_FUNCTION_TRACE (ExStoreObjectToIndex); + + + /* + * Destination must be a reference pointer, and + * must point to either a buffer or a package + */ + switch (IndexDesc->Reference.TargetType) + { + case ACPI_TYPE_PACKAGE: + /* + * Storing to a package element. Copy the object and replace + * any existing object with the new object. No implicit + * conversion is performed. + * + * The object at *(IndexDesc->Reference.Where) is the + * element within the package that is to be modified. + * The parent package object is at IndexDesc->Reference.Object + */ + ObjDesc = *(IndexDesc->Reference.Where); + + if (SourceDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE && + SourceDesc->Reference.Class == ACPI_REFCLASS_TABLE) + { + /* This is a DDBHandle, just add a reference to it */ + + AcpiUtAddReference (SourceDesc); + NewDesc = SourceDesc; + } + else + { + /* Normal object, copy it */ + + Status = AcpiUtCopyIobjectToIobject ( + SourceDesc, &NewDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + if (ObjDesc) + { + /* Decrement reference count by the ref count of the parent package */ + + for (i = 0; + i < ((ACPI_OPERAND_OBJECT *) + IndexDesc->Reference.Object)->Common.ReferenceCount; + i++) + { + AcpiUtRemoveReference (ObjDesc); + } + } + + *(IndexDesc->Reference.Where) = NewDesc; + + /* Increment ref count by the ref count of the parent package-1 */ + + for (i = 1; + i < ((ACPI_OPERAND_OBJECT *) + IndexDesc->Reference.Object)->Common.ReferenceCount; + i++) + { + AcpiUtAddReference (NewDesc); + } + + break; + + case ACPI_TYPE_BUFFER_FIELD: + /* + * Store into a Buffer or String (not actually a real BufferField) + * at a location defined by an Index. + * + * The first 8-bit element of the source object is written to the + * 8-bit Buffer location defined by the Index destination object, + * according to the ACPI 2.0 specification. + */ + + /* + * Make sure the target is a Buffer or String. An error should + * not happen here, since the ReferenceObject was constructed + * by the INDEX_OP code. + */ + ObjDesc = IndexDesc->Reference.Object; + if ((ObjDesc->Common.Type != ACPI_TYPE_BUFFER) && + (ObjDesc->Common.Type != ACPI_TYPE_STRING)) + { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * The assignment of the individual elements will be slightly + * different for each source type. + */ + switch (SourceDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + /* Use the least-significant byte of the integer */ + + Value = (UINT8) (SourceDesc->Integer.Value); + break; + + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + + /* Note: Takes advantage of common string/buffer fields */ + + Value = SourceDesc->Buffer.Pointer[0]; + break; + + default: + + /* All other types are invalid */ + + ACPI_ERROR ((AE_INFO, + "Source must be type [Integer/Buffer/String], found [%s]", + AcpiUtGetObjectTypeName (SourceDesc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Store the source value into the target buffer byte */ + + ObjDesc->Buffer.Pointer[IndexDesc->Reference.Value] = Value; + break; + + default: + ACPI_ERROR ((AE_INFO, + "Target is not of type [Package/BufferField]")); + Status = AE_AML_TARGET_TYPE; + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStoreObjectToNode + * + * PARAMETERS: SourceDesc - Value to be stored + * Node - Named object to receive the value + * WalkState - Current walk state + * ImplicitConversion - Perform implicit conversion (yes/no) + * + * RETURN: Status + * + * DESCRIPTION: Store the object to the named object. + * + * The assignment of an object to a named object is handled here. + * The value passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. A CopyObject can change + * the target type, however. + * + * The ImplicitConversion flag is set to NO/FALSE only when + * storing to an ArgX -- as per the rules of the ACPI spec. + * + * Assumes parameters are already validated. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExStoreObjectToNode ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node, + ACPI_WALK_STATE *WalkState, + UINT8 ImplicitConversion) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *TargetDesc; + ACPI_OPERAND_OBJECT *NewDesc; + ACPI_OBJECT_TYPE TargetType; + + + ACPI_FUNCTION_TRACE_PTR (ExStoreObjectToNode, SourceDesc); + + + /* Get current type of the node, and object attached to Node */ + + TargetType = AcpiNsGetType (Node); + TargetDesc = AcpiNsGetAttachedObject (Node); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n", + SourceDesc, AcpiUtGetObjectTypeName (SourceDesc), + Node, AcpiUtGetTypeName (TargetType))); + + /* Only limited target types possible for everything except CopyObject */ + + if (WalkState->Opcode != AML_COPY_OP) + { + /* + * Only CopyObject allows all object types to be overwritten. For + * TargetRef(s), there are restrictions on the object types that + * are allowed. + * + * Allowable operations/typing for Store: + * + * 1) Simple Store + * Integer --> Integer (Named/Local/Arg) + * String --> String (Named/Local/Arg) + * Buffer --> Buffer (Named/Local/Arg) + * Package --> Package (Named/Local/Arg) + * + * 2) Store with implicit conversion + * Integer --> String or Buffer (Named) + * String --> Integer or Buffer (Named) + * Buffer --> Integer or String (Named) + */ + switch (TargetType) + { + case ACPI_TYPE_PACKAGE: + /* + * Here, can only store a package to an existing package. + * Storing a package to a Local/Arg is OK, and handled + * elsewhere. + */ + if (WalkState->Opcode == AML_STORE_OP) + { + if (SourceDesc->Common.Type != ACPI_TYPE_PACKAGE) + { + ACPI_ERROR ((AE_INFO, + "Cannot assign type [%s] to [Package] " + "(source must be type Pkg)", + AcpiUtGetObjectTypeName (SourceDesc))); + + return_ACPI_STATUS (AE_AML_TARGET_TYPE); + } + break; + } + + /* Fallthrough */ + + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_EVENT: + case ACPI_TYPE_MUTEX: + case ACPI_TYPE_REGION: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + ACPI_ERROR ((AE_INFO, + "Target must be [Buffer/Integer/String/Reference]" + ", found [%s] (%4.4s)", + AcpiUtGetTypeName (Node->Type), Node->Name.Ascii)); + + return_ACPI_STATUS (AE_AML_TARGET_TYPE); + + default: + break; + } + } + + /* + * Resolve the source object to an actual value + * (If it is a reference object) + */ + Status = AcpiExResolveObject (&SourceDesc, TargetType, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Do the actual store operation */ + + switch (TargetType) + { + /* + * The simple data types all support implicit source operand + * conversion before the store. + */ + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + if ((WalkState->Opcode == AML_COPY_OP) || + !ImplicitConversion) + { + /* + * However, CopyObject and Stores to ArgX do not perform + * an implicit conversion, as per the ACPI specification. + * A direct store is performed instead. + */ + Status = AcpiExStoreDirectToNode (SourceDesc, Node, WalkState); + break; + } + + /* Store with implicit source operand conversion support */ + + Status = AcpiExStoreObjectToObject (SourceDesc, TargetDesc, + &NewDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (NewDesc != TargetDesc) + { + /* + * Store the new NewDesc as the new value of the Name, and set + * the Name's type to that of the value being stored in it. + * SourceDesc reference count is incremented by AttachObject. + * + * Note: This may change the type of the node if an explicit + * store has been performed such that the node/object type + * has been changed. + */ + Status = AcpiNsAttachObject ( + Node, NewDesc, NewDesc->Common.Type); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Store type [%s] into [%s] via Convert/Attach\n", + AcpiUtGetObjectTypeName (SourceDesc), + AcpiUtGetObjectTypeName (NewDesc))); + } + break; + + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * For all fields, always write the source data to the target + * field. Any required implicit source operand conversion is + * performed in the function below as necessary. Note, field + * objects must retain their original type permanently. + */ + Status = AcpiExWriteDataToField (SourceDesc, TargetDesc, + &WalkState->ResultObj); + break; + + default: + /* + * CopyObject operator: No conversions for all other types. + * Instead, directly store a copy of the source object. + * + * This is the ACPI spec-defined behavior for the CopyObject + * operator. (Note, for this default case, all normal + * Store/Target operations exited above with an error). + */ + Status = AcpiExStoreDirectToNode (SourceDesc, Node, WalkState); + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStoreDirectToNode + * + * PARAMETERS: SourceDesc - Value to be stored + * Node - Named object to receive the value + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: "Store" an object directly to a node. This involves a copy + * and an attach. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiExStoreDirectToNode ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *NewDesc; + + + ACPI_FUNCTION_TRACE (ExStoreDirectToNode); + + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Storing [%s] (%p) directly into node [%s] (%p)" + " with no implicit conversion\n", + AcpiUtGetObjectTypeName (SourceDesc), SourceDesc, + AcpiUtGetTypeName (Node->Type), Node)); + + /* Copy the source object to a new object */ + + Status = AcpiUtCopyIobjectToIobject (SourceDesc, &NewDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Attach the new object to the node */ + + Status = AcpiNsAttachObject (Node, NewDesc, NewDesc->Common.Type); + AcpiUtRemoveReference (NewDesc); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exstoren.c b/third_party/lib/acpica/source/components/executer/exstoren.c new file mode 100644 index 000000000..7a69927b1 --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exstoren.c @@ -0,0 +1,304 @@ +/****************************************************************************** + * + * Module Name: exstoren - AML Interpreter object store support, + * Store to Node (namespace object) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exstoren") + + +/******************************************************************************* + * + * FUNCTION: AcpiExResolveObject + * + * PARAMETERS: SourceDescPtr - Pointer to the source object + * TargetType - Current type of the target + * WalkState - Current walk state + * + * RETURN: Status, resolved object in SourceDescPtr. + * + * DESCRIPTION: Resolve an object. If the object is a reference, dereference + * it and return the actual object in the SourceDescPtr. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExResolveObject ( + ACPI_OPERAND_OBJECT **SourceDescPtr, + ACPI_OBJECT_TYPE TargetType, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *SourceDesc = *SourceDescPtr; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExResolveObject); + + + /* Ensure we have a Target that can be stored to */ + + switch (TargetType) + { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * These cases all require only Integers or values that + * can be converted to Integers (Strings or Buffers) + */ + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + /* + * Stores into a Field/Region or into a Integer/Buffer/String + * are all essentially the same. This case handles the + * "interchangeable" types Integer, String, and Buffer. + */ + if (SourceDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) + { + /* Resolve a reference object first */ + + Status = AcpiExResolveToValue (SourceDescPtr, WalkState); + if (ACPI_FAILURE (Status)) + { + break; + } + } + + /* For CopyObject, no further validation necessary */ + + if (WalkState->Opcode == AML_COPY_OP) + { + break; + } + + /* Must have a Integer, Buffer, or String */ + + if ((SourceDesc->Common.Type != ACPI_TYPE_INTEGER) && + (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) && + (SourceDesc->Common.Type != ACPI_TYPE_STRING) && + !((SourceDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) && + (SourceDesc->Reference.Class== ACPI_REFCLASS_TABLE))) + { + /* Conversion successful but still not a valid type */ + + ACPI_ERROR ((AE_INFO, + "Cannot assign type [%s] to [%s] (must be type Int/Str/Buf)", + AcpiUtGetObjectTypeName (SourceDesc), + AcpiUtGetTypeName (TargetType))); + + Status = AE_AML_OPERAND_TYPE; + } + break; + + case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: + /* + * All aliases should have been resolved earlier, during the + * operand resolution phase. + */ + ACPI_ERROR ((AE_INFO, "Store into an unresolved Alias object")); + Status = AE_AML_INTERNAL; + break; + + case ACPI_TYPE_PACKAGE: + default: + /* + * All other types than Alias and the various Fields come here, + * including the untyped case - ACPI_TYPE_ANY. + */ + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStoreObjectToObject + * + * PARAMETERS: SourceDesc - Object to store + * DestDesc - Object to receive a copy of the source + * NewDesc - New object if DestDesc is obsoleted + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: "Store" an object to another object. This may include + * converting the source type to the target type (implicit + * conversion), and a copy of the value of the source to + * the target. + * + * The Assignment of an object to another (not named) object + * is handled here. + * The Source passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. + * + * This module allows destination types of Number, String, + * Buffer, and Package. + * + * Assumes parameters are already validated. NOTE: SourceDesc + * resolution (from a reference object) must be performed by + * the caller if necessary. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExStoreObjectToObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_OPERAND_OBJECT **NewDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *ActualSrcDesc; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (ExStoreObjectToObject, SourceDesc); + + + ActualSrcDesc = SourceDesc; + if (!DestDesc) + { + /* + * There is no destination object (An uninitialized node or + * package element), so we can simply copy the source object + * creating a new destination object + */ + Status = AcpiUtCopyIobjectToIobject (ActualSrcDesc, NewDesc, WalkState); + return_ACPI_STATUS (Status); + } + + if (SourceDesc->Common.Type != DestDesc->Common.Type) + { + /* + * The source type does not match the type of the destination. + * Perform the "implicit conversion" of the source to the current type + * of the target as per the ACPI specification. + * + * If no conversion performed, ActualSrcDesc = SourceDesc. + * Otherwise, ActualSrcDesc is a temporary object to hold the + * converted object. + */ + Status = AcpiExConvertToTargetType (DestDesc->Common.Type, + SourceDesc, &ActualSrcDesc, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (SourceDesc == ActualSrcDesc) + { + /* + * No conversion was performed. Return the SourceDesc as the + * new object. + */ + *NewDesc = SourceDesc; + return_ACPI_STATUS (AE_OK); + } + } + + /* + * We now have two objects of identical types, and we can perform a + * copy of the *value* of the source object. + */ + switch (DestDesc->Common.Type) + { + case ACPI_TYPE_INTEGER: + + DestDesc->Integer.Value = ActualSrcDesc->Integer.Value; + + /* Truncate value if we are executing from a 32-bit ACPI table */ + + (void) AcpiExTruncateFor32bitTable (DestDesc); + break; + + case ACPI_TYPE_STRING: + + Status = AcpiExStoreStringToString (ActualSrcDesc, DestDesc); + break; + + case ACPI_TYPE_BUFFER: + + Status = AcpiExStoreBufferToBuffer (ActualSrcDesc, DestDesc); + break; + + case ACPI_TYPE_PACKAGE: + + Status = AcpiUtCopyIobjectToIobject (ActualSrcDesc, &DestDesc, + WalkState); + break; + + default: + /* + * All other types come here. + */ + ACPI_WARNING ((AE_INFO, "Store into type [%s] not implemented", + AcpiUtGetObjectTypeName (DestDesc))); + + Status = AE_NOT_IMPLEMENTED; + break; + } + + if (ActualSrcDesc != SourceDesc) + { + /* Delete the intermediate (temporary) source object */ + + AcpiUtRemoveReference (ActualSrcDesc); + } + + *NewDesc = DestDesc; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/exstorob.c b/third_party/lib/acpica/source/components/executer/exstorob.c new file mode 100644 index 000000000..8418fb85a --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exstorob.c @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * Module Name: exstorob - AML object store support, store to object + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exstorob") + + +/******************************************************************************* + * + * FUNCTION: AcpiExStoreBufferToBuffer + * + * PARAMETERS: SourceDesc - Source object to copy + * TargetDesc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Copy a buffer object to another buffer object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExStoreBufferToBuffer ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc) +{ + UINT32 Length; + UINT8 *Buffer; + + + ACPI_FUNCTION_TRACE_PTR (ExStoreBufferToBuffer, SourceDesc); + + + /* If Source and Target are the same, just return */ + + if (SourceDesc == TargetDesc) + { + return_ACPI_STATUS (AE_OK); + } + + /* We know that SourceDesc is a buffer by now */ + + Buffer = ACPI_CAST_PTR (UINT8, SourceDesc->Buffer.Pointer); + Length = SourceDesc->Buffer.Length; + + /* + * If target is a buffer of length zero or is a static buffer, + * allocate a new buffer of the proper length + */ + if ((TargetDesc->Buffer.Length == 0) || + (TargetDesc->Common.Flags & AOPOBJ_STATIC_POINTER)) + { + TargetDesc->Buffer.Pointer = ACPI_ALLOCATE (Length); + if (!TargetDesc->Buffer.Pointer) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + TargetDesc->Buffer.Length = Length; + } + + /* Copy source buffer to target buffer */ + + if (Length <= TargetDesc->Buffer.Length) + { + /* Clear existing buffer and copy in the new one */ + + memset (TargetDesc->Buffer.Pointer, 0, TargetDesc->Buffer.Length); + memcpy (TargetDesc->Buffer.Pointer, Buffer, Length); + +#ifdef ACPI_OBSOLETE_BEHAVIOR + /* + * NOTE: ACPI versions up to 3.0 specified that the buffer must be + * truncated if the string is smaller than the buffer. However, "other" + * implementations of ACPI never did this and thus became the defacto + * standard. ACPI 3.0A changes this behavior such that the buffer + * is no longer truncated. + */ + + /* + * OBSOLETE BEHAVIOR: + * If the original source was a string, we must truncate the buffer, + * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer + * copy must not truncate the original buffer. + */ + if (OriginalSrcType == ACPI_TYPE_STRING) + { + /* Set the new length of the target */ + + TargetDesc->Buffer.Length = Length; + } +#endif + } + else + { + /* Truncate the source, copy only what will fit */ + + memcpy (TargetDesc->Buffer.Pointer, Buffer, + TargetDesc->Buffer.Length); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Truncating source buffer from %X to %X\n", + Length, TargetDesc->Buffer.Length)); + } + + /* Copy flags */ + + TargetDesc->Buffer.Flags = SourceDesc->Buffer.Flags; + TargetDesc->Common.Flags &= ~AOPOBJ_STATIC_POINTER; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStoreStringToString + * + * PARAMETERS: SourceDesc - Source object to copy + * TargetDesc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Copy a String object to another String object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExStoreStringToString ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc) +{ + UINT32 Length; + UINT8 *Buffer; + + + ACPI_FUNCTION_TRACE_PTR (ExStoreStringToString, SourceDesc); + + + /* If Source and Target are the same, just return */ + + if (SourceDesc == TargetDesc) + { + return_ACPI_STATUS (AE_OK); + } + + /* We know that SourceDesc is a string by now */ + + Buffer = ACPI_CAST_PTR (UINT8, SourceDesc->String.Pointer); + Length = SourceDesc->String.Length; + + /* + * Replace existing string value if it will fit and the string + * pointer is not a static pointer (part of an ACPI table) + */ + if ((Length < TargetDesc->String.Length) && + (!(TargetDesc->Common.Flags & AOPOBJ_STATIC_POINTER))) + { + /* + * String will fit in existing non-static buffer. + * Clear old string and copy in the new one + */ + memset (TargetDesc->String.Pointer, 0, + (ACPI_SIZE) TargetDesc->String.Length + 1); + memcpy (TargetDesc->String.Pointer, Buffer, Length); + } + else + { + /* + * Free the current buffer, then allocate a new buffer + * large enough to hold the value + */ + if (TargetDesc->String.Pointer && + (!(TargetDesc->Common.Flags & AOPOBJ_STATIC_POINTER))) + { + /* Only free if not a pointer into the DSDT */ + + ACPI_FREE (TargetDesc->String.Pointer); + } + + TargetDesc->String.Pointer = + ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) Length + 1); + + if (!TargetDesc->String.Pointer) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + TargetDesc->Common.Flags &= ~AOPOBJ_STATIC_POINTER; + memcpy (TargetDesc->String.Pointer, Buffer, Length); + } + + /* Set the new target length */ + + TargetDesc->String.Length = Length; + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/executer/exsystem.c b/third_party/lib/acpica/source/components/executer/exsystem.c new file mode 100644 index 000000000..17eff66dd --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exsystem.c @@ -0,0 +1,349 @@ +/****************************************************************************** + * + * Module Name: exsystem - Interface to OS services + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exsystem") + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemWaitSemaphore + * + * PARAMETERS: Semaphore - Semaphore to wait on + * Timeout - Max time to wait + * + * RETURN: Status + * + * DESCRIPTION: Implements a semaphore wait with a check to see if the + * semaphore is available immediately. If it is not, the + * interpreter is released before waiting. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemWaitSemaphore ( + ACPI_SEMAPHORE Semaphore, + UINT16 Timeout) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExSystemWaitSemaphore); + + + Status = AcpiOsWaitSemaphore (Semaphore, 1, ACPI_DO_NOT_WAIT); + if (ACPI_SUCCESS (Status)) + { + return_ACPI_STATUS (Status); + } + + if (Status == AE_TIME) + { + /* We must wait, so unlock the interpreter */ + + AcpiExExitInterpreter (); + Status = AcpiOsWaitSemaphore (Semaphore, 1, Timeout); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "*** Thread awake after blocking, %s\n", + AcpiFormatException (Status))); + + /* Reacquire the interpreter */ + + AcpiExEnterInterpreter (); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemWaitMutex + * + * PARAMETERS: Mutex - Mutex to wait on + * Timeout - Max time to wait + * + * RETURN: Status + * + * DESCRIPTION: Implements a mutex wait with a check to see if the + * mutex is available immediately. If it is not, the + * interpreter is released before waiting. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemWaitMutex ( + ACPI_MUTEX Mutex, + UINT16 Timeout) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExSystemWaitMutex); + + + Status = AcpiOsAcquireMutex (Mutex, ACPI_DO_NOT_WAIT); + if (ACPI_SUCCESS (Status)) + { + return_ACPI_STATUS (Status); + } + + if (Status == AE_TIME) + { + /* We must wait, so unlock the interpreter */ + + AcpiExExitInterpreter (); + Status = AcpiOsAcquireMutex (Mutex, Timeout); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "*** Thread awake after blocking, %s\n", + AcpiFormatException (Status))); + + /* Reacquire the interpreter */ + + AcpiExEnterInterpreter (); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemDoStall + * + * PARAMETERS: HowLong - The amount of time to stall, + * in microseconds + * + * RETURN: Status + * + * DESCRIPTION: Suspend running thread for specified amount of time. + * Note: ACPI specification requires that Stall() does not + * relinquish the processor, and delays longer than 100 usec + * should use Sleep() instead. We allow stalls up to 255 usec + * for compatibility with other interpreters and existing BIOSs. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemDoStall ( + UINT32 HowLong) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_ENTRY (); + + + if (HowLong > 255) /* 255 microseconds */ + { + /* + * Longer than 255 usec, this is an error + * + * (ACPI specifies 100 usec as max, but this gives some slack in + * order to support existing BIOSs) + */ + ACPI_ERROR ((AE_INFO, + "Time parameter is too large (%u)", HowLong)); + Status = AE_AML_OPERAND_VALUE; + } + else + { + AcpiOsStall (HowLong); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemDoSleep + * + * PARAMETERS: HowLong - The amount of time to sleep, + * in milliseconds + * + * RETURN: None + * + * DESCRIPTION: Sleep the running thread for specified amount of time. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemDoSleep ( + UINT64 HowLong) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Since this thread will sleep, we must release the interpreter */ + + AcpiExExitInterpreter (); + + /* + * For compatibility with other ACPI implementations and to prevent + * accidental deep sleeps, limit the sleep time to something reasonable. + */ + if (HowLong > ACPI_MAX_SLEEP) + { + HowLong = ACPI_MAX_SLEEP; + } + + AcpiOsSleep (HowLong); + + /* And now we must get the interpreter again */ + + AcpiExEnterInterpreter (); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemSignalEvent + * + * PARAMETERS: ObjDesc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Provides an access point to perform synchronization operations + * within the AML. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemSignalEvent ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExSystemSignalEvent); + + + if (ObjDesc) + { + Status = AcpiOsSignalSemaphore (ObjDesc->Event.OsSemaphore, 1); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemWaitEvent + * + * PARAMETERS: TimeDesc - The 'time to delay' object descriptor + * ObjDesc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Provides an access point to perform synchronization operations + * within the AML. This operation is a request to wait for an + * event. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemWaitEvent ( + ACPI_OPERAND_OBJECT *TimeDesc, + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExSystemWaitEvent); + + + if (ObjDesc) + { + Status = AcpiExSystemWaitSemaphore (ObjDesc->Event.OsSemaphore, + (UINT16) TimeDesc->Integer.Value); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExSystemResetEvent + * + * PARAMETERS: ObjDesc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Reset an event to a known state. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExSystemResetEvent ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status = AE_OK; + ACPI_SEMAPHORE TempSemaphore; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * We are going to simply delete the existing semaphore and + * create a new one! + */ + Status = AcpiOsCreateSemaphore (ACPI_NO_UNIT_LIMIT, 0, &TempSemaphore); + if (ACPI_SUCCESS (Status)) + { + (void) AcpiOsDeleteSemaphore (ObjDesc->Event.OsSemaphore); + ObjDesc->Event.OsSemaphore = TempSemaphore; + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/components/executer/extrace.c b/third_party/lib/acpica/source/components/executer/extrace.c new file mode 100644 index 000000000..6f8a707ae --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/extrace.c @@ -0,0 +1,427 @@ +/****************************************************************************** + * + * Module Name: extrace - Support for interpreter execution tracing + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("extrace") + + +static ACPI_OPERAND_OBJECT *AcpiGbl_TraceMethodObject = NULL; + +/* Local prototypes */ + +#ifdef ACPI_DEBUG_OUTPUT +static const char * +AcpiExGetTraceEventName ( + ACPI_TRACE_EVENT_TYPE Type); +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiExInterpreterTraceEnabled + * + * PARAMETERS: Name - Whether method name should be matched, + * this should be checked before starting + * the tracer + * + * RETURN: TRUE if interpreter trace is enabled. + * + * DESCRIPTION: Check whether interpreter trace is enabled + * + ******************************************************************************/ + +static BOOLEAN +AcpiExInterpreterTraceEnabled ( + char *Name) +{ + + /* Check if tracing is enabled */ + + if (!(AcpiGbl_TraceFlags & ACPI_TRACE_ENABLED)) + { + return (FALSE); + } + + /* + * Check if tracing is filtered: + * + * 1. If the tracer is started, AcpiGbl_TraceMethodObject should have + * been filled by the trace starter + * 2. If the tracer is not started, AcpiGbl_TraceMethodName should be + * matched if it is specified + * 3. If the tracer is oneshot style, AcpiGbl_TraceMethodName should + * not be cleared by the trace stopper during the first match + */ + if (AcpiGbl_TraceMethodObject) + { + return (TRUE); + } + + if (Name && + (AcpiGbl_TraceMethodName && + strcmp (AcpiGbl_TraceMethodName, Name))) + { + return (FALSE); + } + + if ((AcpiGbl_TraceFlags & ACPI_TRACE_ONESHOT) && + !AcpiGbl_TraceMethodName) + { + return (FALSE); + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExGetTraceEventName + * + * PARAMETERS: Type - Trace event type + * + * RETURN: Trace event name. + * + * DESCRIPTION: Used to obtain the full trace event name. + * + ******************************************************************************/ + +#ifdef ACPI_DEBUG_OUTPUT + +static const char * +AcpiExGetTraceEventName ( + ACPI_TRACE_EVENT_TYPE Type) +{ + + switch (Type) + { + case ACPI_TRACE_AML_METHOD: + + return "Method"; + + case ACPI_TRACE_AML_OPCODE: + + return "Opcode"; + + case ACPI_TRACE_AML_REGION: + + return "Region"; + + default: + + return ""; + } +} + +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiExTracePoint + * + * PARAMETERS: Type - Trace event type + * Begin - TRUE if before execution + * Aml - Executed AML address + * Pathname - Object path + * + * RETURN: None + * + * DESCRIPTION: Internal interpreter execution trace. + * + ******************************************************************************/ + +void +AcpiExTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname) +{ + + ACPI_FUNCTION_NAME (ExTracePoint); + + + if (Pathname) + { + ACPI_DEBUG_PRINT ((ACPI_DB_TRACE_POINT, + "%s %s [0x%p:%s] execution.\n", + AcpiExGetTraceEventName (Type), Begin ? "Begin" : "End", + Aml, Pathname)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_TRACE_POINT, + "%s %s [0x%p] execution.\n", + AcpiExGetTraceEventName (Type), Begin ? "Begin" : "End", + Aml)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStartTraceMethod + * + * PARAMETERS: MethodNode - Node of the method + * ObjDesc - The method object + * WalkState - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start control method execution trace + * + ******************************************************************************/ + +void +AcpiExStartTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + char *Pathname = NULL; + BOOLEAN Enabled = FALSE; + + + ACPI_FUNCTION_NAME (ExStartTraceMethod); + + + if (MethodNode) + { + Pathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + Enabled = AcpiExInterpreterTraceEnabled (Pathname); + if (Enabled && !AcpiGbl_TraceMethodObject) + { + AcpiGbl_TraceMethodObject = ObjDesc; + AcpiGbl_OriginalDbgLevel = AcpiDbgLevel; + AcpiGbl_OriginalDbgLayer = AcpiDbgLayer; + AcpiDbgLevel = ACPI_TRACE_LEVEL_ALL; + AcpiDbgLayer = ACPI_TRACE_LAYER_ALL; + + if (AcpiGbl_TraceDbgLevel) + { + AcpiDbgLevel = AcpiGbl_TraceDbgLevel; + } + + if (AcpiGbl_TraceDbgLayer) + { + AcpiDbgLayer = AcpiGbl_TraceDbgLayer; + } + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + +Exit: + if (Enabled) + { + ACPI_TRACE_POINT (ACPI_TRACE_AML_METHOD, TRUE, + ObjDesc ? ObjDesc->Method.AmlStart : NULL, Pathname); + } + + if (Pathname) + { + ACPI_FREE (Pathname); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStopTraceMethod + * + * PARAMETERS: MethodNode - Node of the method + * ObjDesc - The method object + * WalkState - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop control method execution trace + * + ******************************************************************************/ + +void +AcpiExStopTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + char *Pathname = NULL; + BOOLEAN Enabled; + + + ACPI_FUNCTION_NAME (ExStopTraceMethod); + + + if (MethodNode) + { + Pathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto ExitPath; + } + + Enabled = AcpiExInterpreterTraceEnabled (NULL); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + if (Enabled) + { + ACPI_TRACE_POINT (ACPI_TRACE_AML_METHOD, FALSE, + ObjDesc ? ObjDesc->Method.AmlStart : NULL, Pathname); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto ExitPath; + } + + /* Check whether the tracer should be stopped */ + + if (AcpiGbl_TraceMethodObject == ObjDesc) + { + /* Disable further tracing if type is one-shot */ + + if (AcpiGbl_TraceFlags & ACPI_TRACE_ONESHOT) + { + AcpiGbl_TraceMethodName = NULL; + } + + AcpiDbgLevel = AcpiGbl_OriginalDbgLevel; + AcpiDbgLayer = AcpiGbl_OriginalDbgLayer; + AcpiGbl_TraceMethodObject = NULL; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + +ExitPath: + if (Pathname) + { + ACPI_FREE (Pathname); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStartTraceOpcode + * + * PARAMETERS: Op - The parser opcode object + * WalkState - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start opcode execution trace + * + ******************************************************************************/ + +void +AcpiExStartTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + + ACPI_FUNCTION_NAME (ExStartTraceOpcode); + + + if (AcpiExInterpreterTraceEnabled (NULL) && + (AcpiGbl_TraceFlags & ACPI_TRACE_OPCODE)) + { + ACPI_TRACE_POINT (ACPI_TRACE_AML_OPCODE, TRUE, + Op->Common.Aml, Op->Common.AmlOpName); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExStopTraceOpcode + * + * PARAMETERS: Op - The parser opcode object + * WalkState - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop opcode execution trace + * + ******************************************************************************/ + +void +AcpiExStopTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + + ACPI_FUNCTION_NAME (ExStopTraceOpcode); + + + if (AcpiExInterpreterTraceEnabled (NULL) && + (AcpiGbl_TraceFlags & ACPI_TRACE_OPCODE)) + { + ACPI_TRACE_POINT (ACPI_TRACE_AML_OPCODE, FALSE, + Op->Common.Aml, Op->Common.AmlOpName); + } +} diff --git a/third_party/lib/acpica/source/components/executer/exutils.c b/third_party/lib/acpica/source/components/executer/exutils.c new file mode 100644 index 000000000..a570ad6fe --- /dev/null +++ b/third_party/lib/acpica/source/components/executer/exutils.c @@ -0,0 +1,500 @@ +/****************************************************************************** + * + * Module Name: exutils - interpreter/scanner utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * DEFINE_AML_GLOBALS is tested in amlcode.h + * to determine whether certain global names should be "defined" or only + * "declared" in the current compilation. This enhances maintainability + * by enabling a single header file to embody all knowledge of the names + * in question. + * + * Exactly one module of any executable should #define DEFINE_GLOBALS + * before #including the header files which use this convention. The + * names in question will be defined and initialized in that module, + * and declared as extern in all other modules which #include those + * header files. + */ + +#define DEFINE_AML_GLOBALS + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exutils") + +/* Local prototypes */ + +static UINT32 +AcpiExDigitsNeeded ( + UINT64 Value, + UINT32 Base); + + +#ifndef ACPI_NO_METHOD_EXECUTION +/******************************************************************************* + * + * FUNCTION: AcpiExEnterInterpreter + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Enter the interpreter execution region. Failure to enter + * the interpreter region is a fatal system error. Used in + * conjunction with ExitInterpreter. + * + ******************************************************************************/ + +void +AcpiExEnterInterpreter ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExEnterInterpreter); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "Could not acquire AML Interpreter mutex")); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExExitInterpreter + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Exit the interpreter execution region. This is the top level + * routine used to exit the interpreter when all processing has + * been completed, or when the method blocks. + * + * Cases where the interpreter is unlocked internally: + * 1) Method will be blocked on a Sleep() AML opcode + * 2) Method will be blocked on an Acquire() AML opcode + * 3) Method will be blocked on a Wait() AML opcode + * 4) Method will be blocked to acquire the global lock + * 5) Method will be blocked waiting to execute a serialized control + * method that is currently executing + * 6) About to invoke a user-installed opregion handler + * + ******************************************************************************/ + +void +AcpiExExitInterpreter ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExExitInterpreter); + + + Status = AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "Could not release AML Interpreter mutex")); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExTruncateFor32bitTable + * + * PARAMETERS: ObjDesc - Object to be truncated + * + * RETURN: TRUE if a truncation was performed, FALSE otherwise. + * + * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is + * 32-bit, as determined by the revision of the DSDT. + * + ******************************************************************************/ + +BOOLEAN +AcpiExTruncateFor32bitTable ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + + ACPI_FUNCTION_ENTRY (); + + + /* + * Object must be a valid number and we must be executing + * a control method. Object could be NS node for AML_INT_NAMEPATH_OP. + */ + if ((!ObjDesc) || + (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) || + (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) + { + return (FALSE); + } + + if ((AcpiGbl_IntegerByteWidth == 4) && + (ObjDesc->Integer.Value > (UINT64) ACPI_UINT32_MAX)) + { + /* + * We are executing in a 32-bit ACPI table. Truncate + * the value to 32 bits by zeroing out the upper 32-bit field + */ + ObjDesc->Integer.Value &= (UINT64) ACPI_UINT32_MAX; + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExAcquireGlobalLock + * + * PARAMETERS: FieldFlags - Flags with Lock rule: + * AlwaysLock or NeverLock + * + * RETURN: None + * + * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field + * flags specifiy that it is to be obtained before field access. + * + ******************************************************************************/ + +void +AcpiExAcquireGlobalLock ( + UINT32 FieldFlags) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExAcquireGlobalLock); + + + /* Only use the lock if the AlwaysLock bit is set */ + + if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK)) + { + return_VOID; + } + + /* Attempt to get the global lock, wait forever */ + + Status = AcpiExAcquireMutexObject (ACPI_WAIT_FOREVER, + AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ()); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not acquire Global Lock")); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExReleaseGlobalLock + * + * PARAMETERS: FieldFlags - Flags with Lock rule: + * AlwaysLock or NeverLock + * + * RETURN: None + * + * DESCRIPTION: Release the ACPI hardware Global Lock + * + ******************************************************************************/ + +void +AcpiExReleaseGlobalLock ( + UINT32 FieldFlags) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (ExReleaseGlobalLock); + + + /* Only use the lock if the AlwaysLock bit is set */ + + if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK)) + { + return_VOID; + } + + /* Release the global lock */ + + Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex); + if (ACPI_FAILURE (Status)) + { + /* Report the error, but there isn't much else we can do */ + + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not release Global Lock")); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExDigitsNeeded + * + * PARAMETERS: Value - Value to be represented + * Base - Base of representation + * + * RETURN: The number of digits. + * + * DESCRIPTION: Calculate the number of digits needed to represent the Value + * in the given Base (Radix) + * + ******************************************************************************/ + +static UINT32 +AcpiExDigitsNeeded ( + UINT64 Value, + UINT32 Base) +{ + UINT32 NumDigits; + UINT64 CurrentValue; + + + ACPI_FUNCTION_TRACE (ExDigitsNeeded); + + + /* UINT64 is unsigned, so we don't worry about a '-' prefix */ + + if (Value == 0) + { + return_UINT32 (1); + } + + CurrentValue = Value; + NumDigits = 0; + + /* Count the digits in the requested base */ + + while (CurrentValue) + { + (void) AcpiUtShortDivide (CurrentValue, Base, &CurrentValue, NULL); + NumDigits++; + } + + return_UINT32 (NumDigits); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExEisaIdToString + * + * PARAMETERS: CompressedId - EISAID to be converted + * OutString - Where to put the converted string (8 bytes) + * + * RETURN: None + * + * DESCRIPTION: Convert a numeric EISAID to string representation. Return + * buffer must be large enough to hold the string. The string + * returned is always exactly of length ACPI_EISAID_STRING_SIZE + * (includes null terminator). The EISAID is always 32 bits. + * + ******************************************************************************/ + +void +AcpiExEisaIdToString ( + char *OutString, + UINT64 CompressedId) +{ + UINT32 SwappedId; + + + ACPI_FUNCTION_ENTRY (); + + + /* The EISAID should be a 32-bit integer */ + + if (CompressedId > ACPI_UINT32_MAX) + { + ACPI_WARNING ((AE_INFO, + "Expected EISAID is larger than 32 bits: " + "0x%8.8X%8.8X, truncating", + ACPI_FORMAT_UINT64 (CompressedId))); + } + + /* Swap ID to big-endian to get contiguous bits */ + + SwappedId = AcpiUtDwordByteSwap ((UINT32) CompressedId); + + /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */ + + OutString[0] = (char) (0x40 + (((unsigned long) SwappedId >> 26) & 0x1F)); + OutString[1] = (char) (0x40 + ((SwappedId >> 21) & 0x1F)); + OutString[2] = (char) (0x40 + ((SwappedId >> 16) & 0x1F)); + OutString[3] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 12); + OutString[4] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 8); + OutString[5] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 4); + OutString[6] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 0); + OutString[7] = 0; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExIntegerToString + * + * PARAMETERS: OutString - Where to put the converted string. At least + * 21 bytes are needed to hold the largest + * possible 64-bit integer. + * Value - Value to be converted + * + * RETURN: None, string + * + * DESCRIPTION: Convert a 64-bit integer to decimal string representation. + * Assumes string buffer is large enough to hold the string. The + * largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1). + * + ******************************************************************************/ + +void +AcpiExIntegerToString ( + char *OutString, + UINT64 Value) +{ + UINT32 Count; + UINT32 DigitsNeeded; + UINT32 Remainder; + + + ACPI_FUNCTION_ENTRY (); + + + DigitsNeeded = AcpiExDigitsNeeded (Value, 10); + OutString[DigitsNeeded] = 0; + + for (Count = DigitsNeeded; Count > 0; Count--) + { + (void) AcpiUtShortDivide (Value, 10, &Value, &Remainder); + OutString[Count-1] = (char) ('0' + Remainder);\ + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiExPciClsToString + * + * PARAMETERS: OutString - Where to put the converted string (7 bytes) + * PARAMETERS: ClassCode - PCI class code to be converted (3 bytes) + * + * RETURN: None + * + * DESCRIPTION: Convert 3-bytes PCI class code to string representation. + * Return buffer must be large enough to hold the string. The + * string returned is always exactly of length + * ACPI_PCICLS_STRING_SIZE (includes null terminator). + * + ******************************************************************************/ + +void +AcpiExPciClsToString ( + char *OutString, + UINT8 ClassCode[3]) +{ + + ACPI_FUNCTION_ENTRY (); + + + /* All 3 bytes are hexadecimal */ + + OutString[0] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[0], 4); + OutString[1] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[0], 0); + OutString[2] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[1], 4); + OutString[3] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[1], 0); + OutString[4] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[2], 4); + OutString[5] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[2], 0); + OutString[6] = 0; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiIsValidSpaceId + * + * PARAMETERS: SpaceId - ID to be validated + * + * RETURN: TRUE if valid/supported ID. + * + * DESCRIPTION: Validate an operation region SpaceID. + * + ******************************************************************************/ + +BOOLEAN +AcpiIsValidSpaceId ( + UINT8 SpaceId) +{ + + if ((SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) && + (SpaceId < ACPI_USER_REGION_BEGIN) && + (SpaceId != ACPI_ADR_SPACE_DATA_TABLE) && + (SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE)) + { + return (FALSE); + } + + return (TRUE); +} + +#endif diff --git a/third_party/lib/acpica/source/components/hardware/hwacpi.c b/third_party/lib/acpica/source/components/hardware/hwacpi.c new file mode 100644 index 000000000..73512128d --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwacpi.c @@ -0,0 +1,221 @@ +/****************************************************************************** + * + * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwacpi") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/****************************************************************************** + * + * FUNCTION: AcpiHwSetMode + * + * PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY + * + * RETURN: Status + * + * DESCRIPTION: Transitions the system into the requested mode. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwSetMode ( + UINT32 Mode) +{ + + ACPI_STATUS Status; + UINT32 Retry; + + + ACPI_FUNCTION_TRACE (HwSetMode); + + + /* If the Hardware Reduced flag is set, machine is always in acpi mode */ + + if (AcpiGbl_ReducedHardware) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, + * system does not support mode transition. + */ + if (!AcpiGbl_FADT.SmiCommand) + { + ACPI_ERROR ((AE_INFO, "No SMI_CMD in FADT, mode transition failed")); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + } + + /* + * ACPI 2.0 clarified the meaning of ACPI_ENABLE and ACPI_DISABLE + * in FADT: If it is zero, enabling or disabling is not supported. + * As old systems may have used zero for mode transition, + * we make sure both the numbers are zero to determine these + * transitions are not supported. + */ + if (!AcpiGbl_FADT.AcpiEnable && !AcpiGbl_FADT.AcpiDisable) + { + ACPI_ERROR ((AE_INFO, + "No ACPI mode transition supported in this system " + "(enable/disable both zero)")); + return_ACPI_STATUS (AE_OK); + } + + switch (Mode) + { + case ACPI_SYS_MODE_ACPI: + + /* BIOS should have disabled ALL fixed and GP events */ + + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, + (UINT32) AcpiGbl_FADT.AcpiEnable, 8); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Attempting to enable ACPI mode\n")); + break; + + case ACPI_SYS_MODE_LEGACY: + /* + * BIOS should clear all fixed status bits and restore fixed event + * enable bits to default + */ + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, + (UINT32) AcpiGbl_FADT.AcpiDisable, 8); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Attempting to enable Legacy (non-ACPI) mode\n")); + break; + + default: + + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not write ACPI mode change")); + return_ACPI_STATUS (Status); + } + + /* + * Some hardware takes a LONG time to switch modes. Give them 3 sec to + * do so, but allow faster systems to proceed more quickly. + */ + Retry = 3000; + while (Retry) + { + if (AcpiHwGetMode () == Mode) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Mode %X successfully enabled\n", Mode)); + return_ACPI_STATUS (AE_OK); + } + AcpiOsStall (ACPI_USEC_PER_MSEC); + Retry--; + } + + ACPI_ERROR ((AE_INFO, "Hardware did not change modes")); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetMode + * + * PARAMETERS: none + * + * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY + * + * DESCRIPTION: Return current operating state of system. Determined by + * querying the SCI_EN bit. + * + ******************************************************************************/ + +UINT32 +AcpiHwGetMode ( + void) +{ + ACPI_STATUS Status; + UINT32 Value; + + + ACPI_FUNCTION_TRACE (HwGetMode); + + + /* If the Hardware Reduced flag is set, machine is always in acpi mode */ + + if (AcpiGbl_ReducedHardware) + { + return_UINT32 (ACPI_SYS_MODE_ACPI); + } + + /* + * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, + * system does not support mode transition. + */ + if (!AcpiGbl_FADT.SmiCommand) + { + return_UINT32 (ACPI_SYS_MODE_ACPI); + } + + Status = AcpiReadBitRegister (ACPI_BITREG_SCI_ENABLE, &Value); + if (ACPI_FAILURE (Status)) + { + return_UINT32 (ACPI_SYS_MODE_LEGACY); + } + + if (Value) + { + return_UINT32 (ACPI_SYS_MODE_ACPI); + } + else + { + return_UINT32 (ACPI_SYS_MODE_LEGACY); + } +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/hardware/hwesleep.c b/third_party/lib/acpica/source/components/hardware/hwesleep.c new file mode 100644 index 000000000..de914df85 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwesleep.c @@ -0,0 +1,259 @@ +/****************************************************************************** + * + * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the + * extended FADT-V5 sleep registers. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwesleep") + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExecuteSleepMethod + * + * PARAMETERS: MethodPathname - Pathname of method to execute + * IntegerArgument - Argument to pass to the method + * + * RETURN: None + * + * DESCRIPTION: Execute a sleep/wake related method with one integer argument + * and no return value. + * + ******************************************************************************/ + +void +AcpiHwExecuteSleepMethod ( + char *MethodPathname, + UINT32 IntegerArgument) +{ + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwExecuteSleepMethod); + + + /* One argument, IntegerArgument; No return value expected */ + + ArgList.Count = 1; + ArgList.Pointer = &Arg; + Arg.Type = ACPI_TYPE_INTEGER; + Arg.Integer.Value = (UINT64) IntegerArgument; + + Status = AcpiEvaluateObject (NULL, MethodPathname, &ArgList, NULL); + if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While executing method %s", + MethodPathname)); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExtendedSleep + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state via the extended FADT sleep + * registers (V5 FADT). + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwExtendedSleep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + UINT8 SleepTypeValue; + UINT64 SleepStatus; + + + ACPI_FUNCTION_TRACE (HwExtendedSleep); + + + /* Extended sleep registers must be valid */ + + if (!AcpiGbl_FADT.SleepControl.Address || + !AcpiGbl_FADT.SleepStatus.Address) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Clear wake status (WAK_STS) */ + + Status = AcpiWrite ((UINT64) ACPI_X_WAKE_STATUS, + &AcpiGbl_FADT.SleepStatus); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiGbl_SystemAwakeAndRunning = FALSE; + + /* Flush caches, as per ACPI specification */ + + ACPI_FLUSH_CPU_CACHE (); + + /* + * Set the SLP_TYP and SLP_EN bits. + * + * Note: We only use the first value returned by the \_Sx method + * (AcpiGbl_SleepTypeA) - As per ACPI specification. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Entering sleep state [S%u]\n", SleepState)); + + SleepTypeValue = ((AcpiGbl_SleepTypeA << ACPI_X_SLEEP_TYPE_POSITION) & + ACPI_X_SLEEP_TYPE_MASK); + + Status = AcpiWrite ((UINT64) (SleepTypeValue | ACPI_X_SLEEP_ENABLE), + &AcpiGbl_FADT.SleepControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Wait for transition back to Working State */ + + do + { + Status = AcpiRead (&SleepStatus, &AcpiGbl_FADT.SleepStatus); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + } while (!(((UINT8) SleepStatus) & ACPI_X_WAKE_STATUS)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExtendedWakePrep + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after + * a sleep. Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwExtendedWakePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + UINT8 SleepTypeValue; + + + ACPI_FUNCTION_TRACE (HwExtendedWakePrep); + + + Status = AcpiGetSleepTypeData (ACPI_STATE_S0, + &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); + if (ACPI_SUCCESS (Status)) + { + SleepTypeValue = ((AcpiGbl_SleepTypeA << ACPI_X_SLEEP_TYPE_POSITION) & + ACPI_X_SLEEP_TYPE_MASK); + + (void) AcpiWrite ((UINT64) (SleepTypeValue | ACPI_X_SLEEP_ENABLE), + &AcpiGbl_FADT.SleepControl); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExtendedWake + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwExtendedWake ( + UINT8 SleepState) +{ + ACPI_FUNCTION_TRACE (HwExtendedWake); + + + /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ + + AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; + + /* Execute the wake methods */ + + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING); + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState); + + /* + * Some BIOS code assumes that WAK_STS will be cleared on resume + * and use it to determine whether the system is rebooting or + * resuming. Clear WAK_STS for compatibility. + */ + (void) AcpiWrite ((UINT64) ACPI_X_WAKE_STATUS, &AcpiGbl_FADT.SleepStatus); + AcpiGbl_SystemAwakeAndRunning = TRUE; + + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING); + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/hardware/hwgpe.c b/third_party/lib/acpica/source/components/hardware/hwgpe.c new file mode 100644 index 000000000..3dbf10ba0 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwgpe.c @@ -0,0 +1,599 @@ +/****************************************************************************** + * + * Module Name: hwgpe - Low level GPE enable/disable/clear functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwgpe") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwEnableWakeupGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +static ACPI_STATUS +AcpiHwGpeEnableWrite ( + UINT8 EnableMask, + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo); + + +/****************************************************************************** + * + * FUNCTION: AcpiHwGetGpeRegisterBit + * + * PARAMETERS: GpeEventInfo - Info block for the GPE + * + * RETURN: Register mask with a one in the GPE bit position + * + * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the + * correct position for the input GPE. + * + ******************************************************************************/ + +UINT32 +AcpiHwGetGpeRegisterBit ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + + return ((UINT32) 1 << + (GpeEventInfo->GpeNumber - GpeEventInfo->RegisterInfo->BaseGpeNumber)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwLowSetGpe + * + * PARAMETERS: GpeEventInfo - Info block for the GPE to be disabled + * Action - Enable or disable + * + * RETURN: Status + * + * DESCRIPTION: Enable or disable a single GPE in the parent enable register. + * The EnableMask field of the involved GPE register must be + * updated by the caller if necessary. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLowSetGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 Action) +{ + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_STATUS Status; + UINT32 EnableMask; + UINT32 RegisterBit; + + + ACPI_FUNCTION_ENTRY (); + + + /* Get the info block for the entire GPE register */ + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + if (!GpeRegisterInfo) + { + return (AE_NOT_EXIST); + } + + /* Get current value of the enable register that contains this GPE */ + + Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Set or clear just the bit that corresponds to this GPE */ + + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); + switch (Action) + { + case ACPI_GPE_CONDITIONAL_ENABLE: + + /* Only enable if the corresponding EnableMask bit is set */ + + if (!(RegisterBit & GpeRegisterInfo->EnableMask)) + { + return (AE_BAD_PARAMETER); + } + + /*lint -fallthrough */ + + case ACPI_GPE_ENABLE: + + ACPI_SET_BIT (EnableMask, RegisterBit); + break; + + case ACPI_GPE_DISABLE: + + ACPI_CLEAR_BIT (EnableMask, RegisterBit); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u", Action)); + return (AE_BAD_PARAMETER); + } + + /* Write the updated enable mask */ + + Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwClearGpe + * + * PARAMETERS: GpeEventInfo - Info block for the GPE to be cleared + * + * RETURN: Status + * + * DESCRIPTION: Clear the status bit for a single GPE. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwClearGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_STATUS Status; + UINT32 RegisterBit; + + + ACPI_FUNCTION_ENTRY (); + + /* Get the info block for the entire GPE register */ + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + if (!GpeRegisterInfo) + { + return (AE_NOT_EXIST); + } + + /* + * Write a one to the appropriate bit in the status register to + * clear this GPE. + */ + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); + + Status = AcpiHwWrite (RegisterBit, &GpeRegisterInfo->StatusAddress); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwGetGpeStatus + * + * PARAMETERS: GpeEventInfo - Info block for the GPE to queried + * EventStatus - Where the GPE status is returned + * + * RETURN: Status + * + * DESCRIPTION: Return the status of a single GPE. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwGetGpeStatus ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + ACPI_EVENT_STATUS *EventStatus) +{ + UINT32 InByte; + UINT32 RegisterBit; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_EVENT_STATUS LocalEventStatus = 0; + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + if (!EventStatus) + { + return (AE_BAD_PARAMETER); + } + + /* GPE currently handled? */ + + if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != + ACPI_GPE_DISPATCH_NONE) + { + LocalEventStatus |= ACPI_EVENT_FLAG_HAS_HANDLER; + } + + /* Get the info block for the entire GPE register */ + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + + /* Get the register bitmask for this GPE */ + + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); + + /* GPE currently enabled? (enabled for runtime?) */ + + if (RegisterBit & GpeRegisterInfo->EnableForRun) + { + LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED; + } + + /* GPE enabled for wake? */ + + if (RegisterBit & GpeRegisterInfo->EnableForWake) + { + LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED; + } + + /* GPE currently enabled (enable bit == 1)? */ + + Status = AcpiHwRead (&InByte, &GpeRegisterInfo->EnableAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (RegisterBit & InByte) + { + LocalEventStatus |= ACPI_EVENT_FLAG_ENABLE_SET; + } + + /* GPE currently active (status bit == 1)? */ + + Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (RegisterBit & InByte) + { + LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET; + } + + /* Set return value */ + + (*EventStatus) = LocalEventStatus; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwGpeEnableWrite + * + * PARAMETERS: EnableMask - Bit mask to write to the GPE register + * GpeRegisterInfo - Gpe Register info + * + * RETURN: Status + * + * DESCRIPTION: Write the enable mask byte to the given GPE register. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwGpeEnableWrite ( + UINT8 EnableMask, + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo) +{ + ACPI_STATUS Status; + + + GpeRegisterInfo->EnableMask = EnableMask; + + Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwDisableGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Disable all GPEs within a single GPE block + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDisableGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Disable all GPEs in this register */ + + Status = AcpiHwGpeEnableWrite (0x00, &GpeBlock->RegisterInfo[i]); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwClearGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Clear status bits for all GPEs within a single GPE block + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwClearGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Clear status on all GPEs in this register */ + + Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableRuntimeGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes + * combination wake/run GPEs. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwEnableRuntimeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + + + /* NOTE: assumes that all GPEs are currently disabled */ + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; + if (!GpeRegisterInfo->EnableForRun) + { + continue; + } + + /* Enable all "runtime" GPEs in this register */ + + Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForRun, + GpeRegisterInfo); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableWakeupGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes + * combination wake/run GPEs. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwEnableWakeupGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; + + /* + * Enable all "wake" GPEs in this register and disable the + * remaining ones. + */ + Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForWake, + GpeRegisterInfo); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwDisableAllGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDisableAllGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwDisableAllGpes); + + + Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL); + Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableAllRuntimeGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwEnableAllRuntimeGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes); + + + Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL); + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableAllWakeupGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwEnableAllWakeupGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes); + + + Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL); + return_ACPI_STATUS (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/hardware/hwpci.c b/third_party/lib/acpica/source/components/hardware/hwpci.c new file mode 100644 index 000000000..c2b707122 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwpci.c @@ -0,0 +1,463 @@ +/******************************************************************************* + * + * Module Name: hwpci - Obtain PCI bus, device, and function numbers + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("hwpci") + + +/* PCI configuration space values */ + +#define PCI_CFG_HEADER_TYPE_REG 0x0E +#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 +#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 + +/* PCI header values */ + +#define PCI_HEADER_TYPE_MASK 0x7F +#define PCI_TYPE_BRIDGE 0x01 +#define PCI_TYPE_CARDBUS_BRIDGE 0x02 + +typedef struct acpi_pci_device +{ + ACPI_HANDLE Device; + struct acpi_pci_device *Next; + +} ACPI_PCI_DEVICE; + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwBuildPciList ( + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion, + ACPI_PCI_DEVICE **ReturnListHead); + +static ACPI_STATUS +AcpiHwProcessPciList ( + ACPI_PCI_ID *PciId, + ACPI_PCI_DEVICE *ListHead); + +static void +AcpiHwDeletePciList ( + ACPI_PCI_DEVICE *ListHead); + +static ACPI_STATUS +AcpiHwGetPciDeviceInfo ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE PciDevice, + UINT16 *BusNumber, + BOOLEAN *IsBridge); + + +/******************************************************************************* + * + * FUNCTION: AcpiHwDerivePciId + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * RootPciDevice - A handle to a PCI device object. This + * object must be a PCI Root Bridge having a + * _HID value of either PNP0A03 or PNP0A08 + * PciRegion - A handle to a PCI configuration space + * Operation Region being initialized + * + * RETURN: Status + * + * DESCRIPTION: This function derives a full PCI ID for a PCI device, + * consisting of a Segment number, Bus number, Device number, + * and function code. + * + * The PCI hardware dynamically configures PCI bus numbers + * depending on the bus topology discovered during system + * initialization. This function is invoked during configuration + * of a PCI_Config Operation Region in order to (possibly) update + * the Bus/Device/Function numbers in the PciId with the actual + * values as determined by the hardware and operating system + * configuration. + * + * The PciId parameter is initially populated during the Operation + * Region initialization. This function is then called, and is + * will make any necessary modifications to the Bus, Device, or + * Function number PCI ID subfields as appropriate for the + * current hardware and OS configuration. + * + * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId + * interface since this feature is OS-independent. This module + * specifically avoids any use of recursion by building a local + * temporary device list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDerivePciId ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion) +{ + ACPI_STATUS Status; + ACPI_PCI_DEVICE *ListHead; + + + ACPI_FUNCTION_TRACE (HwDerivePciId); + + + if (!PciId) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ + + Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); + if (ACPI_SUCCESS (Status)) + { + /* Walk the list, updating the PCI device/function/bus numbers */ + + Status = AcpiHwProcessPciList (PciId, ListHead); + + /* Delete the list */ + + AcpiHwDeletePciList (ListHead); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwBuildPciList + * + * PARAMETERS: RootPciDevice - A handle to a PCI device object. This + * object is guaranteed to be a PCI Root + * Bridge having a _HID value of either + * PNP0A03 or PNP0A08 + * PciRegion - A handle to the PCI configuration space + * Operation Region + * ReturnListHead - Where the PCI device list is returned + * + * RETURN: Status + * + * DESCRIPTION: Builds a list of devices from the input PCI region up to the + * Root PCI device for this namespace subtree. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwBuildPciList ( + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion, + ACPI_PCI_DEVICE **ReturnListHead) +{ + ACPI_HANDLE CurrentDevice; + ACPI_HANDLE ParentDevice; + ACPI_STATUS Status; + ACPI_PCI_DEVICE *ListElement; + + + /* + * Ascend namespace branch until the RootPciDevice is reached, building + * a list of device nodes. Loop will exit when either the PCI device is + * found, or the root of the namespace is reached. + */ + *ReturnListHead = NULL; + CurrentDevice = PciRegion; + while (1) + { + Status = AcpiGetParent (CurrentDevice, &ParentDevice); + if (ACPI_FAILURE (Status)) + { + /* Must delete the list before exit */ + + AcpiHwDeletePciList (*ReturnListHead); + return (Status); + } + + /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ + + if (ParentDevice == RootPciDevice) + { + return (AE_OK); + } + + ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); + if (!ListElement) + { + /* Must delete the list before exit */ + + AcpiHwDeletePciList (*ReturnListHead); + return (AE_NO_MEMORY); + } + + /* Put new element at the head of the list */ + + ListElement->Next = *ReturnListHead; + ListElement->Device = ParentDevice; + *ReturnListHead = ListElement; + + CurrentDevice = ParentDevice; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwProcessPciList + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * ListHead - Device list created by + * AcpiHwBuildPciList + * + * RETURN: Status + * + * DESCRIPTION: Walk downward through the PCI device list, getting the device + * info for each, via the PCI configuration space and updating + * the PCI ID as necessary. Deletes the list during traversal. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwProcessPciList ( + ACPI_PCI_ID *PciId, + ACPI_PCI_DEVICE *ListHead) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PCI_DEVICE *Info; + UINT16 BusNumber; + BOOLEAN IsBridge = TRUE; + + + ACPI_FUNCTION_NAME (HwProcessPciList); + + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", + PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); + + BusNumber = PciId->Bus; + + /* + * Descend down the namespace tree, collecting PCI device, function, + * and bus numbers. BusNumber is only important for PCI bridges. + * Algorithm: As we descend the tree, use the last valid PCI device, + * function, and bus numbers that are discovered, and assign them + * to the PCI ID for the target device. + */ + Info = ListHead; + while (Info) + { + Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, + &BusNumber, &IsBridge); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Info = Info->Next; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " + "Status %X BusNumber %X IsBridge %X\n", + PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, + Status, BusNumber, IsBridge)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwDeletePciList + * + * PARAMETERS: ListHead - Device list created by + * AcpiHwBuildPciList + * + * RETURN: None + * + * DESCRIPTION: Free the entire PCI list. + * + ******************************************************************************/ + +static void +AcpiHwDeletePciList ( + ACPI_PCI_DEVICE *ListHead) +{ + ACPI_PCI_DEVICE *Next; + ACPI_PCI_DEVICE *Previous; + + + Next = ListHead; + while (Next) + { + Previous = Next; + Next = Previous->Next; + ACPI_FREE (Previous); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetPciDeviceInfo + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * PciDevice - Handle for the PCI device object + * BusNumber - Where a PCI bridge bus number is returned + * IsBridge - Return value, indicates if this PCI + * device is a PCI bridge + * + * RETURN: Status + * + * DESCRIPTION: Get the device info for a single PCI device object. Get the + * _ADR (contains PCI device and function numbers), and for PCI + * bridge devices, get the bus number from PCI configuration + * space. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwGetPciDeviceInfo ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE PciDevice, + UINT16 *BusNumber, + BOOLEAN *IsBridge) +{ + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + UINT64 ReturnValue; + UINT64 PciValue; + + + /* We only care about objects of type Device */ + + Status = AcpiGetType (PciDevice, &ObjectType); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (ObjectType != ACPI_TYPE_DEVICE) + { + return (AE_OK); + } + + /* We need an _ADR. Ignore device if not present */ + + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, + PciDevice, &ReturnValue); + if (ACPI_FAILURE (Status)) + { + return (AE_OK); + } + + /* + * From _ADR, get the PCI Device and Function and + * update the PCI ID. + */ + PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); + PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); + + /* + * If the previous device was a bridge, use the previous + * device bus number + */ + if (*IsBridge) + { + PciId->Bus = *BusNumber; + } + + /* + * Get the bus numbers from PCI Config space: + * + * First, get the PCI HeaderType + */ + *IsBridge = FALSE; + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ + + PciValue &= PCI_HEADER_TYPE_MASK; + + if ((PciValue != PCI_TYPE_BRIDGE) && + (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) + { + return (AE_OK); + } + + /* Bridge: Get the Primary BusNumber */ + + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *IsBridge = TRUE; + PciId->Bus = (UINT16) PciValue; + + /* Bridge: Get the Secondary BusNumber */ + + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *BusNumber = (UINT16) PciValue; + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/hardware/hwregs.c b/third_party/lib/acpica/source/components/hardware/hwregs.c new file mode 100644 index 000000000..bc85c96b5 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwregs.c @@ -0,0 +1,729 @@ +/******************************************************************************* + * + * Module Name: hwregs - Read/write access functions for the various ACPI + * control and status registers. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwregs") + + +#if (!ACPI_REDUCED_HARDWARE) + +/* Local Prototypes */ + +static ACPI_STATUS +AcpiHwReadMultiple ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB); + +static ACPI_STATUS +AcpiHwWriteMultiple ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB); + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/****************************************************************************** + * + * FUNCTION: AcpiHwValidateRegister + * + * PARAMETERS: Reg - GAS register structure + * MaxBitWidth - Max BitWidth supported (32 or 64) + * Address - Pointer to where the gas->address + * is returned + * + * RETURN: Status + * + * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS + * pointer, Address, SpaceId, BitWidth, and BitOffset. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwValidateRegister ( + ACPI_GENERIC_ADDRESS *Reg, + UINT8 MaxBitWidth, + UINT64 *Address) +{ + + /* Must have a valid pointer to a GAS structure */ + + if (!Reg) + { + return (AE_BAD_PARAMETER); + } + + /* + * Copy the target address. This handles possible alignment issues. + * Address must not be null. A null address also indicates an optional + * ACPI register that is not supported, so no error message. + */ + ACPI_MOVE_64_TO_64 (Address, &Reg->Address); + if (!(*Address)) + { + return (AE_BAD_ADDRESS); + } + + /* Validate the SpaceID */ + + if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) + { + ACPI_ERROR ((AE_INFO, + "Unsupported address space: 0x%X", Reg->SpaceId)); + return (AE_SUPPORT); + } + + /* Validate the BitWidth */ + + if ((Reg->BitWidth != 8) && + (Reg->BitWidth != 16) && + (Reg->BitWidth != 32) && + (Reg->BitWidth != MaxBitWidth)) + { + ACPI_ERROR ((AE_INFO, + "Unsupported register bit width: 0x%X", Reg->BitWidth)); + return (AE_SUPPORT); + } + + /* Validate the BitOffset. Just a warning for now. */ + + if (Reg->BitOffset != 0) + { + ACPI_WARNING ((AE_INFO, + "Unsupported register bit offset: 0x%X", Reg->BitOffset)); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwRead + * + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max + * version of AcpiRead, used internally since the overhead of + * 64-bit values is not needed. + * + * LIMITATIONS: + * BitWidth must be exactly 8, 16, or 32. + * SpaceID must be SystemMemory or SystemIO. + * BitOffset and AccessWidth are currently ignored, as there has + * not been a need to implement these. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwRead ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT64 Address; + UINT64 Value64; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (HwRead); + + + /* Validate contents of the GAS register */ + + Status = AcpiHwValidateRegister (Reg, 32, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Initialize entire 32-bit return value to zero */ + + *Value = 0; + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) + Address, &Value64, Reg->BitWidth); + + *Value = (UINT32) Value64; + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) + Address, Value, Reg->BitWidth); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWrite + * + * PARAMETERS: Value - Value to be written + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max + * version of AcpiWrite, used internally since the overhead of + * 64-bit values is not needed. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwWrite ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT64 Address; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (HwWrite); + + + /* Validate contents of the GAS register */ + + Status = AcpiHwValidateRegister (Reg, 32, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) + Address, (UINT64) Value, Reg->BitWidth); + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) + Address, Value, Reg->BitWidth); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiHwClearAcpiStatus + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Clears all fixed and general purpose status bits + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwClearAcpiStatus ( + void) +{ + ACPI_STATUS Status; + ACPI_CPU_FLAGS LockFlags = 0; + + + ACPI_FUNCTION_TRACE (HwClearAcpiStatus); + + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", + ACPI_BITMASK_ALL_FIXED_STATUS, + ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); + + LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); + + /* Clear the fixed events in PM1 A/B */ + + Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); + + AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); + + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Clear the GPE Bits in all GPE registers in all GPE blocks */ + + Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); + +Exit: + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetBitRegisterInfo + * + * PARAMETERS: RegisterId - Index of ACPI Register to access + * + * RETURN: The bitmask to be used when accessing the register + * + * DESCRIPTION: Map RegisterId into a register bitmask. + * + ******************************************************************************/ + +ACPI_BIT_REGISTER_INFO * +AcpiHwGetBitRegisterInfo ( + UINT32 RegisterId) +{ + ACPI_FUNCTION_ENTRY (); + + + if (RegisterId > ACPI_BITREG_MAX) + { + ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); + return (NULL); + } + + return (&AcpiGbl_BitRegisterInfo[RegisterId]); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWritePm1Control + * + * PARAMETERS: Pm1aControl - Value to be written to PM1A control + * Pm1bControl - Value to be written to PM1B control + * + * RETURN: Status + * + * DESCRIPTION: Write the PM1 A/B control registers. These registers are + * different than than the PM1 A/B status and enable registers + * in that different values can be written to the A/B registers. + * Most notably, the SLP_TYP bits can be different, as per the + * values returned from the _Sx predefined methods. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwWritePm1Control ( + UINT32 Pm1aControl, + UINT32 Pm1bControl) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwWritePm1Control); + + + Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (AcpiGbl_FADT.XPm1bControlBlock.Address) + { + Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); + } + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwRegisterRead + * + * PARAMETERS: RegisterId - ACPI Register ID + * ReturnValue - Where the register value is returned + * + * RETURN: Status and the value read. + * + * DESCRIPTION: Read from the specified ACPI register + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwRegisterRead ( + UINT32 RegisterId, + UINT32 *ReturnValue) +{ + UINT32 Value = 0; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwRegisterRead); + + + switch (RegisterId) + { + case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwReadMultiple (&Value, + &AcpiGbl_XPm1aStatus, + &AcpiGbl_XPm1bStatus); + break; + + case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwReadMultiple (&Value, + &AcpiGbl_XPm1aEnable, + &AcpiGbl_XPm1bEnable); + break; + + case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwReadMultiple (&Value, + &AcpiGbl_FADT.XPm1aControlBlock, + &AcpiGbl_FADT.XPm1bControlBlock); + + /* + * Zero the write-only bits. From the ACPI specification, "Hardware + * Write-Only Bits": "Upon reads to registers with write-only bits, + * software masks out all write-only bits." + */ + Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; + break; + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); + break; + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); + break; + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", + RegisterId)); + Status = AE_BAD_PARAMETER; + break; + } + + if (ACPI_SUCCESS (Status)) + { + *ReturnValue = Value; + } + + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwRegisterWrite + * + * PARAMETERS: RegisterId - ACPI Register ID + * Value - The value to write + * + * RETURN: Status + * + * DESCRIPTION: Write to the specified ACPI register + * + * NOTE: In accordance with the ACPI specification, this function automatically + * preserves the value of the following bits, meaning that these bits cannot be + * changed via this interface: + * + * PM1_CONTROL[0] = SCI_EN + * PM1_CONTROL[9] + * PM1_STATUS[11] + * + * ACPI References: + * 1) Hardware Ignored Bits: When software writes to a register with ignored + * bit fields, it preserves the ignored bit fields + * 2) SCI_EN: OSPM always preserves this bit position + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwRegisterWrite ( + UINT32 RegisterId, + UINT32 Value) +{ + ACPI_STATUS Status; + UINT32 ReadValue; + + + ACPI_FUNCTION_TRACE (HwRegisterWrite); + + + switch (RegisterId) + { + case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ + /* + * Handle the "ignored" bit in PM1 Status. According to the ACPI + * specification, ignored bits are to be preserved when writing. + * Normally, this would mean a read/modify/write sequence. However, + * preserving a bit in the status register is different. Writing a + * one clears the status, and writing a zero preserves the status. + * Therefore, we must always write zero to the ignored bit. + * + * This behavior is clarified in the ACPI 4.0 specification. + */ + Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; + + Status = AcpiHwWriteMultiple (Value, + &AcpiGbl_XPm1aStatus, + &AcpiGbl_XPm1bStatus); + break; + + case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwWriteMultiple (Value, + &AcpiGbl_XPm1aEnable, + &AcpiGbl_XPm1bEnable); + break; + + case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ + /* + * Perform a read first to preserve certain bits (per ACPI spec) + * Note: This includes SCI_EN, we never want to change this bit + */ + Status = AcpiHwReadMultiple (&ReadValue, + &AcpiGbl_FADT.XPm1aControlBlock, + &AcpiGbl_FADT.XPm1bControlBlock); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); + + /* Now we can write the data */ + + Status = AcpiHwWriteMultiple (Value, + &AcpiGbl_FADT.XPm1aControlBlock, + &AcpiGbl_FADT.XPm1bControlBlock); + break; + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + /* + * For control registers, all reserved bits must be preserved, + * as per the ACPI spec. + */ + Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); + + Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); + break; + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); + break; + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + /* SMI_CMD is currently always in IO space */ + + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", + RegisterId)); + Status = AE_BAD_PARAMETER; + break; + } + +Exit: + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwReadMultiple + * + * PARAMETERS: Value - Where the register value is returned + * RegisterA - First ACPI register (required) + * RegisterB - Second ACPI register (optional) + * + * RETURN: Status + * + * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwReadMultiple ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB) +{ + UINT32 ValueA = 0; + UINT32 ValueB = 0; + ACPI_STATUS Status; + + + /* The first register is always required */ + + Status = AcpiHwRead (&ValueA, RegisterA); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Second register is optional */ + + if (RegisterB->Address) + { + Status = AcpiHwRead (&ValueB, RegisterB); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* + * OR the two return values together. No shifting or masking is necessary, + * because of how the PM1 registers are defined in the ACPI specification: + * + * "Although the bits can be split between the two register blocks (each + * register block has a unique pointer within the FADT), the bit positions + * are maintained. The register block with unimplemented bits (that is, + * those implemented in the other register block) always returns zeros, + * and writes have no side effects" + */ + *Value = (ValueA | ValueB); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWriteMultiple + * + * PARAMETERS: Value - The value to write + * RegisterA - First ACPI register (required) + * RegisterB - Second ACPI register (optional) + * + * RETURN: Status + * + * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwWriteMultiple ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB) +{ + ACPI_STATUS Status; + + + /* The first register is always required */ + + Status = AcpiHwWrite (Value, RegisterA); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Second register is optional + * + * No bit shifting or clearing is necessary, because of how the PM1 + * registers are defined in the ACPI specification: + * + * "Although the bits can be split between the two register blocks (each + * register block has a unique pointer within the FADT), the bit positions + * are maintained. The register block with unimplemented bits (that is, + * those implemented in the other register block) always returns zeros, + * and writes have no side effects" + */ + if (RegisterB->Address) + { + Status = AcpiHwWrite (Value, RegisterB); + } + + return (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/hardware/hwsleep.c b/third_party/lib/acpica/source/components/hardware/hwsleep.c new file mode 100644 index 000000000..13cf25513 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwsleep.c @@ -0,0 +1,356 @@ +/****************************************************************************** + * + * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the + * original/legacy sleep/PM registers. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwsleep") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/******************************************************************************* + * + * FUNCTION: AcpiHwLegacySleep + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLegacySleep ( + UINT8 SleepState) +{ + ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; + ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; + UINT32 Pm1aControl; + UINT32 Pm1bControl; + UINT32 InValue; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwLegacySleep); + + + SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); + SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); + + /* Clear wake status */ + + Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, + ACPI_CLEAR_STATUS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Clear all fixed and general purpose status bits */ + + Status = AcpiHwClearAcpiStatus (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * 1) Disable/Clear all GPEs + * 2) Enable all wakeup GPEs + */ + Status = AcpiHwDisableAllGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + AcpiGbl_SystemAwakeAndRunning = FALSE; + + Status = AcpiHwEnableAllWakeupGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get current value of PM1A control */ + + Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, + &Pm1aControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Entering sleep state [S%u]\n", SleepState)); + + /* Clear the SLP_EN and SLP_TYP fields */ + + Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | + SleepEnableRegInfo->AccessBitMask); + Pm1bControl = Pm1aControl; + + /* Insert the SLP_TYP bits */ + + Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); + Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); + + /* + * We split the writes of SLP_TYP and SLP_EN to workaround + * poorly implemented hardware. + */ + + /* Write #1: write the SLP_TYP data to the PM1 Control registers */ + + Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Insert the sleep enable (SLP_EN) bit */ + + Pm1aControl |= SleepEnableRegInfo->AccessBitMask; + Pm1bControl |= SleepEnableRegInfo->AccessBitMask; + + /* Flush caches, as per ACPI specification */ + + ACPI_FLUSH_CPU_CACHE (); + + /* Write #2: Write both SLP_TYP + SLP_EN */ + + Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (SleepState > ACPI_STATE_S3) + { + /* + * We wanted to sleep > S3, but it didn't happen (by virtue of the + * fact that we are still executing!) + * + * Wait ten seconds, then try again. This is to get S4/S5 to work on + * all machines. + * + * We wait so long to allow chipsets that poll this reg very slowly + * to still read the right value. Ideally, this block would go + * away entirely. + */ + AcpiOsStall (10 * ACPI_USEC_PER_SEC); + + Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, + SleepEnableRegInfo->AccessBitMask); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* Wait for transition back to Working State */ + + do + { + Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + } while (!InValue); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwLegacyWakePrep + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a + * sleep. + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLegacyWakePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; + ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; + UINT32 Pm1aControl; + UINT32 Pm1bControl; + + + ACPI_FUNCTION_TRACE (HwLegacyWakePrep); + + /* + * Set SLP_TYPE and SLP_EN to state S0. + * This is unclear from the ACPI Spec, but it is required + * by some machines. + */ + Status = AcpiGetSleepTypeData (ACPI_STATE_S0, + &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); + if (ACPI_SUCCESS (Status)) + { + SleepTypeRegInfo = + AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); + SleepEnableRegInfo = + AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); + + /* Get current value of PM1A control */ + + Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, + &Pm1aControl); + if (ACPI_SUCCESS (Status)) + { + /* Clear the SLP_EN and SLP_TYP fields */ + + Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | + SleepEnableRegInfo->AccessBitMask); + Pm1bControl = Pm1aControl; + + /* Insert the SLP_TYP bits */ + + Pm1aControl |= (AcpiGbl_SleepTypeA << + SleepTypeRegInfo->BitPosition); + Pm1bControl |= (AcpiGbl_SleepTypeB << + SleepTypeRegInfo->BitPosition); + + /* Write the control registers and ignore any errors */ + + (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwLegacyWake + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLegacyWake ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwLegacyWake); + + + /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ + + AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING); + + /* + * GPEs must be enabled before _WAK is called as GPEs + * might get fired there + * + * Restore the GPEs: + * 1) Disable/Clear all GPEs + * 2) Enable all runtime GPEs + */ + Status = AcpiHwDisableAllGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwEnableAllRuntimeGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Now we can execute _WAK, etc. Some machines require that the GPEs + * are enabled before the wake methods are executed. + */ + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState); + + /* + * Some BIOS code assumes that WAK_STS will be cleared on resume + * and use it to determine whether the system is rebooting or + * resuming. Clear WAK_STS for compatibility. + */ + (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, + ACPI_CLEAR_STATUS); + AcpiGbl_SystemAwakeAndRunning = TRUE; + + /* Enable power button */ + + (void) AcpiWriteBitRegister( + AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, + ACPI_ENABLE_EVENT); + + (void) AcpiWriteBitRegister( + AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, + ACPI_CLEAR_STATUS); + + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING); + return_ACPI_STATUS (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/hardware/hwtimer.c b/third_party/lib/acpica/source/components/hardware/hwtimer.c new file mode 100644 index 000000000..64b2a8aaf --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwtimer.c @@ -0,0 +1,233 @@ +/****************************************************************************** + * + * Name: hwtimer.c - ACPI Power Management Timer Interface + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwtimer") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/****************************************************************************** + * + * FUNCTION: AcpiGetTimerResolution + * + * PARAMETERS: Resolution - Where the resolution is returned + * + * RETURN: Status and timer resolution + * + * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTimerResolution ( + UINT32 *Resolution) +{ + ACPI_FUNCTION_TRACE (AcpiGetTimerResolution); + + + if (!Resolution) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0) + { + *Resolution = 24; + } + else + { + *Resolution = 32; + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTimerResolution) + + +/****************************************************************************** + * + * FUNCTION: AcpiGetTimer + * + * PARAMETERS: Ticks - Where the timer value is returned + * + * RETURN: Status and current timer value (ticks) + * + * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTimer ( + UINT32 *Ticks) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiGetTimer); + + + if (!Ticks) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* ACPI 5.0A: PM Timer is optional */ + + if (!AcpiGbl_FADT.XPmTimerBlock.Address) + { + return_ACPI_STATUS (AE_SUPPORT); + } + + Status = AcpiHwRead (Ticks, &AcpiGbl_FADT.XPmTimerBlock); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTimer) + + +/****************************************************************************** + * + * FUNCTION: AcpiGetTimerDuration + * + * PARAMETERS: StartTicks - Starting timestamp + * EndTicks - End timestamp + * TimeElapsed - Where the elapsed time is returned + * + * RETURN: Status and TimeElapsed + * + * DESCRIPTION: Computes the time elapsed (in microseconds) between two + * PM Timer time stamps, taking into account the possibility of + * rollovers, the timer resolution, and timer frequency. + * + * The PM Timer's clock ticks at roughly 3.6 times per + * _microsecond_, and its clock continues through Cx state + * transitions (unlike many CPU timestamp counters) -- making it + * a versatile and accurate timer. + * + * Note that this function accommodates only a single timer + * rollover. Thus for 24-bit timers, this function should only + * be used for calculating durations less than ~4.6 seconds + * (~20 minutes for 32-bit timers) -- calculations below: + * + * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec + * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTimerDuration ( + UINT32 StartTicks, + UINT32 EndTicks, + UINT32 *TimeElapsed) +{ + ACPI_STATUS Status; + UINT32 DeltaTicks; + UINT64 Quotient; + + + ACPI_FUNCTION_TRACE (AcpiGetTimerDuration); + + + if (!TimeElapsed) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* ACPI 5.0A: PM Timer is optional */ + + if (!AcpiGbl_FADT.XPmTimerBlock.Address) + { + return_ACPI_STATUS (AE_SUPPORT); + } + + /* + * Compute Tick Delta: + * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. + */ + if (StartTicks < EndTicks) + { + DeltaTicks = EndTicks - StartTicks; + } + else if (StartTicks > EndTicks) + { + if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0) + { + /* 24-bit Timer */ + + DeltaTicks = (((0x00FFFFFF - StartTicks) + EndTicks) & 0x00FFFFFF); + } + else + { + /* 32-bit Timer */ + + DeltaTicks = (0xFFFFFFFF - StartTicks) + EndTicks; + } + } + else /* StartTicks == EndTicks */ + { + *TimeElapsed = 0; + return_ACPI_STATUS (AE_OK); + } + + /* + * Compute Duration (Requires a 64-bit multiply and divide): + * + * TimeElapsed (microseconds) = + * (DeltaTicks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY; + */ + Status = AcpiUtShortDivide (((UINT64) DeltaTicks) * ACPI_USEC_PER_SEC, + ACPI_PM_TIMER_FREQUENCY, &Quotient, NULL); + + *TimeElapsed = (UINT32) Quotient; + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTimerDuration) + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/third_party/lib/acpica/source/components/hardware/hwvalid.c b/third_party/lib/acpica/source/components/hardware/hwvalid.c new file mode 100644 index 000000000..64507d041 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwvalid.c @@ -0,0 +1,363 @@ +/****************************************************************************** + * + * Module Name: hwvalid - I/O request validation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwvalid") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwValidateIoRequest ( + ACPI_IO_ADDRESS Address, + UINT32 BitWidth); + + +/* + * Protected I/O ports. Some ports are always illegal, and some are + * conditionally illegal. This table must remain ordered by port address. + * + * The table is used to implement the Microsoft port access rules that + * first appeared in Windows XP. Some ports are always illegal, and some + * ports are only illegal if the BIOS calls _OSI with a WinXP string or + * later (meaning that the BIOS itelf is post-XP.) + * + * This provides ACPICA with the desired port protections and + * Microsoft compatibility. + * + * Description of port entries: + * DMA: DMA controller + * PIC0: Programmable Interrupt Controller (8259A) + * PIT1: System Timer 1 + * PIT2: System Timer 2 failsafe + * RTC: Real-time clock + * CMOS: Extended CMOS + * DMA1: DMA 1 page registers + * DMA1L: DMA 1 Ch 0 low page + * DMA2: DMA 2 page registers + * DMA2L: DMA 2 low page refresh + * ARBC: Arbitration control + * SETUP: Reserved system board setup + * POS: POS channel select + * PIC1: Cascaded PIC + * IDMA: ISA DMA + * ELCR: PIC edge/level registers + * PCI: PCI configuration space + */ +static const ACPI_PORT_INFO AcpiProtectedPorts[] = +{ + {"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, + {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, + {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, + {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, + {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, + {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, + {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, + {"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, + {"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP}, + {"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, + {"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, + {"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, + {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, + {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, + {"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, + {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, + {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} +}; + +#define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (AcpiProtectedPorts) + + +/****************************************************************************** + * + * FUNCTION: AcpiHwValidateIoRequest + * + * PARAMETERS: Address Address of I/O port/register + * BitWidth Number of bits (8,16,32) + * + * RETURN: Status + * + * DESCRIPTION: Validates an I/O request (address/length). Certain ports are + * always illegal and some ports are only illegal depending on + * the requests the BIOS AML code makes to the predefined + * _OSI method. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwValidateIoRequest ( + ACPI_IO_ADDRESS Address, + UINT32 BitWidth) +{ + UINT32 i; + UINT32 ByteWidth; + ACPI_IO_ADDRESS LastAddress; + const ACPI_PORT_INFO *PortInfo; + + + ACPI_FUNCTION_TRACE (HwValidateIoRequest); + + + /* Supported widths are 8/16/32 */ + + if ((BitWidth != 8) && + (BitWidth != 16) && + (BitWidth != 32)) + { + ACPI_ERROR ((AE_INFO, + "Bad BitWidth parameter: %8.8X", BitWidth)); + return (AE_BAD_PARAMETER); + } + + PortInfo = AcpiProtectedPorts; + ByteWidth = ACPI_DIV_8 (BitWidth); + LastAddress = Address + ByteWidth - 1; + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Address %8.8X%8.8X LastAddress %8.8X%8.8X Length %X", + ACPI_FORMAT_UINT64 (Address), ACPI_FORMAT_UINT64 (LastAddress), + ByteWidth)); + + /* Maximum 16-bit address in I/O space */ + + if (LastAddress > ACPI_UINT16_MAX) + { + ACPI_ERROR ((AE_INFO, + "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", + ACPI_FORMAT_UINT64 (Address), ByteWidth)); + return_ACPI_STATUS (AE_LIMIT); + } + + /* Exit if requested address is not within the protected port table */ + + if (Address > AcpiProtectedPorts[ACPI_PORT_INFO_ENTRIES - 1].End) + { + return_ACPI_STATUS (AE_OK); + } + + /* Check request against the list of protected I/O ports */ + + for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, PortInfo++) + { + /* + * Check if the requested address range will write to a reserved + * port. Four cases to consider: + * + * 1) Address range is contained completely in the port address range + * 2) Address range overlaps port range at the port range start + * 3) Address range overlaps port range at the port range end + * 4) Address range completely encompasses the port range + */ + if ((Address <= PortInfo->End) && (LastAddress >= PortInfo->Start)) + { + /* Port illegality may depend on the _OSI calls made by the BIOS */ + + if (AcpiGbl_OsiData >= PortInfo->OsiDependency) + { + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)", + ACPI_FORMAT_UINT64 (Address), ByteWidth, PortInfo->Name, + PortInfo->Start, PortInfo->End)); + + return_ACPI_STATUS (AE_AML_ILLEGAL_ADDRESS); + } + } + + /* Finished if address range ends before the end of this port */ + + if (LastAddress <= PortInfo->End) + { + break; + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwReadPort + * + * PARAMETERS: Address Address of I/O port/register to read + * Value Where value is placed + * Width Number of bits + * + * RETURN: Status and value read from port + * + * DESCRIPTION: Read data from an I/O port or register. This is a front-end + * to AcpiOsReadPort that performs validation on both the port + * address and the length. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiHwReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + ACPI_STATUS Status; + UINT32 OneByte; + UINT32 i; + + + /* Truncate address to 16 bits if requested */ + + if (AcpiGbl_TruncateIoAddresses) + { + Address &= ACPI_UINT16_MAX; + } + + /* Validate the entire request and perform the I/O */ + + Status = AcpiHwValidateIoRequest (Address, Width); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiOsReadPort (Address, Value, Width); + return (Status); + } + + if (Status != AE_AML_ILLEGAL_ADDRESS) + { + return (Status); + } + + /* + * There has been a protection violation within the request. Fall + * back to byte granularity port I/O and ignore the failing bytes. + * This provides Windows compatibility. + */ + for (i = 0, *Value = 0; i < Width; i += 8) + { + /* Validate and read one byte */ + + if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) + { + Status = AcpiOsReadPort (Address, &OneByte, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *Value |= (OneByte << i); + } + + Address++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWritePort + * + * PARAMETERS: Address Address of I/O port/register to write + * Value Value to write + * Width Number of bits + * + * RETURN: Status + * + * DESCRIPTION: Write data to an I/O port or register. This is a front-end + * to AcpiOsWritePort that performs validation on both the port + * address and the length. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiHwWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + ACPI_STATUS Status; + UINT32 i; + + + /* Truncate address to 16 bits if requested */ + + if (AcpiGbl_TruncateIoAddresses) + { + Address &= ACPI_UINT16_MAX; + } + + /* Validate the entire request and perform the I/O */ + + Status = AcpiHwValidateIoRequest (Address, Width); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiOsWritePort (Address, Value, Width); + return (Status); + } + + if (Status != AE_AML_ILLEGAL_ADDRESS) + { + return (Status); + } + + /* + * There has been a protection violation within the request. Fall + * back to byte granularity port I/O and ignore the failing bytes. + * This provides Windows compatibility. + */ + for (i = 0; i < Width; i += 8) + { + /* Validate and write one byte */ + + if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) + { + Status = AcpiOsWritePort (Address, (Value >> i) & 0xFF, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + Address++; + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/hardware/hwxface.c b/third_party/lib/acpica/source/components/hardware/hwxface.c new file mode 100644 index 000000000..e8b2fe655 --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwxface.c @@ -0,0 +1,663 @@ +/****************************************************************************** + * + * Module Name: hwxface - Public ACPICA hardware interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwxface") + + +/****************************************************************************** + * + * FUNCTION: AcpiReset + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Set reset register in memory or IO space. Note: Does not + * support reset register in PCI config space, this must be + * handled separately. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReset ( + void) +{ + ACPI_GENERIC_ADDRESS *ResetReg; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiReset); + + + ResetReg = &AcpiGbl_FADT.ResetRegister; + + /* Check if the reset register is supported */ + + if (!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) || + !ResetReg->Address) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + if (ResetReg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO) + { + /* + * For I/O space, write directly to the OSL. This bypasses the port + * validation mechanism, which may block a valid write to the reset + * register. + * + * NOTE: + * The ACPI spec requires the reset register width to be 8, so we + * hardcode it here and ignore the FADT value. This maintains + * compatibility with other ACPI implementations that have allowed + * BIOS code with bad register width values to go unnoticed. + */ + Status = AcpiOsWritePort ((ACPI_IO_ADDRESS) ResetReg->Address, + AcpiGbl_FADT.ResetValue, ACPI_RESET_REGISTER_WIDTH); + } + else + { + /* Write the reset value to the reset register */ + + Status = AcpiHwWrite (AcpiGbl_FADT.ResetValue, ResetReg); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiReset) + + +/****************************************************************************** + * + * FUNCTION: AcpiRead + * + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Read from either memory or IO space. + * + * LIMITATIONS: + * BitWidth must be exactly 8, 16, 32, or 64. + * SpaceID must be SystemMemory or SystemIO. + * BitOffset and AccessWidth are currently ignored, as there has + * not been a need to implement these. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRead ( + UINT64 *ReturnValue, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT32 ValueLo; + UINT32 ValueHi; + UINT32 Width; + UINT64 Address; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (AcpiRead); + + + if (!ReturnValue) + { + return (AE_BAD_PARAMETER); + } + + /* Validate contents of the GAS register. Allow 64-bit transfers */ + + Status = AcpiHwValidateRegister (Reg, 64, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Two address spaces supported: Memory or I/O. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) + Address, ReturnValue, Reg->BitWidth); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + ValueLo = 0; + ValueHi = 0; + + Width = Reg->BitWidth; + if (Width == 64) + { + Width = 32; /* Break into two 32-bit transfers */ + } + + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) + Address, &ValueLo, Width); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Reg->BitWidth == 64) + { + /* Read the top 32 bits */ + + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) + (Address + 4), &ValueHi, 32); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Set the return value only if status is AE_OK */ + + *ReturnValue = (ValueLo | ((UINT64) ValueHi << 32)); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n", + ACPI_FORMAT_UINT64 (*ReturnValue), Reg->BitWidth, + ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiRead) + + +/****************************************************************************** + * + * FUNCTION: AcpiWrite + * + * PARAMETERS: Value - Value to be written + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Write to either memory or IO space. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWrite ( + UINT64 Value, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT32 Width; + UINT64 Address; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (AcpiWrite); + + + /* Validate contents of the GAS register. Allow 64-bit transfers */ + + Status = AcpiHwValidateRegister (Reg, 64, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) + Address, Value, Reg->BitWidth); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Width = Reg->BitWidth; + if (Width == 64) + { + Width = 32; /* Break into two 32-bit transfers */ + } + + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) + Address, ACPI_LODWORD (Value), Width); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Reg->BitWidth == 64) + { + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) + (Address + 4), ACPI_HIDWORD (Value), 32); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", + ACPI_FORMAT_UINT64 (Value), Reg->BitWidth, + ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWrite) + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiReadBitRegister + * + * PARAMETERS: RegisterId - ID of ACPI Bit Register to access + * ReturnValue - Value that was read from the register, + * normalized to bit position zero. + * + * RETURN: Status and the value read from the specified Register. Value + * returned is normalized to bit0 (is shifted all the way right) + * + * DESCRIPTION: ACPI BitRegister read function. Does not acquire the HW lock. + * + * SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and + * PM2 Control. + * + * Note: The hardware lock is not required when reading the ACPI bit registers + * since almost all of them are single bit and it does not matter that + * the parent hardware register can be split across two physical + * registers. The only multi-bit field is SLP_TYP in the PM1 control + * register, but this field does not cross an 8-bit boundary (nor does + * it make much sense to actually read this field.) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReadBitRegister ( + UINT32 RegisterId, + UINT32 *ReturnValue) +{ + ACPI_BIT_REGISTER_INFO *BitRegInfo; + UINT32 RegisterValue; + UINT32 Value; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_U32 (AcpiReadBitRegister, RegisterId); + + + /* Get the info structure corresponding to the requested ACPI Register */ + + BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId); + if (!BitRegInfo) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Read the entire parent register */ + + Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister, + &RegisterValue); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Normalize the value that was read, mask off other bits */ + + Value = ((RegisterValue & BitRegInfo->AccessBitMask) + >> BitRegInfo->BitPosition); + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "BitReg %X, ParentReg %X, Actual %8.8X, ReturnValue %8.8X\n", + RegisterId, BitRegInfo->ParentRegister, RegisterValue, Value)); + + *ReturnValue = Value; + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiReadBitRegister) + + +/******************************************************************************* + * + * FUNCTION: AcpiWriteBitRegister + * + * PARAMETERS: RegisterId - ID of ACPI Bit Register to access + * Value - Value to write to the register, in bit + * position zero. The bit is automatically + * shifted to the correct position. + * + * RETURN: Status + * + * DESCRIPTION: ACPI Bit Register write function. Acquires the hardware lock + * since most operations require a read/modify/write sequence. + * + * SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and + * PM2 Control. + * + * Note that at this level, the fact that there may be actually two + * hardware registers (A and B - and B may not exist) is abstracted. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWriteBitRegister ( + UINT32 RegisterId, + UINT32 Value) +{ + ACPI_BIT_REGISTER_INFO *BitRegInfo; + ACPI_CPU_FLAGS LockFlags; + UINT32 RegisterValue; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_U32 (AcpiWriteBitRegister, RegisterId); + + + /* Get the info structure corresponding to the requested ACPI Register */ + + BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId); + if (!BitRegInfo) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); + + /* + * At this point, we know that the parent register is one of the + * following: PM1 Status, PM1 Enable, PM1 Control, or PM2 Control + */ + if (BitRegInfo->ParentRegister != ACPI_REGISTER_PM1_STATUS) + { + /* + * 1) Case for PM1 Enable, PM1 Control, and PM2 Control + * + * Perform a register read to preserve the bits that we are not + * interested in + */ + Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister, + &RegisterValue); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* + * Insert the input bit into the value that was just read + * and write the register + */ + ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition, + BitRegInfo->AccessBitMask, Value); + + Status = AcpiHwRegisterWrite (BitRegInfo->ParentRegister, + RegisterValue); + } + else + { + /* + * 2) Case for PM1 Status + * + * The Status register is different from the rest. Clear an event + * by writing 1, writing 0 has no effect. So, the only relevant + * information is the single bit we're interested in, all others + * should be written as 0 so they will be left unchanged. + */ + RegisterValue = ACPI_REGISTER_PREPARE_BITS (Value, + BitRegInfo->BitPosition, BitRegInfo->AccessBitMask); + + /* No need to write the register if value is all zeros */ + + if (RegisterValue) + { + Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, + RegisterValue); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "BitReg %X, ParentReg %X, Value %8.8X, Actual %8.8X\n", + RegisterId, BitRegInfo->ParentRegister, Value, RegisterValue)); + + +UnlockAndExit: + + AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWriteBitRegister) + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiGetSleepTypeData + * + * PARAMETERS: SleepState - Numeric sleep state + * *SleepTypeA - Where SLP_TYPa is returned + * *SleepTypeB - Where SLP_TYPb is returned + * + * RETURN: Status + * + * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested + * sleep state via the appropriate \_Sx object. + * + * The sleep state package returned from the corresponding \_Sx_ object + * must contain at least one integer. + * + * March 2005: + * Added support for a package that contains two integers. This + * goes against the ACPI specification which defines this object as a + * package with one encoded DWORD integer. However, existing practice + * by many BIOS vendors is to return a package with 2 or more integer + * elements, at least one per sleep type (A/B). + * + * January 2013: + * Therefore, we must be prepared to accept a package with either a + * single integer or multiple integers. + * + * The single integer DWORD format is as follows: + * BYTE 0 - Value for the PM1A SLP_TYP register + * BYTE 1 - Value for the PM1B SLP_TYP register + * BYTE 2-3 - Reserved + * + * The dual integer format is as follows: + * Integer 0 - Value for the PM1A SLP_TYP register + * Integer 1 - Value for the PM1A SLP_TYP register + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetSleepTypeData ( + UINT8 SleepState, + UINT8 *SleepTypeA, + UINT8 *SleepTypeB) +{ + ACPI_STATUS Status; + ACPI_EVALUATE_INFO *Info; + ACPI_OPERAND_OBJECT **Elements; + + + ACPI_FUNCTION_TRACE (AcpiGetSleepTypeData); + + + /* Validate parameters */ + + if ((SleepState > ACPI_S_STATES_MAX) || + !SleepTypeA || !SleepTypeB) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Allocate the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Evaluate the \_Sx namespace object containing the register values + * for this state + */ + Info->RelativePathname = ACPI_CAST_PTR (char, + AcpiGbl_SleepStateNames[SleepState]); + + Status = AcpiNsEvaluate (Info); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + /* The _Sx states are optional, ignore NOT_FOUND */ + + goto FinalCleanup; + } + + goto WarningCleanup; + } + + /* Must have a return object */ + + if (!Info->ReturnObject) + { + ACPI_ERROR ((AE_INFO, "No Sleep State object returned from [%s]", + Info->RelativePathname)); + Status = AE_AML_NO_RETURN_VALUE; + goto WarningCleanup; + } + + /* Return object must be of type Package */ + + if (Info->ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + ACPI_ERROR ((AE_INFO, "Sleep State return object is not a Package")); + Status = AE_AML_OPERAND_TYPE; + goto ReturnValueCleanup; + } + + /* + * Any warnings about the package length or the object types have + * already been issued by the predefined name module -- there is no + * need to repeat them here. + */ + Elements = Info->ReturnObject->Package.Elements; + switch (Info->ReturnObject->Package.Count) + { + case 0: + + Status = AE_AML_PACKAGE_LIMIT; + break; + + case 1: + + if (Elements[0]->Common.Type != ACPI_TYPE_INTEGER) + { + Status = AE_AML_OPERAND_TYPE; + break; + } + + /* A valid _Sx_ package with one integer */ + + *SleepTypeA = (UINT8) Elements[0]->Integer.Value; + *SleepTypeB = (UINT8) (Elements[0]->Integer.Value >> 8); + break; + + case 2: + default: + + if ((Elements[0]->Common.Type != ACPI_TYPE_INTEGER) || + (Elements[1]->Common.Type != ACPI_TYPE_INTEGER)) + { + Status = AE_AML_OPERAND_TYPE; + break; + } + + /* A valid _Sx_ package with two integers */ + + *SleepTypeA = (UINT8) Elements[0]->Integer.Value; + *SleepTypeB = (UINT8) Elements[1]->Integer.Value; + break; + } + +ReturnValueCleanup: + AcpiUtRemoveReference (Info->ReturnObject); + +WarningCleanup: + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While evaluating Sleep State [%s]", + Info->RelativePathname)); + } + +FinalCleanup: + ACPI_FREE (Info); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetSleepTypeData) diff --git a/third_party/lib/acpica/source/components/hardware/hwxfsleep.c b/third_party/lib/acpica/source/components/hardware/hwxfsleep.c new file mode 100644 index 000000000..1e43d987c --- /dev/null +++ b/third_party/lib/acpica/source/components/hardware/hwxfsleep.c @@ -0,0 +1,501 @@ +/****************************************************************************** + * + * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwxfsleep") + +/* Local prototypes */ + +#if (!ACPI_REDUCED_HARDWARE) +static ACPI_STATUS +AcpiHwSetFirmwareWakingVector ( + ACPI_TABLE_FACS *Facs, + ACPI_PHYSICAL_ADDRESS PhysicalAddress, + ACPI_PHYSICAL_ADDRESS PhysicalAddress64); +#endif + +static ACPI_STATUS +AcpiHwSleepDispatch ( + UINT8 SleepState, + UINT32 FunctionId); + +/* + * Dispatch table used to efficiently branch to the various sleep + * functions. + */ +#define ACPI_SLEEP_FUNCTION_ID 0 +#define ACPI_WAKE_PREP_FUNCTION_ID 1 +#define ACPI_WAKE_FUNCTION_ID 2 + +/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ + +static ACPI_SLEEP_FUNCTIONS AcpiSleepDispatch[] = +{ + {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep), AcpiHwExtendedSleep}, + {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep), AcpiHwExtendedWakePrep}, + {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake), AcpiHwExtendedWake} +}; + + +/* + * These functions are removed for the ACPI_REDUCED_HARDWARE case: + * AcpiSetFirmwareWakingVector + * AcpiEnterSleepStateS4bios + */ + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiHwSetFirmwareWakingVector + * + * PARAMETERS: Facs - Pointer to FACS table + * PhysicalAddress - 32-bit physical address of ACPI real mode + * entry point + * PhysicalAddress64 - 64-bit physical address of ACPI protected + * entry point + * + * RETURN: Status + * + * DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwSetFirmwareWakingVector ( + ACPI_TABLE_FACS *Facs, + ACPI_PHYSICAL_ADDRESS PhysicalAddress, + ACPI_PHYSICAL_ADDRESS PhysicalAddress64) +{ + ACPI_FUNCTION_TRACE (AcpiHwSetFirmwareWakingVector); + + + /* + * According to the ACPI specification 2.0c and later, the 64-bit + * waking vector should be cleared and the 32-bit waking vector should + * be used, unless we want the wake-up code to be called by the BIOS in + * Protected Mode. Some systems (for example HP dv5-1004nr) are known + * to fail to resume if the 64-bit vector is used. + */ + + /* Set the 32-bit vector */ + + Facs->FirmwareWakingVector = (UINT32) PhysicalAddress; + + if (Facs->Length > 32) + { + if (Facs->Version >= 1) + { + /* Set the 64-bit vector */ + + Facs->XFirmwareWakingVector = PhysicalAddress64; + } + else + { + /* Clear the 64-bit vector if it exists */ + + Facs->XFirmwareWakingVector = 0; + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiSetFirmwareWakingVector + * + * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode + * entry point + * PhysicalAddress64 - 64-bit physical address of ACPI protected + * entry point + * + * RETURN: Status + * + * DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetFirmwareWakingVector ( + ACPI_PHYSICAL_ADDRESS PhysicalAddress, + ACPI_PHYSICAL_ADDRESS PhysicalAddress64) +{ + + ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); + + if (AcpiGbl_FACS) + { + (void) AcpiHwSetFirmwareWakingVector (AcpiGbl_FACS, + PhysicalAddress, PhysicalAddress64); + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) + + +/******************************************************************************* + * + * FUNCTION: AcpiEnterSleepStateS4bios + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Perform a S4 bios request. + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnterSleepStateS4bios ( + void) +{ + UINT32 InValue; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); + + + /* Clear the wake status bit (PM1) */ + + Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwClearAcpiStatus (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * 1) Disable/Clear all GPEs + * 2) Enable all wakeup GPEs + */ + Status = AcpiHwDisableAllGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + AcpiGbl_SystemAwakeAndRunning = FALSE; + + Status = AcpiHwEnableAllWakeupGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_FLUSH_CPU_CACHE (); + + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, + (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); + + do { + AcpiOsStall (ACPI_USEC_PER_MSEC); + Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + } while (!InValue); + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiHwSleepDispatch + * + * PARAMETERS: SleepState - Which sleep state to enter/exit + * FunctionId - Sleep, WakePrep, or Wake + * + * RETURN: Status from the invoked sleep handling function. + * + * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling + * function. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwSleepDispatch ( + UINT8 SleepState, + UINT32 FunctionId) +{ + ACPI_STATUS Status; + ACPI_SLEEP_FUNCTIONS *SleepFunctions = &AcpiSleepDispatch[FunctionId]; + + +#if (!ACPI_REDUCED_HARDWARE) + /* + * If the Hardware Reduced flag is set (from the FADT), we must + * use the extended sleep registers (FADT). Note: As per the ACPI + * specification, these extended registers are to be used for HW-reduced + * platforms only. They are not general-purpose replacements for the + * legacy PM register sleep support. + */ + if (AcpiGbl_ReducedHardware) + { + Status = SleepFunctions->ExtendedFunction (SleepState); + } + else + { + /* Legacy sleep */ + + Status = SleepFunctions->LegacyFunction (SleepState); + } + + return (Status); + +#else + /* + * For the case where reduced-hardware-only code is being generated, + * we know that only the extended sleep registers are available + */ + Status = SleepFunctions->ExtendedFunction (SleepState); + return (Status); + +#endif /* !ACPI_REDUCED_HARDWARE */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEnterSleepStatePrep + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Prepare to enter a system sleep state. + * This function must execute with interrupts enabled. + * We break sleeping into 2 stages so that OSPM can handle + * various OS-specific tasks between the two steps. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnterSleepStatePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg; + UINT32 SstValue; + + + ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); + + + Status = AcpiGetSleepTypeData (SleepState, + &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Execute the _PTS method (Prepare To Sleep) */ + + ArgList.Count = 1; + ArgList.Pointer = &Arg; + Arg.Type = ACPI_TYPE_INTEGER; + Arg.Integer.Value = SleepState; + + Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL); + if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) + { + return_ACPI_STATUS (Status); + } + + /* Setup the argument to the _SST method (System STatus) */ + + switch (SleepState) + { + case ACPI_STATE_S0: + + SstValue = ACPI_SST_WORKING; + break; + + case ACPI_STATE_S1: + case ACPI_STATE_S2: + case ACPI_STATE_S3: + + SstValue = ACPI_SST_SLEEPING; + break; + + case ACPI_STATE_S4: + + SstValue = ACPI_SST_SLEEP_CONTEXT; + break; + + default: + + SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */ + break; + } + + /* + * Set the system indicators to show the desired sleep state. + * _SST is an optional method (return no error if not found) + */ + AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, SstValue); + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) + + +/******************************************************************************* + * + * FUNCTION: AcpiEnterSleepState + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnterSleepState ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiEnterSleepState); + + + if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || + (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) + { + ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", + AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + + Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnterSleepState) + + +/******************************************************************************* + * + * FUNCTION: AcpiLeaveSleepStatePrep + * + * PARAMETERS: SleepState - Which sleep state we are exiting + * + * RETURN: Status + * + * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a + * sleep. Called with interrupts DISABLED. + * We break wake/resume into 2 stages so that OSPM can handle + * various OS-specific tasks between the two steps. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiLeaveSleepStatePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep); + + + Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep) + + +/******************************************************************************* + * + * FUNCTION: AcpiLeaveSleepState + * + * PARAMETERS: SleepState - Which sleep state we are exiting + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiLeaveSleepState ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); + + + Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) diff --git a/third_party/lib/acpica/source/components/namespace/nsaccess.c b/third_party/lib/acpica/source/components/namespace/nsaccess.c new file mode 100644 index 000000000..64db3a9ea --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsaccess.c @@ -0,0 +1,704 @@ +/******************************************************************************* + * + * Module Name: nsaccess - Top-level functions for accessing ACPI namespace + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsaccess") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsRootInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Allocate and initialize the default root named objects + * + * MUTEX: Locks namespace for entire execution + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsRootInitialize ( + void) +{ + ACPI_STATUS Status; + const ACPI_PREDEFINED_NAMES *InitVal = NULL; + ACPI_NAMESPACE_NODE *NewNode; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STRING Val = NULL; + + + ACPI_FUNCTION_TRACE (NsRootInitialize); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * The global root ptr is initially NULL, so a non-NULL value indicates + * that AcpiNsRootInitialize() has already been called; just return. + */ + if (AcpiGbl_RootNode) + { + Status = AE_OK; + goto UnlockAndExit; + } + + /* + * Tell the rest of the subsystem that the root is initialized + * (This is OK because the namespace is locked) + */ + AcpiGbl_RootNode = &AcpiGbl_RootNodeStruct; + + /* Enter the pre-defined names in the name table */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Entering predefined entries into namespace\n")); + + for (InitVal = AcpiGbl_PreDefinedNames; InitVal->Name; InitVal++) + { + /* _OSI is optional for now, will be permanent later */ + + if (!strcmp (InitVal->Name, "_OSI") && !AcpiGbl_CreateOsiMethod) + { + continue; + } + + Status = AcpiNsLookup (NULL, InitVal->Name, InitVal->Type, + ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, + NULL, &NewNode); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not create predefined name %s", + InitVal->Name)); + continue; + } + + /* + * Name entered successfully. If entry in PreDefinedNames[] specifies + * an initial value, create the initial value. + */ + if (InitVal->Val) + { + Status = AcpiOsPredefinedOverride (InitVal, &Val); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, + "Could not override predefined %s", + InitVal->Name)); + } + + if (!Val) + { + Val = InitVal->Val; + } + + /* + * Entry requests an initial value, allocate a + * descriptor for it. + */ + ObjDesc = AcpiUtCreateInternalObject (InitVal->Type); + if (!ObjDesc) + { + Status = AE_NO_MEMORY; + goto UnlockAndExit; + } + + /* + * Convert value string from table entry to + * internal representation. Only types actually + * used for initial values are implemented here. + */ + switch (InitVal->Type) + { + case ACPI_TYPE_METHOD: + + ObjDesc->Method.ParamCount = (UINT8) ACPI_TO_INTEGER (Val); + ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID; + +#if defined (ACPI_ASL_COMPILER) + + /* Save the parameter count for the iASL compiler */ + + NewNode->Value = ObjDesc->Method.ParamCount; +#else + /* Mark this as a very SPECIAL method */ + + ObjDesc->Method.InfoFlags = ACPI_METHOD_INTERNAL_ONLY; + ObjDesc->Method.Dispatch.Implementation = AcpiUtOsiImplementation; +#endif + break; + + case ACPI_TYPE_INTEGER: + + ObjDesc->Integer.Value = ACPI_TO_INTEGER (Val); + break; + + case ACPI_TYPE_STRING: + + /* Build an object around the static string */ + + ObjDesc->String.Length = (UINT32) strlen (Val); + ObjDesc->String.Pointer = Val; + ObjDesc->Common.Flags |= AOPOBJ_STATIC_POINTER; + break; + + case ACPI_TYPE_MUTEX: + + ObjDesc->Mutex.Node = NewNode; + ObjDesc->Mutex.SyncLevel = (UINT8) (ACPI_TO_INTEGER (Val) - 1); + + /* Create a mutex */ + + Status = AcpiOsCreateMutex (&ObjDesc->Mutex.OsMutex); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ObjDesc); + goto UnlockAndExit; + } + + /* Special case for ACPI Global Lock */ + + if (strcmp (InitVal->Name, "_GL_") == 0) + { + AcpiGbl_GlobalLockMutex = ObjDesc; + + /* Create additional counting semaphore for global lock */ + + Status = AcpiOsCreateSemaphore ( + 1, 0, &AcpiGbl_GlobalLockSemaphore); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ObjDesc); + goto UnlockAndExit; + } + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Unsupported initial type value 0x%X", + InitVal->Type)); + AcpiUtRemoveReference (ObjDesc); + ObjDesc = NULL; + continue; + } + + /* Store pointer to value descriptor in the Node */ + + Status = AcpiNsAttachObject (NewNode, ObjDesc, + ObjDesc->Common.Type); + + /* Remove local reference to the object */ + + AcpiUtRemoveReference (ObjDesc); + } + } + + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + /* Save a handle to "_GPE", it is always present */ + + if (ACPI_SUCCESS (Status)) + { + Status = AcpiNsGetNode (NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH, + &AcpiGbl_FadtGpeDevice); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsLookup + * + * PARAMETERS: ScopeInfo - Current scope info block + * Pathname - Search pathname, in internal format + * (as represented in the AML stream) + * Type - Type associated with name + * InterpreterMode - IMODE_LOAD_PASS2 => add name if not found + * Flags - Flags describing the search restrictions + * WalkState - Current state of the walk + * ReturnNode - Where the Node is placed (if found + * or created successfully) + * + * RETURN: Status + * + * DESCRIPTION: Find or enter the passed name in the name space. + * Log an error if name not found in Exec mode. + * + * MUTEX: Assumes namespace is locked. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsLookup ( + ACPI_GENERIC_STATE *ScopeInfo, + char *Pathname, + ACPI_OBJECT_TYPE Type, + ACPI_INTERPRETER_MODE InterpreterMode, + UINT32 Flags, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + ACPI_STATUS Status; + char *Path = Pathname; + ACPI_NAMESPACE_NODE *PrefixNode; + ACPI_NAMESPACE_NODE *CurrentNode = NULL; + ACPI_NAMESPACE_NODE *ThisNode = NULL; + UINT32 NumSegments; + UINT32 NumCarats; + ACPI_NAME SimpleName; + ACPI_OBJECT_TYPE TypeToCheckFor; + ACPI_OBJECT_TYPE ThisSearchType; + UINT32 SearchParentFlag = ACPI_NS_SEARCH_PARENT; + UINT32 LocalFlags; + + + ACPI_FUNCTION_TRACE (NsLookup); + + + if (!ReturnNode) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + LocalFlags = Flags & + ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_OVERRIDE_IF_FOUND | + ACPI_NS_SEARCH_PARENT); + *ReturnNode = ACPI_ENTRY_NOT_FOUND; + AcpiGbl_NsLookupCount++; + + if (!AcpiGbl_RootNode) + { + return_ACPI_STATUS (AE_NO_NAMESPACE); + } + + /* Get the prefix scope. A null scope means use the root scope */ + + if ((!ScopeInfo) || + (!ScopeInfo->Scope.Node)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Null scope prefix, using root node (%p)\n", + AcpiGbl_RootNode)); + + PrefixNode = AcpiGbl_RootNode; + } + else + { + PrefixNode = ScopeInfo->Scope.Node; + if (ACPI_GET_DESCRIPTOR_TYPE (PrefixNode) != ACPI_DESC_TYPE_NAMED) + { + ACPI_ERROR ((AE_INFO, "%p is not a namespace node [%s]", + PrefixNode, AcpiUtGetDescriptorName (PrefixNode))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + if (!(Flags & ACPI_NS_PREFIX_IS_SCOPE)) + { + /* + * This node might not be a actual "scope" node (such as a + * Device/Method, etc.) It could be a Package or other object + * node. Backup up the tree to find the containing scope node. + */ + while (!AcpiNsOpensScope (PrefixNode->Type) && + PrefixNode->Type != ACPI_TYPE_ANY) + { + PrefixNode = PrefixNode->Parent; + } + } + } + + /* Save type. TBD: may be no longer necessary */ + + TypeToCheckFor = Type; + + /* + * Begin examination of the actual pathname + */ + if (!Pathname) + { + /* A Null NamePath is allowed and refers to the root */ + + NumSegments = 0; + ThisNode = AcpiGbl_RootNode; + Path = ""; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Null Pathname (Zero segments), Flags=%X\n", Flags)); + } + else + { + /* + * Name pointer is valid (and must be in internal name format) + * + * Check for scope prefixes: + * + * As represented in the AML stream, a namepath consists of an + * optional scope prefix followed by a name segment part. + * + * If present, the scope prefix is either a Root Prefix (in + * which case the name is fully qualified), or one or more + * Parent Prefixes (in which case the name's scope is relative + * to the current scope). + */ + if (*Path == (UINT8) AML_ROOT_PREFIX) + { + /* Pathname is fully qualified, start from the root */ + + ThisNode = AcpiGbl_RootNode; + SearchParentFlag = ACPI_NS_NO_UPSEARCH; + + /* Point to name segment part */ + + Path++; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Path is absolute from root [%p]\n", ThisNode)); + } + else + { + /* Pathname is relative to current scope, start there */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching relative to prefix scope [%4.4s] (%p)\n", + AcpiUtGetNodeName (PrefixNode), PrefixNode)); + + /* + * Handle multiple Parent Prefixes (carat) by just getting + * the parent node for each prefix instance. + */ + ThisNode = PrefixNode; + NumCarats = 0; + while (*Path == (UINT8) AML_PARENT_PREFIX) + { + /* Name is fully qualified, no search rules apply */ + + SearchParentFlag = ACPI_NS_NO_UPSEARCH; + + /* + * Point past this prefix to the name segment + * part or the next Parent Prefix + */ + Path++; + + /* Backup to the parent node */ + + NumCarats++; + ThisNode = ThisNode->Parent; + if (!ThisNode) + { + /* Current scope has no parent scope */ + + ACPI_ERROR ((AE_INFO, + "%s: Path has too many parent prefixes (^) " + "- reached beyond root node", Pathname)); + return_ACPI_STATUS (AE_NOT_FOUND); + } + } + + if (SearchParentFlag == ACPI_NS_NO_UPSEARCH) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Search scope is [%4.4s], path has %u carat(s)\n", + AcpiUtGetNodeName (ThisNode), NumCarats)); + } + } + + /* + * Determine the number of ACPI name segments in this pathname. + * + * The segment part consists of either: + * - A Null name segment (0) + * - A DualNamePrefix followed by two 4-byte name segments + * - A MultiNamePrefix followed by a byte indicating the + * number of segments and the segments themselves. + * - A single 4-byte name segment + * + * Examine the name prefix opcode, if any, to determine the number of + * segments. + */ + switch (*Path) + { + case 0: + /* + * Null name after a root or parent prefixes. We already + * have the correct target node and there are no name segments. + */ + NumSegments = 0; + Type = ThisNode->Type; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Prefix-only Pathname (Zero name segments), Flags=%X\n", + Flags)); + break; + + case AML_DUAL_NAME_PREFIX: + + /* More than one NameSeg, search rules do not apply */ + + SearchParentFlag = ACPI_NS_NO_UPSEARCH; + + /* Two segments, point to first name segment */ + + NumSegments = 2; + Path++; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Dual Pathname (2 segments, Flags=%X)\n", Flags)); + break; + + case AML_MULTI_NAME_PREFIX_OP: + + /* More than one NameSeg, search rules do not apply */ + + SearchParentFlag = ACPI_NS_NO_UPSEARCH; + + /* Extract segment count, point to first name segment */ + + Path++; + NumSegments = (UINT32) (UINT8) *Path; + Path++; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Multi Pathname (%u Segments, Flags=%X)\n", + NumSegments, Flags)); + break; + + default: + /* + * Not a Null name, no Dual or Multi prefix, hence there is + * only one name segment and Pathname is already pointing to it. + */ + NumSegments = 1; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Simple Pathname (1 segment, Flags=%X)\n", Flags)); + break; + } + + ACPI_DEBUG_EXEC (AcpiNsPrintPathname (NumSegments, Path)); + } + + + /* + * Search namespace for each segment of the name. Loop through and + * verify (or add to the namespace) each name segment. + * + * The object type is significant only at the last name + * segment. (We don't care about the types along the path, only + * the type of the final target object.) + */ + ThisSearchType = ACPI_TYPE_ANY; + CurrentNode = ThisNode; + while (NumSegments && CurrentNode) + { + NumSegments--; + if (!NumSegments) + { + /* This is the last segment, enable typechecking */ + + ThisSearchType = Type; + + /* + * Only allow automatic parent search (search rules) if the caller + * requested it AND we have a single, non-fully-qualified NameSeg + */ + if ((SearchParentFlag != ACPI_NS_NO_UPSEARCH) && + (Flags & ACPI_NS_SEARCH_PARENT)) + { + LocalFlags |= ACPI_NS_SEARCH_PARENT; + } + + /* Set error flag according to caller */ + + if (Flags & ACPI_NS_ERROR_IF_FOUND) + { + LocalFlags |= ACPI_NS_ERROR_IF_FOUND; + } + + /* Set override flag according to caller */ + + if (Flags & ACPI_NS_OVERRIDE_IF_FOUND) + { + LocalFlags |= ACPI_NS_OVERRIDE_IF_FOUND; + } + } + + /* Extract one ACPI name from the front of the pathname */ + + ACPI_MOVE_32_TO_32 (&SimpleName, Path); + + /* Try to find the single (4 character) ACPI name */ + + Status = AcpiNsSearchAndEnter (SimpleName, WalkState, CurrentNode, + InterpreterMode, ThisSearchType, LocalFlags, &ThisNode); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + /* Name not found in ACPI namespace */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Name [%4.4s] not found in scope [%4.4s] %p\n", + (char *) &SimpleName, (char *) &CurrentNode->Name, + CurrentNode)); + } + + *ReturnNode = ThisNode; + return_ACPI_STATUS (Status); + } + + /* More segments to follow? */ + + if (NumSegments > 0) + { + /* + * If we have an alias to an object that opens a scope (such as a + * device or processor), we need to dereference the alias here so + * that we can access any children of the original node (via the + * remaining segments). + */ + if (ThisNode->Type == ACPI_TYPE_LOCAL_ALIAS) + { + if (!ThisNode->Object) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + if (AcpiNsOpensScope (((ACPI_NAMESPACE_NODE *) + ThisNode->Object)->Type)) + { + ThisNode = (ACPI_NAMESPACE_NODE *) ThisNode->Object; + } + } + } + + /* Special handling for the last segment (NumSegments == 0) */ + + else + { + /* + * Sanity typecheck of the target object: + * + * If 1) This is the last segment (NumSegments == 0) + * 2) And we are looking for a specific type + * (Not checking for TYPE_ANY) + * 3) Which is not an alias + * 4) Which is not a local type (TYPE_SCOPE) + * 5) And the type of target object is known (not TYPE_ANY) + * 6) And target object does not match what we are looking for + * + * Then we have a type mismatch. Just warn and ignore it. + */ + if ((TypeToCheckFor != ACPI_TYPE_ANY) && + (TypeToCheckFor != ACPI_TYPE_LOCAL_ALIAS) && + (TypeToCheckFor != ACPI_TYPE_LOCAL_METHOD_ALIAS) && + (TypeToCheckFor != ACPI_TYPE_LOCAL_SCOPE) && + (ThisNode->Type != ACPI_TYPE_ANY) && + (ThisNode->Type != TypeToCheckFor)) + { + /* Complain about a type mismatch */ + + ACPI_WARNING ((AE_INFO, + "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", + ACPI_CAST_PTR (char, &SimpleName), + AcpiUtGetTypeName (ThisNode->Type), + AcpiUtGetTypeName (TypeToCheckFor))); + } + + /* + * If this is the last name segment and we are not looking for a + * specific type, but the type of found object is known, use that + * type to (later) see if it opens a scope. + */ + if (Type == ACPI_TYPE_ANY) + { + Type = ThisNode->Type; + } + } + + /* Point to next name segment and make this node current */ + + Path += ACPI_NAME_SIZE; + CurrentNode = ThisNode; + } + + /* Always check if we need to open a new scope */ + + if (!(Flags & ACPI_NS_DONT_OPEN_SCOPE) && (WalkState)) + { + /* + * If entry is a type which opens a scope, push the new scope on the + * scope stack. + */ + if (AcpiNsOpensScope (Type)) + { + Status = AcpiDsScopeStackPush (ThisNode, Type, WalkState); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + + *ReturnNode = ThisNode; + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsalloc.c b/third_party/lib/acpica/source/components/namespace/nsalloc.c new file mode 100644 index 000000000..72a974f5b --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsalloc.c @@ -0,0 +1,595 @@ +/******************************************************************************* + * + * Module Name: nsalloc - Namespace allocation and deletion utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsalloc") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCreateNode + * + * PARAMETERS: Name - Name of the new node (4 char ACPI name) + * + * RETURN: New namespace node (Null on failure) + * + * DESCRIPTION: Create a namespace node + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +AcpiNsCreateNode ( + UINT32 Name) +{ + ACPI_NAMESPACE_NODE *Node; +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + UINT32 Temp; +#endif + + + ACPI_FUNCTION_TRACE (NsCreateNode); + + + Node = AcpiOsAcquireObject (AcpiGbl_NamespaceCache); + if (!Node) + { + return_PTR (NULL); + } + + ACPI_MEM_TRACKING (AcpiGbl_NsNodeList->TotalAllocated++); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + Temp = AcpiGbl_NsNodeList->TotalAllocated - + AcpiGbl_NsNodeList->TotalFreed; + if (Temp > AcpiGbl_NsNodeList->MaxOccupied) + { + AcpiGbl_NsNodeList->MaxOccupied = Temp; + } +#endif + + Node->Name.Integer = Name; + ACPI_SET_DESCRIPTOR_TYPE (Node, ACPI_DESC_TYPE_NAMED); + return_PTR (Node); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDeleteNode + * + * PARAMETERS: Node - Node to be deleted + * + * RETURN: None + * + * DESCRIPTION: Delete a namespace node. All node deletions must come through + * here. Detaches any attached objects, including any attached + * data. If a handler is associated with attached data, it is + * invoked before the node is deleted. + * + ******************************************************************************/ + +void +AcpiNsDeleteNode ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *NextDesc; + + + ACPI_FUNCTION_NAME (NsDeleteNode); + + + /* Detach an object if there is one */ + + AcpiNsDetachObject (Node); + + /* + * Delete an attached data object list if present (objects that were + * attached via AcpiAttachData). Note: After any normal object is + * detached above, the only possible remaining object(s) are data + * objects, in a linked list. + */ + ObjDesc = Node->Object; + while (ObjDesc && + (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA)) + { + /* Invoke the attached data deletion handler if present */ + + if (ObjDesc->Data.Handler) + { + ObjDesc->Data.Handler (Node, ObjDesc->Data.Pointer); + } + + NextDesc = ObjDesc->Common.NextObject; + AcpiUtRemoveReference (ObjDesc); + ObjDesc = NextDesc; + } + + /* Special case for the statically allocated root node */ + + if (Node == AcpiGbl_RootNode) + { + return; + } + + /* Now we can delete the node */ + + (void) AcpiOsReleaseObject (AcpiGbl_NamespaceCache, Node); + + ACPI_MEM_TRACKING (AcpiGbl_NsNodeList->TotalFreed++); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", + Node, AcpiGbl_CurrentNodeCount)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsRemoveNode + * + * PARAMETERS: Node - Node to be removed/deleted + * + * RETURN: None + * + * DESCRIPTION: Remove (unlink) and delete a namespace node + * + ******************************************************************************/ + +void +AcpiNsRemoveNode ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_NAMESPACE_NODE *ParentNode; + ACPI_NAMESPACE_NODE *PrevNode; + ACPI_NAMESPACE_NODE *NextNode; + + + ACPI_FUNCTION_TRACE_PTR (NsRemoveNode, Node); + + + ParentNode = Node->Parent; + + PrevNode = NULL; + NextNode = ParentNode->Child; + + /* Find the node that is the previous peer in the parent's child list */ + + while (NextNode != Node) + { + PrevNode = NextNode; + NextNode = NextNode->Peer; + } + + if (PrevNode) + { + /* Node is not first child, unlink it */ + + PrevNode->Peer = Node->Peer; + } + else + { + /* + * Node is first child (has no previous peer). + * Link peer list to parent + */ + ParentNode->Child = Node->Peer; + } + + /* Delete the node and any attached objects */ + + AcpiNsDeleteNode (Node); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsInstallNode + * + * PARAMETERS: WalkState - Current state of the walk + * ParentNode - The parent of the new Node + * Node - The new Node to install + * Type - ACPI object type of the new Node + * + * RETURN: None + * + * DESCRIPTION: Initialize a new namespace node and install it amongst + * its peers. + * + * Note: Current namespace lookup is linear search. This appears + * to be sufficient as namespace searches consume only a small + * fraction of the execution time of the ACPI subsystem. + * + ******************************************************************************/ + +void +AcpiNsInstallNode ( + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *ParentNode, /* Parent */ + ACPI_NAMESPACE_NODE *Node, /* New Child*/ + ACPI_OBJECT_TYPE Type) +{ + ACPI_OWNER_ID OwnerId = 0; + ACPI_NAMESPACE_NODE *ChildNode; + + + ACPI_FUNCTION_TRACE (NsInstallNode); + + + if (WalkState) + { + /* + * Get the owner ID from the Walk state. The owner ID is used to + * track table deletion and deletion of objects created by methods. + */ + OwnerId = WalkState->OwnerId; + + if ((WalkState->MethodDesc) && + (ParentNode != WalkState->MethodNode)) + { + /* + * A method is creating a new node that is not a child of the + * method (it is non-local). Mark the executing method as having + * modified the namespace. This is used for cleanup when the + * method exits. + */ + WalkState->MethodDesc->Method.InfoFlags |= + ACPI_METHOD_MODIFIED_NAMESPACE; + } + } + + /* Link the new entry into the parent and existing children */ + + Node->Peer = NULL; + Node->Parent = ParentNode; + ChildNode = ParentNode->Child; + + if (!ChildNode) + { + ParentNode->Child = Node; + } + else + { + /* Add node to the end of the peer list */ + + while (ChildNode->Peer) + { + ChildNode = ChildNode->Peer; + } + + ChildNode->Peer = Node; + } + + /* Init the new entry */ + + Node->OwnerId = OwnerId; + Node->Type = (UINT8) Type; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", + AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type), Node, OwnerId, + AcpiUtGetNodeName (ParentNode), AcpiUtGetTypeName (ParentNode->Type), + ParentNode)); + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDeleteChildren + * + * PARAMETERS: ParentNode - Delete this objects children + * + * RETURN: None. + * + * DESCRIPTION: Delete all children of the parent object. In other words, + * deletes a "scope". + * + ******************************************************************************/ + +void +AcpiNsDeleteChildren ( + ACPI_NAMESPACE_NODE *ParentNode) +{ + ACPI_NAMESPACE_NODE *NextNode; + ACPI_NAMESPACE_NODE *NodeToDelete; + + + ACPI_FUNCTION_TRACE_PTR (NsDeleteChildren, ParentNode); + + + if (!ParentNode) + { + return_VOID; + } + + /* Deallocate all children at this level */ + + NextNode = ParentNode->Child; + while (NextNode) + { + /* Grandchildren should have all been deleted already */ + + if (NextNode->Child) + { + ACPI_ERROR ((AE_INFO, "Found a grandchild! P=%p C=%p", + ParentNode, NextNode)); + } + + /* + * Delete this child node and move on to the next child in the list. + * No need to unlink the node since we are deleting the entire branch. + */ + NodeToDelete = NextNode; + NextNode = NextNode->Peer; + AcpiNsDeleteNode (NodeToDelete); + }; + + /* Clear the parent's child pointer */ + + ParentNode->Child = NULL; + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDeleteNamespaceSubtree + * + * PARAMETERS: ParentNode - Root of the subtree to be deleted + * + * RETURN: None. + * + * DESCRIPTION: Delete a subtree of the namespace. This includes all objects + * stored within the subtree. + * + ******************************************************************************/ + +void +AcpiNsDeleteNamespaceSubtree ( + ACPI_NAMESPACE_NODE *ParentNode) +{ + ACPI_NAMESPACE_NODE *ChildNode = NULL; + UINT32 Level = 1; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsDeleteNamespaceSubtree); + + + if (!ParentNode) + { + return_VOID; + } + + /* Lock namespace for possible update */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + /* + * Traverse the tree of objects until we bubble back up + * to where we started. + */ + while (Level > 0) + { + /* Get the next node in this scope (NULL if none) */ + + ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); + if (ChildNode) + { + /* Found a child node - detach any attached object */ + + AcpiNsDetachObject (ChildNode); + + /* Check if this node has any children */ + + if (ChildNode->Child) + { + /* + * There is at least one child of this node, + * visit the node + */ + Level++; + ParentNode = ChildNode; + ChildNode = NULL; + } + } + else + { + /* + * No more children of this parent node. + * Move up to the grandparent. + */ + Level--; + + /* + * Now delete all of the children of this parent + * all at the same time. + */ + AcpiNsDeleteChildren (ParentNode); + + /* New "last child" is this parent node */ + + ChildNode = ParentNode; + + /* Move up the tree to the grandparent */ + + ParentNode = ParentNode->Parent; + } + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDeleteNamespaceByOwner + * + * PARAMETERS: OwnerId - All nodes with this owner will be deleted + * + * RETURN: Status + * + * DESCRIPTION: Delete entries within the namespace that are owned by a + * specific ID. Used to delete entire ACPI tables. All + * reference counts are updated. + * + * MUTEX: Locks namespace during deletion walk. + * + ******************************************************************************/ + +void +AcpiNsDeleteNamespaceByOwner ( + ACPI_OWNER_ID OwnerId) +{ + ACPI_NAMESPACE_NODE *ChildNode; + ACPI_NAMESPACE_NODE *DeletionNode; + ACPI_NAMESPACE_NODE *ParentNode; + UINT32 Level; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_U32 (NsDeleteNamespaceByOwner, OwnerId); + + + if (OwnerId == 0) + { + return_VOID; + } + + /* Lock namespace for possible update */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + DeletionNode = NULL; + ParentNode = AcpiGbl_RootNode; + ChildNode = NULL; + Level = 1; + + /* + * Traverse the tree of nodes until we bubble back up + * to where we started. + */ + while (Level > 0) + { + /* + * Get the next child of this parent node. When ChildNode is NULL, + * the first child of the parent is returned + */ + ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); + + if (DeletionNode) + { + AcpiNsDeleteChildren (DeletionNode); + AcpiNsRemoveNode (DeletionNode); + DeletionNode = NULL; + } + + if (ChildNode) + { + if (ChildNode->OwnerId == OwnerId) + { + /* Found a matching child node - detach any attached object */ + + AcpiNsDetachObject (ChildNode); + } + + /* Check if this node has any children */ + + if (ChildNode->Child) + { + /* + * There is at least one child of this node, + * visit the node + */ + Level++; + ParentNode = ChildNode; + ChildNode = NULL; + } + else if (ChildNode->OwnerId == OwnerId) + { + DeletionNode = ChildNode; + } + } + else + { + /* + * No more children of this parent node. + * Move up to the grandparent. + */ + Level--; + if (Level != 0) + { + if (ParentNode->OwnerId == OwnerId) + { + DeletionNode = ParentNode; + } + } + + /* New "last child" is this parent node */ + + ChildNode = ParentNode; + + /* Move up the tree to the grandparent */ + + ParentNode = ParentNode->Parent; + } + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/namespace/nsarguments.c b/third_party/lib/acpica/source/components/namespace/nsarguments.c new file mode 100644 index 000000000..1483e8121 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsarguments.c @@ -0,0 +1,305 @@ +/****************************************************************************** + * + * Module Name: nsarguments - Validation of args for ACPI predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsarguments") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckArgumentTypes + * + * PARAMETERS: Info - Method execution information block + * + * RETURN: None + * + * DESCRIPTION: Check the incoming argument count and all argument types + * against the argument type list for a predefined name. + * + ******************************************************************************/ + +void +AcpiNsCheckArgumentTypes ( + ACPI_EVALUATE_INFO *Info) +{ + UINT16 ArgTypeList; + UINT8 ArgCount; + UINT8 ArgType; + UINT8 UserArgType; + UINT32 i; + + + /* If not a predefined name, cannot typecheck args */ + + if (!Info->Predefined) + { + return; + } + + ArgTypeList = Info->Predefined->Info.ArgumentList; + ArgCount = METHOD_GET_ARG_COUNT (ArgTypeList); + + /* Typecheck all arguments */ + + for (i = 0; ((i < ArgCount) && (i < Info->ParamCount)); i++) + { + ArgType = METHOD_GET_NEXT_TYPE (ArgTypeList); + UserArgType = Info->Parameters[i]->Common.Type; + + if (UserArgType != ArgType) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, ACPI_WARN_ALWAYS, + "Argument #%u type mismatch - " + "Found [%s], ACPI requires [%s]", (i + 1), + AcpiUtGetTypeName (UserArgType), + AcpiUtGetTypeName (ArgType))); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckAcpiCompliance + * + * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * Node - Namespace node for the method/object + * Predefined - Pointer to entry in predefined name table + * + * RETURN: None + * + * DESCRIPTION: Check that the declared parameter count (in ASL/AML) for a + * predefined name is what is expected (matches what is defined in + * the ACPI specification for this predefined name.) + * + ******************************************************************************/ + +void +AcpiNsCheckAcpiCompliance ( + char *Pathname, + ACPI_NAMESPACE_NODE *Node, + const ACPI_PREDEFINED_INFO *Predefined) +{ + UINT32 AmlParamCount; + UINT32 RequiredParamCount; + + + if (!Predefined) + { + return; + } + + /* Get the ACPI-required arg count from the predefined info table */ + + RequiredParamCount = + METHOD_GET_ARG_COUNT (Predefined->Info.ArgumentList); + + /* + * If this object is not a control method, we can check if the ACPI + * spec requires that it be a method. + */ + if (Node->Type != ACPI_TYPE_METHOD) + { + if (RequiredParamCount > 0) + { + /* Object requires args, must be implemented as a method */ + + ACPI_BIOS_ERROR_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Object (%s) must be a control method with %u arguments", + AcpiUtGetTypeName (Node->Type), RequiredParamCount)); + } + else if (!RequiredParamCount && !Predefined->Info.ExpectedBtypes) + { + /* Object requires no args and no return value, must be a method */ + + ACPI_BIOS_ERROR_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Object (%s) must be a control method " + "with no arguments and no return value", + AcpiUtGetTypeName (Node->Type))); + } + + return; + } + + /* + * This is a control method. + * Check that the ASL/AML-defined parameter count for this method + * matches the ACPI-required parameter count + * + * Some methods are allowed to have a "minimum" number of args (_SCP) + * because their definition in ACPI has changed over time. + * + * Note: These are BIOS errors in the declaration of the object + */ + AmlParamCount = Node->Object->Method.ParamCount; + + if (AmlParamCount < RequiredParamCount) + { + ACPI_BIOS_ERROR_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Insufficient arguments - " + "ASL declared %u, ACPI requires %u", + AmlParamCount, RequiredParamCount)); + } + else if ((AmlParamCount > RequiredParamCount) && + !(Predefined->Info.ArgumentList & ARG_COUNT_IS_MINIMUM)) + { + ACPI_BIOS_ERROR_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Excess arguments - " + "ASL declared %u, ACPI requires %u", + AmlParamCount, RequiredParamCount)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckArgumentCount + * + * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * Node - Namespace node for the method/object + * UserParamCount - Number of args passed in by the caller + * Predefined - Pointer to entry in predefined name table + * + * RETURN: None + * + * DESCRIPTION: Check that incoming argument count matches the declared + * parameter count (in the ASL/AML) for an object. + * + ******************************************************************************/ + +void +AcpiNsCheckArgumentCount ( + char *Pathname, + ACPI_NAMESPACE_NODE *Node, + UINT32 UserParamCount, + const ACPI_PREDEFINED_INFO *Predefined) +{ + UINT32 AmlParamCount; + UINT32 RequiredParamCount; + + + if (!Predefined) + { + /* + * Not a predefined name. Check the incoming user argument count + * against the count that is specified in the method/object. + */ + if (Node->Type != ACPI_TYPE_METHOD) + { + if (UserParamCount) + { + ACPI_INFO_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "%u arguments were passed to a non-method ACPI object (%s)", + UserParamCount, AcpiUtGetTypeName (Node->Type))); + } + + return; + } + + /* + * This is a control method. Check the parameter count. + * We can only check the incoming argument count against the + * argument count declared for the method in the ASL/AML. + * + * Emit a message if too few or too many arguments have been passed + * by the caller. + * + * Note: Too many arguments will not cause the method to + * fail. However, the method will fail if there are too few + * arguments and the method attempts to use one of the missing ones. + */ + AmlParamCount = Node->Object->Method.ParamCount; + + if (UserParamCount < AmlParamCount) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Insufficient arguments - " + "Caller passed %u, method requires %u", + UserParamCount, AmlParamCount)); + } + else if (UserParamCount > AmlParamCount) + { + ACPI_INFO_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Excess arguments - " + "Caller passed %u, method requires %u", + UserParamCount, AmlParamCount)); + } + + return; + } + + /* + * This is a predefined name. Validate the user-supplied parameter + * count against the ACPI specification. We don't validate against + * the method itself because what is important here is that the + * caller is in conformance with the spec. (The arg count for the + * method was checked against the ACPI spec earlier.) + * + * Some methods are allowed to have a "minimum" number of args (_SCP) + * because their definition in ACPI has changed over time. + */ + RequiredParamCount = + METHOD_GET_ARG_COUNT (Predefined->Info.ArgumentList); + + if (UserParamCount < RequiredParamCount) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Insufficient arguments - " + "Caller passed %u, ACPI requires %u", + UserParamCount, RequiredParamCount)); + } + else if ((UserParamCount > RequiredParamCount) && + !(Predefined->Info.ArgumentList & ARG_COUNT_IS_MINIMUM)) + { + ACPI_INFO_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Excess arguments - " + "Caller passed %u, ACPI requires %u", + UserParamCount, RequiredParamCount)); + } +} diff --git a/third_party/lib/acpica/source/components/namespace/nsconvert.c b/third_party/lib/acpica/source/components/namespace/nsconvert.c new file mode 100644 index 000000000..8cccf99af --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsconvert.c @@ -0,0 +1,566 @@ +/****************************************************************************** + * + * Module Name: nsconvert - Object conversions for objects returned by + * predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "acpredef.h" +#include "amlresrc.h" + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsconvert") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsConvertToInteger + * + * PARAMETERS: OriginalObject - Object to be converted + * ReturnObject - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsConvertToInteger ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject) +{ + ACPI_OPERAND_OBJECT *NewObject; + ACPI_STATUS Status; + UINT64 Value = 0; + UINT32 i; + + + switch (OriginalObject->Common.Type) + { + case ACPI_TYPE_STRING: + + /* String-to-Integer conversion */ + + Status = AcpiUtStrtoul64 (OriginalObject->String.Pointer, + ACPI_ANY_BASE, &Value); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_TYPE_BUFFER: + + /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ + + if (OriginalObject->Buffer.Length > 8) + { + return (AE_AML_OPERAND_TYPE); + } + + /* Extract each buffer byte to create the integer */ + + for (i = 0; i < OriginalObject->Buffer.Length; i++) + { + Value |= ((UINT64) + OriginalObject->Buffer.Pointer[i] << (i * 8)); + } + break; + + default: + + return (AE_AML_OPERAND_TYPE); + } + + NewObject = AcpiUtCreateIntegerObject (Value); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + *ReturnObject = NewObject; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsConvertToString + * + * PARAMETERS: OriginalObject - Object to be converted + * ReturnObject - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsConvertToString ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject) +{ + ACPI_OPERAND_OBJECT *NewObject; + ACPI_SIZE Length; + ACPI_STATUS Status; + + + switch (OriginalObject->Common.Type) + { + case ACPI_TYPE_INTEGER: + /* + * Integer-to-String conversion. Commonly, convert + * an integer of value 0 to a NULL string. The last element of + * _BIF and _BIX packages occasionally need this fix. + */ + if (OriginalObject->Integer.Value == 0) + { + /* Allocate a new NULL string object */ + + NewObject = AcpiUtCreateStringObject (0); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + } + else + { + Status = AcpiExConvertToString (OriginalObject, + &NewObject, ACPI_IMPLICIT_CONVERT_HEX); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + break; + + case ACPI_TYPE_BUFFER: + /* + * Buffer-to-String conversion. Use a ToString + * conversion, no transform performed on the buffer data. The best + * example of this is the _BIF method, where the string data from + * the battery is often (incorrectly) returned as buffer object(s). + */ + Length = 0; + while ((Length < OriginalObject->Buffer.Length) && + (OriginalObject->Buffer.Pointer[Length])) + { + Length++; + } + + /* Allocate a new string object */ + + NewObject = AcpiUtCreateStringObject (Length); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + /* + * Copy the raw buffer data with no transform. String is already NULL + * terminated at Length+1. + */ + memcpy (NewObject->String.Pointer, + OriginalObject->Buffer.Pointer, Length); + break; + + default: + + return (AE_AML_OPERAND_TYPE); + } + + *ReturnObject = NewObject; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsConvertToBuffer + * + * PARAMETERS: OriginalObject - Object to be converted + * ReturnObject - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsConvertToBuffer ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject) +{ + ACPI_OPERAND_OBJECT *NewObject; + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT **Elements; + UINT32 *DwordBuffer; + UINT32 Count; + UINT32 i; + + + switch (OriginalObject->Common.Type) + { + case ACPI_TYPE_INTEGER: + /* + * Integer-to-Buffer conversion. + * Convert the Integer to a packed-byte buffer. _MAT and other + * objects need this sometimes, if a read has been performed on a + * Field object that is less than or equal to the global integer + * size (32 or 64 bits). + */ + Status = AcpiExConvertToBuffer (OriginalObject, &NewObject); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_TYPE_STRING: + + /* String-to-Buffer conversion. Simple data copy */ + + NewObject = AcpiUtCreateBufferObject + (OriginalObject->String.Length); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + memcpy (NewObject->Buffer.Pointer, + OriginalObject->String.Pointer, OriginalObject->String.Length); + break; + + case ACPI_TYPE_PACKAGE: + /* + * This case is often seen for predefined names that must return a + * Buffer object with multiple DWORD integers within. For example, + * _FDE and _GTM. The Package can be converted to a Buffer. + */ + + /* All elements of the Package must be integers */ + + Elements = OriginalObject->Package.Elements; + Count = OriginalObject->Package.Count; + + for (i = 0; i < Count; i++) + { + if ((!*Elements) || + ((*Elements)->Common.Type != ACPI_TYPE_INTEGER)) + { + return (AE_AML_OPERAND_TYPE); + } + Elements++; + } + + /* Create the new buffer object to replace the Package */ + + NewObject = AcpiUtCreateBufferObject (ACPI_MUL_4 (Count)); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + /* Copy the package elements (integers) to the buffer as DWORDs */ + + Elements = OriginalObject->Package.Elements; + DwordBuffer = ACPI_CAST_PTR (UINT32, NewObject->Buffer.Pointer); + + for (i = 0; i < Count; i++) + { + *DwordBuffer = (UINT32) (*Elements)->Integer.Value; + DwordBuffer++; + Elements++; + } + break; + + default: + + return (AE_AML_OPERAND_TYPE); + } + + *ReturnObject = NewObject; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsConvertToUnicode + * + * PARAMETERS: Scope - Namespace node for the method/object + * OriginalObject - ASCII String Object to be converted + * ReturnObject - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsConvertToUnicode ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject) +{ + ACPI_OPERAND_OBJECT *NewObject; + char *AsciiString; + UINT16 *UnicodeBuffer; + UINT32 UnicodeLength; + UINT32 i; + + + if (!OriginalObject) + { + return (AE_OK); + } + + /* If a Buffer was returned, it must be at least two bytes long */ + + if (OriginalObject->Common.Type == ACPI_TYPE_BUFFER) + { + if (OriginalObject->Buffer.Length < 2) + { + return (AE_AML_OPERAND_VALUE); + } + + *ReturnObject = NULL; + return (AE_OK); + } + + /* + * The original object is an ASCII string. Convert this string to + * a unicode buffer. + */ + AsciiString = OriginalObject->String.Pointer; + UnicodeLength = (OriginalObject->String.Length * 2) + 2; + + /* Create a new buffer object for the Unicode data */ + + NewObject = AcpiUtCreateBufferObject (UnicodeLength); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + UnicodeBuffer = ACPI_CAST_PTR (UINT16, NewObject->Buffer.Pointer); + + /* Convert ASCII to Unicode */ + + for (i = 0; i < OriginalObject->String.Length; i++) + { + UnicodeBuffer[i] = (UINT16) AsciiString[i]; + } + + *ReturnObject = NewObject; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsConvertToResource + * + * PARAMETERS: Scope - Namespace node for the method/object + * OriginalObject - Object to be converted + * ReturnObject - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful + * + * DESCRIPTION: Attempt to convert a Integer object to a ResourceTemplate + * Buffer. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsConvertToResource ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject) +{ + ACPI_OPERAND_OBJECT *NewObject; + UINT8 *Buffer; + + + /* + * We can fix the following cases for an expected resource template: + * 1. No return value (interpreter slack mode is disabled) + * 2. A "Return (Zero)" statement + * 3. A "Return empty buffer" statement + * + * We will return a buffer containing a single EndTag + * resource descriptor. + */ + if (OriginalObject) + { + switch (OriginalObject->Common.Type) + { + case ACPI_TYPE_INTEGER: + + /* We can only repair an Integer==0 */ + + if (OriginalObject->Integer.Value) + { + return (AE_AML_OPERAND_TYPE); + } + break; + + case ACPI_TYPE_BUFFER: + + if (OriginalObject->Buffer.Length) + { + /* Additional checks can be added in the future */ + + *ReturnObject = NULL; + return (AE_OK); + } + break; + + case ACPI_TYPE_STRING: + default: + + return (AE_AML_OPERAND_TYPE); + } + } + + /* Create the new buffer object for the resource descriptor */ + + NewObject = AcpiUtCreateBufferObject (2); + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + Buffer = ACPI_CAST_PTR (UINT8, NewObject->Buffer.Pointer); + + /* Initialize the Buffer with a single EndTag descriptor */ + + Buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE); + Buffer[1] = 0x00; + + *ReturnObject = NewObject; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsConvertToReference + * + * PARAMETERS: Scope - Namespace node for the method/object + * OriginalObject - Object to be converted + * ReturnObject - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful + * + * DESCRIPTION: Attempt to convert a Integer object to a ObjectReference. + * Buffer. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsConvertToReference ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject) +{ + ACPI_OPERAND_OBJECT *NewObject = NULL; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_GENERIC_STATE ScopeInfo; + char *Name; + + + ACPI_FUNCTION_NAME (NsConvertToReference); + + + /* Convert path into internal presentation */ + + Status = AcpiNsInternalizeName (OriginalObject->String.Pointer, &Name); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Find the namespace node */ + + ScopeInfo.Scope.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Scope); + Status = AcpiNsLookup (&ScopeInfo, Name, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &Node); + if (ACPI_FAILURE (Status)) + { + /* Check if we are resolving a named reference within a package */ + + ACPI_ERROR_NAMESPACE (OriginalObject->String.Pointer, Status); + goto ErrorExit; + } + + /* Create and init a new internal ACPI object */ + + NewObject = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); + if (!NewObject) + { + Status = AE_NO_MEMORY; + goto ErrorExit; + } + NewObject->Reference.Node = Node; + NewObject->Reference.Object = Node->Object; + NewObject->Reference.Class = ACPI_REFCLASS_NAME; + + /* + * Increase reference of the object if needed (the object is likely a + * null for device nodes). + */ + AcpiUtAddReference (Node->Object); + +ErrorExit: + ACPI_FREE (Name); + *ReturnObject = NewObject; + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsdump.c b/third_party/lib/acpica/source/components/namespace/nsdump.c new file mode 100644 index 000000000..72ef07eca --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsdump.c @@ -0,0 +1,944 @@ +/****************************************************************************** + * + * Module Name: nsdump - table dumping routines for debug + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acoutput.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsdump") + +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +void +AcpiNsDumpRootDevices ( + void); + +static ACPI_STATUS +AcpiNsDumpOneDevice ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); +#endif + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +static ACPI_STATUS +AcpiNsDumpOneObjectPath ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiNsGetMaxDepth ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/******************************************************************************* + * + * FUNCTION: AcpiNsPrintPathname + * + * PARAMETERS: NumSegments - Number of ACPI name segments + * Pathname - The compressed (internal) path + * + * RETURN: None + * + * DESCRIPTION: Print an object's full namespace pathname + * + ******************************************************************************/ + +void +AcpiNsPrintPathname ( + UINT32 NumSegments, + char *Pathname) +{ + UINT32 i; + + + ACPI_FUNCTION_NAME (NsPrintPathname); + + + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_NAMES, ACPI_NAMESPACE)) + { + return; + } + + /* Print the entire name */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[")); + + while (NumSegments) + { + for (i = 0; i < 4; i++) + { + isprint ((int) Pathname[i]) ? + AcpiOsPrintf ("%c", Pathname[i]) : + AcpiOsPrintf ("?"); + } + + Pathname += ACPI_NAME_SIZE; + NumSegments--; + if (NumSegments) + { + AcpiOsPrintf ("."); + } + } + + AcpiOsPrintf ("]\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpPathname + * + * PARAMETERS: Handle - Object + * Msg - Prefix message + * Level - Desired debug level + * Component - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +void +AcpiNsDumpPathname ( + ACPI_HANDLE Handle, + char *Msg, + UINT32 Level, + UINT32 Component) +{ + + ACPI_FUNCTION_TRACE (NsDumpPathname); + + + /* Do this only if the requested debug level and component are enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (Level, Component)) + { + return_VOID; + } + + /* Convert handle to a full pathname and print it (with supplied message) */ + + AcpiNsPrintNodePathname (Handle, Msg); + AcpiOsPrintf ("\n"); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpOneObject + * + * PARAMETERS: ObjHandle - Node to be dumped + * Level - Nesting level of the handle + * Context - Passed into WalkNamespace + * ReturnValue - Not used + * + * RETURN: Status + * + * DESCRIPTION: Dump a single Node + * This procedure is a UserFunction called by AcpiNsWalkNamespace. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsDumpOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_WALK_INFO *Info = (ACPI_WALK_INFO *) Context; + ACPI_NAMESPACE_NODE *ThisNode; + ACPI_OPERAND_OBJECT *ObjDesc = NULL; + ACPI_OBJECT_TYPE ObjType; + ACPI_OBJECT_TYPE Type; + UINT32 BytesToDump; + UINT32 DbgLevel; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsDumpOneObject); + + + /* Is output enabled? */ + + if (!(AcpiDbgLevel & Info->DebugLevel)) + { + return (AE_OK); + } + + if (!ObjHandle) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null object handle\n")); + return (AE_OK); + } + + ThisNode = AcpiNsValidateHandle (ObjHandle); + if (!ThisNode) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Invalid object handle %p\n", + ObjHandle)); + return (AE_OK); + } + + Type = ThisNode->Type; + + /* Check if the owner matches */ + + if ((Info->OwnerId != ACPI_OWNER_ID_MAX) && + (Info->OwnerId != ThisNode->OwnerId)) + { + return (AE_OK); + } + + if (!(Info->DisplayType & ACPI_DISPLAY_SHORT)) + { + /* Indent the object according to the level */ + + AcpiOsPrintf ("%2d%*s", (UINT32) Level - 1, (int) Level * 2, " "); + + /* Check the node type and name */ + + if (Type > ACPI_TYPE_LOCAL_MAX) + { + ACPI_WARNING ((AE_INFO, + "Invalid ACPI Object Type 0x%08X", Type)); + } + + AcpiOsPrintf ("%4.4s", AcpiUtGetNodeName (ThisNode)); + } + + /* Now we can print out the pertinent information */ + + AcpiOsPrintf (" %-12s %p %2.2X ", + AcpiUtGetTypeName (Type), ThisNode, ThisNode->OwnerId); + + DbgLevel = AcpiDbgLevel; + AcpiDbgLevel = 0; + ObjDesc = AcpiNsGetAttachedObject (ThisNode); + AcpiDbgLevel = DbgLevel; + + /* Temp nodes are those nodes created by a control method */ + + if (ThisNode->Flags & ANOBJ_TEMPORARY) + { + AcpiOsPrintf ("(T) "); + } + + switch (Info->DisplayType & ACPI_DISPLAY_MASK) + { + case ACPI_DISPLAY_SUMMARY: + + if (!ObjDesc) + { + /* No attached object. Some types should always have an object */ + + switch (Type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_METHOD: + + AcpiOsPrintf (""); + break; + + default: + + break; + } + + AcpiOsPrintf ("\n"); + return (AE_OK); + } + + switch (Type) + { + case ACPI_TYPE_PROCESSOR: + + AcpiOsPrintf ("ID %02X Len %02X Addr %8.8X%8.8X\n", + ObjDesc->Processor.ProcId, ObjDesc->Processor.Length, + ACPI_FORMAT_UINT64 (ObjDesc->Processor.Address)); + break; + + case ACPI_TYPE_DEVICE: + + AcpiOsPrintf ("Notify Object: %p\n", ObjDesc); + break; + + case ACPI_TYPE_METHOD: + + AcpiOsPrintf ("Args %X Len %.4X Aml %p\n", + (UINT32) ObjDesc->Method.ParamCount, + ObjDesc->Method.AmlLength, ObjDesc->Method.AmlStart); + break; + + case ACPI_TYPE_INTEGER: + + AcpiOsPrintf ("= %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_PACKAGE: + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + AcpiOsPrintf ("Elements %.2X\n", + ObjDesc->Package.Count); + } + else + { + AcpiOsPrintf ("[Length not yet evaluated]\n"); + } + break; + + case ACPI_TYPE_BUFFER: + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + AcpiOsPrintf ("Len %.2X", + ObjDesc->Buffer.Length); + + /* Dump some of the buffer */ + + if (ObjDesc->Buffer.Length > 0) + { + AcpiOsPrintf (" ="); + for (i = 0; (i < ObjDesc->Buffer.Length && i < 12); i++) + { + AcpiOsPrintf (" %.2hX", ObjDesc->Buffer.Pointer[i]); + } + } + AcpiOsPrintf ("\n"); + } + else + { + AcpiOsPrintf ("[Length not yet evaluated]\n"); + } + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf ("Len %.2X ", ObjDesc->String.Length); + AcpiUtPrintString (ObjDesc->String.Pointer, 32); + AcpiOsPrintf ("\n"); + break; + + case ACPI_TYPE_REGION: + + AcpiOsPrintf ("[%s]", + AcpiUtGetRegionName (ObjDesc->Region.SpaceId)); + if (ObjDesc->Region.Flags & AOPOBJ_DATA_VALID) + { + AcpiOsPrintf (" Addr %8.8X%8.8X Len %.4X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Region.Address), + ObjDesc->Region.Length); + } + else + { + AcpiOsPrintf (" [Address/Length not yet evaluated]\n"); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + AcpiOsPrintf ("[%s]\n", AcpiUtGetReferenceName (ObjDesc)); + break; + + case ACPI_TYPE_BUFFER_FIELD: + + if (ObjDesc->BufferField.BufferObj && + ObjDesc->BufferField.BufferObj->Buffer.Node) + { + AcpiOsPrintf ("Buf [%4.4s]", + AcpiUtGetNodeName ( + ObjDesc->BufferField.BufferObj->Buffer.Node)); + } + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + AcpiOsPrintf ("Rgn [%4.4s]", + AcpiUtGetNodeName ( + ObjDesc->CommonField.RegionObj->Region.Node)); + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + AcpiOsPrintf ("Rgn [%4.4s] Bnk [%4.4s]", + AcpiUtGetNodeName ( + ObjDesc->CommonField.RegionObj->Region.Node), + AcpiUtGetNodeName ( + ObjDesc->BankField.BankObj->CommonField.Node)); + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + AcpiOsPrintf ("Idx [%4.4s] Dat [%4.4s]", + AcpiUtGetNodeName ( + ObjDesc->IndexField.IndexObj->CommonField.Node), + AcpiUtGetNodeName ( + ObjDesc->IndexField.DataObj->CommonField.Node)); + break; + + case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: + + AcpiOsPrintf ("Target %4.4s (%p)\n", + AcpiUtGetNodeName (ObjDesc), ObjDesc); + break; + + default: + + AcpiOsPrintf ("Object %p\n", ObjDesc); + break; + } + + /* Common field handling */ + + switch (Type) + { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + AcpiOsPrintf (" Off %.3X Len %.2X Acc %.2hd\n", + (ObjDesc->CommonField.BaseByteOffset * 8) + + ObjDesc->CommonField.StartFieldBitOffset, + ObjDesc->CommonField.BitLength, + ObjDesc->CommonField.AccessByteWidth); + break; + + default: + + break; + } + break; + + case ACPI_DISPLAY_OBJECTS: + + AcpiOsPrintf ("O:%p", ObjDesc); + if (!ObjDesc) + { + /* No attached object, we are done */ + + AcpiOsPrintf ("\n"); + return (AE_OK); + } + + AcpiOsPrintf ("(R%u)", ObjDesc->Common.ReferenceCount); + + switch (Type) + { + case ACPI_TYPE_METHOD: + + /* Name is a Method and its AML offset/length are set */ + + AcpiOsPrintf (" M:%p-%X\n", ObjDesc->Method.AmlStart, + ObjDesc->Method.AmlLength); + break; + + case ACPI_TYPE_INTEGER: + + AcpiOsPrintf (" I:%8.8X8.8%X\n", + ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + break; + + case ACPI_TYPE_STRING: + + AcpiOsPrintf (" S:%p-%X\n", ObjDesc->String.Pointer, + ObjDesc->String.Length); + break; + + case ACPI_TYPE_BUFFER: + + AcpiOsPrintf (" B:%p-%X\n", ObjDesc->Buffer.Pointer, + ObjDesc->Buffer.Length); + break; + + default: + + AcpiOsPrintf ("\n"); + break; + } + break; + + default: + AcpiOsPrintf ("\n"); + break; + } + + /* If debug turned off, done */ + + if (!(AcpiDbgLevel & ACPI_LV_VALUES)) + { + return (AE_OK); + } + + /* If there is an attached object, display it */ + + DbgLevel = AcpiDbgLevel; + AcpiDbgLevel = 0; + ObjDesc = AcpiNsGetAttachedObject (ThisNode); + AcpiDbgLevel = DbgLevel; + + /* Dump attached objects */ + + while (ObjDesc) + { + ObjType = ACPI_TYPE_INVALID; + AcpiOsPrintf ("Attached Object %p: ", ObjDesc); + + /* Decode the type of attached object and dump the contents */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) + { + case ACPI_DESC_TYPE_NAMED: + + AcpiOsPrintf ("(Ptr to Node)\n"); + BytesToDump = sizeof (ACPI_NAMESPACE_NODE); + ACPI_DUMP_BUFFER (ObjDesc, BytesToDump); + break; + + case ACPI_DESC_TYPE_OPERAND: + + ObjType = ObjDesc->Common.Type; + + if (ObjType > ACPI_TYPE_LOCAL_MAX) + { + AcpiOsPrintf ( + "(Pointer to ACPI Object type %.2X [UNKNOWN])\n", + ObjType); + + BytesToDump = 32; + } + else + { + AcpiOsPrintf ( + "(Pointer to ACPI Object type %.2X [%s])\n", + ObjType, AcpiUtGetTypeName (ObjType)); + + BytesToDump = sizeof (ACPI_OPERAND_OBJECT); + } + + ACPI_DUMP_BUFFER (ObjDesc, BytesToDump); + break; + + default: + + break; + } + + /* If value is NOT an internal object, we are done */ + + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) + { + goto Cleanup; + } + + /* Valid object, get the pointer to next level, if any */ + + switch (ObjType) + { + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + /* + * NOTE: takes advantage of common fields between string/buffer + */ + BytesToDump = ObjDesc->String.Length; + ObjDesc = (void *) ObjDesc->String.Pointer; + + AcpiOsPrintf ("(Buffer/String pointer %p length %X)\n", + ObjDesc, BytesToDump); + ACPI_DUMP_BUFFER (ObjDesc, BytesToDump); + goto Cleanup; + + case ACPI_TYPE_BUFFER_FIELD: + + ObjDesc = (ACPI_OPERAND_OBJECT *) ObjDesc->BufferField.BufferObj; + break; + + case ACPI_TYPE_PACKAGE: + + ObjDesc = (void *) ObjDesc->Package.Elements; + break; + + case ACPI_TYPE_METHOD: + + ObjDesc = (void *) ObjDesc->Method.AmlStart; + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + ObjDesc = (void *) ObjDesc->Field.RegionObj; + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + ObjDesc = (void *) ObjDesc->BankField.RegionObj; + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + ObjDesc = (void *) ObjDesc->IndexField.IndexObj; + break; + + default: + + goto Cleanup; + } + + ObjType = ACPI_TYPE_INVALID; /* Terminate loop after next pass */ + } + +Cleanup: + AcpiOsPrintf ("\n"); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpObjects + * + * PARAMETERS: Type - Object type to be dumped + * DisplayType - 0 or ACPI_DISPLAY_SUMMARY + * MaxDepth - Maximum depth of dump. Use ACPI_UINT32_MAX + * for an effectively unlimited depth. + * OwnerId - Dump only objects owned by this ID. Use + * ACPI_UINT32_MAX to match all owners. + * StartHandle - Where in namespace to start/end search + * + * RETURN: None + * + * DESCRIPTION: Dump typed objects within the loaded namespace. Uses + * AcpiNsWalkNamespace in conjunction with AcpiNsDumpOneObject. + * + ******************************************************************************/ + +void +AcpiNsDumpObjects ( + ACPI_OBJECT_TYPE Type, + UINT8 DisplayType, + UINT32 MaxDepth, + ACPI_OWNER_ID OwnerId, + ACPI_HANDLE StartHandle) +{ + ACPI_WALK_INFO Info; + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * Just lock the entire namespace for the duration of the dump. + * We don't want any changes to the namespace during this time, + * especially the temporary nodes since we are going to display + * them also. + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not acquire namespace mutex\n"); + return; + } + + Info.DebugLevel = ACPI_LV_TABLES; + Info.OwnerId = OwnerId; + Info.DisplayType = DisplayType; + + (void) AcpiNsWalkNamespace (Type, StartHandle, MaxDepth, + ACPI_NS_WALK_NO_UNLOCK | ACPI_NS_WALK_TEMP_NODES, + AcpiNsDumpOneObject, NULL, (void *) &Info, NULL); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpOneObjectPath, AcpiNsGetMaxDepth + * + * PARAMETERS: ObjHandle - Node to be dumped + * Level - Nesting level of the handle + * Context - Passed into WalkNamespace + * ReturnValue - Not used + * + * RETURN: Status + * + * DESCRIPTION: Dump the full pathname to a namespace object. AcpNsGetMaxDepth + * computes the maximum nesting depth in the namespace tree, in + * order to simplify formatting in AcpiNsDumpOneObjectPath. + * These procedures are UserFunctions called by AcpiNsWalkNamespace. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsDumpOneObjectPath ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + UINT32 MaxLevel = *((UINT32 *) Context); + char *Pathname; + ACPI_NAMESPACE_NODE *Node; + int PathIndent; + + + if (!ObjHandle) + { + return (AE_OK); + } + + Node = AcpiNsValidateHandle (ObjHandle); + if (!Node) + { + /* Ignore bad node during namespace walk */ + + return (AE_OK); + } + + Pathname = AcpiNsGetNormalizedPathname (Node, TRUE); + + PathIndent = 1; + if (Level <= MaxLevel) + { + PathIndent = MaxLevel - Level + 1; + } + + AcpiOsPrintf ("%2d%*s%-12s%*s", + Level, Level, " ", AcpiUtGetTypeName (Node->Type), + PathIndent, " "); + + AcpiOsPrintf ("%s\n", &Pathname[1]); + ACPI_FREE (Pathname); + return (AE_OK); +} + + +static ACPI_STATUS +AcpiNsGetMaxDepth ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + UINT32 *MaxLevel = (UINT32 *) Context; + + + if (Level > *MaxLevel) + { + *MaxLevel = Level; + } + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpObjectPaths + * + * PARAMETERS: Type - Object type to be dumped + * DisplayType - 0 or ACPI_DISPLAY_SUMMARY + * MaxDepth - Maximum depth of dump. Use ACPI_UINT32_MAX + * for an effectively unlimited depth. + * OwnerId - Dump only objects owned by this ID. Use + * ACPI_UINT32_MAX to match all owners. + * StartHandle - Where in namespace to start/end search + * + * RETURN: None + * + * DESCRIPTION: Dump full object pathnames within the loaded namespace. Uses + * AcpiNsWalkNamespace in conjunction with AcpiNsDumpOneObjectPath. + * + ******************************************************************************/ + +void +AcpiNsDumpObjectPaths ( + ACPI_OBJECT_TYPE Type, + UINT8 DisplayType, + UINT32 MaxDepth, + ACPI_OWNER_ID OwnerId, + ACPI_HANDLE StartHandle) +{ + ACPI_STATUS Status; + UINT32 MaxLevel = 0; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * Just lock the entire namespace for the duration of the dump. + * We don't want any changes to the namespace during this time, + * especially the temporary nodes since we are going to display + * them also. + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("Could not acquire namespace mutex\n"); + return; + } + + /* Get the max depth of the namespace tree, for formatting later */ + + (void) AcpiNsWalkNamespace (Type, StartHandle, MaxDepth, + ACPI_NS_WALK_NO_UNLOCK | ACPI_NS_WALK_TEMP_NODES, + AcpiNsGetMaxDepth, NULL, (void *) &MaxLevel, NULL); + + /* Now dump the entire namespace */ + + (void) AcpiNsWalkNamespace (Type, StartHandle, MaxDepth, + ACPI_NS_WALK_NO_UNLOCK | ACPI_NS_WALK_TEMP_NODES, + AcpiNsDumpOneObjectPath, NULL, (void *) &MaxLevel, NULL); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpEntry + * + * PARAMETERS: Handle - Node to be dumped + * DebugLevel - Output level + * + * RETURN: None + * + * DESCRIPTION: Dump a single Node + * + ******************************************************************************/ + +void +AcpiNsDumpEntry ( + ACPI_HANDLE Handle, + UINT32 DebugLevel) +{ + ACPI_WALK_INFO Info; + + + ACPI_FUNCTION_ENTRY (); + + + Info.DebugLevel = DebugLevel; + Info.OwnerId = ACPI_OWNER_ID_MAX; + Info.DisplayType = ACPI_DISPLAY_SUMMARY; + + (void) AcpiNsDumpOneObject (Handle, 1, &Info, NULL); +} + + +#ifdef ACPI_ASL_COMPILER +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpTables + * + * PARAMETERS: SearchBase - Root of subtree to be dumped, or + * NS_ALL to dump the entire namespace + * MaxDepth - Maximum depth of dump. Use INT_MAX + * for an effectively unlimited depth. + * + * RETURN: None + * + * DESCRIPTION: Dump the name space, or a portion of it. + * + ******************************************************************************/ + +void +AcpiNsDumpTables ( + ACPI_HANDLE SearchBase, + UINT32 MaxDepth) +{ + ACPI_HANDLE SearchHandle = SearchBase; + + + ACPI_FUNCTION_TRACE (NsDumpTables); + + + if (!AcpiGbl_RootNode) + { + /* + * If the name space has not been initialized, + * there is nothing to dump. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, + "namespace not initialized!\n")); + return_VOID; + } + + if (ACPI_NS_ALL == SearchBase) + { + /* Entire namespace */ + + SearchHandle = AcpiGbl_RootNode; + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n")); + } + + AcpiNsDumpObjects (ACPI_TYPE_ANY, ACPI_DISPLAY_OBJECTS, MaxDepth, + ACPI_OWNER_ID_MAX, SearchHandle); + return_VOID; +} +#endif +#endif diff --git a/third_party/lib/acpica/source/components/namespace/nsdumpdv.c b/third_party/lib/acpica/source/components/namespace/nsdumpdv.c new file mode 100644 index 000000000..ea143fb5b --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsdumpdv.c @@ -0,0 +1,157 @@ +/****************************************************************************** + * + * Module Name: nsdump - table dumping routines for debug + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" + + +/* TBD: This entire module is apparently obsolete and should be removed */ + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsdumpdv") + +#ifdef ACPI_OBSOLETE_FUNCTIONS +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +#include "acnamesp.h" + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpOneDevice + * + * PARAMETERS: Handle - Node to be dumped + * Level - Nesting level of the handle + * Context - Passed into WalkNamespace + * ReturnValue - Not used + * + * RETURN: Status + * + * DESCRIPTION: Dump a single Node that represents a device + * This procedure is a UserFunction called by AcpiNsWalkNamespace. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsDumpOneDevice ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_BUFFER Buffer; + ACPI_DEVICE_INFO *Info; + ACPI_STATUS Status; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsDumpOneDevice); + + + Status = AcpiNsDumpOneObject (ObjHandle, Level, Context, ReturnValue); + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiGetObjectInfo (ObjHandle, &Buffer); + if (ACPI_SUCCESS (Status)) + { + Info = Buffer.Pointer; + for (i = 0; i < Level; i++) + { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, + " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", + Info->HardwareId.Value, ACPI_FORMAT_UINT64 (Info->Address), + Info->CurrentStatus)); + ACPI_FREE (Info); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDumpRootDevices + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Dump all objects of type "device" + * + ******************************************************************************/ + +void +AcpiNsDumpRootDevices ( + void) +{ + ACPI_HANDLE SysBusHandle; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (NsDumpRootDevices); + + + /* Only dump the table if tracing is enabled */ + + if (!(ACPI_LV_TABLES & AcpiDbgLevel)) + { + return; + } + + Status = AcpiGetHandle (NULL, METHOD_NAME__SB_, &SysBusHandle); + if (ACPI_FAILURE (Status)) + { + return; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, + "Display of all devices in the namespace:\n")); + + Status = AcpiNsWalkNamespace (ACPI_TYPE_DEVICE, SysBusHandle, + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, + AcpiNsDumpOneDevice, NULL, NULL, NULL); +} + +#endif +#endif diff --git a/third_party/lib/acpica/source/components/namespace/nseval.c b/third_party/lib/acpica/source/components/namespace/nseval.c new file mode 100644 index 000000000..33a45c03a --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nseval.c @@ -0,0 +1,524 @@ +/******************************************************************************* + * + * Module Name: nseval - Object evaluation, includes control method execution + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nseval") + +/* Local prototypes */ + +static void +AcpiNsExecModuleCode ( + ACPI_OPERAND_OBJECT *MethodObj, + ACPI_EVALUATE_INFO *Info); + + +/******************************************************************************* + * + * FUNCTION: AcpiNsEvaluate + * + * PARAMETERS: Info - Evaluation info block, contains these fields + * and more: + * PrefixNode - Prefix or Method/Object Node to execute + * RelativePath - Name of method to execute, If NULL, the + * Node is the object to execute + * Parameters - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * ParameterType - Type of Parameter list + * ReturnObject - Where to put method's return value (if + * any). If NULL, no value is returned. + * Flags - ACPI_IGNORE_RETURN_VALUE to delete return + * + * RETURN: Status + * + * DESCRIPTION: Execute a control method or return the current value of an + * ACPI namespace object. + * + * MUTEX: Locks interpreter + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsEvaluate ( + ACPI_EVALUATE_INFO *Info) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsEvaluate); + + + if (!Info) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!Info->Node) + { + /* + * Get the actual namespace node for the target object if we + * need to. Handles these cases: + * + * 1) Null node, valid pathname from root (absolute path) + * 2) Node and valid pathname (path relative to Node) + * 3) Node, Null pathname + */ + Status = AcpiNsGetNode (Info->PrefixNode, Info->RelativePathname, + ACPI_NS_NO_UPSEARCH, &Info->Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * For a method alias, we must grab the actual method node so that + * proper scoping context will be established before execution. + */ + if (AcpiNsGetType (Info->Node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) + { + Info->Node = ACPI_CAST_PTR ( + ACPI_NAMESPACE_NODE, Info->Node->Object); + } + + /* Complete the info block initialization */ + + Info->ReturnObject = NULL; + Info->NodeFlags = Info->Node->Flags; + Info->ObjDesc = AcpiNsGetAttachedObject (Info->Node); + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", + Info->RelativePathname, Info->Node, + AcpiNsGetAttachedObject (Info->Node))); + + /* Get info if we have a predefined name (_HID, etc.) */ + + Info->Predefined = AcpiUtMatchPredefinedMethod (Info->Node->Name.Ascii); + + /* Get the full pathname to the object, for use in warning messages */ + + Info->FullPathname = AcpiNsGetNormalizedPathname (Info->Node, TRUE); + if (!Info->FullPathname) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Count the number of arguments being passed in */ + + Info->ParamCount = 0; + if (Info->Parameters) + { + while (Info->Parameters[Info->ParamCount]) + { + Info->ParamCount++; + } + + /* Warn on impossible argument count */ + + if (Info->ParamCount > ACPI_METHOD_NUM_ARGS) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, ACPI_WARN_ALWAYS, + "Excess arguments (%u) - using only %u", + Info->ParamCount, ACPI_METHOD_NUM_ARGS)); + + Info->ParamCount = ACPI_METHOD_NUM_ARGS; + } + } + + /* + * For predefined names: Check that the declared argument count + * matches the ACPI spec -- otherwise this is a BIOS error. + */ + AcpiNsCheckAcpiCompliance (Info->FullPathname, Info->Node, + Info->Predefined); + + /* + * For all names: Check that the incoming argument count for + * this method/object matches the actual ASL/AML definition. + */ + AcpiNsCheckArgumentCount (Info->FullPathname, Info->Node, + Info->ParamCount, Info->Predefined); + + /* For predefined names: Typecheck all incoming arguments */ + + AcpiNsCheckArgumentTypes (Info); + + /* + * Three major evaluation cases: + * + * 1) Object types that cannot be evaluated by definition + * 2) The object is a control method -- execute it + * 3) The object is not a method -- just return it's current value + */ + switch (AcpiNsGetType (Info->Node)) + { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_EVENT: + case ACPI_TYPE_MUTEX: + case ACPI_TYPE_REGION: + case ACPI_TYPE_THERMAL: + case ACPI_TYPE_LOCAL_SCOPE: + /* + * 1) Disallow evaluation of certain object types. For these, + * object evaluation is undefined and not supported. + */ + ACPI_ERROR ((AE_INFO, + "%s: Evaluation of object type [%s] is not supported", + Info->FullPathname, + AcpiUtGetTypeName (Info->Node->Type))); + + Status = AE_TYPE; + goto Cleanup; + + case ACPI_TYPE_METHOD: + /* + * 2) Object is a control method - execute it + */ + + /* Verify that there is a method object associated with this node */ + + if (!Info->ObjDesc) + { + ACPI_ERROR ((AE_INFO, "%s: Method has no attached sub-object", + Info->FullPathname)); + Status = AE_NULL_OBJECT; + goto Cleanup; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "**** Execute method [%s] at AML address %p length %X\n", + Info->FullPathname, + Info->ObjDesc->Method.AmlStart + 1, + Info->ObjDesc->Method.AmlLength - 1)); + + /* + * Any namespace deletion must acquire both the namespace and + * interpreter locks to ensure that no thread is using the portion of + * the namespace that is being deleted. + * + * Execute the method via the interpreter. The interpreter is locked + * here before calling into the AML parser + */ + AcpiExEnterInterpreter (); + Status = AcpiPsExecuteMethod (Info); + AcpiExExitInterpreter (); + break; + + default: + /* + * 3) All other non-method objects -- get the current object value + */ + + /* + * Some objects require additional resolution steps (e.g., the Node + * may be a field that must be read, etc.) -- we can't just grab + * the object out of the node. + * + * Use ResolveNodeToValue() to get the associated value. + * + * NOTE: we can get away with passing in NULL for a walk state because + * the Node is guaranteed to not be a reference to either a method + * local or a method argument (because this interface is never called + * from a running method.) + * + * Even though we do not directly invoke the interpreter for object + * resolution, we must lock it because we could access an OpRegion. + * The OpRegion access code assumes that the interpreter is locked. + */ + AcpiExEnterInterpreter (); + + /* TBD: ResolveNodeToValue has a strange interface, fix */ + + Info->ReturnObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Info->Node); + + Status = AcpiExResolveNodeToValue (ACPI_CAST_INDIRECT_PTR ( + ACPI_NAMESPACE_NODE, &Info->ReturnObject), NULL); + AcpiExExitInterpreter (); + + if (ACPI_FAILURE (Status)) + { + Info->ReturnObject = NULL; + goto Cleanup; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returned object %p [%s]\n", + Info->ReturnObject, + AcpiUtGetObjectTypeName (Info->ReturnObject))); + + Status = AE_CTRL_RETURN_VALUE; /* Always has a "return value" */ + break; + } + + /* + * For predefined names, check the return value against the ACPI + * specification. Some incorrect return value types are repaired. + */ + (void) AcpiNsCheckReturnValue (Info->Node, Info, Info->ParamCount, + Status, &Info->ReturnObject); + + /* Check if there is a return value that must be dealt with */ + + if (Status == AE_CTRL_RETURN_VALUE) + { + /* If caller does not want the return value, delete it */ + + if (Info->Flags & ACPI_IGNORE_RETURN_VALUE) + { + AcpiUtRemoveReference (Info->ReturnObject); + Info->ReturnObject = NULL; + } + + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ + + Status = AE_OK; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "*** Completed evaluation of object %s ***\n", + Info->RelativePathname)); + +Cleanup: + /* + * Namespace was unlocked by the handling AcpiNs* function, so we + * just free the pathname and return + */ + ACPI_FREE (Info->FullPathname); + Info->FullPathname = NULL; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsExecModuleCodeList + * + * PARAMETERS: None + * + * RETURN: None. Exceptions during method execution are ignored, since + * we cannot abort a table load. + * + * DESCRIPTION: Execute all elements of the global module-level code list. + * Each element is executed as a single control method. + * + ******************************************************************************/ + +void +AcpiNsExecModuleCodeList ( + void) +{ + ACPI_OPERAND_OBJECT *Prev; + ACPI_OPERAND_OBJECT *Next; + ACPI_EVALUATE_INFO *Info; + UINT32 MethodCount = 0; + + + ACPI_FUNCTION_TRACE (NsExecModuleCodeList); + + + /* Exit now if the list is empty */ + + Next = AcpiGbl_ModuleCodeList; + if (!Next) + { + return_VOID; + } + + /* Allocate the evaluation information block */ + + Info = ACPI_ALLOCATE (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_VOID; + } + + /* Walk the list, executing each "method" */ + + while (Next) + { + Prev = Next; + Next = Next->Method.Mutex; + + /* Clear the link field and execute the method */ + + Prev->Method.Mutex = NULL; + AcpiNsExecModuleCode (Prev, Info); + MethodCount++; + + /* Delete the (temporary) method object */ + + AcpiUtRemoveReference (Prev); + } + + ACPI_INFO ((AE_INFO, + "Executed %u blocks of module-level executable AML code", + MethodCount)); + + ACPI_FREE (Info); + AcpiGbl_ModuleCodeList = NULL; + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsExecModuleCode + * + * PARAMETERS: MethodObj - Object container for the module-level code + * Info - Info block for method evaluation + * + * RETURN: None. Exceptions during method execution are ignored, since + * we cannot abort a table load. + * + * DESCRIPTION: Execute a control method containing a block of module-level + * executable AML code. The control method is temporarily + * installed to the root node, then evaluated. + * + ******************************************************************************/ + +static void +AcpiNsExecModuleCode ( + ACPI_OPERAND_OBJECT *MethodObj, + ACPI_EVALUATE_INFO *Info) +{ + ACPI_OPERAND_OBJECT *ParentObj; + ACPI_NAMESPACE_NODE *ParentNode; + ACPI_OBJECT_TYPE Type; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsExecModuleCode); + + + /* + * Get the parent node. We cheat by using the NextObject field + * of the method object descriptor. + */ + ParentNode = ACPI_CAST_PTR ( + ACPI_NAMESPACE_NODE, MethodObj->Method.NextObject); + Type = AcpiNsGetType (ParentNode); + + /* + * Get the region handler and save it in the method object. We may need + * this if an operation region declaration causes a _REG method to be run. + * + * We can't do this in AcpiPsLinkModuleCode because + * AcpiGbl_RootNode->Object is NULL at PASS1. + */ + if ((Type == ACPI_TYPE_DEVICE) && ParentNode->Object) + { + MethodObj->Method.Dispatch.Handler = + ParentNode->Object->Device.Handler; + } + + /* Must clear NextObject (AcpiNsAttachObject needs the field) */ + + MethodObj->Method.NextObject = NULL; + + /* Initialize the evaluation information block */ + + memset (Info, 0, sizeof (ACPI_EVALUATE_INFO)); + Info->PrefixNode = ParentNode; + + /* + * Get the currently attached parent object. Add a reference, + * because the ref count will be decreased when the method object + * is installed to the parent node. + */ + ParentObj = AcpiNsGetAttachedObject (ParentNode); + if (ParentObj) + { + AcpiUtAddReference (ParentObj); + } + + /* Install the method (module-level code) in the parent node */ + + Status = AcpiNsAttachObject (ParentNode, MethodObj, ACPI_TYPE_METHOD); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Execute the parent node as a control method */ + + Status = AcpiNsEvaluate (Info); + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT_NAMES, + "Executed module-level code at %p\n", + MethodObj->Method.AmlStart)); + + /* Delete a possible implicit return value (in slack mode) */ + + if (Info->ReturnObject) + { + AcpiUtRemoveReference (Info->ReturnObject); + } + + /* Detach the temporary method object */ + + AcpiNsDetachObject (ParentNode); + + /* Restore the original parent object */ + + if (ParentObj) + { + Status = AcpiNsAttachObject (ParentNode, ParentObj, Type); + } + else + { + ParentNode->Type = (UINT8) Type; + } + +Exit: + if (ParentObj) + { + AcpiUtRemoveReference (ParentObj); + } + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/namespace/nsinit.c b/third_party/lib/acpica/source/components/namespace/nsinit.c new file mode 100644 index 000000000..fc0819786 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsinit.c @@ -0,0 +1,656 @@ +/****************************************************************************** + * + * Module Name: nsinit - namespace initialization + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acdispat.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsinit") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiNsInitOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiNsInitOneDevice ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AcpiNsFindIniMethods ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + + +/******************************************************************************* + * + * FUNCTION: AcpiNsInitializeObjects + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Walk the entire namespace and perform any necessary + * initialization on the objects found therein + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsInitializeObjects ( + void) +{ + ACPI_STATUS Status; + ACPI_INIT_WALK_INFO Info; + + + ACPI_FUNCTION_TRACE (NsInitializeObjects); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "**** Starting initialization of namespace objects ****\n")); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Completing Region/Field/Buffer/Package initialization:\n")); + + /* Set all init info to zero */ + + memset (&Info, 0, sizeof (ACPI_INIT_WALK_INFO)); + + /* Walk entire namespace from the supplied root */ + + Status = AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, AcpiNsInitOneObject, NULL, + &Info, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During WalkNamespace")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + " Initialized %u/%u Regions %u/%u Fields %u/%u " + "Buffers %u/%u Packages (%u nodes)\n", + Info.OpRegionInit, Info.OpRegionCount, + Info.FieldInit, Info.FieldCount, + Info.BufferInit, Info.BufferCount, + Info.PackageInit, Info.PackageCount, Info.ObjectCount)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "%u Control Methods found\n%u Op Regions found\n", + Info.MethodCount, Info.OpRegionCount)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsInitializeDevices + * + * PARAMETERS: None + * + * RETURN: ACPI_STATUS + * + * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. + * This means running _INI on all present devices. + * + * Note: We install PCI config space handler on region access, + * not here. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsInitializeDevices ( + void) +{ + ACPI_STATUS Status; + ACPI_DEVICE_WALK_INFO Info; + + + ACPI_FUNCTION_TRACE (NsInitializeDevices); + + + /* Init counters */ + + Info.DeviceCount = 0; + Info.Num_STA = 0; + Info.Num_INI = 0; + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Initializing Device/Processor/Thermal objects " + "and executing _INI/_STA methods:\n")); + + /* Tree analysis: find all subtrees that contain _INI methods */ + + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, AcpiNsFindIniMethods, NULL, &Info, NULL); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* Allocate the evaluation information block */ + + Info.EvaluateInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info.EvaluateInfo) + { + Status = AE_NO_MEMORY; + goto ErrorExit; + } + + /* + * Execute the "global" _INI method that may appear at the root. This + * support is provided for Windows compatibility (Vista+) and is not + * part of the ACPI specification. + */ + Info.EvaluateInfo->PrefixNode = AcpiGbl_RootNode; + Info.EvaluateInfo->RelativePathname = METHOD_NAME__INI; + Info.EvaluateInfo->Parameters = NULL; + Info.EvaluateInfo->Flags = ACPI_IGNORE_RETURN_VALUE; + + Status = AcpiNsEvaluate (Info.EvaluateInfo); + if (ACPI_SUCCESS (Status)) + { + Info.Num_INI++; + } + + /* Walk namespace to execute all _INIs on present devices */ + + Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, AcpiNsInitOneDevice, NULL, &Info, NULL); + + /* + * Any _OSI requests should be completed by now. If the BIOS has + * requested any Windows OSI strings, we will always truncate + * I/O addresses to 16 bits -- for Windows compatibility. + */ + if (AcpiGbl_OsiData >= ACPI_OSI_WIN_2000) + { + AcpiGbl_TruncateIoAddresses = TRUE; + } + + ACPI_FREE (Info.EvaluateInfo); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + " Executed %u _INI methods requiring %u _STA executions " + "(examined %u objects)\n", + Info.Num_INI, Info.Num_STA, Info.DeviceCount)); + + return_ACPI_STATUS (Status); + + +ErrorExit: + ACPI_EXCEPTION ((AE_INFO, Status, "During device initialization")); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsInitOneObject + * + * PARAMETERS: ObjHandle - Node + * Level - Current nesting level + * Context - Points to a init info struct + * ReturnValue - Not used + * + * RETURN: Status + * + * DESCRIPTION: Callback from AcpiWalkNamespace. Invoked for every object + * within the namespace. + * + * Currently, the only objects that require initialization are: + * 1) Methods + * 2) Op Regions + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsInitOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_OBJECT_TYPE Type; + ACPI_STATUS Status = AE_OK; + ACPI_INIT_WALK_INFO *Info = (ACPI_INIT_WALK_INFO *) Context; + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_NAME (NsInitOneObject); + + + Info->ObjectCount++; + + /* And even then, we are only interested in a few object types */ + + Type = AcpiNsGetType (ObjHandle); + ObjDesc = AcpiNsGetAttachedObject (Node); + if (!ObjDesc) + { + return (AE_OK); + } + + /* Increment counters for object types we are looking for */ + + switch (Type) + { + case ACPI_TYPE_REGION: + + Info->OpRegionCount++; + break; + + case ACPI_TYPE_BUFFER_FIELD: + + Info->FieldCount++; + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + Info->FieldCount++; + break; + + case ACPI_TYPE_BUFFER: + + Info->BufferCount++; + break; + + case ACPI_TYPE_PACKAGE: + + Info->PackageCount++; + break; + + default: + + /* No init required, just exit now */ + + return (AE_OK); + } + + /* If the object is already initialized, nothing else to do */ + + if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID) + { + return (AE_OK); + } + + /* Must lock the interpreter before executing AML code */ + + AcpiExEnterInterpreter (); + + /* + * Each of these types can contain executable AML code within the + * declaration. + */ + switch (Type) + { + case ACPI_TYPE_REGION: + + Info->OpRegionInit++; + Status = AcpiDsGetRegionArguments (ObjDesc); + break; + + case ACPI_TYPE_BUFFER_FIELD: + + Info->FieldInit++; + Status = AcpiDsGetBufferFieldArguments (ObjDesc); + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + Info->FieldInit++; + Status = AcpiDsGetBankFieldArguments (ObjDesc); + break; + + case ACPI_TYPE_BUFFER: + + Info->BufferInit++; + Status = AcpiDsGetBufferArguments (ObjDesc); + break; + + case ACPI_TYPE_PACKAGE: + + Info->PackageInit++; + Status = AcpiDsGetPackageArguments (ObjDesc); + break; + + default: + + /* No other types can get here */ + + break; + } + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not execute arguments for [%4.4s] (%s)", + AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Type))); + } + + /* + * We ignore errors from above, and always return OK, since we don't want + * to abort the walk on any single error. + */ + AcpiExExitInterpreter (); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsFindIniMethods + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: ACPI_STATUS + * + * DESCRIPTION: Called during namespace walk. Finds objects named _INI under + * device/processor/thermal objects, and marks the entire subtree + * with a SUBTREE_HAS_INI flag. This flag is used during the + * subsequent device initialization walk to avoid entire subtrees + * that do not contain an _INI. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsFindIniMethods ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_DEVICE_WALK_INFO *Info = ACPI_CAST_PTR (ACPI_DEVICE_WALK_INFO, Context); + ACPI_NAMESPACE_NODE *Node; + ACPI_NAMESPACE_NODE *ParentNode; + + + /* Keep count of device/processor/thermal objects */ + + Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + if ((Node->Type == ACPI_TYPE_DEVICE) || + (Node->Type == ACPI_TYPE_PROCESSOR) || + (Node->Type == ACPI_TYPE_THERMAL)) + { + Info->DeviceCount++; + return (AE_OK); + } + + /* We are only looking for methods named _INI */ + + if (!ACPI_COMPARE_NAME (Node->Name.Ascii, METHOD_NAME__INI)) + { + return (AE_OK); + } + + /* + * The only _INI methods that we care about are those that are + * present under Device, Processor, and Thermal objects. + */ + ParentNode = Node->Parent; + switch (ParentNode->Type) + { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* Mark parent and bubble up the INI present flag to the root */ + + while (ParentNode) + { + ParentNode->Flags |= ANOBJ_SUBTREE_HAS_INI; + ParentNode = ParentNode->Parent; + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsInitOneDevice + * + * PARAMETERS: ACPI_WALK_CALLBACK + * + * RETURN: ACPI_STATUS + * + * DESCRIPTION: This is called once per device soon after ACPI is enabled + * to initialize each device. It determines if the device is + * present, and if so, calls _INI. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsInitOneDevice ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_DEVICE_WALK_INFO *WalkInfo = ACPI_CAST_PTR (ACPI_DEVICE_WALK_INFO, Context); + ACPI_EVALUATE_INFO *Info = WalkInfo->EvaluateInfo; + UINT32 Flags; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *DeviceNode; + + + ACPI_FUNCTION_TRACE (NsInitOneDevice); + + + /* We are interested in Devices, Processors and ThermalZones only */ + + DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); + if ((DeviceNode->Type != ACPI_TYPE_DEVICE) && + (DeviceNode->Type != ACPI_TYPE_PROCESSOR) && + (DeviceNode->Type != ACPI_TYPE_THERMAL)) + { + return_ACPI_STATUS (AE_OK); + } + + /* + * Because of an earlier namespace analysis, all subtrees that contain an + * _INI method are tagged. + * + * If this device subtree does not contain any _INI methods, we + * can exit now and stop traversing this entire subtree. + */ + if (!(DeviceNode->Flags & ANOBJ_SUBTREE_HAS_INI)) + { + return_ACPI_STATUS (AE_CTRL_DEPTH); + } + + /* + * Run _STA to determine if this device is present and functioning. We + * must know this information for two important reasons (from ACPI spec): + * + * 1) We can only run _INI if the device is present. + * 2) We must abort the device tree walk on this subtree if the device is + * not present and is not functional (we will not examine the children) + * + * The _STA method is not required to be present under the device, we + * assume the device is present if _STA does not exist. + */ + ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( + ACPI_TYPE_METHOD, DeviceNode, METHOD_NAME__STA)); + + Status = AcpiUtExecute_STA (DeviceNode, &Flags); + if (ACPI_FAILURE (Status)) + { + /* Ignore error and move on to next device */ + + return_ACPI_STATUS (AE_OK); + } + + /* + * Flags == -1 means that _STA was not found. In this case, we assume that + * the device is both present and functional. + * + * From the ACPI spec, description of _STA: + * + * "If a device object (including the processor object) does not have an + * _STA object, then OSPM assumes that all of the above bits are set (in + * other words, the device is present, ..., and functioning)" + */ + if (Flags != ACPI_UINT32_MAX) + { + WalkInfo->Num_STA++; + } + + /* + * Examine the PRESENT and FUNCTIONING status bits + * + * Note: ACPI spec does not seem to specify behavior for the present but + * not functioning case, so we assume functioning if present. + */ + if (!(Flags & ACPI_STA_DEVICE_PRESENT)) + { + /* Device is not present, we must examine the Functioning bit */ + + if (Flags & ACPI_STA_DEVICE_FUNCTIONING) + { + /* + * Device is not present but is "functioning". In this case, + * we will not run _INI, but we continue to examine the children + * of this device. + * + * From the ACPI spec, description of _STA: (Note - no mention + * of whether to run _INI or not on the device in question) + * + * "_STA may return bit 0 clear (not present) with bit 3 set + * (device is functional). This case is used to indicate a valid + * device for which no device driver should be loaded (for example, + * a bridge device.) Children of this device may be present and + * valid. OSPM should continue enumeration below a device whose + * _STA returns this bit combination" + */ + return_ACPI_STATUS (AE_OK); + } + else + { + /* + * Device is not present and is not functioning. We must abort the + * walk of this subtree immediately -- don't look at the children + * of such a device. + * + * From the ACPI spec, description of _INI: + * + * "If the _STA method indicates that the device is not present, + * OSPM will not run the _INI and will not examine the children + * of the device for _INI methods" + */ + return_ACPI_STATUS (AE_CTRL_DEPTH); + } + } + + /* + * The device is present or is assumed present if no _STA exists. + * Run the _INI if it exists (not required to exist) + * + * Note: We know there is an _INI within this subtree, but it may not be + * under this particular device, it may be lower in the branch. + */ + ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( + ACPI_TYPE_METHOD, DeviceNode, METHOD_NAME__INI)); + + memset (Info, 0, sizeof (ACPI_EVALUATE_INFO)); + Info->PrefixNode = DeviceNode; + Info->RelativePathname = METHOD_NAME__INI; + Info->Parameters = NULL; + Info->Flags = ACPI_IGNORE_RETURN_VALUE; + + Status = AcpiNsEvaluate (Info); + if (ACPI_SUCCESS (Status)) + { + WalkInfo->Num_INI++; + } + +#ifdef ACPI_DEBUG_OUTPUT + else if (Status != AE_NOT_FOUND) + { + /* Ignore error and move on to next device */ + + char *ScopeName = AcpiNsGetNormalizedPathname (DeviceNode, TRUE); + + ACPI_EXCEPTION ((AE_INFO, Status, "during %s._INI execution", + ScopeName)); + ACPI_FREE (ScopeName); + } +#endif + + /* Ignore errors from above */ + + Status = AE_OK; + + /* + * The _INI method has been run if present; call the Global Initialization + * Handler for this device. + */ + if (AcpiGbl_InitHandler) + { + Status = AcpiGbl_InitHandler (DeviceNode, ACPI_INIT_DEVICE_INI); + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsload.c b/third_party/lib/acpica/source/components/namespace/nsload.c new file mode 100644 index 000000000..5cfadf365 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsload.c @@ -0,0 +1,384 @@ +/****************************************************************************** + * + * Module Name: nsload - namespace loading/expanding/contracting procedures + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acdispat.h" +#include "actables.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsload") + +/* Local prototypes */ + +#ifdef ACPI_FUTURE_IMPLEMENTATION +ACPI_STATUS +AcpiNsUnloadNamespace ( + ACPI_HANDLE Handle); + +static ACPI_STATUS +AcpiNsDeleteSubtree ( + ACPI_HANDLE StartHandle); +#endif + + +#ifndef ACPI_NO_METHOD_EXECUTION +/******************************************************************************* + * + * FUNCTION: AcpiNsLoadTable + * + * PARAMETERS: TableIndex - Index for table to be loaded + * Node - Owning NS node + * + * RETURN: Status + * + * DESCRIPTION: Load one ACPI table into the namespace + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsLoadTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsLoadTable); + + + /* + * Parse the table and load the namespace with all named + * objects found within. Control methods are NOT parsed + * at this time. In fact, the control methods cannot be + * parsed until the entire namespace is loaded, because + * if a control method makes a forward reference (call) + * to another control method, we can't continue parsing + * because we don't know how many arguments to parse next! + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* If table already loaded into namespace, just return */ + + if (AcpiTbIsTableLoaded (TableIndex)) + { + Status = AE_ALREADY_EXISTS; + goto Unlock; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Loading table into namespace ****\n")); + + Status = AcpiTbAllocateOwnerId (TableIndex); + if (ACPI_FAILURE (Status)) + { + goto Unlock; + } + + Status = AcpiNsParseTable (TableIndex, Node); + if (ACPI_SUCCESS (Status)) + { + AcpiTbSetTableLoadedFlag (TableIndex, TRUE); + } + else + { + /* + * On error, delete any namespace objects created by this table. + * We cannot initialize these objects, so delete them. There are + * a couple of expecially bad cases: + * AE_ALREADY_EXISTS - namespace collision. + * AE_NOT_FOUND - the target of a Scope operator does not + * exist. This target of Scope must already exist in the + * namespace, as per the ACPI specification. + */ + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + AcpiNsDeleteNamespaceByOwner ( + AcpiGbl_RootTableList.Tables[TableIndex].OwnerId); + AcpiTbReleaseOwnerId (TableIndex); + + return_ACPI_STATUS (Status); + } + +Unlock: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Now we can parse the control methods. We always parse + * them here for a sanity check, and if configured for + * just-in-time parsing, we delete the control method + * parse trees. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Begin Table Object Initialization\n")); + + Status = AcpiDsInitializeObjects (TableIndex, Node); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Completed Table Object Initialization\n")); + + /* + * Execute any module-level code that was detected during the table load + * phase. Although illegal since ACPI 2.0, there are many machines that + * contain this type of code. Each block of detected executable AML code + * outside of any control method is wrapped with a temporary control + * method object and placed on a global list. The methods on this list + * are executed below. + * + * This case executes the module-level code for each table immediately + * after the table has been loaded. This provides compatibility with + * other ACPI implementations. Optionally, the execution can be deferred + * until later, see AcpiInitializeObjects. + */ + if (!AcpiGbl_GroupModuleLevelCode) + { + AcpiNsExecModuleCodeList (); + } + + return_ACPI_STATUS (Status); +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: AcpiLoadNamespace + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the name space from what ever is pointed to by DSDT. + * (DSDT points to either the BIOS or a buffer.) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsLoadNamespace ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiLoadNameSpace); + + + /* There must be at least a DSDT installed */ + + if (AcpiGbl_DSDT == NULL) + { + ACPI_ERROR ((AE_INFO, "DSDT is not in memory")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* + * Load the namespace. The DSDT is required, + * but the SSDT and PSDT tables are optional. + */ + Status = AcpiNsLoadTableByType (ACPI_TABLE_ID_DSDT); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Ignore exceptions from these */ + + (void) AcpiNsLoadTableByType (ACPI_TABLE_ID_SSDT); + (void) AcpiNsLoadTableByType (ACPI_TABLE_ID_PSDT); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "ACPI Namespace successfully loaded at root %p\n", + AcpiGbl_RootNode)); + + return_ACPI_STATUS (Status); +} +#endif + +#ifdef ACPI_FUTURE_IMPLEMENTATION +/******************************************************************************* + * + * FUNCTION: AcpiNsDeleteSubtree + * + * PARAMETERS: StartHandle - Handle in namespace where search begins + * + * RETURNS Status + * + * DESCRIPTION: Walks the namespace starting at the given handle and deletes + * all objects, entries, and scopes in the entire subtree. + * + * Namespace/Interpreter should be locked or the subsystem should + * be in shutdown before this routine is called. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsDeleteSubtree ( + ACPI_HANDLE StartHandle) +{ + ACPI_STATUS Status; + ACPI_HANDLE ChildHandle; + ACPI_HANDLE ParentHandle; + ACPI_HANDLE NextChildHandle; + ACPI_HANDLE Dummy; + UINT32 Level; + + + ACPI_FUNCTION_TRACE (NsDeleteSubtree); + + + ParentHandle = StartHandle; + ChildHandle = NULL; + Level = 1; + + /* + * Traverse the tree of objects until we bubble back up + * to where we started. + */ + while (Level > 0) + { + /* Attempt to get the next object in this scope */ + + Status = AcpiGetNextObject (ACPI_TYPE_ANY, ParentHandle, + ChildHandle, &NextChildHandle); + + ChildHandle = NextChildHandle; + + /* Did we get a new object? */ + + if (ACPI_SUCCESS (Status)) + { + /* Check if this object has any children */ + + if (ACPI_SUCCESS (AcpiGetNextObject (ACPI_TYPE_ANY, ChildHandle, + NULL, &Dummy))) + { + /* + * There is at least one child of this object, + * visit the object + */ + Level++; + ParentHandle = ChildHandle; + ChildHandle = NULL; + } + } + else + { + /* + * No more children in this object, go back up to + * the object's parent + */ + Level--; + + /* Delete all children now */ + + AcpiNsDeleteChildren (ChildHandle); + + ChildHandle = ParentHandle; + Status = AcpiGetParent (ParentHandle, &ParentHandle); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + } + + /* Now delete the starting object, and we are done */ + + AcpiNsRemoveNode (ChildHandle); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsUnloadNameSpace + * + * PARAMETERS: Handle - Root of namespace subtree to be deleted + * + * RETURN: Status + * + * DESCRIPTION: Shrinks the namespace, typically in response to an undocking + * event. Deletes an entire subtree starting from (and + * including) the given handle. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsUnloadNamespace ( + ACPI_HANDLE Handle) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsUnloadNameSpace); + + + /* Parameter validation */ + + if (!AcpiGbl_RootNode) + { + return_ACPI_STATUS (AE_NO_NAMESPACE); + } + + if (!Handle) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* This function does the real work */ + + Status = AcpiNsDeleteSubtree (Handle); + return_ACPI_STATUS (Status); +} +#endif +#endif diff --git a/third_party/lib/acpica/source/components/namespace/nsnames.c b/third_party/lib/acpica/source/components/namespace/nsnames.c new file mode 100644 index 000000000..95f8c8db9 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsnames.c @@ -0,0 +1,346 @@ +/******************************************************************************* + * + * Module Name: nsnames - Name manipulation and search + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsnames") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetExternalPathname + * + * PARAMETERS: Node - Namespace node whose pathname is needed + * + * RETURN: Pointer to storage containing the fully qualified name of + * the node, In external format (name segments separated by path + * separators.) + * + * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually + * for error and debug statements. + * + ******************************************************************************/ + +char * +AcpiNsGetExternalPathname ( + ACPI_NAMESPACE_NODE *Node) +{ + char *NameBuffer; + + + ACPI_FUNCTION_TRACE_PTR (NsGetExternalPathname, Node); + + + NameBuffer = AcpiNsGetNormalizedPathname (Node, FALSE); + return_PTR (NameBuffer); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetPathnameLength + * + * PARAMETERS: Node - Namespace node + * + * RETURN: Length of path, including prefix + * + * DESCRIPTION: Get the length of the pathname string for this node + * + ******************************************************************************/ + +ACPI_SIZE +AcpiNsGetPathnameLength ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_SIZE Size; + + + ACPI_FUNCTION_ENTRY (); + + + Size = AcpiNsBuildNormalizedPath (Node, NULL, 0, FALSE); + return (Size); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsHandleToPathname + * + * PARAMETERS: TargetHandle - Handle of named object whose name is + * to be found + * Buffer - Where the pathname is returned + * NoTrailing - Remove trailing '_' for each name + * segment + * + * RETURN: Status, Buffer is filled with pathname if status is AE_OK + * + * DESCRIPTION: Build and return a full namespace pathname + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsHandleToPathname ( + ACPI_HANDLE TargetHandle, + ACPI_BUFFER *Buffer, + BOOLEAN NoTrailing) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_SIZE RequiredSize; + + + ACPI_FUNCTION_TRACE_PTR (NsHandleToPathname, TargetHandle); + + + Node = AcpiNsValidateHandle (TargetHandle); + if (!Node) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Determine size required for the caller buffer */ + + RequiredSize = AcpiNsBuildNormalizedPath (Node, NULL, 0, NoTrailing); + if (!RequiredSize) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (Buffer, RequiredSize); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Build the path in the caller buffer */ + + (void) AcpiNsBuildNormalizedPath (Node, Buffer->Pointer, + RequiredSize, NoTrailing); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X]\n", + (char *) Buffer->Pointer, (UINT32) RequiredSize)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsBuildNormalizedPath + * + * PARAMETERS: Node - Namespace node + * FullPath - Where the path name is returned + * PathSize - Size of returned path name buffer + * NoTrailing - Remove trailing '_' from each name segment + * + * RETURN: Return 1 if the AML path is empty, otherwise returning (length + * of pathname + 1) which means the 'FullPath' contains a trailing + * null. + * + * DESCRIPTION: Build and return a full namespace pathname. + * Note that if the size of 'FullPath' isn't large enough to + * contain the namespace node's path name, the actual required + * buffer length is returned, and it should be greater than + * 'PathSize'. So callers are able to check the returning value + * to determine the buffer size of 'FullPath'. + * + ******************************************************************************/ + +UINT32 +AcpiNsBuildNormalizedPath ( + ACPI_NAMESPACE_NODE *Node, + char *FullPath, + UINT32 PathSize, + BOOLEAN NoTrailing) +{ + UINT32 Length = 0, i; + char Name[ACPI_NAME_SIZE]; + BOOLEAN DoNoTrailing; + char c, *Left, *Right; + ACPI_NAMESPACE_NODE *NextNode; + + + ACPI_FUNCTION_TRACE_PTR (NsBuildNormalizedPath, Node); + + +#define ACPI_PATH_PUT8(Path, Size, Byte, Length) \ + do { \ + if ((Length) < (Size)) \ + { \ + (Path)[(Length)] = (Byte); \ + } \ + (Length)++; \ + } while (0) + + /* + * Make sure the PathSize is correct, so that we don't need to + * validate both FullPath and PathSize. + */ + if (!FullPath) + { + PathSize = 0; + } + + if (!Node) + { + goto BuildTrailingNull; + } + + NextNode = Node; + while (NextNode && NextNode != AcpiGbl_RootNode) + { + if (NextNode != Node) + { + ACPI_PATH_PUT8(FullPath, PathSize, AML_DUAL_NAME_PREFIX, Length); + } + + ACPI_MOVE_32_TO_32 (Name, &NextNode->Name); + DoNoTrailing = NoTrailing; + for (i = 0; i < 4; i++) + { + c = Name[4-i-1]; + if (DoNoTrailing && c != '_') + { + DoNoTrailing = FALSE; + } + if (!DoNoTrailing) + { + ACPI_PATH_PUT8(FullPath, PathSize, c, Length); + } + } + + NextNode = NextNode->Parent; + } + + ACPI_PATH_PUT8(FullPath, PathSize, AML_ROOT_PREFIX, Length); + + /* Reverse the path string */ + + if (Length <= PathSize) + { + Left = FullPath; + Right = FullPath+Length - 1; + + while (Left < Right) + { + c = *Left; + *Left++ = *Right; + *Right-- = c; + } + } + + /* Append the trailing null */ + +BuildTrailingNull: + ACPI_PATH_PUT8 (FullPath, PathSize, '\0', Length); + +#undef ACPI_PATH_PUT8 + + return_UINT32 (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetNormalizedPathname + * + * PARAMETERS: Node - Namespace node whose pathname is needed + * NoTrailing - Remove trailing '_' from each name segment + * + * RETURN: Pointer to storage containing the fully qualified name of + * the node, In external format (name segments separated by path + * separators.) + * + * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually + * for error and debug statements. All trailing '_' will be + * removed from the full pathname if 'NoTrailing' is specified.. + * + ******************************************************************************/ + +char * +AcpiNsGetNormalizedPathname ( + ACPI_NAMESPACE_NODE *Node, + BOOLEAN NoTrailing) +{ + char *NameBuffer; + ACPI_SIZE Size; + + + ACPI_FUNCTION_TRACE_PTR (NsGetNormalizedPathname, Node); + + + /* Calculate required buffer size based on depth below root */ + + Size = AcpiNsBuildNormalizedPath (Node, NULL, 0, NoTrailing); + if (!Size) + { + return_PTR (NULL); + } + + /* Allocate a buffer to be returned to caller */ + + NameBuffer = ACPI_ALLOCATE_ZEROED (Size); + if (!NameBuffer) + { + ACPI_ERROR ((AE_INFO, + "Could not allocate %u bytes", (UINT32) Size)); + return_PTR (NULL); + } + + /* Build the path in the allocated buffer */ + + (void) AcpiNsBuildNormalizedPath (Node, NameBuffer, Size, NoTrailing); + + return_PTR (NameBuffer); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsobject.c b/third_party/lib/acpica/source/components/namespace/nsobject.c new file mode 100644 index 000000000..cf2436155 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsobject.c @@ -0,0 +1,515 @@ +/******************************************************************************* + * + * Module Name: nsobject - Utilities for objects attached to namespace + * table entries + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsobject") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsAttachObject + * + * PARAMETERS: Node - Parent Node + * Object - Object to be attached + * Type - Type of object, or ACPI_TYPE_ANY if not + * known + * + * RETURN: Status + * + * DESCRIPTION: Record the given object as the value associated with the + * name whose ACPI_HANDLE is passed. If Object is NULL + * and Type is ACPI_TYPE_ANY, set the name as having no value. + * Note: Future may require that the Node->Flags field be passed + * as a parameter. + * + * MUTEX: Assumes namespace is locked + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsAttachObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *Object, + ACPI_OBJECT_TYPE Type) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *LastObjDesc; + ACPI_OBJECT_TYPE ObjectType = ACPI_TYPE_ANY; + + + ACPI_FUNCTION_TRACE (NsAttachObject); + + + /* + * Parameter validation + */ + if (!Node) + { + /* Invalid handle */ + + ACPI_ERROR ((AE_INFO, "Null NamedObj handle")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!Object && (ACPI_TYPE_ANY != Type)) + { + /* Null object */ + + ACPI_ERROR ((AE_INFO, + "Null object, but type not ACPI_TYPE_ANY")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) + { + /* Not a name handle */ + + ACPI_ERROR ((AE_INFO, "Invalid handle %p [%s]", + Node, AcpiUtGetDescriptorName (Node))); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Check if this object is already attached */ + + if (Node->Object == Object) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj %p already installed in NameObj %p\n", + Object, Node)); + + return_ACPI_STATUS (AE_OK); + } + + /* If null object, we will just install it */ + + if (!Object) + { + ObjDesc = NULL; + ObjectType = ACPI_TYPE_ANY; + } + + /* + * If the source object is a namespace Node with an attached object, + * we will use that (attached) object + */ + else if ((ACPI_GET_DESCRIPTOR_TYPE (Object) == ACPI_DESC_TYPE_NAMED) && + ((ACPI_NAMESPACE_NODE *) Object)->Object) + { + /* + * Value passed is a name handle and that name has a + * non-null value. Use that name's value and type. + */ + ObjDesc = ((ACPI_NAMESPACE_NODE *) Object)->Object; + ObjectType = ((ACPI_NAMESPACE_NODE *) Object)->Type; + } + + /* + * Otherwise, we will use the parameter object, but we must type + * it first + */ + else + { + ObjDesc = (ACPI_OPERAND_OBJECT *) Object; + + /* Use the given type */ + + ObjectType = Type; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n", + ObjDesc, Node, AcpiUtGetNodeName (Node))); + + /* Detach an existing attached object if present */ + + if (Node->Object) + { + AcpiNsDetachObject (Node); + } + + if (ObjDesc) + { + /* + * Must increment the new value's reference count + * (if it is an internal object) + */ + AcpiUtAddReference (ObjDesc); + + /* + * Handle objects with multiple descriptors - walk + * to the end of the descriptor list + */ + LastObjDesc = ObjDesc; + while (LastObjDesc->Common.NextObject) + { + LastObjDesc = LastObjDesc->Common.NextObject; + } + + /* Install the object at the front of the object list */ + + LastObjDesc->Common.NextObject = Node->Object; + } + + Node->Type = (UINT8) ObjectType; + Node->Object = ObjDesc; + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDetachObject + * + * PARAMETERS: Node - A Namespace node whose object will be detached + * + * RETURN: None. + * + * DESCRIPTION: Detach/delete an object associated with a namespace node. + * if the object is an allocated object, it is freed. + * Otherwise, the field is simply cleared. + * + ******************************************************************************/ + +void +AcpiNsDetachObject ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + + + ACPI_FUNCTION_TRACE (NsDetachObject); + + + ObjDesc = Node->Object; + + if (!ObjDesc || + (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA)) + { + return_VOID; + } + + if (Node->Flags & ANOBJ_ALLOCATED_BUFFER) + { + /* Free the dynamic aml buffer */ + + if (ObjDesc->Common.Type == ACPI_TYPE_METHOD) + { + ACPI_FREE (ObjDesc->Method.AmlStart); + } + } + + /* Clear the Node entry in all cases */ + + Node->Object = NULL; + if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_OPERAND) + { + /* Unlink object from front of possible object list */ + + Node->Object = ObjDesc->Common.NextObject; + + /* Handle possible 2-descriptor object */ + + if (Node->Object && + (Node->Object->Common.Type != ACPI_TYPE_LOCAL_DATA)) + { + Node->Object = Node->Object->Common.NextObject; + } + + /* + * Detach the object from any data objects (which are still held by + * the namespace node) + */ + if (ObjDesc->Common.NextObject && + ((ObjDesc->Common.NextObject)->Common.Type == ACPI_TYPE_LOCAL_DATA)) + { + ObjDesc->Common.NextObject = NULL; + } + } + + /* Reset the node type to untyped */ + + Node->Type = ACPI_TYPE_ANY; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", + Node, AcpiUtGetNodeName (Node), ObjDesc)); + + /* Remove one reference on the object (and all subobjects) */ + + AcpiUtRemoveReference (ObjDesc); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetAttachedObject + * + * PARAMETERS: Node - Namespace node + * + * RETURN: Current value of the object field from the Node whose + * handle is passed + * + * DESCRIPTION: Obtain the object attached to a namespace node. + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiNsGetAttachedObject ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_FUNCTION_TRACE_PTR (NsGetAttachedObject, Node); + + + if (!Node) + { + ACPI_WARNING ((AE_INFO, "Null Node ptr")); + return_PTR (NULL); + } + + if (!Node->Object || + ((ACPI_GET_DESCRIPTOR_TYPE (Node->Object) != ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_DESCRIPTOR_TYPE (Node->Object) != ACPI_DESC_TYPE_NAMED)) || + ((Node->Object)->Common.Type == ACPI_TYPE_LOCAL_DATA)) + { + return_PTR (NULL); + } + + return_PTR (Node->Object); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetSecondaryObject + * + * PARAMETERS: Node - Namespace node + * + * RETURN: Current value of the object field from the Node whose + * handle is passed. + * + * DESCRIPTION: Obtain a secondary object associated with a namespace node. + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiNsGetSecondaryObject ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_FUNCTION_TRACE_PTR (NsGetSecondaryObject, ObjDesc); + + + if ((!ObjDesc) || + (ObjDesc->Common.Type== ACPI_TYPE_LOCAL_DATA) || + (!ObjDesc->Common.NextObject) || + ((ObjDesc->Common.NextObject)->Common.Type == ACPI_TYPE_LOCAL_DATA)) + { + return_PTR (NULL); + } + + return_PTR (ObjDesc->Common.NextObject); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsAttachData + * + * PARAMETERS: Node - Namespace node + * Handler - Handler to be associated with the data + * Data - Data to be attached + * + * RETURN: Status + * + * DESCRIPTION: Low-level attach data. Create and attach a Data object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsAttachData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler, + void *Data) +{ + ACPI_OPERAND_OBJECT *PrevObjDesc; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *DataDesc; + + + /* We only allow one attachment per handler */ + + PrevObjDesc = NULL; + ObjDesc = Node->Object; + while (ObjDesc) + { + if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA) && + (ObjDesc->Data.Handler == Handler)) + { + return (AE_ALREADY_EXISTS); + } + + PrevObjDesc = ObjDesc; + ObjDesc = ObjDesc->Common.NextObject; + } + + /* Create an internal object for the data */ + + DataDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_DATA); + if (!DataDesc) + { + return (AE_NO_MEMORY); + } + + DataDesc->Data.Handler = Handler; + DataDesc->Data.Pointer = Data; + + /* Install the data object */ + + if (PrevObjDesc) + { + PrevObjDesc->Common.NextObject = DataDesc; + } + else + { + Node->Object = DataDesc; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsDetachData + * + * PARAMETERS: Node - Namespace node + * Handler - Handler associated with the data + * + * RETURN: Status + * + * DESCRIPTION: Low-level detach data. Delete the data node, but the caller + * is responsible for the actual data. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsDetachData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *PrevObjDesc; + + + PrevObjDesc = NULL; + ObjDesc = Node->Object; + while (ObjDesc) + { + if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA) && + (ObjDesc->Data.Handler == Handler)) + { + if (PrevObjDesc) + { + PrevObjDesc->Common.NextObject = ObjDesc->Common.NextObject; + } + else + { + Node->Object = ObjDesc->Common.NextObject; + } + + AcpiUtRemoveReference (ObjDesc); + return (AE_OK); + } + + PrevObjDesc = ObjDesc; + ObjDesc = ObjDesc->Common.NextObject; + } + + return (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetAttachedData + * + * PARAMETERS: Node - Namespace node + * Handler - Handler associated with the data + * Data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Low level interface to obtain data previously associated with + * a namespace node. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsGetAttachedData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler, + void **Data) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + + + ObjDesc = Node->Object; + while (ObjDesc) + { + if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA) && + (ObjDesc->Data.Handler == Handler)) + { + *Data = ObjDesc->Data.Pointer; + return (AE_OK); + } + + ObjDesc = ObjDesc->Common.NextObject; + } + + return (AE_NOT_FOUND); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsparse.c b/third_party/lib/acpica/source/components/namespace/nsparse.c new file mode 100644 index 000000000..1ff33362e --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsparse.c @@ -0,0 +1,228 @@ +/****************************************************************************** + * + * Module Name: nsparse - namespace interface to AML parser + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acparser.h" +#include "acdispat.h" +#include "actables.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsparse") + + +/******************************************************************************* + * + * FUNCTION: NsOneCompleteParse + * + * PARAMETERS: PassNumber - 1 or 2 + * TableDesc - The table to be parsed. + * + * RETURN: Status + * + * DESCRIPTION: Perform one complete parse of an ACPI/AML table. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsOneCompleteParse ( + UINT32 PassNumber, + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode) +{ + ACPI_PARSE_OBJECT *ParseRoot; + ACPI_STATUS Status; + UINT32 AmlLength; + UINT8 *AmlStart; + ACPI_WALK_STATE *WalkState; + ACPI_TABLE_HEADER *Table; + ACPI_OWNER_ID OwnerId; + + + ACPI_FUNCTION_TRACE (NsOneCompleteParse); + + + Status = AcpiGetTableByIndex (TableIndex, &Table); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Table must consist of at least a complete header */ + + if (Table->Length < sizeof (ACPI_TABLE_HEADER)) + { + return_ACPI_STATUS (AE_BAD_HEADER); + } + + AmlStart = (UINT8 *) Table + sizeof (ACPI_TABLE_HEADER); + AmlLength = Table->Length - sizeof (ACPI_TABLE_HEADER); + + Status = AcpiTbGetOwnerId (TableIndex, &OwnerId); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Create and init a Root Node */ + + ParseRoot = AcpiPsCreateScopeOp (AmlStart); + if (!ParseRoot) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Create and initialize a new walk state */ + + WalkState = AcpiDsCreateWalkState (OwnerId, NULL, NULL, NULL); + if (!WalkState) + { + AcpiPsFreeOp (ParseRoot); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Status = AcpiDsInitAmlWalk (WalkState, ParseRoot, NULL, + AmlStart, AmlLength, NULL, (UINT8) PassNumber); + if (ACPI_FAILURE (Status)) + { + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + + /* Found OSDT table, enable the namespace override feature */ + + if (ACPI_COMPARE_NAME(Table->Signature, ACPI_SIG_OSDT) && + PassNumber == ACPI_IMODE_LOAD_PASS1) + { + WalkState->NamespaceOverride = TRUE; + } + + /* StartNode is the default location to load the table */ + + if (StartNode && StartNode != AcpiGbl_RootNode) + { + Status = AcpiDsScopeStackPush ( + StartNode, ACPI_TYPE_METHOD, WalkState); + if (ACPI_FAILURE (Status)) + { + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + } + + /* Parse the AML */ + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "*PARSE* pass %u parse\n", PassNumber)); + Status = AcpiPsParseAml (WalkState); + +Cleanup: + AcpiPsDeleteParseTree (ParseRoot); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsParseTable + * + * PARAMETERS: TableDesc - An ACPI table descriptor for table to parse + * StartNode - Where to enter the table into the namespace + * + * RETURN: Status + * + * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsParseTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsParseTable); + + + /* + * AML Parse, pass 1 + * + * In this pass, we load most of the namespace. Control methods + * are not parsed until later. A parse tree is not created. Instead, + * each Parser Op subtree is deleted when it is finished. This saves + * a great deal of memory, and allows a small cache of parse objects + * to service the entire parse. The second pass of the parse then + * performs another complete parse of the AML. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Start pass 1\n")); + + Status = AcpiNsOneCompleteParse (ACPI_IMODE_LOAD_PASS1, + TableIndex, StartNode); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * AML Parse, pass 2 + * + * In this pass, we resolve forward references and other things + * that could not be completed during the first pass. + * Another complete parse of the AML is performed, but the + * overhead of this is compensated for by the fact that the + * parse objects are all cached. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Start pass 2\n")); + Status = AcpiNsOneCompleteParse (ACPI_IMODE_LOAD_PASS2, + TableIndex, StartNode); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/namespace/nspredef.c b/third_party/lib/acpica/source/components/namespace/nspredef.c new file mode 100644 index 000000000..ccd4aba8f --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nspredef.c @@ -0,0 +1,435 @@ +/****************************************************************************** + * + * Module Name: nspredef - Validation of ACPI predefined methods and objects + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define ACPI_CREATE_PREDEFINED_TABLE + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nspredef") + + +/******************************************************************************* + * + * This module validates predefined ACPI objects that appear in the namespace, + * at the time they are evaluated (via AcpiEvaluateObject). The purpose of this + * validation is to detect problems with BIOS-exposed predefined ACPI objects + * before the results are returned to the ACPI-related drivers. + * + * There are several areas that are validated: + * + * 1) The number of input arguments as defined by the method/object in the + * ASL is validated against the ACPI specification. + * 2) The type of the return object (if any) is validated against the ACPI + * specification. + * 3) For returned package objects, the count of package elements is + * validated, as well as the type of each package element. Nested + * packages are supported. + * + * For any problems found, a warning message is issued. + * + ******************************************************************************/ + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiNsCheckReference ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *ReturnObject); + +static UINT32 +AcpiNsGetBitmappedType ( + ACPI_OPERAND_OBJECT *ReturnObject); + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckReturnValue + * + * PARAMETERS: Node - Namespace node for the method/object + * Info - Method execution information block + * UserParamCount - Number of parameters actually passed + * ReturnStatus - Status from the object evaluation + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status + * + * DESCRIPTION: Check the value returned from a predefined name. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsCheckReturnValue ( + ACPI_NAMESPACE_NODE *Node, + ACPI_EVALUATE_INFO *Info, + UINT32 UserParamCount, + ACPI_STATUS ReturnStatus, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_STATUS Status; + const ACPI_PREDEFINED_INFO *Predefined; + + + /* If not a predefined name, we cannot validate the return object */ + + Predefined = Info->Predefined; + if (!Predefined) + { + return (AE_OK); + } + + /* + * If the method failed or did not actually return an object, we cannot + * validate the return object + */ + if ((ReturnStatus != AE_OK) && + (ReturnStatus != AE_CTRL_RETURN_VALUE)) + { + return (AE_OK); + } + + /* + * Return value validation and possible repair. + * + * 1) Don't perform return value validation/repair if this feature + * has been disabled via a global option. + * + * 2) We have a return value, but if one wasn't expected, just exit, + * this is not a problem. For example, if the "Implicit Return" + * feature is enabled, methods will always return a value. + * + * 3) If the return value can be of any type, then we cannot perform + * any validation, just exit. + */ + if (AcpiGbl_DisableAutoRepair || + (!Predefined->Info.ExpectedBtypes) || + (Predefined->Info.ExpectedBtypes == ACPI_RTYPE_ALL)) + { + return (AE_OK); + } + + /* + * Check that the type of the main return object is what is expected + * for this predefined name + */ + Status = AcpiNsCheckObjectType (Info, ReturnObjectPtr, + Predefined->Info.ExpectedBtypes, ACPI_NOT_PACKAGE_ELEMENT); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* + * + * 4) If there is no return value and it is optional, just return + * AE_OK (_WAK). + */ + if (!(*ReturnObjectPtr)) + { + goto Exit; + } + + /* + * For returned Package objects, check the type of all sub-objects. + * Note: Package may have been newly created by call above. + */ + if ((*ReturnObjectPtr)->Common.Type == ACPI_TYPE_PACKAGE) + { + Info->ParentPackage = *ReturnObjectPtr; + Status = AcpiNsCheckPackage (Info, ReturnObjectPtr); + if (ACPI_FAILURE (Status)) + { + /* We might be able to fix some errors */ + + if ((Status != AE_AML_OPERAND_TYPE) && + (Status != AE_AML_OPERAND_VALUE)) + { + goto Exit; + } + } + } + + /* + * The return object was OK, or it was successfully repaired above. + * Now make some additional checks such as verifying that package + * objects are sorted correctly (if required) or buffer objects have + * the correct data width (bytes vs. dwords). These repairs are + * performed on a per-name basis, i.e., the code is specific to + * particular predefined names. + */ + Status = AcpiNsComplexRepairs (Info, Node, Status, ReturnObjectPtr); + +Exit: + /* + * If the object validation failed or if we successfully repaired one + * or more objects, mark the parent node to suppress further warning + * messages during the next evaluation of the same method/object. + */ + if (ACPI_FAILURE (Status) || + (Info->ReturnFlags & ACPI_OBJECT_REPAIRED)) + { + Node->Flags |= ANOBJ_EVALUATED; + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckObjectType + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * ExpectedBtypes - Bitmap of expected return type(s) + * PackageIndex - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * + * RETURN: Status + * + * DESCRIPTION: Check the type of the return object against the expected object + * type(s). Use of Btype allows multiple expected object types. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsCheckObjectType ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr, + UINT32 ExpectedBtypes, + UINT32 PackageIndex) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_STATUS Status = AE_OK; + char TypeBuffer[96]; /* Room for 10 types */ + + + /* A Namespace node should not get here, but make sure */ + + if (ReturnObject && + ACPI_GET_DESCRIPTOR_TYPE (ReturnObject) == ACPI_DESC_TYPE_NAMED) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Invalid return type - Found a Namespace node [%4.4s] type %s", + ReturnObject->Node.Name.Ascii, + AcpiUtGetTypeName (ReturnObject->Node.Type))); + return (AE_AML_OPERAND_TYPE); + } + + /* + * Convert the object type (ACPI_TYPE_xxx) to a bitmapped object type. + * The bitmapped type allows multiple possible return types. + * + * Note, the cases below must handle all of the possible types returned + * from all of the predefined names (including elements of returned + * packages) + */ + Info->ReturnBtype = AcpiNsGetBitmappedType (ReturnObject); + if (Info->ReturnBtype == ACPI_RTYPE_ANY) + { + /* Not one of the supported objects, must be incorrect */ + goto TypeErrorExit; + } + + /* For reference objects, check that the reference type is correct */ + + if ((Info->ReturnBtype & ExpectedBtypes) == ACPI_RTYPE_REFERENCE) + { + Status = AcpiNsCheckReference (Info, ReturnObject); + return (Status); + } + + /* Attempt simple repair of the returned object if necessary */ + + Status = AcpiNsSimpleRepair (Info, ExpectedBtypes, + PackageIndex, ReturnObjectPtr); + if (ACPI_SUCCESS (Status)) + { + return (AE_OK); /* Successful repair */ + } + + +TypeErrorExit: + + /* Create a string with all expected types for this predefined object */ + + AcpiUtGetExpectedReturnTypes (TypeBuffer, ExpectedBtypes); + + if (!ReturnObject) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Expected return object of type %s", + TypeBuffer)); + } + else if (PackageIndex == ACPI_NOT_PACKAGE_ELEMENT) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Return type mismatch - found %s, expected %s", + AcpiUtGetObjectTypeName (ReturnObject), TypeBuffer)); + } + else + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Return Package type mismatch at index %u - " + "found %s, expected %s", PackageIndex, + AcpiUtGetObjectTypeName (ReturnObject), TypeBuffer)); + } + + return (AE_AML_OPERAND_TYPE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckReference + * + * PARAMETERS: Info - Method execution information block + * ReturnObject - Object returned from the evaluation of a + * method or object + * + * RETURN: Status + * + * DESCRIPTION: Check a returned reference object for the correct reference + * type. The only reference type that can be returned from a + * predefined method is a named reference. All others are invalid. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsCheckReference ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *ReturnObject) +{ + + /* + * Check the reference object for the correct reference type (opcode). + * The only type of reference that can be converted to an ACPI_OBJECT is + * a reference to a named object (reference class: NAME) + */ + if (ReturnObject->Reference.Class == ACPI_REFCLASS_NAME) + { + return (AE_OK); + } + + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Return type mismatch - unexpected reference object type [%s] %2.2X", + AcpiUtGetReferenceName (ReturnObject), + ReturnObject->Reference.Class)); + + return (AE_AML_OPERAND_TYPE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetBitmappedType + * + * PARAMETERS: ReturnObject - Object returned from method/obj evaluation + * + * RETURN: Object return type. ACPI_RTYPE_ANY indicates that the object + * type is not supported. ACPI_RTYPE_NONE indicates that no + * object was returned (ReturnObject is NULL). + * + * DESCRIPTION: Convert object type into a bitmapped object return type. + * + ******************************************************************************/ + +static UINT32 +AcpiNsGetBitmappedType ( + ACPI_OPERAND_OBJECT *ReturnObject) +{ + UINT32 ReturnBtype; + + + if (!ReturnObject) + { + return (ACPI_RTYPE_NONE); + } + + /* Map ACPI_OBJECT_TYPE to internal bitmapped type */ + + switch (ReturnObject->Common.Type) + { + case ACPI_TYPE_INTEGER: + + ReturnBtype = ACPI_RTYPE_INTEGER; + break; + + case ACPI_TYPE_BUFFER: + + ReturnBtype = ACPI_RTYPE_BUFFER; + break; + + case ACPI_TYPE_STRING: + + ReturnBtype = ACPI_RTYPE_STRING; + break; + + case ACPI_TYPE_PACKAGE: + + ReturnBtype = ACPI_RTYPE_PACKAGE; + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + ReturnBtype = ACPI_RTYPE_REFERENCE; + break; + + default: + + /* Not one of the supported objects, must be incorrect */ + + ReturnBtype = ACPI_RTYPE_ANY; + break; + } + + return (ReturnBtype); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsprepkg.c b/third_party/lib/acpica/source/components/namespace/nsprepkg.c new file mode 100644 index 000000000..3cc9f5360 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsprepkg.c @@ -0,0 +1,685 @@ +/****************************************************************************** + * + * Module Name: nsprepkg - Validation of package objects for predefined names + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsprepkg") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiNsCheckPackageList ( + ACPI_EVALUATE_INFO *Info, + const ACPI_PREDEFINED_INFO *Package, + ACPI_OPERAND_OBJECT **Elements, + UINT32 Count); + +static ACPI_STATUS +AcpiNsCheckPackageElements ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **Elements, + UINT8 Type1, + UINT32 Count1, + UINT8 Type2, + UINT32 Count2, + UINT32 StartIndex); + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckPackage + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status + * + * DESCRIPTION: Check a returned package object for the correct count and + * correct type of all sub-objects. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsCheckPackage ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + const ACPI_PREDEFINED_INFO *Package; + ACPI_OPERAND_OBJECT **Elements; + ACPI_STATUS Status = AE_OK; + UINT32 ExpectedCount; + UINT32 Count; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsCheckPackage); + + + /* The package info for this name is in the next table entry */ + + Package = Info->Predefined + 1; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%s Validating return Package of Type %X, Count %X\n", + Info->FullPathname, Package->RetInfo.Type, + ReturnObject->Package.Count)); + + /* + * For variable-length Packages, we can safely remove all embedded + * and trailing NULL package elements + */ + AcpiNsRemoveNullElements (Info, Package->RetInfo.Type, ReturnObject); + + /* Extract package count and elements array */ + + Elements = ReturnObject->Package.Elements; + Count = ReturnObject->Package.Count; + + /* + * Most packages must have at least one element. The only exception + * is the variable-length package (ACPI_PTYPE1_VAR). + */ + if (!Count) + { + if (Package->RetInfo.Type == ACPI_PTYPE1_VAR) + { + return (AE_OK); + } + + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Return Package has no elements (empty)")); + + return (AE_AML_OPERAND_VALUE); + } + + /* + * Decode the type of the expected package contents + * + * PTYPE1 packages contain no subpackages + * PTYPE2 packages contain subpackages + */ + switch (Package->RetInfo.Type) + { + case ACPI_PTYPE1_FIXED: + /* + * The package count is fixed and there are no subpackages + * + * If package is too small, exit. + * If package is larger than expected, issue warning but continue + */ + ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; + if (Count < ExpectedCount) + { + goto PackageTooSmall; + } + else if (Count > ExpectedCount) + { + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Return Package is larger than needed - " + "found %u, expected %u\n", + Info->FullPathname, Count, ExpectedCount)); + } + + /* Validate all elements of the returned package */ + + Status = AcpiNsCheckPackageElements (Info, Elements, + Package->RetInfo.ObjectType1, Package->RetInfo.Count1, + Package->RetInfo.ObjectType2, Package->RetInfo.Count2, 0); + break; + + case ACPI_PTYPE1_VAR: + /* + * The package count is variable, there are no subpackages, and all + * elements must be of the same type + */ + for (i = 0; i < Count; i++) + { + Status = AcpiNsCheckObjectType (Info, Elements, + Package->RetInfo.ObjectType1, i); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + Elements++; + } + break; + + case ACPI_PTYPE1_OPTION: + /* + * The package count is variable, there are no subpackages. There are + * a fixed number of required elements, and a variable number of + * optional elements. + * + * Check if package is at least as large as the minimum required + */ + ExpectedCount = Package->RetInfo3.Count; + if (Count < ExpectedCount) + { + goto PackageTooSmall; + } + + /* Variable number of sub-objects */ + + for (i = 0; i < Count; i++) + { + if (i < Package->RetInfo3.Count) + { + /* These are the required package elements (0, 1, or 2) */ + + Status = AcpiNsCheckObjectType (Info, Elements, + Package->RetInfo3.ObjectType[i], i); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* These are the optional package elements */ + + Status = AcpiNsCheckObjectType (Info, Elements, + Package->RetInfo3.TailObjectType, i); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + Elements++; + } + break; + + case ACPI_PTYPE2_REV_FIXED: + + /* First element is the (Integer) revision */ + + Status = AcpiNsCheckObjectType ( + Info, Elements, ACPI_RTYPE_INTEGER, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Elements++; + Count--; + + /* Examine the subpackages */ + + Status = AcpiNsCheckPackageList (Info, Package, Elements, Count); + break; + + case ACPI_PTYPE2_PKG_COUNT: + + /* First element is the (Integer) count of subpackages to follow */ + + Status = AcpiNsCheckObjectType ( + Info, Elements, ACPI_RTYPE_INTEGER, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Count cannot be larger than the parent package length, but allow it + * to be smaller. The >= accounts for the Integer above. + */ + ExpectedCount = (UINT32) (*Elements)->Integer.Value; + if (ExpectedCount >= Count) + { + goto PackageTooSmall; + } + + Count = ExpectedCount; + Elements++; + + /* Examine the subpackages */ + + Status = AcpiNsCheckPackageList (Info, Package, Elements, Count); + break; + + case ACPI_PTYPE2: + case ACPI_PTYPE2_FIXED: + case ACPI_PTYPE2_MIN: + case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_FIX_VAR: + /* + * These types all return a single Package that consists of a + * variable number of subpackages. + * + * First, ensure that the first element is a subpackage. If not, + * the BIOS may have incorrectly returned the object as a single + * package instead of a Package of Packages (a common error if + * there is only one entry). We may be able to repair this by + * wrapping the returned Package with a new outer Package. + */ + if (*Elements && ((*Elements)->Common.Type != ACPI_TYPE_PACKAGE)) + { + /* Create the new outer package and populate it */ + + Status = AcpiNsWrapWithPackage ( + Info, ReturnObject, ReturnObjectPtr); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Update locals to point to the new package (of 1 element) */ + + ReturnObject = *ReturnObjectPtr; + Elements = ReturnObject->Package.Elements; + Count = 1; + } + + /* Examine the subpackages */ + + Status = AcpiNsCheckPackageList (Info, Package, Elements, Count); + break; + + case ACPI_PTYPE2_VAR_VAR: + /* + * Returns a variable list of packages, each with a variable list + * of objects. + */ + break; + + case ACPI_PTYPE2_UUID_PAIR: + + /* The package must contain pairs of (UUID + type) */ + + if (Count & 1) + { + ExpectedCount = Count + 1; + goto PackageTooSmall; + } + + while (Count > 0) + { + Status = AcpiNsCheckObjectType(Info, Elements, + Package->RetInfo.ObjectType1, 0); + if (ACPI_FAILURE(Status)) + { + return (Status); + } + + /* Validate length of the UUID buffer */ + + if ((*Elements)->Buffer.Length != 16) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, + Info->NodeFlags, "Invalid length for UUID Buffer")); + return (AE_AML_OPERAND_VALUE); + } + + Status = AcpiNsCheckObjectType(Info, Elements + 1, + Package->RetInfo.ObjectType2, 0); + if (ACPI_FAILURE(Status)) + { + return (Status); + } + + Elements += 2; + Count -= 2; + } + break; + + default: + + /* Should not get here if predefined info table is correct */ + + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Invalid internal return type in table entry: %X", + Package->RetInfo.Type)); + + return (AE_AML_INTERNAL); + } + + return (Status); + + +PackageTooSmall: + + /* Error exit for the case with an incorrect package count */ + + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Return Package is too small - found %u elements, expected %u", + Count, ExpectedCount)); + + return (AE_AML_OPERAND_VALUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckPackageList + * + * PARAMETERS: Info - Method execution information block + * Package - Pointer to package-specific info for method + * Elements - Element list of parent package. All elements + * of this list should be of type Package. + * Count - Count of subpackages + * + * RETURN: Status + * + * DESCRIPTION: Examine a list of subpackages + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsCheckPackageList ( + ACPI_EVALUATE_INFO *Info, + const ACPI_PREDEFINED_INFO *Package, + ACPI_OPERAND_OBJECT **Elements, + UINT32 Count) +{ + ACPI_OPERAND_OBJECT *SubPackage; + ACPI_OPERAND_OBJECT **SubElements; + ACPI_STATUS Status; + UINT32 ExpectedCount; + UINT32 i; + UINT32 j; + + + /* + * Validate each subpackage in the parent Package + * + * NOTE: assumes list of subpackages contains no NULL elements. + * Any NULL elements should have been removed by earlier call + * to AcpiNsRemoveNullElements. + */ + for (i = 0; i < Count; i++) + { + SubPackage = *Elements; + SubElements = SubPackage->Package.Elements; + Info->ParentPackage = SubPackage; + + /* Each sub-object must be of type Package */ + + Status = AcpiNsCheckObjectType (Info, &SubPackage, + ACPI_RTYPE_PACKAGE, i); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Examine the different types of expected subpackages */ + + Info->ParentPackage = SubPackage; + switch (Package->RetInfo.Type) + { + case ACPI_PTYPE2: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_REV_FIXED: + + /* Each subpackage has a fixed number of elements */ + + ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; + if (SubPackage->Package.Count < ExpectedCount) + { + goto PackageTooSmall; + } + + Status = AcpiNsCheckPackageElements (Info, SubElements, + Package->RetInfo.ObjectType1, + Package->RetInfo.Count1, + Package->RetInfo.ObjectType2, + Package->RetInfo.Count2, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_PTYPE2_FIX_VAR: + /* + * Each subpackage has a fixed number of elements and an + * optional element + */ + ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; + if (SubPackage->Package.Count < ExpectedCount) + { + goto PackageTooSmall; + } + + Status = AcpiNsCheckPackageElements (Info, SubElements, + Package->RetInfo.ObjectType1, + Package->RetInfo.Count1, + Package->RetInfo.ObjectType2, + SubPackage->Package.Count - Package->RetInfo.Count1, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_PTYPE2_VAR_VAR: + /* + * Each subpackage has a fixed or variable number of elements + */ + break; + + case ACPI_PTYPE2_FIXED: + + /* Each subpackage has a fixed length */ + + ExpectedCount = Package->RetInfo2.Count; + if (SubPackage->Package.Count < ExpectedCount) + { + goto PackageTooSmall; + } + + /* Check the type of each subpackage element */ + + for (j = 0; j < ExpectedCount; j++) + { + Status = AcpiNsCheckObjectType (Info, &SubElements[j], + Package->RetInfo2.ObjectType[j], j); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + break; + + case ACPI_PTYPE2_MIN: + + /* Each subpackage has a variable but minimum length */ + + ExpectedCount = Package->RetInfo.Count1; + if (SubPackage->Package.Count < ExpectedCount) + { + goto PackageTooSmall; + } + + /* Check the type of each subpackage element */ + + Status = AcpiNsCheckPackageElements (Info, SubElements, + Package->RetInfo.ObjectType1, + SubPackage->Package.Count, 0, 0, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_PTYPE2_COUNT: + /* + * First element is the (Integer) count of elements, including + * the count field (the ACPI name is NumElements) + */ + Status = AcpiNsCheckObjectType (Info, SubElements, + ACPI_RTYPE_INTEGER, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Make sure package is large enough for the Count and is + * is as large as the minimum size + */ + ExpectedCount = (UINT32) (*SubElements)->Integer.Value; + if (SubPackage->Package.Count < ExpectedCount) + { + goto PackageTooSmall; + } + if (SubPackage->Package.Count < Package->RetInfo.Count1) + { + ExpectedCount = Package->RetInfo.Count1; + goto PackageTooSmall; + } + if (ExpectedCount == 0) + { + /* + * Either the NumEntries element was originally zero or it was + * a NULL element and repaired to an Integer of value zero. + * In either case, repair it by setting NumEntries to be the + * actual size of the subpackage. + */ + ExpectedCount = SubPackage->Package.Count; + (*SubElements)->Integer.Value = ExpectedCount; + } + + /* Check the type of each subpackage element */ + + Status = AcpiNsCheckPackageElements (Info, (SubElements + 1), + Package->RetInfo.ObjectType1, + (ExpectedCount - 1), 0, 0, 1); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + default: /* Should not get here, type was validated by caller */ + + return (AE_AML_INTERNAL); + } + + Elements++; + } + + return (AE_OK); + + +PackageTooSmall: + + /* The subpackage count was smaller than required */ + + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Return SubPackage[%u] is too small - found %u elements, expected %u", + i, SubPackage->Package.Count, ExpectedCount)); + + return (AE_AML_OPERAND_VALUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsCheckPackageElements + * + * PARAMETERS: Info - Method execution information block + * Elements - Pointer to the package elements array + * Type1 - Object type for first group + * Count1 - Count for first group + * Type2 - Object type for second group + * Count2 - Count for second group + * StartIndex - Start of the first group of elements + * + * RETURN: Status + * + * DESCRIPTION: Check that all elements of a package are of the correct object + * type. Supports up to two groups of different object types. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsCheckPackageElements ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **Elements, + UINT8 Type1, + UINT32 Count1, + UINT8 Type2, + UINT32 Count2, + UINT32 StartIndex) +{ + ACPI_OPERAND_OBJECT **ThisElement = Elements; + ACPI_STATUS Status; + UINT32 i; + + + /* + * Up to two groups of package elements are supported by the data + * structure. All elements in each group must be of the same type. + * The second group can have a count of zero. + */ + for (i = 0; i < Count1; i++) + { + Status = AcpiNsCheckObjectType (Info, ThisElement, + Type1, i + StartIndex); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + ThisElement++; + } + + for (i = 0; i < Count2; i++) + { + Status = AcpiNsCheckObjectType (Info, ThisElement, + Type2, (i + Count1 + StartIndex)); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + ThisElement++; + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsrepair.c b/third_party/lib/acpica/source/components/namespace/nsrepair.c new file mode 100644 index 000000000..524fcf667 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsrepair.c @@ -0,0 +1,641 @@ +/****************************************************************************** + * + * Module Name: nsrepair - Repair for objects returned by predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "acpredef.h" +#include "amlresrc.h" + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsrepair") + + +/******************************************************************************* + * + * This module attempts to repair or convert objects returned by the + * predefined methods to an object type that is expected, as per the ACPI + * specification. The need for this code is dictated by the many machines that + * return incorrect types for the standard predefined methods. Performing these + * conversions here, in one place, eliminates the need for individual ACPI + * device drivers to do the same. Note: Most of these conversions are different + * than the internal object conversion routines used for implicit object + * conversion. + * + * The following conversions can be performed as necessary: + * + * Integer -> String + * Integer -> Buffer + * String -> Integer + * String -> Buffer + * Buffer -> Integer + * Buffer -> String + * Buffer -> Package of Integers + * Package -> Package of one Package + * + * Additional conversions that are available: + * Convert a null return or zero return value to an EndTag descriptor + * Convert an ASCII string to a Unicode buffer + * + * An incorrect standalone object is wrapped with required outer package + * + * Additional possible repairs: + * Required package elements that are NULL replaced by Integer/String/Buffer + * + ******************************************************************************/ + + +/* Local prototypes */ + +static const ACPI_SIMPLE_REPAIR_INFO * +AcpiNsMatchSimpleRepair ( + ACPI_NAMESPACE_NODE *Node, + UINT32 ReturnBtype, + UINT32 PackageIndex); + + +/* + * Special but simple repairs for some names. + * + * 2nd argument: Unexpected types that can be repaired + */ +static const ACPI_SIMPLE_REPAIR_INFO AcpiObjectRepairInfo[] = +{ + /* Resource descriptor conversions */ + + { "_CRS", ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | ACPI_RTYPE_NONE, + ACPI_NOT_PACKAGE_ELEMENT, + AcpiNsConvertToResource }, + { "_DMA", ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | ACPI_RTYPE_NONE, + ACPI_NOT_PACKAGE_ELEMENT, + AcpiNsConvertToResource }, + { "_PRS", ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | ACPI_RTYPE_NONE, + ACPI_NOT_PACKAGE_ELEMENT, + AcpiNsConvertToResource }, + + /* Object reference conversions */ + + { "_DEP", ACPI_RTYPE_STRING, ACPI_ALL_PACKAGE_ELEMENTS, + AcpiNsConvertToReference }, + + /* Unicode conversions */ + + { "_MLS", ACPI_RTYPE_STRING, 1, + AcpiNsConvertToUnicode }, + { "_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, + ACPI_NOT_PACKAGE_ELEMENT, + AcpiNsConvertToUnicode }, + { {0,0,0,0}, 0, 0, NULL } /* Table terminator */ +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiNsSimpleRepair + * + * PARAMETERS: Info - Method execution information block + * ExpectedBtypes - Object types expected + * PackageIndex - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. + * + * DESCRIPTION: Attempt to repair/convert a return object of a type that was + * not expected. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsSimpleRepair ( + ACPI_EVALUATE_INFO *Info, + UINT32 ExpectedBtypes, + UINT32 PackageIndex, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *NewObject = NULL; + ACPI_STATUS Status; + const ACPI_SIMPLE_REPAIR_INFO *Predefined; + + + ACPI_FUNCTION_NAME (NsSimpleRepair); + + + /* + * Special repairs for certain names that are in the repair table. + * Check if this name is in the list of repairable names. + */ + Predefined = AcpiNsMatchSimpleRepair (Info->Node, + Info->ReturnBtype, PackageIndex); + if (Predefined) + { + if (!ReturnObject) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, + ACPI_WARN_ALWAYS, "Missing expected return value")); + } + + Status = Predefined->ObjectConverter (Info->Node, ReturnObject, + &NewObject); + if (ACPI_FAILURE (Status)) + { + /* A fatal error occurred during a conversion */ + + ACPI_EXCEPTION ((AE_INFO, Status, + "During return object analysis")); + return (Status); + } + if (NewObject) + { + goto ObjectRepaired; + } + } + + /* + * Do not perform simple object repair unless the return type is not + * expected. + */ + if (Info->ReturnBtype & ExpectedBtypes) + { + return (AE_OK); + } + + /* + * At this point, we know that the type of the returned object was not + * one of the expected types for this predefined name. Attempt to + * repair the object by converting it to one of the expected object + * types for this predefined name. + */ + + /* + * If there is no return value, check if we require a return value for + * this predefined name. Either one return value is expected, or none, + * for both methods and other objects. + * + * Try to fix if there was no return object. Warning if failed to fix. + */ + if (!ReturnObject) + { + if (ExpectedBtypes && (!(ExpectedBtypes & ACPI_RTYPE_NONE))) + { + if (PackageIndex != ACPI_NOT_PACKAGE_ELEMENT) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, + ACPI_WARN_ALWAYS, "Found unexpected NULL package element")); + + Status = AcpiNsRepairNullElement (Info, ExpectedBtypes, + PackageIndex, ReturnObjectPtr); + if (ACPI_SUCCESS (Status)) + { + return (AE_OK); /* Repair was successful */ + } + } + else + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, + ACPI_WARN_ALWAYS, "Missing expected return value")); + } + + return (AE_AML_NO_RETURN_VALUE); + } + } + + if (ExpectedBtypes & ACPI_RTYPE_INTEGER) + { + Status = AcpiNsConvertToInteger (ReturnObject, &NewObject); + if (ACPI_SUCCESS (Status)) + { + goto ObjectRepaired; + } + } + if (ExpectedBtypes & ACPI_RTYPE_STRING) + { + Status = AcpiNsConvertToString (ReturnObject, &NewObject); + if (ACPI_SUCCESS (Status)) + { + goto ObjectRepaired; + } + } + if (ExpectedBtypes & ACPI_RTYPE_BUFFER) + { + Status = AcpiNsConvertToBuffer (ReturnObject, &NewObject); + if (ACPI_SUCCESS (Status)) + { + goto ObjectRepaired; + } + } + if (ExpectedBtypes & ACPI_RTYPE_PACKAGE) + { + /* + * A package is expected. We will wrap the existing object with a + * new package object. It is often the case that if a variable-length + * package is required, but there is only a single object needed, the + * BIOS will return that object instead of wrapping it with a Package + * object. Note: after the wrapping, the package will be validated + * for correct contents (expected object type or types). + */ + Status = AcpiNsWrapWithPackage (Info, ReturnObject, &NewObject); + if (ACPI_SUCCESS (Status)) + { + /* + * The original object just had its reference count + * incremented for being inserted into the new package. + */ + *ReturnObjectPtr = NewObject; /* New Package object */ + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); + } + } + + /* We cannot repair this object */ + + return (AE_AML_OPERAND_TYPE); + + +ObjectRepaired: + + /* Object was successfully repaired */ + + if (PackageIndex != ACPI_NOT_PACKAGE_ELEMENT) + { + /* + * The original object is a package element. We need to + * decrement the reference count of the original object, + * for removing it from the package. + * + * However, if the original object was just wrapped with a + * package object as part of the repair, we don't need to + * change the reference count. + */ + if (!(Info->ReturnFlags & ACPI_OBJECT_WRAPPED)) + { + NewObject->Common.ReferenceCount = + ReturnObject->Common.ReferenceCount; + + if (ReturnObject->Common.ReferenceCount > 1) + { + ReturnObject->Common.ReferenceCount--; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Converted %s to expected %s at Package index %u\n", + Info->FullPathname, AcpiUtGetObjectTypeName (ReturnObject), + AcpiUtGetObjectTypeName (NewObject), PackageIndex)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Converted %s to expected %s\n", + Info->FullPathname, AcpiUtGetObjectTypeName (ReturnObject), + AcpiUtGetObjectTypeName (NewObject))); + } + + /* Delete old object, install the new return object */ + + AcpiUtRemoveReference (ReturnObject); + *ReturnObjectPtr = NewObject; + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsMatchSimpleRepair + * + * PARAMETERS: Node - Namespace node for the method/object + * ReturnBtype - Object type that was returned + * PackageIndex - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * + * RETURN: Pointer to entry in repair table. NULL indicates not found. + * + * DESCRIPTION: Check an object name against the repairable object list. + * + *****************************************************************************/ + +static const ACPI_SIMPLE_REPAIR_INFO * +AcpiNsMatchSimpleRepair ( + ACPI_NAMESPACE_NODE *Node, + UINT32 ReturnBtype, + UINT32 PackageIndex) +{ + const ACPI_SIMPLE_REPAIR_INFO *ThisName; + + + /* Search info table for a repairable predefined method/object name */ + + ThisName = AcpiObjectRepairInfo; + while (ThisName->ObjectConverter) + { + if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name)) + { + /* Check if we can actually repair this name/type combination */ + + if ((ReturnBtype & ThisName->UnexpectedBtypes) && + (ThisName->PackageIndex == ACPI_ALL_PACKAGE_ELEMENTS || + PackageIndex == ThisName->PackageIndex)) + { + return (ThisName); + } + + return (NULL); + } + + ThisName++; + } + + return (NULL); /* Name was not found in the repair table */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsRepairNullElement + * + * PARAMETERS: Info - Method execution information block + * ExpectedBtypes - Object types expected + * PackageIndex - Index of object within parent package (if + * applicable - ACPI_NOT_PACKAGE_ELEMENT + * otherwise) + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. + * + * DESCRIPTION: Attempt to repair a NULL element of a returned Package object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsRepairNullElement ( + ACPI_EVALUATE_INFO *Info, + UINT32 ExpectedBtypes, + UINT32 PackageIndex, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *NewObject; + + + ACPI_FUNCTION_NAME (NsRepairNullElement); + + + /* No repair needed if return object is non-NULL */ + + if (ReturnObject) + { + return (AE_OK); + } + + /* + * Attempt to repair a NULL element of a Package object. This applies to + * predefined names that return a fixed-length package and each element + * is required. It does not apply to variable-length packages where NULL + * elements are allowed, especially at the end of the package. + */ + if (ExpectedBtypes & ACPI_RTYPE_INTEGER) + { + /* Need an Integer - create a zero-value integer */ + + NewObject = AcpiUtCreateIntegerObject ((UINT64) 0); + } + else if (ExpectedBtypes & ACPI_RTYPE_STRING) + { + /* Need a String - create a NULL string */ + + NewObject = AcpiUtCreateStringObject (0); + } + else if (ExpectedBtypes & ACPI_RTYPE_BUFFER) + { + /* Need a Buffer - create a zero-length buffer */ + + NewObject = AcpiUtCreateBufferObject (0); + } + else + { + /* Error for all other expected types */ + + return (AE_AML_OPERAND_TYPE); + } + + if (!NewObject) + { + return (AE_NO_MEMORY); + } + + /* Set the reference count according to the parent Package object */ + + NewObject->Common.ReferenceCount = + Info->ParentPackage->Common.ReferenceCount; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Converted NULL package element to expected %s at index %u\n", + Info->FullPathname, AcpiUtGetObjectTypeName (NewObject), + PackageIndex)); + + *ReturnObjectPtr = NewObject; + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRemoveNullElements + * + * PARAMETERS: Info - Method execution information block + * PackageType - An AcpiReturnPackageTypes value + * ObjDesc - A Package object + * + * RETURN: None. + * + * DESCRIPTION: Remove all NULL package elements from packages that contain + * a variable number of subpackages. For these types of + * packages, NULL elements can be safely removed. + * + *****************************************************************************/ + +void +AcpiNsRemoveNullElements ( + ACPI_EVALUATE_INFO *Info, + UINT8 PackageType, + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_OPERAND_OBJECT **Source; + ACPI_OPERAND_OBJECT **Dest; + UINT32 Count; + UINT32 NewCount; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRemoveNullElements); + + + /* + * We can safely remove all NULL elements from these package types: + * PTYPE1_VAR packages contain a variable number of simple data types. + * PTYPE2 packages contain a variable number of subpackages. + */ + switch (PackageType) + { + case ACPI_PTYPE1_VAR: + case ACPI_PTYPE2: + case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_FIXED: + case ACPI_PTYPE2_MIN: + case ACPI_PTYPE2_REV_FIXED: + case ACPI_PTYPE2_FIX_VAR: + break; + + default: + case ACPI_PTYPE2_VAR_VAR: + case ACPI_PTYPE1_FIXED: + case ACPI_PTYPE1_OPTION: + return; + } + + Count = ObjDesc->Package.Count; + NewCount = Count; + + Source = ObjDesc->Package.Elements; + Dest = Source; + + /* Examine all elements of the package object, remove nulls */ + + for (i = 0; i < Count; i++) + { + if (!*Source) + { + NewCount--; + } + else + { + *Dest = *Source; + Dest++; + } + + Source++; + } + + /* Update parent package if any null elements were removed */ + + if (NewCount < Count) + { + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Found and removed %u NULL elements\n", + Info->FullPathname, (Count - NewCount))); + + /* NULL terminate list and update the package count */ + + *Dest = NULL; + ObjDesc->Package.Count = NewCount; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsWrapWithPackage + * + * PARAMETERS: Info - Method execution information block + * OriginalObject - Pointer to the object to repair. + * ObjDescPtr - The new package object is returned here + * + * RETURN: Status, new object in *ObjDescPtr + * + * DESCRIPTION: Repair a common problem with objects that are defined to + * return a variable-length Package of sub-objects. If there is + * only one sub-object, some BIOS code mistakenly simply declares + * the single object instead of a Package with one sub-object. + * This function attempts to repair this error by wrapping a + * Package object around the original object, creating the + * correct and expected Package with one sub-object. + * + * Names that can be repaired in this manner include: + * _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS, + * _BCL, _DOD, _FIX, _Sx + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsWrapWithPackage ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ObjDescPtr) +{ + ACPI_OPERAND_OBJECT *PkgObjDesc; + + + ACPI_FUNCTION_NAME (NsWrapWithPackage); + + + /* + * Create the new outer package and populate it. The new + * package will have a single element, the lone sub-object. + */ + PkgObjDesc = AcpiUtCreatePackageObject (1); + if (!PkgObjDesc) + { + return (AE_NO_MEMORY); + } + + PkgObjDesc->Package.Elements[0] = OriginalObject; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Wrapped %s with expected Package object\n", + Info->FullPathname, AcpiUtGetObjectTypeName (OriginalObject))); + + /* Return the new object in the object pointer */ + + *ObjDescPtr = PkgObjDesc; + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED; + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsrepair2.c b/third_party/lib/acpica/source/components/namespace/nsrepair2.c new file mode 100644 index 000000000..d8625899a --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsrepair2.c @@ -0,0 +1,1083 @@ +/****************************************************************************** + * + * Module Name: nsrepair2 - Repair for objects returned by specific + * predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsrepair2") + + +/* + * Information structure and handler for ACPI predefined names that can + * be repaired on a per-name basis. + */ +typedef +ACPI_STATUS (*ACPI_REPAIR_FUNCTION) ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +typedef struct acpi_repair_info +{ + char Name[ACPI_NAME_SIZE]; + ACPI_REPAIR_FUNCTION RepairFunction; + +} ACPI_REPAIR_INFO; + + +/* Local prototypes */ + +static const ACPI_REPAIR_INFO * +AcpiNsMatchComplexRepair ( + ACPI_NAMESPACE_NODE *Node); + +static ACPI_STATUS +AcpiNsRepair_ALR ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_CID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_CST ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_FDE ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_HID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_PRT ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_PSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_TSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsCheckSortedList ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *ReturnObject, + UINT32 StartIndex, + UINT32 ExpectedCount, + UINT32 SortIndex, + UINT8 SortDirection, + char *SortKeyName); + +/* Values for SortDirection above */ + +#define ACPI_SORT_ASCENDING 0 +#define ACPI_SORT_DESCENDING 1 + +static void +AcpiNsRemoveElement ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Index); + +static void +AcpiNsSortList ( + ACPI_OPERAND_OBJECT **Elements, + UINT32 Count, + UINT32 Index, + UINT8 SortDirection); + + +/* + * This table contains the names of the predefined methods for which we can + * perform more complex repairs. + * + * As necessary: + * + * _ALR: Sort the list ascending by AmbientIlluminance + * _CID: Strings: uppercase all, remove any leading asterisk + * _CST: Sort the list ascending by C state type + * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs + * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs + * _HID: Strings: uppercase all, remove any leading asterisk + * _PRT: Fix reversed SourceName and SourceIndex + * _PSS: Sort the list descending by Power + * _TSS: Sort the list descending by Power + * + * Names that must be packages, but cannot be sorted: + * + * _BCL: Values are tied to the Package index where they appear, and cannot + * be moved or sorted. These index values are used for _BQC and _BCM. + * However, we can fix the case where a buffer is returned, by converting + * it to a Package of integers. + */ +static const ACPI_REPAIR_INFO AcpiNsRepairableNames[] = +{ + {"_ALR", AcpiNsRepair_ALR}, + {"_CID", AcpiNsRepair_CID}, + {"_CST", AcpiNsRepair_CST}, + {"_FDE", AcpiNsRepair_FDE}, + {"_GTM", AcpiNsRepair_FDE}, /* _GTM has same repair as _FDE */ + {"_HID", AcpiNsRepair_HID}, + {"_PRT", AcpiNsRepair_PRT}, + {"_PSS", AcpiNsRepair_PSS}, + {"_TSS", AcpiNsRepair_TSS}, + {{0,0,0,0}, NULL} /* Table terminator */ +}; + + +#define ACPI_FDE_FIELD_COUNT 5 +#define ACPI_FDE_BYTE_BUFFER_SIZE 5 +#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (UINT32)) + + +/****************************************************************************** + * + * FUNCTION: AcpiNsComplexRepairs + * + * PARAMETERS: Info - Method execution information block + * Node - Namespace node for the method/object + * ValidateStatus - Original status of earlier validation + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. If name is not + * matched, ValidateStatus is returned. + * + * DESCRIPTION: Attempt to repair/convert a return object of a type that was + * not expected. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiNsComplexRepairs ( + ACPI_EVALUATE_INFO *Info, + ACPI_NAMESPACE_NODE *Node, + ACPI_STATUS ValidateStatus, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + const ACPI_REPAIR_INFO *Predefined; + ACPI_STATUS Status; + + + /* Check if this name is in the list of repairable names */ + + Predefined = AcpiNsMatchComplexRepair (Node); + if (!Predefined) + { + return (ValidateStatus); + } + + Status = Predefined->RepairFunction (Info, ReturnObjectPtr); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsMatchComplexRepair + * + * PARAMETERS: Node - Namespace node for the method/object + * + * RETURN: Pointer to entry in repair table. NULL indicates not found. + * + * DESCRIPTION: Check an object name against the repairable object list. + * + *****************************************************************************/ + +static const ACPI_REPAIR_INFO * +AcpiNsMatchComplexRepair ( + ACPI_NAMESPACE_NODE *Node) +{ + const ACPI_REPAIR_INFO *ThisName; + + + /* Search info table for a repairable predefined method/object name */ + + ThisName = AcpiNsRepairableNames; + while (ThisName->RepairFunction) + { + if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name)) + { + return (ThisName); + } + + ThisName++; + } + + return (NULL); /* Not found */ +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_ALR + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list + * ascending by the ambient illuminance values. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_ALR ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_STATUS Status; + + + Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1, + ACPI_SORT_ASCENDING, "AmbientIlluminance"); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_FDE + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return + * value is a Buffer of 5 DWORDs. This function repairs a common + * problem where the return value is a Buffer of BYTEs, not + * DWORDs. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_FDE ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *BufferObject; + UINT8 *ByteBuffer; + UINT32 *DwordBuffer; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRepair_FDE); + + + switch (ReturnObject->Common.Type) + { + case ACPI_TYPE_BUFFER: + + /* This is the expected type. Length should be (at least) 5 DWORDs */ + + if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE) + { + return (AE_OK); + } + + /* We can only repair if we have exactly 5 BYTEs */ + + if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE) + { + ACPI_WARN_PREDEFINED ((AE_INFO, + Info->FullPathname, Info->NodeFlags, + "Incorrect return buffer length %u, expected %u", + ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE)); + + return (AE_AML_OPERAND_TYPE); + } + + /* Create the new (larger) buffer object */ + + BufferObject = AcpiUtCreateBufferObject ( + ACPI_FDE_DWORD_BUFFER_SIZE); + if (!BufferObject) + { + return (AE_NO_MEMORY); + } + + /* Expand each byte to a DWORD */ + + ByteBuffer = ReturnObject->Buffer.Pointer; + DwordBuffer = ACPI_CAST_PTR (UINT32, + BufferObject->Buffer.Pointer); + + for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) + { + *DwordBuffer = (UINT32) *ByteBuffer; + DwordBuffer++; + ByteBuffer++; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s Expanded Byte Buffer to expected DWord Buffer\n", + Info->FullPathname)); + break; + + default: + + return (AE_AML_OPERAND_TYPE); + } + + /* Delete the original return object, return the new buffer object */ + + AcpiUtRemoveReference (ReturnObject); + *ReturnObjectPtr = BufferObject; + + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_CID + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _CID object. If a string, ensure that all + * letters are uppercase and that there is no leading asterisk. + * If a Package, ensure same for all string elements. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_CID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **ElementPtr; + ACPI_OPERAND_OBJECT *OriginalElement; + UINT16 OriginalRefCount; + UINT32 i; + + + /* Check for _CID as a simple string */ + + if (ReturnObject->Common.Type == ACPI_TYPE_STRING) + { + Status = AcpiNsRepair_HID (Info, ReturnObjectPtr); + return (Status); + } + + /* Exit if not a Package */ + + if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_OK); + } + + /* Examine each element of the _CID package */ + + ElementPtr = ReturnObject->Package.Elements; + for (i = 0; i < ReturnObject->Package.Count; i++) + { + OriginalElement = *ElementPtr; + OriginalRefCount = OriginalElement->Common.ReferenceCount; + + Status = AcpiNsRepair_HID (Info, ElementPtr); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Take care with reference counts */ + + if (OriginalElement != *ElementPtr) + { + /* Element was replaced */ + + (*ElementPtr)->Common.ReferenceCount = + OriginalRefCount; + + AcpiUtRemoveReference (OriginalElement); + } + + ElementPtr++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_CST + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _CST object: + * 1. Sort the list ascending by C state type + * 2. Ensure type cannot be zero + * 3. A subpackage count of zero means _CST is meaningless + * 4. Count must match the number of C state subpackages + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_CST ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **OuterElements; + UINT32 OuterElementCount; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + BOOLEAN Removing; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRepair_CST); + + + /* + * Check if the C-state type values are proportional. + */ + OuterElementCount = ReturnObject->Package.Count - 1; + i = 0; + while (i < OuterElementCount) + { + OuterElements = &ReturnObject->Package.Elements[i + 1]; + Removing = FALSE; + + if ((*OuterElements)->Package.Count == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, + Info->FullPathname, Info->NodeFlags, + "SubPackage[%u] - removing entry due to zero count", i)); + Removing = TRUE; + goto RemoveElement; + } + + ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */ + if ((UINT32) ObjDesc->Integer.Value == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, + Info->FullPathname, Info->NodeFlags, + "SubPackage[%u] - removing entry due to invalid Type(0)", i)); + Removing = TRUE; + } + +RemoveElement: + if (Removing) + { + AcpiNsRemoveElement (ReturnObject, i + 1); + OuterElementCount--; + } + else + { + i++; + } + } + + /* Update top-level package count, Type "Integer" checked elsewhere */ + + ObjDesc = ReturnObject->Package.Elements[0]; + ObjDesc->Integer.Value = OuterElementCount; + + /* + * Entries (subpackages) in the _CST Package must be sorted by the + * C-state type, in ascending order. + */ + Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1, + ACPI_SORT_ASCENDING, "C-State Type"); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_HID + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _HID object. If a string, ensure that all + * letters are uppercase and that there is no leading asterisk. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_HID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *NewString; + char *Source; + char *Dest; + + + ACPI_FUNCTION_NAME (NsRepair_HID); + + + /* We only care about string _HID objects (not integers) */ + + if (ReturnObject->Common.Type != ACPI_TYPE_STRING) + { + return (AE_OK); + } + + if (ReturnObject->String.Length == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, + Info->FullPathname, Info->NodeFlags, + "Invalid zero-length _HID or _CID string")); + + /* Return AE_OK anyway, let driver handle it */ + + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); + } + + /* It is simplest to always create a new string object */ + + NewString = AcpiUtCreateStringObject (ReturnObject->String.Length); + if (!NewString) + { + return (AE_NO_MEMORY); + } + + /* + * Remove a leading asterisk if present. For some unknown reason, there + * are many machines in the field that contains IDs like this. + * + * Examples: "*PNP0C03", "*ACPI0003" + */ + Source = ReturnObject->String.Pointer; + if (*Source == '*') + { + Source++; + NewString->String.Length--; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Removed invalid leading asterisk\n", Info->FullPathname)); + } + + /* + * Copy and uppercase the string. From the ACPI 5.0 specification: + * + * A valid PNP ID must be of the form "AAA####" where A is an uppercase + * letter and # is a hex digit. A valid ACPI ID must be of the form + * "NNNN####" where N is an uppercase letter or decimal digit, and + * # is a hex digit. + */ + for (Dest = NewString->String.Pointer; *Source; Dest++, Source++) + { + *Dest = (char) toupper ((int) *Source); + } + + AcpiUtRemoveReference (ReturnObject); + *ReturnObjectPtr = NewString; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_PRT + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed + * SourceName and SourceIndex field, a common BIOS bug. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_PRT ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *PackageObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **TopObjectList; + ACPI_OPERAND_OBJECT **SubObjectList; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT *SubPackage; + UINT32 ElementCount; + UINT32 Index; + + + /* Each element in the _PRT package is a subpackage */ + + TopObjectList = PackageObject->Package.Elements; + ElementCount = PackageObject->Package.Count; + + /* Examine each subpackage */ + + for (Index = 0; Index < ElementCount; Index++, TopObjectList++) + { + SubPackage = *TopObjectList; + SubObjectList = SubPackage->Package.Elements; + + /* Check for minimum required element count */ + + if (SubPackage->Package.Count < 4) + { + continue; + } + + /* + * If the BIOS has erroneously reversed the _PRT SourceName (index 2) + * and the SourceIndex (index 3), fix it. _PRT is important enough to + * workaround this BIOS error. This also provides compatibility with + * other ACPI implementations. + */ + ObjDesc = SubObjectList[3]; + if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) + { + SubObjectList[3] = SubObjectList[2]; + SubObjectList[2] = ObjDesc; + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + + ACPI_WARN_PREDEFINED ((AE_INFO, + Info->FullPathname, Info->NodeFlags, + "PRT[%X]: Fixed reversed SourceName and SourceIndex", + Index)); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_PSS + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list + * by the CPU frequencies. Check that the power dissipation values + * are all proportional to CPU frequency (i.e., sorting by + * frequency should be the same as sorting by power.) + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_PSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **OuterElements; + UINT32 OuterElementCount; + ACPI_OPERAND_OBJECT **Elements; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 PreviousValue; + ACPI_STATUS Status; + UINT32 i; + + + /* + * Entries (subpackages) in the _PSS Package must be sorted by power + * dissipation, in descending order. If it appears that the list is + * incorrectly sorted, sort it. We sort by CpuFrequency, since this + * should be proportional to the power. + */ + Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0, + ACPI_SORT_DESCENDING, "CpuFrequency"); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * We now know the list is correctly sorted by CPU frequency. Check if + * the power dissipation values are proportional. + */ + PreviousValue = ACPI_UINT32_MAX; + OuterElements = ReturnObject->Package.Elements; + OuterElementCount = ReturnObject->Package.Count; + + for (i = 0; i < OuterElementCount; i++) + { + Elements = (*OuterElements)->Package.Elements; + ObjDesc = Elements[1]; /* Index1 = PowerDissipation */ + + if ((UINT32) ObjDesc->Integer.Value > PreviousValue) + { + ACPI_WARN_PREDEFINED ((AE_INFO, + Info->FullPathname, Info->NodeFlags, + "SubPackage[%u,%u] - suspicious power dissipation values", + i-1, i)); + } + + PreviousValue = (UINT32) ObjDesc->Integer.Value; + OuterElements++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_TSS + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list + * descending by the power dissipation values. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_TSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + /* + * We can only sort the _TSS return package if there is no _PSS in the + * same scope. This is because if _PSS is present, the ACPI specification + * dictates that the _TSS Power Dissipation field is to be ignored, and + * therefore some BIOSs leave garbage values in the _TSS Power field(s). + * In this case, it is best to just return the _TSS package as-is. + * (May, 2011) + */ + Status = AcpiNsGetNode (Info->Node, "^_PSS", + ACPI_NS_NO_UPSEARCH, &Node); + if (ACPI_SUCCESS (Status)) + { + return (AE_OK); + } + + Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1, + ACPI_SORT_DESCENDING, "PowerDissipation"); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsCheckSortedList + * + * PARAMETERS: Info - Method execution information block + * ReturnObject - Pointer to the top-level returned object + * StartIndex - Index of the first subpackage + * ExpectedCount - Minimum length of each subpackage + * SortIndex - Subpackage entry to sort on + * SortDirection - Ascending or descending + * SortKeyName - Name of the SortIndex field + * + * RETURN: Status. AE_OK if the list is valid and is sorted correctly or + * has been repaired by sorting the list. + * + * DESCRIPTION: Check if the package list is valid and sorted correctly by the + * SortIndex. If not, then sort the list. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsCheckSortedList ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *ReturnObject, + UINT32 StartIndex, + UINT32 ExpectedCount, + UINT32 SortIndex, + UINT8 SortDirection, + char *SortKeyName) +{ + UINT32 OuterElementCount; + ACPI_OPERAND_OBJECT **OuterElements; + ACPI_OPERAND_OBJECT **Elements; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 i; + UINT32 PreviousValue; + + + ACPI_FUNCTION_NAME (NsCheckSortedList); + + + /* The top-level object must be a package */ + + if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_AML_OPERAND_TYPE); + } + + /* + * NOTE: assumes list of subpackages contains no NULL elements. + * Any NULL elements should have been removed by earlier call + * to AcpiNsRemoveNullElements. + */ + OuterElementCount = ReturnObject->Package.Count; + if (!OuterElementCount || StartIndex >= OuterElementCount) + { + return (AE_AML_PACKAGE_LIMIT); + } + + OuterElements = &ReturnObject->Package.Elements[StartIndex]; + OuterElementCount -= StartIndex; + + PreviousValue = 0; + if (SortDirection == ACPI_SORT_DESCENDING) + { + PreviousValue = ACPI_UINT32_MAX; + } + + /* Examine each subpackage */ + + for (i = 0; i < OuterElementCount; i++) + { + /* Each element of the top-level package must also be a package */ + + if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_AML_OPERAND_TYPE); + } + + /* Each subpackage must have the minimum length */ + + if ((*OuterElements)->Package.Count < ExpectedCount) + { + return (AE_AML_PACKAGE_LIMIT); + } + + Elements = (*OuterElements)->Package.Elements; + ObjDesc = Elements[SortIndex]; + + if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) + { + return (AE_AML_OPERAND_TYPE); + } + + /* + * The list must be sorted in the specified order. If we detect a + * discrepancy, sort the entire list. + */ + if (((SortDirection == ACPI_SORT_ASCENDING) && + (ObjDesc->Integer.Value < PreviousValue)) || + ((SortDirection == ACPI_SORT_DESCENDING) && + (ObjDesc->Integer.Value > PreviousValue))) + { + AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex], + OuterElementCount, SortIndex, SortDirection); + + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Repaired unsorted list - now sorted by %s\n", + Info->FullPathname, SortKeyName)); + return (AE_OK); + } + + PreviousValue = (UINT32) ObjDesc->Integer.Value; + OuterElements++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsSortList + * + * PARAMETERS: Elements - Package object element list + * Count - Element count for above + * Index - Sort by which package element + * SortDirection - Ascending or Descending sort + * + * RETURN: None + * + * DESCRIPTION: Sort the objects that are in a package element list. + * + * NOTE: Assumes that all NULL elements have been removed from the package, + * and that all elements have been verified to be of type Integer. + * + *****************************************************************************/ + +static void +AcpiNsSortList ( + ACPI_OPERAND_OBJECT **Elements, + UINT32 Count, + UINT32 Index, + UINT8 SortDirection) +{ + ACPI_OPERAND_OBJECT *ObjDesc1; + ACPI_OPERAND_OBJECT *ObjDesc2; + ACPI_OPERAND_OBJECT *TempObj; + UINT32 i; + UINT32 j; + + + /* Simple bubble sort */ + + for (i = 1; i < Count; i++) + { + for (j = (Count - 1); j >= i; j--) + { + ObjDesc1 = Elements[j-1]->Package.Elements[Index]; + ObjDesc2 = Elements[j]->Package.Elements[Index]; + + if (((SortDirection == ACPI_SORT_ASCENDING) && + (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) || + + ((SortDirection == ACPI_SORT_DESCENDING) && + (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value))) + { + TempObj = Elements[j-1]; + Elements[j-1] = Elements[j]; + Elements[j] = TempObj; + } + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRemoveElement + * + * PARAMETERS: ObjDesc - Package object element list + * Index - Index of element to remove + * + * RETURN: None + * + * DESCRIPTION: Remove the requested element of a package and delete it. + * + *****************************************************************************/ + +static void +AcpiNsRemoveElement ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Index) +{ + ACPI_OPERAND_OBJECT **Source; + ACPI_OPERAND_OBJECT **Dest; + UINT32 Count; + UINT32 NewCount; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRemoveElement); + + + Count = ObjDesc->Package.Count; + NewCount = Count - 1; + + Source = ObjDesc->Package.Elements; + Dest = Source; + + /* Examine all elements of the package object, remove matched index */ + + for (i = 0; i < Count; i++) + { + if (i == Index) + { + AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */ + AcpiUtRemoveReference (*Source); + } + else + { + *Dest = *Source; + Dest++; + } + + Source++; + } + + /* NULL terminate list and update the package count */ + + *Dest = NULL; + ObjDesc->Package.Count = NewCount; +} diff --git a/third_party/lib/acpica/source/components/namespace/nssearch.c b/third_party/lib/acpica/source/components/namespace/nssearch.c new file mode 100644 index 000000000..3a0fe90ea --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nssearch.c @@ -0,0 +1,453 @@ +/******************************************************************************* + * + * Module Name: nssearch - Namespace search + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + +#ifdef ACPI_ASL_COMPILER +#include "amlcode.h" +#endif + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nssearch") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiNsSearchParentTree ( + UINT32 TargetName, + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE **ReturnNode); + + +/******************************************************************************* + * + * FUNCTION: AcpiNsSearchOneScope + * + * PARAMETERS: TargetName - Ascii ACPI name to search for + * ParentNode - Starting node where search will begin + * Type - Object type to match + * ReturnNode - Where the matched Named obj is returned + * + * RETURN: Status + * + * DESCRIPTION: Search a single level of the namespace. Performs a + * simple search of the specified level, and does not add + * entries or search parents. + * + * + * Named object lists are built (and subsequently dumped) in the + * order in which the names are encountered during the namespace load; + * + * All namespace searching is linear in this implementation, but + * could be easily modified to support any improved search + * algorithm. However, the linear search was chosen for simplicity + * and because the trees are small and the other interpreter + * execution overhead is relatively high. + * + * Note: CPU execution analysis has shown that the AML interpreter spends + * a very small percentage of its time searching the namespace. Therefore, + * the linear search seems to be sufficient, as there would seem to be + * little value in improving the search. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsSearchOneScope ( + UINT32 TargetName, + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (NsSearchOneScope); + + +#ifdef ACPI_DEBUG_OUTPUT + if (ACPI_LV_NAMES & AcpiDbgLevel) + { + char *ScopeName; + + ScopeName = AcpiNsGetNormalizedPathname (ParentNode, TRUE); + if (ScopeName) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching %s (%p) For [%4.4s] (%s)\n", + ScopeName, ParentNode, ACPI_CAST_PTR (char, &TargetName), + AcpiUtGetTypeName (Type))); + + ACPI_FREE (ScopeName); + } + } +#endif + + /* + * Search for name at this namespace level, which is to say that we + * must search for the name among the children of this object + */ + Node = ParentNode->Child; + while (Node) + { + /* Check for match against the name */ + + if (Node->Name.Integer == TargetName) + { + /* Resolve a control method alias if any */ + + if (AcpiNsGetType (Node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) + { + Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Node->Object); + } + + /* Found matching entry */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n", + ACPI_CAST_PTR (char, &TargetName), + AcpiUtGetTypeName (Node->Type), + Node, AcpiUtGetNodeName (ParentNode), ParentNode)); + + *ReturnNode = Node; + return_ACPI_STATUS (AE_OK); + } + + /* Didn't match name, move on to the next peer object */ + + Node = Node->Peer; + } + + /* Searched entire namespace level, not found */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Name [%4.4s] (%s) not found in search in scope [%4.4s] " + "%p first child %p\n", + ACPI_CAST_PTR (char, &TargetName), AcpiUtGetTypeName (Type), + AcpiUtGetNodeName (ParentNode), ParentNode, ParentNode->Child)); + + return_ACPI_STATUS (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsSearchParentTree + * + * PARAMETERS: TargetName - Ascii ACPI name to search for + * Node - Starting node where search will begin + * Type - Object type to match + * ReturnNode - Where the matched Node is returned + * + * RETURN: Status + * + * DESCRIPTION: Called when a name has not been found in the current namespace + * level. Before adding it or giving up, ACPI scope rules require + * searching enclosing scopes in cases identified by AcpiNsLocal(). + * + * "A name is located by finding the matching name in the current + * name space, and then in the parent name space. If the parent + * name space does not contain the name, the search continues + * recursively until either the name is found or the name space + * does not have a parent (the root of the name space). This + * indicates that the name is not found" (From ACPI Specification, + * section 5.3) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsSearchParentTree ( + UINT32 TargetName, + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *ParentNode; + + + ACPI_FUNCTION_TRACE (NsSearchParentTree); + + + ParentNode = Node->Parent; + + /* + * If there is no parent (i.e., we are at the root) or type is "local", + * we won't be searching the parent tree. + */ + if (!ParentNode) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] has no parent\n", + ACPI_CAST_PTR (char, &TargetName))); + return_ACPI_STATUS (AE_NOT_FOUND); + } + + if (AcpiNsLocal (Type)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "[%4.4s] type [%s] must be local to this scope (no parent search)\n", + ACPI_CAST_PTR (char, &TargetName), AcpiUtGetTypeName (Type))); + return_ACPI_STATUS (AE_NOT_FOUND); + } + + /* Search the parent tree */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching parent [%4.4s] for [%4.4s]\n", + AcpiUtGetNodeName (ParentNode), ACPI_CAST_PTR (char, &TargetName))); + + /* Search parents until target is found or we have backed up to the root */ + + while (ParentNode) + { + /* + * Search parent scope. Use TYPE_ANY because we don't care about the + * object type at this point, we only care about the existence of + * the actual name we are searching for. Typechecking comes later. + */ + Status = AcpiNsSearchOneScope ( + TargetName, ParentNode, ACPI_TYPE_ANY, ReturnNode); + if (ACPI_SUCCESS (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Not found here, go up another level (until we reach the root) */ + + ParentNode = ParentNode->Parent; + } + + /* Not found in parent tree */ + + return_ACPI_STATUS (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsSearchAndEnter + * + * PARAMETERS: TargetName - Ascii ACPI name to search for (4 chars) + * WalkState - Current state of the walk + * Node - Starting node where search will begin + * InterpreterMode - Add names only in ACPI_MODE_LOAD_PASS_x. + * Otherwise,search only. + * Type - Object type to match + * Flags - Flags describing the search restrictions + * ReturnNode - Where the Node is returned + * + * RETURN: Status + * + * DESCRIPTION: Search for a name segment in a single namespace level, + * optionally adding it if it is not found. If the passed + * Type is not Any and the type previously stored in the + * entry was Any (i.e. unknown), update the stored type. + * + * In ACPI_IMODE_EXECUTE, search only. + * In other modes, search and add if not found. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsSearchAndEnter ( + UINT32 TargetName, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *Node, + ACPI_INTERPRETER_MODE InterpreterMode, + ACPI_OBJECT_TYPE Type, + UINT32 Flags, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *NewNode; + + + ACPI_FUNCTION_TRACE (NsSearchAndEnter); + + + /* Parameter validation */ + + if (!Node || !TargetName || !ReturnNode) + { + ACPI_ERROR ((AE_INFO, + "Null parameter: Node %p Name 0x%X ReturnNode %p", + Node, TargetName, ReturnNode)); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Name must consist of valid ACPI characters. We will repair the name if + * necessary because we don't want to abort because of this, but we want + * all namespace names to be printable. A warning message is appropriate. + * + * This issue came up because there are in fact machines that exhibit + * this problem, and we want to be able to enable ACPI support for them, + * even though there are a few bad names. + */ + AcpiUtRepairName (ACPI_CAST_PTR (char, &TargetName)); + + /* Try to find the name in the namespace level specified by the caller */ + + *ReturnNode = ACPI_ENTRY_NOT_FOUND; + Status = AcpiNsSearchOneScope (TargetName, Node, Type, ReturnNode); + if (Status != AE_NOT_FOUND) + { + /* + * If we found it AND the request specifies that a find is an error, + * return the error + */ + if (Status == AE_OK) + { + /* The node was found in the namespace */ + + /* + * If the namespace override feature is enabled for this node, + * delete any existing attached sub-object and make the node + * look like a new node that is owned by the override table. + */ + if (Flags & ACPI_NS_OVERRIDE_IF_FOUND) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Namespace override: %4.4s pass %u type %X Owner %X\n", + ACPI_CAST_PTR(char, &TargetName), InterpreterMode, + (*ReturnNode)->Type, WalkState->OwnerId)); + + AcpiNsDeleteChildren (*ReturnNode); + if (AcpiGbl_RuntimeNamespaceOverride) + { + AcpiUtRemoveReference ((*ReturnNode)->Object); + (*ReturnNode)->Object = NULL; + (*ReturnNode)->OwnerId = WalkState->OwnerId; + } + else + { + AcpiNsRemoveNode (*ReturnNode); + *ReturnNode = ACPI_ENTRY_NOT_FOUND; + } + } + + /* Return an error if we don't expect to find the object */ + + else if (Flags & ACPI_NS_ERROR_IF_FOUND) + { + Status = AE_ALREADY_EXISTS; + } + } + +#ifdef ACPI_ASL_COMPILER + if (*ReturnNode && (*ReturnNode)->Type == ACPI_TYPE_ANY) + { + (*ReturnNode)->Flags |= ANOBJ_IS_EXTERNAL; + } +#endif + + /* Either found it or there was an error: finished either way */ + + return_ACPI_STATUS (Status); + } + + /* + * The name was not found. If we are NOT performing the first pass + * (name entry) of loading the namespace, search the parent tree (all the + * way to the root if necessary.) We don't want to perform the parent + * search when the namespace is actually being loaded. We want to perform + * the search when namespace references are being resolved (load pass 2) + * and during the execution phase. + */ + if ((InterpreterMode != ACPI_IMODE_LOAD_PASS1) && + (Flags & ACPI_NS_SEARCH_PARENT)) + { + /* + * Not found at this level - search parent tree according to the + * ACPI specification + */ + Status = AcpiNsSearchParentTree (TargetName, Node, Type, ReturnNode); + if (ACPI_SUCCESS (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* In execute mode, just search, never add names. Exit now */ + + if (InterpreterMode == ACPI_IMODE_EXECUTE) + { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%4.4s Not found in %p [Not adding]\n", + ACPI_CAST_PTR (char, &TargetName), Node)); + + return_ACPI_STATUS (AE_NOT_FOUND); + } + + /* Create the new named object */ + + NewNode = AcpiNsCreateNode (TargetName); + if (!NewNode) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + +#ifdef ACPI_ASL_COMPILER + + /* Node is an object defined by an External() statement */ + + if (Flags & ACPI_NS_EXTERNAL || + (WalkState && WalkState->Opcode == AML_SCOPE_OP)) + { + NewNode->Flags |= ANOBJ_IS_EXTERNAL; + } +#endif + + if (Flags & ACPI_NS_TEMPORARY) + { + NewNode->Flags |= ANOBJ_TEMPORARY; + } + + /* Install the new object into the parent's list of children */ + + AcpiNsInstallNode (WalkState, Node, NewNode, Type); + *ReturnNode = NewNode; + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsutils.c b/third_party/lib/acpica/source/components/namespace/nsutils.c new file mode 100644 index 000000000..72f9105ef --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsutils.c @@ -0,0 +1,866 @@ +/****************************************************************************** + * + * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing + * parents and siblings and Scope manipulation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsutils") + +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +ACPI_NAME +AcpiNsFindParentName ( + ACPI_NAMESPACE_NODE *NodeToSearch); +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiNsPrintNodePathname + * + * PARAMETERS: Node - Object + * Message - Prefix message + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +void +AcpiNsPrintNodePathname ( + ACPI_NAMESPACE_NODE *Node, + const char *Message) +{ + ACPI_BUFFER Buffer; + ACPI_STATUS Status; + + + if (!Node) + { + AcpiOsPrintf ("[NULL NAME]"); + return; + } + + /* Convert handle to full pathname and print it (with supplied message) */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + Status = AcpiNsHandleToPathname (Node, &Buffer, TRUE); + if (ACPI_SUCCESS (Status)) + { + if (Message) + { + AcpiOsPrintf ("%s ", Message); + } + + AcpiOsPrintf ("[%s] (Node %p)", (char *) Buffer.Pointer, Node); + ACPI_FREE (Buffer.Pointer); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetType + * + * PARAMETERS: Node - Parent Node to be examined + * + * RETURN: Type field from Node whose handle is passed + * + * DESCRIPTION: Return the type of a Namespace node + * + ******************************************************************************/ + +ACPI_OBJECT_TYPE +AcpiNsGetType ( + ACPI_NAMESPACE_NODE *Node) +{ + ACPI_FUNCTION_TRACE (NsGetType); + + + if (!Node) + { + ACPI_WARNING ((AE_INFO, "Null Node parameter")); + return_UINT8 (ACPI_TYPE_ANY); + } + + return_UINT8 (Node->Type); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsLocal + * + * PARAMETERS: Type - A namespace object type + * + * RETURN: LOCAL if names must be found locally in objects of the + * passed type, 0 if enclosing scopes should be searched + * + * DESCRIPTION: Returns scope rule for the given object type. + * + ******************************************************************************/ + +UINT32 +AcpiNsLocal ( + ACPI_OBJECT_TYPE Type) +{ + ACPI_FUNCTION_TRACE (NsLocal); + + + if (!AcpiUtValidObjectType (Type)) + { + /* Type code out of range */ + + ACPI_WARNING ((AE_INFO, "Invalid Object Type 0x%X", Type)); + return_UINT32 (ACPI_NS_NORMAL); + } + + return_UINT32 (AcpiGbl_NsProperties[Type] & ACPI_NS_LOCAL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetInternalNameLength + * + * PARAMETERS: Info - Info struct initialized with the + * external name pointer. + * + * RETURN: None + * + * DESCRIPTION: Calculate the length of the internal (AML) namestring + * corresponding to the external (ASL) namestring. + * + ******************************************************************************/ + +void +AcpiNsGetInternalNameLength ( + ACPI_NAMESTRING_INFO *Info) +{ + const char *NextExternalChar; + UINT32 i; + + + ACPI_FUNCTION_ENTRY (); + + + NextExternalChar = Info->ExternalName; + Info->NumCarats = 0; + Info->NumSegments = 0; + Info->FullyQualified = FALSE; + + /* + * For the internal name, the required length is 4 bytes per segment, + * plus 1 each for RootPrefix, MultiNamePrefixOp, segment count, + * trailing null (which is not really needed, but no there's harm in + * putting it there) + * + * strlen() + 1 covers the first NameSeg, which has no path separator + */ + if (ACPI_IS_ROOT_PREFIX (*NextExternalChar)) + { + Info->FullyQualified = TRUE; + NextExternalChar++; + + /* Skip redundant RootPrefix, like \\_SB.PCI0.SBRG.EC0 */ + + while (ACPI_IS_ROOT_PREFIX (*NextExternalChar)) + { + NextExternalChar++; + } + } + else + { + /* Handle Carat prefixes */ + + while (ACPI_IS_PARENT_PREFIX (*NextExternalChar)) + { + Info->NumCarats++; + NextExternalChar++; + } + } + + /* + * Determine the number of ACPI name "segments" by counting the number of + * path separators within the string. Start with one segment since the + * segment count is [(# separators) + 1], and zero separators is ok. + */ + if (*NextExternalChar) + { + Info->NumSegments = 1; + for (i = 0; NextExternalChar[i]; i++) + { + if (ACPI_IS_PATH_SEPARATOR (NextExternalChar[i])) + { + Info->NumSegments++; + } + } + } + + Info->Length = (ACPI_NAME_SIZE * Info->NumSegments) + + 4 + Info->NumCarats; + + Info->NextExternalChar = NextExternalChar; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsBuildInternalName + * + * PARAMETERS: Info - Info struct fully initialized + * + * RETURN: Status + * + * DESCRIPTION: Construct the internal (AML) namestring + * corresponding to the external (ASL) namestring. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsBuildInternalName ( + ACPI_NAMESTRING_INFO *Info) +{ + UINT32 NumSegments = Info->NumSegments; + char *InternalName = Info->InternalName; + const char *ExternalName = Info->NextExternalChar; + char *Result = NULL; + UINT32 i; + + + ACPI_FUNCTION_TRACE (NsBuildInternalName); + + + /* Setup the correct prefixes, counts, and pointers */ + + if (Info->FullyQualified) + { + InternalName[0] = AML_ROOT_PREFIX; + + if (NumSegments <= 1) + { + Result = &InternalName[1]; + } + else if (NumSegments == 2) + { + InternalName[1] = AML_DUAL_NAME_PREFIX; + Result = &InternalName[2]; + } + else + { + InternalName[1] = AML_MULTI_NAME_PREFIX_OP; + InternalName[2] = (char) NumSegments; + Result = &InternalName[3]; + } + } + else + { + /* + * Not fully qualified. + * Handle Carats first, then append the name segments + */ + i = 0; + if (Info->NumCarats) + { + for (i = 0; i < Info->NumCarats; i++) + { + InternalName[i] = AML_PARENT_PREFIX; + } + } + + if (NumSegments <= 1) + { + Result = &InternalName[i]; + } + else if (NumSegments == 2) + { + InternalName[i] = AML_DUAL_NAME_PREFIX; + Result = &InternalName[(ACPI_SIZE) i+1]; + } + else + { + InternalName[i] = AML_MULTI_NAME_PREFIX_OP; + InternalName[(ACPI_SIZE) i+1] = (char) NumSegments; + Result = &InternalName[(ACPI_SIZE) i+2]; + } + } + + /* Build the name (minus path separators) */ + + for (; NumSegments; NumSegments--) + { + for (i = 0; i < ACPI_NAME_SIZE; i++) + { + if (ACPI_IS_PATH_SEPARATOR (*ExternalName) || + (*ExternalName == 0)) + { + /* Pad the segment with underscore(s) if segment is short */ + + Result[i] = '_'; + } + else + { + /* Convert the character to uppercase and save it */ + + Result[i] = (char) toupper ((int) *ExternalName); + ExternalName++; + } + } + + /* Now we must have a path separator, or the pathname is bad */ + + if (!ACPI_IS_PATH_SEPARATOR (*ExternalName) && + (*ExternalName != 0)) + { + return_ACPI_STATUS (AE_BAD_PATHNAME); + } + + /* Move on the next segment */ + + ExternalName++; + Result += ACPI_NAME_SIZE; + } + + /* Terminate the string */ + + *Result = 0; + + if (Info->FullyQualified) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (abs) \"\\%s\"\n", + InternalName, InternalName)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n", + InternalName, InternalName)); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsInternalizeName + * + * PARAMETERS: *ExternalName - External representation of name + * **Converted Name - Where to return the resulting + * internal represention of the name + * + * RETURN: Status + * + * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0") + * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) + * + *******************************************************************************/ + +ACPI_STATUS +AcpiNsInternalizeName ( + const char *ExternalName, + char **ConvertedName) +{ + char *InternalName; + ACPI_NAMESTRING_INFO Info; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsInternalizeName); + + + if ((!ExternalName) || + (*ExternalName == 0) || + (!ConvertedName)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the length of the new internal name */ + + Info.ExternalName = ExternalName; + AcpiNsGetInternalNameLength (&Info); + + /* We need a segment to store the internal name */ + + InternalName = ACPI_ALLOCATE_ZEROED (Info.Length); + if (!InternalName) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Build the name */ + + Info.InternalName = InternalName; + Status = AcpiNsBuildInternalName (&Info); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (InternalName); + return_ACPI_STATUS (Status); + } + + *ConvertedName = InternalName; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsExternalizeName + * + * PARAMETERS: InternalNameLength - Lenth of the internal name below + * InternalName - Internal representation of name + * ConvertedNameLength - Where the length is returned + * ConvertedName - Where the resulting external name + * is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) + * to its external (printable) form (e.g. "\_PR_.CPU0") + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsExternalizeName ( + UINT32 InternalNameLength, + const char *InternalName, + UINT32 *ConvertedNameLength, + char **ConvertedName) +{ + UINT32 NamesIndex = 0; + UINT32 NumSegments = 0; + UINT32 RequiredLength; + UINT32 PrefixLength = 0; + UINT32 i = 0; + UINT32 j = 0; + + + ACPI_FUNCTION_TRACE (NsExternalizeName); + + + if (!InternalNameLength || + !InternalName || + !ConvertedName) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Check for a prefix (one '\' | one or more '^') */ + + switch (InternalName[0]) + { + case AML_ROOT_PREFIX: + + PrefixLength = 1; + break; + + case AML_PARENT_PREFIX: + + for (i = 0; i < InternalNameLength; i++) + { + if (ACPI_IS_PARENT_PREFIX (InternalName[i])) + { + PrefixLength = i + 1; + } + else + { + break; + } + } + + if (i == InternalNameLength) + { + PrefixLength = i; + } + + break; + + default: + + break; + } + + /* + * Check for object names. Note that there could be 0-255 of these + * 4-byte elements. + */ + if (PrefixLength < InternalNameLength) + { + switch (InternalName[PrefixLength]) + { + case AML_MULTI_NAME_PREFIX_OP: + + /* 4-byte names */ + + NamesIndex = PrefixLength + 2; + NumSegments = (UINT8) + InternalName[(ACPI_SIZE) PrefixLength + 1]; + break; + + case AML_DUAL_NAME_PREFIX: + + /* Two 4-byte names */ + + NamesIndex = PrefixLength + 1; + NumSegments = 2; + break; + + case 0: + + /* NullName */ + + NamesIndex = 0; + NumSegments = 0; + break; + + default: + + /* one 4-byte name */ + + NamesIndex = PrefixLength; + NumSegments = 1; + break; + } + } + + /* + * Calculate the length of ConvertedName, which equals the length + * of the prefix, length of all object names, length of any required + * punctuation ('.') between object names, plus the NULL terminator. + */ + RequiredLength = PrefixLength + (4 * NumSegments) + + ((NumSegments > 0) ? (NumSegments - 1) : 0) + 1; + + /* + * Check to see if we're still in bounds. If not, there's a problem + * with InternalName (invalid format). + */ + if (RequiredLength > InternalNameLength) + { + ACPI_ERROR ((AE_INFO, "Invalid internal name")); + return_ACPI_STATUS (AE_BAD_PATHNAME); + } + + /* Build the ConvertedName */ + + *ConvertedName = ACPI_ALLOCATE_ZEROED (RequiredLength); + if (!(*ConvertedName)) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + j = 0; + + for (i = 0; i < PrefixLength; i++) + { + (*ConvertedName)[j++] = InternalName[i]; + } + + if (NumSegments > 0) + { + for (i = 0; i < NumSegments; i++) + { + if (i > 0) + { + (*ConvertedName)[j++] = '.'; + } + + /* Copy and validate the 4-char name segment */ + + ACPI_MOVE_NAME (&(*ConvertedName)[j], + &InternalName[NamesIndex]); + AcpiUtRepairName (&(*ConvertedName)[j]); + + j += ACPI_NAME_SIZE; + NamesIndex += ACPI_NAME_SIZE; + } + } + + if (ConvertedNameLength) + { + *ConvertedNameLength = (UINT32) RequiredLength; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsValidateHandle + * + * PARAMETERS: Handle - Handle to be validated and typecast to a + * namespace node. + * + * RETURN: A pointer to a namespace node + * + * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special + * cases for the root node. + * + * NOTE: Real integer handles would allow for more verification + * and keep all pointers within this subsystem - however this introduces + * more overhead and has not been necessary to this point. Drivers + * holding handles are typically notified before a node becomes invalid + * due to a table unload. + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +AcpiNsValidateHandle ( + ACPI_HANDLE Handle) +{ + + ACPI_FUNCTION_ENTRY (); + + + /* Parameter validation */ + + if ((!Handle) || (Handle == ACPI_ROOT_OBJECT)) + { + return (AcpiGbl_RootNode); + } + + /* We can at least attempt to verify the handle */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Handle) != ACPI_DESC_TYPE_NAMED) + { + return (NULL); + } + + return (ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Handle)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsTerminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: free memory allocated for namespace and ACPI table storage. + * + ******************************************************************************/ + +void +AcpiNsTerminate ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (NsTerminate); + + +#ifdef ACPI_EXEC_APP + { + ACPI_OPERAND_OBJECT *Prev; + ACPI_OPERAND_OBJECT *Next; + + /* Delete any module-level code blocks */ + + Next = AcpiGbl_ModuleCodeList; + while (Next) + { + Prev = Next; + Next = Next->Method.Mutex; + Prev->Method.Mutex = NULL; /* Clear the Mutex (cheated) field */ + AcpiUtRemoveReference (Prev); + } + } +#endif + + /* + * Free the entire namespace -- all nodes and all objects + * attached to the nodes + */ + AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode); + + /* Delete any objects attached to the root node */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + AcpiNsDeleteNode (AcpiGbl_RootNode); + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Namespace freed\n")); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsOpensScope + * + * PARAMETERS: Type - A valid namespace type + * + * RETURN: NEWSCOPE if the passed type "opens a name scope" according + * to the ACPI specification, else 0 + * + ******************************************************************************/ + +UINT32 +AcpiNsOpensScope ( + ACPI_OBJECT_TYPE Type) +{ + ACPI_FUNCTION_ENTRY (); + + + if (Type > ACPI_TYPE_LOCAL_MAX) + { + /* type code out of range */ + + ACPI_WARNING ((AE_INFO, "Invalid Object Type 0x%X", Type)); + return (ACPI_NS_NORMAL); + } + + return (((UINT32) AcpiGbl_NsProperties[Type]) & ACPI_NS_NEWSCOPE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetNode + * + * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The + * \ (backslash) and ^ (carat) prefixes, and the + * . (period) to separate segments are supported. + * PrefixNode - Root of subtree to be searched, or NS_ALL for the + * root of the name space. If Name is fully + * qualified (first INT8 is '\'), the passed value + * of Scope will not be accessed. + * Flags - Used to indicate whether to perform upsearch or + * not. + * ReturnNode - Where the Node is returned + * + * DESCRIPTION: Look up a name relative to a given scope and return the + * corresponding Node. NOTE: Scope can be null. + * + * MUTEX: Locks namespace + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsGetNode ( + ACPI_NAMESPACE_NODE *PrefixNode, + const char *Pathname, + UINT32 Flags, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + ACPI_GENERIC_STATE ScopeInfo; + ACPI_STATUS Status; + char *InternalPath; + + + ACPI_FUNCTION_TRACE_PTR (NsGetNode, ACPI_CAST_PTR (char, Pathname)); + + + /* Simplest case is a null pathname */ + + if (!Pathname) + { + *ReturnNode = PrefixNode; + if (!PrefixNode) + { + *ReturnNode = AcpiGbl_RootNode; + } + + return_ACPI_STATUS (AE_OK); + } + + /* Quick check for a reference to the root */ + + if (ACPI_IS_ROOT_PREFIX (Pathname[0]) && (!Pathname[1])) + { + *ReturnNode = AcpiGbl_RootNode; + return_ACPI_STATUS (AE_OK); + } + + /* Convert path to internal representation */ + + Status = AcpiNsInternalizeName (Pathname, &InternalPath); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Must lock namespace during lookup */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Setup lookup scope (search starting point) */ + + ScopeInfo.Scope.Node = PrefixNode; + + /* Lookup the name in the namespace */ + + Status = AcpiNsLookup (&ScopeInfo, InternalPath, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, (Flags | ACPI_NS_DONT_OPEN_SCOPE), + NULL, ReturnNode); + if (ACPI_FAILURE (Status)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s, %s\n", + Pathname, AcpiFormatException (Status))); + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + +Cleanup: + ACPI_FREE (InternalPath); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/namespace/nswalk.c b/third_party/lib/acpica/source/components/namespace/nswalk.c new file mode 100644 index 000000000..08637a6ee --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nswalk.c @@ -0,0 +1,381 @@ +/****************************************************************************** + * + * Module Name: nswalk - Functions for walking the ACPI namespace + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nswalk") + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetNextNode + * + * PARAMETERS: ParentNode - Parent node whose children we are + * getting + * ChildNode - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +AcpiNsGetNextNode ( + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_NAMESPACE_NODE *ChildNode) +{ + ACPI_FUNCTION_ENTRY (); + + + if (!ChildNode) + { + /* It's really the parent's _scope_ that we want */ + + return (ParentNode->Child); + } + + /* Otherwise just return the next peer */ + + return (ChildNode->Peer); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetNextNodeTyped + * + * PARAMETERS: Type - Type of node to be searched for + * ParentNode - Parent node whose children we are + * getting + * ChildNode - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +AcpiNsGetNextNodeTyped ( + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_NAMESPACE_NODE *ChildNode) +{ + ACPI_NAMESPACE_NODE *NextNode = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + NextNode = AcpiNsGetNextNode (ParentNode, ChildNode); + + /* If any type is OK, we are done */ + + if (Type == ACPI_TYPE_ANY) + { + /* NextNode is NULL if we are at the end-of-list */ + + return (NextNode); + } + + /* Must search for the node -- but within this scope only */ + + while (NextNode) + { + /* If type matches, we are done */ + + if (NextNode->Type == Type) + { + return (NextNode); + } + + /* Otherwise, move on to the next peer node */ + + NextNode = NextNode->Peer; + } + + /* Not found */ + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiNsWalkNamespace + * + * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for + * StartNode - Handle in namespace where search begins + * MaxDepth - Depth to which search is to reach + * Flags - Whether to unlock the NS before invoking + * the callback routine + * DescendingCallback - Called during tree descent + * when an object of "Type" is found + * AscendingCallback - Called during tree ascent + * when an object of "Type" is found + * Context - Passed to user function(s) above + * ReturnValue - from the UserFunction if terminated + * early. Otherwise, returns NULL. + * RETURNS: Status + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the node specified by StartHandle. + * The callback function is called whenever a node that matches + * the type parameter is found. If the callback function returns + * a non-zero value, the search is terminated immediately and + * this value is returned to the caller. + * + * The point of this procedure is to provide a generic namespace + * walk routine that can be called from multiple places to + * provide multiple services; the callback function(s) can be + * tailored to each task, whether it is a print function, + * a compare function, etc. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiNsWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartNode, + UINT32 MaxDepth, + UINT32 Flags, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue) +{ + ACPI_STATUS Status; + ACPI_STATUS MutexStatus; + ACPI_NAMESPACE_NODE *ChildNode; + ACPI_NAMESPACE_NODE *ParentNode; + ACPI_OBJECT_TYPE ChildType; + UINT32 Level; + BOOLEAN NodePreviouslyVisited = FALSE; + + + ACPI_FUNCTION_TRACE (NsWalkNamespace); + + + /* Special case for the namespace Root Node */ + + if (StartNode == ACPI_ROOT_OBJECT) + { + StartNode = AcpiGbl_RootNode; + } + + /* Null child means "get first node" */ + + ParentNode = StartNode; + ChildNode = AcpiNsGetNextNode (ParentNode, NULL); + ChildType = ACPI_TYPE_ANY; + Level = 1; + + /* + * Traverse the tree of nodes until we bubble back up to where we + * started. When Level is zero, the loop is done because we have + * bubbled up to (and passed) the original parent handle (StartEntry) + */ + while (Level > 0 && ChildNode) + { + Status = AE_OK; + + /* Found next child, get the type if we are not searching for ANY */ + + if (Type != ACPI_TYPE_ANY) + { + ChildType = ChildNode->Type; + } + + /* + * Ignore all temporary namespace nodes (created during control + * method execution) unless told otherwise. These temporary nodes + * can cause a race condition because they can be deleted during + * the execution of the user function (if the namespace is + * unlocked before invocation of the user function.) Only the + * debugger namespace dump will examine the temporary nodes. + */ + if ((ChildNode->Flags & ANOBJ_TEMPORARY) && + !(Flags & ACPI_NS_WALK_TEMP_NODES)) + { + Status = AE_CTRL_DEPTH; + } + + /* Type must match requested type */ + + else if (ChildType == Type) + { + /* + * Found a matching node, invoke the user callback function. + * Unlock the namespace if flag is set. + */ + if (Flags & ACPI_NS_WALK_UNLOCK) + { + MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (MutexStatus)) + { + return_ACPI_STATUS (MutexStatus); + } + } + + /* + * Invoke the user function, either descending, ascending, + * or both. + */ + if (!NodePreviouslyVisited) + { + if (DescendingCallback) + { + Status = DescendingCallback (ChildNode, Level, + Context, ReturnValue); + } + } + else + { + if (AscendingCallback) + { + Status = AscendingCallback (ChildNode, Level, + Context, ReturnValue); + } + } + + if (Flags & ACPI_NS_WALK_UNLOCK) + { + MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (MutexStatus)) + { + return_ACPI_STATUS (MutexStatus); + } + } + + switch (Status) + { + case AE_OK: + case AE_CTRL_DEPTH: + + /* Just keep going */ + break; + + case AE_CTRL_TERMINATE: + + /* Exit now, with OK status */ + + return_ACPI_STATUS (AE_OK); + + default: + + /* All others are valid exceptions */ + + return_ACPI_STATUS (Status); + } + } + + /* + * Depth first search: Attempt to go down another level in the + * namespace if we are allowed to. Don't go any further if we have + * reached the caller specified maximum depth or if the user + * function has specified that the maximum depth has been reached. + */ + if (!NodePreviouslyVisited && + (Level < MaxDepth) && + (Status != AE_CTRL_DEPTH)) + { + if (ChildNode->Child) + { + /* There is at least one child of this node, visit it */ + + Level++; + ParentNode = ChildNode; + ChildNode = AcpiNsGetNextNode (ParentNode, NULL); + continue; + } + } + + /* No more children, re-visit this node */ + + if (!NodePreviouslyVisited) + { + NodePreviouslyVisited = TRUE; + continue; + } + + /* No more children, visit peers */ + + ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); + if (ChildNode) + { + NodePreviouslyVisited = FALSE; + } + + /* No peers, re-visit parent */ + + else + { + /* + * No more children of this node (AcpiNsGetNextNode failed), go + * back upwards in the namespace tree to the node's parent. + */ + Level--; + ChildNode = ParentNode; + ParentNode = ParentNode->Parent; + + NodePreviouslyVisited = TRUE; + } + } + + /* Complete walk, not terminated by user function */ + + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/namespace/nsxfeval.c b/third_party/lib/acpica/source/components/namespace/nsxfeval.c new file mode 100644 index 000000000..91f8b72b5 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsxfeval.c @@ -0,0 +1,1074 @@ +/******************************************************************************* + * + * Module Name: nsxfeval - Public interfaces to the ACPI subsystem + * ACPI Object evaluation interfaces + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfeval") + +/* Local prototypes */ + +static void +AcpiNsResolveReferences ( + ACPI_EVALUATE_INFO *Info); + + +/******************************************************************************* + * + * FUNCTION: AcpiEvaluateObjectTyped + * + * PARAMETERS: Handle - Object handle (optional) + * Pathname - Object pathname (optional) + * ExternalParams - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * ReturnBuffer - Where to put method's return value (if + * any). If NULL, no value is returned. + * ReturnType - Expected type of return object + * + * RETURN: Status + * + * DESCRIPTION: Find and evaluate the given object, passing the given + * parameters if necessary. One of "Handle" or "Pathname" must + * be valid (non-null) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvaluateObjectTyped ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ExternalParams, + ACPI_BUFFER *ReturnBuffer, + ACPI_OBJECT_TYPE ReturnType) +{ + ACPI_STATUS Status; + BOOLEAN FreeBufferOnError = FALSE; + + + ACPI_FUNCTION_TRACE (AcpiEvaluateObjectTyped); + + + /* Return buffer must be valid */ + + if (!ReturnBuffer) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (ReturnBuffer->Length == ACPI_ALLOCATE_BUFFER) + { + FreeBufferOnError = TRUE; + } + + /* Evaluate the object */ + + Status = AcpiEvaluateObject (Handle, Pathname, + ExternalParams, ReturnBuffer); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Type ANY means "don't care" */ + + if (ReturnType == ACPI_TYPE_ANY) + { + return_ACPI_STATUS (AE_OK); + } + + if (ReturnBuffer->Length == 0) + { + /* Error because caller specifically asked for a return value */ + + ACPI_ERROR ((AE_INFO, "No return value")); + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Examine the object type returned from EvaluateObject */ + + if (((ACPI_OBJECT *) ReturnBuffer->Pointer)->Type == ReturnType) + { + return_ACPI_STATUS (AE_OK); + } + + /* Return object type does not match requested type */ + + ACPI_ERROR ((AE_INFO, + "Incorrect return type [%s] requested [%s]", + AcpiUtGetTypeName (((ACPI_OBJECT *) ReturnBuffer->Pointer)->Type), + AcpiUtGetTypeName (ReturnType))); + + if (FreeBufferOnError) + { + /* + * Free a buffer created via ACPI_ALLOCATE_BUFFER. + * Note: We use AcpiOsFree here because AcpiOsAllocate was used + * to allocate the buffer. This purposefully bypasses the + * (optionally enabled) allocation tracking mechanism since we + * only want to track internal allocations. + */ + AcpiOsFree (ReturnBuffer->Pointer); + ReturnBuffer->Pointer = NULL; + } + + ReturnBuffer->Length = 0; + return_ACPI_STATUS (AE_TYPE); +} + +ACPI_EXPORT_SYMBOL (AcpiEvaluateObjectTyped) + + +/******************************************************************************* + * + * FUNCTION: AcpiEvaluateObject + * + * PARAMETERS: Handle - Object handle (optional) + * Pathname - Object pathname (optional) + * ExternalParams - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * ReturnBuffer - Where to put method's return value (if + * any). If NULL, no value is returned. + * + * RETURN: Status + * + * DESCRIPTION: Find and evaluate the given object, passing the given + * parameters if necessary. One of "Handle" or "Pathname" must + * be valid (non-null) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvaluateObject ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ExternalParams, + ACPI_BUFFER *ReturnBuffer) +{ + ACPI_STATUS Status; + ACPI_EVALUATE_INFO *Info; + ACPI_SIZE BufferSpaceNeeded; + UINT32 i; + + + ACPI_FUNCTION_TRACE (AcpiEvaluateObject); + + + /* Allocate and initialize the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Convert and validate the device handle */ + + Info->PrefixNode = AcpiNsValidateHandle (Handle); + if (!Info->PrefixNode) + { + Status = AE_BAD_PARAMETER; + goto Cleanup; + } + + /* + * Get the actual namespace node for the target object. + * Handles these cases: + * + * 1) Null node, valid pathname from root (absolute path) + * 2) Node and valid pathname (path relative to Node) + * 3) Node, Null pathname + */ + if ((Pathname) && + (ACPI_IS_ROOT_PREFIX (Pathname[0]))) + { + /* The path is fully qualified, just evaluate by name */ + + Info->PrefixNode = NULL; + } + else if (!Handle) + { + /* + * A handle is optional iff a fully qualified pathname is specified. + * Since we've already handled fully qualified names above, this is + * an error. + */ + if (!Pathname) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Both Handle and Pathname are NULL")); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Null Handle with relative pathname [%s]", Pathname)); + } + + Status = AE_BAD_PARAMETER; + goto Cleanup; + } + + Info->RelativePathname = Pathname; + + /* + * Convert all external objects passed as arguments to the + * internal version(s). + */ + if (ExternalParams && ExternalParams->Count) + { + Info->ParamCount = (UINT16) ExternalParams->Count; + + /* Warn on impossible argument count */ + + if (Info->ParamCount > ACPI_METHOD_NUM_ARGS) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, + "Excess arguments (%u) - using only %u", + Info->ParamCount, ACPI_METHOD_NUM_ARGS)); + + Info->ParamCount = ACPI_METHOD_NUM_ARGS; + } + + /* + * Allocate a new parameter block for the internal objects + * Add 1 to count to allow for null terminated internal list + */ + Info->Parameters = ACPI_ALLOCATE_ZEROED ( + ((ACPI_SIZE) Info->ParamCount + 1) * sizeof (void *)); + if (!Info->Parameters) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Convert each external object in the list to an internal object */ + + for (i = 0; i < Info->ParamCount; i++) + { + Status = AcpiUtCopyEobjectToIobject ( + &ExternalParams->Pointer[i], &Info->Parameters[i]); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + } + + Info->Parameters[Info->ParamCount] = NULL; + } + + +#if 0 + + /* + * Begin incoming argument count analysis. Check for too few args + * and too many args. + */ + + switch (AcpiNsGetType (Info->Node)) + { + case ACPI_TYPE_METHOD: + + /* Check incoming argument count against the method definition */ + + if (Info->ObjDesc->Method.ParamCount > Info->ParamCount) + { + ACPI_ERROR ((AE_INFO, + "Insufficient arguments (%u) - %u are required", + Info->ParamCount, + Info->ObjDesc->Method.ParamCount)); + + Status = AE_MISSING_ARGUMENTS; + goto Cleanup; + } + + else if (Info->ObjDesc->Method.ParamCount < Info->ParamCount) + { + ACPI_WARNING ((AE_INFO, + "Excess arguments (%u) - only %u are required", + Info->ParamCount, + Info->ObjDesc->Method.ParamCount)); + + /* Just pass the required number of arguments */ + + Info->ParamCount = Info->ObjDesc->Method.ParamCount; + } + + /* + * Any incoming external objects to be passed as arguments to the + * method must be converted to internal objects + */ + if (Info->ParamCount) + { + /* + * Allocate a new parameter block for the internal objects + * Add 1 to count to allow for null terminated internal list + */ + Info->Parameters = ACPI_ALLOCATE_ZEROED ( + ((ACPI_SIZE) Info->ParamCount + 1) * sizeof (void *)); + if (!Info->Parameters) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Convert each external object in the list to an internal object */ + + for (i = 0; i < Info->ParamCount; i++) + { + Status = AcpiUtCopyEobjectToIobject ( + &ExternalParams->Pointer[i], &Info->Parameters[i]); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + } + + Info->Parameters[Info->ParamCount] = NULL; + } + break; + + default: + + /* Warn if arguments passed to an object that is not a method */ + + if (Info->ParamCount) + { + ACPI_WARNING ((AE_INFO, + "%u arguments were passed to a non-method ACPI object", + Info->ParamCount)); + } + break; + } + +#endif + + + /* Now we can evaluate the object */ + + Status = AcpiNsEvaluate (Info); + + /* + * If we are expecting a return value, and all went well above, + * copy the return value to an external object. + */ + if (ReturnBuffer) + { + if (!Info->ReturnObject) + { + ReturnBuffer->Length = 0; + } + else + { + if (ACPI_GET_DESCRIPTOR_TYPE (Info->ReturnObject) == + ACPI_DESC_TYPE_NAMED) + { + /* + * If we received a NS Node as a return object, this means that + * the object we are evaluating has nothing interesting to + * return (such as a mutex, etc.) We return an error because + * these types are essentially unsupported by this interface. + * We don't check up front because this makes it easier to add + * support for various types at a later date if necessary. + */ + Status = AE_TYPE; + Info->ReturnObject = NULL; /* No need to delete a NS Node */ + ReturnBuffer->Length = 0; + } + + if (ACPI_SUCCESS (Status)) + { + /* Dereference Index and RefOf references */ + + AcpiNsResolveReferences (Info); + + /* Get the size of the returned object */ + + Status = AcpiUtGetObjectSize (Info->ReturnObject, + &BufferSpaceNeeded); + if (ACPI_SUCCESS (Status)) + { + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (ReturnBuffer, + BufferSpaceNeeded); + if (ACPI_FAILURE (Status)) + { + /* + * Caller's buffer is too small or a new one can't + * be allocated + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Needed buffer size %X, %s\n", + (UINT32) BufferSpaceNeeded, + AcpiFormatException (Status))); + } + else + { + /* We have enough space for the object, build it */ + + Status = AcpiUtCopyIobjectToEobject ( + Info->ReturnObject, ReturnBuffer); + } + } + } + } + } + + if (Info->ReturnObject) + { + /* + * Delete the internal return object. NOTE: Interpreter must be + * locked to avoid race condition. + */ + AcpiExEnterInterpreter (); + + /* Remove one reference on the return object (should delete it) */ + + AcpiUtRemoveReference (Info->ReturnObject); + AcpiExExitInterpreter (); + } + + +Cleanup: + + /* Free the input parameter list (if we created one) */ + + if (Info->Parameters) + { + /* Free the allocated parameter block */ + + AcpiUtDeleteInternalObjectList (Info->Parameters); + } + + ACPI_FREE (Info); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEvaluateObject) + + +/******************************************************************************* + * + * FUNCTION: AcpiNsResolveReferences + * + * PARAMETERS: Info - Evaluation info block + * + * RETURN: Info->ReturnObject is replaced with the dereferenced object + * + * DESCRIPTION: Dereference certain reference objects. Called before an + * internal return object is converted to an external ACPI_OBJECT. + * + * Performs an automatic dereference of Index and RefOf reference objects. + * These reference objects are not supported by the ACPI_OBJECT, so this is a + * last resort effort to return something useful. Also, provides compatibility + * with other ACPI implementations. + * + * NOTE: does not handle references within returned package objects or nested + * references, but this support could be added later if found to be necessary. + * + ******************************************************************************/ + +static void +AcpiNsResolveReferences ( + ACPI_EVALUATE_INFO *Info) +{ + ACPI_OPERAND_OBJECT *ObjDesc = NULL; + ACPI_NAMESPACE_NODE *Node; + + + /* We are interested in reference objects only */ + + if ((Info->ReturnObject)->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) + { + return; + } + + /* + * Two types of references are supported - those created by Index and + * RefOf operators. A name reference (AML_NAMEPATH_OP) can be converted + * to an ACPI_OBJECT, so it is not dereferenced here. A DdbHandle + * (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to + * an ACPI_OBJECT. + */ + switch (Info->ReturnObject->Reference.Class) + { + case ACPI_REFCLASS_INDEX: + + ObjDesc = *(Info->ReturnObject->Reference.Where); + break; + + case ACPI_REFCLASS_REFOF: + + Node = Info->ReturnObject->Reference.Object; + if (Node) + { + ObjDesc = Node->Object; + } + break; + + default: + + return; + } + + /* Replace the existing reference object */ + + if (ObjDesc) + { + AcpiUtAddReference (ObjDesc); + AcpiUtRemoveReference (Info->ReturnObject); + Info->ReturnObject = ObjDesc; + } + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiWalkNamespace + * + * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for + * StartObject - Handle in namespace where search begins + * MaxDepth - Depth to which search is to reach + * DescendingCallback - Called during tree descent + * when an object of "Type" is found + * AscendingCallback - Called during tree ascent + * when an object of "Type" is found + * Context - Passed to user function(s) above + * ReturnValue - Location where return value of + * UserFunction is put if terminated early + * + * RETURNS Return value from the UserFunction if terminated early. + * Otherwise, returns NULL. + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the object specified by StartHandle. + * The callback function is called whenever an object that matches + * the type parameter is found. If the callback function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * The point of this procedure is to provide a generic namespace + * walk routine that can be called from multiple places to + * provide multiple services; the callback function(s) can be + * tailored to each task, whether it is a print function, + * a compare function, etc. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiWalkNamespace); + + + /* Parameter validation */ + + if ((Type > ACPI_TYPE_LOCAL_MAX) || + (!MaxDepth) || + (!DescendingCallback && !AscendingCallback)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Need to acquire the namespace reader lock to prevent interference + * with any concurrent table unloads (which causes the deletion of + * namespace objects). We cannot allow the deletion of a namespace node + * while the user function is using it. The exception to this are the + * nodes created and deleted during control method execution -- these + * nodes are marked as temporary nodes and are ignored by the namespace + * walk. Thus, control methods can be executed while holding the + * namespace deletion lock (and the user function can execute control + * methods.) + */ + Status = AcpiUtAcquireReadLock (&AcpiGbl_NamespaceRwLock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Lock the namespace around the walk. The namespace will be + * unlocked/locked around each call to the user function - since the user + * function must be allowed to make ACPICA calls itself (for example, it + * will typically execute control methods during device enumeration.) + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Now we can validate the starting node */ + + if (!AcpiNsValidateHandle (StartObject)) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit2; + } + + Status = AcpiNsWalkNamespace (Type, StartObject, MaxDepth, + ACPI_NS_WALK_UNLOCK, DescendingCallback, + AscendingCallback, Context, ReturnValue); + +UnlockAndExit2: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + +UnlockAndExit: + (void) AcpiUtReleaseReadLock (&AcpiGbl_NamespaceRwLock); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWalkNamespace) + + +/******************************************************************************* + * + * FUNCTION: AcpiNsGetDeviceCallback + * + * PARAMETERS: Callback from AcpiGetDevice + * + * RETURN: Status + * + * DESCRIPTION: Takes callbacks from WalkNamespace and filters out all non- + * present devices, or if they specified a HID, it filters based + * on that. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiNsGetDeviceCallback ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + ACPI_GET_DEVICES_INFO *Info = Context; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + UINT32 Flags; + ACPI_PNP_DEVICE_ID *Hid; + ACPI_PNP_DEVICE_ID_LIST *Cid; + UINT32 i; + BOOLEAN Found; + int NoMatch; + + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Node = AcpiNsValidateHandle (ObjHandle); + Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Node) + { + return (AE_BAD_PARAMETER); + } + + /* + * First, filter based on the device HID and CID. + * + * 01/2010: For this case where a specific HID is requested, we don't + * want to run _STA until we have an actual HID match. Thus, we will + * not unnecessarily execute _STA on devices for which the caller + * doesn't care about. Previously, _STA was executed unconditionally + * on all devices found here. + * + * A side-effect of this change is that now we will continue to search + * for a matching HID even under device trees where the parent device + * would have returned a _STA that indicates it is not present or + * not functioning (thus aborting the search on that branch). + */ + if (Info->Hid != NULL) + { + Status = AcpiUtExecute_HID (Node, &Hid); + if (Status == AE_NOT_FOUND) + { + return (AE_OK); + } + else if (ACPI_FAILURE (Status)) + { + return (AE_CTRL_DEPTH); + } + + NoMatch = strcmp (Hid->String, Info->Hid); + ACPI_FREE (Hid); + + if (NoMatch) + { + /* + * HID does not match, attempt match within the + * list of Compatible IDs (CIDs) + */ + Status = AcpiUtExecute_CID (Node, &Cid); + if (Status == AE_NOT_FOUND) + { + return (AE_OK); + } + else if (ACPI_FAILURE (Status)) + { + return (AE_CTRL_DEPTH); + } + + /* Walk the CID list */ + + Found = FALSE; + for (i = 0; i < Cid->Count; i++) + { + if (strcmp (Cid->Ids[i].String, Info->Hid) == 0) + { + /* Found a matching CID */ + + Found = TRUE; + break; + } + } + + ACPI_FREE (Cid); + if (!Found) + { + return (AE_OK); + } + } + } + + /* Run _STA to determine if device is present */ + + Status = AcpiUtExecute_STA (Node, &Flags); + if (ACPI_FAILURE (Status)) + { + return (AE_CTRL_DEPTH); + } + + if (!(Flags & ACPI_STA_DEVICE_PRESENT) && + !(Flags & ACPI_STA_DEVICE_FUNCTIONING)) + { + /* + * Don't examine the children of the device only when the + * device is neither present nor functional. See ACPI spec, + * description of _STA for more information. + */ + return (AE_CTRL_DEPTH); + } + + /* We have a valid device, invoke the user function */ + + Status = Info->UserFunction (ObjHandle, NestingLevel, + Info->Context, ReturnValue); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiGetDevices + * + * PARAMETERS: HID - HID to search for. Can be NULL. + * UserFunction - Called when a matching object is found + * Context - Passed to user function + * ReturnValue - Location where return value of + * UserFunction is put if terminated early + * + * RETURNS Return value from the UserFunction if terminated early. + * Otherwise, returns NULL. + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the object specified by StartHandle. + * The UserFunction is called whenever an object of type + * Device is found. If the user function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * This is a wrapper for WalkNamespace, but the callback performs + * additional filtering. Please see AcpiNsGetDeviceCallback. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetDevices ( + char *HID, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue) +{ + ACPI_STATUS Status; + ACPI_GET_DEVICES_INFO Info; + + + ACPI_FUNCTION_TRACE (AcpiGetDevices); + + + /* Parameter validation */ + + if (!UserFunction) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * We're going to call their callback from OUR callback, so we need + * to know what it is, and their context parameter. + */ + Info.Hid = HID; + Info.Context = Context; + Info.UserFunction = UserFunction; + + /* + * Lock the namespace around the walk. + * The namespace will be unlocked/locked around each call + * to the user function - since this function + * must be allowed to make Acpi calls itself. + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiNsWalkNamespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, + AcpiNsGetDeviceCallback, NULL, &Info, ReturnValue); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetDevices) + + +/******************************************************************************* + * + * FUNCTION: AcpiAttachData + * + * PARAMETERS: ObjHandle - Namespace node + * Handler - Handler for this attachment + * Data - Pointer to data to be attached + * + * RETURN: Status + * + * DESCRIPTION: Attach arbitrary data and handler to a namespace node. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiAttachData ( + ACPI_HANDLE ObjHandle, + ACPI_OBJECT_HANDLER Handler, + void *Data) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!ObjHandle || + !Handler || + !Data) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Convert and validate the handle */ + + Node = AcpiNsValidateHandle (ObjHandle); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + Status = AcpiNsAttachData (Node, Handler, Data); + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiAttachData) + + +/******************************************************************************* + * + * FUNCTION: AcpiDetachData + * + * PARAMETERS: ObjHandle - Namespace node handle + * Handler - Handler used in call to AcpiAttachData + * + * RETURN: Status + * + * DESCRIPTION: Remove data that was previously attached to a node. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDetachData ( + ACPI_HANDLE ObjHandle, + ACPI_OBJECT_HANDLER Handler) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!ObjHandle || + !Handler) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Convert and validate the handle */ + + Node = AcpiNsValidateHandle (ObjHandle); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + Status = AcpiNsDetachData (Node, Handler); + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiDetachData) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetData + * + * PARAMETERS: ObjHandle - Namespace node + * Handler - Handler used in call to AttachData + * Data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetData ( + ACPI_HANDLE ObjHandle, + ACPI_OBJECT_HANDLER Handler, + void **Data) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!ObjHandle || + !Handler || + !Data) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Convert and validate the handle */ + + Node = AcpiNsValidateHandle (ObjHandle); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + Status = AcpiNsGetAttachedData (Node, Handler, Data); + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetData) diff --git a/third_party/lib/acpica/source/components/namespace/nsxfname.c b/third_party/lib/acpica/source/components/namespace/nsxfname.c new file mode 100644 index 000000000..cfd6937f4 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsxfname.c @@ -0,0 +1,738 @@ +/****************************************************************************** + * + * Module Name: nsxfname - Public interfaces to the ACPI subsystem + * ACPI Namespace oriented interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acparser.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfname") + +/* Local prototypes */ + +static char * +AcpiNsCopyDeviceId ( + ACPI_PNP_DEVICE_ID *Dest, + ACPI_PNP_DEVICE_ID *Source, + char *StringArea); + + +/****************************************************************************** + * + * FUNCTION: AcpiGetHandle + * + * PARAMETERS: Parent - Object to search under (search scope). + * Pathname - Pointer to an asciiz string containing the + * name + * RetHandle - Where the return handle is returned + * + * RETURN: Status + * + * DESCRIPTION: This routine will search for a caller specified name in the + * name space. The caller can restrict the search region by + * specifying a non NULL parent. The parent value is itself a + * namespace handle. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetHandle ( + ACPI_HANDLE Parent, + ACPI_STRING Pathname, + ACPI_HANDLE *RetHandle) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node = NULL; + ACPI_NAMESPACE_NODE *PrefixNode = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + /* Parameter Validation */ + + if (!RetHandle || !Pathname) + { + return (AE_BAD_PARAMETER); + } + + /* Convert a parent handle to a prefix node */ + + if (Parent) + { + PrefixNode = AcpiNsValidateHandle (Parent); + if (!PrefixNode) + { + return (AE_BAD_PARAMETER); + } + } + + /* + * Valid cases are: + * 1) Fully qualified pathname + * 2) Parent + Relative pathname + * + * Error for + */ + if (ACPI_IS_ROOT_PREFIX (Pathname[0])) + { + /* Pathname is fully qualified (starts with '\') */ + + /* Special case for root-only, since we can't search for it */ + + if (!strcmp (Pathname, ACPI_NS_ROOT_PATH)) + { + *RetHandle = ACPI_CAST_PTR (ACPI_HANDLE, AcpiGbl_RootNode); + return (AE_OK); + } + } + else if (!PrefixNode) + { + /* Relative path with null prefix is disallowed */ + + return (AE_BAD_PARAMETER); + } + + /* Find the Node and convert to a handle */ + + Status = AcpiNsGetNode (PrefixNode, Pathname, ACPI_NS_NO_UPSEARCH, &Node); + if (ACPI_SUCCESS (Status)) + { + *RetHandle = ACPI_CAST_PTR (ACPI_HANDLE, Node); + } + + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetHandle) + + +/****************************************************************************** + * + * FUNCTION: AcpiGetName + * + * PARAMETERS: Handle - Handle to be converted to a pathname + * NameType - Full pathname or single segment + * Buffer - Buffer for returned path + * + * RETURN: Pointer to a string containing the fully qualified Name. + * + * DESCRIPTION: This routine returns the fully qualified name associated with + * the Handle parameter. This and the AcpiPathnameToHandle are + * complementary functions. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetName ( + ACPI_HANDLE Handle, + UINT32 NameType, + ACPI_BUFFER *Buffer) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + const char *NodeName; + + + /* Parameter validation */ + + if (NameType > ACPI_NAME_TYPE_MAX) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtValidateBuffer (Buffer); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (NameType == ACPI_FULL_PATHNAME || + NameType == ACPI_FULL_PATHNAME_NO_TRAILING) + { + /* Get the full pathname (From the namespace root) */ + + Status = AcpiNsHandleToPathname (Handle, Buffer, + NameType == ACPI_FULL_PATHNAME ? FALSE : TRUE); + return (Status); + } + + /* + * Wants the single segment ACPI name. + * Validate handle and convert to a namespace Node + */ + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Node = AcpiNsValidateHandle (Handle); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (Buffer, ACPI_PATH_SEGMENT_LENGTH); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Just copy the ACPI name from the Node and zero terminate it */ + + NodeName = AcpiUtGetNodeName (Node); + ACPI_MOVE_NAME (Buffer->Pointer, NodeName); + ((char *) Buffer->Pointer) [ACPI_NAME_SIZE] = 0; + Status = AE_OK; + + +UnlockAndExit: + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetName) + + +/****************************************************************************** + * + * FUNCTION: AcpiNsCopyDeviceId + * + * PARAMETERS: Dest - Pointer to the destination PNP_DEVICE_ID + * Source - Pointer to the source PNP_DEVICE_ID + * StringArea - Pointer to where to copy the dest string + * + * RETURN: Pointer to the next string area + * + * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. + * + ******************************************************************************/ + +static char * +AcpiNsCopyDeviceId ( + ACPI_PNP_DEVICE_ID *Dest, + ACPI_PNP_DEVICE_ID *Source, + char *StringArea) +{ + /* Create the destination PNP_DEVICE_ID */ + + Dest->String = StringArea; + Dest->Length = Source->Length; + + /* Copy actual string and return a pointer to the next string area */ + + memcpy (StringArea, Source->String, Source->Length); + return (StringArea + Source->Length); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiGetObjectInfo + * + * PARAMETERS: Handle - Object Handle + * ReturnBuffer - Where the info is returned + * + * RETURN: Status + * + * DESCRIPTION: Returns information about an object as gleaned from the + * namespace node and possibly by running several standard + * control methods (Such as in the case of a device.) + * + * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA, + * _CLS, _ADR, _SxW, and _SxD methods. + * + * Note: Allocates the return buffer, must be freed by the caller. + * + * Note: This interface is intended to be used during the initial device + * discovery namespace traversal. Therefore, no complex methods can be + * executed, especially those that access operation regions. Therefore, do + * not add any additional methods that could cause problems in this area. + * this was the fate of the _SUB method which was found to cause such + * problems and was removed (11/2015). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetObjectInfo ( + ACPI_HANDLE Handle, + ACPI_DEVICE_INFO **ReturnBuffer) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_DEVICE_INFO *Info; + ACPI_PNP_DEVICE_ID_LIST *CidList = NULL; + ACPI_PNP_DEVICE_ID *Hid = NULL; + ACPI_PNP_DEVICE_ID *Uid = NULL; + ACPI_PNP_DEVICE_ID *Cls = NULL; + char *NextIdString; + ACPI_OBJECT_TYPE Type; + ACPI_NAME Name; + UINT8 ParamCount= 0; + UINT16 Valid = 0; + UINT32 InfoSize; + UINT32 i; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!Handle || !ReturnBuffer) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Node = AcpiNsValidateHandle (Handle); + if (!Node) + { + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (AE_BAD_PARAMETER); + } + + /* Get the namespace node data while the namespace is locked */ + + InfoSize = sizeof (ACPI_DEVICE_INFO); + Type = Node->Type; + Name = Node->Name.Integer; + + if (Node->Type == ACPI_TYPE_METHOD) + { + ParamCount = Node->Object->Method.ParamCount; + } + + Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if ((Type == ACPI_TYPE_DEVICE) || + (Type == ACPI_TYPE_PROCESSOR)) + { + /* + * Get extra info for ACPI Device/Processor objects only: + * Run the Device _HID, _UID, _CLS, and _CID methods. + * + * Note: none of these methods are required, so they may or may + * not be present for this device. The Info->Valid bitfield is used + * to indicate which methods were found and run successfully. + */ + + /* Execute the Device._HID method */ + + Status = AcpiUtExecute_HID (Node, &Hid); + if (ACPI_SUCCESS (Status)) + { + InfoSize += Hid->Length; + Valid |= ACPI_VALID_HID; + } + + /* Execute the Device._UID method */ + + Status = AcpiUtExecute_UID (Node, &Uid); + if (ACPI_SUCCESS (Status)) + { + InfoSize += Uid->Length; + Valid |= ACPI_VALID_UID; + } + + /* Execute the Device._CID method */ + + Status = AcpiUtExecute_CID (Node, &CidList); + if (ACPI_SUCCESS (Status)) + { + /* Add size of CID strings and CID pointer array */ + + InfoSize += (CidList->ListSize - sizeof (ACPI_PNP_DEVICE_ID_LIST)); + Valid |= ACPI_VALID_CID; + } + + /* Execute the Device._CLS method */ + + Status = AcpiUtExecute_CLS (Node, &Cls); + if (ACPI_SUCCESS (Status)) + { + InfoSize += Cls->Length; + Valid |= ACPI_VALID_CLS; + } + } + + /* + * Now that we have the variable-length data, we can allocate the + * return buffer + */ + Info = ACPI_ALLOCATE_ZEROED (InfoSize); + if (!Info) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Get the fixed-length data */ + + if ((Type == ACPI_TYPE_DEVICE) || + (Type == ACPI_TYPE_PROCESSOR)) + { + /* + * Get extra info for ACPI Device/Processor objects only: + * Run the _STA, _ADR and, SxW, and _SxD methods. + * + * Notes: none of these methods are required, so they may or may + * not be present for this device. The Info->Valid bitfield is used + * to indicate which methods were found and run successfully. + * + * For _STA, if the method does not exist, then (as per the ACPI + * specification), the returned CurrentStatus flags will indicate + * that the device is present/functional/enabled. Otherwise, the + * CurrentStatus flags reflect the value returned from _STA. + */ + + /* Execute the Device._STA method */ + + Status = AcpiUtExecute_STA (Node, &Info->CurrentStatus); + if (ACPI_SUCCESS (Status)) + { + Valid |= ACPI_VALID_STA; + } + + /* Execute the Device._ADR method */ + + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, Node, + &Info->Address); + if (ACPI_SUCCESS (Status)) + { + Valid |= ACPI_VALID_ADR; + } + + /* Execute the Device._SxW methods */ + + Status = AcpiUtExecutePowerMethods (Node, + AcpiGbl_LowestDstateNames, ACPI_NUM_SxW_METHODS, + Info->LowestDstates); + if (ACPI_SUCCESS (Status)) + { + Valid |= ACPI_VALID_SXWS; + } + + /* Execute the Device._SxD methods */ + + Status = AcpiUtExecutePowerMethods (Node, + AcpiGbl_HighestDstateNames, ACPI_NUM_SxD_METHODS, + Info->HighestDstates); + if (ACPI_SUCCESS (Status)) + { + Valid |= ACPI_VALID_SXDS; + } + } + + /* + * Create a pointer to the string area of the return buffer. + * Point to the end of the base ACPI_DEVICE_INFO structure. + */ + NextIdString = ACPI_CAST_PTR (char, Info->CompatibleIdList.Ids); + if (CidList) + { + /* Point past the CID PNP_DEVICE_ID array */ + + NextIdString += ((ACPI_SIZE) CidList->Count * sizeof (ACPI_PNP_DEVICE_ID)); + } + + /* + * Copy the HID, UID, and CIDs to the return buffer. The variable-length + * strings are copied to the reserved area at the end of the buffer. + * + * For HID and CID, check if the ID is a PCI Root Bridge. + */ + if (Hid) + { + NextIdString = AcpiNsCopyDeviceId (&Info->HardwareId, + Hid, NextIdString); + + if (AcpiUtIsPciRootBridge (Hid->String)) + { + Info->Flags |= ACPI_PCI_ROOT_BRIDGE; + } + } + + if (Uid) + { + NextIdString = AcpiNsCopyDeviceId (&Info->UniqueId, + Uid, NextIdString); + } + + if (CidList) + { + Info->CompatibleIdList.Count = CidList->Count; + Info->CompatibleIdList.ListSize = CidList->ListSize; + + /* Copy each CID */ + + for (i = 0; i < CidList->Count; i++) + { + NextIdString = AcpiNsCopyDeviceId (&Info->CompatibleIdList.Ids[i], + &CidList->Ids[i], NextIdString); + + if (AcpiUtIsPciRootBridge (CidList->Ids[i].String)) + { + Info->Flags |= ACPI_PCI_ROOT_BRIDGE; + } + } + } + + if (Cls) + { + NextIdString = AcpiNsCopyDeviceId (&Info->ClassCode, + Cls, NextIdString); + } + + /* Copy the fixed-length data */ + + Info->InfoSize = InfoSize; + Info->Type = Type; + Info->Name = Name; + Info->ParamCount = ParamCount; + Info->Valid = Valid; + + *ReturnBuffer = Info; + Status = AE_OK; + + +Cleanup: + if (Hid) + { + ACPI_FREE (Hid); + } + if (Uid) + { + ACPI_FREE (Uid); + } + if (CidList) + { + ACPI_FREE (CidList); + } + if (Cls) + { + ACPI_FREE (Cls); + } + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetObjectInfo) + + +/****************************************************************************** + * + * FUNCTION: AcpiInstallMethod + * + * PARAMETERS: Buffer - An ACPI table containing one control method + * + * RETURN: Status + * + * DESCRIPTION: Install a control method into the namespace. If the method + * name already exists in the namespace, it is overwritten. The + * input buffer must contain a valid DSDT or SSDT containing a + * single control method. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallMethod ( + UINT8 *Buffer) +{ + ACPI_TABLE_HEADER *Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, Buffer); + UINT8 *AmlBuffer; + UINT8 *AmlStart; + char *Path; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *MethodObj; + ACPI_PARSE_STATE ParserState; + UINT32 AmlLength; + UINT16 Opcode; + UINT8 MethodFlags; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!Buffer) + { + return (AE_BAD_PARAMETER); + } + + /* Table must be a DSDT or SSDT */ + + if (!ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_SSDT)) + { + return (AE_BAD_HEADER); + } + + /* First AML opcode in the table must be a control method */ + + ParserState.Aml = Buffer + sizeof (ACPI_TABLE_HEADER); + Opcode = AcpiPsPeekOpcode (&ParserState); + if (Opcode != AML_METHOD_OP) + { + return (AE_BAD_PARAMETER); + } + + /* Extract method information from the raw AML */ + + ParserState.Aml += AcpiPsGetOpcodeSize (Opcode); + ParserState.PkgEnd = AcpiPsGetNextPackageEnd (&ParserState); + Path = AcpiPsGetNextNamestring (&ParserState); + + MethodFlags = *ParserState.Aml++; + AmlStart = ParserState.Aml; + AmlLength = ACPI_PTR_DIFF (ParserState.PkgEnd, AmlStart); + + /* + * Allocate resources up-front. We don't want to have to delete a new + * node from the namespace if we cannot allocate memory. + */ + AmlBuffer = ACPI_ALLOCATE (AmlLength); + if (!AmlBuffer) + { + return (AE_NO_MEMORY); + } + + MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); + if (!MethodObj) + { + ACPI_FREE (AmlBuffer); + return (AE_NO_MEMORY); + } + + /* Lock namespace for AcpiNsLookup, we may be creating a new node */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* The lookup either returns an existing node or creates a new one */ + + Status = AcpiNsLookup (NULL, Path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, NULL, &Node); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (Status)) /* NsLookup */ + { + if (Status != AE_ALREADY_EXISTS) + { + goto ErrorExit; + } + + /* Node existed previously, make sure it is a method node */ + + if (Node->Type != ACPI_TYPE_METHOD) + { + Status = AE_TYPE; + goto ErrorExit; + } + } + + /* Copy the method AML to the local buffer */ + + memcpy (AmlBuffer, AmlStart, AmlLength); + + /* Initialize the method object with the new method's information */ + + MethodObj->Method.AmlStart = AmlBuffer; + MethodObj->Method.AmlLength = AmlLength; + + MethodObj->Method.ParamCount = (UINT8) + (MethodFlags & AML_METHOD_ARG_COUNT); + + if (MethodFlags & AML_METHOD_SERIALIZED) + { + MethodObj->Method.InfoFlags = ACPI_METHOD_SERIALIZED; + + MethodObj->Method.SyncLevel = (UINT8) + ((MethodFlags & AML_METHOD_SYNC_LEVEL) >> 4); + } + + /* + * Now that it is complete, we can attach the new method object to + * the method Node (detaches/deletes any existing object) + */ + Status = AcpiNsAttachObject (Node, MethodObj, ACPI_TYPE_METHOD); + + /* + * Flag indicates AML buffer is dynamic, must be deleted later. + * Must be set only after attach above. + */ + Node->Flags |= ANOBJ_ALLOCATED_BUFFER; + + /* Remove local reference to the method object */ + + AcpiUtRemoveReference (MethodObj); + return (Status); + + +ErrorExit: + + ACPI_FREE (AmlBuffer); + ACPI_FREE (MethodObj); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallMethod) diff --git a/third_party/lib/acpica/source/components/namespace/nsxfobj.c b/third_party/lib/acpica/source/components/namespace/nsxfobj.c new file mode 100644 index 000000000..f00604743 --- /dev/null +++ b/third_party/lib/acpica/source/components/namespace/nsxfobj.c @@ -0,0 +1,280 @@ +/******************************************************************************* + * + * Module Name: nsxfobj - Public interfaces to the ACPI subsystem + * ACPI Object oriented interfaces + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfobj") + +/******************************************************************************* + * + * FUNCTION: AcpiGetType + * + * PARAMETERS: Handle - Handle of object whose type is desired + * RetType - Where the type will be placed + * + * RETURN: Status + * + * DESCRIPTION: This routine returns the type associatd with a particular handle + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetType ( + ACPI_HANDLE Handle, + ACPI_OBJECT_TYPE *RetType) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + /* Parameter Validation */ + + if (!RetType) + { + return (AE_BAD_PARAMETER); + } + + /* Special case for the predefined Root Node (return type ANY) */ + + if (Handle == ACPI_ROOT_OBJECT) + { + *RetType = ACPI_TYPE_ANY; + return (AE_OK); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Convert and validate the handle */ + + Node = AcpiNsValidateHandle (Handle); + if (!Node) + { + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (AE_BAD_PARAMETER); + } + + *RetType = Node->Type; + + Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetType) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetParent + * + * PARAMETERS: Handle - Handle of object whose parent is desired + * RetHandle - Where the parent handle will be placed + * + * RETURN: Status + * + * DESCRIPTION: Returns a handle to the parent of the object represented by + * Handle. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetParent ( + ACPI_HANDLE Handle, + ACPI_HANDLE *RetHandle) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_NAMESPACE_NODE *ParentNode; + ACPI_STATUS Status; + + + if (!RetHandle) + { + return (AE_BAD_PARAMETER); + } + + /* Special case for the predefined Root Node (no parent) */ + + if (Handle == ACPI_ROOT_OBJECT) + { + return (AE_NULL_ENTRY); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Convert and validate the handle */ + + Node = AcpiNsValidateHandle (Handle); + if (!Node) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + + /* Get the parent entry */ + + ParentNode = Node->Parent; + *RetHandle = ACPI_CAST_PTR (ACPI_HANDLE, ParentNode); + + /* Return exception if parent is null */ + + if (!ParentNode) + { + Status = AE_NULL_ENTRY; + } + + +UnlockAndExit: + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetParent) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetNextObject + * + * PARAMETERS: Type - Type of object to be searched for + * Parent - Parent object whose children we are getting + * LastChild - Previous child that was found. + * The NEXT child will be returned + * RetHandle - Where handle to the next object is placed + * + * RETURN: Status + * + * DESCRIPTION: Return the next peer object within the namespace. If Handle is + * valid, Scope is ignored. Otherwise, the first object within + * Scope is returned. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetNextObject ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE Parent, + ACPI_HANDLE Child, + ACPI_HANDLE *RetHandle) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + ACPI_NAMESPACE_NODE *ParentNode = NULL; + ACPI_NAMESPACE_NODE *ChildNode = NULL; + + + /* Parameter validation */ + + if (Type > ACPI_TYPE_EXTERNAL_MAX) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* If null handle, use the parent */ + + if (!Child) + { + /* Start search at the beginning of the specified scope */ + + ParentNode = AcpiNsValidateHandle (Parent); + if (!ParentNode) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + } + else + { + /* Non-null handle, ignore the parent */ + /* Convert and validate the handle */ + + ChildNode = AcpiNsValidateHandle (Child); + if (!ChildNode) + { + Status = AE_BAD_PARAMETER; + goto UnlockAndExit; + } + } + + /* Internal function does the real work */ + + Node = AcpiNsGetNextNodeTyped (Type, ParentNode, ChildNode); + if (!Node) + { + Status = AE_NOT_FOUND; + goto UnlockAndExit; + } + + if (RetHandle) + { + *RetHandle = ACPI_CAST_PTR (ACPI_HANDLE, Node); + } + + +UnlockAndExit: + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetNextObject) diff --git a/third_party/lib/acpica/source/components/parser/psargs.c b/third_party/lib/acpica/source/components/parser/psargs.c new file mode 100644 index 000000000..ccffb7190 --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psargs.c @@ -0,0 +1,936 @@ +/****************************************************************************** + * + * Module Name: psargs - Parse AML opcode arguments + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psargs") + +/* Local prototypes */ + +static UINT32 +AcpiPsGetNextPackageLength ( + ACPI_PARSE_STATE *ParserState); + +static ACPI_PARSE_OBJECT * +AcpiPsGetNextField ( + ACPI_PARSE_STATE *ParserState); + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextPackageLength + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: Decoded package length. On completion, the AML pointer points + * past the length byte or bytes. + * + * DESCRIPTION: Decode and return a package length field. + * Note: Largest package length is 28 bits, from ACPI specification + * + ******************************************************************************/ + +static UINT32 +AcpiPsGetNextPackageLength ( + ACPI_PARSE_STATE *ParserState) +{ + UINT8 *Aml = ParserState->Aml; + UINT32 PackageLength = 0; + UINT32 ByteCount; + UINT8 ByteZeroMask = 0x3F; /* Default [0:5] */ + + + ACPI_FUNCTION_TRACE (PsGetNextPackageLength); + + + /* + * Byte 0 bits [6:7] contain the number of additional bytes + * used to encode the package length, either 0,1,2, or 3 + */ + ByteCount = (Aml[0] >> 6); + ParserState->Aml += ((ACPI_SIZE) ByteCount + 1); + + /* Get bytes 3, 2, 1 as needed */ + + while (ByteCount) + { + /* + * Final bit positions for the package length bytes: + * Byte3->[20:27] + * Byte2->[12:19] + * Byte1->[04:11] + * Byte0->[00:03] + */ + PackageLength |= (Aml[ByteCount] << ((ByteCount << 3) - 4)); + + ByteZeroMask = 0x0F; /* Use bits [0:3] of byte 0 */ + ByteCount--; + } + + /* Byte 0 is a special case, either bits [0:3] or [0:5] are used */ + + PackageLength |= (Aml[0] & ByteZeroMask); + return_UINT32 (PackageLength); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextPackageEnd + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: Pointer to end-of-package +1 + * + * DESCRIPTION: Get next package length and return a pointer past the end of + * the package. Consumes the package length field + * + ******************************************************************************/ + +UINT8 * +AcpiPsGetNextPackageEnd ( + ACPI_PARSE_STATE *ParserState) +{ + UINT8 *Start = ParserState->Aml; + UINT32 PackageLength; + + + ACPI_FUNCTION_TRACE (PsGetNextPackageEnd); + + + /* Function below updates ParserState->Aml */ + + PackageLength = AcpiPsGetNextPackageLength (ParserState); + + return_PTR (Start + PackageLength); /* end of package */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextNamestring + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: Pointer to the start of the name string (pointer points into + * the AML. + * + * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name + * prefix characters. Set parser state to point past the string. + * (Name is consumed from the AML.) + * + ******************************************************************************/ + +char * +AcpiPsGetNextNamestring ( + ACPI_PARSE_STATE *ParserState) +{ + UINT8 *Start = ParserState->Aml; + UINT8 *End = ParserState->Aml; + + + ACPI_FUNCTION_TRACE (PsGetNextNamestring); + + + /* Point past any namestring prefix characters (backslash or carat) */ + + while (ACPI_IS_ROOT_PREFIX (*End) || + ACPI_IS_PARENT_PREFIX (*End)) + { + End++; + } + + /* Decode the path prefix character */ + + switch (*End) + { + case 0: + + /* NullName */ + + if (End == Start) + { + Start = NULL; + } + End++; + break; + + case AML_DUAL_NAME_PREFIX: + + /* Two name segments */ + + End += 1 + (2 * ACPI_NAME_SIZE); + break; + + case AML_MULTI_NAME_PREFIX_OP: + + /* Multiple name segments, 4 chars each, count in next byte */ + + End += 2 + (*(End + 1) * ACPI_NAME_SIZE); + break; + + default: + + /* Single name segment */ + + End += ACPI_NAME_SIZE; + break; + } + + ParserState->Aml = End; + return_PTR ((char *) Start); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextNamepath + * + * PARAMETERS: ParserState - Current parser state object + * Arg - Where the namepath will be stored + * ArgCount - If the namepath points to a control method + * the method's argument is returned here. + * PossibleMethodCall - Whether the namepath can possibly be the + * start of a method call + * + * RETURN: Status + * + * DESCRIPTION: Get next name (if method call, return # of required args). + * Names are looked up in the internal namespace to determine + * if the name represents a control method. If a method + * is found, the number of arguments to the method is returned. + * This information is critical for parsing to continue correctly. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsGetNextNamepath ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Arg, + BOOLEAN PossibleMethodCall) +{ + ACPI_STATUS Status; + char *Path; + ACPI_PARSE_OBJECT *NameOp; + ACPI_OPERAND_OBJECT *MethodDesc; + ACPI_NAMESPACE_NODE *Node; + UINT8 *Start = ParserState->Aml; + + + ACPI_FUNCTION_TRACE (PsGetNextNamepath); + + + Path = AcpiPsGetNextNamestring (ParserState); + AcpiPsInitOp (Arg, AML_INT_NAMEPATH_OP); + + /* Null path case is allowed, just exit */ + + if (!Path) + { + Arg->Common.Value.Name = Path; + return_ACPI_STATUS (AE_OK); + } + + /* + * Lookup the name in the internal namespace, starting with the current + * scope. We don't want to add anything new to the namespace here, + * however, so we use MODE_EXECUTE. + * Allow searching of the parent tree, but don't open a new scope - + * we just want to lookup the object (must be mode EXECUTE to perform + * the upsearch) + */ + Status = AcpiNsLookup (WalkState->ScopeInfo, Path, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &Node); + + /* + * If this name is a control method invocation, we must + * setup the method call + */ + if (ACPI_SUCCESS (Status) && + PossibleMethodCall && + (Node->Type == ACPI_TYPE_METHOD)) + { + if (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) == ARGP_SUPERNAME) + { + /* + * AcpiPsGetNextNamestring has increased the AML pointer, + * so we need to restore the saved AML pointer for method call. + */ + WalkState->ParserState.Aml = Start; + WalkState->ArgCount = 1; + AcpiPsInitOp (Arg, AML_INT_METHODCALL_OP); + return_ACPI_STATUS (AE_OK); + } + + /* This name is actually a control method invocation */ + + MethodDesc = AcpiNsGetAttachedObject (Node); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Control Method - %p Desc %p Path=%p\n", Node, MethodDesc, Path)); + + NameOp = AcpiPsAllocOp (AML_INT_NAMEPATH_OP, Start); + if (!NameOp) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Change Arg into a METHOD CALL and attach name to it */ + + AcpiPsInitOp (Arg, AML_INT_METHODCALL_OP); + NameOp->Common.Value.Name = Path; + + /* Point METHODCALL/NAME to the METHOD Node */ + + NameOp->Common.Node = Node; + AcpiPsAppendArg (Arg, NameOp); + + if (!MethodDesc) + { + ACPI_ERROR ((AE_INFO, + "Control Method %p has no attached object", + Node)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Control Method - %p Args %X\n", + Node, MethodDesc->Method.ParamCount)); + + /* Get the number of arguments to expect */ + + WalkState->ArgCount = MethodDesc->Method.ParamCount; + return_ACPI_STATUS (AE_OK); + } + + /* + * Special handling if the name was not found during the lookup - + * some NotFound cases are allowed + */ + if (Status == AE_NOT_FOUND) + { + /* 1) NotFound is ok during load pass 1/2 (allow forward references) */ + + if ((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) != + ACPI_PARSE_EXECUTE) + { + Status = AE_OK; + } + + /* 2) NotFound during a CondRefOf(x) is ok by definition */ + + else if (WalkState->Op->Common.AmlOpcode == AML_COND_REF_OF_OP) + { + Status = AE_OK; + } + + /* + * 3) NotFound while building a Package is ok at this point, we + * may flag as an error later if slack mode is not enabled. + * (Some ASL code depends on allowing this behavior) + */ + else if ((Arg->Common.Parent) && + ((Arg->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Arg->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP))) + { + Status = AE_OK; + } + } + + /* Final exception check (may have been changed from code above) */ + + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR_NAMESPACE (Path, Status); + + if ((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == + ACPI_PARSE_EXECUTE) + { + /* Report a control method execution error */ + + Status = AcpiDsMethodError (Status, WalkState); + } + } + + /* Save the namepath */ + + Arg->Common.Value.Name = Path; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextSimpleArg + * + * PARAMETERS: ParserState - Current parser state object + * ArgType - The argument type (AML_*_ARG) + * Arg - Where the argument is returned + * + * RETURN: None + * + * DESCRIPTION: Get the next simple argument (constant, string, or namestring) + * + ******************************************************************************/ + +void +AcpiPsGetNextSimpleArg ( + ACPI_PARSE_STATE *ParserState, + UINT32 ArgType, + ACPI_PARSE_OBJECT *Arg) +{ + UINT32 Length; + UINT16 Opcode; + UINT8 *Aml = ParserState->Aml; + + + ACPI_FUNCTION_TRACE_U32 (PsGetNextSimpleArg, ArgType); + + + switch (ArgType) + { + case ARGP_BYTEDATA: + + /* Get 1 byte from the AML stream */ + + Opcode = AML_BYTE_OP; + Arg->Common.Value.Integer = (UINT64) *Aml; + Length = 1; + break; + + case ARGP_WORDDATA: + + /* Get 2 bytes from the AML stream */ + + Opcode = AML_WORD_OP; + ACPI_MOVE_16_TO_64 (&Arg->Common.Value.Integer, Aml); + Length = 2; + break; + + case ARGP_DWORDDATA: + + /* Get 4 bytes from the AML stream */ + + Opcode = AML_DWORD_OP; + ACPI_MOVE_32_TO_64 (&Arg->Common.Value.Integer, Aml); + Length = 4; + break; + + case ARGP_QWORDDATA: + + /* Get 8 bytes from the AML stream */ + + Opcode = AML_QWORD_OP; + ACPI_MOVE_64_TO_64 (&Arg->Common.Value.Integer, Aml); + Length = 8; + break; + + case ARGP_CHARLIST: + + /* Get a pointer to the string, point past the string */ + + Opcode = AML_STRING_OP; + Arg->Common.Value.String = ACPI_CAST_PTR (char, Aml); + + /* Find the null terminator */ + + Length = 0; + while (Aml[Length]) + { + Length++; + } + Length++; + break; + + case ARGP_NAME: + case ARGP_NAMESTRING: + + AcpiPsInitOp (Arg, AML_INT_NAMEPATH_OP); + Arg->Common.Value.Name = AcpiPsGetNextNamestring (ParserState); + return_VOID; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid ArgType 0x%X", ArgType)); + return_VOID; + } + + AcpiPsInitOp (Arg, Opcode); + ParserState->Aml += Length; + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextField + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: A newly allocated FIELD op + * + * DESCRIPTION: Get next field (NamedField, ReservedField, or AccessField) + * + ******************************************************************************/ + +static ACPI_PARSE_OBJECT * +AcpiPsGetNextField ( + ACPI_PARSE_STATE *ParserState) +{ + UINT8 *Aml; + ACPI_PARSE_OBJECT *Field; + ACPI_PARSE_OBJECT *Arg = NULL; + UINT16 Opcode; + UINT32 Name; + UINT8 AccessType; + UINT8 AccessAttribute; + UINT8 AccessLength; + UINT32 PkgLength; + UINT8 *PkgEnd; + UINT32 BufferLength; + + + ACPI_FUNCTION_TRACE (PsGetNextField); + + + Aml = ParserState->Aml; + + /* Determine field type */ + + switch (ACPI_GET8 (ParserState->Aml)) + { + case AML_FIELD_OFFSET_OP: + + Opcode = AML_INT_RESERVEDFIELD_OP; + ParserState->Aml++; + break; + + case AML_FIELD_ACCESS_OP: + + Opcode = AML_INT_ACCESSFIELD_OP; + ParserState->Aml++; + break; + + case AML_FIELD_CONNECTION_OP: + + Opcode = AML_INT_CONNECTION_OP; + ParserState->Aml++; + break; + + case AML_FIELD_EXT_ACCESS_OP: + + Opcode = AML_INT_EXTACCESSFIELD_OP; + ParserState->Aml++; + break; + + default: + + Opcode = AML_INT_NAMEDFIELD_OP; + break; + } + + /* Allocate a new field op */ + + Field = AcpiPsAllocOp (Opcode, Aml); + if (!Field) + { + return_PTR (NULL); + } + + /* Decode the field type */ + + switch (Opcode) + { + case AML_INT_NAMEDFIELD_OP: + + /* Get the 4-character name */ + + ACPI_MOVE_32_TO_32 (&Name, ParserState->Aml); + AcpiPsSetName (Field, Name); + ParserState->Aml += ACPI_NAME_SIZE; + + /* Get the length which is encoded as a package length */ + + Field->Common.Value.Size = AcpiPsGetNextPackageLength (ParserState); + break; + + + case AML_INT_RESERVEDFIELD_OP: + + /* Get the length which is encoded as a package length */ + + Field->Common.Value.Size = AcpiPsGetNextPackageLength (ParserState); + break; + + + case AML_INT_ACCESSFIELD_OP: + case AML_INT_EXTACCESSFIELD_OP: + + /* + * Get AccessType and AccessAttrib and merge into the field Op + * AccessType is first operand, AccessAttribute is second. stuff + * these bytes into the node integer value for convenience. + */ + + /* Get the two bytes (Type/Attribute) */ + + AccessType = ACPI_GET8 (ParserState->Aml); + ParserState->Aml++; + AccessAttribute = ACPI_GET8 (ParserState->Aml); + ParserState->Aml++; + + Field->Common.Value.Integer = (UINT8) AccessType; + Field->Common.Value.Integer |= (UINT16) (AccessAttribute << 8); + + /* This opcode has a third byte, AccessLength */ + + if (Opcode == AML_INT_EXTACCESSFIELD_OP) + { + AccessLength = ACPI_GET8 (ParserState->Aml); + ParserState->Aml++; + + Field->Common.Value.Integer |= (UINT32) (AccessLength << 16); + } + break; + + + case AML_INT_CONNECTION_OP: + + /* + * Argument for Connection operator can be either a Buffer + * (resource descriptor), or a NameString. + */ + Aml = ParserState->Aml; + if (ACPI_GET8 (ParserState->Aml) == AML_BUFFER_OP) + { + ParserState->Aml++; + + PkgEnd = ParserState->Aml; + PkgLength = AcpiPsGetNextPackageLength (ParserState); + PkgEnd += PkgLength; + + if (ParserState->Aml < PkgEnd) + { + /* Non-empty list */ + + Arg = AcpiPsAllocOp (AML_INT_BYTELIST_OP, Aml); + if (!Arg) + { + AcpiPsFreeOp (Field); + return_PTR (NULL); + } + + /* Get the actual buffer length argument */ + + Opcode = ACPI_GET8 (ParserState->Aml); + ParserState->Aml++; + + switch (Opcode) + { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + + BufferLength = ACPI_GET8 (ParserState->Aml); + ParserState->Aml += 1; + break; + + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + + BufferLength = ACPI_GET16 (ParserState->Aml); + ParserState->Aml += 2; + break; + + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ + + BufferLength = ACPI_GET32 (ParserState->Aml); + ParserState->Aml += 4; + break; + + default: + + BufferLength = 0; + break; + } + + /* Fill in bytelist data */ + + Arg->Named.Value.Size = BufferLength; + Arg->Named.Data = ParserState->Aml; + } + + /* Skip to End of byte data */ + + ParserState->Aml = PkgEnd; + } + else + { + Arg = AcpiPsAllocOp (AML_INT_NAMEPATH_OP, Aml); + if (!Arg) + { + AcpiPsFreeOp (Field); + return_PTR (NULL); + } + + /* Get the Namestring argument */ + + Arg->Common.Value.Name = AcpiPsGetNextNamestring (ParserState); + } + + /* Link the buffer/namestring to parent (CONNECTION_OP) */ + + AcpiPsAppendArg (Field, Arg); + break; + + + default: + + /* Opcode was set in previous switch */ + break; + } + + return_PTR (Field); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetNextArg + * + * PARAMETERS: WalkState - Current state + * ParserState - Current parser state object + * ArgType - The parser argument type (ARGP_*) + * ReturnArg - Where the next arg is returned + * + * RETURN: Status, and an op object containing the next argument. + * + * DESCRIPTION: Get next argument (including complex list arguments that require + * pushing the parser stack) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsGetNextArg ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_STATE *ParserState, + UINT32 ArgType, + ACPI_PARSE_OBJECT **ReturnArg) +{ + ACPI_PARSE_OBJECT *Arg = NULL; + ACPI_PARSE_OBJECT *Prev = NULL; + ACPI_PARSE_OBJECT *Field; + UINT32 Subop; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (PsGetNextArg, ParserState); + + + switch (ArgType) + { + case ARGP_BYTEDATA: + case ARGP_WORDDATA: + case ARGP_DWORDDATA: + case ARGP_CHARLIST: + case ARGP_NAME: + case ARGP_NAMESTRING: + + /* Constants, strings, and namestrings are all the same size */ + + Arg = AcpiPsAllocOp (AML_BYTE_OP, ParserState->Aml); + if (!Arg) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + AcpiPsGetNextSimpleArg (ParserState, ArgType, Arg); + break; + + case ARGP_PKGLENGTH: + + /* Package length, nothing returned */ + + ParserState->PkgEnd = AcpiPsGetNextPackageEnd (ParserState); + break; + + case ARGP_FIELDLIST: + + if (ParserState->Aml < ParserState->PkgEnd) + { + /* Non-empty list */ + + while (ParserState->Aml < ParserState->PkgEnd) + { + Field = AcpiPsGetNextField (ParserState); + if (!Field) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + if (Prev) + { + Prev->Common.Next = Field; + } + else + { + Arg = Field; + } + Prev = Field; + } + + /* Skip to End of byte data */ + + ParserState->Aml = ParserState->PkgEnd; + } + break; + + case ARGP_BYTELIST: + + if (ParserState->Aml < ParserState->PkgEnd) + { + /* Non-empty list */ + + Arg = AcpiPsAllocOp (AML_INT_BYTELIST_OP, + ParserState->Aml); + if (!Arg) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Fill in bytelist data */ + + Arg->Common.Value.Size = (UINT32) + ACPI_PTR_DIFF (ParserState->PkgEnd, ParserState->Aml); + Arg->Named.Data = ParserState->Aml; + + /* Skip to End of byte data */ + + ParserState->Aml = ParserState->PkgEnd; + } + break; + + case ARGP_TARGET: + case ARGP_SUPERNAME: + case ARGP_SIMPLENAME: + case ARGP_NAME_OR_REF: + + Subop = AcpiPsPeekOpcode (ParserState); + if (Subop == 0 || + AcpiPsIsLeadingChar (Subop) || + ACPI_IS_ROOT_PREFIX (Subop) || + ACPI_IS_PARENT_PREFIX (Subop)) + { + /* NullName or NameString */ + + Arg = AcpiPsAllocOp (AML_INT_NAMEPATH_OP, ParserState->Aml); + if (!Arg) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* SuperName allows argument to be a method call */ + + if (ArgType == ARGP_SUPERNAME) + { + Status = AcpiPsGetNextNamepath (WalkState, ParserState, + Arg, ACPI_POSSIBLE_METHOD_CALL); + + /* + * If the SuperName argument is a method call, we have + * already restored the AML pointer, just free this Arg + */ + if (Arg->Common.AmlOpcode == AML_INT_METHODCALL_OP) + { + AcpiPsFreeOp (Arg); + Arg = NULL; + } + } + else + { + Status = AcpiPsGetNextNamepath (WalkState, ParserState, + Arg, ACPI_NOT_METHOD_CALL); + } + } + else + { + /* Single complex argument, nothing returned */ + + WalkState->ArgCount = 1; + } + break; + + case ARGP_DATAOBJ: + case ARGP_TERMARG: + + /* Single complex argument, nothing returned */ + + WalkState->ArgCount = 1; + break; + + case ARGP_DATAOBJLIST: + case ARGP_TERMLIST: + case ARGP_OBJLIST: + + if (ParserState->Aml < ParserState->PkgEnd) + { + /* Non-empty list of variable arguments, nothing returned */ + + WalkState->ArgCount = ACPI_VAR_ARGS; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid ArgType: 0x%X", ArgType)); + Status = AE_AML_OPERAND_TYPE; + break; + } + + *ReturnArg = Arg; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/parser/psloop.c b/third_party/lib/acpica/source/components/parser/psloop.c new file mode 100644 index 000000000..e0839fd7d --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psloop.c @@ -0,0 +1,639 @@ +/****************************************************************************** + * + * Module Name: psloop - Main AML parse loop + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Parse the AML and build an operation tree as most interpreters, (such as + * Perl) do. Parsing is done by hand rather than with a YACC generated parser + * to tightly constrain stack and dynamic memory usage. Parsing is kept + * flexible and the code fairly compact by parsing based on a list of AML + * opcode templates in AmlOpInfo[]. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "acdispat.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psloop") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiPsGetArguments ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT *Op); + +static void +AcpiPsLinkModuleCode ( + ACPI_PARSE_OBJECT *ParentOp, + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_OWNER_ID OwnerId); + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetArguments + * + * PARAMETERS: WalkState - Current state + * AmlOpStart - Op start in AML + * Op - Current Op + * + * RETURN: Status + * + * DESCRIPTION: Get arguments for passed Op. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiPsGetArguments ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *Arg = NULL; + const ACPI_OPCODE_INFO *OpInfo; + + + ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState); + + + switch (Op->Common.AmlOpcode) + { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ + case AML_QWORD_OP: /* AML_QWORDATA_ARG */ + case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ + + /* Fill in constant or string argument directly */ + + AcpiPsGetNextSimpleArg (&(WalkState->ParserState), + GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op); + break; + + case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ + + Status = AcpiPsGetNextNamepath (WalkState, + &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + WalkState->ArgTypes = 0; + break; + + default: + /* + * Op is not a constant or string, append each argument to the Op + */ + while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && + !WalkState->ArgCount) + { + WalkState->Aml = WalkState->ParserState.Aml; + + Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState), + GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (Arg) + { + AcpiPsAppendArg (Op, Arg); + } + + INCREMENT_ARG_LIST (WalkState->ArgTypes); + } + + + /* + * Handle executable code at "module-level". This refers to + * executable opcodes that appear outside of any control method. + */ + if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) && + ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0)) + { + /* + * We want to skip If/Else/While constructs during Pass1 because we + * want to actually conditionally execute the code during Pass2. + * + * Except for disassembly, where we always want to walk the + * If/Else/While packages + */ + switch (Op->Common.AmlOpcode) + { + case AML_IF_OP: + case AML_ELSE_OP: + case AML_WHILE_OP: + /* + * Currently supported module-level opcodes are: + * IF/ELSE/WHILE. These appear to be the most common, + * and easiest to support since they open an AML + * package. + */ + if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) + { + AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart, + (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart), + WalkState->OwnerId); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Pass1: Skipping an If/Else/While body\n")); + + /* Skip body of if/else/while in pass 1 */ + + WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; + WalkState->ArgCount = 0; + break; + + default: + /* + * Check for an unsupported executable opcode at module + * level. We must be in PASS1, the parent must be a SCOPE, + * The opcode class must be EXECUTE, and the opcode must + * not be an argument to another opcode. + */ + if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) && + (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) + { + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if ((OpInfo->Class == AML_CLASS_EXECUTE) && + (!Arg)) + { + ACPI_WARNING ((AE_INFO, + "Unsupported module-level executable opcode " + "0x%.2X at table offset 0x%.4X", + Op->Common.AmlOpcode, + (UINT32) (ACPI_PTR_DIFF (AmlOpStart, + WalkState->ParserState.AmlStart) + + sizeof (ACPI_TABLE_HEADER)))); + } + } + break; + } + } + + /* Special processing for certain opcodes */ + + switch (Op->Common.AmlOpcode) + { + case AML_METHOD_OP: + /* + * Skip parsing of control method because we don't have enough + * info in the first pass to parse it correctly. + * + * Save the length and address of the body + */ + Op->Named.Data = WalkState->ParserState.Aml; + Op->Named.Length = (UINT32) + (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml); + + /* Skip body of method */ + + WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; + WalkState->ArgCount = 0; + break; + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + if ((Op->Common.Parent) && + (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && + (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) + { + /* + * Skip parsing of Buffers and Packages because we don't have + * enough info in the first pass to parse them correctly. + */ + Op->Named.Data = AmlOpStart; + Op->Named.Length = (UINT32) + (WalkState->ParserState.PkgEnd - AmlOpStart); + + /* Skip body */ + + WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; + WalkState->ArgCount = 0; + } + break; + + case AML_WHILE_OP: + + if (WalkState->ControlState) + { + WalkState->ControlState->Control.PackageEnd = + WalkState->ParserState.PkgEnd; + } + break; + + default: + + /* No action for all other opcodes */ + + break; + } + + break; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsLinkModuleCode + * + * PARAMETERS: ParentOp - Parent parser op + * AmlStart - Pointer to the AML + * AmlLength - Length of executable AML + * OwnerId - OwnerId of module level code + * + * RETURN: None. + * + * DESCRIPTION: Wrap the module-level code with a method object and link the + * object to the global list. Note, the mutex field of the method + * object is used to link multiple module-level code objects. + * + ******************************************************************************/ + +static void +AcpiPsLinkModuleCode ( + ACPI_PARSE_OBJECT *ParentOp, + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_OWNER_ID OwnerId) +{ + ACPI_OPERAND_OBJECT *Prev; + ACPI_OPERAND_OBJECT *Next; + ACPI_OPERAND_OBJECT *MethodObj; + ACPI_NAMESPACE_NODE *ParentNode; + + + ACPI_FUNCTION_TRACE (PsLinkModuleCode); + + + /* Get the tail of the list */ + + Prev = Next = AcpiGbl_ModuleCodeList; + while (Next) + { + Prev = Next; + Next = Next->Method.Mutex; + } + + /* + * Insert the module level code into the list. Merge it if it is + * adjacent to the previous element. + */ + if (!Prev || + ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart)) + { + /* Create, initialize, and link a new temporary method object */ + + MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); + if (!MethodObj) + { + return_VOID; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Create/Link new code block: %p\n", MethodObj)); + + if (ParentOp->Common.Node) + { + ParentNode = ParentOp->Common.Node; + } + else + { + ParentNode = AcpiGbl_RootNode; + } + + MethodObj->Method.AmlStart = AmlStart; + MethodObj->Method.AmlLength = AmlLength; + MethodObj->Method.OwnerId = OwnerId; + MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL; + + /* + * Save the parent node in NextObject. This is cheating, but we + * don't want to expand the method object. + */ + MethodObj->Method.NextObject = + ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode); + + if (!Prev) + { + AcpiGbl_ModuleCodeList = MethodObj; + } + else + { + Prev->Method.Mutex = MethodObj; + } + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Appending to existing code block: %p\n", Prev)); + + Prev->Method.AmlLength += AmlLength; + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: AcpiPsParseLoop + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Parse AML (pointed to by the current parser state) and return + * a tree of ops. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsParseLoop ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *Op = NULL; /* current op */ + ACPI_PARSE_STATE *ParserState; + UINT8 *AmlOpStart = NULL; + + + ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState); + + + if (WalkState->DescendingCallback == NULL) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + ParserState = &WalkState->ParserState; + WalkState->ArgTypes = 0; + +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + + if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART) + { + /* We are restarting a preempted control method */ + + if (AcpiPsHasCompletedScope (ParserState)) + { + /* + * We must check if a predicate to an IF or WHILE statement + * was just completed + */ + if ((ParserState->Scope->ParseScope.Op) && + ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) || + (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) && + (WalkState->ControlState) && + (WalkState->ControlState->Common.State == + ACPI_CONTROL_PREDICATE_EXECUTING)) + { + /* + * A predicate was just completed, get the value of the + * predicate and branch based on that value + */ + WalkState->Op = NULL; + Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE)); + if (ACPI_FAILURE (Status) && + ((Status & AE_CODE_MASK) != AE_CODE_CONTROL)) + { + if (Status == AE_AML_NO_RETURN_VALUE) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Invoked method did not return a value")); + } + + ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed")); + return_ACPI_STATUS (Status); + } + + Status = AcpiPsNextParseState (WalkState, Op, Status); + } + + AcpiPsPopScope (ParserState, &Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op)); + } + else if (WalkState->PrevOp) + { + /* We were in the middle of an op */ + + Op = WalkState->PrevOp; + WalkState->ArgTypes = WalkState->PrevArgTypes; + } + } +#endif + + /* Iterative parsing loop, while there is more AML to process: */ + + while ((ParserState->Aml < ParserState->AmlEnd) || (Op)) + { + AmlOpStart = ParserState->Aml; + if (!Op) + { + Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_CTRL_PARSE_CONTINUE) + { + continue; + } + + if (Status == AE_CTRL_PARSE_PENDING) + { + Status = AE_OK; + } + + if (Status == AE_CTRL_TERMINATE) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiPsCompleteOp (WalkState, &Op, Status); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + continue; + } + + AcpiExStartTraceOpcode (Op, WalkState); + } + + + /* + * Start ArgCount at zero because we don't know if there are + * any args yet + */ + WalkState->ArgCount = 0; + + /* Are there any arguments that must be processed? */ + + if (WalkState->ArgTypes) + { + /* Get arguments */ + + Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op); + if (ACPI_FAILURE (Status)) + { + Status = AcpiPsCompleteOp (WalkState, &Op, Status); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + continue; + } + } + + /* Check for arguments that need to be processed */ + + if (WalkState->ArgCount) + { + /* + * There are arguments (complex ones), push Op and + * prepare for argument + */ + Status = AcpiPsPushScope (ParserState, Op, + WalkState->ArgTypes, WalkState->ArgCount); + if (ACPI_FAILURE (Status)) + { + Status = AcpiPsCompleteOp (WalkState, &Op, Status); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + continue; + } + + Op = NULL; + continue; + } + + /* + * All arguments have been processed -- Op is complete, + * prepare for next + */ + WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (WalkState->OpInfo->Flags & AML_NAMED) + { + if (Op->Common.AmlOpcode == AML_REGION_OP || + Op->Common.AmlOpcode == AML_DATA_REGION_OP) + { + /* + * Skip parsing of control method or opregion body, + * because we don't have enough info in the first pass + * to parse them correctly. + * + * Completed parsing an OpRegion declaration, we now + * know the length. + */ + Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); + } + } + + if (WalkState->OpInfo->Flags & AML_CREATE) + { + /* + * Backup to beginning of CreateXXXfield declaration (1 for + * Opcode) + * + * BodyLength is unknown until we parse the body + */ + Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); + } + + if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP) + { + /* + * Backup to beginning of BankField declaration + * + * BodyLength is unknown until we parse the body + */ + Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); + } + + /* This op complete, notify the dispatcher */ + + if (WalkState->AscendingCallback != NULL) + { + WalkState->Op = Op; + WalkState->Opcode = Op->Common.AmlOpcode; + + Status = WalkState->AscendingCallback (WalkState); + Status = AcpiPsNextParseState (WalkState, Op, Status); + if (Status == AE_CTRL_PENDING) + { + Status = AE_OK; + } + } + + Status = AcpiPsCompleteOp (WalkState, &Op, Status); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + } /* while ParserState->Aml */ + + Status = AcpiPsCompleteFinalOp (WalkState, Op, Status); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/parser/psobject.c b/third_party/lib/acpica/source/components/parser/psobject.c new file mode 100644 index 000000000..7edc39e2b --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psobject.c @@ -0,0 +1,686 @@ +/****************************************************************************** + * + * Module Name: psobject - Support for parse objects + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psobject") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiPsGetAmlOpcode ( + ACPI_WALK_STATE *WalkState); + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetAmlOpcode + * + * PARAMETERS: WalkState - Current state + * + * RETURN: Status + * + * DESCRIPTION: Extract the next AML opcode from the input stream. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiPsGetAmlOpcode ( + ACPI_WALK_STATE *WalkState) +{ + UINT32 AmlOffset; + + + ACPI_FUNCTION_TRACE_PTR (PsGetAmlOpcode, WalkState); + + + WalkState->Aml = WalkState->ParserState.Aml; + WalkState->Opcode = AcpiPsPeekOpcode (&(WalkState->ParserState)); + + /* + * First cut to determine what we have found: + * 1) A valid AML opcode + * 2) A name string + * 3) An unknown/invalid opcode + */ + WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode); + + switch (WalkState->OpInfo->Class) + { + case AML_CLASS_ASCII: + case AML_CLASS_PREFIX: + /* + * Starts with a valid prefix or ASCII char, this is a name + * string. Convert the bare name string to a namepath. + */ + WalkState->Opcode = AML_INT_NAMEPATH_OP; + WalkState->ArgTypes = ARGP_NAMESTRING; + break; + + case AML_CLASS_UNKNOWN: + + /* The opcode is unrecognized. Complain and skip unknown opcodes */ + + if (WalkState->PassNumber == 2) + { + AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml, + WalkState->ParserState.AmlStart); + + ACPI_ERROR ((AE_INFO, + "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", + WalkState->Opcode, + (UINT32) (AmlOffset + sizeof (ACPI_TABLE_HEADER)))); + + ACPI_DUMP_BUFFER ((WalkState->ParserState.Aml - 16), 48); + +#ifdef ACPI_ASL_COMPILER + /* + * This is executed for the disassembler only. Output goes + * to the disassembled ASL output file. + */ + AcpiOsPrintf ( + "/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", + WalkState->Opcode, + (UINT32) (AmlOffset + sizeof (ACPI_TABLE_HEADER))); + + /* Dump the context surrounding the invalid opcode */ + + AcpiUtDumpBuffer (((UINT8 *) WalkState->ParserState.Aml - 16), + 48, DB_BYTE_DISPLAY, + (AmlOffset + sizeof (ACPI_TABLE_HEADER) - 16)); + AcpiOsPrintf (" */\n"); +#endif + } + + /* Increment past one-byte or two-byte opcode */ + + WalkState->ParserState.Aml++; + if (WalkState->Opcode > 0xFF) /* Can only happen if first byte is 0x5B */ + { + WalkState->ParserState.Aml++; + } + + return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); + + default: + + /* Found opcode info, this is a normal opcode */ + + WalkState->ParserState.Aml += + AcpiPsGetOpcodeSize (WalkState->Opcode); + WalkState->ArgTypes = WalkState->OpInfo->ParseArgs; + break; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsBuildNamedOp + * + * PARAMETERS: WalkState - Current state + * AmlOpStart - Begin of named Op in AML + * UnnamedOp - Early Op (not a named Op) + * Op - Returned Op + * + * RETURN: Status + * + * DESCRIPTION: Parse a named Op + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsBuildNamedOp ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT *UnnamedOp, + ACPI_PARSE_OBJECT **Op) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *Arg = NULL; + + + ACPI_FUNCTION_TRACE_PTR (PsBuildNamedOp, WalkState); + + + UnnamedOp->Common.Value.Arg = NULL; + UnnamedOp->Common.ArgListLength = 0; + UnnamedOp->Common.AmlOpcode = WalkState->Opcode; + + /* + * Get and append arguments until we find the node that contains + * the name (the type ARGP_NAME). + */ + while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && + (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) != ARGP_NAME)) + { + Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState), + GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiPsAppendArg (UnnamedOp, Arg); + INCREMENT_ARG_LIST (WalkState->ArgTypes); + } + + /* + * Make sure that we found a NAME and didn't run out of arguments + */ + if (!GET_CURRENT_ARG_TYPE (WalkState->ArgTypes)) + { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* We know that this arg is a name, move to next arg */ + + INCREMENT_ARG_LIST (WalkState->ArgTypes); + + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + WalkState->Op = NULL; + + Status = WalkState->DescendingCallback (WalkState, Op); + if (ACPI_FAILURE (Status)) + { + if (Status != AE_CTRL_TERMINATE) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During name lookup/catalog")); + } + return_ACPI_STATUS (Status); + } + + if (!*Op) + { + return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); + } + + Status = AcpiPsNextParseState (WalkState, *Op, Status); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_CTRL_PENDING) + { + Status = AE_CTRL_PARSE_PENDING; + } + return_ACPI_STATUS (Status); + } + + AcpiPsAppendArg (*Op, UnnamedOp->Common.Value.Arg); + + if ((*Op)->Common.AmlOpcode == AML_REGION_OP || + (*Op)->Common.AmlOpcode == AML_DATA_REGION_OP) + { + /* + * Defer final parsing of an OperationRegion body, because we don't + * have enough info in the first pass to parse it correctly (i.e., + * there may be method calls within the TermArg elements of the body.) + * + * However, we must continue parsing because the opregion is not a + * standalone package -- we don't know where the end is at this point. + * + * (Length is unknown until parse of the body complete) + */ + (*Op)->Named.Data = AmlOpStart; + (*Op)->Named.Length = 0; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsCreateOp + * + * PARAMETERS: WalkState - Current state + * AmlOpStart - Op start in AML + * NewOp - Returned Op + * + * RETURN: Status + * + * DESCRIPTION: Get Op from AML + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsCreateOp ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT **NewOp) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PARSE_OBJECT *Op; + ACPI_PARSE_OBJECT *NamedOp = NULL; + ACPI_PARSE_OBJECT *ParentScope; + UINT8 ArgumentCount; + const ACPI_OPCODE_INFO *OpInfo; + + + ACPI_FUNCTION_TRACE_PTR (PsCreateOp, WalkState); + + + Status = AcpiPsGetAmlOpcode (WalkState); + if (Status == AE_CTRL_PARSE_CONTINUE) + { + return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); + } + + /* Create Op structure and append to parent's argument list */ + + WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode); + Op = AcpiPsAllocOp (WalkState->Opcode, AmlOpStart); + if (!Op) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + if (WalkState->OpInfo->Flags & AML_NAMED) + { + Status = AcpiPsBuildNamedOp (WalkState, AmlOpStart, Op, &NamedOp); + AcpiPsFreeOp (Op); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + *NewOp = NamedOp; + return_ACPI_STATUS (AE_OK); + } + + /* Not a named opcode, just allocate Op and append to parent */ + + if (WalkState->OpInfo->Flags & AML_CREATE) + { + /* + * Backup to beginning of CreateXXXfield declaration + * BodyLength is unknown until we parse the body + */ + Op->Named.Data = AmlOpStart; + Op->Named.Length = 0; + } + + if (WalkState->Opcode == AML_BANK_FIELD_OP) + { + /* + * Backup to beginning of BankField declaration + * BodyLength is unknown until we parse the body + */ + Op->Named.Data = AmlOpStart; + Op->Named.Length = 0; + } + + ParentScope = AcpiPsGetParentScope (&(WalkState->ParserState)); + AcpiPsAppendArg (ParentScope, Op); + + if (ParentScope) + { + OpInfo = AcpiPsGetOpcodeInfo (ParentScope->Common.AmlOpcode); + if (OpInfo->Flags & AML_HAS_TARGET) + { + ArgumentCount = AcpiPsGetArgumentCount (OpInfo->Type); + if (ParentScope->Common.ArgListLength > ArgumentCount) + { + Op->Common.Flags |= ACPI_PARSEOP_TARGET; + } + } + else if (ParentScope->Common.AmlOpcode == AML_INCREMENT_OP) + { + Op->Common.Flags |= ACPI_PARSEOP_TARGET; + } + } + + if (WalkState->DescendingCallback != NULL) + { + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + WalkState->Op = *NewOp = Op; + + Status = WalkState->DescendingCallback (WalkState, &Op); + Status = AcpiPsNextParseState (WalkState, Op, Status); + if (Status == AE_CTRL_PENDING) + { + Status = AE_CTRL_PARSE_PENDING; + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsCompleteOp + * + * PARAMETERS: WalkState - Current state + * Op - Returned Op + * Status - Parse status before complete Op + * + * RETURN: Status + * + * DESCRIPTION: Complete Op + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsCompleteOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **Op, + ACPI_STATUS Status) +{ + ACPI_STATUS Status2; + + + ACPI_FUNCTION_TRACE_PTR (PsCompleteOp, WalkState); + + + /* + * Finished one argument of the containing scope + */ + WalkState->ParserState.Scope->ParseScope.ArgCount--; + + /* Close this Op (will result in parse subtree deletion) */ + + Status2 = AcpiPsCompleteThisOp (WalkState, *Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + + *Op = NULL; + + switch (Status) + { + case AE_OK: + + break; + + case AE_CTRL_TRANSFER: + + /* We are about to transfer to a called method */ + + WalkState->PrevOp = NULL; + WalkState->PrevArgTypes = WalkState->ArgTypes; + return_ACPI_STATUS (Status); + + case AE_CTRL_END: + + AcpiPsPopScope (&(WalkState->ParserState), Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + + if (*Op) + { + WalkState->Op = *Op; + WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode); + WalkState->Opcode = (*Op)->Common.AmlOpcode; + + Status = WalkState->AscendingCallback (WalkState); + Status = AcpiPsNextParseState (WalkState, *Op, Status); + + Status2 = AcpiPsCompleteThisOp (WalkState, *Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + } + + Status = AE_OK; + break; + + case AE_CTRL_BREAK: + case AE_CTRL_CONTINUE: + + /* Pop off scopes until we find the While */ + + while (!(*Op) || ((*Op)->Common.AmlOpcode != AML_WHILE_OP)) + { + AcpiPsPopScope (&(WalkState->ParserState), Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + } + + /* Close this iteration of the While loop */ + + WalkState->Op = *Op; + WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode); + WalkState->Opcode = (*Op)->Common.AmlOpcode; + + Status = WalkState->AscendingCallback (WalkState); + Status = AcpiPsNextParseState (WalkState, *Op, Status); + + Status2 = AcpiPsCompleteThisOp (WalkState, *Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + + Status = AE_OK; + break; + + case AE_CTRL_TERMINATE: + + /* Clean up */ + do + { + if (*Op) + { + Status2 = AcpiPsCompleteThisOp (WalkState, *Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + + AcpiUtDeleteGenericState ( + AcpiUtPopGenericState (&WalkState->ControlState)); + } + + AcpiPsPopScope (&(WalkState->ParserState), Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + + } while (*Op); + + return_ACPI_STATUS (AE_OK); + + default: /* All other non-AE_OK status */ + + do + { + if (*Op) + { + Status2 = AcpiPsCompleteThisOp (WalkState, *Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + } + + AcpiPsPopScope (&(WalkState->ParserState), Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + + } while (*Op); + + +#if 0 + /* + * TBD: Cleanup parse ops on error + */ + if (*Op == NULL) + { + AcpiPsPopScope (ParserState, Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + } +#endif + WalkState->PrevOp = NULL; + WalkState->PrevArgTypes = WalkState->ArgTypes; + return_ACPI_STATUS (Status); + } + + /* This scope complete? */ + + if (AcpiPsHasCompletedScope (&(WalkState->ParserState))) + { + AcpiPsPopScope (&(WalkState->ParserState), Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *Op)); + } + else + { + *Op = NULL; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsCompleteFinalOp + * + * PARAMETERS: WalkState - Current state + * Op - Current Op + * Status - Current parse status before complete last + * Op + * + * RETURN: Status + * + * DESCRIPTION: Complete last Op. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsCompleteFinalOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS Status) +{ + ACPI_STATUS Status2; + + + ACPI_FUNCTION_TRACE_PTR (PsCompleteFinalOp, WalkState); + + + /* + * Complete the last Op (if not completed), and clear the scope stack. + * It is easily possible to end an AML "package" with an unbounded number + * of open scopes (such as when several ASL blocks are closed with + * sequential closing braces). We want to terminate each one cleanly. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "AML package complete at Op %p\n", Op)); + do + { + if (Op) + { + if (WalkState->AscendingCallback != NULL) + { + WalkState->Op = Op; + WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + WalkState->Opcode = Op->Common.AmlOpcode; + + Status = WalkState->AscendingCallback (WalkState); + Status = AcpiPsNextParseState (WalkState, Op, Status); + if (Status == AE_CTRL_PENDING) + { + Status = AcpiPsCompleteOp (WalkState, &Op, AE_OK); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + if (Status == AE_CTRL_TERMINATE) + { + Status = AE_OK; + + /* Clean up */ + do + { + if (Op) + { + Status2 = AcpiPsCompleteThisOp (WalkState, Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + } + + AcpiPsPopScope (&(WalkState->ParserState), &Op, + &WalkState->ArgTypes, &WalkState->ArgCount); + + } while (Op); + + return_ACPI_STATUS (Status); + } + + else if (ACPI_FAILURE (Status)) + { + /* First error is most important */ + + (void) AcpiPsCompleteThisOp (WalkState, Op); + return_ACPI_STATUS (Status); + } + } + + Status2 = AcpiPsCompleteThisOp (WalkState, Op); + if (ACPI_FAILURE (Status2)) + { + return_ACPI_STATUS (Status2); + } + } + + AcpiPsPopScope (&(WalkState->ParserState), &Op, &WalkState->ArgTypes, + &WalkState->ArgCount); + + } while (Op); + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/parser/psopcode.c b/third_party/lib/acpica/source/components/parser/psopcode.c new file mode 100644 index 000000000..ec44339b7 --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psopcode.c @@ -0,0 +1,343 @@ +/****************************************************************************** + * + * Module Name: psopcode - Parser/Interpreter opcode information table + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acopcode.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psopcode") + + +/******************************************************************************* + * + * NAME: AcpiGbl_AmlOpInfo + * + * DESCRIPTION: Opcode table. Each entry contains + * The name is a simple ascii string, the operand specifier is an + * ascii string with one letter per operand. The letter specifies + * the operand type. + * + ******************************************************************************/ + +/* + * Summary of opcode types/flags + * + + Opcodes that have associated namespace objects (AML_NSOBJECT flag) + + AML_SCOPE_OP + AML_DEVICE_OP + AML_THERMAL_ZONE_OP + AML_METHOD_OP + AML_POWER_RES_OP + AML_PROCESSOR_OP + AML_FIELD_OP + AML_INDEX_FIELD_OP + AML_BANK_FIELD_OP + AML_NAME_OP + AML_ALIAS_OP + AML_MUTEX_OP + AML_EVENT_OP + AML_REGION_OP + AML_CREATE_FIELD_OP + AML_CREATE_BIT_FIELD_OP + AML_CREATE_BYTE_FIELD_OP + AML_CREATE_WORD_FIELD_OP + AML_CREATE_DWORD_FIELD_OP + AML_CREATE_QWORD_FIELD_OP + AML_INT_NAMEDFIELD_OP + AML_INT_METHODCALL_OP + AML_INT_NAMEPATH_OP + + Opcodes that are "namespace" opcodes (AML_NSOPCODE flag) + + AML_SCOPE_OP + AML_DEVICE_OP + AML_THERMAL_ZONE_OP + AML_METHOD_OP + AML_POWER_RES_OP + AML_PROCESSOR_OP + AML_FIELD_OP + AML_INDEX_FIELD_OP + AML_BANK_FIELD_OP + AML_NAME_OP + AML_ALIAS_OP + AML_MUTEX_OP + AML_EVENT_OP + AML_REGION_OP + AML_INT_NAMEDFIELD_OP + + Opcodes that have an associated namespace node (AML_NSNODE flag) + + AML_SCOPE_OP + AML_DEVICE_OP + AML_THERMAL_ZONE_OP + AML_METHOD_OP + AML_POWER_RES_OP + AML_PROCESSOR_OP + AML_NAME_OP + AML_ALIAS_OP + AML_MUTEX_OP + AML_EVENT_OP + AML_REGION_OP + AML_CREATE_FIELD_OP + AML_CREATE_BIT_FIELD_OP + AML_CREATE_BYTE_FIELD_OP + AML_CREATE_WORD_FIELD_OP + AML_CREATE_DWORD_FIELD_OP + AML_CREATE_QWORD_FIELD_OP + AML_INT_NAMEDFIELD_OP + AML_INT_METHODCALL_OP + AML_INT_NAMEPATH_OP + + Opcodes that define named ACPI objects (AML_NAMED flag) + + AML_SCOPE_OP + AML_DEVICE_OP + AML_THERMAL_ZONE_OP + AML_METHOD_OP + AML_POWER_RES_OP + AML_PROCESSOR_OP + AML_NAME_OP + AML_ALIAS_OP + AML_MUTEX_OP + AML_EVENT_OP + AML_REGION_OP + AML_INT_NAMEDFIELD_OP + + Opcodes that contain executable AML as part of the definition that + must be deferred until needed + + AML_METHOD_OP + AML_VAR_PACKAGE_OP + AML_CREATE_FIELD_OP + AML_CREATE_BIT_FIELD_OP + AML_CREATE_BYTE_FIELD_OP + AML_CREATE_WORD_FIELD_OP + AML_CREATE_DWORD_FIELD_OP + AML_CREATE_QWORD_FIELD_OP + AML_REGION_OP + AML_BUFFER_OP + + Field opcodes + + AML_CREATE_FIELD_OP + AML_FIELD_OP + AML_INDEX_FIELD_OP + AML_BANK_FIELD_OP + + Field "Create" opcodes + + AML_CREATE_FIELD_OP + AML_CREATE_BIT_FIELD_OP + AML_CREATE_BYTE_FIELD_OP + AML_CREATE_WORD_FIELD_OP + AML_CREATE_DWORD_FIELD_OP + AML_CREATE_QWORD_FIELD_OP + + ******************************************************************************/ + + +/* + * Master Opcode information table. A summary of everything we know about each + * opcode, all in one place. + */ +const ACPI_OPCODE_INFO AcpiGbl_AmlOpInfo[AML_NUM_OPCODES] = +{ +/*! [Begin] no source code translation */ +/* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */ + +/* 00 */ ACPI_OP ("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), +/* 01 */ ACPI_OP ("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), +/* 02 */ ACPI_OP ("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 03 */ ACPI_OP ("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 04 */ ACPI_OP ("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 05 */ ACPI_OP ("WordConst", ARGP_WORD_OP, ARGI_WORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 06 */ ACPI_OP ("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 07 */ ACPI_OP ("String", ARGP_STRING_OP, ARGI_STRING_OP, ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 08 */ ACPI_OP ("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 09 */ ACPI_OP ("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, ACPI_TYPE_BUFFER, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), +/* 0A */ ACPI_OP ("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), +/* 0B */ ACPI_OP ("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), +/* 0C */ ACPI_OP ("Local0", ARGP_LOCAL0, ARGI_LOCAL0, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 0D */ ACPI_OP ("Local1", ARGP_LOCAL1, ARGI_LOCAL1, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 0E */ ACPI_OP ("Local2", ARGP_LOCAL2, ARGI_LOCAL2, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 0F */ ACPI_OP ("Local3", ARGP_LOCAL3, ARGI_LOCAL3, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 10 */ ACPI_OP ("Local4", ARGP_LOCAL4, ARGI_LOCAL4, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 11 */ ACPI_OP ("Local5", ARGP_LOCAL5, ARGI_LOCAL5, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 12 */ ACPI_OP ("Local6", ARGP_LOCAL6, ARGI_LOCAL6, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 13 */ ACPI_OP ("Local7", ARGP_LOCAL7, ARGI_LOCAL7, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 14 */ ACPI_OP ("Arg0", ARGP_ARG0, ARGI_ARG0, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 15 */ ACPI_OP ("Arg1", ARGP_ARG1, ARGI_ARG1, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 16 */ ACPI_OP ("Arg2", ARGP_ARG2, ARGI_ARG2, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 17 */ ACPI_OP ("Arg3", ARGP_ARG3, ARGI_ARG3, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 18 */ ACPI_OP ("Arg4", ARGP_ARG4, ARGI_ARG4, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 19 */ ACPI_OP ("Arg5", ARGP_ARG5, ARGI_ARG5, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 1A */ ACPI_OP ("Arg6", ARGP_ARG6, ARGI_ARG6, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 1B */ ACPI_OP ("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 1C */ ACPI_OP ("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), +/* 1D */ ACPI_OP ("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 1E */ ACPI_OP ("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 1F */ ACPI_OP ("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 20 */ ACPI_OP ("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), +/* 21 */ ACPI_OP ("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), +/* 22 */ ACPI_OP ("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 23 */ ACPI_OP ("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_2T_1R, AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), +/* 24 */ ACPI_OP ("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 25 */ ACPI_OP ("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 26 */ ACPI_OP ("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 27 */ ACPI_OP ("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 28 */ ACPI_OP ("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 29 */ ACPI_OP ("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 2A */ ACPI_OP ("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 2B */ ACPI_OP ("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 2C */ ACPI_OP ("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 2D */ ACPI_OP ("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP,ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 2E */ ACPI_OP ("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), +/* 2F */ ACPI_OP ("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), +/* 30 */ ACPI_OP ("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), +/* 31 */ ACPI_OP ("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R), +/* 32 */ ACPI_OP ("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), +/* 33 */ ACPI_OP ("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP,ARGI_CREATE_DWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 34 */ ACPI_OP ("CreateWordField", ARGP_CREATE_WORD_FIELD_OP, ARGI_CREATE_WORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 35 */ ACPI_OP ("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP, ARGI_CREATE_BYTE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 36 */ ACPI_OP ("CreateBitField", ARGP_CREATE_BIT_FIELD_OP, ARGI_CREATE_BIT_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 37 */ ACPI_OP ("ObjectType", ARGP_OBJECT_TYPE_OP, ARGI_OBJECT_TYPE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), +/* 38 */ ACPI_OP ("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), +/* 39 */ ACPI_OP ("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), +/* 3A */ ACPI_OP ("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), +/* 3B */ ACPI_OP ("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3C */ ACPI_OP ("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3D */ ACPI_OP ("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3E */ ACPI_OP ("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 3F */ ACPI_OP ("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 40 */ ACPI_OP ("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 41 */ ACPI_OP ("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 42 */ ACPI_OP ("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 43 */ ACPI_OP ("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 44 */ ACPI_OP ("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 45 */ ACPI_OP ("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + +/* Prefixed opcodes (Two-byte opcodes with a prefix op) */ + +/* 46 */ ACPI_OP ("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 47 */ ACPI_OP ("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ), +/* 48 */ ACPI_OP ("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 49 */ ACPI_OP ("CreateField", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_FIELD | AML_CREATE), +/* 4A */ ACPI_OP ("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, AML_FLAGS_EXEC_1A_1T_0R), +/* 4B */ ACPI_OP ("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 4C */ ACPI_OP ("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 4D */ ACPI_OP ("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), +/* 4E */ ACPI_OP ("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 4F */ ACPI_OP ("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), +/* 50 */ ACPI_OP ("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 51 */ ACPI_OP ("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 52 */ ACPI_OP ("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 53 */ ACPI_OP ("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 54 */ ACPI_OP ("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 55 */ ACPI_OP ("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), +/* 56 */ ACPI_OP ("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), +/* 57 */ ACPI_OP ("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R), +/* 58 */ ACPI_OP ("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP, ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), +/* 59 */ ACPI_OP ("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), +/* 5A */ ACPI_OP ("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5B */ ACPI_OP ("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5C */ ACPI_OP ("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5D */ ACPI_OP ("ThermalZone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5E */ ACPI_OP ("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), +/* 5F */ ACPI_OP ("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD | AML_DEFER), + +/* Internal opcodes that map to invalid AML opcodes */ + +/* 60 */ ACPI_OP ("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), +/* 61 */ ACPI_OP ("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), +/* 62 */ ACPI_OP ("LGreaterEqual", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), +/* 63 */ ACPI_OP ("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE ), +/* 64 */ ACPI_OP ("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, AML_TYPE_METHOD_CALL, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), +/* 65 */ ACPI_OP ("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), +/* 66 */ ACPI_OP ("-ReservedField-", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), +/* 67 */ ACPI_OP ("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ), +/* 68 */ ACPI_OP ("-AccessField-", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), +/* 69 */ ACPI_OP ("-StaticString", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), +/* 6A */ ACPI_OP ("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, AML_HAS_ARGS | AML_HAS_RETVAL), +/* 6B */ ACPI_OP ("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID, AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 6C */ ACPI_OP ("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 6D */ ACPI_OP ("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), + +/* ACPI 2.0 opcodes */ + +/* 6E */ ACPI_OP ("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 6F */ ACPI_OP ("Package", /* Var */ ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER), +/* 70 */ ACPI_OP ("ConcatenateResTemplate", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 71 */ ACPI_OP ("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 72 */ ACPI_OP ("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP,ARGI_CREATE_QWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 73 */ ACPI_OP ("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 74 */ ACPI_OP ("ToDecimalString", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 75 */ ACPI_OP ("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 76 */ ACPI_OP ("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 77 */ ACPI_OP ("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 78 */ ACPI_OP ("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 79 */ ACPI_OP ("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), +/* 7A */ ACPI_OP ("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 7B */ ACPI_OP ("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), +/* 7C */ ACPI_OP ("DataTableRegion", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), +/* 7D */ ACPI_OP ("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE), + +/* ACPI 3.0 opcodes */ + +/* 7E */ ACPI_OP ("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, AML_FLAGS_EXEC_0A_0T_1R), + +/* ACPI 5.0 opcodes */ + +/* 7F */ ACPI_OP ("-ConnectField-", ARGP_CONNECTFIELD_OP, ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 80 */ ACPI_OP ("-ExtAccessField-", ARGP_CONNECTFIELD_OP, ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + +/* ACPI 6.0 opcodes */ + +/* 81 */ ACPI_OP ("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE,/* ? */ AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R) + +/*! [End] no source code translation !*/ +}; diff --git a/third_party/lib/acpica/source/components/parser/psopinfo.c b/third_party/lib/acpica/source/components/parser/psopinfo.c new file mode 100644 index 000000000..28fa0ed29 --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psopinfo.c @@ -0,0 +1,284 @@ +/****************************************************************************** + * + * Module Name: psopinfo - AML opcode information functions and dispatch tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acopcode.h" +#include "amlcode.h" + + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psopinfo") + + +static const UINT8 AcpiGbl_ArgumentCount[] = {0,1,1,1,1,2,2,2,2,3,3,6}; + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetOpcodeInfo + * + * PARAMETERS: Opcode - The AML opcode + * + * RETURN: A pointer to the info about the opcode. + * + * DESCRIPTION: Find AML opcode description based on the opcode. + * NOTE: This procedure must ALWAYS return a valid pointer! + * + ******************************************************************************/ + +const ACPI_OPCODE_INFO * +AcpiPsGetOpcodeInfo ( + UINT16 Opcode) +{ +#ifdef ACPI_DEBUG_OUTPUT + const char *OpcodeName = "Unknown AML opcode"; +#endif + + ACPI_FUNCTION_NAME (PsGetOpcodeInfo); + + + /* + * Detect normal 8-bit opcode or extended 16-bit opcode + */ + if (!(Opcode & 0xFF00)) + { + /* Simple (8-bit) opcode: 0-255, can't index beyond table */ + + return (&AcpiGbl_AmlOpInfo [AcpiGbl_ShortOpIndex [(UINT8) Opcode]]); + } + + if (((Opcode & 0xFF00) == AML_EXTENDED_OPCODE) && + (((UINT8) Opcode) <= MAX_EXTENDED_OPCODE)) + { + /* Valid extended (16-bit) opcode */ + + return (&AcpiGbl_AmlOpInfo [AcpiGbl_LongOpIndex [(UINT8) Opcode]]); + } + +#if defined ACPI_ASL_COMPILER && defined ACPI_DEBUG_OUTPUT +#include "asldefine.h" + + switch (Opcode) + { + case AML_RAW_DATA_BYTE: + OpcodeName = "-Raw Data Byte-"; + break; + + case AML_RAW_DATA_WORD: + OpcodeName = "-Raw Data Word-"; + break; + + case AML_RAW_DATA_DWORD: + OpcodeName = "-Raw Data Dword-"; + break; + + case AML_RAW_DATA_QWORD: + OpcodeName = "-Raw Data Qword-"; + break; + + case AML_RAW_DATA_BUFFER: + OpcodeName = "-Raw Data Buffer-"; + break; + + case AML_RAW_DATA_CHAIN: + OpcodeName = "-Raw Data Buffer Chain-"; + break; + + case AML_PACKAGE_LENGTH: + OpcodeName = "-Package Length-"; + break; + + case AML_UNASSIGNED_OPCODE: + OpcodeName = "-Unassigned Opcode-"; + break; + + case AML_DEFAULT_ARG_OP: + OpcodeName = "-Default Arg-"; + break; + + default: + break; + } +#endif + + /* Unknown AML opcode */ + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s [%4.4X]\n", OpcodeName, Opcode)); + + return (&AcpiGbl_AmlOpInfo [_UNK]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetOpcodeName + * + * PARAMETERS: Opcode - The AML opcode + * + * RETURN: A pointer to the name of the opcode (ASCII String) + * Note: Never returns NULL. + * + * DESCRIPTION: Translate an opcode into a human-readable string + * + ******************************************************************************/ + +char * +AcpiPsGetOpcodeName ( + UINT16 Opcode) +{ +#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT) + + const ACPI_OPCODE_INFO *Op; + + + Op = AcpiPsGetOpcodeInfo (Opcode); + + /* Always guaranteed to return a valid pointer */ + + return (Op->Name); + +#else + return ("OpcodeName unavailable"); + +#endif +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetArgumentCount + * + * PARAMETERS: OpType - Type associated with the AML opcode + * + * RETURN: Argument count + * + * DESCRIPTION: Obtain the number of expected arguments for an AML opcode + * + ******************************************************************************/ + +UINT8 +AcpiPsGetArgumentCount ( + UINT32 OpType) +{ + + if (OpType <= AML_TYPE_EXEC_6A_0T_1R) + { + return (AcpiGbl_ArgumentCount[OpType]); + } + + return (0); +} + + +/* + * This table is directly indexed by the opcodes It returns + * an index into the opcode table (AcpiGbl_AmlOpInfo) + */ +const UINT8 AcpiGbl_ShortOpIndex[256] = +{ +/* 0 1 2 3 4 5 6 7 */ +/* 8 9 A B C D E F */ +/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK, +/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK, +/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, 0x81, _UNK, _UNK, +/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, +/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D, +/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC, +/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, +/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK, +/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, +/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, +/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30, +/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72, +/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74, +/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A, +/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, +/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK, +/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45, +}; + +/* + * This table is indexed by the second opcode of the extended opcode + * pair. It returns an index into the opcode table (AcpiGbl_AmlOpInfo) + */ +const UINT8 AcpiGbl_LongOpIndex[NUM_EXTENDED_OPCODE] = +{ +/* 0 1 2 3 4 5 6 7 */ +/* 8 9 A B C D E F */ +/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK, +/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B, +/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, +/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK, +/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, +/* 0x88 */ 0x7C, +}; diff --git a/third_party/lib/acpica/source/components/parser/psparse.c b/third_party/lib/acpica/source/components/parser/psparse.c new file mode 100644 index 000000000..810d97e0e --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psparse.c @@ -0,0 +1,710 @@ +/****************************************************************************** + * + * Module Name: psparse - Parser top level AML parse routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Parse the AML and build an operation tree as most interpreters, + * like Perl, do. Parsing is done by hand rather than with a YACC + * generated parser to tightly constrain stack and dynamic memory + * usage. At the same time, parsing is kept flexible and the code + * fairly compact by parsing based on a list of AML opcode + * templates in AmlOpInfo[] + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "amlcode.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psparse") + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetOpcodeSize + * + * PARAMETERS: Opcode - An AML opcode + * + * RETURN: Size of the opcode, in bytes (1 or 2) + * + * DESCRIPTION: Get the size of the current opcode. + * + ******************************************************************************/ + +UINT32 +AcpiPsGetOpcodeSize ( + UINT32 Opcode) +{ + + /* Extended (2-byte) opcode if > 255 */ + + if (Opcode > 0x00FF) + { + return (2); + } + + /* Otherwise, just a single byte opcode */ + + return (1); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsPeekOpcode + * + * PARAMETERS: ParserState - A parser state object + * + * RETURN: Next AML opcode + * + * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) + * + ******************************************************************************/ + +UINT16 +AcpiPsPeekOpcode ( + ACPI_PARSE_STATE *ParserState) +{ + UINT8 *Aml; + UINT16 Opcode; + + + Aml = ParserState->Aml; + Opcode = (UINT16) ACPI_GET8 (Aml); + + if (Opcode == AML_EXTENDED_OP_PREFIX) + { + /* Extended opcode, get the second opcode byte */ + + Aml++; + Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml)); + } + + return (Opcode); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsCompleteThisOp + * + * PARAMETERS: WalkState - Current State + * Op - Op to complete + * + * RETURN: Status + * + * DESCRIPTION: Perform any cleanup at the completion of an Op. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsCompleteThisOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Prev; + ACPI_PARSE_OBJECT *Next; + const ACPI_OPCODE_INFO *ParentInfo; + ACPI_PARSE_OBJECT *ReplacementOp = NULL; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op); + + + /* Check for null Op, can happen if AML code is corrupt */ + + if (!Op) + { + return_ACPI_STATUS (AE_OK); /* OK for now */ + } + + AcpiExStopTraceOpcode (Op, WalkState); + + /* Delete this op and the subtree below it if asked to */ + + if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || + (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT)) + { + return_ACPI_STATUS (AE_OK); + } + + /* Make sure that we only delete this subtree */ + + if (Op->Common.Parent) + { + Prev = Op->Common.Parent->Common.Value.Arg; + if (!Prev) + { + /* Nothing more to do */ + + goto Cleanup; + } + + /* + * Check if we need to replace the operator and its subtree + * with a return value op (placeholder op) + */ + ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); + + switch (ParentInfo->Class) + { + case AML_CLASS_CONTROL: + + break; + + case AML_CLASS_CREATE: + /* + * These opcodes contain TermArg operands. The current + * op must be replaced by a placeholder return op + */ + ReplacementOp = AcpiPsAllocOp ( + AML_INT_RETURN_VALUE_OP, Op->Common.Aml); + if (!ReplacementOp) + { + Status = AE_NO_MEMORY; + } + break; + + case AML_CLASS_NAMED_OBJECT: + /* + * These opcodes contain TermArg operands. The current + * op must be replaced by a placeholder return op + */ + if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP) || + (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) + { + ReplacementOp = AcpiPsAllocOp ( + AML_INT_RETURN_VALUE_OP, Op->Common.Aml); + if (!ReplacementOp) + { + Status = AE_NO_MEMORY; + } + } + else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && + (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) + { + if ((Op->Common.AmlOpcode == AML_BUFFER_OP) || + (Op->Common.AmlOpcode == AML_PACKAGE_OP) || + (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) + { + ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode, + Op->Common.Aml); + if (!ReplacementOp) + { + Status = AE_NO_MEMORY; + } + else + { + ReplacementOp->Named.Data = Op->Named.Data; + ReplacementOp->Named.Length = Op->Named.Length; + } + } + } + break; + + default: + + ReplacementOp = AcpiPsAllocOp ( + AML_INT_RETURN_VALUE_OP, Op->Common.Aml); + if (!ReplacementOp) + { + Status = AE_NO_MEMORY; + } + } + + /* We must unlink this op from the parent tree */ + + if (Prev == Op) + { + /* This op is the first in the list */ + + if (ReplacementOp) + { + ReplacementOp->Common.Parent = Op->Common.Parent; + ReplacementOp->Common.Value.Arg = NULL; + ReplacementOp->Common.Node = Op->Common.Node; + Op->Common.Parent->Common.Value.Arg = ReplacementOp; + ReplacementOp->Common.Next = Op->Common.Next; + } + else + { + Op->Common.Parent->Common.Value.Arg = Op->Common.Next; + } + } + + /* Search the parent list */ + + else while (Prev) + { + /* Traverse all siblings in the parent's argument list */ + + Next = Prev->Common.Next; + if (Next == Op) + { + if (ReplacementOp) + { + ReplacementOp->Common.Parent = Op->Common.Parent; + ReplacementOp->Common.Value.Arg = NULL; + ReplacementOp->Common.Node = Op->Common.Node; + Prev->Common.Next = ReplacementOp; + ReplacementOp->Common.Next = Op->Common.Next; + Next = NULL; + } + else + { + Prev->Common.Next = Op->Common.Next; + Next = NULL; + } + } + Prev = Next; + } + } + + +Cleanup: + + /* Now we can actually delete the subtree rooted at Op */ + + AcpiPsDeleteParseTree (Op); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsNextParseState + * + * PARAMETERS: WalkState - Current state + * Op - Current parse op + * CallbackStatus - Status from previous operation + * + * RETURN: Status + * + * DESCRIPTION: Update the parser state based upon the return exception from + * the parser callback. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsNextParseState ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS CallbackStatus) +{ + ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; + ACPI_STATUS Status = AE_CTRL_PENDING; + + + ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op); + + + switch (CallbackStatus) + { + case AE_CTRL_TERMINATE: + /* + * A control method was terminated via a RETURN statement. + * The walk of this method is complete. + */ + ParserState->Aml = ParserState->AmlEnd; + Status = AE_CTRL_TERMINATE; + break; + + case AE_CTRL_BREAK: + + ParserState->Aml = WalkState->AmlLastWhile; + WalkState->ControlState->Common.Value = FALSE; + Status = AE_CTRL_BREAK; + break; + + case AE_CTRL_CONTINUE: + + ParserState->Aml = WalkState->AmlLastWhile; + Status = AE_CTRL_CONTINUE; + break; + + case AE_CTRL_PENDING: + + ParserState->Aml = WalkState->AmlLastWhile; + break; + +#if 0 + case AE_CTRL_SKIP: + + ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; + Status = AE_OK; + break; +#endif + + case AE_CTRL_TRUE: + /* + * Predicate of an IF was true, and we are at the matching ELSE. + * Just close out this package + */ + ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState); + Status = AE_CTRL_PENDING; + break; + + case AE_CTRL_FALSE: + /* + * Either an IF/WHILE Predicate was false or we encountered a BREAK + * opcode. In both cases, we do not execute the rest of the + * package; We simply close out the parent (finishing the walk of + * this branch of the tree) and continue execution at the parent + * level. + */ + ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; + + /* In the case of a BREAK, just force a predicate (if any) to FALSE */ + + WalkState->ControlState->Common.Value = FALSE; + Status = AE_CTRL_END; + break; + + case AE_CTRL_TRANSFER: + + /* A method call (invocation) -- transfer control */ + + Status = AE_CTRL_TRANSFER; + WalkState->PrevOp = Op; + WalkState->MethodCallOp = Op; + WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node; + + /* Will return value (if any) be used by the caller? */ + + WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState); + break; + + default: + + Status = CallbackStatus; + if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL) + { + Status = AE_OK; + } + break; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsParseAml + * + * PARAMETERS: WalkState - Current state + * + * + * RETURN: Status + * + * DESCRIPTION: Parse raw AML and return a tree of ops + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsParseAml ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status; + ACPI_THREAD_STATE *Thread; + ACPI_THREAD_STATE *PrevWalkList = AcpiGbl_CurrentWalkList; + ACPI_WALK_STATE *PreviousWalkState; + + + ACPI_FUNCTION_TRACE (PsParseAml); + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Entered with WalkState=%p Aml=%p size=%X\n", + WalkState, WalkState->ParserState.Aml, + WalkState->ParserState.AmlSize)); + + if (!WalkState->ParserState.Aml) + { + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Create and initialize a new thread state */ + + Thread = AcpiUtCreateThreadState (); + if (!Thread) + { + if (WalkState->MethodDesc) + { + /* Executing a control method - additional cleanup */ + + AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); + } + + AcpiDsDeleteWalkState (WalkState); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + WalkState->Thread = Thread; + + /* + * If executing a method, the starting SyncLevel is this method's + * SyncLevel + */ + if (WalkState->MethodDesc) + { + WalkState->Thread->CurrentSyncLevel = + WalkState->MethodDesc->Method.SyncLevel; + } + + AcpiDsPushWalkState (WalkState, Thread); + + /* + * This global allows the AML debugger to get a handle to the currently + * executing control method. + */ + AcpiGbl_CurrentWalkList = Thread; + + /* + * Execute the walk loop as long as there is a valid Walk State. This + * handles nested control method invocations without recursion. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState)); + + Status = AE_OK; + while (WalkState) + { + if (ACPI_SUCCESS (Status)) + { + /* + * The ParseLoop executes AML until the method terminates + * or calls another method. + */ + Status = AcpiPsParseLoop (WalkState); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Completed one call to walk loop, %s State=%p\n", + AcpiFormatException (Status), WalkState)); + + if (Status == AE_CTRL_TRANSFER) + { + /* + * A method call was detected. + * Transfer control to the called control method + */ + Status = AcpiDsCallControlMethod (Thread, WalkState, NULL); + if (ACPI_FAILURE (Status)) + { + Status = AcpiDsMethodError (Status, WalkState); + } + + /* + * If the transfer to the new method method call worked + *, a new walk state was created -- get it + */ + WalkState = AcpiDsGetCurrentWalkState (Thread); + continue; + } + else if (Status == AE_CTRL_TERMINATE) + { + Status = AE_OK; + } + else if ((Status != AE_OK) && (WalkState->MethodDesc)) + { + /* Either the method parse or actual execution failed */ + + ACPI_ERROR_METHOD ("Method parse/execution failed", + WalkState->MethodNode, NULL, Status); + + /* Check for possible multi-thread reentrancy problem */ + + if ((Status == AE_ALREADY_EXISTS) && + (!(WalkState->MethodDesc->Method.InfoFlags & + ACPI_METHOD_SERIALIZED))) + { + /* + * Method is not serialized and tried to create an object + * twice. The probable cause is that the method cannot + * handle reentrancy. Mark as "pending serialized" now, and + * then mark "serialized" when the last thread exits. + */ + WalkState->MethodDesc->Method.InfoFlags |= + ACPI_METHOD_SERIALIZED_PENDING; + } + } + + /* We are done with this walk, move on to the parent if any */ + + WalkState = AcpiDsPopWalkState (Thread); + + /* Reset the current scope to the beginning of scope stack */ + + AcpiDsScopeStackClear (WalkState); + + /* + * If we just returned from the execution of a control method or if we + * encountered an error during the method parse phase, there's lots of + * cleanup to do + */ + if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == + ACPI_PARSE_EXECUTE) || + (ACPI_FAILURE (Status))) + { + AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); + } + + /* Delete this walk state and all linked control states */ + + AcpiPsCleanupScope (&WalkState->ParserState); + PreviousWalkState = WalkState; + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "ReturnValue=%p, ImplicitValue=%p State=%p\n", + WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState)); + + /* Check if we have restarted a preempted walk */ + + WalkState = AcpiDsGetCurrentWalkState (Thread); + if (WalkState) + { + if (ACPI_SUCCESS (Status)) + { + /* + * There is another walk state, restart it. + * If the method return value is not used by the parent, + * The object is deleted + */ + if (!PreviousWalkState->ReturnDesc) + { + /* + * In slack mode execution, if there is no return value + * we should implicitly return zero (0) as a default value. + */ + if (AcpiGbl_EnableInterpreterSlack && + !PreviousWalkState->ImplicitReturnObj) + { + PreviousWalkState->ImplicitReturnObj = + AcpiUtCreateIntegerObject ((UINT64) 0); + if (!PreviousWalkState->ImplicitReturnObj) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + + /* Restart the calling control method */ + + Status = AcpiDsRestartControlMethod (WalkState, + PreviousWalkState->ImplicitReturnObj); + } + else + { + /* + * We have a valid return value, delete any implicit + * return value. + */ + AcpiDsClearImplicitReturn (PreviousWalkState); + + Status = AcpiDsRestartControlMethod (WalkState, + PreviousWalkState->ReturnDesc); + } + if (ACPI_SUCCESS (Status)) + { + WalkState->WalkType |= ACPI_WALK_METHOD_RESTART; + } + } + else + { + /* On error, delete any return object or implicit return */ + + AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); + AcpiDsClearImplicitReturn (PreviousWalkState); + } + } + + /* + * Just completed a 1st-level method, save the final internal return + * value (if any) + */ + else if (PreviousWalkState->CallerReturnDesc) + { + if (PreviousWalkState->ImplicitReturnObj) + { + *(PreviousWalkState->CallerReturnDesc) = + PreviousWalkState->ImplicitReturnObj; + } + else + { + /* NULL if no return value */ + + *(PreviousWalkState->CallerReturnDesc) = + PreviousWalkState->ReturnDesc; + } + } + else + { + if (PreviousWalkState->ReturnDesc) + { + /* Caller doesn't want it, must delete it */ + + AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); + } + if (PreviousWalkState->ImplicitReturnObj) + { + /* Caller doesn't want it, must delete it */ + + AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj); + } + } + + AcpiDsDeleteWalkState (PreviousWalkState); + } + + /* Normal exit */ + + AcpiExReleaseAllMutexes (Thread); + AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread)); + AcpiGbl_CurrentWalkList = PrevWalkList; + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/parser/psscope.c b/third_party/lib/acpica/source/components/parser/psscope.c new file mode 100644 index 000000000..f5b89d0f5 --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psscope.c @@ -0,0 +1,300 @@ +/****************************************************************************** + * + * Module Name: psscope - Parser scope stack management routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psscope") + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetParentScope + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: Pointer to an Op object + * + * DESCRIPTION: Get parent of current op being parsed + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +AcpiPsGetParentScope ( + ACPI_PARSE_STATE *ParserState) +{ + + return (ParserState->Scope->ParseScope.Op); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsHasCompletedScope + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: Boolean, TRUE = scope completed. + * + * DESCRIPTION: Is parsing of current argument complete? Determined by + * 1) AML pointer is at or beyond the end of the scope + * 2) The scope argument count has reached zero. + * + ******************************************************************************/ + +BOOLEAN +AcpiPsHasCompletedScope ( + ACPI_PARSE_STATE *ParserState) +{ + + return ((BOOLEAN) + ((ParserState->Aml >= ParserState->Scope->ParseScope.ArgEnd || + !ParserState->Scope->ParseScope.ArgCount))); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsInitScope + * + * PARAMETERS: ParserState - Current parser state object + * Root - the Root Node of this new scope + * + * RETURN: Status + * + * DESCRIPTION: Allocate and init a new scope object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsInitScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *RootOp) +{ + ACPI_GENERIC_STATE *Scope; + + + ACPI_FUNCTION_TRACE_PTR (PsInitScope, RootOp); + + + Scope = AcpiUtCreateGenericState (); + if (!Scope) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Scope->Common.DescriptorType = ACPI_DESC_TYPE_STATE_RPSCOPE; + Scope->ParseScope.Op = RootOp; + Scope->ParseScope.ArgCount = ACPI_VAR_ARGS; + Scope->ParseScope.ArgEnd = ParserState->AmlEnd; + Scope->ParseScope.PkgEnd = ParserState->AmlEnd; + + ParserState->Scope = Scope; + ParserState->StartOp = RootOp; + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsPushScope + * + * PARAMETERS: ParserState - Current parser state object + * Op - Current op to be pushed + * RemainingArgs - List of args remaining + * ArgCount - Fixed or variable number of args + * + * RETURN: Status + * + * DESCRIPTION: Push current op to begin parsing its argument + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsPushScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Op, + UINT32 RemainingArgs, + UINT32 ArgCount) +{ + ACPI_GENERIC_STATE *Scope; + + + ACPI_FUNCTION_TRACE_PTR (PsPushScope, Op); + + + Scope = AcpiUtCreateGenericState (); + if (!Scope) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Scope->Common.DescriptorType = ACPI_DESC_TYPE_STATE_PSCOPE; + Scope->ParseScope.Op = Op; + Scope->ParseScope.ArgList = RemainingArgs; + Scope->ParseScope.ArgCount = ArgCount; + Scope->ParseScope.PkgEnd = ParserState->PkgEnd; + + /* Push onto scope stack */ + + AcpiUtPushGenericState (&ParserState->Scope, Scope); + + if (ArgCount == ACPI_VAR_ARGS) + { + /* Multiple arguments */ + + Scope->ParseScope.ArgEnd = ParserState->PkgEnd; + } + else + { + /* Single argument */ + + Scope->ParseScope.ArgEnd = ACPI_TO_POINTER (ACPI_MAX_PTR); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsPopScope + * + * PARAMETERS: ParserState - Current parser state object + * Op - Where the popped op is returned + * ArgList - Where the popped "next argument" is + * returned + * ArgCount - Count of objects in ArgList + * + * RETURN: Status + * + * DESCRIPTION: Return to parsing a previous op + * + ******************************************************************************/ + +void +AcpiPsPopScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT **Op, + UINT32 *ArgList, + UINT32 *ArgCount) +{ + ACPI_GENERIC_STATE *Scope = ParserState->Scope; + + + ACPI_FUNCTION_TRACE (PsPopScope); + + + /* Only pop the scope if there is in fact a next scope */ + + if (Scope->Common.Next) + { + Scope = AcpiUtPopGenericState (&ParserState->Scope); + + /* Return to parsing previous op */ + + *Op = Scope->ParseScope.Op; + *ArgList = Scope->ParseScope.ArgList; + *ArgCount = Scope->ParseScope.ArgCount; + ParserState->PkgEnd = Scope->ParseScope.PkgEnd; + + /* All done with this scope state structure */ + + AcpiUtDeleteGenericState (Scope); + } + else + { + /* Empty parse stack, prepare to fetch next opcode */ + + *Op = NULL; + *ArgList = 0; + *ArgCount = 0; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Popped Op %p Args %X\n", *Op, *ArgCount)); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsCleanupScope + * + * PARAMETERS: ParserState - Current parser state object + * + * RETURN: None + * + * DESCRIPTION: Destroy available list, remaining stack levels, and return + * root scope + * + ******************************************************************************/ + +void +AcpiPsCleanupScope ( + ACPI_PARSE_STATE *ParserState) +{ + ACPI_GENERIC_STATE *Scope; + + + ACPI_FUNCTION_TRACE_PTR (PsCleanupScope, ParserState); + + + if (!ParserState) + { + return_VOID; + } + + /* Delete anything on the scope stack */ + + while (ParserState->Scope) + { + Scope = AcpiUtPopGenericState (&ParserState->Scope); + AcpiUtDeleteGenericState (Scope); + } + + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/parser/pstree.c b/third_party/lib/acpica/source/components/parser/pstree.c new file mode 100644 index 000000000..729856982 --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/pstree.c @@ -0,0 +1,353 @@ +/****************************************************************************** + * + * Module Name: pstree - Parser op tree manipulation/traversal/search + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("pstree") + +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +ACPI_PARSE_OBJECT * +AcpiPsGetChild ( + ACPI_PARSE_OBJECT *op); +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetArg + * + * PARAMETERS: Op - Get an argument for this op + * Argn - Nth argument to get + * + * RETURN: The argument (as an Op object). NULL if argument does not exist + * + * DESCRIPTION: Get the specified op's argument. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +AcpiPsGetArg ( + ACPI_PARSE_OBJECT *Op, + UINT32 Argn) +{ + ACPI_PARSE_OBJECT *Arg = NULL; + const ACPI_OPCODE_INFO *OpInfo; + + + ACPI_FUNCTION_ENTRY (); + +/* + if (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP) + { + return (Op->Common.Value.Arg); + } +*/ + /* Get the info structure for this opcode */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (OpInfo->Class == AML_CLASS_UNKNOWN) + { + /* Invalid opcode or ASCII character */ + + return (NULL); + } + + /* Check if this opcode requires argument sub-objects */ + + if (!(OpInfo->Flags & AML_HAS_ARGS)) + { + /* Has no linked argument objects */ + + return (NULL); + } + + /* Get the requested argument object */ + + Arg = Op->Common.Value.Arg; + while (Arg && Argn) + { + Argn--; + Arg = Arg->Common.Next; + } + + return (Arg); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsAppendArg + * + * PARAMETERS: Op - Append an argument to this Op. + * Arg - Argument Op to append + * + * RETURN: None. + * + * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK) + * + ******************************************************************************/ + +void +AcpiPsAppendArg ( + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_OBJECT *Arg) +{ + ACPI_PARSE_OBJECT *PrevArg; + const ACPI_OPCODE_INFO *OpInfo; + + + ACPI_FUNCTION_ENTRY (); + + + if (!Op) + { + return; + } + + /* Get the info structure for this opcode */ + + OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); + if (OpInfo->Class == AML_CLASS_UNKNOWN) + { + /* Invalid opcode */ + + ACPI_ERROR ((AE_INFO, "Invalid AML Opcode: 0x%2.2X", + Op->Common.AmlOpcode)); + return; + } + + /* Check if this opcode requires argument sub-objects */ + + if (!(OpInfo->Flags & AML_HAS_ARGS)) + { + /* Has no linked argument objects */ + + return; + } + + /* Append the argument to the linked argument list */ + + if (Op->Common.Value.Arg) + { + /* Append to existing argument list */ + + PrevArg = Op->Common.Value.Arg; + while (PrevArg->Common.Next) + { + PrevArg = PrevArg->Common.Next; + } + PrevArg->Common.Next = Arg; + } + else + { + /* No argument list, this will be the first argument */ + + Op->Common.Value.Arg = Arg; + } + + /* Set the parent in this arg and any args linked after it */ + + while (Arg) + { + Arg->Common.Parent = Op; + Arg = Arg->Common.Next; + + Op->Common.ArgListLength++; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsGetDepthNext + * + * PARAMETERS: Origin - Root of subtree to search + * Op - Last (previous) Op that was found + * + * RETURN: Next Op found in the search. + * + * DESCRIPTION: Get next op in tree (walking the tree in depth-first order) + * Return NULL when reaching "origin" or when walking up from root + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +AcpiPsGetDepthNext ( + ACPI_PARSE_OBJECT *Origin, + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Next = NULL; + ACPI_PARSE_OBJECT *Parent; + ACPI_PARSE_OBJECT *Arg; + + + ACPI_FUNCTION_ENTRY (); + + + if (!Op) + { + return (NULL); + } + + /* Look for an argument or child */ + + Next = AcpiPsGetArg (Op, 0); + if (Next) + { + return (Next); + } + + /* Look for a sibling */ + + Next = Op->Common.Next; + if (Next) + { + return (Next); + } + + /* Look for a sibling of parent */ + + Parent = Op->Common.Parent; + + while (Parent) + { + Arg = AcpiPsGetArg (Parent, 0); + while (Arg && (Arg != Origin) && (Arg != Op)) + { + Arg = Arg->Common.Next; + } + + if (Arg == Origin) + { + /* Reached parent of origin, end search */ + + return (NULL); + } + + if (Parent->Common.Next) + { + /* Found sibling of parent */ + + return (Parent->Common.Next); + } + + Op = Parent; + Parent = Parent->Common.Parent; + } + + return (Next); +} + + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: AcpiPsGetChild + * + * PARAMETERS: Op - Get the child of this Op + * + * RETURN: Child Op, Null if none is found. + * + * DESCRIPTION: Get op's children or NULL if none + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +AcpiPsGetChild ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_PARSE_OBJECT *Child = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + switch (Op->Common.AmlOpcode) + { + case AML_SCOPE_OP: + case AML_ELSE_OP: + case AML_DEVICE_OP: + case AML_THERMAL_ZONE_OP: + case AML_INT_METHODCALL_OP: + + Child = AcpiPsGetArg (Op, 0); + break; + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_METHOD_OP: + case AML_IF_OP: + case AML_WHILE_OP: + case AML_FIELD_OP: + + Child = AcpiPsGetArg (Op, 1); + break; + + case AML_POWER_RES_OP: + case AML_INDEX_FIELD_OP: + + Child = AcpiPsGetArg (Op, 2); + break; + + case AML_PROCESSOR_OP: + case AML_BANK_FIELD_OP: + + Child = AcpiPsGetArg (Op, 3); + break; + + default: + + /* All others have no children */ + + break; + } + + return (Child); +} +#endif diff --git a/third_party/lib/acpica/source/components/parser/psutils.c b/third_party/lib/acpica/source/components/parser/psutils.c new file mode 100644 index 000000000..29cac85af --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psutils.c @@ -0,0 +1,281 @@ +/****************************************************************************** + * + * Module Name: psutils - Parser miscellaneous utilities (Parser only) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psutils") + + +/******************************************************************************* + * + * FUNCTION: AcpiPsCreateScopeOp + * + * PARAMETERS: None + * + * RETURN: A new Scope object, null on failure + * + * DESCRIPTION: Create a Scope and associated namepath op with the root name + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +AcpiPsCreateScopeOp ( + UINT8 *Aml) +{ + ACPI_PARSE_OBJECT *ScopeOp; + + + ScopeOp = AcpiPsAllocOp (AML_SCOPE_OP, Aml); + if (!ScopeOp) + { + return (NULL); + } + + ScopeOp->Named.Name = ACPI_ROOT_NAME; + return (ScopeOp); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsInitOp + * + * PARAMETERS: Op - A newly allocated Op object + * Opcode - Opcode to store in the Op + * + * RETURN: None + * + * DESCRIPTION: Initialize a parse (Op) object + * + ******************************************************************************/ + +void +AcpiPsInitOp ( + ACPI_PARSE_OBJECT *Op, + UINT16 Opcode) +{ + ACPI_FUNCTION_ENTRY (); + + + Op->Common.DescriptorType = ACPI_DESC_TYPE_PARSER; + Op->Common.AmlOpcode = Opcode; + + ACPI_DISASM_ONLY_MEMBERS (strncpy (Op->Common.AmlOpName, + (AcpiPsGetOpcodeInfo (Opcode))->Name, + sizeof (Op->Common.AmlOpName))); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsAllocOp + * + * PARAMETERS: Opcode - Opcode that will be stored in the new Op + * Aml - Address of the opcode + * + * RETURN: Pointer to the new Op, null on failure + * + * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on + * opcode. A cache of opcodes is available for the pure + * GENERIC_OP, since this is by far the most commonly used. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT* +AcpiPsAllocOp ( + UINT16 Opcode, + UINT8 *Aml) +{ + ACPI_PARSE_OBJECT *Op; + const ACPI_OPCODE_INFO *OpInfo; + UINT8 Flags = ACPI_PARSEOP_GENERIC; + + + ACPI_FUNCTION_ENTRY (); + + + OpInfo = AcpiPsGetOpcodeInfo (Opcode); + + /* Determine type of ParseOp required */ + + if (OpInfo->Flags & AML_DEFER) + { + Flags = ACPI_PARSEOP_DEFERRED; + } + else if (OpInfo->Flags & AML_NAMED) + { + Flags = ACPI_PARSEOP_NAMED; + } + else if (Opcode == AML_INT_BYTELIST_OP) + { + Flags = ACPI_PARSEOP_BYTELIST; + } + + /* Allocate the minimum required size object */ + + if (Flags == ACPI_PARSEOP_GENERIC) + { + /* The generic op (default) is by far the most common (16 to 1) */ + + Op = AcpiOsAcquireObject (AcpiGbl_PsNodeCache); + } + else + { + /* Extended parseop */ + + Op = AcpiOsAcquireObject (AcpiGbl_PsNodeExtCache); + } + + /* Initialize the Op */ + + if (Op) + { + AcpiPsInitOp (Op, Opcode); + Op->Common.Aml = Aml; + Op->Common.Flags = Flags; + } + + return (Op); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsFreeOp + * + * PARAMETERS: Op - Op to be freed + * + * RETURN: None. + * + * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list + * or actually free it. + * + ******************************************************************************/ + +void +AcpiPsFreeOp ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_FUNCTION_NAME (PsFreeOp); + + + if (Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) + { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Free retval op: %p\n", Op)); + } + + if (Op->Common.Flags & ACPI_PARSEOP_GENERIC) + { + (void) AcpiOsReleaseObject (AcpiGbl_PsNodeCache, Op); + } + else + { + (void) AcpiOsReleaseObject (AcpiGbl_PsNodeExtCache, Op); + } +} + + +/******************************************************************************* + * + * FUNCTION: Utility functions + * + * DESCRIPTION: Low level character and object functions + * + ******************************************************************************/ + + +/* + * Is "c" a namestring lead character? + */ +BOOLEAN +AcpiPsIsLeadingChar ( + UINT32 c) +{ + return ((BOOLEAN) (c == '_' || (c >= 'A' && c <= 'Z'))); +} + + +/* + * Get op's name (4-byte name segment) or 0 if unnamed + */ +UINT32 +AcpiPsGetName ( + ACPI_PARSE_OBJECT *Op) +{ + + /* The "generic" object has no name associated with it */ + + if (Op->Common.Flags & ACPI_PARSEOP_GENERIC) + { + return (0); + } + + /* Only the "Extended" parse objects have a name */ + + return (Op->Named.Name); +} + + +/* + * Set op's name + */ +void +AcpiPsSetName ( + ACPI_PARSE_OBJECT *Op, + UINT32 name) +{ + + /* The "generic" object has no name associated with it */ + + if (Op->Common.Flags & ACPI_PARSEOP_GENERIC) + { + return; + } + + Op->Named.Name = name; +} diff --git a/third_party/lib/acpica/source/components/parser/pswalk.c b/third_party/lib/acpica/source/components/parser/pswalk.c new file mode 100644 index 000000000..fb6071ade --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/pswalk.c @@ -0,0 +1,121 @@ +/****************************************************************************** + * + * Module Name: pswalk - Parser routines to walk parsed op tree(s) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("pswalk") + + +/******************************************************************************* + * + * FUNCTION: AcpiPsDeleteParseTree + * + * PARAMETERS: SubtreeRoot - Root of tree (or subtree) to delete + * + * RETURN: None + * + * DESCRIPTION: Delete a portion of or an entire parse tree. + * + ******************************************************************************/ + +void +AcpiPsDeleteParseTree ( + ACPI_PARSE_OBJECT *SubtreeRoot) +{ + ACPI_PARSE_OBJECT *Op = SubtreeRoot; + ACPI_PARSE_OBJECT *Next = NULL; + ACPI_PARSE_OBJECT *Parent = NULL; + + + ACPI_FUNCTION_TRACE_PTR (PsDeleteParseTree, SubtreeRoot); + + + /* Visit all nodes in the subtree */ + + while (Op) + { + /* Check if we are not ascending */ + + if (Op != Parent) + { + /* Look for an argument or child of the current op */ + + Next = AcpiPsGetArg (Op, 0); + if (Next) + { + /* Still going downward in tree (Op is not completed yet) */ + + Op = Next; + continue; + } + } + + /* No more children, this Op is complete. */ + + Next = Op->Common.Next; + Parent = Op->Common.Parent; + + AcpiPsFreeOp (Op); + + /* If we are back to the starting point, the walk is complete. */ + + if (Op == SubtreeRoot) + { + return_VOID; + } + + if (Next) + { + Op = Next; + } + else + { + Op = Parent; + } + } + + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/parser/psxface.c b/third_party/lib/acpica/source/components/parser/psxface.c new file mode 100644 index 000000000..a6fe31648 --- /dev/null +++ b/third_party/lib/acpica/source/components/parser/psxface.c @@ -0,0 +1,310 @@ +/****************************************************************************** + * + * Module Name: psxface - Parser external interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "actables.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_PARSER + ACPI_MODULE_NAME ("psxface") + +/* Local Prototypes */ + +static void +AcpiPsUpdateParameterList ( + ACPI_EVALUATE_INFO *Info, + UINT16 Action); + + +/******************************************************************************* + * + * FUNCTION: AcpiDebugTrace + * + * PARAMETERS: MethodName - Valid ACPI name string + * DebugLevel - Optional level mask. 0 to use default + * DebugLayer - Optional layer mask. 0 to use default + * Flags - bit 1: one shot(1) or persistent(0) + * + * RETURN: Status + * + * DESCRIPTION: External interface to enable debug tracing during control + * method execution + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDebugTrace ( + const char *Name, + UINT32 DebugLevel, + UINT32 DebugLayer, + UINT32 Flags) +{ + ACPI_STATUS Status; + + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + AcpiGbl_TraceMethodName = Name; + AcpiGbl_TraceFlags = Flags; + AcpiGbl_TraceDbgLevel = DebugLevel; + AcpiGbl_TraceDbgLayer = DebugLayer; + Status = AE_OK; + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsExecuteMethod + * + * PARAMETERS: Info - Method info block, contains: + * Node - Method Node to execute + * ObjDesc - Method object + * Parameters - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * ReturnObject - Where to put method's return value (if + * any). If NULL, no value is returned. + * ParameterType - Type of Parameter list + * ReturnObject - Where to put method's return value (if + * any). If NULL, no value is returned. + * PassNumber - Parse or execute pass + * + * RETURN: Status + * + * DESCRIPTION: Execute a control method + * + ******************************************************************************/ + +ACPI_STATUS +AcpiPsExecuteMethod ( + ACPI_EVALUATE_INFO *Info) +{ + ACPI_STATUS Status; + ACPI_PARSE_OBJECT *Op; + ACPI_WALK_STATE *WalkState; + + + ACPI_FUNCTION_TRACE (PsExecuteMethod); + + + /* Quick validation of DSDT header */ + + AcpiTbCheckDsdtHeader (); + + /* Validate the Info and method Node */ + + if (!Info || !Info->Node) + { + return_ACPI_STATUS (AE_NULL_ENTRY); + } + + /* Init for new method, wait on concurrency semaphore */ + + Status = AcpiDsBeginMethodExecution (Info->Node, Info->ObjDesc, NULL); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * The caller "owns" the parameters, so give each one an extra reference + */ + AcpiPsUpdateParameterList (Info, REF_INCREMENT); + + /* + * Execute the method. Performs parse simultaneously + */ + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n", + Info->Node->Name.Ascii, Info->Node, Info->ObjDesc)); + + /* Create and init a Root Node */ + + Op = AcpiPsCreateScopeOp (Info->ObjDesc->Method.AmlStart); + if (!Op) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Create and initialize a new walk state */ + + Info->PassNumber = ACPI_IMODE_EXECUTE; + WalkState = AcpiDsCreateWalkState ( + Info->ObjDesc->Method.OwnerId, NULL, NULL, NULL); + if (!WalkState) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + Status = AcpiDsInitAmlWalk (WalkState, Op, Info->Node, + Info->ObjDesc->Method.AmlStart, + Info->ObjDesc->Method.AmlLength, Info, Info->PassNumber); + if (ACPI_FAILURE (Status)) + { + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + + if (Info->ObjDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) + { + WalkState->ParseFlags |= ACPI_PARSE_MODULE_LEVEL; + } + + /* Invoke an internal method if necessary */ + + if (Info->ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) + { + Status = Info->ObjDesc->Method.Dispatch.Implementation (WalkState); + Info->ReturnObject = WalkState->ReturnDesc; + + /* Cleanup states */ + + AcpiDsScopeStackClear (WalkState); + AcpiPsCleanupScope (&WalkState->ParserState); + AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + + /* + * Start method evaluation with an implicit return of zero. + * This is done for Windows compatibility. + */ + if (AcpiGbl_EnableInterpreterSlack) + { + WalkState->ImplicitReturnObj = + AcpiUtCreateIntegerObject ((UINT64) 0); + if (!WalkState->ImplicitReturnObj) + { + Status = AE_NO_MEMORY; + AcpiDsDeleteWalkState (WalkState); + goto Cleanup; + } + } + + /* Parse the AML */ + + Status = AcpiPsParseAml (WalkState); + + /* WalkState was deleted by ParseAml */ + +Cleanup: + AcpiPsDeleteParseTree (Op); + + /* Take away the extra reference that we gave the parameters above */ + + AcpiPsUpdateParameterList (Info, REF_DECREMENT); + + /* Exit now if error above */ + + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * If the method has returned an object, signal this to the caller with + * a control exception code + */ + if (Info->ReturnObject) + { + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n", + Info->ReturnObject)); + ACPI_DUMP_STACK_ENTRY (Info->ReturnObject); + + Status = AE_CTRL_RETURN_VALUE; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiPsUpdateParameterList + * + * PARAMETERS: Info - See ACPI_EVALUATE_INFO + * (Used: ParameterType and Parameters) + * Action - Add or Remove reference + * + * RETURN: Status + * + * DESCRIPTION: Update reference count on all method parameter objects + * + ******************************************************************************/ + +static void +AcpiPsUpdateParameterList ( + ACPI_EVALUATE_INFO *Info, + UINT16 Action) +{ + UINT32 i; + + + if (Info->Parameters) + { + /* Update reference count for each parameter */ + + for (i = 0; Info->Parameters[i]; i++) + { + /* Ignore errors, just do them all */ + + (void) AcpiUtUpdateObjectReference ( + Info->Parameters[i], Action); + } + } +} diff --git a/third_party/lib/acpica/source/components/resources/rsaddr.c b/third_party/lib/acpica/source/components/resources/rsaddr.c new file mode 100644 index 000000000..4a3823c82 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsaddr.c @@ -0,0 +1,412 @@ +/******************************************************************************* + * + * Module Name: rsaddr - Address resource descriptors (16/32/64) + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsaddr") + + +/******************************************************************************* + * + * AcpiRsConvertAddress16 - All WORD (16-bit) address resources + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertAddress16[5] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_ADDRESS16, + ACPI_RS_SIZE (ACPI_RESOURCE_ADDRESS16), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertAddress16)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_ADDRESS16, + sizeof (AML_RESOURCE_ADDRESS16), + 0}, + + /* Resource Type, General Flags, and Type-Specific Flags */ + + {ACPI_RSC_ADDRESS, 0, 0, 0}, + + /* + * These fields are contiguous in both the source and destination: + * Address Granularity + * Address Range Minimum + * Address Range Maximum + * Address Translation Offset + * Address Length + */ + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.Address16.Address.Granularity), + AML_OFFSET (Address16.Granularity), + 5}, + + /* Optional ResourceSource (Index and String) */ + + {ACPI_RSC_SOURCE, ACPI_RS_OFFSET (Data.Address16.ResourceSource), + 0, + sizeof (AML_RESOURCE_ADDRESS16)} +}; + + +/******************************************************************************* + * + * AcpiRsConvertAddress32 - All DWORD (32-bit) address resources + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertAddress32[5] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_ADDRESS32, + ACPI_RS_SIZE (ACPI_RESOURCE_ADDRESS32), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertAddress32)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_ADDRESS32, + sizeof (AML_RESOURCE_ADDRESS32), + 0}, + + /* Resource Type, General Flags, and Type-Specific Flags */ + + {ACPI_RSC_ADDRESS, 0, 0, 0}, + + /* + * These fields are contiguous in both the source and destination: + * Address Granularity + * Address Range Minimum + * Address Range Maximum + * Address Translation Offset + * Address Length + */ + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.Address32.Address.Granularity), + AML_OFFSET (Address32.Granularity), + 5}, + + /* Optional ResourceSource (Index and String) */ + + {ACPI_RSC_SOURCE, ACPI_RS_OFFSET (Data.Address32.ResourceSource), + 0, + sizeof (AML_RESOURCE_ADDRESS32)} +}; + + +/******************************************************************************* + * + * AcpiRsConvertAddress64 - All QWORD (64-bit) address resources + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertAddress64[5] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_ADDRESS64, + ACPI_RS_SIZE (ACPI_RESOURCE_ADDRESS64), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertAddress64)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_ADDRESS64, + sizeof (AML_RESOURCE_ADDRESS64), + 0}, + + /* Resource Type, General Flags, and Type-Specific Flags */ + + {ACPI_RSC_ADDRESS, 0, 0, 0}, + + /* + * These fields are contiguous in both the source and destination: + * Address Granularity + * Address Range Minimum + * Address Range Maximum + * Address Translation Offset + * Address Length + */ + {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.Address64.Address.Granularity), + AML_OFFSET (Address64.Granularity), + 5}, + + /* Optional ResourceSource (Index and String) */ + + {ACPI_RSC_SOURCE, ACPI_RS_OFFSET (Data.Address64.ResourceSource), + 0, + sizeof (AML_RESOURCE_ADDRESS64)} +}; + + +/******************************************************************************* + * + * AcpiRsConvertExtAddress64 - All Extended (64-bit) address resources + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertExtAddress64[5] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64, + ACPI_RS_SIZE (ACPI_RESOURCE_EXTENDED_ADDRESS64), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertExtAddress64)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64, + sizeof (AML_RESOURCE_EXTENDED_ADDRESS64), + 0}, + + /* Resource Type, General Flags, and Type-Specific Flags */ + + {ACPI_RSC_ADDRESS, 0, 0, 0}, + + /* Revision ID */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.ExtAddress64.RevisionID), + AML_OFFSET (ExtAddress64.RevisionID), + 1}, + /* + * These fields are contiguous in both the source and destination: + * Address Granularity + * Address Range Minimum + * Address Range Maximum + * Address Translation Offset + * Address Length + * Type-Specific Attribute + */ + {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.ExtAddress64.Address.Granularity), + AML_OFFSET (ExtAddress64.Granularity), + 6} +}; + + +/******************************************************************************* + * + * AcpiRsConvertGeneralFlags - Flags common to all address descriptors + * + ******************************************************************************/ + +static ACPI_RSCONVERT_INFO AcpiRsConvertGeneralFlags[6] = +{ + {ACPI_RSC_FLAGINIT, 0, AML_OFFSET (Address.Flags), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertGeneralFlags)}, + + /* Resource Type (Memory, Io, BusNumber, etc.) */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Address.ResourceType), + AML_OFFSET (Address.ResourceType), + 1}, + + /* General Flags - Consume, Decode, MinFixed, MaxFixed */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.ProducerConsumer), + AML_OFFSET (Address.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.Decode), + AML_OFFSET (Address.Flags), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.MinAddressFixed), + AML_OFFSET (Address.Flags), + 2}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.MaxAddressFixed), + AML_OFFSET (Address.Flags), + 3} +}; + + +/******************************************************************************* + * + * AcpiRsConvertMemFlags - Flags common to Memory address descriptors + * + ******************************************************************************/ + +static ACPI_RSCONVERT_INFO AcpiRsConvertMemFlags[5] = +{ + {ACPI_RSC_FLAGINIT, 0, AML_OFFSET (Address.SpecificFlags), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertMemFlags)}, + + /* Memory-specific flags */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Mem.WriteProtect), + AML_OFFSET (Address.SpecificFlags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Mem.Caching), + AML_OFFSET (Address.SpecificFlags), + 1}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Mem.RangeType), + AML_OFFSET (Address.SpecificFlags), + 3}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Mem.Translation), + AML_OFFSET (Address.SpecificFlags), + 5} +}; + + +/******************************************************************************* + * + * AcpiRsConvertIoFlags - Flags common to I/O address descriptors + * + ******************************************************************************/ + +static ACPI_RSCONVERT_INFO AcpiRsConvertIoFlags[4] = +{ + {ACPI_RSC_FLAGINIT, 0, AML_OFFSET (Address.SpecificFlags), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertIoFlags)}, + + /* I/O-specific flags */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Io.RangeType), + AML_OFFSET (Address.SpecificFlags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Io.Translation), + AML_OFFSET (Address.SpecificFlags), + 4}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Address.Info.Io.TranslationType), + AML_OFFSET (Address.SpecificFlags), + 5} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetAddressCommon + * + * PARAMETERS: Resource - Pointer to the internal resource struct + * Aml - Pointer to the AML resource descriptor + * + * RETURN: TRUE if the ResourceType field is OK, FALSE otherwise + * + * DESCRIPTION: Convert common flag fields from a raw AML resource descriptor + * to an internal resource descriptor + * + ******************************************************************************/ + +BOOLEAN +AcpiRsGetAddressCommon ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Validate the Resource Type */ + + if ((Aml->Address.ResourceType > 2) && + (Aml->Address.ResourceType < 0xC0)) + { + return (FALSE); + } + + /* Get the Resource Type and General Flags */ + + (void) AcpiRsConvertAmlToResource ( + Resource, Aml, AcpiRsConvertGeneralFlags); + + /* Get the Type-Specific Flags (Memory and I/O descriptors only) */ + + if (Resource->Data.Address.ResourceType == ACPI_MEMORY_RANGE) + { + (void) AcpiRsConvertAmlToResource ( + Resource, Aml, AcpiRsConvertMemFlags); + } + else if (Resource->Data.Address.ResourceType == ACPI_IO_RANGE) + { + (void) AcpiRsConvertAmlToResource ( + Resource, Aml, AcpiRsConvertIoFlags); + } + else + { + /* Generic resource type, just grab the TypeSpecific byte */ + + Resource->Data.Address.Info.TypeSpecific = + Aml->Address.SpecificFlags; + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsSetAddressCommon + * + * PARAMETERS: Aml - Pointer to the AML resource descriptor + * Resource - Pointer to the internal resource struct + * + * RETURN: None + * + * DESCRIPTION: Convert common flag fields from a resource descriptor to an + * AML descriptor + * + ******************************************************************************/ + +void +AcpiRsSetAddressCommon ( + AML_RESOURCE *Aml, + ACPI_RESOURCE *Resource) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Set the Resource Type and General Flags */ + + (void) AcpiRsConvertResourceToAml ( + Resource, Aml, AcpiRsConvertGeneralFlags); + + /* Set the Type-Specific Flags (Memory and I/O descriptors only) */ + + if (Resource->Data.Address.ResourceType == ACPI_MEMORY_RANGE) + { + (void) AcpiRsConvertResourceToAml ( + Resource, Aml, AcpiRsConvertMemFlags); + } + else if (Resource->Data.Address.ResourceType == ACPI_IO_RANGE) + { + (void) AcpiRsConvertResourceToAml ( + Resource, Aml, AcpiRsConvertIoFlags); + } + else + { + /* Generic resource type, just copy the TypeSpecific byte */ + + Aml->Address.SpecificFlags = + Resource->Data.Address.Info.TypeSpecific; + } +} diff --git a/third_party/lib/acpica/source/components/resources/rscalc.c b/third_party/lib/acpica/source/components/resources/rscalc.c new file mode 100644 index 000000000..92a710c1e --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rscalc.c @@ -0,0 +1,759 @@ +/******************************************************************************* + * + * Module Name: rscalc - Calculate stream and list lengths + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rscalc") + + +/* Local prototypes */ + +static UINT8 +AcpiRsCountSetBits ( + UINT16 BitField); + +static ACPI_RS_LENGTH +AcpiRsStructOptionLength ( + ACPI_RESOURCE_SOURCE *ResourceSource); + +static UINT32 +AcpiRsStreamOptionLength ( + UINT32 ResourceLength, + UINT32 MinimumTotalLength); + + +/******************************************************************************* + * + * FUNCTION: AcpiRsCountSetBits + * + * PARAMETERS: BitField - Field in which to count bits + * + * RETURN: Number of bits set within the field + * + * DESCRIPTION: Count the number of bits set in a resource field. Used for + * (Short descriptor) interrupt and DMA lists. + * + ******************************************************************************/ + +static UINT8 +AcpiRsCountSetBits ( + UINT16 BitField) +{ + UINT8 BitsSet; + + + ACPI_FUNCTION_ENTRY (); + + + for (BitsSet = 0; BitField; BitsSet++) + { + /* Zero the least significant bit that is set */ + + BitField &= (UINT16) (BitField - 1); + } + + return (BitsSet); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsStructOptionLength + * + * PARAMETERS: ResourceSource - Pointer to optional descriptor field + * + * RETURN: Status + * + * DESCRIPTION: Common code to handle optional ResourceSourceIndex and + * ResourceSource fields in some Large descriptors. Used during + * list-to-stream conversion + * + ******************************************************************************/ + +static ACPI_RS_LENGTH +AcpiRsStructOptionLength ( + ACPI_RESOURCE_SOURCE *ResourceSource) +{ + ACPI_FUNCTION_ENTRY (); + + + /* + * If the ResourceSource string is valid, return the size of the string + * (StringLength includes the NULL terminator) plus the size of the + * ResourceSourceIndex (1). + */ + if (ResourceSource->StringPtr) + { + return ((ACPI_RS_LENGTH) (ResourceSource->StringLength + 1)); + } + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsStreamOptionLength + * + * PARAMETERS: ResourceLength - Length from the resource header + * MinimumTotalLength - Minimum length of this resource, before + * any optional fields. Includes header size + * + * RETURN: Length of optional string (0 if no string present) + * + * DESCRIPTION: Common code to handle optional ResourceSourceIndex and + * ResourceSource fields in some Large descriptors. Used during + * stream-to-list conversion + * + ******************************************************************************/ + +static UINT32 +AcpiRsStreamOptionLength ( + UINT32 ResourceLength, + UINT32 MinimumAmlResourceLength) +{ + UINT32 StringLength = 0; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * The ResourceSourceIndex and ResourceSource are optional elements of + * some Large-type resource descriptors. + */ + + /* + * If the length of the actual resource descriptor is greater than the + * ACPI spec-defined minimum length, it means that a ResourceSourceIndex + * exists and is followed by a (required) null terminated string. The + * string length (including the null terminator) is the resource length + * minus the minimum length, minus one byte for the ResourceSourceIndex + * itself. + */ + if (ResourceLength > MinimumAmlResourceLength) + { + /* Compute the length of the optional string */ + + StringLength = ResourceLength - MinimumAmlResourceLength - 1; + } + + /* + * Round the length up to a multiple of the native word in order to + * guarantee that the entire resource descriptor is native word aligned + */ + return ((UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (StringLength)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetAmlLength + * + * PARAMETERS: Resource - Pointer to the resource linked list + * ResourceListSize - Size of the resource linked list + * SizeNeeded - Where the required size is returned + * + * RETURN: Status + * + * DESCRIPTION: Takes a linked list of internal resource descriptors and + * calculates the size buffer needed to hold the corresponding + * external resource byte stream. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetAmlLength ( + ACPI_RESOURCE *Resource, + ACPI_SIZE ResourceListSize, + ACPI_SIZE *SizeNeeded) +{ + ACPI_SIZE AmlSizeNeeded = 0; + ACPI_RESOURCE *ResourceEnd; + ACPI_RS_LENGTH TotalSize; + + + ACPI_FUNCTION_TRACE (RsGetAmlLength); + + + /* Traverse entire list of internal resource descriptors */ + + ResourceEnd = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, ResourceListSize); + while (Resource < ResourceEnd) + { + /* Validate the descriptor type */ + + if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) + { + return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); + } + + /* Sanity check the length. It must not be zero, or we loop forever */ + + if (!Resource->Length) + { + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); + } + + /* Get the base size of the (external stream) resource descriptor */ + + TotalSize = AcpiGbl_AmlResourceSizes [Resource->Type]; + + /* + * Augment the base size for descriptors with optional and/or + * variable-length fields + */ + switch (Resource->Type) + { + case ACPI_RESOURCE_TYPE_IRQ: + + /* Length can be 3 or 2 */ + + if (Resource->Data.Irq.DescriptorLength == 2) + { + TotalSize--; + } + break; + + + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + + /* Length can be 1 or 0 */ + + if (Resource->Data.Irq.DescriptorLength == 0) + { + TotalSize--; + } + break; + + + case ACPI_RESOURCE_TYPE_VENDOR: + /* + * Vendor Defined Resource: + * For a Vendor Specific resource, if the Length is between 1 and 7 + * it will be created as a Small Resource data type, otherwise it + * is a Large Resource data type. + */ + if (Resource->Data.Vendor.ByteLength > 7) + { + /* Base size of a Large resource descriptor */ + + TotalSize = sizeof (AML_RESOURCE_LARGE_HEADER); + } + + /* Add the size of the vendor-specific data */ + + TotalSize = (ACPI_RS_LENGTH) + (TotalSize + Resource->Data.Vendor.ByteLength); + break; + + + case ACPI_RESOURCE_TYPE_END_TAG: + /* + * End Tag: + * We are done -- return the accumulated total size. + */ + *SizeNeeded = AmlSizeNeeded + TotalSize; + + /* Normal exit */ + + return_ACPI_STATUS (AE_OK); + + + case ACPI_RESOURCE_TYPE_ADDRESS16: + /* + * 16-Bit Address Resource: + * Add the size of the optional ResourceSource info + */ + TotalSize = (ACPI_RS_LENGTH) (TotalSize + + AcpiRsStructOptionLength ( + &Resource->Data.Address16.ResourceSource)); + break; + + + case ACPI_RESOURCE_TYPE_ADDRESS32: + /* + * 32-Bit Address Resource: + * Add the size of the optional ResourceSource info + */ + TotalSize = (ACPI_RS_LENGTH) (TotalSize + + AcpiRsStructOptionLength ( + &Resource->Data.Address32.ResourceSource)); + break; + + + case ACPI_RESOURCE_TYPE_ADDRESS64: + /* + * 64-Bit Address Resource: + * Add the size of the optional ResourceSource info + */ + TotalSize = (ACPI_RS_LENGTH) (TotalSize + + AcpiRsStructOptionLength ( + &Resource->Data.Address64.ResourceSource)); + break; + + + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + /* + * Extended IRQ Resource: + * Add the size of each additional optional interrupt beyond the + * required 1 (4 bytes for each UINT32 interrupt number) + */ + TotalSize = (ACPI_RS_LENGTH) (TotalSize + + ((Resource->Data.ExtendedIrq.InterruptCount - 1) * 4) + + + /* Add the size of the optional ResourceSource info */ + + AcpiRsStructOptionLength ( + &Resource->Data.ExtendedIrq.ResourceSource)); + break; + + + case ACPI_RESOURCE_TYPE_GPIO: + + TotalSize = (ACPI_RS_LENGTH) (TotalSize + + (Resource->Data.Gpio.PinTableLength * 2) + + Resource->Data.Gpio.ResourceSource.StringLength + + Resource->Data.Gpio.VendorLength); + + break; + + + case ACPI_RESOURCE_TYPE_SERIAL_BUS: + + TotalSize = AcpiGbl_AmlResourceSerialBusSizes [ + Resource->Data.CommonSerialBus.Type]; + + TotalSize = (ACPI_RS_LENGTH) (TotalSize + + Resource->Data.I2cSerialBus.ResourceSource.StringLength + + Resource->Data.I2cSerialBus.VendorLength); + + break; + + default: + + break; + } + + /* Update the total */ + + AmlSizeNeeded += TotalSize; + + /* Point to the next object */ + + Resource = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, Resource->Length); + } + + /* Did not find an EndTag resource descriptor */ + + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetListLength + * + * PARAMETERS: AmlBuffer - Pointer to the resource byte stream + * AmlBufferLength - Size of AmlBuffer + * SizeNeeded - Where the size needed is returned + * + * RETURN: Status + * + * DESCRIPTION: Takes an external resource byte stream and calculates the size + * buffer needed to hold the corresponding internal resource + * descriptor linked list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetListLength ( + UINT8 *AmlBuffer, + UINT32 AmlBufferLength, + ACPI_SIZE *SizeNeeded) +{ + ACPI_STATUS Status; + UINT8 *EndAml; + UINT8 *Buffer; + UINT32 BufferSize; + UINT16 Temp16; + UINT16 ResourceLength; + UINT32 ExtraStructBytes; + UINT8 ResourceIndex; + UINT8 MinimumAmlResourceLength; + AML_RESOURCE *AmlResource; + + + ACPI_FUNCTION_TRACE (RsGetListLength); + + + *SizeNeeded = ACPI_RS_SIZE_MIN; /* Minimum size is one EndTag */ + EndAml = AmlBuffer + AmlBufferLength; + + /* Walk the list of AML resource descriptors */ + + while (AmlBuffer < EndAml) + { + /* Validate the Resource Type and Resource Length */ + + Status = AcpiUtValidateResource (NULL, AmlBuffer, &ResourceIndex); + if (ACPI_FAILURE (Status)) + { + /* + * Exit on failure. Cannot continue because the descriptor length + * may be bogus also. + */ + return_ACPI_STATUS (Status); + } + + AmlResource = (void *) AmlBuffer; + + /* Get the resource length and base (minimum) AML size */ + + ResourceLength = AcpiUtGetResourceLength (AmlBuffer); + MinimumAmlResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex]; + + /* + * Augment the size for descriptors with optional + * and/or variable length fields + */ + ExtraStructBytes = 0; + Buffer = AmlBuffer + AcpiUtGetResourceHeaderLength (AmlBuffer); + + switch (AcpiUtGetResourceType (AmlBuffer)) + { + case ACPI_RESOURCE_NAME_IRQ: + /* + * IRQ Resource: + * Get the number of bits set in the 16-bit IRQ mask + */ + ACPI_MOVE_16_TO_16 (&Temp16, Buffer); + ExtraStructBytes = AcpiRsCountSetBits (Temp16); + break; + + + case ACPI_RESOURCE_NAME_DMA: + /* + * DMA Resource: + * Get the number of bits set in the 8-bit DMA mask + */ + ExtraStructBytes = AcpiRsCountSetBits (*Buffer); + break; + + + case ACPI_RESOURCE_NAME_VENDOR_SMALL: + case ACPI_RESOURCE_NAME_VENDOR_LARGE: + /* + * Vendor Resource: + * Get the number of vendor data bytes + */ + ExtraStructBytes = ResourceLength; + + /* + * There is already one byte included in the minimum + * descriptor size. If there are extra struct bytes, + * subtract one from the count. + */ + if (ExtraStructBytes) + { + ExtraStructBytes--; + } + break; + + + case ACPI_RESOURCE_NAME_END_TAG: + /* + * End Tag: This is the normal exit + */ + return_ACPI_STATUS (AE_OK); + + + case ACPI_RESOURCE_NAME_ADDRESS32: + case ACPI_RESOURCE_NAME_ADDRESS16: + case ACPI_RESOURCE_NAME_ADDRESS64: + /* + * Address Resource: + * Add the size of the optional ResourceSource + */ + ExtraStructBytes = AcpiRsStreamOptionLength ( + ResourceLength, MinimumAmlResourceLength); + break; + + + case ACPI_RESOURCE_NAME_EXTENDED_IRQ: + /* + * Extended IRQ Resource: + * Using the InterruptTableLength, add 4 bytes for each additional + * interrupt. Note: at least one interrupt is required and is + * included in the minimum descriptor size (reason for the -1) + */ + ExtraStructBytes = (Buffer[1] - 1) * sizeof (UINT32); + + /* Add the size of the optional ResourceSource */ + + ExtraStructBytes += AcpiRsStreamOptionLength ( + ResourceLength - ExtraStructBytes, MinimumAmlResourceLength); + break; + + case ACPI_RESOURCE_NAME_GPIO: + + /* Vendor data is optional */ + + if (AmlResource->Gpio.VendorLength) + { + ExtraStructBytes += + AmlResource->Gpio.VendorOffset - + AmlResource->Gpio.PinTableOffset + + AmlResource->Gpio.VendorLength; + } + else + { + ExtraStructBytes += + AmlResource->LargeHeader.ResourceLength + + sizeof (AML_RESOURCE_LARGE_HEADER) - + AmlResource->Gpio.PinTableOffset; + } + break; + + case ACPI_RESOURCE_NAME_SERIAL_BUS: + + MinimumAmlResourceLength = AcpiGbl_ResourceAmlSerialBusSizes[ + AmlResource->CommonSerialBus.Type]; + ExtraStructBytes += + AmlResource->CommonSerialBus.ResourceLength - + MinimumAmlResourceLength; + break; + + default: + + break; + } + + /* + * Update the required buffer size for the internal descriptor structs + * + * Important: Round the size up for the appropriate alignment. This + * is a requirement on IA64. + */ + if (AcpiUtGetResourceType (AmlBuffer) == + ACPI_RESOURCE_NAME_SERIAL_BUS) + { + BufferSize = AcpiGbl_ResourceStructSerialBusSizes[ + AmlResource->CommonSerialBus.Type] + ExtraStructBytes; + } + else + { + BufferSize = AcpiGbl_ResourceStructSizes[ResourceIndex] + + ExtraStructBytes; + } + + BufferSize = (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (BufferSize); + *SizeNeeded += BufferSize; + + ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, + "Type %.2X, AmlLength %.2X InternalLength %.2X\n", + AcpiUtGetResourceType (AmlBuffer), + AcpiUtGetDescriptorLength (AmlBuffer), BufferSize)); + + /* + * Point to the next resource within the AML stream using the length + * contained in the resource descriptor header + */ + AmlBuffer += AcpiUtGetDescriptorLength (AmlBuffer); + } + + /* Did not find an EndTag resource descriptor */ + + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetPciRoutingTableLength + * + * PARAMETERS: PackageObject - Pointer to the package object + * BufferSizeNeeded - UINT32 pointer of the size buffer + * needed to properly return the + * parsed data + * + * RETURN: Status + * + * DESCRIPTION: Given a package representing a PCI routing table, this + * calculates the size of the corresponding linked list of + * descriptions. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetPciRoutingTableLength ( + ACPI_OPERAND_OBJECT *PackageObject, + ACPI_SIZE *BufferSizeNeeded) +{ + UINT32 NumberOfElements; + ACPI_SIZE TempSizeNeeded = 0; + ACPI_OPERAND_OBJECT **TopObjectList; + UINT32 Index; + ACPI_OPERAND_OBJECT *PackageElement; + ACPI_OPERAND_OBJECT **SubObjectList; + BOOLEAN NameFound; + UINT32 TableIndex; + + + ACPI_FUNCTION_TRACE (RsGetPciRoutingTableLength); + + + NumberOfElements = PackageObject->Package.Count; + + /* + * Calculate the size of the return buffer. + * The base size is the number of elements * the sizes of the + * structures. Additional space for the strings is added below. + * The minus one is to subtract the size of the UINT8 Source[1] + * member because it is added below. + * + * But each PRT_ENTRY structure has a pointer to a string and + * the size of that string must be found. + */ + TopObjectList = PackageObject->Package.Elements; + + for (Index = 0; Index < NumberOfElements; Index++) + { + /* Dereference the subpackage */ + + PackageElement = *TopObjectList; + + /* We must have a valid Package object */ + + if (!PackageElement || + (PackageElement->Common.Type != ACPI_TYPE_PACKAGE)) + { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * The SubObjectList will now point to an array of the + * four IRQ elements: Address, Pin, Source and SourceIndex + */ + SubObjectList = PackageElement->Package.Elements; + + /* Scan the IrqTableElements for the Source Name String */ + + NameFound = FALSE; + + for (TableIndex = 0; + TableIndex < PackageElement->Package.Count && !NameFound; + TableIndex++) + { + if (*SubObjectList && /* Null object allowed */ + + ((ACPI_TYPE_STRING == + (*SubObjectList)->Common.Type) || + + ((ACPI_TYPE_LOCAL_REFERENCE == + (*SubObjectList)->Common.Type) && + + ((*SubObjectList)->Reference.Class == + ACPI_REFCLASS_NAME)))) + { + NameFound = TRUE; + } + else + { + /* Look at the next element */ + + SubObjectList++; + } + } + + TempSizeNeeded += (sizeof (ACPI_PCI_ROUTING_TABLE) - 4); + + /* Was a String type found? */ + + if (NameFound) + { + if ((*SubObjectList)->Common.Type == ACPI_TYPE_STRING) + { + /* + * The length String.Length field does not include the + * terminating NULL, add 1 + */ + TempSizeNeeded += ((ACPI_SIZE) + (*SubObjectList)->String.Length + 1); + } + else + { + TempSizeNeeded += AcpiNsGetPathnameLength ( + (*SubObjectList)->Reference.Node); + } + } + else + { + /* + * If no name was found, then this is a NULL, which is + * translated as a UINT32 zero. + */ + TempSizeNeeded += sizeof (UINT32); + } + + /* Round up the size since each element must be aligned */ + + TempSizeNeeded = ACPI_ROUND_UP_TO_64BIT (TempSizeNeeded); + + /* Point to the next ACPI_OPERAND_OBJECT */ + + TopObjectList++; + } + + /* + * Add an extra element to the end of the list, essentially a + * NULL terminator + */ + *BufferSizeNeeded = TempSizeNeeded + sizeof (ACPI_PCI_ROUTING_TABLE); + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/resources/rscreate.c b/third_party/lib/acpica/source/components/resources/rscreate.c new file mode 100644 index 000000000..64bbdbe99 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rscreate.c @@ -0,0 +1,506 @@ +/******************************************************************************* + * + * Module Name: rscreate - Create resource lists/tables + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rscreate") + + +/******************************************************************************* + * + * FUNCTION: AcpiBufferToResource + * + * PARAMETERS: AmlBuffer - Pointer to the resource byte stream + * AmlBufferLength - Length of the AmlBuffer + * ResourcePtr - Where the converted resource is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a raw AML buffer to a resource list + * + ******************************************************************************/ + +ACPI_STATUS +AcpiBufferToResource ( + UINT8 *AmlBuffer, + UINT16 AmlBufferLength, + ACPI_RESOURCE **ResourcePtr) +{ + ACPI_STATUS Status; + ACPI_SIZE ListSizeNeeded; + void *Resource; + void *CurrentResourcePtr; + + + ACPI_FUNCTION_TRACE (AcpiBufferToResource); + + + /* + * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag + * is not required here. + */ + + /* Get the required length for the converted resource */ + + Status = AcpiRsGetListLength ( + AmlBuffer, AmlBufferLength, &ListSizeNeeded); + if (Status == AE_AML_NO_RESOURCE_END_TAG) + { + Status = AE_OK; + } + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Allocate a buffer for the converted resource */ + + Resource = ACPI_ALLOCATE_ZEROED (ListSizeNeeded); + CurrentResourcePtr = Resource; + if (!Resource) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Perform the AML-to-Resource conversion */ + + Status = AcpiUtWalkAmlResources (NULL, AmlBuffer, AmlBufferLength, + AcpiRsConvertAmlToResources, &CurrentResourcePtr); + if (Status == AE_AML_NO_RESOURCE_END_TAG) + { + Status = AE_OK; + } + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (Resource); + } + else + { + *ResourcePtr = Resource; + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiBufferToResource) + + +/******************************************************************************* + * + * FUNCTION: AcpiRsCreateResourceList + * + * PARAMETERS: AmlBuffer - Pointer to the resource byte stream + * OutputBuffer - Pointer to the user's buffer + * + * RETURN: Status: AE_OK if okay, else a valid ACPI_STATUS code + * If OutputBuffer is not large enough, OutputBufferLength + * indicates how large OutputBuffer should be, else it + * indicates how may UINT8 elements of OutputBuffer are valid. + * + * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method + * execution and parses the stream to create a linked list + * of device resources. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsCreateResourceList ( + ACPI_OPERAND_OBJECT *AmlBuffer, + ACPI_BUFFER *OutputBuffer) +{ + + ACPI_STATUS Status; + UINT8 *AmlStart; + ACPI_SIZE ListSizeNeeded = 0; + UINT32 AmlBufferLength; + void *Resource; + + + ACPI_FUNCTION_TRACE (RsCreateResourceList); + + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AmlBuffer = %p\n", + AmlBuffer)); + + /* Params already validated, so we don't re-validate here */ + + AmlBufferLength = AmlBuffer->Buffer.Length; + AmlStart = AmlBuffer->Buffer.Pointer; + + /* + * Pass the AmlBuffer into a module that can calculate + * the buffer size needed for the linked list + */ + Status = AcpiRsGetListLength (AmlStart, AmlBufferLength, + &ListSizeNeeded); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status=%X ListSizeNeeded=%X\n", + Status, (UINT32) ListSizeNeeded)); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (OutputBuffer, ListSizeNeeded); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Do the conversion */ + + Resource = OutputBuffer->Pointer; + Status = AcpiUtWalkAmlResources (NULL, AmlStart, AmlBufferLength, + AcpiRsConvertAmlToResources, &Resource); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", + OutputBuffer->Pointer, (UINT32) OutputBuffer->Length)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsCreatePciRoutingTable + * + * PARAMETERS: PackageObject - Pointer to a package containing one + * of more ACPI_OPERAND_OBJECTs + * OutputBuffer - Pointer to the user's buffer + * + * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. + * If the OutputBuffer is too small, the error will be + * AE_BUFFER_OVERFLOW and OutputBuffer->Length will point + * to the size buffer needed. + * + * DESCRIPTION: Takes the ACPI_OPERAND_OBJECT package and creates a + * linked list of PCI interrupt descriptions + * + * NOTE: It is the caller's responsibility to ensure that the start of the + * output buffer is aligned properly (if necessary). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsCreatePciRoutingTable ( + ACPI_OPERAND_OBJECT *PackageObject, + ACPI_BUFFER *OutputBuffer) +{ + UINT8 *Buffer; + ACPI_OPERAND_OBJECT **TopObjectList; + ACPI_OPERAND_OBJECT **SubObjectList; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_SIZE BufferSizeNeeded = 0; + UINT32 NumberOfElements; + UINT32 Index; + ACPI_PCI_ROUTING_TABLE *UserPrt; + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + ACPI_BUFFER PathBuffer; + + + ACPI_FUNCTION_TRACE (RsCreatePciRoutingTable); + + + /* Params already validated, so we don't re-validate here */ + + /* Get the required buffer length */ + + Status = AcpiRsGetPciRoutingTableLength ( + PackageObject,&BufferSizeNeeded); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "BufferSizeNeeded = %X\n", + (UINT32) BufferSizeNeeded)); + + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (OutputBuffer, BufferSizeNeeded); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a + * package that in turn contains an UINT64 Address, a UINT8 Pin, + * a Name, and a UINT8 SourceIndex. + */ + TopObjectList = PackageObject->Package.Elements; + NumberOfElements = PackageObject->Package.Count; + Buffer = OutputBuffer->Pointer; + UserPrt = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, Buffer); + + for (Index = 0; Index < NumberOfElements; Index++) + { + /* + * Point UserPrt past this current structure + * + * NOTE: On the first iteration, UserPrt->Length will + * be zero because we cleared the return buffer earlier + */ + Buffer += UserPrt->Length; + UserPrt = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, Buffer); + + /* + * Fill in the Length field with the information we have at this + * point. The minus four is to subtract the size of the UINT8 + * Source[4] member because it is added below. + */ + UserPrt->Length = (sizeof (ACPI_PCI_ROUTING_TABLE) - 4); + + /* Each subpackage must be of length 4 */ + + if ((*TopObjectList)->Package.Count != 4) + { + ACPI_ERROR ((AE_INFO, + "(PRT[%u]) Need package of length 4, found length %u", + Index, (*TopObjectList)->Package.Count)); + return_ACPI_STATUS (AE_AML_PACKAGE_LIMIT); + } + + /* + * Dereference the subpackage. + * The SubObjectList will now point to an array of the four IRQ + * elements: [Address, Pin, Source, SourceIndex] + */ + SubObjectList = (*TopObjectList)->Package.Elements; + + /* 1) First subobject: Dereference the PRT.Address */ + + ObjDesc = SubObjectList[0]; + if (!ObjDesc || ObjDesc->Common.Type != ACPI_TYPE_INTEGER) + { + ACPI_ERROR ((AE_INFO, + "(PRT[%u].Address) Need Integer, found %s", + Index, AcpiUtGetObjectTypeName (ObjDesc))); + return_ACPI_STATUS (AE_BAD_DATA); + } + + UserPrt->Address = ObjDesc->Integer.Value; + + /* 2) Second subobject: Dereference the PRT.Pin */ + + ObjDesc = SubObjectList[1]; + if (!ObjDesc || ObjDesc->Common.Type != ACPI_TYPE_INTEGER) + { + ACPI_ERROR ((AE_INFO, "(PRT[%u].Pin) Need Integer, found %s", + Index, AcpiUtGetObjectTypeName (ObjDesc))); + return_ACPI_STATUS (AE_BAD_DATA); + } + + UserPrt->Pin = (UINT32) ObjDesc->Integer.Value; + + /* + * 3) Third subobject: Dereference the PRT.SourceName + * The name may be unresolved (slack mode), so allow a null object + */ + ObjDesc = SubObjectList[2]; + if (ObjDesc) + { + switch (ObjDesc->Common.Type) + { + case ACPI_TYPE_LOCAL_REFERENCE: + + if (ObjDesc->Reference.Class != ACPI_REFCLASS_NAME) + { + ACPI_ERROR ((AE_INFO, + "(PRT[%u].Source) Need name, found Reference Class 0x%X", + Index, ObjDesc->Reference.Class)); + return_ACPI_STATUS (AE_BAD_DATA); + } + + Node = ObjDesc->Reference.Node; + + /* Use *remaining* length of the buffer as max for pathname */ + + PathBuffer.Length = OutputBuffer->Length - + (UINT32) ((UINT8 *) UserPrt->Source - + (UINT8 *) OutputBuffer->Pointer); + PathBuffer.Pointer = UserPrt->Source; + + Status = AcpiNsHandleToPathname ( + (ACPI_HANDLE) Node, &PathBuffer, FALSE); + + /* +1 to include null terminator */ + + UserPrt->Length += (UINT32) strlen (UserPrt->Source) + 1; + break; + + case ACPI_TYPE_STRING: + + strcpy (UserPrt->Source, ObjDesc->String.Pointer); + + /* + * Add to the Length field the length of the string + * (add 1 for terminator) + */ + UserPrt->Length += ObjDesc->String.Length + 1; + break; + + case ACPI_TYPE_INTEGER: + /* + * If this is a number, then the Source Name is NULL, since + * the entire buffer was zeroed out, we can leave this alone. + * + * Add to the Length field the length of the UINT32 NULL + */ + UserPrt->Length += sizeof (UINT32); + break; + + default: + + ACPI_ERROR ((AE_INFO, + "(PRT[%u].Source) Need Ref/String/Integer, found %s", + Index, AcpiUtGetObjectTypeName (ObjDesc))); + return_ACPI_STATUS (AE_BAD_DATA); + } + } + + /* Now align the current length */ + + UserPrt->Length = (UINT32) ACPI_ROUND_UP_TO_64BIT (UserPrt->Length); + + /* 4) Fourth subobject: Dereference the PRT.SourceIndex */ + + ObjDesc = SubObjectList[3]; + if (!ObjDesc || ObjDesc->Common.Type != ACPI_TYPE_INTEGER) + { + ACPI_ERROR ((AE_INFO, + "(PRT[%u].SourceIndex) Need Integer, found %s", + Index, AcpiUtGetObjectTypeName (ObjDesc))); + return_ACPI_STATUS (AE_BAD_DATA); + } + + UserPrt->SourceIndex = (UINT32) ObjDesc->Integer.Value; + + /* Point to the next ACPI_OPERAND_OBJECT in the top level package */ + + TopObjectList++; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", + OutputBuffer->Pointer, (UINT32) OutputBuffer->Length)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsCreateAmlResources + * + * PARAMETERS: ResourceList - Pointer to the resource list buffer + * OutputBuffer - Where the AML buffer is returned + * + * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. + * If the OutputBuffer is too small, the error will be + * AE_BUFFER_OVERFLOW and OutputBuffer->Length will point + * to the size buffer needed. + * + * DESCRIPTION: Converts a list of device resources to an AML bytestream + * to be used as input for the _SRS control method. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsCreateAmlResources ( + ACPI_BUFFER *ResourceList, + ACPI_BUFFER *OutputBuffer) +{ + ACPI_STATUS Status; + ACPI_SIZE AmlSizeNeeded = 0; + + + ACPI_FUNCTION_TRACE (RsCreateAmlResources); + + + /* Params already validated, no need to re-validate here */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ResourceList Buffer = %p\n", + ResourceList->Pointer)); + + /* Get the buffer size needed for the AML byte stream */ + + Status = AcpiRsGetAmlLength ( + ResourceList->Pointer, ResourceList->Length, &AmlSizeNeeded); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", + (UINT32) AmlSizeNeeded, AcpiFormatException (Status))); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (OutputBuffer, AmlSizeNeeded); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Do the conversion */ + + Status = AcpiRsConvertResourcesToAml (ResourceList->Pointer, + AmlSizeNeeded, OutputBuffer->Pointer); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", + OutputBuffer->Pointer, (UINT32) OutputBuffer->Length)); + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/resources/rsdump.c b/third_party/lib/acpica/source/components/resources/rsdump.c new file mode 100644 index 000000000..c0421cd24 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsdump.c @@ -0,0 +1,671 @@ +/******************************************************************************* + * + * Module Name: rsdump - AML debugger support for resource structures. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsdump") + +/* + * All functions in this module are used by the AML Debugger only + */ + +/* Local prototypes */ + +static void +AcpiRsOutString ( + char *Title, + char *Value); + +static void +AcpiRsOutInteger8 ( + char *Title, + UINT8 Value); + +static void +AcpiRsOutInteger16 ( + char *Title, + UINT16 Value); + +static void +AcpiRsOutInteger32 ( + char *Title, + UINT32 Value); + +static void +AcpiRsOutInteger64 ( + char *Title, + UINT64 Value); + +static void +AcpiRsOutTitle ( + char *Title); + +static void +AcpiRsDumpByteList ( + UINT16 Length, + UINT8 *Data); + +static void +AcpiRsDumpWordList ( + UINT16 Length, + UINT16 *Data); + +static void +AcpiRsDumpDwordList ( + UINT8 Length, + UINT32 *Data); + +static void +AcpiRsDumpShortByteList ( + UINT8 Length, + UINT8 *Data); + +static void +AcpiRsDumpResourceSource ( + ACPI_RESOURCE_SOURCE *ResourceSource); + +static void +AcpiRsDumpAddressCommon ( + ACPI_RESOURCE_DATA *Resource); + +static void +AcpiRsDumpDescriptor ( + void *Resource, + ACPI_RSDUMP_INFO *Table); + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDumpResourceList + * + * PARAMETERS: ResourceList - Pointer to a resource descriptor list + * + * RETURN: None + * + * DESCRIPTION: Dispatches the structure to the correct dump routine. + * + ******************************************************************************/ + +void +AcpiRsDumpResourceList ( + ACPI_RESOURCE *ResourceList) +{ + UINT32 Count = 0; + UINT32 Type; + + + ACPI_FUNCTION_ENTRY (); + + + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT)) + { + return; + } + + /* Walk list and dump all resource descriptors (END_TAG terminates) */ + + do + { + AcpiOsPrintf ("\n[%02X] ", Count); + Count++; + + /* Validate Type before dispatch */ + + Type = ResourceList->Type; + if (Type > ACPI_RESOURCE_TYPE_MAX) + { + AcpiOsPrintf ( + "Invalid descriptor type (%X) in resource list\n", + ResourceList->Type); + return; + } + + /* Sanity check the length. It must not be zero, or we loop forever */ + + if (!ResourceList->Length) + { + AcpiOsPrintf ( + "Invalid zero length descriptor in resource list\n"); + return; + } + + /* Dump the resource descriptor */ + + if (Type == ACPI_RESOURCE_TYPE_SERIAL_BUS) + { + AcpiRsDumpDescriptor (&ResourceList->Data, + AcpiGbl_DumpSerialBusDispatch[ + ResourceList->Data.CommonSerialBus.Type]); + } + else + { + AcpiRsDumpDescriptor (&ResourceList->Data, + AcpiGbl_DumpResourceDispatch[Type]); + } + + /* Point to the next resource structure */ + + ResourceList = ACPI_NEXT_RESOURCE (ResourceList); + + /* Exit when END_TAG descriptor is reached */ + + } while (Type != ACPI_RESOURCE_TYPE_END_TAG); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDumpIrqList + * + * PARAMETERS: RouteTable - Pointer to the routing table to dump. + * + * RETURN: None + * + * DESCRIPTION: Print IRQ routing table + * + ******************************************************************************/ + +void +AcpiRsDumpIrqList ( + UINT8 *RouteTable) +{ + ACPI_PCI_ROUTING_TABLE *PrtElement; + UINT8 Count; + + + ACPI_FUNCTION_ENTRY (); + + + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT)) + { + return; + } + + PrtElement = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, RouteTable); + + /* Dump all table elements, Exit on zero length element */ + + for (Count = 0; PrtElement->Length; Count++) + { + AcpiOsPrintf ("\n[%02X] PCI IRQ Routing Table Package\n", Count); + AcpiRsDumpDescriptor (PrtElement, AcpiRsDumpPrt); + + PrtElement = ACPI_ADD_PTR (ACPI_PCI_ROUTING_TABLE, + PrtElement, PrtElement->Length); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDumpDescriptor + * + * PARAMETERS: Resource - Buffer containing the resource + * Table - Table entry to decode the resource + * + * RETURN: None + * + * DESCRIPTION: Dump a resource descriptor based on a dump table entry. + * + ******************************************************************************/ + +static void +AcpiRsDumpDescriptor ( + void *Resource, + ACPI_RSDUMP_INFO *Table) +{ + UINT8 *Target = NULL; + UINT8 *PreviousTarget; + char *Name; + UINT8 Count; + + + /* First table entry must contain the table length (# of table entries) */ + + Count = Table->Offset; + + while (Count) + { + PreviousTarget = Target; + Target = ACPI_ADD_PTR (UINT8, Resource, Table->Offset); + Name = Table->Name; + + switch (Table->Opcode) + { + case ACPI_RSD_TITLE: + /* + * Optional resource title + */ + if (Table->Name) + { + AcpiOsPrintf ("%s Resource\n", Name); + } + break; + + /* Strings */ + + case ACPI_RSD_LITERAL: + + AcpiRsOutString (Name, ACPI_CAST_PTR (char, Table->Pointer)); + break; + + case ACPI_RSD_STRING: + + AcpiRsOutString (Name, ACPI_CAST_PTR (char, Target)); + break; + + /* Data items, 8/16/32/64 bit */ + + case ACPI_RSD_UINT8: + + if (Table->Pointer) + { + AcpiRsOutString (Name, ACPI_CAST_PTR (char, + Table->Pointer [*Target])); + } + else + { + AcpiRsOutInteger8 (Name, ACPI_GET8 (Target)); + } + break; + + case ACPI_RSD_UINT16: + + AcpiRsOutInteger16 (Name, ACPI_GET16 (Target)); + break; + + case ACPI_RSD_UINT32: + + AcpiRsOutInteger32 (Name, ACPI_GET32 (Target)); + break; + + case ACPI_RSD_UINT64: + + AcpiRsOutInteger64 (Name, ACPI_GET64 (Target)); + break; + + /* Flags: 1-bit and 2-bit flags supported */ + + case ACPI_RSD_1BITFLAG: + + AcpiRsOutString (Name, ACPI_CAST_PTR (char, + Table->Pointer [*Target & 0x01])); + break; + + case ACPI_RSD_2BITFLAG: + + AcpiRsOutString (Name, ACPI_CAST_PTR (char, + Table->Pointer [*Target & 0x03])); + break; + + case ACPI_RSD_3BITFLAG: + + AcpiRsOutString (Name, ACPI_CAST_PTR (char, + Table->Pointer [*Target & 0x07])); + break; + + case ACPI_RSD_SHORTLIST: + /* + * Short byte list (single line output) for DMA and IRQ resources + * Note: The list length is obtained from the previous table entry + */ + if (PreviousTarget) + { + AcpiRsOutTitle (Name); + AcpiRsDumpShortByteList (*PreviousTarget, Target); + } + break; + + case ACPI_RSD_SHORTLISTX: + /* + * Short byte list (single line output) for GPIO vendor data + * Note: The list length is obtained from the previous table entry + */ + if (PreviousTarget) + { + AcpiRsOutTitle (Name); + AcpiRsDumpShortByteList (*PreviousTarget, + *(ACPI_CAST_INDIRECT_PTR (UINT8, Target))); + } + break; + + case ACPI_RSD_LONGLIST: + /* + * Long byte list for Vendor resource data + * Note: The list length is obtained from the previous table entry + */ + if (PreviousTarget) + { + AcpiRsDumpByteList (ACPI_GET16 (PreviousTarget), Target); + } + break; + + case ACPI_RSD_DWORDLIST: + /* + * Dword list for Extended Interrupt resources + * Note: The list length is obtained from the previous table entry + */ + if (PreviousTarget) + { + AcpiRsDumpDwordList (*PreviousTarget, + ACPI_CAST_PTR (UINT32, Target)); + } + break; + + case ACPI_RSD_WORDLIST: + /* + * Word list for GPIO Pin Table + * Note: The list length is obtained from the previous table entry + */ + if (PreviousTarget) + { + AcpiRsDumpWordList (*PreviousTarget, + *(ACPI_CAST_INDIRECT_PTR (UINT16, Target))); + } + break; + + case ACPI_RSD_ADDRESS: + /* + * Common flags for all Address resources + */ + AcpiRsDumpAddressCommon (ACPI_CAST_PTR ( + ACPI_RESOURCE_DATA, Target)); + break; + + case ACPI_RSD_SOURCE: + /* + * Optional ResourceSource for Address resources + */ + AcpiRsDumpResourceSource (ACPI_CAST_PTR ( + ACPI_RESOURCE_SOURCE, Target)); + break; + + default: + + AcpiOsPrintf ("**** Invalid table opcode [%X] ****\n", + Table->Opcode); + return; + } + + Table++; + Count--; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDumpResourceSource + * + * PARAMETERS: ResourceSource - Pointer to a Resource Source struct + * + * RETURN: None + * + * DESCRIPTION: Common routine for dumping the optional ResourceSource and the + * corresponding ResourceSourceIndex. + * + ******************************************************************************/ + +static void +AcpiRsDumpResourceSource ( + ACPI_RESOURCE_SOURCE *ResourceSource) +{ + ACPI_FUNCTION_ENTRY (); + + + if (ResourceSource->Index == 0xFF) + { + return; + } + + AcpiRsOutInteger8 ("Resource Source Index", + ResourceSource->Index); + + AcpiRsOutString ("Resource Source", + ResourceSource->StringPtr ? + ResourceSource->StringPtr : "[Not Specified]"); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDumpAddressCommon + * + * PARAMETERS: Resource - Pointer to an internal resource descriptor + * + * RETURN: None + * + * DESCRIPTION: Dump the fields that are common to all Address resource + * descriptors + * + ******************************************************************************/ + +static void +AcpiRsDumpAddressCommon ( + ACPI_RESOURCE_DATA *Resource) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Decode the type-specific flags */ + + switch (Resource->Address.ResourceType) + { + case ACPI_MEMORY_RANGE: + + AcpiRsDumpDescriptor (Resource, AcpiRsDumpMemoryFlags); + break; + + case ACPI_IO_RANGE: + + AcpiRsDumpDescriptor (Resource, AcpiRsDumpIoFlags); + break; + + case ACPI_BUS_NUMBER_RANGE: + + AcpiRsOutString ("Resource Type", "Bus Number Range"); + break; + + default: + + AcpiRsOutInteger8 ("Resource Type", + (UINT8) Resource->Address.ResourceType); + break; + } + + /* Decode the general flags */ + + AcpiRsDumpDescriptor (Resource, AcpiRsDumpGeneralFlags); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsOut* + * + * PARAMETERS: Title - Name of the resource field + * Value - Value of the resource field + * + * RETURN: None + * + * DESCRIPTION: Miscellaneous helper functions to consistently format the + * output of the resource dump routines + * + ******************************************************************************/ + +static void +AcpiRsOutString ( + char *Title, + char *Value) +{ + + AcpiOsPrintf ("%27s : %s", Title, Value); + if (!*Value) + { + AcpiOsPrintf ("[NULL NAMESTRING]"); + } + AcpiOsPrintf ("\n"); +} + +static void +AcpiRsOutInteger8 ( + char *Title, + UINT8 Value) +{ + AcpiOsPrintf ("%27s : %2.2X\n", Title, Value); +} + +static void +AcpiRsOutInteger16 ( + char *Title, + UINT16 Value) +{ + + AcpiOsPrintf ("%27s : %4.4X\n", Title, Value); +} + +static void +AcpiRsOutInteger32 ( + char *Title, + UINT32 Value) +{ + + AcpiOsPrintf ("%27s : %8.8X\n", Title, Value); +} + +static void +AcpiRsOutInteger64 ( + char *Title, + UINT64 Value) +{ + + AcpiOsPrintf ("%27s : %8.8X%8.8X\n", Title, + ACPI_FORMAT_UINT64 (Value)); +} + +static void +AcpiRsOutTitle ( + char *Title) +{ + + AcpiOsPrintf ("%27s : ", Title); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDump*List + * + * PARAMETERS: Length - Number of elements in the list + * Data - Start of the list + * + * RETURN: None + * + * DESCRIPTION: Miscellaneous functions to dump lists of raw data + * + ******************************************************************************/ + +static void +AcpiRsDumpByteList ( + UINT16 Length, + UINT8 *Data) +{ + UINT8 i; + + + for (i = 0; i < Length; i++) + { + AcpiOsPrintf ("%25s%2.2X : %2.2X\n", "Byte", i, Data[i]); + } +} + +static void +AcpiRsDumpShortByteList ( + UINT8 Length, + UINT8 *Data) +{ + UINT8 i; + + + for (i = 0; i < Length; i++) + { + AcpiOsPrintf ("%X ", Data[i]); + } + + AcpiOsPrintf ("\n"); +} + +static void +AcpiRsDumpDwordList ( + UINT8 Length, + UINT32 *Data) +{ + UINT8 i; + + + for (i = 0; i < Length; i++) + { + AcpiOsPrintf ("%25s%2.2X : %8.8X\n", "Dword", i, Data[i]); + } +} + +static void +AcpiRsDumpWordList ( + UINT16 Length, + UINT16 *Data) +{ + UINT16 i; + + + for (i = 0; i < Length; i++) + { + AcpiOsPrintf ("%25s%2.2X : %4.4X\n", "Word", i, Data[i]); + } +} diff --git a/third_party/lib/acpica/source/components/resources/rsdumpinfo.c b/third_party/lib/acpica/source/components/resources/rsdumpinfo.c new file mode 100644 index 000000000..bec10dc05 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsdumpinfo.c @@ -0,0 +1,359 @@ +/******************************************************************************* + * + * Module Name: rsdumpinfo - Tables used to display resource descriptors. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsdumpinfo") + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER) + + +#define ACPI_RSD_OFFSET(f) (UINT8) ACPI_OFFSET (ACPI_RESOURCE_DATA,f) +#define ACPI_PRT_OFFSET(f) (UINT8) ACPI_OFFSET (ACPI_PCI_ROUTING_TABLE,f) +#define ACPI_RSD_TABLE_SIZE(name) (sizeof(name) / sizeof (ACPI_RSDUMP_INFO)) + + +/******************************************************************************* + * + * Resource Descriptor info tables + * + * Note: The first table entry must be a Title or Literal and must contain + * the table length (number of table entries) + * + ******************************************************************************/ + +ACPI_RSDUMP_INFO AcpiRsDumpIrq[7] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpIrq), "IRQ", NULL}, + {ACPI_RSD_UINT8 , ACPI_RSD_OFFSET (Irq.DescriptorLength), "Descriptor Length", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Irq.Triggering), "Triggering", AcpiGbl_HeDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Irq.Polarity), "Polarity", AcpiGbl_LlDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Irq.Sharable), "Sharing", AcpiGbl_ShrDecode}, + {ACPI_RSD_UINT8 , ACPI_RSD_OFFSET (Irq.InterruptCount), "Interrupt Count", NULL}, + {ACPI_RSD_SHORTLIST,ACPI_RSD_OFFSET (Irq.Interrupts[0]), "Interrupt List", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpDma[6] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpDma), "DMA", NULL}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Dma.Type), "Speed", AcpiGbl_TypDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Dma.BusMaster), "Mastering", AcpiGbl_BmDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Dma.Transfer), "Transfer Type", AcpiGbl_SizDecode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (Dma.ChannelCount), "Channel Count", NULL}, + {ACPI_RSD_SHORTLIST,ACPI_RSD_OFFSET (Dma.Channels[0]), "Channel List", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpStartDpf[4] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpStartDpf), "Start-Dependent-Functions",NULL}, + {ACPI_RSD_UINT8 , ACPI_RSD_OFFSET (StartDpf.DescriptorLength), "Descriptor Length", NULL}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (StartDpf.CompatibilityPriority), "Compatibility Priority", AcpiGbl_ConfigDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (StartDpf.PerformanceRobustness), "Performance/Robustness", AcpiGbl_ConfigDecode} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpEndDpf[1] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpEndDpf), "End-Dependent-Functions", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpIo[6] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpIo), "I/O", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Io.IoDecode), "Address Decoding", AcpiGbl_IoDecode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Io.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Io.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (Io.Alignment), "Alignment", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (Io.AddressLength), "Address Length", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpFixedIo[3] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpFixedIo), "Fixed I/O", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (FixedIo.Address), "Address", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (FixedIo.AddressLength), "Address Length", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpVendor[3] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpVendor), "Vendor Specific", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Vendor.ByteLength), "Length", NULL}, + {ACPI_RSD_LONGLIST, ACPI_RSD_OFFSET (Vendor.ByteData[0]), "Vendor Data", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpEndTag[1] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpEndTag), "EndTag", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpMemory24[6] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpMemory24), "24-Bit Memory Range", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Memory24.WriteProtect), "Write Protect", AcpiGbl_RwDecode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Memory24.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Memory24.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Memory24.Alignment), "Alignment", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Memory24.AddressLength), "Address Length", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpMemory32[6] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpMemory32), "32-Bit Memory Range", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Memory32.WriteProtect), "Write Protect", AcpiGbl_RwDecode}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Memory32.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Memory32.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Memory32.Alignment), "Alignment", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Memory32.AddressLength), "Address Length", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpFixedMemory32[4] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpFixedMemory32), "32-Bit Fixed Memory Range",NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (FixedMemory32.WriteProtect), "Write Protect", AcpiGbl_RwDecode}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (FixedMemory32.Address), "Address", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (FixedMemory32.AddressLength), "Address Length", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpAddress16[8] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpAddress16), "16-Bit WORD Address Space",NULL}, + {ACPI_RSD_ADDRESS, 0, NULL, NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.Granularity), "Granularity", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.TranslationOffset), + "Translation Offset", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.AddressLength), "Address Length", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Address16.ResourceSource), NULL, NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpAddress32[8] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpAddress32), "32-Bit DWORD Address Space", NULL}, + {ACPI_RSD_ADDRESS, 0, NULL, NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.Granularity), "Granularity", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.TranslationOffset), + "Translation Offset", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.AddressLength), "Address Length", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Address32.ResourceSource), NULL, NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpAddress64[8] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpAddress64), "64-Bit QWORD Address Space", NULL}, + {ACPI_RSD_ADDRESS, 0, NULL, NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.Granularity), "Granularity", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.TranslationOffset), + "Translation Offset", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.AddressLength), "Address Length", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Address64.ResourceSource), NULL, NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpExtAddress64[8] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpExtAddress64), "64-Bit Extended Address Space", NULL}, + {ACPI_RSD_ADDRESS, 0, NULL, NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.Granularity), "Granularity", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.Minimum), "Address Minimum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.Maximum), "Address Maximum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.TranslationOffset), + "Translation Offset", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.AddressLength), + "Address Length", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.TypeSpecific), "Type-Specific Attribute", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpExtIrq[8] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpExtIrq), "Extended IRQ", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (ExtendedIrq.ProducerConsumer), "Type", AcpiGbl_ConsumeDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (ExtendedIrq.Triggering), "Triggering", AcpiGbl_HeDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (ExtendedIrq.Polarity), "Polarity", AcpiGbl_LlDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (ExtendedIrq.Sharable), "Sharing", AcpiGbl_ShrDecode}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (ExtendedIrq.ResourceSource), NULL, NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (ExtendedIrq.InterruptCount), "Interrupt Count", NULL}, + {ACPI_RSD_DWORDLIST,ACPI_RSD_OFFSET (ExtendedIrq.Interrupts[0]), "Interrupt List", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpGenericReg[6] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpGenericReg), "Generic Register", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (GenericReg.SpaceId), "Space ID", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (GenericReg.BitWidth), "Bit Width", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (GenericReg.BitOffset), "Bit Offset", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (GenericReg.AccessSize), "Access Size", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (GenericReg.Address), "Address", NULL} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpGpio[16] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpGpio), "GPIO", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (Gpio.RevisionId), "RevisionId", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (Gpio.ConnectionType), "ConnectionType", AcpiGbl_CtDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Gpio.ProducerConsumer), "ProducerConsumer", AcpiGbl_ConsumeDecode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (Gpio.PinConfig), "PinConfig", AcpiGbl_PpcDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Gpio.Sharable), "Sharing", AcpiGbl_ShrDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Gpio.IoRestriction), "IoRestriction", AcpiGbl_IorDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Gpio.Triggering), "Triggering", AcpiGbl_HeDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Gpio.Polarity), "Polarity", AcpiGbl_LlDecode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Gpio.DriveStrength), "DriveStrength", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Gpio.DebounceTimeout), "DebounceTimeout", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Gpio.ResourceSource), "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Gpio.PinTableLength), "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET (Gpio.PinTable), "PinTable", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Gpio.VendorLength), "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (Gpio.VendorData), "VendorData", NULL}, +}; + +ACPI_RSDUMP_INFO AcpiRsDumpFixedDma[4] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpFixedDma), "FixedDma", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (FixedDma.RequestLines), "RequestLines", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (FixedDma.Channels), "Channels", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (FixedDma.Width), "TransferWidth", AcpiGbl_DtsDecode}, +}; + +#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (CommonSerialBus.RevisionId), "RevisionId", NULL}, \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (CommonSerialBus.Type), "Type", AcpiGbl_SbtDecode}, \ + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (CommonSerialBus.ProducerConsumer), "ProducerConsumer", AcpiGbl_ConsumeDecode}, \ + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (CommonSerialBus.SlaveMode), "SlaveMode", AcpiGbl_SmDecode}, \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (CommonSerialBus.TypeRevisionId), "TypeRevisionId", NULL}, \ + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (CommonSerialBus.TypeDataLength), "TypeDataLength", NULL}, \ + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (CommonSerialBus.ResourceSource), "ResourceSource", NULL}, \ + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (CommonSerialBus.VendorLength), "VendorLength", NULL}, \ + {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (CommonSerialBus.VendorData), "VendorData", NULL}, + +ACPI_RSDUMP_INFO AcpiRsDumpCommonSerialBus[10] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpCommonSerialBus), "Common Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS +}; + +ACPI_RSDUMP_INFO AcpiRsDumpI2cSerialBus[13] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpI2cSerialBus), "I2C Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (I2cSerialBus.AccessMode), "AccessMode", AcpiGbl_AmDecode}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (I2cSerialBus.ConnectionSpeed), "ConnectionSpeed", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (I2cSerialBus.SlaveAddress), "SlaveAddress", NULL}, +}; + +ACPI_RSDUMP_INFO AcpiRsDumpSpiSerialBus[17] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpSpiSerialBus), "Spi Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (SpiSerialBus.WireMode), "WireMode", AcpiGbl_WmDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (SpiSerialBus.DevicePolarity), "DevicePolarity", AcpiGbl_DpDecode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (SpiSerialBus.DataBitLength), "DataBitLength", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (SpiSerialBus.ClockPhase), "ClockPhase", AcpiGbl_CphDecode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (SpiSerialBus.ClockPolarity), "ClockPolarity", AcpiGbl_CpoDecode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (SpiSerialBus.DeviceSelection), "DeviceSelection", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (SpiSerialBus.ConnectionSpeed), "ConnectionSpeed", NULL}, +}; + +ACPI_RSDUMP_INFO AcpiRsDumpUartSerialBus[19] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpUartSerialBus), "Uart Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (UartSerialBus.FlowControl), "FlowControl", AcpiGbl_FcDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (UartSerialBus.StopBits), "StopBits", AcpiGbl_SbDecode}, + {ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET (UartSerialBus.DataBits), "DataBits", AcpiGbl_BpbDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (UartSerialBus.Endian), "Endian", AcpiGbl_EdDecode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (UartSerialBus.Parity), "Parity", AcpiGbl_PtDecode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (UartSerialBus.LinesEnabled), "LinesEnabled", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (UartSerialBus.RxFifoSize), "RxFifoSize", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (UartSerialBus.TxFifoSize), "TxFifoSize", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (UartSerialBus.DefaultBaudRate), "ConnectionSpeed", NULL}, +}; + +/* + * Tables used for common address descriptor flag fields + */ +ACPI_RSDUMP_INFO AcpiRsDumpGeneralFlags[5] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpGeneralFlags), NULL, NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.ProducerConsumer), "Consumer/Producer", AcpiGbl_ConsumeDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.Decode), "Address Decode", AcpiGbl_DecDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.MinAddressFixed), "Min Relocatability", AcpiGbl_MinDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.MaxAddressFixed), "Max Relocatability", AcpiGbl_MaxDecode} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpMemoryFlags[5] = +{ + {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE (AcpiRsDumpMemoryFlags), "Resource Type", (void *) "Memory Range"}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.Info.Mem.WriteProtect), "Write Protect", AcpiGbl_RwDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Address.Info.Mem.Caching), "Caching", AcpiGbl_MemDecode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Address.Info.Mem.RangeType), "Range Type", AcpiGbl_MtpDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.Info.Mem.Translation), "Translation", AcpiGbl_TtpDecode} +}; + +ACPI_RSDUMP_INFO AcpiRsDumpIoFlags[4] = +{ + {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE (AcpiRsDumpIoFlags), "Resource Type", (void *) "I/O Range"}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET (Address.Info.Io.RangeType), "Range Type", AcpiGbl_RngDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.Info.Io.Translation), "Translation", AcpiGbl_TtpDecode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (Address.Info.Io.TranslationType), "Translation Type", AcpiGbl_TrsDecode} +}; + + +/* + * Table used to dump _PRT contents + */ +ACPI_RSDUMP_INFO AcpiRsDumpPrt[5] = +{ + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpPrt), NULL, NULL}, + {ACPI_RSD_UINT64, ACPI_PRT_OFFSET (Address), "Address", NULL}, + {ACPI_RSD_UINT32, ACPI_PRT_OFFSET (Pin), "Pin", NULL}, + {ACPI_RSD_STRING, ACPI_PRT_OFFSET (Source[0]), "Source", NULL}, + {ACPI_RSD_UINT32, ACPI_PRT_OFFSET (SourceIndex), "Source Index", NULL} +}; + +#endif diff --git a/third_party/lib/acpica/source/components/resources/rsinfo.c b/third_party/lib/acpica/source/components/resources/rsinfo.c new file mode 100644 index 000000000..15f6105c8 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsinfo.c @@ -0,0 +1,263 @@ +/******************************************************************************* + * + * Module Name: rsinfo - Dispatch and Info tables + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsinfo") + +/* + * Resource dispatch and information tables. Any new resource types (either + * Large or Small) must be reflected in each of these tables, so they are here + * in one place. + * + * The tables for Large descriptors are indexed by bits 6:0 of the AML + * descriptor type byte. The tables for Small descriptors are indexed by + * bits 6:3 of the descriptor byte. The tables for internal resource + * descriptors are indexed by the ACPI_RESOURCE_TYPE field. + */ + + +/* Dispatch table for resource-to-AML (Set Resource) conversion functions */ + +ACPI_RSCONVERT_INFO *AcpiGbl_SetResourceDispatch[] = +{ + AcpiRsSetIrq, /* 0x00, ACPI_RESOURCE_TYPE_IRQ */ + AcpiRsConvertDma, /* 0x01, ACPI_RESOURCE_TYPE_DMA */ + AcpiRsSetStartDpf, /* 0x02, ACPI_RESOURCE_TYPE_START_DEPENDENT */ + AcpiRsConvertEndDpf, /* 0x03, ACPI_RESOURCE_TYPE_END_DEPENDENT */ + AcpiRsConvertIo, /* 0x04, ACPI_RESOURCE_TYPE_IO */ + AcpiRsConvertFixedIo, /* 0x05, ACPI_RESOURCE_TYPE_FIXED_IO */ + AcpiRsSetVendor, /* 0x06, ACPI_RESOURCE_TYPE_VENDOR */ + AcpiRsConvertEndTag, /* 0x07, ACPI_RESOURCE_TYPE_END_TAG */ + AcpiRsConvertMemory24, /* 0x08, ACPI_RESOURCE_TYPE_MEMORY24 */ + AcpiRsConvertMemory32, /* 0x09, ACPI_RESOURCE_TYPE_MEMORY32 */ + AcpiRsConvertFixedMemory32, /* 0x0A, ACPI_RESOURCE_TYPE_FIXED_MEMORY32 */ + AcpiRsConvertAddress16, /* 0x0B, ACPI_RESOURCE_TYPE_ADDRESS16 */ + AcpiRsConvertAddress32, /* 0x0C, ACPI_RESOURCE_TYPE_ADDRESS32 */ + AcpiRsConvertAddress64, /* 0x0D, ACPI_RESOURCE_TYPE_ADDRESS64 */ + AcpiRsConvertExtAddress64, /* 0x0E, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ + AcpiRsConvertExtIrq, /* 0x0F, ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ + AcpiRsConvertGenericReg, /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + AcpiRsConvertGpio, /* 0x11, ACPI_RESOURCE_TYPE_GPIO */ + AcpiRsConvertFixedDma, /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */ + NULL, /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */ +}; + +/* Dispatch tables for AML-to-resource (Get Resource) conversion functions */ + +ACPI_RSCONVERT_INFO *AcpiGbl_GetResourceDispatch[] = +{ + /* Small descriptors */ + + NULL, /* 0x00, Reserved */ + NULL, /* 0x01, Reserved */ + NULL, /* 0x02, Reserved */ + NULL, /* 0x03, Reserved */ + AcpiRsGetIrq, /* 0x04, ACPI_RESOURCE_NAME_IRQ */ + AcpiRsConvertDma, /* 0x05, ACPI_RESOURCE_NAME_DMA */ + AcpiRsGetStartDpf, /* 0x06, ACPI_RESOURCE_NAME_START_DEPENDENT */ + AcpiRsConvertEndDpf, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */ + AcpiRsConvertIo, /* 0x08, ACPI_RESOURCE_NAME_IO */ + AcpiRsConvertFixedIo, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO */ + AcpiRsConvertFixedDma, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */ + NULL, /* 0x0B, Reserved */ + NULL, /* 0x0C, Reserved */ + NULL, /* 0x0D, Reserved */ + AcpiRsGetVendorSmall, /* 0x0E, ACPI_RESOURCE_NAME_VENDOR_SMALL */ + AcpiRsConvertEndTag, /* 0x0F, ACPI_RESOURCE_NAME_END_TAG */ + + /* Large descriptors */ + + NULL, /* 0x00, Reserved */ + AcpiRsConvertMemory24, /* 0x01, ACPI_RESOURCE_NAME_MEMORY24 */ + AcpiRsConvertGenericReg, /* 0x02, ACPI_RESOURCE_NAME_GENERIC_REGISTER */ + NULL, /* 0x03, Reserved */ + AcpiRsGetVendorLarge, /* 0x04, ACPI_RESOURCE_NAME_VENDOR_LARGE */ + AcpiRsConvertMemory32, /* 0x05, ACPI_RESOURCE_NAME_MEMORY32 */ + AcpiRsConvertFixedMemory32, /* 0x06, ACPI_RESOURCE_NAME_FIXED_MEMORY32 */ + AcpiRsConvertAddress32, /* 0x07, ACPI_RESOURCE_NAME_ADDRESS32 */ + AcpiRsConvertAddress16, /* 0x08, ACPI_RESOURCE_NAME_ADDRESS16 */ + AcpiRsConvertExtIrq, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_IRQ */ + AcpiRsConvertAddress64, /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */ + AcpiRsConvertExtAddress64, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ + AcpiRsConvertGpio, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ + NULL, /* 0x0D, Reserved */ + NULL, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */ +}; + +/* Subtype table for SerialBus -- I2C, SPI, and UART */ + +ACPI_RSCONVERT_INFO *AcpiGbl_ConvertResourceSerialBusDispatch[] = +{ + NULL, + AcpiRsConvertI2cSerialBus, + AcpiRsConvertSpiSerialBus, + AcpiRsConvertUartSerialBus, +}; + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER) + +/* Dispatch table for resource dump functions */ + +ACPI_RSDUMP_INFO *AcpiGbl_DumpResourceDispatch[] = +{ + AcpiRsDumpIrq, /* ACPI_RESOURCE_TYPE_IRQ */ + AcpiRsDumpDma, /* ACPI_RESOURCE_TYPE_DMA */ + AcpiRsDumpStartDpf, /* ACPI_RESOURCE_TYPE_START_DEPENDENT */ + AcpiRsDumpEndDpf, /* ACPI_RESOURCE_TYPE_END_DEPENDENT */ + AcpiRsDumpIo, /* ACPI_RESOURCE_TYPE_IO */ + AcpiRsDumpFixedIo, /* ACPI_RESOURCE_TYPE_FIXED_IO */ + AcpiRsDumpVendor, /* ACPI_RESOURCE_TYPE_VENDOR */ + AcpiRsDumpEndTag, /* ACPI_RESOURCE_TYPE_END_TAG */ + AcpiRsDumpMemory24, /* ACPI_RESOURCE_TYPE_MEMORY24 */ + AcpiRsDumpMemory32, /* ACPI_RESOURCE_TYPE_MEMORY32 */ + AcpiRsDumpFixedMemory32, /* ACPI_RESOURCE_TYPE_FIXED_MEMORY32 */ + AcpiRsDumpAddress16, /* ACPI_RESOURCE_TYPE_ADDRESS16 */ + AcpiRsDumpAddress32, /* ACPI_RESOURCE_TYPE_ADDRESS32 */ + AcpiRsDumpAddress64, /* ACPI_RESOURCE_TYPE_ADDRESS64 */ + AcpiRsDumpExtAddress64, /* ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ + AcpiRsDumpExtIrq, /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ + AcpiRsDumpGenericReg, /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + AcpiRsDumpGpio, /* ACPI_RESOURCE_TYPE_GPIO */ + AcpiRsDumpFixedDma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */ + NULL, /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ +}; + +ACPI_RSDUMP_INFO *AcpiGbl_DumpSerialBusDispatch[] = +{ + NULL, + AcpiRsDumpI2cSerialBus, /* AML_RESOURCE_I2C_BUS_TYPE */ + AcpiRsDumpSpiSerialBus, /* AML_RESOURCE_SPI_BUS_TYPE */ + AcpiRsDumpUartSerialBus, /* AML_RESOURCE_UART_BUS_TYPE */ +}; +#endif + + +/* + * Base sizes for external AML resource descriptors, indexed by internal type. + * Includes size of the descriptor header (1 byte for small descriptors, + * 3 bytes for large descriptors) + */ +const UINT8 AcpiGbl_AmlResourceSizes[] = +{ + sizeof (AML_RESOURCE_IRQ), /* ACPI_RESOURCE_TYPE_IRQ (optional Byte 3 always created) */ + sizeof (AML_RESOURCE_DMA), /* ACPI_RESOURCE_TYPE_DMA */ + sizeof (AML_RESOURCE_START_DEPENDENT), /* ACPI_RESOURCE_TYPE_START_DEPENDENT (optional Byte 1 always created) */ + sizeof (AML_RESOURCE_END_DEPENDENT), /* ACPI_RESOURCE_TYPE_END_DEPENDENT */ + sizeof (AML_RESOURCE_IO), /* ACPI_RESOURCE_TYPE_IO */ + sizeof (AML_RESOURCE_FIXED_IO), /* ACPI_RESOURCE_TYPE_FIXED_IO */ + sizeof (AML_RESOURCE_VENDOR_SMALL), /* ACPI_RESOURCE_TYPE_VENDOR */ + sizeof (AML_RESOURCE_END_TAG), /* ACPI_RESOURCE_TYPE_END_TAG */ + sizeof (AML_RESOURCE_MEMORY24), /* ACPI_RESOURCE_TYPE_MEMORY24 */ + sizeof (AML_RESOURCE_MEMORY32), /* ACPI_RESOURCE_TYPE_MEMORY32 */ + sizeof (AML_RESOURCE_FIXED_MEMORY32), /* ACPI_RESOURCE_TYPE_FIXED_MEMORY32 */ + sizeof (AML_RESOURCE_ADDRESS16), /* ACPI_RESOURCE_TYPE_ADDRESS16 */ + sizeof (AML_RESOURCE_ADDRESS32), /* ACPI_RESOURCE_TYPE_ADDRESS32 */ + sizeof (AML_RESOURCE_ADDRESS64), /* ACPI_RESOURCE_TYPE_ADDRESS64 */ + sizeof (AML_RESOURCE_EXTENDED_ADDRESS64),/*ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ + sizeof (AML_RESOURCE_EXTENDED_IRQ), /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ + sizeof (AML_RESOURCE_GENERIC_REGISTER), /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + sizeof (AML_RESOURCE_GPIO), /* ACPI_RESOURCE_TYPE_GPIO */ + sizeof (AML_RESOURCE_FIXED_DMA), /* ACPI_RESOURCE_TYPE_FIXED_DMA */ + sizeof (AML_RESOURCE_COMMON_SERIALBUS), /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ +}; + + +const UINT8 AcpiGbl_ResourceStructSizes[] = +{ + /* Small descriptors */ + + 0, + 0, + 0, + 0, + ACPI_RS_SIZE (ACPI_RESOURCE_IRQ), + ACPI_RS_SIZE (ACPI_RESOURCE_DMA), + ACPI_RS_SIZE (ACPI_RESOURCE_START_DEPENDENT), + ACPI_RS_SIZE_MIN, + ACPI_RS_SIZE (ACPI_RESOURCE_IO), + ACPI_RS_SIZE (ACPI_RESOURCE_FIXED_IO), + ACPI_RS_SIZE (ACPI_RESOURCE_FIXED_DMA), + 0, + 0, + 0, + ACPI_RS_SIZE (ACPI_RESOURCE_VENDOR), + ACPI_RS_SIZE_MIN, + + /* Large descriptors */ + + 0, + ACPI_RS_SIZE (ACPI_RESOURCE_MEMORY24), + ACPI_RS_SIZE (ACPI_RESOURCE_GENERIC_REGISTER), + 0, + ACPI_RS_SIZE (ACPI_RESOURCE_VENDOR), + ACPI_RS_SIZE (ACPI_RESOURCE_MEMORY32), + ACPI_RS_SIZE (ACPI_RESOURCE_FIXED_MEMORY32), + ACPI_RS_SIZE (ACPI_RESOURCE_ADDRESS32), + ACPI_RS_SIZE (ACPI_RESOURCE_ADDRESS16), + ACPI_RS_SIZE (ACPI_RESOURCE_EXTENDED_IRQ), + ACPI_RS_SIZE (ACPI_RESOURCE_ADDRESS64), + ACPI_RS_SIZE (ACPI_RESOURCE_EXTENDED_ADDRESS64), + ACPI_RS_SIZE (ACPI_RESOURCE_GPIO), + ACPI_RS_SIZE (ACPI_RESOURCE_COMMON_SERIALBUS) +}; + +const UINT8 AcpiGbl_AmlResourceSerialBusSizes[] = +{ + 0, + sizeof (AML_RESOURCE_I2C_SERIALBUS), + sizeof (AML_RESOURCE_SPI_SERIALBUS), + sizeof (AML_RESOURCE_UART_SERIALBUS), +}; + +const UINT8 AcpiGbl_ResourceStructSerialBusSizes[] = +{ + 0, + ACPI_RS_SIZE (ACPI_RESOURCE_I2C_SERIALBUS), + ACPI_RS_SIZE (ACPI_RESOURCE_SPI_SERIALBUS), + ACPI_RS_SIZE (ACPI_RESOURCE_UART_SERIALBUS), +}; diff --git a/third_party/lib/acpica/source/components/resources/rsio.c b/third_party/lib/acpica/source/components/resources/rsio.c new file mode 100644 index 000000000..442a7b8b3 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsio.c @@ -0,0 +1,300 @@ +/******************************************************************************* + * + * Module Name: rsio - IO and DMA resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsio") + + +/******************************************************************************* + * + * AcpiRsConvertIo + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertIo[5] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IO, + ACPI_RS_SIZE (ACPI_RESOURCE_IO), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertIo)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IO, + sizeof (AML_RESOURCE_IO), + 0}, + + /* Decode flag */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Io.IoDecode), + AML_OFFSET (Io.Flags), + 0}, + /* + * These fields are contiguous in both the source and destination: + * Address Alignment + * Length + * Minimum Base Address + * Maximum Base Address + */ + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Io.Alignment), + AML_OFFSET (Io.Alignment), + 2}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.Io.Minimum), + AML_OFFSET (Io.Minimum), + 2} +}; + + +/******************************************************************************* + * + * AcpiRsConvertFixedIo + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertFixedIo[4] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_IO, + ACPI_RS_SIZE (ACPI_RESOURCE_FIXED_IO), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertFixedIo)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_IO, + sizeof (AML_RESOURCE_FIXED_IO), + 0}, + /* + * These fields are contiguous in both the source and destination: + * Base Address + * Length + */ + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.FixedIo.AddressLength), + AML_OFFSET (FixedIo.AddressLength), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.FixedIo.Address), + AML_OFFSET (FixedIo.Address), + 1} +}; + + +/******************************************************************************* + * + * AcpiRsConvertGenericReg + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertGenericReg[4] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GENERIC_REGISTER, + ACPI_RS_SIZE (ACPI_RESOURCE_GENERIC_REGISTER), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertGenericReg)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GENERIC_REGISTER, + sizeof (AML_RESOURCE_GENERIC_REGISTER), + 0}, + /* + * These fields are contiguous in both the source and destination: + * Address Space ID + * Register Bit Width + * Register Bit Offset + * Access Size + */ + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.GenericReg.SpaceId), + AML_OFFSET (GenericReg.AddressSpaceId), + 4}, + + /* Get the Register Address */ + + {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.GenericReg.Address), + AML_OFFSET (GenericReg.Address), + 1} +}; + + +/******************************************************************************* + * + * AcpiRsConvertEndDpf + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertEndDpf[2] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_END_DEPENDENT, + ACPI_RS_SIZE_MIN, + ACPI_RSC_TABLE_SIZE (AcpiRsConvertEndDpf)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_END_DEPENDENT, + sizeof (AML_RESOURCE_END_DEPENDENT), + 0} +}; + + +/******************************************************************************* + * + * AcpiRsConvertEndTag + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertEndTag[2] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_END_TAG, + ACPI_RS_SIZE_MIN, + ACPI_RSC_TABLE_SIZE (AcpiRsConvertEndTag)}, + + /* + * Note: The checksum field is set to zero, meaning that the resource + * data is treated as if the checksum operation succeeded. + * (ACPI Spec 1.0b Section 6.4.2.8) + */ + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_END_TAG, + sizeof (AML_RESOURCE_END_TAG), + 0} +}; + + +/******************************************************************************* + * + * AcpiRsGetStartDpf + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsGetStartDpf[6] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT, + ACPI_RS_SIZE (ACPI_RESOURCE_START_DEPENDENT), + ACPI_RSC_TABLE_SIZE (AcpiRsGetStartDpf)}, + + /* Defaults for Compatibility and Performance priorities */ + + {ACPI_RSC_SET8, ACPI_RS_OFFSET (Data.StartDpf.CompatibilityPriority), + ACPI_ACCEPTABLE_CONFIGURATION, + 2}, + + /* Get the descriptor length (0 or 1 for Start Dpf descriptor) */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.StartDpf.DescriptorLength), + AML_OFFSET (StartDpf.DescriptorType), + 0}, + + /* All done if there is no flag byte present in the descriptor */ + + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1}, + + /* Flag byte is present, get the flags */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.StartDpf.CompatibilityPriority), + AML_OFFSET (StartDpf.Flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.StartDpf.PerformanceRobustness), + AML_OFFSET (StartDpf.Flags), + 2} +}; + + +/******************************************************************************* + * + * AcpiRsSetStartDpf + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsSetStartDpf[10] = +{ + /* Start with a default descriptor of length 1 */ + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT, + sizeof (AML_RESOURCE_START_DEPENDENT), + ACPI_RSC_TABLE_SIZE (AcpiRsSetStartDpf)}, + + /* Set the default flag values */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.StartDpf.CompatibilityPriority), + AML_OFFSET (StartDpf.Flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.StartDpf.PerformanceRobustness), + AML_OFFSET (StartDpf.Flags), + 2}, + /* + * All done if the output descriptor length is required to be 1 + * (i.e., optimization to 0 bytes cannot be attempted) + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(Data.StartDpf.DescriptorLength), + 1}, + + /* Set length to 0 bytes (no flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof (AML_RESOURCE_START_DEPENDENT_NOPRIO)}, + + /* + * All done if the output descriptor length is required to be 0. + * + * TBD: Perhaps we should check for error if input flags are not + * compatible with a 0-byte descriptor. + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(Data.StartDpf.DescriptorLength), + 0}, + + /* Reset length to 1 byte (descriptor with flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof (AML_RESOURCE_START_DEPENDENT)}, + + + /* + * All done if flags byte is necessary -- if either priority value + * is not ACPI_ACCEPTABLE_CONFIGURATION + */ + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET (Data.StartDpf.CompatibilityPriority), + ACPI_ACCEPTABLE_CONFIGURATION}, + + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET (Data.StartDpf.PerformanceRobustness), + ACPI_ACCEPTABLE_CONFIGURATION}, + + /* Flag byte is not necessary */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof (AML_RESOURCE_START_DEPENDENT_NOPRIO)} +}; diff --git a/third_party/lib/acpica/source/components/resources/rsirq.c b/third_party/lib/acpica/source/components/resources/rsirq.c new file mode 100644 index 000000000..d094a9bfd --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsirq.c @@ -0,0 +1,318 @@ +/******************************************************************************* + * + * Module Name: rsirq - IRQ resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsirq") + + +/******************************************************************************* + * + * AcpiRsGetIrq + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsGetIrq[9] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ, + ACPI_RS_SIZE (ACPI_RESOURCE_IRQ), + ACPI_RSC_TABLE_SIZE (AcpiRsGetIrq)}, + + /* Get the IRQ mask (bytes 1:2) */ + + {ACPI_RSC_BITMASK16,ACPI_RS_OFFSET (Data.Irq.Interrupts[0]), + AML_OFFSET (Irq.IrqMask), + ACPI_RS_OFFSET (Data.Irq.InterruptCount)}, + + /* Set default flags (others are zero) */ + + {ACPI_RSC_SET8, ACPI_RS_OFFSET (Data.Irq.Triggering), + ACPI_EDGE_SENSITIVE, + 1}, + + /* Get the descriptor length (2 or 3 for IRQ descriptor) */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Irq.DescriptorLength), + AML_OFFSET (Irq.DescriptorType), + 0}, + + /* All done if no flag byte present in descriptor */ + + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3}, + + /* Get flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.Triggering), + AML_OFFSET (Irq.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.Polarity), + AML_OFFSET (Irq.Flags), + 3}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.Sharable), + AML_OFFSET (Irq.Flags), + 4}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.WakeCapable), + AML_OFFSET (Irq.Flags), + 5} +}; + + +/******************************************************************************* + * + * AcpiRsSetIrq + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsSetIrq[14] = +{ + /* Start with a default descriptor of length 3 */ + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ, + sizeof (AML_RESOURCE_IRQ), + ACPI_RSC_TABLE_SIZE (AcpiRsSetIrq)}, + + /* Convert interrupt list to 16-bit IRQ bitmask */ + + {ACPI_RSC_BITMASK16,ACPI_RS_OFFSET (Data.Irq.Interrupts[0]), + AML_OFFSET (Irq.IrqMask), + ACPI_RS_OFFSET (Data.Irq.InterruptCount)}, + + /* Set flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.Triggering), + AML_OFFSET (Irq.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.Polarity), + AML_OFFSET (Irq.Flags), + 3}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.Sharable), + AML_OFFSET (Irq.Flags), + 4}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Irq.WakeCapable), + AML_OFFSET (Irq.Flags), + 5}, + + /* + * All done if the output descriptor length is required to be 3 + * (i.e., optimization to 2 bytes cannot be attempted) + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(Data.Irq.DescriptorLength), + 3}, + + /* Set length to 2 bytes (no flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof (AML_RESOURCE_IRQ_NOFLAGS)}, + + /* + * All done if the output descriptor length is required to be 2. + * + * TBD: Perhaps we should check for error if input flags are not + * compatible with a 2-byte descriptor. + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(Data.Irq.DescriptorLength), + 2}, + + /* Reset length to 3 bytes (descriptor with flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof (AML_RESOURCE_IRQ)}, + + /* + * Check if the flags byte is necessary. Not needed if the flags are: + * ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE + */ + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET (Data.Irq.Triggering), + ACPI_EDGE_SENSITIVE}, + + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET (Data.Irq.Polarity), + ACPI_ACTIVE_HIGH}, + + {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET (Data.Irq.Sharable), + ACPI_EXCLUSIVE}, + + /* We can optimize to a 2-byte IrqNoFlags() descriptor */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof (AML_RESOURCE_IRQ_NOFLAGS)} +}; + + +/******************************************************************************* + * + * AcpiRsConvertExtIrq + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertExtIrq[10] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_EXTENDED_IRQ, + ACPI_RS_SIZE (ACPI_RESOURCE_EXTENDED_IRQ), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertExtIrq)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_EXTENDED_IRQ, + sizeof (AML_RESOURCE_EXTENDED_IRQ), + 0}, + + /* + * Flags: Producer/Consumer[0], Triggering[1], Polarity[2], + * Sharing[3], Wake[4] + */ + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.ExtendedIrq.ProducerConsumer), + AML_OFFSET (ExtendedIrq.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.ExtendedIrq.Triggering), + AML_OFFSET (ExtendedIrq.Flags), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.ExtendedIrq.Polarity), + AML_OFFSET (ExtendedIrq.Flags), + 2}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.ExtendedIrq.Sharable), + AML_OFFSET (ExtendedIrq.Flags), + 3}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.ExtendedIrq.WakeCapable), + AML_OFFSET (ExtendedIrq.Flags), + 4}, + + /* IRQ Table length (Byte4) */ + + {ACPI_RSC_COUNT, ACPI_RS_OFFSET (Data.ExtendedIrq.InterruptCount), + AML_OFFSET (ExtendedIrq.InterruptCount), + sizeof (UINT32)}, + + /* Copy every IRQ in the table, each is 32 bits */ + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.ExtendedIrq.Interrupts[0]), + AML_OFFSET (ExtendedIrq.Interrupts[0]), + 0}, + + /* Optional ResourceSource (Index and String) */ + + {ACPI_RSC_SOURCEX, ACPI_RS_OFFSET (Data.ExtendedIrq.ResourceSource), + ACPI_RS_OFFSET (Data.ExtendedIrq.Interrupts[0]), + sizeof (AML_RESOURCE_EXTENDED_IRQ)} +}; + + +/******************************************************************************* + * + * AcpiRsConvertDma + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertDma[6] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_DMA, + ACPI_RS_SIZE (ACPI_RESOURCE_DMA), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertDma)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_DMA, + sizeof (AML_RESOURCE_DMA), + 0}, + + /* Flags: transfer preference, bus mastering, channel speed */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Dma.Transfer), + AML_OFFSET (Dma.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Dma.BusMaster), + AML_OFFSET (Dma.Flags), + 2}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Dma.Type), + AML_OFFSET (Dma.Flags), + 5}, + + /* DMA channel mask bits */ + + {ACPI_RSC_BITMASK, ACPI_RS_OFFSET (Data.Dma.Channels[0]), + AML_OFFSET (Dma.DmaChannelMask), + ACPI_RS_OFFSET (Data.Dma.ChannelCount)} +}; + + +/******************************************************************************* + * + * AcpiRsConvertFixedDma + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertFixedDma[4] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_DMA, + ACPI_RS_SIZE (ACPI_RESOURCE_FIXED_DMA), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertFixedDma)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_DMA, + sizeof (AML_RESOURCE_FIXED_DMA), + 0}, + + /* + * These fields are contiguous in both the source and destination: + * RequestLines + * Channels + */ + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.FixedDma.RequestLines), + AML_OFFSET (FixedDma.RequestLines), + 2}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.FixedDma.Width), + AML_OFFSET (FixedDma.Width), + 1}, +}; diff --git a/third_party/lib/acpica/source/components/resources/rslist.c b/third_party/lib/acpica/source/components/resources/rslist.c new file mode 100644 index 000000000..0f7a49603 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rslist.c @@ -0,0 +1,282 @@ +/******************************************************************************* + * + * Module Name: rslist - Linked list utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rslist") + + +/******************************************************************************* + * + * FUNCTION: AcpiRsConvertAmlToResources + * + * PARAMETERS: ACPI_WALK_AML_CALLBACK + * ResourcePtr - Pointer to the buffer that will + * contain the output structures + * + * RETURN: Status + * + * DESCRIPTION: Convert an AML resource to an internal representation of the + * resource that is aligned and easier to access. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsConvertAmlToResources ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context) +{ + ACPI_RESOURCE **ResourcePtr = ACPI_CAST_INDIRECT_PTR ( + ACPI_RESOURCE, Context); + ACPI_RESOURCE *Resource; + AML_RESOURCE *AmlResource; + ACPI_RSCONVERT_INFO *ConversionTable; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsConvertAmlToResources); + + + /* + * Check that the input buffer and all subsequent pointers into it + * are aligned on a native word boundary. Most important on IA64 + */ + Resource = *ResourcePtr; + if (ACPI_IS_MISALIGNED (Resource)) + { + ACPI_WARNING ((AE_INFO, + "Misaligned resource pointer %p", Resource)); + } + + /* Get the appropriate conversion info table */ + + AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml); + + if (AcpiUtGetResourceType (Aml) == + ACPI_RESOURCE_NAME_SERIAL_BUS) + { + if (AmlResource->CommonSerialBus.Type > + AML_RESOURCE_MAX_SERIALBUSTYPE) + { + ConversionTable = NULL; + } + else + { + /* This is an I2C, SPI, or UART SerialBus descriptor */ + + ConversionTable = AcpiGbl_ConvertResourceSerialBusDispatch [ + AmlResource->CommonSerialBus.Type]; + } + } + else + { + ConversionTable = AcpiGbl_GetResourceDispatch[ResourceIndex]; + } + + if (!ConversionTable) + { + ACPI_ERROR ((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + ResourceIndex)); + return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); + } + + /* Convert the AML byte stream resource to a local resource struct */ + + Status = AcpiRsConvertAmlToResource ( + Resource, AmlResource, ConversionTable); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not convert AML resource (Type 0x%X)", *Aml)); + return_ACPI_STATUS (Status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, + "Type %.2X, AmlLength %.2X InternalLength %.2X\n", + AcpiUtGetResourceType (Aml), Length, + Resource->Length)); + + /* Point to the next structure in the output buffer */ + + *ResourcePtr = ACPI_NEXT_RESOURCE (Resource); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsConvertResourcesToAml + * + * PARAMETERS: Resource - Pointer to the resource linked list + * AmlSizeNeeded - Calculated size of the byte stream + * needed from calling AcpiRsGetAmlLength() + * The size of the OutputBuffer is + * guaranteed to be >= AmlSizeNeeded + * OutputBuffer - Pointer to the buffer that will + * contain the byte stream + * + * RETURN: Status + * + * DESCRIPTION: Takes the resource linked list and parses it, creating a + * byte stream of resources in the caller's output buffer + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsConvertResourcesToAml ( + ACPI_RESOURCE *Resource, + ACPI_SIZE AmlSizeNeeded, + UINT8 *OutputBuffer) +{ + UINT8 *Aml = OutputBuffer; + UINT8 *EndAml = OutputBuffer + AmlSizeNeeded; + ACPI_RSCONVERT_INFO *ConversionTable; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsConvertResourcesToAml); + + + /* Walk the resource descriptor list, convert each descriptor */ + + while (Aml < EndAml) + { + /* Validate the (internal) Resource Type */ + + if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) + { + ACPI_ERROR ((AE_INFO, + "Invalid descriptor type (0x%X) in resource list", + Resource->Type)); + return_ACPI_STATUS (AE_BAD_DATA); + } + + /* Sanity check the length. It must not be zero, or we loop forever */ + + if (!Resource->Length) + { + ACPI_ERROR ((AE_INFO, + "Invalid zero length descriptor in resource list\n")); + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); + } + + /* Perform the conversion */ + + if (Resource->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS) + { + if (Resource->Data.CommonSerialBus.Type > + AML_RESOURCE_MAX_SERIALBUSTYPE) + { + ConversionTable = NULL; + } + else + { + /* This is an I2C, SPI, or UART SerialBus descriptor */ + + ConversionTable = AcpiGbl_ConvertResourceSerialBusDispatch[ + Resource->Data.CommonSerialBus.Type]; + } + } + else + { + ConversionTable = AcpiGbl_SetResourceDispatch[Resource->Type]; + } + + if (!ConversionTable) + { + ACPI_ERROR ((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + Resource->Type)); + return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); + } + + Status = AcpiRsConvertResourceToAml (Resource, + ACPI_CAST_PTR (AML_RESOURCE, Aml), ConversionTable); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not convert resource (type 0x%X) to AML", + Resource->Type)); + return_ACPI_STATUS (Status); + } + + /* Perform final sanity check on the new AML resource descriptor */ + + Status = AcpiUtValidateResource ( + NULL, ACPI_CAST_PTR (AML_RESOURCE, Aml), NULL); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Check for end-of-list, normal exit */ + + if (Resource->Type == ACPI_RESOURCE_TYPE_END_TAG) + { + /* An End Tag indicates the end of the input Resource Template */ + + return_ACPI_STATUS (AE_OK); + } + + /* + * Extract the total length of the new descriptor and set the + * Aml to point to the next (output) resource descriptor + */ + Aml += AcpiUtGetDescriptorLength (Aml); + + /* Point to the next input resource descriptor */ + + Resource = ACPI_NEXT_RESOURCE (Resource); + } + + /* Completed buffer, but did not find an EndTag resource descriptor */ + + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); +} diff --git a/third_party/lib/acpica/source/components/resources/rsmemory.c b/third_party/lib/acpica/source/components/resources/rsmemory.c new file mode 100644 index 000000000..90e58fc20 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsmemory.c @@ -0,0 +1,247 @@ +/******************************************************************************* + * + * Module Name: rsmem24 - Memory resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsmemory") + + +/******************************************************************************* + * + * AcpiRsConvertMemory24 + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertMemory24[4] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_MEMORY24, + ACPI_RS_SIZE (ACPI_RESOURCE_MEMORY24), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertMemory24)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_MEMORY24, + sizeof (AML_RESOURCE_MEMORY24), + 0}, + + /* Read/Write bit */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Memory24.WriteProtect), + AML_OFFSET (Memory24.Flags), + 0}, + /* + * These fields are contiguous in both the source and destination: + * Minimum Base Address + * Maximum Base Address + * Address Base Alignment + * Range Length + */ + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.Memory24.Minimum), + AML_OFFSET (Memory24.Minimum), + 4} +}; + + +/******************************************************************************* + * + * AcpiRsConvertMemory32 + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertMemory32[4] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_MEMORY32, + ACPI_RS_SIZE (ACPI_RESOURCE_MEMORY32), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertMemory32)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_MEMORY32, + sizeof (AML_RESOURCE_MEMORY32), + 0}, + + /* Read/Write bit */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Memory32.WriteProtect), + AML_OFFSET (Memory32.Flags), + 0}, + /* + * These fields are contiguous in both the source and destination: + * Minimum Base Address + * Maximum Base Address + * Address Base Alignment + * Range Length + */ + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.Memory32.Minimum), + AML_OFFSET (Memory32.Minimum), + 4} +}; + + +/******************************************************************************* + * + * AcpiRsConvertFixedMemory32 + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertFixedMemory32[4] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_MEMORY32, + ACPI_RS_SIZE (ACPI_RESOURCE_FIXED_MEMORY32), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertFixedMemory32)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_MEMORY32, + sizeof (AML_RESOURCE_FIXED_MEMORY32), + 0}, + + /* Read/Write bit */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.FixedMemory32.WriteProtect), + AML_OFFSET (FixedMemory32.Flags), + 0}, + /* + * These fields are contiguous in both the source and destination: + * Base Address + * Range Length + */ + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.FixedMemory32.Address), + AML_OFFSET (FixedMemory32.Address), + 2} +}; + + +/******************************************************************************* + * + * AcpiRsGetVendorSmall + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsGetVendorSmall[3] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_VENDOR, + ACPI_RS_SIZE (ACPI_RESOURCE_VENDOR), + ACPI_RSC_TABLE_SIZE (AcpiRsGetVendorSmall)}, + + /* Length of the vendor data (byte count) */ + + {ACPI_RSC_COUNT16, ACPI_RS_OFFSET (Data.Vendor.ByteLength), + 0, + sizeof (UINT8)}, + + /* Vendor data */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Vendor.ByteData[0]), + sizeof (AML_RESOURCE_SMALL_HEADER), + 0} +}; + + +/******************************************************************************* + * + * AcpiRsGetVendorLarge + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsGetVendorLarge[3] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_VENDOR, + ACPI_RS_SIZE (ACPI_RESOURCE_VENDOR), + ACPI_RSC_TABLE_SIZE (AcpiRsGetVendorLarge)}, + + /* Length of the vendor data (byte count) */ + + {ACPI_RSC_COUNT16, ACPI_RS_OFFSET (Data.Vendor.ByteLength), + 0, + sizeof (UINT8)}, + + /* Vendor data */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Vendor.ByteData[0]), + sizeof (AML_RESOURCE_LARGE_HEADER), + 0} +}; + + +/******************************************************************************* + * + * AcpiRsSetVendor + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsSetVendor[7] = +{ + /* Default is a small vendor descriptor */ + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_VENDOR_SMALL, + sizeof (AML_RESOURCE_SMALL_HEADER), + ACPI_RSC_TABLE_SIZE (AcpiRsSetVendor)}, + + /* Get the length and copy the data */ + + {ACPI_RSC_COUNT16, ACPI_RS_OFFSET (Data.Vendor.ByteLength), + 0, + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Vendor.ByteData[0]), + sizeof (AML_RESOURCE_SMALL_HEADER), + 0}, + + /* + * All done if the Vendor byte length is 7 or less, meaning that it will + * fit within a small descriptor + */ + {ACPI_RSC_EXIT_LE, 0, 0, 7}, + + /* Must create a large vendor descriptor */ + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_VENDOR_LARGE, + sizeof (AML_RESOURCE_LARGE_HEADER), + 0}, + + {ACPI_RSC_COUNT16, ACPI_RS_OFFSET (Data.Vendor.ByteLength), + 0, + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Vendor.ByteData[0]), + sizeof (AML_RESOURCE_LARGE_HEADER), + 0} +}; diff --git a/third_party/lib/acpica/source/components/resources/rsmisc.c b/third_party/lib/acpica/source/components/resources/rsmisc.c new file mode 100644 index 000000000..73019a9b6 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsmisc.c @@ -0,0 +1,817 @@ +/******************************************************************************* + * + * Module Name: rsmisc - Miscellaneous resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsmisc") + + +#define INIT_RESOURCE_TYPE(i) i->ResourceOffset +#define INIT_RESOURCE_LENGTH(i) i->AmlOffset +#define INIT_TABLE_LENGTH(i) i->Value + +#define COMPARE_OPCODE(i) i->ResourceOffset +#define COMPARE_TARGET(i) i->AmlOffset +#define COMPARE_VALUE(i) i->Value + + +/******************************************************************************* + * + * FUNCTION: AcpiRsConvertAmlToResource + * + * PARAMETERS: Resource - Pointer to the resource descriptor + * Aml - Where the AML descriptor is returned + * Info - Pointer to appropriate conversion table + * + * RETURN: Status + * + * DESCRIPTION: Convert an external AML resource descriptor to the corresponding + * internal resource descriptor + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsConvertAmlToResource ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml, + ACPI_RSCONVERT_INFO *Info) +{ + ACPI_RS_LENGTH AmlResourceLength; + void *Source; + void *Destination; + char *Target; + UINT8 Count; + UINT8 FlagsMode = FALSE; + UINT16 ItemCount = 0; + UINT16 Temp16 = 0; + + + ACPI_FUNCTION_TRACE (RsConvertAmlToResource); + + + if (!Info) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (((ACPI_SIZE) Resource) & 0x3) + { + /* Each internal resource struct is expected to be 32-bit aligned */ + + ACPI_WARNING ((AE_INFO, + "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u", + Resource, Resource->Type, Resource->Length)); + } + + /* Extract the resource Length field (does not include header length) */ + + AmlResourceLength = AcpiUtGetResourceLength (Aml); + + /* + * First table entry must be ACPI_RSC_INITxxx and must contain the + * table length (# of table entries) + */ + Count = INIT_TABLE_LENGTH (Info); + while (Count) + { + /* + * Source is the external AML byte stream buffer, + * destination is the internal resource descriptor + */ + Source = ACPI_ADD_PTR (void, Aml, Info->AmlOffset); + Destination = ACPI_ADD_PTR (void, Resource, Info->ResourceOffset); + + switch (Info->Opcode) + { + case ACPI_RSC_INITGET: + /* + * Get the resource type and the initial (minimum) length + */ + memset (Resource, 0, INIT_RESOURCE_LENGTH (Info)); + Resource->Type = INIT_RESOURCE_TYPE (Info); + Resource->Length = INIT_RESOURCE_LENGTH (Info); + break; + + case ACPI_RSC_INITSET: + break; + + case ACPI_RSC_FLAGINIT: + + FlagsMode = TRUE; + break; + + case ACPI_RSC_1BITFLAG: + /* + * Mask and shift the flag bit + */ + ACPI_SET8 (Destination, + ((ACPI_GET8 (Source) >> Info->Value) & 0x01)); + break; + + case ACPI_RSC_2BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8 (Destination, + ((ACPI_GET8 (Source) >> Info->Value) & 0x03)); + break; + + case ACPI_RSC_3BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8 (Destination, + ((ACPI_GET8 (Source) >> Info->Value) & 0x07)); + break; + + case ACPI_RSC_COUNT: + + ItemCount = ACPI_GET8 (Source); + ACPI_SET8 (Destination, ItemCount); + + Resource->Length = Resource->Length + + (Info->Value * (ItemCount - 1)); + break; + + case ACPI_RSC_COUNT16: + + ItemCount = AmlResourceLength; + ACPI_SET16 (Destination, ItemCount); + + Resource->Length = Resource->Length + + (Info->Value * (ItemCount - 1)); + break; + + case ACPI_RSC_COUNT_GPIO_PIN: + + Target = ACPI_ADD_PTR (void, Aml, Info->Value); + ItemCount = ACPI_GET16 (Target) - ACPI_GET16 (Source); + + Resource->Length = Resource->Length + ItemCount; + ItemCount = ItemCount / 2; + ACPI_SET16 (Destination, ItemCount); + break; + + case ACPI_RSC_COUNT_GPIO_VEN: + + ItemCount = ACPI_GET8 (Source); + ACPI_SET8 (Destination, ItemCount); + + Resource->Length = Resource->Length + (Info->Value * ItemCount); + break; + + case ACPI_RSC_COUNT_GPIO_RES: + /* + * Vendor data is optional (length/offset may both be zero) + * Examine vendor data length field first + */ + Target = ACPI_ADD_PTR (void, Aml, (Info->Value + 2)); + if (ACPI_GET16 (Target)) + { + /* Use vendor offset to get resource source length */ + + Target = ACPI_ADD_PTR (void, Aml, Info->Value); + ItemCount = ACPI_GET16 (Target) - ACPI_GET16 (Source); + } + else + { + /* No vendor data to worry about */ + + ItemCount = Aml->LargeHeader.ResourceLength + + sizeof (AML_RESOURCE_LARGE_HEADER) - + ACPI_GET16 (Source); + } + + Resource->Length = Resource->Length + ItemCount; + ACPI_SET16 (Destination, ItemCount); + break; + + case ACPI_RSC_COUNT_SERIAL_VEN: + + ItemCount = ACPI_GET16 (Source) - Info->Value; + + Resource->Length = Resource->Length + ItemCount; + ACPI_SET16 (Destination, ItemCount); + break; + + case ACPI_RSC_COUNT_SERIAL_RES: + + ItemCount = (AmlResourceLength + + sizeof (AML_RESOURCE_LARGE_HEADER)) - + ACPI_GET16 (Source) - Info->Value; + + Resource->Length = Resource->Length + ItemCount; + ACPI_SET16 (Destination, ItemCount); + break; + + case ACPI_RSC_LENGTH: + + Resource->Length = Resource->Length + Info->Value; + break; + + case ACPI_RSC_MOVE8: + case ACPI_RSC_MOVE16: + case ACPI_RSC_MOVE32: + case ACPI_RSC_MOVE64: + /* + * Raw data move. Use the Info value field unless ItemCount has + * been previously initialized via a COUNT opcode + */ + if (Info->Value) + { + ItemCount = Info->Value; + } + AcpiRsMoveData (Destination, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_GPIO_PIN: + + /* Generate and set the PIN data pointer */ + + Target = (char *) ACPI_ADD_PTR (void, Resource, + (Resource->Length - ItemCount * 2)); + *(UINT16 **) Destination = ACPI_CAST_PTR (UINT16, Target); + + /* Copy the PIN data */ + + Source = ACPI_ADD_PTR (void, Aml, ACPI_GET16 (Source)); + AcpiRsMoveData (Target, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_GPIO_RES: + + /* Generate and set the ResourceSource string pointer */ + + Target = (char *) ACPI_ADD_PTR (void, Resource, + (Resource->Length - ItemCount)); + *(UINT8 **) Destination = ACPI_CAST_PTR (UINT8, Target); + + /* Copy the ResourceSource string */ + + Source = ACPI_ADD_PTR (void, Aml, ACPI_GET16 (Source)); + AcpiRsMoveData (Target, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_VEN: + + /* Generate and set the Vendor Data pointer */ + + Target = (char *) ACPI_ADD_PTR (void, Resource, + (Resource->Length - ItemCount)); + *(UINT8 **) Destination = ACPI_CAST_PTR (UINT8, Target); + + /* Copy the Vendor Data */ + + Source = ACPI_ADD_PTR (void, Aml, Info->Value); + AcpiRsMoveData (Target, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_RES: + + /* Generate and set the ResourceSource string pointer */ + + Target = (char *) ACPI_ADD_PTR (void, Resource, + (Resource->Length - ItemCount)); + *(UINT8 **) Destination = ACPI_CAST_PTR (UINT8, Target); + + /* Copy the ResourceSource string */ + + Source = ACPI_ADD_PTR ( + void, Aml, (ACPI_GET16 (Source) + Info->Value)); + AcpiRsMoveData (Target, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_SET8: + + memset (Destination, Info->AmlOffset, Info->Value); + break; + + case ACPI_RSC_DATA8: + + Target = ACPI_ADD_PTR (char, Resource, Info->Value); + memcpy (Destination, Source, ACPI_GET16 (Target)); + break; + + case ACPI_RSC_ADDRESS: + /* + * Common handler for address descriptor flags + */ + if (!AcpiRsGetAddressCommon (Resource, Aml)) + { + return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); + } + break; + + case ACPI_RSC_SOURCE: + /* + * Optional ResourceSource (Index and String) + */ + Resource->Length += + AcpiRsGetResourceSource (AmlResourceLength, Info->Value, + Destination, Aml, NULL); + break; + + case ACPI_RSC_SOURCEX: + /* + * Optional ResourceSource (Index and String). This is the more + * complicated case used by the Interrupt() macro + */ + Target = ACPI_ADD_PTR (char, Resource, + Info->AmlOffset + (ItemCount * 4)); + + Resource->Length += + AcpiRsGetResourceSource (AmlResourceLength, (ACPI_RS_LENGTH) + (((ItemCount - 1) * sizeof (UINT32)) + Info->Value), + Destination, Aml, Target); + break; + + case ACPI_RSC_BITMASK: + /* + * 8-bit encoded bitmask (DMA macro) + */ + ItemCount = AcpiRsDecodeBitmask (ACPI_GET8 (Source), Destination); + if (ItemCount) + { + Resource->Length += (ItemCount - 1); + } + + Target = ACPI_ADD_PTR (char, Resource, Info->Value); + ACPI_SET8 (Target, ItemCount); + break; + + case ACPI_RSC_BITMASK16: + /* + * 16-bit encoded bitmask (IRQ macro) + */ + ACPI_MOVE_16_TO_16 (&Temp16, Source); + + ItemCount = AcpiRsDecodeBitmask (Temp16, Destination); + if (ItemCount) + { + Resource->Length += (ItemCount - 1); + } + + Target = ACPI_ADD_PTR (char, Resource, Info->Value); + ACPI_SET8 (Target, ItemCount); + break; + + case ACPI_RSC_EXIT_NE: + /* + * Control - Exit conversion if not equal + */ + switch (Info->ResourceOffset) + { + case ACPI_RSC_COMPARE_AML_LENGTH: + + if (AmlResourceLength != Info->Value) + { + goto Exit; + } + break; + + case ACPI_RSC_COMPARE_VALUE: + + if (ACPI_GET8 (Source) != Info->Value) + { + goto Exit; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid conversion sub-opcode")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid conversion opcode")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Count--; + Info++; + } + +Exit: + if (!FlagsMode) + { + /* Round the resource struct length up to the next boundary (32 or 64) */ + + Resource->Length = (UINT32) + ACPI_ROUND_UP_TO_NATIVE_WORD (Resource->Length); + } + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsConvertResourceToAml + * + * PARAMETERS: Resource - Pointer to the resource descriptor + * Aml - Where the AML descriptor is returned + * Info - Pointer to appropriate conversion table + * + * RETURN: Status + * + * DESCRIPTION: Convert an internal resource descriptor to the corresponding + * external AML resource descriptor. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsConvertResourceToAml ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml, + ACPI_RSCONVERT_INFO *Info) +{ + void *Source = NULL; + void *Destination; + char *Target; + ACPI_RSDESC_SIZE AmlLength = 0; + UINT8 Count; + UINT16 Temp16 = 0; + UINT16 ItemCount = 0; + + + ACPI_FUNCTION_TRACE (RsConvertResourceToAml); + + + if (!Info) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * First table entry must be ACPI_RSC_INITxxx and must contain the + * table length (# of table entries) + */ + Count = INIT_TABLE_LENGTH (Info); + + while (Count) + { + /* + * Source is the internal resource descriptor, + * destination is the external AML byte stream buffer + */ + Source = ACPI_ADD_PTR (void, Resource, Info->ResourceOffset); + Destination = ACPI_ADD_PTR (void, Aml, Info->AmlOffset); + + switch (Info->Opcode) + { + case ACPI_RSC_INITSET: + + memset (Aml, 0, INIT_RESOURCE_LENGTH (Info)); + AmlLength = INIT_RESOURCE_LENGTH (Info); + AcpiRsSetResourceHeader ( + INIT_RESOURCE_TYPE (Info), AmlLength, Aml); + break; + + case ACPI_RSC_INITGET: + break; + + case ACPI_RSC_FLAGINIT: + /* + * Clear the flag byte + */ + ACPI_SET8 (Destination, 0); + break; + + case ACPI_RSC_1BITFLAG: + /* + * Mask and shift the flag bit + */ + ACPI_SET_BIT (*ACPI_CAST8 (Destination), (UINT8) + ((ACPI_GET8 (Source) & 0x01) << Info->Value)); + break; + + case ACPI_RSC_2BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET_BIT (*ACPI_CAST8 (Destination), (UINT8) + ((ACPI_GET8 (Source) & 0x03) << Info->Value)); + break; + + case ACPI_RSC_3BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET_BIT (*ACPI_CAST8 (Destination), (UINT8) + ((ACPI_GET8 (Source) & 0x07) << Info->Value)); + break; + + case ACPI_RSC_COUNT: + + ItemCount = ACPI_GET8 (Source); + ACPI_SET8 (Destination, ItemCount); + + AmlLength = (UINT16) + (AmlLength + (Info->Value * (ItemCount - 1))); + break; + + case ACPI_RSC_COUNT16: + + ItemCount = ACPI_GET16 (Source); + AmlLength = (UINT16) (AmlLength + ItemCount); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_COUNT_GPIO_PIN: + + ItemCount = ACPI_GET16 (Source); + ACPI_SET16 (Destination, AmlLength); + + AmlLength = (UINT16) (AmlLength + ItemCount * 2); + Target = ACPI_ADD_PTR (void, Aml, Info->Value); + ACPI_SET16 (Target, AmlLength); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_COUNT_GPIO_VEN: + + ItemCount = ACPI_GET16 (Source); + ACPI_SET16 (Destination, ItemCount); + + AmlLength = (UINT16) ( + AmlLength + (Info->Value * ItemCount)); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_COUNT_GPIO_RES: + + /* Set resource source string length */ + + ItemCount = ACPI_GET16 (Source); + ACPI_SET16 (Destination, AmlLength); + + /* Compute offset for the Vendor Data */ + + AmlLength = (UINT16) (AmlLength + ItemCount); + Target = ACPI_ADD_PTR (void, Aml, Info->Value); + + /* Set vendor offset only if there is vendor data */ + + if (Resource->Data.Gpio.VendorLength) + { + ACPI_SET16 (Target, AmlLength); + } + + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_COUNT_SERIAL_VEN: + + ItemCount = ACPI_GET16 (Source); + ACPI_SET16 (Destination, ItemCount + Info->Value); + AmlLength = (UINT16) (AmlLength + ItemCount); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_COUNT_SERIAL_RES: + + ItemCount = ACPI_GET16 (Source); + AmlLength = (UINT16) (AmlLength + ItemCount); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_LENGTH: + + AcpiRsSetResourceLength (Info->Value, Aml); + break; + + case ACPI_RSC_MOVE8: + case ACPI_RSC_MOVE16: + case ACPI_RSC_MOVE32: + case ACPI_RSC_MOVE64: + + if (Info->Value) + { + ItemCount = Info->Value; + } + AcpiRsMoveData (Destination, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_GPIO_PIN: + + Destination = (char *) ACPI_ADD_PTR (void, Aml, + ACPI_GET16 (Destination)); + Source = * (UINT16 **) Source; + AcpiRsMoveData (Destination, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_GPIO_RES: + + /* Used for both ResourceSource string and VendorData */ + + Destination = (char *) ACPI_ADD_PTR (void, Aml, + ACPI_GET16 (Destination)); + Source = * (UINT8 **) Source; + AcpiRsMoveData (Destination, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_VEN: + + Destination = (char *) ACPI_ADD_PTR (void, Aml, + (AmlLength - ItemCount)); + Source = * (UINT8 **) Source; + AcpiRsMoveData (Destination, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_RES: + + Destination = (char *) ACPI_ADD_PTR (void, Aml, + (AmlLength - ItemCount)); + Source = * (UINT8 **) Source; + AcpiRsMoveData (Destination, Source, ItemCount, Info->Opcode); + break; + + case ACPI_RSC_ADDRESS: + + /* Set the Resource Type, General Flags, and Type-Specific Flags */ + + AcpiRsSetAddressCommon (Aml, Resource); + break; + + case ACPI_RSC_SOURCEX: + /* + * Optional ResourceSource (Index and String) + */ + AmlLength = AcpiRsSetResourceSource ( + Aml, (ACPI_RS_LENGTH) AmlLength, Source); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_SOURCE: + /* + * Optional ResourceSource (Index and String). This is the more + * complicated case used by the Interrupt() macro + */ + AmlLength = AcpiRsSetResourceSource (Aml, Info->Value, Source); + AcpiRsSetResourceLength (AmlLength, Aml); + break; + + case ACPI_RSC_BITMASK: + /* + * 8-bit encoded bitmask (DMA macro) + */ + ACPI_SET8 (Destination, + AcpiRsEncodeBitmask (Source, + *ACPI_ADD_PTR (UINT8, Resource, Info->Value))); + break; + + case ACPI_RSC_BITMASK16: + /* + * 16-bit encoded bitmask (IRQ macro) + */ + Temp16 = AcpiRsEncodeBitmask ( + Source, *ACPI_ADD_PTR (UINT8, Resource, Info->Value)); + ACPI_MOVE_16_TO_16 (Destination, &Temp16); + break; + + case ACPI_RSC_EXIT_LE: + /* + * Control - Exit conversion if less than or equal + */ + if (ItemCount <= Info->Value) + { + goto Exit; + } + break; + + case ACPI_RSC_EXIT_NE: + /* + * Control - Exit conversion if not equal + */ + switch (COMPARE_OPCODE (Info)) + { + case ACPI_RSC_COMPARE_VALUE: + + if (*ACPI_ADD_PTR (UINT8, Resource, + COMPARE_TARGET (Info)) != COMPARE_VALUE (Info)) + { + goto Exit; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid conversion sub-opcode")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + break; + + case ACPI_RSC_EXIT_EQ: + /* + * Control - Exit conversion if equal + */ + if (*ACPI_ADD_PTR (UINT8, Resource, + COMPARE_TARGET (Info)) == COMPARE_VALUE (Info)) + { + goto Exit; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Invalid conversion opcode")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Count--; + Info++; + } + +Exit: + return_ACPI_STATUS (AE_OK); +} + + +#if 0 +/* Previous resource validations */ + + if (Aml->ExtAddress64.RevisionID != + AML_RESOURCE_EXTENDED_ADDRESS_REVISION) + { + return_ACPI_STATUS (AE_SUPPORT); + } + + if (Resource->Data.StartDpf.PerformanceRobustness >= 3) + { + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE); + } + + if (((Aml->Irq.Flags & 0x09) == 0x00) || + ((Aml->Irq.Flags & 0x09) == 0x09)) + { + /* + * Only [ActiveHigh, EdgeSensitive] or [ActiveLow, LevelSensitive] + * polarity/trigger interrupts are allowed (ACPI spec, section + * "IRQ Format"), so 0x00 and 0x09 are illegal. + */ + ACPI_ERROR ((AE_INFO, + "Invalid interrupt polarity/trigger in resource list, 0x%X", + Aml->Irq.Flags)); + return_ACPI_STATUS (AE_BAD_DATA); + } + + Resource->Data.ExtendedIrq.InterruptCount = Temp8; + if (Temp8 < 1) + { + /* Must have at least one IRQ */ + + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); + } + + if (Resource->Data.Dma.Transfer == 0x03) + { + ACPI_ERROR ((AE_INFO, + "Invalid DMA.Transfer preference (3)")); + return_ACPI_STATUS (AE_BAD_DATA); + } +#endif diff --git a/third_party/lib/acpica/source/components/resources/rsserial.c b/third_party/lib/acpica/source/components/resources/rsserial.c new file mode 100644 index 000000000..bbc69000b --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsserial.c @@ -0,0 +1,427 @@ +/******************************************************************************* + * + * Module Name: rsserial - GPIO/SerialBus resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsserial") + + +/******************************************************************************* + * + * AcpiRsConvertGpio + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertGpio[18] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO, + ACPI_RS_SIZE (ACPI_RESOURCE_GPIO), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertGpio)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GPIO, + sizeof (AML_RESOURCE_GPIO), + 0}, + + /* + * These fields are contiguous in both the source and destination: + * RevisionId + * ConnectionType + */ + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Gpio.RevisionId), + AML_OFFSET (Gpio.RevisionId), + 2}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Gpio.ProducerConsumer), + AML_OFFSET (Gpio.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Gpio.Sharable), + AML_OFFSET (Gpio.IntFlags), + 3}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Gpio.WakeCapable), + AML_OFFSET (Gpio.IntFlags), + 4}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Gpio.IoRestriction), + AML_OFFSET (Gpio.IntFlags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.Gpio.Triggering), + AML_OFFSET (Gpio.IntFlags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.Gpio.Polarity), + AML_OFFSET (Gpio.IntFlags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Gpio.PinConfig), + AML_OFFSET (Gpio.PinConfig), + 1}, + + /* + * These fields are contiguous in both the source and destination: + * DriveStrength + * DebounceTimeout + */ + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.Gpio.DriveStrength), + AML_OFFSET (Gpio.DriveStrength), + 2}, + + /* Pin Table */ + + {ACPI_RSC_COUNT_GPIO_PIN, ACPI_RS_OFFSET (Data.Gpio.PinTableLength), + AML_OFFSET (Gpio.PinTableOffset), + AML_OFFSET (Gpio.ResSourceOffset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET (Data.Gpio.PinTable), + AML_OFFSET (Gpio.PinTableOffset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.Gpio.ResourceSource.Index), + AML_OFFSET (Gpio.ResSourceIndex), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, ACPI_RS_OFFSET (Data.Gpio.ResourceSource.StringLength), + AML_OFFSET (Gpio.ResSourceOffset), + AML_OFFSET (Gpio.VendorOffset)}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET (Data.Gpio.ResourceSource.StringPtr), + AML_OFFSET (Gpio.ResSourceOffset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET (Data.Gpio.VendorLength), + AML_OFFSET (Gpio.VendorLength), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET (Data.Gpio.VendorData), + AML_OFFSET (Gpio.VendorOffset), + 0}, +}; + + +/******************************************************************************* + * + * AcpiRsConvertI2cSerialBus + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertI2cSerialBus[16] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE (ACPI_RESOURCE_I2C_SERIALBUS), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertI2cSerialBus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof (AML_RESOURCE_I2C_SERIALBUS), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.RevisionId), + AML_OFFSET (CommonSerialBus.RevisionId), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.Type), + AML_OFFSET (CommonSerialBus.Type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.CommonSerialBus.SlaveMode), + AML_OFFSET (CommonSerialBus.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.CommonSerialBus.ProducerConsumer), + AML_OFFSET (CommonSerialBus.Flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.TypeRevisionId), + AML_OFFSET (CommonSerialBus.TypeRevisionId), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.CommonSerialBus.TypeDataLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, ACPI_RS_OFFSET (Data.CommonSerialBus.VendorLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + AML_RESOURCE_I2C_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, ACPI_RS_OFFSET (Data.CommonSerialBus.VendorData), + 0, + sizeof (AML_RESOURCE_I2C_SERIALBUS)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.Index), + AML_OFFSET (CommonSerialBus.ResSourceIndex), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.StringLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + sizeof (AML_RESOURCE_COMMON_SERIALBUS)}, + + {ACPI_RSC_MOVE_SERIAL_RES, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.StringPtr), + AML_OFFSET (CommonSerialBus.TypeDataLength), + sizeof (AML_RESOURCE_COMMON_SERIALBUS)}, + + /* I2C bus type specific */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.I2cSerialBus.AccessMode), + AML_OFFSET (I2cSerialBus.TypeSpecificFlags), + 0}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.I2cSerialBus.ConnectionSpeed), + AML_OFFSET (I2cSerialBus.ConnectionSpeed), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.I2cSerialBus.SlaveAddress), + AML_OFFSET (I2cSerialBus.SlaveAddress), + 1}, +}; + + +/******************************************************************************* + * + * AcpiRsConvertSpiSerialBus + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertSpiSerialBus[20] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE (ACPI_RESOURCE_SPI_SERIALBUS), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertSpiSerialBus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof (AML_RESOURCE_SPI_SERIALBUS), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.RevisionId), + AML_OFFSET (CommonSerialBus.RevisionId), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.Type), + AML_OFFSET (CommonSerialBus.Type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.CommonSerialBus.SlaveMode), + AML_OFFSET (CommonSerialBus.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.CommonSerialBus.ProducerConsumer), + AML_OFFSET (CommonSerialBus.Flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.TypeRevisionId), + AML_OFFSET (CommonSerialBus.TypeRevisionId), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.CommonSerialBus.TypeDataLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, ACPI_RS_OFFSET (Data.CommonSerialBus.VendorLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + AML_RESOURCE_SPI_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, ACPI_RS_OFFSET (Data.CommonSerialBus.VendorData), + 0, + sizeof (AML_RESOURCE_SPI_SERIALBUS)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.Index), + AML_OFFSET (CommonSerialBus.ResSourceIndex), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.StringLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + sizeof (AML_RESOURCE_COMMON_SERIALBUS)}, + + {ACPI_RSC_MOVE_SERIAL_RES, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.StringPtr), + AML_OFFSET (CommonSerialBus.TypeDataLength), + sizeof (AML_RESOURCE_COMMON_SERIALBUS)}, + + /* Spi bus type specific */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.SpiSerialBus.WireMode), + AML_OFFSET (SpiSerialBus.TypeSpecificFlags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.SpiSerialBus.DevicePolarity), + AML_OFFSET (SpiSerialBus.TypeSpecificFlags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.SpiSerialBus.DataBitLength), + AML_OFFSET (SpiSerialBus.DataBitLength), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.SpiSerialBus.ClockPhase), + AML_OFFSET (SpiSerialBus.ClockPhase), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.SpiSerialBus.ClockPolarity), + AML_OFFSET (SpiSerialBus.ClockPolarity), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.SpiSerialBus.DeviceSelection), + AML_OFFSET (SpiSerialBus.DeviceSelection), + 1}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.SpiSerialBus.ConnectionSpeed), + AML_OFFSET (SpiSerialBus.ConnectionSpeed), + 1}, +}; + + +/******************************************************************************* + * + * AcpiRsConvertUartSerialBus + * + ******************************************************************************/ + +ACPI_RSCONVERT_INFO AcpiRsConvertUartSerialBus[22] = +{ + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE (ACPI_RESOURCE_UART_SERIALBUS), + ACPI_RSC_TABLE_SIZE (AcpiRsConvertUartSerialBus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof (AML_RESOURCE_UART_SERIALBUS), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.RevisionId), + AML_OFFSET (CommonSerialBus.RevisionId), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.Type), + AML_OFFSET (CommonSerialBus.Type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.CommonSerialBus.SlaveMode), + AML_OFFSET (CommonSerialBus.Flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.CommonSerialBus.ProducerConsumer), + AML_OFFSET (CommonSerialBus.Flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.TypeRevisionId), + AML_OFFSET (CommonSerialBus.TypeRevisionId), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.CommonSerialBus.TypeDataLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, ACPI_RS_OFFSET (Data.CommonSerialBus.VendorLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + AML_RESOURCE_UART_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, ACPI_RS_OFFSET (Data.CommonSerialBus.VendorData), + 0, + sizeof (AML_RESOURCE_UART_SERIALBUS)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.Index), + AML_OFFSET (CommonSerialBus.ResSourceIndex), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.StringLength), + AML_OFFSET (CommonSerialBus.TypeDataLength), + sizeof (AML_RESOURCE_COMMON_SERIALBUS)}, + + {ACPI_RSC_MOVE_SERIAL_RES, ACPI_RS_OFFSET (Data.CommonSerialBus.ResourceSource.StringPtr), + AML_OFFSET (CommonSerialBus.TypeDataLength), + sizeof (AML_RESOURCE_COMMON_SERIALBUS)}, + + /* Uart bus type specific */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.UartSerialBus.FlowControl), + AML_OFFSET (UartSerialBus.TypeSpecificFlags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET (Data.UartSerialBus.StopBits), + AML_OFFSET (UartSerialBus.TypeSpecificFlags), + 2}, + + {ACPI_RSC_3BITFLAG, ACPI_RS_OFFSET (Data.UartSerialBus.DataBits), + AML_OFFSET (UartSerialBus.TypeSpecificFlags), + 4}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET (Data.UartSerialBus.Endian), + AML_OFFSET (UartSerialBus.TypeSpecificFlags), + 7}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.UartSerialBus.Parity), + AML_OFFSET (UartSerialBus.Parity), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET (Data.UartSerialBus.LinesEnabled), + AML_OFFSET (UartSerialBus.LinesEnabled), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.UartSerialBus.RxFifoSize), + AML_OFFSET (UartSerialBus.RxFifoSize), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.UartSerialBus.TxFifoSize), + AML_OFFSET (UartSerialBus.TxFifoSize), + 1}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.UartSerialBus.DefaultBaudRate), + AML_OFFSET (UartSerialBus.DefaultBaudRate), + 1}, +}; diff --git a/third_party/lib/acpica/source/components/resources/rsutils.c b/third_party/lib/acpica/source/components/resources/rsutils.c new file mode 100644 index 000000000..fbd1c4662 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsutils.c @@ -0,0 +1,870 @@ +/******************************************************************************* + * + * Module Name: rsutils - Utilities for the resource manager + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acresrc.h" + + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsutils") + + +/******************************************************************************* + * + * FUNCTION: AcpiRsDecodeBitmask + * + * PARAMETERS: Mask - Bitmask to decode + * List - Where the converted list is returned + * + * RETURN: Count of bits set (length of list) + * + * DESCRIPTION: Convert a bit mask into a list of values + * + ******************************************************************************/ + +UINT8 +AcpiRsDecodeBitmask ( + UINT16 Mask, + UINT8 *List) +{ + UINT8 i; + UINT8 BitCount; + + + ACPI_FUNCTION_ENTRY (); + + + /* Decode the mask bits */ + + for (i = 0, BitCount = 0; Mask; i++) + { + if (Mask & 0x0001) + { + List[BitCount] = i; + BitCount++; + } + + Mask >>= 1; + } + + return (BitCount); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsEncodeBitmask + * + * PARAMETERS: List - List of values to encode + * Count - Length of list + * + * RETURN: Encoded bitmask + * + * DESCRIPTION: Convert a list of values to an encoded bitmask + * + ******************************************************************************/ + +UINT16 +AcpiRsEncodeBitmask ( + UINT8 *List, + UINT8 Count) +{ + UINT32 i; + UINT16 Mask; + + + ACPI_FUNCTION_ENTRY (); + + + /* Encode the list into a single bitmask */ + + for (i = 0, Mask = 0; i < Count; i++) + { + Mask |= (0x1 << List[i]); + } + + return (Mask); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsMoveData + * + * PARAMETERS: Destination - Pointer to the destination descriptor + * Source - Pointer to the source descriptor + * ItemCount - How many items to move + * MoveType - Byte width + * + * RETURN: None + * + * DESCRIPTION: Move multiple data items from one descriptor to another. Handles + * alignment issues and endian issues if necessary, as configured + * via the ACPI_MOVE_* macros. (This is why a memcpy is not used) + * + ******************************************************************************/ + +void +AcpiRsMoveData ( + void *Destination, + void *Source, + UINT16 ItemCount, + UINT8 MoveType) +{ + UINT32 i; + + + ACPI_FUNCTION_ENTRY (); + + + /* One move per item */ + + for (i = 0; i < ItemCount; i++) + { + switch (MoveType) + { + /* + * For the 8-bit case, we can perform the move all at once + * since there are no alignment or endian issues + */ + case ACPI_RSC_MOVE8: + case ACPI_RSC_MOVE_GPIO_RES: + case ACPI_RSC_MOVE_SERIAL_VEN: + case ACPI_RSC_MOVE_SERIAL_RES: + + memcpy (Destination, Source, ItemCount); + return; + + /* + * 16-, 32-, and 64-bit cases must use the move macros that perform + * endian conversion and/or accommodate hardware that cannot perform + * misaligned memory transfers + */ + case ACPI_RSC_MOVE16: + case ACPI_RSC_MOVE_GPIO_PIN: + + ACPI_MOVE_16_TO_16 ( + &ACPI_CAST_PTR (UINT16, Destination)[i], + &ACPI_CAST_PTR (UINT16, Source)[i]); + break; + + case ACPI_RSC_MOVE32: + + ACPI_MOVE_32_TO_32 ( + &ACPI_CAST_PTR (UINT32, Destination)[i], + &ACPI_CAST_PTR (UINT32, Source)[i]); + break; + + case ACPI_RSC_MOVE64: + + ACPI_MOVE_64_TO_64 ( + &ACPI_CAST_PTR (UINT64, Destination)[i], + &ACPI_CAST_PTR (UINT64, Source)[i]); + break; + + default: + + return; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsSetResourceLength + * + * PARAMETERS: TotalLength - Length of the AML descriptor, including + * the header and length fields. + * Aml - Pointer to the raw AML descriptor + * + * RETURN: None + * + * DESCRIPTION: Set the ResourceLength field of an AML + * resource descriptor, both Large and Small descriptors are + * supported automatically. Note: Descriptor Type field must + * be valid. + * + ******************************************************************************/ + +void +AcpiRsSetResourceLength ( + ACPI_RSDESC_SIZE TotalLength, + AML_RESOURCE *Aml) +{ + ACPI_RS_LENGTH ResourceLength; + + + ACPI_FUNCTION_ENTRY (); + + + /* Length is the total descriptor length minus the header length */ + + ResourceLength = (ACPI_RS_LENGTH) + (TotalLength - AcpiUtGetResourceHeaderLength (Aml)); + + /* Length is stored differently for large and small descriptors */ + + if (Aml->SmallHeader.DescriptorType & ACPI_RESOURCE_NAME_LARGE) + { + /* Large descriptor -- bytes 1-2 contain the 16-bit length */ + + ACPI_MOVE_16_TO_16 ( + &Aml->LargeHeader.ResourceLength, &ResourceLength); + } + else + { + /* + * Small descriptor -- bits 2:0 of byte 0 contain the length + * Clear any existing length, preserving descriptor type bits + */ + Aml->SmallHeader.DescriptorType = (UINT8) + ((Aml->SmallHeader.DescriptorType & + ~ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK) + | ResourceLength); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsSetResourceHeader + * + * PARAMETERS: DescriptorType - Byte to be inserted as the type + * TotalLength - Length of the AML descriptor, including + * the header and length fields. + * Aml - Pointer to the raw AML descriptor + * + * RETURN: None + * + * DESCRIPTION: Set the DescriptorType and ResourceLength fields of an AML + * resource descriptor, both Large and Small descriptors are + * supported automatically + * + ******************************************************************************/ + +void +AcpiRsSetResourceHeader ( + UINT8 DescriptorType, + ACPI_RSDESC_SIZE TotalLength, + AML_RESOURCE *Aml) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Set the Resource Type */ + + Aml->SmallHeader.DescriptorType = DescriptorType; + + /* Set the Resource Length */ + + AcpiRsSetResourceLength (TotalLength, Aml); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsStrcpy + * + * PARAMETERS: Destination - Pointer to the destination string + * Source - Pointer to the source string + * + * RETURN: String length, including NULL terminator + * + * DESCRIPTION: Local string copy that returns the string length, saving a + * strcpy followed by a strlen. + * + ******************************************************************************/ + +static UINT16 +AcpiRsStrcpy ( + char *Destination, + char *Source) +{ + UINT16 i; + + + ACPI_FUNCTION_ENTRY (); + + + for (i = 0; Source[i]; i++) + { + Destination[i] = Source[i]; + } + + Destination[i] = 0; + + /* Return string length including the NULL terminator */ + + return ((UINT16) (i + 1)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetResourceSource + * + * PARAMETERS: ResourceLength - Length field of the descriptor + * MinimumLength - Minimum length of the descriptor (minus + * any optional fields) + * ResourceSource - Where the ResourceSource is returned + * Aml - Pointer to the raw AML descriptor + * StringPtr - (optional) where to store the actual + * ResourceSource string + * + * RETURN: Length of the string plus NULL terminator, rounded up to native + * word boundary + * + * DESCRIPTION: Copy the optional ResourceSource data from a raw AML descriptor + * to an internal resource descriptor + * + ******************************************************************************/ + +ACPI_RS_LENGTH +AcpiRsGetResourceSource ( + ACPI_RS_LENGTH ResourceLength, + ACPI_RS_LENGTH MinimumLength, + ACPI_RESOURCE_SOURCE *ResourceSource, + AML_RESOURCE *Aml, + char *StringPtr) +{ + ACPI_RSDESC_SIZE TotalLength; + UINT8 *AmlResourceSource; + + + ACPI_FUNCTION_ENTRY (); + + + TotalLength = ResourceLength + sizeof (AML_RESOURCE_LARGE_HEADER); + AmlResourceSource = ACPI_ADD_PTR (UINT8, Aml, MinimumLength); + + /* + * ResourceSource is present if the length of the descriptor is longer + * than the minimum length. + * + * Note: Some resource descriptors will have an additional null, so + * we add 1 to the minimum length. + */ + if (TotalLength > (ACPI_RSDESC_SIZE) (MinimumLength + 1)) + { + /* Get the ResourceSourceIndex */ + + ResourceSource->Index = AmlResourceSource[0]; + + ResourceSource->StringPtr = StringPtr; + if (!StringPtr) + { + /* + * String destination pointer is not specified; Set the String + * pointer to the end of the current ResourceSource structure. + */ + ResourceSource->StringPtr = ACPI_ADD_PTR ( + char, ResourceSource, sizeof (ACPI_RESOURCE_SOURCE)); + } + + /* + * In order for the Resource length to be a multiple of the native + * word, calculate the length of the string (+1 for NULL terminator) + * and expand to the next word multiple. + * + * Zero the entire area of the buffer. + */ + TotalLength = (UINT32) strlen ( + ACPI_CAST_PTR (char, &AmlResourceSource[1])) + 1; + + TotalLength = (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (TotalLength); + + memset (ResourceSource->StringPtr, 0, TotalLength); + + /* Copy the ResourceSource string to the destination */ + + ResourceSource->StringLength = AcpiRsStrcpy ( + ResourceSource->StringPtr, + ACPI_CAST_PTR (char, &AmlResourceSource[1])); + + return ((ACPI_RS_LENGTH) TotalLength); + } + + /* ResourceSource is not present */ + + ResourceSource->Index = 0; + ResourceSource->StringLength = 0; + ResourceSource->StringPtr = NULL; + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsSetResourceSource + * + * PARAMETERS: Aml - Pointer to the raw AML descriptor + * MinimumLength - Minimum length of the descriptor (minus + * any optional fields) + * ResourceSource - Internal ResourceSource + + * + * RETURN: Total length of the AML descriptor + * + * DESCRIPTION: Convert an optional ResourceSource from internal format to a + * raw AML resource descriptor + * + ******************************************************************************/ + +ACPI_RSDESC_SIZE +AcpiRsSetResourceSource ( + AML_RESOURCE *Aml, + ACPI_RS_LENGTH MinimumLength, + ACPI_RESOURCE_SOURCE *ResourceSource) +{ + UINT8 *AmlResourceSource; + ACPI_RSDESC_SIZE DescriptorLength; + + + ACPI_FUNCTION_ENTRY (); + + + DescriptorLength = MinimumLength; + + /* Non-zero string length indicates presence of a ResourceSource */ + + if (ResourceSource->StringLength) + { + /* Point to the end of the AML descriptor */ + + AmlResourceSource = ACPI_ADD_PTR (UINT8, Aml, MinimumLength); + + /* Copy the ResourceSourceIndex */ + + AmlResourceSource[0] = (UINT8) ResourceSource->Index; + + /* Copy the ResourceSource string */ + + strcpy (ACPI_CAST_PTR (char, &AmlResourceSource[1]), + ResourceSource->StringPtr); + + /* + * Add the length of the string (+ 1 for null terminator) to the + * final descriptor length + */ + DescriptorLength += ((ACPI_RSDESC_SIZE) + ResourceSource->StringLength + 1); + } + + /* Return the new total length of the AML descriptor */ + + return (DescriptorLength); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetPrtMethodData + * + * PARAMETERS: Node - Device node + * RetBuffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _PRT value of an object + * contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetPrtMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsGetPrtMethodData); + + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + Status = AcpiUtEvaluateObject ( + Node, METHOD_NAME__PRT, ACPI_BTYPE_PACKAGE, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Create a resource linked list from the byte stream buffer that comes + * back from the _CRS method execution. + */ + Status = AcpiRsCreatePciRoutingTable (ObjDesc, RetBuffer); + + /* On exit, we must delete the object returned by EvaluateObject */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetCrsMethodData + * + * PARAMETERS: Node - Device node + * RetBuffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _CRS value of an object + * contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetCrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsGetCrsMethodData); + + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + Status = AcpiUtEvaluateObject ( + Node, METHOD_NAME__CRS, ACPI_BTYPE_BUFFER, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Make the call to create a resource linked list from the + * byte stream buffer that comes back from the _CRS method + * execution. + */ + Status = AcpiRsCreateResourceList (ObjDesc, RetBuffer); + + /* On exit, we must delete the object returned by evaluateObject */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetPrsMethodData + * + * PARAMETERS: Node - Device node + * RetBuffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _PRS value of an object + * contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetPrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsGetPrsMethodData); + + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + Status = AcpiUtEvaluateObject ( + Node, METHOD_NAME__PRS, ACPI_BTYPE_BUFFER, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Make the call to create a resource linked list from the + * byte stream buffer that comes back from the _CRS method + * execution. + */ + Status = AcpiRsCreateResourceList (ObjDesc, RetBuffer); + + /* On exit, we must delete the object returned by evaluateObject */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetAeiMethodData + * + * PARAMETERS: Node - Device node + * RetBuffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _AEI value of an object + * contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetAeiMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsGetAeiMethodData); + + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + Status = AcpiUtEvaluateObject ( + Node, METHOD_NAME__AEI, ACPI_BTYPE_BUFFER, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Make the call to create a resource linked list from the + * byte stream buffer that comes back from the _CRS method + * execution. + */ + Status = AcpiRsCreateResourceList (ObjDesc, RetBuffer); + + /* On exit, we must delete the object returned by evaluateObject */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsGetMethodData + * + * PARAMETERS: Handle - Handle to the containing object + * Path - Path to method, relative to Handle + * RetBuffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _CRS or _PRS value of an + * object contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsGetMethodData ( + ACPI_HANDLE Handle, + char *Path, + ACPI_BUFFER *RetBuffer) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (RsGetMethodData); + + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + Status = AcpiUtEvaluateObject ( + ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Handle), + Path, ACPI_BTYPE_BUFFER, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Make the call to create a resource linked list from the + * byte stream buffer that comes back from the method + * execution. + */ + Status = AcpiRsCreateResourceList (ObjDesc, RetBuffer); + + /* On exit, we must delete the object returned by EvaluateObject */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiRsSetSrsMethodData + * + * PARAMETERS: Node - Device node + * InBuffer - Pointer to a buffer structure of the + * parameter + * + * RETURN: Status + * + * DESCRIPTION: This function is called to set the _SRS of an object contained + * in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + * Note: Parameters guaranteed valid by caller + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRsSetSrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *InBuffer) +{ + ACPI_EVALUATE_INFO *Info; + ACPI_OPERAND_OBJECT *Args[2]; + ACPI_STATUS Status; + ACPI_BUFFER Buffer; + + + ACPI_FUNCTION_TRACE (RsSetSrsMethodData); + + + /* Allocate and initialize the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Info->PrefixNode = Node; + Info->RelativePathname = METHOD_NAME__SRS; + Info->Parameters = Args; + Info->Flags = ACPI_IGNORE_RETURN_VALUE; + + /* + * The InBuffer parameter will point to a linked list of + * resource parameters. It needs to be formatted into a + * byte stream to be sent in as an input parameter to _SRS + * + * Convert the linked list into a byte stream + */ + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiRsCreateAmlResources (InBuffer, &Buffer); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + + /* Create and initialize the method parameter object */ + + Args[0] = AcpiUtCreateInternalObject (ACPI_TYPE_BUFFER); + if (!Args[0]) + { + /* + * Must free the buffer allocated above (otherwise it is freed + * later) + */ + ACPI_FREE (Buffer.Pointer); + Status = AE_NO_MEMORY; + goto Cleanup; + } + + Args[0]->Buffer.Length = (UINT32) Buffer.Length; + Args[0]->Buffer.Pointer = Buffer.Pointer; + Args[0]->Common.Flags = AOPOBJ_DATA_VALID; + Args[1] = NULL; + + /* Execute the method, no return value is expected */ + + Status = AcpiNsEvaluate (Info); + + /* Clean up and return the status from AcpiNsEvaluate */ + + AcpiUtRemoveReference (Args[0]); + +Cleanup: + ACPI_FREE (Info); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/resources/rsxface.c b/third_party/lib/acpica/source/components/resources/rsxface.c new file mode 100644 index 000000000..81c9ac8b4 --- /dev/null +++ b/third_party/lib/acpica/source/components/resources/rsxface.c @@ -0,0 +1,743 @@ +/******************************************************************************* + * + * Module Name: rsxface - Public interfaces to the resource manager + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_RESOURCES + ACPI_MODULE_NAME ("rsxface") + +/* Local macros for 16,32-bit to 64-bit conversion */ + +#define ACPI_COPY_FIELD(Out, In, Field) ((Out)->Field = (In)->Field) +#define ACPI_COPY_ADDRESS(Out, In) \ + ACPI_COPY_FIELD(Out, In, ResourceType); \ + ACPI_COPY_FIELD(Out, In, ProducerConsumer); \ + ACPI_COPY_FIELD(Out, In, Decode); \ + ACPI_COPY_FIELD(Out, In, MinAddressFixed); \ + ACPI_COPY_FIELD(Out, In, MaxAddressFixed); \ + ACPI_COPY_FIELD(Out, In, Info); \ + ACPI_COPY_FIELD(Out, In, Address.Granularity); \ + ACPI_COPY_FIELD(Out, In, Address.Minimum); \ + ACPI_COPY_FIELD(Out, In, Address.Maximum); \ + ACPI_COPY_FIELD(Out, In, Address.TranslationOffset); \ + ACPI_COPY_FIELD(Out, In, Address.AddressLength); \ + ACPI_COPY_FIELD(Out, In, ResourceSource); + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiRsMatchVendorResource ( + ACPI_RESOURCE *Resource, + void *Context); + +static ACPI_STATUS +AcpiRsValidateParameters ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *Buffer, + ACPI_NAMESPACE_NODE **ReturnNode); + + +/******************************************************************************* + * + * FUNCTION: AcpiRsValidateParameters + * + * PARAMETERS: DeviceHandle - Handle to a device + * Buffer - Pointer to a data buffer + * ReturnNode - Pointer to where the device node is returned + * + * RETURN: Status + * + * DESCRIPTION: Common parameter validation for resource interfaces + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiRsValidateParameters ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *Buffer, + ACPI_NAMESPACE_NODE **ReturnNode) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (RsValidateParameters); + + + /* + * Must have a valid handle to an ACPI device + */ + if (!DeviceHandle) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Node = AcpiNsValidateHandle (DeviceHandle); + if (!Node) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (Node->Type != ACPI_TYPE_DEVICE) + { + return_ACPI_STATUS (AE_TYPE); + } + + /* + * Validate the user buffer object + * + * if there is a non-zero buffer length we also need a valid pointer in + * the buffer. If it's a zero buffer length, we'll be returning the + * needed buffer size (later), so keep going. + */ + Status = AcpiUtValidateBuffer (Buffer); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + *ReturnNode = Node; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiGetIrqRoutingTable + * + * PARAMETERS: DeviceHandle - Handle to the Bus device we are querying + * RetBuffer - Pointer to a buffer to receive the + * current resources for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the IRQ routing table for a + * specific bus. The caller must first acquire a handle for the + * desired bus. The routine table is placed in the buffer pointed + * to by the RetBuffer variable parameter. + * + * If the function fails an appropriate status will be returned + * and the value of RetBuffer is undefined. + * + * This function attempts to execute the _PRT method contained in + * the object indicated by the passed DeviceHandle. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetIrqRoutingTable ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (AcpiGetIrqRoutingTable); + + + /* Validate parameters then dispatch to internal routine */ + + Status = AcpiRsValidateParameters (DeviceHandle, RetBuffer, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiRsGetPrtMethodData (Node, RetBuffer); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetIrqRoutingTable) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetCurrentResources + * + * PARAMETERS: DeviceHandle - Handle to the device object for the + * device we are querying + * RetBuffer - Pointer to a buffer to receive the + * current resources for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the current resources for a + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is placed in the buffer + * pointed to by the RetBuffer variable parameter. + * + * If the function fails an appropriate status will be returned + * and the value of RetBuffer is undefined. + * + * This function attempts to execute the _CRS method contained in + * the object indicated by the passed DeviceHandle. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetCurrentResources ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (AcpiGetCurrentResources); + + + /* Validate parameters then dispatch to internal routine */ + + Status = AcpiRsValidateParameters (DeviceHandle, RetBuffer, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiRsGetCrsMethodData (Node, RetBuffer); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetCurrentResources) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetPossibleResources + * + * PARAMETERS: DeviceHandle - Handle to the device object for the + * device we are querying + * RetBuffer - Pointer to a buffer to receive the + * resources for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get a list of the possible resources + * for a specific device. The caller must first acquire a handle + * for the desired device. The resource data is placed in the + * buffer pointed to by the RetBuffer variable. + * + * If the function fails an appropriate status will be returned + * and the value of RetBuffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetPossibleResources ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (AcpiGetPossibleResources); + + + /* Validate parameters then dispatch to internal routine */ + + Status = AcpiRsValidateParameters (DeviceHandle, RetBuffer, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiRsGetPrsMethodData (Node, RetBuffer); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetPossibleResources) + + +/******************************************************************************* + * + * FUNCTION: AcpiSetCurrentResources + * + * PARAMETERS: DeviceHandle - Handle to the device object for the + * device we are setting resources + * InBuffer - Pointer to a buffer containing the + * resources to be set for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to set the current resources for a + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is passed to the routine + * the buffer pointed to by the InBuffer variable. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetCurrentResources ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *InBuffer) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (AcpiSetCurrentResources); + + + /* Validate the buffer, don't allow zero length */ + + if ((!InBuffer) || + (!InBuffer->Pointer) || + (!InBuffer->Length)) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Validate parameters then dispatch to internal routine */ + + Status = AcpiRsValidateParameters (DeviceHandle, InBuffer, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiRsSetSrsMethodData (Node, InBuffer); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiSetCurrentResources) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetEventResources + * + * PARAMETERS: DeviceHandle - Handle to the device object for the + * device we are getting resources + * InBuffer - Pointer to a buffer containing the + * resources to be set for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the event resources for a + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is passed to the routine + * the buffer pointed to by the InBuffer variable. Uses the + * _AEI method. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetEventResources ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + ACPI_FUNCTION_TRACE (AcpiGetEventResources); + + + /* Validate parameters then dispatch to internal routine */ + + Status = AcpiRsValidateParameters (DeviceHandle, RetBuffer, &Node); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiRsGetAeiMethodData (Node, RetBuffer); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetEventResources) + + +/****************************************************************************** + * + * FUNCTION: AcpiResourceToAddress64 + * + * PARAMETERS: Resource - Pointer to a resource + * Out - Pointer to the users's return buffer + * (a struct acpi_resource_address64) + * + * RETURN: Status + * + * DESCRIPTION: If the resource is an address16, address32, or address64, + * copy it to the address64 return buffer. This saves the + * caller from having to duplicate code for different-sized + * addresses. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiResourceToAddress64 ( + ACPI_RESOURCE *Resource, + ACPI_RESOURCE_ADDRESS64 *Out) +{ + ACPI_RESOURCE_ADDRESS16 *Address16; + ACPI_RESOURCE_ADDRESS32 *Address32; + + + if (!Resource || !Out) + { + return (AE_BAD_PARAMETER); + } + + /* Convert 16 or 32 address descriptor to 64 */ + + switch (Resource->Type) + { + case ACPI_RESOURCE_TYPE_ADDRESS16: + + Address16 = ACPI_CAST_PTR ( + ACPI_RESOURCE_ADDRESS16, &Resource->Data); + ACPI_COPY_ADDRESS (Out, Address16); + break; + + case ACPI_RESOURCE_TYPE_ADDRESS32: + + Address32 = ACPI_CAST_PTR ( + ACPI_RESOURCE_ADDRESS32, &Resource->Data); + ACPI_COPY_ADDRESS (Out, Address32); + break; + + case ACPI_RESOURCE_TYPE_ADDRESS64: + + /* Simple copy for 64 bit source */ + + memcpy (Out, &Resource->Data, sizeof (ACPI_RESOURCE_ADDRESS64)); + break; + + default: + + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiResourceToAddress64) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetVendorResource + * + * PARAMETERS: DeviceHandle - Handle for the parent device object + * Name - Method name for the parent resource + * (METHOD_NAME__CRS or METHOD_NAME__PRS) + * Uuid - Pointer to the UUID to be matched. + * includes both subtype and 16-byte UUID + * RetBuffer - Where the vendor resource is returned + * + * RETURN: Status + * + * DESCRIPTION: Walk a resource template for the specified device to find a + * vendor-defined resource that matches the supplied UUID and + * UUID subtype. Returns a ACPI_RESOURCE of type Vendor. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetVendorResource ( + ACPI_HANDLE DeviceHandle, + char *Name, + ACPI_VENDOR_UUID *Uuid, + ACPI_BUFFER *RetBuffer) +{ + ACPI_VENDOR_WALK_INFO Info; + ACPI_STATUS Status; + + + /* Other parameters are validated by AcpiWalkResources */ + + if (!Uuid || !RetBuffer) + { + return (AE_BAD_PARAMETER); + } + + Info.Uuid = Uuid; + Info.Buffer = RetBuffer; + Info.Status = AE_NOT_EXIST; + + /* Walk the _CRS or _PRS resource list for this device */ + + Status = AcpiWalkResources ( + DeviceHandle, Name, AcpiRsMatchVendorResource, &Info); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (Info.Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetVendorResource) + + +/******************************************************************************* + * + * FUNCTION: AcpiRsMatchVendorResource + * + * PARAMETERS: ACPI_WALK_RESOURCE_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Match a vendor resource via the ACPI 3.0 UUID + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiRsMatchVendorResource ( + ACPI_RESOURCE *Resource, + void *Context) +{ + ACPI_VENDOR_WALK_INFO *Info = Context; + ACPI_RESOURCE_VENDOR_TYPED *Vendor; + ACPI_BUFFER *Buffer; + ACPI_STATUS Status; + + + /* Ignore all descriptors except Vendor */ + + if (Resource->Type != ACPI_RESOURCE_TYPE_VENDOR) + { + return (AE_OK); + } + + Vendor = &Resource->Data.VendorTyped; + + /* + * For a valid match, these conditions must hold: + * + * 1) Length of descriptor data must be at least as long as a UUID struct + * 2) The UUID subtypes must match + * 3) The UUID data must match + */ + if ((Vendor->ByteLength < (ACPI_UUID_LENGTH + 1)) || + (Vendor->UuidSubtype != Info->Uuid->Subtype) || + (memcmp (Vendor->Uuid, Info->Uuid->Data, ACPI_UUID_LENGTH))) + { + return (AE_OK); + } + + /* Validate/Allocate/Clear caller buffer */ + + Buffer = Info->Buffer; + Status = AcpiUtInitializeBuffer (Buffer, Resource->Length); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Found the correct resource, copy and return it */ + + memcpy (Buffer->Pointer, Resource, Resource->Length); + Buffer->Length = Resource->Length; + + /* Found the desired descriptor, terminate resource walk */ + + Info->Status = AE_OK; + return (AE_CTRL_TERMINATE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiWalkResourceBuffer + * + * PARAMETERS: Buffer - Formatted buffer returned by one of the + * various Get*Resource functions + * UserFunction - Called for each resource + * Context - Passed to UserFunction + * + * RETURN: Status + * + * DESCRIPTION: Walks the input resource template. The UserFunction is called + * once for each resource in the list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWalkResourceBuffer ( + ACPI_BUFFER *Buffer, + ACPI_WALK_RESOURCE_CALLBACK UserFunction, + void *Context) +{ + ACPI_STATUS Status = AE_OK; + ACPI_RESOURCE *Resource; + ACPI_RESOURCE *ResourceEnd; + + + ACPI_FUNCTION_TRACE (AcpiWalkResourceBuffer); + + + /* Parameter validation */ + + if (!Buffer || !Buffer->Pointer || !UserFunction) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Buffer contains the resource list and length */ + + Resource = ACPI_CAST_PTR (ACPI_RESOURCE, Buffer->Pointer); + ResourceEnd = ACPI_ADD_PTR ( + ACPI_RESOURCE, Buffer->Pointer, Buffer->Length); + + /* Walk the resource list until the EndTag is found (or buffer end) */ + + while (Resource < ResourceEnd) + { + /* Sanity check the resource type */ + + if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) + { + Status = AE_AML_INVALID_RESOURCE_TYPE; + break; + } + + /* Sanity check the length. It must not be zero, or we loop forever */ + + if (!Resource->Length) + { + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH); + } + + /* Invoke the user function, abort on any error returned */ + + Status = UserFunction (Resource, Context); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_CTRL_TERMINATE) + { + /* This is an OK termination by the user function */ + + Status = AE_OK; + } + break; + } + + /* EndTag indicates end-of-list */ + + if (Resource->Type == ACPI_RESOURCE_TYPE_END_TAG) + { + break; + } + + /* Get the next resource descriptor */ + + Resource = ACPI_NEXT_RESOURCE (Resource); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWalkResourceBuffer) + + +/******************************************************************************* + * + * FUNCTION: AcpiWalkResources + * + * PARAMETERS: DeviceHandle - Handle to the device object for the + * device we are querying + * Name - Method name of the resources we want. + * (METHOD_NAME__CRS, METHOD_NAME__PRS, or + * METHOD_NAME__AEI) + * UserFunction - Called for each resource + * Context - Passed to UserFunction + * + * RETURN: Status + * + * DESCRIPTION: Retrieves the current or possible resource list for the + * specified device. The UserFunction is called once for + * each resource in the list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWalkResources ( + ACPI_HANDLE DeviceHandle, + char *Name, + ACPI_WALK_RESOURCE_CALLBACK UserFunction, + void *Context) +{ + ACPI_STATUS Status; + ACPI_BUFFER Buffer; + + + ACPI_FUNCTION_TRACE (AcpiWalkResources); + + + /* Parameter validation */ + + if (!DeviceHandle || !UserFunction || !Name || + (!ACPI_COMPARE_NAME (Name, METHOD_NAME__CRS) && + !ACPI_COMPARE_NAME (Name, METHOD_NAME__PRS) && + !ACPI_COMPARE_NAME (Name, METHOD_NAME__AEI))) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the _CRS/_PRS/_AEI resource list */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiRsGetMethodData (DeviceHandle, Name, &Buffer); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Walk the resource list and cleanup */ + + Status = AcpiWalkResourceBuffer (&Buffer, UserFunction, Context); + ACPI_FREE (Buffer.Pointer); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWalkResources) diff --git a/third_party/lib/acpica/source/components/tables/tbdata.c b/third_party/lib/acpica/source/components/tables/tbdata.c new file mode 100644 index 000000000..fd69a57b3 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbdata.c @@ -0,0 +1,869 @@ +/****************************************************************************** + * + * Module Name: tbdata - Table manager data structure functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbdata") + + +/******************************************************************************* + * + * FUNCTION: AcpiTbInitTableDescriptor + * + * PARAMETERS: TableDesc - Table descriptor + * Address - Physical address of the table + * Flags - Allocation flags of the table + * Table - Pointer to the table + * + * RETURN: None + * + * DESCRIPTION: Initialize a new table descriptor + * + ******************************************************************************/ + +void +AcpiTbInitTableDescriptor ( + ACPI_TABLE_DESC *TableDesc, + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + ACPI_TABLE_HEADER *Table) +{ + + /* + * Initialize the table descriptor. Set the pointer to NULL, since the + * table is not fully mapped at this time. + */ + memset (TableDesc, 0, sizeof (ACPI_TABLE_DESC)); + TableDesc->Address = Address; + TableDesc->Length = Table->Length; + TableDesc->Flags = Flags; + ACPI_MOVE_32_TO_32 (TableDesc->Signature.Ascii, Table->Signature); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbAcquireTable + * + * PARAMETERS: TableDesc - Table descriptor + * TablePtr - Where table is returned + * TableLength - Where table length is returned + * TableFlags - Where table allocation flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Acquire an ACPI table. It can be used for tables not + * maintained in the AcpiGbl_RootTableList. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbAcquireTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_TABLE_HEADER **TablePtr, + UINT32 *TableLength, + UINT8 *TableFlags) +{ + ACPI_TABLE_HEADER *Table = NULL; + + + switch (TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK) + { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + Table = AcpiOsMapMemory (TableDesc->Address, TableDesc->Length); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, + ACPI_PHYSADDR_TO_PTR (TableDesc->Address)); + break; + + default: + + break; + } + + /* Table is not valid yet */ + + if (!Table) + { + return (AE_NO_MEMORY); + } + + /* Fill the return values */ + + *TablePtr = Table; + *TableLength = TableDesc->Length; + *TableFlags = TableDesc->Flags; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbReleaseTable + * + * PARAMETERS: Table - Pointer for the table + * TableLength - Length for the table + * TableFlags - Allocation flags for the table + * + * RETURN: None + * + * DESCRIPTION: Release a table. The inverse of AcpiTbAcquireTable(). + * + ******************************************************************************/ + +void +AcpiTbReleaseTable ( + ACPI_TABLE_HEADER *Table, + UINT32 TableLength, + UINT8 TableFlags) +{ + + switch (TableFlags & ACPI_TABLE_ORIGIN_MASK) + { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + AcpiOsUnmapMemory (Table, TableLength); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + default: + + break; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbAcquireTempTable + * + * PARAMETERS: TableDesc - Table descriptor to be acquired + * Address - Address of the table + * Flags - Allocation flags of the table + * + * RETURN: Status + * + * DESCRIPTION: This function validates the table header to obtain the length + * of a table and fills the table descriptor to make its state as + * "INSTALLED". Such a table descriptor is only used for verified + * installation. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbAcquireTempTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags) +{ + ACPI_TABLE_HEADER *TableHeader; + + + switch (Flags & ACPI_TABLE_ORIGIN_MASK) + { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + /* Get the length of the full table from the header */ + + TableHeader = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); + if (!TableHeader) + { + return (AE_NO_MEMORY); + } + + AcpiTbInitTableDescriptor (TableDesc, Address, Flags, TableHeader); + AcpiOsUnmapMemory (TableHeader, sizeof (ACPI_TABLE_HEADER)); + return (AE_OK); + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + TableHeader = ACPI_CAST_PTR (ACPI_TABLE_HEADER, + ACPI_PHYSADDR_TO_PTR (Address)); + if (!TableHeader) + { + return (AE_NO_MEMORY); + } + + AcpiTbInitTableDescriptor (TableDesc, Address, Flags, TableHeader); + return (AE_OK); + + default: + + break; + } + + /* Table is not valid yet */ + + return (AE_NO_MEMORY); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbReleaseTempTable + * + * PARAMETERS: TableDesc - Table descriptor to be released + * + * RETURN: Status + * + * DESCRIPTION: The inverse of AcpiTbAcquireTempTable(). + * + *****************************************************************************/ + +void +AcpiTbReleaseTempTable ( + ACPI_TABLE_DESC *TableDesc) +{ + + /* + * Note that the .Address is maintained by the callers of + * AcpiTbAcquireTempTable(), thus do not invoke AcpiTbUninstallTable() + * where .Address will be freed. + */ + AcpiTbInvalidateTable (TableDesc); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiTbValidateTable + * + * PARAMETERS: TableDesc - Table descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate the table, the returned + * table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiTbValidateTable ( + ACPI_TABLE_DESC *TableDesc) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (TbValidateTable); + + + /* Validate the table if necessary */ + + if (!TableDesc->Pointer) + { + Status = AcpiTbAcquireTable (TableDesc, &TableDesc->Pointer, + &TableDesc->Length, &TableDesc->Flags); + if (!TableDesc->Pointer) + { + Status = AE_NO_MEMORY; + } + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbInvalidateTable + * + * PARAMETERS: TableDesc - Table descriptor + * + * RETURN: None + * + * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of + * AcpiTbValidateTable(). + * + ******************************************************************************/ + +void +AcpiTbInvalidateTable ( + ACPI_TABLE_DESC *TableDesc) +{ + + ACPI_FUNCTION_TRACE (TbInvalidateTable); + + + /* Table must be validated */ + + if (!TableDesc->Pointer) + { + return_VOID; + } + + AcpiTbReleaseTable (TableDesc->Pointer, TableDesc->Length, + TableDesc->Flags); + TableDesc->Pointer = NULL; + + return_VOID; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiTbValidateTempTable + * + * PARAMETERS: TableDesc - Table descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate the table, the returned + * table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiTbValidateTempTable ( + ACPI_TABLE_DESC *TableDesc) +{ + + if (!TableDesc->Pointer && !AcpiGbl_VerifyTableChecksum) + { + /* + * Only validates the header of the table. + * Note that Length contains the size of the mapping after invoking + * this work around, this value is required by + * AcpiTbReleaseTempTable(). + * We can do this because in AcpiInitTableDescriptor(), the Length + * field of the installed descriptor is filled with the actual + * table length obtaining from the table header. + */ + TableDesc->Length = sizeof (ACPI_TABLE_HEADER); + } + + return (AcpiTbValidateTable (TableDesc)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiTbVerifyTempTable + * + * PARAMETERS: TableDesc - Table descriptor + * Signature - Table signature to verify + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate and verify the table, the + * returned table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiTbVerifyTempTable ( + ACPI_TABLE_DESC *TableDesc, + char *Signature) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (TbVerifyTempTable); + + + /* Validate the table */ + + Status = AcpiTbValidateTempTable (TableDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* If a particular signature is expected (DSDT/FACS), it must match */ + + if (Signature && + !ACPI_COMPARE_NAME (&TableDesc->Signature, Signature)) + { + ACPI_BIOS_ERROR ((AE_INFO, + "Invalid signature 0x%X for ACPI table, expected [%s]", + TableDesc->Signature.Integer, Signature)); + Status = AE_BAD_SIGNATURE; + goto InvalidateAndExit; + } + + /* Verify the checksum */ + + if (AcpiGbl_VerifyTableChecksum) + { + Status = AcpiTbVerifyChecksum (TableDesc->Pointer, TableDesc->Length); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, AE_NO_MEMORY, + "%4.4s 0x%8.8X%8.8X" + " Attempted table install failed", + AcpiUtValidAcpiName (TableDesc->Signature.Ascii) ? + TableDesc->Signature.Ascii : "????", + ACPI_FORMAT_UINT64 (TableDesc->Address))); + + goto InvalidateAndExit; + } + } + + return_ACPI_STATUS (AE_OK); + +InvalidateAndExit: + AcpiTbInvalidateTable (TableDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbResizeRootTableList + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Expand the size of global table array + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbResizeRootTableList ( + void) +{ + ACPI_TABLE_DESC *Tables; + UINT32 TableCount; + + + ACPI_FUNCTION_TRACE (TbResizeRootTableList); + + + /* AllowResize flag is a parameter to AcpiInitializeTables */ + + if (!(AcpiGbl_RootTableList.Flags & ACPI_ROOT_ALLOW_RESIZE)) + { + ACPI_ERROR ((AE_INFO, "Resize of Root Table Array is not allowed")); + return_ACPI_STATUS (AE_SUPPORT); + } + + /* Increase the Table Array size */ + + if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED) + { + TableCount = AcpiGbl_RootTableList.MaxTableCount; + } + else + { + TableCount = AcpiGbl_RootTableList.CurrentTableCount; + } + + Tables = ACPI_ALLOCATE_ZEROED ( + ((ACPI_SIZE) TableCount + ACPI_ROOT_TABLE_SIZE_INCREMENT) * + sizeof (ACPI_TABLE_DESC)); + if (!Tables) + { + ACPI_ERROR ((AE_INFO, "Could not allocate new root table array")); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy and free the previous table array */ + + if (AcpiGbl_RootTableList.Tables) + { + memcpy (Tables, AcpiGbl_RootTableList.Tables, + (ACPI_SIZE) TableCount * sizeof (ACPI_TABLE_DESC)); + + if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED) + { + ACPI_FREE (AcpiGbl_RootTableList.Tables); + } + } + + AcpiGbl_RootTableList.Tables = Tables; + AcpiGbl_RootTableList.MaxTableCount = + TableCount + ACPI_ROOT_TABLE_SIZE_INCREMENT; + AcpiGbl_RootTableList.Flags |= ACPI_ROOT_ORIGIN_ALLOCATED; + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbGetNextTableDescriptor + * + * PARAMETERS: TableIndex - Where table index is returned + * TableDesc - Where table descriptor is returned + * + * RETURN: Status and table index/descriptor. + * + * DESCRIPTION: Allocate a new ACPI table entry to the global table list + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbGetNextTableDescriptor ( + UINT32 *TableIndex, + ACPI_TABLE_DESC **TableDesc) +{ + ACPI_STATUS Status; + UINT32 i; + + + /* Ensure that there is room for the table in the Root Table List */ + + if (AcpiGbl_RootTableList.CurrentTableCount >= + AcpiGbl_RootTableList.MaxTableCount) + { + Status = AcpiTbResizeRootTableList(); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + i = AcpiGbl_RootTableList.CurrentTableCount; + AcpiGbl_RootTableList.CurrentTableCount++; + + if (TableIndex) + { + *TableIndex = i; + } + if (TableDesc) + { + *TableDesc = &AcpiGbl_RootTableList.Tables[i]; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbTerminate + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all internal ACPI tables + * + ******************************************************************************/ + +void +AcpiTbTerminate ( + void) +{ + UINT32 i; + + + ACPI_FUNCTION_TRACE (TbTerminate); + + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + + /* Delete the individual tables */ + + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++) + { + AcpiTbUninstallTable (&AcpiGbl_RootTableList.Tables[i]); + } + + /* + * Delete the root table array if allocated locally. Array cannot be + * mapped, so we don't need to check for that flag. + */ + if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED) + { + ACPI_FREE (AcpiGbl_RootTableList.Tables); + } + + AcpiGbl_RootTableList.Tables = NULL; + AcpiGbl_RootTableList.Flags = 0; + AcpiGbl_RootTableList.CurrentTableCount = 0; + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Tables freed\n")); + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbDeleteNamespaceByOwner + * + * PARAMETERS: TableIndex - Table index + * + * RETURN: Status + * + * DESCRIPTION: Delete all namespace objects created when this table was loaded. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbDeleteNamespaceByOwner ( + UINT32 TableIndex) +{ + ACPI_OWNER_ID OwnerId; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (TbDeleteNamespaceByOwner); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (TableIndex >= AcpiGbl_RootTableList.CurrentTableCount) + { + /* The table index does not exist */ + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Get the owner ID for this table, used to delete namespace nodes */ + + OwnerId = AcpiGbl_RootTableList.Tables[TableIndex].OwnerId; + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + + /* + * Need to acquire the namespace writer lock to prevent interference + * with any concurrent namespace walks. The interpreter must be + * released during the deletion since the acquisition of the deletion + * lock may block, and also since the execution of a namespace walk + * must be allowed to use the interpreter. + */ + (void) AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER); + Status = AcpiUtAcquireWriteLock (&AcpiGbl_NamespaceRwLock); + + AcpiNsDeleteNamespaceByOwner (OwnerId); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiUtReleaseWriteLock (&AcpiGbl_NamespaceRwLock); + + Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbAllocateOwnerId + * + * PARAMETERS: TableIndex - Table index + * + * RETURN: Status + * + * DESCRIPTION: Allocates OwnerId in TableDesc + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbAllocateOwnerId ( + UINT32 TableIndex) +{ + ACPI_STATUS Status = AE_BAD_PARAMETER; + + + ACPI_FUNCTION_TRACE (TbAllocateOwnerId); + + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount) + { + Status = AcpiUtAllocateOwnerId ( + &(AcpiGbl_RootTableList.Tables[TableIndex].OwnerId)); + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbReleaseOwnerId + * + * PARAMETERS: TableIndex - Table index + * + * RETURN: Status + * + * DESCRIPTION: Releases OwnerId in TableDesc + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbReleaseOwnerId ( + UINT32 TableIndex) +{ + ACPI_STATUS Status = AE_BAD_PARAMETER; + + + ACPI_FUNCTION_TRACE (TbReleaseOwnerId); + + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount) + { + AcpiUtReleaseOwnerId ( + &(AcpiGbl_RootTableList.Tables[TableIndex].OwnerId)); + Status = AE_OK; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbGetOwnerId + * + * PARAMETERS: TableIndex - Table index + * OwnerId - Where the table OwnerId is returned + * + * RETURN: Status + * + * DESCRIPTION: returns OwnerId for the ACPI table + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbGetOwnerId ( + UINT32 TableIndex, + ACPI_OWNER_ID *OwnerId) +{ + ACPI_STATUS Status = AE_BAD_PARAMETER; + + + ACPI_FUNCTION_TRACE (TbGetOwnerId); + + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount) + { + *OwnerId = AcpiGbl_RootTableList.Tables[TableIndex].OwnerId; + Status = AE_OK; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbIsTableLoaded + * + * PARAMETERS: TableIndex - Index into the root table + * + * RETURN: Table Loaded Flag + * + ******************************************************************************/ + +BOOLEAN +AcpiTbIsTableLoaded ( + UINT32 TableIndex) +{ + BOOLEAN IsLoaded = FALSE; + + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount) + { + IsLoaded = (BOOLEAN) + (AcpiGbl_RootTableList.Tables[TableIndex].Flags & + ACPI_TABLE_IS_LOADED); + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return (IsLoaded); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbSetTableLoadedFlag + * + * PARAMETERS: TableIndex - Table index + * IsLoaded - TRUE if table is loaded, FALSE otherwise + * + * RETURN: None + * + * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. + * + ******************************************************************************/ + +void +AcpiTbSetTableLoadedFlag ( + UINT32 TableIndex, + BOOLEAN IsLoaded) +{ + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount) + { + if (IsLoaded) + { + AcpiGbl_RootTableList.Tables[TableIndex].Flags |= + ACPI_TABLE_IS_LOADED; + } + else + { + AcpiGbl_RootTableList.Tables[TableIndex].Flags &= + ~ACPI_TABLE_IS_LOADED; + } + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); +} diff --git a/third_party/lib/acpica/source/components/tables/tbfadt.c b/third_party/lib/acpica/source/components/tables/tbfadt.c new file mode 100644 index 000000000..2bcecedf9 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbfadt.c @@ -0,0 +1,778 @@ +/****************************************************************************** + * + * Module Name: tbfadt - FADT table utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbfadt") + +/* Local prototypes */ + +static void +AcpiTbInitGenericAddress ( + ACPI_GENERIC_ADDRESS *GenericAddress, + UINT8 SpaceId, + UINT8 ByteWidth, + UINT64 Address, + char *RegisterName, + UINT8 Flags); + +static void +AcpiTbConvertFadt ( + void); + +static void +AcpiTbSetupFadtRegisters ( + void); + +static UINT64 +AcpiTbSelectAddress ( + char *RegisterName, + UINT32 Address32, + UINT64 Address64); + + +/* Table for conversion of FADT to common internal format and FADT validation */ + +typedef struct acpi_fadt_info +{ + char *Name; + UINT16 Address64; + UINT16 Address32; + UINT16 Length; + UINT8 DefaultLength; + UINT8 Flags; + +} ACPI_FADT_INFO; + +#define ACPI_FADT_OPTIONAL 0 +#define ACPI_FADT_REQUIRED 1 +#define ACPI_FADT_SEPARATE_LENGTH 2 +#define ACPI_FADT_GPE_REGISTER 4 + +static ACPI_FADT_INFO FadtInfoTable[] = +{ + {"Pm1aEventBlock", + ACPI_FADT_OFFSET (XPm1aEventBlock), + ACPI_FADT_OFFSET (Pm1aEventBlock), + ACPI_FADT_OFFSET (Pm1EventLength), + ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ + ACPI_FADT_REQUIRED}, + + {"Pm1bEventBlock", + ACPI_FADT_OFFSET (XPm1bEventBlock), + ACPI_FADT_OFFSET (Pm1bEventBlock), + ACPI_FADT_OFFSET (Pm1EventLength), + ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ + ACPI_FADT_OPTIONAL}, + + {"Pm1aControlBlock", + ACPI_FADT_OFFSET (XPm1aControlBlock), + ACPI_FADT_OFFSET (Pm1aControlBlock), + ACPI_FADT_OFFSET (Pm1ControlLength), + ACPI_PM1_REGISTER_WIDTH, + ACPI_FADT_REQUIRED}, + + {"Pm1bControlBlock", + ACPI_FADT_OFFSET (XPm1bControlBlock), + ACPI_FADT_OFFSET (Pm1bControlBlock), + ACPI_FADT_OFFSET (Pm1ControlLength), + ACPI_PM1_REGISTER_WIDTH, + ACPI_FADT_OPTIONAL}, + + {"Pm2ControlBlock", + ACPI_FADT_OFFSET (XPm2ControlBlock), + ACPI_FADT_OFFSET (Pm2ControlBlock), + ACPI_FADT_OFFSET (Pm2ControlLength), + ACPI_PM2_REGISTER_WIDTH, + ACPI_FADT_SEPARATE_LENGTH}, + + {"PmTimerBlock", + ACPI_FADT_OFFSET (XPmTimerBlock), + ACPI_FADT_OFFSET (PmTimerBlock), + ACPI_FADT_OFFSET (PmTimerLength), + ACPI_PM_TIMER_WIDTH, + ACPI_FADT_SEPARATE_LENGTH}, /* ACPI 5.0A: Timer is optional */ + + {"Gpe0Block", + ACPI_FADT_OFFSET (XGpe0Block), + ACPI_FADT_OFFSET (Gpe0Block), + ACPI_FADT_OFFSET (Gpe0BlockLength), + 0, + ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}, + + {"Gpe1Block", + ACPI_FADT_OFFSET (XGpe1Block), + ACPI_FADT_OFFSET (Gpe1Block), + ACPI_FADT_OFFSET (Gpe1BlockLength), + 0, + ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER} +}; + +#define ACPI_FADT_INFO_ENTRIES \ + (sizeof (FadtInfoTable) / sizeof (ACPI_FADT_INFO)) + + +/* Table used to split Event Blocks into separate status/enable registers */ + +typedef struct acpi_fadt_pm_info +{ + ACPI_GENERIC_ADDRESS *Target; + UINT16 Source; + UINT8 RegisterNum; + +} ACPI_FADT_PM_INFO; + +static ACPI_FADT_PM_INFO FadtPmInfoTable[] = +{ + {&AcpiGbl_XPm1aStatus, + ACPI_FADT_OFFSET (XPm1aEventBlock), + 0}, + + {&AcpiGbl_XPm1aEnable, + ACPI_FADT_OFFSET (XPm1aEventBlock), + 1}, + + {&AcpiGbl_XPm1bStatus, + ACPI_FADT_OFFSET (XPm1bEventBlock), + 0}, + + {&AcpiGbl_XPm1bEnable, + ACPI_FADT_OFFSET (XPm1bEventBlock), + 1} +}; + +#define ACPI_FADT_PM_INFO_ENTRIES \ + (sizeof (FadtPmInfoTable) / sizeof (ACPI_FADT_PM_INFO)) + + +/******************************************************************************* + * + * FUNCTION: AcpiTbInitGenericAddress + * + * PARAMETERS: GenericAddress - GAS struct to be initialized + * SpaceId - ACPI Space ID for this register + * ByteWidth - Width of this register + * Address - Address of the register + * RegisterName - ASCII name of the ACPI register + * + * RETURN: None + * + * DESCRIPTION: Initialize a Generic Address Structure (GAS) + * See the ACPI specification for a full description and + * definition of this structure. + * + ******************************************************************************/ + +static void +AcpiTbInitGenericAddress ( + ACPI_GENERIC_ADDRESS *GenericAddress, + UINT8 SpaceId, + UINT8 ByteWidth, + UINT64 Address, + char *RegisterName, + UINT8 Flags) +{ + UINT8 BitWidth; + + + /* + * Bit width field in the GAS is only one byte long, 255 max. + * Check for BitWidth overflow in GAS. + */ + BitWidth = (UINT8) (ByteWidth * 8); + if (ByteWidth > 31) /* (31*8)=248, (32*8)=256 */ + { + /* + * No error for GPE blocks, because we do not use the BitWidth + * for GPEs, the legacy length (ByteWidth) is used instead to + * allow for a large number of GPEs. + */ + if (!(Flags & ACPI_FADT_GPE_REGISTER)) + { + ACPI_ERROR ((AE_INFO, + "%s - 32-bit FADT register is too long (%u bytes, %u bits) " + "to convert to GAS struct - 255 bits max, truncating", + RegisterName, ByteWidth, (ByteWidth * 8))); + } + + BitWidth = 255; + } + + /* + * The 64-bit Address field is non-aligned in the byte packed + * GAS struct. + */ + ACPI_MOVE_64_TO_64 (&GenericAddress->Address, &Address); + + /* All other fields are byte-wide */ + + GenericAddress->SpaceId = SpaceId; + GenericAddress->BitWidth = BitWidth; + GenericAddress->BitOffset = 0; + GenericAddress->AccessWidth = 0; /* Access width ANY */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbSelectAddress + * + * PARAMETERS: RegisterName - ASCII name of the ACPI register + * Address32 - 32-bit address of the register + * Address64 - 64-bit address of the register + * + * RETURN: The resolved 64-bit address + * + * DESCRIPTION: Select between 32-bit and 64-bit versions of addresses within + * the FADT. Used for the FACS and DSDT addresses. + * + * NOTES: + * + * Check for FACS and DSDT address mismatches. An address mismatch between + * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and + * DSDT/X_DSDT) could be a corrupted address field or it might indicate + * the presence of two FACS or two DSDT tables. + * + * November 2013: + * By default, as per the ACPICA specification, a valid 64-bit address is + * used regardless of the value of the 32-bit address. However, this + * behavior can be overridden via the AcpiGbl_Use32BitFadtAddresses flag. + * + ******************************************************************************/ + +static UINT64 +AcpiTbSelectAddress ( + char *RegisterName, + UINT32 Address32, + UINT64 Address64) +{ + + if (!Address64) + { + /* 64-bit address is zero, use 32-bit address */ + + return ((UINT64) Address32); + } + + if (Address32 && + (Address64 != (UINT64) Address32)) + { + /* Address mismatch between 32-bit and 64-bit versions */ + + ACPI_BIOS_WARNING ((AE_INFO, + "32/64X %s address mismatch in FADT: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + RegisterName, Address32, ACPI_FORMAT_UINT64 (Address64), + AcpiGbl_Use32BitFadtAddresses ? 32 : 64)); + + /* 32-bit address override */ + + if (AcpiGbl_Use32BitFadtAddresses) + { + return ((UINT64) Address32); + } + } + + /* Default is to use the 64-bit address */ + + return (Address64); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbParseFadt + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Initialize the FADT, DSDT and FACS tables + * (FADT contains the addresses of the DSDT and FACS) + * + ******************************************************************************/ + +void +AcpiTbParseFadt ( + void) +{ + UINT32 Length; + ACPI_TABLE_HEADER *Table; + + + /* + * The FADT has multiple versions with different lengths, + * and it contains pointers to both the DSDT and FACS tables. + * + * Get a local copy of the FADT and convert it to a common format + * Map entire FADT, assumed to be smaller than one page. + */ + Length = AcpiGbl_RootTableList.Tables[AcpiGbl_FadtIndex].Length; + + Table = AcpiOsMapMemory ( + AcpiGbl_RootTableList.Tables[AcpiGbl_FadtIndex].Address, Length); + if (!Table) + { + return; + } + + /* + * Validate the FADT checksum before we copy the table. Ignore + * checksum error as we want to try to get the DSDT and FACS. + */ + (void) AcpiTbVerifyChecksum (Table, Length); + + /* Create a local copy of the FADT in common ACPI 2.0+ format */ + + AcpiTbCreateLocalFadt (Table, Length); + + /* All done with the real FADT, unmap it */ + + AcpiOsUnmapMemory (Table, Length); + + /* Obtain the DSDT and FACS tables via their addresses within the FADT */ + + AcpiTbInstallFixedTable ((ACPI_PHYSICAL_ADDRESS) AcpiGbl_FADT.XDsdt, + ACPI_SIG_DSDT, &AcpiGbl_DsdtIndex); + + /* If Hardware Reduced flag is set, there is no FACS */ + + if (!AcpiGbl_ReducedHardware) + { + if (AcpiGbl_FADT.Facs) + { + AcpiTbInstallFixedTable ((ACPI_PHYSICAL_ADDRESS) AcpiGbl_FADT.Facs, + ACPI_SIG_FACS, &AcpiGbl_FacsIndex); + } + if (AcpiGbl_FADT.XFacs) + { + AcpiTbInstallFixedTable ((ACPI_PHYSICAL_ADDRESS) AcpiGbl_FADT.XFacs, + ACPI_SIG_FACS, &AcpiGbl_XFacsIndex); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbCreateLocalFadt + * + * PARAMETERS: Table - Pointer to BIOS FADT + * Length - Length of the table + * + * RETURN: None + * + * DESCRIPTION: Get a local copy of the FADT and convert it to a common format. + * Performs validation on some important FADT fields. + * + * NOTE: We create a local copy of the FADT regardless of the version. + * + ******************************************************************************/ + +void +AcpiTbCreateLocalFadt ( + ACPI_TABLE_HEADER *Table, + UINT32 Length) +{ + + /* + * Check if the FADT is larger than the largest table that we expect + * (the ACPI 5.0 version). If so, truncate the table, and issue + * a warning. + */ + if (Length > sizeof (ACPI_TABLE_FADT)) + { + ACPI_BIOS_WARNING ((AE_INFO, + "FADT (revision %u) is longer than ACPI 5.0 version, " + "truncating length %u to %u", + Table->Revision, Length, (UINT32) sizeof (ACPI_TABLE_FADT))); + } + + /* Clear the entire local FADT */ + + memset (&AcpiGbl_FADT, 0, sizeof (ACPI_TABLE_FADT)); + + /* Copy the original FADT, up to sizeof (ACPI_TABLE_FADT) */ + + memcpy (&AcpiGbl_FADT, Table, + ACPI_MIN (Length, sizeof (ACPI_TABLE_FADT))); + + /* Take a copy of the Hardware Reduced flag */ + + AcpiGbl_ReducedHardware = FALSE; + if (AcpiGbl_FADT.Flags & ACPI_FADT_HW_REDUCED) + { + AcpiGbl_ReducedHardware = TRUE; + } + + /* Convert the local copy of the FADT to the common internal format */ + + AcpiTbConvertFadt (); + + /* Initialize the global ACPI register structures */ + + AcpiTbSetupFadtRegisters (); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbConvertFadt + * + * PARAMETERS: None - AcpiGbl_FADT is used. + * + * RETURN: None + * + * DESCRIPTION: Converts all versions of the FADT to a common internal format. + * Expand 32-bit addresses to 64-bit as necessary. Also validate + * important fields within the FADT. + * + * NOTE: AcpiGbl_FADT must be of size (ACPI_TABLE_FADT), and must + * contain a copy of the actual BIOS-provided FADT. + * + * Notes on 64-bit register addresses: + * + * After this FADT conversion, later ACPICA code will only use the 64-bit "X" + * fields of the FADT for all ACPI register addresses. + * + * The 64-bit X fields are optional extensions to the original 32-bit FADT + * V1.0 fields. Even if they are present in the FADT, they are optional and + * are unused if the BIOS sets them to zero. Therefore, we must copy/expand + * 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is + * originally zero. + * + * For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address + * fields are expanded to the corresponding 64-bit X fields in the internal + * common FADT. + * + * For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded + * to the corresponding 64-bit X fields, if the 64-bit field is originally + * zero. Adhering to the ACPI specification, we completely ignore the 32-bit + * field if the 64-bit field is valid, regardless of whether the host OS is + * 32-bit or 64-bit. + * + * Possible additional checks: + * (AcpiGbl_FADT.Pm1EventLength >= 4) + * (AcpiGbl_FADT.Pm1ControlLength >= 2) + * (AcpiGbl_FADT.PmTimerLength >= 4) + * Gpe block lengths must be multiple of 2 + * + ******************************************************************************/ + +static void +AcpiTbConvertFadt ( + void) +{ + char *Name; + ACPI_GENERIC_ADDRESS *Address64; + UINT32 Address32; + UINT8 Length; + UINT8 Flags; + UINT32 i; + + + /* + * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which + * should be zero are indeed zero. This will workaround BIOSs that + * inadvertently place values in these fields. + * + * The ACPI 1.0 reserved fields that will be zeroed are the bytes located + * at offset 45, 55, 95, and the word located at offset 109, 110. + * + * Note: The FADT revision value is unreliable. Only the length can be + * trusted. + */ + if (AcpiGbl_FADT.Header.Length <= ACPI_FADT_V2_SIZE) + { + AcpiGbl_FADT.PreferredProfile = 0; + AcpiGbl_FADT.PstateControl = 0; + AcpiGbl_FADT.CstControl = 0; + AcpiGbl_FADT.BootFlags = 0; + } + + /* + * Now we can update the local FADT length to the length of the + * current FADT version as defined by the ACPI specification. + * Thus, we will have a common FADT internally. + */ + AcpiGbl_FADT.Header.Length = sizeof (ACPI_TABLE_FADT); + + /* + * Expand the 32-bit DSDT addresses to 64-bit as necessary. + * Later ACPICA code will always use the X 64-bit field. + */ + AcpiGbl_FADT.XDsdt = AcpiTbSelectAddress ("DSDT", + AcpiGbl_FADT.Dsdt, AcpiGbl_FADT.XDsdt); + + /* If Hardware Reduced flag is set, we are all done */ + + if (AcpiGbl_ReducedHardware) + { + return; + } + + /* Examine all of the 64-bit extended address fields (X fields) */ + + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) + { + /* + * Get the 32-bit and 64-bit addresses, as well as the register + * length and register name. + */ + Address32 = *ACPI_ADD_PTR (UINT32, + &AcpiGbl_FADT, FadtInfoTable[i].Address32); + + Address64 = ACPI_ADD_PTR (ACPI_GENERIC_ADDRESS, + &AcpiGbl_FADT, FadtInfoTable[i].Address64); + + Length = *ACPI_ADD_PTR (UINT8, + &AcpiGbl_FADT, FadtInfoTable[i].Length); + + Name = FadtInfoTable[i].Name; + Flags = FadtInfoTable[i].Flags; + + /* + * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. Later code will always use + * the 64-bit address structures. + * + * November 2013: + * Now always use the 64-bit address if it is valid (non-zero), in + * accordance with the ACPI specification which states that a 64-bit + * address supersedes the 32-bit version. This behavior can be + * overridden by the AcpiGbl_Use32BitFadtAddresses flag. + * + * During 64-bit address construction and verification, + * these cases are handled: + * + * Address32 zero, Address64 [don't care] - Use Address64 + * + * Address32 non-zero, Address64 zero - Copy/use Address32 + * Address32 non-zero == Address64 non-zero - Use Address64 + * Address32 non-zero != Address64 non-zero - Warning, use Address64 + * + * Override: if AcpiGbl_Use32BitFadtAddresses is TRUE, and: + * Address32 non-zero != Address64 non-zero - Warning, copy/use Address32 + * + * Note: SpaceId is always I/O for 32-bit legacy address fields + */ + if (Address32) + { + if (!Address64->Address) + { + /* 64-bit address is zero, use 32-bit address */ + + AcpiTbInitGenericAddress (Address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR (UINT8, &AcpiGbl_FADT, + FadtInfoTable[i].Length), + (UINT64) Address32, Name, Flags); + } + else if (Address64->Address != (UINT64) Address32) + { + /* Address mismatch */ + + ACPI_BIOS_WARNING ((AE_INFO, + "32/64X address mismatch in FADT/%s: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + Name, Address32, + ACPI_FORMAT_UINT64 (Address64->Address), + AcpiGbl_Use32BitFadtAddresses ? 32 : 64)); + + if (AcpiGbl_Use32BitFadtAddresses) + { + /* 32-bit address override */ + + AcpiTbInitGenericAddress (Address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR (UINT8, &AcpiGbl_FADT, + FadtInfoTable[i].Length), + (UINT64) Address32, Name, Flags); + } + } + } + + /* + * For each extended field, check for length mismatch between the + * legacy length field and the corresponding 64-bit X length field. + * Note: If the legacy length field is > 0xFF bits, ignore this + * check. (GPE registers can be larger than the 64-bit GAS structure + * can accomodate, 0xFF bits). + */ + if (Address64->Address && + (ACPI_MUL_8 (Length) <= ACPI_UINT8_MAX) && + (Address64->BitWidth != ACPI_MUL_8 (Length))) + { + ACPI_BIOS_WARNING ((AE_INFO, + "32/64X length mismatch in FADT/%s: %u/%u", + Name, ACPI_MUL_8 (Length), Address64->BitWidth)); + } + + if (FadtInfoTable[i].Flags & ACPI_FADT_REQUIRED) + { + /* + * Field is required (PM1aEvent, PM1aControl). + * Both the address and length must be non-zero. + */ + if (!Address64->Address || !Length) + { + ACPI_BIOS_ERROR ((AE_INFO, + "Required FADT field %s has zero address and/or length: " + "0x%8.8X%8.8X/0x%X", + Name, ACPI_FORMAT_UINT64 (Address64->Address), Length)); + } + } + else if (FadtInfoTable[i].Flags & ACPI_FADT_SEPARATE_LENGTH) + { + /* + * Field is optional (PM2Control, GPE0, GPE1) AND has its own + * length field. If present, both the address and length must + * be valid. + */ + if ((Address64->Address && !Length) || + (!Address64->Address && Length)) + { + ACPI_BIOS_WARNING ((AE_INFO, + "Optional FADT field %s has zero address or length: " + "0x%8.8X%8.8X/0x%X", + Name, ACPI_FORMAT_UINT64 (Address64->Address), Length)); + } + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbSetupFadtRegisters + * + * PARAMETERS: None, uses AcpiGbl_FADT. + * + * RETURN: None + * + * DESCRIPTION: Initialize global ACPI PM1 register definitions. Optionally, + * force FADT register definitions to their default lengths. + * + ******************************************************************************/ + +static void +AcpiTbSetupFadtRegisters ( + void) +{ + ACPI_GENERIC_ADDRESS *Target64; + ACPI_GENERIC_ADDRESS *Source64; + UINT8 Pm1RegisterByteWidth; + UINT32 i; + + + /* + * Optionally check all register lengths against the default values and + * update them if they are incorrect. + */ + if (AcpiGbl_UseDefaultRegisterWidths) + { + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) + { + Target64 = ACPI_ADD_PTR (ACPI_GENERIC_ADDRESS, &AcpiGbl_FADT, + FadtInfoTable[i].Address64); + + /* + * If a valid register (Address != 0) and the (DefaultLength > 0) + * (Not a GPE register), then check the width against the default. + */ + if ((Target64->Address) && + (FadtInfoTable[i].DefaultLength > 0) && + (FadtInfoTable[i].DefaultLength != Target64->BitWidth)) + { + ACPI_BIOS_WARNING ((AE_INFO, + "Invalid length for FADT/%s: %u, using default %u", + FadtInfoTable[i].Name, Target64->BitWidth, + FadtInfoTable[i].DefaultLength)); + + /* Incorrect size, set width to the default */ + + Target64->BitWidth = FadtInfoTable[i].DefaultLength; + } + } + } + + /* + * Get the length of the individual PM1 registers (enable and status). + * Each register is defined to be (event block length / 2). Extra divide + * by 8 converts bits to bytes. + */ + Pm1RegisterByteWidth = (UINT8) + ACPI_DIV_16 (AcpiGbl_FADT.XPm1aEventBlock.BitWidth); + + /* + * Calculate separate GAS structs for the PM1x (A/B) Status and Enable + * registers. These addresses do not appear (directly) in the FADT, so it + * is useful to pre-calculate them from the PM1 Event Block definitions. + * + * The PM event blocks are split into two register blocks, first is the + * PM Status Register block, followed immediately by the PM Enable + * Register block. Each is of length (Pm1EventLength/2) + * + * Note: The PM1A event block is required by the ACPI specification. + * However, the PM1B event block is optional and is rarely, if ever, + * used. + */ + + for (i = 0; i < ACPI_FADT_PM_INFO_ENTRIES; i++) + { + Source64 = ACPI_ADD_PTR (ACPI_GENERIC_ADDRESS, &AcpiGbl_FADT, + FadtPmInfoTable[i].Source); + + if (Source64->Address) + { + AcpiTbInitGenericAddress (FadtPmInfoTable[i].Target, + Source64->SpaceId, Pm1RegisterByteWidth, + Source64->Address + + (FadtPmInfoTable[i].RegisterNum * Pm1RegisterByteWidth), + "PmRegisters", 0); + } + } +} diff --git a/third_party/lib/acpica/source/components/tables/tbfind.c b/third_party/lib/acpica/source/components/tables/tbfind.c new file mode 100644 index 000000000..d144cab62 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbfind.c @@ -0,0 +1,156 @@ +/****************************************************************************** + * + * Module Name: tbfind - find table + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbfind") + + +/******************************************************************************* + * + * FUNCTION: AcpiTbFindTable + * + * PARAMETERS: Signature - String with ACPI table signature + * OemId - String with the table OEM ID + * OemTableId - String with the OEM Table ID + * TableIndex - Where the table index is returned + * + * RETURN: Status and table index + * + * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the + * Signature, OEM ID and OEM Table ID. Returns an index that can + * be used to get the table header or entire table. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbFindTable ( + char *Signature, + char *OemId, + char *OemTableId, + UINT32 *TableIndex) +{ + ACPI_STATUS Status; + ACPI_TABLE_HEADER Header; + UINT32 i; + + + ACPI_FUNCTION_TRACE (TbFindTable); + + + /* Validate the input table signature */ + + if (!AcpiIsValidSignature (Signature)) + { + return_ACPI_STATUS (AE_BAD_SIGNATURE); + } + + /* Don't allow the OEM strings to be too long */ + + if ((strlen (OemId) > ACPI_OEM_ID_SIZE) || + (strlen (OemTableId) > ACPI_OEM_TABLE_ID_SIZE)) + { + return_ACPI_STATUS (AE_AML_STRING_LIMIT); + } + + /* Normalize the input strings */ + + memset (&Header, 0, sizeof (ACPI_TABLE_HEADER)); + ACPI_MOVE_NAME (Header.Signature, Signature); + strncpy (Header.OemId, OemId, ACPI_OEM_ID_SIZE); + strncpy (Header.OemTableId, OemTableId, ACPI_OEM_TABLE_ID_SIZE); + + /* Search for the table */ + + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i) + { + if (memcmp (&(AcpiGbl_RootTableList.Tables[i].Signature), + Header.Signature, ACPI_NAME_SIZE)) + { + /* Not the requested table */ + + continue; + } + + /* Table with matching signature has been found */ + + if (!AcpiGbl_RootTableList.Tables[i].Pointer) + { + /* Table is not currently mapped, map it */ + + Status = AcpiTbValidateTable (&AcpiGbl_RootTableList.Tables[i]); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (!AcpiGbl_RootTableList.Tables[i].Pointer) + { + continue; + } + } + + /* Check for table match on all IDs */ + + if (!memcmp (AcpiGbl_RootTableList.Tables[i].Pointer->Signature, + Header.Signature, ACPI_NAME_SIZE) && + (!OemId[0] || + !memcmp (AcpiGbl_RootTableList.Tables[i].Pointer->OemId, + Header.OemId, ACPI_OEM_ID_SIZE)) && + (!OemTableId[0] || + !memcmp (AcpiGbl_RootTableList.Tables[i].Pointer->OemTableId, + Header.OemTableId, ACPI_OEM_TABLE_ID_SIZE))) + { + *TableIndex = i; + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", + Header.Signature)); + return_ACPI_STATUS (AE_OK); + } + } + + return_ACPI_STATUS (AE_NOT_FOUND); +} diff --git a/third_party/lib/acpica/source/components/tables/tbinstal.c b/third_party/lib/acpica/source/components/tables/tbinstal.c new file mode 100644 index 000000000..d5ae92083 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbinstal.c @@ -0,0 +1,528 @@ +/****************************************************************************** + * + * Module Name: tbinstal - ACPI table installation and removal + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbinstal") + +/* Local prototypes */ + +static BOOLEAN +AcpiTbCompareTables ( + ACPI_TABLE_DESC *TableDesc, + UINT32 TableIndex); + + +/******************************************************************************* + * + * FUNCTION: AcpiTbCompareTables + * + * PARAMETERS: TableDesc - Table 1 descriptor to be compared + * TableIndex - Index of table 2 to be compared + * + * RETURN: TRUE if both tables are identical. + * + * DESCRIPTION: This function compares a table with another table that has + * already been installed in the root table list. + * + ******************************************************************************/ + +static BOOLEAN +AcpiTbCompareTables ( + ACPI_TABLE_DESC *TableDesc, + UINT32 TableIndex) +{ + ACPI_STATUS Status = AE_OK; + BOOLEAN IsIdentical; + ACPI_TABLE_HEADER *Table; + UINT32 TableLength; + UINT8 TableFlags; + + + Status = AcpiTbAcquireTable (&AcpiGbl_RootTableList.Tables[TableIndex], + &Table, &TableLength, &TableFlags); + if (ACPI_FAILURE (Status)) + { + return (FALSE); + } + + /* + * Check for a table match on the entire table length, + * not just the header. + */ + IsIdentical = (BOOLEAN)((TableDesc->Length != TableLength || + memcmp (TableDesc->Pointer, Table, TableLength)) ? + FALSE : TRUE); + + /* Release the acquired table */ + + AcpiTbReleaseTable (Table, TableLength, TableFlags); + return (IsIdentical); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbInstallTableWithOverride + * + * PARAMETERS: NewTableDesc - New table descriptor to install + * Override - Whether override should be performed + * TableIndex - Where the table index is returned + * + * RETURN: None + * + * DESCRIPTION: Install an ACPI table into the global data structure. The + * table override mechanism is called to allow the host + * OS to replace any table before it is installed in the root + * table array. + * + ******************************************************************************/ + +void +AcpiTbInstallTableWithOverride ( + ACPI_TABLE_DESC *NewTableDesc, + BOOLEAN Override, + UINT32 *TableIndex) +{ + UINT32 i; + ACPI_STATUS Status; + + + Status = AcpiTbGetNextTableDescriptor (&i, NULL); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* + * ACPI Table Override: + * + * Before we install the table, let the host OS override it with a new + * one if desired. Any table within the RSDT/XSDT can be replaced, + * including the DSDT which is pointed to by the FADT. + */ + if (Override) + { + AcpiTbOverrideTable (NewTableDesc); + } + + AcpiTbInitTableDescriptor (&AcpiGbl_RootTableList.Tables[i], + NewTableDesc->Address, NewTableDesc->Flags, NewTableDesc->Pointer); + + AcpiTbPrintTableHeader (NewTableDesc->Address, NewTableDesc->Pointer); + + /* This synchronizes AcpiGbl_DsdtIndex */ + + *TableIndex = i; + + /* Set the global integer width (based upon revision of the DSDT) */ + + if (i == AcpiGbl_DsdtIndex) + { + AcpiUtSetIntegerWidth (NewTableDesc->Pointer->Revision); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbInstallFixedTable + * + * PARAMETERS: Address - Physical address of DSDT or FACS + * Signature - Table signature, NULL if no need to + * match + * TableIndex - Where the table index is returned + * + * RETURN: Status + * + * DESCRIPTION: Install a fixed ACPI table (DSDT/FACS) into the global data + * structure. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbInstallFixedTable ( + ACPI_PHYSICAL_ADDRESS Address, + char *Signature, + UINT32 *TableIndex) +{ + ACPI_TABLE_DESC NewTableDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (TbInstallFixedTable); + + + if (!Address) + { + ACPI_ERROR ((AE_INFO, "Null physical address for ACPI table [%s]", + Signature)); + return (AE_NO_MEMORY); + } + + /* Fill a table descriptor for validation */ + + Status = AcpiTbAcquireTempTable (&NewTableDesc, Address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, "Could not acquire table length at %8.8X%8.8X", + ACPI_FORMAT_UINT64 (Address))); + return_ACPI_STATUS (Status); + } + + /* Validate and verify a table before installation */ + + Status = AcpiTbVerifyTempTable (&NewTableDesc, Signature); + if (ACPI_FAILURE (Status)) + { + goto ReleaseAndExit; + } + + /* Add the table to the global root table list */ + + AcpiTbInstallTableWithOverride (&NewTableDesc, TRUE, TableIndex); + +ReleaseAndExit: + + /* Release the temporary table descriptor */ + + AcpiTbReleaseTempTable (&NewTableDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbInstallStandardTable + * + * PARAMETERS: Address - Address of the table (might be a virtual + * address depending on the TableFlags) + * Flags - Flags for the table + * Reload - Whether reload should be performed + * Override - Whether override should be performed + * TableIndex - Where the table index is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to install an ACPI table that is + * neither DSDT nor FACS (a "standard" table.) + * When this function is called by "Load" or "LoadTable" opcodes, + * or by AcpiLoadTable() API, the "Reload" parameter is set. + * After sucessfully returning from this function, table is + * "INSTALLED" but not "VALIDATED". + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbInstallStandardTable ( + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + BOOLEAN Reload, + BOOLEAN Override, + UINT32 *TableIndex) +{ + UINT32 i; + ACPI_STATUS Status = AE_OK; + ACPI_TABLE_DESC NewTableDesc; + + + ACPI_FUNCTION_TRACE (TbInstallStandardTable); + + + /* Acquire a temporary table descriptor for validation */ + + Status = AcpiTbAcquireTempTable (&NewTableDesc, Address, Flags); + if (ACPI_FAILURE (Status)) + { + ACPI_ERROR ((AE_INFO, + "Could not acquire table length at %8.8X%8.8X", + ACPI_FORMAT_UINT64 (Address))); + return_ACPI_STATUS (Status); + } + + /* + * Optionally do not load any SSDTs from the RSDT/XSDT. This can + * be useful for debugging ACPI problems on some machines. + */ + if (!Reload && + AcpiGbl_DisableSsdtTableInstall && + ACPI_COMPARE_NAME (&NewTableDesc.Signature, ACPI_SIG_SSDT)) + { + ACPI_INFO ((AE_INFO, + "Ignoring installation of %4.4s at %8.8X%8.8X", + NewTableDesc.Signature.Ascii, ACPI_FORMAT_UINT64 (Address))); + goto ReleaseAndExit; + } + + /* Validate and verify a table before installation */ + + Status = AcpiTbVerifyTempTable (&NewTableDesc, NULL); + if (ACPI_FAILURE (Status)) + { + goto ReleaseAndExit; + } + + if (Reload) + { + /* + * Validate the incoming table signature. + * + * 1) Originally, we checked the table signature for "SSDT" or "PSDT". + * 2) We added support for OEMx tables, signature "OEM". + * 3) Valid tables were encountered with a null signature, so we just + * gave up on validating the signature, (05/2008). + * 4) We encountered non-AML tables such as the MADT, which caused + * interpreter errors and kernel faults. So now, we once again allow + * only "SSDT", "OEMx", and now, also a null signature. (05/2011). + */ + if ((NewTableDesc.Signature.Ascii[0] != 0x00) && + (!ACPI_COMPARE_NAME (&NewTableDesc.Signature, ACPI_SIG_SSDT)) && + (strncmp (NewTableDesc.Signature.Ascii, "OEM", 3))) + { + ACPI_BIOS_ERROR ((AE_INFO, + "Table has invalid signature [%4.4s] (0x%8.8X), " + "must be SSDT or OEMx", + AcpiUtValidAcpiName (NewTableDesc.Signature.Ascii) ? + NewTableDesc.Signature.Ascii : "????", + NewTableDesc.Signature.Integer)); + + Status = AE_BAD_SIGNATURE; + goto ReleaseAndExit; + } + + /* Check if table is already registered */ + + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i) + { + /* + * Check for a table match on the entire table length, + * not just the header. + */ + if (!AcpiTbCompareTables (&NewTableDesc, i)) + { + continue; + } + + /* + * Note: the current mechanism does not unregister a table if it is + * dynamically unloaded. The related namespace entries are deleted, + * but the table remains in the root table list. + * + * The assumption here is that the number of different tables that + * will be loaded is actually small, and there is minimal overhead + * in just keeping the table in case it is needed again. + * + * If this assumption changes in the future (perhaps on large + * machines with many table load/unload operations), tables will + * need to be unregistered when they are unloaded, and slots in the + * root table list should be reused when empty. + */ + if (AcpiGbl_RootTableList.Tables[i].Flags & + ACPI_TABLE_IS_LOADED) + { + /* Table is still loaded, this is an error */ + + Status = AE_ALREADY_EXISTS; + goto ReleaseAndExit; + } + else + { + /* + * Table was unloaded, allow it to be reloaded. + * As we are going to return AE_OK to the caller, we should + * take the responsibility of freeing the input descriptor. + * Refill the input descriptor to ensure + * AcpiTbInstallTableWithOverride() can be called again to + * indicate the re-installation. + */ + AcpiTbUninstallTable (&NewTableDesc); + *TableIndex = i; + return_ACPI_STATUS (AE_OK); + } + } + } + + /* Add the table to the global root table list */ + + AcpiTbInstallTableWithOverride (&NewTableDesc, Override, TableIndex); + +ReleaseAndExit: + + /* Release the temporary table descriptor */ + + AcpiTbReleaseTempTable (&NewTableDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbOverrideTable + * + * PARAMETERS: OldTableDesc - Validated table descriptor to be + * overridden + * + * RETURN: None + * + * DESCRIPTION: Attempt table override by calling the OSL override functions. + * Note: If the table is overridden, then the entire new table + * is acquired and returned by this function. + * Before/after invocation, the table descriptor is in a state + * that is "VALIDATED". + * + ******************************************************************************/ + +void +AcpiTbOverrideTable ( + ACPI_TABLE_DESC *OldTableDesc) +{ + ACPI_STATUS Status; + char *OverrideType; + ACPI_TABLE_DESC NewTableDesc; + ACPI_TABLE_HEADER *Table; + ACPI_PHYSICAL_ADDRESS Address; + UINT32 Length; + + + /* (1) Attempt logical override (returns a logical address) */ + + Status = AcpiOsTableOverride (OldTableDesc->Pointer, &Table); + if (ACPI_SUCCESS (Status) && Table) + { + AcpiTbAcquireTempTable (&NewTableDesc, ACPI_PTR_TO_PHYSADDR (Table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); + OverrideType = "Logical"; + goto FinishOverride; + } + + /* (2) Attempt physical override (returns a physical address) */ + + Status = AcpiOsPhysicalTableOverride (OldTableDesc->Pointer, + &Address, &Length); + if (ACPI_SUCCESS (Status) && Address && Length) + { + AcpiTbAcquireTempTable (&NewTableDesc, Address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); + OverrideType = "Physical"; + goto FinishOverride; + } + + return; /* There was no override */ + + +FinishOverride: + + /* Validate and verify a table before overriding */ + + Status = AcpiTbVerifyTempTable (&NewTableDesc, NULL); + if (ACPI_FAILURE (Status)) + { + return; + } + + ACPI_INFO ((AE_INFO, "%4.4s 0x%8.8X%8.8X" + " %s table override, new table: 0x%8.8X%8.8X", + OldTableDesc->Signature.Ascii, + ACPI_FORMAT_UINT64 (OldTableDesc->Address), + OverrideType, ACPI_FORMAT_UINT64 (NewTableDesc.Address))); + + /* We can now uninstall the original table */ + + AcpiTbUninstallTable (OldTableDesc); + + /* + * Replace the original table descriptor and keep its state as + * "VALIDATED". + */ + AcpiTbInitTableDescriptor (OldTableDesc, NewTableDesc.Address, + NewTableDesc.Flags, NewTableDesc.Pointer); + AcpiTbValidateTempTable (OldTableDesc); + + /* Release the temporary table descriptor */ + + AcpiTbReleaseTempTable (&NewTableDesc); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbUninstallTable + * + * PARAMETERS: TableDesc - Table descriptor + * + * RETURN: None + * + * DESCRIPTION: Delete one internal ACPI table + * + ******************************************************************************/ + +void +AcpiTbUninstallTable ( + ACPI_TABLE_DESC *TableDesc) +{ + + ACPI_FUNCTION_TRACE (TbUninstallTable); + + + /* Table must be installed */ + + if (!TableDesc->Address) + { + return_VOID; + } + + AcpiTbInvalidateTable (TableDesc); + + if ((TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) + { + ACPI_FREE (ACPI_PHYSADDR_TO_PTR (TableDesc->Address)); + } + + TableDesc->Address = ACPI_PTR_TO_PHYSADDR (NULL); + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/tables/tbprint.c b/third_party/lib/acpica/source/components/tables/tbprint.c new file mode 100644 index 000000000..65ce70936 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbprint.c @@ -0,0 +1,272 @@ +/****************************************************************************** + * + * Module Name: tbprint - Table output utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbprint") + + +/* Local prototypes */ + +static void +AcpiTbFixString ( + char *String, + ACPI_SIZE Length); + +static void +AcpiTbCleanupTableHeader ( + ACPI_TABLE_HEADER *OutHeader, + ACPI_TABLE_HEADER *Header); + + +/******************************************************************************* + * + * FUNCTION: AcpiTbFixString + * + * PARAMETERS: String - String to be repaired + * Length - Maximum length + * + * RETURN: None + * + * DESCRIPTION: Replace every non-printable or non-ascii byte in the string + * with a question mark '?'. + * + ******************************************************************************/ + +static void +AcpiTbFixString ( + char *String, + ACPI_SIZE Length) +{ + + while (Length && *String) + { + if (!isprint ((int) *String)) + { + *String = '?'; + } + + String++; + Length--; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbCleanupTableHeader + * + * PARAMETERS: OutHeader - Where the cleaned header is returned + * Header - Input ACPI table header + * + * RETURN: Returns the cleaned header in OutHeader + * + * DESCRIPTION: Copy the table header and ensure that all "string" fields in + * the header consist of printable characters. + * + ******************************************************************************/ + +static void +AcpiTbCleanupTableHeader ( + ACPI_TABLE_HEADER *OutHeader, + ACPI_TABLE_HEADER *Header) +{ + + memcpy (OutHeader, Header, sizeof (ACPI_TABLE_HEADER)); + + AcpiTbFixString (OutHeader->Signature, ACPI_NAME_SIZE); + AcpiTbFixString (OutHeader->OemId, ACPI_OEM_ID_SIZE); + AcpiTbFixString (OutHeader->OemTableId, ACPI_OEM_TABLE_ID_SIZE); + AcpiTbFixString (OutHeader->AslCompilerId, ACPI_NAME_SIZE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbPrintTableHeader + * + * PARAMETERS: Address - Table physical address + * Header - Table header + * + * RETURN: None + * + * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP. + * + ******************************************************************************/ + +void +AcpiTbPrintTableHeader ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER *Header) +{ + ACPI_TABLE_HEADER LocalHeader; + + + if (ACPI_COMPARE_NAME (Header->Signature, ACPI_SIG_FACS)) + { + /* FACS only has signature and length fields */ + + ACPI_INFO ((AE_INFO, "%-4.4s 0x%8.8X%8.8X %06X", + Header->Signature, ACPI_FORMAT_UINT64 (Address), + Header->Length)); + } + else if (ACPI_VALIDATE_RSDP_SIG (Header->Signature)) + { + /* RSDP has no common fields */ + + memcpy (LocalHeader.OemId, ACPI_CAST_PTR (ACPI_TABLE_RSDP, + Header)->OemId, ACPI_OEM_ID_SIZE); + AcpiTbFixString (LocalHeader.OemId, ACPI_OEM_ID_SIZE); + + ACPI_INFO ((AE_INFO, "RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)", + ACPI_FORMAT_UINT64 (Address), + (ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision > 0) ? + ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Length : 20, + ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision, + LocalHeader.OemId)); + } + else + { + /* Standard ACPI table with full common header */ + + AcpiTbCleanupTableHeader (&LocalHeader, Header); + + ACPI_INFO ((AE_INFO, + "%-4.4s 0x%8.8X%8.8X" + " %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)", + LocalHeader.Signature, ACPI_FORMAT_UINT64 (Address), + LocalHeader.Length, LocalHeader.Revision, LocalHeader.OemId, + LocalHeader.OemTableId, LocalHeader.OemRevision, + LocalHeader.AslCompilerId, LocalHeader.AslCompilerRevision)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbValidateChecksum + * + * PARAMETERS: Table - ACPI table to verify + * Length - Length of entire table + * + * RETURN: Status + * + * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns + * exception on bad checksum. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbVerifyChecksum ( + ACPI_TABLE_HEADER *Table, + UINT32 Length) +{ + UINT8 Checksum; + + + /* + * FACS/S3PT: + * They are the odd tables, have no standard ACPI header and no checksum + */ + + if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_S3PT) || + ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_FACS)) + { + return (AE_OK); + } + + /* Compute the checksum on the table */ + + Checksum = AcpiTbChecksum (ACPI_CAST_PTR (UINT8, Table), Length); + + /* Checksum ok? (should be zero) */ + + if (Checksum) + { + ACPI_BIOS_WARNING ((AE_INFO, + "Incorrect checksum in table [%4.4s] - 0x%2.2X, " + "should be 0x%2.2X", + Table->Signature, Table->Checksum, + (UINT8) (Table->Checksum - Checksum))); + +#if (ACPI_CHECKSUM_ABORT) + return (AE_BAD_CHECKSUM); +#endif + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbChecksum + * + * PARAMETERS: Buffer - Pointer to memory region to be checked + * Length - Length of this memory region + * + * RETURN: Checksum (UINT8) + * + * DESCRIPTION: Calculates circular checksum of memory region. + * + ******************************************************************************/ + +UINT8 +AcpiTbChecksum ( + UINT8 *Buffer, + UINT32 Length) +{ + UINT8 Sum = 0; + UINT8 *End = Buffer + Length; + + + while (Buffer < End) + { + Sum = (UINT8) (Sum + *(Buffer++)); + } + + return (Sum); +} diff --git a/third_party/lib/acpica/source/components/tables/tbutils.c b/third_party/lib/acpica/source/components/tables/tbutils.c new file mode 100644 index 000000000..0a34708af --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbutils.c @@ -0,0 +1,446 @@ +/****************************************************************************** + * + * Module Name: tbutils - ACPI Table utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbutils") + + +/* Local prototypes */ + +static ACPI_PHYSICAL_ADDRESS +AcpiTbGetRootTableEntry ( + UINT8 *TableEntry, + UINT32 TableEntrySize); + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiTbInitializeFacs + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global + * for accessing the Global Lock and Firmware Waking Vector + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbInitializeFacs ( + void) +{ + ACPI_TABLE_FACS *Facs; + + + /* If Hardware Reduced flag is set, there is no FACS */ + + if (AcpiGbl_ReducedHardware) + { + AcpiGbl_FACS = NULL; + return (AE_OK); + } + else if (AcpiGbl_FADT.XFacs && + (!AcpiGbl_FADT.Facs || !AcpiGbl_Use32BitFacsAddresses)) + { + (void) AcpiGetTableByIndex (AcpiGbl_XFacsIndex, + ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Facs)); + AcpiGbl_FACS = Facs; + } + else if (AcpiGbl_FADT.Facs) + { + (void) AcpiGetTableByIndex (AcpiGbl_FacsIndex, + ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Facs)); + AcpiGbl_FACS = Facs; + } + + /* If there is no FACS, just continue. There was already an error msg */ + + return (AE_OK); +} +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiTbCheckDsdtHeader + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect + * if the DSDT has been replaced from outside the OS and/or if + * the DSDT header has been corrupted. + * + ******************************************************************************/ + +void +AcpiTbCheckDsdtHeader ( + void) +{ + + /* Compare original length and checksum to current values */ + + if (AcpiGbl_OriginalDsdtHeader.Length != AcpiGbl_DSDT->Length || + AcpiGbl_OriginalDsdtHeader.Checksum != AcpiGbl_DSDT->Checksum) + { + ACPI_BIOS_ERROR ((AE_INFO, + "The DSDT has been corrupted or replaced - " + "old, new headers below")); + + AcpiTbPrintTableHeader (0, &AcpiGbl_OriginalDsdtHeader); + AcpiTbPrintTableHeader (0, AcpiGbl_DSDT); + + /* Disable further error messages */ + + AcpiGbl_OriginalDsdtHeader.Length = AcpiGbl_DSDT->Length; + AcpiGbl_OriginalDsdtHeader.Checksum = AcpiGbl_DSDT->Checksum; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbCopyDsdt + * + * PARAMETERS: TableDesc - Installed table to copy + * + * RETURN: None + * + * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. + * Some very bad BIOSs are known to either corrupt the DSDT or + * install a new, bad DSDT. This copy works around the problem. + * + ******************************************************************************/ + +ACPI_TABLE_HEADER * +AcpiTbCopyDsdt ( + UINT32 TableIndex) +{ + ACPI_TABLE_HEADER *NewTable; + ACPI_TABLE_DESC *TableDesc; + + + TableDesc = &AcpiGbl_RootTableList.Tables[TableIndex]; + + NewTable = ACPI_ALLOCATE (TableDesc->Length); + if (!NewTable) + { + ACPI_ERROR ((AE_INFO, "Could not copy DSDT of length 0x%X", + TableDesc->Length)); + return (NULL); + } + + memcpy (NewTable, TableDesc->Pointer, TableDesc->Length); + AcpiTbUninstallTable (TableDesc); + + AcpiTbInitTableDescriptor ( + &AcpiGbl_RootTableList.Tables[AcpiGbl_DsdtIndex], + ACPI_PTR_TO_PHYSADDR (NewTable), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, NewTable); + + ACPI_INFO ((AE_INFO, + "Forced DSDT copy: length 0x%05X copied locally, original unmapped", + NewTable->Length)); + + return (NewTable); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbGetRootTableEntry + * + * PARAMETERS: TableEntry - Pointer to the RSDT/XSDT table entry + * TableEntrySize - sizeof 32 or 64 (RSDT or XSDT) + * + * RETURN: Physical address extracted from the root table + * + * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on + * both 32-bit and 64-bit platforms + * + * NOTE: ACPI_PHYSICAL_ADDRESS is 32-bit on 32-bit platforms, 64-bit on + * 64-bit platforms. + * + ******************************************************************************/ + +static ACPI_PHYSICAL_ADDRESS +AcpiTbGetRootTableEntry ( + UINT8 *TableEntry, + UINT32 TableEntrySize) +{ + UINT64 Address64; + + + /* + * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): + * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT + */ + if (TableEntrySize == ACPI_RSDT_ENTRY_SIZE) + { + /* + * 32-bit platform, RSDT: Return 32-bit table entry + * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return + */ + return ((ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST_PTR ( + UINT32, TableEntry))); + } + else + { + /* + * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return + * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, + * return 64-bit + */ + ACPI_MOVE_64_TO_64 (&Address64, TableEntry); + +#if ACPI_MACHINE_WIDTH == 32 + if (Address64 > ACPI_UINT32_MAX) + { + /* Will truncate 64-bit address to 32 bits, issue warning */ + + ACPI_BIOS_WARNING ((AE_INFO, + "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X)," + " truncating", + ACPI_FORMAT_UINT64 (Address64))); + } +#endif + return ((ACPI_PHYSICAL_ADDRESS) (Address64)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbParseRootTable + * + * PARAMETERS: Rsdp - Pointer to the RSDP + * + * RETURN: Status + * + * DESCRIPTION: This function is called to parse the Root System Description + * Table (RSDT or XSDT) + * + * NOTE: Tables are mapped (not copied) for efficiency. The FACS must + * be mapped and cannot be copied because it contains the actual + * memory location of the ACPI Global Lock. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbParseRootTable ( + ACPI_PHYSICAL_ADDRESS RsdpAddress) +{ + ACPI_TABLE_RSDP *Rsdp; + UINT32 TableEntrySize; + UINT32 i; + UINT32 TableCount; + ACPI_TABLE_HEADER *Table; + ACPI_PHYSICAL_ADDRESS Address; + UINT32 Length; + UINT8 *TableEntry; + ACPI_STATUS Status; + UINT32 TableIndex; + + + ACPI_FUNCTION_TRACE (TbParseRootTable); + + + /* Map the entire RSDP and extract the address of the RSDT or XSDT */ + + Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP)); + if (!Rsdp) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + AcpiTbPrintTableHeader (RsdpAddress, + ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp)); + + /* Use XSDT if present and not overridden. Otherwise, use RSDT */ + + if ((Rsdp->Revision > 1) && + Rsdp->XsdtPhysicalAddress && + !AcpiGbl_DoNotUseXsdt) + { + /* + * RSDP contains an XSDT (64-bit physical addresses). We must use + * the XSDT if the revision is > 1 and the XSDT pointer is present, + * as per the ACPI specification. + */ + Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress; + TableEntrySize = ACPI_XSDT_ENTRY_SIZE; + } + else + { + /* Root table is an RSDT (32-bit physical addresses) */ + + Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress; + TableEntrySize = ACPI_RSDT_ENTRY_SIZE; + } + + /* + * It is not possible to map more than one entry in some environments, + * so unmap the RSDP here before mapping other tables + */ + AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP)); + + /* Map the RSDT/XSDT table header to get the full table length */ + + Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); + if (!Table) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + AcpiTbPrintTableHeader (Address, Table); + + /* + * Validate length of the table, and map entire table. + * Minimum length table must contain at least one entry. + */ + Length = Table->Length; + AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER)); + + if (Length < (sizeof (ACPI_TABLE_HEADER) + TableEntrySize)) + { + ACPI_BIOS_ERROR ((AE_INFO, + "Invalid table length 0x%X in RSDT/XSDT", Length)); + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } + + Table = AcpiOsMapMemory (Address, Length); + if (!Table) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Validate the root table checksum */ + + Status = AcpiTbVerifyChecksum (Table, Length); + if (ACPI_FAILURE (Status)) + { + AcpiOsUnmapMemory (Table, Length); + return_ACPI_STATUS (Status); + } + + /* Get the number of entries and pointer to first entry */ + + TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) / + TableEntrySize); + TableEntry = ACPI_ADD_PTR (UINT8, Table, sizeof (ACPI_TABLE_HEADER)); + + /* Initialize the root table array from the RSDT/XSDT */ + + for (i = 0; i < TableCount; i++) + { + /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ + + Address = AcpiTbGetRootTableEntry (TableEntry, TableEntrySize); + + /* Skip NULL entries in RSDT/XSDT */ + + if (!Address) + { + goto NextTable; + } + + Status = AcpiTbInstallStandardTable (Address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, FALSE, TRUE, &TableIndex); + + if (ACPI_SUCCESS (Status) && + ACPI_COMPARE_NAME ( + &AcpiGbl_RootTableList.Tables[TableIndex].Signature, + ACPI_SIG_FADT)) + { + AcpiGbl_FadtIndex = TableIndex; + AcpiTbParseFadt (); + } + +NextTable: + + TableEntry += TableEntrySize; + } + + AcpiOsUnmapMemory (Table, Length); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiIsValidSignature + * + * PARAMETERS: Signature - Sig string to be validated + * + * RETURN: TRUE if signature is has 4 valid ACPI characters + * + * DESCRIPTION: Validate an ACPI table signature. + * + ******************************************************************************/ + +BOOLEAN +AcpiIsValidSignature ( + char *Signature) +{ + UINT32 i; + + + /* Validate each character in the signature */ + + for (i = 0; i < ACPI_NAME_SIZE; i++) + { + if (!AcpiUtValidAcpiChar (Signature[i], i)) + { + return (FALSE); + } + } + + return (TRUE); +} diff --git a/third_party/lib/acpica/source/components/tables/tbxface.c b/third_party/lib/acpica/source/components/tables/tbxface.c new file mode 100644 index 000000000..8c0caaee7 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbxface.c @@ -0,0 +1,527 @@ +/****************************************************************************** + * + * Module Name: tbxface - ACPI table-oriented external interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbxface") + + +/******************************************************************************* + * + * FUNCTION: AcpiAllocateRootTable + * + * PARAMETERS: InitialTableCount - Size of InitialTableArray, in number of + * ACPI_TABLE_DESC structures + * + * RETURN: Status + * + * DESCRIPTION: Allocate a root table array. Used by iASL compiler and + * AcpiInitializeTables. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiAllocateRootTable ( + UINT32 InitialTableCount) +{ + + AcpiGbl_RootTableList.MaxTableCount = InitialTableCount; + AcpiGbl_RootTableList.Flags = ACPI_ROOT_ALLOW_RESIZE; + + return (AcpiTbResizeRootTableList ()); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiInitializeTables + * + * PARAMETERS: InitialTableArray - Pointer to an array of pre-allocated + * ACPI_TABLE_DESC structures. If NULL, the + * array is dynamically allocated. + * InitialTableCount - Size of InitialTableArray, in number of + * ACPI_TABLE_DESC structures + * AllowResize - Flag to tell Table Manager if resize of + * pre-allocated array is allowed. Ignored + * if InitialTableArray is NULL. + * + * RETURN: Status + * + * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT. + * + * NOTE: Allows static allocation of the initial table array in order + * to avoid the use of dynamic memory in confined environments + * such as the kernel boot sequence where it may not be available. + * + * If the host OS memory managers are initialized, use NULL for + * InitialTableArray, and the table will be dynamically allocated. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInitializeTables ( + ACPI_TABLE_DESC *InitialTableArray, + UINT32 InitialTableCount, + BOOLEAN AllowResize) +{ + ACPI_PHYSICAL_ADDRESS RsdpAddress; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInitializeTables); + + + /* + * Setup the Root Table Array and allocate the table array + * if requested + */ + if (!InitialTableArray) + { + Status = AcpiAllocateRootTable (InitialTableCount); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + else + { + /* Root Table Array has been statically allocated by the host */ + + memset (InitialTableArray, 0, + (ACPI_SIZE) InitialTableCount * sizeof (ACPI_TABLE_DESC)); + + AcpiGbl_RootTableList.Tables = InitialTableArray; + AcpiGbl_RootTableList.MaxTableCount = InitialTableCount; + AcpiGbl_RootTableList.Flags = ACPI_ROOT_ORIGIN_UNKNOWN; + if (AllowResize) + { + AcpiGbl_RootTableList.Flags |= ACPI_ROOT_ALLOW_RESIZE; + } + } + + /* Get the address of the RSDP */ + + RsdpAddress = AcpiOsGetRootPointer (); + if (!RsdpAddress) + { + return_ACPI_STATUS (AE_NOT_FOUND); + } + + /* + * Get the root table (RSDT or XSDT) and extract all entries to the local + * Root Table Array. This array contains the information of the RSDT/XSDT + * in a common, more useable format. + */ + Status = AcpiTbParseRootTable (RsdpAddress); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiInitializeTables) + + +/******************************************************************************* + * + * FUNCTION: AcpiReallocateRootTable + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the + * root list from the previously provided scratch area. Should + * be called once dynamic memory allocation is available in the + * kernel. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReallocateRootTable ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiReallocateRootTable); + + + /* + * Only reallocate the root table if the host provided a static buffer + * for the table array in the call to AcpiInitializeTables. + */ + if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED) + { + return_ACPI_STATUS (AE_SUPPORT); + } + + AcpiGbl_RootTableList.Flags |= ACPI_ROOT_ALLOW_RESIZE; + + Status = AcpiTbResizeRootTableList (); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiReallocateRootTable) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetTableHeader + * + * PARAMETERS: Signature - ACPI signature of needed table + * Instance - Which instance (for SSDTs) + * OutTableHeader - The pointer to the table header to fill + * + * RETURN: Status and pointer to mapped table header + * + * DESCRIPTION: Finds an ACPI table header. + * + * NOTE: Caller is responsible in unmapping the header with + * AcpiOsUnmapMemory + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTableHeader ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER *OutTableHeader) +{ + UINT32 i; + UINT32 j; + ACPI_TABLE_HEADER *Header; + + + /* Parameter validation */ + + if (!Signature || !OutTableHeader) + { + return (AE_BAD_PARAMETER); + } + + /* Walk the root table list */ + + for (i = 0, j = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++) + { + if (!ACPI_COMPARE_NAME ( + &(AcpiGbl_RootTableList.Tables[i].Signature), Signature)) + { + continue; + } + + if (++j < Instance) + { + continue; + } + + if (!AcpiGbl_RootTableList.Tables[i].Pointer) + { + if ((AcpiGbl_RootTableList.Tables[i].Flags & + ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) + { + Header = AcpiOsMapMemory ( + AcpiGbl_RootTableList.Tables[i].Address, + sizeof (ACPI_TABLE_HEADER)); + if (!Header) + { + return (AE_NO_MEMORY); + } + + memcpy (OutTableHeader, Header, sizeof (ACPI_TABLE_HEADER)); + AcpiOsUnmapMemory (Header, sizeof (ACPI_TABLE_HEADER)); + } + else + { + return (AE_NOT_FOUND); + } + } + else + { + memcpy (OutTableHeader, + AcpiGbl_RootTableList.Tables[i].Pointer, + sizeof (ACPI_TABLE_HEADER)); + } + + return (AE_OK); + } + + return (AE_NOT_FOUND); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTableHeader) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetTable + * + * PARAMETERS: Signature - ACPI signature of needed table + * Instance - Which instance (for SSDTs) + * OutTable - Where the pointer to the table is returned + * + * RETURN: Status and pointer to the requested table + * + * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the + * RSDT/XSDT. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTable ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **OutTable) +{ + UINT32 i; + UINT32 j; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!Signature || !OutTable) + { + return (AE_BAD_PARAMETER); + } + + /* Walk the root table list */ + + for (i = 0, j = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++) + { + if (!ACPI_COMPARE_NAME ( + &(AcpiGbl_RootTableList.Tables[i].Signature), Signature)) + { + continue; + } + + if (++j < Instance) + { + continue; + } + + Status = AcpiTbValidateTable (&AcpiGbl_RootTableList.Tables[i]); + if (ACPI_SUCCESS (Status)) + { + *OutTable = AcpiGbl_RootTableList.Tables[i].Pointer; + } + + return (Status); + } + + return (AE_NOT_FOUND); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTable) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetTableByIndex + * + * PARAMETERS: TableIndex - Table index + * Table - Where the pointer to the table is returned + * + * RETURN: Status and pointer to the requested table + * + * DESCRIPTION: Obtain a table by an index into the global table list. Used + * internally also. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTableByIndex ( + UINT32 TableIndex, + ACPI_TABLE_HEADER **Table) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiGetTableByIndex); + + + /* Parameter validation */ + + if (!Table) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + + /* Validate index */ + + if (TableIndex >= AcpiGbl_RootTableList.CurrentTableCount) + { + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!AcpiGbl_RootTableList.Tables[TableIndex].Pointer) + { + /* Table is not mapped, map it */ + + Status = AcpiTbValidateTable ( + &AcpiGbl_RootTableList.Tables[TableIndex]); + if (ACPI_FAILURE (Status)) + { + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (Status); + } + } + + *Table = AcpiGbl_RootTableList.Tables[TableIndex].Pointer; + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTableByIndex) + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallTableHandler + * + * PARAMETERS: Handler - Table event handler + * Context - Value passed to the handler on each event + * + * RETURN: Status + * + * DESCRIPTION: Install a global table event handler. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallTableHandler ( + ACPI_TABLE_HANDLER Handler, + void *Context) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInstallTableHandler); + + + if (!Handler) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Don't allow more than one handler */ + + if (AcpiGbl_TableHandler) + { + Status = AE_ALREADY_EXISTS; + goto Cleanup; + } + + /* Install the handler */ + + AcpiGbl_TableHandler = Handler; + AcpiGbl_TableHandlerContext = Context; + +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallTableHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiRemoveTableHandler + * + * PARAMETERS: Handler - Table event handler that was installed + * previously. + * + * RETURN: Status + * + * DESCRIPTION: Remove a table event handler + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRemoveTableHandler ( + ACPI_TABLE_HANDLER Handler) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiRemoveTableHandler); + + + Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Make sure that the installed handler is the same */ + + if (!Handler || + Handler != AcpiGbl_TableHandler) + { + Status = AE_BAD_PARAMETER; + goto Cleanup; + } + + /* Remove the handler */ + + AcpiGbl_TableHandler = NULL; + +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveTableHandler) diff --git a/third_party/lib/acpica/source/components/tables/tbxfload.c b/third_party/lib/acpica/source/components/tables/tbxfload.c new file mode 100644 index 000000000..3583e819e --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbxfload.c @@ -0,0 +1,502 @@ +/****************************************************************************** + * + * Module Name: tbxfload - Table load/unload external interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbxfload") + + +/******************************************************************************* + * + * FUNCTION: AcpiLoadTables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT + * + ******************************************************************************/ + +ACPI_STATUS +AcpiLoadTables ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiLoadTables); + + + /* Load the namespace from the tables */ + + Status = AcpiTbLoadNamespace (); + + /* Don't let single failures abort the load */ + + if (Status == AE_CTRL_TERMINATE) + { + Status = AE_OK; + } + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While loading namespace from ACPI tables")); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiLoadTables) + + +/******************************************************************************* + * + * FUNCTION: AcpiTbLoadNamespace + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in + * the RSDT/XSDT. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbLoadNamespace ( + void) +{ + ACPI_STATUS Status; + UINT32 i; + ACPI_TABLE_HEADER *NewDsdt; + ACPI_TABLE_DESC *Table; + UINT32 TablesLoaded = 0; + UINT32 TablesFailed = 0; + + + ACPI_FUNCTION_TRACE (TbLoadNamespace); + + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + + /* + * Load the namespace. The DSDT is required, but any SSDT and + * PSDT tables are optional. Verify the DSDT. + */ + Table = &AcpiGbl_RootTableList.Tables[AcpiGbl_DsdtIndex]; + + if (!AcpiGbl_RootTableList.CurrentTableCount || + !ACPI_COMPARE_NAME (Table->Signature.Ascii, ACPI_SIG_DSDT) || + ACPI_FAILURE (AcpiTbValidateTable (Table))) + { + Status = AE_NO_ACPI_TABLES; + goto UnlockAndExit; + } + + /* + * Save the DSDT pointer for simple access. This is the mapped memory + * address. We must take care here because the address of the .Tables + * array can change dynamically as tables are loaded at run-time. Note: + * .Pointer field is not validated until after call to AcpiTbValidateTable. + */ + AcpiGbl_DSDT = Table->Pointer; + + /* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ + if (AcpiGbl_CopyDsdtLocally) + { + NewDsdt = AcpiTbCopyDsdt (AcpiGbl_DsdtIndex); + if (NewDsdt) + { + AcpiGbl_DSDT = NewDsdt; + } + } + + /* + * Save the original DSDT header for detection of table corruption + * and/or replacement of the DSDT from outside the OS. + */ + memcpy (&AcpiGbl_OriginalDsdtHeader, AcpiGbl_DSDT, + sizeof (ACPI_TABLE_HEADER)); + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + + /* Load and parse tables */ + + Status = AcpiNsLoadTable (AcpiGbl_DsdtIndex, AcpiGbl_RootNode); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "[DSDT] table load failed")); + TablesFailed++; + } + else + { + TablesLoaded++; + } + + /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i) + { + Table = &AcpiGbl_RootTableList.Tables[i]; + + if (!AcpiGbl_RootTableList.Tables[i].Address || + (!ACPI_COMPARE_NAME (Table->Signature.Ascii, ACPI_SIG_SSDT) && + !ACPI_COMPARE_NAME (Table->Signature.Ascii, ACPI_SIG_PSDT) && + !ACPI_COMPARE_NAME (Table->Signature.Ascii, ACPI_SIG_OSDT)) || + ACPI_FAILURE (AcpiTbValidateTable (Table))) + { + continue; + } + + /* Ignore errors while loading tables, get as many as possible */ + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + Status = AcpiNsLoadTable (i, AcpiGbl_RootNode); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "(%4.4s:%8.8s) while loading table", + Table->Signature.Ascii, Table->Pointer->OemTableId)); + + TablesFailed++; + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Table [%4.4s:%8.8s] (id FF) - Table namespace load failed\n\n", + Table->Signature.Ascii, Table->Pointer->OemTableId)); + } + else + { + TablesLoaded++; + } + + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + } + + if (!TablesFailed) + { + ACPI_INFO ((AE_INFO, + "%u ACPI AML tables successfully acquired and loaded\n", + TablesLoaded)); + } + else + { + ACPI_ERROR ((AE_INFO, + "%u table load failures, %u successful", + TablesFailed, TablesLoaded)); + + /* Indicate at least one failure */ + + Status = AE_CTRL_TERMINATE; + } + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiInstallTable + * + * PARAMETERS: Address - Address of the ACPI table to be installed. + * Physical - Whether the address is a physical table + * address or not + * + * RETURN: Status + * + * DESCRIPTION: Dynamically install an ACPI table. + * Note: This function should only be invoked after + * AcpiInitializeTables() and before AcpiLoadTables(). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallTable ( + ACPI_PHYSICAL_ADDRESS Address, + BOOLEAN Physical) +{ + ACPI_STATUS Status; + UINT8 Flags; + UINT32 TableIndex; + + + ACPI_FUNCTION_TRACE (AcpiInstallTable); + + + if (Physical) + { + Flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; + } + else + { + Flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; + } + + Status = AcpiTbInstallStandardTable (Address, Flags, + FALSE, FALSE, &TableIndex); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiInstallTable) + + +/******************************************************************************* + * + * FUNCTION: AcpiLoadTable + * + * PARAMETERS: Table - Pointer to a buffer containing the ACPI + * table to be loaded. + * + * RETURN: Status + * + * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must + * be a valid ACPI table with a valid ACPI table header. + * Note1: Mainly intended to support hotplug addition of SSDTs. + * Note2: Does not copy the incoming table. User is responsible + * to ensure that the table is not deleted or unmapped. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiLoadTable ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + UINT32 TableIndex; + + + ACPI_FUNCTION_TRACE (AcpiLoadTable); + + + /* Parameter validation */ + + if (!Table) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Must acquire the interpreter lock during this operation */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Install the table and load it into the namespace */ + + ACPI_INFO ((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); + (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES); + + Status = AcpiTbInstallStandardTable (ACPI_PTR_TO_PHYSADDR (Table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, TRUE, FALSE, + &TableIndex); + + (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* + * Note: Now table is "INSTALLED", it must be validated before + * using. + */ + Status = AcpiTbValidateTable ( + &AcpiGbl_RootTableList.Tables[TableIndex]); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + Status = AcpiNsLoadTable (TableIndex, AcpiGbl_RootNode); + + /* Invoke table handler if present */ + + if (AcpiGbl_TableHandler) + { + (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table, + AcpiGbl_TableHandlerContext); + } + +UnlockAndExit: + (void) AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiLoadTable) + + +/******************************************************************************* + * + * FUNCTION: AcpiUnloadParentTable + * + * PARAMETERS: Object - Handle to any namespace object owned by + * the table to be unloaded + * + * RETURN: Status + * + * DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads + * the table and deletes all namespace objects associated with + * that table. Unloading of the DSDT is not allowed. + * Note: Mainly intended to support hotplug removal of SSDTs. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUnloadParentTable ( + ACPI_HANDLE Object) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Object); + ACPI_STATUS Status = AE_NOT_EXIST; + ACPI_OWNER_ID OwnerId; + UINT32 i; + + + ACPI_FUNCTION_TRACE (AcpiUnloadParentTable); + + + /* Parameter validation */ + + if (!Object) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * The node OwnerId is currently the same as the parent table ID. + * However, this could change in the future. + */ + OwnerId = Node->OwnerId; + if (!OwnerId) + { + /* OwnerId==0 means DSDT is the owner. DSDT cannot be unloaded */ + + return_ACPI_STATUS (AE_TYPE); + } + + /* Must acquire the interpreter lock during this operation */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Find the table in the global table list */ + + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++) + { + if (OwnerId != AcpiGbl_RootTableList.Tables[i].OwnerId) + { + continue; + } + + /* + * Allow unload of SSDT and OEMx tables only. Do not allow unload + * of the DSDT. No other types of tables should get here, since + * only these types can contain AML and thus are the only types + * that can create namespace objects. + */ + if (ACPI_COMPARE_NAME ( + AcpiGbl_RootTableList.Tables[i].Signature.Ascii, + ACPI_SIG_DSDT)) + { + Status = AE_TYPE; + break; + } + + /* Ensure the table is actually loaded */ + + if (!AcpiTbIsTableLoaded (i)) + { + Status = AE_NOT_EXIST; + break; + } + + /* Invoke table handler if present */ + + if (AcpiGbl_TableHandler) + { + (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, + AcpiGbl_RootTableList.Tables[i].Pointer, + AcpiGbl_TableHandlerContext); + } + + /* + * Delete all namespace objects owned by this table. Note that + * these objects can appear anywhere in the namespace by virtue + * of the AML "Scope" operator. Thus, we need to track ownership + * by an ID, not simply a position within the hierarchy. + */ + Status = AcpiTbDeleteNamespaceByOwner (i); + if (ACPI_FAILURE (Status)) + { + break; + } + + Status = AcpiTbReleaseOwnerId (i); + AcpiTbSetTableLoadedFlag (i, FALSE); + break; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiUnloadParentTable) diff --git a/third_party/lib/acpica/source/components/tables/tbxfroot.c b/third_party/lib/acpica/source/components/tables/tbxfroot.c new file mode 100644 index 000000000..aaa24c470 --- /dev/null +++ b/third_party/lib/acpica/source/components/tables/tbxfroot.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Module Name: tbxfroot - Find the root ACPI table (RSDT) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + + +#define _COMPONENT ACPI_TABLES + ACPI_MODULE_NAME ("tbxfroot") + + +/******************************************************************************* + * + * FUNCTION: AcpiTbGetRsdpLength + * + * PARAMETERS: Rsdp - Pointer to RSDP + * + * RETURN: Table length + * + * DESCRIPTION: Get the length of the RSDP + * + ******************************************************************************/ + +UINT32 +AcpiTbGetRsdpLength ( + ACPI_TABLE_RSDP *Rsdp) +{ + + if (!ACPI_VALIDATE_RSDP_SIG (Rsdp->Signature)) + { + /* BAD Signature */ + + return (0); + } + + /* "Length" field is available if table version >= 2 */ + + if (Rsdp->Revision >= 2) + { + return (Rsdp->Length); + } + else + { + return (ACPI_RSDP_CHECKSUM_LENGTH); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbValidateRsdp + * + * PARAMETERS: Rsdp - Pointer to unvalidated RSDP + * + * RETURN: Status + * + * DESCRIPTION: Validate the RSDP (ptr) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTbValidateRsdp ( + ACPI_TABLE_RSDP *Rsdp) +{ + + /* + * The signature and checksum must both be correct + * + * Note: Sometimes there exists more than one RSDP in memory; the valid + * RSDP has a valid checksum, all others have an invalid checksum. + */ + if (!ACPI_VALIDATE_RSDP_SIG (Rsdp->Signature)) + { + /* Nope, BAD Signature */ + + return (AE_BAD_SIGNATURE); + } + + /* Check the standard checksum */ + + if (AcpiTbChecksum ((UINT8 *) Rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) + { + return (AE_BAD_CHECKSUM); + } + + /* Check extended checksum if table version >= 2 */ + + if ((Rsdp->Revision >= 2) && + (AcpiTbChecksum ((UINT8 *) Rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) + { + return (AE_BAD_CHECKSUM); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiFindRootPointer + * + * PARAMETERS: TableAddress - Where the table pointer is returned + * + * RETURN: Status, RSDP physical address + * + * DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE1: The RSDP must be either in the first 1K of the Extended + * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) + * Only a 32-bit physical address is necessary. + * + * NOTE2: This function is always available, regardless of the + * initialization state of the rest of ACPI. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiFindRootPointer ( + ACPI_PHYSICAL_ADDRESS *TableAddress) +{ + UINT8 *TablePtr; + UINT8 *MemRover; + UINT32 PhysicalAddress; + + + ACPI_FUNCTION_TRACE (AcpiFindRootPointer); + + + /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ + + TablePtr = AcpiOsMapMemory ( + (ACPI_PHYSICAL_ADDRESS) ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH); + if (!TablePtr) + { + ACPI_ERROR ((AE_INFO, + "Could not map memory at 0x%8.8X for length %u", + ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); + + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ACPI_MOVE_16_TO_32 (&PhysicalAddress, TablePtr); + + /* Convert segment part to physical address */ + + PhysicalAddress <<= 4; + AcpiOsUnmapMemory (TablePtr, ACPI_EBDA_PTR_LENGTH); + + /* EBDA present? */ + + if (PhysicalAddress > 0x400) + { + /* + * 1b) Search EBDA paragraphs (EBDA is required to be a + * minimum of 1K length) + */ + TablePtr = AcpiOsMapMemory ( + (ACPI_PHYSICAL_ADDRESS) PhysicalAddress, + ACPI_EBDA_WINDOW_SIZE); + if (!TablePtr) + { + ACPI_ERROR ((AE_INFO, + "Could not map memory at 0x%8.8X for length %u", + PhysicalAddress, ACPI_EBDA_WINDOW_SIZE)); + + return_ACPI_STATUS (AE_NO_MEMORY); + } + + MemRover = AcpiTbScanMemoryForRsdp ( + TablePtr, ACPI_EBDA_WINDOW_SIZE); + AcpiOsUnmapMemory (TablePtr, ACPI_EBDA_WINDOW_SIZE); + + if (MemRover) + { + /* Return the physical address */ + + PhysicalAddress += + (UINT32) ACPI_PTR_DIFF (MemRover, TablePtr); + + *TableAddress = (ACPI_PHYSICAL_ADDRESS) PhysicalAddress; + return_ACPI_STATUS (AE_OK); + } + } + + /* + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh + */ + TablePtr = AcpiOsMapMemory ( + (ACPI_PHYSICAL_ADDRESS) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE); + + if (!TablePtr) + { + ACPI_ERROR ((AE_INFO, + "Could not map memory at 0x%8.8X for length %u", + ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); + + return_ACPI_STATUS (AE_NO_MEMORY); + } + + MemRover = AcpiTbScanMemoryForRsdp ( + TablePtr, ACPI_HI_RSDP_WINDOW_SIZE); + AcpiOsUnmapMemory (TablePtr, ACPI_HI_RSDP_WINDOW_SIZE); + + if (MemRover) + { + /* Return the physical address */ + + PhysicalAddress = (UINT32) + (ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (MemRover, TablePtr)); + + *TableAddress = (ACPI_PHYSICAL_ADDRESS) PhysicalAddress; + return_ACPI_STATUS (AE_OK); + } + + /* A valid RSDP was not found */ + + ACPI_BIOS_ERROR ((AE_INFO, "A valid RSDP was not found")); + return_ACPI_STATUS (AE_NOT_FOUND); +} + +ACPI_EXPORT_SYMBOL (AcpiFindRootPointer) + + +/******************************************************************************* + * + * FUNCTION: AcpiTbScanMemoryForRsdp + * + * PARAMETERS: StartAddress - Starting pointer for search + * Length - Maximum length to search + * + * RETURN: Pointer to the RSDP if found, otherwise NULL. + * + * DESCRIPTION: Search a block of memory for the RSDP signature + * + ******************************************************************************/ + +UINT8 * +AcpiTbScanMemoryForRsdp ( + UINT8 *StartAddress, + UINT32 Length) +{ + ACPI_STATUS Status; + UINT8 *MemRover; + UINT8 *EndAddress; + + + ACPI_FUNCTION_TRACE (TbScanMemoryForRsdp); + + + EndAddress = StartAddress + Length; + + /* Search from given start address for the requested length */ + + for (MemRover = StartAddress; MemRover < EndAddress; + MemRover += ACPI_RSDP_SCAN_STEP) + { + /* The RSDP signature and checksum must both be correct */ + + Status = AcpiTbValidateRsdp ( + ACPI_CAST_PTR (ACPI_TABLE_RSDP, MemRover)); + if (ACPI_SUCCESS (Status)) + { + /* Sig and checksum valid, we have found a real RSDP */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "RSDP located at physical address %p\n", MemRover)); + return_PTR (MemRover); + } + + /* No sig match or bad checksum, keep searching */ + } + + /* Searched entire block, no RSDP was found */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Searched entire block from %p, valid RSDP was not found\n", + StartAddress)); + return_PTR (NULL); +} diff --git a/third_party/lib/acpica/source/components/utilities/utaddress.c b/third_party/lib/acpica/source/components/utilities/utaddress.c new file mode 100644 index 000000000..4b36391e2 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utaddress.c @@ -0,0 +1,324 @@ +/****************************************************************************** + * + * Module Name: utaddress - OpRegion address range check + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utaddress") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAddAddressRange + * + * PARAMETERS: SpaceId - Address space ID + * Address - OpRegion start address + * Length - OpRegion length + * RegionNode - OpRegion namespace node + * + * RETURN: Status + * + * DESCRIPTION: Add the Operation Region address range to the global list. + * The only supported Space IDs are Memory and I/O. Called when + * the OpRegion address/length operands are fully evaluated. + * + * MUTEX: Locks the namespace + * + * NOTE: Because this interface is only called when an OpRegion argument + * list is evaluated, there cannot be any duplicate RegionNodes. + * Duplicate Address/Length values are allowed, however, so that multiple + * address conflicts can be detected. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtAddAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 Length, + ACPI_NAMESPACE_NODE *RegionNode) +{ + ACPI_ADDRESS_RANGE *RangeInfo; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtAddAddressRange); + + + if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) + { + return_ACPI_STATUS (AE_OK); + } + + /* Allocate/init a new info block, add it to the appropriate list */ + + RangeInfo = ACPI_ALLOCATE (sizeof (ACPI_ADDRESS_RANGE)); + if (!RangeInfo) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + RangeInfo->StartAddress = Address; + RangeInfo->EndAddress = (Address + Length - 1); + RangeInfo->RegionNode = RegionNode; + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (RangeInfo); + return_ACPI_STATUS (Status); + } + + RangeInfo->Next = AcpiGbl_AddressRangeList[SpaceId]; + AcpiGbl_AddressRangeList[SpaceId] = RangeInfo; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", + AcpiUtGetNodeName (RangeInfo->RegionNode), + ACPI_FORMAT_UINT64 (Address), + ACPI_FORMAT_UINT64 (RangeInfo->EndAddress))); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtRemoveAddressRange + * + * PARAMETERS: SpaceId - Address space ID + * RegionNode - OpRegion namespace node + * + * RETURN: None + * + * DESCRIPTION: Remove the Operation Region from the global list. The only + * supported Space IDs are Memory and I/O. Called when an + * OpRegion is deleted. + * + * MUTEX: Assumes the namespace is locked + * + ******************************************************************************/ + +void +AcpiUtRemoveAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_NAMESPACE_NODE *RegionNode) +{ + ACPI_ADDRESS_RANGE *RangeInfo; + ACPI_ADDRESS_RANGE *Prev; + + + ACPI_FUNCTION_TRACE (UtRemoveAddressRange); + + + if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) + { + return_VOID; + } + + /* Get the appropriate list head and check the list */ + + RangeInfo = Prev = AcpiGbl_AddressRangeList[SpaceId]; + while (RangeInfo) + { + if (RangeInfo->RegionNode == RegionNode) + { + if (RangeInfo == Prev) /* Found at list head */ + { + AcpiGbl_AddressRangeList[SpaceId] = RangeInfo->Next; + } + else + { + Prev->Next = RangeInfo->Next; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", + AcpiUtGetNodeName (RangeInfo->RegionNode), + ACPI_FORMAT_UINT64 (RangeInfo->StartAddress), + ACPI_FORMAT_UINT64 (RangeInfo->EndAddress))); + + ACPI_FREE (RangeInfo); + return_VOID; + } + + Prev = RangeInfo; + RangeInfo = RangeInfo->Next; + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCheckAddressRange + * + * PARAMETERS: SpaceId - Address space ID + * Address - Start address + * Length - Length of address range + * Warn - TRUE if warning on overlap desired + * + * RETURN: Count of the number of conflicts detected. Zero is always + * returned for Space IDs other than Memory or I/O. + * + * DESCRIPTION: Check if the input address range overlaps any of the + * ASL operation region address ranges. The only supported + * Space IDs are Memory and I/O. + * + * MUTEX: Assumes the namespace is locked. + * + ******************************************************************************/ + +UINT32 +AcpiUtCheckAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 Length, + BOOLEAN Warn) +{ + ACPI_ADDRESS_RANGE *RangeInfo; + ACPI_PHYSICAL_ADDRESS EndAddress; + char *Pathname; + UINT32 OverlapCount = 0; + + + ACPI_FUNCTION_TRACE (UtCheckAddressRange); + + + if ((SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) + { + return_UINT32 (0); + } + + RangeInfo = AcpiGbl_AddressRangeList[SpaceId]; + EndAddress = Address + Length - 1; + + /* Check entire list for all possible conflicts */ + + while (RangeInfo) + { + /* + * Check if the requested address/length overlaps this + * address range. There are four cases to consider: + * + * 1) Input address/length is contained completely in the + * address range + * 2) Input address/length overlaps range at the range start + * 3) Input address/length overlaps range at the range end + * 4) Input address/length completely encompasses the range + */ + if ((Address <= RangeInfo->EndAddress) && + (EndAddress >= RangeInfo->StartAddress)) + { + /* Found an address range overlap */ + + OverlapCount++; + if (Warn) /* Optional warning message */ + { + Pathname = AcpiNsGetNormalizedPathname (RangeInfo->RegionNode, TRUE); + + ACPI_WARNING ((AE_INFO, + "%s range 0x%8.8X%8.8X-0x%8.8X%8.8X conflicts with OpRegion 0x%8.8X%8.8X-0x%8.8X%8.8X (%s)", + AcpiUtGetRegionName (SpaceId), + ACPI_FORMAT_UINT64 (Address), + ACPI_FORMAT_UINT64 (EndAddress), + ACPI_FORMAT_UINT64 (RangeInfo->StartAddress), + ACPI_FORMAT_UINT64 (RangeInfo->EndAddress), + Pathname)); + ACPI_FREE (Pathname); + } + } + + RangeInfo = RangeInfo->Next; + } + + return_UINT32 (OverlapCount); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteAddressLists + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all global address range lists (called during + * subsystem shutdown). + * + ******************************************************************************/ + +void +AcpiUtDeleteAddressLists ( + void) +{ + ACPI_ADDRESS_RANGE *Next; + ACPI_ADDRESS_RANGE *RangeInfo; + int i; + + + /* Delete all elements in all address range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) + { + Next = AcpiGbl_AddressRangeList[i]; + + while (Next) + { + RangeInfo = Next; + Next = RangeInfo->Next; + ACPI_FREE (RangeInfo); + } + + AcpiGbl_AddressRangeList[i] = NULL; + } +} diff --git a/third_party/lib/acpica/source/components/utilities/utalloc.c b/third_party/lib/acpica/source/components/utilities/utalloc.c new file mode 100644 index 000000000..bb29586e8 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utalloc.c @@ -0,0 +1,365 @@ +/****************************************************************************** + * + * Module Name: utalloc - local memory allocation routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utalloc") + + +#if !defined (USE_NATIVE_ALLOCATE_ZEROED) +/******************************************************************************* + * + * FUNCTION: AcpiOsAllocateZeroed + * + * PARAMETERS: Size - Size of the allocation + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. Allocate and zero memory. + * This is the default implementation. Can be overridden via the + * USE_NATIVE_ALLOCATE_ZEROED flag. + * + ******************************************************************************/ + +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE Size) +{ + void *Allocation; + + + ACPI_FUNCTION_ENTRY (); + + + Allocation = AcpiOsAllocate (Size); + if (Allocation) + { + /* Clear the memory block */ + + memset (Allocation, 0, Size); + } + + return (Allocation); +} + +#endif /* !USE_NATIVE_ALLOCATE_ZEROED */ + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateCaches + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create all local caches + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCreateCaches ( + void) +{ + ACPI_STATUS Status; + + + /* Object Caches, for frequently used objects */ + + Status = AcpiOsCreateCache ("Acpi-Namespace", sizeof (ACPI_NAMESPACE_NODE), + ACPI_MAX_NAMESPACE_CACHE_DEPTH, &AcpiGbl_NamespaceCache); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiOsCreateCache ("Acpi-State", sizeof (ACPI_GENERIC_STATE), + ACPI_MAX_STATE_CACHE_DEPTH, &AcpiGbl_StateCache); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiOsCreateCache ("Acpi-Parse", sizeof (ACPI_PARSE_OBJ_COMMON), + ACPI_MAX_PARSE_CACHE_DEPTH, &AcpiGbl_PsNodeCache); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiOsCreateCache ("Acpi-ParseExt", sizeof (ACPI_PARSE_OBJ_NAMED), + ACPI_MAX_EXTPARSE_CACHE_DEPTH, &AcpiGbl_PsNodeExtCache); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiOsCreateCache ("Acpi-Operand", sizeof (ACPI_OPERAND_OBJECT), + ACPI_MAX_OBJECT_CACHE_DEPTH, &AcpiGbl_OperandCache); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Memory allocation lists */ + + Status = AcpiUtCreateList ("Acpi-Global", 0, + &AcpiGbl_GlobalList); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtCreateList ("Acpi-Namespace", sizeof (ACPI_NAMESPACE_NODE), + &AcpiGbl_NsNodeList); + if (ACPI_FAILURE (Status)) + { + return (Status); + } +#endif + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteCaches + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Purge and delete all local caches + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtDeleteCaches ( + void) +{ +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + char Buffer[7]; + + + if (AcpiGbl_DisplayFinalMemStats) + { + strcpy (Buffer, "MEMORY"); + (void) AcpiDbDisplayStatistics (Buffer); + } +#endif + + (void) AcpiOsDeleteCache (AcpiGbl_NamespaceCache); + AcpiGbl_NamespaceCache = NULL; + + (void) AcpiOsDeleteCache (AcpiGbl_StateCache); + AcpiGbl_StateCache = NULL; + + (void) AcpiOsDeleteCache (AcpiGbl_OperandCache); + AcpiGbl_OperandCache = NULL; + + (void) AcpiOsDeleteCache (AcpiGbl_PsNodeCache); + AcpiGbl_PsNodeCache = NULL; + + (void) AcpiOsDeleteCache (AcpiGbl_PsNodeExtCache); + AcpiGbl_PsNodeExtCache = NULL; + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Debug only - display leftover memory allocation, if any */ + + AcpiUtDumpAllocations (ACPI_UINT32_MAX, NULL); + + /* Free memory lists */ + + AcpiOsFree (AcpiGbl_GlobalList); + AcpiGbl_GlobalList = NULL; + + AcpiOsFree (AcpiGbl_NsNodeList); + AcpiGbl_NsNodeList = NULL; +#endif + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidateBuffer + * + * PARAMETERS: Buffer - Buffer descriptor to be validated + * + * RETURN: Status + * + * DESCRIPTION: Perform parameter validation checks on an ACPI_BUFFER + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtValidateBuffer ( + ACPI_BUFFER *Buffer) +{ + + /* Obviously, the structure pointer must be valid */ + + if (!Buffer) + { + return (AE_BAD_PARAMETER); + } + + /* Special semantics for the length */ + + if ((Buffer->Length == ACPI_NO_BUFFER) || + (Buffer->Length == ACPI_ALLOCATE_BUFFER) || + (Buffer->Length == ACPI_ALLOCATE_LOCAL_BUFFER)) + { + return (AE_OK); + } + + /* Length is valid, the buffer pointer must be also */ + + if (!Buffer->Pointer) + { + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtInitializeBuffer + * + * PARAMETERS: Buffer - Buffer to be validated + * RequiredLength - Length needed + * + * RETURN: Status + * + * DESCRIPTION: Validate that the buffer is of the required length or + * allocate a new buffer. Returned buffer is always zeroed. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtInitializeBuffer ( + ACPI_BUFFER *Buffer, + ACPI_SIZE RequiredLength) +{ + ACPI_SIZE InputBufferLength; + + + /* Parameter validation */ + + if (!Buffer || !RequiredLength) + { + return (AE_BAD_PARAMETER); + } + + /* + * Buffer->Length is used as both an input and output parameter. Get the + * input actual length and set the output required buffer length. + */ + InputBufferLength = Buffer->Length; + Buffer->Length = RequiredLength; + + /* + * The input buffer length contains the actual buffer length, or the type + * of buffer to be allocated by this routine. + */ + switch (InputBufferLength) + { + case ACPI_NO_BUFFER: + + /* Return the exception (and the required buffer length) */ + + return (AE_BUFFER_OVERFLOW); + + case ACPI_ALLOCATE_BUFFER: + /* + * Allocate a new buffer. We directectly call AcpiOsAllocate here to + * purposefully bypass the (optionally enabled) internal allocation + * tracking mechanism since we only want to track internal + * allocations. Note: The caller should use AcpiOsFree to free this + * buffer created via ACPI_ALLOCATE_BUFFER. + */ + Buffer->Pointer = AcpiOsAllocate (RequiredLength); + break; + + case ACPI_ALLOCATE_LOCAL_BUFFER: + + /* Allocate a new buffer with local interface to allow tracking */ + + Buffer->Pointer = ACPI_ALLOCATE (RequiredLength); + break; + + default: + + /* Existing buffer: Validate the size of the buffer */ + + if (InputBufferLength < RequiredLength) + { + return (AE_BUFFER_OVERFLOW); + } + break; + } + + /* Validate allocation from above or input buffer pointer */ + + if (!Buffer->Pointer) + { + return (AE_NO_MEMORY); + } + + /* Have a valid buffer, clear it */ + + memset (Buffer->Pointer, 0, RequiredLength); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/utilities/utbuffer.c b/third_party/lib/acpica/source/components/utilities/utbuffer.c new file mode 100644 index 000000000..863055f73 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utbuffer.c @@ -0,0 +1,362 @@ +/****************************************************************************** + * + * Module Name: utbuffer - Buffer dump routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utbuffer") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDumpBuffer + * + * PARAMETERS: Buffer - Buffer to dump + * Count - Amount to dump, in bytes + * Display - BYTE, WORD, DWORD, or QWORD display: + * DB_BYTE_DISPLAY + * DB_WORD_DISPLAY + * DB_DWORD_DISPLAY + * DB_QWORD_DISPLAY + * BaseOffset - Beginning buffer offset (display only) + * + * RETURN: None + * + * DESCRIPTION: Generic dump buffer in both hex and ascii. + * + ******************************************************************************/ + +void +AcpiUtDumpBuffer ( + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 BaseOffset) +{ + UINT32 i = 0; + UINT32 j; + UINT32 Temp32; + UINT8 BufChar; + + + if (!Buffer) + { + AcpiOsPrintf ("Null Buffer Pointer in DumpBuffer!\n"); + return; + } + + if ((Count < 4) || (Count & 0x01)) + { + Display = DB_BYTE_DISPLAY; + } + + /* Nasty little dump buffer routine! */ + + while (i < Count) + { + /* Print current offset */ + + AcpiOsPrintf ("%6.4X: ", (BaseOffset + i)); + + /* Print 16 hex chars */ + + for (j = 0; j < 16;) + { + if (i + j >= Count) + { + /* Dump fill spaces */ + + AcpiOsPrintf ("%*s", ((Display * 2) + 1), " "); + j += Display; + continue; + } + + switch (Display) + { + case DB_BYTE_DISPLAY: + default: /* Default is BYTE display */ + + AcpiOsPrintf ("%02X ", Buffer[(ACPI_SIZE) i + j]); + break; + + case DB_WORD_DISPLAY: + + ACPI_MOVE_16_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j]); + AcpiOsPrintf ("%04X ", Temp32); + break; + + case DB_DWORD_DISPLAY: + + ACPI_MOVE_32_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j]); + AcpiOsPrintf ("%08X ", Temp32); + break; + + case DB_QWORD_DISPLAY: + + ACPI_MOVE_32_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j]); + AcpiOsPrintf ("%08X", Temp32); + + ACPI_MOVE_32_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j + 4]); + AcpiOsPrintf ("%08X ", Temp32); + break; + } + + j += Display; + } + + /* + * Print the ASCII equivalent characters but watch out for the bad + * unprintable ones (printable chars are 0x20 through 0x7E) + */ + AcpiOsPrintf (" "); + for (j = 0; j < 16; j++) + { + if (i + j >= Count) + { + AcpiOsPrintf ("\n"); + return; + } + + /* + * Add comment characters so rest of line is ignored when + * compiled + */ + if (j == 0) + { + AcpiOsPrintf ("// "); + } + + BufChar = Buffer[(ACPI_SIZE) i + j]; + if (isprint (BufChar)) + { + AcpiOsPrintf ("%c", BufChar); + } + else + { + AcpiOsPrintf ("."); + } + } + + /* Done with that line. */ + + AcpiOsPrintf ("\n"); + i += 16; + } + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDebugDumpBuffer + * + * PARAMETERS: Buffer - Buffer to dump + * Count - Amount to dump, in bytes + * Display - BYTE, WORD, DWORD, or QWORD display: + * DB_BYTE_DISPLAY + * DB_WORD_DISPLAY + * DB_DWORD_DISPLAY + * DB_QWORD_DISPLAY + * ComponentID - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Generic dump buffer in both hex and ascii. + * + ******************************************************************************/ + +void +AcpiUtDebugDumpBuffer ( + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 ComponentId) +{ + + /* Only dump the buffer if tracing is enabled */ + + if (!((ACPI_LV_TABLES & AcpiDbgLevel) && + (ComponentId & AcpiDbgLayer))) + { + return; + } + + AcpiUtDumpBuffer (Buffer, Count, Display, 0); +} + + +#ifdef ACPI_APPLICATION +/******************************************************************************* + * + * FUNCTION: AcpiUtDumpBufferToFile + * + * PARAMETERS: File - File descriptor + * Buffer - Buffer to dump + * Count - Amount to dump, in bytes + * Display - BYTE, WORD, DWORD, or QWORD display: + * DB_BYTE_DISPLAY + * DB_WORD_DISPLAY + * DB_DWORD_DISPLAY + * DB_QWORD_DISPLAY + * BaseOffset - Beginning buffer offset (display only) + * + * RETURN: None + * + * DESCRIPTION: Generic dump buffer in both hex and ascii to a file. + * + ******************************************************************************/ + +void +AcpiUtDumpBufferToFile ( + ACPI_FILE File, + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 BaseOffset) +{ + UINT32 i = 0; + UINT32 j; + UINT32 Temp32; + UINT8 BufChar; + + + if (!Buffer) + { + AcpiUtFilePrintf (File, "Null Buffer Pointer in DumpBuffer!\n"); + return; + } + + if ((Count < 4) || (Count & 0x01)) + { + Display = DB_BYTE_DISPLAY; + } + + /* Nasty little dump buffer routine! */ + + while (i < Count) + { + /* Print current offset */ + + AcpiUtFilePrintf (File, "%6.4X: ", (BaseOffset + i)); + + /* Print 16 hex chars */ + + for (j = 0; j < 16;) + { + if (i + j >= Count) + { + /* Dump fill spaces */ + + AcpiUtFilePrintf (File, "%*s", ((Display * 2) + 1), " "); + j += Display; + continue; + } + + switch (Display) + { + case DB_BYTE_DISPLAY: + default: /* Default is BYTE display */ + + AcpiUtFilePrintf (File, "%02X ", Buffer[(ACPI_SIZE) i + j]); + break; + + case DB_WORD_DISPLAY: + + ACPI_MOVE_16_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j]); + AcpiUtFilePrintf (File, "%04X ", Temp32); + break; + + case DB_DWORD_DISPLAY: + + ACPI_MOVE_32_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j]); + AcpiUtFilePrintf (File, "%08X ", Temp32); + break; + + case DB_QWORD_DISPLAY: + + ACPI_MOVE_32_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j]); + AcpiUtFilePrintf (File, "%08X", Temp32); + + ACPI_MOVE_32_TO_32 (&Temp32, &Buffer[(ACPI_SIZE) i + j + 4]); + AcpiUtFilePrintf (File, "%08X ", Temp32); + break; + } + + j += Display; + } + + /* + * Print the ASCII equivalent characters but watch out for the bad + * unprintable ones (printable chars are 0x20 through 0x7E) + */ + AcpiUtFilePrintf (File, " "); + for (j = 0; j < 16; j++) + { + if (i + j >= Count) + { + AcpiUtFilePrintf (File, "\n"); + return; + } + + BufChar = Buffer[(ACPI_SIZE) i + j]; + if (isprint (BufChar)) + { + AcpiUtFilePrintf (File, "%c", BufChar); + } + else + { + AcpiUtFilePrintf (File, "."); + } + } + + /* Done with that line. */ + + AcpiUtFilePrintf (File, "\n"); + i += 16; + } + + return; +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utcache.c b/third_party/lib/acpica/source/components/utilities/utcache.c new file mode 100644 index 000000000..66fa86806 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utcache.c @@ -0,0 +1,353 @@ +/****************************************************************************** + * + * Module Name: utcache - local cache allocation routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utcache") + + +#ifdef ACPI_USE_LOCAL_CACHE +/******************************************************************************* + * + * FUNCTION: AcpiOsCreateCache + * + * PARAMETERS: CacheName - Ascii name for the cache + * ObjectSize - Size of each cached object + * MaxDepth - Maximum depth of the cache (in objects) + * ReturnCache - Where the new cache object is returned + * + * RETURN: Status + * + * DESCRIPTION: Create a cache object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiOsCreateCache ( + char *CacheName, + UINT16 ObjectSize, + UINT16 MaxDepth, + ACPI_MEMORY_LIST **ReturnCache) +{ + ACPI_MEMORY_LIST *Cache; + + + ACPI_FUNCTION_ENTRY (); + + + if (!CacheName || !ReturnCache || (ObjectSize < 16)) + { + return (AE_BAD_PARAMETER); + } + + /* Create the cache object */ + + Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST)); + if (!Cache) + { + return (AE_NO_MEMORY); + } + + /* Populate the cache object and return it */ + + memset (Cache, 0, sizeof (ACPI_MEMORY_LIST)); + Cache->ListName = CacheName; + Cache->ObjectSize = ObjectSize; + Cache->MaxDepth = MaxDepth; + + *ReturnCache = Cache; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsPurgeCache + * + * PARAMETERS: Cache - Handle to cache object + * + * RETURN: Status + * + * DESCRIPTION: Free all objects within the requested cache. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiOsPurgeCache ( + ACPI_MEMORY_LIST *Cache) +{ + void *Next; + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + if (!Cache) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Walk the list of objects in this cache */ + + while (Cache->ListHead) + { + /* Delete and unlink one cached state object */ + + Next = ACPI_GET_DESCRIPTOR_PTR (Cache->ListHead); + ACPI_FREE (Cache->ListHead); + + Cache->ListHead = Next; + Cache->CurrentDepth--; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsDeleteCache + * + * PARAMETERS: Cache - Handle to cache object + * + * RETURN: Status + * + * DESCRIPTION: Free all objects within the requested cache and delete the + * cache object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiOsDeleteCache ( + ACPI_MEMORY_LIST *Cache) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + /* Purge all objects in the cache */ + + Status = AcpiOsPurgeCache (Cache); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Now we can delete the cache object */ + + AcpiOsFree (Cache); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsReleaseObject + * + * PARAMETERS: Cache - Handle to cache object + * Object - The object to be released + * + * RETURN: None + * + * DESCRIPTION: Release an object to the specified cache. If cache is full, + * the object is deleted. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiOsReleaseObject ( + ACPI_MEMORY_LIST *Cache, + void *Object) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + if (!Cache || !Object) + { + return (AE_BAD_PARAMETER); + } + + /* If cache is full, just free this object */ + + if (Cache->CurrentDepth >= Cache->MaxDepth) + { + ACPI_FREE (Object); + ACPI_MEM_TRACKING (Cache->TotalFreed++); + } + + /* Otherwise put this object back into the cache */ + + else + { + Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Mark the object as cached */ + + memset (Object, 0xCA, Cache->ObjectSize); + ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_CACHED); + + /* Put the object at the head of the cache list */ + + ACPI_SET_DESCRIPTOR_PTR (Object, Cache->ListHead); + Cache->ListHead = Object; + Cache->CurrentDepth++; + + (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsAcquireObject + * + * PARAMETERS: Cache - Handle to cache object + * + * RETURN: the acquired object. NULL on error + * + * DESCRIPTION: Get an object from the specified cache. If cache is empty, + * the object is allocated. + * + ******************************************************************************/ + +void * +AcpiOsAcquireObject ( + ACPI_MEMORY_LIST *Cache) +{ + ACPI_STATUS Status; + void *Object; + + + ACPI_FUNCTION_NAME (OsAcquireObject); + + + if (!Cache) + { + return_PTR (NULL); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return_PTR (NULL); + } + + ACPI_MEM_TRACKING (Cache->Requests++); + + /* Check the cache first */ + + if (Cache->ListHead) + { + /* There is an object available, use it */ + + Object = Cache->ListHead; + Cache->ListHead = ACPI_GET_DESCRIPTOR_PTR (Object); + + Cache->CurrentDepth--; + + ACPI_MEM_TRACKING (Cache->Hits++); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Object %p from %s cache\n", Object, Cache->ListName)); + + Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return_PTR (NULL); + } + + /* Clear (zero) the previously used Object */ + + memset (Object, 0, Cache->ObjectSize); + } + else + { + /* The cache is empty, create a new object */ + + ACPI_MEM_TRACKING (Cache->TotalAllocated++); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied) + { + Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed; + } +#endif + + /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ + + Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return_PTR (NULL); + } + + Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize); + if (!Object) + { + return_PTR (NULL); + } + } + + return_PTR (Object); +} +#endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/third_party/lib/acpica/source/components/utilities/utclib.c b/third_party/lib/acpica/source/components/utilities/utclib.c new file mode 100644 index 000000000..8c188d00a --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utclib.c @@ -0,0 +1,918 @@ +/****************************************************************************** + * + * Module Name: utclib - ACPICA implementations of C library functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define ACPI_CLIBRARY +#include "acpi.h" +#include "accommon.h" + +/* + * This module contains implementations of the standard C library functions + * that are required by the ACPICA code at both application level and kernel + * level. + * + * The module is an optional feature that can be used if a local/system + * C library is not available. Some operating system kernels may not have + * an internal C library. + * + * In general, these functions are less efficient than an inline or assembly + * code implementation. + * + * These C functions and the associated prototypes are enabled by default + * unless the ACPI_USE_SYSTEM_CLIBRARY symbol is defined. This is usually + * automatically defined for the ACPICA applications such as iASL and + * AcpiExec, so that these user-level applications use the local C library + * instead of the functions in this module. + */ + +/******************************************************************************* + * + * Functions implemented in this module: + * + * FUNCTION: memcmp + * FUNCTION: memcpy + * FUNCTION: memset + * FUNCTION: strlen + * FUNCTION: strcpy + * FUNCTION: strncpy + * FUNCTION: strcmp + * FUNCTION: strchr + * FUNCTION: strncmp + * FUNCTION: strcat + * FUNCTION: strncat + * FUNCTION: strstr + * FUNCTION: strtoul + * FUNCTION: toupper + * FUNCTION: tolower + * FUNCTION: is* functions + * + ******************************************************************************/ + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utclib") + + +#ifndef ACPI_USE_SYSTEM_CLIBRARY /* Entire module */ + + +/******************************************************************************* + * + * FUNCTION: memcmp + * + * PARAMETERS: Buffer1 - First Buffer + * Buffer2 - Second Buffer + * Count - Maximum # of bytes to compare + * + * RETURN: Index where Buffers mismatched, or 0 if Buffers matched + * + * DESCRIPTION: Compare two Buffers, with a maximum length + * + ******************************************************************************/ + +int +memcmp ( + void *VBuffer1, + void *VBuffer2, + ACPI_SIZE Count) +{ + char *Buffer1 = (char *) VBuffer1; + char *Buffer2 = (char *) VBuffer2; + + + for ( ; Count-- && (*Buffer1 == *Buffer2); Buffer1++, Buffer2++) + { + } + + return ((Count == ACPI_SIZE_MAX) ? 0 : ((unsigned char) *Buffer1 - + (unsigned char) *Buffer2)); +} + + +/******************************************************************************* + * + * FUNCTION: memcpy + * + * PARAMETERS: Dest - Target of the copy + * Src - Source buffer to copy + * Count - Number of bytes to copy + * + * RETURN: Dest + * + * DESCRIPTION: Copy arbitrary bytes of memory + * + ******************************************************************************/ + +void * +memcpy ( + void *Dest, + const void *Src, + ACPI_SIZE Count) +{ + char *New = (char *) Dest; + char *Old = (char *) Src; + + + while (Count) + { + *New = *Old; + New++; + Old++; + Count--; + } + + return (Dest); +} + + +/******************************************************************************* + * + * FUNCTION: memset + * + * PARAMETERS: Dest - Buffer to set + * Value - Value to set each byte of memory + * Count - Number of bytes to set + * + * RETURN: Dest + * + * DESCRIPTION: Initialize a buffer to a known value. + * + ******************************************************************************/ + +void * +memset ( + void *Dest, + int Value, + ACPI_SIZE Count) +{ + char *New = (char *) Dest; + + + while (Count) + { + *New = (char) Value; + New++; + Count--; + } + + return (Dest); +} + + +/******************************************************************************* + * + * FUNCTION: strlen + * + * PARAMETERS: String - Null terminated string + * + * RETURN: Length + * + * DESCRIPTION: Returns the length of the input string + * + ******************************************************************************/ + + +ACPI_SIZE +strlen ( + const char *String) +{ + UINT32 Length = 0; + + + /* Count the string until a null is encountered */ + + while (*String) + { + Length++; + String++; + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: strcpy + * + * PARAMETERS: DstString - Target of the copy + * SrcString - The source string to copy + * + * RETURN: DstString + * + * DESCRIPTION: Copy a null terminated string + * + ******************************************************************************/ + +char * +strcpy ( + char *DstString, + const char *SrcString) +{ + char *String = DstString; + + + /* Move bytes brute force */ + + while (*SrcString) + { + *String = *SrcString; + + String++; + SrcString++; + } + + /* Null terminate */ + + *String = 0; + return (DstString); +} + + +/******************************************************************************* + * + * FUNCTION: strncpy + * + * PARAMETERS: DstString - Target of the copy + * SrcString - The source string to copy + * Count - Maximum # of bytes to copy + * + * RETURN: DstString + * + * DESCRIPTION: Copy a null terminated string, with a maximum length + * + ******************************************************************************/ + +char * +strncpy ( + char *DstString, + const char *SrcString, + ACPI_SIZE Count) +{ + char *String = DstString; + + + /* Copy the string */ + + for (String = DstString; + Count && (Count--, (*String++ = *SrcString++)); ) + {;} + + /* Pad with nulls if necessary */ + + while (Count--) + { + *String = 0; + String++; + } + + /* Return original pointer */ + + return (DstString); +} + + +/******************************************************************************* + * + * FUNCTION: strcmp + * + * PARAMETERS: String1 - First string + * String2 - Second string + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings + * + ******************************************************************************/ + +int +strcmp ( + const char *String1, + const char *String2) +{ + + + for ( ; (*String1 == *String2); String2++) + { + if (!*String1++) + { + return (0); + } + } + + return ((unsigned char) *String1 - (unsigned char) *String2); +} + + +/******************************************************************************* + * + * FUNCTION: strchr + * + * PARAMETERS: String - Search string + * ch - character to search for + * + * RETURN: Ptr to char or NULL if not found + * + * DESCRIPTION: Search a string for a character + * + ******************************************************************************/ + +char * +strchr ( + const char *String, + int ch) +{ + + + for ( ; (*String); String++) + { + if ((*String) == (char) ch) + { + return ((char *) String); + } + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: strncmp + * + * PARAMETERS: String1 - First string + * String2 - Second string + * Count - Maximum # of bytes to compare + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings, with a maximum length + * + ******************************************************************************/ + +int +strncmp ( + const char *String1, + const char *String2, + ACPI_SIZE Count) +{ + + + for ( ; Count-- && (*String1 == *String2); String2++) + { + if (!*String1++) + { + return (0); + } + } + + return ((Count == ACPI_SIZE_MAX) ? 0 : ((unsigned char) *String1 - + (unsigned char) *String2)); +} + + +/******************************************************************************* + * + * FUNCTION: strcat + * + * PARAMETERS: DstString - Target of the copy + * SrcString - The source string to copy + * + * RETURN: DstString + * + * DESCRIPTION: Append a null terminated string to a null terminated string + * + ******************************************************************************/ + +char * +strcat ( + char *DstString, + const char *SrcString) +{ + char *String; + + + /* Find end of the destination string */ + + for (String = DstString; *String++; ) + { ; } + + /* Concatenate the string */ + + for (--String; (*String++ = *SrcString++); ) + { ; } + + return (DstString); +} + + +/******************************************************************************* + * + * FUNCTION: strncat + * + * PARAMETERS: DstString - Target of the copy + * SrcString - The source string to copy + * Count - Maximum # of bytes to copy + * + * RETURN: DstString + * + * DESCRIPTION: Append a null terminated string to a null terminated string, + * with a maximum count. + * + ******************************************************************************/ + +char * +strncat ( + char *DstString, + const char *SrcString, + ACPI_SIZE Count) +{ + char *String; + + + if (Count) + { + /* Find end of the destination string */ + + for (String = DstString; *String++; ) + { ; } + + /* Concatenate the string */ + + for (--String; (*String++ = *SrcString++) && --Count; ) + { ; } + + /* Null terminate if necessary */ + + if (!Count) + { + *String = 0; + } + } + + return (DstString); +} + + +/******************************************************************************* + * + * FUNCTION: strstr + * + * PARAMETERS: String1 - Target string + * String2 - Substring to search for + * + * RETURN: Where substring match starts, Null if no match found + * + * DESCRIPTION: Checks if String2 occurs in String1. This is not really a + * full implementation of strstr, only sufficient for command + * matching + * + ******************************************************************************/ + +char * +strstr ( + char *String1, + char *String2) +{ + UINT32 Length; + + + Length = strlen (String2); + if (!Length) + { + return (String1); + } + + while (strlen (String1) >= Length) + { + if (memcmp (String1, String2, Length) == 0) + { + return (String1); + } + String1++; + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: strtoul + * + * PARAMETERS: String - Null terminated string + * Terminater - Where a pointer to the terminating byte is + * returned + * Base - Radix of the string + * + * RETURN: Converted value + * + * DESCRIPTION: Convert a string into a 32-bit unsigned value. + * Note: use strtoul64 for 64-bit integers. + * + ******************************************************************************/ + +UINT32 +strtoul ( + const char *String, + char **Terminator, + UINT32 Base) +{ + UINT32 converted = 0; + UINT32 index; + UINT32 sign; + const char *StringStart; + UINT32 ReturnValue = 0; + ACPI_STATUS Status = AE_OK; + + + /* + * Save the value of the pointer to the buffer's first + * character, save the current errno value, and then + * skip over any white space in the buffer: + */ + StringStart = String; + while (isspace (*String) || *String == '\t') + { + ++String; + } + + /* + * The buffer may contain an optional plus or minus sign. + * If it does, then skip over it but remember what is was: + */ + if (*String == '-') + { + sign = ACPI_SIGN_NEGATIVE; + ++String; + } + else if (*String == '+') + { + ++String; + sign = ACPI_SIGN_POSITIVE; + } + else + { + sign = ACPI_SIGN_POSITIVE; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is octal, decimal, or hexadecimal: + */ + if (Base == 0) + { + if (*String == '0') + { + if (tolower (*(++String)) == 'x') + { + Base = 16; + ++String; + } + else + { + Base = 8; + } + } + else + { + Base = 10; + } + } + else if (Base < 2 || Base > 36) + { + /* + * The specified Base parameter is not in the domain of + * this function: + */ + goto done; + } + + /* + * For octal and hexadecimal bases, skip over the leading + * 0 or 0x, if they are present. + */ + if (Base == 8 && *String == '0') + { + String++; + } + + if (Base == 16 && + *String == '0' && + tolower (*(++String)) == 'x') + { + String++; + } + + /* + * Main loop: convert the string to an unsigned long: + */ + while (*String) + { + if (isdigit (*String)) + { + index = (UINT32) ((UINT8) *String - '0'); + } + else + { + index = (UINT32) toupper (*String); + if (isupper (index)) + { + index = index - 'A' + 10; + } + else + { + goto done; + } + } + + if (index >= Base) + { + goto done; + } + + /* + * Check to see if value is out of range: + */ + + if (ReturnValue > ((ACPI_UINT32_MAX - (UINT32) index) / + (UINT32) Base)) + { + Status = AE_ERROR; + ReturnValue = 0; /* reset */ + } + else + { + ReturnValue *= Base; + ReturnValue += index; + converted = 1; + } + + ++String; + } + +done: + /* + * If appropriate, update the caller's pointer to the next + * unconverted character in the buffer. + */ + if (Terminator) + { + if (converted == 0 && ReturnValue == 0 && String != NULL) + { + *Terminator = (char *) StringStart; + } + else + { + *Terminator = (char *) String; + } + } + + if (Status == AE_ERROR) + { + ReturnValue = ACPI_UINT32_MAX; + } + + /* + * If a minus sign was present, then "the conversion is negated": + */ + if (sign == ACPI_SIGN_NEGATIVE) + { + ReturnValue = (ACPI_UINT32_MAX - ReturnValue) + 1; + } + + return (ReturnValue); +} + + +/******************************************************************************* + * + * FUNCTION: toupper + * + * PARAMETERS: c - Character to convert + * + * RETURN: Converted character as an int + * + * DESCRIPTION: Convert character to uppercase + * + ******************************************************************************/ + +int +toupper ( + int c) +{ + + return (islower(c) ? ((c)-0x20) : (c)); +} + + +/******************************************************************************* + * + * FUNCTION: tolower + * + * PARAMETERS: c - Character to convert + * + * RETURN: Converted character as an int + * + * DESCRIPTION: Convert character to lowercase + * + ******************************************************************************/ + +int +tolower ( + int c) +{ + + return (isupper(c) ? ((c)+0x20) : (c)); +} + + +/******************************************************************************* + * + * FUNCTION: is* function array + * + * DESCRIPTION: is* functions use the ctype table below + * + ******************************************************************************/ + +const UINT8 AcpiGbl_Ctypes[257] = { + _ACPI_CN, /* 0x00 0 NUL */ + _ACPI_CN, /* 0x01 1 SOH */ + _ACPI_CN, /* 0x02 2 STX */ + _ACPI_CN, /* 0x03 3 ETX */ + _ACPI_CN, /* 0x04 4 EOT */ + _ACPI_CN, /* 0x05 5 ENQ */ + _ACPI_CN, /* 0x06 6 ACK */ + _ACPI_CN, /* 0x07 7 BEL */ + _ACPI_CN, /* 0x08 8 BS */ + _ACPI_CN|_ACPI_SP, /* 0x09 9 TAB */ + _ACPI_CN|_ACPI_SP, /* 0x0A 10 LF */ + _ACPI_CN|_ACPI_SP, /* 0x0B 11 VT */ + _ACPI_CN|_ACPI_SP, /* 0x0C 12 FF */ + _ACPI_CN|_ACPI_SP, /* 0x0D 13 CR */ + _ACPI_CN, /* 0x0E 14 SO */ + _ACPI_CN, /* 0x0F 15 SI */ + _ACPI_CN, /* 0x10 16 DLE */ + _ACPI_CN, /* 0x11 17 DC1 */ + _ACPI_CN, /* 0x12 18 DC2 */ + _ACPI_CN, /* 0x13 19 DC3 */ + _ACPI_CN, /* 0x14 20 DC4 */ + _ACPI_CN, /* 0x15 21 NAK */ + _ACPI_CN, /* 0x16 22 SYN */ + _ACPI_CN, /* 0x17 23 ETB */ + _ACPI_CN, /* 0x18 24 CAN */ + _ACPI_CN, /* 0x19 25 EM */ + _ACPI_CN, /* 0x1A 26 SUB */ + _ACPI_CN, /* 0x1B 27 ESC */ + _ACPI_CN, /* 0x1C 28 FS */ + _ACPI_CN, /* 0x1D 29 GS */ + _ACPI_CN, /* 0x1E 30 RS */ + _ACPI_CN, /* 0x1F 31 US */ + _ACPI_XS|_ACPI_SP, /* 0x20 32 ' ' */ + _ACPI_PU, /* 0x21 33 '!' */ + _ACPI_PU, /* 0x22 34 '"' */ + _ACPI_PU, /* 0x23 35 '#' */ + _ACPI_PU, /* 0x24 36 '$' */ + _ACPI_PU, /* 0x25 37 '%' */ + _ACPI_PU, /* 0x26 38 '&' */ + _ACPI_PU, /* 0x27 39 ''' */ + _ACPI_PU, /* 0x28 40 '(' */ + _ACPI_PU, /* 0x29 41 ')' */ + _ACPI_PU, /* 0x2A 42 '*' */ + _ACPI_PU, /* 0x2B 43 '+' */ + _ACPI_PU, /* 0x2C 44 ',' */ + _ACPI_PU, /* 0x2D 45 '-' */ + _ACPI_PU, /* 0x2E 46 '.' */ + _ACPI_PU, /* 0x2F 47 '/' */ + _ACPI_XD|_ACPI_DI, /* 0x30 48 '0' */ + _ACPI_XD|_ACPI_DI, /* 0x31 49 '1' */ + _ACPI_XD|_ACPI_DI, /* 0x32 50 '2' */ + _ACPI_XD|_ACPI_DI, /* 0x33 51 '3' */ + _ACPI_XD|_ACPI_DI, /* 0x34 52 '4' */ + _ACPI_XD|_ACPI_DI, /* 0x35 53 '5' */ + _ACPI_XD|_ACPI_DI, /* 0x36 54 '6' */ + _ACPI_XD|_ACPI_DI, /* 0x37 55 '7' */ + _ACPI_XD|_ACPI_DI, /* 0x38 56 '8' */ + _ACPI_XD|_ACPI_DI, /* 0x39 57 '9' */ + _ACPI_PU, /* 0x3A 58 ':' */ + _ACPI_PU, /* 0x3B 59 ';' */ + _ACPI_PU, /* 0x3C 60 '<' */ + _ACPI_PU, /* 0x3D 61 '=' */ + _ACPI_PU, /* 0x3E 62 '>' */ + _ACPI_PU, /* 0x3F 63 '?' */ + _ACPI_PU, /* 0x40 64 '@' */ + _ACPI_XD|_ACPI_UP, /* 0x41 65 'A' */ + _ACPI_XD|_ACPI_UP, /* 0x42 66 'B' */ + _ACPI_XD|_ACPI_UP, /* 0x43 67 'C' */ + _ACPI_XD|_ACPI_UP, /* 0x44 68 'D' */ + _ACPI_XD|_ACPI_UP, /* 0x45 69 'E' */ + _ACPI_XD|_ACPI_UP, /* 0x46 70 'F' */ + _ACPI_UP, /* 0x47 71 'G' */ + _ACPI_UP, /* 0x48 72 'H' */ + _ACPI_UP, /* 0x49 73 'I' */ + _ACPI_UP, /* 0x4A 74 'J' */ + _ACPI_UP, /* 0x4B 75 'K' */ + _ACPI_UP, /* 0x4C 76 'L' */ + _ACPI_UP, /* 0x4D 77 'M' */ + _ACPI_UP, /* 0x4E 78 'N' */ + _ACPI_UP, /* 0x4F 79 'O' */ + _ACPI_UP, /* 0x50 80 'P' */ + _ACPI_UP, /* 0x51 81 'Q' */ + _ACPI_UP, /* 0x52 82 'R' */ + _ACPI_UP, /* 0x53 83 'S' */ + _ACPI_UP, /* 0x54 84 'T' */ + _ACPI_UP, /* 0x55 85 'U' */ + _ACPI_UP, /* 0x56 86 'V' */ + _ACPI_UP, /* 0x57 87 'W' */ + _ACPI_UP, /* 0x58 88 'X' */ + _ACPI_UP, /* 0x59 89 'Y' */ + _ACPI_UP, /* 0x5A 90 'Z' */ + _ACPI_PU, /* 0x5B 91 '[' */ + _ACPI_PU, /* 0x5C 92 '\' */ + _ACPI_PU, /* 0x5D 93 ']' */ + _ACPI_PU, /* 0x5E 94 '^' */ + _ACPI_PU, /* 0x5F 95 '_' */ + _ACPI_PU, /* 0x60 96 '`' */ + _ACPI_XD|_ACPI_LO, /* 0x61 97 'a' */ + _ACPI_XD|_ACPI_LO, /* 0x62 98 'b' */ + _ACPI_XD|_ACPI_LO, /* 0x63 99 'c' */ + _ACPI_XD|_ACPI_LO, /* 0x64 100 'd' */ + _ACPI_XD|_ACPI_LO, /* 0x65 101 'e' */ + _ACPI_XD|_ACPI_LO, /* 0x66 102 'f' */ + _ACPI_LO, /* 0x67 103 'g' */ + _ACPI_LO, /* 0x68 104 'h' */ + _ACPI_LO, /* 0x69 105 'i' */ + _ACPI_LO, /* 0x6A 106 'j' */ + _ACPI_LO, /* 0x6B 107 'k' */ + _ACPI_LO, /* 0x6C 108 'l' */ + _ACPI_LO, /* 0x6D 109 'm' */ + _ACPI_LO, /* 0x6E 110 'n' */ + _ACPI_LO, /* 0x6F 111 'o' */ + _ACPI_LO, /* 0x70 112 'p' */ + _ACPI_LO, /* 0x71 113 'q' */ + _ACPI_LO, /* 0x72 114 'r' */ + _ACPI_LO, /* 0x73 115 's' */ + _ACPI_LO, /* 0x74 116 't' */ + _ACPI_LO, /* 0x75 117 'u' */ + _ACPI_LO, /* 0x76 118 'v' */ + _ACPI_LO, /* 0x77 119 'w' */ + _ACPI_LO, /* 0x78 120 'x' */ + _ACPI_LO, /* 0x79 121 'y' */ + _ACPI_LO, /* 0x7A 122 'z' */ + _ACPI_PU, /* 0x7B 123 '{' */ + _ACPI_PU, /* 0x7C 124 '|' */ + _ACPI_PU, /* 0x7D 125 '}' */ + _ACPI_PU, /* 0x7E 126 '~' */ + _ACPI_CN, /* 0x7F 127 DEL */ + + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 to 0x8F */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90 to 0x9F */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xA0 to 0xAF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xB0 to 0xBF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xC0 to 0xCF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xD0 to 0xDF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xE0 to 0xEF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xF0 to 0xFF */ + 0 /* 0x100 */ +}; + + +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ diff --git a/third_party/lib/acpica/source/components/utilities/utcopy.c b/third_party/lib/acpica/source/components/utilities/utcopy.c new file mode 100644 index 000000000..40abdfb76 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utcopy.c @@ -0,0 +1,1076 @@ +/****************************************************************************** + * + * Module Name: utcopy - Internal to external object translation utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utcopy") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiUtCopyIsimpleToEsimple ( + ACPI_OPERAND_OBJECT *InternalObject, + ACPI_OBJECT *ExternalObject, + UINT8 *DataSpace, + ACPI_SIZE *BufferSpaceUsed); + +static ACPI_STATUS +AcpiUtCopyIelementToIelement ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context); + +static ACPI_STATUS +AcpiUtCopyIpackageToEpackage ( + ACPI_OPERAND_OBJECT *InternalObject, + UINT8 *Buffer, + ACPI_SIZE *SpaceUsed); + +static ACPI_STATUS +AcpiUtCopyEsimpleToIsimple( + ACPI_OBJECT *UserObj, + ACPI_OPERAND_OBJECT **ReturnObj); + +static ACPI_STATUS +AcpiUtCopyEpackageToIpackage ( + ACPI_OBJECT *ExternalObject, + ACPI_OPERAND_OBJECT **InternalObject); + +static ACPI_STATUS +AcpiUtCopySimpleObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *DestDesc); + +static ACPI_STATUS +AcpiUtCopyIelementToEelement ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context); + +static ACPI_STATUS +AcpiUtCopyIpackageToIpackage ( + ACPI_OPERAND_OBJECT *SourceObj, + ACPI_OPERAND_OBJECT *DestObj, + ACPI_WALK_STATE *WalkState); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIsimpleToEsimple + * + * PARAMETERS: InternalObject - Source object to be copied + * ExternalObject - Where to return the copied object + * DataSpace - Where object data is returned (such as + * buffer and string data) + * BufferSpaceUsed - Length of DataSpace that was used + * + * RETURN: Status + * + * DESCRIPTION: This function is called to copy a simple internal object to + * an external object. + * + * The DataSpace buffer is assumed to have sufficient space for + * the object. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyIsimpleToEsimple ( + ACPI_OPERAND_OBJECT *InternalObject, + ACPI_OBJECT *ExternalObject, + UINT8 *DataSpace, + ACPI_SIZE *BufferSpaceUsed) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (UtCopyIsimpleToEsimple); + + + *BufferSpaceUsed = 0; + + /* + * Check for NULL object case (could be an uninitialized + * package element) + */ + if (!InternalObject) + { + return_ACPI_STATUS (AE_OK); + } + + /* Always clear the external object */ + + memset (ExternalObject, 0, sizeof (ACPI_OBJECT)); + + /* + * In general, the external object will be the same type as + * the internal object + */ + ExternalObject->Type = InternalObject->Common.Type; + + /* However, only a limited number of external types are supported */ + + switch (InternalObject->Common.Type) + { + case ACPI_TYPE_STRING: + + ExternalObject->String.Pointer = (char *) DataSpace; + ExternalObject->String.Length = InternalObject->String.Length; + *BufferSpaceUsed = ACPI_ROUND_UP_TO_NATIVE_WORD ( + (ACPI_SIZE) InternalObject->String.Length + 1); + + memcpy ((void *) DataSpace, + (void *) InternalObject->String.Pointer, + (ACPI_SIZE) InternalObject->String.Length + 1); + break; + + case ACPI_TYPE_BUFFER: + + ExternalObject->Buffer.Pointer = DataSpace; + ExternalObject->Buffer.Length = InternalObject->Buffer.Length; + *BufferSpaceUsed = ACPI_ROUND_UP_TO_NATIVE_WORD ( + InternalObject->String.Length); + + memcpy ((void *) DataSpace, + (void *) InternalObject->Buffer.Pointer, + InternalObject->Buffer.Length); + break; + + case ACPI_TYPE_INTEGER: + + ExternalObject->Integer.Value = InternalObject->Integer.Value; + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + /* This is an object reference. */ + + switch (InternalObject->Reference.Class) + { + case ACPI_REFCLASS_NAME: + /* + * For namepath, return the object handle ("reference") + * We are referring to the namespace node + */ + ExternalObject->Reference.Handle = + InternalObject->Reference.Node; + ExternalObject->Reference.ActualType = + AcpiNsGetType (InternalObject->Reference.Node); + break; + + default: + + /* All other reference types are unsupported */ + + return_ACPI_STATUS (AE_TYPE); + } + break; + + case ACPI_TYPE_PROCESSOR: + + ExternalObject->Processor.ProcId = + InternalObject->Processor.ProcId; + ExternalObject->Processor.PblkAddress = + InternalObject->Processor.Address; + ExternalObject->Processor.PblkLength = + InternalObject->Processor.Length; + break; + + case ACPI_TYPE_POWER: + + ExternalObject->PowerResource.SystemLevel = + InternalObject->PowerResource.SystemLevel; + + ExternalObject->PowerResource.ResourceOrder = + InternalObject->PowerResource.ResourceOrder; + break; + + default: + /* + * There is no corresponding external object type + */ + ACPI_ERROR ((AE_INFO, + "Unsupported object type, cannot convert to external object: %s", + AcpiUtGetTypeName (InternalObject->Common.Type))); + + return_ACPI_STATUS (AE_SUPPORT); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIelementToEelement + * + * PARAMETERS: ACPI_PKG_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Copy one package element to another package element + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyIelementToEelement ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PKG_INFO *Info = (ACPI_PKG_INFO *) Context; + ACPI_SIZE ObjectSpace; + UINT32 ThisIndex; + ACPI_OBJECT *TargetObject; + + + ACPI_FUNCTION_ENTRY (); + + + ThisIndex = State->Pkg.Index; + TargetObject = (ACPI_OBJECT *) &((ACPI_OBJECT *) + (State->Pkg.DestObject))->Package.Elements[ThisIndex]; + + switch (ObjectType) + { + case ACPI_COPY_TYPE_SIMPLE: + /* + * This is a simple or null object + */ + Status = AcpiUtCopyIsimpleToEsimple (SourceObject, + TargetObject, Info->FreeSpace, &ObjectSpace); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_COPY_TYPE_PACKAGE: + /* + * Build the package object + */ + TargetObject->Type = ACPI_TYPE_PACKAGE; + TargetObject->Package.Count = SourceObject->Package.Count; + TargetObject->Package.Elements = + ACPI_CAST_PTR (ACPI_OBJECT, Info->FreeSpace); + + /* + * Pass the new package object back to the package walk routine + */ + State->Pkg.ThisTargetObj = TargetObject; + + /* + * Save space for the array of objects (Package elements) + * update the buffer length counter + */ + ObjectSpace = ACPI_ROUND_UP_TO_NATIVE_WORD ( + (ACPI_SIZE) TargetObject->Package.Count * + sizeof (ACPI_OBJECT)); + break; + + default: + + return (AE_BAD_PARAMETER); + } + + Info->FreeSpace += ObjectSpace; + Info->Length += ObjectSpace; + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIpackageToEpackage + * + * PARAMETERS: InternalObject - Pointer to the object we are returning + * Buffer - Where the object is returned + * SpaceUsed - Where the object length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to place a package object in a user + * buffer. A package object by definition contains other objects. + * + * The buffer is assumed to have sufficient space for the object. + * The caller must have verified the buffer length needed using + * the AcpiUtGetObjectSize function before calling this function. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyIpackageToEpackage ( + ACPI_OPERAND_OBJECT *InternalObject, + UINT8 *Buffer, + ACPI_SIZE *SpaceUsed) +{ + ACPI_OBJECT *ExternalObject; + ACPI_STATUS Status; + ACPI_PKG_INFO Info; + + + ACPI_FUNCTION_TRACE (UtCopyIpackageToEpackage); + + + /* + * First package at head of the buffer + */ + ExternalObject = ACPI_CAST_PTR (ACPI_OBJECT, Buffer); + + /* + * Free space begins right after the first package + */ + Info.Length = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); + Info.FreeSpace = Buffer + + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); + Info.ObjectSpace = 0; + Info.NumPackages = 1; + + ExternalObject->Type = InternalObject->Common.Type; + ExternalObject->Package.Count = InternalObject->Package.Count; + ExternalObject->Package.Elements = + ACPI_CAST_PTR (ACPI_OBJECT, Info.FreeSpace); + + /* + * Leave room for an array of ACPI_OBJECTS in the buffer + * and move the free space past it + */ + Info.Length += (ACPI_SIZE) ExternalObject->Package.Count * + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); + Info.FreeSpace += ExternalObject->Package.Count * + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT)); + + Status = AcpiUtWalkPackageTree (InternalObject, ExternalObject, + AcpiUtCopyIelementToEelement, &Info); + + *SpaceUsed = Info.Length; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIobjectToEobject + * + * PARAMETERS: InternalObject - The internal object to be converted + * RetBuffer - Where the object is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to build an API object to be returned + * to the caller. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCopyIobjectToEobject ( + ACPI_OPERAND_OBJECT *InternalObject, + ACPI_BUFFER *RetBuffer) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtCopyIobjectToEobject); + + + if (InternalObject->Common.Type == ACPI_TYPE_PACKAGE) + { + /* + * Package object: Copy all subobjects (including + * nested packages) + */ + Status = AcpiUtCopyIpackageToEpackage (InternalObject, + RetBuffer->Pointer, &RetBuffer->Length); + } + else + { + /* + * Build a simple object (no nested objects) + */ + Status = AcpiUtCopyIsimpleToEsimple (InternalObject, + ACPI_CAST_PTR (ACPI_OBJECT, RetBuffer->Pointer), + ACPI_ADD_PTR (UINT8, RetBuffer->Pointer, + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT))), + &RetBuffer->Length); + /* + * build simple does not include the object size in the length + * so we add it in here + */ + RetBuffer->Length += sizeof (ACPI_OBJECT); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyEsimpleToIsimple + * + * PARAMETERS: ExternalObject - The external object to be converted + * RetInternalObject - Where the internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: This function copies an external object to an internal one. + * NOTE: Pointers can be copied, we don't need to copy data. + * (The pointers have to be valid in our address space no matter + * what we do with them!) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyEsimpleToIsimple ( + ACPI_OBJECT *ExternalObject, + ACPI_OPERAND_OBJECT **RetInternalObject) +{ + ACPI_OPERAND_OBJECT *InternalObject; + + + ACPI_FUNCTION_TRACE (UtCopyEsimpleToIsimple); + + + /* + * Simple types supported are: String, Buffer, Integer + */ + switch (ExternalObject->Type) + { + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_LOCAL_REFERENCE: + + InternalObject = AcpiUtCreateInternalObject ( + (UINT8) ExternalObject->Type); + if (!InternalObject) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + break; + + case ACPI_TYPE_ANY: /* This is the case for a NULL object */ + + *RetInternalObject = NULL; + return_ACPI_STATUS (AE_OK); + + default: + + /* All other types are not supported */ + + ACPI_ERROR ((AE_INFO, + "Unsupported object type, cannot convert to internal object: %s", + AcpiUtGetTypeName (ExternalObject->Type))); + + return_ACPI_STATUS (AE_SUPPORT); + } + + + /* Must COPY string and buffer contents */ + + switch (ExternalObject->Type) + { + case ACPI_TYPE_STRING: + + InternalObject->String.Pointer = + ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) + ExternalObject->String.Length + 1); + + if (!InternalObject->String.Pointer) + { + goto ErrorExit; + } + + memcpy (InternalObject->String.Pointer, + ExternalObject->String.Pointer, + ExternalObject->String.Length); + + InternalObject->String.Length = ExternalObject->String.Length; + break; + + case ACPI_TYPE_BUFFER: + + InternalObject->Buffer.Pointer = + ACPI_ALLOCATE_ZEROED (ExternalObject->Buffer.Length); + if (!InternalObject->Buffer.Pointer) + { + goto ErrorExit; + } + + memcpy (InternalObject->Buffer.Pointer, + ExternalObject->Buffer.Pointer, + ExternalObject->Buffer.Length); + + InternalObject->Buffer.Length = ExternalObject->Buffer.Length; + + /* Mark buffer data valid */ + + InternalObject->Buffer.Flags |= AOPOBJ_DATA_VALID; + break; + + case ACPI_TYPE_INTEGER: + + InternalObject->Integer.Value = ExternalObject->Integer.Value; + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + /* An incoming reference is defined to be a namespace node */ + + InternalObject->Reference.Class = ACPI_REFCLASS_REFOF; + InternalObject->Reference.Object = ExternalObject->Reference.Handle; + break; + + default: + + /* Other types can't get here */ + + break; + } + + *RetInternalObject = InternalObject; + return_ACPI_STATUS (AE_OK); + + +ErrorExit: + AcpiUtRemoveReference (InternalObject); + return_ACPI_STATUS (AE_NO_MEMORY); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyEpackageToIpackage + * + * PARAMETERS: ExternalObject - The external object to be converted + * InternalObject - Where the internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Copy an external package object to an internal package. + * Handles nested packages. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyEpackageToIpackage ( + ACPI_OBJECT *ExternalObject, + ACPI_OPERAND_OBJECT **InternalObject) +{ + ACPI_STATUS Status = AE_OK; + ACPI_OPERAND_OBJECT *PackageObject; + ACPI_OPERAND_OBJECT **PackageElements; + UINT32 i; + + + ACPI_FUNCTION_TRACE (UtCopyEpackageToIpackage); + + + /* Create the package object */ + + PackageObject = AcpiUtCreatePackageObject ( + ExternalObject->Package.Count); + if (!PackageObject) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + PackageElements = PackageObject->Package.Elements; + + /* + * Recursive implementation. Probably ok, since nested external + * packages as parameters should be very rare. + */ + for (i = 0; i < ExternalObject->Package.Count; i++) + { + Status = AcpiUtCopyEobjectToIobject ( + &ExternalObject->Package.Elements[i], + &PackageElements[i]); + if (ACPI_FAILURE (Status)) + { + /* Truncate package and delete it */ + + PackageObject->Package.Count = i; + PackageElements[i] = NULL; + AcpiUtRemoveReference (PackageObject); + return_ACPI_STATUS (Status); + } + } + + /* Mark package data valid */ + + PackageObject->Package.Flags |= AOPOBJ_DATA_VALID; + + *InternalObject = PackageObject; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyEobjectToIobject + * + * PARAMETERS: ExternalObject - The external object to be converted + * InternalObject - Where the internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Converts an external object to an internal object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCopyEobjectToIobject ( + ACPI_OBJECT *ExternalObject, + ACPI_OPERAND_OBJECT **InternalObject) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtCopyEobjectToIobject); + + + if (ExternalObject->Type == ACPI_TYPE_PACKAGE) + { + Status = AcpiUtCopyEpackageToIpackage ( + ExternalObject, InternalObject); + } + else + { + /* + * Build a simple object (no nested objects) + */ + Status = AcpiUtCopyEsimpleToIsimple (ExternalObject, + InternalObject); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopySimpleObject + * + * PARAMETERS: SourceDesc - The internal object to be copied + * DestDesc - New target object + * + * RETURN: Status + * + * DESCRIPTION: Simple copy of one internal object to another. Reference count + * of the destination object is preserved. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopySimpleObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *DestDesc) +{ + UINT16 ReferenceCount; + ACPI_OPERAND_OBJECT *NextObject; + ACPI_STATUS Status; + ACPI_SIZE CopySize; + + + /* Save fields from destination that we don't want to overwrite */ + + ReferenceCount = DestDesc->Common.ReferenceCount; + NextObject = DestDesc->Common.NextObject; + + /* + * Copy the entire source object over the destination object. + * Note: Source can be either an operand object or namespace node. + */ + CopySize = sizeof (ACPI_OPERAND_OBJECT); + if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc) == ACPI_DESC_TYPE_NAMED) + { + CopySize = sizeof (ACPI_NAMESPACE_NODE); + } + + memcpy (ACPI_CAST_PTR (char, DestDesc), + ACPI_CAST_PTR (char, SourceDesc), CopySize); + + /* Restore the saved fields */ + + DestDesc->Common.ReferenceCount = ReferenceCount; + DestDesc->Common.NextObject = NextObject; + + /* New object is not static, regardless of source */ + + DestDesc->Common.Flags &= ~AOPOBJ_STATIC_POINTER; + + /* Handle the objects with extra data */ + + switch (DestDesc->Common.Type) + { + case ACPI_TYPE_BUFFER: + /* + * Allocate and copy the actual buffer if and only if: + * 1) There is a valid buffer pointer + * 2) The buffer has a length > 0 + */ + if ((SourceDesc->Buffer.Pointer) && + (SourceDesc->Buffer.Length)) + { + DestDesc->Buffer.Pointer = + ACPI_ALLOCATE (SourceDesc->Buffer.Length); + if (!DestDesc->Buffer.Pointer) + { + return (AE_NO_MEMORY); + } + + /* Copy the actual buffer data */ + + memcpy (DestDesc->Buffer.Pointer, + SourceDesc->Buffer.Pointer, SourceDesc->Buffer.Length); + } + break; + + case ACPI_TYPE_STRING: + /* + * Allocate and copy the actual string if and only if: + * 1) There is a valid string pointer + * (Pointer to a NULL string is allowed) + */ + if (SourceDesc->String.Pointer) + { + DestDesc->String.Pointer = + ACPI_ALLOCATE ((ACPI_SIZE) SourceDesc->String.Length + 1); + if (!DestDesc->String.Pointer) + { + return (AE_NO_MEMORY); + } + + /* Copy the actual string data */ + + memcpy (DestDesc->String.Pointer, SourceDesc->String.Pointer, + (ACPI_SIZE) SourceDesc->String.Length + 1); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + /* + * We copied the reference object, so we now must add a reference + * to the object pointed to by the reference + * + * DDBHandle reference (from Load/LoadTable) is a special reference, + * it does not have a Reference.Object, so does not need to + * increase the reference count + */ + if (SourceDesc->Reference.Class == ACPI_REFCLASS_TABLE) + { + break; + } + + AcpiUtAddReference (SourceDesc->Reference.Object); + break; + + case ACPI_TYPE_REGION: + /* + * We copied the Region Handler, so we now must add a reference + */ + if (DestDesc->Region.Handler) + { + AcpiUtAddReference (DestDesc->Region.Handler); + } + break; + + /* + * For Mutex and Event objects, we cannot simply copy the underlying + * OS object. We must create a new one. + */ + case ACPI_TYPE_MUTEX: + + Status = AcpiOsCreateMutex (&DestDesc->Mutex.OsMutex); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + case ACPI_TYPE_EVENT: + + Status = AcpiOsCreateSemaphore (ACPI_NO_UNIT_LIMIT, 0, + &DestDesc->Event.OsSemaphore); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + break; + + default: + + /* Nothing to do for other simple objects */ + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIelementToIelement + * + * PARAMETERS: ACPI_PKG_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Copy one package element to another package element + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyIelementToIelement ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context) +{ + ACPI_STATUS Status = AE_OK; + UINT32 ThisIndex; + ACPI_OPERAND_OBJECT **ThisTargetPtr; + ACPI_OPERAND_OBJECT *TargetObject; + + + ACPI_FUNCTION_ENTRY (); + + + ThisIndex = State->Pkg.Index; + ThisTargetPtr = (ACPI_OPERAND_OBJECT **) + &State->Pkg.DestObject->Package.Elements[ThisIndex]; + + switch (ObjectType) + { + case ACPI_COPY_TYPE_SIMPLE: + + /* A null source object indicates a (legal) null package element */ + + if (SourceObject) + { + /* + * This is a simple object, just copy it + */ + TargetObject = AcpiUtCreateInternalObject ( + SourceObject->Common.Type); + if (!TargetObject) + { + return (AE_NO_MEMORY); + } + + Status = AcpiUtCopySimpleObject (SourceObject, TargetObject); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + *ThisTargetPtr = TargetObject; + } + else + { + /* Pass through a null element */ + + *ThisTargetPtr = NULL; + } + break; + + case ACPI_COPY_TYPE_PACKAGE: + /* + * This object is a package - go down another nesting level + * Create and build the package object + */ + TargetObject = AcpiUtCreatePackageObject ( + SourceObject->Package.Count); + if (!TargetObject) + { + return (AE_NO_MEMORY); + } + + TargetObject->Common.Flags = SourceObject->Common.Flags; + + /* Pass the new package object back to the package walk routine */ + + State->Pkg.ThisTargetObj = TargetObject; + + /* Store the object pointer in the parent package object */ + + *ThisTargetPtr = TargetObject; + break; + + default: + + return (AE_BAD_PARAMETER); + } + + return (Status); + +ErrorExit: + AcpiUtRemoveReference (TargetObject); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIpackageToIpackage + * + * PARAMETERS: SourceObj - Pointer to the source package object + * DestObj - Where the internal object is returned + * WalkState - Current Walk state descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to copy an internal package object + * into another internal package object. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCopyIpackageToIpackage ( + ACPI_OPERAND_OBJECT *SourceObj, + ACPI_OPERAND_OBJECT *DestObj, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (UtCopyIpackageToIpackage); + + + DestObj->Common.Type = SourceObj->Common.Type; + DestObj->Common.Flags = SourceObj->Common.Flags; + DestObj->Package.Count = SourceObj->Package.Count; + + /* + * Create the object array and walk the source package tree + */ + DestObj->Package.Elements = ACPI_ALLOCATE_ZEROED ( + ((ACPI_SIZE) SourceObj->Package.Count + 1) * + sizeof (void *)); + if (!DestObj->Package.Elements) + { + ACPI_ERROR ((AE_INFO, "Package allocation failure")); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Copy the package element-by-element by walking the package "tree". + * This handles nested packages of arbitrary depth. + */ + Status = AcpiUtWalkPackageTree (SourceObj, DestObj, + AcpiUtCopyIelementToIelement, WalkState); + if (ACPI_FAILURE (Status)) + { + /* On failure, delete the destination package object */ + + AcpiUtRemoveReference (DestObj); + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCopyIobjectToIobject + * + * PARAMETERS: SourceDesc - The internal object to be copied + * DestDesc - Where the copied object is returned + * WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Copy an internal object to a new internal object + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCopyIobjectToIobject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **DestDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (UtCopyIobjectToIobject); + + + /* Create the top level object */ + + *DestDesc = AcpiUtCreateInternalObject (SourceDesc->Common.Type); + if (!*DestDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the object and possible subobjects */ + + if (SourceDesc->Common.Type == ACPI_TYPE_PACKAGE) + { + Status = AcpiUtCopyIpackageToIpackage ( + SourceDesc, *DestDesc, WalkState); + } + else + { + Status = AcpiUtCopySimpleObject (SourceDesc, *DestDesc); + } + + /* Delete the allocated object if copy failed */ + + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (*DestDesc); + } + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/utilities/utdebug.c b/third_party/lib/acpica/source/components/utilities/utdebug.c new file mode 100644 index 000000000..ccdca57bf --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utdebug.c @@ -0,0 +1,704 @@ +/****************************************************************************** + * + * Module Name: utdebug - Debug print/trace routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utdebug") + + +#ifdef ACPI_DEBUG_OUTPUT + +static ACPI_THREAD_ID AcpiGbl_PrevThreadId = (ACPI_THREAD_ID) 0xFFFFFFFF; +static char *AcpiGbl_FnEntryStr = "----Entry"; +static char *AcpiGbl_FnExitStr = "----Exit-"; + +/* Local prototypes */ + +static const char * +AcpiUtTrimFunctionName ( + const char *FunctionName); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtInitStackPtrTrace + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Save the current CPU stack pointer at subsystem startup + * + ******************************************************************************/ + +void +AcpiUtInitStackPtrTrace ( + void) +{ + ACPI_SIZE CurrentSp; + + + AcpiGbl_EntryStackPointer = &CurrentSp; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTrackStackPtr + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Save the current CPU stack pointer + * + ******************************************************************************/ + +void +AcpiUtTrackStackPtr ( + void) +{ + ACPI_SIZE CurrentSp; + + + if (&CurrentSp < AcpiGbl_LowestStackPointer) + { + AcpiGbl_LowestStackPointer = &CurrentSp; + } + + if (AcpiGbl_NestingLevel > AcpiGbl_DeepestNesting) + { + AcpiGbl_DeepestNesting = AcpiGbl_NestingLevel; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTrimFunctionName + * + * PARAMETERS: FunctionName - Ascii string containing a procedure name + * + * RETURN: Updated pointer to the function name + * + * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. + * This allows compiler macros such as __FUNCTION__ to be used + * with no change to the debug output. + * + ******************************************************************************/ + +static const char * +AcpiUtTrimFunctionName ( + const char *FunctionName) +{ + + /* All Function names are longer than 4 chars, check is safe */ + + if (*(ACPI_CAST_PTR (UINT32, FunctionName)) == ACPI_PREFIX_MIXED) + { + /* This is the case where the original source has not been modified */ + + return (FunctionName + 4); + } + + if (*(ACPI_CAST_PTR (UINT32, FunctionName)) == ACPI_PREFIX_LOWER) + { + /* This is the case where the source has been 'linuxized' */ + + return (FunctionName + 5); + } + + return (FunctionName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiDebugPrint + * + * PARAMETERS: RequestedDebugLevel - Requested debug print level + * LineNumber - Caller's line number (for error output) + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Format - Printf format field + * ... - Optional printf arguments + * + * RETURN: None + * + * DESCRIPTION: Print error message with prefix consisting of the module name, + * line number, and component ID. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiDebugPrint ( + UINT32 RequestedDebugLevel, + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *Format, + ...) +{ + ACPI_THREAD_ID ThreadId; + va_list args; + + + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (RequestedDebugLevel, ComponentId)) + { + return; + } + + /* + * Thread tracking and context switch notification + */ + ThreadId = AcpiOsGetThreadId (); + if (ThreadId != AcpiGbl_PrevThreadId) + { + if (ACPI_LV_THREADS & AcpiDbgLevel) + { + AcpiOsPrintf ( + "\n**** Context Switch from TID %u to TID %u ****\n\n", + (UINT32) AcpiGbl_PrevThreadId, (UINT32) ThreadId); + } + + AcpiGbl_PrevThreadId = ThreadId; + AcpiGbl_NestingLevel = 0; + } + + /* + * Display the module name, current line number, thread ID (if requested), + * current procedure nesting level, and the current procedure name + */ + AcpiOsPrintf ("%9s-%04ld ", ModuleName, LineNumber); + +#ifdef ACPI_APPLICATION + /* + * For AcpiExec/iASL only, emit the thread ID and nesting level. + * Note: nesting level is really only useful during a single-thread + * execution. Otherwise, multiple threads will keep resetting the + * level. + */ + if (ACPI_LV_THREADS & AcpiDbgLevel) + { + AcpiOsPrintf ("[%u] ", (UINT32) ThreadId); + } + + AcpiOsPrintf ("[%02ld] ", AcpiGbl_NestingLevel); +#endif + + AcpiOsPrintf ("%-22.22s: ", AcpiUtTrimFunctionName (FunctionName)); + + va_start (args, Format); + AcpiOsVprintf (Format, args); + va_end (args); +} + +ACPI_EXPORT_SYMBOL (AcpiDebugPrint) + + +/******************************************************************************* + * + * FUNCTION: AcpiDebugPrintRaw + * + * PARAMETERS: RequestedDebugLevel - Requested debug print level + * LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Format - Printf format field + * ... - Optional printf arguments + * + * RETURN: None + * + * DESCRIPTION: Print message with no headers. Has same interface as + * DebugPrint so that the same macros can be used. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiDebugPrintRaw ( + UINT32 RequestedDebugLevel, + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *Format, + ...) +{ + va_list args; + + + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED (RequestedDebugLevel, ComponentId)) + { + return; + } + + va_start (args, Format); + AcpiOsVprintf (Format, args); + va_end (args); +} + +ACPI_EXPORT_SYMBOL (AcpiDebugPrintRaw) + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTrace + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel + * + ******************************************************************************/ + +void +AcpiUtTrace ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId) +{ + + AcpiGbl_NestingLevel++; + AcpiUtTrackStackPtr (); + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s\n", AcpiGbl_FnEntryStr); + } +} + +ACPI_EXPORT_SYMBOL (AcpiUtTrace) + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTracePtr + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Pointer - Pointer to display + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel + * + ******************************************************************************/ + +void +AcpiUtTracePtr ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + void *Pointer) +{ + + AcpiGbl_NestingLevel++; + AcpiUtTrackStackPtr (); + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s %p\n", AcpiGbl_FnEntryStr, Pointer); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTraceStr + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * String - Additional string to display + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel + * + ******************************************************************************/ + +void +AcpiUtTraceStr ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + char *String) +{ + + AcpiGbl_NestingLevel++; + AcpiUtTrackStackPtr (); + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s %s\n", AcpiGbl_FnEntryStr, String); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTraceU32 + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Integer - Integer to display + * + * RETURN: None + * + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel + * + ******************************************************************************/ + +void +AcpiUtTraceU32 ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT32 Integer) +{ + + AcpiGbl_NestingLevel++; + AcpiUtTrackStackPtr (); + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s %08X\n", AcpiGbl_FnEntryStr, Integer); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExit + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel + * + ******************************************************************************/ + +void +AcpiUtExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId) +{ + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s\n", AcpiGbl_FnExitStr); + } + + if (AcpiGbl_NestingLevel) + { + AcpiGbl_NestingLevel--; + } +} + +ACPI_EXPORT_SYMBOL (AcpiUtExit) + + +/******************************************************************************* + * + * FUNCTION: AcpiUtStatusExit + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Status - Exit status code + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel. Prints exit status also. + * + ******************************************************************************/ + +void +AcpiUtStatusExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + ACPI_STATUS Status) +{ + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + if (ACPI_SUCCESS (Status)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s %s\n", AcpiGbl_FnExitStr, + AcpiFormatException (Status)); + } + else + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s ****Exception****: %s\n", AcpiGbl_FnExitStr, + AcpiFormatException (Status)); + } + } + + if (AcpiGbl_NestingLevel) + { + AcpiGbl_NestingLevel--; + } +} + +ACPI_EXPORT_SYMBOL (AcpiUtStatusExit) + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValueExit + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Value - Value to be printed with exit msg + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel. Prints exit value also. + * + ******************************************************************************/ + +void +AcpiUtValueExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT64 Value) +{ + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s %8.8X%8.8X\n", AcpiGbl_FnExitStr, + ACPI_FORMAT_UINT64 (Value)); + } + + if (AcpiGbl_NestingLevel) + { + AcpiGbl_NestingLevel--; + } +} + +ACPI_EXPORT_SYMBOL (AcpiUtValueExit) + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPtrExit + * + * PARAMETERS: LineNumber - Caller's line number + * FunctionName - Caller's procedure name + * ModuleName - Caller's module name + * ComponentId - Caller's component ID + * Ptr - Pointer to display + * + * RETURN: None + * + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * set in DebugLevel. Prints exit value also. + * + ******************************************************************************/ + +void +AcpiUtPtrExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT8 *Ptr) +{ + + /* Check if enabled up-front for performance */ + + if (ACPI_IS_DEBUG_ENABLED (ACPI_LV_FUNCTIONS, ComponentId)) + { + AcpiDebugPrint (ACPI_LV_FUNCTIONS, + LineNumber, FunctionName, ModuleName, ComponentId, + "%s %p\n", AcpiGbl_FnExitStr, Ptr); + } + + if (AcpiGbl_NestingLevel) + { + AcpiGbl_NestingLevel--; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTracePoint + * + * PARAMETERS: Type - Trace event type + * Begin - TRUE if before execution + * Aml - Executed AML address + * Pathname - Object path + * Pointer - Pointer to the related object + * + * RETURN: None + * + * DESCRIPTION: Interpreter execution trace. + * + ******************************************************************************/ + +void +AcpiTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname) +{ + + ACPI_FUNCTION_ENTRY (); + + AcpiExTracePoint (Type, Begin, Aml, Pathname); + +#ifdef ACPI_USE_SYSTEM_TRACER + AcpiOsTracePoint (Type, Begin, Aml, Pathname); +#endif +} + +ACPI_EXPORT_SYMBOL (AcpiTracePoint) + +#endif + + +#ifdef ACPI_APPLICATION +/******************************************************************************* + * + * FUNCTION: AcpiLogError + * + * PARAMETERS: Format - Printf format field + * ... - Optional printf arguments + * + * RETURN: None + * + * DESCRIPTION: Print error message to the console, used by applications. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiLogError ( + const char *Format, + ...) +{ + va_list Args; + + va_start (Args, Format); + (void) AcpiUtFileVprintf (ACPI_FILE_ERR, Format, Args); + va_end (Args); +} + +ACPI_EXPORT_SYMBOL (AcpiLogError) +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utdecode.c b/third_party/lib/acpica/source/components/utilities/utdecode.c new file mode 100644 index 000000000..06817ab3b --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utdecode.c @@ -0,0 +1,632 @@ +/****************************************************************************** + * + * Module Name: utdecode - Utility decoding routines (value-to-string) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utdecode") + + +/* + * Properties of the ACPI Object Types, both internal and external. + * The table is indexed by values of ACPI_OBJECT_TYPE + */ +const UINT8 AcpiGbl_NsProperties[ACPI_NUM_NS_TYPES] = +{ + ACPI_NS_NORMAL, /* 00 Any */ + ACPI_NS_NORMAL, /* 01 Number */ + ACPI_NS_NORMAL, /* 02 String */ + ACPI_NS_NORMAL, /* 03 Buffer */ + ACPI_NS_NORMAL, /* 04 Package */ + ACPI_NS_NORMAL, /* 05 FieldUnit */ + ACPI_NS_NEWSCOPE, /* 06 Device */ + ACPI_NS_NORMAL, /* 07 Event */ + ACPI_NS_NEWSCOPE, /* 08 Method */ + ACPI_NS_NORMAL, /* 09 Mutex */ + ACPI_NS_NORMAL, /* 10 Region */ + ACPI_NS_NEWSCOPE, /* 11 Power */ + ACPI_NS_NEWSCOPE, /* 12 Processor */ + ACPI_NS_NEWSCOPE, /* 13 Thermal */ + ACPI_NS_NORMAL, /* 14 BufferField */ + ACPI_NS_NORMAL, /* 15 DdbHandle */ + ACPI_NS_NORMAL, /* 16 Debug Object */ + ACPI_NS_NORMAL, /* 17 DefField */ + ACPI_NS_NORMAL, /* 18 BankField */ + ACPI_NS_NORMAL, /* 19 IndexField */ + ACPI_NS_NORMAL, /* 20 Reference */ + ACPI_NS_NORMAL, /* 21 Alias */ + ACPI_NS_NORMAL, /* 22 MethodAlias */ + ACPI_NS_NORMAL, /* 23 Notify */ + ACPI_NS_NORMAL, /* 24 Address Handler */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */ + ACPI_NS_NEWSCOPE, /* 27 Scope */ + ACPI_NS_NORMAL, /* 28 Extra */ + ACPI_NS_NORMAL, /* 29 Data */ + ACPI_NS_NORMAL /* 30 Invalid */ +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetRegionName + * + * PARAMETERS: Space ID - ID for the region + * + * RETURN: Decoded region SpaceId name + * + * DESCRIPTION: Translate a Space ID into a name string (Debug only) + * + ******************************************************************************/ + +/* Region type decoding */ + +const char *AcpiGbl_RegionTypes[ACPI_NUM_PREDEFINED_REGIONS] = +{ + "SystemMemory", /* 0x00 */ + "SystemIO", /* 0x01 */ + "PCI_Config", /* 0x02 */ + "EmbeddedControl", /* 0x03 */ + "SMBus", /* 0x04 */ + "SystemCMOS", /* 0x05 */ + "PCIBARTarget", /* 0x06 */ + "IPMI", /* 0x07 */ + "GeneralPurposeIo", /* 0x08 */ + "GenericSerialBus", /* 0x09 */ + "PCC" /* 0x0A */ +}; + + +const char * +AcpiUtGetRegionName ( + UINT8 SpaceId) +{ + + if (SpaceId >= ACPI_USER_REGION_BEGIN) + { + return ("UserDefinedRegion"); + } + else if (SpaceId == ACPI_ADR_SPACE_DATA_TABLE) + { + return ("DataTable"); + } + else if (SpaceId == ACPI_ADR_SPACE_FIXED_HARDWARE) + { + return ("FunctionalFixedHW"); + } + else if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) + { + return ("InvalidSpaceId"); + } + + return (AcpiGbl_RegionTypes[SpaceId]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetEventName + * + * PARAMETERS: EventId - Fixed event ID + * + * RETURN: Decoded event ID name + * + * DESCRIPTION: Translate a Event ID into a name string (Debug only) + * + ******************************************************************************/ + +/* Event type decoding */ + +static const char *AcpiGbl_EventTypes[ACPI_NUM_FIXED_EVENTS] = +{ + "PM_Timer", + "GlobalLock", + "PowerButton", + "SleepButton", + "RealTimeClock", +}; + + +const char * +AcpiUtGetEventName ( + UINT32 EventId) +{ + + if (EventId > ACPI_EVENT_MAX) + { + return ("InvalidEventID"); + } + + return (AcpiGbl_EventTypes[EventId]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetTypeName + * + * PARAMETERS: Type - An ACPI object type + * + * RETURN: Decoded ACPI object type name + * + * DESCRIPTION: Translate a Type ID into a name string (Debug only) + * + ******************************************************************************/ + +/* + * Elements of AcpiGbl_NsTypeNames below must match + * one-to-one with values of ACPI_OBJECT_TYPE + * + * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; + * when stored in a table it really means that we have thus far seen no + * evidence to indicate what type is actually going to be stored for this + & entry. + */ +static const char AcpiGbl_BadType[] = "UNDEFINED"; + +/* Printable names of the ACPI object types */ + +static const char *AcpiGbl_NsTypeNames[] = +{ + /* 00 */ "Untyped", + /* 01 */ "Integer", + /* 02 */ "String", + /* 03 */ "Buffer", + /* 04 */ "Package", + /* 05 */ "FieldUnit", + /* 06 */ "Device", + /* 07 */ "Event", + /* 08 */ "Method", + /* 09 */ "Mutex", + /* 10 */ "Region", + /* 11 */ "Power", + /* 12 */ "Processor", + /* 13 */ "Thermal", + /* 14 */ "BufferField", + /* 15 */ "DdbHandle", + /* 16 */ "DebugObject", + /* 17 */ "RegionField", + /* 18 */ "BankField", + /* 19 */ "IndexField", + /* 20 */ "Reference", + /* 21 */ "Alias", + /* 22 */ "MethodAlias", + /* 23 */ "Notify", + /* 24 */ "AddrHandler", + /* 25 */ "ResourceDesc", + /* 26 */ "ResourceFld", + /* 27 */ "Scope", + /* 28 */ "Extra", + /* 29 */ "Data", + /* 30 */ "Invalid" +}; + + +const char * +AcpiUtGetTypeName ( + ACPI_OBJECT_TYPE Type) +{ + + if (Type > ACPI_TYPE_INVALID) + { + return (AcpiGbl_BadType); + } + + return (AcpiGbl_NsTypeNames[Type]); +} + + +const char * +AcpiUtGetObjectTypeName ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_FUNCTION_TRACE (UtGetObjectTypeName); + + + if (!ObjDesc) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n")); + return_PTR ("[NULL Object Descriptor]"); + } + + /* These descriptor types share a common area */ + + if ((ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_NAMED)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Invalid object descriptor type: 0x%2.2X [%s] (%p)\n", + ACPI_GET_DESCRIPTOR_TYPE (ObjDesc), + AcpiUtGetDescriptorName (ObjDesc), ObjDesc)); + + return_PTR ("Invalid object"); + } + + return_PTR (AcpiUtGetTypeName (ObjDesc->Common.Type)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetNodeName + * + * PARAMETERS: Object - A namespace node + * + * RETURN: ASCII name of the node + * + * DESCRIPTION: Validate the node and return the node's ACPI name. + * + ******************************************************************************/ + +const char * +AcpiUtGetNodeName ( + void *Object) +{ + ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) Object; + + + /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ + + if (!Object) + { + return ("NULL"); + } + + /* Check for Root node */ + + if ((Object == ACPI_ROOT_OBJECT) || + (Object == AcpiGbl_RootNode)) + { + return ("\"\\\" "); + } + + /* Descriptor must be a namespace node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED) + { + return ("####"); + } + + /* + * Ensure name is valid. The name was validated/repaired when the node + * was created, but make sure it has not been corrupted. + */ + AcpiUtRepairName (Node->Name.Ascii); + + /* Return the name */ + + return (Node->Name.Ascii); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetDescriptorName + * + * PARAMETERS: Object - An ACPI object + * + * RETURN: Decoded name of the descriptor type + * + * DESCRIPTION: Validate object and return the descriptor type + * + ******************************************************************************/ + +/* Printable names of object descriptor types */ + +static const char *AcpiGbl_DescTypeNames[] = +{ + /* 00 */ "Not a Descriptor", + /* 01 */ "Cached", + /* 02 */ "State-Generic", + /* 03 */ "State-Update", + /* 04 */ "State-Package", + /* 05 */ "State-Control", + /* 06 */ "State-RootParseScope", + /* 07 */ "State-ParseScope", + /* 08 */ "State-WalkScope", + /* 09 */ "State-Result", + /* 10 */ "State-Notify", + /* 11 */ "State-Thread", + /* 12 */ "Walk", + /* 13 */ "Parser", + /* 14 */ "Operand", + /* 15 */ "Node" +}; + + +const char * +AcpiUtGetDescriptorName ( + void *Object) +{ + + if (!Object) + { + return ("NULL OBJECT"); + } + + if (ACPI_GET_DESCRIPTOR_TYPE (Object) > ACPI_DESC_TYPE_MAX) + { + return ("Not a Descriptor"); + } + + return (AcpiGbl_DescTypeNames[ACPI_GET_DESCRIPTOR_TYPE (Object)]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetReferenceName + * + * PARAMETERS: Object - An ACPI reference object + * + * RETURN: Decoded name of the type of reference + * + * DESCRIPTION: Decode a reference object sub-type to a string. + * + ******************************************************************************/ + +/* Printable names of reference object sub-types */ + +static const char *AcpiGbl_RefClassNames[] = +{ + /* 00 */ "Local", + /* 01 */ "Argument", + /* 02 */ "RefOf", + /* 03 */ "Index", + /* 04 */ "DdbHandle", + /* 05 */ "Named Object", + /* 06 */ "Debug" +}; + +const char * +AcpiUtGetReferenceName ( + ACPI_OPERAND_OBJECT *Object) +{ + + if (!Object) + { + return ("NULL Object"); + } + + if (ACPI_GET_DESCRIPTOR_TYPE (Object) != ACPI_DESC_TYPE_OPERAND) + { + return ("Not an Operand object"); + } + + if (Object->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) + { + return ("Not a Reference object"); + } + + if (Object->Reference.Class > ACPI_REFCLASS_MAX) + { + return ("Unknown Reference class"); + } + + return (AcpiGbl_RefClassNames[Object->Reference.Class]); +} + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* + * Strings and procedures used for debug only + */ + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetMutexName + * + * PARAMETERS: MutexId - The predefined ID for this mutex. + * + * RETURN: Decoded name of the internal mutex + * + * DESCRIPTION: Translate a mutex ID into a name string (Debug only) + * + ******************************************************************************/ + +/* Names for internal mutex objects, used for debug output */ + +static const char *AcpiGbl_MutexNames[ACPI_NUM_MUTEX] = +{ + "ACPI_MTX_Interpreter", + "ACPI_MTX_Namespace", + "ACPI_MTX_Tables", + "ACPI_MTX_Events", + "ACPI_MTX_Caches", + "ACPI_MTX_Memory", +}; + +const char * +AcpiUtGetMutexName ( + UINT32 MutexId) +{ + + if (MutexId > ACPI_MAX_MUTEX) + { + return ("Invalid Mutex ID"); + } + + return (AcpiGbl_MutexNames[MutexId]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetNotifyName + * + * PARAMETERS: NotifyValue - Value from the Notify() request + * + * RETURN: Decoded name for the notify value + * + * DESCRIPTION: Translate a Notify Value to a notify namestring. + * + ******************************************************************************/ + +/* Names for Notify() values, used for debug output */ + +static const char *AcpiGbl_GenericNotify[ACPI_NOTIFY_MAX + 1] = +{ + /* 00 */ "Bus Check", + /* 01 */ "Device Check", + /* 02 */ "Device Wake", + /* 03 */ "Eject Request", + /* 04 */ "Device Check Light", + /* 05 */ "Frequency Mismatch", + /* 06 */ "Bus Mode Mismatch", + /* 07 */ "Power Fault", + /* 08 */ "Capabilities Check", + /* 09 */ "Device PLD Check", + /* 0A */ "Reserved", + /* 0B */ "System Locality Update", + /* 0C */ "Shutdown Request", + /* 0D */ "System Resource Affinity Update" +}; + +static const char *AcpiGbl_DeviceNotify[4] = +{ + /* 80 */ "Status Change", + /* 81 */ "Information Change", + /* 82 */ "Device-Specific Change", + /* 83 */ "Device-Specific Change" +}; + +static const char *AcpiGbl_ProcessorNotify[4] = +{ + /* 80 */ "Performance Capability Change", + /* 81 */ "C-State Change", + /* 82 */ "Throttling Capability Change", + /* 83 */ "Device-Specific Change" +}; + +static const char *AcpiGbl_ThermalNotify[4] = +{ + /* 80 */ "Thermal Status Change", + /* 81 */ "Thermal Trip Point Change", + /* 82 */ "Thermal Device List Change", + /* 83 */ "Thermal Relationship Change" +}; + + +const char * +AcpiUtGetNotifyName ( + UINT32 NotifyValue, + ACPI_OBJECT_TYPE Type) +{ + + /* 00 - 0D are common to all object types */ + + if (NotifyValue <= ACPI_NOTIFY_MAX) + { + return (AcpiGbl_GenericNotify[NotifyValue]); + } + + /* 0D - 7F are reserved */ + + if (NotifyValue <= ACPI_MAX_SYS_NOTIFY) + { + return ("Reserved"); + } + + /* 80 - 83 are per-object-type */ + + if (NotifyValue <= 0x83) + { + switch (Type) + { + case ACPI_TYPE_ANY: + case ACPI_TYPE_DEVICE: + return (AcpiGbl_DeviceNotify [NotifyValue - 0x80]); + + case ACPI_TYPE_PROCESSOR: + return (AcpiGbl_ProcessorNotify [NotifyValue - 0x80]); + + case ACPI_TYPE_THERMAL: + return (AcpiGbl_ThermalNotify [NotifyValue - 0x80]); + + default: + return ("Target object type does not support notifies"); + } + } + + /* 84 - BF are device-specific */ + + if (NotifyValue <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) + { + return ("Device-Specific"); + } + + /* C0 and above are hardware-specific */ + + return ("Hardware-Specific"); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidObjectType + * + * PARAMETERS: Type - Object type to be validated + * + * RETURN: TRUE if valid object type, FALSE otherwise + * + * DESCRIPTION: Validate an object type + * + ******************************************************************************/ + +BOOLEAN +AcpiUtValidObjectType ( + ACPI_OBJECT_TYPE Type) +{ + + if (Type > ACPI_TYPE_LOCAL_MAX) + { + /* Note: Assumes all TYPEs are contiguous (external/local) */ + + return (FALSE); + } + + return (TRUE); +} diff --git a/third_party/lib/acpica/source/components/utilities/utdelete.c b/third_party/lib/acpica/source/components/utilities/utdelete.c new file mode 100644 index 000000000..95a98f568 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utdelete.c @@ -0,0 +1,811 @@ +/******************************************************************************* + * + * Module Name: utdelete - object deletion and reference count utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utdelete") + +/* Local prototypes */ + +static void +AcpiUtDeleteInternalObj ( + ACPI_OPERAND_OBJECT *Object); + +static void +AcpiUtUpdateRefCount ( + ACPI_OPERAND_OBJECT *Object, + UINT32 Action); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteInternalObj + * + * PARAMETERS: Object - Object to be deleted + * + * RETURN: None + * + * DESCRIPTION: Low level object deletion, after reference counts have been + * updated (All reference counts, including sub-objects!) + * + ******************************************************************************/ + +static void +AcpiUtDeleteInternalObj ( + ACPI_OPERAND_OBJECT *Object) +{ + void *ObjPointer = NULL; + ACPI_OPERAND_OBJECT *HandlerDesc; + ACPI_OPERAND_OBJECT *SecondDesc; + ACPI_OPERAND_OBJECT *NextDesc; + ACPI_OPERAND_OBJECT *StartDesc; + ACPI_OPERAND_OBJECT **LastObjPtr; + + + ACPI_FUNCTION_TRACE_PTR (UtDeleteInternalObj, Object); + + + if (!Object) + { + return_VOID; + } + + /* + * Must delete or free any pointers within the object that are not + * actual ACPI objects (for example, a raw buffer pointer). + */ + switch (Object->Common.Type) + { + case ACPI_TYPE_STRING: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n", + Object, Object->String.Pointer)); + + /* Free the actual string buffer */ + + if (!(Object->Common.Flags & AOPOBJ_STATIC_POINTER)) + { + /* But only if it is NOT a pointer into an ACPI table */ + + ObjPointer = Object->String.Pointer; + } + break; + + case ACPI_TYPE_BUFFER: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n", + Object, Object->Buffer.Pointer)); + + /* Free the actual buffer */ + + if (!(Object->Common.Flags & AOPOBJ_STATIC_POINTER)) + { + /* But only if it is NOT a pointer into an ACPI table */ + + ObjPointer = Object->Buffer.Pointer; + } + break; + + case ACPI_TYPE_PACKAGE: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n", + Object->Package.Count)); + + /* + * Elements of the package are not handled here, they are deleted + * separately + */ + + /* Free the (variable length) element pointer array */ + + ObjPointer = Object->Package.Elements; + break; + + /* + * These objects have a possible list of notify handlers. + * Device object also may have a GPE block. + */ + case ACPI_TYPE_DEVICE: + + if (Object->Device.GpeBlock) + { + (void) AcpiEvDeleteGpeBlock (Object->Device.GpeBlock); + } + + /*lint -fallthrough */ + + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* Walk the address handler list for this object */ + + HandlerDesc = Object->CommonNotify.Handler; + while (HandlerDesc) + { + NextDesc = HandlerDesc->AddressSpace.Next; + AcpiUtRemoveReference (HandlerDesc); + HandlerDesc = NextDesc; + } + break; + + case ACPI_TYPE_MUTEX: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Mutex %p, OS Mutex %p\n", + Object, Object->Mutex.OsMutex)); + + if (Object == AcpiGbl_GlobalLockMutex) + { + /* Global Lock has extra semaphore */ + + (void) AcpiOsDeleteSemaphore (AcpiGbl_GlobalLockSemaphore); + AcpiGbl_GlobalLockSemaphore = NULL; + + AcpiOsDeleteMutex (Object->Mutex.OsMutex); + AcpiGbl_GlobalLockMutex = NULL; + } + else + { + AcpiExUnlinkMutex (Object); + AcpiOsDeleteMutex (Object->Mutex.OsMutex); + } + break; + + case ACPI_TYPE_EVENT: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Event %p, OS Semaphore %p\n", + Object, Object->Event.OsSemaphore)); + + (void) AcpiOsDeleteSemaphore (Object->Event.OsSemaphore); + Object->Event.OsSemaphore = NULL; + break; + + case ACPI_TYPE_METHOD: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Method %p\n", Object)); + + /* Delete the method mutex if it exists */ + + if (Object->Method.Mutex) + { + AcpiOsDeleteMutex (Object->Method.Mutex->Mutex.OsMutex); + AcpiUtDeleteObjectDesc (Object->Method.Mutex); + Object->Method.Mutex = NULL; + } + + if (Object->Method.Node) + { + Object->Method.Node = NULL; + } + break; + + case ACPI_TYPE_REGION: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Region %p\n", Object)); + + /* + * Update AddressRange list. However, only permanent regions + * are installed in this list. (Not created within a method) + */ + if (!(Object->Region.Node->Flags & ANOBJ_TEMPORARY)) + { + AcpiUtRemoveAddressRange (Object->Region.SpaceId, + Object->Region.Node); + } + + SecondDesc = AcpiNsGetSecondaryObject (Object); + if (SecondDesc) + { + /* + * Free the RegionContext if and only if the handler is one of the + * default handlers -- and therefore, we created the context object + * locally, it was not created by an external caller. + */ + HandlerDesc = Object->Region.Handler; + if (HandlerDesc) + { + NextDesc = HandlerDesc->AddressSpace.RegionList; + StartDesc = NextDesc; + LastObjPtr = &HandlerDesc->AddressSpace.RegionList; + + /* Remove the region object from the handler list */ + + while (NextDesc) + { + if (NextDesc == Object) + { + *LastObjPtr = NextDesc->Region.Next; + break; + } + + /* Walk the linked list of handlers */ + + LastObjPtr = &NextDesc->Region.Next; + NextDesc = NextDesc->Region.Next; + + /* Prevent infinite loop if list is corrupted */ + + if (NextDesc == StartDesc) + { + ACPI_ERROR ((AE_INFO, + "Circular region list in address handler object %p", + HandlerDesc)); + return_VOID; + } + } + + if (HandlerDesc->AddressSpace.HandlerFlags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) + { + /* Deactivate region and free region context */ + + if (HandlerDesc->AddressSpace.Setup) + { + (void) HandlerDesc->AddressSpace.Setup (Object, + ACPI_REGION_DEACTIVATE, + HandlerDesc->AddressSpace.Context, + &SecondDesc->Extra.RegionContext); + } + } + + AcpiUtRemoveReference (HandlerDesc); + } + + /* Now we can free the Extra object */ + + AcpiUtDeleteObjectDesc (SecondDesc); + } + break; + + case ACPI_TYPE_BUFFER_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Buffer Field %p\n", Object)); + + SecondDesc = AcpiNsGetSecondaryObject (Object); + if (SecondDesc) + { + AcpiUtDeleteObjectDesc (SecondDesc); + } + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Bank Field %p\n", Object)); + + SecondDesc = AcpiNsGetSecondaryObject (Object); + if (SecondDesc) + { + AcpiUtDeleteObjectDesc (SecondDesc); + } + break; + + default: + + break; + } + + /* Free any allocated memory (pointer within the object) found above */ + + if (ObjPointer) + { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n", + ObjPointer)); + ACPI_FREE (ObjPointer); + } + + /* Now the object can be safely deleted */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n", + Object, AcpiUtGetObjectTypeName (Object))); + + AcpiUtDeleteObjectDesc (Object); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteInternalObjectList + * + * PARAMETERS: ObjList - Pointer to the list to be deleted + * + * RETURN: None + * + * DESCRIPTION: This function deletes an internal object list, including both + * simple objects and package objects + * + ******************************************************************************/ + +void +AcpiUtDeleteInternalObjectList ( + ACPI_OPERAND_OBJECT **ObjList) +{ + ACPI_OPERAND_OBJECT **InternalObj; + + + ACPI_FUNCTION_ENTRY (); + + + /* Walk the null-terminated internal list */ + + for (InternalObj = ObjList; *InternalObj; InternalObj++) + { + AcpiUtRemoveReference (*InternalObj); + } + + /* Free the combined parameter pointer list and object array */ + + ACPI_FREE (ObjList); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtUpdateRefCount + * + * PARAMETERS: Object - Object whose ref count is to be updated + * Action - What to do (REF_INCREMENT or REF_DECREMENT) + * + * RETURN: None. Sets new reference count within the object + * + * DESCRIPTION: Modify the reference count for an internal acpi object + * + ******************************************************************************/ + +static void +AcpiUtUpdateRefCount ( + ACPI_OPERAND_OBJECT *Object, + UINT32 Action) +{ + UINT16 OriginalCount; + UINT16 NewCount = 0; + ACPI_CPU_FLAGS LockFlags; + + + ACPI_FUNCTION_NAME (UtUpdateRefCount); + + + if (!Object) + { + return; + } + + /* + * Always get the reference count lock. Note: Interpreter and/or + * Namespace is not always locked when this function is called. + */ + LockFlags = AcpiOsAcquireLock (AcpiGbl_ReferenceCountLock); + OriginalCount = Object->Common.ReferenceCount; + + /* Perform the reference count action (increment, decrement) */ + + switch (Action) + { + case REF_INCREMENT: + + NewCount = OriginalCount + 1; + Object->Common.ReferenceCount = NewCount; + AcpiOsReleaseLock (AcpiGbl_ReferenceCountLock, LockFlags); + + /* The current reference count should never be zero here */ + + if (!OriginalCount) + { + ACPI_WARNING ((AE_INFO, + "Obj %p, Reference Count was zero before increment\n", + Object)); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Type %.2X Refs %.2X [Incremented]\n", + Object, Object->Common.Type, NewCount)); + break; + + case REF_DECREMENT: + + /* The current reference count must be non-zero */ + + if (OriginalCount) + { + NewCount = OriginalCount - 1; + Object->Common.ReferenceCount = NewCount; + } + + AcpiOsReleaseLock (AcpiGbl_ReferenceCountLock, LockFlags); + + if (!OriginalCount) + { + ACPI_WARNING ((AE_INFO, + "Obj %p, Reference Count is already zero, cannot decrement\n", + Object)); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Type %.2X Refs %.2X [Decremented]\n", + Object, Object->Common.Type, NewCount)); + + /* Actually delete the object on a reference count of zero */ + + if (NewCount == 0) + { + AcpiUtDeleteInternalObj (Object); + } + break; + + default: + + AcpiOsReleaseLock (AcpiGbl_ReferenceCountLock, LockFlags); + ACPI_ERROR ((AE_INFO, "Unknown Reference Count action (0x%X)", + Action)); + return; + } + + /* + * Sanity check the reference count, for debug purposes only. + * (A deleted object will have a huge reference count) + */ + if (NewCount > ACPI_MAX_REFERENCE_COUNT) + { + ACPI_WARNING ((AE_INFO, + "Large Reference Count (0x%X) in object %p, Type=0x%.2X", + NewCount, Object, Object->Common.Type)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtUpdateObjectReference + * + * PARAMETERS: Object - Increment ref count for this object + * and all sub-objects + * Action - Either REF_INCREMENT or REF_DECREMENT + * + * RETURN: Status + * + * DESCRIPTION: Increment the object reference count + * + * Object references are incremented when: + * 1) An object is attached to a Node (namespace object) + * 2) An object is copied (all subobjects must be incremented) + * + * Object references are decremented when: + * 1) An object is detached from an Node + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtUpdateObjectReference ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GENERIC_STATE *StateList = NULL; + ACPI_OPERAND_OBJECT *NextObject = NULL; + ACPI_OPERAND_OBJECT *PrevObject; + ACPI_GENERIC_STATE *State; + UINT32 i; + + + ACPI_FUNCTION_NAME (UtUpdateObjectReference); + + + while (Object) + { + /* Make sure that this isn't a namespace handle */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Object) == ACPI_DESC_TYPE_NAMED) + { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Object %p is NS handle\n", Object)); + return (AE_OK); + } + + /* + * All sub-objects must have their reference count incremented + * also. Different object types have different subobjects. + */ + switch (Object->Common.Type) + { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + case ACPI_TYPE_THERMAL: + /* + * Update the notify objects for these types (if present) + * Two lists, system and device notify handlers. + */ + for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) + { + PrevObject = Object->CommonNotify.NotifyList[i]; + while (PrevObject) + { + NextObject = PrevObject->Notify.Next[i]; + AcpiUtUpdateRefCount (PrevObject, Action); + PrevObject = NextObject; + } + } + break; + + case ACPI_TYPE_PACKAGE: + /* + * We must update all the sub-objects of the package, + * each of whom may have their own sub-objects. + */ + for (i = 0; i < Object->Package.Count; i++) + { + /* + * Null package elements are legal and can be simply + * ignored. + */ + NextObject = Object->Package.Elements[i]; + if (!NextObject) + { + continue; + } + + switch (NextObject->Common.Type) + { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + /* + * For these very simple sub-objects, we can just + * update the reference count here and continue. + * Greatly increases performance of this operation. + */ + AcpiUtUpdateRefCount (NextObject, Action); + break; + + default: + /* + * For complex sub-objects, push them onto the stack + * for later processing (this eliminates recursion.) + */ + Status = AcpiUtCreateUpdateStateAndPush ( + NextObject, Action, &StateList); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + break; + } + } + NextObject = NULL; + break; + + case ACPI_TYPE_BUFFER_FIELD: + + NextObject = Object->BufferField.BufferObj; + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + NextObject = Object->Field.RegionObj; + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + NextObject = Object->BankField.BankObj; + Status = AcpiUtCreateUpdateStateAndPush ( + Object->BankField.RegionObj, Action, &StateList); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + NextObject = Object->IndexField.IndexObj; + Status = AcpiUtCreateUpdateStateAndPush ( + Object->IndexField.DataObj, Action, &StateList); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + /* + * The target of an Index (a package, string, or buffer) or a named + * reference must track changes to the ref count of the index or + * target object. + */ + if ((Object->Reference.Class == ACPI_REFCLASS_INDEX) || + (Object->Reference.Class== ACPI_REFCLASS_NAME)) + { + NextObject = Object->Reference.Object; + } + break; + + case ACPI_TYPE_REGION: + default: + + break; /* No subobjects for all other types */ + } + + /* + * Now we can update the count in the main object. This can only + * happen after we update the sub-objects in case this causes the + * main object to be deleted. + */ + AcpiUtUpdateRefCount (Object, Action); + Object = NULL; + + /* Move on to the next object to be updated */ + + if (NextObject) + { + Object = NextObject; + NextObject = NULL; + } + else if (StateList) + { + State = AcpiUtPopGenericState (&StateList); + Object = State->Update.Object; + AcpiUtDeleteGenericState (State); + } + } + + return (AE_OK); + + +ErrorExit: + + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not update object reference count")); + + /* Free any stacked Update State objects */ + + while (StateList) + { + State = AcpiUtPopGenericState (&StateList); + AcpiUtDeleteGenericState (State); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAddReference + * + * PARAMETERS: Object - Object whose reference count is to be + * incremented + * + * RETURN: None + * + * DESCRIPTION: Add one reference to an ACPI object + * + ******************************************************************************/ + +void +AcpiUtAddReference ( + ACPI_OPERAND_OBJECT *Object) +{ + + ACPI_FUNCTION_NAME (UtAddReference); + + + /* Ensure that we have a valid object */ + + if (!AcpiUtValidInternalObject (Object)) + { + return; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Current Refs=%X [To Be Incremented]\n", + Object, Object->Common.ReferenceCount)); + + /* Increment the reference count */ + + (void) AcpiUtUpdateObjectReference (Object, REF_INCREMENT); + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtRemoveReference + * + * PARAMETERS: Object - Object whose ref count will be decremented + * + * RETURN: None + * + * DESCRIPTION: Decrement the reference count of an ACPI internal object + * + ******************************************************************************/ + +void +AcpiUtRemoveReference ( + ACPI_OPERAND_OBJECT *Object) +{ + + ACPI_FUNCTION_NAME (UtRemoveReference); + + + /* + * Allow a NULL pointer to be passed in, just ignore it. This saves + * each caller from having to check. Also, ignore NS nodes. + */ + if (!Object || + (ACPI_GET_DESCRIPTOR_TYPE (Object) == ACPI_DESC_TYPE_NAMED)) + + { + return; + } + + /* Ensure that we have a valid object */ + + if (!AcpiUtValidInternalObject (Object)) + { + return; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Current Refs=%X [To Be Decremented]\n", + Object, Object->Common.ReferenceCount)); + + /* + * Decrement the reference count, and only actually delete the object + * if the reference count becomes 0. (Must also decrement the ref count + * of all subobjects!) + */ + (void) AcpiUtUpdateObjectReference (Object, REF_DECREMENT); + return; +} diff --git a/third_party/lib/acpica/source/components/utilities/uterror.c b/third_party/lib/acpica/source/components/utilities/uterror.c new file mode 100644 index 000000000..86d236852 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/uterror.c @@ -0,0 +1,325 @@ +/******************************************************************************* + * + * Module Name: uterror - Various internal error/warning output functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("uterror") + + +/* + * This module contains internal error functions that may + * be configured out. + */ +#if !defined (ACPI_NO_ERROR_MESSAGES) + +/******************************************************************************* + * + * FUNCTION: AcpiUtPredefinedWarning + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Pathname - Full pathname to the node + * NodeFlags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Warnings for the predefined validation module. Messages are + * only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of error + * messages for methods that are repeatedly evaluated. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedWarning ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...) +{ + va_list ArgList; + + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (NodeFlags & ANOBJ_EVALUATED) + { + return; + } + + AcpiOsPrintf (ACPI_MSG_WARNING "%s: ", Pathname); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPredefinedInfo + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Pathname - Full pathname to the node + * NodeFlags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Info messages for the predefined validation module. Messages + * are only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of + * messages for methods that are repeatedly evaluated. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedInfo ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...) +{ + va_list ArgList; + + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (NodeFlags & ANOBJ_EVALUATED) + { + return; + } + + AcpiOsPrintf (ACPI_MSG_INFO "%s: ", Pathname); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPredefinedBiosError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Pathname - Full pathname to the node + * NodeFlags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: BIOS error message for predefined names. Messages + * are only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of + * messages for methods that are repeatedly evaluated. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedBiosError ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...) +{ + va_list ArgList; + + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (NodeFlags & ANOBJ_EVALUATED) + { + return; + } + + AcpiOsPrintf (ACPI_MSG_BIOS_ERROR "%s: ", Pathname); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtNamespaceError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * InternalName - Name or path of the namespace node + * LookupStatus - Exception code from NS lookup + * + * RETURN: None + * + * DESCRIPTION: Print error message with the full pathname for the NS node. + * + ******************************************************************************/ + +void +AcpiUtNamespaceError ( + const char *ModuleName, + UINT32 LineNumber, + const char *InternalName, + ACPI_STATUS LookupStatus) +{ + ACPI_STATUS Status; + UINT32 BadName; + char *Name = NULL; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_ERROR); + + if (LookupStatus == AE_BAD_CHARACTER) + { + /* There is a non-ascii character in the name */ + + ACPI_MOVE_32_TO_32 (&BadName, ACPI_CAST_PTR (UINT32, InternalName)); + AcpiOsPrintf ("[0x%.8X] (NON-ASCII)", BadName); + } + else + { + /* Convert path to external format */ + + Status = AcpiNsExternalizeName ( + ACPI_UINT32_MAX, InternalName, NULL, &Name); + + /* Print target name */ + + if (ACPI_SUCCESS (Status)) + { + AcpiOsPrintf ("[%s]", Name); + } + else + { + AcpiOsPrintf ("[COULD NOT EXTERNALIZE NAME]"); + } + + if (Name) + { + ACPI_FREE (Name); + } + } + + AcpiOsPrintf (" Namespace lookup failure, %s", + AcpiFormatException (LookupStatus)); + + ACPI_MSG_SUFFIX; + ACPI_MSG_REDIRECT_END; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtMethodError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Message - Error message to use on failure + * PrefixNode - Prefix relative to the path + * Path - Path to the node (optional) + * MethodStatus - Execution status + * + * RETURN: None + * + * DESCRIPTION: Print error message with the full pathname for the method. + * + ******************************************************************************/ + +void +AcpiUtMethodError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Message, + ACPI_NAMESPACE_NODE *PrefixNode, + const char *Path, + ACPI_STATUS MethodStatus) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node = PrefixNode; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_ERROR); + + if (Path) + { + Status = AcpiNsGetNode (PrefixNode, Path, + ACPI_NS_NO_UPSEARCH, &Node); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("[Could not get node by pathname]"); + } + } + + AcpiNsPrintNodePathname (Node, Message); + AcpiOsPrintf (", %s", AcpiFormatException (MethodStatus)); + + ACPI_MSG_SUFFIX; + ACPI_MSG_REDIRECT_END; +} + +#endif /* ACPI_NO_ERROR_MESSAGES */ diff --git a/third_party/lib/acpica/source/components/utilities/uteval.c b/third_party/lib/acpica/source/components/utilities/uteval.c new file mode 100644 index 000000000..bdde51388 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/uteval.c @@ -0,0 +1,379 @@ +/****************************************************************************** + * + * Module Name: uteval - Object evaluation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("uteval") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtEvaluateObject + * + * PARAMETERS: PrefixNode - Starting node + * Path - Path to object from starting node + * ExpectedReturnTypes - Bitmap of allowed return types + * ReturnDesc - Where a return value is stored + * + * RETURN: Status + * + * DESCRIPTION: Evaluates a namespace object and verifies the type of the + * return object. Common code that simplifies accessing objects + * that have required return objects of fixed types. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtEvaluateObject ( + ACPI_NAMESPACE_NODE *PrefixNode, + char *Path, + UINT32 ExpectedReturnBtypes, + ACPI_OPERAND_OBJECT **ReturnDesc) +{ + ACPI_EVALUATE_INFO *Info; + ACPI_STATUS Status; + UINT32 ReturnBtype; + + + ACPI_FUNCTION_TRACE (UtEvaluateObject); + + + /* Allocate the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Info->PrefixNode = PrefixNode; + Info->RelativePathname = Path; + + /* Evaluate the object/method */ + + Status = AcpiNsEvaluate (Info); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NOT_FOUND) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", + AcpiUtGetNodeName (PrefixNode), Path)); + } + else + { + ACPI_ERROR_METHOD ("Method execution failed", + PrefixNode, Path, Status); + } + + goto Cleanup; + } + + /* Did we get a return object? */ + + if (!Info->ReturnObject) + { + if (ExpectedReturnBtypes) + { + ACPI_ERROR_METHOD ("No object was returned from", + PrefixNode, Path, AE_NOT_EXIST); + + Status = AE_NOT_EXIST; + } + + goto Cleanup; + } + + /* Map the return object type to the bitmapped type */ + + switch ((Info->ReturnObject)->Common.Type) + { + case ACPI_TYPE_INTEGER: + + ReturnBtype = ACPI_BTYPE_INTEGER; + break; + + case ACPI_TYPE_BUFFER: + + ReturnBtype = ACPI_BTYPE_BUFFER; + break; + + case ACPI_TYPE_STRING: + + ReturnBtype = ACPI_BTYPE_STRING; + break; + + case ACPI_TYPE_PACKAGE: + + ReturnBtype = ACPI_BTYPE_PACKAGE; + break; + + default: + + ReturnBtype = 0; + break; + } + + if ((AcpiGbl_EnableInterpreterSlack) && + (!ExpectedReturnBtypes)) + { + /* + * We received a return object, but one was not expected. This can + * happen frequently if the "implicit return" feature is enabled. + * Just delete the return object and return AE_OK. + */ + AcpiUtRemoveReference (Info->ReturnObject); + goto Cleanup; + } + + /* Is the return object one of the expected types? */ + + if (!(ExpectedReturnBtypes & ReturnBtype)) + { + ACPI_ERROR_METHOD ("Return object type is incorrect", + PrefixNode, Path, AE_TYPE); + + ACPI_ERROR ((AE_INFO, + "Type returned from %s was incorrect: %s, expected Btypes: 0x%X", + Path, AcpiUtGetObjectTypeName (Info->ReturnObject), + ExpectedReturnBtypes)); + + /* On error exit, we must delete the return object */ + + AcpiUtRemoveReference (Info->ReturnObject); + Status = AE_TYPE; + goto Cleanup; + } + + /* Object type is OK, return it */ + + *ReturnDesc = Info->ReturnObject; + +Cleanup: + ACPI_FREE (Info); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtEvaluateNumericObject + * + * PARAMETERS: ObjectName - Object name to be evaluated + * DeviceNode - Node for the device + * Value - Where the value is returned + * + * RETURN: Status + * + * DESCRIPTION: Evaluates a numeric namespace object for a selected device + * and stores result in *Value. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtEvaluateNumericObject ( + char *ObjectName, + ACPI_NAMESPACE_NODE *DeviceNode, + UINT64 *Value) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtEvaluateNumericObject); + + + Status = AcpiUtEvaluateObject (DeviceNode, ObjectName, + ACPI_BTYPE_INTEGER, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get the returned Integer */ + + *Value = ObjDesc->Integer.Value; + + /* On exit, we must delete the return object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExecute_STA + * + * PARAMETERS: DeviceNode - Node for the device + * Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. If _STA does not exist, then the device is assumed + * to be present/functional/enabled (as per the ACPI spec). + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtExecute_STA ( + ACPI_NAMESPACE_NODE *DeviceNode, + UINT32 *Flags) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtExecute_STA); + + + Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__STA, + ACPI_BTYPE_INTEGER, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + if (AE_NOT_FOUND == Status) + { + /* + * if _STA does not exist, then (as per the ACPI specification), + * the returned flags will indicate that the device is present, + * functional, and enabled. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "_STA on %4.4s was not found, assuming device is present\n", + AcpiUtGetNodeName (DeviceNode))); + + *Flags = ACPI_UINT32_MAX; + Status = AE_OK; + } + + return_ACPI_STATUS (Status); + } + + /* Extract the status flags */ + + *Flags = (UINT32) ObjDesc->Integer.Value; + + /* On exit, we must delete the return object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExecutePowerMethods + * + * PARAMETERS: DeviceNode - Node for the device + * MethodNames - Array of power method names + * MethodCount - Number of methods to execute + * OutValues - Where the power method values are returned + * + * RETURN: Status, OutValues + * + * DESCRIPTION: Executes the specified power methods for the device and returns + * the result(s). + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtExecutePowerMethods ( + ACPI_NAMESPACE_NODE *DeviceNode, + const char **MethodNames, + UINT8 MethodCount, + UINT8 *OutValues) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + ACPI_STATUS FinalStatus = AE_NOT_FOUND; + UINT32 i; + + + ACPI_FUNCTION_TRACE (UtExecutePowerMethods); + + + for (i = 0; i < MethodCount; i++) + { + /* + * Execute the power method (_SxD or _SxW). The only allowable + * return type is an Integer. + */ + Status = AcpiUtEvaluateObject (DeviceNode, + ACPI_CAST_PTR (char, MethodNames[i]), + ACPI_BTYPE_INTEGER, &ObjDesc); + if (ACPI_SUCCESS (Status)) + { + OutValues[i] = (UINT8) ObjDesc->Integer.Value; + + /* Delete the return object */ + + AcpiUtRemoveReference (ObjDesc); + FinalStatus = AE_OK; /* At least one value is valid */ + continue; + } + + OutValues[i] = ACPI_UINT8_MAX; + if (Status == AE_NOT_FOUND) + { + continue; /* Ignore if not found */ + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Failed %s on Device %4.4s, %s\n", + ACPI_CAST_PTR (char, MethodNames[i]), + AcpiUtGetNodeName (DeviceNode), AcpiFormatException (Status))); + } + + return_ACPI_STATUS (FinalStatus); +} diff --git a/third_party/lib/acpica/source/components/utilities/utexcep.c b/third_party/lib/acpica/source/components/utilities/utexcep.c new file mode 100644 index 000000000..5be8efd5f --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utexcep.c @@ -0,0 +1,179 @@ +/******************************************************************************* + * + * Module Name: utexcep - Exception code support + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#define ACPI_DEFINE_EXCEPTION_TABLE +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utexcep") + + +/******************************************************************************* + * + * FUNCTION: AcpiFormatException + * + * PARAMETERS: Status - The ACPI_STATUS code to be formatted + * + * RETURN: A string containing the exception text. A valid pointer is + * always returned. + * + * DESCRIPTION: This function translates an ACPI exception into an ASCII + * string. Returns "unknown status" string for invalid codes. + * + ******************************************************************************/ + +const char * +AcpiFormatException ( + ACPI_STATUS Status) +{ + const ACPI_EXCEPTION_INFO *Exception; + + + ACPI_FUNCTION_ENTRY (); + + + Exception = AcpiUtValidateException (Status); + if (!Exception) + { + /* Exception code was not recognized */ + + ACPI_ERROR ((AE_INFO, + "Unknown exception code: 0x%8.8X", Status)); + + return ("UNKNOWN_STATUS_CODE"); + } + + return (Exception->Name); +} + +ACPI_EXPORT_SYMBOL (AcpiFormatException) + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidateException + * + * PARAMETERS: Status - The ACPI_STATUS code to be formatted + * + * RETURN: A string containing the exception text. NULL if exception is + * not valid. + * + * DESCRIPTION: This function validates and translates an ACPI exception into + * an ASCII string. + * + ******************************************************************************/ + +const ACPI_EXCEPTION_INFO * +AcpiUtValidateException ( + ACPI_STATUS Status) +{ + UINT32 SubStatus; + const ACPI_EXCEPTION_INFO *Exception = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * Status is composed of two parts, a "type" and an actual code + */ + SubStatus = (Status & ~AE_CODE_MASK); + + switch (Status & AE_CODE_MASK) + { + case AE_CODE_ENVIRONMENTAL: + + if (SubStatus <= AE_CODE_ENV_MAX) + { + Exception = &AcpiGbl_ExceptionNames_Env [SubStatus]; + } + break; + + case AE_CODE_PROGRAMMER: + + if (SubStatus <= AE_CODE_PGM_MAX) + { + Exception = &AcpiGbl_ExceptionNames_Pgm [SubStatus]; + } + break; + + case AE_CODE_ACPI_TABLES: + + if (SubStatus <= AE_CODE_TBL_MAX) + { + Exception = &AcpiGbl_ExceptionNames_Tbl [SubStatus]; + } + break; + + case AE_CODE_AML: + + if (SubStatus <= AE_CODE_AML_MAX) + { + Exception = &AcpiGbl_ExceptionNames_Aml [SubStatus]; + } + break; + + case AE_CODE_CONTROL: + + if (SubStatus <= AE_CODE_CTRL_MAX) + { + Exception = &AcpiGbl_ExceptionNames_Ctrl [SubStatus]; + } + break; + + default: + + break; + } + + if (!Exception || !Exception->Name) + { + return (NULL); + } + + return (Exception); +} diff --git a/third_party/lib/acpica/source/components/utilities/utglobal.c b/third_party/lib/acpica/source/components/utilities/utglobal.c new file mode 100644 index 000000000..ed3a171ee --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utglobal.c @@ -0,0 +1,188 @@ +/****************************************************************************** + * + * Module Name: utglobal - Global variables for the ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES +#define DEFINE_ACPI_GLOBALS + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utglobal") + + +/******************************************************************************* + * + * Static global variable initialization. + * + ******************************************************************************/ + +/* Various state name strings */ + +const char *AcpiGbl_SleepStateNames[ACPI_S_STATE_COUNT] = +{ + "\\_S0_", + "\\_S1_", + "\\_S2_", + "\\_S3_", + "\\_S4_", + "\\_S5_" +}; + +const char *AcpiGbl_LowestDstateNames[ACPI_NUM_SxW_METHODS] = +{ + "_S0W", + "_S1W", + "_S2W", + "_S3W", + "_S4W" +}; + +const char *AcpiGbl_HighestDstateNames[ACPI_NUM_SxD_METHODS] = +{ + "_S1D", + "_S2D", + "_S3D", + "_S4D" +}; + + +/******************************************************************************* + * + * Namespace globals + * + ******************************************************************************/ + +/* + * Predefined ACPI Names (Built-in to the Interpreter) + * + * NOTES: + * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run + * during the initialization sequence. + * 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to + * perform a Notify() operation on it. 09/2010: Changed to type Device. + * This still allows notifies, but does not confuse host code that + * searches for valid ThermalZone objects. + */ +const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames[] = +{ + {"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_SB_", ACPI_TYPE_DEVICE, NULL}, + {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_TZ_", ACPI_TYPE_DEVICE, NULL}, + /* + * March, 2015: + * The _REV object is in the process of being deprecated, because + * other ACPI implementations permanently return 2. Thus, it + * has little or no value. Return 2 for compatibility with + * other ACPI implementations. + */ + {"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR (char, 2)}, + {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, + {"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR (char, 1)}, + +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) + {"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR (char, 1)}, +#endif + + /* Table terminator */ + + {NULL, ACPI_TYPE_ANY, NULL} +}; + + +#if (!ACPI_REDUCED_HARDWARE) +/****************************************************************************** + * + * Event and Hardware globals + * + ******************************************************************************/ + +ACPI_BIT_REGISTER_INFO AcpiGbl_BitRegisterInfo[ACPI_NUM_BITREG] = +{ + /* Name Parent Register Register Bit Position Register Bit Mask */ + + /* ACPI_BITREG_TIMER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_TIMER_STATUS, ACPI_BITMASK_TIMER_STATUS}, + /* ACPI_BITREG_BUS_MASTER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_BUS_MASTER_STATUS, ACPI_BITMASK_BUS_MASTER_STATUS}, + /* ACPI_BITREG_GLOBAL_LOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_STATUS}, + /* ACPI_BITREG_POWER_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_STATUS}, + /* ACPI_BITREG_SLEEP_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_STATUS}, + /* ACPI_BITREG_RT_CLOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_STATUS}, + /* ACPI_BITREG_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_WAKE_STATUS, ACPI_BITMASK_WAKE_STATUS}, + /* ACPI_BITREG_PCIEXP_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_PCIEXP_WAKE_STATUS, ACPI_BITMASK_PCIEXP_WAKE_STATUS}, + + /* ACPI_BITREG_TIMER_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_TIMER_ENABLE, ACPI_BITMASK_TIMER_ENABLE}, + /* ACPI_BITREG_GLOBAL_LOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, + /* ACPI_BITREG_POWER_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_ENABLE}, + /* ACPI_BITREG_SLEEP_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, + /* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_ENABLE}, + /* ACPI_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE, ACPI_BITMASK_PCIEXP_WAKE_DISABLE}, + + /* ACPI_BITREG_SCI_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SCI_ENABLE, ACPI_BITMASK_SCI_ENABLE}, + /* ACPI_BITREG_BUS_MASTER_RLD */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_BUS_MASTER_RLD, ACPI_BITMASK_BUS_MASTER_RLD}, + /* ACPI_BITREG_GLOBAL_LOCK_RELEASE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE, ACPI_BITMASK_GLOBAL_LOCK_RELEASE}, + /* ACPI_BITREG_SLEEP_TYPE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE, ACPI_BITMASK_SLEEP_TYPE}, + /* ACPI_BITREG_SLEEP_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_ENABLE, ACPI_BITMASK_SLEEP_ENABLE}, + + /* ACPI_BITREG_ARB_DIS */ {ACPI_REGISTER_PM2_CONTROL, ACPI_BITPOSITION_ARB_DISABLE, ACPI_BITMASK_ARB_DISABLE} +}; + + +ACPI_FIXED_EVENT_INFO AcpiGbl_FixedEventInfo[ACPI_NUM_FIXED_EVENTS] = +{ + /* ACPI_EVENT_PMTIMER */ {ACPI_BITREG_TIMER_STATUS, ACPI_BITREG_TIMER_ENABLE, ACPI_BITMASK_TIMER_STATUS, ACPI_BITMASK_TIMER_ENABLE}, + /* ACPI_EVENT_GLOBAL */ {ACPI_BITREG_GLOBAL_LOCK_STATUS, ACPI_BITREG_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, + /* ACPI_EVENT_POWER_BUTTON */ {ACPI_BITREG_POWER_BUTTON_STATUS, ACPI_BITREG_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_ENABLE}, + /* ACPI_EVENT_SLEEP_BUTTON */ {ACPI_BITREG_SLEEP_BUTTON_STATUS, ACPI_BITREG_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, + /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE}, +}; +#endif /* !ACPI_REDUCED_HARDWARE */ + +/* Public globals */ + +ACPI_EXPORT_SYMBOL (AcpiGbl_FADT) +ACPI_EXPORT_SYMBOL (AcpiDbgLevel) +ACPI_EXPORT_SYMBOL (AcpiDbgLayer) +ACPI_EXPORT_SYMBOL (AcpiGpeCount) +ACPI_EXPORT_SYMBOL (AcpiCurrentGpeCount) diff --git a/third_party/lib/acpica/source/components/utilities/uthex.c b/third_party/lib/acpica/source/components/utilities/uthex.c new file mode 100644 index 000000000..b93013b20 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/uthex.c @@ -0,0 +1,111 @@ +/****************************************************************************** + * + * Module Name: uthex -- Hex/ASCII support functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("uthex") + + +/* Hex to ASCII conversion table */ + +static const char AcpiGbl_HexToAscii[] = +{ + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtHexToAsciiChar + * + * PARAMETERS: Integer - Contains the hex digit + * Position - bit position of the digit within the + * integer (multiple of 4) + * + * RETURN: The converted Ascii character + * + * DESCRIPTION: Convert a hex digit to an Ascii character + * + ******************************************************************************/ + +char +AcpiUtHexToAsciiChar ( + UINT64 Integer, + UINT32 Position) +{ + + return (AcpiGbl_HexToAscii[(Integer >> Position) & 0xF]); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAsciiCharToHex + * + * PARAMETERS: HexChar - Hex character in Ascii + * + * RETURN: The binary value of the ascii/hex character + * + * DESCRIPTION: Perform ascii-to-hex translation + * + ******************************************************************************/ + +UINT8 +AcpiUtAsciiCharToHex ( + int HexChar) +{ + + if (HexChar <= 0x39) + { + return ((UINT8) (HexChar - 0x30)); + } + + if (HexChar <= 0x46) + { + return ((UINT8) (HexChar - 0x37)); + } + + return ((UINT8) (HexChar - 0x57)); +} diff --git a/third_party/lib/acpica/source/components/utilities/utids.c b/third_party/lib/acpica/source/components/utilities/utids.c new file mode 100644 index 000000000..7182a91ae --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utids.c @@ -0,0 +1,478 @@ +/****************************************************************************** + * + * Module Name: utids - support for device IDs - HID, UID, CID, SUB, CLS + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acinterp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utids") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExecute_HID + * + * PARAMETERS: DeviceNode - Node for the device + * ReturnId - Where the string HID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _HID control method that returns the hardware + * ID of the device. The HID is either an 32-bit encoded EISAID + * Integer or a String. A string is always returned. An EISAID + * is converted to a string. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtExecute_HID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PNP_DEVICE_ID *Hid; + UINT32 Length; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtExecute_HID); + + + Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__HID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) + { + Length = ACPI_EISAID_STRING_SIZE; + } + else + { + Length = ObjDesc->String.Length + 1; + } + + /* Allocate a buffer for the HID */ + + Hid = ACPI_ALLOCATE_ZEROED ( + sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length); + if (!Hid) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Area for the string starts after PNP_DEVICE_ID struct */ + + Hid->String = ACPI_ADD_PTR (char, Hid, sizeof (ACPI_PNP_DEVICE_ID)); + + /* Convert EISAID to a string or simply copy existing string */ + + if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) + { + AcpiExEisaIdToString (Hid->String, ObjDesc->Integer.Value); + } + else + { + strcpy (Hid->String, ObjDesc->String.Pointer); + } + + Hid->Length = Length; + *ReturnId = Hid; + + +Cleanup: + + /* On exit, we must delete the return object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExecute_UID + * + * PARAMETERS: DeviceNode - Node for the device + * ReturnId - Where the string UID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _UID control method that returns the unique + * ID of the device. The UID is either a 64-bit Integer (NOT an + * EISAID) or a string. Always returns a string. A 64-bit integer + * is converted to a decimal string. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtExecute_UID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PNP_DEVICE_ID *Uid; + UINT32 Length; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtExecute_UID); + + + Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__UID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) + { + Length = ACPI_MAX64_DECIMAL_DIGITS + 1; + } + else + { + Length = ObjDesc->String.Length + 1; + } + + /* Allocate a buffer for the UID */ + + Uid = ACPI_ALLOCATE_ZEROED ( + sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length); + if (!Uid) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Area for the string starts after PNP_DEVICE_ID struct */ + + Uid->String = ACPI_ADD_PTR (char, Uid, sizeof (ACPI_PNP_DEVICE_ID)); + + /* Convert an Integer to string, or just copy an existing string */ + + if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) + { + AcpiExIntegerToString (Uid->String, ObjDesc->Integer.Value); + } + else + { + strcpy (Uid->String, ObjDesc->String.Pointer); + } + + Uid->Length = Length; + *ReturnId = Uid; + + +Cleanup: + + /* On exit, we must delete the return object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExecute_CID + * + * PARAMETERS: DeviceNode - Node for the device + * ReturnCidList - Where the CID list is returned + * + * RETURN: Status, list of CID strings + * + * DESCRIPTION: Executes the _CID control method that returns one or more + * compatible hardware IDs for the device. + * + * NOTE: Internal function, no parameter validation + * + * A _CID method can return either a single compatible ID or a package of + * compatible IDs. Each compatible ID can be one of the following: + * 1) Integer (32 bit compressed EISA ID) or + * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") + * + * The Integer CIDs are converted to string format by this function. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtExecute_CID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID_LIST **ReturnCidList) +{ + ACPI_OPERAND_OBJECT **CidObjects; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_PNP_DEVICE_ID_LIST *CidList; + char *NextIdString; + UINT32 StringAreaSize; + UINT32 Length; + UINT32 CidListSize; + ACPI_STATUS Status; + UINT32 Count; + UINT32 i; + + + ACPI_FUNCTION_TRACE (UtExecute_CID); + + + /* Evaluate the _CID method for this device */ + + Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__CID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_PACKAGE, + &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Get the count and size of the returned _CIDs. _CID can return either + * a Package of Integers/Strings or a single Integer or String. + * Note: This section also validates that all CID elements are of the + * correct type (Integer or String). + */ + if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE) + { + Count = ObjDesc->Package.Count; + CidObjects = ObjDesc->Package.Elements; + } + else /* Single Integer or String CID */ + { + Count = 1; + CidObjects = &ObjDesc; + } + + StringAreaSize = 0; + for (i = 0; i < Count; i++) + { + /* String lengths include null terminator */ + + switch (CidObjects[i]->Common.Type) + { + case ACPI_TYPE_INTEGER: + + StringAreaSize += ACPI_EISAID_STRING_SIZE; + break; + + case ACPI_TYPE_STRING: + + StringAreaSize += CidObjects[i]->String.Length + 1; + break; + + default: + + Status = AE_TYPE; + goto Cleanup; + } + } + + /* + * Now that we know the length of the CIDs, allocate return buffer: + * 1) Size of the base structure + + * 2) Size of the CID PNP_DEVICE_ID array + + * 3) Size of the actual CID strings + */ + CidListSize = sizeof (ACPI_PNP_DEVICE_ID_LIST) + + ((Count - 1) * sizeof (ACPI_PNP_DEVICE_ID)) + + StringAreaSize; + + CidList = ACPI_ALLOCATE_ZEROED (CidListSize); + if (!CidList) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Area for CID strings starts after the CID PNP_DEVICE_ID array */ + + NextIdString = ACPI_CAST_PTR (char, CidList->Ids) + + ((ACPI_SIZE) Count * sizeof (ACPI_PNP_DEVICE_ID)); + + /* Copy/convert the CIDs to the return buffer */ + + for (i = 0; i < Count; i++) + { + if (CidObjects[i]->Common.Type == ACPI_TYPE_INTEGER) + { + /* Convert the Integer (EISAID) CID to a string */ + + AcpiExEisaIdToString ( + NextIdString, CidObjects[i]->Integer.Value); + Length = ACPI_EISAID_STRING_SIZE; + } + else /* ACPI_TYPE_STRING */ + { + /* Copy the String CID from the returned object */ + + strcpy (NextIdString, CidObjects[i]->String.Pointer); + Length = CidObjects[i]->String.Length + 1; + } + + CidList->Ids[i].String = NextIdString; + CidList->Ids[i].Length = Length; + NextIdString += Length; + } + + /* Finish the CID list */ + + CidList->Count = Count; + CidList->ListSize = CidListSize; + *ReturnCidList = CidList; + + +Cleanup: + + /* On exit, we must delete the _CID return object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtExecute_CLS + * + * PARAMETERS: DeviceNode - Node for the device + * ReturnId - Where the _CLS is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _CLS control method that returns PCI-defined + * class code of the device. The _CLS value is always a package + * containing PCI class information as a list of integers. + * The returned string has format "BBSSPP", where: + * BB = Base-class code + * SS = Sub-class code + * PP = Programming Interface code + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtExecute_CLS ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_OPERAND_OBJECT **ClsObjects; + UINT32 Count; + ACPI_PNP_DEVICE_ID *Cls; + UINT32 Length; + ACPI_STATUS Status; + UINT8 ClassCode[3] = {0, 0, 0}; + + + ACPI_FUNCTION_TRACE (UtExecute_CLS); + + + Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__CLS, + ACPI_BTYPE_PACKAGE, &ObjDesc); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + Length = ACPI_PCICLS_STRING_SIZE; + ClsObjects = ObjDesc->Package.Elements; + Count = ObjDesc->Package.Count; + + if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE) + { + if (Count > 0 && ClsObjects[0]->Common.Type == ACPI_TYPE_INTEGER) + { + ClassCode[0] = (UINT8) ClsObjects[0]->Integer.Value; + } + if (Count > 1 && ClsObjects[1]->Common.Type == ACPI_TYPE_INTEGER) + { + ClassCode[1] = (UINT8) ClsObjects[1]->Integer.Value; + } + if (Count > 2 && ClsObjects[2]->Common.Type == ACPI_TYPE_INTEGER) + { + ClassCode[2] = (UINT8) ClsObjects[2]->Integer.Value; + } + } + + /* Allocate a buffer for the CLS */ + + Cls = ACPI_ALLOCATE_ZEROED ( + sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length); + if (!Cls) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Area for the string starts after PNP_DEVICE_ID struct */ + + Cls->String = ACPI_ADD_PTR (char, Cls, sizeof (ACPI_PNP_DEVICE_ID)); + + /* Simply copy existing string */ + + AcpiExPciClsToString (Cls->String, ClassCode); + Cls->Length = Length; + *ReturnId = Cls; + + +Cleanup: + + /* On exit, we must delete the return object */ + + AcpiUtRemoveReference (ObjDesc); + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/utilities/utinit.c b/third_party/lib/acpica/source/components/utilities/utinit.c new file mode 100644 index 000000000..03c3e510b --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utinit.c @@ -0,0 +1,353 @@ +/****************************************************************************** + * + * Module Name: utinit - Common ACPI subsystem initialization + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utinit") + +/* Local prototypes */ + +static void AcpiUtTerminate ( + void); + +#if (!ACPI_REDUCED_HARDWARE) + +static void +AcpiUtFreeGpeLists ( + void); + +#else + +#define AcpiUtFreeGpeLists() +#endif /* !ACPI_REDUCED_HARDWARE */ + + +#if (!ACPI_REDUCED_HARDWARE) +/****************************************************************************** + * + * FUNCTION: AcpiUtFreeGpeLists + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Free global GPE lists + * + ******************************************************************************/ + +static void +AcpiUtFreeGpeLists ( + void) +{ + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_GPE_BLOCK_INFO *NextGpeBlock; + ACPI_GPE_XRUPT_INFO *GpeXruptInfo; + ACPI_GPE_XRUPT_INFO *NextGpeXruptInfo; + + + /* Free global GPE blocks and related info structures */ + + GpeXruptInfo = AcpiGbl_GpeXruptListHead; + while (GpeXruptInfo) + { + GpeBlock = GpeXruptInfo->GpeBlockListHead; + while (GpeBlock) + { + NextGpeBlock = GpeBlock->Next; + ACPI_FREE (GpeBlock->EventInfo); + ACPI_FREE (GpeBlock->RegisterInfo); + ACPI_FREE (GpeBlock); + + GpeBlock = NextGpeBlock; + } + NextGpeXruptInfo = GpeXruptInfo->Next; + ACPI_FREE (GpeXruptInfo); + GpeXruptInfo = NextGpeXruptInfo; + } +} +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiUtInitGlobals + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize ACPICA globals. All globals that require specific + * initialization should be initialized here. This allows for + * a warm restart. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtInitGlobals ( + void) +{ + ACPI_STATUS Status; + UINT32 i; + + + ACPI_FUNCTION_TRACE (UtInitGlobals); + + + /* Create all memory caches */ + + Status = AcpiUtCreateCaches (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Address Range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) + { + AcpiGbl_AddressRangeList[i] = NULL; + } + + /* Mutex locked flags */ + + for (i = 0; i < ACPI_NUM_MUTEX; i++) + { + AcpiGbl_MutexInfo[i].Mutex = NULL; + AcpiGbl_MutexInfo[i].ThreadId = ACPI_MUTEX_NOT_ACQUIRED; + AcpiGbl_MutexInfo[i].UseCount = 0; + } + + for (i = 0; i < ACPI_NUM_OWNERID_MASKS; i++) + { + AcpiGbl_OwnerIdMask[i] = 0; + } + + /* Last OwnerID is never valid */ + + AcpiGbl_OwnerIdMask[ACPI_NUM_OWNERID_MASKS - 1] = 0x80000000; + + /* Event counters */ + + AcpiMethodCount = 0; + AcpiSciCount = 0; + AcpiGpeCount = 0; + + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) + { + AcpiFixedEventCount[i] = 0; + } + +#if (!ACPI_REDUCED_HARDWARE) + + /* GPE/SCI support */ + + AcpiGbl_AllGpesInitialized = FALSE; + AcpiGbl_GpeXruptListHead = NULL; + AcpiGbl_GpeFadtBlocks[0] = NULL; + AcpiGbl_GpeFadtBlocks[1] = NULL; + AcpiCurrentGpeCount = 0; + + AcpiGbl_GlobalEventHandler = NULL; + AcpiGbl_SciHandlerList = NULL; + +#endif /* !ACPI_REDUCED_HARDWARE */ + + /* Global handlers */ + + AcpiGbl_GlobalNotify[0].Handler = NULL; + AcpiGbl_GlobalNotify[1].Handler = NULL; + AcpiGbl_ExceptionHandler = NULL; + AcpiGbl_InitHandler = NULL; + AcpiGbl_TableHandler = NULL; + AcpiGbl_InterfaceHandler = NULL; + + /* Global Lock support */ + + AcpiGbl_GlobalLockSemaphore = NULL; + AcpiGbl_GlobalLockMutex = NULL; + AcpiGbl_GlobalLockAcquired = FALSE; + AcpiGbl_GlobalLockHandle = 0; + AcpiGbl_GlobalLockPresent = FALSE; + + /* Miscellaneous variables */ + + AcpiGbl_DSDT = NULL; + AcpiGbl_CmSingleStep = FALSE; + AcpiGbl_Shutdown = FALSE; + AcpiGbl_NsLookupCount = 0; + AcpiGbl_PsFindCount = 0; + AcpiGbl_AcpiHardwarePresent = TRUE; + AcpiGbl_LastOwnerIdIndex = 0; + AcpiGbl_NextOwnerIdOffset = 0; + AcpiGbl_DebuggerConfiguration = DEBUGGER_THREADING; + AcpiGbl_OsiMutex = NULL; + AcpiGbl_MaxLoopIterations = 0xFFFF; + + /* Hardware oriented */ + + AcpiGbl_EventsInitialized = FALSE; + AcpiGbl_SystemAwakeAndRunning = TRUE; + + /* Namespace */ + + AcpiGbl_ModuleCodeList = NULL; + AcpiGbl_RootNode = NULL; + AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME; + AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED; + AcpiGbl_RootNodeStruct.Type = ACPI_TYPE_DEVICE; + AcpiGbl_RootNodeStruct.Parent = NULL; + AcpiGbl_RootNodeStruct.Child = NULL; + AcpiGbl_RootNodeStruct.Peer = NULL; + AcpiGbl_RootNodeStruct.Object = NULL; + + +#ifdef ACPI_DISASSEMBLER + AcpiGbl_ExternalList = NULL; + AcpiGbl_NumExternalMethods = 0; + AcpiGbl_ResolvedExternalMethods = 0; +#endif + +#ifdef ACPI_DEBUG_OUTPUT + AcpiGbl_LowestStackPointer = ACPI_CAST_PTR (ACPI_SIZE, ACPI_SIZE_MAX); +#endif + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + AcpiGbl_DisplayFinalMemStats = FALSE; + AcpiGbl_DisableMemTracking = FALSE; +#endif + + return_ACPI_STATUS (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiUtTerminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Free global memory + * + ******************************************************************************/ + +static void +AcpiUtTerminate ( + void) +{ + ACPI_FUNCTION_TRACE (UtTerminate); + + AcpiUtFreeGpeLists (); + AcpiUtDeleteAddressLists (); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtSubsystemShutdown + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Shutdown the various components. Do not delete the mutex + * objects here, because the AML debugger may be still running. + * + ******************************************************************************/ + +void +AcpiUtSubsystemShutdown ( + void) +{ + ACPI_FUNCTION_TRACE (UtSubsystemShutdown); + + + /* Just exit if subsystem is already shutdown */ + + if (AcpiGbl_Shutdown) + { + ACPI_ERROR ((AE_INFO, "ACPI Subsystem is already terminated")); + return_VOID; + } + + /* Subsystem appears active, go ahead and shut it down */ + + AcpiGbl_Shutdown = TRUE; + AcpiGbl_StartupFlags = 0; + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); + +#ifndef ACPI_ASL_COMPILER + + /* Close the AcpiEvent Handling */ + + AcpiEvTerminate (); + + /* Delete any dynamic _OSI interfaces */ + + AcpiUtInterfaceTerminate (); +#endif + + /* Close the Namespace */ + + AcpiNsTerminate (); + + /* Delete the ACPI tables */ + + AcpiTbTerminate (); + + /* Close the globals */ + + AcpiUtTerminate (); + + /* Purge the local caches */ + + (void) AcpiUtDeleteCaches (); + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/utilities/utlock.c b/third_party/lib/acpica/source/components/utilities/utlock.c new file mode 100644 index 000000000..c62a37d9f --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utlock.c @@ -0,0 +1,202 @@ +/****************************************************************************** + * + * Module Name: utlock - Reader/Writer lock interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utlock") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateRwLock + * AcpiUtDeleteRwLock + * + * PARAMETERS: Lock - Pointer to a valid RW lock + * + * RETURN: Status + * + * DESCRIPTION: Reader/writer lock creation and deletion interfaces. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCreateRwLock ( + ACPI_RW_LOCK *Lock) +{ + ACPI_STATUS Status; + + + Lock->NumReaders = 0; + Status = AcpiOsCreateMutex (&Lock->ReaderMutex); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiOsCreateMutex (&Lock->WriterMutex); + return (Status); +} + + +void +AcpiUtDeleteRwLock ( + ACPI_RW_LOCK *Lock) +{ + + AcpiOsDeleteMutex (Lock->ReaderMutex); + AcpiOsDeleteMutex (Lock->WriterMutex); + + Lock->NumReaders = 0; + Lock->ReaderMutex = NULL; + Lock->WriterMutex = NULL; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAcquireReadLock + * AcpiUtReleaseReadLock + * + * PARAMETERS: Lock - Pointer to a valid RW lock + * + * RETURN: Status + * + * DESCRIPTION: Reader interfaces for reader/writer locks. On acquisition, + * only the first reader acquires the write mutex. On release, + * only the last reader releases the write mutex. Although this + * algorithm can in theory starve writers, this should not be a + * problem with ACPICA since the subsystem is infrequently used + * in comparison to (for example) an I/O system. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtAcquireReadLock ( + ACPI_RW_LOCK *Lock) +{ + ACPI_STATUS Status; + + + Status = AcpiOsAcquireMutex (Lock->ReaderMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Acquire the write lock only for the first reader */ + + Lock->NumReaders++; + if (Lock->NumReaders == 1) + { + Status = AcpiOsAcquireMutex (Lock->WriterMutex, ACPI_WAIT_FOREVER); + } + + AcpiOsReleaseMutex (Lock->ReaderMutex); + return (Status); +} + + +ACPI_STATUS +AcpiUtReleaseReadLock ( + ACPI_RW_LOCK *Lock) +{ + ACPI_STATUS Status; + + + Status = AcpiOsAcquireMutex (Lock->ReaderMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Release the write lock only for the very last reader */ + + Lock->NumReaders--; + if (Lock->NumReaders == 0) + { + AcpiOsReleaseMutex (Lock->WriterMutex); + } + + AcpiOsReleaseMutex (Lock->ReaderMutex); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAcquireWriteLock + * AcpiUtReleaseWriteLock + * + * PARAMETERS: Lock - Pointer to a valid RW lock + * + * RETURN: Status + * + * DESCRIPTION: Writer interfaces for reader/writer locks. Simply acquire or + * release the writer mutex associated with the lock. Acquisition + * of the lock is fully exclusive and will block all readers and + * writers until it is released. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtAcquireWriteLock ( + ACPI_RW_LOCK *Lock) +{ + ACPI_STATUS Status; + + + Status = AcpiOsAcquireMutex (Lock->WriterMutex, ACPI_WAIT_FOREVER); + return (Status); +} + + +void +AcpiUtReleaseWriteLock ( + ACPI_RW_LOCK *Lock) +{ + + AcpiOsReleaseMutex (Lock->WriterMutex); +} diff --git a/third_party/lib/acpica/source/components/utilities/utmath.c b/third_party/lib/acpica/source/components/utilities/utmath.c new file mode 100644 index 000000000..aa3d762c0 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utmath.c @@ -0,0 +1,375 @@ +/******************************************************************************* + * + * Module Name: utmath - Integer math support routines + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utmath") + +/* + * Optional support for 64-bit double-precision integer divide. This code + * is configurable and is implemented in order to support 32-bit kernel + * environments where a 64-bit double-precision math library is not available. + * + * Support for a more normal 64-bit divide/modulo (with check for a divide- + * by-zero) appears after this optional section of code. + */ +#ifndef ACPI_USE_NATIVE_DIVIDE + +/* Structures used only for 64-bit divide */ + +typedef struct uint64_struct +{ + UINT32 Lo; + UINT32 Hi; + +} UINT64_STRUCT; + +typedef union uint64_overlay +{ + UINT64 Full; + UINT64_STRUCT Part; + +} UINT64_OVERLAY; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtShortDivide + * + * PARAMETERS: Dividend - 64-bit dividend + * Divisor - 32-bit divisor + * OutQuotient - Pointer to where the quotient is returned + * OutRemainder - Pointer to where the remainder is returned + * + * RETURN: Status (Checks for divide-by-zero) + * + * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) + * divide and modulo. The result is a 64-bit quotient and a + * 32-bit remainder. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtShortDivide ( + UINT64 Dividend, + UINT32 Divisor, + UINT64 *OutQuotient, + UINT32 *OutRemainder) +{ + UINT64_OVERLAY DividendOvl; + UINT64_OVERLAY Quotient; + UINT32 Remainder32; + + + ACPI_FUNCTION_TRACE (UtShortDivide); + + + /* Always check for a zero divisor */ + + if (Divisor == 0) + { + ACPI_ERROR ((AE_INFO, "Divide by zero")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + DividendOvl.Full = Dividend; + + /* + * The quotient is 64 bits, the remainder is always 32 bits, + * and is generated by the second divide. + */ + ACPI_DIV_64_BY_32 (0, DividendOvl.Part.Hi, Divisor, + Quotient.Part.Hi, Remainder32); + + ACPI_DIV_64_BY_32 (Remainder32, DividendOvl.Part.Lo, Divisor, + Quotient.Part.Lo, Remainder32); + + /* Return only what was requested */ + + if (OutQuotient) + { + *OutQuotient = Quotient.Full; + } + if (OutRemainder) + { + *OutRemainder = Remainder32; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDivide + * + * PARAMETERS: InDividend - Dividend + * InDivisor - Divisor + * OutQuotient - Pointer to where the quotient is returned + * OutRemainder - Pointer to where the remainder is returned + * + * RETURN: Status (Checks for divide-by-zero) + * + * DESCRIPTION: Perform a divide and modulo. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtDivide ( + UINT64 InDividend, + UINT64 InDivisor, + UINT64 *OutQuotient, + UINT64 *OutRemainder) +{ + UINT64_OVERLAY Dividend; + UINT64_OVERLAY Divisor; + UINT64_OVERLAY Quotient; + UINT64_OVERLAY Remainder; + UINT64_OVERLAY NormalizedDividend; + UINT64_OVERLAY NormalizedDivisor; + UINT32 Partial1; + UINT64_OVERLAY Partial2; + UINT64_OVERLAY Partial3; + + + ACPI_FUNCTION_TRACE (UtDivide); + + + /* Always check for a zero divisor */ + + if (InDivisor == 0) + { + ACPI_ERROR ((AE_INFO, "Divide by zero")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + Divisor.Full = InDivisor; + Dividend.Full = InDividend; + if (Divisor.Part.Hi == 0) + { + /* + * 1) Simplest case is where the divisor is 32 bits, we can + * just do two divides + */ + Remainder.Part.Hi = 0; + + /* + * The quotient is 64 bits, the remainder is always 32 bits, + * and is generated by the second divide. + */ + ACPI_DIV_64_BY_32 (0, Dividend.Part.Hi, Divisor.Part.Lo, + Quotient.Part.Hi, Partial1); + + ACPI_DIV_64_BY_32 (Partial1, Dividend.Part.Lo, Divisor.Part.Lo, + Quotient.Part.Lo, Remainder.Part.Lo); + } + + else + { + /* + * 2) The general case where the divisor is a full 64 bits + * is more difficult + */ + Quotient.Part.Hi = 0; + NormalizedDividend = Dividend; + NormalizedDivisor = Divisor; + + /* Normalize the operands (shift until the divisor is < 32 bits) */ + + do + { + ACPI_SHIFT_RIGHT_64 ( + NormalizedDivisor.Part.Hi, NormalizedDivisor.Part.Lo); + ACPI_SHIFT_RIGHT_64 ( + NormalizedDividend.Part.Hi, NormalizedDividend.Part.Lo); + + } while (NormalizedDivisor.Part.Hi != 0); + + /* Partial divide */ + + ACPI_DIV_64_BY_32 ( + NormalizedDividend.Part.Hi, NormalizedDividend.Part.Lo, + NormalizedDivisor.Part.Lo, Quotient.Part.Lo, Partial1); + + /* + * The quotient is always 32 bits, and simply requires + * adjustment. The 64-bit remainder must be generated. + */ + Partial1 = Quotient.Part.Lo * Divisor.Part.Hi; + Partial2.Full = (UINT64) Quotient.Part.Lo * Divisor.Part.Lo; + Partial3.Full = (UINT64) Partial2.Part.Hi + Partial1; + + Remainder.Part.Hi = Partial3.Part.Lo; + Remainder.Part.Lo = Partial2.Part.Lo; + + if (Partial3.Part.Hi == 0) + { + if (Partial3.Part.Lo >= Dividend.Part.Hi) + { + if (Partial3.Part.Lo == Dividend.Part.Hi) + { + if (Partial2.Part.Lo > Dividend.Part.Lo) + { + Quotient.Part.Lo--; + Remainder.Full -= Divisor.Full; + } + } + else + { + Quotient.Part.Lo--; + Remainder.Full -= Divisor.Full; + } + } + + Remainder.Full = Remainder.Full - Dividend.Full; + Remainder.Part.Hi = (UINT32) -((INT32) Remainder.Part.Hi); + Remainder.Part.Lo = (UINT32) -((INT32) Remainder.Part.Lo); + + if (Remainder.Part.Lo) + { + Remainder.Part.Hi--; + } + } + } + + /* Return only what was requested */ + + if (OutQuotient) + { + *OutQuotient = Quotient.Full; + } + if (OutRemainder) + { + *OutRemainder = Remainder.Full; + } + + return_ACPI_STATUS (AE_OK); +} + +#else + +/******************************************************************************* + * + * FUNCTION: AcpiUtShortDivide, AcpiUtDivide + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native versions of the UtDivide functions. Use these if either + * 1) The target is a 64-bit platform and therefore 64-bit + * integer math is supported directly by the machine. + * 2) The target is a 32-bit or 16-bit platform, and the + * double-precision integer math library is available to + * perform the divide. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtShortDivide ( + UINT64 InDividend, + UINT32 Divisor, + UINT64 *OutQuotient, + UINT32 *OutRemainder) +{ + + ACPI_FUNCTION_TRACE (UtShortDivide); + + + /* Always check for a zero divisor */ + + if (Divisor == 0) + { + ACPI_ERROR ((AE_INFO, "Divide by zero")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + /* Return only what was requested */ + + if (OutQuotient) + { + *OutQuotient = InDividend / Divisor; + } + if (OutRemainder) + { + *OutRemainder = (UINT32) (InDividend % Divisor); + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_STATUS +AcpiUtDivide ( + UINT64 InDividend, + UINT64 InDivisor, + UINT64 *OutQuotient, + UINT64 *OutRemainder) +{ + ACPI_FUNCTION_TRACE (UtDivide); + + + /* Always check for a zero divisor */ + + if (InDivisor == 0) + { + ACPI_ERROR ((AE_INFO, "Divide by zero")); + return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); + } + + + /* Return only what was requested */ + + if (OutQuotient) + { + *OutQuotient = InDividend / InDivisor; + } + if (OutRemainder) + { + *OutRemainder = InDividend % InDivisor; + } + + return_ACPI_STATUS (AE_OK); +} + +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utmisc.c b/third_party/lib/acpica/source/components/utilities/utmisc.c new file mode 100644 index 000000000..e35a0ef50 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utmisc.c @@ -0,0 +1,459 @@ +/******************************************************************************* + * + * Module Name: utmisc - common utility procedures + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utmisc") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtIsPciRootBridge + * + * PARAMETERS: Id - The HID/CID in string format + * + * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. + * + ******************************************************************************/ + +BOOLEAN +AcpiUtIsPciRootBridge ( + char *Id) +{ + + /* + * Check if this is a PCI root bridge. + * ACPI 3.0+: check for a PCI Express root also. + */ + if (!(strcmp (Id, + PCI_ROOT_HID_STRING)) || + + !(strcmp (Id, + PCI_EXPRESS_ROOT_HID_STRING))) + { + return (TRUE); + } + + return (FALSE); +} + + +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) +/******************************************************************************* + * + * FUNCTION: AcpiUtIsAmlTable + * + * PARAMETERS: Table - An ACPI table + * + * RETURN: TRUE if table contains executable AML; FALSE otherwise + * + * DESCRIPTION: Check ACPI Signature for a table that contains AML code. + * Currently, these are DSDT,SSDT,PSDT. All other table types are + * data tables that do not contain AML code. + * + ******************************************************************************/ + +BOOLEAN +AcpiUtIsAmlTable ( + ACPI_TABLE_HEADER *Table) +{ + + /* These are the only tables that contain executable AML */ + + if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_PSDT) || + ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_SSDT) || + ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_OSDT)) + { + return (TRUE); + } + + return (FALSE); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDwordByteSwap + * + * PARAMETERS: Value - Value to be converted + * + * RETURN: UINT32 integer with bytes swapped + * + * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) + * + ******************************************************************************/ + +UINT32 +AcpiUtDwordByteSwap ( + UINT32 Value) +{ + union + { + UINT32 Value; + UINT8 Bytes[4]; + } Out; + union + { + UINT32 Value; + UINT8 Bytes[4]; + } In; + + + ACPI_FUNCTION_ENTRY (); + + + In.Value = Value; + + Out.Bytes[0] = In.Bytes[3]; + Out.Bytes[1] = In.Bytes[2]; + Out.Bytes[2] = In.Bytes[1]; + Out.Bytes[3] = In.Bytes[0]; + + return (Out.Value); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtSetIntegerWidth + * + * PARAMETERS: Revision From DSDT header + * + * RETURN: None + * + * DESCRIPTION: Set the global integer bit width based upon the revision + * of the DSDT. For Revision 1 and 0, Integers are 32 bits. + * For Revision 2 and above, Integers are 64 bits. Yes, this + * makes a difference. + * + ******************************************************************************/ + +void +AcpiUtSetIntegerWidth ( + UINT8 Revision) +{ + + if (Revision < 2) + { + /* 32-bit case */ + + AcpiGbl_IntegerBitWidth = 32; + AcpiGbl_IntegerNybbleWidth = 8; + AcpiGbl_IntegerByteWidth = 4; + } + else + { + /* 64-bit case (ACPI 2.0+) */ + + AcpiGbl_IntegerBitWidth = 64; + AcpiGbl_IntegerNybbleWidth = 16; + AcpiGbl_IntegerByteWidth = 8; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateUpdateStateAndPush + * + * PARAMETERS: Object - Object to be added to the new state + * Action - Increment/Decrement + * StateList - List the state will be added to + * + * RETURN: Status + * + * DESCRIPTION: Create a new state and push it + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCreateUpdateStateAndPush ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action, + ACPI_GENERIC_STATE **StateList) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + /* Ignore null objects; these are expected */ + + if (!Object) + { + return (AE_OK); + } + + State = AcpiUtCreateUpdateState (Object, Action); + if (!State) + { + return (AE_NO_MEMORY); + } + + AcpiUtPushGenericState (StateList, State); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtWalkPackageTree + * + * PARAMETERS: SourceObject - The package to walk + * TargetObject - Target object (if package is being copied) + * WalkCallback - Called once for each package element + * Context - Passed to the callback function + * + * RETURN: Status + * + * DESCRIPTION: Walk through a package + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtWalkPackageTree ( + ACPI_OPERAND_OBJECT *SourceObject, + void *TargetObject, + ACPI_PKG_CALLBACK WalkCallback, + void *Context) +{ + ACPI_STATUS Status = AE_OK; + ACPI_GENERIC_STATE *StateList = NULL; + ACPI_GENERIC_STATE *State; + UINT32 ThisIndex; + ACPI_OPERAND_OBJECT *ThisSourceObj; + + + ACPI_FUNCTION_TRACE (UtWalkPackageTree); + + + State = AcpiUtCreatePkgState (SourceObject, TargetObject, 0); + if (!State) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + while (State) + { + /* Get one element of the package */ + + ThisIndex = State->Pkg.Index; + ThisSourceObj = (ACPI_OPERAND_OBJECT *) + State->Pkg.SourceObject->Package.Elements[ThisIndex]; + + /* + * Check for: + * 1) An uninitialized package element. It is completely + * legal to declare a package and leave it uninitialized + * 2) Not an internal object - can be a namespace node instead + * 3) Any type other than a package. Packages are handled in else + * case below. + */ + if ((!ThisSourceObj) || + (ACPI_GET_DESCRIPTOR_TYPE (ThisSourceObj) != + ACPI_DESC_TYPE_OPERAND) || + (ThisSourceObj->Common.Type != ACPI_TYPE_PACKAGE)) + { + Status = WalkCallback (ACPI_COPY_TYPE_SIMPLE, ThisSourceObj, + State, Context); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + State->Pkg.Index++; + while (State->Pkg.Index >= + State->Pkg.SourceObject->Package.Count) + { + /* + * We've handled all of the objects at this level, This means + * that we have just completed a package. That package may + * have contained one or more packages itself. + * + * Delete this state and pop the previous state (package). + */ + AcpiUtDeleteGenericState (State); + State = AcpiUtPopGenericState (&StateList); + + /* Finished when there are no more states */ + + if (!State) + { + /* + * We have handled all of the objects in the top level + * package just add the length of the package objects + * and exit + */ + return_ACPI_STATUS (AE_OK); + } + + /* + * Go back up a level and move the index past the just + * completed package object. + */ + State->Pkg.Index++; + } + } + else + { + /* This is a subobject of type package */ + + Status = WalkCallback ( + ACPI_COPY_TYPE_PACKAGE, ThisSourceObj, State, Context); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Push the current state and create a new one + * The callback above returned a new target package object. + */ + AcpiUtPushGenericState (&StateList, State); + State = AcpiUtCreatePkgState ( + ThisSourceObj, State->Pkg.ThisTargetObj, 0); + if (!State) + { + /* Free any stacked Update State objects */ + + while (StateList) + { + State = AcpiUtPopGenericState (&StateList); + AcpiUtDeleteGenericState (State); + } + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + } + + /* We should never get here */ + + return_ACPI_STATUS (AE_AML_INTERNAL); +} + + +#ifdef ACPI_DEBUG_OUTPUT +/******************************************************************************* + * + * FUNCTION: AcpiUtDisplayInitPathname + * + * PARAMETERS: Type - Object type of the node + * ObjHandle - Handle whose pathname will be displayed + * Path - Additional path string to be appended. + * (NULL if no extra path) + * + * RETURN: ACPI_STATUS + * + * DESCRIPTION: Display full pathname of an object, DEBUG ONLY + * + ******************************************************************************/ + +void +AcpiUtDisplayInitPathname ( + UINT8 Type, + ACPI_NAMESPACE_NODE *ObjHandle, + char *Path) +{ + ACPI_STATUS Status; + ACPI_BUFFER Buffer; + + + ACPI_FUNCTION_ENTRY (); + + + /* Only print the path if the appropriate debug level is enabled */ + + if (!(AcpiDbgLevel & ACPI_LV_INIT_NAMES)) + { + return; + } + + /* Get the full pathname to the node */ + + Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + Status = AcpiNsHandleToPathname (ObjHandle, &Buffer, TRUE); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Print what we're doing */ + + switch (Type) + { + case ACPI_TYPE_METHOD: + + AcpiOsPrintf ("Executing "); + break; + + default: + + AcpiOsPrintf ("Initializing "); + break; + } + + /* Print the object type and pathname */ + + AcpiOsPrintf ("%-12s %s", + AcpiUtGetTypeName (Type), (char *) Buffer.Pointer); + + /* Extra path is used to append names like _STA, _INI, etc. */ + + if (Path) + { + AcpiOsPrintf (".%s", Path); + } + AcpiOsPrintf ("\n"); + + ACPI_FREE (Buffer.Pointer); +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utmutex.c b/third_party/lib/acpica/source/components/utilities/utmutex.c new file mode 100644 index 000000000..83b1cee0d --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utmutex.c @@ -0,0 +1,428 @@ +/******************************************************************************* + * + * Module Name: utmutex - local mutex support + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utmutex") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiUtCreateMutex ( + ACPI_MUTEX_HANDLE MutexId); + +static void +AcpiUtDeleteMutex ( + ACPI_MUTEX_HANDLE MutexId); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtMutexInitialize + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Create the system mutex objects. This includes mutexes, + * spin locks, and reader/writer locks. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtMutexInitialize ( + void) +{ + UINT32 i; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtMutexInitialize); + + + /* Create each of the predefined mutex objects */ + + for (i = 0; i < ACPI_NUM_MUTEX; i++) + { + Status = AcpiUtCreateMutex (i); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* Create the spinlocks for use at interrupt level or for speed */ + + Status = AcpiOsCreateLock (&AcpiGbl_GpeLock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiOsCreateLock (&AcpiGbl_HardwareLock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiOsCreateLock (&AcpiGbl_ReferenceCountLock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Mutex for _OSI support */ + + Status = AcpiOsCreateMutex (&AcpiGbl_OsiMutex); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Create the reader/writer lock for namespace access */ + + Status = AcpiUtCreateRwLock (&AcpiGbl_NamespaceRwLock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + +#ifdef ACPI_DEBUGGER + + /* Debugger Support */ + + Status = AcpiOsCreateMutex (&AcpiGbl_DbCommandReady); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiOsCreateMutex (&AcpiGbl_DbCommandComplete); +#endif + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtMutexTerminate + * + * PARAMETERS: None. + * + * RETURN: None. + * + * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes, + * spin locks, and reader/writer locks. + * + ******************************************************************************/ + +void +AcpiUtMutexTerminate ( + void) +{ + UINT32 i; + + + ACPI_FUNCTION_TRACE (UtMutexTerminate); + + + /* Delete each predefined mutex object */ + + for (i = 0; i < ACPI_NUM_MUTEX; i++) + { + AcpiUtDeleteMutex (i); + } + + AcpiOsDeleteMutex (AcpiGbl_OsiMutex); + + /* Delete the spinlocks */ + + AcpiOsDeleteLock (AcpiGbl_GpeLock); + AcpiOsDeleteLock (AcpiGbl_HardwareLock); + AcpiOsDeleteLock (AcpiGbl_ReferenceCountLock); + + /* Delete the reader/writer lock */ + + AcpiUtDeleteRwLock (&AcpiGbl_NamespaceRwLock); + +#ifdef ACPI_DEBUGGER + AcpiOsDeleteMutex (AcpiGbl_DbCommandReady); + AcpiOsDeleteMutex (AcpiGbl_DbCommandComplete); +#endif + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateMutex + * + * PARAMETERS: MutexID - ID of the mutex to be created + * + * RETURN: Status + * + * DESCRIPTION: Create a mutex object. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtCreateMutex ( + ACPI_MUTEX_HANDLE MutexId) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_U32 (UtCreateMutex, MutexId); + + + if (!AcpiGbl_MutexInfo[MutexId].Mutex) + { + Status = AcpiOsCreateMutex (&AcpiGbl_MutexInfo[MutexId].Mutex); + AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED; + AcpiGbl_MutexInfo[MutexId].UseCount = 0; + } + + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteMutex + * + * PARAMETERS: MutexID - ID of the mutex to be deleted + * + * RETURN: Status + * + * DESCRIPTION: Delete a mutex object. + * + ******************************************************************************/ + +static void +AcpiUtDeleteMutex ( + ACPI_MUTEX_HANDLE MutexId) +{ + + ACPI_FUNCTION_TRACE_U32 (UtDeleteMutex, MutexId); + + + AcpiOsDeleteMutex (AcpiGbl_MutexInfo[MutexId].Mutex); + + AcpiGbl_MutexInfo[MutexId].Mutex = NULL; + AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED; + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAcquireMutex + * + * PARAMETERS: MutexID - ID of the mutex to be acquired + * + * RETURN: Status + * + * DESCRIPTION: Acquire a mutex object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtAcquireMutex ( + ACPI_MUTEX_HANDLE MutexId) +{ + ACPI_STATUS Status; + ACPI_THREAD_ID ThisThreadId; + + + ACPI_FUNCTION_NAME (UtAcquireMutex); + + + if (MutexId > ACPI_MAX_MUTEX) + { + return (AE_BAD_PARAMETER); + } + + ThisThreadId = AcpiOsGetThreadId (); + +#ifdef ACPI_MUTEX_DEBUG + { + UINT32 i; + /* + * Mutex debug code, for internal debugging only. + * + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than or equal to this one. If so, the thread has violated + * the mutex ordering rule. This indicates a coding error somewhere in + * the ACPI subsystem code. + */ + for (i = MutexId; i < ACPI_NUM_MUTEX; i++) + { + if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId) + { + if (i == MutexId) + { + ACPI_ERROR ((AE_INFO, + "Mutex [%s] already acquired by this thread [%u]", + AcpiUtGetMutexName (MutexId), + (UINT32) ThisThreadId)); + + return (AE_ALREADY_ACQUIRED); + } + + ACPI_ERROR ((AE_INFO, + "Invalid acquire order: Thread %u owns [%s], wants [%s]", + (UINT32) ThisThreadId, AcpiUtGetMutexName (i), + AcpiUtGetMutexName (MutexId))); + + return (AE_ACQUIRE_DEADLOCK); + } + } + } +#endif + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, + "Thread %u attempting to acquire Mutex [%s]\n", + (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId))); + + Status = AcpiOsAcquireMutex ( + AcpiGbl_MutexInfo[MutexId].Mutex, ACPI_WAIT_FOREVER); + if (ACPI_SUCCESS (Status)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, + "Thread %u acquired Mutex [%s]\n", + (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId))); + + AcpiGbl_MutexInfo[MutexId].UseCount++; + AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId; + } + else + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Thread %u could not acquire Mutex [0x%X]", + (UINT32) ThisThreadId, MutexId)); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtReleaseMutex + * + * PARAMETERS: MutexID - ID of the mutex to be released + * + * RETURN: Status + * + * DESCRIPTION: Release a mutex object. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtReleaseMutex ( + ACPI_MUTEX_HANDLE MutexId) +{ + ACPI_FUNCTION_NAME (UtReleaseMutex); + + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n", + (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId))); + + if (MutexId > ACPI_MAX_MUTEX) + { + return (AE_BAD_PARAMETER); + } + + /* + * Mutex must be acquired in order to release it! + */ + if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED) + { + ACPI_ERROR ((AE_INFO, + "Mutex [0x%X] is not acquired, cannot release", MutexId)); + + return (AE_NOT_ACQUIRED); + } + +#ifdef ACPI_MUTEX_DEBUG + { + UINT32 i; + /* + * Mutex debug code, for internal debugging only. + * + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than this one. If so, the thread has violated the mutex + * ordering rule. This indicates a coding error somewhere in + * the ACPI subsystem code. + */ + for (i = MutexId; i < ACPI_NUM_MUTEX; i++) + { + if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ()) + { + if (i == MutexId) + { + continue; + } + + ACPI_ERROR ((AE_INFO, + "Invalid release order: owns [%s], releasing [%s]", + AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId))); + + return (AE_RELEASE_DEADLOCK); + } + } + } +#endif + + /* Mark unlocked FIRST */ + + AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED; + + AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/utilities/utnonansi.c b/third_party/lib/acpica/source/components/utilities/utnonansi.c new file mode 100644 index 000000000..5f45aaa1f --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utnonansi.c @@ -0,0 +1,453 @@ +/******************************************************************************* + * + * Module Name: utnonansi - Non-ansi C library functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utnonansi") + + +/* + * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit + * version of strtoul. + */ + +/******************************************************************************* + * + * FUNCTION: AcpiUtStrlwr (strlwr) + * + * PARAMETERS: SrcString - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert a string to lowercase + * + ******************************************************************************/ + +void +AcpiUtStrlwr ( + char *SrcString) +{ + char *String; + + + ACPI_FUNCTION_ENTRY (); + + + if (!SrcString) + { + return; + } + + /* Walk entire string, lowercasing the letters */ + + for (String = SrcString; *String; String++) + { + *String = (char) tolower ((int) *String); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtStrupr (strupr) + * + * PARAMETERS: SrcString - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert a string to uppercase + * + ******************************************************************************/ + +void +AcpiUtStrupr ( + char *SrcString) +{ + char *String; + + + ACPI_FUNCTION_ENTRY (); + + + if (!SrcString) + { + return; + } + + /* Walk entire string, uppercasing the letters */ + + for (String = SrcString; *String; String++) + { + *String = (char) toupper ((int) *String); + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiUtStricmp (stricmp) + * + * PARAMETERS: String1 - first string to compare + * String2 - second string to compare + * + * RETURN: int that signifies string relationship. Zero means strings + * are equal. + * + * DESCRIPTION: Case-insensitive string compare. Implementation of the + * non-ANSI stricmp function. + * + ******************************************************************************/ + +int +AcpiUtStricmp ( + char *String1, + char *String2) +{ + int c1; + int c2; + + + do + { + c1 = tolower ((int) *String1); + c2 = tolower ((int) *String2); + + String1++; + String2++; + } + while ((c1 == c2) && (c1)); + + return (c1 - c2); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtStrtoul64 + * + * PARAMETERS: String - Null terminated string + * Base - Radix of the string: 16 or ACPI_ANY_BASE; + * ACPI_ANY_BASE means 'in behalf of ToInteger' + * RetInteger - Where the converted integer is returned + * + * RETURN: Status and Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. Performs either a + * 32-bit or 64-bit conversion, depending on the current mode + * of the interpreter. + * + * NOTE: Does not support Octal strings, not needed. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtStrtoul64 ( + char *String, + UINT32 Base, + UINT64 *RetInteger) +{ + UINT32 ThisDigit = 0; + UINT64 ReturnValue = 0; + UINT64 Quotient; + UINT64 Dividend; + UINT32 ToIntegerOp = (Base == ACPI_ANY_BASE); + UINT32 Mode32 = (AcpiGbl_IntegerByteWidth == 4); + UINT8 ValidDigits = 0; + UINT8 SignOf0x = 0; + UINT8 Term = 0; + + + ACPI_FUNCTION_TRACE_STR (UtStroul64, String); + + + switch (Base) + { + case ACPI_ANY_BASE: + case 16: + + break; + + default: + + /* Invalid Base */ + + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!String) + { + goto ErrorExit; + } + + /* Skip over any white space in the buffer */ + + while ((*String) && (isspace ((int) *String) || *String == '\t')) + { + String++; + } + + if (ToIntegerOp) + { + /* + * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. + * We need to determine if it is decimal or hexadecimal. + */ + if ((*String == '0') && (tolower ((int) *(String + 1)) == 'x')) + { + SignOf0x = 1; + Base = 16; + + /* Skip over the leading '0x' */ + String += 2; + } + else + { + Base = 10; + } + } + + /* Any string left? Check that '0x' is not followed by white space. */ + + if (!(*String) || isspace ((int) *String) || *String == '\t') + { + if (ToIntegerOp) + { + goto ErrorExit; + } + else + { + goto AllDone; + } + } + + /* + * Perform a 32-bit or 64-bit conversion, depending upon the current + * execution mode of the interpreter + */ + Dividend = (Mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; + + /* Main loop: convert the string to a 32- or 64-bit integer */ + + while (*String) + { + if (isdigit ((int) *String)) + { + /* Convert ASCII 0-9 to Decimal value */ + + ThisDigit = ((UINT8) *String) - '0'; + } + else if (Base == 10) + { + /* Digit is out of range; possible in ToInteger case only */ + + Term = 1; + } + else + { + ThisDigit = (UINT8) toupper ((int) *String); + if (isxdigit ((int) ThisDigit)) + { + /* Convert ASCII Hex char to value */ + + ThisDigit = ThisDigit - 'A' + 10; + } + else + { + Term = 1; + } + } + + if (Term) + { + if (ToIntegerOp) + { + goto ErrorExit; + } + else + { + break; + } + } + else if ((ValidDigits == 0) && (ThisDigit == 0) && !SignOf0x) + { + /* Skip zeros */ + String++; + continue; + } + + ValidDigits++; + + if (SignOf0x && ((ValidDigits > 16) || ((ValidDigits > 8) && Mode32))) + { + /* + * This is ToInteger operation case. + * No any restrictions for string-to-integer conversion, + * see ACPI spec. + */ + goto ErrorExit; + } + + /* Divide the digit into the correct position */ + + (void) AcpiUtShortDivide ( + (Dividend - (UINT64) ThisDigit), Base, &Quotient, NULL); + + if (ReturnValue > Quotient) + { + if (ToIntegerOp) + { + goto ErrorExit; + } + else + { + break; + } + } + + ReturnValue *= Base; + ReturnValue += ThisDigit; + String++; + } + + /* All done, normal exit */ + +AllDone: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (ReturnValue))); + + *RetInteger = ReturnValue; + return_ACPI_STATUS (AE_OK); + + +ErrorExit: + /* Base was set/validated above */ + + if (Base == 10) + { + return_ACPI_STATUS (AE_BAD_DECIMAL_CONSTANT); + } + else + { + return_ACPI_STATUS (AE_BAD_HEX_CONSTANT); + } +} + + +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +/******************************************************************************* + * + * FUNCTION: AcpiUtSafeStrcpy, AcpiUtSafeStrcat, AcpiUtSafeStrncat + * + * PARAMETERS: Adds a "DestSize" parameter to each of the standard string + * functions. This is the size of the Destination buffer. + * + * RETURN: TRUE if the operation would overflow the destination buffer. + * + * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that + * the result of the operation will not overflow the output string + * buffer. + * + * NOTE: These functions are typically only helpful for processing + * user input and command lines. For most ACPICA code, the + * required buffer length is precisely calculated before buffer + * allocation, so the use of these functions is unnecessary. + * + ******************************************************************************/ + +BOOLEAN +AcpiUtSafeStrcpy ( + char *Dest, + ACPI_SIZE DestSize, + char *Source) +{ + + if (strlen (Source) >= DestSize) + { + return (TRUE); + } + + strcpy (Dest, Source); + return (FALSE); +} + +BOOLEAN +AcpiUtSafeStrcat ( + char *Dest, + ACPI_SIZE DestSize, + char *Source) +{ + + if ((strlen (Dest) + strlen (Source)) >= DestSize) + { + return (TRUE); + } + + strcat (Dest, Source); + return (FALSE); +} + +BOOLEAN +AcpiUtSafeStrncat ( + char *Dest, + ACPI_SIZE DestSize, + char *Source, + ACPI_SIZE MaxTransferLength) +{ + ACPI_SIZE ActualTransferLength; + + + ActualTransferLength = ACPI_MIN (MaxTransferLength, strlen (Source)); + + if ((strlen (Dest) + ActualTransferLength) >= DestSize) + { + return (TRUE); + } + + strncat (Dest, Source, MaxTransferLength); + return (FALSE); +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utobject.c b/third_party/lib/acpica/source/components/utilities/utobject.c new file mode 100644 index 000000000..ed3b85f1d --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utobject.c @@ -0,0 +1,780 @@ +/****************************************************************************** + * + * Module Name: utobject - ACPI object create/delete/size/cache routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utobject") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiUtGetSimpleObjectSize ( + ACPI_OPERAND_OBJECT *Obj, + ACPI_SIZE *ObjLength); + +static ACPI_STATUS +AcpiUtGetPackageObjectSize ( + ACPI_OPERAND_OBJECT *Obj, + ACPI_SIZE *ObjLength); + +static ACPI_STATUS +AcpiUtGetElementLength ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateInternalObjectDbg + * + * PARAMETERS: ModuleName - Source file name of caller + * LineNumber - Line number of caller + * ComponentId - Component type of caller + * Type - ACPI Type of the new object + * + * RETURN: A new internal object, null on failure + * + * DESCRIPTION: Create and initialize a new internal object. + * + * NOTE: We always allocate the worst-case object descriptor because + * these objects are cached, and we want them to be + * one-size-satisifies-any-request. This in itself may not be + * the most memory efficient, but the efficiency of the object + * cache should more than make up for this! + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiUtCreateInternalObjectDbg ( + const char *ModuleName, + UINT32 LineNumber, + UINT32 ComponentId, + ACPI_OBJECT_TYPE Type) +{ + ACPI_OPERAND_OBJECT *Object; + ACPI_OPERAND_OBJECT *SecondObject; + + + ACPI_FUNCTION_TRACE_STR (UtCreateInternalObjectDbg, + AcpiUtGetTypeName (Type)); + + + /* Allocate the raw object descriptor */ + + Object = AcpiUtAllocateObjectDescDbg ( + ModuleName, LineNumber, ComponentId); + if (!Object) + { + return_PTR (NULL); + } + + switch (Type) + { + case ACPI_TYPE_REGION: + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + + /* These types require a secondary object */ + + SecondObject = AcpiUtAllocateObjectDescDbg ( + ModuleName, LineNumber, ComponentId); + if (!SecondObject) + { + AcpiUtDeleteObjectDesc (Object); + return_PTR (NULL); + } + + SecondObject->Common.Type = ACPI_TYPE_LOCAL_EXTRA; + SecondObject->Common.ReferenceCount = 1; + + /* Link the second object to the first */ + + Object->Common.NextObject = SecondObject; + break; + + default: + + /* All others have no secondary object */ + break; + } + + /* Save the object type in the object descriptor */ + + Object->Common.Type = (UINT8) Type; + + /* Init the reference count */ + + Object->Common.ReferenceCount = 1; + + /* Any per-type initialization should go here */ + + return_PTR (Object); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreatePackageObject + * + * PARAMETERS: Count - Number of package elements + * + * RETURN: Pointer to a new Package object, null on failure + * + * DESCRIPTION: Create a fully initialized package object + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiUtCreatePackageObject ( + UINT32 Count) +{ + ACPI_OPERAND_OBJECT *PackageDesc; + ACPI_OPERAND_OBJECT **PackageElements; + + + ACPI_FUNCTION_TRACE_U32 (UtCreatePackageObject, Count); + + + /* Create a new Package object */ + + PackageDesc = AcpiUtCreateInternalObject (ACPI_TYPE_PACKAGE); + if (!PackageDesc) + { + return_PTR (NULL); + } + + /* + * Create the element array. Count+1 allows the array to be null + * terminated. + */ + PackageElements = ACPI_ALLOCATE_ZEROED ( + ((ACPI_SIZE) Count + 1) * sizeof (void *)); + if (!PackageElements) + { + ACPI_FREE (PackageDesc); + return_PTR (NULL); + } + + PackageDesc->Package.Count = Count; + PackageDesc->Package.Elements = PackageElements; + return_PTR (PackageDesc); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateIntegerObject + * + * PARAMETERS: InitialValue - Initial value for the integer + * + * RETURN: Pointer to a new Integer object, null on failure + * + * DESCRIPTION: Create an initialized integer object + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiUtCreateIntegerObject ( + UINT64 InitialValue) +{ + ACPI_OPERAND_OBJECT *IntegerDesc; + + + ACPI_FUNCTION_TRACE (UtCreateIntegerObject); + + + /* Create and initialize a new integer object */ + + IntegerDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!IntegerDesc) + { + return_PTR (NULL); + } + + IntegerDesc->Integer.Value = InitialValue; + return_PTR (IntegerDesc); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateBufferObject + * + * PARAMETERS: BufferSize - Size of buffer to be created + * + * RETURN: Pointer to a new Buffer object, null on failure + * + * DESCRIPTION: Create a fully initialized buffer object + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiUtCreateBufferObject ( + ACPI_SIZE BufferSize) +{ + ACPI_OPERAND_OBJECT *BufferDesc; + UINT8 *Buffer = NULL; + + + ACPI_FUNCTION_TRACE_U32 (UtCreateBufferObject, BufferSize); + + + /* Create a new Buffer object */ + + BufferDesc = AcpiUtCreateInternalObject (ACPI_TYPE_BUFFER); + if (!BufferDesc) + { + return_PTR (NULL); + } + + /* Create an actual buffer only if size > 0 */ + + if (BufferSize > 0) + { + /* Allocate the actual buffer */ + + Buffer = ACPI_ALLOCATE_ZEROED (BufferSize); + if (!Buffer) + { + ACPI_ERROR ((AE_INFO, "Could not allocate size %u", + (UINT32) BufferSize)); + + AcpiUtRemoveReference (BufferDesc); + return_PTR (NULL); + } + } + + /* Complete buffer object initialization */ + + BufferDesc->Buffer.Flags |= AOPOBJ_DATA_VALID; + BufferDesc->Buffer.Pointer = Buffer; + BufferDesc->Buffer.Length = (UINT32) BufferSize; + + /* Return the new buffer descriptor */ + + return_PTR (BufferDesc); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateStringObject + * + * PARAMETERS: StringSize - Size of string to be created. Does not + * include NULL terminator, this is added + * automatically. + * + * RETURN: Pointer to a new String object + * + * DESCRIPTION: Create a fully initialized string object + * + ******************************************************************************/ + +ACPI_OPERAND_OBJECT * +AcpiUtCreateStringObject ( + ACPI_SIZE StringSize) +{ + ACPI_OPERAND_OBJECT *StringDesc; + char *String; + + + ACPI_FUNCTION_TRACE_U32 (UtCreateStringObject, StringSize); + + + /* Create a new String object */ + + StringDesc = AcpiUtCreateInternalObject (ACPI_TYPE_STRING); + if (!StringDesc) + { + return_PTR (NULL); + } + + /* + * Allocate the actual string buffer -- (Size + 1) for NULL terminator. + * NOTE: Zero-length strings are NULL terminated + */ + String = ACPI_ALLOCATE_ZEROED (StringSize + 1); + if (!String) + { + ACPI_ERROR ((AE_INFO, "Could not allocate size %u", + (UINT32) StringSize)); + + AcpiUtRemoveReference (StringDesc); + return_PTR (NULL); + } + + /* Complete string object initialization */ + + StringDesc->String.Pointer = String; + StringDesc->String.Length = (UINT32) StringSize; + + /* Return the new string descriptor */ + + return_PTR (StringDesc); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidInternalObject + * + * PARAMETERS: Object - Object to be validated + * + * RETURN: TRUE if object is valid, FALSE otherwise + * + * DESCRIPTION: Validate a pointer to be of type ACPI_OPERAND_OBJECT + * + ******************************************************************************/ + +BOOLEAN +AcpiUtValidInternalObject ( + void *Object) +{ + + ACPI_FUNCTION_NAME (UtValidInternalObject); + + + /* Check for a null pointer */ + + if (!Object) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "**** Null Object Ptr\n")); + return (FALSE); + } + + /* Check the descriptor type field */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (Object)) + { + case ACPI_DESC_TYPE_OPERAND: + + /* The object appears to be a valid ACPI_OPERAND_OBJECT */ + + return (TRUE); + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%p is not an ACPI operand obj [%s]\n", + Object, AcpiUtGetDescriptorName (Object))); + break; + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAllocateObjectDescDbg + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * ComponentId - Caller's component ID (for error output) + * + * RETURN: Pointer to newly allocated object descriptor. Null on error + * + * DESCRIPTION: Allocate a new object descriptor. Gracefully handle + * error conditions. + * + ******************************************************************************/ + +void * +AcpiUtAllocateObjectDescDbg ( + const char *ModuleName, + UINT32 LineNumber, + UINT32 ComponentId) +{ + ACPI_OPERAND_OBJECT *Object; + + + ACPI_FUNCTION_TRACE (UtAllocateObjectDescDbg); + + + Object = AcpiOsAcquireObject (AcpiGbl_OperandCache); + if (!Object) + { + ACPI_ERROR ((ModuleName, LineNumber, + "Could not allocate an object descriptor")); + + return_PTR (NULL); + } + + /* Mark the descriptor type */ + + ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_OPERAND); + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p Size %X\n", + Object, (UINT32) sizeof (ACPI_OPERAND_OBJECT))); + + return_PTR (Object); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteObjectDesc + * + * PARAMETERS: Object - An Acpi internal object to be deleted + * + * RETURN: None. + * + * DESCRIPTION: Free an ACPI object descriptor or add it to the object cache + * + ******************************************************************************/ + +void +AcpiUtDeleteObjectDesc ( + ACPI_OPERAND_OBJECT *Object) +{ + ACPI_FUNCTION_TRACE_PTR (UtDeleteObjectDesc, Object); + + + /* Object must be of type ACPI_OPERAND_OBJECT */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Object) != ACPI_DESC_TYPE_OPERAND) + { + ACPI_ERROR ((AE_INFO, + "%p is not an ACPI Operand object [%s]", Object, + AcpiUtGetDescriptorName (Object))); + return_VOID; + } + + (void) AcpiOsReleaseObject (AcpiGbl_OperandCache, Object); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetSimpleObjectSize + * + * PARAMETERS: InternalObject - An ACPI operand object + * ObjLength - Where the length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to determine the space required to + * contain a simple object for return to an external user. + * + * The length includes the object structure plus any additional + * needed space. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtGetSimpleObjectSize ( + ACPI_OPERAND_OBJECT *InternalObject, + ACPI_SIZE *ObjLength) +{ + ACPI_SIZE Length; + ACPI_SIZE Size; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (UtGetSimpleObjectSize, InternalObject); + + + /* Start with the length of the (external) Acpi object */ + + Length = sizeof (ACPI_OBJECT); + + /* A NULL object is allowed, can be a legal uninitialized package element */ + + if (!InternalObject) + { + /* + * Object is NULL, just return the length of ACPI_OBJECT + * (A NULL ACPI_OBJECT is an object of all zeroes.) + */ + *ObjLength = ACPI_ROUND_UP_TO_NATIVE_WORD (Length); + return_ACPI_STATUS (AE_OK); + } + + /* A Namespace Node should never appear here */ + + if (ACPI_GET_DESCRIPTOR_TYPE (InternalObject) == ACPI_DESC_TYPE_NAMED) + { + /* A namespace node should never get here */ + + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * The final length depends on the object type + * Strings and Buffers are packed right up against the parent object and + * must be accessed bytewise or there may be alignment problems on + * certain processors + */ + switch (InternalObject->Common.Type) + { + case ACPI_TYPE_STRING: + + Length += (ACPI_SIZE) InternalObject->String.Length + 1; + break; + + case ACPI_TYPE_BUFFER: + + Length += (ACPI_SIZE) InternalObject->Buffer.Length; + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + + /* No extra data for these types */ + + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (InternalObject->Reference.Class) + { + case ACPI_REFCLASS_NAME: + /* + * Get the actual length of the full pathname to this object. + * The reference will be converted to the pathname to the object + */ + Size = AcpiNsGetPathnameLength (InternalObject->Reference.Node); + if (!Size) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Length += ACPI_ROUND_UP_TO_NATIVE_WORD (Size); + break; + + default: + /* + * No other reference opcodes are supported. + * Notably, Locals and Args are not supported, but this may be + * required eventually. + */ + ACPI_ERROR ((AE_INFO, "Cannot convert to external object - " + "unsupported Reference Class [%s] 0x%X in object %p", + AcpiUtGetReferenceName (InternalObject), + InternalObject->Reference.Class, InternalObject)); + Status = AE_TYPE; + break; + } + break; + + default: + + ACPI_ERROR ((AE_INFO, "Cannot convert to external object - " + "unsupported type [%s] 0x%X in object %p", + AcpiUtGetObjectTypeName (InternalObject), + InternalObject->Common.Type, InternalObject)); + Status = AE_TYPE; + break; + } + + /* + * Account for the space required by the object rounded up to the next + * multiple of the machine word size. This keeps each object aligned + * on a machine word boundary. (preventing alignment faults on some + * machines.) + */ + *ObjLength = ACPI_ROUND_UP_TO_NATIVE_WORD (Length); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetElementLength + * + * PARAMETERS: ACPI_PKG_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Get the length of one package element. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtGetElementLength ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PKG_INFO *Info = (ACPI_PKG_INFO *) Context; + ACPI_SIZE ObjectSpace; + + + switch (ObjectType) + { + case ACPI_COPY_TYPE_SIMPLE: + /* + * Simple object - just get the size (Null object/entry is handled + * here also) and sum it into the running package length + */ + Status = AcpiUtGetSimpleObjectSize (SourceObject, &ObjectSpace); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Info->Length += ObjectSpace; + break; + + case ACPI_COPY_TYPE_PACKAGE: + + /* Package object - nothing much to do here, let the walk handle it */ + + Info->NumPackages++; + State->Pkg.ThisTargetObj = NULL; + break; + + default: + + /* No other types allowed */ + + return (AE_BAD_PARAMETER); + } + + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetPackageObjectSize + * + * PARAMETERS: InternalObject - An ACPI internal object + * ObjLength - Where the length is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to determine the space required to + * contain a package object for return to an external user. + * + * This is moderately complex since a package contains other + * objects including packages. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtGetPackageObjectSize ( + ACPI_OPERAND_OBJECT *InternalObject, + ACPI_SIZE *ObjLength) +{ + ACPI_STATUS Status; + ACPI_PKG_INFO Info; + + + ACPI_FUNCTION_TRACE_PTR (UtGetPackageObjectSize, InternalObject); + + + Info.Length = 0; + Info.ObjectSpace = 0; + Info.NumPackages = 1; + + Status = AcpiUtWalkPackageTree ( + InternalObject, NULL, AcpiUtGetElementLength, &Info); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * We have handled all of the objects in all levels of the package. + * just add the length of the package objects themselves. + * Round up to the next machine word. + */ + Info.Length += ACPI_ROUND_UP_TO_NATIVE_WORD ( + sizeof (ACPI_OBJECT)) * (ACPI_SIZE) Info.NumPackages; + + /* Return the total package length */ + + *ObjLength = Info.Length; + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetObjectSize + * + * PARAMETERS: InternalObject - An ACPI internal object + * ObjLength - Where the length will be returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to determine the space required to + * contain an object for return to an API user. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtGetObjectSize ( + ACPI_OPERAND_OBJECT *InternalObject, + ACPI_SIZE *ObjLength) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + if ((ACPI_GET_DESCRIPTOR_TYPE (InternalObject) == + ACPI_DESC_TYPE_OPERAND) && + (InternalObject->Common.Type == ACPI_TYPE_PACKAGE)) + { + Status = AcpiUtGetPackageObjectSize (InternalObject, ObjLength); + } + else + { + Status = AcpiUtGetSimpleObjectSize (InternalObject, ObjLength); + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/components/utilities/utosi.c b/third_party/lib/acpica/source/components/utilities/utosi.c new file mode 100644 index 000000000..674fe364d --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utosi.c @@ -0,0 +1,536 @@ +/****************************************************************************** + * + * Module Name: utosi - Support for the _OSI predefined control method + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utosi") + + +/****************************************************************************** + * + * ACPICA policy for new _OSI strings: + * + * It is the stated policy of ACPICA that new _OSI strings will be integrated + * into this module as soon as possible after they are defined. It is strongly + * recommended that all ACPICA hosts mirror this policy and integrate any + * changes to this module as soon as possible. There are several historical + * reasons behind this policy: + * + * 1) New BIOSs tend to test only the case where the host responds TRUE to + * the latest version of Windows, which would respond to the latest/newest + * _OSI string. Not responding TRUE to the latest version of Windows will + * risk executing untested code paths throughout the DSDT and SSDTs. + * + * 2) If a new _OSI string is recognized only after a significant delay, this + * has the potential to cause problems on existing working machines because + * of the possibility that a new and different path through the ASL code + * will be executed. + * + * 3) New _OSI strings are tending to come out about once per year. A delay + * in recognizing a new string for a significant amount of time risks the + * release of another string which only compounds the initial problem. + * + *****************************************************************************/ + + +/* + * Strings supported by the _OSI predefined control method (which is + * implemented internally within this module.) + * + * March 2009: Removed "Linux" as this host no longer wants to respond true + * for this string. Basically, the only safe OS strings are windows-related + * and in many or most cases represent the only test path within the + * BIOS-provided ASL code. + * + * The last element of each entry is used to track the newest version of + * Windows that the BIOS has requested. + */ +static ACPI_INTERFACE_INFO AcpiDefaultSupportedInterfaces[] = +{ + /* Operating System Vendor Strings */ + + {"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000}, /* Windows 2000 */ + {"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */ + {"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */ + {"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */ + {"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */ + {"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */ + {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */ + {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */ + {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */ + {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */ + {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ + {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ + {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ + {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ + + /* Feature Group Strings */ + + {"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0}, + + /* + * All "optional" feature group strings (features that are implemented + * by the host) should be dynamically modified to VALID by the host via + * AcpiInstallInterface or AcpiUpdateInterfaces. Such optional feature + * group strings are set as INVALID by default here. + */ + + {"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, + {"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0} +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtInitializeInterfaces + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize the global _OSI supported interfaces list + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtInitializeInterfaces ( + void) +{ + ACPI_STATUS Status; + UINT32 i; + + + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + AcpiGbl_SupportedInterfaces = AcpiDefaultSupportedInterfaces; + + /* Link the static list of supported interfaces */ + + for (i = 0; + i < (ACPI_ARRAY_LENGTH (AcpiDefaultSupportedInterfaces) - 1); + i++) + { + AcpiDefaultSupportedInterfaces[i].Next = + &AcpiDefaultSupportedInterfaces[(ACPI_SIZE) i + 1]; + } + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtInterfaceTerminate + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Delete all interfaces in the global list. Sets + * AcpiGbl_SupportedInterfaces to NULL. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtInterfaceTerminate ( + void) +{ + ACPI_STATUS Status; + ACPI_INTERFACE_INFO *NextInterface; + + + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + NextInterface = AcpiGbl_SupportedInterfaces; + while (NextInterface) + { + AcpiGbl_SupportedInterfaces = NextInterface->Next; + + if (NextInterface->Flags & ACPI_OSI_DYNAMIC) + { + /* Only interfaces added at runtime can be freed */ + + ACPI_FREE (NextInterface->Name); + ACPI_FREE (NextInterface); + } + else + { + /* Interface is in static list. Reset it to invalid or valid. */ + + if (NextInterface->Flags & ACPI_OSI_DEFAULT_INVALID) + { + NextInterface->Flags |= ACPI_OSI_INVALID; + } + else + { + NextInterface->Flags &= ~ACPI_OSI_INVALID; + } + } + + NextInterface = AcpiGbl_SupportedInterfaces; + } + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtInstallInterface + * + * PARAMETERS: InterfaceName - The interface to install + * + * RETURN: Status + * + * DESCRIPTION: Install the interface into the global interface list. + * Caller MUST hold AcpiGbl_OsiMutex + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtInstallInterface ( + ACPI_STRING InterfaceName) +{ + ACPI_INTERFACE_INFO *InterfaceInfo; + + + /* Allocate info block and space for the name string */ + + InterfaceInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_INTERFACE_INFO)); + if (!InterfaceInfo) + { + return (AE_NO_MEMORY); + } + + InterfaceInfo->Name = ACPI_ALLOCATE_ZEROED (strlen (InterfaceName) + 1); + if (!InterfaceInfo->Name) + { + ACPI_FREE (InterfaceInfo); + return (AE_NO_MEMORY); + } + + /* Initialize new info and insert at the head of the global list */ + + strcpy (InterfaceInfo->Name, InterfaceName); + InterfaceInfo->Flags = ACPI_OSI_DYNAMIC; + InterfaceInfo->Next = AcpiGbl_SupportedInterfaces; + + AcpiGbl_SupportedInterfaces = InterfaceInfo; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtRemoveInterface + * + * PARAMETERS: InterfaceName - The interface to remove + * + * RETURN: Status + * + * DESCRIPTION: Remove the interface from the global interface list. + * Caller MUST hold AcpiGbl_OsiMutex + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtRemoveInterface ( + ACPI_STRING InterfaceName) +{ + ACPI_INTERFACE_INFO *PreviousInterface; + ACPI_INTERFACE_INFO *NextInterface; + + + PreviousInterface = NextInterface = AcpiGbl_SupportedInterfaces; + while (NextInterface) + { + if (!strcmp (InterfaceName, NextInterface->Name)) + { + /* + * Found: name is in either the static list + * or was added at runtime + */ + if (NextInterface->Flags & ACPI_OSI_DYNAMIC) + { + /* Interface was added dynamically, remove and free it */ + + if (PreviousInterface == NextInterface) + { + AcpiGbl_SupportedInterfaces = NextInterface->Next; + } + else + { + PreviousInterface->Next = NextInterface->Next; + } + + ACPI_FREE (NextInterface->Name); + ACPI_FREE (NextInterface); + } + else + { + /* + * Interface is in static list. If marked invalid, then + * it does not actually exist. Else, mark it invalid. + */ + if (NextInterface->Flags & ACPI_OSI_INVALID) + { + return (AE_NOT_EXIST); + } + + NextInterface->Flags |= ACPI_OSI_INVALID; + } + + return (AE_OK); + } + + PreviousInterface = NextInterface; + NextInterface = NextInterface->Next; + } + + /* Interface was not found */ + + return (AE_NOT_EXIST); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtUpdateInterfaces + * + * PARAMETERS: Action - Actions to be performed during the + * update + * + * RETURN: Status + * + * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor + * strings or/and feature group strings. + * Caller MUST hold AcpiGbl_OsiMutex + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtUpdateInterfaces ( + UINT8 Action) +{ + ACPI_INTERFACE_INFO *NextInterface; + + + NextInterface = AcpiGbl_SupportedInterfaces; + while (NextInterface) + { + if (((NextInterface->Flags & ACPI_OSI_FEATURE) && + (Action & ACPI_FEATURE_STRINGS)) || + (!(NextInterface->Flags & ACPI_OSI_FEATURE) && + (Action & ACPI_VENDOR_STRINGS))) + { + if (Action & ACPI_DISABLE_INTERFACES) + { + /* Mark the interfaces as invalid */ + + NextInterface->Flags |= ACPI_OSI_INVALID; + } + else + { + /* Mark the interfaces as valid */ + + NextInterface->Flags &= ~ACPI_OSI_INVALID; + } + } + + NextInterface = NextInterface->Next; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetInterface + * + * PARAMETERS: InterfaceName - The interface to find + * + * RETURN: ACPI_INTERFACE_INFO if found. NULL if not found. + * + * DESCRIPTION: Search for the specified interface name in the global list. + * Caller MUST hold AcpiGbl_OsiMutex + * + ******************************************************************************/ + +ACPI_INTERFACE_INFO * +AcpiUtGetInterface ( + ACPI_STRING InterfaceName) +{ + ACPI_INTERFACE_INFO *NextInterface; + + + NextInterface = AcpiGbl_SupportedInterfaces; + while (NextInterface) + { + if (!strcmp (InterfaceName, NextInterface->Name)) + { + return (NextInterface); + } + + NextInterface = NextInterface->Next; + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtOsiImplementation + * + * PARAMETERS: WalkState - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Implementation of the _OSI predefined control method. When + * an invocation of _OSI is encountered in the system AML, + * control is transferred to this function. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtOsiImplementation ( + ACPI_WALK_STATE *WalkState) +{ + ACPI_OPERAND_OBJECT *StringDesc; + ACPI_OPERAND_OBJECT *ReturnDesc; + ACPI_INTERFACE_INFO *InterfaceInfo; + ACPI_INTERFACE_HANDLER InterfaceHandler; + ACPI_STATUS Status; + UINT32 ReturnValue; + + + ACPI_FUNCTION_TRACE (UtOsiImplementation); + + + /* Validate the string input argument (from the AML caller) */ + + StringDesc = WalkState->Arguments[0].Object; + if (!StringDesc || + (StringDesc->Common.Type != ACPI_TYPE_STRING)) + { + return_ACPI_STATUS (AE_TYPE); + } + + /* Create a return object */ + + ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); + if (!ReturnDesc) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Default return value is 0, NOT SUPPORTED */ + + ReturnValue = 0; + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + AcpiUtRemoveReference (ReturnDesc); + return_ACPI_STATUS (Status); + } + + /* Lookup the interface in the global _OSI list */ + + InterfaceInfo = AcpiUtGetInterface (StringDesc->String.Pointer); + if (InterfaceInfo && + !(InterfaceInfo->Flags & ACPI_OSI_INVALID)) + { + /* + * The interface is supported. + * Update the OsiData if necessary. We keep track of the latest + * version of Windows that has been requested by the BIOS. + */ + if (InterfaceInfo->Value > AcpiGbl_OsiData) + { + AcpiGbl_OsiData = InterfaceInfo->Value; + } + + ReturnValue = ACPI_UINT32_MAX; + } + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + + /* + * Invoke an optional _OSI interface handler. The host OS may wish + * to do some interface-specific handling. For example, warn about + * certain interfaces or override the true/false support value. + */ + InterfaceHandler = AcpiGbl_InterfaceHandler; + if (InterfaceHandler) + { + ReturnValue = InterfaceHandler ( + StringDesc->String.Pointer, ReturnValue); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, + "ACPI: BIOS _OSI(\"%s\") is %ssupported\n", + StringDesc->String.Pointer, ReturnValue == 0 ? "not " : "")); + + /* Complete the return object */ + + ReturnDesc->Integer.Value = ReturnValue; + WalkState->ReturnDesc = ReturnDesc; + return_ACPI_STATUS (AE_OK); +} diff --git a/third_party/lib/acpica/source/components/utilities/utownerid.c b/third_party/lib/acpica/source/components/utilities/utownerid.c new file mode 100644 index 000000000..8fe67bc33 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utownerid.c @@ -0,0 +1,239 @@ +/******************************************************************************* + * + * Module Name: utownerid - Support for Table/Method Owner IDs + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utownerid") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAllocateOwnerId + * + * PARAMETERS: OwnerId - Where the new owner ID is returned + * + * RETURN: Status + * + * DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to + * track objects created by the table or method, to be deleted + * when the method exits or the table is unloaded. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtAllocateOwnerId ( + ACPI_OWNER_ID *OwnerId) +{ + UINT32 i; + UINT32 j; + UINT32 k; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtAllocateOwnerId); + + + /* Guard against multiple allocations of ID to the same location */ + + if (*OwnerId) + { + ACPI_ERROR ((AE_INFO, + "Owner ID [0x%2.2X] already exists", *OwnerId)); + return_ACPI_STATUS (AE_ALREADY_EXISTS); + } + + /* Mutex for the global ID mask */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Find a free owner ID, cycle through all possible IDs on repeated + * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index + * may have to be scanned twice. + */ + for (i = 0, j = AcpiGbl_LastOwnerIdIndex; + i < (ACPI_NUM_OWNERID_MASKS + 1); + i++, j++) + { + if (j >= ACPI_NUM_OWNERID_MASKS) + { + j = 0; /* Wraparound to start of mask array */ + } + + for (k = AcpiGbl_NextOwnerIdOffset; k < 32; k++) + { + if (AcpiGbl_OwnerIdMask[j] == ACPI_UINT32_MAX) + { + /* There are no free IDs in this mask */ + + break; + } + + if (!(AcpiGbl_OwnerIdMask[j] & (1 << k))) + { + /* + * Found a free ID. The actual ID is the bit index plus one, + * making zero an invalid Owner ID. Save this as the last ID + * allocated and update the global ID mask. + */ + AcpiGbl_OwnerIdMask[j] |= (1 << k); + + AcpiGbl_LastOwnerIdIndex = (UINT8) j; + AcpiGbl_NextOwnerIdOffset = (UINT8) (k + 1); + + /* + * Construct encoded ID from the index and bit position + * + * Note: Last [j].k (bit 255) is never used and is marked + * permanently allocated (prevents +1 overflow) + */ + *OwnerId = (ACPI_OWNER_ID) ((k + 1) + ACPI_MUL_32 (j)); + + ACPI_DEBUG_PRINT ((ACPI_DB_VALUES, + "Allocated OwnerId: %2.2X\n", (unsigned int) *OwnerId)); + goto Exit; + } + } + + AcpiGbl_NextOwnerIdOffset = 0; + } + + /* + * All OwnerIds have been allocated. This typically should + * not happen since the IDs are reused after deallocation. The IDs are + * allocated upon table load (one per table) and method execution, and + * they are released when a table is unloaded or a method completes + * execution. + * + * If this error happens, there may be very deep nesting of invoked + * control methods, or there may be a bug where the IDs are not released. + */ + Status = AE_OWNER_ID_LIMIT; + ACPI_ERROR ((AE_INFO, + "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT")); + +Exit: + (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtReleaseOwnerId + * + * PARAMETERS: OwnerIdPtr - Pointer to a previously allocated OwnerID + * + * RETURN: None. No error is returned because we are either exiting a + * control method or unloading a table. Either way, we would + * ignore any error anyway. + * + * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 + * + ******************************************************************************/ + +void +AcpiUtReleaseOwnerId ( + ACPI_OWNER_ID *OwnerIdPtr) +{ + ACPI_OWNER_ID OwnerId = *OwnerIdPtr; + ACPI_STATUS Status; + UINT32 Index; + UINT32 Bit; + + + ACPI_FUNCTION_TRACE_U32 (UtReleaseOwnerId, OwnerId); + + + /* Always clear the input OwnerId (zero is an invalid ID) */ + + *OwnerIdPtr = 0; + + /* Zero is not a valid OwnerID */ + + if (OwnerId == 0) + { + ACPI_ERROR ((AE_INFO, "Invalid OwnerId: 0x%2.2X", OwnerId)); + return_VOID; + } + + /* Mutex for the global ID mask */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (Status)) + { + return_VOID; + } + + /* Normalize the ID to zero */ + + OwnerId--; + + /* Decode ID to index/offset pair */ + + Index = ACPI_DIV_32 (OwnerId); + Bit = 1 << ACPI_MOD_32 (OwnerId); + + /* Free the owner ID only if it is valid */ + + if (AcpiGbl_OwnerIdMask[Index] & Bit) + { + AcpiGbl_OwnerIdMask[Index] ^= Bit; + } + else + { + ACPI_ERROR ((AE_INFO, + "Release of non-allocated OwnerId: 0x%2.2X", OwnerId + 1)); + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES); + return_VOID; +} diff --git a/third_party/lib/acpica/source/components/utilities/utpredef.c b/third_party/lib/acpica/source/components/utilities/utpredef.c new file mode 100644 index 000000000..0f6658ecf --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utpredef.c @@ -0,0 +1,452 @@ +/****************************************************************************** + * + * Module Name: utpredef - support functions for predefined names + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acpredef.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utpredef") + + +/* + * Names for the types that can be returned by the predefined objects. + * Used for warning messages. Must be in the same order as the ACPI_RTYPEs + */ +static const char *UtRtypeNames[] = +{ + "/Integer", + "/String", + "/Buffer", + "/Package", + "/Reference", +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetNextPredefinedMethod + * + * PARAMETERS: ThisName - Entry in the predefined method/name table + * + * RETURN: Pointer to next entry in predefined table. + * + * DESCRIPTION: Get the next entry in the predefine method table. Handles the + * cases where a package info entry follows a method name that + * returns a package. + * + ******************************************************************************/ + +const ACPI_PREDEFINED_INFO * +AcpiUtGetNextPredefinedMethod ( + const ACPI_PREDEFINED_INFO *ThisName) +{ + + /* + * Skip next entry in the table if this name returns a Package + * (next entry contains the package info) + */ + if ((ThisName->Info.ExpectedBtypes & ACPI_RTYPE_PACKAGE) && + (ThisName->Info.ExpectedBtypes != ACPI_RTYPE_ALL)) + { + ThisName++; + } + + ThisName++; + return (ThisName); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtMatchPredefinedMethod + * + * PARAMETERS: Name - Name to find + * + * RETURN: Pointer to entry in predefined table. NULL indicates not found. + * + * DESCRIPTION: Check an object name against the predefined object list. + * + ******************************************************************************/ + +const ACPI_PREDEFINED_INFO * +AcpiUtMatchPredefinedMethod ( + char *Name) +{ + const ACPI_PREDEFINED_INFO *ThisName; + + + /* Quick check for a predefined name, first character must be underscore */ + + if (Name[0] != '_') + { + return (NULL); + } + + /* Search info table for a predefined method/object name */ + + ThisName = AcpiGbl_PredefinedMethods; + while (ThisName->Info.Name[0]) + { + if (ACPI_COMPARE_NAME (Name, ThisName->Info.Name)) + { + return (ThisName); + } + + ThisName = AcpiUtGetNextPredefinedMethod (ThisName); + } + + return (NULL); /* Not found */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetExpectedReturnTypes + * + * PARAMETERS: Buffer - Where the formatted string is returned + * ExpectedBTypes - Bitfield of expected data types + * + * RETURN: Formatted string in Buffer. + * + * DESCRIPTION: Format the expected object types into a printable string. + * + ******************************************************************************/ + +void +AcpiUtGetExpectedReturnTypes ( + char *Buffer, + UINT32 ExpectedBtypes) +{ + UINT32 ThisRtype; + UINT32 i; + UINT32 j; + + + if (!ExpectedBtypes) + { + strcpy (Buffer, "NONE"); + return; + } + + j = 1; + Buffer[0] = 0; + ThisRtype = ACPI_RTYPE_INTEGER; + + for (i = 0; i < ACPI_NUM_RTYPES; i++) + { + /* If one of the expected types, concatenate the name of this type */ + + if (ExpectedBtypes & ThisRtype) + { + strcat (Buffer, &UtRtypeNames[i][j]); + j = 0; /* Use name separator from now on */ + } + + ThisRtype <<= 1; /* Next Rtype */ + } +} + + +/******************************************************************************* + * + * The remaining functions are used by iASL and AcpiHelp only + * + ******************************************************************************/ + +#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP) +#include +#include + +/* Local prototypes */ + +static UINT32 +AcpiUtGetArgumentTypes ( + char *Buffer, + UINT16 ArgumentTypes); + + +/* Types that can be returned externally by a predefined name */ + +static const char *UtExternalTypeNames[] = /* Indexed by ACPI_TYPE_* */ +{ + ", UNSUPPORTED-TYPE", + ", Integer", + ", String", + ", Buffer", + ", Package" +}; + +/* Bit widths for resource descriptor predefined names */ + +static const char *UtResourceTypeNames[] = +{ + "/1", + "/2", + "/3", + "/8", + "/16", + "/32", + "/64", + "/variable", +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtMatchResourceName + * + * PARAMETERS: Name - Name to find + * + * RETURN: Pointer to entry in the resource table. NULL indicates not + * found. + * + * DESCRIPTION: Check an object name against the predefined resource + * descriptor object list. + * + ******************************************************************************/ + +const ACPI_PREDEFINED_INFO * +AcpiUtMatchResourceName ( + char *Name) +{ + const ACPI_PREDEFINED_INFO *ThisName; + + + /* + * Quick check for a predefined name, first character must + * be underscore + */ + if (Name[0] != '_') + { + return (NULL); + } + + /* Search info table for a predefined method/object name */ + + ThisName = AcpiGbl_ResourceNames; + while (ThisName->Info.Name[0]) + { + if (ACPI_COMPARE_NAME (Name, ThisName->Info.Name)) + { + return (ThisName); + } + + ThisName++; + } + + return (NULL); /* Not found */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDisplayPredefinedMethod + * + * PARAMETERS: Buffer - Scratch buffer for this function + * ThisName - Entry in the predefined method/name table + * MultiLine - TRUE if output should be on >1 line + * + * RETURN: None + * + * DESCRIPTION: Display information about a predefined method. Number and + * type of the input arguments, and expected type(s) for the + * return value, if any. + * + ******************************************************************************/ + +void +AcpiUtDisplayPredefinedMethod ( + char *Buffer, + const ACPI_PREDEFINED_INFO *ThisName, + BOOLEAN MultiLine) +{ + UINT32 ArgCount; + + /* + * Get the argument count and the string buffer + * containing all argument types + */ + ArgCount = AcpiUtGetArgumentTypes (Buffer, + ThisName->Info.ArgumentList); + + if (MultiLine) + { + printf (" "); + } + + printf ("%4.4s Requires %s%u argument%s", + ThisName->Info.Name, + (ThisName->Info.ArgumentList & ARG_COUNT_IS_MINIMUM) ? + "(at least) " : "", + ArgCount, ArgCount != 1 ? "s" : ""); + + /* Display the types for any arguments */ + + if (ArgCount > 0) + { + printf (" (%s)", Buffer); + } + + if (MultiLine) + { + printf ("\n "); + } + + /* Get the return value type(s) allowed */ + + if (ThisName->Info.ExpectedBtypes) + { + AcpiUtGetExpectedReturnTypes (Buffer, ThisName->Info.ExpectedBtypes); + printf (" Return value types: %s\n", Buffer); + } + else + { + printf (" No return value\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetArgumentTypes + * + * PARAMETERS: Buffer - Where to return the formatted types + * ArgumentTypes - Types field for this method + * + * RETURN: Count - the number of arguments required for this method + * + * DESCRIPTION: Format the required data types for this method (Integer, + * String, Buffer, or Package) and return the required argument + * count. + * + ******************************************************************************/ + +static UINT32 +AcpiUtGetArgumentTypes ( + char *Buffer, + UINT16 ArgumentTypes) +{ + UINT16 ThisArgumentType; + UINT16 SubIndex; + UINT16 ArgCount; + UINT32 i; + + + *Buffer = 0; + SubIndex = 2; + + /* First field in the types list is the count of args to follow */ + + ArgCount = METHOD_GET_ARG_COUNT (ArgumentTypes); + if (ArgCount > METHOD_PREDEF_ARGS_MAX) + { + printf ("**** Invalid argument count (%u) " + "in predefined info structure\n", ArgCount); + return (ArgCount); + } + + /* Get each argument from the list, convert to ascii, store to buffer */ + + for (i = 0; i < ArgCount; i++) + { + ThisArgumentType = METHOD_GET_NEXT_TYPE (ArgumentTypes); + + if (!ThisArgumentType || (ThisArgumentType > METHOD_MAX_ARG_TYPE)) + { + printf ("**** Invalid argument type (%u) " + "in predefined info structure\n", ThisArgumentType); + return (ArgCount); + } + + strcat (Buffer, UtExternalTypeNames[ThisArgumentType] + SubIndex); + SubIndex = 0; + } + + return (ArgCount); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetResourceBitWidth + * + * PARAMETERS: Buffer - Where the formatted string is returned + * Types - Bitfield of expected data types + * + * RETURN: Count of return types. Formatted string in Buffer. + * + * DESCRIPTION: Format the resource bit widths into a printable string. + * + ******************************************************************************/ + +UINT32 +AcpiUtGetResourceBitWidth ( + char *Buffer, + UINT16 Types) +{ + UINT32 i; + UINT16 SubIndex; + UINT32 Found; + + + *Buffer = 0; + SubIndex = 1; + Found = 0; + + for (i = 0; i < NUM_RESOURCE_WIDTHS; i++) + { + if (Types & 1) + { + strcat (Buffer, &(UtResourceTypeNames[i][SubIndex])); + SubIndex = 0; + Found++; + } + + Types >>= 1; + } + + return (Found); +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utprint.c b/third_party/lib/acpica/source/components/utilities/utprint.c new file mode 100644 index 000000000..7656924d0 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utprint.c @@ -0,0 +1,818 @@ +/****************************************************************************** + * + * Module Name: utprint - Formatted printing routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utprint") + + +#define ACPI_FORMAT_SIGN 0x01 +#define ACPI_FORMAT_SIGN_PLUS 0x02 +#define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04 +#define ACPI_FORMAT_ZERO 0x08 +#define ACPI_FORMAT_LEFT 0x10 +#define ACPI_FORMAT_UPPER 0x20 +#define ACPI_FORMAT_PREFIX 0x40 + + +/* Local prototypes */ + +static ACPI_SIZE +AcpiUtBoundStringLength ( + const char *String, + ACPI_SIZE Count); + +static char * +AcpiUtBoundStringOutput ( + char *String, + const char *End, + char c); + +static char * +AcpiUtFormatNumber ( + char *String, + char *End, + UINT64 Number, + UINT8 Base, + INT32 Width, + INT32 Precision, + UINT8 Type); + +static char * +AcpiUtPutNumber ( + char *String, + UINT64 Number, + UINT8 Base, + BOOLEAN Upper); + + +/* Module globals */ + +static const char AcpiGbl_LowerHexDigits[] = "0123456789abcdef"; +static const char AcpiGbl_UpperHexDigits[] = "0123456789ABCDEF"; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtBoundStringLength + * + * PARAMETERS: String - String with boundary + * Count - Boundary of the string + * + * RETURN: Length of the string. Less than or equal to Count. + * + * DESCRIPTION: Calculate the length of a string with boundary. + * + ******************************************************************************/ + +static ACPI_SIZE +AcpiUtBoundStringLength ( + const char *String, + ACPI_SIZE Count) +{ + UINT32 Length = 0; + + + while (*String && Count) + { + Length++; + String++; + Count--; + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtBoundStringOutput + * + * PARAMETERS: String - String with boundary + * End - Boundary of the string + * c - Character to be output to the string + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Output a character into a string with boundary check. + * + ******************************************************************************/ + +static char * +AcpiUtBoundStringOutput ( + char *String, + const char *End, + char c) +{ + + if (String < End) + { + *String = c; + } + + ++String; + return (String); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPutNumber + * + * PARAMETERS: String - Buffer to hold reverse-ordered string + * Number - Integer to be converted + * Base - Base of the integer + * Upper - Whether or not using upper cased digits + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Convert an integer into a string, note that, the string holds a + * reversed ordered number without the trailing zero. + * + ******************************************************************************/ + +static char * +AcpiUtPutNumber ( + char *String, + UINT64 Number, + UINT8 Base, + BOOLEAN Upper) +{ + const char *Digits; + UINT64 DigitIndex; + char *Pos; + + + Pos = String; + Digits = Upper ? AcpiGbl_UpperHexDigits : AcpiGbl_LowerHexDigits; + + if (Number == 0) + { + *(Pos++) = '0'; + } + else + { + while (Number) + { + (void) AcpiUtDivide (Number, Base, &Number, &DigitIndex); + *(Pos++) = Digits[DigitIndex]; + } + } + + /* *(Pos++) = '0'; */ + return (Pos); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtScanNumber + * + * PARAMETERS: String - String buffer + * NumberPtr - Where the number is returned + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Scan a string for a decimal integer. + * + ******************************************************************************/ + +const char * +AcpiUtScanNumber ( + const char *String, + UINT64 *NumberPtr) +{ + UINT64 Number = 0; + + + while (isdigit ((int) *String)) + { + Number *= 10; + Number += *(String++) - '0'; + } + + *NumberPtr = Number; + return (String); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPrintNumber + * + * PARAMETERS: String - String buffer + * Number - The number to be converted + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Print a decimal integer into a string. + * + ******************************************************************************/ + +const char * +AcpiUtPrintNumber ( + char *String, + UINT64 Number) +{ + char AsciiString[20]; + const char *Pos1; + char *Pos2; + + + Pos1 = AcpiUtPutNumber (AsciiString, Number, 10, FALSE); + Pos2 = String; + + while (Pos1 != AsciiString) + { + *(Pos2++) = *(--Pos1); + } + + *Pos2 = 0; + return (String); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtFormatNumber + * + * PARAMETERS: String - String buffer with boundary + * End - Boundary of the string + * Number - The number to be converted + * Base - Base of the integer + * Width - Field width + * Precision - Precision of the integer + * Type - Special printing flags + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Print an integer into a string with any base and any precision. + * + ******************************************************************************/ + +static char * +AcpiUtFormatNumber ( + char *String, + char *End, + UINT64 Number, + UINT8 Base, + INT32 Width, + INT32 Precision, + UINT8 Type) +{ + char *Pos; + char Sign; + char Zero; + BOOLEAN NeedPrefix; + BOOLEAN Upper; + INT32 i; + char ReversedString[66]; + + + /* Parameter validation */ + + if (Base < 2 || Base > 16) + { + return (NULL); + } + + if (Type & ACPI_FORMAT_LEFT) + { + Type &= ~ACPI_FORMAT_ZERO; + } + + NeedPrefix = ((Type & ACPI_FORMAT_PREFIX) && Base != 10) ? TRUE : FALSE; + Upper = (Type & ACPI_FORMAT_UPPER) ? TRUE : FALSE; + Zero = (Type & ACPI_FORMAT_ZERO) ? '0' : ' '; + + /* Calculate size according to sign and prefix */ + + Sign = '\0'; + if (Type & ACPI_FORMAT_SIGN) + { + if ((INT64) Number < 0) + { + Sign = '-'; + Number = - (INT64) Number; + Width--; + } + else if (Type & ACPI_FORMAT_SIGN_PLUS) + { + Sign = '+'; + Width--; + } + else if (Type & ACPI_FORMAT_SIGN_PLUS_SPACE) + { + Sign = ' '; + Width--; + } + } + if (NeedPrefix) + { + Width--; + if (Base == 16) + { + Width--; + } + } + + /* Generate full string in reverse order */ + + Pos = AcpiUtPutNumber (ReversedString, Number, Base, Upper); + i = ACPI_PTR_DIFF (Pos, ReversedString); + + /* Printing 100 using %2d gives "100", not "00" */ + + if (i > Precision) + { + Precision = i; + } + + Width -= Precision; + + /* Output the string */ + + if (!(Type & (ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT))) + { + while (--Width >= 0) + { + String = AcpiUtBoundStringOutput (String, End, ' '); + } + } + if (Sign) + { + String = AcpiUtBoundStringOutput (String, End, Sign); + } + if (NeedPrefix) + { + String = AcpiUtBoundStringOutput (String, End, '0'); + if (Base == 16) + { + String = AcpiUtBoundStringOutput ( + String, End, Upper ? 'X' : 'x'); + } + } + if (!(Type & ACPI_FORMAT_LEFT)) + { + while (--Width >= 0) + { + String = AcpiUtBoundStringOutput (String, End, Zero); + } + } + + while (i <= --Precision) + { + String = AcpiUtBoundStringOutput (String, End, '0'); + } + while (--i >= 0) + { + String = AcpiUtBoundStringOutput (String, End, + ReversedString[i]); + } + while (--Width >= 0) + { + String = AcpiUtBoundStringOutput (String, End, ' '); + } + + return (String); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtVsnprintf + * + * PARAMETERS: String - String with boundary + * Size - Boundary of the string + * Format - Standard printf format + * Args - Argument list + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a string using argument list pointer. + * + ******************************************************************************/ + +int +AcpiUtVsnprintf ( + char *String, + ACPI_SIZE Size, + const char *Format, + va_list Args) +{ + UINT8 Base; + UINT8 Type; + INT32 Width; + INT32 Precision; + char Qualifier; + UINT64 Number; + char *Pos; + char *End; + char c; + const char *s; + const void *p; + INT32 Length; + int i; + + + Pos = String; + End = String + Size; + + for (; *Format; ++Format) + { + if (*Format != '%') + { + Pos = AcpiUtBoundStringOutput (Pos, End, *Format); + continue; + } + + Type = 0; + Base = 10; + + /* Process sign */ + + do + { + ++Format; + if (*Format == '#') + { + Type |= ACPI_FORMAT_PREFIX; + } + else if (*Format == '0') + { + Type |= ACPI_FORMAT_ZERO; + } + else if (*Format == '+') + { + Type |= ACPI_FORMAT_SIGN_PLUS; + } + else if (*Format == ' ') + { + Type |= ACPI_FORMAT_SIGN_PLUS_SPACE; + } + else if (*Format == '-') + { + Type |= ACPI_FORMAT_LEFT; + } + else + { + break; + } + + } while (1); + + /* Process width */ + + Width = -1; + if (isdigit ((int) *Format)) + { + Format = AcpiUtScanNumber (Format, &Number); + Width = (INT32) Number; + } + else if (*Format == '*') + { + ++Format; + Width = va_arg (Args, int); + if (Width < 0) + { + Width = -Width; + Type |= ACPI_FORMAT_LEFT; + } + } + + /* Process precision */ + + Precision = -1; + if (*Format == '.') + { + ++Format; + if (isdigit ((int) *Format)) + { + Format = AcpiUtScanNumber (Format, &Number); + Precision = (INT32) Number; + } + else if (*Format == '*') + { + ++Format; + Precision = va_arg (Args, int); + } + + if (Precision < 0) + { + Precision = 0; + } + } + + /* Process qualifier */ + + Qualifier = -1; + if (*Format == 'h' || *Format == 'l' || *Format == 'L') + { + Qualifier = *Format; + ++Format; + + if (Qualifier == 'l' && *Format == 'l') + { + Qualifier = 'L'; + ++Format; + } + } + + switch (*Format) + { + case '%': + + Pos = AcpiUtBoundStringOutput (Pos, End, '%'); + continue; + + case 'c': + + if (!(Type & ACPI_FORMAT_LEFT)) + { + while (--Width > 0) + { + Pos = AcpiUtBoundStringOutput (Pos, End, ' '); + } + } + + c = (char) va_arg (Args, int); + Pos = AcpiUtBoundStringOutput (Pos, End, c); + + while (--Width > 0) + { + Pos = AcpiUtBoundStringOutput (Pos, End, ' '); + } + continue; + + case 's': + + s = va_arg (Args, char *); + if (!s) + { + s = ""; + } + Length = AcpiUtBoundStringLength (s, Precision); + if (!(Type & ACPI_FORMAT_LEFT)) + { + while (Length < Width--) + { + Pos = AcpiUtBoundStringOutput (Pos, End, ' '); + } + } + + for (i = 0; i < Length; ++i) + { + Pos = AcpiUtBoundStringOutput (Pos, End, *s); + ++s; + } + + while (Length < Width--) + { + Pos = AcpiUtBoundStringOutput (Pos, End, ' '); + } + continue; + + case 'o': + + Base = 8; + break; + + case 'X': + + Type |= ACPI_FORMAT_UPPER; + + case 'x': + + Base = 16; + break; + + case 'd': + case 'i': + + Type |= ACPI_FORMAT_SIGN; + + case 'u': + + break; + + case 'p': + + if (Width == -1) + { + Width = 2 * sizeof (void *); + Type |= ACPI_FORMAT_ZERO; + } + + p = va_arg (Args, void *); + Pos = AcpiUtFormatNumber ( + Pos, End, ACPI_TO_INTEGER (p), 16, Width, Precision, Type); + continue; + + default: + + Pos = AcpiUtBoundStringOutput (Pos, End, '%'); + if (*Format) + { + Pos = AcpiUtBoundStringOutput (Pos, End, *Format); + } + else + { + --Format; + } + continue; + } + + if (Qualifier == 'L') + { + Number = va_arg (Args, UINT64); + if (Type & ACPI_FORMAT_SIGN) + { + Number = (INT64) Number; + } + } + else if (Qualifier == 'l') + { + Number = va_arg (Args, unsigned long); + if (Type & ACPI_FORMAT_SIGN) + { + Number = (INT32) Number; + } + } + else if (Qualifier == 'h') + { + Number = (UINT16) va_arg (Args, int); + if (Type & ACPI_FORMAT_SIGN) + { + Number = (INT16) Number; + } + } + else + { + Number = va_arg (Args, unsigned int); + if (Type & ACPI_FORMAT_SIGN) + { + Number = (signed int) Number; + } + } + + Pos = AcpiUtFormatNumber (Pos, End, Number, Base, + Width, Precision, Type); + } + + if (Size > 0) + { + if (Pos < End) + { + *Pos = '\0'; + } + else + { + End[-1] = '\0'; + } + } + + return (ACPI_PTR_DIFF (Pos, String)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtSnprintf + * + * PARAMETERS: String - String with boundary + * Size - Boundary of the string + * Format, ... - Standard printf format + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a string. + * + ******************************************************************************/ + +int +AcpiUtSnprintf ( + char *String, + ACPI_SIZE Size, + const char *Format, + ...) +{ + va_list Args; + int Length; + + + va_start (Args, Format); + Length = AcpiUtVsnprintf (String, Size, Format, Args); + va_end (Args); + + return (Length); +} + + +#ifdef ACPI_APPLICATION +/******************************************************************************* + * + * FUNCTION: AcpiUtFileVprintf + * + * PARAMETERS: File - File descriptor + * Format - Standard printf format + * Args - Argument list + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a file using argument list pointer. + * + ******************************************************************************/ + +int +AcpiUtFileVprintf ( + ACPI_FILE File, + const char *Format, + va_list Args) +{ + ACPI_CPU_FLAGS Flags; + int Length; + + + Flags = AcpiOsAcquireLock (AcpiGbl_PrintLock); + Length = AcpiUtVsnprintf (AcpiGbl_PrintBuffer, + sizeof (AcpiGbl_PrintBuffer), Format, Args); + + (void) AcpiOsWriteFile (File, AcpiGbl_PrintBuffer, Length, 1); + AcpiOsReleaseLock (AcpiGbl_PrintLock, Flags); + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtFilePrintf + * + * PARAMETERS: File - File descriptor + * Format, ... - Standard printf format + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a file. + * + ******************************************************************************/ + +int +AcpiUtFilePrintf ( + ACPI_FILE File, + const char *Format, + ...) +{ + va_list Args; + int Length; + + + va_start (Args, Format); + Length = AcpiUtFileVprintf (File, Format, Args); + va_end (Args); + + return (Length); +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utresrc.c b/third_party/lib/acpica/source/components/utilities/utresrc.c new file mode 100644 index 000000000..8efae4297 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utresrc.c @@ -0,0 +1,925 @@ +/******************************************************************************* + * + * Module Name: utresrc - Resource management utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acresrc.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utresrc") + + +#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) + +/* + * Strings used to decode resource descriptors. + * Used by both the disassembler and the debugger resource dump routines + */ +const char *AcpiGbl_BmDecode[] = +{ + "NotBusMaster", + "BusMaster" +}; + +const char *AcpiGbl_ConfigDecode[] = +{ + "0 - Good Configuration", + "1 - Acceptable Configuration", + "2 - Suboptimal Configuration", + "3 - ***Invalid Configuration***", +}; + +const char *AcpiGbl_ConsumeDecode[] = +{ + "ResourceProducer", + "ResourceConsumer" +}; + +const char *AcpiGbl_DecDecode[] = +{ + "PosDecode", + "SubDecode" +}; + +const char *AcpiGbl_HeDecode[] = +{ + "Level", + "Edge" +}; + +const char *AcpiGbl_IoDecode[] = +{ + "Decode10", + "Decode16" +}; + +const char *AcpiGbl_LlDecode[] = +{ + "ActiveHigh", + "ActiveLow", + "ActiveBoth", + "Reserved" +}; + +const char *AcpiGbl_MaxDecode[] = +{ + "MaxNotFixed", + "MaxFixed" +}; + +const char *AcpiGbl_MemDecode[] = +{ + "NonCacheable", + "Cacheable", + "WriteCombining", + "Prefetchable" +}; + +const char *AcpiGbl_MinDecode[] = +{ + "MinNotFixed", + "MinFixed" +}; + +const char *AcpiGbl_MtpDecode[] = +{ + "AddressRangeMemory", + "AddressRangeReserved", + "AddressRangeACPI", + "AddressRangeNVS" +}; + +const char *AcpiGbl_RngDecode[] = +{ + "InvalidRanges", + "NonISAOnlyRanges", + "ISAOnlyRanges", + "EntireRange" +}; + +const char *AcpiGbl_RwDecode[] = +{ + "ReadOnly", + "ReadWrite" +}; + +const char *AcpiGbl_ShrDecode[] = +{ + "Exclusive", + "Shared", + "ExclusiveAndWake", /* ACPI 5.0 */ + "SharedAndWake" /* ACPI 5.0 */ +}; + +const char *AcpiGbl_SizDecode[] = +{ + "Transfer8", + "Transfer8_16", + "Transfer16", + "InvalidSize" +}; + +const char *AcpiGbl_TrsDecode[] = +{ + "DenseTranslation", + "SparseTranslation" +}; + +const char *AcpiGbl_TtpDecode[] = +{ + "TypeStatic", + "TypeTranslation" +}; + +const char *AcpiGbl_TypDecode[] = +{ + "Compatibility", + "TypeA", + "TypeB", + "TypeF" +}; + +const char *AcpiGbl_PpcDecode[] = +{ + "PullDefault", + "PullUp", + "PullDown", + "PullNone" +}; + +const char *AcpiGbl_IorDecode[] = +{ + "IoRestrictionNone", + "IoRestrictionInputOnly", + "IoRestrictionOutputOnly", + "IoRestrictionNoneAndPreserve" +}; + +const char *AcpiGbl_DtsDecode[] = +{ + "Width8bit", + "Width16bit", + "Width32bit", + "Width64bit", + "Width128bit", + "Width256bit", +}; + +/* GPIO connection type */ + +const char *AcpiGbl_CtDecode[] = +{ + "Interrupt", + "I/O" +}; + +/* Serial bus type */ + +const char *AcpiGbl_SbtDecode[] = +{ + "/* UNKNOWN serial bus type */", + "I2C", + "SPI", + "UART" +}; + +/* I2C serial bus access mode */ + +const char *AcpiGbl_AmDecode[] = +{ + "AddressingMode7Bit", + "AddressingMode10Bit" +}; + +/* I2C serial bus slave mode */ + +const char *AcpiGbl_SmDecode[] = +{ + "ControllerInitiated", + "DeviceInitiated" +}; + +/* SPI serial bus wire mode */ + +const char *AcpiGbl_WmDecode[] = +{ + "FourWireMode", + "ThreeWireMode" +}; + +/* SPI serial clock phase */ + +const char *AcpiGbl_CphDecode[] = +{ + "ClockPhaseFirst", + "ClockPhaseSecond" +}; + +/* SPI serial bus clock polarity */ + +const char *AcpiGbl_CpoDecode[] = +{ + "ClockPolarityLow", + "ClockPolarityHigh" +}; + +/* SPI serial bus device polarity */ + +const char *AcpiGbl_DpDecode[] = +{ + "PolarityLow", + "PolarityHigh" +}; + +/* UART serial bus endian */ + +const char *AcpiGbl_EdDecode[] = +{ + "LittleEndian", + "BigEndian" +}; + +/* UART serial bus bits per byte */ + +const char *AcpiGbl_BpbDecode[] = +{ + "DataBitsFive", + "DataBitsSix", + "DataBitsSeven", + "DataBitsEight", + "DataBitsNine", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */" +}; + +/* UART serial bus stop bits */ + +const char *AcpiGbl_SbDecode[] = +{ + "StopBitsZero", + "StopBitsOne", + "StopBitsOnePlusHalf", + "StopBitsTwo" +}; + +/* UART serial bus flow control */ + +const char *AcpiGbl_FcDecode[] = +{ + "FlowControlNone", + "FlowControlHardware", + "FlowControlXON", + "/* UNKNOWN flow control keyword */" +}; + +/* UART serial bus parity type */ + +const char *AcpiGbl_PtDecode[] = +{ + "ParityTypeNone", + "ParityTypeEven", + "ParityTypeOdd", + "ParityTypeMark", + "ParityTypeSpace", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */" +}; + +#endif + + +/* + * Base sizes of the raw AML resource descriptors, indexed by resource type. + * Zero indicates a reserved (and therefore invalid) resource type. + */ +const UINT8 AcpiGbl_ResourceAmlSizes[] = +{ + /* Small descriptors */ + + 0, + 0, + 0, + 0, + ACPI_AML_SIZE_SMALL (AML_RESOURCE_IRQ), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_DMA), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_START_DEPENDENT), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_DEPENDENT), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_IO), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_IO), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_DMA), + 0, + 0, + 0, + ACPI_AML_SIZE_SMALL (AML_RESOURCE_VENDOR_SMALL), + ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_TAG), + + /* Large descriptors */ + + 0, + ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY24), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_GENERIC_REGISTER), + 0, + ACPI_AML_SIZE_LARGE (AML_RESOURCE_VENDOR_LARGE), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY32), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_FIXED_MEMORY32), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS32), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS16), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_IRQ), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS64), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_ADDRESS64), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_GPIO), + 0, + ACPI_AML_SIZE_LARGE (AML_RESOURCE_COMMON_SERIALBUS), +}; + +const UINT8 AcpiGbl_ResourceAmlSerialBusSizes[] = +{ + 0, + ACPI_AML_SIZE_LARGE (AML_RESOURCE_I2C_SERIALBUS), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_SPI_SERIALBUS), + ACPI_AML_SIZE_LARGE (AML_RESOURCE_UART_SERIALBUS), +}; + + +/* + * Resource types, used to validate the resource length field. + * The length of fixed-length types must match exactly, variable + * lengths must meet the minimum required length, etc. + * Zero indicates a reserved (and therefore invalid) resource type. + */ +static const UINT8 AcpiGbl_ResourceTypes[] = +{ + /* Small descriptors */ + + 0, + 0, + 0, + 0, + ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */ + ACPI_FIXED_LENGTH, /* 05 DMA */ + ACPI_SMALL_VARIABLE_LENGTH, /* 06 StartDependentFunctions */ + ACPI_FIXED_LENGTH, /* 07 EndDependentFunctions */ + ACPI_FIXED_LENGTH, /* 08 IO */ + ACPI_FIXED_LENGTH, /* 09 FixedIO */ + ACPI_FIXED_LENGTH, /* 0A FixedDMA */ + 0, + 0, + 0, + ACPI_VARIABLE_LENGTH, /* 0E VendorShort */ + ACPI_FIXED_LENGTH, /* 0F EndTag */ + + /* Large descriptors */ + + 0, + ACPI_FIXED_LENGTH, /* 01 Memory24 */ + ACPI_FIXED_LENGTH, /* 02 GenericRegister */ + 0, + ACPI_VARIABLE_LENGTH, /* 04 VendorLong */ + ACPI_FIXED_LENGTH, /* 05 Memory32 */ + ACPI_FIXED_LENGTH, /* 06 Memory32Fixed */ + ACPI_VARIABLE_LENGTH, /* 07 Dword* address */ + ACPI_VARIABLE_LENGTH, /* 08 Word* address */ + ACPI_VARIABLE_LENGTH, /* 09 ExtendedIRQ */ + ACPI_VARIABLE_LENGTH, /* 0A Qword* address */ + ACPI_FIXED_LENGTH, /* 0B Extended* address */ + ACPI_VARIABLE_LENGTH, /* 0C Gpio* */ + 0, + ACPI_VARIABLE_LENGTH /* 0E *SerialBus */ +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtWalkAmlResources + * + * PARAMETERS: WalkState - Current walk info + * PARAMETERS: Aml - Pointer to the raw AML resource template + * AmlLength - Length of the entire template + * UserFunction - Called once for each descriptor found. If + * NULL, a pointer to the EndTag is returned + * Context - Passed to UserFunction + * + * RETURN: Status + * + * DESCRIPTION: Walk a raw AML resource list(buffer). User function called + * once for each resource found. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtWalkAmlResources ( + ACPI_WALK_STATE *WalkState, + UINT8 *Aml, + ACPI_SIZE AmlLength, + ACPI_WALK_AML_CALLBACK UserFunction, + void **Context) +{ + ACPI_STATUS Status; + UINT8 *EndAml; + UINT8 ResourceIndex; + UINT32 Length; + UINT32 Offset = 0; + UINT8 EndTag[2] = {0x79, 0x00}; + + + ACPI_FUNCTION_TRACE (UtWalkAmlResources); + + + /* The absolute minimum resource template is one EndTag descriptor */ + + if (AmlLength < sizeof (AML_RESOURCE_END_TAG)) + { + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); + } + + /* Point to the end of the resource template buffer */ + + EndAml = Aml + AmlLength; + + /* Walk the byte list, abort on any invalid descriptor type or length */ + + while (Aml < EndAml) + { + /* Validate the Resource Type and Resource Length */ + + Status = AcpiUtValidateResource (WalkState, Aml, &ResourceIndex); + if (ACPI_FAILURE (Status)) + { + /* + * Exit on failure. Cannot continue because the descriptor + * length may be bogus also. + */ + return_ACPI_STATUS (Status); + } + + /* Get the length of this descriptor */ + + Length = AcpiUtGetDescriptorLength (Aml); + + /* Invoke the user function */ + + if (UserFunction) + { + Status = UserFunction ( + Aml, Length, Offset, ResourceIndex, Context); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* An EndTag descriptor terminates this resource template */ + + if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_END_TAG) + { + /* + * There must be at least one more byte in the buffer for + * the 2nd byte of the EndTag + */ + if ((Aml + 1) >= EndAml) + { + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); + } + + /* Return the pointer to the EndTag if requested */ + + if (!UserFunction) + { + *Context = Aml; + } + + /* Normal exit */ + + return_ACPI_STATUS (AE_OK); + } + + Aml += Length; + Offset += Length; + } + + /* Did not find an EndTag descriptor */ + + if (UserFunction) + { + /* Insert an EndTag anyway. AcpiRsGetListLength always leaves room */ + + (void) AcpiUtValidateResource (WalkState, EndTag, &ResourceIndex); + Status = UserFunction (EndTag, 2, Offset, ResourceIndex, Context); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidateResource + * + * PARAMETERS: WalkState - Current walk info + * Aml - Pointer to the raw AML resource descriptor + * ReturnIndex - Where the resource index is returned. NULL + * if the index is not required. + * + * RETURN: Status, and optionally the Index into the global resource tables + * + * DESCRIPTION: Validate an AML resource descriptor by checking the Resource + * Type and Resource Length. Returns an index into the global + * resource information/dispatch tables for later use. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtValidateResource ( + ACPI_WALK_STATE *WalkState, + void *Aml, + UINT8 *ReturnIndex) +{ + AML_RESOURCE *AmlResource; + UINT8 ResourceType; + UINT8 ResourceIndex; + ACPI_RS_LENGTH ResourceLength; + ACPI_RS_LENGTH MinimumResourceLength; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * 1) Validate the ResourceType field (Byte 0) + */ + ResourceType = ACPI_GET8 (Aml); + + /* + * Byte 0 contains the descriptor name (Resource Type) + * Examine the large/small bit in the resource header + */ + if (ResourceType & ACPI_RESOURCE_NAME_LARGE) + { + /* Verify the large resource type (name) against the max */ + + if (ResourceType > ACPI_RESOURCE_NAME_LARGE_MAX) + { + goto InvalidResource; + } + + /* + * Large Resource Type -- bits 6:0 contain the name + * Translate range 0x80-0x8B to index range 0x10-0x1B + */ + ResourceIndex = (UINT8) (ResourceType - 0x70); + } + else + { + /* + * Small Resource Type -- bits 6:3 contain the name + * Shift range to index range 0x00-0x0F + */ + ResourceIndex = (UINT8) + ((ResourceType & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3); + } + + /* + * Check validity of the resource type, via AcpiGbl_ResourceTypes. + * Zero indicates an invalid resource. + */ + if (!AcpiGbl_ResourceTypes[ResourceIndex]) + { + goto InvalidResource; + } + + /* + * Validate the ResourceLength field. This ensures that the length + * is at least reasonable, and guarantees that it is non-zero. + */ + ResourceLength = AcpiUtGetResourceLength (Aml); + MinimumResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex]; + + /* Validate based upon the type of resource - fixed length or variable */ + + switch (AcpiGbl_ResourceTypes[ResourceIndex]) + { + case ACPI_FIXED_LENGTH: + + /* Fixed length resource, length must match exactly */ + + if (ResourceLength != MinimumResourceLength) + { + goto BadResourceLength; + } + break; + + case ACPI_VARIABLE_LENGTH: + + /* Variable length resource, length must be at least the minimum */ + + if (ResourceLength < MinimumResourceLength) + { + goto BadResourceLength; + } + break; + + case ACPI_SMALL_VARIABLE_LENGTH: + + /* Small variable length resource, length can be (Min) or (Min-1) */ + + if ((ResourceLength > MinimumResourceLength) || + (ResourceLength < (MinimumResourceLength - 1))) + { + goto BadResourceLength; + } + break; + + default: + + /* Shouldn't happen (because of validation earlier), but be sure */ + + goto InvalidResource; + } + + AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml); + if (ResourceType == ACPI_RESOURCE_NAME_SERIAL_BUS) + { + /* Validate the BusType field */ + + if ((AmlResource->CommonSerialBus.Type == 0) || + (AmlResource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE)) + { + if (WalkState) + { + ACPI_ERROR ((AE_INFO, + "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", + AmlResource->CommonSerialBus.Type)); + } + return (AE_AML_INVALID_RESOURCE_TYPE); + } + } + + /* Optionally return the resource table index */ + + if (ReturnIndex) + { + *ReturnIndex = ResourceIndex; + } + + return (AE_OK); + + +InvalidResource: + + if (WalkState) + { + ACPI_ERROR ((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + ResourceType)); + } + return (AE_AML_INVALID_RESOURCE_TYPE); + +BadResourceLength: + + if (WalkState) + { + ACPI_ERROR ((AE_INFO, + "Invalid resource descriptor length: Type " + "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", + ResourceType, ResourceLength, MinimumResourceLength)); + } + return (AE_AML_BAD_RESOURCE_LENGTH); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetResourceType + * + * PARAMETERS: Aml - Pointer to the raw AML resource descriptor + * + * RETURN: The Resource Type with no extraneous bits (except the + * Large/Small descriptor bit -- this is left alone) + * + * DESCRIPTION: Extract the Resource Type/Name from the first byte of + * a resource descriptor. + * + ******************************************************************************/ + +UINT8 +AcpiUtGetResourceType ( + void *Aml) +{ + ACPI_FUNCTION_ENTRY (); + + + /* + * Byte 0 contains the descriptor name (Resource Type) + * Examine the large/small bit in the resource header + */ + if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) + { + /* Large Resource Type -- bits 6:0 contain the name */ + + return (ACPI_GET8 (Aml)); + } + else + { + /* Small Resource Type -- bits 6:3 contain the name */ + + return ((UINT8) (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_SMALL_MASK)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetResourceLength + * + * PARAMETERS: Aml - Pointer to the raw AML resource descriptor + * + * RETURN: Byte Length + * + * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By + * definition, this does not include the size of the descriptor + * header or the length field itself. + * + ******************************************************************************/ + +UINT16 +AcpiUtGetResourceLength ( + void *Aml) +{ + ACPI_RS_LENGTH ResourceLength; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * Byte 0 contains the descriptor name (Resource Type) + * Examine the large/small bit in the resource header + */ + if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) + { + /* Large Resource type -- bytes 1-2 contain the 16-bit length */ + + ACPI_MOVE_16_TO_16 (&ResourceLength, ACPI_ADD_PTR (UINT8, Aml, 1)); + + } + else + { + /* Small Resource type -- bits 2:0 of byte 0 contain the length */ + + ResourceLength = (UINT16) (ACPI_GET8 (Aml) & + ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK); + } + + return (ResourceLength); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetResourceHeaderLength + * + * PARAMETERS: Aml - Pointer to the raw AML resource descriptor + * + * RETURN: Length of the AML header (depends on large/small descriptor) + * + * DESCRIPTION: Get the length of the header for this resource. + * + ******************************************************************************/ + +UINT8 +AcpiUtGetResourceHeaderLength ( + void *Aml) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Examine the large/small bit in the resource header */ + + if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) + { + return (sizeof (AML_RESOURCE_LARGE_HEADER)); + } + else + { + return (sizeof (AML_RESOURCE_SMALL_HEADER)); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetDescriptorLength + * + * PARAMETERS: Aml - Pointer to the raw AML resource descriptor + * + * RETURN: Byte length + * + * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the + * length of the descriptor header and the length field itself. + * Used to walk descriptor lists. + * + ******************************************************************************/ + +UINT32 +AcpiUtGetDescriptorLength ( + void *Aml) +{ + ACPI_FUNCTION_ENTRY (); + + + /* + * Get the Resource Length (does not include header length) and add + * the header length (depends on if this is a small or large resource) + */ + return (AcpiUtGetResourceLength (Aml) + + AcpiUtGetResourceHeaderLength (Aml)); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetResourceEndTag + * + * PARAMETERS: ObjDesc - The resource template buffer object + * EndTag - Where the pointer to the EndTag is returned + * + * RETURN: Status, pointer to the end tag + * + * DESCRIPTION: Find the EndTag resource descriptor in an AML resource template + * Note: allows a buffer length of zero. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtGetResourceEndTag ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 **EndTag) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (UtGetResourceEndTag); + + + /* Allow a buffer length of zero */ + + if (!ObjDesc->Buffer.Length) + { + *EndTag = ObjDesc->Buffer.Pointer; + return_ACPI_STATUS (AE_OK); + } + + /* Validate the template and get a pointer to the EndTag */ + + Status = AcpiUtWalkAmlResources (NULL, ObjDesc->Buffer.Pointer, + ObjDesc->Buffer.Length, NULL, (void **) EndTag); + + return_ACPI_STATUS (Status); +} diff --git a/third_party/lib/acpica/source/components/utilities/utstate.c b/third_party/lib/acpica/source/components/utilities/utstate.c new file mode 100644 index 000000000..deffd283c --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utstate.c @@ -0,0 +1,354 @@ +/******************************************************************************* + * + * Module Name: utstate - state object support procedures + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utstate") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPushGenericState + * + * PARAMETERS: ListHead - Head of the state stack + * State - State object to push + * + * RETURN: None + * + * DESCRIPTION: Push a state object onto a state stack + * + ******************************************************************************/ + +void +AcpiUtPushGenericState ( + ACPI_GENERIC_STATE **ListHead, + ACPI_GENERIC_STATE *State) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Push the state object onto the front of the list (stack) */ + + State->Common.Next = *ListHead; + *ListHead = State; + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPopGenericState + * + * PARAMETERS: ListHead - Head of the state stack + * + * RETURN: The popped state object + * + * DESCRIPTION: Pop a state object from a state stack + * + ******************************************************************************/ + +ACPI_GENERIC_STATE * +AcpiUtPopGenericState ( + ACPI_GENERIC_STATE **ListHead) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + /* Remove the state object at the head of the list (stack) */ + + State = *ListHead; + if (State) + { + /* Update the list head */ + + *ListHead = State->Common.Next; + } + + return (State); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateGenericState + * + * PARAMETERS: None + * + * RETURN: The new state object. NULL on failure. + * + * DESCRIPTION: Create a generic state object. Attempt to obtain one from + * the global state cache; If none available, create a new one. + * + ******************************************************************************/ + +ACPI_GENERIC_STATE * +AcpiUtCreateGenericState ( + void) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + State = AcpiOsAcquireObject (AcpiGbl_StateCache); + if (State) + { + /* Initialize */ + State->Common.DescriptorType = ACPI_DESC_TYPE_STATE; + } + + return (State); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateThreadState + * + * PARAMETERS: None + * + * RETURN: New Thread State. NULL on failure + * + * DESCRIPTION: Create a "Thread State" - a flavor of the generic state used + * to track per-thread info during method execution + * + ******************************************************************************/ + +ACPI_THREAD_STATE * +AcpiUtCreateThreadState ( + void) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + /* Create the generic state object */ + + State = AcpiUtCreateGenericState (); + if (!State) + { + return (NULL); + } + + /* Init fields specific to the update struct */ + + State->Common.DescriptorType = ACPI_DESC_TYPE_STATE_THREAD; + State->Thread.ThreadId = AcpiOsGetThreadId (); + + /* Check for invalid thread ID - zero is very bad, it will break things */ + + if (!State->Thread.ThreadId) + { + ACPI_ERROR ((AE_INFO, "Invalid zero ID from AcpiOsGetThreadId")); + State->Thread.ThreadId = (ACPI_THREAD_ID) 1; + } + + return ((ACPI_THREAD_STATE *) State); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateUpdateState + * + * PARAMETERS: Object - Initial Object to be installed in the state + * Action - Update action to be performed + * + * RETURN: New state object, null on failure + * + * DESCRIPTION: Create an "Update State" - a flavor of the generic state used + * to update reference counts and delete complex objects such + * as packages. + * + ******************************************************************************/ + +ACPI_GENERIC_STATE * +AcpiUtCreateUpdateState ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + /* Create the generic state object */ + + State = AcpiUtCreateGenericState (); + if (!State) + { + return (NULL); + } + + /* Init fields specific to the update struct */ + + State->Common.DescriptorType = ACPI_DESC_TYPE_STATE_UPDATE; + State->Update.Object = Object; + State->Update.Value = Action; + return (State); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreatePkgState + * + * PARAMETERS: Object - Initial Object to be installed in the state + * Action - Update action to be performed + * + * RETURN: New state object, null on failure + * + * DESCRIPTION: Create a "Package State" + * + ******************************************************************************/ + +ACPI_GENERIC_STATE * +AcpiUtCreatePkgState ( + void *InternalObject, + void *ExternalObject, + UINT16 Index) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + /* Create the generic state object */ + + State = AcpiUtCreateGenericState (); + if (!State) + { + return (NULL); + } + + /* Init fields specific to the update struct */ + + State->Common.DescriptorType = ACPI_DESC_TYPE_STATE_PACKAGE; + State->Pkg.SourceObject = (ACPI_OPERAND_OBJECT *) InternalObject; + State->Pkg.DestObject = ExternalObject; + State->Pkg.Index= Index; + State->Pkg.NumPackages = 1; + + return (State); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateControlState + * + * PARAMETERS: None + * + * RETURN: New state object, null on failure + * + * DESCRIPTION: Create a "Control State" - a flavor of the generic state used + * to support nested IF/WHILE constructs in the AML. + * + ******************************************************************************/ + +ACPI_GENERIC_STATE * +AcpiUtCreateControlState ( + void) +{ + ACPI_GENERIC_STATE *State; + + + ACPI_FUNCTION_ENTRY (); + + + /* Create the generic state object */ + + State = AcpiUtCreateGenericState (); + if (!State) + { + return (NULL); + } + + /* Init fields specific to the control struct */ + + State->Common.DescriptorType = ACPI_DESC_TYPE_STATE_CONTROL; + State->Common.State = ACPI_CONTROL_CONDITIONAL_EXECUTING; + + return (State); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDeleteGenericState + * + * PARAMETERS: State - The state object to be deleted + * + * RETURN: None + * + * DESCRIPTION: Release a state object to the state cache. NULL state objects + * are ignored. + * + ******************************************************************************/ + +void +AcpiUtDeleteGenericState ( + ACPI_GENERIC_STATE *State) +{ + ACPI_FUNCTION_ENTRY (); + + + /* Ignore null state */ + + if (State) + { + (void) AcpiOsReleaseObject (AcpiGbl_StateCache, State); + } + + return; +} diff --git a/third_party/lib/acpica/source/components/utilities/utstring.c b/third_party/lib/acpica/source/components/utilities/utstring.c new file mode 100644 index 000000000..646307edc --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utstring.c @@ -0,0 +1,357 @@ +/******************************************************************************* + * + * Module Name: utstring - Common functions for strings and characters + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utstring") + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPrintString + * + * PARAMETERS: String - Null terminated ASCII string + * MaxLength - Maximum output length. Used to constrain the + * length of strings during debug output only. + * + * RETURN: None + * + * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape + * sequences. + * + ******************************************************************************/ + +void +AcpiUtPrintString ( + char *String, + UINT16 MaxLength) +{ + UINT32 i; + + + if (!String) + { + AcpiOsPrintf ("<\"NULL STRING PTR\">"); + return; + } + + AcpiOsPrintf ("\""); + for (i = 0; (i < MaxLength) && String[i]; i++) + { + /* Escape sequences */ + + switch (String[i]) + { + case 0x07: + + AcpiOsPrintf ("\\a"); /* BELL */ + break; + + case 0x08: + + AcpiOsPrintf ("\\b"); /* BACKSPACE */ + break; + + case 0x0C: + + AcpiOsPrintf ("\\f"); /* FORMFEED */ + break; + + case 0x0A: + + AcpiOsPrintf ("\\n"); /* LINEFEED */ + break; + + case 0x0D: + + AcpiOsPrintf ("\\r"); /* CARRIAGE RETURN*/ + break; + + case 0x09: + + AcpiOsPrintf ("\\t"); /* HORIZONTAL TAB */ + break; + + case 0x0B: + + AcpiOsPrintf ("\\v"); /* VERTICAL TAB */ + break; + + case '\'': /* Single Quote */ + case '\"': /* Double Quote */ + case '\\': /* Backslash */ + + AcpiOsPrintf ("\\%c", (int) String[i]); + break; + + default: + + /* Check for printable character or hex escape */ + + if (isprint ((int) String[i])) + { + /* This is a normal character */ + + AcpiOsPrintf ("%c", (int) String[i]); + } + else + { + /* All others will be Hex escapes */ + + AcpiOsPrintf ("\\x%2.2X", (INT32) String[i]); + } + break; + } + } + + AcpiOsPrintf ("\""); + + if (i == MaxLength && String[i]) + { + AcpiOsPrintf ("..."); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidAcpiChar + * + * PARAMETERS: Char - The character to be examined + * Position - Byte position (0-3) + * + * RETURN: TRUE if the character is valid, FALSE otherwise + * + * DESCRIPTION: Check for a valid ACPI character. Must be one of: + * 1) Upper case alpha + * 2) numeric + * 3) underscore + * + * We allow a '!' as the last character because of the ASF! table + * + ******************************************************************************/ + +BOOLEAN +AcpiUtValidAcpiChar ( + char Character, + UINT32 Position) +{ + + if (!((Character >= 'A' && Character <= 'Z') || + (Character >= '0' && Character <= '9') || + (Character == '_'))) + { + /* Allow a '!' in the last position */ + + if (Character == '!' && Position == 3) + { + return (TRUE); + } + + return (FALSE); + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtValidAcpiName + * + * PARAMETERS: Name - The name to be examined. Does not have to + * be NULL terminated string. + * + * RETURN: TRUE if the name is valid, FALSE otherwise + * + * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: + * 1) Upper case alpha + * 2) numeric + * 3) underscore + * + ******************************************************************************/ + +BOOLEAN +AcpiUtValidAcpiName ( + char *Name) +{ + UINT32 i; + + + ACPI_FUNCTION_ENTRY (); + + + for (i = 0; i < ACPI_NAME_SIZE; i++) + { + if (!AcpiUtValidAcpiChar (Name[i], i)) + { + return (FALSE); + } + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtRepairName + * + * PARAMETERS: Name - The ACPI name to be repaired + * + * RETURN: Repaired version of the name + * + * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and + * return the new name. NOTE: the Name parameter must reside in + * read/write memory, cannot be a const. + * + * An ACPI Name must consist of valid ACPI characters. We will repair the name + * if necessary because we don't want to abort because of this, but we want + * all namespace names to be printable. A warning message is appropriate. + * + * This issue came up because there are in fact machines that exhibit + * this problem, and we want to be able to enable ACPI support for them, + * even though there are a few bad names. + * + ******************************************************************************/ + +void +AcpiUtRepairName ( + char *Name) +{ + UINT32 i; + BOOLEAN FoundBadChar = FALSE; + UINT32 OriginalName; + + + ACPI_FUNCTION_NAME (UtRepairName); + + + /* + * Special case for the root node. This can happen if we get an + * error during the execution of module-level code. + */ + if (ACPI_COMPARE_NAME (Name, "\\___")) + { + return; + } + + ACPI_MOVE_NAME (&OriginalName, Name); + + /* Check each character in the name */ + + for (i = 0; i < ACPI_NAME_SIZE; i++) + { + if (AcpiUtValidAcpiChar (Name[i], i)) + { + continue; + } + + /* + * Replace a bad character with something printable, yet technically + * still invalid. This prevents any collisions with existing "good" + * names in the namespace. + */ + Name[i] = '*'; + FoundBadChar = TRUE; + } + + if (FoundBadChar) + { + /* Report warning only if in strict mode or debug mode */ + + if (!AcpiGbl_EnableInterpreterSlack) + { + ACPI_WARNING ((AE_INFO, + "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]", + OriginalName, Name)); + } + else + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]", + OriginalName, Name)); + } + } +} + + +#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP +/******************************************************************************* + * + * FUNCTION: UtConvertBackslashes + * + * PARAMETERS: Pathname - File pathname string to be converted + * + * RETURN: Modifies the input Pathname + * + * DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within + * the entire input file pathname string. + * + ******************************************************************************/ + +void +UtConvertBackslashes ( + char *Pathname) +{ + + if (!Pathname) + { + return; + } + + while (*Pathname) + { + if (*Pathname == '\\') + { + *Pathname = '/'; + } + + Pathname++; + } +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/uttrack.c b/third_party/lib/acpica/source/components/utilities/uttrack.c new file mode 100644 index 000000000..b5383c8c3 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/uttrack.c @@ -0,0 +1,789 @@ +/****************************************************************************** + * + * Module Name: uttrack - Memory allocation tracking routines (debug only) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * These procedures are used for tracking memory leaks in the subsystem, and + * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. + * + * Each memory allocation is tracked via a doubly linked list. Each + * element contains the caller's component, module name, function name, and + * line number. AcpiUtAllocate and AcpiUtAllocateZeroed call + * AcpiUtTrackAllocation to add an element to the list; deletion + * occurs in the body of AcpiUtFree. + */ + +#include "acpi.h" +#include "accommon.h" + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("uttrack") + + +/* Local prototypes */ + +static ACPI_DEBUG_MEM_BLOCK * +AcpiUtFindAllocation ( + ACPI_DEBUG_MEM_BLOCK *Allocation); + +static ACPI_STATUS +AcpiUtTrackAllocation ( + ACPI_DEBUG_MEM_BLOCK *Address, + ACPI_SIZE Size, + UINT8 AllocType, + UINT32 Component, + const char *Module, + UINT32 Line); + +static ACPI_STATUS +AcpiUtRemoveAllocation ( + ACPI_DEBUG_MEM_BLOCK *Address, + UINT32 Component, + const char *Module, + UINT32 Line); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtCreateList + * + * PARAMETERS: CacheName - Ascii name for the cache + * ObjectSize - Size of each cached object + * ReturnCache - Where the new cache object is returned + * + * RETURN: Status + * + * DESCRIPTION: Create a local memory list for tracking purposed + * + ******************************************************************************/ + +ACPI_STATUS +AcpiUtCreateList ( + char *ListName, + UINT16 ObjectSize, + ACPI_MEMORY_LIST **ReturnCache) +{ + ACPI_MEMORY_LIST *Cache; + + + Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST)); + if (!Cache) + { + return (AE_NO_MEMORY); + } + + memset (Cache, 0, sizeof (ACPI_MEMORY_LIST)); + + Cache->ListName = ListName; + Cache->ObjectSize = ObjectSize; + + *ReturnCache = Cache; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAllocateAndTrack + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void * +AcpiUtAllocateAndTrack ( + ACPI_SIZE Size, + UINT32 Component, + const char *Module, + UINT32 Line) +{ + ACPI_DEBUG_MEM_BLOCK *Allocation; + ACPI_STATUS Status; + + + /* Check for an inadvertent size of zero bytes */ + + if (!Size) + { + ACPI_WARNING ((Module, Line, + "Attempt to allocate zero bytes, allocating 1 byte")); + Size = 1; + } + + Allocation = AcpiOsAllocate (Size + sizeof (ACPI_DEBUG_MEM_HEADER)); + if (!Allocation) + { + /* Report allocation error */ + + ACPI_WARNING ((Module, Line, + "Could not allocate size %u", (UINT32) Size)); + + return (NULL); + } + + Status = AcpiUtTrackAllocation ( + Allocation, Size, ACPI_MEM_MALLOC, Component, Module, Line); + if (ACPI_FAILURE (Status)) + { + AcpiOsFree (Allocation); + return (NULL); + } + + AcpiGbl_GlobalList->TotalAllocated++; + AcpiGbl_GlobalList->TotalSize += (UINT32) Size; + AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size; + + if (AcpiGbl_GlobalList->CurrentTotalSize > + AcpiGbl_GlobalList->MaxOccupied) + { + AcpiGbl_GlobalList->MaxOccupied = + AcpiGbl_GlobalList->CurrentTotalSize; + } + + return ((void *) &Allocation->UserSpace); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtAllocateZeroedAndTrack + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void * +AcpiUtAllocateZeroedAndTrack ( + ACPI_SIZE Size, + UINT32 Component, + const char *Module, + UINT32 Line) +{ + ACPI_DEBUG_MEM_BLOCK *Allocation; + ACPI_STATUS Status; + + + /* Check for an inadvertent size of zero bytes */ + + if (!Size) + { + ACPI_WARNING ((Module, Line, + "Attempt to allocate zero bytes, allocating 1 byte")); + Size = 1; + } + + Allocation = AcpiOsAllocateZeroed ( + Size + sizeof (ACPI_DEBUG_MEM_HEADER)); + if (!Allocation) + { + /* Report allocation error */ + + ACPI_ERROR ((Module, Line, + "Could not allocate size %u", (UINT32) Size)); + return (NULL); + } + + Status = AcpiUtTrackAllocation (Allocation, Size, + ACPI_MEM_CALLOC, Component, Module, Line); + if (ACPI_FAILURE (Status)) + { + AcpiOsFree (Allocation); + return (NULL); + } + + AcpiGbl_GlobalList->TotalAllocated++; + AcpiGbl_GlobalList->TotalSize += (UINT32) Size; + AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size; + + if (AcpiGbl_GlobalList->CurrentTotalSize > + AcpiGbl_GlobalList->MaxOccupied) + { + AcpiGbl_GlobalList->MaxOccupied = + AcpiGbl_GlobalList->CurrentTotalSize; + } + + return ((void *) &Allocation->UserSpace); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtFreeAndTrack + * + * PARAMETERS: Allocation - Address of the memory to deallocate + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: None + * + * DESCRIPTION: Frees the memory at Allocation + * + ******************************************************************************/ + +void +AcpiUtFreeAndTrack ( + void *Allocation, + UINT32 Component, + const char *Module, + UINT32 Line) +{ + ACPI_DEBUG_MEM_BLOCK *DebugBlock; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (UtFree, Allocation); + + + if (NULL == Allocation) + { + ACPI_ERROR ((Module, Line, + "Attempt to delete a NULL address")); + + return_VOID; + } + + DebugBlock = ACPI_CAST_PTR (ACPI_DEBUG_MEM_BLOCK, + (((char *) Allocation) - sizeof (ACPI_DEBUG_MEM_HEADER))); + + AcpiGbl_GlobalList->TotalFreed++; + AcpiGbl_GlobalList->CurrentTotalSize -= DebugBlock->Size; + + Status = AcpiUtRemoveAllocation (DebugBlock, Component, Module, Line); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "Could not free memory")); + } + + AcpiOsFree (DebugBlock); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n", + Allocation, DebugBlock)); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtFindAllocation + * + * PARAMETERS: Allocation - Address of allocated memory + * + * RETURN: Three cases: + * 1) List is empty, NULL is returned. + * 2) Element was found. Returns Allocation parameter. + * 3) Element was not found. Returns position where it should be + * inserted into the list. + * + * DESCRIPTION: Searches for an element in the global allocation tracking list. + * If the element is not found, returns the location within the + * list where the element should be inserted. + * + * Note: The list is ordered by larger-to-smaller addresses. + * + * This global list is used to detect memory leaks in ACPICA as + * well as other issues such as an attempt to release the same + * internal object more than once. Although expensive as far + * as cpu time, this list is much more helpful for finding these + * types of issues than using memory leak detectors outside of + * the ACPICA code. + * + ******************************************************************************/ + +static ACPI_DEBUG_MEM_BLOCK * +AcpiUtFindAllocation ( + ACPI_DEBUG_MEM_BLOCK *Allocation) +{ + ACPI_DEBUG_MEM_BLOCK *Element; + + + Element = AcpiGbl_GlobalList->ListHead; + if (!Element) + { + return (NULL); + } + + /* + * Search for the address. + * + * Note: List is ordered by larger-to-smaller addresses, on the + * assumption that a new allocation usually has a larger address + * than previous allocations. + */ + while (Element > Allocation) + { + /* Check for end-of-list */ + + if (!Element->Next) + { + return (Element); + } + + Element = Element->Next; + } + + if (Element == Allocation) + { + return (Element); + } + + return (Element->Previous); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtTrackAllocation + * + * PARAMETERS: Allocation - Address of allocated memory + * Size - Size of the allocation + * AllocType - MEM_MALLOC or MEM_CALLOC + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Status + * + * DESCRIPTION: Inserts an element into the global allocation tracking list. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtTrackAllocation ( + ACPI_DEBUG_MEM_BLOCK *Allocation, + ACPI_SIZE Size, + UINT8 AllocType, + UINT32 Component, + const char *Module, + UINT32 Line) +{ + ACPI_MEMORY_LIST *MemList; + ACPI_DEBUG_MEM_BLOCK *Element; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR (UtTrackAllocation, Allocation); + + + if (AcpiGbl_DisableMemTracking) + { + return_ACPI_STATUS (AE_OK); + } + + MemList = AcpiGbl_GlobalList; + Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Search the global list for this address to make sure it is not + * already present. This will catch several kinds of problems. + */ + Element = AcpiUtFindAllocation (Allocation); + if (Element == Allocation) + { + ACPI_ERROR ((AE_INFO, + "UtTrackAllocation: Allocation (%p) already present in global list!", + Allocation)); + goto UnlockAndExit; + } + + /* Fill in the instance data */ + + Allocation->Size = (UINT32) Size; + Allocation->AllocType = AllocType; + Allocation->Component = Component; + Allocation->Line = Line; + + strncpy (Allocation->Module, Module, ACPI_MAX_MODULE_NAME); + Allocation->Module[ACPI_MAX_MODULE_NAME-1] = 0; + + if (!Element) + { + /* Insert at list head */ + + if (MemList->ListHead) + { + ((ACPI_DEBUG_MEM_BLOCK *)(MemList->ListHead))->Previous = + Allocation; + } + + Allocation->Next = MemList->ListHead; + Allocation->Previous = NULL; + + MemList->ListHead = Allocation; + } + else + { + /* Insert after element */ + + Allocation->Next = Element->Next; + Allocation->Previous = Element; + + if (Element->Next) + { + (Element->Next)->Previous = Allocation; + } + + Element->Next = Allocation; + } + + +UnlockAndExit: + Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtRemoveAllocation + * + * PARAMETERS: Allocation - Address of allocated memory + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Status + * + * DESCRIPTION: Deletes an element from the global allocation tracking list. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtRemoveAllocation ( + ACPI_DEBUG_MEM_BLOCK *Allocation, + UINT32 Component, + const char *Module, + UINT32 Line) +{ + ACPI_MEMORY_LIST *MemList; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (UtRemoveAllocation); + + + if (AcpiGbl_DisableMemTracking) + { + return (AE_OK); + } + + MemList = AcpiGbl_GlobalList; + if (NULL == MemList->ListHead) + { + /* No allocations! */ + + ACPI_ERROR ((Module, Line, + "Empty allocation list, nothing to free!")); + + return (AE_OK); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Unlink */ + + if (Allocation->Previous) + { + (Allocation->Previous)->Next = Allocation->Next; + } + else + { + MemList->ListHead = Allocation->Next; + } + + if (Allocation->Next) + { + (Allocation->Next)->Previous = Allocation->Previous; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n", + &Allocation->UserSpace, Allocation->Size)); + + /* Mark the segment as deleted */ + + memset (&Allocation->UserSpace, 0xEA, Allocation->Size); + + Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDumpAllocationInfo + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Print some info about the outstanding allocations. + * + ******************************************************************************/ + +void +AcpiUtDumpAllocationInfo ( + void) +{ +/* + ACPI_MEMORY_LIST *MemList; +*/ + + ACPI_FUNCTION_TRACE (UtDumpAllocationInfo); + +/* + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Current allocations", + MemList->CurrentCount, + ROUND_UP_TO_1K (MemList->CurrentSize))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", + MemList->MaxConcurrentCount, + ROUND_UP_TO_1K (MemList->MaxConcurrentSize))); + + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", + RunningObjectCount, + ROUND_UP_TO_1K (RunningObjectSize))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", + RunningAllocCount, + ROUND_UP_TO_1K (RunningAllocSize))); + + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Current Nodes", + AcpiGbl_CurrentNodeCount, + ROUND_UP_TO_1K (AcpiGbl_CurrentNodeSize))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Max Nodes", + AcpiGbl_MaxConcurrentNodeCount, + ROUND_UP_TO_1K ((AcpiGbl_MaxConcurrentNodeCount * + sizeof (ACPI_NAMESPACE_NODE))))); +*/ + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtDumpAllocations + * + * PARAMETERS: Component - Component(s) to dump info for. + * Module - Module to dump info for. NULL means all. + * + * RETURN: None + * + * DESCRIPTION: Print a list of all outstanding allocations. + * + ******************************************************************************/ + +void +AcpiUtDumpAllocations ( + UINT32 Component, + const char *Module) +{ + ACPI_DEBUG_MEM_BLOCK *Element; + ACPI_DESCRIPTOR *Descriptor; + UINT32 NumOutstanding = 0; + UINT8 DescriptorType; + + + ACPI_FUNCTION_TRACE (UtDumpAllocations); + + + if (AcpiGbl_DisableMemTracking) + { + return_VOID; + } + + /* + * Walk the allocation list. + */ + if (ACPI_FAILURE (AcpiUtAcquireMutex (ACPI_MTX_MEMORY))) + { + return_VOID; + } + + Element = AcpiGbl_GlobalList->ListHead; + while (Element) + { + if ((Element->Component & Component) && + ((Module == NULL) || (0 == strcmp (Module, Element->Module)))) + { + Descriptor = ACPI_CAST_PTR ( + ACPI_DESCRIPTOR, &Element->UserSpace); + + if (Element->Size < sizeof (ACPI_COMMON_DESCRIPTOR)) + { + AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u " + "[Not a Descriptor - too small]\n", + Descriptor, Element->Size, Element->Module, + Element->Line); + } + else + { + /* Ignore allocated objects that are in a cache */ + + if (ACPI_GET_DESCRIPTOR_TYPE (Descriptor) != + ACPI_DESC_TYPE_CACHED) + { + AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u [%s] ", + Descriptor, Element->Size, Element->Module, + Element->Line, AcpiUtGetDescriptorName (Descriptor)); + + /* Validate the descriptor type using Type field and length */ + + DescriptorType = 0; /* Not a valid descriptor type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (Descriptor)) + { + case ACPI_DESC_TYPE_OPERAND: + + if (Element->Size == sizeof (ACPI_OPERAND_OBJECT)) + { + DescriptorType = ACPI_DESC_TYPE_OPERAND; + } + break; + + case ACPI_DESC_TYPE_PARSER: + + if (Element->Size == sizeof (ACPI_PARSE_OBJECT)) + { + DescriptorType = ACPI_DESC_TYPE_PARSER; + } + break; + + case ACPI_DESC_TYPE_NAMED: + + if (Element->Size == sizeof (ACPI_NAMESPACE_NODE)) + { + DescriptorType = ACPI_DESC_TYPE_NAMED; + } + break; + + default: + + break; + } + + /* Display additional info for the major descriptor types */ + + switch (DescriptorType) + { + case ACPI_DESC_TYPE_OPERAND: + + AcpiOsPrintf ("%12.12s RefCount 0x%04X\n", + AcpiUtGetTypeName (Descriptor->Object.Common.Type), + Descriptor->Object.Common.ReferenceCount); + break; + + case ACPI_DESC_TYPE_PARSER: + + AcpiOsPrintf ("AmlOpcode 0x%04hX\n", + Descriptor->Op.Asl.AmlOpcode); + break; + + case ACPI_DESC_TYPE_NAMED: + + AcpiOsPrintf ("%4.4s\n", + AcpiUtGetNodeName (&Descriptor->Node)); + break; + + default: + + AcpiOsPrintf ( "\n"); + break; + } + } + } + + NumOutstanding++; + } + + Element = Element->Next; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_MEMORY); + + /* Print summary */ + + if (!NumOutstanding) + { + ACPI_INFO ((AE_INFO, "No outstanding allocations")); + } + else + { + ACPI_ERROR ((AE_INFO, "%u(0x%X) Outstanding allocations", + NumOutstanding, NumOutstanding)); + } + + return_VOID; +} + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/third_party/lib/acpica/source/components/utilities/utuuid.c b/third_party/lib/acpica/source/components/utilities/utuuid.c new file mode 100644 index 000000000..df48912a2 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utuuid.c @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * Module Name: utuuid -- UUID support functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("utuuid") + + +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP) +/* + * UUID support functions. + * + * This table is used to convert an input UUID ascii string to a 16 byte + * buffer and the reverse. The table maps a UUID buffer index 0-15 to + * the index within the 36-byte UUID string where the associated 2-byte + * hex value can be found. + * + * 36-byte UUID strings are of the form: + * aabbccdd-eeff-gghh-iijj-kkllmmnnoopp + * Where aa-pp are one byte hex numbers, made up of two hex digits + * + * Note: This table is basically the inverse of the string-to-offset table + * found in the ACPI spec in the description of the ToUUID macro. + */ +const UINT8 AcpiGbl_MapToUuidOffset[UUID_BUFFER_LENGTH] = +{ + 6,4,2,0,11,9,16,14,19,21,24,26,28,30,32,34 +}; + + +/******************************************************************************* + * + * FUNCTION: AcpiUtConvertStringToUuid + * + * PARAMETERS: InString - 36-byte formatted UUID string + * UuidBuffer - Where the 16-byte UUID buffer is returned + * + * RETURN: None. Output data is returned in the UuidBuffer + * + * DESCRIPTION: Convert a 36-byte formatted UUID string to 16-byte UUID buffer + * + ******************************************************************************/ + +void +AcpiUtConvertStringToUuid ( + char *InString, + UINT8 *UuidBuffer) +{ + UINT32 i; + + + for (i = 0; i < UUID_BUFFER_LENGTH; i++) + { + UuidBuffer[i] = (AcpiUtAsciiCharToHex ( + InString[AcpiGbl_MapToUuidOffset[i]]) << 4); + + UuidBuffer[i] |= AcpiUtAsciiCharToHex ( + InString[AcpiGbl_MapToUuidOffset[i] + 1]); + } +} +#endif diff --git a/third_party/lib/acpica/source/components/utilities/utxface.c b/third_party/lib/acpica/source/components/utilities/utxface.c new file mode 100644 index 000000000..a8452c329 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utxface.c @@ -0,0 +1,643 @@ +/****************************************************************************** + * + * Module Name: utxface - External interfaces, miscellaneous utility functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acdebug.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utxface") + + +/******************************************************************************* + * + * FUNCTION: AcpiTerminate + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Shutdown the ACPICA subsystem and release all resources. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiTerminate ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiTerminate); + + + /* Shutdown and free all resources */ + + AcpiUtSubsystemShutdown (); + + /* Free the mutex objects */ + + AcpiUtMutexTerminate (); + + /* Now we can shutdown the OS-dependent layer */ + + Status = AcpiOsTerminate (); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiTerminate) + + +#ifndef ACPI_ASL_COMPILER +/******************************************************************************* + * + * FUNCTION: AcpiSubsystemStatus + * + * PARAMETERS: None + * + * RETURN: Status of the ACPI subsystem + * + * DESCRIPTION: Other drivers that use the ACPI subsystem should call this + * before making any other calls, to ensure the subsystem + * initialized successfully. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSubsystemStatus ( + void) +{ + + if (AcpiGbl_StartupFlags & ACPI_INITIALIZED_OK) + { + return (AE_OK); + } + else + { + return (AE_ERROR); + } +} + +ACPI_EXPORT_SYMBOL (AcpiSubsystemStatus) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetSystemInfo + * + * PARAMETERS: OutBuffer - A buffer to receive the resources for the + * device + * + * RETURN: Status - the status of the call + * + * DESCRIPTION: This function is called to get information about the current + * state of the ACPI subsystem. It will return system information + * in the OutBuffer. + * + * If the function fails an appropriate status will be returned + * and the value of OutBuffer is undefined. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetSystemInfo ( + ACPI_BUFFER *OutBuffer) +{ + ACPI_SYSTEM_INFO *InfoPtr; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiGetSystemInfo); + + + /* Parameter validation */ + + Status = AcpiUtValidateBuffer (OutBuffer); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Validate/Allocate/Clear caller buffer */ + + Status = AcpiUtInitializeBuffer (OutBuffer, sizeof (ACPI_SYSTEM_INFO)); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Populate the return buffer + */ + InfoPtr = (ACPI_SYSTEM_INFO *) OutBuffer->Pointer; + InfoPtr->AcpiCaVersion = ACPI_CA_VERSION; + + /* System flags (ACPI capabilities) */ + + InfoPtr->Flags = ACPI_SYS_MODE_ACPI; + + /* Timer resolution - 24 or 32 bits */ + + if (AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) + { + InfoPtr->TimerResolution = 24; + } + else + { + InfoPtr->TimerResolution = 32; + } + + /* Clear the reserved fields */ + + InfoPtr->Reserved1 = 0; + InfoPtr->Reserved2 = 0; + + /* Current debug levels */ + + InfoPtr->DebugLayer = AcpiDbgLayer; + InfoPtr->DebugLevel = AcpiDbgLevel; + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiGetSystemInfo) + + +/******************************************************************************* + * + * FUNCTION: AcpiGetStatistics + * + * PARAMETERS: Stats - Where the statistics are returned + * + * RETURN: Status - the status of the call + * + * DESCRIPTION: Get the contents of the various system counters + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetStatistics ( + ACPI_STATISTICS *Stats) +{ + ACPI_FUNCTION_TRACE (AcpiGetStatistics); + + + /* Parameter validation */ + + if (!Stats) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Various interrupt-based event counters */ + + Stats->SciCount = AcpiSciCount; + Stats->GpeCount = AcpiGpeCount; + + memcpy (Stats->FixedEventCount, AcpiFixedEventCount, + sizeof (AcpiFixedEventCount)); + + /* Other counters */ + + Stats->MethodCount = AcpiMethodCount; + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiGetStatistics) + + +/***************************************************************************** + * + * FUNCTION: AcpiInstallInitializationHandler + * + * PARAMETERS: Handler - Callback procedure + * Function - Not (currently) used, see below + * + * RETURN: Status + * + * DESCRIPTION: Install an initialization handler + * + * TBD: When a second function is added, must save the Function also. + * + ****************************************************************************/ + +ACPI_STATUS +AcpiInstallInitializationHandler ( + ACPI_INIT_HANDLER Handler, + UINT32 Function) +{ + + if (!Handler) + { + return (AE_BAD_PARAMETER); + } + + if (AcpiGbl_InitHandler) + { + return (AE_ALREADY_EXISTS); + } + + AcpiGbl_InitHandler = Handler; + return (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallInitializationHandler) + + +/***************************************************************************** + * + * FUNCTION: AcpiPurgeCachedObjects + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Empty all caches (delete the cached objects) + * + ****************************************************************************/ + +ACPI_STATUS +AcpiPurgeCachedObjects ( + void) +{ + ACPI_FUNCTION_TRACE (AcpiPurgeCachedObjects); + + + (void) AcpiOsPurgeCache (AcpiGbl_StateCache); + (void) AcpiOsPurgeCache (AcpiGbl_OperandCache); + (void) AcpiOsPurgeCache (AcpiGbl_PsNodeCache); + (void) AcpiOsPurgeCache (AcpiGbl_PsNodeExtCache); + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiPurgeCachedObjects) + + +/***************************************************************************** + * + * FUNCTION: AcpiInstallInterface + * + * PARAMETERS: InterfaceName - The interface to install + * + * RETURN: Status + * + * DESCRIPTION: Install an _OSI interface to the global list + * + ****************************************************************************/ + +ACPI_STATUS +AcpiInstallInterface ( + ACPI_STRING InterfaceName) +{ + ACPI_STATUS Status; + ACPI_INTERFACE_INFO *InterfaceInfo; + + + /* Parameter validation */ + + if (!InterfaceName || (strlen (InterfaceName) == 0)) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Check if the interface name is already in the global list */ + + InterfaceInfo = AcpiUtGetInterface (InterfaceName); + if (InterfaceInfo) + { + /* + * The interface already exists in the list. This is OK if the + * interface has been marked invalid -- just clear the bit. + */ + if (InterfaceInfo->Flags & ACPI_OSI_INVALID) + { + InterfaceInfo->Flags &= ~ACPI_OSI_INVALID; + Status = AE_OK; + } + else + { + Status = AE_ALREADY_EXISTS; + } + } + else + { + /* New interface name, install into the global list */ + + Status = AcpiUtInstallInterface (InterfaceName); + } + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallInterface) + + +/***************************************************************************** + * + * FUNCTION: AcpiRemoveInterface + * + * PARAMETERS: InterfaceName - The interface to remove + * + * RETURN: Status + * + * DESCRIPTION: Remove an _OSI interface from the global list + * + ****************************************************************************/ + +ACPI_STATUS +AcpiRemoveInterface ( + ACPI_STRING InterfaceName) +{ + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!InterfaceName || (strlen (InterfaceName) == 0)) + { + return (AE_BAD_PARAMETER); + } + + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtRemoveInterface (InterfaceName); + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRemoveInterface) + + +/***************************************************************************** + * + * FUNCTION: AcpiInstallInterfaceHandler + * + * PARAMETERS: Handler - The _OSI interface handler to install + * NULL means "remove existing handler" + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for the predefined _OSI ACPI method. + * invoked during execution of the internal implementation of + * _OSI. A NULL handler simply removes any existing handler. + * + ****************************************************************************/ + +ACPI_STATUS +AcpiInstallInterfaceHandler ( + ACPI_INTERFACE_HANDLER Handler) +{ + ACPI_STATUS Status; + + + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Handler && AcpiGbl_InterfaceHandler) + { + Status = AE_ALREADY_EXISTS; + } + else + { + AcpiGbl_InterfaceHandler = Handler; + } + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallInterfaceHandler) + + +/***************************************************************************** + * + * FUNCTION: AcpiUpdateInterfaces + * + * PARAMETERS: Action - Actions to be performed during the + * update + * + * RETURN: Status + * + * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor + * string or/and feature group strings. + * + ****************************************************************************/ + +ACPI_STATUS +AcpiUpdateInterfaces ( + UINT8 Action) +{ + ACPI_STATUS Status; + + + Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtUpdateInterfaces (Action); + + AcpiOsReleaseMutex (AcpiGbl_OsiMutex); + return (Status); +} + + +/***************************************************************************** + * + * FUNCTION: AcpiCheckAddressRange + * + * PARAMETERS: SpaceId - Address space ID + * Address - Start address + * Length - Length + * Warn - TRUE if warning on overlap desired + * + * RETURN: Count of the number of conflicts detected. + * + * DESCRIPTION: Check if the input address range overlaps any of the + * ASL operation region address ranges. + * + ****************************************************************************/ + +UINT32 +AcpiCheckAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + ACPI_SIZE Length, + BOOLEAN Warn) +{ + UINT32 Overlaps; + ACPI_STATUS Status; + + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return (0); + } + + Overlaps = AcpiUtCheckAddressRange (SpaceId, Address, + (UINT32) Length, Warn); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return (Overlaps); +} + +ACPI_EXPORT_SYMBOL (AcpiCheckAddressRange) + +#endif /* !ACPI_ASL_COMPILER */ + + +/******************************************************************************* + * + * FUNCTION: AcpiDecodePldBuffer + * + * PARAMETERS: InBuffer - Buffer returned by _PLD method + * Length - Length of the InBuffer + * ReturnBuffer - Where the decode buffer is returned + * + * RETURN: Status and the decoded _PLD buffer. User must deallocate + * the buffer via ACPI_FREE. + * + * DESCRIPTION: Decode the bit-packed buffer returned by the _PLD method into + * a local struct that is much more useful to an ACPI driver. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiDecodePldBuffer ( + UINT8 *InBuffer, + ACPI_SIZE Length, + ACPI_PLD_INFO **ReturnBuffer) +{ + ACPI_PLD_INFO *PldInfo; + UINT32 *Buffer = ACPI_CAST_PTR (UINT32, InBuffer); + UINT32 Dword; + + + /* Parameter validation */ + + if (!InBuffer || !ReturnBuffer || (Length < ACPI_PLD_REV1_BUFFER_SIZE)) + { + return (AE_BAD_PARAMETER); + } + + PldInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PLD_INFO)); + if (!PldInfo) + { + return (AE_NO_MEMORY); + } + + /* First 32-bit DWord */ + + ACPI_MOVE_32_TO_32 (&Dword, &Buffer[0]); + PldInfo->Revision = ACPI_PLD_GET_REVISION (&Dword); + PldInfo->IgnoreColor = ACPI_PLD_GET_IGNORE_COLOR (&Dword); + PldInfo->Red = ACPI_PLD_GET_RED (&Dword); + PldInfo->Green = ACPI_PLD_GET_GREEN (&Dword); + PldInfo->Blue = ACPI_PLD_GET_BLUE (&Dword); + + /* Second 32-bit DWord */ + + ACPI_MOVE_32_TO_32 (&Dword, &Buffer[1]); + PldInfo->Width = ACPI_PLD_GET_WIDTH (&Dword); + PldInfo->Height = ACPI_PLD_GET_HEIGHT(&Dword); + + /* Third 32-bit DWord */ + + ACPI_MOVE_32_TO_32 (&Dword, &Buffer[2]); + PldInfo->UserVisible = ACPI_PLD_GET_USER_VISIBLE (&Dword); + PldInfo->Dock = ACPI_PLD_GET_DOCK (&Dword); + PldInfo->Lid = ACPI_PLD_GET_LID (&Dword); + PldInfo->Panel = ACPI_PLD_GET_PANEL (&Dword); + PldInfo->VerticalPosition = ACPI_PLD_GET_VERTICAL (&Dword); + PldInfo->HorizontalPosition = ACPI_PLD_GET_HORIZONTAL (&Dword); + PldInfo->Shape = ACPI_PLD_GET_SHAPE (&Dword); + PldInfo->GroupOrientation = ACPI_PLD_GET_ORIENTATION (&Dword); + PldInfo->GroupToken = ACPI_PLD_GET_TOKEN (&Dword); + PldInfo->GroupPosition = ACPI_PLD_GET_POSITION (&Dword); + PldInfo->Bay = ACPI_PLD_GET_BAY (&Dword); + + /* Fourth 32-bit DWord */ + + ACPI_MOVE_32_TO_32 (&Dword, &Buffer[3]); + PldInfo->Ejectable = ACPI_PLD_GET_EJECTABLE (&Dword); + PldInfo->OspmEjectRequired = ACPI_PLD_GET_OSPM_EJECT (&Dword); + PldInfo->CabinetNumber = ACPI_PLD_GET_CABINET (&Dword); + PldInfo->CardCageNumber = ACPI_PLD_GET_CARD_CAGE (&Dword); + PldInfo->Reference = ACPI_PLD_GET_REFERENCE (&Dword); + PldInfo->Rotation = ACPI_PLD_GET_ROTATION (&Dword); + PldInfo->Order = ACPI_PLD_GET_ORDER (&Dword); + + if (Length >= ACPI_PLD_REV2_BUFFER_SIZE) + { + /* Fifth 32-bit DWord (Revision 2 of _PLD) */ + + ACPI_MOVE_32_TO_32 (&Dword, &Buffer[4]); + PldInfo->VerticalOffset = ACPI_PLD_GET_VERT_OFFSET (&Dword); + PldInfo->HorizontalOffset = ACPI_PLD_GET_HORIZ_OFFSET (&Dword); + } + + *ReturnBuffer = PldInfo; + return (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiDecodePldBuffer) diff --git a/third_party/lib/acpica/source/components/utilities/utxferror.c b/third_party/lib/acpica/source/components/utilities/utxferror.c new file mode 100644 index 000000000..35efd522b --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utxferror.c @@ -0,0 +1,307 @@ +/******************************************************************************* + * + * Module Name: utxferror - Various error/warning output functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utxferror") + +/* + * This module is used for the in-kernel ACPICA as well as the ACPICA + * tools/applications. + */ + +#ifndef ACPI_NO_ERROR_MESSAGES /* Entire module */ + +/******************************************************************************* + * + * FUNCTION: AcpiError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Error" message with module/line/version info + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_ERROR); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiError) + + +/******************************************************************************* + * + * FUNCTION: AcpiException + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Status - Status to be formatted + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Exception" message with module/line/version info + * and decoded ACPI_STATUS. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiException ( + const char *ModuleName, + UINT32 LineNumber, + ACPI_STATUS Status, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + + /* For AE_OK, just print the message */ + + if (ACPI_SUCCESS (Status)) + { + AcpiOsPrintf (ACPI_MSG_EXCEPTION); + + } + else + { + AcpiOsPrintf (ACPI_MSG_EXCEPTION "%s, ", + AcpiFormatException (Status)); + } + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiException) + + +/******************************************************************************* + * + * FUNCTION: AcpiWarning + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Warning" message with module/line/version info + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_WARNING); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiWarning) + + +/******************************************************************************* + * + * FUNCTION: AcpiInfo + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print generic "ACPI:" information message. There is no + * module/line/version info in order to keep the message simple. + * + * TBD: ModuleName and LineNumber args are not needed, should be removed. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiInfo ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_INFO); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + AcpiOsPrintf ("\n"); + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiInfo) + + +/******************************************************************************* + * + * FUNCTION: AcpiBiosError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Firmware Error" message with module/line/version + * info + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiBiosError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_BIOS_ERROR); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiBiosError) + + +/******************************************************************************* + * + * FUNCTION: AcpiBiosWarning + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Firmware Warning" message with module/line/version + * info + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiBiosWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_BIOS_WARNING); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiBiosWarning) + +#endif /* ACPI_NO_ERROR_MESSAGES */ diff --git a/third_party/lib/acpica/source/components/utilities/utxfinit.c b/third_party/lib/acpica/source/components/utilities/utxfinit.c new file mode 100644 index 000000000..898a75cf3 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utxfinit.c @@ -0,0 +1,403 @@ +/****************************************************************************** + * + * Module Name: utxfinit - External interfaces for ACPICA initialization + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define EXPORT_ACPI_INTERFACES + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acdebug.h" +#include "actables.h" + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utxfinit") + +/* For AcpiExec only */ +void +AeDoObjectOverrides ( + void); + + +/******************************************************************************* + * + * FUNCTION: AcpiInitializeSubsystem + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initializes all global variables. This is the first function + * called, so any early initialization belongs here. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInitializeSubsystem ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiInitializeSubsystem); + + + AcpiGbl_StartupFlags = ACPI_SUBSYSTEM_INITIALIZE; + ACPI_DEBUG_EXEC (AcpiUtInitStackPtrTrace ()); + + /* Initialize the OS-Dependent layer */ + + Status = AcpiOsInitialize (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During OSL initialization")); + return_ACPI_STATUS (Status); + } + + /* Initialize all globals used by the subsystem */ + + Status = AcpiUtInitGlobals (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During initialization of globals")); + return_ACPI_STATUS (Status); + } + + /* Create the default mutex objects */ + + Status = AcpiUtMutexInitialize (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During Global Mutex creation")); + return_ACPI_STATUS (Status); + } + + /* + * Initialize the namespace manager and + * the root of the namespace tree + */ + Status = AcpiNsRootInitialize (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During Namespace initialization")); + return_ACPI_STATUS (Status); + } + + /* Initialize the global OSI interfaces list with the static names */ + + Status = AcpiUtInitializeInterfaces (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During OSI interfaces initialization")); + return_ACPI_STATUS (Status); + } + + if (!AcpiGbl_OverrideDefaultRegionHandlers) + { + /* + * Install the default operation region handlers. These are the + * handlers that are defined by the ACPI specification to be + * "always accessible" -- namely, SystemMemory, SystemIO, and + * PCI_Config. This also means that no _REG methods need to be + * run for these address spaces. We need to have these handlers + * installed before any AML code can be executed, especially any + * module-level code (11/2015). + */ + Status = AcpiEvInstallRegionHandlers (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During Region initialization")); + return_ACPI_STATUS (Status); + } + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiInitializeSubsystem) + + +/******************************************************************************* + * + * FUNCTION: AcpiEnableSubsystem + * + * PARAMETERS: Flags - Init/enable Options + * + * RETURN: Status + * + * DESCRIPTION: Completes the subsystem initialization including hardware. + * Puts system into ACPI mode if it isn't already. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnableSubsystem ( + UINT32 Flags) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (AcpiEnableSubsystem); + + + /* + * The early initialization phase is complete. The namespace is loaded, + * and we can now support address spaces other than Memory, I/O, and + * PCI_Config. + */ + AcpiGbl_EarlyInitialization = FALSE; + + if (AcpiGbl_OverrideDefaultRegionHandlers) + { + /* + * Install the default operation region handlers. These are the + * handlers that are defined by the ACPI specification to be + * "always accessible" -- namely, SystemMemory, SystemIO, and + * PCI_Config. This also means that no _REG methods need to be + * run for these address spaces. We need to have these handlers + * installed before any AML code can be executed, especially any + * module-level code (11/2015). + */ + Status = AcpiEvInstallRegionHandlers (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "During Region initialization")); + return_ACPI_STATUS (Status); + } + } + + +#if (!ACPI_REDUCED_HARDWARE) + + /* Enable ACPI mode */ + + if (!(Flags & ACPI_NO_ACPI_ENABLE)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n")); + + AcpiGbl_OriginalMode = AcpiHwGetMode(); + + Status = AcpiEnable (); + if (ACPI_FAILURE (Status)) + { + ACPI_WARNING ((AE_INFO, "AcpiEnable failed")); + return_ACPI_STATUS (Status); + } + } + + /* + * Obtain a permanent mapping for the FACS. This is required for the + * Global Lock and the Firmware Waking Vector + */ + if (!(Flags & ACPI_NO_FACS_INIT)) + { + Status = AcpiTbInitializeFacs (); + if (ACPI_FAILURE (Status)) + { + ACPI_WARNING ((AE_INFO, "Could not map the FACS table")); + return_ACPI_STATUS (Status); + } + } + + /* + * Initialize ACPI Event handling (Fixed and General Purpose) + * + * Note1: We must have the hardware and events initialized before we can + * execute any control methods safely. Any control method can require + * ACPI hardware support, so the hardware must be fully initialized before + * any method execution! + * + * Note2: Fixed events are initialized and enabled here. GPEs are + * initialized, but cannot be enabled until after the hardware is + * completely initialized (SCI and GlobalLock activated) and the various + * initialization control methods are run (_REG, _STA, _INI) on the + * entire namespace. + */ + if (!(Flags & ACPI_NO_EVENT_INIT)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI events\n")); + + Status = AcpiEvInitializeEvents (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * Install the SCI handler and Global Lock handler. This completes the + * hardware initialization. + */ + if (!(Flags & ACPI_NO_HANDLER_INIT)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Installing SCI/GL handlers\n")); + + Status = AcpiEvInstallXruptHandlers (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + +#endif /* !ACPI_REDUCED_HARDWARE */ + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiEnableSubsystem) + + +/******************************************************************************* + * + * FUNCTION: AcpiInitializeObjects + * + * PARAMETERS: Flags - Init/enable Options + * + * RETURN: Status + * + * DESCRIPTION: Completes namespace initialization by initializing device + * objects and executing AML code for Regions, buffers, etc. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInitializeObjects ( + UINT32 Flags) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (AcpiInitializeObjects); + + + /* + * Run all _REG methods + * + * Note: Any objects accessed by the _REG methods will be automatically + * initialized, even if they contain executable AML (see the call to + * AcpiNsInitializeObjects below). + */ + if (!(Flags & ACPI_NO_ADDRESS_SPACE_INIT)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Executing _REG OpRegion methods\n")); + + Status = AcpiEvInitializeOpRegions (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + +#ifdef ACPI_EXEC_APP + /* + * This call implements the "initialization file" option for AcpiExec. + * This is the precise point that we want to perform the overrides. + */ + AeDoObjectOverrides (); +#endif + + /* + * Execute any module-level code that was detected during the table load + * phase. Although illegal since ACPI 2.0, there are many machines that + * contain this type of code. Each block of detected executable AML code + * outside of any control method is wrapped with a temporary control + * method object and placed on a global list. The methods on this list + * are executed below. + * + * This case executes the module-level code for all tables only after + * all of the tables have been loaded. It is a legacy option and is + * not compatible with other ACPI implementations. See AcpiNsLoadTable. + */ + if (AcpiGbl_GroupModuleLevelCode) + { + AcpiNsExecModuleCodeList (); + } + + /* + * Initialize the objects that remain uninitialized. This runs the + * executable AML that may be part of the declaration of these objects: + * OperationRegions, BufferFields, Buffers, and Packages. + */ + if (!(Flags & ACPI_NO_OBJECT_INIT)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Completing Initialization of ACPI Objects\n")); + + Status = AcpiNsInitializeObjects (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * Initialize all device objects in the namespace. This runs the device + * _STA and _INI methods. + */ + if (!(Flags & ACPI_NO_DEVICE_INIT)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI Devices\n")); + + Status = AcpiNsInitializeDevices (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * Empty the caches (delete the cached objects) on the assumption that + * the table load filled them up more than they will be at runtime -- + * thus wasting non-paged memory. + */ + Status = AcpiPurgeCachedObjects (); + + AcpiGbl_StartupFlags |= ACPI_INITIALIZED_OK; + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL_INIT (AcpiInitializeObjects) diff --git a/third_party/lib/acpica/source/components/utilities/utxfmutex.c b/third_party/lib/acpica/source/components/utilities/utxfmutex.c new file mode 100644 index 000000000..f47fbe554 --- /dev/null +++ b/third_party/lib/acpica/source/components/utilities/utxfmutex.c @@ -0,0 +1,211 @@ +/******************************************************************************* + * + * Module Name: utxfmutex - external AML mutex access functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utxfmutex") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiUtGetMutexObject ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + ACPI_OPERAND_OBJECT **RetObj); + + +/******************************************************************************* + * + * FUNCTION: AcpiUtGetMutexObject + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * RetObj - Where the mutex object is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an AML mutex object. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiUtGetMutexObject ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + ACPI_OPERAND_OBJECT **RetObj) +{ + ACPI_NAMESPACE_NODE *MutexNode; + ACPI_OPERAND_OBJECT *MutexObj; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!RetObj || (!Handle && !Pathname)) + { + return (AE_BAD_PARAMETER); + } + + /* Get a the namespace node for the mutex */ + + MutexNode = Handle; + if (Pathname != NULL) + { + Status = AcpiGetHandle ( + Handle, Pathname, ACPI_CAST_PTR (ACPI_HANDLE, &MutexNode)); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Ensure that we actually have a Mutex object */ + + if (!MutexNode || + (MutexNode->Type != ACPI_TYPE_MUTEX)) + { + return (AE_TYPE); + } + + /* Get the low-level mutex object */ + + MutexObj = AcpiNsGetAttachedObject (MutexNode); + if (!MutexObj) + { + return (AE_NULL_OBJECT); + } + + *RetObj = MutexObj; + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiAcquireMutex + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * Timeout - Max time to wait for the lock (millisec) + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex. This is a device driver interface to + * AML mutex objects, and allows for transaction locking between + * drivers and AML code. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiAcquireMutex ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + UINT16 Timeout) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *MutexObj; + + + /* Get the low-level mutex associated with Handle:Pathname */ + + Status = AcpiUtGetMutexObject (Handle, Pathname, &MutexObj); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Acquire the OS mutex */ + + Status = AcpiOsAcquireMutex (MutexObj->Mutex.OsMutex, Timeout); + return (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiReleaseMutex + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * + * RETURN: Status + * + * DESCRIPTION: Release an AML mutex. This is a device driver interface to + * AML mutex objects, and allows for transaction locking between + * drivers and AML code. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReleaseMutex ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *MutexObj; + + + /* Get the low-level mutex associated with Handle:Pathname */ + + Status = AcpiUtGetMutexObject (Handle, Pathname, &MutexObj); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Release the OS mutex */ + + AcpiOsReleaseMutex (MutexObj->Mutex.OsMutex); + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/include/acapps.h b/third_party/lib/acpica/source/include/acapps.h new file mode 100644 index 000000000..87284f20b --- /dev/null +++ b/third_party/lib/acpica/source/include/acapps.h @@ -0,0 +1,226 @@ +/****************************************************************************** + * + * Module Name: acapps - common include for ACPI applications/tools + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACAPPS +#define _ACAPPS + +#include + +#ifdef _MSC_VER /* disable some level-4 warnings */ +#pragma warning(disable:4100) /* warning C4100: unreferenced formal parameter */ +#endif + +/* Common info for tool signons */ + +#define ACPICA_NAME "Intel ACPI Component Architecture" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2016 Intel Corporation" + +#if ACPI_MACHINE_WIDTH == 64 +#define ACPI_WIDTH "-64" + +#elif ACPI_MACHINE_WIDTH == 32 +#define ACPI_WIDTH "-32" + +#else +#error unknown ACPI_MACHINE_WIDTH +#define ACPI_WIDTH "-??" + +#endif + +/* Macros for signons and file headers */ + +#define ACPI_COMMON_SIGNON(UtilityName) \ + "\n%s\n%s version %8.8X%s\n%s\n\n", \ + ACPICA_NAME, \ + UtilityName, ((UINT32) ACPI_CA_VERSION), ACPI_WIDTH, \ + ACPICA_COPYRIGHT + +#define ACPI_COMMON_HEADER(UtilityName, Prefix) \ + "%s%s\n%s%s version %8.8X%s\n%s%s\n%s\n", \ + Prefix, ACPICA_NAME, \ + Prefix, UtilityName, ((UINT32) ACPI_CA_VERSION), ACPI_WIDTH, \ + Prefix, ACPICA_COPYRIGHT, \ + Prefix + +/* Macros for usage messages */ + +#define ACPI_USAGE_HEADER(Usage) \ + AcpiOsPrintf ("Usage: %s\nOptions:\n", Usage); + +#define ACPI_USAGE_TEXT(Description) \ + AcpiOsPrintf (Description); + +#define ACPI_OPTION(Name, Description) \ + AcpiOsPrintf (" %-20s%s\n", Name, Description); + + +/* Check for unexpected exceptions */ + +#define ACPI_CHECK_STATUS(Name, Status, Expected) \ + if (Status != Expected) \ + { \ + AcpiOsPrintf ("Unexpected %s from %s (%s-%d)\n", \ + AcpiFormatException (Status), #Name, _AcpiModuleName, __LINE__); \ + } + +/* Check for unexpected non-AE_OK errors */ + + +#define ACPI_CHECK_OK(Name, Status) ACPI_CHECK_STATUS (Name, Status, AE_OK); + +#define FILE_SUFFIX_DISASSEMBLY "dsl" +#define FILE_SUFFIX_BINARY_TABLE ".dat" /* Needs the dot */ + + +/* acfileio */ + +ACPI_STATUS +AcGetAllTablesFromFile ( + char *Filename, + UINT8 GetOnlyAmlTables, + ACPI_NEW_TABLE_DESC **ReturnListHead); + +BOOLEAN +AcIsFileBinary ( + FILE *File); + +ACPI_STATUS +AcValidateTableHeader ( + FILE *File, + long TableOffset); + + +/* Values for GetOnlyAmlTables */ + +#define ACPI_GET_ONLY_AML_TABLES TRUE +#define ACPI_GET_ALL_TABLES FALSE + + +/* + * getopt + */ +int +AcpiGetopt( + int argc, + char **argv, + char *opts); + +int +AcpiGetoptArgument ( + int argc, + char **argv); + +extern int AcpiGbl_Optind; +extern int AcpiGbl_Opterr; +extern int AcpiGbl_SubOptChar; +extern char *AcpiGbl_Optarg; + + +/* + * cmfsize - Common get file size function + */ +UINT32 +CmGetFileSize ( + ACPI_FILE File); + + +/* + * adwalk + */ +void +AcpiDmCrossReferenceNamespace ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot, + ACPI_OWNER_ID OwnerId); + +void +AcpiDmDumpTree ( + ACPI_PARSE_OBJECT *Origin); + +void +AcpiDmFindOrphanMethods ( + ACPI_PARSE_OBJECT *Origin); + +void +AcpiDmFinishNamespaceLoad ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot, + ACPI_OWNER_ID OwnerId); + +void +AcpiDmConvertResourceIndexes ( + ACPI_PARSE_OBJECT *ParseTreeRoot, + ACPI_NAMESPACE_NODE *NamespaceRoot); + + +/* + * adfile + */ +ACPI_STATUS +AdInitialize ( + void); + +char * +FlGenerateFilename ( + char *InputFilename, + char *Suffix); + +ACPI_STATUS +FlSplitInputPathname ( + char *InputPath, + char **OutDirectoryPath, + char **OutFilename); + +char * +AdGenerateFilename ( + char *Prefix, + char *TableId); + +void +AdWriteTable ( + ACPI_TABLE_HEADER *Table, + UINT32 Length, + char *TableName, + char *OemTableId); + +#endif /* _ACAPPS */ diff --git a/third_party/lib/acpica/source/include/acbuffer.h b/third_party/lib/acpica/source/include/acbuffer.h new file mode 100644 index 000000000..78f6db4a9 --- /dev/null +++ b/third_party/lib/acpica/source/include/acbuffer.h @@ -0,0 +1,255 @@ +/****************************************************************************** + * + * Name: acbuffer.h - Support for buffers returned by ACPI predefined names + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACBUFFER_H__ +#define __ACBUFFER_H__ + +/* + * Contains buffer structures for these predefined names: + * _FDE, _GRT, _GTM, _PLD, _SRT + */ + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/* _FDE return value */ + +typedef struct acpi_fde_info +{ + UINT32 Floppy0; + UINT32 Floppy1; + UINT32 Floppy2; + UINT32 Floppy3; + UINT32 Tape; + +} ACPI_FDE_INFO; + +/* + * _GRT return value + * _SRT input value + */ +typedef struct acpi_grt_info +{ + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Valid; + UINT16 Milliseconds; + UINT16 Timezone; + UINT8 Daylight; + UINT8 Reserved[3]; + +} ACPI_GRT_INFO; + +/* _GTM return value */ + +typedef struct acpi_gtm_info +{ + UINT32 PioSpeed0; + UINT32 DmaSpeed0; + UINT32 PioSpeed1; + UINT32 DmaSpeed1; + UINT32 Flags; + +} ACPI_GTM_INFO; + +/* + * Formatted _PLD return value. The minimum size is a package containing + * one buffer. + * Revision 1: Buffer is 16 bytes (128 bits) + * Revision 2: Buffer is 20 bytes (160 bits) + * + * Note: This structure is returned from the AcpiDecodePldBuffer + * interface. + */ +typedef struct acpi_pld_info +{ + UINT8 Revision; + UINT8 IgnoreColor; + UINT8 Red; + UINT8 Green; + UINT8 Blue; + UINT16 Width; + UINT16 Height; + UINT8 UserVisible; + UINT8 Dock; + UINT8 Lid; + UINT8 Panel; + UINT8 VerticalPosition; + UINT8 HorizontalPosition; + UINT8 Shape; + UINT8 GroupOrientation; + UINT8 GroupToken; + UINT8 GroupPosition; + UINT8 Bay; + UINT8 Ejectable; + UINT8 OspmEjectRequired; + UINT8 CabinetNumber; + UINT8 CardCageNumber; + UINT8 Reference; + UINT8 Rotation; + UINT8 Order; + UINT8 Reserved; + UINT16 VerticalOffset; + UINT16 HorizontalOffset; + +} ACPI_PLD_INFO; + + +/* + * Macros to: + * 1) Convert a _PLD buffer to internal ACPI_PLD_INFO format - ACPI_PLD_GET* + * (Used by AcpiDecodePldBuffer) + * 2) Construct a _PLD buffer - ACPI_PLD_SET* + * (Intended for BIOS use only) + */ +#define ACPI_PLD_REV1_BUFFER_SIZE 16 /* For Revision 1 of the buffer (From ACPI spec) */ +#define ACPI_PLD_REV2_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ +#define ACPI_PLD_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ + +/* First 32-bit dword, bits 0:32 */ + +#define ACPI_PLD_GET_REVISION(dword) ACPI_GET_BITS (dword, 0, ACPI_7BIT_MASK) +#define ACPI_PLD_SET_REVISION(dword,value) ACPI_SET_BITS (dword, 0, ACPI_7BIT_MASK, value) /* Offset 0, Len 7 */ + +#define ACPI_PLD_GET_IGNORE_COLOR(dword) ACPI_GET_BITS (dword, 7, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_IGNORE_COLOR(dword,value) ACPI_SET_BITS (dword, 7, ACPI_1BIT_MASK, value) /* Offset 7, Len 1 */ + +#define ACPI_PLD_GET_RED(dword) ACPI_GET_BITS (dword, 8, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_RED(dword,value) ACPI_SET_BITS (dword, 8, ACPI_8BIT_MASK, value) /* Offset 8, Len 8 */ + +#define ACPI_PLD_GET_GREEN(dword) ACPI_GET_BITS (dword, 16, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_GREEN(dword,value) ACPI_SET_BITS (dword, 16, ACPI_8BIT_MASK, value) /* Offset 16, Len 8 */ + +#define ACPI_PLD_GET_BLUE(dword) ACPI_GET_BITS (dword, 24, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_BLUE(dword,value) ACPI_SET_BITS (dword, 24, ACPI_8BIT_MASK, value) /* Offset 24, Len 8 */ + +/* Second 32-bit dword, bits 33:63 */ + +#define ACPI_PLD_GET_WIDTH(dword) ACPI_GET_BITS (dword, 0, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_WIDTH(dword,value) ACPI_SET_BITS (dword, 0, ACPI_16BIT_MASK, value) /* Offset 32+0=32, Len 16 */ + +#define ACPI_PLD_GET_HEIGHT(dword) ACPI_GET_BITS (dword, 16, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_HEIGHT(dword,value) ACPI_SET_BITS (dword, 16, ACPI_16BIT_MASK, value) /* Offset 32+16=48, Len 16 */ + +/* Third 32-bit dword, bits 64:95 */ + +#define ACPI_PLD_GET_USER_VISIBLE(dword) ACPI_GET_BITS (dword, 0, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_USER_VISIBLE(dword,value) ACPI_SET_BITS (dword, 0, ACPI_1BIT_MASK, value) /* Offset 64+0=64, Len 1 */ + +#define ACPI_PLD_GET_DOCK(dword) ACPI_GET_BITS (dword, 1, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_DOCK(dword,value) ACPI_SET_BITS (dword, 1, ACPI_1BIT_MASK, value) /* Offset 64+1=65, Len 1 */ + +#define ACPI_PLD_GET_LID(dword) ACPI_GET_BITS (dword, 2, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_LID(dword,value) ACPI_SET_BITS (dword, 2, ACPI_1BIT_MASK, value) /* Offset 64+2=66, Len 1 */ + +#define ACPI_PLD_GET_PANEL(dword) ACPI_GET_BITS (dword, 3, ACPI_3BIT_MASK) +#define ACPI_PLD_SET_PANEL(dword,value) ACPI_SET_BITS (dword, 3, ACPI_3BIT_MASK, value) /* Offset 64+3=67, Len 3 */ + +#define ACPI_PLD_GET_VERTICAL(dword) ACPI_GET_BITS (dword, 6, ACPI_2BIT_MASK) +#define ACPI_PLD_SET_VERTICAL(dword,value) ACPI_SET_BITS (dword, 6, ACPI_2BIT_MASK, value) /* Offset 64+6=70, Len 2 */ + +#define ACPI_PLD_GET_HORIZONTAL(dword) ACPI_GET_BITS (dword, 8, ACPI_2BIT_MASK) +#define ACPI_PLD_SET_HORIZONTAL(dword,value) ACPI_SET_BITS (dword, 8, ACPI_2BIT_MASK, value) /* Offset 64+8=72, Len 2 */ + +#define ACPI_PLD_GET_SHAPE(dword) ACPI_GET_BITS (dword, 10, ACPI_4BIT_MASK) +#define ACPI_PLD_SET_SHAPE(dword,value) ACPI_SET_BITS (dword, 10, ACPI_4BIT_MASK, value) /* Offset 64+10=74, Len 4 */ + +#define ACPI_PLD_GET_ORIENTATION(dword) ACPI_GET_BITS (dword, 14, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_ORIENTATION(dword,value) ACPI_SET_BITS (dword, 14, ACPI_1BIT_MASK, value) /* Offset 64+14=78, Len 1 */ + +#define ACPI_PLD_GET_TOKEN(dword) ACPI_GET_BITS (dword, 15, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_TOKEN(dword,value) ACPI_SET_BITS (dword, 15, ACPI_8BIT_MASK, value) /* Offset 64+15=79, Len 8 */ + +#define ACPI_PLD_GET_POSITION(dword) ACPI_GET_BITS (dword, 23, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_POSITION(dword,value) ACPI_SET_BITS (dword, 23, ACPI_8BIT_MASK, value) /* Offset 64+23=87, Len 8 */ + +#define ACPI_PLD_GET_BAY(dword) ACPI_GET_BITS (dword, 31, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_BAY(dword,value) ACPI_SET_BITS (dword, 31, ACPI_1BIT_MASK, value) /* Offset 64+31=95, Len 1 */ + +/* Fourth 32-bit dword, bits 96:127 */ + +#define ACPI_PLD_GET_EJECTABLE(dword) ACPI_GET_BITS (dword, 0, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_EJECTABLE(dword,value) ACPI_SET_BITS (dword, 0, ACPI_1BIT_MASK, value) /* Offset 96+0=96, Len 1 */ + +#define ACPI_PLD_GET_OSPM_EJECT(dword) ACPI_GET_BITS (dword, 1, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_OSPM_EJECT(dword,value) ACPI_SET_BITS (dword, 1, ACPI_1BIT_MASK, value) /* Offset 96+1=97, Len 1 */ + +#define ACPI_PLD_GET_CABINET(dword) ACPI_GET_BITS (dword, 2, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_CABINET(dword,value) ACPI_SET_BITS (dword, 2, ACPI_8BIT_MASK, value) /* Offset 96+2=98, Len 8 */ + +#define ACPI_PLD_GET_CARD_CAGE(dword) ACPI_GET_BITS (dword, 10, ACPI_8BIT_MASK) +#define ACPI_PLD_SET_CARD_CAGE(dword,value) ACPI_SET_BITS (dword, 10, ACPI_8BIT_MASK, value) /* Offset 96+10=106, Len 8 */ + +#define ACPI_PLD_GET_REFERENCE(dword) ACPI_GET_BITS (dword, 18, ACPI_1BIT_MASK) +#define ACPI_PLD_SET_REFERENCE(dword,value) ACPI_SET_BITS (dword, 18, ACPI_1BIT_MASK, value) /* Offset 96+18=114, Len 1 */ + +#define ACPI_PLD_GET_ROTATION(dword) ACPI_GET_BITS (dword, 19, ACPI_4BIT_MASK) +#define ACPI_PLD_SET_ROTATION(dword,value) ACPI_SET_BITS (dword, 19, ACPI_4BIT_MASK, value) /* Offset 96+19=115, Len 4 */ + +#define ACPI_PLD_GET_ORDER(dword) ACPI_GET_BITS (dword, 23, ACPI_5BIT_MASK) +#define ACPI_PLD_SET_ORDER(dword,value) ACPI_SET_BITS (dword, 23, ACPI_5BIT_MASK, value) /* Offset 96+23=119, Len 5 */ + +/* Fifth 32-bit dword, bits 128:159 (Revision 2 of _PLD only) */ + +#define ACPI_PLD_GET_VERT_OFFSET(dword) ACPI_GET_BITS (dword, 0, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_VERT_OFFSET(dword,value) ACPI_SET_BITS (dword, 0, ACPI_16BIT_MASK, value) /* Offset 128+0=128, Len 16 */ + +#define ACPI_PLD_GET_HORIZ_OFFSET(dword) ACPI_GET_BITS (dword, 16, ACPI_16BIT_MASK) +#define ACPI_PLD_SET_HORIZ_OFFSET(dword,value) ACPI_SET_BITS (dword, 16, ACPI_16BIT_MASK, value) /* Offset 128+16=144, Len 16 */ + + +#endif /* ACBUFFER_H */ diff --git a/third_party/lib/acpica/source/include/acclib.h b/third_party/lib/acpica/source/include/acclib.h new file mode 100644 index 000000000..56a30723a --- /dev/null +++ b/third_party/lib/acpica/source/include/acclib.h @@ -0,0 +1,167 @@ +/****************************************************************************** + * + * Name: acclib.h -- C library support. Prototypes for the (optional) local + * implementations of required C library functions. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACCLIB_H +#define _ACCLIB_H + + +/* + * Prototypes and macros for local implementations of C library functions + */ + +/* is* functions. The AcpiGbl_Ctypes array is defined in utclib.c */ + +extern const UINT8 AcpiGbl_Ctypes[]; + +#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ +#define _ACPI_XS 0x40 /* extra space */ +#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ +#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ +#define _ACPI_DI 0x04 /* '0'-'9' */ +#define _ACPI_LO 0x02 /* 'a'-'z' */ +#define _ACPI_PU 0x10 /* punctuation */ +#define _ACPI_SP 0x08 /* space, tab, CR, LF, VT, FF */ +#define _ACPI_UP 0x01 /* 'A'-'Z' */ +#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ + +#define isdigit(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_DI)) +#define isspace(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_SP)) +#define isxdigit(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_XD)) +#define isupper(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_UP)) +#define islower(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_LO)) +#define isprint(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) +#define isalpha(c) (AcpiGbl_Ctypes[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) + + +/* Strings */ + +char * +strcat ( + char *DstString, + const char *SrcString); + +char * +strchr ( + const char *String, + int ch); + +char * +strcpy ( + char *DstString, + const char *SrcString); + +int +strcmp ( + const char *String1, + const char *String2); + +ACPI_SIZE +strlen ( + const char *String); + +char * +strncat ( + char *DstString, + const char *SrcString, + ACPI_SIZE Count); + +int +strncmp ( + const char *String1, + const char *String2, + ACPI_SIZE Count); + +char * +strncpy ( + char *DstString, + const char *SrcString, + ACPI_SIZE Count); + +char * +strstr ( + char *String1, + char *String2); + + +/* Conversion */ + +UINT32 +strtoul ( + const char *String, + char **Terminator, + UINT32 Base); + + +/* Memory */ + +int +memcmp ( + void *Buffer1, + void *Buffer2, + ACPI_SIZE Count); + +void * +memcpy ( + void *Dest, + const void *Src, + ACPI_SIZE Count); + +void * +memset ( + void *Dest, + int Value, + ACPI_SIZE Count); + + +/* upper/lower case */ + +int +tolower ( + int c); + +int +toupper ( + int c); + +#endif /* _ACCLIB_H */ diff --git a/third_party/lib/acpica/source/include/accommon.h b/third_party/lib/acpica/source/include/accommon.h new file mode 100644 index 000000000..02e6f5139 --- /dev/null +++ b/third_party/lib/acpica/source/include/accommon.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Name: accommon.h - Common include files for generation of ACPICA source + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACCOMMON_H__ +#define __ACCOMMON_H__ + +/* + * Common set of includes for all ACPICA source files. + * We put them here because we don't want to duplicate them + * in the the source code again and again. + * + * Note: The order of these include files is important. + */ +#include "acconfig.h" /* Global configuration constants */ +#include "acmacros.h" /* C macros */ +#include "aclocal.h" /* Internal data types */ +#include "acobject.h" /* ACPI internal object */ +#include "acstruct.h" /* Common structures */ +#include "acglobal.h" /* All global variables */ +#include "achware.h" /* Hardware defines and interfaces */ +#include "acutils.h" /* Utility interfaces */ +#ifndef ACPI_USE_SYSTEM_CLIBRARY +#include "acclib.h" /* C library interfaces */ +#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ + + +#endif /* __ACCOMMON_H__ */ diff --git a/third_party/lib/acpica/source/include/acconfig.h b/third_party/lib/acpica/source/include/acconfig.h new file mode 100644 index 000000000..a626f8759 --- /dev/null +++ b/third_party/lib/acpica/source/include/acconfig.h @@ -0,0 +1,252 @@ +/****************************************************************************** + * + * Name: acconfig.h - Global configuration constants + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACCONFIG_H +#define _ACCONFIG_H + + +/****************************************************************************** + * + * Configuration options + * + *****************************************************************************/ + +/* + * ACPI_DEBUG_OUTPUT - This switch enables all the debug facilities of the + * ACPI subsystem. This includes the DEBUG_PRINT output + * statements. When disabled, all DEBUG_PRINT + * statements are compiled out. + * + * ACPI_APPLICATION - Use this switch if the subsystem is going to be run + * at the application level. + * + */ + +/* + * OS name, used for the _OS object. The _OS object is essentially obsolete, + * but there is a large base of ASL/AML code in existing machines that check + * for the string below. The use of this string usually guarantees that + * the ASL will execute down the most tested code path. Also, there is some + * code that will not execute the _OSI method unless _OS matches the string + * below. Therefore, change this string at your own risk. + */ +#define ACPI_OS_NAME "Microsoft Windows NT" + +/* Maximum objects in the various object caches */ + +#define ACPI_MAX_STATE_CACHE_DEPTH 96 /* State objects */ +#define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */ +#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */ + +/* + * Should the subsystem abort the loading of an ACPI table if the + * table checksum is incorrect? + */ +#ifndef ACPI_CHECKSUM_ABORT +#define ACPI_CHECKSUM_ABORT FALSE +#endif + +/* + * Generate a version of ACPICA that only supports "reduced hardware" + * platforms (as defined in ACPI 5.0). Set to TRUE to generate a specialized + * version of ACPICA that ONLY supports the ACPI 5.0 "reduced hardware" + * model. In other words, no ACPI hardware is supported. + * + * If TRUE, this means no support for the following: + * PM Event and Control registers + * SCI interrupt (and handler) + * Fixed Events + * General Purpose Events (GPEs) + * Global Lock + * ACPI PM timer + * FACS table (Waking vectors and Global Lock) + */ +#ifndef ACPI_REDUCED_HARDWARE +#define ACPI_REDUCED_HARDWARE FALSE +#endif + + +/****************************************************************************** + * + * Subsystem Constants + * + *****************************************************************************/ + +/* Version of ACPI supported */ + +#define ACPI_CA_SUPPORT_LEVEL 5 + +/* Maximum count for a semaphore object */ + +#define ACPI_MAX_SEMAPHORE_COUNT 256 + +/* Maximum object reference count (detects object deletion issues) */ + +#define ACPI_MAX_REFERENCE_COUNT 0x800 + +/* Default page size for use in mapping memory for operation regions */ + +#define ACPI_DEFAULT_PAGE_SIZE 4096 /* Must be power of 2 */ + +/* OwnerId tracking. 8 entries allows for 255 OwnerIds */ + +#define ACPI_NUM_OWNERID_MASKS 8 + +/* Size of the root table array is increased by this increment */ + +#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 + +/* Maximum sleep allowed via Sleep() operator */ + +#define ACPI_MAX_SLEEP 2000 /* 2000 millisec == two seconds */ + +/* Address Range lists are per-SpaceId (Memory and I/O only) */ + +#define ACPI_ADDRESS_RANGE_MAX 2 + + +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification changes) + * + *****************************************************************************/ + +/* Method info (in WALK_STATE), containing local variables and argumetns */ + +#define ACPI_METHOD_NUM_LOCALS 8 +#define ACPI_METHOD_MAX_LOCAL 7 + +#define ACPI_METHOD_NUM_ARGS 7 +#define ACPI_METHOD_MAX_ARG 6 + +/* + * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG + */ +#define ACPI_OBJ_NUM_OPERANDS 8 +#define ACPI_OBJ_MAX_OPERAND 7 + +/* Number of elements in the Result Stack frame, can be an arbitrary value */ + +#define ACPI_RESULTS_FRAME_OBJ_NUM 8 + +/* + * Maximal number of elements the Result Stack can contain, + * it may be an arbitray value not exceeding the types of + * ResultSize and ResultCount (now UINT8). + */ +#define ACPI_RESULTS_OBJ_NUM_MAX 255 + +/* Constants used in searching for the RSDP in low memory */ + +#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ +#define ACPI_EBDA_PTR_LENGTH 2 +#define ACPI_EBDA_WINDOW_SIZE 1024 +#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ +#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 +#define ACPI_RSDP_SCAN_STEP 16 + +/* Operation regions */ + +#define ACPI_USER_REGION_BEGIN 0x80 + +/* Maximum SpaceIds for Operation Regions */ + +#define ACPI_MAX_ADDRESS_SPACE 255 +#define ACPI_NUM_DEFAULT_SPACES 4 + +/* Array sizes. Used for range checking also */ + +#define ACPI_MAX_MATCH_OPCODE 5 + +/* RSDP checksums */ + +#define ACPI_RSDP_CHECKSUM_LENGTH 20 +#define ACPI_RSDP_XCHECKSUM_LENGTH 36 + +/* SMBus, GSBus and IPMI bidirectional buffer size */ + +#define ACPI_SMBUS_BUFFER_SIZE 34 +#define ACPI_GSBUS_BUFFER_SIZE 34 +#define ACPI_IPMI_BUFFER_SIZE 66 + +/* _SxD and _SxW control methods */ + +#define ACPI_NUM_SxD_METHODS 4 +#define ACPI_NUM_SxW_METHODS 5 + + +/****************************************************************************** + * + * Miscellaneous constants + * + *****************************************************************************/ + +/* UUID constants */ + +#define UUID_BUFFER_LENGTH 16 /* Length of UUID in memory */ +#define UUID_STRING_LENGTH 36 /* Total length of a UUID string */ + +/* Positions for required hyphens (dashes) in UUID strings */ + +#define UUID_HYPHEN1_OFFSET 8 +#define UUID_HYPHEN2_OFFSET 13 +#define UUID_HYPHEN3_OFFSET 18 +#define UUID_HYPHEN4_OFFSET 23 + + +/****************************************************************************** + * + * ACPI AML Debugger + * + *****************************************************************************/ + +#define ACPI_DEBUGGER_MAX_ARGS ACPI_METHOD_NUM_ARGS + 4 /* Max command line arguments */ +#define ACPI_DB_LINE_BUFFER_SIZE 512 + +#define ACPI_DEBUGGER_COMMAND_PROMPT '-' +#define ACPI_DEBUGGER_EXECUTE_PROMPT '%' + + +#endif /* _ACCONFIG_H */ diff --git a/third_party/lib/acpica/source/include/acdebug.h b/third_party/lib/acpica/source/include/acdebug.h new file mode 100644 index 000000000..63b8be88c --- /dev/null +++ b/third_party/lib/acpica/source/include/acdebug.h @@ -0,0 +1,498 @@ +/****************************************************************************** + * + * Name: acdebug.h - ACPI/AML debugger + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACDEBUG_H__ +#define __ACDEBUG_H__ + +/* The debugger is used in conjunction with the disassembler most of time */ + +#ifdef ACPI_DISASSEMBLER +#include "acdisasm.h" +#endif + + +#define ACPI_DEBUG_BUFFER_SIZE 0x4000 /* 16K buffer for return objects */ + +typedef struct acpi_db_command_info +{ + char *Name; /* Command Name */ + UINT8 MinArgs; /* Minimum arguments required */ + +} ACPI_DB_COMMAND_INFO; + +typedef struct acpi_db_command_help +{ + UINT8 LineCount; /* Number of help lines */ + char *Invocation; /* Command Invocation */ + char *Description; /* Command Description */ + +} ACPI_DB_COMMAND_HELP; + +typedef struct acpi_db_argument_info +{ + char *Name; /* Argument Name */ + +} ACPI_DB_ARGUMENT_INFO; + +typedef struct acpi_db_execute_walk +{ + UINT32 Count; + UINT32 MaxCount; + +} ACPI_DB_EXECUTE_WALK; + + +#define PARAM_LIST(pl) pl + +#define EX_NO_SINGLE_STEP 1 +#define EX_SINGLE_STEP 2 + + +/* + * dbxface - external debugger interfaces + */ +ACPI_DBR_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiDbSingleStep ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 OpType)) + +ACPI_DBR_DEPENDENT_RETURN_VOID ( +void +AcpiDbSignalBreakPoint ( + ACPI_WALK_STATE *WalkState)) + + +/* + * dbcmds - debug commands and output routines + */ +ACPI_NAMESPACE_NODE * +AcpiDbConvertToNode ( + char *InString); + +void +AcpiDbDisplayTableInfo ( + char *TableArg); + +void +AcpiDbDisplayTemplate ( + char *BufferArg); + +void +AcpiDbUnloadAcpiTable ( + char *Name); + +void +AcpiDbSendNotify ( + char *Name, + UINT32 Value); + +void +AcpiDbDisplayInterfaces ( + char *ActionArg, + char *InterfaceNameArg); + +ACPI_STATUS +AcpiDbSleep ( + char *ObjectArg); + +void +AcpiDbTrace ( + char *EnableArg, + char *MethodArg, + char *OnceArg); + +void +AcpiDbDisplayLocks ( + void); + +void +AcpiDbDisplayResources ( + char *ObjectArg); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiDbDisplayGpes ( + void)) + +void +AcpiDbDisplayHandlers ( + void); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiDbGenerateGpe ( + char *GpeArg, + char *BlockArg)) + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiDbGenerateSci ( + void)) + +void +AcpiDbExecuteTest ( + char *TypeArg); + + +/* + * dbconvert - miscellaneous conversion routines + */ +ACPI_STATUS +AcpiDbHexCharToValue ( + int HexChar, + UINT8 *ReturnValue); + +ACPI_STATUS +AcpiDbConvertToPackage ( + char *String, + ACPI_OBJECT *Object); + +ACPI_STATUS +AcpiDbConvertToObject ( + ACPI_OBJECT_TYPE Type, + char *String, + ACPI_OBJECT *Object); + +UINT8 * +AcpiDbEncodePldBuffer ( + ACPI_PLD_INFO *PldInfo); + +void +AcpiDbDumpPldBuffer ( + ACPI_OBJECT *ObjDesc); + + +/* + * dbmethod - control method commands + */ +void +AcpiDbSetMethodBreakpoint ( + char *Location, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbSetMethodCallBreakpoint ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbSetMethodData ( + char *TypeArg, + char *IndexArg, + char *ValueArg); + +ACPI_STATUS +AcpiDbDisassembleMethod ( + char *Name); + +void +AcpiDbDisassembleAml ( + char *Statements, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbBatchExecute ( + char *CountArg); + + +/* + * dbnames - namespace commands + */ +void +AcpiDbSetScope ( + char *Name); + +void +AcpiDbDumpNamespace ( + char *StartArg, + char *DepthArg); + +void +AcpiDbDumpNamespacePaths ( + void); + +void +AcpiDbDumpNamespaceByOwner ( + char *OwnerArg, + char *DepthArg); + +ACPI_STATUS +AcpiDbFindNameInNamespace ( + char *NameArg); + +void +AcpiDbCheckPredefinedNames ( + void); + +ACPI_STATUS +AcpiDbDisplayObjects ( + char *ObjTypeArg, + char *DisplayCountArg); + +void +AcpiDbCheckIntegrity ( + void); + +void +AcpiDbFindReferences ( + char *ObjectArg); + +void +AcpiDbGetBusInfo ( + void); + + +/* + * dbdisply - debug display commands + */ +void +AcpiDbDisplayMethodInfo ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDbDecodeAndDisplayObject ( + char *Target, + char *OutputType); + +ACPI_DBR_DEPENDENT_RETURN_VOID ( +void +AcpiDbDisplayResultObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState)) + +ACPI_STATUS +AcpiDbDisplayAllMethods ( + char *DisplayCountArg); + +void +AcpiDbDisplayArguments ( + void); + +void +AcpiDbDisplayLocals ( + void); + +void +AcpiDbDisplayResults ( + void); + +void +AcpiDbDisplayCallingTree ( + void); + +void +AcpiDbDisplayObjectType ( + char *ObjectArg); + +ACPI_DBR_DEPENDENT_RETURN_VOID ( +void +AcpiDbDisplayArgumentObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState)) + + +/* + * dbexec - debugger control method execution + */ +void +AcpiDbExecute ( + char *Name, + char **Args, + ACPI_OBJECT_TYPE *Types, + UINT32 Flags); + +void +AcpiDbCreateExecutionThreads ( + char *NumThreadsArg, + char *NumLoopsArg, + char *MethodNameArg); + +void +AcpiDbDeleteObjects ( + UINT32 Count, + ACPI_OBJECT *Objects); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +UINT32 +AcpiDbGetCacheInfo ( + ACPI_MEMORY_LIST *Cache); +#endif + + +/* + * dbfileio - Debugger file I/O commands + */ +ACPI_OBJECT_TYPE +AcpiDbMatchArgument ( + char *UserArgument, + ACPI_DB_ARGUMENT_INFO *Arguments); + +void +AcpiDbCloseDebugFile ( + void); + +void +AcpiDbOpenDebugFile ( + char *Name); + +ACPI_STATUS +AcpiDbLoadAcpiTable ( + char *Filename); + +ACPI_STATUS +AcpiDbLoadTables ( + ACPI_NEW_TABLE_DESC *ListHead); + + +/* + * dbhistry - debugger HISTORY command + */ +void +AcpiDbAddToHistory ( + char *CommandLine); + +void +AcpiDbDisplayHistory ( + void); + +char * +AcpiDbGetFromHistory ( + char *CommandNumArg); + +char * +AcpiDbGetHistoryByIndex ( + UINT32 CommanddNum); + + +/* + * dbinput - user front-end to the AML debugger + */ +ACPI_STATUS +AcpiDbCommandDispatch ( + char *InputBuffer, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void ACPI_SYSTEM_XFACE +AcpiDbExecuteThread ( + void *Context); + +ACPI_STATUS +AcpiDbUserCommands ( + char Prompt, + ACPI_PARSE_OBJECT *Op); + +char * +AcpiDbGetNextToken ( + char *String, + char **Next, + ACPI_OBJECT_TYPE *ReturnType); + + +/* + * dbobject + */ +void +AcpiDbDecodeInternalObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +void +AcpiDbDisplayInternalObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +void +AcpiDbDecodeArguments ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDbDecodeLocals ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDbDumpMethodInfo ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState); + + +/* + * dbstats - Generation and display of ACPI table statistics + */ +void +AcpiDbGenerateStatistics ( + ACPI_PARSE_OBJECT *Root, + BOOLEAN IsMethod); + +ACPI_STATUS +AcpiDbDisplayStatistics ( + char *TypeArg); + + +/* + * dbutils - AML debugger utilities + */ +void +AcpiDbSetOutputDestination ( + UINT32 Where); + +void +AcpiDbDumpExternalObject ( + ACPI_OBJECT *ObjDesc, + UINT32 Level); + +void +AcpiDbPrepNamestring ( + char *Name); + +ACPI_NAMESPACE_NODE * +AcpiDbLocalNsLookup ( + char *Name); + +void +AcpiDbUint32ToHexString ( + UINT32 Value, + char *Buffer); + +#endif /* __ACDEBUG_H__ */ diff --git a/third_party/lib/acpica/source/include/acdisasm.h b/third_party/lib/acpica/source/include/acdisasm.h new file mode 100644 index 000000000..b6e250ee1 --- /dev/null +++ b/third_party/lib/acpica/source/include/acdisasm.h @@ -0,0 +1,1091 @@ +/****************************************************************************** + * + * Name: acdisasm.h - AML disassembler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACDISASM_H__ +#define __ACDISASM_H__ + +#include "amlresrc.h" + + +#define BLOCK_NONE 0 +#define BLOCK_PAREN 1 +#define BLOCK_BRACE 2 +#define BLOCK_COMMA_LIST 4 +#define ACPI_DEFAULT_RESNAME *(UINT32 *) "__RD" + +/* + * Raw table data header. Used by disassembler and data table compiler. + * Do not change. + */ +#define ACPI_RAW_TABLE_DATA_HEADER "Raw Table Data" + + +typedef struct acpi_dmtable_info +{ + UINT8 Opcode; + UINT16 Offset; + char *Name; + UINT8 Flags; + +} ACPI_DMTABLE_INFO; + +/* Values for Flags field above */ + +#define DT_LENGTH 0x01 /* Field is a subtable length */ +#define DT_FLAG 0x02 /* Field is a flag value */ +#define DT_NON_ZERO 0x04 /* Field must be non-zero */ +#define DT_OPTIONAL 0x08 /* Field is optional */ +#define DT_DESCRIBES_OPTIONAL 0x10 /* Field describes an optional field (length, etc.) */ +#define DT_COUNT 0x20 /* Currently not used */ + +/* + * Values for Opcode above. + * Note: 0-7 must not change, they are used as a flag shift value. Other + * than those, new values can be added wherever appropriate. + */ +typedef enum +{ + /* Simple Data Types */ + + ACPI_DMT_FLAG0 = 0, + ACPI_DMT_FLAG1 = 1, + ACPI_DMT_FLAG2 = 2, + ACPI_DMT_FLAG3 = 3, + ACPI_DMT_FLAG4 = 4, + ACPI_DMT_FLAG5 = 5, + ACPI_DMT_FLAG6 = 6, + ACPI_DMT_FLAG7 = 7, + ACPI_DMT_FLAGS0, + ACPI_DMT_FLAGS1, + ACPI_DMT_FLAGS2, + ACPI_DMT_FLAGS4, + ACPI_DMT_UINT8, + ACPI_DMT_UINT16, + ACPI_DMT_UINT24, + ACPI_DMT_UINT32, + ACPI_DMT_UINT40, + ACPI_DMT_UINT48, + ACPI_DMT_UINT56, + ACPI_DMT_UINT64, + ACPI_DMT_BUF7, + ACPI_DMT_BUF10, + ACPI_DMT_BUF16, + ACPI_DMT_BUF128, + ACPI_DMT_SIG, + ACPI_DMT_STRING, + ACPI_DMT_NAME4, + ACPI_DMT_NAME6, + ACPI_DMT_NAME8, + + /* Types that are decoded to strings and miscellaneous */ + + ACPI_DMT_ACCWIDTH, + ACPI_DMT_CHKSUM, + ACPI_DMT_GAS, + ACPI_DMT_SPACEID, + ACPI_DMT_UNICODE, + ACPI_DMT_UUID, + + /* Types used only for the Data Table Compiler */ + + ACPI_DMT_BUFFER, + ACPI_DMT_RAW_BUFFER, /* Large, multiple line buffer */ + ACPI_DMT_DEVICE_PATH, + ACPI_DMT_LABEL, + ACPI_DMT_PCI_PATH, + + /* Types that are specific to particular ACPI tables */ + + ACPI_DMT_ASF, + ACPI_DMT_DMAR, + ACPI_DMT_DMAR_SCOPE, + ACPI_DMT_EINJACT, + ACPI_DMT_EINJINST, + ACPI_DMT_ERSTACT, + ACPI_DMT_ERSTINST, + ACPI_DMT_FADTPM, + ACPI_DMT_GTDT, + ACPI_DMT_HEST, + ACPI_DMT_HESTNTFY, + ACPI_DMT_HESTNTYP, + ACPI_DMT_IORTMEM, + ACPI_DMT_IVRS, + ACPI_DMT_LPIT, + ACPI_DMT_MADT, + ACPI_DMT_NFIT, + ACPI_DMT_PCCT, + ACPI_DMT_PMTT, + ACPI_DMT_SLIC, + ACPI_DMT_SRAT, + + /* Special opcodes */ + + ACPI_DMT_EXTRA_TEXT, + ACPI_DMT_EXIT + +} ACPI_ENTRY_TYPES; + +typedef +void (*ACPI_DMTABLE_HANDLER) ( + ACPI_TABLE_HEADER *Table); + +typedef +ACPI_STATUS (*ACPI_CMTABLE_HANDLER) ( + void **PFieldList); + +typedef struct acpi_dmtable_data +{ + char *Signature; + ACPI_DMTABLE_INFO *TableInfo; + ACPI_DMTABLE_HANDLER TableHandler; + ACPI_CMTABLE_HANDLER CmTableHandler; + const unsigned char *Template; + +} ACPI_DMTABLE_DATA; + + +typedef struct acpi_op_walk_info +{ + ACPI_WALK_STATE *WalkState; + ACPI_PARSE_OBJECT *MappingOp; + UINT8 *PreviousAml; + UINT8 *StartAml; + UINT32 Level; + UINT32 LastLevel; + UINT32 Count; + UINT32 BitOffset; + UINT32 Flags; + UINT32 AmlOffset; + +} ACPI_OP_WALK_INFO; + +/* + * TBD - another copy of this is in asltypes.h, fix + */ +#ifndef ASL_WALK_CALLBACK_DEFINED +typedef +ACPI_STATUS (*ASL_WALK_CALLBACK) ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context); +#define ASL_WALK_CALLBACK_DEFINED +#endif + +typedef +void (*ACPI_RESOURCE_HANDLER) ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +typedef struct acpi_resource_tag +{ + UINT32 BitIndex; + char *Tag; + +} ACPI_RESOURCE_TAG; + +/* Strings used for decoding flags to ASL keywords */ + +extern const char *AcpiGbl_WordDecode[]; +extern const char *AcpiGbl_IrqDecode[]; +extern const char *AcpiGbl_LockRule[]; +extern const char *AcpiGbl_AccessTypes[]; +extern const char *AcpiGbl_UpdateRules[]; +extern const char *AcpiGbl_MatchOps[]; + +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsf4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoAsfHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoBoot[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoBert[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoBgrt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCpep[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCpep0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoCsrt2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Device[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Addr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Size[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2Name[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbg2OemData[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDbgp[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmarHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmarScope[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDmar4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoDrtm2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoEcdt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoEinj[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoEinj0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoErst[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoErst0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFacs[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt5[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFadt6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdtHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoFpdt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGas[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdtHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGtdt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHeader[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest7[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest8[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHest9[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHestNotify[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHestBank[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoHpet[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoLpitHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoLpit0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoLpit1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort0a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3b[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIort3c[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortAcc[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortMap[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIortPad[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8b[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrs8c[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoIvrsHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt5[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt7[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt8[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt9[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt10[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt11[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt12[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt13[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt14[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadt15[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMadtHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMcfg[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMcfg0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMchi[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0A[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst0B[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMpst2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMsct[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMsct0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMtmr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoMtmr0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfitHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit2a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit3a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit4[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit5[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit6[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoNfit6a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt1a[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmtt2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPmttHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcctHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoPcct1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoRsdp1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoRsdp2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3ptHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSbst[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlic[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlit[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSpcr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSpmi[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSratHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat1[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoSrat3[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoStao[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoStaoStr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaHdr[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaClient[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTcpaServer[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoTpm2[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoUefi[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoVrtc[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoVrtc0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWaet[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdat[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdat0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWddt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdrt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWpbt[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoWpbt0[]; +extern ACPI_DMTABLE_INFO AcpiDmTableInfoXenv[]; + +extern ACPI_DMTABLE_INFO AcpiDmTableInfoGeneric[][2]; + +/* + * dmtable and ahtable + */ +extern const ACPI_DMTABLE_DATA AcpiDmTableData[]; +extern const AH_TABLE AcpiSupportedTables[]; + +UINT8 +AcpiDmGenerateChecksum ( + void *Table, + UINT32 Length, + UINT8 OriginalChecksum); + +const ACPI_DMTABLE_DATA * +AcpiDmGetTableData ( + char *Signature); + +void +AcpiDmDumpDataTable ( + ACPI_TABLE_HEADER *Table); + +ACPI_STATUS +AcpiDmDumpTable ( + UINT32 TableLength, + UINT32 TableOffset, + void *Table, + UINT32 SubTableLength, + ACPI_DMTABLE_INFO *Info); + +void +AcpiDmLineHeader ( + UINT32 Offset, + UINT32 ByteLength, + char *Name); + +void +AcpiDmLineHeader2 ( + UINT32 Offset, + UINT32 ByteLength, + char *Name, + UINT32 Value); + + +/* + * dmtbdump + */ +void +AcpiDmDumpBuffer ( + void *Table, + UINT32 BufferOffset, + UINT32 Length, + UINT32 AbsoluteOffset, + char *Header); + +void +AcpiDmDumpUnicode ( + void *Table, + UINT32 BufferOffset, + UINT32 ByteLength); + +void +AcpiDmDumpAsf ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpCpep ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpCsrt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpDbg2 ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpDmar ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpDrtm ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpEinj ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpErst ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpFadt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpFpdt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpGtdt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpHest ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpIort ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpIvrs ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpLpit ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMadt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMcfg ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMpst ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMsct ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpMtmr ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpNfit ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpPcct ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpPmtt ( + ACPI_TABLE_HEADER *Table); + +UINT32 +AcpiDmDumpRsdp ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpRsdt ( + ACPI_TABLE_HEADER *Table); + +UINT32 +AcpiDmDumpS3pt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSlic ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSlit ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpSrat ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpStao ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpTcpa ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpVrtc ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpWdat ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpWpbt ( + ACPI_TABLE_HEADER *Table); + +void +AcpiDmDumpXsdt ( + ACPI_TABLE_HEADER *Table); + + +/* + * dmwalk + */ +void +AcpiDmDisassemble ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Origin, + UINT32 NumOpcodes); + +void +AcpiDmWalkParseTree ( + ACPI_PARSE_OBJECT *Op, + ASL_WALK_CALLBACK DescendingCallback, + ASL_WALK_CALLBACK AscendingCallback, + void *Context); + + +/* + * dmopcode + */ +void +AcpiDmDisassembleOneOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op); + +UINT32 +AcpiDmListType ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmMethodFlags ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmDisplayTargetPathname ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmNotifyDescription ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmPredefinedDescription ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmFieldPredefinedDescription ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmFieldFlags ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmAddressSpace ( + UINT8 SpaceId); + +void +AcpiDmRegionFlags ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmMatchOp ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmnames + */ +UINT32 +AcpiDmDumpName ( + UINT32 Name); + +ACPI_STATUS +AcpiPsDisplayObjectPathname ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmNamestring ( + char *Name); + + +/* + * dmbuffer + */ +void +AcpiDmDisasmByteList ( + UINT32 Level, + UINT8 *ByteData, + UINT32 ByteCount); + +void +AcpiDmByteList ( + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmCheckForHardwareId ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmDecompressEisaId ( + UINT32 EncodedId); + +BOOLEAN +AcpiDmIsUuidBuffer ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiDmIsUnicodeBuffer ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiDmIsStringBuffer ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiDmIsPldBuffer ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmdeferred + */ +ACPI_STATUS +AcpiDmParseDeferredOps ( + ACPI_PARSE_OBJECT *Root); + + +/* + * dmextern + */ +ACPI_STATUS +AcpiDmAddToExternalFileList ( + char *PathList); + +void +AcpiDmClearExternalFileList ( + void); + +void +AcpiDmAddOpToExternalList ( + ACPI_PARSE_OBJECT *Op, + char *Path, + UINT8 Type, + UINT32 Value, + UINT16 Flags); + +void +AcpiDmAddNodeToExternalList ( + ACPI_NAMESPACE_NODE *Node, + UINT8 Type, + UINT32 Value, + UINT16 Flags); + +void +AcpiDmAddExternalsToNamespace ( + void); + +UINT32 +AcpiDmGetExternalMethodCount ( + void); + +void +AcpiDmClearExternalList ( + void); + +void +AcpiDmEmitExternals ( + void); + +void +AcpiDmUnresolvedWarning ( + UINT8 Type); + +void +AcpiDmGetExternalsFromFile ( + void); + +/* + * dmresrc + */ +void +AcpiDmDumpInteger8 ( + UINT8 Value, + char *Name); + +void +AcpiDmDumpInteger16 ( + UINT16 Value, + char *Name); + +void +AcpiDmDumpInteger32 ( + UINT32 Value, + char *Name); + +void +AcpiDmDumpInteger64 ( + UINT64 Value, + char *Name); + +void +AcpiDmResourceTemplate ( + ACPI_OP_WALK_INFO *Info, + ACPI_PARSE_OBJECT *Op, + UINT8 *ByteData, + UINT32 ByteCount); + +ACPI_STATUS +AcpiDmIsResourceTemplate ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmBitList ( + UINT16 Mask); + +void +AcpiDmDescriptorName ( + void); + + +/* + * dmresrcl + */ +void +AcpiDmWordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmDwordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmExtendedDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmQwordDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmMemory24Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmMemory32Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmFixedMemory32Descriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmGenericRegisterDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmInterruptDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmVendorLargeDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmGpioDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmSerialBusDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmVendorCommon ( + char *Name, + UINT8 *ByteData, + UINT32 Length, + UINT32 Level); + + +/* + * dmresrcs + */ +void +AcpiDmIrqDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmDmaDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmFixedDmaDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmFixedIoDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmStartDependentDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmEndDependentDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + +void +AcpiDmVendorSmallDescriptor ( + ACPI_OP_WALK_INFO *Info, + AML_RESOURCE *Resource, + UINT32 Length, + UINT32 Level); + + +/* + * dmutils + */ +void +AcpiDmDecodeAttribute ( + UINT8 Attribute); + +void +AcpiDmIndent ( + UINT32 Level); + +BOOLEAN +AcpiDmCommaIfListMember ( + ACPI_PARSE_OBJECT *Op); + +void +AcpiDmCommaIfFieldMember ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmrestag + */ +void +AcpiDmFindResources ( + ACPI_PARSE_OBJECT *Root); + +void +AcpiDmCheckResourceReference ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + + +/* + * dmcstyle + */ +BOOLEAN +AcpiDmCheckForSymbolicOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_OP_WALK_INFO *Info); + +void +AcpiDmCloseOperator ( + ACPI_PARSE_OBJECT *Op); + + +/* + * dmtables + */ +void +AdDisassemblerHeader ( + char *Filename, + UINT8 TableType); + +#define ACPI_IS_AML_TABLE 0 +#define ACPI_IS_DATA_TABLE 1 + + +/* + * adisasm + */ +ACPI_STATUS +AdAmlDisassemble ( + BOOLEAN OutToFile, + char *Filename, + char *Prefix, + char **OutFilename); + +ACPI_STATUS +AdGetLocalTables ( + void); + +ACPI_STATUS +AdParseTable ( + ACPI_TABLE_HEADER *Table, + ACPI_OWNER_ID *OwnerId, + BOOLEAN LoadTable, + BOOLEAN External); + +ACPI_STATUS +AdDisplayTables ( + char *Filename, + ACPI_TABLE_HEADER *Table); + +ACPI_STATUS +AdDisplayStatistics ( + void); + +#endif /* __ACDISASM_H__ */ diff --git a/third_party/lib/acpica/source/include/acdispat.h b/third_party/lib/acpica/source/include/acdispat.h new file mode 100644 index 000000000..1a6f39e2a --- /dev/null +++ b/third_party/lib/acpica/source/include/acdispat.h @@ -0,0 +1,474 @@ +/****************************************************************************** + * + * Name: acdispat.h - dispatcher (parser to interpreter interface) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACDISPAT_H_ +#define _ACDISPAT_H_ + + +#define NAMEOF_LOCAL_NTE "__L0" +#define NAMEOF_ARG_NTE "__A0" + + +/* + * dsargs - execution of dynamic arguments for static objects + */ +ACPI_STATUS +AcpiDsGetBufferFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsGetBankFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsGetRegionArguments ( + ACPI_OPERAND_OBJECT *RgnDesc); + +ACPI_STATUS +AcpiDsGetBufferArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsGetPackageArguments ( + ACPI_OPERAND_OBJECT *ObjDesc); + + +/* + * dscontrol - support for execution control opcodes + */ +ACPI_STATUS +AcpiDsExecBeginControlOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsExecEndControlOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + + +/* + * dsopcode - support for late operand evaluation + */ +ACPI_STATUS +AcpiDsEvalBufferFieldOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsEvalRegionOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsEvalTableRegionOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsEvalDataObjectOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsEvalBankFieldOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsInitializeRegion ( + ACPI_HANDLE ObjHandle); + + +/* + * dsexec - Parser/Interpreter interface, method execution callbacks + */ +ACPI_STATUS +AcpiDsGetPredicateValue ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ResultObj); + +ACPI_STATUS +AcpiDsExecBeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +ACPI_STATUS +AcpiDsExecEndOp ( + ACPI_WALK_STATE *State); + + +/* + * dsfield - Parser/Interpreter interface for AML fields + */ +ACPI_STATUS +AcpiDsCreateField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateBankField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateIndexField ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *RegionNode, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateBufferField ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsInitFieldObjects ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + + +/* + * dsload - Parser/Interpreter interface + */ +ACPI_STATUS +AcpiDsInitCallbacks ( + ACPI_WALK_STATE *WalkState, + UINT32 PassNumber); + +/* dsload - pass 1 namespace load callbacks */ + +ACPI_STATUS +AcpiDsLoad1BeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +ACPI_STATUS +AcpiDsLoad1EndOp ( + ACPI_WALK_STATE *WalkState); + + +/* dsload - pass 2 namespace load callbacks */ + +ACPI_STATUS +AcpiDsLoad2BeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp); + +ACPI_STATUS +AcpiDsLoad2EndOp ( + ACPI_WALK_STATE *WalkState); + + +/* + * dsmthdat - method data (locals/args) + */ +ACPI_STATUS +AcpiDsStoreObjectToLocal ( + UINT8 Type, + UINT32 Index, + ACPI_OPERAND_OBJECT *SrcDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsMethodDataGetEntry ( + UINT16 Opcode, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT ***Node); + +void +AcpiDsMethodDataDeleteAll ( + ACPI_WALK_STATE *WalkState); + +BOOLEAN +AcpiDsIsMethodValue ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsMethodDataGetValue ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **DestDesc); + +ACPI_STATUS +AcpiDsMethodDataInitArgs ( + ACPI_OPERAND_OBJECT **Params, + UINT32 MaxParamCount, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsMethodDataGetNode ( + UINT8 Type, + UINT32 Index, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **Node); + +void +AcpiDsMethodDataInit ( + ACPI_WALK_STATE *WalkState); + + +/* + * dsmethod - Parser/Interpreter interface - control method parsing + */ +ACPI_STATUS +AcpiDsAutoSerializeMethod ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiDsCallControlMethod ( + ACPI_THREAD_STATE *Thread, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiDsRestartControlMethod ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ReturnDesc); + +void +AcpiDsTerminateControlMethod ( + ACPI_OPERAND_OBJECT *MethodDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsBeginMethodExecution ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState); + +/* + * dsinit + */ +ACPI_STATUS +AcpiDsInitializeObjects ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + + +/* + * dsobject - Parser/Interpreter interface - object initialization and conversion + */ +ACPI_STATUS +AcpiDsBuildInternalBufferObj ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT32 BufferLength, + ACPI_OPERAND_OBJECT **ObjDescPtr); + +ACPI_STATUS +AcpiDsBuildInternalPackageObj ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *op, + UINT32 PackageLength, + ACPI_OPERAND_OBJECT **ObjDesc); + +ACPI_STATUS +AcpiDsInitObjectFromOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + UINT16 Opcode, + ACPI_OPERAND_OBJECT **ObjDesc); + +ACPI_STATUS +AcpiDsCreateNode ( + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *Node, + ACPI_PARSE_OBJECT *Op); + + +/* + * dsutils - Parser/Interpreter interface utility routines + */ +void +AcpiDsClearImplicitReturn ( + ACPI_WALK_STATE *WalkState); + +BOOLEAN +AcpiDsDoImplicitReturn ( + ACPI_OPERAND_OBJECT *ReturnDesc, + ACPI_WALK_STATE *WalkState, + BOOLEAN AddReference); + +BOOLEAN +AcpiDsIsResultUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +void +AcpiDsDeleteResultIfNotUsed ( + ACPI_PARSE_OBJECT *Op, + ACPI_OPERAND_OBJECT *ResultObj, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsCreateOperand ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Arg, + UINT32 ArgsRemaining); + +ACPI_STATUS +AcpiDsCreateOperands ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *FirstArg); + +ACPI_STATUS +AcpiDsResolveOperands ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDsClearOperands ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsEvaluateNamePath ( + ACPI_WALK_STATE *WalkState); + + +/* + * dswscope - Scope Stack manipulation + */ +ACPI_STATUS +AcpiDsScopeStackPush ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_WALK_STATE *WalkState); + + +ACPI_STATUS +AcpiDsScopeStackPop ( + ACPI_WALK_STATE *WalkState); + +void +AcpiDsScopeStackClear ( + ACPI_WALK_STATE *WalkState); + + +/* + * dswstate - parser WALK_STATE management routines + */ +ACPI_STATUS +AcpiDsObjStackPush ( + void *Object, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsObjStackPop ( + UINT32 PopCount, + ACPI_WALK_STATE *WalkState); + +ACPI_WALK_STATE * +AcpiDsCreateWalkState ( + ACPI_OWNER_ID OwnerId, + ACPI_PARSE_OBJECT *Origin, + ACPI_OPERAND_OBJECT *MthDesc, + ACPI_THREAD_STATE *Thread); + +ACPI_STATUS +AcpiDsInitAmlWalk ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE *MethodNode, + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_EVALUATE_INFO *Info, + UINT8 PassNumber); + +void +AcpiDsObjStackPopAndDelete ( + UINT32 PopCount, + ACPI_WALK_STATE *WalkState); + +void +AcpiDsDeleteWalkState ( + ACPI_WALK_STATE *WalkState); + +ACPI_WALK_STATE * +AcpiDsPopWalkState ( + ACPI_THREAD_STATE *Thread); + +void +AcpiDsPushWalkState ( + ACPI_WALK_STATE *WalkState, + ACPI_THREAD_STATE *Thread); + +ACPI_STATUS +AcpiDsResultStackClear ( + ACPI_WALK_STATE *WalkState); + +ACPI_WALK_STATE * +AcpiDsGetCurrentWalkState ( + ACPI_THREAD_STATE *Thread); + +ACPI_STATUS +AcpiDsResultPop ( + ACPI_OPERAND_OBJECT **Object, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiDsResultPush ( + ACPI_OPERAND_OBJECT *Object, + ACPI_WALK_STATE *WalkState); + + +/* + * dsdebug - parser debugging routines + */ +void +AcpiDsDumpMethodStack ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +#endif /* _ACDISPAT_H_ */ diff --git a/third_party/lib/acpica/source/include/acevents.h b/third_party/lib/acpica/source/include/acevents.h new file mode 100644 index 000000000..62bc0edeb --- /dev/null +++ b/third_party/lib/acpica/source/include/acevents.h @@ -0,0 +1,366 @@ +/****************************************************************************** + * + * Name: acevents.h - Event subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACEVENTS_H__ +#define __ACEVENTS_H__ + + +/* + * evevent + */ +ACPI_STATUS +AcpiEvInitializeEvents ( + void); + +ACPI_STATUS +AcpiEvInstallXruptHandlers ( + void); + +UINT32 +AcpiEvFixedEventDetect ( + void); + + +/* + * evmisc + */ +BOOLEAN +AcpiEvIsNotifyObject ( + ACPI_NAMESPACE_NODE *Node); + +UINT32 +AcpiEvGetGpeNumberIndex ( + UINT32 GpeNumber); + +ACPI_STATUS +AcpiEvQueueNotifyRequest ( + ACPI_NAMESPACE_NODE *Node, + UINT32 NotifyValue); + + +/* + * evglock - Global Lock support + */ +ACPI_STATUS +AcpiEvInitGlobalLockHandler ( + void); + +ACPI_HW_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiEvAcquireGlobalLock( + UINT16 Timeout)) + +ACPI_HW_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiEvReleaseGlobalLock( + void)) + +ACPI_STATUS +AcpiEvRemoveGlobalLockHandler ( + void); + + +/* + * evgpe - Low-level GPE support + */ +UINT32 +AcpiEvGpeDetect ( + ACPI_GPE_XRUPT_INFO *GpeXruptList); + +ACPI_STATUS +AcpiEvUpdateGpeEnableMask ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiEvEnableGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiEvAddGpeReference ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiEvRemoveGpeReference ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_GPE_EVENT_INFO * +AcpiEvGetGpeEventInfo ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber); + +ACPI_GPE_EVENT_INFO * +AcpiEvLowGetGpeInfo ( + UINT32 GpeNumber, + ACPI_GPE_BLOCK_INFO *GpeBlock); + +ACPI_STATUS +AcpiEvFinishGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + + +/* + * evgpeblk - Upper-level GPE block support + */ +ACPI_STATUS +AcpiEvCreateGpeBlock ( + ACPI_NAMESPACE_NODE *GpeDevice, + UINT64 Address, + UINT8 SpaceId, + UINT32 RegisterCount, + UINT16 GpeBlockBaseNumber, + UINT32 InterruptNumber, + ACPI_GPE_BLOCK_INFO **ReturnGpeBlock); + +ACPI_STATUS +AcpiEvInitializeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_HW_DEPENDENT_RETURN_OK ( +ACPI_STATUS +AcpiEvDeleteGpeBlock ( + ACPI_GPE_BLOCK_INFO *GpeBlock)) + +UINT32 +AcpiEvGpeDispatch ( + ACPI_NAMESPACE_NODE *GpeDevice, + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 GpeNumber); + + +/* + * evgpeinit - GPE initialization and update + */ +ACPI_STATUS +AcpiEvGpeInitialize ( + void); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiEvUpdateGpes ( + ACPI_OWNER_ID TableOwnerId)) + +ACPI_STATUS +AcpiEvMatchGpeMethod ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +/* + * evgpeutil - GPE utilities + */ +ACPI_STATUS +AcpiEvWalkGpeList ( + ACPI_GPE_CALLBACK GpeWalkCallback, + void *Context); + +ACPI_STATUS +AcpiEvGetGpeDevice ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_STATUS +AcpiEvGetGpeXruptBlock ( + UINT32 InterruptNumber, + ACPI_GPE_XRUPT_INFO **GpeXruptBlock); + +ACPI_STATUS +AcpiEvDeleteGpeXrupt ( + ACPI_GPE_XRUPT_INFO *GpeXrupt); + +ACPI_STATUS +AcpiEvDeleteGpeHandlers ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/* + * evhandler - Address space handling + */ +ACPI_OPERAND_OBJECT * +AcpiEvFindRegionHandler ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_OPERAND_OBJECT *HandlerObj); + +BOOLEAN +AcpiEvHasDefaultHandler ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId); + +ACPI_STATUS +AcpiEvInstallRegionHandlers ( + void); + +ACPI_STATUS +AcpiEvInstallSpaceHandler ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context); + + +/* + * evregion - Operation region support + */ +ACPI_STATUS +AcpiEvInitializeOpRegions ( + void); + +ACPI_STATUS +AcpiEvAddressSpaceDispatch ( + ACPI_OPERAND_OBJECT *RegionObj, + ACPI_OPERAND_OBJECT *FieldObj, + UINT32 Function, + UINT32 RegionOffset, + UINT32 BitWidth, + UINT64 *Value); + +ACPI_STATUS +AcpiEvAttachRegion ( + ACPI_OPERAND_OBJECT *HandlerObj, + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsIsLocked); + +void +AcpiEvDetachRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsIsLocked); + +void +AcpiEvAssociateRegMethod ( + ACPI_OPERAND_OBJECT *RegionObj); + +void +AcpiEvExecuteRegMethods ( + ACPI_NAMESPACE_NODE *Node, + ACPI_ADR_SPACE_TYPE SpaceId, + UINT32 Function); + +ACPI_STATUS +AcpiEvExecuteRegMethod ( + ACPI_OPERAND_OBJECT *RegionObj, + UINT32 Function); + + +/* + * evregini - Region initialization and setup + */ +ACPI_STATUS +AcpiEvSystemMemoryRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvIoSpaceRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvPciConfigRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvCmosRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvPciBarRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvDefaultRegionSetup ( + ACPI_HANDLE Handle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +ACPI_STATUS +AcpiEvInitializeRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsLocked); + + +/* + * evsci - SCI (System Control Interrupt) handling/dispatch + */ +UINT32 ACPI_SYSTEM_XFACE +AcpiEvGpeXruptHandler ( + void *Context); + +UINT32 +AcpiEvSciDispatch ( + void); + +UINT32 +AcpiEvInstallSciHandler ( + void); + +ACPI_STATUS +AcpiEvRemoveAllSciHandlers ( + void); + +ACPI_HW_DEPENDENT_RETURN_VOID ( +void +AcpiEvTerminate ( + void)) + +#endif /* __ACEVENTS_H__ */ diff --git a/third_party/lib/acpica/source/include/acexcep.h b/third_party/lib/acpica/source/include/acexcep.h new file mode 100644 index 000000000..0f9a6aa56 --- /dev/null +++ b/third_party/lib/acpica/source/include/acexcep.h @@ -0,0 +1,354 @@ +/****************************************************************************** + * + * Name: acexcep.h - Exception codes returned by the ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACEXCEP_H__ +#define __ACEXCEP_H__ + + +/* This module contains all possible exception codes for ACPI_STATUS */ + +/* + * Exception code classes + */ +#define AE_CODE_ENVIRONMENTAL 0x0000 /* General ACPICA environment */ +#define AE_CODE_PROGRAMMER 0x1000 /* External ACPICA interface caller */ +#define AE_CODE_ACPI_TABLES 0x2000 /* ACPI tables */ +#define AE_CODE_AML 0x3000 /* From executing AML code */ +#define AE_CODE_CONTROL 0x4000 /* Internal control codes */ + +#define AE_CODE_MAX 0x4000 +#define AE_CODE_MASK 0xF000 + +/* + * Macros to insert the exception code classes + */ +#define EXCEP_ENV(code) ((ACPI_STATUS) (code | AE_CODE_ENVIRONMENTAL)) +#define EXCEP_PGM(code) ((ACPI_STATUS) (code | AE_CODE_PROGRAMMER)) +#define EXCEP_TBL(code) ((ACPI_STATUS) (code | AE_CODE_ACPI_TABLES)) +#define EXCEP_AML(code) ((ACPI_STATUS) (code | AE_CODE_AML)) +#define EXCEP_CTL(code) ((ACPI_STATUS) (code | AE_CODE_CONTROL)) + +/* + * Exception info table. The "Description" field is used only by the + * ACPICA help application (acpihelp). + */ +typedef struct acpi_exception_info +{ + char *Name; + +#ifdef ACPI_HELP_APP + char *Description; +#endif +} ACPI_EXCEPTION_INFO; + +#ifdef ACPI_HELP_APP +#define EXCEP_TXT(Name,Description) {Name, Description} +#else +#define EXCEP_TXT(Name,Description) {Name} +#endif + + +/* + * Success is always zero, failure is non-zero + */ +#define ACPI_SUCCESS(a) (!(a)) +#define ACPI_FAILURE(a) (a) + +#define AE_OK (ACPI_STATUS) 0x0000 + +/* + * Environmental exceptions + */ +#define AE_ERROR EXCEP_ENV (0x0001) +#define AE_NO_ACPI_TABLES EXCEP_ENV (0x0002) +#define AE_NO_NAMESPACE EXCEP_ENV (0x0003) +#define AE_NO_MEMORY EXCEP_ENV (0x0004) +#define AE_NOT_FOUND EXCEP_ENV (0x0005) +#define AE_NOT_EXIST EXCEP_ENV (0x0006) +#define AE_ALREADY_EXISTS EXCEP_ENV (0x0007) +#define AE_TYPE EXCEP_ENV (0x0008) +#define AE_NULL_OBJECT EXCEP_ENV (0x0009) +#define AE_NULL_ENTRY EXCEP_ENV (0x000A) +#define AE_BUFFER_OVERFLOW EXCEP_ENV (0x000B) +#define AE_STACK_OVERFLOW EXCEP_ENV (0x000C) +#define AE_STACK_UNDERFLOW EXCEP_ENV (0x000D) +#define AE_NOT_IMPLEMENTED EXCEP_ENV (0x000E) +#define AE_SUPPORT EXCEP_ENV (0x000F) +#define AE_LIMIT EXCEP_ENV (0x0010) +#define AE_TIME EXCEP_ENV (0x0011) +#define AE_ACQUIRE_DEADLOCK EXCEP_ENV (0x0012) +#define AE_RELEASE_DEADLOCK EXCEP_ENV (0x0013) +#define AE_NOT_ACQUIRED EXCEP_ENV (0x0014) +#define AE_ALREADY_ACQUIRED EXCEP_ENV (0x0015) +#define AE_NO_HARDWARE_RESPONSE EXCEP_ENV (0x0016) +#define AE_NO_GLOBAL_LOCK EXCEP_ENV (0x0017) +#define AE_ABORT_METHOD EXCEP_ENV (0x0018) +#define AE_SAME_HANDLER EXCEP_ENV (0x0019) +#define AE_NO_HANDLER EXCEP_ENV (0x001A) +#define AE_OWNER_ID_LIMIT EXCEP_ENV (0x001B) +#define AE_NOT_CONFIGURED EXCEP_ENV (0x001C) +#define AE_ACCESS EXCEP_ENV (0x001D) +#define AE_IO_ERROR EXCEP_ENV (0x001E) + +#define AE_CODE_ENV_MAX 0x001E + + +/* + * Programmer exceptions + */ +#define AE_BAD_PARAMETER EXCEP_PGM (0x0001) +#define AE_BAD_CHARACTER EXCEP_PGM (0x0002) +#define AE_BAD_PATHNAME EXCEP_PGM (0x0003) +#define AE_BAD_DATA EXCEP_PGM (0x0004) +#define AE_BAD_HEX_CONSTANT EXCEP_PGM (0x0005) +#define AE_BAD_OCTAL_CONSTANT EXCEP_PGM (0x0006) +#define AE_BAD_DECIMAL_CONSTANT EXCEP_PGM (0x0007) +#define AE_MISSING_ARGUMENTS EXCEP_PGM (0x0008) +#define AE_BAD_ADDRESS EXCEP_PGM (0x0009) + +#define AE_CODE_PGM_MAX 0x0009 + + +/* + * Acpi table exceptions + */ +#define AE_BAD_SIGNATURE EXCEP_TBL (0x0001) +#define AE_BAD_HEADER EXCEP_TBL (0x0002) +#define AE_BAD_CHECKSUM EXCEP_TBL (0x0003) +#define AE_BAD_VALUE EXCEP_TBL (0x0004) +#define AE_INVALID_TABLE_LENGTH EXCEP_TBL (0x0005) + +#define AE_CODE_TBL_MAX 0x0005 + + +/* + * AML exceptions. These are caused by problems with + * the actual AML byte stream + */ +#define AE_AML_BAD_OPCODE EXCEP_AML (0x0001) +#define AE_AML_NO_OPERAND EXCEP_AML (0x0002) +#define AE_AML_OPERAND_TYPE EXCEP_AML (0x0003) +#define AE_AML_OPERAND_VALUE EXCEP_AML (0x0004) +#define AE_AML_UNINITIALIZED_LOCAL EXCEP_AML (0x0005) +#define AE_AML_UNINITIALIZED_ARG EXCEP_AML (0x0006) +#define AE_AML_UNINITIALIZED_ELEMENT EXCEP_AML (0x0007) +#define AE_AML_NUMERIC_OVERFLOW EXCEP_AML (0x0008) +#define AE_AML_REGION_LIMIT EXCEP_AML (0x0009) +#define AE_AML_BUFFER_LIMIT EXCEP_AML (0x000A) +#define AE_AML_PACKAGE_LIMIT EXCEP_AML (0x000B) +#define AE_AML_DIVIDE_BY_ZERO EXCEP_AML (0x000C) +#define AE_AML_BAD_NAME EXCEP_AML (0x000D) +#define AE_AML_NAME_NOT_FOUND EXCEP_AML (0x000E) +#define AE_AML_INTERNAL EXCEP_AML (0x000F) +#define AE_AML_INVALID_SPACE_ID EXCEP_AML (0x0010) +#define AE_AML_STRING_LIMIT EXCEP_AML (0x0011) +#define AE_AML_NO_RETURN_VALUE EXCEP_AML (0x0012) +#define AE_AML_METHOD_LIMIT EXCEP_AML (0x0013) +#define AE_AML_NOT_OWNER EXCEP_AML (0x0014) +#define AE_AML_MUTEX_ORDER EXCEP_AML (0x0015) +#define AE_AML_MUTEX_NOT_ACQUIRED EXCEP_AML (0x0016) +#define AE_AML_INVALID_RESOURCE_TYPE EXCEP_AML (0x0017) +#define AE_AML_INVALID_INDEX EXCEP_AML (0x0018) +#define AE_AML_REGISTER_LIMIT EXCEP_AML (0x0019) +#define AE_AML_NO_WHILE EXCEP_AML (0x001A) +#define AE_AML_ALIGNMENT EXCEP_AML (0x001B) +#define AE_AML_NO_RESOURCE_END_TAG EXCEP_AML (0x001C) +#define AE_AML_BAD_RESOURCE_VALUE EXCEP_AML (0x001D) +#define AE_AML_CIRCULAR_REFERENCE EXCEP_AML (0x001E) +#define AE_AML_BAD_RESOURCE_LENGTH EXCEP_AML (0x001F) +#define AE_AML_ILLEGAL_ADDRESS EXCEP_AML (0x0020) +#define AE_AML_INFINITE_LOOP EXCEP_AML (0x0021) +#define AE_AML_UNINITIALIZED_NODE EXCEP_AML (0x0022) +#define AE_AML_TARGET_TYPE EXCEP_AML (0x0023) + +#define AE_CODE_AML_MAX 0x0023 + + +/* + * Internal exceptions used for control + */ +#define AE_CTRL_RETURN_VALUE EXCEP_CTL (0x0001) +#define AE_CTRL_PENDING EXCEP_CTL (0x0002) +#define AE_CTRL_TERMINATE EXCEP_CTL (0x0003) +#define AE_CTRL_TRUE EXCEP_CTL (0x0004) +#define AE_CTRL_FALSE EXCEP_CTL (0x0005) +#define AE_CTRL_DEPTH EXCEP_CTL (0x0006) +#define AE_CTRL_END EXCEP_CTL (0x0007) +#define AE_CTRL_TRANSFER EXCEP_CTL (0x0008) +#define AE_CTRL_BREAK EXCEP_CTL (0x0009) +#define AE_CTRL_CONTINUE EXCEP_CTL (0x000A) +#define AE_CTRL_SKIP EXCEP_CTL (0x000B) +#define AE_CTRL_PARSE_CONTINUE EXCEP_CTL (0x000C) +#define AE_CTRL_PARSE_PENDING EXCEP_CTL (0x000D) + +#define AE_CODE_CTRL_MAX 0x000D + + +/* Exception strings for AcpiFormatException */ + +#ifdef ACPI_DEFINE_EXCEPTION_TABLE + +/* + * String versions of the exception codes above + * These strings must match the corresponding defines exactly + */ +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Env[] = +{ + EXCEP_TXT ("AE_OK", "No error"), + EXCEP_TXT ("AE_ERROR", "Unspecified error"), + EXCEP_TXT ("AE_NO_ACPI_TABLES", "ACPI tables could not be found"), + EXCEP_TXT ("AE_NO_NAMESPACE", "A namespace has not been loaded"), + EXCEP_TXT ("AE_NO_MEMORY", "Insufficient dynamic memory"), + EXCEP_TXT ("AE_NOT_FOUND", "A requested entity is not found"), + EXCEP_TXT ("AE_NOT_EXIST", "A required entity does not exist"), + EXCEP_TXT ("AE_ALREADY_EXISTS", "An entity already exists"), + EXCEP_TXT ("AE_TYPE", "The object type is incorrect"), + EXCEP_TXT ("AE_NULL_OBJECT", "A required object was missing"), + EXCEP_TXT ("AE_NULL_ENTRY", "The requested object does not exist"), + EXCEP_TXT ("AE_BUFFER_OVERFLOW", "The buffer provided is too small"), + EXCEP_TXT ("AE_STACK_OVERFLOW", "An internal stack overflowed"), + EXCEP_TXT ("AE_STACK_UNDERFLOW", "An internal stack underflowed"), + EXCEP_TXT ("AE_NOT_IMPLEMENTED", "The feature is not implemented"), + EXCEP_TXT ("AE_SUPPORT", "The feature is not supported"), + EXCEP_TXT ("AE_LIMIT", "A predefined limit was exceeded"), + EXCEP_TXT ("AE_TIME", "A time limit or timeout expired"), + EXCEP_TXT ("AE_ACQUIRE_DEADLOCK", "Internal error, attempt was made to acquire a mutex in improper order"), + EXCEP_TXT ("AE_RELEASE_DEADLOCK", "Internal error, attempt was made to release a mutex in improper order"), + EXCEP_TXT ("AE_NOT_ACQUIRED", "An attempt to release a mutex or Global Lock without a previous acquire"), + EXCEP_TXT ("AE_ALREADY_ACQUIRED", "Internal error, attempt was made to acquire a mutex twice"), + EXCEP_TXT ("AE_NO_HARDWARE_RESPONSE", "Hardware did not respond after an I/O operation"), + EXCEP_TXT ("AE_NO_GLOBAL_LOCK", "There is no FACS Global Lock"), + EXCEP_TXT ("AE_ABORT_METHOD", "A control method was aborted"), + EXCEP_TXT ("AE_SAME_HANDLER", "Attempt was made to install the same handler that is already installed"), + EXCEP_TXT ("AE_NO_HANDLER", "A handler for the operation is not installed"), + EXCEP_TXT ("AE_OWNER_ID_LIMIT", "There are no more Owner IDs available for ACPI tables or control methods"), + EXCEP_TXT ("AE_NOT_CONFIGURED", "The interface is not part of the current subsystem configuration"), + EXCEP_TXT ("AE_ACCESS", "Permission denied for the requested operation"), + EXCEP_TXT ("AE_IO_ERROR", "An I/O error occurred") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Pgm[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_BAD_PARAMETER", "A parameter is out of range or invalid"), + EXCEP_TXT ("AE_BAD_CHARACTER", "An invalid character was found in a name"), + EXCEP_TXT ("AE_BAD_PATHNAME", "An invalid character was found in a pathname"), + EXCEP_TXT ("AE_BAD_DATA", "A package or buffer contained incorrect data"), + EXCEP_TXT ("AE_BAD_HEX_CONSTANT", "Invalid character in a Hex constant"), + EXCEP_TXT ("AE_BAD_OCTAL_CONSTANT", "Invalid character in an Octal constant"), + EXCEP_TXT ("AE_BAD_DECIMAL_CONSTANT", "Invalid character in a Decimal constant"), + EXCEP_TXT ("AE_MISSING_ARGUMENTS", "Too few arguments were passed to a control method"), + EXCEP_TXT ("AE_BAD_ADDRESS", "An illegal null I/O address") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Tbl[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_BAD_SIGNATURE", "An ACPI table has an invalid signature"), + EXCEP_TXT ("AE_BAD_HEADER", "Invalid field in an ACPI table header"), + EXCEP_TXT ("AE_BAD_CHECKSUM", "An ACPI table checksum is not correct"), + EXCEP_TXT ("AE_BAD_VALUE", "An invalid value was found in a table"), + EXCEP_TXT ("AE_INVALID_TABLE_LENGTH", "The FADT or FACS has improper length") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Aml[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_AML_BAD_OPCODE", "Invalid AML opcode encountered"), + EXCEP_TXT ("AE_AML_NO_OPERAND", "A required operand is missing"), + EXCEP_TXT ("AE_AML_OPERAND_TYPE", "An operand of an incorrect type was encountered"), + EXCEP_TXT ("AE_AML_OPERAND_VALUE", "The operand had an inappropriate or invalid value"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_LOCAL", "Method tried to use an uninitialized local variable"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_ARG", "Method tried to use an uninitialized argument"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_ELEMENT", "Method tried to use an empty package element"), + EXCEP_TXT ("AE_AML_NUMERIC_OVERFLOW", "Overflow during BCD conversion or other"), + EXCEP_TXT ("AE_AML_REGION_LIMIT", "Tried to access beyond the end of an Operation Region"), + EXCEP_TXT ("AE_AML_BUFFER_LIMIT", "Tried to access beyond the end of a buffer"), + EXCEP_TXT ("AE_AML_PACKAGE_LIMIT", "Tried to access beyond the end of a package"), + EXCEP_TXT ("AE_AML_DIVIDE_BY_ZERO", "During execution of AML Divide operator"), + EXCEP_TXT ("AE_AML_BAD_NAME", "An ACPI name contains invalid character(s)"), + EXCEP_TXT ("AE_AML_NAME_NOT_FOUND", "Could not resolve a named reference"), + EXCEP_TXT ("AE_AML_INTERNAL", "An internal error within the interprete"), + EXCEP_TXT ("AE_AML_INVALID_SPACE_ID", "An Operation Region SpaceID is invalid"), + EXCEP_TXT ("AE_AML_STRING_LIMIT", "String is longer than 200 characters"), + EXCEP_TXT ("AE_AML_NO_RETURN_VALUE", "A method did not return a required value"), + EXCEP_TXT ("AE_AML_METHOD_LIMIT", "A control method reached the maximum reentrancy limit of 255"), + EXCEP_TXT ("AE_AML_NOT_OWNER", "A thread tried to release a mutex that it does not own"), + EXCEP_TXT ("AE_AML_MUTEX_ORDER", "Mutex SyncLevel release mismatch"), + EXCEP_TXT ("AE_AML_MUTEX_NOT_ACQUIRED", "Attempt to release a mutex that was not previously acquired"), + EXCEP_TXT ("AE_AML_INVALID_RESOURCE_TYPE", "Invalid resource type in resource list"), + EXCEP_TXT ("AE_AML_INVALID_INDEX", "Invalid Argx or Localx (x too large)"), + EXCEP_TXT ("AE_AML_REGISTER_LIMIT", "Bank value or Index value beyond range of register"), + EXCEP_TXT ("AE_AML_NO_WHILE", "Break or Continue without a While"), + EXCEP_TXT ("AE_AML_ALIGNMENT", "Non-aligned memory transfer on platform that does not support this"), + EXCEP_TXT ("AE_AML_NO_RESOURCE_END_TAG", "No End Tag in a resource list"), + EXCEP_TXT ("AE_AML_BAD_RESOURCE_VALUE", "Invalid value of a resource element"), + EXCEP_TXT ("AE_AML_CIRCULAR_REFERENCE", "Two references refer to each other"), + EXCEP_TXT ("AE_AML_BAD_RESOURCE_LENGTH", "The length of a Resource Descriptor in the AML is incorrect"), + EXCEP_TXT ("AE_AML_ILLEGAL_ADDRESS", "A memory, I/O, or PCI configuration address is invalid"), + EXCEP_TXT ("AE_AML_INFINITE_LOOP", "An apparent infinite AML While loop, method was aborted"), + EXCEP_TXT ("AE_AML_UNINITIALIZED_NODE", "A namespace node is uninitialized or unresolved"), + EXCEP_TXT ("AE_AML_TARGET_TYPE", "A target operand of an incorrect type was encountered") +}; + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Ctrl[] = +{ + EXCEP_TXT (NULL, NULL), + EXCEP_TXT ("AE_CTRL_RETURN_VALUE", "A Method returned a value"), + EXCEP_TXT ("AE_CTRL_PENDING", "Method is calling another method"), + EXCEP_TXT ("AE_CTRL_TERMINATE", "Terminate the executing method"), + EXCEP_TXT ("AE_CTRL_TRUE", "An If or While predicate result"), + EXCEP_TXT ("AE_CTRL_FALSE", "An If or While predicate result"), + EXCEP_TXT ("AE_CTRL_DEPTH", "Maximum search depth has been reached"), + EXCEP_TXT ("AE_CTRL_END", "An If or While predicate is false"), + EXCEP_TXT ("AE_CTRL_TRANSFER", "Transfer control to called method"), + EXCEP_TXT ("AE_CTRL_BREAK", "A Break has been executed"), + EXCEP_TXT ("AE_CTRL_CONTINUE", "A Continue has been executed"), + EXCEP_TXT ("AE_CTRL_SKIP", "Not currently used"), + EXCEP_TXT ("AE_CTRL_PARSE_CONTINUE", "Used to skip over bad opcodes"), + EXCEP_TXT ("AE_CTRL_PARSE_PENDING", "Used to implement AML While loops") +}; + +#endif /* EXCEPTION_TABLE */ + +#endif /* __ACEXCEP_H__ */ diff --git a/third_party/lib/acpica/source/include/acglobal.h b/third_party/lib/acpica/source/include/acglobal.h new file mode 100644 index 000000000..2fe04d4a7 --- /dev/null +++ b/third_party/lib/acpica/source/include/acglobal.h @@ -0,0 +1,405 @@ +/****************************************************************************** + * + * Name: acglobal.h - Declarations for global variables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACGLOBAL_H__ +#define __ACGLOBAL_H__ + + +/***************************************************************************** + * + * Globals related to the ACPI tables + * + ****************************************************************************/ + +/* Master list of all ACPI tables that were found in the RSDT/XSDT */ + +ACPI_GLOBAL (ACPI_TABLE_LIST, AcpiGbl_RootTableList); + +/* DSDT information. Used to check for DSDT corruption */ + +ACPI_GLOBAL (ACPI_TABLE_HEADER *, AcpiGbl_DSDT); +ACPI_GLOBAL (ACPI_TABLE_HEADER, AcpiGbl_OriginalDsdtHeader); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_DsdtIndex, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_FacsIndex, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_XFacsIndex, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_FadtIndex, ACPI_INVALID_TABLE_INDEX); + +#if (!ACPI_REDUCED_HARDWARE) +ACPI_GLOBAL (ACPI_TABLE_FACS *, AcpiGbl_FACS); + +#endif /* !ACPI_REDUCED_HARDWARE */ + +/* These addresses are calculated from the FADT Event Block addresses */ + +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1aStatus); +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1aEnable); + +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1bStatus); +ACPI_GLOBAL (ACPI_GENERIC_ADDRESS, AcpiGbl_XPm1bEnable); + +/* + * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is + * determined by the revision of the DSDT: If the DSDT revision is less than + * 2, use only the lower 32 bits of the internal 64-bit Integer. + */ +ACPI_GLOBAL (UINT8, AcpiGbl_IntegerBitWidth); +ACPI_GLOBAL (UINT8, AcpiGbl_IntegerByteWidth); +ACPI_GLOBAL (UINT8, AcpiGbl_IntegerNybbleWidth); + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_GroupModuleLevelCode, FALSE); + + +/***************************************************************************** + * + * Mutual exclusion within ACPICA subsystem + * + ****************************************************************************/ + +/* + * Predefined mutex objects. This array contains the + * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. + * (The table maps local handles to the real OS handles) + */ +ACPI_GLOBAL (ACPI_MUTEX_INFO, AcpiGbl_MutexInfo[ACPI_NUM_MUTEX]); + +/* + * Global lock mutex is an actual AML mutex object + * Global lock semaphore works in conjunction with the actual global lock + * Global lock spinlock is used for "pending" handshake + */ +ACPI_GLOBAL (ACPI_OPERAND_OBJECT *, AcpiGbl_GlobalLockMutex); +ACPI_GLOBAL (ACPI_SEMAPHORE, AcpiGbl_GlobalLockSemaphore); +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_GlobalLockPendingLock); +ACPI_GLOBAL (UINT16, AcpiGbl_GlobalLockHandle); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_GlobalLockAcquired); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_GlobalLockPresent); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_GlobalLockPending); + +/* + * Spinlocks are used for interfaces that can be possibly called at + * interrupt level + */ +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_GpeLock); /* For GPE data structs and registers */ +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_HardwareLock); /* For ACPI H/W except GPE registers */ +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_ReferenceCountLock); + +/* Mutex for _OSI support */ + +ACPI_GLOBAL (ACPI_MUTEX, AcpiGbl_OsiMutex); + +/* Reader/Writer lock is used for namespace walk and dynamic table unload */ + +ACPI_GLOBAL (ACPI_RW_LOCK, AcpiGbl_NamespaceRwLock); + + +/***************************************************************************** + * + * Miscellaneous globals + * + ****************************************************************************/ + +/* Object caches */ + +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_NamespaceCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_StateCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_PsNodeCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_PsNodeExtCache); +ACPI_GLOBAL (ACPI_CACHE_T *, AcpiGbl_OperandCache); + +/* System */ + +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_StartupFlags, 0); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_Shutdown, TRUE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_EarlyInitialization, TRUE); + +/* Global handlers */ + +ACPI_GLOBAL (ACPI_GLOBAL_NOTIFY_HANDLER,AcpiGbl_GlobalNotify[2]); +ACPI_GLOBAL (ACPI_EXCEPTION_HANDLER, AcpiGbl_ExceptionHandler); +ACPI_GLOBAL (ACPI_INIT_HANDLER, AcpiGbl_InitHandler); +ACPI_GLOBAL (ACPI_TABLE_HANDLER, AcpiGbl_TableHandler); +ACPI_GLOBAL (void *, AcpiGbl_TableHandlerContext); +ACPI_GLOBAL (ACPI_INTERFACE_HANDLER, AcpiGbl_InterfaceHandler); +ACPI_GLOBAL (ACPI_SCI_HANDLER_INFO *, AcpiGbl_SciHandlerList); + +/* Owner ID support */ + +ACPI_GLOBAL (UINT32, AcpiGbl_OwnerIdMask[ACPI_NUM_OWNERID_MASKS]); +ACPI_GLOBAL (UINT8, AcpiGbl_LastOwnerIdIndex); +ACPI_GLOBAL (UINT8, AcpiGbl_NextOwnerIdOffset); + +/* Initialization sequencing */ + +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_RegMethodsEnabled, FALSE); + +/* Misc */ + +ACPI_GLOBAL (UINT32, AcpiGbl_OriginalMode); +ACPI_GLOBAL (UINT32, AcpiGbl_NsLookupCount); +ACPI_GLOBAL (UINT32, AcpiGbl_PsFindCount); +ACPI_GLOBAL (UINT16, AcpiGbl_Pm1EnableRegisterSave); +ACPI_GLOBAL (UINT8, AcpiGbl_DebuggerConfiguration); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_StepToNextCall); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_AcpiHardwarePresent); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_EventsInitialized); +ACPI_GLOBAL (ACPI_INTERFACE_INFO *, AcpiGbl_SupportedInterfaces); +ACPI_GLOBAL (ACPI_ADDRESS_RANGE *, AcpiGbl_AddressRangeList[ACPI_ADDRESS_RANGE_MAX]); + +/* Other miscellaneous, declared and initialized in utglobal */ + +extern const char *AcpiGbl_SleepStateNames[ACPI_S_STATE_COUNT]; +extern const char *AcpiGbl_LowestDstateNames[ACPI_NUM_SxW_METHODS]; +extern const char *AcpiGbl_HighestDstateNames[ACPI_NUM_SxD_METHODS]; +extern const char *AcpiGbl_RegionTypes[ACPI_NUM_PREDEFINED_REGIONS]; +extern const ACPI_OPCODE_INFO AcpiGbl_AmlOpInfo[AML_NUM_OPCODES]; + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +/* Lists for tracking memory allocations (debug only) */ + +ACPI_GLOBAL (ACPI_MEMORY_LIST *, AcpiGbl_GlobalList); +ACPI_GLOBAL (ACPI_MEMORY_LIST *, AcpiGbl_NsNodeList); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DisplayFinalMemStats); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DisableMemTracking); +#endif + + +/***************************************************************************** + * + * Namespace globals + * + ****************************************************************************/ + +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#define NUM_PREDEFINED_NAMES 10 +#else +#define NUM_PREDEFINED_NAMES 9 +#endif + +ACPI_GLOBAL (ACPI_NAMESPACE_NODE, AcpiGbl_RootNodeStruct); +ACPI_GLOBAL (ACPI_NAMESPACE_NODE *, AcpiGbl_RootNode); +ACPI_GLOBAL (ACPI_NAMESPACE_NODE *, AcpiGbl_FadtGpeDevice); +ACPI_GLOBAL (ACPI_OPERAND_OBJECT *, AcpiGbl_ModuleCodeList); + + +extern const UINT8 AcpiGbl_NsProperties [ACPI_NUM_NS_TYPES]; +extern const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames [NUM_PREDEFINED_NAMES]; + +#ifdef ACPI_DEBUG_OUTPUT +ACPI_GLOBAL (UINT32, AcpiGbl_CurrentNodeCount); +ACPI_GLOBAL (UINT32, AcpiGbl_CurrentNodeSize); +ACPI_GLOBAL (UINT32, AcpiGbl_MaxConcurrentNodeCount); +ACPI_GLOBAL (ACPI_SIZE *, AcpiGbl_EntryStackPointer); +ACPI_GLOBAL (ACPI_SIZE *, AcpiGbl_LowestStackPointer); +ACPI_GLOBAL (UINT32, AcpiGbl_DeepestNesting); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_NestingLevel, 0); +#endif + + +/***************************************************************************** + * + * Interpreter globals + * + ****************************************************************************/ + +ACPI_GLOBAL (ACPI_THREAD_STATE *, AcpiGbl_CurrentWalkList); + +/* Maximum number of While() loop iterations before forced abort */ + +ACPI_GLOBAL (UINT16, AcpiGbl_MaxLoopIterations); + +/* Control method single step flag */ + +ACPI_GLOBAL (UINT8, AcpiGbl_CmSingleStep); + + +/***************************************************************************** + * + * Hardware globals + * + ****************************************************************************/ + +extern ACPI_BIT_REGISTER_INFO AcpiGbl_BitRegisterInfo[ACPI_NUM_BITREG]; + +ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeA); +ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeB); + + +/***************************************************************************** + * + * Event and GPE globals + * + ****************************************************************************/ + +#if (!ACPI_REDUCED_HARDWARE) + +ACPI_GLOBAL (UINT8, AcpiGbl_AllGpesInitialized); +ACPI_GLOBAL (ACPI_GPE_XRUPT_INFO *, AcpiGbl_GpeXruptListHead); +ACPI_GLOBAL (ACPI_GPE_BLOCK_INFO *, AcpiGbl_GpeFadtBlocks[ACPI_MAX_GPE_BLOCKS]); +ACPI_GLOBAL (ACPI_GBL_EVENT_HANDLER, AcpiGbl_GlobalEventHandler); +ACPI_GLOBAL (void *, AcpiGbl_GlobalEventHandlerContext); +ACPI_GLOBAL (ACPI_FIXED_EVENT_HANDLER, AcpiGbl_FixedEventHandlers[ACPI_NUM_FIXED_EVENTS]); + +extern ACPI_FIXED_EVENT_INFO AcpiGbl_FixedEventInfo[ACPI_NUM_FIXED_EVENTS]; + +#endif /* !ACPI_REDUCED_HARDWARE */ + +/***************************************************************************** + * + * Debug support + * + ****************************************************************************/ + +/* Event counters */ + +ACPI_GLOBAL (UINT32, AcpiMethodCount); +ACPI_GLOBAL (UINT32, AcpiGpeCount); +ACPI_GLOBAL (UINT32, AcpiSciCount); +ACPI_GLOBAL (UINT32, AcpiFixedEventCount[ACPI_NUM_FIXED_EVENTS]); + +/* Support for dynamic control method tracing mechanism */ + +ACPI_GLOBAL (UINT32, AcpiGbl_OriginalDbgLevel); +ACPI_GLOBAL (UINT32, AcpiGbl_OriginalDbgLayer); + + +/***************************************************************************** + * + * Debugger and Disassembler globals + * + ****************************************************************************/ + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DbOutputFlags, ACPI_DB_CONSOLE_OUTPUT); + +#ifdef ACPI_DISASSEMBLER + +/* Do not disassemble buffers to resource descriptors */ + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_NoResourceDisassembly, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_IgnoreNoopOperator, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_CstyleDisassembly, TRUE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_ForceAmlDisassembly, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DmOpt_Verbose, TRUE); + +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DmOpt_Disasm); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DmOpt_Listing); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_NumExternalMethods); +ACPI_GLOBAL (UINT32, AcpiGbl_ResolvedExternalMethods); +ACPI_GLOBAL (ACPI_EXTERNAL_LIST *, AcpiGbl_ExternalList); +ACPI_GLOBAL (ACPI_EXTERNAL_FILE *, AcpiGbl_ExternalFileList); +#endif + +#ifdef ACPI_DEBUGGER + +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_AbortMethod, FALSE); +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_MethodExecuting, FALSE); +ACPI_INIT_GLOBAL (ACPI_THREAD_ID, AcpiGbl_DbThreadId, ACPI_INVALID_THREAD_ID); + +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_NoIniMethods); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_NoRegionSupport); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOutputToFile); +ACPI_GLOBAL (char *, AcpiGbl_DbBuffer); +ACPI_GLOBAL (char *, AcpiGbl_DbFilename); +ACPI_GLOBAL (UINT32, AcpiGbl_DbDebugLevel); +ACPI_GLOBAL (UINT32, AcpiGbl_DbConsoleDebugLevel); +ACPI_GLOBAL (ACPI_NAMESPACE_NODE *, AcpiGbl_DbScopeNode); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbTerminateLoop); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbThreadsTerminated); + +ACPI_GLOBAL (char *, AcpiGbl_DbArgs[ACPI_DEBUGGER_MAX_ARGS]); +ACPI_GLOBAL (ACPI_OBJECT_TYPE, AcpiGbl_DbArgTypes[ACPI_DEBUGGER_MAX_ARGS]); + +/* These buffers should all be the same size */ + +ACPI_GLOBAL (char, AcpiGbl_DbLineBuf[ACPI_DB_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, AcpiGbl_DbParsedBuf[ACPI_DB_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, AcpiGbl_DbScopeBuf[ACPI_DB_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, AcpiGbl_DbDebugFilename[ACPI_DB_LINE_BUFFER_SIZE]); + +/* + * Statistic globals + */ +ACPI_GLOBAL (UINT16, AcpiGbl_ObjTypeCount[ACPI_TOTAL_TYPES]); +ACPI_GLOBAL (UINT16, AcpiGbl_NodeTypeCount[ACPI_TOTAL_TYPES]); +ACPI_GLOBAL (UINT16, AcpiGbl_ObjTypeCountMisc); +ACPI_GLOBAL (UINT16, AcpiGbl_NodeTypeCountMisc); +ACPI_GLOBAL (UINT32, AcpiGbl_NumNodes); +ACPI_GLOBAL (UINT32, AcpiGbl_NumObjects); + +ACPI_GLOBAL (ACPI_MUTEX, AcpiGbl_DbCommandReady); +ACPI_GLOBAL (ACPI_MUTEX, AcpiGbl_DbCommandComplete); + +#endif /* ACPI_DEBUGGER */ + + +/***************************************************************************** + * + * Application globals + * + ****************************************************************************/ + +#ifdef ACPI_APPLICATION + +ACPI_INIT_GLOBAL (ACPI_FILE, AcpiGbl_DebugFile, NULL); +ACPI_INIT_GLOBAL (ACPI_FILE, AcpiGbl_OutputFile, NULL); + +/* Print buffer */ + +ACPI_GLOBAL (ACPI_SPINLOCK, AcpiGbl_PrintLock); /* For print buffer */ +ACPI_GLOBAL (char, AcpiGbl_PrintBuffer[1024]); + +#endif /* ACPI_APPLICATION */ + + +/***************************************************************************** + * + * Info/help support + * + ****************************************************************************/ + +extern const AH_PREDEFINED_NAME AslPredefinedInfo[]; +extern const AH_DEVICE_ID AslDeviceIds[]; + + +#endif /* __ACGLOBAL_H__ */ diff --git a/third_party/lib/acpica/source/include/achware.h b/third_party/lib/acpica/source/include/achware.h new file mode 100644 index 000000000..b7a5f20fe --- /dev/null +++ b/third_party/lib/acpica/source/include/achware.h @@ -0,0 +1,227 @@ +/****************************************************************************** + * + * Name: achware.h -- hardware specific interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACHWARE_H__ +#define __ACHWARE_H__ + + +/* Values for the _SST predefined method */ + +#define ACPI_SST_INDICATOR_OFF 0 +#define ACPI_SST_WORKING 1 +#define ACPI_SST_WAKING 2 +#define ACPI_SST_SLEEPING 3 +#define ACPI_SST_SLEEP_CONTEXT 4 + + +/* + * hwacpi - high level functions + */ +ACPI_STATUS +AcpiHwSetMode ( + UINT32 Mode); + +UINT32 +AcpiHwGetMode ( + void); + + +/* + * hwregs - ACPI Register I/O + */ +ACPI_STATUS +AcpiHwValidateRegister ( + ACPI_GENERIC_ADDRESS *Reg, + UINT8 MaxBitWidth, + UINT64 *Address); + +ACPI_STATUS +AcpiHwRead ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *Reg); + +ACPI_STATUS +AcpiHwWrite ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *Reg); + +ACPI_BIT_REGISTER_INFO * +AcpiHwGetBitRegisterInfo ( + UINT32 RegisterId); + +ACPI_STATUS +AcpiHwWritePm1Control ( + UINT32 Pm1aControl, + UINT32 Pm1bControl); + +ACPI_STATUS +AcpiHwRegisterRead ( + UINT32 RegisterId, + UINT32 *ReturnValue); + +ACPI_STATUS +AcpiHwRegisterWrite ( + UINT32 RegisterId, + UINT32 Value); + +ACPI_STATUS +AcpiHwClearAcpiStatus ( + void); + + +/* + * hwsleep - sleep/wake support (Legacy sleep registers) + */ +ACPI_STATUS +AcpiHwLegacySleep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwLegacyWakePrep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwLegacyWake ( + UINT8 SleepState); + + +/* + * hwesleep - sleep/wake support (Extended FADT-V5 sleep registers) + */ +void +AcpiHwExecuteSleepMethod ( + char *MethodName, + UINT32 IntegerArgument); + +ACPI_STATUS +AcpiHwExtendedSleep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwExtendedWakePrep ( + UINT8 SleepState); + +ACPI_STATUS +AcpiHwExtendedWake ( + UINT8 SleepState); + + +/* + * hwvalid - Port I/O with validation + */ +ACPI_STATUS +AcpiHwReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width); + +ACPI_STATUS +AcpiHwWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width); + + +/* + * hwgpe - GPE support + */ +UINT32 +AcpiHwGetGpeRegisterBit ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiHwLowSetGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 Action); + +ACPI_STATUS +AcpiHwDisableGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_STATUS +AcpiHwClearGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo); + +ACPI_STATUS +AcpiHwClearGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + +ACPI_STATUS +AcpiHwGetGpeStatus ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + ACPI_EVENT_STATUS *EventStatus); + +ACPI_STATUS +AcpiHwDisableAllGpes ( + void); + +ACPI_STATUS +AcpiHwEnableAllRuntimeGpes ( + void); + +ACPI_STATUS +AcpiHwEnableAllWakeupGpes ( + void); + +ACPI_STATUS +AcpiHwEnableRuntimeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/* + * hwpci - PCI configuration support + */ +ACPI_STATUS +AcpiHwDerivePciId ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion); + + +#endif /* __ACHWARE_H__ */ diff --git a/third_party/lib/acpica/source/include/acinterp.h b/third_party/lib/acpica/source/include/acinterp.h new file mode 100644 index 000000000..454e8bafb --- /dev/null +++ b/third_party/lib/acpica/source/include/acinterp.h @@ -0,0 +1,756 @@ +/****************************************************************************** + * + * Name: acinterp.h - Interpreter subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACINTERP_H__ +#define __ACINTERP_H__ + + +#define ACPI_WALK_OPERANDS (&(WalkState->Operands [WalkState->NumOperands -1])) + +/* Macros for tables used for debug output */ + +#define ACPI_EXD_OFFSET(f) (UINT8) ACPI_OFFSET (ACPI_OPERAND_OBJECT,f) +#define ACPI_EXD_NSOFFSET(f) (UINT8) ACPI_OFFSET (ACPI_NAMESPACE_NODE,f) +#define ACPI_EXD_TABLE_SIZE(name) (sizeof(name) / sizeof (ACPI_EXDUMP_INFO)) + +/* + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures + */ +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) +#pragma pack(1) +#endif + +typedef const struct acpi_exdump_info +{ + UINT8 Opcode; + UINT8 Offset; + char *Name; + +} ACPI_EXDUMP_INFO; + +/* Values for the Opcode field above */ + +#define ACPI_EXD_INIT 0 +#define ACPI_EXD_TYPE 1 +#define ACPI_EXD_UINT8 2 +#define ACPI_EXD_UINT16 3 +#define ACPI_EXD_UINT32 4 +#define ACPI_EXD_UINT64 5 +#define ACPI_EXD_LITERAL 6 +#define ACPI_EXD_POINTER 7 +#define ACPI_EXD_ADDRESS 8 +#define ACPI_EXD_STRING 9 +#define ACPI_EXD_BUFFER 10 +#define ACPI_EXD_PACKAGE 11 +#define ACPI_EXD_FIELD 12 +#define ACPI_EXD_REFERENCE 13 +#define ACPI_EXD_LIST 14 /* Operand object list */ +#define ACPI_EXD_HDLR_LIST 15 /* Address Handler list */ +#define ACPI_EXD_RGN_LIST 16 /* Region list */ +#define ACPI_EXD_NODE 17 /* Namespace Node */ + +/* restore default alignment */ + +#pragma pack() + + +/* + * exconvrt - object conversion + */ +ACPI_STATUS +AcpiExConvertToInteger ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + UINT32 Flags); + +ACPI_STATUS +AcpiExConvertToBuffer ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc); + +ACPI_STATUS +AcpiExConvertToString ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + UINT32 Type); + +/* Types for ->String conversion */ + +#define ACPI_EXPLICIT_BYTE_COPY 0x00000000 +#define ACPI_EXPLICIT_CONVERT_HEX 0x00000001 +#define ACPI_IMPLICIT_CONVERT_HEX 0x00000002 +#define ACPI_EXPLICIT_CONVERT_DECIMAL 0x00000003 + +ACPI_STATUS +AcpiExConvertToTargetType ( + ACPI_OBJECT_TYPE DestinationType, + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **ResultDesc, + ACPI_WALK_STATE *WalkState); + + +/* + * exdebug - AML debug object + */ +void +AcpiExDoDebugObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + UINT32 Level, + UINT32 Index); + +void +AcpiExStartTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +void +AcpiExStopTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +void +AcpiExStartTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +void +AcpiExStopTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState); + +void +AcpiExTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname); + + +/* + * exfield - ACPI AML (p-code) execution - field manipulation + */ +ACPI_STATUS +AcpiExCommonBufferSetup ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 BufferLength, + UINT32 *DatumCount); + +ACPI_STATUS +AcpiExWriteWithUpdateRule ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT64 Mask, + UINT64 FieldValue, + UINT32 FieldDatumByteOffset); + +void +AcpiExGetBufferDatum( + UINT64 *Datum, + void *Buffer, + UINT32 BufferLength, + UINT32 ByteGranularity, + UINT32 BufferOffset); + +void +AcpiExSetBufferDatum ( + UINT64 MergedDatum, + void *Buffer, + UINT32 BufferLength, + UINT32 ByteGranularity, + UINT32 BufferOffset); + +ACPI_STATUS +AcpiExReadDataFromField ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **RetBufferDesc); + +ACPI_STATUS +AcpiExWriteDataToField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc); + + +/* + * exfldio - low level field I/O + */ +ACPI_STATUS +AcpiExExtractFromField ( + ACPI_OPERAND_OBJECT *ObjDesc, + void *Buffer, + UINT32 BufferLength); + +ACPI_STATUS +AcpiExInsertIntoField ( + ACPI_OPERAND_OBJECT *ObjDesc, + void *Buffer, + UINT32 BufferLength); + +ACPI_STATUS +AcpiExAccessRegion ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset, + UINT64 *Value, + UINT32 ReadWrite); + + +/* + * exmisc - misc support routines + */ +ACPI_STATUS +AcpiExGetObjectReference ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ReturnDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExConcatTemplate ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *ObjDesc2, + ACPI_OPERAND_OBJECT **ActualReturnDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExDoConcatenate ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *ObjDesc2, + ACPI_OPERAND_OBJECT **ActualReturnDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExDoLogicalNumericOp ( + UINT16 Opcode, + UINT64 Integer0, + UINT64 Integer1, + BOOLEAN *LogicalResult); + +ACPI_STATUS +AcpiExDoLogicalOp ( + UINT16 Opcode, + ACPI_OPERAND_OBJECT *Operand0, + ACPI_OPERAND_OBJECT *Operand1, + BOOLEAN *LogicalResult); + +UINT64 +AcpiExDoMathOp ( + UINT16 Opcode, + UINT64 Operand0, + UINT64 Operand1); + +ACPI_STATUS +AcpiExCreateMutex ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateProcessor ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreatePowerResource ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateRegion ( + UINT8 *AmlStart, + UINT32 AmlLength, + UINT8 RegionSpace, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateEvent ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateAlias ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExCreateMethod ( + UINT8 *AmlStart, + UINT32 AmlLength, + ACPI_WALK_STATE *WalkState); + + +/* + * exconfig - dynamic table load/unload + */ +ACPI_STATUS +AcpiExLoadOp ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT *Target, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExLoadTableOp ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT **ReturnDesc); + +ACPI_STATUS +AcpiExUnloadTable ( + ACPI_OPERAND_OBJECT *DdbHandle); + + +/* + * exmutex - mutex support + */ +ACPI_STATUS +AcpiExAcquireMutex ( + ACPI_OPERAND_OBJECT *TimeDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExAcquireMutexObject ( + UINT16 Timeout, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_THREAD_ID ThreadId); + +ACPI_STATUS +AcpiExReleaseMutex ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExReleaseMutexObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +void +AcpiExReleaseAllMutexes ( + ACPI_THREAD_STATE *Thread); + +void +AcpiExUnlinkMutex ( + ACPI_OPERAND_OBJECT *ObjDesc); + + +/* + * exprep - ACPI AML execution - prep utilities + */ +ACPI_STATUS +AcpiExPrepCommonFieldObject ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 FieldFlags, + UINT8 FieldAttribute, + UINT32 FieldBitPosition, + UINT32 FieldBitLength); + +ACPI_STATUS +AcpiExPrepFieldValue ( + ACPI_CREATE_FIELD_INFO *Info); + + +/* + * exsystem - Interface to OS services + */ +ACPI_STATUS +AcpiExSystemDoNotifyOp ( + ACPI_OPERAND_OBJECT *Value, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemDoSleep( + UINT64 Time); + +ACPI_STATUS +AcpiExSystemDoStall ( + UINT32 Time); + +ACPI_STATUS +AcpiExSystemSignalEvent( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemWaitEvent( + ACPI_OPERAND_OBJECT *Time, + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemResetEvent( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiExSystemWaitSemaphore ( + ACPI_SEMAPHORE Semaphore, + UINT16 Timeout); + +ACPI_STATUS +AcpiExSystemWaitMutex ( + ACPI_MUTEX Mutex, + UINT16 Timeout); + +/* + * exoparg1 - ACPI AML execution, 1 operand + */ +ACPI_STATUS +AcpiExOpcode_0A_0T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_0T_0R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_0T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_1T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_1A_1T_0R ( + ACPI_WALK_STATE *WalkState); + +/* + * exoparg2 - ACPI AML execution, 2 operands + */ +ACPI_STATUS +AcpiExOpcode_2A_0T_0R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_2A_0T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_2A_1T_1R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_2A_2T_1R ( + ACPI_WALK_STATE *WalkState); + + +/* + * exoparg3 - ACPI AML execution, 3 operands + */ +ACPI_STATUS +AcpiExOpcode_3A_0T_0R ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExOpcode_3A_1T_1R ( + ACPI_WALK_STATE *WalkState); + + +/* + * exoparg6 - ACPI AML execution, 6 operands + */ +ACPI_STATUS +AcpiExOpcode_6A_0T_1R ( + ACPI_WALK_STATE *WalkState); + + +/* + * exresolv - Object resolution and get value functions + */ +ACPI_STATUS +AcpiExResolveToValue ( + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExResolveMultiple ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *Operand, + ACPI_OBJECT_TYPE *ReturnType, + ACPI_OPERAND_OBJECT **ReturnDesc); + + +/* + * exresnte - resolve namespace node + */ +ACPI_STATUS +AcpiExResolveNodeToValue ( + ACPI_NAMESPACE_NODE **StackPtr, + ACPI_WALK_STATE *WalkState); + + +/* + * exresop - resolve operand to value + */ +ACPI_STATUS +AcpiExResolveOperands ( + UINT16 Opcode, + ACPI_OPERAND_OBJECT **StackPtr, + ACPI_WALK_STATE *WalkState); + + +/* + * exdump - Interpreter debug output routines + */ +void +AcpiExDumpOperand ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Depth); + +void +AcpiExDumpOperands ( + ACPI_OPERAND_OBJECT **Operands, + const char *OpcodeName, + UINT32 NumOpcodes); + +void +AcpiExDumpObjectDescriptor ( + ACPI_OPERAND_OBJECT *Object, + UINT32 Flags); + +void +AcpiExDumpNamespaceNode ( + ACPI_NAMESPACE_NODE *Node, + UINT32 Flags); + + +/* + * exnames - AML namestring support + */ +ACPI_STATUS +AcpiExGetNameString ( + ACPI_OBJECT_TYPE DataType, + UINT8 *InAmlAddress, + char **OutNameString, + UINT32 *OutNameLength); + + +/* + * exstore - Object store support + */ +ACPI_STATUS +AcpiExStore ( + ACPI_OPERAND_OBJECT *ValDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExStoreObjectToNode ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node, + ACPI_WALK_STATE *WalkState, + UINT8 ImplicitConversion); + +#define ACPI_IMPLICIT_CONVERSION TRUE +#define ACPI_NO_IMPLICIT_CONVERSION FALSE + + +/* + * exstoren - resolve/store object + */ +ACPI_STATUS +AcpiExResolveObject ( + ACPI_OPERAND_OBJECT **SourceDescPtr, + ACPI_OBJECT_TYPE TargetType, + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiExStoreObjectToObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *DestDesc, + ACPI_OPERAND_OBJECT **NewDesc, + ACPI_WALK_STATE *WalkState); + + +/* + * exstorob - store object - buffer/string + */ +ACPI_STATUS +AcpiExStoreBufferToBuffer ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + +ACPI_STATUS +AcpiExStoreStringToString ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + + +/* + * excopy - object copy + */ +ACPI_STATUS +AcpiExCopyIntegerToIndexField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + +ACPI_STATUS +AcpiExCopyIntegerToBankField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + +ACPI_STATUS +AcpiExCopyDataToNamedField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node); + +ACPI_STATUS +AcpiExCopyIntegerToBufferField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *TargetDesc); + + +/* + * exutils - interpreter/scanner utilities + */ +void +AcpiExEnterInterpreter ( + void); + +void +AcpiExExitInterpreter ( + void); + +BOOLEAN +AcpiExTruncateFor32bitTable ( + ACPI_OPERAND_OBJECT *ObjDesc); + +void +AcpiExAcquireGlobalLock ( + UINT32 Rule); + +void +AcpiExReleaseGlobalLock ( + UINT32 Rule); + +void +AcpiExEisaIdToString ( + char *Dest, + UINT64 CompressedId); + +void +AcpiExIntegerToString ( + char *Dest, + UINT64 Value); + +void +AcpiExPciClsToString ( + char *Dest, + UINT8 ClassCode[3]); + +BOOLEAN +AcpiIsValidSpaceId ( + UINT8 SpaceId); + + +/* + * exregion - default OpRegion handlers + */ +ACPI_STATUS +AcpiExSystemMemorySpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExSystemIoSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExPciConfigSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExCmosSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExPciBarSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExEmbeddedControllerSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +ACPI_STATUS +AcpiExSmBusSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + + +ACPI_STATUS +AcpiExDataTableSpaceHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +#endif /* __INTERP_H__ */ diff --git a/third_party/lib/acpica/source/include/aclocal.h b/third_party/lib/acpica/source/include/aclocal.h new file mode 100644 index 000000000..086618250 --- /dev/null +++ b/third_party/lib/acpica/source/include/aclocal.h @@ -0,0 +1,1438 @@ +/****************************************************************************** + * + * Name: aclocal.h - Internal data types used across the ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACLOCAL_H__ +#define __ACLOCAL_H__ + + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +#define ACPI_SERIALIZED 0xFF + +typedef UINT32 ACPI_MUTEX_HANDLE; +#define ACPI_GLOBAL_LOCK (ACPI_SEMAPHORE) (-1) + +/* Total number of aml opcodes defined */ + +#define AML_NUM_OPCODES 0x82 + + +/* Forward declarations */ + +struct acpi_walk_state; +struct acpi_obj_mutex; +union acpi_parse_object; + + +/***************************************************************************** + * + * Mutex typedefs and structs + * + ****************************************************************************/ + + +/* + * Predefined handles for the mutex objects used within the subsystem + * All mutex objects are automatically created by AcpiUtMutexInitialize. + * + * The acquire/release ordering protocol is implied via this list. Mutexes + * with a lower value must be acquired before mutexes with a higher value. + * + * NOTE: any changes here must be reflected in the AcpiGbl_MutexNames + * table below also! + */ +#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */ +#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */ +#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */ +#define ACPI_MTX_EVENTS 3 /* Data for ACPI events */ +#define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */ +#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */ + +#define ACPI_MAX_MUTEX 5 +#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1 + + +/* Lock structure for reader/writer interfaces */ + +typedef struct acpi_rw_lock +{ + ACPI_MUTEX WriterMutex; + ACPI_MUTEX ReaderMutex; + UINT32 NumReaders; + +} ACPI_RW_LOCK; + + +/* + * Predefined handles for spinlocks used within the subsystem. + * These spinlocks are created by AcpiUtMutexInitialize + */ +#define ACPI_LOCK_GPES 0 +#define ACPI_LOCK_HARDWARE 1 + +#define ACPI_MAX_LOCK 1 +#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1 + + +/* This Thread ID means that the mutex is not in use (unlocked) */ + +#define ACPI_MUTEX_NOT_ACQUIRED (ACPI_THREAD_ID) -1 + +/* This Thread ID means an invalid thread ID */ + +#ifdef ACPI_OS_INVALID_THREAD_ID +#define ACPI_INVALID_THREAD_ID ACPI_OS_INVALID_THREAD_ID +#else +#define ACPI_INVALID_THREAD_ID ((ACPI_THREAD_ID) 0xFFFFFFFF) +#endif + +/* Table for the global mutexes */ + +typedef struct acpi_mutex_info +{ + ACPI_MUTEX Mutex; + UINT32 UseCount; + ACPI_THREAD_ID ThreadId; + +} ACPI_MUTEX_INFO; + + +/* Lock flag parameter for various interfaces */ + +#define ACPI_MTX_DO_NOT_LOCK 0 +#define ACPI_MTX_LOCK 1 + + +/* Field access granularities */ + +#define ACPI_FIELD_BYTE_GRANULARITY 1 +#define ACPI_FIELD_WORD_GRANULARITY 2 +#define ACPI_FIELD_DWORD_GRANULARITY 4 +#define ACPI_FIELD_QWORD_GRANULARITY 8 + + +#define ACPI_ENTRY_NOT_FOUND NULL + + +/***************************************************************************** + * + * Namespace typedefs and structs + * + ****************************************************************************/ + +/* Operational modes of the AML interpreter/scanner */ + +typedef enum +{ + ACPI_IMODE_LOAD_PASS1 = 0x01, + ACPI_IMODE_LOAD_PASS2 = 0x02, + ACPI_IMODE_EXECUTE = 0x03 + +} ACPI_INTERPRETER_MODE; + + +/* + * The Namespace Node describes a named object that appears in the AML. + * DescriptorType is used to differentiate between internal descriptors. + * + * The node is optimized for both 32-bit and 64-bit platforms: + * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case. + * + * Note: The DescriptorType and Type fields must appear in the identical + * position in both the ACPI_NAMESPACE_NODE and ACPI_OPERAND_OBJECT + * structures. + */ +typedef struct acpi_namespace_node +{ + union acpi_operand_object *Object; /* Interpreter object */ + UINT8 DescriptorType; /* Differentiate object descriptor types */ + UINT8 Type; /* ACPI Type associated with this name */ + UINT8 Flags; /* Miscellaneous flags */ + ACPI_OWNER_ID OwnerId; /* Node creator */ + ACPI_NAME_UNION Name; /* ACPI Name, always 4 chars per ACPI spec */ + struct acpi_namespace_node *Parent; /* Parent node */ + struct acpi_namespace_node *Child; /* First child */ + struct acpi_namespace_node *Peer; /* First peer */ + + /* + * The following fields are used by the ASL compiler and disassembler only + */ +#ifdef ACPI_LARGE_NAMESPACE_NODE + union acpi_parse_object *Op; + void *MethodLocals; + void *MethodArgs; + UINT32 Value; + UINT32 Length; + UINT8 ArgCount; + +#endif + +} ACPI_NAMESPACE_NODE; + + +/* Namespace Node flags */ + +#define ANOBJ_RESERVED 0x01 /* Available for use */ +#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */ +#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ +#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ +#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ +#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ +#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (InstallMethod) */ + +#define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ +#define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ +#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */ +#define ANOBJ_IS_REFERENCED 0x80 /* iASL only: Object was referenced */ + + +/* Internal ACPI table management - master table list */ + +typedef struct acpi_table_list +{ + ACPI_TABLE_DESC *Tables; /* Table descriptor array */ + UINT32 CurrentTableCount; /* Tables currently in the array */ + UINT32 MaxTableCount; /* Max tables array will hold */ + UINT8 Flags; + +} ACPI_TABLE_LIST; + +/* Flags for above */ + +#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */ +#define ACPI_ROOT_ORIGIN_ALLOCATED (1) +#define ACPI_ROOT_ALLOW_RESIZE (2) + + +/* List to manage incoming ACPI tables */ + +typedef struct acpi_new_table_desc +{ + ACPI_TABLE_HEADER *Table; + struct acpi_new_table_desc *Next; + +} ACPI_NEW_TABLE_DESC; + + +/* Predefined table indexes */ + +#define ACPI_INVALID_TABLE_INDEX (0xFFFFFFFF) + + +typedef struct acpi_find_context +{ + char *SearchFor; + ACPI_HANDLE *List; + UINT32 *Count; + +} ACPI_FIND_CONTEXT; + + +typedef struct acpi_ns_search_data +{ + ACPI_NAMESPACE_NODE *Node; + +} ACPI_NS_SEARCH_DATA; + + +/* Object types used during package copies */ + +#define ACPI_COPY_TYPE_SIMPLE 0 +#define ACPI_COPY_TYPE_PACKAGE 1 + + +/* Info structure used to convert external<->internal namestrings */ + +typedef struct acpi_namestring_info +{ + const char *ExternalName; + const char *NextExternalChar; + char *InternalName; + UINT32 Length; + UINT32 NumSegments; + UINT32 NumCarats; + BOOLEAN FullyQualified; + +} ACPI_NAMESTRING_INFO; + + +/* Field creation info */ + +typedef struct acpi_create_field_info +{ + ACPI_NAMESPACE_NODE *RegionNode; + ACPI_NAMESPACE_NODE *FieldNode; + ACPI_NAMESPACE_NODE *RegisterNode; + ACPI_NAMESPACE_NODE *DataRegisterNode; + ACPI_NAMESPACE_NODE *ConnectionNode; + UINT8 *ResourceBuffer; + UINT32 BankValue; + UINT32 FieldBitPosition; + UINT32 FieldBitLength; + UINT16 ResourceLength; + UINT16 PinNumberIndex; + UINT8 FieldFlags; + UINT8 Attribute; + UINT8 FieldType; + UINT8 AccessLength; + +} ACPI_CREATE_FIELD_INFO; + + +typedef +ACPI_STATUS (*ACPI_INTERNAL_METHOD) ( + struct acpi_walk_state *WalkState); + + +/* + * Bitmapped ACPI types. Used internally only + */ +#define ACPI_BTYPE_ANY 0x00000000 +#define ACPI_BTYPE_INTEGER 0x00000001 +#define ACPI_BTYPE_STRING 0x00000002 +#define ACPI_BTYPE_BUFFER 0x00000004 +#define ACPI_BTYPE_PACKAGE 0x00000008 +#define ACPI_BTYPE_FIELD_UNIT 0x00000010 +#define ACPI_BTYPE_DEVICE 0x00000020 +#define ACPI_BTYPE_EVENT 0x00000040 +#define ACPI_BTYPE_METHOD 0x00000080 +#define ACPI_BTYPE_MUTEX 0x00000100 +#define ACPI_BTYPE_REGION 0x00000200 +#define ACPI_BTYPE_POWER 0x00000400 +#define ACPI_BTYPE_PROCESSOR 0x00000800 +#define ACPI_BTYPE_THERMAL 0x00001000 +#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 +#define ACPI_BTYPE_DDB_HANDLE 0x00004000 +#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 +#define ACPI_BTYPE_REFERENCE_OBJECT 0x00010000 /* From Index(), RefOf(), etc (Type6Opcodes) */ +#define ACPI_BTYPE_RESOURCE 0x00020000 +#define ACPI_BTYPE_NAMED_REFERENCE 0x00040000 /* Generic unresolved Name or Namepath */ + +#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) + +#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) + + /* Used by Copy, DeRefOf, Store, Printf, Fprintf */ + +#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE_OBJECT | ACPI_BTYPE_DDB_HANDLE) +#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) +#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */ +#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF + +#pragma pack(1) + +/* + * Information structure for ACPI predefined names. + * Each entry in the table contains the following items: + * + * Name - The ACPI reserved name + * ParamCount - Number of arguments to the method + * ExpectedReturnBtypes - Allowed type(s) for the return value + */ +typedef struct acpi_name_info +{ + char Name[ACPI_NAME_SIZE]; + UINT16 ArgumentList; + UINT8 ExpectedBtypes; + +} ACPI_NAME_INFO; + +/* + * Secondary information structures for ACPI predefined objects that return + * package objects. This structure appears as the next entry in the table + * after the NAME_INFO structure above. + * + * The reason for this is to minimize the size of the predefined name table. + */ + +/* + * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2, + * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT, + * ACPI_PTYPE2_FIX_VAR + */ +typedef struct acpi_package_info +{ + UINT8 Type; + UINT8 ObjectType1; + UINT8 Count1; + UINT8 ObjectType2; + UINT8 Count2; + UINT16 Reserved; + +} ACPI_PACKAGE_INFO; + +/* Used for ACPI_PTYPE2_FIXED */ + +typedef struct acpi_package_info2 +{ + UINT8 Type; + UINT8 Count; + UINT8 ObjectType[4]; + UINT8 Reserved; + +} ACPI_PACKAGE_INFO2; + +/* Used for ACPI_PTYPE1_OPTION */ + +typedef struct acpi_package_info3 +{ + UINT8 Type; + UINT8 Count; + UINT8 ObjectType[2]; + UINT8 TailObjectType; + UINT16 Reserved; + +} ACPI_PACKAGE_INFO3; + +typedef struct acpi_package_info4 +{ + UINT8 Type; + UINT8 ObjectType1; + UINT8 Count1; + UINT8 SubObjectTypes; + UINT8 PkgCount; + UINT16 Reserved; + +} ACPI_PACKAGE_INFO4; + +typedef union acpi_predefined_info +{ + ACPI_NAME_INFO Info; + ACPI_PACKAGE_INFO RetInfo; + ACPI_PACKAGE_INFO2 RetInfo2; + ACPI_PACKAGE_INFO3 RetInfo3; + ACPI_PACKAGE_INFO4 RetInfo4; + +} ACPI_PREDEFINED_INFO; + +/* Reset to default packing */ + +#pragma pack() + + +/* Return object auto-repair info */ + +typedef ACPI_STATUS (*ACPI_OBJECT_CONVERTER) ( + struct acpi_namespace_node *Scope, + union acpi_operand_object *OriginalObject, + union acpi_operand_object **ConvertedObject); + +typedef struct acpi_simple_repair_info +{ + char Name[ACPI_NAME_SIZE]; + UINT32 UnexpectedBtypes; + UINT32 PackageIndex; + ACPI_OBJECT_CONVERTER ObjectConverter; + +} ACPI_SIMPLE_REPAIR_INFO; + + +/* + * Bitmapped return value types + * Note: the actual data types must be contiguous, a loop in nspredef.c + * depends on this. + */ +#define ACPI_RTYPE_ANY 0x00 +#define ACPI_RTYPE_NONE 0x01 +#define ACPI_RTYPE_INTEGER 0x02 +#define ACPI_RTYPE_STRING 0x04 +#define ACPI_RTYPE_BUFFER 0x08 +#define ACPI_RTYPE_PACKAGE 0x10 +#define ACPI_RTYPE_REFERENCE 0x20 +#define ACPI_RTYPE_ALL 0x3F + +#define ACPI_NUM_RTYPES 5 /* Number of actual object types */ + + +/* Info for running the _REG methods */ + +typedef struct acpi_reg_walk_info +{ + ACPI_ADR_SPACE_TYPE SpaceId; + UINT32 Function; + UINT32 RegRunCount; + +} ACPI_REG_WALK_INFO; + + +/***************************************************************************** + * + * Event typedefs and structs + * + ****************************************************************************/ + +/* Dispatch info for each host-installed SCI handler */ + +typedef struct acpi_sci_handler_info +{ + struct acpi_sci_handler_info *Next; + ACPI_SCI_HANDLER Address; /* Address of handler */ + void *Context; /* Context to be passed to handler */ + +} ACPI_SCI_HANDLER_INFO; + +/* Dispatch info for each GPE -- either a method or handler, cannot be both */ + +typedef struct acpi_gpe_handler_info +{ + ACPI_GPE_HANDLER Address; /* Address of handler, if any */ + void *Context; /* Context to be passed to handler */ + ACPI_NAMESPACE_NODE *MethodNode; /* Method node for this GPE level (saved) */ + UINT8 OriginalFlags; /* Original (pre-handler) GPE info */ + BOOLEAN OriginallyEnabled; /* True if GPE was originally enabled */ + +} ACPI_GPE_HANDLER_INFO; + +/* Notify info for implicit notify, multiple device objects */ + +typedef struct acpi_gpe_notify_info +{ + ACPI_NAMESPACE_NODE *DeviceNode; /* Device to be notified */ + struct acpi_gpe_notify_info *Next; + +} ACPI_GPE_NOTIFY_INFO; + +/* + * GPE dispatch info. At any time, the GPE can have at most one type + * of dispatch - Method, Handler, or Implicit Notify. + */ +typedef union acpi_gpe_dispatch_info +{ + ACPI_NAMESPACE_NODE *MethodNode; /* Method node for this GPE level */ + ACPI_GPE_HANDLER_INFO *Handler; /* Installed GPE handler */ + ACPI_GPE_NOTIFY_INFO *NotifyList; /* List of _PRW devices for implicit notifies */ + +} ACPI_GPE_DISPATCH_INFO; + +/* + * Information about a GPE, one per each GPE in an array. + * NOTE: Important to keep this struct as small as possible. + */ +typedef struct acpi_gpe_event_info +{ + union acpi_gpe_dispatch_info Dispatch; /* Either Method, Handler, or NotifyList */ + struct acpi_gpe_register_info *RegisterInfo; /* Backpointer to register info */ + UINT8 Flags; /* Misc info about this GPE */ + UINT8 GpeNumber; /* This GPE */ + UINT8 RuntimeCount; /* References to a run GPE */ + +} ACPI_GPE_EVENT_INFO; + +/* Information about a GPE register pair, one per each status/enable pair in an array */ + +typedef struct acpi_gpe_register_info +{ + ACPI_GENERIC_ADDRESS StatusAddress; /* Address of status reg */ + ACPI_GENERIC_ADDRESS EnableAddress; /* Address of enable reg */ + UINT16 BaseGpeNumber; /* Base GPE number for this register */ + UINT8 EnableForWake; /* GPEs to keep enabled when sleeping */ + UINT8 EnableForRun; /* GPEs to keep enabled when running */ + UINT8 EnableMask; /* Current mask of enabled GPEs */ + +} ACPI_GPE_REGISTER_INFO; + +/* + * Information about a GPE register block, one per each installed block -- + * GPE0, GPE1, and one per each installed GPE Block Device. + */ +typedef struct acpi_gpe_block_info +{ + ACPI_NAMESPACE_NODE *Node; + struct acpi_gpe_block_info *Previous; + struct acpi_gpe_block_info *Next; + struct acpi_gpe_xrupt_info *XruptBlock; /* Backpointer to interrupt block */ + ACPI_GPE_REGISTER_INFO *RegisterInfo; /* One per GPE register pair */ + ACPI_GPE_EVENT_INFO *EventInfo; /* One for each GPE */ + UINT64 Address; /* Base address of the block */ + UINT32 RegisterCount; /* Number of register pairs in block */ + UINT16 GpeCount; /* Number of individual GPEs in block */ + UINT16 BlockBaseNumber;/* Base GPE number for this block */ + UINT8 SpaceId; + BOOLEAN Initialized; /* TRUE if this block is initialized */ + +} ACPI_GPE_BLOCK_INFO; + +/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ + +typedef struct acpi_gpe_xrupt_info +{ + struct acpi_gpe_xrupt_info *Previous; + struct acpi_gpe_xrupt_info *Next; + ACPI_GPE_BLOCK_INFO *GpeBlockListHead; /* List of GPE blocks for this xrupt */ + UINT32 InterruptNumber; /* System interrupt number */ + +} ACPI_GPE_XRUPT_INFO; + +typedef struct acpi_gpe_walk_info +{ + ACPI_NAMESPACE_NODE *GpeDevice; + ACPI_GPE_BLOCK_INFO *GpeBlock; + UINT16 Count; + ACPI_OWNER_ID OwnerId; + BOOLEAN ExecuteByOwnerId; + +} ACPI_GPE_WALK_INFO; + +typedef struct acpi_gpe_device_info +{ + UINT32 Index; + UINT32 NextBlockBaseIndex; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *GpeDevice; + +} ACPI_GPE_DEVICE_INFO; + +typedef ACPI_STATUS (*ACPI_GPE_CALLBACK) ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/* Information about each particular fixed event */ + +typedef struct acpi_fixed_event_handler +{ + ACPI_EVENT_HANDLER Handler; /* Address of handler. */ + void *Context; /* Context to be passed to handler */ + +} ACPI_FIXED_EVENT_HANDLER; + +typedef struct acpi_fixed_event_info +{ + UINT8 StatusRegisterId; + UINT8 EnableRegisterId; + UINT16 StatusBitMask; + UINT16 EnableBitMask; + +} ACPI_FIXED_EVENT_INFO; + +/* Information used during field processing */ + +typedef struct acpi_field_info +{ + UINT8 SkipField; + UINT8 FieldFlag; + UINT32 PkgLength; + +} ACPI_FIELD_INFO; + + +/***************************************************************************** + * + * Generic "state" object for stacks + * + ****************************************************************************/ + +#define ACPI_CONTROL_NORMAL 0xC0 +#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1 +#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2 +#define ACPI_CONTROL_PREDICATE_FALSE 0xC3 +#define ACPI_CONTROL_PREDICATE_TRUE 0xC4 + + +#define ACPI_STATE_COMMON \ + void *Next; \ + UINT8 DescriptorType; /* To differentiate various internal objs */\ + UINT8 Flags; \ + UINT16 Value; \ + UINT16 State; + + /* There are 2 bytes available here until the next natural alignment boundary */ + +typedef struct acpi_common_state +{ + ACPI_STATE_COMMON +} ACPI_COMMON_STATE; + + +/* + * Update state - used to traverse complex objects such as packages + */ +typedef struct acpi_update_state +{ + ACPI_STATE_COMMON + union acpi_operand_object *Object; + +} ACPI_UPDATE_STATE; + + +/* + * Pkg state - used to traverse nested package structures + */ +typedef struct acpi_pkg_state +{ + ACPI_STATE_COMMON + UINT16 Index; + union acpi_operand_object *SourceObject; + union acpi_operand_object *DestObject; + struct acpi_walk_state *WalkState; + void *ThisTargetObj; + UINT32 NumPackages; + +} ACPI_PKG_STATE; + + +/* + * Control state - one per if/else and while constructs. + * Allows nesting of these constructs + */ +typedef struct acpi_control_state +{ + ACPI_STATE_COMMON + UINT16 Opcode; + union acpi_parse_object *PredicateOp; + UINT8 *AmlPredicateStart; /* Start of if/while predicate */ + UINT8 *PackageEnd; /* End of if/while block */ + UINT32 LoopCount; /* While() loop counter */ + +} ACPI_CONTROL_STATE; + + +/* + * Scope state - current scope during namespace lookups + */ +typedef struct acpi_scope_state +{ + ACPI_STATE_COMMON + ACPI_NAMESPACE_NODE *Node; + +} ACPI_SCOPE_STATE; + + +typedef struct acpi_pscope_state +{ + ACPI_STATE_COMMON + UINT32 ArgCount; /* Number of fixed arguments */ + union acpi_parse_object *Op; /* Current op being parsed */ + UINT8 *ArgEnd; /* Current argument end */ + UINT8 *PkgEnd; /* Current package end */ + UINT32 ArgList; /* Next argument to parse */ + +} ACPI_PSCOPE_STATE; + + +/* + * Thread state - one per thread across multiple walk states. Multiple walk + * states are created when there are nested control methods executing. + */ +typedef struct acpi_thread_state +{ + ACPI_STATE_COMMON + UINT8 CurrentSyncLevel; /* Mutex Sync (nested acquire) level */ + struct acpi_walk_state *WalkStateList; /* Head of list of WalkStates for this thread */ + union acpi_operand_object *AcquiredMutexList; /* List of all currently acquired mutexes */ + ACPI_THREAD_ID ThreadId; /* Running thread ID */ + +} ACPI_THREAD_STATE; + + +/* + * Result values - used to accumulate the results of nested + * AML arguments + */ +typedef struct acpi_result_values +{ + ACPI_STATE_COMMON + union acpi_operand_object *ObjDesc [ACPI_RESULTS_FRAME_OBJ_NUM]; + +} ACPI_RESULT_VALUES; + + +typedef +ACPI_STATUS (*ACPI_PARSE_DOWNWARDS) ( + struct acpi_walk_state *WalkState, + union acpi_parse_object **OutOp); + +typedef +ACPI_STATUS (*ACPI_PARSE_UPWARDS) ( + struct acpi_walk_state *WalkState); + + +/* Global handlers for AML Notifies */ + +typedef struct acpi_global_notify_handler +{ + ACPI_NOTIFY_HANDLER Handler; + void *Context; + +} ACPI_GLOBAL_NOTIFY_HANDLER; + +/* + * Notify info - used to pass info to the deferred notify + * handler/dispatcher. + */ +typedef struct acpi_notify_info +{ + ACPI_STATE_COMMON + UINT8 HandlerListId; + ACPI_NAMESPACE_NODE *Node; + union acpi_operand_object *HandlerListHead; + ACPI_GLOBAL_NOTIFY_HANDLER *Global; + +} ACPI_NOTIFY_INFO; + + +/* Generic state is union of structs above */ + +typedef union acpi_generic_state +{ + ACPI_COMMON_STATE Common; + ACPI_CONTROL_STATE Control; + ACPI_UPDATE_STATE Update; + ACPI_SCOPE_STATE Scope; + ACPI_PSCOPE_STATE ParseScope; + ACPI_PKG_STATE Pkg; + ACPI_THREAD_STATE Thread; + ACPI_RESULT_VALUES Results; + ACPI_NOTIFY_INFO Notify; + +} ACPI_GENERIC_STATE; + + +/***************************************************************************** + * + * Interpreter typedefs and structs + * + ****************************************************************************/ + +typedef +ACPI_STATUS (*ACPI_EXECUTE_OP) ( + struct acpi_walk_state *WalkState); + +/* Address Range info block */ + +typedef struct acpi_address_range +{ + struct acpi_address_range *Next; + ACPI_NAMESPACE_NODE *RegionNode; + ACPI_PHYSICAL_ADDRESS StartAddress; + ACPI_PHYSICAL_ADDRESS EndAddress; + +} ACPI_ADDRESS_RANGE; + + +/***************************************************************************** + * + * Parser typedefs and structs + * + ****************************************************************************/ + +/* + * AML opcode, name, and argument layout + */ +typedef struct acpi_opcode_info +{ +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) + char *Name; /* Opcode name (disassembler/debug only) */ +#endif + UINT32 ParseArgs; /* Grammar/Parse time arguments */ + UINT32 RuntimeArgs; /* Interpret time arguments */ + UINT16 Flags; /* Misc flags */ + UINT8 ObjectType; /* Corresponding internal object type */ + UINT8 Class; /* Opcode class */ + UINT8 Type; /* Opcode type */ + +} ACPI_OPCODE_INFO; + +/* Structure for Resource Tag information */ + +typedef struct acpi_tag_info +{ + UINT32 BitOffset; + UINT32 BitLength; + +} ACPI_TAG_INFO; + +/* Value associated with the parse object */ + +typedef union acpi_parse_value +{ + UINT64 Integer; /* Integer constant (Up to 64 bits) */ + UINT32 Size; /* bytelist or field size */ + char *String; /* NULL terminated string */ + UINT8 *Buffer; /* buffer or string */ + char *Name; /* NULL terminated string */ + union acpi_parse_object *Arg; /* arguments and contained ops */ + ACPI_TAG_INFO Tag; /* Resource descriptor tag info */ + +} ACPI_PARSE_VALUE; + + +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) +#define ACPI_DISASM_ONLY_MEMBERS(a) a; +#else +#define ACPI_DISASM_ONLY_MEMBERS(a) +#endif + +#define ACPI_PARSE_COMMON \ + union acpi_parse_object *Parent; /* Parent op */\ + UINT8 DescriptorType; /* To differentiate various internal objs */\ + UINT8 Flags; /* Type of Op */\ + UINT16 AmlOpcode; /* AML opcode */\ + UINT8 *Aml; /* Address of declaration in AML */\ + union acpi_parse_object *Next; /* Next op */\ + ACPI_NAMESPACE_NODE *Node; /* For use by interpreter */\ + ACPI_PARSE_VALUE Value; /* Value or args associated with the opcode */\ + UINT8 ArgListLength; /* Number of elements in the arg list */\ + ACPI_DISASM_ONLY_MEMBERS (\ + UINT8 DisasmFlags; /* Used during AML disassembly */\ + UINT8 DisasmOpcode; /* Subtype used for disassembly */\ + char *OperatorSymbol;/* Used for C-style operator name strings */\ + char AmlOpName[16]) /* Op name (debug only) */ + + +/* Flags for DisasmFlags field above */ + +#define ACPI_DASM_BUFFER 0x00 /* Buffer is a simple data buffer */ +#define ACPI_DASM_RESOURCE 0x01 /* Buffer is a Resource Descriptor */ +#define ACPI_DASM_STRING 0x02 /* Buffer is a ASCII string */ +#define ACPI_DASM_UNICODE 0x03 /* Buffer is a Unicode string */ +#define ACPI_DASM_PLD_METHOD 0x04 /* Buffer is a _PLD method bit-packed buffer */ +#define ACPI_DASM_UUID 0x05 /* Buffer is a UUID/GUID */ +#define ACPI_DASM_EISAID 0x06 /* Integer is an EISAID */ +#define ACPI_DASM_MATCHOP 0x07 /* Parent opcode is a Match() operator */ +#define ACPI_DASM_LNOT_PREFIX 0x08 /* Start of a LNotEqual (etc.) pair of opcodes */ +#define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a LNotEqual (etc.) pair of opcodes */ +#define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */ +#define ACPI_DASM_IGNORE 0x0B /* Not used at this time */ + +/* + * Generic operation (for example: If, While, Store) + */ +typedef struct acpi_parse_obj_common +{ + ACPI_PARSE_COMMON +} ACPI_PARSE_OBJ_COMMON; + + +/* + * Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and OpRegions), + * and bytelists. + */ +typedef struct acpi_parse_obj_named +{ + ACPI_PARSE_COMMON + UINT8 *Path; + UINT8 *Data; /* AML body or bytelist data */ + UINT32 Length; /* AML length */ + UINT32 Name; /* 4-byte name or zero if no name */ + +} ACPI_PARSE_OBJ_NAMED; + + +/* This version is used by the iASL compiler only */ + +#define ACPI_MAX_PARSEOP_NAME 20 + +typedef struct acpi_parse_obj_asl +{ + ACPI_PARSE_COMMON + union acpi_parse_object *Child; + union acpi_parse_object *ParentMethod; + char *Filename; + char *ExternalName; + char *Namepath; + char NameSeg[4]; + UINT32 ExtraValue; + UINT32 Column; + UINT32 LineNumber; + UINT32 LogicalLineNumber; + UINT32 LogicalByteOffset; + UINT32 EndLine; + UINT32 EndLogicalLine; + UINT32 AcpiBtype; + UINT32 AmlLength; + UINT32 AmlSubtreeLength; + UINT32 FinalAmlLength; + UINT32 FinalAmlOffset; + UINT32 CompileFlags; + UINT16 ParseOpcode; + UINT8 AmlOpcodeLength; + UINT8 AmlPkgLenBytes; + UINT8 Extra; + char ParseOpName[ACPI_MAX_PARSEOP_NAME]; + +} ACPI_PARSE_OBJ_ASL; + +typedef union acpi_parse_object +{ + ACPI_PARSE_OBJ_COMMON Common; + ACPI_PARSE_OBJ_NAMED Named; + ACPI_PARSE_OBJ_ASL Asl; + +} ACPI_PARSE_OBJECT; + + +/* + * Parse state - one state per parser invocation and each control + * method. + */ +typedef struct acpi_parse_state +{ + UINT8 *AmlStart; /* First AML byte */ + UINT8 *Aml; /* Next AML byte */ + UINT8 *AmlEnd; /* (last + 1) AML byte */ + UINT8 *PkgStart; /* Current package begin */ + UINT8 *PkgEnd; /* Current package end */ + union acpi_parse_object *StartOp; /* Root of parse tree */ + struct acpi_namespace_node *StartNode; + union acpi_generic_state *Scope; /* Current scope */ + union acpi_parse_object *StartScope; + UINT32 AmlSize; + +} ACPI_PARSE_STATE; + + +/* Parse object flags */ + +#define ACPI_PARSEOP_GENERIC 0x01 +#define ACPI_PARSEOP_NAMED 0x02 +#define ACPI_PARSEOP_DEFERRED 0x04 +#define ACPI_PARSEOP_BYTELIST 0x08 +#define ACPI_PARSEOP_IN_STACK 0x10 +#define ACPI_PARSEOP_TARGET 0x20 +#define ACPI_PARSEOP_IN_CACHE 0x80 + +/* Parse object DisasmFlags */ + +#define ACPI_PARSEOP_IGNORE 0x01 +#define ACPI_PARSEOP_PARAMLIST 0x02 +#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 +#define ACPI_PARSEOP_PREDEF_CHECKED 0x08 +#define ACPI_PARSEOP_CLOSING_PAREN 0x10 +#define ACPI_PARSEOP_COMPOUND 0x20 +#define ACPI_PARSEOP_ASSIGNMENT 0x40 +#define ACPI_PARSEOP_ELSEIF 0x80 + + +/***************************************************************************** + * + * Hardware (ACPI registers) and PNP + * + ****************************************************************************/ + +typedef struct acpi_bit_register_info +{ + UINT8 ParentRegister; + UINT8 BitPosition; + UINT16 AccessBitMask; + +} ACPI_BIT_REGISTER_INFO; + + +/* + * Some ACPI registers have bits that must be ignored -- meaning that they + * must be preserved. + */ +#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */ + +/* Write-only bits must be zeroed by software */ + +#define ACPI_PM1_CONTROL_WRITEONLY_BITS 0x2004 /* Bits 13, 2 */ + +/* For control registers, both ignored and reserved bits must be preserved */ + +/* + * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the + * ACPI specification to be a "preserved" bit - "OSPM always preserves this + * bit position", section 4.7.3.2.1. However, on some machines the OS must + * write a one to this bit after resume for the machine to work properly. + * To enable this, we no longer attempt to preserve this bit. No machines + * are known to fail if the bit is not preserved. (May 2009) + */ +#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ +#define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ +#define ACPI_PM1_CONTROL_PRESERVED_BITS \ + (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) + +#define ACPI_PM2_CONTROL_PRESERVED_BITS 0xFFFFFFFE /* All except bit 0 */ + +/* + * Register IDs + * These are the full ACPI registers + */ +#define ACPI_REGISTER_PM1_STATUS 0x01 +#define ACPI_REGISTER_PM1_ENABLE 0x02 +#define ACPI_REGISTER_PM1_CONTROL 0x03 +#define ACPI_REGISTER_PM2_CONTROL 0x04 +#define ACPI_REGISTER_PM_TIMER 0x05 +#define ACPI_REGISTER_PROCESSOR_BLOCK 0x06 +#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x07 + + +/* Masks used to access the BitRegisters */ + +#define ACPI_BITMASK_TIMER_STATUS 0x0001 +#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 +#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 +#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 +#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ +#define ACPI_BITMASK_WAKE_STATUS 0x8000 + +#define ACPI_BITMASK_ALL_FIXED_STATUS (\ + ACPI_BITMASK_TIMER_STATUS | \ + ACPI_BITMASK_BUS_MASTER_STATUS | \ + ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ + ACPI_BITMASK_POWER_BUTTON_STATUS | \ + ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ + ACPI_BITMASK_RT_CLOCK_STATUS | \ + ACPI_BITMASK_PCIEXP_WAKE_STATUS | \ + ACPI_BITMASK_WAKE_STATUS) + +#define ACPI_BITMASK_TIMER_ENABLE 0x0001 +#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200 +#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400 +#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */ + +#define ACPI_BITMASK_SCI_ENABLE 0x0001 +#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002 +#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004 +#define ACPI_BITMASK_SLEEP_TYPE 0x1C00 +#define ACPI_BITMASK_SLEEP_ENABLE 0x2000 + +#define ACPI_BITMASK_ARB_DISABLE 0x0001 + + +/* Raw bit position of each BitRegister */ + +#define ACPI_BITPOSITION_TIMER_STATUS 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_STATUS 0x04 +#define ACPI_BITPOSITION_GLOBAL_LOCK_STATUS 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_STATUS 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_STATUS 0x0A +#define ACPI_BITPOSITION_PCIEXP_WAKE_STATUS 0x0E /* ACPI 3.0 */ +#define ACPI_BITPOSITION_WAKE_STATUS 0x0F + +#define ACPI_BITPOSITION_TIMER_ENABLE 0x00 +#define ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_ENABLE 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_ENABLE 0x0A +#define ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE 0x0E /* ACPI 3.0 */ + +#define ACPI_BITPOSITION_SCI_ENABLE 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_RLD 0x01 +#define ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE 0x02 +#define ACPI_BITPOSITION_SLEEP_TYPE 0x0A +#define ACPI_BITPOSITION_SLEEP_ENABLE 0x0D + +#define ACPI_BITPOSITION_ARB_DISABLE 0x00 + + +/* Structs and definitions for _OSI support and I/O port validation */ + +#define ACPI_ALWAYS_ILLEGAL 0x00 + +typedef struct acpi_interface_info +{ + char *Name; + struct acpi_interface_info *Next; + UINT8 Flags; + UINT8 Value; + +} ACPI_INTERFACE_INFO; + +#define ACPI_OSI_INVALID 0x01 +#define ACPI_OSI_DYNAMIC 0x02 +#define ACPI_OSI_FEATURE 0x04 +#define ACPI_OSI_DEFAULT_INVALID 0x08 +#define ACPI_OSI_OPTIONAL_FEATURE (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID) + +typedef struct acpi_port_info +{ + char *Name; + UINT16 Start; + UINT16 End; + UINT8 OsiDependency; + +} ACPI_PORT_INFO; + + +/***************************************************************************** + * + * Resource descriptors + * + ****************************************************************************/ + +/* ResourceType values */ + +#define ACPI_ADDRESS_TYPE_MEMORY_RANGE 0 +#define ACPI_ADDRESS_TYPE_IO_RANGE 1 +#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2 + +/* Resource descriptor types and masks */ + +#define ACPI_RESOURCE_NAME_LARGE 0x80 +#define ACPI_RESOURCE_NAME_SMALL 0x00 + +#define ACPI_RESOURCE_NAME_SMALL_MASK 0x78 /* Bits 6:3 contain the type */ +#define ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK 0x07 /* Bits 2:0 contain the length */ +#define ACPI_RESOURCE_NAME_LARGE_MASK 0x7F /* Bits 6:0 contain the type */ + + +/* + * Small resource descriptor "names" as defined by the ACPI specification. + * Note: Bits 2:0 are used for the descriptor length + */ +#define ACPI_RESOURCE_NAME_IRQ 0x20 +#define ACPI_RESOURCE_NAME_DMA 0x28 +#define ACPI_RESOURCE_NAME_START_DEPENDENT 0x30 +#define ACPI_RESOURCE_NAME_END_DEPENDENT 0x38 +#define ACPI_RESOURCE_NAME_IO 0x40 +#define ACPI_RESOURCE_NAME_FIXED_IO 0x48 +#define ACPI_RESOURCE_NAME_FIXED_DMA 0x50 +#define ACPI_RESOURCE_NAME_RESERVED_S2 0x58 +#define ACPI_RESOURCE_NAME_RESERVED_S3 0x60 +#define ACPI_RESOURCE_NAME_RESERVED_S4 0x68 +#define ACPI_RESOURCE_NAME_VENDOR_SMALL 0x70 +#define ACPI_RESOURCE_NAME_END_TAG 0x78 + +/* + * Large resource descriptor "names" as defined by the ACPI specification. + * Note: includes the Large Descriptor bit in bit[7] + */ +#define ACPI_RESOURCE_NAME_MEMORY24 0x81 +#define ACPI_RESOURCE_NAME_GENERIC_REGISTER 0x82 +#define ACPI_RESOURCE_NAME_RESERVED_L1 0x83 +#define ACPI_RESOURCE_NAME_VENDOR_LARGE 0x84 +#define ACPI_RESOURCE_NAME_MEMORY32 0x85 +#define ACPI_RESOURCE_NAME_FIXED_MEMORY32 0x86 +#define ACPI_RESOURCE_NAME_ADDRESS32 0x87 +#define ACPI_RESOURCE_NAME_ADDRESS16 0x88 +#define ACPI_RESOURCE_NAME_EXTENDED_IRQ 0x89 +#define ACPI_RESOURCE_NAME_ADDRESS64 0x8A +#define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B +#define ACPI_RESOURCE_NAME_GPIO 0x8C +#define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8E + + +/***************************************************************************** + * + * Miscellaneous + * + ****************************************************************************/ + +#define ACPI_ASCII_ZERO 0x30 + + +/***************************************************************************** + * + * Disassembler + * + ****************************************************************************/ + +typedef struct acpi_external_list +{ + char *Path; + char *InternalPath; + struct acpi_external_list *Next; + UINT32 Value; + UINT16 Length; + UINT16 Flags; + UINT8 Type; + +} ACPI_EXTERNAL_LIST; + +/* Values for Flags field above */ + +#define ACPI_EXT_RESOLVED_REFERENCE 0x01 /* Object was resolved during cross ref */ +#define ACPI_EXT_ORIGIN_FROM_FILE 0x02 /* External came from a file */ +#define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ +#define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ + + +typedef struct acpi_external_file +{ + char *Path; + struct acpi_external_file *Next; + +} ACPI_EXTERNAL_FILE; + + +/***************************************************************************** + * + * Debugger + * + ****************************************************************************/ + +typedef struct acpi_db_method_info +{ + ACPI_HANDLE Method; + ACPI_HANDLE MainThreadGate; + ACPI_HANDLE ThreadCompleteGate; + ACPI_HANDLE InfoGate; + ACPI_THREAD_ID *Threads; + UINT32 NumThreads; + UINT32 NumCreated; + UINT32 NumCompleted; + + char *Name; + UINT32 Flags; + UINT32 NumLoops; + char Pathname[ACPI_DB_LINE_BUFFER_SIZE]; + char **Args; + ACPI_OBJECT_TYPE *Types; + + /* + * Arguments to be passed to method for the command + * Threads - + * the Number of threads, ID of current thread and + * Index of current thread inside all them created. + */ + char InitArgs; +#ifdef ACPI_DEBUGGER + ACPI_OBJECT_TYPE ArgTypes[4]; +#endif + char *Arguments[4]; + char NumThreadsStr[11]; + char IdOfThreadStr[11]; + char IndexOfThreadStr[11]; + +} ACPI_DB_METHOD_INFO; + +typedef struct acpi_integrity_info +{ + UINT32 Nodes; + UINT32 Objects; + +} ACPI_INTEGRITY_INFO; + + +#define ACPI_DB_DISABLE_OUTPUT 0x00 +#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 +#define ACPI_DB_CONSOLE_OUTPUT 0x02 +#define ACPI_DB_DUPLICATE_OUTPUT 0x03 + + +typedef struct acpi_object_info +{ + UINT32 Types[ACPI_TOTAL_TYPES]; + +} ACPI_OBJECT_INFO; + + +/***************************************************************************** + * + * Debug + * + ****************************************************************************/ + +/* Entry for a memory allocation (debug only) */ + +#define ACPI_MEM_MALLOC 0 +#define ACPI_MEM_CALLOC 1 +#define ACPI_MAX_MODULE_NAME 16 + +#define ACPI_COMMON_DEBUG_MEM_HEADER \ + struct acpi_debug_mem_block *Previous; \ + struct acpi_debug_mem_block *Next; \ + UINT32 Size; \ + UINT32 Component; \ + UINT32 Line; \ + char Module[ACPI_MAX_MODULE_NAME]; \ + UINT8 AllocType; + +typedef struct acpi_debug_mem_header +{ + ACPI_COMMON_DEBUG_MEM_HEADER + +} ACPI_DEBUG_MEM_HEADER; + +typedef struct acpi_debug_mem_block +{ + ACPI_COMMON_DEBUG_MEM_HEADER + UINT64 UserSpace; + +} ACPI_DEBUG_MEM_BLOCK; + + +#define ACPI_MEM_LIST_GLOBAL 0 +#define ACPI_MEM_LIST_NSNODE 1 +#define ACPI_MEM_LIST_MAX 1 +#define ACPI_NUM_MEM_LISTS 2 + + +/***************************************************************************** + * + * Info/help support + * + ****************************************************************************/ + +typedef struct ah_predefined_name +{ + char *Name; + char *Description; +#ifndef ACPI_ASL_COMPILER + char *Action; +#endif + +} AH_PREDEFINED_NAME; + +typedef struct ah_device_id +{ + char *Name; + char *Description; + +} AH_DEVICE_ID; + +typedef struct ah_uuid +{ + char *Description; + char *String; + +} AH_UUID; + +typedef struct ah_table +{ + char *Signature; + char *Description; + +} AH_TABLE; + +#endif /* __ACLOCAL_H__ */ diff --git a/third_party/lib/acpica/source/include/acmacros.h b/third_party/lib/acpica/source/include/acmacros.h new file mode 100644 index 000000000..139341292 --- /dev/null +++ b/third_party/lib/acpica/source/include/acmacros.h @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * Name: acmacros.h - C macros for the entire subsystem. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACMACROS_H__ +#define __ACMACROS_H__ + + +/* + * Extract data using a pointer. Any more than a byte and we + * get into potential aligment issues -- see the STORE macros below. + * Use with care. + */ +#define ACPI_CAST8(ptr) ACPI_CAST_PTR (UINT8, (ptr)) +#define ACPI_CAST16(ptr) ACPI_CAST_PTR (UINT16, (ptr)) +#define ACPI_CAST32(ptr) ACPI_CAST_PTR (UINT32, (ptr)) +#define ACPI_CAST64(ptr) ACPI_CAST_PTR (UINT64, (ptr)) +#define ACPI_GET8(ptr) (*ACPI_CAST8 (ptr)) +#define ACPI_GET16(ptr) (*ACPI_CAST16 (ptr)) +#define ACPI_GET32(ptr) (*ACPI_CAST32 (ptr)) +#define ACPI_GET64(ptr) (*ACPI_CAST64 (ptr)) +#define ACPI_SET8(ptr, val) (*ACPI_CAST8 (ptr) = (UINT8) (val)) +#define ACPI_SET16(ptr, val) (*ACPI_CAST16 (ptr) = (UINT16) (val)) +#define ACPI_SET32(ptr, val) (*ACPI_CAST32 (ptr) = (UINT32) (val)) +#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (UINT64) (val)) + +/* + * printf() format helper. This macros is a workaround for the difficulties + * with emitting 64-bit integers and 64-bit pointers with the same code + * for both 32-bit and 64-bit hosts. + */ +#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i) + + +/* + * Macros for moving data around to/from buffers that are possibly unaligned. + * If the hardware supports the transfer of unaligned data, just do the store. + * Otherwise, we have to move one byte at a time. + */ +#ifdef ACPI_BIG_ENDIAN +/* + * Macros for big-endian machines + */ + +/* These macros reverse the bytes during the move, converting little-endian to big endian */ + + /* Big Endian <== Little Endian */ + /* Hi...Lo Lo...Hi */ +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[0];} + +#define ACPI_MOVE_16_TO_32(d, s) {(*(UINT32 *)(void *)(d))=0;\ + ((UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[1];\ + ((UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[0];} + +#define ACPI_MOVE_16_TO_64(d, s) {(*(UINT64 *)(void *)(d))=0;\ + ((UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[1];\ + ((UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[0];} + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_32_TO_32(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[3];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[0];} + +#define ACPI_MOVE_32_TO_64(d, s) {(*(UINT64 *)(void *)(d))=0;\ + ((UINT8 *)(void *)(d))[4] = ((UINT8 *)(void *)(s))[3];\ + ((UINT8 *)(void *)(d))[5] = ((UINT8 *)(void *)(s))[2];\ + ((UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[1];\ + ((UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[0];} + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ + +#define ACPI_MOVE_64_TO_64(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[7];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[6];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[5];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[4];\ + (( UINT8 *)(void *)(d))[4] = ((UINT8 *)(void *)(s))[3];\ + (( UINT8 *)(void *)(d))[5] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[0];} +#else +/* + * Macros for little-endian machines + */ + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED + +/* The hardware supports unaligned transfers, just do the little-endian move */ + +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) *(UINT16 *)(void *)(d) = *(UINT16 *)(void *)(s) +#define ACPI_MOVE_16_TO_32(d, s) *(UINT32 *)(void *)(d) = *(UINT16 *)(void *)(s) +#define ACPI_MOVE_16_TO_64(d, s) *(UINT64 *)(void *)(d) = *(UINT16 *)(void *)(s) + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_32_TO_32(d, s) *(UINT32 *)(void *)(d) = *(UINT32 *)(void *)(s) +#define ACPI_MOVE_32_TO_64(d, s) *(UINT64 *)(void *)(d) = *(UINT32 *)(void *)(s) + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ +#define ACPI_MOVE_64_TO_64(d, s) *(UINT64 *)(void *)(d) = *(UINT64 *)(void *)(s) + +#else +/* + * The hardware does not support unaligned transfers. We must move the + * data one byte at a time. These macros work whether the source or + * the destination (or both) is/are unaligned. (Little-endian move) + */ + +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[0];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[1];} + +#define ACPI_MOVE_16_TO_32(d, s) {(*(UINT32 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} +#define ACPI_MOVE_16_TO_64(d, s) {(*(UINT64 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_32_TO_32(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[0];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[3];} + +#define ACPI_MOVE_32_TO_64(d, s) {(*(UINT64 *)(void *)(d)) = 0; ACPI_MOVE_32_TO_32(d, s);} + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ +#define ACPI_MOVE_64_TO_64(d, s) {(( UINT8 *)(void *)(d))[0] = ((UINT8 *)(void *)(s))[0];\ + (( UINT8 *)(void *)(d))[1] = ((UINT8 *)(void *)(s))[1];\ + (( UINT8 *)(void *)(d))[2] = ((UINT8 *)(void *)(s))[2];\ + (( UINT8 *)(void *)(d))[3] = ((UINT8 *)(void *)(s))[3];\ + (( UINT8 *)(void *)(d))[4] = ((UINT8 *)(void *)(s))[4];\ + (( UINT8 *)(void *)(d))[5] = ((UINT8 *)(void *)(s))[5];\ + (( UINT8 *)(void *)(d))[6] = ((UINT8 *)(void *)(s))[6];\ + (( UINT8 *)(void *)(d))[7] = ((UINT8 *)(void *)(s))[7];} +#endif +#endif + + +/* + * Fast power-of-two math macros for non-optimized compilers + */ +#define _ACPI_DIV(value, PowerOf2) ((UINT32) ((value) >> (PowerOf2))) +#define _ACPI_MUL(value, PowerOf2) ((UINT32) ((value) << (PowerOf2))) +#define _ACPI_MOD(value, Divisor) ((UINT32) ((value) & ((Divisor) -1))) + +#define ACPI_DIV_2(a) _ACPI_DIV(a, 1) +#define ACPI_MUL_2(a) _ACPI_MUL(a, 1) +#define ACPI_MOD_2(a) _ACPI_MOD(a, 2) + +#define ACPI_DIV_4(a) _ACPI_DIV(a, 2) +#define ACPI_MUL_4(a) _ACPI_MUL(a, 2) +#define ACPI_MOD_4(a) _ACPI_MOD(a, 4) + +#define ACPI_DIV_8(a) _ACPI_DIV(a, 3) +#define ACPI_MUL_8(a) _ACPI_MUL(a, 3) +#define ACPI_MOD_8(a) _ACPI_MOD(a, 8) + +#define ACPI_DIV_16(a) _ACPI_DIV(a, 4) +#define ACPI_MUL_16(a) _ACPI_MUL(a, 4) +#define ACPI_MOD_16(a) _ACPI_MOD(a, 16) + +#define ACPI_DIV_32(a) _ACPI_DIV(a, 5) +#define ACPI_MUL_32(a) _ACPI_MUL(a, 5) +#define ACPI_MOD_32(a) _ACPI_MOD(a, 32) + +/* Test for ASCII character */ + +#define ACPI_IS_ASCII(c) ((c) < 0x80) + +/* Signed integers */ + +#define ACPI_SIGN_POSITIVE 0 +#define ACPI_SIGN_NEGATIVE 1 + + +/* + * Rounding macros (Power of two boundaries only) + */ +#define ACPI_ROUND_DOWN(value, boundary) (((ACPI_SIZE)(value)) & \ + (~(((ACPI_SIZE) boundary)-1))) + +#define ACPI_ROUND_UP(value, boundary) ((((ACPI_SIZE)(value)) + \ + (((ACPI_SIZE) boundary)-1)) & \ + (~(((ACPI_SIZE) boundary)-1))) + +/* Note: sizeof(ACPI_SIZE) evaluates to either 4 or 8 (32- vs 64-bit mode) */ + +#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a, 4) +#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a, 8) +#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a, sizeof(ACPI_SIZE)) + +#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a, 4) +#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a, 8) +#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a, sizeof(ACPI_SIZE)) + +#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) +#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) + +#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) + +/* Generic (non-power-of-two) rounding */ + +#define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary)) + +#define ACPI_IS_MISALIGNED(value) (((ACPI_SIZE) value) & (sizeof(ACPI_SIZE)-1)) + +/* + * Bitmask creation + * Bit positions start at zero. + * MASK_BITS_ABOVE creates a mask starting AT the position and above + * MASK_BITS_BELOW creates a mask starting one bit BELOW the position + */ +#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_UINT64_MAX) << ((UINT32) (position)))) +#define ACPI_MASK_BITS_BELOW(position) ((ACPI_UINT64_MAX) << ((UINT32) (position))) + +/* Bitfields within ACPI registers */ + +#define ACPI_REGISTER_PREPARE_BITS(Val, Pos, Mask) \ + ((Val << Pos) & Mask) + +#define ACPI_REGISTER_INSERT_VALUE(Reg, Pos, Mask, Val) \ + Reg = (Reg & (~(Mask))) | ACPI_REGISTER_PREPARE_BITS(Val, Pos, Mask) + +#define ACPI_INSERT_BITS(Target, Mask, Source) \ + Target = ((Target & (~(Mask))) | (Source & Mask)) + +/* Generic bitfield macros and masks */ + +#define ACPI_GET_BITS(SourcePtr, Position, Mask) \ + ((*SourcePtr >> Position) & Mask) + +#define ACPI_SET_BITS(TargetPtr, Position, Mask, Value) \ + (*TargetPtr |= ((Value & Mask) << Position)) + +#define ACPI_1BIT_MASK 0x00000001 +#define ACPI_2BIT_MASK 0x00000003 +#define ACPI_3BIT_MASK 0x00000007 +#define ACPI_4BIT_MASK 0x0000000F +#define ACPI_5BIT_MASK 0x0000001F +#define ACPI_6BIT_MASK 0x0000003F +#define ACPI_7BIT_MASK 0x0000007F +#define ACPI_8BIT_MASK 0x000000FF +#define ACPI_16BIT_MASK 0x0000FFFF +#define ACPI_24BIT_MASK 0x00FFFFFF + +/* Macros to extract flag bits from position zero */ + +#define ACPI_GET_1BIT_FLAG(Value) ((Value) & ACPI_1BIT_MASK) +#define ACPI_GET_2BIT_FLAG(Value) ((Value) & ACPI_2BIT_MASK) +#define ACPI_GET_3BIT_FLAG(Value) ((Value) & ACPI_3BIT_MASK) +#define ACPI_GET_4BIT_FLAG(Value) ((Value) & ACPI_4BIT_MASK) + +/* Macros to extract flag bits from position one and above */ + +#define ACPI_EXTRACT_1BIT_FLAG(Field, Position) (ACPI_GET_1BIT_FLAG ((Field) >> Position)) +#define ACPI_EXTRACT_2BIT_FLAG(Field, Position) (ACPI_GET_2BIT_FLAG ((Field) >> Position)) +#define ACPI_EXTRACT_3BIT_FLAG(Field, Position) (ACPI_GET_3BIT_FLAG ((Field) >> Position)) +#define ACPI_EXTRACT_4BIT_FLAG(Field, Position) (ACPI_GET_4BIT_FLAG ((Field) >> Position)) + +/* ACPI Pathname helpers */ + +#define ACPI_IS_ROOT_PREFIX(c) ((c) == (UINT8) 0x5C) /* Backslash */ +#define ACPI_IS_PARENT_PREFIX(c) ((c) == (UINT8) 0x5E) /* Carat */ +#define ACPI_IS_PATH_SEPARATOR(c) ((c) == (UINT8) 0x2E) /* Period (dot) */ + +/* + * An object of type ACPI_NAMESPACE_NODE can appear in some contexts + * where a pointer to an object of type ACPI_OPERAND_OBJECT can also + * appear. This macro is used to distinguish them. + * + * The "DescriptorType" field is the second field in both structures. + */ +#define ACPI_GET_DESCRIPTOR_PTR(d) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.CommonPointer) +#define ACPI_SET_DESCRIPTOR_PTR(d, p) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.CommonPointer = (p)) +#define ACPI_GET_DESCRIPTOR_TYPE(d) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.DescriptorType) +#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((ACPI_DESCRIPTOR *)(void *)(d))->Common.DescriptorType = (t)) + +/* + * Macros for the master AML opcode table + */ +#if defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT) +#define ACPI_OP(Name, PArgs, IArgs, ObjType, Class, Type, Flags) \ + {Name, (UINT32)(PArgs), (UINT32)(IArgs), (UINT32)(Flags), ObjType, Class, Type} +#else +#define ACPI_OP(Name, PArgs, IArgs, ObjType, Class, Type, Flags) \ + {(UINT32)(PArgs), (UINT32)(IArgs), (UINT32)(Flags), ObjType, Class, Type} +#endif + +#define ARG_TYPE_WIDTH 5 +#define ARG_1(x) ((UINT32)(x)) +#define ARG_2(x) ((UINT32)(x) << (1 * ARG_TYPE_WIDTH)) +#define ARG_3(x) ((UINT32)(x) << (2 * ARG_TYPE_WIDTH)) +#define ARG_4(x) ((UINT32)(x) << (3 * ARG_TYPE_WIDTH)) +#define ARG_5(x) ((UINT32)(x) << (4 * ARG_TYPE_WIDTH)) +#define ARG_6(x) ((UINT32)(x) << (5 * ARG_TYPE_WIDTH)) + +#define ARGI_LIST1(a) (ARG_1(a)) +#define ARGI_LIST2(a, b) (ARG_1(b)|ARG_2(a)) +#define ARGI_LIST3(a, b, c) (ARG_1(c)|ARG_2(b)|ARG_3(a)) +#define ARGI_LIST4(a, b, c, d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a)) +#define ARGI_LIST5(a, b, c, d, e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a)) +#define ARGI_LIST6(a, b, c, d, e, f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a)) + +#define ARGP_LIST1(a) (ARG_1(a)) +#define ARGP_LIST2(a, b) (ARG_1(a)|ARG_2(b)) +#define ARGP_LIST3(a, b, c) (ARG_1(a)|ARG_2(b)|ARG_3(c)) +#define ARGP_LIST4(a, b, c, d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)) +#define ARGP_LIST5(a, b, c, d, e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)) +#define ARGP_LIST6(a, b, c, d, e, f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f)) + +#define GET_CURRENT_ARG_TYPE(List) (List & ((UINT32) 0x1F)) +#define INCREMENT_ARG_LIST(List) (List >>= ((UINT32) ARG_TYPE_WIDTH)) + +/* + * Ascii error messages can be configured out + */ +#ifndef ACPI_NO_ERROR_MESSAGES +/* + * Error reporting. Callers module and line number are inserted by AE_INFO, + * the plist contains a set of parens to allow variable-length lists. + * These macros are used for both the debug and non-debug versions of the code. + */ +#define ACPI_ERROR_NAMESPACE(s, e) AcpiUtNamespaceError (AE_INFO, s, e); +#define ACPI_ERROR_METHOD(s, n, p, e) AcpiUtMethodError (AE_INFO, s, n, p, e); +#define ACPI_WARN_PREDEFINED(plist) AcpiUtPredefinedWarning plist +#define ACPI_INFO_PREDEFINED(plist) AcpiUtPredefinedInfo plist +#define ACPI_BIOS_ERROR_PREDEFINED(plist) AcpiUtPredefinedBiosError plist + +#else + +/* No error messages */ + +#define ACPI_ERROR_NAMESPACE(s, e) +#define ACPI_ERROR_METHOD(s, n, p, e) +#define ACPI_WARN_PREDEFINED(plist) +#define ACPI_INFO_PREDEFINED(plist) +#define ACPI_BIOS_ERROR_PREDEFINED(plist) + +#endif /* ACPI_NO_ERROR_MESSAGES */ + +#if (!ACPI_REDUCED_HARDWARE) +#define ACPI_HW_OPTIONAL_FUNCTION(addr) addr +#else +#define ACPI_HW_OPTIONAL_FUNCTION(addr) NULL +#endif + + +/* + * Macros used for ACPICA utilities only + */ + +/* Generate a UUID */ + +#define ACPI_INIT_UUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + (a) & 0xFF, ((a) >> 8) & 0xFF, ((a) >> 16) & 0xFF, ((a) >> 24) & 0xFF, \ + (b) & 0xFF, ((b) >> 8) & 0xFF, \ + (c) & 0xFF, ((c) >> 8) & 0xFF, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) + +#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) + + +#endif /* ACMACROS_H */ diff --git a/third_party/lib/acpica/source/include/acnames.h b/third_party/lib/acpica/source/include/acnames.h new file mode 100644 index 000000000..4710323e0 --- /dev/null +++ b/third_party/lib/acpica/source/include/acnames.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Name: acnames.h - Global names and strings + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACNAMES_H__ +#define __ACNAMES_H__ + +/* Method names - these methods can appear anywhere in the namespace */ + +#define METHOD_NAME__ADR "_ADR" +#define METHOD_NAME__AEI "_AEI" +#define METHOD_NAME__BBN "_BBN" +#define METHOD_NAME__CBA "_CBA" +#define METHOD_NAME__CID "_CID" +#define METHOD_NAME__CLS "_CLS" +#define METHOD_NAME__CRS "_CRS" +#define METHOD_NAME__DDN "_DDN" +#define METHOD_NAME__HID "_HID" +#define METHOD_NAME__INI "_INI" +#define METHOD_NAME__PLD "_PLD" +#define METHOD_NAME__DSD "_DSD" +#define METHOD_NAME__PRS "_PRS" +#define METHOD_NAME__PRT "_PRT" +#define METHOD_NAME__PRW "_PRW" +#define METHOD_NAME__PS0 "_PS0" +#define METHOD_NAME__PS1 "_PS1" +#define METHOD_NAME__PS2 "_PS2" +#define METHOD_NAME__PS3 "_PS3" +#define METHOD_NAME__REG "_REG" +#define METHOD_NAME__SB_ "_SB_" +#define METHOD_NAME__SEG "_SEG" +#define METHOD_NAME__SRS "_SRS" +#define METHOD_NAME__STA "_STA" +#define METHOD_NAME__SUB "_SUB" +#define METHOD_NAME__UID "_UID" + +/* Method names - these methods must appear at the namespace root */ + +#define METHOD_PATHNAME__PTS "\\_PTS" +#define METHOD_PATHNAME__SST "\\_SI._SST" +#define METHOD_PATHNAME__WAK "\\_WAK" + +/* Definitions of the predefined namespace names */ + +#define ACPI_UNKNOWN_NAME (UINT32) 0x3F3F3F3F /* Unknown name is "????" */ +#define ACPI_ROOT_NAME (UINT32) 0x5F5F5F5C /* Root name is "\___" */ + +#define ACPI_PREFIX_MIXED (UINT32) 0x69706341 /* "Acpi" */ +#define ACPI_PREFIX_LOWER (UINT32) 0x69706361 /* "acpi" */ + +#define ACPI_NS_ROOT_PATH "\\" + +#endif /* __ACNAMES_H__ */ diff --git a/third_party/lib/acpica/source/include/acnamesp.h b/third_party/lib/acpica/source/include/acnamesp.h new file mode 100644 index 000000000..492f18720 --- /dev/null +++ b/third_party/lib/acpica/source/include/acnamesp.h @@ -0,0 +1,555 @@ +/****************************************************************************** + * + * Name: acnamesp.h - Namespace subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACNAMESP_H__ +#define __ACNAMESP_H__ + + +/* To search the entire name space, pass this as SearchBase */ + +#define ACPI_NS_ALL ((ACPI_HANDLE)0) + +/* + * Elements of AcpiNsProperties are bit significant + * and should be one-to-one with values of ACPI_OBJECT_TYPE + */ +#define ACPI_NS_NORMAL 0 +#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */ +#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */ + +/* Flags for AcpiNsLookup, AcpiNsSearchAndEnter */ + +#define ACPI_NS_NO_UPSEARCH 0 +#define ACPI_NS_SEARCH_PARENT 0x01 +#define ACPI_NS_DONT_OPEN_SCOPE 0x02 +#define ACPI_NS_NO_PEER_SEARCH 0x04 +#define ACPI_NS_ERROR_IF_FOUND 0x08 +#define ACPI_NS_PREFIX_IS_SCOPE 0x10 +#define ACPI_NS_EXTERNAL 0x20 +#define ACPI_NS_TEMPORARY 0x40 +#define ACPI_NS_OVERRIDE_IF_FOUND 0x80 + +/* Flags for AcpiNsWalkNamespace */ + +#define ACPI_NS_WALK_NO_UNLOCK 0 +#define ACPI_NS_WALK_UNLOCK 0x01 +#define ACPI_NS_WALK_TEMP_NODES 0x02 + +/* Object is not a package element */ + +#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX +#define ACPI_ALL_PACKAGE_ELEMENTS (ACPI_UINT32_MAX-1) + +/* Always emit warning message, not dependent on node flags */ + +#define ACPI_WARN_ALWAYS 0 + + +/* + * nsinit - Namespace initialization + */ +ACPI_STATUS +AcpiNsInitializeObjects ( + void); + +ACPI_STATUS +AcpiNsInitializeDevices ( + void); + + +/* + * nsload - Namespace loading + */ +ACPI_STATUS +AcpiNsLoadNamespace ( + void); + +ACPI_STATUS +AcpiNsLoadTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *Node); + + +/* + * nswalk - walk the namespace + */ +ACPI_STATUS +AcpiNsWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + UINT32 Flags, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue); + +ACPI_NAMESPACE_NODE * +AcpiNsGetNextNode ( + ACPI_NAMESPACE_NODE *Parent, + ACPI_NAMESPACE_NODE *Child); + +ACPI_NAMESPACE_NODE * +AcpiNsGetNextNodeTyped ( + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE *Parent, + ACPI_NAMESPACE_NODE *Child); + +/* + * nsparse - table parsing + */ +ACPI_STATUS +AcpiNsParseTable ( + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + +ACPI_STATUS +AcpiNsOneCompleteParse ( + UINT32 PassNumber, + UINT32 TableIndex, + ACPI_NAMESPACE_NODE *StartNode); + + +/* + * nsaccess - Top-level namespace access + */ +ACPI_STATUS +AcpiNsRootInitialize ( + void); + +ACPI_STATUS +AcpiNsLookup ( + ACPI_GENERIC_STATE *ScopeInfo, + char *Name, + ACPI_OBJECT_TYPE Type, + ACPI_INTERPRETER_MODE InterpreterMode, + UINT32 Flags, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE **RetNode); + + +/* + * nsalloc - Named object allocation/deallocation + */ +ACPI_NAMESPACE_NODE * +AcpiNsCreateNode ( + UINT32 Name); + +void +AcpiNsDeleteNode ( + ACPI_NAMESPACE_NODE *Node); + +void +AcpiNsRemoveNode ( + ACPI_NAMESPACE_NODE *Node); + +void +AcpiNsDeleteNamespaceSubtree ( + ACPI_NAMESPACE_NODE *ParentHandle); + +void +AcpiNsDeleteNamespaceByOwner ( + ACPI_OWNER_ID OwnerId); + +void +AcpiNsDetachObject ( + ACPI_NAMESPACE_NODE *Node); + +void +AcpiNsDeleteChildren ( + ACPI_NAMESPACE_NODE *Parent); + +int +AcpiNsCompareNames ( + char *Name1, + char *Name2); + + +/* + * nsconvert - Dynamic object conversion routines + */ +ACPI_STATUS +AcpiNsConvertToInteger ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToString ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToBuffer ( + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToUnicode ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToResource ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsConvertToReference ( + ACPI_NAMESPACE_NODE *Scope, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ReturnObject); + + +/* + * nsdump - Namespace dump/print utilities + */ +void +AcpiNsDumpTables ( + ACPI_HANDLE SearchBase, + UINT32 MaxDepth); + +void +AcpiNsDumpEntry ( + ACPI_HANDLE Handle, + UINT32 DebugLevel); + +void +AcpiNsDumpPathname ( + ACPI_HANDLE Handle, + char *Msg, + UINT32 Level, + UINT32 Component); + +void +AcpiNsPrintPathname ( + UINT32 NumSegments, + char *Pathname); + +ACPI_STATUS +AcpiNsDumpOneObject ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +void +AcpiNsDumpObjects ( + ACPI_OBJECT_TYPE Type, + UINT8 DisplayType, + UINT32 MaxDepth, + ACPI_OWNER_ID OwnerId, + ACPI_HANDLE StartHandle); + +void +AcpiNsDumpObjectPaths ( + ACPI_OBJECT_TYPE Type, + UINT8 DisplayType, + UINT32 MaxDepth, + ACPI_OWNER_ID OwnerId, + ACPI_HANDLE StartHandle); + + +/* + * nseval - Namespace evaluation functions + */ +ACPI_STATUS +AcpiNsEvaluate ( + ACPI_EVALUATE_INFO *Info); + +void +AcpiNsExecModuleCodeList ( + void); + + +/* + * nsarguments - Argument count/type checking for predefined/reserved names + */ +void +AcpiNsCheckArgumentCount ( + char *Pathname, + ACPI_NAMESPACE_NODE *Node, + UINT32 UserParamCount, + const ACPI_PREDEFINED_INFO *Info); + +void +AcpiNsCheckAcpiCompliance ( + char *Pathname, + ACPI_NAMESPACE_NODE *Node, + const ACPI_PREDEFINED_INFO *Predefined); + +void +AcpiNsCheckArgumentTypes ( + ACPI_EVALUATE_INFO *Info); + + +/* + * nspredef - Return value checking for predefined/reserved names + */ +ACPI_STATUS +AcpiNsCheckReturnValue ( + ACPI_NAMESPACE_NODE *Node, + ACPI_EVALUATE_INFO *Info, + UINT32 UserParamCount, + ACPI_STATUS ReturnStatus, + ACPI_OPERAND_OBJECT **ReturnObject); + +ACPI_STATUS +AcpiNsCheckObjectType ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr, + UINT32 ExpectedBtypes, + UINT32 PackageIndex); + + +/* + * nsprepkg - Validation of predefined name packages + */ +ACPI_STATUS +AcpiNsCheckPackage ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + + +/* + * nsnames - Name and Scope manipulation + */ +UINT32 +AcpiNsOpensScope ( + ACPI_OBJECT_TYPE Type); + +char * +AcpiNsGetExternalPathname ( + ACPI_NAMESPACE_NODE *Node); + +UINT32 +AcpiNsBuildNormalizedPath ( + ACPI_NAMESPACE_NODE *Node, + char *FullPath, + UINT32 PathSize, + BOOLEAN NoTrailing); + +char * +AcpiNsGetNormalizedPathname ( + ACPI_NAMESPACE_NODE *Node, + BOOLEAN NoTrailing); + +char * +AcpiNsNameOfCurrentScope ( + ACPI_WALK_STATE *WalkState); + +ACPI_STATUS +AcpiNsHandleToPathname ( + ACPI_HANDLE TargetHandle, + ACPI_BUFFER *Buffer, + BOOLEAN NoTrailing); + +BOOLEAN +AcpiNsPatternMatch ( + ACPI_NAMESPACE_NODE *ObjNode, + char *SearchFor); + +ACPI_STATUS +AcpiNsGetNode ( + ACPI_NAMESPACE_NODE *PrefixNode, + const char *ExternalPathname, + UINT32 Flags, + ACPI_NAMESPACE_NODE **OutNode); + +ACPI_SIZE +AcpiNsGetPathnameLength ( + ACPI_NAMESPACE_NODE *Node); + + +/* + * nsobject - Object management for namespace nodes + */ +ACPI_STATUS +AcpiNsAttachObject ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *Object, + ACPI_OBJECT_TYPE Type); + +ACPI_OPERAND_OBJECT * +AcpiNsGetAttachedObject ( + ACPI_NAMESPACE_NODE *Node); + +ACPI_OPERAND_OBJECT * +AcpiNsGetSecondaryObject ( + ACPI_OPERAND_OBJECT *ObjDesc); + +ACPI_STATUS +AcpiNsAttachData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler, + void *Data); + +ACPI_STATUS +AcpiNsDetachData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler); + +ACPI_STATUS +AcpiNsGetAttachedData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_HANDLER Handler, + void **Data); + + +/* + * nsrepair - General return object repair for all + * predefined methods/objects + */ +ACPI_STATUS +AcpiNsSimpleRepair ( + ACPI_EVALUATE_INFO *Info, + UINT32 ExpectedBtypes, + UINT32 PackageIndex, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +ACPI_STATUS +AcpiNsWrapWithPackage ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *OriginalObject, + ACPI_OPERAND_OBJECT **ObjDescPtr); + +ACPI_STATUS +AcpiNsRepairNullElement ( + ACPI_EVALUATE_INFO *Info, + UINT32 ExpectedBtypes, + UINT32 PackageIndex, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +void +AcpiNsRemoveNullElements ( + ACPI_EVALUATE_INFO *Info, + UINT8 PackageType, + ACPI_OPERAND_OBJECT *ObjDesc); + + +/* + * nsrepair2 - Return object repair for specific + * predefined methods/objects + */ +ACPI_STATUS +AcpiNsComplexRepairs ( + ACPI_EVALUATE_INFO *Info, + ACPI_NAMESPACE_NODE *Node, + ACPI_STATUS ValidateStatus, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + + +/* + * nssearch - Namespace searching and entry + */ +ACPI_STATUS +AcpiNsSearchAndEnter ( + UINT32 EntryName, + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *Node, + ACPI_INTERPRETER_MODE InterpreterMode, + ACPI_OBJECT_TYPE Type, + UINT32 Flags, + ACPI_NAMESPACE_NODE **RetNode); + +ACPI_STATUS +AcpiNsSearchOneScope ( + UINT32 EntryName, + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type, + ACPI_NAMESPACE_NODE **RetNode); + +void +AcpiNsInstallNode ( + ACPI_WALK_STATE *WalkState, + ACPI_NAMESPACE_NODE *ParentNode, + ACPI_NAMESPACE_NODE *Node, + ACPI_OBJECT_TYPE Type); + + +/* + * nsutils - Utility functions + */ +ACPI_OBJECT_TYPE +AcpiNsGetType ( + ACPI_NAMESPACE_NODE *Node); + +UINT32 +AcpiNsLocal ( + ACPI_OBJECT_TYPE Type); + +void +AcpiNsPrintNodePathname ( + ACPI_NAMESPACE_NODE *Node, + const char *Msg); + +ACPI_STATUS +AcpiNsBuildInternalName ( + ACPI_NAMESTRING_INFO *Info); + +void +AcpiNsGetInternalNameLength ( + ACPI_NAMESTRING_INFO *Info); + +ACPI_STATUS +AcpiNsInternalizeName ( + const char *DottedName, + char **ConvertedName); + +ACPI_STATUS +AcpiNsExternalizeName ( + UINT32 InternalNameLength, + const char *InternalName, + UINT32 *ConvertedNameLength, + char **ConvertedName); + +ACPI_NAMESPACE_NODE * +AcpiNsValidateHandle ( + ACPI_HANDLE Handle); + +void +AcpiNsTerminate ( + void); + +#endif /* __ACNAMESP_H__ */ diff --git a/third_party/lib/acpica/source/include/acobject.h b/third_party/lib/acpica/source/include/acobject.h new file mode 100644 index 000000000..83f29ec3c --- /dev/null +++ b/third_party/lib/acpica/source/include/acobject.h @@ -0,0 +1,591 @@ +/****************************************************************************** + * + * Name: acobject.h - Definition of ACPI_OPERAND_OBJECT (Internal object only) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACOBJECT_H +#define _ACOBJECT_H + +/* acpisrc:StructDefs -- for acpisrc conversion */ + + +/* + * The ACPI_OPERAND_OBJECT is used to pass AML operands from the dispatcher + * to the interpreter, and to keep track of the various handlers such as + * address space handlers and notify handlers. The object is a constant + * size in order to allow it to be cached and reused. + * + * Note: The object is optimized to be aligned and will not work if it is + * byte-packed. + */ +#if ACPI_MACHINE_WIDTH == 64 +#pragma pack(8) +#else +#pragma pack(4) +#endif + +/******************************************************************************* + * + * Common Descriptors + * + ******************************************************************************/ + +/* + * Common area for all objects. + * + * DescriptorType is used to differentiate between internal descriptors, and + * must be in the same place across all descriptors + * + * Note: The DescriptorType and Type fields must appear in the identical + * position in both the ACPI_NAMESPACE_NODE and ACPI_OPERAND_OBJECT + * structures. + */ +#define ACPI_OBJECT_COMMON_HEADER \ + union acpi_operand_object *NextObject; /* Objects linked to parent NS node */\ + UINT8 DescriptorType; /* To differentiate various internal objs */\ + UINT8 Type; /* ACPI_OBJECT_TYPE */\ + UINT16 ReferenceCount; /* For object deletion management */\ + UINT8 Flags; + /* + * Note: There are 3 bytes available here before the + * next natural alignment boundary (for both 32/64 cases) + */ + +/* Values for Flag byte above */ + +#define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */ +#define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */ +#define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */ +#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized */ +#define AOPOBJ_REG_CONNECTED 0x10 /* _REG was run */ +#define AOPOBJ_SETUP_COMPLETE 0x20 /* Region setup is complete */ +#define AOPOBJ_INVALID 0x40 /* Host OS won't allow a Region address */ + + +/****************************************************************************** + * + * Basic data types + * + *****************************************************************************/ + +typedef struct acpi_object_common +{ + ACPI_OBJECT_COMMON_HEADER + +} ACPI_OBJECT_COMMON; + + +typedef struct acpi_object_integer +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 Fill[3]; /* Prevent warning on some compilers */ + UINT64 Value; + +} ACPI_OBJECT_INTEGER; + + +/* + * Note: The String and Buffer object must be identical through the + * pointer and length elements. There is code that depends on this. + * + * Fields common to both Strings and Buffers + */ +#define ACPI_COMMON_BUFFER_INFO(_Type) \ + _Type *Pointer; \ + UINT32 Length; + + +typedef struct acpi_object_string /* Null terminated, ASCII characters only */ +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_BUFFER_INFO (char) /* String in AML stream or allocated string */ + +} ACPI_OBJECT_STRING; + + +typedef struct acpi_object_buffer +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_BUFFER_INFO (UINT8) /* Buffer in AML stream or allocated buffer */ + UINT32 AmlLength; + UINT8 *AmlStart; + ACPI_NAMESPACE_NODE *Node; /* Link back to parent node */ + +} ACPI_OBJECT_BUFFER; + + +typedef struct acpi_object_package +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_NAMESPACE_NODE *Node; /* Link back to parent node */ + union acpi_operand_object **Elements; /* Array of pointers to AcpiObjects */ + UINT8 *AmlStart; + UINT32 AmlLength; + UINT32 Count; /* # of elements in package */ + +} ACPI_OBJECT_PACKAGE; + + +/****************************************************************************** + * + * Complex data types + * + *****************************************************************************/ + +typedef struct acpi_object_event +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_SEMAPHORE OsSemaphore; /* Actual OS synchronization object */ + +} ACPI_OBJECT_EVENT; + + +typedef struct acpi_object_mutex +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 SyncLevel; /* 0-15, specified in Mutex() call */ + UINT16 AcquisitionDepth; /* Allow multiple Acquires, same thread */ + ACPI_MUTEX OsMutex; /* Actual OS synchronization object */ + ACPI_THREAD_ID ThreadId; /* Current owner of the mutex */ + struct acpi_thread_state *OwnerThread; /* Current owner of the mutex */ + union acpi_operand_object *Prev; /* Link for list of acquired mutexes */ + union acpi_operand_object *Next; /* Link for list of acquired mutexes */ + ACPI_NAMESPACE_NODE *Node; /* Containing namespace node */ + UINT8 OriginalSyncLevel; /* Owner's original sync level (0-15) */ + +} ACPI_OBJECT_MUTEX; + + +typedef struct acpi_object_region +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 SpaceId; + ACPI_NAMESPACE_NODE *Node; /* Containing namespace node */ + union acpi_operand_object *Handler; /* Handler for region access */ + union acpi_operand_object *Next; + ACPI_PHYSICAL_ADDRESS Address; + UINT32 Length; + +} ACPI_OBJECT_REGION; + + +typedef struct acpi_object_method +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 InfoFlags; + UINT8 ParamCount; + UINT8 SyncLevel; + union acpi_operand_object *Mutex; + union acpi_operand_object *Node; + UINT8 *AmlStart; + union + { + ACPI_INTERNAL_METHOD Implementation; + union acpi_operand_object *Handler; + } Dispatch; + + UINT32 AmlLength; + UINT8 ThreadCount; + ACPI_OWNER_ID OwnerId; + +} ACPI_OBJECT_METHOD; + +/* Flags for InfoFlags field above */ + +#define ACPI_METHOD_MODULE_LEVEL 0x01 /* Method is actually module-level code */ +#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */ +#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */ +#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */ +#define ACPI_METHOD_IGNORE_SYNC_LEVEL 0x10 /* Method was auto-serialized at table load time */ +#define ACPI_METHOD_MODIFIED_NAMESPACE 0x20 /* Method modified the namespace */ + + +/****************************************************************************** + * + * Objects that can be notified. All share a common NotifyInfo area. + * + *****************************************************************************/ + +/* + * Common fields for objects that support ASL notifications + */ +#define ACPI_COMMON_NOTIFY_INFO \ + union acpi_operand_object *NotifyList[2]; /* Handlers for system/device notifies */\ + union acpi_operand_object *Handler; /* Handler for Address space */ + + +typedef struct acpi_object_notify_common /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + +} ACPI_OBJECT_NOTIFY_COMMON; + + +typedef struct acpi_object_device +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + ACPI_GPE_BLOCK_INFO *GpeBlock; + +} ACPI_OBJECT_DEVICE; + + +typedef struct acpi_object_power_resource +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + UINT32 SystemLevel; + UINT32 ResourceOrder; + +} ACPI_OBJECT_POWER_RESOURCE; + + +typedef struct acpi_object_processor +{ + ACPI_OBJECT_COMMON_HEADER + + /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */ + + UINT8 ProcId; + UINT8 Length; + ACPI_COMMON_NOTIFY_INFO + ACPI_IO_ADDRESS Address; + +} ACPI_OBJECT_PROCESSOR; + + +typedef struct acpi_object_thermal_zone +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + +} ACPI_OBJECT_THERMAL_ZONE; + + +/****************************************************************************** + * + * Fields. All share a common header/info field. + * + *****************************************************************************/ + +/* + * Common bitfield for the field objects + * "Field Datum" -- a datum from the actual field object + * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field + */ +#define ACPI_COMMON_FIELD_INFO \ + UINT8 FieldFlags; /* Access, update, and lock bits */\ + UINT8 Attribute; /* From AccessAs keyword */\ + UINT8 AccessByteWidth; /* Read/Write size in bytes */\ + ACPI_NAMESPACE_NODE *Node; /* Link back to parent node */\ + UINT32 BitLength; /* Length of field in bits */\ + UINT32 BaseByteOffset; /* Byte offset within containing object */\ + UINT32 Value; /* Value to store into the Bank or Index register */\ + UINT8 StartFieldBitOffset;/* Bit offset within first field datum (0-63) */\ + UINT8 AccessLength; /* For serial regions/fields */ + + +typedef struct acpi_object_field_common /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + union acpi_operand_object *RegionObj; /* Parent Operation Region object (REGION/BANK fields only) */ + +} ACPI_OBJECT_FIELD_COMMON; + + +typedef struct acpi_object_region_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + UINT16 ResourceLength; + union acpi_operand_object *RegionObj; /* Containing OpRegion object */ + UINT8 *ResourceBuffer; /* ResourceTemplate for serial regions/fields */ + UINT16 PinNumberIndex; /* Index relative to previous Connection/Template */ + +} ACPI_OBJECT_REGION_FIELD; + + +typedef struct acpi_object_bank_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + union acpi_operand_object *RegionObj; /* Containing OpRegion object */ + union acpi_operand_object *BankObj; /* BankSelect Register object */ + +} ACPI_OBJECT_BANK_FIELD; + + +typedef struct acpi_object_index_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + + /* + * No "RegionObj" pointer needed since the Index and Data registers + * are each field definitions unto themselves. + */ + union acpi_operand_object *IndexObj; /* Index register */ + union acpi_operand_object *DataObj; /* Data register */ + +} ACPI_OBJECT_INDEX_FIELD; + + +/* The BufferField is different in that it is part of a Buffer, not an OpRegion */ + +typedef struct acpi_object_buffer_field +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_FIELD_INFO + union acpi_operand_object *BufferObj; /* Containing Buffer object */ + +} ACPI_OBJECT_BUFFER_FIELD; + + +/****************************************************************************** + * + * Objects for handlers + * + *****************************************************************************/ + +typedef struct acpi_object_notify_handler +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_NAMESPACE_NODE *Node; /* Parent device */ + UINT32 HandlerType; /* Type: Device/System/Both */ + ACPI_NOTIFY_HANDLER Handler; /* Handler address */ + void *Context; + union acpi_operand_object *Next[2]; /* Device and System handler lists */ + +} ACPI_OBJECT_NOTIFY_HANDLER; + + +typedef struct acpi_object_addr_handler +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 SpaceId; + UINT8 HandlerFlags; + ACPI_ADR_SPACE_HANDLER Handler; + ACPI_NAMESPACE_NODE *Node; /* Parent device */ + void *Context; + ACPI_ADR_SPACE_SETUP Setup; + union acpi_operand_object *RegionList; /* Regions using this handler */ + union acpi_operand_object *Next; + +} ACPI_OBJECT_ADDR_HANDLER; + +/* Flags for address handler (HandlerFlags) */ + +#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01 + + +/****************************************************************************** + * + * Special internal objects + * + *****************************************************************************/ + +/* + * The Reference object is used for these opcodes: + * Arg[0-6], Local[0-7], IndexOp, NameOp, RefOfOp, LoadOp, LoadTableOp, DebugOp + * The Reference.Class differentiates these types. + */ +typedef struct acpi_object_reference +{ + ACPI_OBJECT_COMMON_HEADER + UINT8 Class; /* Reference Class */ + UINT8 TargetType; /* Used for Index Op */ + UINT8 Reserved; + void *Object; /* NameOp=>HANDLE to obj, IndexOp=>ACPI_OPERAND_OBJECT */ + ACPI_NAMESPACE_NODE *Node; /* RefOf or Namepath */ + union acpi_operand_object **Where; /* Target of Index */ + UINT8 *IndexPointer; /* Used for Buffers and Strings */ + UINT32 Value; /* Used for Local/Arg/Index/DdbHandle */ + +} ACPI_OBJECT_REFERENCE; + +/* Values for Reference.Class above */ + +typedef enum +{ + ACPI_REFCLASS_LOCAL = 0, /* Method local */ + ACPI_REFCLASS_ARG = 1, /* Method argument */ + ACPI_REFCLASS_REFOF = 2, /* Result of RefOf() TBD: Split to Ref/Node and Ref/OperandObj? */ + ACPI_REFCLASS_INDEX = 3, /* Result of Index() */ + ACPI_REFCLASS_TABLE = 4, /* DdbHandle - Load(), LoadTable() */ + ACPI_REFCLASS_NAME = 5, /* Reference to a named object */ + ACPI_REFCLASS_DEBUG = 6, /* Debug object */ + + ACPI_REFCLASS_MAX = 6 + +} ACPI_REFERENCE_CLASSES; + + +/* + * Extra object is used as additional storage for types that + * have AML code in their declarations (TermArgs) that must be + * evaluated at run time. + * + * Currently: Region and FieldUnit types + */ +typedef struct acpi_object_extra +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_NAMESPACE_NODE *Method_REG; /* _REG method for this region (if any) */ + ACPI_NAMESPACE_NODE *ScopeNode; + void *RegionContext; /* Region-specific data */ + UINT8 *AmlStart; + UINT32 AmlLength; + +} ACPI_OBJECT_EXTRA; + + +/* Additional data that can be attached to namespace nodes */ + +typedef struct acpi_object_data +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_OBJECT_HANDLER Handler; + void *Pointer; + +} ACPI_OBJECT_DATA; + + +/* Structure used when objects are cached for reuse */ + +typedef struct acpi_object_cache_list +{ + ACPI_OBJECT_COMMON_HEADER + union acpi_operand_object *Next; /* Link for object cache and internal lists*/ + +} ACPI_OBJECT_CACHE_LIST; + + +/****************************************************************************** + * + * ACPI_OPERAND_OBJECT Descriptor - a giant union of all of the above + * + *****************************************************************************/ + +typedef union acpi_operand_object +{ + ACPI_OBJECT_COMMON Common; + ACPI_OBJECT_INTEGER Integer; + ACPI_OBJECT_STRING String; + ACPI_OBJECT_BUFFER Buffer; + ACPI_OBJECT_PACKAGE Package; + ACPI_OBJECT_EVENT Event; + ACPI_OBJECT_METHOD Method; + ACPI_OBJECT_MUTEX Mutex; + ACPI_OBJECT_REGION Region; + ACPI_OBJECT_NOTIFY_COMMON CommonNotify; + ACPI_OBJECT_DEVICE Device; + ACPI_OBJECT_POWER_RESOURCE PowerResource; + ACPI_OBJECT_PROCESSOR Processor; + ACPI_OBJECT_THERMAL_ZONE ThermalZone; + ACPI_OBJECT_FIELD_COMMON CommonField; + ACPI_OBJECT_REGION_FIELD Field; + ACPI_OBJECT_BUFFER_FIELD BufferField; + ACPI_OBJECT_BANK_FIELD BankField; + ACPI_OBJECT_INDEX_FIELD IndexField; + ACPI_OBJECT_NOTIFY_HANDLER Notify; + ACPI_OBJECT_ADDR_HANDLER AddressSpace; + ACPI_OBJECT_REFERENCE Reference; + ACPI_OBJECT_EXTRA Extra; + ACPI_OBJECT_DATA Data; + ACPI_OBJECT_CACHE_LIST Cache; + + /* + * Add namespace node to union in order to simplify code that accepts both + * ACPI_OPERAND_OBJECTs and ACPI_NAMESPACE_NODEs. The structures share + * a common DescriptorType field in order to differentiate them. + */ + ACPI_NAMESPACE_NODE Node; + +} ACPI_OPERAND_OBJECT; + + +/****************************************************************************** + * + * ACPI_DESCRIPTOR - objects that share a common descriptor identifier + * + *****************************************************************************/ + +/* Object descriptor types */ + +#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */ +#define ACPI_DESC_TYPE_STATE 0x02 +#define ACPI_DESC_TYPE_STATE_UPDATE 0x03 +#define ACPI_DESC_TYPE_STATE_PACKAGE 0x04 +#define ACPI_DESC_TYPE_STATE_CONTROL 0x05 +#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x06 +#define ACPI_DESC_TYPE_STATE_PSCOPE 0x07 +#define ACPI_DESC_TYPE_STATE_WSCOPE 0x08 +#define ACPI_DESC_TYPE_STATE_RESULT 0x09 +#define ACPI_DESC_TYPE_STATE_NOTIFY 0x0A +#define ACPI_DESC_TYPE_STATE_THREAD 0x0B +#define ACPI_DESC_TYPE_WALK 0x0C +#define ACPI_DESC_TYPE_PARSER 0x0D +#define ACPI_DESC_TYPE_OPERAND 0x0E +#define ACPI_DESC_TYPE_NAMED 0x0F +#define ACPI_DESC_TYPE_MAX 0x0F + + +typedef struct acpi_common_descriptor +{ + void *CommonPointer; + UINT8 DescriptorType; /* To differentiate various internal objs */ + +} ACPI_COMMON_DESCRIPTOR; + +typedef union acpi_descriptor +{ + ACPI_COMMON_DESCRIPTOR Common; + ACPI_OPERAND_OBJECT Object; + ACPI_NAMESPACE_NODE Node; + ACPI_PARSE_OBJECT Op; + +} ACPI_DESCRIPTOR; + +#pragma pack() + +#endif /* _ACOBJECT_H */ diff --git a/third_party/lib/acpica/source/include/acopcode.h b/third_party/lib/acpica/source/include/acopcode.h new file mode 100644 index 000000000..a278d4a15 --- /dev/null +++ b/third_party/lib/acpica/source/include/acopcode.h @@ -0,0 +1,331 @@ +/****************************************************************************** + * + * Name: acopcode.h - AML opcode information for the AML parser and interpreter + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACOPCODE_H__ +#define __ACOPCODE_H__ + +#define MAX_EXTENDED_OPCODE 0x88 +#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) +#define MAX_INTERNAL_OPCODE +#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) + +/* Used for non-assigned opcodes */ + +#define _UNK 0x6B + +/* + * Reserved ASCII characters. Do not use any of these for + * internal opcodes, since they are used to differentiate + * name strings from AML opcodes + */ +#define _ASC 0x6C +#define _NAM 0x6C +#define _PFX 0x6D + + +/* + * All AML opcodes and the parse-time arguments for each. Used by the AML + * parser Each list is compressed into a 32-bit number and stored in the + * master opcode table (in psopcode.c). + */ +#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA) +#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME) +#define ARGP_ARG0 ARG_NONE +#define ARGP_ARG1 ARG_NONE +#define ARGP_ARG2 ARG_NONE +#define ARGP_ARG3 ARG_NONE +#define ARGP_ARG4 ARG_NONE +#define ARGP_ARG5 ARG_NONE +#define ARGP_ARG6 ARG_NONE +#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BREAK_OP ARG_NONE +#define ARGP_BREAK_POINT_OP ARG_NONE +#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) +#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) +#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_NAME_OR_REF,ARGP_TARGET) +#define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_CONTINUE_OP ARG_NONE +#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) +#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_DEBUG_OP ARG_NONE +#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) +#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) +#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) +#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) +#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) +#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_BYTEDATA) +#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) +#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) +#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) +#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LOCAL0 ARG_NONE +#define ARGP_LOCAL1 ARG_NONE +#define ARGP_LOCAL2 ARG_NONE +#define ARGP_LOCAL3 ARG_NONE +#define ARGP_LOCAL4 ARG_NONE +#define ARGP_LOCAL5 ARG_NONE +#define ARGP_LOCAL6 ARG_NONE +#define ARGP_LOCAL7 ARG_NONE +#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) +#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA) +#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ) +#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_NOOP_OP ARG_NONE +#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF) +#define ARGP_ONE_OP ARG_NONE +#define ARGP_ONES_OP ARG_NONE +#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) +#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) +#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) +#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) +#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_NAME_OR_REF) +#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_REVISION_OP ARG_NONE +#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) +#define ARGP_SERIALFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME) +#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) +#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) +#define ARGP_TIMER_OP ARG_NONE +#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) +#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) +#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) +#define ARGP_ZERO_OP ARG_NONE + + +/* + * All AML opcodes and the runtime arguments for each. Used by the AML + * interpreter Each list is compressed into a 32-bit number and stored + * in the master opcode table (in psopcode.c). + * + * (Used by PrepOperands procedure and the ASL Compiler) + */ +#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) +#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE +#define ARGI_ARG0 ARG_NONE +#define ARGI_ARG1 ARG_NONE +#define ARGI_ARG2 ARG_NONE +#define ARGI_ARG3 ARG_NONE +#define ARGI_ARG4 ARG_NONE +#define ARGI_ARG5 ARG_NONE +#define ARGI_ARG6 ARG_NONE +#define ARGI_BANK_FIELD_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BREAK_OP ARG_NONE +#define ARGI_BREAK_POINT_OP ARG_NONE +#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_BYTE_OP ARGI_INVALID_OPCODE +#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE +#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_ANYTYPE, ARGI_ANYTYPE, ARGI_TARGETREF) +#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) +#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) +#define ARGI_CONNECTFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE +#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) +#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) +#define ARGI_DEBUG_OP ARG_NONE +#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) +#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) +#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE +#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) +#define ARGI_DWORD_OP ARGI_INVALID_OPCODE +#define ARGI_ELSE_OP ARGI_INVALID_OPCODE +#define ARGI_EVENT_OP ARGI_INVALID_OPCODE +#define ARGI_EXTERNAL_OP ARGI_LIST3 (ARGI_STRING, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_IF_OP ARGI_INVALID_OPCODE +#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) +#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF) +#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) +#define ARGI_LOCAL0 ARG_NONE +#define ARGI_LOCAL1 ARG_NONE +#define ARGI_LOCAL2 ARG_NONE +#define ARGI_LOCAL3 ARG_NONE +#define ARGI_LOCAL4 ARG_NONE +#define ARGI_LOCAL5 ARG_NONE +#define ARGI_LOCAL6 ARG_NONE +#define ARGI_LOCAL7 ARG_NONE +#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER) +#define ARGI_METHOD_OP ARGI_INVALID_OPCODE +#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE +#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE +#define ARGI_NAME_OP ARGI_INVALID_OPCODE +#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE +#define ARGI_NOOP_OP ARG_NONE +#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) +#define ARGI_OBJECT_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) +#define ARGI_ONE_OP ARG_NONE +#define ARGI_ONES_OP ARG_NONE +#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE +#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE +#define ARGI_QWORD_OP ARGI_INVALID_OPCODE +#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) +#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) +#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) +#define ARGI_RETURN_OP ARGI_INVALID_OPCODE +#define ARGI_REVISION_OP ARG_NONE +#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE +#define ARGI_SERIALFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) +#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) +#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE +#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_STORE_TARGET) +#define ARGI_STRING_OP ARGI_INVALID_OPCODE +#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE +#define ARGI_TIMER_OP ARG_NONE +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) +#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) +#define ARGI_WHILE_OP ARGI_INVALID_OPCODE +#define ARGI_WORD_OP ARGI_INVALID_OPCODE +#define ARGI_ZERO_OP ARG_NONE + +#endif /* __ACOPCODE_H__ */ diff --git a/third_party/lib/acpica/source/include/acoutput.h b/third_party/lib/acpica/source/include/acoutput.h new file mode 100644 index 000000000..49dbc8630 --- /dev/null +++ b/third_party/lib/acpica/source/include/acoutput.h @@ -0,0 +1,496 @@ +/****************************************************************************** + * + * Name: acoutput.h -- debug output + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACOUTPUT_H__ +#define __ACOUTPUT_H__ + +/* + * Debug levels and component IDs. These are used to control the + * granularity of the output of the ACPI_DEBUG_PRINT macro -- on a + * per-component basis and a per-exception-type basis. + */ + +/* Component IDs are used in the global "DebugLayer" */ + +#define ACPI_UTILITIES 0x00000001 +#define ACPI_HARDWARE 0x00000002 +#define ACPI_EVENTS 0x00000004 +#define ACPI_TABLES 0x00000008 +#define ACPI_NAMESPACE 0x00000010 +#define ACPI_PARSER 0x00000020 +#define ACPI_DISPATCHER 0x00000040 +#define ACPI_EXECUTER 0x00000080 +#define ACPI_RESOURCES 0x00000100 +#define ACPI_CA_DEBUGGER 0x00000200 +#define ACPI_OS_SERVICES 0x00000400 +#define ACPI_CA_DISASSEMBLER 0x00000800 + +/* Component IDs for ACPI tools and utilities */ + +#define ACPI_COMPILER 0x00001000 +#define ACPI_TOOLS 0x00002000 +#define ACPI_EXAMPLE 0x00004000 +#define ACPI_DRIVER 0x00008000 +#define DT_COMPILER 0x00010000 +#define ASL_PREPROCESSOR 0x00020000 + +#define ACPI_ALL_COMPONENTS 0x0001FFFF +#define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS) + +/* Component IDs reserved for ACPI drivers */ + +#define ACPI_ALL_DRIVERS 0xFFFF0000 + + +/* + * Raw debug output levels, do not use these in the ACPI_DEBUG_PRINT macros + */ +#define ACPI_LV_INIT 0x00000001 +#define ACPI_LV_DEBUG_OBJECT 0x00000002 +#define ACPI_LV_INFO 0x00000004 +#define ACPI_LV_REPAIR 0x00000008 +#define ACPI_LV_TRACE_POINT 0x00000010 +#define ACPI_LV_ALL_EXCEPTIONS 0x0000001F + +/* Trace verbosity level 1 [Standard Trace Level] */ + +#define ACPI_LV_INIT_NAMES 0x00000020 +#define ACPI_LV_PARSE 0x00000040 +#define ACPI_LV_LOAD 0x00000080 +#define ACPI_LV_DISPATCH 0x00000100 +#define ACPI_LV_EXEC 0x00000200 +#define ACPI_LV_NAMES 0x00000400 +#define ACPI_LV_OPREGION 0x00000800 +#define ACPI_LV_BFIELD 0x00001000 +#define ACPI_LV_TABLES 0x00002000 +#define ACPI_LV_VALUES 0x00004000 +#define ACPI_LV_OBJECTS 0x00008000 +#define ACPI_LV_RESOURCES 0x00010000 +#define ACPI_LV_USER_REQUESTS 0x00020000 +#define ACPI_LV_PACKAGE 0x00040000 +#define ACPI_LV_VERBOSITY1 0x0007FF40 | ACPI_LV_ALL_EXCEPTIONS + +/* Trace verbosity level 2 [Function tracing and memory allocation] */ + +#define ACPI_LV_ALLOCATIONS 0x00100000 +#define ACPI_LV_FUNCTIONS 0x00200000 +#define ACPI_LV_OPTIMIZATIONS 0x00400000 +#define ACPI_LV_VERBOSITY2 0x00700000 | ACPI_LV_VERBOSITY1 +#define ACPI_LV_ALL ACPI_LV_VERBOSITY2 + +/* Trace verbosity level 3 [Threading, I/O, and Interrupts] */ + +#define ACPI_LV_MUTEX 0x01000000 +#define ACPI_LV_THREADS 0x02000000 +#define ACPI_LV_IO 0x04000000 +#define ACPI_LV_INTERRUPTS 0x08000000 +#define ACPI_LV_VERBOSITY3 0x0F000000 | ACPI_LV_VERBOSITY2 + +/* Exceptionally verbose output -- also used in the global "DebugLevel" */ + +#define ACPI_LV_AML_DISASSEMBLE 0x10000000 +#define ACPI_LV_VERBOSE_INFO 0x20000000 +#define ACPI_LV_FULL_TABLES 0x40000000 +#define ACPI_LV_EVENTS 0x80000000 +#define ACPI_LV_VERBOSE 0xF0000000 + + +/* + * Debug level macros that are used in the DEBUG_PRINT macros + */ +#define ACPI_DEBUG_LEVEL(dl) (UINT32) dl,ACPI_DEBUG_PARAMETERS + +/* + * Exception level -- used in the global "DebugLevel" + * + * Note: For errors, use the ACPI_ERROR or ACPI_EXCEPTION interfaces. + * For warnings, use ACPI_WARNING. + */ +#define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT) +#define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) +#define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) +#define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR) +#define ACPI_DB_TRACE_POINT ACPI_DEBUG_LEVEL (ACPI_LV_TRACE_POINT) +#define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) + +/* Trace level -- also used in the global "DebugLevel" */ + +#define ACPI_DB_INIT_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_INIT_NAMES) +#define ACPI_DB_THREADS ACPI_DEBUG_LEVEL (ACPI_LV_THREADS) +#define ACPI_DB_PARSE ACPI_DEBUG_LEVEL (ACPI_LV_PARSE) +#define ACPI_DB_DISPATCH ACPI_DEBUG_LEVEL (ACPI_LV_DISPATCH) +#define ACPI_DB_LOAD ACPI_DEBUG_LEVEL (ACPI_LV_LOAD) +#define ACPI_DB_EXEC ACPI_DEBUG_LEVEL (ACPI_LV_EXEC) +#define ACPI_DB_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_NAMES) +#define ACPI_DB_OPREGION ACPI_DEBUG_LEVEL (ACPI_LV_OPREGION) +#define ACPI_DB_BFIELD ACPI_DEBUG_LEVEL (ACPI_LV_BFIELD) +#define ACPI_DB_TABLES ACPI_DEBUG_LEVEL (ACPI_LV_TABLES) +#define ACPI_DB_FUNCTIONS ACPI_DEBUG_LEVEL (ACPI_LV_FUNCTIONS) +#define ACPI_DB_OPTIMIZATIONS ACPI_DEBUG_LEVEL (ACPI_LV_OPTIMIZATIONS) +#define ACPI_DB_VALUES ACPI_DEBUG_LEVEL (ACPI_LV_VALUES) +#define ACPI_DB_OBJECTS ACPI_DEBUG_LEVEL (ACPI_LV_OBJECTS) +#define ACPI_DB_ALLOCATIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALLOCATIONS) +#define ACPI_DB_RESOURCES ACPI_DEBUG_LEVEL (ACPI_LV_RESOURCES) +#define ACPI_DB_IO ACPI_DEBUG_LEVEL (ACPI_LV_IO) +#define ACPI_DB_INTERRUPTS ACPI_DEBUG_LEVEL (ACPI_LV_INTERRUPTS) +#define ACPI_DB_USER_REQUESTS ACPI_DEBUG_LEVEL (ACPI_LV_USER_REQUESTS) +#define ACPI_DB_PACKAGE ACPI_DEBUG_LEVEL (ACPI_LV_PACKAGE) +#define ACPI_DB_MUTEX ACPI_DEBUG_LEVEL (ACPI_LV_MUTEX) +#define ACPI_DB_EVENTS ACPI_DEBUG_LEVEL (ACPI_LV_EVENTS) + +#define ACPI_DB_ALL ACPI_DEBUG_LEVEL (ACPI_LV_ALL) + +/* Defaults for DebugLevel, debug and normal */ + +#define ACPI_DEBUG_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) +#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) +#define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) + + +/* + * Global trace flags + */ +#define ACPI_TRACE_ENABLED ((UINT32) 4) +#define ACPI_TRACE_ONESHOT ((UINT32) 2) +#define ACPI_TRACE_OPCODE ((UINT32) 1) + +/* Defaults for trace debugging level/layer */ + +#define ACPI_TRACE_LEVEL_ALL ACPI_LV_ALL +#define ACPI_TRACE_LAYER_ALL 0x000001FF +#define ACPI_TRACE_LEVEL_DEFAULT ACPI_LV_TRACE_POINT +#define ACPI_TRACE_LAYER_DEFAULT ACPI_EXECUTER + + +#if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) +/* + * The module name is used primarily for error and debug messages. + * The __FILE__ macro is not very useful for this, because it + * usually includes the entire pathname to the module making the + * debug output difficult to read. + */ +#define ACPI_MODULE_NAME(Name) static const char ACPI_UNUSED_VAR _AcpiModuleName[] = Name; +#else +/* + * For the no-debug and no-error-msg cases, we must at least define + * a null module name. + */ +#define ACPI_MODULE_NAME(Name) +#define _AcpiModuleName "" +#endif + +/* + * Ascii error messages can be configured out + */ +#ifndef ACPI_NO_ERROR_MESSAGES +#define AE_INFO _AcpiModuleName, __LINE__ + +/* + * Error reporting. Callers module and line number are inserted by AE_INFO, + * the plist contains a set of parens to allow variable-length lists. + * These macros are used for both the debug and non-debug versions of the code. + */ +#define ACPI_INFO(plist) AcpiInfo plist +#define ACPI_WARNING(plist) AcpiWarning plist +#define ACPI_EXCEPTION(plist) AcpiException plist +#define ACPI_ERROR(plist) AcpiError plist +#define ACPI_BIOS_WARNING(plist) AcpiBiosWarning plist +#define ACPI_BIOS_ERROR(plist) AcpiBiosError plist +#define ACPI_DEBUG_OBJECT(obj,l,i) AcpiExDoDebugObject(obj,l,i) + +#else + +/* No error messages */ + +#define ACPI_INFO(plist) +#define ACPI_WARNING(plist) +#define ACPI_EXCEPTION(plist) +#define ACPI_ERROR(plist) +#define ACPI_BIOS_WARNING(plist) +#define ACPI_BIOS_ERROR(plist) +#define ACPI_DEBUG_OBJECT(obj,l,i) + +#endif /* ACPI_NO_ERROR_MESSAGES */ + + +/* + * Debug macros that are conditionally compiled + */ +#ifdef ACPI_DEBUG_OUTPUT + +/* + * If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header, + * define it now. This is the case where there the compiler does not support + * a __FUNCTION__ macro or equivalent. + */ +#ifndef ACPI_GET_FUNCTION_NAME +#define ACPI_GET_FUNCTION_NAME _AcpiFunctionName + +/* + * The Name parameter should be the procedure name as a quoted string. + * The function name is also used by the function exit macros below. + * Note: (const char) is used to be compatible with the debug interfaces + * and macros such as __FUNCTION__. + */ +#define ACPI_FUNCTION_NAME(Name) static const char _AcpiFunctionName[] = #Name; + +#else +/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */ + +#define ACPI_FUNCTION_NAME(Name) +#endif /* ACPI_GET_FUNCTION_NAME */ + +/* + * Common parameters used for debug output functions: + * line number, function name, module(file) name, component ID + */ +#define ACPI_DEBUG_PARAMETERS \ + __LINE__, ACPI_GET_FUNCTION_NAME, _AcpiModuleName, _COMPONENT + +/* Check if debug output is currently dynamically enabled */ + +#define ACPI_IS_DEBUG_ENABLED(Level, Component) \ + ((Level & AcpiDbgLevel) && (Component & AcpiDbgLayer)) + +/* + * Master debug print macros + * Print message if and only if: + * 1) Debug print for the current component is enabled + * 2) Debug error level or trace level for the print statement is enabled + * + * November 2012: Moved the runtime check for whether to actually emit the + * debug message outside of the print function itself. This improves overall + * performance at a relatively small code cost. Implementation involves the + * use of variadic macros supported by C99. + * + * Note: the ACPI_DO_WHILE0 macro is used to prevent some compilers from + * complaining about these constructs. On other compilers the do...while + * adds some extra code, so this feature is optional. + */ +#ifdef ACPI_USE_DO_WHILE_0 +#define ACPI_DO_WHILE0(a) do a while(0) +#else +#define ACPI_DO_WHILE0(a) a +#endif + +/* DEBUG_PRINT functions */ + +#ifndef COMPILER_VA_MACRO + +#define ACPI_DEBUG_PRINT(plist) AcpiDebugPrint plist +#define ACPI_DEBUG_PRINT_RAW(plist) AcpiDebugPrintRaw plist + +#else + +/* Helper macros for DEBUG_PRINT */ + +#define ACPI_DO_DEBUG_PRINT(Function, Level, Line, Filename, Modulename, Component, ...) \ + ACPI_DO_WHILE0 ({ \ + if (ACPI_IS_DEBUG_ENABLED (Level, Component)) \ + { \ + Function (Level, Line, Filename, Modulename, Component, __VA_ARGS__); \ + } \ + }) + +#define ACPI_ACTUAL_DEBUG(Level, Line, Filename, Modulename, Component, ...) \ + ACPI_DO_DEBUG_PRINT (AcpiDebugPrint, Level, Line, \ + Filename, Modulename, Component, __VA_ARGS__) + +#define ACPI_ACTUAL_DEBUG_RAW(Level, Line, Filename, Modulename, Component, ...) \ + ACPI_DO_DEBUG_PRINT (AcpiDebugPrintRaw, Level, Line, \ + Filename, Modulename, Component, __VA_ARGS__) + +#define ACPI_DEBUG_PRINT(plist) ACPI_ACTUAL_DEBUG plist +#define ACPI_DEBUG_PRINT_RAW(plist) ACPI_ACTUAL_DEBUG_RAW plist + +#endif + + +/* + * Function entry tracing + * + * The name of the function is emitted as a local variable that is + * intended to be used by both the entry trace and the exit trace. + */ + +/* Helper macro */ + +#define ACPI_TRACE_ENTRY(Name, Function, Type, Param) \ + ACPI_FUNCTION_NAME (Name) \ + Function (ACPI_DEBUG_PARAMETERS, (Type) (Param)) + +/* The actual entry trace macros */ + +#define ACPI_FUNCTION_TRACE(Name) \ + ACPI_FUNCTION_NAME(Name) \ + AcpiUtTrace (ACPI_DEBUG_PARAMETERS) + +#define ACPI_FUNCTION_TRACE_PTR(Name, Pointer) \ + ACPI_TRACE_ENTRY (Name, AcpiUtTracePtr, void *, Pointer) + +#define ACPI_FUNCTION_TRACE_U32(Name, Value) \ + ACPI_TRACE_ENTRY (Name, AcpiUtTraceU32, UINT32, Value) + +#define ACPI_FUNCTION_TRACE_STR(Name, String) \ + ACPI_TRACE_ENTRY (Name, AcpiUtTraceStr, char *, String) + +#define ACPI_FUNCTION_ENTRY() \ + AcpiUtTrackStackPtr() + + +/* + * Function exit tracing + * + * These macros include a return statement. This is usually considered + * bad form, but having a separate exit macro before the actual return + * is very ugly and difficult to maintain. + * + * One of the FUNCTION_TRACE macros above must be used in conjunction + * with these macros so that "_AcpiFunctionName" is defined. + * + * There are two versions of most of the return macros. The default version is + * safer, since it avoids side-effects by guaranteeing that the argument will + * not be evaluated twice. + * + * A less-safe version of the macros is provided for optional use if the + * compiler uses excessive CPU stack (for example, this may happen in the + * debug case if code optimzation is disabled.) + */ + +/* Exit trace helper macro */ + +#ifndef ACPI_SIMPLE_RETURN_MACROS + +#define ACPI_TRACE_EXIT(Function, Type, Param) \ + ACPI_DO_WHILE0 ({ \ + register Type _Param = (Type) (Param); \ + Function (ACPI_DEBUG_PARAMETERS, _Param); \ + return (_Param); \ + }) + +#else /* Use original less-safe macros */ + +#define ACPI_TRACE_EXIT(Function, Type, Param) \ + ACPI_DO_WHILE0 ({ \ + Function (ACPI_DEBUG_PARAMETERS, (Type) (Param)); \ + return (Param); \ + }) + +#endif /* ACPI_SIMPLE_RETURN_MACROS */ + +/* The actual exit macros */ + +#define return_VOID \ + ACPI_DO_WHILE0 ({ \ + AcpiUtExit (ACPI_DEBUG_PARAMETERS); \ + return; \ + }) + +#define return_ACPI_STATUS(Status) \ + ACPI_TRACE_EXIT (AcpiUtStatusExit, ACPI_STATUS, Status) + +#define return_PTR(Pointer) \ + ACPI_TRACE_EXIT (AcpiUtPtrExit, void *, Pointer) + +#define return_VALUE(Value) \ + ACPI_TRACE_EXIT (AcpiUtValueExit, UINT64, Value) + +#define return_UINT32(Value) \ + ACPI_TRACE_EXIT (AcpiUtValueExit, UINT32, Value) + +#define return_UINT8(Value) \ + ACPI_TRACE_EXIT (AcpiUtValueExit, UINT8, Value) + +/* Conditional execution */ + +#define ACPI_DEBUG_EXEC(a) a +#define ACPI_DEBUG_ONLY_MEMBERS(a) a; +#define _VERBOSE_STRUCTURES + + +/* Various object display routines for debug */ + +#define ACPI_DUMP_STACK_ENTRY(a) AcpiExDumpOperand((a), 0) +#define ACPI_DUMP_OPERANDS(a, b ,c) AcpiExDumpOperands(a, b, c) +#define ACPI_DUMP_ENTRY(a, b) AcpiNsDumpEntry (a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) AcpiNsDumpPathname(a, b, c, d) +#define ACPI_DUMP_BUFFER(a, b) AcpiUtDebugDumpBuffer((UINT8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) + +#define ACPI_TRACE_POINT(a, b, c, d) AcpiTracePoint (a, b, c, d) + +#else /* ACPI_DEBUG_OUTPUT */ +/* + * This is the non-debug case -- make everything go away, + * leaving no executable debug code! + */ +#define ACPI_DEBUG_PRINT(pl) +#define ACPI_DEBUG_PRINT_RAW(pl) +#define ACPI_DEBUG_EXEC(a) +#define ACPI_DEBUG_ONLY_MEMBERS(a) +#define ACPI_FUNCTION_NAME(a) +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_TRACE_PTR(a, b) +#define ACPI_FUNCTION_TRACE_U32(a, b) +#define ACPI_FUNCTION_TRACE_STR(a, b) +#define ACPI_FUNCTION_ENTRY() +#define ACPI_DUMP_STACK_ENTRY(a) +#define ACPI_DUMP_OPERANDS(a, b, c) +#define ACPI_DUMP_ENTRY(a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) +#define ACPI_DUMP_BUFFER(a, b) +#define ACPI_IS_DEBUG_ENABLED(Level, Component) 0 +#define ACPI_TRACE_POINT(a, b, c, d) + +/* Return macros must have a return statement at the minimum */ + +#define return_VOID return +#define return_ACPI_STATUS(s) return(s) +#define return_PTR(s) return(s) +#define return_VALUE(s) return(s) +#define return_UINT8(s) return(s) +#define return_UINT32(s) return(s) + +#endif /* ACPI_DEBUG_OUTPUT */ + + +#endif /* __ACOUTPUT_H__ */ diff --git a/third_party/lib/acpica/source/include/acparser.h b/third_party/lib/acpica/source/include/acparser.h new file mode 100644 index 000000000..26651280e --- /dev/null +++ b/third_party/lib/acpica/source/include/acparser.h @@ -0,0 +1,364 @@ +/****************************************************************************** + * + * Module Name: acparser.h - AML Parser subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACPARSER_H__ +#define __ACPARSER_H__ + + +#define OP_HAS_RETURN_VALUE 1 + +/* Variable number of arguments. This field must be 32 bits */ + +#define ACPI_VAR_ARGS ACPI_UINT32_MAX + + +#define ACPI_PARSE_DELETE_TREE 0x0001 +#define ACPI_PARSE_NO_TREE_DELETE 0x0000 +#define ACPI_PARSE_TREE_MASK 0x0001 + +#define ACPI_PARSE_LOAD_PASS1 0x0010 +#define ACPI_PARSE_LOAD_PASS2 0x0020 +#define ACPI_PARSE_EXECUTE 0x0030 +#define ACPI_PARSE_MODE_MASK 0x0030 + +#define ACPI_PARSE_DEFERRED_OP 0x0100 +#define ACPI_PARSE_DISASSEMBLE 0x0200 + +#define ACPI_PARSE_MODULE_LEVEL 0x0400 + +/****************************************************************************** + * + * Parser interfaces + * + *****************************************************************************/ + +extern const UINT8 AcpiGbl_ShortOpIndex[]; +extern const UINT8 AcpiGbl_LongOpIndex[]; + + +/* + * psxface - Parser external interfaces + */ +ACPI_STATUS +AcpiPsExecuteMethod ( + ACPI_EVALUATE_INFO *Info); + + +/* + * psargs - Parse AML opcode arguments + */ +UINT8 * +AcpiPsGetNextPackageEnd ( + ACPI_PARSE_STATE *ParserState); + +char * +AcpiPsGetNextNamestring ( + ACPI_PARSE_STATE *ParserState); + +void +AcpiPsGetNextSimpleArg ( + ACPI_PARSE_STATE *ParserState, + UINT32 ArgType, + ACPI_PARSE_OBJECT *Arg); + +ACPI_STATUS +AcpiPsGetNextNamepath ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Arg, + BOOLEAN PossibleMethodCall); + +/* Values for BOOLEAN above */ + +#define ACPI_NOT_METHOD_CALL FALSE +#define ACPI_POSSIBLE_METHOD_CALL TRUE + +ACPI_STATUS +AcpiPsGetNextArg ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_STATE *ParserState, + UINT32 ArgType, + ACPI_PARSE_OBJECT **ReturnArg); + + +/* + * psfind + */ +ACPI_PARSE_OBJECT * +AcpiPsFindName ( + ACPI_PARSE_OBJECT *Scope, + UINT32 Name, + UINT32 Opcode); + +ACPI_PARSE_OBJECT* +AcpiPsGetParent ( + ACPI_PARSE_OBJECT *Op); + + +/* + * psobject - support for parse object processing + */ +ACPI_STATUS +AcpiPsBuildNamedOp ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT *UnnamedOp, + ACPI_PARSE_OBJECT **Op); + +ACPI_STATUS +AcpiPsCreateOp ( + ACPI_WALK_STATE *WalkState, + UINT8 *AmlOpStart, + ACPI_PARSE_OBJECT **NewOp); + +ACPI_STATUS +AcpiPsCompleteOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **Op, + ACPI_STATUS Status); + +ACPI_STATUS +AcpiPsCompleteFinalOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS Status); + + +/* + * psopinfo - AML Opcode information + */ +const ACPI_OPCODE_INFO * +AcpiPsGetOpcodeInfo ( + UINT16 Opcode); + +char * +AcpiPsGetOpcodeName ( + UINT16 Opcode); + +UINT8 +AcpiPsGetArgumentCount ( + UINT32 OpType); + + +/* + * psparse - top level parsing routines + */ +ACPI_STATUS +AcpiPsParseAml ( + ACPI_WALK_STATE *WalkState); + +UINT32 +AcpiPsGetOpcodeSize ( + UINT32 Opcode); + +UINT16 +AcpiPsPeekOpcode ( + ACPI_PARSE_STATE *state); + +ACPI_STATUS +AcpiPsCompleteThisOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op); + +ACPI_STATUS +AcpiPsNextParseState ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_STATUS CallbackStatus); + + +/* + * psloop - main parse loop + */ +ACPI_STATUS +AcpiPsParseLoop ( + ACPI_WALK_STATE *WalkState); + + +/* + * psscope - Scope stack management routines + */ +ACPI_STATUS +AcpiPsInitScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Root); + +ACPI_PARSE_OBJECT * +AcpiPsGetParentScope ( + ACPI_PARSE_STATE *state); + +BOOLEAN +AcpiPsHasCompletedScope ( + ACPI_PARSE_STATE *ParserState); + +void +AcpiPsPopScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT **Op, + UINT32 *ArgList, + UINT32 *ArgCount); + +ACPI_STATUS +AcpiPsPushScope ( + ACPI_PARSE_STATE *ParserState, + ACPI_PARSE_OBJECT *Op, + UINT32 RemainingArgs, + UINT32 ArgCount); + +void +AcpiPsCleanupScope ( + ACPI_PARSE_STATE *state); + + +/* + * pstree - parse tree manipulation routines + */ +void +AcpiPsAppendArg( + ACPI_PARSE_OBJECT *op, + ACPI_PARSE_OBJECT *arg); + +ACPI_PARSE_OBJECT* +AcpiPsFind ( + ACPI_PARSE_OBJECT *Scope, + char *Path, + UINT16 Opcode, + UINT32 Create); + +ACPI_PARSE_OBJECT * +AcpiPsGetArg( + ACPI_PARSE_OBJECT *op, + UINT32 argn); + +ACPI_PARSE_OBJECT * +AcpiPsGetDepthNext ( + ACPI_PARSE_OBJECT *Origin, + ACPI_PARSE_OBJECT *Op); + + +/* + * pswalk - parse tree walk routines + */ +ACPI_STATUS +AcpiPsWalkParsedAml ( + ACPI_PARSE_OBJECT *StartOp, + ACPI_PARSE_OBJECT *EndOp, + ACPI_OPERAND_OBJECT *MthDesc, + ACPI_NAMESPACE_NODE *StartNode, + ACPI_OPERAND_OBJECT **Params, + ACPI_OPERAND_OBJECT **CallerReturnDesc, + ACPI_OWNER_ID OwnerId, + ACPI_PARSE_DOWNWARDS DescendingCallback, + ACPI_PARSE_UPWARDS AscendingCallback); + +ACPI_STATUS +AcpiPsGetNextWalkOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op, + ACPI_PARSE_UPWARDS AscendingCallback); + +ACPI_STATUS +AcpiPsDeleteCompletedOp ( + ACPI_WALK_STATE *WalkState); + +void +AcpiPsDeleteParseTree ( + ACPI_PARSE_OBJECT *root); + + +/* + * psutils - parser utilities + */ +ACPI_PARSE_OBJECT * +AcpiPsCreateScopeOp ( + UINT8 *Aml); + +void +AcpiPsInitOp ( + ACPI_PARSE_OBJECT *op, + UINT16 opcode); + +ACPI_PARSE_OBJECT * +AcpiPsAllocOp ( + UINT16 Opcode, + UINT8 *Aml); + +void +AcpiPsFreeOp ( + ACPI_PARSE_OBJECT *Op); + +BOOLEAN +AcpiPsIsLeadingChar ( + UINT32 c); + +UINT32 +AcpiPsGetName( + ACPI_PARSE_OBJECT *op); + +void +AcpiPsSetName( + ACPI_PARSE_OBJECT *op, + UINT32 name); + + +/* + * psdump - display parser tree + */ +UINT32 +AcpiPsSprintPath ( + char *BufferStart, + UINT32 BufferSize, + ACPI_PARSE_OBJECT *Op); + +UINT32 +AcpiPsSprintOp ( + char *BufferStart, + UINT32 BufferSize, + ACPI_PARSE_OBJECT *Op); + +void +AcpiPsShow ( + ACPI_PARSE_OBJECT *op); + + +#endif /* __ACPARSER_H__ */ diff --git a/third_party/lib/acpica/source/include/acpi.h b/third_party/lib/acpica/source/include/acpi.h new file mode 100644 index 000000000..105cb5256 --- /dev/null +++ b/third_party/lib/acpica/source/include/acpi.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Name: acpi.h - Master public include file used to interface to ACPICA + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACPI_H__ +#define __ACPI_H__ + +/* + * Public include files for use by code that will interface to ACPICA. + * + * Information includes the ACPICA data types, names, exceptions, and + * external interface prototypes. Also included are the definitions for + * all ACPI tables (FADT, MADT, etc.) + * + * Note: The order of these include files is important. + */ +#include "platform/acenv.h" /* Environment-specific items */ +#include "acnames.h" /* Common ACPI names and strings */ +#include "actypes.h" /* ACPICA data types and structures */ +#include "acexcep.h" /* ACPICA exceptions */ +#include "actbl.h" /* ACPI table definitions */ +#include "acoutput.h" /* Error output and Debug macros */ +#include "acrestyp.h" /* Resource Descriptor structs */ +#include "acpiosxf.h" /* OSL interfaces (ACPICA-to-OS) */ +#include "acpixf.h" /* ACPI core subsystem external interfaces */ +#include "platform/acenvex.h" /* Extra environment-specific items */ + +#endif /* __ACPI_H__ */ diff --git a/third_party/lib/acpica/source/include/acpiosxf.h b/third_party/lib/acpica/source/include/acpiosxf.h new file mode 100644 index 000000000..eb61d9a8c --- /dev/null +++ b/third_party/lib/acpica/source/include/acpiosxf.h @@ -0,0 +1,613 @@ +/****************************************************************************** + * + * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These + * interfaces must be implemented by OSL to interface the + * ACPI components to the host operating system. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACPIOSXF_H__ +#define __ACPIOSXF_H__ + +#include "platform/acenv.h" +#include "actypes.h" + + +/* Types for AcpiOsExecute */ + +typedef enum +{ + OSL_GLOBAL_LOCK_HANDLER, + OSL_NOTIFY_HANDLER, + OSL_GPE_HANDLER, + OSL_DEBUGGER_MAIN_THREAD, + OSL_DEBUGGER_EXEC_THREAD, + OSL_EC_POLL_HANDLER, + OSL_EC_BURST_HANDLER + +} ACPI_EXECUTE_TYPE; + +#define ACPI_NO_UNIT_LIMIT ((UINT32) -1) +#define ACPI_MUTEX_SEM 1 + + +/* Functions for AcpiOsSignal */ + +#define ACPI_SIGNAL_FATAL 0 +#define ACPI_SIGNAL_BREAKPOINT 1 + +typedef struct acpi_signal_fatal_info +{ + UINT32 Type; + UINT32 Code; + UINT32 Argument; + +} ACPI_SIGNAL_FATAL_INFO; + + +/* + * OSL Initialization and shutdown primitives + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsInitialize +ACPI_STATUS +AcpiOsInitialize ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTerminate +ACPI_STATUS +AcpiOsTerminate ( + void); +#endif + + +/* + * ACPI Table interfaces + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetRootPointer +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPredefinedOverride +ACPI_STATUS +AcpiOsPredefinedOverride ( + const ACPI_PREDEFINED_NAMES *InitVal, + ACPI_STRING *NewVal); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTableOverride +ACPI_STATUS +AcpiOsTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPhysicalTableOverride +ACPI_STATUS +AcpiOsPhysicalTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_PHYSICAL_ADDRESS *NewAddress, + UINT32 *NewTableLength); +#endif + + +/* + * Spinlock primitives + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateLock +ACPI_STATUS +AcpiOsCreateLock ( + ACPI_SPINLOCK *OutHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteLock +void +AcpiOsDeleteLock ( + ACPI_SPINLOCK Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireLock +ACPI_CPU_FLAGS +AcpiOsAcquireLock ( + ACPI_SPINLOCK Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseLock +void +AcpiOsReleaseLock ( + ACPI_SPINLOCK Handle, + ACPI_CPU_FLAGS Flags); +#endif + + +/* + * Semaphore primitives + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateSemaphore +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_SEMAPHORE *OutHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteSemaphore +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_SEMAPHORE Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitSemaphore +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_SEMAPHORE Handle, + UINT32 Units, + UINT16 Timeout); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSignalSemaphore +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_SEMAPHORE Handle, + UINT32 Units); +#endif + + +/* + * Mutex primitives. May be configured to use semaphores instead via + * ACPI_MUTEX_TYPE (see platform/acenv.h) + */ +#if (ACPI_MUTEX_TYPE != ACPI_BINARY_SEMAPHORE) + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateMutex +ACPI_STATUS +AcpiOsCreateMutex ( + ACPI_MUTEX *OutHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteMutex +void +AcpiOsDeleteMutex ( + ACPI_MUTEX Handle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireMutex +ACPI_STATUS +AcpiOsAcquireMutex ( + ACPI_MUTEX Handle, + UINT16 Timeout); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseMutex +void +AcpiOsReleaseMutex ( + ACPI_MUTEX Handle); +#endif + +#endif + + +/* + * Memory allocation and mapping + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAllocate +void * +AcpiOsAllocate ( + ACPI_SIZE Size); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAllocateZeroed +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE Size); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsFree +void +AcpiOsFree ( + void * Memory); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsMapMemory +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsUnmapMemory +void +AcpiOsUnmapMemory ( + void *LogicalAddress, + ACPI_SIZE Size); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetPhysicalAddress +ACPI_STATUS +AcpiOsGetPhysicalAddress ( + void *LogicalAddress, + ACPI_PHYSICAL_ADDRESS *PhysicalAddress); +#endif + + +/* + * Memory/Object Cache + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateCache +ACPI_STATUS +AcpiOsCreateCache ( + char *CacheName, + UINT16 ObjectSize, + UINT16 MaxDepth, + ACPI_CACHE_T **ReturnCache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsDeleteCache +ACPI_STATUS +AcpiOsDeleteCache ( + ACPI_CACHE_T *Cache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPurgeCache +ACPI_STATUS +AcpiOsPurgeCache ( + ACPI_CACHE_T *Cache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireObject +void * +AcpiOsAcquireObject ( + ACPI_CACHE_T *Cache); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseObject +ACPI_STATUS +AcpiOsReleaseObject ( + ACPI_CACHE_T *Cache, + void *Object); +#endif + + +/* + * Interrupt handlers + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsInstallInterruptHandler +ACPI_STATUS +AcpiOsInstallInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine, + void *Context); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsRemoveInterruptHandler +ACPI_STATUS +AcpiOsRemoveInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine); +#endif + + +/* + * Threads and Scheduling + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetThreadId +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsExecute +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitEventsComplete +void +AcpiOsWaitEventsComplete ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSleep +void +AcpiOsSleep ( + UINT64 Milliseconds); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsStall +void +AcpiOsStall ( + UINT32 Microseconds); +#endif + + +/* + * Platform and hardware-independent I/O interfaces + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadPort +ACPI_STATUS +AcpiOsReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritePort +ACPI_STATUS +AcpiOsWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width); +#endif + + +/* + * Platform and hardware-independent physical memory interfaces + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadMemory +ACPI_STATUS +AcpiOsReadMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 *Value, + UINT32 Width); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWriteMemory +ACPI_STATUS +AcpiOsWriteMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 Value, + UINT32 Width); +#endif + + +/* + * Platform and hardware-independent PCI configuration space access + * Note: Can't use "Register" as a parameter, changed to "Reg" -- + * certain compilers complain. + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadPciConfiguration +ACPI_STATUS +AcpiOsReadPciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 Reg, + UINT64 *Value, + UINT32 Width); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritePciConfiguration +ACPI_STATUS +AcpiOsWritePciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 Reg, + UINT64 Value, + UINT32 Width); +#endif + + +/* + * Miscellaneous + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadable +BOOLEAN +AcpiOsReadable ( + void *Pointer, + ACPI_SIZE Length); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritable +BOOLEAN +AcpiOsWritable ( + void *Pointer, + ACPI_SIZE Length); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTimer +UINT64 +AcpiOsGetTimer ( + void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSignal +ACPI_STATUS +AcpiOsSignal ( + UINT32 Function, + void *Info); +#endif + + +/* + * Debug print routines + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsPrintf +void ACPI_INTERNAL_VAR_XFACE +AcpiOsPrintf ( + const char *Format, + ...); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsVprintf +void +AcpiOsVprintf ( + const char *Format, + va_list Args); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsRedirectOutput +void +AcpiOsRedirectOutput ( + void *Destination); +#endif + + +/* + * Debug input + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetLine +ACPI_STATUS +AcpiOsGetLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead); +#endif + + +/* + * Obtain ACPI table(s) + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByName +ACPI_STATUS +AcpiOsGetTableByName ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByIndex +ACPI_STATUS +AcpiOsGetTableByIndex ( + UINT32 Index, + ACPI_TABLE_HEADER **Table, + UINT32 *Instance, + ACPI_PHYSICAL_ADDRESS *Address); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByAddress +ACPI_STATUS +AcpiOsGetTableByAddress ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER **Table); +#endif + + +/* + * Directory manipulation + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsOpenDirectory +void * +AcpiOsOpenDirectory ( + char *Pathname, + char *WildcardSpec, + char RequestedFileType); +#endif + +/* RequesteFileType values */ + +#define REQUEST_FILE_ONLY 0 +#define REQUEST_DIR_ONLY 1 + + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetNextFilename +char * +AcpiOsGetNextFilename ( + void *DirHandle); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCloseDirectory +void +AcpiOsCloseDirectory ( + void *DirHandle); +#endif + + +/* + * File I/O and related support + */ +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsOpenFile +ACPI_FILE +AcpiOsOpenFile ( + const char *Path, + UINT8 Modes); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCloseFile +void +AcpiOsCloseFile ( + ACPI_FILE File); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadFile +int +AcpiOsReadFile ( + ACPI_FILE File, + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWriteFile +int +AcpiOsWriteFile ( + ACPI_FILE File, + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetFileOffset +long +AcpiOsGetFileOffset ( + ACPI_FILE File); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsSetFileOffset +ACPI_STATUS +AcpiOsSetFileOffset ( + ACPI_FILE File, + long Offset, + UINT8 From); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTracePoint +void +AcpiOsTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname); +#endif + + +#endif /* __ACPIOSXF_H__ */ diff --git a/third_party/lib/acpica/source/include/acpixf.h b/third_party/lib/acpica/source/include/acpixf.h new file mode 100644 index 000000000..408bdf95f --- /dev/null +++ b/third_party/lib/acpica/source/include/acpixf.h @@ -0,0 +1,1256 @@ +/****************************************************************************** + * + * Name: acpixf.h - External interfaces to the ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACXFACE_H__ +#define __ACXFACE_H__ + +/* Current ACPICA subsystem version in YYYYMMDD format */ + +#define ACPI_CA_VERSION 0x20160108 + +#include "acconfig.h" +#include "actypes.h" +#include "actbl.h" +#include "acbuffer.h" + + +/***************************************************************************** + * + * Macros used for ACPICA globals and configuration + * + ****************************************************************************/ + +/* + * Ensure that global variables are defined and initialized only once. + * + * The use of these macros allows for a single list of globals (here) + * in order to simplify maintenance of the code. + */ +#ifdef DEFINE_ACPI_GLOBALS +#define ACPI_GLOBAL(type,name) \ + extern type name; \ + type name + +#define ACPI_INIT_GLOBAL(type,name,value) \ + type name=value + +#else +#ifndef ACPI_GLOBAL +#define ACPI_GLOBAL(type,name) \ + extern type name +#endif + +#ifndef ACPI_INIT_GLOBAL +#define ACPI_INIT_GLOBAL(type,name,value) \ + extern type name +#endif +#endif + +/* + * These macros configure the various ACPICA interfaces. They are + * useful for generating stub inline functions for features that are + * configured out of the current kernel or ACPICA application. + */ +#ifndef ACPI_EXTERNAL_RETURN_STATUS +#define ACPI_EXTERNAL_RETURN_STATUS(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_OK +#define ACPI_EXTERNAL_RETURN_OK(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_VOID +#define ACPI_EXTERNAL_RETURN_VOID(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_UINT32 +#define ACPI_EXTERNAL_RETURN_UINT32(Prototype) \ + Prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_PTR +#define ACPI_EXTERNAL_RETURN_PTR(Prototype) \ + Prototype; +#endif + + +/***************************************************************************** + * + * Public globals and runtime configuration options + * + ****************************************************************************/ + +/* + * Enable "slack mode" of the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to ignore certain errors and/or bad AML constructs. + * + * Currently, these features are enabled by this flag: + * + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond the end of an operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + * 5) Allow unresolved references (invalid target name) in package objects + * 6) Enable warning messages for behavior that is not ACPI spec compliant + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_EnableInterpreterSlack, FALSE); + +/* + * Automatically serialize all methods that create named objects? Default + * is TRUE, meaning that all NonSerialized methods are scanned once at + * table load time to determine those that create named objects. Methods + * that create named objects are marked Serialized in order to prevent + * possible run-time problems if they are entered by more than one thread. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_AutoSerializeMethods, TRUE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPICA is fully compatible with other ACPI implementations. + * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_CreateOsiMethod, TRUE); + +/* + * Optionally use default values for the ACPI register widths. Set this to + * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_UseDefaultRegisterWidths, TRUE); + +/* + * Whether or not to verify the table checksum before installation. Set + * this to TRUE to verify the table checksum before install it to the table + * manager. Note that enabling this option causes errors to happen in some + * OSPMs during early initialization stages. Default behavior is to do such + * verification. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_VerifyTableChecksum, TRUE); + +/* + * Optionally enable output from the AML Debug Object. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_EnableAmlDebugObject, FALSE); + +/* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_CopyDsdtLocally, FALSE); + +/* + * Optionally ignore an XSDT if present and use the RSDT instead. + * Although the ACPI specification requires that an XSDT be used instead + * of the RSDT, the XSDT has been found to be corrupt or ill-formed on + * some machines. Default behavior is to use the XSDT if present. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DoNotUseXsdt, FALSE); + +/* + * Optionally allow default region handlers to be overridden. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_OverrideDefaultRegionHandlers, FALSE); + +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_Use32BitFadtAddresses, FALSE); + +/* + * Optionally use 32-bit FACS table addresses. + * It is reported that some platforms fail to resume from system suspending + * if 64-bit FACS table address is selected: + * https://bugzilla.kernel.org/show_bug.cgi?id=74021 + * Default is TRUE, favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_Use32BitFacsAddresses, TRUE); + +/* + * Optionally truncate I/O addresses to 16 bits. Provides compatibility + * with other ACPI implementations. NOTE: During ACPICA initialization, + * this value is set to TRUE if any Windows OSI strings have been + * requested by the BIOS. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_TruncateIoAddresses, FALSE); + +/* + * Disable runtime checking and repair of values returned by control methods. + * Use only if the repair is causing a problem on a particular machine. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DisableAutoRepair, FALSE); + +/* + * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. + * This can be useful for debugging ACPI problems on some machines. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DisableSsdtTableInstall, FALSE); + +/* + * Optionally enable runtime namespace override. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_RuntimeNamespaceOverride, TRUE); + +/* + * We keep track of the latest version of Windows that has been requested by + * the BIOS. ACPI 5.0. + */ +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_OsiData, 0); + +/* + * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning + * that the ACPI hardware is no longer required. A flag in the FADT indicates + * a reduced HW machine, and that flag is duplicated here for convenience. + */ +ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_ReducedHardware, FALSE); + +/* + * This mechanism is used to trace a specified AML method. The method is + * traced each time it is executed. + */ +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_TraceFlags, 0); +ACPI_INIT_GLOBAL (const char *, AcpiGbl_TraceMethodName, NULL); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_TraceDbgLevel, ACPI_TRACE_LEVEL_DEFAULT); +ACPI_INIT_GLOBAL (UINT32, AcpiGbl_TraceDbgLayer, ACPI_TRACE_LAYER_DEFAULT); + +/* + * Runtime configuration of debug output control masks. We want the debug + * switches statically initialized so they are already set when the debugger + * is entered. + */ +#ifdef ACPI_DEBUG_OUTPUT +ACPI_INIT_GLOBAL (UINT32, AcpiDbgLevel, ACPI_DEBUG_DEFAULT); +#else +ACPI_INIT_GLOBAL (UINT32, AcpiDbgLevel, ACPI_NORMAL_DEFAULT); +#endif +ACPI_INIT_GLOBAL (UINT32, AcpiDbgLayer, ACPI_COMPONENT_DEFAULT); + +/* Optionally enable timer output with Debug Object output */ + +ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DisplayDebugTimer, FALSE); + +/* + * Other miscellaneous globals + */ +ACPI_GLOBAL (ACPI_TABLE_FADT, AcpiGbl_FADT); +ACPI_GLOBAL (UINT32, AcpiCurrentGpeCount); +ACPI_GLOBAL (BOOLEAN, AcpiGbl_SystemAwakeAndRunning); + + +/***************************************************************************** + * + * ACPICA public interface configuration. + * + * Interfaces that are configured out of the ACPICA build are replaced + * by inlined stubs by default. + * + ****************************************************************************/ + +/* + * Hardware-reduced prototypes (default: Not hardware reduced). + * + * All ACPICA hardware-related interfaces that use these macros will be + * configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag + * is set to TRUE. + * + * Note: This static build option for reduced hardware is intended to + * reduce ACPICA code size if desired or necessary. However, even if this + * option is not specified, the runtime behavior of ACPICA is dependent + * on the actual FADT reduced hardware flag (HW_REDUCED_ACPI). If set, + * the flag will enable similar behavior -- ACPICA will not attempt + * to access any ACPI-relate hardware (SCI, GPEs, Fixed Events, etc.) + */ +#if (!ACPI_REDUCED_HARDWARE) +#define ACPI_HW_DEPENDENT_RETURN_STATUS(Prototype) \ + ACPI_EXTERNAL_RETURN_STATUS(Prototype) + +#define ACPI_HW_DEPENDENT_RETURN_OK(Prototype) \ + ACPI_EXTERNAL_RETURN_OK(Prototype) + +#define ACPI_HW_DEPENDENT_RETURN_VOID(Prototype) \ + ACPI_EXTERNAL_RETURN_VOID(Prototype) + +#else +#define ACPI_HW_DEPENDENT_RETURN_STATUS(Prototype) \ + static ACPI_INLINE Prototype {return(AE_NOT_CONFIGURED);} + +#define ACPI_HW_DEPENDENT_RETURN_OK(Prototype) \ + static ACPI_INLINE Prototype {return(AE_OK);} + +#define ACPI_HW_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/* + * Error message prototypes (default: error messages enabled). + * + * All interfaces related to error and warning messages + * will be configured out of the ACPICA build if the + * ACPI_NO_ERROR_MESSAGE flag is defined. + */ +#ifndef ACPI_NO_ERROR_MESSAGES +#define ACPI_MSG_DEPENDENT_RETURN_VOID(Prototype) \ + Prototype; + +#else +#define ACPI_MSG_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_NO_ERROR_MESSAGES */ + + +/* + * Debugging output prototypes (default: no debug output). + * + * All interfaces related to debug output messages + * will be configured out of the ACPICA build unless the + * ACPI_DEBUG_OUTPUT flag is defined. + */ +#ifdef ACPI_DEBUG_OUTPUT +#define ACPI_DBG_DEPENDENT_RETURN_VOID(Prototype) \ + Prototype; + +#else +#define ACPI_DBG_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_DEBUG_OUTPUT */ + + +/* + * Application prototypes + * + * All interfaces used by application will be configured + * out of the ACPICA build unless the ACPI_APPLICATION + * flag is defined. + */ +#ifdef ACPI_APPLICATION +#define ACPI_APP_DEPENDENT_RETURN_VOID(Prototype) \ + Prototype; + +#else +#define ACPI_APP_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_APPLICATION */ + + +/* + * Debugger prototypes + * + * All interfaces used by debugger will be configured + * out of the ACPICA build unless the ACPI_DEBUGGER + * flag is defined. + */ +#ifdef ACPI_DEBUGGER +#define ACPI_DBR_DEPENDENT_RETURN_OK(Prototype) \ + ACPI_EXTERNAL_RETURN_OK(Prototype) + +#define ACPI_DBR_DEPENDENT_RETURN_VOID(Prototype) \ + ACPI_EXTERNAL_RETURN_VOID(Prototype) + +#else +#define ACPI_DBR_DEPENDENT_RETURN_OK(Prototype) \ + static ACPI_INLINE Prototype {return(AE_OK);} + +#define ACPI_DBR_DEPENDENT_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} + +#endif /* ACPI_DEBUGGER */ + + +/***************************************************************************** + * + * ACPICA public interface prototypes + * + ****************************************************************************/ + +/* + * Initialization + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInitializeTables ( + ACPI_TABLE_DESC *InitialStorage, + UINT32 InitialTableCount, + BOOLEAN AllowResize)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInitializeSubsystem ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableSubsystem ( + UINT32 Flags)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInitializeObjects ( + UINT32 Flags)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiTerminate ( + void)) + + +/* + * Miscellaneous global interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnable ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisable ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiSubsystemStatus ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetSystemInfo ( + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetStatistics ( + ACPI_STATISTICS *Stats)) + +ACPI_EXTERNAL_RETURN_PTR ( +const char * +AcpiFormatException ( + ACPI_STATUS Exception)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiPurgeCachedObjects ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallInterface ( + ACPI_STRING InterfaceName)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveInterface ( + ACPI_STRING InterfaceName)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiUpdateInterfaces ( + UINT8 Action)) + +ACPI_EXTERNAL_RETURN_UINT32 ( +UINT32 +AcpiCheckAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + ACPI_SIZE Length, + BOOLEAN Warn)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiDecodePldBuffer ( + UINT8 *InBuffer, + ACPI_SIZE Length, + ACPI_PLD_INFO **ReturnBuffer)) + + +/* + * ACPI table load/unload interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallTable ( + ACPI_PHYSICAL_ADDRESS Address, + BOOLEAN Physical)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLoadTable ( + ACPI_TABLE_HEADER *Table)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiUnloadParentTable ( + ACPI_HANDLE Object)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLoadTables ( + void)) + + +/* + * ACPI table manipulation interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiReallocateRootTable ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiFindRootPointer ( + ACPI_PHYSICAL_ADDRESS *RsdpAddress)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTableHeader ( + ACPI_STRING Signature, + UINT32 Instance, + ACPI_TABLE_HEADER *OutTableHeader)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTable ( + ACPI_STRING Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **OutTable)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTableByIndex ( + UINT32 TableIndex, + ACPI_TABLE_HEADER **OutTable)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallTableHandler ( + ACPI_TABLE_HANDLER Handler, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveTableHandler ( + ACPI_TABLE_HANDLER Handler)) + + +/* + * Namespace and name interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK DescendingCallback, + ACPI_WALK_CALLBACK AscendingCallback, + void *Context, + void **ReturnValue)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetDevices ( + char *HID, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetName ( + ACPI_HANDLE Object, + UINT32 NameType, + ACPI_BUFFER *RetPathPtr)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetHandle ( + ACPI_HANDLE Parent, + ACPI_STRING Pathname, + ACPI_HANDLE *RetHandle)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiAttachData ( + ACPI_HANDLE Object, + ACPI_OBJECT_HANDLER Handler, + void *Data)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiDetachData ( + ACPI_HANDLE Object, + ACPI_OBJECT_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetData ( + ACPI_HANDLE Object, + ACPI_OBJECT_HANDLER Handler, + void **Data)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiDebugTrace ( + const char *Name, + UINT32 DebugLevel, + UINT32 DebugLayer, + UINT32 Flags)) + + +/* + * Object manipulation and enumeration + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEvaluateObject ( + ACPI_HANDLE Object, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ParameterObjects, + ACPI_BUFFER *ReturnObjectBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEvaluateObjectTyped ( + ACPI_HANDLE Object, + ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ExternalParams, + ACPI_BUFFER *ReturnBuffer, + ACPI_OBJECT_TYPE ReturnType)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetObjectInfo ( + ACPI_HANDLE Object, + ACPI_DEVICE_INFO **ReturnBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallMethod ( + UINT8 *Buffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetNextObject ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE Parent, + ACPI_HANDLE Child, + ACPI_HANDLE *OutHandle)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetType ( + ACPI_HANDLE Object, + ACPI_OBJECT_TYPE *OutType)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetParent ( + ACPI_HANDLE Object, + ACPI_HANDLE *OutHandle)) + + +/* + * Handler interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallInitializationHandler ( + ACPI_INIT_HANDLER Handler, + UINT32 Function)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallSciHandler ( + ACPI_SCI_HANDLER Address, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveSciHandler ( + ACPI_SCI_HANDLER Address)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGlobalEventHandler ( + ACPI_GBL_EVENT_HANDLER Handler, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallFixedEventHandler ( + UINT32 AcpiEvent, + ACPI_EVENT_HANDLER Handler, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveFixedEventHandler ( + UINT32 AcpiEvent, + ACPI_EVENT_HANDLER Handler)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + ACPI_GPE_HANDLER Address, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGpeRawHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT32 Type, + ACPI_GPE_HANDLER Address, + void *Context)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + ACPI_GPE_HANDLER Address)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallNotifyHandler ( + ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveNotifyHandler ( + ACPI_HANDLE Device, + UINT32 HandlerType, + ACPI_NOTIFY_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallExceptionHandler ( + ACPI_EXCEPTION_HANDLER Handler)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallInterfaceHandler ( + ACPI_INTERFACE_HANDLER Handler)) + + +/* + * Global Lock interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiAcquireGlobalLock ( + UINT16 Timeout, + UINT32 *Handle)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiReleaseGlobalLock ( + UINT32 Handle)) + + +/* + * Interfaces to AML mutex objects + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiAcquireMutex ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname, + UINT16 Timeout)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiReleaseMutex ( + ACPI_HANDLE Handle, + ACPI_STRING Pathname)) + + +/* + * Fixed Event interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableEvent ( + UINT32 Event, + UINT32 Flags)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisableEvent ( + UINT32 Event, + UINT32 Flags)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiClearEvent ( + UINT32 Event)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetEventStatus ( + UINT32 Event, + ACPI_EVENT_STATUS *EventStatus)) + + +/* + * General Purpose Event (GPE) Interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiUpdateAllGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisableGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiClearGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT8 Action)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiFinishGpe ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiMarkGpeForWake ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetupGpeForWake ( + ACPI_HANDLE ParentDevice, + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetGpeWakeMask ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + UINT8 Action)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetGpeStatus ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + ACPI_EVENT_STATUS *EventStatus)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiDisableAllGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableAllRuntimeGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnableAllWakeupGpes ( + void)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetGpeDevice ( + UINT32 GpeIndex, + ACPI_HANDLE *GpeDevice)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallGpeBlock ( + ACPI_HANDLE GpeDevice, + ACPI_GENERIC_ADDRESS *GpeBlockAddress, + UINT32 RegisterCount, + UINT32 InterruptNumber)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiRemoveGpeBlock ( + ACPI_HANDLE GpeDevice)) + + +/* + * Resource interfaces + */ +typedef +ACPI_STATUS (*ACPI_WALK_RESOURCE_CALLBACK) ( + ACPI_RESOURCE *Resource, + void *Context); + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetVendorResource ( + ACPI_HANDLE Device, + char *Name, + ACPI_VENDOR_UUID *Uuid, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetCurrentResources ( + ACPI_HANDLE Device, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetPossibleResources ( + ACPI_HANDLE Device, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetEventResources ( + ACPI_HANDLE DeviceHandle, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWalkResourceBuffer ( + ACPI_BUFFER *Buffer, + ACPI_WALK_RESOURCE_CALLBACK UserFunction, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWalkResources ( + ACPI_HANDLE Device, + char *Name, + ACPI_WALK_RESOURCE_CALLBACK UserFunction, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiSetCurrentResources ( + ACPI_HANDLE Device, + ACPI_BUFFER *InBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetIrqRoutingTable ( + ACPI_HANDLE Device, + ACPI_BUFFER *RetBuffer)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiResourceToAddress64 ( + ACPI_RESOURCE *Resource, + ACPI_RESOURCE_ADDRESS64 *Out)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiBufferToResource ( + UINT8 *AmlBuffer, + UINT16 AmlBufferLength, + ACPI_RESOURCE **ResourcePtr)) + + +/* + * Hardware (ACPI device) interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiReset ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiRead ( + UINT64 *Value, + ACPI_GENERIC_ADDRESS *Reg)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiWrite ( + UINT64 Value, + ACPI_GENERIC_ADDRESS *Reg)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiReadBitRegister ( + UINT32 RegisterId, + UINT32 *ReturnValue)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiWriteBitRegister ( + UINT32 RegisterId, + UINT32 Value)) + + +/* + * Sleep/Wake interfaces + */ +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiGetSleepTypeData ( + UINT8 SleepState, + UINT8 *Slp_TypA, + UINT8 *Slp_TypB)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEnterSleepStatePrep ( + UINT8 SleepState)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiEnterSleepState ( + UINT8 SleepState)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiEnterSleepStateS4bios ( + void)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLeaveSleepStatePrep ( + UINT8 SleepState)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiLeaveSleepState ( + UINT8 SleepState)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiSetFirmwareWakingVector ( + ACPI_PHYSICAL_ADDRESS PhysicalAddress, + ACPI_PHYSICAL_ADDRESS PhysicalAddress64)) + + +/* + * ACPI Timer interfaces + */ +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTimerResolution ( + UINT32 *Resolution)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTimer ( + UINT32 *Ticks)) + +ACPI_HW_DEPENDENT_RETURN_STATUS ( +ACPI_STATUS +AcpiGetTimerDuration ( + UINT32 StartTicks, + UINT32 EndTicks, + UINT32 *TimeElapsed)) + + +/* + * Error/Warning output + */ +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(4) +void ACPI_INTERNAL_VAR_XFACE +AcpiException ( + const char *ModuleName, + UINT32 LineNumber, + ACPI_STATUS Status, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiInfo ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiBiosError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + +ACPI_MSG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(3) +void ACPI_INTERNAL_VAR_XFACE +AcpiBiosWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...)) + + +/* + * Debug output + */ +ACPI_DBG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(6) +void ACPI_INTERNAL_VAR_XFACE +AcpiDebugPrint ( + UINT32 RequestedDebugLevel, + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *Format, + ...)) + +ACPI_DBG_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(6) +void ACPI_INTERNAL_VAR_XFACE +AcpiDebugPrintRaw ( + UINT32 RequestedDebugLevel, + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + const char *Format, + ...)) + +ACPI_DBG_DEPENDENT_RETURN_VOID ( +void +AcpiTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname)) + +ACPI_APP_DEPENDENT_RETURN_VOID ( +ACPI_PRINTF_LIKE(1) +void ACPI_INTERNAL_VAR_XFACE +AcpiLogError ( + const char *Format, + ...)) + +ACPI_STATUS +AcpiInitializeDebugger ( + void); + +void +AcpiTerminateDebugger ( + void); + +void +AcpiSetDebuggerThreadId ( + ACPI_THREAD_ID ThreadId); + +#endif /* __ACXFACE_H__ */ diff --git a/third_party/lib/acpica/source/include/acpredef.h b/third_party/lib/acpica/source/include/acpredef.h new file mode 100644 index 000000000..2e95223df --- /dev/null +++ b/third_party/lib/acpica/source/include/acpredef.h @@ -0,0 +1,1119 @@ +/****************************************************************************** + * + * Name: acpredef - Information table for ACPI predefined methods and objects + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACPREDEF_H__ +#define __ACPREDEF_H__ + + +/****************************************************************************** + * + * Return Package types + * + * 1) PTYPE1 packages do not contain subpackages. + * + * ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types: + * object type + * count + * object type + * count + * + * ACPI_PTYPE1_VAR: Variable-length length. Zero-length package is allowed: + * object type (Int/Buf/Ref) + * + * ACPI_PTYPE1_OPTION: Package has some required and some optional elements + * (Used for _PRW) + * + * + * 2) PTYPE2 packages contain a Variable-length number of subpackages. Each + * of the different types describe the contents of each of the subpackages. + * + * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length + * parent package is allowed: + * object type + * count + * object type + * count + * (Used for _ALR,_MLS,_PSS,_TRT,_TSS) + * + * ACPI_PTYPE2_COUNT: Each subpackage has a count as first element. + * Zero-length parent package is allowed: + * object type + * (Used for _CSD,_PSD,_TSD) + * + * ACPI_PTYPE2_PKG_COUNT: Count of subpackages at start, 1 or 2 object types: + * object type + * count + * object type + * count + * (Used for _CST) + * + * ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length. Zero-length + * parent package is allowed. + * (Used for _PRT) + * + * ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length. + * Zero-length parent package is allowed: + * (Used for _HPX) + * + * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length + * (Used for _ART, _FPS) + * + * ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements + * followed by an optional element. Zero-length parent package is allowed. + * object type + * count + * object type + * count = 0 (optional) + * (Used for _DLM) + * + * ACPI_PTYPE2_VAR_VAR: Variable number of subpackages, each of either a + * constant or variable length. The subpackages are preceded by a + * constant number of objects. + * (Used for _LPI, _RDI) + * + * ACPI_PTYPE2_UUID_PAIR: Each subpackage is preceded by a UUID Buffer. The UUID + * defines the format of the package. Zero-length parent package is + * allowed. + * (Used for _DSD) + * + *****************************************************************************/ + +enum AcpiReturnPackageTypes +{ + ACPI_PTYPE1_FIXED = 1, + ACPI_PTYPE1_VAR = 2, + ACPI_PTYPE1_OPTION = 3, + ACPI_PTYPE2 = 4, + ACPI_PTYPE2_COUNT = 5, + ACPI_PTYPE2_PKG_COUNT = 6, + ACPI_PTYPE2_FIXED = 7, + ACPI_PTYPE2_MIN = 8, + ACPI_PTYPE2_REV_FIXED = 9, + ACPI_PTYPE2_FIX_VAR = 10, + ACPI_PTYPE2_VAR_VAR = 11, + ACPI_PTYPE2_UUID_PAIR = 12 +}; + + +/* Support macros for users of the predefined info table */ + +#define METHOD_PREDEF_ARGS_MAX 4 +#define METHOD_ARG_BIT_WIDTH 3 +#define METHOD_ARG_MASK 0x0007 +#define ARG_COUNT_IS_MINIMUM 0x8000 +#define METHOD_MAX_ARG_TYPE ACPI_TYPE_PACKAGE + +#define METHOD_GET_ARG_COUNT(ArgList) ((ArgList) & METHOD_ARG_MASK) +#define METHOD_GET_NEXT_TYPE(ArgList) (((ArgList) >>= METHOD_ARG_BIT_WIDTH) & METHOD_ARG_MASK) + +/* Macros used to build the predefined info table */ + +#define METHOD_0ARGS 0 +#define METHOD_1ARGS(a1) (1 | (a1 << 3)) +#define METHOD_2ARGS(a1,a2) (2 | (a1 << 3) | (a2 << 6)) +#define METHOD_3ARGS(a1,a2,a3) (3 | (a1 << 3) | (a2 << 6) | (a3 << 9)) +#define METHOD_4ARGS(a1,a2,a3,a4) (4 | (a1 << 3) | (a2 << 6) | (a3 << 9) | (a4 << 12)) + +#define METHOD_RETURNS(type) (type) +#define METHOD_NO_RETURN_VALUE 0 + +#define PACKAGE_INFO(a,b,c,d,e,f) {{{(a),(b),(c),(d)}, ((((UINT16)(f)) << 8) | (e)), 0}} + + +/* Support macros for the resource descriptor info table */ + +#define WIDTH_1 0x0001 +#define WIDTH_2 0x0002 +#define WIDTH_3 0x0004 +#define WIDTH_8 0x0008 +#define WIDTH_16 0x0010 +#define WIDTH_32 0x0020 +#define WIDTH_64 0x0040 +#define VARIABLE_DATA 0x0080 +#define NUM_RESOURCE_WIDTHS 8 + +#define WIDTH_ADDRESS WIDTH_16 | WIDTH_32 | WIDTH_64 + + +#ifdef ACPI_CREATE_PREDEFINED_TABLE +/****************************************************************************** + * + * Predefined method/object information table. + * + * These are the names that can actually be evaluated via AcpiEvaluateObject. + * Not present in this table are the following: + * + * 1) Predefined/Reserved names that are not usually evaluated via + * AcpiEvaluateObject: + * _Lxx and _Exx GPE methods + * _Qxx EC methods + * _T_x compiler temporary variables + * _Wxx wake events + * + * 2) Predefined names that never actually exist within the AML code: + * Predefined resource descriptor field names + * + * 3) Predefined names that are implemented within ACPICA: + * _OSI + * + * The main entries in the table each contain the following items: + * + * Name - The ACPI reserved name + * ArgumentList - Contains (in 16 bits), the number of required + * arguments to the method (3 bits), and a 3-bit type + * field for each argument (up to 4 arguments). The + * METHOD_?ARGS macros generate the correct packed data. + * ExpectedBtypes - Allowed type(s) for the return value. + * 0 means that no return value is expected. + * + * For methods that return packages, the next entry in the table contains + * information about the expected structure of the package. This information + * is saved here (rather than in a separate table) in order to minimize the + * overall size of the stored data. + * + * Note: The additional braces are intended to promote portability. + * + * Note2: Table is used by the kernel-resident subsystem, the iASL compiler, + * and the AcpiHelp utility. + * + * TBD: _PRT - currently ignore reversed entries. Attempt to fix in nsrepair. + * Possibly fixing package elements like _BIF, etc. + * + *****************************************************************************/ + +const ACPI_PREDEFINED_INFO AcpiGbl_PredefinedMethods[] = +{ + {{"_AC0", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC3", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC4", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC5", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC6", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC7", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC8", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AC9", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ADR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_AEI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_AL0", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL3", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL4", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL5", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL6", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL7", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL8", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_AL9", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_ALC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ALI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ALP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ALR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 (Ints) */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2,0,0,0), + + {{"_ALT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ART", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER, 11,0), + + {{"_BBN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BCL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_BCM", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BCT", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BDN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BFS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BIF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (9 Int),(4 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING, 4,0), + + {{"_BIX", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int),(4 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING, 4,0), + + {{"_BLT", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BMA", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BMC", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_BMD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (5 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_BMS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BQC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + {{"_BTH", METHOD_1ARGS (ACPI_TYPE_INTEGER), /* ACPI 6.0 */ + METHOD_NO_RETURN_VALUE}}, + + {{"_BTM", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_BTP", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_CBA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See PCI firmware spec 3.0 */ + + {{"_CCA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* ACPI 5.1 */ + + {{"_CDM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_CID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Strs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0,0,0), + + {{"_CLS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3,0,0,0), + + {{"_CPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Bufs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,0,0,0), + + {{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_CRS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_CRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_CSD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n-1 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_CST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER, 3,0), + + {{"_CWS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DCK", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DCS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DDC", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER)}}, + + {{"_DDN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_DEP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_DGS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_DIS", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_DLM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */ + PACKAGE_INFO (ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1, ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER, 0,0), + + {{"_DMA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_DOD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_DOS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */ + PACKAGE_INFO (ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_PACKAGE, 1,0), + + {{"_DSM", METHOD_4ARGS (ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_PACKAGE), + METHOD_RETURNS (ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */ + + {{"_DSS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_DSW", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_DTI", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EC_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_EDL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs)*/ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_EJ0", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ1", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ2", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ3", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJ4", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_EJD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_ERR", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_STRING, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* Internal use only, used by ACPICA test suites */ + + {{"_EVT", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_FDE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_FDI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0,0,0), + + {{"_FDM", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_FIF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + {{"_FIX", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_FPS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_REV_FIXED,ACPI_RTYPE_INTEGER, 5, 0,0,0), + + {{"_FSL", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_FST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3,0,0,0), + + {{"_GAI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GCP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GHL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GLK", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GPD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GPE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* _GPE method, not _GPE scope */ + + {{"_GRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_GSB", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_GTF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_GTM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_GTS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_GWS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_HID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, + + {{"_HOT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_HPP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + /* + * For _HPX, a single package is returned, containing a variable-length number + * of subpackages. Each subpackage contains a PCI record setting. + * There are several different type of record settings, of different + * lengths, but all elements of all settings are Integers. + */ + {{"_HPX", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (var Ints) */ + PACKAGE_INFO (ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_HRV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_IFT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */ + + {{"_INI", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_IRC", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_LCK", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_LID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_LPD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */ + PACKAGE_INFO (ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2,0,0,0), + + {{"_LPI", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (3 Int, n Pkg (10 Int/Buf) */ + PACKAGE_INFO (ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 3, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING, 10,0), + + {{"_MAT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_MBM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (8 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8,0,0,0), + + {{"_MLS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Str/1 Buf) */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER, 1,0), + + {{"_MSG", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_MSM", METHOD_4ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_MTL", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_NTT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_OFF", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_ON_", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_OS_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_OSC", METHOD_4ARGS (ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_OST", METHOD_3ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PAI", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PCL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PCT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0,0,0), + + {{"_PDC", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PDL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PIC", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PIF", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int),(3 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, ACPI_RTYPE_STRING, 3,0), + + {{"_PLD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Bufs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0,0,0,0), + + {{"_PMC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (11 Int),(3 Str) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11, ACPI_RTYPE_STRING, 3,0), + + {{"_PMD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PMM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PPE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See dig64 spec */ + + {{"_PR0", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PR1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PR2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PR3", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PRE", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PRL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PRR", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Ref) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_REFERENCE, 1,0,0,0), + + {{"_PRS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + /* + * For _PRT, many BIOSs reverse the 3rd and 4th Package elements (Source + * and SourceIndex). This bug is so prevalent that there is code in the + * ACPICA Resource Manager to detect this and switch them back. For now, + * do not allow and issue a warning. To allow this and eliminate the + * warning, add the ACPI_RTYPE_REFERENCE type to the 4th element (index 3) + * in the statement below. + */ + {{"_PRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */ + PACKAGE_INFO (ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER, ACPI_RTYPE_INTEGER, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, ACPI_RTYPE_INTEGER), + + {{"_PRW", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */ + PACKAGE_INFO (ACPI_PTYPE1_OPTION, 2, ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE, + ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0), + + {{"_PS0", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PS1", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PS2", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PS3", METHOD_0ARGS, + METHOD_NO_RETURN_VALUE}}, + + {{"_PSC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PSD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (5 Int) with count */ + PACKAGE_INFO (ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0,0,0), + + {{"_PSE", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PSL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_PSR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PSS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (6 Int) */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6,0,0,0), + + {{"_PSV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PSW", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PTC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0,0,0), + + {{"_PTP", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_PTS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_PUR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0,0,0), + + {{"_PXM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_RDI", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int, n Pkg (m Ref)) */ + PACKAGE_INFO (ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 1, + ACPI_RTYPE_REFERENCE,0,0), + + {{"_REG", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_REV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_RMV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_ROM", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_RST", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_NO_RETURN_VALUE}}, + + {{"_RTV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + /* + * For _S0_ through _S5_, the ACPI spec defines a return Package + * containing 1 Integer, but most DSDTs have it wrong - 2,3, or 4 integers. + * Allow this by making the objects "Variable-length length", but all elements + * must be Integers. + */ + {{"_S0_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S1_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S2_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S3_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S4_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S5_", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0,0,0), + + {{"_S1D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S2D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S3D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S4D", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S0W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S1W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S2W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S3W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_S4W", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SBS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SCP", METHOD_1ARGS (ACPI_TYPE_INTEGER) | ARG_COUNT_IS_MINIMUM, + METHOD_NO_RETURN_VALUE}}, /* Acpi 1.0 allowed 1 integer arg. Acpi 3.0 expanded to 3 args. Allow both. */ + + {{"_SDD", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_SEG", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SHL", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SLI", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_SPD", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SRS", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_SRT", METHOD_1ARGS (ACPI_TYPE_BUFFER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SRV", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */ + + {{"_SST", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_STA", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_STM", METHOD_3ARGS (ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER), + METHOD_NO_RETURN_VALUE}}, + + {{"_STP", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_STR", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_STV", METHOD_2ARGS (ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SUB", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_STRING)}}, + + {{"_SUN", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_SWS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TC1", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TC2", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TDL", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TFP", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TIP", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TIV", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TMP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TPT", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_TRT", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 Ref/6 Int */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER, 6, 0), + + {{"_TSD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int with count */ + PACKAGE_INFO (ACPI_PTYPE2_COUNT,ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_TSN", METHOD_0ARGS, /* ACPI 6.0 */ + METHOD_RETURNS (ACPI_RTYPE_REFERENCE)}}, + + {{"_TSP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TSS", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int */ + PACKAGE_INFO (ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5,0,0,0), + + {{"_TST", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_TTS", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_NO_RETURN_VALUE}}, + + {{"_TZD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ + PACKAGE_INFO (ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0,0,0), + + {{"_TZM", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_REFERENCE)}}, + + {{"_TZP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_UID", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, + + {{"_UPC", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */ + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0,0,0), + + {{"_UPD", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_UPP", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + {{"_VPO", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_INTEGER)}}, + + /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ + + {{"_WAK", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO (ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0,0,0), /* Fixed-length (2 Int), but is optional */ + + /* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */ + + {{"_WDG", METHOD_0ARGS, + METHOD_RETURNS (ACPI_RTYPE_BUFFER)}}, + + {{"_WED", METHOD_1ARGS (ACPI_TYPE_INTEGER), + METHOD_RETURNS (ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER)}}, + + PACKAGE_INFO (0,0,0,0,0,0) /* Table terminator */ +}; +#else +extern const ACPI_PREDEFINED_INFO AcpiGbl_PredefinedMethods[]; +#endif + + +#if (defined ACPI_CREATE_RESOURCE_TABLE && defined ACPI_APPLICATION) +/****************************************************************************** + * + * Predefined names for use in Resource Descriptors. These names do not + * appear in the global Predefined Name table (since these names never + * appear in actual AML byte code, only in the original ASL) + * + * Note: Used by iASL compiler and AcpiHelp utility only. + * + *****************************************************************************/ + +const ACPI_PREDEFINED_INFO AcpiGbl_ResourceNames[] = +{ + {{"_ADR", WIDTH_16 | WIDTH_64, 0}}, + {{"_ALN", WIDTH_8 | WIDTH_16 | WIDTH_32, 0}}, + {{"_ASI", WIDTH_8, 0}}, + {{"_ASZ", WIDTH_8, 0}}, + {{"_ATT", WIDTH_64, 0}}, + {{"_BAS", WIDTH_16 | WIDTH_32, 0}}, + {{"_BM_", WIDTH_1, 0}}, + {{"_DBT", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_DEC", WIDTH_1, 0}}, + {{"_DMA", WIDTH_8, 0}}, + {{"_DPL", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_DRS", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_END", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_FLC", WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_GRA", WIDTH_ADDRESS, 0}}, + {{"_HE_", WIDTH_1, 0}}, + {{"_INT", WIDTH_16 | WIDTH_32, 0}}, + {{"_IOR", WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_LEN", WIDTH_8 | WIDTH_ADDRESS, 0}}, + {{"_LIN", WIDTH_8, 0}}, /* Acpi 5.0 */ + {{"_LL_", WIDTH_1, 0}}, + {{"_MAF", WIDTH_1, 0}}, + {{"_MAX", WIDTH_ADDRESS, 0}}, + {{"_MEM", WIDTH_2, 0}}, + {{"_MIF", WIDTH_1, 0}}, + {{"_MIN", WIDTH_ADDRESS, 0}}, + {{"_MOD", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_MTP", WIDTH_2, 0}}, + {{"_PAR", WIDTH_8, 0}}, /* Acpi 5.0 */ + {{"_PHA", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_PIN", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_PPI", WIDTH_8, 0}}, /* Acpi 5.0 */ + {{"_POL", WIDTH_1 | WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_RBO", WIDTH_8, 0}}, + {{"_RBW", WIDTH_8, 0}}, + {{"_RNG", WIDTH_1, 0}}, + {{"_RT_", WIDTH_8, 0}}, /* Acpi 3.0 */ + {{"_RW_", WIDTH_1, 0}}, + {{"_RXL", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_SHR", WIDTH_2, 0}}, + {{"_SIZ", WIDTH_2, 0}}, + {{"_SLV", WIDTH_1, 0}}, /* Acpi 5.0 */ + {{"_SPE", WIDTH_32, 0}}, /* Acpi 5.0 */ + {{"_STB", WIDTH_2, 0}}, /* Acpi 5.0 */ + {{"_TRA", WIDTH_ADDRESS, 0}}, + {{"_TRS", WIDTH_1, 0}}, + {{"_TSF", WIDTH_8, 0}}, /* Acpi 3.0 */ + {{"_TTP", WIDTH_1, 0}}, + {{"_TXL", WIDTH_16, 0}}, /* Acpi 5.0 */ + {{"_TYP", WIDTH_2 | WIDTH_16, 0}}, + {{"_VEN", VARIABLE_DATA, 0}}, /* Acpi 5.0 */ + PACKAGE_INFO (0,0,0,0,0,0) /* Table terminator */ +}; + +static const ACPI_PREDEFINED_INFO AcpiGbl_ScopeNames[] = { + {{"_GPE", 0, 0}}, + {{"_PR_", 0, 0}}, + {{"_SB_", 0, 0}}, + {{"_SI_", 0, 0}}, + {{"_TZ_", 0, 0}}, + PACKAGE_INFO (0,0,0,0,0,0) /* Table terminator */ +}; +#else +extern const ACPI_PREDEFINED_INFO AcpiGbl_ResourceNames[]; +#endif + +#endif diff --git a/third_party/lib/acpica/source/include/acresrc.h b/third_party/lib/acpica/source/include/acresrc.h new file mode 100644 index 000000000..cbce5dea6 --- /dev/null +++ b/third_party/lib/acpica/source/include/acresrc.h @@ -0,0 +1,442 @@ +/****************************************************************************** + * + * Name: acresrc.h - Resource Manager function prototypes + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACRESRC_H__ +#define __ACRESRC_H__ + +/* Need the AML resource descriptor structs */ + +#include "amlresrc.h" + + +/* + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures + */ +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) +#pragma pack(1) +#endif + +/* + * Individual entry for the resource conversion tables + */ +typedef const struct acpi_rsconvert_info +{ + UINT8 Opcode; + UINT8 ResourceOffset; + UINT8 AmlOffset; + UINT8 Value; + +} ACPI_RSCONVERT_INFO; + +/* Resource conversion opcodes */ + +typedef enum +{ + ACPI_RSC_INITGET = 0, + ACPI_RSC_INITSET, + ACPI_RSC_FLAGINIT, + ACPI_RSC_1BITFLAG, + ACPI_RSC_2BITFLAG, + ACPI_RSC_3BITFLAG, + ACPI_RSC_ADDRESS, + ACPI_RSC_BITMASK, + ACPI_RSC_BITMASK16, + ACPI_RSC_COUNT, + ACPI_RSC_COUNT16, + ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RSC_COUNT_GPIO_RES, + ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RSC_DATA8, + ACPI_RSC_EXIT_EQ, + ACPI_RSC_EXIT_LE, + ACPI_RSC_EXIT_NE, + ACPI_RSC_LENGTH, + ACPI_RSC_MOVE_GPIO_PIN, + ACPI_RSC_MOVE_GPIO_RES, + ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RSC_MOVE8, + ACPI_RSC_MOVE16, + ACPI_RSC_MOVE32, + ACPI_RSC_MOVE64, + ACPI_RSC_SET8, + ACPI_RSC_SOURCE, + ACPI_RSC_SOURCEX + +} ACPI_RSCONVERT_OPCODES; + +/* Resource Conversion sub-opcodes */ + +#define ACPI_RSC_COMPARE_AML_LENGTH 0 +#define ACPI_RSC_COMPARE_VALUE 1 + +#define ACPI_RSC_TABLE_SIZE(d) (sizeof (d) / sizeof (ACPI_RSCONVERT_INFO)) + +#define ACPI_RS_OFFSET(f) (UINT8) ACPI_OFFSET (ACPI_RESOURCE,f) +#define AML_OFFSET(f) (UINT8) ACPI_OFFSET (AML_RESOURCE,f) + + +/* + * Individual entry for the resource dump tables + */ +typedef const struct acpi_rsdump_info +{ + UINT8 Opcode; + UINT8 Offset; + char *Name; + const char **Pointer; + +} ACPI_RSDUMP_INFO; + +/* Values for the Opcode field above */ + +typedef enum +{ + ACPI_RSD_TITLE = 0, + ACPI_RSD_1BITFLAG, + ACPI_RSD_2BITFLAG, + ACPI_RSD_3BITFLAG, + ACPI_RSD_ADDRESS, + ACPI_RSD_DWORDLIST, + ACPI_RSD_LITERAL, + ACPI_RSD_LONGLIST, + ACPI_RSD_SHORTLIST, + ACPI_RSD_SHORTLISTX, + ACPI_RSD_SOURCE, + ACPI_RSD_STRING, + ACPI_RSD_UINT8, + ACPI_RSD_UINT16, + ACPI_RSD_UINT32, + ACPI_RSD_UINT64, + ACPI_RSD_WORDLIST + +} ACPI_RSDUMP_OPCODES; + +/* restore default alignment */ + +#pragma pack() + + +/* Resource tables indexed by internal resource type */ + +extern const UINT8 AcpiGbl_AmlResourceSizes[]; +extern const UINT8 AcpiGbl_AmlResourceSerialBusSizes[]; +extern ACPI_RSCONVERT_INFO *AcpiGbl_SetResourceDispatch[]; + +/* Resource tables indexed by raw AML resource descriptor type */ + +extern const UINT8 AcpiGbl_ResourceStructSizes[]; +extern const UINT8 AcpiGbl_ResourceStructSerialBusSizes[]; +extern ACPI_RSCONVERT_INFO *AcpiGbl_GetResourceDispatch[]; + +extern ACPI_RSCONVERT_INFO *AcpiGbl_ConvertResourceSerialBusDispatch[]; + +typedef struct acpi_vendor_walk_info +{ + ACPI_VENDOR_UUID *Uuid; + ACPI_BUFFER *Buffer; + ACPI_STATUS Status; + +} ACPI_VENDOR_WALK_INFO; + + +/* + * rscreate + */ +ACPI_STATUS +AcpiRsCreateResourceList ( + ACPI_OPERAND_OBJECT *AmlBuffer, + ACPI_BUFFER *OutputBuffer); + +ACPI_STATUS +AcpiRsCreateAmlResources ( + ACPI_BUFFER *ResourceList, + ACPI_BUFFER *OutputBuffer); + +ACPI_STATUS +AcpiRsCreatePciRoutingTable ( + ACPI_OPERAND_OBJECT *PackageObject, + ACPI_BUFFER *OutputBuffer); + + +/* + * rsutils + */ +ACPI_STATUS +AcpiRsGetPrtMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetCrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetPrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetMethodData ( + ACPI_HANDLE Handle, + char *Path, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsSetSrsMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiRsGetAeiMethodData ( + ACPI_NAMESPACE_NODE *Node, + ACPI_BUFFER *RetBuffer); + +/* + * rscalc + */ +ACPI_STATUS +AcpiRsGetListLength ( + UINT8 *AmlBuffer, + UINT32 AmlBufferLength, + ACPI_SIZE *SizeNeeded); + +ACPI_STATUS +AcpiRsGetAmlLength ( + ACPI_RESOURCE *ResourceList, + ACPI_SIZE ResourceListSize, + ACPI_SIZE *SizeNeeded); + +ACPI_STATUS +AcpiRsGetPciRoutingTableLength ( + ACPI_OPERAND_OBJECT *PackageObject, + ACPI_SIZE *BufferSizeNeeded); + +ACPI_STATUS +AcpiRsConvertAmlToResources ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context); + +ACPI_STATUS +AcpiRsConvertResourcesToAml ( + ACPI_RESOURCE *Resource, + ACPI_SIZE AmlSizeNeeded, + UINT8 *OutputBuffer); + + +/* + * rsaddr + */ +void +AcpiRsSetAddressCommon ( + AML_RESOURCE *Aml, + ACPI_RESOURCE *Resource); + +BOOLEAN +AcpiRsGetAddressCommon ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml); + + +/* + * rsmisc + */ +ACPI_STATUS +AcpiRsConvertAmlToResource ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml, + ACPI_RSCONVERT_INFO *Info); + +ACPI_STATUS +AcpiRsConvertResourceToAml ( + ACPI_RESOURCE *Resource, + AML_RESOURCE *Aml, + ACPI_RSCONVERT_INFO *Info); + + +/* + * rsutils + */ +void +AcpiRsMoveData ( + void *Destination, + void *Source, + UINT16 ItemCount, + UINT8 MoveType); + +UINT8 +AcpiRsDecodeBitmask ( + UINT16 Mask, + UINT8 *List); + +UINT16 +AcpiRsEncodeBitmask ( + UINT8 *List, + UINT8 Count); + +ACPI_RS_LENGTH +AcpiRsGetResourceSource ( + ACPI_RS_LENGTH ResourceLength, + ACPI_RS_LENGTH MinimumLength, + ACPI_RESOURCE_SOURCE *ResourceSource, + AML_RESOURCE *Aml, + char *StringPtr); + +ACPI_RSDESC_SIZE +AcpiRsSetResourceSource ( + AML_RESOURCE *Aml, + ACPI_RS_LENGTH MinimumLength, + ACPI_RESOURCE_SOURCE *ResourceSource); + +void +AcpiRsSetResourceHeader ( + UINT8 DescriptorType, + ACPI_RSDESC_SIZE TotalLength, + AML_RESOURCE *Aml); + +void +AcpiRsSetResourceLength ( + ACPI_RSDESC_SIZE TotalLength, + AML_RESOURCE *Aml); + + +/* + * rsdump - Debugger support + */ +#ifdef ACPI_DEBUGGER +void +AcpiRsDumpResourceList ( + ACPI_RESOURCE *Resource); + +void +AcpiRsDumpIrqList ( + UINT8 *RouteTable); +#endif + + +/* + * Resource conversion tables + */ +extern ACPI_RSCONVERT_INFO AcpiRsConvertDma[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertEndDpf[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertIo[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertFixedIo[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertEndTag[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertMemory24[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertGenericReg[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertMemory32[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertFixedMemory32[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertAddress32[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertAddress16[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertExtIrq[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertAddress64[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertExtAddress64[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertGpio[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertFixedDma[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertI2cSerialBus[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertSpiSerialBus[]; +extern ACPI_RSCONVERT_INFO AcpiRsConvertUartSerialBus[]; + +/* These resources require separate get/set tables */ + +extern ACPI_RSCONVERT_INFO AcpiRsGetIrq[]; +extern ACPI_RSCONVERT_INFO AcpiRsGetStartDpf[]; +extern ACPI_RSCONVERT_INFO AcpiRsGetVendorSmall[]; +extern ACPI_RSCONVERT_INFO AcpiRsGetVendorLarge[]; + +extern ACPI_RSCONVERT_INFO AcpiRsSetIrq[]; +extern ACPI_RSCONVERT_INFO AcpiRsSetStartDpf[]; +extern ACPI_RSCONVERT_INFO AcpiRsSetVendor[]; + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* + * rsinfo + */ +extern ACPI_RSDUMP_INFO *AcpiGbl_DumpResourceDispatch[]; +extern ACPI_RSDUMP_INFO *AcpiGbl_DumpSerialBusDispatch[]; + +/* + * rsdumpinfo + */ +extern ACPI_RSDUMP_INFO AcpiRsDumpIrq[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpPrt[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpDma[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpStartDpf[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpEndDpf[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpIo[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpIoFlags[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpFixedIo[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpVendor[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpEndTag[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpMemory24[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpMemory32[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpMemoryFlags[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpFixedMemory32[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpAddress16[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpAddress32[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpAddress64[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpExtAddress64[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpExtIrq[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpGenericReg[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpGpio[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpFixedDma[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpCommonSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpI2cSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpSpiSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpUartSerialBus[]; +extern ACPI_RSDUMP_INFO AcpiRsDumpGeneralFlags[]; +#endif + +#endif /* __ACRESRC_H__ */ diff --git a/third_party/lib/acpica/source/include/acrestyp.h b/third_party/lib/acpica/source/include/acrestyp.h new file mode 100644 index 000000000..feec49803 --- /dev/null +++ b/third_party/lib/acpica/source/include/acrestyp.h @@ -0,0 +1,714 @@ +/****************************************************************************** + * + * Name: acrestyp.h - Defines, types, and structures for resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACRESTYP_H__ +#define __ACRESTYP_H__ + + +/* + * Definitions for Resource Attributes + */ +typedef UINT16 ACPI_RS_LENGTH; /* Resource Length field is fixed at 16 bits */ +typedef UINT32 ACPI_RSDESC_SIZE; /* Max Resource Descriptor size is (Length+3) = (64K-1)+3 */ + +/* + * Memory Attributes + */ +#define ACPI_READ_ONLY_MEMORY (UINT8) 0x00 +#define ACPI_READ_WRITE_MEMORY (UINT8) 0x01 + +#define ACPI_NON_CACHEABLE_MEMORY (UINT8) 0x00 +#define ACPI_CACHABLE_MEMORY (UINT8) 0x01 +#define ACPI_WRITE_COMBINING_MEMORY (UINT8) 0x02 +#define ACPI_PREFETCHABLE_MEMORY (UINT8) 0x03 + +/*! [Begin] no source code translation */ +/* + * IO Attributes + * The ISA IO ranges are: n000-n0FFh, n400-n4FFh, n800-n8FFh, nC00-nCFFh. + * The non-ISA IO ranges are: n100-n3FFh, n500-n7FFh, n900-nBFFh, nCD0-nFFFh. + */ +/*! [End] no source code translation !*/ + +#define ACPI_NON_ISA_ONLY_RANGES (UINT8) 0x01 +#define ACPI_ISA_ONLY_RANGES (UINT8) 0x02 +#define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) + +/* Type of translation - 1=Sparse, 0=Dense */ + +#define ACPI_SPARSE_TRANSLATION (UINT8) 0x01 + +/* + * IO Port Descriptor Decode + */ +#define ACPI_DECODE_10 (UINT8) 0x00 /* 10-bit IO address decode */ +#define ACPI_DECODE_16 (UINT8) 0x01 /* 16-bit IO address decode */ + +/* + * Interrupt attributes - used in multiple descriptors + */ + +/* Triggering */ + +#define ACPI_LEVEL_SENSITIVE (UINT8) 0x00 +#define ACPI_EDGE_SENSITIVE (UINT8) 0x01 + +/* Polarity */ + +#define ACPI_ACTIVE_HIGH (UINT8) 0x00 +#define ACPI_ACTIVE_LOW (UINT8) 0x01 +#define ACPI_ACTIVE_BOTH (UINT8) 0x02 + +/* Sharing */ + +#define ACPI_EXCLUSIVE (UINT8) 0x00 +#define ACPI_SHARED (UINT8) 0x01 + +/* Wake */ + +#define ACPI_NOT_WAKE_CAPABLE (UINT8) 0x00 +#define ACPI_WAKE_CAPABLE (UINT8) 0x01 + +/* + * DMA Attributes + */ +#define ACPI_COMPATIBILITY (UINT8) 0x00 +#define ACPI_TYPE_A (UINT8) 0x01 +#define ACPI_TYPE_B (UINT8) 0x02 +#define ACPI_TYPE_F (UINT8) 0x03 + +#define ACPI_NOT_BUS_MASTER (UINT8) 0x00 +#define ACPI_BUS_MASTER (UINT8) 0x01 + +#define ACPI_TRANSFER_8 (UINT8) 0x00 +#define ACPI_TRANSFER_8_16 (UINT8) 0x01 +#define ACPI_TRANSFER_16 (UINT8) 0x02 + +/* + * Start Dependent Functions Priority definitions + */ +#define ACPI_GOOD_CONFIGURATION (UINT8) 0x00 +#define ACPI_ACCEPTABLE_CONFIGURATION (UINT8) 0x01 +#define ACPI_SUB_OPTIMAL_CONFIGURATION (UINT8) 0x02 + +/* + * 16, 32 and 64-bit Address Descriptor resource types + */ +#define ACPI_MEMORY_RANGE (UINT8) 0x00 +#define ACPI_IO_RANGE (UINT8) 0x01 +#define ACPI_BUS_NUMBER_RANGE (UINT8) 0x02 + +#define ACPI_ADDRESS_NOT_FIXED (UINT8) 0x00 +#define ACPI_ADDRESS_FIXED (UINT8) 0x01 + +#define ACPI_POS_DECODE (UINT8) 0x00 +#define ACPI_SUB_DECODE (UINT8) 0x01 + +/* Producer/Consumer */ + +#define ACPI_PRODUCER (UINT8) 0x00 +#define ACPI_CONSUMER (UINT8) 0x01 + + +/* + * If possible, pack the following structures to byte alignment + */ +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#pragma pack(1) +#endif + +/* UUID data structures for use in vendor-defined resource descriptors */ + +typedef struct acpi_uuid +{ + UINT8 Data[ACPI_UUID_LENGTH]; +} ACPI_UUID; + +typedef struct acpi_vendor_uuid +{ + UINT8 Subtype; + UINT8 Data[ACPI_UUID_LENGTH]; + +} ACPI_VENDOR_UUID; + +/* + * Structures used to describe device resources + */ +typedef struct acpi_resource_irq +{ + UINT8 DescriptorLength; + UINT8 Triggering; + UINT8 Polarity; + UINT8 Sharable; + UINT8 WakeCapable; + UINT8 InterruptCount; + UINT8 Interrupts[1]; + +} ACPI_RESOURCE_IRQ; + +typedef struct acpi_resource_dma +{ + UINT8 Type; + UINT8 BusMaster; + UINT8 Transfer; + UINT8 ChannelCount; + UINT8 Channels[1]; + +} ACPI_RESOURCE_DMA; + +typedef struct acpi_resource_start_dependent +{ + UINT8 DescriptorLength; + UINT8 CompatibilityPriority; + UINT8 PerformanceRobustness; + +} ACPI_RESOURCE_START_DEPENDENT; + + +/* + * The END_DEPENDENT_FUNCTIONS_RESOURCE struct is not + * needed because it has no fields + */ + + +typedef struct acpi_resource_io +{ + UINT8 IoDecode; + UINT8 Alignment; + UINT8 AddressLength; + UINT16 Minimum; + UINT16 Maximum; + +} ACPI_RESOURCE_IO; + +typedef struct acpi_resource_fixed_io +{ + UINT16 Address; + UINT8 AddressLength; + +} ACPI_RESOURCE_FIXED_IO; + +typedef struct acpi_resource_fixed_dma +{ + UINT16 RequestLines; + UINT16 Channels; + UINT8 Width; + +} ACPI_RESOURCE_FIXED_DMA; + +/* Values for Width field above */ + +#define ACPI_DMA_WIDTH8 0 +#define ACPI_DMA_WIDTH16 1 +#define ACPI_DMA_WIDTH32 2 +#define ACPI_DMA_WIDTH64 3 +#define ACPI_DMA_WIDTH128 4 +#define ACPI_DMA_WIDTH256 5 + + +typedef struct acpi_resource_vendor +{ + UINT16 ByteLength; + UINT8 ByteData[1]; + +} ACPI_RESOURCE_VENDOR; + +/* Vendor resource with UUID info (introduced in ACPI 3.0) */ + +typedef struct acpi_resource_vendor_typed +{ + UINT16 ByteLength; + UINT8 UuidSubtype; + UINT8 Uuid[ACPI_UUID_LENGTH]; + UINT8 ByteData[1]; + +} ACPI_RESOURCE_VENDOR_TYPED; + +typedef struct acpi_resource_end_tag +{ + UINT8 Checksum; + +} ACPI_RESOURCE_END_TAG; + +typedef struct acpi_resource_memory24 +{ + UINT8 WriteProtect; + UINT16 Minimum; + UINT16 Maximum; + UINT16 Alignment; + UINT16 AddressLength; + +} ACPI_RESOURCE_MEMORY24; + +typedef struct acpi_resource_memory32 +{ + UINT8 WriteProtect; + UINT32 Minimum; + UINT32 Maximum; + UINT32 Alignment; + UINT32 AddressLength; + +} ACPI_RESOURCE_MEMORY32; + +typedef struct acpi_resource_fixed_memory32 +{ + UINT8 WriteProtect; + UINT32 Address; + UINT32 AddressLength; + +} ACPI_RESOURCE_FIXED_MEMORY32; + +typedef struct acpi_memory_attribute +{ + UINT8 WriteProtect; + UINT8 Caching; + UINT8 RangeType; + UINT8 Translation; + +} ACPI_MEMORY_ATTRIBUTE; + +typedef struct acpi_io_attribute +{ + UINT8 RangeType; + UINT8 Translation; + UINT8 TranslationType; + UINT8 Reserved1; + +} ACPI_IO_ATTRIBUTE; + +typedef union acpi_resource_attribute +{ + ACPI_MEMORY_ATTRIBUTE Mem; + ACPI_IO_ATTRIBUTE Io; + + /* Used for the *WordSpace macros */ + + UINT8 TypeSpecific; + +} ACPI_RESOURCE_ATTRIBUTE; + +typedef struct acpi_resource_source +{ + UINT8 Index; + UINT16 StringLength; + char *StringPtr; + +} ACPI_RESOURCE_SOURCE; + +/* Fields common to all address descriptors, 16/32/64 bit */ + +#define ACPI_RESOURCE_ADDRESS_COMMON \ + UINT8 ResourceType; \ + UINT8 ProducerConsumer; \ + UINT8 Decode; \ + UINT8 MinAddressFixed; \ + UINT8 MaxAddressFixed; \ + ACPI_RESOURCE_ATTRIBUTE Info; + +typedef struct acpi_address16_attribute +{ + UINT16 Granularity; + UINT16 Minimum; + UINT16 Maximum; + UINT16 TranslationOffset; + UINT16 AddressLength; + +} ACPI_ADDRESS16_ATTRIBUTE; + +typedef struct acpi_address32_attribute +{ + UINT32 Granularity; + UINT32 Minimum; + UINT32 Maximum; + UINT32 TranslationOffset; + UINT32 AddressLength; + +} ACPI_ADDRESS32_ATTRIBUTE; + +typedef struct acpi_address64_attribute +{ + UINT64 Granularity; + UINT64 Minimum; + UINT64 Maximum; + UINT64 TranslationOffset; + UINT64 AddressLength; + +} ACPI_ADDRESS64_ATTRIBUTE; + +typedef struct acpi_resource_address +{ + ACPI_RESOURCE_ADDRESS_COMMON + +} ACPI_RESOURCE_ADDRESS; + +typedef struct acpi_resource_address16 +{ + ACPI_RESOURCE_ADDRESS_COMMON + ACPI_ADDRESS16_ATTRIBUTE Address; + ACPI_RESOURCE_SOURCE ResourceSource; + +} ACPI_RESOURCE_ADDRESS16; + +typedef struct acpi_resource_address32 +{ + ACPI_RESOURCE_ADDRESS_COMMON + ACPI_ADDRESS32_ATTRIBUTE Address; + ACPI_RESOURCE_SOURCE ResourceSource; + +} ACPI_RESOURCE_ADDRESS32; + +typedef struct acpi_resource_address64 +{ + ACPI_RESOURCE_ADDRESS_COMMON + ACPI_ADDRESS64_ATTRIBUTE Address; + ACPI_RESOURCE_SOURCE ResourceSource; + +} ACPI_RESOURCE_ADDRESS64; + +typedef struct acpi_resource_extended_address64 +{ + ACPI_RESOURCE_ADDRESS_COMMON + UINT8 RevisionID; + ACPI_ADDRESS64_ATTRIBUTE Address; + UINT64 TypeSpecific; + +} ACPI_RESOURCE_EXTENDED_ADDRESS64; + +typedef struct acpi_resource_extended_irq +{ + UINT8 ProducerConsumer; + UINT8 Triggering; + UINT8 Polarity; + UINT8 Sharable; + UINT8 WakeCapable; + UINT8 InterruptCount; + ACPI_RESOURCE_SOURCE ResourceSource; + UINT32 Interrupts[1]; + +} ACPI_RESOURCE_EXTENDED_IRQ; + +typedef struct acpi_resource_generic_register +{ + UINT8 SpaceId; + UINT8 BitWidth; + UINT8 BitOffset; + UINT8 AccessSize; + UINT64 Address; + +} ACPI_RESOURCE_GENERIC_REGISTER; + +typedef struct acpi_resource_gpio +{ + UINT8 RevisionId; + UINT8 ConnectionType; + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */ + UINT8 PinConfig; + UINT8 Sharable; /* For values, see Interrupt Attributes above */ + UINT8 WakeCapable; /* For values, see Interrupt Attributes above */ + UINT8 IoRestriction; + UINT8 Triggering; /* For values, see Interrupt Attributes above */ + UINT8 Polarity; /* For values, see Interrupt Attributes above */ + UINT16 DriveStrength; + UINT16 DebounceTimeout; + UINT16 PinTableLength; + UINT16 VendorLength; + ACPI_RESOURCE_SOURCE ResourceSource; + UINT16 *PinTable; + UINT8 *VendorData; + +} ACPI_RESOURCE_GPIO; + +/* Values for GPIO ConnectionType field above */ + +#define ACPI_RESOURCE_GPIO_TYPE_INT 0 +#define ACPI_RESOURCE_GPIO_TYPE_IO 1 + +/* Values for PinConfig field above */ + +#define ACPI_PIN_CONFIG_DEFAULT 0 +#define ACPI_PIN_CONFIG_PULLUP 1 +#define ACPI_PIN_CONFIG_PULLDOWN 2 +#define ACPI_PIN_CONFIG_NOPULL 3 + +/* Values for IoRestriction field above */ + +#define ACPI_IO_RESTRICT_NONE 0 +#define ACPI_IO_RESTRICT_INPUT 1 +#define ACPI_IO_RESTRICT_OUTPUT 2 +#define ACPI_IO_RESTRICT_NONE_PRESERVE 3 + + +/* Common structure for I2C, SPI, and UART serial descriptors */ + +#define ACPI_RESOURCE_SERIAL_COMMON \ + UINT8 RevisionId; \ + UINT8 Type; \ + UINT8 ProducerConsumer; /* For values, see Producer/Consumer above */\ + UINT8 SlaveMode; \ + UINT8 TypeRevisionId; \ + UINT16 TypeDataLength; \ + UINT16 VendorLength; \ + ACPI_RESOURCE_SOURCE ResourceSource; \ + UINT8 *VendorData; + +typedef struct acpi_resource_common_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + +} ACPI_RESOURCE_COMMON_SERIALBUS; + +/* Values for the Type field above */ + +#define ACPI_RESOURCE_SERIAL_TYPE_I2C 1 +#define ACPI_RESOURCE_SERIAL_TYPE_SPI 2 +#define ACPI_RESOURCE_SERIAL_TYPE_UART 3 + +/* Values for SlaveMode field above */ + +#define ACPI_CONTROLLER_INITIATED 0 +#define ACPI_DEVICE_INITIATED 1 + + +typedef struct acpi_resource_i2c_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + UINT8 AccessMode; + UINT16 SlaveAddress; + UINT32 ConnectionSpeed; + +} ACPI_RESOURCE_I2C_SERIALBUS; + +/* Values for AccessMode field above */ + +#define ACPI_I2C_7BIT_MODE 0 +#define ACPI_I2C_10BIT_MODE 1 + + +typedef struct acpi_resource_spi_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + UINT8 WireMode; + UINT8 DevicePolarity; + UINT8 DataBitLength; + UINT8 ClockPhase; + UINT8 ClockPolarity; + UINT16 DeviceSelection; + UINT32 ConnectionSpeed; + +} ACPI_RESOURCE_SPI_SERIALBUS; + +/* Values for WireMode field above */ + +#define ACPI_SPI_4WIRE_MODE 0 +#define ACPI_SPI_3WIRE_MODE 1 + +/* Values for DevicePolarity field above */ + +#define ACPI_SPI_ACTIVE_LOW 0 +#define ACPI_SPI_ACTIVE_HIGH 1 + +/* Values for ClockPhase field above */ + +#define ACPI_SPI_FIRST_PHASE 0 +#define ACPI_SPI_SECOND_PHASE 1 + +/* Values for ClockPolarity field above */ + +#define ACPI_SPI_START_LOW 0 +#define ACPI_SPI_START_HIGH 1 + + +typedef struct acpi_resource_uart_serialbus +{ + ACPI_RESOURCE_SERIAL_COMMON + UINT8 Endian; + UINT8 DataBits; + UINT8 StopBits; + UINT8 FlowControl; + UINT8 Parity; + UINT8 LinesEnabled; + UINT16 RxFifoSize; + UINT16 TxFifoSize; + UINT32 DefaultBaudRate; + +} ACPI_RESOURCE_UART_SERIALBUS; + +/* Values for Endian field above */ + +#define ACPI_UART_LITTLE_ENDIAN 0 +#define ACPI_UART_BIG_ENDIAN 1 + +/* Values for DataBits field above */ + +#define ACPI_UART_5_DATA_BITS 0 +#define ACPI_UART_6_DATA_BITS 1 +#define ACPI_UART_7_DATA_BITS 2 +#define ACPI_UART_8_DATA_BITS 3 +#define ACPI_UART_9_DATA_BITS 4 + +/* Values for StopBits field above */ + +#define ACPI_UART_NO_STOP_BITS 0 +#define ACPI_UART_1_STOP_BIT 1 +#define ACPI_UART_1P5_STOP_BITS 2 +#define ACPI_UART_2_STOP_BITS 3 + +/* Values for FlowControl field above */ + +#define ACPI_UART_FLOW_CONTROL_NONE 0 +#define ACPI_UART_FLOW_CONTROL_HW 1 +#define ACPI_UART_FLOW_CONTROL_XON_XOFF 2 + +/* Values for Parity field above */ + +#define ACPI_UART_PARITY_NONE 0 +#define ACPI_UART_PARITY_EVEN 1 +#define ACPI_UART_PARITY_ODD 2 +#define ACPI_UART_PARITY_MARK 3 +#define ACPI_UART_PARITY_SPACE 4 + +/* Values for LinesEnabled bitfield above */ + +#define ACPI_UART_CARRIER_DETECT (1<<2) +#define ACPI_UART_RING_INDICATOR (1<<3) +#define ACPI_UART_DATA_SET_READY (1<<4) +#define ACPI_UART_DATA_TERMINAL_READY (1<<5) +#define ACPI_UART_CLEAR_TO_SEND (1<<6) +#define ACPI_UART_REQUEST_TO_SEND (1<<7) + + +/* ACPI_RESOURCE_TYPEs */ + +#define ACPI_RESOURCE_TYPE_IRQ 0 +#define ACPI_RESOURCE_TYPE_DMA 1 +#define ACPI_RESOURCE_TYPE_START_DEPENDENT 2 +#define ACPI_RESOURCE_TYPE_END_DEPENDENT 3 +#define ACPI_RESOURCE_TYPE_IO 4 +#define ACPI_RESOURCE_TYPE_FIXED_IO 5 +#define ACPI_RESOURCE_TYPE_VENDOR 6 +#define ACPI_RESOURCE_TYPE_END_TAG 7 +#define ACPI_RESOURCE_TYPE_MEMORY24 8 +#define ACPI_RESOURCE_TYPE_MEMORY32 9 +#define ACPI_RESOURCE_TYPE_FIXED_MEMORY32 10 +#define ACPI_RESOURCE_TYPE_ADDRESS16 11 +#define ACPI_RESOURCE_TYPE_ADDRESS32 12 +#define ACPI_RESOURCE_TYPE_ADDRESS64 13 +#define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 14 /* ACPI 3.0 */ +#define ACPI_RESOURCE_TYPE_EXTENDED_IRQ 15 +#define ACPI_RESOURCE_TYPE_GENERIC_REGISTER 16 +#define ACPI_RESOURCE_TYPE_GPIO 17 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_FIXED_DMA 18 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_SERIAL_BUS 19 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_MAX 19 + +/* Master union for resource descriptors */ + +typedef union acpi_resource_data +{ + ACPI_RESOURCE_IRQ Irq; + ACPI_RESOURCE_DMA Dma; + ACPI_RESOURCE_START_DEPENDENT StartDpf; + ACPI_RESOURCE_IO Io; + ACPI_RESOURCE_FIXED_IO FixedIo; + ACPI_RESOURCE_FIXED_DMA FixedDma; + ACPI_RESOURCE_VENDOR Vendor; + ACPI_RESOURCE_VENDOR_TYPED VendorTyped; + ACPI_RESOURCE_END_TAG EndTag; + ACPI_RESOURCE_MEMORY24 Memory24; + ACPI_RESOURCE_MEMORY32 Memory32; + ACPI_RESOURCE_FIXED_MEMORY32 FixedMemory32; + ACPI_RESOURCE_ADDRESS16 Address16; + ACPI_RESOURCE_ADDRESS32 Address32; + ACPI_RESOURCE_ADDRESS64 Address64; + ACPI_RESOURCE_EXTENDED_ADDRESS64 ExtAddress64; + ACPI_RESOURCE_EXTENDED_IRQ ExtendedIrq; + ACPI_RESOURCE_GENERIC_REGISTER GenericReg; + ACPI_RESOURCE_GPIO Gpio; + ACPI_RESOURCE_I2C_SERIALBUS I2cSerialBus; + ACPI_RESOURCE_SPI_SERIALBUS SpiSerialBus; + ACPI_RESOURCE_UART_SERIALBUS UartSerialBus; + ACPI_RESOURCE_COMMON_SERIALBUS CommonSerialBus; + + /* Common fields */ + + ACPI_RESOURCE_ADDRESS Address; /* Common 16/32/64 address fields */ + +} ACPI_RESOURCE_DATA; + + +/* Common resource header */ + +typedef struct acpi_resource +{ + UINT32 Type; + UINT32 Length; + ACPI_RESOURCE_DATA Data; + +} ACPI_RESOURCE; + +/* restore default alignment */ + +#pragma pack() + + +#define ACPI_RS_SIZE_NO_DATA 8 /* Id + Length fields */ +#define ACPI_RS_SIZE_MIN (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (12) +#define ACPI_RS_SIZE(Type) (UINT32) (ACPI_RS_SIZE_NO_DATA + sizeof (Type)) + +/* Macro for walking resource templates with multiple descriptors */ + +#define ACPI_NEXT_RESOURCE(Res) \ + ACPI_ADD_PTR (ACPI_RESOURCE, (Res), (Res)->Length) + + +typedef struct acpi_pci_routing_table +{ + UINT32 Length; + UINT32 Pin; + UINT64 Address; /* here for 64-bit alignment */ + UINT32 SourceIndex; + char Source[4]; /* pad to 64 bits so sizeof() works in all cases */ + +} ACPI_PCI_ROUTING_TABLE; + +#endif /* __ACRESTYP_H__ */ diff --git a/third_party/lib/acpica/source/include/acstruct.h b/third_party/lib/acpica/source/include/acstruct.h new file mode 100644 index 000000000..e1d8fa58d --- /dev/null +++ b/third_party/lib/acpica/source/include/acstruct.h @@ -0,0 +1,269 @@ +/****************************************************************************** + * + * Name: acstruct.h - Internal structs + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACSTRUCT_H__ +#define __ACSTRUCT_H__ + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +/***************************************************************************** + * + * Tree walking typedefs and structs + * + ****************************************************************************/ + + +/* + * Walk state - current state of a parse tree walk. Used for both a leisurely + * stroll through the tree (for whatever reason), and for control method + * execution. + */ +#define ACPI_NEXT_OP_DOWNWARD 1 +#define ACPI_NEXT_OP_UPWARD 2 + +/* + * Groups of definitions for WalkType used for different implementations of + * walkers (never simultaneously) - flags for interpreter: + */ +#define ACPI_WALK_NON_METHOD 0 +#define ACPI_WALK_METHOD 0x01 +#define ACPI_WALK_METHOD_RESTART 0x02 + + +typedef struct acpi_walk_state +{ + struct acpi_walk_state *Next; /* Next WalkState in list */ + UINT8 DescriptorType; /* To differentiate various internal objs */ + UINT8 WalkType; + UINT16 Opcode; /* Current AML opcode */ + UINT8 NextOpInfo; /* Info about NextOp */ + UINT8 NumOperands; /* Stack pointer for Operands[] array */ + UINT8 OperandIndex; /* Index into operand stack, to be used by AcpiDsObjStackPush */ + ACPI_OWNER_ID OwnerId; /* Owner of objects created during the walk */ + BOOLEAN LastPredicate; /* Result of last predicate */ + UINT8 CurrentResult; + UINT8 ReturnUsed; + UINT8 ScopeDepth; + UINT8 PassNumber; /* Parse pass during table load */ + BOOLEAN NamespaceOverride; /* Override existing objects */ + UINT8 ResultSize; /* Total elements for the result stack */ + UINT8 ResultCount; /* Current number of occupied elements of result stack */ + UINT8 *Aml; + UINT32 ArgTypes; + UINT32 MethodBreakpoint; /* For single stepping */ + UINT32 UserBreakpoint; /* User AML breakpoint */ + UINT32 ParseFlags; + + ACPI_PARSE_STATE ParserState; /* Current state of parser */ + UINT32 PrevArgTypes; + UINT32 ArgCount; /* push for fixed or var args */ + + struct acpi_namespace_node Arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ + struct acpi_namespace_node LocalVariables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ + union acpi_operand_object *Operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */ + union acpi_operand_object **Params; + + UINT8 *AmlLastWhile; + union acpi_operand_object **CallerReturnDesc; + ACPI_GENERIC_STATE *ControlState; /* List of control states (nested IFs) */ + struct acpi_namespace_node *DeferredNode; /* Used when executing deferred opcodes */ + union acpi_operand_object *ImplicitReturnObj; + struct acpi_namespace_node *MethodCallNode; /* Called method Node*/ + ACPI_PARSE_OBJECT *MethodCallOp; /* MethodCall Op if running a method */ + union acpi_operand_object *MethodDesc; /* Method descriptor if running a method */ + struct acpi_namespace_node *MethodNode; /* Method node if running a method. */ + ACPI_PARSE_OBJECT *Op; /* Current parser op */ + const ACPI_OPCODE_INFO *OpInfo; /* Info on current opcode */ + ACPI_PARSE_OBJECT *Origin; /* Start of walk [Obsolete] */ + union acpi_operand_object *ResultObj; + ACPI_GENERIC_STATE *Results; /* Stack of accumulated results */ + union acpi_operand_object *ReturnDesc; /* Return object, if any */ + ACPI_GENERIC_STATE *ScopeInfo; /* Stack of nested scopes */ + ACPI_PARSE_OBJECT *PrevOp; /* Last op that was processed */ + ACPI_PARSE_OBJECT *NextOp; /* next op to be processed */ + ACPI_THREAD_STATE *Thread; + ACPI_PARSE_DOWNWARDS DescendingCallback; + ACPI_PARSE_UPWARDS AscendingCallback; + +} ACPI_WALK_STATE; + + +/* Info used by AcpiNsInitializeObjects and AcpiDsInitializeObjects */ + +typedef struct acpi_init_walk_info +{ + UINT32 TableIndex; + UINT32 ObjectCount; + UINT32 MethodCount; + UINT32 SerialMethodCount; + UINT32 NonSerialMethodCount; + UINT32 SerializedMethodCount; + UINT32 DeviceCount; + UINT32 OpRegionCount; + UINT32 FieldCount; + UINT32 BufferCount; + UINT32 PackageCount; + UINT32 OpRegionInit; + UINT32 FieldInit; + UINT32 BufferInit; + UINT32 PackageInit; + ACPI_OWNER_ID OwnerId; + +} ACPI_INIT_WALK_INFO; + + +typedef struct acpi_get_devices_info +{ + ACPI_WALK_CALLBACK UserFunction; + void *Context; + char *Hid; + +} ACPI_GET_DEVICES_INFO; + + +typedef union acpi_aml_operands +{ + ACPI_OPERAND_OBJECT *Operands[7]; + + struct + { + ACPI_OBJECT_INTEGER *Type; + ACPI_OBJECT_INTEGER *Code; + ACPI_OBJECT_INTEGER *Argument; + + } Fatal; + + struct + { + ACPI_OPERAND_OBJECT *Source; + ACPI_OBJECT_INTEGER *Index; + ACPI_OPERAND_OBJECT *Target; + + } Index; + + struct + { + ACPI_OPERAND_OBJECT *Source; + ACPI_OBJECT_INTEGER *Index; + ACPI_OBJECT_INTEGER *Length; + ACPI_OPERAND_OBJECT *Target; + + } Mid; + +} ACPI_AML_OPERANDS; + + +/* + * Structure used to pass object evaluation information and parameters. + * Purpose is to reduce CPU stack use. + */ +typedef struct acpi_evaluate_info +{ + /* The first 3 elements are passed by the caller to AcpiNsEvaluate */ + + ACPI_NAMESPACE_NODE *PrefixNode; /* Input: starting node */ + char *RelativePathname; /* Input: path relative to PrefixNode */ + ACPI_OPERAND_OBJECT **Parameters; /* Input: argument list */ + + ACPI_NAMESPACE_NODE *Node; /* Resolved node (PrefixNode:RelativePathname) */ + ACPI_OPERAND_OBJECT *ObjDesc; /* Object attached to the resolved node */ + char *FullPathname; /* Full pathname of the resolved node */ + + const ACPI_PREDEFINED_INFO *Predefined; /* Used if Node is a predefined name */ + ACPI_OPERAND_OBJECT *ReturnObject; /* Object returned from the evaluation */ + union acpi_operand_object *ParentPackage; /* Used if return object is a Package */ + + UINT32 ReturnFlags; /* Used for return value analysis */ + UINT32 ReturnBtype; /* Bitmapped type of the returned object */ + UINT16 ParamCount; /* Count of the input argument list */ + UINT8 PassNumber; /* Parser pass number */ + UINT8 ReturnObjectType; /* Object type of the returned object */ + UINT8 NodeFlags; /* Same as Node->Flags */ + UINT8 Flags; /* General flags */ + +} ACPI_EVALUATE_INFO; + +/* Values for Flags above */ + +#define ACPI_IGNORE_RETURN_VALUE 1 + +/* Defines for ReturnFlags field above */ + +#define ACPI_OBJECT_REPAIRED 1 +#define ACPI_OBJECT_WRAPPED 2 + + +/* Info used by AcpiNsInitializeDevices */ + +typedef struct acpi_device_walk_info +{ + ACPI_TABLE_DESC *TableDesc; + ACPI_EVALUATE_INFO *EvaluateInfo; + UINT32 DeviceCount; + UINT32 Num_STA; + UINT32 Num_INI; + +} ACPI_DEVICE_WALK_INFO; + + +/* TBD: [Restructure] Merge with struct above */ + +typedef struct acpi_walk_info +{ + UINT32 DebugLevel; + UINT32 Count; + ACPI_OWNER_ID OwnerId; + UINT8 DisplayType; + +} ACPI_WALK_INFO; + +/* Display Types */ + +#define ACPI_DISPLAY_SUMMARY (UINT8) 0 +#define ACPI_DISPLAY_OBJECTS (UINT8) 1 +#define ACPI_DISPLAY_MASK (UINT8) 1 + +#define ACPI_DISPLAY_SHORT (UINT8) 2 + + +#endif diff --git a/third_party/lib/acpica/source/include/actables.h b/third_party/lib/acpica/source/include/actables.h new file mode 100644 index 000000000..69fbbc8a8 --- /dev/null +++ b/third_party/lib/acpica/source/include/actables.h @@ -0,0 +1,261 @@ +/****************************************************************************** + * + * Name: actables.h - ACPI table management + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTABLES_H__ +#define __ACTABLES_H__ + + +ACPI_STATUS +AcpiAllocateRootTable ( + UINT32 InitialTableCount); + +/* + * tbxfroot - Root pointer utilities + */ +UINT32 +AcpiTbGetRsdpLength ( + ACPI_TABLE_RSDP *Rsdp); + +ACPI_STATUS +AcpiTbValidateRsdp ( + ACPI_TABLE_RSDP *Rsdp); + +UINT8 * +AcpiTbScanMemoryForRsdp ( + UINT8 *StartAddress, + UINT32 Length); + + +/* + * tbdata - table data structure management + */ +ACPI_STATUS +AcpiTbGetNextTableDescriptor ( + UINT32 *TableIndex, + ACPI_TABLE_DESC **TableDesc); + +void +AcpiTbInitTableDescriptor ( + ACPI_TABLE_DESC *TableDesc, + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + ACPI_TABLE_HEADER *Table); + +ACPI_STATUS +AcpiTbAcquireTempTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags); + +void +AcpiTbReleaseTempTable ( + ACPI_TABLE_DESC *TableDesc); + +ACPI_STATUS +AcpiTbValidateTempTable ( + ACPI_TABLE_DESC *TableDesc); + +ACPI_STATUS +AcpiTbVerifyTempTable ( + ACPI_TABLE_DESC *TableDesc, + char *Signature); + +BOOLEAN +AcpiTbIsTableLoaded ( + UINT32 TableIndex); + +void +AcpiTbSetTableLoadedFlag ( + UINT32 TableIndex, + BOOLEAN IsLoaded); + + +/* + * tbfadt - FADT parse/convert/validate + */ +void +AcpiTbParseFadt ( + void); + +void +AcpiTbCreateLocalFadt ( + ACPI_TABLE_HEADER *Table, + UINT32 Length); + + +/* + * tbfind - find ACPI table + */ +ACPI_STATUS +AcpiTbFindTable ( + char *Signature, + char *OemId, + char *OemTableId, + UINT32 *TableIndex); + + +/* + * tbinstal - Table removal and deletion + */ +ACPI_STATUS +AcpiTbResizeRootTableList ( + void); + +ACPI_STATUS +AcpiTbValidateTable ( + ACPI_TABLE_DESC *TableDesc); + +void +AcpiTbInvalidateTable ( + ACPI_TABLE_DESC *TableDesc); + +void +AcpiTbOverrideTable ( + ACPI_TABLE_DESC *OldTableDesc); + +ACPI_STATUS +AcpiTbAcquireTable ( + ACPI_TABLE_DESC *TableDesc, + ACPI_TABLE_HEADER **TablePtr, + UINT32 *TableLength, + UINT8 *TableFlags); + +void +AcpiTbReleaseTable ( + ACPI_TABLE_HEADER *Table, + UINT32 TableLength, + UINT8 TableFlags); + +ACPI_STATUS +AcpiTbInstallStandardTable ( + ACPI_PHYSICAL_ADDRESS Address, + UINT8 Flags, + BOOLEAN Reload, + BOOLEAN Override, + UINT32 *TableIndex); + +void +AcpiTbUninstallTable ( + ACPI_TABLE_DESC *TableDesc); + +void +AcpiTbTerminate ( + void); + +ACPI_STATUS +AcpiTbDeleteNamespaceByOwner ( + UINT32 TableIndex); + +ACPI_STATUS +AcpiTbAllocateOwnerId ( + UINT32 TableIndex); + +ACPI_STATUS +AcpiTbReleaseOwnerId ( + UINT32 TableIndex); + +ACPI_STATUS +AcpiTbGetOwnerId ( + UINT32 TableIndex, + ACPI_OWNER_ID *OwnerId); + + +/* + * tbutils - table manager utilities + */ +ACPI_STATUS +AcpiTbInitializeFacs ( + void); + +void +AcpiTbPrintTableHeader( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER *Header); + +UINT8 +AcpiTbChecksum ( + UINT8 *Buffer, + UINT32 Length); + +ACPI_STATUS +AcpiTbVerifyChecksum ( + ACPI_TABLE_HEADER *Table, + UINT32 Length); + +void +AcpiTbCheckDsdtHeader ( + void); + +ACPI_TABLE_HEADER * +AcpiTbCopyDsdt ( + UINT32 TableIndex); + +void +AcpiTbInstallTableWithOverride ( + ACPI_TABLE_DESC *NewTableDesc, + BOOLEAN Override, + UINT32 *TableIndex); + +ACPI_STATUS +AcpiTbInstallFixedTable ( + ACPI_PHYSICAL_ADDRESS Address, + char *Signature, + UINT32 *TableIndex); + +ACPI_STATUS +AcpiTbParseRootTable ( + ACPI_PHYSICAL_ADDRESS RsdpAddress); + +BOOLEAN +AcpiIsValidSignature ( + char *Signature); + + +/* + * tbxfload + */ +ACPI_STATUS +AcpiTbLoadNamespace ( + void); + +#endif /* __ACTABLES_H__ */ diff --git a/third_party/lib/acpica/source/include/actbl.h b/third_party/lib/acpica/source/include/actbl.h new file mode 100644 index 000000000..e868909e5 --- /dev/null +++ b/third_party/lib/acpica/source/include/actbl.h @@ -0,0 +1,452 @@ +/****************************************************************************** + * + * Name: actbl.h - Basic ACPI Table Definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTBL_H__ +#define __ACTBL_H__ + + +/******************************************************************************* + * + * Fundamental ACPI tables + * + * This file contains definitions for the ACPI tables that are directly consumed + * by ACPICA. All other tables are consumed by the OS-dependent ACPI-related + * device drivers and other OS support code. + * + * The RSDP and FACS do not use the common ACPI table header. All other ACPI + * tables use the header. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */ +#define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */ +#define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */ +#define ACPI_SIG_OSDT "OSDT" /* Override System Description Table */ +#define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */ +#define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */ +#define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */ +#define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */ +#define ACPI_SIG_SSDT "SSDT" /* Secondary System Description Table */ +#define ACPI_RSDP_NAME "RSDP" /* Short name for RSDP, not signature */ + + +/* + * All tables and structures must be byte-packed to match the ACPI + * specification, since the tables are provided by the system BIOS + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * Master ACPI Table Header. This common header is used by all ACPI tables + * except the RSDP and FACS. + * + ******************************************************************************/ + +typedef struct acpi_table_header +{ + char Signature[ACPI_NAME_SIZE]; /* ASCII table signature */ + UINT32 Length; /* Length of table in bytes, including this header */ + UINT8 Revision; /* ACPI Specification minor version number */ + UINT8 Checksum; /* To make sum of entire table == 0 */ + char OemId[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */ + char OemTableId[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */ + UINT32 OemRevision; /* OEM revision number */ + char AslCompilerId[ACPI_NAME_SIZE]; /* ASCII ASL compiler vendor ID */ + UINT32 AslCompilerRevision; /* ASL compiler version */ + +} ACPI_TABLE_HEADER; + + +/******************************************************************************* + * + * GAS - Generic Address Structure (ACPI 2.0+) + * + * Note: Since this structure is used in the ACPI tables, it is byte aligned. + * If misaligned access is not supported by the hardware, accesses to the + * 64-bit Address field must be performed with care. + * + ******************************************************************************/ + +typedef struct acpi_generic_address +{ + UINT8 SpaceId; /* Address space where struct or register exists */ + UINT8 BitWidth; /* Size in bits of given register */ + UINT8 BitOffset; /* Bit offset within the register */ + UINT8 AccessWidth; /* Minimum Access size (ACPI 3.0) */ + UINT64 Address; /* 64-bit address of struct or register */ + +} ACPI_GENERIC_ADDRESS; + + +/******************************************************************************* + * + * RSDP - Root System Description Pointer (Signature is "RSD PTR ") + * Version 2 + * + ******************************************************************************/ + +typedef struct acpi_table_rsdp +{ + char Signature[8]; /* ACPI signature, contains "RSD PTR " */ + UINT8 Checksum; /* ACPI 1.0 checksum */ + char OemId[ACPI_OEM_ID_SIZE]; /* OEM identification */ + UINT8 Revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ + UINT32 RsdtPhysicalAddress; /* 32-bit physical address of the RSDT */ + UINT32 Length; /* Table length in bytes, including header (ACPI 2.0+) */ + UINT64 XsdtPhysicalAddress; /* 64-bit physical address of the XSDT (ACPI 2.0+) */ + UINT8 ExtendedChecksum; /* Checksum of entire table (ACPI 2.0+) */ + UINT8 Reserved[3]; /* Reserved, must be zero */ + +} ACPI_TABLE_RSDP; + +/* Standalone struct for the ACPI 1.0 RSDP */ + +typedef struct acpi_rsdp_common +{ + char Signature[8]; + UINT8 Checksum; + char OemId[ACPI_OEM_ID_SIZE]; + UINT8 Revision; + UINT32 RsdtPhysicalAddress; + +} ACPI_RSDP_COMMON; + +/* Standalone struct for the extended part of the RSDP (ACPI 2.0+) */ + +typedef struct acpi_rsdp_extension +{ + UINT32 Length; + UINT64 XsdtPhysicalAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; + +} ACPI_RSDP_EXTENSION; + + +/******************************************************************************* + * + * RSDT/XSDT - Root System Description Tables + * Version 1 (both) + * + ******************************************************************************/ + +typedef struct acpi_table_rsdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 TableOffsetEntry[1]; /* Array of pointers to ACPI tables */ + +} ACPI_TABLE_RSDT; + +typedef struct acpi_table_xsdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 TableOffsetEntry[1]; /* Array of pointers to ACPI tables */ + +} ACPI_TABLE_XSDT; + +#define ACPI_RSDT_ENTRY_SIZE (sizeof (UINT32)) +#define ACPI_XSDT_ENTRY_SIZE (sizeof (UINT64)) + + +/******************************************************************************* + * + * FACS - Firmware ACPI Control Structure (FACS) + * + ******************************************************************************/ + +typedef struct acpi_table_facs +{ + char Signature[4]; /* ASCII table signature */ + UINT32 Length; /* Length of structure, in bytes */ + UINT32 HardwareSignature; /* Hardware configuration signature */ + UINT32 FirmwareWakingVector; /* 32-bit physical address of the Firmware Waking Vector */ + UINT32 GlobalLock; /* Global Lock for shared hardware resources */ + UINT32 Flags; + UINT64 XFirmwareWakingVector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */ + UINT8 Version; /* Version of this table (ACPI 2.0+) */ + UINT8 Reserved[3]; /* Reserved, must be zero */ + UINT32 OspmFlags; /* Flags to be set by OSPM (ACPI 4.0) */ + UINT8 Reserved1[24]; /* Reserved, must be zero */ + +} ACPI_TABLE_FACS; + +/* Masks for GlobalLock flag field above */ + +#define ACPI_GLOCK_PENDING (1) /* 00: Pending global lock ownership */ +#define ACPI_GLOCK_OWNED (1<<1) /* 01: Global lock is owned */ + +/* Masks for Flags field above */ + +#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */ +#define ACPI_FACS_64BIT_WAKE (1<<1) /* 01: 64-bit wake vector supported (ACPI 4.0) */ + +/* Masks for OspmFlags field above */ + +#define ACPI_FACS_64BIT_ENVIRONMENT (1) /* 00: 64-bit wake environment is required (ACPI 4.0) */ + + +/******************************************************************************* + * + * FADT - Fixed ACPI Description Table (Signature "FACP") + * Version 4 + * + ******************************************************************************/ + +/* Fields common to all versions of the FADT */ + +typedef struct acpi_table_fadt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Facs; /* 32-bit physical address of FACS */ + UINT32 Dsdt; /* 32-bit physical address of DSDT */ + UINT8 Model; /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */ + UINT8 PreferredProfile; /* Conveys preferred power management profile to OSPM. */ + UINT16 SciInterrupt; /* System vector of SCI interrupt */ + UINT32 SmiCommand; /* 32-bit Port address of SMI command port */ + UINT8 AcpiEnable; /* Value to write to SMI_CMD to enable ACPI */ + UINT8 AcpiDisable; /* Value to write to SMI_CMD to disable ACPI */ + UINT8 S4BiosRequest; /* Value to write to SMI_CMD to enter S4BIOS state */ + UINT8 PstateControl; /* Processor performance state control*/ + UINT32 Pm1aEventBlock; /* 32-bit port address of Power Mgt 1a Event Reg Blk */ + UINT32 Pm1bEventBlock; /* 32-bit port address of Power Mgt 1b Event Reg Blk */ + UINT32 Pm1aControlBlock; /* 32-bit port address of Power Mgt 1a Control Reg Blk */ + UINT32 Pm1bControlBlock; /* 32-bit port address of Power Mgt 1b Control Reg Blk */ + UINT32 Pm2ControlBlock; /* 32-bit port address of Power Mgt 2 Control Reg Blk */ + UINT32 PmTimerBlock; /* 32-bit port address of Power Mgt Timer Ctrl Reg Blk */ + UINT32 Gpe0Block; /* 32-bit port address of General Purpose Event 0 Reg Blk */ + UINT32 Gpe1Block; /* 32-bit port address of General Purpose Event 1 Reg Blk */ + UINT8 Pm1EventLength; /* Byte Length of ports at Pm1xEventBlock */ + UINT8 Pm1ControlLength; /* Byte Length of ports at Pm1xControlBlock */ + UINT8 Pm2ControlLength; /* Byte Length of ports at Pm2ControlBlock */ + UINT8 PmTimerLength; /* Byte Length of ports at PmTimerBlock */ + UINT8 Gpe0BlockLength; /* Byte Length of ports at Gpe0Block */ + UINT8 Gpe1BlockLength; /* Byte Length of ports at Gpe1Block */ + UINT8 Gpe1Base; /* Offset in GPE number space where GPE1 events start */ + UINT8 CstControl; /* Support for the _CST object and C-States change notification */ + UINT16 C2Latency; /* Worst case HW latency to enter/exit C2 state */ + UINT16 C3Latency; /* Worst case HW latency to enter/exit C3 state */ + UINT16 FlushSize; /* Processor memory cache line width, in bytes */ + UINT16 FlushStride; /* Number of flush strides that need to be read */ + UINT8 DutyOffset; /* Processor duty cycle index in processor P_CNT reg */ + UINT8 DutyWidth; /* Processor duty cycle value bit width in P_CNT register */ + UINT8 DayAlarm; /* Index to day-of-month alarm in RTC CMOS RAM */ + UINT8 MonthAlarm; /* Index to month-of-year alarm in RTC CMOS RAM */ + UINT8 Century; /* Index to century in RTC CMOS RAM */ + UINT16 BootFlags; /* IA-PC Boot Architecture Flags (see below for individual flags) */ + UINT8 Reserved; /* Reserved, must be zero */ + UINT32 Flags; /* Miscellaneous flag bits (see below for individual flags) */ + ACPI_GENERIC_ADDRESS ResetRegister; /* 64-bit address of the Reset register */ + UINT8 ResetValue; /* Value to write to the ResetRegister port to reset the system */ + UINT16 ArmBootFlags; /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */ + UINT8 MinorRevision; /* FADT Minor Revision (ACPI 5.1) */ + UINT64 XFacs; /* 64-bit physical address of FACS */ + UINT64 XDsdt; /* 64-bit physical address of DSDT */ + ACPI_GENERIC_ADDRESS XPm1aEventBlock; /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm1bEventBlock; /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm1aControlBlock; /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm1bControlBlock; /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ + ACPI_GENERIC_ADDRESS XPm2ControlBlock; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ + ACPI_GENERIC_ADDRESS XPmTimerBlock; /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ + ACPI_GENERIC_ADDRESS XGpe0Block; /* 64-bit Extended General Purpose Event 0 Reg Blk address */ + ACPI_GENERIC_ADDRESS XGpe1Block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */ + ACPI_GENERIC_ADDRESS SleepControl; /* 64-bit Sleep Control register (ACPI 5.0) */ + ACPI_GENERIC_ADDRESS SleepStatus; /* 64-bit Sleep Status register (ACPI 5.0) */ + UINT64 HypervisorId; /* Hypervisor Vendor ID (ACPI 6.0) */ + +} ACPI_TABLE_FADT; + + +/* Masks for FADT IA-PC Boot Architecture Flags (boot_flags) [Vx]=Introduced in this FADT revision */ + +#define ACPI_FADT_LEGACY_DEVICES (1) /* 00: [V2] System has LPC or ISA bus devices */ +#define ACPI_FADT_8042 (1<<1) /* 01: [V3] System has an 8042 controller on port 60/64 */ +#define ACPI_FADT_NO_VGA (1<<2) /* 02: [V4] It is not safe to probe for VGA hardware */ +#define ACPI_FADT_NO_MSI (1<<3) /* 03: [V4] Message Signaled Interrupts (MSI) must not be enabled */ +#define ACPI_FADT_NO_ASPM (1<<4) /* 04: [V4] PCIe ASPM control must not be enabled */ +#define ACPI_FADT_NO_CMOS_RTC (1<<5) /* 05: [V5] No CMOS real-time clock present */ + +/* Masks for FADT ARM Boot Architecture Flags (arm_boot_flags) ACPI 5.1 */ + +#define ACPI_FADT_PSCI_COMPLIANT (1) /* 00: [V5+] PSCI 0.2+ is implemented */ +#define ACPI_FADT_PSCI_USE_HVC (1<<1) /* 01: [V5+] HVC must be used instead of SMC as the PSCI conduit */ + +/* Masks for FADT flags */ + +#define ACPI_FADT_WBINVD (1) /* 00: [V1] The WBINVD instruction works properly */ +#define ACPI_FADT_WBINVD_FLUSH (1<<1) /* 01: [V1] WBINVD flushes but does not invalidate caches */ +#define ACPI_FADT_C1_SUPPORTED (1<<2) /* 02: [V1] All processors support C1 state */ +#define ACPI_FADT_C2_MP_SUPPORTED (1<<3) /* 03: [V1] C2 state works on MP system */ +#define ACPI_FADT_POWER_BUTTON (1<<4) /* 04: [V1] Power button is handled as a control method device */ +#define ACPI_FADT_SLEEP_BUTTON (1<<5) /* 05: [V1] Sleep button is handled as a control method device */ +#define ACPI_FADT_FIXED_RTC (1<<6) /* 06: [V1] RTC wakeup status is not in fixed register space */ +#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: [V1] RTC alarm can wake system from S4 */ +#define ACPI_FADT_32BIT_TIMER (1<<8) /* 08: [V1] ACPI timer width is 32-bit (0=24-bit) */ +#define ACPI_FADT_DOCKING_SUPPORTED (1<<9) /* 09: [V1] Docking supported */ +#define ACPI_FADT_RESET_REGISTER (1<<10) /* 10: [V2] System reset via the FADT RESET_REG supported */ +#define ACPI_FADT_SEALED_CASE (1<<11) /* 11: [V3] No internal expansion capabilities and case is sealed */ +#define ACPI_FADT_HEADLESS (1<<12) /* 12: [V3] No local video capabilities or local input devices */ +#define ACPI_FADT_SLEEP_TYPE (1<<13) /* 13: [V3] Must execute native instruction after writing SLP_TYPx register */ +#define ACPI_FADT_PCI_EXPRESS_WAKE (1<<14) /* 14: [V4] System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ +#define ACPI_FADT_PLATFORM_CLOCK (1<<15) /* 15: [V4] OSPM should use platform-provided timer (ACPI 3.0) */ +#define ACPI_FADT_S4_RTC_VALID (1<<16) /* 16: [V4] Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ +#define ACPI_FADT_REMOTE_POWER_ON (1<<17) /* 17: [V4] System is compatible with remote power on (ACPI 3.0) */ +#define ACPI_FADT_APIC_CLUSTER (1<<18) /* 18: [V4] All local APICs must use cluster model (ACPI 3.0) */ +#define ACPI_FADT_APIC_PHYSICAL (1<<19) /* 19: [V4] All local xAPICs must use physical dest mode (ACPI 3.0) */ +#define ACPI_FADT_HW_REDUCED (1<<20) /* 20: [V5] ACPI hardware is not implemented (ACPI 5.0) */ +#define ACPI_FADT_LOW_POWER_S0 (1<<21) /* 21: [V5] S0 power savings are equal or better than S3 (ACPI 5.0) */ + + +/* Values for PreferredProfile (Preferred Power Management Profiles) */ + +enum AcpiPreferredPmProfiles +{ + PM_UNSPECIFIED = 0, + PM_DESKTOP = 1, + PM_MOBILE = 2, + PM_WORKSTATION = 3, + PM_ENTERPRISE_SERVER = 4, + PM_SOHO_SERVER = 5, + PM_APPLIANCE_PC = 6, + PM_PERFORMANCE_SERVER = 7, + PM_TABLET = 8 +}; + +/* Values for SleepStatus and SleepControl registers (V5+ FADT) */ + +#define ACPI_X_WAKE_STATUS 0x80 +#define ACPI_X_SLEEP_TYPE_MASK 0x1C +#define ACPI_X_SLEEP_TYPE_POSITION 0x02 +#define ACPI_X_SLEEP_ENABLE 0x20 + + +/* Reset to default packing */ + +#pragma pack() + + +/* + * Internal table-related structures + */ +typedef union acpi_name_union +{ + UINT32 Integer; + char Ascii[4]; + +} ACPI_NAME_UNION; + + +/* Internal ACPI Table Descriptor. One per ACPI table. */ + +typedef struct acpi_table_desc +{ + ACPI_PHYSICAL_ADDRESS Address; + ACPI_TABLE_HEADER *Pointer; + UINT32 Length; /* Length fixed at 32 bits (fixed in table header) */ + ACPI_NAME_UNION Signature; + ACPI_OWNER_ID OwnerId; + UINT8 Flags; + +} ACPI_TABLE_DESC; + +/* Masks for Flags field above */ + +#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */ +#define ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL (1) /* Physical address, internally mapped */ +#define ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL (2) /* Virtual address, internallly allocated */ +#define ACPI_TABLE_ORIGIN_MASK (3) +#define ACPI_TABLE_IS_LOADED (8) + + +/* + * Get the remaining ACPI tables + */ +#include "actbl1.h" +#include "actbl2.h" +#include "actbl3.h" + +/* Macros used to generate offsets to specific table fields */ + +#define ACPI_FADT_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_FADT, f) + +/* + * Sizes of the various flavors of FADT. We need to look closely + * at the FADT length because the version number essentially tells + * us nothing because of many BIOS bugs where the version does not + * match the expected length. In other words, the length of the + * FADT is the bottom line as to what the version really is. + * + * For reference, the values below are as follows: + * FADT V1 size: 0x074 + * FADT V2 size: 0x084 + * FADT V3 size: 0x0F4 + * FADT V4 size: 0x0F4 + * FADT V5 size: 0x10C + * FADT V6 size: 0x114 + */ +#define ACPI_FADT_V1_SIZE (UINT32) (ACPI_FADT_OFFSET (Flags) + 4) +#define ACPI_FADT_V2_SIZE (UINT32) (ACPI_FADT_OFFSET (MinorRevision) + 1) +#define ACPI_FADT_V3_SIZE (UINT32) (ACPI_FADT_OFFSET (SleepControl)) +#define ACPI_FADT_V5_SIZE (UINT32) (ACPI_FADT_OFFSET (HypervisorId)) +#define ACPI_FADT_V6_SIZE (UINT32) (sizeof (ACPI_TABLE_FADT)) + +#endif /* __ACTBL_H__ */ diff --git a/third_party/lib/acpica/source/include/actbl1.h b/third_party/lib/acpica/source/include/actbl1.h new file mode 100644 index 000000000..e789b9bf2 --- /dev/null +++ b/third_party/lib/acpica/source/include/actbl1.h @@ -0,0 +1,1420 @@ +/****************************************************************************** + * + * Name: actbl1.h - Additional ACPI table definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTBL1_H__ +#define __ACTBL1_H__ + + +/******************************************************************************* + * + * Additional ACPI Tables (1) + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + * The tables in this file are fully defined within the ACPI specification. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */ +#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */ +#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */ +#define ACPI_SIG_EINJ "EINJ" /* Error Injection table */ +#define ACPI_SIG_ERST "ERST" /* Error Record Serialization Table */ +#define ACPI_SIG_HEST "HEST" /* Hardware Error Source Table */ +#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */ +#define ACPI_SIG_MSCT "MSCT" /* Maximum System Characteristics Table */ +#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */ +#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */ +#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */ +#define ACPI_SIG_NFIT "NFIT" /* NVDIMM Firmware Interface Table */ + + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * Common subtable headers + * + ******************************************************************************/ + +/* Generic subtable header (used in MADT, SRAT, etc.) */ + +typedef struct acpi_subtable_header +{ + UINT8 Type; + UINT8 Length; + +} ACPI_SUBTABLE_HEADER; + + +/* Subtable header for WHEA tables (EINJ, ERST, WDAT) */ + +typedef struct acpi_whea_header +{ + UINT8 Action; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved; + ACPI_GENERIC_ADDRESS RegisterRegion; + UINT64 Value; /* Value used with Read/Write register */ + UINT64 Mask; /* Bitmask required for this register instruction */ + +} ACPI_WHEA_HEADER; + + +/******************************************************************************* + * + * BERT - Boot Error Record Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_bert +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 RegionLength; /* Length of the boot error region */ + UINT64 Address; /* Physical address of the error region */ + +} ACPI_TABLE_BERT; + + +/* Boot Error Region (not a subtable, pointed to by Address field above) */ + +typedef struct acpi_bert_region +{ + UINT32 BlockStatus; /* Type of error information */ + UINT32 RawDataOffset; /* Offset to raw error data */ + UINT32 RawDataLength; /* Length of raw error data */ + UINT32 DataLength; /* Length of generic error data */ + UINT32 ErrorSeverity; /* Severity code */ + +} ACPI_BERT_REGION; + +/* Values for BlockStatus flags above */ + +#define ACPI_BERT_UNCORRECTABLE (1) +#define ACPI_BERT_CORRECTABLE (1<<1) +#define ACPI_BERT_MULTIPLE_UNCORRECTABLE (1<<2) +#define ACPI_BERT_MULTIPLE_CORRECTABLE (1<<3) +#define ACPI_BERT_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ + +/* Values for ErrorSeverity above */ + +enum AcpiBertErrorSeverity +{ + ACPI_BERT_ERROR_CORRECTABLE = 0, + ACPI_BERT_ERROR_FATAL = 1, + ACPI_BERT_ERROR_CORRECTED = 2, + ACPI_BERT_ERROR_NONE = 3, + ACPI_BERT_ERROR_RESERVED = 4 /* 4 and greater are reserved */ +}; + +/* + * Note: The generic error data that follows the ErrorSeverity field above + * uses the ACPI_HEST_GENERIC_DATA defined under the HEST table below + */ + + +/******************************************************************************* + * + * CPEP - Corrected Platform Error Polling table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_cpep +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 Reserved; + +} ACPI_TABLE_CPEP; + + +/* Subtable */ + +typedef struct acpi_cpep_polling +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Id; /* Processor ID */ + UINT8 Eid; /* Processor EID */ + UINT32 Interval; /* Polling interval (msec) */ + +} ACPI_CPEP_POLLING; + + +/******************************************************************************* + * + * ECDT - Embedded Controller Boot Resources Table + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_ecdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + ACPI_GENERIC_ADDRESS Control; /* Address of EC command/status register */ + ACPI_GENERIC_ADDRESS Data; /* Address of EC data register */ + UINT32 Uid; /* Unique ID - must be same as the EC _UID method */ + UINT8 Gpe; /* The GPE for the EC */ + UINT8 Id[1]; /* Full namepath of the EC in the ACPI namespace */ + +} ACPI_TABLE_ECDT; + + +/******************************************************************************* + * + * EINJ - Error Injection Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_einj +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HeaderLength; + UINT8 Flags; + UINT8 Reserved[3]; + UINT32 Entries; + +} ACPI_TABLE_EINJ; + + +/* EINJ Injection Instruction Entries (actions) */ + +typedef struct acpi_einj_entry +{ + ACPI_WHEA_HEADER WheaHeader; /* Common header for WHEA tables */ + +} ACPI_EINJ_ENTRY; + +/* Masks for Flags field above */ + +#define ACPI_EINJ_PRESERVE (1) + +/* Values for Action field above */ + +enum AcpiEinjActions +{ + ACPI_EINJ_BEGIN_OPERATION = 0, + ACPI_EINJ_GET_TRIGGER_TABLE = 1, + ACPI_EINJ_SET_ERROR_TYPE = 2, + ACPI_EINJ_GET_ERROR_TYPE = 3, + ACPI_EINJ_END_OPERATION = 4, + ACPI_EINJ_EXECUTE_OPERATION = 5, + ACPI_EINJ_CHECK_BUSY_STATUS = 6, + ACPI_EINJ_GET_COMMAND_STATUS = 7, + ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS = 8, + ACPI_EINJ_ACTION_RESERVED = 9, /* 9 and greater are reserved */ + ACPI_EINJ_TRIGGER_ERROR = 0xFF /* Except for this value */ +}; + +/* Values for Instruction field above */ + +enum AcpiEinjInstructions +{ + ACPI_EINJ_READ_REGISTER = 0, + ACPI_EINJ_READ_REGISTER_VALUE = 1, + ACPI_EINJ_WRITE_REGISTER = 2, + ACPI_EINJ_WRITE_REGISTER_VALUE = 3, + ACPI_EINJ_NOOP = 4, + ACPI_EINJ_FLUSH_CACHELINE = 5, + ACPI_EINJ_INSTRUCTION_RESERVED = 6 /* 6 and greater are reserved */ +}; + +typedef struct acpi_einj_error_type_with_addr +{ + UINT32 ErrorType; + UINT32 VendorStructOffset; + UINT32 Flags; + UINT32 ApicId; + UINT64 Address; + UINT64 Range; + UINT32 PcieId; + +} ACPI_EINJ_ERROR_TYPE_WITH_ADDR; + +typedef struct acpi_einj_vendor +{ + UINT32 Length; + UINT32 PcieId; + UINT16 VendorId; + UINT16 DeviceId; + UINT8 RevisionId; + UINT8 Reserved[3]; + +} ACPI_EINJ_VENDOR; + + +/* EINJ Trigger Error Action Table */ + +typedef struct acpi_einj_trigger +{ + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; + +} ACPI_EINJ_TRIGGER; + +/* Command status return values */ + +enum AcpiEinjCommandStatus +{ + ACPI_EINJ_SUCCESS = 0, + ACPI_EINJ_FAILURE = 1, + ACPI_EINJ_INVALID_ACCESS = 2, + ACPI_EINJ_STATUS_RESERVED = 3 /* 3 and greater are reserved */ +}; + + +/* Error types returned from ACPI_EINJ_GET_ERROR_TYPE (bitfield) */ + +#define ACPI_EINJ_PROCESSOR_CORRECTABLE (1) +#define ACPI_EINJ_PROCESSOR_UNCORRECTABLE (1<<1) +#define ACPI_EINJ_PROCESSOR_FATAL (1<<2) +#define ACPI_EINJ_MEMORY_CORRECTABLE (1<<3) +#define ACPI_EINJ_MEMORY_UNCORRECTABLE (1<<4) +#define ACPI_EINJ_MEMORY_FATAL (1<<5) +#define ACPI_EINJ_PCIX_CORRECTABLE (1<<6) +#define ACPI_EINJ_PCIX_UNCORRECTABLE (1<<7) +#define ACPI_EINJ_PCIX_FATAL (1<<8) +#define ACPI_EINJ_PLATFORM_CORRECTABLE (1<<9) +#define ACPI_EINJ_PLATFORM_UNCORRECTABLE (1<<10) +#define ACPI_EINJ_PLATFORM_FATAL (1<<11) +#define ACPI_EINJ_VENDOR_DEFINED (1<<31) + + +/******************************************************************************* + * + * ERST - Error Record Serialization Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_erst +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HeaderLength; + UINT32 Reserved; + UINT32 Entries; + +} ACPI_TABLE_ERST; + + +/* ERST Serialization Entries (actions) */ + +typedef struct acpi_erst_entry +{ + ACPI_WHEA_HEADER WheaHeader; /* Common header for WHEA tables */ + +} ACPI_ERST_ENTRY; + +/* Masks for Flags field above */ + +#define ACPI_ERST_PRESERVE (1) + +/* Values for Action field above */ + +enum AcpiErstActions +{ + ACPI_ERST_BEGIN_WRITE = 0, + ACPI_ERST_BEGIN_READ = 1, + ACPI_ERST_BEGIN_CLEAR = 2, + ACPI_ERST_END = 3, + ACPI_ERST_SET_RECORD_OFFSET = 4, + ACPI_ERST_EXECUTE_OPERATION = 5, + ACPI_ERST_CHECK_BUSY_STATUS = 6, + ACPI_ERST_GET_COMMAND_STATUS = 7, + ACPI_ERST_GET_RECORD_ID = 8, + ACPI_ERST_SET_RECORD_ID = 9, + ACPI_ERST_GET_RECORD_COUNT = 10, + ACPI_ERST_BEGIN_DUMMY_WRIITE = 11, + ACPI_ERST_NOT_USED = 12, + ACPI_ERST_GET_ERROR_RANGE = 13, + ACPI_ERST_GET_ERROR_LENGTH = 14, + ACPI_ERST_GET_ERROR_ATTRIBUTES = 15, + ACPI_ERST_ACTION_RESERVED = 16 /* 16 and greater are reserved */ +}; + +/* Values for Instruction field above */ + +enum AcpiErstInstructions +{ + ACPI_ERST_READ_REGISTER = 0, + ACPI_ERST_READ_REGISTER_VALUE = 1, + ACPI_ERST_WRITE_REGISTER = 2, + ACPI_ERST_WRITE_REGISTER_VALUE = 3, + ACPI_ERST_NOOP = 4, + ACPI_ERST_LOAD_VAR1 = 5, + ACPI_ERST_LOAD_VAR2 = 6, + ACPI_ERST_STORE_VAR1 = 7, + ACPI_ERST_ADD = 8, + ACPI_ERST_SUBTRACT = 9, + ACPI_ERST_ADD_VALUE = 10, + ACPI_ERST_SUBTRACT_VALUE = 11, + ACPI_ERST_STALL = 12, + ACPI_ERST_STALL_WHILE_TRUE = 13, + ACPI_ERST_SKIP_NEXT_IF_TRUE = 14, + ACPI_ERST_GOTO = 15, + ACPI_ERST_SET_SRC_ADDRESS_BASE = 16, + ACPI_ERST_SET_DST_ADDRESS_BASE = 17, + ACPI_ERST_MOVE_DATA = 18, + ACPI_ERST_INSTRUCTION_RESERVED = 19 /* 19 and greater are reserved */ +}; + +/* Command status return values */ + +enum AcpiErstCommandStatus +{ + ACPI_ERST_SUCESS = 0, + ACPI_ERST_NO_SPACE = 1, + ACPI_ERST_NOT_AVAILABLE = 2, + ACPI_ERST_FAILURE = 3, + ACPI_ERST_RECORD_EMPTY = 4, + ACPI_ERST_NOT_FOUND = 5, + ACPI_ERST_STATUS_RESERVED = 6 /* 6 and greater are reserved */ +}; + + +/* Error Record Serialization Information */ + +typedef struct acpi_erst_info +{ + UINT16 Signature; /* Should be "ER" */ + UINT8 Data[48]; + +} ACPI_ERST_INFO; + + +/******************************************************************************* + * + * HEST - Hardware Error Source Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_hest +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 ErrorSourceCount; + +} ACPI_TABLE_HEST; + + +/* HEST subtable header */ + +typedef struct acpi_hest_header +{ + UINT16 Type; + UINT16 SourceId; + +} ACPI_HEST_HEADER; + + +/* Values for Type field above for subtables */ + +enum AcpiHestTypes +{ + ACPI_HEST_TYPE_IA32_CHECK = 0, + ACPI_HEST_TYPE_IA32_CORRECTED_CHECK = 1, + ACPI_HEST_TYPE_IA32_NMI = 2, + ACPI_HEST_TYPE_NOT_USED3 = 3, + ACPI_HEST_TYPE_NOT_USED4 = 4, + ACPI_HEST_TYPE_NOT_USED5 = 5, + ACPI_HEST_TYPE_AER_ROOT_PORT = 6, + ACPI_HEST_TYPE_AER_ENDPOINT = 7, + ACPI_HEST_TYPE_AER_BRIDGE = 8, + ACPI_HEST_TYPE_GENERIC_ERROR = 9, + ACPI_HEST_TYPE_RESERVED = 10 /* 10 and greater are reserved */ +}; + + +/* + * HEST substructures contained in subtables + */ + +/* + * IA32 Error Bank(s) - Follows the ACPI_HEST_IA_MACHINE_CHECK and + * ACPI_HEST_IA_CORRECTED structures. + */ +typedef struct acpi_hest_ia_error_bank +{ + UINT8 BankNumber; + UINT8 ClearStatusOnInit; + UINT8 StatusFormat; + UINT8 Reserved; + UINT32 ControlRegister; + UINT64 ControlData; + UINT32 StatusRegister; + UINT32 AddressRegister; + UINT32 MiscRegister; + +} ACPI_HEST_IA_ERROR_BANK; + + +/* Common HEST sub-structure for PCI/AER structures below (6,7,8) */ + +typedef struct acpi_hest_aer_common +{ + UINT16 Reserved1; + UINT8 Flags; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; /* Bus and Segment numbers */ + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT16 Reserved2; + UINT32 UncorrectableMask; + UINT32 UncorrectableSeverity; + UINT32 CorrectableMask; + UINT32 AdvancedCapabilities; + +} ACPI_HEST_AER_COMMON; + +/* Masks for HEST Flags fields */ + +#define ACPI_HEST_FIRMWARE_FIRST (1) +#define ACPI_HEST_GLOBAL (1<<1) + +/* + * Macros to access the bus/segment numbers in Bus field above: + * Bus number is encoded in bits 7:0 + * Segment number is encoded in bits 23:8 + */ +#define ACPI_HEST_BUS(Bus) ((Bus) & 0xFF) +#define ACPI_HEST_SEGMENT(Bus) (((Bus) >> 8) & 0xFFFF) + + +/* Hardware Error Notification */ + +typedef struct acpi_hest_notify +{ + UINT8 Type; + UINT8 Length; + UINT16 ConfigWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 PollingThresholdValue; + UINT32 PollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; + +} ACPI_HEST_NOTIFY; + +/* Values for Notify Type field above */ + +enum AcpiHestNotifyTypes +{ + ACPI_HEST_NOTIFY_POLLED = 0, + ACPI_HEST_NOTIFY_EXTERNAL = 1, + ACPI_HEST_NOTIFY_LOCAL = 2, + ACPI_HEST_NOTIFY_SCI = 3, + ACPI_HEST_NOTIFY_NMI = 4, + ACPI_HEST_NOTIFY_CMCI = 5, /* ACPI 5.0 */ + ACPI_HEST_NOTIFY_MCE = 6, /* ACPI 5.0 */ + ACPI_HEST_NOTIFY_RESERVED = 7 /* 7 and greater are reserved */ +}; + +/* Values for ConfigWriteEnable bitfield above */ + +#define ACPI_HEST_TYPE (1) +#define ACPI_HEST_POLL_INTERVAL (1<<1) +#define ACPI_HEST_POLL_THRESHOLD_VALUE (1<<2) +#define ACPI_HEST_POLL_THRESHOLD_WINDOW (1<<3) +#define ACPI_HEST_ERR_THRESHOLD_VALUE (1<<4) +#define ACPI_HEST_ERR_THRESHOLD_WINDOW (1<<5) + + +/* + * HEST subtables + */ + +/* 0: IA32 Machine Check Exception */ + +typedef struct acpi_hest_ia_machine_check +{ + ACPI_HEST_HEADER Header; + UINT16 Reserved1; + UINT8 Flags; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityData; + UINT64 GlobalControlData; + UINT8 NumHardwareBanks; + UINT8 Reserved3[7]; + +} ACPI_HEST_IA_MACHINE_CHECK; + + +/* 1: IA32 Corrected Machine Check */ + +typedef struct acpi_hest_ia_corrected +{ + ACPI_HEST_HEADER Header; + UINT16 Reserved1; + UINT8 Flags; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + ACPI_HEST_NOTIFY Notify; + UINT8 NumHardwareBanks; + UINT8 Reserved2[3]; + +} ACPI_HEST_IA_CORRECTED; + + +/* 2: IA32 Non-Maskable Interrupt */ + +typedef struct acpi_hest_ia_nmi +{ + ACPI_HEST_HEADER Header; + UINT32 Reserved; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + +} ACPI_HEST_IA_NMI; + + +/* 3,4,5: Not used */ + +/* 6: PCI Express Root Port AER */ + +typedef struct acpi_hest_aer_root +{ + ACPI_HEST_HEADER Header; + ACPI_HEST_AER_COMMON Aer; + UINT32 RootErrorCommand; + +} ACPI_HEST_AER_ROOT; + + +/* 7: PCI Express AER (AER Endpoint) */ + +typedef struct acpi_hest_aer +{ + ACPI_HEST_HEADER Header; + ACPI_HEST_AER_COMMON Aer; + +} ACPI_HEST_AER; + + +/* 8: PCI Express/PCI-X Bridge AER */ + +typedef struct acpi_hest_aer_bridge +{ + ACPI_HEST_HEADER Header; + ACPI_HEST_AER_COMMON Aer; + UINT32 UncorrectableMask2; + UINT32 UncorrectableSeverity2; + UINT32 AdvancedCapabilities2; + +} ACPI_HEST_AER_BRIDGE; + + +/* 9: Generic Hardware Error Source */ + +typedef struct acpi_hest_generic +{ + ACPI_HEST_HEADER Header; + UINT16 RelatedSourceId; + UINT8 Reserved; + UINT8 Enabled; + UINT32 RecordsToPreallocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + ACPI_GENERIC_ADDRESS ErrorStatusAddress; + ACPI_HEST_NOTIFY Notify; + UINT32 ErrorBlockLength; + +} ACPI_HEST_GENERIC; + + +/* Generic Error Status block */ + +typedef struct acpi_hest_generic_status +{ + UINT32 BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; + +} ACPI_HEST_GENERIC_STATUS; + +/* Values for BlockStatus flags above */ + +#define ACPI_HEST_UNCORRECTABLE (1) +#define ACPI_HEST_CORRECTABLE (1<<1) +#define ACPI_HEST_MULTIPLE_UNCORRECTABLE (1<<2) +#define ACPI_HEST_MULTIPLE_CORRECTABLE (1<<3) +#define ACPI_HEST_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ + + +/* Generic Error Data entry */ + +typedef struct acpi_hest_generic_data +{ + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + +} ACPI_HEST_GENERIC_DATA; + + +/******************************************************************************* + * + * MADT - Multiple APIC Description Table + * Version 3 + * + ******************************************************************************/ + +typedef struct acpi_table_madt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Address; /* Physical address of local APIC */ + UINT32 Flags; + +} ACPI_TABLE_MADT; + +/* Masks for Flags field above */ + +#define ACPI_MADT_PCAT_COMPAT (1) /* 00: System also has dual 8259s */ + +/* Values for PCATCompat flag */ + +#define ACPI_MADT_DUAL_PIC 0 +#define ACPI_MADT_MULTIPLE_APIC 1 + + +/* Values for MADT subtable type in ACPI_SUBTABLE_HEADER */ + +enum AcpiMadtType +{ + ACPI_MADT_TYPE_LOCAL_APIC = 0, + ACPI_MADT_TYPE_IO_APIC = 1, + ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, + ACPI_MADT_TYPE_NMI_SOURCE = 3, + ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, + ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, + ACPI_MADT_TYPE_IO_SAPIC = 6, + ACPI_MADT_TYPE_LOCAL_SAPIC = 7, + ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, + ACPI_MADT_TYPE_LOCAL_X2APIC = 9, + ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, + ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, + ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, + ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, + ACPI_MADT_TYPE_RESERVED = 16 /* 16 and greater are reserved */ +}; + + +/* + * MADT Subtables, correspond to Type in ACPI_SUBTABLE_HEADER + */ + +/* 0: Processor Local APIC */ + +typedef struct acpi_madt_local_apic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProcessorId; /* ACPI processor id */ + UINT8 Id; /* Processor's local APIC id */ + UINT32 LapicFlags; + +} ACPI_MADT_LOCAL_APIC; + + +/* 1: IO APIC */ + +typedef struct acpi_madt_io_apic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Id; /* I/O APIC ID */ + UINT8 Reserved; /* Reserved - must be zero */ + UINT32 Address; /* APIC physical address */ + UINT32 GlobalIrqBase; /* Global system interrupt where INTI lines start */ + +} ACPI_MADT_IO_APIC; + + +/* 2: Interrupt Override */ + +typedef struct acpi_madt_interrupt_override +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Bus; /* 0 - ISA */ + UINT8 SourceIrq; /* Interrupt source (IRQ) */ + UINT32 GlobalIrq; /* Global system interrupt */ + UINT16 IntiFlags; + +} ACPI_MADT_INTERRUPT_OVERRIDE; + + +/* 3: NMI Source */ + +typedef struct acpi_madt_nmi_source +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 IntiFlags; + UINT32 GlobalIrq; /* Global system interrupt */ + +} ACPI_MADT_NMI_SOURCE; + + +/* 4: Local APIC NMI */ + +typedef struct acpi_madt_local_apic_nmi +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProcessorId; /* ACPI processor id */ + UINT16 IntiFlags; + UINT8 Lint; /* LINTn to which NMI is connected */ + +} ACPI_MADT_LOCAL_APIC_NMI; + + +/* 5: Address Override */ + +typedef struct acpi_madt_local_apic_override +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved, must be zero */ + UINT64 Address; /* APIC physical address */ + +} ACPI_MADT_LOCAL_APIC_OVERRIDE; + + +/* 6: I/O Sapic */ + +typedef struct acpi_madt_io_sapic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Id; /* I/O SAPIC ID */ + UINT8 Reserved; /* Reserved, must be zero */ + UINT32 GlobalIrqBase; /* Global interrupt for SAPIC start */ + UINT64 Address; /* SAPIC physical address */ + +} ACPI_MADT_IO_SAPIC; + + +/* 7: Local Sapic */ + +typedef struct acpi_madt_local_sapic +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProcessorId; /* ACPI processor id */ + UINT8 Id; /* SAPIC ID */ + UINT8 Eid; /* SAPIC EID */ + UINT8 Reserved[3]; /* Reserved, must be zero */ + UINT32 LapicFlags; + UINT32 Uid; /* Numeric UID - ACPI 3.0 */ + char UidString[1]; /* String UID - ACPI 3.0 */ + +} ACPI_MADT_LOCAL_SAPIC; + + +/* 8: Platform Interrupt Source */ + +typedef struct acpi_madt_interrupt_source +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 IntiFlags; + UINT8 Type; /* 1=PMI, 2=INIT, 3=corrected */ + UINT8 Id; /* Processor ID */ + UINT8 Eid; /* Processor EID */ + UINT8 IoSapicVector; /* Vector value for PMI interrupts */ + UINT32 GlobalIrq; /* Global system interrupt */ + UINT32 Flags; /* Interrupt Source Flags */ + +} ACPI_MADT_INTERRUPT_SOURCE; + +/* Masks for Flags field above */ + +#define ACPI_MADT_CPEI_OVERRIDE (1) + + +/* 9: Processor Local X2APIC (ACPI 4.0) */ + +typedef struct acpi_madt_local_x2apic +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 LocalApicId; /* Processor x2APIC ID */ + UINT32 LapicFlags; + UINT32 Uid; /* ACPI processor UID */ + +} ACPI_MADT_LOCAL_X2APIC; + + +/* 10: Local X2APIC NMI (ACPI 4.0) */ + +typedef struct acpi_madt_local_x2apic_nmi +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 IntiFlags; + UINT32 Uid; /* ACPI processor UID */ + UINT8 Lint; /* LINTn to which NMI is connected */ + UINT8 Reserved[3]; /* Reserved - must be zero */ + +} ACPI_MADT_LOCAL_X2APIC_NMI; + + +/* 11: Generic Interrupt (ACPI 5.0 + ACPI 6.0 changes) */ + +typedef struct acpi_madt_generic_interrupt +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 CpuInterfaceNumber; + UINT32 Uid; + UINT32 Flags; + UINT32 ParkingVersion; + UINT32 PerformanceInterrupt; + UINT64 ParkedAddress; + UINT64 BaseAddress; + UINT64 GicvBaseAddress; + UINT64 GichBaseAddress; + UINT32 VgicInterrupt; + UINT64 GicrBaseAddress; + UINT64 ArmMpidr; + UINT8 EfficiencyClass; + UINT8 Reserved2[3]; + +} ACPI_MADT_GENERIC_INTERRUPT; + +/* Masks for Flags field above */ + +/* ACPI_MADT_ENABLED (1) Processor is usable if set */ +#define ACPI_MADT_PERFORMANCE_IRQ_MODE (1<<1) /* 01: Performance Interrupt Mode */ +#define ACPI_MADT_VGIC_IRQ_MODE (1<<2) /* 02: VGIC Maintenance Interrupt mode */ + + +/* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */ + +typedef struct acpi_madt_generic_distributor +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 GicId; + UINT64 BaseAddress; + UINT32 GlobalIrqBase; + UINT8 Version; + UINT8 Reserved2[3]; /* Reserved - must be zero */ + +} ACPI_MADT_GENERIC_DISTRIBUTOR; + +/* Values for Version field above */ + +enum AcpiMadtGicVersion +{ + ACPI_MADT_GIC_VERSION_NONE = 0, + ACPI_MADT_GIC_VERSION_V1 = 1, + ACPI_MADT_GIC_VERSION_V2 = 2, + ACPI_MADT_GIC_VERSION_V3 = 3, + ACPI_MADT_GIC_VERSION_V4 = 4, + ACPI_MADT_GIC_VERSION_RESERVED = 5 /* 5 and greater are reserved */ +}; + + +/* 13: Generic MSI Frame (ACPI 5.1) */ + +typedef struct acpi_madt_generic_msi_frame +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved - must be zero */ + UINT32 MsiFrameId; + UINT64 BaseAddress; + UINT32 Flags; + UINT16 SpiCount; + UINT16 SpiBase; + +} ACPI_MADT_GENERIC_MSI_FRAME; + +/* Masks for Flags field above */ + +#define ACPI_MADT_OVERRIDE_SPI_VALUES (1) + + +/* 14: Generic Redistributor (ACPI 5.1) */ + +typedef struct acpi_madt_generic_redistributor +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* reserved - must be zero */ + UINT64 BaseAddress; + UINT32 Length; + +} ACPI_MADT_GENERIC_REDISTRIBUTOR; + + +/* 15: Generic Translator (ACPI 6.0) */ + +typedef struct acpi_madt_generic_translator +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* reserved - must be zero */ + UINT32 TranslationId; + UINT64 BaseAddress; + UINT32 Reserved2; + +} ACPI_MADT_GENERIC_TRANSLATOR; + + +/* + * Common flags fields for MADT subtables + */ + +/* MADT Local APIC flags */ + +#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ + +/* MADT MPS INTI flags (IntiFlags) */ + +#define ACPI_MADT_POLARITY_MASK (3) /* 00-01: Polarity of APIC I/O input signals */ +#define ACPI_MADT_TRIGGER_MASK (3<<2) /* 02-03: Trigger mode of APIC input signals */ + +/* Values for MPS INTI flags */ + +#define ACPI_MADT_POLARITY_CONFORMS 0 +#define ACPI_MADT_POLARITY_ACTIVE_HIGH 1 +#define ACPI_MADT_POLARITY_RESERVED 2 +#define ACPI_MADT_POLARITY_ACTIVE_LOW 3 + +#define ACPI_MADT_TRIGGER_CONFORMS (0) +#define ACPI_MADT_TRIGGER_EDGE (1<<2) +#define ACPI_MADT_TRIGGER_RESERVED (2<<2) +#define ACPI_MADT_TRIGGER_LEVEL (3<<2) + + +/******************************************************************************* + * + * MSCT - Maximum System Characteristics Table (ACPI 4.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_msct +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 ProximityOffset; /* Location of proximity info struct(s) */ + UINT32 MaxProximityDomains;/* Max number of proximity domains */ + UINT32 MaxClockDomains; /* Max number of clock domains */ + UINT64 MaxAddress; /* Max physical address in system */ + +} ACPI_TABLE_MSCT; + + +/* Subtable - Maximum Proximity Domain Information. Version 1 */ + +typedef struct acpi_msct_proximity +{ + UINT8 Revision; + UINT8 Length; + UINT32 RangeStart; /* Start of domain range */ + UINT32 RangeEnd; /* End of domain range */ + UINT32 ProcessorCapacity; + UINT64 MemoryCapacity; /* In bytes */ + +} ACPI_MSCT_PROXIMITY; + + +/******************************************************************************* + * + * NFIT - NVDIMM Interface Table (ACPI 6.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_nfit +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Reserved; /* Reserved, must be zero */ + +} ACPI_TABLE_NFIT; + +/* Subtable header for NFIT */ + +typedef struct acpi_nfit_header +{ + UINT16 Type; + UINT16 Length; + +} ACPI_NFIT_HEADER; + + +/* Values for subtable type in ACPI_NFIT_HEADER */ + +enum AcpiNfitType +{ + ACPI_NFIT_TYPE_SYSTEM_ADDRESS = 0, + ACPI_NFIT_TYPE_MEMORY_MAP = 1, + ACPI_NFIT_TYPE_INTERLEAVE = 2, + ACPI_NFIT_TYPE_SMBIOS = 3, + ACPI_NFIT_TYPE_CONTROL_REGION = 4, + ACPI_NFIT_TYPE_DATA_REGION = 5, + ACPI_NFIT_TYPE_FLUSH_ADDRESS = 6, + ACPI_NFIT_TYPE_RESERVED = 7 /* 7 and greater are reserved */ +}; + +/* + * NFIT Subtables + */ + +/* 0: System Physical Address Range Structure */ + +typedef struct acpi_nfit_system_address +{ + ACPI_NFIT_HEADER Header; + UINT16 RangeIndex; + UINT16 Flags; + UINT32 Reserved; /* Reseved, must be zero */ + UINT32 ProximityDomain; + UINT8 RangeGuid[16]; + UINT64 Address; + UINT64 Length; + UINT64 MemoryMapping; + +} ACPI_NFIT_SYSTEM_ADDRESS; + +/* Flags */ + +#define ACPI_NFIT_ADD_ONLINE_ONLY (1) /* 00: Add/Online Operation Only */ +#define ACPI_NFIT_PROXIMITY_VALID (1<<1) /* 01: Proximity Domain Valid */ + +/* Range Type GUIDs appear in the include/acuuid.h file */ + + +/* 1: Memory Device to System Address Range Map Structure */ + +typedef struct acpi_nfit_memory_map +{ + ACPI_NFIT_HEADER Header; + UINT32 DeviceHandle; + UINT16 PhysicalId; + UINT16 RegionId; + UINT16 RangeIndex; + UINT16 RegionIndex; + UINT64 RegionSize; + UINT64 RegionOffset; + UINT64 Address; + UINT16 InterleaveIndex; + UINT16 InterleaveWays; + UINT16 Flags; + UINT16 Reserved; /* Reserved, must be zero */ + +} ACPI_NFIT_MEMORY_MAP; + +/* Flags */ + +#define ACPI_NFIT_MEM_SAVE_FAILED (1) /* 00: Last SAVE to Memory Device failed */ +#define ACPI_NFIT_MEM_RESTORE_FAILED (1<<1) /* 01: Last RESTORE from Memory Device failed */ +#define ACPI_NFIT_MEM_FLUSH_FAILED (1<<2) /* 02: Platform flush failed */ +#define ACPI_NFIT_MEM_NOT_ARMED (1<<3) /* 03: Memory Device is not armed */ +#define ACPI_NFIT_MEM_HEALTH_OBSERVED (1<<4) /* 04: Memory Device observed SMART/health events */ +#define ACPI_NFIT_MEM_HEALTH_ENABLED (1<<5) /* 05: SMART/health events enabled */ + + +/* 2: Interleave Structure */ + +typedef struct acpi_nfit_interleave +{ + ACPI_NFIT_HEADER Header; + UINT16 InterleaveIndex; + UINT16 Reserved; /* Reserved, must be zero */ + UINT32 LineCount; + UINT32 LineSize; + UINT32 LineOffset[1]; /* Variable length */ + +} ACPI_NFIT_INTERLEAVE; + + +/* 3: SMBIOS Management Information Structure */ + +typedef struct acpi_nfit_smbios +{ + ACPI_NFIT_HEADER Header; + UINT32 Reserved; /* Reserved, must be zero */ + UINT8 Data[1]; /* Variable length */ + +} ACPI_NFIT_SMBIOS; + + +/* 4: NVDIMM Control Region Structure */ + +typedef struct acpi_nfit_control_region +{ + ACPI_NFIT_HEADER Header; + UINT16 RegionIndex; + UINT16 VendorId; + UINT16 DeviceId; + UINT16 RevisionId; + UINT16 SubsystemVendorId; + UINT16 SubsystemDeviceId; + UINT16 SubsystemRevisionId; + UINT8 Reserved[6]; /* Reserved, must be zero */ + UINT32 SerialNumber; + UINT16 Code; + UINT16 Windows; + UINT64 WindowSize; + UINT64 CommandOffset; + UINT64 CommandSize; + UINT64 StatusOffset; + UINT64 StatusSize; + UINT16 Flags; + UINT8 Reserved1[6]; /* Reserved, must be zero */ + +} ACPI_NFIT_CONTROL_REGION; + +/* Flags */ + +#define ACPI_NFIT_CONTROL_BUFFERED (1) /* Block Data Windows implementation is buffered */ + + +/* 5: NVDIMM Block Data Window Region Structure */ + +typedef struct acpi_nfit_data_region +{ + ACPI_NFIT_HEADER Header; + UINT16 RegionIndex; + UINT16 Windows; + UINT64 Offset; + UINT64 Size; + UINT64 Capacity; + UINT64 StartAddress; + +} ACPI_NFIT_DATA_REGION; + + +/* 6: Flush Hint Address Structure */ + +typedef struct acpi_nfit_flush_address +{ + ACPI_NFIT_HEADER Header; + UINT32 DeviceHandle; + UINT16 HintCount; + UINT8 Reserved[6]; /* Reserved, must be zero */ + UINT64 HintAddress[1]; /* Variable length */ + +} ACPI_NFIT_FLUSH_ADDRESS; + + +/******************************************************************************* + * + * SBST - Smart Battery Specification Table + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_sbst +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 WarningLevel; + UINT32 LowLevel; + UINT32 CriticalLevel; + +} ACPI_TABLE_SBST; + + +/******************************************************************************* + * + * SLIT - System Locality Distance Information Table + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_slit +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 LocalityCount; + UINT8 Entry[1]; /* Real size = localities^2 */ + +} ACPI_TABLE_SLIT; + + +/******************************************************************************* + * + * SRAT - System Resource Affinity Table + * Version 3 + * + ******************************************************************************/ + +typedef struct acpi_table_srat +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 TableRevision; /* Must be value '1' */ + UINT64 Reserved; /* Reserved, must be zero */ + +} ACPI_TABLE_SRAT; + +/* Values for subtable type in ACPI_SUBTABLE_HEADER */ + +enum AcpiSratType +{ + ACPI_SRAT_TYPE_CPU_AFFINITY = 0, + ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1, + ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2, + ACPI_SRAT_TYPE_GICC_AFFINITY = 3, + ACPI_SRAT_TYPE_RESERVED = 4 /* 4 and greater are reserved */ +}; + +/* + * SRAT Subtables, correspond to Type in ACPI_SUBTABLE_HEADER + */ + +/* 0: Processor Local APIC/SAPIC Affinity */ + +typedef struct acpi_srat_cpu_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 ProximityDomainLo; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomainHi[3]; + UINT32 ClockDomain; + +} ACPI_SRAT_CPU_AFFINITY; + +/* Flags */ + +#define ACPI_SRAT_CPU_USE_AFFINITY (1) /* 00: Use affinity structure */ + + +/* 1: Memory Affinity */ + +typedef struct acpi_srat_mem_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 ProximityDomain; + UINT16 Reserved; /* Reserved, must be zero */ + UINT64 BaseAddress; + UINT64 Length; + UINT32 Reserved1; + UINT32 Flags; + UINT64 Reserved2; /* Reserved, must be zero */ + +} ACPI_SRAT_MEM_AFFINITY; + +/* Flags */ + +#define ACPI_SRAT_MEM_ENABLED (1) /* 00: Use affinity structure */ +#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */ +#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */ + + +/* 2: Processor Local X2_APIC Affinity (ACPI 4.0) */ + +typedef struct acpi_srat_x2apic_cpu_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT16 Reserved; /* Reserved, must be zero */ + UINT32 ProximityDomain; + UINT32 ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT32 Reserved2; + +} ACPI_SRAT_X2APIC_CPU_AFFINITY; + +/* Flags for ACPI_SRAT_CPU_AFFINITY and ACPI_SRAT_X2APIC_CPU_AFFINITY */ + +#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */ + + +/* 3: GICC Affinity (ACPI 5.1) */ + +typedef struct acpi_srat_gicc_affinity +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; + +} ACPI_SRAT_GICC_AFFINITY; + +/* Flags for ACPI_SRAT_GICC_AFFINITY */ + +#define ACPI_SRAT_GICC_ENABLED (1) /* 00: Use affinity structure */ + + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL1_H__ */ diff --git a/third_party/lib/acpica/source/include/actbl2.h b/third_party/lib/acpica/source/include/actbl2.h new file mode 100644 index 000000000..2a955bac4 --- /dev/null +++ b/third_party/lib/acpica/source/include/actbl2.h @@ -0,0 +1,1692 @@ +/****************************************************************************** + * + * Name: actbl2.h - ACPI Table Definitions (tables not in ACPI spec) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTBL2_H__ +#define __ACTBL2_H__ + + +/******************************************************************************* + * + * Additional ACPI Tables (2) + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + * Generally, the tables in this file are defined by third-party specifications, + * and are not defined directly by the ACPI specification itself. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */ +#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */ +#define ACPI_SIG_CSRT "CSRT" /* Core System Resource Table */ +#define ACPI_SIG_DBG2 "DBG2" /* Debug Port table type 2 */ +#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */ +#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */ +#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ +#define ACPI_SIG_IBFT "IBFT" /* iSCSI Boot Firmware Table */ +#define ACPI_SIG_IORT "IORT" /* IO Remapping Table */ +#define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */ +#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */ +#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */ +#define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */ +#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ +#define ACPI_SIG_MTMR "MTMR" /* MID Timer table */ +#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */ +#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */ +#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */ +#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ +#define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ +#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */ +#define ACPI_SIG_VRTC "VRTC" /* Virtual Real Time Clock Table */ +#define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */ +#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */ +#define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */ +#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */ + +#ifdef ACPI_UNDEFINED_TABLES +/* + * These tables have been seen in the field, but no definition has been found + */ +#define ACPI_SIG_ATKG "ATKG" +#define ACPI_SIG_GSCI "GSCI" /* GMCH SCI table */ +#define ACPI_SIG_IEIT "IEIT" +#endif + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * ASF - Alert Standard Format table (Signature "ASF!") + * Revision 0x10 + * + * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003 + * + ******************************************************************************/ + +typedef struct acpi_table_asf +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_ASF; + + +/* ASF subtable header */ + +typedef struct acpi_asf_header +{ + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + +} ACPI_ASF_HEADER; + + +/* Values for Type field above */ + +enum AcpiAsfType +{ + ACPI_ASF_TYPE_INFO = 0, + ACPI_ASF_TYPE_ALERT = 1, + ACPI_ASF_TYPE_CONTROL = 2, + ACPI_ASF_TYPE_BOOT = 3, + ACPI_ASF_TYPE_ADDRESS = 4, + ACPI_ASF_TYPE_RESERVED = 5 +}; + +/* + * ASF subtables + */ + +/* 0: ASF Information */ + +typedef struct acpi_asf_info +{ + ACPI_ASF_HEADER Header; + UINT8 MinResetValue; + UINT8 MinPollInterval; + UINT16 SystemId; + UINT32 MfgId; + UINT8 Flags; + UINT8 Reserved2[3]; + +} ACPI_ASF_INFO; + +/* Masks for Flags field above */ + +#define ACPI_ASF_SMBUS_PROTOCOLS (1) + + +/* 1: ASF Alerts */ + +typedef struct acpi_asf_alert +{ + ACPI_ASF_HEADER Header; + UINT8 AssertMask; + UINT8 DeassertMask; + UINT8 Alerts; + UINT8 DataLength; + +} ACPI_ASF_ALERT; + +typedef struct acpi_asf_alert_data +{ + UINT8 Address; + UINT8 Command; + UINT8 Mask; + UINT8 Value; + UINT8 SensorType; + UINT8 Type; + UINT8 Offset; + UINT8 SourceType; + UINT8 Severity; + UINT8 SensorNumber; + UINT8 Entity; + UINT8 Instance; + +} ACPI_ASF_ALERT_DATA; + + +/* 2: ASF Remote Control */ + +typedef struct acpi_asf_remote +{ + ACPI_ASF_HEADER Header; + UINT8 Controls; + UINT8 DataLength; + UINT16 Reserved2; + +} ACPI_ASF_REMOTE; + +typedef struct acpi_asf_control_data +{ + UINT8 Function; + UINT8 Address; + UINT8 Command; + UINT8 Value; + +} ACPI_ASF_CONTROL_DATA; + + +/* 3: ASF RMCP Boot Options */ + +typedef struct acpi_asf_rmcp +{ + ACPI_ASF_HEADER Header; + UINT8 Capabilities[7]; + UINT8 CompletionCode; + UINT32 EnterpriseId; + UINT8 Command; + UINT16 Parameter; + UINT16 BootOptions; + UINT16 OemParameters; + +} ACPI_ASF_RMCP; + + +/* 4: ASF Address */ + +typedef struct acpi_asf_address +{ + ACPI_ASF_HEADER Header; + UINT8 EpromAddress; + UINT8 Devices; + +} ACPI_ASF_ADDRESS; + + +/******************************************************************************* + * + * BOOT - Simple Boot Flag Table + * Version 1 + * + * Conforms to the "Simple Boot Flag Specification", Version 2.1 + * + ******************************************************************************/ + +typedef struct acpi_table_boot +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 CmosIndex; /* Index in CMOS RAM for the boot register */ + UINT8 Reserved[3]; + +} ACPI_TABLE_BOOT; + + +/******************************************************************************* + * + * CSRT - Core System Resource Table + * Version 0 + * + * Conforms to the "Core System Resource Table (CSRT)", November 14, 2011 + * + ******************************************************************************/ + +typedef struct acpi_table_csrt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_CSRT; + + +/* Resource Group subtable */ + +typedef struct acpi_csrt_group +{ + UINT32 Length; + UINT32 VendorId; + UINT32 SubvendorId; + UINT16 DeviceId; + UINT16 SubdeviceId; + UINT16 Revision; + UINT16 Reserved; + UINT32 SharedInfoLength; + + /* Shared data immediately follows (Length = SharedInfoLength) */ + +} ACPI_CSRT_GROUP; + +/* Shared Info subtable */ + +typedef struct acpi_csrt_shared_info +{ + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 MmioBaseLow; + UINT32 MmioBaseHigh; + UINT32 GsiInterrupt; + UINT8 InterruptPolarity; + UINT8 InterruptMode; + UINT8 NumChannels; + UINT8 DmaAddressWidth; + UINT16 BaseRequestLine; + UINT16 NumHandshakeSignals; + UINT32 MaxBlockSize; + + /* Resource descriptors immediately follow (Length = Group Length - SharedInfoLength) */ + +} ACPI_CSRT_SHARED_INFO; + +/* Resource Descriptor subtable */ + +typedef struct acpi_csrt_descriptor +{ + UINT32 Length; + UINT16 Type; + UINT16 Subtype; + UINT32 Uid; + + /* Resource-specific information immediately follows */ + +} ACPI_CSRT_DESCRIPTOR; + + +/* Resource Types */ + +#define ACPI_CSRT_TYPE_INTERRUPT 0x0001 +#define ACPI_CSRT_TYPE_TIMER 0x0002 +#define ACPI_CSRT_TYPE_DMA 0x0003 + +/* Resource Subtypes */ + +#define ACPI_CSRT_XRUPT_LINE 0x0000 +#define ACPI_CSRT_XRUPT_CONTROLLER 0x0001 +#define ACPI_CSRT_TIMER 0x0000 +#define ACPI_CSRT_DMA_CHANNEL 0x0000 +#define ACPI_CSRT_DMA_CONTROLLER 0x0001 + + +/******************************************************************************* + * + * DBG2 - Debug Port Table 2 + * Version 0 (Both main table and subtables) + * + * Conforms to "Microsoft Debug Port Table 2 (DBG2)", May 22 2012. + * + ******************************************************************************/ + +typedef struct acpi_table_dbg2 +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 InfoOffset; + UINT32 InfoCount; + +} ACPI_TABLE_DBG2; + + +typedef struct acpi_dbg2_header +{ + UINT32 InfoOffset; + UINT32 InfoCount; + +} ACPI_DBG2_HEADER; + + +/* Debug Device Information Subtable */ + +typedef struct acpi_dbg2_device +{ + UINT8 Revision; + UINT16 Length; + UINT8 RegisterCount; /* Number of BaseAddress registers */ + UINT16 NamepathLength; + UINT16 NamepathOffset; + UINT16 OemDataLength; + UINT16 OemDataOffset; + UINT16 PortType; + UINT16 PortSubtype; + UINT16 Reserved; + UINT16 BaseAddressOffset; + UINT16 AddressSizeOffset; + /* + * Data that follows: + * BaseAddress (required) - Each in 12-byte Generic Address Structure format. + * AddressSize (required) - Array of UINT32 sizes corresponding to each BaseAddress register. + * Namepath (required) - Null terminated string. Single dot if not supported. + * OemData (optional) - Length is OemDataLength. + */ +} ACPI_DBG2_DEVICE; + +/* Types for PortType field above */ + +#define ACPI_DBG2_SERIAL_PORT 0x8000 +#define ACPI_DBG2_1394_PORT 0x8001 +#define ACPI_DBG2_USB_PORT 0x8002 +#define ACPI_DBG2_NET_PORT 0x8003 + +/* Subtypes for PortSubtype field above */ + +#define ACPI_DBG2_16550_COMPATIBLE 0x0000 +#define ACPI_DBG2_16550_SUBSET 0x0001 + +#define ACPI_DBG2_1394_STANDARD 0x0000 + +#define ACPI_DBG2_USB_XHCI 0x0000 +#define ACPI_DBG2_USB_EHCI 0x0001 + + +/******************************************************************************* + * + * DBGP - Debug Port table + * Version 1 + * + * Conforms to the "Debug Port Specification", Version 1.00, 2/9/2000 + * + ******************************************************************************/ + +typedef struct acpi_table_dbgp +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Type; /* 0=full 16550, 1=subset of 16550 */ + UINT8 Reserved[3]; + ACPI_GENERIC_ADDRESS DebugPort; + +} ACPI_TABLE_DBGP; + + +/******************************************************************************* + * + * DMAR - DMA Remapping table + * Version 1 + * + * Conforms to "Intel Virtualization Technology for Directed I/O", + * Version 2.2, Sept. 2013 + * + ******************************************************************************/ + +typedef struct acpi_table_dmar +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Width; /* Host Address Width */ + UINT8 Flags; + UINT8 Reserved[10]; + +} ACPI_TABLE_DMAR; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_INTR_REMAP (1) + + +/* DMAR subtable header */ + +typedef struct acpi_dmar_header +{ + UINT16 Type; + UINT16 Length; + +} ACPI_DMAR_HEADER; + +/* Values for subtable type in ACPI_DMAR_HEADER */ + +enum AcpiDmarType +{ + ACPI_DMAR_TYPE_HARDWARE_UNIT = 0, + ACPI_DMAR_TYPE_RESERVED_MEMORY = 1, + ACPI_DMAR_TYPE_ROOT_ATS = 2, + ACPI_DMAR_TYPE_HARDWARE_AFFINITY = 3, + ACPI_DMAR_TYPE_NAMESPACE = 4, + ACPI_DMAR_TYPE_RESERVED = 5 /* 5 and greater are reserved */ +}; + + +/* DMAR Device Scope structure */ + +typedef struct acpi_dmar_device_scope +{ + UINT8 EntryType; + UINT8 Length; + UINT16 Reserved; + UINT8 EnumerationId; + UINT8 Bus; + +} ACPI_DMAR_DEVICE_SCOPE; + +/* Values for EntryType in ACPI_DMAR_DEVICE_SCOPE - device types */ + +enum AcpiDmarScopeType +{ + ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0, + ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1, + ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2, + ACPI_DMAR_SCOPE_TYPE_IOAPIC = 3, + ACPI_DMAR_SCOPE_TYPE_HPET = 4, + ACPI_DMAR_SCOPE_TYPE_NAMESPACE = 5, + ACPI_DMAR_SCOPE_TYPE_RESERVED = 6 /* 6 and greater are reserved */ +}; + +typedef struct acpi_dmar_pci_path +{ + UINT8 Device; + UINT8 Function; + +} ACPI_DMAR_PCI_PATH; + + +/* + * DMAR Subtables, correspond to Type in ACPI_DMAR_HEADER + */ + +/* 0: Hardware Unit Definition */ + +typedef struct acpi_dmar_hardware_unit +{ + ACPI_DMAR_HEADER Header; + UINT8 Flags; + UINT8 Reserved; + UINT16 Segment; + UINT64 Address; /* Register Base Address */ + +} ACPI_DMAR_HARDWARE_UNIT; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_INCLUDE_ALL (1) + + +/* 1: Reserved Memory Defininition */ + +typedef struct acpi_dmar_reserved_memory +{ + ACPI_DMAR_HEADER Header; + UINT16 Reserved; + UINT16 Segment; + UINT64 BaseAddress; /* 4K aligned base address */ + UINT64 EndAddress; /* 4K aligned limit address */ + +} ACPI_DMAR_RESERVED_MEMORY; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_ALLOW_ALL (1) + + +/* 2: Root Port ATS Capability Reporting Structure */ + +typedef struct acpi_dmar_atsr +{ + ACPI_DMAR_HEADER Header; + UINT8 Flags; + UINT8 Reserved; + UINT16 Segment; + +} ACPI_DMAR_ATSR; + +/* Masks for Flags field above */ + +#define ACPI_DMAR_ALL_PORTS (1) + + +/* 3: Remapping Hardware Static Affinity Structure */ + +typedef struct acpi_dmar_rhsa +{ + ACPI_DMAR_HEADER Header; + UINT32 Reserved; + UINT64 BaseAddress; + UINT32 ProximityDomain; + +} ACPI_DMAR_RHSA; + + +/* 4: ACPI Namespace Device Declaration Structure */ + +typedef struct acpi_dmar_andd +{ + ACPI_DMAR_HEADER Header; + UINT8 Reserved[3]; + UINT8 DeviceNumber; + char DeviceName[1]; + +} ACPI_DMAR_ANDD; + + +/******************************************************************************* + * + * HPET - High Precision Event Timer table + * Version 1 + * + * Conforms to "IA-PC HPET (High Precision Event Timers) Specification", + * Version 1.0a, October 2004 + * + ******************************************************************************/ + +typedef struct acpi_table_hpet +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Id; /* Hardware ID of event timer block */ + ACPI_GENERIC_ADDRESS Address; /* Address of event timer block */ + UINT8 Sequence; /* HPET sequence number */ + UINT16 MinimumTick; /* Main counter min tick, periodic mode */ + UINT8 Flags; + +} ACPI_TABLE_HPET; + +/* Masks for Flags field above */ + +#define ACPI_HPET_PAGE_PROTECT_MASK (3) + +/* Values for Page Protect flags */ + +enum AcpiHpetPageProtect +{ + ACPI_HPET_NO_PAGE_PROTECT = 0, + ACPI_HPET_PAGE_PROTECT4 = 1, + ACPI_HPET_PAGE_PROTECT64 = 2 +}; + + +/******************************************************************************* + * + * IBFT - Boot Firmware Table + * Version 1 + * + * Conforms to "iSCSI Boot Firmware Table (iBFT) as Defined in ACPI 3.0b + * Specification", Version 1.01, March 1, 2007 + * + * Note: It appears that this table is not intended to appear in the RSDT/XSDT. + * Therefore, it is not currently supported by the disassembler. + * + ******************************************************************************/ + +typedef struct acpi_table_ibft +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Reserved[12]; + +} ACPI_TABLE_IBFT; + + +/* IBFT common subtable header */ + +typedef struct acpi_ibft_header +{ + UINT8 Type; + UINT8 Version; + UINT16 Length; + UINT8 Index; + UINT8 Flags; + +} ACPI_IBFT_HEADER; + +/* Values for Type field above */ + +enum AcpiIbftType +{ + ACPI_IBFT_TYPE_NOT_USED = 0, + ACPI_IBFT_TYPE_CONTROL = 1, + ACPI_IBFT_TYPE_INITIATOR = 2, + ACPI_IBFT_TYPE_NIC = 3, + ACPI_IBFT_TYPE_TARGET = 4, + ACPI_IBFT_TYPE_EXTENSIONS = 5, + ACPI_IBFT_TYPE_RESERVED = 6 /* 6 and greater are reserved */ +}; + + +/* IBFT subtables */ + +typedef struct acpi_ibft_control +{ + ACPI_IBFT_HEADER Header; + UINT16 Extensions; + UINT16 InitiatorOffset; + UINT16 Nic0Offset; + UINT16 Target0Offset; + UINT16 Nic1Offset; + UINT16 Target1Offset; + +} ACPI_IBFT_CONTROL; + +typedef struct acpi_ibft_initiator +{ + ACPI_IBFT_HEADER Header; + UINT8 SnsServer[16]; + UINT8 SlpServer[16]; + UINT8 PrimaryServer[16]; + UINT8 SecondaryServer[16]; + UINT16 NameLength; + UINT16 NameOffset; + +} ACPI_IBFT_INITIATOR; + +typedef struct acpi_ibft_nic +{ + ACPI_IBFT_HEADER Header; + UINT8 IpAddress[16]; + UINT8 SubnetMaskPrefix; + UINT8 Origin; + UINT8 Gateway[16]; + UINT8 PrimaryDns[16]; + UINT8 SecondaryDns[16]; + UINT8 Dhcp[16]; + UINT16 Vlan; + UINT8 MacAddress[6]; + UINT16 PciAddress; + UINT16 NameLength; + UINT16 NameOffset; + +} ACPI_IBFT_NIC; + +typedef struct acpi_ibft_target +{ + ACPI_IBFT_HEADER Header; + UINT8 TargetIpAddress[16]; + UINT16 TargetIpSocket; + UINT8 TargetBootLun[8]; + UINT8 ChapType; + UINT8 NicAssociation; + UINT16 TargetNameLength; + UINT16 TargetNameOffset; + UINT16 ChapNameLength; + UINT16 ChapNameOffset; + UINT16 ChapSecretLength; + UINT16 ChapSecretOffset; + UINT16 ReverseChapNameLength; + UINT16 ReverseChapNameOffset; + UINT16 ReverseChapSecretLength; + UINT16 ReverseChapSecretOffset; + +} ACPI_IBFT_TARGET; + + +/******************************************************************************* + * + * IORT - IO Remapping Table + * + * Conforms to "IO Remapping Table System Software on ARM Platforms", + * Document number: ARM DEN 0049A, 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_iort +{ + ACPI_TABLE_HEADER Header; + UINT32 NodeCount; + UINT32 NodeOffset; + UINT32 Reserved; + +} ACPI_TABLE_IORT; + + +/* + * IORT subtables + */ +typedef struct acpi_iort_node +{ + UINT8 Type; + UINT16 Length; + UINT8 Revision; + UINT32 Reserved; + UINT32 MappingCount; + UINT32 MappingOffset; + char NodeData[1]; + +} ACPI_IORT_NODE; + +/* Values for subtable Type above */ + +enum AcpiIortNodeType +{ + ACPI_IORT_NODE_ITS_GROUP = 0x00, + ACPI_IORT_NODE_NAMED_COMPONENT = 0x01, + ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02, + ACPI_IORT_NODE_SMMU = 0x03 +}; + + +typedef struct acpi_iort_id_mapping +{ + UINT32 InputBase; /* Lowest value in input range */ + UINT32 IdCount; /* Number of IDs */ + UINT32 OutputBase; /* Lowest value in output range */ + UINT32 OutputReference; /* A reference to the output node */ + UINT32 Flags; + +} ACPI_IORT_ID_MAPPING; + +/* Masks for Flags field above for IORT subtable */ + +#define ACPI_IORT_ID_SINGLE_MAPPING (1) + + +typedef struct acpi_iort_memory_access +{ + UINT32 CacheCoherency; + UINT8 Hints; + UINT16 Reserved; + UINT8 MemoryFlags; + +} ACPI_IORT_MEMORY_ACCESS; + +/* Values for CacheCoherency field above */ + +#define ACPI_IORT_NODE_COHERENT 0x00000001 /* The device node is fully coherent */ +#define ACPI_IORT_NODE_NOT_COHERENT 0x00000000 /* The device node is not coherent */ + +/* Masks for Hints field above */ + +#define ACPI_IORT_HT_TRANSIENT (1) +#define ACPI_IORT_HT_WRITE (1<<1) +#define ACPI_IORT_HT_READ (1<<2) +#define ACPI_IORT_HT_OVERRIDE (1<<3) + +/* Masks for MemoryFlags field above */ + +#define ACPI_IORT_MF_COHERENCY (1) +#define ACPI_IORT_MF_ATTRIBUTES (1<<1) + + +/* + * IORT node specific subtables + */ +typedef struct acpi_iort_its_group +{ + UINT32 ItsCount; + UINT32 Identifiers[1]; /* GIC ITS identifier arrary */ + +} ACPI_IORT_ITS_GROUP; + + +typedef struct acpi_iort_named_component +{ + UINT32 NodeFlags; + UINT64 MemoryProperties; /* Memory access properties */ + UINT8 MemoryAddressLimit; /* Memory address size limit */ + char DeviceName[1]; /* Path of namespace object */ + +} ACPI_IORT_NAMED_COMPONENT; + + +typedef struct acpi_iort_root_complex +{ + UINT64 MemoryProperties; /* Memory access properties */ + UINT32 AtsAttribute; + UINT32 PciSegmentNumber; + +} ACPI_IORT_ROOT_COMPLEX; + +/* Values for AtsAttribute field above */ + +#define ACPI_IORT_ATS_SUPPORTED 0x00000001 /* The root complex supports ATS */ +#define ACPI_IORT_ATS_UNSUPPORTED 0x00000000 /* The root complex doesn't support ATS */ + + +typedef struct acpi_iort_smmu +{ + UINT64 BaseAddress; /* SMMU base address */ + UINT64 Span; /* Length of memory range */ + UINT32 Model; + UINT32 Flags; + UINT32 GlobalInterruptOffset; + UINT32 ContextInterruptCount; + UINT32 ContextInterruptOffset; + UINT32 PmuInterruptCount; + UINT32 PmuInterruptOffset; + UINT64 Interrupts[1]; /* Interrupt array */ + +} ACPI_IORT_SMMU; + +/* Values for Model field above */ + +#define ACPI_IORT_SMMU_V1 0x00000000 /* Generic SMMUv1 */ +#define ACPI_IORT_SMMU_V2 0x00000001 /* Generic SMMUv2 */ +#define ACPI_IORT_SMMU_CORELINK_MMU400 0x00000002 /* ARM Corelink MMU-400 */ +#define ACPI_IORT_SMMU_CORELINK_MMU500 0x00000003 /* ARM Corelink MMU-500 */ + +/* Masks for Flags field above */ + +#define ACPI_IORT_SMMU_DVM_SUPPORTED (1) +#define ACPI_IORT_SMMU_COHERENT_WALK (1<<1) + + +/******************************************************************************* + * + * IVRS - I/O Virtualization Reporting Structure + * Version 1 + * + * Conforms to "AMD I/O Virtualization Technology (IOMMU) Specification", + * Revision 1.26, February 2009. + * + ******************************************************************************/ + +typedef struct acpi_table_ivrs +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Info; /* Common virtualization info */ + UINT64 Reserved; + +} ACPI_TABLE_IVRS; + +/* Values for Info field above */ + +#define ACPI_IVRS_PHYSICAL_SIZE 0x00007F00 /* 7 bits, physical address size */ +#define ACPI_IVRS_VIRTUAL_SIZE 0x003F8000 /* 7 bits, virtual address size */ +#define ACPI_IVRS_ATS_RESERVED 0x00400000 /* ATS address translation range reserved */ + + +/* IVRS subtable header */ + +typedef struct acpi_ivrs_header +{ + UINT8 Type; /* Subtable type */ + UINT8 Flags; + UINT16 Length; /* Subtable length */ + UINT16 DeviceId; /* ID of IOMMU */ + +} ACPI_IVRS_HEADER; + +/* Values for subtable Type above */ + +enum AcpiIvrsType +{ + ACPI_IVRS_TYPE_HARDWARE = 0x10, + ACPI_IVRS_TYPE_MEMORY1 = 0x20, + ACPI_IVRS_TYPE_MEMORY2 = 0x21, + ACPI_IVRS_TYPE_MEMORY3 = 0x22 +}; + +/* Masks for Flags field above for IVHD subtable */ + +#define ACPI_IVHD_TT_ENABLE (1) +#define ACPI_IVHD_PASS_PW (1<<1) +#define ACPI_IVHD_RES_PASS_PW (1<<2) +#define ACPI_IVHD_ISOC (1<<3) +#define ACPI_IVHD_IOTLB (1<<4) + +/* Masks for Flags field above for IVMD subtable */ + +#define ACPI_IVMD_UNITY (1) +#define ACPI_IVMD_READ (1<<1) +#define ACPI_IVMD_WRITE (1<<2) +#define ACPI_IVMD_EXCLUSION_RANGE (1<<3) + + +/* + * IVRS subtables, correspond to Type in ACPI_IVRS_HEADER + */ + +/* 0x10: I/O Virtualization Hardware Definition Block (IVHD) */ + +typedef struct acpi_ivrs_hardware +{ + ACPI_IVRS_HEADER Header; + UINT16 CapabilityOffset; /* Offset for IOMMU control fields */ + UINT64 BaseAddress; /* IOMMU control registers */ + UINT16 PciSegmentGroup; + UINT16 Info; /* MSI number and unit ID */ + UINT32 Reserved; + +} ACPI_IVRS_HARDWARE; + +/* Masks for Info field above */ + +#define ACPI_IVHD_MSI_NUMBER_MASK 0x001F /* 5 bits, MSI message number */ +#define ACPI_IVHD_UNIT_ID_MASK 0x1F00 /* 5 bits, UnitID */ + + +/* + * Device Entries for IVHD subtable, appear after ACPI_IVRS_HARDWARE structure. + * Upper two bits of the Type field are the (encoded) length of the structure. + * Currently, only 4 and 8 byte entries are defined. 16 and 32 byte entries + * are reserved for future use but not defined. + */ +typedef struct acpi_ivrs_de_header +{ + UINT8 Type; + UINT16 Id; + UINT8 DataSetting; + +} ACPI_IVRS_DE_HEADER; + +/* Length of device entry is in the top two bits of Type field above */ + +#define ACPI_IVHD_ENTRY_LENGTH 0xC0 + +/* Values for device entry Type field above */ + +enum AcpiIvrsDeviceEntryType +{ + /* 4-byte device entries, all use ACPI_IVRS_DEVICE4 */ + + ACPI_IVRS_TYPE_PAD4 = 0, + ACPI_IVRS_TYPE_ALL = 1, + ACPI_IVRS_TYPE_SELECT = 2, + ACPI_IVRS_TYPE_START = 3, + ACPI_IVRS_TYPE_END = 4, + + /* 8-byte device entries */ + + ACPI_IVRS_TYPE_PAD8 = 64, + ACPI_IVRS_TYPE_NOT_USED = 65, + ACPI_IVRS_TYPE_ALIAS_SELECT = 66, /* Uses ACPI_IVRS_DEVICE8A */ + ACPI_IVRS_TYPE_ALIAS_START = 67, /* Uses ACPI_IVRS_DEVICE8A */ + ACPI_IVRS_TYPE_EXT_SELECT = 70, /* Uses ACPI_IVRS_DEVICE8B */ + ACPI_IVRS_TYPE_EXT_START = 71, /* Uses ACPI_IVRS_DEVICE8B */ + ACPI_IVRS_TYPE_SPECIAL = 72 /* Uses ACPI_IVRS_DEVICE8C */ +}; + +/* Values for Data field above */ + +#define ACPI_IVHD_INIT_PASS (1) +#define ACPI_IVHD_EINT_PASS (1<<1) +#define ACPI_IVHD_NMI_PASS (1<<2) +#define ACPI_IVHD_SYSTEM_MGMT (3<<4) +#define ACPI_IVHD_LINT0_PASS (1<<6) +#define ACPI_IVHD_LINT1_PASS (1<<7) + + +/* Types 0-4: 4-byte device entry */ + +typedef struct acpi_ivrs_device4 +{ + ACPI_IVRS_DE_HEADER Header; + +} ACPI_IVRS_DEVICE4; + +/* Types 66-67: 8-byte device entry */ + +typedef struct acpi_ivrs_device8a +{ + ACPI_IVRS_DE_HEADER Header; + UINT8 Reserved1; + UINT16 UsedId; + UINT8 Reserved2; + +} ACPI_IVRS_DEVICE8A; + +/* Types 70-71: 8-byte device entry */ + +typedef struct acpi_ivrs_device8b +{ + ACPI_IVRS_DE_HEADER Header; + UINT32 ExtendedData; + +} ACPI_IVRS_DEVICE8B; + +/* Values for ExtendedData above */ + +#define ACPI_IVHD_ATS_DISABLED (1<<31) + +/* Type 72: 8-byte device entry */ + +typedef struct acpi_ivrs_device8c +{ + ACPI_IVRS_DE_HEADER Header; + UINT8 Handle; + UINT16 UsedId; + UINT8 Variety; + +} ACPI_IVRS_DEVICE8C; + +/* Values for Variety field above */ + +#define ACPI_IVHD_IOAPIC 1 +#define ACPI_IVHD_HPET 2 + + +/* 0x20, 0x21, 0x22: I/O Virtualization Memory Definition Block (IVMD) */ + +typedef struct acpi_ivrs_memory +{ + ACPI_IVRS_HEADER Header; + UINT16 AuxData; + UINT64 Reserved; + UINT64 StartAddress; + UINT64 MemoryLength; + +} ACPI_IVRS_MEMORY; + + +/******************************************************************************* + * + * LPIT - Low Power Idle Table + * + * Conforms to "ACPI Low Power Idle Table (LPIT)" July 2014. + * + ******************************************************************************/ + +typedef struct acpi_table_lpit +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_LPIT; + + +/* LPIT subtable header */ + +typedef struct acpi_lpit_header +{ + UINT32 Type; /* Subtable type */ + UINT32 Length; /* Subtable length */ + UINT16 UniqueId; + UINT16 Reserved; + UINT32 Flags; + +} ACPI_LPIT_HEADER; + +/* Values for subtable Type above */ + +enum AcpiLpitType +{ + ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00, + ACPI_LPIT_TYPE_RESERVED = 0x01 /* 1 and above are reserved */ +}; + +/* Masks for Flags field above */ + +#define ACPI_LPIT_STATE_DISABLED (1) +#define ACPI_LPIT_NO_COUNTER (1<<1) + +/* + * LPIT subtables, correspond to Type in ACPI_LPIT_HEADER + */ + +/* 0x00: Native C-state instruction based LPI structure */ + +typedef struct acpi_lpit_native +{ + ACPI_LPIT_HEADER Header; + ACPI_GENERIC_ADDRESS EntryTrigger; + UINT32 Residency; + UINT32 Latency; + ACPI_GENERIC_ADDRESS ResidencyCounter; + UINT64 CounterFrequency; + +} ACPI_LPIT_NATIVE; + + +/******************************************************************************* + * + * MCFG - PCI Memory Mapped Configuration table and subtable + * Version 1 + * + * Conforms to "PCI Firmware Specification", Revision 3.0, June 20, 2005 + * + ******************************************************************************/ + +typedef struct acpi_table_mcfg +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Reserved[8]; + +} ACPI_TABLE_MCFG; + + +/* Subtable */ + +typedef struct acpi_mcfg_allocation +{ + UINT64 Address; /* Base address, processor-relative */ + UINT16 PciSegment; /* PCI segment group number */ + UINT8 StartBusNumber; /* Starting PCI Bus number */ + UINT8 EndBusNumber; /* Final PCI Bus number */ + UINT32 Reserved; + +} ACPI_MCFG_ALLOCATION; + + +/******************************************************************************* + * + * MCHI - Management Controller Host Interface Table + * Version 1 + * + * Conforms to "Management Component Transport Protocol (MCTP) Host + * Interface Specification", Revision 1.0.0a, October 13, 2009 + * + ******************************************************************************/ + +typedef struct acpi_table_mchi +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 InterfaceType; + UINT8 Protocol; + UINT64 ProtocolData; + UINT8 InterruptType; + UINT8 Gpe; + UINT8 PciDeviceFlag; + UINT32 GlobalInterrupt; + ACPI_GENERIC_ADDRESS ControlRegister; + UINT8 PciSegment; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + +} ACPI_TABLE_MCHI; + + +/******************************************************************************* + * + * MSDM - Microsoft Data Management table + * + * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)", + * November 29, 2011. Copyright 2011 Microsoft + * + ******************************************************************************/ + +/* Basic MSDM table is only the common ACPI header */ + +typedef struct acpi_table_msdm +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_MSDM; + + +/******************************************************************************* + * + * MTMR - MID Timer Table + * Version 1 + * + * Conforms to "Simple Firmware Interface Specification", + * Draft 0.8.2, Oct 19, 2010 + * NOTE: The ACPI MTMR is equivalent to the SFI MTMR table. + * + ******************************************************************************/ + +typedef struct acpi_table_mtmr +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_MTMR; + +/* MTMR entry */ + +typedef struct acpi_mtmr_entry +{ + ACPI_GENERIC_ADDRESS PhysicalAddress; + UINT32 Frequency; + UINT32 Irq; + +} ACPI_MTMR_ENTRY; + + +/******************************************************************************* + * + * SLIC - Software Licensing Description Table + * + * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)", + * November 29, 2011. Copyright 2011 Microsoft + * + ******************************************************************************/ + +/* Basic SLIC table is only the common ACPI header */ + +typedef struct acpi_table_slic +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_SLIC; + + +/******************************************************************************* + * + * SPCR - Serial Port Console Redirection table + * Version 1 + * + * Conforms to "Serial Port Console Redirection Table", + * Version 1.00, January 11, 2002 + * + ******************************************************************************/ + +typedef struct acpi_table_spcr +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 InterfaceType; /* 0=full 16550, 1=subset of 16550 */ + UINT8 Reserved[3]; + ACPI_GENERIC_ADDRESS SerialPort; + UINT8 InterruptType; + UINT8 PcInterrupt; + UINT32 Interrupt; + UINT8 BaudRate; + UINT8 Parity; + UINT8 StopBits; + UINT8 FlowControl; + UINT8 TerminalType; + UINT8 Reserved1; + UINT16 PciDeviceId; + UINT16 PciVendorId; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + UINT32 PciFlags; + UINT8 PciSegment; + UINT32 Reserved2; + +} ACPI_TABLE_SPCR; + +/* Masks for PciFlags field above */ + +#define ACPI_SPCR_DO_NOT_DISABLE (1) + + +/******************************************************************************* + * + * SPMI - Server Platform Management Interface table + * Version 5 + * + * Conforms to "Intelligent Platform Management Interface Specification + * Second Generation v2.0", Document Revision 1.0, February 12, 2004 with + * June 12, 2009 markup. + * + ******************************************************************************/ + +typedef struct acpi_table_spmi +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 InterfaceType; + UINT8 Reserved; /* Must be 1 */ + UINT16 SpecRevision; /* Version of IPMI */ + UINT8 InterruptType; + UINT8 GpeNumber; /* GPE assigned */ + UINT8 Reserved1; + UINT8 PciDeviceFlag; + UINT32 Interrupt; + ACPI_GENERIC_ADDRESS IpmiRegister; + UINT8 PciSegment; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + UINT8 Reserved2; + +} ACPI_TABLE_SPMI; + +/* Values for InterfaceType above */ + +enum AcpiSpmiInterfaceTypes +{ + ACPI_SPMI_NOT_USED = 0, + ACPI_SPMI_KEYBOARD = 1, + ACPI_SPMI_SMI = 2, + ACPI_SPMI_BLOCK_TRANSFER = 3, + ACPI_SPMI_SMBUS = 4, + ACPI_SPMI_RESERVED = 5 /* 5 and above are reserved */ +}; + + +/******************************************************************************* + * + * TCPA - Trusted Computing Platform Alliance table + * Version 2 + * + * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", + * December 19, 2014 + * + * NOTE: There are two versions of the table with the same signature -- + * the client version and the server version. The common PlatformClass + * field is used to differentiate the two types of tables. + * + ******************************************************************************/ + +typedef struct acpi_table_tcpa_hdr +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 PlatformClass; + +} ACPI_TABLE_TCPA_HDR; + +/* + * Values for PlatformClass above. + * This is how the client and server subtables are differentiated + */ +#define ACPI_TCPA_CLIENT_TABLE 0 +#define ACPI_TCPA_SERVER_TABLE 1 + + +typedef struct acpi_table_tcpa_client +{ + UINT32 MinimumLogLength; /* Minimum length for the event log area */ + UINT64 LogAddress; /* Address of the event log area */ + +} ACPI_TABLE_TCPA_CLIENT; + +typedef struct acpi_table_tcpa_server +{ + UINT16 Reserved; + UINT64 MinimumLogLength; /* Minimum length for the event log area */ + UINT64 LogAddress; /* Address of the event log area */ + UINT16 SpecRevision; + UINT8 DeviceFlags; + UINT8 InterruptFlags; + UINT8 GpeNumber; + UINT8 Reserved2[3]; + UINT32 GlobalInterrupt; + ACPI_GENERIC_ADDRESS Address; + UINT32 Reserved3; + ACPI_GENERIC_ADDRESS ConfigAddress; + UINT8 Group; + UINT8 Bus; /* PCI Bus/Segment/Function numbers */ + UINT8 Device; + UINT8 Function; + +} ACPI_TABLE_TCPA_SERVER; + +/* Values for DeviceFlags above */ + +#define ACPI_TCPA_PCI_DEVICE (1) +#define ACPI_TCPA_BUS_PNP (1<<1) +#define ACPI_TCPA_ADDRESS_VALID (1<<2) + +/* Values for InterruptFlags above */ + +#define ACPI_TCPA_INTERRUPT_MODE (1) +#define ACPI_TCPA_INTERRUPT_POLARITY (1<<1) +#define ACPI_TCPA_SCI_VIA_GPE (1<<2) +#define ACPI_TCPA_GLOBAL_INTERRUPT (1<<3) + + +/******************************************************************************* + * + * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table + * Version 4 + * + * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", + * December 19, 2014 + * + ******************************************************************************/ + +typedef struct acpi_table_tpm2 +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 PlatformClass; + UINT16 Reserved; + UINT64 ControlAddress; + UINT32 StartMethod; + + /* Platform-specific data follows */ + +} ACPI_TABLE_TPM2; + +/* Values for StartMethod above */ + +#define ACPI_TPM2_NOT_ALLOWED 0 +#define ACPI_TPM2_START_METHOD 2 +#define ACPI_TPM2_MEMORY_MAPPED 6 +#define ACPI_TPM2_COMMAND_BUFFER 7 +#define ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD 8 + + +/******************************************************************************* + * + * UEFI - UEFI Boot optimization Table + * Version 1 + * + * Conforms to "Unified Extensible Firmware Interface Specification", + * Version 2.3, May 8, 2009 + * + ******************************************************************************/ + +typedef struct acpi_table_uefi +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 Identifier[16]; /* UUID identifier */ + UINT16 DataOffset; /* Offset of remaining data in table */ + +} ACPI_TABLE_UEFI; + + +/******************************************************************************* + * + * VRTC - Virtual Real Time Clock Table + * Version 1 + * + * Conforms to "Simple Firmware Interface Specification", + * Draft 0.8.2, Oct 19, 2010 + * NOTE: The ACPI VRTC is equivalent to The SFI MRTC table. + * + ******************************************************************************/ + +typedef struct acpi_table_vrtc +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_VRTC; + +/* VRTC entry */ + +typedef struct acpi_vrtc_entry +{ + ACPI_GENERIC_ADDRESS PhysicalAddress; + UINT32 Irq; + +} ACPI_VRTC_ENTRY; + + +/******************************************************************************* + * + * WAET - Windows ACPI Emulated devices Table + * Version 1 + * + * Conforms to "Windows ACPI Emulated Devices Table", version 1.0, April 6, 2009 + * + ******************************************************************************/ + +typedef struct acpi_table_waet +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Flags; + +} ACPI_TABLE_WAET; + +/* Masks for Flags field above */ + +#define ACPI_WAET_RTC_NO_ACK (1) /* RTC requires no int acknowledge */ +#define ACPI_WAET_TIMER_ONE_READ (1<<1) /* PM timer requires only one read */ + + +/******************************************************************************* + * + * WDAT - Watchdog Action Table + * Version 1 + * + * Conforms to "Hardware Watchdog Timers Design Specification", + * Copyright 2006 Microsoft Corporation. + * + ******************************************************************************/ + +typedef struct acpi_table_wdat +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HeaderLength; /* Watchdog Header Length */ + UINT16 PciSegment; /* PCI Segment number */ + UINT8 PciBus; /* PCI Bus number */ + UINT8 PciDevice; /* PCI Device number */ + UINT8 PciFunction; /* PCI Function number */ + UINT8 Reserved[3]; + UINT32 TimerPeriod; /* Period of one timer count (msec) */ + UINT32 MaxCount; /* Maximum counter value supported */ + UINT32 MinCount; /* Minimum counter value */ + UINT8 Flags; + UINT8 Reserved2[3]; + UINT32 Entries; /* Number of watchdog entries that follow */ + +} ACPI_TABLE_WDAT; + +/* Masks for Flags field above */ + +#define ACPI_WDAT_ENABLED (1) +#define ACPI_WDAT_STOPPED 0x80 + + +/* WDAT Instruction Entries (actions) */ + +typedef struct acpi_wdat_entry +{ + UINT8 Action; + UINT8 Instruction; + UINT16 Reserved; + ACPI_GENERIC_ADDRESS RegisterRegion; + UINT32 Value; /* Value used with Read/Write register */ + UINT32 Mask; /* Bitmask required for this register instruction */ + +} ACPI_WDAT_ENTRY; + +/* Values for Action field above */ + +enum AcpiWdatActions +{ + ACPI_WDAT_RESET = 1, + ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4, + ACPI_WDAT_GET_COUNTDOWN = 5, + ACPI_WDAT_SET_COUNTDOWN = 6, + ACPI_WDAT_GET_RUNNING_STATE = 8, + ACPI_WDAT_SET_RUNNING_STATE = 9, + ACPI_WDAT_GET_STOPPED_STATE = 10, + ACPI_WDAT_SET_STOPPED_STATE = 11, + ACPI_WDAT_GET_REBOOT = 16, + ACPI_WDAT_SET_REBOOT = 17, + ACPI_WDAT_GET_SHUTDOWN = 18, + ACPI_WDAT_SET_SHUTDOWN = 19, + ACPI_WDAT_GET_STATUS = 32, + ACPI_WDAT_SET_STATUS = 33, + ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */ +}; + +/* Values for Instruction field above */ + +enum AcpiWdatInstructions +{ + ACPI_WDAT_READ_VALUE = 0, + ACPI_WDAT_READ_COUNTDOWN = 1, + ACPI_WDAT_WRITE_VALUE = 2, + ACPI_WDAT_WRITE_COUNTDOWN = 3, + ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */ + ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */ +}; + + +/******************************************************************************* + * + * WDDT - Watchdog Descriptor Table + * Version 1 + * + * Conforms to "Using the Intel ICH Family Watchdog Timer (WDT)", + * Version 001, September 2002 + * + ******************************************************************************/ + +typedef struct acpi_table_wddt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 SpecVersion; + UINT16 TableVersion; + UINT16 PciVendorId; + ACPI_GENERIC_ADDRESS Address; + UINT16 MaxCount; /* Maximum counter value supported */ + UINT16 MinCount; /* Minimum counter value supported */ + UINT16 Period; + UINT16 Status; + UINT16 Capability; + +} ACPI_TABLE_WDDT; + +/* Flags for Status field above */ + +#define ACPI_WDDT_AVAILABLE (1) +#define ACPI_WDDT_ACTIVE (1<<1) +#define ACPI_WDDT_TCO_OS_OWNED (1<<2) +#define ACPI_WDDT_USER_RESET (1<<11) +#define ACPI_WDDT_WDT_RESET (1<<12) +#define ACPI_WDDT_POWER_FAIL (1<<13) +#define ACPI_WDDT_UNKNOWN_RESET (1<<14) + +/* Flags for Capability field above */ + +#define ACPI_WDDT_AUTO_RESET (1) +#define ACPI_WDDT_ALERT_SUPPORT (1<<1) + + +/******************************************************************************* + * + * WDRT - Watchdog Resource Table + * Version 1 + * + * Conforms to "Watchdog Timer Hardware Requirements for Windows Server 2003", + * Version 1.01, August 28, 2006 + * + ******************************************************************************/ + +typedef struct acpi_table_wdrt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + ACPI_GENERIC_ADDRESS ControlRegister; + ACPI_GENERIC_ADDRESS CountRegister; + UINT16 PciDeviceId; + UINT16 PciVendorId; + UINT8 PciBus; /* PCI Bus number */ + UINT8 PciDevice; /* PCI Device number */ + UINT8 PciFunction; /* PCI Function number */ + UINT8 PciSegment; /* PCI Segment number */ + UINT16 MaxCount; /* Maximum counter value supported */ + UINT8 Units; + +} ACPI_TABLE_WDRT; + + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL2_H__ */ diff --git a/third_party/lib/acpica/source/include/actbl3.h b/third_party/lib/acpica/source/include/actbl3.h new file mode 100644 index 000000000..c27bb9619 --- /dev/null +++ b/third_party/lib/acpica/source/include/actbl3.h @@ -0,0 +1,894 @@ +/****************************************************************************** + * + * Name: actbl3.h - ACPI Table Definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTBL3_H__ +#define __ACTBL3_H__ + + +/******************************************************************************* + * + * Additional ACPI Tables (3) + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + * In general, the tables in this file are fully defined within the ACPI + * specification. + * + ******************************************************************************/ + + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_BGRT "BGRT" /* Boot Graphics Resource Table */ +#define ACPI_SIG_DRTM "DRTM" /* Dynamic Root of Trust for Measurement table */ +#define ACPI_SIG_FPDT "FPDT" /* Firmware Performance Data Table */ +#define ACPI_SIG_GTDT "GTDT" /* Generic Timer Description Table */ +#define ACPI_SIG_MPST "MPST" /* Memory Power State Table */ +#define ACPI_SIG_PCCT "PCCT" /* Platform Communications Channel Table */ +#define ACPI_SIG_PMTT "PMTT" /* Platform Memory Topology Table */ +#define ACPI_SIG_RASF "RASF" /* RAS Feature table */ +#define ACPI_SIG_STAO "STAO" /* Status Override table */ +#define ACPI_SIG_WPBT "WPBT" /* Windows Platform Binary Table */ +#define ACPI_SIG_XENV "XENV" /* Xen Environment table */ + +#define ACPI_SIG_S3PT "S3PT" /* S3 Performance (sub)Table */ +#define ACPI_SIG_PCCS "PCC" /* PCC Shared Memory Region */ + +/* Reserved table signatures */ + +#define ACPI_SIG_MATR "MATR" /* Memory Address Translation Table */ +#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note: C bitfields are not used for this reason: + * + * "Bitfields are great and easy to read, but unfortunately the C language + * does not specify the layout of bitfields in memory, which means they are + * essentially useless for dealing with packed data in on-disk formats or + * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, + * this decision was a design error in C. Ritchie could have picked an order + * and stuck with it." Norman Ramsey. + * See http://stackoverflow.com/a/1053662/41661 + */ + + +/******************************************************************************* + * + * BGRT - Boot Graphics Resource Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_bgrt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT16 Version; + UINT8 Status; + UINT8 ImageType; + UINT64 ImageAddress; + UINT32 ImageOffsetX; + UINT32 ImageOffsetY; + +} ACPI_TABLE_BGRT; + + +/******************************************************************************* + * + * DRTM - Dynamic Root of Trust for Measurement table + * Conforms to "TCG D-RTM Architecture" June 17 2013, Version 1.0.0 + * Table version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_drtm +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 EntryBaseAddress; + UINT64 EntryLength; + UINT32 EntryAddress32; + UINT64 EntryAddress64; + UINT64 ExitAddress; + UINT64 LogAreaAddress; + UINT32 LogAreaLength; + UINT64 ArchDependentAddress; + UINT32 Flags; + +} ACPI_TABLE_DRTM; + +/* Flag Definitions for above */ + +#define ACPI_DRTM_ACCESS_ALLOWED (1) +#define ACPI_DRTM_ENABLE_GAP_CODE (1<<1) +#define ACPI_DRTM_INCOMPLETE_MEASUREMENTS (1<<2) +#define ACPI_DRTM_AUTHORITY_ORDER (1<<3) + + +/* 1) Validated Tables List (64-bit addresses) */ + +typedef struct acpi_drtm_vtable_list +{ + UINT32 ValidatedTableCount; + UINT64 ValidatedTables[1]; + +} ACPI_DRTM_VTABLE_LIST; + +/* 2) Resources List (of Resource Descriptors) */ + +/* Resource Descriptor */ + +typedef struct acpi_drtm_resource +{ + UINT8 Size[7]; + UINT8 Type; + UINT64 Address; + +} ACPI_DRTM_RESOURCE; + +typedef struct acpi_drtm_resource_list +{ + UINT32 ResourceCount; + ACPI_DRTM_RESOURCE Resources[1]; + +} ACPI_DRTM_RESOURCE_LIST; + +/* 3) Platform-specific Identifiers List */ + +typedef struct acpi_drtm_dps_id +{ + UINT32 DpsIdLength; + UINT8 DpsId[16]; + +} ACPI_DRTM_DPS_ID; + + +/******************************************************************************* + * + * FPDT - Firmware Performance Data Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_fpdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + +} ACPI_TABLE_FPDT; + + +/* FPDT subtable header */ + +typedef struct acpi_fpdt_header +{ + UINT16 Type; + UINT8 Length; + UINT8 Revision; + +} ACPI_FPDT_HEADER; + +/* Values for Type field above */ + +enum AcpiFpdtType +{ + ACPI_FPDT_TYPE_BOOT = 0, + ACPI_FPDT_TYPE_S3PERF = 1 +}; + + +/* + * FPDT subtables + */ + +/* 0: Firmware Basic Boot Performance Record */ + +typedef struct acpi_fpdt_boot +{ + ACPI_FPDT_HEADER Header; + UINT8 Reserved[4]; + UINT64 ResetEnd; + UINT64 LoadStart; + UINT64 StartupStart; + UINT64 ExitServicesEntry; + UINT64 ExitServicesExit; + +} ACPI_FPDT_BOOT; + + +/* 1: S3 Performance Table Pointer Record */ + +typedef struct acpi_fpdt_s3pt_ptr +{ + ACPI_FPDT_HEADER Header; + UINT8 Reserved[4]; + UINT64 Address; + +} ACPI_FPDT_S3PT_PTR; + + +/* + * S3PT - S3 Performance Table. This table is pointed to by the + * FPDT S3 Pointer Record above. + */ +typedef struct acpi_table_s3pt +{ + UINT8 Signature[4]; /* "S3PT" */ + UINT32 Length; + +} ACPI_TABLE_S3PT; + + +/* + * S3PT Subtables + */ +typedef struct acpi_s3pt_header +{ + UINT16 Type; + UINT8 Length; + UINT8 Revision; + +} ACPI_S3PT_HEADER; + +/* Values for Type field above */ + +enum AcpiS3ptType +{ + ACPI_S3PT_TYPE_RESUME = 0, + ACPI_S3PT_TYPE_SUSPEND = 1 +}; + +typedef struct acpi_s3pt_resume +{ + ACPI_S3PT_HEADER Header; + UINT32 ResumeCount; + UINT64 FullResume; + UINT64 AverageResume; + +} ACPI_S3PT_RESUME; + +typedef struct acpi_s3pt_suspend +{ + ACPI_S3PT_HEADER Header; + UINT64 SuspendStart; + UINT64 SuspendEnd; + +} ACPI_S3PT_SUSPEND; + + +/******************************************************************************* + * + * GTDT - Generic Timer Description Table (ACPI 5.1) + * Version 2 + * + ******************************************************************************/ + +typedef struct acpi_table_gtdt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 CounterBlockAddresss; + UINT32 Reserved; + UINT32 SecureEl1Interrupt; + UINT32 SecureEl1Flags; + UINT32 NonSecureEl1Interrupt; + UINT32 NonSecureEl1Flags; + UINT32 VirtualTimerInterrupt; + UINT32 VirtualTimerFlags; + UINT32 NonSecureEl2Interrupt; + UINT32 NonSecureEl2Flags; + UINT64 CounterReadBlockAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; + +} ACPI_TABLE_GTDT; + +/* Flag Definitions: Timer Block Physical Timers and Virtual timers */ + +#define ACPI_GTDT_INTERRUPT_MODE (1) +#define ACPI_GTDT_INTERRUPT_POLARITY (1<<1) +#define ACPI_GTDT_ALWAYS_ON (1<<2) + + +/* Common GTDT subtable header */ + +typedef struct acpi_gtdt_header +{ + UINT8 Type; + UINT16 Length; + +} ACPI_GTDT_HEADER; + +/* Values for GTDT subtable type above */ + +enum AcpiGtdtType +{ + ACPI_GTDT_TYPE_TIMER_BLOCK = 0, + ACPI_GTDT_TYPE_WATCHDOG = 1, + ACPI_GTDT_TYPE_RESERVED = 2 /* 2 and greater are reserved */ +}; + + +/* GTDT Subtables, correspond to Type in acpi_gtdt_header */ + +/* 0: Generic Timer Block */ + +typedef struct acpi_gtdt_timer_block +{ + ACPI_GTDT_HEADER Header; + UINT8 Reserved; + UINT64 BlockAddress; + UINT32 TimerCount; + UINT32 TimerOffset; + +} ACPI_GTDT_TIMER_BLOCK; + +/* Timer Sub-Structure, one per timer */ + +typedef struct acpi_gtdt_timer_entry +{ + UINT8 FrameNumber; + UINT8 Reserved[3]; + UINT64 BaseAddress; + UINT64 El0BaseAddress; + UINT32 TimerInterrupt; + UINT32 TimerFlags; + UINT32 VirtualTimerInterrupt; + UINT32 VirtualTimerFlags; + UINT32 CommonFlags; + +} ACPI_GTDT_TIMER_ENTRY; + +/* Flag Definitions: TimerFlags and VirtualTimerFlags above */ + +#define ACPI_GTDT_GT_IRQ_MODE (1) +#define ACPI_GTDT_GT_IRQ_POLARITY (1<<1) + +/* Flag Definitions: CommonFlags above */ + +#define ACPI_GTDT_GT_IS_SECURE_TIMER (1) +#define ACPI_GTDT_GT_ALWAYS_ON (1<<1) + + +/* 1: SBSA Generic Watchdog Structure */ + +typedef struct acpi_gtdt_watchdog +{ + ACPI_GTDT_HEADER Header; + UINT8 Reserved; + UINT64 RefreshFrameAddress; + UINT64 ControlFrameAddress; + UINT32 TimerInterrupt; + UINT32 TimerFlags; + +} ACPI_GTDT_WATCHDOG; + +/* Flag Definitions: TimerFlags above */ + +#define ACPI_GTDT_WATCHDOG_IRQ_MODE (1) +#define ACPI_GTDT_WATCHDOG_IRQ_POLARITY (1<<1) +#define ACPI_GTDT_WATCHDOG_SECURE (1<<2) + + +/******************************************************************************* + * + * MPST - Memory Power State Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +#define ACPI_MPST_CHANNEL_INFO \ + UINT8 ChannelId; \ + UINT8 Reserved1[3]; \ + UINT16 PowerNodeCount; \ + UINT16 Reserved2; + +/* Main table */ + +typedef struct acpi_table_mpst +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ + +} ACPI_TABLE_MPST; + + +/* Memory Platform Communication Channel Info */ + +typedef struct acpi_mpst_channel +{ + ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ + +} ACPI_MPST_CHANNEL; + + +/* Memory Power Node Structure */ + +typedef struct acpi_mpst_power_node +{ + UINT8 Flags; + UINT8 Reserved1; + UINT16 NodeId; + UINT32 Length; + UINT64 RangeAddress; + UINT64 RangeLength; + UINT32 NumPowerStates; + UINT32 NumPhysicalComponents; + +} ACPI_MPST_POWER_NODE; + +/* Values for Flags field above */ + +#define ACPI_MPST_ENABLED 1 +#define ACPI_MPST_POWER_MANAGED 2 +#define ACPI_MPST_HOT_PLUG_CAPABLE 4 + + +/* Memory Power State Structure (follows POWER_NODE above) */ + +typedef struct acpi_mpst_power_state +{ + UINT8 PowerState; + UINT8 InfoIndex; + +} ACPI_MPST_POWER_STATE; + + +/* Physical Component ID Structure (follows POWER_STATE above) */ + +typedef struct acpi_mpst_component +{ + UINT16 ComponentId; + +} ACPI_MPST_COMPONENT; + + +/* Memory Power State Characteristics Structure (follows all POWER_NODEs) */ + +typedef struct acpi_mpst_data_hdr +{ + UINT16 CharacteristicsCount; + UINT16 Reserved; + +} ACPI_MPST_DATA_HDR; + +typedef struct acpi_mpst_power_data +{ + UINT8 StructureId; + UINT8 Flags; + UINT16 Reserved1; + UINT32 AveragePower; + UINT32 PowerSaving; + UINT64 ExitLatency; + UINT64 Reserved2; + +} ACPI_MPST_POWER_DATA; + +/* Values for Flags field above */ + +#define ACPI_MPST_PRESERVE 1 +#define ACPI_MPST_AUTOENTRY 2 +#define ACPI_MPST_AUTOEXIT 4 + + +/* Shared Memory Region (not part of an ACPI table) */ + +typedef struct acpi_mpst_shared +{ + UINT32 Signature; + UINT16 PccCommand; + UINT16 PccStatus; + UINT32 CommandRegister; + UINT32 StatusRegister; + UINT32 PowerStateId; + UINT32 PowerNodeId; + UINT64 EnergyConsumed; + UINT64 AveragePower; + +} ACPI_MPST_SHARED; + + +/******************************************************************************* + * + * PCCT - Platform Communications Channel Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_pcct +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Flags; + UINT64 Reserved; + +} ACPI_TABLE_PCCT; + +/* Values for Flags field above */ + +#define ACPI_PCCT_DOORBELL 1 + +/* Values for subtable type in ACPI_SUBTABLE_HEADER */ + +enum AcpiPcctType +{ + ACPI_PCCT_TYPE_GENERIC_SUBSPACE = 0, + ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE = 1, + ACPI_PCCT_TYPE_RESERVED = 2 /* 2 and greater are reserved */ +}; + +/* + * PCCT Subtables, correspond to Type in ACPI_SUBTABLE_HEADER + */ + +/* 0: Generic Communications Subspace */ + +typedef struct acpi_pcct_subspace +{ + ACPI_SUBTABLE_HEADER Header; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT16 MinTurnaroundTime; + +} ACPI_PCCT_SUBSPACE; + + +/* 1: HW-reduced Communications Subspace (ACPI 5.1) */ + +typedef struct acpi_pcct_hw_reduced +{ + ACPI_SUBTABLE_HEADER Header; + UINT32 DoorbellInterrupt; + UINT8 Flags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 Length; + ACPI_GENERIC_ADDRESS DoorbellRegister; + UINT64 PreserveMask; + UINT64 WriteMask; + UINT32 Latency; + UINT32 MaxAccessRate; + UINT16 MinTurnaroundTime; + +} ACPI_PCCT_HW_REDUCED; + +/* Values for doorbell flags above */ + +#define ACPI_PCCT_INTERRUPT_POLARITY (1) +#define ACPI_PCCT_INTERRUPT_MODE (1<<1) + + +/* + * PCC memory structures (not part of the ACPI table) + */ + +/* Shared Memory Region */ + +typedef struct acpi_pcct_shared_memory +{ + UINT32 Signature; + UINT16 Command; + UINT16 Status; + +} ACPI_PCCT_SHARED_MEMORY; + + +/******************************************************************************* + * + * PMTT - Platform Memory Topology Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_pmtt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 Reserved; + +} ACPI_TABLE_PMTT; + + +/* Common header for PMTT subtables that follow main table */ + +typedef struct acpi_pmtt_header +{ + UINT8 Type; + UINT8 Reserved1; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved2; + +} ACPI_PMTT_HEADER; + +/* Values for Type field above */ + +#define ACPI_PMTT_TYPE_SOCKET 0 +#define ACPI_PMTT_TYPE_CONTROLLER 1 +#define ACPI_PMTT_TYPE_DIMM 2 +#define ACPI_PMTT_TYPE_RESERVED 3 /* 0x03-0xFF are reserved */ + +/* Values for Flags field above */ + +#define ACPI_PMTT_TOP_LEVEL 0x0001 +#define ACPI_PMTT_PHYSICAL 0x0002 +#define ACPI_PMTT_MEMORY_TYPE 0x000C + + +/* + * PMTT subtables, correspond to Type in acpi_pmtt_header + */ + + +/* 0: Socket Structure */ + +typedef struct acpi_pmtt_socket +{ + ACPI_PMTT_HEADER Header; + UINT16 SocketId; + UINT16 Reserved; + +} ACPI_PMTT_SOCKET; + + +/* 1: Memory Controller subtable */ + +typedef struct acpi_pmtt_controller +{ + ACPI_PMTT_HEADER Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 AccessWidth; + UINT16 Alignment; + UINT16 Reserved; + UINT16 DomainCount; + +} ACPI_PMTT_CONTROLLER; + +/* 1a: Proximity Domain substructure */ + +typedef struct acpi_pmtt_domain +{ + UINT32 ProximityDomain; + +} ACPI_PMTT_DOMAIN; + + +/* 2: Physical Component Identifier (DIMM) */ + +typedef struct acpi_pmtt_physical_component +{ + ACPI_PMTT_HEADER Header; + UINT16 ComponentId; + UINT16 Reserved; + UINT32 MemorySize; + UINT32 BiosHandle; + +} ACPI_PMTT_PHYSICAL_COMPONENT; + + +/******************************************************************************* + * + * RASF - RAS Feature Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +typedef struct acpi_table_rasf +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 ChannelId[12]; + +} ACPI_TABLE_RASF; + +/* RASF Platform Communication Channel Shared Memory Region */ + +typedef struct acpi_rasf_shared_memory +{ + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 Capabilities[16]; + UINT8 SetCapabilities[16]; + UINT16 NumParameterBlocks; + UINT32 SetCapabilitiesStatus; + +} ACPI_RASF_SHARED_MEMORY; + +/* RASF Parameter Block Structure Header */ + +typedef struct acpi_rasf_parameter_block +{ + UINT16 Type; + UINT16 Version; + UINT16 Length; + +} ACPI_RASF_PARAMETER_BLOCK; + +/* RASF Parameter Block Structure for PATROL_SCRUB */ + +typedef struct acpi_rasf_patrol_scrub_parameter +{ + ACPI_RASF_PARAMETER_BLOCK Header; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; + +} ACPI_RASF_PATROL_SCRUB_PARAMETER; + +/* Masks for Flags and Speed fields above */ + +#define ACPI_RASF_SCRUBBER_RUNNING 1 +#define ACPI_RASF_SPEED (7<<1) +#define ACPI_RASF_SPEED_SLOW (0<<1) +#define ACPI_RASF_SPEED_MEDIUM (4<<1) +#define ACPI_RASF_SPEED_FAST (7<<1) + +/* Channel Commands */ + +enum AcpiRasfCommands +{ + ACPI_RASF_EXECUTE_RASF_COMMAND = 1 +}; + +/* Platform RAS Capabilities */ + +enum AcpiRasfCapabiliities +{ + ACPI_HW_PATROL_SCRUB_SUPPORTED = 0, + ACPI_SW_PATROL_SCRUB_EXPOSED = 1 +}; + +/* Patrol Scrub Commands */ + +enum AcpiRasfPatrolScrubCommands +{ + ACPI_RASF_GET_PATROL_PARAMETERS = 1, + ACPI_RASF_START_PATROL_SCRUBBER = 2, + ACPI_RASF_STOP_PATROL_SCRUBBER = 3 +}; + +/* Channel Command flags */ + +#define ACPI_RASF_GENERATE_SCI (1<<15) + +/* Status values */ + +enum AcpiRasfStatus +{ + ACPI_RASF_SUCCESS = 0, + ACPI_RASF_NOT_VALID = 1, + ACPI_RASF_NOT_SUPPORTED = 2, + ACPI_RASF_BUSY = 3, + ACPI_RASF_FAILED = 4, + ACPI_RASF_ABORTED = 5, + ACPI_RASF_INVALID_DATA = 6 +}; + +/* Status flags */ + +#define ACPI_RASF_COMMAND_COMPLETE (1) +#define ACPI_RASF_SCI_DOORBELL (1<<1) +#define ACPI_RASF_ERROR (1<<2) +#define ACPI_RASF_STATUS (0x1F<<3) + + +/******************************************************************************* + * + * STAO - Status Override Table (_STA override) - ACPI 6.0 + * Version 1 + * + * Conforms to "ACPI Specification for Status Override Table" + * 6 January 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_stao +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT8 IgnoreUart; + +} ACPI_TABLE_STAO; + + +/******************************************************************************* + * + * WPBT - Windows Platform Environment Table (ACPI 6.0) + * Version 1 + * + * Conforms to "Windows Platform Binary Table (WPBT)" 29 November 2011 + * + ******************************************************************************/ + +typedef struct acpi_table_wpbt +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT32 HandoffSize; + UINT64 HandoffAddress; + UINT8 Layout; + UINT8 Type; + UINT16 ArgumentsLength; + +} ACPI_TABLE_WPBT; + + +/******************************************************************************* + * + * XENV - Xen Environment Table (ACPI 6.0) + * Version 1 + * + * Conforms to "ACPI Specification for Xen Environment Table" 4 January 2015 + * + ******************************************************************************/ + +typedef struct acpi_table_xenv +{ + ACPI_TABLE_HEADER Header; /* Common ACPI table header */ + UINT64 GrantTableAddress; + UINT64 GrantTableSize; + UINT32 EventInterrupt; + UINT8 EventFlags; + +} ACPI_TABLE_XENV; + + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL3_H__ */ diff --git a/third_party/lib/acpica/source/include/actypes.h b/third_party/lib/acpica/source/include/actypes.h new file mode 100644 index 000000000..e43424a37 --- /dev/null +++ b/third_party/lib/acpica/source/include/actypes.h @@ -0,0 +1,1404 @@ +/****************************************************************************** + * + * Name: actypes.h - Common data types for the entire ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTYPES_H__ +#define __ACTYPES_H__ + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +/* + * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header + * and must be either 32 or 64. 16-bit ACPICA is no longer supported, as of + * 12/2006. + */ +#ifndef ACPI_MACHINE_WIDTH +#error ACPI_MACHINE_WIDTH not defined +#endif + +/* + * Data type ranges + * Note: These macros are designed to be compiler independent as well as + * working around problems that some 32-bit compilers have with 64-bit + * constants. + */ +#define ACPI_UINT8_MAX (UINT8) (~((UINT8) 0)) /* 0xFF */ +#define ACPI_UINT16_MAX (UINT16)(~((UINT16) 0)) /* 0xFFFF */ +#define ACPI_UINT32_MAX (UINT32)(~((UINT32) 0)) /* 0xFFFFFFFF */ +#define ACPI_UINT64_MAX (UINT64)(~((UINT64) 0)) /* 0xFFFFFFFFFFFFFFFF */ +#define ACPI_ASCII_MAX 0x7F + + +/* + * Architecture-specific ACPICA Subsystem Data Types + * + * The goal of these types is to provide source code portability across + * 16-bit, 32-bit, and 64-bit targets. + * + * 1) The following types are of fixed size for all targets (16/32/64): + * + * BOOLEAN Logical boolean + * + * UINT8 8-bit (1 byte) unsigned value + * UINT16 16-bit (2 byte) unsigned value + * UINT32 32-bit (4 byte) unsigned value + * UINT64 64-bit (8 byte) unsigned value + * + * INT16 16-bit (2 byte) signed value + * INT32 32-bit (4 byte) signed value + * INT64 64-bit (8 byte) signed value + * + * COMPILER_DEPENDENT_UINT64/INT64 - These types are defined in the + * compiler-dependent header(s) and were introduced because there is no common + * 64-bit integer type across the various compilation models, as shown in + * the table below. + * + * Datatype LP64 ILP64 LLP64 ILP32 LP32 16bit + * char 8 8 8 8 8 8 + * short 16 16 16 16 16 16 + * _int32 32 + * int 32 64 32 32 16 16 + * long 64 64 32 32 32 32 + * long long 64 64 + * pointer 64 64 64 32 32 32 + * + * Note: ILP64 and LP32 are currently not supported. + * + * + * 2) These types represent the native word size of the target mode of the + * processor, and may be 16-bit, 32-bit, or 64-bit as required. They are + * usually used for memory allocation, efficient loop counters, and array + * indexes. The types are similar to the size_t type in the C library and are + * required because there is no C type that consistently represents the native + * data width. ACPI_SIZE is needed because there is no guarantee that a + * kernel-level C library is present. + * + * ACPI_SIZE 16/32/64-bit unsigned value + * ACPI_NATIVE_INT 16/32/64-bit signed value + */ + +/******************************************************************************* + * + * Common types for all compilers, all targets + * + ******************************************************************************/ + +#ifndef ACPI_USE_SYSTEM_INTTYPES + +typedef unsigned char BOOLEAN; +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef short INT16; +typedef COMPILER_DEPENDENT_UINT64 UINT64; +typedef COMPILER_DEPENDENT_INT64 INT64; + +#endif /* ACPI_USE_SYSTEM_INTTYPES */ + +/* + * Value returned by AcpiOsGetThreadId. There is no standard "thread_id" + * across operating systems or even the various UNIX systems. Since ACPICA + * only needs the thread ID as a unique thread identifier, we use a UINT64 + * as the only common data type - it will accommodate any type of pointer or + * any type of integer. It is up to the host-dependent OSL to cast the + * native thread ID type to a UINT64 (in AcpiOsGetThreadId). + */ +#define ACPI_THREAD_ID UINT64 + + +/******************************************************************************* + * + * Types specific to 64-bit targets + * + ******************************************************************************/ + +#if ACPI_MACHINE_WIDTH == 64 + +#ifndef ACPI_USE_SYSTEM_INTTYPES + +typedef unsigned int UINT32; +typedef int INT32; + +#endif /* ACPI_USE_SYSTEM_INTTYPES */ + + +typedef INT64 ACPI_NATIVE_INT; +typedef UINT64 ACPI_SIZE; +typedef UINT64 ACPI_IO_ADDRESS; +typedef UINT64 ACPI_PHYSICAL_ADDRESS; + +#define ACPI_MAX_PTR ACPI_UINT64_MAX +#define ACPI_SIZE_MAX ACPI_UINT64_MAX +#define ACPI_USE_NATIVE_DIVIDE /* Has native 64-bit integer support */ + +/* + * In the case of the Itanium Processor Family (IPF), the hardware does not + * support misaligned memory transfers. Set the MISALIGNMENT_NOT_SUPPORTED flag + * to indicate that special precautions must be taken to avoid alignment faults. + * (IA64 or ia64 is currently used by existing compilers to indicate IPF.) + * + * Note: EM64T and other X86-64 processors support misaligned transfers, + * so there is no need to define this flag. + */ +#if defined (__IA64__) || defined (__ia64__) +#define ACPI_MISALIGNMENT_NOT_SUPPORTED +#endif + + +/******************************************************************************* + * + * Types specific to 32-bit targets + * + ******************************************************************************/ + +#elif ACPI_MACHINE_WIDTH == 32 + +#ifndef ACPI_USE_SYSTEM_INTTYPES + +typedef unsigned int UINT32; +typedef int INT32; + +#endif /* ACPI_USE_SYSTEM_INTTYPES */ + + +typedef INT32 ACPI_NATIVE_INT; +typedef UINT32 ACPI_SIZE; + +#ifdef ACPI_32BIT_PHYSICAL_ADDRESS + +/* + * OSPMs can define this to shrink the size of the structures for 32-bit + * none PAE environment. ASL compiler may always define this to generate + * 32-bit OSPM compliant tables. + */ +typedef UINT32 ACPI_IO_ADDRESS; +typedef UINT32 ACPI_PHYSICAL_ADDRESS; + +#else /* ACPI_32BIT_PHYSICAL_ADDRESS */ + +/* + * It is reported that, after some calculations, the physical addresses can + * wrap over the 32-bit boundary on 32-bit PAE environment. + * https://bugzilla.kernel.org/show_bug.cgi?id=87971 + */ +typedef UINT64 ACPI_IO_ADDRESS; +typedef UINT64 ACPI_PHYSICAL_ADDRESS; + +#endif /* ACPI_32BIT_PHYSICAL_ADDRESS */ + +#define ACPI_MAX_PTR ACPI_UINT32_MAX +#define ACPI_SIZE_MAX ACPI_UINT32_MAX + +#else + +/* ACPI_MACHINE_WIDTH must be either 64 or 32 */ + +#error unknown ACPI_MACHINE_WIDTH +#endif + + +/******************************************************************************* + * + * OS-dependent types + * + * If the defaults below are not appropriate for the host system, they can + * be defined in the OS-specific header, and this will take precedence. + * + ******************************************************************************/ + +/* Flags for AcpiOsAcquireLock/AcpiOsReleaseLock */ + +#ifndef ACPI_CPU_FLAGS +#define ACPI_CPU_FLAGS ACPI_SIZE +#endif + +/* Object returned from AcpiOsCreateCache */ + +#ifndef ACPI_CACHE_T +#ifdef ACPI_USE_LOCAL_CACHE +#define ACPI_CACHE_T ACPI_MEMORY_LIST +#else +#define ACPI_CACHE_T void * +#endif +#endif + +/* + * Synchronization objects - Mutexes, Semaphores, and SpinLocks + */ +#if (ACPI_MUTEX_TYPE == ACPI_BINARY_SEMAPHORE) +/* + * These macros are used if the host OS does not support a mutex object. + * Map the OSL Mutex interfaces to binary semaphores. + */ +#define ACPI_MUTEX ACPI_SEMAPHORE +#define AcpiOsCreateMutex(OutHandle) AcpiOsCreateSemaphore (1, 1, OutHandle) +#define AcpiOsDeleteMutex(Handle) (void) AcpiOsDeleteSemaphore (Handle) +#define AcpiOsAcquireMutex(Handle,Time) AcpiOsWaitSemaphore (Handle, 1, Time) +#define AcpiOsReleaseMutex(Handle) (void) AcpiOsSignalSemaphore (Handle, 1) +#endif + +/* Configurable types for synchronization objects */ + +#ifndef ACPI_SPINLOCK +#define ACPI_SPINLOCK void * +#endif + +#ifndef ACPI_SEMAPHORE +#define ACPI_SEMAPHORE void * +#endif + +#ifndef ACPI_MUTEX +#define ACPI_MUTEX void * +#endif + + +/******************************************************************************* + * + * Compiler-dependent types + * + * If the defaults below are not appropriate for the host compiler, they can + * be defined in the compiler-specific header, and this will take precedence. + * + ******************************************************************************/ + +/* Use C99 uintptr_t for pointer casting if available, "void *" otherwise */ + +#ifndef ACPI_UINTPTR_T +#define ACPI_UINTPTR_T void * +#endif + +/* + * ACPI_PRINTF_LIKE is used to tag functions as "printf-like" because + * some compilers can catch printf format string problems + */ +#ifndef ACPI_PRINTF_LIKE +#define ACPI_PRINTF_LIKE(c) +#endif + +/* + * Some compilers complain about unused variables. Sometimes we don't want to + * use all the variables (for example, _AcpiModuleName). This allows us + * to tell the compiler in a per-variable manner that a variable + * is unused + */ +#ifndef ACPI_UNUSED_VAR +#define ACPI_UNUSED_VAR +#endif + +/* + * All ACPICA external functions that are available to the rest of the kernel + * are tagged with thes macros which can be defined as appropriate for the host. + * + * Notes: + * ACPI_EXPORT_SYMBOL_INIT is used for initialization and termination + * interfaces that may need special processing. + * ACPI_EXPORT_SYMBOL is used for all other public external functions. + */ +#ifndef ACPI_EXPORT_SYMBOL_INIT +#define ACPI_EXPORT_SYMBOL_INIT(Symbol) +#endif + +#ifndef ACPI_EXPORT_SYMBOL +#define ACPI_EXPORT_SYMBOL(Symbol) +#endif + +/* + * Compiler/Clibrary-dependent debug initialization. Used for ACPICA + * utilities only. + */ +#ifndef ACPI_DEBUG_INITIALIZE +#define ACPI_DEBUG_INITIALIZE() +#endif + + +/******************************************************************************* + * + * Configuration + * + ******************************************************************************/ + +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE(a) NULL +#define ACPI_ALLOCATE_ZEROED(a) NULL +#define ACPI_FREE(a) +#define ACPI_MEM_TRACKING(a) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +/* + * Memory allocation tracking (used by AcpiExec to detect memory leaks) + */ +#define ACPI_MEM_PARAMETERS _COMPONENT, _AcpiModuleName, __LINE__ +#define ACPI_ALLOCATE(a) AcpiUtAllocateAndTrack ((ACPI_SIZE) (a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) AcpiUtAllocateZeroedAndTrack ((ACPI_SIZE) (a), ACPI_MEM_PARAMETERS) +#define ACPI_FREE(a) AcpiUtFreeAndTrack (a, ACPI_MEM_PARAMETERS) +#define ACPI_MEM_TRACKING(a) a + +#else +/* + * Normal memory allocation directly via the OS services layer + */ +#define ACPI_ALLOCATE(a) AcpiOsAllocate ((ACPI_SIZE) (a)) +#define ACPI_ALLOCATE_ZEROED(a) AcpiOsAllocateZeroed ((ACPI_SIZE) (a)) +#define ACPI_FREE(a) AcpiOsFree (a) +#define ACPI_MEM_TRACKING(a) + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + + +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification changes) + * + *****************************************************************************/ + +/* Number of distinct FADT-based GPE register blocks (GPE0 and GPE1) */ + +#define ACPI_MAX_GPE_BLOCKS 2 + +/* Default ACPI register widths */ + +#define ACPI_GPE_REGISTER_WIDTH 8 +#define ACPI_PM1_REGISTER_WIDTH 16 +#define ACPI_PM2_REGISTER_WIDTH 8 +#define ACPI_PM_TIMER_WIDTH 32 +#define ACPI_RESET_REGISTER_WIDTH 8 + +/* Names within the namespace are 4 bytes long */ + +#define ACPI_NAME_SIZE 4 +#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ +#define ACPI_PATH_SEPARATOR '.' + +/* Sizes for ACPI table headers */ + +#define ACPI_OEM_ID_SIZE 6 +#define ACPI_OEM_TABLE_ID_SIZE 8 + +/* ACPI/PNP hardware IDs */ + +#define PCI_ROOT_HID_STRING "PNP0A03" +#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" + +/* PM Timer ticks per second (HZ) */ + +#define ACPI_PM_TIMER_FREQUENCY 3579545 + + +/******************************************************************************* + * + * Independent types + * + ******************************************************************************/ + +/* Logical defines and NULL */ + +#ifdef FALSE +#undef FALSE +#endif +#define FALSE (1 == 0) + +#ifdef TRUE +#undef TRUE +#endif +#define TRUE (1 == 1) + +#ifndef NULL +#define NULL (void *) 0 +#endif + + +/* + * Miscellaneous types + */ +typedef UINT32 ACPI_STATUS; /* All ACPI Exceptions */ +typedef UINT32 ACPI_NAME; /* 4-byte ACPI name */ +typedef char * ACPI_STRING; /* Null terminated ASCII string */ +typedef void * ACPI_HANDLE; /* Actually a ptr to a NS Node */ + + +/* Time constants for timer calculations */ + +#define ACPI_MSEC_PER_SEC 1000L + +#define ACPI_USEC_PER_MSEC 1000L +#define ACPI_USEC_PER_SEC 1000000L + +#define ACPI_100NSEC_PER_USEC 10L +#define ACPI_100NSEC_PER_MSEC 10000L +#define ACPI_100NSEC_PER_SEC 10000000L + +#define ACPI_NSEC_PER_USEC 1000L +#define ACPI_NSEC_PER_MSEC 1000000L +#define ACPI_NSEC_PER_SEC 1000000000L + + +/* Owner IDs are used to track namespace nodes for selective deletion */ + +typedef UINT8 ACPI_OWNER_ID; +#define ACPI_OWNER_ID_MAX 0xFF + + +#define ACPI_INTEGER_BIT_SIZE 64 +#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ +#define ACPI_MAX64_DECIMAL_DIGITS 20 +#define ACPI_MAX32_DECIMAL_DIGITS 10 +#define ACPI_MAX16_DECIMAL_DIGITS 5 +#define ACPI_MAX8_DECIMAL_DIGITS 3 + +/* + * Constants with special meanings + */ +#define ACPI_ROOT_OBJECT ACPI_ADD_PTR (ACPI_HANDLE, NULL, ACPI_MAX_PTR) +#define ACPI_WAIT_FOREVER 0xFFFF /* UINT16, as per ACPI spec */ +#define ACPI_DO_NOT_WAIT 0 + +/* + * Obsolete: Acpi integer width. In ACPI version 1 (1996), integers are 32 bits. + * In ACPI version 2 (2000) and later, integers are 64 bits. Note that this + * pertains to the ACPI integer type only, not to other integers used in the + * implementation of the ACPICA subsystem. + * + * 01/2010: This type is obsolete and has been removed from the entire ACPICA + * code base. It remains here for compatibility with device drivers that use + * the type. However, it will be removed in the future. + */ +typedef UINT64 ACPI_INTEGER; +#define ACPI_INTEGER_MAX ACPI_UINT64_MAX + + +/******************************************************************************* + * + * Commonly used macros + * + ******************************************************************************/ + +/* Data manipulation */ + +#define ACPI_LOBYTE(Integer) ((UINT8) (UINT16)(Integer)) +#define ACPI_HIBYTE(Integer) ((UINT8) (((UINT16)(Integer)) >> 8)) +#define ACPI_LOWORD(Integer) ((UINT16) (UINT32)(Integer)) +#define ACPI_HIWORD(Integer) ((UINT16)(((UINT32)(Integer)) >> 16)) +#define ACPI_LODWORD(Integer64) ((UINT32) (UINT64)(Integer64)) +#define ACPI_HIDWORD(Integer64) ((UINT32)(((UINT64)(Integer64)) >> 32)) + +#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) +#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) +#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) +#define ACPI_MAX(a,b) (((a)>(b))?(a):(b)) + +/* Size calculation */ + +#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) + +/* Pointer manipulation */ + +#define ACPI_CAST_PTR(t, p) ((t *) (ACPI_UINTPTR_T) (p)) +#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **) (ACPI_UINTPTR_T) (p)) +#define ACPI_ADD_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (UINT8, (a)) + (ACPI_SIZE)(b))) +#define ACPI_SUB_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (UINT8, (a)) - (ACPI_SIZE)(b))) +#define ACPI_PTR_DIFF(a, b) (ACPI_SIZE) (ACPI_CAST_PTR (UINT8, (a)) - ACPI_CAST_PTR (UINT8, (b))) + +/* Pointer/Integer type conversions */ + +#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void, (void *) NULL,(ACPI_SIZE) i) +#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p, (void *) NULL) +#define ACPI_OFFSET(d, f) ACPI_PTR_DIFF (&(((d *) 0)->f), (void *) NULL) +#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) +#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) + +/* Optimizations for 4-character (32-bit) ACPI_NAME manipulation */ + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (UINT32, (a)) == *ACPI_CAST_PTR (UINT32, (b))) +#define ACPI_MOVE_NAME(dest,src) (*ACPI_CAST_PTR (UINT32, (dest)) = *ACPI_CAST_PTR (UINT32, (src))) +#else +#define ACPI_COMPARE_NAME(a,b) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) +#define ACPI_MOVE_NAME(dest,src) (strncpy (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) +#endif + +/* Support for the special RSDP signature (8 characters) */ + +#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) +#define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) + + +/******************************************************************************* + * + * Miscellaneous constants + * + ******************************************************************************/ + +/* + * Initialization sequence + */ +#define ACPI_FULL_INITIALIZATION 0x00 +#define ACPI_NO_ADDRESS_SPACE_INIT 0x01 +#define ACPI_NO_HARDWARE_INIT 0x02 +#define ACPI_NO_EVENT_INIT 0x04 +#define ACPI_NO_HANDLER_INIT 0x08 +#define ACPI_NO_ACPI_ENABLE 0x10 +#define ACPI_NO_DEVICE_INIT 0x20 +#define ACPI_NO_OBJECT_INIT 0x40 +#define ACPI_NO_FACS_INIT 0x80 + +/* + * Initialization state + */ +#define ACPI_SUBSYSTEM_INITIALIZE 0x01 +#define ACPI_INITIALIZED_OK 0x02 + +/* + * Power state values + */ +#define ACPI_STATE_UNKNOWN (UINT8) 0xFF + +#define ACPI_STATE_S0 (UINT8) 0 +#define ACPI_STATE_S1 (UINT8) 1 +#define ACPI_STATE_S2 (UINT8) 2 +#define ACPI_STATE_S3 (UINT8) 3 +#define ACPI_STATE_S4 (UINT8) 4 +#define ACPI_STATE_S5 (UINT8) 5 +#define ACPI_S_STATES_MAX ACPI_STATE_S5 +#define ACPI_S_STATE_COUNT 6 + +#define ACPI_STATE_D0 (UINT8) 0 +#define ACPI_STATE_D1 (UINT8) 1 +#define ACPI_STATE_D2 (UINT8) 2 +#define ACPI_STATE_D3 (UINT8) 3 +#define ACPI_D_STATES_MAX ACPI_STATE_D3 +#define ACPI_D_STATE_COUNT 4 + +#define ACPI_STATE_C0 (UINT8) 0 +#define ACPI_STATE_C1 (UINT8) 1 +#define ACPI_STATE_C2 (UINT8) 2 +#define ACPI_STATE_C3 (UINT8) 3 +#define ACPI_C_STATES_MAX ACPI_STATE_C3 +#define ACPI_C_STATE_COUNT 4 + +/* + * Sleep type invalid value + */ +#define ACPI_SLEEP_TYPE_MAX 0x7 +#define ACPI_SLEEP_TYPE_INVALID 0xFF + +/* + * Standard notify values + */ +#define ACPI_NOTIFY_BUS_CHECK (UINT8) 0x00 +#define ACPI_NOTIFY_DEVICE_CHECK (UINT8) 0x01 +#define ACPI_NOTIFY_DEVICE_WAKE (UINT8) 0x02 +#define ACPI_NOTIFY_EJECT_REQUEST (UINT8) 0x03 +#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (UINT8) 0x04 +#define ACPI_NOTIFY_FREQUENCY_MISMATCH (UINT8) 0x05 +#define ACPI_NOTIFY_BUS_MODE_MISMATCH (UINT8) 0x06 +#define ACPI_NOTIFY_POWER_FAULT (UINT8) 0x07 +#define ACPI_NOTIFY_CAPABILITIES_CHECK (UINT8) 0x08 +#define ACPI_NOTIFY_DEVICE_PLD_CHECK (UINT8) 0x09 +#define ACPI_NOTIFY_RESERVED (UINT8) 0x0A +#define ACPI_NOTIFY_LOCALITY_UPDATE (UINT8) 0x0B +#define ACPI_NOTIFY_SHUTDOWN_REQUEST (UINT8) 0x0C +#define ACPI_NOTIFY_AFFINITY_UPDATE (UINT8) 0x0D + +#define ACPI_NOTIFY_MAX 0x0D + +/* + * Types associated with ACPI names and objects. The first group of + * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition + * of the ACPI ObjectType() operator (See the ACPI Spec). Therefore, + * only add to the first group if the spec changes. + * + * NOTE: Types must be kept in sync with the global AcpiNsProperties + * and AcpiNsTypeNames arrays. + */ +typedef UINT32 ACPI_OBJECT_TYPE; + +#define ACPI_TYPE_ANY 0x00 +#define ACPI_TYPE_INTEGER 0x01 /* Byte/Word/Dword/Zero/One/Ones */ +#define ACPI_TYPE_STRING 0x02 +#define ACPI_TYPE_BUFFER 0x03 +#define ACPI_TYPE_PACKAGE 0x04 /* ByteConst, multiple DataTerm/Constant/SuperName */ +#define ACPI_TYPE_FIELD_UNIT 0x05 +#define ACPI_TYPE_DEVICE 0x06 /* Name, multiple Node */ +#define ACPI_TYPE_EVENT 0x07 +#define ACPI_TYPE_METHOD 0x08 /* Name, ByteConst, multiple Code */ +#define ACPI_TYPE_MUTEX 0x09 +#define ACPI_TYPE_REGION 0x0A +#define ACPI_TYPE_POWER 0x0B /* Name,ByteConst,WordConst,multi Node */ +#define ACPI_TYPE_PROCESSOR 0x0C /* Name,ByteConst,DWordConst,ByteConst,multi NmO */ +#define ACPI_TYPE_THERMAL 0x0D /* Name, multiple Node */ +#define ACPI_TYPE_BUFFER_FIELD 0x0E +#define ACPI_TYPE_DDB_HANDLE 0x0F +#define ACPI_TYPE_DEBUG_OBJECT 0x10 + +#define ACPI_TYPE_EXTERNAL_MAX 0x10 +#define ACPI_NUM_TYPES (ACPI_TYPE_EXTERNAL_MAX + 1) + +/* + * These are object types that do not map directly to the ACPI + * ObjectType() operator. They are used for various internal purposes only. + * If new predefined ACPI_TYPEs are added (via the ACPI specification), these + * internal types must move upwards. (There is code that depends on these + * values being contiguous with the external types above.) + */ +#define ACPI_TYPE_LOCAL_REGION_FIELD 0x11 +#define ACPI_TYPE_LOCAL_BANK_FIELD 0x12 +#define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13 +#define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, RefOf, Index */ +#define ACPI_TYPE_LOCAL_ALIAS 0x15 +#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16 +#define ACPI_TYPE_LOCAL_NOTIFY 0x17 +#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18 +#define ACPI_TYPE_LOCAL_RESOURCE 0x19 +#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A +#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple ObjectList Nodes */ + +#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ +#define ACPI_TOTAL_TYPES (ACPI_TYPE_NS_NODE_MAX + 1) + +/* + * These are special object types that never appear in + * a Namespace node, only in an object of ACPI_OPERAND_OBJECT + */ +#define ACPI_TYPE_LOCAL_EXTRA 0x1C +#define ACPI_TYPE_LOCAL_DATA 0x1D + +#define ACPI_TYPE_LOCAL_MAX 0x1D + +/* All types above here are invalid */ + +#define ACPI_TYPE_INVALID 0x1E +#define ACPI_TYPE_NOT_FOUND 0xFF + +#define ACPI_NUM_NS_TYPES (ACPI_TYPE_INVALID + 1) + + +/* + * All I/O + */ +#define ACPI_READ 0 +#define ACPI_WRITE 1 +#define ACPI_IO_MASK 1 + +/* + * Event Types: Fixed & General Purpose + */ +typedef UINT32 ACPI_EVENT_TYPE; + +/* + * Fixed events + */ +#define ACPI_EVENT_PMTIMER 0 +#define ACPI_EVENT_GLOBAL 1 +#define ACPI_EVENT_POWER_BUTTON 2 +#define ACPI_EVENT_SLEEP_BUTTON 3 +#define ACPI_EVENT_RTC 4 +#define ACPI_EVENT_MAX 4 +#define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 + +/* + * Event Status - Per event + * ------------- + * The encoding of ACPI_EVENT_STATUS is illustrated below. + * Note that a set bit (1) indicates the property is TRUE + * (e.g. if bit 0 is set then the event is enabled). + * +-------------+-+-+-+-+-+ + * | Bits 31:5 |4|3|2|1|0| + * +-------------+-+-+-+-+-+ + * | | | | | | + * | | | | | +- Enabled? + * | | | | +--- Enabled for wake? + * | | | +----- Status bit set? + * | | +------- Enable bit set? + * | +--------- Has a handler? + * +--------------- + */ +typedef UINT32 ACPI_EVENT_STATUS; + +#define ACPI_EVENT_FLAG_DISABLED (ACPI_EVENT_STATUS) 0x00 +#define ACPI_EVENT_FLAG_ENABLED (ACPI_EVENT_STATUS) 0x01 +#define ACPI_EVENT_FLAG_WAKE_ENABLED (ACPI_EVENT_STATUS) 0x02 +#define ACPI_EVENT_FLAG_STATUS_SET (ACPI_EVENT_STATUS) 0x04 +#define ACPI_EVENT_FLAG_ENABLE_SET (ACPI_EVENT_STATUS) 0x08 +#define ACPI_EVENT_FLAG_HAS_HANDLER (ACPI_EVENT_STATUS) 0x10 +#define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET + +/* Actions for AcpiSetGpe, AcpiGpeWakeup, AcpiHwLowSetGpe */ + +#define ACPI_GPE_ENABLE 0 +#define ACPI_GPE_DISABLE 1 +#define ACPI_GPE_CONDITIONAL_ENABLE 2 + +/* + * GPE info flags - Per GPE + * +-------+-+-+---+ + * | 7:5 |4|3|2:0| + * +-------+-+-+---+ + * | | | | + * | | | +-- Type of dispatch:to method, handler, notify, or none + * | | +----- Interrupt type: edge or level triggered + * | +------- Is a Wake GPE + * +------------ + */ +#define ACPI_GPE_DISPATCH_NONE (UINT8) 0x00 +#define ACPI_GPE_DISPATCH_METHOD (UINT8) 0x01 +#define ACPI_GPE_DISPATCH_HANDLER (UINT8) 0x02 +#define ACPI_GPE_DISPATCH_NOTIFY (UINT8) 0x03 +#define ACPI_GPE_DISPATCH_RAW_HANDLER (UINT8) 0x04 +#define ACPI_GPE_DISPATCH_MASK (UINT8) 0x07 +#define ACPI_GPE_DISPATCH_TYPE(flags) ((UINT8) ((flags) & ACPI_GPE_DISPATCH_MASK)) + +#define ACPI_GPE_LEVEL_TRIGGERED (UINT8) 0x08 +#define ACPI_GPE_EDGE_TRIGGERED (UINT8) 0x00 +#define ACPI_GPE_XRUPT_TYPE_MASK (UINT8) 0x08 + +#define ACPI_GPE_CAN_WAKE (UINT8) 0x10 + +/* + * Flags for GPE and Lock interfaces + */ +#define ACPI_NOT_ISR 0x1 +#define ACPI_ISR 0x0 + + +/* Notify types */ + +#define ACPI_SYSTEM_NOTIFY 0x1 +#define ACPI_DEVICE_NOTIFY 0x2 +#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY) +#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 +#define ACPI_NUM_NOTIFY_TYPES 2 + +#define ACPI_MAX_SYS_NOTIFY 0x7F +#define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF + +#define ACPI_SYSTEM_HANDLER_LIST 0 /* Used as index, must be SYSTEM_NOTIFY -1 */ +#define ACPI_DEVICE_HANDLER_LIST 1 /* Used as index, must be DEVICE_NOTIFY -1 */ + + +/* Address Space (Operation Region) Types */ + +typedef UINT8 ACPI_ADR_SPACE_TYPE; + +#define ACPI_ADR_SPACE_SYSTEM_MEMORY (ACPI_ADR_SPACE_TYPE) 0 +#define ACPI_ADR_SPACE_SYSTEM_IO (ACPI_ADR_SPACE_TYPE) 1 +#define ACPI_ADR_SPACE_PCI_CONFIG (ACPI_ADR_SPACE_TYPE) 2 +#define ACPI_ADR_SPACE_EC (ACPI_ADR_SPACE_TYPE) 3 +#define ACPI_ADR_SPACE_SMBUS (ACPI_ADR_SPACE_TYPE) 4 +#define ACPI_ADR_SPACE_CMOS (ACPI_ADR_SPACE_TYPE) 5 +#define ACPI_ADR_SPACE_PCI_BAR_TARGET (ACPI_ADR_SPACE_TYPE) 6 +#define ACPI_ADR_SPACE_IPMI (ACPI_ADR_SPACE_TYPE) 7 +#define ACPI_ADR_SPACE_GPIO (ACPI_ADR_SPACE_TYPE) 8 +#define ACPI_ADR_SPACE_GSBUS (ACPI_ADR_SPACE_TYPE) 9 +#define ACPI_ADR_SPACE_PLATFORM_COMM (ACPI_ADR_SPACE_TYPE) 10 + +#define ACPI_NUM_PREDEFINED_REGIONS 11 + +/* + * Special Address Spaces + * + * Note: A Data Table region is a special type of operation region + * that has its own AML opcode. However, internally, the AML + * interpreter simply creates an operation region with an an address + * space type of ACPI_ADR_SPACE_DATA_TABLE. + */ +#define ACPI_ADR_SPACE_DATA_TABLE (ACPI_ADR_SPACE_TYPE) 0x7E /* Internal to ACPICA only */ +#define ACPI_ADR_SPACE_FIXED_HARDWARE (ACPI_ADR_SPACE_TYPE) 0x7F + +/* Values for _REG connection code */ + +#define ACPI_REG_DISCONNECT 0 +#define ACPI_REG_CONNECT 1 + +/* + * BitRegister IDs + * + * These values are intended to be used by the hardware interfaces + * and are mapped to individual bitfields defined within the ACPI + * registers. See the AcpiGbl_BitRegisterInfo global table in utglobal.c + * for this mapping. + */ + +/* PM1 Status register */ + +#define ACPI_BITREG_TIMER_STATUS 0x00 +#define ACPI_BITREG_BUS_MASTER_STATUS 0x01 +#define ACPI_BITREG_GLOBAL_LOCK_STATUS 0x02 +#define ACPI_BITREG_POWER_BUTTON_STATUS 0x03 +#define ACPI_BITREG_SLEEP_BUTTON_STATUS 0x04 +#define ACPI_BITREG_RT_CLOCK_STATUS 0x05 +#define ACPI_BITREG_WAKE_STATUS 0x06 +#define ACPI_BITREG_PCIEXP_WAKE_STATUS 0x07 + +/* PM1 Enable register */ + +#define ACPI_BITREG_TIMER_ENABLE 0x08 +#define ACPI_BITREG_GLOBAL_LOCK_ENABLE 0x09 +#define ACPI_BITREG_POWER_BUTTON_ENABLE 0x0A +#define ACPI_BITREG_SLEEP_BUTTON_ENABLE 0x0B +#define ACPI_BITREG_RT_CLOCK_ENABLE 0x0C +#define ACPI_BITREG_PCIEXP_WAKE_DISABLE 0x0D + +/* PM1 Control register */ + +#define ACPI_BITREG_SCI_ENABLE 0x0E +#define ACPI_BITREG_BUS_MASTER_RLD 0x0F +#define ACPI_BITREG_GLOBAL_LOCK_RELEASE 0x10 +#define ACPI_BITREG_SLEEP_TYPE 0x11 +#define ACPI_BITREG_SLEEP_ENABLE 0x12 + +/* PM2 Control register */ + +#define ACPI_BITREG_ARB_DISABLE 0x13 + +#define ACPI_BITREG_MAX 0x13 +#define ACPI_NUM_BITREG ACPI_BITREG_MAX + 1 + + +/* Status register values. A 1 clears a status bit. 0 = no effect */ + +#define ACPI_CLEAR_STATUS 1 + +/* Enable and Control register values */ + +#define ACPI_ENABLE_EVENT 1 +#define ACPI_DISABLE_EVENT 0 + + +/* Sleep function dispatch */ + +typedef ACPI_STATUS (*ACPI_SLEEP_FUNCTION) ( + UINT8 SleepState); + +typedef struct acpi_sleep_functions +{ + ACPI_SLEEP_FUNCTION LegacyFunction; + ACPI_SLEEP_FUNCTION ExtendedFunction; + +} ACPI_SLEEP_FUNCTIONS; + + +/* + * External ACPI object definition + */ + +/* + * Note: Type == ACPI_TYPE_ANY (0) is used to indicate a NULL package element + * or an unresolved named reference. + */ +typedef union acpi_object +{ + ACPI_OBJECT_TYPE Type; /* See definition of AcpiNsType for values */ + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_INTEGER */ + UINT64 Value; /* The actual number */ + } Integer; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_STRING */ + UINT32 Length; /* # of bytes in string, excluding trailing null */ + char *Pointer; /* points to the string value */ + } String; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_BUFFER */ + UINT32 Length; /* # of bytes in buffer */ + UINT8 *Pointer; /* points to the buffer */ + } Buffer; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_PACKAGE */ + UINT32 Count; /* # of elements in package */ + union acpi_object *Elements; /* Pointer to an array of ACPI_OBJECTs */ + } Package; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_LOCAL_REFERENCE */ + ACPI_OBJECT_TYPE ActualType; /* Type associated with the Handle */ + ACPI_HANDLE Handle; /* object reference */ + } Reference; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_PROCESSOR */ + UINT32 ProcId; + ACPI_IO_ADDRESS PblkAddress; + UINT32 PblkLength; + } Processor; + + struct + { + ACPI_OBJECT_TYPE Type; /* ACPI_TYPE_POWER */ + UINT32 SystemLevel; + UINT32 ResourceOrder; + } PowerResource; + +} ACPI_OBJECT; + + +/* + * List of objects, used as a parameter list for control method evaluation + */ +typedef struct acpi_object_list +{ + UINT32 Count; + ACPI_OBJECT *Pointer; + +} ACPI_OBJECT_LIST; + + +/* + * Miscellaneous common Data Structures used by the interfaces + */ +#define ACPI_NO_BUFFER 0 + +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE_BUFFER (ACPI_SIZE) (0) +#define ACPI_ALLOCATE_LOCAL_BUFFER (ACPI_SIZE) (0) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + +#define ACPI_ALLOCATE_BUFFER (ACPI_SIZE) (-1) /* Let ACPICA allocate buffer */ +#define ACPI_ALLOCATE_LOCAL_BUFFER (ACPI_SIZE) (-2) /* For internal use only (enables tracking) */ + +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + +typedef struct acpi_buffer +{ + ACPI_SIZE Length; /* Length in bytes of the buffer */ + void *Pointer; /* pointer to buffer */ + +} ACPI_BUFFER; + + +/* + * NameType for AcpiGetName + */ +#define ACPI_FULL_PATHNAME 0 +#define ACPI_SINGLE_NAME 1 +#define ACPI_FULL_PATHNAME_NO_TRAILING 2 +#define ACPI_NAME_TYPE_MAX 2 + + +/* + * Predefined Namespace items + */ +typedef struct acpi_predefined_names +{ + char *Name; + UINT8 Type; + char *Val; + +} ACPI_PREDEFINED_NAMES; + + +/* + * Structure and flags for AcpiGetSystemInfo + */ +#define ACPI_SYS_MODE_UNKNOWN 0x0000 +#define ACPI_SYS_MODE_ACPI 0x0001 +#define ACPI_SYS_MODE_LEGACY 0x0002 +#define ACPI_SYS_MODES_MASK 0x0003 + + +/* + * System info returned by AcpiGetSystemInfo() + */ +typedef struct acpi_system_info +{ + UINT32 AcpiCaVersion; + UINT32 Flags; + UINT32 TimerResolution; + UINT32 Reserved1; + UINT32 Reserved2; + UINT32 DebugLevel; + UINT32 DebugLayer; + +} ACPI_SYSTEM_INFO; + + +/* + * System statistics returned by AcpiGetStatistics() + */ +typedef struct acpi_statistics +{ + UINT32 SciCount; + UINT32 GpeCount; + UINT32 FixedEventCount[ACPI_NUM_FIXED_EVENTS]; + UINT32 MethodCount; + +} ACPI_STATISTICS; + + +/* Table Event Types */ + +#define ACPI_TABLE_EVENT_LOAD 0x0 +#define ACPI_TABLE_EVENT_UNLOAD 0x1 +#define ACPI_NUM_TABLE_EVENTS 2 + + +/* + * Types specific to the OS service interfaces + */ +typedef UINT32 +(ACPI_SYSTEM_XFACE *ACPI_OSD_HANDLER) ( + void *Context); + +typedef void +(ACPI_SYSTEM_XFACE *ACPI_OSD_EXEC_CALLBACK) ( + void *Context); + +/* + * Various handlers and callback procedures + */ +typedef +UINT32 (*ACPI_SCI_HANDLER) ( + void *Context); + +typedef +void (*ACPI_GBL_EVENT_HANDLER) ( + UINT32 EventType, + ACPI_HANDLE Device, + UINT32 EventNumber, + void *Context); + +#define ACPI_EVENT_TYPE_GPE 0 +#define ACPI_EVENT_TYPE_FIXED 1 + +typedef +UINT32 (*ACPI_EVENT_HANDLER) ( + void *Context); + +typedef +UINT32 (*ACPI_GPE_HANDLER) ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + void *Context); + +typedef +void (*ACPI_NOTIFY_HANDLER) ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context); + +typedef +void (*ACPI_OBJECT_HANDLER) ( + ACPI_HANDLE Object, + void *Data); + +typedef +ACPI_STATUS (*ACPI_INIT_HANDLER) ( + ACPI_HANDLE Object, + UINT32 Function); + +#define ACPI_INIT_DEVICE_INI 1 + +typedef +ACPI_STATUS (*ACPI_EXCEPTION_HANDLER) ( + ACPI_STATUS AmlStatus, + ACPI_NAME Name, + UINT16 Opcode, + UINT32 AmlOffset, + void *Context); + +/* Table Event handler (Load, LoadTable, etc.) and types */ + +typedef +ACPI_STATUS (*ACPI_TABLE_HANDLER) ( + UINT32 Event, + void *Table, + void *Context); + +#define ACPI_TABLE_LOAD 0x0 +#define ACPI_TABLE_UNLOAD 0x1 +#define ACPI_NUM_TABLE_EVENTS 2 + + +/* Address Spaces (For Operation Regions) */ + +typedef +ACPI_STATUS (*ACPI_ADR_SPACE_HANDLER) ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +#define ACPI_DEFAULT_HANDLER NULL + +/* Special Context data for GenericSerialBus/GeneralPurposeIo (ACPI 5.0) */ + +typedef struct acpi_connection_info +{ + UINT8 *Connection; + UINT16 Length; + UINT8 AccessLength; + +} ACPI_CONNECTION_INFO; + + +typedef +ACPI_STATUS (*ACPI_ADR_SPACE_SETUP) ( + ACPI_HANDLE RegionHandle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +#define ACPI_REGION_ACTIVATE 0 +#define ACPI_REGION_DEACTIVATE 1 + +typedef +ACPI_STATUS (*ACPI_WALK_CALLBACK) ( + ACPI_HANDLE Object, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +typedef +UINT32 (*ACPI_INTERFACE_HANDLER) ( + ACPI_STRING InterfaceName, + UINT32 Supported); + + +/* Interrupt handler return values */ + +#define ACPI_INTERRUPT_NOT_HANDLED 0x00 +#define ACPI_INTERRUPT_HANDLED 0x01 + +/* GPE handler return values */ + +#define ACPI_REENABLE_GPE 0x80 + + +/* Length of 32-bit EISAID values when converted back to a string */ + +#define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */ + +/* Length of UUID (string) values */ + +#define ACPI_UUID_LENGTH 16 + +/* Length of 3-byte PCI class code values when converted back to a string */ + +#define ACPI_PCICLS_STRING_SIZE 7 /* Includes null terminator */ + + +/* Structures used for device/processor HID, UID, CID */ + +typedef struct acpi_pnp_device_id +{ + UINT32 Length; /* Length of string + null */ + char *String; + +} ACPI_PNP_DEVICE_ID; + +typedef struct acpi_pnp_device_id_list +{ + UINT32 Count; /* Number of IDs in Ids array */ + UINT32 ListSize; /* Size of list, including ID strings */ + ACPI_PNP_DEVICE_ID Ids[1]; /* ID array */ + +} ACPI_PNP_DEVICE_ID_LIST; + +/* + * Structure returned from AcpiGetObjectInfo. + * Optimized for both 32- and 64-bit builds + */ +typedef struct acpi_device_info +{ + UINT32 InfoSize; /* Size of info, including ID strings */ + UINT32 Name; /* ACPI object Name */ + ACPI_OBJECT_TYPE Type; /* ACPI object Type */ + UINT8 ParamCount; /* If a method, required parameter count */ + UINT16 Valid; /* Indicates which optional fields are valid */ + UINT8 Flags; /* Miscellaneous info */ + UINT8 HighestDstates[4]; /* _SxD values: 0xFF indicates not valid */ + UINT8 LowestDstates[5]; /* _SxW values: 0xFF indicates not valid */ + UINT32 CurrentStatus; /* _STA value */ + UINT64 Address; /* _ADR value */ + ACPI_PNP_DEVICE_ID HardwareId; /* _HID value */ + ACPI_PNP_DEVICE_ID UniqueId; /* _UID value */ + ACPI_PNP_DEVICE_ID ClassCode; /* _CLS value */ + ACPI_PNP_DEVICE_ID_LIST CompatibleIdList; /* _CID list */ + +} ACPI_DEVICE_INFO; + +/* Values for Flags field above (AcpiGetObjectInfo) */ + +#define ACPI_PCI_ROOT_BRIDGE 0x01 + +/* Flags for Valid field above (AcpiGetObjectInfo) */ + +#define ACPI_VALID_STA 0x0001 +#define ACPI_VALID_ADR 0x0002 +#define ACPI_VALID_HID 0x0004 +#define ACPI_VALID_UID 0x0008 +#define ACPI_VALID_CID 0x0020 +#define ACPI_VALID_CLS 0x0040 +#define ACPI_VALID_SXDS 0x0100 +#define ACPI_VALID_SXWS 0x0200 + +/* Flags for _STA method */ + +#define ACPI_STA_DEVICE_PRESENT 0x01 +#define ACPI_STA_DEVICE_ENABLED 0x02 +#define ACPI_STA_DEVICE_UI 0x04 +#define ACPI_STA_DEVICE_FUNCTIONING 0x08 +#define ACPI_STA_DEVICE_OK 0x08 /* Synonym */ +#define ACPI_STA_BATTERY_PRESENT 0x10 + + +/* Context structs for address space handlers */ + +typedef struct acpi_pci_id +{ + UINT16 Segment; + UINT16 Bus; + UINT16 Device; + UINT16 Function; + +} ACPI_PCI_ID; + +typedef struct acpi_mem_space_context +{ + UINT32 Length; + ACPI_PHYSICAL_ADDRESS Address; + ACPI_PHYSICAL_ADDRESS MappedPhysicalAddress; + UINT8 *MappedLogicalAddress; + ACPI_SIZE MappedLength; + +} ACPI_MEM_SPACE_CONTEXT; + + +/* + * ACPI_MEMORY_LIST is used only if the ACPICA local cache is enabled + */ +typedef struct acpi_memory_list +{ + char *ListName; + void *ListHead; + UINT16 ObjectSize; + UINT16 MaxDepth; + UINT16 CurrentDepth; + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Statistics for debug memory tracking only */ + + UINT32 TotalAllocated; + UINT32 TotalFreed; + UINT32 MaxOccupied; + UINT32 TotalSize; + UINT32 CurrentTotalSize; + UINT32 Requests; + UINT32 Hits; +#endif + +} ACPI_MEMORY_LIST; + + +/* Definitions of trace event types */ + +typedef enum +{ + ACPI_TRACE_AML_METHOD, + ACPI_TRACE_AML_OPCODE, + ACPI_TRACE_AML_REGION + +} ACPI_TRACE_EVENT_TYPE; + + +/* Definitions of _OSI support */ + +#define ACPI_VENDOR_STRINGS 0x01 +#define ACPI_FEATURE_STRINGS 0x02 +#define ACPI_ENABLE_INTERFACES 0x00 +#define ACPI_DISABLE_INTERFACES 0x04 + +#define ACPI_DISABLE_ALL_VENDOR_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_DISABLE_ALL_FEATURE_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_DISABLE_ALL_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_VENDOR_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS) +#define ACPI_ENABLE_ALL_FEATURE_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS) +#define ACPI_ENABLE_ALL_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) + +#define ACPI_OSI_WIN_2000 0x01 +#define ACPI_OSI_WIN_XP 0x02 +#define ACPI_OSI_WIN_XP_SP1 0x03 +#define ACPI_OSI_WINSRV_2003 0x04 +#define ACPI_OSI_WIN_XP_SP2 0x05 +#define ACPI_OSI_WINSRV_2003_SP1 0x06 +#define ACPI_OSI_WIN_VISTA 0x07 +#define ACPI_OSI_WINSRV_2008 0x08 +#define ACPI_OSI_WIN_VISTA_SP1 0x09 +#define ACPI_OSI_WIN_VISTA_SP2 0x0A +#define ACPI_OSI_WIN_7 0x0B +#define ACPI_OSI_WIN_8 0x0C +#define ACPI_OSI_WIN_10 0x0D + + +/* Definitions of file IO */ + +#define ACPI_FILE_READING 0x01 +#define ACPI_FILE_WRITING 0x02 +#define ACPI_FILE_BINARY 0x04 + +#define ACPI_FILE_BEGIN 0x01 +#define ACPI_FILE_END 0x02 + + +/* Definitions of getopt */ + +#define ACPI_OPT_END -1 + + +#endif /* __ACTYPES_H__ */ diff --git a/third_party/lib/acpica/source/include/acutils.h b/third_party/lib/acpica/source/include/acutils.h new file mode 100644 index 000000000..cbbf7c509 --- /dev/null +++ b/third_party/lib/acpica/source/include/acutils.h @@ -0,0 +1,1086 @@ +/****************************************************************************** + * + * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACUTILS_H +#define _ACUTILS_H + + +extern const UINT8 AcpiGbl_ResourceAmlSizes[]; +extern const UINT8 AcpiGbl_ResourceAmlSerialBusSizes[]; + +/* Strings used by the disassembler and debugger resource dump routines */ + +#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) + +extern const char *AcpiGbl_BmDecode[]; +extern const char *AcpiGbl_ConfigDecode[]; +extern const char *AcpiGbl_ConsumeDecode[]; +extern const char *AcpiGbl_DecDecode[]; +extern const char *AcpiGbl_HeDecode[]; +extern const char *AcpiGbl_IoDecode[]; +extern const char *AcpiGbl_LlDecode[]; +extern const char *AcpiGbl_MaxDecode[]; +extern const char *AcpiGbl_MemDecode[]; +extern const char *AcpiGbl_MinDecode[]; +extern const char *AcpiGbl_MtpDecode[]; +extern const char *AcpiGbl_RngDecode[]; +extern const char *AcpiGbl_RwDecode[]; +extern const char *AcpiGbl_ShrDecode[]; +extern const char *AcpiGbl_SizDecode[]; +extern const char *AcpiGbl_TrsDecode[]; +extern const char *AcpiGbl_TtpDecode[]; +extern const char *AcpiGbl_TypDecode[]; +extern const char *AcpiGbl_PpcDecode[]; +extern const char *AcpiGbl_IorDecode[]; +extern const char *AcpiGbl_DtsDecode[]; +extern const char *AcpiGbl_CtDecode[]; +extern const char *AcpiGbl_SbtDecode[]; +extern const char *AcpiGbl_AmDecode[]; +extern const char *AcpiGbl_SmDecode[]; +extern const char *AcpiGbl_WmDecode[]; +extern const char *AcpiGbl_CphDecode[]; +extern const char *AcpiGbl_CpoDecode[]; +extern const char *AcpiGbl_DpDecode[]; +extern const char *AcpiGbl_EdDecode[]; +extern const char *AcpiGbl_BpbDecode[]; +extern const char *AcpiGbl_SbDecode[]; +extern const char *AcpiGbl_FcDecode[]; +extern const char *AcpiGbl_PtDecode[]; +#endif + +/* + * For the iASL compiler case, the output is redirected to stderr so that + * any of the various ACPI errors and warnings do not appear in the output + * files, for either the compiler or disassembler portions of the tool. + */ +#ifdef ACPI_ASL_COMPILER + +#include + +#define ACPI_MSG_REDIRECT_BEGIN \ + FILE *OutputFile = AcpiGbl_OutputFile; \ + AcpiOsRedirectOutput (stderr); + +#define ACPI_MSG_REDIRECT_END \ + AcpiOsRedirectOutput (OutputFile); + +#else +/* + * non-iASL case - no redirection, nothing to do + */ +#define ACPI_MSG_REDIRECT_BEGIN +#define ACPI_MSG_REDIRECT_END +#endif + +/* + * Common error message prefixes + */ +#define ACPI_MSG_ERROR "ACPI Error: " +#define ACPI_MSG_EXCEPTION "ACPI Exception: " +#define ACPI_MSG_WARNING "ACPI Warning: " +#define ACPI_MSG_INFO "ACPI: " + +#define ACPI_MSG_BIOS_ERROR "ACPI BIOS Error (bug): " +#define ACPI_MSG_BIOS_WARNING "ACPI BIOS Warning (bug): " + +/* + * Common message suffix + */ +#define ACPI_MSG_SUFFIX \ + AcpiOsPrintf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, ModuleName, LineNumber) + + +/* Types for Resource descriptor entries */ + +#define ACPI_INVALID_RESOURCE 0 +#define ACPI_FIXED_LENGTH 1 +#define ACPI_VARIABLE_LENGTH 2 +#define ACPI_SMALL_VARIABLE_LENGTH 3 + +typedef +ACPI_STATUS (*ACPI_WALK_AML_CALLBACK) ( + UINT8 *Aml, + UINT32 Length, + UINT32 Offset, + UINT8 ResourceIndex, + void **Context); + +typedef +ACPI_STATUS (*ACPI_PKG_CALLBACK) ( + UINT8 ObjectType, + ACPI_OPERAND_OBJECT *SourceObject, + ACPI_GENERIC_STATE *State, + void *Context); + +typedef struct acpi_pkg_info +{ + UINT8 *FreeSpace; + ACPI_SIZE Length; + UINT32 ObjectSpace; + UINT32 NumPackages; + +} ACPI_PKG_INFO; + +/* Object reference counts */ + +#define REF_INCREMENT (UINT16) 0 +#define REF_DECREMENT (UINT16) 1 + +/* AcpiUtDumpBuffer */ + +#define DB_BYTE_DISPLAY 1 +#define DB_WORD_DISPLAY 2 +#define DB_DWORD_DISPLAY 4 +#define DB_QWORD_DISPLAY 8 + + +/* + * utnonansi - Non-ANSI C library functions + */ +void +AcpiUtStrupr ( + char *SrcString); + +void +AcpiUtStrlwr ( + char *SrcString); + +int +AcpiUtStricmp ( + char *String1, + char *String2); + +ACPI_STATUS +AcpiUtStrtoul64 ( + char *String, + UINT32 Base, + UINT64 *RetInteger); + + +/* + * utglobal - Global data structures and procedures + */ +ACPI_STATUS +AcpiUtInitGlobals ( + void); + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +const char * +AcpiUtGetMutexName ( + UINT32 MutexId); + +const char * +AcpiUtGetNotifyName ( + UINT32 NotifyValue, + ACPI_OBJECT_TYPE Type); +#endif + +const char * +AcpiUtGetTypeName ( + ACPI_OBJECT_TYPE Type); + +const char * +AcpiUtGetNodeName ( + void *Object); + +const char * +AcpiUtGetDescriptorName ( + void *Object); + +const char * +AcpiUtGetReferenceName ( + ACPI_OPERAND_OBJECT *Object); + +const char * +AcpiUtGetObjectTypeName ( + ACPI_OPERAND_OBJECT *ObjDesc); + +const char * +AcpiUtGetRegionName ( + UINT8 SpaceId); + +const char * +AcpiUtGetEventName ( + UINT32 EventId); + +char +AcpiUtHexToAsciiChar ( + UINT64 Integer, + UINT32 Position); + +UINT8 +AcpiUtAsciiCharToHex ( + int HexChar); + +BOOLEAN +AcpiUtValidObjectType ( + ACPI_OBJECT_TYPE Type); + + +/* + * utinit - miscellaneous initialization and shutdown + */ +ACPI_STATUS +AcpiUtHardwareInitialize ( + void); + +void +AcpiUtSubsystemShutdown ( + void); + + +/* + * utcopy - Object construction and conversion interfaces + */ +ACPI_STATUS +AcpiUtBuildSimpleObject( + ACPI_OPERAND_OBJECT *Obj, + ACPI_OBJECT *UserObj, + UINT8 *DataSpace, + UINT32 *BufferSpaceUsed); + +ACPI_STATUS +AcpiUtBuildPackageObject ( + ACPI_OPERAND_OBJECT *Obj, + UINT8 *Buffer, + UINT32 *SpaceUsed); + +ACPI_STATUS +AcpiUtCopyIobjectToEobject ( + ACPI_OPERAND_OBJECT *Obj, + ACPI_BUFFER *RetBuffer); + +ACPI_STATUS +AcpiUtCopyEobjectToIobject ( + ACPI_OBJECT *Obj, + ACPI_OPERAND_OBJECT **InternalObj); + +ACPI_STATUS +AcpiUtCopyISimpleToIsimple ( + ACPI_OPERAND_OBJECT *SourceObj, + ACPI_OPERAND_OBJECT *DestObj); + +ACPI_STATUS +AcpiUtCopyIobjectToIobject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **DestDesc, + ACPI_WALK_STATE *WalkState); + + +/* + * utcreate - Object creation + */ +ACPI_STATUS +AcpiUtUpdateObjectReference ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action); + + +/* + * utdebug - Debug interfaces + */ +void +AcpiUtInitStackPtrTrace ( + void); + +void +AcpiUtTrackStackPtr ( + void); + +void +AcpiUtTrace ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId); + +void +AcpiUtTracePtr ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + void *Pointer); + +void +AcpiUtTraceU32 ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT32 Integer); + +void +AcpiUtTraceStr ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + char *String); + +void +AcpiUtExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId); + +void +AcpiUtStatusExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + ACPI_STATUS Status); + +void +AcpiUtValueExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT64 Value); + +void +AcpiUtPtrExit ( + UINT32 LineNumber, + const char *FunctionName, + const char *ModuleName, + UINT32 ComponentId, + UINT8 *Ptr); + +void +AcpiUtDebugDumpBuffer ( + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 ComponentId); + +void +AcpiUtDumpBuffer ( + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 Offset); + +#ifdef ACPI_APPLICATION +void +AcpiUtDumpBufferToFile ( + ACPI_FILE File, + UINT8 *Buffer, + UINT32 Count, + UINT32 Display, + UINT32 BaseOffset); +#endif + +void +AcpiUtReportError ( + char *ModuleName, + UINT32 LineNumber); + +void +AcpiUtReportInfo ( + char *ModuleName, + UINT32 LineNumber); + +void +AcpiUtReportWarning ( + char *ModuleName, + UINT32 LineNumber); + + +/* + * utdelete - Object deletion and reference counts + */ +void +AcpiUtAddReference ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtRemoveReference ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtDeleteInternalPackageObject ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtDeleteInternalSimpleObject ( + ACPI_OPERAND_OBJECT *Object); + +void +AcpiUtDeleteInternalObjectList ( + ACPI_OPERAND_OBJECT **ObjList); + + +/* + * uteval - object evaluation + */ +ACPI_STATUS +AcpiUtEvaluateObject ( + ACPI_NAMESPACE_NODE *PrefixNode, + char *Path, + UINT32 ExpectedReturnBtypes, + ACPI_OPERAND_OBJECT **ReturnDesc); + +ACPI_STATUS +AcpiUtEvaluateNumericObject ( + char *ObjectName, + ACPI_NAMESPACE_NODE *DeviceNode, + UINT64 *Value); + +ACPI_STATUS +AcpiUtExecute_STA ( + ACPI_NAMESPACE_NODE *DeviceNode, + UINT32 *StatusFlags); + +ACPI_STATUS +AcpiUtExecutePowerMethods ( + ACPI_NAMESPACE_NODE *DeviceNode, + const char **MethodNames, + UINT8 MethodCount, + UINT8 *OutValues); + + +/* + * utids - device ID support + */ +ACPI_STATUS +AcpiUtExecute_HID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId); + +ACPI_STATUS +AcpiUtExecute_UID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId); + +ACPI_STATUS +AcpiUtExecute_CID ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID_LIST **ReturnCidList); + +ACPI_STATUS +AcpiUtExecute_CLS ( + ACPI_NAMESPACE_NODE *DeviceNode, + ACPI_PNP_DEVICE_ID **ReturnId); + + +/* + * utlock - reader/writer locks + */ +ACPI_STATUS +AcpiUtCreateRwLock ( + ACPI_RW_LOCK *Lock); + +void +AcpiUtDeleteRwLock ( + ACPI_RW_LOCK *Lock); + +ACPI_STATUS +AcpiUtAcquireReadLock ( + ACPI_RW_LOCK *Lock); + +ACPI_STATUS +AcpiUtReleaseReadLock ( + ACPI_RW_LOCK *Lock); + +ACPI_STATUS +AcpiUtAcquireWriteLock ( + ACPI_RW_LOCK *Lock); + +void +AcpiUtReleaseWriteLock ( + ACPI_RW_LOCK *Lock); + + +/* + * utobject - internal object create/delete/cache routines + */ +ACPI_OPERAND_OBJECT * +AcpiUtCreateInternalObjectDbg ( + const char *ModuleName, + UINT32 LineNumber, + UINT32 ComponentId, + ACPI_OBJECT_TYPE Type); + +void * +AcpiUtAllocateObjectDescDbg ( + const char *ModuleName, + UINT32 LineNumber, + UINT32 ComponentId); + +#define AcpiUtCreateInternalObject(t) AcpiUtCreateInternalObjectDbg (_AcpiModuleName,__LINE__,_COMPONENT,t) +#define AcpiUtAllocateObjectDesc() AcpiUtAllocateObjectDescDbg (_AcpiModuleName,__LINE__,_COMPONENT) + +void +AcpiUtDeleteObjectDesc ( + ACPI_OPERAND_OBJECT *Object); + +BOOLEAN +AcpiUtValidInternalObject ( + void *Object); + +ACPI_OPERAND_OBJECT * +AcpiUtCreatePackageObject ( + UINT32 Count); + +ACPI_OPERAND_OBJECT * +AcpiUtCreateIntegerObject ( + UINT64 Value); + +ACPI_OPERAND_OBJECT * +AcpiUtCreateBufferObject ( + ACPI_SIZE BufferSize); + +ACPI_OPERAND_OBJECT * +AcpiUtCreateStringObject ( + ACPI_SIZE StringSize); + +ACPI_STATUS +AcpiUtGetObjectSize( + ACPI_OPERAND_OBJECT *Obj, + ACPI_SIZE *ObjLength); + + +/* + * utosi - Support for the _OSI predefined control method + */ +ACPI_STATUS +AcpiUtInitializeInterfaces ( + void); + +ACPI_STATUS +AcpiUtInterfaceTerminate ( + void); + +ACPI_STATUS +AcpiUtInstallInterface ( + ACPI_STRING InterfaceName); + +ACPI_STATUS +AcpiUtRemoveInterface ( + ACPI_STRING InterfaceName); + +ACPI_STATUS +AcpiUtUpdateInterfaces ( + UINT8 Action); + +ACPI_INTERFACE_INFO * +AcpiUtGetInterface ( + ACPI_STRING InterfaceName); + +ACPI_STATUS +AcpiUtOsiImplementation ( + ACPI_WALK_STATE *WalkState); + + +/* + * utpredef - support for predefined names + */ +const ACPI_PREDEFINED_INFO * +AcpiUtGetNextPredefinedMethod ( + const ACPI_PREDEFINED_INFO *ThisName); + +const ACPI_PREDEFINED_INFO * +AcpiUtMatchPredefinedMethod ( + char *Name); + +void +AcpiUtGetExpectedReturnTypes ( + char *Buffer, + UINT32 ExpectedBtypes); + +#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP) +const ACPI_PREDEFINED_INFO * +AcpiUtMatchResourceName ( + char *Name); + +void +AcpiUtDisplayPredefinedMethod ( + char *Buffer, + const ACPI_PREDEFINED_INFO *ThisName, + BOOLEAN MultiLine); + +UINT32 +AcpiUtGetResourceBitWidth ( + char *Buffer, + UINT16 Types); +#endif + + +/* + * utstate - Generic state creation/cache routines + */ +void +AcpiUtPushGenericState ( + ACPI_GENERIC_STATE **ListHead, + ACPI_GENERIC_STATE *State); + +ACPI_GENERIC_STATE * +AcpiUtPopGenericState ( + ACPI_GENERIC_STATE **ListHead); + + +ACPI_GENERIC_STATE * +AcpiUtCreateGenericState ( + void); + +ACPI_THREAD_STATE * +AcpiUtCreateThreadState ( + void); + +ACPI_GENERIC_STATE * +AcpiUtCreateUpdateState ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action); + +ACPI_GENERIC_STATE * +AcpiUtCreatePkgState ( + void *InternalObject, + void *ExternalObject, + UINT16 Index); + +ACPI_STATUS +AcpiUtCreateUpdateStateAndPush ( + ACPI_OPERAND_OBJECT *Object, + UINT16 Action, + ACPI_GENERIC_STATE **StateList); + +ACPI_GENERIC_STATE * +AcpiUtCreateControlState ( + void); + +void +AcpiUtDeleteGenericState ( + ACPI_GENERIC_STATE *State); + + +/* + * utmath + */ +ACPI_STATUS +AcpiUtDivide ( + UINT64 InDividend, + UINT64 InDivisor, + UINT64 *OutQuotient, + UINT64 *OutRemainder); + +ACPI_STATUS +AcpiUtShortDivide ( + UINT64 InDividend, + UINT32 Divisor, + UINT64 *OutQuotient, + UINT32 *OutRemainder); + + +/* + * utmisc + */ +const ACPI_EXCEPTION_INFO * +AcpiUtValidateException ( + ACPI_STATUS Status); + +BOOLEAN +AcpiUtIsPciRootBridge ( + char *Id); + +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) +BOOLEAN +AcpiUtIsAmlTable ( + ACPI_TABLE_HEADER *Table); +#endif + +ACPI_STATUS +AcpiUtWalkPackageTree ( + ACPI_OPERAND_OBJECT *SourceObject, + void *TargetObject, + ACPI_PKG_CALLBACK WalkCallback, + void *Context); + +/* Values for Base above (16=Hex, 10=Decimal) */ + +#define ACPI_ANY_BASE 0 + + +UINT32 +AcpiUtDwordByteSwap ( + UINT32 Value); + +void +AcpiUtSetIntegerWidth ( + UINT8 Revision); + +#ifdef ACPI_DEBUG_OUTPUT +void +AcpiUtDisplayInitPathname ( + UINT8 Type, + ACPI_NAMESPACE_NODE *ObjHandle, + char *Path); +#endif + + +/* + * utownerid - Support for Table/Method Owner IDs + */ +ACPI_STATUS +AcpiUtAllocateOwnerId ( + ACPI_OWNER_ID *OwnerId); + +void +AcpiUtReleaseOwnerId ( + ACPI_OWNER_ID *OwnerId); + + +/* + * utresrc + */ +ACPI_STATUS +AcpiUtWalkAmlResources ( + ACPI_WALK_STATE *WalkState, + UINT8 *Aml, + ACPI_SIZE AmlLength, + ACPI_WALK_AML_CALLBACK UserFunction, + void **Context); + +ACPI_STATUS +AcpiUtValidateResource ( + ACPI_WALK_STATE *WalkState, + void *Aml, + UINT8 *ReturnIndex); + +UINT32 +AcpiUtGetDescriptorLength ( + void *Aml); + +UINT16 +AcpiUtGetResourceLength ( + void *Aml); + +UINT8 +AcpiUtGetResourceHeaderLength ( + void *Aml); + +UINT8 +AcpiUtGetResourceType ( + void *Aml); + +ACPI_STATUS +AcpiUtGetResourceEndTag ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT8 **EndTag); + + +/* + * utstring - String and character utilities + */ +void +AcpiUtPrintString ( + char *String, + UINT16 MaxLength); + +#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP +void +UtConvertBackslashes ( + char *Pathname); +#endif + +BOOLEAN +AcpiUtValidAcpiName ( + char *Name); + +BOOLEAN +AcpiUtValidAcpiChar ( + char Character, + UINT32 Position); + +void +AcpiUtRepairName ( + char *Name); + +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +BOOLEAN +AcpiUtSafeStrcpy ( + char *Dest, + ACPI_SIZE DestSize, + char *Source); + +BOOLEAN +AcpiUtSafeStrcat ( + char *Dest, + ACPI_SIZE DestSize, + char *Source); + +BOOLEAN +AcpiUtSafeStrncat ( + char *Dest, + ACPI_SIZE DestSize, + char *Source, + ACPI_SIZE MaxTransferLength); +#endif + + +/* + * utmutex - mutex support + */ +ACPI_STATUS +AcpiUtMutexInitialize ( + void); + +void +AcpiUtMutexTerminate ( + void); + +ACPI_STATUS +AcpiUtAcquireMutex ( + ACPI_MUTEX_HANDLE MutexId); + +ACPI_STATUS +AcpiUtReleaseMutex ( + ACPI_MUTEX_HANDLE MutexId); + + +/* + * utalloc - memory allocation and object caching + */ +ACPI_STATUS +AcpiUtCreateCaches ( + void); + +ACPI_STATUS +AcpiUtDeleteCaches ( + void); + +ACPI_STATUS +AcpiUtValidateBuffer ( + ACPI_BUFFER *Buffer); + +ACPI_STATUS +AcpiUtInitializeBuffer ( + ACPI_BUFFER *Buffer, + ACPI_SIZE RequiredLength); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +void * +AcpiUtAllocateAndTrack ( + ACPI_SIZE Size, + UINT32 Component, + const char *Module, + UINT32 Line); + +void * +AcpiUtAllocateZeroedAndTrack ( + ACPI_SIZE Size, + UINT32 Component, + const char *Module, + UINT32 Line); + +void +AcpiUtFreeAndTrack ( + void *Address, + UINT32 Component, + const char *Module, + UINT32 Line); + +void +AcpiUtDumpAllocationInfo ( + void); + +void +AcpiUtDumpAllocations ( + UINT32 Component, + const char *Module); + +ACPI_STATUS +AcpiUtCreateList ( + char *ListName, + UINT16 ObjectSize, + ACPI_MEMORY_LIST **ReturnCache); + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + + +/* + * utaddress - address range check + */ +ACPI_STATUS +AcpiUtAddAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 Length, + ACPI_NAMESPACE_NODE *RegionNode); + +void +AcpiUtRemoveAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_NAMESPACE_NODE *RegionNode); + +UINT32 +AcpiUtCheckAddressRange ( + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 Length, + BOOLEAN Warn); + +void +AcpiUtDeleteAddressLists ( + void); + + +/* + * utxferror - various error/warning output functions + */ +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedWarning ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedInfo ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedBiosError ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void +AcpiUtNamespaceError ( + const char *ModuleName, + UINT32 LineNumber, + const char *InternalName, + ACPI_STATUS LookupStatus); + +void +AcpiUtMethodError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Message, + ACPI_NAMESPACE_NODE *Node, + const char *Path, + ACPI_STATUS LookupStatus); + + +/* + * Utility functions for ACPI names and IDs + */ +const AH_PREDEFINED_NAME * +AcpiAhMatchPredefinedName ( + char *Nameseg); + +const AH_DEVICE_ID * +AcpiAhMatchHardwareId ( + char *Hid); + +const char * +AcpiAhMatchUuid ( + UINT8 *Data); + + +/* + * utprint - printf/vprintf output functions + */ +const char * +AcpiUtScanNumber ( + const char *String, + UINT64 *NumberPtr); + +const char * +AcpiUtPrintNumber ( + char *String, + UINT64 Number); + +int +AcpiUtVsnprintf ( + char *String, + ACPI_SIZE Size, + const char *Format, + va_list Args); + +int +AcpiUtSnprintf ( + char *String, + ACPI_SIZE Size, + const char *Format, + ...); + +#ifdef ACPI_APPLICATION +int +AcpiUtFileVprintf ( + ACPI_FILE File, + const char *Format, + va_list Args); + +int +AcpiUtFilePrintf ( + ACPI_FILE File, + const char *Format, + ...); +#endif + + +/* + * utuuid -- UUID support functions + */ +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP) +void +AcpiUtConvertStringToUuid ( + char *InString, + UINT8 *UuidBuffer); +#endif + +#endif /* _ACUTILS_H */ diff --git a/third_party/lib/acpica/source/include/acuuid.h b/third_party/lib/acpica/source/include/acuuid.h new file mode 100644 index 000000000..5c42990ab --- /dev/null +++ b/third_party/lib/acpica/source/include/acuuid.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * + * Name: acuuid.h - ACPI-related UUID/GUID definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACUUID_H__ +#define __ACUUID_H__ + +/* + * Note1: UUIDs and GUIDs are defined to be identical in ACPI. + * + * Note2: This file is standalone and should remain that way. + */ + +/* Controllers */ + +#define UUID_GPIO_CONTROLLER "4f248f40-d5e2-499f-834c-27758ea1cd3f" +#define UUID_USB_CONTROLLER "ce2ee385-00e6-48cb-9f05-2edb927c4899" +#define UUID_SATA_CONTROLLER "e4db149b-fcfe-425b-a6d8-92357d78fc7f" + +/* Devices */ + +#define UUID_PCI_HOST_BRIDGE "33db4d5b-1ff7-401c-9657-7441c03dd766" +#define UUID_I2C_DEVICE "3cdff6f7-4267-4555-ad05-b30a3d8938de" +#define UUID_POWER_BUTTON "dfbcf3c5-e7a5-44e6-9c1f-29c76f6e059c" + +/* Interfaces */ + +#define UUID_DEVICE_LABELING "e5c937d0-3553-4d7a-9117-ea4d19c3434d" +#define UUID_PHYSICAL_PRESENCE "3dddfaa6-361b-4eb4-a424-8d10089d1653" + +/* NVDIMM - NFIT table */ + +#define UUID_VOLATILE_MEMORY "7305944f-fdda-44e3-b16c-3f22d252e5d0" +#define UUID_PERSISTENT_MEMORY "66f0d379-b4f3-4074-ac43-0d3318b78cdb" +#define UUID_CONTROL_REGION "92f701f6-13b4-405d-910b-299367e8234c" +#define UUID_DATA_REGION "91af0530-5d86-470e-a6b0-0a2db9408249" +#define UUID_VOLATILE_VIRTUAL_DISK "77ab535a-45fc-624b-5560-f7b281d1f96e" +#define UUID_VOLATILE_VIRTUAL_CD "3d5abd30-4175-87ce-6d64-d2ade523c4bb" +#define UUID_PERSISTENT_VIRTUAL_DISK "5cea02c9-4d07-69d3-269f-4496fbe096f9" +#define UUID_PERSISTENT_VIRTUAL_CD "08018188-42cd-bb48-100f-5387d53ded3d" + +/* Miscellaneous */ + +#define UUID_PLATFORM_CAPABILITIES "0811b06e-4a27-44f9-8d60-3cbbc22e7b48" +#define UUID_DYNAMIC_ENUMERATION "d8c1a3a6-be9b-4c9b-91bf-c3cb81fc5daf" +#define UUID_BATTERY_THERMAL_LIMIT "4c2067e3-887d-475c-9720-4af1d3ed602e" +#define UUID_THERMAL_EXTENSIONS "14d399cd-7a27-4b18-8fb4-7cb7b9f4e500" +#define UUID_DEVICE_PROPERTIES "daffd814-6eba-4d8c-8a91-bc9bbf4aa301" + + +#endif /* __AUUID_H__ */ diff --git a/third_party/lib/acpica/source/include/amlcode.h b/third_party/lib/acpica/source/include/amlcode.h new file mode 100644 index 000000000..a432c2b7d --- /dev/null +++ b/third_party/lib/acpica/source/include/amlcode.h @@ -0,0 +1,514 @@ +/****************************************************************************** + * + * Name: amlcode.h - Definitions for AML, as included in "definition blocks" + * Declarations and definitions contained herein are derived + * directly from the ACPI specification. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __AMLCODE_H__ +#define __AMLCODE_H__ + +/* primary opcodes */ + +#define AML_NULL_CHAR (UINT16) 0x00 + +#define AML_ZERO_OP (UINT16) 0x00 +#define AML_ONE_OP (UINT16) 0x01 +#define AML_UNASSIGNED (UINT16) 0x02 +#define AML_ALIAS_OP (UINT16) 0x06 +#define AML_NAME_OP (UINT16) 0x08 +#define AML_BYTE_OP (UINT16) 0x0a +#define AML_WORD_OP (UINT16) 0x0b +#define AML_DWORD_OP (UINT16) 0x0c +#define AML_STRING_OP (UINT16) 0x0d +#define AML_QWORD_OP (UINT16) 0x0e /* ACPI 2.0 */ +#define AML_SCOPE_OP (UINT16) 0x10 +#define AML_BUFFER_OP (UINT16) 0x11 +#define AML_PACKAGE_OP (UINT16) 0x12 +#define AML_VAR_PACKAGE_OP (UINT16) 0x13 /* ACPI 2.0 */ +#define AML_METHOD_OP (UINT16) 0x14 +#define AML_EXTERNAL_OP (UINT16) 0x15 /* ACPI 6.0 */ +#define AML_DUAL_NAME_PREFIX (UINT16) 0x2e +#define AML_MULTI_NAME_PREFIX_OP (UINT16) 0x2f +#define AML_NAME_CHAR_SUBSEQ (UINT16) 0x30 +#define AML_NAME_CHAR_FIRST (UINT16) 0x41 +#define AML_EXTENDED_OP_PREFIX (UINT16) 0x5b +#define AML_ROOT_PREFIX (UINT16) 0x5c +#define AML_PARENT_PREFIX (UINT16) 0x5e +#define AML_LOCAL_OP (UINT16) 0x60 +#define AML_LOCAL0 (UINT16) 0x60 +#define AML_LOCAL1 (UINT16) 0x61 +#define AML_LOCAL2 (UINT16) 0x62 +#define AML_LOCAL3 (UINT16) 0x63 +#define AML_LOCAL4 (UINT16) 0x64 +#define AML_LOCAL5 (UINT16) 0x65 +#define AML_LOCAL6 (UINT16) 0x66 +#define AML_LOCAL7 (UINT16) 0x67 +#define AML_ARG_OP (UINT16) 0x68 +#define AML_ARG0 (UINT16) 0x68 +#define AML_ARG1 (UINT16) 0x69 +#define AML_ARG2 (UINT16) 0x6a +#define AML_ARG3 (UINT16) 0x6b +#define AML_ARG4 (UINT16) 0x6c +#define AML_ARG5 (UINT16) 0x6d +#define AML_ARG6 (UINT16) 0x6e +#define AML_STORE_OP (UINT16) 0x70 +#define AML_REF_OF_OP (UINT16) 0x71 +#define AML_ADD_OP (UINT16) 0x72 +#define AML_CONCAT_OP (UINT16) 0x73 +#define AML_SUBTRACT_OP (UINT16) 0x74 +#define AML_INCREMENT_OP (UINT16) 0x75 +#define AML_DECREMENT_OP (UINT16) 0x76 +#define AML_MULTIPLY_OP (UINT16) 0x77 +#define AML_DIVIDE_OP (UINT16) 0x78 +#define AML_SHIFT_LEFT_OP (UINT16) 0x79 +#define AML_SHIFT_RIGHT_OP (UINT16) 0x7a +#define AML_BIT_AND_OP (UINT16) 0x7b +#define AML_BIT_NAND_OP (UINT16) 0x7c +#define AML_BIT_OR_OP (UINT16) 0x7d +#define AML_BIT_NOR_OP (UINT16) 0x7e +#define AML_BIT_XOR_OP (UINT16) 0x7f +#define AML_BIT_NOT_OP (UINT16) 0x80 +#define AML_FIND_SET_LEFT_BIT_OP (UINT16) 0x81 +#define AML_FIND_SET_RIGHT_BIT_OP (UINT16) 0x82 +#define AML_DEREF_OF_OP (UINT16) 0x83 +#define AML_CONCAT_RES_OP (UINT16) 0x84 /* ACPI 2.0 */ +#define AML_MOD_OP (UINT16) 0x85 /* ACPI 2.0 */ +#define AML_NOTIFY_OP (UINT16) 0x86 +#define AML_SIZE_OF_OP (UINT16) 0x87 +#define AML_INDEX_OP (UINT16) 0x88 +#define AML_MATCH_OP (UINT16) 0x89 +#define AML_CREATE_DWORD_FIELD_OP (UINT16) 0x8a +#define AML_CREATE_WORD_FIELD_OP (UINT16) 0x8b +#define AML_CREATE_BYTE_FIELD_OP (UINT16) 0x8c +#define AML_CREATE_BIT_FIELD_OP (UINT16) 0x8d +#define AML_OBJECT_TYPE_OP (UINT16) 0x8e +#define AML_CREATE_QWORD_FIELD_OP (UINT16) 0x8f /* ACPI 2.0 */ +#define AML_LAND_OP (UINT16) 0x90 +#define AML_LOR_OP (UINT16) 0x91 +#define AML_LNOT_OP (UINT16) 0x92 +#define AML_LEQUAL_OP (UINT16) 0x93 +#define AML_LGREATER_OP (UINT16) 0x94 +#define AML_LLESS_OP (UINT16) 0x95 +#define AML_TO_BUFFER_OP (UINT16) 0x96 /* ACPI 2.0 */ +#define AML_TO_DECSTRING_OP (UINT16) 0x97 /* ACPI 2.0 */ +#define AML_TO_HEXSTRING_OP (UINT16) 0x98 /* ACPI 2.0 */ +#define AML_TO_INTEGER_OP (UINT16) 0x99 /* ACPI 2.0 */ +#define AML_TO_STRING_OP (UINT16) 0x9c /* ACPI 2.0 */ +#define AML_COPY_OP (UINT16) 0x9d /* ACPI 2.0 */ +#define AML_MID_OP (UINT16) 0x9e /* ACPI 2.0 */ +#define AML_CONTINUE_OP (UINT16) 0x9f /* ACPI 2.0 */ +#define AML_IF_OP (UINT16) 0xa0 +#define AML_ELSE_OP (UINT16) 0xa1 +#define AML_WHILE_OP (UINT16) 0xa2 +#define AML_NOOP_OP (UINT16) 0xa3 +#define AML_RETURN_OP (UINT16) 0xa4 +#define AML_BREAK_OP (UINT16) 0xa5 +#define AML_BREAK_POINT_OP (UINT16) 0xcc +#define AML_ONES_OP (UINT16) 0xff + +/* prefixed opcodes */ + +#define AML_EXTENDED_OPCODE (UINT16) 0x5b00 /* prefix for 2-byte opcodes */ + +#define AML_MUTEX_OP (UINT16) 0x5b01 +#define AML_EVENT_OP (UINT16) 0x5b02 +#define AML_SHIFT_RIGHT_BIT_OP (UINT16) 0x5b10 +#define AML_SHIFT_LEFT_BIT_OP (UINT16) 0x5b11 +#define AML_COND_REF_OF_OP (UINT16) 0x5b12 +#define AML_CREATE_FIELD_OP (UINT16) 0x5b13 +#define AML_LOAD_TABLE_OP (UINT16) 0x5b1f /* ACPI 2.0 */ +#define AML_LOAD_OP (UINT16) 0x5b20 +#define AML_STALL_OP (UINT16) 0x5b21 +#define AML_SLEEP_OP (UINT16) 0x5b22 +#define AML_ACQUIRE_OP (UINT16) 0x5b23 +#define AML_SIGNAL_OP (UINT16) 0x5b24 +#define AML_WAIT_OP (UINT16) 0x5b25 +#define AML_RESET_OP (UINT16) 0x5b26 +#define AML_RELEASE_OP (UINT16) 0x5b27 +#define AML_FROM_BCD_OP (UINT16) 0x5b28 +#define AML_TO_BCD_OP (UINT16) 0x5b29 +#define AML_UNLOAD_OP (UINT16) 0x5b2a +#define AML_REVISION_OP (UINT16) 0x5b30 +#define AML_DEBUG_OP (UINT16) 0x5b31 +#define AML_FATAL_OP (UINT16) 0x5b32 +#define AML_TIMER_OP (UINT16) 0x5b33 /* ACPI 3.0 */ +#define AML_REGION_OP (UINT16) 0x5b80 +#define AML_FIELD_OP (UINT16) 0x5b81 +#define AML_DEVICE_OP (UINT16) 0x5b82 +#define AML_PROCESSOR_OP (UINT16) 0x5b83 +#define AML_POWER_RES_OP (UINT16) 0x5b84 +#define AML_THERMAL_ZONE_OP (UINT16) 0x5b85 +#define AML_INDEX_FIELD_OP (UINT16) 0x5b86 +#define AML_BANK_FIELD_OP (UINT16) 0x5b87 +#define AML_DATA_REGION_OP (UINT16) 0x5b88 /* ACPI 2.0 */ + + +/* + * Combination opcodes (actually two one-byte opcodes) + * Used by the disassembler and iASL compiler + */ +#define AML_LGREATEREQUAL_OP (UINT16) 0x9295 +#define AML_LLESSEQUAL_OP (UINT16) 0x9294 +#define AML_LNOTEQUAL_OP (UINT16) 0x9293 + + +/* + * Opcodes for "Field" operators + */ +#define AML_FIELD_OFFSET_OP (UINT8) 0x00 +#define AML_FIELD_ACCESS_OP (UINT8) 0x01 +#define AML_FIELD_CONNECTION_OP (UINT8) 0x02 /* ACPI 5.0 */ +#define AML_FIELD_EXT_ACCESS_OP (UINT8) 0x03 /* ACPI 5.0 */ + + +/* + * Internal opcodes + * Use only "Unknown" AML opcodes, don't attempt to use + * any valid ACPI ASCII values (A-Z, 0-9, '-') + */ +#define AML_INT_NAMEPATH_OP (UINT16) 0x002d +#define AML_INT_NAMEDFIELD_OP (UINT16) 0x0030 +#define AML_INT_RESERVEDFIELD_OP (UINT16) 0x0031 +#define AML_INT_ACCESSFIELD_OP (UINT16) 0x0032 +#define AML_INT_BYTELIST_OP (UINT16) 0x0033 +#define AML_INT_METHODCALL_OP (UINT16) 0x0035 +#define AML_INT_RETURN_VALUE_OP (UINT16) 0x0036 +#define AML_INT_EVAL_SUBTREE_OP (UINT16) 0x0037 +#define AML_INT_CONNECTION_OP (UINT16) 0x0038 +#define AML_INT_EXTACCESSFIELD_OP (UINT16) 0x0039 + +#define ARG_NONE 0x0 + +/* + * Argument types for the AML Parser + * Each field in the ArgTypes UINT32 is 5 bits, allowing for a maximum of 6 arguments. + * There can be up to 31 unique argument types + * Zero is reserved as end-of-list indicator + */ +#define ARGP_BYTEDATA 0x01 +#define ARGP_BYTELIST 0x02 +#define ARGP_CHARLIST 0x03 +#define ARGP_DATAOBJ 0x04 +#define ARGP_DATAOBJLIST 0x05 +#define ARGP_DWORDDATA 0x06 +#define ARGP_FIELDLIST 0x07 +#define ARGP_NAME 0x08 +#define ARGP_NAMESTRING 0x09 +#define ARGP_OBJLIST 0x0A +#define ARGP_PKGLENGTH 0x0B +#define ARGP_SUPERNAME 0x0C +#define ARGP_TARGET 0x0D +#define ARGP_TERMARG 0x0E +#define ARGP_TERMLIST 0x0F +#define ARGP_WORDDATA 0x10 +#define ARGP_QWORDDATA 0x11 +#define ARGP_SIMPLENAME 0x12 /* NameString | LocalTerm | ArgTerm */ +#define ARGP_NAME_OR_REF 0x13 /* For ObjectType only */ + +/* + * Resolved argument types for the AML Interpreter + * Each field in the ArgTypes UINT32 is 5 bits, allowing for a maximum of 6 arguments. + * There can be up to 31 unique argument types (0 is end-of-arg-list indicator) + * + * Note1: These values are completely independent from the ACPI_TYPEs + * i.e., ARGI_INTEGER != ACPI_TYPE_INTEGER + * + * Note2: If and when 5 bits becomes insufficient, it would probably be best + * to convert to a 6-byte array of argument types, allowing 8 bits per argument. + */ + +/* Single, simple types */ + +#define ARGI_ANYTYPE 0x01 /* Don't care */ +#define ARGI_PACKAGE 0x02 +#define ARGI_EVENT 0x03 +#define ARGI_MUTEX 0x04 +#define ARGI_DDBHANDLE 0x05 + +/* Interchangeable types (via implicit conversion) */ + +#define ARGI_INTEGER 0x06 +#define ARGI_STRING 0x07 +#define ARGI_BUFFER 0x08 +#define ARGI_BUFFER_OR_STRING 0x09 /* Used by MID op only */ +#define ARGI_COMPUTEDATA 0x0A /* Buffer, String, or Integer */ + +/* Reference objects */ + +#define ARGI_INTEGER_REF 0x0B +#define ARGI_OBJECT_REF 0x0C +#define ARGI_DEVICE_REF 0x0D +#define ARGI_REFERENCE 0x0E +#define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */ +#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */ +#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */ +#define ARGI_STORE_TARGET 0x12 /* Target for store is TARGETREF + package objects */ + +/* Multiple/complex types */ + +#define ARGI_DATAOBJECT 0x13 /* Buffer, String, package or reference to a Node - Used only by SizeOf operator*/ +#define ARGI_COMPLEXOBJ 0x14 /* Buffer, String, or package (Used by INDEX op only) */ +#define ARGI_REF_OR_STRING 0x15 /* Reference or String (Used by DEREFOF op only) */ +#define ARGI_REGION_OR_BUFFER 0x16 /* Used by LOAD op only */ +#define ARGI_DATAREFOBJ 0x17 + +/* Note: types above can expand to 0x1F maximum */ + +#define ARGI_INVALID_OPCODE 0xFFFFFFFF + + +/* + * hash offsets + */ +#define AML_EXTOP_HASH_OFFSET 22 +#define AML_LNOT_HASH_OFFSET 19 + + +/* + * opcode groups and types + */ +#define OPGRP_NAMED 0x01 +#define OPGRP_FIELD 0x02 +#define OPGRP_BYTELIST 0x04 + + +/* + * Opcode information + */ + +/* Opcode flags */ + +#define AML_LOGICAL 0x0001 +#define AML_LOGICAL_NUMERIC 0x0002 +#define AML_MATH 0x0004 +#define AML_CREATE 0x0008 +#define AML_FIELD 0x0010 +#define AML_DEFER 0x0020 +#define AML_NAMED 0x0040 +#define AML_NSNODE 0x0080 +#define AML_NSOPCODE 0x0100 +#define AML_NSOBJECT 0x0200 +#define AML_HAS_RETVAL 0x0400 +#define AML_HAS_TARGET 0x0800 +#define AML_HAS_ARGS 0x1000 +#define AML_CONSTANT 0x2000 +#define AML_NO_OPERAND_RESOLVE 0x4000 + +/* Convenient flag groupings */ + +#define AML_FLAGS_EXEC_0A_0T_1R AML_HAS_RETVAL +#define AML_FLAGS_EXEC_1A_0T_0R AML_HAS_ARGS /* Monadic1 */ +#define AML_FLAGS_EXEC_1A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Monadic2 */ +#define AML_FLAGS_EXEC_1A_1T_0R AML_HAS_ARGS | AML_HAS_TARGET +#define AML_FLAGS_EXEC_1A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* Monadic2R */ +#define AML_FLAGS_EXEC_2A_0T_0R AML_HAS_ARGS /* Dyadic1 */ +#define AML_FLAGS_EXEC_2A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Dyadic2 */ +#define AML_FLAGS_EXEC_2A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* Dyadic2R */ +#define AML_FLAGS_EXEC_2A_2T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL +#define AML_FLAGS_EXEC_3A_0T_0R AML_HAS_ARGS +#define AML_FLAGS_EXEC_3A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL +#define AML_FLAGS_EXEC_6A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL + + +/* + * The opcode Type is used in a dispatch table, do not change + * without updating the table. + */ +#define AML_TYPE_EXEC_0A_0T_1R 0x00 +#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */ +#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* Monadic2 */ +#define AML_TYPE_EXEC_1A_1T_0R 0x03 +#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* Monadic2R */ +#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* Dyadic1 */ +#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* Dyadic2 */ +#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* Dyadic2R */ +#define AML_TYPE_EXEC_2A_2T_1R 0x08 +#define AML_TYPE_EXEC_3A_0T_0R 0x09 +#define AML_TYPE_EXEC_3A_1T_1R 0x0A +#define AML_TYPE_EXEC_6A_0T_1R 0x0B +/* End of types used in dispatch table */ + +#define AML_TYPE_LITERAL 0x0B +#define AML_TYPE_CONSTANT 0x0C +#define AML_TYPE_METHOD_ARGUMENT 0x0D +#define AML_TYPE_LOCAL_VARIABLE 0x0E +#define AML_TYPE_DATA_TERM 0x0F + +/* Generic for an op that returns a value */ + +#define AML_TYPE_METHOD_CALL 0x10 + +/* Misc */ + +#define AML_TYPE_CREATE_FIELD 0x11 +#define AML_TYPE_CREATE_OBJECT 0x12 +#define AML_TYPE_CONTROL 0x13 +#define AML_TYPE_NAMED_NO_OBJ 0x14 +#define AML_TYPE_NAMED_FIELD 0x15 +#define AML_TYPE_NAMED_SIMPLE 0x16 +#define AML_TYPE_NAMED_COMPLEX 0x17 +#define AML_TYPE_RETURN 0x18 + +#define AML_TYPE_UNDEFINED 0x19 +#define AML_TYPE_BOGUS 0x1A + +/* AML Package Length encodings */ + +#define ACPI_AML_PACKAGE_TYPE1 0x40 +#define ACPI_AML_PACKAGE_TYPE2 0x4000 +#define ACPI_AML_PACKAGE_TYPE3 0x400000 +#define ACPI_AML_PACKAGE_TYPE4 0x40000000 + +/* + * Opcode classes + */ +#define AML_CLASS_EXECUTE 0x00 +#define AML_CLASS_CREATE 0x01 +#define AML_CLASS_ARGUMENT 0x02 +#define AML_CLASS_NAMED_OBJECT 0x03 +#define AML_CLASS_CONTROL 0x04 +#define AML_CLASS_ASCII 0x05 +#define AML_CLASS_PREFIX 0x06 +#define AML_CLASS_INTERNAL 0x07 +#define AML_CLASS_RETURN_VALUE 0x08 +#define AML_CLASS_METHOD_CALL 0x09 +#define AML_CLASS_UNKNOWN 0x0A + + +/* Comparison operation codes for MatchOp operator */ + +typedef enum +{ + MATCH_MTR = 0, + MATCH_MEQ = 1, + MATCH_MLE = 2, + MATCH_MLT = 3, + MATCH_MGE = 4, + MATCH_MGT = 5 + +} AML_MATCH_OPERATOR; + +#define MAX_MATCH_OPERATOR 5 + + +/* + * FieldFlags + * + * This byte is extracted from the AML and includes three separate + * pieces of information about the field: + * 1) The field access type + * 2) The field update rule + * 3) The lock rule for the field + * + * Bits 00 - 03 : AccessType (AnyAcc, ByteAcc, etc.) + * 04 : LockRule (1 == Lock) + * 05 - 06 : UpdateRule + */ +#define AML_FIELD_ACCESS_TYPE_MASK 0x0F +#define AML_FIELD_LOCK_RULE_MASK 0x10 +#define AML_FIELD_UPDATE_RULE_MASK 0x60 + + +/* 1) Field Access Types */ + +typedef enum +{ + AML_FIELD_ACCESS_ANY = 0x00, + AML_FIELD_ACCESS_BYTE = 0x01, + AML_FIELD_ACCESS_WORD = 0x02, + AML_FIELD_ACCESS_DWORD = 0x03, + AML_FIELD_ACCESS_QWORD = 0x04, /* ACPI 2.0 */ + AML_FIELD_ACCESS_BUFFER = 0x05 /* ACPI 2.0 */ + +} AML_ACCESS_TYPE; + + +/* 2) Field Lock Rules */ + +typedef enum +{ + AML_FIELD_LOCK_NEVER = 0x00, + AML_FIELD_LOCK_ALWAYS = 0x10 + +} AML_LOCK_RULE; + + +/* 3) Field Update Rules */ + +typedef enum +{ + AML_FIELD_UPDATE_PRESERVE = 0x00, + AML_FIELD_UPDATE_WRITE_AS_ONES = 0x20, + AML_FIELD_UPDATE_WRITE_AS_ZEROS = 0x40 + +} AML_UPDATE_RULE; + + +/* + * Field Access Attributes. + * This byte is extracted from the AML via the + * AccessAs keyword + */ +typedef enum +{ + AML_FIELD_ATTRIB_QUICK = 0x02, + AML_FIELD_ATTRIB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_BYTE = 0x06, + AML_FIELD_ATTRIB_WORD = 0x08, + AML_FIELD_ATTRIB_BLOCK = 0x0A, + AML_FIELD_ATTRIB_MULTIBYTE = 0x0B, + AML_FIELD_ATTRIB_WORD_CALL = 0x0C, + AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D, + AML_FIELD_ATTRIB_RAW_BYTES = 0x0E, + AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F + +} AML_ACCESS_ATTRIBUTE; + + +/* Bit fields in the AML MethodFlags byte */ + +#define AML_METHOD_ARG_COUNT 0x07 +#define AML_METHOD_SERIALIZED 0x08 +#define AML_METHOD_SYNC_LEVEL 0xF0 + + +#endif /* __AMLCODE_H__ */ diff --git a/third_party/lib/acpica/source/include/amlresrc.h b/third_party/lib/acpica/source/include/amlresrc.h new file mode 100644 index 000000000..960da1b31 --- /dev/null +++ b/third_party/lib/acpica/source/include/amlresrc.h @@ -0,0 +1,631 @@ +/****************************************************************************** + * + * Module Name: amlresrc.h - AML resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* acpisrc:StructDefs -- for acpisrc conversion */ + +#ifndef __AMLRESRC_H +#define __AMLRESRC_H + + +/* + * Resource descriptor tags, as defined in the ACPI specification. + * Used to symbolically reference fields within a descriptor. + */ +#define ACPI_RESTAG_ADDRESS "_ADR" +#define ACPI_RESTAG_ALIGNMENT "_ALN" +#define ACPI_RESTAG_ADDRESSSPACE "_ASI" +#define ACPI_RESTAG_ACCESSSIZE "_ASZ" +#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" +#define ACPI_RESTAG_BASEADDRESS "_BAS" +#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ +#define ACPI_RESTAG_DEBOUNCETIME "_DBT" +#define ACPI_RESTAG_DECODE "_DEC" +#define ACPI_RESTAG_DEVICEPOLARITY "_DPL" +#define ACPI_RESTAG_DMA "_DMA" +#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ +#define ACPI_RESTAG_DRIVESTRENGTH "_DRS" +#define ACPI_RESTAG_ENDIANNESS "_END" +#define ACPI_RESTAG_FLOWCONTROL "_FLC" +#define ACPI_RESTAG_GRANULARITY "_GRA" +#define ACPI_RESTAG_INTERRUPT "_INT" +#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* ActiveLo(1), ActiveHi(0) */ +#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), NoShare(0) */ +#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ +#define ACPI_RESTAG_IORESTRICTION "_IOR" +#define ACPI_RESTAG_LENGTH "_LEN" +#define ACPI_RESTAG_LINE "_LIN" +#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ +#define ACPI_RESTAG_MEMTYPE "_MEM" /* NonCache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ +#define ACPI_RESTAG_MAXADDR "_MAX" +#define ACPI_RESTAG_MINADDR "_MIN" +#define ACPI_RESTAG_MAXTYPE "_MAF" +#define ACPI_RESTAG_MINTYPE "_MIF" +#define ACPI_RESTAG_MODE "_MOD" +#define ACPI_RESTAG_PARITY "_PAR" +#define ACPI_RESTAG_PHASE "_PHA" +#define ACPI_RESTAG_PIN "_PIN" +#define ACPI_RESTAG_PINCONFIG "_PPI" +#define ACPI_RESTAG_POLARITY "_POL" +#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" +#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" +#define ACPI_RESTAG_RANGETYPE "_RNG" +#define ACPI_RESTAG_READWRITETYPE "_RW_" /* ReadOnly(0), Writeable (1) */ +#define ACPI_RESTAG_LENGTH_RX "_RXL" +#define ACPI_RESTAG_LENGTH_TX "_TXL" +#define ACPI_RESTAG_SLAVEMODE "_SLV" +#define ACPI_RESTAG_SPEED "_SPE" +#define ACPI_RESTAG_STOPBITS "_STB" +#define ACPI_RESTAG_TRANSLATION "_TRA" +#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ +#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ +#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8And16(1), 16(2) */ +#define ACPI_RESTAG_VENDORDATA "_VEN" + + +/* Default sizes for "small" resource descriptors */ + +#define ASL_RDESC_IRQ_SIZE 0x02 +#define ASL_RDESC_DMA_SIZE 0x02 +#define ASL_RDESC_ST_DEPEND_SIZE 0x00 +#define ASL_RDESC_END_DEPEND_SIZE 0x00 +#define ASL_RDESC_IO_SIZE 0x07 +#define ASL_RDESC_FIXED_IO_SIZE 0x03 +#define ASL_RDESC_FIXED_DMA_SIZE 0x05 +#define ASL_RDESC_END_TAG_SIZE 0x01 + + +typedef struct asl_resource_node +{ + UINT32 BufferLength; + void *Buffer; + struct asl_resource_node *Next; + +} ASL_RESOURCE_NODE; + +typedef struct asl_resource_info +{ + ACPI_PARSE_OBJECT *DescriptorTypeOp; /* Resource descriptor parse node */ + ACPI_PARSE_OBJECT *MappingOp; /* Used for mapfile support */ + UINT32 CurrentByteOffset; /* Offset in resource template */ + +} ASL_RESOURCE_INFO; + + +/* Macros used to generate AML resource length fields */ + +#define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (AML_RESOURCE_LARGE_HEADER)) +#define ACPI_AML_SIZE_SMALL(r) (sizeof (r) - sizeof (AML_RESOURCE_SMALL_HEADER)) + +/* + * Resource descriptors defined in the ACPI specification. + * + * Packing/alignment must be BYTE because these descriptors + * are used to overlay the raw AML byte stream. + */ +#pragma pack(1) + +/* + * SMALL descriptors + */ +#define AML_RESOURCE_SMALL_HEADER_COMMON \ + UINT8 DescriptorType; + +typedef struct aml_resource_small_header +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_SMALL_HEADER; + + +typedef struct aml_resource_irq +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 IrqMask; + UINT8 Flags; + +} AML_RESOURCE_IRQ; + + +typedef struct aml_resource_irq_noflags +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 IrqMask; + +} AML_RESOURCE_IRQ_NOFLAGS; + + +typedef struct aml_resource_dma +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 DmaChannelMask; + UINT8 Flags; + +} AML_RESOURCE_DMA; + + +typedef struct aml_resource_start_dependent +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 Flags; + +} AML_RESOURCE_START_DEPENDENT; + + +typedef struct aml_resource_start_dependent_noprio +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_START_DEPENDENT_NOPRIO; + + +typedef struct aml_resource_end_dependent +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_END_DEPENDENT; + + +typedef struct aml_resource_io +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 Flags; + UINT16 Minimum; + UINT16 Maximum; + UINT8 Alignment; + UINT8 AddressLength; + +} AML_RESOURCE_IO; + + +typedef struct aml_resource_fixed_io +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 Address; + UINT8 AddressLength; + +} AML_RESOURCE_FIXED_IO; + + +typedef struct aml_resource_vendor_small +{ + AML_RESOURCE_SMALL_HEADER_COMMON + +} AML_RESOURCE_VENDOR_SMALL; + + +typedef struct aml_resource_end_tag +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT8 Checksum; + +} AML_RESOURCE_END_TAG; + + +typedef struct aml_resource_fixed_dma +{ + AML_RESOURCE_SMALL_HEADER_COMMON + UINT16 RequestLines; + UINT16 Channels; + UINT8 Width; + +} AML_RESOURCE_FIXED_DMA; + + +/* + * LARGE descriptors + */ +#define AML_RESOURCE_LARGE_HEADER_COMMON \ + UINT8 DescriptorType;\ + UINT16 ResourceLength; + +typedef struct aml_resource_large_header +{ + AML_RESOURCE_LARGE_HEADER_COMMON + +} AML_RESOURCE_LARGE_HEADER; + + +/* General Flags for address space resource descriptors */ + +#define ACPI_RESOURCE_FLAG_DEC 2 +#define ACPI_RESOURCE_FLAG_MIF 4 +#define ACPI_RESOURCE_FLAG_MAF 8 + +typedef struct aml_resource_memory24 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT16 Minimum; + UINT16 Maximum; + UINT16 Alignment; + UINT16 AddressLength; + +} AML_RESOURCE_MEMORY24; + + +typedef struct aml_resource_vendor_large +{ + AML_RESOURCE_LARGE_HEADER_COMMON + +} AML_RESOURCE_VENDOR_LARGE; + + +typedef struct aml_resource_memory32 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT32 Minimum; + UINT32 Maximum; + UINT32 Alignment; + UINT32 AddressLength; + +} AML_RESOURCE_MEMORY32; + + +typedef struct aml_resource_fixed_memory32 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT32 Address; + UINT32 AddressLength; + +} AML_RESOURCE_FIXED_MEMORY32; + + +#define AML_RESOURCE_ADDRESS_COMMON \ + UINT8 ResourceType; \ + UINT8 Flags; \ + UINT8 SpecificFlags; + + +typedef struct aml_resource_address +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + +} AML_RESOURCE_ADDRESS; + + +typedef struct aml_resource_extended_address64 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT8 RevisionID; + UINT8 Reserved; + UINT64 Granularity; + UINT64 Minimum; + UINT64 Maximum; + UINT64 TranslationOffset; + UINT64 AddressLength; + UINT64 TypeSpecific; + +} AML_RESOURCE_EXTENDED_ADDRESS64; + +#define AML_RESOURCE_EXTENDED_ADDRESS_REVISION 1 /* ACPI 3.0 */ + + +typedef struct aml_resource_address64 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT64 Granularity; + UINT64 Minimum; + UINT64 Maximum; + UINT64 TranslationOffset; + UINT64 AddressLength; + +} AML_RESOURCE_ADDRESS64; + + +typedef struct aml_resource_address32 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT32 Granularity; + UINT32 Minimum; + UINT32 Maximum; + UINT32 TranslationOffset; + UINT32 AddressLength; + +} AML_RESOURCE_ADDRESS32; + + +typedef struct aml_resource_address16 +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON + UINT16 Granularity; + UINT16 Minimum; + UINT16 Maximum; + UINT16 TranslationOffset; + UINT16 AddressLength; + +} AML_RESOURCE_ADDRESS16; + + +typedef struct aml_resource_extended_irq +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 Flags; + UINT8 InterruptCount; + UINT32 Interrupts[1]; + /* ResSourceIndex, ResSource optional fields follow */ + +} AML_RESOURCE_EXTENDED_IRQ; + + +typedef struct aml_resource_generic_register +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 AddressSpaceId; + UINT8 BitWidth; + UINT8 BitOffset; + UINT8 AccessSize; /* ACPI 3.0, was previously Reserved */ + UINT64 Address; + +} AML_RESOURCE_GENERIC_REGISTER; + + +/* Common descriptor for GpioInt and GpioIo (ACPI 5.0) */ + +typedef struct aml_resource_gpio +{ + AML_RESOURCE_LARGE_HEADER_COMMON + UINT8 RevisionId; + UINT8 ConnectionType; + UINT16 Flags; + UINT16 IntFlags; + UINT8 PinConfig; + UINT16 DriveStrength; + UINT16 DebounceTimeout; + UINT16 PinTableOffset; + UINT8 ResSourceIndex; + UINT16 ResSourceOffset; + UINT16 VendorOffset; + UINT16 VendorLength; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ + +} AML_RESOURCE_GPIO; + +#define AML_RESOURCE_GPIO_REVISION 1 /* ACPI 5.0 */ + +/* Values for ConnectionType above */ + +#define AML_RESOURCE_GPIO_TYPE_INT 0 +#define AML_RESOURCE_GPIO_TYPE_IO 1 +#define AML_RESOURCE_MAX_GPIOTYPE 1 + + +/* Common preamble for all serial descriptors (ACPI 5.0) */ + +#define AML_RESOURCE_SERIAL_COMMON \ + UINT8 RevisionId; \ + UINT8 ResSourceIndex; \ + UINT8 Type; \ + UINT8 Flags; \ + UINT16 TypeSpecificFlags; \ + UINT8 TypeRevisionId; \ + UINT16 TypeDataLength; \ + +/* Values for the type field above */ + +#define AML_RESOURCE_I2C_SERIALBUSTYPE 1 +#define AML_RESOURCE_SPI_SERIALBUSTYPE 2 +#define AML_RESOURCE_UART_SERIALBUSTYPE 3 +#define AML_RESOURCE_MAX_SERIALBUSTYPE 3 +#define AML_RESOURCE_VENDOR_SERIALBUSTYPE 192 /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */ + +typedef struct aml_resource_common_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + +} AML_RESOURCE_COMMON_SERIALBUS; + +typedef struct aml_resource_i2c_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + UINT32 ConnectionSpeed; + UINT16 SlaveAddress; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ + +} AML_RESOURCE_I2C_SERIALBUS; + +#define AML_RESOURCE_I2C_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_MIN_DATA_LEN 6 + +typedef struct aml_resource_spi_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + UINT32 ConnectionSpeed; + UINT8 DataBitLength; + UINT8 ClockPhase; + UINT8 ClockPolarity; + UINT16 DeviceSelection; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ + +} AML_RESOURCE_SPI_SERIALBUS; + +#define AML_RESOURCE_SPI_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_MIN_DATA_LEN 9 + + +typedef struct aml_resource_uart_serialbus +{ + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON + UINT32 DefaultBaudRate; + UINT16 RxFifoSize; + UINT16 TxFifoSize; + UINT8 Parity; + UINT8 LinesEnabled; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ + +} AML_RESOURCE_UART_SERIALBUS; + +#define AML_RESOURCE_UART_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_MIN_DATA_LEN 10 + + +/* restore default alignment */ + +#pragma pack() + +/* Union of all resource descriptors, so we can allocate the worst case */ + +typedef union aml_resource +{ + /* Descriptor headers */ + + UINT8 DescriptorType; + AML_RESOURCE_SMALL_HEADER SmallHeader; + AML_RESOURCE_LARGE_HEADER LargeHeader; + + /* Small resource descriptors */ + + AML_RESOURCE_IRQ Irq; + AML_RESOURCE_DMA Dma; + AML_RESOURCE_START_DEPENDENT StartDpf; + AML_RESOURCE_END_DEPENDENT EndDpf; + AML_RESOURCE_IO Io; + AML_RESOURCE_FIXED_IO FixedIo; + AML_RESOURCE_FIXED_DMA FixedDma; + AML_RESOURCE_VENDOR_SMALL VendorSmall; + AML_RESOURCE_END_TAG EndTag; + + /* Large resource descriptors */ + + AML_RESOURCE_MEMORY24 Memory24; + AML_RESOURCE_GENERIC_REGISTER GenericReg; + AML_RESOURCE_VENDOR_LARGE VendorLarge; + AML_RESOURCE_MEMORY32 Memory32; + AML_RESOURCE_FIXED_MEMORY32 FixedMemory32; + AML_RESOURCE_ADDRESS16 Address16; + AML_RESOURCE_ADDRESS32 Address32; + AML_RESOURCE_ADDRESS64 Address64; + AML_RESOURCE_EXTENDED_ADDRESS64 ExtAddress64; + AML_RESOURCE_EXTENDED_IRQ ExtendedIrq; + AML_RESOURCE_GPIO Gpio; + AML_RESOURCE_I2C_SERIALBUS I2cSerialBus; + AML_RESOURCE_SPI_SERIALBUS SpiSerialBus; + AML_RESOURCE_UART_SERIALBUS UartSerialBus; + AML_RESOURCE_COMMON_SERIALBUS CommonSerialBus; + + /* Utility overlays */ + + AML_RESOURCE_ADDRESS Address; + UINT32 DwordItem; + UINT16 WordItem; + UINT8 ByteItem; + +} AML_RESOURCE; + + +/* Interfaces used by both the disassembler and compiler */ + +void +MpSaveGpioInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + UINT32 PinCount, + UINT16 *PinList, + char *DeviceName); + +void +MpSaveSerialInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + char *DeviceName); + +char * +MpGetHidFromParseTree ( + ACPI_NAMESPACE_NODE *HidNode); + +char * +MpGetHidViaNamestring ( + char *DeviceName); + +char * +MpGetConnectionInfo ( + ACPI_PARSE_OBJECT *Op, + UINT32 PinIndex, + ACPI_NAMESPACE_NODE **TargetNode, + char **TargetName); + +char * +MpGetParentDeviceHid ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAMESPACE_NODE **TargetNode, + char **ParentDeviceName); + +char * +MpGetDdnValue ( + char *DeviceName); + +char * +MpGetHidValue ( + ACPI_NAMESPACE_NODE *DeviceNode); + +#endif diff --git a/third_party/lib/acpica/source/include/platform/accygwin.h b/third_party/lib/acpica/source/include/platform/accygwin.h new file mode 100644 index 000000000..518fc27d6 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/accygwin.h @@ -0,0 +1,105 @@ +/****************************************************************************** + * + * Name: accygwin.h - OS specific defines, etc. for cygwin environment + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACCYGWIN_H__ +#define __ACCYGWIN_H__ + +/* + * ACPICA configuration + */ +#define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_USE_DO_WHILE_0 +#define ACPI_FLUSH_CPU_CACHE() + +/* + * This is needed since sem_timedwait does not appear to work properly + * on cygwin (always hangs forever). + */ +#define ACPI_USE_ALTERNATE_TIMEOUT + + +#include +#include +#include +#include +#include + +#if defined(__ia64__) || defined(__x86_64__) +#define ACPI_MACHINE_WIDTH 64 +#define COMPILER_DEPENDENT_INT64 long +#define COMPILER_DEPENDENT_UINT64 unsigned long +#else +#define ACPI_MACHINE_WIDTH 32 +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long +#define ACPI_USE_NATIVE_DIVIDE +#endif + +#ifndef __cdecl +#define __cdecl +#endif + +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) if (GLptr) Acq=1; else Acq=0; +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Pending) Pending = 1 + +/* On Cygwin, pthread_t is a pointer */ + +#define ACPI_CAST_PTHREAD_T(pthread) ((ACPI_THREAD_ID) ACPI_TO_INTEGER (pthread)) + +/* Cygwin uses GCC */ + +#include "acgcc.h" + + +/* + * The vsnprintf/snprintf functions are defined by c99, but cygwin/gcc + * does not enable this prototype when the -ansi flag is set. Also related + * to __STRICT_ANSI__. So, we just declare the prototype here. + */ +int +vsnprintf (char *s, size_t n, const char *format, va_list ap); + +int +snprintf (char *s, size_t n, const char *format, ...); + +#endif /* __ACCYGWIN_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acdragonfly.h b/third_party/lib/acpica/source/include/platform/acdragonfly.h new file mode 100644 index 000000000..73a1867f7 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acdragonfly.h @@ -0,0 +1,128 @@ +/****************************************************************************** + * + * Name: acdragonfly.h - OS specific for DragonFly BSD + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACDRAGONFLY_H_ +#define __ACDRAGONFLY_H_ + +#include /* DragonFly uses GCC */ +#include + +#ifdef __LP64__ +#define ACPI_MACHINE_WIDTH 64 +#else +#define ACPI_MACHINE_WIDTH 32 +#define ACPI_USE_NATIVE_DIVIDE +#endif + +#define ACPI_UINTPTR_T uintptr_t +#define COMPILER_DEPENDENT_INT64 int64_t +#define COMPILER_DEPENDENT_UINT64 uint64_t + +#define ACPI_USE_DO_WHILE_0 +#define ACPI_USE_SYSTEM_CLIBRARY + +#ifdef _KERNEL + +#include "opt_acpi.h" +#include +#include +#include +#include + +#ifdef ACPI_DEBUG +#define ACPI_DEBUG_OUTPUT /* enable debug output */ +#ifdef DEBUGGER_THREADING +#undef DEBUGGER_THREADING +#endif /* DEBUGGER_THREADING */ +#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED /* integrated with DDB */ +#include "opt_ddb.h" +#ifdef DDB +#define ACPI_DEBUGGER +#endif /* DDB */ +#define ACPI_DISASSEMBLER +#endif + +#ifdef ACPI_DEBUG_CACHE +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReleaseObject +#define AcpiOsReleaseObject(Cache, Object) \ + _AcpiOsReleaseObject((Cache), (Object), __func__, __LINE__) +#endif + +#ifdef ACPI_DEBUG_LOCKS +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireLock +#define AcpiOsAcquireLock(Handle) \ + _AcpiOsAcquireLock((Handle), __func__, __LINE__) +#endif + +#ifdef ACPI_DEBUG_MEMMAP +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsMapMemory +#define AcpiOsMapMemory(Where, Length) \ + _AcpiOsMapMemory((Where), (Length), __func__, __LINE__) + +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsUnmapMemory +#define AcpiOsUnmapMemory(LogicalAddress, Size) \ + _AcpiOsUnmapMemory((LogicalAddress), (Size), __func__, __LINE__) +#endif + +/* XXX TBI */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitEventsComplete +#define AcpiOsWaitEventsComplete() + +#define USE_NATIVE_ALLOCATE_ZEROED + +#define ACPI_SPINLOCK struct acpi_spinlock * +struct acpi_spinlock; + +#define ACPI_CACHE_T struct acpicache +struct acpicache; + +#else /* _KERNEL */ + +#define ACPI_USE_STANDARD_HEADERS + +#define ACPI_CAST_PTHREAD_T(pthread) ((ACPI_THREAD_ID) ACPI_TO_INTEGER (pthread)) +#define ACPI_FLUSH_CPU_CACHE() + +#endif /* _KERNEL */ + +#endif /* __ACDRAGONFLY_H_ */ diff --git a/third_party/lib/acpica/source/include/platform/acdragonflyex.h b/third_party/lib/acpica/source/include/platform/acdragonflyex.h new file mode 100644 index 000000000..e1043448f --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acdragonflyex.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Name: acdragonflyex.h - Extra OS specific defines, etc. for DragonFly BSD + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACDRAGONFLYEX_H__ +#define __ACDRAGONFLYEX_H__ + +#ifdef _KERNEL + +#ifdef ACPI_DEBUG_CACHE +ACPI_STATUS +_AcpiOsReleaseObject ( + ACPI_CACHE_T *Cache, + void *Object, + const char *func, + int line); +#endif + +#ifdef ACPI_DEBUG_LOCKS +ACPI_CPU_FLAGS +_AcpiOsAcquireLock ( + ACPI_SPINLOCK Spin, + const char *func, + int line); +#endif + +#ifdef ACPI_DEBUG_MEMMAP +void * +_AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length, + const char *caller, + int line); + +void +_AcpiOsUnmapMemory ( + void *LogicalAddress, + ACPI_SIZE Length, + const char *caller, + int line); +#endif + +#endif /* _KERNEL */ + +#endif /* __ACDRAGONFLYEX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acefi.h b/third_party/lib/acpica/source/include/platform/acefi.h new file mode 100644 index 000000000..1a9e7c402 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acefi.h @@ -0,0 +1,275 @@ +/****************************************************************************** + * + * Name: acefi.h - OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACEFI_H__ +#define __ACEFI_H__ + +#include +#if defined(_GNU_EFI) +#include +#include +#endif + +#if defined(__x86_64__) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +#define USE_MS_ABI 1 +#endif +#endif + +#ifdef _MSC_EXTENSIONS +#define EFIAPI __cdecl +#elif USE_MS_ABI +#define EFIAPI __attribute__((ms_abi)) +#else +#define EFIAPI +#endif + +typedef uint8_t UINT8; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint8_t BOOLEAN; +typedef uint16_t CHAR16; + +#define VOID void + +#if defined(__ia64__) || defined(__x86_64__) + +#define ACPI_MACHINE_WIDTH 64 + +#if defined(__x86_64__) + +/* for x86_64, EFI_FUNCTION_WRAPPER must be defined */ + +#ifndef USE_MS_ABI +#define USE_EFI_FUNCTION_WRAPPER +#endif + +#ifdef _MSC_EXTENSIONS +#pragma warning ( disable : 4731 ) /* Suppress warnings about modification of EBP */ +#endif + +#endif + +typedef uint64_t UINTN; +typedef int64_t INTN; + +#define EFIERR(a) (0x8000000000000000 | a) + +#else + +#define ACPI_MACHINE_WIDTH 32 +#define ACPI_USE_NATIVE_DIVIDE + +typedef uint32_t UINTN; +typedef int32_t INTN; + +#define EFIERR(a) (0x80000000 | a) + +#endif + + +#ifdef USE_EFI_FUNCTION_WRAPPER +#define __VA_NARG__(...) \ + __VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) +#define __VA_NARG_(...) \ + __VA_ARG_N(__VA_ARGS__) +#define __VA_ARG_N( \ + _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N +#define __RSEQ_N() \ + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define __VA_ARG_NSUFFIX__(prefix,...) \ + __VA_ARG_NSUFFIX_N(prefix, __VA_NARG__(__VA_ARGS__)) +#define __VA_ARG_NSUFFIX_N(prefix,nargs) \ + __VA_ARG_NSUFFIX_N_(prefix, nargs) +#define __VA_ARG_NSUFFIX_N_(prefix,nargs) \ + prefix ## nargs + +/* Prototypes of EFI cdecl -> stdcall trampolines */ + +UINT64 efi_call0(void *func); +UINT64 efi_call1(void *func, UINT64 arg1); +UINT64 efi_call2(void *func, UINT64 arg1, UINT64 arg2); +UINT64 efi_call3(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3); +UINT64 efi_call4(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4); +UINT64 efi_call5(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4, UINT64 arg5); +UINT64 efi_call6(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4, UINT64 arg5, UINT64 arg6); +UINT64 efi_call7(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7); +UINT64 efi_call8(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7, + UINT64 arg8); +UINT64 efi_call9(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7, + UINT64 arg8, UINT64 arg9); +UINT64 efi_call10(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3, + UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7, + UINT64 arg8, UINT64 arg9, UINT64 arg10); + +/* Front-ends to efi_callX to avoid compiler warnings */ + +#define _cast64_efi_call0(f) \ + efi_call0(f) +#define _cast64_efi_call1(f,a1) \ + efi_call1(f, (UINT64)(a1)) +#define _cast64_efi_call2(f,a1,a2) \ + efi_call2(f, (UINT64)(a1), (UINT64)(a2)) +#define _cast64_efi_call3(f,a1,a2,a3) \ + efi_call3(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3)) +#define _cast64_efi_call4(f,a1,a2,a3,a4) \ + efi_call4(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4)) +#define _cast64_efi_call5(f,a1,a2,a3,a4,a5) \ + efi_call5(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \ + (UINT64)(a5)) +#define _cast64_efi_call6(f,a1,a2,a3,a4,a5,a6) \ + efi_call6(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \ + (UINT64)(a5), (UINT64)(a6)) +#define _cast64_efi_call7(f,a1,a2,a3,a4,a5,a6,a7) \ + efi_call7(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \ + (UINT64)(a5), (UINT64)(a6), (UINT64)(a7)) +#define _cast64_efi_call8(f,a1,a2,a3,a4,a5,a6,a7,a8) \ + efi_call8(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \ + (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8)) +#define _cast64_efi_call9(f,a1,a2,a3,a4,a5,a6,a7,a8,a9) \ + efi_call9(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \ + (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), \ + (UINT64)(a9)) +#define _cast64_efi_call10(f,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) \ + efi_call10(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \ + (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), \ + (UINT64)(a9), (UINT64)(a10)) + +/* main wrapper (va_num ignored) */ + +#define uefi_call_wrapper(func,va_num,...) \ + __VA_ARG_NSUFFIX__(_cast64_efi_call, __VA_ARGS__) (func , ##__VA_ARGS__) + +#else + +#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__) + +#endif + +/* AED EFI definitions */ + +#if defined(_AED_EFI) + +/* _int64 works for both IA32 and IA64 */ + +#define COMPILER_DEPENDENT_INT64 __int64 +#define COMPILER_DEPENDENT_UINT64 unsigned __int64 + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +/* warn C4142: redefinition of type */ + +#pragma warning(disable:4142) + +#endif + + +/* GNU EFI definitions */ + +#if defined(_GNU_EFI) + +/* Using GCC for GNU EFI */ + +#include "acgcc.h" + +#undef ACPI_USE_SYSTEM_CLIBRARY +#undef ACPI_USE_STANDARD_HEADERS +#undef ACPI_USE_NATIVE_DIVIDE +#define ACPI_USE_SYSTEM_INTTYPES + +/* + * Math helpers + */ +#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ + do { \ + UINT64 __n = ((UINT64) n_hi) << 32 | (n_lo); \ + (q32) = DivU64x32 ((__n), (d32), &(r32)); \ + } while (0) + +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ + do { \ + (n_lo) >>= 1; \ + (n_lo) |= (((n_hi) & 1) << 31); \ + (n_hi) >>= 1; \ + } while (0) + + +#endif + +struct _SIMPLE_TEXT_OUTPUT_INTERFACE; +struct _SIMPLE_INPUT_INTERFACE; +struct _EFI_FILE_IO_INTERFACE; +struct _EFI_FILE_HANDLE; +struct _EFI_BOOT_SERVICES; +struct _EFI_SYSTEM_TABLE; + +extern struct _EFI_SYSTEM_TABLE *ST; +extern struct _EFI_BOOT_SERVICES *BS; + +#define ACPI_FILE struct _SIMPLE_TEXT_OUTPUT_INTERFACE * +#define ACPI_FILE_OUT ST->ConOut +#define ACPI_FILE_ERR ST->ConOut + +#endif /* __ACEFI_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acefiex.h b/third_party/lib/acpica/source/include/platform/acefiex.h new file mode 100644 index 000000000..7df501280 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acefiex.h @@ -0,0 +1,855 @@ +/****************************************************************************** + * + * Name: acefiex.h - Extra OS specific defines, etc. for EFI + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACEFIEX_H__ +#define __ACEFIEX_H__ + + +#define EFI_ERROR(a) (((INTN) a) < 0) +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFIERR(1) +#define EFI_INVALID_PARAMETER EFIERR(2) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BAD_BUFFER_SIZE EFIERR(4) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_NOT_READY EFIERR(6) +#define EFI_DEVICE_ERROR EFIERR(7) +#define EFI_WRITE_PROTECTED EFIERR(8) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_VOLUME_CORRUPTED EFIERR(10) +#define EFI_VOLUME_FULL EFIERR(11) +#define EFI_NO_MEDIA EFIERR(12) +#define EFI_MEDIA_CHANGED EFIERR(13) +#define EFI_NOT_FOUND EFIERR(14) +#define EFI_ACCESS_DENIED EFIERR(15) +#define EFI_NO_RESPONSE EFIERR(16) +#define EFI_NO_MAPPING EFIERR(17) +#define EFI_TIMEOUT EFIERR(18) +#define EFI_NOT_STARTED EFIERR(19) +#define EFI_ALREADY_STARTED EFIERR(20) +#define EFI_ABORTED EFIERR(21) +#define EFI_PROTOCOL_ERROR EFIERR(24) + + +typedef UINTN EFI_STATUS; +typedef VOID *EFI_HANDLE; +typedef VOID *EFI_EVENT; + +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} EFI_GUID; + +typedef struct _EFI_DEVICE_PATH { + UINT8 Type; + UINT8 SubType; + UINT8 Length[2]; +} EFI_DEVICE_PATH; + +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} EFI_ALLOCATE_TYPE; + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + +/* possible caching types for the memory range */ +#define EFI_MEMORY_UC 0x0000000000000001 +#define EFI_MEMORY_WC 0x0000000000000002 +#define EFI_MEMORY_WT 0x0000000000000004 +#define EFI_MEMORY_WB 0x0000000000000008 +#define EFI_MEMORY_UCE 0x0000000000000010 + +/* physical memory protection on range */ +#define EFI_MEMORY_WP 0x0000000000001000 +#define EFI_MEMORY_RP 0x0000000000002000 +#define EFI_MEMORY_XP 0x0000000000004000 + +/* range requires a runtime mapping */ +#define EFI_MEMORY_RUNTIME 0x8000000000000000 + +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 +typedef struct { + UINT32 Type; + UINT32 Pad; + EFI_PHYSICAL_ADDRESS PhysicalStart; + EFI_VIRTUAL_ADDRESS VirtualStart; + UINT64 NumberOfPages; + UINT64 Attribute; +} EFI_MEMORY_DESCRIPTOR; + +typedef struct _EFI_TABLE_HEARDER { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + +typedef +EFI_STATUS +(EFIAPI *EFI_UNKNOWN_INTERFACE) ( + void); + + +/* + * Text output protocol + */ +#define SIMPLE_TEXT_OUTPUT_PROTOCOL \ + { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_RESET) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + BOOLEAN ExtendedVerification); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_OUTPUT_STRING) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + CHAR16 *String); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_TEST_STRING) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + CHAR16 *String); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_QUERY_MODE) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + UINTN ModeNumber, + UINTN *Columns, + UINTN *Rows); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_MODE) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + UINTN ModeNumber); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_ATTRIBUTE) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + UINTN Attribute); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_CLEAR_SCREEN) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + UINTN Column, + UINTN Row); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_ENABLE_CURSOR) ( + struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + BOOLEAN Enable); + +typedef struct { + INT32 MaxMode; + INT32 Mode; + INT32 Attribute; + INT32 CursorColumn; + INT32 CursorRow; + BOOLEAN CursorVisible; +} SIMPLE_TEXT_OUTPUT_MODE; + +typedef struct _SIMPLE_TEXT_OUTPUT_INTERFACE { + EFI_TEXT_RESET Reset; + + EFI_TEXT_OUTPUT_STRING OutputString; + EFI_TEXT_TEST_STRING TestString; + + EFI_TEXT_QUERY_MODE QueryMode; + EFI_TEXT_SET_MODE SetMode; + EFI_TEXT_SET_ATTRIBUTE SetAttribute; + + EFI_TEXT_CLEAR_SCREEN ClearScreen; + EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition; + EFI_TEXT_ENABLE_CURSOR EnableCursor; + + SIMPLE_TEXT_OUTPUT_MODE *Mode; +} SIMPLE_TEXT_OUTPUT_INTERFACE; + +/* + * Text input protocol + */ +#define SIMPLE_TEXT_INPUT_PROTOCOL \ + { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +/* + * Baseline unicode control chars + */ +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_RESET) ( + struct _SIMPLE_INPUT_INTERFACE *This, + BOOLEAN ExtendedVerification); + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_READ_KEY) ( + struct _SIMPLE_INPUT_INTERFACE *This, + EFI_INPUT_KEY *Key); + +typedef struct _SIMPLE_INPUT_INTERFACE { + EFI_INPUT_RESET Reset; + EFI_INPUT_READ_KEY ReadKeyStroke; + EFI_EVENT WaitForKey; +} SIMPLE_INPUT_INTERFACE; + + +/* + * Simple file system protocol + */ +#define SIMPLE_FILE_SYSTEM_PROTOCOL \ + { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef +EFI_STATUS +(EFIAPI *EFI_VOLUME_OPEN) ( + struct _EFI_FILE_IO_INTERFACE *This, + struct _EFI_FILE_HANDLE **Root); + +#define EFI_FILE_IO_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_FILE_IO_INTERFACE { + UINT64 Revision; + EFI_VOLUME_OPEN OpenVolume; +} EFI_FILE_IO_INTERFACE; + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_OPEN) ( + struct _EFI_FILE_HANDLE *File, + struct _EFI_FILE_HANDLE **NewHandle, + CHAR16 *FileName, + UINT64 OpenMode, + UINT64 Attributes); + +/* Values for OpenMode used above */ + +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +/* Values for Attribute used above */ + +#define EFI_FILE_READ_ONLY 0x0000000000000001 +#define EFI_FILE_HIDDEN 0x0000000000000002 +#define EFI_FILE_SYSTEM 0x0000000000000004 +#define EFI_FILE_RESERVIED 0x0000000000000008 +#define EFI_FILE_DIRECTORY 0x0000000000000010 +#define EFI_FILE_ARCHIVE 0x0000000000000020 +#define EFI_FILE_VALID_ATTR 0x0000000000000037 + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_CLOSE) ( + struct _EFI_FILE_HANDLE *File); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_DELETE) ( + struct _EFI_FILE_HANDLE *File); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_READ) ( + struct _EFI_FILE_HANDLE *File, + UINTN *BufferSize, + VOID *Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_WRITE) ( + struct _EFI_FILE_HANDLE *File, + UINTN *BufferSize, + VOID *Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_POSITION) ( + struct _EFI_FILE_HANDLE *File, + UINT64 Position); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_POSITION) ( + struct _EFI_FILE_HANDLE *File, + UINT64 *Position); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_INFO) ( + struct _EFI_FILE_HANDLE *File, + EFI_GUID *InformationType, + UINTN *BufferSize, + VOID *Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_INFO) ( + struct _EFI_FILE_HANDLE *File, + EFI_GUID *InformationType, + UINTN BufferSize, + VOID *Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_FLUSH) ( + struct _EFI_FILE_HANDLE *File); + + +#define EFI_FILE_HANDLE_REVISION 0x00010000 + +typedef struct _EFI_FILE_HANDLE { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; +} EFI_FILE, *EFI_FILE_HANDLE; + + +/* + * Loaded image protocol + */ +#define LOADED_IMAGE_PROTOCOL \ + { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_ENTRY_POINT) ( + EFI_HANDLE ImageHandle, + struct _EFI_SYSTEM_TABLE *SystemTable); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_LOAD) ( + BOOLEAN BootPolicy, + EFI_HANDLE ParentImageHandle, + EFI_DEVICE_PATH *FilePath, + VOID *SourceBuffer, + UINTN SourceSize, + EFI_HANDLE *ImageHandle); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_START) ( + EFI_HANDLE ImageHandle, + UINTN *ExitDataSize, + CHAR16 **ExitData); + +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT) ( + EFI_HANDLE ImageHandle, + EFI_STATUS ExitStatus, + UINTN ExitDataSize, + CHAR16 *ExitData); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_UNLOAD) ( + EFI_HANDLE ImageHandle); + + +#define EFI_IMAGE_INFORMATION_REVISION 0x1000 +typedef struct { + UINT32 Revision; + EFI_HANDLE ParentHandle; + struct _EFI_SYSTEM_TABLE *SystemTable; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH *FilePath; + VOID *Reserved; + UINT32 LoadOptionsSize; + VOID *LoadOptions; + VOID *ImageBase; + UINT64 ImageSize; + EFI_MEMORY_TYPE ImageCodeType; + EFI_MEMORY_TYPE ImageDataType; + EFI_IMAGE_UNLOAD Unload; + +} EFI_LOADED_IMAGE; + + +/* + * EFI Memory + */ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_PAGES) ( + EFI_ALLOCATE_TYPE Type, + EFI_MEMORY_TYPE MemoryType, + UINTN NoPages, + EFI_PHYSICAL_ADDRESS *Memory); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_PAGES) ( + EFI_PHYSICAL_ADDRESS Memory, + UINTN NoPages); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_MAP) ( + UINTN *MemoryMapSize, + EFI_MEMORY_DESCRIPTOR *MemoryMap, + UINTN *MapKey, + UINTN *DescriptorSize, + UINT32 *DescriptorVersion); + +#define NextMemoryDescriptor(Ptr,Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) Ptr) + Size)) + +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_POOL) ( + EFI_MEMORY_TYPE PoolType, + UINTN Size, + VOID **Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_POOL) ( + VOID *Buffer); + + +/* + * Protocol handler functions + */ +typedef enum { + EFI_NATIVE_INTERFACE, + EFI_PCODE_INTERFACE +} EFI_INTERFACE_TYPE; + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} EFI_LOCATE_SEARCH_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) ( + EFI_HANDLE *Handle, + EFI_GUID *Protocol, + EFI_INTERFACE_TYPE InterfaceType, + VOID *Interface); + +typedef +EFI_STATUS +(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE) ( + EFI_HANDLE Handle, + EFI_GUID *Protocol, + VOID *OldInterface, + VOID *NewInterface); + +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE) ( + EFI_HANDLE Handle, + EFI_GUID *Protocol, + VOID *Interface); + +typedef +EFI_STATUS +(EFIAPI *EFI_HANDLE_PROTOCOL) ( + EFI_HANDLE Handle, + EFI_GUID *Protocol, + VOID **Interface); + +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY) ( + EFI_GUID *Protocol, + EFI_EVENT Event, + VOID **Registration); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE) ( + EFI_LOCATE_SEARCH_TYPE SearchType, + EFI_GUID *Protocol, + VOID *SearchKey, + UINTN *BufferSize, + EFI_HANDLE *Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_DEVICE_PATH) ( + EFI_GUID *Protocol, + EFI_DEVICE_PATH **DevicePath, + EFI_HANDLE *Device); + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE) ( + EFI_GUID *Guid, + VOID *Table); + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL) ( + EFI_HANDLE Handle, + EFI_GUID *Protocol, + VOID **Interface, + EFI_HANDLE AgentHandle, + EFI_HANDLE ControllerHandle, + UINT32 Attributes); + +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_PROTOCOL) ( + EFI_HANDLE Handle, + EFI_GUID *Protocol, + EFI_HANDLE AgentHandle, + EFI_HANDLE ControllerHandle); + +typedef struct { + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY; + +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION) ( + EFI_HANDLE Handle, + EFI_GUID *Protocol, + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + UINTN *EntryCount); + +typedef +EFI_STATUS +(EFIAPI *EFI_PROTOCOLS_PER_HANDLE) ( + EFI_HANDLE Handle, + EFI_GUID ***ProtocolBuffer, + UINTN *ProtocolBufferCount); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE_BUFFER) ( + EFI_LOCATE_SEARCH_TYPE SearchType, + EFI_GUID *Protocol, + VOID *SearchKey, + UINTN *NoHandles, + EFI_HANDLE **Buffer); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_PROTOCOL) ( + EFI_GUID *Protocol, + VOID *Registration, + VOID **Interface); + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( + EFI_HANDLE *Handle, + ...); + +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( + EFI_HANDLE Handle, + ...); + +typedef +EFI_STATUS +(EFIAPI *EFI_CALCULATE_CRC32) ( + VOID *Data, + UINTN DataSize, + UINT32 *Crc32); + +typedef +VOID +(EFIAPI *EFI_COPY_MEM) ( + VOID *Destination, + VOID *Source, + UINTN Length); + +typedef +VOID +(EFIAPI *EFI_SET_MEM) ( + VOID *Buffer, + UINTN Size, + UINT8 Value); + +/* + * EFI Boot Services Table + */ +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 +#define EFI_BOOT_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +typedef struct _EFI_BOOT_SERVICES { + EFI_TABLE_HEADER Hdr; + +#if 0 + EFI_RAISE_TPL RaiseTPL; + EFI_RESTORE_TPL RestoreTPL; +#else + EFI_UNKNOWN_INTERFACE RaiseTPL; + EFI_UNKNOWN_INTERFACE RestoreTPL; +#endif + + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; + EFI_GET_MEMORY_MAP GetMemoryMap; + EFI_ALLOCATE_POOL AllocatePool; + EFI_FREE_POOL FreePool; + +#if 0 + EFI_CREATE_EVENT CreateEvent; + EFI_SET_TIMER SetTimer; + EFI_WAIT_FOR_EVENT WaitForEvent; + EFI_SIGNAL_EVENT SignalEvent; + EFI_CLOSE_EVENT CloseEvent; + EFI_CHECK_EVENT CheckEvent; +#else + EFI_UNKNOWN_INTERFACE CreateEvent; + EFI_UNKNOWN_INTERFACE SetTimer; + EFI_UNKNOWN_INTERFACE WaitForEvent; + EFI_UNKNOWN_INTERFACE SignalEvent; + EFI_UNKNOWN_INTERFACE CloseEvent; + EFI_UNKNOWN_INTERFACE CheckEvent; +#endif + + EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; + EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; + EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; + EFI_HANDLE_PROTOCOL HandleProtocol; + EFI_HANDLE_PROTOCOL PCHandleProtocol; + EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; + EFI_LOCATE_HANDLE LocateHandle; + EFI_LOCATE_DEVICE_PATH LocateDevicePath; + EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; + + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; + +#if 0 + EFI_EXIT_BOOT_SERVICES ExitBootServices; + EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; + EFI_STALL Stall; + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; +#else + EFI_UNKNOWN_INTERFACE ExitBootServices; + EFI_UNKNOWN_INTERFACE GetNextMonotonicCount; + EFI_UNKNOWN_INTERFACE Stall; + EFI_UNKNOWN_INTERFACE SetWatchdogTimer; +#endif + +#if 0 + EFI_CONNECT_CONTROLLER ConnectController; + EFI_DISCONNECT_CONTROLLER DisconnectController; +#else + EFI_UNKNOWN_INTERFACE ConnectController; + EFI_UNKNOWN_INTERFACE DisconnectController; +#endif + + EFI_OPEN_PROTOCOL OpenProtocol; + EFI_CLOSE_PROTOCOL CloseProtocol; + EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; + EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + EFI_LOCATE_PROTOCOL LocateProtocol; + EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; + EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; + + EFI_CALCULATE_CRC32 CalculateCrc32; + + EFI_COPY_MEM CopyMem; + EFI_SET_MEM SetMem; + +#if 0 + EFI_CREATE_EVENT_EX CreateEventEx; +#else + EFI_UNKNOWN_INTERFACE CreateEventEx; +#endif +} EFI_BOOT_SERVICES; + + +/* + * EFI System Table + */ + +/* + * EFI Configuration Table and GUID definitions + */ +#define ACPI_TABLE_GUID \ + { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define ACPI_20_TABLE_GUID \ + { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } + +typedef struct _EFI_CONFIGURATION_TABLE { + EFI_GUID VendorGuid; + VOID *VendorTable; +} EFI_CONFIGURATION_TABLE; + + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +typedef struct _EFI_SYSTEM_TABLE { + EFI_TABLE_HEADER Hdr; + + CHAR16 *FirmwareVendor; + UINT32 FirmwareRevision; + + EFI_HANDLE ConsoleInHandle; + SIMPLE_INPUT_INTERFACE *ConIn; + + EFI_HANDLE ConsoleOutHandle; + SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut; + + EFI_HANDLE StandardErrorHandle; + SIMPLE_TEXT_OUTPUT_INTERFACE *StdErr; + +#if 0 + EFI_RUNTIME_SERVICES *RuntimeServices; +#else + EFI_HANDLE *RuntimeServices; +#endif + EFI_BOOT_SERVICES *BootServices; + + UINTN NumberOfTableEntries; + EFI_CONFIGURATION_TABLE *ConfigurationTable; + +} EFI_SYSTEM_TABLE; + + +/* GNU EFI definitions */ + +#if defined(_GNU_EFI) + +/* + * This is needed to hide platform specific code from ACPICA + */ +UINT64 +DivU64x32 ( + UINT64 Dividend, + UINTN Divisor, + UINTN *Remainder); + +/* + * EFI specific prototypes + */ +EFI_STATUS +efi_main ( + EFI_HANDLE Image, + EFI_SYSTEM_TABLE *SystemTab); + +int +acpi_main ( + int argc, + char *argv[]); + + +#endif + +extern EFI_GUID AcpiGbl_LoadedImageProtocol; +extern EFI_GUID AcpiGbl_TextInProtocol; +extern EFI_GUID AcpiGbl_TextOutProtocol; +extern EFI_GUID AcpiGbl_FileSystemProtocol; + +#endif /* __ACEFIEX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acenv.h b/third_party/lib/acpica/source/include/platform/acenv.h new file mode 100644 index 000000000..a3ad90929 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acenv.h @@ -0,0 +1,409 @@ +/****************************************************************************** + * + * Name: acenv.h - Host and compiler configuration + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACENV_H__ +#define __ACENV_H__ + +/* + * Environment configuration. The purpose of this file is to interface ACPICA + * to the local environment. This includes compiler-specific, OS-specific, + * and machine-specific configuration. + */ + +/* Types for ACPI_MUTEX_TYPE */ + +#define ACPI_BINARY_SEMAPHORE 0 +#define ACPI_OSL_MUTEX 1 + +/* Types for DEBUGGER_THREADING */ + +#define DEBUGGER_SINGLE_THREADED 0 +#define DEBUGGER_MULTI_THREADED 1 + + +/****************************************************************************** + * + * Configuration for ACPI tools and utilities + * + *****************************************************************************/ + +/* iASL configuration */ + +#ifdef ACPI_ASL_COMPILER +#define ACPI_APPLICATION +#define ACPI_DEBUG_OUTPUT +#define ACPI_CONSTANT_EVAL_ONLY +#define ACPI_LARGE_NAMESPACE_NODE +#define ACPI_DATA_TABLE_DISASSEMBLY +#define ACPI_SINGLE_THREADED +#define ACPI_32BIT_PHYSICAL_ADDRESS + +#define ACPI_DISASSEMBLER 1 +#endif + +/* AcpiExec configuration. Multithreaded with full AML debugger */ + +#ifdef ACPI_EXEC_APP +#define ACPI_APPLICATION +#define ACPI_FULL_DEBUG +#define ACPI_MUTEX_DEBUG +#define ACPI_DBG_TRACK_ALLOCATIONS +#endif + +/* + * AcpiBin/AcpiDump/AcpiHelp/AcpiNames/AcpiSrc/AcpiXtract/Example + * configuration. All single threaded. + */ +#if (defined ACPI_BIN_APP) || \ + (defined ACPI_DUMP_APP) || \ + (defined ACPI_HELP_APP) || \ + (defined ACPI_NAMES_APP) || \ + (defined ACPI_SRC_APP) || \ + (defined ACPI_XTRACT_APP) || \ + (defined ACPI_EXAMPLE_APP) +#define ACPI_APPLICATION +#define ACPI_SINGLE_THREADED +#endif + +/* AcpiHelp configuration. Error messages disabled. */ + +#ifdef ACPI_HELP_APP +#define ACPI_NO_ERROR_MESSAGES +#endif + +/* AcpiNames configuration. Debug output enabled. */ + +#ifdef ACPI_NAMES_APP +#define ACPI_DEBUG_OUTPUT +#endif + +/* AcpiExec/AcpiNames/Example configuration. Native RSDP used. */ + +#if (defined ACPI_EXEC_APP) || \ + (defined ACPI_EXAMPLE_APP) || \ + (defined ACPI_NAMES_APP) +#define ACPI_USE_NATIVE_RSDP_POINTER +#endif + +/* AcpiDump configuration. Native mapping used if provided by the host */ + +#ifdef ACPI_DUMP_APP +#define ACPI_USE_NATIVE_MEMORY_MAPPING +#define USE_NATIVE_ALLOCATE_ZEROED +#endif + +/* AcpiNames/Example configuration. Hardware disabled */ + +#if (defined ACPI_EXAMPLE_APP) || \ + (defined ACPI_NAMES_APP) +#define ACPI_REDUCED_HARDWARE 1 +#endif + +/* Linkable ACPICA library */ + +#ifdef ACPI_LIBRARY +#define ACPI_USE_LOCAL_CACHE +#define ACPI_FULL_DEBUG +#endif + +/* Common for all ACPICA applications */ + +#ifdef ACPI_APPLICATION +#define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_USE_LOCAL_CACHE +#endif + +/* Common debug/disassembler support */ + +#ifdef ACPI_FULL_DEBUG +#define ACPI_DEBUG_OUTPUT +#define ACPI_DEBUGGER 1 +#define ACPI_DISASSEMBLER 1 +#endif + +/*! [Begin] no source code translation */ + +/****************************************************************************** + * + * Host configuration files. The compiler configuration files are included + * by the host files. + * + *****************************************************************************/ + +#if defined(_LINUX) || defined(__linux__) +#include "aclinux.h" + +#elif defined(_APPLE) || defined(__APPLE__) +#include "acmacosx.h" + +#elif defined(__DragonFly__) +#include "acdragonfly.h" + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include "acfreebsd.h" + +#elif defined(__NetBSD__) +#include "acnetbsd.h" + +#elif defined(__sun) +#include "acsolaris.h" + +#elif defined(MODESTO) +#include "acmodesto.h" + +#elif defined(NETWARE) +#include "acnetware.h" + +#elif defined(_CYGWIN) +#include "accygwin.h" + +#elif defined(WIN32) +#include "acwin.h" + +#elif defined(WIN64) +#include "acwin64.h" + +#elif defined(_WRS_LIB_BUILD) +#include "acvxworks.h" + +#elif defined(__OS2__) +#include "acos2.h" + +#elif defined(_AED_EFI) +#include "acefi.h" + +#elif defined(_GNU_EFI) +#include "acefi.h" + +#elif defined(__HAIKU__) +#include "achaiku.h" + +#elif defined(LK) +#include "acmagenta.h" + +#else + +/* Unknown environment */ + +#error Unknown target environment +#endif + +/*! [End] no source code translation !*/ + + +/****************************************************************************** + * + * Setup defaults for the required symbols that were not defined in one of + * the host/compiler files above. + * + *****************************************************************************/ + +/* 64-bit data types */ + +#ifndef COMPILER_DEPENDENT_INT64 +#define COMPILER_DEPENDENT_INT64 long long +#endif + +#ifndef COMPILER_DEPENDENT_UINT64 +#define COMPILER_DEPENDENT_UINT64 unsigned long long +#endif + +/* Type of mutex supported by host. Default is binary semaphores. */ + +#ifndef ACPI_MUTEX_TYPE +#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE +#endif + +/* Global Lock acquire/release */ + +#ifndef ACPI_ACQUIRE_GLOBAL_LOCK +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acquired) Acquired = 1 +#endif + +#ifndef ACPI_RELEASE_GLOBAL_LOCK +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Pending) Pending = 0 +#endif + +/* Flush CPU cache - used when going to sleep. Wbinvd or similar. */ + +#ifndef ACPI_FLUSH_CPU_CACHE +#define ACPI_FLUSH_CPU_CACHE() +#endif + +/* "inline" keywords - configurable since inline is not standardized */ + +#ifndef ACPI_INLINE +#define ACPI_INLINE +#endif + +/* + * Configurable calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#ifndef ACPI_SYSTEM_XFACE +#define ACPI_SYSTEM_XFACE +#endif + +#ifndef ACPI_EXTERNAL_XFACE +#define ACPI_EXTERNAL_XFACE +#endif + +#ifndef ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#endif + +#ifndef ACPI_INTERNAL_VAR_XFACE +#define ACPI_INTERNAL_VAR_XFACE +#endif + + +/* + * Debugger threading model + * Use single threaded if the entire subsystem is contained in an application + * Use multiple threaded when the subsystem is running in the kernel. + * + * By default the model is single threaded if ACPI_APPLICATION is set, + * multi-threaded if ACPI_APPLICATION is not set. + */ +#ifndef DEBUGGER_THREADING +#if !defined (ACPI_APPLICATION) || defined (ACPI_EXEC_APP) +#define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED + +#else +#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED +#endif +#endif /* !DEBUGGER_THREADING */ + + +/****************************************************************************** + * + * C library configuration + * + *****************************************************************************/ + +/* + * ACPI_USE_SYSTEM_CLIBRARY - Define this if linking to an actual C library. + * Otherwise, local versions of string/memory functions will be used. + * ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and + * the standard header files may be used. + * + * The ACPICA subsystem only uses low level C library functions that do not + * call operating system services and may therefore be inlined in the code. + * + * It may be necessary to tailor these include files to the target + * generation environment. + */ +#ifdef ACPI_USE_SYSTEM_CLIBRARY + +/* Use the standard C library headers. We want to keep these to a minimum. */ + +#ifdef ACPI_USE_STANDARD_HEADERS + +/* Use the standard headers from the standard locations */ + +#include +#include +#include +#include + +#endif /* ACPI_USE_STANDARD_HEADERS */ + +/* We will be linking to the standard Clib functions */ + +#else + +/****************************************************************************** + * + * Not using native C library, use local implementations + * + *****************************************************************************/ + +/* + * Use local definitions of C library macros and functions. These function + * implementations may not be as efficient as an inline or assembly code + * implementation provided by a native C library, but they are functionally + * equivalent. + */ +#ifndef va_arg + +#ifndef _VALIST +#define _VALIST +typedef char *va_list; +#endif /* _VALIST */ + +/* Storage alignment properties */ + +#define _AUPBND (sizeof (ACPI_NATIVE_INT) - 1) +#define _ADNBND (sizeof (ACPI_NATIVE_INT) - 1) + +/* Variable argument list macro definitions */ + +#define _Bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) +#define va_arg(ap, T) (*(T *)(((ap) += (_Bnd (T, _AUPBND))) - (_Bnd (T,_ADNBND)))) +#define va_end(ap) (ap = (va_list) NULL) +#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_Bnd (A,_AUPBND)))) + +#endif /* va_arg */ + +/* Use the local (ACPICA) definitions of the clib functions */ + +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ + +#ifndef ACPI_FILE +#ifdef ACPI_APPLICATION +#include +#define ACPI_FILE FILE * +#define ACPI_FILE_OUT stdout +#define ACPI_FILE_ERR stderr +#else +#define ACPI_FILE void * +#define ACPI_FILE_OUT NULL +#define ACPI_FILE_ERR NULL +#endif /* ACPI_APPLICATION */ +#endif /* ACPI_FILE */ + +#endif /* __ACENV_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acenvex.h b/third_party/lib/acpica/source/include/platform/acenvex.h new file mode 100644 index 000000000..02a46f148 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acenvex.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Name: acenvex.h - Extra host and compiler configuration + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACENVEX_H__ +#define __ACENVEX_H__ + +/*! [Begin] no source code translation */ + +/****************************************************************************** + * + * Extra host configuration files. All ACPICA headers are included before + * including these files. + * + *****************************************************************************/ + +#if defined(_LINUX) || defined(__linux__) +#include "aclinuxex.h" + +#elif defined(WIN32) +#include "acwinex.h" + +#elif defined(_AED_EFI) +#include "acefiex.h" + +#elif defined(_GNU_EFI) +#include "acefiex.h" + +#elif defined(__DragonFly__) +#include "acdragonflyex.h" + +#endif + +/*! [End] no source code translation !*/ + +#endif /* __ACENVEX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acfreebsd.h b/third_party/lib/acpica/source/include/platform/acfreebsd.h new file mode 100644 index 000000000..a968e12cc --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acfreebsd.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * Name: acfreebsd.h - OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACFREEBSD_H__ +#define __ACFREEBSD_H__ + + +/* FreeBSD uses GCC */ + +#include "acgcc.h" +#include + +#ifdef __LP64__ +#define ACPI_MACHINE_WIDTH 64 +#else +#define ACPI_MACHINE_WIDTH 32 +#endif + +#define COMPILER_DEPENDENT_INT64 int64_t +#define COMPILER_DEPENDENT_UINT64 uint64_t + +#define ACPI_UINTPTR_T uintptr_t + +#define ACPI_USE_DO_WHILE_0 +#define ACPI_USE_LOCAL_CACHE +#define ACPI_USE_NATIVE_DIVIDE +#define ACPI_USE_SYSTEM_CLIBRARY + +#ifdef _KERNEL + +#include +#include +#include +#include +#include +#include + +#include "opt_acpi.h" + +#define ACPI_MUTEX_TYPE ACPI_OSL_MUTEX + +#ifdef ACPI_DEBUG +#define ACPI_DEBUG_OUTPUT /* for backward compatibility */ +#define ACPI_DISASSEMBLER +#endif + +#ifdef ACPI_DEBUG_OUTPUT +#include "opt_ddb.h" +#ifdef DDB +#define ACPI_DEBUGGER +#endif /* DDB */ +#endif /* ACPI_DEBUG_OUTPUT */ + +#ifdef DEBUGGER_THREADING +#undef DEBUGGER_THREADING +#endif /* DEBUGGER_THREADING */ + +#define DEBUGGER_THREADING 0 /* integrated with DDB */ + +#else /* _KERNEL */ + +#if __STDC_HOSTED__ +#include +#endif + +#define ACPI_CAST_PTHREAD_T(pthread) ((ACPI_THREAD_ID) ACPI_TO_INTEGER (pthread)) + +#define ACPI_USE_STANDARD_HEADERS + +#define ACPI_FLUSH_CPU_CACHE() +#define __cdecl + +#endif /* _KERNEL */ + +#endif /* __ACFREEBSD_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acgcc.h b/third_party/lib/acpica/source/include/platform/acgcc.h new file mode 100644 index 000000000..7d703da3d --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acgcc.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Name: acgcc.h - GCC specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACGCC_H__ +#define __ACGCC_H__ + +#define ACPI_INLINE __inline__ + +/* Function name is used for debug output. Non-ANSI, compiler-dependent */ + +#define ACPI_GET_FUNCTION_NAME __func__ + +/* + * This macro is used to tag functions as "printf-like" because + * some compilers (like GCC) can catch printf format string problems. + */ +#define ACPI_PRINTF_LIKE(c) __attribute__ ((__format__ (__printf__, c, c+1))) + +/* + * Some compilers complain about unused variables. Sometimes we don't want to + * use all the variables (for example, _AcpiModuleName). This allows us + * to tell the compiler warning in a per-variable manner that a variable + * is unused. + */ +#define ACPI_UNUSED_VAR __attribute__ ((unused)) + +/* + * Some versions of gcc implement strchr() with a buggy macro. So, + * undef it here. Prevents error messages of this form (usually from the + * file getopt.c): + * + * error: logical '&&' with non-zero constant will always evaluate as true + */ +#ifdef strchr +#undef strchr +#endif + +/* GCC supports __VA_ARGS__ in macros */ + +#define COMPILER_VA_MACRO 1 + +#endif /* __ACGCC_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/achaiku.h b/third_party/lib/acpica/source/include/platform/achaiku.h new file mode 100644 index 000000000..10aa6a3f4 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/achaiku.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * Name: achaiku.h - OS specific defines, etc. for Haiku (www.haiku-os.org) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACHAIKU_H__ +#define __ACHAIKU_H__ + +#include "acgcc.h" +#include + +struct mutex; + + +/* Host-dependent types and defines for user- and kernel-space ACPICA */ + +#define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_USE_STANDARD_HEADERS + +#define ACPI_MUTEX_TYPE ACPI_OSL_MUTEX +#define ACPI_MUTEX struct mutex * + +#define ACPI_USE_NATIVE_DIVIDE + +/* #define ACPI_THREAD_ID thread_id */ + +#define ACPI_SEMAPHORE sem_id +#define ACPI_SPINLOCK spinlock * +#define ACPI_CPU_FLAGS cpu_status + +#define COMPILER_DEPENDENT_INT64 int64 +#define COMPILER_DEPENDENT_UINT64 uint64 + + +#ifdef B_HAIKU_64_BIT +#define ACPI_MACHINE_WIDTH 64 +#else +#define ACPI_MACHINE_WIDTH 32 +#endif + + +#ifdef _KERNEL_MODE +/* Host-dependent types and defines for in-kernel ACPICA */ + +/* ACPICA cache implementation is adequate. */ +#define ACPI_USE_LOCAL_CACHE + +#define ACPI_FLUSH_CPU_CACHE() __asm __volatile("wbinvd"); + +/* Based on FreeBSD's due to lack of documentation */ +extern int AcpiOsAcquireGlobalLock(uint32 *lock); +extern int AcpiOsReleaseGlobalLock(uint32 *lock); + +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) do { \ + (Acq) = AcpiOsAcquireGlobalLock(&((GLptr)->GlobalLock)); \ +} while (0) + +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) do { \ + (Acq) = AcpiOsReleaseGlobalLock(&((GLptr)->GlobalLock)); \ +} while (0) + +#else /* _KERNEL_MODE */ +/* Host-dependent types and defines for user-space ACPICA */ + +#error "We only support kernel mode ACPI atm." + +#endif /* _KERNEL_MODE */ +#endif /* __ACHAIKU_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acintel.h b/third_party/lib/acpica/source/include/platform/acintel.h new file mode 100644 index 000000000..b8dda571f --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acintel.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Name: acintel.h - VC specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACINTEL_H__ +#define __ACINTEL_H__ + +/* Configuration specific to Intel 64-bit C compiler */ + +#define COMPILER_DEPENDENT_INT64 __int64 +#define COMPILER_DEPENDENT_UINT64 unsigned __int64 +#define ACPI_INLINE __inline + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +/* remark 981 - operands evaluated in no particular order */ +#pragma warning(disable:981) + +/* warn C4100: unreferenced formal parameter */ +#pragma warning(disable:4100) + +/* warn C4127: conditional expression is constant */ +#pragma warning(disable:4127) + +/* warn C4706: assignment within conditional expression */ +#pragma warning(disable:4706) + +/* warn C4214: bit field types other than int */ +#pragma warning(disable:4214) + + +#endif /* __ACINTEL_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/aclinux.h b/third_party/lib/acpica/source/include/platform/aclinux.h new file mode 100644 index 000000000..a70b4e68e --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/aclinux.h @@ -0,0 +1,207 @@ +/****************************************************************************** + * + * Name: aclinux.h - OS specific defines, etc. for Linux + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACLINUX_H__ +#define __ACLINUX_H__ + +#ifdef __KERNEL__ + +/* ACPICA external files should not include ACPICA headers directly. */ + +#if !defined(BUILDING_ACPICA) && !defined(_LINUX_ACPI_H) +#error "Please don't include directly, include instead." +#endif + +#endif + +/* Common (in-kernel/user-space) ACPICA configuration */ + +#define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_USE_DO_WHILE_0 + + +#ifdef __KERNEL__ + +#define ACPI_USE_SYSTEM_INTTYPES + +/* Kernel specific ACPICA configuration */ + +#ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY +#define ACPI_REDUCED_HARDWARE 1 +#endif + +#ifdef CONFIG_ACPI_DEBUGGER +#define ACPI_DEBUGGER +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef EXPORT_ACPI_INTERFACES +#include +#endif +#ifdef CONFIG_ACPI +#include +#endif + +#ifndef CONFIG_ACPI + +/* External globals for __KERNEL__, stubs is needed */ + +#define ACPI_GLOBAL(t,a) +#define ACPI_INIT_GLOBAL(t,a,b) + +/* Generating stubs for configurable ACPICA macros */ + +#define ACPI_NO_MEM_ALLOCATIONS + +/* Generating stubs for configurable ACPICA functions */ + +#define ACPI_NO_ERROR_MESSAGES +#undef ACPI_DEBUG_OUTPUT + +/* External interface for __KERNEL__, stub is needed */ + +#define ACPI_EXTERNAL_RETURN_STATUS(Prototype) \ + static ACPI_INLINE Prototype {return(AE_NOT_CONFIGURED);} +#define ACPI_EXTERNAL_RETURN_OK(Prototype) \ + static ACPI_INLINE Prototype {return(AE_OK);} +#define ACPI_EXTERNAL_RETURN_VOID(Prototype) \ + static ACPI_INLINE Prototype {return;} +#define ACPI_EXTERNAL_RETURN_UINT32(Prototype) \ + static ACPI_INLINE Prototype {return(0);} +#define ACPI_EXTERNAL_RETURN_PTR(Prototype) \ + static ACPI_INLINE Prototype {return(NULL);} + +#endif /* CONFIG_ACPI */ + +/* Host-dependent types and defines for in-kernel ACPICA */ + +#define ACPI_MACHINE_WIDTH BITS_PER_LONG +#define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); +#define strtoul simple_strtoul + +#define ACPI_CACHE_T struct kmem_cache +#define ACPI_SPINLOCK spinlock_t * +#define ACPI_CPU_FLAGS unsigned long + +/* Use native linux version of AcpiOsAllocateZeroed */ + +#define USE_NATIVE_ALLOCATE_ZEROED + +/* + * Overrides for in-kernel ACPICA + */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsInitialize +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsTerminate +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAllocate +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAllocateZeroed +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsFree +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsAcquireObject +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetThreadId +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCreateLock + +/* + * OSL interfaces used by debugger/disassembler + */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsReadable +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWritable + +/* + * OSL interfaces used by utilities + */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsRedirectOutput +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByName +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByIndex +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetTableByAddress +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsOpenDirectory +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsGetNextFilename +#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsCloseDirectory + +#else /* !__KERNEL__ */ + +#include +#include +#include +#include +#include + +/* Define/disable kernel-specific declarators */ + +#ifndef __init +#define __init +#endif + +/* Host-dependent types and defines for user-space ACPICA */ + +#define ACPI_FLUSH_CPU_CACHE() +#define ACPI_CAST_PTHREAD_T(Pthread) ((ACPI_THREAD_ID) (Pthread)) + +#if defined(__ia64__) || defined(__x86_64__) ||\ + defined(__aarch64__) || defined(__PPC64__) +#define ACPI_MACHINE_WIDTH 64 +#define COMPILER_DEPENDENT_INT64 long +#define COMPILER_DEPENDENT_UINT64 unsigned long +#else +#define ACPI_MACHINE_WIDTH 32 +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long +#define ACPI_USE_NATIVE_DIVIDE +#endif + +#ifndef __cdecl +#define __cdecl +#endif + +#endif /* __KERNEL__ */ + +/* Linux uses GCC */ + +#include "acgcc.h" + +#endif /* __ACLINUX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/aclinuxex.h b/third_party/lib/acpica/source/include/platform/aclinuxex.h new file mode 100644 index 000000000..c262e4081 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/aclinuxex.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * Name: aclinuxex.h - Extra OS specific defines, etc. for Linux + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACLINUXEX_H__ +#define __ACLINUXEX_H__ + +#ifdef __KERNEL__ + +#ifndef ACPI_USE_NATIVE_DIVIDE + +#ifndef ACPI_DIV_64_BY_32 +#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ + do { \ + UINT64 (__n) = ((UINT64) n_hi) << 32 | (n_lo); \ + (r32) = do_div ((__n), (d32)); \ + (q32) = (UINT32) (__n); \ + } while (0) +#endif + +#ifndef ACPI_SHIFT_RIGHT_64 +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ + do { \ + (n_lo) >>= 1; \ + (n_lo) |= (((n_hi) & 1) << 31); \ + (n_hi) >>= 1; \ + } while (0) +#endif + +#endif + +/* + * Overrides for in-kernel ACPICA + */ +ACPI_STATUS __init AcpiOsInitialize ( + void); + +ACPI_STATUS AcpiOsTerminate ( + void); + +/* + * The irqs_disabled() check is for resume from RAM. + * Interrupts are off during resume, just like they are for boot. + * However, boot has (system_state != SYSTEM_RUNNING) + * to quiet __might_sleep() in kmalloc() and resume does not. + */ +static inline void * +AcpiOsAllocate ( + ACPI_SIZE Size) +{ + return kmalloc (Size, irqs_disabled () ? GFP_ATOMIC : GFP_KERNEL); +} + +static inline void * +AcpiOsAllocateZeroed ( + ACPI_SIZE Size) +{ + return kzalloc (Size, irqs_disabled () ? GFP_ATOMIC : GFP_KERNEL); +} + +static inline void +AcpiOsFree ( + void *Memory) +{ + kfree (Memory); +} + +static inline void * +AcpiOsAcquireObject ( + ACPI_CACHE_T *Cache) +{ + return kmem_cache_zalloc (Cache, + irqs_disabled () ? GFP_ATOMIC : GFP_KERNEL); +} + +static inline ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + return (ACPI_THREAD_ID) (unsigned long) current; +} + +/* + * When lockdep is enabled, the spin_lock_init() macro stringifies it's + * argument and uses that as a name for the lock in debugging. + * By executing spin_lock_init() in a macro the key changes from "lock" for + * all locks to the name of the argument of acpi_os_create_lock(), which + * prevents lockdep from reporting false positives for ACPICA locks. + */ +#define AcpiOsCreateLock(__Handle) \ + ({ \ + spinlock_t *Lock = ACPI_ALLOCATE(sizeof(*Lock)); \ + if (Lock) { \ + *(__Handle) = Lock; \ + spin_lock_init(*(__Handle)); \ + } \ + Lock ? AE_OK : AE_NO_MEMORY; \ + }) + +static inline BOOLEAN +AcpiOsReadable ( + void *Pointer, + ACPI_SIZE Length) +{ + return TRUE; +} + + +/* + * OSL interfaces added by Linux + */ +void +EarlyAcpiOsUnmapMemory ( + void __iomem *Virt, + ACPI_SIZE Size); + +#endif /* __KERNEL__ */ + +#endif /* __ACLINUXEX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acmacosx.h b/third_party/lib/acpica/source/include/platform/acmacosx.h new file mode 100644 index 000000000..5d2ba41e8 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acmacosx.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Name: acmacosx.h - OS specific defines, etc. for Mac OS X + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACMACOSX_H__ +#define __ACMACOSX_H__ + +#include "aclinux.h" + +#ifdef __APPLE__ +#define sem_destroy sem_close +#define ACPI_USE_ALTERNATE_TIMEOUT +#endif /* __APPLE__ */ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + +#endif /* __ACMACOSX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acmagenta.h b/third_party/lib/acpica/source/include/platform/acmagenta.h new file mode 100644 index 000000000..c7da0667d --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acmagenta.h @@ -0,0 +1,50 @@ +#ifndef __ACMAGENTA_H__ +#define __ACMAGENTA_H__ + +#include +#include + +/* + * Settings described in section 7 of + * https://acpica.org/sites/acpica/files/acpica-reference_17.pdf + */ + + +#if defined(ARCH_X86_64) +#define ACPI_MACHINE_WIDTH 64 +#elif defined(ARCH_X86_32) +#define ACPI_MACHINE_WIDTH 32 +#define ACPI_USE_NATIVE_DIVIDE +#else +#error Unexpected architecture +#endif + +#define ACPI_FLUSH_CPU_CACHE() __asm__ volatile ("wbinvd") +#if 0 +#define ACPI_ACQUIRE_GLOBAL_LOCK(FacsPtr, Acquired) +#define ACPI_RELEASE_GLOBAL_LOCK(FacsPtr, Pending) +#endif + +// Use the standard library headers +#define ACPI_USE_STANDARD_HEADERS +#define ACPI_USE_SYSTEM_CLIBRARY + +// Use the builtin cache implementation +#define ACPI_USE_LOCAL_CACHE + +// Specify the types Magenta uses for various common objects +#define ACPI_CPU_FLAGS spin_lock_saved_state_t +#define ACPI_SPINLOCK spin_lock_t* +#define ACPI_SEMAPHORE semaphore_t* + +// Borrowed from aclinuxex.h + +// Include the gcc header since we're compiling on gcc +#include "acgcc.h" + +extern bool _acpica_acquire_global_lock(void *FacsPtr); +extern bool _acpica_release_global_lock(void *FacsPtr); +#define ACPI_ACQUIRE_GLOBAL_LOCK(FacsPtr, Acq) Acq = _acpica_acquire_global_lock(FacsPtr) +#define ACPI_RELEASE_GLOBAL_LOCK(FacsPtr, Pnd) Pnd = _acpica_release_global_lock(FacsPtr) + +#endif diff --git a/third_party/lib/acpica/source/include/platform/acmsvc.h b/third_party/lib/acpica/source/include/platform/acmsvc.h new file mode 100644 index 000000000..e8c801f56 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acmsvc.h @@ -0,0 +1,195 @@ +/****************************************************************************** + * + * Name: acmsvc.h - VC specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACMSVC_H__ +#define __ACMSVC_H__ + +/* Note: do not include any C library headers here */ + +/* + * Note: MSVC project files should define ACPI_DEBUGGER and ACPI_DISASSEMBLER + * as appropriate to enable editor functions like "Find all references". + * The editor isn't smart enough to dig through the include files to find + * out if these are actually defined. + */ + +/* + * Map low I/O functions for MS. This allows us to disable MS language + * extensions for maximum portability. + */ +#define open _open +#define read _read +#define write _write +#define close _close +#define stat _stat +#define fstat _fstat +#define mkdir _mkdir +#define O_RDONLY _O_RDONLY +#define O_BINARY _O_BINARY +#define O_CREAT _O_CREAT +#define O_WRONLY _O_WRONLY +#define O_TRUNC _O_TRUNC +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IFDIR _S_IFDIR + +/* Eliminate warnings for "old" (non-secure) versions of clib functions */ + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* Eliminate warnings for POSIX clib function names (open, write, etc.) */ + +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif + +#define COMPILER_DEPENDENT_INT64 __int64 +#define COMPILER_DEPENDENT_UINT64 unsigned __int64 +#define ACPI_INLINE __inline + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE __cdecl +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE __cdecl + +#ifndef _LINT +/* + * Math helper functions + */ +#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ +{ \ + __asm mov edx, n_hi \ + __asm mov eax, n_lo \ + __asm div d32 \ + __asm mov q32, eax \ + __asm mov r32, edx \ +} + +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ +{ \ + __asm shr n_hi, 1 \ + __asm rcr n_lo, 1 \ +} +#else + +/* Fake versions to make lint happy */ + +#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ +{ \ + q32 = n_hi / d32; \ + r32 = n_lo / d32; \ +} + +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ +{ \ + n_hi >>= 1; \ + n_lo >>= 1; \ +} +#endif + +/* warn C4100: unreferenced formal parameter */ +#pragma warning(disable:4100) + +/* warn C4127: conditional expression is constant */ +#pragma warning(disable:4127) + +/* warn C4706: assignment within conditional expression */ +#pragma warning(disable:4706) + +/* warn C4131: uses old-style declarator (iASL compiler only) */ +#pragma warning(disable:4131) + +#if _MSC_VER > 1200 /* Versions above VC++ 6 */ +#pragma warning( disable : 4295 ) /* needed for acpredef.h array */ +#endif + + +/* Debug support. */ + +#ifdef _DEBUG + +/* + * Debugging memory corruption issues with windows: + * Add #include to accommon.h if necessary. + * Add _ASSERTE(_CrtCheckMemory()); where needed to test memory integrity. + * This can quickly localize the memory corruption. + */ +#define ACPI_DEBUG_INITIALIZE() \ + _CrtSetDbgFlag (\ + _CRTDBG_CHECK_ALWAYS_DF | \ + _CRTDBG_ALLOC_MEM_DF | \ + _CRTDBG_DELAY_FREE_MEM_DF | \ + _CRTDBG_LEAK_CHECK_DF | \ + _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); + +#if 0 +/* + * _CrtSetBreakAlloc can be used to set a breakpoint at a particular + * memory leak, add to the macro above. + */ +Detected memory leaks! +Dumping objects -> +..\..\source\os_specific\service_layers\oswinxf.c(701) : {937} normal block at 0x002E9190, 40 bytes long. + Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +_CrtSetBreakAlloc (937); +#endif + +#endif + +#if _MSC_VER > 1200 /* Versions above VC++ 6 */ +#define COMPILER_VA_MACRO 1 +#else +#endif + +#endif /* __ACMSVC_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acmsvcex.h b/third_party/lib/acpica/source/include/platform/acmsvcex.h new file mode 100644 index 000000000..f99a034a4 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acmsvcex.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Name: acmsvcex.h - Extra VC specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACMSVCEX_H__ +#define __ACMSVCEX_H__ + +/* Debug support. */ + +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC /* Enables specific file/lineno for leaks */ +#include +#endif + +#endif /* __ACMSVCEX_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acnetbsd.h b/third_party/lib/acpica/source/include/platform/acnetbsd.h new file mode 100644 index 000000000..09259af3a --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acnetbsd.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * Name: acnetbsd.h - OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACNETBSD_H__ +#define __ACNETBSD_H__ + +/* NetBSD uses GCC */ + +#include "acgcc.h" + +#define ACPI_UINTPTR_T uintptr_t +#define ACPI_USE_LOCAL_CACHE +#define ACPI_CAST_PTHREAD_T(x) ((ACPI_THREAD_ID) ACPI_TO_INTEGER (x)) + +#ifdef _LP64 +#define ACPI_MACHINE_WIDTH 64 +#else +#define ACPI_MACHINE_WIDTH 32 +#endif + +#define COMPILER_DEPENDENT_INT64 int64_t +#define COMPILER_DEPENDENT_UINT64 uint64_t + +#if defined(_KERNEL) || defined(_STANDALONE) +#ifdef _KERNEL_OPT +#include "opt_acpi.h" /* collect build-time options here */ +#endif /* _KERNEL_OPT */ + +#include +#include +#include +#include + +#define asm __asm + +#define ACPI_USE_NATIVE_DIVIDE + +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +#ifdef ACPI_DEBUG +#define ACPI_DEBUG_OUTPUT +#define ACPI_DBG_TRACK_ALLOCATIONS +#ifdef DEBUGGER_THREADING +#undef DEBUGGER_THREADING +#endif /* DEBUGGER_THREADING */ +#define DEBUGGER_THREADING 0 /* integrated with DDB */ +#include "opt_ddb.h" +#ifdef DDB +#define ACPI_DISASSEMBLER +#define ACPI_DEBUGGER +#endif /* DDB */ +#endif /* ACPI_DEBUG */ + +#else /* defined(_KERNEL) || defined(_STANDALONE) */ + +#include +#include + +/* Not building kernel code, so use libc */ +#define ACPI_USE_STANDARD_HEADERS + +#define __cli() +#define __sti() +#define __cdecl + +#endif /* defined(_KERNEL) || defined(_STANDALONE) */ + +/* Always use NetBSD code over our local versions */ +#define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_USE_NATIVE_DIVIDE + +#endif /* __ACNETBSD_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acos2.h b/third_party/lib/acpica/source/include/platform/acos2.h new file mode 100644 index 000000000..419579bac --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acos2.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Name: acos2.h - OS/2 specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACOS2_H__ +#define __ACOS2_H__ +#define INCL_LONGLONG +#include + + +#define ACPI_MACHINE_WIDTH 32 + +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long +#define ACPI_USE_NATIVE_DIVIDE + +#define ACPI_SYSTEM_XFACE APIENTRY +#define ACPI_EXTERNAL_XFACE APIENTRY +#define ACPI_INTERNAL_XFACE APIENTRY +#define ACPI_INTERNAL_VAR_XFACE APIENTRY + +/* + * Some compilers complain about unused variables. Sometimes we don't want to + * use all the variables (most specifically for _THIS_MODULE). This allow us + * to to tell the compiler warning in a per-variable manner that a variable + * is unused. + */ +#define ACPI_UNUSED_VAR + +#define ACPI_USE_STANDARD_HEADERS +#include + +#define ACPI_FLUSH_CPU_CACHE() Wbinvd() +void Wbinvd(void); + +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) Acq = OSPMAcquireGlobalLock(GLptr) +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Pnd) Pnd = OSPMReleaseGlobalLock(GLptr) +unsigned short OSPMAcquireGlobalLock (void *); +unsigned short OSPMReleaseGlobalLock (void *); + +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ +{ \ + unsigned long long val = 0LL; \ + val = n_lo | ( ((unsigned long long)h_hi) << 32 ); \ + __llrotr (val,1); \ + n_hi = (unsigned long)((val >> 32 ) & 0xffffffff ); \ + n_lo = (unsigned long)(val & 0xffffffff); \ +} + +#ifndef ACPI_ASL_COMPILER +#define ACPI_USE_LOCAL_CACHE +#undef ACPI_DEBUGGER +#endif + +#endif /* __ACOS2_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acwin.h b/third_party/lib/acpica/source/include/platform/acwin.h new file mode 100644 index 000000000..dd5b334b2 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acwin.h @@ -0,0 +1,146 @@ +/****************************************************************************** + * + * Name: acwin.h - OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACWIN_H__ +#define __ACWIN_H__ + +/*! [Begin] no source code translation (Keep the include) */ + +/* Windows uses VC */ +#ifdef _MSC_VER +#include "acmsvc.h" +#endif +/*! [End] no source code translation !*/ + +#define ACPI_MACHINE_WIDTH 32 + +#define ACPI_USE_STANDARD_HEADERS + +#ifdef ACPI_DEFINE_ALTERNATE_TYPES +/* + * Types used only in (Linux) translated source, defined here to enable + * cross-platform compilation (i.e., generate the Linux code on Windows, + * for test purposes only) + */ +typedef int s32; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef COMPILER_DEPENDENT_UINT64 u64; +#endif + + +/* + * Handle platform- and compiler-specific assembly language differences. + * + * Notes: + * 1) Interrupt 3 is used to break into a debugger + * 2) Interrupts are turned off during ACPI register setup + */ + +/*! [Begin] no source code translation */ + +#ifdef ACPI_APPLICATION +#define ACPI_FLUSH_CPU_CACHE() +#else +#define ACPI_FLUSH_CPU_CACHE() __asm {WBINVD} +#endif + +#ifdef _DEBUG +#define ACPI_SIMPLE_RETURN_MACROS +#endif + +/*! [End] no source code translation !*/ + +/* + * Global Lock acquire/release code + * + * Note: Handles case where the FACS pointer is null + */ +#define ACPI_ACQUIRE_GLOBAL_LOCK(FacsPtr, Acq) __asm \ +{ \ + __asm mov eax, 0xFF \ + __asm mov ecx, FacsPtr \ + __asm or ecx, ecx \ + __asm jz exit_acq \ + __asm lea ecx, [ecx].GlobalLock \ + \ + __asm acq10: \ + __asm mov eax, [ecx] \ + __asm mov edx, eax \ + __asm and edx, 0xFFFFFFFE \ + __asm bts edx, 1 \ + __asm adc edx, 0 \ + __asm lock cmpxchg dword ptr [ecx], edx \ + __asm jnz acq10 \ + \ + __asm cmp dl, 3 \ + __asm sbb eax, eax \ + \ + __asm exit_acq: \ + __asm mov Acq, al \ +} + +#define ACPI_RELEASE_GLOBAL_LOCK(FacsPtr, Pnd) __asm \ +{ \ + __asm xor eax, eax \ + __asm mov ecx, FacsPtr \ + __asm or ecx, ecx \ + __asm jz exit_rel \ + __asm lea ecx, [ecx].GlobalLock \ + \ + __asm Rel10: \ + __asm mov eax, [ecx] \ + __asm mov edx, eax \ + __asm and edx, 0xFFFFFFFC \ + __asm lock cmpxchg dword ptr [ecx], edx \ + __asm jnz Rel10 \ + \ + __asm cmp dl, 3 \ + __asm and eax, 1 \ + \ + __asm exit_rel: \ + __asm mov Pnd, al \ +} + +#endif /* __ACWIN_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acwin64.h b/third_party/lib/acpica/source/include/platform/acwin64.h new file mode 100644 index 000000000..6481f4611 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acwin64.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Name: acwin64.h - OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACWIN64_H__ +#define __ACWIN64_H__ + +/*! [Begin] no source code translation (Keep the include) */ + +#include "acintel.h" +/*! [End] no source code translation !*/ + +#define ACPI_MACHINE_WIDTH 64 + +#define ACPI_USE_STANDARD_HEADERS + +/* + * Handle platform- and compiler-specific assembly language differences. + * + * Notes: + * 1) Interrupt 3 is used to break into a debugger + * 2) Interrupts are turned off during ACPI register setup + */ + +/*! [Begin] no source code translation */ + +#define ACPI_FLUSH_CPU_CACHE() + +/* + * For Acpi applications, we don't want to try to access the global lock + */ +#ifdef ACPI_APPLICATION +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) if (AcpiGbl_GlobalLockPresent) {Acq = 0xFF;} else {Acq = 0;} +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Pnd) if (AcpiGbl_GlobalLockPresent) {Pnd = 0xFF;} else {Pnd = 0;} +#else + +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) + +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Pnd) + +#endif + +/*! [End] no source code translation !*/ + +#endif /* __ACWIN_H__ */ diff --git a/third_party/lib/acpica/source/include/platform/acwinex.h b/third_party/lib/acpica/source/include/platform/acwinex.h new file mode 100644 index 000000000..8c8e21b25 --- /dev/null +++ b/third_party/lib/acpica/source/include/platform/acwinex.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Name: acwinex.h - Extra OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACWINEX_H__ +#define __ACWINEX_H__ + +/* Windows uses VC */ +#ifdef _MSC_VER +#include "acmsvcex.h" +#endif + +#endif /* __ACWINEX_H__ */ diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osbsdtbl.c b/third_party/lib/acpica/source/os_specific/service_layers/osbsdtbl.c new file mode 100644 index 000000000..0fa499f1f --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osbsdtbl.c @@ -0,0 +1,907 @@ +/****************************************************************************** + * + * Module Name: osbsdtbl - BSD OSL for obtaining ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include +#endif +#include +#include +#include + + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("osbsdtbl") + + +/* Local prototypes */ + +static ACPI_STATUS +OslTableInitialize ( + void); + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table); + +static ACPI_STATUS +OslAddTablesToList ( + void); + +static ACPI_STATUS +OslGetTableViaRoot ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + + +/* Hints for RSDP */ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#define SYSTEM_KENV "hint.acpi.0.rsdp" +#define SYSTEM_SYSCTL "machdep.acpi_root" +#elif defined(__NetBSD__) +#define SYSTEM_SYSCTL "hw.acpi.root" +#endif + +/* Initialization flags */ + +UINT8 Gbl_TableListInitialized = FALSE; +UINT8 Gbl_MainTableObtained = FALSE; + +/* Local copies of main ACPI tables */ + +ACPI_TABLE_RSDP Gbl_Rsdp; +ACPI_TABLE_FADT *Gbl_Fadt; +ACPI_TABLE_RSDT *Gbl_Rsdt; +ACPI_TABLE_XSDT *Gbl_Xsdt; + +/* Fadt address */ + +ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress; + +/* Revision of RSD PTR */ + +UINT8 Gbl_Revision; + +/* List of information about obtained ACPI tables */ + +typedef struct table_info +{ + struct table_info *Next; + char Signature[4]; + UINT32 Instance; + ACPI_PHYSICAL_ADDRESS Address; + +} OSL_TABLE_INFO; + +OSL_TABLE_INFO *Gbl_TableListHead = NULL; + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByAddress + * + * PARAMETERS: Address - Physical address of the ACPI table + * Table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get an ACPI table via a physical memory address. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByAddress ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER **Table) +{ + ACPI_TABLE_HEADER *MappedTable; + ACPI_TABLE_HEADER *LocalTable; + ACPI_STATUS Status; + + + /* Validate the input physical address to avoid program crash */ + + if (Address < ACPI_HI_RSDP_WINDOW_BASE) + { + fprintf (stderr, "Invalid table address: 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Address)); + return (AE_BAD_ADDRESS); + } + + /* Map the table and validate it */ + + Status = OslMapTable (Address, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Copy table to local buffer and return it */ + + LocalTable = calloc (1, MappedTable->Length); + if (!LocalTable) + { + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_NO_MEMORY); + } + + memcpy (LocalTable, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + + *Table = LocalTable; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByName + * + * PARAMETERS: Signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByName ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_STATUS Status; + + + /* Instance is only valid for SSDT/UEFI tables */ + + if (Instance && + !ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT) && + !ACPI_COMPARE_NAME (Signature, ACPI_SIG_UEFI)) + { + return (AE_LIMIT); + } + + /* Initialize main tables */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * If one of the main ACPI tables was requested (RSDT/XSDT/FADT), + * simply return it immediately. + */ + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT)) + { + if (!Gbl_Revision) + { + return (AE_NOT_FOUND); + } + + *Address = Gbl_Rsdp.XsdtPhysicalAddress; + *Table = (ACPI_TABLE_HEADER *) Gbl_Xsdt; + return (AE_OK); + } + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT)) + { + if (!Gbl_Rsdp.RsdtPhysicalAddress) + { + return (AE_NOT_FOUND); + } + + *Address = Gbl_Rsdp.RsdtPhysicalAddress; + *Table = (ACPI_TABLE_HEADER *) Gbl_Rsdt; + return (AE_OK); + } + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FADT)) + { + *Address = Gbl_FadtAddress; + *Table = (ACPI_TABLE_HEADER *) Gbl_Fadt; + return (AE_OK); + } + + /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ + + Status = OslGetTableViaRoot (Signature, Instance, Table, Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByIndex + * + * PARAMETERS: Index - Which table to get + * Table - Where a pointer to the table is returned + * Instance - Where a pointer to the table instance no. is + * returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Index is beyond valid limit + * + * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns + * AE_LIMIT when an invalid index is reached. Index is not + * necessarily an index into the RSDT/XSDT. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByIndex ( + UINT32 Index, + ACPI_TABLE_HEADER **Table, + UINT32 *Instance, + ACPI_PHYSICAL_ADDRESS *Address) +{ + OSL_TABLE_INFO *Info; + ACPI_STATUS Status; + UINT32 i; + + + /* Initialize main tables */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Add all tables to list */ + + Status = OslAddTablesToList (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Validate Index */ + + if (Index >= Gbl_TableListHead->Instance) + { + return (AE_LIMIT); + } + + /* Point to the table list entry specified by the Index argument */ + + Info = Gbl_TableListHead; + for (i = 0; i <= Index; i++) + { + Info = Info->Next; + } + + /* Now we can just get the table via the address or name */ + + if (Info->Address) + { + Status = AcpiOsGetTableByAddress (Info->Address, Table); + if (ACPI_SUCCESS (Status)) + { + *Address = Info->Address; + } + } + else + { + Status = AcpiOsGetTableByName (Info->Signature, Info->Instance, + Table, Address); + } + + if (ACPI_SUCCESS (Status)) + { + *Instance = Info->Instance; + } + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslTableInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to + * local variables. Main ACPI tables include RSDP, FADT, RSDT, + * and/or XSDT. + * + *****************************************************************************/ + +static ACPI_STATUS +OslTableInitialize ( + void) +{ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + char Buffer[32]; +#endif + ACPI_TABLE_HEADER *MappedTable; + UINT8 *TableAddress; + UINT8 *RsdpAddress; + ACPI_PHYSICAL_ADDRESS RsdpBase; + ACPI_SIZE RsdpSize; + ACPI_STATUS Status; + u_long Address = 0; + size_t Length = sizeof (Address); + + + /* Get main ACPI tables from memory on first invocation of this function */ + + if (Gbl_MainTableObtained) + { + return (AE_OK); + } + + /* Attempt to use kenv or sysctl to find RSD PTR record. */ + + if (Gbl_RsdpBase) + { + Address = Gbl_RsdpBase; + } +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + else if (kenv (KENV_GET, SYSTEM_KENV, Buffer, sizeof (Buffer)) > 0) + { + Address = strtoul (Buffer, NULL, 0); + } +#endif + if (!Address) + { + if (sysctlbyname (SYSTEM_SYSCTL, &Address, &Length, NULL, 0) != 0) + { + Address = 0; + } + } + if (Address) + { + RsdpBase = Address; + RsdpSize = sizeof (Gbl_Rsdp); + } + else + { + RsdpBase = ACPI_HI_RSDP_WINDOW_BASE; + RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE; + } + + /* Get RSDP from memory */ + + RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize); + if (!RsdpAddress) + { + return (AE_BAD_ADDRESS); + } + + /* Search low memory for the RSDP */ + + TableAddress = AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize); + if (!TableAddress) + { + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + return (AE_ERROR); + } + + memcpy (&Gbl_Rsdp, TableAddress, sizeof (Gbl_Rsdp)); + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + + /* Get XSDT from memory */ + + if (Gbl_Rsdp.Revision) + { + Status = OslMapTable (Gbl_Rsdp.XsdtPhysicalAddress, + ACPI_SIG_XSDT, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_Revision = 2; + Gbl_Xsdt = calloc (1, MappedTable->Length); + if (!Gbl_Xsdt) + { + fprintf (stderr, + "XSDT: Could not allocate buffer for table of length %X\n", + MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_NO_MEMORY); + } + + memcpy (Gbl_Xsdt, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + } + + /* Get RSDT from memory */ + + if (Gbl_Rsdp.RsdtPhysicalAddress) + { + Status = OslMapTable (Gbl_Rsdp.RsdtPhysicalAddress, + ACPI_SIG_RSDT, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_Rsdt = calloc (1, MappedTable->Length); + if (!Gbl_Rsdt) + { + fprintf (stderr, + "RSDT: Could not allocate buffer for table of length %X\n", + MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_NO_MEMORY); + } + + memcpy (Gbl_Rsdt, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + } + + /* Get FADT from memory */ + + if (Gbl_Revision) + { + Gbl_FadtAddress = Gbl_Xsdt->TableOffsetEntry[0]; + } + else + { + Gbl_FadtAddress = Gbl_Rsdt->TableOffsetEntry[0]; + } + + if (!Gbl_FadtAddress) + { + fprintf(stderr, "FADT: Table could not be found\n"); + return (AE_ERROR); + } + + Status = OslMapTable (Gbl_FadtAddress, ACPI_SIG_FADT, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Gbl_Fadt = calloc (1, MappedTable->Length); + if (!Gbl_Fadt) + { + fprintf (stderr, + "FADT: Could not allocate buffer for table of length %X\n", + MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_NO_MEMORY); + } + + memcpy (Gbl_Fadt, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + Gbl_MainTableObtained = TRUE; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetTableViaRoot + * + * PARAMETERS: Signature - ACPI Signature for common table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get an ACPI table via the root table (RSDT/XSDT) + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetTableViaRoot ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_TABLE_HEADER *LocalTable = NULL; + ACPI_TABLE_HEADER *MappedTable = NULL; + UINT8 NumberOfTables; + UINT32 CurrentInstance = 0; + ACPI_PHYSICAL_ADDRESS TableAddress = 0; + ACPI_STATUS Status; + UINT32 i; + + + /* DSDT and FACS address must be extracted from the FADT */ + + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + /* + * Get the appropriate address, either 32-bit or 64-bit. Be very + * careful about the FADT length and validate table addresses. + * Note: The 64-bit addresses have priority. + */ + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT)) + { + if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) && + Gbl_Fadt->XDsdt) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt; + } + else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) && + Gbl_Fadt->Dsdt) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt; + } + } + else /* FACS */ + { + if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) && + Gbl_Fadt->XFacs) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs; + } + else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) && + Gbl_Fadt->Facs) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs; + } + } + } + else /* Case for a normal ACPI table */ + { + if (Gbl_Revision) + { + NumberOfTables = + (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header)) + / sizeof (Gbl_Xsdt->TableOffsetEntry[0]); + } + else /* Use RSDT if XSDT is not available */ + { + NumberOfTables = + (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header)) + / sizeof (Gbl_Rsdt->TableOffsetEntry[0]); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < NumberOfTables; i++) + { + if (Gbl_Revision) + { + TableAddress = Gbl_Xsdt->TableOffsetEntry[i]; + } + else + { + TableAddress = Gbl_Rsdt->TableOffsetEntry[i]; + } + + MappedTable = AcpiOsMapMemory (TableAddress, sizeof (*MappedTable)); + if (!MappedTable) + { + return (AE_BAD_ADDRESS); + } + + /* Does this table match the requested signature? */ + + if (ACPI_COMPARE_NAME (MappedTable->Signature, Signature)) + { + + /* Match table instance (for SSDT/UEFI tables) */ + + if (CurrentInstance == Instance) + { + AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable)); + break; + } + + CurrentInstance++; + } + + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + TableAddress = 0; + } + } + + if (!TableAddress) + { + if (CurrentInstance) + { + return (AE_LIMIT); + } + return (AE_NOT_FOUND); + } + + /* Now we can get the requested table */ + + Status = OslMapTable (TableAddress, Signature, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Copy table to local buffer and return it */ + + LocalTable = calloc (1, MappedTable->Length); + if (!LocalTable) + { + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + return (AE_NO_MEMORY); + } + + memcpy (LocalTable, MappedTable, MappedTable->Length); + AcpiOsUnmapMemory (MappedTable, MappedTable->Length); + *Table = LocalTable; + *Address = TableAddress; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslAddTablesToList + * + * PARAMETERS: None + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list. + * + *****************************************************************************/ + +static ACPI_STATUS +OslAddTablesToList( + void) +{ + ACPI_PHYSICAL_ADDRESS TableAddress; + OSL_TABLE_INFO *Info = NULL; + OSL_TABLE_INFO *NewInfo; + ACPI_TABLE_HEADER *Table; + UINT8 Instance; + UINT8 NumberOfTables; + int i; + + + /* Initialize the table list on first invocation */ + + if (Gbl_TableListInitialized) + { + return (AE_OK); + } + + /* Add mandatory tables to global table list first */ + + for (i = 0; i < 4; i++) + { + NewInfo = calloc (1, sizeof (*NewInfo)); + if (!NewInfo) + { + return (AE_NO_MEMORY); + } + + switch (i) { + case 0: + + Gbl_TableListHead = Info = NewInfo; + continue; + + case 1: + + ACPI_MOVE_NAME (NewInfo->Signature, + Gbl_Revision ? ACPI_SIG_XSDT : ACPI_SIG_RSDT); + break; + + case 2: + + ACPI_MOVE_NAME (NewInfo->Signature, ACPI_SIG_FACS); + break; + + default: + + ACPI_MOVE_NAME (NewInfo->Signature, ACPI_SIG_DSDT); + + } + + Info->Next = NewInfo; + Info = NewInfo; + Gbl_TableListHead->Instance++; + } + + /* Add normal tables from RSDT/XSDT to global list */ + + if (Gbl_Revision) + { + NumberOfTables = + (Gbl_Xsdt->Header.Length - sizeof (Gbl_Xsdt->Header)) + / sizeof (Gbl_Xsdt->TableOffsetEntry[0]); + } + else + { + NumberOfTables = + (Gbl_Rsdt->Header.Length - sizeof (Gbl_Rsdt->Header)) + / sizeof (Gbl_Rsdt->TableOffsetEntry[0]); + } + + for (i = 0; i < NumberOfTables; i++) + { + if (Gbl_Revision) + { + TableAddress = Gbl_Xsdt->TableOffsetEntry[i]; + } + else + { + TableAddress = Gbl_Rsdt->TableOffsetEntry[i]; + } + + Table = AcpiOsMapMemory (TableAddress, sizeof (*Table)); + if (!Table) + { + return (AE_BAD_ADDRESS); + } + + Instance = 0; + NewInfo = Gbl_TableListHead; + while (NewInfo->Next != NULL) + { + NewInfo = NewInfo->Next; + if (ACPI_COMPARE_NAME (Table->Signature, NewInfo->Signature)) + { + Instance++; + } + } + + NewInfo = calloc (1, sizeof (*NewInfo)); + if (!NewInfo) + { + AcpiOsUnmapMemory (Table, sizeof (*Table)); + return (AE_NO_MEMORY); + } + + ACPI_MOVE_NAME (NewInfo->Signature, Table->Signature); + + AcpiOsUnmapMemory (Table, sizeof (*Table)); + + NewInfo->Instance = Instance; + NewInfo->Address = TableAddress; + Info->Next = NewInfo; + Info = NewInfo; + Gbl_TableListHead->Instance++; + } + + Gbl_TableListInitialized = TRUE; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslMapTable + * + * PARAMETERS: Address - Address of the table in memory + * Signature - Optional ACPI Signature for desired table. + * Null terminated 4-character string. + * Table - Where a pointer to the mapped table is + * returned + * + * RETURN: Status; Mapped table is returned if AE_OK. + * + * DESCRIPTION: Map entire ACPI table into caller's address space. Also + * validates the table and checksum. + * + *****************************************************************************/ + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table) +{ + ACPI_TABLE_HEADER *MappedTable; + UINT32 Length; + + + /* Map the header so we can get the table length */ + + MappedTable = AcpiOsMapMemory (Address, sizeof (*MappedTable)); + if (!MappedTable) + { + return (AE_BAD_ADDRESS); + } + + /* Check if table is valid */ + + if (!ApIsValidHeader (MappedTable)) + { + AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable)); + return (AE_BAD_HEADER); + } + + /* If specified, signature must match */ + + if (Signature && + !ACPI_COMPARE_NAME (Signature, MappedTable->Signature)) + { + AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable)); + return (AE_NOT_EXIST); + } + + /* Map the entire table */ + + Length = MappedTable->Length; + AcpiOsUnmapMemory (MappedTable, sizeof (*MappedTable)); + + MappedTable = AcpiOsMapMemory (Address, Length); + if (!MappedTable) + { + return (AE_BAD_ADDRESS); + } + + (void) ApIsValidChecksum (MappedTable); + + *Table = MappedTable; + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osefitbl.c b/third_party/lib/acpica/source/os_specific/service_layers/osefitbl.c new file mode 100644 index 000000000..ef95e164b --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osefitbl.c @@ -0,0 +1,1033 @@ +/****************************************************************************** + * + * Module Name: osefitbl - EFI OSL for obtaining ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" + + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("osefitbl") + + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + + +/* List of information about obtained ACPI tables */ + +typedef struct osl_table_info +{ + struct osl_table_info *Next; + UINT32 Instance; + char Signature[ACPI_NAME_SIZE]; + +} OSL_TABLE_INFO; + +/* Local prototypes */ + +static ACPI_STATUS +OslTableInitialize ( + void); + +static ACPI_STATUS +OslAddTableToList ( + char *Signature, + UINT32 Instance); + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table); + +static void +OslUnmapTable ( + ACPI_TABLE_HEADER *Table); + +static ACPI_STATUS +OslLoadRsdp ( + void); + +static ACPI_STATUS +OslListTables ( + void); + +static ACPI_STATUS +OslGetTable ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + + +/* File locations */ + +#define EFI_SYSTAB "/sys/firmware/efi/systab" + +/* Initialization flags */ + +UINT8 Gbl_TableListInitialized = FALSE; + +/* Local copies of main ACPI tables */ + +ACPI_TABLE_RSDP Gbl_Rsdp; +ACPI_TABLE_FADT *Gbl_Fadt = NULL; +ACPI_TABLE_RSDT *Gbl_Rsdt = NULL; +ACPI_TABLE_XSDT *Gbl_Xsdt = NULL; + +/* Table addresses */ + +ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0; +ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0; + +/* Revision of RSD PTR */ + +UINT8 Gbl_Revision = 0; + +OSL_TABLE_INFO *Gbl_TableListHead = NULL; +UINT32 Gbl_TableCount = 0; + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByAddress + * + * PARAMETERS: Address - Physical address of the ACPI table + * Table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get an ACPI table via a physical memory address. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByAddress ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER **Table) +{ + UINT32 TableLength; + ACPI_TABLE_HEADER *MappedTable; + ACPI_TABLE_HEADER *LocalTable = NULL; + ACPI_STATUS Status = AE_OK; + + + /* Get main ACPI tables from memory on first invocation of this function */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Map the table and validate it */ + + Status = OslMapTable (Address, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Copy table to local buffer and return it */ + + TableLength = ApGetTableLength (MappedTable); + if (TableLength == 0) + { + Status = AE_BAD_HEADER; + goto Exit; + } + + LocalTable = ACPI_ALLOCATE_ZEROED (TableLength); + if (!LocalTable) + { + Status = AE_NO_MEMORY; + goto Exit; + } + + memcpy (LocalTable, MappedTable, TableLength); + +Exit: + OslUnmapTable (MappedTable); + *Table = LocalTable; + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByName + * + * PARAMETERS: Signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByName ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_STATUS Status; + + + /* Get main ACPI tables from memory on first invocation of this function */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ + + if (!Gbl_DumpCustomizedTables) + { + /* Attempt to get the table from the memory */ + + Status = OslGetTable (Signature, Instance, Table, Address); + } + else + { + /* Attempt to get the table from the static directory */ + + Status = AE_SUPPORT; + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslAddTableToList + * + * PARAMETERS: Signature - Table signature + * Instance - Table instance + * + * RETURN: Status; Successfully added if AE_OK. + * AE_NO_MEMORY: Memory allocation error + * + * DESCRIPTION: Insert a table structure into OSL table list. + * + *****************************************************************************/ + +static ACPI_STATUS +OslAddTableToList ( + char *Signature, + UINT32 Instance) +{ + OSL_TABLE_INFO *NewInfo; + OSL_TABLE_INFO *Next; + UINT32 NextInstance = 0; + BOOLEAN Found = FALSE; + + + NewInfo = ACPI_ALLOCATE_ZEROED (sizeof (OSL_TABLE_INFO)); + if (!NewInfo) + { + return (AE_NO_MEMORY); + } + + ACPI_MOVE_NAME (NewInfo->Signature, Signature); + + if (!Gbl_TableListHead) + { + Gbl_TableListHead = NewInfo; + } + else + { + Next = Gbl_TableListHead; + while (1) + { + if (ACPI_COMPARE_NAME (Next->Signature, Signature)) + { + if (Next->Instance == Instance) + { + Found = TRUE; + } + if (Next->Instance >= NextInstance) + { + NextInstance = Next->Instance + 1; + } + } + + if (!Next->Next) + { + break; + } + Next = Next->Next; + } + Next->Next = NewInfo; + } + + if (Found) + { + if (Instance) + { + AcpiLogError ( + "%4.4s: Warning unmatched table instance %d, expected %d\n", + Signature, Instance, NextInstance); + } + Instance = NextInstance; + } + + NewInfo->Instance = Instance; + Gbl_TableCount++; + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByIndex + * + * PARAMETERS: Index - Which table to get + * Table - Where a pointer to the table is returned + * Instance - Where a pointer to the table instance no. is + * returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Index is beyond valid limit + * + * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns + * AE_LIMIT when an invalid index is reached. Index is not + * necessarily an index into the RSDT/XSDT. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByIndex ( + UINT32 Index, + ACPI_TABLE_HEADER **Table, + UINT32 *Instance, + ACPI_PHYSICAL_ADDRESS *Address) +{ + OSL_TABLE_INFO *Info; + ACPI_STATUS Status; + UINT32 i; + + + /* Get main ACPI tables from memory on first invocation of this function */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Validate Index */ + + if (Index >= Gbl_TableCount) + { + return (AE_LIMIT); + } + + /* Point to the table list entry specified by the Index argument */ + + Info = Gbl_TableListHead; + for (i = 0; i < Index; i++) + { + Info = Info->Next; + } + + /* Now we can just get the table via the signature */ + + Status = AcpiOsGetTableByName (Info->Signature, Info->Instance, + Table, Address); + + if (ACPI_SUCCESS (Status)) + { + *Instance = Info->Instance; + } + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslLoadRsdp + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Scan and load RSDP. + * + *****************************************************************************/ + +static ACPI_STATUS +OslLoadRsdp ( + void) +{ + ACPI_TABLE_HEADER *MappedTable; + UINT8 *RsdpAddress; + ACPI_PHYSICAL_ADDRESS RsdpBase; + ACPI_SIZE RsdpSize; + + + /* Get RSDP from memory */ + + RsdpSize = sizeof (ACPI_TABLE_RSDP); + if (Gbl_RsdpBase) + { + RsdpBase = Gbl_RsdpBase; + } + else + { + RsdpBase = AcpiOsGetRootPointer (); + } + + if (!RsdpBase) + { + RsdpBase = ACPI_HI_RSDP_WINDOW_BASE; + RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE; + } + + RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize); + if (!RsdpAddress) + { + return (AE_BAD_ADDRESS); + } + + /* Search low memory for the RSDP */ + + MappedTable = ACPI_CAST_PTR (ACPI_TABLE_HEADER, + AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize)); + if (!MappedTable) + { + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + return (AE_NOT_FOUND); + } + + Gbl_RsdpAddress = RsdpBase + (ACPI_CAST8 (MappedTable) - RsdpAddress); + + memcpy (&Gbl_Rsdp, MappedTable, sizeof (ACPI_TABLE_RSDP)); + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslCanUseXsdt + * + * PARAMETERS: None + * + * RETURN: TRUE if XSDT is allowed to be used. + * + * DESCRIPTION: This function collects logic that can be used to determine if + * XSDT should be used instead of RSDT. + * + *****************************************************************************/ + +static BOOLEAN +OslCanUseXsdt ( + void) +{ + if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) + { + return (TRUE); + } + else + { + return (FALSE); + } +} + + +/****************************************************************************** + * + * FUNCTION: OslTableInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to + * local variables. Main ACPI tables include RSDT, FADT, RSDT, + * and/or XSDT. + * + *****************************************************************************/ + +static ACPI_STATUS +OslTableInitialize ( + void) +{ + ACPI_STATUS Status; + ACPI_PHYSICAL_ADDRESS Address; + + + if (Gbl_TableListInitialized) + { + return (AE_OK); + } + + /* Get RSDP from memory */ + + Status = OslLoadRsdp (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Get XSDT from memory */ + + if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) + { + if (Gbl_Xsdt) + { + ACPI_FREE (Gbl_Xsdt); + Gbl_Xsdt = NULL; + } + + Gbl_Revision = 2; + Status = OslGetTable (ACPI_SIG_XSDT, 0, + ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Get RSDT from memory */ + + if (Gbl_Rsdp.RsdtPhysicalAddress) + { + if (Gbl_Rsdt) + { + ACPI_FREE (Gbl_Rsdt); + Gbl_Rsdt = NULL; + } + + Status = OslGetTable (ACPI_SIG_RSDT, 0, + ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Get FADT from memory */ + + if (Gbl_Fadt) + { + ACPI_FREE (Gbl_Fadt); + Gbl_Fadt = NULL; + } + + Status = OslGetTable (ACPI_SIG_FADT, 0, + ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (!Gbl_DumpCustomizedTables) + { + /* Add mandatory tables to global table list first */ + + Status = OslAddTableToList (ACPI_RSDP_NAME, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = OslAddTableToList (ACPI_SIG_RSDT, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Gbl_Revision == 2) + { + Status = OslAddTableToList (ACPI_SIG_XSDT, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + Status = OslAddTableToList (ACPI_SIG_DSDT, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = OslAddTableToList (ACPI_SIG_FACS, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Add all tables found in the memory */ + + Status = OslListTables (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* Add all tables found in the static directory */ + + Status = AE_SUPPORT; + } + + Gbl_TableListInitialized = TRUE; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslListTables + * + * PARAMETERS: None + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from memory. + * + *****************************************************************************/ + +static ACPI_STATUS +OslListTables ( + void) +{ + ACPI_TABLE_HEADER *MappedTable = NULL; + UINT8 *TableData; + UINT8 NumberOfTables; + UINT8 ItemSize; + ACPI_PHYSICAL_ADDRESS TableAddress = 0; + ACPI_STATUS Status = AE_OK; + UINT32 i; + + + if (OslCanUseXsdt ()) + { + ItemSize = sizeof (UINT64); + TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + else /* Use RSDT if XSDT is not available */ + { + ItemSize = sizeof (UINT32); + TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) + { + if (OslCanUseXsdt ()) + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); + } + else + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); + } + + /* Skip NULL entries in RSDT/XSDT */ + + if (!TableAddress) + { + continue; + } + + Status = OslMapTable (TableAddress, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + OslAddTableToList (MappedTable->Signature, 0); + OslUnmapTable (MappedTable); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetTable + * + * PARAMETERS: Signature - ACPI Signature for common table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get a BIOS provided ACPI table + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetTable ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_TABLE_HEADER *LocalTable = NULL; + ACPI_TABLE_HEADER *MappedTable = NULL; + UINT8 *TableData; + UINT8 NumberOfTables; + UINT8 ItemSize; + UINT32 CurrentInstance = 0; + ACPI_PHYSICAL_ADDRESS TableAddress = 0; + UINT32 TableLength = 0; + ACPI_STATUS Status = AE_OK; + UINT32 i; + + + /* Handle special tables whose addresses are not in RSDT/XSDT */ + + if (ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + /* + * Get the appropriate address, either 32-bit or 64-bit. Be very + * careful about the FADT length and validate table addresses. + * Note: The 64-bit addresses have priority. + */ + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT)) + { + if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) && + Gbl_Fadt->XDsdt) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt; + } + else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) && + Gbl_Fadt->Dsdt) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt; + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) && + Gbl_Fadt->XFacs) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs; + } + else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) && + Gbl_Fadt->Facs) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs; + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT)) + { + if (!Gbl_Revision) + { + return (AE_BAD_SIGNATURE); + } + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress; + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT)) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress; + } + else + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress; + Signature = ACPI_SIG_RSDP; + } + + /* Now we can get the requested special table */ + + Status = OslMapTable (TableAddress, Signature, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + TableLength = ApGetTableLength (MappedTable); + } + else /* Case for a normal ACPI table */ + { + if (OslCanUseXsdt ()) + { + ItemSize = sizeof (UINT64); + TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + else /* Use RSDT if XSDT is not available */ + { + ItemSize = sizeof (UINT32); + TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) + { + if (OslCanUseXsdt ()) + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); + } + else + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); + } + + /* Skip NULL entries in RSDT/XSDT */ + + if (!TableAddress) + { + continue; + } + + Status = OslMapTable (TableAddress, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + TableLength = MappedTable->Length; + + /* Does this table match the requested signature? */ + + if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature)) + { + OslUnmapTable (MappedTable); + MappedTable = NULL; + continue; + } + + /* Match table instance (for SSDT/UEFI tables) */ + + if (CurrentInstance != Instance) + { + OslUnmapTable (MappedTable); + MappedTable = NULL; + CurrentInstance++; + continue; + } + + break; + } + } + + if (!MappedTable) + { + return (AE_LIMIT); + } + + if (TableLength == 0) + { + Status = AE_BAD_HEADER; + goto Exit; + } + + /* Copy table to local buffer and return it */ + + LocalTable = ACPI_ALLOCATE_ZEROED (TableLength); + if (!LocalTable) + { + Status = AE_NO_MEMORY; + goto Exit; + } + + memcpy (LocalTable, MappedTable, TableLength); + *Address = TableAddress; + *Table = LocalTable; + +Exit: + OslUnmapTable (MappedTable); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslMapTable + * + * PARAMETERS: Address - Address of the table in memory + * Signature - Optional ACPI Signature for desired table. + * Null terminated 4-character string. + * Table - Where a pointer to the mapped table is + * returned + * + * RETURN: Status; Mapped table is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Map entire ACPI table into caller's address space. + * + *****************************************************************************/ + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table) +{ + ACPI_TABLE_HEADER *MappedTable; + UINT32 Length; + + + if (!Address) + { + return (AE_BAD_ADDRESS); + } + + /* + * Map the header so we can get the table length. + * Use sizeof (ACPI_TABLE_HEADER) as: + * 1. it is bigger than 24 to include RSDP->Length + * 2. it is smaller than sizeof (ACPI_TABLE_RSDP) + */ + MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); + if (!MappedTable) + { + AcpiLogError ("Could not map table header at 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Address)); + return (AE_BAD_ADDRESS); + } + + /* If specified, signature must match */ + + if (Signature) + { + if (ACPI_VALIDATE_RSDP_SIG (Signature)) + { + if (!ACPI_VALIDATE_RSDP_SIG (MappedTable->Signature)) + { + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + return (AE_BAD_SIGNATURE); + } + } + else if (!ACPI_COMPARE_NAME (Signature, MappedTable->Signature)) + { + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + return (AE_BAD_SIGNATURE); + } + } + + /* Map the entire table */ + + Length = ApGetTableLength (MappedTable); + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + if (Length == 0) + { + return (AE_BAD_HEADER); + } + + MappedTable = AcpiOsMapMemory (Address, Length); + if (!MappedTable) + { + AcpiLogError ("Could not map table at 0x%8.8X%8.8X length %8.8X\n", + ACPI_FORMAT_UINT64 (Address), Length); + return (AE_INVALID_TABLE_LENGTH); + } + + (void) ApIsValidChecksum (MappedTable); + + *Table = MappedTable; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslUnmapTable + * + * PARAMETERS: Table - A pointer to the mapped table + * + * RETURN: None + * + * DESCRIPTION: Unmap entire ACPI table. + * + *****************************************************************************/ + +static void +OslUnmapTable ( + ACPI_TABLE_HEADER *Table) +{ + if (Table) + { + AcpiOsUnmapMemory (Table, ApGetTableLength (Table)); + } +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osefixf.c b/third_party/lib/acpica/source/os_specific/service_layers/osefixf.c new file mode 100644 index 000000000..091c0eae6 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osefixf.c @@ -0,0 +1,1091 @@ +/****************************************************************************** + * + * Module Name: osefixf - EFI OSL interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("osefixf") + + +/* Local definitions */ + +#define ACPI_EFI_PRINT_LENGTH 256 + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiEfiArgify ( + char *String, + int *ArgcPtr, + char ***ArgvPtr); + +static BOOLEAN +AcpiEfiCompareGuid ( + EFI_GUID *Guid1, + EFI_GUID *Guid2); + +static ACPI_STATUS +AcpiEfiConvertArgcv ( + CHAR16 *LoadOpt, + UINT32 LoadOptSize, + int *ArgcPtr, + char ***ArgvPtr, + char **BufferPtr); + +static ACPI_PHYSICAL_ADDRESS +AcpiEfiGetRsdpViaGuid ( + EFI_GUID *Guid); + +static CHAR16 * +AcpiEfiFlushFile ( + ACPI_FILE File, + CHAR16 *Begin, + CHAR16 *End, + CHAR16 *Pos, + BOOLEAN FlushAll); + + +/* Local variables */ + +static EFI_FILE_HANDLE AcpiGbl_EfiCurrentVolume = NULL; +EFI_GUID AcpiGbl_LoadedImageProtocol = LOADED_IMAGE_PROTOCOL; +EFI_GUID AcpiGbl_TextInProtocol = SIMPLE_TEXT_INPUT_PROTOCOL; +EFI_GUID AcpiGbl_TextOutProtocol = SIMPLE_TEXT_OUTPUT_PROTOCOL; +EFI_GUID AcpiGbl_FileSystemProtocol = SIMPLE_FILE_SYSTEM_PROTOCOL; + + +/****************************************************************************** + * + * FUNCTION: AcpiEfiGetRsdpViaGuid + * + * PARAMETERS: Guid1 - GUID to compare + * Guid2 - GUID to compare + * + * RETURN: TRUE if Guid1 == Guid2 + * + * DESCRIPTION: Compares two GUIDs + * + *****************************************************************************/ + +static BOOLEAN +AcpiEfiCompareGuid ( + EFI_GUID *Guid1, + EFI_GUID *Guid2) +{ + INT32 *g1; + INT32 *g2; + INT32 r; + + + g1 = (INT32 *) Guid1; + g2 = (INT32 *) Guid2; + + r = g1[0] - g2[0]; + r |= g1[1] - g2[1]; + r |= g1[2] - g2[2]; + r |= g1[3] - g2[3]; + + return (r ? FALSE : TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiEfiGetRsdpViaGuid + * + * PARAMETERS: None + * + * RETURN: RSDP address if found + * + * DESCRIPTION: Find RSDP address via EFI using specified GUID. + * + *****************************************************************************/ + +static ACPI_PHYSICAL_ADDRESS +AcpiEfiGetRsdpViaGuid ( + EFI_GUID *Guid) +{ + ACPI_PHYSICAL_ADDRESS Address = 0; + int i; + + + for (i = 0; i < ST->NumberOfTableEntries; i++) + { + if (AcpiEfiCompareGuid (&ST->ConfigurationTable[i].VendorGuid, Guid)) + { + Address = ACPI_PTR_TO_PHYSADDR ( + ST->ConfigurationTable[i].VendorTable); + break; + } + } + + return (Address); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetRootPointer + * + * PARAMETERS: None + * + * RETURN: RSDP physical address + * + * DESCRIPTION: Gets the ACPI root pointer (RSDP) + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + ACPI_PHYSICAL_ADDRESS Address; + EFI_GUID Guid10 = ACPI_TABLE_GUID; + EFI_GUID Guid20 = ACPI_20_TABLE_GUID; + + + Address = AcpiEfiGetRsdpViaGuid (&Guid20); + if (!Address) + { + Address = AcpiEfiGetRsdpViaGuid (&Guid10); + } + + return (Address); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsMapMemory + * + * PARAMETERS: where - Physical address of memory to be mapped + * length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into caller's address space + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS where, + ACPI_SIZE length) +{ + + return (ACPI_TO_POINTER ((ACPI_SIZE) where)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: where - Logical address of memory to be unmapped + * length - How much memory to unmap + * + * RETURN: None + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *where, + ACPI_SIZE length) +{ + + return; +} + + +/****************************************************************************** + * + * FUNCTION: Spinlock interfaces + * + * DESCRIPTION: No-op on single threaded BIOS + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateLock ( + ACPI_SPINLOCK *OutHandle) +{ + return (AE_OK); +} + +void +AcpiOsDeleteLock ( + ACPI_SPINLOCK Handle) +{ +} + +ACPI_CPU_FLAGS +AcpiOsAcquireLock ( + ACPI_SPINLOCK Handle) +{ + return (0); +} + +void +AcpiOsReleaseLock ( + ACPI_SPINLOCK Handle, + ACPI_CPU_FLAGS Flags) +{ +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocate + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocate ( + ACPI_SIZE Size) +{ + EFI_STATUS EfiStatus; + void *Mem; + + + EfiStatus = uefi_call_wrapper (BS->AllocatePool, 3, + EfiLoaderData, Size, &Mem); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_BOOT_SERVICES->AllocatePool(EfiLoaderData) failure.\n"); + return (NULL); + } + + return (Mem); +} + + +#ifdef USE_NATIVE_ALLOCATE_ZEROED +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocateZeroed + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate and zero memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE Size) +{ + void *Mem; + + + Mem = AcpiOsAllocate (Size); + if (Mem) + { + memset (Mem, 0, Size); + } + + return (Mem); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsFree + * + * PARAMETERS: Mem - Pointer to previously allocated memory + * + * RETURN: None + * + * DESCRIPTION: Free memory allocated via AcpiOsAllocate + * + *****************************************************************************/ + +void +AcpiOsFree ( + void *Mem) +{ + + uefi_call_wrapper (BS->FreePool, 1, Mem); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsOpenFile + * + * PARAMETERS: Path - File path + * Modes - File operation type + * + * RETURN: File descriptor + * + * DESCRIPTION: Open a file for reading (ACPI_FILE_READING) or/and writing + * (ACPI_FILE_WRITING). + * + ******************************************************************************/ + +ACPI_FILE +AcpiOsOpenFile ( + const char *Path, + UINT8 Modes) +{ + EFI_STATUS EfiStatus = EFI_SUCCESS; + UINT64 OpenModes; + EFI_FILE_HANDLE EfiFile = NULL; + CHAR16 *Path16 = NULL; + CHAR16 *Pos16; + const char *Pos; + INTN Count, i; + + + if (!Path) + { + return (NULL); + } + + /* Convert modes */ + + OpenModes = EFI_FILE_MODE_READ; + if (Modes & ACPI_FILE_WRITING) + { + OpenModes |= (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE); + } + + /* Allocate path buffer */ + + Count = strlen (Path); + Path16 = ACPI_ALLOCATE_ZEROED ((Count + 1) * sizeof (CHAR16)); + if (!Path16) + { + EfiStatus = EFI_BAD_BUFFER_SIZE; + goto ErrorExit; + } + Pos = Path; + Pos16 = Path16; + while (*Pos == '/' || *Pos == '\\') + { + Pos++; + Count--; + } + for (i = 0; i < Count; i++) + { + if (*Pos == '/') + { + *Pos16++ = '\\'; + Pos++; + } + else + { + *Pos16++ = *Pos++; + } + } + *Pos16 = '\0'; + + EfiStatus = uefi_call_wrapper (AcpiGbl_EfiCurrentVolume->Open, 5, + AcpiGbl_EfiCurrentVolume, &EfiFile, Path16, OpenModes, 0); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_FILE_HANDLE->Open() failure.\n"); + goto ErrorExit; + } + +ErrorExit: + + if (Path16) + { + ACPI_FREE (Path16); + } + + return ((ACPI_FILE) EfiFile); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsCloseFile + * + * PARAMETERS: File - File descriptor + * + * RETURN: None. + * + * DESCRIPTION: Close a file. + * + ******************************************************************************/ + +void +AcpiOsCloseFile ( + ACPI_FILE File) +{ + EFI_FILE_HANDLE EfiFile; + + + if (File == ACPI_FILE_OUT || + File == ACPI_FILE_ERR) + { + return; + } + EfiFile = (EFI_FILE_HANDLE) File; + (void) uefi_call_wrapper (AcpiGbl_EfiCurrentVolume->Close, 1, EfiFile); + + return; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsReadFile + * + * PARAMETERS: File - File descriptor + * Buffer - Data buffer + * Size - Data block size + * Count - Number of data blocks + * + * RETURN: Size of successfully read buffer + * + * DESCRIPTION: Read from a file. + * + ******************************************************************************/ + +int +AcpiOsReadFile ( + ACPI_FILE File, + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count) +{ + int Length = -1; + EFI_FILE_HANDLE EfiFile; + UINTN ReadSize; + EFI_STATUS EfiStatus; + + + if (File == ACPI_FILE_OUT || + File == ACPI_FILE_ERR) + { + } + else + { + EfiFile = (EFI_FILE_HANDLE) File; + if (!EfiFile) + { + goto ErrorExit; + } + ReadSize = Size * Count; + + EfiStatus = uefi_call_wrapper (AcpiGbl_EfiCurrentVolume->Read, 3, + EfiFile, &ReadSize, Buffer); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_FILE_HANDLE->Read() failure.\n"); + goto ErrorExit; + } + Length = ReadSize; + } + +ErrorExit: + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEfiFlushFile + * + * PARAMETERS: File - File descriptor + * Begin - String with boundary + * End - Boundary of the string + * Pos - Current position + * FlushAll - Whether checking boundary before flushing + * + * RETURN: Updated position + * + * DESCRIPTION: Flush cached buffer to the file. + * + ******************************************************************************/ + +static CHAR16 * +AcpiEfiFlushFile ( + ACPI_FILE File, + CHAR16 *Begin, + CHAR16 *End, + CHAR16 *Pos, + BOOLEAN FlushAll) +{ + + if (FlushAll || Pos >= (End - 1)) + { + *Pos = 0; + uefi_call_wrapper (File->OutputString, 2, File, Begin); + Pos = Begin; + } + + return (Pos); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsWriteFile + * + * PARAMETERS: File - File descriptor + * Buffer - Data buffer + * Size - Data block size + * Count - Number of data blocks + * + * RETURN: Size of successfully written buffer + * + * DESCRIPTION: Write to a file. + * + ******************************************************************************/ + +int +AcpiOsWriteFile ( + ACPI_FILE File, + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count) +{ + int Length = -1; + CHAR16 String[ACPI_EFI_PRINT_LENGTH]; + const char *Ascii; + CHAR16 *End; + CHAR16 *Pos; + int i, j; + EFI_FILE_HANDLE EfiFile; + UINTN WriteSize; + EFI_STATUS EfiStatus; + + + if (File == ACPI_FILE_OUT || + File == ACPI_FILE_ERR) + { + Pos = String; + End = String + ACPI_EFI_PRINT_LENGTH - 1; + Ascii = ACPI_CAST_PTR (const char, Buffer); + Length = 0; + + for (j = 0; j < Count; j++) + { + for (i = 0; i < Size; i++) + { + if (*Ascii == '\n') + { + *Pos++ = '\r'; + Pos = AcpiEfiFlushFile (File, String, + End, Pos, FALSE); + } + *Pos++ = *Ascii++; + Length++; + Pos = AcpiEfiFlushFile (File, String, + End, Pos, FALSE); + } + } + Pos = AcpiEfiFlushFile (File, String, End, Pos, TRUE); + } + else + { + EfiFile = (EFI_FILE_HANDLE) File; + if (!EfiFile) + { + goto ErrorExit; + } + WriteSize = Size * Count; + + EfiStatus = uefi_call_wrapper (AcpiGbl_EfiCurrentVolume->Write, 3, + EfiFile, &WriteSize, Buffer); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_FILE_HANDLE->Write() failure.\n"); + goto ErrorExit; + } + Length = WriteSize; + } + +ErrorExit: + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsGetFileOffset + * + * PARAMETERS: File - File descriptor + * + * RETURN: Size of current position + * + * DESCRIPTION: Get current file offset. + * + ******************************************************************************/ + +long +AcpiOsGetFileOffset ( + ACPI_FILE File) +{ + long Offset = -1; + + + return (Offset); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsSetFileOffset + * + * PARAMETERS: File - File descriptor + * Offset - File offset + * From - From begin/end of file + * + * RETURN: Status + * + * DESCRIPTION: Set current file offset. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiOsSetFileOffset ( + ACPI_FILE File, + long Offset, + UINT8 From) +{ + + return (AE_SUPPORT); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPrintf + * + * PARAMETERS: Format, ... - Standard printf format + * + * RETURN: None + * + * DESCRIPTION: Formatted output. + * + *****************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiOsPrintf ( + const char *Format, + ...) +{ + va_list Args; + + + va_start (Args, Format); + AcpiOsVprintf (Format, Args); + va_end (Args); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsVprintf + * + * PARAMETERS: Format - Standard printf format + * Args - Argument list + * + * RETURN: None + * + * DESCRIPTION: Formatted output with arguments list pointer. + * + *****************************************************************************/ + +void +AcpiOsVprintf ( + const char *Format, + va_list Args) +{ + + (void) AcpiUtFileVprintf (ACPI_FILE_OUT, Format, Args); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize this module. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsInitialize ( + void) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiEfiArgify + * + * PARAMETERS: String - Pointer to command line argument strings + * which are seperated with spaces + * ArgcPtr - Return number of the arguments + * ArgvPtr - Return vector of the arguments + * + * RETURN: Status + * + * DESCRIPTION: Convert EFI arguments into C arguments. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiEfiArgify ( + char *String, + int *ArgcPtr, + char ***ArgvPtr) +{ + char *CopyBuffer; + int MaxArgc = *ArgcPtr; + int Argc = 0; + char **Argv = *ArgvPtr; + char *Arg; + BOOLEAN IsSingleQuote = FALSE; + BOOLEAN IsDoubleQuote = FALSE; + BOOLEAN IsEscape = FALSE; + + + if (String == NULL) + { + return (AE_BAD_PARAMETER); + } + + CopyBuffer = String; + + while (*String != '\0') + { + while (isspace (*String)) + { + *String++ = '\0'; + } + Arg = CopyBuffer; + while (*String != '\0') + { + if (isspace (*String) && + !IsSingleQuote && !IsDoubleQuote && !IsEscape) + { + *Arg++ = '\0'; + String++; + break; + } + if (IsEscape) + { + IsEscape = FALSE; + *Arg++ = *String; + } + else if (*String == '\\') + { + IsEscape = TRUE; + } + else if (IsSingleQuote) + { + if (*String == '\'') + { + IsSingleQuote = FALSE; + *Arg++ = '\0'; + } + else + { + *Arg++ = *String; + } + } + else if (IsDoubleQuote) + { + if (*String == '"') + { + IsDoubleQuote = FALSE; + *Arg = '\0'; + } + else + { + *Arg++ = *String; + } + } + else + { + if (*String == '\'') + { + IsSingleQuote = TRUE; + } + else if (*String == '"') + { + IsDoubleQuote = TRUE; + } + else + { + *Arg++ = *String; + } + } + String++; + } + if (Argv && Argc < MaxArgc) + { + Argv[Argc] = CopyBuffer; + } + Argc++; + CopyBuffer = Arg; + } + if (Argv && Argc < MaxArgc) + { + Argv[Argc] = NULL; + } + + *ArgcPtr = Argc; + *ArgvPtr = Argv; + + return ((MaxArgc < Argc) ? AE_NO_MEMORY : AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiEfiConvertArgcv + * + * PARAMETERS: LoadOptions - Pointer to the EFI options buffer, which + * is NULL terminated + * LoadOptionsSize - Size of the EFI options buffer + * ArgcPtr - Return number of the arguments + * ArgvPtr - Return vector of the arguments + * BufferPtr - Buffer to contain the argument strings + * + * RETURN: Status + * + * DESCRIPTION: Convert EFI arguments into C arguments. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiEfiConvertArgcv ( + CHAR16 *LoadOptions, + UINT32 LoadOptionsSize, + int *ArgcPtr, + char ***ArgvPtr, + char **BufferPtr) +{ + ACPI_STATUS Status = AE_OK; + UINT32 Count = LoadOptionsSize / sizeof (CHAR16); + UINT32 i; + CHAR16 *From; + char *To; + int Argc = 0; + char **Argv = NULL; + char *Buffer; + + + /* Prepare a buffer to contain the argument strings */ + + Buffer = ACPI_ALLOCATE_ZEROED (Count); + if (!Buffer) + { + Status = AE_NO_MEMORY; + goto ErrorExit; + } + +TryAgain: + + /* Extend the argument vector */ + + if (Argv) + { + ACPI_FREE (Argv); + Argv = NULL; + } + if (Argc > 0) + { + Argv = ACPI_ALLOCATE_ZEROED (sizeof (char *) * (Argc + 1)); + if (!Argv) + { + Status = AE_NO_MEMORY; + goto ErrorExit; + } + } + + /* + * Note: As AcpiEfiArgify() will modify the content of the buffer, so + * we need to restore it each time before invoking + * AcpiEfiArgify(). + */ + From = LoadOptions; + To = ACPI_CAST_PTR (char, Buffer); + for (i = 0; i < Count; i++) + { + *To++ = (char) *From++; + } + + /* + * The "Buffer" will contain NULL terminated strings after invoking + * AcpiEfiArgify(). The number of the strings are saved in Argc and the + * pointers of the strings are saved in Argv. + */ + Status = AcpiEfiArgify (Buffer, &Argc, &Argv); + if (ACPI_FAILURE (Status)) + { + if (Status == AE_NO_MEMORY) + { + goto TryAgain; + } + } + +ErrorExit: + + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (Buffer); + ACPI_FREE (Argv); + } + else + { + *ArgcPtr = Argc; + *ArgvPtr = Argv; + *BufferPtr = Buffer; + } + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: efi_main + * + * PARAMETERS: Image - EFI image handle + * SystemTab - EFI system table + * + * RETURN: EFI Status + * + * DESCRIPTION: Entry point of EFI executable + * + *****************************************************************************/ + +EFI_STATUS +efi_main ( + EFI_HANDLE Image, + EFI_SYSTEM_TABLE *SystemTab) +{ + EFI_LOADED_IMAGE *Info; + EFI_STATUS EfiStatus = EFI_SUCCESS; + ACPI_STATUS Status; + int argc; + char **argv = NULL; + char *OptBuffer = NULL; + EFI_FILE_IO_INTERFACE *Volume = NULL; + + + /* Initialize global variables */ + + ST = SystemTab; + BS = SystemTab->BootServices; + + /* Retrieve image information */ + + EfiStatus = uefi_call_wrapper (BS->HandleProtocol, 3, + Image, &AcpiGbl_LoadedImageProtocol, ACPI_CAST_PTR (VOID, &Info)); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_BOOT_SERVICES->HandleProtocol(LoadedImageProtocol) failure.\n"); + return (EfiStatus); + } + + EfiStatus = uefi_call_wrapper (BS->HandleProtocol, 3, + Info->DeviceHandle, &AcpiGbl_FileSystemProtocol, (void **) &Volume); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_BOOT_SERVICES->HandleProtocol(FileSystemProtocol) failure.\n"); + return (EfiStatus); + } + EfiStatus = uefi_call_wrapper (Volume->OpenVolume, 2, + Volume, &AcpiGbl_EfiCurrentVolume); + if (EFI_ERROR (EfiStatus)) + { + AcpiLogError ("EFI_FILE_IO_INTERFACE->OpenVolume() failure.\n"); + return (EfiStatus); + } + + Status = AcpiEfiConvertArgcv (Info->LoadOptions, + Info->LoadOptionsSize, &argc, &argv, &OptBuffer); + if (ACPI_FAILURE (Status)) + { + EfiStatus = EFI_DEVICE_ERROR; + goto ErrorAlloc; + } + + acpi_main (argc, argv); + +ErrorAlloc: + + if (argv) + { + ACPI_FREE (argv); + } + if (OptBuffer) + { + ACPI_FREE (OptBuffer); + } + + return (EfiStatus); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/oslibcfs.c b/third_party/lib/acpica/source/os_specific/service_layers/oslibcfs.c new file mode 100644 index 000000000..192354c38 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/oslibcfs.c @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * Module Name: oslibcfs - C library OSL for file I/O + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include +#include + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("oslibcfs") + + +/******************************************************************************* + * + * FUNCTION: AcpiOsOpenFile + * + * PARAMETERS: Path - File path + * Modes - File operation type + * + * RETURN: File descriptor. + * + * DESCRIPTION: Open a file for reading (ACPI_FILE_READING) or/and writing + * (ACPI_FILE_WRITING). + * + ******************************************************************************/ + +ACPI_FILE +AcpiOsOpenFile ( + const char *Path, + UINT8 Modes) +{ + ACPI_FILE File; + UINT32 i = 0; + char ModesStr[4]; + + + if (Modes & ACPI_FILE_READING) + { + ModesStr[i++] = 'r'; + } + if (Modes & ACPI_FILE_WRITING) + { + ModesStr[i++] = 'w'; + } + + if (Modes & ACPI_FILE_BINARY) + { + ModesStr[i++] = 'b'; + } + + ModesStr[i++] = '\0'; + + File = fopen (Path, ModesStr); + if (!File) + { + perror ("Could not open file"); + } + + return (File); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsCloseFile + * + * PARAMETERS: File - An open file descriptor + * + * RETURN: None. + * + * DESCRIPTION: Close a file opened via AcpiOsOpenFile. + * + ******************************************************************************/ + +void +AcpiOsCloseFile ( + ACPI_FILE File) +{ + + fclose (File); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsReadFile + * + * PARAMETERS: File - An open file descriptor + * Buffer - Data buffer + * Size - Data block size + * Count - Number of data blocks + * + * RETURN: Number of bytes actually read. + * + * DESCRIPTION: Read from a file. + * + ******************************************************************************/ + +int +AcpiOsReadFile ( + ACPI_FILE File, + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count) +{ + int Length; + + + Length = fread (Buffer, Size, Count, File); + if (Length < 0) + { + perror ("Error reading file"); + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsWriteFile + * + * PARAMETERS: File - An open file descriptor + * Buffer - Data buffer + * Size - Data block size + * Count - Number of data blocks + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Write to a file. + * + ******************************************************************************/ + +int +AcpiOsWriteFile ( + ACPI_FILE File, + void *Buffer, + ACPI_SIZE Size, + ACPI_SIZE Count) +{ + int Length; + + + Length = fwrite (Buffer, Size, Count, File); + if (Length < 0) + { + perror ("Error writing file"); + } + + return (Length); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsGetFileOffset + * + * PARAMETERS: File - An open file descriptor + * + * RETURN: Current file pointer position. + * + * DESCRIPTION: Get current file offset. + * + ******************************************************************************/ + +long +AcpiOsGetFileOffset ( + ACPI_FILE File) +{ + long Offset; + + + Offset = ftell (File); + return (Offset); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsSetFileOffset + * + * PARAMETERS: File - An open file descriptor + * Offset - New file offset + * From - From begin/end of file + * + * RETURN: Status + * + * DESCRIPTION: Set current file offset. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiOsSetFileOffset ( + ACPI_FILE File, + long Offset, + UINT8 From) +{ + int Ret = 0; + + + if (From == ACPI_FILE_BEGIN) + { + Ret = fseek (File, Offset, SEEK_SET); + } + + if (From == ACPI_FILE_END) + { + Ret = fseek (File, Offset, SEEK_END); + } + + if (Ret < 0) + { + return (AE_ERROR); + } + else + { + return (AE_OK); + } +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/oslinuxtbl.c b/third_party/lib/acpica/source/os_specific/service_layers/oslinuxtbl.c new file mode 100644 index 000000000..92faa3912 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/oslinuxtbl.c @@ -0,0 +1,1547 @@ +/****************************************************************************** + * + * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" + + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("oslinuxtbl") + + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + + +/* List of information about obtained ACPI tables */ + +typedef struct osl_table_info +{ + struct osl_table_info *Next; + UINT32 Instance; + char Signature[ACPI_NAME_SIZE]; + +} OSL_TABLE_INFO; + +/* Local prototypes */ + +static ACPI_STATUS +OslTableInitialize ( + void); + +static ACPI_STATUS +OslTableNameFromFile ( + char *Filename, + char *Signature, + UINT32 *Instance); + +static ACPI_STATUS +OslAddTableToList ( + char *Signature, + UINT32 Instance); + +static ACPI_STATUS +OslReadTableFromFile ( + char *Filename, + ACPI_SIZE FileOffset, + char *Signature, + ACPI_TABLE_HEADER **Table); + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table); + +static void +OslUnmapTable ( + ACPI_TABLE_HEADER *Table); + +static ACPI_PHYSICAL_ADDRESS +OslFindRsdpViaEfiByKeyword ( + FILE *File, + const char *Keyword); + +static ACPI_PHYSICAL_ADDRESS +OslFindRsdpViaEfi ( + void); + +static ACPI_STATUS +OslLoadRsdp ( + void); + +static ACPI_STATUS +OslListCustomizedTables ( + char *Directory); + +static ACPI_STATUS +OslGetCustomizedTable ( + char *Pathname, + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + +static ACPI_STATUS +OslListBiosTables ( + void); + +static ACPI_STATUS +OslGetBiosTable ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address); + +static ACPI_STATUS +OslGetLastStatus ( + ACPI_STATUS DefaultStatus); + + +/* File locations */ + +#define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic" +#define STATIC_TABLE_DIR "/sys/firmware/acpi/tables" +#define EFI_SYSTAB "/sys/firmware/efi/systab" + +/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */ + +UINT8 Gbl_DumpDynamicTables = TRUE; + +/* Initialization flags */ + +UINT8 Gbl_TableListInitialized = FALSE; + +/* Local copies of main ACPI tables */ + +ACPI_TABLE_RSDP Gbl_Rsdp; +ACPI_TABLE_FADT *Gbl_Fadt = NULL; +ACPI_TABLE_RSDT *Gbl_Rsdt = NULL; +ACPI_TABLE_XSDT *Gbl_Xsdt = NULL; + +/* Table addresses */ + +ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0; +ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0; + +/* Revision of RSD PTR */ + +UINT8 Gbl_Revision = 0; + +OSL_TABLE_INFO *Gbl_TableListHead = NULL; +UINT32 Gbl_TableCount = 0; + + +/****************************************************************************** + * + * FUNCTION: OslGetLastStatus + * + * PARAMETERS: DefaultStatus - Default error status to return + * + * RETURN: Status; Converted from errno. + * + * DESCRIPTION: Get last errno and conver it to ACPI_STATUS. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetLastStatus ( + ACPI_STATUS DefaultStatus) +{ + + switch (errno) + { + case EACCES: + case EPERM: + + return (AE_ACCESS); + + case ENOENT: + + return (AE_NOT_FOUND); + + case ENOMEM: + + return (AE_NO_MEMORY); + + default: + + return (DefaultStatus); + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByAddress + * + * PARAMETERS: Address - Physical address of the ACPI table + * Table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get an ACPI table via a physical memory address. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByAddress ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER **Table) +{ + UINT32 TableLength; + ACPI_TABLE_HEADER *MappedTable; + ACPI_TABLE_HEADER *LocalTable = NULL; + ACPI_STATUS Status = AE_OK; + + + /* Get main ACPI tables from memory on first invocation of this function */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Map the table and validate it */ + + Status = OslMapTable (Address, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Copy table to local buffer and return it */ + + TableLength = ApGetTableLength (MappedTable); + if (TableLength == 0) + { + Status = AE_BAD_HEADER; + goto Exit; + } + + LocalTable = calloc (1, TableLength); + if (!LocalTable) + { + Status = AE_NO_MEMORY; + goto Exit; + } + + memcpy (LocalTable, MappedTable, TableLength); + +Exit: + OslUnmapTable (MappedTable); + *Table = LocalTable; + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByName + * + * PARAMETERS: Signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByName ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_STATUS Status; + + + /* Get main ACPI tables from memory on first invocation of this function */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ + + if (!Gbl_DumpCustomizedTables) + { + /* Attempt to get the table from the memory */ + + Status = OslGetBiosTable (Signature, Instance, Table, Address); + } + else + { + /* Attempt to get the table from the static directory */ + + Status = OslGetCustomizedTable (STATIC_TABLE_DIR, Signature, + Instance, Table, Address); + } + + if (ACPI_FAILURE (Status) && Status == AE_LIMIT) + { + if (Gbl_DumpDynamicTables) + { + /* Attempt to get a dynamic table */ + + Status = OslGetCustomizedTable (DYNAMIC_TABLE_DIR, Signature, + Instance, Table, Address); + } + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslAddTableToList + * + * PARAMETERS: Signature - Table signature + * Instance - Table instance + * + * RETURN: Status; Successfully added if AE_OK. + * AE_NO_MEMORY: Memory allocation error + * + * DESCRIPTION: Insert a table structure into OSL table list. + * + *****************************************************************************/ + +static ACPI_STATUS +OslAddTableToList ( + char *Signature, + UINT32 Instance) +{ + OSL_TABLE_INFO *NewInfo; + OSL_TABLE_INFO *Next; + UINT32 NextInstance = 0; + BOOLEAN Found = FALSE; + + + NewInfo = calloc (1, sizeof (OSL_TABLE_INFO)); + if (!NewInfo) + { + return (AE_NO_MEMORY); + } + + ACPI_MOVE_NAME (NewInfo->Signature, Signature); + + if (!Gbl_TableListHead) + { + Gbl_TableListHead = NewInfo; + } + else + { + Next = Gbl_TableListHead; + while (1) + { + if (ACPI_COMPARE_NAME (Next->Signature, Signature)) + { + if (Next->Instance == Instance) + { + Found = TRUE; + } + if (Next->Instance >= NextInstance) + { + NextInstance = Next->Instance + 1; + } + } + + if (!Next->Next) + { + break; + } + Next = Next->Next; + } + Next->Next = NewInfo; + } + + if (Found) + { + if (Instance) + { + fprintf (stderr, + "%4.4s: Warning unmatched table instance %d, expected %d\n", + Signature, Instance, NextInstance); + } + Instance = NextInstance; + } + + NewInfo->Instance = Instance; + Gbl_TableCount++; + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByIndex + * + * PARAMETERS: Index - Which table to get + * Table - Where a pointer to the table is returned + * Instance - Where a pointer to the table instance no. is + * returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Index is beyond valid limit + * + * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns + * AE_LIMIT when an invalid index is reached. Index is not + * necessarily an index into the RSDT/XSDT. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByIndex ( + UINT32 Index, + ACPI_TABLE_HEADER **Table, + UINT32 *Instance, + ACPI_PHYSICAL_ADDRESS *Address) +{ + OSL_TABLE_INFO *Info; + ACPI_STATUS Status; + UINT32 i; + + + /* Get main ACPI tables from memory on first invocation of this function */ + + Status = OslTableInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Validate Index */ + + if (Index >= Gbl_TableCount) + { + return (AE_LIMIT); + } + + /* Point to the table list entry specified by the Index argument */ + + Info = Gbl_TableListHead; + for (i = 0; i < Index; i++) + { + Info = Info->Next; + } + + /* Now we can just get the table via the signature */ + + Status = AcpiOsGetTableByName (Info->Signature, Info->Instance, + Table, Address); + + if (ACPI_SUCCESS (Status)) + { + *Instance = Info->Instance; + } + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslFindRsdpViaEfiByKeyword + * + * PARAMETERS: Keyword - Character string indicating ACPI GUID version + * in the EFI table + * + * RETURN: RSDP address if found + * + * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI + * GUID version. + * + *****************************************************************************/ + +static ACPI_PHYSICAL_ADDRESS +OslFindRsdpViaEfiByKeyword ( + FILE *File, + const char *Keyword) +{ + char Buffer[80]; + unsigned long long Address = 0; + char Format[32]; + + + snprintf (Format, 32, "%s=%s", Keyword, "%llx"); + fseek (File, 0, SEEK_SET); + while (fgets (Buffer, 80, File)) + { + if (sscanf (Buffer, Format, &Address) == 1) + { + break; + } + } + + return ((ACPI_PHYSICAL_ADDRESS) (Address)); +} + + +/****************************************************************************** + * + * FUNCTION: OslFindRsdpViaEfi + * + * PARAMETERS: None + * + * RETURN: RSDP address if found + * + * DESCRIPTION: Find RSDP address via EFI. + * + *****************************************************************************/ + +static ACPI_PHYSICAL_ADDRESS +OslFindRsdpViaEfi ( + void) +{ + FILE *File; + ACPI_PHYSICAL_ADDRESS Address = 0; + + + File = fopen (EFI_SYSTAB, "r"); + if (File) + { + Address = OslFindRsdpViaEfiByKeyword (File, "ACPI20"); + if (!Address) + { + Address = OslFindRsdpViaEfiByKeyword (File, "ACPI"); + } + fclose (File); + } + + return (Address); +} + + +/****************************************************************************** + * + * FUNCTION: OslLoadRsdp + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Scan and load RSDP. + * + *****************************************************************************/ + +static ACPI_STATUS +OslLoadRsdp ( + void) +{ + ACPI_TABLE_HEADER *MappedTable; + UINT8 *RsdpAddress; + ACPI_PHYSICAL_ADDRESS RsdpBase; + ACPI_SIZE RsdpSize; + + + /* Get RSDP from memory */ + + RsdpSize = sizeof (ACPI_TABLE_RSDP); + if (Gbl_RsdpBase) + { + RsdpBase = Gbl_RsdpBase; + } + else + { + RsdpBase = OslFindRsdpViaEfi (); + } + + if (!RsdpBase) + { + RsdpBase = ACPI_HI_RSDP_WINDOW_BASE; + RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE; + } + + RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize); + if (!RsdpAddress) + { + return (OslGetLastStatus (AE_BAD_ADDRESS)); + } + + /* Search low memory for the RSDP */ + + MappedTable = ACPI_CAST_PTR (ACPI_TABLE_HEADER, + AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize)); + if (!MappedTable) + { + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + return (AE_NOT_FOUND); + } + + Gbl_RsdpAddress = RsdpBase + (ACPI_CAST8 (MappedTable) - RsdpAddress); + + memcpy (&Gbl_Rsdp, MappedTable, sizeof (ACPI_TABLE_RSDP)); + AcpiOsUnmapMemory (RsdpAddress, RsdpSize); + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslCanUseXsdt + * + * PARAMETERS: None + * + * RETURN: TRUE if XSDT is allowed to be used. + * + * DESCRIPTION: This function collects logic that can be used to determine if + * XSDT should be used instead of RSDT. + * + *****************************************************************************/ + +static BOOLEAN +OslCanUseXsdt ( + void) +{ + if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) + { + return (TRUE); + } + else + { + return (FALSE); + } +} + + +/****************************************************************************** + * + * FUNCTION: OslTableInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to + * local variables. Main ACPI tables include RSDT, FADT, RSDT, + * and/or XSDT. + * + *****************************************************************************/ + +static ACPI_STATUS +OslTableInitialize ( + void) +{ + ACPI_STATUS Status; + ACPI_PHYSICAL_ADDRESS Address; + + + if (Gbl_TableListInitialized) + { + return (AE_OK); + } + + if (!Gbl_DumpCustomizedTables) + { + /* Get RSDP from memory */ + + Status = OslLoadRsdp (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Get XSDT from memory */ + + if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) + { + if (Gbl_Xsdt) + { + free (Gbl_Xsdt); + Gbl_Xsdt = NULL; + } + + Gbl_Revision = 2; + Status = OslGetBiosTable (ACPI_SIG_XSDT, 0, + ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Get RSDT from memory */ + + if (Gbl_Rsdp.RsdtPhysicalAddress) + { + if (Gbl_Rsdt) + { + free (Gbl_Rsdt); + Gbl_Rsdt = NULL; + } + + Status = OslGetBiosTable (ACPI_SIG_RSDT, 0, + ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* Get FADT from memory */ + + if (Gbl_Fadt) + { + free (Gbl_Fadt); + Gbl_Fadt = NULL; + } + + Status = OslGetBiosTable (ACPI_SIG_FADT, 0, + ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Add mandatory tables to global table list first */ + + Status = OslAddTableToList (ACPI_RSDP_NAME, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = OslAddTableToList (ACPI_SIG_RSDT, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Gbl_Revision == 2) + { + Status = OslAddTableToList (ACPI_SIG_XSDT, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + Status = OslAddTableToList (ACPI_SIG_DSDT, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = OslAddTableToList (ACPI_SIG_FACS, 0); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Add all tables found in the memory */ + + Status = OslListBiosTables (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else + { + /* Add all tables found in the static directory */ + + Status = OslListCustomizedTables (STATIC_TABLE_DIR); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + if (Gbl_DumpDynamicTables) + { + /* Add all dynamically loaded tables in the dynamic directory */ + + Status = OslListCustomizedTables (DYNAMIC_TABLE_DIR); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + Gbl_TableListInitialized = TRUE; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslListBiosTables + * + * PARAMETERS: None + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from memory. + * + * NOTE: This works on Linux as table customization does not modify the + * addresses stored in RSDP/RSDT/XSDT/FADT. + * + *****************************************************************************/ + +static ACPI_STATUS +OslListBiosTables ( + void) +{ + ACPI_TABLE_HEADER *MappedTable = NULL; + UINT8 *TableData; + UINT8 NumberOfTables; + UINT8 ItemSize; + ACPI_PHYSICAL_ADDRESS TableAddress = 0; + ACPI_STATUS Status = AE_OK; + UINT32 i; + + + if (OslCanUseXsdt ()) + { + ItemSize = sizeof (UINT64); + TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + else /* Use RSDT if XSDT is not available */ + { + ItemSize = sizeof (UINT32); + TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) + { + if (OslCanUseXsdt ()) + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); + } + else + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); + } + + /* Skip NULL entries in RSDT/XSDT */ + + if (!TableAddress) + { + continue; + } + + Status = OslMapTable (TableAddress, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + OslAddTableToList (MappedTable->Signature, 0); + OslUnmapTable (MappedTable); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetBiosTable + * + * PARAMETERS: Signature - ACPI Signature for common table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get a BIOS provided ACPI table + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetBiosTable ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_TABLE_HEADER *LocalTable = NULL; + ACPI_TABLE_HEADER *MappedTable = NULL; + UINT8 *TableData; + UINT8 NumberOfTables; + UINT8 ItemSize; + UINT32 CurrentInstance = 0; + ACPI_PHYSICAL_ADDRESS TableAddress = 0; + UINT32 TableLength = 0; + ACPI_STATUS Status = AE_OK; + UINT32 i; + + + /* Handle special tables whose addresses are not in RSDT/XSDT */ + + if (ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + if (Instance > 0) + { + return (AE_LIMIT); + } + + /* + * Get the appropriate address, either 32-bit or 64-bit. Be very + * careful about the FADT length and validate table addresses. + * Note: The 64-bit addresses have priority. + */ + if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT)) + { + if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) && + Gbl_Fadt->XDsdt) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt; + } + else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) && + Gbl_Fadt->Dsdt) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt; + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) + { + if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) && + Gbl_Fadt->XFacs) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs; + } + else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) && + Gbl_Fadt->Facs) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs; + } + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT)) + { + if (!Gbl_Revision) + { + return (AE_BAD_SIGNATURE); + } + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress; + } + else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT)) + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress; + } + else + { + TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress; + Signature = ACPI_SIG_RSDP; + } + + /* Now we can get the requested special table */ + + Status = OslMapTable (TableAddress, Signature, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + TableLength = ApGetTableLength (MappedTable); + } + else /* Case for a normal ACPI table */ + { + if (OslCanUseXsdt ()) + { + ItemSize = sizeof (UINT64); + TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + else /* Use RSDT if XSDT is not available */ + { + ItemSize = sizeof (UINT32); + TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); + NumberOfTables = + (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) + / ItemSize); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) + { + if (OslCanUseXsdt ()) + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); + } + else + { + TableAddress = + (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); + } + + /* Skip NULL entries in RSDT/XSDT */ + + if (!TableAddress) + { + continue; + } + + Status = OslMapTable (TableAddress, NULL, &MappedTable); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + TableLength = MappedTable->Length; + + /* Does this table match the requested signature? */ + + if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature)) + { + OslUnmapTable (MappedTable); + MappedTable = NULL; + continue; + } + + /* Match table instance (for SSDT/UEFI tables) */ + + if (CurrentInstance != Instance) + { + OslUnmapTable (MappedTable); + MappedTable = NULL; + CurrentInstance++; + continue; + } + + break; + } + } + + if (!MappedTable) + { + return (AE_LIMIT); + } + + if (TableLength == 0) + { + Status = AE_BAD_HEADER; + goto Exit; + } + + /* Copy table to local buffer and return it */ + + LocalTable = calloc (1, TableLength); + if (!LocalTable) + { + Status = AE_NO_MEMORY; + goto Exit; + } + + memcpy (LocalTable, MappedTable, TableLength); + *Address = TableAddress; + *Table = LocalTable; + +Exit: + OslUnmapTable (MappedTable); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslListCustomizedTables + * + * PARAMETERS: Directory - Directory that contains the tables + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from a directory. + * + *****************************************************************************/ + +static ACPI_STATUS +OslListCustomizedTables ( + char *Directory) +{ + void *TableDir; + UINT32 Instance; + char TempName[ACPI_NAME_SIZE]; + char *Filename; + ACPI_STATUS Status = AE_OK; + + + /* Open the requested directory */ + + TableDir = AcpiOsOpenDirectory (Directory, "*", REQUEST_FILE_ONLY); + if (!TableDir) + { + return (OslGetLastStatus (AE_NOT_FOUND)); + } + + /* Examine all entries in this directory */ + + while ((Filename = AcpiOsGetNextFilename (TableDir))) + { + /* Extract table name and instance number */ + + Status = OslTableNameFromFile (Filename, TempName, &Instance); + + /* Ignore meaningless files */ + + if (ACPI_FAILURE (Status)) + { + continue; + } + + /* Add new info node to global table list */ + + Status = OslAddTableToList (TempName, Instance); + if (ACPI_FAILURE (Status)) + { + break; + } + } + + AcpiOsCloseDirectory (TableDir); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslMapTable + * + * PARAMETERS: Address - Address of the table in memory + * Signature - Optional ACPI Signature for desired table. + * Null terminated 4-character string. + * Table - Where a pointer to the mapped table is + * returned + * + * RETURN: Status; Mapped table is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Map entire ACPI table into caller's address space. + * + *****************************************************************************/ + +static ACPI_STATUS +OslMapTable ( + ACPI_SIZE Address, + char *Signature, + ACPI_TABLE_HEADER **Table) +{ + ACPI_TABLE_HEADER *MappedTable; + UINT32 Length; + + + if (!Address) + { + return (AE_BAD_ADDRESS); + } + + /* + * Map the header so we can get the table length. + * Use sizeof (ACPI_TABLE_HEADER) as: + * 1. it is bigger than 24 to include RSDP->Length + * 2. it is smaller than sizeof (ACPI_TABLE_RSDP) + */ + MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); + if (!MappedTable) + { + fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Address)); + return (OslGetLastStatus (AE_BAD_ADDRESS)); + } + + /* If specified, signature must match */ + + if (Signature) + { + if (ACPI_VALIDATE_RSDP_SIG (Signature)) + { + if (!ACPI_VALIDATE_RSDP_SIG (MappedTable->Signature)) + { + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + return (AE_BAD_SIGNATURE); + } + } + else if (!ACPI_COMPARE_NAME (Signature, MappedTable->Signature)) + { + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + return (AE_BAD_SIGNATURE); + } + } + + /* Map the entire table */ + + Length = ApGetTableLength (MappedTable); + AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); + if (Length == 0) + { + return (AE_BAD_HEADER); + } + + MappedTable = AcpiOsMapMemory (Address, Length); + if (!MappedTable) + { + fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n", + ACPI_FORMAT_UINT64 (Address), Length); + return (OslGetLastStatus (AE_INVALID_TABLE_LENGTH)); + } + + (void) ApIsValidChecksum (MappedTable); + + *Table = MappedTable; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslUnmapTable + * + * PARAMETERS: Table - A pointer to the mapped table + * + * RETURN: None + * + * DESCRIPTION: Unmap entire ACPI table. + * + *****************************************************************************/ + +static void +OslUnmapTable ( + ACPI_TABLE_HEADER *Table) +{ + if (Table) + { + AcpiOsUnmapMemory (Table, ApGetTableLength (Table)); + } +} + + +/****************************************************************************** + * + * FUNCTION: OslTableNameFromFile + * + * PARAMETERS: Filename - File that contains the desired table + * Signature - Pointer to 4-character buffer to store + * extracted table signature. + * Instance - Pointer to integer to store extracted + * table instance number. + * + * RETURN: Status; Table name is extracted if AE_OK. + * + * DESCRIPTION: Extract table signature and instance number from a table file + * name. + * + *****************************************************************************/ + +static ACPI_STATUS +OslTableNameFromFile ( + char *Filename, + char *Signature, + UINT32 *Instance) +{ + + /* Ignore meaningless files */ + + if (strlen (Filename) < ACPI_NAME_SIZE) + { + return (AE_BAD_SIGNATURE); + } + + /* Extract instance number */ + + if (isdigit ((int) Filename[ACPI_NAME_SIZE])) + { + sscanf (&Filename[ACPI_NAME_SIZE], "%u", Instance); + } + else if (strlen (Filename) != ACPI_NAME_SIZE) + { + return (AE_BAD_SIGNATURE); + } + else + { + *Instance = 0; + } + + /* Extract signature */ + + ACPI_MOVE_NAME (Signature, Filename); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: OslReadTableFromFile + * + * PARAMETERS: Filename - File that contains the desired table + * FileOffset - Offset of the table in file + * Signature - Optional ACPI Signature for desired table. + * A null terminated 4-character string. + * Table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * + * DESCRIPTION: Read a ACPI table from a file. + * + *****************************************************************************/ + +static ACPI_STATUS +OslReadTableFromFile ( + char *Filename, + ACPI_SIZE FileOffset, + char *Signature, + ACPI_TABLE_HEADER **Table) +{ + FILE *TableFile; + ACPI_TABLE_HEADER Header; + ACPI_TABLE_HEADER *LocalTable = NULL; + UINT32 TableLength; + INT32 Count; + ACPI_STATUS Status = AE_OK; + + + /* Open the file */ + + TableFile = fopen (Filename, "rb"); + if (TableFile == NULL) + { + fprintf (stderr, "Could not open table file: %s\n", Filename); + return (OslGetLastStatus (AE_NOT_FOUND)); + } + + fseek (TableFile, FileOffset, SEEK_SET); + + /* Read the Table header to get the table length */ + + Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile); + if (Count != sizeof (ACPI_TABLE_HEADER)) + { + fprintf (stderr, "Could not read table header: %s\n", Filename); + Status = AE_BAD_HEADER; + goto Exit; + } + + /* If signature is specified, it must match the table */ + + if (Signature) + { + if (ACPI_VALIDATE_RSDP_SIG (Signature)) + { + if (!ACPI_VALIDATE_RSDP_SIG (Header.Signature)) { + fprintf (stderr, "Incorrect RSDP signature: found %8.8s\n", + Header.Signature); + Status = AE_BAD_SIGNATURE; + goto Exit; + } + } + else if (!ACPI_COMPARE_NAME (Signature, Header.Signature)) + { + fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n", + Signature, Header.Signature); + Status = AE_BAD_SIGNATURE; + goto Exit; + } + } + + TableLength = ApGetTableLength (&Header); + if (TableLength == 0) + { + Status = AE_BAD_HEADER; + goto Exit; + } + + /* Read the entire table into a local buffer */ + + LocalTable = calloc (1, TableLength); + if (!LocalTable) + { + fprintf (stderr, + "%4.4s: Could not allocate buffer for table of length %X\n", + Header.Signature, TableLength); + Status = AE_NO_MEMORY; + goto Exit; + } + + fseek (TableFile, FileOffset, SEEK_SET); + + Count = fread (LocalTable, 1, TableLength, TableFile); + if (Count != TableLength) + { + fprintf (stderr, "%4.4s: Could not read table content\n", + Header.Signature); + Status = AE_INVALID_TABLE_LENGTH; + goto Exit; + } + + /* Validate checksum */ + + (void) ApIsValidChecksum (LocalTable); + +Exit: + fclose (TableFile); + *Table = LocalTable; + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: OslGetCustomizedTable + * + * PARAMETERS: Pathname - Directory to find Linux customized table + * Signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * Instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get an OS customized table. + * + *****************************************************************************/ + +static ACPI_STATUS +OslGetCustomizedTable ( + char *Pathname, + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + void *TableDir; + UINT32 CurrentInstance = 0; + char TempName[ACPI_NAME_SIZE]; + char TableFilename[PATH_MAX]; + char *Filename; + ACPI_STATUS Status; + + + /* Open the directory for customized tables */ + + TableDir = AcpiOsOpenDirectory (Pathname, "*", REQUEST_FILE_ONLY); + if (!TableDir) + { + return (OslGetLastStatus (AE_NOT_FOUND)); + } + + /* Attempt to find the table in the directory */ + + while ((Filename = AcpiOsGetNextFilename (TableDir))) + { + /* Ignore meaningless files */ + + if (!ACPI_COMPARE_NAME (Filename, Signature)) + { + continue; + } + + /* Extract table name and instance number */ + + Status = OslTableNameFromFile (Filename, TempName, &CurrentInstance); + + /* Ignore meaningless files */ + + if (ACPI_FAILURE (Status) || CurrentInstance != Instance) + { + continue; + } + + /* Create the table pathname */ + + if (Instance != 0) + { + sprintf (TableFilename, "%s/%4.4s%d", Pathname, TempName, Instance); + } + else + { + sprintf (TableFilename, "%s/%4.4s", Pathname, TempName); + } + break; + } + + AcpiOsCloseDirectory (TableDir); + + if (!Filename) + { + return (AE_LIMIT); + } + + /* There is no physical address saved for customized tables, use zero */ + + *Address = 0; + Status = OslReadTableFromFile (TableFilename, 0, NULL, Table); + + return (Status); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osmagenta.c b/third_party/lib/acpica/source/os_specific/service_layers/osmagenta.c new file mode 100644 index 000000000..c2467443a --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osmagenta.c @@ -0,0 +1,815 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !ARCH_X86 +#error "Unsupported architecture" +#endif +// Needed for port IO +#include + +#include "acpi.h" + +#define _COMPONENT ACPI_OS_SERVICES +ACPI_MODULE_NAME ("osmagenta") + +#define LOCAL_TRACE 0 + +/** + * @brief Initialize the OSL subsystem. + * + * This function allows the OSL to initialize itself. It is called during + * intiialization of the ACPICA subsystem. + * + * @return Initialization status + */ +ACPI_STATUS AcpiOsInitialize() { + return AE_OK; +} + +/** + * @brief Terminate the OSL subsystem. + * + * This function allows the OSL to cleanup and terminate. It is called during + * termination of the ACPICA subsystem. + * + * @return Termination status + */ +ACPI_STATUS AcpiOsTerminate() { + return AE_OK; +} + +extern uint32_t bootloader_acpi_rsdp; +/** + * @brief Obtain the Root ACPI table pointer (RSDP). + * + * @return The physical address of the RSDP + */ +ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer() { + if (bootloader_acpi_rsdp) { + return bootloader_acpi_rsdp; + } else { + ACPI_PHYSICAL_ADDRESS TableAddress = 0; + ACPI_STATUS status = AcpiFindRootPointer(&TableAddress); + + if (status != AE_OK) { + return 0; + } + return TableAddress; + } +} + +/** + * @brief Allow the host OS to override a predefined ACPI object. + * + * @param PredefinedObject A pointer to a predefind object (name and initial + * value) + * @param NewValue Where a new value for the predefined object is returned. + * NULL if there is no override for this object. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsPredefinedOverride( + const ACPI_PREDEFINED_NAMES *PredefinedObject, + ACPI_STRING *NewValue) { + *NewValue = NULL; + return AE_OK; +} + +/** + * @brief Allow the host OS to override a firmware ACPI table via a logical + * address. + * + * @param ExistingTable A pointer to the header of the existing ACPI table + * @param NewTable Where the pointer to the replacment table is returned. The + * OSL returns NULL if no replacement is provided. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsTableOverride( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable) { + *NewTable = NULL; + return AE_OK; +} + +/** + * @brief Allow the host OS to override a firmware ACPI table via a physical + * address. + * + * @param ExistingTable A pointer to the header of the existing ACPI table + * @param NewAddress Where the physical address of the replacment table is + * returned. The OSL returns NULL if no replacement is provided. + * @param NewLength Where the length of the replacement table is returned. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsPhysicalTableOverride( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_PHYSICAL_ADDRESS *NewAddress, + UINT32 *NewTableLength) { + *NewAddress = 0; + return AE_OK; +} + +// If we decide to make use of a more Magenta specific cache mechanism, +// remove the ACPI_USE_LOCAL_CACHE define from the header and implement these +// functions. +#if 0 +/** + * @brief Create a memory cache object. + * + * @param CacheName An ASCII identfier for the cache. + * @param ObjectSize The size of each object in the cache. + * @param MaxDepth Maximum number of objects in the cache. + * @param ReturnCache Where a pointer to the cache object is returned. + * + * @return AE_OK The cache was successfully created. + * @return AE_BAD_PARAMETER The ReturnCache pointer is NULL or ObjectSize < 16. + * @return AE_NO_MEMORY Insufficient dynamic memory to complete the operation. + */ +ACPI_STATUS AcpiOsCreateCache( + char *CacheName, + UINT16 ObjectSize, + UINT16 MaxDepth, + ACPI_CACHE_T **ReturnCache) { + PANIC_UNIMPLEMENTED; + return AE_NO_MEMORY; +} + +/** + * @brief Delete a memory cache object. + * + * @param Cache The cache object to be deleted. + * + * @return AE_OK The cache was successfully deleted. + * @return AE_BAD_PARAMETER The Cache pointer is NULL. + */ +ACPI_STATUS AcpiOsDeleteCache(ACPI_CACHE_T *Cache) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} + +/** + * @brief Free all objects currently within a cache object. + * + * @param Cache The cache object to purge. + * + * @return AE_OK The cache was successfully purged. + * @return AE_BAD_PARAMETER The Cache pointer is NULL. + */ +ACPI_STATUS AcpiOsPurgeCache(ACPI_CACHE_T *Cache) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} + + +/** + * @brief Acquire an object from a cache. + * + * @param Cache The cache object from which to acquire an object. + * + * @return A pointer to a cache object. NULL if the object could not be + * acquired. + */ +void *AcpiOsAcquireObject(ACPI_CACHE_T *Cache) { + PANIC_UNIMPLEMENTED; + return NULL; +} + +/** + * @brief Release an object to a cache. + * + * @param Cache The cache object to which the object will be released. + * @param Object The object to be released. + * + * @return AE_OK The object was successfully released. + * @return AE_BAD_PARAMETER The Cache or Object pointer is NULL. + */ +ACPI_STATUS AcpiOsReleaseObject(ACPI_CACHE_T *Cache, void *Object) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} +#endif + +/** + * @brief Map physical memory into the caller's address space. + * + * @param PhysicalAddress A full physical address of the memory to be mapped + * into the caller's address space + * @param Length The amount of memory to mapped starting at the given physical + * address + * + * @return Logical pointer to the mapped memory. A NULL pointer indicated failures. + */ +void *AcpiOsMapMemory( + ACPI_PHYSICAL_ADDRESS PhysicalAddress, + ACPI_SIZE Length) { + + // Caution: PhysicalAddress might not be page-aligned, Length might not + // be a page multiple. + + ACPI_PHYSICAL_ADDRESS aligned_address = ROUNDDOWN(PhysicalAddress, PAGE_SIZE); + ACPI_PHYSICAL_ADDRESS end = ROUNDUP(PhysicalAddress + Length, PAGE_SIZE); + + vmm_aspace_t *kernel_aspace = vmm_get_kernel_aspace(); + void *vaddr = NULL; + status_t status = vmm_alloc_physical( + kernel_aspace, + "acpi_mapping", + end - aligned_address, + &vaddr, + PAGE_SIZE_SHIFT, + aligned_address, + 0, + ARCH_MMU_FLAG_PERM_NO_EXECUTE); + if (status != NO_ERROR) { + return NULL; + } + return vaddr + (PhysicalAddress - aligned_address); +} + +/** + * @brief Remove a physical to logical memory mapping. + * + * @param LogicalAddress The logical address that was returned from a previous + * call to AcpiOsMapMemory. + * @param Length The amount of memory that was mapped. This value must be + * identical to the value used in the call to AcpiOsMapMemory. + */ +void AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length) { + vmm_aspace_t *kernel_aspace = vmm_get_kernel_aspace(); + status_t status = vmm_free_region(kernel_aspace, (vaddr_t)LogicalAddress); + if (status != NO_ERROR) { + TRACEF("WARNING: ACPI failed to free region %p, size %llu\n", + LogicalAddress, (uint64_t)Length); + } +} + +/** + * @brief Allocate memory from the dynamic memory pool. + * + * @param Size Amount of memory to allocate. + * + * @return A pointer to the allocated memory. A NULL pointer is returned on + * error. + */ +void *AcpiOsAllocate(ACPI_SIZE Size) { + return malloc(Size); +} + +/** + * @brief Free previously allocated memory. + * + * @param Memory A pointer to the memory to be freed. + */ +void AcpiOsFree(void *Memory) { + free(Memory); +} + +/** + * @brief Obtain the ID of the currently executing thread. + * + * @return A unique non-zero value that represents the ID of the currently + * executing thread. The value -1 is reserved and must not be returned + * by this interface. + */ +static_assert(sizeof(ACPI_THREAD_ID) >= sizeof(uintptr_t)); +ACPI_THREAD_ID AcpiOsGetThreadId() { + // Just use the address of the thread_t + return (uintptr_t)get_current_thread(); +} + +/** + * @brief Schedule a procedure for deferred execution. + * + * @param Type Type of the callback function. + * @param Function Address of the procedure to execute. + * @param Context A context value to be passed to the called procedure. + * + * @return AE_OK The procedure was successfully queued for execution. + * @return AE_BAD_PARAMETER The Type is invalid or the Function pointer + * is NULL. + */ +ACPI_STATUS AcpiOsExecute( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} + +/** + * @brief Suspend the running task (course granularity). + * + * @param Milliseconds The amount of time to sleep, in milliseconds. + */ +void AcpiOsSleep(UINT64 Milliseconds) { + if (Milliseconds > UINT32_MAX) { + // If we're asked to sleep for a long time (>1.5 months), shorten it + Milliseconds = UINT32_MAX; + } + thread_sleep(Milliseconds); +} + +/** + * @brief Wait for a short amount of time (fine granularity). + * + * Execution of the running thread is not suspended for this time. + * + * @param Microseconds The amount of time to delay, in microseconds. + */ +void AcpiOsStall(UINT32 Microseconds) { + spin(Microseconds); +} + +/** + * @brief Wait for completion of asynchronous events. + * + * This function blocks until all asynchronous events initiated by + * AcpiOsExecute have completed. + */ +void AcpiOsWaitEventsComplete() { + PANIC_UNIMPLEMENTED; +} + +/** + * @brief Create a semaphore. + * + * @param MaxUnits The maximum number of units this semaphore will be required + * to accept + * @param InitialUnits The initial number of units to be assigned to the + * semaphore. + * @param OutHandle A pointer to a locaton where a handle to the semaphore is + * to be returned. + * + * @return AE_OK The semaphore was successfully created. + * @return AE_BAD_PARAMETER The InitialUnits is invalid or the OutHandle + * pointer is NULL. + * @return AE_NO_MEMORY Insufficient memory to create the semaphore. + */ +ACPI_STATUS AcpiOsCreateSemaphore( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_SEMAPHORE *OutHandle) { + semaphore_t *sem = malloc(sizeof(semaphore_t)); + if (!sem) { + return AE_NO_MEMORY; + } + sem_init(sem, InitialUnits); + *OutHandle = sem; + return AE_OK; +} + +/** + * @brief Delete a semaphore. + * + * @param Handle A handle to a semaphore objected that was returned by a + * previous call to AcpiOsCreateSemaphore. + * + * @return AE_OK The semaphore was successfully deleted. + * @return AE_BAD_PARAMETER The Handle is invalid. + */ +ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle) { + free(Handle); + return AE_OK; +} + +/** + * @brief Wait for units from a semaphore. + * + * @param Handle A handle to a semaphore objected that was returned by a + * previous call to AcpiOsCreateSemaphore. + * @param Units The number of units the caller is requesting. + * @param Timeout How long the caller is willing to wait for the requested + * units, in milliseconds. A value of -1 indicates that the caller + * is willing to wait forever. Timeout may be 0. + * + * @return AE_OK The requested units were successfully received. + * @return AE_BAD_PARAMETER The Handle is invalid. + * @return AE_TIME The units could not be acquired within the specified time. + */ +ACPI_STATUS AcpiOsWaitSemaphore( + ACPI_SEMAPHORE Handle, + UINT32 Units, + UINT16 Time) { + // TODO: Implement support for Units > 1 + ASSERT(Units == 1); + lk_time_t timeout = Time; + if (Time == 0xffff) { + timeout = INFINITE_TIME; + } + status_t status = sem_timedwait(Handle, timeout); + if (status == ERR_TIMED_OUT) { + return AE_TIME; + } + // The API doesn't have any bailout other than timeout, so if this was + // unsuccessfuly for some other reason, we can't really do anything... + ASSERT(status == NO_ERROR); + return AE_OK; +} + +/** + * @brief Send units to a semaphore. + * + * @param Handle A handle to a semaphore objected that was returned by a + * previous call to AcpiOsCreateSemaphore. + * @param Units The number of units to send to the semaphore. + * + * @return AE_OK The semaphore was successfully signaled. + * @return AE_BAD_PARAMETER The Handle is invalid. + */ +ACPI_STATUS AcpiOsSignalSemaphore( + ACPI_SEMAPHORE Handle, + UINT32 Units) { + // TODO: Implement support for Units > 1 + ASSERT(Units == 1); + + sem_post(Handle, false /* don't reschedule (TODO: revisit?) */); + return AE_OK; +} + +/** + * @brief Create a spin lock. + * + * @param OutHandle A pointer to a locaton where a handle to the lockis + * to be returned. + * + * @return AE_OK The semaphore was successfully created. + * @return AE_BAD_PARAMETER The OutHandle pointer is NULL. + * @return AE_NO_MEMORY Insufficient memory to create the lock. + */ +ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK *OutHandle) { + spin_lock_t *lock = malloc(sizeof(spin_lock_t)); + if (!lock) { + return AE_NO_MEMORY; + } + spin_lock_init(lock); + *OutHandle = lock; + return AE_OK; +} + +/** + * @brief Delete a spin lock. + * + * @param Handle A handle to a lock objected that was returned by a + * previous call to AcpiOsCreateLock. + * + * @return AE_OK The lock was successfully deleted. + * @return AE_BAD_PARAMETER The Handle is invalid. + */ +void AcpiOsDeleteLock(ACPI_SPINLOCK Handle) { + free(Handle); +} + +/** + * @brief Acquire a spin lock. + * + * @param Handle A handle to a lock objected that was returned by a + * previous call to AcpiOsCreateLock. + * + * @return Platform-dependent CPU flags. To be used when the lock is released. + */ +ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK Handle) { + spin_lock_saved_state_t state; + spin_lock_irqsave(Handle, state); + return state; +} + +/** + * @brief Release a spin lock. + * + * @param Handle A handle to a lock objected that was returned by a + * previous call to AcpiOsCreateLock. + * @param Flags CPU Flags that were returned from AcpiOsAcquireLock. + */ +void AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) { + spin_unlock_irqrestore(Handle, Flags); +} + +// Wrapper structs for interfacing between our interrupt handler convention and +// ACPICA's +struct acpi_irq_wrapper_arg { + ACPI_OSD_HANDLER handler; + void *context; +}; +enum handler_return acpi_irq_wrapper(void *arg) { + struct acpi_irq_wrapper_arg *real_arg = (struct acpi_irq_wrapper_arg *)arg; + real_arg->handler(real_arg->context); + // TODO: Should we do something with the return value from the handler? + return INT_NO_RESCHEDULE; +} + +/** + * @brief Install a handler for a hardware interrupt. + * + * @param InterruptLevel Interrupt level that the handler will service. + * @param Handler Address of the handler. + * @param Context A context value that is passed to the handler when the + * interrupt is dispatched. + * + * @return AE_OK The handler was successfully installed. + * @return AE_BAD_PARAMETER The InterruptNumber is invalid or the Handler + * pointer is NULL. + * @return AE_ALREADY_EXISTS A handler for this interrupt level is already + * installed. + */ +ACPI_STATUS AcpiOsInstallInterruptHandler( + UINT32 InterruptLevel, + ACPI_OSD_HANDLER Handler, + void *Context) { + // Note that InterruptLevel here is Global IRQ, not system exceptions + // TODO: Clean this up to be less x86 centric. Ideally we want an interface + // that will let us install a handler for a Global IRQ and abstract away the + // details of what interrupt vector was picked + + ASSERT(InterruptLevel == 0x9); // SCI + apic_io_configure_isa_irq( + InterruptLevel, + DELIVERY_MODE_FIXED, + IO_APIC_IRQ_MASK, + DST_MODE_PHYSICAL, + apic_local_id(), + 0); + + struct acpi_irq_wrapper_arg *arg = malloc(sizeof(*arg)); + arg->handler = Handler; + arg->context = Context; + register_int_handler(InterruptLevel, acpi_irq_wrapper, arg); + unmask_interrupt(InterruptLevel); + return AE_OK; +} + +/** + * @brief Remove an interrupt handler. + * + * @param InterruptNumber Interrupt number that the handler is currently + * servicing. + * @param Handler Address of the handler that was previously installed. + * + * @return AE_OK The handler was successfully removed. + * @return AE_BAD_PARAMETER The InterruptNumber is invalid, the Handler + * pointer is NULL, or the Handler address is no the same as the one + * currently installed. + * @return AE_NOT_EXIST There is no handler installed for this interrupt level. + */ +ACPI_STATUS AcpiOsRemoveInterruptHandler( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER Handler) { + PANIC_UNIMPLEMENTED; + return AE_NOT_EXIST; +} + +/** + * @brief Read a value from a memory location. + * + * @param Address Memory address to be read. + * @param Value A pointer to a location where the data is to be returned. + * @param Width The memory width in bits, either 8, 16, 32, or 64. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsReadMemory( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 *Value, + UINT32 Width) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} + +/** + * @brief Write a value to a memory location. + * + * @param Address Memory address where data is to be written. + * @param Value Data to be written to the memory location. + * @param Width The memory width in bits, either 8, 16, 32, or 64. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsWriteMemory( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 Value, + UINT32 Width) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} + +/** + * @brief Read a value from an input port. + * + * @param Address Hardware I/O port address to be read. + * @param Value A pointer to a location where the data is to be returned. + * @param Width The port width in bits, either 8, 16, or 32. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsReadPort( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) { + if (Address > 0xffff) { + return AE_BAD_PARAMETER; + } + + switch (Width) { + case 8: + *Value = inp(Address); + break; + case 16: + *Value = inpw(Address); + break; + case 32: + *Value = inpd(Address); + break; + default: + return AE_BAD_PARAMETER; + } + return AE_OK; +} + +/** + * @brief Write a value to an output port. + * + * @param Address Hardware I/O port address where data is to be written. + * @param Value The value to be written. + * @param Width The port width in bits, either 8, 16, or 32. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsWritePort( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) { + if (Address > 0xffff) { + return AE_BAD_PARAMETER; + } + + switch (Width) { + case 8: + outp(Address, (uint8_t)Value); + break; + case 16: + outpw(Address, (uint16_t)Value); + break; + case 32: + outpd(Address, (uint32_t)Value); + break; + default: + return AE_BAD_PARAMETER; + } + return AE_OK; +} + +/** + * @brief Read a value from a PCI configuration register. + * + * @param PciId The full PCI configuration space address, consisting of a + * segment number, bus number, device number, and function number. + * @param Register The PCI register address to be read from. + * @param Value A pointer to a location where the data is to be returned. + * @param Width The register width in bits, either 8, 16, 32, or 64. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsReadPciConfiguration( + ACPI_PCI_ID *PciId, + UINT32 Register, + UINT64 *Value, + UINT32 Width) { + LTRACEF("Reading PCI ID ptr %p\n", PciId); + LTRACEF("Reading PCI: %02x:%02x.%x, reg %#08x, width %u\n", PciId->Bus, PciId->Device, PciId->Function, Register, Width); + // TODO: Maybe implement for real + // Pretending the answer is 0 for now makes our hardware targets work fine. + // On primary target it attempts to read some registers on the LPC endpoint. + *Value = 0; + return AE_OK; +} + +/** + * @brief Write a value to a PCI configuration register. + * + * @param PciId The full PCI configuration space address, consisting of a + * segment number, bus number, device number, and function number. + * @param Register The PCI register address to be written to. + * @param Value Data to be written. + * @param Width The register width in bits, either 8, 16, or 32. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsWritePciConfiguration( + ACPI_PCI_ID *PciId, + UINT32 Register, + UINT64 Value, + UINT32 Width) { + // TODO: Maybe implement + return AE_ERROR; +} + +/** + * @brief Formatted stream output. + * + * @param Format A standard print format string. + * @param ... + */ +void ACPI_INTERNAL_VAR_XFACE AcpiOsPrintf(const char *Format, ...) { + va_list argp; + va_start(argp, Format); + AcpiOsVprintf(Format, argp); + va_end(argp); +} + +/** + * @brief Formatted stream output. + * + * @param Format A standard print format string. + * @param Args A variable parameter list + */ +void AcpiOsVprintf(const char *Format, va_list Args) { +} + +/** + * @brief Get current value of the system timer + * + * @return The current value of the system timer in 100-ns units. + */ +UINT64 AcpiOsGetTimer() { + PANIC_UNIMPLEMENTED; + return 0; +} + +/** + * @brief Break to the debugger or display a breakpoint message. + * + * @param Function Signal to be sent to the host operating system. Either + * ACPI_SIGNAL_FATAL or ACPI_SIGNAL_BREAKPOINT + * @param Info Data associated with the signal; type depends on signal type. + * + * @return Exception code that indicates success or reason for failure. + */ +ACPI_STATUS AcpiOsSignal( + UINT32 Function, + void *Info) { + PANIC_UNIMPLEMENTED; + return AE_OK; +} + +/* @brief Acquire the ACPI global lock + * + * Implementation for ACPI_ACQUIRE_GLOBAL_LOCK + * + * @param FacsPtr pointer to the FACS ACPI structure + * + * @return True if the lock was successfully acquired + */ +bool _acpica_acquire_global_lock(void *FacsPtr) +{ + ACPI_TABLE_FACS *table = FacsPtr; + uint32_t old_val, new_val, test_val; + do { + old_val = test_val = table->GlobalLock; + new_val = old_val & ~ACPI_GLOCK_PENDING; + // If the lock is owned, we'll mark it pending + if (new_val & ACPI_GLOCK_OWNED) { + new_val |= ACPI_GLOCK_PENDING; + } + new_val |= ACPI_GLOCK_OWNED; + __atomic_compare_exchange_n(&table->GlobalLock, &old_val, new_val, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + } while (old_val != test_val); + + /* If we're here, we either acquired the lock or marked it pending */ + return !(new_val & ACPI_GLOCK_PENDING); +} + + +/* @brief Release the ACPI global lock + * + * Implementation for ACPI_RELEASE_GLOBAL_LOCK + * + * @param FacsPtr pointer to the FACS ACPI structure + * + * @return True if there is someone waiting to acquire the lock + */ +bool _acpica_release_global_lock(void *FacsPtr) +{ + ACPI_TABLE_FACS *table = FacsPtr; + uint32_t old_val, new_val, test_val; + do { + old_val = test_val = table->GlobalLock; + new_val = old_val & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED); + __atomic_compare_exchange_n(&table->GlobalLock, &old_val, new_val, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + } while (old_val != test_val); + + return !!(old_val & ACPI_GLOCK_PENDING); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osunixdir.c b/third_party/lib/acpica/source/os_specific/service_layers/osunixdir.c new file mode 100644 index 000000000..1dd101ad5 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osunixdir.c @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * Module Name: osunixdir - Unix directory access interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" + +#include +#include +#include +#include +#include +#include +#include + +/* + * Allocated structure returned from OsOpenDirectory + */ +typedef struct ExternalFindInfo +{ + char *DirPathname; + DIR *DirPtr; + char temp_buffer[256]; + char *WildcardSpec; + char RequestedFileType; + +} EXTERNAL_FIND_INFO; + + +/******************************************************************************* + * + * FUNCTION: AcpiOsOpenDirectory + * + * PARAMETERS: DirPathname - Full pathname to the directory + * WildcardSpec - string of the form "*.c", etc. + * + * RETURN: A directory "handle" to be used in subsequent search operations. + * NULL returned on failure. + * + * DESCRIPTION: Open a directory in preparation for a wildcard search + * + ******************************************************************************/ + +void * +AcpiOsOpenDirectory ( + char *DirPathname, + char *WildcardSpec, + char RequestedFileType) +{ + EXTERNAL_FIND_INFO *ExternalInfo; + DIR *dir; + + + /* Allocate the info struct that will be returned to the caller */ + + ExternalInfo = calloc (1, sizeof (EXTERNAL_FIND_INFO)); + if (!ExternalInfo) + { + return (NULL); + } + + /* Get the directory stream */ + + dir = opendir (DirPathname); + if (!dir) + { + fprintf (stderr, "Cannot open directory - %s\n", DirPathname); + free (ExternalInfo); + return (NULL); + } + + /* Save the info in the return structure */ + + ExternalInfo->WildcardSpec = WildcardSpec; + ExternalInfo->RequestedFileType = RequestedFileType; + ExternalInfo->DirPathname = DirPathname; + ExternalInfo->DirPtr = dir; + return (ExternalInfo); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsGetNextFilename + * + * PARAMETERS: DirHandle - Created via AcpiOsOpenDirectory + * + * RETURN: Next filename matched. NULL if no more matches. + * + * DESCRIPTION: Get the next file in the directory that matches the wildcard + * specification. + * + ******************************************************************************/ + +char * +AcpiOsGetNextFilename ( + void *DirHandle) +{ + EXTERNAL_FIND_INFO *ExternalInfo = DirHandle; + struct dirent *dir_entry; + char *temp_str; + int str_len; + struct stat temp_stat; + int err; + + + while ((dir_entry = readdir (ExternalInfo->DirPtr))) + { + if (!fnmatch (ExternalInfo->WildcardSpec, dir_entry->d_name, 0)) + { + if (dir_entry->d_name[0] == '.') + { + continue; + } + + str_len = strlen (dir_entry->d_name) + + strlen (ExternalInfo->DirPathname) + 2; + + temp_str = calloc (str_len, 1); + if (!temp_str) + { + fprintf (stderr, + "Could not allocate buffer for temporary string\n"); + return (NULL); + } + + strcpy (temp_str, ExternalInfo->DirPathname); + strcat (temp_str, "/"); + strcat (temp_str, dir_entry->d_name); + + err = stat (temp_str, &temp_stat); + if (err == -1) + { + fprintf (stderr, + "Cannot stat file (should not happen) - %s\n", + temp_str); + free (temp_str); + return (NULL); + } + + free (temp_str); + + if ((S_ISDIR (temp_stat.st_mode) + && (ExternalInfo->RequestedFileType == REQUEST_DIR_ONLY)) + || + ((!S_ISDIR (temp_stat.st_mode) + && ExternalInfo->RequestedFileType == REQUEST_FILE_ONLY))) + { + /* copy to a temp buffer because dir_entry struct is on the stack */ + + strcpy (ExternalInfo->temp_buffer, dir_entry->d_name); + return (ExternalInfo->temp_buffer); + } + } + } + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsCloseDirectory + * + * PARAMETERS: DirHandle - Created via AcpiOsOpenDirectory + * + * RETURN: None. + * + * DESCRIPTION: Close the open directory and cleanup. + * + ******************************************************************************/ + +void +AcpiOsCloseDirectory ( + void *DirHandle) +{ + EXTERNAL_FIND_INFO *ExternalInfo = DirHandle; + + + /* Close the directory and free allocations */ + + closedir (ExternalInfo->DirPtr); + free (DirHandle); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osunixmap.c b/third_party/lib/acpica/source/os_specific/service_layers/osunixmap.c new file mode 100644 index 000000000..9133f575d --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osunixmap.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Module Name: osunixmap - Unix OSL for file mappings + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" +#include +#include +#ifdef _FreeBSD +#include +#endif + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("osunixmap") + + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#if defined(_DragonFly) || defined(_FreeBSD) +#define MMAP_FLAGS MAP_SHARED +#else +#define MMAP_FLAGS MAP_PRIVATE +#endif + +#define SYSTEM_MEMORY "/dev/mem" + + +/******************************************************************************* + * + * FUNCTION: AcpiOsGetPageSize + * + * PARAMETERS: None + * + * RETURN: Page size of the platform. + * + * DESCRIPTION: Obtain page size of the platform. + * + ******************************************************************************/ + +static ACPI_SIZE +AcpiOsGetPageSize ( + void) +{ + +#ifdef PAGE_SIZE + return PAGE_SIZE; +#else + return sysconf (_SC_PAGESIZE); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsMapMemory + * + * PARAMETERS: Where - Physical address of memory to be mapped + * Length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into local address space. + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length) +{ + UINT8 *MappedMemory; + ACPI_PHYSICAL_ADDRESS Offset; + ACPI_SIZE PageSize; + int fd; + + + fd = open (SYSTEM_MEMORY, O_RDONLY | O_BINARY); + if (fd < 0) + { + fprintf (stderr, "Cannot open %s\n", SYSTEM_MEMORY); + return (NULL); + } + + /* Align the offset to use mmap */ + + PageSize = AcpiOsGetPageSize (); + Offset = Where % PageSize; + + /* Map the table header to get the length of the full table */ + + MappedMemory = mmap (NULL, (Length + Offset), PROT_READ, MMAP_FLAGS, + fd, (Where - Offset)); + if (MappedMemory == MAP_FAILED) + { + fprintf (stderr, "Cannot map %s\n", SYSTEM_MEMORY); + close (fd); + return (NULL); + } + + close (fd); + return (ACPI_CAST8 (MappedMemory + Offset)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: Where - Logical address of memory to be unmapped + * Length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *Where, + ACPI_SIZE Length) +{ + ACPI_PHYSICAL_ADDRESS Offset; + ACPI_SIZE PageSize; + + + PageSize = AcpiOsGetPageSize (); + Offset = ACPI_TO_INTEGER (Where) % PageSize; + munmap ((UINT8 *) Where - Offset, (Length + Offset)); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/osunixxf.c b/third_party/lib/acpica/source/os_specific/service_layers/osunixxf.c new file mode 100644 index 000000000..21ac91d84 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/osunixxf.c @@ -0,0 +1,1540 @@ +/****************************************************************************** + * + * Module Name: osunixxf - UNIX OSL interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * These interfaces are required in order to compile the ASL compiler and the + * various ACPICA tools under Linux or other Unix-like system. + */ +#include "acpi.h" +#include "accommon.h" +#include "amlcode.h" +#include "acparser.h" +#include "acdebug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("osunixxf") + + +BOOLEAN AcpiGbl_DebugTimeout = FALSE; + + +/* Upcalls to AcpiExec */ + +void +AeTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable); + +typedef void* (*PTHREAD_CALLBACK) (void *); + +/* Buffer used by AcpiOsVprintf */ + +#define ACPI_VPRINTF_BUFFER_SIZE 512 +#define _ASCII_NEWLINE '\n' + +/* Terminal support for AcpiExec only */ + +#ifdef ACPI_EXEC_APP +#include + +struct termios OriginalTermAttributes; +int TermAttributesWereSet = 0; + +ACPI_STATUS +AcpiUtReadLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead); + +static void +OsEnterLineEditMode ( + void); + +static void +OsExitLineEditMode ( + void); + + +/****************************************************************************** + * + * FUNCTION: OsEnterLineEditMode, OsExitLineEditMode + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Enter/Exit the raw character input mode for the terminal. + * + * Interactive line-editing support for the AML debugger. Used with the + * common/acgetline module. + * + * readline() is not used because of non-portability. It is not available + * on all systems, and if it is, often the package must be manually installed. + * + * Therefore, we use the POSIX tcgetattr/tcsetattr and do the minimal line + * editing that we need in AcpiOsGetLine. + * + * If the POSIX tcgetattr/tcsetattr interfaces are unavailable, these + * calls will also work: + * For OsEnterLineEditMode: system ("stty cbreak -echo") + * For OsExitLineEditMode: system ("stty cooked echo") + * + *****************************************************************************/ + +static void +OsEnterLineEditMode ( + void) +{ + struct termios LocalTermAttributes; + + + TermAttributesWereSet = 0; + + /* STDIN must be a terminal */ + + if (!isatty (STDIN_FILENO)) + { + return; + } + + /* Get and keep the original attributes */ + + if (tcgetattr (STDIN_FILENO, &OriginalTermAttributes)) + { + fprintf (stderr, "Could not get terminal attributes!\n"); + return; + } + + /* Set the new attributes to enable raw character input */ + + memcpy (&LocalTermAttributes, &OriginalTermAttributes, + sizeof (struct termios)); + + LocalTermAttributes.c_lflag &= ~(ICANON | ECHO); + LocalTermAttributes.c_cc[VMIN] = 1; + LocalTermAttributes.c_cc[VTIME] = 0; + + if (tcsetattr (STDIN_FILENO, TCSANOW, &LocalTermAttributes)) + { + fprintf (stderr, "Could not set terminal attributes!\n"); + return; + } + + TermAttributesWereSet = 1; +} + + +static void +OsExitLineEditMode ( + void) +{ + + if (!TermAttributesWereSet) + { + return; + } + + /* Set terminal attributes back to the original values */ + + if (tcsetattr (STDIN_FILENO, TCSANOW, &OriginalTermAttributes)) + { + fprintf (stderr, "Could not restore terminal attributes!\n"); + } +} + + +#else + +/* These functions are not needed for other ACPICA utilities */ + +#define OsEnterLineEditMode() +#define OsExitLineEditMode() +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInitialize, AcpiOsTerminate + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize and terminate this module. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsInitialize ( + void) +{ + ACPI_STATUS Status; + + + AcpiGbl_OutputFile = stdout; + + OsEnterLineEditMode (); + + Status = AcpiOsCreateLock (&AcpiGbl_PrintLock); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (AE_OK); +} + +ACPI_STATUS +AcpiOsTerminate ( + void) +{ + + OsExitLineEditMode (); + return (AE_OK); +} + + +#ifndef ACPI_USE_NATIVE_RSDP_POINTER +/****************************************************************************** + * + * FUNCTION: AcpiOsGetRootPointer + * + * PARAMETERS: None + * + * RETURN: RSDP physical address + * + * DESCRIPTION: Gets the ACPI root pointer (RSDP) + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + + return (0); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPredefinedOverride + * + * PARAMETERS: InitVal - Initial value of the predefined object + * NewVal - The new value for the object + * + * RETURN: Status, pointer to value. Null pointer returned if not + * overriding. + * + * DESCRIPTION: Allow the OS to override predefined names + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsPredefinedOverride ( + const ACPI_PREDEFINED_NAMES *InitVal, + ACPI_STRING *NewVal) +{ + + if (!InitVal || !NewVal) + { + return (AE_BAD_PARAMETER); + } + + *NewVal = NULL; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsTableOverride + * + * PARAMETERS: ExistingTable - Header of current table (probably + * firmware) + * NewTable - Where an entire new table is returned. + * + * RETURN: Status, pointer to new table. Null pointer returned if no + * table is available to override + * + * DESCRIPTION: Return a different version of a table if one is available + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable) +{ + + if (!ExistingTable || !NewTable) + { + return (AE_BAD_PARAMETER); + } + + *NewTable = NULL; + +#ifdef ACPI_EXEC_APP + + AeTableOverride (ExistingTable, NewTable); + return (AE_OK); +#else + + return (AE_NO_ACPI_TABLES); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPhysicalTableOverride + * + * PARAMETERS: ExistingTable - Header of current table (probably firmware) + * NewAddress - Where new table address is returned + * (Physical address) + * NewTableLength - Where new table length is returned + * + * RETURN: Status, address/length of new table. Null pointer returned + * if no table is available to override. + * + * DESCRIPTION: Returns AE_SUPPORT, function not used in user space. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsPhysicalTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_PHYSICAL_ADDRESS *NewAddress, + UINT32 *NewTableLength) +{ + + return (AE_SUPPORT); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsRedirectOutput + * + * PARAMETERS: Destination - An open file handle/pointer + * + * RETURN: None + * + * DESCRIPTION: Causes redirect of AcpiOsPrintf and AcpiOsVprintf + * + *****************************************************************************/ + +void +AcpiOsRedirectOutput ( + void *Destination) +{ + + AcpiGbl_OutputFile = Destination; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPrintf + * + * PARAMETERS: fmt, ... - Standard printf format + * + * RETURN: None + * + * DESCRIPTION: Formatted output. Note: very similar to AcpiOsVprintf + * (performance), changes should be tracked in both functions. + * + *****************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiOsPrintf ( + const char *Fmt, + ...) +{ + va_list Args; + UINT8 Flags; + + + Flags = AcpiGbl_DbOutputFlags; + if (Flags & ACPI_DB_REDIRECTABLE_OUTPUT) + { + /* Output is directable to either a file (if open) or the console */ + + if (AcpiGbl_DebugFile) + { + /* Output file is open, send the output there */ + + va_start (Args, Fmt); + vfprintf (AcpiGbl_DebugFile, Fmt, Args); + va_end (Args); + } + else + { + /* No redirection, send output to console (once only!) */ + + Flags |= ACPI_DB_CONSOLE_OUTPUT; + } + } + + if (Flags & ACPI_DB_CONSOLE_OUTPUT) + { + va_start (Args, Fmt); + vfprintf (AcpiGbl_OutputFile, Fmt, Args); + va_end (Args); + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsVprintf + * + * PARAMETERS: fmt - Standard printf format + * args - Argument list + * + * RETURN: None + * + * DESCRIPTION: Formatted output with argument list pointer. Note: very + * similar to AcpiOsPrintf, changes should be tracked in both + * functions. + * + *****************************************************************************/ + +void +AcpiOsVprintf ( + const char *Fmt, + va_list Args) +{ + UINT8 Flags; + char Buffer[ACPI_VPRINTF_BUFFER_SIZE]; + + + /* + * We build the output string in a local buffer because we may be + * outputting the buffer twice. Using vfprintf is problematic because + * some implementations modify the args pointer/structure during + * execution. Thus, we use the local buffer for portability. + * + * Note: Since this module is intended for use by the various ACPICA + * utilities/applications, we can safely declare the buffer on the stack. + * Also, This function is used for relatively small error messages only. + */ + vsnprintf (Buffer, ACPI_VPRINTF_BUFFER_SIZE, Fmt, Args); + + Flags = AcpiGbl_DbOutputFlags; + if (Flags & ACPI_DB_REDIRECTABLE_OUTPUT) + { + /* Output is directable to either a file (if open) or the console */ + + if (AcpiGbl_DebugFile) + { + /* Output file is open, send the output there */ + + fputs (Buffer, AcpiGbl_DebugFile); + } + else + { + /* No redirection, send output to console (once only!) */ + + Flags |= ACPI_DB_CONSOLE_OUTPUT; + } + } + + if (Flags & ACPI_DB_CONSOLE_OUTPUT) + { + fputs (Buffer, AcpiGbl_OutputFile); + } +} + + +#ifndef ACPI_EXEC_APP +/****************************************************************************** + * + * FUNCTION: AcpiOsGetLine + * + * PARAMETERS: Buffer - Where to return the command line + * BufferLength - Maximum length of Buffer + * BytesRead - Where the actual byte count is returned + * + * RETURN: Status and actual bytes read + * + * DESCRIPTION: Get the next input line from the terminal. NOTE: For the + * AcpiExec utility, we use the acgetline module instead to + * provide line-editing and history support. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead) +{ + int InputChar; + UINT32 EndOfLine; + + + /* Standard AcpiOsGetLine for all utilities except AcpiExec */ + + for (EndOfLine = 0; ; EndOfLine++) + { + if (EndOfLine >= BufferLength) + { + return (AE_BUFFER_OVERFLOW); + } + + if ((InputChar = getchar ()) == EOF) + { + return (AE_ERROR); + } + + if (!InputChar || InputChar == _ASCII_NEWLINE) + { + break; + } + + Buffer[EndOfLine] = (char) InputChar; + } + + /* Null terminate the buffer */ + + Buffer[EndOfLine] = 0; + + /* Return the number of bytes in the string */ + + if (BytesRead) + { + *BytesRead = EndOfLine; + } + + return (AE_OK); +} +#endif + + +#ifndef ACPI_USE_NATIVE_MEMORY_MAPPING +/****************************************************************************** + * + * FUNCTION: AcpiOsMapMemory + * + * PARAMETERS: where - Physical address of memory to be mapped + * length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into caller's address space + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS where, + ACPI_SIZE length) +{ + + return (ACPI_TO_POINTER ((ACPI_SIZE) where)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: where - Logical address of memory to be unmapped + * length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *where, + ACPI_SIZE length) +{ + + return; +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocate + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocate ( + ACPI_SIZE size) +{ + void *Mem; + + + Mem = (void *) malloc ((size_t) size); + return (Mem); +} + + +#ifdef USE_NATIVE_ALLOCATE_ZEROED +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocateZeroed + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate and zero memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE size) +{ + void *Mem; + + + Mem = (void *) calloc (1, (size_t) size); + return (Mem); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsFree + * + * PARAMETERS: mem - Pointer to previously allocated memory + * + * RETURN: None. + * + * DESCRIPTION: Free memory allocated via AcpiOsAllocate + * + *****************************************************************************/ + +void +AcpiOsFree ( + void *mem) +{ + + free (mem); +} + + +#ifdef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: Semaphore stub functions + * + * DESCRIPTION: Stub functions used for single-thread applications that do + * not require semaphore synchronization. Full implementations + * of these functions appear after the stubs. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_HANDLE *OutHandle) +{ + *OutHandle = (ACPI_HANDLE) 1; + return (AE_OK); +} + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_HANDLE Handle) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units, + UINT16 Timeout) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units) +{ + return (AE_OK); +} + +#else +/****************************************************************************** + * + * FUNCTION: AcpiOsCreateSemaphore + * + * PARAMETERS: InitialUnits - Units to be assigned to the new semaphore + * OutHandle - Where a handle will be returned + * + * RETURN: Status + * + * DESCRIPTION: Create an OS semaphore + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_HANDLE *OutHandle) +{ + sem_t *Sem; + + + if (!OutHandle) + { + return (AE_BAD_PARAMETER); + } + +#ifdef __APPLE__ + { + char *SemaphoreName = tmpnam (NULL); + + Sem = sem_open (SemaphoreName, O_EXCL|O_CREAT, 0755, InitialUnits); + if (!Sem) + { + return (AE_NO_MEMORY); + } + sem_unlink (SemaphoreName); /* This just deletes the name */ + } + +#else + Sem = AcpiOsAllocate (sizeof (sem_t)); + if (!Sem) + { + return (AE_NO_MEMORY); + } + + if (sem_init (Sem, 0, InitialUnits) == -1) + { + AcpiOsFree (Sem); + return (AE_BAD_PARAMETER); + } +#endif + + *OutHandle = (ACPI_HANDLE) Sem; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsDeleteSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * + * RETURN: Status + * + * DESCRIPTION: Delete an OS semaphore + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_HANDLE Handle) +{ + sem_t *Sem = (sem_t *) Handle; + + + if (!Sem) + { + return (AE_BAD_PARAMETER); + } + + if (sem_destroy (Sem) == -1) + { + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWaitSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * Units - How many units to wait for + * MsecTimeout - How long to wait (milliseconds) + * + * RETURN: Status + * + * DESCRIPTION: Wait for units + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units, + UINT16 MsecTimeout) +{ + ACPI_STATUS Status = AE_OK; + sem_t *Sem = (sem_t *) Handle; +#ifndef ACPI_USE_ALTERNATE_TIMEOUT + struct timespec Time; + int RetVal; +#endif + + + if (!Sem) + { + return (AE_BAD_PARAMETER); + } + + switch (MsecTimeout) + { + /* + * No Wait: + * -------- + * A zero timeout value indicates that we shouldn't wait - just + * acquire the semaphore if available otherwise return AE_TIME + * (a.k.a. 'would block'). + */ + case 0: + + if (sem_trywait(Sem) == -1) + { + Status = (AE_TIME); + } + break; + + /* Wait Indefinitely */ + + case ACPI_WAIT_FOREVER: + + if (sem_wait (Sem)) + { + Status = (AE_TIME); + } + break; + + /* Wait with MsecTimeout */ + + default: + +#ifdef ACPI_USE_ALTERNATE_TIMEOUT + /* + * Alternate timeout mechanism for environments where + * sem_timedwait is not available or does not work properly. + */ + while (MsecTimeout) + { + if (sem_trywait (Sem) == 0) + { + /* Got the semaphore */ + return (AE_OK); + } + + if (MsecTimeout >= 10) + { + MsecTimeout -= 10; + usleep (10 * ACPI_USEC_PER_MSEC); /* ten milliseconds */ + } + else + { + MsecTimeout--; + usleep (ACPI_USEC_PER_MSEC); /* one millisecond */ + } + } + Status = (AE_TIME); +#else + /* + * The interface to sem_timedwait is an absolute time, so we need to + * get the current time, then add in the millisecond Timeout value. + */ + if (clock_gettime (CLOCK_REALTIME, &Time) == -1) + { + perror ("clock_gettime"); + return (AE_TIME); + } + + Time.tv_sec += (MsecTimeout / ACPI_MSEC_PER_SEC); + Time.tv_nsec += ((MsecTimeout % ACPI_MSEC_PER_SEC) * ACPI_NSEC_PER_MSEC); + + /* Handle nanosecond overflow (field must be less than one second) */ + + if (Time.tv_nsec >= ACPI_NSEC_PER_SEC) + { + Time.tv_sec += (Time.tv_nsec / ACPI_NSEC_PER_SEC); + Time.tv_nsec = (Time.tv_nsec % ACPI_NSEC_PER_SEC); + } + + while (((RetVal = sem_timedwait (Sem, &Time)) == -1) && (errno == EINTR)) + { + continue; + } + + if (RetVal != 0) + { + if (errno != ETIMEDOUT) + { + perror ("sem_timedwait"); + } + Status = (AE_TIME); + } +#endif + break; + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSignalSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * Units - Number of units to send + * + * RETURN: Status + * + * DESCRIPTION: Send units + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units) +{ + sem_t *Sem = (sem_t *)Handle; + + + if (!Sem) + { + return (AE_BAD_PARAMETER); + } + + if (sem_post (Sem) == -1) + { + return (AE_LIMIT); + } + + return (AE_OK); +} + +#endif /* ACPI_SINGLE_THREADED */ + + +/****************************************************************************** + * + * FUNCTION: Spinlock interfaces + * + * DESCRIPTION: Map these interfaces to semaphore interfaces + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateLock ( + ACPI_SPINLOCK *OutHandle) +{ + + return (AcpiOsCreateSemaphore (1, 1, OutHandle)); +} + + +void +AcpiOsDeleteLock ( + ACPI_SPINLOCK Handle) +{ + AcpiOsDeleteSemaphore (Handle); +} + + +ACPI_CPU_FLAGS +AcpiOsAcquireLock ( + ACPI_HANDLE Handle) +{ + AcpiOsWaitSemaphore (Handle, 1, 0xFFFF); + return (0); +} + + +void +AcpiOsReleaseLock ( + ACPI_SPINLOCK Handle, + ACPI_CPU_FLAGS Flags) +{ + AcpiOsSignalSemaphore (Handle, 1); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInstallInterruptHandler + * + * PARAMETERS: InterruptNumber - Level handler should respond to. + * Isr - Address of the ACPI interrupt handler + * ExceptPtr - Where status is returned + * + * RETURN: Handle to the newly installed handler. + * + * DESCRIPTION: Install an interrupt handler. Used to install the ACPI + * OS-independent handler. + * + *****************************************************************************/ + +UINT32 +AcpiOsInstallInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine, + void *Context) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsRemoveInterruptHandler + * + * PARAMETERS: Handle - Returned when handler was installed + * + * RETURN: Status + * + * DESCRIPTION: Uninstalls an interrupt handler. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsRemoveInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsStall + * + * PARAMETERS: microseconds - Time to sleep + * + * RETURN: Blocks until sleep is completed. + * + * DESCRIPTION: Sleep at microsecond granularity + * + *****************************************************************************/ + +void +AcpiOsStall ( + UINT32 microseconds) +{ + + if (microseconds) + { + usleep (microseconds); + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSleep + * + * PARAMETERS: milliseconds - Time to sleep + * + * RETURN: Blocks until sleep is completed. + * + * DESCRIPTION: Sleep at millisecond granularity + * + *****************************************************************************/ + +void +AcpiOsSleep ( + UINT64 milliseconds) +{ + + /* Sleep for whole seconds */ + + sleep (milliseconds / ACPI_MSEC_PER_SEC); + + /* + * Sleep for remaining microseconds. + * Arg to usleep() is in usecs and must be less than 1,000,000 (1 second). + */ + usleep ((milliseconds % ACPI_MSEC_PER_SEC) * ACPI_USEC_PER_MSEC); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTimer + * + * PARAMETERS: None + * + * RETURN: Current time in 100 nanosecond units + * + * DESCRIPTION: Get the current system time + * + *****************************************************************************/ + +UINT64 +AcpiOsGetTimer ( + void) +{ + struct timeval time; + + + /* This timer has sufficient resolution for user-space application code */ + + gettimeofday (&time, NULL); + + /* (Seconds * 10^7 = 100ns(10^-7)) + (Microseconds(10^-6) * 10^1 = 100ns) */ + + return (((UINT64) time.tv_sec * ACPI_100NSEC_PER_SEC) + + ((UINT64) time.tv_usec * ACPI_100NSEC_PER_USEC)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadPciConfiguration + * + * PARAMETERS: PciId - Seg/Bus/Dev + * PciRegister - Device Register + * Value - Buffer where value is placed + * Width - Number of bits + * + * RETURN: Status + * + * DESCRIPTION: Read data from PCI configuration space + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadPciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 PciRegister, + UINT64 *Value, + UINT32 Width) +{ + + *Value = 0; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritePciConfiguration + * + * PARAMETERS: PciId - Seg/Bus/Dev + * PciRegister - Device Register + * Value - Value to be written + * Width - Number of bits + * + * RETURN: Status. + * + * DESCRIPTION: Write data to PCI configuration space + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWritePciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 PciRegister, + UINT64 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadPort + * + * PARAMETERS: Address - Address of I/O port/register to read + * Value - Where value is placed + * Width - Number of bits + * + * RETURN: Value read from port + * + * DESCRIPTION: Read data from an I/O port or register + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + + switch (Width) + { + case 8: + + *Value = 0xFF; + break; + + case 16: + + *Value = 0xFFFF; + break; + + case 32: + + *Value = 0xFFFFFFFF; + break; + + default: + + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritePort + * + * PARAMETERS: Address - Address of I/O port/register to write + * Value - Value to write + * Width - Number of bits + * + * RETURN: None + * + * DESCRIPTION: Write data to an I/O port or register + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadMemory + * + * PARAMETERS: Address - Physical Memory Address to read + * Value - Where value is placed + * Width - Number of bits (8,16,32, or 64) + * + * RETURN: Value read from physical memory address. Always returned + * as a 64-bit integer, regardless of the read width. + * + * DESCRIPTION: Read data from a physical memory address + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 *Value, + UINT32 Width) +{ + + switch (Width) + { + case 8: + case 16: + case 32: + case 64: + + *Value = 0; + break; + + default: + + return (AE_BAD_PARAMETER); + } + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWriteMemory + * + * PARAMETERS: Address - Physical Memory Address to write + * Value - Value to write + * Width - Number of bits (8,16,32, or 64) + * + * RETURN: None + * + * DESCRIPTION: Write data to a physical memory address + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWriteMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadable + * + * PARAMETERS: Pointer - Area to be verified + * Length - Size of area + * + * RETURN: TRUE if readable for entire length + * + * DESCRIPTION: Verify that a pointer is valid for reading + * + *****************************************************************************/ + +BOOLEAN +AcpiOsReadable ( + void *Pointer, + ACPI_SIZE Length) +{ + + return (TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritable + * + * PARAMETERS: Pointer - Area to be verified + * Length - Size of area + * + * RETURN: TRUE if writable for entire length + * + * DESCRIPTION: Verify that a pointer is valid for writing + * + *****************************************************************************/ + +BOOLEAN +AcpiOsWritable ( + void *Pointer, + ACPI_SIZE Length) +{ + + return (TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSignal + * + * PARAMETERS: Function - ACPI A signal function code + * Info - Pointer to function-dependent structure + * + * RETURN: Status + * + * DESCRIPTION: Miscellaneous functions. Example implementation only. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsSignal ( + UINT32 Function, + void *Info) +{ + + switch (Function) + { + case ACPI_SIGNAL_FATAL: + + break; + + case ACPI_SIGNAL_BREAKPOINT: + + break; + + default: + + break; + } + + return (AE_OK); +} + +/* Optional multi-thread support */ + +#ifndef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: AcpiOsGetThreadId + * + * PARAMETERS: None + * + * RETURN: Id of the running thread + * + * DESCRIPTION: Get the ID of the current (running) thread + * + *****************************************************************************/ + +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + pthread_t thread; + + + thread = pthread_self(); + return (ACPI_CAST_PTHREAD_T (thread)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsExecute + * + * PARAMETERS: Type - Type of execution + * Function - Address of the function to execute + * Context - Passed as a parameter to the function + * + * RETURN: Status. + * + * DESCRIPTION: Execute a new thread + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) +{ + pthread_t thread; + int ret; + + + ret = pthread_create (&thread, NULL, (PTHREAD_CALLBACK) Function, Context); + if (ret) + { + AcpiOsPrintf("Create thread failed"); + } + return (0); +} + +#else /* ACPI_SINGLE_THREADED */ +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + return (1); +} + +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) +{ + + Function (Context); + + return (AE_OK); +} + +#endif /* ACPI_SINGLE_THREADED */ + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWaitEventsComplete + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Wait for all asynchronous events to complete. This + * implementation does nothing. + * + *****************************************************************************/ + +void +AcpiOsWaitEventsComplete ( + void) +{ + return; +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/oswindir.c b/third_party/lib/acpica/source/os_specific/service_layers/oswindir.c new file mode 100644 index 000000000..9194021c4 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/oswindir.c @@ -0,0 +1,252 @@ +/****************************************************************************** + * + * Module Name: oswindir - Windows directory access interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include + +#include +#include +#include +#include + +typedef struct ExternalFindInfo +{ + struct _finddata_t DosInfo; + char *FullWildcardSpec; + long FindHandle; + char State; + char RequestedFileType; + +} EXTERNAL_FIND_INFO; + + +/******************************************************************************* + * + * FUNCTION: AcpiOsOpenDirectory + * + * PARAMETERS: DirPathname - Full pathname to the directory + * WildcardSpec - string of the form "*.c", etc. + * RequestedFileType - Either a directory or normal file + * + * RETURN: A directory "handle" to be used in subsequent search operations. + * NULL returned on failure. + * + * DESCRIPTION: Open a directory in preparation for a wildcard search + * + ******************************************************************************/ + +void * +AcpiOsOpenDirectory ( + char *DirPathname, + char *WildcardSpec, + char RequestedFileType) +{ + long FindHandle; + char *FullWildcardSpec; + EXTERNAL_FIND_INFO *SearchInfo; + + + /* No directory path means "use current directory" - use a dot */ + + if (!DirPathname || strlen (DirPathname) == 0) + { + DirPathname = "."; + } + + /* Allocate the info struct that will be returned to the caller */ + + SearchInfo = calloc (sizeof (EXTERNAL_FIND_INFO), 1); + if (!SearchInfo) + { + return (NULL); + } + + /* Allocate space for the full wildcard path */ + + FullWildcardSpec = calloc ( + strlen (DirPathname) + strlen (WildcardSpec) + 2, 1); + if (!FullWildcardSpec) + { + printf ("Could not allocate buffer for wildcard pathname\n"); + free (SearchInfo); + return (NULL); + } + + /* Create the full wildcard path */ + + strcpy (FullWildcardSpec, DirPathname); + strcat (FullWildcardSpec, "/"); + strcat (FullWildcardSpec, WildcardSpec); + + /* Initialize the find functions, get first match */ + + FindHandle = _findfirst (FullWildcardSpec, &SearchInfo->DosInfo); + if (FindHandle == -1) + { + /* Failure means that no match was found */ + + free (FullWildcardSpec); + free (SearchInfo); + return (NULL); + } + + /* Save the info in the return structure */ + + SearchInfo->RequestedFileType = RequestedFileType; + SearchInfo->FullWildcardSpec = FullWildcardSpec; + SearchInfo->FindHandle = FindHandle; + SearchInfo->State = 0; + return (SearchInfo); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsGetNextFilename + * + * PARAMETERS: DirHandle - Created via AcpiOsOpenDirectory + * + * RETURN: Next filename matched. NULL if no more matches. + * + * DESCRIPTION: Get the next file in the directory that matches the wildcard + * specification. + * + ******************************************************************************/ + +char * +AcpiOsGetNextFilename ( + void *DirHandle) +{ + EXTERNAL_FIND_INFO *SearchInfo = DirHandle; + int Status; + char FileTypeNotMatched = 1; + + + /* + * Loop while we have matched files but not found any files of + * the requested type. + */ + while (FileTypeNotMatched) + { + /* On the first call, we already have the first match */ + + if (SearchInfo->State == 0) + { + /* No longer the first match */ + + SearchInfo->State = 1; + } + else + { + /* Get the next match */ + + Status = _findnext (SearchInfo->FindHandle, &SearchInfo->DosInfo); + if (Status != 0) + { + return (NULL); + } + } + + /* + * Found a match, now check to make sure that the file type + * matches the requested file type (directory or normal file) + * + * NOTE: use of the attrib field saves us from doing a very + * expensive stat() on the file! + */ + switch (SearchInfo->RequestedFileType) + { + case REQUEST_FILE_ONLY: + + /* Anything other than A_SUBDIR is OK */ + + if (!(SearchInfo->DosInfo.attrib & _A_SUBDIR)) + { + FileTypeNotMatched = 0; + } + break; + + case REQUEST_DIR_ONLY: + + /* Must have A_SUBDIR bit set */ + + if (SearchInfo->DosInfo.attrib & _A_SUBDIR) + { + FileTypeNotMatched = 0; + } + break; + + default: + + return (NULL); + } + } + + return (SearchInfo->DosInfo.name); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiOsCloseDirectory + * + * PARAMETERS: DirHandle - Created via AcpiOsOpenDirectory + * + * RETURN: None + * + * DESCRIPTION: Close the open directory and cleanup. + * + ******************************************************************************/ + +void +AcpiOsCloseDirectory ( + void *DirHandle) +{ + EXTERNAL_FIND_INFO *SearchInfo = DirHandle; + + + /* Close the directory and free allocations */ + + _findclose (SearchInfo->FindHandle); + free (SearchInfo->FullWildcardSpec); + free (DirHandle); +} diff --git a/third_party/lib/acpica/source/os_specific/service_layers/oswintbl.c b/third_party/lib/acpica/source/os_specific/service_layers/oswintbl.c new file mode 100644 index 000000000..4e6e9ded2 --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/oswintbl.c @@ -0,0 +1,419 @@ +/****************************************************************************** + * + * Module Name: oswintbl - Windows OSL for obtaining ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acutils.h" +#include + +#ifdef WIN32 +#pragma warning(disable:4115) /* warning C4115: (caused by rpcasync.h) */ +#include + +#elif WIN64 +#include +#endif + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("oswintbl") + +/* Local prototypes */ + +static char * +WindowsFormatException ( + LONG WinStatus); + +/* Globals */ + +#define LOCAL_BUFFER_SIZE 64 + +static char KeyBuffer[LOCAL_BUFFER_SIZE]; +static char ErrorBuffer[LOCAL_BUFFER_SIZE]; + +/* + * Tables supported in the Windows registry. SSDTs are not placed into + * the registry, a limitation. + */ +static char *SupportedTables[] = +{ + "DSDT", + "RSDT", + "FACS", + "FACP" +}; + +/* Max index for table above */ + +#define ACPI_OS_MAX_TABLE_INDEX 3 + + +/****************************************************************************** + * + * FUNCTION: WindowsFormatException + * + * PARAMETERS: WinStatus - Status from a Windows system call + * + * RETURN: Formatted (ascii) exception code. Front-end to Windows + * FormatMessage interface. + * + * DESCRIPTION: Decode a windows exception + * + *****************************************************************************/ + +static char * +WindowsFormatException ( + LONG WinStatus) +{ + + ErrorBuffer[0] = 0; + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, WinStatus, 0, + ErrorBuffer, LOCAL_BUFFER_SIZE, NULL); + + return (ErrorBuffer); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByAddress + * + * PARAMETERS: Address - Physical address of the ACPI table + * Table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get an ACPI table via a physical memory address. + * + * NOTE: Cannot be implemented without a Windows device driver. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByAddress ( + ACPI_PHYSICAL_ADDRESS Address, + ACPI_TABLE_HEADER **Table) +{ + + fprintf (stderr, "Get table by address is not supported on Windows\n"); + return (AE_SUPPORT); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByIndex + * + * PARAMETERS: Index - Which table to get + * Table - Where a pointer to the table is returned + * Instance - Where a pointer to the table instance no. is + * returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Index is beyond valid limit + * + * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns + * AE_LIMIT when an invalid index is reached. Index is not + * necessarily an index into the RSDT/XSDT. + * Table is obtained from the Windows registry. + * + * NOTE: Cannot get the physical address from the windows registry; + * zero is returned instead. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByIndex ( + UINT32 Index, + ACPI_TABLE_HEADER **Table, + UINT32 *Instance, + ACPI_PHYSICAL_ADDRESS *Address) +{ + ACPI_STATUS Status; + + + if (Index > ACPI_OS_MAX_TABLE_INDEX) + { + return (AE_LIMIT); + } + + Status = AcpiOsGetTableByName (SupportedTables[Index], 0, Table, Address); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTableByName + * + * PARAMETERS: Signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * Instance - For SSDTs (0...n). Use 0 otherwise. + * Table - Where a pointer to the table is returned + * Address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters). + * Returns AE_LIMIT when an invalid instance is reached. + * Table is obtained from the Windows registry. + * + * NOTE: Assumes the input signature is uppercase. + * Cannot get the physical address from the windows registry; + * zero is returned instead. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetTableByName ( + char *Signature, + UINT32 Instance, + ACPI_TABLE_HEADER **Table, + ACPI_PHYSICAL_ADDRESS *Address) +{ + HKEY Handle = NULL; + LONG WinStatus; + ULONG Type; + ULONG NameSize; + ULONG DataSize; + HKEY SubKey; + ULONG i; + ACPI_TABLE_HEADER *ReturnTable; + ACPI_STATUS Status = AE_OK; + + + /* + * Windows has no SSDTs in the registry, so multiple instances are + * not supported. + */ + if (Instance > 0) + { + return (AE_LIMIT); + } + + /* Get a handle to the table key */ + + while (1) + { + strcpy (KeyBuffer, "HARDWARE\\ACPI\\"); + if (AcpiUtSafeStrcat (KeyBuffer, sizeof (KeyBuffer), Signature)) + { + return (AE_BUFFER_OVERFLOW); + } + + WinStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyBuffer, + 0L, KEY_READ, &Handle); + + if (WinStatus != ERROR_SUCCESS) + { + /* + * Somewhere along the way, MS changed the registry entry for + * the FADT from + * HARDWARE/ACPI/FACP to + * HARDWARE/ACPI/FADT. + * + * This code allows for both. + */ + if (ACPI_COMPARE_NAME (Signature, "FACP")) + { + Signature = "FADT"; + } + else if (ACPI_COMPARE_NAME (Signature, "XSDT")) + { + Signature = "RSDT"; + } + else + { + fprintf (stderr, + "Could not find %s in registry at %s: %s (WinStatus=0x%X)\n", + Signature, KeyBuffer, WindowsFormatException (WinStatus), WinStatus); + return (AE_NOT_FOUND); + } + } + else + { + break; + } + } + + /* Actual data for the table is down a couple levels */ + + for (i = 0; ;) + { + WinStatus = RegEnumKey (Handle, i, KeyBuffer, sizeof (KeyBuffer)); + i++; + if (WinStatus == ERROR_NO_MORE_ITEMS) + { + break; + } + + WinStatus = RegOpenKey (Handle, KeyBuffer, &SubKey); + if (WinStatus != ERROR_SUCCESS) + { + fprintf (stderr, "Could not open %s entry: %s\n", + Signature, WindowsFormatException (WinStatus)); + Status = AE_ERROR; + goto Cleanup; + } + + RegCloseKey (Handle); + Handle = SubKey; + i = 0; + } + + /* Find the (binary) table entry */ + + for (i = 0; ; i++) + { + NameSize = sizeof (KeyBuffer); + WinStatus = RegEnumValue (Handle, i, KeyBuffer, &NameSize, NULL, + &Type, NULL, 0); + if (WinStatus != ERROR_SUCCESS) + { + fprintf (stderr, "Could not get %s registry entry: %s\n", + Signature, WindowsFormatException (WinStatus)); + Status = AE_ERROR; + goto Cleanup; + } + + if (Type == REG_BINARY) + { + break; + } + } + + /* Get the size of the table */ + + WinStatus = RegQueryValueEx (Handle, KeyBuffer, NULL, NULL, + NULL, &DataSize); + if (WinStatus != ERROR_SUCCESS) + { + fprintf (stderr, "Could not read the %s table size: %s\n", + Signature, WindowsFormatException (WinStatus)); + Status = AE_ERROR; + goto Cleanup; + } + + /* Allocate a new buffer for the table */ + + ReturnTable = malloc (DataSize); + if (!ReturnTable) + { + Status = AE_NO_MEMORY; + goto Cleanup; + } + + /* Get the actual table from the registry */ + + WinStatus = RegQueryValueEx (Handle, KeyBuffer, NULL, NULL, + (UCHAR *) ReturnTable, &DataSize); + if (WinStatus != ERROR_SUCCESS) + { + fprintf (stderr, "Could not read %s data: %s\n", + Signature, WindowsFormatException (WinStatus)); + free (ReturnTable); + Status = AE_ERROR; + goto Cleanup; + } + + *Table = ReturnTable; + *Address = 0; + +Cleanup: + RegCloseKey (Handle); + return (Status); +} + + +/* These are here for acpidump only, so we don't need to link oswinxf */ + +#ifdef ACPI_DUMP_APP +/****************************************************************************** + * + * FUNCTION: AcpiOsMapMemory + * + * PARAMETERS: Where - Physical address of memory to be mapped + * Length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into caller's address space + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length) +{ + + return (ACPI_TO_POINTER ((ACPI_SIZE) Where)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: Where - Logical address of memory to be unmapped + * Length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *Where, + ACPI_SIZE Length) +{ + + return; +} +#endif diff --git a/third_party/lib/acpica/source/os_specific/service_layers/oswinxf.c b/third_party/lib/acpica/source/os_specific/service_layers/oswinxf.c new file mode 100644 index 000000000..73af3a87d --- /dev/null +++ b/third_party/lib/acpica/source/os_specific/service_layers/oswinxf.c @@ -0,0 +1,1568 @@ +/****************************************************************************** + * + * Module Name: oswinxf - Windows OSL + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#ifdef WIN32 +#pragma warning(disable:4115) /* warning C4115: named type definition in parentheses (caused by rpcasync.h> */ + +#include +#include + +#elif WIN64 +#include +#endif + +#include +#include +#include +#include +#include + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("oswinxf") + + +UINT64 TimerFrequency; +char TableName[ACPI_NAME_SIZE + 1]; + +#define ACPI_OS_DEBUG_TIMEOUT 30000 /* 30 seconds */ + + +/* Upcalls to AcpiExec application */ + +void +AeTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable); + +/* + * Real semaphores are only used for a multi-threaded application + */ +#ifndef ACPI_SINGLE_THREADED + +/* Semaphore information structure */ + +typedef struct acpi_os_semaphore_info +{ + UINT16 MaxUnits; + UINT16 CurrentUnits; + void *OsHandle; + +} ACPI_OS_SEMAPHORE_INFO; + +/* Need enough semaphores to run the large aslts suite */ + +#define ACPI_OS_MAX_SEMAPHORES 256 + +ACPI_OS_SEMAPHORE_INFO AcpiGbl_Semaphores[ACPI_OS_MAX_SEMAPHORES]; + +#endif /* ACPI_SINGLE_THREADED */ + +BOOLEAN AcpiGbl_DebugTimeout = FALSE; + + +/****************************************************************************** + * + * FUNCTION: AcpiOsTerminate + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Nothing to do for windows + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsTerminate ( + void) +{ + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Init this OSL + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsInitialize ( + void) +{ + ACPI_STATUS Status; + LARGE_INTEGER LocalTimerFrequency; + + +#ifndef ACPI_SINGLE_THREADED + /* Clear the semaphore info array */ + + memset (AcpiGbl_Semaphores, 0x00, sizeof (AcpiGbl_Semaphores)); +#endif + + AcpiGbl_OutputFile = stdout; + + /* Get the timer frequency for use in AcpiOsGetTimer */ + + TimerFrequency = 0; + if (QueryPerformanceFrequency (&LocalTimerFrequency)) + { + /* Frequency is in ticks per second */ + + TimerFrequency = LocalTimerFrequency.QuadPart; + } + + Status = AcpiOsCreateLock (&AcpiGbl_PrintLock); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (AE_OK); +} + + +#ifndef ACPI_USE_NATIVE_RSDP_POINTER +/****************************************************************************** + * + * FUNCTION: AcpiOsGetRootPointer + * + * PARAMETERS: None + * + * RETURN: RSDP physical address + * + * DESCRIPTION: Gets the root pointer (RSDP) + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + + return (0); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPredefinedOverride + * + * PARAMETERS: InitVal - Initial value of the predefined object + * NewVal - The new value for the object + * + * RETURN: Status, pointer to value. Null pointer returned if not + * overriding. + * + * DESCRIPTION: Allow the OS to override predefined names + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsPredefinedOverride ( + const ACPI_PREDEFINED_NAMES *InitVal, + ACPI_STRING *NewVal) +{ + + if (!InitVal || !NewVal) + { + return (AE_BAD_PARAMETER); + } + + *NewVal = NULL; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsTableOverride + * + * PARAMETERS: ExistingTable - Header of current table (probably firmware) + * NewTable - Where an entire new table is returned. + * + * RETURN: Status, pointer to new table. Null pointer returned if no + * table is available to override + * + * DESCRIPTION: Return a different version of a table if one is available + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable) +{ + + if (!ExistingTable || !NewTable) + { + return (AE_BAD_PARAMETER); + } + + *NewTable = NULL; + + +#ifdef ACPI_EXEC_APP + + /* Call back up to AcpiExec */ + + AeTableOverride (ExistingTable, NewTable); +#endif + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPhysicalTableOverride + * + * PARAMETERS: ExistingTable - Header of current table (probably firmware) + * NewAddress - Where new table address is returned + * (Physical address) + * NewTableLength - Where new table length is returned + * + * RETURN: Status, address/length of new table. Null pointer returned + * if no table is available to override. + * + * DESCRIPTION: Returns AE_SUPPORT, function not used in user space. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsPhysicalTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_PHYSICAL_ADDRESS *NewAddress, + UINT32 *NewTableLength) +{ + + return (AE_SUPPORT); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTimer + * + * PARAMETERS: None + * + * RETURN: Current ticks in 100-nanosecond units + * + * DESCRIPTION: Get the value of a system timer + * + ******************************************************************************/ + +UINT64 +AcpiOsGetTimer ( + void) +{ + LARGE_INTEGER Timer; + + + /* Attempt to use hi-granularity timer first */ + + if (TimerFrequency && + QueryPerformanceCounter (&Timer)) + { + /* Convert to 100 nanosecond ticks */ + + return ((UINT64) ((Timer.QuadPart * (UINT64) ACPI_100NSEC_PER_SEC) / + TimerFrequency)); + } + + /* Fall back to the lo-granularity timer */ + + else + { + /* Convert milliseconds to 100 nanosecond ticks */ + + return ((UINT64) GetTickCount() * ACPI_100NSEC_PER_MSEC); + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadable + * + * PARAMETERS: Pointer - Area to be verified + * Length - Size of area + * + * RETURN: TRUE if readable for entire length + * + * DESCRIPTION: Verify that a pointer is valid for reading + * + *****************************************************************************/ + +BOOLEAN +AcpiOsReadable ( + void *Pointer, + ACPI_SIZE Length) +{ + + return ((BOOLEAN) !IsBadReadPtr (Pointer, Length)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritable + * + * PARAMETERS: Pointer - Area to be verified + * Length - Size of area + * + * RETURN: TRUE if writable for entire length + * + * DESCRIPTION: Verify that a pointer is valid for writing + * + *****************************************************************************/ + +BOOLEAN +AcpiOsWritable ( + void *Pointer, + ACPI_SIZE Length) +{ + + return ((BOOLEAN) !IsBadWritePtr (Pointer, Length)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsRedirectOutput + * + * PARAMETERS: Destination - An open file handle/pointer + * + * RETURN: None + * + * DESCRIPTION: Causes redirect of AcpiOsPrintf and AcpiOsVprintf + * + *****************************************************************************/ + +void +AcpiOsRedirectOutput ( + void *Destination) +{ + + AcpiGbl_OutputFile = Destination; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPrintf + * + * PARAMETERS: Fmt, ... - Standard printf format + * + * RETURN: None + * + * DESCRIPTION: Formatted output + * + *****************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiOsPrintf ( + const char *Fmt, + ...) +{ + va_list Args; + UINT8 Flags; + + + Flags = AcpiGbl_DbOutputFlags; + if (Flags & ACPI_DB_REDIRECTABLE_OUTPUT) + { + /* Output is directable to either a file (if open) or the console */ + + if (AcpiGbl_DebugFile) + { + /* Output file is open, send the output there */ + + va_start (Args, Fmt); + vfprintf (AcpiGbl_DebugFile, Fmt, Args); + va_end (Args); + } + else + { + /* No redirection, send output to console (once only!) */ + + Flags |= ACPI_DB_CONSOLE_OUTPUT; + } + } + + if (Flags & ACPI_DB_CONSOLE_OUTPUT) + { + va_start (Args, Fmt); + vfprintf (AcpiGbl_OutputFile, Fmt, Args); + va_end (Args); + } + + return; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsVprintf + * + * PARAMETERS: Fmt - Standard printf format + * Args - Argument list + * + * RETURN: None + * + * DESCRIPTION: Formatted output with argument list pointer + * + *****************************************************************************/ + +void +AcpiOsVprintf ( + const char *Fmt, + va_list Args) +{ + INT32 Count = 0; + UINT8 Flags; + + + Flags = AcpiGbl_DbOutputFlags; + if (Flags & ACPI_DB_REDIRECTABLE_OUTPUT) + { + /* Output is directable to either a file (if open) or the console */ + + if (AcpiGbl_DebugFile) + { + /* Output file is open, send the output there */ + + Count = vfprintf (AcpiGbl_DebugFile, Fmt, Args); + } + else + { + /* No redirection, send output to console (once only!) */ + + Flags |= ACPI_DB_CONSOLE_OUTPUT; + } + } + + if (Flags & ACPI_DB_CONSOLE_OUTPUT) + { + Count = vfprintf (AcpiGbl_OutputFile, Fmt, Args); + } + + return; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetLine + * + * PARAMETERS: Buffer - Where to return the command line + * BufferLength - Maximum length of Buffer + * BytesRead - Where the actual byte count is returned + * + * RETURN: Status and actual bytes read + * + * DESCRIPTION: Formatted input with argument list pointer + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead) +{ + int Temp; + UINT32 i; + + + for (i = 0; ; i++) + { + if (i >= BufferLength) + { + return (AE_BUFFER_OVERFLOW); + } + + if ((Temp = getchar ()) == EOF) + { + return (AE_ERROR); + } + + if (!Temp || Temp == '\n') + { + break; + } + + Buffer [i] = (char) Temp; + } + + /* Null terminate the buffer */ + + Buffer [i] = 0; + + /* Return the number of bytes in the string */ + + if (BytesRead) + { + *BytesRead = i; + } + + return (AE_OK); +} + + +#ifndef ACPI_USE_NATIVE_MEMORY_MAPPING +/****************************************************************************** + * + * FUNCTION: AcpiOsMapMemory + * + * PARAMETERS: Where - Physical address of memory to be mapped + * Length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into caller's address space + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS Where, + ACPI_SIZE Length) +{ + + return (ACPI_TO_POINTER ((ACPI_SIZE) Where)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: Where - Logical address of memory to be unmapped + * Length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *Where, + ACPI_SIZE Length) +{ + + return; +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocate + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocate ( + ACPI_SIZE Size) +{ + void *Mem; + + + Mem = (void *) malloc ((size_t) Size); + return (Mem); +} + + +#ifdef USE_NATIVE_ALLOCATE_ZEROED +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocateZeroed + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate and zero memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE Size) +{ + void *Mem; + + + Mem = (void *) calloc (1, (size_t) Size); + return (Mem); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsFree + * + * PARAMETERS: Mem - Pointer to previously allocated memory + * + * RETURN: None. + * + * DESCRIPTION: Free memory allocated via AcpiOsAllocate + * + *****************************************************************************/ + +void +AcpiOsFree ( + void *Mem) +{ + + free (Mem); +} + + +#ifdef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: Semaphore stub functions + * + * DESCRIPTION: Stub functions used for single-thread applications that do + * not require semaphore synchronization. Full implementations + * of these functions appear after the stubs. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_HANDLE *OutHandle) +{ + *OutHandle = (ACPI_HANDLE) 1; + return (AE_OK); +} + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_HANDLE Handle) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units, + UINT16 Timeout) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units) +{ + return (AE_OK); +} + +#else +/****************************************************************************** + * + * FUNCTION: AcpiOsCreateSemaphore + * + * PARAMETERS: MaxUnits - Maximum units that can be sent + * InitialUnits - Units to be assigned to the new semaphore + * OutHandle - Where a handle will be returned + * + * RETURN: Status + * + * DESCRIPTION: Create an OS semaphore + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_SEMAPHORE *OutHandle) +{ + void *Mutex; + UINT32 i; + + ACPI_FUNCTION_NAME (OsCreateSemaphore); + + + if (MaxUnits == ACPI_UINT32_MAX) + { + MaxUnits = 255; + } + + if (InitialUnits == ACPI_UINT32_MAX) + { + InitialUnits = MaxUnits; + } + + if (InitialUnits > MaxUnits) + { + return (AE_BAD_PARAMETER); + } + + /* Find an empty slot */ + + for (i = 0; i < ACPI_OS_MAX_SEMAPHORES; i++) + { + if (!AcpiGbl_Semaphores[i].OsHandle) + { + break; + } + } + if (i >= ACPI_OS_MAX_SEMAPHORES) + { + ACPI_EXCEPTION ((AE_INFO, AE_LIMIT, + "Reached max semaphores (%u), could not create", + ACPI_OS_MAX_SEMAPHORES)); + return (AE_LIMIT); + } + + /* Create an OS semaphore */ + + Mutex = CreateSemaphore (NULL, InitialUnits, MaxUnits, NULL); + if (!Mutex) + { + ACPI_ERROR ((AE_INFO, "Could not create semaphore")); + return (AE_NO_MEMORY); + } + + AcpiGbl_Semaphores[i].MaxUnits = (UINT16) MaxUnits; + AcpiGbl_Semaphores[i].CurrentUnits = (UINT16) InitialUnits; + AcpiGbl_Semaphores[i].OsHandle = Mutex; + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, + "Handle=%u, Max=%u, Current=%u, OsHandle=%p\n", + i, MaxUnits, InitialUnits, Mutex)); + + *OutHandle = (void *) i; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsDeleteSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * + * RETURN: Status + * + * DESCRIPTION: Delete an OS semaphore + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_SEMAPHORE Handle) +{ + UINT32 Index = (UINT32) Handle; + + + if ((Index >= ACPI_OS_MAX_SEMAPHORES) || + !AcpiGbl_Semaphores[Index].OsHandle) + { + return (AE_BAD_PARAMETER); + } + + CloseHandle (AcpiGbl_Semaphores[Index].OsHandle); + AcpiGbl_Semaphores[Index].OsHandle = NULL; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWaitSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * Units - How many units to wait for + * Timeout - How long to wait + * + * RETURN: Status + * + * DESCRIPTION: Wait for units + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_SEMAPHORE Handle, + UINT32 Units, + UINT16 Timeout) +{ + UINT32 Index = (UINT32) Handle; + UINT32 WaitStatus; + UINT32 OsTimeout = Timeout; + + + ACPI_FUNCTION_ENTRY (); + + + if ((Index >= ACPI_OS_MAX_SEMAPHORES) || + !AcpiGbl_Semaphores[Index].OsHandle) + { + return (AE_BAD_PARAMETER); + } + + if (Units > 1) + { + printf ("WaitSemaphore: Attempt to receive %u units\n", Units); + return (AE_NOT_IMPLEMENTED); + } + + if (Timeout == ACPI_WAIT_FOREVER) + { + OsTimeout = INFINITE; + if (AcpiGbl_DebugTimeout) + { + /* The debug timeout will prevent hang conditions */ + + OsTimeout = ACPI_OS_DEBUG_TIMEOUT; + } + } + else + { + /* Add 10ms to account for clock tick granularity */ + + OsTimeout += 10; + } + + WaitStatus = WaitForSingleObject ( + AcpiGbl_Semaphores[Index].OsHandle, OsTimeout); + if (WaitStatus == WAIT_TIMEOUT) + { + if (AcpiGbl_DebugTimeout) + { + ACPI_EXCEPTION ((AE_INFO, AE_TIME, + "Debug timeout on semaphore 0x%04X (%ums)\n", + Index, ACPI_OS_DEBUG_TIMEOUT)); + } + + return (AE_TIME); + } + + if (AcpiGbl_Semaphores[Index].CurrentUnits == 0) + { + ACPI_ERROR ((AE_INFO, + "%s - No unit received. Timeout 0x%X, OS_Status 0x%X", + AcpiUtGetMutexName (Index), Timeout, WaitStatus)); + + return (AE_OK); + } + + AcpiGbl_Semaphores[Index].CurrentUnits--; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSignalSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * Units - Number of units to send + * + * RETURN: Status + * + * DESCRIPTION: Send units + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_SEMAPHORE Handle, + UINT32 Units) +{ + UINT32 Index = (UINT32) Handle; + + + ACPI_FUNCTION_ENTRY (); + + + if (Index >= ACPI_OS_MAX_SEMAPHORES) + { + printf ("SignalSemaphore: Index/Handle out of range: %2.2X\n", Index); + return (AE_BAD_PARAMETER); + } + + if (!AcpiGbl_Semaphores[Index].OsHandle) + { + printf ("SignalSemaphore: Null OS handle, Index %2.2X\n", Index); + return (AE_BAD_PARAMETER); + } + + if (Units > 1) + { + printf ("SignalSemaphore: Attempt to signal %u units, Index %2.2X\n", Units, Index); + return (AE_NOT_IMPLEMENTED); + } + + if ((AcpiGbl_Semaphores[Index].CurrentUnits + 1) > + AcpiGbl_Semaphores[Index].MaxUnits) + { + ACPI_ERROR ((AE_INFO, + "Oversignalled semaphore[%u]! Current %u Max %u", + Index, AcpiGbl_Semaphores[Index].CurrentUnits, + AcpiGbl_Semaphores[Index].MaxUnits)); + + return (AE_LIMIT); + } + + AcpiGbl_Semaphores[Index].CurrentUnits++; + ReleaseSemaphore (AcpiGbl_Semaphores[Index].OsHandle, Units, NULL); + + return (AE_OK); +} + +#endif /* ACPI_SINGLE_THREADED */ + + +/****************************************************************************** + * + * FUNCTION: Spinlock interfaces + * + * DESCRIPTION: Map these interfaces to semaphore interfaces + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateLock ( + ACPI_SPINLOCK *OutHandle) +{ + return (AcpiOsCreateSemaphore (1, 1, OutHandle)); +} + +void +AcpiOsDeleteLock ( + ACPI_SPINLOCK Handle) +{ + AcpiOsDeleteSemaphore (Handle); +} + +ACPI_CPU_FLAGS +AcpiOsAcquireLock ( + ACPI_SPINLOCK Handle) +{ + AcpiOsWaitSemaphore (Handle, 1, 0xFFFF); + return (0); +} + +void +AcpiOsReleaseLock ( + ACPI_SPINLOCK Handle, + ACPI_CPU_FLAGS Flags) +{ + AcpiOsSignalSemaphore (Handle, 1); +} + + +#if ACPI_FUTURE_IMPLEMENTATION + +/* Mutex interfaces, just implement with a semaphore */ + +ACPI_STATUS +AcpiOsCreateMutex ( + ACPI_MUTEX *OutHandle) +{ + return (AcpiOsCreateSemaphore (1, 1, OutHandle)); +} + +void +AcpiOsDeleteMutex ( + ACPI_MUTEX Handle) +{ + AcpiOsDeleteSemaphore (Handle); +} + +ACPI_STATUS +AcpiOsAcquireMutex ( + ACPI_MUTEX Handle, + UINT16 Timeout) +{ + AcpiOsWaitSemaphore (Handle, 1, Timeout); + return (0); +} + +void +AcpiOsReleaseMutex ( + ACPI_MUTEX Handle) +{ + AcpiOsSignalSemaphore (Handle, 1); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInstallInterruptHandler + * + * PARAMETERS: InterruptNumber - Level handler should respond to. + * ServiceRoutine - Address of the ACPI interrupt handler + * Context - User context + * + * RETURN: Handle to the newly installed handler. + * + * DESCRIPTION: Install an interrupt handler. Used to install the ACPI + * OS-independent handler. + * + *****************************************************************************/ + +UINT32 +AcpiOsInstallInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine, + void *Context) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsRemoveInterruptHandler + * + * PARAMETERS: Handle - Returned when handler was installed + * + * RETURN: Status + * + * DESCRIPTION: Uninstalls an interrupt handler. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsRemoveInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsStall + * + * PARAMETERS: Microseconds - Time to stall + * + * RETURN: None. Blocks until stall is completed. + * + * DESCRIPTION: Sleep at microsecond granularity + * + *****************************************************************************/ + +void +AcpiOsStall ( + UINT32 Microseconds) +{ + + Sleep ((Microseconds / ACPI_USEC_PER_MSEC) + 1); + return; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSleep + * + * PARAMETERS: Milliseconds - Time to sleep + * + * RETURN: None. Blocks until sleep is completed. + * + * DESCRIPTION: Sleep at millisecond granularity + * + *****************************************************************************/ + +void +AcpiOsSleep ( + UINT64 Milliseconds) +{ + + /* Add 10ms to account for clock tick granularity */ + + Sleep (((unsigned long) Milliseconds) + 10); + return; +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadPciConfiguration + * + * PARAMETERS: PciId - Seg/Bus/Dev + * Register - Device Register + * Value - Buffer where value is placed + * Width - Number of bits + * + * RETURN: Status + * + * DESCRIPTION: Read data from PCI configuration space + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadPciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 Register, + UINT64 *Value, + UINT32 Width) +{ + + *Value = 0; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritePciConfiguration + * + * PARAMETERS: PciId - Seg/Bus/Dev + * Register - Device Register + * Value - Value to be written + * Width - Number of bits + * + * RETURN: Status + * + * DESCRIPTION: Write data to PCI configuration space + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWritePciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 Register, + UINT64 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadPort + * + * PARAMETERS: Address - Address of I/O port/register to read + * Value - Where value is placed + * Width - Number of bits + * + * RETURN: Value read from port + * + * DESCRIPTION: Read data from an I/O port or register + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + ACPI_FUNCTION_NAME (OsReadPort); + + + switch (Width) + { + case 8: + + *Value = 0xFF; + break; + + case 16: + + *Value = 0xFFFF; + break; + + case 32: + + *Value = 0xFFFFFFFF; + break; + + default: + + ACPI_ERROR ((AE_INFO, "Bad width parameter: %X", Width)); + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritePort + * + * PARAMETERS: Address - Address of I/O port/register to write + * Value - Value to write + * Width - Number of bits + * + * RETURN: None + * + * DESCRIPTION: Write data to an I/O port or register + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + ACPI_FUNCTION_NAME (OsWritePort); + + + if ((Width == 8) || (Width == 16) || (Width == 32)) + { + return (AE_OK); + } + + ACPI_ERROR ((AE_INFO, "Bad width parameter: %X", Width)); + return (AE_BAD_PARAMETER); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadMemory + * + * PARAMETERS: Address - Physical Memory Address to read + * Value - Where value is placed + * Width - Number of bits (8,16,32, or 64) + * + * RETURN: Value read from physical memory address. Always returned + * as a 64-bit integer, regardless of the read width. + * + * DESCRIPTION: Read data from a physical memory address + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 *Value, + UINT32 Width) +{ + + switch (Width) + { + case 8: + case 16: + case 32: + case 64: + + *Value = 0; + break; + + default: + + return (AE_BAD_PARAMETER); + break; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWriteMemory + * + * PARAMETERS: Address - Physical Memory Address to write + * Value - Value to write + * Width - Number of bits (8,16,32, or 64) + * + * RETURN: None + * + * DESCRIPTION: Write data to a physical memory address + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWriteMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSignal + * + * PARAMETERS: Function - ACPICA signal function code + * Info - Pointer to function-dependent structure + * + * RETURN: Status + * + * DESCRIPTION: Miscellaneous functions. Example implementation only. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsSignal ( + UINT32 Function, + void *Info) +{ + + switch (Function) + { + case ACPI_SIGNAL_FATAL: + + break; + + case ACPI_SIGNAL_BREAKPOINT: + + break; + + default: + + break; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: Local cache interfaces + * + * DESCRIPTION: Implements cache interfaces via malloc/free for testing + * purposes only. + * + *****************************************************************************/ + +#ifndef ACPI_USE_LOCAL_CACHE + +ACPI_STATUS +AcpiOsCreateCache ( + char *CacheName, + UINT16 ObjectSize, + UINT16 MaxDepth, + ACPI_CACHE_T **ReturnCache) +{ + ACPI_MEMORY_LIST *NewCache; + + + NewCache = malloc (sizeof (ACPI_MEMORY_LIST)); + if (!NewCache) + { + return (AE_NO_MEMORY); + } + + memset (NewCache, 0, sizeof (ACPI_MEMORY_LIST)); + NewCache->ListName = CacheName; + NewCache->ObjectSize = ObjectSize; + NewCache->MaxDepth = MaxDepth; + + *ReturnCache = (ACPI_CACHE_T) NewCache; + return (AE_OK); +} + +ACPI_STATUS +AcpiOsDeleteCache ( + ACPI_CACHE_T *Cache) +{ + free (Cache); + return (AE_OK); +} + +ACPI_STATUS +AcpiOsPurgeCache ( + ACPI_CACHE_T *Cache) +{ + return (AE_OK); +} + +void * +AcpiOsAcquireObject ( + ACPI_CACHE_T *Cache) +{ + void *NewObject; + + NewObject = malloc (((ACPI_MEMORY_LIST *) Cache)->ObjectSize); + memset (NewObject, 0, ((ACPI_MEMORY_LIST *) Cache)->ObjectSize); + + return (NewObject); +} + +ACPI_STATUS +AcpiOsReleaseObject ( + ACPI_CACHE_T *Cache, + void *Object) +{ + free (Object); + return (AE_OK); +} + +#endif /* ACPI_USE_LOCAL_CACHE */ + + +/* Optional multi-thread support */ + +#ifndef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: AcpiOsGetThreadId + * + * PARAMETERS: None + * + * RETURN: Id of the running thread + * + * DESCRIPTION: Get the Id of the current (running) thread + * + *****************************************************************************/ + +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + DWORD ThreadId; + + /* Ensure ID is never 0 */ + + ThreadId = GetCurrentThreadId (); + return ((ACPI_THREAD_ID) (ThreadId + 1)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsExecute + * + * PARAMETERS: Type - Type of execution + * Function - Address of the function to execute + * Context - Passed as a parameter to the function + * + * RETURN: Status + * + * DESCRIPTION: Execute a new thread + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) +{ + + _beginthread (Function, (unsigned) 0, Context); + return (0); +} + +#else /* ACPI_SINGLE_THREADED */ +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + return (1); +} + +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) +{ + + Function (Context); + return (AE_OK); +} + +#endif /* ACPI_SINGLE_THREADED */ + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWaitEventsComplete + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Wait for all asynchronous events to complete. This + * implementation does nothing. + * + *****************************************************************************/ + +void +AcpiOsWaitEventsComplete ( + void) +{ + + return; +} diff --git a/third_party/lib/acpica/source/tools/acpibin/abcompare.c b/third_party/lib/acpica/source/tools/acpibin/abcompare.c new file mode 100644 index 000000000..93520a6e2 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpibin/abcompare.c @@ -0,0 +1,617 @@ +/****************************************************************************** + * + * Module Name: abcompare - compare AML files + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpibin.h" +#include "acapps.h" + + +ACPI_TABLE_HEADER Header1; +ACPI_TABLE_HEADER Header2; + +#define BUFFER_SIZE 256 +char Buffer[BUFFER_SIZE]; + + +/* Local prototypes */ + +static BOOLEAN +AbValidateHeader ( + ACPI_TABLE_HEADER *Header); + +static UINT8 +AcpiTbSumTable ( + void *Buffer, + UINT32 Length); + +static char * +AbGetFile ( + char *Filename, + UINT32 *FileSize); + +static void +AbPrintHeaderInfo ( + ACPI_TABLE_HEADER *Header); + +static void +AbPrintHeadersInfo ( + ACPI_TABLE_HEADER *Header, + ACPI_TABLE_HEADER *Header2); + + +/****************************************************************************** + * + * FUNCTION: AbValidateHeader + * + * DESCRIPTION: Check for valid ACPI table header + * + ******************************************************************************/ + +static BOOLEAN +AbValidateHeader ( + ACPI_TABLE_HEADER *Header) +{ + + if (!AcpiUtValidAcpiName (Header->Signature)) + { + printf ("Header signature is invalid\n"); + return (FALSE); + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiTbSumTable + * + * PARAMETERS: Buffer - Buffer to checksum + * Length - Size of the buffer + * + * RETURNS 8 bit checksum of buffer + * + * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it. + * + ******************************************************************************/ + +static UINT8 +AcpiTbSumTable ( + void *Buffer, + UINT32 Length) +{ + const UINT8 *Limit; + const UINT8 *Rover; + UINT8 Sum = 0; + + + if (Buffer && Length) + { + /* Buffer and Length are valid */ + + Limit = (UINT8 *) Buffer + Length; + + for (Rover = Buffer; Rover < Limit; Rover++) + { + Sum = (UINT8) (Sum + *Rover); + } + } + + return (Sum); +} + + +/******************************************************************************* + * + * FUNCTION: AbPrintHeaderInfo + * + * PARAMETERS: Header - An ACPI table header + * + * RETURNS None. + * + * DESCRIPTION: Format and display header contents. + * + ******************************************************************************/ + +static void +AbPrintHeaderInfo ( + ACPI_TABLE_HEADER *Header) +{ + + /* Display header information */ + + printf ("Signature : %4.4s\n", Header->Signature); + printf ("Length : %8.8X\n", Header->Length); + printf ("Revision : %2.2X\n", Header->Revision); + printf ("Checksum : %2.2X\n", Header->Checksum); + printf ("OEM ID : %.6s\n", Header->OemId); + printf ("OEM Table ID : %.8s\n", Header->OemTableId); + printf ("OEM Revision : %8.8X\n", Header->OemRevision); + printf ("ASL Compiler ID : %.4s\n", Header->AslCompilerId); + printf ("Compiler Revision : %8.8X\n", Header->AslCompilerRevision); + printf ("\n"); +} + +static void +AbPrintHeadersInfo ( + ACPI_TABLE_HEADER *Header, + ACPI_TABLE_HEADER *Header2) +{ + + /* Display header information for both headers */ + + printf ("Signature %8.4s : %4.4s\n", Header->Signature, Header2->Signature); + printf ("Length %8.8X : %8.8X\n", Header->Length, Header2->Length); + printf ("Revision %8.2X : %2.2X\n", Header->Revision, Header2->Revision); + printf ("Checksum %8.2X : %2.2X\n", Header->Checksum, Header2->Checksum); + printf ("OEM ID %8.6s : %.6s\n", Header->OemId, Header2->OemId); + printf ("OEM Table ID %8.8s : %.8s\n", Header->OemTableId, Header2->OemTableId); + printf ("OEM Revision %8.8X : %8.8X\n", Header->OemRevision, Header2->OemRevision); + printf ("ASL Compiler ID %8.4s : %.4s\n", Header->AslCompilerId, Header2->AslCompilerId); + printf ("Compiler Revision %8.8X : %8.8X\n", Header->AslCompilerRevision, Header2->AslCompilerRevision); + printf ("\n"); +} + + +/****************************************************************************** + * + * FUNCTION: AbDisplayHeader + * + * DESCRIPTION: Display an ACPI table header + * + ******************************************************************************/ + +void +AbDisplayHeader ( + char *FilePath) +{ + UINT32 Actual; + FILE *File; + + + File = fopen (FilePath, "rb"); + if (!File) + { + printf ("Could not open file %s\n", FilePath); + return; + } + + Actual = fread (&Header1, 1, sizeof (ACPI_TABLE_HEADER), File); + fclose (File); + + if (Actual != sizeof (ACPI_TABLE_HEADER)) + { + printf ("File %s does not contain a valid ACPI table header\n", FilePath); + return; + } + + if (!AbValidateHeader (&Header1)) + { + return; + } + + AbPrintHeaderInfo (&Header1); +} + + +/****************************************************************************** + * + * FUNCTION: AbComputeChecksum + * + * DESCRIPTION: Compute proper checksum for an ACPI table + * + ******************************************************************************/ + +void +AbComputeChecksum ( + char *FilePath) +{ + UINT32 Actual; + ACPI_TABLE_HEADER *Table; + UINT8 Checksum; + FILE *File; + + + File = fopen (FilePath, "rb"); + if (!File) + { + printf ("Could not open file %s\n", FilePath); + return; + } + + Actual = fread (&Header1, 1, sizeof (ACPI_TABLE_HEADER), File); + if (Actual < sizeof (ACPI_TABLE_HEADER)) + { + printf ("File %s does not contain a valid ACPI table header\n", FilePath); + goto Exit1; + } + + if (!AbValidateHeader (&Header1)) + { + goto Exit1; + } + + if (!Gbl_TerseMode) + { + AbPrintHeaderInfo (&Header1); + } + + /* Allocate a buffer to hold the entire table */ + + Table = AcpiOsAllocate (Header1.Length); + if (!Table) + { + printf ("Could not allocate buffer for table\n"); + goto Exit1; + } + + /* Read the entire table, including header */ + + fseek (File, 0, SEEK_SET); + Actual = fread (Table, 1, Header1.Length, File); + if (Actual != Header1.Length) + { + printf ("Could not read table, length %u\n", Header1.Length); + goto Exit2; + } + + /* Compute the checksum for the table */ + + Table->Checksum = 0; + + Checksum = (UINT8) (0 - AcpiTbSumTable (Table, Table->Length)); + printf ("Computed checksum: 0x%X\n\n", Checksum); + + if (Header1.Checksum == Checksum) + { + printf ("Checksum OK in AML file, not updating\n"); + goto Exit2; + } + + /* Open the target file for writing, to update checksum */ + + fclose (File); + File = fopen (FilePath, "r+b"); + if (!File) + { + printf ("Could not open file %s for writing\n", FilePath); + goto Exit2; + } + + /* Set the checksum, write the new header */ + + Header1.Checksum = Checksum; + + Actual = fwrite (&Header1, 1, sizeof (ACPI_TABLE_HEADER), File); + if (Actual != sizeof (ACPI_TABLE_HEADER)) + { + printf ("Could not write updated table header\n"); + goto Exit2; + } + + printf ("Wrote new checksum\n"); + +Exit2: + AcpiOsFree (Table); + +Exit1: + if (File) + { + fclose (File); + } + return; +} + + +/****************************************************************************** + * + * FUNCTION: AbCompareAmlFiles + * + * DESCRIPTION: Compare two AML files + * + ******************************************************************************/ + +int +AbCompareAmlFiles ( + char *File1Path, + char *File2Path) +{ + UINT32 Actual1; + UINT32 Actual2; + UINT32 Offset; + UINT8 Char1; + UINT8 Char2; + UINT8 Mismatches = 0; + BOOLEAN HeaderMismatch = FALSE; + FILE *File1; + FILE *File2; + int Status = -1; + + + File1 = fopen (File1Path, "rb"); + if (!File1) + { + printf ("Could not open file %s\n", File1Path); + return (-1); + } + + File2 = fopen (File2Path, "rb"); + if (!File2) + { + printf ("Could not open file %s\n", File2Path); + goto Exit1; + } + + /* Read the ACPI header from each file */ + + Actual1 = fread (&Header1, 1, sizeof (ACPI_TABLE_HEADER), File1); + if (Actual1 != sizeof (ACPI_TABLE_HEADER)) + { + printf ("File %s does not contain an ACPI table header\n", File1Path); + goto Exit2; + } + + Actual2 = fread (&Header2, 1, sizeof (ACPI_TABLE_HEADER), File2); + if (Actual2 != sizeof (ACPI_TABLE_HEADER)) + { + printf ("File %s does not contain an ACPI table header\n", File2Path); + goto Exit2; + } + + if ((!AbValidateHeader (&Header1)) || + (!AbValidateHeader (&Header2))) + { + goto Exit2; + } + + /* Table signatures must match */ + + if (*((UINT32 *) Header1.Signature) != *((UINT32 *) Header2.Signature)) + { + printf ("Table signatures do not match\n"); + goto Exit2; + } + + if (!Gbl_TerseMode) + { + /* Display header information */ + + AbPrintHeadersInfo (&Header1, &Header2); + } + + if (memcmp (&Header1, &Header2, sizeof (ACPI_TABLE_HEADER))) + { + printf ("Headers do not match exactly\n"); + HeaderMismatch = TRUE; + } + + /* Do the byte-by-byte compare */ + + Actual1 = fread (&Char1, 1, 1, File1); + Actual2 = fread (&Char2, 1, 1, File2); + Offset = sizeof (ACPI_TABLE_HEADER); + + while ((Actual1 == 1) && (Actual2 == 1)) + { + if (Char1 != Char2) + { + printf ("Error - Byte mismatch at offset %8.8X: 0x%2.2X 0x%2.2X\n", + Offset, Char1, Char2); + Mismatches++; + if (Mismatches > 100) + { + printf ("100 Mismatches: Too many mismatches\n"); + goto Exit2; + } + } + + Offset++; + Actual1 = fread (&Char1, 1, 1, File1); + Actual2 = fread (&Char2, 1, 1, File2); + } + + if (Actual1) + { + printf ("Error - file %s is longer than file %s\n", File1Path, File2Path); + Mismatches++; + } + else if (Actual2) + { + printf ("Error - file %s is shorter than file %s\n", File1Path, File2Path); + Mismatches++; + } + else if (!Mismatches) + { + if (HeaderMismatch) + { + printf ("Files compare exactly after header\n"); + } + else + { + printf ("Files compare exactly\n"); + } + } + + printf ("%u Mismatches found\n", Mismatches); + Status = 0; + +Exit2: + fclose (File2); + +Exit1: + fclose (File1); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AbGetFile + * + * DESCRIPTION: Open a file and read it entirely into a new buffer + * + ******************************************************************************/ + +static char * +AbGetFile ( + char *Filename, + UINT32 *FileSize) +{ + FILE *File; + UINT32 Size; + char *Buffer = NULL; + size_t Actual; + + + /* Binary mode does not alter CR/LF pairs */ + + File = fopen (Filename, "rb"); + if (!File) + { + printf ("Could not open file %s\n", Filename); + return (NULL); + } + + /* Need file size to allocate a buffer */ + + Size = CmGetFileSize (File); + if (Size == ACPI_UINT32_MAX) + { + printf ("Could not get file size (seek) for %s\n", Filename); + goto ErrorExit; + } + + /* Allocate a buffer for the entire file */ + + Buffer = calloc (Size, 1); + if (!Buffer) + { + printf ("Could not allocate buffer of size %u\n", Size); + goto ErrorExit; + } + + /* Read the entire file */ + + Actual = fread (Buffer, 1, Size, File); + if (Actual != Size) + { + printf ("Could not read the input file %s\n", Filename); + free (Buffer); + Buffer = NULL; + goto ErrorExit; + } + + *FileSize = Size; + +ErrorExit: + fclose (File); + return (Buffer); +} + + +/****************************************************************************** + * + * FUNCTION: AbDumpAmlFile + * + * DESCRIPTION: Dump a binary AML file to a text file + * + ******************************************************************************/ + +int +AbDumpAmlFile ( + char *File1Path, + char *File2Path) +{ + char *FileBuffer; + FILE *FileOutHandle; + UINT32 FileSize = 0; + int Status = -1; + + + /* Get the entire AML file, validate header */ + + FileBuffer = AbGetFile (File1Path, &FileSize); + if (!FileBuffer) + { + return (-1); + } + + printf ("Input file: %s contains %u (0x%X) bytes\n", + File1Path, FileSize, FileSize); + + FileOutHandle = fopen (File2Path, "wb"); + if (!FileOutHandle) + { + printf ("Could not open file %s\n", File2Path); + goto Exit1; + } + + if (!AbValidateHeader ((ACPI_TABLE_HEADER *) FileBuffer)) + { + goto Exit2; + } + + /* Convert binary AML to text, using common dump buffer routine */ + + AcpiGbl_DebugFile = FileOutHandle; + AcpiGbl_DbOutputFlags = ACPI_DB_REDIRECTABLE_OUTPUT; + + AcpiOsPrintf ("%4.4s @ 0x%8.8X\n", + ((ACPI_TABLE_HEADER *) FileBuffer)->Signature, 0); + + AcpiUtDumpBuffer ((UINT8 *) FileBuffer, FileSize, DB_BYTE_DISPLAY, 0); + + /* Summary for the output file */ + + FileSize = CmGetFileSize (FileOutHandle); + printf ("Output file: %s contains %u (0x%X) bytes\n\n", + File2Path, FileSize, FileSize); + + Status = 0; + +Exit2: + fclose (FileOutHandle); + +Exit1: + free (FileBuffer); + return (Status); +} diff --git a/third_party/lib/acpica/source/tools/acpibin/abmain.c b/third_party/lib/acpica/source/tools/acpibin/abmain.c new file mode 100644 index 000000000..53a1ffd32 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpibin/abmain.c @@ -0,0 +1,184 @@ +/****************************************************************************** + * + * Module Name: abmain - Main module for the acpi binary utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define _DECLARE_GLOBALS +#include "acpibin.h" +#include "acapps.h" + +/* Local prototypes */ + +static void +AbDisplayUsage ( + UINT8 OptionCount); + + +#define AB_UTILITY_NAME "ACPI Binary Table Dump Utility" +#define AB_SUPPORTED_OPTIONS "c:d:h:s:tv" + + +/****************************************************************************** + * + * FUNCTION: AbDisplayUsage + * + * DESCRIPTION: Usage message + * + ******************************************************************************/ + +static void +AbDisplayUsage ( + UINT8 OptionCount) +{ + + if (OptionCount) + { + printf ("Option requires %u arguments\n\n", OptionCount); + } + + ACPI_USAGE_HEADER ("acpibin [options]"); + + ACPI_OPTION ("-c ", "Compare two binary AML files"); + ACPI_OPTION ("-d ", "Dump AML binary to text file"); + ACPI_OPTION ("-e ", "Extract binary AML table from acpidump file"); + ACPI_OPTION ("-h ", "Display table header for binary AML file"); + ACPI_OPTION ("-s ", "Update checksum for binary AML file"); + ACPI_OPTION ("-t", "Terse mode"); + ACPI_OPTION ("-v", "Display version information"); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * DESCRIPTION: C main function + * + ******************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char *argv[]) +{ + int j; + int Status = AE_OK; + + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + + AcpiGbl_DebugFile = NULL; + AcpiGbl_DbOutputFlags = DB_CONSOLE_OUTPUT; + + AcpiOsInitialize (); + printf (ACPI_COMMON_SIGNON (AB_UTILITY_NAME)); + + if (argc < 2) + { + AbDisplayUsage (0); + return (0); + } + + /* Command line options */ + + while ((j = AcpiGetopt (argc, argv, AB_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch(j) + { + case 'c': /* Compare Files */ + + if (argc < 4) + { + AbDisplayUsage (2); + return (-1); + } + + Status = AbCompareAmlFiles (AcpiGbl_Optarg, argv[AcpiGbl_Optind]); + break; + + case 'd': /* Dump AML file */ + + if (argc < 4) + { + AbDisplayUsage (2); + return (-1); + } + + Status = AbDumpAmlFile (AcpiGbl_Optarg, argv[AcpiGbl_Optind]); + break; + + case 'h': /* Display ACPI table header */ + + if (argc < 3) + { + AbDisplayUsage (1); + return (-1); + } + + AbDisplayHeader (AcpiGbl_Optarg); + return (0); + + case 's': /* Compute/update checksum */ + + if (argc < 3) + { + AbDisplayUsage (1); + return (-1); + } + + AbComputeChecksum (AcpiGbl_Optarg); + return (0); + + case 't': /* Enable terse mode */ + + Gbl_TerseMode = TRUE; + break; + + case 'v': /* -v: (Version): signon already emitted, just exit */ + + return (0); + + default: + + AbDisplayUsage (0); + return (-1); + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/tools/acpibin/acpibin.h b/third_party/lib/acpica/source/tools/acpibin/acpibin.h new file mode 100644 index 000000000..cc22be76f --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpibin/acpibin.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * + * Module Name: acpibinh - Include file for AcpiBin utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#include +#include +#include + +#define DB_CONSOLE_OUTPUT 0x02 +#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 + +/* + * Global variables. Defined in main.c only, externed in all other files + */ +#ifdef _DECLARE_GLOBALS +#define EXTERN +#define INIT_GLOBAL(a,b) a=b +#else +#define EXTERN extern +#define INIT_GLOBAL(a,b) a +#endif + + +/* Globals */ + +EXTERN BOOLEAN INIT_GLOBAL (Gbl_TerseMode, FALSE); + + +/* Prototypes */ + +int +AbCompareAmlFiles ( + char *File1Path, + char *File2Path); + +int +AbDumpAmlFile ( + char *File1Path, + char *File2Path); + +void +AbComputeChecksum ( + char *File1Path); + +void +AbDisplayHeader ( + char *File1Path); diff --git a/third_party/lib/acpica/source/tools/acpidump/acpidump.h b/third_party/lib/acpica/source/tools/acpidump/acpidump.h new file mode 100644 index 000000000..0817338da --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpidump/acpidump.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * Module Name: acpidump.h - Include file for AcpiDump utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Global variables. Defined in main.c only, externed in all other files + */ +#ifdef _DECLARE_GLOBALS +#define EXTERN +#define INIT_GLOBAL(a,b) a=b +#else +#define EXTERN extern +#define INIT_GLOBAL(a,b) a +#endif + +#include "acpi.h" +#include "accommon.h" +#include "actables.h" + +#include +#include +#include +#include + + +/* Globals */ + +EXTERN BOOLEAN INIT_GLOBAL (Gbl_SummaryMode, FALSE); +EXTERN BOOLEAN INIT_GLOBAL (Gbl_VerboseMode, FALSE); +EXTERN BOOLEAN INIT_GLOBAL (Gbl_BinaryMode, FALSE); +EXTERN BOOLEAN INIT_GLOBAL (Gbl_DumpCustomizedTables, TRUE); +EXTERN BOOLEAN INIT_GLOBAL (Gbl_DoNotDumpXsdt, FALSE); +EXTERN ACPI_FILE INIT_GLOBAL (Gbl_OutputFile, NULL); +EXTERN char INIT_GLOBAL (*Gbl_OutputFilename, NULL); +EXTERN UINT64 INIT_GLOBAL (Gbl_RsdpBase, 0); + +/* Globals required for use with ACPICA modules */ + +#ifdef _DECLARE_GLOBALS +UINT8 AcpiGbl_IntegerByteWidth = 8; +#endif + +/* Action table used to defer requested options */ + +typedef struct ap_dump_action +{ + char *Argument; + UINT32 ToBeDone; + +} AP_DUMP_ACTION; + +#define AP_MAX_ACTIONS 32 + +#define AP_DUMP_ALL_TABLES 0 +#define AP_DUMP_TABLE_BY_ADDRESS 1 +#define AP_DUMP_TABLE_BY_NAME 2 +#define AP_DUMP_TABLE_BY_FILE 3 + +#define AP_MAX_ACPI_FILES 256 /* Prevent infinite loops */ + +/* Minimum FADT sizes for various table addresses */ + +#define MIN_FADT_FOR_DSDT (ACPI_FADT_OFFSET (Dsdt) + sizeof (UINT32)) +#define MIN_FADT_FOR_FACS (ACPI_FADT_OFFSET (Facs) + sizeof (UINT32)) +#define MIN_FADT_FOR_XDSDT (ACPI_FADT_OFFSET (XDsdt) + sizeof (UINT64)) +#define MIN_FADT_FOR_XFACS (ACPI_FADT_OFFSET (XFacs) + sizeof (UINT64)) + + +/* + * apdump - Table get/dump routines + */ +int +ApDumpTableFromFile ( + char *Pathname); + +int +ApDumpTableByName ( + char *Signature); + +int +ApDumpTableByAddress ( + char *AsciiAddress); + +int +ApDumpAllTables ( + void); + +BOOLEAN +ApIsValidHeader ( + ACPI_TABLE_HEADER *Table); + +BOOLEAN +ApIsValidChecksum ( + ACPI_TABLE_HEADER *Table); + +UINT32 +ApGetTableLength ( + ACPI_TABLE_HEADER *Table); + + +/* + * apfiles - File I/O utilities + */ +int +ApOpenOutputFile ( + char *Pathname); + +int +ApWriteToBinaryFile ( + ACPI_TABLE_HEADER *Table, + UINT32 Instance); + +ACPI_TABLE_HEADER * +ApGetTableFromFile ( + char *Pathname, + UINT32 *FileSize); diff --git a/third_party/lib/acpica/source/tools/acpidump/apdump.c b/third_party/lib/acpica/source/tools/acpidump/apdump.c new file mode 100644 index 000000000..00d7e098d --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpidump/apdump.c @@ -0,0 +1,489 @@ +/****************************************************************************** + * + * Module Name: apdump - Dump routines for ACPI tables (acpidump) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" + + +/* Local prototypes */ + +static int +ApDumpTableBuffer ( + ACPI_TABLE_HEADER *Table, + UINT32 Instance, + ACPI_PHYSICAL_ADDRESS Address); + + +/****************************************************************************** + * + * FUNCTION: ApIsValidHeader + * + * PARAMETERS: Table - Pointer to table to be validated + * + * RETURN: TRUE if the header appears to be valid. FALSE otherwise + * + * DESCRIPTION: Check for a valid ACPI table header + * + ******************************************************************************/ + +BOOLEAN +ApIsValidHeader ( + ACPI_TABLE_HEADER *Table) +{ + + if (!ACPI_VALIDATE_RSDP_SIG (Table->Signature)) + { + /* Make sure signature is all ASCII and a valid ACPI name */ + + if (!AcpiUtValidAcpiName (Table->Signature)) + { + AcpiLogError ("Table signature (0x%8.8X) is invalid\n", + *(UINT32 *) Table->Signature); + return (FALSE); + } + + /* Check for minimum table length */ + + if (Table->Length < sizeof (ACPI_TABLE_HEADER)) + { + AcpiLogError ("Table length (0x%8.8X) is invalid\n", + Table->Length); + return (FALSE); + } + } + + return (TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: ApIsValidChecksum + * + * PARAMETERS: Table - Pointer to table to be validated + * + * RETURN: TRUE if the checksum appears to be valid. FALSE otherwise. + * + * DESCRIPTION: Check for a valid ACPI table checksum. + * + ******************************************************************************/ + +BOOLEAN +ApIsValidChecksum ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_STATUS Status; + ACPI_TABLE_RSDP *Rsdp; + + + if (ACPI_VALIDATE_RSDP_SIG (Table->Signature)) + { + /* + * Checksum for RSDP. + * Note: Other checksums are computed during the table dump. + */ + Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table); + Status = AcpiTbValidateRsdp (Rsdp); + } + else + { + Status = AcpiTbVerifyChecksum (Table, Table->Length); + } + + if (ACPI_FAILURE (Status)) + { + AcpiLogError ("%4.4s: Warning: wrong checksum in table\n", + Table->Signature); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: ApGetTableLength + * + * PARAMETERS: Table - Pointer to the table + * + * RETURN: Table length + * + * DESCRIPTION: Obtain table length according to table signature. + * + ******************************************************************************/ + +UINT32 +ApGetTableLength ( + ACPI_TABLE_HEADER *Table) +{ + ACPI_TABLE_RSDP *Rsdp; + + + /* Check if table is valid */ + + if (!ApIsValidHeader (Table)) + { + return (0); + } + + if (ACPI_VALIDATE_RSDP_SIG (Table->Signature)) + { + Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table); + return (AcpiTbGetRsdpLength (Rsdp)); + } + + /* Normal ACPI table */ + + return (Table->Length); +} + + +/****************************************************************************** + * + * FUNCTION: ApDumpTableBuffer + * + * PARAMETERS: Table - ACPI table to be dumped + * Instance - ACPI table instance no. to be dumped + * Address - Physical address of the table + * + * RETURN: None + * + * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a + * header that is compatible with the AcpiXtract utility. + * + ******************************************************************************/ + +static int +ApDumpTableBuffer ( + ACPI_TABLE_HEADER *Table, + UINT32 Instance, + ACPI_PHYSICAL_ADDRESS Address) +{ + UINT32 TableLength; + + + TableLength = ApGetTableLength (Table); + + /* Print only the header if requested */ + + if (Gbl_SummaryMode) + { + AcpiTbPrintTableHeader (Address, Table); + return (0); + } + + /* Dump to binary file if requested */ + + if (Gbl_BinaryMode) + { + return (ApWriteToBinaryFile (Table, Instance)); + } + + /* + * Dump the table with header for use with acpixtract utility. + * Note: simplest to just always emit a 64-bit address. AcpiXtract + * utility can handle this. + */ + AcpiUtFilePrintf (Gbl_OutputFile, "%4.4s @ 0x%8.8X%8.8X\n", + Table->Signature, ACPI_FORMAT_UINT64 (Address)); + + AcpiUtDumpBufferToFile (Gbl_OutputFile, + ACPI_CAST_PTR (UINT8, Table), TableLength, + DB_BYTE_DISPLAY, 0); + AcpiUtFilePrintf (Gbl_OutputFile, "\n"); + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: ApDumpAllTables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the + * tables that we can possibly get). + * + ******************************************************************************/ + +int +ApDumpAllTables ( + void) +{ + ACPI_TABLE_HEADER *Table; + UINT32 Instance = 0; + ACPI_PHYSICAL_ADDRESS Address; + ACPI_STATUS Status; + int TableStatus; + UINT32 i; + + + /* Get and dump all available ACPI tables */ + + for (i = 0; i < AP_MAX_ACPI_FILES; i++) + { + Status = AcpiOsGetTableByIndex (i, &Table, &Instance, &Address); + if (ACPI_FAILURE (Status)) + { + /* AE_LIMIT means that no more tables are available */ + + if (Status == AE_LIMIT) + { + return (0); + } + else if (i == 0) + { + AcpiLogError ("Could not get ACPI tables, %s\n", + AcpiFormatException (Status)); + return (-1); + } + else + { + AcpiLogError ("Could not get ACPI table at index %u, %s\n", + i, AcpiFormatException (Status)); + continue; + } + } + + TableStatus = ApDumpTableBuffer (Table, Instance, Address); + ACPI_FREE (Table); + + if (TableStatus) + { + break; + } + } + + /* Something seriously bad happened if the loop terminates here */ + + return (-1); +} + + +/****************************************************************************** + * + * FUNCTION: ApDumpTableByAddress + * + * PARAMETERS: AsciiAddress - Address for requested ACPI table + * + * RETURN: Status + * + * DESCRIPTION: Get an ACPI table via a physical address and dump it. + * + ******************************************************************************/ + +int +ApDumpTableByAddress ( + char *AsciiAddress) +{ + ACPI_PHYSICAL_ADDRESS Address; + ACPI_TABLE_HEADER *Table; + ACPI_STATUS Status; + int TableStatus; + UINT64 LongAddress; + + + /* Convert argument to an integer physical address */ + + Status = AcpiUtStrtoul64 (AsciiAddress, 0, &LongAddress); + if (ACPI_FAILURE (Status)) + { + AcpiLogError ("%s: Could not convert to a physical address\n", + AsciiAddress); + return (-1); + } + + Address = (ACPI_PHYSICAL_ADDRESS) LongAddress; + Status = AcpiOsGetTableByAddress (Address, &Table); + if (ACPI_FAILURE (Status)) + { + AcpiLogError ("Could not get table at 0x%8.8X%8.8X, %s\n", + ACPI_FORMAT_UINT64 (Address), + AcpiFormatException (Status)); + return (-1); + } + + TableStatus = ApDumpTableBuffer (Table, 0, Address); + ACPI_FREE (Table); + return (TableStatus); +} + + +/****************************************************************************** + * + * FUNCTION: ApDumpTableByName + * + * PARAMETERS: Signature - Requested ACPI table signature + * + * RETURN: Status + * + * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles + * multiple tables with the same signature (SSDTs). + * + ******************************************************************************/ + +int +ApDumpTableByName ( + char *Signature) +{ + char LocalSignature [ACPI_NAME_SIZE + 1]; + UINT32 Instance; + ACPI_TABLE_HEADER *Table; + ACPI_PHYSICAL_ADDRESS Address; + ACPI_STATUS Status; + int TableStatus; + + + if (strlen (Signature) != ACPI_NAME_SIZE) + { + AcpiLogError ( + "Invalid table signature [%s]: must be exactly 4 characters\n", + Signature); + return (-1); + } + + /* Table signatures are expected to be uppercase */ + + strcpy (LocalSignature, Signature); + AcpiUtStrupr (LocalSignature); + + /* To be friendly, handle tables whose signatures do not match the name */ + + if (ACPI_COMPARE_NAME (LocalSignature, "FADT")) + { + strcpy (LocalSignature, ACPI_SIG_FADT); + } + else if (ACPI_COMPARE_NAME (LocalSignature, "MADT")) + { + strcpy (LocalSignature, ACPI_SIG_MADT); + } + + /* Dump all instances of this signature (to handle multiple SSDTs) */ + + for (Instance = 0; Instance < AP_MAX_ACPI_FILES; Instance++) + { + Status = AcpiOsGetTableByName (LocalSignature, Instance, + &Table, &Address); + if (ACPI_FAILURE (Status)) + { + /* AE_LIMIT means that no more tables are available */ + + if (Status == AE_LIMIT) + { + return (0); + } + + AcpiLogError ( + "Could not get ACPI table with signature [%s], %s\n", + LocalSignature, AcpiFormatException (Status)); + return (-1); + } + + TableStatus = ApDumpTableBuffer (Table, Instance, Address); + ACPI_FREE (Table); + + if (TableStatus) + { + break; + } + } + + /* Something seriously bad happened if the loop terminates here */ + + return (-1); +} + + +/****************************************************************************** + * + * FUNCTION: ApDumpTableFromFile + * + * PARAMETERS: Pathname - File containing the binary ACPI table + * + * RETURN: Status + * + * DESCRIPTION: Dump an ACPI table from a binary file + * + ******************************************************************************/ + +int +ApDumpTableFromFile ( + char *Pathname) +{ + ACPI_TABLE_HEADER *Table; + UINT32 FileSize = 0; + int TableStatus = -1; + + + /* Get the entire ACPI table from the file */ + + Table = ApGetTableFromFile (Pathname, &FileSize); + if (!Table) + { + return (-1); + } + + /* File must be at least as long as the table length */ + + if (Table->Length > FileSize) + { + AcpiLogError ( + "Table length (0x%X) is too large for input file (0x%X) %s\n", + Table->Length, FileSize, Pathname); + goto Exit; + } + + if (Gbl_VerboseMode) + { + AcpiLogError ( + "Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n", + Pathname, Table->Signature, FileSize, FileSize); + } + + TableStatus = ApDumpTableBuffer (Table, 0, 0); + +Exit: + ACPI_FREE (Table); + return (TableStatus); +} diff --git a/third_party/lib/acpica/source/tools/acpidump/apfiles.c b/third_party/lib/acpica/source/tools/acpidump/apfiles.c new file mode 100644 index 000000000..f26ef6b6c --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpidump/apfiles.c @@ -0,0 +1,291 @@ +/****************************************************************************** + * + * Module Name: apfiles - File-related functions for acpidump utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" +#include "acapps.h" + + +/* Local prototypes */ + +static int +ApIsExistingFile ( + char *Pathname); + + +/****************************************************************************** + * + * FUNCTION: ApIsExistingFile + * + * PARAMETERS: Pathname - Output filename + * + * RETURN: 0 on success + * + * DESCRIPTION: Query for file overwrite if it already exists. + * + ******************************************************************************/ + +static int +ApIsExistingFile ( + char *Pathname) +{ +#ifndef _GNU_EFI + struct stat StatInfo; + + + if (!stat (Pathname, &StatInfo)) + { + AcpiLogError ("Target path already exists, overwrite? [y|n] "); + + if (getchar () != 'y') + { + return (-1); + } + } +#endif + + return 0; +} + + +/****************************************************************************** + * + * FUNCTION: ApOpenOutputFile + * + * PARAMETERS: Pathname - Output filename + * + * RETURN: Open file handle + * + * DESCRIPTION: Open a text output file for acpidump. Checks if file already + * exists. + * + ******************************************************************************/ + +int +ApOpenOutputFile ( + char *Pathname) +{ + ACPI_FILE File; + + + /* If file exists, prompt for overwrite */ + + if (ApIsExistingFile (Pathname) != 0) + { + return (-1); + } + + /* Point stdout to the file */ + + File = AcpiOsOpenFile (Pathname, ACPI_FILE_WRITING); + if (!File) + { + AcpiLogError ("Could not open output file: %s\n", Pathname); + return (-1); + } + + /* Save the file and path */ + + Gbl_OutputFile = File; + Gbl_OutputFilename = Pathname; + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: ApWriteToBinaryFile + * + * PARAMETERS: Table - ACPI table to be written + * Instance - ACPI table instance no. to be written + * + * RETURN: Status + * + * DESCRIPTION: Write an ACPI table to a binary file. Builds the output + * filename from the table signature. + * + ******************************************************************************/ + +int +ApWriteToBinaryFile ( + ACPI_TABLE_HEADER *Table, + UINT32 Instance) +{ + char Filename[ACPI_NAME_SIZE + 16]; + char InstanceStr [16]; + ACPI_FILE File; + size_t Actual; + UINT32 TableLength; + + + /* Obtain table length */ + + TableLength = ApGetTableLength (Table); + + /* Construct lower-case filename from the table local signature */ + + if (ACPI_VALIDATE_RSDP_SIG (Table->Signature)) + { + ACPI_MOVE_NAME (Filename, ACPI_RSDP_NAME); + } + else + { + ACPI_MOVE_NAME (Filename, Table->Signature); + } + + Filename[0] = (char) tolower ((int) Filename[0]); + Filename[1] = (char) tolower ((int) Filename[1]); + Filename[2] = (char) tolower ((int) Filename[2]); + Filename[3] = (char) tolower ((int) Filename[3]); + Filename[ACPI_NAME_SIZE] = 0; + + /* Handle multiple SSDTs - create different filenames for each */ + + if (Instance > 0) + { + AcpiUtSnprintf (InstanceStr, sizeof (InstanceStr), "%u", Instance); + strcat (Filename, InstanceStr); + } + + strcat (Filename, FILE_SUFFIX_BINARY_TABLE); + + if (Gbl_VerboseMode) + { + AcpiLogError ( + "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n", + Table->Signature, Filename, Table->Length, Table->Length); + } + + /* Open the file and dump the entire table in binary mode */ + + File = AcpiOsOpenFile (Filename, + ACPI_FILE_WRITING | ACPI_FILE_BINARY); + if (!File) + { + AcpiLogError ("Could not open output file: %s\n", Filename); + return (-1); + } + + Actual = AcpiOsWriteFile (File, Table, 1, TableLength); + if (Actual != TableLength) + { + AcpiLogError ("Error writing binary output file: %s\n", Filename); + AcpiOsCloseFile (File); + return (-1); + } + + AcpiOsCloseFile (File); + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: ApGetTableFromFile + * + * PARAMETERS: Pathname - File containing the binary ACPI table + * OutFileSize - Where the file size is returned + * + * RETURN: Buffer containing the ACPI table. NULL on error. + * + * DESCRIPTION: Open a file and read it entirely into a new buffer + * + ******************************************************************************/ + +ACPI_TABLE_HEADER * +ApGetTableFromFile ( + char *Pathname, + UINT32 *OutFileSize) +{ + ACPI_TABLE_HEADER *Buffer = NULL; + ACPI_FILE File; + UINT32 FileSize; + size_t Actual; + + + /* Must use binary mode */ + + File = AcpiOsOpenFile (Pathname, ACPI_FILE_READING | ACPI_FILE_BINARY); + if (!File) + { + AcpiLogError ("Could not open input file: %s\n", Pathname); + return (NULL); + } + + /* Need file size to allocate a buffer */ + + FileSize = CmGetFileSize (File); + if (FileSize == ACPI_UINT32_MAX) + { + AcpiLogError ( + "Could not get input file size: %s\n", Pathname); + goto Cleanup; + } + + /* Allocate a buffer for the entire file */ + + Buffer = ACPI_ALLOCATE_ZEROED (FileSize); + if (!Buffer) + { + AcpiLogError ( + "Could not allocate file buffer of size: %u\n", FileSize); + goto Cleanup; + } + + /* Read the entire file */ + + Actual = AcpiOsReadFile (File, Buffer, 1, FileSize); + if (Actual != FileSize) + { + AcpiLogError ( + "Could not read input file: %s\n", Pathname); + ACPI_FREE (Buffer); + Buffer = NULL; + goto Cleanup; + } + + *OutFileSize = FileSize; + +Cleanup: + AcpiOsCloseFile (File); + return (Buffer); +} diff --git a/third_party/lib/acpica/source/tools/acpidump/apmain.c b/third_party/lib/acpica/source/tools/acpidump/apmain.c new file mode 100644 index 000000000..e37ec2ca0 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpidump/apmain.c @@ -0,0 +1,425 @@ +/****************************************************************************** + * + * Module Name: apmain - Main module for the acpidump utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define _DECLARE_GLOBALS +#include "acpidump.h" +#include "acapps.h" + + +/* + * acpidump - A portable utility for obtaining system ACPI tables and dumping + * them in an ASCII hex format suitable for binary extraction via acpixtract. + * + * Obtaining the system ACPI tables is an OS-specific operation. + * + * This utility can be ported to any host operating system by providing a + * module containing system-specific versions of these interfaces: + * + * AcpiOsGetTableByAddress + * AcpiOsGetTableByIndex + * AcpiOsGetTableByName + * + * See the ACPICA Reference Guide for the exact definitions of these + * interfaces. Also, see these ACPICA source code modules for example + * implementations: + * + * source/os_specific/service_layers/oswintbl.c + * source/os_specific/service_layers/oslinuxtbl.c + */ + + +/* Local prototypes */ + +static void +ApDisplayUsage ( + void); + +static int +ApDoOptions ( + int argc, + char **argv); + +static int +ApInsertAction ( + char *Argument, + UINT32 ToBeDone); + + +/* Table for deferred actions from command line options */ + +AP_DUMP_ACTION ActionTable [AP_MAX_ACTIONS]; +UINT32 CurrentAction = 0; + + +#define AP_UTILITY_NAME "ACPI Binary Table Dump Utility" +#define AP_SUPPORTED_OPTIONS "?a:bc:f:hn:o:r:svxz" + + +/****************************************************************************** + * + * FUNCTION: ApDisplayUsage + * + * DESCRIPTION: Usage message for the AcpiDump utility + * + ******************************************************************************/ + +static void +ApDisplayUsage ( + void) +{ + + ACPI_USAGE_HEADER ("acpidump [options]"); + + ACPI_OPTION ("-b", "Dump tables to binary files"); + ACPI_OPTION ("-h -?", "This help message"); + ACPI_OPTION ("-o ", "Redirect output to file"); + ACPI_OPTION ("-r
", "Dump tables from specified RSDP"); + ACPI_OPTION ("-s", "Print table summaries only"); + ACPI_OPTION ("-v", "Display version information"); + ACPI_OPTION ("-z", "Verbose mode"); + + ACPI_USAGE_TEXT ("\nTable Options:\n"); + + ACPI_OPTION ("-a
", "Get table via a physical address"); + ACPI_OPTION ("-c ", "Turning on/off customized table dumping"); + ACPI_OPTION ("-f ", "Get table via a binary file"); + ACPI_OPTION ("-n ", "Get table via a name/signature"); + ACPI_OPTION ("-x", "Do not use but dump XSDT"); + ACPI_OPTION ("-x -x", "Do not use or dump XSDT"); + + ACPI_USAGE_TEXT ( + "\n" + "Invocation without parameters dumps all available tables\n" + "Multiple mixed instances of -a, -f, and -n are supported\n\n"); +} + + +/****************************************************************************** + * + * FUNCTION: ApInsertAction + * + * PARAMETERS: Argument - Pointer to the argument for this action + * ToBeDone - What to do to process this action + * + * RETURN: Status + * + * DESCRIPTION: Add an action item to the action table + * + ******************************************************************************/ + +static int +ApInsertAction ( + char *Argument, + UINT32 ToBeDone) +{ + + /* Insert action and check for table overflow */ + + ActionTable [CurrentAction].Argument = Argument; + ActionTable [CurrentAction].ToBeDone = ToBeDone; + + CurrentAction++; + if (CurrentAction > AP_MAX_ACTIONS) + { + AcpiLogError ("Too many table options (max %u)\n", AP_MAX_ACTIONS); + return (-1); + } + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: ApDoOptions + * + * PARAMETERS: argc/argv - Standard argc/argv + * + * RETURN: Status + * + * DESCRIPTION: Command line option processing. The main actions for getting + * and dumping tables are deferred via the action table. + * + *****************************************************************************/ + +static int +ApDoOptions ( + int argc, + char **argv) +{ + int j; + ACPI_STATUS Status; + + + /* Command line options */ + + while ((j = AcpiGetopt (argc, argv, AP_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch (j) + { + /* + * Global options + */ + case 'b': /* Dump all input tables to binary files */ + + Gbl_BinaryMode = TRUE; + continue; + + case 'c': /* Dump customized tables */ + + if (!strcmp (AcpiGbl_Optarg, "on")) + { + Gbl_DumpCustomizedTables = TRUE; + } + else if (!strcmp (AcpiGbl_Optarg, "off")) + { + Gbl_DumpCustomizedTables = FALSE; + } + else + { + AcpiLogError ("%s: Cannot handle this switch, please use on|off\n", + AcpiGbl_Optarg); + return (-1); + } + continue; + + case 'h': + case '?': + + ApDisplayUsage (); + return (1); + + case 'o': /* Redirect output to a single file */ + + if (ApOpenOutputFile (AcpiGbl_Optarg)) + { + return (-1); + } + continue; + + case 'r': /* Dump tables from specified RSDP */ + + Status = AcpiUtStrtoul64 (AcpiGbl_Optarg, 0, &Gbl_RsdpBase); + if (ACPI_FAILURE (Status)) + { + AcpiLogError ("%s: Could not convert to a physical address\n", + AcpiGbl_Optarg); + return (-1); + } + continue; + + case 's': /* Print table summaries only */ + + Gbl_SummaryMode = TRUE; + continue; + + case 'x': /* Do not use XSDT */ + + if (!AcpiGbl_DoNotUseXsdt) + { + AcpiGbl_DoNotUseXsdt = TRUE; + } + else + { + Gbl_DoNotDumpXsdt = TRUE; + } + continue; + + case 'v': /* Revision/version */ + + AcpiOsPrintf (ACPI_COMMON_SIGNON (AP_UTILITY_NAME)); + return (1); + + case 'z': /* Verbose mode */ + + Gbl_VerboseMode = TRUE; + AcpiLogError (ACPI_COMMON_SIGNON (AP_UTILITY_NAME)); + continue; + + /* + * Table options + */ + case 'a': /* Get table by physical address */ + + if (ApInsertAction (AcpiGbl_Optarg, AP_DUMP_TABLE_BY_ADDRESS)) + { + return (-1); + } + break; + + case 'f': /* Get table from a file */ + + if (ApInsertAction (AcpiGbl_Optarg, AP_DUMP_TABLE_BY_FILE)) + { + return (-1); + } + break; + + case 'n': /* Get table by input name (signature) */ + + if (ApInsertAction (AcpiGbl_Optarg, AP_DUMP_TABLE_BY_NAME)) + { + return (-1); + } + break; + + default: + + ApDisplayUsage (); + return (-1); + } + + /* If there are no actions, this means "get/dump all tables" */ + + if (CurrentAction == 0) + { + if (ApInsertAction (NULL, AP_DUMP_ALL_TABLES)) + { + return (-1); + } + } + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * PARAMETERS: argc/argv - Standard argc/argv + * + * RETURN: Status + * + * DESCRIPTION: C main function for acpidump utility + * + ******************************************************************************/ + +#ifndef _GNU_EFI +int ACPI_SYSTEM_XFACE +main ( + int argc, + char *argv[]) +#else +int ACPI_SYSTEM_XFACE +acpi_main ( + int argc, + char *argv[]) +#endif +{ + int Status = 0; + AP_DUMP_ACTION *Action; + UINT32 FileSize; + UINT32 i; + + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + AcpiOsInitialize (); + Gbl_OutputFile = ACPI_FILE_OUT; + + /* Process command line options */ + + Status = ApDoOptions (argc, argv); + if (Status > 0) + { + return (0); + } + if (Status < 0) + { + return (Status); + } + + /* Get/dump ACPI table(s) as requested */ + + for (i = 0; i < CurrentAction; i++) + { + Action = &ActionTable[i]; + switch (Action->ToBeDone) + { + case AP_DUMP_ALL_TABLES: + + Status = ApDumpAllTables (); + break; + + case AP_DUMP_TABLE_BY_ADDRESS: + + Status = ApDumpTableByAddress (Action->Argument); + break; + + case AP_DUMP_TABLE_BY_NAME: + + Status = ApDumpTableByName (Action->Argument); + break; + + case AP_DUMP_TABLE_BY_FILE: + + Status = ApDumpTableFromFile (Action->Argument); + break; + + default: + + AcpiLogError ("Internal error, invalid action: 0x%X\n", + Action->ToBeDone); + return (-1); + } + + if (Status) + { + return (Status); + } + } + + if (Gbl_OutputFilename) + { + if (Gbl_VerboseMode) + { + /* Summary for the output file */ + + FileSize = CmGetFileSize (Gbl_OutputFile); + AcpiLogError ("Output file %s contains 0x%X (%u) bytes\n\n", + Gbl_OutputFilename, FileSize, FileSize); + } + + AcpiOsCloseFile (Gbl_OutputFile); + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aecommon.h b/third_party/lib/acpica/source/tools/acpiexec/aecommon.h new file mode 100644 index 000000000..e573f73eb --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aecommon.h @@ -0,0 +1,212 @@ +/****************************************************************************** + * + * Module Name: aecommon - common include for the AcpiExec utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _AECOMMON +#define _AECOMMON + +#ifdef _MSC_VER /* disable some level-4 warnings */ +#pragma warning(disable:4100) /* warning C4100: unreferenced formal parameter */ +#endif + +#include "acpi.h" +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdebug.h" +#include "actables.h" +#include "acinterp.h" +#include "amlresrc.h" +#include "acapps.h" + +#include +#include +#include +#include + + +/* + * Debug Regions + */ +typedef struct ae_region +{ + ACPI_PHYSICAL_ADDRESS Address; + UINT32 Length; + void *Buffer; + void *NextRegion; + UINT8 SpaceId; + +} AE_REGION; + +typedef struct ae_debug_regions +{ + UINT32 NumberOfRegions; + AE_REGION *RegionList; + +} AE_DEBUG_REGIONS; + + +extern BOOLEAN AcpiGbl_IgnoreErrors; +extern UINT8 AcpiGbl_RegionFillValue; +extern UINT8 AcpiGbl_UseHwReducedFadt; +extern BOOLEAN AcpiGbl_DisplayRegionAccess; +extern BOOLEAN AcpiGbl_DoInterfaceTests; +extern BOOLEAN AcpiGbl_LoadTestTables; +extern FILE *AcpiGbl_NamespaceInitFile; +extern ACPI_CONNECTION_INFO AeMyContext; + + +#define TEST_OUTPUT_LEVEL(lvl) if ((lvl) & OutputLevel) + +#define OSD_PRINT(lvl,fp) TEST_OUTPUT_LEVEL(lvl) {\ + AcpiOsPrintf PARAM_LIST(fp);} + +void ACPI_SYSTEM_XFACE +AeCtrlCHandler ( + int Sig); + +ACPI_STATUS +AeBuildLocalTables ( + ACPI_NEW_TABLE_DESC *TableList); + +ACPI_STATUS +AeInstallTables ( + void); + +ACPI_STATUS +AeLoadTables ( + void); + +void +AeDumpNamespace ( + void); + +void +AeDumpObject ( + char *MethodName, + ACPI_BUFFER *ReturnObj); + +void +AeDumpBuffer ( + UINT32 Address); + +void +AeExecute ( + char *Name); + +void +AeSetScope ( + char *Name); + +void +AeCloseDebugFile ( + void); + +void +AeOpenDebugFile ( + char *Name); + +ACPI_STATUS +AeDisplayAllMethods ( + UINT32 DisplayCount); + +ACPI_STATUS +AeInstallEarlyHandlers ( + void); + +ACPI_STATUS +AeInstallLateHandlers ( + void); + +void +AeMiscellaneousTests ( + void); + +ACPI_STATUS +AeRegionHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +UINT32 +AeGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + void *Context); + +void +AeGlobalEventHandler ( + UINT32 Type, + ACPI_HANDLE GpeDevice, + UINT32 EventNumber, + void *Context); + +/* aeregion */ + +ACPI_STATUS +AeInstallDeviceHandlers ( + void); + +void +AeInstallRegionHandlers ( + void); + +void +AeOverrideRegionHandlers ( + void); + + +/* aeinitfile */ + +int +AeOpenInitializationFile ( + char *Filename); + +void +AeDoObjectOverrides ( + void); + +#endif /* _AECOMMON */ diff --git a/third_party/lib/acpica/source/tools/acpiexec/aeexec.c b/third_party/lib/acpica/source/tools/acpiexec/aeexec.c new file mode 100644 index 000000000..9fc80078c --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aeexec.c @@ -0,0 +1,868 @@ +/****************************************************************************** + * + * Module Name: aeexec - Support routines for AcpiExec utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aecommon.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("aeexec") + +/* Local prototypes */ + +static ACPI_STATUS +AeSetupConfiguration ( + void *RegionAddr); + +static void +AeTestBufferArgument ( + void); + +static void +AeTestPackageArgument ( + void); + +static ACPI_STATUS +AeGetDevices ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +ExecuteOSI ( + char *OsiString, + UINT32 ExpectedResult); + +static void +AeMutexInterfaces ( + void); + +static void +AeHardwareInterfaces ( + void); + +static void +AeGenericRegisters ( + void); + +static void +AeTestSleepData ( + void); + +#if (!ACPI_REDUCED_HARDWARE) +static void +AfInstallGpeBlock ( + void); +#endif /* !ACPI_REDUCED_HARDWARE */ + +extern unsigned char Ssdt2Code[]; +extern unsigned char Ssdt3Code[]; +extern unsigned char Ssdt4Code[]; + + +/****************************************************************************** + * + * FUNCTION: AeSetupConfiguration + * + * PARAMETERS: RegionAddr - Address for an ACPI table to be loaded + * dynamically. Test purposes only. + * + * RETURN: Status + * + * DESCRIPTION: Call AML _CFG configuration control method + * + *****************************************************************************/ + +static ACPI_STATUS +AeSetupConfiguration ( + void *RegionAddr) +{ + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg[3]; + + + /* + * Invoke _CFG method if present + */ + ArgList.Count = 1; + ArgList.Pointer = Arg; + + Arg[0].Type = ACPI_TYPE_INTEGER; + Arg[0].Integer.Value = ACPI_TO_INTEGER (RegionAddr); + + (void) AcpiEvaluateObject (NULL, "\\_CFG", &ArgList, NULL); + return (AE_OK); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/****************************************************************************** + * + * FUNCTION: AfInstallGpeBlock + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Test GPE block device initialization. Requires test ASL with + * A \GPE2 device. + * + *****************************************************************************/ + +static void +AfInstallGpeBlock ( + void) +{ + ACPI_STATUS Status; + ACPI_HANDLE Handle; + ACPI_GENERIC_ADDRESS BlockAddress; + ACPI_HANDLE GpeDevice; + ACPI_OBJECT_TYPE Type; + + + /* _GPE should always exist */ + + Status = AcpiGetHandle (NULL, "\\_GPE", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + if (ACPI_FAILURE (Status)) + { + return; + } + + memset (&BlockAddress, 0, sizeof (ACPI_GENERIC_ADDRESS)); + BlockAddress.SpaceId = ACPI_ADR_SPACE_SYSTEM_MEMORY; + BlockAddress.Address = 0x76540000; + + /* Attempt to install a GPE block on GPE2 (if present) */ + + Status = AcpiGetHandle (NULL, "\\GPE2", &Handle); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiGetType (Handle, &Type); + if (ACPI_FAILURE (Status) || + (Type != ACPI_TYPE_DEVICE)) + { + return; + } + + Status = AcpiInstallGpeBlock (Handle, &BlockAddress, 7, 8); + ACPI_CHECK_OK (AcpiInstallGpeBlock, Status); + + Status = AcpiInstallGpeHandler (Handle, 8, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (Handle, 8); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + Status = AcpiGetGpeDevice (0x30, &GpeDevice); + ACPI_CHECK_OK (AcpiGetGpeDevice, Status); + + Status = AcpiGetGpeDevice (0x42, &GpeDevice); + ACPI_CHECK_OK (AcpiGetGpeDevice, Status); + + Status = AcpiGetGpeDevice (AcpiCurrentGpeCount-1, &GpeDevice); + ACPI_CHECK_OK (AcpiGetGpeDevice, Status); + + Status = AcpiGetGpeDevice (AcpiCurrentGpeCount, &GpeDevice); + ACPI_CHECK_STATUS (AcpiGetGpeDevice, Status, AE_NOT_EXIST); + + Status = AcpiRemoveGpeHandler (Handle, 8, AeGpeHandler); + ACPI_CHECK_OK (AcpiRemoveGpeHandler, Status); + } + + /* Attempt to install a GPE block on GPE3 (if present) */ + + Status = AcpiGetHandle (NULL, "\\GPE3", &Handle); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiGetType (Handle, &Type); + if (ACPI_FAILURE (Status) || + (Type != ACPI_TYPE_DEVICE)) + { + return; + } + + Status = AcpiInstallGpeBlock (Handle, &BlockAddress, 8, 11); + ACPI_CHECK_OK (AcpiInstallGpeBlock, Status); + } +} +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/* Test using a Buffer object as a method argument */ + +static void +AeTestBufferArgument ( + void) +{ + ACPI_OBJECT_LIST Params; + ACPI_OBJECT BufArg; + UINT8 Buffer[] = + { + 0,0,0,0, + 4,0,0,0, + 1,2,3,4 + }; + + + BufArg.Type = ACPI_TYPE_BUFFER; + BufArg.Buffer.Length = 12; + BufArg.Buffer.Pointer = Buffer; + + Params.Count = 1; + Params.Pointer = &BufArg; + + (void) AcpiEvaluateObject (NULL, "\\BUF", &Params, NULL); +} + + +static ACPI_OBJECT PkgArg; +static ACPI_OBJECT PkgElements[5]; +static ACPI_OBJECT Pkg2Elements[5]; +static ACPI_OBJECT_LIST Params; + + +/* + * Test using a Package object as an method argument + */ +static void +AeTestPackageArgument ( + void) +{ + + /* Main package */ + + PkgArg.Type = ACPI_TYPE_PACKAGE; + PkgArg.Package.Count = 4; + PkgArg.Package.Elements = PkgElements; + + /* Main package elements */ + + PkgElements[0].Type = ACPI_TYPE_INTEGER; + PkgElements[0].Integer.Value = 0x22228888; + + PkgElements[1].Type = ACPI_TYPE_STRING; + PkgElements[1].String.Length = sizeof ("Top-level package"); + PkgElements[1].String.Pointer = "Top-level package"; + + PkgElements[2].Type = ACPI_TYPE_BUFFER; + PkgElements[2].Buffer.Length = sizeof ("XXXX"); + PkgElements[2].Buffer.Pointer = (UINT8 *) "XXXX"; + + PkgElements[3].Type = ACPI_TYPE_PACKAGE; + PkgElements[3].Package.Count = 2; + PkgElements[3].Package.Elements = Pkg2Elements; + + /* Subpackage elements */ + + Pkg2Elements[0].Type = ACPI_TYPE_INTEGER; + Pkg2Elements[0].Integer.Value = 0xAAAABBBB; + + Pkg2Elements[1].Type = ACPI_TYPE_STRING; + Pkg2Elements[1].String.Length = sizeof ("Nested Package"); + Pkg2Elements[1].String.Pointer = "Nested Package"; + + /* Parameter object */ + + Params.Count = 1; + Params.Pointer = &PkgArg; + + (void) AcpiEvaluateObject (NULL, "\\_PKG", &Params, NULL); +} + + +static ACPI_STATUS +AeGetDevices ( + ACPI_HANDLE ObjHandle, + UINT32 NestingLevel, + void *Context, + void **ReturnValue) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: ExecuteOSI + * + * PARAMETERS: OsiString - String passed to _OSI method + * ExpectedResult - 0 (FALSE) or 0xFFFFFFFF (TRUE) + * + * RETURN: Status + * + * DESCRIPTION: Execute the internally implemented (in ACPICA) _OSI method. + * + *****************************************************************************/ + +static ACPI_STATUS +ExecuteOSI ( + char *OsiString, + UINT32 ExpectedResult) +{ + ACPI_STATUS Status; + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg[1]; + ACPI_BUFFER ReturnValue; + ACPI_OBJECT *Obj; + + + /* Setup input argument */ + + ArgList.Count = 1; + ArgList.Pointer = Arg; + + Arg[0].Type = ACPI_TYPE_STRING; + Arg[0].String.Pointer = OsiString; + Arg[0].String.Length = strlen (Arg[0].String.Pointer); + + /* Ask ACPICA to allocate space for the return object */ + + ReturnValue.Length = ACPI_ALLOCATE_BUFFER; + + Status = AcpiEvaluateObject (NULL, "\\_OSI", &ArgList, &ReturnValue); + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ( + "Could not execute _OSI method, %s\n", + AcpiFormatException (Status)); + return (Status); + } + + Status = AE_ERROR; + + if (ReturnValue.Length < sizeof (ACPI_OBJECT)) + { + AcpiOsPrintf ( + "Return value from _OSI method too small, %.8X\n", + ReturnValue.Length); + goto ErrorExit; + } + + Obj = ReturnValue.Pointer; + if (Obj->Type != ACPI_TYPE_INTEGER) + { + AcpiOsPrintf ( + "Invalid return type from _OSI method, %.2X\n", Obj->Type); + goto ErrorExit; + } + + if (Obj->Integer.Value != ExpectedResult) + { + AcpiOsPrintf ( + "Invalid return value from _OSI, expected %.8X found %.8X\n", + ExpectedResult, (UINT32) Obj->Integer.Value); + goto ErrorExit; + } + + Status = AE_OK; + + /* Reset the OSI data */ + + AcpiGbl_OsiData = 0; + +ErrorExit: + + /* Free a buffer created via ACPI_ALLOCATE_BUFFER */ + + AcpiOsFree (ReturnValue.Pointer); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AeGenericRegisters + * + * DESCRIPTION: Call the AcpiRead/Write interfaces. + * + *****************************************************************************/ + +static ACPI_GENERIC_ADDRESS GenericRegister; + +static void +AeGenericRegisters ( + void) +{ + ACPI_STATUS Status; + UINT64 Value; + + + GenericRegister.Address = 0x1234; + GenericRegister.BitWidth = 64; + GenericRegister.BitOffset = 0; + GenericRegister.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO; + + Status = AcpiRead (&Value, &GenericRegister); + ACPI_CHECK_OK (AcpiRead, Status); + + Status = AcpiWrite (Value, &GenericRegister); + ACPI_CHECK_OK (AcpiWrite, Status); + + GenericRegister.Address = 0x12345678; + GenericRegister.BitOffset = 0; + GenericRegister.SpaceId = ACPI_ADR_SPACE_SYSTEM_MEMORY; + + Status = AcpiRead (&Value, &GenericRegister); + ACPI_CHECK_OK (AcpiRead, Status); + + Status = AcpiWrite (Value, &GenericRegister); + ACPI_CHECK_OK (AcpiWrite, Status); +} + + +/****************************************************************************** + * + * FUNCTION: AeMutexInterfaces + * + * DESCRIPTION: Exercise the AML mutex access interfaces + * + *****************************************************************************/ + +static void +AeMutexInterfaces ( + void) +{ + ACPI_STATUS Status; + ACPI_HANDLE MutexHandle; + + + /* Get a handle to an AML mutex */ + + Status = AcpiGetHandle (NULL, "\\MTX1", &MutexHandle); + if (Status == AE_NOT_FOUND) + { + return; + } + + ACPI_CHECK_OK (AcpiGetHandle, Status); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Acquire the mutex */ + + Status = AcpiAcquireMutex (NULL, "\\MTX1", 0xFFFF); + ACPI_CHECK_OK (AcpiAcquireMutex, Status); + if (ACPI_FAILURE (Status)) + { + return; + } + + /* Release mutex with different parameters */ + + Status = AcpiReleaseMutex (MutexHandle, NULL); + ACPI_CHECK_OK (AcpiReleaseMutex, Status); +} + + +/****************************************************************************** + * + * FUNCTION: AeHardwareInterfaces + * + * DESCRIPTION: Call various hardware support interfaces + * + *****************************************************************************/ + +static void +AeHardwareInterfaces ( + void) +{ +#if (!ACPI_REDUCED_HARDWARE) + + ACPI_STATUS Status; + UINT32 Value; + + + /* If Hardware Reduced flag is set, we are all done */ + + if (AcpiGbl_ReducedHardware) + { + return; + } + + Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, 1); + ACPI_CHECK_OK (AcpiWriteBitRegister, Status); + + Status = AcpiWriteBitRegister (ACPI_BITREG_GLOBAL_LOCK_ENABLE, 1); + ACPI_CHECK_OK (AcpiWriteBitRegister, Status); + + Status = AcpiWriteBitRegister (ACPI_BITREG_SLEEP_ENABLE, 1); + ACPI_CHECK_OK (AcpiWriteBitRegister, Status); + + Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); + ACPI_CHECK_OK (AcpiWriteBitRegister, Status); + + + Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &Value); + ACPI_CHECK_OK (AcpiReadBitRegister, Status); + + Status = AcpiReadBitRegister (ACPI_BITREG_GLOBAL_LOCK_ENABLE, &Value); + ACPI_CHECK_OK (AcpiReadBitRegister, Status); + + Status = AcpiReadBitRegister (ACPI_BITREG_SLEEP_ENABLE, &Value); + ACPI_CHECK_OK (AcpiReadBitRegister, Status); + + Status = AcpiReadBitRegister (ACPI_BITREG_ARB_DISABLE, &Value); + ACPI_CHECK_OK (AcpiReadBitRegister, Status); + +#endif /* !ACPI_REDUCED_HARDWARE */ +} + + +/****************************************************************************** + * + * FUNCTION: AeTestSleepData + * + * DESCRIPTION: Exercise the sleep/wake support (_S0, _S1, etc.) + * + *****************************************************************************/ + +static void +AeTestSleepData ( + void) +{ + int State; + UINT8 TypeA; + UINT8 TypeB; + ACPI_STATUS Status; + + + /* Attempt to get sleep data for all known sleep states */ + + for (State = ACPI_STATE_S0; State <= ACPI_S_STATES_MAX; State++) + { + Status = AcpiGetSleepTypeData ((UINT8) State, &TypeA, &TypeB); + + /* All sleep methods are optional */ + + if (Status != AE_NOT_FOUND) + { + ACPI_CHECK_OK (AcpiGetSleepTypeData, Status); + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AeMiscellaneousTests + * + * DESCRIPTION: Various ACPICA validation tests. + * + *****************************************************************************/ + +void +AeMiscellaneousTests ( + void) +{ + ACPI_BUFFER ReturnBuf; + char Buffer[32]; + ACPI_STATUS Status; + ACPI_STATISTICS Stats; + ACPI_HANDLE Handle; + +#if (!ACPI_REDUCED_HARDWARE) + UINT32 LockHandle1; + UINT32 LockHandle2; + ACPI_VENDOR_UUID Uuid = + {0, {ACPI_INIT_UUID (0,0,0,0,0,0,0,0,0,0,0)}}; +#endif /* !ACPI_REDUCED_HARDWARE */ + + + Status = AcpiGetHandle (NULL, "\\", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + + if (AcpiGbl_DoInterfaceTests) + { + /* + * Tests for AcpiLoadTable and AcpiUnloadParentTable + */ + + /* Attempt unload of DSDT, should fail */ + + Status = AcpiGetHandle (NULL, "\\_SB_", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + + Status = AcpiUnloadParentTable (Handle); + ACPI_CHECK_STATUS (AcpiUnloadParentTable, Status, AE_TYPE); + + /* Load and unload SSDT4 */ + + Status = AcpiLoadTable ((ACPI_TABLE_HEADER *) Ssdt4Code); + ACPI_CHECK_OK (AcpiLoadTable, Status); + + Status = AcpiGetHandle (NULL, "\\_T96", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + + Status = AcpiUnloadParentTable (Handle); + ACPI_CHECK_OK (AcpiUnloadParentTable, Status); + + /* Re-load SSDT4 */ + + Status = AcpiLoadTable ((ACPI_TABLE_HEADER *) Ssdt4Code); + ACPI_CHECK_OK (AcpiLoadTable, Status); + + /* Unload and re-load SSDT2 (SSDT2 is in the XSDT) */ + + Status = AcpiGetHandle (NULL, "\\_T99", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + + Status = AcpiUnloadParentTable (Handle); + ACPI_CHECK_OK (AcpiUnloadParentTable, Status); + + Status = AcpiLoadTable ((ACPI_TABLE_HEADER *) Ssdt2Code); + ACPI_CHECK_OK (AcpiLoadTable, Status); + + /* Load OEM9 table (causes table override) */ + + Status = AcpiLoadTable ((ACPI_TABLE_HEADER *) Ssdt3Code); + ACPI_CHECK_OK (AcpiLoadTable, Status); + } + + AeHardwareInterfaces (); + AeGenericRegisters (); + AeSetupConfiguration (Ssdt3Code); + + AeTestBufferArgument(); + AeTestPackageArgument (); + AeMutexInterfaces (); + AeTestSleepData (); + + /* Test _OSI install/remove */ + + Status = AcpiInstallInterface (""); + ACPI_CHECK_STATUS (AcpiInstallInterface, Status, AE_BAD_PARAMETER); + + Status = AcpiInstallInterface ("TestString"); + ACPI_CHECK_OK (AcpiInstallInterface, Status); + + Status = AcpiInstallInterface ("TestString"); + ACPI_CHECK_STATUS (AcpiInstallInterface, Status, AE_ALREADY_EXISTS); + + Status = AcpiRemoveInterface ("Windows 2006"); + ACPI_CHECK_OK (AcpiRemoveInterface, Status); + + Status = AcpiRemoveInterface ("TestString"); + ACPI_CHECK_OK (AcpiRemoveInterface, Status); + + Status = AcpiRemoveInterface ("XXXXXX"); + ACPI_CHECK_STATUS (AcpiRemoveInterface, Status, AE_NOT_EXIST); + + Status = AcpiInstallInterface ("AnotherTestString"); + ACPI_CHECK_OK (AcpiInstallInterface, Status); + + /* Test _OSI execution */ + + Status = ExecuteOSI ("Extended Address Space Descriptor", 0xFFFFFFFF); + ACPI_CHECK_OK (ExecuteOSI, Status); + + Status = ExecuteOSI ("Windows 2001", 0xFFFFFFFF); + ACPI_CHECK_OK (ExecuteOSI, Status); + + Status = ExecuteOSI ("MichiganTerminalSystem", 0); + ACPI_CHECK_OK (ExecuteOSI, Status); + + + ReturnBuf.Length = 32; + ReturnBuf.Pointer = Buffer; + + Status = AcpiGetName (ACPI_ROOT_OBJECT, + ACPI_FULL_PATHNAME_NO_TRAILING, &ReturnBuf); + ACPI_CHECK_OK (AcpiGetName, Status); + + /* Get Devices */ + + Status = AcpiGetDevices (NULL, AeGetDevices, NULL, NULL); + ACPI_CHECK_OK (AcpiGetDevices, Status); + + Status = AcpiGetStatistics (&Stats); + ACPI_CHECK_OK (AcpiGetStatistics, Status); + + +#if (!ACPI_REDUCED_HARDWARE) + + Status = AcpiInstallGlobalEventHandler (AeGlobalEventHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGlobalEventHandler, Status); + + /* If Hardware Reduced flag is set, we are all done */ + + if (AcpiGbl_ReducedHardware) + { + return; + } + + Status = AcpiEnableEvent (ACPI_EVENT_GLOBAL, 0); + ACPI_CHECK_OK (AcpiEnableEvent, Status); + + /* + * GPEs: Handlers, enable/disable, etc. + */ + Status = AcpiInstallGpeHandler (NULL, 0, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (NULL, 0); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + Status = AcpiRemoveGpeHandler (NULL, 0, AeGpeHandler); + ACPI_CHECK_OK (AcpiRemoveGpeHandler, Status); + + Status = AcpiInstallGpeHandler (NULL, 0, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (NULL, 0); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + Status = AcpiSetGpe (NULL, 0, ACPI_GPE_DISABLE); + ACPI_CHECK_OK (AcpiSetGpe, Status); + + Status = AcpiSetGpe (NULL, 0, ACPI_GPE_ENABLE); + ACPI_CHECK_OK (AcpiSetGpe, Status); + + + Status = AcpiInstallGpeHandler (NULL, 1, + ACPI_GPE_EDGE_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (NULL, 1); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + + Status = AcpiInstallGpeHandler (NULL, 2, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (NULL, 2); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + + Status = AcpiInstallGpeHandler (NULL, 3, + ACPI_GPE_EDGE_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiInstallGpeHandler (NULL, 4, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiInstallGpeHandler (NULL, 5, + ACPI_GPE_EDGE_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiGetHandle (NULL, "\\_SB", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + + Status = AcpiSetupGpeForWake (Handle, NULL, 5); + ACPI_CHECK_OK (AcpiSetupGpeForWake, Status); + + Status = AcpiSetGpeWakeMask (NULL, 5, ACPI_GPE_ENABLE); + ACPI_CHECK_OK (AcpiSetGpeWakeMask, Status); + + Status = AcpiSetupGpeForWake (Handle, NULL, 6); + ACPI_CHECK_OK (AcpiSetupGpeForWake, Status); + + Status = AcpiSetupGpeForWake (ACPI_ROOT_OBJECT, NULL, 6); + ACPI_CHECK_OK (AcpiSetupGpeForWake, Status); + + Status = AcpiSetupGpeForWake (Handle, NULL, 9); + ACPI_CHECK_OK (AcpiSetupGpeForWake, Status); + + Status = AcpiInstallGpeHandler (NULL, 0x19, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (NULL, 0x19); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + + /* GPE block 1 */ + + Status = AcpiInstallGpeHandler (NULL, 101, + ACPI_GPE_LEVEL_TRIGGERED, AeGpeHandler, NULL); + ACPI_CHECK_OK (AcpiInstallGpeHandler, Status); + + Status = AcpiEnableGpe (NULL, 101); + ACPI_CHECK_OK (AcpiEnableGpe, Status); + + Status = AcpiDisableGpe (NULL, 101); + ACPI_CHECK_OK (AcpiDisableGpe, Status); + + AfInstallGpeBlock (); + + /* Here is where the GPEs are actually "enabled" */ + + Status = AcpiUpdateAllGpes (); + ACPI_CHECK_OK (AcpiUpdateAllGpes, Status); + + Status = AcpiGetHandle (NULL, "RSRC", &Handle); + if (ACPI_SUCCESS (Status)) + { + ReturnBuf.Length = ACPI_ALLOCATE_BUFFER; + + Status = AcpiGetVendorResource (Handle, "_CRS", &Uuid, &ReturnBuf); + if (ACPI_SUCCESS (Status)) + { + AcpiOsFree (ReturnBuf.Pointer); + } + } + + /* Test global lock */ + + Status = AcpiAcquireGlobalLock (0xFFFF, &LockHandle1); + ACPI_CHECK_OK (AcpiAcquireGlobalLock, Status); + + Status = AcpiAcquireGlobalLock (0x5, &LockHandle2); + ACPI_CHECK_OK (AcpiAcquireGlobalLock, Status); + + Status = AcpiReleaseGlobalLock (LockHandle1); + ACPI_CHECK_OK (AcpiReleaseGlobalLock, Status); + + Status = AcpiReleaseGlobalLock (LockHandle2); + ACPI_CHECK_OK (AcpiReleaseGlobalLock, Status); + +#endif /* !ACPI_REDUCED_HARDWARE */ +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aehandlers.c b/third_party/lib/acpica/source/tools/acpiexec/aehandlers.c new file mode 100644 index 000000000..811e41ec8 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aehandlers.c @@ -0,0 +1,927 @@ +/****************************************************************************** + * + * Module Name: aehandlers - Various handlers for acpiexec + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aecommon.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("aehandlers") + + +/* Local prototypes */ + +static void +AeNotifyHandler1 ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context); + +static void +AeNotifyHandler2 ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context); + +static void +AeCommonNotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + UINT32 HandlerId); + +static void +AeDeviceNotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context); + +static ACPI_STATUS +AeExceptionHandler ( + ACPI_STATUS AmlStatus, + ACPI_NAME Name, + UINT16 Opcode, + UINT32 AmlOffset, + void *Context); + +static ACPI_STATUS +AeTableHandler ( + UINT32 Event, + void *Table, + void *Context); + +static void +AeAttachedDataHandler ( + ACPI_HANDLE Object, + void *Data); + +static void +AeAttachedDataHandler2 ( + ACPI_HANDLE Object, + void *Data); + +static UINT32 +AeInterfaceHandler ( + ACPI_STRING InterfaceName, + UINT32 Supported); + +#if (!ACPI_REDUCED_HARDWARE) +static UINT32 +AeEventHandler ( + void *Context); + +static UINT32 +AeSciHandler ( + void *Context); + +static char *TableEvents[] = +{ + "LOAD", + "UNLOAD", + "UNKNOWN" +}; +#endif /* !ACPI_REDUCED_HARDWARE */ + + +static UINT32 SigintCount = 0; +static AE_DEBUG_REGIONS AeRegions; + + +/****************************************************************************** + * + * FUNCTION: AeCtrlCHandler + * + * PARAMETERS: Sig + * + * RETURN: none + * + * DESCRIPTION: Control-C handler. Abort running control method if any. + * + *****************************************************************************/ + +void ACPI_SYSTEM_XFACE +AeCtrlCHandler ( + int Sig) +{ + + signal (SIGINT, SIG_IGN); + SigintCount++; + + AcpiOsPrintf ("Caught a ctrl-c (#%u)\n\n", SigintCount); + + if (AcpiGbl_MethodExecuting) + { + AcpiGbl_AbortMethod = TRUE; + signal (SIGINT, AeCtrlCHandler); + + if (SigintCount < 10) + { + return; + } + } + + (void) AcpiOsTerminate (); + exit (0); +} + + +/****************************************************************************** + * + * FUNCTION: AeNotifyHandler(s) + * + * PARAMETERS: Standard notify handler parameters + * + * RETURN: Status + * + * DESCRIPTION: Notify handlers for AcpiExec utility. Used by the ASL + * test suite(s) to communicate errors and other information to + * this utility via the Notify() operator. Tests notify handling + * and multiple notify handler support. + * + *****************************************************************************/ + +static void +AeNotifyHandler1 ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context) +{ + AeCommonNotifyHandler (Device, Value, 1); +} + +static void +AeNotifyHandler2 ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context) +{ + AeCommonNotifyHandler (Device, Value, 2); +} + +static void +AeCommonNotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + UINT32 HandlerId) +{ + char *Type; + + + Type = "Device"; + if (Value <= ACPI_MAX_SYS_NOTIFY) + { + Type = "System"; + } + + switch (Value) + { +#if 0 + case 0: + + printf ("[AcpiExec] Method Error 0x%X: Results not equal\n", Value); + if (AcpiGbl_DebugFile) + { + AcpiOsPrintf ("[AcpiExec] Method Error: Results not equal\n"); + } + break; + + case 1: + + printf ("[AcpiExec] Method Error: Incorrect numeric result\n"); + if (AcpiGbl_DebugFile) + { + AcpiOsPrintf ("[AcpiExec] Method Error: Incorrect numeric result\n"); + } + break; + + case 2: + + printf ("[AcpiExec] Method Error: An operand was overwritten\n"); + if (AcpiGbl_DebugFile) + { + AcpiOsPrintf ("[AcpiExec] Method Error: An operand was overwritten\n"); + } + break; + +#endif + + default: + + printf ("[AcpiExec] Handler %u: Received a %s Notify on [%4.4s] %p Value 0x%2.2X (%s)\n", + HandlerId, Type, AcpiUtGetNodeName (Device), Device, Value, + AcpiUtGetNotifyName (Value, ACPI_TYPE_ANY)); + if (AcpiGbl_DebugFile) + { + AcpiOsPrintf ("[AcpiExec] Handler %u: Received a %s notify, Value 0x%2.2X\n", + HandlerId, Type, Value); + } + + (void) AcpiEvaluateObject (Device, "_NOT", NULL, NULL); + break; + } +} + + +/****************************************************************************** + * + * FUNCTION: AeSystemNotifyHandler + * + * PARAMETERS: Standard notify handler parameters + * + * RETURN: Status + * + * DESCRIPTION: System notify handler for AcpiExec utility. Used by the ASL + * test suite(s) to communicate errors and other information to + * this utility via the Notify() operator. + * + *****************************************************************************/ + +static void +AeSystemNotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context) +{ + + printf ("[AcpiExec] Global: Received a System Notify on [%4.4s] %p Value 0x%2.2X (%s)\n", + AcpiUtGetNodeName (Device), Device, Value, + AcpiUtGetNotifyName (Value, ACPI_TYPE_ANY)); + if (AcpiGbl_DebugFile) + { + AcpiOsPrintf ("[AcpiExec] Global: Received a System Notify, Value 0x%2.2X\n", Value); + } + + (void) AcpiEvaluateObject (Device, "_NOT", NULL, NULL); +} + + +/****************************************************************************** + * + * FUNCTION: AeDeviceNotifyHandler + * + * PARAMETERS: Standard notify handler parameters + * + * RETURN: Status + * + * DESCRIPTION: Device notify handler for AcpiExec utility. Used by the ASL + * test suite(s) to communicate errors and other information to + * this utility via the Notify() operator. + * + *****************************************************************************/ + +static void +AeDeviceNotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context) +{ + + printf ("[AcpiExec] Global: Received a Device Notify on [%4.4s] %p Value 0x%2.2X (%s)\n", + AcpiUtGetNodeName (Device), Device, Value, + AcpiUtGetNotifyName (Value, ACPI_TYPE_ANY)); + if (AcpiGbl_DebugFile) + { + AcpiOsPrintf ("[AcpiExec] Global: Received a Device Notify, Value 0x%2.2X\n", Value); + } + + (void) AcpiEvaluateObject (Device, "_NOT", NULL, NULL); +} + + +/****************************************************************************** + * + * FUNCTION: AeExceptionHandler + * + * PARAMETERS: Standard exception handler parameters + * + * RETURN: Status + * + * DESCRIPTION: System exception handler for AcpiExec utility. + * + *****************************************************************************/ + +static ACPI_STATUS +AeExceptionHandler ( + ACPI_STATUS AmlStatus, + ACPI_NAME Name, + UINT16 Opcode, + UINT32 AmlOffset, + void *Context) +{ + ACPI_STATUS NewAmlStatus = AmlStatus; + ACPI_STATUS Status; + ACPI_BUFFER ReturnObj; + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg[3]; + const char *Exception; + + + Exception = AcpiFormatException (AmlStatus); + AcpiOsPrintf ("[AcpiExec] Exception %s during execution ", Exception); + if (Name) + { + AcpiOsPrintf ("of method [%4.4s]", (char *) &Name); + } + else + { + AcpiOsPrintf ("at module level (table load)"); + } + + AcpiOsPrintf (" Opcode [%s] @%X\n", AcpiPsGetOpcodeName (Opcode), AmlOffset); + + /* + * Invoke the _ERR method if present + * + * Setup parameter object + */ + ArgList.Count = 3; + ArgList.Pointer = Arg; + + Arg[0].Type = ACPI_TYPE_INTEGER; + Arg[0].Integer.Value = AmlStatus; + + Arg[1].Type = ACPI_TYPE_STRING; + Arg[1].String.Pointer = ACPI_CAST_PTR (char, Exception); + Arg[1].String.Length = strlen (Exception); + + Arg[2].Type = ACPI_TYPE_INTEGER; + Arg[2].Integer.Value = AcpiOsGetThreadId(); + + /* Setup return buffer */ + + ReturnObj.Pointer = NULL; + ReturnObj.Length = ACPI_ALLOCATE_BUFFER; + + Status = AcpiEvaluateObject (NULL, "\\_ERR", &ArgList, &ReturnObj); + if (ACPI_SUCCESS (Status)) + { + if (ReturnObj.Pointer) + { + /* Override original status */ + + NewAmlStatus = (ACPI_STATUS) + ((ACPI_OBJECT *) ReturnObj.Pointer)->Integer.Value; + + /* Free a buffer created via ACPI_ALLOCATE_BUFFER */ + + AcpiOsFree (ReturnObj.Pointer); + } + } + else if (Status != AE_NOT_FOUND) + { + AcpiOsPrintf ("[AcpiExec] Could not execute _ERR method, %s\n", + AcpiFormatException (Status)); + } + + /* Global override */ + + if (AcpiGbl_IgnoreErrors) + { + NewAmlStatus = AE_OK; + } + + if (NewAmlStatus != AmlStatus) + { + AcpiOsPrintf ("[AcpiExec] Exception override, new status %s\n\n", + AcpiFormatException (NewAmlStatus)); + } + + return (NewAmlStatus); +} + + +/****************************************************************************** + * + * FUNCTION: AeTableHandler + * + * PARAMETERS: Table handler + * + * RETURN: Status + * + * DESCRIPTION: System table handler for AcpiExec utility. + * + *****************************************************************************/ + +static ACPI_STATUS +AeTableHandler ( + UINT32 Event, + void *Table, + void *Context) +{ +#if (!ACPI_REDUCED_HARDWARE) + ACPI_STATUS Status; +#endif /* !ACPI_REDUCED_HARDWARE */ + + + if (Event > ACPI_NUM_TABLE_EVENTS) + { + Event = ACPI_NUM_TABLE_EVENTS; + } + +#if (!ACPI_REDUCED_HARDWARE) + /* Enable any GPEs associated with newly-loaded GPE methods */ + + Status = AcpiUpdateAllGpes (); + ACPI_CHECK_OK (AcpiUpdateAllGpes, Status); + + printf ("[AcpiExec] Table Event %s, [%4.4s] %p\n", + TableEvents[Event], ((ACPI_TABLE_HEADER *) Table)->Signature, Table); +#endif /* !ACPI_REDUCED_HARDWARE */ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AeGpeHandler + * + * DESCRIPTION: Common GPE handler for acpiexec + * + *****************************************************************************/ + +UINT32 +AeGpeHandler ( + ACPI_HANDLE GpeDevice, + UINT32 GpeNumber, + void *Context) +{ + ACPI_NAMESPACE_NODE *DeviceNode = (ACPI_NAMESPACE_NODE *) GpeDevice; + + + AcpiOsPrintf ("[AcpiExec] GPE Handler received GPE %02X (GPE block %4.4s)\n", + GpeNumber, GpeDevice ? DeviceNode->Name.Ascii : "FADT"); + + return (ACPI_REENABLE_GPE); +} + + +/****************************************************************************** + * + * FUNCTION: AeGlobalEventHandler + * + * DESCRIPTION: Global GPE/Fixed event handler + * + *****************************************************************************/ + +void +AeGlobalEventHandler ( + UINT32 Type, + ACPI_HANDLE Device, + UINT32 EventNumber, + void *Context) +{ + char *TypeName; + + + switch (Type) + { + case ACPI_EVENT_TYPE_GPE: + + TypeName = "GPE"; + break; + + case ACPI_EVENT_TYPE_FIXED: + + TypeName = "FixedEvent"; + break; + + default: + + TypeName = "UNKNOWN"; + break; + } + + AcpiOsPrintf ( + "[AcpiExec] Global Event Handler received: Type %s Number %.2X Dev %p\n", + TypeName, EventNumber, Device); +} + + +/****************************************************************************** + * + * FUNCTION: AeAttachedDataHandler + * + * DESCRIPTION: Handler for deletion of nodes with attached data (attached via + * AcpiAttachData) + * + *****************************************************************************/ + +static void +AeAttachedDataHandler ( + ACPI_HANDLE Object, + void *Data) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Data); + + + AcpiOsPrintf ("Received an attached data deletion (1) on %4.4s\n", + Node->Name.Ascii); +} + + +/****************************************************************************** + * + * FUNCTION: AeAttachedDataHandler2 + * + * DESCRIPTION: Handler for deletion of nodes with attached data (attached via + * AcpiAttachData) + * + *****************************************************************************/ + +static void +AeAttachedDataHandler2 ( + ACPI_HANDLE Object, + void *Data) +{ + ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Data); + + + AcpiOsPrintf ("Received an attached data deletion (2) on %4.4s\n", + Node->Name.Ascii); +} + + +/****************************************************************************** + * + * FUNCTION: AeInterfaceHandler + * + * DESCRIPTION: Handler for _OSI invocations + * + *****************************************************************************/ + +static UINT32 +AeInterfaceHandler ( + ACPI_STRING InterfaceName, + UINT32 Supported) +{ + ACPI_FUNCTION_NAME (AeInterfaceHandler); + + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Received _OSI (\"%s\"), is %ssupported\n", + InterfaceName, Supported == 0 ? "not " : "")); + + return (Supported); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/****************************************************************************** + * + * FUNCTION: AeEventHandler, AeSciHandler + * + * DESCRIPTION: Handler for Fixed Events and SCIs + * + *****************************************************************************/ + +static UINT32 +AeEventHandler ( + void *Context) +{ + return (0); +} + +static UINT32 +AeSciHandler ( + void *Context) +{ + + AcpiOsPrintf ("[AcpiExec] Received an SCI at handler\n"); + return (0); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AeInstallSciHandler + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install handler for SCIs. Exercise the code by doing an + * install/remove/install. + * + ******************************************************************************/ + +static ACPI_STATUS +AeInstallSciHandler ( + void) +{ + ACPI_STATUS Status; + + + Status = AcpiInstallSciHandler (AeSciHandler, &AeMyContext); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an SCI handler (1)")); + } + + Status = AcpiRemoveSciHandler (AeSciHandler); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not remove an SCI handler")); + } + + Status = AcpiInstallSciHandler (AeSciHandler, &AeMyContext); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an SCI handler (2)")); + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AeInstallLateHandlers + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install handlers for the AcpiExec utility. + * + *****************************************************************************/ + +ACPI_STATUS +AeInstallLateHandlers ( + void) +{ + ACPI_STATUS Status; + ACPI_HANDLE Handle; + + + Status = AcpiGetHandle (NULL, "\\_TZ.TZ1", &Handle); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1, ACPI_CAST_PTR (void, 0x01234567)); + + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler2, ACPI_CAST_PTR (void, 0x89ABCDEF)); + + Status = AcpiRemoveNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1); + Status = AcpiRemoveNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler2); + + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler2, ACPI_CAST_PTR (void, 0x89ABCDEF)); + + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1, ACPI_CAST_PTR (void, 0x01234567)); + } + + Status = AcpiGetHandle (NULL, "\\_PR.CPU0", &Handle); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1, ACPI_CAST_PTR (void, 0x01234567)); + + Status = AcpiInstallNotifyHandler (Handle, ACPI_SYSTEM_NOTIFY, + AeNotifyHandler2, ACPI_CAST_PTR (void, 0x89ABCDEF)); + } + +#if (!ACPI_REDUCED_HARDWARE) + if (!AcpiGbl_ReducedHardware) + { + /* Install a user SCI handler */ + + Status = AeInstallSciHandler (); + ACPI_CHECK_OK (AeInstallSciHandler, Status); + + /* Install some fixed event handlers */ + + Status = AcpiInstallFixedEventHandler ( + ACPI_EVENT_GLOBAL, AeEventHandler, NULL); + ACPI_CHECK_OK (AcpiInstallFixedEventHandler, Status); + + Status = AcpiInstallFixedEventHandler ( + ACPI_EVENT_RTC, AeEventHandler, NULL); + ACPI_CHECK_OK (AcpiInstallFixedEventHandler, Status); + } +#endif /* !ACPI_REDUCED_HARDWARE */ + + AeMyContext.Connection = NULL; + AeMyContext.AccessLength = 0xA5; + + /* + * We will install a handler for each EC device, directly under the EC + * device definition. This is unlike the other handlers which we install + * at the root node. Also install memory and I/O handlers at any PCI + * devices. + */ + AeInstallDeviceHandlers (); + + /* + * Install handlers for some of the "device driver" address spaces + * such as SMBus, etc. + */ + AeInstallRegionHandlers (); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AeInstallEarlyHandlers + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install handlers for the AcpiExec utility. + * + * Notes: Don't install handler for PCI_Config, we want to use the + * default handler to exercise that code. + * + *****************************************************************************/ + +ACPI_STATUS +AeInstallEarlyHandlers ( + void) +{ + ACPI_STATUS Status; + ACPI_HANDLE Handle; + + + ACPI_FUNCTION_ENTRY (); + + + Status = AcpiInstallInterfaceHandler (AeInterfaceHandler); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install interface handler, %s\n", + AcpiFormatException (Status)); + } + + Status = AcpiInstallTableHandler (AeTableHandler, NULL); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install table handler, %s\n", + AcpiFormatException (Status)); + } + + Status = AcpiInstallExceptionHandler (AeExceptionHandler); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install exception handler, %s\n", + AcpiFormatException (Status)); + } + + /* Install global notify handlers */ + + Status = AcpiInstallNotifyHandler (ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, + AeSystemNotifyHandler, NULL); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install a global system notify handler, %s\n", + AcpiFormatException (Status)); + } + + Status = AcpiInstallNotifyHandler (ACPI_ROOT_OBJECT, ACPI_DEVICE_NOTIFY, + AeDeviceNotifyHandler, NULL); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install a global notify handler, %s\n", + AcpiFormatException (Status)); + } + + Status = AcpiGetHandle (NULL, "\\_SB", &Handle); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiInstallNotifyHandler (Handle, ACPI_SYSTEM_NOTIFY, + AeNotifyHandler1, NULL); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install a notify handler, %s\n", + AcpiFormatException (Status)); + } + + Status = AcpiRemoveNotifyHandler (Handle, ACPI_SYSTEM_NOTIFY, + AeNotifyHandler1); + if (ACPI_FAILURE (Status)) + { + printf ("Could not remove a notify handler, %s\n", + AcpiFormatException (Status)); + } + + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1, NULL); + ACPI_CHECK_OK (AcpiInstallNotifyHandler, Status); + + Status = AcpiRemoveNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1); + ACPI_CHECK_OK (AcpiRemoveNotifyHandler, Status); + +#if 0 + Status = AcpiInstallNotifyHandler (Handle, ACPI_ALL_NOTIFY, + AeNotifyHandler1, NULL); + if (ACPI_FAILURE (Status)) + { + printf ("Could not install a notify handler, %s\n", + AcpiFormatException (Status)); + } +#endif + + /* Install two handlers for _SB_ */ + + Status = AcpiInstallNotifyHandler (Handle, ACPI_SYSTEM_NOTIFY, + AeNotifyHandler1, ACPI_CAST_PTR (void, 0x01234567)); + + Status = AcpiInstallNotifyHandler (Handle, ACPI_SYSTEM_NOTIFY, + AeNotifyHandler2, ACPI_CAST_PTR (void, 0x89ABCDEF)); + + /* Attempt duplicate handler installation, should fail */ + + Status = AcpiInstallNotifyHandler (Handle, ACPI_SYSTEM_NOTIFY, + AeNotifyHandler1, ACPI_CAST_PTR (void, 0x77777777)); + + Status = AcpiAttachData (Handle, AeAttachedDataHandler, Handle); + ACPI_CHECK_OK (AcpiAttachData, Status); + + Status = AcpiDetachData (Handle, AeAttachedDataHandler); + ACPI_CHECK_OK (AcpiDetachData, Status); + + /* Test attach data at the root object */ + + Status = AcpiAttachData (ACPI_ROOT_OBJECT, AeAttachedDataHandler, + AcpiGbl_RootNode); + ACPI_CHECK_OK (AcpiAttachData, Status); + + Status = AcpiAttachData (ACPI_ROOT_OBJECT, AeAttachedDataHandler2, + AcpiGbl_RootNode); + ACPI_CHECK_OK (AcpiAttachData, Status); + + /* Test support for multiple attaches */ + + Status = AcpiAttachData (Handle, AeAttachedDataHandler, Handle); + ACPI_CHECK_OK (AcpiAttachData, Status); + + Status = AcpiAttachData (Handle, AeAttachedDataHandler2, Handle); + ACPI_CHECK_OK (AcpiAttachData, Status); + } + else + { + printf ("No _SB_ found, %s\n", AcpiFormatException (Status)); + } + + /* + * Install handlers that will override the default handlers for some of + * the space IDs. + */ + AeOverrideRegionHandlers (); + + /* + * Initialize the global Region Handler space + * MCW 3/23/00 + */ + AeRegions.NumberOfRegions = 0; + AeRegions.RegionList = NULL; + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aeinitfile.c b/third_party/lib/acpica/source/tools/acpiexec/aeinitfile.c new file mode 100644 index 000000000..c8ceb2069 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aeinitfile.c @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * Module Name: aeinitfile - Support for optional initialization file + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aecommon.h" +#include "acdispat.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("aeinitfile") + + +/* Local prototypes */ + +static void +AeDoOneOverride ( + char *Pathname, + char *ValueString, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState); + + +#define AE_FILE_BUFFER_SIZE 512 + +static char LineBuffer[AE_FILE_BUFFER_SIZE]; +static char NameBuffer[AE_FILE_BUFFER_SIZE]; +static char ValueBuffer[AE_FILE_BUFFER_SIZE]; +static FILE *InitFile; + + +/****************************************************************************** + * + * FUNCTION: AeOpenInitializationFile + * + * PARAMETERS: Filename - Path to the init file + * + * RETURN: Status + * + * DESCRIPTION: Open the initialization file for the -fi option + * + *****************************************************************************/ + +int +AeOpenInitializationFile ( + char *Filename) +{ + + InitFile = fopen (Filename, "r"); + if (!InitFile) + { + perror ("Could not open initialization file"); + return (-1); + } + + AcpiOsPrintf ("Opened initialization file [%s]\n", Filename); + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: AeDoObjectOverrides + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Read the initialization file and perform all overrides + * + * NOTE: The format of the file is multiple lines, each of format: + * + * + *****************************************************************************/ + +void +AeDoObjectOverrides ( + void) +{ + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_WALK_STATE *WalkState; + int i; + + + if (!InitFile) + { + return; + } + + /* Create needed objects to be reused for each init entry */ + + ObjDesc = AcpiUtCreateIntegerObject (0); + WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); + NameBuffer[0] = '\\'; + + /* Read the entire file line-by-line */ + + while (fgets (LineBuffer, AE_FILE_BUFFER_SIZE, InitFile) != NULL) + { + if (sscanf (LineBuffer, "%s %s\n", + &NameBuffer[1], ValueBuffer) != 2) + { + goto CleanupAndExit; + } + + /* Add a root prefix if not present in the string */ + + i = 0; + if (NameBuffer[1] == '\\') + { + i = 1; + } + + AeDoOneOverride (&NameBuffer[i], ValueBuffer, ObjDesc, WalkState); + } + + /* Cleanup */ + +CleanupAndExit: + fclose (InitFile); + AcpiDsDeleteWalkState (WalkState); + AcpiUtRemoveReference (ObjDesc); +} + + +/****************************************************************************** + * + * FUNCTION: AeDoOneOverride + * + * PARAMETERS: Pathname - AML namepath + * ValueString - New integer value to be stored + * ObjDesc - Descriptor with integer override value + * WalkState - Used for the Store operation + * + * RETURN: None + * + * DESCRIPTION: Perform an overrided for a single namespace object + * + *****************************************************************************/ + +static void +AeDoOneOverride ( + char *Pathname, + char *ValueString, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + ACPI_HANDLE Handle; + ACPI_STATUS Status; + UINT64 Value; + + + AcpiOsPrintf ("Value Override: %s, ", Pathname); + + /* + * Get the namespace node associated with the override + * pathname from the init file. + */ + Status = AcpiGetHandle (NULL, Pathname, &Handle); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s\n", AcpiFormatException (Status)); + return; + } + + /* Extract the 64-bit integer */ + + Status = AcpiUtStrtoul64 (ValueString, 0, &Value); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s %s\n", ValueString, + AcpiFormatException (Status)); + return; + } + + ObjDesc->Integer.Value = Value; + + /* + * At the point this function is called, the namespace is fully + * built and initialized. We can simply store the new object to + * the target node. + */ + AcpiExEnterInterpreter (); + Status = AcpiExStore (ObjDesc, Handle, WalkState); + AcpiExExitInterpreter (); + + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s\n", AcpiFormatException (Status)); + return; + } + + AcpiOsPrintf ("New value: 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Value)); +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aemain.c b/third_party/lib/acpica/source/tools/acpiexec/aemain.c new file mode 100644 index 000000000..a182a4377 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aemain.c @@ -0,0 +1,731 @@ +/****************************************************************************** + * + * Module Name: aemain - Main routine for the AcpiExec utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aecommon.h" +#include "errno.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("aemain") + + +/* + * Main routine for the ACPI user-space execution utility. + * + * Portability note: The utility depends upon the host for command-line + * wildcard support - it is not implemented locally. For example: + * + * Linux/Unix systems: Shell expands wildcards automatically. + * + * Windows: The setargv.obj module must be linked in to automatically + * expand wildcards. + */ +extern BOOLEAN AcpiGbl_DebugTimeout; + +/* Local prototypes */ + +static int +AeDoOptions ( + int argc, + char **argv); + +static ACPI_STATUS +AcpiDbRunBatchMode ( + void); + + +#define AE_BUFFER_SIZE 1024 +#define ASL_MAX_FILES 256 + +/* Execution modes */ + +#define AE_MODE_COMMAND_LOOP 0 /* Normal command execution loop */ +#define AE_MODE_BATCH_MULTIPLE 1 /* -b option to execute a command line */ +#define AE_MODE_BATCH_SINGLE 2 /* -m option to execute a single control method */ + + +/* Globals */ + +UINT8 AcpiGbl_RegionFillValue = 0; +BOOLEAN AcpiGbl_IgnoreErrors = FALSE; +BOOLEAN AcpiGbl_DbOpt_NoRegionSupport = FALSE; +UINT8 AcpiGbl_UseHwReducedFadt = FALSE; +BOOLEAN AcpiGbl_DoInterfaceTests = FALSE; +BOOLEAN AcpiGbl_LoadTestTables = FALSE; +BOOLEAN AcpiGbl_AeLoadOnly = FALSE; +static UINT8 AcpiGbl_ExecutionMode = AE_MODE_COMMAND_LOOP; +static char BatchBuffer[AE_BUFFER_SIZE]; /* Batch command buffer */ + +#define ACPIEXEC_NAME "AML Execution/Debug Utility" +#define AE_SUPPORTED_OPTIONS "?b:d:e:f^ghi:lm^rv^:x:" + + +/* Stubs for the disassembler */ + +void +MpSaveGpioInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + UINT32 PinCount, + UINT16 *PinList, + char *DeviceName) +{ +} + +void +MpSaveSerialInfo ( + ACPI_PARSE_OBJECT *Op, + AML_RESOURCE *Resource, + char *DeviceName) +{ +} + + +/****************************************************************************** + * + * FUNCTION: usage + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Print a usage message + * + *****************************************************************************/ + +static void +usage ( + void) +{ + + ACPI_USAGE_HEADER ("acpiexec [options] AMLfile1 AMLfile2 ..."); + + ACPI_OPTION ("-b \"CommandLine\"", "Batch mode command line execution (cmd1;cmd2;...)"); + ACPI_OPTION ("-h -?", "Display this help message"); + ACPI_OPTION ("-m [Method]", "Batch mode method execution. Default=MAIN"); + printf ("\n"); + + ACPI_OPTION ("-da", "Disable method abort on error"); + ACPI_OPTION ("-di", "Disable execution of STA/INI methods during init"); + ACPI_OPTION ("-do", "Disable Operation Region address simulation"); + ACPI_OPTION ("-dr", "Disable repair of method return values"); + ACPI_OPTION ("-ds", "Disable method auto-serialization"); + ACPI_OPTION ("-dt", "Disable allocation tracking (performance)"); + printf ("\n"); + + ACPI_OPTION ("-ed", "Enable timer output for Debug Object"); + ACPI_OPTION ("-ef", "Enable display of final memory statistics"); + ACPI_OPTION ("-ei", "Enable additional tests for ACPICA interfaces"); + ACPI_OPTION ("-el", "Enable loading of additional test tables"); + ACPI_OPTION ("-em", "Enable grouping of module-level code"); + ACPI_OPTION ("-es", "Enable Interpreter Slack Mode"); + ACPI_OPTION ("-et", "Enable debug semaphore timeout"); + printf ("\n"); + + ACPI_OPTION ("-fi ", "Specify namespace initialization file"); + ACPI_OPTION ("-fv ", "Operation Region initialization fill value"); + printf ("\n"); + + ACPI_OPTION ("-i ", "Maximum iterations for AML while loops"); + ACPI_OPTION ("-l", "Load tables and namespace only"); + ACPI_OPTION ("-r", "Use hardware-reduced FADT V5"); + ACPI_OPTION ("-v", "Display version information"); + ACPI_OPTION ("-vi", "Verbose initialization output"); + ACPI_OPTION ("-vr", "Verbose region handler output"); + ACPI_OPTION ("-x ", "Debug output level"); + + printf ("\n From within the interactive mode, use '?' or \"help\" to see\n" + " a list of available AML Debugger commands\n"); +} + + +/****************************************************************************** + * + * FUNCTION: AeDoOptions + * + * PARAMETERS: argc/argv - Standard argc/argv + * + * RETURN: Status + * + * DESCRIPTION: Command line option processing + * + *****************************************************************************/ + +static int +AeDoOptions ( + int argc, + char **argv) +{ + int j; + UINT32 Temp; + + + while ((j = AcpiGetopt (argc, argv, AE_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch (j) + { + case 'b': + + if (strlen (AcpiGbl_Optarg) > (AE_BUFFER_SIZE -1)) + { + printf ("**** The length of command line (%u) exceeded maximum (%u)\n", + (UINT32) strlen (AcpiGbl_Optarg), (AE_BUFFER_SIZE -1)); + return (-1); + } + AcpiGbl_ExecutionMode = AE_MODE_BATCH_MULTIPLE; + strcpy (BatchBuffer, AcpiGbl_Optarg); + break; + + case 'd': + + switch (AcpiGbl_Optarg[0]) + { + case 'a': + + AcpiGbl_IgnoreErrors = TRUE; + break; + + case 'i': + + AcpiGbl_DbOpt_NoIniMethods = TRUE; + break; + + case 'o': + + AcpiGbl_DbOpt_NoRegionSupport = TRUE; + break; + + case 'r': + + AcpiGbl_DisableAutoRepair = TRUE; + break; + + case 's': + + AcpiGbl_AutoSerializeMethods = FALSE; + break; + + case 't': + + #ifdef ACPI_DBG_TRACK_ALLOCATIONS + AcpiGbl_DisableMemTracking = TRUE; + #endif + break; + + default: + + printf ("Unknown option: -d%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'e': + + switch (AcpiGbl_Optarg[0]) + { + case 'd': + + AcpiGbl_DisplayDebugTimer = TRUE; + break; + + case 'f': + + #ifdef ACPI_DBG_TRACK_ALLOCATIONS + AcpiGbl_DisplayFinalMemStats = TRUE; + #endif + break; + + case 'i': + + AcpiGbl_DoInterfaceTests = TRUE; + break; + + case 'l': + + AcpiGbl_LoadTestTables = TRUE; + break; + + case 'm': + + AcpiGbl_GroupModuleLevelCode = TRUE; + break; + + case 's': + + AcpiGbl_EnableInterpreterSlack = TRUE; + printf ("Enabling AML Interpreter slack mode\n"); + break; + + case 't': + + AcpiGbl_DebugTimeout = TRUE; + break; + + default: + + printf ("Unknown option: -e%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'f': + + switch (AcpiGbl_Optarg[0]) + { + case 'v': /* -fv: region fill value */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + AcpiGbl_RegionFillValue = (UINT8) strtoul (AcpiGbl_Optarg, NULL, 0); + break; + + case 'i': /* -fi: specify initialization file */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + if (AeOpenInitializationFile (AcpiGbl_Optarg)) + { + return (-1); + } + break; + + default: + + printf ("Unknown option: -f%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'g': + + AcpiGbl_DbFilename = NULL; + break; + + case 'h': + case '?': + + usage(); + return (1); + + case 'i': + + Temp = strtoul (AcpiGbl_Optarg, NULL, 0); + if (!Temp || (Temp > ACPI_UINT16_MAX)) + { + printf ("%s: Invalid max loops value\n", AcpiGbl_Optarg); + return (-1); + } + + AcpiGbl_MaxLoopIterations = (UINT16) Temp; + printf ("Max Loop Iterations is %u (0x%X)\n", + AcpiGbl_MaxLoopIterations, AcpiGbl_MaxLoopIterations); + break; + + case 'l': + + AcpiGbl_AeLoadOnly = TRUE; + break; + + case 'm': + + AcpiGbl_ExecutionMode = AE_MODE_BATCH_SINGLE; + switch (AcpiGbl_Optarg[0]) + { + case '^': + + strcpy (BatchBuffer, "MAIN"); + break; + + default: + + strcpy (BatchBuffer, AcpiGbl_Optarg); + break; + } + break; + + case 'r': + + AcpiGbl_UseHwReducedFadt = TRUE; + printf ("Using ACPI 5.0 Hardware Reduced Mode via version 5 FADT\n"); + break; + + case 'v': + + switch (AcpiGbl_Optarg[0]) + { + case '^': /* -v: (Version): signon already emitted, just exit */ + + (void) AcpiOsTerminate (); + return (1); + + case 'i': + + AcpiDbgLevel |= ACPI_LV_INIT_NAMES; + break; + + case 'r': + + AcpiGbl_DisplayRegionAccess = TRUE; + break; + + default: + + printf ("Unknown option: -v%s\n", AcpiGbl_Optarg); + return (-1); + } + break; + + case 'x': + + AcpiDbgLevel = strtoul (AcpiGbl_Optarg, NULL, 0); + AcpiGbl_DbConsoleDebugLevel = AcpiDbgLevel; + printf ("Debug Level: 0x%8.8X\n", AcpiDbgLevel); + break; + + default: + + usage(); + return (-1); + } + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * PARAMETERS: argc, argv + * + * RETURN: Status + * + * DESCRIPTION: Main routine for AcpiExec utility + * + *****************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char **argv) +{ + ACPI_NEW_TABLE_DESC *ListHead = NULL; + ACPI_STATUS Status; + UINT32 InitFlags; + int ExitCode = 0; + + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + signal (SIGINT, AeCtrlCHandler); + + /* Init debug globals */ + + AcpiDbgLevel = ACPI_NORMAL_DEFAULT; + AcpiDbgLayer = 0xFFFFFFFF; + + /* Init ACPICA and start debugger thread */ + + AcpiGbl_OverrideDefaultRegionHandlers = TRUE; + Status = AcpiInitializeSubsystem (); + ACPI_CHECK_OK (AcpiInitializeSubsystem, Status); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* ACPICA runtime configuration */ + + AcpiGbl_MaxLoopIterations = 400; + + + /* Initialize the AML debugger */ + + Status = AcpiInitializeDebugger (); + ACPI_CHECK_OK (AcpiInitializeDebugger, Status); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + printf (ACPI_COMMON_SIGNON (ACPIEXEC_NAME)); + if (argc < 2) + { + usage (); + (void) AcpiOsTerminate (); + return (0); + } + + /* Get the command line options */ + + ExitCode = AeDoOptions (argc, argv); + if (ExitCode) + { + if (ExitCode > 0) + { + ExitCode = 0; + } + + goto ErrorExit; + } + + /* The remaining arguments are filenames for ACPI tables */ + + if (!argv[AcpiGbl_Optind]) + { + goto EnterDebugger; + } + + AcpiGbl_CstyleDisassembly = FALSE; /* Not supported for AcpiExec */ + + /* Get each of the ACPI table files on the command line */ + + while (argv[AcpiGbl_Optind]) + { + /* Get all ACPI AML tables in this file */ + + Status = AcGetAllTablesFromFile (argv[AcpiGbl_Optind], + ACPI_GET_ONLY_AML_TABLES, &ListHead); + if (ACPI_FAILURE (Status)) + { + ExitCode = -1; + goto ErrorExit; + } + + AcpiGbl_Optind++; + } + + printf ("\n"); + + /* Build a local RSDT with all tables and let ACPICA process the RSDT */ + + Status = AeBuildLocalTables (ListHead); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* Install all of the ACPI tables */ + + Status = AeInstallTables (); + + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not install ACPI tables, %s\n", + AcpiFormatException (Status)); + goto EnterDebugger; + } + + /* + * Install most of the handlers (Regions, Notify, Table, etc.) + * Override the default region handlers, especially SystemMemory, + * which is simulated in this utility. + */ + Status = AeInstallEarlyHandlers (); + if (ACPI_FAILURE (Status)) + { + goto EnterDebugger; + } + + /* Setup initialization flags for ACPICA */ + + InitFlags = (ACPI_NO_HANDLER_INIT | ACPI_NO_ACPI_ENABLE); + if (AcpiGbl_DbOpt_NoIniMethods) + { + InitFlags |= (ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT); + } + + /* + * Main initialization for ACPICA subsystem + * TBD: Need a way to call this after the ACPI table "LOAD" command + */ + Status = AcpiEnableSubsystem (InitFlags); + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not EnableSubsystem, %s\n", + AcpiFormatException (Status)); + goto EnterDebugger; + } + + Status = AeLoadTables (); + + /* + * Exit namespace initialization for the "load namespace only" option. + * No control methods will be executed. However, still enter the + * the debugger. + */ + if (AcpiGbl_AeLoadOnly) + { + goto EnterDebugger; + } + + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not load ACPI tables, %s\n", + AcpiFormatException (Status)); + goto EnterDebugger; + } + + /* + * Install handlers for "device driver" space IDs (EC,SMBus, etc.) + * and fixed event handlers + */ + AeInstallLateHandlers (); + + /* Finish the ACPICA initialization */ + + Status = AcpiInitializeObjects (InitFlags); + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not InitializeObjects, %s\n", + AcpiFormatException (Status)); + goto EnterDebugger; + } + + AeMiscellaneousTests (); + + +EnterDebugger: + + /* Exit if error above and we are in one of the batch modes */ + + if (ACPI_FAILURE (Status) && (AcpiGbl_ExecutionMode > 0)) + { + goto ErrorExit; + } + + /* Run a batch command or enter the command loop */ + + switch (AcpiGbl_ExecutionMode) + { + default: + case AE_MODE_COMMAND_LOOP: + + AcpiDbUserCommands (ACPI_DEBUGGER_COMMAND_PROMPT, NULL); + break; + + case AE_MODE_BATCH_MULTIPLE: + + AcpiDbRunBatchMode (); + break; + + case AE_MODE_BATCH_SINGLE: + + AcpiDbExecute (BatchBuffer, NULL, NULL, EX_NO_SINGLE_STEP); + + /* Shut down the debugger */ + + AcpiTerminateDebugger (); + Status = AcpiTerminate (); + break; + } + + (void) AcpiOsTerminate (); + return (0); + + +ErrorExit: + (void) AcpiOsTerminate (); + return (ExitCode); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiDbRunBatchMode + * + * PARAMETERS: BatchCommandLine - A semicolon separated list of commands + * to be executed. + * Use only commas to separate elements of + * particular command. + * RETURN: Status + * + * DESCRIPTION: For each command of list separated by ';' prepare the command + * buffer and pass it to AcpiDbCommandDispatch. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiDbRunBatchMode ( + void) +{ + ACPI_STATUS Status; + char *Ptr = BatchBuffer; + char *Cmd = Ptr; + UINT8 Run = 0; + + + AcpiGbl_MethodExecuting = FALSE; + AcpiGbl_StepToNextCall = FALSE; + + while (*Ptr) + { + if (*Ptr == ',') + { + /* Convert commas to spaces */ + *Ptr = ' '; + } + else if (*Ptr == ';') + { + *Ptr = '\0'; + Run = 1; + } + + Ptr++; + + if (Run || (*Ptr == '\0')) + { + (void) AcpiDbCommandDispatch (Cmd, NULL, NULL); + Run = 0; + Cmd = Ptr; + } + } + + /* Shut down the debugger */ + + AcpiTerminateDebugger (); + Status = AcpiTerminate (); + return (Status); +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aeregion.c b/third_party/lib/acpica/source/tools/acpiexec/aeregion.c new file mode 100644 index 000000000..27ab7e362 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aeregion.c @@ -0,0 +1,924 @@ +/****************************************************************************** + * + * Module Name: aeregion - Operation region support for acpiexec + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aecommon.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("aeregion") + + +/* Local prototypes */ + +static ACPI_STATUS +AeRegionInit ( + ACPI_HANDLE RegionHandle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +static ACPI_STATUS +AeInstallEcHandler ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + +static ACPI_STATUS +AeInstallPciHandler ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue); + + +static AE_DEBUG_REGIONS AeRegions; +BOOLEAN AcpiGbl_DisplayRegionAccess = FALSE; +ACPI_CONNECTION_INFO AeMyContext; + + +/* + * We will override some of the default region handlers, especially + * the SystemMemory handler, which must be implemented locally. + * These handlers are installed "early" - before any _REG methods + * are executed - since they are special in the sense that the ACPI spec + * declares that they must "always be available". Cannot override the + * DataTable region handler either -- needed for test execution. + * + * NOTE: The local region handler will simulate access to these address + * spaces by creating a memory buffer behind each operation region. + */ +static ACPI_ADR_SPACE_TYPE DefaultSpaceIdList[] = +{ + ACPI_ADR_SPACE_SYSTEM_MEMORY, + ACPI_ADR_SPACE_SYSTEM_IO, + ACPI_ADR_SPACE_PCI_CONFIG, + ACPI_ADR_SPACE_EC +}; + +/* + * We will install handlers for some of the various address space IDs. + * Test one user-defined address space (used by aslts). + */ +#define ACPI_ADR_SPACE_USER_DEFINED1 0x80 +#define ACPI_ADR_SPACE_USER_DEFINED2 0xE4 + +static ACPI_ADR_SPACE_TYPE SpaceIdList[] = +{ + ACPI_ADR_SPACE_SMBUS, + ACPI_ADR_SPACE_CMOS, + ACPI_ADR_SPACE_PCI_BAR_TARGET, + ACPI_ADR_SPACE_IPMI, + ACPI_ADR_SPACE_GPIO, + ACPI_ADR_SPACE_GSBUS, + ACPI_ADR_SPACE_FIXED_HARDWARE, + ACPI_ADR_SPACE_USER_DEFINED1, + ACPI_ADR_SPACE_USER_DEFINED2 +}; + + +/****************************************************************************** + * + * FUNCTION: AeRegionInit + * + * PARAMETERS: Region init handler + * + * RETURN: Status + * + * DESCRIPTION: Opregion init function. + * + *****************************************************************************/ + +static ACPI_STATUS +AeRegionInit ( + ACPI_HANDLE RegionHandle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + + if (Function == ACPI_REGION_DEACTIVATE) + { + *RegionContext = NULL; + } + else + { + *RegionContext = RegionHandle; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AeOverrideRegionHandlers + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Override the default region handlers for memory, i/o, and + * pci_config. Also install a handler for EC. This is part of + * the "install early handlers" functionality. + * + *****************************************************************************/ + +void +AeOverrideRegionHandlers ( + void) +{ + UINT32 i; + ACPI_STATUS Status; + + /* + * Install handlers that will override the default handlers for some of + * the space IDs. + */ + for (i = 0; i < ACPI_ARRAY_LENGTH (DefaultSpaceIdList); i++) + { + /* Install handler at the root object */ + + Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT, + DefaultSpaceIdList[i], AeRegionHandler, + AeRegionInit, &AeMyContext); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an OpRegion handler for %s space(%u)", + AcpiUtGetRegionName ((UINT8) DefaultSpaceIdList[i]), + DefaultSpaceIdList[i])); + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AeInstallRegionHandlers + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Install handlers for the address spaces other than memory, + * i/o, and pci_config. + * + *****************************************************************************/ + +void +AeInstallRegionHandlers ( + void) +{ + UINT32 i; + ACPI_STATUS Status; + + /* + * Install handlers for some of the "device driver" address spaces + * such as SMBus, etc. + */ + for (i = 0; i < ACPI_ARRAY_LENGTH (SpaceIdList); i++) + { + /* Install handler at the root object */ + + Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT, + SpaceIdList[i], AeRegionHandler, + AeRegionInit, &AeMyContext); + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an OpRegion handler for %s space(%u)", + AcpiUtGetRegionName((UINT8) SpaceIdList[i]), SpaceIdList[i])); + return; + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AeInstallDeviceHandlers, + * AeInstallEcHandler, + * AeInstallPciHandler + * + * PARAMETERS: ACPI_WALK_NAMESPACE callback + * + * RETURN: Status + * + * DESCRIPTION: Walk entire namespace, install a handler for every EC + * and PCI device found. + * + ******************************************************************************/ + +static ACPI_STATUS +AeInstallEcHandler ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_STATUS Status; + + + /* Install the handler for this EC device */ + + Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_EC, + AeRegionHandler, AeRegionInit, &AeMyContext); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an OpRegion handler for EC device (%p)", + ObjHandle)); + } + + return (Status); +} + + +static ACPI_STATUS +AeInstallPciHandler ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Context, + void **ReturnValue) +{ + ACPI_STATUS Status; + + + /* Install memory and I/O handlers for the PCI device */ + + Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_IO, + AeRegionHandler, AeRegionInit, &AeMyContext); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an OpRegion handler for PCI device (%p)", + ObjHandle)); + } + + Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_MEMORY, + AeRegionHandler, AeRegionInit, &AeMyContext); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not install an OpRegion handler for PCI device (%p)", + ObjHandle)); + } + + return (AE_CTRL_TERMINATE); +} + + +ACPI_STATUS +AeInstallDeviceHandlers ( + void) +{ + + /* Find all Embedded Controller devices */ + + AcpiGetDevices ("PNP0C09", AeInstallEcHandler, NULL, NULL); + + /* Install a PCI handler */ + + AcpiGetDevices ("PNP0A08", AeInstallPciHandler, NULL, NULL); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AeRegionHandler + * + * PARAMETERS: Standard region handler parameters + * + * RETURN: Status + * + * DESCRIPTION: Test handler - Handles some dummy regions via memory that can + * be manipulated in Ring 3. Simulates actual reads and writes. + * + *****************************************************************************/ + +ACPI_STATUS +AeRegionHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + + ACPI_OPERAND_OBJECT *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext); + UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Value); + UINT8 *OldBuffer; + UINT8 *NewBuffer; + ACPI_PHYSICAL_ADDRESS BaseAddress; + ACPI_PHYSICAL_ADDRESS BaseAddressEnd; + ACPI_PHYSICAL_ADDRESS RegionAddress; + ACPI_PHYSICAL_ADDRESS RegionAddressEnd; + ACPI_SIZE Length; + BOOLEAN BufferExists; + BOOLEAN BufferResize; + AE_REGION *RegionElement; + void *BufferValue; + ACPI_STATUS Status; + UINT32 ByteWidth; + UINT32 RegionLength; + UINT32 i; + UINT8 SpaceId; + ACPI_CONNECTION_INFO *MyContext; + UINT32 Value1; + UINT32 Value2; + ACPI_RESOURCE *Resource; + + + ACPI_FUNCTION_NAME (AeRegionHandler); + + /* + * If the object is not a region, simply return + */ + if (RegionObject->Region.Type != ACPI_TYPE_REGION) + { + return (AE_OK); + } + + /* Check that we actually got back our context parameter */ + + if (HandlerContext != &AeMyContext) + { + printf ("Region handler received incorrect context %p, should be %p\n", + HandlerContext, &AeMyContext); + } + + MyContext = ACPI_CAST_PTR (ACPI_CONNECTION_INFO, HandlerContext); + + /* + * Find the region's address space and length before searching + * the linked list. + */ + BaseAddress = RegionObject->Region.Address; + Length = (ACPI_SIZE) RegionObject->Region.Length; + SpaceId = RegionObject->Region.SpaceId; + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Operation Region request on %s at 0x%X\n", + AcpiUtGetRegionName (RegionObject->Region.SpaceId), + (UINT32) Address)); + + /* + * Region support can be disabled with the -do option. + * We use this to support dynamically loaded tables where we pass a valid + * address to the AML. + */ + if (AcpiGbl_DbOpt_NoRegionSupport) + { + BufferValue = ACPI_TO_POINTER (Address); + ByteWidth = (BitWidth / 8); + + if (BitWidth % 8) + { + ByteWidth += 1; + } + goto DoFunction; + } + + switch (SpaceId) + { + case ACPI_ADR_SPACE_SYSTEM_IO: + /* + * For I/O space, exercise the port validation + * Note: ReadPort currently always returns all ones, length=BitLength + */ + switch (Function & ACPI_IO_MASK) + { + case ACPI_READ: + + if (BitWidth == 64) + { + /* Split the 64-bit request into two 32-bit requests */ + + Status = AcpiHwReadPort (Address, &Value1, 32); + ACPI_CHECK_OK (AcpiHwReadPort, Status); + Status = AcpiHwReadPort (Address+4, &Value2, 32); + ACPI_CHECK_OK (AcpiHwReadPort, Status); + + *Value = Value1 | ((UINT64) Value2 << 32); + } + else + { + Status = AcpiHwReadPort (Address, &Value1, BitWidth); + ACPI_CHECK_OK (AcpiHwReadPort, Status); + *Value = (UINT64) Value1; + } + break; + + case ACPI_WRITE: + + if (BitWidth == 64) + { + /* Split the 64-bit request into two 32-bit requests */ + + Status = AcpiHwWritePort (Address, ACPI_LODWORD (*Value), 32); + ACPI_CHECK_OK (AcpiHwWritePort, Status); + Status = AcpiHwWritePort (Address+4, ACPI_HIDWORD (*Value), 32); + ACPI_CHECK_OK (AcpiHwWritePort, Status); + } + else + { + Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth); + ACPI_CHECK_OK (AcpiHwWritePort, Status); + } + break; + + default: + + Status = AE_BAD_PARAMETER; + break; + } + + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Now go ahead and simulate the hardware */ + break; + + /* + * SMBus and GenericSerialBus support the various bidirectional + * protocols. + */ + case ACPI_ADR_SPACE_SMBUS: + case ACPI_ADR_SPACE_GSBUS: /* ACPI 5.0 */ + + Length = 0; + + switch (Function & ACPI_IO_MASK) + { + case ACPI_READ: + + switch (Function >> 16) + { + case AML_FIELD_ATTRIB_QUICK: + + Length = 0; + break; + + case AML_FIELD_ATTRIB_SEND_RCV: + case AML_FIELD_ATTRIB_BYTE: + + Length = 1; + break; + + case AML_FIELD_ATTRIB_WORD: + case AML_FIELD_ATTRIB_WORD_CALL: + + Length = 2; + break; + + case AML_FIELD_ATTRIB_BLOCK: + case AML_FIELD_ATTRIB_BLOCK_CALL: + + Length = 32; + break; + + case AML_FIELD_ATTRIB_MULTIBYTE: + case AML_FIELD_ATTRIB_RAW_BYTES: + case AML_FIELD_ATTRIB_RAW_PROCESS: + + Length = MyContext->AccessLength; + break; + + default: + + break; + } + break; + + case ACPI_WRITE: + + switch (Function >> 16) + { + case AML_FIELD_ATTRIB_QUICK: + case AML_FIELD_ATTRIB_SEND_RCV: + case AML_FIELD_ATTRIB_BYTE: + case AML_FIELD_ATTRIB_WORD: + case AML_FIELD_ATTRIB_BLOCK: + + Length = 0; + break; + + case AML_FIELD_ATTRIB_WORD_CALL: + Length = 2; + break; + + case AML_FIELD_ATTRIB_BLOCK_CALL: + Length = 32; + break; + + case AML_FIELD_ATTRIB_MULTIBYTE: + case AML_FIELD_ATTRIB_RAW_BYTES: + case AML_FIELD_ATTRIB_RAW_PROCESS: + + Length = MyContext->AccessLength; + break; + + default: + + break; + } + break; + + default: + + break; + } + + if (AcpiGbl_DisplayRegionAccess) + { + AcpiOsPrintf ("AcpiExec: %s " + "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X", + AcpiUtGetRegionName (SpaceId), + (Function & ACPI_IO_MASK) ? "Write" : "Read ", + (UINT32) (Function >> 16), + (UINT32) Address, (UINT32) BaseAddress, + Length, BitWidth, Buffer[1]); + + /* GenericSerialBus has a Connection() parameter */ + + if (SpaceId == ACPI_ADR_SPACE_GSBUS) + { + Status = AcpiBufferToResource (MyContext->Connection, + MyContext->Length, &Resource); + + AcpiOsPrintf (" [AccLen %.2X Conn %p]", + MyContext->AccessLength, MyContext->Connection); + } + AcpiOsPrintf ("\n"); + } + + /* Setup the return buffer. Note: ASLTS depends on these fill values */ + + for (i = 0; i < Length; i++) + { + Buffer[i+2] = (UINT8) (0xA0 + i); + } + + Buffer[0] = 0x7A; + Buffer[1] = (UINT8) Length; + return (AE_OK); + + + case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */ + + if (AcpiGbl_DisplayRegionAccess) + { + AcpiOsPrintf ("AcpiExec: IPMI " + "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X\n", + (Function & ACPI_IO_MASK) ? "Write" : "Read ", + (UINT32) (Function >> 16), (UINT32) Address, (UINT32) BaseAddress, + Length, BitWidth, Buffer[1]); + } + + /* + * Regardless of a READ or WRITE, this handler is passed a 66-byte + * buffer in which to return the IPMI status/length/data. + * + * Return some example data to show use of the bidirectional buffer + */ + Buffer[0] = 0; /* Status byte */ + Buffer[1] = 64; /* Return buffer data length */ + Buffer[2] = 0; /* Completion code */ + Buffer[3] = 0; /* Reserved */ + + /* + * Fill the 66-byte buffer with the return data. + * Note: ASLTS depends on these fill values. + */ + for (i = 4; i < 66; i++) + { + Buffer[i] = (UINT8) (i); + } + return (AE_OK); + + /* + * GPIO has some special semantics: + * 1) Address is the pin number index into the Connection() pin list + * 2) BitWidth is the actual number of bits (pins) defined by the field + */ + case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */ + + if (AcpiGbl_DisplayRegionAccess) + { + AcpiOsPrintf ("AcpiExec: GPIO " + "%s: Addr %.4X Width %X Conn %p\n", + (Function & ACPI_IO_MASK) ? "Write" : "Read ", + (UINT32) Address, BitWidth, MyContext->Connection); + } + return (AE_OK); + + default: + break; + } + + /* + * Search through the linked list for this region's buffer + */ + BufferExists = FALSE; + BufferResize = FALSE; + RegionElement = AeRegions.RegionList; + + if (AeRegions.NumberOfRegions) + { + BaseAddressEnd = BaseAddress + Length - 1; + while (!BufferExists && RegionElement) + { + RegionAddress = RegionElement->Address; + RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1; + RegionLength = RegionElement->Length; + + /* + * Overlapping Region Support + * + * While searching through the region buffer list, determine if an + * overlap exists between the requested buffer space and the current + * RegionElement space. If there is an overlap then replace the old + * buffer with a new buffer of increased size before continuing to + * do the read or write + */ + if (RegionElement->SpaceId != SpaceId || + BaseAddressEnd < RegionAddress || + BaseAddress > RegionAddressEnd) + { + /* + * Requested buffer is outside of the current RegionElement + * bounds + */ + RegionElement = RegionElement->NextRegion; + } + else + { + /* + * Some amount of buffer space sharing exists. There are 4 cases + * to consider: + * + * 1. Right overlap + * 2. Left overlap + * 3. Left and right overlap + * 4. Fully contained - no resizing required + */ + BufferExists = TRUE; + + if ((BaseAddress >= RegionAddress) && + (BaseAddress <= RegionAddressEnd) && + (BaseAddressEnd > RegionAddressEnd)) + { + /* Right overlap */ + + RegionElement->Length = (UINT32) (BaseAddress - + RegionAddress + Length); + BufferResize = TRUE; + } + + else if ((BaseAddressEnd >= RegionAddress) && + (BaseAddressEnd <= RegionAddressEnd) && + (BaseAddress < RegionAddress)) + { + /* Left overlap */ + + RegionElement->Address = BaseAddress; + RegionElement->Length = (UINT32) (RegionAddress - + BaseAddress + RegionElement->Length); + BufferResize = TRUE; + } + + else if ((BaseAddress < RegionAddress) && + (BaseAddressEnd > RegionAddressEnd)) + { + /* Left and right overlap */ + + RegionElement->Address = BaseAddress; + RegionElement->Length = Length; + BufferResize = TRUE; + } + + /* + * only remaining case is fully contained for which we don't + * need to do anything + */ + if (BufferResize) + { + NewBuffer = AcpiOsAllocate (RegionElement->Length); + if (!NewBuffer) + { + return (AE_NO_MEMORY); + } + + OldBuffer = RegionElement->Buffer; + RegionElement->Buffer = NewBuffer; + NewBuffer = NULL; + + /* Initialize the region with the default fill value */ + + memset (RegionElement->Buffer, + AcpiGbl_RegionFillValue, RegionElement->Length); + + /* + * Get BufferValue to point (within the new buffer) to the + * base address of the old buffer + */ + BufferValue = (UINT8 *) RegionElement->Buffer + + (UINT64) RegionAddress - + (UINT64) RegionElement->Address; + + /* + * Copy the old buffer to its same location within the new + * buffer + */ + memcpy (BufferValue, OldBuffer, RegionLength); + AcpiOsFree (OldBuffer); + } + } + } + } + + /* + * If the Region buffer does not exist, create it now + */ + if (!BufferExists) + { + /* Do the memory allocations first */ + + RegionElement = AcpiOsAllocate (sizeof (AE_REGION)); + if (!RegionElement) + { + return (AE_NO_MEMORY); + } + + RegionElement->Buffer = AcpiOsAllocate (Length); + if (!RegionElement->Buffer) + { + AcpiOsFree (RegionElement); + return (AE_NO_MEMORY); + } + + /* Initialize the region with the default fill value */ + + memset (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length); + + RegionElement->Address = BaseAddress; + RegionElement->Length = Length; + RegionElement->SpaceId = SpaceId; + RegionElement->NextRegion = NULL; + + /* + * Increment the number of regions and put this one + * at the head of the list as it will probably get accessed + * more often anyway. + */ + AeRegions.NumberOfRegions += 1; + + if (AeRegions.RegionList) + { + RegionElement->NextRegion = AeRegions.RegionList; + } + + AeRegions.RegionList = RegionElement; + } + + /* Calculate the size of the memory copy */ + + ByteWidth = (BitWidth / 8); + + if (BitWidth % 8) + { + ByteWidth += 1; + } + + /* + * The buffer exists and is pointed to by RegionElement. + * We now need to verify the request is valid and perform the operation. + * + * NOTE: RegionElement->Length is in bytes, therefore it we compare against + * ByteWidth (see above) + */ + if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) && + ((UINT64) Address + ByteWidth) > + ((UINT64)(RegionElement->Address) + RegionElement->Length)) + { + ACPI_WARNING ((AE_INFO, + "Request on [%4.4s] is beyond region limit " + "Req-0x%X+0x%X, Base=0x%X, Len-0x%X", + (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address, + ByteWidth, (UINT32)(RegionElement->Address), + RegionElement->Length)); + + return (AE_AML_REGION_LIMIT); + } + + /* + * Get BufferValue to point to the "address" in the buffer + */ + BufferValue = ((UINT8 *) RegionElement->Buffer + + ((UINT64) Address - (UINT64) RegionElement->Address)); + +DoFunction: + /* + * Perform a read or write to the buffer space + */ + switch (Function) + { + case ACPI_READ: + /* + * Set the pointer Value to whatever is in the buffer + */ + memcpy (Value, BufferValue, ByteWidth); + break; + + case ACPI_WRITE: + /* + * Write the contents of Value to the buffer + */ + memcpy (BufferValue, Value, ByteWidth); + break; + + default: + + return (AE_BAD_PARAMETER); + } + + if (AcpiGbl_DisplayRegionAccess) + { + switch (SpaceId) + { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + + AcpiOsPrintf ("AcpiExec: SystemMemory " + "%s: Val %.8X Addr %.4X Width %X [REGION: BaseAddr %.4X Len %.2X]\n", + (Function & ACPI_IO_MASK) ? "Write" : "Read ", + (UINT32) *Value, (UINT32) Address, BitWidth, (UINT32) BaseAddress, Length); + break; + + case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */ + + /* This space is required to always be ByteAcc */ + + Status = AcpiBufferToResource (MyContext->Connection, + MyContext->Length, &Resource); + + AcpiOsPrintf ("AcpiExec: GeneralPurposeIo " + "%s: Val %.8X Addr %.4X BaseAddr %.4X Len %.2X Width %X AccLen %.2X Conn %p\n", + (Function & ACPI_IO_MASK) ? "Write" : "Read ", (UINT32) *Value, + (UINT32) Address, (UINT32) BaseAddress, Length, BitWidth, + MyContext->AccessLength, MyContext->Connection); + break; + + default: + + break; + } + } + + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aetables.c b/third_party/lib/acpica/source/tools/acpiexec/aetables.c new file mode 100644 index 000000000..16ea9af65 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aetables.c @@ -0,0 +1,599 @@ +/****************************************************************************** + * + * Module Name: aetables - ACPI table setup/install for acpiexec utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "aecommon.h" +#include "aetables.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("aetables") + +/* Local prototypes */ + +static void +AeInitializeTableHeader ( + ACPI_TABLE_HEADER *Header, + char *Signature, + UINT32 Length); + +void +AeTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable); + +/* User table (DSDT) */ + +static ACPI_TABLE_HEADER *DsdtToInstallOverride; + +/* Non-AML tables that are constructed locally and installed */ + +static ACPI_TABLE_RSDP LocalRSDP; +static ACPI_TABLE_FACS LocalFACS; +static ACPI_TABLE_HEADER LocalTEST; +static ACPI_TABLE_HEADER LocalBADTABLE; + +/* + * We need a local FADT so that the hardware subcomponent will function, + * even though the underlying OSD HW access functions don't do anything. + */ +static ACPI_TABLE_FADT LocalFADT; + +/* + * Use XSDT so that both 32- and 64-bit versions of this utility will + * function automatically. + */ +static ACPI_TABLE_XSDT *LocalXSDT; + +#define BASE_XSDT_TABLES 9 +#define BASE_XSDT_SIZE ((BASE_XSDT_TABLES) * sizeof (UINT64)) + +#define ACPI_MAX_INIT_TABLES (32) + + +/****************************************************************************** + * + * FUNCTION: AeTableOverride + * + * DESCRIPTION: Local implementation of AcpiOsTableOverride. + * Exercise the override mechanism + * + *****************************************************************************/ + +void +AeTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable) +{ + + if (!AcpiGbl_LoadTestTables) + { + *NewTable = NULL; + return; + } + + /* This code exercises the table override mechanism in the core */ + + if (ACPI_COMPARE_NAME (ExistingTable->Signature, ACPI_SIG_DSDT)) + { + *NewTable = DsdtToInstallOverride; + } + + /* This code tests override of dynamically loaded tables */ + + else if (ACPI_COMPARE_NAME (ExistingTable->Signature, "OEM9")) + { + *NewTable = ACPI_CAST_PTR (ACPI_TABLE_HEADER, Ssdt3Code); + } +} + + +/****************************************************************************** + * + * FUNCTION: AeInitializeTableHeader + * + * PARAMETERS: Header - A valid standard ACPI table header + * Signature - Signature to insert + * Length - Length of the table + * + * RETURN: None. Header is modified. + * + * DESCRIPTION: Initialize the table header for a local ACPI table. + * + *****************************************************************************/ + +static void +AeInitializeTableHeader ( + ACPI_TABLE_HEADER *Header, + char *Signature, + UINT32 Length) +{ + + ACPI_MOVE_NAME (Header->Signature, Signature); + Header->Length = Length; + + Header->OemRevision = 0x1001; + strncpy (Header->OemId, "Intel", ACPI_OEM_ID_SIZE); + strncpy (Header->OemTableId, "AcpiExec", ACPI_OEM_TABLE_ID_SIZE); + strncpy (Header->AslCompilerId, "INTL", ACPI_NAME_SIZE); + Header->AslCompilerRevision = ACPI_CA_VERSION; + + /* Set the checksum, must set to zero first */ + + Header->Checksum = 0; + Header->Checksum = (UINT8) -AcpiTbChecksum ( + (void *) Header, Header->Length); +} + + +/****************************************************************************** + * + * FUNCTION: AeBuildLocalTables + * + * PARAMETERS: TableCount - Number of tables on the command line + * ListHead - List of actual tables from files + * + * RETURN: Status + * + * DESCRIPTION: Build a complete ACPI table chain, with a local RSDP, XSDT, + * FADT, and several other test tables. + * + *****************************************************************************/ + +ACPI_STATUS +AeBuildLocalTables ( + ACPI_NEW_TABLE_DESC *ListHead) +{ + UINT32 TableCount = 1; + ACPI_PHYSICAL_ADDRESS DsdtAddress = 0; + UINT32 XsdtSize; + ACPI_NEW_TABLE_DESC *NextTable; + UINT32 NextIndex; + ACPI_TABLE_FADT *ExternalFadt = NULL; + + + /* + * Update the table count. For the DSDT, it is not put into the XSDT. + * For the FADT, this table is already accounted for since we usually + * install a local FADT. + */ + NextTable = ListHead; + while (NextTable) + { + if (!ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_FADT)) + { + TableCount++; + } + + NextTable = NextTable->Next; + } + + XsdtSize = (((TableCount + 1) * sizeof (UINT64)) + + sizeof (ACPI_TABLE_HEADER)); + if (AcpiGbl_LoadTestTables) + { + XsdtSize += BASE_XSDT_SIZE; + } + + /* Build an XSDT */ + + LocalXSDT = AcpiOsAllocate (XsdtSize); + if (!LocalXSDT) + { + return (AE_NO_MEMORY); + } + + memset (LocalXSDT, 0, XsdtSize); + LocalXSDT->TableOffsetEntry[0] = ACPI_PTR_TO_PHYSADDR (&LocalFADT); + NextIndex = 1; + + /* + * Install the user tables. The DSDT must be installed in the FADT. + * All other tables are installed directly into the XSDT. + */ + NextTable = ListHead; + while (NextTable) + { + /* + * Incoming DSDT or FADT are special cases. All other tables are + * just immediately installed into the XSDT. + */ + if (ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_DSDT)) + { + if (DsdtAddress) + { + printf ("Already found a DSDT, only one allowed\n"); + return (AE_ALREADY_EXISTS); + } + + /* The incoming user table is a DSDT */ + + DsdtAddress = ACPI_PTR_TO_PHYSADDR (NextTable->Table); + DsdtToInstallOverride = NextTable->Table; + } + else if (ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_FADT)) + { + ExternalFadt = ACPI_CAST_PTR (ACPI_TABLE_FADT, NextTable->Table); + LocalXSDT->TableOffsetEntry[0] = ACPI_PTR_TO_PHYSADDR (NextTable->Table); + } + else + { + /* Install the table in the XSDT */ + + LocalXSDT->TableOffsetEntry[NextIndex] = + ACPI_PTR_TO_PHYSADDR (NextTable->Table); + NextIndex++; + } + + NextTable = NextTable->Next; + } + + /* Install the optional extra local tables */ + + if (AcpiGbl_LoadTestTables) + { + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&LocalTEST); + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&LocalBADTABLE); + + /* Install two SSDTs to test multiple table support */ + + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&Ssdt1Code); + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&Ssdt2Code); + + /* Install the OEM1 table to test LoadTable */ + + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&Oem1Code); + + /* Install the OEMx table to test LoadTable */ + + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&OemxCode); + + /* Install the ECDT table to test _REG */ + + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&EcdtCode); + + /* Install two UEFIs to test multiple table support */ + + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&Uefi1Code); + LocalXSDT->TableOffsetEntry[NextIndex++] = ACPI_PTR_TO_PHYSADDR (&Uefi2Code); + } + + /* Build an RSDP. Contains a valid XSDT only, no RSDT */ + + memset (&LocalRSDP, 0, sizeof (ACPI_TABLE_RSDP)); + ACPI_MAKE_RSDP_SIG (LocalRSDP.Signature); + memcpy (LocalRSDP.OemId, "Intel", 6); + + LocalRSDP.Revision = 2; + LocalRSDP.XsdtPhysicalAddress = ACPI_PTR_TO_PHYSADDR (LocalXSDT); + LocalRSDP.Length = sizeof (ACPI_TABLE_RSDP); + + /* Set checksums for both XSDT and RSDP */ + + AeInitializeTableHeader ((void *) LocalXSDT, ACPI_SIG_XSDT, XsdtSize); + + LocalRSDP.Checksum = 0; + LocalRSDP.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) &LocalRSDP, ACPI_RSDP_CHECKSUM_LENGTH); + + if (!DsdtAddress) + { + /* Use the local DSDT because incoming table(s) are all SSDT(s) */ + + DsdtAddress = ACPI_PTR_TO_PHYSADDR (LocalDsdtCode); + DsdtToInstallOverride = ACPI_CAST_PTR (ACPI_TABLE_HEADER, LocalDsdtCode); + } + + /* + * Build an FADT. There are three options for the FADT: + * 1) Incoming external FADT specified on the command line + * 2) A "hardware reduced" local FADT + * 3) A fully featured local FADT + */ + memset (&LocalFADT, 0, sizeof (ACPI_TABLE_FADT)); + + if (ExternalFadt) + { + /* + * Use the external FADT, but we must update the DSDT/FACS + * addresses as well as the checksum + */ + ExternalFadt->Dsdt = (UINT32) DsdtAddress; + if (!AcpiGbl_ReducedHardware) + { + ExternalFadt->Facs = ACPI_PTR_TO_PHYSADDR (&LocalFACS); + } + + /* + * If there room in the FADT for the XDsdt and XFacs 64-bit + * pointers, use them. + */ + if (ExternalFadt->Header.Length > ACPI_PTR_DIFF ( + &ExternalFadt->XDsdt, ExternalFadt)) + { + ExternalFadt->Dsdt = 0; + ExternalFadt->Facs = 0; + + ExternalFadt->XDsdt = DsdtAddress; + if (!AcpiGbl_ReducedHardware) + { + ExternalFadt->XFacs = ACPI_PTR_TO_PHYSADDR (&LocalFACS); + } + } + + /* Complete the external FADT with the checksum */ + + ExternalFadt->Header.Checksum = 0; + ExternalFadt->Header.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) ExternalFadt, ExternalFadt->Header.Length); + } + else if (AcpiGbl_UseHwReducedFadt) + { + memcpy (&LocalFADT, HwReducedFadtCode, ACPI_FADT_V5_SIZE); + LocalFADT.Dsdt = 0; + LocalFADT.XDsdt = DsdtAddress; + } + else + { + /* + * Build a local FADT so we can test the hardware/event init + */ + LocalFADT.Header.Revision = 5; + + /* Setup FADT header and DSDT/FACS addresses */ + + LocalFADT.Dsdt = 0; + LocalFADT.Facs = 0; + + LocalFADT.XDsdt = DsdtAddress; + LocalFADT.XFacs = ACPI_PTR_TO_PHYSADDR (&LocalFACS); + + /* Miscellaneous FADT fields */ + + LocalFADT.Gpe0BlockLength = 0x08; + LocalFADT.Gpe0Block = 0x00001234; + + LocalFADT.Gpe1BlockLength = 0x80; + LocalFADT.Gpe1Block = 0x00005678; + LocalFADT.Gpe1Base = 100; + + LocalFADT.Pm1EventLength = 4; + LocalFADT.Pm1aEventBlock = 0x00001aaa; + LocalFADT.Pm1bEventBlock = 0x00001bbb; + + LocalFADT.Pm1ControlLength = 2; + LocalFADT.Pm1aControlBlock = 0xB0; + + LocalFADT.PmTimerLength = 4; + LocalFADT.PmTimerBlock = 0xA0; + + LocalFADT.Pm2ControlBlock = 0xC0; + LocalFADT.Pm2ControlLength = 1; + + /* Setup one example X-64 GAS field */ + + LocalFADT.XPm1bEventBlock.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO; + LocalFADT.XPm1bEventBlock.Address = LocalFADT.Pm1bEventBlock; + LocalFADT.XPm1bEventBlock.BitWidth = (UINT8) + ACPI_MUL_8 (LocalFADT.Pm1EventLength); + } + + AeInitializeTableHeader ((void *) &LocalFADT, + ACPI_SIG_FADT, sizeof (ACPI_TABLE_FADT)); + + /* Build a FACS */ + + memset (&LocalFACS, 0, sizeof (ACPI_TABLE_FACS)); + ACPI_MOVE_NAME (LocalFACS.Signature, ACPI_SIG_FACS); + + LocalFACS.Length = sizeof (ACPI_TABLE_FACS); + LocalFACS.GlobalLock = 0x11AA0011; + + /* Build the optional local tables */ + + if (AcpiGbl_LoadTestTables) + { + /* + * Build a fake table [TEST] so that we make sure that the + * ACPICA core ignores it + */ + memset (&LocalTEST, 0, sizeof (ACPI_TABLE_HEADER)); + ACPI_MOVE_NAME (LocalTEST.Signature, "TEST"); + + LocalTEST.Revision = 1; + LocalTEST.Length = sizeof (ACPI_TABLE_HEADER); + + LocalTEST.Checksum = 0; + LocalTEST.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) &LocalTEST, LocalTEST.Length); + + /* + * Build a fake table with a bad signature [BAD!] so that we make + * sure that the ACPICA core ignores it + */ + memset (&LocalBADTABLE, 0, sizeof (ACPI_TABLE_HEADER)); + ACPI_MOVE_NAME (LocalBADTABLE.Signature, "BAD!"); + + LocalBADTABLE.Revision = 1; + LocalBADTABLE.Length = sizeof (ACPI_TABLE_HEADER); + + LocalBADTABLE.Checksum = 0; + LocalBADTABLE.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) &LocalBADTABLE, LocalBADTABLE.Length); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AeInstallTables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install the various ACPI tables + * + *****************************************************************************/ + +ACPI_STATUS +AeInstallTables ( + void) +{ + ACPI_STATUS Status; + ACPI_TABLE_HEADER Header; + ACPI_TABLE_HEADER *Table; + UINT32 i; + + + Status = AcpiInitializeTables (NULL, ACPI_MAX_INIT_TABLES, TRUE); + ACPI_CHECK_OK (AcpiInitializeTables, Status); + + if (AcpiGbl_LoadTestTables) + { + /* Test multiple table/UEFI support. First, get the headers */ + + Status = AcpiGetTableHeader (ACPI_SIG_UEFI, 1, &Header); + ACPI_CHECK_OK (AcpiGetTableHeader, Status); + + Status = AcpiGetTableHeader (ACPI_SIG_UEFI, 2, &Header); + ACPI_CHECK_OK (AcpiGetTableHeader, Status); + + Status = AcpiGetTableHeader (ACPI_SIG_UEFI, 3, &Header); + ACPI_CHECK_STATUS (AcpiGetTableHeader, Status, AE_NOT_FOUND); + + /* Now get the actual tables */ + + Status = AcpiGetTable (ACPI_SIG_UEFI, 1, &Table); + ACPI_CHECK_OK (AcpiGetTable, Status); + + Status = AcpiGetTable (ACPI_SIG_UEFI, 2, &Table); + ACPI_CHECK_OK (AcpiGetTable, Status); + + Status = AcpiGetTable (ACPI_SIG_UEFI, 3, &Table); + ACPI_CHECK_STATUS (AcpiGetTable, Status, AE_NOT_FOUND); + } + + /* Check that we can get all of the ACPI tables */ + + for (i = 0; ; i++) + { + Status = AcpiGetTableByIndex (i, &Table); + if ((Status == AE_BAD_PARAMETER) || !Table) + { + break; + } + + ACPI_CHECK_OK (AcpiGetTableByIndex, Status); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AeLoadTables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the definition block ACPI tables + * + *****************************************************************************/ + +ACPI_STATUS +AeLoadTables ( + void) +{ + ACPI_STATUS Status; + + + Status = AcpiLoadTables (); + ACPI_CHECK_OK (AcpiLoadTables, Status); + + /* + * Test run-time control method installation. Do it twice to test code + * for an existing name. + */ + Status = AcpiInstallMethod (MethodCode); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, Could not install method\n", + AcpiFormatException (Status)); + } + + Status = AcpiInstallMethod (MethodCode); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, Could not install method\n", + AcpiFormatException (Status)); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetRootPointer + * + * PARAMETERS: Flags - not used + * Address - Where the root pointer is returned + * + * RETURN: Status + * + * DESCRIPTION: Return a local RSDP, used to dynamically load tables via the + * standard ACPI mechanism. + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + + return (ACPI_PTR_TO_PHYSADDR (&LocalRSDP)); +} diff --git a/third_party/lib/acpica/source/tools/acpiexec/aetables.h b/third_party/lib/acpica/source/tools/acpiexec/aetables.h new file mode 100644 index 000000000..9377f5897 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpiexec/aetables.h @@ -0,0 +1,498 @@ +/****************************************************************************** + * + * Module Name: aetables.h - Precompiled AML ACPI tables for acpiexec + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __AETABLES_H__ +#define __AETABLES_H__ + + +/* + * Miscellaneous pre-compiled AML ACPI tables to be installed + */ + +/* Local DSDT used only if not present in the input */ + +static unsigned char LocalDsdtCode[] = +{ + 0x44,0x53,0x44,0x54,0x24,0x00,0x00,0x00, /* 00000000 "DSDT$..." */ + 0x02,0x2C,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 ".,Intel." */ + 0x4C,0x6F,0x63,0x61,0x6C,0x00,0x00,0x00, /* 00000010 "Local..." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x30,0x07,0x09,0x20, +}; + +/* Several example SSDTs */ + +/* SSDT1 is used by ASLTS; if changed here, must also be changed in dtregions.asl */ + +static unsigned char Ssdt1Code[] = /* Has method _T98 */ +{ + 0x53,0x53,0x44,0x54,0x3E,0x00,0x00,0x00, /* 00000000 "SSDT>..." */ + 0x02,0x08,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x73,0x73,0x64,0x74,0x31,0x00,0x00,0x00, /* 00000010 "ssdt1..." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x20,0x06,0x12,0x20,0x14,0x19,0x5F,0x54, /* 00000020 " .. .._T" */ + 0x39,0x38,0x01,0x70,0x0D,0x53,0x53,0x44, /* 00000028 "98.p.SSD" */ + 0x54,0x31,0x20,0x2D,0x20,0x5F,0x54,0x39, /* 00000030 "T1 - _T9" */ + 0x38,0x00,0x5B,0x31,0xA4,0x00 /* 00000038 "8.[1.." */ +}; + +unsigned char Ssdt2Code[] = /* Has method _T99 */ +{ + 0x53,0x53,0x44,0x54,0x3E,0x00,0x00,0x00, /* 00000000 "SSDT>..." */ + 0x02,0xFE,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x73,0x73,0x64,0x74,0x32,0x00,0x00,0x00, /* 00000010 "ssdt2..." */ + 0x02,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x20,0x06,0x12,0x20,0x14,0x19,0x5F,0x54, /* 00000020 " .. .._T" */ + 0x39,0x39,0x06,0x70,0x0D,0x53,0x53,0x44, /* 00000028 "99.p.SSD" */ + 0x54,0x32,0x20,0x2D,0x20,0x5F,0x54,0x39, /* 00000030 "T2 - _T9" */ + 0x39,0x00,0x5B,0x31,0xA4,0x00 /* 00000038 "9.[1.." */ +}; + +unsigned char Ssdt3Code[] = /* OEM9: Has method _T97 */ +{ + 0x4F,0x45,0x4D,0x39,0x30,0x00,0x00,0x00, /* 00000000 "OEM10..." */ + 0x01,0xDD,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010 "Many...." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x24,0x04,0x03,0x20,0x14,0x0B,0x5F,0x54, /* 00000020 "$.. .._T" */ + 0x39,0x37,0x00,0x70,0x0A,0x04,0x60,0xA4, /* 00000028 "97.p..`." */ +}; + +unsigned char Ssdt4Code[] = /* Has method _T96 */ +{ + 0x53,0x53,0x44,0x54,0x2D,0x00,0x00,0x00, /* 00000000 "SSDT-..." */ + 0x02,0x2B,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 ".+Intel." */ + 0x73,0x73,0x64,0x74,0x34,0x00,0x00,0x00, /* 00000010 "ssdt4..." */ + 0x04,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x20,0x06,0x12,0x20,0x14,0x08,0x5F,0x54, /* 00000020 " .. .._T" */ + 0x39,0x36,0x05,0xA4,0x00 /* 00000028 "96..." */ +}; + +/* "Hardware-Reduced" ACPI 5.0 FADT (No FACS, no ACPI hardware) */ + +unsigned char HwReducedFadtCode[] = +{ + 0x46,0x41,0x43,0x50,0x0C,0x01,0x00,0x00, /* 00000000 "FACP...." */ + 0x05,0x8C,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x41,0x43,0x50,0x49,0x35,0x30,0x20,0x20, /* 00000010 "ACPI50 " */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x13,0x04,0x11,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000048 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x78,0x00,0x01,0x08,0x00,0x01, /* 00000070 "..x....." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x02, /* 00000090 "..... .." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x10,0x00,0x02, /* 000000A8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x00, /* 000000C0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x01,0x20,0x00,0x03,0x00,0x00,0x00,0x00, /* 000000D0 ". ......" */ + 0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x01, /* 000000D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 000000F0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x01,0x08,0x00,0x01,0x01,0x00,0x00,0x00, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00 /* 00000108 "........" */ +}; + +/* Example OEM table */ + +static unsigned char Oem1Code[] = +{ + 0x4F,0x45,0x4D,0x31,0x38,0x00,0x00,0x00, /* 00000000 "OEM18..." */ + 0x01,0x4B,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 ".KIntel." */ + 0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010 "Many...." */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x18,0x09,0x03,0x20,0x08,0x5F,0x58,0x54, /* 00000020 "... ._XT" */ + 0x32,0x0A,0x04,0x14,0x0C,0x5F,0x58,0x54, /* 00000028 "2...._XT" */ + 0x31,0x00,0x70,0x01,0x5F,0x58,0x54,0x32, /* 00000030 "1.p._XT2" */ +}; + +/* ASL source for this table is at the end of this file */ + +static unsigned char OemxCode[] = +{ + 0x4F,0x45,0x4D,0x58,0xB0,0x00,0x00,0x00, /* 00000000 "OEMX...." */ + 0x02,0x54,0x4D,0x79,0x4F,0x45,0x4D,0x00, /* 00000008 ".TMyOEM." */ + 0x54,0x65,0x73,0x74,0x00,0x00,0x00,0x00, /* 00000010 "Test...." */ + 0x32,0x04,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "2...INTL" */ + 0x31,0x03,0x10,0x20,0x14,0x1D,0x5F,0x49, /* 00000020 "1.. .._I" */ + 0x4E,0x49,0x00,0x70,0x0D,0x54,0x61,0x62, /* 00000028 "NI.p.Tab" */ + 0x6C,0x65,0x20,0x4F,0x45,0x4D,0x58,0x20, /* 00000030 "le OEMX " */ + 0x72,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x00, /* 00000038 "running." */ + 0x5B,0x31,0x10,0x22,0x5C,0x5F,0x47,0x50, /* 00000040 "[1."\_GP" */ + 0x45,0x14,0x06,0x5F,0x45,0x30,0x37,0x00, /* 00000048 "E.._E07." */ + 0x14,0x06,0x5F,0x45,0x32,0x32,0x00,0x14, /* 00000050 ".._E22.." */ + 0x06,0x5F,0x4C,0x33,0x31,0x00,0x14,0x06, /* 00000058 "._L31..." */ + 0x5F,0x4C,0x36,0x36,0x00,0x5B,0x82,0x10, /* 00000060 "_L66.[.." */ + 0x4F,0x45,0x4D,0x31,0x08,0x5F,0x50,0x52, /* 00000068 "OEM1._PR" */ + 0x57,0x12,0x05,0x02,0x0A,0x07,0x00,0x5B, /* 00000070 "W......[" */ + 0x82,0x10,0x4F,0x45,0x4D,0x32,0x08,0x5F, /* 00000078 "..OEM2._" */ + 0x50,0x52,0x57,0x12,0x05,0x02,0x0A,0x66, /* 00000080 "PRW....f" */ + 0x00,0x10,0x26,0x5C,0x47,0x50,0x45,0x32, /* 00000088 "..&\GPE2" */ + 0x14,0x06,0x5F,0x4C,0x30,0x31,0x00,0x14, /* 00000090 ".._L01.." */ + 0x06,0x5F,0x45,0x30,0x37,0x00,0x08,0x5F, /* 00000098 "._E07.._" */ + 0x50,0x52,0x57,0x12,0x0C,0x02,0x12,0x08, /* 000000A0 "PRW....." */ + 0x02,0x5C,0x47,0x50,0x45,0x32,0x01,0x00 /* 000000A8 ".\GPE2.." */ +}; + +/* Example ECDT */ + +unsigned char EcdtCode[] = +{ + 0x45,0x43,0x44,0x54,0x4E,0x00,0x00,0x00, /* 00000000 "ECDTN..." */ + 0x01,0x94,0x20,0x49,0x6E,0x74,0x65,0x6C, /* 00000008 ".. Intel" */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x16,0x03,0x11,0x20,0x01,0x08,0x00,0x00, /* 00000020 "... ...." */ + 0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "f......." */ + 0x01,0x08,0x00,0x00,0x62,0x00,0x00,0x00, /* 00000030 "....b..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x09,0x5C,0x5F,0x53,0x42,0x2E,0x50,0x43, /* 00000040 ".\_SB.PC" */ + 0x49,0x30,0x2E,0x45,0x43,0x00 /* 00000048 "I0.EC." */ +}; + +/* Test for multiple UEFI tables */ + +unsigned char Uefi1Code[] = +{ + 0x55,0x45,0x46,0x49,0x36,0x00,0x00,0x00, /* 00000000 "UEFI6..." */ + 0x01,0x6E,0x20,0x49,0x6E,0x74,0x65,0x6C, /* 00000008 ".n Intel" */ + 0x20,0x20,0x20,0x55,0x45,0x46,0x49,0x31, /* 00000010 " UEFI1" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x23,0x08,0x13,0x20,0x06,0x07,0x08,0x09, /* 00000020 "#.. ...." */ + 0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B, /* 00000028 "........" */ + 0x0C,0x0D,0x0E,0x0F,0x36,0x00 /* 00000030 "....6." */ +}; + +unsigned char Uefi2Code[] = +{ + 0x55,0x45,0x46,0x49,0xAA,0x00,0x00,0x00, /* 00000000 "UEFI...." */ + 0x01,0xE0,0x20,0x49,0x6E,0x74,0x65,0x6C, /* 00000008 ".. Intel" */ + 0x20,0x20,0x20,0x55,0x45,0x46,0x49,0x32, /* 00000010 " UEFI2" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x23,0x08,0x13,0x20,0x67,0x45,0x23,0x01, /* 00000020 "#.. gE#." */ + 0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B, /* 00000028 "........" */ + 0x0C,0x0D,0x0E,0x0F,0x36,0x00,0x04,0x19, /* 00000030 "....6..." */ + 0x00,0x56,0x34,0xF2,0x04,0x03,0x02,0x01, /* 00000038 ".V4....." */ + 0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x1E, /* 00000040 "wfUD3".." */ + 0x1C,0x1F,0x14,0x10,0x0C,0x08,0x04,0xAB, /* 00000048 "........" */ + 0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20, /* 00000050 "This is " */ + 0x61,0x20,0x73,0x74,0x72,0x69,0x6E,0x67, /* 00000058 "a string" */ + 0x00,0x5C,0x50,0x43,0x49,0x30,0x5C,0x41, /* 00000060 ".\PCI0\A" */ + 0x42,0x43,0x44,0x00,0x36,0x00,0x55,0x00, /* 00000068 "BCD.6.U." */ + 0x6E,0x00,0x69,0x00,0x63,0x00,0x6F,0x00, /* 00000070 "n.i.c.o." */ + 0x64,0x00,0x65,0x00,0x20,0x00,0x53,0x00, /* 00000078 "d.e. .S." */ + 0x74,0x00,0x72,0x00,0x69,0x00,0x6E,0x00, /* 00000080 "t.r.i.n." */ + 0x67,0x00,0x00,0x00,0x58,0x5B,0x00,0x00, /* 00000088 "g...X[.." */ + 0x00,0x00,0x00,0x00,0x41,0x42,0x43,0x44, /* 00000090 "....ABCD" */ + 0x45,0x00,0x00,0x01,0x02,0x03,0x04,0x05, /* 00000098 "E......." */ + 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, /* 000000A0 "........" */ + 0x0E,0x0F /* 000000A8 ".." */ +}; + + +/* + * Example installable control method + * + * DefinitionBlock ("", "DSDT", 2, "Intel", "MTHDTEST", 0x20090512) + * { + * Method (\_SI_._T97, 1, Serialized) + * { + * Store ("Example installed method", Debug) + * Store (Arg0, Debug) + * Return () + * } + * } + * + * Compiled byte code below. + */ +static unsigned char MethodCode[] = +{ + 0x44,0x53,0x44,0x54,0x53,0x00,0x00,0x00, /* 00000000 "DSDTS..." */ + 0x02,0xF9,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x4D,0x54,0x48,0x44,0x54,0x45,0x53,0x54, /* 00000010 "MTHDTEST" */ + 0x12,0x05,0x09,0x20,0x49,0x4E,0x54,0x4C, /* 00000018 "... INTL" */ + 0x22,0x04,0x09,0x20,0x14,0x2E,0x2E,0x5F, /* 00000020 "".. ..._" */ + 0x54,0x49,0x5F,0x5F,0x54,0x39,0x37,0x09, /* 00000028 "SI__T97." */ + 0x70,0x0D,0x45,0x78,0x61,0x6D,0x70,0x6C, /* 00000030 "p.Exampl" */ + 0x65,0x20,0x69,0x6E,0x73,0x74,0x61,0x6C, /* 00000038 "e instal" */ + 0x6C,0x65,0x64,0x20,0x6D,0x65,0x74,0x68, /* 00000040 "led meth" */ + 0x6F,0x64,0x00,0x5B,0x31,0x70,0x68,0x5B, /* 00000048 "od.[1ph[" */ + 0x31,0xA4,0x00, +}; + + +#if 0 +/****************************************************************************** + * + * DESCRIPTION: ASL tables that are used in RSDT/XSDT, also used to test + * Load/LoadTable operators. + * + *****************************************************************************/ + +DefinitionBlock ("", "OEMX", 2, "MyOEM", "Test", 0x00000432) +{ + External (GPE2, DeviceObj) + + Method (_INI) + { + Store ("Table OEMX running", Debug) + } + + Scope (\_GPE) + { + Method (_E07) {} + Method (_E22) {} + Method (_L31) {} + Method (_L66) {} + } + + Device (OEM1) + { + Name (_PRW, Package(){7,0}) + } + Device (OEM2) + { + Name (_PRW, Package(){0x66,0}) + } + + Scope (\GPE2) + { + Method (_L01) {} + Method (_E07) {} + + Name (_PRW, Package() {Package() {\GPE2, 1}, 0}) + } +} + +/* Parent gr.asl file */ + +DefinitionBlock ("", "DSDT", 2, "Intel", "Many", 0x00000001) +{ + Name (BUF1, Buffer() + { + 0x4F,0x45,0x4D,0x58,0xB0,0x00,0x00,0x00, /* 00000000 "OEMX...." */ + 0x02,0x54,0x4D,0x79,0x4F,0x45,0x4D,0x00, /* 00000008 ".TMyOEM." */ + 0x54,0x65,0x73,0x74,0x00,0x00,0x00,0x00, /* 00000010 "Test...." */ + 0x32,0x04,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "2...INTL" */ + 0x31,0x03,0x10,0x20,0x14,0x1D,0x5F,0x49, /* 00000020 "1.. .._I" */ + 0x4E,0x49,0x00,0x70,0x0D,0x54,0x61,0x62, /* 00000028 "NI.p.Tab" */ + 0x6C,0x65,0x20,0x4F,0x45,0x4D,0x58,0x20, /* 00000030 "le OEMX " */ + 0x72,0x75,0x6E,0x6E,0x69,0x6E,0x67,0x00, /* 00000038 "running." */ + 0x5B,0x31,0x10,0x22,0x5C,0x5F,0x47,0x50, /* 00000040 "[1."\_GP" */ + 0x45,0x14,0x06,0x5F,0x45,0x30,0x37,0x00, /* 00000048 "E.._E07." */ + 0x14,0x06,0x5F,0x45,0x32,0x32,0x00,0x14, /* 00000050 ".._E22.." */ + 0x06,0x5F,0x4C,0x33,0x31,0x00,0x14,0x06, /* 00000058 "._L31..." */ + 0x5F,0x4C,0x36,0x36,0x00,0x5B,0x82,0x10, /* 00000060 "_L66.[.." */ + 0x4F,0x45,0x4D,0x31,0x08,0x5F,0x50,0x52, /* 00000068 "OEM1._PR" */ + 0x57,0x12,0x05,0x02,0x0A,0x07,0x00,0x5B, /* 00000070 "W......[" */ + 0x82,0x10,0x4F,0x45,0x4D,0x32,0x08,0x5F, /* 00000078 "..OEM2._" */ + 0x50,0x52,0x57,0x12,0x05,0x02,0x0A,0x66, /* 00000080 "PRW....f" */ + 0x00,0x10,0x26,0x5C,0x47,0x50,0x45,0x32, /* 00000088 "..&\GPE2" */ + 0x14,0x06,0x5F,0x4C,0x30,0x31,0x00,0x14, /* 00000090 ".._L01.." */ + 0x06,0x5F,0x45,0x30,0x37,0x00,0x08,0x5F, /* 00000098 "._E07.._" */ + 0x50,0x52,0x57,0x12,0x0C,0x02,0x12,0x08, /* 000000A0 "PRW....." */ + 0x02,0x5C,0x47,0x50,0x45,0x32,0x01,0x00 /* 000000A8 ".\GPE2.." */ + }) + + Name (HNDL, 0) + Method (LD) + { + Load (BUF1, HNDL) + Store ("Load operator, handle:", Debug) + Store (HNDL, Debug) + } + + Method (MAIN, 0, NotSerialized) + { + Store ("Loading OEMX table", Debug) + Store (LoadTable ("OEMX", "MyOEM", "Test"), Debug) + } + + Scope (\_GPE) + { + Method (_L08) {} + Method (_E08) {} + Method (_L0B) {} + } + + Device (DEV0) + { + Name (_PRW, Package() {0x11, 0}) + } + + Device (\GPE2) + { + Method (_L00) {} + } +} + +/* SSDT1 */ + +DefinitionBlock ("ssdt1.aml", "SSDT", 2, "Intel", "ssdt1", 0x00000001) +{ + Method (_T98, 1, NotSerialized) + { + Store ("SSDT1 - _T98", Debug) + Return (Zero) + } +} + +/* SSDT2 */ + +DefinitionBlock ("ssdt2.aml", "SSDT", 2, "Intel", "ssdt2", 0x00000002) +{ + Method (_T99, 6, NotSerialized) + { + Store ("SSDT2 - _T99", Debug) + Return (Zero) + } +} + +/* SSDT4 */ + +DefinitionBlock ("ssdt4.aml", "SSDT", 2, "Intel", "ssdt4", 0x00000004) +{ + Method (_T96, 5, NotSerialized) + { + Return (Zero) + } +} + +/* Example ECDT */ + +[000h 0000 4] Signature : "ECDT" /* Embedded Controller Boot Resources Table */ +[004h 0004 4] Table Length : 0000004E +[008h 0008 1] Revision : 01 +[009h 0009 1] Checksum : 14 +[00Ah 0010 6] Oem ID : " Intel" +[010h 0016 8] Oem Table ID : "Template" +[018h 0024 4] Oem Revision : 00000001 +[01Ch 0028 4] Asl Compiler ID : "INTL" +[020h 0032 4] Asl Compiler Revision : 20110316 + + +[024h 0036 12] Command/Status Register : +[024h 0036 1] Space ID : 01 (SystemIO) +[025h 0037 1] Bit Width : 08 +[026h 0038 1] Bit Offset : 00 +[027h 0039 1] Encoded Access Width : 00 (Undefined/Legacy) +[028h 0040 8] Address : 0000000000000066 + +[030h 0048 12] Data Register : +[030h 0048 1] Space ID : 01 (SystemIO) +[031h 0049 1] Bit Width : 08 +[032h 0050 1] Bit Offset : 00 +[033h 0051 1] Encoded Access Width : 00 (Undefined/Legacy) +[034h 0052 8] Address : 0000000000000062 + +[03Ch 0060 4] UID : 00000000 +[040h 0064 1] GPE Number : 09 +[041h 0065 13] Namepath : "\_SB.PCI0.EC" + + +/* Test multiple UEFI support */ + +[0004] Signature : "UEFI" [UEFI Boot Optimization Table] +[0004] Table Length : 00000036 +[0001] Revision : 01 +[0001] Checksum : 9B +[0006] Oem ID : " Intel" +[0008] Oem Table ID : " UEFI1" +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20100528 + +[0016] UUID Identifier : 09080706-0504-0706-0809-0A0B0C0D0E0F +[0002] Data Offset : 0000 + + +[004] Signature : "UEFI" /* UEFI Boot Optimization Table */ +[004] Table Length : 00000036 +[001] Revision : 01 +[001] Checksum : 9B +[006] Oem ID : " Intel" +[008] Oem Table ID : " UEFI2" +[004] Oem Revision : 00000001 +[004] Asl Compiler ID : "INTL" +[004] Asl Compiler Revision : 20100528 + +[016] UUID Identifier : 01234567-0504-0706-0809-0A0B0C0D0E0F +[002] Data Offset : 0000 + + Label : StartRecord + UINT8 : 4 + UINT16 : $EndRecord - $StartRecord /* Should be 0x19 */ + UINT24 : 123456 | F00000 + UINT32 : 01020304 + UINT56 : 11223344556677 + UINT64 : 0102030405060708 * 4 - 200 / 100 | F0000 + Label : EndRecord + + UINT8 : AB + String : "This is a string" + DevicePath : "\PCI0\ABCD" + UINT16 : $StartRecord + Unicode : "Unicode String" + UINT64 : $EndRecord * 128 + + Buffer : 41 42 43 44 45 + String : "" + GUID : 03020100-0504-0706-0809-0A0B0C0D0E0F +#endif + +#endif /* __AETABLES_H__ */ diff --git a/third_party/lib/acpica/source/tools/acpihelp/acpihelp.h b/third_party/lib/acpica/source/tools/acpihelp/acpihelp.h new file mode 100644 index 000000000..19f005265 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpihelp/acpihelp.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * + * Module Name: acpihelp.h - Include file for AcpiHelp utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACPIHELP_H +#define __ACPIHELP_H + + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" + +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#endif +#include + + +typedef enum +{ + AH_DECODE_DEFAULT = 0, + AH_DECODE_ASL, + AH_DECODE_ASL_KEYWORD, + AH_DECODE_PREDEFINED_NAME, + AH_DECODE_AML, + AH_DECODE_AML_OPCODE, + AH_DISPLAY_DEVICE_IDS, + AH_DECODE_EXCEPTION, + AH_DECODE_ASL_AML, + AH_DISPLAY_UUIDS, + AH_DISPLAY_TABLES, + AH_DISPLAY_DIRECTIVES + +} AH_OPTION_TYPES; + +#define AH_MAX_ASL_LINE_LENGTH 70 +#define AH_MAX_AML_LINE_LENGTH 100 + + +typedef struct ah_aml_opcode +{ + UINT16 OpcodeRangeStart; + UINT16 OpcodeRangeEnd; + char *OpcodeString; + char *OpcodeName; + char *Type; + char *FixedArguments; + char *VariableArguments; + char *Grammar; + +} AH_AML_OPCODE; + +typedef struct ah_asl_operator +{ + char *Name; + char *Syntax; + char *Description; + +} AH_ASL_OPERATOR; + +typedef struct ah_asl_keyword +{ + char *Name; + char *Description; + char *KeywordList; + +} AH_ASL_KEYWORD; + +typedef struct ah_directive_info +{ + char *Name; + char *Description; + +} AH_DIRECTIVE_INFO; + +extern const AH_AML_OPCODE AmlOpcodeInfo[]; +extern const AH_ASL_OPERATOR AslOperatorInfo[]; +extern const AH_ASL_KEYWORD AslKeywordInfo[]; +extern const AH_UUID AcpiUuids[]; +extern const AH_DIRECTIVE_INFO PreprocessorDirectives[]; +extern const AH_TABLE AcpiSupportedTables[]; +extern BOOLEAN AhDisplayAll; + +void +AhFindAmlOpcode ( + char *Name); + +void +AhDecodeAmlOpcode ( + char *Name); + +void +AhDecodeException ( + char *Name); + +void +AhFindPredefinedNames ( + char *Name); + +void +AhFindAslAndAmlOperators ( + char *Name); + +UINT32 +AhFindAslOperators ( + char *Name); + +void +AhFindAslKeywords ( + char *Name); + +void +AhDisplayDeviceIds ( + char *Name); + +void +AhDisplayTables ( + void); + +const AH_TABLE * +AcpiAhGetTableInfo ( + char *Signature); + +void +AhDisplayUuids ( + void); + +void +AhDisplayDirectives ( + void); + +#endif /* __ACPIHELP_H */ diff --git a/third_party/lib/acpica/source/tools/acpihelp/ahamlops.c b/third_party/lib/acpica/source/tools/acpihelp/ahamlops.c new file mode 100644 index 000000000..70863e4eb --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpihelp/ahamlops.c @@ -0,0 +1,327 @@ +/****************************************************************************** + * + * Module Name: ahamlops - Table of all known AML opcodes + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpihelp.h" + +/* + * AML opcodes with related syntax and grammar information. + * This table was extracted from the ACPI specification. + */ +const AH_AML_OPCODE AmlOpcodeInfo[] = +{ + {0x00, 0x00, "0x00", "ZeroOp", "DataObject", NULL, NULL, + NULL}, + {0x01, 0x01, "0x01", "OneOp", "DataObject", NULL, NULL, + NULL}, + {0x02, 0x05, "0x02-0x05", NULL, NULL, NULL, NULL, + NULL}, + {0x06, 0x06, "0x06", "AliasOp", "TermObject", "NameString NameString", NULL, + "DefAlias := AliasOp NameString NameString"}, + {0x07, 0x07, "0x07", NULL, NULL, NULL, NULL, + NULL}, + {0x08, 0x08, "0x08", "NameOp", "TermObject", "NameString DataRefObject", NULL, + "DefName := NameOp NameString DataRefObject"}, + {0x09, 0x09, "0x09", NULL, NULL, NULL, NULL, + NULL}, + {0x0A, 0x0A, "0x0A", "BytePrefix", "DataObject", "ByteData", NULL, + "ByteConst := BytePrefix ByteData"}, + {0x0B, 0x0B, "0x0B", "WordPrefix", "DataObject", "WordData", NULL, + "WordConst := WordPrefix WordData"}, + {0x0C, 0x0C, "0x0C", "DWordPrefix", "DataObject", "DWordData", NULL, + "DWordConst := DWordPrefix DWordData"}, + {0x0D, 0x0D, "0x0D", "StringPrefix", "DataObject", "AsciiCharList NullChar", NULL, + "String := StringPrefix AsciiCharList NullChar"}, + {0x0E, 0x0E, "0x0E", "QWordPrefix", "DataObject", "QWordData", NULL, + "QWordConst := QWordPrefix QWordData"}, + {0x0F, 0x0F, "0x0F", NULL, NULL, NULL, NULL, + NULL}, + {0x10, 0x10, "0x10", "ScopeOp", "TermObject", "NameString", "TermList", + "DefScope := ScopeOp PkgLength NameString TermList"}, + {0x11, 0x11, "0x11", "BufferOp", "TermObject", "TermArg", "ByteList", + "DefBuffer := BufferOp PkgLength BufferSize ByteList"}, + {0x12, 0x12, "0x12", "PackageOp", "TermObject", "ByteData", "Package TermList", + "DefPackage := PackageOp PkgLength NumElements PackageElementList"}, + {0x13, 0x13, "0x13", "VarPackageOp", "TermObject", "TermArg", "Package TermList", + "DefVarPackage := VarPackageOp PkgLength VarNumElements PackageElementList"}, + {0x14, 0x14, "0x14", "MethodOp", "TermObject", "NameString ByteData", "TermList", + "DefMethod := MethodOp PkgLength NameString MethodFlags TermList"}, + {0x15, 0x15, "0x15", "ExternalOp", "NameObject", "NameString ByteData ByteData", NULL, + "DefExternal := ExternalOp NameString ObjectType ArgumentCount"}, + {0x16, 0x2D, "0x16-0x2D", NULL, NULL, NULL, NULL, + NULL}, + {0x2E, 0x2E, "0x2E", "DualNamePrefix", "NameObject", "NameSeg NameSeg", NULL, + "DualNamePath := DualNamePrefix NameSeg NameSeg"}, + {0x2F, 0x2F, "0x2F", "MultiNamePrefix", "NameObject", "ByteData NameSeg", NULL, + "MultiNamePath := MultiNamePrefix SegCount NameSeg(SegCount)"}, + {0x30, 0x39, "0x30-0x39", "DigitChar", "NameObject", NULL, NULL, + NULL}, + {0x3A, 0x40, "0x3A-0x40", NULL, NULL, NULL, NULL, + NULL}, + {0x41, 0x5A, "0x41-0x5A", "NameChar", "NameObject", NULL, NULL, + NULL}, + {0x5B, 0x5B, "0x5B", "ExtOpPrefix", "DataObject", "ByteData", NULL, + NULL}, + {0x5B00, 0x5B00, "0x5B00", NULL, NULL, NULL, NULL, + NULL}, + {0x5B01, 0x5B01, "0x5B01", "MutexOp", "TermObject", "NameString ByteData", NULL, + "DefMutex := MutexOp NameString SyncFlags"}, + {0x5B02, 0x5B02, "0x5B02", "EventOp", "TermObject", "NameString", NULL, + "DefEvent := EventOp NameString"}, + {0x5B12, 0x5B12, "0x5B12", "CondRefOfOp", "TermObject", "SuperName SuperName", NULL, + "DefCondRefOf := CondRefOfOp SuperName Target"}, + {0x5B13, 0x5B13, "0x5B13", "CreateFieldOp", "TermObject", "TermArg TermArg TermArg NameString", NULL, + "DefCreateField := CreateFieldOp SourceBuff BitIndex NumBits NameString"}, + {0x5B1F, 0x5B1F, "0x5B1F", "LoadTableOp", "TermObject", "TermArg TermArg TermArg TermArg TermArg TermArg", NULL, + "DefLoadTable := LoadTableOp TermArg TermArg TermArg TermArg TermArg TermArg"}, + {0x5B20, 0x5B20, "0x5B20", "LoadOp", "TermObject", "NameString SuperName", NULL, + "DefLoad := LoadOp NameString DdbHandleObject"}, + {0x5B21, 0x5B21, "0x5B21", "StallOp", "TermObject", "TermArg", NULL, + "DefStall := StallOp UsecTime"}, + {0x5B22, 0x5B22, "0x5B22", "SleepOp", "TermObject", "TermArg", NULL, + "DefSleep := SleepOp MsecTime"}, + {0x5B23, 0x5B23, "0x5B23", "AcquireOp", "TermObject", "SuperName WordData", NULL, + "DefAcquire := AcquireOp MutexObject Timeout"}, + {0x5B24, 0x5B24, "0x5B24", "SignalOp", "TermObject", "SuperName", NULL, + "DefSignal := SignalOp EventObject"}, + {0x5B25, 0x5B25, "0x5B25", "WaitOp", "TermObject", "SuperName TermArg", NULL, + "DefWait := WaitOp EventObject Operand"}, + {0x5B26, 0x5B26, "0x5B26", "ResetOp", "TermObject", "SuperName", NULL, + "DefReset := ResetOp EventObject"}, + {0x5B27, 0x5B27, "0x5B27", "ReleaseOp", "TermObject", "SuperName", NULL, + "DefRelease := ReleaseOp MutexObject"}, + {0x5B28, 0x5B28, "0x5B28", "FromBcdOp", "TermObject", "TermArg Target", NULL, + "DefFromBcd := FromBcdOp BcdValue Target"}, + {0x5B29, 0x5B29, "0x5B29", "ToBcd", "TermObject", "TermArg Target", NULL, + "DefToBcd := ToBcdOp Operand Target"}, + {0x5B2A, 0x5B2A, "0x5B2A", "UnloadOp", "TermObject", "SuperName", NULL, + "DefUnload := UnloadOp DdbHandleObject"}, + {0x5B30, 0x5B30, "0x5B30", "RevisionOp", "DataObject", NULL, NULL, + NULL}, + {0x5B31, 0x5B31, "0x5B31", "DebugOp", "DebugObject", NULL, NULL, + NULL}, + {0x5B32, 0x5B32, "0x5B32", "FatalOp", "TermObject", "ByteData DWordData TermArg", NULL, + "DefFatal := FatalOp FatalType FatalCode FatalArg"}, + {0x5B33, 0x5B33, "0x5B33", "TimerOp", "TermObject", NULL, NULL, + "DefTimer := TimerOp"}, + {0x5B80, 0x5B80, "0x5B80", "OperationRegionOp", "TermObject", "NameString ByteData TermArg TermArg", NULL, + "DefOpRegion := OpRegionOp NameString RegionSpace RegionOffset RegionLen"}, + {0x5B81, 0x5B81, "0x5B81", "FieldOp", "TermObject", "NameString ByteData", "FieldList", + "DefField := FieldOp PkgLength NameString FieldFlags FieldList"}, + {0x5B82, 0x5B82, "0x5B82", "DeviceOp", "TermObject", "NameString", "ObjectList", + "DefDevice := DeviceOp PkgLength NameString ObjectList"}, + {0x5B83, 0x5B83, "0x5B83", "ProcessorOp", "TermObject", "NameString ByteData DWordData ByteData", "ObjectList", + "DefProcessor := ProcessorOp PkgLength NameString ProcId PblkAddr PblkLen ObjectList"}, + {0x5B84, 0x5B84, "0x5B84", "PowerResOp", "TermObject", "NameString ByteData WordData", "ObjectList", + "DefPowerRes := PowerResOp PkgLength NameString SystemLevel ResourceOrder ObjectList"}, + {0x5B85, 0x5B85, "0x5B85", "ThermalZoneOp", "TermObject", "NameString", "ObjectList", + "DefThermalZone := ThermalZoneOp PkgLength NameString ObjectList"}, + {0x5B86, 0x5B86, "0x5B86", "IndexFieldOp", "TermObject", "NameString NameString ByteData", "FieldList", + "DefIndexField := IndexFieldOp PkgLength NameString NameString FieldFlags FieldList"}, + {0x5B87, 0x5B87, "0x5B87", "BankFieldOp", "TermObject", "NameString NameString TermArg ByteData", "FieldList", + "DefBankField := BankFieldOp PkgLength NameString NameString BankValue FieldFlags FieldList"}, + {0x5B88, 0x5B88, "0x5B88", "DataRegionOp", "TermObject", "NameString TermArg TermArg TermArg", NULL, + "DefDataRegion := DataRegionOp NameString TermArg TermArg TermArg"}, + {0x5B89, 0x5BFF, "0x5B89-0x5BFF", NULL, NULL, NULL, NULL, + NULL}, + {0x5C, 0x5C, "0x5C", "RootChar", "NameObject", NULL, NULL, + NULL}, + {0x5D, 0x5D, "0x5D", NULL, NULL, NULL, NULL, + NULL}, + {0x5E, 0x5E, "0x5E", "ParentPrefixChar", "NameObject", NULL, NULL, + NULL}, + {0x5F, 0x5F, "0x5F", "NameChar", "NameObject", NULL, NULL, + NULL}, + {0x60, 0x60, "0x60", "Local0Op", "LocalObject", NULL, NULL, + NULL}, + {0x61, 0x61, "0x61", "Local1Op", "LocalObject", NULL, NULL, + NULL}, + {0x62, 0x62, "0x62", "Local2Op", "LocalObject", NULL, NULL, + NULL}, + {0x63, 0x63, "0x63", "Local3Op", "LocalObject", NULL, NULL, + NULL}, + {0x64, 0x64, "0x64", "Local4Op", "LocalObject", NULL, NULL, + NULL}, + {0x65, 0x65, "0x65", "Local5Op", "LocalObject", NULL, NULL, + NULL}, + {0x66, 0x66, "0x66", "Local6Op", "LocalObject", NULL, NULL, + NULL}, + {0x67, 0x67, "0x67", "Local7Op", "LocalObject", NULL, NULL, + NULL}, + {0x68, 0x68, "0x68", "Arg0Op", "ArgObject", NULL, NULL, + NULL}, + {0x69, 0x69, "0x69", "Arg1Op", "ArgObject", NULL, NULL, + NULL}, + {0x6A, 0x6A, "0x6A", "Arg2Op", "ArgObject", NULL, NULL, + NULL}, + {0x6B, 0x6B, "0x6B", "Arg3Op", "ArgObject", NULL, NULL, + NULL}, + {0x6C, 0x6C, "0x6C", "Arg4Op", "ArgObject", NULL, NULL, + NULL}, + {0x6D, 0x6D, "0x6D", "Arg5Op", "ArgObject", NULL, NULL, + NULL}, + {0x6E, 0x6E, "0x6E", "Arg6Op", "ArgObject", NULL, NULL, + NULL}, + {0x6F, 0x6F, "0x6F", NULL, NULL, NULL, NULL, + NULL}, + {0x70, 0x70, "0x70", "StoreOp", "TermObject", "TermArg SuperName", NULL, + "DefStore := StoreOp TermArg SuperName"}, + {0x71, 0x71, "0x71", "RefOfOp", "TermObject", "SuperName ", NULL, + "DefRefOf := RefOfOp SuperName"}, + {0x72, 0x72, "0x72", "AddOp", "TermObject", "TermArg TermArg Target", NULL, + "DefAdd := AddOp Operand Operand Target"}, + {0x73, 0x73, "0x73", "ConcatOp", "TermObject", "TermArg TermArg Target", NULL, + "DefConcat := ConcatOp Data Data Target"}, + {0x74, 0x74, "0x74", "SubtractOp", "TermObject", "TermArg TermArg Target", NULL, + "DefSubtract := SubtractOp Operand Operand Target"}, + {0x75, 0x75, "0x75", "IncrementOp", "TermObject", "SuperName", NULL, + "DefIncrement := IncrementOp SuperName"}, + {0x76, 0x76, "0x76", "DecrementOp", "TermObject", "SuperName", NULL, + "DefDecrement := DecrementOp SuperName"}, + {0x77, 0x77, "0x77", "MultiplyOp", "TermObject", "TermArg TermArg Target", NULL, + "DefMultiply := MultiplyOp Operand Operand Target"}, + {0x78, 0x78, "0x78", "DivideOp", "TermObject", "TermArg TermArg Target Target", NULL, + "DefDivide := DivideOp Dividend Divisor Remainder Quotient"}, + {0x79, 0x79, "0x79", "ShiftLeftOp", "TermObject", "TermArg TermArg Target", NULL, + "DefShiftLeft := ShiftLeftOp Operand ShiftCount Target"}, + {0x7A, 0x7A, "0x7A", "ShiftRightOp", "TermObject", "TermArg TermArg Target", NULL, + "DefShiftRight := ShiftRightOp Operand ShiftCount Target"}, + {0x7B, 0x7B, "0x7B", "AndOp", "TermObject", "TermArg TermArg Target", NULL, + "DefAnd := AndOp Operand Operand Target"}, + {0x7C, 0x7C, "0x7C", "NandOp", "TermObject", "TermArg TermArg Target", NULL, + "DefNand := NandOp Operand Operand Target"}, + {0x7D, 0x7D, "0x7D", "OrOp", "TermObject", "TermArg TermArg Target", NULL, + "DefOr := OrOp Operand Operand Target"}, + {0x7E, 0x7E, "0x7E", "NorOp", "TermObject", "TermArg TermArg Target", NULL, + "DefNor := NorOp Operand Operand Target"}, + {0x7F, 0x7F, "0x7F", "XorOp", "TermObject", "TermArg TermArg Target", NULL, + "DefXor := XorOp Operand Operand Target"}, + {0x80, 0x80, "0x80", "NotOp", "TermObject", "TermArg Target", NULL, + "DefNot := NotOp Operand Target"}, + {0x81, 0x81, "0x81", "FindSetLeftBitOp", "TermObject", "TermArg Target", NULL, + "DefFindSetLeftBit := FindSetLeftBitOp Operand Target"}, + {0x82, 0x82, "0x82", "FindSetRightBitOp", "TermObject", "TermArg Target", NULL, + "DefFindSetRightBit := FindSetRightBitOp Operand Target"}, + {0x83, 0x83, "0x83", "DerefOfOp", "TermObject", "TermArg", NULL, + "DefDerefOf := DerefOfOp ObjReference"}, + {0x84, 0x84, "0x84", "ConcatResOp", "TermObject", "TermArg TermArg Target", NULL, + "DefConcatRes := ConcatResOp BufData BufData Target"}, + {0x85, 0x85, "0x85", "ModOp", "TermObject", "TermArg TermArg Target", NULL, + "DefMod := ModOp Dividend Divisor Target"}, + {0x86, 0x86, "0x86", "NotifyOp", "TermObject", "SuperName TermArg", NULL, + "DefNotify := NotifyOp NotifyObject NotifyValue"}, + {0x87, 0x87, "0x87", "SizeOfOp", "TermObject", "SuperName", NULL, + "DefSizeOf := SizeOfOp SuperName"}, + {0x88, 0x88, "0x88", "IndexOp", "TermObject", "TermArg TermArg Target", NULL, + "DefIndex := IndexOp BuffPkgStrObj IndexValue Target"}, + {0x89, 0x89, "0x89", "MatchOp", "TermObject", "TermArg ByteData TermArg ByteData TermArg TermArg", NULL, + "DefMatch := MatchOp SearchPkg MatchOpcode Operand MatchOpcode Operand StartIndex"}, + {0x8A, 0x8A, "0x8A", "CreateDWordFieldOp", "TermObject", "TermArg TermArg NameString", NULL, + "DefCreateDWordField := CreateDWordFieldOp SourceBuff ByteIndex NameString"}, + {0x8B, 0x8B, "0x8B", "CreateWordFieldOp", "TermObject", "TermArg TermArg NameString", NULL, + "DefCreateWordField := CreateWordFieldOp SourceBuff ByteIndex NameString"}, + {0x8C, 0x8C, "0x8C", "CreateByteFieldOp", "TermObject", "TermArg TermArg NameString", NULL, + "DefCreateByteField := CreateByteFieldOp SourceBuff ByteIndex NameString"}, + {0x8D, 0x8D, "0x8D", "CreateBitFieldOp", "TermObject", "TermArg TermArg NameString", NULL, + "DefCreateBitField := CreateBitFieldOp SourceBuff BitIndex NameString"}, + {0x8E, 0x8E, "0x8E", "ObjectTypeOp", "TermObject", "SuperName", NULL, + "DefObjectType := ObjectTypeOp SuperName"}, + {0x8F, 0x8F, "0x8F", "CreateQWordFieldOp", "TermObject", "TermArg TermArg NameString", NULL, + "DefCreateQWordField := CreateQWordFieldOp SourceBuff ByteIndex NameString"}, + {0x90, 0x90, "0x90", "LAndOp", "TermObject", "TermArg TermArg", NULL, + "DefLAnd := LAndOp Operand Operand"}, + {0x91, 0x91, "0x91", "LOrOp", "TermObject", "TermArg TermArg", NULL, + "DefLOr := LOrOp Operand Operand"}, + {0x92, 0x92, "0x92", "LNotOp", "TermObject", "TermArg", NULL, + "DefLNot := LNotOp Operand"}, + {0x9293, 0x9293, "0x9293", "LNotEqualOp", "TermObject", "TermArg TermArg", NULL, + "DefLNotEqual := LNotEqualOp Operand Operand"}, + {0x9294, 0x9294, "0x9294", "LLessEqualOp", "TermObject", "TermArg TermArg", NULL, + "DefLLessEqual := LLessEqualOp Operand Operand"}, + {0x9295, 0x9295, "0x9295", "LGreaterEqualOp", "TermObject", "TermArg TermArg", NULL, + "DefLGreaterEqual := LGreaterEqualOp Operand Operand"}, + {0x93, 0x93, "0x93", "LEqualOp", "TermObject", "TermArg TermArg", NULL, + "DefLEqual := LEqualOp Operand Operand"}, + {0x94, 0x94, "0x94", "LGreaterOp", "TermObject", "TermArg TermArg", NULL, + "DefLGreater := LGreaterOp Operand Operand"}, + {0x95, 0x95, "0x95", "LLessOp", "TermObject", "TermArg TermArg", NULL, + "DefLLess := LLessOp Operand Operand"}, + {0x96, 0x96, "0x96", "ToBufferOp", "TermObject", "TermArg Target", NULL, + "DefToBuffer := ToBufferOp Operand Target"}, + {0x97, 0x97, "0x97", "ToDecimalStringOp", "TermObject", "TermArg Target", NULL, + "DefToDecimalString := ToDecimalStringOp Operand Target"}, + {0x98, 0x98, "0x98", "ToHexStringOp", "TermObject", "TermArg Target", NULL, + "DefToHexString := ToHexStringOp Operand Target"}, + {0x99, 0x99, "0x99", "ToIntegerOp", "TermObject", "TermArg Target", NULL, + "DefToInteger := ToIntegerOp Operand Target"}, + {0x9A, 0x9B, "0x9A-0x9B", NULL, NULL, NULL, NULL, + NULL}, + {0x9C, 0x9C, "0x9C", "ToStringOp", "TermObject", "TermArg TermArg Target", NULL, + "DefToString := ToStringOp TermArg LengthArg Target"}, + {0x9D, 0x9D, "0x9D", "CopyObjectOp", "TermObject", "TermArg SimpleName", NULL, + "DefCopyObject := CopyObjectOp TermArg SimpleName"}, + {0x9E, 0x9E, "0x9E", "MidOp", "TermObject", "TermArg TermArg TermArg Target", NULL, + "DefMid := MidOp MidObj TermArg TermArg Target"}, + {0x9F, 0x9F, "0x9F", "ContinueOp", "TermObject", NULL, NULL, + "DefContinue := ContinueOp"}, + {0xA0, 0xA0, "0xA0", "IfOp", "TermObject", "TermArg", "TermList", + "DefIfElse := IfOp PkgLength Predicate TermList DefElse"}, + {0xA1, 0xA1, "0xA1", "ElseOp", "TermObject", NULL, "TermList", + "DefElse := Nothing | "}, + {0xA2, 0xA2, "0xA2", "WhileOp", "TermObject", "TermArg", "TermList", + "DefWhile := WhileOp PkgLength Predicate TermList"}, + {0xA3, 0xA3, "0xA3", "NoOpOp", "TermObject", NULL, NULL, + "DefNoOp := NoOpOp"}, + {0xA4, 0xA4, "0xA4", "ReturnOp", "TermObject", "TermArg", NULL, + "DefReturn := ReturnOp ArgObject"}, + {0xA5, 0xA5, "0xA5", "BreakOp", "TermObject", NULL, NULL, + "DefBreak := BreakOp"}, + {0xA6, 0xCB, "0xA6-0xCB", NULL, NULL, NULL, NULL, + NULL}, + {0xCC, 0xCC, "0xCC", "BreakPointOp", "TermObject", NULL, NULL, + "DefBreakPoint := BreakPointOp"}, + {0xCD, 0xFE, "0xCD-0xFE", NULL, NULL, NULL, NULL, + NULL}, + {0xFF, 0xFF, "0xFF", "OnesOp", "DataObject", NULL, NULL, + NULL}, + {0, 0, NULL, NULL, NULL, NULL, NULL, NULL} +}; diff --git a/third_party/lib/acpica/source/tools/acpihelp/ahaslkey.c b/third_party/lib/acpica/source/tools/acpihelp/ahaslkey.c new file mode 100644 index 000000000..62791801f --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpihelp/ahaslkey.c @@ -0,0 +1,192 @@ +/****************************************************************************** + * + * Module Name: ahaslkey - Table of all known ASL non-operator keywords and + * table of iASL Preprocessor directives + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpihelp.h" + +/* + * ASL Keyword types and associated actual keywords. + * This table was extracted from the ACPI specification. + */ +const AH_ASL_KEYWORD AslKeywordInfo[] = +{ + {"AccessAttribKeyword", "Serial Bus Attributes (with legacy SMBus aliases)", + ":= AttribQuick (SMBusQuick) | AttribSendReceive (SMBusSendReceive) | " + "AttribByte (SMBusByte) | AttribWord (SMBusWord) | " + "AttribBlock (SMBusBlock) | AttribProcessCall (SMBusProcessCall) | " + "AttribBlockProcessCall (SMBusProcessCall)"}, + {"AccessTypeKeyword", "Field Access Types", + ":= AnyAcc | ByteAcc | WordAcc | DWordAcc | QWordAcc | BufferAcc"}, + {"AddressingModeKeyword", "Mode - Resource Descriptors", + ":= AddressingMode7Bit | AddressingMode10Bit"}, + {"AddressKeyword", "ACPI memory range types", + ":= AddressRangeMemory | AddressRangeReserved | " + "AddressRangeNVS | AddressRangeACPI"}, + {"AddressSpaceKeyword", "Operation Region Address Space Types", + ":= RegionSpaceKeyword | FFixedHW"}, + {"BusMasterKeyword", "DMA Bus Mastering", + ":= BusMaster | NotBusMaster"}, + {"ByteLengthKeyword", "Bits per Byte - Resource Descriptors", + ":= DataBitsFive | DataBitsSix | DataBitsSeven | DataBitsEight | DataBitsNine"}, + {"ClockPhaseKeyword", "Resource Descriptors", + ":= ClockPhaseFirst | ClockPhaseSecond"}, + {"ClockPolarityKeyword", "Resource Descriptors", + ":= ClockPolarityLow | ClockPolarityHigh"}, + {"DecodeKeyword", "Type of Memory Decoding - Resource Descriptors", + ":= SubDecode | PosDecode"}, + {"DmaTypeKeyword", "DMA Types - DMA Resource Descriptor", + ":= Compatibility | TypeA | TypeB | TypeF"}, + {"EndianKeyword", "Endian type - Resource Descriptor", + ":= BigEndian | LittleEndian"}, + {"ExtendedAttribKeyword", "Extended Bus Attributes", + ":= AttribBytes (AccessLength) | AttribRawBytes (AccessLength) | " + "AttribRawProcessBytes (AccessLength)"}, + {"FlowControlKeyword", "Resource Descriptor", + ":= FlowControlNone | FlowControlXon | FlowControlHardware"}, + {"InterruptLevelKeyword", "Interrupt Active Types", + ":= ActiveHigh | ActiveLow | ActiveBoth"}, + {"InterruptTypeKeyword", "Interrupt Types", + ":= Edge | Level"}, + {"IoDecodeKeyword", "I/O Decoding - IO Resource Descriptor", + ":= Decode16 | Decode10"}, + {"IoRestrictionKeyword", "I/O Restriction - GPIO Resource Descriptors", + ":= IoRestrictionNone | IoRestrictionInputOnly | " + "IoRestrictionOutputOnly | IoRestrictionNoneAndPreserve"}, + {"LockRuleKeyword", "Global Lock use for Field Operator", + ":= Lock | NoLock"}, + {"MatchOpKeyword", "Types for Match Operator", + ":= MTR | MEQ | MLE | MLT | MGE | MGT"}, + {"MaxKeyword", "Max Range Type - Resource Descriptors", + ":= MaxFixed | MaxNotFixed"}, + {"MemTypeKeyword", "Memory Types - Resource Descriptors", + ":= Cacheable | WriteCombining | Prefetchable | NonCacheable"}, + {"MinKeyword", "Min Range Type - Resource Descriptors", + ":= MinFixed | MinNotFixed"}, + {"ObjectTypeKeyword", "ACPI Object Types", + ":= UnknownObj | IntObj | StrObj | BuffObj | PkgObj | FieldUnitObj | " + "DeviceObj | EventObj | MethodObj | MutexObj | OpRegionObj | PowerResObj | " + "ProcessorObj | ThermalZoneObj | BuffFieldObj | DDBHandleObj"}, + {"ParityKeyword", "Resource Descriptors", + ":= ParityTypeNone | ParityTypeSpace | ParityTypeMark | " + "ParityTypeOdd | ParityTypeEven"}, + {"PinConfigKeyword", "Pin Configuration - GPIO Resource Descriptors", + ":= PullDefault | PullUp | PullDown | PullNone"}, + {"PolarityKeyword", "Resource Descriptors", + ":= PolarityHigh | PolarityLow"}, + {"RangeTypeKeyword", "I/O Range Types - Resource Descriptors", + ":= ISAOnlyRanges | NonISAOnlyRanges | EntireRange"}, + {"ReadWriteKeyword", "Memory Access Types - Resource Descriptors", + ":= ReadWrite | ReadOnly"}, + {"RegionSpaceKeyword", "Operation Region Address Space Types", + ":= UserDefRegionSpace | SystemIO | SystemMemory | PCI_Config | " + "EmbeddedControl | SMBus | SystemCMOS | PciBarTarget | IPMI | " + "GeneralPurposeIo, GenericSerialBus"}, + {"ResourceTypeKeyword", "Resource Usage - Resource Descriptors", + ":= ResourceConsumer | ResourceProducer"}, + {"SerializeRuleKeyword", "Control Method Serialization", + ":= Serialized | NotSerialized"}, + {"ShareTypeKeyword", "Interrupt Sharing - Resource Descriptors", + ":= Shared | Exclusive | SharedAndWake | ExclusiveAndWake"}, + {"SlaveModeKeyword", "Resource Descriptors", + ":= ControllerInitiated | DeviceInitiated"}, + {"StopBitsKeyword", "Resource Descriptors", + ":= StopBitsZero | StopBitsOne | StopBitsOnePlusHalf | StopBitsTwo"}, + {"TransferWidthKeyword", "DMA Widths - Fixed DMA Resource Descriptor", + ":= Width8bit | Width16bit | Width32bit | Width64bit | " + "Width128bit | Width256bit"}, + {"TranslationKeyword", "Translation Density Types - Resource Descriptors", + ":= SparseTranslation | DenseTranslation"}, + {"TypeKeyword", "Translation Types - Resource Descriptors", + ":= TypeTranslation | TypeStatic"}, + {"UpdateRuleKeyword", "Field Update Rules", + ":= Preserve | WriteAsOnes | WriteAsZeros"}, + {"UserDefRegionSpace", "User defined address spaces", + ":= IntegerData => 0x80 - 0xFF"}, + {"WireModeKeyword", "SPI Wire Mode - Resource Descriptors", + ":= ThreeWireMode | FourWireMode"}, + {"XferTypeKeyword", "DMA Transfer Types", + ":= Transfer8 | Transfer16 | Transfer8_16"}, + {NULL, NULL, NULL} +}; + +/* Preprocessor directives */ + +const AH_DIRECTIVE_INFO PreprocessorDirectives[] = +{ + {"#include \"Filename\"", "Standard include of an ASCII ASL source code file"}, + {"#include ", "Alternate syntax for #include, alternate search path"}, + {"#includebuffer \"Filename\" ", "Include a binary file to create AML Buffer with ASL namepath"}, + {"#includebuffer ", "Alternate syntax for #includebuffer, alternate search path"}, + + {"", ""}, + {"#define , ", "Simple macro definition (full macros not supported at this time)"}, + {"#define , ","Simple macro definition (full macros not supported at this time)"}, + {"#undef ", "Delete a previous #define"}, + + {"", ""}, + {"#if ", "Evaluate and test return value"}, + {"#ifdef ", "Test existence of the "}, + {"#ifndef ", "Test non-existence of the "}, + {"#elif ", "Else-If contraction - evaluate #if , test return value"}, + {"#else", "Execute alternate case for a previous #if, #ifdef or #ifndef block"}, + {"#endif", "Close a previous #if, #ifdef or #ifndef block"}, + + {"", ""}, + {"#line [Filename]", "Set the current ASL source code line number, optional filename"}, + + {"", ""}, + {"#error \"String\"", "Emit error message and abort compilation"}, + {"#warning \"String\"", "Emit an iASL warning at this location in the ASL source"}, + + {"", ""}, + {"#pragma disable (Error number)", "Disable an iASL error or warning number"}, + {"#pragma message \"String\"", "Emit an informational message to the output file(s)"}, + + {"", ""}, + {"__FILE__", "Return the simple filename of the current ASL file"}, + {"__PATH__", "Return the full pathname of the current ASL file"}, + {"__LINE__", "Return the current line number within the current ASL file"}, + {"__DATE__", "Return the current date"}, + {"__IASL__", "Permanently defined for the iASL compiler"}, + {NULL, NULL} +}; diff --git a/third_party/lib/acpica/source/tools/acpihelp/ahaslops.c b/third_party/lib/acpica/source/tools/acpihelp/ahaslops.c new file mode 100644 index 000000000..9fcca7d1c --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpihelp/ahaslops.c @@ -0,0 +1,425 @@ +/****************************************************************************** + * + * Module Name: ahaslops - Table of all known ASL operators + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpihelp.h" + +/* + * ASL operators with syntax (directly from ACPI specification). + * Note: All tokens require a space separator. + * Long lines are automatically split during output. + */ +const AH_ASL_OPERATOR AslOperatorInfo[] = +{ + {"AccessAs", "(AccessType, AccessAttribKeyword | " + "ExtendedAttribKeyword (AccessLength))", + "ChangeFieldUnitAccess"}, + {"Acquire", "(SyncObject, TimeoutValue) => Boolean", + "Acquire a mutex"}, + {"Add", "(Addend1, Addend2, Result) => Integer", + "Integer Add"}, + {"Alias", "(SourceObject, AliasObject)", + "Define a name alias"}, + {"And", "(Source1, Source2, Result) => Integer", + "Integer Bitwise And"}, + {"Arg", "Arg0 - Arg6", + "Method argument data objects"}, + {"BankField", "(RegionName, BankName, BankValue, " + "AccessTypeKeyword, LockRuleKeyword, " + "UpdateRuleKeyword) {FieldUnitList}", + "Declare fields in a banked configuration object"}, + {"Break", "No parameters", + "Continue following the innermost enclosing While"}, + {"BreakPoint", "No parameters", + "Used for debugging, stops execution in the debugger"}, + {"Buffer", "(BufferSize) {String or ByteList} => Buffer", + "Declare Buffer object"}, + {"Case", "(Value) {TermList}", + "Expression for conditional execution"}, + {"Concatenate", "(Source1, Source2, Result) => ComputationalData", + "Concatenate two strings, integers or buffers"}, + {"ConcatenateResTemplate", "(Source1, Source2, Result) => Buffer", + "Concatenate two resource templates"}, + {"CondRefOf", "(Source, Result) => Boolean", + "Conditional reference to an object"}, + {"Connection", "(ResourceMacro)", + "Associate connection with FieldUnits within a Field object"}, + {"Continue", "No parameters", + "Continue innermost enclosing While loop"}, + {"CopyObject", "(Source, Destination) => DataRefObject", + "Copy and existing object"}, + {"CreateBitField", "(SourceBuffer, BitIndex, BitFieldName)", + "Declare a bit field object of a buffer object"}, + {"CreateByteField", "(SourceBuffer, ByteIndex, ByteFieldName)", + "Declare a byte field object of a buffer object"}, + {"CreateDWordField", "(SourceBuffer, ByteIndex, DWordFieldName)", + "Declare a DWord field object of a buffer object"}, + {"CreateField", "(SourceBuffer, BitIndex, NumBits, FieldName)", + "Declare an arbitrary length bit field of a buffer object"}, + {"CreateQWordField", "(SourceBuffer, ByteIndex, QWordFieldName)", + "Declare a QWord field object of a buffer object"}, + {"CreateWordField", "(SourceBuffer, ByteIndex, WordFieldName)", + "Declare a Word field object of a buffer object"}, + {"DataTableRegion", "(RegionName, SignatureString, OemIDString, OemTableIDString)", + "Declare a Data Table Region"}, + {"Debug", "No parameters", + "Debugger output"}, + {"Decrement", "(Minuend) => Integer", + "Decrement an Integer"}, + {"Default", "{TermList}", + "Default execution path in Switch()"}, + {"DefinitionBlock", "(AmlFileName, TableSignature, ComplianceRevision, " + "OemId, TableId, OemRevision) {TermList}", + "Declare a Definition Block"}, + {"DerefOf", "(Source) => Object", + "Dereference an object reference"}, + {"Device", "(DeviceName) {ObjectList}", + "Declare a bus/device object"}, + {"Divide", "(Dividend, Divisor, Remainder, Result) => Integer", + "Integer Divide"}, + {"Dma", "(DmaTypeKeyword, BusMasterKeyword, XferTypeKeyword, " + "DescriptorName) {DmaChannelList} => Buffer", + "DMA Resource Descriptor macro"}, + {"DWordIo", "(ResourceTypeKeyword, MinKeyword, MaxKeyword, " + "DecodeKeyword, RangeTypeKeyword, AddressGranularity, " + "AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, ResourceSourceIndex, " + "ResourceSource, DescriptorName, TypeKeyword, TranslationKeyword)", + "DWord I/O Resource Descriptor macro"}, + {"DWordMemory", "(ResourceTypeKeyword, DecodeKeyword, MinKeyword, " + "MaxKeyword, MemTypeKeyword, ReadWriteKeyword, " + "AddressGranularity, AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, ResourceSourceIndex, ResourceSource, DescriptorName, AddressKeyword, " + "TypeKeyword)", + "DWord Memory Resource Descriptor macro"}, + {"DWordSpace", "(ResourceType, ResourceTypeKeyword, DecodeKeyword, " + "MinKeyword, MaxKeyword, TypeSpecificFlags, " + "AddressGranularity, AddressMinimum, AddressMaximum, " + "AddressTranslation, RangeLength, " + "ResourceSourceIndex, ResourceSource, DescriptorName)", + "DWord Space Resource Descriptor macro"}, + {"EisaId", "(EisaIdString) => DWordConst", + "EISA ID String to Integer conversion macro"}, + {"Else", "{TermList}", + "Alternate conditional execution"}, + {"ElseIf", "(Predicate)", + "Conditional execution"}, + {"EndDependentFn", "() => Buffer", + "End Dependent Function Resource Descriptor macro"}, + {"Event", "(EventName)", + "Declare an event synchronization object"}, + {"ExtendedIo", "(ResourceTypeKeyword, MinKeyword, MaxKeyword, " + "DecodeKeyword, RangeTypeKeyword, AddressGranularity, " + "AddressMinimum, AddressMaximum, AddressTranslation, RangeLength, " + "TypeSpecificAttributes, DescriptorName, TypeKeyword, TranslationKeyword)", + "Extended I/O Resource Descriptor macro"}, + {"ExtendedMemory", "(ResourceTypeKeyword, DecodeKeyword, MinKeyword, " + "MaxKeyword, MemTypeKeyword, ReadWriteKeyword, " + "AddressGranularity, AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, TypeSpecificAttributes, DescriptorName, " + "AddressKeyword, TypeKeyword)", + "Extended Memory Resource Descriptor macro"}, + {"ExtendedSpace", "(ResourceType, ResourceTypeKeyword, DecodeKeyword, " + "MinKeyword, MaxKeyword, TypeSpecificFlags, " + "AddressGranularity, AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, TypeSpecificAttributes, DescriptorName)", + "Extended Space Resource Descriptor macro"}, + {"External", "(ObjectName, ObjectTypeKeyword, ReturnType, ParameterTypes)", + "Declare external objects"}, + {"Fatal", "(Type, Code, Arg)", + "Fatal error check"}, + {"Field", "(RegionName, AccessTypeKeyword, LockRuleKeyword, " + "UpdateRuleKeyword) {FieldUnitList}", + "Declare fields of an operation region object"}, + {"FindSetLeftBit", "(Source, Result) => Integer", + "Index of first least significant bit set"}, + {"FindSetRightBit", "(Source, Result) => Integer", + "Index of first most significant bit set"}, + {"FixedDma", "(DmaRequestLine, Channel, TransferWidthKeyword, DescriptorName) => Buffer", + "Fixed DMA Resource Descriptor macro"}, + {"FixedIo", "(AddressBase, RangeLength, DescriptorName) => Buffer", + "Fixed I/O Resource Descriptor macro"}, + {"FromBcd", "(BcdValue, Result) => Integer", + "Convert from BCD to numeric"}, + {"Function", "(FunctionName, ReturnType, ParameterTypes) {TermList}", + "Declare control method"}, + {"GpioInt", "(InterruptTypeKeyword, InterruptLevelKeyword, " + "ShareTypeKeyword, PinConfigKeyword, " + "DebounceTimeout, ResourceSource, " + "ResourceSourceIndex, ResourceTypeKeyword, DescriptorName, " + "RawDataBuffer() {VendorData}) {Pin}", + "GPIO Interrupt Connection Resource Descriptor Macro"}, + {"GpioIo", "(ShareTypeKeyword, PinConfigKeyword, DebounceTimeout, DriveStrength, " + "IoRestrictionKeyword, ResourceSource, " + "ResourceSourceIndex, ResourceTypeKeyword, DescriptorName, " + "RawDataBuffer() {VendorData}) {PinList}", + "GPIO I/O Connection Resource Descriptor Macro"}, + {"I2cSerialBus", "(SlaveAddress, SlaveModeKeyword, ConnectionSpeed, " + "AddressingModeKeyword, ResourceSource, " + "ResourceSourceIndex, ResourceTypeKeyword, DescriptorName, " + "RawDataBuffer() {VendorData})", + "I2C Serial Bus Connection Resource Descriptor Macro"}, + {"If", "(Predicate) {TermList}", + "Conditional execution"}, + {"Include", "(FilePathName)", + "Include another ASL file"}, + {"Increment", "(Addend) => Integer", + "Increment a Integer"}, + {"Index", "(Source, Index, Destination) => ObjectReference", + "Indexed Reference to member object"}, + {"IndexField", "(IndexName, DataName, AccessTypeKeyword, LockRuleKeyword, " + "UpdateRuleKeyword) {FieldUnitList}", + "Declare Index/Data Fields"}, + {"Interrupt", "(ResourceTypeKeyword, InterruptTypeKeyword, InterruptLevelKeyword, " + "ShareTypeKeyword, ResourceSourceIndex, " + "ResourceSource, DescriptorName) {InterruptList} => Buffer", + "Interrupt Resource Descriptor macro"}, + {"Io", "(IoDecodeKeyword, AddressMin, AddressMax, AddressAlignment, " + "RangeLength, DescriptorName) => Buffer", + "I/O Resource Descriptor macro"}, + {"Irq", "(InterruptTypeKeyword, InterruptLevelKeyword, ShareTypeKeyword, " + "DescriptorName) {InterruptList} => Buffer", + "Interrupt Resource Descriptor macro"}, + {"IrqNoFlags", "(DescriptorName) {InterruptList} => Buffer", + "Short Interrupt Resource Descriptor macro"}, + {"LAnd", "(Source1, Source2) => Boolean", + "Logical And"}, + {"LEqual", "(Source1, Source2) => Boolean", + "Logical Equal"}, + {"LGreater", "(Source1, Source2) => Boolean", + "Logical Greater"}, + {"LGreaterEqual", "(Source1, Source2) => Boolean", + "Logical Not less"}, + {"LLess", "(Source1, Source2) => Boolean", + "Logical Less"}, + {"LLessEqual", "(Source1, Source2) => Boolean", + "Logical Not greater"}, + {"LNot", "(Source) => Boolean", + "Logical Not"}, + {"LNotEqual", "(Source1, Source2) => Boolean", + "Logical Not equal"}, + {"Load", "(Object, DDBHandle)", + "Load differentiating definition block"}, + {"LoadTable", "(SignatureString, OemIdString, OemTableIdString, RootPathString, " + "ParameterPathString, ParameterData) => DDBHandle", + "Load Table from RSDT/XSDT"}, + {"Local", "Local0 - Local7", + "Method local data objects"}, + {"LOr", "(Source1, Source2) => Boolean", + "Logical Or"}, + {"Match", "(SearchPackage, MatchOpKeyword, MatchObject1, MatchOpKeyword, " + "MatchObject2, StartIndex) => Ones | Integer", + "Search for match in package array"}, + {"Memory24", "(ReadWriteKeyword, AddressMinimum, AddressMaximum, AddressAlignment, " + "RangeLength, DescriptorName)", + "Memory Resource Descriptor macro"}, + {"Memory32", "(ReadWriteKeyword, AddressMinimum, AddressMaximum, AddressAlignment, " + "RangeLength, DescriptorName)", + "Memory Resource Descriptor macro"}, + {"Memory32Fixed", "(ReadWriteKeyword, AddressBase, RangeLength, DescriptorName)", + "Memory Resource Descriptor macro"}, + {"Method", "(MethodName, NumArgs, SerializeRuleKeyword, " + "SyncLevel, ReturnType, ParameterTypes) " + "{TermList}", + "Declare a control method"}, + {"Mid", "(Source, Index, Length, Result) => Buffer or String", + "Return a portion of buffer or string"}, + {"Mod", "(Dividend, Divisor, Result) => Integer", + "Integer Modulo"}, + {"Multiply", "(Multiplicand, Multiplier, Result) => Integer", + "Integer Multiply"}, + {"Mutex", "(MutexName, SyncLevel)", + "Declare a mutex synchronization object"}, + {"Name", "(ObjectName, Object)", + "Declare a Named object"}, + {"NAnd", "(Source1, Source2, Result) => Integer", + "Integer Bitwise Nand"}, + {"NoOp", "No parameters", + "No operation"}, + {"NOr", "(Source1, Source2, Result) => Integer", + "Integer Bitwise Nor"}, + {"Not", "(Source, Result) => Integer", + "Integer Bitwise Not"}, + {"Notify", "(Object, NotificationValue)", + "Notify Object of event"}, + {"ObjectType", "(Object) => Integer", + "Type of object"}, + {"Offset", "(ByteOffset)", + "Change Current Field Unit Offset"}, + {"One", "=> Integer", + "Constant One Object (1)"}, + {"Ones", "=> Integer", + "Constant Ones Object (0xFFFFFFFF or 0xFFFFFFFFFFFFFFFF)"}, + {"OperationRegion", "(RegionName, RegionSpaceKeyword, Offset, Length)", + "Declare an operational region"}, + {"Or", "(Source1, Source2, Result) => Integer", + "Integer Bitwise Or"}, + {"Package", "(NumElements) {PackageList} => Package", + "Declare a package object"}, + {"PowerResource", "(ResourceName, SystemLevel, ResourceOrder) {ObjectList}", + "Declare a power resource object"}, + {"Processor", "(ProcessorName, ProcessorID, PBlockAddress, PblockLength) {ObjectList}", + "Declare a processor package"}, + {"QWordIo", "(ResourceTypeKeyword, MinKeyword, MaxKeyword, DecodeKeyword, " + "RangeTypeKeyword, AddressGranularity, " + "AddressMinimum, AddressMaximum, AddressTranslation, RangeLength, " + "ResourceSourceIndex, ResourceSource, DescriptorName, TypeKeyword, " + "TranslationKeyword)", + "QWord I/O Resource Descriptor macro"}, + {"QWordMemory", "(ResourceTypeKeyword, DecodeKeyword, MinKeyword, MaxKeyword, " + "MemTypeKeyword, ReadWriteKeyword, " + "AddressGranularity, AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, ResourceSourceIndex, ResourceSource, " + "DescriptorName, AddressKeyword, " + "TypeKeyword)", + "QWord Memory Resource Descriptor macro"}, + {"QWordSpace", "(ResourceType, ResourceTypeKeyword, DecodeKeyword, " + "MinKeyword, MaxKeyword, TypeSpecificFlags, " + "AddressGranularity, AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, ResourceSourceIndex, ResourceSource, DescriptorName)", + "Qword Space Resource Descriptor macro"}, + {"RawDataBuffer", "(BufferSize) {ByteList} => RawDataBuffer", + "Create a raw data buffer (does not use Buffer AML opcode)"}, + {"RefOf", "(Object) => ObjectReference", + "Create Reference to an object"}, + {"Register", "(AddressSpaceKeyword, RegisterBitWidth, " + "RegisterBitOffset, RegisterAddress, " + "AccessSize, DescriptorName)", + "Generic register Resource Descriptor macro"}, + {"Release", "(SyncObject)", + "Release a synchronization object"}, + {"Reset", "(SyncObject)", + "Reset a synchronization object"}, + {"ResourceTemplate", "() {ResourceMacroList} => Buffer", + "Resource to buffer conversion macro"}, + {"Return", "None | () | (ReturnArg)", + "Return from method execution"}, + {"Revision", "=> Integer", + "Constant revision object"}, + {"Scope", "(Location) {ObjectList}", + "Open named scope "}, + {"ShiftLeft", "(Source, ShiftCount, Result) => Integer", + "Integer shift value left"}, + {"ShiftRight", "(Source, ShiftCount, Result) => Integer", + "Integer shift value right"}, + {"Signal", "(SyncObject)", + "Signal a synchronization object"}, + {"SizeOf", "(ObjectName) => Integer", + "Get the size of a buffer}, string}, or package"}, + {"Sleep", "(Milliseconds)", + "Sleep n milliseconds (yields the processor)"}, + {"SpiSerialBus", "(DeviceSelection, PolarityKeyword, WireModeKeyword, " + "DataBitLength, SlaveModeKeyword, " + "ConnectionSpeed, ClockPolarityKeyword, ClockPhaseKeyword, " + "ResourceSource, ResourceSourceIndex, " + "ResourceTypeKeyword, DescriptorName, RawDataBuffer() {VendorData})", + "SPI Serial Bus Connection Resource Descriptor Macro"}, + {"Stall", "(Microseconds)", + "Delay n microseconds (does not yield the processor)"}, + {"StartDependentFn", "(CompatibilityPriority, PerformancePriority) {ResourceList}", + "Start Dependent Function Resource Descriptor macro"}, + {"StartDependentFnNoPri", "() {ResourceList}", + "Start Dependent Function Resource Descriptor macro"}, + {"Store", "(Source, Destination) => DataRefObject", + "Store object"}, + {"Subtract", "(Minuend, Subtrahend, Result) => Integer", + "Integer Subtract"}, + {"Switch", "(Expression) {CaseTermList}", + "Select code to execute based on expression value"}, + {"ThermalZone", "(ThermalZoneName) {ObjectList}", + "Declare a thermal zone package"}, + {"Timer", "=> Integer", + "Get 64-bit timer value"}, + {"ToBcd", "(Value, Result) => Integer", + "Convert Integer to BCD"}, + {"ToBuffer", "(Data, Result) => Buffer", + "Convert data type to buffer"}, + {"ToDecimalString", "(Data, Result) => String", + "Convert data type to decimal string"}, + {"ToHexString", "(Data, Result) => String", + "Convert data type to hexadecimal string"}, + {"ToInteger", "(Data, Result) => Integer", + "Convert data type to integer"}, + {"ToString", "(Source, Length, Result) => String", + "Copy ASCII string from buffer"}, + {"ToUuid", "(AsciiString) => Buffer", + "Convert Ascii string to UUID"}, + {"UartSerialBus", "(ConnectionSpeed, ByteLengthKeyword, StopBitsKeyword, " + "LinesInUse, EndianKeyword, ParityKeyword, " + "FlowControlKeyword, ReceiveBufferSize, TransmitBufferSize, ResourceSource, " + "ResourceSourceIndex, ResourceTypeKeyword, DescriptorName, " + "RawDataBuffer() {VendorData})", + "UART Serial Bus Connection Resource Descriptor Macro"}, + {"Unicode", "(String) => Buffer", + "String to Unicode conversion macro"}, + {"Unload", "(Handle)", + "Unload definition block"}, + {"VendorLong", "(DescriptorName) {VendorByteList}", + "Vendor Resource Descriptor"}, + {"VendorShort", "(DescriptorName) {VendorByteList}", + "Vendor Resource Descriptor"}, + {"Wait", "(SyncObject, TimeoutValue) => Boolean", + "Wait on an Event"}, + {"While", "(Predicate) {TermList}", + "Conditional loop"}, + {"WordBusNumber", "(ResourceTypeKeyword, MinKeyword, MaxKeyword, DecodeKeyword, " + "AddressGranularity, AddressMinimum, " + "AddressMaximum, AddressTranslation, RangeLength, ResourceSourceIndex, " + "ResourceSource, DescriptorName)", + "Word Bus number Resource Descriptor macro"}, + {"WordIo", "(ResourceTypeKeyword, MinKeyword, MaxKeyword, DecodeKeyword, " + "RangeTypeKeyword, AddressGranularity, " + "AddressMinimum, AddressMaximum, AddressTranslation, RangeLength, " + "ResourceSourceIndex, ResourceSource, DescriptorName, TypeKeyword, " + "TranslationKeyword)", + "Word I/O Resource Descriptor macro"}, + {"WordSpace", "(ResourceType, ResourceTypeKeyword, DecodeKeyword, MinKeyword, " + "MaxKeyword, TypeSpecificFlags, " + "AddressGranularity, AddressMinimum, AddressMaximum, AddressTranslation, " + "RangeLength, ResourceSourceIndex, ResourceSource, DescriptorName)", + "Word Space Resource Descriptor macro"}, + {"Xor", "(Source1, Source2, Result) => Integer", + "Integer Bitwise Xor"}, + {"Zero", "=> Integer", + "Constant Zero object (0)"}, + {NULL, NULL, NULL} +}; diff --git a/third_party/lib/acpica/source/tools/acpihelp/ahdecode.c b/third_party/lib/acpica/source/tools/acpihelp/ahdecode.c new file mode 100644 index 000000000..ec22e4964 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpihelp/ahdecode.c @@ -0,0 +1,1064 @@ +/****************************************************************************** + * + * Module Name: ahdecode - Operator/Opcode decoding for acpihelp utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define ACPI_CREATE_PREDEFINED_TABLE +#define ACPI_CREATE_RESOURCE_TABLE + +#include "acpihelp.h" +#include "acpredef.h" + + +#define AH_DISPLAY_EXCEPTION(Status, Name) \ + printf ("%.4X: %s\n", Status, Name) + +#define AH_DISPLAY_EXCEPTION_TEXT(Status, Exception) \ + printf ("%.4X: %-28s (%s)\n", Status, Exception->Name, Exception->Description) + +#define BUFFER_LENGTH 128 +#define LINE_BUFFER_LENGTH 512 + +static char Gbl_Buffer[BUFFER_LENGTH]; +static char Gbl_LineBuffer[LINE_BUFFER_LENGTH]; + + +/* Local prototypes */ + +static BOOLEAN +AhDisplayPredefinedName ( + char *Name, + UINT32 Length); + +static void +AhDisplayPredefinedInfo ( + char *Name); + +static void +AhDisplayResourceName ( + const ACPI_PREDEFINED_INFO *ThisName); + +static void +AhDisplayAmlOpcode ( + const AH_AML_OPCODE *Op); + +static void +AhDisplayAslOperator ( + const AH_ASL_OPERATOR *Op); + +static void +AhDisplayOperatorKeywords ( + const AH_ASL_OPERATOR *Op); + +static void +AhDisplayAslKeyword ( + const AH_ASL_KEYWORD *Op); + +static void +AhPrintOneField ( + UINT32 Indent, + UINT32 CurrentPosition, + UINT32 MaxPosition, + const char *Field); + + +/******************************************************************************* + * + * FUNCTION: AhDisplayDirectives + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display all iASL preprocessor directives. + * + ******************************************************************************/ + +void +AhDisplayDirectives ( + void) +{ + const AH_DIRECTIVE_INFO *Info; + + + printf ("iASL Preprocessor Directives\n\n"); + + for (Info = PreprocessorDirectives; Info->Name; Info++) + { + printf (" %-36s : %s\n", Info->Name, Info->Description); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhFindPredefinedNames (entry point for predefined name search) + * + * PARAMETERS: NamePrefix - Name or prefix to find. Must start with + * an underscore. NULL means "find all" + * + * RETURN: None + * + * DESCRIPTION: Find and display all ACPI predefined names that match the + * input name or prefix. Includes the required number of arguments + * and the expected return type, if any. + * + ******************************************************************************/ + +void +AhFindPredefinedNames ( + char *NamePrefix) +{ + UINT32 Length; + BOOLEAN Found; + char Name[9]; + + + if (!NamePrefix) + { + Found = AhDisplayPredefinedName (NULL, 0); + return; + } + + /* Contruct a local name or name prefix */ + + AcpiUtStrupr (NamePrefix); + if (*NamePrefix == '_') + { + NamePrefix++; + } + + Name[0] = '_'; + strncpy (&Name[1], NamePrefix, 7); + + Length = strlen (Name); + if (Length > ACPI_NAME_SIZE) + { + printf ("%.8s: Predefined name must be 4 characters maximum\n", Name); + return; + } + + Found = AhDisplayPredefinedName (Name, Length); + if (!Found) + { + printf ("%s, no matching predefined names\n", Name); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayPredefinedName + * + * PARAMETERS: Name - Name or name prefix + * + * RETURN: TRUE if any names matched, FALSE otherwise + * + * DESCRIPTION: Display information about ACPI predefined names that match + * the input name or name prefix. + * + ******************************************************************************/ + +static BOOLEAN +AhDisplayPredefinedName ( + char *Name, + UINT32 Length) +{ + const AH_PREDEFINED_NAME *Info; + BOOLEAN Found = FALSE; + BOOLEAN Matched; + UINT32 i = 0; + + + /* Find/display all names that match the input name prefix */ + + for (Info = AslPredefinedInfo; Info->Name; Info++) + { + if (!Name) + { + Found = TRUE; + printf ("%s: <%s>\n", Info->Name, Info->Description); + printf ("%*s%s\n", 6, " ", Info->Action); + + AhDisplayPredefinedInfo (Info->Name); + i++; + continue; + } + + Matched = TRUE; + for (i = 0; i < Length; i++) + { + if (Info->Name[i] != Name[i]) + { + Matched = FALSE; + break; + } + } + + if (Matched) + { + Found = TRUE; + printf ("%s: <%s>\n", Info->Name, Info->Description); + printf ("%*s%s\n", 6, " ", Info->Action); + + AhDisplayPredefinedInfo (Info->Name); + } + } + + if (!Name) + { + printf ("\nFound %d Predefined ACPI Names\n", i); + } + return (Found); +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayPredefinedInfo + * + * PARAMETERS: Name - Exact 4-character ACPI name. + * + * RETURN: None + * + * DESCRIPTION: Find the name in the main ACPICA predefined info table and + * display the # of arguments and the return value type. + * + * Note: Resource Descriptor field names do not appear in this + * table -- thus, nothing will be displayed for them. + * + ******************************************************************************/ + +static void +AhDisplayPredefinedInfo ( + char *Name) +{ + const ACPI_PREDEFINED_INFO *ThisName; + + + /* NOTE: we check both tables always because there are some dupes */ + + /* Check against the predefine methods first */ + + ThisName = AcpiUtMatchPredefinedMethod (Name); + if (ThisName) + { + AcpiUtDisplayPredefinedMethod (Gbl_Buffer, ThisName, TRUE); + } + + /* Check against the predefined resource descriptor names */ + + ThisName = AcpiUtMatchResourceName (Name); + if (ThisName) + { + AhDisplayResourceName (ThisName); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayResourceName + * + * PARAMETERS: ThisName - Entry in the predefined method/name table + * + * RETURN: None + * + * DESCRIPTION: Display information about a resource descriptor name. + * + ******************************************************************************/ + +static void +AhDisplayResourceName ( + const ACPI_PREDEFINED_INFO *ThisName) +{ + UINT32 NumTypes; + + + NumTypes = AcpiUtGetResourceBitWidth (Gbl_Buffer, + ThisName->Info.ArgumentList); + + printf (" %4.4s resource descriptor field is %s bits wide%s\n", + ThisName->Info.Name, + Gbl_Buffer, + (NumTypes > 1) ? " (depending on descriptor type)" : ""); +} + + +/******************************************************************************* + * + * FUNCTION: AhFindAmlOpcode (entry point for AML opcode name search) + * + * PARAMETERS: Name - Name or prefix for an AML opcode. + * NULL means "find all" + * + * RETURN: None + * + * DESCRIPTION: Find all AML opcodes that match the input Name or name + * prefix. + * + ******************************************************************************/ + +void +AhFindAmlOpcode ( + char *Name) +{ + const AH_AML_OPCODE *Op; + BOOLEAN Found = FALSE; + + + AcpiUtStrupr (Name); + + /* Find/display all opcode names that match the input name prefix */ + + for (Op = AmlOpcodeInfo; Op->OpcodeString; Op++) + { + if (!Op->OpcodeName) /* Unused opcodes */ + { + continue; + } + + if (!Name) + { + AhDisplayAmlOpcode (Op); + Found = TRUE; + continue; + } + + /* Upper case the opcode name before substring compare */ + + strcpy (Gbl_Buffer, Op->OpcodeName); + AcpiUtStrupr (Gbl_Buffer); + + if (strstr (Gbl_Buffer, Name) == Gbl_Buffer) + { + AhDisplayAmlOpcode (Op); + Found = TRUE; + } + } + + if (!Found) + { + printf ("%s, no matching AML operators\n", Name); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDecodeAmlOpcode (entry point for AML opcode search) + * + * PARAMETERS: OpcodeString - String version of AML opcode + * + * RETURN: None + * + * DESCRIPTION: Display information about the input AML opcode + * + ******************************************************************************/ + +void +AhDecodeAmlOpcode ( + char *OpcodeString) +{ + const AH_AML_OPCODE *Op; + UINT32 Opcode; + UINT8 Prefix; + + + if (!OpcodeString) + { + AhFindAmlOpcode (NULL); + return; + } + + Opcode = strtoul (OpcodeString, NULL, 16); + if (Opcode > ACPI_UINT16_MAX) + { + printf ("Invalid opcode (more than 16 bits)\n"); + return; + } + + /* Only valid opcode extension is 0x5B */ + + Prefix = (Opcode & 0x0000FF00) >> 8; + if (Prefix && (Prefix != 0x5B)) + { + printf ("Invalid opcode (invalid extension prefix 0x%X)\n", + Prefix); + return; + } + + /* Find/Display the opcode. May fall within an opcode range */ + + for (Op = AmlOpcodeInfo; Op->OpcodeString; Op++) + { + if ((Opcode >= Op->OpcodeRangeStart) && + (Opcode <= Op->OpcodeRangeEnd)) + { + AhDisplayAmlOpcode (Op); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayAmlOpcode + * + * PARAMETERS: Op - An opcode info struct + * + * RETURN: None + * + * DESCRIPTION: Display the contents of an AML opcode information struct + * + ******************************************************************************/ + +static void +AhDisplayAmlOpcode ( + const AH_AML_OPCODE *Op) +{ + + if (!Op->OpcodeName) + { + printf ("%18s: Opcode=%-9s\n", "Reserved opcode", Op->OpcodeString); + return; + } + + /* Opcode name and value(s) */ + + printf ("%18s: Opcode=%-9s Type (%s)", + Op->OpcodeName, Op->OpcodeString, Op->Type); + + /* Optional fixed/static arguments */ + + if (Op->FixedArguments) + { + printf (" FixedArgs ("); + AhPrintOneField (37, 36 + 7 + strlen (Op->Type) + 12, + AH_MAX_AML_LINE_LENGTH, Op->FixedArguments); + printf (")"); + } + + /* Optional variable-length argument list */ + + if (Op->VariableArguments) + { + if (Op->FixedArguments) + { + printf ("\n%*s", 36, " "); + } + printf (" VariableArgs ("); + AhPrintOneField (37, 15, AH_MAX_AML_LINE_LENGTH, Op->VariableArguments); + printf (")"); + } + printf ("\n"); + + /* Grammar specification */ + + if (Op->Grammar) + { + AhPrintOneField (37, 0, AH_MAX_AML_LINE_LENGTH, Op->Grammar); + printf ("\n"); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhFindAslKeywords (entry point for ASL keyword search) + * + * PARAMETERS: Name - Name or prefix for an ASL keyword. + * NULL means "find all" + * + * RETURN: None + * + * DESCRIPTION: Find all ASL keywords that match the input Name or name + * prefix. + * + ******************************************************************************/ + +void +AhFindAslKeywords ( + char *Name) +{ + const AH_ASL_KEYWORD *Keyword; + BOOLEAN Found = FALSE; + + + AcpiUtStrupr (Name); + + for (Keyword = AslKeywordInfo; Keyword->Name; Keyword++) + { + if (!Name) + { + AhDisplayAslKeyword (Keyword); + Found = TRUE; + continue; + } + + /* Upper case the operator name before substring compare */ + + strcpy (Gbl_Buffer, Keyword->Name); + AcpiUtStrupr (Gbl_Buffer); + + if (strstr (Gbl_Buffer, Name) == Gbl_Buffer) + { + AhDisplayAslKeyword (Keyword); + Found = TRUE; + } + } + + if (!Found) + { + printf ("%s, no matching ASL keywords\n", Name); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayAslKeyword + * + * PARAMETERS: Op - Pointer to ASL keyword with syntax info + * + * RETURN: None + * + * DESCRIPTION: Format and display syntax info for an ASL keyword. Splits + * long lines appropriately for reading. + * + ******************************************************************************/ + +static void +AhDisplayAslKeyword ( + const AH_ASL_KEYWORD *Op) +{ + + /* ASL keyword name and description */ + + printf ("%22s: %s\n", Op->Name, Op->Description); + if (!Op->KeywordList) + { + return; + } + + /* List of actual keywords */ + + AhPrintOneField (24, 0, AH_MAX_ASL_LINE_LENGTH, Op->KeywordList); + printf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AhFindAslAndAmlOperators + * + * PARAMETERS: Name - Name or prefix for an ASL operator. + * NULL means "find all" + * + * RETURN: None + * + * DESCRIPTION: Find all ASL operators that match the input Name or name + * prefix. Also displays the AML information if only one entry + * matches. + * + ******************************************************************************/ + +void +AhFindAslAndAmlOperators ( + char *Name) +{ + UINT32 MatchCount; + + + MatchCount = AhFindAslOperators (Name); + if (MatchCount == 1) + { + AhFindAmlOpcode (Name); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhFindAslOperators (entry point for ASL operator search) + * + * PARAMETERS: Name - Name or prefix for an ASL operator. + * NULL means "find all" + * + * RETURN: Number of operators that matched the name prefix. + * + * DESCRIPTION: Find all ASL operators that match the input Name or name + * prefix. + * + ******************************************************************************/ + +UINT32 +AhFindAslOperators ( + char *Name) +{ + const AH_ASL_OPERATOR *Operator; + BOOLEAN MatchCount = 0; + + + AcpiUtStrupr (Name); + + /* Find/display all names that match the input name prefix */ + + for (Operator = AslOperatorInfo; Operator->Name; Operator++) + { + if (!Name) + { + AhDisplayAslOperator (Operator); + MatchCount++; + continue; + } + + /* Upper case the operator name before substring compare */ + + strcpy (Gbl_Buffer, Operator->Name); + AcpiUtStrupr (Gbl_Buffer); + + if (strstr (Gbl_Buffer, Name) == Gbl_Buffer) + { + AhDisplayAslOperator (Operator); + MatchCount++; + } + } + + if (!MatchCount) + { + printf ("%s, no matching ASL operators\n", Name); + } + + return (MatchCount); +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayAslOperator + * + * PARAMETERS: Op - Pointer to ASL operator with syntax info + * + * RETURN: None + * + * DESCRIPTION: Format and display syntax info for an ASL operator. Splits + * long lines appropriately for reading. + * + ******************************************************************************/ + +static void +AhDisplayAslOperator ( + const AH_ASL_OPERATOR *Op) +{ + + /* ASL operator name and description */ + + printf ("%16s: %s\n", Op->Name, Op->Description); + if (!Op->Syntax) + { + return; + } + + /* Syntax for the operator */ + + AhPrintOneField (18, 0, AH_MAX_ASL_LINE_LENGTH, Op->Syntax); + printf ("\n"); + + AhDisplayOperatorKeywords (Op); + printf ("\n"); +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayOperatorKeywords + * + * PARAMETERS: Op - Pointer to ASL keyword with syntax info + * + * RETURN: None + * + * DESCRIPTION: Display any/all keywords that are associated with the ASL + * operator. + * + ******************************************************************************/ + +static void +AhDisplayOperatorKeywords ( + const AH_ASL_OPERATOR *Op) +{ + char *Token; + char *Separators = "(){}, "; + BOOLEAN FirstKeyword = TRUE; + + + if (!Op || !Op->Syntax) + { + return; + } + + /* + * Find all parameters that have the word "keyword" within, and then + * display the info about that keyword + */ + strcpy (Gbl_LineBuffer, Op->Syntax); + Token = strtok (Gbl_LineBuffer, Separators); + while (Token) + { + if (strstr (Token, "Keyword")) + { + if (FirstKeyword) + { + printf ("\n"); + FirstKeyword = FALSE; + } + + /* Found a keyword, display keyword information */ + + AhFindAslKeywords (Token); + } + + Token = strtok (NULL, Separators); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhPrintOneField + * + * PARAMETERS: Indent - Indent length for new line(s) + * CurrentPosition - Position on current line + * MaxPosition - Max allowed line length + * Field - Data to output + * + * RETURN: Line position after field is written + * + * DESCRIPTION: Split long lines appropriately for ease of reading. + * + ******************************************************************************/ + +static void +AhPrintOneField ( + UINT32 Indent, + UINT32 CurrentPosition, + UINT32 MaxPosition, + const char *Field) +{ + UINT32 Position; + UINT32 TokenLength; + const char *This; + const char *Next; + const char *Last; + + + This = Field; + Position = CurrentPosition; + + if (Position == 0) + { + printf ("%*s", (int) Indent, " "); + Position = Indent; + } + + Last = This + strlen (This); + while ((Next = strpbrk (This, " "))) + { + TokenLength = Next - This; + Position += TokenLength; + + /* Split long lines */ + + if (Position > MaxPosition) + { + printf ("\n%*s", (int) Indent, " "); + Position = TokenLength; + } + + printf ("%.*s ", (int) TokenLength, This); + This = Next + 1; + } + + /* Handle last token on the input line */ + + TokenLength = Last - This; + if (TokenLength > 0) + { + Position += TokenLength; + if (Position > MaxPosition) + { + printf ("\n%*s", (int) Indent, " "); + } + + printf ("%s", This); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayDeviceIds + * + * PARAMETERS: Name - Device Hardware ID string. + * NULL means "find all" + * + * RETURN: None + * + * DESCRIPTION: Display PNP* and ACPI* device IDs. + * + ******************************************************************************/ + +void +AhDisplayDeviceIds ( + char *Name) +{ + const AH_DEVICE_ID *Info; + UINT32 Length; + BOOLEAN Matched; + UINT32 i; + BOOLEAN Found = FALSE; + + + /* Null input name indicates "display all" */ + + if (!Name) + { + printf ("ACPI and PNP Device/Hardware IDs:\n\n"); + for (Info = AslDeviceIds; Info->Name; Info++) + { + printf ("%8s %s\n", Info->Name, Info->Description); + } + + return; + } + + Length = strlen (Name); + if (Length > 8) + { + printf ("%.8s: Hardware ID must be 8 characters maximum\n", Name); + return; + } + + /* Find/display all names that match the input name prefix */ + + AcpiUtStrupr (Name); + for (Info = AslDeviceIds; Info->Name; Info++) + { + Matched = TRUE; + for (i = 0; i < Length; i++) + { + if (Info->Name[i] != Name[i]) + { + Matched = FALSE; + break; + } + } + + if (Matched) + { + Found = TRUE; + printf ("%8s %s\n", Info->Name, Info->Description); + } + } + + if (!Found) + { + printf ("%s, Hardware ID not found\n", Name); + } +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayUuids + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display all known UUIDs. + * + ******************************************************************************/ + +void +AhDisplayUuids ( + void) +{ + const AH_UUID *Info; + + + printf ("ACPI-related UUIDs/GUIDs:\n"); + + /* Display entire table of known ACPI-related UUIDs/GUIDs */ + + for (Info = AcpiUuids; Info->Description; Info++) + { + if (!Info->String) /* Null UUID string means group description */ + { + printf ("\n%36s\n", Info->Description); + } + else + { + printf ("%32s : %s\n", Info->Description, Info->String); + } + } + + /* Help info on how UUIDs/GUIDs strings are encoded */ + + printf ("\n\nByte encoding of UUID/GUID strings" + " into ACPI Buffer objects (use ToUUID from ASL):\n\n"); + + printf ("%32s : %s\n", "Input UUID/GUID String format", + "aabbccdd-eeff-gghh-iijj-kkllmmnnoopp"); + + printf ("%32s : %s\n", "Expected output ACPI buffer", + "dd,cc,bb,aa, ff,ee, hh,gg, ii,jj, kk,ll,mm,nn,oo,pp"); +} + + +/******************************************************************************* + * + * FUNCTION: AhDisplayTables + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Display all known ACPI tables + * + ******************************************************************************/ + +void +AhDisplayTables ( + void) +{ + const AH_TABLE *Info; + UINT32 i = 0; + + + printf ("Known ACPI tables:\n"); + + for (Info = AcpiSupportedTables; Info->Signature; Info++) + { + printf ("%8s : %s\n", Info->Signature, Info->Description); + i++; + } + + printf ("\nTotal %u ACPI tables\n\n", i); +} + + +/******************************************************************************* + * + * FUNCTION: AhDecodeException + * + * PARAMETERS: HexString - ACPI status string from command line, in + * hex. If null, display all exceptions. + * + * RETURN: None + * + * DESCRIPTION: Decode and display an ACPI_STATUS exception code. + * + ******************************************************************************/ + +void +AhDecodeException ( + char *HexString) +{ + const ACPI_EXCEPTION_INFO *ExceptionInfo; + UINT32 Status; + UINT32 i; + + + /* + * A null input string means to decode and display all known + * exception codes. + */ + if (!HexString) + { + printf ("All defined ACPICA exception codes:\n\n"); + AH_DISPLAY_EXCEPTION (0, + "AE_OK (No error occurred)"); + + /* Display codes in each block of exception types */ + + for (i = 1; (i & AE_CODE_MASK) <= AE_CODE_MAX; i += 0x1000) + { + Status = i; + do + { + ExceptionInfo = AcpiUtValidateException ((ACPI_STATUS) Status); + if (ExceptionInfo) + { + AH_DISPLAY_EXCEPTION_TEXT (Status, ExceptionInfo); + } + + Status++; + + } while (ExceptionInfo); + } + return; + } + + /* Decode a single user-supplied exception code */ + + Status = strtoul (HexString, NULL, 16); + if (!Status) + { + printf ("%s: Invalid hexadecimal exception code value\n", HexString); + return; + } + + if (Status > ACPI_UINT16_MAX) + { + AH_DISPLAY_EXCEPTION (Status, "Invalid exception code (more than 16 bits)"); + return; + } + + ExceptionInfo = AcpiUtValidateException ((ACPI_STATUS) Status); + if (!ExceptionInfo) + { + AH_DISPLAY_EXCEPTION (Status, "Unknown exception code"); + return; + } + + AH_DISPLAY_EXCEPTION_TEXT (Status, ExceptionInfo); +} diff --git a/third_party/lib/acpica/source/tools/acpihelp/ahmain.c b/third_party/lib/acpica/source/tools/acpihelp/ahmain.c new file mode 100644 index 000000000..4538ae4ea --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpihelp/ahmain.c @@ -0,0 +1,280 @@ +/****************************************************************************** + * + * Module Name: ahmain - Main module for the acpi help utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpihelp.h" + + +/* Local prototypes */ + +static void +AhDisplayUsage ( + void); + +#define AH_UTILITY_NAME "ACPI Help Utility" +#define AH_SUPPORTED_OPTIONS "adehikmopstuv" + + +/****************************************************************************** + * + * FUNCTION: AhDisplayUsage + * + * DESCRIPTION: Usage message + * + ******************************************************************************/ + +static void +AhDisplayUsage ( + void) +{ + + ACPI_USAGE_HEADER ("acpihelp [Name/Prefix | HexValue]"); + ACPI_OPTION ("-h", "Display help"); + ACPI_OPTION ("-v", "Display version information"); + + ACPI_USAGE_TEXT ("\nAML (ACPI Machine Language) Names and Encodings:\n"); + ACPI_OPTION ("-a [Name/Prefix]", "Find/Display both ASL operator and AML opcode name(s)"); + ACPI_OPTION ("-m [Name/Prefix]", "Find/Display AML opcode name(s)"); + + ACPI_USAGE_TEXT ("\nACPI Values:\n"); + ACPI_OPTION ("-e [HexValue]", "Decode ACPICA exception code"); + ACPI_OPTION ("-o [HexValue]", "Decode hex AML opcode"); + + ACPI_USAGE_TEXT ("\nASL (ACPI Source Language) Names and Symbols:\n"); + ACPI_OPTION ("-k [Name/Prefix]", "Find/Display ASL non-operator keyword(s)"); + ACPI_OPTION ("-p [Name/Prefix]", "Find/Display ASL predefined method name(s)"); + ACPI_OPTION ("-s [Name/Prefix]", "Find/Display ASL operator name(s)"); + + ACPI_USAGE_TEXT ("\nOther ACPI Names:\n"); + ACPI_OPTION ("-i [Name/Prefix]", "Find/Display ACPI/PNP Hardware ID(s)"); + ACPI_OPTION ("-d", "Display iASL Preprocessor directives"); + ACPI_OPTION ("-t", "Display supported ACPI tables"); + ACPI_OPTION ("-u", "Display ACPI-related UUIDs"); + + ACPI_USAGE_TEXT ("\nName/Prefix or HexValue not specified means \"Display All\"\n"); + ACPI_USAGE_TEXT ("\nDefault search with valid Name/Prefix and no options:\n"); + ACPI_USAGE_TEXT (" Find ASL/AML operator names - if NamePrefix does not start with underscore\n"); + ACPI_USAGE_TEXT (" Find ASL predefined method names - if NamePrefix starts with underscore\n"); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * DESCRIPTION: C main function for AcpiHelp utility. + * + ******************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char *argv[]) +{ + char *Name; + UINT32 DecodeType; + int j; + + + AcpiOsInitialize (); + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + printf (ACPI_COMMON_SIGNON (AH_UTILITY_NAME)); + DecodeType = AH_DECODE_DEFAULT; + + if (argc < 2) + { + AhDisplayUsage (); + return (0); + } + + /* Command line options */ + + while ((j = AcpiGetopt (argc, argv, AH_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch (j) + { + case 'a': + + DecodeType = AH_DECODE_ASL_AML; + break; + + case 'd': + + DecodeType = AH_DISPLAY_DIRECTIVES; + break; + + case 'e': + + DecodeType = AH_DECODE_EXCEPTION; + break; + + case 'i': + + DecodeType = AH_DISPLAY_DEVICE_IDS; + break; + + case 'k': + + DecodeType = AH_DECODE_ASL_KEYWORD; + break; + + case 'm': + + DecodeType = AH_DECODE_AML; + break; + + case 'o': + + DecodeType = AH_DECODE_AML_OPCODE; + break; + + case 'p': + + DecodeType = AH_DECODE_PREDEFINED_NAME; + break; + + case 's': + + DecodeType = AH_DECODE_ASL; + break; + + case 't': + + DecodeType = AH_DISPLAY_TABLES; + break; + + case 'u': + + DecodeType = AH_DISPLAY_UUIDS; + break; + + case 'v': /* -v: (Version): signon already emitted, just exit */ + + return (0); + + case 'h': + default: + + AhDisplayUsage (); + return (-1); + } + + /* Missing (null) name means "display all" */ + + Name = argv[AcpiGbl_Optind]; + + switch (DecodeType) + { + case AH_DECODE_ASL_AML: + + AhFindAslAndAmlOperators (Name); + break; + + case AH_DECODE_AML: + + AhFindAmlOpcode (Name); + break; + + case AH_DECODE_AML_OPCODE: + + AhDecodeAmlOpcode (Name); + break; + + case AH_DECODE_PREDEFINED_NAME: + + AhFindPredefinedNames (Name); + break; + + case AH_DECODE_ASL: + + AhFindAslOperators (Name); + break; + + case AH_DECODE_ASL_KEYWORD: + + AhFindAslKeywords (Name); + break; + + case AH_DISPLAY_DEVICE_IDS: + + AhDisplayDeviceIds (Name); + break; + + case AH_DECODE_EXCEPTION: + + AhDecodeException (Name); + break; + + case AH_DISPLAY_UUIDS: + + AhDisplayUuids (); + break; + + case AH_DISPLAY_TABLES: + + AhDisplayTables (); + break; + + case AH_DISPLAY_DIRECTIVES: + + AhDisplayDirectives (); + break; + + default: + + if (!Name) + { + AhFindAslOperators (Name); + break; + } + + if (*Name == '_') + { + AhFindPredefinedNames (Name); + } + else + { + AhFindAslAndAmlOperators (Name); + } + break; + } + + return (0); +} diff --git a/third_party/lib/acpica/source/tools/acpinames/acpinames.h b/third_party/lib/acpica/source/tools/acpinames/acpinames.h new file mode 100644 index 000000000..ee2a87f52 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpinames/acpinames.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * + * Module Name: acpinames.h - Common include for AcpiNames utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ACPINAMES_H +#define _ACPINAMES_H + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include "acutils.h" +#include "acnamesp.h" +#include "actables.h" +#include "acinterp.h" + +#include + +#define ACPI_MAX_INIT_TABLES (32) + +extern BOOLEAN AcpiGbl_NsLoadOnly; + + +ACPI_STATUS +AnBuildLocalTables ( + ACPI_NEW_TABLE_DESC *TableList); + +#endif diff --git a/third_party/lib/acpica/source/tools/acpinames/anmain.c b/third_party/lib/acpica/source/tools/acpinames/anmain.c new file mode 100644 index 000000000..6e48bfdd6 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpinames/anmain.c @@ -0,0 +1,305 @@ +/****************************************************************************** + * + * Module Name: anmain - Main routine for the AcpiNames utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpinames.h" +#include "actables.h" +#include "errno.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("anmain") + + +/* Local prototypes */ + +static int +AnDumpEntireNamespace ( + ACPI_NEW_TABLE_DESC *ListHead); + + +/* + * Main routine for the ACPI user-space namespace utility. + * + * Portability note: The utility depends upon the host for command-line + * wildcard support - it is not implemented locally. For example: + * + * Linux/Unix systems: Shell expands wildcards automatically. + * + * Windows: The setargv.obj module must be linked in to automatically + * expand wildcards. + */ +BOOLEAN AcpiGbl_NsLoadOnly = FALSE; + + +#define AN_UTILITY_NAME "ACPI Namespace Dump Utility" +#define AN_SUPPORTED_OPTIONS "?hlvx:" + + +/****************************************************************************** + * + * FUNCTION: usage + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Print a usage message + * + *****************************************************************************/ + +static void +usage ( + void) +{ + + ACPI_USAGE_HEADER ("AcpiNames [options] AMLfile"); + ACPI_OPTION ("-?", "Display this message"); + ACPI_OPTION ("-l", "Load namespace only, no display"); + ACPI_OPTION ("-v", "Display version information"); + ACPI_OPTION ("-x ", "Debug output level"); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * PARAMETERS: argc, argv + * + * RETURN: Status (pass/fail) + * + * DESCRIPTION: Main routine for NsDump utility + * + *****************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char **argv) +{ + ACPI_NEW_TABLE_DESC *ListHead = NULL; + ACPI_STATUS Status; + int j; + + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + + /* Init debug globals and ACPICA */ + + AcpiDbgLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; + AcpiDbgLayer = 0xFFFFFFFF; + + Status = AcpiInitializeSubsystem (); + ACPI_CHECK_OK (AcpiInitializeSubsystem, Status); + if (ACPI_FAILURE (Status)) + { + return (-1); + } + + printf (ACPI_COMMON_SIGNON (AN_UTILITY_NAME)); + if (argc < 2) + { + usage (); + return (0); + } + + /* Get the command line options */ + + while ((j = AcpiGetopt (argc, argv, AN_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch(j) + { + case 'l': + + AcpiGbl_NsLoadOnly = TRUE; + break; + + case 'v': /* -v: (Version): signon already emitted, just exit */ + + return (0); + + case 'x': + + AcpiDbgLevel = strtoul (AcpiGbl_Optarg, NULL, 0); + printf ("Debug Level: 0x%8.8X\n", AcpiDbgLevel); + break; + + case '?': + case 'h': + default: + + usage(); + return (0); + } + + /* Get each of the ACPI table files on the command line */ + + while (argv[AcpiGbl_Optind]) + { + /* Get all ACPI AML tables in this file */ + + Status = AcGetAllTablesFromFile (argv[AcpiGbl_Optind], + ACPI_GET_ONLY_AML_TABLES, &ListHead); + if (ACPI_FAILURE (Status)) + { + return (-1); + } + + AcpiGbl_Optind++; + } + + printf ("\n"); + + /* + * The next argument is the filename for the DSDT or SSDT. + * Open the file, build namespace and dump it. + */ + return (AnDumpEntireNamespace (ListHead)); +} + + +/****************************************************************************** + * + * FUNCTION: AnDumpEntireNamespace + * + * PARAMETERS: AmlFilename - Filename for DSDT or SSDT AML table + * + * RETURN: Status (pass/fail) + * + * DESCRIPTION: Build an ACPI namespace for the input AML table, and dump the + * formatted namespace contents. + * + *****************************************************************************/ + +static int +AnDumpEntireNamespace ( + ACPI_NEW_TABLE_DESC *ListHead) +{ + ACPI_STATUS Status; + ACPI_HANDLE Handle; + + + /* + * Build a local XSDT with all tables. Normally, here is where the + * RSDP search is performed to find the ACPI tables + */ + Status = AnBuildLocalTables (ListHead); + if (ACPI_FAILURE (Status)) + { + return (-1); + } + + /* Initialize table manager, get XSDT */ + + Status = AcpiInitializeTables (NULL, ACPI_MAX_INIT_TABLES, TRUE); + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not initialize ACPI table manager, %s\n", + AcpiFormatException (Status)); + return (-1); + } + + /* Load the ACPI namespace */ + + Status = AcpiTbLoadNamespace (); + if (Status == AE_CTRL_TERMINATE) + { + /* At least one table load failed -- terminate with error */ + + return (-1); + } + + if (ACPI_FAILURE (Status)) + { + printf ("**** While creating namespace, %s\n", + AcpiFormatException (Status)); + return (-1); + } + + if (AcpiGbl_NsLoadOnly) + { + printf ("**** Namespace successfully loaded\n"); + return (0); + } + + /* + * Enable ACPICA. These calls don't do much for this + * utility, since we only dump the namespace. There is no + * hardware or event manager code underneath. + */ + Status = AcpiEnableSubsystem ( + ACPI_NO_ACPI_ENABLE | + ACPI_NO_ADDRESS_SPACE_INIT | + ACPI_NO_EVENT_INIT | + ACPI_NO_HANDLER_INIT); + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not EnableSubsystem, %s\n", + AcpiFormatException (Status)); + return (-1); + } + + Status = AcpiInitializeObjects ( + ACPI_NO_ADDRESS_SPACE_INIT | + ACPI_NO_DEVICE_INIT | + ACPI_NO_EVENT_INIT); + if (ACPI_FAILURE (Status)) + { + printf ("**** Could not InitializeObjects, %s\n", + AcpiFormatException (Status)); + return (-1); + } + + /* + * Perform a namespace walk to dump the contents + */ + AcpiOsPrintf ("\nACPI Namespace:\n"); + + AcpiNsDumpObjects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, + ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX, AcpiGbl_RootNode); + + + /* Example: get a handle to the _GPE scope */ + + Status = AcpiGetHandle (NULL, "\\_GPE", &Handle); + ACPI_CHECK_OK (AcpiGetHandle, Status); + + return (0); +} diff --git a/third_party/lib/acpica/source/tools/acpinames/anstubs.c b/third_party/lib/acpica/source/tools/acpinames/anstubs.c new file mode 100644 index 000000000..78984ce01 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpinames/anstubs.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * Module Name: anstubs - Stub routines for the AcpiNames utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpinames.h" + +#include +#include +#include + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("anstubs") + + +/****************************************************************************** + * + * DESCRIPTION: Stubs used to facilitate linkage of the NsDump utility. + * + *****************************************************************************/ + + +/* Utilities */ + +ACPI_STATUS +AcpiUtCopyIobjectToEobject ( + ACPI_OPERAND_OBJECT *Obj, + ACPI_BUFFER *RetBuffer) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiUtCopyEobjectToIobject ( + ACPI_OBJECT *Obj, + ACPI_OPERAND_OBJECT **InternalObj) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiUtCopyIobjectToIobject ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT **DestDesc, + ACPI_WALK_STATE *WalkState) +{ + return (AE_NOT_IMPLEMENTED); +} + +/* Hardware */ + +UINT32 +AcpiHwGetMode ( + void) +{ + return (0); +} + +/* Event manager */ + +ACPI_STATUS +AcpiEvInstallRegionHandlers ( + void) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvInitializeOpRegions ( + void) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvInitializeRegion ( + ACPI_OPERAND_OBJECT *RegionObj, + BOOLEAN AcpiNsLocked) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvInstallXruptHandlers ( + void) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiEvInitializeEvents ( + void) +{ + return (AE_OK); +} + + +/* AML Interpreter */ + +ACPI_STATUS +AcpiExReadDataFromField ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **RetBufferDesc) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiExWriteDataToField ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_OPERAND_OBJECT **ResultDesc) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiExStoreObjectToNode ( + ACPI_OPERAND_OBJECT *SourceDesc, + ACPI_NAMESPACE_NODE *Node, + ACPI_WALK_STATE *WalkState, + UINT8 ImplicitConversion) +{ + return (AE_NOT_IMPLEMENTED); +} + + +/* Namespace manager */ + +ACPI_STATUS +AcpiNsEvaluate ( + ACPI_EVALUATE_INFO *Info) +{ + return (AE_NOT_IMPLEMENTED); +} + +void +AcpiNsExecModuleCodeList ( + void) +{ +} + +void +AcpiExDoDebugObject ( + ACPI_OPERAND_OBJECT *SourceDesc, + UINT32 Level, + UINT32 Index) +{ + return; +} + +void +AcpiExStartTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +void +AcpiExStopTraceMethod ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +void +AcpiExStartTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) +{ + return; +} + +void +AcpiExStopTraceOpcode ( + ACPI_PARSE_OBJECT *Op, + ACPI_WALK_STATE *WalkState) + +{ + return; +} + +void +AcpiExTracePoint ( + ACPI_TRACE_EVENT_TYPE Type, + BOOLEAN Begin, + UINT8 *Aml, + char *Pathname) +{ + return; +} + + +/* Dispatcher */ + +ACPI_STATUS +AcpiDsAutoSerializeMethod ( + ACPI_NAMESPACE_NODE *Node, + ACPI_OPERAND_OBJECT *ObjDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsInitializeRegion ( + ACPI_HANDLE ObjHandle) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsCallControlMethod ( + ACPI_THREAD_STATE *Thread, + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT *Op) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiDsRestartControlMethod ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ReturnDesc) +{ + return (AE_NOT_IMPLEMENTED); +} + +void +AcpiDsTerminateControlMethod ( + ACPI_OPERAND_OBJECT *MethodDesc, + ACPI_WALK_STATE *WalkState) +{ +} + +ACPI_STATUS +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiDsBeginMethodExecution ( + ACPI_NAMESPACE_NODE *MethodNode, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_WALK_STATE *WalkState) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiDsGetPredicateValue ( + ACPI_WALK_STATE *WalkState, + ACPI_OPERAND_OBJECT *ResultObj) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiDsGetBufferFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsGetBankFieldArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsGetRegionArguments ( + ACPI_OPERAND_OBJECT *RgnDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsGetBufferArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsGetPackageArguments ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiDsExecBeginOp ( + ACPI_WALK_STATE *WalkState, + ACPI_PARSE_OBJECT **OutOp) +{ + return (AE_NOT_IMPLEMENTED); +} + +ACPI_STATUS +AcpiDsExecEndOp ( + ACPI_WALK_STATE *State) +{ + return (AE_NOT_IMPLEMENTED); +} diff --git a/third_party/lib/acpica/source/tools/acpinames/antables.c b/third_party/lib/acpica/source/tools/acpinames/antables.c new file mode 100644 index 000000000..f797c9155 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpinames/antables.c @@ -0,0 +1,356 @@ +/****************************************************************************** + * + * Module Name: antables - ACPI table setup/install for AcpiNames utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpinames.h" + +#define _COMPONENT ACPI_TOOLS + ACPI_MODULE_NAME ("antables") + +/* Local prototypes */ + +static void +AnInitializeTableHeader ( + ACPI_TABLE_HEADER *Header, + char *Signature, + UINT32 Length); + + +/* Non-AML tables that are constructed locally and installed */ + +static ACPI_TABLE_RSDP LocalRSDP; +static ACPI_TABLE_FACS LocalFACS; + +/* + * We need a local FADT so that the hardware subcomponent will function, + * even though the underlying OSD HW access functions don't do anything. + */ +static ACPI_TABLE_FADT LocalFADT; + +/* + * Use XSDT so that both 32- and 64-bit versions of this utility will + * function automatically. + */ +static ACPI_TABLE_XSDT *LocalXSDT; + +#define BASE_XSDT_TABLES 1 +#define BASE_XSDT_SIZE (sizeof (ACPI_TABLE_XSDT) + \ + ((BASE_XSDT_TABLES -1) * sizeof (UINT64))) + + +/****************************************************************************** + * + * FUNCTION: AnInitializeTableHeader + * + * PARAMETERS: Header - A valid standard ACPI table header + * Signature - Signature to insert + * Length - Length of the table + * + * RETURN: None. Header is modified. + * + * DESCRIPTION: Initialize the table header for a local ACPI table. + * + *****************************************************************************/ + +static void +AnInitializeTableHeader ( + ACPI_TABLE_HEADER *Header, + char *Signature, + UINT32 Length) +{ + + ACPI_MOVE_NAME (Header->Signature, Signature); + Header->Length = Length; + + Header->OemRevision = 0x1001; + strncpy (Header->OemId, "Intel", ACPI_OEM_ID_SIZE); + strncpy (Header->OemTableId, "AcpiName", ACPI_OEM_TABLE_ID_SIZE); + strncpy (Header->AslCompilerId, "INTL", ACPI_NAME_SIZE); + Header->AslCompilerRevision = ACPI_CA_VERSION; + + /* Set the checksum, must set to zero first */ + + Header->Checksum = 0; + Header->Checksum = (UINT8) -AcpiTbChecksum ( + (void *) Header, Header->Length); +} + + +/****************************************************************************** + * + * FUNCTION: AnBuildLocalTables + * + * PARAMETERS: TableCount - Number of tables on the command line + * TableList - List of actual tables from files + * + * RETURN: Status + * + * DESCRIPTION: Build a complete ACPI table chain, with a local RSDP, XSDT, + * FADT, FACS, and the input DSDT/SSDT. + * + *****************************************************************************/ + +ACPI_STATUS +AnBuildLocalTables ( + ACPI_NEW_TABLE_DESC *TableList) +{ + UINT32 TableCount = 0; + ACPI_PHYSICAL_ADDRESS DsdtAddress = 0; + UINT32 XsdtSize; + ACPI_NEW_TABLE_DESC *NextTable; + UINT32 NextIndex; + ACPI_TABLE_FADT *ExternalFadt = NULL; + + + /* + * Update the table count. For the DSDT, it is not put into the XSDT. + * For the FADT, this table is already accounted for since we usually + * install a local FADT. + */ + NextTable = TableList; + while (NextTable) + { + if (!ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_FADT)) + { + TableCount++; + } + + NextTable = NextTable->Next; + } + + XsdtSize = BASE_XSDT_SIZE + (TableCount * sizeof (UINT64)); + + /* Build an XSDT */ + + LocalXSDT = AcpiOsAllocate (XsdtSize); + if (!LocalXSDT) + { + return (AE_NO_MEMORY); + } + + memset (LocalXSDT, 0, XsdtSize); + LocalXSDT->TableOffsetEntry[0] = ACPI_PTR_TO_PHYSADDR (&LocalFADT); + + /* + * Install the user tables. The DSDT must be installed in the FADT. + * All other tables are installed directly into the XSDT. + * + * Note: The tables are loaded in reverse order from the incoming + * input, which makes it match the command line order. + */ + NextIndex = BASE_XSDT_TABLES; + NextTable = TableList; + while (NextTable) + { + /* + * Incoming DSDT or FADT are special cases. All other tables are + * just immediately installed into the XSDT. + */ + if (ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_DSDT)) + { + if (DsdtAddress) + { + printf ("Already found a DSDT, only one allowed\n"); + return (AE_ALREADY_EXISTS); + } + + /* The incoming user table is a DSDT */ + + DsdtAddress = ACPI_PTR_TO_PHYSADDR (NextTable->Table); + } + else if (ACPI_COMPARE_NAME (NextTable->Table->Signature, ACPI_SIG_FADT)) + { + ExternalFadt = + ACPI_CAST_PTR (ACPI_TABLE_FADT, NextTable->Table); + LocalXSDT->TableOffsetEntry[0] = + ACPI_PTR_TO_PHYSADDR (NextTable->Table); + } + else + { + /* Install the table in the XSDT */ + + LocalXSDT->TableOffsetEntry[TableCount - NextIndex + 1] = + ACPI_PTR_TO_PHYSADDR (NextTable->Table); + NextIndex++; + } + + NextTable = NextTable->Next; + } + + /* Build an RSDP. Contains a valid XSDT only, no RSDT */ + + memset (&LocalRSDP, 0, sizeof (ACPI_TABLE_RSDP)); + ACPI_MAKE_RSDP_SIG (LocalRSDP.Signature); + memcpy (LocalRSDP.OemId, "Intel", 6); + + LocalRSDP.Revision = 2; + LocalRSDP.XsdtPhysicalAddress = ACPI_PTR_TO_PHYSADDR (LocalXSDT); + LocalRSDP.Length = sizeof (ACPI_TABLE_XSDT); + + /* Set checksums for both XSDT and RSDP */ + + AnInitializeTableHeader ((void *) LocalXSDT, ACPI_SIG_XSDT, XsdtSize); + + LocalRSDP.Checksum = 0; + LocalRSDP.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) &LocalRSDP, ACPI_RSDP_CHECKSUM_LENGTH); + + if (!DsdtAddress) + { + return (AE_SUPPORT); + } + + /* + * Build an FADT. There are two options for the FADT: + * 1) Incoming external FADT specified on the command line + * 2) A fully featured local FADT + */ + memset (&LocalFADT, 0, sizeof (ACPI_TABLE_FADT)); + + if (ExternalFadt) + { + /* + * Use the external FADT, but we must update the DSDT/FACS + * addresses as well as the checksum + */ + ExternalFadt->Dsdt = (UINT32) DsdtAddress; + ExternalFadt->Facs = ACPI_PTR_TO_PHYSADDR (&LocalFACS); + + /* + * If there room in the FADT for the XDsdt and XFacs 64-bit + * pointers, use them. + */ + if (ExternalFadt->Header.Length > ACPI_PTR_DIFF ( + &ExternalFadt->XDsdt, ExternalFadt)) + { + ExternalFadt->Dsdt = 0; + ExternalFadt->Facs = 0; + ExternalFadt->XDsdt = DsdtAddress; + ExternalFadt->XFacs = ACPI_PTR_TO_PHYSADDR (&LocalFACS); + } + + /* Complete the external FADT with the checksum */ + + ExternalFadt->Header.Checksum = 0; + ExternalFadt->Header.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) ExternalFadt, ExternalFadt->Header.Length); + } + else + { + /* + * Build a local FADT so we can test the hardware/event init + */ + LocalFADT.Header.Revision = 5; + + /* Setup FADT header and DSDT/FACS addresses */ + + LocalFADT.Dsdt = 0; + LocalFADT.Facs = 0; + + LocalFADT.XDsdt = DsdtAddress; + LocalFADT.XFacs = ACPI_PTR_TO_PHYSADDR (&LocalFACS); + + /* Miscellaneous FADT fields */ + + LocalFADT.Gpe0BlockLength = 16; + LocalFADT.Gpe0Block = 0x00001234; + + LocalFADT.Gpe1BlockLength = 6; + LocalFADT.Gpe1Block = 0x00005678; + LocalFADT.Gpe1Base = 96; + + LocalFADT.Pm1EventLength = 4; + LocalFADT.Pm1aEventBlock = 0x00001aaa; + LocalFADT.Pm1bEventBlock = 0x00001bbb; + + LocalFADT.Pm1ControlLength = 2; + LocalFADT.Pm1aControlBlock = 0xB0; + + LocalFADT.PmTimerLength = 4; + LocalFADT.PmTimerBlock = 0xA0; + + LocalFADT.Pm2ControlBlock = 0xC0; + LocalFADT.Pm2ControlLength = 1; + + /* Setup one example X-64 field */ + + LocalFADT.XPm1bEventBlock.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO; + LocalFADT.XPm1bEventBlock.Address = LocalFADT.Pm1bEventBlock; + LocalFADT.XPm1bEventBlock.BitWidth = (UINT8) + ACPI_MUL_8 (LocalFADT.Pm1EventLength); + } + + AnInitializeTableHeader ((void *) &LocalFADT, + ACPI_SIG_FADT, sizeof (ACPI_TABLE_FADT)); + + /* Build a FACS */ + + memset (&LocalFACS, 0, sizeof (ACPI_TABLE_FACS)); + ACPI_MOVE_NAME (LocalFACS.Signature, ACPI_SIG_FACS); + + LocalFACS.Length = sizeof (ACPI_TABLE_FACS); + LocalFACS.GlobalLock = 0x11AA0011; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetRootPointer + * + * PARAMETERS: None + * + * RETURN: Address of the RSDP + * + * DESCRIPTION: Return a local RSDP, used to dynamically load tables via the + * standard ACPI mechanism. + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + + return (ACPI_PTR_TO_PHYSADDR (&LocalRSDP)); +} diff --git a/third_party/lib/acpica/source/tools/acpisrc/acpisrc.h b/third_party/lib/acpica/source/tools/acpisrc/acpisrc.h new file mode 100644 index 000000000..ea1161f00 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/acpisrc.h @@ -0,0 +1,428 @@ +/****************************************************************************** + * + * Module Name: acpisrc.h - Include file for AcpiSrc utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#include +#include +#include + +/* mkdir support */ + +#ifdef WIN32 +#include +#else +#define mkdir(x) mkdir(x, 0770) +#endif + + +/* Constants */ + +#define LINES_IN_LEGAL_HEADER 105 /* See above */ +#define LEGAL_HEADER_SIGNATURE " * 2.1. This is your license from Intel Corp. under its intellectual property" +#define LINES_IN_LINUX_HEADER 34 +#define LINUX_HEADER_SIGNATURE " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS" +#define LINES_IN_ASL_HEADER 29 /* Header as output from disassembler */ + +#define ASRC_MAX_FILE_SIZE (1024 * 100) + +#define FILE_TYPE_SOURCE 1 +#define FILE_TYPE_HEADER 2 +#define FILE_TYPE_DIRECTORY 3 +#define FILE_TYPE_PATCH 4 + +#define CVT_COUNT_TABS 0x00000001 +#define CVT_COUNT_NON_ANSI_COMMENTS 0x00000002 +#define CVT_TRIM_LINES 0x00000004 +#define CVT_CHECK_BRACES 0x00000008 +#define CVT_COUNT_LINES 0x00000010 +#define CVT_BRACES_ON_SAME_LINE 0x00000020 +#define CVT_MIXED_CASE_TO_UNDERSCORES 0x00000040 +#define CVT_LOWER_CASE_IDENTIFIERS 0x00000080 +#define CVT_REMOVE_DEBUG_MACROS 0x00000100 +#define CVT_TRIM_WHITESPACE 0x00000200 /* Should be after all line removal */ +#define CVT_REMOVE_EMPTY_BLOCKS 0x00000400 /* Should be after trimming lines */ +#define CVT_REDUCE_TYPEDEFS 0x00000800 +#define CVT_COUNT_SHORTMULTILINE_COMMENTS 0x00001000 +#define CVT_SPACES_TO_TABS4 0x40000000 /* Tab conversion should be last */ +#define CVT_SPACES_TO_TABS8 0x80000000 /* Tab conversion should be last */ + +#define FLG_DEFAULT_FLAGS 0x00000000 +#define FLG_NO_CARRIAGE_RETURNS 0x00000001 +#define FLG_NO_FILE_OUTPUT 0x00000002 +#define FLG_LOWERCASE_DIRNAMES 0x00000004 + +#define AS_START_IGNORE "/*!" +#define AS_STOP_IGNORE "!*/" + + +/* Globals */ + +extern UINT32 Gbl_Files; +extern UINT32 Gbl_MissingBraces; +extern UINT32 Gbl_Tabs; +extern UINT32 Gbl_NonAnsiComments; +extern UINT32 Gbl_SourceLines; +extern UINT32 Gbl_WhiteLines; +extern UINT32 Gbl_CommentLines; +extern UINT32 Gbl_LongLines; +extern UINT32 Gbl_TotalLines; +extern UINT32 Gbl_HeaderSize; +extern UINT32 Gbl_HeaderLines; +extern struct stat Gbl_StatBuf; +extern char *Gbl_FileBuffer; +extern UINT32 Gbl_TotalSize; +extern UINT32 Gbl_FileSize; +extern UINT32 Gbl_FileType; +extern BOOLEAN Gbl_VerboseMode; +extern BOOLEAN Gbl_QuietMode; +extern BOOLEAN Gbl_BatchMode; +extern BOOLEAN Gbl_MadeChanges; +extern BOOLEAN Gbl_Overwrite; +extern BOOLEAN Gbl_WidenDeclarations; +extern BOOLEAN Gbl_IgnoreLoneLineFeeds; +extern BOOLEAN Gbl_HasLoneLineFeeds; +extern BOOLEAN Gbl_Cleanup; +extern BOOLEAN Gbl_IgnoreTranslationEscapes; +extern void *Gbl_StructDefs; + +#define PARAM_LIST(pl) pl +#define TERSE_PRINT(a) if (!Gbl_VerboseMode) printf PARAM_LIST(a) +#define VERBOSE_PRINT(a) if (Gbl_VerboseMode) printf PARAM_LIST(a) + +#define REPLACE_WHOLE_WORD 0x00 +#define REPLACE_SUBSTRINGS 0x01 +#define REPLACE_MASK 0x01 + +#define EXTRA_INDENT_C 0x02 + + +/* Conversion table structs */ + +typedef struct acpi_string_table +{ + char *Target; + char *Replacement; + UINT8 Type; + +} ACPI_STRING_TABLE; + + +typedef struct acpi_typed_identifier_table +{ + char *Identifier; + UINT8 Type; + +} ACPI_TYPED_IDENTIFIER_TABLE; + +#define SRC_TYPE_SIMPLE 0 +#define SRC_TYPE_STRUCT 1 +#define SRC_TYPE_UNION 2 + + +typedef struct acpi_identifier_table +{ + char *Identifier; + +} ACPI_IDENTIFIER_TABLE; + +typedef struct acpi_conversion_table +{ + char *NewHeader; + UINT32 Flags; + + ACPI_TYPED_IDENTIFIER_TABLE *LowerCaseTable; + + ACPI_STRING_TABLE *SourceStringTable; + ACPI_IDENTIFIER_TABLE *SourceLineTable; + ACPI_IDENTIFIER_TABLE *SourceConditionalTable; + ACPI_IDENTIFIER_TABLE *SourceMacroTable; + ACPI_TYPED_IDENTIFIER_TABLE *SourceStructTable; + ACPI_IDENTIFIER_TABLE *SourceSpecialMacroTable; + UINT32 SourceFunctions; + + ACPI_STRING_TABLE *HeaderStringTable; + ACPI_IDENTIFIER_TABLE *HeaderLineTable; + ACPI_IDENTIFIER_TABLE *HeaderConditionalTable; + ACPI_IDENTIFIER_TABLE *HeaderMacroTable; + ACPI_TYPED_IDENTIFIER_TABLE *HeaderStructTable; + ACPI_IDENTIFIER_TABLE *HeaderSpecialMacroTable; + UINT32 HeaderFunctions; + + ACPI_STRING_TABLE *PatchStringTable; + ACPI_IDENTIFIER_TABLE *PatchLineTable; + ACPI_IDENTIFIER_TABLE *PatchConditionalTable; + ACPI_IDENTIFIER_TABLE *PatchMacroTable; + ACPI_TYPED_IDENTIFIER_TABLE *PatchStructTable; + ACPI_IDENTIFIER_TABLE *PatchSpecialMacroTable; + UINT32 PatchFunctions; + +} ACPI_CONVERSION_TABLE; + + +/* Conversion tables */ + +extern ACPI_CONVERSION_TABLE LinuxConversionTable; +extern ACPI_CONVERSION_TABLE CleanupConversionTable; +extern ACPI_CONVERSION_TABLE StatsConversionTable; +extern ACPI_CONVERSION_TABLE CustomConversionTable; +extern ACPI_CONVERSION_TABLE LicenseConversionTable; +extern ACPI_CONVERSION_TABLE IndentConversionTable; + +typedef +char * (*AS_SCAN_CALLBACK) ( + char *Buffer, + char *Filename, + UINT32 LineNumber); + +typedef struct as_brace_info +{ + char *Operator; + UINT32 Length; + +} AS_BRACE_INFO; + + +/* Prototypes */ + +char * +AsSkipUntilChar ( + char *Buffer, + char Target); + +char * +AsSkipPastChar ( + char *Buffer, + char Target); + +char * +AsReplaceData ( + char *Buffer, + UINT32 LengthToRemove, + char *BufferToAdd, + UINT32 LengthToAdd); + +int +AsReplaceString ( + char *Target, + char *Replacement, + UINT8 Type, + char *Buffer); + +int +AsLowerCaseString ( + char *Target, + char *Buffer); + +void +AsRemoveLine ( + char *Buffer, + char *Keyword); + +void +AsCheckForBraces ( + char *Buffer, + char *Filename); + +void +AsTrimLines ( + char *Buffer, + char *Filename); + +void +AsMixedCaseToUnderscores ( + char *Buffer, + char *Filename); + +void +AsCountTabs ( + char *Buffer, + char *Filename); + +void +AsBracesOnSameLine ( + char *Buffer); + +void +AsLowerCaseIdentifiers ( + char *Buffer); + +void +AsReduceTypedefs ( + char *Buffer, + char *Keyword); + +void +AsRemoveDebugMacros ( + char *Buffer); + +void +AsRemoveEmptyBlocks ( + char *Buffer, + char *Filename); + +void +AsCleanupSpecialMacro ( + char *Buffer, + char *Keyword); + +void +AsCountSourceLines ( + char *Buffer, + char *Filename); + +void +AsCountNonAnsiComments ( + char *Buffer, + char *Filename); + +void +AsTrimWhitespace ( + char *Buffer); + +void +AsTabify4 ( + char *Buffer); + +void +AsTabify8 ( + char *Buffer); + +void +AsRemoveConditionalCompile ( + char *Buffer, + char *Keyword); + +ACPI_NATIVE_INT +AsProcessTree ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *SourcePath, + char *TargetPath); + +int +AsGetFile ( + char *FileName, + char **FileBuffer, + UINT32 *FileSize); + +int +AsPutFile ( + char *Pathname, + char *FileBuffer, + UINT32 SystemFlags); + +void +AsReplaceHeader ( + char *Buffer, + char *NewHeader); + +void +AsConvertFile ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *FileBuffer, + char *Filename, + ACPI_NATIVE_INT FileType); + +ACPI_NATIVE_INT +AsProcessOneFile ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *SourcePath, + char *TargetPath, + int MaxPathLength, + char *Filename, + ACPI_NATIVE_INT FileType); + +ACPI_NATIVE_INT +AsCheckForDirectory ( + char *SourceDirPath, + char *TargetDirPath, + char *Filename, + char **SourcePath, + char **TargetPath); + +void +AsRemoveExtraLines ( + char *FileBuffer, + char *Filename); + +void +AsRemoveSpacesAfterPeriod ( + char *FileBuffer, + char *Filename); + +BOOLEAN +AsMatchExactWord ( + char *Word, + UINT32 WordLength); + +void +AsPrint ( + char *Message, + UINT32 Count, + char *Filename); + +void +AsInsertPrefix ( + char *Buffer, + char *Keyword, + UINT8 Type); + +char * +AsInsertData ( + char *Buffer, + char *BufferToAdd, + UINT32 LengthToAdd); + +char * +AsRemoveData ( + char *StartPointer, + char *EndPointer); + +void +AsInsertCarriageReturns ( + char *Buffer); + +void +AsConvertToLineFeeds ( + char *Buffer); diff --git a/third_party/lib/acpica/source/tools/acpisrc/ascase.c b/third_party/lib/acpica/source/tools/acpisrc/ascase.c new file mode 100644 index 000000000..d8a68bd39 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/ascase.c @@ -0,0 +1,641 @@ +/****************************************************************************** + * + * Module Name: ascase - Source conversion - lower/upper case utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" + +/* Local prototypes */ + +void +AsUppercaseTokens ( + char *Buffer, + char *PrefixString); + + +/****************************************************************************** + * + * FUNCTION: AsLowerCaseString + * + * DESCRIPTION: LowerCase all instances of a target string with a replacement + * string. Returns count of the strings replaced. + * + ******************************************************************************/ + +int +AsLowerCaseString ( + char *Target, + char *Buffer) +{ + char *SubString1; + char *SubString2; + char *SubBuffer; + int TargetLength; + int LowerCaseCount = 0; + int i; + + + TargetLength = strlen (Target); + + SubBuffer = Buffer; + SubString1 = Buffer; + + while (SubString1) + { + /* Find the target string */ + + SubString1 = strstr (SubBuffer, Target); + if (!SubString1) + { + return (LowerCaseCount); + } + + /* + * Check for translation escape string -- means to ignore + * blocks of code while replacing + */ + if (Gbl_IgnoreTranslationEscapes) + { + SubString2 = NULL; + } + else + { + SubString2 = strstr (SubBuffer, AS_START_IGNORE); + } + + if ((SubString2) && + (SubString2 < SubString1)) + { + /* Find end of the escape block starting at "Substring2" */ + + SubString2 = strstr (SubString2, AS_STOP_IGNORE); + if (!SubString2) + { + /* Didn't find terminator */ + + return (LowerCaseCount); + } + + /* Move buffer to end of escape block and continue */ + + SubBuffer = SubString2; + } + + /* Do the actual replace if the target was found */ + + else + { + if (!AsMatchExactWord (SubString1, TargetLength)) + { + SubBuffer = SubString1 + 1; + continue; + } + + for (i = 0; i < TargetLength; i++) + { + SubString1[i] = (char) tolower ((int) SubString1[i]); + } + + SubBuffer = SubString1 + TargetLength; + + if ((Gbl_WidenDeclarations) && (!Gbl_StructDefs)) + { + if ((SubBuffer[0] == ' ') && (SubBuffer[1] == ' ')) + { + AsInsertData (SubBuffer, " ", 8); + } + } + + LowerCaseCount++; + } + } + + return (LowerCaseCount); +} + + +/****************************************************************************** + * + * FUNCTION: AsMixedCaseToUnderscores + * + * DESCRIPTION: Converts mixed case identifiers to underscored identifiers. + * for example, + * + * ThisUsefullyNamedIdentifier becomes: + * + * this_usefully_named_identifier + * + ******************************************************************************/ + +void +AsMixedCaseToUnderscores ( + char *Buffer, + char *Filename) +{ + UINT32 Length; + char *SubBuffer = Buffer; + char *TokenEnd; + char *TokenStart = NULL; + char *SubString; + UINT32 LineNumber = 1; + UINT32 Count; + + + /* + * Examine the entire buffer (contains the entire file) + * We are only interested in these tokens: + * Escape sequences - ignore entire sequence + * Single-quoted constants - ignore + * Quoted strings - ignore entire string + * Translation escape - starts with /,*,! + * Decimal and hex numeric constants - ignore entire token + * Entire uppercase token - ignore, it is a macro or define + * Starts with underscore, then a lowercase or digit: convert + */ + while (*SubBuffer) + { + if (*SubBuffer == '\n') + { + LineNumber++; + SubBuffer++; + continue; + } + + /* Ignore standard escape sequences (\n, \r, etc.) Not Hex or Octal escapes */ + + if (*SubBuffer == '\\') + { + SubBuffer += 2; + continue; + } + + /* Ignore single-quoted characters */ + + if (*SubBuffer == '\'') + { + SubBuffer += 3; + continue; + } + + /* Ignore standard double-quoted strings */ + + if (*SubBuffer == '"') + { + SubBuffer++; + Count = 0; + while (*SubBuffer != '"') + { + Count++; + if ((!*SubBuffer) || + (Count > 8192)) + { + printf ("Found an unterminated quoted string!, line %u: %s\n", + LineNumber, Filename); + return; + } + + /* Handle escape sequences */ + + if (*SubBuffer == '\\') + { + SubBuffer++; + } + + SubBuffer++; + } + + SubBuffer++; + continue; + } + + /* + * Check for translation escape string. It means to ignore + * blocks of code during this code conversion. + */ + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*') && + (SubBuffer[2] == '!')) + { + SubBuffer = strstr (SubBuffer, "!*/"); + if (!SubBuffer) + { + printf ("Found an unterminated translation escape!, line %u: %s\n", + LineNumber, Filename); + return; + } + + continue; + } + + /* Ignore anything that starts with a number (0-9) */ + + if (isdigit ((int) *SubBuffer)) + { + /* Ignore hex constants */ + + if ((SubBuffer[0] == '0') && + ((SubBuffer[1] == 'x') || (SubBuffer[1] == 'X'))) + { + SubBuffer += 2; + } + + /* Skip over all digits, both decimal and hex */ + + while (isxdigit ((int) *SubBuffer)) + { + SubBuffer++; + } + TokenStart = NULL; + continue; + } + + /* + * Check for fully upper case identifiers. These are usually macros + * or defines. Allow decimal digits and embedded underscores. + */ + if (isupper ((int) *SubBuffer)) + { + SubString = SubBuffer + 1; + while ((isupper ((int) *SubString)) || + (isdigit ((int) *SubString)) || + (*SubString == '_')) + { + SubString++; + } + + /* + * For the next character, anything other than a lower case + * means that the identifier has terminated, and contains + * exclusively Uppers/Digits/Underscores. Ignore the entire + * identifier. + */ + if (!islower ((int) *SubString)) + { + SubBuffer = SubString + 1; + continue; + } + } + + /* + * These forms may indicate an identifier that can be converted: + * (Ax) + * (An) + */ + if (isupper ((int) SubBuffer[0]) && + ((islower ((int) SubBuffer[1])) || isdigit ((int) SubBuffer[1]))) + { + TokenStart = SubBuffer; + SubBuffer++; + + while (1) + { + /* Walk over the lower case letters and decimal digits */ + + while (islower ((int) *SubBuffer) || + isdigit ((int) *SubBuffer)) + { + SubBuffer++; + } + + /* Check for end of line or end of token */ + + if (*SubBuffer == '\n') + { + LineNumber++; + break; + } + + if (*SubBuffer == ' ') + { + /* Check for form "Axx - " in a parameter header description */ + + while (*SubBuffer == ' ') + { + SubBuffer++; + } + + SubBuffer--; + if ((SubBuffer[1] == '-') && + (SubBuffer[2] == ' ')) + { + if (TokenStart) + { + *TokenStart = (char) tolower ((int) *TokenStart); + } + } + break; + } + + /* + * Ignore these combinations: + * + * + * + */ + if (isdigit ((int) *SubBuffer)) + { + if (isalnum ((int) *(SubBuffer-1)) || + *(SubBuffer-1) == '_') + { + break; + } + } + + /* Ignore token if next character is not uppercase or digit */ + + if (!isupper ((int) *SubBuffer) && + !isdigit ((int) *SubBuffer)) + { + break; + } + + /* + * Form (AxxB): + * Convert leading character of the token to lower case + */ + if (TokenStart) + { + *TokenStart = (char) tolower ((int) *TokenStart); + TokenStart = NULL; + } + + /* Find the end of this identifier (token) */ + + TokenEnd = SubBuffer - 1; + while ((isalnum ((int) *TokenEnd)) || + (*TokenEnd == '_')) + { + TokenEnd++; + } + + SubString = TokenEnd; + Length = 0; + + while (*SubString != '\n') + { + /* + * If we have at least two trailing spaces, we can get rid of + * one to make up for the newly inserted underscore. This will + * help preserve the alignment of the text + */ + if ((SubString[0] == ' ') && + (SubString[1] == ' ')) + { + Length = SubString - SubBuffer - 1; + break; + } + + SubString++; + } + + if (!Length) + { + Length = strlen (&SubBuffer[0]); + } + + /* + * Within this identifier, convert this pair of letters that + * matches the form: + * + * + * to + * + */ + Gbl_MadeChanges = TRUE; + + /* Insert the underscore */ + + memmove (&SubBuffer[1], &SubBuffer[0], Length + 1); + SubBuffer[0] = '_'; + + /* + * If we have , leave them as-is + * Enables transforms like: + * LocalFADT -> local_FADT + */ + if (isupper ((int) SubBuffer[2])) + { + SubBuffer += 1; + break; + } + + /* Lower case the original upper case letter */ + + SubBuffer[1] = (char) tolower ((int) SubBuffer[1]); + SubBuffer += 2; + } + } + + SubBuffer++; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsLowerCaseIdentifiers + * + * DESCRIPTION: Converts mixed case identifiers to lower case. Leaves comments, + * quoted strings, and all-upper-case macros alone. + * + ******************************************************************************/ + +void +AsLowerCaseIdentifiers ( + char *Buffer) +{ + char *SubBuffer = Buffer; + + + while (*SubBuffer) + { + /* + * Check for translation escape string -- means to ignore + * blocks of code while replacing + */ + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*') && + (SubBuffer[2] == '!')) + { + SubBuffer = strstr (SubBuffer, "!*/"); + if (!SubBuffer) + { + return; + } + } + + /* Ignore comments */ + + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*')) + { + SubBuffer = strstr (SubBuffer, "*/"); + if (!SubBuffer) + { + return; + } + + SubBuffer += 2; + } + + /* Ignore quoted strings */ + + if ((SubBuffer[0] == '\"') && (SubBuffer[1] != '\'')) + { + SubBuffer++; + + /* Find the closing quote */ + + while (SubBuffer[0]) + { + /* Ignore escaped quote characters */ + + if (SubBuffer[0] == '\\') + { + SubBuffer++; + } + else if (SubBuffer[0] == '\"') + { + SubBuffer++; + break; + } + + SubBuffer++; + } + } + + if (!SubBuffer[0]) + { + return; + } + + /* + * Only lower case if we have an upper followed by a lower + * This leaves the all-uppercase things (macros, etc.) intact + */ + if ((isupper ((int) SubBuffer[0])) && + (islower ((int) SubBuffer[1]))) + { + Gbl_MadeChanges = TRUE; + *SubBuffer = (char) tolower ((int) *SubBuffer); + } + + SubBuffer++; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsUppercaseTokens + * + * DESCRIPTION: Force to uppercase all tokens that begin with the prefix string. + * used to convert mixed-case macros and constants to uppercase. + * + ******************************************************************************/ + +void +AsUppercaseTokens ( + char *Buffer, + char *PrefixString) +{ + char *SubBuffer; + char *TokenEnd; + char *SubString; + int i; + UINT32 Length; + + + SubBuffer = Buffer; + + while (SubBuffer) + { + SubBuffer = strstr (SubBuffer, PrefixString); + if (SubBuffer) + { + TokenEnd = SubBuffer; + while ((isalnum ((int) *TokenEnd)) || (*TokenEnd == '_')) + { + TokenEnd++; + } + + for (i = 0; i < (TokenEnd - SubBuffer); i++) + { + if ((islower ((int) SubBuffer[i])) && + (isupper ((int) SubBuffer[i+1]))) + { + + SubString = TokenEnd; + Length = 0; + + while (*SubString != '\n') + { + if ((SubString[0] == ' ') && + (SubString[1] == ' ')) + { + Length = SubString - &SubBuffer[i] - 2; + break; + } + + SubString++; + } + + if (!Length) + { + Length = strlen (&SubBuffer[i+1]); + } + + memmove (&SubBuffer[i+2], &SubBuffer[i+1], (Length+1)); + SubBuffer[i+1] = '_'; + i +=2; + TokenEnd++; + } + } + + for (i = 0; i < (TokenEnd - SubBuffer); i++) + { + SubBuffer[i] = (char) toupper ((int) SubBuffer[i]); + } + + SubBuffer = TokenEnd; + } + } +} diff --git a/third_party/lib/acpica/source/tools/acpisrc/asconvrt.c b/third_party/lib/acpica/source/tools/acpisrc/asconvrt.c new file mode 100644 index 000000000..70a3f0a30 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/asconvrt.c @@ -0,0 +1,1747 @@ +/****************************************************************************** + * + * Module Name: asconvrt - Source conversion code + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" + +AS_BRACE_INFO Gbl_BraceInfo[] = +{ + {" if", 3}, + {" else if", 8}, + {" else while", 11}, + {" else", 5}, + {" do ", 4}, + {NULL, 0} +}; + + +/* Local prototypes */ + +static char * +AsMatchValidToken ( + char *Buffer, + char *Filename, + char TargetChar, + AS_SCAN_CALLBACK Callback); + +static char * +AsCheckBracesCallback ( + char *Buffer, + char *Filename, + UINT32 LineNumber); + +static UINT32 +AsCountLines ( + char *Buffer, + char *Filename); + + +/* Opening signature of the Intel legal header */ + +char *HeaderBegin = "/******************************************************************************\n *\n * 1. Copyright Notice"; + +UINT32 NonAnsiCommentCount; + + +/****************************************************************************** + * + * FUNCTION: AsCountNonAnsiComments + * + * DESCRIPTION: Count the number of "//" comments. This type of comment is + * non-ANSI C. + * + * NOTE: July 2014: Allows // within quoted strings and within normal + * comments. Eliminates extraneous warnings from this utility. + * + ******************************************************************************/ + +void +AsCountNonAnsiComments ( + char *Buffer, + char *Filename) +{ + + AsMatchValidToken (Buffer, Filename, 0, NULL); + + /* Error if any slash-slash comments found */ + + if (NonAnsiCommentCount) + { + AsPrint ("Non-ANSI // Comments Found", NonAnsiCommentCount, Filename); + Gbl_NonAnsiComments += NonAnsiCommentCount; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsCheckForBraces + * + * DESCRIPTION: Check for an open brace after each if/else/do (etc.) + * statement + * + ******************************************************************************/ + +void +AsCheckForBraces ( + char *Buffer, + char *Filename) +{ + + AsMatchValidToken (Buffer, Filename, 0, AsCheckBracesCallback); +} + + +/****************************************************************************** + * + * FUNCTION: AsCheckBracesCallback + * + * DESCRIPTION: Check if/else/do statements. Ensure that braces + * are always used. + * + * TBD: Currently, don't check while() statements. The problem is that there + * are two forms: do {} while (); and while () {}. + * + ******************************************************************************/ + +static char * +AsCheckBracesCallback ( + char *Buffer, + char *Filename, + UINT32 LineNumber) +{ + char *SubBuffer = Buffer; + char *NextBrace; + char *NextSemicolon; + AS_BRACE_INFO *BraceInfo; + + + for (BraceInfo = Gbl_BraceInfo; BraceInfo->Operator; BraceInfo++) + { + if (!(strncmp (BraceInfo->Operator, SubBuffer, BraceInfo->Length))) + { + SubBuffer += (BraceInfo->Length - 1); + + /* Find next brace and the next semicolon */ + + NextBrace = AsMatchValidToken (SubBuffer, Filename, '{', NULL); + NextSemicolon = AsMatchValidToken (SubBuffer, Filename, ';', NULL); + + /* Next brace should appear before next semicolon */ + + if ((!NextBrace) || + (NextSemicolon && (NextBrace > NextSemicolon))) + { + Gbl_MissingBraces++; + + if (!Gbl_QuietMode) + { + printf ("Missing braces for <%s>, line %u: %s\n", + BraceInfo->Operator + 1, LineNumber, Filename); + } + } + + return (SubBuffer); + } + } + + /* No match, just return original buffer */ + + return (Buffer); +} + + +/****************************************************************************** + * + * FUNCTION: AsMatchValidToken + * + * DESCRIPTION: Find the next matching token in the input buffer. + * + ******************************************************************************/ + +static char * +AsMatchValidToken ( + char *Buffer, + char *Filename, + char TargetChar, + AS_SCAN_CALLBACK Callback) +{ + char *SubBuffer = Buffer; + char *StringStart; + UINT32 TotalLines; + + + TotalLines = 1; + NonAnsiCommentCount = 0; + + /* Scan from current position up to the end if necessary */ + + while (*SubBuffer) + { + /* Skip normal comments */ + + if ((*SubBuffer == '/') && + (*(SubBuffer + 1) == '*')) + { + /* Must maintain line count */ + + SubBuffer += 2; + while (strncmp ("*/", SubBuffer, 2)) + { + if (*SubBuffer == '\n') + { + TotalLines++; + } + SubBuffer++; + } + + SubBuffer += 2; + continue; + } + + /* Skip single quoted chars */ + + if (*SubBuffer == '\'') + { + SubBuffer++; + if (!(*SubBuffer)) + { + break; + } + + if (*SubBuffer == '\\') + { + SubBuffer++; + } + + SubBuffer++; + continue; + } + + /* Skip quoted strings */ + + if (*SubBuffer == '"') + { + StringStart = SubBuffer; + SubBuffer++; + if (!(*SubBuffer)) + { + break; + } + + while (*SubBuffer != '"') + { + if ((*SubBuffer == '\n') || + (!(*SubBuffer))) + { + AsPrint ("Unbalanced quoted string",1, Filename); + printf (" %.32s (line %u)\n", StringStart, TotalLines); + break; + } + + /* Handle escapes within the string */ + + if (*SubBuffer == '\\') + { + SubBuffer++; + } + + SubBuffer++; + } + + SubBuffer++; + continue; + } + + /* Now we can check for a slash-slash comment */ + + if ((*SubBuffer == '/') && + (*(SubBuffer + 1) == '/')) + { + NonAnsiCommentCount++; + + /* Skip to end-of-line */ + + while ((*SubBuffer != '\n') && + (*SubBuffer)) + { + SubBuffer++; + } + + if (!(*SubBuffer)) + { + break; + } + + if (*SubBuffer == '\n') + { + TotalLines++; + } + + SubBuffer++; + continue; + } + + /* Finally, check for a newline */ + + if (*SubBuffer == '\n') + { + TotalLines++; + SubBuffer++; + continue; + } + + /* Normal character, do the user actions */ + + if (Callback) + { + SubBuffer = Callback (SubBuffer, Filename, TotalLines); + } + + if (TargetChar && (*SubBuffer == TargetChar)) + { + return (SubBuffer); + } + + SubBuffer++; + } + + return (NULL); +} + + +/****************************************************************************** + * + * FUNCTION: AsRemoveExtraLines + * + * DESCRIPTION: Remove all extra lines at the start and end of the file. + * + ******************************************************************************/ + +void +AsRemoveExtraLines ( + char *FileBuffer, + char *Filename) +{ + char *FileEnd; + int Length; + + + /* Remove any extra lines at the start of the file */ + + while (*FileBuffer == '\n') + { + printf ("Removing extra line at start of file: %s\n", Filename); + AsRemoveData (FileBuffer, FileBuffer + 1); + } + + /* Remove any extra lines at the end of the file */ + + Length = strlen (FileBuffer); + FileEnd = FileBuffer + (Length - 2); + + while (*FileEnd == '\n') + { + printf ("Removing extra line at end of file: %s\n", Filename); + AsRemoveData (FileEnd, FileEnd + 1); + FileEnd--; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsRemoveSpacesAfterPeriod + * + * DESCRIPTION: Remove an extra space after a period. + * + ******************************************************************************/ + +void +AsRemoveSpacesAfterPeriod ( + char *FileBuffer, + char *Filename) +{ + int ReplaceCount = 0; + char *Possible; + + + Possible = FileBuffer; + while (Possible) + { + Possible = strstr (Possible, ". "); + if (Possible) + { + if ((*(Possible -1) == '.') || + (*(Possible -1) == '\"') || + (*(Possible -1) == '\n')) + { + Possible += 3; + continue; + } + + Possible = AsReplaceData (Possible, 3, ". ", 2); + ReplaceCount++; + } + } + + if (ReplaceCount) + { + printf ("Removed %d extra blanks after a period: %s\n", + ReplaceCount, Filename); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsMatchExactWord + * + * DESCRIPTION: Check previous and next characters for whitespace + * + ******************************************************************************/ + +BOOLEAN +AsMatchExactWord ( + char *Word, + UINT32 WordLength) +{ + char NextChar; + char PrevChar; + + + NextChar = Word[WordLength]; + PrevChar = * (Word -1); + + if (isalnum ((int) NextChar) || + (NextChar == '_') || + isalnum ((int) PrevChar) || + (PrevChar == '_')) + { + return (FALSE); + } + + return (TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: AsPrint + * + * DESCRIPTION: Common formatted print + * + ******************************************************************************/ + +void +AsPrint ( + char *Message, + UINT32 Count, + char *Filename) +{ + + if (Gbl_QuietMode) + { + return; + } + + printf ("-- %4u %28.28s : %s\n", Count, Message, Filename); +} + + +/****************************************************************************** + * + * FUNCTION: AsTrimLines + * + * DESCRIPTION: Remove extra blanks from the end of source lines. Does not + * check for tabs. + * + ******************************************************************************/ + +void +AsTrimLines ( + char *Buffer, + char *Filename) +{ + char *SubBuffer = Buffer; + char *StartWhiteSpace = NULL; + UINT32 SpaceCount = 0; + + + while (*SubBuffer) + { + while (*SubBuffer != '\n') + { + if (!*SubBuffer) + { + goto Exit; + } + + if (*SubBuffer == ' ') + { + if (!StartWhiteSpace) + { + StartWhiteSpace = SubBuffer; + } + } + else + { + StartWhiteSpace = NULL; + } + + SubBuffer++; + } + + if (StartWhiteSpace) + { + SpaceCount += (SubBuffer - StartWhiteSpace); + + /* Remove the spaces */ + + SubBuffer = AsRemoveData (StartWhiteSpace, SubBuffer); + StartWhiteSpace = NULL; + } + + SubBuffer++; + } + + +Exit: + if (SpaceCount) + { + Gbl_MadeChanges = TRUE; + AsPrint ("Extraneous spaces removed", SpaceCount, Filename); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsTrimWhitespace + * + * DESCRIPTION: Remove "excess" blank lines - any more than 2 blank lines. + * this can happen during the translation when lines are removed. + * + ******************************************************************************/ + +void +AsTrimWhitespace ( + char *Buffer) +{ + char *SubBuffer; + int ReplaceCount = 1; + + + while (ReplaceCount) + { + ReplaceCount = AsReplaceString ("\n\n\n\n", "\n\n\n", + REPLACE_SUBSTRINGS, Buffer); + } + + /* + * Check for exactly one blank line after the copyright header + */ + + /* Find the header */ + + SubBuffer = strstr (Buffer, HeaderBegin); + if (!SubBuffer) + { + return; + } + + /* Find the end of the header */ + + SubBuffer = strstr (SubBuffer, "*/"); + SubBuffer = AsSkipPastChar (SubBuffer, '\n'); + + /* Replace a double blank line with a single */ + + if (!strncmp (SubBuffer, "\n\n", 2)) + { + AsReplaceData (SubBuffer, 2, "\n", 1); + AcpiOsPrintf ("Found multiple blank lines after copyright\n"); + } + + /* If no blank line after header, insert one */ + + else if (*SubBuffer != '\n') + { + AsInsertData (SubBuffer, "\n", 1); + AcpiOsPrintf ("Inserted blank line after copyright\n"); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsReplaceHeader + * + * DESCRIPTION: Replace the default Intel legal header with a new header + * + ******************************************************************************/ + +void +AsReplaceHeader ( + char *Buffer, + char *NewHeader) +{ + char *SubBuffer; + char *TokenEnd; + + + /* Find the original header */ + + SubBuffer = strstr (Buffer, HeaderBegin); + if (!SubBuffer) + { + return; + } + + /* Find the end of the original header */ + + TokenEnd = strstr (SubBuffer, "*/"); + TokenEnd = AsSkipPastChar (TokenEnd, '\n'); + + /* Delete old header, insert new one */ + + AsReplaceData (SubBuffer, TokenEnd - SubBuffer, + NewHeader, strlen (NewHeader)); +} + + +/****************************************************************************** + * + * FUNCTION: AsReplaceString + * + * DESCRIPTION: Replace all instances of a target string with a replacement + * string. Returns count of the strings replaced. + * + ******************************************************************************/ + +int +AsReplaceString ( + char *Target, + char *Replacement, + UINT8 Type, + char *Buffer) +{ + char *SubString1; + char *SubString2; + char *SubBuffer; + int TargetLength; + int ReplacementLength; + int ReplaceCount = 0; + + + TargetLength = strlen (Target); + ReplacementLength = strlen (Replacement); + + SubBuffer = Buffer; + SubString1 = Buffer; + + while (SubString1) + { + /* Find the target string */ + + SubString1 = strstr (SubBuffer, Target); + if (!SubString1) + { + return (ReplaceCount); + } + + /* + * Check for translation escape string -- means to ignore + * blocks of code while replacing + */ + if (Gbl_IgnoreTranslationEscapes) + { + SubString2 = NULL; + } + else + { + SubString2 = strstr (SubBuffer, AS_START_IGNORE); + } + + if ((SubString2) && + (SubString2 < SubString1)) + { + /* Find end of the escape block starting at "Substring2" */ + + SubString2 = strstr (SubString2, AS_STOP_IGNORE); + if (!SubString2) + { + /* Didn't find terminator */ + + return (ReplaceCount); + } + + /* Move buffer to end of escape block and continue */ + + SubBuffer = SubString2; + } + + /* Do the actual replace if the target was found */ + + else + { + if ((Type & REPLACE_MASK) == REPLACE_WHOLE_WORD) + { + if (!AsMatchExactWord (SubString1, TargetLength)) + { + SubBuffer = SubString1 + 1; + continue; + } + } + + SubBuffer = AsReplaceData (SubString1, TargetLength, + Replacement, ReplacementLength); + + if ((Type & EXTRA_INDENT_C) && + (!Gbl_StructDefs)) + { + SubBuffer = AsInsertData (SubBuffer, " ", 8); + } + + ReplaceCount++; + } + } + + return (ReplaceCount); +} + + +/****************************************************************************** + * + * FUNCTION: AsConvertToLineFeeds + * + * DESCRIPTION: Convert all CR/LF pairs to LF only. + * + ******************************************************************************/ + +void +AsConvertToLineFeeds ( + char *Buffer) +{ + char *SubString; + char *SubBuffer; + + + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + /* Find the target string */ + + SubString = strstr (SubBuffer, "\r\n"); + if (!SubString) + { + return; + } + + SubBuffer = AsReplaceData (SubString, 1, NULL, 0); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsInsertCarriageReturns + * + * DESCRIPTION: Convert lone LFs to CR/LF pairs. + * + ******************************************************************************/ + +void +AsInsertCarriageReturns ( + char *Buffer) +{ + char *SubString; + char *SubBuffer; + + + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + /* Find the target string */ + + SubString = strstr (SubBuffer, "\n"); + if (!SubString) + { + return; + } + + SubBuffer = AsInsertData (SubString, "\r", 1); + SubBuffer += 1; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsBracesOnSameLine + * + * DESCRIPTION: Move opening braces up to the same line as an if, for, else, + * or while statement (leave function opening brace on separate + * line). + * + ******************************************************************************/ + +void +AsBracesOnSameLine ( + char *Buffer) +{ + char *SubBuffer = Buffer; + char *Beginning; + char *StartOfThisLine; + char *Next; + BOOLEAN BlockBegin = TRUE; + + + while (*SubBuffer) + { + /* Ignore comments */ + + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*')) + { + SubBuffer = strstr (SubBuffer, "*/"); + if (!SubBuffer) + { + return; + } + + SubBuffer += 2; + continue; + } + + /* Ignore quoted strings */ + + if (*SubBuffer == '\"') + { + SubBuffer++; + SubBuffer = AsSkipPastChar (SubBuffer, '\"'); + if (!SubBuffer) + { + return; + } + } + + if (!strncmp ("\n}", SubBuffer, 2)) + { + /* + * A newline followed by a closing brace closes a function + * or struct or initializer block + */ + BlockBegin = TRUE; + } + + /* + * Move every standalone brace up to the previous line + * Check for digit will ignore initializer lists surrounded by braces. + * This will work until we we need more complex detection. + */ + if ((*SubBuffer == '{') && !isdigit ((int) SubBuffer[1])) + { + if (BlockBegin) + { + BlockBegin = FALSE; + } + else + { + /* + * Backup to previous non-whitespace + */ + Beginning = SubBuffer - 1; + while ((*Beginning == ' ') || + (*Beginning == '\n')) + { + Beginning--; + } + + StartOfThisLine = Beginning; + while (*StartOfThisLine != '\n') + { + StartOfThisLine--; + } + + /* + * Move the brace up to the previous line, UNLESS: + * + * 1) There is a conditional compile on the line (starts with '#') + * 2) Previous line ends with an '=' (Start of initializer block) + * 3) Previous line ends with a comma (part of an init list) + * 4) Previous line ends with a backslash (part of a macro) + */ + if ((StartOfThisLine[1] != '#') && + (*Beginning != '\\') && + (*Beginning != '/') && + (*Beginning != '{') && + (*Beginning != '=') && + (*Beginning != ',')) + { + Beginning++; + SubBuffer++; + + Gbl_MadeChanges = TRUE; + +#ifdef ADD_EXTRA_WHITESPACE + AsReplaceData (Beginning, SubBuffer - Beginning, " {\n", 3); +#else + /* Find non-whitespace start of next line */ + + Next = SubBuffer + 1; + while ((*Next == ' ') || + (*Next == '\t')) + { + Next++; + } + + /* Find non-whitespace start of this line */ + + StartOfThisLine++; + while ((*StartOfThisLine == ' ') || + (*StartOfThisLine == '\t')) + { + StartOfThisLine++; + } + + /* + * Must be a single-line comment to need more whitespace + * Even then, we don't need more if the previous statement + * is an "else". + */ + if ((Next[0] == '/') && + (Next[1] == '*') && + (Next[2] != '\n') && + + (!strncmp (StartOfThisLine, "else if", 7) || + !strncmp (StartOfThisLine, "else while", 10) || + strncmp (StartOfThisLine, "else", 4))) + { + AsReplaceData (Beginning, SubBuffer - Beginning, " {\n", 3); + } + else + { + AsReplaceData (Beginning, SubBuffer - Beginning, " {", 2); + } +#endif + } + } + } + + SubBuffer++; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsTabify4 + * + * DESCRIPTION: Convert the text to tabbed text. Alignment of text is + * preserved. + * + ******************************************************************************/ + +void +AsTabify4 ( + char *Buffer) +{ + char *SubBuffer = Buffer; + char *NewSubBuffer; + UINT32 SpaceCount = 0; + UINT32 Column = 0; + + + while (*SubBuffer) + { + if (*SubBuffer == '\n') + { + Column = 0; + } + else + { + Column++; + } + + /* Ignore comments */ + + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*')) + { + SubBuffer = strstr (SubBuffer, "*/"); + if (!SubBuffer) + { + return; + } + + SubBuffer += 2; + continue; + } + + /* Ignore quoted strings */ + + if (*SubBuffer == '\"') + { + SubBuffer++; + SubBuffer = AsSkipPastChar (SubBuffer, '\"'); + if (!SubBuffer) + { + return; + } + SpaceCount = 0; + } + + if (*SubBuffer == ' ') + { + SpaceCount++; + + if (SpaceCount >= 4) + { + SpaceCount = 0; + + NewSubBuffer = (SubBuffer + 1) - 4; + *NewSubBuffer = '\t'; + NewSubBuffer++; + + /* Remove the spaces */ + + SubBuffer = AsRemoveData (NewSubBuffer, SubBuffer + 1); + } + + if ((Column % 4) == 0) + { + SpaceCount = 0; + } + } + else + { + SpaceCount = 0; + } + + SubBuffer++; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsTabify8 + * + * DESCRIPTION: Convert the text to tabbed text. Alignment of text is + * preserved. + * + ******************************************************************************/ + +void +AsTabify8 ( + char *Buffer) +{ + char *SubBuffer = Buffer; + char *NewSubBuffer; + char *CommentEnd = NULL; + UINT32 SpaceCount = 0; + UINT32 Column = 0; + UINT32 TabCount = 0; + UINT32 LastLineTabCount = 0; + UINT32 LastLineColumnStart = 0; + UINT32 ThisColumnStart = 0; + UINT32 ThisTabCount = 0; + char *FirstNonBlank = NULL; + + + while (*SubBuffer) + { + if (*SubBuffer == '\n') + { + /* This is a standalone blank line */ + + FirstNonBlank = NULL; + Column = 0; + SpaceCount = 0; + TabCount = 0; + SubBuffer++; + continue; + } + + if (!FirstNonBlank) + { + /* Find the first non-blank character on this line */ + + FirstNonBlank = SubBuffer; + while (*FirstNonBlank == ' ') + { + FirstNonBlank++; + } + + /* + * This mechanism limits the difference in tab counts from + * line to line. It helps avoid the situation where a second + * continuation line (which was indented correctly for tabs=4) would + * get indented off the screen if we just blindly converted to tabs. + */ + ThisColumnStart = FirstNonBlank - SubBuffer; + + if (LastLineTabCount == 0) + { + ThisTabCount = 0; + } + else if (ThisColumnStart == LastLineColumnStart) + { + ThisTabCount = LastLineTabCount -1; + } + else + { + ThisTabCount = LastLineTabCount + 1; + } + } + + Column++; + + /* Check if we are in a comment */ + + if ((SubBuffer[0] == '*') && + (SubBuffer[1] == '/')) + { + SpaceCount = 0; + SubBuffer += 2; + + if (*SubBuffer == '\n') + { + if (TabCount > 0) + { + LastLineTabCount = TabCount; + TabCount = 0; + } + + FirstNonBlank = NULL; + LastLineColumnStart = ThisColumnStart; + SubBuffer++; + } + + continue; + } + + /* Check for comment open */ + + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*')) + { + /* Find the end of the comment, it must exist */ + + CommentEnd = strstr (SubBuffer, "*/"); + if (!CommentEnd) + { + return; + } + + /* Toss the rest of this line or single-line comment */ + + while ((SubBuffer < CommentEnd) && + (*SubBuffer != '\n')) + { + SubBuffer++; + } + + if (*SubBuffer == '\n') + { + if (TabCount > 0) + { + LastLineTabCount = TabCount; + TabCount = 0; + } + + FirstNonBlank = NULL; + LastLineColumnStart = ThisColumnStart; + } + + SpaceCount = 0; + continue; + } + + /* Ignore quoted strings */ + + if ((!CommentEnd) && (*SubBuffer == '\"')) + { + SubBuffer++; + SubBuffer = AsSkipPastChar (SubBuffer, '\"'); + if (!SubBuffer) + { + return; + } + + SpaceCount = 0; + } + + if (*SubBuffer != ' ') + { + /* Not a space, skip to end of line */ + + SubBuffer = AsSkipUntilChar (SubBuffer, '\n'); + if (!SubBuffer) + { + return; + } + if (TabCount > 0) + { + LastLineTabCount = TabCount; + TabCount = 0; + } + + FirstNonBlank = NULL; + LastLineColumnStart = ThisColumnStart; + Column = 0; + SpaceCount = 0; + } + else + { + /* Another space */ + + SpaceCount++; + + if (SpaceCount >= 4) + { + /* Replace this group of spaces with a tab character */ + + SpaceCount = 0; + + NewSubBuffer = SubBuffer - 3; + + if (TabCount <= ThisTabCount ? (ThisTabCount +1) : 0) + { + *NewSubBuffer = '\t'; + NewSubBuffer++; + SubBuffer++; + TabCount++; + } + + /* Remove the spaces */ + + SubBuffer = AsRemoveData (NewSubBuffer, SubBuffer); + continue; + } + } + + SubBuffer++; + } +} + + +/****************************************************************************** + * + * FUNCTION: AsCountLines + * + * DESCRIPTION: Count the number of lines in the input buffer. Also count + * the number of long lines (lines longer than 80 chars). + * + ******************************************************************************/ + +static UINT32 +AsCountLines ( + char *Buffer, + char *Filename) +{ + char *SubBuffer = Buffer; + char *EndOfLine; + UINT32 LineCount = 0; + UINT32 LongLineCount = 0; + + + while (*SubBuffer) + { + EndOfLine = AsSkipUntilChar (SubBuffer, '\n'); + if (!EndOfLine) + { + Gbl_TotalLines += LineCount; + return (LineCount); + } + + if ((EndOfLine - SubBuffer) > 80) + { + LongLineCount++; + VERBOSE_PRINT (("long: %.80s\n", SubBuffer)); + } + + LineCount++; + SubBuffer = EndOfLine + 1; + } + + if (LongLineCount) + { + VERBOSE_PRINT (("%u Lines longer than 80 found in %s\n", + LongLineCount, Filename)); + + Gbl_LongLines += LongLineCount; + } + + Gbl_TotalLines += LineCount; + return (LineCount); +} + + +/****************************************************************************** + * + * FUNCTION: AsCountTabs + * + * DESCRIPTION: Simply count the number of tabs in the input file buffer + * + ******************************************************************************/ + +void +AsCountTabs ( + char *Buffer, + char *Filename) +{ + UINT32 i; + UINT32 TabCount = 0; + + + for (i = 0; Buffer[i]; i++) + { + if (Buffer[i] == '\t') + { + TabCount++; + } + } + + if (TabCount) + { + AsPrint ("Tabs found", TabCount, Filename); + Gbl_Tabs += TabCount; + } + + AsCountLines (Buffer, Filename); +} + + +/****************************************************************************** + * + * FUNCTION: AsCountSourceLines + * + * DESCRIPTION: Count the number of C source lines. Defined by 1) not a + * comment, and 2) not a blank line. + * + ******************************************************************************/ + +void +AsCountSourceLines ( + char *Buffer, + char *Filename) +{ + char *SubBuffer = Buffer; + UINT32 LineCount = 0; + UINT32 WhiteCount = 0; + UINT32 CommentCount = 0; + + + while (*SubBuffer) + { + /* Detect comments (// comments are not used, non-ansii) */ + + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*')) + { + SubBuffer += 2; + + /* First line of multi-line comment is often just whitespace */ + + if (SubBuffer[0] == '\n') + { + WhiteCount++; + SubBuffer++; + } + else + { + CommentCount++; + } + + /* Find end of comment */ + + while (SubBuffer[0] && SubBuffer[1] && + !(((SubBuffer[0] == '*') && + (SubBuffer[1] == '/')))) + { + if (SubBuffer[0] == '\n') + { + CommentCount++; + } + + SubBuffer++; + } + } + + /* A linefeed followed by a non-linefeed is a valid source line */ + + else if ((SubBuffer[0] == '\n') && + (SubBuffer[1] != '\n')) + { + LineCount++; + } + + /* Two back-to-back linefeeds indicate a whitespace line */ + + else if ((SubBuffer[0] == '\n') && + (SubBuffer[1] == '\n')) + { + WhiteCount++; + } + + SubBuffer++; + } + + /* Adjust comment count for legal header */ + + if (Gbl_HeaderSize < CommentCount) + { + CommentCount -= Gbl_HeaderSize; + Gbl_HeaderLines += Gbl_HeaderSize; + } + + Gbl_SourceLines += LineCount; + Gbl_WhiteLines += WhiteCount; + Gbl_CommentLines += CommentCount; + + VERBOSE_PRINT (("%u Comment %u White %u Code %u Lines in %s\n", + CommentCount, WhiteCount, LineCount, + LineCount + WhiteCount + CommentCount, Filename)); +} + + +/****************************************************************************** + * + * FUNCTION: AsInsertPrefix + * + * DESCRIPTION: Insert struct or union prefixes + * + ******************************************************************************/ + +void +AsInsertPrefix ( + char *Buffer, + char *Keyword, + UINT8 Type) +{ + char *SubString; + char *SubBuffer; + char *EndKeyword; + int InsertLength; + char *InsertString; + int TrailingSpaces; + char LowerKeyword[128]; + int KeywordLength; + + + switch (Type) + { + case SRC_TYPE_STRUCT: + + InsertString = "struct "; + break; + + case SRC_TYPE_UNION: + + InsertString = "union "; + break; + + default: + + return; + } + + strcpy (LowerKeyword, Keyword); + AcpiUtStrlwr (LowerKeyword); + + SubBuffer = Buffer; + SubString = Buffer; + InsertLength = strlen (InsertString); + KeywordLength = strlen (Keyword); + + + while (SubString) + { + /* Find an instance of the keyword */ + + SubString = strstr (SubBuffer, LowerKeyword); + if (!SubString) + { + return; + } + + SubBuffer = SubString; + + /* Must be standalone word, not a substring */ + + if (AsMatchExactWord (SubString, KeywordLength)) + { + /* Make sure the keyword isn't already prefixed with the insert */ + + if (!strncmp (SubString - InsertLength, InsertString, InsertLength)) + { + /* Add spaces if not already at the end-of-line */ + + if (*(SubBuffer + KeywordLength) != '\n') + { + /* Already present, add spaces after to align structure members */ + +#if 0 +/* ONLY FOR C FILES */ + AsInsertData (SubBuffer + KeywordLength, " ", 8); +#endif + } + goto Next; + } + + /* Make sure the keyword isn't at the end of a struct/union */ + /* Note: This code depends on a single space after the brace */ + + if (*(SubString - 2) == '}') + { + goto Next; + } + + /* Prefix the keyword with the insert string */ + + Gbl_MadeChanges = TRUE; + + /* Is there room for insertion */ + + EndKeyword = SubString + strlen (LowerKeyword); + + TrailingSpaces = 0; + while (EndKeyword[TrailingSpaces] == ' ') + { + TrailingSpaces++; + } + + /* + * Use "if (TrailingSpaces > 1)" if we want to ignore casts + */ + SubBuffer = SubString + InsertLength; + + if (TrailingSpaces > InsertLength) + { + /* Insert the keyword */ + + memmove (SubBuffer, SubString, KeywordLength); + + /* Insert the keyword */ + + memmove (SubString, InsertString, InsertLength); + } + else + { + AsInsertData (SubString, InsertString, InsertLength); + } + } + +Next: + SubBuffer += KeywordLength; + } +} + +#ifdef ACPI_FUTURE_IMPLEMENTATION +/****************************************************************************** + * + * FUNCTION: AsTrimComments + * + * DESCRIPTION: Finds 3-line comments with only a single line of text + * + ******************************************************************************/ + +void +AsTrimComments ( + char *Buffer, + char *Filename) +{ + char *SubBuffer = Buffer; + char *Ptr1; + char *Ptr2; + UINT32 LineCount; + UINT32 ShortCommentCount = 0; + + + while (1) + { + /* Find comment open, within procedure level */ + + SubBuffer = strstr (SubBuffer, " /*"); + if (!SubBuffer) + { + goto Exit; + } + + /* Find comment terminator */ + + Ptr1 = strstr (SubBuffer, "*/"); + if (!Ptr1) + { + goto Exit; + } + + /* Find next EOL (from original buffer) */ + + Ptr2 = strstr (SubBuffer, "\n"); + if (!Ptr2) + { + goto Exit; + } + + /* Ignore one-line comments */ + + if (Ptr1 < Ptr2) + { + /* Normal comment, ignore and continue; */ + + SubBuffer = Ptr2; + continue; + } + + /* Examine multi-line comment */ + + LineCount = 1; + while (Ptr1 > Ptr2) + { + /* Find next EOL */ + + Ptr2++; + Ptr2 = strstr (Ptr2, "\n"); + if (!Ptr2) + { + goto Exit; + } + + LineCount++; + } + + SubBuffer = Ptr1; + + if (LineCount <= 3) + { + ShortCommentCount++; + } + } + + +Exit: + + if (ShortCommentCount) + { + AsPrint ("Short Comments found", ShortCommentCount, Filename); + } +} +#endif + +#ifdef ACPI_UNUSED_FUNCTIONS +/****************************************************************************** + * + * FUNCTION: AsCheckAndSkipLiterals + * + * DESCRIPTION: Generic routine to skip comments and quoted string literals. + * Keeps a line count. + * + ******************************************************************************/ + +static char * +AsCheckAndSkipLiterals ( + char *Buffer, + UINT32 *TotalLines); + + +static char * +AsCheckAndSkipLiterals ( + char *Buffer, + UINT32 *TotalLines) +{ + UINT32 NewLines = 0; + char *SubBuffer = Buffer; + char *LiteralEnd; + + + /* Ignore comments */ + + if ((SubBuffer[0] == '/') && + (SubBuffer[1] == '*')) + { + LiteralEnd = strstr (SubBuffer, "*/"); + SubBuffer += 2; /* Get past comment opening */ + + if (!LiteralEnd) + { + return (SubBuffer); + } + + while (SubBuffer < LiteralEnd) + { + if (*SubBuffer == '\n') + { + NewLines++; + } + + SubBuffer++; + } + + SubBuffer += 2; /* Get past comment close */ + } + + /* Ignore quoted strings */ + + else if (*SubBuffer == '\"') + { + SubBuffer++; + LiteralEnd = AsSkipPastChar (SubBuffer, '\"'); + if (!LiteralEnd) + { + return (SubBuffer); + } + } + + if (TotalLines) + { + (*TotalLines) += NewLines; + } + return (SubBuffer); +} +#endif diff --git a/third_party/lib/acpica/source/tools/acpisrc/asfile.c b/third_party/lib/acpica/source/tools/acpisrc/asfile.c new file mode 100644 index 000000000..2836dd65b --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/asfile.c @@ -0,0 +1,839 @@ +/****************************************************************************** + * + * Module Name: asfile - Main module for the acpi source processor utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" +#include "acapps.h" + +/* Local prototypes */ + +void +AsDoWildcard ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *SourcePath, + char *TargetPath, + int MaxPathLength, + int FileType, + char *WildcardSpec); + +BOOLEAN +AsDetectLoneLineFeeds ( + char *Filename, + char *Buffer); + +static ACPI_INLINE int +AsMaxInt (int a, int b) +{ + return (a > b ? a : b); +} + + +/****************************************************************************** + * + * FUNCTION: AsDoWildcard + * + * DESCRIPTION: Process files via wildcards + * + ******************************************************************************/ + +void +AsDoWildcard ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *SourcePath, + char *TargetPath, + int MaxPathLength, + int FileType, + char *WildcardSpec) +{ + void *DirInfo; + char *Filename; + char *SourceDirPath; + char *TargetDirPath; + char RequestedFileType; + + + if (FileType == FILE_TYPE_DIRECTORY) + { + RequestedFileType = REQUEST_DIR_ONLY; + } + else + { + RequestedFileType = REQUEST_FILE_ONLY; + } + + VERBOSE_PRINT (("Checking for %s source files in directory \"%s\"\n", + WildcardSpec, SourcePath)); + + /* Open the directory for wildcard search */ + + DirInfo = AcpiOsOpenDirectory (SourcePath, WildcardSpec, RequestedFileType); + if (DirInfo) + { + /* + * Get all of the files that match both the + * wildcard and the requested file type + */ + while ((Filename = AcpiOsGetNextFilename (DirInfo))) + { + /* Looking for directory files, must check file type */ + + switch (RequestedFileType) + { + case REQUEST_DIR_ONLY: + + /* If we actually have a dir, process the subtree */ + + if (!AsCheckForDirectory (SourcePath, TargetPath, Filename, + &SourceDirPath, &TargetDirPath)) + { + VERBOSE_PRINT (("Subdirectory: %s\n", Filename)); + + AsProcessTree (ConversionTable, SourceDirPath, TargetDirPath); + free (SourceDirPath); + free (TargetDirPath); + } + break; + + case REQUEST_FILE_ONLY: + + /* Otherwise, this is a file, not a directory */ + + VERBOSE_PRINT (("File: %s\n", Filename)); + + AsProcessOneFile (ConversionTable, SourcePath, TargetPath, + MaxPathLength, Filename, FileType); + break; + + default: + + break; + } + } + + /* Cleanup */ + + AcpiOsCloseDirectory (DirInfo); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsProcessTree + * + * DESCRIPTION: Process the directory tree. Files with the extension ".C" and + * ".H" are processed as the tree is traversed. + * + ******************************************************************************/ + +ACPI_NATIVE_INT +AsProcessTree ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *SourcePath, + char *TargetPath) +{ + int MaxPathLength; + + + MaxPathLength = AsMaxInt (strlen (SourcePath), strlen (TargetPath)); + + if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT)) + { + if (ConversionTable->Flags & FLG_LOWERCASE_DIRNAMES) + { + AcpiUtStrlwr (TargetPath); + } + + VERBOSE_PRINT (("Creating Directory \"%s\"\n", TargetPath)); + if (mkdir (TargetPath)) + { + if (errno != EEXIST) + { + printf ("Could not create target directory\n"); + return (-1); + } + } + } + + /* Do the C source files */ + + AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, + FILE_TYPE_SOURCE, "*.c"); + + /* Do the C header files */ + + AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, + FILE_TYPE_HEADER, "*.h"); + + /* Do the Lex file(s) */ + + AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, + FILE_TYPE_SOURCE, "*.l"); + + /* Do the yacc file(s) */ + + AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, + FILE_TYPE_SOURCE, "*.y"); + + /* Do any ASL files */ + + AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, + FILE_TYPE_HEADER, "*.asl"); + + /* Do any subdirectories */ + + AsDoWildcard (ConversionTable, SourcePath, TargetPath, MaxPathLength, + FILE_TYPE_DIRECTORY, "*"); + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: AsDetectLoneLineFeeds + * + * DESCRIPTION: Find LF without CR. + * + ******************************************************************************/ + +BOOLEAN +AsDetectLoneLineFeeds ( + char *Filename, + char *Buffer) +{ + UINT32 i = 1; + UINT32 LfCount = 0; + UINT32 LineCount = 0; + + + if (!Buffer[0]) + { + return (FALSE); + } + + while (Buffer[i]) + { + if (Buffer[i] == 0x0A) + { + if (Buffer[i-1] != 0x0D) + { + LfCount++; + } + + LineCount++; + } + i++; + } + + if (LfCount) + { + if (LineCount == LfCount) + { + if (!Gbl_IgnoreLoneLineFeeds) + { + printf ("%s: ****File has UNIX format**** (LF only, not CR/LF) %u lines\n", + Filename, LfCount); + } + } + else + { + printf ("%s: %u lone linefeeds in file\n", Filename, LfCount); + } + + return (TRUE); + } + + return (FALSE); +} + + +/****************************************************************************** + * + * FUNCTION: AsConvertFile + * + * DESCRIPTION: Perform the requested transforms on the file buffer (as + * determined by the ConversionTable and the FileType). + * + ******************************************************************************/ + +void +AsConvertFile ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *FileBuffer, + char *Filename, + ACPI_NATIVE_INT FileType) +{ + UINT32 i; + UINT32 Functions; + ACPI_STRING_TABLE *StringTable; + ACPI_IDENTIFIER_TABLE *ConditionalTable; + ACPI_IDENTIFIER_TABLE *LineTable; + ACPI_TYPED_IDENTIFIER_TABLE *StructTable; + ACPI_IDENTIFIER_TABLE *SpecialMacroTable; + + + switch (FileType) + { + case FILE_TYPE_SOURCE: + + Functions = ConversionTable->SourceFunctions; + StringTable = ConversionTable->SourceStringTable; + LineTable = ConversionTable->SourceLineTable; + ConditionalTable = ConversionTable->SourceConditionalTable; + StructTable = ConversionTable->SourceStructTable; + SpecialMacroTable = ConversionTable->SourceSpecialMacroTable; + break; + + case FILE_TYPE_HEADER: + + Functions = ConversionTable->HeaderFunctions; + StringTable = ConversionTable->HeaderStringTable; + LineTable = ConversionTable->HeaderLineTable; + ConditionalTable = ConversionTable->HeaderConditionalTable; + StructTable = ConversionTable->HeaderStructTable; + SpecialMacroTable = ConversionTable->HeaderSpecialMacroTable; + break; + + case FILE_TYPE_PATCH: + + Functions = ConversionTable->PatchFunctions; + StringTable = ConversionTable->PatchStringTable; + LineTable = ConversionTable->PatchLineTable; + ConditionalTable = ConversionTable->PatchConditionalTable; + StructTable = ConversionTable->PatchStructTable; + SpecialMacroTable = ConversionTable->PatchSpecialMacroTable; + break; + + default: + + printf ("Unknown file type, cannot process\n"); + return; + } + + + Gbl_StructDefs = strstr (FileBuffer, "/* acpisrc:StructDefs"); + Gbl_Files++; + VERBOSE_PRINT (("Processing %u bytes\n", + (unsigned int) strlen (FileBuffer))); + + if (Gbl_Cleanup) + { + AsRemoveExtraLines (FileBuffer, Filename); + AsRemoveSpacesAfterPeriod (FileBuffer, Filename); + } + + if (ConversionTable->LowerCaseTable) + { + for (i = 0; ConversionTable->LowerCaseTable[i].Identifier; i++) + { + AsLowerCaseString (ConversionTable->LowerCaseTable[i].Identifier, + FileBuffer); + } + } + + /* Process all the string replacements */ + + if (StringTable) + { + for (i = 0; StringTable[i].Target; i++) + { + AsReplaceString (StringTable[i].Target, StringTable[i].Replacement, + StringTable[i].Type, FileBuffer); + } + } + + if (LineTable) + { + for (i = 0; LineTable[i].Identifier; i++) + { + AsRemoveLine (FileBuffer, LineTable[i].Identifier); + } + } + + if (ConditionalTable) + { + for (i = 0; ConditionalTable[i].Identifier; i++) + { + AsRemoveConditionalCompile (FileBuffer, ConditionalTable[i].Identifier); + } + } + +#ifdef _OBSOLETE_FUNCTIONS + if (MacroTable) + { + for (i = 0; MacroTable[i].Identifier; i++) + { + AsRemoveMacro (FileBuffer, MacroTable[i].Identifier); + } + } +#endif + + if (StructTable) + { + for (i = 0; StructTable[i].Identifier; i++) + { + AsInsertPrefix (FileBuffer, StructTable[i].Identifier, + StructTable[i].Type); + } + } + + if (SpecialMacroTable) + { + for (i = 0; SpecialMacroTable[i].Identifier; i++) + { + AsCleanupSpecialMacro (FileBuffer, SpecialMacroTable[i].Identifier); + } + } + + /* Process the function table */ + + for (i = 0; i < 32; i++) + { + /* Decode the function bitmap */ + + switch ((1 << i) & Functions) + { + case 0: + + /* This function not configured */ + break; + + case CVT_COUNT_TABS: + + AsCountTabs (FileBuffer, Filename); + break; + + case CVT_COUNT_NON_ANSI_COMMENTS: + + AsCountNonAnsiComments (FileBuffer, Filename); + break; + + case CVT_CHECK_BRACES: + + AsCheckForBraces (FileBuffer, Filename); + break; + + case CVT_TRIM_LINES: + + AsTrimLines (FileBuffer, Filename); + break; + + case CVT_COUNT_LINES: + + AsCountSourceLines (FileBuffer, Filename); + break; + + case CVT_BRACES_ON_SAME_LINE: + + AsBracesOnSameLine (FileBuffer); + break; + + case CVT_MIXED_CASE_TO_UNDERSCORES: + + AsMixedCaseToUnderscores (FileBuffer, Filename); + break; + + case CVT_LOWER_CASE_IDENTIFIERS: + + AsLowerCaseIdentifiers (FileBuffer); + break; + + case CVT_REMOVE_DEBUG_MACROS: + + AsRemoveDebugMacros (FileBuffer); + break; + + case CVT_TRIM_WHITESPACE: + + AsTrimWhitespace (FileBuffer); + break; + + case CVT_REMOVE_EMPTY_BLOCKS: + + AsRemoveEmptyBlocks (FileBuffer, Filename); + break; + + case CVT_REDUCE_TYPEDEFS: + + AsReduceTypedefs (FileBuffer, "typedef union"); + AsReduceTypedefs (FileBuffer, "typedef struct"); + break; + + case CVT_SPACES_TO_TABS4: + + AsTabify4 (FileBuffer); + break; + + case CVT_SPACES_TO_TABS8: + + AsTabify8 (FileBuffer); + break; + + case CVT_COUNT_SHORTMULTILINE_COMMENTS: + +#ifdef ACPI_FUTURE_IMPLEMENTATION + AsTrimComments (FileBuffer, Filename); +#endif + break; + + default: + + printf ("Unknown conversion subfunction opcode\n"); + break; + } + } + + if (ConversionTable->NewHeader) + { + AsReplaceHeader (FileBuffer, ConversionTable->NewHeader); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsProcessOneFile + * + * DESCRIPTION: Process one source file. The file is opened, read entirely + * into a buffer, converted, then written to a new file. + * + ******************************************************************************/ + +ACPI_NATIVE_INT +AsProcessOneFile ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *SourcePath, + char *TargetPath, + int MaxPathLength, + char *Filename, + ACPI_NATIVE_INT FileType) +{ + char *Pathname; + char *OutPathname = NULL; + + + /* Allocate a file pathname buffer for both source and target */ + + Pathname = calloc (MaxPathLength + strlen (Filename) + 2, 1); + if (!Pathname) + { + printf ("Could not allocate buffer for file pathnames\n"); + return (-1); + } + + Gbl_FileType = FileType; + + /* Generate the source pathname and read the file */ + + if (SourcePath) + { + strcpy (Pathname, SourcePath); + strcat (Pathname, "/"); + } + + strcat (Pathname, Filename); + + if (AsGetFile (Pathname, &Gbl_FileBuffer, &Gbl_FileSize)) + { + return (-1); + } + + Gbl_HeaderSize = 0; + if (strstr (Filename, ".asl")) + { + Gbl_HeaderSize = LINES_IN_ASL_HEADER; /* Lines in default ASL header */ + } + else if (strstr (Gbl_FileBuffer, LEGAL_HEADER_SIGNATURE)) + { + Gbl_HeaderSize = LINES_IN_LEGAL_HEADER; /* Normal C file and H header */ + } + else if (strstr (Gbl_FileBuffer, LINUX_HEADER_SIGNATURE)) + { + Gbl_HeaderSize = LINES_IN_LINUX_HEADER; /* Linuxized C file and H header */ + } + + /* Process the file in the buffer */ + + Gbl_MadeChanges = FALSE; + if (!Gbl_IgnoreLoneLineFeeds && Gbl_HasLoneLineFeeds) + { + /* + * All lone LFs will be converted to CR/LF + * (when file is written, Windows version only) + */ + printf ("Converting lone linefeeds\n"); + Gbl_MadeChanges = TRUE; + } + + AsConvertFile (ConversionTable, Gbl_FileBuffer, Pathname, FileType); + + if (!(ConversionTable->Flags & FLG_NO_FILE_OUTPUT)) + { + if (!(Gbl_Overwrite && !Gbl_MadeChanges)) + { + /* Generate the target pathname and write the file */ + + OutPathname = calloc (MaxPathLength + + strlen (Filename) + 2 + strlen (TargetPath), 1); + if (!OutPathname) + { + printf ("Could not allocate buffer for file pathnames\n"); + return (-1); + } + + strcpy (OutPathname, TargetPath); + if (SourcePath) + { + strcat (OutPathname, "/"); + strcat (OutPathname, Filename); + } + + AsPutFile (OutPathname, Gbl_FileBuffer, ConversionTable->Flags); + } + } + + free (Gbl_FileBuffer); + free (Pathname); + if (OutPathname) + { + free (OutPathname); + } + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: AsCheckForDirectory + * + * DESCRIPTION: Check if the current file is a valid directory. If not, + * construct the full pathname for the source and target paths. + * Checks for the dot and dot-dot files (they are ignored) + * + ******************************************************************************/ + +ACPI_NATIVE_INT +AsCheckForDirectory ( + char *SourceDirPath, + char *TargetDirPath, + char *Filename, + char **SourcePath, + char **TargetPath) +{ + char *SrcPath; + char *TgtPath; + + + if (!(strcmp (Filename, ".")) || + !(strcmp (Filename, ".."))) + { + return (-1); + } + + SrcPath = calloc (strlen (SourceDirPath) + strlen (Filename) + 2, 1); + if (!SrcPath) + { + printf ("Could not allocate buffer for directory source pathname\n"); + return (-1); + } + + TgtPath = calloc (strlen (TargetDirPath) + strlen (Filename) + 2, 1); + if (!TgtPath) + { + printf ("Could not allocate buffer for directory target pathname\n"); + free (SrcPath); + return (-1); + } + + strcpy (SrcPath, SourceDirPath); + strcat (SrcPath, "/"); + strcat (SrcPath, Filename); + + strcpy (TgtPath, TargetDirPath); + strcat (TgtPath, "/"); + strcat (TgtPath, Filename); + + *SourcePath = SrcPath; + *TargetPath = TgtPath; + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: AsGetFile + * + * DESCRIPTION: Open a file and read it entirely into a an allocated buffer + * + ******************************************************************************/ + +int +AsGetFile ( + char *Filename, + char **FileBuffer, + UINT32 *FileSize) +{ + FILE *File; + UINT32 Size; + char *Buffer; + size_t Actual; + + + /* Binary mode leaves CR/LF pairs */ + + File = fopen (Filename, "rb"); + if (!File) + { + printf ("Could not open file %s\n", Filename); + return (-1); + } + + /* Need file size to allocate a buffer */ + + Size = CmGetFileSize (File); + if (Size == ACPI_UINT32_MAX) + { + printf ("Could not get file size for %s\n", Filename); + goto ErrorExit; + } + + /* + * Create a buffer for the entire file + * Add plenty extra buffer to accommodate string replacements + */ + Gbl_TotalSize += Size; + + Buffer = calloc (Size * 2, 1); + if (!Buffer) + { + printf ("Could not allocate buffer of size %u\n", Size * 2); + goto ErrorExit; + } + + /* Read the entire file */ + + Actual = fread (Buffer, 1, Size, File); + if (Actual != Size) + { + printf ("Could not read the input file %s (%u bytes)\n", + Filename, Size); + goto ErrorExit; + } + + Buffer [Size] = 0; /* Null terminate the buffer */ + fclose (File); + + /* Check for unix contamination */ + + Gbl_HasLoneLineFeeds = AsDetectLoneLineFeeds (Filename, Buffer); + + /* + * Convert all CR/LF pairs to LF only. We do this locally so that + * this code is portable across operating systems. + */ + AsConvertToLineFeeds (Buffer); + + *FileBuffer = Buffer; + *FileSize = Size; + return (0); + + +ErrorExit: + + fclose (File); + return (-1); +} + + +/****************************************************************************** + * + * FUNCTION: AsPutFile + * + * DESCRIPTION: Create a new output file and write the entire contents of the + * buffer to the new file. Buffer must be a zero terminated string + * + ******************************************************************************/ + +int +AsPutFile ( + char *Pathname, + char *FileBuffer, + UINT32 SystemFlags) +{ + FILE *File; + UINT32 FileSize; + size_t Actual; + int Status = 0; + + + /* Create the target file */ + + if (!(SystemFlags & FLG_NO_CARRIAGE_RETURNS)) + { + /* Put back the CR before each LF */ + + AsInsertCarriageReturns (FileBuffer); + } + + File = fopen (Pathname, "w+b"); + if (!File) + { + perror ("Could not create destination file"); + printf ("Could not create destination file \"%s\"\n", Pathname); + return (-1); + } + + /* Write the buffer to the file */ + + FileSize = strlen (FileBuffer); + Actual = fwrite (FileBuffer, 1, FileSize, File); + if (Actual != FileSize) + { + printf ("Error writing output file \"%s\"\n", Pathname); + Status = -1; + } + + fclose (File); + return (Status); +} diff --git a/third_party/lib/acpica/source/tools/acpisrc/asmain.c b/third_party/lib/acpica/source/tools/acpisrc/asmain.c new file mode 100644 index 000000000..f64e95f5f --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/asmain.c @@ -0,0 +1,483 @@ +/****************************************************************************** + * + * Module Name: asmain - Main module for the acpi source processor utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" +#include "acapps.h" + +/* Local prototypes */ + +int +AsExaminePaths ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *Source, + char *Target, + UINT32 *SourceFileType); + +void +AsDisplayStats ( + void); + +void +AsDisplayUsage ( + void); + +/* Globals */ + +UINT32 Gbl_Tabs = 0; +UINT32 Gbl_MissingBraces = 0; +UINT32 Gbl_NonAnsiComments = 0; +UINT32 Gbl_Files = 0; +UINT32 Gbl_WhiteLines = 0; +UINT32 Gbl_CommentLines = 0; +UINT32 Gbl_SourceLines = 0; +UINT32 Gbl_LongLines = 0; +UINT32 Gbl_TotalLines = 0; +UINT32 Gbl_TotalSize = 0; +UINT32 Gbl_HeaderLines = 0; +UINT32 Gbl_HeaderSize = 0; +void *Gbl_StructDefs = NULL; + +struct stat Gbl_StatBuf; +char *Gbl_FileBuffer; +UINT32 Gbl_FileSize; +UINT32 Gbl_FileType; +BOOLEAN Gbl_VerboseMode = FALSE; +BOOLEAN Gbl_QuietMode = FALSE; +BOOLEAN Gbl_BatchMode = FALSE; +BOOLEAN Gbl_DebugStatementsMode = FALSE; +BOOLEAN Gbl_MadeChanges = FALSE; +BOOLEAN Gbl_Overwrite = FALSE; +BOOLEAN Gbl_WidenDeclarations = FALSE; +BOOLEAN Gbl_IgnoreLoneLineFeeds = FALSE; +BOOLEAN Gbl_HasLoneLineFeeds = FALSE; +BOOLEAN Gbl_Cleanup = FALSE; +BOOLEAN Gbl_IgnoreTranslationEscapes = FALSE; + +#define AS_UTILITY_NAME "ACPI Source Code Conversion Utility" +#define AS_SUPPORTED_OPTIONS "cdhilqsuv^y" + + +/****************************************************************************** + * + * FUNCTION: AsExaminePaths + * + * DESCRIPTION: Source and Target pathname verification and handling + * + ******************************************************************************/ + +int +AsExaminePaths ( + ACPI_CONVERSION_TABLE *ConversionTable, + char *Source, + char *Target, + UINT32 *SourceFileType) +{ + int Status; + int Response; + + + Status = stat (Source, &Gbl_StatBuf); + if (Status) + { + printf ("Source path \"%s\" does not exist\n", Source); + return (-1); + } + + /* Return the filetype -- file or a directory */ + + *SourceFileType = 0; + if (Gbl_StatBuf.st_mode & S_IFDIR) + { + *SourceFileType = S_IFDIR; + } + + /* + * If we are in no-output mode or in batch mode, we are done + */ + if ((ConversionTable->Flags & FLG_NO_FILE_OUTPUT) || + (Gbl_BatchMode)) + { + return (0); + } + + if (!AcpiUtStricmp (Source, Target)) + { + printf ("Target path is the same as the source path, overwrite?\n"); + Response = getchar (); + + /* Check response */ + + if (Response != 'y') + { + return (-1); + } + + Gbl_Overwrite = TRUE; + } + else + { + Status = stat (Target, &Gbl_StatBuf); + if (!Status) + { + printf ("Target path already exists, overwrite?\n"); + Response = getchar (); + + /* Check response */ + + if (Response != 'y') + { + return (-1); + } + } + } + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: AsDisplayStats + * + * DESCRIPTION: Display global statistics gathered during translation + * + ******************************************************************************/ + +void +AsDisplayStats ( + void) +{ + + if (Gbl_QuietMode) + { + return; + } + + printf ("\nAcpiSrc statistics:\n\n"); + printf ("%8u Files processed\n", Gbl_Files); + + if (!Gbl_Files) + { + return; + } + + printf ("%8u Total bytes (%.1fK/file)\n", + Gbl_TotalSize, ((double) Gbl_TotalSize/Gbl_Files)/1024); + printf ("%8u Tabs found\n", Gbl_Tabs); + printf ("%8u Missing if/else/while braces\n", Gbl_MissingBraces); + printf ("%8u Non-ANSI // comments found\n", Gbl_NonAnsiComments); + printf ("%8u Total Lines\n", Gbl_TotalLines); + printf ("%8u Lines of code\n", Gbl_SourceLines); + printf ("%8u Lines of non-comment whitespace\n", Gbl_WhiteLines); + printf ("%8u Lines of comments\n", Gbl_CommentLines); + printf ("%8u Long lines found\n", Gbl_LongLines); + + if (Gbl_WhiteLines > 0) + { + printf ("%8.1f Ratio of code to whitespace\n", + ((float) Gbl_SourceLines / (float) Gbl_WhiteLines)); + } + + if ((Gbl_CommentLines + Gbl_NonAnsiComments) > 0) + { + printf ("%8.1f Ratio of code to comments\n", + ((float) Gbl_SourceLines / + (float) (Gbl_CommentLines + Gbl_NonAnsiComments))); + } + + if (!Gbl_TotalLines) + { + return; + } + + printf (" %u%% code, %u%% comments, %u%% whitespace, %u%% headers\n", + (Gbl_SourceLines * 100) / Gbl_TotalLines, + (Gbl_CommentLines * 100) / Gbl_TotalLines, + (Gbl_WhiteLines * 100) / Gbl_TotalLines, + (Gbl_HeaderLines * 100) / Gbl_TotalLines); + return; +} + + +/****************************************************************************** + * + * FUNCTION: AsDisplayUsage + * + * DESCRIPTION: Usage message + * + ******************************************************************************/ + +void +AsDisplayUsage ( + void) +{ + + ACPI_USAGE_HEADER ("acpisrc [-c|l|u] [-dsvy] "); + + ACPI_OPTION ("-c", "Generate cleaned version of the source"); + ACPI_OPTION ("-h", "Insert dual-license header into all modules"); + ACPI_OPTION ("-i", "Cleanup macro indentation"); + ACPI_OPTION ("-l", "Generate Linux version of the source"); + ACPI_OPTION ("-u", "Generate Custom source translation"); + + ACPI_USAGE_TEXT ("\n"); + ACPI_OPTION ("-d", "Leave debug statements in code"); + ACPI_OPTION ("-s", "Generate source statistics only"); + ACPI_OPTION ("-v", "Display version information"); + ACPI_OPTION ("-vb", "Verbose mode"); + ACPI_OPTION ("-y", "Suppress file overwrite prompts"); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * DESCRIPTION: C main function + * + ******************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char *argv[]) +{ + int j; + ACPI_CONVERSION_TABLE *ConversionTable = NULL; + char *SourcePath; + char *TargetPath; + UINT32 FileType; + + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + AcpiOsInitialize (); + printf (ACPI_COMMON_SIGNON (AS_UTILITY_NAME)); + + if (argc < 2) + { + AsDisplayUsage (); + return (0); + } + + /* Command line options */ + + while ((j = AcpiGetopt (argc, argv, AS_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch(j) + { + case 'l': + + /* Linux code generation */ + + printf ("Creating Linux source code\n"); + ConversionTable = &LinuxConversionTable; + Gbl_WidenDeclarations = TRUE; + Gbl_IgnoreLoneLineFeeds = TRUE; + break; + + case 'c': + + /* Cleanup code */ + + printf ("Code cleanup\n"); + ConversionTable = &CleanupConversionTable; + Gbl_Cleanup = TRUE; + break; + + case 'h': + + /* Inject Dual-license header */ + + printf ("Inserting Dual-license header to all modules\n"); + ConversionTable = &LicenseConversionTable; + break; + + case 'i': + + /* Cleanup wrong indent result */ + + printf ("Cleaning up macro indentation\n"); + ConversionTable = &IndentConversionTable; + Gbl_IgnoreLoneLineFeeds = TRUE; + Gbl_IgnoreTranslationEscapes = TRUE; + break; + + case 's': + + /* Statistics only */ + + break; + + case 'u': + + /* custom conversion */ + + printf ("Custom source translation\n"); + ConversionTable = &CustomConversionTable; + break; + + case 'v': + + switch (AcpiGbl_Optarg[0]) + { + case '^': /* -v: (Version): signon already emitted, just exit */ + + exit (0); + + case 'b': + + /* Verbose mode */ + + Gbl_VerboseMode = TRUE; + break; + + default: + + printf ("Unknown option: -v%s\n", AcpiGbl_Optarg); + return (-1); + } + + break; + + case 'y': + + /* Batch mode */ + + Gbl_BatchMode = TRUE; + break; + + case 'd': + + /* Leave debug statements in */ + + Gbl_DebugStatementsMode = TRUE; + break; + + case 'q': + + /* Quiet mode */ + + Gbl_QuietMode = TRUE; + break; + + default: + + AsDisplayUsage (); + return (-1); + } + + + SourcePath = argv[AcpiGbl_Optind]; + if (!SourcePath) + { + printf ("Missing source path\n"); + AsDisplayUsage (); + return (-1); + } + + TargetPath = argv[AcpiGbl_Optind+1]; + + if (!ConversionTable) + { + /* Just generate statistics. Ignore target path */ + + TargetPath = SourcePath; + + printf ("Source code statistics only\n"); + ConversionTable = &StatsConversionTable; + } + else if (!TargetPath) + { + TargetPath = SourcePath; + } + + if (Gbl_DebugStatementsMode) + { + ConversionTable->SourceFunctions &= ~CVT_REMOVE_DEBUG_MACROS; + } + + /* Check source and target paths and files */ + + if (AsExaminePaths (ConversionTable, SourcePath, TargetPath, &FileType)) + { + return (-1); + } + + /* Source/target can be either directories or a files */ + + if (FileType == S_IFDIR) + { + /* Process the directory tree */ + + AsProcessTree (ConversionTable, SourcePath, TargetPath); + } + else + { + /* Process a single file */ + + /* Differentiate between source and header files */ + + if (strstr (SourcePath, ".h")) + { + AsProcessOneFile (ConversionTable, NULL, TargetPath, 0, + SourcePath, FILE_TYPE_HEADER); + } + else if (strstr (SourcePath, ".c")) + { + AsProcessOneFile (ConversionTable, NULL, TargetPath, 0, + SourcePath, FILE_TYPE_SOURCE); + } + else if (strstr (SourcePath, ".patch")) + { + AsProcessOneFile (ConversionTable, NULL, TargetPath, 0, + SourcePath, FILE_TYPE_PATCH); + } + else + { + printf ("Unknown file type - %s\n", SourcePath); + } + } + + /* Always display final summary and stats */ + + AsDisplayStats (); + return (0); +} diff --git a/third_party/lib/acpica/source/tools/acpisrc/asremove.c b/third_party/lib/acpica/source/tools/acpisrc/asremove.c new file mode 100644 index 000000000..c5d70804f --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/asremove.c @@ -0,0 +1,740 @@ +/****************************************************************************** + * + * Module Name: asremove - Source conversion - removal functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" + +/* Local prototypes */ + +void +AsRemoveStatement ( + char *Buffer, + char *Keyword, + UINT32 Type); + + +/****************************************************************************** + * + * FUNCTION: AsRemoveStatement + * + * DESCRIPTION: Remove all statements that contain the given keyword. + * Limitations: Removes text from the start of the line that + * contains the keyword to the next semicolon. Currently + * doesn't ignore comments. + * + ******************************************************************************/ + +void +AsRemoveStatement ( + char *Buffer, + char *Keyword, + UINT32 Type) +{ + char *SubString; + char *SubBuffer; + int KeywordLength; + + + KeywordLength = strlen (Keyword); + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + SubString = strstr (SubBuffer, Keyword); + + if (SubString) + { + SubBuffer = SubString; + + if ((Type == REPLACE_WHOLE_WORD) && + (!AsMatchExactWord (SubString, KeywordLength))) + { + SubBuffer++; + continue; + } + + /* Find start of this line */ + + while (*SubString != '\n') + { + SubString--; + } + SubString++; + + /* Find end of this statement */ + + SubBuffer = AsSkipPastChar (SubBuffer, ';'); + if (!SubBuffer) + { + return; + } + + /* Find end of this line */ + + SubBuffer = AsSkipPastChar (SubBuffer, '\n'); + if (!SubBuffer) + { + return; + } + + /* If next line is blank, remove it too */ + + if (*SubBuffer == '\n') + { + SubBuffer++; + } + + /* Remove the lines */ + + SubBuffer = AsRemoveData (SubString, SubBuffer); + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AsRemoveConditionalCompile + * + * DESCRIPTION: Remove a "#ifdef" statement, and all text that it encompasses. + * Limitations: cannot handle nested ifdefs. + * + ******************************************************************************/ + +void +AsRemoveConditionalCompile ( + char *Buffer, + char *Keyword) +{ + char *SubString; + char *SubBuffer; + char *IfPtr; + char *EndifPtr; + char *ElsePtr; + char *Comment; + int KeywordLength; + + + KeywordLength = strlen (Keyword); + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + SubBuffer = strstr (SubString, Keyword); + if (!SubBuffer) + { + return; + } + + /* + * Check for translation escape string -- means to ignore + * blocks of code while replacing + */ + if (Gbl_IgnoreTranslationEscapes) + { + Comment = NULL; + } + else + { + Comment = strstr (SubString, AS_START_IGNORE); + } + + if ((Comment) && + (Comment < SubBuffer)) + { + SubString = strstr (Comment, AS_STOP_IGNORE); + if (!SubString) + { + return; + } + + SubString += 3; + continue; + } + + /* Check for ordinary comment */ + + Comment = strstr (SubString, "/*"); + + if ((Comment) && + (Comment < SubBuffer)) + { + SubString = strstr (Comment, "*/"); + if (!SubString) + { + return; + } + + SubString += 2; + continue; + } + + SubString = SubBuffer; + if (!AsMatchExactWord (SubString, KeywordLength)) + { + SubString++; + continue; + } + + /* Find start of this line */ + + while (*SubString != '\n' && (SubString > Buffer)) + { + SubString--; + } + + SubString++; + + /* Find the "#ifxxxx" */ + + IfPtr = strstr (SubString, "#if"); + if (!IfPtr) + { + return; + } + + if (IfPtr > SubBuffer) + { + /* Not the right #if */ + + SubString = SubBuffer + strlen (Keyword); + continue; + } + + /* Find closing #endif or #else */ + + EndifPtr = strstr (SubBuffer, "#endif"); + if (!EndifPtr) + { + /* There has to be an #endif */ + + return; + } + + ElsePtr = strstr (SubBuffer, "#else"); + if ((ElsePtr) && + (EndifPtr > ElsePtr)) + { + /* This #ifdef contains an #else clause */ + /* Find end of this line */ + + SubBuffer = AsSkipPastChar (ElsePtr, '\n'); + if (!SubBuffer) + { + return; + } + + /* Remove the #ifdef .... #else code */ + + AsRemoveData (SubString, SubBuffer); + + /* Next, we will remove the #endif statement */ + + EndifPtr = strstr (SubString, "#endif"); + if (!EndifPtr) + { + /* There has to be an #endif */ + + return; + } + + SubString = EndifPtr; + } + + /* Remove the ... #endif part */ + /* Find end of this line */ + + SubBuffer = AsSkipPastChar (EndifPtr, '\n'); + if (!SubBuffer) + { + return; + } + + /* Remove the lines */ + + SubBuffer = AsRemoveData (SubString, SubBuffer); + } +} + + +#ifdef _OBSOLETE_FUNCTIONS +/****************************************************************************** + * + * FUNCTION: AsRemoveMacro + * + * DESCRIPTION: Remove every line that contains the keyword. Does not + * skip comments. + * + ******************************************************************************/ + +NOTE: This function is no longer used and is commented out for now. + +Also, it appears to have one or more bugs in it. It can incorrectly remove +lines of code, producing some garbage. + +void +AsRemoveMacro ( + char *Buffer, + char *Keyword) +{ + char *SubString; + char *SubBuffer; + int NestLevel; + + + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + SubString = strstr (SubBuffer, Keyword); + + if (SubString) + { + SubBuffer = SubString; + + /* Find start of the macro parameters */ + + while (*SubString != '(') + { + SubString++; + } + SubString++; + + /* Remove the macro name and opening paren */ + + SubString = AsRemoveData (SubBuffer, SubString); + + NestLevel = 1; + while (*SubString) + { + if (*SubString == '(') + { + NestLevel++; + } + else if (*SubString == ')') + { + NestLevel--; + } + + SubString++; + + if (NestLevel == 0) + { + break; + } + } + + /* Remove the closing paren */ + + SubBuffer = AsRemoveData (SubString-1, SubString); + } + } +} +#endif + +/****************************************************************************** + * + * FUNCTION: AsRemoveLine + * + * DESCRIPTION: Remove every line that contains the keyword. Does not + * skip comments. + * + ******************************************************************************/ + +void +AsRemoveLine ( + char *Buffer, + char *Keyword) +{ + char *SubString; + char *SubBuffer; + + + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + SubString = strstr (SubBuffer, Keyword); + + if (SubString) + { + SubBuffer = SubString; + + /* Find start of this line */ + + while (*SubString != '\n') + { + SubString--; + } + SubString++; + + /* Find end of this line */ + + SubBuffer = AsSkipPastChar (SubBuffer, '\n'); + if (!SubBuffer) + { + return; + } + + /* Remove the line */ + + SubBuffer = AsRemoveData (SubString, SubBuffer); + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AsReduceTypedefs + * + * DESCRIPTION: Eliminate certain typedefs + * + ******************************************************************************/ + +void +AsReduceTypedefs ( + char *Buffer, + char *Keyword) +{ + char *SubString; + char *SubBuffer; + int NestLevel; + + + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + SubString = strstr (SubBuffer, Keyword); + + if (SubString) + { + /* Remove the typedef itself */ + + SubBuffer = SubString + strlen ("typedef") + 1; + SubBuffer = AsRemoveData (SubString, SubBuffer); + + /* Find the opening brace of the struct or union */ + + while (*SubString != '{') + { + SubString++; + } + SubString++; + + /* Find the closing brace. Handles nested braces */ + + NestLevel = 1; + while (*SubString) + { + if (*SubString == '{') + { + NestLevel++; + } + else if (*SubString == '}') + { + NestLevel--; + } + + SubString++; + + if (NestLevel == 0) + { + break; + } + } + + /* Remove an extra line feed if present */ + + if (!strncmp (SubString - 3, "\n\n", 2)) + { + *(SubString -2) = '}'; + SubString--; + } + + /* Find the end of the typedef name */ + + SubBuffer = AsSkipUntilChar (SubString, ';'); + + /* And remove the typedef name */ + + SubBuffer = AsRemoveData (SubString, SubBuffer); + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AsRemoveEmptyBlocks + * + * DESCRIPTION: Remove any C blocks (e.g., if {}) that contain no code. This + * can happen as a result of removing lines such as DEBUG_PRINT. + * + ******************************************************************************/ + +void +AsRemoveEmptyBlocks ( + char *Buffer, + char *Filename) +{ + char *SubBuffer; + char *BlockStart; + BOOLEAN EmptyBlock = TRUE; + BOOLEAN AnotherPassRequired = TRUE; + UINT32 BlockCount = 0; + + + while (AnotherPassRequired) + { + SubBuffer = Buffer; + AnotherPassRequired = FALSE; + + while (*SubBuffer) + { + if (*SubBuffer == '{') + { + BlockStart = SubBuffer; + EmptyBlock = TRUE; + + SubBuffer++; + while (*SubBuffer != '}') + { + if ((*SubBuffer != ' ') && + (*SubBuffer != '\n')) + { + EmptyBlock = FALSE; + break; + } + + SubBuffer++; + } + + if (EmptyBlock) + { + /* Find start of the first line of the block */ + + while (*BlockStart != '\n') + { + BlockStart--; + } + + /* Find end of the last line of the block */ + + SubBuffer = AsSkipUntilChar (SubBuffer, '\n'); + if (!SubBuffer) + { + break; + } + + /* Remove the block */ + + SubBuffer = AsRemoveData (BlockStart, SubBuffer); + BlockCount++; + AnotherPassRequired = TRUE; + continue; + } + } + + SubBuffer++; + } + } + + if (BlockCount) + { + Gbl_MadeChanges = TRUE; + AsPrint ("Code blocks deleted", BlockCount, Filename); + } +} + + +/****************************************************************************** + * + * FUNCTION: AsRemoveDebugMacros + * + * DESCRIPTION: Remove all "Debug" macros -- macros that produce debug output. + * + ******************************************************************************/ + +void +AsRemoveDebugMacros ( + char *Buffer) +{ + AsRemoveConditionalCompile (Buffer, "ACPI_DEBUG_OUTPUT"); + + AsRemoveStatement (Buffer, "ACPI_DEBUG_PRINT", REPLACE_WHOLE_WORD); + AsRemoveStatement (Buffer, "ACPI_DEBUG_PRINT_RAW", REPLACE_WHOLE_WORD); + AsRemoveStatement (Buffer, "DEBUG_EXEC", REPLACE_WHOLE_WORD); + AsRemoveStatement (Buffer, "FUNCTION_ENTRY", REPLACE_WHOLE_WORD); + AsRemoveStatement (Buffer, "PROC_NAME", REPLACE_WHOLE_WORD); + AsRemoveStatement (Buffer, "FUNCTION_TRACE", REPLACE_SUBSTRINGS); + AsRemoveStatement (Buffer, "DUMP_", REPLACE_SUBSTRINGS); + + AsReplaceString ("return_VOID", "return", REPLACE_WHOLE_WORD, Buffer); + AsReplaceString ("return_PTR", "return", REPLACE_WHOLE_WORD, Buffer); + AsReplaceString ("return_ACPI_STATUS", "return", REPLACE_WHOLE_WORD, Buffer); + AsReplaceString ("return_acpi_status", "return", REPLACE_WHOLE_WORD, Buffer); + AsReplaceString ("return_VALUE", "return", REPLACE_WHOLE_WORD, Buffer); +} + + +/****************************************************************************** + * + * FUNCTION: AsCleanupSpecialMacro + * + * DESCRIPTION: For special macro invocations (invoked without ";" at the end + * of the lines), do the following: + * 1. Remove spaces appended by indent at the beginning of lines. + * 2. Add an empty line between two special macro invocations. + * + ******************************************************************************/ + +void +AsCleanupSpecialMacro ( + char *Buffer, + char *Keyword) +{ + char *SubString; + char *SubBuffer; + char *CommentEnd; + int NewLine; + int NestLevel; + + + SubBuffer = Buffer; + SubString = Buffer; + + while (SubString) + { + SubString = strstr (SubBuffer, Keyword); + + if (SubString) + { + /* Find start of the macro parameters */ + + while (*SubString != '(') + { + SubString++; + } + + SubString++; + + NestLevel = 1; + while (*SubString) + { + if (*SubString == '(') + { + NestLevel++; + } + else if (*SubString == ')') + { + NestLevel--; + } + + SubString++; + + if (NestLevel == 0) + { + break; + } + } + +SkipLine: + + /* Find end of the line */ + + NewLine = FALSE; + while (!NewLine && *SubString) + { + if (*SubString == '\n' && *(SubString - 1) != '\\') + { + NewLine = TRUE; + } + + SubString++; + } + + /* Find end of the line */ + + if (*SubString == '#' || *SubString == '\n') + { + goto SkipLine; + } + + SubBuffer = SubString; + + /* Find start of the non-space */ + + while (*SubString == ' ') + { + SubString++; + } + + /* Find end of the line */ + + if (*SubString == '#' || *SubString == '\n') + { + goto SkipLine; + } + + /* Find end of the line */ + + if (*SubString == '/' || *SubString == '*') + { + CommentEnd = strstr (SubString, "*/"); + if (CommentEnd) + { + SubString = CommentEnd + 2; + goto SkipLine; + } + } + + SubString = AsRemoveData (SubBuffer, SubString); + } + } +} diff --git a/third_party/lib/acpica/source/tools/acpisrc/astable.c b/third_party/lib/acpica/source/tools/acpisrc/astable.c new file mode 100644 index 000000000..0e921adeb --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/astable.c @@ -0,0 +1,1124 @@ +/****************************************************************************** + * + * Module Name: astable - Tables used for source conversion + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" +#include "acapps.h" + + +/****************************************************************************** + * + * Standard/Common translation tables + * + ******************************************************************************/ + + +ACPI_STRING_TABLE StandardDataTypes[] = { + + /* Declarations first */ + + {"UINT32 ", "unsigned int", REPLACE_SUBSTRINGS}, + {"UINT16 ", "unsigned short", REPLACE_SUBSTRINGS}, + {"UINT8 ", "unsigned char", REPLACE_SUBSTRINGS}, + {"BOOLEAN ", "unsigned char", REPLACE_SUBSTRINGS}, + + /* Now do embedded typecasts */ + + {"UINT32", "unsigned int", REPLACE_SUBSTRINGS}, + {"UINT16", "unsigned short", REPLACE_SUBSTRINGS}, + {"UINT8", "unsigned char", REPLACE_SUBSTRINGS}, + {"BOOLEAN", "unsigned char", REPLACE_SUBSTRINGS}, + + {"INT32 ", "int ", REPLACE_SUBSTRINGS}, + {"INT32", "int", REPLACE_SUBSTRINGS}, + {"INT16", "short", REPLACE_SUBSTRINGS}, + {"INT8", "char", REPLACE_SUBSTRINGS}, + + /* Put back anything we broke (such as anything with _INT32_ in it) */ + + {"_int_", "_INT32_", REPLACE_SUBSTRINGS}, + {"_unsigned int_", "_UINT32_", REPLACE_SUBSTRINGS}, + {NULL, NULL, 0} +}; + + +/****************************************************************************** + * + * Linux-specific translation tables + * + ******************************************************************************/ + +char DualLicenseHeader[] = +"/*\n" +" * Copyright (C) 2000 - 2016, Intel Corp.\n" +" * All rights reserved.\n" +" *\n" +" * Redistribution and use in source and binary forms, with or without\n" +" * modification, are permitted provided that the following conditions\n" +" * are met:\n" +" * 1. Redistributions of source code must retain the above copyright\n" +" * notice, this list of conditions, and the following disclaimer,\n" +" * without modification.\n" +" * 2. Redistributions in binary form must reproduce at minimum a disclaimer\n" +" * substantially similar to the \"NO WARRANTY\" disclaimer below\n" +" * (\"Disclaimer\") and any redistribution must be conditioned upon\n" +" * including a substantially similar Disclaimer requirement for further\n" +" * binary redistribution.\n" +" * 3. Neither the names of the above-listed copyright holders nor the names\n" +" * of any contributors may be used to endorse or promote products derived\n" +" * from this software without specific prior written permission.\n" +" *\n" +" * Alternatively, this software may be distributed under the terms of the\n" +" * GNU General Public License (\"GPL\") version 2 as published by the Free\n" +" * Software Foundation.\n" +" *\n" +" * NO WARRANTY\n" +" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" +" * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" +" * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR\n" +" * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" +" * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n" +" * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n" +" * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n" +" * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n" +" * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n" +" * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" +" * POSSIBILITY OF SUCH DAMAGES.\n" +" */\n"; + +ACPI_STRING_TABLE LinuxDataTypes[] = { + +/* + * Extra space is added after the type so there is room to add "struct", "union", + * etc. when the existing struct typedefs are eliminated. + */ + + /* Declarations first - ACPI types and standard C types */ + + {"INT64 ", "s64 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"UINT64 ", "u64 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"UINT32 ", "u32 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"INT32 ", "s32 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"UINT16 ", "u16 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"INT16 ", "s16 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"UINT8 ", "u8 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"BOOLEAN ", "u8 ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"char ", "char ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"void ", "void ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"char * ", "char * ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"void * ", "void * ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"int ", "int ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"FILE ", "FILE ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + {"size_t ", "size_t ", REPLACE_WHOLE_WORD | EXTRA_INDENT_C}, + + /* Now do embedded typecasts */ + + {"UINT64", "u64", REPLACE_WHOLE_WORD}, + {"UINT32", "u32", REPLACE_WHOLE_WORD}, + {"UINT16", "u16", REPLACE_WHOLE_WORD}, + {"UINT8", "u8", REPLACE_WHOLE_WORD}, + {"BOOLEAN", "u8", REPLACE_WHOLE_WORD}, + + {"INT64 ", "s64 ", REPLACE_WHOLE_WORD}, + {"INT64", "s64", REPLACE_WHOLE_WORD}, + {"INT32 ", "s32 ", REPLACE_WHOLE_WORD}, + {"INT32", "s32", REPLACE_WHOLE_WORD}, + {"INT16 ", "s16 ", REPLACE_WHOLE_WORD}, + {"INT8 ", "s8 ", REPLACE_WHOLE_WORD}, + {"INT16", "s16", REPLACE_WHOLE_WORD}, + {"INT8", "s8", REPLACE_WHOLE_WORD}, + + {"__FUNCTION__", "__func__", REPLACE_WHOLE_WORD}, + + {NULL, NULL, 0} +}; + +ACPI_TYPED_IDENTIFIER_TABLE AcpiIdentifiers[] = { + + {"ACPI_ADDRESS16_ATTRIBUTE", SRC_TYPE_STRUCT}, + {"ACPI_ADDRESS32_ATTRIBUTE", SRC_TYPE_STRUCT}, + {"ACPI_ADDRESS64_ATTRIBUTE", SRC_TYPE_STRUCT}, + {"ACPI_ADDRESS_RANGE", SRC_TYPE_STRUCT}, + {"ACPI_ADR_SPACE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_ADR_SPACE_SETUP", SRC_TYPE_SIMPLE}, + {"ACPI_ADR_SPACE_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_AML_OPERANDS", SRC_TYPE_UNION}, + {"ACPI_BIT_REGISTER_INFO", SRC_TYPE_STRUCT}, + {"ACPI_BUFFER", SRC_TYPE_STRUCT}, + {"ACPI_BUS_ATTRIBUTE", SRC_TYPE_STRUCT}, + {"ACPI_CACHE_T", SRC_TYPE_SIMPLE}, + {"ACPI_CMTABLE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_COMMON_FACS", SRC_TYPE_STRUCT}, + {"ACPI_COMMON_STATE", SRC_TYPE_STRUCT}, + {"ACPI_COMMON_DESCRIPTOR", SRC_TYPE_STRUCT}, + {"ACPI_COMPATIBLE_ID", SRC_TYPE_STRUCT}, + {"ACPI_CONNECTION_INFO", SRC_TYPE_STRUCT}, + {"ACPI_CONTROL_STATE", SRC_TYPE_STRUCT}, + {"ACPI_CONVERSION_TABLE", SRC_TYPE_STRUCT}, + {"ACPI_CPU_FLAGS", SRC_TYPE_SIMPLE}, + {"ACPI_CREATE_FIELD_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DB_ARGUMENT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DB_COMMAND_HELP", SRC_TYPE_STRUCT}, + {"ACPI_DB_COMMAND_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DB_EXECUTE_WALK", SRC_TYPE_STRUCT}, + {"ACPI_DB_METHOD_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DEBUG_MEM_BLOCK", SRC_TYPE_STRUCT}, + {"ACPI_DEBUG_MEM_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_DEBUG_PRINT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DESCRIPTOR", SRC_TYPE_UNION}, + {"ACPI_DEVICE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DEVICE_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DMTABLE_DATA", SRC_TYPE_STRUCT}, + {"ACPI_DMTABLE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DMTABLE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_EVALUATE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_EVENT_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_EVENT_STATUS", SRC_TYPE_SIMPLE}, + {"ACPI_EVENT_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_EXCEPTION_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_EXCEPTION_INFO", SRC_TYPE_STRUCT}, + {"ACPI_EXDUMP_INFO", SRC_TYPE_STRUCT}, + {"ACPI_EXECUTE_OP", SRC_TYPE_SIMPLE}, + {"ACPI_EXECUTE_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_EXTERNAL_LIST", SRC_TYPE_STRUCT}, + {"ACPI_EXTERNAL_FILE", SRC_TYPE_STRUCT}, + {"ACPI_FADT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_FADT_PM_INFO", SRC_TYPE_STRUCT}, + {"ACPI_FIELD_INFO", SRC_TYPE_STRUCT}, + {"ACPI_FIND_CONTEXT", SRC_TYPE_STRUCT}, + {"ACPI_FIXED_EVENT_HANDLER", SRC_TYPE_STRUCT}, + {"ACPI_FIXED_EVENT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GBL_EVENT_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_GENERIC_ADDRESS", SRC_TYPE_STRUCT}, + {"ACPI_GENERIC_STATE", SRC_TYPE_UNION}, + {"ACPI_GET_DEVICES_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GLOBAL_NOTIFY_HANDLER", SRC_TYPE_STRUCT}, + {"ACPI_GPE_BLOCK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_CALLBACK", SRC_TYPE_SIMPLE}, + {"ACPI_GPE_DEVICE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_EVENT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_GPE_HANDLER_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_INDEX_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_NOTIFY_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_REGISTER_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPE_XRUPT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GPIO_INFO", SRC_TYPE_STRUCT}, + {"ACPI_HANDLE", SRC_TYPE_SIMPLE}, + {"ACPI_HANDLER_INFO", SRC_TYPE_STRUCT}, + {"ACPI_INIT_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_INTERFACE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_IDENTIFIER_TABLE", SRC_TYPE_STRUCT}, + {"ACPI_INIT_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_INTEGER", SRC_TYPE_SIMPLE}, + {"ACPI_INTEGER_OVERLAY", SRC_TYPE_STRUCT}, + {"ACPI_INTEGRITY_INFO", SRC_TYPE_STRUCT}, + {"ACPI_INTERFACE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_INTERNAL_METHOD", SRC_TYPE_SIMPLE}, + {"ACPI_INTERPRETER_MODE", SRC_TYPE_SIMPLE}, + {"ACPI_IO_ADDRESS", SRC_TYPE_SIMPLE}, + {"ACPI_IO_ATTRIBUTE", SRC_TYPE_STRUCT}, + {"ACPI_LPIT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_LPIT_IO", SRC_TYPE_STRUCT}, + {"ACPI_LPIT_NATIVE", SRC_TYPE_STRUCT}, + {"ACPI_MEM_SPACE_CONTEXT", SRC_TYPE_STRUCT}, + {"ACPI_MEMORY_ATTRIBUTE", SRC_TYPE_STRUCT}, + {"ACPI_MEMORY_LIST", SRC_TYPE_STRUCT}, + {"ACPI_METHOD_LOCAL", SRC_TYPE_STRUCT}, + {"ACPI_MTMR_ENTRY", SRC_TYPE_STRUCT}, + {"ACPI_MUTEX", SRC_TYPE_SIMPLE}, + {"ACPI_MUTEX_HANDLE", SRC_TYPE_SIMPLE}, + {"ACPI_MUTEX_INFO", SRC_TYPE_STRUCT}, + {"ACPI_NAME", SRC_TYPE_SIMPLE}, + {"ACPI_NAME_INFO", SRC_TYPE_STRUCT}, + {"ACPI_NAME_UNION", SRC_TYPE_UNION}, + {"ACPI_NAMESPACE_NODE", SRC_TYPE_STRUCT}, + {"ACPI_NAMESTRING_INFO", SRC_TYPE_STRUCT}, + {"ACPI_NATIVE_INT", SRC_TYPE_SIMPLE}, + {"ACPI_NATIVE_UINT", SRC_TYPE_SIMPLE}, + {"ACPI_NEW_TABLE_DESC", SRC_TYPE_STRUCT}, + {"ACPI_NOTIFY_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_NOTIFY_INFO", SRC_TYPE_STRUCT}, + {"ACPI_NS_SEARCH_DATA", SRC_TYPE_STRUCT}, + {"ACPI_OBJ_INFO_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT", SRC_TYPE_UNION}, + {"ACPI_OBJECT_ADDR_HANDLER", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_BANK_FIELD", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_BUFFER", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_BUFFER_FIELD", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_CACHE_LIST", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_COMMON", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_CONVERTER", SRC_TYPE_SIMPLE}, + {"ACPI_OBJECT_DATA", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_DEVICE", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_EVENT", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_EXTRA", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_FIELD_COMMON", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_OBJECT_INDEX_FIELD", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_INTEGER", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_LIST", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_METHOD", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_MUTEX", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_NOTIFY_COMMON", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_NOTIFY_HANDLER", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_PACKAGE", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_POWER_RESOURCE", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_PROCESSOR", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_REFERENCE", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_REGION", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_REGION_FIELD", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_STRING", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_THERMAL_ZONE", SRC_TYPE_STRUCT}, + {"ACPI_OBJECT_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_OBJECT_TYPE8", SRC_TYPE_SIMPLE}, + {"ACPI_OP_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_OPCODE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_OPERAND_OBJECT", SRC_TYPE_UNION}, + {"ACPI_OSD_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_OSD_EXEC_CALLBACK", SRC_TYPE_SIMPLE}, + {"ACPI_OWNER_ID", SRC_TYPE_SIMPLE}, + {"ACPI_PACKAGE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_PACKAGE_INFO2", SRC_TYPE_STRUCT}, + {"ACPI_PACKAGE_INFO3", SRC_TYPE_STRUCT}, + {"ACPI_PACKAGE_INFO4", SRC_TYPE_STRUCT}, + {"ACPI_PARSE_DOWNWARDS", SRC_TYPE_SIMPLE}, + {"ACPI_PARSE_OBJ_ASL", SRC_TYPE_STRUCT}, + {"ACPI_PARSE_OBJ_COMMON", SRC_TYPE_STRUCT}, + {"ACPI_PARSE_OBJ_NAMED", SRC_TYPE_STRUCT}, + {"ACPI_PARSE_OBJECT", SRC_TYPE_UNION}, + {"ACPI_PARSE_STATE", SRC_TYPE_STRUCT}, + {"ACPI_PARSE_UPWARDS", SRC_TYPE_SIMPLE}, + {"ACPI_PARSE_VALUE", SRC_TYPE_UNION}, + {"ACPI_PCI_DEVICE", SRC_TYPE_STRUCT}, + {"ACPI_PCI_ID", SRC_TYPE_STRUCT}, + {"ACPI_PCI_ROUTING_TABLE", SRC_TYPE_STRUCT}, + {"ACPI_PHYSICAL_ADDRESS", SRC_TYPE_SIMPLE}, + {"ACPI_PKG_CALLBACK", SRC_TYPE_SIMPLE}, + {"ACPI_PKG_INFO", SRC_TYPE_STRUCT}, + {"ACPI_PKG_STATE", SRC_TYPE_STRUCT}, + {"ACPI_PMTT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_PNP_DEVICE_ID", SRC_TYPE_STRUCT}, + {"ACPI_PNP_DEVICE_ID_LIST", SRC_TYPE_STRUCT}, + {"ACPI_POINTER", SRC_TYPE_STRUCT}, + {"ACPI_POINTERS", SRC_TYPE_UNION}, + {"ACPI_PORT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_PREDEFINED_DATA", SRC_TYPE_STRUCT}, + {"ACPI_PREDEFINED_INFO", SRC_TYPE_UNION}, + {"ACPI_PREDEFINED_NAMES", SRC_TYPE_STRUCT}, + {"ACPI_PRUNE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_PSCOPE_STATE", SRC_TYPE_STRUCT}, + {"ACPI_RASF_PARAMETER_BLOCK", SRC_TYPE_STRUCT}, + {"ACPI_RASF_PATROL_SCRUB_PARAMETER", SRC_TYPE_STRUCT}, + {"ACPI_RASF_SHARED_MEMORY", SRC_TYPE_STRUCT}, + {"ACPI_REPAIR_FUNCTION", SRC_TYPE_SIMPLE}, + {"ACPI_REPAIR_INFO", SRC_TYPE_STRUCT}, + {"ACPI_REG_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_RESOURCE_ADDRESS", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_ADDRESS16", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_ADDRESS32", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_ADDRESS64", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_COMMON_SERIALBUS", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_EXTENDED_ADDRESS64", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_ATTRIBUTE", SRC_TYPE_UNION}, + {"ACPI_RESOURCE_DATA", SRC_TYPE_UNION}, + {"ACPI_RESOURCE_DMA", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_END_TAG", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_EXTENDED_IRQ", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_FIXED_DMA", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_FIXED_IO", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_FIXED_MEMORY32", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_GENERIC_REGISTER", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_GPIO", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_I2C_SERIALBUS", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_IO", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_IRQ", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_MEMORY24", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_MEMORY32", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_SOURCE", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_SPI_SERIALBUS", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_START_DEPENDENT", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_TAG", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_RESOURCE_UART_SERIALBUS", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_VENDOR", SRC_TYPE_STRUCT}, + {"ACPI_RESOURCE_VENDOR_TYPED", SRC_TYPE_STRUCT}, + {"ACPI_RESULT_VALUES", SRC_TYPE_STRUCT}, + {"ACPI_ROUND_UP_TO_32_BIT", SRC_TYPE_SIMPLE}, + {"ACPI_RSCONVERT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_RSDUMP_INFO", SRC_TYPE_STRUCT}, + {"ACPI_RW_LOCK", SRC_TYPE_STRUCT}, + {"ACPI_S3PT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_SCI_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_SCI_HANDLER_INFO", SRC_TYPE_STRUCT}, + {"ACPI_SCOPE_STATE", SRC_TYPE_STRUCT}, + {"ACPI_SEMAPHORE", SRC_TYPE_SIMPLE}, + {"ACPI_SERIAL_INFO", SRC_TYPE_STRUCT}, + {"ACPI_SIGNAL_FATAL_INFO", SRC_TYPE_STRUCT}, + {"ACPI_SIMPLE_REPAIR_INFO", SRC_TYPE_STRUCT}, + {"ACPI_SIZE", SRC_TYPE_SIMPLE}, + {"ACPI_SLEEP_FUNCTION", SRC_TYPE_SIMPLE}, + {"ACPI_SLEEP_FUNCTIONS", SRC_TYPE_STRUCT}, + {"ACPI_SPINLOCK", SRC_TYPE_SIMPLE}, + {"ACPI_STATISTICS", SRC_TYPE_STRUCT}, + {"ACPI_STATUS", SRC_TYPE_SIMPLE}, + {"ACPI_STRING", SRC_TYPE_SIMPLE}, + {"ACPI_STRING_TABLE", SRC_TYPE_STRUCT}, + {"ACPI_SUBTABLE_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_SYSTEM_INFO", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_DESC", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_HANDLER", SRC_TYPE_SIMPLE}, + {"ACPI_TABLE_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_LIST", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_LPIT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MTMR", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SUPPORT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_TABLE_VRTC", SRC_TYPE_STRUCT}, + {"ACPI_TAG_INFO", SRC_TYPE_STRUCT}, + {"ACPI_THREAD_ID", SRC_TYPE_SIMPLE}, + {"ACPI_THREAD_STATE", SRC_TYPE_STRUCT}, + {"ACPI_TRACE_EVENT_TYPE", SRC_TYPE_SIMPLE}, + {"ACPI_TYPED_IDENTIFIER_TABLE", SRC_TYPE_STRUCT}, + {"ACPI_UINTPTR_T", SRC_TYPE_SIMPLE}, + {"ACPI_UPDATE_STATE", SRC_TYPE_STRUCT}, + {"ACPI_UUID", SRC_TYPE_STRUCT}, + {"ACPI_VENDOR_UUID", SRC_TYPE_STRUCT}, + {"ACPI_VENDOR_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_VRTC_ENTRY", SRC_TYPE_STRUCT}, + {"ACPI_WALK_AML_CALLBACK", SRC_TYPE_SIMPLE}, + {"ACPI_WALK_CALLBACK", SRC_TYPE_SIMPLE}, + {"ACPI_WALK_RESOURCE_CALLBACK", SRC_TYPE_SIMPLE}, + {"ACPI_WALK_INFO", SRC_TYPE_STRUCT}, + {"ACPI_WALK_STATE", SRC_TYPE_STRUCT}, + {"ACPI_WHEA_HEADER", SRC_TYPE_STRUCT}, + + /* Buffers related to predefined ACPI names (_PLD, etc.) */ + + {"ACPI_FDE_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GRT_INFO", SRC_TYPE_STRUCT}, + {"ACPI_GTM_INFO", SRC_TYPE_STRUCT}, + {"ACPI_PLD_INFO", SRC_TYPE_STRUCT}, + + /* Resources */ + + {"ACPI_RS_LENGTH", SRC_TYPE_SIMPLE}, + {"ACPI_RSDESC_SIZE", SRC_TYPE_SIMPLE}, + + {"AML_RESOURCE", SRC_TYPE_UNION}, + {"AML_RESOURCE_ADDRESS", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_ADDRESS16", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_ADDRESS32", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_ADDRESS64", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_COMMON_SERIALBUS", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_DMA", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_END_DEPENDENT", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_END_TAG", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_EXTENDED_ADDRESS64", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_EXTENDED_IRQ", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_FIXED_DMA", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_FIXED_IO", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_FIXED_MEMORY32", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_GENERIC_REGISTER", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_GPIO", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_IO", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_I2C_SERIALBUS", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_IRQ", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_IRQ_NOFLAGS", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_LARGE_HEADER", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_MEMORY24", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_MEMORY32", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_SMALL_HEADER", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_SPI_SERIALBUS", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_START_DEPENDENT", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_START_DEPENDENT_NOPRIO", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_UART_SERIALBUS", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_VENDOR_LARGE", SRC_TYPE_STRUCT}, + {"AML_RESOURCE_VENDOR_SMALL", SRC_TYPE_STRUCT}, + {"AS_BRACE_INFO", SRC_TYPE_STRUCT}, + {"AS_SCAN_CALLBACK", SRC_TYPE_SIMPLE}, + + {"APIC_HEADER", SRC_TYPE_STRUCT}, + {"AE_DEBUG_REGIONS", SRC_TYPE_STRUCT}, + {"AE_REGION", SRC_TYPE_STRUCT}, + {"ASL_ANALYSIS_WALK_INFO", SRC_TYPE_STRUCT}, + {"ASL_ERROR_MSG", SRC_TYPE_STRUCT}, + {"ASL_ERROR_MSG", SRC_TYPE_STRUCT}, + {"ASL_EVENT_INFO", SRC_TYPE_STRUCT}, + {"ASL_FILE_INFO", SRC_TYPE_STRUCT}, + {"ASL_FILE_STATUS", SRC_TYPE_STRUCT}, + {"ASL_INCLUDE_DIR", SRC_TYPE_STRUCT}, + {"ASL_LISTING_NODE", SRC_TYPE_STRUCT}, + {"ASL_MAPPING_ENTRY", SRC_TYPE_STRUCT}, + {"ASL_METHOD_INFO", SRC_TYPE_STRUCT}, + {"ASL_METHOD_LOCAL", SRC_TYPE_STRUCT}, + {"ASL_RESERVED_INFO", SRC_TYPE_STRUCT}, + {"ASL_RESOURCE_INFO", SRC_TYPE_STRUCT}, + {"ASL_RESOURCE_NODE", SRC_TYPE_STRUCT}, + {"ASL_WALK_CALLBACK", SRC_TYPE_SIMPLE}, + {"UINT64_OVERLAY", SRC_TYPE_UNION}, + {"UINT64_STRUCT", SRC_TYPE_STRUCT}, + + /* + * Acpi table definition names. + */ + {"ACPI_TABLE_ASF", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_BERT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_BGRT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_BOOT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_CPEP", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_CSRT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_DBG2", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_DBGP", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_DMAR", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_DRTM", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_ECDT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_EINJ", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_ERST", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_FACS", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_FADT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_FPDT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_GTDT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_HEST", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_HPET", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_IBFT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_IORT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_IVRS", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MADT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MCFG", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MCHI", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MPST", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MSCT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MSDM", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_NFIT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_PCCT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_RSDP", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_RSDT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_MCHI", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_S3PT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SBST", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SLIC", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SLIT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SPCR", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SPMI", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_SRAT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_STAO", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_TCPA", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_TPM2", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_UEFI", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_WAET", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_WDAT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_WDDT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_WDRT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_WPBT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_XENV", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_XSDT", SRC_TYPE_STRUCT}, + + {"ACPI_ASF_ADDRESS", SRC_TYPE_STRUCT}, + {"ACPI_ASF_ALERT", SRC_TYPE_STRUCT}, + {"ACPI_ASF_ALERT_DATA", SRC_TYPE_STRUCT}, + {"ACPI_ASF_CONTROL_DATA", SRC_TYPE_STRUCT}, + {"ACPI_ASF_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_ASF_INFO", SRC_TYPE_STRUCT}, + {"ACPI_ASF_REMOTE", SRC_TYPE_STRUCT}, + {"ACPI_ASF_RMCP", SRC_TYPE_STRUCT}, + {"ACPI_BERT_REGION", SRC_TYPE_STRUCT}, + {"ACPI_CPEP_POLLING", SRC_TYPE_STRUCT}, + {"ACPI_CSRT_GROUP", SRC_TYPE_STRUCT}, + {"ACPI_CSRT_DESCRIPTOR", SRC_TYPE_STRUCT}, + {"ACPI_CSRT_SHARED_INFO", SRC_TYPE_STRUCT}, + {"ACPI_DBG2_DEVICE", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_DEVICE_SCOPE", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_ANDD", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_ATSR", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_RHSA", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_HARDWARE_UNIT", SRC_TYPE_STRUCT}, + {"ACPI_DMAR_RESERVED_MEMORY", SRC_TYPE_STRUCT}, + {"ACPI_DRTM_DPS_ID", SRC_TYPE_STRUCT}, + {"ACPI_DRTM_RESOURCE", SRC_TYPE_STRUCT}, + {"ACPI_DRTM_RESOURCE_LIST", SRC_TYPE_STRUCT}, + {"ACPI_DRTM_VTABLE_LIST", SRC_TYPE_STRUCT}, + {"ACPI_EINJ_ENTRY", SRC_TYPE_STRUCT}, + {"ACPI_EINJ_TRIGGER", SRC_TYPE_STRUCT}, + {"ACPI_ERST_ENTRY", SRC_TYPE_STRUCT}, + {"ACPI_ERST_INFO", SRC_TYPE_STRUCT}, + {"ACPI_FPDT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_FPDT_BOOT", SRC_TYPE_STRUCT}, + {"ACPI_FPDT_S3PT_PTR", SRC_TYPE_STRUCT}, + {"ACPI_GTDT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_GTDT_TIMER_BLOCK", SRC_TYPE_STRUCT}, + {"ACPI_GTDT_TIMER_ENTRY", SRC_TYPE_STRUCT}, + {"ACPI_GTDT_WATCHDOG", SRC_TYPE_STRUCT}, + {"ACPI_HEST_AER_COMMON", SRC_TYPE_STRUCT}, + {"ACPI_HEST_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_HEST_NOTIFY", SRC_TYPE_STRUCT}, + {"ACPI_HEST_IA_ERROR_BANK", SRC_TYPE_STRUCT}, + {"ACPI_HEST_IA_MACHINE_CHECK", SRC_TYPE_STRUCT}, + {"ACPI_HEST_IA_CORRECTED", SRC_TYPE_STRUCT}, + {"ACPI_HEST_IA_NMI", SRC_TYPE_STRUCT}, + {"ACPI_HEST_AER_ROOT", SRC_TYPE_STRUCT}, + {"ACPI_HEST_AER", SRC_TYPE_STRUCT}, + {"ACPI_HEST_AER_BRIDGE", SRC_TYPE_STRUCT}, + {"ACPI_HEST_GENERIC", SRC_TYPE_STRUCT}, + {"ACPI_HEST_GENERIC_STATUS", SRC_TYPE_STRUCT}, + {"ACPI_HEST_GENERIC_DATA", SRC_TYPE_STRUCT}, + {"ACPI_IBFT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_IBFT_CONTROL", SRC_TYPE_STRUCT}, + {"ACPI_IBFT_INITIATOR", SRC_TYPE_STRUCT}, + {"ACPI_IBFT_NIC", SRC_TYPE_STRUCT}, + {"ACPI_IBFT_TARGET", SRC_TYPE_STRUCT}, + {"ACPI_IORT_ID_MAPPING", SRC_TYPE_STRUCT}, + {"ACPI_IORT_ITS_GROUP", SRC_TYPE_STRUCT}, + {"ACPI_IORT_MEMORY_ACCESS", SRC_TYPE_STRUCT}, + {"ACPI_IORT_NAMED_COMPONENT", SRC_TYPE_STRUCT}, + {"ACPI_IORT_NODE", SRC_TYPE_STRUCT}, + {"ACPI_IORT_ROOT_COMPLEX", SRC_TYPE_STRUCT}, + {"ACPI_IORT_SMMU", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_HARDWARE", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_DE_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_DEVICE4", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_DEVICE8A", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_DEVICE8B", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_DEVICE8C", SRC_TYPE_STRUCT}, + {"ACPI_IVRS_MEMORY", SRC_TYPE_STRUCT}, + {"ACPI_MADT_ADDRESS_OVERRIDE", SRC_TYPE_STRUCT}, + {"ACPI_MADT_GENERIC_MSI_FRAME", SRC_TYPE_STRUCT}, + {"ACPI_MADT_GENERIC_REDISTRIBUTOR", SRC_TYPE_STRUCT}, + {"ACPI_MADT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_MADT_IO_APIC", SRC_TYPE_STRUCT}, + {"ACPI_MADT_IO_SAPIC", SRC_TYPE_STRUCT}, + {"ACPI_MADT_LOCAL_APIC", SRC_TYPE_STRUCT}, + {"ACPI_MADT_LOCAL_APIC_NMI", SRC_TYPE_STRUCT}, + {"ACPI_MADT_LOCAL_APIC_OVERRIDE", SRC_TYPE_STRUCT}, + {"ACPI_MADT_LOCAL_SAPIC", SRC_TYPE_STRUCT}, + {"ACPI_MADT_LOCAL_X2APIC", SRC_TYPE_STRUCT}, + {"ACPI_MADT_LOCAL_X2APIC_NMI", SRC_TYPE_STRUCT}, + {"ACPI_MADT_GENERIC_DISTRIBUTOR", SRC_TYPE_STRUCT}, + {"ACPI_MADT_GENERIC_INTERRUPT", SRC_TYPE_STRUCT}, + {"ACPI_MADT_INTERRUPT_OVERRIDE", SRC_TYPE_STRUCT}, + {"ACPI_MADT_INTERRUPT_SOURCE", SRC_TYPE_STRUCT}, + {"ACPI_MADT_NMI_SOURCE", SRC_TYPE_STRUCT}, + {"ACPI_MADT_PROCESSOR_APIC", SRC_TYPE_STRUCT}, + {"ACPI_MPST_COMPONENT", SRC_TYPE_STRUCT}, + {"ACPI_MPST_DATA_HDR", SRC_TYPE_STRUCT}, + {"ACPI_MPST_POWER_DATA", SRC_TYPE_STRUCT}, + {"ACPI_MPST_POWER_NODE", SRC_TYPE_STRUCT}, + {"ACPI_MPST_POWER_STATE", SRC_TYPE_STRUCT}, + {"ACPI_MCFG_ALLOCATION", SRC_TYPE_STRUCT}, + {"ACPI_MSCT_PROXIMITY", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_SYSTEM_ADDRESS", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_MEMORY_MAP", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_INTERLEAVE", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_SMBIOS", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_CONTROL_REGION", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_DATA_REGION", SRC_TYPE_STRUCT}, + {"ACPI_NFIT_FLUSH_ADDRESS", SRC_TYPE_STRUCT}, + {"ACPI_PCCT_HW_REDUCED", SRC_TYPE_STRUCT}, + {"ACPI_PCCT_SHARED_MEMORY", SRC_TYPE_STRUCT}, + {"ACPI_PCCT_SUBSPACE", SRC_TYPE_STRUCT}, + {"ACPI_RSDP_COMMON", SRC_TYPE_STRUCT}, + {"ACPI_RSDP_EXTENSION", SRC_TYPE_STRUCT}, + {"ACPI_S3PT_RESUME", SRC_TYPE_STRUCT}, + {"ACPI_S3PT_SUSPEND", SRC_TYPE_STRUCT}, + {"ACPI_SRAT_CPU_AFFINITY", SRC_TYPE_STRUCT}, + {"ACPI_SRAT_HEADER", SRC_TYPE_STRUCT}, + {"ACPI_SRAT_MEM_AFFINITY", SRC_TYPE_STRUCT}, + {"ACPI_SRAT_X2APIC_CPU_AFFINITY", SRC_TYPE_STRUCT}, + {"ACPI_SRAT_GICC_AFFINITY", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_TCPA_CLIENT", SRC_TYPE_STRUCT}, + {"ACPI_TABLE_TCPA_SERVER", SRC_TYPE_STRUCT}, + {"ACPI_TPM2_CONTROL", SRC_TYPE_STRUCT}, + {"ACPI_WDAT_ENTRY", SRC_TYPE_STRUCT}, + + /* Data Table compiler */ + + {"DT_FIELD", SRC_TYPE_STRUCT}, + {"DT_SUBTABLE", SRC_TYPE_STRUCT}, + {"DT_WALK_CALLBACK", SRC_TYPE_SIMPLE}, + + /* iASL preprocessor */ + + {"PR_DEFINE_INFO", SRC_TYPE_STRUCT}, + {"PR_DIRECTIVE_INFO", SRC_TYPE_STRUCT}, + {"PR_FILE_NODE", SRC_TYPE_STRUCT}, + {"PR_LINE_MAPPING", SRC_TYPE_STRUCT}, + {"PR_MACRO_ARG", SRC_TYPE_STRUCT}, + {"PR_OPERATOR_INFO", SRC_TYPE_STRUCT}, + + /* AcpiDump utility */ + + {"AP_DUMP_ACTION", SRC_TYPE_STRUCT}, + + /* AcpiHelp utility */ + + {"AH_AML_OPCODE", SRC_TYPE_STRUCT}, + {"AH_ASL_OPERATOR", SRC_TYPE_STRUCT}, + {"AH_ASL_KEYWORD", SRC_TYPE_STRUCT}, + {"AH_DEVICE_ID", SRC_TYPE_STRUCT}, + {"AH_PREDEFINED_NAME", SRC_TYPE_STRUCT}, + {"AH_UUID", SRC_TYPE_STRUCT}, + + /* AcpiXtract utility */ + + {"AX_TABLE_INFO", SRC_TYPE_STRUCT}, + + /* OS service layers */ + + {"EXTERNAL_FIND_INFO", SRC_TYPE_STRUCT}, + {"OSL_TABLE_INFO", SRC_TYPE_STRUCT}, + + {NULL, 0} +}; + + +ACPI_IDENTIFIER_TABLE LinuxAddStruct[] = { + {"acpi_namespace_node"}, + {"acpi_parse_object"}, + {"acpi_table_desc"}, + {"acpi_walk_state"}, + {NULL} +}; + + +ACPI_IDENTIFIER_TABLE LinuxEliminateLines_C[] = { + + {"#define __"}, + {NULL} +}; + + +ACPI_IDENTIFIER_TABLE LinuxEliminateLines_H[] = { + + {NULL} +}; + + +ACPI_IDENTIFIER_TABLE LinuxConditionalIdentifiers[] = { + +/* {"ACPI_USE_STANDARD_HEADERS"}, */ + {"WIN32"}, + {"_MSC_VER"}, + {NULL} +}; + + +ACPI_STRING_TABLE LinuxSpecialStrings[] = { + + /* Include file paths */ + + {"\"acpi.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acpiosxf.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acpixf.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acbuffer.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acconfig.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acexcep.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acnames.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acoutput.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acrestyp.h\"", "", REPLACE_WHOLE_WORD}, + {"\"actbl.h\"", "", REPLACE_WHOLE_WORD}, + {"\"actbl1.h\"", "", REPLACE_WHOLE_WORD}, + {"\"actbl2.h\"", "", REPLACE_WHOLE_WORD}, + {"\"actbl3.h\"", "", REPLACE_WHOLE_WORD}, + {"\"actypes.h\"", "", REPLACE_WHOLE_WORD}, + {"\"platform/acenv.h\"", "", REPLACE_WHOLE_WORD}, + {"\"platform/acenvex.h\"", "", REPLACE_WHOLE_WORD}, + {"\"acgcc.h\"", "", REPLACE_WHOLE_WORD}, + {"\"aclinux.h\"", "", REPLACE_WHOLE_WORD}, + {"\"aclinuxex.h\"", "", REPLACE_WHOLE_WORD}, + + {NULL, NULL, 0} +}; + + +ACPI_IDENTIFIER_TABLE LinuxSpecialMacros[] = { + + {"ACPI_DBG_DEPENDENT_RETURN_VOID"}, + {"ACPI_EXPORT_SYMBOL"}, + {"ACPI_EXPORT_SYMBOL_INIT"}, + {"ACPI_EXTERNAL_RETURN_OK"}, + {"ACPI_EXTERNAL_RETURN_PTR"}, + {"ACPI_EXTERNAL_RETURN_STATUS"}, + {"ACPI_EXTERNAL_RETURN_UINT32"}, + {"ACPI_EXTERNAL_RETURN_VOID"}, + {"ACPI_HW_DEPENDENT_RETURN_OK"}, + {"ACPI_HW_DEPENDENT_RETURN_STATUS"}, + {"ACPI_HW_DEPENDENT_RETURN_VOID"}, + {"ACPI_MSG_DEPENDENT_RETURN_VOID"}, + + {NULL} +}; + + +ACPI_CONVERSION_TABLE LinuxConversionTable = +{ + DualLicenseHeader, + FLG_NO_CARRIAGE_RETURNS | FLG_LOWERCASE_DIRNAMES, + + AcpiIdentifiers, + + /* C source files */ + + LinuxDataTypes, + LinuxEliminateLines_C, + NULL, + NULL, + AcpiIdentifiers, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_CHECK_BRACES | CVT_TRIM_LINES | CVT_BRACES_ON_SAME_LINE | + CVT_MIXED_CASE_TO_UNDERSCORES | CVT_LOWER_CASE_IDENTIFIERS | + CVT_REMOVE_DEBUG_MACROS | CVT_TRIM_WHITESPACE | + CVT_REMOVE_EMPTY_BLOCKS | CVT_SPACES_TO_TABS8), + + /* C header files */ + + LinuxDataTypes, + LinuxEliminateLines_H, + LinuxConditionalIdentifiers, + NULL, + AcpiIdentifiers, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_TRIM_LINES | CVT_MIXED_CASE_TO_UNDERSCORES | + CVT_LOWER_CASE_IDENTIFIERS | CVT_TRIM_WHITESPACE | + CVT_REMOVE_EMPTY_BLOCKS| CVT_REDUCE_TYPEDEFS | CVT_SPACES_TO_TABS8), + + /* Patch files */ + + LinuxDataTypes, + NULL, + NULL, + NULL, + AcpiIdentifiers, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_MIXED_CASE_TO_UNDERSCORES), +}; + + +/****************************************************************************** + * + * Code cleanup translation tables + * + ******************************************************************************/ + +ACPI_CONVERSION_TABLE CleanupConversionTable = +{ + NULL, + FLG_DEFAULT_FLAGS, + NULL, + /* C source files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_CHECK_BRACES | CVT_TRIM_LINES | CVT_TRIM_WHITESPACE), + + /* C header files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_TRIM_LINES | CVT_TRIM_WHITESPACE), + + /* Patch files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES), +}; + + +ACPI_CONVERSION_TABLE StatsConversionTable = +{ + NULL, + FLG_NO_FILE_OUTPUT, + NULL, + + /* C source files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_COUNT_SHORTMULTILINE_COMMENTS), + + /* C header files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_COUNT_SHORTMULTILINE_COMMENTS), + + /* Patch files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_COUNT_SHORTMULTILINE_COMMENTS), +}; + + +/****************************************************************************** + * + * Dual License injection translation table + * + ******************************************************************************/ + +ACPI_CONVERSION_TABLE LicenseConversionTable = +{ + DualLicenseHeader, + FLG_DEFAULT_FLAGS, + NULL, + + /* C source files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_COUNT_SHORTMULTILINE_COMMENTS), + + /* C header files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_COUNT_SHORTMULTILINE_COMMENTS), + + /* Patch files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_COUNT_SHORTMULTILINE_COMMENTS), +}; + + +/****************************************************************************** + * + * Customizable translation tables + * + ******************************************************************************/ + +ACPI_STRING_TABLE CustomReplacements[] = +{ + {"(c) 1999 - 2016", "(c) 1999 - 2016", REPLACE_WHOLE_WORD}, /* Main ACPICA source */ + {"(c) 2006 - 2016", "(c) 2006 - 2016", REPLACE_WHOLE_WORD}, /* Test suites */ + +#if 0 + {"SUPPORT, ASSISTANCE", "SUPPORT, ASSISTANCE", REPLACE_WHOLE_WORD}, /* Fix intel header */ + + {"(ACPI_INTEGER)", "(UINT64)", REPLACE_WHOLE_WORD}, + {"ACPI_INTEGER ", "UINT64 ", REPLACE_WHOLE_WORD}, + {"ACPI_INTEGER", "UINT64", REPLACE_WHOLE_WORD}, + {"ACPI_INTEGER_MAX", "ACPI_UINT64_MAX", REPLACE_WHOLE_WORD}, + {"#include \"acpi.h\"", "#include \"acpi.h\"\n#include \"accommon.h\"", REPLACE_SUBSTRINGS}, + {"AcpiTbSumTable", "AcpiTbSumTable", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_BOOT", "ACPI_SIG_BOOT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_DBGP", "ACPI_SIG_DBGP", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_DSDT", "ACPI_SIG_DSDT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_ECDT", "ACPI_SIG_ECDT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_FACS", "ACPI_SIG_FACS", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_FADT", "ACPI_SIG_FADT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_HPET", "ACPI_SIG_HPET", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_MADT", "ACPI_SIG_MADT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_MCFG", "ACPI_SIG_MCFG", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_PSDT", "ACPI_SIG_PSDT", REPLACE_WHOLE_WORD}, + {"ACPI_NAME_RSDP", "ACPI_NAME_RSDP", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_RSDP", "ACPI_SIG_RSDP", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_RSDT", "ACPI_SIG_RSDT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SBST", "ACPI_SIG_SBST", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SLIT", "ACPI_SIG_SLIT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SPCR", "ACPI_SIG_SPCR", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SPIC", "ACPI_SIG_SPIC", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SPMI", "ACPI_SIG_SPMI", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SRAT", "ACPI_SIG_SRAT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_SSDT", "ACPI_SIG_SSDT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_TCPA", "ACPI_SIG_TCPA", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_WDRT", "ACPI_SIG_WDRT", REPLACE_WHOLE_WORD}, + {"ACPI_SIG_XSDT", "ACPI_SIG_XSDT", REPLACE_WHOLE_WORD}, + + {"ACPI_ALLOCATE_ZEROED", "ACPI_ALLOCATE_ZEROED", REPLACE_WHOLE_WORD}, + {"ACPI_ALLOCATE", "ACPI_ALLOCATE", REPLACE_WHOLE_WORD}, + {"ACPI_FREE", "ACPI_FREE", REPLACE_WHOLE_WORD}, + + "ACPI_NATIVE_UINT", "ACPI_NATIVE_UINT", REPLACE_WHOLE_WORD, + "ACPI_NATIVE_UINT *", "ACPI_NATIVE_UINT *", REPLACE_WHOLE_WORD, + "ACPI_NATIVE_UINT", "ACPI_NATIVE_UINT", REPLACE_WHOLE_WORD, + "ACPI_NATIVE_INT", "ACPI_NATIVE_INT", REPLACE_WHOLE_WORD, + "ACPI_NATIVE_INT *", "ACPI_NATIVE_INT *", REPLACE_WHOLE_WORD, + "ACPI_NATIVE_INT", "ACPI_NATIVE_INT", REPLACE_WHOLE_WORD, +#endif + + {NULL, NULL, 0} +}; + + +ACPI_CONVERSION_TABLE CustomConversionTable = +{ + NULL, + FLG_DEFAULT_FLAGS, + NULL, + + /* C source files */ + + CustomReplacements, + LinuxEliminateLines_H, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_TRIM_LINES | CVT_TRIM_WHITESPACE), + + /* C header files */ + + CustomReplacements, + LinuxEliminateLines_H, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_TRIM_LINES | CVT_TRIM_WHITESPACE), + + /* C header files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES), +}; + + +/****************************************************************************** + * + * Indentation result fixup table + * + ******************************************************************************/ + +ACPI_CONVERSION_TABLE IndentConversionTable = +{ + NULL, + FLG_NO_CARRIAGE_RETURNS, + + NULL, + + /* C source files */ + + LinuxSpecialStrings, + NULL, + NULL, + NULL, + NULL, + LinuxSpecialMacros, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_TRIM_LINES | CVT_TRIM_WHITESPACE), + + /* C header files */ + + LinuxSpecialStrings, + NULL, + NULL, + NULL, + NULL, + LinuxSpecialMacros, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES | + CVT_TRIM_LINES | CVT_TRIM_WHITESPACE), + + /* C header files */ + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (CVT_COUNT_TABS | CVT_COUNT_NON_ANSI_COMMENTS | CVT_COUNT_LINES), +}; diff --git a/third_party/lib/acpica/source/tools/acpisrc/asutils.c b/third_party/lib/acpica/source/tools/acpisrc/asutils.c new file mode 100644 index 000000000..de981f7c5 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpisrc/asutils.c @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * Module Name: asutils - common utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpisrc.h" + + +/****************************************************************************** + * + * FUNCTION: AsSkipUntilChar + * + * DESCRIPTION: Find the next instance of the input character + * + ******************************************************************************/ + +char * +AsSkipUntilChar ( + char *Buffer, + char Target) +{ + + while (*Buffer != Target) + { + if (!*Buffer) + { + return (NULL); + } + + Buffer++; + } + + return (Buffer); +} + + +/****************************************************************************** + * + * FUNCTION: AsSkipPastChar + * + * DESCRIPTION: Find the next instance of the input character, return a buffer + * pointer to this character+1. + * + ******************************************************************************/ + +char * +AsSkipPastChar ( + char *Buffer, + char Target) +{ + + while (*Buffer != Target) + { + if (!*Buffer) + { + return (NULL); + } + + Buffer++; + } + + Buffer++; + return (Buffer); +} + + +/****************************************************************************** + * + * FUNCTION: AsReplaceData + * + * DESCRIPTION: This function inserts and removes data from the file buffer. + * if more data is inserted than is removed, the data in the buffer + * is moved to make room. If less data is inserted than is removed, + * the remaining data is moved to close the hole. + * + ******************************************************************************/ + +char * +AsReplaceData ( + char *Buffer, + UINT32 LengthToRemove, + char *BufferToAdd, + UINT32 LengthToAdd) +{ + UINT32 BufferLength; + + + /* + * Buffer is a string, so the length must include the terminating zero + */ + BufferLength = strlen (Buffer) + 1; + + if (LengthToRemove != LengthToAdd) + { + /* + * Move some of the existing data + * 1) If adding more bytes than removing, make room for the new data + * 2) if removing more bytes than adding, delete the extra space + */ + if (LengthToRemove > 0) + { + Gbl_MadeChanges = TRUE; + memmove ((Buffer + LengthToAdd), (Buffer + LengthToRemove), + (BufferLength - LengthToRemove)); + } + } + + /* + * Now we can move in the new data + */ + if (LengthToAdd > 0) + { + Gbl_MadeChanges = TRUE; + memmove (Buffer, BufferToAdd, LengthToAdd); + } + + return (Buffer + LengthToAdd); +} + + +/****************************************************************************** + * + * FUNCTION: AsInsertData + * + * DESCRIPTION: This function inserts and removes data from the file buffer. + * if more data is inserted than is removed, the data in the buffer + * is moved to make room. If less data is inserted than is removed, + * the remaining data is moved to close the hole. + * + ******************************************************************************/ + +char * +AsInsertData ( + char *Buffer, + char *BufferToAdd, + UINT32 LengthToAdd) +{ + UINT32 BufferLength; + + + if (LengthToAdd > 0) + { + /* + * Buffer is a string, so the length must include the terminating zero + */ + BufferLength = strlen (Buffer) + 1; + + /* + * Move some of the existing data + * 1) If adding more bytes than removing, make room for the new data + * 2) if removing more bytes than adding, delete the extra space + */ + Gbl_MadeChanges = TRUE; + memmove ((Buffer + LengthToAdd), Buffer, BufferLength); + + /* + * Now we can move in the new data + */ + memmove (Buffer, BufferToAdd, LengthToAdd); + } + + return (Buffer + LengthToAdd); +} + + +/****************************************************************************** + * + * FUNCTION: AsRemoveData + * + * DESCRIPTION: This function inserts and removes data from the file buffer. + * if more data is inserted than is removed, the data in the buffer + * is moved to make room. If less data is inserted than is removed, + * the remaining data is moved to close the hole. + * + ******************************************************************************/ + +char * +AsRemoveData ( + char *StartPointer, + char *EndPointer) +{ + UINT32 BufferLength; + + + /* + * Buffer is a string, so the length must include the terminating zero + */ + BufferLength = strlen (EndPointer) + 1; + + Gbl_MadeChanges = TRUE; + memmove (StartPointer, EndPointer, BufferLength); + + return (StartPointer); +} diff --git a/third_party/lib/acpica/source/tools/acpixtract/acpixtract.c b/third_party/lib/acpica/source/tools/acpixtract/acpixtract.c new file mode 100644 index 000000000..b6cb4d076 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpixtract/acpixtract.c @@ -0,0 +1,476 @@ +/****************************************************************************** + * + * Module Name: acpixtract - convert ascii ACPI tables to binary + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpixtract.h" + + +/****************************************************************************** + * + * FUNCTION: AxExtractTables + * + * PARAMETERS: InputPathname - Filename for input acpidump file + * Signature - Requested ACPI signature to extract. + * NULL means extract ALL tables. + * MinimumInstances - Min instances that are acceptable + * + * RETURN: Status + * + * DESCRIPTION: Convert text ACPI tables to binary + * + ******************************************************************************/ + +int +AxExtractTables ( + char *InputPathname, + char *Signature, + unsigned int MinimumInstances) +{ + FILE *InputFile; + FILE *OutputFile = NULL; + unsigned int BytesConverted; + unsigned int ThisTableBytesWritten = 0; + unsigned int FoundTable = 0; + unsigned int Instances = 0; + unsigned int ThisInstance; + char ThisSignature[4]; + int Status = 0; + unsigned int State = AX_STATE_FIND_HEADER; + + + /* Open input in text mode, output is in binary mode */ + + InputFile = fopen (InputPathname, "rt"); + if (!InputFile) + { + printf ("Could not open input file %s\n", InputPathname); + return (-1); + } + + if (Signature) + { + /* Are there enough instances of the table to continue? */ + + AxNormalizeSignature (Signature); + + Instances = AxCountTableInstances (InputPathname, Signature); + if (Instances < MinimumInstances) + { + printf ("Table [%s] was not found in %s\n", + Signature, InputPathname); + fclose (InputFile); + return (-1); + } + + if (Instances == 0) + { + fclose (InputFile); + return (-1); + } + } + + /* Convert all instances of the table to binary */ + + while (fgets (Gbl_LineBuffer, AX_LINE_BUFFER_SIZE, InputFile)) + { + switch (State) + { + case AX_STATE_FIND_HEADER: + + if (!AxIsDataBlockHeader ()) + { + continue; + } + + ACPI_MOVE_NAME (ThisSignature, Gbl_LineBuffer); + if (Signature) + { + /* Ignore signatures that don't match */ + + if (!ACPI_COMPARE_NAME (ThisSignature, Signature)) + { + continue; + } + } + + /* + * Get the instance number for this signature. Only the + * SSDT and PSDT tables can have multiple instances. + */ + ThisInstance = AxGetNextInstance (InputPathname, ThisSignature); + + /* Build an output filename and create/open the output file */ + + if (ThisInstance > 0) + { + /* Add instance number to the output filename */ + + sprintf (Gbl_OutputFilename, "%4.4s%u.dat", + ThisSignature, ThisInstance); + } + else + { + sprintf (Gbl_OutputFilename, "%4.4s.dat", + ThisSignature); + } + + AcpiUtStrlwr (Gbl_OutputFilename); + OutputFile = fopen (Gbl_OutputFilename, "w+b"); + if (!OutputFile) + { + printf ("Could not open output file %s\n", + Gbl_OutputFilename); + fclose (InputFile); + return (-1); + } + + /* + * Toss this block header of the form " @ " line + * and move on to the actual data block + */ + Gbl_TableCount++; + FoundTable = 1; + ThisTableBytesWritten = 0; + State = AX_STATE_EXTRACT_DATA; + continue; + + case AX_STATE_EXTRACT_DATA: + + /* Empty line or non-data line terminates the data block */ + + BytesConverted = AxProcessOneTextLine ( + OutputFile, ThisSignature, ThisTableBytesWritten); + switch (BytesConverted) + { + case 0: + + State = AX_STATE_FIND_HEADER; /* No more data block lines */ + continue; + + case -1: + + goto CleanupAndExit; /* There was a write error */ + + default: /* Normal case, get next line */ + + ThisTableBytesWritten += BytesConverted; + continue; + } + + default: + + Status = -1; + goto CleanupAndExit; + } + } + + if (!FoundTable) + { + printf ("Table [%s] was not found in %s\n", + Signature, InputPathname); + } + + +CleanupAndExit: + + if (State == AX_STATE_EXTRACT_DATA) + { + /* Received an input file EOF while extracting data */ + + printf (AX_TABLE_INFO_FORMAT, + ThisSignature, ThisTableBytesWritten, Gbl_OutputFilename); + } + + if (Gbl_TableCount > 1) + { + printf ("\n%d binary ACPI tables extracted\n", + Gbl_TableCount); + } + + if (OutputFile) + { + fclose (OutputFile); + } + + fclose (InputFile); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AxExtractToMultiAmlFile + * + * PARAMETERS: InputPathname - Filename for input acpidump file + * + * RETURN: Status + * + * DESCRIPTION: Convert all DSDT/SSDT tables to binary and append them all + * into a single output file. Used to simplify the loading of + * multiple/many SSDTs into a utility like acpiexec -- instead + * of creating many separate output files. + * + ******************************************************************************/ + +int +AxExtractToMultiAmlFile ( + char *InputPathname) +{ + FILE *InputFile; + FILE *OutputFile; + int Status = 0; + unsigned int TotalBytesWritten = 0; + unsigned int ThisTableBytesWritten = 0; + unsigned int BytesConverted; + char ThisSignature[4]; + unsigned int State = AX_STATE_FIND_HEADER; + + + strcpy (Gbl_OutputFilename, AX_MULTI_TABLE_FILENAME); + + /* Open the input file in text mode */ + + InputFile = fopen (InputPathname, "rt"); + if (!InputFile) + { + printf ("Could not open input file %s\n", InputPathname); + return (-1); + } + + /* Open the output file in binary mode */ + + OutputFile = fopen (Gbl_OutputFilename, "w+b"); + if (!OutputFile) + { + printf ("Could not open output file %s\n", Gbl_OutputFilename); + fclose (InputFile); + return (-1); + } + + /* Convert the DSDT and all SSDTs to binary */ + + while (fgets (Gbl_LineBuffer, AX_LINE_BUFFER_SIZE, InputFile)) + { + switch (State) + { + case AX_STATE_FIND_HEADER: + + if (!AxIsDataBlockHeader ()) + { + continue; + } + + ACPI_MOVE_NAME (ThisSignature, Gbl_LineBuffer); + + /* Only want DSDT and SSDTs */ + + if (!ACPI_COMPARE_NAME (ThisSignature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME (ThisSignature, ACPI_SIG_SSDT)) + { + continue; + } + + /* + * Toss this block header of the form " @ " line + * and move on to the actual data block + */ + Gbl_TableCount++; + ThisTableBytesWritten = 0; + State = AX_STATE_EXTRACT_DATA; + continue; + + case AX_STATE_EXTRACT_DATA: + + /* Empty line or non-data line terminates the data block */ + + BytesConverted = AxProcessOneTextLine ( + OutputFile, ThisSignature, ThisTableBytesWritten); + switch (BytesConverted) + { + case 0: + + State = AX_STATE_FIND_HEADER; /* No more data block lines */ + continue; + + case -1: + + goto CleanupAndExit; /* There was a write error */ + + default: /* Normal case, get next line */ + + ThisTableBytesWritten += BytesConverted; + TotalBytesWritten += BytesConverted; + continue; + } + + default: + + Status = -1; + goto CleanupAndExit; + } + } + + +CleanupAndExit: + + if (State == AX_STATE_EXTRACT_DATA) + { + /* Received an input file EOF or error while writing data */ + + printf (AX_TABLE_INFO_FORMAT, + ThisSignature, ThisTableBytesWritten, Gbl_OutputFilename); + } + + printf ("\n%d binary ACPI tables extracted and written to %s (%u bytes)\n", + Gbl_TableCount, Gbl_OutputFilename, TotalBytesWritten); + + fclose (InputFile); + fclose (OutputFile); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AxListTables + * + * PARAMETERS: InputPathname - Filename for acpidump file + * + * RETURN: Status + * + * DESCRIPTION: Display info for all ACPI tables found in input. Does not + * perform an actual extraction of the tables. + * + ******************************************************************************/ + +int +AxListTables ( + char *InputPathname) +{ + FILE *InputFile; + size_t HeaderSize; + unsigned char Header[48]; + ACPI_TABLE_HEADER *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header; + + + /* Open input in text mode, output is in binary mode */ + + InputFile = fopen (InputPathname, "rt"); + if (!InputFile) + { + printf ("Could not open input file %s\n", InputPathname); + return (-1); + } + + /* Dump the headers for all tables found in the input file */ + + printf ("\nSignature Length Revision OemId OemTableId" + " OemRevision CompilerId CompilerRevision\n\n"); + + while (fgets (Gbl_LineBuffer, AX_LINE_BUFFER_SIZE, InputFile)) + { + /* Ignore empty lines and lines that start with a space */ + + if (AxIsEmptyLine (Gbl_LineBuffer) || + (Gbl_LineBuffer[0] == ' ')) + { + continue; + } + + /* Get the 36 byte header and display the fields */ + + HeaderSize = AxGetTableHeader (InputFile, Header); + if (HeaderSize < 16) + { + continue; + } + + /* RSDP has an oddball signature and header */ + + if (!strncmp (TableHeader->Signature, "RSD PTR ", 8)) + { + AxCheckAscii ((char *) &Header[9], 6); + printf ("%7.4s \"%6.6s\"\n", "RSDP", + &Header[9]); + Gbl_TableCount++; + continue; + } + + /* Minimum size for table with standard header */ + + if (HeaderSize < sizeof (ACPI_TABLE_HEADER)) + { + continue; + } + + /* Signature and Table length */ + + Gbl_TableCount++; + printf ("%7.4s 0x%8.8X", TableHeader->Signature, + TableHeader->Length); + + /* FACS has only signature and length */ + + if (ACPI_COMPARE_NAME (TableHeader->Signature, "FACS")) + { + printf ("\n"); + continue; + } + + /* OEM IDs and Compiler IDs */ + + AxCheckAscii (TableHeader->OemId, 6); + AxCheckAscii (TableHeader->OemTableId, 8); + AxCheckAscii (TableHeader->AslCompilerId, 4); + + printf ( + " 0x%2.2X \"%6.6s\" \"%8.8s\" 0x%8.8X" + " \"%4.4s\" 0x%8.8X\n", + TableHeader->Revision, TableHeader->OemId, + TableHeader->OemTableId, TableHeader->OemRevision, + TableHeader->AslCompilerId, TableHeader->AslCompilerRevision); + } + + printf ("\nFound %u ACPI tables\n", Gbl_TableCount); + fclose (InputFile); + return (0); +} diff --git a/third_party/lib/acpica/source/tools/acpixtract/acpixtract.h b/third_party/lib/acpica/source/tools/acpixtract/acpixtract.h new file mode 100644 index 000000000..14df786a4 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpixtract/acpixtract.h @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * Module Name: acpixtract.h - Include for acpixtract utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include + + +#undef ACPI_GLOBAL + +#ifdef DEFINE_ACPIXTRACT_GLOBALS +#define ACPI_GLOBAL(type,name) \ + extern type name; \ + type name + +#else +#define ACPI_GLOBAL(type,name) \ + extern type name +#endif + + +/* Options */ + +#define AX_EXTRACT_ALL 0 +#define AX_LIST_ALL 1 +#define AX_EXTRACT_SIGNATURE 2 +#define AX_EXTRACT_AML_TABLES 3 +#define AX_EXTRACT_MULTI_TABLE 4 + +#define AX_OPTIONAL_TABLES 0 +#define AX_REQUIRED_TABLE 1 + +#define AX_UTILITY_NAME "ACPI Binary Table Extraction Utility" +#define AX_SUPPORTED_OPTIONS "ahlms:v" +#define AX_MULTI_TABLE_FILENAME "amltables.dat" +#define AX_TABLE_INFO_FORMAT "Acpi table [%4.4s] - %7u bytes written to %s\n" + +/* Extraction states */ + +#define AX_STATE_FIND_HEADER 0 +#define AX_STATE_EXTRACT_DATA 1 + +/* Miscellaneous constants */ + +#define AX_LINE_BUFFER_SIZE 256 +#define AX_MIN_BLOCK_HEADER_LENGTH 6 /* strlen ("DSDT @") */ + + +typedef struct AxTableInfo +{ + UINT32 Signature; + unsigned int Instances; + unsigned int NextInstance; + struct AxTableInfo *Next; + +} AX_TABLE_INFO; + + +/* Globals */ + +ACPI_GLOBAL (char, Gbl_LineBuffer[AX_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, Gbl_HeaderBuffer[AX_LINE_BUFFER_SIZE]); +ACPI_GLOBAL (char, Gbl_InstanceBuffer[AX_LINE_BUFFER_SIZE]); + +ACPI_GLOBAL (AX_TABLE_INFO, *Gbl_TableListHead); +ACPI_GLOBAL (char, Gbl_OutputFilename[32]); +ACPI_GLOBAL (unsigned char, Gbl_BinaryData[16]); +ACPI_GLOBAL (unsigned int, Gbl_TableCount); + +/* + * acpixtract.c + */ +int +AxExtractTables ( + char *InputPathname, + char *Signature, + unsigned int MinimumInstances); + +int +AxExtractToMultiAmlFile ( + char *InputPathname); + +int +AxListTables ( + char *InputPathname); + + +/* + * axutils.c + */ +size_t +AxGetTableHeader ( + FILE *InputFile, + unsigned char *OutputData); + +unsigned int +AxCountTableInstances ( + char *InputPathname, + char *Signature); + +unsigned int +AxGetNextInstance ( + char *InputPathname, + char *Signature); + +void +AxNormalizeSignature ( + char *Signature); + +void +AxCheckAscii ( + char *Name, + int Count); + +int +AxIsEmptyLine ( + char *Buffer); + +int +AxIsDataBlockHeader ( + void); + +long +AxProcessOneTextLine ( + FILE *OutputFile, + char *ThisSignature, + unsigned int ThisTableBytesWritten); + +size_t +AxConvertLine ( + char *InputLine, + unsigned char *OutputData); diff --git a/third_party/lib/acpica/source/tools/acpixtract/axmain.c b/third_party/lib/acpica/source/tools/acpixtract/axmain.c new file mode 100644 index 000000000..df18bc4b7 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpixtract/axmain.c @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * Module Name: axmain - main module for acpixtract utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define DEFINE_ACPIXTRACT_GLOBALS +#include "acpixtract.h" + + +/* Local prototypes */ + +static void +DisplayUsage ( + void); + + +/****************************************************************************** + * + * FUNCTION: DisplayUsage + * + * DESCRIPTION: Usage message + * + ******************************************************************************/ + +static void +DisplayUsage ( + void) +{ + + ACPI_USAGE_HEADER ("acpixtract [option] "); + + ACPI_OPTION ("-a", "Extract all tables, not just DSDT/SSDT"); + ACPI_OPTION ("-l", "List table summaries, do not extract"); + ACPI_OPTION ("-m", "Extract multiple DSDT/SSDTs to a single file"); + ACPI_OPTION ("-s ", "Extract all tables with "); + ACPI_OPTION ("-v", "Display version information"); + + ACPI_USAGE_TEXT ("\nExtract binary ACPI tables from text acpidump output\n"); + ACPI_USAGE_TEXT ("Default invocation extracts the DSDT and all SSDTs\n"); +} + + +/****************************************************************************** + * + * FUNCTION: main + * + * DESCRIPTION: C main function + * + ******************************************************************************/ + +int +main ( + int argc, + char *argv[]) +{ + char *Filename; + int AxAction; + int Status; + int j; + + + Gbl_TableCount = 0; + Gbl_TableListHead = NULL; + AxAction = AX_EXTRACT_AML_TABLES; /* Default: DSDT & SSDTs */ + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + AcpiOsInitialize (); + printf (ACPI_COMMON_SIGNON (AX_UTILITY_NAME)); + + if (argc < 2) + { + DisplayUsage (); + return (0); + } + + /* Command line options */ + + while ((j = AcpiGetopt (argc, argv, AX_SUPPORTED_OPTIONS)) != ACPI_OPT_END) switch (j) + { + case 'a': + + AxAction = AX_EXTRACT_ALL; /* Extract all tables found */ + break; + + case 'l': + + AxAction = AX_LIST_ALL; /* List tables only, do not extract */ + break; + + case 'm': + + AxAction = AX_EXTRACT_MULTI_TABLE; /* Make single file for all DSDT/SSDTs */ + break; + + case 's': + + AxAction = AX_EXTRACT_SIGNATURE; /* Extract only tables with this sig */ + break; + + case 'v': /* -v: (Version): signon already emitted, just exit */ + + return (0); + + case 'h': + default: + + DisplayUsage (); + return (0); + } + + /* Input filename is always required */ + + Filename = argv[AcpiGbl_Optind]; + if (!Filename) + { + printf ("Missing required input filename\n"); + return (-1); + } + + /* Perform requested action */ + + switch (AxAction) + { + case AX_EXTRACT_ALL: + + Status = AxExtractTables (Filename, NULL, AX_OPTIONAL_TABLES); + break; + + case AX_EXTRACT_MULTI_TABLE: + + Status = AxExtractToMultiAmlFile (Filename); + break; + + case AX_LIST_ALL: + + Status = AxListTables (Filename); + break; + + case AX_EXTRACT_SIGNATURE: + + Status = AxExtractTables (Filename, AcpiGbl_Optarg, AX_REQUIRED_TABLE); + break; + + default: + /* + * Default output is the DSDT and all SSDTs. One DSDT is required, + * any SSDTs are optional. + */ + Status = AxExtractTables (Filename, "DSDT", AX_REQUIRED_TABLE); + if (Status) + { + return (Status); + } + + Status = AxExtractTables (Filename, "SSDT", AX_OPTIONAL_TABLES); + break; + } + + return (Status); +} diff --git a/third_party/lib/acpica/source/tools/acpixtract/axutils.c b/third_party/lib/acpica/source/tools/acpixtract/axutils.c new file mode 100644 index 000000000..6af8cdc29 --- /dev/null +++ b/third_party/lib/acpica/source/tools/acpixtract/axutils.c @@ -0,0 +1,463 @@ +/****************************************************************************** + * + * Module Name: axutils - Utility functions for acpixtract tool. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpixtract.h" + + +/******************************************************************************* + * + * FUNCTION: AxCheckAscii + * + * PARAMETERS: Name - Ascii string, at least as long as Count + * Count - Number of characters to check + * + * RETURN: None + * + * DESCRIPTION: Ensure that the requested number of characters are printable + * Ascii characters. Sets non-printable and null chars to . + * + ******************************************************************************/ + +void +AxCheckAscii ( + char *Name, + int Count) +{ + int i; + + + for (i = 0; i < Count; i++) + { + if (!Name[i] || !isprint ((int) Name[i])) + { + Name[i] = ' '; + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AxIsEmptyLine + * + * PARAMETERS: Buffer - Line from input file + * + * RETURN: TRUE if line is empty (zero or more blanks only) + * + * DESCRIPTION: Determine if an input line is empty. + * + ******************************************************************************/ + +int +AxIsEmptyLine ( + char *Buffer) +{ + + /* Skip all spaces */ + + while (*Buffer == ' ') + { + Buffer++; + } + + /* If end-of-line, this line is empty */ + + if (*Buffer == '\n') + { + return (1); + } + + return (0); +} + + +/******************************************************************************* + * + * FUNCTION: AxNormalizeSignature + * + * PARAMETERS: Name - Ascii string containing an ACPI signature + * + * RETURN: None + * + * DESCRIPTION: Change "RSD PTR" to "RSDP" + * + ******************************************************************************/ + +void +AxNormalizeSignature ( + char *Signature) +{ + + if (!strncmp (Signature, "RSD ", 4)) + { + Signature[3] = 'P'; + } +} + + +/****************************************************************************** + * + * FUNCTION: AxConvertLine + * + * PARAMETERS: InputLine - One line from the input acpidump file + * OutputData - Where the converted data is returned + * + * RETURN: The number of bytes actually converted + * + * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes) + * + ******************************************************************************/ + +size_t +AxConvertLine ( + char *InputLine, + unsigned char *OutputData) +{ + char *End; + int BytesConverted; + int Converted[16]; + int i; + + + /* Terminate the input line at the end of the actual data (for sscanf) */ + + End = strstr (InputLine + 2, " "); + if (!End) + { + return (0); /* Don't understand the format */ + } + *End = 0; + + /* + * Convert one line of table data, of the form: + * : + * + * Example: + * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08 _SB_LNKD........ + */ + BytesConverted = sscanf (InputLine, + "%*s %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + &Converted[0], &Converted[1], &Converted[2], &Converted[3], + &Converted[4], &Converted[5], &Converted[6], &Converted[7], + &Converted[8], &Converted[9], &Converted[10], &Converted[11], + &Converted[12], &Converted[13], &Converted[14], &Converted[15]); + + /* Pack converted data into a byte array */ + + for (i = 0; i < BytesConverted; i++) + { + OutputData[i] = (unsigned char) Converted[i]; + } + + return ((size_t) BytesConverted); +} + + +/****************************************************************************** + * + * FUNCTION: AxGetTableHeader + * + * PARAMETERS: InputFile - Handle for the input acpidump file + * OutputData - Where the table header is returned + * + * RETURN: The actual number of bytes converted + * + * DESCRIPTION: Extract and convert an ACPI table header + * + ******************************************************************************/ + +size_t +AxGetTableHeader ( + FILE *InputFile, + unsigned char *OutputData) +{ + size_t BytesConverted; + size_t TotalConverted = 0; + int i; + + + /* Get the full 36 byte ACPI table header, requires 3 input text lines */ + + for (i = 0; i < 3; i++) + { + if (!fgets (Gbl_HeaderBuffer, AX_LINE_BUFFER_SIZE, InputFile)) + { + return (TotalConverted); + } + + BytesConverted = AxConvertLine (Gbl_HeaderBuffer, OutputData); + TotalConverted += BytesConverted; + OutputData += 16; + + if (BytesConverted != 16) + { + return (TotalConverted); + } + } + + return (TotalConverted); +} + + +/****************************************************************************** + * + * FUNCTION: AxCountTableInstances + * + * PARAMETERS: InputPathname - Filename for acpidump file + * Signature - Requested signature to count + * + * RETURN: The number of instances of the signature + * + * DESCRIPTION: Count the instances of tables with the given signature within + * the input acpidump file. + * + ******************************************************************************/ + +unsigned int +AxCountTableInstances ( + char *InputPathname, + char *Signature) +{ + FILE *InputFile; + unsigned int Instances = 0; + + + InputFile = fopen (InputPathname, "rt"); + if (!InputFile) + { + printf ("Could not open input file %s\n", InputPathname); + return (0); + } + + /* Count the number of instances of this signature */ + + while (fgets (Gbl_InstanceBuffer, AX_LINE_BUFFER_SIZE, InputFile)) + { + /* Ignore empty lines and lines that start with a space */ + + if (AxIsEmptyLine (Gbl_InstanceBuffer) || + (Gbl_InstanceBuffer[0] == ' ')) + { + continue; + } + + AxNormalizeSignature (Gbl_InstanceBuffer); + if (ACPI_COMPARE_NAME (Gbl_InstanceBuffer, Signature)) + { + Instances++; + } + } + + fclose (InputFile); + return (Instances); +} + + +/****************************************************************************** + * + * FUNCTION: AxGetNextInstance + * + * PARAMETERS: InputPathname - Filename for acpidump file + * Signature - Requested ACPI signature + * + * RETURN: The next instance number for this signature. Zero if this + * is the first instance of this signature. + * + * DESCRIPTION: Get the next instance number of the specified table. If this + * is the first instance of the table, create a new instance + * block. Note: only SSDT and PSDT tables can have multiple + * instances. + * + ******************************************************************************/ + +unsigned int +AxGetNextInstance ( + char *InputPathname, + char *Signature) +{ + AX_TABLE_INFO *Info; + + + Info = Gbl_TableListHead; + while (Info) + { + if (*(UINT32 *) Signature == Info->Signature) + { + break; + } + + Info = Info->Next; + } + + if (!Info) + { + /* Signature not found, create new table info block */ + + Info = malloc (sizeof (AX_TABLE_INFO)); + if (!Info) + { + printf ("Could not allocate memory (0x%X bytes)\n", + (unsigned int) sizeof (AX_TABLE_INFO)); + exit (0); + } + + Info->Signature = *(UINT32 *) Signature; + Info->Instances = AxCountTableInstances (InputPathname, Signature); + Info->NextInstance = 1; + Info->Next = Gbl_TableListHead; + Gbl_TableListHead = Info; + } + + if (Info->Instances > 1) + { + return (Info->NextInstance++); + } + + return (0); +} + + +/****************************************************************************** + * + * FUNCTION: AxIsDataBlockHeader + * + * PARAMETERS: None + * + * RETURN: Status. 1 if the table header is valid, 0 otherwise. + * + * DESCRIPTION: Check if the ACPI table identifier in the input acpidump text + * file is valid (of the form: @ ). + * + ******************************************************************************/ + +int +AxIsDataBlockHeader ( + void) +{ + + /* Ignore lines that are too short to be header lines */ + + if (strlen (Gbl_LineBuffer) < AX_MIN_BLOCK_HEADER_LENGTH) + { + return (0); + } + + /* Ignore empty lines and lines that start with a space */ + + if (AxIsEmptyLine (Gbl_LineBuffer) || + (Gbl_LineBuffer[0] == ' ')) + { + return (0); + } + + /* + * Ignore lines that are not headers of the form @ . + * Basically, just look for the '@' symbol, surrounded by spaces. + * + * Examples of headers that must be supported: + * + * DSDT @ 0x737e4000 + * XSDT @ 0x737f2fff + * RSD PTR @ 0xf6cd0 + * SSDT @ (nil) + */ + if (!strstr (Gbl_LineBuffer, " @ ")) + { + return (0); + } + + AxNormalizeSignature (Gbl_LineBuffer); + return (1); +} + + +/****************************************************************************** + * + * FUNCTION: AxProcessOneTextLine + * + * PARAMETERS: OutputFile - Where to write the binary data + * ThisSignature - Signature of current ACPI table + * ThisTableBytesWritten - Total count of data written + * + * RETURN: Length of the converted line + * + * DESCRIPTION: Convert one line of input hex ascii text to binary, and write + * the binary data to the table output file. + * + ******************************************************************************/ + +long +AxProcessOneTextLine ( + FILE *OutputFile, + char *ThisSignature, + unsigned int ThisTableBytesWritten) +{ + size_t BytesWritten; + size_t BytesConverted; + + + /* Check for the end of this table data block */ + + if (AxIsEmptyLine (Gbl_LineBuffer) || + (Gbl_LineBuffer[0] != ' ')) + { + printf (AX_TABLE_INFO_FORMAT, + ThisSignature, ThisTableBytesWritten, Gbl_OutputFilename); + return (0); + } + + /* Convert one line of ascii hex data to binary */ + + BytesConverted = AxConvertLine (Gbl_LineBuffer, Gbl_BinaryData); + + /* Write the binary data */ + + BytesWritten = fwrite (Gbl_BinaryData, 1, BytesConverted, OutputFile); + if (BytesWritten != BytesConverted) + { + printf ("Error while writing file %s\n", Gbl_OutputFilename); + return (-1); + } + + return (BytesWritten); +} diff --git a/third_party/lib/acpica/source/tools/examples/examples.c b/third_party/lib/acpica/source/tools/examples/examples.c new file mode 100644 index 000000000..d6b15b223 --- /dev/null +++ b/third_party/lib/acpica/source/tools/examples/examples.c @@ -0,0 +1,549 @@ +/****************************************************************************** + * + * Module Name: examples - Example ACPICA initialization and execution code + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "examples.h" + +#define _COMPONENT ACPI_EXAMPLE + ACPI_MODULE_NAME ("examples") + + +/****************************************************************************** + * + * ACPICA Example Code + * + * This module contains examples of how the host OS should interface to the + * ACPICA subsystem. + * + * 1) How to use the platform/acenv.h file and how to set configuration + * options. + * + * 2) main - using the debug output mechanism and the error/warning output + * macros. + * + * 3) Two examples of the ACPICA initialization sequence. The first is a + * initialization with no "early" ACPI table access. The second shows + * how to use ACPICA to obtain the tables very early during kernel + * initialization, even before dynamic memory is available. + * + * 4) How to invoke a control method, including argument setup and how to + * access the return value. + * + *****************************************************************************/ + + +/* Local Prototypes */ + +static ACPI_STATUS +InitializeFullAcpica (void); + +static ACPI_STATUS +InstallHandlers (void); + +static void +NotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context); + +static ACPI_STATUS +RegionHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext); + +static ACPI_STATUS +RegionInit ( + ACPI_HANDLE RegionHandle, + UINT32 Function, + void *HandlerContext, + void **RegionContext); + +static void +ExecuteMAIN (void); + +static void +ExecuteOSI (void); + +ACPI_STATUS +InitializeAcpiTables ( + void); + +ACPI_STATUS +InitializeAcpi ( + void); + + +/****************************************************************************** + * + * FUNCTION: main + * + * PARAMETERS: argc, argv + * + * RETURN: Status + * + * DESCRIPTION: Main routine. Shows the use of the various output macros, as + * well as the use of the debug layer/level globals. + * + *****************************************************************************/ + +int ACPI_SYSTEM_XFACE +main ( + int argc, + char **argv) +{ + + ACPI_DEBUG_INITIALIZE (); /* For debug version only */ + + printf (ACPI_COMMON_SIGNON ("ACPI Example Code")); + + /* Initialize the local ACPI tables (RSDP/RSDT/XSDT/FADT/DSDT/FACS) */ + + ExInitializeAcpiTables (); + + /* Initialize the ACPICA subsystem */ + + InitializeFullAcpica (); + + /* Example warning and error output */ + + ACPI_INFO ((AE_INFO, "Example ACPICA info message")); + ACPI_WARNING ((AE_INFO, "Example ACPICA warning message")); + ACPI_ERROR ((AE_INFO, "Example ACPICA error message")); + ACPI_EXCEPTION ((AE_INFO, AE_AML_OPERAND_TYPE, + "Example ACPICA exception message")); + + ExecuteOSI (); + ExecuteMAIN (); + return (0); +} + + +/****************************************************************************** + * + * Example ACPICA initialization code. This shows a full initialization with + * no early ACPI table access. + * + *****************************************************************************/ + +static ACPI_STATUS +InitializeFullAcpica (void) +{ + ACPI_STATUS Status; + + + /* Initialize the ACPICA subsystem */ + + AcpiGbl_OverrideDefaultRegionHandlers = TRUE; + Status = AcpiInitializeSubsystem (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While initializing ACPICA")); + return (Status); + } + + /* Initialize the ACPICA Table Manager and get all ACPI tables */ + + ACPI_INFO ((AE_INFO, "Loading ACPI tables")); + + Status = AcpiInitializeTables (NULL, 16, FALSE); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While initializing Table Manager")); + return (Status); + } + + /* Install local handlers */ + + Status = InstallHandlers (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While installing handlers")); + return (Status); + } + + /* Initialize the ACPI hardware */ + + Status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While enabling ACPICA")); + return (Status); + } + + /* Create the ACPI namespace from ACPI tables */ + + Status = AcpiLoadTables (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While loading ACPI tables")); + return (Status); + } + + /* Complete the ACPI namespace object initialization */ + + Status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While initializing ACPICA objects")); + return (Status); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * Example ACPICA initialization code with early ACPI table access. This shows + * an initialization that requires early access to ACPI tables (before + * kernel dynamic memory is available) + * + *****************************************************************************/ + +/* + * The purpose of this static table array is to avoid the use of kernel + * dynamic memory which may not be available during early ACPI table + * access. + */ +#define ACPI_MAX_INIT_TABLES 16 +static ACPI_TABLE_DESC TableArray[ACPI_MAX_INIT_TABLES]; + + +/* + * This function would be called early in kernel initialization. After this + * is called, all ACPI tables are available to the host. + */ +ACPI_STATUS +InitializeAcpiTables ( + void) +{ + ACPI_STATUS Status; + + + /* Initialize the ACPICA Table Manager and get all ACPI tables */ + + Status = AcpiInitializeTables (TableArray, ACPI_MAX_INIT_TABLES, TRUE); + return (Status); +} + + +/* + * This function would be called after the kernel is initialized and + * dynamic/virtual memory is available. It completes the initialization of + * the ACPICA subsystem. + */ +ACPI_STATUS +InitializeAcpi ( + void) +{ + ACPI_STATUS Status; + + + /* Initialize the ACPICA subsystem */ + + AcpiGbl_OverrideDefaultRegionHandlers = TRUE; + Status = AcpiInitializeSubsystem (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Copy the root table list to dynamic memory */ + + Status = AcpiReallocateRootTable (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Install local handlers */ + + Status = InstallHandlers (); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While installing handlers")); + return (Status); + } + + /* Initialize the ACPI hardware */ + + Status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Create the ACPI namespace from ACPI tables */ + + Status = AcpiLoadTables (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Complete the ACPI namespace object initialization */ + + Status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * Example ACPICA handler and handler installation + * + *****************************************************************************/ + +static void +NotifyHandler ( + ACPI_HANDLE Device, + UINT32 Value, + void *Context) +{ + + ACPI_INFO ((AE_INFO, "Received a notify 0x%X", Value)); +} + + +static ACPI_STATUS +RegionInit ( + ACPI_HANDLE RegionHandle, + UINT32 Function, + void *HandlerContext, + void **RegionContext) +{ + + if (Function == ACPI_REGION_DEACTIVATE) + { + *RegionContext = NULL; + } + else + { + *RegionContext = RegionHandle; + } + + return (AE_OK); +} + + +static ACPI_STATUS +RegionHandler ( + UINT32 Function, + ACPI_PHYSICAL_ADDRESS Address, + UINT32 BitWidth, + UINT64 *Value, + void *HandlerContext, + void *RegionContext) +{ + + ACPI_INFO ((AE_INFO, "Received a region access")); + + return (AE_OK); +} + + +static ACPI_STATUS +InstallHandlers (void) +{ + ACPI_STATUS Status; + + + /* Install global notify handler */ + + Status = AcpiInstallNotifyHandler (ACPI_ROOT_OBJECT, + ACPI_SYSTEM_NOTIFY, NotifyHandler, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While installing Notify handler")); + return (Status); + } + + Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT, + ACPI_ADR_SPACE_SYSTEM_MEMORY, RegionHandler, RegionInit, NULL); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While installing an OpRegion handler")); + return (Status); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * Examples of control method execution. + * + * _OSI is a predefined method that is implemented internally within ACPICA. + * + * Shows the following elements: + * + * 1) How to setup a control method argument and argument list + * 2) How to setup the return value object + * 3) How to invoke AcpiEvaluateObject + * 4) How to check the returned ACPI_STATUS + * 5) How to analyze the return value + * + *****************************************************************************/ + +static void +ExecuteOSI (void) +{ + ACPI_STATUS Status; + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg[1]; + ACPI_BUFFER ReturnValue; + ACPI_OBJECT *Object; + + + ACPI_INFO ((AE_INFO, "Executing _OSI reserved method")); + + /* Setup input argument */ + + ArgList.Count = 1; + ArgList.Pointer = Arg; + + Arg[0].Type = ACPI_TYPE_STRING; + Arg[0].String.Pointer = "Windows 2001"; + Arg[0].String.Length = strlen (Arg[0].String.Pointer); + + /* Ask ACPICA to allocate space for the return object */ + + ReturnValue.Length = ACPI_ALLOCATE_BUFFER; + + Status = AcpiEvaluateObject (NULL, "\\_OSI", &ArgList, &ReturnValue); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While executing _OSI")); + return; + } + + /* Ensure that the return object is large enough */ + + if (ReturnValue.Length < sizeof (ACPI_OBJECT)) + { + AcpiOsPrintf ("Return value from _OSI method too small, %.8X\n", + ReturnValue.Length); + goto ErrorExit; + } + + /* Expect an integer return value from execution of _OSI */ + + Object = ReturnValue.Pointer; + if (Object->Type != ACPI_TYPE_INTEGER) + { + AcpiOsPrintf ("Invalid return type from _OSI, %.2X\n", Object->Type); + } + + ACPI_INFO ((AE_INFO, "_OSI returned 0x%8.8X", + (UINT32) Object->Integer.Value)); + + +ErrorExit: + + /* Free a buffer created via ACPI_ALLOCATE_BUFFER */ + + AcpiOsFree (ReturnValue.Pointer); +} + + +/****************************************************************************** + * + * Execute an actual control method in the DSDT (MAIN) + * + *****************************************************************************/ + +static void +ExecuteMAIN (void) +{ + ACPI_STATUS Status; + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg[1]; + ACPI_BUFFER ReturnValue; + ACPI_OBJECT *Object; + + + ACPI_INFO ((AE_INFO, "Executing MAIN method")); + + /* Setup input argument */ + + ArgList.Count = 1; + ArgList.Pointer = Arg; + + Arg[0].Type = ACPI_TYPE_STRING; + Arg[0].String.Pointer = "Method [MAIN] is executing"; + Arg[0].String.Length = strlen (Arg[0].String.Pointer); + + /* Ask ACPICA to allocate space for the return object */ + + ReturnValue.Length = ACPI_ALLOCATE_BUFFER; + + Status = AcpiEvaluateObject (NULL, "\\MAIN", &ArgList, &ReturnValue); + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While executing MAIN")); + return; + } + + if (ReturnValue.Pointer) + { + /* Obtain and validate the returned ACPI_OBJECT */ + + Object = ReturnValue.Pointer; + if (Object->Type == ACPI_TYPE_STRING) + { + AcpiOsPrintf ("Method [MAIN] returned: \"%s\"\n", + Object->String.Pointer); + } + + ACPI_FREE (ReturnValue.Pointer); + } +} diff --git a/third_party/lib/acpica/source/tools/examples/examples.h b/third_party/lib/acpica/source/tools/examples/examples.h new file mode 100644 index 000000000..4cee563ba --- /dev/null +++ b/third_party/lib/acpica/source/tools/examples/examples.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Module Name: examples.h - Common include for Examples program + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _EXAMPLES_H +#define _EXAMPLES_H + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include "../acpiexec/aecommon.h" + +#include + + +void +ExInitializeAcpiTables ( + void); + +#endif diff --git a/third_party/lib/acpica/source/tools/examples/exstubs.c b/third_party/lib/acpica/source/tools/examples/exstubs.c new file mode 100644 index 000000000..3cdccf589 --- /dev/null +++ b/third_party/lib/acpica/source/tools/examples/exstubs.c @@ -0,0 +1,89 @@ +/****************************************************************************** + * + * Module Name: exstubs - Stub routines for the Example program + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "examples.h" + +#include +#include +#include + +#define _COMPONENT ACPI_EXAMPLE + ACPI_MODULE_NAME ("exstubs") + + +/****************************************************************************** + * + * DESCRIPTION: Stubs used to facilitate linkage of the example program + * + *****************************************************************************/ + + +/* Hardware manager */ + +ACPI_STATUS +AcpiHwReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiHwWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + return (AE_OK); +} + + +/* Event manager */ + +ACPI_STATUS +AcpiEvInitializeEvents ( + void) +{ + return (AE_OK); +} diff --git a/third_party/lib/acpica/source/tools/examples/extables.c b/third_party/lib/acpica/source/tools/examples/extables.c new file mode 100644 index 000000000..63ef610ec --- /dev/null +++ b/third_party/lib/acpica/source/tools/examples/extables.c @@ -0,0 +1,491 @@ +/****************************************************************************** + * + * Module Name: extables - ACPI tables for Example program + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "examples.h" +#include "actables.h" + +#define _COMPONENT ACPI_EXAMPLE + ACPI_MODULE_NAME ("extables") + + +/****************************************************************************** + * + * ACPICA Example tables and table setup + * + * This module contains the ACPI tables used for the example program. The + * original source code for the tables appears at the end of the module. + * + *****************************************************************************/ + + +/* These tables will be modified at runtime */ + +unsigned char RsdpCode[] = +{ + 0x52,0x53,0x44,0x20,0x50,0x54,0x52,0x20, /* 00000000 "RSD PTR " */ + 0x43,0x49,0x4E,0x54,0x45,0x4C,0x20,0x02, /* 00000008 "CINTEL ." */ + 0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x00, /* 00000010 "....$..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000018 "........" */ + 0xDC,0x00,0x00,0x00 /* 00000020 "...." */ +}; + +unsigned char RsdtCode[] = +{ + 0x52,0x53,0x44,0x54,0x28,0x00,0x00,0x00, /* 00000000 "RSDT(..." */ + 0x01,0x10,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x15,0x11,0x13,0x20,0x01,0x00,0x00,0x00 /* 00000020 "... ...." */ +}; + +unsigned char XsdtCode[] = +{ + 0x58,0x53,0x44,0x54,0x2C,0x00,0x00,0x00, /* 00000000 "XSDT,..." */ + 0x01,0x06,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 "..INTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x15,0x11,0x13,0x20,0x01,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x00,0x00,0x00,0x00 /* 00000028 "...." */ +}; + +unsigned char FadtCode[] = +{ + 0x46,0x41,0x43,0x50,0x0C,0x01,0x00,0x00, /* 00000000 "FACP...." */ + 0x05,0x64,0x49,0x4E,0x54,0x45,0x4C,0x20, /* 00000008 ".dINTEL " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x15,0x11,0x13,0x20,0x01,0x00,0x00,0x00, /* 00000020 "... ...." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000038 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000040 "........" */ + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000048 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000050 "........" */ + 0x04,0x02,0x01,0x04,0x08,0x00,0x00,0x00, /* 00000058 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000060 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000068 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 00000070 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000078 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000080 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, /* 00000088 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x02, /* 00000090 "..... .." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000098 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000A0 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x10,0x00,0x02, /* 000000A8 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000B8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x00, /* 000000C0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000C8 "........" */ + 0x01,0x20,0x00,0x03,0x01,0x00,0x00,0x00, /* 000000D0 ". ......" */ + 0x00,0x00,0x00,0x00,0x01,0x40,0x00,0x01, /* 000000D8 ".....@.." */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x01, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ + 0x01,0x08,0x00,0x01,0x00,0x00,0x00,0x00, /* 00000100 "........" */ + 0x00,0x00,0x00,0x00 /* 00000108 "...." */ +}; + +/* Fixed tables */ + +static unsigned char FacsCode[] = +{ + 0x46,0x41,0x43,0x53,0x40,0x00,0x00,0x00, /* 00000000 "FACS@..." */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000008 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000010 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000018 "........" */ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000020 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000028 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000030 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000038 "........" */ +}; + +static unsigned char DsdtCode[] = +{ + 0x44,0x53,0x44,0x54,0x8C,0x00,0x00,0x00, /* 00000000 "DSDT...." */ + 0x02,0x76,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 ".vIntel." */ + 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x24,0x04,0x14,0x20,0x5B,0x80,0x47,0x4E, /* 00000020 "$.. [.GN" */ + 0x56,0x53,0x00,0x0C,0x98,0xEE,0xBB,0xDF, /* 00000028 "VS......" */ + 0x0A,0x13,0x5B,0x81,0x0B,0x47,0x4E,0x56, /* 00000030 "..[..GNV" */ + 0x53,0x00,0x46,0x4C,0x44,0x31,0x08,0x14, /* 00000038 "S.FLD1.." */ + 0x4C,0x04,0x4D,0x41,0x49,0x4E,0x01,0x70, /* 00000040 "L.MAIN.p" */ + 0x73,0x0D,0x4D,0x61,0x69,0x6E,0x2F,0x41, /* 00000048 "s.Main/A" */ + 0x72,0x67,0x30,0x3A,0x20,0x00,0x68,0x00, /* 00000050 "rg0: .h." */ + 0x5B,0x31,0x70,0x00,0x46,0x4C,0x44,0x31, /* 00000058 "[1p.FLD1" */ + 0x86,0x5C,0x00,0x00,0xA4,0x0D,0x4D,0x61, /* 00000060 ".\....Ma" */ + 0x69,0x6E,0x20,0x73,0x75,0x63,0x63,0x65, /* 00000068 "in succe" */ + 0x73,0x73,0x66,0x75,0x6C,0x6C,0x79,0x20, /* 00000070 "ssfully " */ + 0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,0x65, /* 00000078 "complete" */ + 0x64,0x20,0x65,0x78,0x65,0x63,0x75,0x74, /* 00000080 "d execut" */ + 0x69,0x6F,0x6E,0x00 /* 00000088 "ion." */ +}; + + +/* Useful pointers */ + +ACPI_TABLE_RSDP *Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, RsdpCode); +ACPI_TABLE_RSDT *Rsdt = ACPI_CAST_PTR (ACPI_TABLE_RSDT, RsdtCode); +ACPI_TABLE_XSDT *Xsdt = ACPI_CAST_PTR (ACPI_TABLE_XSDT, XsdtCode); +ACPI_TABLE_FADT *Fadt = ACPI_CAST_PTR (ACPI_TABLE_FADT, FadtCode); + + +/****************************************************************************** + * + * Build the various required ACPI tables: + * + * 1) Setup RSDP to point to the RSDT and XSDT + * 2) Setup RSDT/XSDT to point to the FADT + * 3) Setup FADT to point to the DSDT and FACS + * 4) Update checksums for all modified tables + * + *****************************************************************************/ + +void +ExInitializeAcpiTables ( + void) +{ + + /* Setup RSDP */ + + Rsdp->RsdtPhysicalAddress = (UINT32) ACPI_TO_INTEGER (RsdtCode); + Rsdp->XsdtPhysicalAddress = (UINT64) ACPI_TO_INTEGER (XsdtCode); + + /* RSDT and XSDT */ + + Rsdt->TableOffsetEntry[0] = (UINT32) ACPI_TO_INTEGER (FadtCode); + Xsdt->TableOffsetEntry[0] = (UINT64) ACPI_TO_INTEGER (FadtCode); + + /* FADT */ + + Fadt->Facs = 0; + Fadt->Dsdt = 0; + Fadt->XFacs = (UINT64) ACPI_TO_INTEGER (FacsCode); + Fadt->XDsdt = (UINT64) ACPI_TO_INTEGER (DsdtCode); + + /* Set new checksums for the modified tables */ + + Rsdp->Checksum = 0; + Rsdp->Checksum = (UINT8) -AcpiTbChecksum ( + (void *) RsdpCode, ACPI_RSDP_CHECKSUM_LENGTH); + + Rsdt->Header.Checksum = 0; + Rsdt->Header.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) Rsdt, Rsdt->Header.Length); + + Xsdt->Header.Checksum = 0; + Xsdt->Header.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) Xsdt, Xsdt->Header.Length); + + Fadt->Header.Checksum = 0; + Fadt->Header.Checksum = (UINT8) -AcpiTbChecksum ( + (void *) Fadt, Fadt->Header.Length); +} + + +/****************************************************************************** + * + * OSL support - return the address of the RSDP + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + + return (ACPI_PTR_TO_PHYSADDR (RsdpCode)); +} + + +#ifdef DO_NOT_COMPILE_ACPI_TABLE_CODE +/****************************************************************************** + * + * ACPICA Example table source code + * + * This is the original source code for the tables above + * + *****************************************************************************/ + +/* RSDP */ + +[0008] Signature : "RSD PTR " +[0001] Checksum : 43 +[0006] Oem ID : "INTEL " +[0001] Revision : 02 +[0004] RSDT Address : 00000000 +[0004] Length : 00000024 +[0008] XSDT Address : 0000000000000000 +[0001] Extended Checksum : DC +[0003] Reserved : 000000 + + +/* RSDT */ + +[0004] Signature : "RSDT" [Root System Description Table] +[0004] Table Length : 00000044 +[0001] Revision : 01 +[0001] Checksum : B1 +[0006] Oem ID : "INTEL " +[0008] Oem Table ID : "TEMPLATE" +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20100528 + +[0004] ACPI Table Address 0 : 00000001 + + +/* XSDT */ + +[0004] Signature : "XSDT" [Extended System Description Table] +[0004] Table Length : 00000064 +[0001] Revision : 01 +[0001] Checksum : 8B +[0006] Oem ID : "INTEL " +[0008] Oem Table ID : "TEMPLATE" +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20100528 + +[0008] ACPI Table Address 0 : 0000000000000001 + + +/* FADT */ + +[0004] Signature : "FACP" [Fixed ACPI Description Table (FADT)] +[0004] Table Length : 0000010C +[0001] Revision : 05 +[0001] Checksum : 18 +[0006] Oem ID : "INTEL " +[0008] Oem Table ID : "TEMPLATE" +[0004] Oem Revision : 00000000 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20111123 + +[0004] FACS Address : 00000001 +[0004] DSDT Address : 00000001 +[0001] Model : 00 +[0001] PM Profile : 00 [Unspecified] +[0002] SCI Interrupt : 0000 +[0004] SMI Command Port : 00000000 +[0001] ACPI Enable Value : 00 +[0001] ACPI Disable Value : 00 +[0001] S4BIOS Command : 00 +[0001] P-State Control : 00 +[0004] PM1A Event Block Address : 00000001 +[0004] PM1B Event Block Address : 00000000 +[0004] PM1A Control Block Address : 00000001 +[0004] PM1B Control Block Address : 00000000 +[0004] PM2 Control Block Address : 00000001 +[0004] PM Timer Block Address : 00000001 +[0004] GPE0 Block Address : 00000001 +[0004] GPE1 Block Address : 00000000 +[0001] PM1 Event Block Length : 04 +[0001] PM1 Control Block Length : 02 +[0001] PM2 Control Block Length : 01 +[0001] PM Timer Block Length : 04 +[0001] GPE0 Block Length : 08 +[0001] GPE1 Block Length : 00 +[0001] GPE1 Base Offset : 00 +[0001] _CST Support : 00 +[0002] C2 Latency : 0000 +[0002] C3 Latency : 0000 +[0002] CPU Cache Size : 0000 +[0002] Cache Flush Stride : 0000 +[0001] Duty Cycle Offset : 00 +[0001] Duty Cycle Width : 00 +[0001] RTC Day Alarm Index : 00 +[0001] RTC Month Alarm Index : 00 +[0001] RTC Century Index : 00 +[0002] Boot Flags (decoded below) : 0000 + Legacy Devices Supported (V2) : 0 + 8042 Present on ports 60/64 (V2) : 0 + VGA Not Present (V4) : 0 + MSI Not Supported (V4) : 0 + PCIe ASPM Not Supported (V4) : 0 + CMOS RTC Not Present (V5) : 0 +[0001] Reserved : 00 +[0004] Flags (decoded below) : 00000000 + WBINVD instruction is operational (V1) : 0 + WBINVD flushes all caches (V1) : 0 + All CPUs support C1 (V1) : 0 + C2 works on MP system (V1) : 0 + Control Method Power Button (V1) : 0 + Control Method Sleep Button (V1) : 0 + RTC wake not in fixed reg space (V1) : 0 + RTC can wake system from S4 (V1) : 0 + 32-bit PM Timer (V1) : 0 + Docking Supported (V1) : 0 + Reset Register Supported (V2) : 0 + Sealed Case (V3) : 0 + Headless - No Video (V3) : 0 + Use native instr after SLP_TYPx (V3) : 0 + PCIEXP_WAK Bits Supported (V4) : 0 + Use Platform Timer (V4) : 0 + RTC_STS valid on S4 wake (V4) : 0 + Remote Power-on capable (V4) : 0 + Use APIC Cluster Model (V4) : 0 + Use APIC Physical Destination Mode (V4) : 0 + Hardware Reduced (V5) : 0 + Low Power S0 Idle (V5) : 0 + +[0012] Reset Register : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 08 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 01 [Byte Access:8] +[0008] Address : 0000000000000001 + +[0001] Value to cause reset : 00 +[0003] Reserved : 000000 +[0008] FACS Address : 0000000000000001 +[0008] DSDT Address : 0000000000000001 +[0012] PM1A Event Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 20 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 02 [Word Access:16] +[0008] Address : 0000000000000001 + +[0012] PM1B Event Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 00 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 00 [Undefined/Legacy] +[0008] Address : 0000000000000000 + +[0012] PM1A Control Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 10 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 02 [Word Access:16] +[0008] Address : 0000000000000001 + +[0012] PM1B Control Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 00 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 00 [Undefined/Legacy] +[0008] Address : 0000000000000000 + +[0012] PM2 Control Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 08 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 00 [Undefined/Legacy] +[0008] Address : 0000000000000001 + +[0012] PM Timer Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 20 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 03 [DWord Access:32] +[0008] Address : 0000000000000001 + +[0012] GPE0 Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 40 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 01 [Byte Access:8] +[0008] Address : 0000000000000001 + +[0012] GPE1 Block : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 00 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 00 [Undefined/Legacy] +[0008] Address : 0000000000000000 + + +[0012] Sleep Control Register : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 08 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 01 [Byte Access:8] +[0008] Address : 0000000000000000 + +[0012] Sleep Status Register : [Generic Address Structure] +[0001] Space ID : 01 [SystemIO] +[0001] Bit Width : 08 +[0001] Bit Offset : 00 +[0001] Encoded Access Width : 01 [Byte Access:8] +[0008] Address : 0000000000000000 + + +/* FACS */ + +[0004] Signature : "FACS" +[0004] Length : 00000040 +[0004] Hardware Signature : 00000000 +[0004] 32 Firmware Waking Vector : 00000000 +[0004] Global Lock : 00000000 +[0004] Flags (decoded below) : 00000000 + S4BIOS Support Present : 0 + 64-bit Wake Supported (V2) : 0 +[0008] 64 Firmware Waking Vector : 0000000000000000 +[0001] Version : 02 +[0003] Reserved : 000000 +[0004] OspmFlags (decoded below) : 00000000 + 64-bit Wake Env Required (V2) : 0 + + +/* DSDT - ASL code */ + +DefinitionBlock ("dsdt.aml", "DSDT", 2, "Intel", "Template", 0x00000001) +{ + OperationRegion (GNVS, SystemMemory, 0xDFBBEE98, 0x00000013) + Field (GNVS, AnyAcc, NoLock, Preserve) + { + FLD1, 8, + } + + Method (MAIN, 1, NotSerialized) + { + Store (Concatenate ("Main/Arg0: ", Arg0), Debug) + Store (Zero, FLD1) + Notify (\, Zero) + Return ("Main successfully completed execution") + } +} +#endif diff --git a/third_party/lib/acpica/tests/misc/badcode.asl b/third_party/lib/acpica/tests/misc/badcode.asl new file mode 100644 index 000000000..33ce923fb --- /dev/null +++ b/third_party/lib/acpica/tests/misc/badcode.asl @@ -0,0 +1,407 @@ +/* + * badcode.asl + * + * This file contains examples of the extended error checking and + * typechecking capabilities of the iASL compiler. Other ASL compilers + * may ignore these errors completely. Note - this is not an exhaustive + * list of errors detected by iASL, it shows many of the errors that + * are not detected by other ASL compilers. + * + * To compile, use: + * iasl badcode.asl + * + * Output: + * Compilation complete. 45 Errors, 22 Warnings, 3 Remarks, 16 Optimizations + * + */ +DefinitionBlock ("badcode.aml", "DSDT", 1, "Intel", "Example", 0x00000001) +{ + Name (INT1, 0) + Name (BUF1, Buffer() {0,1,2,3}) + Event (EVT1) + + // Invalid SyncLevel in Mutex declaration + + Mutex (MTX1, 32) + + // Integer beyond the table integer size (32 bits) + + Name (BIG, 0x1234567887654321) + + // CPackage length does not match initializer list length + + Name (PKG1, Package(5) {0,1}) + + // Inadvertent use of single backslash in a string + + Name (PATH, Buffer() {"\_SB_.PCI2._CRS"}) + + // Invalid hex escape sequence + + Name (ESC1, "abcdefg\x00hijklmn") + + // Field access beyond region bounds + + OperationRegion (OPR1, SystemMemory, 0x2000, 6) + Field (OPR1, DWordAcc, NoLock, Preserve) + { + Offset (4), + FLD1, 8 + } + + // Some address spaces support only ByteAcc or BufferAcc + + OperationRegion (OPR2, EmbeddedControl, 0x4000, 8) + Field (OPR2, DWordAcc, NoLock, Preserve) + { + FLD2, 8 + } + OperationRegion (OPR3, SMBus, 0x8000, 16) + Field (OPR3, WordAcc, NoLock, Preserve) + { + FLD3, 8 + } + + // Invalid SyncLevel in method declaration + + Method (MTH1, 0, NotSerialized, 32) + { + // Invalid arguments and uninitialized locals + + Store (Arg3, Local0) + Store (Local1, Local2) + + // Parameter typechecking (MTX1 is invalid type) + + Subtract (MTX1, 4, Local3) + + // Various invalid parameters + + CreateField (BUF1, 0, Subtract (4, 4), FLD1) + + // Unchecked mutex and event timeouts + + Acquire (MTX1, 100) + Wait (EVT1, 1) + + // Result from operation is not used - statement has no effect + + Add (INT1, 8) + + // Unreachable code + + Return (0) + Store (5, INT1) + } + + Method (MTH2) + { + // Switch with no Case statements + + Switch (ToInteger (INT1)) + { + Default + { + } + } + + if (LEqual (INT1, 0)) + { + Return (INT1) + } + + // Fallthrough exit path does not return a value + } + + Method (MTH3) + { + // Method MTH2 above does not always return a value + + Store (MTH2 (), Local0) + } + + // Method MTH4 does not explicitly return a value + + Method (MTH4) {} + Method (MTH5) {Store (MTH4(), Local0)} + + // Invalid _HID values + + Device (H1) + { + Name (_HID, "*PNP0C0A") // Illegal leading asterisk + } + Device (H2) + { + Name (_HID, "PNP") // Too short, must be 7 or 8 chars + } + Device (H3) + { + Name (_HID, "MYDEVICE01") // Too long, must be 7 or 8 chars + } + Device (H4) + { + Name (_HID, "acpi0001") // non-hex chars must be uppercase + } + Device (H5) + { + Name (_HID, "PNP-123") // HID must be alphanumeric + } + Device (H6) + { + Name (_HID, "") // Illegal Null HID + Name (_CID, "") // Illegal Null CID + } + + // Predefined Name typechecking + + Name (_PRW, 4) + Name (_FDI, Buffer () {0}) + + // Predefined Name argument count validation + // and return value validation + + Method (_OSC, 5) + { + } + + // Predefined Names that must be implemented as control methods + + Name (_L01, 1) + Name (_E02, 2) + Name (_Q03, 3) + Name (_ON, 0) + Name (_INI, 1) + Name (_PTP, 2) + + // GPE methods that cause type collision (L vs. E) + + Scope (\_GPE) + { + Method (_L1D) + { + } + Method (_E1D) + { + } + } + + // Predefined names that should not have a return value + + Method (_FDM, 1) + { + Return (Buffer(1){0x33}) + } + Method (_Q22) + { + Return ("Unexpected Return Value") + } + + // _REG must have a corresponding Operation Region declaration + // within the same scope + + Device (EC) + { + Method (_REG, 2) + { + } + } + + /* + * Resource Descriptor error checking + */ + Name (RSC1, ResourceTemplate () + { + // Illegal nested StartDependent macros + + StartDependentFn (0, 0) + { + StartDependentFn (0, 0) + { + } + } + + // Missing EndDependentFn macro + }) + + Name (RSC2, ResourceTemplate () + { + // AddressMin is larger than AddressMax + IO (Decode16, + 0x07D0, // Range Minimum + 0x03E8, // Range Maximum + 0x01, // Alignment + 0x20, // Length + ) + + // Length larger than Min/Max window size + Memory32 (ReadOnly, + 0x00001000, // Range Minimum + 0x00002000, // Range Maximum + 0x00000004, // Alignment + 0x00002000, // Length + ) + + // Min and Max not multiples of alignment value + Memory32 (ReadOnly, + 0x00001001, // Range Minimum + 0x00002002, // Range Maximum + 0x00000004, // Alignment + 0x00000200, // Length + ) + + // 10-bit ISA I/O address has a max of 0x3FF + FixedIO ( + 0xFFFF, // Address + 0x20, // Length + ) + + // Invalid AccessSize parameter + Register (SystemIO, + 0x08, // Bit Width + 0x00, // Bit Offset + 0x0000000000000100, // Address + 0x05 // Access Size + ) + + // Invalid ResourceType (0xB0) + QWordSpace (0xB0, ResourceConsumer, PosDecode, MinFixed, MaxFixed, 0xA5, + 0x0000, // Granularity + 0xA000, // Range Minimum + 0xBFFF, // Range Maximum + 0x0000, // Translation Offset + 0x2000, // Length + ,, ) + + // AddressMin is larger than AddressMax + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Granularity + 0x0200, // Range Minimum + 0x0100, // Range Maximum + 0x0000, // Translation Offset + 0x0100, // Length + ,, , TypeStatic) + + // Length larger than Min/Max window size + DWordSpace (0xC3, ResourceConsumer, PosDecode, MinFixed, MaxFixed, 0xA5, + 0x00000000, // Granularity + 0x000C8000, // Range Minimum + 0x000C9000, // Range Maximum + 0x00000000, // Translation Offset + 0x00001002, // Length + ,, ) + + // Granularity must be (power-of-two -1) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxNotFixed, NonCacheable, ReadWrite, + 0x00000010, + 0x40000000, + 0xFED9FFFF, + 0x00000000, + 0xBECA0000) + + // Address Min (with zero length) not on granularity boundary + QWordIO (ResourceProducer, MinFixed, MaxNotFixed, PosDecode, EntireRange, + 0x0000000000000003, // Granularity + 0x0000000000000B02, // Range Minimum + 0x0000000000000C00, // Range Maximum + 0x0000000000000000, // Translation Offset + 0x0000000000000000, // Length + ,, , TypeStatic) + + // Address Max (with zero length) not on (granularity boundary -1) + QWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, Cacheable, ReadWrite, + 0x0000000000000001, // Granularity + 0x0000000000100000, // Range Minimum + 0x00000000002FFFFE, // Range Maximum + 0x0000000000000000, // Translation Offset + 0x0000000000000000, // Length + ,, , AddressRangeMemory, TypeStatic) + + // Invalid combination: zero length, both Min and Max are fixed + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x00000000, // Granularity + 0x000C8000, // Range Minimum + 0x000C8FFF, // Range Maximum + 0x00000000, // Translation Offset + 0x00000000, // Length + ,, ) + + // Invalid combination: non-zero length, Min Fixed, Max not fixed + DWordIO (ResourceProducer, MinFixed, MaxNotFixed, PosDecode, EntireRange, + 0x00000001, // Granularity + 0x000C8000, // Range Minimum + 0x000C8FFF, // Range Maximum + 0x00000000, // Translation Offset + 0x00000100, // Length + ,, ) + + // Invalid combination: non-zero length, Min not Fixed, Max fixed + DWordIO (ResourceProducer, MinNotFixed, MaxFixed, PosDecode, EntireRange, + 0x00000001, // Granularity + 0x000C8000, // Range Minimum + 0x000C8FFF, // Range Maximum + 0x00000000, // Translation Offset + 0x00000200, // Length + ,, ) + + // Granularity must be zero if non-zero length, min/max fixed + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000000F, // Granularity + 0x000C8000, // Range Minimum + 0x000C8FFF, // Range Maximum + 0x00000000, // Translation Offset + 0x00001000, // Length + ,, ) + + // Null descriptor (intended to be modified at runtime) must + // have a resource tag (to allow it to be modified at runtime) + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x00000000, // Granularity + 0x00000000, // Range Minimum + 0x00000000, // Range Maximum + 0x00000000, // Translation Offset + 0x00000000, // Length + ,, ) + + // Missing StartDependentFn macro + + EndDependentFn () + }) + + // Test descriptor for CreateXxxxField operators in REM1 below + + Name (RSC3, ResourceTemplate () + { + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x00000000, // Granularity + 0x000C8000, // Range Minimum + 0x000C8FFF, // Range Maximum + 0x00000000, // Translation Offset + 0x00001000, // Length + ,, DWI1) + }) + + Method (REM1) + { + // Tagged resource field larger than field being created + + CreateWordField (RSC3, \DWI1._LEN, LEN) + CreateByteField (RSC3, \DWI1._MIN, MIN) + CreateBitField (RSC3, \DWI1._RNG, RNG1) + + // Tagged resource field smaller than field being created + + CreateQWordField (RSC3, \DWI1._MAX, MAX) + CreateBitField (RSC3, \DWI1._GRA, GRA) + CreateField (RSC3, \DWI1._MIF, 5, MIF) + CreateField (RSC3, \DWI1._RNG, 3, RNG2) + } + + Method (L100) + { + /* Method Local is set but never used */ + + Store (40, Local0) + } +} + diff --git a/third_party/lib/acpica/tests/misc/grammar.asl b/third_party/lib/acpica/tests/misc/grammar.asl new file mode 100644 index 000000000..1b89e5999 --- /dev/null +++ b/third_party/lib/acpica/tests/misc/grammar.asl @@ -0,0 +1,10282 @@ +/* + * Some or all of this work - Copyright (c) 2006 - 2016, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// +// +// Grammar.asl - Minimally excercises most ASL constructs +// +// NOTE -- use: iasl -f -of grammar.asl to compile +// +// This 1) Ignores errors (checks compiler error handling) +// 2) Disables constant folding +// +// + +/******************************************************************************* +Compilation should look like this: + +C:\acpica\tests\misc>iasl -f -of grammar.asl + +Intel ACPI Component Architecture +ASL Optimizing Compiler version 20090422 [Apr 22 2009] +Copyright (C) 2000 - 2009 Intel Corporation +Supports ACPI Specification Revision 3.0a + +grammar.asl 187: Name (_NPK, Package (8) +Warning 1098 - ^ Unknown reserved name (_NPK) + +grammar.asl 510: NAME (ESC1, "abcdefg\x00hijklmn") +Warning 1042 - ^ Invalid Hex/Octal Escape - Non-ASCII or NULL + +grammar.asl 511: NAME (ESC2, "abcdefg\000hijklmn") +Warning 1042 - ^ Invalid Hex/Octal Escape - Non-ASCII or NULL + +grammar.asl 601: Method (RCIV, 1) +Warning 1087 - ^ Not all control paths return a value (RCIV) + +grammar.asl 608: RCIV (Subtract (Arg0, 1)) +Remark 5073 - ^ Recursive method call (RCIV) + +grammar.asl 937: Method (_ERR, 2) +Warning 1077 - ^ Reserved method has too few arguments (_ERR requires 3) + +grammar.asl 1377: Store (0x1234567887654321, QWD2) +Warning 1032 - ^ 64-bit integer in 32-bit table, truncating + +grammar.asl 1379: if (LNotEqual (Local0, 0x1234567887654321)) +Warning 1032 - 64-bit integer in 32-bit table, truncating ^ + +grammar.asl 1459: SizeOf (BUFO) +Warning 1105 - ^ Result is not used, operator has no effect + +grammar.asl 1485: Acquire (MTX2, 1) +Warning 1104 - ^ Possible operator timeout is ignored + +grammar.asl 1633: Add (Local0, Local1) +Warning 1105 - ^ Result is not used, operator has no effect + +grammar.asl 1804: Method (COND) +Warning 1087 - ^ Not all control paths return a value (COND) + +grammar.asl 6010: Name (_HID, "*PNP0A06") +Error 4001 - ^ String must be entirely alphanumeric (*PNP0A06) + +grammar.asl 6461: Name (_CRS, Buffer(26) {"\_SB_.PCI2._CRS..........."}) +Warning 1038 - Invalid or unknown escape sequence ^ + +grammar.asl 6800: And (Local0, 1, Local0) // Local0 &= 1 +Error 4050 - ^ Method local variable is not initialized (Local0) + +grammar.asl 6886: Name (_HID, "*PNP0C0A") // Control Method Battey ID +Error 4001 - ^ String must be entirely alphanumeric (*PNP0C0A) + +ASL Input: grammar.asl - 10254 lines, 322162 bytes, 4810 keywords +AML Output: grammar.aml - 43392 bytes, 669 named objects, 4141 executable opcodes + +Compilation complete. 3 Errors, 12 Warnings, 1 Remarks, 1101 Optimizations + +***************************************************************************************************/ + +DefinitionBlock ( + "grammar.aml", //Output filename + "DSDT", //Signature + 0x01, //DSDT Revision ---> 32-bit table + "Intel", //OEMID + "GRMTEST", //TABLE ID + 0x20090511 //OEM Revision + ) +{ + + External (\ABCD, UnknownObj) + + + /* Device with _STA and _INI */ + + Device (A1) + { + Method (_STA) + { + Return (0x0F) + } + + Method (_INI) + { + Return + } + } + + /* Device with no _STA, has _INI */ + + Device (A2) + { + Method (_INI) + { + Return + } + } + + /* Device with _STA, no _INI */ + + Device (A3) + { + Method (_STA) + { + Return (0x0F) + } + } + + /* Device with _STA and _INI, but not present */ + + Device (A4) + { + Method (_STA) + { + Return (Zero) + } + + Method (_INI) + { + Return + } + } + + + /* Resource descriptors */ + + Device (IRES) + { + Name (PRT0, ResourceTemplate () + { + IRQ (Edge, ActiveHigh, Exclusive) {3,4,5,6,7,9,10,11,14,15} + + StartDependentFn (1,1) + { + IRQNoFlags () {0,1,2} + } + EndDependentFn () + }) + + Method (_CRS, 0, NotSerialized) + { + Store ("_CRS:", Debug) + Store (PRT0, Debug) + Return (PRT0) + } + + Method (_SRS, 1, Serialized) + { + Store ("_SRS:", Debug) + Store (Arg0, Debug) + Return (Zero) + } + } + + Name (_NPK, Package () + { + 0x1111, + 0x2222, + 0x3333, + 0x4444 + }) + + + Device (RES) + { + Name (_PRT, Package (0x04) + { + Package (0x04) + { + 0x0002FFFF, + Zero, + Zero, + Zero + }, + + Package (0x04) + { + 0x0002FFFF, + One, + Zero, + Zero + }, + + Package (0x04) + { + 0x000AFFFF, + Zero, + Zero, + Zero + }, + + Package (0x04) + { + 0x000BFFFF, + Zero, + Zero, + Zero + } + }) + + Method (_CRS, 0, Serialized) + { + Name (PRT0, ResourceTemplate () + { + WordBusNumber (ResourceConsumer, MinFixed, MaxFixed, SubDecode, + 0x0000, // Address Space Granularity + 0xFFF2, // Address Range Minimum + 0xFFF3, // Address Range Maximum + 0x0032, // Address Translation Offset + 0x0002,,,) + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x00FF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0100,,,) + WordSpace (0xC3, ResourceConsumer, PosDecode, MinFixed, MaxFixed, 0xA5, + 0x0000, // Address Space Granularity + 0xA000, // Address Range Minimum + 0xBFFF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x2000,,,) + IO (Decode16, 0x0CF8, 0x0CFF, 0x01, 0x08) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x0CF7, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0CF8,,, + , TypeStatic) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0D00, // Address Range Minimum + 0xFFFF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0xF300,,, + , TypeStatic) + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x00000000, // Address Space Granularity + 0x00000000, // Address Range Minimum + 0x00000CF7, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00000CF8,,, + , TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0x000C8000, // Address Range Minimum + 0x000EFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00028000,,, + , AddressRangeMemory, TypeStatic) + DWordSpace (0xC3, ResourceConsumer, PosDecode, MinFixed, MaxFixed, 0xA5, + 0x00000000, // Address Space Granularity + 0x000C8000, // Address Range Minimum + 0x000EFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00028000,,,) + QWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000000000000000, // Address Space Granularity + 0x0000000000000000, // Address Range Minimum + 0x0000000000000CF7, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x0000000000000CF8, 0x44, "This is a ResouceSource string", + , TypeStatic) + QWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000000000000000, // Address Space Granularity + 0x0000000000000000, // Address Range Minimum + 0x0000000000000CF7, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x0000000000000CF8,,, + , TypeStatic) + QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x0000000000000000, // Address Space Granularity + 0x0000000000100000, // Address Range Minimum + 0x00000000FFDFFFFF, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x00000000FFD00000,,, + , AddressRangeMemory, TypeStatic) + QWordSpace (0xC3, ResourceConsumer, PosDecode, MinFixed, MaxFixed, 0xA5, + 0x0000000000000000, // Address Space Granularity + 0x0000000000000000, // Address Range Minimum + 0x0000000000000CF7, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x0000000000000CF8,,,) + ExtendedIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000000000000000, // Address Space Granularity + 0x0000000000000000, // Address Range Minimum + 0x0000000000000CF7, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x0000000000000CF8, // Address Length + 0x0000000000000000, // Type Specific Attributes + , TypeStatic) + ExtendedMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x0000000000000000, // Address Space Granularity + 0x0000000000100000, // Address Range Minimum + 0x00000000FFDFFFFF, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x00000000FFD00000, // Address Length + 0x0000000000000000, // Type Specific Attributes + , AddressRangeMemory, TypeStatic) + ExtendedSpace (0xC3, ResourceProducer, PosDecode, MinFixed, MaxFixed, 0xA3, + 0x0000000000000000, // Address Space Granularity + 0x0000000000100000, // Address Range Minimum + 0x00000000FFDFFFFF, // Address Range Maximum + 0x0000000000000000, // Address Translation Offset + 0x00000000FFD00000, // Address Length + 0x0000000000000000) // Type Specific Attributes + IO (Decode16, 0x0010, 0x0020, 0x01, 0x10) + IO (Decode16, 0x0090, 0x00A0, 0x01, 0x10) + FixedIO (0x0061, 0x01) + IRQNoFlags () {2} + DMA (Compatibility, BusMaster, Transfer8_16) {4} + DMA (Compatibility, BusMaster, Transfer8) {2,5,7} + Memory32Fixed (ReadWrite, 0x00100000, 0x00000000) + Memory32Fixed (ReadOnly, 0xFFFE0000, 0x00020000) + Memory32 (ReadOnly, 0x00020000, 0xFFFE0000, 0x00000004, 0x00000200) + Memory24 (ReadOnly, 0x1111, 0x2222, 0x0004, 0x0200) + Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive, 0xE, "\\_SB_.TEST") + { + 0x00000E01, + } + Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, 0x6, "xxxx") + { + 0x00000601, + 0x00000003, + 0x00000002, + 0x00000001, + } + Interrupt (ResourceProducer, Edge, ActiveHigh, Exclusive) + { + 0xFFFF0000, + 0x00000003, + 0x00000002, + 0x00000001, + 0x00000005, + 0x00000007, + 0x00000009, + } + VendorShort () {0x01, 0x02, 0x03} + VendorLong () + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09 + } + Register (SystemIO, 0x08, 0x00, 0x00000000000000B2, , R000) + Register (SystemMemory, 0x08, 0x00, 0x00000000000000B2) + StartDependentFnNoPri () + { + IRQNoFlags () {0,1,2} + IRQ (Level, ActiveLow, Shared) {3,4,5,6,7,9,10,11,14,15} + } + EndDependentFn () + }) + CreateWordField (PRT0, 0x08, BMIN) + CreateByteField (PRT0, R000._ASZ, RSIZ) + Store (0x03, BMIN) + Return (PRT0) + } + + Method (_PRS, 0, Serialized) + { + Name (BUF0, ResourceTemplate () + { + StartDependentFn (0x01, 0x02) + { + IO (Decode16, 0x03D8, 0x03F8, 0x01, 0x08) + IRQNoFlags () {4} + } + StartDependentFn (0x02, 0x01) + { + IO (Decode16, 0x03D8, 0x03E8, 0x01, 0x08) + IRQNoFlags () {4} + } + StartDependentFn (0x00, 0x02) + { + IO (Decode16, 0x02E8, 0x02F8, 0x01, 0x08) + IRQNoFlags () {3} + } + StartDependentFn (0x00, 0x02) + { + IO (Decode16, 0x02D8, 0x02E8, 0x01, 0x08) + IRQNoFlags () {3} + } + StartDependentFn (0x02, 0x00) + { + IO (Decode16, 0x0100, 0x03F8, 0x08, 0x08) + IRQNoFlags () {1,3,4,5,6,7,8,10,11,12,13,14,15} + } + EndDependentFn () + }) + Return (BUF0) + } + + Method (_SRS, 1, Serialized) + { + Return (Zero) + } + } + + + Name(\_S0,Package(0x04){ + 0x00, + 0x00, + 0x00, + 0x00 + }) + Name(\_S3,Package(0x04){ + 0x05, + 0x05, + 0x00, + 0x00 + }) + Name(\_S4,Package(0x04){ + 0x06, + 0x06, + 0x00, + 0x00 + }) + Name(\_S5,Package(0x04){ + 0x07, + 0x07, + 0x00, + 0x00 + }) + +/* Examine this table header (DSDT) */ + +/* + DataTableRegion (HDR, "DSDT", "", "") + Field (HDR, AnyAcc, NoLock, Preserve) + { + SIG, 32, + LENG, 32, + REV, 8, + SUM, 8, + OID, 48, + OTID, 64, + OREV, 32, + CID, 32, + CREV, 32 + } + + Method (SIZE) + { + If (LLess (REV, 2)) + { + Store ("32-bit table", Debug) + } + else + { + Store ("64-bit table", Debug) + } + Return (0) + } + +*/ + Name (SIZE, 0) + + /* Custom operation region */ + + OperationRegion(MYOP,0x80,0xFD60,0x6) + Field(MYOP,ByteAcc,NoLock,Preserve) + { + MFLD,8 + } + + Method (TCOP,, Serialized) + { + Name (_STR, Unicode ("test")) + Store (4, MFLD) + Store (MFLD, Local0) + } + + Name (ERRS, 0x0) + + /* Warning should be issued for premature string termination */ + + NAME (ESC1, "abcdefg\x00hijklmn") + NAME (ESC2, "abcdefg\000hijklmn") + Name (ESC3, "abc\a\bdef\f\n\r\t\v\x03ffff\432") + + + Name(CRSA,ResourceTemplate() + { + WORDBusNumber(ResourceProducer,MinFixed,MaxFixed,PosDecode,0x0000,0x0019,0x001D,0x0000,0x0005) + WORDIO(ResourceProducer,MinFixed,MaxFixed,PosDecode,NonISAOnlyRanges,0x0000,0xC000,0xCFFF,0x0000,0x1000) + DWORDMemory(ResourceProducer,PosDecode,MinFixed,MaxFixed,NonCacheable,ReadWrite,0x00000000,0xD8000000,0xDBFFFFFF,0x00000000,0x04000000) + + }) + Name(CRSB,ResourceTemplate() + { + DWORDMemory(ResourceProducer,PosDecode,MinFixed,MaxFixed,NonCacheable,ReadWrite,0x00000000,0xD8000000,0xDBFFFFFF,0x00000000,0x04000000) + + }) + + Name(CRSC,ResourceTemplate() + { + VendorShort () {0x1, 0x2, 0x3} + }) + Name(CRSD,ResourceTemplate() + { + VendorLong (VNDL) {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9} + }) + + Name(CRSE,ResourceTemplate() + { + IRQNoFlags(){3,4,10,11} + IRQNoFlags(xxxt){3,4,10,11} + }) + Name(CRSR, Buffer (Add (SizeOf(CRSA),SizeOf(CRSB))){}) + Method(_CRS,0,NotSerialized) + { + Return(CRSR) + } + + + // + // Unnamed scope + // + Scope (\) + { + Name(Bxxx,0xFFFFFFFF) + } + + Name (LANS, 0x0) + + PowerResource(LANP,1,0) + { + Method(_STA){ + If(LEqual(And(LANS,0x30),0x30)){ + Return(One) + } Else { + Return(Zero) + } + } + Method(_ON){ + If(LNot(_STA())){ + Store (0x30, LANS) + } + } + Method(_OFF){ + If(_STA()){ + Store (0, LANS) + } + } + } + + + /* Can a method define another method? */ + + /********************************** + Method (TASK, 2, SERIALIZED) + { + Sleep (100) + + Method (TAS2) + { + Sleep (100) + } + + TAS2() + Return + + } + ************************************/ + + /* A recursive method */ + + Method (RCIV, 1) + { + Store (Arg0, Debug) + If (Lequal (Arg0, 0)) + { + Return () + } + RCIV (Subtract (Arg0, 1)) + } + + Method (RTOP) + { + RCIV (100) + } + + + Scope(\_PR) + { + Processor(CPU0,0x0,0xFFFFFFFF,0x0) {} + } + + Name(B1TP,0xFFFFFFFF) + + Name(B2TP,0xFFFFFFFF) + Name(ADPS,0xFFFFFFFF) + Name(B1PS,0xFFFFFFFF) + Name(B1RS,0xFFFFFFFF) + Name(B1CS,0xFFFFFFFF) + Name(B2PS,0xFFFFFFFF) + Name(B2RS,0xFFFFFFFF) + Name(B2CS,0xFFFFFFFF) + Name(B1DC,3000) + Name(B2DC,2600) + Name(B1LF,3000) + Name(B2LF,2600) + Name(BPIF,0) + Name(PBLL,0) + + Name(RBIF,Package() + { + 0x1, + 2200, + 2200, + 0x1, + 10800, + 0, + 0, + 1, + 1, + "CA54200-5003/5", + "1", + "LION", + "Fujitsu" + }) + + Method(SMWE, 4) + { + return(ONES) + } + + Method(SMRE, 4) + { + return(ONES) + } + +/* + Method(RDBT,0,Serialized){ + If(LNot(SMWE(0x09,0x15,1,1))){ + Store(0x18,Local2) + } + } +*/ + Scope(_SB) + { + + Name (SBUF, Buffer (128) {}) + + CreateBitField (SBUF, 3, BITY) + CreateByteField (SBUF, 1, BYTY) + CreateWordField (SBUF, 2, WRDZ) + CreateDwordField (SBUF, 4, DWDZ) + CreateQwordField (SBUF, 8, QWDZ) + CreateField (SBUF, 128, 12, FLDZ) + CreateField (SBUF, 148, 96, FLDY) + CreateField (SBUF, 148, 96, \_SB_.FLDW) + + Method (_INI) + { + CreateField (\_SB_.SBUF, 148, 96, FLDV) + } + + + Device(PCI0) + { + Name(_HID,EISAID("PNP0A03")) + Name(_ADR,0x0) + + Method(_CRS,, Serialized) + { + Name(PRT0, ResourceTemplate() { + WORDBusNumber( // Bus number resource(0) + ResourceConsumer, // bit 0 of general flags is 1 + MinFixed, // Range is notfixed + MaxFixed, // Range is not fixed + SubDecode, // SubDecode + 0x0000, // Granularity + 0xfff1, // Min + 0xfff2, // Max + 0x0032, // Translation + 0x0002,,, // Range Length + BUS0 + ) } )// PRT0 + + CreateWordField(PRT0, BUS0._MIN, BMIN) //Minimum bus number suported under this bridge. + + Store(3, BMIN) + Return(PRT0) + + } // _CRS + + Method(_SRS) + { + Return () + } + + Device(EIO) + { + OperationRegion(FJIO,SystemIO,0xFD60,0x6) + Field(FJIO,ByteAcc,NoLock,Preserve) + { + GIDX,8, + + GDTA,8, + + PIDX,8, + + PDTA,8, + + SIDX,8, + + SDTA,8 + } + IndexField(GIDX,GDTA,ByteAcc,NoLock,Preserve) + { + Offset(0x2), + ,5, + VGAS,2, + Offset(0x4), + ,4, + DCKE,1, + Offset(0x5), + ,6, + ACPW,1, + + Offset(0xA), + B1P,1, + + B2P,1, + + B1C,1, + + B2C,1, + + B1ER,1, + + B2ER,1, + + Offset(0xB), + B1CP,8, + + B2CP,8, + + BCP,8, + + B1VH,8, + + B1VL,8, + + B2VH,8, + + B2VL,8, + + B1TM,8, + + B2TM,8, + + B1CH,8, + + B1CL,8, + + B2CH,8, + + B2CL,8 + } + } + } + } + + Method(RDBT,3,Serialized){ + Store(0x1FFF,Local1) + If( Arg0 ){ + Store(0x2FFF,Local1) + } + Store(0x18,Local2) + If( Arg1 ){ + Store(0x10,Local2) + } + If(LNot(SMRE(0x09,0x15,1,RefOf(Local0)))){ + If(LNot(SMWE(0x08,0x14,1,Local1))){ + If(LNot(SMRE(0x09,0x17,Local2,RefOf(Local3)))){ + Store(Local1,Arg2) + } + } + Or(Local0,0xFFF,Local0) + SMWE(0x08,0x14,1,Local0) + } + } + Method(MKWD,2) + { + If(And(Arg1,0x80)) { + Or(0xFFFF0000,Arg0,Local0) + Or(Local0,ShiftLeft(Arg1,8),Local0) + Subtract(Zero,Local0,Local0) + } else { + Store(Arg0,Local0) + Or(Local0,ShiftLeft(Arg1,8),Local0) + } + Return(Local0) + } + + Device(CMB1) + { + Name(_HID,EISAID("PNP0C0A")) + Name(_UID,0x1) + Alias(\_SB.PCI0.EIO.B1P,\_SB_.PCI0.XXXX) + Alias(\_SB.PCI0.EIO.B1P,B1P) + Alias(\_SB.PCI0.EIO.B1C,B1C) + Alias(\_SB.PCI0.EIO.B1CH,B1CH) + Alias(\_SB.PCI0.EIO.B1CL,B1CL) + Alias(\_SB.PCI0.EIO.B1VH,B1VH) + Alias(\_SB.PCI0.EIO.B1VL,B1VL) + Alias(\_SB.PCI0.EIO.B1CP,B1CP) + + Method(_INI) + { + Store(B1P, B1PS) + Store(B1CP,B1RS) + Store(B1C, B1CS) + } + + Method(_BIF){ + RDBT(Zero,Zero,RefOf(B1DC)) + RDBT(Zero,One,RefOf(B1LF)) + Store(B1DC,Index(RBIF,1)) + Store(B1LF,Index(RBIF,2)) + Store("CA54200-5003/5",Index(RBIF,9)) + Store("1",Index(RBIF,10)) + Return(RBIF) + } + + Method(_BST,, Serialized) { + + _INI() + + Store(Zero,Local0) + + if (LAnd(B1P,LNot(B1C))){ + Or(Local0,1,Local0) + } + + if (LAnd(B1P,B1C)) { + Or(Local0,2,Local0) + } + + if (LLessEqual(B1CP,1)) { + Or(Local0,4,Local0) + } + + Store(MKWD(B1CL,B1CH),Local1) + + Store(Divide(Add(Multiply(B1CP,B1LF),99),100),Local2) + + Store(MKWD(B1VL,B1VH),Local3) + + Name(STAT,Package(4){}) + Store(Local0,Index(STAT,0)) + Store(Local1,Index(STAT,1)) + Store(Local2,Index(STAT,2)) + Store(Local3,Index(STAT,3)) + + If(LNot(BPIF)){ +// \_SB.PCI0.EIO.EC0.IECT() +// \_SB.PCI0.EIO.EC0.SECT() + Store(One,BPIF) + } + return(STAT) + } + + } + + Device (DEV1) + { + } + + Scope(\_TZ) + { + ThermalZone(TZ1) + { + Name(_PSL,Package() + { + \_PR.CPU0 + }) + } + } + + Method (TZ2, 0, SERIALIZED) + { + Name(_PSL,Package() + { + \_PR.CPU0 + }) + + Return (_PSL) + } + + ThermalZone (THM1) + { + } + + Method (NOTI) + { + Notify (\DEV1, 0) + Notify (\THM1, 0) + Notify (\_PR.CPU0, 0) + } + + Method (_ERR, 2) + { + Increment (ERRS) + Store ("Run-time exception:", Debug) + Store (Arg0, Debug) + Store (Arg1, Debug) + + Return (0) // Map error to AE_OK + } + + Method (DIV0) + { + Store (1, Local0) + Store (0, Local1) + Divide (Local0, Local1, Local3) + + Store ("DIV0 - noabort", Debug) + } + + Method (ERR_, 1) + { + if (LEqual (Arg0, 0)) + { + Store ("+*+*+*+* MTHD_ERROR: Results not equal!", Debug) + } + if (LEqual (Arg0, 1)) + { + Store ("+*+*+*+* MTHD_ERROR: Numeric result is incorrect!", Debug) + } + if (LEqual (Arg0, 2)) + { + Store ("+*+*+*+* MTHD_ERROR: Operand was clobbered!", Debug) + } + + Notify (DEV1, Arg0) + Increment (ERRS) + } + + Method (R226, 2) + { + } + Method (R225, 2) + { + R226 (Arg0, Arg1) + } + Method (R224, 2) + { + R225 (Arg1, Arg0) + } + Method (R223, 2) + { + R224 (Arg0, Arg1) + } + Method (R222, 2) + { + R223 (Arg1, Arg0) + } + Method (R111) + { + Store (0x01010101, Local0) + R222 (0xABAB, Local0) + Store (Local0, Local1) + } + + Method (MAIN) + { + +// SIZE() + Store (NUM1(), Local0) + \CMB1._BST() + RDBT(1,2,3) + OBJ1(1) + OBJ2(2) + CHEK() + RETZ() + BITZ() + LOGS() + REFS() + COND() + TZ2() + + // + // iPCO tests added + // + Store (\IFEL.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\NOSV.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\IDXF.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.NSTL.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\RTBF.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.RTLV.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.RETP.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\WHLR.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\ANDO.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\BRKP.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\ADSU.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\INDC.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\LOPS.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\FDSO.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\MLDV.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\NBIT.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\SHFT.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\XORD.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\CRBF.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\IDX4.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\EVNT.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\SZLV.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.BYTF.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\DWDF.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\DVAX.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\IDX6.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\IDX5.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.IDX0.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.IDX3.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\IDX7.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\MTCH.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\WHLB.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.IDX2.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\SIZO.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + Store (\_SB_.SMIS.TEST(), Local0) + if (LGreater (Local0, 0)) + { + ERR_ (1) + Return(Local0) + } + + if (LGreater (ERRS, 0)) + { + Store ("****** There were errors during the execution of the test ******", Debug) + } + + // Flush all notifies + + Sleep (250) + + // + // Last Test + // + + Return(0) // Success + } + + + Method (OBJ1, 1, SERIALIZED) + { + + Store (3, Local0) + Name(BUFR, Buffer (Local0) {}) + Name(BUF1, Buffer (4) {1,2,3,4}) + Name(BUF2, Buffer (4) {}) + + Store (BUF1, BUF2) + Mutex (MTX1, 4) + + Alias (MTX1, MTX2) + } + + + Mutex (MTXT, 0) + Mutex (MTXX, 0) + + /* + * Field Creation + */ + + Method (FLDS,, Serialized) + { + Store ("++++++++ Creating BufferFields", Debug) + Name (BUF2, Buffer (128) {}) + + CreateBitField (BUF2, 3, BIT2) + CreateByteField (BUF2, 1, BYT2) + CreateWordField (BUF2, 2, WRD2) + CreateDwordField (BUF2, 4, DWD2) + CreateQwordField (BUF2, 8, QWD2) + CreateField (BUF2, 128, 12, FLD2) + CreateField (BUF2, 148, 96, FLD3) + + Store (0x1, BIT2) + Store (BIT2, Local0) + if (LNotEqual (Local0, 0x1)) + { + ERR_ (1) + } + else + { + Store (DerefOf (Index (BUF2, 0)), Local0) + if (LNotEqual (Local0, 0x08)) + { + ERR_ (1) + } + else + { + Store ("++++++++ Bit BufferField I/O PASS", Debug) + } + } + + Store (0x1A, BYT2) + Store (BYT2, Local0) + if (LNotEqual (Local0, 0x1A)) + { + ERR_ (1) + } + else + { + Store ("++++++++ Byte BufferField I/O PASS", Debug) + } + + Store (0x1234, WRD2) + Store (WRD2, Local0) + if (LNotEqual (Local0, 0x1234)) + { + ERR_ (1) + } + else + { + Store ("++++++++ Word BufferField I/O PASS", Debug) + } + + Store (0x123, FLD2) + Store (FLD2, Local0) + if (LNotEqual (Local0, 0x123)) + { + ERR_ (1) + } + else + { + Store ("++++++++ 12-bit BufferField I/O PASS", Debug) + } + + Store (0x12345678, DWD2) + Store (DWD2, Local0) + if (LNotEqual (Local0, 0x12345678)) + { + ERR_ (1) + } + else + { + Store ("++++++++ Dword BufferField I/O PASS", Debug) + } + + Store (0x1234567887654321, QWD2) + Store (QWD2, Local0) + if (LNotEqual (Local0, 0x1234567887654321)) + { + ERR_ (1) + } + else + { + Store ("++++++++ Qword BufferField I/O PASS", Debug) + } + } + + + /* Field execution */ + + Method (FLDX,, Serialized) + { + Field (\_SB_.MEM.SMEM, AnyAcc, NoLock, Preserve) + { // Field: SMEM overlay using 32-bit field elements + SMD0, 32, // 32-bits + SMD1, 32, // 32-bits + SMD2, 32, // 32-bits + SMD3, 32 // 32-bits + } // Field: SMEM overlay using 32-bit field elements + Field (\_SB_.MEM.SMEM, AnyAcc, NoLock, Preserve) + { // Field: SMEM overlay using greater than 32-bit field elements + SME0, 69, // larger than an integer (32 or 64) + SME1, 97 // larger than an integer + } // Field: SMEM overlay using greater than 32-bit field elements + } + + + Method (MTX_, ) + { + /* Test "Force release" of mutex on method exit */ + + Acquire (MTXT, 0xFFFF) + Acquire (MTXX, 0xFFFF) + + Store ("++++++++ Acquiring Mutex MTX2", Debug) + Acquire (_GL_, 0xFFFF) + + + Store ("++++++++ Releasing Mutex MTX2", Debug) + Release (_GL_) + } + + + Method (OBJ2, 1, Serialized) + { + Store ("++++++++ Creating Buffer BUFO", Debug) + Name (BUFO, Buffer (32) {}) + + Store ("++++++++ Creating OpRegion OPR2", Debug) + OperationRegion (OPR2, SystemMemory, Arg0, 256) + + Store ("++++++++ Creating Field(s) in OpRegion OPR2", Debug) + Field (OPR2, ByteAcc, NoLock, Preserve) + { + IDX2, 8, + DAT2, 8, + BNK2, 4 + } + + Store ("++++++++ Creating BankField BNK2 in OpRegion OPR2", Debug) + // + // mcw 3/20/00 - changed FET0, 4, FET1, 3 to FET0, 1, FET1, 1 + // + BankField (OPR2, BNK2, 0, ByteAcc, NoLock, Preserve) + { + FET0, 4, + FET1, 3 + } + + Store ("++++++++ Creating IndexField", Debug) + IndexField (IDX2, DAT2, ByteAcc, NoLock, Preserve) + { + FET2, 4, + FET3, 3 + } + + Store ("++++++++ SizeOf (BUFO)", Debug) + SizeOf (BUFO) + + Store ("++++++++ Store (SizeOf (BUFO), Local0)", Debug) + Store (SizeOf (BUFO), Local0) + + Store ("++++++++ Concatenate (\"abd\", \"def\", Local0)", Debug) + Concatenate ("abd", "def", Local0) + Store (Local0, Debug) + + Store ("++++++++ Concatenate (\"abd\", 0x7B, Local0)", Debug) + Concatenate ("abd", 0x7B, Local0) + Store (Local0, Debug) + + Store ("++++++++ Creating Event EVT2", Debug) + Event (EVT2) + + Store ("++++++++ Creating Mutex MTX2", Debug) + Mutex (MTX2, 0) + + Store ("++++++++ Creating Alias MTXA to MTX2", Debug) + Alias (MTX2, MTXA) + + Store ("++++++++ Acquiring Mutex MTX2", Debug) + Acquire (MTX2, 0xFFFF) + + Store ("++++++++ Acquiring Mutex MTX2 (2nd acquire)", Debug) + Acquire (MTX2, 1) + + Store ("++++++++ Releasing Mutex MTX2", Debug) + Release (MTX2) + + // Type 1 opcodes + + Store ("++++++++ Signalling Event EVT2", Debug) + Signal (EVT2) + + Store ("++++++++ Resetting Event EVT2", Debug) + Reset (EVT2) + + Store ("++++++++ Signalling Event EVT2", Debug) + Signal (EVT2) + + Store ("++++++++ Waiting Event EVT2", Debug) + Wait (EVT2, 0xFFFF) + + Store ("++++++++ Sleep", Debug) + Sleep (100) + + Store ("++++++++ Stall", Debug) + Stall (254) + + Store ("++++++++ NoOperation", Debug) + Noop + + // Type 2 Opcodes + + Store ("++++++++ Return from Method OBJ2", Debug) + return (4) + } + + + Method (NUM1, 0) + { + /* ADD */ + + Store ("++++++++ Add (0x12345678, 0x11111111, Local0)", Debug) + Add (0x12345678, 0x11111111, Local0) + + Store ("++++++++ Store (Add (0x12345678, 0x11111111), Local1)", Debug) + Store (Add (0x12345678, 0x11111111), Local1) + + Store ("++++++++ Checking result from ADD", Debug) + if (LNotEqual (Local0, Local1)) + { + ERR_ (0) + } + + + /* SUBTRACT */ + + Store ("++++++++ Subtract (0x87654321, 0x11111111, Local4)", Debug) + Subtract (0x87654321, 0x11111111, Local4) + + Store ("++++++++ Store (Subtract (0x87654321, 0x11111111), Local5)", Debug) + Store (Subtract (0x87654321, 0x11111111), Local5) + + Store ("++++++++ Checking result from SUBTRACT", Debug) + if (LNotEqual (Local4, Local5)) + { + ERR_ (0) + } + + + /* MULTIPLY */ + + Store ("++++++++ Multiply (33, 10, Local6)", Debug) + Multiply (33, 10, Local6) + + Store ("++++++++ Store (Multiply (33, 10), Local7)", Debug) + Store (Multiply (33, 10), Local7) + + + Store ("++++++++ Checking result from MULTIPLY", Debug) + if (LNotEqual (Local6, Local7)) + { + ERR_ (0) + } + + + /* DIVIDE */ + + Store ("++++++++ Divide (100, 9, Local1, Local2)", Debug) + Divide (100, 9, Local1, Local2) + + Store ("++++++++ Store (Divide (100, 9), Local3)", Debug) + Store (Divide (100, 9), Local3) + + Store ("++++++++ Checking (quotient) result from DIVIDE", Debug) + if (LNotEqual (Local2, Local3)) + { + ERR_ (0) + } + + + /* INCREMENT */ + + Store ("++++++++ Increment (Local0)", Debug) + Store (1, Local0) + Store (2, Local1) + Increment (Local0) + + Store ("++++++++ Checking result from INCREMENT", Debug) + if (LNotEqual (Local0, Local1)) + { + ERR_ (0) + } + + + /* DECREMENT */ + + Store ("++++++++ Decrement (Local0)", Debug) + Store (2, Local0) + Store (1, Local1) + Decrement (Local0) + + Store ("++++++++ Checking result from DECREMENT", Debug) + if (LNotEqual (Local0, Local1)) + { + ERR_ (0) + } + + + /* TOBCD */ + /* FROMBCD */ + + Store ("++++++++ ToBCD (0x1234, Local5)", Debug) + ToBCD (0x1234, Local5) + + Store ("++++++++ FromBCD (Local5, Local6)", Debug) + FromBCD (Local5, Local6) + + Store ("++++++++ Return (Local6)", Debug) + Return (Local6) + } + + + Method (CHEK) + { + + Store (3, Local0) + Store (3, Debug) + Store (Local0, Debug) + Store (7, Local1) + + Add (Local0, Local1) + if (LNotEqual (Local0, 3)) + { + ERR_ (2) + } + if (LNotEqual (Local1, 7)) + { + ERR_ (2) + } + + + Add (Local0, Local1, Local2) + if (LNotEqual (Local0, 3)) + { + ERR_ (2) + } + if (LNotEqual (Local1, 7)) + { + ERR_ (2) + } + } + + + Method (RET1) + { + Store (3, Local0) + Return (Local0) + } + + Method (RET2) + { + Return (RET1()) + } + + Method (RETZ) + { + RET2 () + } + + + Method (BITZ) + { + Store ("++++++++ FindSetLeftBit (0x00100100, Local0)", Debug) + FindSetLeftBit (0x00100100, Local0) + if (LNotEqual (Local0, 21)) + { + ERR_ (1) + } + + Store ("++++++++ FindSetRightBit (0x00100100, Local1)", Debug) + FindSetRightBit (0x00100100, Local1) + if (LNotEqual (Local1, 9)) + { + ERR_ (1) + } + + Store ("++++++++ And (0xF0F0F0F0, 0x11111111, Local2)", Debug) + And (0xF0F0F0F0, 0x11111111, Local2) + if (LNotEqual (Local2, 0x10101010)) + { + ERR_ (1) + } + + Store ("++++++++ NAnd (0xF0F0F0F0, 0x11111111, Local3)", Debug) + NAnd (0xF0F0F0F0, 0x11111111, Local3) + if (LNotEqual (Local3, 0xEFEFEFEF)) + { + ERR_ (1) + } + + Store ("++++++++ Or (0x11111111, 0x22222222, Local4)", Debug) + Or (0x11111111, 0x22222222, Local4) + if (LNotEqual (Local4, 0x33333333)) + { + ERR_ (1) + } + + Store ("++++++++ NOr (0x11111111, 0x22222222, Local5)", Debug) + NOr (0x11111111, 0x22222222, Local5) + if (LNotEqual (Local5, 0xCCCCCCCC)) + { + ERR_ (1) + } + + Store ("++++++++ XOr (0x11113333, 0x22222222, Local6)", Debug) + XOr (0x11113333, 0x22222222, Local6) + if (LNotEqual (Local6, 0x33331111)) + { + ERR_ (1) + } + + Store ("++++++++ ShiftLeft (0x11112222, 2, Local7)", Debug) + ShiftLeft (0x11112222, 2, Local7) + if (LNotEqual (Local7, 0x44448888)) + { + ERR_ (1) + } + + Store ("++++++++ ShiftRight (Local7, 2, Local7)", Debug) + ShiftRight (Local7, 2, Local7) + if (LNotEqual (Local7, 0x11112222)) + { + ERR_ (1) + } + + + Store ("++++++++ Not (Local0, Local1)", Debug) + Store (0x22224444, Local0) + Not (Local0, Local1) + if (LNotEqual (Local0, 0x22224444)) + { + ERR_ (2) + } + + if (LNotEqual (Local1, 0xDDDDBBBB)) + { + ERR_ (1) + } + + Return (Local7) + } + + + Method (LOGS) + { + + Store ("++++++++ Store (LAnd (0xFFFFFFFF, 0x11111111), Local0)", Debug) + Store (LAnd (0xFFFFFFFF, 0x11111111), Local0) + + Store ("++++++++ Store (LEqual (0xFFFFFFFF, 0x11111111), Local)", Debug) + Store (LEqual (0xFFFFFFFF, 0x11111111), Local1) + + Store ("++++++++ Store (LGreater (0xFFFFFFFF, 0x11111111), Local2)", Debug) + Store (LGreater (0xFFFFFFFF, 0x11111111), Local2) + + Store ("++++++++ Store (LGreaterEqual (0xFFFFFFFF, 0x11111111), Local3)", Debug) + Store (LGreaterEqual (0xFFFFFFFF, 0x11111111), Local3) + + Store ("++++++++ Store (LLess (0xFFFFFFFF, 0x11111111), Local4)", Debug) + Store (LLess (0xFFFFFFFF, 0x11111111), Local4) + + Store ("++++++++ Store (LLessEqual (0xFFFFFFFF, 0x11111111), Local5)", Debug) + Store (LLessEqual (0xFFFFFFFF, 0x11111111), Local5) + + Store ("++++++++ Store (LNot (0x31313131), Local6)", Debug) + Store (0x00001111, Local6) + Store (LNot (Local6), Local7) + if (LNotEqual (Local6, 0x00001111)) + { + ERR_ (2) + } + + if (LNotEqual (Local7, 0x0)) + { + ERR_ (1) + } + + + Store ("++++++++ Store (LNotEqual (0xFFFFFFFF, 0x11111111), Local7)", Debug) + Store (LNotEqual (0xFFFFFFFF, 0x11111111), Local7) + + Store ("++++++++ Lor (0x0, 0x1)", Debug) + if (Lor (0x0, 0x1)) + { + Store ("+_+_+_+_+ Lor (0x0, 0x1) returned TRUE", Debug) + } + + return (Local7) + } + + + Method (COND) + { + Store ("++++++++ Store (0x4, Local0)", Debug) + Store (0x4, Local0) + + Store ("++++++++ While (Local0)", Debug) + While (Local0) + { + Store ("++++++++ Decrement (Local0)", Debug) + Decrement (Local0) + } + + + Store ("++++++++ Store (0x3, Local6)", Debug) + Store (0x3, Local6) + + Store ("++++++++ While (Subtract (Local6, 1))", Debug) + While (Subtract (Local6, 1)) + { + Store ("++++++++ Decrement (Local6)", Debug) + Decrement (Local6) + } + + + Store ("++++++++ [LVL1] If (LGreater (0x2, 0x1))", Debug) + If (LGreater (0x2, 0x1)) + { + Store ("++++++++ [LVL2] If (LEqual (0x11111111, 0x22222222))", Debug) + If (LEqual (0x11111111, 0x22222222)) + { + Store ("++++++++ ERROR: If (LEqual (0x11111111, 0x22222222)) returned TRUE", Debug) + } + + else + { + Store ("++++++++ [LVL3] If (LNot (0x0))", Debug) + If (LNot (0x0)) + { + Store ("++++++++ [LVL4] If (LAnd (0xEEEEEEEE, 0x2))", Debug) + If (LAnd (0xEEEEEEEE, 0x2)) + { + Store ("++++++++ [LVL5] If (LLess (0x44444444, 0x3))", Debug) + If (LLess (0x44444444, 0x3)) + { + Store ("++++++++ ERROR: If (LLess (0x44444444, 0x3)) returned TRUE", Debug) + } + + else + { + Store ("++++++++ Exiting from nested IF/ELSE statements", Debug) + } + } + } + } + } + + + Store ("++++++++ [LVL1] If (LGreater (0x2, 0x1))", Debug) + If (LGreater (0x2, 0x1)) + { + Store ("++++++++ [LVL2] If (LEqual (0x11111111, 0x22222222))", Debug) + If (LEqual (0x11111111, 0x22222222)) + { + Store ("++++++++ ERROR: If (LEqual (0x11111111, 0x22222222)) returned TRUE", Debug) + } + + else + { + Store ("++++++++ [LVL3] If (LNot (0x0))", Debug) + If (LNot (0x0)) + { + Store ("++++++++ [LVL4] If (LAnd (0xEEEEEEEE, 0x2))", Debug) + If (LAnd (0xEEEEEEEE, 0x2)) + { + Store ("++++++++ [LVL5] If (LLess (0x44444444, 0x3))", Debug) + If (LLess (0x44444444, 0x3)) + { + Store ("++++++++ ERROR: If (LLess (0x44444444, 0x3)) returned TRUE", Debug) + } + + else + { + Store ("++++++++ Returning from nested IF/ELSE statements", Debug) + Return (Local6) + } + } + } + } + } + + } + + + Method (REFS,, Serialized) + { + Name (BBUF, Buffer() {0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7}) + + Name (NEST, Package () + { + Package () + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 + }, + Package () + { + 0x11, 0x12, 0x12, 0x14, 0x15, 0x16 + } + }) + + Store (RefOf (MAIN), Local5) + + // For this to work, ABCD must NOT exist. + + Store (CondRefOf (ABCD, Local0), Local1) + if (LNotEqual (Local1, 0)) + { + ERR_ (2) + } + + Store (CondRefOf (BBUF, Local0), Local1) + if (LNotEqual (Local1, Ones)) + { + ERR_ (2) + } + + Store (DeRefOf (Index (BBUF, 3)), Local6) + if (LNotEqual (Local6, 0xB3)) + { + ERR_ (2) + } + + Store (DeRefOf (Index (DeRefOf (Index (NEST, 1)), 3)), Local0) + if (LNotEqual (Local0, 0x14)) + { + ERR_ (2) + } + + + Store (0x11223344, Local0) + Store (RefOf (Local0), Local1) + + Store (DerefOf (Local1), Local2) + If (LNotEqual (Local2, 0x11223344)) + { + ERR_ (2) + } + + + /* Parser thinks this is a method invocation!! */ + + // RefOf (MAIN) + + + // RefOf (R___) + // RefOf (BBUF) + + // Store (RefOf (Local0), Local1) + + // CondRefOf (BBUF, Local2) + // CondRefOf (R___, Local3) + + // Store (DerefOf (Local1), Local4) + + // Return (Local4) + } + + + Method (INDX, 0, Serialized) + { + Name(STAT,Package(4){}) + Store(0x44443333,Index(STAT,0)) + } + +//================================================================= +//================================================================= +//===================== iPCO TESTS ================================ +//================================================================= +//================================================================= +// +// +// test IfElseOp.asl +// +// test for IfOp and ElseOp, including validation of object stack cleanup +// + Device (IFEL) + { + Name (DWRD, 1) + Name (RSLT, 0) + + // IFNR control method executes IfOp branch with NO nested Return + // and no Else branch + Method (IFNR) + { + Store (DWRD, RSLT) + If (LEqual (DWRD, 1)) + { + Store (0, RSLT) + } + } // IFNR + + // NINR control method does not execute If branch and has no Else branch + Method (NINR) + { + Store (0, RSLT) + If (LNotEqual (DWRD, 1)) + { + Store (DWRD, RSLT) + } + } // NINR + + // IENR control method executes IfOp branch with NO nested Return + Method (IENR) + { + If (LEqual (DWRD, 1)) + { + Store (0, RSLT) + } + Else + { + Store (DWRD, RSLT) + } + } // IENR + + // ELNR control method executes ElseOp branch with NO nested Return + Method (ELNR) + { + If (LNotEqual (DWRD, 1)) + { + Store (DWRD, RSLT) + } + Else + { + Store (0, RSLT) + } + } // ELNR + + // IFRT control method executes IfOp branch with nested Return with + // no Else branch + Method (IFRT) + + { + If (LEqual (DWRD, 1)) + { + Return (0) + } + Return (DWRD) + } // IFRT + + // IERT control method executes IfOp branch with nested Return with + // Else branch + Method (IERT) + { + If (LEqual (DWRD, 1)) + { + Return (0) + } + Else + { + Return (DWRD) + } + } // IERT + + // ELRT control method executes ElseOp branch with nested Return + Method (ELRT) + { + If (LNotEqual (DWRD, 1)) + { + Return (DWRD) + } + Else + { + Return (0) + } + } // ELRT + + Method (TEST) + { + Store ("++++++++ IfElseOp Test", Debug) + + // IfOp with NO return value + IFNR() + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + // IfOp with NO return value + NINR() + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + // IfOp with NO return value + IENR() + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + // ElseOp with NO return value + ELNR() + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + // IfOp with return value + Store (IFRT, RSLT) + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + // IfOp with return value + Store (IERT, RSLT) + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + // ElseOp with return value + Store (ELRT, RSLT) + If (LNotEqual (RSLT, 0)) + { + Return (RSLT) + } + + Return (0) + } // TEST + } // IFEL + +// +// test NoSave.asl +// +// +// Internal test cases to validate IfOp (Operator (,,)) where Operator +// target is ZeroOp to throw away the results. +// Includes internal test cases for logical operators with no destination +// operands. +// + Device (NOSV) + { + Method (TEST,, Serialized) + { + Store ("++++++++ NoSave Test", Debug) + + Name (WRD, 0x1234) + + // + // Begin test of nested operators without saving results + // + + // Test If (And ()) with no save of And result + If (And (3, 1, )) + { + Store (1, WRD) // pass -- just do something + } + else + { + Return (1) // fail + } + + // Test If (And ()) with no save of And result + If (And (4, 1, )) + { + Return (2) // fail + } + else + { + Store (2, WRD) // pass -- just do something + } + + + // Test If (NAnd ()) with no save of NAnd result + If (NAnd (3, 1, )) + { + Store (3, WRD) // pass -- just do something + } + else + { + Return (3) // fail + } + + // Test If (NAnd ()) with no save of NAnd result + If (NAnd (0xFFFFFFFF, 0xFFFFFFFF, )) + { + Return (4) // fail + } + else + { + Store (4, WRD) // pass -- just do something + } + + + // Test If (NOr ()) with no save of NOr result + If (NOr (0, 1, )) + { + Store (5, WRD) // pass -- just do something + } + else + { + Return (5) // fail + } + + // Test If (NOr ()) with no save of NOr result + If (NOr (0xFFFFFFFE, 1, )) + { + Return (6) // fail + } + else + { + Store (6, WRD) // pass -- just do something + } + + + // Test If (Not ()) with no save of Not result + If (Not (1, )) + { + Store (7, WRD) // pass -- just do something + } + else + { + Return (7) // fail + } + + // Test If (Not ()) with no save of Not result + If (Not (0xFFFFFFFF, )) + { + Return (8) // fail + } + else + { + Store (8, WRD) // pass -- just do something + } + + + // Test If (Or ()) with no save of Or result + If (Or (3, 1, )) + { + Store (9, WRD) // pass -- just do something + } + else + { + Return (9) // fail + } + + // Test If (Or ()) with no save of Or result + If (Or (0, 0, )) + { + Return (10) // fail + } + else + { + Store (10, WRD) // pass -- just do something + } + + + // Test If (XOr ()) with no save of XOr result + If (XOr (3, 1, )) + { + Store (11, WRD) // pass -- just do something + } + else + { + Return (11) // fail + } + + // Test If (XOr ()) with no save of XOr result + If (XOr (3, 3, )) + { + Return (12) // fail + } + else + { + Store (12, WRD) // pass -- just do something + } + + + // + // Begin test of logical operators with no destination operands + // + + // Test If (LAnd ()) with no save of LAnd result + If (LAnd (3, 3)) + { + Store (21, WRD) // pass -- just do something + } + else + { + Return (21) // fail + } + + // Test If (LAnd ()) with no save of LAnd result + If (LAnd (3, 0)) + { + Return (22) // fail + } + else + { + Store (22, WRD) // pass -- just do something + } + + // Test If (LAnd ()) with no save of LAnd result + If (LAnd (0, 3)) + { + Return (23) // fail + } + else + { + Store (23, WRD) // pass -- just do something + } + + // Test If (LAnd ()) with no save of LAnd result + If (LAnd (0, 0)) + { + Return (24) // fail + } + else + { + Store (24, WRD) // pass -- just do something + } + + + // Test If (LEqual ()) with no save of LEqual result + If (LEqual (3, 3)) + { + Store (31, WRD) // pass -- just do something + } + else + { + Return (31) // fail + } + + // Test If (LEqual ()) with no save of LEqual result + If (LEqual (1, 3)) + { + Return (32) // fail + } + else + { + Store (32, WRD) // pass -- just do something + } + + + // Test If (LGreater ()) with no save of LGreater result + If (LGreater (3, 1)) + { + Store (41, WRD) // pass -- just do something + } + else + { + Return (41) // fail + } + + // Test If (LGreater ()) with no save of LGreater result + If (LGreater (4, 4)) + { + Return (42) // fail + } + else + { + Store (42, WRD) // pass -- just do something + } + + // Test If (LGreater ()) with no save of LGreater result + If (LGreater (1, 4)) + { + Return (43) // fail + } + else + { + Store (43, WRD) // pass -- just do something + } + + // Test If (LGreaterEqual ()) with no save of LGreaterEqual result + If (LGreaterEqual (3, 1)) + { + Store (44, WRD) // pass -- just do something + } + else + { + Return (44) // fail + } + + // Test If (LGreaterEqual ()) with no save of LGreaterEqual result + If (LGreaterEqual (3, 3)) + { + Store (45, WRD) // pass -- just do something + } + else + { + Return (45) // fail + } + + // Test If (LGreaterEqual ()) with no save of LGreaterEqual result + If (LGreaterEqual (3, 4)) + { + Return (46) // fail + } + else + { + Store (46, WRD) // pass -- just do something + } + + + // Test If (LLess ()) with no save of LLess result + If (LLess (1, 3)) + { + Store (51, WRD) // pass -- just do something + } + else + { + Return (51) // fail + } + + // Test If (LLess ()) with no save of LLess result + If (LLess (2, 2)) + { + Return (52) // fail + } + else + { + Store (52, WRD) // pass -- just do something + } + + // Test If (LLess ()) with no save of LLess result + If (LLess (4, 2)) + { + Return (53) // fail + } + else + { + Store (53, WRD) // pass -- just do something + } + + + // Test If (LLessEqual ()) with no save of LLessEqual result + If (LLessEqual (1, 3)) + { + Store (54, WRD) // pass -- just do something + } + else + { + Return (54) // fail + } + + // Test If (LLessEqual ()) with no save of LLessEqual result + If (LLessEqual (2, 2)) + { + Store (55, WRD) // pass -- just do something + } + else + { + Return (55) // fail + } + + // Test If (LLessEqual ()) with no save of LLessEqual result + If (LLessEqual (4, 2)) + { + Return (56) // fail + } + else + { + Store (56, WRD) // pass -- just do something + } + + + // Test If (LNot ()) with no save of LNot result + If (LNot (0)) + { + Store (61, WRD) // pass -- just do something + } + else + { + Return (61) // fail + } + + // Test If (LNot ()) with no save of LNot result + If (LNot (1)) + { + Return (62) // fail + } + else + { + Store (62, WRD) // pass -- just do something + } + + + // Test If (LNotEqual ()) with no save of LNotEqual result + If (LNotEqual (3, 3)) + { + Return (63) // fail + } + else + { + Store (63, WRD) // pass -- just do something + } + + // Test If (LNotEqual ()) with no save of LNotEqual result + If (LNotEqual (1, 3)) + { + Store (64, WRD) // pass -- just do something + } + else + { + Return (64) // fail + } + + + // Test If (LOr ()) with no save of LOr result + If (LOr (3, 1)) + { + Store (71, WRD) // pass -- just do something + } + else + { + Return (71) // fail + } + + // Test If (LOr ()) with no save of LOr result + If (LOr (0, 1)) + { + Store (72, WRD) // pass -- just do something + } + else + { + Return (72) // fail + } + + // Test If (LOr ()) with no save of LOr result + If (LOr (3, 0)) + { + Store (73, WRD) // pass -- just do something + } + else + { + Return (73) // fail + } + + // Test If (LOr ()) with no save of LOr result + If (LOr (0, 0)) + { + Return (74) // fail + } + else + { + Store (74, WRD) // pass -- just do something + } + + Return (0) + } // TEST + } // NOSV + + +// +// test IndxFld.asl +// +// IndexFld test +// This is just a subset of the many RegionOp/Index Field test cases. +// Tests index field element AccessAs macro. +// + Device (IDXF) + { // Test device name + + OperationRegion (SIO, SystemIO, 0x100, 2) + Field (SIO, ByteAcc, NoLock, Preserve) + { + INDX, 8, + DATA, 8 + } + IndexField (INDX, DATA, AnyAcc, NoLock, WriteAsOnes) + { + AccessAs (ByteAcc, 0), + IFE0, 8, + IFE1, 8, + IFE2, 8, + IFE3, 8, + IFE4, 8, + IFE5, 8, + IFE6, 8, + IFE7, 8, + IFE8, 8, + IFE9, 8, + } + + Method (TEST) + { + Store ("++++++++ IndxFld Test", Debug) + + Store (IFE0, Local0) + Store (IFE1, Local1) + Store (IFE2, Local2) + + Return (0) + } // TEST + } // IDXF + +// +// test NestdLor.asl +// + Scope (\_SB) // System Bus + { // _SB system bus + + Name (ZER0, 0) + Name (ZER1, 0) + Name (ZER2, 0) + Name (ONE0, 1) + + Device (NSTL) + { + Method (TEST) + { + Store ("++++++++ NestdLor Test", Debug) + + If (Lor (ZER0, Lor (ZER1, Lor (ZER2, ONE0)))) + { // Indicate Pass + Store (0x00, Local0) + } + + Else + { // Indicate Fail + Store (0x01, Local0) + } + + Return (Local0) + } // End Method TEST + } // Device NSTL + } // _SB system bus + +// +// test RetBuf.asl +// +// Test ReturnOp(Buffer) +// This is required to support Control Method Batteries on +// Dell Latitude Laptops (e.g., CP1-A) +// + Device (RTBF) + { + Method (SUBR, 1) + { + Return (Arg0) + } + + Method (RBUF,, Serialized) + { // RBUF: Return Buffer from local variable + Name (ABUF, Buffer() {"ARBITRARY_BUFFER"}) + + // store local buffer ABUF into Local0 + Store (ABUF, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Buffer + If (LNotEqual (Local1, 3)) // Buffer type is 3 + { + Return (1) // failure + } + + // store value returned by control method SUBR into Local0 + Store (SUBR (ABUF), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Buffer + If (LNotEqual (Local1, 3)) // Buffer type is 3 + { + Return (2) // failure + } + + // allocate buffer using Local1 as buffer size (run-time evaluation) + Store (5, Local1) + Name (BUFR, Buffer(Local1) {}) + + // store value returned by control method SUBR into Local0 + Store (SUBR (BUFR), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Buffer + If (LNotEqual (Local1, 3)) // Buffer type is 3 + { + Return (3) // failure + } + + // store BUFR Buffer into Local0 + Store (BUFR, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Buffer + If (LNotEqual (Local1, 3)) // Buffer type is 3 + { + Return (4) // failure + } + + + // return Local0 Buffer + Return (Local0) + } // RBUF + + Method (TEST) + { + Store ("++++++++ RetBuf Test", Debug) + + // store RBUF Buffer return value into Local0 + Store (RBUF, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Buffer + If (LNotEqual (Local1, 3)) // Buffer type is 3 + { + Return (10) // failure + } + Else + { + Return (0) // success + } + } // TEST + } // RTBF + +// +// test RetLVal.asl +// +// Test ReturnOp(Lvalue) +// This is required to support _PSR on IBM ThinkPad 560D and +// _DCK on Toshiba Tecra 8000. +// + + Device (GPE2) + { + Method (_L03) + { + Store ("Method GPE2._L03 invoked", Debug) + Return () + } + + Method (_E05) + { + Store ("Method GPE2._E05 invoked", Debug) + Return () + } + } + + Device (PRW2) + { + Name (_PRW, Package(2) {Package(2){\GPE2, 0x05}, 3}) + } + + + Scope (\_GPE) + { + Name (ACST, 0xFF) + + Method (_L08) + { + Store ("Method _GPE._L08 invoked", Debug) + Return () + } + + Method (_E09) + { + Store ("Method _GPE._E09 invoked", Debug) + Return () + } + + Method (_E11) + { + Store ("Method _GPE._E11 invoked", Debug) + Notify (\PRW1, 2) + } + + Method (_L22) + { + Store ("Method _GPE._L22 invoked", Debug) + Return () + } + + Method (_L33) + { + Store ("Method _GPE._L33 invoked", Debug) + Return () + } + + Method (_E64) + { + Store ("Method _GPE._E64 invoked", Debug) + Return () + } + + } // _GPE + + Device (PRW1) + { + Name (_PRW, Package(2) {0x11, 3}) + } + + Device (PWRB) + { + Name (_HID, EISAID("PNP0C0C")) + Name (_PRW, Package(2) {0x33, 3}) + } + + + Scope (\_SB) // System Bus + { // _SB system bus + + Device (ACAD) + { // ACAD: AC adapter device + Name (_HID, "ACPI0003") // AC adapter device + + Name (_PCL, Package () {\_SB}) + + OperationRegion (AREG, SystemIO, 0x0372, 2) + Field (AREG, ByteAcc, NoLock, Preserve) + { + AIDX, 8, + ADAT, 8 + } + IndexField (AIDX, ADAT, ByteAcc, NoLock, Preserve) + { + , 1, // skips + ACIN, 1, + , 2, // skips + CHAG, 1, + , 3, // skips + , 7, // skips + ABAT, 1, + } // IndexField + + Method (_PSR) + { + Store (\_GPE.ACST, Local0) + Store (ACIN, Local1) + If (LNotEqual (\_GPE.ACST, Local1)) + { + Store (Local1, \_GPE.ACST) + // This Notify is commented because it causes a + // method error when running on a system without the + // specific device. + // Notify (\_SB_.ACAD, 0) + } + Return (Local0) + } // _PSR + + Method (_STA) + { + Return (0x0F) + } + + Method (_INI) + { + Store (ACIN, \_GPE.ACST) + } + } // ACAD: AC adapter device + + // test implicit return from control method + Method (DIS_, 1) + { + Store (Arg0, Local0) + } + + Device (RTLV) + { + // test implicit return inside nested if with explicit return of Lvalue + Method (_DCK, 1) + // Arg0: 1 == dock, 0 == undock + { + If (Arg0) + { // dock + Store (0x87, Local0) + + If (Local0) + { + DIS_ (0x23) + Return (1) + } + + Return (0) + } // dock + Else + { // undock + Store (Arg0, Local0) + + If (Local0) + { + DIS_ (0x23) + Return (1) + } + + Return (0) + } // undock + } // _DCK control method + + Method (TEST) + { + Store ("++++++++ RetLVal Test", Debug) + + // store _PSR return value into Local0 + Store (\_SB_.ACAD._PSR, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number/Integer type is 1 + { + Return (1) // failure + } + + // test implicit return inside nested if with explicit return of Lvalue + Store (_DCK (1), Local2) + + // save Local2 object type value into Local3 + Store (ObjectType (Local2), Local3) + + // validate Local2 is a Number + If (LNotEqual (Local3, 1)) // Number/Integer type is 1 + { + Return (2) // failure + } + + If (LNotEqual (Local2, 1)) + { + Return (3) // failure + } + + Return (0) // success + } // TEST + } // RTLV + } // _SB system bus + +// +// test RetPkg.asl +// +// Test ReturnOp(Package) +// This is required to support _PRT on Dell Optiplex Workstations (e.g. GX1) +// + + Scope (\_SB) // System Bus + { // _SB system bus + Device(LNKA) + { + Name (_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name (_UID, 1) + } + Device(LNKB) + { + Name (_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name (_UID, 2) + } + Device(LNKC) + { + Name (_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name (_UID, 3) + } + Device(LNKD) + { + Name (_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name (_UID, 4) + } + + Device (PCI1) + { // PCI1: Root PCI Bus + Name (_HID, "PNP0A03") // Need _HID for root device (String format) + Name (_ADR,0x00000000) + Name (_CRS,0) + + Name (_PRT, Package () + { + Package () {0x0004ffff, 0, LNKA, 0}, // Slot 1, INTA + Package () {0x0004ffff, 1, LNKB, 0}, // Slot 1, INTB + Package () {0x0004ffff, 2, LNKC, 0}, // Slot 1, INTC + Package () {0x0004ffff, 3, LNKD, 0}, // Slot 1, INTD + Package () {0x0005ffff, 0, \_SB_.LNKB, 0}, // Slot 2, INTA + Package () {0x0005ffff, 1, \_SB_.LNKC, 0}, // Slot 2, INTB + Package () {0x0005ffff, 2, \_SB_.LNKD, 0}, // Slot 2, INTC + Package () {0x0006ffff, 3, \_SB_.LNKA, 0}, // Slot 2, INTD + Package () {0x0006ffff, 0, LNKC, 0}, // Slot 3, INTA + Package () {0x0006ffff, 1, LNKD, 0}, // Slot 3, INTB + Package () {0x0006ffff, 2, LNKA, 0}, // Slot 3, INTC + Package () {0x0006ffff, 3, LNKB, 0}, // Slot 3, INTD + }) + + Device (PX40) + { // Map f0 space, Start PX40 + Name (_ADR,0x00070000) // Address+function. + } + } // PCI0: Root PCI Bus + + Device (RETP) + { + Method (RPKG) + { // RPKG: Return Package from local variable + + // store _PRT package into Local0 + Store (\_SB_.PCI1._PRT, Local0) + + // return Local0 Package + Return (Local0) + } // RPKG + + Method (TEST) + { + Store ("++++++++ RetPkg Test", Debug) + + // store RPKG package return value into Local0 + Store (RPKG, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Package + If (LNotEqual (Local1, 4)) // Package type is 4 + { Return (1) } // failure + Else + { Return (0) } // success + } // TEST + } // RETP + } // _SB_ + +// +// test WhileRet.asl +// +// WhileRet.asl tests a ReturnOp nested in a IfOp nested in a WhileOp. +// + Device (WHLR) + { + Name (LCNT, 0) + Method (WIR) + { // WIR: control method that returns inside of IfOp inside of WhileOp + While (LLess (LCNT, 4)) + { + If (LEqual (LCNT, 2)) + { + Return (0) + } + + Increment (LCNT) + } + + Return (LCNT) + } // WIR: control method that returns inside of IfOp inside of WhileOp + + Method (TEST) + { + Store ("++++++++ WhileRet Test", Debug) + + Store (WIR, Local0) + + Return (Local0) + } // TEST + } // WHLR + +// +// test AndOrOp.asl +// +//This code tests the bitwise AndOp and OrOp Operator terms +// +//Syntax of Andop term +//And - Bitwise And +//AndTerm := And( +// Source1, //TermArg=>Integer +// Source2, //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source1 and Source2 are evaluated as integer data types, +// a bit-wise AND is performed, and the result is optionally +//stored into Result. +// +// +//Syntax of OrOp +//Or - Bit-wise Or +//OrTerm := Or( +// Source1, //TermArg=>Integer +// Source2 //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source1 and Source2 are evaluated as integer data types, +// a bit-wide OR is performed, and the result is optionally +//stored in Result +// + Device (ANDO) + { + OperationRegion (TMEM, SystemMemory, 0xC4, 0x02) + Field (TMEM, ByteAcc, NoLock, Preserve) + { + , 3, + TOUD, 13 + } + + //Create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + }// Field(RAM) + + + //And with Byte Data + Name (BYT1, 0xff) + Name (BYT2, 0xff) + Name (BRSL, 0x00) + + //And with Word Data + Name (WRD1, 0xffff) + Name (WRD2, 0xffff) + Name (WRSL, 0x0000) + + //And with DWord Data + Name (DWD1, 0xffffffff) + Name (DWD2, 0xffffffff) + Name (DRSL, 0x00000000) + + Method (ANDP) + { + //Check with 1 And 1 on byte data + And(BYT1, BYT2, BRSL) + if(LNotEqual(BRSL,0xff)) + {Return(1)} + + //Check with 1 And 1 on Word data + And(WRD1, WRD2, WRSL) + if(LNotEqual(WRSL,0xffff)) + { + Return (1) // failure + } + + //Check with 1 And 1 Dword + And(DWD1, DWD2, DRSL) + if(LNotEqual(DRSL,0xffffffff)) + { + Return (1) // failure + } + + //Check with 0 And 0 on byte data + Store(0x00,BYT1) + Store(0x00,BYT2) + Store(0x00,BRSL) + And(BYT1, BYT2, BRSL) + if(LNotEqual(BRSL,0x00)) + { + Return (1) // failure + } + + //Check with 0 And 0 on Word data + Store (0x0000,WRD1) + Store (0x0000,WRD2) + Store (0x0000,WRSL) + And(WRD1, WRD2, WRSL) + if(LNotEqual(WRSL,0x0000)) + { + Return (1) // failure + } + + //Check with 0 And 0 Dword + Store (0x00000000,DWD1) + Store (0x00000000,DWD2) + Store (0x00000000,DRSL) + And(DWD1, DWD2, DRSL) + if(LNotEqual(DRSL,0x00000000)) + { + Return (1) // failure + } + + + //Check with 1 And 0 on byte data + Store(0x55,BYT1) + Store(0xAA,BYT2) + Store(0x00,BRSL) + And(BYT1, BYT2, BRSL) + if(LNotEqual(BRSL,0x00)) + { + Return (1) // failure + } + + //Check with 1 And 0 on Word data + Store (0x5555,WRD1) + Store (0xAAAA,WRD2) + Store (0x0000,WRSL) + And(WRD1, WRD2, WRSL) + if(LNotEqual(WRSL,0x0000)) + { + Return (1) // failure + } + + //Check with 1 And 0 on Dword + Store (0x55555555,DWD1) + Store (0xAAAAAAAA,DWD2) + Store (0x00000000,DRSL) + And(DWD1, DWD2, DRSL) + if(LNotEqual(DRSL,0x00000000)) + { + Return (1) // failure + } + + Store (0x1FFF, TOUD) + Store (TOUD, Local0) + if(LNotEqual(Local0,0x1FFF)) + { + Return (1) // failure + } + + //TBD- Do We need to check for system memory data also for each test case ?? + + Return(0) + + }//ANDP + + Method (OROP) + { + + //Check with 1 Ored with 1 on byte data + Store(0xff,BYT1) + Store(0xff,BYT2) + Store(0x00,BRSL) + Or(BYT1, BYT2, BRSL) + if(LNotEqual(BRSL,0xff)) + { + Return (1) // failure + } + + + //Check with 1 Ored with 1 on Word data + Store(0xffff,WRD1) + Store(0xffff,WRD2) + Store(0x0000,WRSL) + Or(WRD1, WRD2, WRSL) + if(LNotEqual(WRSL,0xffff)) + { + Return (1) // failure + } + + //Check with 1 Ored with 1 on Dword data + Store(0xffffffff,DWD1) + Store(0xffffffff,DWD2) + Store(0x00000000,DRSL) + Or(DWD1, DWD2, DRSL) + if(LNotEqual(DRSL,0xffffffff)) + { + Return (1) // failure + } + + //Check with 0 Ored with 0 on byte data + Store(0x00,BYT1) + Store(0x00,BYT2) + Store(0x00,BRSL) + Or(BYT1, BYT2, BRSL) + if(LNotEqual(BRSL,0x00)) + { + Return (1) // failure + } + + //Check with 0 Ored with 0 on Word data + Store (0x0000,WRD1) + Store (0x0000,WRD2) + Store (0x0000,WRSL) + Or(WRD1, WRD2, WRSL) + if(LNotEqual(WRSL,0x0000)) + { + Return (1) // failure + } + + //Check with 0 Ored with 0 Dword data + Store (0x00000000,DWD1) + Store (0x00000000,DWD2) + Store (0x00000000,DRSL) + Or(DWD1, DWD2, DRSL) + if(LNotEqual(DRSL,0x00000000)) + { + Return (1) // failure + } + + + //Check with 1 Ored with 0 on byte data + Store(0x55,BYT1) + Store(0xAA,BYT2) + Store(0x00,BRSL) + Or(BYT1, BYT2, BRSL) + if(LNotEqual(BRSL,0xff)) + { + Return (1) // failure + } + + //Check with 1 Ored with 0 on Word data + Store (0x5555,WRD1) + Store (0xAAAA,WRD2) + Store (0x0000,WRSL) + Or(WRD1, WRD2, WRSL) + if(LNotEqual(WRSL,0xffff)) + { + Return (1) // failure + } + + //Check with 1 Ored with 0 on Dword data + Store (0x55555555,DWD1) + Store (0xAAAAAAAA,DWD2) + Store (0x00000000,DRSL) + Or(DWD1, DWD2, DRSL) + if(LNotEqual(DRSL,0xffffffff)) + { + Return (1) // failure + } + + //TBD - Do We need to check for system memory data also for each test case ?? + + Return(0) + + }//OROP + + Method(TEST,, Serialized) + { + Store ("++++++++ AndOrOp Test", Debug) + + Name(RSLT,1) + //Call Andop method + Store(ANDP,RSLT) + if(LEqual(RSLT,1)) + { + Return (RSLT) + } + + //Call OrOp Method + Store(OROP,RSLT) + if(LEqual(RSLT,1)) + { + Return(RSLT) + } + + // + // Return original conditions to allow iterative execution + // + Store(0xff,BYT1) + Store(0xff,BYT2) + Store(0x00,BRSL) + Store (0xffff,WRD1) + Store (0xffff,WRD2) + Store (0x0000,WRSL) + Store (0xffffffff,DWD1) + Store (0xffffffff,DWD2) + Store (0x00000000,DRSL) + + Return(0) + } //TEST + } //ANDO + +// +// test BreakPnt.asl +// +// This code tests the BreakPoint opcode term. The syntax of BreakPoint Term is +// BreakPointTerm := BreakPoint +// Used for debugging, the Breakpoint opcode stops the execution and enters the AML debugger. +// In the non-debug version of the interpreter, BreakPoint is equivalent to Noop. +// + Device (BRKP) + { + Name(CNT0,0) + + Method (BK1) + { + BreakPoint + Return(0) + } + + Method (TEST) + { + Store ("++++++++ BreakPnt Test", Debug) + + Store(0,CNT0) + + //Check BreakPoint statement + While(LLess(CNT0,10)) + { + Increment(CNT0) + } + + //Check the BreakPoint statement + If(LEqual(CNT0,10)) + { + // BreakPoint + Return(0) + } + + //failed + Return(1) + } + } + +// +// test AddSubOp.asl +// + Device (ADSU) + { + // create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + } // Field(RAM) + + Method (TEST,, Serialized) + { + Store ("++++++++ AddSubOp Test", Debug) + + Name (DWRD, 0x12345678) + Name (WRD, 0x1234) + Name (BYT, 0x12) + + // Test AddOp with DWORD data + Store (0x12345678, DWRD) + Add (DWRD, 7, DWRD) + If (LNotEqual (DWRD, 0x1234567F)) + { Return (DWRD) } + + // Test AddOp with WORD data + Add (WRD, 5, WRD) + If (LNotEqual (WRD, 0x1239)) + { Return (WRD) } + + // Test AddOp with BYTE data + Add (BYT, 3, BYT) + If (LNotEqual (BYT, 0x15)) + { Return (BYT) } + + // Test SubtractOp with DWORD data + Subtract (DWRD, 7, DWRD) + If (LNotEqual (DWRD, 0x12345678)) + { Return (DWRD) } + + // Test SubtractOp with WORD data + Subtract (WRD, 3, WRD) + If (LNotEqual (WRD, 0x1236)) + { Return (WRD) } + + // Test SubtractOp with BYTE data + Subtract (BYT, 3, BYT) + If (LNotEqual (BYT, 0x12)) + { Return (BYT) } + + + // test AddOp with DWORD SystemMemory OpRegion + Store (0x01234567, SMDW) + Add (SMDW, 8, SMDW) + If (LNotEqual (SMDW, 0x0123456F)) + { Return (SMDW) } + + // test SubtractOp with DWORD SystemMemory OpRegion + Subtract (SMDW, 7, SMDW) + If (LNotEqual (SMDW, 0x01234568)) + { Return (SMDW) } + + + // test AddOp with WORD SystemMemory OpRegion + Store (0x0123, SMWD) + Add (SMWD, 6, SMWD) + If (LNotEqual (SMWD, 0x0129)) + { Return (SMWD) } + + // test SubtractOp with WORD SystemMemory OpRegion + Subtract (SMWD, 5, SMWD) + If (LNotEqual (SMWD, 0x0124)) + { Return (SMWD) } + + + // test AddOp with BYTE SystemMemory OpRegion + Store (0x01, SMBY) + Add (SMBY, 4, SMBY) + If (LNotEqual (SMBY, 0x05)) + { Return (SMBY) } + + // test SubtractOp with BYTE SystemMemory OpRegion + Subtract (SMBY, 3, SMBY) + If (LNotEqual (SMBY, 0x02)) + { Return (SMBY) } + + Return (0) + } // TEST + } // ADSU + +// +// test IncDecOp.asl +// + Device (INDC) + { + // create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + } // Field(RAM) + + Method (TEST,, Serialized) + { + Store ("++++++++ IncDecOp Test", Debug) + + Name (DWRD, 0x12345678) + Name (WRD, 0x1234) + Name (BYT, 0x12) + + // Test IncrementOp with DWORD data + Store (0x12345678, DWRD) + Increment (DWRD) + If (LNotEqual (DWRD, 0x12345679)) + { Return (DWRD) } + + // Test IncrementOp with WORD data + Increment (WRD) + If (LNotEqual (WRD, 0x1235)) + { Return (WRD) } + + // Test IncrementOp with BYTE data + Increment (BYT) + If (LNotEqual (BYT, 0x13)) + { Return (BYT) } + + // Test DecrementOp with DWORD data + Decrement (DWRD) + If (LNotEqual (DWRD, 0x12345678)) + { Return (DWRD) } + + // Test DecrementOp with WORD data + Decrement (WRD) + If (LNotEqual (WRD, 0x1234)) + { Return (WRD) } + + // Test DecrementOp with BYTE data + Decrement (BYT) + If (LNotEqual (BYT, 0x12)) + { Return (BYT) } + + + // test IncrementOp with DWORD SystemMemory OpRegion + Store (0x01234567, SMDW) + Increment (SMDW) + If (LNotEqual (SMDW, 0x01234568)) + { Return (SMDW) } + + // test DecrementOp with DWORD SystemMemory OpRegion + Decrement (SMDW) + If (LNotEqual (SMDW, 0x01234567)) + { Return (SMDW) } + + + // test IncrementOp with WORD SystemMemory OpRegion + Store (0x0123, SMWD) + Increment (SMWD) + If (LNotEqual (SMWD, 0x0124)) + { Return (SMWD) } + + // test DecrementOp with WORD SystemMemory OpRegion + Decrement (SMWD) + If (LNotEqual (SMWD, 0x0123)) + { Return (SMWD) } + + + // test IncrementOp with BYTE SystemMemory OpRegion + Store (0x01, SMBY) + Increment (SMBY) + If (LNotEqual (SMBY, 0x02)) + { Return (SMBY) } + + // test DecrementOp with BYTE SystemMemory OpRegion + Decrement (SMBY) + If (LNotEqual (SMBY, 0x01)) + { Return (SMBY) } + + Return (0) + } // TEST + } // INDC + +// +// test LOps.asl +// +//This source tests all the logical operators. Logical operators in ASL are as follows. +//LAnd, LEqual, LGreater, LLess, LNot, LNotEqual, LOr. +// Success will return 0 and failure will return a non zero number. Check the source code for +// non zero number to find where the test failed + + Device (LOPS) + { + //Create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + }// Field(RAM) + + //And with Byte Data + Name (BYT1, 0xff) + Name (BYT2, 0xff) + Name (BRSL, 0x00) + + //And with Word Data + Name (WRD1, 0xffff) + Name (WRD2, 0xffff) + Name (WRSL, 0x0000) + + //And with DWord Data + Name (DWD1, 0xffffffff) + Name (DWD2, 0xffffffff) + Name (DRSL, 0x00000000) + + Name(RSLT,1) + + Method (ANDL,2) // Test Logical And + { + //test with the arguments passed + if(LEqual(Arg0,Arg1)) + { Store(LAnd(Arg0,Arg1),RSLT) + if(LNotEqual(Ones,RSLT)) + {Return(11)} + } + + //test with he locals + Store(Arg0,Local0) + Store(Arg1,Local1) + + if(LEqual(Local0,Local1)) + { + Store(LAnd(Local0,Local1),RSLT) + if(LNotEqual(Ones,RSLT)) + {Return(12)} + } + + //test with BYTE data + if(LEqual(BYT1,BYT2)) + { Store(LAnd(BYT1,BYT2),BRSL) + if(LNotEqual(Ones,BRSL)) + {Return(13)} + } + + //test with WORD data + if(LEqual(WRD1,WRD2)) + { Store(LAnd(WRD1,WRD2),WRSL) + if(LNotEqual(Ones,WRSL)) + {Return(14)} + } + + //test with DWORD data + if(LEqual(DWD1,DWD2)) + { Store(LAnd(DWD1,DWD2),DRSL) + if(LNotEqual(Ones,DRSL)) + {Return(15)} + } + + //Test for system memory data for each test case. + + Store(0xff,BYT1) + Store(0xff,SMBY) + Store(0x00,BRSL) + + //test with BYTE system memory data + if(LEqual(BYT1,SMBY)) + { Store(LAnd(BYT1,SMBY),BRSL) + if(LNotEqual(Ones,BRSL)) + {Return(16)} + } + + Store (0xffff,WRD1) + Store(0xffff,SMWD) + Store(0x0000,WRSL) + //test with WORD system memory data + if(LEqual(WRD1,SMWD)) + { Store(LAnd(WRD1,SMWD),WRSL) + if(LNotEqual(Ones,WRSL)) + {Return(17)} + } + + Store(0x000000,DRSL) + Store (0xffffff,DWD1) + Store(0xffffff,SMDW) + + //test with DWORD system memory data + if(LEqual(DWD1,SMDW)) + { Store(LAnd(DWD1,SMDW),DRSL) + if(LNotEqual(Ones,DRSL)) + {Return(18)} + } + + Return(0) + + }//ANDL + + //Test the LOr Operator + + Method (ORL_,2) + {//ORL_ + + //test with the arguments passed + if(LEqual(Arg0,Arg1)) + { + Store(LOr(Arg0,Arg1),RSLT) + if(LNotEqual(Ones,RSLT)) + { + Return(21) + } + } + + //test with he locals + Store(Arg0,Local0) + Store(Arg1,Local1) + + if(LEqual(Local0,Local1)) + { + Store(LOr(Local0,Local1),RSLT) + if(LNotEqual(Ones,RSLT)) + {Return(22)} + } + + //Check with 1 LOred with 0 on byte data + Store(0xff,BYT1) + Store(0x00,BYT2) + Store(0x00,BRSL) + + if(LNotEqual(BYT1, BYT2)) + { + Store(LOr(BYT1, BYT2), BRSL) + if(LNotEqual(Ones,BRSL)) + {Return(23)} + } + + //Check with 1 LOred with 0 on WORD data + Store(0xffff,WRD1) + Store(0x0000,WRD2) + Store(0x0000,WRSL) + + if(LNotEqual(WRD1, WRD2)) + { + Store(LOr(WRD1, WRD2), WRSL) + if(LNotEqual(Ones,WRSL)) + {Return(24)} + } + + //Check with 1 LOred with 0 on DWORD data + Store(0xffffffff,DWD1) + Store(0x00000000,DWD2) + Store(0x00000000,DRSL) + + if(LNotEqual(DWD1, DWD2)) + { + Store(LOr(DWD1, DWD2), DRSL) + if(LNotEqual(Ones,DRSL)) + {Return(25)} + } + + Store(0x00,BYT1) + Store(0xff,SMBY) + Store(0x00,BRSL) + + //test with BYTE system memory data + if(LEqual(BYT1,SMBY)) + { Store(LOr(BYT1,SMBY),BRSL) + if(LNotEqual(Ones,BRSL)) + {Return(26)} + } + + Store (0x0000,WRD1) + Store(0xffff,SMWD) + Store(0x0000,WRSL) + + //test with WORD system memory data + if(LEqual(WRD1,SMWD)) + { Store(LOr(WRD1,SMWD),WRSL) + if(LNotEqual(Ones,WRSL)) + {Return(27)} + } + + + Store(0x00000000,DWD1) + Store(0xffffffff,SMDW) + Store(0x00000000,DRSL) + + //test with DWORD system memory data + if(LEqual(DWD1,SMDW)) + { Store(LAnd(DWD1,SMDW),DRSL) + if(LNotEqual(Ones,DRSL)) + {Return(28)} + } + Return(0) + + }//ORL_ + + //This method tests LGreater and LNot operator + Method(LSGR,2) + {//LSGR + + //Test on arguements passed + + //in test data, Arg1 > Arg0 + if(LEqual(Ones,LNot(LGreater(Arg1,Arg0)))) + {Return(31)} + + //test LLessEqual + if(LEqual(Ones,LNot(LGreaterEqual(Arg1,Arg0)))) + {Return(32)} + + if(LEqual(Ones,LLess(Arg1,Arg0))) + {Return(33)} + + //test LLessEqual + if(LEqual(Ones,LLessEqual(Arg1,Arg0))) + {Return(34)} + + Store(Arg0,Local0) + Store(Arg1,Local1) + + //test with the locals + if(LNot(LGreater(Local1,Local0))) + {Return(35)} + + //test on Byte data + Store(0x12,BYT1) + Store(0x21,BYT2) + + if(LNot(LGreater(BYT2,BYT1))) + {Return(36)} + + if(LNot(LLess(BYT1,BYT2))) + {Return(37)} + + //test LGreaterEqual with byte data + if(LNot(LGreaterEqual(BYT2,BYT1))) + {Return(38)} + + //test LLessEqual byte data + if(LNot(LLessEqual(BYT1,BYT2))) + {Return(39)} + + + //test on Word data + Store(0x1212,WRD1) + Store(0x2121,WRD2) + + if(LNot(LGreater(WRD2,WRD1))) + {Return(310)} + + if(LNot(LLess(WRD1,WRD2))) + {Return(311)} + + //Test LGreaterEqual with Word Data + if(LNot(LGreaterEqual(WRD2,WRD1))) + {Return(312)} + + + //Test LLessEqual with Word Data + if(LNot(LLessEqual(WRD1,WRD2))) + {Return(313)} + + //test on DWord data + Store(0x12121212,DWD1) + Store(0x21212121,DWD2) + + if(LNot(LGreater(DWD2,DWD1))) + {Return(314)} + + if(LNot(LLess(DWD1,DWD2))) + {Return(315)} + + + //Test LGreaterEqual with Dword + if(LNot(LGreaterEqual(DWD2,DWD1))) + {Return(316)} + + //Test LLessEqual DWord + if(LNot(LLessEqual(DWD1,DWD2))) + {Return(317)} + + Return(0) + }//LSGR + + //The test method + Method(TEST) + { + Store ("++++++++ LOps Test", Debug) + + Store(0,RSLT) + //Call LAndOp method + Store(ANDL(2,2),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + + //Call LOrOp Method + Store(ORL_(5,5),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + + //Call LSGR Method + Store(LSGR(5,7),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + + Return(0) + }//TEST + }//LOPS + +// +// test FdSetOps.asl +// +// FindSetLeftBit - Find Set Left Bit +// FindSetLeftBitTerm := FindSetLeftBit +// ( Source, //TermArg=>Integer +// Result //Nothing | SuperName +// ) => Integer +// Source is evaluated as integer data type, and the one-based bit location of +// the first MSb (most significant set bit) is optionally stored into Result. +// The result of 0 means no bit was set, 1 means the left-most bit set is the +// first bit, 2 means the left-most bit set is the second bit, and so on. +// FindSetRightBit - Find Set Right Bit + +// FindSetRightBitTerm := FindSetRightBit +// ( Source, //TermArg=>Integer +// Result //Nothing | SuperName +// ) => Integer +// Source is evaluated as integer data type, and the one-based bit location of +// the most LSb (least significant set bit) is optionally stored in Result. +// The result of 0 means no bit was set, 32 means the first bit set is the +// 32nd bit, 31 means the first bit set is the 31st bit, and so on. + +// If the Control method is success Zero is returned. Otherwise a non-zero +// number is returned. +// + Device (FDSO) + { // FDSO + + // Create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + } // Field(RAM) + + // Byte Data + Name (BYT1, 1) + Name (BRSL, 0x00) + + // Word Data + Name (WRD1, 0x100) + Name (WRSL, 0x0000) + + // DWord Data + Name (DWD1, 0x10000) + Name (DRSL, 0x00000000) + Name (RSLT, 1) + Name (CNTR, 1) + + Method (SHFT,2) + // Arg0 is the actual data and Arg1 is the bit position + { // SHFT + Store (Arg0, Local0) + Store (Arg1, Local1) + + FindSetLeftBit (Arg0, BRSL) + If (LNotEqual (BRSL, Arg1)) + { Return (0x11) } + If (LNotEqual (Arg0, Local0)) + { Return (0x12) } + + FindSetLeftBit (Local0, BRSL) + If (LNotEqual (BRSL, Local1)) + { Return (0x13) } + If (LNotEqual (Arg0, Local0)) + { Return (0x14) } + + // test the byte value for SetLeftBit + Store (7, BYT1) + FindSetLeftBit (BYT1, BRSL) + If (LNotEqual (BRSL, 3)) + { Return (0x15) } + If (LNotEqual (BYT1, 7)) + { Return (0x16) } + + Store (1, BYT1) + Store (1, CNTR) + While (LLessEqual (CNTR, 8)) + { // FindSetLeftBit check loop for byte data + FindSetLeftBit (BYT1, BRSL) + If (LNotEqual (BRSL, CNTR)) + { Return (0x17) } + + // Shift the bits to check the same + ShiftLeft (BYT1, 1, BYT1) + Increment (CNTR) + } // FindSetLeftBit check loop for byte data + + + // Check BYTE value for SetRightBit + Store (7, BYT1) + FindSetRightBit (BYT1, BRSL) + If (LNotEqual (BRSL, 1)) + { Return (0x21) } + If (LNotEqual (BYT1, 7)) + { Return (0x22) } + + Store (1, CNTR) + Store (0xFF, BYT1) + While (LLessEqual (CNTR, 8)) + { // FindSetRightBit check loop for byte data + FindSetRightBit (BYT1, BRSL) + If (LNotEqual (BRSL, CNTR)) + { Return (0x23) } + + ShiftLeft (BYT1, 1, BYT1) + Increment (CNTR) + } // FindSetRightBit check loop for byte data + + + // Test Word value for SetLeftBit + Store (9, CNTR) + Store (0x100, WRD1) + While (LLessEqual (CNTR, 16)) + { + // FindSetLeftBit check loop for Word data + FindSetLeftBit (WRD1, WRSL) + If (LNotEqual (WRSL, CNTR)) + { Return (0x31) } + + // Shift the bits to check the same + ShiftLeft (WRD1, 1, WRD1) + Increment (CNTR) + } // FindSetLeftBit check loop for Word data + + // Check Word value for SetRightBit + Store (9, CNTR) + Store (0xFF00, WRD1) + While (LLessEqual (CNTR, 16)) + { + // FindSetRightBit check loop for Word data + FindSetRightBit (WRD1, WRSL) + If (LNotEqual (WRSL, CNTR)) + { Return (0x32) } + + ShiftLeft (WRD1, 1, WRD1) + Increment (CNTR) + } // FindSetRightBit check loop for Word data + + // Test the DWord value for SetLeftBit + Store (17, CNTR) + Store (0x10000, DWD1) + While (LLessEqual (CNTR, 32)) + { + // FindSetLeftBit check loop for Dword + FindSetLeftBit (DWD1, DRSL) + If (LNotEqual (DRSL, CNTR)) + { Return (0x41) } + + // Shift the bits to check the same + ShiftLeft (DWD1, 1, DWD1) + Increment (CNTR) + } // FindSetLeftBit check loop for Dword + + // Check DWord value for SetRightBit + Store (17, CNTR) + Store (0xFFFF0000, DWD1) + While (LLessEqual (CNTR, 32)) + { // FindSetRightBit Check loop for DWORD + FindSetRightBit (DWD1, DRSL) + If (LNotEqual (DRSL, CNTR)) + { Return (0x42) } + + ShiftLeft (DWD1, 1, DWD1) + Increment (CNTR) + } // FindSetRightBit Check loop for DWORD + + Return (0) + } // SHFT + + // Test method called from amlexec + Method (TEST) + { // TEST + + Store ("++++++++ FdSetOps Test", Debug) + + Store (SHFT (0x80, 8), RSLT) + If (LNotEqual (RSLT, 0)) + { Return (RSLT) } + + Return (0) // pass + } // TEST + } // Device FDSO + +// +// test MulDivOp.asl +// + Device (MLDV) + { + // create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + } // Field(RAM) + + Method (TEST,, Serialized) + { + Store ("++++++++ MulDivOp Test", Debug) + + Name (RMDR, 0) + Name (DWRD, 0x12345678) + Name (WRD, 0x1234) + Name (BYT, 0x12) + + // Test MultiplyOp with DWORD data + Store (0x12345678, DWRD) + Multiply (DWRD, 3, DWRD) + If (LNotEqual (DWRD, 0x369D0368)) + { Return (DWRD) } + + // Test MultiplyOp with WORD data + Multiply (WRD, 4, WRD) + If (LNotEqual (WRD, 0x48D0)) + { Return (WRD) } + + // Test MultiplyOp with BYTE data + Multiply (BYT, 5, BYT) + If (LNotEqual (BYT, 0x5A)) + { Return (BYT) } + + // Test DivideOp with DWORD data + Divide (DWRD, 3, DWRD, RMDR) + If (LNotEqual (DWRD, 0x12345678)) + { Return (DWRD) } + If (LNotEqual (RMDR, 0)) + { Return (RMDR) } + + // Test DivideOp with WORD data + Divide (WRD, 4, WRD, RMDR) + If (LNotEqual (WRD, 0x1234)) + { Return (WRD) } + If (LNotEqual (RMDR, 0)) + { Return (RMDR) } + + // Test DivideOp with BYTE data + Divide (BYT, 5, BYT, RMDR) + If (LNotEqual (BYT, 0x12)) + { Return (BYT) } + If (LNotEqual (RMDR, 0)) + { Return (RMDR) } + + + // test MultiplyOp with DWORD SystemMemory OpRegion + Store (0x01234567, SMDW) + Multiply (SMDW, 2, SMDW) + If (LNotEqual (SMDW, 0x02468ACE)) + { Return (SMDW) } + + // test DivideOp with DWORD SystemMemory OpRegion + Divide (SMDW, 3, SMDW, RMDR) + If (LNotEqual (SMDW, 0x00C22E44)) + { Return (SMDW) } + If (LNotEqual (RMDR, 2)) + { Return (RMDR) } + + + // test MultiplyOp with WORD SystemMemory OpRegion + Store (0x0123, SMWD) + Multiply (SMWD, 3, SMWD) + If (LNotEqual (SMWD, 0x369)) + { Return (SMWD) } + + // test DivideOp with WORD SystemMemory OpRegion + Divide (SMWD, 2, SMWD, RMDR) + If (LNotEqual (SMWD, 0x01B4)) + { Return (SMWD) } + If (LNotEqual (RMDR, 1)) + { Return (RMDR) } + + + // test MultiplyOp with BYTE SystemMemory OpRegion + Store (0x01, SMBY) + Multiply (SMBY, 7, SMBY) + If (LNotEqual (SMBY, 0x07)) + { Return (SMBY) } + + // test DivideOp with BYTE SystemMemory OpRegion + Divide (SMBY, 4, SMBY, RMDR) + If (LNotEqual (SMBY, 0x01)) + { Return (SMBY) } + If (LNotEqual (RMDR, 3)) + { Return (RMDR) } + + Return (0) + } // TEST + } // MLDV + +// +// test NBitOps.asl +// +//NAnd - Bit-wise NAnd +//NAndTerm := NAnd( +// Source1, //TermArg=>Integer +// Source2 //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source1 and Source2 are evaluated as integer data types, a bit-wise NAND is performed, and the result is optionally +//stored in Result. + +//NOr - Bitwise NOr +//NOrTerm := NOr( +// Source1, //TermArg=>Integer +// Source2 //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source1 and Source2 are evaluated as integer data types, a bit-wise NOR is performed, and the result is optionally +//stored in Result. +// Not - Not +//NotTerm := Not( +// Source, //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source1 is evaluated as an integer data type, a bit-wise NOT is performed, and the result is optionally stored in +//Result. + +//If the Control method is success Zero is returned else a non-zero number is returned + + Device (NBIT) + {//NBIT + + //Create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + }// Field(RAM) + + + //And with Byte Data + Name (BYT1, 0xff) + Name (BYT2, 0xff) + Name (BRSL, 0x00) + + //And with Word Data + Name (WRD1, 0xffff) + Name (WRD2, 0xffff) + Name (WRSL, 0x0000) + + //And with DWord Data + Name (DWD1, 0xffffffff) + Name (DWD2, 0xffffffff) + Name (DRSL, 0x00000000) + Name(RSLT,1) + + + Name(ARSL,0x00) + Name(LRSL,0x00) + + Method(NNDB,2) + {//NNDB + + Store(0xffffffff,SMDW) + Store(0xffff,SMWD) + Store(0xff,SMBY) + + + NAnd(Arg0,Arg1,ARSL) + if(LNotEqual(ARSL,0xfffffffd)) + {Return(11)} + + Store(Arg0,local0) + Store(Arg1,Local1) + + NAnd(Local0,Local1,LRSL) + if(LNotEqual(LRSL,0xfffffffd)) + {Return(12)} + + + //Byte data + NAnd(BYT1,BYT2,BRSL) + if(LNotEqual(BRSL,0xffffff00)) + {Return(13)} + + //Word Data + NAnd(WRD1,WRD2,WRSL) + if(LNotEqual(WRSL,0xffff0000)) + {Return(14)} + + //DWord Data + NAnd(DWD1,DWD2,DRSL) + if(LNotEqual(DRSL,0x00000000)) + {Return(15)} + + //Byte data + NAnd(SMBY,0xff,BRSL) + if(LNotEqual(BRSL,0xffffff00)) + {Return(16)} + + //Word Data + NAnd(SMWD,0xffff,WRSL) + if(LNotEqual(WRSL,0xffff0000)) + {Return(17)} + + //DWord Data + NAnd(SMDW,0xffffffff,DRSL) + if(LNotEqual(DRSL,0x00000000)) + {Return(18)} + + Return(0) + + }//NNDB + + Method(NNOR,2) + {//NNOR + + NOr(Arg0,Arg1,ARSL) + if(LNotEqual(ARSL,0xfffffffd)) + {Return(21)} + + Store(Arg0,local0) + Store(Arg1,Local1) + + NOr(Local0,Local1,LRSL) + if(LNotEqual(LRSL,0xfffffffd)) + {Return(22)} + + + //Byte data + NOr(BYT1,BYT2,BRSL) + if(LNotEqual(BRSL,0xffffff00)) + {Return(23)} + + //Word Data + NOr(WRD1,WRD2,WRSL) + if(LNotEqual(WRSL,0xffff0000)) + {Return(24)} + + //DWord Data + NOr(DWD1,DWD2,DRSL) + if(LNotEqual(DRSL,0x00000000)) + {Return(25)} + + //System Memory Byte data + NOr(SMBY,0xff,BRSL) + if(LNotEqual(BRSL,0xffffff00)) + {Return(26)} + + //System Memory Word Data + NOr(SMWD,0xffff,WRSL) + if(LNotEqual(WRSL,0xffff0000)) + {Return(27)} + + //System Memory DWord Data + NOr(SMDW,0xffffffff,DRSL) + if(LNotEqual(DRSL,0x00000000)) + {Return(28)} + + Return(0) + + }//NNOR + + Method(NNOT,2) + {//NNOT + + Or(Arg0,Arg1,ARSL) + Not(ARSL,ARSL) + if(LNotEqual(ARSL,0xfffffffd)) + {Return(31)} + + Store(Arg0,local0) + Store(Arg1,Local1) + + Or(Local0,Local1,LRSL) + Not(LRSL,LRSL) + if(LNotEqual(LRSL,0xfffffffd)) + {Return(32)} + + + //Byte data + Or(BYT1,BYT2,BRSL) + Not(BRSL,BRSL) + if(LNotEqual(BRSL,0xffffff00)) + {Return(33)} + + //Word Data + Or(WRD1,WRD2,WRSL) + Not(WRSL,WRSL) + if(LNotEqual(WRSL,0xffff0000)) + {Return(34)} + + //DWord Data + Or(DWD1,DWD2,DRSL) + Not(DRSL,DRSL) + if(LNotEqual(DRSL,0x00000000)) + {Return(35)} + + //System Memory Byte data + Or(SMBY,0xff,BRSL) + Not(BRSL,BRSL) + if(LNotEqual(BRSL,0xffffff00)) + {Return(36)} + + //System Memory Word Data + Or(SMWD,0xffff,WRSL) + Not(WRSL,WRSL) + if(LNotEqual(WRSL,0xffff0000)) + {Return(37)} + + //System Memory DWord Data + Or(SMDW,0xffffffff,DRSL) + Not(DRSL,DRSL) + if(LNotEqual(DRSL,0x00000000)) + {Return(38)} + + Return(0) + }//NNOT + + + Method(TEST) + { + + Store ("++++++++ NBitOps Test", Debug) + + Store(NNDB(2,2),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + + Store(NNOR(2,2),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + + Store(NNOT(2,2),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + + + Return(0) + } + + }//Device NBIT + +// +// test ShftOp.asl +// +//ShiftRightTerm := ShiftRight( +// Source, //TermArg=>Integer +// ShiftCount //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source and ShiftCount are evaluated as integer data types. Source is shifted right with the most significant bit +//zeroed ShiftCount times. The result is optionally stored into Result. + +//ShiftLeft( +// Source, //TermArg=>Integer +// ShiftCount //TermArg=>Integer +// Result //Nothing | SuperName +//) => Integer +//Source and ShiftCount are evaluated as integer data types. Source is shifted left with the least significant +//bit zeroed ShiftCount times. The result is optionally stored into Result. + +//If the Control method is success Zero is returned else a non-zero number is returned + Device (SHFT) + {//SHFT + + //Create System Memory Operation Region and field overlays + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + SMDW, 32, // 32-bit DWORD + SMWD, 16, // 16-bit WORD + SMBY, 8, // 8-bit BYTE + }// Field(RAM) + + + Name(SHFC,0x00) + + //And with Byte Data + Name (BYT1, 0xff) + Name (BRSL, 0x00) + + //And with Word Data + Name (WRD1, 0xffff) + Name (WRSL, 0x0000) + + //And with DWord Data + Name (DWD1, 0xffffffff) + Name (DRSL, 0x00000000) + + Name(RSLT,1) + + Name(ARSL,0x00) + Name(LRSL,0x00) + + Method(SLFT,2) + {//SLFT + + Store(0xffffffff,SMDW) + Store(0xffff,SMWD) + Store(0xff,SMBY) + + + //Arg0-> 2 & Arg1->2 + ShiftLeft(Arg0,Arg1,ARSL) + if(LNotEqual(ARSL,8)) + {Return(11)} + + Store(Arg0,local0) + Store(Arg1,Local1) + + //Local0->8 and Local1->2 + ShiftLeft(Local0,Local1,LRSL) + if(LNotEqual(LRSL,8)) + {Return(12)} + + Store(2,SHFC) + //Byte data + ShiftLeft(BYT1,SHFC,BRSL) + if(LNotEqual(BRSL,0x3FC)) + {Return(13)} + + Store(4,SHFC) + //Word Data + ShiftLeft(WRD1,SHFC,WRSL) + if(LNotEqual(WRSL,0xFFFF0)) + {Return(14)} + + Store(8,SHFC) + //DWord Data + ShiftLeft(DWD1,SHFC,DRSL) + if(LNotEqual(DRSL,0xFFFFFF00)) + {Return(15)} + + + //System Memory Byte data + Store(4,SHFC) + ShiftLeft(SMBY,SHFC,BRSL) + if(LNotEqual(BRSL,0xFF0)) + {Return(16)} + + //Word Data + Store(4,SHFC) + ShiftLeft(SMWD,SHFC,WRSL) + if(LNotEqual(WRSL,0xffff0)) + {Return(17)} + + //DWord Data + Store(8,SHFC) + ShiftLeft(SMDW,SHFC,DRSL) + if(LNotEqual(DRSL,0xFFFFFF00)) + {Return(18)} + + Return(0) + + }//SLFT + + Method(SRGT,2) + {//SRGT + //And with Byte Data + Store (0xff,BYT1) + Store (0x00,BRSL) + + //And with Word Data + Store (0xffff,WRD1) + Store (0x0000,WRSL) + + //And with DWord Data + Store(0xffffffff,DWD1) + Store (0x00000000,DRSL) + + //Reinitialize the result objects + Store(0x00,ARSL) + Store(0x00,LRSL) + + Store(0xffffffff,SMDW) + Store(0xffff,SMWD) + Store(0xff,SMBY) + + //Arg0-> 2 & Arg1->2 + ShiftRight(Arg0,Arg1,ARSL) + if(LNotEqual(ARSL,0)) + {Return(21)} + + Store(Arg0,local0) + Store(Arg1,Local1) + + //Local0->8 and Local1->2 + ShiftRight(Local0,Local1,LRSL) + if(LNotEqual(LRSL,0)) + {Return(22)} + + Store(2,SHFC) + //Byte data + ShiftRight(BYT1,SHFC,BRSL) + if(LNotEqual(BRSL,0x3F)) + {Return(23)} + + Store(4,SHFC) + //Word Data + ShiftRight(WRD1,SHFC,WRSL) + if(LNotEqual(WRSL,0xFFF)) + {Return(24)} + + Store(8,SHFC) + //DWord Data + ShiftRight(DWD1,SHFC,DRSL) + if(LNotEqual(DRSL,0xFFFFFF)) + {Return(25)} + + //System Memory Byte data + Store(4,SHFC) + ShiftRight(SMBY,SHFC,BRSL) + if(LNotEqual(BRSL,0xF)) + {Return(26)} + + //Word Data + Store(4,SHFC) + ShiftRight(SMWD,SHFC,WRSL) + if(LNotEqual(WRSL,0xFFF)) + {Return(27)} + + //DWord Data + Store(8,SHFC) + ShiftRight(SMDW,SHFC,DRSL) + if(LNotEqual(DRSL,0xFFFFFF)) + {Return(28)} + + Return(0) + }//SRGT + + //Test method called from amlexec + Method(TEST) + { + Store ("++++++++ ShftOp Test", Debug) + + Store(SLFT(2,2),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + Store(SRGT(2,2),RSLT) + if(LNotEqual(RSLT,0)) + {Return(RSLT)} + Return(0) + } + + }//Device SHFT + +// +// test Xor.asl and slightly modified +// +//This code tests the XOR opcode term +//Syntax of XOR term +// XOr( +// Source1 //TermArg=>BufferTerm +// Source2 //TermArg=>Integer +// Result //NameString +// ) +//"Source1" and "Source2" are evaluated as integers, a bit-wise XOR is performed, and the result is optionally stored in +// Result + Device (XORD) + { + //This Method tests XOr operator for all the data types i.e. BYTE, WORD and DWORD + Method (TEST,, Serialized) + { + Store ("++++++++ Xor Test", Debug) + + //Overlay in system memory + OperationRegion (RAM, SystemMemory, 0x800000, 256) + Field (RAM, ByteAcc, NoLock, Preserve) + { + RES1, 1, //Offset + BYT1, 8, //First BYTE + BYT2, 8, //Second BYTE + RBYT, 8, //Result Byte + RES2, 1, //Offset + WRD1, 16, //First WORD field + WRD2, 16, //Second WORD field + RWRD, 16, //RSLT WORD field + RES3, 1, //Offset + DWD1, 32, //First Dword + DWD2, 32, //Second Dword + RDWD, 32, //Result Dword + RES4, 1, //Offset + } + + // Store bits in the single bit fields for checking + // at the end + Store(1, RES1) + Store(1, RES2) + Store(1, RES3) + Store(1, RES4) + + // Check the stored single bits + if(LNotEqual(RES1, 1)) + { + Return(1) + } + + if(LNotEqual(RES2, 1)) + { + Return(1) + } + + if(LNotEqual(RES3, 1)) + { + Return(1) + } + + if(LNotEqual(RES4, 1)) + { + Return(1) + } + + //************************************************ + // (BYT1) Bit1 ->0 and (BYT2)Bit2 -> 0 condition + Store(0x00,BYT1) + Store(0x00,BYT2) + XOr(BYT1,BYT2,Local0) + Store (Local0, RBYT) + if(LNotEqual(RBYT,0)) + { Return(1)} + + // (BYT1) Bit1 ->1 and (BYT2)Bit2 -> 1 condition + Store(0xff,BYT1) + Store(0xff,BYT2) + XOr(BYT1,BYT2,Local0) + Store (Local0, RBYT) + if(LNotEqual(RBYT,0)) + { Return(1)} + + // (BYT1) Bit1 ->1 and (BYT)Bit2 -> 0 condition + Store(0x55,BYT1) + Store(0xAA,BYT2) + XOr(BYT1,BYT2,Local0) + Store (Local0, RBYT) + if(LNotEqual(RBYT,0xFF)) + { Return(1)} + + //(BYT1) Bit1 ->0 and (BYT2)Bit2 -> 1 condition + Store(0xAA,BYT1) + Store(0x55,BYT2) + XOr(BYT1,BYT2,Local0) + Store (Local0, RBYT) + if(LNotEqual(RBYT,0xFF)) + { Return(1)} + + Store(0x12,BYT1) + Store(0xED,BYT2) + + XOr(BYT1,BYT2,Local0) + Store (Local0, RBYT) + if(LNotEqual(RBYT,0xFF)) + { + Return(1) + } + + // Store known values for checking later + Store(0x12, BYT1) + if(LNotEqual(BYT1, 0x12)) + { + Return(1) + } + + Store(0xFE, BYT2) + if(LNotEqual(BYT2, 0xFE)) + { + Return(1) + } + + Store(0xAB, RBYT) + if(LNotEqual(RBYT, 0xAB)) + { + Return(1) + } + + //*********************************************** + // (WRD1) Bit1 ->0 and (WRD2)Bit2 -> 0 condition + Store(0x0000,WRD1) + Store(0x0000,WRD2) + XOr(WRD1,WRD2,RWRD) + if(LNotEqual(RWRD,0)) + { Return(1)} + + // (WRD1) Bit1 ->1 and (WRD2)Bit2 -> 1 condition + Store(0xffff,WRD1) + Store(0xffff,WRD2) + XOr(WRD1,WRD2,RWRD) + if(LNotEqual(RWRD,0)) + { Return(1)} + + // (WRD1) Bit1 ->1 and (WRD2)Bit2 -> 0 condition + Store(0x5555,WRD1) + Store(0xAAAA,WRD2) + XOr(WRD1,WRD2,RWRD) + if(LNotEqual(RWRD,0xFFFF)) + { Return(1)} + + //(WRD1) Bit1 ->0 and (WRD2)Bit2 -> 1 condition + Store(0xAAAA,WRD1) + Store(0x5555,WRD2) + XOr(WRD1,WRD2,RWRD) + if(LNotEqual(RWRD,0xFFFF)) + { Return(1)} + + Store(0x1234,WRD1) + Store(0xEDCB,WRD2) + XOr(WRD1,WRD2,RWRD) + if(LNotEqual(RWRD,0xFFFF)) + { Return(1)} + + // Store known values for checking later + Store(0x1234, WRD1) + if(LNotEqual(WRD1, 0x1234)) + { + Return(1) + } + + Store(0xFEDC, WRD2) + if(LNotEqual(WRD2, 0xFEDC)) + { + Return(1) + } + + Store(0x87AB, RWRD) + if(LNotEqual(RWRD, 0x87AB)) + { + Return(1) + } + + + //************************************************** + // (DWD1) Bit1 ->0 and (DWD2)Bit2 -> 0 condition + Store(0x00000000,DWD1) + Store(0x00000000,DWD2) + XOr(DWD1,DWD2,RDWD) + if(LNotEqual(RDWD,0)) + { Return(1)} + + // (DWD1) Bit1 ->1 and (DWD2)Bit2 -> 1 condition + Store(0xffffffff,DWD1) + Store(0xffffffff,DWD2) + XOr(DWD1,DWD2,RDWD) + if(LNotEqual(RDWD,0)) + { Return(1)} + + // (DWD1) Bit1 ->1 and (DWD2)Bit2 -> 0 condition + Store(0x55555555,DWD1) + Store(0xAAAAAAAA,DWD2) + XOr(DWD1,DWD2,RDWD) + if(LNotEqual(RDWD,0xFFFFFFFF)) + { Return(1)} + + //(DWD1) Bit1 ->0 and (DWD2)Bit2 -> 1 condition + Store(0xAAAAAAAA,DWD1) + Store(0x55555555,DWD2) + XOr(DWD1,DWD2,RDWD) + if(LNotEqual(RDWD,0xFFFFFFFF)) + { Return(1)} + + // (DWD1) Bit1 ->1 and (DWD2)Bit2 -> 0 condition + Store(0x12345678,DWD1) + Store(0xEDCBA987,DWD2) + XOr(DWD1,DWD2,RDWD) + if(LNotEqual(RDWD,0xFFFFFFFF)) + { Return(1)} + + Store(0x12345678,DWD1) + if(LNotEqual(DWD1,0x12345678)) + { + Return(1) + } + + Store(0xFEDCBA98,DWD2) + if(LNotEqual(DWD2,0xFEDCBA98)) + { + Return(1) + } + + Store(0x91827364,RDWD) + if(LNotEqual(RDWD,0x91827364)) + { + Return(1) + } + + //**************************************************** + // Check the stored single bits + if(LNotEqual(RES1, 1)) + { + Return(1) + } + + if(LNotEqual(RES2, 1)) + { + Return(1) + } + + if(LNotEqual(RES3, 1)) + { + Return(1) + } + + if(LNotEqual(RES4, 1)) + { + Return(1) + } + + // Change all of the single bit fields to zero + Store(0, RES1) + Store(0, RES2) + Store(0, RES3) + Store(0, RES4) + + // Now, check all of the fields + + // Byte + if(LNotEqual(BYT1, 0x12)) + { + Return(1) + } + + if(LNotEqual(BYT2, 0xFE)) + { + Return(1) + } + + if(LNotEqual(RBYT, 0xAB)) + { + Return(1) + } + + // Word + if(LNotEqual(WRD1, 0x1234)) + { + Return(1) + } + + if(LNotEqual(WRD2, 0xFEDC)) + { + Return(1) + } + + if(LNotEqual(RWRD, 0x87AB)) + { + Return(1) + } + + // Dword + if(LNotEqual(DWD1, 0x12345678)) + { + Return(1) + } + + if(LNotEqual(DWD2, 0xFEDCBA98)) + { + Return(1) + } + + if(LNotEqual(RDWD, 0x91827364)) + { + Return(1) + } + + // Bits + if(LNotEqual(RES1, 0)) + { + Return(1) + } + + if(LNotEqual(RES2, 0)) + { + Return(1) + } + + if(LNotEqual(RES3, 0)) + { + Return(1) + } + + if(LNotEqual(RES4, 0)) + { + Return(1) + } + + + Return(0) + } // TEST + } // XORD + +// +// test CrBytFld.asl +// +// CrBytFld test +// Test for CreateByteField. +// Tests creating byte field overlay of buffer stored in Local0. +// Tests need to be added for Arg0 and Name buffers. +// + Device (CRBF) + { // Test device name + Method (TEST) + { + Store ("++++++++ CrBytFld Test", Debug) + + // Local0 is unitialized buffer with 4 elements + Store (Buffer (4) {}, Local0) + + // create Byte Field named BF0 based on Local0 element 0 + CreateByteField (Local0, 0, BF0) + + // validate CreateByteField did not alter Local0 + Store (ObjectType (Local0), Local1) // Local1 = Local0 object type + If (LNotEqual (Local1, 3)) // Buffer object type value is 3 + { Return (2) } + + // store something into BF0 + Store (1, BF0) + + // validate Store did not alter Local0 object type + Store (ObjectType (Local0), Local1) // Local1 = Local0 object type + If (LNotEqual (Local1, 3)) // Buffer object type value is 3 + { Return (3) } + + // verify that the Store into BF0 was successful + If (LNotEqual (BF0, 1)) + { Return (4) } + + + // create Byte Field named BF1 based on Local0 element 1 + CreateByteField (Local0, 1, BF1) + + // validate CreateByteField did not alter Local0 + Store (ObjectType (Local0), Local1) // Local1 = Local0 object type + If (LNotEqual (Local1, 3)) // Buffer object type value is 3 + { Return (10) } + + // store something into BF1 + Store (5, BF1) + + // validate Store did not alter Local0 object type + Store (ObjectType (Local0), Local1) // Local1 = Local0 object type + If (LNotEqual (Local1, 3)) // Buffer object type value is 3 + { Return (11) } + + // verify that the Store into BF1 was successful + If (LNotEqual (BF1, 5)) + { Return (12) } + + // verify that the Store into BF1 did not alter BF0 + If (LNotEqual (BF0, 1)) + { Return (13) } + + + // store something into BF0 + Store (0xFFFF, BF0) + + // verify that the Store into BF0 was successful + If (LNotEqual (BF0, 0xFF)) + { Return (20) } + + // verify that the Store into BF0 did not alter BF1 + If (LNotEqual (BF1, 5)) + { Return (21) } + + + Return (0) + } // TEST + } // CRBF + +// +// test IndexOp4.asl +// +// IndexOp4 test +// This is just a subset of the many RegionOp/Index Field test cases. +// Tests access of index fields smaller than 8 bits. +// + Device (IDX4) + { // Test device name + + // MADM: Misaligned Dynamic RAM SystemMemory OperationRegion + // Tests OperationRegion memory access using misaligned BYTE, + // WORD, and DWORD field element accesses. Validation is performed + // using both misaligned field entries and aligned field entries. + // + // MADM returns 0 if all test cases pass or non-zero identifying + // the failing test case for debug purposes. This non-zero numbers + // are not guaranteed to be in perfect sequence (i.e., test case + // index), but are guaranteed to be unique so the failing test + // case can be uniquely identified. + // + Method (MADM, 1, Serialized) // Misaligned Dynamic RAM SystemMemory OperationRegion + // Arg0 -- SystemMemory OperationRegion base address + { // MADM: Misaligned Dynamic RAM SystemMemory OperationRegion + OperationRegion (RAM, SystemMemory, Arg0, 0x100) + Field (RAM, DwordAcc, NoLock, Preserve) + { // aligned field definition (for verification) + DWD0, 32, // aligned DWORD field + DWD1, 32 // aligned DWORD field + } + Field (RAM, ByteAcc, NoLock, Preserve) + { // bit access field definition + BIT0, 1, // single bit field entry + BIT1, 1, // single bit field entry + BIT2, 1, // single bit field entry + BIT3, 1, // single bit field entry + BIT4, 1, // single bit field entry + BIT5, 1, // single bit field entry + BIT6, 1, // single bit field entry + BIT7, 1, // single bit field entry + BIT8, 1, // single bit field entry + BIT9, 1, // single bit field entry + BITA, 1, // single bit field entry + BITB, 1, // single bit field entry + BITC, 1, // single bit field entry + BITD, 1, // single bit field entry + BITE, 1, // single bit field entry + BITF, 1, // single bit field entry + BI10, 1, // single bit field entry + BI11, 1, // single bit field entry + BI12, 1, // single bit field entry + BI13, 1, // single bit field entry + BI14, 1, // single bit field entry + BI15, 1, // single bit field entry + BI16, 1, // single bit field entry + BI17, 1, // single bit field entry + BI18, 1, // single bit field entry + BI19, 1, // single bit field entry + BI1A, 1, // single bit field entry + BI1B, 1, // single bit field entry + BI1C, 1, // single bit field entry + BI1D, 1, // single bit field entry + BI1E, 1, // single bit field entry + BI1F, 1 // single bit field entry + } // bit access field definition + + Field (RAM, ByteAcc, NoLock, Preserve) + { // two-bit access field definition + B2_0, 2, // single bit field entry + B2_1, 2, // single bit field entry + B2_2, 2, // single bit field entry + B2_3, 2, // single bit field entry + B2_4, 2, // single bit field entry + B2_5, 2, // single bit field entry + B2_6, 2, // single bit field entry + B2_7, 2, // single bit field entry + B2_8, 2, // single bit field entry + B2_9, 2, // single bit field entry + B2_A, 2, // single bit field entry + B2_B, 2, // single bit field entry + B2_C, 2, // single bit field entry + B2_D, 2, // single bit field entry + B2_E, 2, // single bit field entry + B2_F, 2 // single bit field entry + } // bit access field definition + + // initialize memory contents using aligned field entries + Store (0x5AA55AA5, DWD0) + Store (0x5AA55AA5, DWD1) + + // set memory contents to known values using misaligned field entries + Store (0, BIT0) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT0, 0)) + { Return (1) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55AA4)) + { Return (2) } + + // set memory contents to known values using misaligned field entries + Store (1, BIT1) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT1, 1)) + { Return (3) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55AA6)) + { Return (4) } + + // set memory contents to known values using misaligned field entries + Store (0, BIT2) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT2, 0)) + { Return (5) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55AA2)) + { Return (6) } + + // set memory contents to known values using misaligned field entries + Store (1, BIT3) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT3, 1)) + { Return (7) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55AAA)) + { Return (8) } + + // set memory contents to known values using misaligned field entries + Store (1, BIT4) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT4, 1)) + { Return (9) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55ABA)) + { Return (10) } + + // set memory contents to known values using misaligned field entries + Store (0, BIT5) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT5, 0)) + { Return (11) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55A9A)) + { Return (12) } + + // set memory contents to known values using misaligned field entries + Store (1, BIT6) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT6, 1)) + { Return (13) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55ADA)) + { Return (14) } + + // set memory contents to known values using misaligned field entries + Store (0, BIT7) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT7, 0)) + { Return (15) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55A5A)) + { Return (16) } + + // set memory contents to known values using misaligned field entries + Store (1, BIT8) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT8, 1)) + { Return (17) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55B5A)) + { Return (18) } + + // set memory contents to known values using misaligned field entries + Store (0, BIT9) + // verify memory contents using misaligned field entries + If (LNotEqual (BIT9, 0)) + { Return (19) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA5595A)) + { Return (20) } + + // set memory contents to known values using misaligned field entries + Store (1, BITA) + // verify memory contents using misaligned field entries + If (LNotEqual (BITA, 1)) + { Return (21) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA55D5A)) + { Return (22) } + + // set memory contents to known values using misaligned field entries + Store (0, BITB) + // verify memory contents using misaligned field entries + If (LNotEqual (BITB, 0)) + { Return (23) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA5555A)) + { Return (24) } + + // set memory contents to known values using misaligned field entries + Store (0, BITC) + // verify memory contents using misaligned field entries + If (LNotEqual (BITC, 0)) + { Return (25) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA5455A)) + { Return (26) } + + // set memory contents to known values using misaligned field entries + Store (1, BITD) + // verify memory contents using misaligned field entries + If (LNotEqual (BITD, 1)) + { Return (27) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA5655A)) + { Return (28) } + + // set memory contents to known values using misaligned field entries + Store (0, BITE) + // verify memory contents using misaligned field entries + If (LNotEqual (BITE, 0)) + { Return (29) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA5255A)) + { Return (30) } + + // set memory contents to known values using misaligned field entries + Store (1, BITF) + // verify memory contents using misaligned field entries + If (LNotEqual (BITF, 1)) + { Return (31) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA5A55A)) + { Return (32) } + + // set memory contents to known values using misaligned field entries + Store (0, BI10) + // verify memory contents using misaligned field entries + If (LNotEqual (BI10, 0)) + { Return (33) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA4A55A)) + { Return (34) } + + // set memory contents to known values using misaligned field entries + Store (1, BI11) + // verify memory contents using misaligned field entries + If (LNotEqual (BI11, 1)) + { Return (35) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA6A55A)) + { Return (36) } + + // set memory contents to known values using misaligned field entries + Store (0, BI12) + // verify memory contents using misaligned field entries + If (LNotEqual (BI12, 0)) + { Return (37) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AA2A55A)) + { Return (38) } + + // set memory contents to known values using misaligned field entries + Store (1, BI13) + // verify memory contents using misaligned field entries + If (LNotEqual (BI13, 1)) + { Return (39) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5AAAA55A)) + { Return (40) } + + // set memory contents to known values using misaligned field entries + Store (1, BI14) + // verify memory contents using misaligned field entries + If (LNotEqual (BI14, 1)) + { Return (41) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5ABAA55A)) + { Return (42) } + + // set memory contents to known values using misaligned field entries + Store (0, BI15) + // verify memory contents using misaligned field entries + If (LNotEqual (BI15, 0)) + { Return (43) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5A9AA55A)) + { Return (44) } + + // set memory contents to known values using misaligned field entries + Store (1, BI16) + // verify memory contents using misaligned field entries + If (LNotEqual (BI16, 1)) + { Return (45) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5ADAA55A)) + { Return (46) } + + // set memory contents to known values using misaligned field entries + Store (0, BI17) + // verify memory contents using misaligned field entries + If (LNotEqual (BI17, 0)) + { Return (47) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5A5AA55A)) + { Return (48) } + + // set memory contents to known values using misaligned field entries + Store (1, BI18) + // verify memory contents using misaligned field entries + If (LNotEqual (BI18, 1)) + { Return (49) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5B5AA55A)) + { Return (50) } + + // set memory contents to known values using misaligned field entries + Store (0, BI19) + // verify memory contents using misaligned field entries + If (LNotEqual (BI19, 0)) + { Return (51) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x595AA55A)) + { Return (52) } + + // set memory contents to known values using misaligned field entries + Store (1, BI1A) + // verify memory contents using misaligned field entries + If (LNotEqual (BI1A, 1)) + { Return (53) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x5D5AA55A)) + { Return (54) } + + // set memory contents to known values using misaligned field entries + Store (0, BI1B) + // verify memory contents using misaligned field entries + If (LNotEqual (BI1B, 0)) + { Return (55) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x555AA55A)) + { Return (56) } + + // set memory contents to known values using misaligned field entries + Store (0, BI1C) + // verify memory contents using misaligned field entries + If (LNotEqual (BI1C, 0)) + { Return (57) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x455AA55A)) + { Return (58) } + + // set memory contents to known values using misaligned field entries + Store (1, BI1D) + // verify memory contents using misaligned field entries + If (LNotEqual (BI1D, 1)) + { Return (59) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x655AA55A)) + { Return (60) } + + // set memory contents to known values using misaligned field entries + Store (0, BI1E) + // verify memory contents using misaligned field entries + If (LNotEqual (BI1E, 0)) + { Return (61) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x255AA55A)) + { Return (62) } + + // set memory contents to known values using misaligned field entries + Store (1, BI1F) + // verify memory contents using misaligned field entries + If (LNotEqual (BI1F, 1)) + { Return (63) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA55A)) + { Return (64) } + + + // set memory contents to known values using misaligned field entries + Store (3, B2_0) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_0, 3)) + { Return (65) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA55B)) + { Return (66) } + + // set memory contents to known values using misaligned field entries + Store (1, B2_1) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_1, 1)) + { Return (67) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA557)) + { Return (68) } + + // set memory contents to known values using misaligned field entries + Store (0, B2_2) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_2, 0)) + { Return (69) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA547)) + { Return (70) } + + // set memory contents to known values using misaligned field entries + Store (3, B2_3) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_3, 3)) + { Return (71) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA5C7)) + { Return (72) } + + // set memory contents to known values using misaligned field entries + Store (3, B2_4) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_4, 3)) + { Return (73) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA7C7)) + { Return (74) } + + // set memory contents to known values using misaligned field entries + Store (0, B2_5) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_5, 0)) + { Return (75) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55AA3C7)) + { Return (76) } + + // set memory contents to known values using misaligned field entries + Store (1, B2_6) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_6, 1)) + { Return (77) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55A93C7)) + { Return (78) } + + // set memory contents to known values using misaligned field entries + Store (1, B2_7) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_7, 1)) + { Return (79) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55A53C7)) + { Return (80) } + + // set memory contents to known values using misaligned field entries + Store (0, B2_8) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_8, 0)) + { Return (81) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55853C7)) + { Return (82) } + + // set memory contents to known values using misaligned field entries + Store (1, B2_9) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_9, 1)) + { Return (83) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA55453C7)) + { Return (84) } + + // set memory contents to known values using misaligned field entries + Store (2, B2_A) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_A, 2)) + { Return (85) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA56453C7)) + { Return (86) } + + // set memory contents to known values using misaligned field entries + Store (2, B2_B) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_B, 2)) + { Return (87) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA5A453C7)) + { Return (88) } + + // set memory contents to known values using misaligned field entries + Store (3, B2_C) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_C, 3)) + { Return (89) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xA7A453C7)) + { Return (90) } + + // set memory contents to known values using misaligned field entries + Store (3, B2_D) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_D, 3)) + { Return (91) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0xAFA453C7)) + { Return (92) } + + // set memory contents to known values using misaligned field entries + Store (1, B2_E) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_E, 1)) + { Return (93) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x9FA453C7)) + { Return (94) } + + // set memory contents to known values using misaligned field entries + Store (0, B2_F) + // verify memory contents using misaligned field entries + If (LNotEqual (B2_F, 0)) + { Return (95) } + // verify memory contents using aligned field entries + If (LNotEqual (DWD0, 0x1FA453C7)) + { Return (96) } + + + Return (0) // pass + } // MADM: Misaligned Dynamic RAM SystemMemory OperationRegion + + Method (TEST) + { + Store ("++++++++ IndexOp4 Test", Debug) + + // MADM (Misaligned Dynamic RAM SystemMemory OperationRegion) arguments: + // Arg0 -- SystemMemory OperationRegion base address + Store (MADM (0x800000), Local0) + If (LNotEqual (Local0, 0)) // MADM returns zero if successful + { Return (Local0) } // failure: return MADM error code + + Return (Local0) + } // TEST + } // IDX4 + +// +// test Event.asl +// +// EventOp, ResetOp, SignalOp, and WaitOp test cases. +// + Device (EVNT) + { + Event (EVNT) // event synchronization object + + Method (TEVN, 1) + // Arg0: time to Wait for event in milliseconds + { // TEVN control method to test ResetOp, SignalOp, and WaitOp + // reset EVNT to initialization (zero) state + Reset (EVNT) + + // prime EVNT with two outstanding signals + Signal (EVNT) + Signal (EVNT) + + + // acquire existing signal + Store (Wait (EVNT, Arg0), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x21) } // Local1 indicates Local0 is not a Number + + If (LNotEqual (Local0, 0)) // Number is type 1 + { Return (0x22) } // timeout occurred without acquiring signal + + Store ("Acquire 1st existing signal PASS", Debug) + + + // acquire existing signal + Store (Wait (EVNT, Arg0), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x31) } // Local1 indicates Local0 is not a Number + + If (LNotEqual (Local0, 0)) // Number is type 1 + { Return (0x32) } // timeout occurred without acquiring signal + + Store ("Acquire 2nd existing signal PASS", Debug) + + + // ensure WaitOp timeout test cases do not hang + if (LEqual (Arg0, 0xFFFF)) + { Store (0xFFFE, Arg0) } + + // acquire non-existing signal + Store (Wait (EVNT, Arg0), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x41) } // Local1 indicates Local0 is not a Number + + If (LEqual (Local0, 0)) // Number is type 1 + { Return (0x42) } // non-existant signal was acquired + + Store ("Acquire signal timeout PASS", Debug) + + + // prime EVNT with two outstanding signals + Signal (EVNT) + Signal (EVNT) + + // reset EVNT to initialization (zero) state + Reset (EVNT) + + // acquire non-existing signal + Store (Wait (EVNT, Arg0), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x51) } // Local1 indicates Local0 is not a Number + + If (LEqual (Local0, 0)) // Number is type 1 + { Return (0x52) } // non-existant signal was acquired + + Store ("Reset signal PASS", Debug) + + + // acquire non-existing signal using Lvalue timeout + Store (Wait (EVNT, Zero), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x61) } // Local1 indicates Local0 is not a Number + + If (LEqual (Local0, 0)) // Number is type 1 + { Return (0x62) } // non-existant signal was acquired + + Store ("Zero Lvalue PASS", Debug) + + + // acquire non-existing signal using Lvalue timeout + Store (Wait (EVNT, One), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x71) } // Local1 indicates Local0 is not a Number + + If (LEqual (Local0, 0)) // Number is type 1 + { Return (0x72) } // non-existant signal was acquired + + Store ("One Lvalue PASS", Debug) + + // Lvalue Event test cases + // ILLEGAL SOURCE OPERAND Store (EVNT, Local2) + + // validate Local2 is an Event + Store (ObjectType (EVNT), Local1) + If (LNotEqual (Local1, 7)) // Event is type 7 + { Return (0x81) } // Local1 indicates Local0 is not a Number + + // reset EVNT to initialization (zero) state + Reset (EVNT) + + // prime EVNT with two outstanding signals + Signal (EVNT) + + // acquire existing signal + Store (Wait (EVNT, Arg0), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x82) } // Local1 indicates Local0 is not a Number + + If (LNotEqual (Local0, 0)) // Number is type 1 + { Return (0x83) } // timeout occurred without acquiring signal + + Store ("Acquire Lvalue existing signal PASS", Debug) + + + // acquire non-existing signal + Store (Wait (EVNT, Arg0), Local0) + + // validate Local0 is a Number + Store (ObjectType (Local0), Local1) + If (LNotEqual (Local1, 1)) // Number is type 1 + { Return (0x84) } // Local1 indicates Local0 is not a Number + + If (LEqual (Local0, 0)) // Number is type 1 + { Return (0x85) } // non-existant signal was acquired + + Store ("Acquire Lvalue signal timeout PASS", Debug) + + + Return (0) // success + } // TEVN control method to test ResetOp, SignalOp, and WaitOp + + Method (TEST) + { + Store ("++++++++ Event Test", Debug) + + Store (TEVN (100), Local0) + + Return (Local0) + } // TEST + } // EVNT + +// +// test SizeOfLv.asl +// +// Test for SizeOf (Lvalue) +// +// This next section will contain the packages that the SizeOfOp will be +// exercised on. The first one, PKG0, is a regular package of 3 elements. +// The 2nd one, PKG1, is a nested package with 3 packages inside it, each +// with 3 elements. It is expected that SizeOf operator will return the +// same value for these two packages since they both have 3 elements. The +// final package, PKG2, has 4 elements and the SizeOf operator is expected +// to return different results for this package. + + Name (PKG0, + Package (3) + {0x0123, 0x4567, 0x89AB} + ) // PKG0 + + Name (PKG1, + Package (3) + { + Package (3) {0x0123, 0x4567, 0x89AB}, + Package (3) {0xCDEF, 0xFEDC, 0xBA98}, + Package (3) {0x7654, 0x3210, 0x1234} + } + ) // PKG1 + + Name (PKG2, + Package (4) + {0x0123, 0x4567, 0x89AB, 0x8888} + ) // PKG2 + + Name (PKG3, + Package (5) + {0x0123, 0x4567, 0x89AB, 0x8888, 0x7777} + ) // PKG3 + +// End Packages ********************************************************** + +// The following section will declare the data strings that will be used to +// exercise the SizeOf operator. STR0 and STR1 are expected to be equal, +// STR2 is expected to have a different SizeOf value than STR0 and STR1. + + Name (STR0, "ACPI permits very flexible methods of expressing a system") + + Name (STR1, "MIKE permits very flexible methods of expressing a system") + + Name (STR2, "Needless to say, Mike and ACPI are frequently at odds") + +// This string is being made in case we want to do a SizeOf comparison +// between strings and packages or buffers + Name (STR3, "12345") + +// End Strings ********************************************************** + +// The following section will declare the buffers that will be used to exercise +// the SizeOf operator. + + Name (BUF0, Buffer (10) {}) + Name (BUF1, Buffer (10) {}) + Name (BUF2, Buffer (8) {}) + Name (BUF3, Buffer (5) {}) + +// End Buffers ********************************************************** + Device (SZLV) + { + + Method (CMPR, 2) + { + // CMPR is passed two arguments. If unequal, return 1 to indicate + // that, otherwise return 0 to indicate SizeOf each is equal. + + Store (0x01, Local0) + + if (LEqual (SizeOf(Arg0), SizeOf(Arg1))) + { + Store (0x00, Local0) + } + + return (Local0) + } // CMPR + + + Method (TEST) + { + + Store ("++++++++ SizeOfLv Test", Debug) + + // TBD: SizeOf ("string") + // SizeOf (Buffer) + // SizeOf (Package) + // SizeOf (String) + // SizeOf (STR0) -- where Name (STR0,...) -- lot's of cases + // buffer, string, package, + // SizeOf (METH) -- where METH control method returns + // buffer, string, package, + + // TBD: SLOC [SizeOf (Local0)] -- dup SARG + + // Compare the elements that we expect to be the same. Exit out with an error + // code on the first failure. + if (LNotEqual (0x00, CMPR (STR0, STR1))) + { + Return (0x01) + } + + if (LNotEqual (0x00, CMPR (STR3, BUF3))) + { + Return (0x02) + } + + if (LNotEqual (0x00, CMPR (STR3, PKG3))) + { + Return (0x03) + } + + // In the following section, this test will cover the SizeOf + // operator for Local values. + // In this case, both Local0 and Local1 should have the same Size + Store (STR0, Local0) + Store (STR1, Local1) + + if (LNotEqual (SizeOf (Local0), SizeOf (Local1))) + { + Return (0x04) + } + + // Now create a case where Local0 and Local1 are different + Store (STR2, Local1) + + if (LEqual (SizeOf (Local0), SizeOf (Local1))) + { + Return (0x05) + } + + // Finally, check for the return of SizeOf for a known Buffer. Just + // in case we magically pass above cases due to all Buffers being Zero + // bytes in size, or Infinity, etc. + if (LNotEqual (0x05, SizeOf (BUF3))) + { + Return (0x06) + } + + Return (0) + } // TEST + } // SZLV + + +// +// test BytField.asl +// +// BytField test +// This is just a subset of the many RegionOp/Index Field test cases. +// Tests access of TBD. +// + Scope (\_SB) // System Bus + { // _SB system bus + Device (BYTF) + { // Test device name + Method (TEST) + { + Store ("++++++++ BytField Test", Debug) + + Return (\_TZ.C19B.RSLT) + } // TEST + } // BYTF + + Device (C005) + { // Device C005 + Device (C013) + { // Device C013 + } // Device C013 + } // Device C005 + + Method (C115) + { // C115 control method + Acquire (\_GL, 0xFFFF) + Store (\_SB.C005.C013.C058.C07E, Local0) + Release (\_GL) + And (Local0, 16, Local0) + Store (ShiftRight (Local0, 4, ), Local1) + If (LEqual (Local1, 0)) + { Return (1) } + Else + { Return (0) } + } // C115 control method + } // _SB system bus + + OperationRegion (C018, SystemIO, 0x5028, 4) + Field (C018, AnyAcc, NoLock, Preserve) + { // Field overlaying C018 + C019, 32 + } // Field overlaying C018 + + OperationRegion (C01A, SystemIO, 0x5030, 4) + Field (C01A, ByteAcc, NoLock, Preserve) + { // Field overlaying C01A + C01B, 8, + C01C, 8, + C01D, 8, + C01E, 8 + } // Field overlaying C01A + + Mutex (\C01F, 0) + Name (\C020, 0) + Name (\C021, 0) + + Method (\C022, 0) + { // \C022 control method + Acquire (\C01F, 0xFFFF) + If (LEqual (\C021, 0)) + { + Store (C019, Local0) + And (Local0, 0xFFFEFFFE, Local0) + Store (Local0, C019) + Increment (\C021) + } + Release (\C01F) + } // \C022 control method + + Scope (\_SB.C005.C013) + { // Scope \_SB.C005.C013 + Device (C058) + { // Device C058 + Name (_HID, "*PNP0A06") + + OperationRegion (C059, SystemIO, 0xE0, 2) + Field (C059, ByteAcc, NoLock, Preserve) + { // Field overlaying C059 + C05A, 8, + C05B, 8 + } // Field overlaying C059 + + OperationRegion (C05C, SystemIO, 0xE2, 2) + Field (C05C, ByteAcc, NoLock, Preserve) + { // Field overlaying C05C + C05D, 8, + C05E, 8 + } // Field overlaying C05C + IndexField (C05D, C05E, ByteAcc, NoLock, Preserve) + { // IndexField overlaying C05D/C05E + , 0x410, // skip + C05F, 8, + C060, 8, + C061, 8, + C062, 8, + C063, 8, + C064, 8, + C065, 8, + C066, 8, + C067, 8, + C068, 8, + C069, 8, + C06A, 8, + C06B, 8, + C06C, 8, + C06D, 8, + C06E, 8, + , 0x70, // skip + C06F, 8, + C070, 8, + C071, 8, + C072, 8, + C073, 8, + C074, 8, + C075, 8, + C076, 8, + C077, 8, + C078, 8, + C079, 8, + C07A, 8, + C07B, 8, + C07C, 8, + C07D, 8, + C07E, 8 + } // IndexField overlaying C05D/C05E + + OperationRegion (C07F, SystemIO, 0xE4, 2) + Field (C07F, ByteAcc, NoLock, Preserve) + { // Field overlaying C07F + C080, 8, + C081, 8 + } // Field overlaying C07F + + OperationRegion (C082, SystemIO, 0xE0, 1) + Field (C082, ByteAcc, NoLock, Preserve) + { // Field overlaying C082 + C083, 8 + } // Field overlaying C082 + + OperationRegion (C084, SystemIO, 0xFF, 1) + Field (C084, ByteAcc, NoLock, Preserve) + { // Field overlaying C084 + C085, 8 + } // Field overlaying C084 + + OperationRegion (C086, SystemIO, 0xFD, 1) + Field (C086, ByteAcc, NoLock, Preserve) + { // Field overlaying C086 + C087, 8 + } // Field overlaying C086 + + Mutex (C088, 0) + Mutex (C089, 0) + Mutex (C08A, 0) + Mutex (C08B, 0) + Mutex (C08C, 0) + Mutex (C08D, 0) + + Name (C08E, 0xFFFFFFFD) + Name (C08F, 0) + + Method (C0AA, 4) + { // C0AA control method + Store (Buffer (4) {}, Local7) + CreateByteField (Local7, 0, C0AB) + CreateByteField (Local7, 1, C0AC) + CreateByteField (Local7, 2, C0AD) + CreateByteField (Local7, 3, C0AE) + Acquire (^C08B, 0xFFFF) + Acquire (\_GL, 0xFFFF) + \C022 () + Store (1, \_SB.C005.C013.C058.C06B) + While (LNot (LEqual (0, \_SB.C005.C013.C058.C06B))) + { Stall (100) } + Store (Arg3, \_SB.C005.C013.C058.C06E) + Store (Arg2, \_SB.C005.C013.C058.C06D) + Store (Arg1, \_SB.C005.C013.C058.C06C) + Store (Arg0, \_SB.C005.C013.C058.C06B) + While (LNot (LEqual (0, \_SB.C005.C013.C058.C06B))) + { Stall (100) } + Store (\_SB.C005.C013.C058.C06E, C0AB) + Store (\_SB.C005.C013.C058.C06D, C0AC) + Store (\_SB.C005.C013.C058.C06C, C0AD) + Store (\_SB.C005.C013.C058.C06B, C0AE) + If (LNot (LEqual (Arg0, 23))) + { + Store (2, \_SB.C005.C013.C058.C06B) + Stall (100) + } + Release (\_GL) + Release (^C08B) + Return (Local7) + } // C0AA control method + } // Device C058 + } // Scope \_SB.C005.C013 + + Scope (\_TZ) + { // \_TZ thermal zone scope + Name (C18B, Package (2) + { + Package (2) + { + Package (5) {0x05AC, 0x0CD2, 0x0D68, 0x0DE0, 0x0E4E}, + Package (5) {0x0D04, 0x0D9A, 0x0DFE, 0x0E80, 0x0FA2} + }, + Package (2) + { + Package (5) {0x05AC, 0x0CD2, 0x0D68, 0x0DE0, 0x0E4E}, + Package (5) {0x0D04, 0x0D9A, 0x0DFE, 0x0E80, 0x0FA2} + } + }) // C18B + + Name (C18C, Package (2) + { + Package (2) + { + Package (3) {0x64, 0x4B, 0x32}, + Package (3) {0x64, 0x4B, 0x32} + } + }) // C81C + + Name (C18D, 0) + Name (C18E, 0) + Name (C18F, 0) + Name (C190, 0) + Name (C191, 3) + Name (C192, 0) + Name (C193, 1) + Name (C194, 2) + Mutex (C195, 0) + Name (C196, 1) + Name (C197, 0x0B9C) + Name (C198, 0x0B9C) + Name (C199, 0xFFFFFFFD) + Name (C19A, 0) + + Device (C19B) + { // Device C19B + Name (RSLT, 0) // default to zero + + Method (XINI) + { // _INI control method (Uses Global Lock -- can't run under AcpiExec) + Store (\_SB.C115, C19A) + \_TZ.C19C._SCP (0) + Subtract (0x0EB2, 0x0AAC, Local1) // Local1 = AACh - EB2h + Divide (Local1, 10, Local0, Local2) // Local0 = Local1 / 10 + // Local2 = Local1 % 10 + \_SB.C005.C013.C058.C0AA (14, Local2, 0, 0) + Store + (DerefOf (Index (DerefOf (Index (\_TZ.C18C, C19A, )), 0, )), C18D) + Store + (DerefOf (Index (DerefOf (Index (\_TZ.C18C, C19A, )), 1, )), C18E) + Store + (DerefOf (Index (DerefOf (Index (\_TZ.C18C, C19A, )), 2, )), C18F) + + Store (1, RSLT) // set RSLT to 1 if _INI control method completes + } // _INI control method + + // PowerResource (C19D) {...} + } // Device C19B + + ThermalZone (C19C) + { + Method (_SCP, 1) + { // _SCP control method + Store (Arg0, Local0) + If (LEqual (Local0, 0)) + { + Store (0, \_TZ.C192) + Store (1, \_TZ.C193) + Store (2, \_TZ.C194) + Store (3, \_TZ.C191) + } + Else + { + Store (0, \_TZ.C191) + Store (1, \_TZ.C192) + Store (2, \_TZ.C193) + Store (3, \_TZ.C194) + } + } // _SCP control method + } // ThermalZone C19C + } // \_TZ thermal zone scope + + +// +// test DwrdFld.asl +// + Name (BUFR, buffer(10) {0,0,0,0,0,0,0,0,0,0} ) + + Device (DWDF) + { + Method (TEST) + { + Store ("++++++++ DwrdFld Test", Debug) + + CreateByteField (BUFR, 0, BYTE) + Store (0xAA, BYTE) + + CreateWordField (BUFR, 1, WORD) + Store (0xBBCC, WORD) + + CreateDWordField (BUFR, 3, DWRD) + Store (0xDDEEFF00, DWRD) + + CreateByteField (BUFR, 7, BYT2) + Store (0x11, BYT2) + + CreateWordField (BUFR, 8, WRD2) + Store (0x2233, WRD2) + + Return (0) + + } // End Method TEST + } // Device DWDF + + // + // test DivAddx.asl + // + Name (B1LO, 0xAA) + Name (B1HI, 0xBB) + + Method (MKW_, 2) + { // This control method will take two bytes and make them into a WORD + + Multiply (B1HI, 256, Local0) // Make high byte.....high + Or (Local0, B1LO, Local0) // OR in the low byte + Return (Local0) // Return the WORD + + } // MKW_ + + Device (DVAX) + { + Method (TEST) + { + + Store ("++++++++ DivAddx Test", Debug) + + Store (25, B1LO) + Store (0, B1HI) + + // We'll multiply 25 * 3 to get 75, add 99 to it then divide + // by 100. We expect to get 74 for the remainder and 1 for + // the quotient. + Divide( + Add (Multiply (3, MKW_ (B1LO, B1HI)), 0x63), + // Dividend, + 100, // Divisor + Local4, // Remainder + Local2) // Quotient + + If (LAnd (LEqual (74, Local4), LEqual (1, Local2))) + { // Indicate Pass + Store (0x00, Local0) + } + + Else + { // Indicate Fail + Store (0x01, Local0) + } + + Return (Local0) + } // End Method TEST + } // Device DVAX + +// +// test IndexFld.asl (IndexOp6.asl) +// +// IndexFld test +// This is just a subset of the many RegionOp/Index Field test cases. +// Tests index field element AccessAs macro. +// Also tests name resolution of index field elements with same names +// but different namespace scopes. +// + Device (IDX6) + { // Test device name + + OperationRegion (SIO, SystemIO, 0x100, 2) + Field (SIO, ByteAcc, NoLock, Preserve) + { + INDX, 8, + DATA, 8 + } + IndexField (INDX, DATA, AnyAcc, NoLock, WriteAsOnes) + { + AccessAs (ByteAcc, 0), + IFE0, 8, + IFE1, 8, + IFE2, 8, + IFE3, 8, + IFE4, 8, + IFE5, 8, + IFE6, 8, + IFE7, 8, + IFE8, 8, + IFE9, 8, + } + + Device (TST_) + { // TST_: provides a different namespace scope for IFE0 and IFE1 + OperationRegion (SIO2, SystemIO, 0x100, 2) + Field (SIO2, ByteAcc, NoLock, Preserve) + { + IND2, 8, + DAT2, 8 + } + IndexField (IND2, DAT2, AnyAcc, NoLock, WriteAsOnes) + { + IFE0, 8, // duplicate IndexField name with different scope + IFE1, 8 + } + } // TST_: provides a different namespace scope for IFE0 and IFE1 + + Method (TEST) + { + Store ("++++++++ IndexOp6 Test", Debug) + + Store (IFE0, Local0) + Store (IFE1, Local1) + Store (IFE2, Local2) + + // validate name resolution of IndexFields with different scopes + Store (\IDX6.IFE0, Local3) + Store (\IDX6.IFE1, Local4) + // verioading of namespace can resolve following names + Store (\IDX6.TST_.IFE0, Local5) + Store (\IDX6.TST_.IFE1, Local6) + + Return (0) + } // TEST + } // IDX6 + +// +// test IndexOp5.asl +// +// IndexOp5 test +// This is just a subset of the many RegionOp/Index Field test cases. +// Tests copying string into buffer then performing IndexOp on result. +// + Device (IDX5) + { // Test device name + + Name (OSFL, 0) // 0 == Windows 98, 1 == Windows NT + + // MCTH is a control method to compare two strings. It returns + // zero if the strings mismatch, or 1 if the strings match. + // This exercises the test case of copying a string into a buffer + // and performing an IndexOp on the resulting buffer. + Method (MCTH, 2, Serialized) // Control Method to compare two strings + { // MCTH: Control Method to compare two strings + // Arg0: first string to compare + // Arg1: second string to compare + // Return: zero if strings mismatch, 1 if strings match + + // check if first string's length is less than second string's length + If (LLess (SizeOf (Arg0), SizeOf (Arg1))) + { Return (0) } + + // increment length to include NULL termination character + Add (SizeOf (Arg0), 1, Local0) // Local0 = strlen(Arg0) + 1 + + // create two buffers of size Local0 [strlen(Arg0)+1] + Name (BUF0, Buffer (Local0) {}) + Name (BUF1, Buffer (Local0) {}) + + // copy strings into buffers + Store (Arg0, BUF0) + Store (Arg1, BUF1) + + // validate BUF0 and BUF1 are still buffers + Store (ObjectType (BUF0), Local1) + If (LNotEqual (Local1, 3)) // Buffer is type 3 + { Return (20) } + Store (ObjectType (BUF1), Local1) + If (LNotEqual (Local1, 3)) // Buffer is type 3 + { Return (21) } + + // Decrement because the Index base below is zero based + // while Local0 length is one based. + Decrement (Local0) + + While (Local0) + { // loop through all BUF0 buffer elements + Decrement (Local0) + + // check if BUF0[n] == BUF1[n] + If (LEqual (DerefOf (Index (BUF0, Local0, )), + DerefOf (Index (BUF1, Local0, )))) + { } // this is how the code was really implemented + Else + { Return (Zero) } + } // loop through all BUF0 buffer elements + + Return (One) // strings / buffers match + } // MCTH: Control Method to compare two strings + + + Method (TEST) + { + Store ("++++++++ IndexOp5 Test", Debug) + + If (MCTH (\_OS, "Microsoft Windows NT")) + { Store (1, OSFL) } + + If (LNotEqual (OSFL, 1)) + { Return (11) } + + Return (0) + } // TEST + } // IDX5 + +// +// test IndexOp.asl +// + Scope (\_SB) // System Bus + { // _SB system bus + + Method (C097) + { Return (1) } + + Device (PCI2) + { // Root PCI Bus + Name (_HID, EISAID("PNP0A03")) + Name (_ADR, 0x00000000) + Name (_CRS, Buffer(26) {"\_SB_.PCI2._CRS..........."}) + Method (_STA) {Return (0x0F)} + + Device (ISA) + { // ISA bridge + Name (_ADR, 0x00030000) // ISA bus ID + + Device (EC0) + { // Embedded Controller + Name (_GPE, 0) // EC use GPE0 + Name (_ADR, 0x0030000) // PCI address + + Method (_STA,0) // EC Status + { Return(0xF) } // EC is functioning + + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x62, 0x62, 1, 1) + IO (Decode16, 0x66, 0x66, 1, 1) + } + ) + + // create EC's region and field + OperationRegion (RAM, SystemMemory, 0x400000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { + // AC information + ADP, 1, // AC Adapter 1:On-line, 0:Off-line + AFLT, 1, // AC Adapter Fault 1:Fault 0:Normal + BAT0, 1, // BAT0 1:present, 0:not present + , 1, // reserved + , 28, // filler to force DWORD alignment + + // CMBatt information + BPU0, 32, // Power Unit + BDC0, 32, // Designed Capacity + BFC0, 32, // Last Full Charge Capacity + BTC0, 32, // Battery Technology + BDV0, 32, // Design Voltage + BST0, 32, // Battery State + BPR0, 32, // Battery Present Rate + // (Designed Capacity)x(%)/{(h)x100} + BRC0, 32, // Battery Remaining Capacity + // (Designed Capacity)(%)^100 + BPV0, 32, // Battery Present Voltage + BTP0, 32, // Trip Point + BCW0, 32, // Design capacity of Warning + BCL0, 32, // Design capacity of Low + BCG0, 32, // capacity granularity 1 + BG20, 32, // capacity granularity 2 + BMO0, 32, // Battery model number field + BIF0, 32, // OEM Information(00h) + BSN0, 32, // Battery Serial Number + BTY0, 32, // Battery Type (e.g., "Li-Ion") + BTY1, 32 // Battery Type (e.g., "Li-Ion") + } // Field + } // EC0: Embedded Controller + } // ISA bridge + } // PCI2 Root PCI Bus + + Device (IDX0) + { // Test device name + Name (_HID, EISAID ("PNP0C0A")) // Control Method Battey ID + Name (_PCL, Package() {\_SB}) + Method (_STA) + { + // _STA bits 0-3 indicate existence of battery slot + // _STA bit 4 indicates battery (not) present + If (\_SB.PCI2.ISA.EC0.BAT0) + { Return (0x1F) } // Battery present + else + { Return (0x0F) } // Battery not present + } // _STA + + Method (_BIF,, Serialized) + { + Name (BUFR, Package(13) {}) + Store (\_SB.PCI2.ISA.EC0.BPU0, Index (BUFR,0)) // Power Unit + Store (\_SB.PCI2.ISA.EC0.BDC0, Index (BUFR,1)) // Designed Capacity + Store (\_SB.PCI2.ISA.EC0.BFC0, Index (BUFR,2)) // Last Full Charge Capa. + Store (\_SB.PCI2.ISA.EC0.BTC0, Index (BUFR,3)) // Battery Technology + Store (\_SB.PCI2.ISA.EC0.BDV0, Index (BUFR,4)) // Designed Voltage + Store (\_SB.PCI2.ISA.EC0.BCW0, Index (BUFR,5)) // Designed warning level + Store (\_SB.PCI2.ISA.EC0.BCL0, Index (BUFR,6)) // Designed Low level + Store (\_SB.PCI2.ISA.EC0.BCG0, Index (BUFR,7)) // Capacity granularity 1 + Store (\_SB.PCI2.ISA.EC0.BG20, Index (BUFR,8)) // Capacity granularity 2 + + Store ("", Index (BUFR,9)) // Model Number + + Store ("", Index (BUFR,10)) // Serial Number + + Store ("LiOn", Index (BUFR,11)) // Battery Type + + Store ("Chicony", Index (BUFR,12)) // OEM Information + + Return (BUFR) + } // _BIF + + Method (_BST,, Serialized) + { + Name (BUFR, Package(4) {1, 0x100, 0x76543210, 0x180}) + Return (BUFR) + } // _BST + + Method (_BTP,1) + { + Store (arg0, \_SB.PCI2.ISA.EC0.BTP0) // Set Battery Trip point + } + + Method (TEST,, Serialized) + { + + Store ("++++++++ IndexOp Test", Debug) + + // test storing into uninitialized package elements + Name (PBUF, Package(4) {}) // leave unitialized + Store (0x01234567, Index (PBUF,0)) + Store (0x89ABCDEF, Index (PBUF,1)) + Store (0xFEDCBA98, Index (PBUF,2)) + Store (0x76543210, Index (PBUF,3)) + + // verify values stored into uninitialized package elements + If (LNotEqual (DerefOf (Index (PBUF,0)), 0x01234567)) + { Return (0x10) } + + If (LNotEqual (DerefOf (Index (PBUF,1)), 0x89ABCDEF)) + { Return (0x11) } + + If (LNotEqual (DerefOf (Index (PBUF,2)), 0xFEDCBA98)) + { Return (0x12) } + + If (LNotEqual (DerefOf (Index (PBUF,3)), 0x76543210)) + { Return (0x13) } + + + // store _BIF package return value into Local0 + Store (_BIF, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Package + If (LNotEqual (Local1, 4)) // Package type is 4 + { Return (0x21) } // failure + + + // test storing into buffer field elements + Name (BUFR, Buffer(16) + { // initial values + 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, + } + ) // BUFR + // test storing into buffer field elements + Store (0x01234567, Index (BUFR,0)) // should only store 0x67 + Store (0x89ABCDEF, Index (BUFR,4)) // should only store 0xEF + Store (0xFEDCBA98, Index (BUFR,8)) // should only store 0x98 + Store (0x76543210, Index (BUFR,12)) // should only store 0x10 + + // verify storing into buffer field elements + If (LNotEqual (DerefOf (Index (BUFR,0)), 0x67)) + { Return (0x30) } + + If (LNotEqual (DerefOf (Index (BUFR,1)), 0)) + { Return (0x31) } + + If (LNotEqual (DerefOf (Index (BUFR,4)), 0xEF)) + { Return (0x34) } + + If (LNotEqual (DerefOf (Index (BUFR,8)), 0x98)) + { Return (0x38) } + + If (LNotEqual (DerefOf (Index (BUFR,12)), 0x10)) + { Return (0x3C) } + + + Return (0) // pass + } // TEST + } // IDX0 + } // _SB system bus + +// +// test BitIndex.asl +// +// BitIndex test +// This is a test case for accessing fields defined as single bits in +// memory. This is done by creating two index fields that overlay the +// same DWORD in memory. One field accesses the DWORD as a DWORD, the +// other accesses individual bits of the same DWORD field in memory. +// + Scope (\_SB) // System Bus + { // _SB system bus + OperationRegion (RAM, SystemMemory, 0x800000, 0x100) + Field (RAM, AnyAcc, NoLock, Preserve) + { // Any access + TREE, 3, + WRD0, 16, + WRD1, 16, + WRD2, 16, + WRD3, 16, + WRD4, 16, + DWRD, 32, // DWORD field + } + Field (RAM, AnyAcc, NoLock, Preserve) + { // Any access + THRE, 3, + WD00, 16, + WD01, 16, + WD02, 16, + WD03, 16, + WD04, 16, + BYT0, 8, // Start off with a BYTE + BIT0, 1, // single-bit field + BIT1, 1, // single-bit field + BIT2, 1, // single-bit field + BIT3, 1, // single-bit field + BIT4, 1, // single-bit field + BIT5, 1, // single-bit field + BIT6, 1, // single-bit field + BIT7, 1, // single-bit field + BIT8, 1, // single-bit field + BIT9, 1, // single-bit field + BITA, 1, // single-bit field + BITB, 1, // single-bit field + BITC, 1, // single-bit field + BITD, 1, // single-bit field + BITE, 1, // single-bit field + BITF, 1, // single-bit field + BYTZ, 8, // End with a BYTE for a total of 32 bits + } + + Device (BITI) + { // Test device name + + Method (MBIT) // Test single bit memory accesses + { + + If (LNotEqual (DWRD, 0x00)) + { + Store (0xFF00, Local0) + } + Else + { + // Prime Local0 with 0...assume passing condition + Store (0, Local0) + + // set memory contents to known values using DWORD field + Store (0x5A5A5A5A, DWRD) + + // Given the value programmed into DWRD, only the odd bits + // of the lower nibble should be set. BIT1, BIT3 should be set. + // BIT0 and BIT2 should be clear + + If (BIT0) + { + Or (Local0, 0x01, Local0) + } + + If (LNot (BIT1)) + { + Or (Local0, 0x02, Local0) + } + + If (BIT2) + { + Or (Local0, 0x04, Local0) + } + + If (LNot (BIT3)) + { + Or (Local0, 0x08, Local0) + } + + // Now check the upper nibble. Only the "even" bits should + // be set. BIT4, BIT6. BIT5 and BIT7 should be clear. + If (LNot (BIT4)) + { + Or (Local0, 0x10, Local0) + } + + If (BIT5) + { + Or (Local0, 0x20, Local0) + } + + If (LNot (BIT6)) + { + Or (Local0, 0x40, Local0) + } + + If (BIT7) + { + Or (Local0, 0x80, Local0) + } + } // End Else DWRD zeroed out + + Return (Local0) + } // MBIT: Test single bit memory accesses + + Method (TEST) + { + + Store ("++++++++ BitIndex Test", Debug) + + // Zero out DWRD + Store (0x00000000, DWRD) + + // MBIT returns zero if successful + // This may be causing problems -- Return (MBIT) + Store (MBIT, Local0) + + Return (Local0) + } // TEST + } // BITI + } // _SB system bus + +// +// test IndexOp3.asl +// +// Additional IndexOp test cases to support ACPICMB (control method battery +// test) on Compaq laptops. Test cases include storing a package into +// an IndexOp target and validating that changing source and destination +// package contents are independent of each other. +// + Scope (\_SB) // System Bus + { // _SB system bus + + Name (C174, 13) + Name (C175, 8) + + Device (C158) + { // C158: AC Adapter device + Name (_HID, "ACPI0003") // AC Adapter device + Name (_PCL, Package (1) {\_SB}) + + Method (_PSR) + { + Acquire (\_GL, 0xFFFF) + Release (\_GL) + And (Local0, 1, Local0) // Local0 &= 1 + Return (Local0) + } // _PSR + } // C158: AC Adapter device + + Name (C176, Package (4) {"Primary", "MultiBay", "DockRight", "DockLeft"}) + + Name (C177, Package (4) {0x99F5, 0x99F5, 0x995F, 0x995F}) + + Name (C178, Package (4) + { + Package (4) {0, 0, 0x966B, 0x4190}, + Package (4) {0, 0, 0x966B, 0x4190}, + Package (4) {0, 0, 0x966B, 0x4190}, + Package (4) {0, 0, 0x966B, 0x4190} + }) // C178 + + Name (C179, Package (4) {0, 0, 0x966B, 0x4190}) + + Name (C17A, Package (4) + { + Package (3) {0, 0, 0}, + Package (3) {0, 0, 0}, + Package (3) {0, 0, 0}, + Package (3) {0, 0, 0} + }) // C17A + + Method (C17B, 1, Serialized) + { // C17B: _BIF implementation + Name (C17C, Package (13) + { // C17C: _BIF control method return package + 0, // Power Unit (0 ==> mWh and mW) + 0x99F5, // Design Capacity + 0x99F5, // Last Full Charge Capacity + 1, // Battery Technology (1 ==> rechargeable) + 0x3840, // Design Voltage + 0x1280, // Design Capacity of Warning + 0x0AC7, // Design Capacity of Low + 1, // Battery Capacity Granularity 1 (Low -- Warning) + 1, // Battery Capacity Granularity 2 (Warning -- Full) + "2891", // Model Number (ASCIIZ) + "(-Unknown-)", // Serial Number (ASCIIZ) + "LIon", // Battery Type (ASCIIZ) + 0 // OEM Information (ASCIIZ) + }) // C17C: _BIF control method return package + + And (Arg0, 7, Local0) // Local0 = Arg0 & 7 + + ShiftRight (Local0, 1, Local4) // Local4 = Local0 >> 1 + + Store (C179, Index (C178, Local4, )) // C178->Local4 = C179 + + // verify source and destination packages can be altered independent + // of each other (i.e., changing one's contents does NOT change other's + // contents) + Store (0x1234, Index (C179, 2, )) // C179[2] = 0x1234 + Store (DerefOf (Index (C179, 2, )), Local2) // Local2 = C179[2] + if (LNotEqual (Local2, 0x1234)) + { Return (0x1234) } + // Local2 = C178[0,2] + Store (DerefOf (Index (DerefOf (Index (C178, 0, )), 2, )), Local2) + if (LNotEqual (Local2, 0x966B)) + { Return (0x1234) } + + // Restore data to allow iterative execution + Store (0x966B, Index (C179, 2, )) // C179[2] = 0x966B + + // C178[0,3] = 0x5678 + Store (0x5678, Index (DerefOf (Index (C178, 0, )), 3, )) + // Local2 = C178[0,3] + Store (DerefOf (Index (DerefOf (Index (C178, 0, )), 3, )), Local2) + if (LNotEqual (Local2, 0x5678)) + { Return (0x5678) } + + Store (DerefOf (Index (C179, 3, )), Local2) // Local2 = C179[3] + if (LNotEqual (Local2, 0x4190)) + { Return (0x5678) } + + // Restore data to allow iterative execution + Store (0x4190, Index (DerefOf (Index (C178, 0, )), 3, )) // C179[2] = 0x4190 + + Return (C17C) + } // C17B: _BIF implementation + + Device (C154) + { // C154: Battery 0 + Name (_HID, "*PNP0C0A") // Control Method Battey ID + Name (_UID, 0) // first instance + + Method (_BIF) + { // _BIF + Return (C17B (48)) + } // _BIF + } // C154: Battery 0 + + Device (IDX3) + { + Method (LCLB,, Serialized) + { // LCLB control method: test Index(Local#) where Local# is buffer + // Local0 is index counter + // Local1 is buffer + // Local2 receives BUFR[Local0] via Deref(Index(Local1...)) + // Local3 is Local1 or Local2 object type + // Local4 is return error code + + Name (BUFR, Buffer () {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) + + // save PKG into Local1 + Store (BUFR, Local1) + + // save Local2 object type value into Local3 + Store (ObjectType (Local1), Local3) + + // validate Local1 is a Buffer + If (LNotEqual (Local3, 3)) // Buffer type is 3 + { Return (0x9F) } + + + Store (0, Local0) + While (LLess (Local0, 5)) + { // While (Local0 < 5) + // Local2 = Local1[Local0] + Store (DerefOf (Index (Local1, Local0, )), Local2) + + // save Local2 object type value into Local3 + Store (ObjectType (Local2), Local3) + + // validate Local2 is a Number + If (LNotEqual (Local3, 1)) // Number type is 1 + { Return (0x9E) } + + // validate Local1[Local0] value == Local0 + If (LNotEqual (Local0, Local2)) + { // Local0 != Local2 == PKG[Local0] + // Local4 = 0x90 + loop index (Local0) + Add (0x90, Local0, Local4) + + // return 0x90 + loop index + Return (Local4) + } + + Increment (Local0) + } // While (Local0 < 5) + + Store ("DerefOf(Index(LocalBuffer,,)) PASS", Debug) + + Return (0) // Pass + } // LCLB control method: test Index(Local#) where Local# is buffer + + Method (LCLP,, Serialized) + { // LCLP control method: test Index(Local#) where Local# is package + // Local0 is index counter + // Local1 is package + // Local2 receives PKG[Local0] via Deref(Index(Local1...)) + // Local3 is Local1 or Local2 object type + // Local4 is return error code + + Name (PKG, Package () {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) + + // save PKG into Local1 + Store (PKG, Local1) + + // save Local2 object type value into Local3 + Store (ObjectType (Local1), Local3) + + // validate Local1 is a Package + If (LNotEqual (Local3, 4)) // Package type is 4 + { Return (0x8F) } + + + Store (0, Local0) + While (LLess (Local0, 5)) + { // While (Local0 < 5) + // Local2 = Local1[Local0] + Store (DerefOf (Index (Local1, Local0, )), Local2) + + // save Local2 object type value into Local3 + Store (ObjectType (Local2), Local3) + + // validate Local2 is a Number + If (LNotEqual (Local3, 1)) // Number type is 1 + { Return (0x8E) } + + // validate Local1[Local0] value == Local0 + If (LNotEqual (Local0, Local2)) + { // Local0 != Local2 == PKG[Local0] + // Local4 = 0x80 + loop index (Local0) + Add (0x80, Local0, Local4) + + // return 0x80 + loop index + Return (Local4) + } + + Increment (Local0) + } // While (Local0 < 5) + + Store ("DerefOf(Index(LocalPackage,,)) PASS", Debug) + + Return (0) // Pass + } // LCLP control method: test Index(Local#) where Local# is package + + Method (TEST) + { + + Store ("++++++++ IndexOp3 Test", Debug) + + // store _BIF package return value into Local0 + Store (\_SB.C154._BIF, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Package + If (LNotEqual (Local1, 4)) // Package type is 4 + { // failure: did not return a Package (type 4) + // if Local0 is a Number, it contains an error code + If (LEqual (Local1, 1)) // Number type is 1 + { Return (Local0) } // return Local0 error code + Else // Local0 is not a Number + { Return (1) } // return default error code + } // failure: did not return a Package (type 4) + + // save LCLB control method return value into Local2 + Store (LCLB, Local2) + If (LNotEqual (Local2, 0)) + { Return (Local2) } // return failure code + + // save LCLP control method return value into Local2 + Store (LCLP, Local2) + If (LNotEqual (Local2, 0)) + { Return (Local2) } // return failure code + + Return (0) // Pass + } // TEST + } // IDX3: Test device name + } // _SB system bus + +// +// MTL developed test to exercise Indexes into buffers +// + Device(IDX7) + { + + Name (PKG4, Package() { + 0x2, + "A short string", + Buffer() {0xA, 0xB, 0xC, 0xD}, + 0x1234, + Package() {IDX7, 0x3} + }) + + // + // Generic Test method + // + // This test returns 0xE (14) - ObjectType = Buffer Field + Method(TST1,, Serialized) + { + Name (DEST, Buffer () // 62 characters plus NULL + {"Destination buffer that is longer than the short source buffer"}) + + // verify object type returned by Index(Buffer,Element,) + Store (Index (DEST, 2, ), Local1) + Store (ObjectType (Local1), Local2) + If (LEqual(Local2, 14)) + { + Return(0) + } + Else + { + Return(0x1) + } + + } + + Method(TST2,, Serialized) + { + Name (BUF0, Buffer() {0x1, 0x2, 0x3, 0x4, 0x5}) + Store(0x55, Index(BUF0, 2)) + Store(DerefOf(Index(BUF0, 2)), Local0) + If (LEqual(Local0, 0x55)) + { + Return(0) + } + Else + { + Return(0x2) + } + + + } + + Method(TST3,, Serialized) + { + Name (BUF1, Buffer() {0x1, 0x2, 0x3, 0x4, 0x5}) + Store(Index(BUF1, 1), Local0) + Store(DerefOf(Local0), Local1) + If (LEqual(Local1, 0x2)) + { + Return(0) + } + Else + { + Return(0x3) + } + + } + + Method(TST4) + { + // Index (PKG4, 0) is a Number + Store (Index (PKG4, 0), Local0) + Store (ObjectType(Local0), Local1) + If (LEqual(Local1, 0x1)) + { + Return(0) + } + Else + { + Return(0x4) + } + + } + + Method(TST5) + { + // Index (PKG4, 1) is a String + Store (Index (PKG4, 1), Local0) + Store (ObjectType(Local0), Local1) + If (LEqual(Local1, 0x2)) + { + Return(0) + } + Else + { + Return(0x5) + } + + } + + Method(TST6) + { + // Index (PKG4, 2) is a Buffer + Store (Index (PKG4, 2), Local0) + Store (ObjectType(Local0), Local1) + If (LEqual(Local1, 0x3)) + { + Return(0) + } + Else + { + Return(0x6) + } + + } + + Method(TST7) + { + // Index (PKG4, 3) is a Number + Store (Index (PKG4, 3), Local0) + Store (ObjectType(Local0), Local1) + If (LEqual(Local1, 0x1)) + { + Return(0) + } + Else + { + Return(0x7) + } + + } + + Method(TST8) + { + // Index (PKG4, 4) is a Package + Store (Index (PKG4, 4), Local0) + Store (ObjectType(Local0), Local1) + If (LEqual(Local1, 0x4)) + { + Return(0) + } + Else + { + Return(0x8) + } + + } + + Method(TST9) + { + // DerefOf (Index (PKG4, 0)) is a Number + Store (DerefOf (Index (PKG4, 0)), Local0) + If (LEqual(Local0, 0x2)) + { + Return(0) + } + Else + { + Return(0x9) + } + + } + + Method(TSTA) + { + // DerefOf (Index (PKG4, 1)) is a String + Store (DerefOf (Index (PKG4, 1)), Local0) + Store (SizeOf(Local0), Local1) + If (LEqual(Local1, 0xE)) + { + Return(0) + } + Else + { + Return(0xA) + } + + } + + Method(TSTB) + { + // DerefOf (Index (PKG4, 2)) is a Buffer + Store (DerefOf (Index (PKG4, 2)), Local0) + Store (SizeOf(Local0), Local1) + If (LEqual(Local1, 0x4)) + { + Return(0) + } + Else + { + Return(0xB) + } + + } + + Method(TSTC) + { + // DerefOf (Index (PKG4, 3)) is a Number + Store (DerefOf (Index (PKG4, 3)), Local0) + If (LEqual(Local0, 0x1234)) + { + Return(0) + } + Else + { + Return(0xC) + } + + } + + Method(TSTD) + { + // DerefOf (Index (PKG4, 4)) is a Package + Store (DerefOf (Index (PKG4, 4)), Local0) + Store (SizeOf(Local0), Local1) + If (LEqual(Local1, 0x2)) + { + Return(0) + } + Else + { + Return(0xD) + } + + } + + Method(TSTE) + { + // DerefOf (Index (PKG4, 2)) is a Buffer + Store (DerefOf (Index (PKG4, 2)), Local0) + // DerefOf (Index (Local0, 1)) is a Number + Store (DerefOf (Index (Local0, 1)), Local1) + If (LEqual(Local1, 0xB)) + { + Return(0) + } + Else + { + Return(0xE) + } + + } + + Method (TSTF,, Serialized) + { + Name (SRCB, Buffer (12) {}) // 12 characters + Store ("Short Buffer", SRCB) + + Name (DEST, Buffer () // 62 characters plus NULL + {"Destination buffer that is longer than the short source buffer"}) + + // overwrite DEST contents, starting at buffer position 2 + Store (SRCB, Index (DEST, 2)) + + // + // The DEST buffer element should be replaced with the last element of + // the SRCB element (i.e. 's'->'r') + Store (DerefOf (Index (DEST, 2)), Local0) + + If (LNotEqual (Local0, 0x72)) // 'r' + { + // DEST element does not match the value from SRCB + Return(Or(Local0, 0x1000)) + } + + Return(0) + } + + Method (TSTG,, Serialized) + { + + Name (SRCB, Buffer (12) {}) // 12 characters + Store ("Short Buffer", SRCB) + + Name (DEST, Buffer () // 62 characters plus NULL + {"Destination buffer that is longer than the short source buffer"}) + + // overwrite DEST contents, starting at buffer position 2 + Store (SRCB, Index (DEST, 2)) + + // + // The next element of DEST should be unchanged + // + Store (DerefOf (Index (DEST, 3)), Local0) + + If (LNotEqual (Local0, 0x74)) // 't' + { + // DEST has been changed + Return(Or(Local0, 0x2000)) + } + + // + // The next element of DEST should be unchanged + // + Store (DerefOf (Index (DEST, 4)), Local0) + + If (LNotEqual (Local0, 0x69)) // 'i' + { + // DEST has been changed + Return(Or(Local0, 0x2100)) + } + + // + // The next element of DEST should be unchanged + // + Store (DerefOf (Index (DEST, 5)), Local0) + + If (LNotEqual (Local0, 0x6E)) // 'n' + { + // DEST has been changed + Return(Or(Local0, 0x2200)) + } + + // + // The next element of DEST should be unchanged + // + Store (DerefOf (Index (DEST, 6)), Local0) + + If (LNotEqual (Local0, 0x61)) // 'a' + { + // DEST has been changed + Return(Or(Local0, 0x2300)) + } + + // + // The next element of DEST should be unchanged + // + Store (DerefOf (Index (DEST, 7)), Local0) + + If (LNotEqual (Local0, 0x74)) // 't' + { + // DEST has been changed + Return(Or(Local0, 0x2400)) + } + + // + // Verify DEST elements beyond end of SRCB buffer copy + // have not been changed + Store (DerefOf (Index (DEST, 14)), Local0) + + If (LNotEqual (Local0, 0x66)) // 'f' + { + // DEST has been changed + Return(Or(Local0, 0x2400)) + } + + Return(0) + } + + // + // This test shows that MS ACPI.SYS stores only the lower 8-bits of a 32-bit + // number into the index'ed buffer + // + Method (TSTH,, Serialized) + { + // Create a Destination Buffer + Name (DBUF, Buffer () {"abcdefghijklmnopqrstuvwxyz"}) + + // Store a number > UINT8 into an index of the buffer + Store (0x12345678, Index(DBUF, 2)) + + // Check the results + Store (DerefOf (Index (DBUF, 2)), Local0) + If (LNotEqual (Local0, 0x78)) // 0x78 + { + Return(Or(Local0, 0x3000)) + } + + Store (DerefOf (Index (DBUF, 3)), Local0) + If (LNotEqual (Local0, 0x64)) // 'd' + { + Return(Or(Local0, 0x3100)) + } + + Store (DerefOf (Index (DBUF, 4)), Local0) + If (LNotEqual (Local0, 0x65)) // 'e' + { + Return(Or(Local0, 0x3200)) + } + + Store (DerefOf (Index (DBUF, 5)), Local0) + If (LNotEqual (Local0, 0x66)) // 'f' + { + Return(Or(Local0, 0x3300)) + } + + Return(0) + } + + Method (TSTI,, Serialized) + { + // Create a Destination Buffer + Name (DBUF, Buffer () {"abcdefghijklmnopqrstuvwxyz"}) + + // Store a String into an index of the buffer + Store ("ABCDEFGH", Index(DBUF, 2)) + + // Check the results + Store (DerefOf (Index (DBUF, 2)), Local0) + If (LNotEqual (Local0, 0x48)) // 'H' + { + Return(Or(Local0, 0x4000)) + } + + Store (DerefOf (Index (DBUF, 3)), Local0) + If (LNotEqual (Local0, 0x64)) // 'd' + { + Return(Or(Local0, 0x4100)) + } + + Store (DerefOf (Index (DBUF, 4)), Local0) + If (LNotEqual (Local0, 0x65)) // 'e' + { + Return(Or(Local0, 0x4200)) + } + + Store (DerefOf (Index (DBUF, 5)), Local0) + If (LNotEqual (Local0, 0x66)) // 'f' + { + Return(Or(Local0, 0x4300)) + } + + Return(0) + } + + Method(TSTJ,, Serialized) + { + // Create a Destination Buffer + Name (DBUF, Buffer () {"abcdefghijklmnopqrstuvwxyz"}) + + // Store a number > UINT8 into an index of the buffer + Store (0x1234, Index(DBUF, 2)) + + // Check the results + Store (DerefOf (Index (DBUF, 2)), Local0) + If (LNotEqual (Local0, 0x34)) // 0x34 + { + Return(Or(Local0, 0x3000)) + } + + Store (DerefOf (Index (DBUF, 3)), Local0) + If (LNotEqual (Local0, 0x64)) // 'd' + { + Return(Or(Local0, 0x3100)) + } + + Store (DerefOf (Index (DBUF, 4)), Local0) + If (LNotEqual (Local0, 0x65)) // 'e' + { + Return(Or(Local0, 0x3200)) + } + + Store (DerefOf (Index (DBUF, 5)), Local0) + If (LNotEqual (Local0, 0x66)) // 'f' + { + Return(Or(Local0, 0x3300)) + } + + Return(0) + } + + Method(TSTK,, Serialized) + { + // Create a Destination Buffer + Name (DBUF, Buffer () {"abcdefghijklmnopqrstuvwxyz"}) + + // Store a number > UINT8 into an index of the buffer + Store (0x123456, Index(DBUF, 2)) + + // Check the results + Store (DerefOf (Index (DBUF, 2)), Local0) + If (LNotEqual (Local0, 0x56)) // 0x56 + { + Return(Or(Local0, 0x3000)) + } + + Store (DerefOf (Index (DBUF, 3)), Local0) + If (LNotEqual (Local0, 0x64)) // 'd' + { + Return(Or(Local0, 0x3100)) + } + + Store (DerefOf (Index (DBUF, 4)), Local0) + If (LNotEqual (Local0, 0x65)) // 'e' + { + Return(Or(Local0, 0x3200)) + } + + Store (DerefOf (Index (DBUF, 5)), Local0) + If (LNotEqual (Local0, 0x66)) // 'f' + { + Return(Or(Local0, 0x3300)) + } + + Return(0) + } + + Method(TSTL,, Serialized) + { + // Create a Destination Buffer + Name (DBUF, Buffer () {"abcdefghijklmnopqrstuvwxyz"}) + + // Store a number > UINT8 into an index of the buffer + Store (0x12, Index(DBUF, 2)) + + // Check the results + Store (DerefOf (Index (DBUF, 2)), Local0) + If (LNotEqual (Local0, 0x12)) // 0x12 + { + Return(Or(Local0, 0x3000)) + } + + Store (DerefOf (Index (DBUF, 3)), Local0) + If (LNotEqual (Local0, 0x64)) // 'd' + { + Return(Or(Local0, 0x3100)) + } + + Store (DerefOf (Index (DBUF, 4)), Local0) + If (LNotEqual (Local0, 0x65)) // 'e' + { + Return(Or(Local0, 0x3200)) + } + + Store (DerefOf (Index (DBUF, 5)), Local0) + If (LNotEqual (Local0, 0x66)) // 'f' + { + Return(Or(Local0, 0x3300)) + } + + Return(0) + } + + Method(TEST) + { + Store ("++++++++ IndexOp7 Test", Debug) + + Store(TST1(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST2(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST3(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST4(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST5(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST6(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST7(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST8(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TST9(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTA(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTB(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTC(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTD(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTE(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + /* No longer ACPI compliant */ + /* + Store(TSTF(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + */ + + Store(TSTG(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTH(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + /* No longer ACPI compliant */ + /* + Store(TSTI(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + */ + Store(TSTJ(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTK(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Store(TSTL(), Local0) + if (LGreater (Local0, 0)) + { + Return(Local0) + } + + Return(Local0) + + } + + } // Device(IDX7) + +// +// test MatchOp.asl +// +// MatchOp test cases that utilize nested DerefOf(Index(...)) to validate +// MatchOp, DerefOfOp, and IndexOp of nested packages. +// + Device (MTCH) + { + + Method (TEST,, Serialized) + { + Store ("++++++++ MatchOp Test", Debug) + + Name (TIM0, Package () + { + Package () {0x78, 0xB4, 0xF0, 0x0384}, + Package () {0x23, 0x21, 0x10, 0}, + Package () {0x0B, 9, 4, 0}, + Package () {0x70, 0x49, 0x36, 0x27, 0x19}, + Package () {0, 1, 2, 1, 2}, + Package () {0, 0, 0, 1, 1}, + Package () {4, 3, 2, 0}, + Package () {2, 1, 0, 0} + }) // TIM0 + + Name (TMD0, Buffer (20) {0xFF, 0xFF, 0xFF, 0xFF }) + CreateDWordField (TMD0, 0, PIO0) // 0xFFFFFFFF + CreateDWordField (TMD0, 4, DMA0) + CreateDWordField (TMD0, 8, PIO1) + CreateDWordField (TMD0, 12, DMA1) + CreateDWordField (TMD0, 16, CHNF) + + + // validate PIO0 value + Store (PIO0, Local3) + + // save Local3 object type value into Local2 + Store (ObjectType (Local3), Local2) + + // validate Local3 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { Return (2) } // failure + + // validate Local3 Number value + If (LNotEqual (Local3, 0xFFFFFFFF)) // Number value 0xFFFFFFFF + { Return (3) } // failure + + Store ("DWordField PASS", Debug) + + + Store (0, Local5) + Store (Match (DerefOf (Index (TIM0, 1, )), MLE, Local5, MTR, 0, 0), Local6) + + // save Local6 object type value into Local2 + Store (ObjectType (Local6), Local2) + + // validate Local6 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { Return (4) } // failure + + Store ("Match(DerefOf(Index(TIM0,1)),... PASS", Debug) + + + // validate following produces a nested package to validate + // that MatchOp did not corrupt SearchPackage (TIM0) + Store (DerefOf (Index (TIM0, 1, )), Local4) + + // save Local4 object type value into Local2 + Store (ObjectType (Local4), Local2) + + // validate Local4 is a Package + If (LNotEqual (Local2, 4)) // Package type is 4 + { Return (5) } // failure + + Store ("DerefOf(Index(TIM0,1)),... PASS", Debug) + + + And (Match (DerefOf (Index (TIM0, 0, )), MGE, PIO0, MTR, 0, 0), 3, Local0) + + // save Local0 object type value into Local2 + Store (ObjectType (Local0), Local2) + + // validate Local0 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { Return (6) } // failure + + // validate Local0 Number value + If (LNotEqual (Local0, 3)) // Number value 3 + { Return (7) } // failure + + Store ("And(Match(DerefOf(Index(TIM0,0)),... PASS", Debug) + + + // again, validate following produces a nested package + Store (DerefOf (Index (TIM0, 1, )), Local4) + + // save Local4 object type value into Local2 + Store (ObjectType (Local4), Local2) + + // validate Local4 is a Package + If (LNotEqual (Local2, 4)) // Package type is 4 + { Return (8) } // failure + + Store ("DerefOf(Index(TIM0,1)),... PASS again", Debug) + + + // again, validate following produces a nested package + Store (DerefOf (Index (TIM0, 1, )), Local4) + + // save Local4 object type value into Local2 + Store (ObjectType (Local4), Local2) + + // validate Local4 is a Package + If (LNotEqual (Local2, 4)) // Package type is 4 + { Return (9) } // failure + + Store ("DerefOf(Index(TIM0,1)),... PASS again", Debug) + + + // test nested DerefOf(Index) operators + Store (DerefOf (Index (DerefOf (Index (TIM0, 1, )), Local0, )), Local1) + + // save Local1 object type value into Local2 + Store (ObjectType (Local1), Local2) + + // validate Local1 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { Return (10) } // failure + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local1, 0)) + { Return (11) } // failure + + Store ("DerefOf(Index(DerefOf(Index(TIM0,1)),... PASS", Debug) + + + // again, validate following produces a nested package + Store (DerefOf (Index (TIM0, 1, )), Local4) + + // save Local4 object type value into Local2 + Store (ObjectType (Local4), Local2) + + // validate Local4 is a Package + If (LNotEqual (Local2, 4)) // Package type is 4 + { Return (12) } // failure + + Store ("DerefOf(Index(TIM0,1)),... PASS again", Debug) + + + // retest nested DerefOf(Index) operators + Store (DerefOf (Index (DerefOf (Index (TIM0, 1, )), Local0, )), Local1) + + // save Local1 object type value into Local2 + Store (ObjectType (Local1), Local2) + + // validate Local1 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { Return (13) } // failure + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local1, 0)) + { Return (14) } // failure + + Store ("DerefOf(Index(DerefOf(Index(TIM0,1)),... PASS again", Debug) + + + // again, validate following produces a nested package + Store (DerefOf (Index (TIM0, 1, )), Local4) + + // save Local4 object type value into Local2 + Store (ObjectType (Local4), Local2) + + // validate Local4 is a Package + If (LNotEqual (Local2, 4)) // Package type is 4 + { Return (15) } // failure + + Store ("DerefOf(Index(TIM0,1)),... PASS again", Debug) + + + Return (0) // pass + } // TEST + } // MTCH + +// +// test WhileBrk.asl +// +// This code tests the Break term and While term +// +// Syntax of Break term +// BreakTerm := Break +// The break operation causes the current package execution to complete. +// +// Syntax of While Term +// WhileTerm := While( +// Predicate //TermArg=>Integer +// ) {TermList} +// Predicate is evaluated as an integer. +// If the integer is non-zero, the list of terms in TermList is executed. +// The operation repeats until the Predicate evaluates to zero. +// +// MTL NOTE: This test has been modified to reflect ACPI 2.0 break +// NOTE: This test, when run under the MS ACPI.SYS grinds the system to +// a halt. +// + Device (WHLB) + { + Name (CNT0, 0) + Name (CNT1, 0) + + Method (TEST) + { + // Check Break statement nested in If nested in While nested in + // While only exits inner-most While loop + Store (0, CNT0) + + While (LLess (CNT0, 4)) + { + Store (0, CNT1) + While (LLess (CNT1, 10)) + { + if (LEqual (CNT1, 1)) + { + Break // exit encompassing loop + } + + Increment (CNT1) + } + + If (LNotEqual (CNT1, 1)) + { + // failure + Return (7) + } + + Increment (CNT0) + } + + // Verify Break only exited inner-most While loop + + If (LNotEqual (CNT0, 4)) + { + // failure + Return (8) + } + + Store ("While/While/If/Break PASS", Debug) + + Store ("++++++++ WhileBrk Test", Debug) + + // Check Break statement nested in While + Store (0, CNT0) + + While (LLess (CNT0, 10)) + { + Break // exit encompassing package + Increment (CNT0) + } + + If (LNotEqual (CNT0, 0)) // instruction after Break executed + { + Return (4) + } + + + Store (0, CNT0) + + // Test While Term + While (LLess (CNT0, 10)) + { + Increment (CNT0) + } + + // Check if the while loop was executed until the condition is satisfied. + If (LNotEqual (CNT0, 10)) + { + Return (1) + } + + + // While loop in a reverse order + While (LGreater (CNT0, 0)) + { + Decrement (CNT0) + } + + // Check if the while loop was executed until the condition is satisfied. + If (LNotEqual (CNT0, 0)) + { + Return (2) + } + + + Store ("While/Break PASS", Debug) + + + // Check Break statement nested in If nested in While + Store (0, CNT0) + + While (LLess (CNT0, 10)) + { + if (LEqual (CNT0, 5)) + { + Break // exit encompassing Package (If) + + // if we execute the next instruction, + // Break did not exit the loop + Store (20, CNT0) // exit While loop with value larger + // than above + } + + Increment (CNT0) // check if Break exited both If and While + } // While + + If (LGreater (CNT0, 19)) + { // instruction after Break inside IfOp executed + Return (5) + } + + // + // Break will exit out of the while loop, therefore + // the CNT0 counter should still Increment until 5 + // + If (LNotEqual (CNT0, 5)) + { // instruction after Break inside WhileOp executed + Return (6) + } + Store ("While/If/Break PASS", Debug) + + + // All the conditions passed + Return (0) + } // TEST + } // WHLB + + +// +// test IndexOp2.asl +// +// Additional IndexOp test cases to support ACPICMB (control method battery +// test) on Toshiba Portege 7020CT. Test cases include appropriate bit +// shifting of Field elements and reading Field elements greater than 64 bits. +// +// MTL NOTE: This test has been modified slightly from the original test +// to take into account ACPI specification limitations. +// + Scope (\_SB) // System Bus + { // _SB system bus + + Device (MEM) + { // MEM + Name (_HID, 0x010CD041) + Name (_STA, 0x0F) + + OperationRegion (SMEM, SystemMemory, 0x800000, 0x100) + Field (SMEM, AnyAcc, NoLock, Preserve) + { // Field: SMEM overlay using 32-bit field elements + SMD0, 32, // 32-bits + SMD1, 32, // 32-bits + SMD2, 32, // 32-bits + SMD3, 32 // 32-bits + } // Field: SMEM overlay using 32-bit field elements + Field (SMEM, AnyAcc, NoLock, Preserve) + { // Field: SMEM overlay using greater than 32-bit field elements + SME0, 69, // larger than an integer (32 or 64) + SME1, 97 // larger than an integer + } // Field: SMEM overlay using greater than 32-bit field elements + + OperationRegion (SRAM, SystemMemory, 0x100B0000, 0xF000) + Field (SRAM, AnyAcc, NoLock, Preserve) + { // Field: SRAM overlay + , 0x34000, // skip + IEAX, 0x20, + IEBX, 0x20, + IECX, 0x20, + IEDX, 0x20, + IESI, 0x20, + IEDI, 0x20, + IEBP, 0x20, + , 0x20, + OEAX, 0x20, + OEBX, 0x20, + OECX, 0x20, + OEDX, 0x20, + OESI, 0x20, + OEDI, 0x20, + OEBP, 0x20, + , 0x618, // skip + ACST, 1, + BES1, 1, + BES2, 1, + , 5, // skip + BMN1, 0x68, + BSN1, 0x58, + BTP1, 0x48, + BPU1, 0x20, + BDC1, 0x20, + BLF1, 0x20, + BTC1, 0x20, + BDV1, 0x20, + BST1, 0x20, + BPR1, 0x20, + BRC1, 0x20, + BPV1, 0x20, + , 0x20, + BCW1, 0x20, + BCL1, 0x20, + BG11, 0x20, + BG21, 0x20, + BOI1, 0x20, + , 0x530, // skip + BMN2, 0x68, + BSN2, 0x58, + BTP2, 0x48, + BPU2, 0x20, + BDC2, 0x20, + BLF2, 0x20, + BTC2, 0x20, + BDV2, 0x20, + BST2, 0x20, + BPR2, 0x20, + BRC2, 0x20, + BPV2, 0x20, + , 0x20, + BCW2, 0x20, + BCL2, 0x20, + BG12, 0x20, + BG22, 0x20, + BOI2, 0x20, + , 0x518, // skip + AC01, 0x10, + AC11, 0x10, + PSV1, 0x10, + CRT1, 0x10, + TMP1, 0x10, + AST1, 0x10, + AC21, 0x10, + AC31, 0x10, + AC02, 0x10, + AC12, 0x10, + PSV2, 0x10, + CRT2, 0x10, + TMP2, 0x10, + AST2, 0x10, + AC22, 0x10, + AC32, 0x10, + AC03, 0x10, + AC13, 0x10, + PSV3, 0x10, + CRT3, 0x10, + TMP3, 0x10, + AST3, 0x10, + AC23, 0x10, + AC33, 0x10, + , 0x80, // skip + TMPF, 0x10, + , 0x570, // skip + FANH, 1, + FANL, 7, + TF11, 1, + TF21, 1, + TF31, 1, + , 1, + TF10, 1, + TF20, 1, + TF30, 1, + , 1, + TP11, 1, + TP21, 1, + TP31, 1, + , 0x6D, // 109 + GP50, 1, + GP51, 1, + GP52, 1, + GP53, 1, + , 4, + GP60, 1, + GP61, 1, + GP62, 1, + GP63, 1, + GP64, 1, + GP65, 1, + GP66, 1, + , 1, + GP70, 1, + GP71, 1, + GP72, 1, + GP73, 1, + GP74, 1, + GP75, 1, + GP76, 1, + , 1, + WED0, 1, + WED1, 1, + WED2, 1, + WED3, 1, + WED4, 1, + , 3, + SBL0, 1, + SBL1, 1, + SBL2, 1, + SBL3, 1, + , 4, + LIDS, 1, + VALF, 1, + , 2, + DCKI, 1, + DCKF, 1, + BT1F, 1, + BT2F, 1, + , 0x7D0, // skip + HKCD, 8, + , 8, + DLID, 0x20, + DSRN, 0x20, + , 0x20, + BDID, 0x20, + DSPW, 1, + VGAF, 1, + VWE0, 1, + VWE1, 1, + PPSC, 1, + SPSC, 1, + EWLD, 1, + EWPS, 1, + , 0x1768, // skip + PRES, 0x8000 + } // Field: SRAM overlay + } // MEM + + Device (BAT1) + { // BAT1 + Name (_HID, EISAID ("PNP0C0A")) // Control Method Battey ID + Name (_UID, 1) + Name (_PCL, Package (1) {\_SB}) + + Method (_STA) + { // _STA + If (\_SB.MEM.BES1) + { Return (0x1F) } // battery present + Else + { Return (0x0F) } // battery not present + } // _STA + + Method (_BIF,, Serialized) + { // _BIF + Name (BUFR, Package (13) {}) + + Store (\_SB.MEM.BPU1, Index (BUFR, 0)) + Store (\_SB.MEM.BDC1, Index (BUFR, 1)) + Store (\_SB.MEM.BLF1, Index (BUFR, 2)) + Store (\_SB.MEM.BTC1, Index (BUFR, 3)) + Store (\_SB.MEM.BDV1, Index (BUFR, 4)) + Store (\_SB.MEM.BCW1, Index (BUFR, 5)) + Store (\_SB.MEM.BCL1, Index (BUFR, 6)) + Store (\_SB.MEM.BG11, Index (BUFR, 7)) + Store (\_SB.MEM.BG21, Index (BUFR, 8)) + Store (\_SB.MEM.BMN1, Index (BUFR, 9)) + Store (\_SB.MEM.BSN1, Index (BUFR, 10)) + Store (\_SB.MEM.BTP1, Index (BUFR, 11)) + Store (\_SB.MEM.BOI1, Index (BUFR, 12)) + + Return (BUFR) + } // _BIF + } // BAT1 + + Device (IDX2) + { + Method (B2IB,, Serialized) + { // B2IB: store from Buffer into Index'ed Buffer + + Name (SRCB, Buffer () {"Short Buffer"}) // 12 characters plus NULL + + Name (DEST, Buffer () // 62 characters plus NULL + {"Destination buffer that is longer than the short source buffer"}) + + + // verify object type returned by Index(Buffer,Element,) + + Store (Index (DEST, 2, ), Local1) + Store (ObjectType (Local1), Local2) + + If (LNotEqual (Local2, 14)) // Buffer Field is type 14 + { + // Local2 indicates Local1 is not a Buffer Field + + Return (0x61) + } + + // verify object type and value returned by DerefOf(Index(Buffer,Element,)) + // should return Number containing element value + + Store (DerefOf (Local1), Local3) + Store (ObjectType (Local3), Local4) + + If (LNotEqual (Local4, 1)) // Number is type 1 + { + // Local2 indicates Local1 is not a Number + Return (0x62) + } + Else + { + If (LNotEqual (Local3, 0x73)) // expect 's' element from DEST + { + Return (0x63) + } + } + + Store ("DerefOf(Index(Buffer,,)) PASS", Debug) + + + // + // The following sections have been rewritten because storing into + // an Indexed buffer only changes one byte - the FIRST byte of the + // buffer is written to the source index. This is the ONLY byte + // written -- as per ACPI 2.0 + // + // Overwrite DEST contents, at buffer position 2 [only] + + Store (SRCB, Index (DEST, 2, )) + + // + // Check that the next byte is not changed + // + Store (DerefOf (Index (DEST, 3, )), Local0) + If (LNotEqual (Local0, 0x74)) // 't' + { + // DEST element is not matching original value + If (LEqual (Local0, 0x68)) + { + // DEST element was altered to 'h' + Return (0x68) + } + Else + { + // DEST element is an unknown value + Return (0x69) + } + } + + // + // Check that the elements beyond the SRCB buffer copy + // have not been altered. + // + Store (DerefOf (Index (DEST, 14)), Local0) + + // + // This should be an 'f'. + // + If (LNotEqual (Local0, 0x66)) + { + // DEST element was zero'd by buffer copy + If (LEqual (Local0, 0)) + { + // DEST element is zero + Return (0x6A) + } + Else + { + // DEST element is unknown value + Return (0x6B) + } + } + + Store ("Store(SRCB,Index(Buffer,,)) PASS", Debug) + + // + // verify altering SRCB does NOT alter DEST + // + Store (0x6A, Index (SRCB, 1)) // SRCB = "Sjort Buffer" + + Store (DerefOf (Index (SRCB, 1)), Local0) + + If (LNotEqual (Local0, 0x6A)) // 'j' + { + // SRCB element is unaltered + Return (0x71) + } + + Store (DerefOf (Index (DEST, 3)), Local0) // DEST = "Destination buffer that... + + If (LNotEqual (Local0, 0x74)) // 't' + { + // DEST element is altered + If (LEqual (Local0, 0x6A)) // 'j' + { + // SRCB change altered DEST element + Return (0x72) + } + Else + { + // DEST element is unknown value + Return (0x73) + } + } + + // verify altering DEST does NOT alter SRCB + + Store (0x6B, Index (DEST, 4, )) // DEST = "DeSkination buffer..." + + Store (DerefOf (Index (DEST, 4, )), Local0) + + If (LNotEqual (Local0, 0x6B)) // 'k' + { + // DEST element is unaltered + Return (0x74) + } + + Store (DerefOf (Index (SRCB, 2, )), Local0) + + If (LNotEqual (Local0, 0x6F)) // 'o' + { // SRC element is altered + If (LEqual (Local0, 0x6B)) // 'k' + { + // DEST change altered SRCB element + Return (0x75) + } + Else + { + // SRCB element is unknown value + Return (0x76) + } + } + + Store ("SRCB and DEST independent PASS", Debug) + + + // verify string can be written to Index target/destination + // Only FIRST byte is written + + Store ("New Buff", Index (DEST, 2, )) // DEST = "DeNkination buffer..." + + Store (DerefOf (Index (DEST, 2, )), Local0) + + If (LNotEqual (Local0, 0x4E)) // 'N' + { + // DEST element is unaltered + Return (0x81) + } + + Store (DerefOf (Index (DEST, 6, )), Local0) + + If (LNotEqual (Local0, 0x61)) // 'a' + { + // DEST element is unaltered + Return (0x82) + } + + Store (DerefOf (Index (DEST, 10, )), Local0) + + If (LNotEqual (Local0, 0x6E)) // 'n' + { + // DEST element is unaltered + Return (0x83) + } + + Store ("Store(String,Index) PASS", Debug) + + + Return (0) // pass + } // B2IB: store from Buffer into Index'ed Buffer + + Method (FB2P,, Serialized) + { // FB2P: store from Field Buffer into Index'ed Package + Name (DEST, Package (2) {}) + + // initialize memory using 32-bit field elements + Store (0x01234567, \_SB.MEM.SMD0) + Store (0x89ABCDEF, \_SB.MEM.SMD1) + Store (0xFEDCBA98, \_SB.MEM.SMD2) + Store (0x76543210, \_SB.MEM.SMD3) + + // move greater than 64-bit buffers into DEST package + Store (\_SB.MEM.SME0, Index (DEST, 0)) + Store (\_SB.MEM.SME1, Index (DEST, 1)) + + // validate DEST contents + Store (DerefOf (Index (DEST, 0, )), Local0) + Store (DerefOf (Index (DEST, 1, )), Local1) + + // verify Local0 and Local1 are Buffers + Store (ObjectType (Local0), Local2) + if (LNotEqual (Local2, 3)) // Buffer type is 3 + { + Return (0x11) + } + + Store (ObjectType (Local1), Local3) + if (LNotEqual (Local3, 3)) // Buffer type is 3 + { + Return (0x12) + } + + // validate DEST buffer contents + Store (DerefOf (Index (DerefOf (Index (DEST, 0)), 0)), Local4) + If (LNotEqual (Local4, 0x67)) + { + Return (0x13) + } + + Store (DerefOf (Index (DerefOf (Index (DEST, 0)), 1)), Local4) + If (LNotEqual (Local4, 0x45)) + { + Return (0x14) + } + + Store (DerefOf (Index (DerefOf (Index (DEST, 0)), 4)), Local4) + If (LNotEqual (Local4, 0xEF)) + { + Return (0x15) + } + + Store (DerefOf (Index (DerefOf (Index (DEST, 0, )), 5, )), Local4) + If (LNotEqual (Local4, 0xCD)) + { + Return (0x16) + } + + Store ("Store(Mem,PkgElement) PASS", Debug) + + + // validate changing source \_SB.MEM.SMD* does not impact DEST + Store (0x12345678, \_SB.MEM.SMD0) + + Store (DerefOf (Index (DerefOf (Index (DEST, 0, )), 0, )), Local5) + If (LNotEqual (Local5, 0x67)) + { + Return (0x21) + } + + Store (DerefOf (Index (DerefOf (Index (DEST, 0, )), 1, )), Local5) + If (LNotEqual (Local5, 0x45)) + { + Return (0x22) + } + + // validate changing DEST does not impact source \_SB.MEM.SMD* + Store (0x30, Index (DerefOf (Index (DEST, 0)), 0)) + + Store (DerefOf(Index (DerefOf (Index (DEST, 0)), 0)), Local5) + If (LNotEqual (Local5, 0x30)) + { + Return (0x23) + } + + // + // This section was modified from the original iPCO code because + // it attempted to compare two buffers. This is not allowed until + // ACPI v2.0, so the test has been modified to just check the + // changed \_SB.MEM.SMD0 + // + Store (\_SB.MEM.SMD0, Local5) + + If(LNotEqual(Local5, 0x12345678)) + { + Return (0x24) + } + + Store ("Mem and Pkg independent PASS", Debug) + + + Return (0) + } // FB2P: store from Field Buffer into Index'ed Package + + Method (TEST) + { + Store ("++++++++ IndexOp2 Test", Debug) + + // store _BIF package return value into Local0 + + Store (\_SB.BAT1._BIF, Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Package + If (LNotEqual (Local1, 4)) // Package type is 4 + { + // failure + Return (2) + } + + // validate source and destination buffers are independent of each + // of each other (i.e., changing one's contents does not change + // other's contents) using B2IB (store from Buffer into Index'ed + // Buffer) and FB2P (store from Field Buffer into Index'ed Package) + + // call B2IB (store from Buffer into Index'ed Buffer) + Store (B2IB, Local2) // Local2 is B2IB return value + + // save Local2 object type value into Local3 + Store (ObjectType (Local2), Local3) + + // validate Local2 is a Number + If (LNotEqual (Local3, 1)) // Number type is 1 + { + // failure + Return (4) + } + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local2, 0)) + { + // return B2IB error code + Return (Local2) + } + + // call FB2P (store from Field Buffer into Index'ed Package) + Store (FB2P, Local2) // Local2 is FB2P return value + + // save Local2 object type value into Local3 + Store (ObjectType (Local2), Local3) + + // validate Local2 is a Number + If (LNotEqual (Local3, 1)) // Number type is 1 + { + // failure + Return (5) + } + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local2, 0)) + { + // return FB2P error code + Return (Local2) + } + + + Return (0) + } // TEST + } // IDX2: Test device name + } // _SB system bus + +// +// test SizeOf.asl +// +// Test for SizeOf +// test cases include following SizeOf arguments: +// buffer, buffer field; +// control method argument, control method local variable; +// control method return values; +// direct string, string; +// package; +// buffer, package, and string package elements +// +// MTL NOTE: This test has been modified to remove any SizeOf(Index(Buff,... +// calls because it is not legal to perform a SizeOf operation on a Buffer Field. +// This test has also been extended to test additional Package element sizes. +// + Device (SIZO) + { + // SAR0 control method validates SizeOf(Arg) + // SAR0 should only be called by SARG + Method (SAR0, 2) + // Arg0 object to determine size of + // Arg1 expected Arg length + { // SAR0: SizeOf(Arg) test control method + // Local0 Arg0 length + // Local1 Local0 object type + + // Store first string size (Arg0) into Local7 + Store (SizeOf (Arg0), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { Return (0x21) } + + // If strings are not of equal size, return error code + If (LNotEqual (Local0, Arg1)) + { Return (0x22) } + + Return (0) + } // SAR0: SizeOf(Arg) test control method + + Method (SARG,, Serialized) + { // SARG: SizeOf(Arg) test control method + Name (BUFR, Buffer (12) {}) // uninitialized Buffer + Name (BUF1, Buffer() {0x01, 0x02, 0x03, 0x04, 0x05}) + Name (PKG0, Package (4) {}) // uninitialized Package + Name (STR0, "String") + Name (PKG1, Package (4) + { + BUFR, + "String2", + STR0, + PKG0 + }) // PKG1 + + Name (PKG2, Package (4) + { + Buffer (15) {}, + "String 1", + Package (2) {} + }) // PKG2 + + // Namespace entry buffer reference + Store (SAR0 (BUFR, 12), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x23) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=BUFR) PASS", Debug) + + + // Namespace entry package reference + Store (SAR0 (PKG0, 4), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x24) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=PKG0) PASS", Debug) + + + // Namespace entry string reference + Store (SAR0 (STR0, 6), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x25) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=STR0) PASS", Debug) + + + // direct string reference + Store (SAR0 ("String", 6), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x26) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=String) PASS", Debug) + + Store (0x55, Index (BUF1, 2)) + + /**************************************************** + // + // This section is commented because it is illegal to + // perform a SizeOf operation on a Buffer Field + // + // Namespace BufferField reference + Store (SAR0 (Index (BUFR, 2, ), 10), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { Return (0x27) } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { Return (Local0) } + + Store ("SizeOf(Arg=BufferField) PASS", Debug) + ****************************************************/ + + // Namespace BufferPackageElement reference + // + Store (SAR0 (Index(PKG1, 0), 12), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x28) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=PackageBuffer NTE Reference Element) PASS", Debug) + + + // Namespace StringPackageElement reference + Store (SAR0 (Index (PKG1, 1, ), 7), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x29) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=Package String Element) PASS", Debug) + + + // Namespace StringPackageElement reference + Store (SAR0 (Index (PKG1, 2, ), 6), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x2A) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=Package String NTE Reference Element) PASS", Debug) + + + // Namespace PackagePackageElement reference + Store (SAR0 (Index (PKG1, 3, ), 4), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x2B) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=Package Package NTE Reference Element) PASS", Debug) + + // Package Buffer Element + Store (SAR0 (Index (PKG2, 0), 15), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x2B) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=Package Buffer Element) PASS", Debug) + + // Package String Element + Store (SAR0 (Index (PKG2, 1), 8), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x2B) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=Package String Element) PASS", Debug) + + // Package Package Element + Store (SAR0 (Index (PKG2, 2), 2), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x2B) + } + + If (LNotEqual (Local0, 0)) // Local0 is SAR0 return error code + { + Return (Local0) + } + + Store ("SizeOf(Arg=Package Package Element) PASS", Debug) + + Store ("SizeOf(Arg) PASS", Debug) + + Return (0) + } // SARG: SizeOf(Arg) test control method + + Method (SBUF,, Serialized) + { // SBUF: SizeOf(Buffer) test control method + Name (BUFR, Buffer (12) {}) + + // store size of BUFR buffer into Local0 + Store (SizeOf (BUFR), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x31) + } + + If (LNotEqual (Local0, 12)) // BUFR size is 12 + { + Return (0x32) + } + + Store ("SizeOf(BUFR) PASS", Debug) + + Return (0) + } // SBUF: SizeOf(Buffer) test control method + + + /**************************************************** + // + // This section is commented because it is illegal to + // perform a SizeOf operation on a Buffer Field + // + Method (SIND) + { // SIND: SizeOf(Index(,,)) test control method + Name (BUFR, Buffer (12) {}) + + // store size of Index(BUFR,2,) buffer into Local0 + Store (SizeOf (Index (BUFR, 2, )), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x41) + } + + If (LNotEqual (Local0, 10)) // 12 - 2 = 10 + { + Return (0x42) + } + + Store ("SizeOf(Index(BUFR,,)) PASS", Debug) + + // TBD: strings and packages + + Return (0) + } // SIND: SizeOf(Index(,,)) test control method + ****************************************************/ + + Method (SLOC,, Serialized) + { // SLOC: SizeOf(Local) test control method + Name (BUFR, Buffer (12) {}) // uninitialized Buffer + Name (STR0, "String") + Name (PKG0, Package (4) {}) // uninitialized Package + + + // store BUFR Buffer into Local2 + Store (BUFR, Local2) + + // store size of BUFR buffer into Local0 + Store (SizeOf (Local2), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x51) + } + + If (LNotEqual (Local0, 12)) // BUFR size is 12 + { + Return (0x52) + } + + Store ("SizeOf(Local2=Buffer) PASS", Debug) + + + // store STR0 string into Local2 + Store (STR0, Local2) + + // store size of STR0 buffer into Local0 + Store (SizeOf (Local2), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x53) + } + + If (LNotEqual (Local0, 6)) // STR0 size is 6 + { + Return (0x54) + } + + Store ("SizeOf(Local2=String) PASS", Debug) + + + // store PKG0 Package into Local2 + Store (PKG0, Local2) + + // store size of PKG0 buffer into Local0 + Store (SizeOf (Local2), Local0) + + // save Local0 object type value into Local1 + Store (ObjectType (Local0), Local1) + + // validate Local0 is a Number + If (LNotEqual (Local1, 1)) // Number type is 1 + { + Return (0x55) + } + + If (LNotEqual (Local0, 4)) // PKG0 size is 4 + { + Return (0x56) + } + + Store ("SizeOf(Local2=Package) PASS", Debug) + + + Return (0) + } // SLOC: SizeOf(Local) test control method + + Method (TEST) + { + Store ("++++++++ SizeOf Test", Debug) + + // Store current operating system string into Local0 + Store (_OS, Local0) + + Store (SizeOf (_OS), Local3) + + // save Local3 object type value into Local4 + Store (ObjectType (Local3), Local4) + + // validate Local3 is a Number + If (LNotEqual (Local4, 1)) // Number type is 1 + { + // failure + Return (0x61) + } + + // Store current operating system string into Local0 + // This verifies above SizeOf(_OS) did not corrupt ACPI namespace + Store (_OS, Local0) + + // Store SARG [Validate SizeOf(Arg)] return value into Local1 + Store (SARG, Local1) + + // save Local1 object type value into Local2 + Store (ObjectType (Local1), Local2) + + // validate Local1 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { + // failure + Return (0x62) + } + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local1, 0)) + { + // return SARG error code + Return (Local1) + } + + + // Store SBUF [Validate SizeOf(Buffer)] return value into Local1 + Store (SBUF, Local1) + + // save Local1 object type value into Local2 + Store (ObjectType (Local1), Local2) + + // validate Local1 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { + // failure + Return (0x63) + } + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local1, 0)) + { + // return SBUF error code + Return (Local1) + } + + /**************************************************** + // + // This section is commented because it is illegal to + // perform a SizeOf operation on a Buffer Field + // + // Store SIND [verify SizeOf(Index(,,))] return value into Local1 + Store (SIND, Local1) + + // save Local1 object type value into Local2 + Store (ObjectType (Local1), Local2) + + // validate Local1 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { + // failure + Return (0x64) + } + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local1, 0)) + { + // return SARG error code + Return (Local1) + } + ****************************************************/ + + // Store SLOC [verify SizeOf(Local)] return value into Local1 + Store (SLOC, Local1) + + // save Local1 object type value into Local2 + Store (ObjectType (Local1), Local2) + + // validate Local1 is a Number + If (LNotEqual (Local2, 1)) // Number type is 1 + { + // failure + Return (0x65) + } + + // zero indicates pass, non-zero is an error code + If (LNotEqual (Local1, 0)) + { + // return SLOC error code + Return (Local1) + } + + + // TBD: SizeOf (METH) -- where METH control method returns + // buffer, BufferField, string, package, package element + + + Return (0) + } // TEST + } // SIZO + +// +// test SmiShare.asl +// + Scope (\_SB) // System Bus + { // _SB system bus + // Declare an OpRegion in Memory starting at offset 0x400000 that is 10 bytes long + OperationRegion(RAM1, SystemMemory, 0x400000, 0xA) + + Field (RAM1, AnyAcc, NoLock, Preserve) + { + BI1T, 1, // Create some bits in memory to access + BI2T, 2, + BI3T, 3, + LST2, 2 + } // End Field RAM1 + + Field (RAM1, WordAcc, NoLock, WriteAsZeros) + { + WRD, 16 + } // End 2nd Field RAM1 + + Field (RAM1, ByteAcc, NoLock, WriteAsOnes) + { + BYTE, 8 + } // End 3rd Field RAM1 + + Field (RAM1, ByteAcc, NoLock, Preserve) + { + SMIC, 8, + SMID, 8 + } + + Device (MBIT) + { + Method (_INI) + { + Store (0, BI1T) + Store (3, BI2T) + Store (7, BI3T) + Store (0, LST2) + } // End _INI Method + } // End Device MBIT + + Device (MWRD) + { + Method (_INI) + { + Store (0, WRD) + } // End _INI Method + } // End Device MWRD + + Device (MBYT) + { + Method (_INI) + { + Store (0, BYTE) + Store (0xC, SMIC) + Store (0xD, SMID) + } // End _INI Method + } // End Device MBYT + + /* + // Declare an OpRegion in Memory starting at offset 0x400000 that is 10 bytes long + OperationRegion(\RAM1, SystemMemory, 0x400000, 0xA) + + Field (\RAM1, AnyAcc, NoLock, Preserve) + { + BI1T, 1, // Create some bits in memory to access + BI2T, 2, + BI3T, 3, + LST2, 2 + } // End Field RAM1 + + Field (\RAM1, WordAcc, NoLock, WriteAsZeros) + { + WRD, 16 + } // End 2nd Field RAM1 + + Field (\RAM1, ByteAcc, NoLock, WriteAsOnes) + { + BYTE, 8 + } // End 3rd Field RAM1 + + Field (\RAM1, ByteAcc, NoLock, Preserve) + { + SMIC, 8, + SMID, 8 + } + */ + Method (SMIX) + { + Return (BYTE) + } // End SMIX + + Method (EVNT) + { + Store (SMIX, Local0) + + Notify (\_SB_, 0x29) + If (And (Local0, 0x01)) + { Notify (\_SB_.SMIS, 0x21)} + + If (And (Local0, 0x02)) + { Notify (\_SB_.SMIS, 0x22)} + + If (And (Local0, 0x04)) + { Notify (\_SB_.SMIS, 0x24)} + + If (And (Local0, 0x08)) + { Notify (\_SB_.SMIS, 0x28)} + + } // End Method EVNT + + Method (NTFY) + { + Notify (\_SB_, 1) + Notify (\_TZ_.TZ1, 2) + Notify (\_PR_.CPU0, 3) + + Notify (\_SB_, 0x81) + Notify (\_TZ_.TZ1, 0x82) + Notify (\_PR_.CPU0, 0x83) + } + + Device (SMIS) + { + Method (BINK) + { + Store (0, Local0) // Zero out Local0 + + If (LNotEqual (SMID, 0xD)) + { Or (0x80, Local0, Local0)} + + If (LNotEqual (SMIC, 0xC)) + { Or (0x40, Local0, Local0)} + + If (LNotEqual (BYTE, 0)) + { Or (0x20, Local0, Local0)} + + If (LNotEqual (WRD, 0)) + { Or (0x10, Local0, Local0)} + + If (LNotEqual (LST2, 0)) + { Or (0x8, Local0, Local0)} + + If (LNotEqual (BI3T, 0x7)) + { Or (0x4, Local0, Local0)} + + If (LNotEqual (BI2T, 0x3)) + { Or (0x2, Local0, Local0)} + + If (LNotEqual (BI1T, 0)) + { Or (0x1, Local0, Local0)} + + Return (Local0) + } // End Method BINK + + Method (TEST) + { + Store ("++++++++ SmiShare Test", Debug) + + // Expect EVNT to generate Notify value we just previously + // stored in BYTE + + Store (0x20, BYTE) + EVNT () + Store (0x21, BYTE) + EVNT () + Store (0x22, BYTE) + EVNT () + Store (0x23, BYTE) + EVNT () + + NTFY () + Return (0) // pass + } // End Method TEST + } // Device SMIS + + Device(CNDT) + { + Method(TEST) + { + If (ECOK) + { + return("Broken") + } + Else + { + return("Works") + } + } + + Method(ECOK) + { + Return(0x0) + } + } + + } // _SB system bus + + +/* Test a very big buffer */ + + Name(WQAB, Buffer(6756) + { + 0x46,0x4F,0x4D,0x42,0x01,0x00,0x00,0x00, + 0x54,0x1A,0x00,0x00,0xBA,0xAD,0x00,0x00, + 0x44,0x53,0x00,0x01,0x1A,0x7D,0xDA,0x54, + 0x98,0xBD,0x92,0x00,0x01,0x06,0x18,0x42, + 0x10,0x47,0x10,0x92,0x46,0x62,0x02,0x89, + 0x80,0x90,0x18,0x18,0x14,0x81,0x85,0x00, + 0x49,0x02,0x88,0xC4,0x41,0xE1,0x20,0xD4, + 0x9F,0x40,0x7E,0x05,0x20,0x74,0x28,0x40, + 0xA6,0x00,0x83,0x02,0x9C,0x22,0x88,0xA0, + 0x57,0x01,0x36,0x05,0x98,0x14,0x60,0x51, + 0x80,0x76,0x01,0x96,0x05,0xE8,0x16,0x20, + 0x1D,0x96,0x88,0x04,0x47,0x89,0x01,0x47, + 0xE9,0xC4,0x16,0x6E,0xD8,0xE0,0x85,0xA2, + 0x68,0x06,0x51,0x12,0x94,0x8B,0x20,0x5D, + 0x10,0x52,0x2E,0xC0,0x37,0x82,0x06,0x10, + 0xA5,0x77,0x01,0xB6,0x05,0x98,0x86,0x27, + 0xD2,0x20,0xE4,0x60,0x08,0x54,0xCE,0x80, + 0x20,0x69,0x44,0x21,0x1E,0xA7,0x44,0x08, + 0x0A,0x84,0x90,0xD4,0xF1,0xA0,0xA0,0x71, + 0x88,0xAD,0xCE,0x46,0x93,0xA9,0x74,0x7E, + 0x48,0x82,0x70,0xC6,0x2A,0x7E,0x3A,0x9A, + 0xD0,0xD9,0x9C,0x60,0xE7,0x18,0x72,0x3C, + 0x48,0xF4,0x20,0xB8,0x00,0x0F,0x1C,0x2C, + 0x34,0x84,0x22,0x6B,0x80,0xC1,0x8C,0xDD, + 0x63,0xB1,0x0B,0x4E,0x0A,0xEC,0x61,0xB3, + 0x01,0x19,0xA2,0x24,0x38,0xD4,0x11,0xC0, + 0x12,0x05,0x98,0x1F,0x87,0x0C,0x0F,0x95, + 0x8C,0x25,0x24,0x1B,0xAB,0x87,0xC2,0xA5, + 0x40,0x68,0x6C,0x27,0xED,0x19,0x45,0x2C, + 0x79,0x4A,0x82,0x49,0xE0,0x51,0x44,0x36, + 0x1A,0x27,0x28,0x1B,0x1A,0x25,0x03,0x42, + 0x9E,0x05,0x58,0x07,0x26,0x04,0x76,0x2F, + 0xC0,0x9A,0x00,0x73,0xB3,0x90,0xB1,0xB9, + 0xE8,0xFF,0x0F,0x71,0xB0,0x31,0xDA,0x9A, + 0xAE,0x90,0xC2,0xC4,0x88,0x12,0x2C,0x5E, + 0xC5,0xC3,0x10,0xCA,0x93,0x42,0xA8,0x48, + 0x95,0xA1,0x68,0xB4,0x51,0x2A,0x14,0xE0, + 0x4C,0x80,0x30,0x5C,0x1D,0x03,0x82,0x46, + 0x88,0x15,0x29,0x56,0xFB,0x83,0x20,0xF1, + 0x2D,0x40,0x54,0x01,0xA2,0x48,0xA3,0x41, + 0x9D,0x03,0x3C,0x5C,0x0F,0xF5,0xF0,0x3D, + 0xF6,0x93,0x0C,0x72,0x90,0x67,0xF1,0xA8, + 0x70,0x9C,0x06,0x49,0xE0,0x0B,0x80,0x4F, + 0x08,0x1E,0x38,0xDE,0x35,0xA0,0x66,0x7C, + 0xBC,0x4C,0x10,0x1C,0x6A,0x88,0x1E,0x68, + 0xB8,0x13,0x38,0x44,0x06,0xE8,0x49,0x3D, + 0x52,0x60,0x07,0x77,0x32,0xEF,0x01,0xAF, + 0x0A,0xCD,0x5E,0x12,0x08,0xC1,0xF1,0xF8, + 0x7E,0xC0,0x26,0x9C,0xC0,0xF2,0x07,0x81, + 0x1A,0x99,0xA1,0x3D,0xCA,0xD3,0x8A,0x19, + 0xF2,0x31,0xC1,0x04,0x16,0x0B,0x21,0x05, + 0x10,0x1A,0x0F,0xF8,0x6F,0x00,0x8F,0x17, + 0xBE,0x12,0xC4,0xF6,0x80,0x12,0x0C,0x0B, + 0x21,0x23,0xAB,0xF0,0x78,0xE8,0x28,0x7C, + 0x95,0x38,0x9C,0xD3,0x8A,0x67,0x82,0xE1, + 0x20,0xF4,0x05,0x90,0x00,0x51,0xE7,0x0C, + 0xD4,0x61,0xC1,0xE7,0x04,0x76,0x33,0x38, + 0x83,0x47,0x00,0x8F,0xE4,0x84,0xFC,0x2B, + 0xF1,0xC0,0xE0,0x03,0xE2,0xEF,0x1F,0xA7, + 0xEC,0x11,0x9C,0xA9,0x01,0x7D,0x1C,0xF0, + 0xFF,0x7F,0x28,0x7C,0x88,0x1E,0xDF,0x29, + 0x1F,0xAF,0x4F,0x17,0x96,0x35,0x4E,0xE8, + 0x77,0x08,0x9F,0x38,0x7C,0x64,0x71,0x44, + 0x08,0x39,0x39,0x05,0xA0,0x81,0x4F,0xF7, + 0xEC,0x22,0x9C,0xAE,0x27,0xE5,0x40,0xC3, + 0xA0,0xE3,0x04,0xC7,0x79,0x00,0x1C,0xE3, + 0x84,0x7F,0x2E,0x80,0x3F,0x40,0x7E,0xCA, + 0x78,0xC5,0x48,0xE0,0x98,0x23,0x44,0x9F, + 0x6B,0x3C,0x42,0x2C,0xFC,0x53,0x45,0xE1, + 0x03,0x21,0x63,0x04,0x17,0xA0,0xC7,0x08, + 0x7C,0x03,0x8E,0x11,0x7D,0x94,0xE0,0xEA, + 0x0F,0x1A,0x74,0x80,0xB8,0xFF,0xFF,0x00, + 0xE1,0x83,0x7A,0x80,0xC0,0x37,0xFA,0xD1, + 0x03,0x3D,0x2E,0x8B,0x3E,0x0F,0xC8,0xF8, + 0x89,0x46,0xF3,0xE2,0xA7,0x03,0x7E,0xF8, + 0x00,0x0F,0xA8,0x87,0x84,0x03,0xC5,0x4C, + 0x9B,0x83,0x3E,0xBB,0x1C,0x3A,0x76,0xB8, + 0xE0,0x3F,0x81,0x80,0x4B,0xDE,0x21,0x0C, + 0x14,0x23,0xC6,0x9F,0x83,0x7C,0x0A,0x03, + 0xFF,0xFF,0xFF,0x14,0x06,0xFE,0xE1,0xF0, + 0x20,0x4F,0x07,0x9F,0xB6,0xA8,0x74,0x18, + 0xD4,0x81,0x0B,0xB0,0x32,0x89,0x08,0xCF, + 0x12,0xB5,0x41,0xE8,0xD4,0xF0,0x36,0xF1, + 0xB6,0xE5,0x5B,0x40,0x9C,0xD3,0xEC,0xED, + 0xC0,0x45,0x30,0x22,0xD4,0x0C,0x45,0x4E, + 0x5A,0x11,0x63,0x44,0x79,0xDC,0x32,0xCA, + 0xDB,0xD6,0x0B,0x40,0xBC,0x13,0x7B,0xDE, + 0x32,0x46,0xF0,0xC8,0x0F,0x5C,0x2C,0xC6, + 0xEA,0xF5,0x5F,0xF3,0x81,0x0B,0x70,0xF6, + 0xFF,0x3F,0x70,0x01,0x1C,0x0A,0x7A,0x18, + 0x42,0x0F,0xC3,0x53,0x39,0x97,0x87,0xC8, + 0x53,0x89,0x18,0x35,0x4C,0xD4,0x67,0x28, + 0xDF,0x2D,0x7C,0x20,0x02,0xDF,0x99,0x0B, + 0xF8,0xFD,0xFF,0x0F,0x44,0x70,0x8E,0x29, + 0xB8,0x33,0x0D,0x78,0x7C,0xCE,0x40,0x20, + 0xA7,0xE2,0x43,0x0D,0x60,0x41,0xF4,0x13, + 0xC2,0x27,0x1A,0x2A,0x13,0x06,0x75,0xA8, + 0x01,0xAC,0x5C,0x61,0x9E,0x46,0xCF,0xF9, + 0x59,0xC6,0xA7,0x1A,0x1F,0x4A,0x8D,0x63, + 0x88,0x97,0x99,0x87,0x1A,0x1F,0x0B,0x5E, + 0x49,0x7D,0xA8,0x31,0x54,0x9C,0x87,0x1A, + 0x0F,0x37,0x50,0xD4,0x37,0x9B,0x67,0x1B, + 0xA3,0xC7,0xF7,0x0D,0xD5,0x10,0x0F,0x35, + 0x4C,0xF2,0x4A,0x35,0x16,0x1F,0x6A,0xC0, + 0xF1,0xFF,0x3F,0xD4,0x00,0xFC,0xFF,0xFF, + 0x1F,0x6A,0x00,0x47,0x47,0x03,0x38,0x47, + 0x46,0xDC,0xD1,0x00,0x5C,0x87,0x52,0xE0, + 0x70,0x34,0x00,0x1E,0x47,0x21,0x30,0x5F, + 0x68,0x7C,0x14,0x02,0x16,0xFF,0xFF,0xA3, + 0x10,0xF8,0x65,0x9F,0x83,0x50,0x42,0x8F, + 0x42,0x80,0xA0,0xDB,0xCF,0x53,0xC4,0xB3, + 0x8F,0x2F,0x3F,0x0F,0x04,0x11,0x5E,0xF3, + 0x7D,0x0A,0xF2,0x21,0xDF,0x47,0x21,0x06, + 0x63,0x28,0x5F,0x83,0x7C,0x14,0x62,0x50, + 0xAF,0x41,0xBE,0xEF,0x1B,0xE4,0xF1,0x22, + 0x48,0xEC,0x67,0x02,0x1F,0x85,0x98,0xE8, + 0xA3,0x10,0xA0,0xF0,0xFF,0x7F,0x14,0x02, + 0xF8,0xFF,0xFF,0x3F,0x0A,0x01,0xCE,0x02, + 0x1C,0x0D,0x40,0x37,0xAD,0x47,0x21,0xF0, + 0xDE,0x59,0x4E,0xFB,0x04,0x7C,0x16,0x02, + 0xCC,0xFE,0xFF,0xCF,0x42,0xC0,0xEC,0x28, + 0x74,0x14,0x67,0xF9,0x2A,0xF4,0x04,0xF0, + 0x02,0x10,0x23,0xCC,0x3B,0xD0,0x4B,0x26, + 0xBB,0x8B,0x1B,0xE7,0xC9,0xE5,0x2C,0x9E, + 0xC4,0x7D,0x09,0xF2,0x81,0xE2,0x59,0xC8, + 0x50,0xA7,0x1B,0xF4,0x8D,0xDC,0x03,0x8B, + 0x19,0x3F,0xC4,0xF3,0x90,0x21,0x9E,0x85, + 0x00,0x76,0xFD,0xFF,0xCF,0x42,0x00,0xFF, + 0xFF,0xFF,0x47,0x03,0xF8,0x2F,0x00,0x9F, + 0x85,0x80,0xE7,0x09,0xE0,0x41,0xDB,0x67, + 0x21,0x80,0x33,0x87,0xCB,0xF3,0x7F,0x05, + 0x3A,0x96,0xF7,0x08,0xCF,0xFA,0x24,0x5F, + 0x2F,0x3D,0xD3,0x87,0x82,0x67,0x21,0x86, + 0x75,0x18,0x3E,0x0B,0x31,0x88,0x17,0x4D, + 0x43,0xBC,0x70,0xFA,0x30,0xE0,0xFF,0x3F, + 0x5E,0xE0,0x57,0x4E,0x03,0x05,0x09,0xF4, + 0x2C,0x04,0x30,0xFE,0xFF,0x7F,0x16,0x02, + 0xC8,0xB8,0x46,0x9D,0x85,0x80,0xE5,0x6D, + 0xE5,0x19,0xDB,0xA7,0x95,0x04,0xFF,0xFF, + 0x67,0x21,0xC0,0x41,0x2E,0x23,0x07,0x21, + 0x4C,0xC4,0x87,0x83,0x8F,0x99,0x80,0x9E, + 0x29,0xBE,0xB8,0x1B,0xE3,0x09,0xE0,0x45, + 0xE2,0x31,0x93,0x1D,0x35,0x0D,0xF3,0x2C, + 0x64,0xBC,0xB3,0x78,0x0D,0x78,0x82,0xF7, + 0xE4,0x9F,0x85,0x18,0xD8,0x61,0x05,0x7B, + 0x14,0x32,0xA8,0xC1,0x63,0x87,0x08,0x13, + 0xE8,0x59,0x88,0xC5,0x7D,0xAE,0xE8,0x3C, + 0xE1,0xB3,0x10,0xF0,0xFE,0xFF,0x9F,0x25, + 0xE0,0x5E,0x0D,0x9E,0x85,0x00,0x13,0x87, + 0x0D,0x9F,0x35,0xC0,0x33,0x7C,0x8F,0xEA, + 0x1C,0x1E,0x8F,0x81,0x7F,0x56,0x1D,0xE7, + 0x04,0x96,0x7B,0xD1,0xB2,0x71,0xA0,0xA1, + 0x23,0xB2,0x3A,0x20,0x8D,0x0D,0x73,0x29, + 0x89,0x7C,0x72,0x6C,0xD4,0x56,0x04,0xA7, + 0x33,0x93,0x4F,0x00,0xD6,0x42,0x21,0x05, + 0x34,0x1A,0x8B,0xE1,0x9D,0xF9,0xE8,0x44, + 0x41,0x0C,0xE8,0xE3,0x90,0x6D,0x1C,0x0A, + 0x50,0x7B,0xD1,0x14,0xC8,0x39,0x07,0xA3, + 0x7F,0x76,0x74,0x36,0xBE,0x13,0x70,0x0D, + 0x10,0x3A,0x25,0x18,0xDA,0x6A,0x04,0xFC, + 0xFF,0x67,0x89,0x01,0x33,0xFE,0x53,0x8C, + 0x09,0x7C,0x8E,0xC1,0x1F,0x0C,0xF0,0x03, + 0x7F,0x31,0xA8,0xFA,0x5E,0xA0,0xFB,0x82, + 0xD5,0xDD,0x64,0x20,0xCC,0xC8,0x04,0xF5, + 0x9D,0x0E,0x40,0x01,0xE4,0x0B,0x81,0xCF, + 0x51,0x0F,0x05,0x6C,0x22,0x21,0xC2,0x44, + 0x33,0x3A,0x62,0xC2,0xA8,0xE8,0x13,0xA6, + 0x20,0x9E,0xB0,0x63,0x4D,0x18,0x3D,0x13, + 0x5F,0x74,0xD8,0x88,0x31,0x21,0xAE,0x1E, + 0xD0,0x26,0x18,0xD4,0x97,0x22,0x58,0x43, + 0xE6,0x63,0xF1,0x05,0x02,0x37,0x65,0x30, + 0xCE,0x89,0x5D,0x13,0x7C,0xD9,0xC1,0xCD, + 0x19,0x8C,0xF0,0x98,0xBB,0x18,0xBF,0x3A, + 0x79,0x74,0xFC,0xA0,0xE0,0x1B,0x0E,0xC3, + 0x7E,0x32,0xF3,0x8C,0xDE,0xCB,0x7C,0x8D, + 0xC3,0xC0,0x7A,0xBC,0x1C,0xD6,0x68,0x61, + 0x0F,0xED,0x3D,0xC4,0xFF,0xFF,0x43,0x8C, + 0xCF,0x13,0xC6,0x08,0xEB,0xDB,0x0B,0x38, + 0xEE,0x59,0xF0,0xEF,0x1A,0xE0,0xB9,0x84, + 0xF8,0xAE,0x01,0x30,0xF0,0xFF,0x7F,0xD7, + 0x00,0x4E,0xD7,0x04,0xDF,0x35,0x80,0xF7, + 0xD0,0x7D,0xD7,0x00,0xAE,0xD9,0xEF,0x1A, + 0xA8,0x63,0x80,0x15,0xDE,0x35,0xA0,0x5D, + 0xD9,0xDE,0xD7,0x9E,0xB0,0xAC,0xE9,0xB2, + 0x81,0x52,0x73,0xD9,0x00,0x14,0xFC,0xFF, + 0x2F,0x1B,0x80,0x01,0x29,0x13,0x46,0x85, + 0x9F,0x30,0x05,0xF1,0x84,0x1D,0xEC,0xB2, + 0x01,0x8A,0x18,0x97,0x0D,0xD0,0x8F,0xED, + 0x65,0x03,0x18,0xDC,0x13,0xF8,0x6D,0x03, + 0x78,0x43,0xFA,0xB6,0x01,0xD6,0xFF,0xFF, + 0x6D,0x03,0xAC,0xF9,0x6F,0x1B,0x28,0x0E, + 0xAB,0xBC,0x6D,0x40,0x3C,0xC9,0x33,0x02, + 0xAB,0xBA,0x6E,0xA0,0xF4,0x5C,0x37,0x00, + 0x12,0x88,0x99,0x30,0x2A,0xFE,0x84,0x29, + 0x88,0x27,0xEC,0x68,0xD7,0x0D,0x50,0x04, + 0xB9,0x6E,0x80,0x7E,0x5E,0x09,0xFE,0xFF, + 0xAF,0x1B,0xC0,0xE0,0xA2,0x80,0xB9,0x6F, + 0x00,0x6F,0x58,0x7E,0xDF,0x00,0x7C,0xDC, + 0xC4,0x31,0xF7,0x0D,0xC0,0xCC,0xFF,0xFF, + 0xBE,0x01,0xB0,0xE7,0xA2,0x80,0xBB,0x6F, + 0x00,0xEF,0x8B,0xB4,0xEF,0x1B,0x60,0xFE, + 0xFF,0xDF,0x37,0xC0,0x28,0x6D,0xFD,0x1E, + 0x1C,0x3D,0x21,0x78,0x7C,0xB8,0xFB,0xA5, + 0xC7,0xE7,0xBB,0x39,0x38,0x06,0x79,0x8C, + 0x87,0x76,0xC0,0xAF,0xEF,0x9E,0x98,0xEF, + 0xE6,0xC0,0xFF,0x4C,0x70,0x3C,0x18,0x68, + 0x1C,0x62,0xAB,0x97,0x06,0x72,0x34,0x38, + 0x3F,0xDC,0x19,0x81,0x61,0x15,0x7F,0xF2, + 0x47,0x38,0xC7,0xD0,0xD9,0xE1,0x20,0xB1, + 0x83,0xE0,0xC1,0x56,0x6D,0x02,0x85,0x86, + 0x50,0x14,0x18,0x14,0x8B,0x0F,0x18,0xF8, + 0x61,0xB3,0xB3,0x00,0x93,0x04,0x87,0x3A, + 0x02,0xF8,0x3E,0xD1,0xFC,0x38,0x74,0x37, + 0x38,0x54,0x8F,0xE5,0xA1,0x80,0x9E,0x01, + 0x71,0xC7,0x0C,0x32,0x69,0xCF,0x28,0xE2, + 0x53,0xC2,0x29,0x85,0x49,0xE0,0xF3,0x03, + 0x43,0xE3,0x04,0xAF,0x0D,0xA1,0xF9,0xFF, + 0xFF,0xA4,0xC0,0x3C,0xDF,0x31,0x04,0x6C, + 0x02,0xBB,0xBF,0x64,0xC8,0xDA,0xC0,0x75, + 0x4B,0x32,0x44,0x6F,0x38,0xB2,0x85,0xA2, + 0xE9,0x44,0x79,0xDF,0x88,0x62,0x67,0x08, + 0xC2,0x88,0x12,0x2C,0xC8,0xA3,0x42,0xAC, + 0x28,0x2F,0x05,0x46,0x88,0x18,0xE2,0x95, + 0x23,0xD0,0x09,0x87,0x0F,0xF2,0xD8,0x14, + 0xA7,0xFD,0x41,0x90,0x58,0x4F,0x02,0x8D, + 0xC5,0x91,0x46,0x83,0x3A,0x07,0x78,0xB8, + 0x3E,0xC4,0x78,0xF8,0x0F,0x21,0x06,0x39, + 0xC8,0x73,0x7B,0x54,0x38,0x4E,0x5F,0x25, + 0x4C,0xF0,0x02,0xE0,0x83,0x0A,0x1C,0xD7, + 0x80,0x9A,0xF1,0x33,0x06,0x58,0x8E,0xE3, + 0x3E,0xA9,0xC0,0x1D,0x8F,0xEF,0x07,0x6C, + 0xC2,0x09,0x2C,0x7F,0x10,0xA8,0xE3,0x0C, + 0x9F,0xE7,0x0B,0x8B,0x21,0x1F,0x13,0x4C, + 0x60,0xB1,0x27,0x1B,0x3A,0x1E,0xF0,0xDF, + 0x63,0x1E,0x2F,0x7C,0x32,0xF1,0x7C,0x4D, + 0x30,0x22,0x84,0x9C,0x8C,0x07,0x7D,0x87, + 0xC0,0x5C,0x6F,0xD8,0xB9,0x85,0x8B,0x3A, + 0x68,0xA0,0x4E,0x0B,0x3E,0x28,0xB0,0x9B, + 0x11,0xE6,0xB8,0xCE,0xCF,0x2A,0x60,0xF8, + 0xFF,0x9F,0x55,0x60,0x8F,0x10,0xFE,0xED, + 0xC1,0xF3,0xF2,0x95,0xE1,0xD5,0x21,0x81, + 0x43,0x8E,0x10,0x3D,0x2E,0x8F,0x10,0x73, + 0x3E,0xC2,0x0C,0x11,0x5C,0x67,0x01,0x70, + 0x0C,0x11,0xF8,0x1C,0x70,0xC0,0x71,0x69, + 0xE2,0x03,0xF5,0x01,0x07,0x70,0x70,0x4D, + 0xC3,0x1D,0x70,0xC0,0x71,0x16,0x60,0xFF, + 0xFF,0xC3,0x0D,0x2C,0x49,0x26,0x0E,0x23, + 0x18,0x11,0x30,0x28,0x02,0x02,0xA4,0xB3, + 0x80,0x0F,0x29,0x00,0x1F,0xAE,0x0C,0x0F, + 0x29,0xD8,0x93,0x86,0x07,0x8E,0x1B,0x85, + 0x07,0x8D,0x0B,0x30,0x68,0x7A,0xE2,0x80, + 0x7F,0x4C,0xF0,0x19,0x05,0x1C,0xE3,0x06, + 0xDF,0x2A,0x0C,0xFC,0xFF,0x3F,0x30,0xCC, + 0xE1,0xC2,0x63,0x39,0x8A,0xA0,0x07,0x1E, + 0xD4,0xF7,0x8C,0x33,0xF7,0x24,0x8F,0xD1, + 0x51,0x0F,0x27,0xF4,0xE4,0x85,0x3B,0x57, + 0xF9,0x0A,0x71,0x14,0x18,0xB8,0x77,0x29, + 0x8F,0xCF,0x17,0x2B,0xC3,0x63,0x46,0xFB, + 0x1E,0x72,0xD6,0x11,0x02,0xE2,0x2F,0x75, + 0x6C,0xC0,0x60,0x39,0x18,0x00,0x87,0x01, + 0xE3,0x13,0x0D,0x58,0x67,0x1B,0x3C,0xF4, + 0x69,0x31,0xC4,0xE3,0x0B,0xFB,0x56,0x61, + 0x82,0xEA,0x41,0x75,0x12,0xF4,0xD0,0xC0, + 0x01,0xE8,0xA1,0xC1,0x3F,0xB9,0x90,0xFB, + 0x2B,0x1D,0x82,0xB5,0xE2,0x69,0xDE,0x47, + 0x1E,0xF3,0xDC,0xA2,0xBC,0x0D,0x3C,0x07, + 0xF0,0xD3,0x82,0x87,0xE3,0x63,0x81,0xC7, + 0xE9,0x4B,0x58,0x82,0xF7,0x1A,0x9F,0x6C, + 0x1E,0x5C,0x58,0xB2,0x21,0xA0,0x06,0xEB, + 0x21,0x60,0xA6,0x9A,0xC0,0x49,0x46,0x80, + 0xCA,0x00,0xA1,0x1B,0xCB,0xE9,0x3E,0x8B, + 0x84,0x38,0xCD,0x47,0x99,0xC7,0x02,0x8F, + 0xF5,0xC1,0xC0,0xFF,0x7F,0xCD,0x23,0xD4, + 0x7D,0xCD,0x33,0x7B,0x3A,0xC0,0xAC,0x22, + 0xDC,0x7B,0xCE,0x1B,0x86,0xD1,0x9E,0x2D, + 0x7C,0xCD,0x78,0xD6,0x34,0x42,0x38,0x76, + 0x83,0xF3,0x48,0x8C,0xF0,0x82,0xC0,0x4E, + 0x0C,0x0F,0x30,0xC6,0x39,0x79,0xC3,0xFA, + 0xC2,0xCB,0x40,0x83,0x19,0xDB,0x97,0x01, + 0x36,0x2A,0xDF,0x88,0xC0,0x97,0xFC,0x62, + 0x00,0x65,0x16,0xBE,0x9E,0xF8,0xA0,0xC4, + 0x2E,0x06,0x2C,0xE5,0xC5,0x00,0x54,0x37, + 0x0C,0x5F,0x0C,0xE0,0x5F,0x89,0x5E,0x0C, + 0xC0,0x70,0x71,0xF2,0x3D,0xC0,0x1E,0xEE, + 0xA3,0x74,0x9C,0xBE,0xFD,0xBD,0x19,0xF8, + 0x6C,0xC0,0x60,0x3C,0xC3,0x30,0xC6,0x08, + 0xE3,0x51,0x86,0x31,0xC1,0xDC,0xB7,0x03, + 0xE8,0x39,0x87,0x81,0x4A,0x78,0x3B,0x80, + 0x72,0x0E,0xE8,0xF2,0x68,0x42,0x4F,0x01, + 0x4F,0x07,0x3E,0x29,0x1A,0xA2,0xAF,0xB1, + 0x0A,0x26,0x50,0xC4,0x07,0x0D,0x3E,0xB5, + 0x28,0x3E,0x15,0x78,0x2D,0xCF,0x4E,0xE1, + 0xE2,0x9C,0x89,0xA7,0x6A,0x38,0x03,0xBD, + 0xE6,0x86,0x63,0xFF,0x7F,0x38,0xFC,0xA9, + 0xE0,0x35,0x80,0x1D,0x24,0x3D,0x2D,0x23, + 0xC2,0x38,0xA4,0x3C,0x32,0xF8,0xB6,0x18, + 0xC7,0x90,0x0F,0x91,0xBE,0x13,0x18,0xF2, + 0x21,0xEF,0x79,0xC7,0xC0,0xAF,0x08,0x71, + 0x9E,0xB2,0x7C,0x67,0xF0,0x65,0x01,0x7C, + 0x91,0x2E,0x0B,0x68,0x68,0x9F,0x64,0x7C, + 0x41,0x30,0xEC,0x89,0xB3,0x00,0x77,0x05, + 0x50,0x81,0xFA,0xAE,0x00,0xFF,0x42,0xF0, + 0xAE,0x00,0x86,0x79,0xF9,0x56,0xC0,0x35, + 0x1D,0x4A,0xD0,0x67,0x12,0x5F,0x17,0x70, + 0x53,0x64,0xA9,0x8E,0x0A,0xD0,0x53,0x4C, + 0x02,0x75,0x47,0xF7,0x51,0x01,0xC6,0x4D, + 0xD9,0x07,0x54,0x76,0x5A,0x60,0x67,0x21, + 0x76,0x1D,0xC1,0x5D,0x49,0x18,0xCA,0xB3, + 0x81,0x2F,0x59,0xFC,0x70,0x00,0x03,0xDC, + 0xB3,0x38,0xC4,0x08,0xB1,0xD9,0x81,0xEB, + 0x75,0xD2,0x70,0x2F,0x44,0xEC,0xFF,0x7F, + 0x32,0x00,0xE3,0x51,0x1B,0x1C,0x27,0x9D, + 0xF0,0x91,0x9E,0x59,0xF8,0x49,0x19,0x30, + 0x71,0xF2,0x03,0xE3,0xC9,0x1A,0xC6,0x00, + 0xB8,0xBC,0x57,0x95,0x81,0xFC,0x43,0x90, + 0x20,0x18,0xD4,0x29,0x19,0x38,0x1C,0xC5, + 0x70,0xA7,0x64,0x78,0x50,0xF8,0xC3,0x00, + 0xE6,0x46,0xE8,0x7B,0x82,0xA1,0xDE,0x93, + 0x0E,0xE3,0x91,0xD0,0x04,0x3E,0x2D,0xC3, + 0xFA,0xFF,0x9F,0x96,0x81,0xD5,0xB1,0xDD, + 0x43,0xF6,0x59,0x01,0x77,0x76,0x80,0x3B, + 0x3D,0x7E,0x7A,0x00,0x9C,0x00,0x3D,0x3D, + 0x80,0xED,0xBC,0x01,0xF7,0x40,0x80,0x38, + 0xFE,0xA3,0x82,0x5F,0x59,0x28,0x1C,0x3F, + 0xB6,0xF3,0x63,0x09,0xEE,0x70,0xE0,0x23, + 0x83,0x0F,0x90,0xB8,0xA1,0xF8,0x50,0x81, + 0x3C,0x0B,0x80,0x62,0xF4,0x6C,0x04,0xEC, + 0x06,0xF3,0xD2,0x12,0xE5,0xFF,0xFF,0xDE, + 0xC0,0x4E,0x29,0xB8,0x83,0x00,0xF8,0x8E, + 0x01,0xE0,0x1D,0x0C,0x97,0x35,0x66,0x94, + 0x10,0x18,0x8D,0x19,0x77,0x08,0xE1,0x27, + 0x02,0xDC,0x98,0x3D,0x6E,0x8F,0x19,0x77, + 0x9C,0xE5,0xA3,0x7A,0xCA,0x08,0xE5,0x03, + 0x07,0x3B,0x67,0xBC,0x11,0xF0,0xA1,0x03, + 0x8F,0x03,0x0C,0xEE,0x48,0x01,0xC6,0xCB, + 0x01,0x1B,0x3B,0xB8,0x83,0x90,0x53,0x20, + 0x4B,0x87,0xD1,0xD8,0x71,0xB2,0x81,0x74, + 0x8C,0xF1,0x21,0xD7,0x63,0xC7,0x0D,0xD6, + 0x63,0xC7,0x1D,0x5F,0xB0,0xFF,0xFF,0xE3, + 0x0B,0x18,0xC6,0xC0,0xC5,0x0F,0x03,0x7D, + 0xF3,0xF3,0xE8,0x0C,0xEE,0x61,0xFB,0x04, + 0x13,0xE3,0xF9,0x25,0xC4,0x23,0xCC,0x8B, + 0x4B,0x84,0xA3,0x08,0xF2,0xE6,0x12,0xE7, + 0xD5,0x20,0xCC,0x63,0x4B,0x94,0x10,0x11, + 0x0E,0x26,0xCE,0x13,0x8C,0x11,0x0E,0x3C, + 0x8A,0x21,0x22,0x9C,0x40,0x88,0x93,0x3E, + 0xD9,0x20,0xE1,0x63,0x84,0x8D,0xF6,0x04, + 0xC3,0xC7,0xC2,0xCF,0x2B,0x1E,0x3C,0x3F, + 0xAD,0xF9,0x2E,0xE8,0xC9,0x9C,0xE3,0x43, + 0x96,0xA7,0xF6,0x38,0xE9,0xC3,0x2C,0x6E, + 0x50,0x0F,0x8E,0xEC,0xAE,0xE3,0xE3,0x35, + 0xF6,0x14,0xE4,0x21,0xF0,0x13,0x81,0x2F, + 0x88,0x9E,0xAC,0xEF,0x7A,0xEC,0x5E,0x66, + 0x8C,0xEA,0xA7,0x80,0x3A,0xA6,0x9C,0xC1, + 0x2B,0x04,0xBB,0xE7,0xF9,0x90,0xED,0xBB, + 0x24,0x1B,0x05,0xEE,0x90,0xE0,0x33,0x12, + 0x3F,0x55,0x78,0x18,0x1E,0x05,0x8C,0x19, + 0xBC,0x23,0x1C,0x5A,0x88,0x03,0x7E,0xDF, + 0x65,0x43,0x8D,0x71,0x7A,0x3E,0x7F,0xB0, + 0x41,0xC0,0x87,0x3A,0x54,0x0F,0xF3,0xA8, + 0x5E,0x0A,0x19,0xCE,0xD9,0xC1,0x1D,0x04, + 0xF6,0xF8,0xE1,0x41,0xF0,0x9B,0x25,0x1F, + 0x04,0x3B,0xDF,0xBC,0xC1,0x19,0xE4,0xFF, + 0x7F,0x0C,0xB0,0xCF,0x54,0x3E,0x9A,0x20, + 0x8E,0x80,0xE8,0xF3,0x87,0xC7,0xF0,0x26, + 0xC7,0x87,0x83,0x3D,0x7A,0xE0,0x4E,0x22, + 0x70,0x8F,0x5D,0x07,0xED,0x6B,0x9C,0x2F, + 0x5A,0x30,0xEE,0x7B,0xCF,0x22,0xE0,0xC7, + 0x78,0x6C,0x01,0xC7,0xA1,0x04,0xDC,0xC1, + 0x8E,0x6B,0x1C,0x42,0x51,0x60,0x74,0x28, + 0xC1,0xC5,0x00,0x12,0x8C,0x63,0x9C,0xD1, + 0xD0,0x97,0x48,0x1F,0xD2,0xE0,0x0C,0x1A, + 0xF6,0x3C,0x9F,0x50,0xB8,0x3D,0x01,0x8A, + 0x4E,0x28,0x20,0xC3,0x7D,0x06,0xC1,0x9E, + 0x10,0xF8,0x19,0x84,0xFD,0xFF,0x0F,0x8E, + 0x1E,0xF7,0x7B,0xA3,0x4F,0x8D,0x6C,0xEE, + 0x0F,0x01,0x27,0x70,0xEE,0xEC,0xD4,0x8C, + 0x3B,0x33,0x60,0xCF,0x1F,0x1E,0x02,0x3F, + 0x17,0x78,0xF8,0x1E,0x02,0x7E,0xF0,0x0F, + 0xCC,0x06,0x07,0xE3,0x29,0xC2,0xD7,0x0E, + 0x0E,0xCE,0x4F,0x03,0x06,0xE7,0xAF,0x50, + 0x9F,0xE7,0x19,0x38,0xF6,0xD4,0xEB,0x7B, + 0x87,0xE7,0xEB,0x43,0x05,0xFE,0xA6,0xE7, + 0x43,0x05,0x38,0x0E,0x0F,0xFC,0xB0,0xC2, + 0x86,0xF0,0x28,0x80,0x3F,0xB5,0xF8,0xF8, + 0x17,0xE7,0x29,0x82,0xDD,0x46,0xB0,0x87, + 0x0B,0xC0,0x51,0xB4,0xB3,0x18,0x2A,0xCC, + 0x59,0x8C,0xFC,0xFF,0xCF,0x51,0xA8,0xB3, + 0x18,0x3D,0x5C,0x00,0x2E,0x04,0x1F,0x0F, + 0x40,0x73,0x10,0x78,0x5C,0xF0,0x85,0xE0, + 0x48,0x0E,0xE4,0xE9,0x00,0xF0,0x19,0x4A, + 0xC3,0xA1,0x09,0x13,0x03,0x06,0x75,0x3E, + 0xF0,0x09,0xC5,0xC7,0x0E,0x7E,0x36,0xF0, + 0x8D,0xDC,0x43,0xE5,0xA7,0x66,0x5F,0xF2, + 0x11,0xE0,0x02,0x75,0xA0,0x61,0xA0,0x46, + 0xE4,0x23,0xD2,0xFF,0xFF,0xB9,0x0D,0x1B, + 0x60,0x68,0xF4,0x1C,0x0E,0xE3,0x80,0xEB, + 0x73,0x38,0x76,0x40,0x3E,0x87,0xC3,0x3F, + 0x47,0xC3,0x1F,0x1B,0x3B,0xDD,0xF3,0x81, + 0xC1,0xBA,0x7E,0x63,0x06,0x06,0xB6,0x6F, + 0x91,0x07,0x06,0x1C,0x51,0xCF,0xC6,0x57, + 0x08,0x0F,0x0C,0x6C,0x80,0x1E,0x18,0xF0, + 0x89,0x05,0x21,0x27,0x03,0x43,0x9D,0x32, + 0x8C,0x1C,0xF3,0x89,0xC3,0xC3,0xF0,0xA1, + 0x22,0xEA,0x33,0xC0,0x23,0x1E,0x1B,0x1B, + 0xFB,0xFF,0x8F,0x0D,0x2C,0xC7,0x16,0x8F, + 0x0D,0xFC,0x47,0x78,0xFC,0xD8,0xE0,0x8C, + 0xE5,0xD1,0xC4,0x97,0x99,0x23,0x3B,0x8D, + 0x33,0x7B,0x0D,0xF1,0xD1,0xEE,0xF1,0xDB, + 0x63,0x03,0x97,0x85,0xB1,0x01,0xA5,0x90, + 0x63,0x43,0x1F,0x52,0x7C,0x0A,0xB0,0x71, + 0x54,0x32,0x0F,0x1F,0xAF,0x7C,0x62,0x38, + 0xBA,0x20,0x6F,0xE8,0xBE,0x5C,0xF8,0x48, + 0x63,0x30,0x5F,0x5A,0x7C,0x06,0xE5,0x43, + 0x04,0xD7,0x57,0xC5,0x43,0x04,0x3E,0xA1, + 0x86,0x88,0x1E,0xCF,0xFF,0xFF,0x11,0xCC, + 0x43,0x64,0x43,0x03,0xAF,0x87,0xA1,0x01, + 0xA5,0x98,0xC0,0x5E,0x85,0x87,0x46,0x4F, + 0x3F,0x3E,0x04,0x30,0x08,0xDF,0x06,0xD8, + 0x55,0xC0,0x57,0x21,0x83,0x24,0x18,0xE7, + 0x64,0x41,0x07,0x07,0x8E,0x21,0x79,0x70, + 0xF0,0x07,0xE3,0x21,0x70,0x60,0xCF,0xE0, + 0xB9,0xE8,0x31,0xD8,0xA7,0x1D,0x9F,0x4A, + 0xC0,0x77,0xE6,0x04,0xC7,0xE9,0x1D,0x7B, + 0x29,0xF0,0x08,0x1E,0xAD,0x3C,0x02,0x7E, + 0xB4,0x02,0x66,0xFF,0xFF,0xA3,0x15,0x30, + 0x09,0x7A,0xE6,0xA4,0x03,0x77,0x34,0x18, + 0xD4,0xD1,0x0A,0x5C,0x11,0xC0,0x75,0xDC, + 0xF0,0xD1,0x02,0xCE,0x50,0x0F,0xDA,0x07, + 0x65,0xCF,0xDA,0x97,0x21,0x76,0xB4,0x00, + 0x97,0x89,0x43,0x08,0xD0,0x04,0x3E,0x89, + 0x67,0xEF,0x43,0x03,0xB3,0x8A,0xA1,0x01, + 0xA5,0xA3,0x01,0xEE,0x44,0x81,0xFD,0xFF, + 0x9F,0x28,0x60,0xDE,0x30,0x70,0x07,0x0A, + 0xC0,0xCD,0xE9,0xDB,0xE3,0xE2,0xD0,0x38, + 0xC4,0xE7,0xA7,0x73,0xF6,0xD1,0xE8,0x4C, + 0x71,0x67,0x11,0x30,0x9C,0x7D,0x11,0x8F, + 0x18,0x03,0xF9,0x81,0x21,0x59,0x30,0x28, + 0x16,0x0F,0xC5,0x07,0x03,0x0E,0xEC,0x23, + 0x02,0x3B,0x17,0xB0,0x73,0xAD,0xE1,0xF8, + 0x59,0xC0,0xA7,0x84,0xB7,0xA6,0x17,0x7B, + 0x9F,0xD7,0x7D,0xD6,0x08,0xC9,0xCE,0xF4, + 0x3E,0x89,0xE2,0x0E,0xA2,0x70,0x4E,0x9F, + 0xE0,0x22,0xF0,0x65,0xDF,0xA3,0xE0,0xA7, + 0x07,0xCF,0xF1,0x8D,0xC1,0xA7,0x07,0xE6, + 0x7E,0xF8,0x9A,0xF1,0x33,0xC3,0xE3,0x43, + 0x88,0x27,0xE2,0xDA,0xA6,0x20,0x5B,0x18, + 0x42,0x09,0xF4,0xFF,0x8F,0x10,0xE5,0x6D, + 0x20,0xCA,0x29,0x44,0x88,0x12,0xA4,0xB1, + 0xC9,0x0B,0x35,0xCA,0xD9,0x45,0x6E,0x6D, + 0xF6,0x82,0x0B,0x14,0x2A,0x66,0x9C,0x28, + 0xEF,0x10,0xB1,0xDA,0x1F,0x04,0x91,0xF4, + 0x32,0xD0,0x71,0xC9,0x91,0x0E,0x7D,0xE8, + 0x61,0xFB,0x04,0x8C,0x3F,0x48,0xE2,0xAE, + 0x2A,0x3E,0x28,0xF8,0x00,0x80,0x77,0x09, + 0xA8,0x5B,0x9D,0xC7,0xED,0xF3,0x06,0xF8, + 0xAF,0x17,0x58,0x82,0xF2,0x07,0x81,0x1A, + 0x99,0xA1,0x3D,0xCC,0xB7,0x19,0x43,0xBE, + 0x07,0x1C,0x16,0x3B,0x27,0xF9,0xF0,0x08, + 0x1C,0x8E,0x01,0x4F,0x1B,0xBE,0x51,0x7B, + 0xBE,0x3E,0x62,0x01,0x8E,0xFE,0xFF,0x47, + 0x2C,0x30,0x9D,0xDF,0x7D,0x82,0x01,0xC7, + 0xCD,0x82,0x9F,0x61,0x00,0x67,0x40,0xCF, + 0x30,0x60,0x1F,0x2A,0x6E,0x08,0x5C,0xEE, + 0x8A,0x28,0x90,0x05,0xC2,0xA0,0x0E,0xFD, + 0xE4,0x08,0x42,0xCF,0x9C,0x70,0x86,0x72, + 0xB2,0xBD,0x5F,0x1D,0xC8,0x2D,0xC2,0x43, + 0x3D,0x8B,0xC7,0x04,0x76,0xDA,0x02,0x36, + 0xFF,0xFF,0xE3,0x29,0xB0,0x98,0xF7,0xD3, + 0x69,0x84,0x63,0x03,0xFB,0x71,0x0B,0x38, + 0x1D,0xCC,0xE0,0xDC,0x7F,0xD8,0x2D,0x1A, + 0x37,0x34,0xB0,0x0D,0xCC,0x43,0x03,0x3E, + 0x27,0x47,0x30,0x9E,0x98,0xF8,0x55,0xE2, + 0xE1,0x89,0x1F,0x43,0xC0,0xFA,0xFF,0x3F, + 0x99,0x01,0xF6,0x84,0x1E,0xCB,0x50,0xD2, + 0x4E,0x66,0x80,0xC0,0xFB,0xD8,0x3B,0xC3, + 0x4B,0x83,0xE7,0x74,0xD2,0xCF,0x62,0x3E, + 0x99,0x19,0x21,0x0A,0xBB,0x8F,0x19,0xAD, + 0x37,0x14,0xCD,0x3C,0xE8,0x3B,0x99,0x51, + 0x62,0x46,0x6A,0x0E,0x4C,0x48,0x11,0x0F, + 0x27,0x4A,0x88,0x60,0xAF,0x13,0x6F,0x67, + 0x4F,0x66,0x4C,0xD6,0xC9,0x0C,0x24,0xFF, + 0xFF,0x93,0x19,0x98,0x5C,0x9F,0xCC,0x80, + 0xCA,0x39,0x0A,0x7F,0x32,0x03,0x78,0x74, + 0xC0,0xC2,0x9D,0xCC,0xC0,0xF2,0xFF,0x3F, + 0xC4,0x00,0xCE,0xC7,0x0A,0x63,0x0C,0x3C, + 0xDA,0xC1,0x0C,0x15,0xE6,0x6C,0x86,0x0E, + 0x72,0x08,0xA1,0xC1,0x0E,0x21,0x50,0xE6, + 0x72,0xA0,0xA7,0xF0,0x9A,0xE0,0x73,0x14, + 0xD8,0x0F,0x67,0xC0,0xE1,0xD4,0x80,0x0F, + 0x74,0xE2,0x42,0x8F,0xC2,0x23,0x0E,0x58, + 0xFD,0xC0,0xC8,0xFF,0xFF,0x64,0x06,0x18, + 0x78,0x6A,0xF8,0x40,0x82,0x63,0x31,0xEA, + 0x1B,0xC4,0x21,0xBE,0x8D,0xF8,0xE8,0xFE, + 0x6A,0xE2,0x4B,0x00,0xE6,0x42,0xE2,0xD3, + 0x09,0xB3,0x70,0x38,0x03,0x5A,0x43,0x60, + 0x57,0x26,0xCF,0x9C,0x0F,0xE1,0x6C,0x3C, + 0x7A,0xDC,0xE9,0x04,0xDE,0x38,0x7C,0x3A, + 0x01,0x5E,0x07,0x0C,0xCC,0x0C,0xC2,0x3F, + 0x84,0xB0,0x21,0x9C,0xAA,0xC7,0x70,0xEE, + 0xAF,0x38,0x3E,0x9D,0x80,0xF3,0xFF,0x7F, + 0x62,0x03,0x0C,0x0A,0x7E,0x32,0xF8,0xB8, + 0x46,0x25,0xC2,0xA0,0x8E,0xE6,0x80,0x7B, + 0x98,0x27,0x36,0x26,0x6F,0xC5,0x1A,0x8B, + 0x4F,0x6C,0x30,0xFF,0xFF,0x27,0x36,0x80, + 0xD1,0x87,0x20,0xB0,0xFD,0xFF,0x0F,0x41, + 0x60,0x1C,0xA0,0x0F,0x41,0x80,0x9B,0xD3, + 0x09,0xEE,0xC4,0x07,0xB6,0x63,0x10,0x60, + 0x6D,0xE8,0x3E,0x06,0x81,0xF9,0xFF,0x3F, + 0x5A,0x98,0xA3,0xE0,0xC2,0x8E,0x7C,0x28, + 0x29,0xA7,0x3E,0xB4,0x0C,0x20,0x69,0x38, + 0xC9,0x01,0x9D,0xD3,0x3D,0x70,0x92,0x75, + 0xEA,0x40,0x8F,0xC7,0xA0,0xAF,0x1C,0xBE, + 0x12,0xF0,0x23,0x07,0x93,0x00,0xAA,0x41, + 0xFA,0xCC,0x07,0x9C,0x8E,0x1C,0xE0,0x38, + 0x26,0x05,0xC6,0xDE,0x0E,0xDE,0x22,0x3D, + 0x89,0xA7,0xA1,0xE3,0x0C,0x51,0x38,0x26, + 0x39,0x18,0x44,0x7A,0x95,0x62,0x03,0x7C, + 0xAB,0xF1,0xD9,0xC8,0x07,0x10,0x78,0xE3, + 0xF6,0xD8,0x61,0xFF,0xFF,0x0F,0x75,0xC0, + 0x01,0xE2,0xA4,0xF8,0x21,0xC3,0x98,0x67, + 0xC5,0x0F,0x75,0x80,0xF5,0x18,0x27,0x3A, + 0x94,0xF0,0x43,0x1D,0x20,0xE8,0xFF,0x7F, + 0xA8,0x03,0x86,0x38,0x6F,0x24,0xD1,0x1E, + 0xEA,0x98,0xE8,0x43,0x1D,0x40,0xC8,0xFF, + 0xFF,0xA1,0x0E,0x18,0x9E,0x87,0x00,0xAE, + 0x9C,0xEF,0xC0,0x7C,0x22,0x02,0xEF,0xFF, + 0xFF,0x7C,0x07,0xB8,0x1B,0x2D,0xCC,0x51, + 0x70,0x41,0xAF,0x0E,0x03,0x51,0x09,0x30, + 0x28,0x02,0xC7,0x5F,0x9B,0x60,0x1C,0xEA, + 0x7C,0x87,0x3E,0x2F,0x78,0xD8,0x4F,0x05, + 0x9E,0xC4,0xA9,0xFA,0x5A,0x70,0x14,0x4F, + 0x00,0x3E,0xE1,0x01,0xFF,0xA1,0xC1,0x9A, + 0x44,0xF1,0x43,0x03,0xF5,0x11,0xE4,0xFF, + 0x7F,0x68,0xC0,0x28,0xEA,0xF9,0x06,0x7D, + 0xCC,0xF2,0xD9,0x20,0xE6,0x0B,0x48,0x84, + 0x07,0x10,0x5F,0x1F,0xD8,0x71,0xD2,0x67, + 0xA0,0x40,0x51,0xDE,0x37,0xF8,0x09,0x07, + 0x5C,0x83,0xF3,0x09,0x07,0xBC,0x87,0x23, + 0x1F,0x4B,0xC0,0x77,0xD0,0x84,0x73,0x81, + 0xF1,0x8D,0x8D,0x9D,0x06,0xC0,0x76,0x00, + 0x06,0xDF,0x69,0x00,0x1C,0xC7,0x24,0x7E, + 0x3A,0x04,0x13,0xCC,0xC1,0xBC,0x34,0xFB, + 0xFF,0xEF,0xFD,0x94,0x43,0xCF,0x86,0x80, + 0x75,0x49,0x07,0x43,0x94,0x88,0xB3,0x21, + 0x20,0xFD,0xFF,0x7F,0x36,0xC4,0x20,0xC4, + 0x09,0xFC,0x12,0xD1,0xDC,0xD9,0x90,0xAE, + 0xD8,0x67,0x43,0x80,0xE1,0xFF,0xFF,0x23, + 0x00,0xF6,0x7C,0x04,0x38,0x3D,0x64,0x83, + 0xE7,0x14,0x08,0xE3,0xE4,0x03,0x38,0xFE, + 0xFF,0x8F,0x15,0xE6,0x18,0x78,0xEA,0x97, + 0x9B,0x8F,0x03,0x54,0xD4,0x2B,0xC2,0x30, + 0x94,0xC5,0x87,0x05,0x1F,0x11,0xF8,0x61, + 0xC1,0x23,0xA8,0x78,0x9C,0xF4,0x74,0xE3, + 0x33,0x21,0x3B,0x24,0x38,0xFC,0x20,0xE9, + 0x41,0x13,0x3C,0xE7,0x23,0x78,0xB7,0x1E, + 0x38,0xA7,0x02,0xC0,0x4D,0xAE,0x27,0xA3, + 0x4E,0x17,0x0E,0x70,0x8E,0x92,0x8D,0x63, + 0x08,0xE5,0x70,0xCC,0xB7,0x87,0xA6,0xC9, + 0x4E,0x56,0x30,0x63,0x41,0xEA,0x24,0xE0, + 0x01,0x38,0x10,0x8C,0xB4,0x93,0x68,0x34, + 0x86,0xB3,0x5A,0x18,0xC1,0x19,0xC4,0xC7, + 0x11,0xE7,0x3A,0x19,0xA1,0x3F,0x07,0x3E, + 0x15,0x61,0x82,0xDC,0x4B,0xE8,0xBC,0x7D, + 0x37,0xE0,0x57,0x61,0x8F,0xC5,0xFF,0x7F, + 0x60,0xDF,0x4E,0xC0,0x31,0x17,0xAB,0x01, + 0x45,0x0D,0xC0,0x68,0x98,0x53,0xC0,0x53, + 0x09,0xB8,0x82,0xCD,0x0D,0x7D,0x61,0xB1, + 0xD6,0xA9,0xE8,0x14,0xF4,0x3E,0x70,0x70, + 0xC0,0x63,0xF6,0x1E,0x1C,0x2C,0x34,0x0F, + 0x0E,0x6C,0xD9,0x06,0x87,0x56,0x72,0x17, + 0x21,0x87,0x0F,0xFC,0xEC,0x80,0x03,0xA0, + 0x67,0x07,0x0B,0xC9,0xB3,0x03,0x9B,0xBE, + 0xB3,0x08,0x28,0x70,0xFE,0xFF,0x11,0xDE, + 0x3B,0x7C,0x6E,0x79,0xF6,0x60,0x63,0x78, + 0x74,0x31,0x9A,0xD1,0xB9,0xA6,0xDB,0x04, + 0x4A,0xC5,0x6D,0x82,0x82,0xF8,0x06,0xE0, + 0x84,0x34,0xBA,0x75,0xE2,0x66,0x62,0xFC, + 0x47,0x0C,0x1F,0x11,0x0E,0xE9,0x6C,0x4D, + 0x30,0x0F,0xA4,0x9E,0x81,0xBE,0xB3,0xE1, + 0x67,0x1F,0xF2,0xC1,0xC5,0xD3,0xF0,0xF5, + 0x86,0xDC,0x3B,0xE8,0xB4,0x7D,0x66,0xC0, + 0x1C,0x74,0x7D,0x9D,0x7A,0x83,0x27,0x57, + 0x09,0xEA,0xE1,0x02,0x42,0x2F,0x34,0xBE, + 0xDC,0x25,0x78,0xE0,0xF4,0xE9,0xEE,0xBD, + 0x84,0x9D,0xF1,0x12,0xBC,0xE0,0x25,0x98, + 0x77,0x10,0xA8,0x51,0x79,0x10,0x98,0xAB, + 0x3C,0xCB,0x37,0x06,0x54,0xB2,0x8B,0x16, + 0x3D,0xC3,0xBC,0xC3,0xF8,0x92,0xE0,0xEB, + 0x87,0xCF,0x2D,0x5E,0xC0,0xEB,0x16,0x0C, + 0x82,0x67,0xA0,0x57,0x17,0xDF,0xD9,0x0D, + 0xFC,0x2A,0xF0,0x46,0x13,0x22,0x98,0x61, + 0x0F,0xFF,0xDD,0xDD,0xA8,0xBE,0xE9,0x18, + 0xEB,0x75,0xC4,0x23,0xE5,0xC7,0x96,0x03, + 0x8A,0xF4,0xF2,0xE6,0x09,0xF8,0x2C,0xE3, + 0x53,0xDD,0x49,0xF9,0x7A,0x68,0xF4,0x57, + 0x08,0x1F,0x7E,0x8C,0xEC,0x73,0x0E,0x3B, + 0xDF,0xB1,0x41,0x71,0xC4,0x07,0x86,0x97, + 0x1A,0x4F,0x85,0x9D,0xBB,0x60,0x1C,0x1C, + 0xD8,0xB1,0x08,0x73,0x7C,0x05,0xD7,0xC9, + 0xE6,0xFF,0xFF,0xE4,0x00,0x6E,0x78,0xCC, + 0xC1,0xD7,0xE7,0x0D,0xDF,0x0C,0x3C,0x2E, + 0x7E,0xE4,0xF0,0x49,0xE3,0xA5,0xD3,0xD8, + 0xA7,0xE9,0xA3,0xD1,0xCB,0x9B,0x4F,0x2F, + 0x18,0x58,0x5F,0x1A,0x38,0xAC,0xD1,0xC2, + 0x3E,0x06,0x9C,0xB9,0x2F,0x44,0xB8,0xC3, + 0x23,0x58,0x00,0xF1,0xB7,0x92,0x47,0x0E, + 0x4F,0xC0,0x80,0x4C,0xD3,0xBA,0x74,0x20, + 0xE2,0xA7,0x3C,0x2B,0x5F,0x99,0x2E,0x43, + 0x0C,0xE3,0xA9,0xF2,0xF1,0xC3,0xB3,0xF1, + 0x51,0xC0,0xC7,0x28,0xCF,0xFC,0x8C,0x22, + 0xBD,0x32,0x10,0x50,0x9D,0x88,0xB8,0x42, + 0x18,0x89,0xA1,0xD1,0x9D,0x83,0xC7,0x1F, + 0x22,0x05,0x31,0xA0,0x6F,0x2E,0xC0,0xF4, + 0x4C,0x04,0x5C,0xFE,0xFF,0x37,0x17,0x80, + 0xFF,0xFF,0xFF,0x9B,0x0B,0xE0,0xE6,0xFE, + 0xE0,0x9B,0x0B,0x70,0x8D,0xB4,0x2A,0x7A, + 0x61,0x77,0x08,0x18,0xD4,0x9D,0x1D,0x70, + 0x78,0x2B,0x78,0x67,0x87,0xF5,0xFF,0xBF, + 0xB3,0xC3,0xC3,0x8C,0x13,0xE5,0x85,0x21, + 0xC6,0x3B,0x3B,0x0B,0xF0,0x26,0xD0,0x51, + 0xC6,0x77,0x76,0x80,0x1F,0x67,0xD8,0x77, + 0x69,0xF0,0x5E,0x75,0x81,0xF5,0xFF,0xFF, + 0xAA,0x0B,0x3C,0x04,0xDF,0xA7,0x41,0x3E, + 0x5E,0x30,0x8C,0x83,0x2B,0x27,0xA1,0xC7, + 0x02,0x6B,0x85,0x41,0xDD,0xA9,0xC1,0xA5, + 0x09,0x5C,0x17,0x5F,0x1F,0x6A,0x7C,0xA4, + 0xC5,0x9F,0x2F,0x70,0x01,0x86,0x4C,0x4F, + 0x65,0x30,0xAE,0x29,0x3E,0x95,0x61,0xEE, + 0x0E,0x1E,0x90,0x8F,0x18,0xC0,0x67,0x15, + 0x1E,0x18,0xEE,0xB4,0xE0,0x9B,0x92,0x41, + 0xCF,0x31,0xA8,0x8F,0x3C,0x27,0xEF,0x7B, + 0xC2,0xE3,0x84,0xA3,0x9E,0x83,0xE8,0xD8, + 0xC0,0x71,0xDC,0xC0,0xFD,0xFF,0xC7,0x06, + 0xEF,0x70,0x83,0x3B,0xE8,0xF8,0x62,0x70, + 0x5C,0x18,0xB8,0xE7,0x02,0x0F,0xC3,0x37, + 0x1D,0x8F,0x08,0x33,0xFE,0xD7,0x3F,0x23, + 0x04,0xC4,0x5F,0x8C,0xD8,0x80,0xC1,0x78, + 0x6B,0xF3,0xF5,0x0D,0x37,0x60,0x5F,0x1D, + 0x7C,0xC1,0xF0,0x09,0xCC,0xE8,0x2F,0x30, + 0x4F,0x62,0x3E,0x36,0x90,0x0B,0x1C,0x1D, + 0x30,0x38,0x00,0x3D,0x60,0xF8,0x87,0x8B, + 0x77,0x39,0x30,0x5C,0x05,0x7D,0x5C,0xF0, + 0xB1,0xC7,0x8A,0xEE,0x72,0xE8,0x9B,0x9C, + 0x61,0xE2,0x18,0xE2,0x0D,0x8C,0xDD,0x25, + 0xC8,0x61,0x0E,0xEA,0x5D,0xC2,0x73,0xE0, + 0x67,0x0B,0x9F,0xE0,0x7C,0xF3,0x09,0x71, + 0xAA,0x8F,0x56,0xEF,0x01,0x3E,0x7A,0xBC, + 0x77,0xF9,0xEC,0xC4,0x2E,0x02,0x3E,0x72, + 0x19,0xC7,0xD3,0xF4,0x15,0xD0,0x43,0x36, + 0xD8,0xAB,0x86,0x4F,0x60,0x3E,0xBA,0xE1, + 0x8E,0x51,0x9E,0x89,0xA7,0xEF,0x3B,0x08, + 0x3B,0x92,0x1C,0x75,0xA8,0x6B,0x7A,0x44, + 0xF9,0xFF,0x9F,0xD0,0x81,0xF8,0xD6,0x06, + 0xCE,0x68,0xF7,0x0F,0xF4,0x36,0x3D,0x32, + 0xCC,0xD1,0x00,0xD6,0x25,0x04,0x5C,0x77, + 0x0C,0x5F,0x42,0x80,0x4F,0xD0,0x4B,0x04, + 0xFA,0x9A,0xE1,0xD1,0x3D,0x02,0x60,0xAE, + 0x18,0xEC,0x58,0xE0,0xC3,0x86,0xAF,0x01, + 0xEC,0x5E,0xE0,0x30,0xF7,0x08,0x50,0x81, + 0x7A,0x78,0xF0,0xD5,0xDE,0x23,0x40,0x71, + 0xB2,0xF4,0xA1,0xC1,0x03,0xB5,0xAA,0x33, + 0x26,0x94,0x23,0x26,0x3F,0x9B,0xF9,0x26, + 0x81,0xB9,0x5D,0xFA,0x26,0x01,0x37,0xCF, + 0x2C,0x50,0x49,0x20,0xF4,0xFF,0xBF,0x49, + 0xC0,0x85,0xE9,0xF2,0x32,0x43,0xE7,0x7F, + 0xE0,0xBE,0xD5,0x79,0x84,0x3E,0x44,0x30, + 0x94,0xF7,0x3C,0x9F,0xC2,0xF8,0x19,0xC2, + 0x07,0x4C,0x76,0xA6,0xE0,0x67,0x4D,0xDC, + 0x1D,0xC0,0x28,0x6F,0x9E,0x9E,0x00,0x3B, + 0x7F,0x1A,0xF9,0xDD,0xE0,0x5D,0xC0,0xD3, + 0xF7,0xBD,0x88,0x9F,0x28,0xC0,0x17,0xEC, + 0x4E,0x07,0x05,0xFA,0x84,0x3C,0x22,0xA3, + 0xFA,0x88,0xC0,0x2F,0x49,0x60,0x3C,0x92, + 0xF8,0x40,0x01,0x84,0xEE,0x05,0xA8,0xD3, + 0x07,0x47,0x3D,0xE3,0x17,0x54,0x63,0xBE, + 0x5B,0x3D,0xC2,0x79,0x72,0x98,0xCB,0x01, + 0x8B,0x73,0x4D,0x02,0xD5,0x71,0x97,0x8F, + 0x0E,0xEE,0xB5,0x15,0xFB,0xFF,0x27,0x38, + 0xB8,0x77,0x96,0x77,0x3E,0x43,0x79,0x90, + 0xE0,0xBB,0xB6,0x82,0xE3,0xAA,0x06,0xE3, + 0xD8,0xC2,0x2F,0x79,0x80,0x9D,0x61,0x71, + 0xC1,0x7F,0x0F,0x03,0x51,0x89,0x30,0x28, + 0x02,0xCB,0xBB,0xB7,0x52,0xF8,0x43,0x06, + 0xE3,0x4D,0x81,0x4F,0x1A,0x3B,0x6A,0xE0, + 0xFB,0xFF,0x1F,0x35,0xD8,0x86,0x8A,0xBB, + 0x29,0x82,0x75,0xAA,0x98,0x21,0xF0,0x60, + 0x0F,0x00,0x9F,0xAF,0x7C,0x06,0x50,0x14, + 0x18,0xD4,0xA1,0x1D,0xCE,0x6D,0x18,0x70, + 0x30,0x62,0xDC,0xA5,0x10,0xEE,0x94,0xDF, + 0x51,0x62,0x3F,0x97,0xB3,0xE9,0xE2,0xAE, + 0xE6,0x3E,0x9D,0xB0,0x0B,0x32,0x8C,0xB3, + 0xC0,0x23,0xC0,0xAB,0x39,0xBF,0x20,0x3F, + 0x17,0xBF,0x10,0x3C,0x26,0x85,0x78,0x53, + 0x7A,0x25,0x36,0xC6,0x93,0x71,0x73,0xB7, + 0x62,0x72,0xDE,0x79,0x41,0x36,0xC6,0xD1, + 0x44,0x8C,0x72,0x6E,0x0F,0x03,0x91,0x5F, + 0x90,0x7D,0x3F,0x79,0x21,0x88,0x18,0xCD, + 0x10,0x41,0x9F,0x97,0x8D,0x15,0x28,0xDE, + 0x0B,0x32,0x13,0xF8,0x56,0xD0,0xC1,0xC5, + 0x17,0x64,0xEC,0xFF,0xFF,0x82,0x0C,0x30, + 0xE2,0x64,0x04,0xF8,0x3C,0x71,0xE0,0xCE, + 0x35,0x30,0xFE,0xFF,0x97,0x6A,0xD8,0x27, + 0x1B,0xC0,0xD9,0xD0,0x7D,0xB2,0x01,0xF7, + 0x68,0xE1,0x1D,0x4D,0x10,0x27,0x1B,0x0A, + 0xE4,0xE0,0xEB,0xA2,0x70,0x3C,0xF4,0x49, + 0x84,0x1E,0x9D,0x7C,0x94,0xC4,0x9D,0x19, + 0x3C,0x91,0x77,0x16,0x8F,0xE2,0x65,0xD0, + 0xF7,0x82,0x13,0x79,0x7D,0xB0,0x9C,0x63, + 0x24,0xA8,0x46,0xE2,0xE3,0x03,0xFC,0xEB, + 0x8B,0x8F,0x91,0xF0,0xF9,0xFC,0xC3,0xF2, + 0x60,0x0C,0xF9,0xFF,0x7F,0x8A,0xC4,0x80, + 0x3C,0xBB,0x3C,0x86,0xF0,0x0B,0x24,0xDC, + 0xD3,0xCC,0x01,0x60,0x64,0x5D,0x1E,0xD1, + 0x67,0x47,0x8E,0x11,0xD7,0x17,0x45,0x5F, + 0x81,0x7D,0x10,0x38,0x9F,0xE7,0x44,0xB0, + 0x8E,0x9A,0x1F,0x6D,0xF8,0xF8,0x39,0xF8, + 0x5B,0xC1,0x03,0xA5,0x8F,0x45,0x21,0x1E, + 0x91,0xF8,0x39,0x11,0x5C,0x26,0xCE,0x89, + 0x40,0xE2,0xD0,0x0B,0xE3,0xB4,0x80,0x1B, + 0x88,0xCF,0x94,0xD8,0x29,0x9F,0x08,0x3B, + 0x97,0x60,0x46,0x07,0xAE,0xCB,0xBD,0x47, + 0x07,0xFE,0x93,0x00,0x1E,0xEB,0xFF,0xFF, + 0x78,0x07,0xBE,0x93,0xBA,0xEF,0x26,0xBE, + 0xC8,0xF8,0x50,0xF4,0x7C,0x07,0xF8,0x0F, + 0x77,0xB8,0x43,0xC5,0x39,0xDF,0x01,0xD2, + 0xFE,0xFF,0xE7,0x3B,0x60,0x79,0xB6,0x7E, + 0xBE,0x03,0xBB,0xC8,0xF3,0x1D,0x40,0xAC, + 0xFF,0xFF,0xF9,0x0E,0xB0,0x73,0x46,0xC3, + 0x9D,0xEF,0xC0,0x76,0xB4,0x01,0xCC,0x4D, + 0xE3,0xD1,0x06,0xDC,0xC3,0x85,0x3D,0x0C, + 0xAE,0xD0,0xA6,0x4F,0x8D,0x46,0xAD,0x1A, + 0x94,0xA9,0x51,0xE6,0xFF,0xDF,0xA0,0x56, + 0x9F,0x4A,0x8D,0x19,0xCB,0x0E,0xA5,0x80, + 0x8F,0x0A,0x8D,0xCD,0xF2,0x28,0x04,0x62, + 0x31,0xAF,0x06,0x81,0x38,0x2C,0x08,0x8D, + 0xF4,0xCA,0x11,0x88,0x25,0x3F,0xFB,0x05, + 0x62,0xB9,0x6F,0x06,0x81,0x38,0xE0,0x1B, + 0x4C,0xE0,0xE4,0x61,0x25,0x70,0xF2,0x6E, + 0x10,0x88,0x23,0x83,0x50,0xA1,0x3A,0x40, + 0x58,0x4C,0x10,0x1A,0xCA,0x07,0x08,0x93, + 0xFE,0x48,0x10,0x20,0x31,0x02,0xC2,0xC2, + 0xBD,0xBF,0x04,0x62,0x69,0xEF,0x09,0x81, + 0x58,0x88,0x15,0x10,0x16,0x17,0x84,0x86, + 0xD3,0x02,0xC2,0x24,0x99,0x01,0x61,0x81, + 0x40,0xA8,0x7C,0x35,0x20,0x4C,0xA4,0x1B, + 0x40,0xBA,0x7A,0x81,0x38,0x88,0x1E,0x10, + 0x26,0xC3,0x0F,0x08,0x0B,0x0D,0x42,0xA3, + 0x3D,0x30,0x04,0x48,0x0C,0x81,0xB0,0xF8, + 0x8E,0x40,0x98,0xF8,0x57,0x91,0x40,0x9C, + 0xDF,0x12,0xC4,0x4D,0x69,0x88,0x35,0x01, + 0x31,0x0D,0x9E,0x80,0x98,0x22,0x10,0x01, + 0x39,0xF6,0xD3,0x43,0x40,0xD6,0x60,0x0A, + 0x88,0x45,0x07,0x11,0x90,0x85,0xA8,0x02, + 0x62,0x79,0x5D,0x01,0xB1,0xF0,0x20,0x02, + 0x72,0xE6,0x97,0x9F,0x80,0xAC,0xE0,0xA5, + 0xF3,0x10,0xC0,0xDE,0x10,0x81,0x48,0x72, + 0x10,0x01,0x39,0xB0,0x2F,0x20,0x16,0x1F, + 0x44,0x40,0xCE,0xFA,0x28,0x14,0x90,0x83, + 0x83,0x68,0x10,0xE4,0x6B,0x26,0x20,0xA7, + 0x07,0x11,0x10,0xF9,0x04,0x05,0x21,0x6A, + 0xBD,0x81,0x30,0x3D,0x8F,0x42,0x0D,0x85, + 0x80,0x50,0xE5,0xEA,0xCE,0x31,0x2C,0x07, + 0x08,0xCD,0x05,0x22,0x30,0xAB,0x70,0x07, + 0xC4,0x54,0x81,0x08,0xC8,0x09,0x80,0xC8, + 0xFF,0x9F,0x60,0x2A,0x10,0x9A,0x12,0x8C, + 0xEA,0x92,0x07,0xC4,0x12,0x80,0xD0,0x54, + 0x20,0x34,0x25,0x88,0x00,0xAD,0xCA,0x1E, + 0x10,0x53,0x0A,0x42,0x95,0x83,0xD0,0x74, + 0x20,0x54,0xB6,0xBE,0xC3,0x02,0x05,0x11, + 0x90,0xA3,0x83,0x50,0xE1,0xFE,0x40,0x98, + 0xDE,0x97,0x86,0x00,0x9D,0x0E,0x44,0x40, + 0x4E,0x0C,0x42,0x15,0x7C,0x32,0x82,0x10, + 0xB1,0x20,0x54,0xC1,0x27,0x23,0x28,0xD1, + 0xF2,0xB2,0x13,0x90,0xF5,0x81,0x50,0xBD, + 0x20,0x02,0x73,0x36,0x20,0x9A,0x17,0x84, + 0xE6,0x07,0xA3,0x5A,0x8D,0x02,0x31,0xFD, + 0x20,0x34,0x0F,0x88,0xC0,0xAC,0xE0,0xF9, + 0x71,0xC0,0x0C,0x84,0xAA,0x04,0x11,0x98, + 0x73,0x01,0xD1,0xAC,0x20,0x34,0x3B,0x18, + 0xD5,0xFE,0x0F,0xD1,0x00,0x08,0x08,0xCD, + 0x07,0xA2,0xC3,0x00,0x79,0x96,0x09,0xC8, + 0x1A,0x41,0xA8,0x66,0x10,0x81,0x39,0x27, + 0x10,0xCD,0x0E,0x42,0x95,0xFD,0x4D,0x82, + 0x91,0x8C,0x0F,0xD0,0x40,0x24,0x37,0x08, + 0xD5,0xF1,0x0C,0x0A,0x46,0x74,0x83,0x08, + 0xC8,0x59,0x40,0x68,0x36,0x30,0x9A,0x4C, + 0xED,0x91,0x80,0xBA,0x05,0x61,0xE9,0x41, + 0x68,0x3A,0xBB,0x83,0xA7,0x20,0x54,0x81, + 0x5E,0x30,0xA6,0x19,0x44,0x87,0x05,0x02, + 0x42,0x73,0x81,0x51,0x1D,0xAF,0x96,0x40, + 0x44,0x1B,0x08,0xD5,0x0A,0xA2,0x81,0x93, + 0x1F,0x53,0x10,0x92,0x14,0x84,0xFC,0xFF, + 0x07,0xAA,0xC7,0x9C,0x40,0xAC,0xFA,0x5B, + 0x25,0x50,0x27,0x01,0xA1,0xC9,0x40,0x74, + 0x7C,0x20,0x0F,0xB8,0x83,0x64,0x20,0x54, + 0x29,0x88,0xC0,0xAC,0xF4,0x63,0xA4,0x23, + 0x05,0x51,0x7D,0xBC,0xA0,0x20,0x34,0xD1, + 0x3B,0x2C,0x08,0x7B,0xB8,0x69,0xA8,0xE4, + 0x59,0xA5,0xA1,0x12,0x10,0x9A,0x0D,0x44, + 0xC7,0x04,0xF2,0xAA,0x79,0x4C,0x60,0x20, + 0x54,0x2F,0x08,0xCD,0x01,0x42,0x13,0x83, + 0x08,0xD4,0xA9,0xBF,0x37,0x1A,0x2A,0xF9, + 0x5B,0x09,0xC4,0xCA,0x5E,0x69,0x02,0xB1, + 0xDE,0xA7,0x4E,0x20,0xE6,0x1D,0x98,0xA9, + 0x05,0xA1,0xEA,0x41,0x04,0xE6,0xB4,0x40, + 0x54,0x81,0x78,0x10,0xA6,0x08,0x44,0x60, + 0x4E,0x02,0x44,0xD3,0x81,0xD0,0xEC,0x60, + 0x54,0xE7,0xA3,0x4D,0x40,0xD6,0x0E,0x42, + 0xB3,0x80,0x08,0xCC,0x59,0x1E,0x69,0x02, + 0xB1,0x92,0x2F,0x9D,0x0E,0x24,0x04,0x84, + 0x26,0xD3,0x7F,0x68,0xA1,0x05,0x80,0x99, + 0x84,0x04,0x20,0x4C,0x16,0x88,0x0E,0x27, + 0xD6,0x08,0x22,0x40,0xC7,0x01,0xA3,0xD1, + 0x40,0x68,0x5C,0x40,0x9A,0x1D,0x90,0x2A, + 0x6D,0x00,0xC6,0x54,0x83,0xD0,0x24,0x20, + 0x02,0x74,0x2C,0x10,0x01,0x5A,0x74,0x04, + 0x30,0x16,0x01,0x84,0x46,0x05,0xA1,0xC9, + 0x2A,0x80,0xB2,0x9C,0x20,0x1A,0x20,0xC9, + 0x30,0x60,0x0A,0x42,0x33,0x81,0xD0,0x8C, + 0x20,0x54,0x7C,0x07,0x10,0x16,0x04,0x84, + 0x86,0x03,0xD1,0x00,0xFE,0xFF,0x8F,0x0C, + 0x02,0xD1,0x00,0x9C,0x23,0xC4,0x61,0x85, + 0x82,0xD0,0xF4,0x20,0x34,0x6C,0x09,0x50, + 0x16,0x1D,0x44,0xC7,0x23,0x92,0x02,0x8C, + 0x05,0x02,0xA1,0x31,0x41,0x68,0x6C,0x10, + 0x1A,0x29,0x06,0x28,0x13,0x54,0xE3,0x50, + 0x44,0x7B,0x80,0x31,0x99,0x20,0x54,0x36, + 0x88,0xC0,0x1C,0x14,0x88,0x86,0x07,0xA1, + 0x62,0x82,0x00,0x52,0x10,0x01,0x12,0x20, + 0x1A,0x1E,0x84,0x8A,0x29,0x32,0x74,0x0A, + 0x42,0x55,0x24,0x39,0x9A,0x50,0x10,0x1D, + 0x4D,0x08,0x08,0xCD,0x07,0x46,0x75,0x35, + 0x39,0x6E,0x50,0x10,0xAA,0x1D,0x84,0x06, + 0x05,0xA1,0x39,0xA2,0x80,0xB2,0xEC,0x20, + 0x02,0xB2,0x9E,0x2A,0x87,0x0A,0x0A,0x22, + 0x30,0xA7,0x02,0xA2,0x49,0x41,0xA8,0x8E, + 0x2C,0x47,0x0A,0x9A,0x06,0x84,0x25,0x06, + 0xA1,0xC9,0xDA,0x80,0xB0,0x0C,0x75,0x0E, + 0x24,0x14,0x84,0xE6,0x04,0xA1,0x4A,0xF2, + 0x0C,0x8F,0x82,0xE8,0x38,0x42,0x80,0x68, + 0x7A,0x10,0xAA,0xA6,0xCF,0x00,0x28,0x88, + 0x06,0x40,0x40,0x68,0x4E,0x30,0xAA,0xA8, + 0xD1,0xD1,0x84,0x82,0x50,0xDD,0x2F,0x4E, + 0x81,0xF8,0xFF,0x0F, + }) // END MBUF + +} //end DefinitionBlock + diff --git a/third_party/lib/acpica/tests/templates/Makefile b/third_party/lib/acpica/tests/templates/Makefile new file mode 100644 index 000000000..1880dcc04 --- /dev/null +++ b/third_party/lib/acpica/tests/templates/Makefile @@ -0,0 +1,9 @@ + +PROG= templates + +templates : + sh templates.sh + +clean : + rm -f *.asl *.aml *.dsl *.hex diff.log + diff --git a/third_party/lib/acpica/tests/templates/templates.sh b/third_party/lib/acpica/tests/templates/templates.sh new file mode 100755 index 000000000..06c08143d --- /dev/null +++ b/third_party/lib/acpica/tests/templates/templates.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +rm -f *.aml *.asl *.dsl *.log + +files=`ls` + +if [ "$1" == 1 ]; then + ASL_COMPILER="../../generate/unix/bin/iasl" +else + ASL_COMPILER="iasl" +fi + +echo "Using $ASL_COMPILER" + +# +# Create and compile the terse (normal) templates just +# to ensure that they will emit and compile +# +$ASL_COMPILER -T ALL > /dev/null 2>&1 +$ASL_COMPILER *.asl > /dev/null 2>&1 + +rm -f *.aml *.asl *.dsl *.log + +# Create the templates (use verbose mode) + +$ASL_COMPILER -vt -T ALL > /dev/null 2>&1 + +# Compile the templates + +$ASL_COMPILER *.asl > /dev/null 2>&1 + +# Disassemble the compiled templates + +$ASL_COMPILER -d *.aml > /dev/null 2>&1 + +> diff.log + +# +# Compare templates to compiled/disassembled templates +# +for f in $files ; do + if [ "$f" != "$0" ] && [ "$f" != "Makefile" ]; then + sig=`echo $f | awk -F. '{print $1}'` + + # Ignore differences in the comment/header field + + diff -pu -I" \*" $sig.asl $sig.dsl >> diff.log + fi +done + diff --git a/third_party/lib/cksum/BUILD.gn b/third_party/lib/cksum/BUILD.gn new file mode 100644 index 000000000..f708e7cf9 --- /dev/null +++ b/third_party/lib/cksum/BUILD.gn @@ -0,0 +1,22 @@ +import("//gnbuild/config.gni") + +config("_cksum_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] + defines = [ "WITH_LIB_CKSUM=1" ] +} + +module("cksum") { + public_configs = [ ":_cksum_config" ] + configs -= [ "//gnbuild:strict_compiler_flags" ] + sources = [ + "adler32.c", + "crc16.c", + "crc32.c", + "debug.c", + ] + deps = [ + "//kernel/lib/console", + "//kernel/lib/libc", + ] +} diff --git a/third_party/lib/cksum/LICENSE b/third_party/lib/cksum/LICENSE new file mode 100644 index 000000000..0ffadc9e5 --- /dev/null +++ b/third_party/lib/cksum/LICENSE @@ -0,0 +1,23 @@ +(from zlib.h and README) + +Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + diff --git a/third_party/lib/cksum/adler32.c b/third_party/lib/cksum/adler32.c new file mode 100644 index 000000000..614478211 --- /dev/null +++ b/third_party/lib/cksum/adler32.c @@ -0,0 +1,177 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521 /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/third_party/lib/cksum/crc16.c b/third_party/lib/cksum/crc16.c new file mode 100644 index 000000000..cbc649662 --- /dev/null +++ b/third_party/lib/cksum/crc16.c @@ -0,0 +1,38 @@ +/* + * Computes the CRC for transmitted and received data using + * the CCITT 16bit algorithm (X^16 + X^12 + X^5 + 1) with + * a 0xFFFF initialization vector. + */ + +#define CRC16_INIT_VALUE 0xFFFF + + /* + * Computes an updated version of the CRC from existing CRC. + * crc: the previous values of the CRC + * buf: the data on which to apply the checksum + * length: the number of bytes of data in 'buf' to be calculated. + */ +unsigned short update_crc16(unsigned short crc, const unsigned char *buf, + unsigned int length) +{ + unsigned int i; + for (i = 0; i < length; i++) { + crc = (unsigned char) (crc >> 8) | (crc << 8); + crc ^= buf[i]; + crc ^= (unsigned char) (crc & 0xff) >> 4; + crc ^= (crc << 8) << 4; + crc ^= ((crc & 0xff) << 4) << 1; + } + return crc; +} + + /* + * Computes a CRC, starting with an initialization value. + * buf: the data on which to apply the checksum + * length: the number of bytes of data in 'buf' to be calculated. + */ +unsigned short crc16(const unsigned char *buf, unsigned int length) +{ + unsigned short crc = CRC16_INIT_VALUE; + return update_crc16(crc, buf, length); +} diff --git a/third_party/lib/cksum/crc32.c b/third_party/lib/cksum/crc32.c new file mode 100644 index 000000000..edf70008f --- /dev/null +++ b/third_party/lib/cksum/crc32.c @@ -0,0 +1,426 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +#error +# define BYFOUR +#endif +#ifdef BYFOUR + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local z_crc_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + z_crc_t c; + int n, k; + z_crc_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (z_crc_t)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = ZSWAP32(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = ZSWAP32(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const z_crc_t FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const z_crc_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + z_crc_t endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = (z_crc_t)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = ZSWAP32((z_crc_t)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(ZSWAP32(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/third_party/lib/cksum/crc32.h b/third_party/lib/cksum/crc32.h new file mode 100644 index 000000000..9e0c77810 --- /dev/null +++ b/third_party/lib/cksum/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/third_party/lib/cksum/debug.c b/third_party/lib/cksum/debug.c new file mode 100644 index 000000000..aec432955 --- /dev/null +++ b/third_party/lib/cksum/debug.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2012 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#if WITH_LIB_CONSOLE + +#include +#include +#include +#include +#include +#include +#include + +#include + +static int cmd_crc16(int argc, const cmd_args *argv); +static int cmd_crc32(int argc, const cmd_args *argv); +static int cmd_adler32(int argc, const cmd_args *argv); +static int cmd_cksum_bench(int argc, const cmd_args *argv); + +STATIC_COMMAND_START +#if LK_DEBUGLEVEL > 0 +STATIC_COMMAND("crc16", "crc16", &cmd_crc16) +STATIC_COMMAND("crc32", "crc32", &cmd_crc32) +STATIC_COMMAND("adler32", "adler32", &cmd_adler32) +#endif +#if LK_DEBUGLEVEL > 1 +STATIC_COMMAND("bench_cksum", "benchmark the checksum routines", &cmd_cksum_bench) +#endif +STATIC_COMMAND_END(crc); + +static int cmd_crc16(int argc, const cmd_args *argv) +{ + if (argc < 3) { + printf("not enough arguments\n"); + printf("usage: %s
\n", argv[0].str); + return -1; + } + + uint16_t crc = crc16(argv[1].p, argv[2].u); + + printf("0x%hx\n", crc); + + return 0; +} + +static int cmd_crc32(int argc, const cmd_args *argv) +{ + if (argc < 3) { + printf("not enough arguments\n"); + printf("usage: %s
\n", argv[0].str); + return -1; + } + + uint32_t crc = crc32(0, argv[1].p, argv[2].u); + + printf("0x%x\n", crc); + + return 0; +} + +static int cmd_adler32(int argc, const cmd_args *argv) +{ + if (argc < 3) { + printf("not enough arguments\n"); + printf("usage: %s
\n", argv[0].str); + return -1; + } + + uint32_t crc = adler32(0, argv[1].p, argv[2].u); + + printf("0x%x\n", crc); + + return 0; +} + +static int cmd_cksum_bench(int argc, const cmd_args *argv) +{ +#define BUFSIZE 0x1000 +#define ITER 16384 + void *buf; + bool freebuf; + + if (argc > 1) { + buf = argv[1].p; + freebuf = false; + } else { + buf = malloc(BUFSIZE); + freebuf = true; + } + + if (!buf) + return -1; + + lk_bigtime_t t; + uint32_t crc; + + printf("buffer at %p, size %u\n", buf, BUFSIZE); + + t = current_time_hires(); + crc = 0; + for (int i = 0; i < ITER; i++) { + crc = crc32(crc, buf, BUFSIZE); + } + t = current_time_hires() - t; + + printf("took %llu usecs to crc32 %d bytes (%lld bytes/sec)\n", t, BUFSIZE * ITER, (BUFSIZE * ITER) * 1000000ULL / t); + thread_sleep(500); + + t = current_time_hires(); + crc = 0; + for (int i = 0; i < ITER; i++) { + crc = adler32(crc, buf, BUFSIZE); + } + t = current_time_hires() - t; + + printf("took %llu usecs to adler32 %d bytes (%lld bytes/sec)\n", t, BUFSIZE * ITER, (BUFSIZE * ITER) * 1000000ULL / t); + + if (freebuf) + free(buf); + return 0; +} + +#endif // WITH_LIB_CONSOLE diff --git a/third_party/lib/cksum/include/lib/cksum.h b/third_party/lib/cksum/include/lib/cksum.h new file mode 100644 index 000000000..67d43455a --- /dev/null +++ b/third_party/lib/cksum/include/lib/cksum.h @@ -0,0 +1,30 @@ +#ifndef __CKSUM_H +#define __CKSUM_H + +#include + +__BEGIN_CDECLS + +/* + * Computes the CRC-CCITT, starting with an initialization value. + * buf: the data on which to apply the checksum + * length: the number of bytes of data in 'buf' to be calculated. + */ +unsigned short crc16(const unsigned char *buf, unsigned int length); + +/* + * Computes an updated version of the CRC-CCITT from existing CRC. + * crc: the previous values of the CRC + * buf: the data on which to apply the checksum + * length: the number of bytes of data in 'buf' to be calculated. + */ +unsigned short update_crc16(unsigned short crc, const unsigned char *buf, unsigned int len); + +unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len); + +unsigned long adler32(unsigned long adler, const unsigned char *buf, unsigned int len); + +__END_CDECLS + +#endif + diff --git a/third_party/lib/cksum/rules.mk b/third_party/lib/cksum/rules.mk new file mode 100644 index 000000000..7d2aabe53 --- /dev/null +++ b/third_party/lib/cksum/rules.mk @@ -0,0 +1,13 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/adler32.c \ + $(LOCAL_DIR)/crc16.c \ + $(LOCAL_DIR)/crc32.c \ + $(LOCAL_DIR)/debug.c + +MODULE_CFLAGS += -Wno-strict-prototypes + +include make/module.mk diff --git a/third_party/lib/cksum/zutil.h b/third_party/lib/cksum/zutil.h new file mode 100644 index 000000000..8fe715b38 --- /dev/null +++ b/third_party/lib/cksum/zutil.h @@ -0,0 +1,26 @@ +#ifndef __ZUTIL_H +#define __ZUTIL_H + +/* necessary stuff to transplant crc32 and adler32 from zlib */ +#include +#include + +typedef ulong uLong; +typedef uint uInt; +typedef uint8_t Byte; +typedef Byte Bytef; +typedef off_t z_off_t; +typedef int64_t z_off64_t; +typedef unsigned long z_crc_t; + +//#define Z_U4 uint32_t + + +#define Z_NULL NULL +#define OF(args) args +#define local static +#define ZEXPORT +#define FAR + +#endif + diff --git a/third_party/lib/cryptolib/BUILD.gn b/third_party/lib/cryptolib/BUILD.gn new file mode 100644 index 000000000..1f8b3bb10 --- /dev/null +++ b/third_party/lib/cryptolib/BUILD.gn @@ -0,0 +1,14 @@ +config("_cryptolib_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("cryptolib") { + public_configs = [ ":_cryptolib_config" ] + sources = [ + "cryptolib.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/third_party/lib/cryptolib/README.fuchsia b/third_party/lib/cryptolib/README.fuchsia new file mode 100644 index 000000000..f06a0d03f --- /dev/null +++ b/third_party/lib/cryptolib/README.fuchsia @@ -0,0 +1,7 @@ +Source: https://github.com/jlnt/greygoo/tree/master/ucryptolib +Git Commit: b74ba4db80c6de95892b3a3429529eed89b8773a +License: Apache License version 2.0 + +Modifications: + - Changed header guard to "#pragma once" + - Added __BEGIN_CDECLS / __END_CDECLS diff --git a/third_party/lib/cryptolib/cryptolib.c b/third_party/lib/cryptolib/cryptolib.c new file mode 100644 index 000000000..ccd0d94ee --- /dev/null +++ b/third_party/lib/cryptolib/cryptolib.c @@ -0,0 +1,601 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Marius Schilder + +#include + +#include + +// Generic HASH code section =========================================== + +static void _HASH_update(clHASH_CTX* ctx, const void* data, int len) { + int i = (int) (ctx->count & 63); + const uint8_t* p = (const uint8_t*)data; + + ctx->count += len; + + while (len--) { + ctx->buf[i++] = *p++; + if (i == 64) { + ctx->f->_transform(ctx); + i = 0; + } + } +} + +static const uint8_t* _HASH_final(clHASH_CTX* ctx) { + uint8_t *p = ctx->buf; + uint64_t cnt = ctx->count * 8; + int i; + + clHASH_update(ctx, (const uint8_t*)"\x80", 1); + while ((ctx->count & 63) != 56) { + clHASH_update(ctx, (const uint8_t*)"\0", 1); + } + for (i = 0; i < 8; ++i) { + uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); + clHASH_update(ctx, &tmp, 1); + } + + for (i = 0; i < clHASH_size(ctx) / 4; i++) { + uint32_t tmp = ctx->state[i]; + *p++ = tmp >> 24; + *p++ = tmp >> 16; + *p++ = tmp >> 8; + *p++ = tmp >> 0; + } + + return ctx->buf; +} + +// Generic HMAC code section =========================================== + +static void _HMAC_init(clHMAC_CTX* ctx, const void* key, int len) { + unsigned int i; + memset(&ctx->opad[0], 0, sizeof(ctx->opad)); + + if ((unsigned int) len > sizeof(ctx->opad)) { + clHASH_init(&ctx->hash); + clHASH_update(&ctx->hash, key, len); + memcpy(&ctx->opad[0], clHASH_final(&ctx->hash), clHASH_size(&ctx->hash)); + } else { + memcpy(&ctx->opad[0], key, len); + } + + for (i = 0; i < sizeof(ctx->opad); ++i) { + ctx->opad[i] ^= 0x36; + } + + clHASH_init(&ctx->hash); + clHASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad)); // hash ipad + + for (i = 0; i < sizeof(ctx->opad); ++i) { + ctx->opad[i] ^= (0x36 ^ 0x5c); + } +} + +const uint8_t* clHMAC_final(clHMAC_CTX* ctx) { + uint8_t digest[clHASH_size(&ctx->hash)]; + memcpy(digest, clHASH_final(&ctx->hash), sizeof(digest)); + clHASH_init(&ctx->hash); + clHASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad)); + clHASH_update(&ctx->hash, digest, sizeof(digest)); + memset(&ctx->opad[0], 0, sizeof(ctx->opad)); // wipe key + return clHASH_final(&ctx->hash); +} + +// Fixed timing comparision function ==================================== + +int clEqual(const uint8_t* a, int a_len, const uint8_t* b, int b_len) { + int i, c = a_len - b_len; + for (i = 0; i < a_len && i < b_len; ++i) { + c |= a[i] - b[i]; + } + return c; +} + +// SHA256 code section ================================================== + +static void _SHA256_transform(clHASH_CTX* ctx) { + static const uint32_t _SHA256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; + +#define _ROR(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits)))) +#define _SHR(value, bits) ((value) >> (bits)) + + uint32_t W[64]; + uint32_t A, B, C, D, E, F, G, H; + const uint8_t* p = ctx->buf; + int t; + + for(t = 0; t < 16; ++t) { + uint32_t tmp = *p++ << 24; + tmp |= *p++ << 16; + tmp |= *p++ << 8; + tmp |= *p++; + W[t] = tmp; + } + + for(; t < 64; t++) { + uint32_t s0 = _ROR(W[t-15], 7) ^ _ROR(W[t-15], 18) ^ _SHR(W[t-15], 3); + uint32_t s1 = _ROR(W[t-2], 17) ^ _ROR(W[t-2], 19) ^ _SHR(W[t-2], 10); + W[t] = W[t-16] + s0 + W[t-7] + s1; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + for(t = 0; t < 64; t++) { + uint32_t s0 = _ROR(A, 2) ^ _ROR(A, 13) ^ _ROR(A, 22); + uint32_t maj = (A & B) ^ (A & C) ^ (B & C); + uint32_t t2 = s0 + maj; + uint32_t s1 = _ROR(E, 6) ^ _ROR(E, 11) ^ _ROR(E, 25); + uint32_t ch = (E & F) ^ ((~E) & G); + uint32_t t1 = H + s1 + ch + _SHA256_K[t] + W[t]; + + H = G; + G = F; + F = E; + E = D + t1; + D = C; + C = B; + B = A; + A = t1 + t2; + } + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; + +#undef _SHR +#undef _ROR +} + +const uint8_t* clSHA256(const void* data, int len, uint8_t* digest) { + clSHA256_CTX ctx; + clSHA256_init(&ctx); + clHASH_update(&ctx, data, len); + memcpy(digest, clHASH_final(&ctx), clSHA256_DIGEST_SIZE); + return digest; +} + +// SHA256 of PKCS1.5 signature padding for 2048 bit RSA, +// as per openssl, RSA_PKCS1_PADDING, EVP_sha256() hash. +// At the location of the bytes of the hash all 00 are hashed. +static const uint8_t kExpectedPadRsa2kSha256[clSHA256_DIGEST_SIZE] = { + 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92, + 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e, + 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd, + 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59 +}; + +static const clHASH_vtab _SHA256_vtab = { + clSHA256_init, + _HASH_update, + _HASH_final, + _SHA256_transform, + clSHA256_DIGEST_SIZE, + kExpectedPadRsa2kSha256 +}; + +void clSHA256_init(clSHA256_CTX* ctx) { + ctx->f = &_SHA256_vtab; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; + ctx->count = 0; +} + +void clHMAC_SHA256_init(clHMAC_CTX* ctx, const void* key, int len) { + clSHA256_init(&ctx->hash); + _HMAC_init(ctx, key, len); +} + +// SHA1 code section ===================================================== + +static void _SHA1_transform(clHASH_CTX* ctx) { +#define _ROL(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + uint32_t W[80]; + uint32_t A, B, C, D, E; + const uint8_t* p = ctx->buf; + int t; + + for(t = 0; t < 16; ++t) { + uint32_t tmp = *p++ << 24; + tmp |= *p++ << 16; + tmp |= *p++ << 8; + tmp |= *p++; + W[t] = tmp; + } + + for(; t < 80; t++) { + W[t] = _ROL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16],1); + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + + for(t = 0; t < 80; t++) { + uint32_t tmp = _ROL(A,5) + E + W[t]; + + if (t < 20) + tmp += (D^(B&(C^D))) + 0x5A827999; + else if ( t < 40) + tmp += (B^C^D) + 0x6ED9EBA1; + else if ( t < 60) + tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC; + else + tmp += (B^C^D) + 0xCA62C1D6; + + E = D; + D = C; + C = _ROL(B,30); + B = A; + A = tmp; + } + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +#undef _ROL +} + +// SHA1 of PKCS1.5 signature padding for 2048 bit RSA, +// as per openssl, RSA_PKCS1_PADDING, EVP_sha1() hash. +// At the location of the bytes of the hash all 00 are hashed. +static const uint8_t kExpectedPadRsa2kSha1[clSHA1_DIGEST_SIZE] = { + 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, 0x6e, 0xfc, + 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, 0x7c, 0xfb, 0xf1, 0x67 +}; + +static const clHASH_vtab _SHA1_vtab = { + clSHA1_init, + _HASH_update, + _HASH_final, + _SHA1_transform, + clSHA1_DIGEST_SIZE, + kExpectedPadRsa2kSha1 +}; + +void clSHA1_init(clSHA1_CTX* ctx) { + ctx->f = &_SHA1_vtab; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->count = 0; +} + +void clHMAC_SHA1_init(clHMAC_CTX* ctx, const void* key, int len) { + clSHA1_init(&ctx->hash); + _HMAC_init(ctx, key, len); +} + +const uint8_t* clSHA1(const void* data, int len, uint8_t* digest) { + clSHA1_CTX ctx; + clSHA1_init(&ctx); + clHASH_update(&ctx, data, len); + memcpy(digest, clHASH_final(&ctx), clSHA1_DIGEST_SIZE); + return digest; +} + +// Bignum code section ==================================================== + +// c[] = a[] - mod, fixed timing +// mask either 0 or 1. +// Returns unmodified input a[] if borrow, modified output c[] if no borrow. +static const uint32_t* subM(const clBignumModulus * mod, + uint32_t* c, + const uint32_t* a, + uint32_t mask) { + int64_t A = 0; + int64_t offset = a - c; + int i; + for (i = 0; i < mod->nwords; ++i) { + A += (uint64_t)a[i] - (mod->n[i] * mask); + c[i] = (uint32_t)A; + A >>= 32; + } + return c + (offset & A); +} + +// montgomery c[] += a * b[] / R % mod, fixed timing. +static void montMulAdd(const clBignumModulus * mod, + uint32_t* c, + const uint32_t a, + const uint32_t* b) { + uint64_t A = (uint64_t)a * b[0] + c[0]; + uint32_t d0 = (uint32_t)A * mod->n0inv; + uint64_t B = (uint64_t)d0 * mod->n[0] + (uint32_t)A; + int i; + + for (i = 1; i < mod->nwords; ++i) { + A = (A >> 32) + (uint64_t)a * b[i] + c[i]; + B = (B >> 32) + (uint64_t)d0 * mod->n[i] + (uint32_t)A; + c[i - 1] = (uint32_t)B; + } + + A = (A >> 32) + (B >> 32); + + c[i - 1] = (uint32_t)A; + + subM(mod, c, c, (uint32_t)(A >> 32)); // A >> 32 either 0 or 1. +} + +// montgomery c[] = a[] * b[] / R % mod, fixed timing. +static void montMul(const clBignumModulus * mod, + uint32_t* c, + const uint32_t* a, + const uint32_t* b) { + int i; + memset(c, 0, mod->size); + for (i = 0; i < mod->nwords; ++i) { + montMulAdd(mod, c, a[i], b); + } +} + +// Convert from lsw first uint32_t to msb first uint8_t. +// len in words. +static void u32tou8(uint8_t* dst, const uint32_t* src, int len) { + int i; + dst += len * 4; + for (i = 0; i < len; ++i) { + *--dst = (src[i] & 0x000000ff) >> 0; + *--dst = (src[i] & 0x0000ff00) >> 8; + *--dst = (src[i] & 0x00ff0000) >> 16; + *--dst = (src[i] & 0xff000000) >> 24; + } +} + +// Convert from msb first uint8_t to lsw first uint32_t. +// src_len in bytes, multiple of 4. +static void u8tou32(uint32_t* dst, const uint8_t* src, int src_len) { + int i; + src += src_len; + for (i = 0; i < src_len; i += 4) { + *dst = (*--src & 0xff) << 0; + *dst |= (*--src & 0xff) << 8; + *dst |= (*--src & 0xff) << 16; + *dst |= (*--src & 0xff) << 24; + dst++; + } +} + +// In-place exponentiation to power 65537. +// Input and output big-endian byte array in inout. Fixed timing. +static void modpowF4(const clBignumModulus* key, uint8_t* inout) { + uint32_t a[clBIGNUMWORDS]; + uint32_t aR[clBIGNUMWORDS]; + uint32_t aaR[clBIGNUMWORDS]; + uint32_t* aaa = aaR; // Re-use location. + int i; + + u8tou32(a, inout, key->size); + + montMul(key, aR, a, key->rr); // aR = a * RR / R mod M + for (i = 0; i < 16; i += 2) { + montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M + montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M + } + montMul(key, aaa, aR, a); // aaa = aR * a / R mod M + + u32tou8(inout, subM(key, a, aaa, 1), key->nwords); +} + +// Verify a 2048 bit RSA PKCS1.5 signature against an expected hash. +// Returns 0 on failure, 1 on success. NOT-fixed timing! +int clRSA2K_verify(const clBignumModulus* key, + const uint8_t* signature, + const int len, + clHASH_CTX* hash) { + uint8_t buf[clBIGNUMBYTES]; + const uint8_t* digest = clHASH_final(hash); + int i; + + if (key->nwords != clBIGNUMWORDS) return 0; // Wrong key passed in. + if (len != sizeof(buf)) return 0; // Wrong input length. + + memcpy(buf, signature, sizeof buf); + + modpowF4(key, buf); // In-place exponentiation to power 65537. + + // Xor digest location, so all bytes becomes 0 if equal. + for (i = len - clHASH_size(hash); i < len; ++i) { + buf[i] ^= *digest++; + } + + // Hash resulting buffer. + clHASH_init(hash); + clHASH_update(hash, buf, len); + digest = clHASH_final(hash); + + // This should equal hash of pkcs15 padding. + return clEqual(digest, clHASH_size(hash), + hash->f->_2Kpkcs15hashpad, clHASH_size(hash)) == 0; +} + +// DH code section ======================================== + +// c[] = a[] * 1 / R mod M, fixed timing. +static void montMul1(const clBignumModulus* M, + uint32_t* c, + const uint32_t* a) { + int i; + memset(c, 0, M->size); + montMulAdd(M, c, 1, a); + for (i = 1; i < M->nwords; ++i) + montMulAdd(M, c, 0, a); +} + +// c = a[] ** x mod M, fixed timing. +// c, x bigendian +static void modExp(const clBignumModulus* M, + uint8_t* c, + const uint32_t* a, + const uint8_t* x, const int size_x) { + uint32_t tmp[M->nwords]; + uint32_t base[M->nwords]; + uint32_t one[M->nwords]; // Could be const member of M to save stack. + uint32_t accu[M->nwords]; + int64_t offset = base - one; + int i, b; + + montMul1(M, one, M->rr); // 1 * RR / R mod M == R mod M aka '1' + montMul(M, base, a, M->rr); // base = a * R mod M + montMul1(M, accu, M->rr); // accu = 1 * RR / R = R mod M aka '1' + montMul1(M, tmp, M->rr); // tmp = 1 * RR / R = R mod M aka '1' + + for (i = 0; i < size_x; ++i) { + for (b = 7; b >= 0; --b) { + // Always multiply, either with base or one. + // This should keep timing reasonably constant at cost of efficiency. + // Does _not_ protect against L1 cache sharing timing channels. + int64_t mask = 0 - ((x[i] >> b) & 1); + montMul(M, tmp, accu, one + (offset & mask)); + montMul(M, accu, tmp, tmp); + } + } + + montMul1(M, accu, tmp); // accu = 1 * tmp * R / R mod M; undo last sqr. + u32tou8(c, subM(M, tmp, accu, 1), M->nwords); +} + +static const uint32_t dh_G[clBIGNUMWORDS] = { 2 }; // Hardcoded DH generator. + +// Returns a[] >= b[] +static int dhGE(const uint32_t* a, const uint32_t* b, int nwords) { + int64_t A = 0; + int i; + for (i = 0; i < nwords; ++i) { + A += (uint64_t)a[i] - b[i]; + A >>= 32; + } + return A == 0; // 0 == no borrow, hence >=. +} + +// Returns 2 <= n < M->n - 1 +static int dhCheck(const clBignumModulus* M, const uint32_t* n) { + uint32_t Mmin1[M->nwords]; + if (!dhGE(n, dh_G, M->nwords)) return 0; // n >= 2? + memcpy(Mmin1, M->n, sizeof Mmin1); + Mmin1[0] -= 1; // M->n odd, so just decrementing Mmin1[0] works. + return !dhGE(n, Mmin1, M->nwords); // n < n - 1? +} + +int clDHgenerate(const clBignumModulus* M, + const uint8_t* x, const int size_x, + uint8_t* out) { + uint32_t chk[M->nwords]; + modExp(M, out, dh_G, x, size_x); + // Make sure we didn't compute a value outside [2..M-1> + u8tou32(chk, out, M->size); + if (!dhCheck(M, chk)) return 0; + return 1; +} + +int clDHcompute(const clBignumModulus* M, + const uint8_t* gy, const int size_gy, + const uint8_t* x, const int size_x, + uint8_t* out) { + uint32_t base[M->nwords]; + if (size_gy != M->size) return 0; + u8tou32(base, gy, size_gy); + // Make sure the other party's value is inside [2..M-1> + if (!dhCheck(M, base)) return 0; + modExp(M, out, base, x, size_x); + return 1; +} + +// PRNG code section ================================================== + +void clPRNG_init(clPRNG_CTX* ctx, const void* data, int size) { + ctx->index = 0; + memset(ctx->v, 0, sizeof(ctx->v)); + clPRNG_entropy(ctx, data, size); +} + +void clPRNG_entropy(clPRNG_CTX* ctx, const void* data, int size) { + const uint8_t* p = (const uint8_t*)data; + while (size-- > 0) { + ctx->v[ctx->index++ % sizeof (ctx->v)] ^= *p++; + } +} + +void clPRNG_draw(clPRNG_CTX* ctx, void* out, int size) { + const uint8_t* digest; + uint8_t* output = (uint8_t*)out; + const uint8_t* rnd; + clHMAC_CTX hmac; + int i; + + while (size > 0) { + // compute output: out = hmac(v, v0); + clHMAC_SHA256_init(&hmac, ctx->v, sizeof(ctx->v)); + clHMAC_update(&hmac, ctx->v, clSHA256_DIGEST_SIZE); + rnd = clHMAC_final(&hmac); + + for (i = 0; (i < clSHA256_DIGEST_SIZE) && (size > 0); ++i) { + *output++ = *rnd++; + --size; + } + + // update state: v0, v1 = v0 ^ hmac(v, v1), v0 ^ v1 + clHMAC_SHA256_init(&hmac, ctx->v, sizeof(ctx->v)); + clHMAC_update(&hmac, &ctx->v[clSHA256_DIGEST_SIZE], + clSHA256_DIGEST_SIZE); + digest = clHMAC_final(&hmac); + for (i = 0; i < clSHA256_DIGEST_SIZE; ++i) { + ctx->v[clSHA256_DIGEST_SIZE + i] ^= ctx->v[i]; + ctx->v[i] ^= digest[i]; + } + } +} diff --git a/third_party/lib/cryptolib/include/lib/crypto/cryptolib.h b/third_party/lib/cryptolib/include/lib/crypto/cryptolib.h new file mode 100644 index 000000000..eb405ff61 --- /dev/null +++ b/third_party/lib/cryptolib/include/lib/crypto/cryptolib.h @@ -0,0 +1,145 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Author: Marius Schilder +// +// Lightweight C crypto library for sha256, hmac-sha256, DH, +// RSA2K-SHA256-PKCS15, PRNG, sha1, hmac-sha1, RSA2K-SHA1-PKCS15. +// +// Plain C, no system calls, no malloc. + +#pragma once + +#include +#include + +#define clBIGNUMBYTES 256 // 2048 bit key length max +#define clBIGNUMWORDS (clBIGNUMBYTES / sizeof(uint32_t)) + +__BEGIN_CDECLS + +struct clHASH_CTX; // forward decl. + +// RSA interface ---------------------------------------- + +typedef struct clBignumModulus { + int size; // Length of n[] in bytes; + int nwords; // Length of n[] in number of uint32_t + uint32_t n0inv; // -1 / n[0] mod 2^32 + uint32_t n[clBIGNUMWORDS]; // modulus as little endian array + uint32_t rr[clBIGNUMWORDS]; // 2^(2*32*nwords) mod n as little endian array +} clBignumModulus; + +// PKCS1.5 signature verify. +// signature_len must be key->size. +// Returns 1 if OK. Trashes hash. +int clRSA2K_verify(const clBignumModulus* key, + const uint8_t* signature, + const int signature_len, + struct clHASH_CTX* hash /* not const! */); + +// Generic hash interface ---------------------------------------- + +typedef struct clHASH_vtab { + void (* const init)(struct clHASH_CTX*); + void (* const update)(struct clHASH_CTX*, const void*, int); + const uint8_t* (* const final)(struct clHASH_CTX*); + void (* const _transform)(struct clHASH_CTX*); + const int size; + const uint8_t* _2Kpkcs15hashpad; // hash of 2K bit padding. +} clHASH_vtab; + +typedef struct clHASH_CTX { + const clHASH_vtab* f; + uint64_t count; + uint8_t buf[64]; + uint32_t state[8]; +} clHASH_CTX; + +#define clHASH_init(ctx) (ctx)->f->init(ctx) +#define clHASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len) +#define clHASH_final(ctx) (ctx)->f->final(ctx) +#define clHASH_size(ctx) (ctx)->f->size + +// Generic hmac interface ---------------------------------------- + +typedef struct clHMAC_CTX { + clHASH_CTX hash; + uint8_t opad[64]; +} clHMAC_CTX; + +#define clHMAC_update(ctx, data, len) clHASH_update(&(ctx)->hash, data, len) +#define clHMAC_size(ctx) clHASH_size(&(ctx)->hash) +const uint8_t* clHMAC_final(clHMAC_CTX* ctx); + +// SHA1 interface ---------------------------------------------- + +#define clSHA1_DIGEST_SIZE 20 +typedef clHASH_CTX clSHA1_CTX; + +void clSHA1_init(clSHA1_CTX* ctx); +void clHMAC_SHA1_init(clHMAC_CTX* ctx, const void* key, int len); +const uint8_t* clSHA1(const void* data, int len, uint8_t* digest); + +// SHA256 interface -------------------------------------------- + +#define clSHA256_DIGEST_SIZE 32 +typedef clHASH_CTX clSHA256_CTX; + +void clSHA256_init(clSHA256_CTX* ctx); +void clHMAC_SHA256_init(clHMAC_CTX* ctx, const void* key, int len); +const uint8_t* clSHA256(const void* data, int len, uint8_t* digest); + +// Safe compare interface -------------------------------- + +// Returns 0 if equal. +// Only fixed timing if arrays are of same length! +int clEqual(const uint8_t* a, int a_len, const uint8_t* b, int b_len); + +// DH interface -------------------------------------------- + +// Computes 2 ** x into out. x and out bigendian byte strings. +// out must be able to hold mod->size bytes. +// Return 0 on error. (invalid value for x). +int clDHgenerate(const clBignumModulus* mod, + const uint8_t* x, const int size_x, + uint8_t* out); + +// Computes gy ** x into out. gy, x, and out bigendian byte strings. +// size_gy must be mod->size. +// Returns 0 on error. (invalid size_gy, gy, x). +int clDHcompute(const clBignumModulus* mod, + const uint8_t* gy, const int size_gy, + const uint8_t* x, const int size_x, + uint8_t* out); + +// PRNG interface -------------------------------------------- + +typedef struct clPRNG_CTX { + uint8_t v[clSHA256_DIGEST_SIZE * 2]; + int index; +} clPRNG_CTX; + +// Initial seeding. +void clPRNG_init(clPRNG_CTX* ctx, const void* data, int size); + +// Add entropy to state. Non-destructive, additive. +// Best to call at least once before calling clPRNG_draw(). +void clPRNG_entropy(clPRNG_CTX* ctx, const void* data, int size); + +// Generate size bytes random and advance state. +// Beware: out value covers entire spectrum so all 0 is possible. +void clPRNG_draw(clPRNG_CTX* ctx, void* out, int size); + +__END_CDECLS diff --git a/third_party/lib/cryptolib/rules.mk b/third_party/lib/cryptolib/rules.mk new file mode 100644 index 000000000..f9be4c81d --- /dev/null +++ b/third_party/lib/cryptolib/rules.mk @@ -0,0 +1,8 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/cryptolib.c + +include make/module.mk diff --git a/third_party/lib/fdt/BUILD.gn b/third_party/lib/fdt/BUILD.gn new file mode 100644 index 000000000..17a9438d7 --- /dev/null +++ b/third_party/lib/fdt/BUILD.gn @@ -0,0 +1,26 @@ +config("_fdt_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("fdt") { + public_configs = [ ":_fdt_config" ] + public = [ + "include/fdt.h", + "include/fdt_env.h", + "include/libfdt.h", + ] + sources = [ + "fdt.c", + "fdt_addresses.c", + "fdt_empty_tree.c", + "fdt_ro.c", + "fdt_rw.c", + "fdt_strerror.c", + "fdt_sw.c", + "fdt_wip.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/third_party/lib/fdt/LICENSE b/third_party/lib/fdt/LICENSE new file mode 100644 index 000000000..498961c57 --- /dev/null +++ b/third_party/lib/fdt/LICENSE @@ -0,0 +1,50 @@ +Magenta chooses to use the BSD License (option b): + + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/lib/fdt/Makefile.libfdt b/third_party/lib/fdt/Makefile.libfdt new file mode 100644 index 000000000..09c322ed8 --- /dev/null +++ b/third_party/lib/fdt/Makefile.libfdt @@ -0,0 +1,11 @@ +# Makefile.libfdt +# +# This is not a complete Makefile of itself. Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ + fdt_addresses.c +LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/third_party/lib/fdt/TODO b/third_party/lib/fdt/TODO new file mode 100644 index 000000000..288437e39 --- /dev/null +++ b/third_party/lib/fdt/TODO @@ -0,0 +1,3 @@ +- Tree traversal functions +- Graft function +- Complete libfdt.h documenting comments diff --git a/third_party/lib/fdt/fdt.c b/third_party/lib/fdt/fdt.c new file mode 100644 index 000000000..2ce6a4417 --- /dev/null +++ b/third_party/lib/fdt/fdt.c @@ -0,0 +1,250 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_check_header(const void *fdt) +{ + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (fdt_size_dt_struct(fdt) == 0) + return -FDT_ERR_BADSTATE; + } else { + return -FDT_ERR_BADMAGIC; + } + + return 0; +} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) +{ + const char *p; + + if (fdt_version(fdt) >= 0x11) + if (((offset + len) < offset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; + + p = _fdt_offset_ptr(fdt, offset); + + if (p + len < p) + return NULL; + return p; +} + +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) +{ + const fdt32_t *tagp, *lenp; + uint32_t tag; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); + if (!tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu(*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) { + case FDT_BEGIN_NODE: + /* skip name */ + do { + p = fdt_offset_ptr(fdt, offset++, 1); + } while (p && (*p != '\0')); + if (!p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN(offset); + return tag; +} + +int _fdt_check_node_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int _fdt_check_prop_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) + return nextoffset; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; +} + +int fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +int fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) +{ + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp(p, s, len) == 0) + return p; + return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_totalsize(fdt) > bufsize) + return -FDT_ERR_NOSPACE; + + memmove(buf, fdt, fdt_totalsize(fdt)); + return 0; +} diff --git a/third_party/lib/fdt/fdt_addresses.c b/third_party/lib/fdt/fdt_addresses.c new file mode 100644 index 000000000..eff4dbcc7 --- /dev/null +++ b/third_party/lib/fdt/fdt_addresses.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2014 David Gibson + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_address_cells(const void *fdt, int nodeoffset) +{ + const fdt32_t *ac; + int val; + int len; + + ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); + if (!ac) + return 2; + + if (len != sizeof(*ac)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*ac); + if ((val <= 0) || (val > FDT_MAX_NCELLS)) + return -FDT_ERR_BADNCELLS; + + return val; +} + +int fdt_size_cells(const void *fdt, int nodeoffset) +{ + const fdt32_t *sc; + int val; + int len; + + sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); + if (!sc) + return 2; + + if (len != sizeof(*sc)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*sc); + if ((val < 0) || (val > FDT_MAX_NCELLS)) + return -FDT_ERR_BADNCELLS; + + return val; +} diff --git a/third_party/lib/fdt/fdt_empty_tree.c b/third_party/lib/fdt/fdt_empty_tree.c new file mode 100644 index 000000000..f72d13b1d --- /dev/null +++ b/third_party/lib/fdt/fdt_empty_tree.c @@ -0,0 +1,84 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} + diff --git a/third_party/lib/fdt/fdt_ro.c b/third_party/lib/fdt/fdt_ro.c new file mode 100644 index 000000000..a65e4b5b7 --- /dev/null +++ b/third_party/lib/fdt/fdt_ro.c @@ -0,0 +1,579 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int _fdt_nodename_eq(const void *fdt, int offset, + const char *s, int len) +{ + const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); + + if (! p) + /* short match */ + return 0; + + if (memcmp(p, s, len) != 0) + return 0; + + if (p[len] == '\0') + return 1; + else if (!memchr(s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; +} + +const char *fdt_string(const void *fdt, int stroffset) +{ + return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; +} + +static int _fdt_string_eq(const void *fdt, int stroffset, + const char *s, int len) +{ + const char *p = fdt_string(fdt, stroffset); + + return (strlen(p) == len) && (memcmp(p, s, len) == 0); +} + +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ + FDT_CHECK_HEADER(fdt); + *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); + *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); + return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ + int i = 0; + + while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) + i++; + return i; +} + +static int _nextprop(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset_namelen(const void *fdt, int offset, + const char *name, int namelen) +{ + int depth; + + FDT_CHECK_HEADER(fdt); + + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && _fdt_nodename_eq(fdt, offset, name, namelen)) + return offset; + + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, + const char *name) +{ + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) +{ + const char *end = path + namelen; + const char *p = path; + int offset = 0; + + FDT_CHECK_HEADER(fdt); + + /* see if we have an alias */ + if (*path != '/') { + const char *q = memchr(path, '/', end - p); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } + + while (p < end) { + const char *q; + + while (*p == '/') { + p++; + if (p == end) + return offset; + } + q = memchr(p, '/', end - p); + if (! q) + q = end; + + offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); + if (offset < 0) + return offset; + + p = q; + } + + return offset; +} + +int fdt_path_offset(const void *fdt, const char *path) +{ + return fdt_path_offset_namelen(fdt, path, strlen(path)); +} + +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ + const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); + int err; + + if (((err = fdt_check_header(fdt)) != 0) + || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) + goto fail; + + if (len) + *len = strlen(nh->name); + + return nh->name; + + fail: + if (len) + *len = err; + return NULL; +} + +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) +{ + int err; + const struct fdt_property *prop; + + if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } + + prop = _fdt_offset_ptr(fdt, offset); + + if (lenp) + *lenp = fdt32_to_cpu(prop->len); + + return prop; +} + +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + + if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { + offset = -FDT_ERR_INTERNAL; + break; + } + if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), + name, namelen)) + return prop; + } + + if (lenp) + *lenp = offset; + return NULL; +} + +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); + if (! prop) + return NULL; + + return prop->data; +} + +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ + const fdt32_t *php; + int len; + + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } + + return fdt32_to_cpu(*php); +} + +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) +{ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_CHECK_HEADER(fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth) +{ + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; + + FDT_CHECK_HEADER(fdt); + + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; + + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; + + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ + int nodedepth; + int err; + + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); + if (err) + return (err < 0) ? err : -FDT_ERR_INTERNAL; + return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ + int nodedepth = fdt_node_depth(fdt, nodeoffset); + + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset(fdt, nodeoffset, + nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen) +{ + int offset; + const void *val; + int len; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) +{ + int offset; + + if ((phandle == 0) || (phandle == -1)) + return -FDT_ERR_BADPHANDLE; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) +{ + int len = strlen(str); + const char *p; + + while (listlen >= len) { + if (memcmp(str, strlist, len+1) == 0) + return 1; + p = memchr(strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p-strlist) + 1; + strlist = p + 1; + } + return 0; +} + +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) +{ + const void *prop; + int len; + + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; + if (fdt_stringlist_contains(prop, len, compatible)) + return 0; + else + return 1; +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible) +{ + int offset, err; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} diff --git a/third_party/lib/fdt/fdt_rw.c b/third_party/lib/fdt/fdt_rw.c new file mode 100644 index 000000000..70adec6c3 --- /dev/null +++ b/third_party/lib/fdt/fdt_rw.c @@ -0,0 +1,492 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int _fdt_blocks_misordered(const void *fdt, + int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + +static int _fdt_rw_check_header(void *fdt) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; + if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (fdt_version(fdt) > 17) + fdt_set_version(fdt, 17); + + return 0; +} + +#define FDT_RW_CHECK_HEADER(fdt) \ + { \ + int __err; \ + if ((__err = _fdt_rw_check_header(fdt)) != 0) \ + return __err; \ + } + +static inline int _fdt_data_size(void *fdt) +{ + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) +{ + char *p = splicepoint; + char *end = (char *)fdt + _fdt_data_size(fdt); + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, end - p - oldlen); + return 0; +} + +static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof(*p); + int err; + err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_struct(void *fdt, void *p, + int oldlen, int newlen) +{ + int delta = newlen - oldlen; + int err; + + if ((err = _fdt_splice(fdt, p, oldlen, newlen))) + return err; + + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_string(void *fdt, int newlen) +{ + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; + + if ((err = _fdt_splice(fdt, p, 0, newlen))) + return err; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; + char *new; + int len = strlen(s) + 1; + int err; + + p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); + err = _fdt_splice_string(fdt, len); + if (err) + return err; + + memcpy(new, s, len); + return (new - strtab); +} + +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); + err = _fdt_splice_mem_rsv(fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ + struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); + int err; + + FDT_RW_CHECK_HEADER(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + + err = _fdt_splice_mem_rsv(fdt, re, 1, 0); + if (err) + return err; + return 0; +} + +static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int oldlen; + int err; + + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (! (*prop)) + return oldlen; + + if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) + return err; + + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int proplen; + int nextoffset; + int namestroff; + int err; + + if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = _fdt_find_add_string(fdt, name); + if (namestroff < 0) + return namestroff; + + *prop = _fdt_offset_ptr_w(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + + err = _fdt_splice_struct(fdt, *prop, 0, proplen); + if (err) + return err; + + (*prop)->tag = cpu_to_fdt32(FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32(namestroff); + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; + + memcpy(namep, name, newlen+1); + return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + + memcpy(prop->data, val, len); + return 0; +} + +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len, proplen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (! prop) + return len; + + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return _fdt_splice_struct(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen) +{ + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + fdt32_t *endtag; + + FDT_RW_CHECK_HEADER(fdt); + + offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = _fdt_offset_ptr_w(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + + err = _fdt_splice_struct(fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); + memcpy(nh->name, name, namelen); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32(FDT_END_NODE); + + return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ + return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ + int endoffset; + + FDT_RW_CHECK_HEADER(fdt); + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), + endoffset - nodeoffset, 0); +} + +static void _fdt_packblocks(const char *old, char *new, + int mem_rsv_size, int struct_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); + + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); + + memmove(new + strings_off, old + fdt_off_dt_strings(old), + fdt_size_dt_strings(old)); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) +{ + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; + + FDT_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + + if (fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } + + if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + + return 0; +} + +int fdt_pack(void *fdt) +{ + int mem_rsv_size; + + FDT_RW_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_set_totalsize(fdt, _fdt_data_size(fdt)); + + return 0; +} diff --git a/third_party/lib/fdt/fdt_strerror.c b/third_party/lib/fdt/fdt_strerror.c new file mode 100644 index 000000000..e6c3ceee8 --- /dev/null +++ b/third_party/lib/fdt/fdt_strerror.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +struct fdt_errtabent { + const char *str; +}; + +#define FDT_ERRTABENT(val) \ + [(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), +}; +#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +const char *fdt_strerror(int errval) +{ + if (errval > 0) + return ""; + else if (errval == 0) + return ""; + else if (errval > -FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return ""; +} diff --git a/third_party/lib/fdt/fdt_sw.c b/third_party/lib/fdt/fdt_sw.c new file mode 100644 index 000000000..6a804859f --- /dev/null +++ b/third_party/lib/fdt/fdt_sw.c @@ -0,0 +1,288 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int _fdt_sw_check_header(void *fdt) +{ + if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + /* FIXME: should check more details about the header state */ + return 0; +} + +#define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_sw_check_header(fdt)) != 0) \ + return err; \ + } + +static void *_fdt_grab_space(void *fdt, size_t len) +{ + int offset = fdt_size_dt_struct(fdt); + int spaceleft; + + spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) + - fdt_size_dt_strings(fdt); + + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; + + fdt_set_size_dt_struct(fdt, offset + len); + return _fdt_offset_ptr_w(fdt, offset); +} + +int fdt_create(void *buf, int bufsize) +{ + void *fdt = buf; + + if (bufsize < sizeof(struct fdt_header)) + return -FDT_ERR_NOSPACE; + + memset(buf, 0, bufsize); + + fdt_set_magic(fdt, FDT_SW_MAGIC); + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_totalsize(fdt, bufsize); + + fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry))); + fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); + fdt_set_off_dt_strings(fdt, bufsize); + + return 0; +} + +int fdt_resize(void *fdt, void *buf, int bufsize) +{ + size_t headsize, tailsize; + char *oldtail, *newtail; + + FDT_SW_CHECK_HEADER(fdt); + + headsize = fdt_off_dt_struct(fdt); + tailsize = fdt_size_dt_strings(fdt); + + if ((headsize + tailsize) > bufsize) + return -FDT_ERR_NOSPACE; + + oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; + newtail = (char *)buf + bufsize - tailsize; + + /* Two cases to avoid clobbering data if the old and new + * buffers partially overlap */ + if (buf <= fdt) { + memmove(buf, fdt, headsize); + memmove(newtail, oldtail, tailsize); + } else { + memmove(newtail, oldtail, tailsize); + memmove(buf, fdt, headsize); + } + + fdt_set_off_dt_strings(buf, bufsize); + fdt_set_totalsize(buf, bufsize); + + return 0; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int offset; + + FDT_SW_CHECK_HEADER(fdt); + + if (fdt_size_dt_struct(fdt)) + return -FDT_ERR_BADSTATE; + + offset = fdt_off_dt_struct(fdt); + if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + + re = (struct fdt_reserve_entry *)((char *)fdt + offset); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); + + fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + + return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ + return fdt_add_reservemap_entry(fdt, 0, 0); +} + +int fdt_begin_node(void *fdt, const char *name) +{ + struct fdt_node_header *nh; + int namelen = strlen(name) + 1; + + FDT_SW_CHECK_HEADER(fdt); + + nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memcpy(nh->name, name, namelen); + return 0; +} + +int fdt_end_node(void *fdt) +{ + fdt32_t *en; + + FDT_SW_CHECK_HEADER(fdt); + + en = _fdt_grab_space(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; + + *en = cpu_to_fdt32(FDT_END_NODE); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_totalsize(fdt); + const char *p; + int strtabsize = fdt_size_dt_strings(fdt); + int len = strlen(s) + 1; + int struct_top, offset; + + p = _fdt_find_string(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + + /* Add it */ + offset = -strtabsize - len; + struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + if (fdt_totalsize(fdt) + offset < struct_top) + return 0; /* no more room :( */ + + memcpy(strtab + offset, s, len); + fdt_set_size_dt_strings(fdt, strtabsize + len); + return offset; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ + struct fdt_property *prop; + int nameoff; + + FDT_SW_CHECK_HEADER(fdt); + + nameoff = _fdt_find_add_string(fdt, name); + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) + return -FDT_ERR_NOSPACE; + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); + memcpy(prop->data, val, len); + return 0; +} + +int fdt_finish(void *fdt) +{ + char *p = (char *)fdt; + fdt32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_CHECK_HEADER(fdt); + + /* Add terminator */ + end = _fdt_grab_space(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); + newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = + _fdt_offset_ptr_w(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); + nameoff += fdt_size_dt_strings(fdt); + prop->nameoff = cpu_to_fdt32(nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); + fdt_set_magic(fdt, FDT_MAGIC); + return 0; +} diff --git a/third_party/lib/fdt/fdt_wip.c b/third_party/lib/fdt/fdt_wip.c new file mode 100644 index 000000000..c5bbb68d3 --- /dev/null +++ b/third_party/lib/fdt/fdt_wip.c @@ -0,0 +1,118 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + if (! propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + + memcpy(propval, val, len); + return 0; +} + +static void _fdt_nop_region(void *start, int len) +{ + fdt32_t *p; + + for (p = start; (char *)p < ((char *)start + len); p++) + *p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len; + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (! prop) + return len; + + _fdt_nop_region(prop, len + sizeof(*prop)); + + return 0; +} + +int _fdt_node_end_offset(void *fdt, int offset) +{ + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ + int endoffset; + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; +} diff --git a/third_party/lib/fdt/include/fdt.h b/third_party/lib/fdt/include/fdt.h new file mode 100644 index 000000000..526aedb51 --- /dev/null +++ b/third_party/lib/fdt/include/fdt.h @@ -0,0 +1,111 @@ +#ifndef _FDT_H +#define _FDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ASSEMBLY__ + +struct fdt_header { + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + fdt32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + fdt32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry { + fdt64_t address; + fdt64_t size; +}; + +struct fdt_node_header { + fdt32_t tag; + char name[0]; +}; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(fdt32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) + +#endif /* _FDT_H */ diff --git a/third_party/lib/fdt/include/libfdt.h b/third_party/lib/fdt/include/libfdt.h new file mode 100644 index 000000000..1bd024218 --- /dev/null +++ b/third_party/lib/fdt/include/libfdt.h @@ -0,0 +1,1586 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#define FDT_FIRST_SUPPORTED_VERSION 0x10 +#define FDT_LAST_SUPPORTED_VERSION 0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS 2 + /* FDT_ERR_EXISTS: Attemped to create a node or property which + * already exists */ +#define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device + * tree, but its buffer did not have sufficient space to + * contain the expanded tree. Use fdt_open_into() to move the + * device tree to a buffer with more space. */ + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET 4 + /* FDT_ERR_BADOFFSET: Function was passed a structure block + * offset which is out-of-bounds, or which points to an + * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH 5 + /* FDT_ERR_BADPATH: Function was passed a badly formatted path + * (e.g. missing a leading / for a function which requires an + * absolute path) */ +#define FDT_ERR_BADPHANDLE 6 + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle + * value. phandle values of 0 and -1 are not permitted. */ +#define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is + * not sufficiently complete for the requested operation. */ + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED 8 + /* FDT_ERR_TRUNCATED: Structure block of the given device tree + * ends without an FDT_END tag. */ +#define FDT_ERR_BADMAGIC 9 + /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a + * device tree at all - it is missing the flattened device + * tree magic number. */ +#define FDT_ERR_BADVERSION 10 + /* FDT_ERR_BADVERSION: Given device tree has a version which + * can't be handled by the requested operation. For + * read-write functions, this may mean that fdt_open_into() is + * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE 11 + /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt + * structure block or other serious error (e.g. misnested + * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT 12 + /* FDT_ERR_BADLAYOUT: For read-write functions, the given + * device tree has it's sub-blocks in an order that the + * function can't handle (memory reserve map, then structure, + * then strings). Use fdt_open_into() to reorganize the tree + * into a form suitable for the read-write operations. */ + +/* "Can't happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL 13 + /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. + * Should never be returned, if it is, it indicates a bug in + * libfdt itself. */ + +/* Errors in device tree content */ +#define FDT_ERR_BADNCELLS 14 + /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells + * or similar property with a bad format or value */ + +#define FDT_ERR_MAX 14 + +/**********************************************************************/ +/* Low-level functions (you probably don't need these) */ +/**********************************************************************/ + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); +static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) +{ + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); + +/**********************************************************************/ +/* Traversal functions */ +/**********************************************************************/ + +int fdt_next_node(const void *fdt, int offset, int *depth); + +/** + * fdt_first_subnode() - get offset of first direct subnode + * + * @fdt: FDT blob + * @offset: Offset of node to check + * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + */ +int fdt_first_subnode(const void *fdt, int offset); + +/** + * fdt_next_subnode() - get offset of next direct subnode + * + * After first calling fdt_first_subnode(), call this function repeatedly to + * get direct subnodes of a parent node. + * + * @fdt: FDT blob + * @offset: Offset of previous subnode + * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes + */ +int fdt_next_subnode(const void *fdt, int offset); + +/**********************************************************************/ +/* General functions */ +/**********************************************************************/ + +#define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +#define __fdt_set_hdr(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ + struct fdt_header *fdth = (struct fdt_header*)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } +__fdt_set_hdr(magic); +__fdt_set_hdr(totalsize); +__fdt_set_hdr(off_dt_struct); +__fdt_set_hdr(off_dt_strings); +__fdt_set_hdr(off_mem_rsvmap); +__fdt_set_hdr(version); +__fdt_set_hdr(last_comp_version); +__fdt_set_hdr(boot_cpuid_phys); +__fdt_set_hdr(size_dt_strings); +__fdt_set_hdr(size_dt_struct); +#undef __fdt_set_hdr + +/** + * fdt_check_header - sanity check a device tree or possible device tree + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree with sane information in its + * header. + * + * returns: + * 0, if the buffer appears to contain a valid device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings, as above + */ +int fdt_check_header(const void *fdt); + +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize. The buffer may overlap + * with the existing device tree blob at fdt. Therefore, + * fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move(const void *fdt, void *buf, int bufsize); + +/**********************************************************************/ +/* Read-only functions */ +/**********************************************************************/ + +/** + * fdt_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds + */ +const char *fdt_string(const void *fdt, int stroffset); + +/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob's memory + * reservation map. This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + * the number of entries + */ +int fdt_num_mem_rsv(const void *fdt); + +/** + * fdt_get_mem_rsv - retrieve one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: pointers to 64-bit variables + * + * On success, *address and *size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name. This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + const char *name, int namelen); +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name. name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + +/** + * fdt_path_offset_namelen - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * @namelen: number of characters of path to consider + * + * Identical to fdt_path_offset(), but only consider the first namelen + * characters of path as the path name. + */ +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); + +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + * structure block offset of the node with the requested path (>=0), on success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset(const void *fdt, const char *path); + +/** + * fdt_get_name - retrieve the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset. If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + * pointer to the node's name, on success + * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); + +/** + * fdt_first_property_offset - find the offset of a node's first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset(const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node's properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset(const void *fdt, int offset); + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp); + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_get_property(), but only examine the first namelen + * characters of name for matching the property name. + */ +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); + +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named 'name' of the node at offset nodeoffset. If lenp is + * non-NULL, the length of the property value is also returned, in the + * integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, + const char *name, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @ffset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset 'offset' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property's namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree's string + * block, not a new copy of the name). + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); + +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named 'name' of the node at offset nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline void *fdt_getprop_w(void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retrieve the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + * the phandle of the node at nodeoffset, on success (!= 0, != -1) + * 0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + +/** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); + +/** + * fdt_get_alias - retreive the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named 'name' in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named 'name', if it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias(const void *fdt, const char *name); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth). So + * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node. If the node at + * nodeoffset has depth D, then: + * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node. The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * depth of the node at nodeoffset (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth(const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset(const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + * propval, proplen); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + * propval, proplen); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_phandle() returns the offset of the node + * which has the given phandle value. If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + * structure block offset of the located node (>= 0), on success + * -FDT_ERR_NOTFOUND, no node with that phandle exists + * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible: check a node's compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * 'compatible' property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + * 0, if the node has a 'compatible' property listing the given string + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: 'compatible' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a 'compatible' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible); + +/** + * fdt_stringlist_contains - check a string list property for a string + * @strlist: Property containing a list of strings to check + * @listlen: Length of property + * @str: String to search for + * + * This is a utility function provided for convenience. The list contains + * one or more strings, each terminated by \0, as is found in a device tree + * "compatible" property. + * + * @return: 1 if the string is found in the list, 0 not found, or invalid list + */ +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + +/**********************************************************************/ +/* Read-only functions (addressing related) */ +/**********************************************************************/ + +/** + * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells + * + * This is the maximum value for #address-cells, #size-cells and + * similar properties that will be processed by libfdt. IEE1275 + * requires that OF implementations handle values up to 4. + * Implementations may support larger values, but in practice higher + * values aren't used. + */ +#define FDT_MAX_NCELLS 4 + +/** + * fdt_address_cells - retrieve address size for a bus represented in the tree + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to find the address size for + * + * When the node has a valid #address-cells property, returns its value. + * + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_address_cells(const void *fdt, int nodeoffset); + +/** + * fdt_size_cells - retrieve address range size for a bus represented in the + * tree + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to find the address range size for + * + * When the node has a valid #size-cells property, returns its value. + * + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_size_cells(const void *fdt, int nodeoffset); + + +/**********************************************************************/ +/* Write-in-place functions */ +/**********************************************************************/ + +/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len. This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property's current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to replace the property with + * + * fdt_setprop_inplace_u32() replaces the value of a given property + * with the 32-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to replace the property with + * + * fdt_setprop_inplace_u64() replaces the value of a given property + * with the 64-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 8. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * + * This is an alternative name for fdt_setprop_inplace_u32() + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property's representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_property(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node's representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Sequential write functions */ +/**********************************************************************/ + +int fdt_create(void *buf, int bufsize); +int fdt_resize(void *fdt, void *buf, int bufsize); +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap(void *fdt); +int fdt_begin_node(void *fdt, const char *name); +int fdt_property(void *fdt, const char *name, const void *val, int len); +static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} +static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ + return fdt_property_u32(fdt, name, val); +} +#define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node(void *fdt); +int fdt_finish(void *fdt); + +/**********************************************************************/ +/* Read-write functions */ +/**********************************************************************/ + +int fdt_create_empty_tree(void *buf, int bufsize); +int fdt_open_into(const void *fdt, void *buf, int bufsize); +int fdt_pack(void *fdt); + +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: 64-bit values (native endian) + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_mem_rsv(void *fdt, int n); + +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string. NOTE: this function can't + * efficiently check if the new name is unique amongst the given + * node's siblings; results are undefined if this function is invoked + * with a name equal to one of the given node's siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_setprop - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_u32 - set a property to a 32-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_u32() sets the value of the named property in the given + * node to the given 32-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_u64 - set a property to a 64-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value for the property (native endian) + * + * fdt_setprop_u64() sets the value of the named property in the given + * node to the given 64-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, + uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_cell - set a property to a single cell value + * + * This is an alternative name for fdt_setprop_u32() + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + return fdt_setprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to append to + * @val: pointer to data to append to the property value + * @len: length of the data to append to the property value + * + * fdt_appendprop() appends the value to the named property in the + * given node, creating the property if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_appendprop_u32 - append a 32-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u32() appends the given 32-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_u64 - append a 64-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u64() appends the given 64-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_cell - append a single cell value to a property + * + * This is an alternative name for fdt_appendprop_u32() + */ +static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_appendprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_appendprop_string - append a string to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value to append to the property + * + * fdt_appendprop_string() appends the given string to the value of + * the named property in the given node, or creates a new property + * with that value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first namelen + * characters of name as the name of the new node. This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen); + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + + * returns: + * structure block offset of the created nodeequested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Debugging / informational functions */ +/**********************************************************************/ + +const char *fdt_strerror(int errval); + +#endif /* _LIBFDT_H */ diff --git a/third_party/lib/fdt/include/libfdt_env.h b/third_party/lib/fdt/include/libfdt_env.h new file mode 100644 index 000000000..9dea97dff --- /dev/null +++ b/third_party/lib/fdt/include/libfdt_env.h @@ -0,0 +1,111 @@ +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef uint16_t __bitwise fdt16_t; +typedef uint32_t __bitwise fdt32_t; +typedef uint64_t __bitwise fdt64_t; + +#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) +#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) +#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ + (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) +#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ + (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ + (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ + (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) + +static inline uint16_t fdt16_to_cpu(fdt16_t x) +{ + return (__force uint16_t)CPU_TO_FDT16(x); +} +static inline fdt16_t cpu_to_fdt16(uint16_t x) +{ + return (__force fdt16_t)CPU_TO_FDT16(x); +} + +static inline uint32_t fdt32_to_cpu(fdt32_t x) +{ + return (__force uint32_t)CPU_TO_FDT32(x); +} +static inline fdt32_t cpu_to_fdt32(uint32_t x) +{ + return (__force fdt32_t)CPU_TO_FDT32(x); +} + +static inline uint64_t fdt64_to_cpu(fdt64_t x) +{ + return (__force uint64_t)CPU_TO_FDT64(x); +} +static inline fdt64_t cpu_to_fdt64(uint64_t x) +{ + return (__force fdt64_t)CPU_TO_FDT64(x); +} +#undef CPU_TO_FDT64 +#undef CPU_TO_FDT32 +#undef CPU_TO_FDT16 +#undef EXTRACT_BYTE + +#endif /* _LIBFDT_ENV_H */ diff --git a/third_party/lib/fdt/libfdt_internal.h b/third_party/lib/fdt/libfdt_internal.h new file mode 100644 index 000000000..02cfa6fb6 --- /dev/null +++ b/third_party/lib/fdt/libfdt_internal.h @@ -0,0 +1,95 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +#define FDT_CHECK_HEADER(fdt) \ + { \ + int __err; \ + if ((__err = fdt_check_header(fdt)) != 0) \ + return __err; \ + } + +int _fdt_check_node_offset(const void *fdt, int offset); +int _fdt_check_prop_offset(const void *fdt, int offset); +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset(void *fdt, int nodeoffset); + +static inline const void *_fdt_offset_ptr(const void *fdt, int offset) +{ + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *_fdt_offset_ptr_w(void *fdt, int offset) +{ + return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); +} + +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + + return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) +{ + return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); +} + +#define FDT_SW_MAGIC (~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ diff --git a/third_party/lib/fdt/rules.mk b/third_party/lib/fdt/rules.mk new file mode 100644 index 000000000..040936e30 --- /dev/null +++ b/third_party/lib/fdt/rules.mk @@ -0,0 +1,17 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/fdt.c \ + $(LOCAL_DIR)/fdt_addresses.c \ + $(LOCAL_DIR)/fdt_empty_tree.c \ + $(LOCAL_DIR)/fdt_ro.c \ + $(LOCAL_DIR)/fdt_rw.c \ + $(LOCAL_DIR)/fdt_strerror.c \ + $(LOCAL_DIR)/fdt_sw.c \ + $(LOCAL_DIR)/fdt_wip.c + +MODULE_COMPILEFLAGS += -Wno-sign-compare + +include make/module.mk diff --git a/third_party/lib/fdt/version.lds b/third_party/lib/fdt/version.lds new file mode 100644 index 000000000..f19f157f3 --- /dev/null +++ b/third_party/lib/fdt/version.lds @@ -0,0 +1,63 @@ +LIBFDT_1.2 { + global: + fdt_next_node; + fdt_check_header; + fdt_move; + fdt_string; + fdt_num_mem_rsv; + fdt_get_mem_rsv; + fdt_subnode_offset_namelen; + fdt_subnode_offset; + fdt_path_offset_namelen; + fdt_path_offset; + fdt_get_name; + fdt_get_property_namelen; + fdt_get_property; + fdt_getprop_namelen; + fdt_getprop; + fdt_get_phandle; + fdt_get_alias_namelen; + fdt_get_alias; + fdt_get_path; + fdt_supernode_atdepth_offset; + fdt_node_depth; + fdt_parent_offset; + fdt_node_offset_by_prop_value; + fdt_node_offset_by_phandle; + fdt_node_check_compatible; + fdt_node_offset_by_compatible; + fdt_setprop_inplace; + fdt_nop_property; + fdt_nop_node; + fdt_create; + fdt_add_reservemap_entry; + fdt_finish_reservemap; + fdt_begin_node; + fdt_property; + fdt_end_node; + fdt_finish; + fdt_open_into; + fdt_pack; + fdt_add_mem_rsv; + fdt_del_mem_rsv; + fdt_set_name; + fdt_setprop; + fdt_delprop; + fdt_add_subnode_namelen; + fdt_add_subnode; + fdt_del_node; + fdt_strerror; + fdt_offset_ptr; + fdt_next_tag; + fdt_appendprop; + fdt_create_empty_tree; + fdt_first_property_offset; + fdt_get_property_by_offset; + fdt_getprop_by_offset; + fdt_next_property_offset; + fdt_first_subnode; + fdt_next_subnode; + + local: + *; +}; diff --git a/third_party/lib/libm/BUILD.gn b/third_party/lib/libm/BUILD.gn new file mode 100644 index 000000000..6b1c321e9 --- /dev/null +++ b/third_party/lib/libm/BUILD.gn @@ -0,0 +1,53 @@ +config("_libm_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("libm") { + public_configs = [ ":_libm_config" ] + cflags = [ + "-Wno-unused-variable", + "-Wno-sign-compare", + "-Wno-parentheses", + ] + sources = [ + "e_acos.c", + "e_acosf.c", + "e_asin.c", + "e_asinf.c", + "e_atan2.c", + "e_exp.c", + "e_fmod.c", + "e_log.c", + "e_pow.c", + "e_powf.c", + "e_sqrt.c", + "e_sqrtf.c", + "k_cos.c", + "k_rem_pio2.c", + "k_sin.c", + "k_tan.c", + "s_atan.c", + "s_ceil.c", + "s_ceilf.c", + "s_copysign.c", + "s_copysignf.c", + "s_cos.c", + "s_cosf.c", + "s_fabs.c", + "s_fabsf.c", + "s_floor.c", + "s_floorf.c", + "s_round.c", + "s_scalbn.c", + "s_scalbnf.c", + "s_sin.c", + "s_sinf.c", + "s_tan.c", + "s_tanf.c", + "s_trunc.c", + ] + deps = [ + "//kernel/lib/libc", + ] +} diff --git a/third_party/lib/libm/e_acos.c b/third_party/lib/libm/e_acos.c new file mode 100644 index 000000000..8ba672a7d --- /dev/null +++ b/third_party/lib/libm/e_acos.c @@ -0,0 +1,104 @@ + +/* @(#)e_acos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/e_acos.c,v 1.10 2005/02/04 18:26:05 das Exp $"; +#endif + +/* __ieee754_acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include "math.h" +#include "math_private.h" + +static const double +one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +double +__ieee754_acos(double x) +{ + double z,p,q,r,w,s,c,df; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3ff00000) { /* |x| >= 1 */ + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((ix-0x3ff00000)|lx)==0) { /* |x|==1 */ + if(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3fe00000) { /* |x| < 0.5 */ + if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/ + z = x*x; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (hx<0) { /* x < -0.5 */ + z = (one+x)*0.5; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + s = sqrt(z); + r = p/q; + w = r*s-pio2_lo; + return pi - 2.0*(s+w); + } else { /* x > 0.5 */ + z = (one-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + w = r*s+c; + return 2.0*(df+w); + } +} diff --git a/third_party/lib/libm/e_acosf.c b/third_party/lib/libm/e_acosf.c new file mode 100644 index 000000000..a11f48ee6 --- /dev/null +++ b/third_party/lib/libm/e_acosf.c @@ -0,0 +1,81 @@ +/* e_acosf.c -- float version of e_acos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/e_acosf.c,v 1.7 2002/05/28 17:03:12 alfred Exp $"; +#endif + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +pi = 3.1415925026e+00, /* 0x40490fda */ +pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ +pS0 = 1.6666667163e-01, /* 0x3e2aaaab */ +pS1 = -3.2556581497e-01, /* 0xbea6b090 */ +pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */ +pS3 = -4.0055535734e-02, /* 0xbd241146 */ +pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */ +pS5 = 3.4793309169e-05, /* 0x3811ef08 */ +qS1 = -2.4033949375e+00, /* 0xc019d139 */ +qS2 = 2.0209457874e+00, /* 0x4001572d */ +qS3 = -6.8828397989e-01, /* 0xbf303361 */ +qS4 = 7.7038154006e-02; /* 0x3d9dc62e */ + +float +__ieee754_acosf(float x) +{ + float z,p,q,r,w,s,c,df; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix==0x3f800000) { /* |x|==1 */ + if(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+(float)2.0*pio2_lo; /* acos(-1)= pi */ + } else if(ix>0x3f800000) { /* |x| >= 1 */ + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3f000000) { /* |x| < 0.5 */ + if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/ + z = x*x; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (hx<0) { /* x < -0.5 */ + z = (one+x)*(float)0.5; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + s = __ieee754_sqrtf(z); + r = p/q; + w = r*s-pio2_lo; + return pi - (float)2.0*(s+w); + } else { /* x > 0.5 */ + int32_t idf; + z = (one-x)*(float)0.5; + s = __ieee754_sqrtf(z); + df = s; + GET_FLOAT_WORD(idf,df); + SET_FLOAT_WORD(df,idf&0xfffff000); + c = (z-df*df)/(s+df); + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + w = r*s+c; + return (float)2.0*(df+w); + } +} diff --git a/third_party/lib/libm/e_asin.c b/third_party/lib/libm/e_asin.c new file mode 100644 index 000000000..1ba702626 --- /dev/null +++ b/third_party/lib/libm/e_asin.c @@ -0,0 +1,113 @@ + +/* @(#)e_asin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/e_asin.c,v 1.11 2005/02/04 18:26:05 das Exp $"; +#endif + +/* __ieee754_asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +huge = 1.000e+300, +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */ + /* coefficient for R(x^2) */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +double +__ieee754_asin(double x) +{ + double t=0.0,w,p,q,c,r,s; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>= 0x3ff00000) { /* |x|>= 1 */ + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((ix-0x3ff00000)|lx)==0) + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3fe00000) { /* |x|<0.5 */ + if(ix<0x3e400000) { /* if |x| < 2**-27 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } else + t = x*x; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabs(x); + t = w*0.5; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + s = sqrt(t); + if(ix>=0x3FEF3333) { /* if |x| > 0.975 */ + w = p/q; + t = pio2_hi-(2.0*(s+s*w)-pio2_lo); + } else { + w = s; + SET_LOW_WORD(w,0); + c = (t-w*w)/(s+w); + r = p/q; + p = 2.0*s*r-(pio2_lo-2.0*c); + q = pio4_hi-2.0*w; + t = pio4_hi-(p-q); + } + if(hx>0) return t; else return -t; +} diff --git a/third_party/lib/libm/e_asinf.c b/third_party/lib/libm/e_asinf.c new file mode 100644 index 000000000..1405fafc6 --- /dev/null +++ b/third_party/lib/libm/e_asinf.c @@ -0,0 +1,84 @@ +/* e_asinf.c -- float version of e_asin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/e_asinf.c,v 1.9 2005/12/04 13:52:46 bde Exp $"; +#endif + +#include "math.h" +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +huge = 1.000e+30, +pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ +pio4_hi = 7.8539812565e-01, /* 0x3f490fda */ + /* coefficient for R(x^2) */ +pS0 = 1.6666667163e-01, /* 0x3e2aaaab */ +pS1 = -3.2556581497e-01, /* 0xbea6b090 */ +pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */ +pS3 = -4.0055535734e-02, /* 0xbd241146 */ +pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */ +pS5 = 3.4793309169e-05, /* 0x3811ef08 */ +qS1 = -2.4033949375e+00, /* 0xc019d139 */ +qS2 = 2.0209457874e+00, /* 0x4001572d */ +qS3 = -6.8828397989e-01, /* 0xbf303361 */ +qS4 = 7.7038154006e-02; /* 0x3d9dc62e */ + +float +__ieee754_asinf(float x) +{ + float t=0.0,w,p,q,c,r,s; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix==0x3f800000) { + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + } else if(ix> 0x3f800000) { /* |x|>= 1 */ + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3f000000) { /* |x|<0.5 */ + if(ix<0x32000000) { /* if |x| < 2**-27 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } else + t = x*x; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabsf(x); + t = w*(float)0.5; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + s = __ieee754_sqrtf(t); + if(ix>=0x3F79999A) { /* if |x| > 0.975 */ + w = p/q; + t = pio2_hi-((float)2.0*(s+s*w)-pio2_lo); + } else { + int32_t iw; + w = s; + GET_FLOAT_WORD(iw,w); + SET_FLOAT_WORD(w,iw&0xfffff000); + c = (t-w*w)/(s+w); + r = p/q; + p = (float)2.0*s*r-(pio2_lo-(float)2.0*c); + q = pio4_hi-(float)2.0*w; + t = pio4_hi-(p-q); + } + if(hx>0) return t; else return -t; +} diff --git a/third_party/lib/libm/e_atan2.c b/third_party/lib/libm/e_atan2.c new file mode 100644 index 000000000..e91d3094a --- /dev/null +++ b/third_party/lib/libm/e_atan2.c @@ -0,0 +1,131 @@ + +/* @(#)e_atan2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __ieee754_atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include + +#include "math.h" +#include "math_private.h" + +static volatile double +tiny = 1.0e-300; +static const double +zero = 0.0, +pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */ +pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */ +pi = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +static volatile double +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double +__ieee754_atan2(double y, double x) +{ + double z; + int32_t k,m,hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; + EXTRACT_WORDS(hy,ly,y); + iy = hy&0x7fffffff; + if(((ix|((lx|-lx)>>31))>0x7ff00000)|| + ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */ + return x+y; + if((hx-0x3ff00000|lx)==0) return atan(y); /* x=1.0 */ + m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if((iy|ly)==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* when x is INF */ + if(ix==0x7ff00000) { + if(iy==0x7ff00000) { + switch(m) { + case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */ + case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ + case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ + case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* compute y/x */ + k = (iy-ix)>>20; + if(k > 60) { /* |y/x| > 2**60 */ + z=pi_o_2+0.5*pi_lo; + m&=1; + } + else if(hx<0&&k<-60) z=0.0; /* 0 > |y|/x > -2**-60 */ + else z=atan(fabs(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} + +#if SUPPORT_LONG_DOUBLE +#if LDBL_MANT_DIG == 53 +__weak_reference(atan2, atan2l); +#endif +#endif diff --git a/third_party/lib/libm/e_exp.c b/third_party/lib/libm/e_exp.c new file mode 100644 index 000000000..c03c9de7d --- /dev/null +++ b/third_party/lib/libm/e_exp.c @@ -0,0 +1,166 @@ + +/* @(#)e_exp.c 1.6 04/04/22 */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __ieee754_exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remes algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ------- + * R - r + * r*R1(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - R1(r) + * where + * 2 4 10 + * R1(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then exp(x) overflow + * if x < -7.45133219101941108420e+02 then exp(x) underflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.0, +halF[2] = {0.5,-0.5,}, +o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */ +ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */ +ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +static volatile double +huge = 1.0e+300, +twom1000= 9.33263618503218878990e-302; /* 2**-1000=0x01700000,0*/ + +double +__ieee754_exp(double x) /* default IEEE double exp */ +{ + double y,hi=0.0,lo=0.0,c,t,twopk; + int32_t k=0,xsb; + u_int32_t hx; + + GET_HIGH_WORD(hx,x); + xsb = (hx>>31)&1; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out non-finite argument */ + if(hx >= 0x40862E42) { /* if |x|>=709.78... */ + if(hx>=0x7ff00000) { + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((hx&0xfffff)|lx)!=0) + return x+x; /* NaN */ + else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ + } + if(x > o_threshold) return huge*huge; /* overflow */ + if(x < u_threshold) return twom1000*twom1000; /* underflow */ + } + + /* argument reduction */ + if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; + } else { + k = (int)(invln2*x+halF[xsb]); + t = k; + hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + lo = t*ln2LO[0]; + } + STRICT_ASSIGN(double, x, hi - lo); + } + else if(hx < 0x3e300000) { /* when |x|<2**-28 */ + if(huge+x>one) return one+x;/* trigger inexact */ + } + else k = 0; + + /* x is now in primary range */ + t = x*x; + if(k >= -1021) + INSERT_WORDS(twopk,0x3ff00000+(k<<20), 0); + else + INSERT_WORDS(twopk,0x3ff00000+((k+1000)<<20), 0); + c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + if(k==0) return one-((x*c)/(c-2.0)-x); + else y = one-((lo-(x*c)/(2.0-c))-hi); + if(k >= -1021) { + if (k==1024) return y*2.0*0x1p1023; + return y*twopk; + } else { + return y*twopk*twom1000; + } +} + +#ifdef SUPPORT_LONG_DOUBLE +#if (LDBL_MANT_DIG == 53) +__weak_reference(exp, expl); +#endif +#endif diff --git a/third_party/lib/libm/e_fmod.c b/third_party/lib/libm/e_fmod.c new file mode 100644 index 000000000..720aa0333 --- /dev/null +++ b/third_party/lib/libm/e_fmod.c @@ -0,0 +1,132 @@ + +/* @(#)e_fmod.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * __ieee754_fmod(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include "math.h" +#include "math_private.h" + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + +double +__ieee754_fmod(double x, double y) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t lx,ly,lz; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx>31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x00100000) { /* subnormal x */ + if(hx==0) { + for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; + } + } else ix = (hx>>20)-1023; + + /* determine iy = ilogb(y) */ + if(hy<0x00100000) { /* subnormal y */ + if(hy==0) { + for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; + } + } else iy = (hy>>20)-1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -1022) + hx = 0x00100000|(0x000fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -1022-ix; + if(n<=31) { + hx = (hx<>(32-n)); + lx <<= n; + } else { + hx = lx<<(n-32); + lx = 0; + } + } + if(iy >= -1022) + hy = 0x00100000|(0x000fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -1022-iy; + if(n<=31) { + hy = (hy<>(32-n)); + ly <<= n; + } else { + hy = ly<<(n-32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx>31); lx = lx+lx;} + else { + if((hz|lz)==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + hx = hz+hz+(lz>>31); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + while(hx<0x00100000) { /* normalize x */ + hx = hx+hx+(lx>>31); lx = lx+lx; + iy -= 1; + } + if(iy>= -1022) { /* normalize output */ + hx = ((hx-0x00100000)|((iy+1023)<<20)); + INSERT_WORDS(x,hx|sx,lx); + } else { /* subnormal output */ + n = -1022 - iy; + if(n<=20) { + lx = (lx>>n)|((u_int32_t)hx<<(32-n)); + hx >>= n; + } else if (n<=31) { + lx = (hx<<(32-n))|(lx>>n); hx = sx; + } else { + lx = hx>>(n-32); hx = sx; + } + INSERT_WORDS(x,hx|sx,lx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/third_party/lib/libm/e_log.c b/third_party/lib/libm/e_log.c new file mode 100644 index 000000000..9425b85d1 --- /dev/null +++ b/third_party/lib/libm/e_log.c @@ -0,0 +1,149 @@ + +/* @(#)e_log.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __ieee754_log(x) + * Return the logrithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; +static volatile double vzero = 0.0; + +double +__ieee754_log(double x) +{ + double hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,hx,i,j; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/vzero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + f = x-1.0; + if((0x000fffff&(2+hx))<3) { /* -2**-20 <= f < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + dk=(double)k; + return dk*ln2_hi+dk*ln2_lo; + } + } + R = f*f*(0.5-0.33333333333333333*f); + if(k==0) return f-R; else {dk=(double)k; + return dk*ln2_hi-((R-dk*ln2_lo)-f);} + } + s = f/(2.0+f); + dk = (double)k; + z = s*s; + i = hx-0x6147a; + w = z*z; + j = 0x6b851-hx; + t1= w*(Lg2+w*(Lg4+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + i |= j; + R = t2+t1; + if(i>0) { + hfsq=0.5*f*f; + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); + } else { + if(k==0) return f-s*(f-R); else + return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); + } +} + +#ifdef SUPPORT_LONG_DOUBLE +#if (LDBL_MANT_DIG == 53) +__weak_reference(log, logl); +#endif +#endif diff --git a/third_party/lib/libm/e_pow.c b/third_party/lib/libm/e_pow.c new file mode 100644 index 000000000..d21313253 --- /dev/null +++ b/third_party/lib/libm/e_pow.c @@ -0,0 +1,304 @@ +/* @(#)e_pow.c 1.5 04/04/22 SMI */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/e_pow.c,v 1.11 2005/02/04 18:26:06 das Exp $"; +#endif + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "math.h" +#include "math_private.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double +__ieee754_pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* +-NaN return x+y */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return x+y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if((j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return y - y; /* inf**+-1 is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be + n = (hx>>31)+1; + but ANSI C says a right shift of a signed negative quantity is + implementation defined. */ + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + SET_LOW_WORD(t1,0); + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|>1)|0x20000000)+0x00080000+(k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + SET_LOW_WORD(t_h,0); + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + SET_LOW_WORD(p_h,0); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + SET_LOW_WORD(t1,0); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1,0); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + EXTRACT_WORDS(j,i,z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + SET_HIGH_WORD(t,n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + SET_LOW_WORD(t,0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_HIGH_WORD(j,z); + j += (n<<20); + if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */ + else SET_HIGH_WORD(z,j); + return s*z; +} diff --git a/third_party/lib/libm/e_powf.c b/third_party/lib/libm/e_powf.c new file mode 100644 index 000000000..41f08ddbb --- /dev/null +++ b/third_party/lib/libm/e_powf.c @@ -0,0 +1,247 @@ +/* e_powf.c -- float version of e_pow.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/e_powf.c,v 1.12 2004/06/01 19:33:30 bde Exp $"; +#endif + +#include "math.h" +#include "math_private.h" + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +zero = 0.0, +one = 1.0, +two = 2.0, +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6179199219e-01, /* 0x3f763800 =head of cp */ +cp_l = 4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float +__ieee754_powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if(iy==0) return one; + + /* +-NaN return x+y */ + if(ix > 0x7f800000 || + iy > 0x7f800000) + return x+y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x4b800000) yisint = 2; /* even integer y */ + else if(iy>=0x3f800000) { + k = (iy>>23)-0x7f; /* exponent */ + j = iy>>(23-k); + if((j<<(23-k))==iy) yisint = 2-(j&1); + } + } + + /* special value of y */ + if (iy==0x7f800000) { /* y is +-inf */ + if (ix==0x3f800000) + return y - y; /* inf**+-1 is NaN */ + else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3f800000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3f000000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return __ieee754_sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if(ix==0x7f800000||ix==0||ix==0x3f800000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3f800000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny; + if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-1; /* t has 20 trailing zeros */ + w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + GET_FLOAT_WORD(is,t1); + SET_FLOAT_WORD(t1,is&0xfffff000); + t2 = v-(t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00800000) + {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); } + n += ((ix)>>23)-0x7f; + j = ix&0x007fffff; + /* determine interval */ + ix = j|0x3f800000; /* normalize ix */ + if(j<=0x1cc471) k=0; /* |x|>1)&0xfffff000)|0x20000000; + SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = (float)3.0+s2+r; + GET_FLOAT_WORD(is,t_h); + SET_FLOAT_WORD(t_h,is&0xfffff000); + t_l = r-((t_h-(float)3.0)-s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u+v; + GET_FLOAT_WORD(is,p_h); + SET_FLOAT_WORD(p_h,is&0xfffff000); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + GET_FLOAT_WORD(is,t1); + SET_FLOAT_WORD(t1,is&0xfffff000); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is,y); + SET_FLOAT_WORD(y1,is&0xfffff000); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + GET_FLOAT_WORD(j,z); + if (j>0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j==0x43000000) { /* if z == 128 */ + if(p_l+ovt>z-p_h) return sn*huge*huge; /* overflow */ + } + else if ((j&0x7fffffff)>0x43160000) /* z <= -150 */ + return sn*tiny*tiny; /* underflow */ + else if (j==0xc3160000){ /* z == -150 */ + if(p_l<=z-p_h) return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>23)-0x7f; + n = 0; + if(i>0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23)-0x7f; /* new k for n */ + SET_FLOAT_WORD(t,n&~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + GET_FLOAT_WORD(is,t); + SET_FLOAT_WORD(t,is&0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_FLOAT_WORD(j,z); + j += (n<<23); + if((j>>23)<=0) z = scalbnf(z,n); /* subnormal output */ + else SET_FLOAT_WORD(z,j); + return sn*z; +} diff --git a/third_party/lib/libm/e_rem_pio2.c b/third_party/lib/libm/e_rem_pio2.c new file mode 100644 index 000000000..86fde2d9e --- /dev/null +++ b/third_party/lib/libm/e_rem_pio2.c @@ -0,0 +1,189 @@ + +/* @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __ieee754_rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include + +#include "math.h" +#include "math_private.h" + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const double +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +#ifdef INLINE_REM_PIO2 +static __inline __always_inline +#endif +int +__ieee754_rem_pio2(double x, double *y) +{ + double z,w,t,r,fn; + double tx[3],ty[2]; + int32_t e0,i,j,nx,n,ix,hx; + u_int32_t low; + + GET_HIGH_WORD(hx,x); /* high word of x */ + ix = hx&0x7fffffff; +#if 0 /* Must be handled in caller. */ + if (ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} +#endif + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (hx > 0) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + return -1; + } + } else { + if (hx > 0) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0])-2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0])+2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (hx > 0) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0])-3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0])+3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (hx > 0) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0])-4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0])+4*pio2_1t; + return -4; + } + } + } + if (ix<0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52); + fn = fn-0x1.8p52; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = (int32_t)fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 85 bit */ + { + u_int32_t high; + j = ix>>20; + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if (i>16) { /* 2nd iteration needed, good to 118 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if (i>49) { /* 3rd iteration need, 151 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + return n; + } + /* + * all other (large) arguments + */ + if (ix>=0x7ff00000) { /* x is inf or NaN */ + y[0]=y[1]=x-x; + return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + GET_LOW_WORD(low,x); + e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */ + INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low); + for (i=0; i<2; i++) { + tx[i] = (double)((int32_t)(z)); + z = (z-tx[i])*two24; + } + tx[2] = z; + nx = 3; + while (tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,ty,e0,nx,1); + if (hx<0) {y[0] = -ty[0]; y[1] = -ty[1]; return -n;} + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} diff --git a/third_party/lib/libm/e_rem_pio2f.c b/third_party/lib/libm/e_rem_pio2f.c new file mode 100644 index 000000000..b06846614 --- /dev/null +++ b/third_party/lib/libm/e_rem_pio2f.c @@ -0,0 +1,86 @@ +/* e_rem_pio2f.c -- float version of e_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __kernel_rem_pio2() for large x + */ + +#include + +#include "math.h" +#include "math_private.h" + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ + +static const double +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ +pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +#ifdef INLINE_REM_PIO2F +static __inline __always_inline +#endif +int +__ieee754_rem_pio2f(float x, double *y) +{ + double w,r,fn; + double tx[1],ty[1]; + float z; + int32_t e0,n,ix,hx; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + /* 33+53 bit pi is good enough for medium size */ + if (ix<0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52); + fn = fn-0x1.8p52; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = (int32_t)fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; + *y = r-w; + return n; + } + /* + * all other (large) arguments + */ + if (ix>=0x7f800000) { /* x is inf or NaN */ + *y=x-x; + return 0; + } + /* set z = scalbn(|x|,ilogb(|x|)-23) */ + e0 = (ix>>23)-150; /* e0 = ilogb(|x|)-23; */ + SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23))); + tx[0] = z; + n = __kernel_rem_pio2(tx,ty,e0,1,0); + if (hx<0) {*y = -ty[0]; return -n;} + *y = ty[0]; + return n; +} diff --git a/third_party/lib/libm/e_sqrt.c b/third_party/lib/libm/e_sqrt.c new file mode 100644 index 000000000..1abcb014a --- /dev/null +++ b/third_party/lib/libm/e_sqrt.c @@ -0,0 +1,468 @@ + +/* @(#)e_sqrt.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __ieee754_sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + * + * Other methods : see the appended file at the end of the program below. + *--------------- + */ + +#include + +#include "math.h" +#include "math_private.h" + +#if defined(LK) && ARCH_ARM && ARM_WITH_VFP +/* use ARM w/VFP sqrt instruction */ +double +__ieee754_sqrt(double x) +{ + double res; + + __asm__("vsqrt.f64 %0, %1" : "=w"(res) : "w"(x)); + + return res; +} + +#else + +static const double one = 1.0, tiny=1.0e-300; + +double +__ieee754_sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + u_int32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0,ix1,x); + + /* take care of Inf and NaN */ + if ((ix0&0x7ff00000)==0x7ff00000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix0<=0) { + if (((ix0&(~sign))|ix1)==0) return x; /* sqrt(+-0) = +-0 */ + else if (ix0<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix0>>20); + if (m==0) { /* subnormal x */ + while (ix0==0) { + m -= 21; + ix0 |= (ix1>>11); + ix1 <<= 21; + } + for (i=0; (ix0&0x00100000)==0; i++) ix0<<=1; + m -= i-1; + ix0 |= (ix1>>(32-i)); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if (m&1) { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while (r!=0) { + t = s0+r; + if (t<=ix0) { + s0 = t+r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r>>=1; + } + + r = sign; + while (r!=0) { + t1 = s1+r; + t = s0; + if ((t>31); + ix1 += ix1; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if ((ix0|ix1)!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;} + else if (z>one) { + if (q1==(u_int32_t)0xfffffffe) q+=1; + q1+=2; + } else + q1 += (q1&1); + } + } + ix0 = (q>>1)+0x3fe00000; + ix1 = q1>>1; + if ((q&1)==1) ix1 |= sign; + ix0 += (m <<20); + INSERT_WORDS(z,ix0,ix1); + return z; +} +#endif + +#if SUPPORT_LONG_DOUBLE +#if (LDBL_MANT_DIG == 53) +__weak_reference(sqrt, sqrtl); +#endif +#endif +/* +Other methods (use floating-point arithmetic) +------------- +(This is a copy of a drafted paper by Prof W. Kahan +and K.C. Ng, written in May, 1986) + + Two algorithms are given here to implement sqrt(x) + (IEEE double precision arithmetic) in software. + Both supply sqrt(x) correctly rounded. The first algorithm (in + Section A) uses newton iterations and involves four divisions. + The second one uses reciproot iterations to avoid division, but + requires more multiplications. Both algorithms need the ability + to chop results of arithmetic operations instead of round them, + and the INEXACT flag to indicate when an arithmetic operation + is executed exactly with no roundoff error, all part of the + standard (IEEE 754-1985). The ability to perform shift, add, + subtract and logical AND operations upon 32-bit words is needed + too, though not part of the standard. + +A. sqrt(x) by Newton Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + + 1 11 52 ...widths + ------------------------------------------------------ + x: |s| e | f | + ------------------------------------------------------ + msb lsb msb lsb ...order + + + ------------------------ ------------------------ + x0: |s| e | f1 | x1: | f2 | + ------------------------ ------------------------ + + By performing shifts and subtracts on x0 and x1 (both regarded + as integers), we obtain an 8-bit approximation of sqrt(x) as + follows. + + k := (x0>>1) + 0x1ff80000; + y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits + Here k is a 32-bit integer and T1[] is an integer array containing + correction terms. Now magically the floating value of y (y's + leading 32-bit word is y0, the value of its trailing word is 0) + approximates sqrt(x) to almost 8-bit. + + Value of T1: + static int T1[32]= { + 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215, + 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581, + 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,}; + + (2) Iterative refinement + + Apply Heron's rule three times to y, we have y approximates + sqrt(x) to within 1 ulp (Unit in the Last Place): + + y := (y+x/y)/2 ... almost 17 sig. bits + y := (y+x/y)/2 ... almost 35 sig. bits + y := y-(y-x/y)/2 ... within 1 ulp + + + Remark 1. + Another way to improve y to within 1 ulp is: + + y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x) + y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x) + + 2 + (x-y )*y + y := y + 2* ---------- ...within 1 ulp + 2 + 3y + x + + + This formula has one division fewer than the one above; however, + it requires more multiplications and additions. Also x must be + scaled in advance to avoid spurious overflow in evaluating the + expression 3y*y+x. Hence it is not recommended uless division + is slow. If division is very slow, then one should use the + reciproot algorithm given in section B. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + I := FALSE; ... reset INEXACT flag I + R := RZ; ... set rounding mode to round-toward-zero + z := x/y; ... chopped quotient, possibly inexact + If(not I) then { ... if the quotient is exact + if(z=y) { + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + } else { + z := z - ulp; ... special rounding + } + } + i := TRUE; ... sqrt(x) is inexact + If (r=RN) then z=z+ulp ... rounded-to-nearest + If (r=RP) then { ... round-toward-+inf + y = y+ulp; z=z+ulp; + } + y := y+z; ... chopped sum + y0:=y0-0x00100000; ... y := y/2 is correctly rounded. + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + + (4) Special cases + + Square root of +inf, +-0, or NaN is itself; + Square root of a negative number is NaN with invalid signal. + + +B. sqrt(x) by Reciproot Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + (see section A). By performing shifs and subtracts on x0 and y0, + we obtain a 7.8-bit approximation of 1/sqrt(x) as follows. + + k := 0x5fe80000 - (x0>>1); + y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits + + Here k is a 32-bit integer and T2[] is an integer array + containing correction terms. Now magically the floating + value of y (y's leading 32-bit word is y0, the value of + its trailing word y1 is set to zero) approximates 1/sqrt(x) + to almost 7.8-bit. + + Value of T2: + static int T2[64]= { + 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866, + 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f, + 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d, + 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0, + 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989, + 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd, + 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e, + 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,}; + + (2) Iterative refinement + + Apply Reciproot iteration three times to y and multiply the + result by x to get an approximation z that matches sqrt(x) + to about 1 ulp. To be exact, we will have + -1ulp < sqrt(x)-z<1.0625ulp. + + ... set rounding mode to Round-to-nearest + y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x) + y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x) + ... special arrangement for better accuracy + z := x*y ... 29 bits to sqrt(x), with z*y<1 + z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x) + + Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that + (a) the term z*y in the final iteration is always less than 1; + (b) the error in the final result is biased upward so that + -1 ulp < sqrt(x) - z < 1.0625 ulp + instead of |sqrt(x)-z|<1.03125ulp. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + R := RZ; ... set rounding mode to round-toward-zero + switch(r) { + case RN: ... round-to-nearest + if(x<= z*(z-ulp)...chopped) z = z - ulp; else + if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp; + break; + case RZ:case RM: ... round-to-zero or round-to--inf + R:=RP; ... reset rounding mod to round-to-+inf + if(x=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp; + break; + case RP: ... round-to-+inf + if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else + if(x>z*z ...chopped) z = z+ulp; + break; + } + + Remark 3. The above comparisons can be done in fixed point. For + example, to compare x and w=z*z chopped, it suffices to compare + x1 and w1 (the trailing parts of x and w), regarding them as + two's complement integers. + + ...Is z an exact square root? + To determine whether z is an exact square root of x, let z1 be the + trailing part of z, and also let x0 and x1 be the leading and + trailing parts of x. + + If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0 + I := 1; ... Raise Inexact flag: z is not exact + else { + j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2 + k := z1 >> 26; ... get z's 25-th and 26-th + fraction bits + I := i or (k&j) or ((k&(j+j+1))!=(x1&3)); + } + R:= r ... restore rounded mode + return sqrt(x):=z. + + If multiplication is cheaper then the foregoing red tape, the + Inexact flag can be evaluated by + + I := i; + I := (z*z!=x) or I. + + Note that z*z can overwrite I; this value must be sensed if it is + True. + + Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be + zero. + + -------------------- + z1: | f2 | + -------------------- + bit 31 bit 0 + + Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd + or even of logb(x) have the following relations: + + ------------------------------------------------- + bit 27,26 of z1 bit 1,0 of x1 logb(x) + ------------------------------------------------- + 00 00 odd and even + 01 01 even + 10 10 odd + 10 00 even + 11 01 even + ------------------------------------------------- + + (4) Special cases (see (4) of Section A). + + */ + diff --git a/third_party/lib/libm/e_sqrtf.c b/third_party/lib/libm/e_sqrtf.c new file mode 100644 index 000000000..5d5412a71 --- /dev/null +++ b/third_party/lib/libm/e_sqrtf.c @@ -0,0 +1,106 @@ +/* e_sqrtf.c -- float version of e_sqrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD$"; +#endif + +#include "math.h" +#include "math_private.h" + +static const float one = 1.0, tiny=1.0e-30; + +#if defined(LK) && ARCH_ARM && ARM_WITH_VFP +/* use ARM w/VFP sqrt instruction */ +float +__ieee754_sqrtf(float x) +{ + float res; + + __asm__("vsqrt.f32 %0, %1" : "=t"(res) : "t"(x)); + + return res; +} + +#else + +float +__ieee754_sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix,s,q,m,t,i; + u_int32_t r; + + GET_FLOAT_WORD(ix,x); + + /* take care of Inf and NaN */ + if ((ix&0x7f800000)==0x7f800000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix<=0) { + if ((ix&(~sign))==0) return x; /* sqrt(+-0) = +-0 */ + else if (ix<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix>>23); + if (m==0) { /* subnormal x */ + for (i=0; (ix&0x00800000)==0; i++) ix<<=1; + m -= i-1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffff)|0x00800000; + if (m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r!=0) { + t = s+r; + if (t<=ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if (ix!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (z>one) + q += 2; + else + q += (q&1); + } + } + ix = (q>>1)+0x3f000000; + ix += (m <<23); + SET_FLOAT_WORD(z,ix); + return z; +} + +#endif + diff --git a/third_party/lib/libm/include/math.h b/third_party/lib/libm/include/math.h new file mode 100644 index 000000000..64c166f91 --- /dev/null +++ b/third_party/lib/libm/include/math.h @@ -0,0 +1,474 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD$ + */ + +#ifndef _MATH_H_ +#define _MATH_H_ + +#include +#include + +__BEGIN_DECLS +#pragma GCC visibility push(default) + +/* + * ANSI/POSIX + */ +extern const union __infinity_un { + unsigned char __uc[8]; + double __ud; +} __infinity; + +extern const union __nan_un { + unsigned char __uc[sizeof(float)]; + float __uf; +} __nan; + +#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) +#define __MATH_BUILTIN_CONSTANTS +#endif + +#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER) +#define __MATH_BUILTIN_RELOPS +#endif + +#ifdef __MATH_BUILTIN_CONSTANTS +#define HUGE_VAL __builtin_huge_val() +#else +#define HUGE_VAL (__infinity.__ud) +#endif + +#if __ISO_C_VISIBLE >= 1999 +#define FP_ILOGB0 (-INT_MAX) /* Android-changed */ +#define FP_ILOGBNAN INT_MAX /* Android-changed */ + +#ifdef __MATH_BUILTIN_CONSTANTS +#define HUGE_VALF __builtin_huge_valf() +#define HUGE_VALL __builtin_huge_vall() +#define INFINITY __builtin_inff() +#define NAN __builtin_nanf("") +#else +#define HUGE_VALF (float)HUGE_VAL +#define HUGE_VALL (long double)HUGE_VAL +#define INFINITY HUGE_VALF +#define NAN (__nan.__uf) +#endif /* __MATH_BUILTIN_CONSTANTS */ + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling MATH_ERREXCEPT + +#define FP_FAST_FMAF 1 +#ifdef __ia64__ +#define FP_FAST_FMA 1 +#define FP_FAST_FMAL 1 +#endif + +/* Symbolic constants to classify floating point numbers. */ +#define FP_INFINITE 0x01 +#define FP_NAN 0x02 +#define FP_NORMAL 0x04 +#define FP_SUBNORMAL 0x08 +#define FP_ZERO 0x10 +#define fpclassify(x) \ + ((sizeof (x) == sizeof (float)) ? __fpclassifyf(x) \ + : (sizeof (x) == sizeof (double)) ? __fpclassifyd(x) \ + : __fpclassifyl(x)) + +#define isfinite(x) \ + ((sizeof (x) == sizeof (float)) ? __isfinitef(x) \ + : (sizeof (x) == sizeof (double)) ? __isfinite(x) \ + : __isfinitel(x)) +#define isinf(x) \ + ((sizeof (x) == sizeof (float)) ? __isinff(x) \ + : (sizeof (x) == sizeof (double)) ? isinf(x) \ + : __isinfl(x)) +#define isnan(x) \ + ((sizeof (x) == sizeof (float)) ? __isnanf(x) \ + : (sizeof (x) == sizeof (double)) ? isnan(x) \ + : __isnanl(x)) +#define isnormal(x) \ + ((sizeof (x) == sizeof (float)) ? __isnormalf(x) \ + : (sizeof (x) == sizeof (double)) ? __isnormal(x) \ + : __isnormall(x)) + +#ifdef __MATH_BUILTIN_RELOPS +#define isgreater(x, y) __builtin_isgreater((x), (y)) +#define isgreaterequal(x, y) __builtin_isgreaterequal((x), (y)) +#define isless(x, y) __builtin_isless((x), (y)) +#define islessequal(x, y) __builtin_islessequal((x), (y)) +#define islessgreater(x, y) __builtin_islessgreater((x), (y)) +#define isunordered(x, y) __builtin_isunordered((x), (y)) +#else +#define isgreater(x, y) (!isunordered((x), (y)) && (x) > (y)) +#define isgreaterequal(x, y) (!isunordered((x), (y)) && (x) >= (y)) +#define isless(x, y) (!isunordered((x), (y)) && (x) < (y)) +#define islessequal(x, y) (!isunordered((x), (y)) && (x) <= (y)) +#define islessgreater(x, y) (!isunordered((x), (y)) && \ + ((x) > (y) || (y) > (x))) +#define isunordered(x, y) (isnan(x) || isnan(y)) +#endif /* __MATH_BUILTIN_RELOPS */ + +#define signbit(x) \ + ((sizeof (x) == sizeof (float)) ? __signbitf(x) \ + : (sizeof (x) == sizeof (double)) ? __signbit(x) \ + : __signbitl(x)) + +typedef double __double_t; +typedef __double_t double_t; +typedef float __float_t; +typedef __float_t float_t; +#endif /* __ISO_C_VISIBLE >= 1999 */ + +/* + * XOPEN/SVID + */ +#if __BSD_VISIBLE || __XSI_VISIBLE +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log 2e */ +#define M_LOG10E 0.43429448190325182765 /* log 10e */ +#define M_LN2 0.69314718055994530942 /* log e2 */ +#define M_LN10 2.30258509299404568402 /* log e10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +#define MAXFLOAT ((float)3.40282346638528860e+38) +extern int signgam; +#endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +#if __BSD_VISIBLE +#if 0 +/* Old value from 4.4BSD-Lite math.h; this is probably better. */ +#define HUGE HUGE_VAL +#else +#define HUGE MAXFLOAT +#endif +#endif /* __BSD_VISIBLE */ + +/* + * Most of these functions depend on the rounding mode and have the side + * effect of raising floating-point exceptions, so they are not declared + * as __pure2. In C99, FENV_ACCESS affects the purity of these functions. + */ + +/* + * ANSI/POSIX + */ +int __fpclassifyd(double) __pure2; +int __fpclassifyf(float) __pure2; +int __fpclassifyl(long double) __pure2; +int __isfinitef(float) __pure2; +int __isfinite(double) __pure2; +int __isfinitel(long double) __pure2; +int __isinff(float) __pure2; +int __isinfl(long double) __pure2; +int __isnanf(float) __pure2; +int __isnanl(long double) __pure2; +int __isnormalf(float) __pure2; +int __isnormal(double) __pure2; +int __isnormall(long double) __pure2; +int __signbit(double) __pure2; +int __signbitf(float) __pure2; +int __signbitl(long double) __pure2; + +double acos(double); +double asin(double); +double atan(double); +double atan2(double, double); +double cos(double); +double sin(double); +double tan(double); + +double cosh(double); +double sinh(double); +double tanh(double); + +double exp(double); +double frexp(double, int *); /* fundamentally !__pure2 */ +double ldexp(double, int); +double log(double); +double log10(double); +double modf(double, double *); /* fundamentally !__pure2 */ + +double pow(double, double); +double sqrt(double); + +double ceil(double); +double fabs(double) __pure2; +double floor(double); +double fmod(double, double); + +/* + * These functions are not in C90. + */ +#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE +double acosh(double); +double asinh(double); +double atanh(double); +double cbrt(double); +double erf(double); +double erfc(double); +double exp2(double); +double expm1(double); +double fma(double, double, double); +double hypot(double, double); +int ilogb(double) __pure2; +int (isinf)(double) __pure2; +int (isnan)(double) __pure2; +double lgamma(double); +long long llrint(double); +long long llround(double); +double log1p(double); +double log2(double); +double logb(double); +long lrint(double); +long lround(double); +double nan(const char *) __pure2; +double nextafter(double, double); +double remainder(double, double); +double remquo(double, double, int *); +double rint(double); +#endif /* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE */ + +#if __BSD_VISIBLE || __XSI_VISIBLE +double j0(double); +double j1(double); +double jn(int, double); +double y0(double); +double y1(double); +double yn(int, double); + +#if __XSI_VISIBLE <= 500 || __BSD_VISIBLE +double gamma(double); +#endif + +#if __XSI_VISIBLE <= 600 || __BSD_VISIBLE +double scalb(double, double); +#endif +#endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 +double copysign(double, double) __pure2; +double fdim(double, double); +double fmax(double, double) __pure2; +double fmin(double, double) __pure2; +double nearbyint(double); +double round(double); +double scalbln(double, long); +double scalbn(double, int); +double tgamma(double); +double trunc(double); +#endif + +/* + * BSD math library entry points + */ +#if __BSD_VISIBLE +double drem(double, double); +int finite(double) __pure2; +int isnanf(float) __pure2; +long double significandl(long double); + +/* + * Reentrant version of gamma & lgamma; passes signgam back by reference + * as the second argument; user must allocate space for signgam. + */ +double gamma_r(double, int *); +double lgamma_r(double, int *); + +/* + * IEEE Test Vector + */ +double significand(double); +#endif /* __BSD_VISIBLE */ + +/* float versions of ANSI/POSIX functions */ +#if __ISO_C_VISIBLE >= 1999 +float acosf(float); +float asinf(float); +float atanf(float); +float atan2f(float, float); +float cosf(float); +float sinf(float); +float tanf(float); + +float coshf(float); +float sinhf(float); +float tanhf(float); + +float exp2f(float); +float expf(float); +float expm1f(float); +float frexpf(float, int *); /* fundamentally !__pure2 */ +int ilogbf(float) __pure2; +float ldexpf(float, int); +float log10f(float); +float log1pf(float); +float log2f(float); +float logf(float); +float modff(float, float *); /* fundamentally !__pure2 */ + +float powf(float, float); +float sqrtf(float); + +float ceilf(float); +float fabsf(float) __pure2; +float floorf(float); +float fmodf(float, float); +float roundf(float); + +float erff(float); +float erfcf(float); +float hypotf(float, float); +float lgammaf(float); +float tgammaf(float); + +float acoshf(float); +float asinhf(float); +float atanhf(float); +float cbrtf(float); +float logbf(float); +float copysignf(float, float) __pure2; +long long llrintf(float); +long long llroundf(float); +long lrintf(float); +long lroundf(float); +float nanf(const char *) __pure2; +float nearbyintf(float); +float nextafterf(float, float); +float remainderf(float, float); +float remquof(float, float, int *); +float rintf(float); +float scalblnf(float, long); +float scalbnf(float, int); +float truncf(float); + +float fdimf(float, float); +float fmaf(float, float, float); +float fmaxf(float, float) __pure2; +float fminf(float, float) __pure2; +#endif + +/* + * float versions of BSD math library entry points + */ +#if __BSD_VISIBLE +float dremf(float, float); +int finitef(float) __pure2; +float gammaf(float); +float j0f(float); +float j1f(float); +float jnf(int, float); +float scalbf(float, float); +float y0f(float); +float y1f(float); +float ynf(int, float); + +/* + * Float versions of reentrant version of gamma & lgamma; passes + * signgam back by reference as the second argument; user must + * allocate space for signgam. + */ +float gammaf_r(float, int *); +float lgammaf_r(float, int *); + +/* + * float version of IEEE Test Vector + */ +float significandf(float); +#endif /* __BSD_VISIBLE */ + +/* + * long double versions of ISO/POSIX math functions + */ +#if __ISO_C_VISIBLE >= 1999 +long double acoshl(long double); +long double acosl(long double); +long double asinhl(long double); +long double asinl(long double); +long double atan2l(long double, long double); +long double atanhl(long double); +long double atanl(long double); +long double cbrtl(long double); +long double ceill(long double); +long double copysignl(long double, long double) __pure2; +long double coshl(long double); +long double cosl(long double); +long double erfcl(long double); +long double erfl(long double); +long double exp2l(long double); +long double expl(long double); +long double expm1l(long double); +long double fabsl(long double) __pure2; +long double fdiml(long double, long double); +long double floorl(long double); +long double fmal(long double, long double, long double); +long double fmaxl(long double, long double) __pure2; +long double fminl(long double, long double) __pure2; +long double fmodl(long double, long double); +long double frexpl(long double value, int *); /* fundamentally !__pure2 */ +long double hypotl(long double, long double); +int ilogbl(long double) __pure2; +long double ldexpl(long double, int); +long double lgammal(long double); +long long llrintl(long double); +long long llroundl(long double); +long double log10l(long double); +long double log1pl(long double); +long double log2l(long double); +long double logbl(long double); +long double logl(long double); +long lrintl(long double); +long lroundl(long double); +long double modfl(long double, long double *); /* fundamentally !__pure2 */ +long double nanl(const char *) __pure2; +long double nearbyintl(long double); +long double nextafterl(long double, long double); +double nexttoward(double, long double); +float nexttowardf(float, long double); +long double nexttowardl(long double, long double); +long double powl(long double, long double); +long double remainderl(long double, long double); +long double remquol(long double, long double, int *); +long double rintl(long double); +long double roundl(long double); +long double scalblnl(long double, long); +long double scalbnl(long double, int); +long double sinhl(long double); +long double sinl(long double); +long double sqrtl(long double); +long double tanhl(long double); +long double tanl(long double); +long double tgammal(long double); +long double truncl(long double); + +#endif /* __ISO_C_VISIBLE >= 1999 */ + +#if defined(_GNU_SOURCE) +void sincos(double, double*, double*); +void sincosf(float, float*, float*); +void sincosl(long double, long double*, long double*); +#endif /* _GNU_SOURCE */ + +#pragma GCC visibility pop +__END_DECLS + +#endif /* !_MATH_H_ */ diff --git a/third_party/lib/libm/include/sys/cdefs.h b/third_party/lib/libm/include/sys/cdefs.h new file mode 100644 index 000000000..4681e7c69 --- /dev/null +++ b/third_party/lib/libm/include/sys/cdefs.h @@ -0,0 +1,144 @@ +/* $NetBSD: cdefs.h,v 1.58 2004/12/11 05:59:00 christos Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Berkeley Software Design, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 + */ + +/* + * This is a minimum version of cdefs.h for LK, this might be + * modified if necessary + */ +#ifndef _SYS_CDEFS_H_ +#define _SYS_CDEFS_H_ + +/*- + * Deal with _ANSI_SOURCE: + * If it is defined, and no other compilation environment is explicitly + * requested, then define our internal feature-test macros to zero. This + * makes no difference to the preprocessor (undefined symbols in preprocessing + * expressions are defined to have value zero), but makes it more convenient for + * a test program to print out the values. + * + * If a program mistakenly defines _ANSI_SOURCE and some other macro such as + * _POSIX_C_SOURCE, we will assume that it wants the broader compilation + * environment (and in fact we will never get here). + */ +#if defined(_ANSI_SOURCE) /* Hide almost everything. */ +#define __POSIX_VISIBLE 0 +#define __XSI_VISIBLE 0 +#define __BSD_VISIBLE 0 +#define __ISO_C_VISIBLE 1990 +#elif defined(_C99_SOURCE) /* Localism to specify strict C99 env. */ +#define __POSIX_VISIBLE 0 +#define __XSI_VISIBLE 0 +#define __BSD_VISIBLE 0 +#define __ISO_C_VISIBLE 1999 +#else /* Default environment: show everything. */ +#define __POSIX_VISIBLE 200809 +#define __XSI_VISIBLE 700 +#define __BSD_VISIBLE 1 +#define __ISO_C_VISIBLE 1999 +#endif + +/* + * Default values. + */ +#ifndef __XPG_VISIBLE +# define __XPG_VISIBLE 700 +#endif +#ifndef __POSIX_VISIBLE +# define __POSIX_VISIBLE 200809 +#endif +#ifndef __ISO_C_VISIBLE +# define __ISO_C_VISIBLE 1999 +#endif +#ifndef __BSD_VISIBLE +# define __BSD_VISIBLE 1 +#endif + + +/* + * Some of the FreeBSD sources used in Bionic need this. + * Originally, this is used to embed the rcs versions of each source file + * in the generated binary. We certainly don't want this in Bionic. + */ +#define __FBSDID(s) /* nothing */ + +#define __pure2 __attribute__((__const__)) /* Android-added: used by FreeBSD libm */ + +/* + * Macro to test if we're using a GNU C compiler of a specific vintage + * or later, for e.g. features that appeared in a particular version + * of GNU C. Usage: + * + * #if __GNUC_PREREQ__(major, minor) + * ...cool feature... + * #else + * ...delete feature... + * #endif + */ +#ifdef __GNUC__ +#define __GNUC_PREREQ__(x, y) \ + ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ + (__GNUC__ > (x))) +#else +#define __GNUC_PREREQ__(x, y) 0 +#endif + +#if defined(__cplusplus) +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#define __static_cast(x,y) static_cast(y) +#else +#define __BEGIN_DECLS +#define __END_DECLS +#define __static_cast(x,y) (x)y +#endif + +#if defined(__cplusplus) +#define __inline inline /* convert to C++ keyword */ +#else +#if !defined(__GNUC__) && !defined(__lint__) +#define __inline /* delete GCC keyword */ +#endif /* !__GNUC__ && !__lint__ */ +#endif /* !__cplusplus */ + +#if __GNUC_PREREQ__(3, 1) +#define __always_inline __attribute__((__always_inline__)) +#else +#define __always_inline +#endif + + + +#endif /* !_SYS_CDEFS_H_ */ diff --git a/third_party/lib/libm/k_cos.c b/third_party/lib/libm/k_cos.c new file mode 100644 index 000000000..b6412bfea --- /dev/null +++ b/third_party/lib/libm/k_cos.c @@ -0,0 +1,79 @@ + +/* @(#)k_cos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * __kernel_cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "math.h" +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double +__kernel_cos(double x, double y) +{ + double hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = one-hz; + return w + (((one-w)-hz) + (z*r-x*y)); +} diff --git a/third_party/lib/libm/k_cosf.c b/third_party/lib/libm/k_cosf.c new file mode 100644 index 000000000..3126b4776 --- /dev/null +++ b/third_party/lib/libm/k_cosf.c @@ -0,0 +1,46 @@ +/* k_cosf.c -- float version of k_cos.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_COSDF +#include +__FBSDID("$FreeBSD$"); +#endif + +#include "math.h" +#include "math_private.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double +one = 1.0, +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +#ifdef INLINE_KERNEL_COSDF +static __inline +#endif +float +__kernel_cosdf(double x) +{ + double r, w, z; + + /* Try to optimize for parallel evaluation as in k_tanf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((one+z*C0) + w*C1) + (w*z)*r; +} diff --git a/third_party/lib/libm/k_rem_pio2.c b/third_party/lib/libm/k_rem_pio2.c new file mode 100644 index 000000000..03559b48d --- /dev/null +++ b/third_party/lib/libm/k_rem_pio2.c @@ -0,0 +1,457 @@ + +/* @(#)k_rem_pio2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __kernel_rem_pio2 return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] output result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ + + +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +#if LDBL_MAX_EXP > 16384 +#error "ipio2 table needs to be expanded" +#endif + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, + 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, + 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, + 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, + 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, + 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, + 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, + 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, + 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, + 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, + 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, + 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, + 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, + 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, + 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, + 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, + 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, + 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, + 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, + 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, + 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, + 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, + 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, + 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, + 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, + 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, + 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, + 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, + 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, + 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, + 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, + 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, + 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, + 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, + 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif + +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +static const double +zero = 0.0, +one = 1.0, +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +int +__kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; + if (jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; + m = jx+jk; + for (i=0; i<=m; i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)((int32_t)(twon24* z)); + iq[i] = (int32_t)(z-two24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t) z; + z -= (double)n; + ih = 0; + if (q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(24-q0)); + n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } else if (q0==0) ih = iq[jz-1]>>23; + else if (z>=0.5) ih=2; + + if (ih>0) { /* q > 0.5 */ + n += 1; + carry = 0; + for (i=0; i0) { /* rare case: chance is 1 in 12 */ + switch (q0) { + case 1: + iq[jz-1] &= 0x7fffff; + break; + case 2: + iq[jz-1] &= 0x3fffff; + break; + } + } + if (ih==2) { + z = one - z; + if (carry!=0) z -= scalbn(one,q0); + } + } + + /* check if recomputation is needed */ + if (z==zero) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j==0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double) ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z==0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz]==0) { jz--; q0-=24;} + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z>=two24) { + fw = (double)((int32_t)(twon24*z)); + iq[jz] = (int32_t)(z-two24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t) fw; + } else iq[jz] = (int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(one,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw*=twon24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for (i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp&&k<=jz-i; k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch (prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) fw += fq[i]; + STRICT_ASSIGN(double,fw,fw); + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; + } else { + y[0] = -fq[0]; + y[1] = -fq[1]; + y[2] = -fw; + } + } + return n&7; +} diff --git a/third_party/lib/libm/k_sin.c b/third_party/lib/libm/k_sin.c new file mode 100644 index 000000000..8922a0475 --- /dev/null +++ b/third_party/lib/libm/k_sin.c @@ -0,0 +1,70 @@ + +/* @(#)k_sin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* __kernel_sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "math.h" +#include "math_private.h" + +static const double +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double +__kernel_sin(double x, double y, int iy) +{ + double z,r,v,w; + + z = x*x; + w = z*z; + r = S2+z*(S3+z*S4) + z*w*(S5+z*S6); + v = z*x; + if (iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/third_party/lib/libm/k_sinf.c b/third_party/lib/libm/k_sinf.c new file mode 100644 index 000000000..efc318904 --- /dev/null +++ b/third_party/lib/libm/k_sinf.c @@ -0,0 +1,46 @@ +/* k_sinf.c -- float version of k_sin.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_SINDF +#include +__FBSDID("$FreeBSD$"); +#endif + +#include "math.h" +#include "math_private.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +#ifdef INLINE_KERNEL_SINDF +static __inline +#endif +float +__kernel_sindf(double x) +{ + double r, s, w, z; + + /* Try to optimize for parallel evaluation as in k_tanf.c. */ + z = x*x; + w = z*z; + r = S3+z*S4; + s = z*x; + return (x + s*(S1+z*S2)) + s*w*r; +} diff --git a/third_party/lib/libm/k_tan.c b/third_party/lib/libm/k_tan.c new file mode 100644 index 000000000..edb0d4bf5 --- /dev/null +++ b/third_party/lib/libm/k_tan.c @@ -0,0 +1,133 @@ +/* @(#)k_tan.c 1.5 04/04/22 SMI */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* INDENT OFF */ +#include +__FBSDID("$FreeBSD$"); + +/* __kernel_tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "math.h" +#include "math_private.h" +static const double xxx[] = { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ + /* one */ 1.00000000000000000000e+00, /* 3FF00000, 00000000 */ + /* pio4 */ 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ + /* pio4lo */ 3.06161699786838301793e-17 /* 3C81A626, 33145C07 */ +}; +#define one xxx[13] +#define pio4 xxx[14] +#define pio4lo xxx[15] +#define T xxx +/* INDENT ON */ + +double +__kernel_tan(double x, double y, int iy) +{ + double z, r, v, w, s; + int32_t ix, hx; + + GET_HIGH_WORD(hx,x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */ + if (hx < 0) { + x = -x; + y = -y; + } + z = pio4 - x; + w = pio4lo - y; + x = z + w; + y = 0.0; + } + z = x * x; + w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + + w * T[11])))); + v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + + w * T[12]))))); + s = z * x; + r = y + z * (s * (r + v) + y); + r += T[0] * s; + w = x + r; + if (ix >= 0x3FE59428) { + v = (double) iy; + return (double) (1 - ((hx >> 30) & 2)) * + (v - 2.0 * (x - (w * w / (w + v) - r))); + } + if (iy == 1) + return w; + else { + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + double a, t; + z = w; + SET_LOW_WORD(z,0); + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + SET_LOW_WORD(t,0); + s = 1.0 + t * z; + return t + a * (s + t * v); + } +} diff --git a/third_party/lib/libm/k_tanf.c b/third_party/lib/libm/k_tanf.c new file mode 100644 index 000000000..887bd4c20 --- /dev/null +++ b/third_party/lib/libm/k_tanf.c @@ -0,0 +1,66 @@ +/* k_tanf.c -- float version of k_tan.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_TANDF +#include +__FBSDID("$FreeBSD$"); +#endif + +#include "math.h" +#include "math_private.h" + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +static const double +T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ +}; + +#ifdef INLINE_KERNEL_TANDF +static __inline +#endif +float +__kernel_tandf(double x, int iy) +{ + double z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4]+z*T[5]; + t = T[2]+z*T[3]; + w = z*z; + s = z*x; + u = T[0]+z*T[1]; + r = (x+s*u)+(s*w)*(t+w*r); + if (iy==1) return r; + else return -1.0/r; +} diff --git a/third_party/lib/libm/math_private.h b/third_party/lib/libm/math_private.h new file mode 100644 index 000000000..86b1f8563 --- /dev/null +++ b/third_party/lib/libm/math_private.h @@ -0,0 +1,757 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD$ + */ + +#ifndef _MATH_PRIVATE_H_ +#define _MATH_PRIVATE_H_ + +#include +#include + +/* + * The original fdlibm code used statements like: + * n0 = ((*(int*)&one)>>29)^1; * index of high word * + * ix0 = *(n0+(int*)&x); * high word of x * + * ix1 = *((1-n0)+(int*)&x); * low word of x * + * to dig two 32 bit words out of the 64 bit IEEE floating point + * value. That is non-ANSI, and, moreover, the gcc instruction + * scheduler gets it wrong. We instead use the following macros. + * Unlike the original code, we determine the endianness at compile + * time, not at run time; I don't see much benefit to selecting + * endianness at run time. + */ + +/* + * A union which permits us to convert between a double and two 32 bit + * ints. + */ + +#ifdef __arm__ +#if defined(__VFP_FP__) || defined(__ARM_EABI__) +#define IEEE_WORD_ORDER BYTE_ORDER +#else +#define IEEE_WORD_ORDER BIG_ENDIAN +#endif +#else /* __arm__ */ +#define IEEE_WORD_ORDER BYTE_ORDER +#endif + +#if IEEE_WORD_ORDER == BIG_ENDIAN + +typedef union { + double value; + struct { + u_int32_t msw; + u_int32_t lsw; + } parts; + struct { + u_int64_t w; + } xparts; +} ieee_double_shape_type; + +#endif + +#if IEEE_WORD_ORDER == LITTLE_ENDIAN + +typedef union { + double value; + struct { + u_int32_t lsw; + u_int32_t msw; + } parts; + struct { + u_int64_t w; + } xparts; +} ieee_double_shape_type; + +#endif + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0,ix1,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Get a 64-bit int from a double. */ +#define EXTRACT_WORD64(ix,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix) = ew_u.xparts.w; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i,d) \ +do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ + +#define GET_LOW_WORD(i,d) \ +do { \ + ieee_double_shape_type gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,ix0,ix1) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +/* Set a double from a 64-bit int. */ +#define INSERT_WORD64(d,ix) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.xparts.w = (ix); \ + (d) = iw_u.value; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ + +#define SET_HIGH_WORD(d,v) \ +do { \ + ieee_double_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ + +#define SET_LOW_WORD(d,v) \ +do { \ + ieee_double_shape_type sl_u; \ + sl_u.value = (d); \ + sl_u.parts.lsw = (v); \ + (d) = sl_u.value; \ +} while (0) + +/* + * A union which permits us to convert between a float and a 32 bit + * int. + */ + +typedef union { + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + +/* + * Get expsign and mantissa as 16 bit and 64 bit ints from an 80 bit long + * double. + */ + +#define EXTRACT_LDBL80_WORDS(ix0,ix1,d) \ +do { \ + union IEEEl2bits ew_u; \ + ew_u.e = (d); \ + (ix0) = ew_u.xbits.expsign; \ + (ix1) = ew_u.xbits.man; \ +} while (0) + +/* + * Get expsign and mantissa as one 16 bit and two 64 bit ints from a 128 bit + * long double. + */ + +#define EXTRACT_LDBL128_WORDS(ix0,ix1,ix2,d) \ +do { \ + union IEEEl2bits ew_u; \ + ew_u.e = (d); \ + (ix0) = ew_u.xbits.expsign; \ + (ix1) = ew_u.xbits.manh; \ + (ix2) = ew_u.xbits.manl; \ +} while (0) + +/* Get expsign as a 16 bit int from a long double. */ + +#define GET_LDBL_EXPSIGN(i,d) \ +do { \ + union IEEEl2bits ge_u; \ + ge_u.e = (d); \ + (i) = ge_u.xbits.expsign; \ +} while (0) + +/* + * Set an 80 bit long double from a 16 bit int expsign and a 64 bit int + * mantissa. + */ + +#define INSERT_LDBL80_WORDS(d,ix0,ix1) \ +do { \ + union IEEEl2bits iw_u; \ + iw_u.xbits.expsign = (ix0); \ + iw_u.xbits.man = (ix1); \ + (d) = iw_u.e; \ +} while (0) + +/* + * Set a 128 bit long double from a 16 bit int expsign and two 64 bit ints + * comprising the mantissa. + */ + +#define INSERT_LDBL128_WORDS(d,ix0,ix1,ix2) \ +do { \ + union IEEEl2bits iw_u; \ + iw_u.xbits.expsign = (ix0); \ + iw_u.xbits.manh = (ix1); \ + iw_u.xbits.manl = (ix2); \ + (d) = iw_u.e; \ +} while (0) + +/* Set expsign of a long double from a 16 bit int. */ + +#define SET_LDBL_EXPSIGN(d,v) \ +do { \ + union IEEEl2bits se_u; \ + se_u.e = (d); \ + se_u.xbits.expsign = (v); \ + (d) = se_u.e; \ +} while (0) + +#ifdef __i386__ +/* Long double constants are broken on i386. */ +#define LD80C(m, ex, v) { \ + .xbits.man = __CONCAT(m, ULL), \ + .xbits.expsign = (0x3fff + (ex)) | ((v) < 0 ? 0x8000 : 0), \ +} +#else +/* The above works on non-i386 too, but we use this to check v. */ +#define LD80C(m, ex, v) { .e = (v), } +#endif + +#ifdef FLT_EVAL_METHOD +/* + * Attempt to get strict C99 semantics for assignment with non-C99 compilers. + */ +#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0 +#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval)) +#else +#define STRICT_ASSIGN(type, lval, rval) do { \ + volatile type __lval; \ + \ + if (sizeof(type) >= sizeof(long double)) \ + (lval) = (rval); \ + else { \ + __lval = (rval); \ + (lval) = __lval; \ + } \ +} while (0) +#endif +#endif /* FLT_EVAL_METHOD */ + +/* Support switching the mode to FP_PE if necessary. */ +#if defined(__i386__) && !defined(NO_FPSETPREC) +#define ENTERI() \ + long double __retval; \ + fp_prec_t __oprec; \ + \ + if ((__oprec = fpgetprec()) != FP_PE) \ + fpsetprec(FP_PE) +#define RETURNI(x) do { \ + __retval = (x); \ + if (__oprec != FP_PE) \ + fpsetprec(__oprec); \ + RETURNF(__retval); \ +} while (0) +#else +#define ENTERI(x) +#define RETURNI(x) RETURNF(x) +#endif + +/* Default return statement if hack*_t() is not used. */ +#define RETURNF(v) return (v) + +/* + * 2sum gives the same result as 2sumF without requiring |a| >= |b| or + * a == 0, but is slower. + */ +#define _2sum(a, b) do { \ + __typeof(a) __s, __w; \ + \ + __w = (a) + (b); \ + __s = __w - (a); \ + (b) = ((a) - (__w - __s)) + ((b) - __s); \ + (a) = __w; \ +} while (0) + +/* + * 2sumF algorithm. + * + * "Normalize" the terms in the infinite-precision expression a + b for + * the sum of 2 floating point values so that b is as small as possible + * relative to 'a'. (The resulting 'a' is the value of the expression in + * the same precision as 'a' and the resulting b is the rounding error.) + * |a| must be >= |b| or 0, b's type must be no larger than 'a's type, and + * exponent overflow or underflow must not occur. This uses a Theorem of + * Dekker (1971). See Knuth (1981) 4.2.2 Theorem C. The name "TwoSum" + * is apparently due to Skewchuk (1997). + * + * For this to always work, assignment of a + b to 'a' must not retain any + * extra precision in a + b. This is required by C standards but broken + * in many compilers. The brokenness cannot be worked around using + * STRICT_ASSIGN() like we do elsewhere, since the efficiency of this + * algorithm would be destroyed by non-null strict assignments. (The + * compilers are correct to be broken -- the efficiency of all floating + * point code calculations would be destroyed similarly if they forced the + * conversions.) + * + * Fortunately, a case that works well can usually be arranged by building + * any extra precision into the type of 'a' -- 'a' should have type float_t, + * double_t or long double. b's type should be no larger than 'a's type. + * Callers should use these types with scopes as large as possible, to + * reduce their own extra-precision and efficiciency problems. In + * particular, they shouldn't convert back and forth just to call here. + */ +#ifdef DEBUG +#define _2sumF(a, b) do { \ + __typeof(a) __w; \ + volatile __typeof(a) __ia, __ib, __r, __vw; \ + \ + __ia = (a); \ + __ib = (b); \ + assert(__ia == 0 || fabsl(__ia) >= fabsl(__ib)); \ + \ + __w = (a) + (b); \ + (b) = ((a) - __w) + (b); \ + (a) = __w; \ + \ + /* The next 2 assertions are weak if (a) is already long double. */ \ + assert((long double)__ia + __ib == (long double)(a) + (b)); \ + __vw = __ia + __ib; \ + __r = __ia - __vw; \ + __r += __ib; \ + assert(__vw == (a) && __r == (b)); \ +} while (0) +#else /* !DEBUG */ +#define _2sumF(a, b) do { \ + __typeof(a) __w; \ + \ + __w = (a) + (b); \ + (b) = ((a) - __w) + (b); \ + (a) = __w; \ +} while (0) +#endif /* DEBUG */ + +/* + * Set x += c, where x is represented in extra precision as a + b. + * x must be sufficiently normalized and sufficiently larger than c, + * and the result is then sufficiently normalized. + * + * The details of ordering are that |a| must be >= |c| (so that (a, c) + * can be normalized without extra work to swap 'a' with c). The details of + * the normalization are that b must be small relative to the normalized 'a'. + * Normalization of (a, c) makes the normalized c tiny relative to the + * normalized a, so b remains small relative to 'a' in the result. However, + * b need not ever be tiny relative to 'a'. For example, b might be about + * 2**20 times smaller than 'a' to give about 20 extra bits of precision. + * That is usually enough, and adding c (which by normalization is about + * 2**53 times smaller than a) cannot change b significantly. However, + * cancellation of 'a' with c in normalization of (a, c) may reduce 'a' + * significantly relative to b. The caller must ensure that significant + * cancellation doesn't occur, either by having c of the same sign as 'a', + * or by having |c| a few percent smaller than |a|. Pre-normalization of + * (a, b) may help. + * + * This is is a variant of an algorithm of Kahan (see Knuth (1981) 4.2.2 + * exercise 19). We gain considerable efficiency by requiring the terms to + * be sufficiently normalized and sufficiently increasing. + */ +#define _3sumF(a, b, c) do { \ + __typeof(a) __tmp; \ + \ + __tmp = (c); \ + _2sumF(__tmp, (a)); \ + (b) += (a); \ + (a) = __tmp; \ +} while (0) + +/* + * Common routine to process the arguments to nan(), nanf(), and nanl(). + */ +void _scan_nan(uint32_t *__words, int __num_words, const char *__s); + +#ifdef _COMPLEX_H + +/* + * C99 specifies that complex numbers have the same representation as + * an array of two elements, where the first element is the real part + * and the second element is the imaginary part. + */ +typedef union { + float complex f; + float a[2]; +} float_complex; +typedef union { + double complex f; + double a[2]; +} double_complex; +typedef union { + long double complex f; + long double a[2]; +} long_double_complex; +#define REALPART(z) ((z).a[0]) +#define IMAGPART(z) ((z).a[1]) + +/* + * Inline functions that can be used to construct complex values. + * + * The C99 standard intends x+I*y to be used for this, but x+I*y is + * currently unusable in general since gcc introduces many overflow, + * underflow, sign and efficiency bugs by rewriting I*y as + * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product. + * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted + * to -0.0+I*0.0. + */ +static __inline float complex +cpackf(float x, float y) +{ + float_complex z; + + REALPART(z) = x; + IMAGPART(z) = y; + return (z.f); +} + +static __inline double complex +cpack(double x, double y) +{ + double_complex z; + + REALPART(z) = x; + IMAGPART(z) = y; + return (z.f); +} + +static __inline long double complex +cpackl(long double x, long double y) +{ + long_double_complex z; + + REALPART(z) = x; + IMAGPART(z) = y; + return (z.f); +} +#endif /* _COMPLEX_H */ + +#ifdef __GNUCLIKE_ASM + +/* Asm versions of some functions. */ + +#ifdef __amd64__ +static __inline int +irint(double x) +{ + int n; + + asm("cvtsd2si %1,%0" : "=r" (n) : "x" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINT +#endif + +#ifdef __i386__ +static __inline int +irint(double x) +{ + int n; + + asm("fistl %0" : "=m" (n) : "t" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINT +#endif + +#if defined(__amd64__) || defined(__i386__) +static __inline int +irintl(long double x) +{ + int n; + + asm("fistl %0" : "=m" (n) : "t" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINTL +#endif + +#endif /* __GNUCLIKE_ASM */ + +#ifdef DEBUG +#if defined(__amd64__) || defined(__i386__) +#define breakpoint() asm("int $3") +#else +#include + +#define breakpoint() raise(SIGTRAP) +#endif +#endif + +/* Write a pari script to test things externally. */ +#ifdef DOPRINT +#include + +#ifndef DOPRINT_SWIZZLE +#define DOPRINT_SWIZZLE 0 +#endif + +#ifdef DOPRINT_LD80 + +#define DOPRINT_START(xp) do { \ + uint64_t __lx; \ + uint16_t __hx; \ + \ + /* Hack to give more-problematic args. */ \ + EXTRACT_LDBL80_WORDS(__hx, __lx, *xp); \ + __lx ^= DOPRINT_SWIZZLE; \ + INSERT_LDBL80_WORDS(*xp, __hx, __lx); \ + printf("x = %.21Lg; ", (long double)*xp); \ +} while (0) +#define DOPRINT_END1(v) \ + printf("y = %.21Lg; z = 0; show(x, y, z);\n", (long double)(v)) +#define DOPRINT_END2(hi, lo) \ + printf("y = %.21Lg; z = %.21Lg; show(x, y, z);\n", \ + (long double)(hi), (long double)(lo)) + +#elif defined(DOPRINT_D64) + +#define DOPRINT_START(xp) do { \ + uint32_t __hx, __lx; \ + \ + EXTRACT_WORDS(__hx, __lx, *xp); \ + __lx ^= DOPRINT_SWIZZLE; \ + INSERT_WORDS(*xp, __hx, __lx); \ + printf("x = %.21Lg; ", (long double)*xp); \ +} while (0) +#define DOPRINT_END1(v) \ + printf("y = %.21Lg; z = 0; show(x, y, z);\n", (long double)(v)) +#define DOPRINT_END2(hi, lo) \ + printf("y = %.21Lg; z = %.21Lg; show(x, y, z);\n", \ + (long double)(hi), (long double)(lo)) + +#elif defined(DOPRINT_F32) + +#define DOPRINT_START(xp) do { \ + uint32_t __hx; \ + \ + GET_FLOAT_WORD(__hx, *xp); \ + __hx ^= DOPRINT_SWIZZLE; \ + SET_FLOAT_WORD(*xp, __hx); \ + printf("x = %.21Lg; ", (long double)*xp); \ +} while (0) +#define DOPRINT_END1(v) \ + printf("y = %.21Lg; z = 0; show(x, y, z);\n", (long double)(v)) +#define DOPRINT_END2(hi, lo) \ + printf("y = %.21Lg; z = %.21Lg; show(x, y, z);\n", \ + (long double)(hi), (long double)(lo)) + +#else /* !DOPRINT_LD80 && !DOPRINT_D64 (LD128 only) */ + +#ifndef DOPRINT_SWIZZLE_HIGH +#define DOPRINT_SWIZZLE_HIGH 0 +#endif + +#define DOPRINT_START(xp) do { \ + uint64_t __lx, __llx; \ + uint16_t __hx; \ + \ + EXTRACT_LDBL128_WORDS(__hx, __lx, __llx, *xp); \ + __llx ^= DOPRINT_SWIZZLE; \ + __lx ^= DOPRINT_SWIZZLE_HIGH; \ + INSERT_LDBL128_WORDS(*xp, __hx, __lx, __llx); \ + printf("x = %.36Lg; ", (long double)*xp); \ +} while (0) +#define DOPRINT_END1(v) \ + printf("y = %.36Lg; z = 0; show(x, y, z);\n", (long double)(v)) +#define DOPRINT_END2(hi, lo) \ + printf("y = %.36Lg; z = %.36Lg; show(x, y, z);\n", \ + (long double)(hi), (long double)(lo)) + +#endif /* DOPRINT_LD80 */ + +#else /* !DOPRINT */ +#define DOPRINT_START(xp) +#define DOPRINT_END1(v) +#define DOPRINT_END2(hi, lo) +#endif /* DOPRINT */ + +#define RETURNP(x) do { \ + DOPRINT_END1(x); \ + RETURNF(x); \ +} while (0) +#define RETURNPI(x) do { \ + DOPRINT_END1(x); \ + RETURNI(x); \ +} while (0) +#define RETURN2P(x, y) do { \ + DOPRINT_END2((x), (y)); \ + RETURNF((x) + (y)); \ +} while (0) +#define RETURN2PI(x, y) do { \ + DOPRINT_END2((x), (y)); \ + RETURNI((x) + (y)); \ +} while (0) +#ifdef STRUCT_RETURN +#define RETURNSP(rp) do { \ + if (!(rp)->lo_set) \ + RETURNP((rp)->hi); \ + RETURN2P((rp)->hi, (rp)->lo); \ +} while (0) +#define RETURNSPI(rp) do { \ + if (!(rp)->lo_set) \ + RETURNPI((rp)->hi); \ + RETURN2PI((rp)->hi, (rp)->lo); \ +} while (0) +#endif +#define SUM2P(x, y) ({ \ + const __typeof (x) __x = (x); \ + const __typeof (y) __y = (y); \ + \ + DOPRINT_END2(__x, __y); \ + __x + __y; \ +}) + +/* + * ieee style elementary functions + * + * We rename functions here to improve other sources' diffability + * against fdlibm. + */ +#define __ieee754_sqrt sqrt +#define __ieee754_acos acos +#define __ieee754_acosh acosh +#define __ieee754_log log +#define __ieee754_log2 log2 +#define __ieee754_atanh atanh +#define __ieee754_asin asin +#define __ieee754_atan2 atan2 +#define __ieee754_exp exp +#define __ieee754_cosh cosh +#define __ieee754_fmod fmod +#define __ieee754_pow pow +#define __ieee754_lgamma lgamma +#define __ieee754_gamma gamma +#define __ieee754_lgamma_r lgamma_r +#define __ieee754_gamma_r gamma_r +#define __ieee754_log10 log10 +#define __ieee754_sinh sinh +#define __ieee754_hypot hypot +#define __ieee754_j0 j0 +#define __ieee754_j1 j1 +#define __ieee754_y0 y0 +#define __ieee754_y1 y1 +#define __ieee754_jn jn +#define __ieee754_yn yn +#define __ieee754_remainder remainder +#define __ieee754_scalb scalb +#define __ieee754_sqrtf sqrtf +#define __ieee754_acosf acosf +#define __ieee754_acoshf acoshf +#define __ieee754_logf logf +#define __ieee754_atanhf atanhf +#define __ieee754_asinf asinf +#define __ieee754_atan2f atan2f +#define __ieee754_expf expf +#define __ieee754_coshf coshf +#define __ieee754_fmodf fmodf +#define __ieee754_powf powf +#define __ieee754_lgammaf lgammaf +#define __ieee754_gammaf gammaf +#define __ieee754_lgammaf_r lgammaf_r +#define __ieee754_gammaf_r gammaf_r +#define __ieee754_log10f log10f +#define __ieee754_log2f log2f +#define __ieee754_sinhf sinhf +#define __ieee754_hypotf hypotf +#define __ieee754_j0f j0f +#define __ieee754_j1f j1f +#define __ieee754_y0f y0f +#define __ieee754_y1f y1f +#define __ieee754_jnf jnf +#define __ieee754_ynf ynf +#define __ieee754_remainderf remainderf +#define __ieee754_scalbf scalbf + +/* fdlibm kernel function */ +int __kernel_rem_pio2(double*,double*,int,int,int); + +/* double precision kernel functions */ +#ifndef INLINE_REM_PIO2 +int __ieee754_rem_pio2(double,double*); +#endif +double __kernel_sin(double,double,int); +double __kernel_cos(double,double); +double __kernel_tan(double,double,int); +double __ldexp_exp(double,int); +#ifdef _COMPLEX_H +double complex __ldexp_cexp(double complex,int); +#endif + +/* float precision kernel functions */ +#ifndef INLINE_REM_PIO2F +int __ieee754_rem_pio2f(float,double*); +#endif +#ifndef INLINE_KERNEL_SINDF +float __kernel_sindf(double); +#endif +#ifndef INLINE_KERNEL_COSDF +float __kernel_cosdf(double); +#endif +#ifndef INLINE_KERNEL_TANDF +float __kernel_tandf(double,int); +#endif +float __ldexp_expf(float,int); +#ifdef _COMPLEX_H +float complex __ldexp_cexpf(float complex,int); +#endif + +/* long double precision kernel functions */ +long double __kernel_sinl(long double, long double, int); +long double __kernel_cosl(long double, long double); +long double __kernel_tanl(long double, long double, int); + +#endif /* !_MATH_PRIVATE_H_ */ diff --git a/third_party/lib/libm/rules.mk b/third_party/lib/libm/rules.mk new file mode 100644 index 000000000..9e0914d09 --- /dev/null +++ b/third_party/lib/libm/rules.mk @@ -0,0 +1,44 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_CFLAGS += -Wno-unused-variable -Wno-sign-compare -Wno-parentheses + +MODULE_SRCS += \ + $(LOCAL_DIR)/k_sin.c \ + $(LOCAL_DIR)/s_sin.c \ + $(LOCAL_DIR)/s_sinf.c \ + $(LOCAL_DIR)/k_cos.c \ + $(LOCAL_DIR)/s_cos.c \ + $(LOCAL_DIR)/s_cosf.c \ + $(LOCAL_DIR)/k_tan.c \ + $(LOCAL_DIR)/s_tan.c \ + $(LOCAL_DIR)/s_tanf.c \ + $(LOCAL_DIR)/e_sqrt.c \ + $(LOCAL_DIR)/e_sqrtf.c \ + $(LOCAL_DIR)/k_rem_pio2.c \ + $(LOCAL_DIR)/s_floor.c \ + $(LOCAL_DIR)/s_floorf.c \ + $(LOCAL_DIR)/s_scalbn.c \ + $(LOCAL_DIR)/s_scalbnf.c \ + $(LOCAL_DIR)/s_copysign.c \ + $(LOCAL_DIR)/s_copysignf.c \ + $(LOCAL_DIR)/e_acos.c \ + $(LOCAL_DIR)/e_acosf.c \ + $(LOCAL_DIR)/e_asin.c \ + $(LOCAL_DIR)/e_asinf.c \ + $(LOCAL_DIR)/e_pow.c \ + $(LOCAL_DIR)/e_powf.c \ + $(LOCAL_DIR)/s_fabs.c \ + $(LOCAL_DIR)/s_fabsf.c \ + $(LOCAL_DIR)/e_fmod.c \ + $(LOCAL_DIR)/e_log.c \ + $(LOCAL_DIR)/e_exp.c \ + $(LOCAL_DIR)/s_round.c \ + $(LOCAL_DIR)/s_ceil.c \ + $(LOCAL_DIR)/s_ceilf.c \ + $(LOCAL_DIR)/s_trunc.c \ + $(LOCAL_DIR)/s_atan.c \ + $(LOCAL_DIR)/e_atan2.c \ + +include make/module.mk diff --git a/third_party/lib/libm/s_atan.c b/third_party/lib/libm/s_atan.c new file mode 100644 index 000000000..ed6b5c36b --- /dev/null +++ b/third_party/lib/libm/s_atan.c @@ -0,0 +1,126 @@ +/* @(#)s_atan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + + static const double +one = 1.0, +huge = 1.0e300; + +double +atan(double x) +{ + double w,s1,s2,z; + int32_t ix,hx,id; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x44100000) { /* if |x| >= 2^66 */ + u_int32_t low; + GET_LOW_WORD(low,x); + if(ix>0x7ff00000|| + (ix==0x7ff00000&&(low!=0))) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+*(volatile double *)&atanlo[3]; + else return -atanhi[3]-*(volatile double *)&atanlo[3]; + } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */ + id = 0; x = (2.0*x-one)/(2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; x = (x-1.5)/(one+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; x = -1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (hx<0)? -z:z; + } +} + +#if SUPPORT_LONG_DOUBLE +#if LDBL_MANT_DIG == 53 +__weak_reference(atan, atanl); +#endif +#endif diff --git a/third_party/lib/libm/s_ceil.c b/third_party/lib/libm/s_ceil.c new file mode 100644 index 000000000..c8933c64d --- /dev/null +++ b/third_party/lib/libm/s_ceil.c @@ -0,0 +1,80 @@ +/* @(#)s_ceil.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * ceil(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceil(x). + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const double huge = 1.0e300; + +double +ceil(double x) +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;i1=0;} + else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) { + if(j0==20) i0+=1; + else { + j = i1 + (1<<(52-j0)); + if(j +__FBSDID("$FreeBSD$"); + +#include "math.h" +#include "math_private.h" + +static const float huge = 1.0e30; + +float +ceilf(float x) +{ + int32_t i0,j0; + u_int32_t i; + + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;} + else if(i0!=0) { i0=0x3f800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/third_party/lib/libm/s_copysign.c b/third_party/lib/libm/s_copysign.c new file mode 100644 index 000000000..ac28b5c9f --- /dev/null +++ b/third_party/lib/libm/s_copysign.c @@ -0,0 +1,33 @@ +/* @(#)s_copysign.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * copysign(double x, double y) + * copysign(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include "math.h" +#include "math_private.h" + +double +copysign(double x, double y) +{ + u_int32_t hx,hy; + GET_HIGH_WORD(hx,x); + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000)); + return x; +} diff --git a/third_party/lib/libm/s_copysignf.c b/third_party/lib/libm/s_copysignf.c new file mode 100644 index 000000000..346257bd1 --- /dev/null +++ b/third_party/lib/libm/s_copysignf.c @@ -0,0 +1,35 @@ +/* s_copysignf.c -- float version of s_copysign.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +/* + * copysignf(float x, float y) + * copysignf(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include "math.h" +#include "math_private.h" + +float +copysignf(float x, float y) +{ + u_int32_t ix,iy; + GET_FLOAT_WORD(ix,x); + GET_FLOAT_WORD(iy,y); + SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000)); + return x; +} diff --git a/third_party/lib/libm/s_cos.c b/third_party/lib/libm/s_cos.c new file mode 100644 index 000000000..b71438b27 --- /dev/null +++ b/third_party/lib/libm/s_cos.c @@ -0,0 +1,93 @@ +/* @(#)s_cos.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cosine function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include + +#include "math.h" +#define INLINE_REM_PIO2 +#include "math_private.h" +#include "e_rem_pio2.c" + +double +cos(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if (ix <= 0x3fe921fb) { + if (ix<0x3e46a09e) /* if x < 2**-27 * sqrt(2) */ + if (((int)x)==0) return 1.0; /* generate inexact */ + return __kernel_cos(x,z); + } + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch (n&3) { + case 0: + return __kernel_cos(y[0],y[1]); + case 1: + return -__kernel_sin(y[0],y[1],1); + case 2: + return -__kernel_cos(y[0],y[1]); + default: + return __kernel_sin(y[0],y[1],1); + } + } +} +#if SUPPORT_LONG_DOUBLE +#if (LDBL_MANT_DIG == 53) +__weak_reference(cos, cosl); +#endif +#endif diff --git a/third_party/lib/libm/s_cosf.c b/third_party/lib/libm/s_cosf.c new file mode 100644 index 000000000..a74ebdc0c --- /dev/null +++ b/third_party/lib/libm/s_cosf.c @@ -0,0 +1,90 @@ +/* s_cosf.c -- float version of s_cos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "math.h" +#define INLINE_KERNEL_COSDF +#define INLINE_KERNEL_SINDF +#define INLINE_REM_PIO2F +#include "math_private.h" +#include "e_rem_pio2f.c" +#include "k_cosf.c" +#include "k_sinf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float +cosf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix<0x39800000) /* |x| < 2**-12 */ + if (((int)x)==0) return 1.0; /* 1 with inexact if x != 0 */ + return __kernel_cosdf(x); + } + if (ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix>0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__kernel_cosdf(x + (hx > 0 ? -c2pio2 : c2pio2)); + else { + if (hx>0) + return __kernel_sindf(c1pio2 - x); + else + return __kernel_sindf(x + c1pio2); + } + } + if (ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix>0x40afeddf) /* |x| ~> 7*pi/4 */ + return __kernel_cosdf(x + (hx > 0 ? -c4pio2 : c4pio2)); + else { + if (hx>0) + return __kernel_sindf(x - c3pio2); + else + return __kernel_sindf(-c3pio2 - x); + } + } + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + switch (n&3) { + case 0: + return __kernel_cosdf(y); + case 1: + return __kernel_sindf(-y); + case 2: + return -__kernel_cosdf(y); + default: + return __kernel_sindf(y); + } + } +} diff --git a/third_party/lib/libm/s_fabs.c b/third_party/lib/libm/s_fabs.c new file mode 100644 index 000000000..0dfa9405e --- /dev/null +++ b/third_party/lib/libm/s_fabs.c @@ -0,0 +1,31 @@ +/* @(#)s_fabs.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/s_fabs.c,v 1.7 2002/05/28 18:15:04 alfred Exp $"; +#endif + +/* + * fabs(x) returns the absolute value of x. + */ + +#include "math.h" +#include "math_private.h" + +double +fabs(double x) +{ + u_int32_t high; + GET_HIGH_WORD(high,x); + SET_HIGH_WORD(x,high&0x7fffffff); + return x; +} diff --git a/third_party/lib/libm/s_fabsf.c b/third_party/lib/libm/s_fabsf.c new file mode 100644 index 000000000..2200705c6 --- /dev/null +++ b/third_party/lib/libm/s_fabsf.c @@ -0,0 +1,34 @@ +/* s_fabsf.c -- float version of s_fabs.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef lint +static char rcsid[] = "$FreeBSD: src/lib/msun/src/s_fabsf.c,v 1.7 2002/05/28 18:15:04 alfred Exp $"; +#endif + +/* + * fabsf(x) returns the absolute value of x. + */ + +#include "math.h" +#include "math_private.h" + +float +fabsf(float x) +{ + u_int32_t ix; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x7fffffff); + return x; +} diff --git a/third_party/lib/libm/s_floor.c b/third_party/lib/libm/s_floor.c new file mode 100644 index 000000000..e14a5cb04 --- /dev/null +++ b/third_party/lib/libm/s_floor.c @@ -0,0 +1,83 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * floor(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floor(x). + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const double huge = 1.0e300; + +double +floor(double x) +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if (j0<20) { + if (j0<0) { /* raise inexact if x != 0 */ + if (huge+x>0.0) { /* return 0*sign(x) if |x|<1 */ + if (i0>=0) {i0=i1=0;} + else if (((i0&0x7fffffff)|i1)!=0) + { i0=0xbff00000; i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if (((i0&i)|i1)==0) return x; /* x is integral */ + if (huge+x>0.0) { /* raise inexact flag */ + if (i0<0) i0 += (0x00100000)>>j0; + i0 &= (~i); + i1=0; + } + } + } else if (j0>51) { + if (j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if ((i1&i)==0) return x; /* x is integral */ + if (huge+x>0.0) { /* raise inexact flag */ + if (i0<0) { + if (j0==20) i0+=1; + else { + j = i1+(1<<(52-j0)); + if (j<(u_int32_t)i1) i0 +=1 ; /* got a carry */ + i1=j; + } + } + i1 &= (~i); + } + } + INSERT_WORDS(x,i0,i1); + return x; +} + +#if SUPPORT_LONG_DOUBLE + +#if LDBL_MANT_DIG == 53 +__weak_reference(floor, floorl); +#endif + +#endif diff --git a/third_party/lib/libm/s_floorf.c b/third_party/lib/libm/s_floorf.c new file mode 100644 index 000000000..6b510dee3 --- /dev/null +++ b/third_party/lib/libm/s_floorf.c @@ -0,0 +1,61 @@ +/* s_floorf.c -- float version of s_floor.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * floorf(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floorf(x). + */ + +#include "math.h" +#include "math_private.h" + +static const float huge = 1.0e30; + +float +floorf(float x) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=0;} + else if((i0&0x7fffffff)!=0) + { i0=0xbf800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/third_party/lib/libm/s_round.c b/third_party/lib/libm/s_round.c new file mode 100644 index 000000000..dd293aac4 --- /dev/null +++ b/third_party/lib/libm/s_round.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "math.h" +#include "math_private.h" + +double +round(double x) +{ + double t; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + if ((hx & 0x7fffffff) == 0x7ff00000) + return (x + x); + + if (!(hx & 0x80000000)) { + t = floor(x); + if (t - x <= -0.5) + t += 1; + return (t); + } else { + t = floor(-x); + if (t + x <= -0.5) + t += 1; + return (-t); + } +} + +#if SUPPORT_LONG_DOUBLE +#if (LDBL_MANT_DIG == 53) +__weak_reference(round, roundl); +#endif +#endif diff --git a/third_party/lib/libm/s_scalbn.c b/third_party/lib/libm/s_scalbn.c new file mode 100644 index 000000000..ef5a68525 --- /dev/null +++ b/third_party/lib/libm/s_scalbn.c @@ -0,0 +1,70 @@ +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * scalbn (double x, int n) + * scalbn(x,n) returns x* 2**n computed by exponent + * manipulation rather than by actually performing an + * exponentiation or a multiplication. + */ + +#include +#include + +#include "math.h" +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ +huge = 1.0e+300, +tiny = 1.0e-300; + +double +scalbn (double x, int n) +{ + int32_t k,hx,lx; + EXTRACT_WORDS(hx,lx,x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx,x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} + + if (k <= -54) { + if (n > 50000) { /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + } else { + return tiny*copysign(tiny,x); /*underflow*/ + } + } + k += 54; /* subnormal result */ + SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); + return x*twom54; +} + +#if SUPPORT_LONG_DOUBLE + +#if (LDBL_MANT_DIG == 53) +__weak_reference(scalbn, ldexpl); +__weak_reference(scalbn, scalbnl); +#endif + +#endif diff --git a/third_party/lib/libm/s_scalbnf.c b/third_party/lib/libm/s_scalbnf.c new file mode 100644 index 000000000..dbbc2ddf2 --- /dev/null +++ b/third_party/lib/libm/s_scalbnf.c @@ -0,0 +1,55 @@ +/* s_scalbnf.c -- float version of s_scalbn.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const float +two25 = 3.355443200e+07, /* 0x4c000000 */ +twom25 = 2.9802322388e-08, /* 0x33000000 */ +huge = 1.0e+30, +tiny = 1.0e-30; + +float +scalbnf (float x, int n) +{ + int32_t k,ix; + GET_FLOAT_WORD(ix,x); + k = (ix&0x7f800000)>>23; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((ix&0x7fffffff)==0) return x; /* +-0 */ + x *= two25; + GET_FLOAT_WORD(ix,x); + k = ((ix&0x7f800000)>>23) - 25; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0xff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0xfe) return huge*copysignf(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;} + if (k <= -25) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysignf(huge,x); /*overflow*/ + else return tiny*copysignf(tiny,x); /*underflow*/ + } + k += 25; /* subnormal result */ + SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); + return x*twom25; +} + +//__strong_reference(scalbnf, ldexpf); diff --git a/third_party/lib/libm/s_sin.c b/third_party/lib/libm/s_sin.c new file mode 100644 index 000000000..8d505c80d --- /dev/null +++ b/third_party/lib/libm/s_sin.c @@ -0,0 +1,96 @@ +/* @(#)s_sin.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cose function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include + +#include "math.h" +#define INLINE_REM_PIO2 +#include "math_private.h" +#include "e_rem_pio2.c" + +double +sin(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if (ix <= 0x3fe921fb) { + if (ix<0x3e500000) /* |x| < 2**-26 */ + {if ((int)x==0) return x;} /* generate inexact */ + return __kernel_sin(x,z,0); + } + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch (n&3) { + case 0: + return __kernel_sin(y[0],y[1],1); + case 1: + return __kernel_cos(y[0],y[1]); + case 2: + return -__kernel_sin(y[0],y[1],1); + default: + return -__kernel_cos(y[0],y[1]); + } + } +} + +#if SUPPORT_LONG_DOUBLE + +#if (LDBL_MANT_DIG == 53) +__weak_reference(sin, sinl); +#endif + +#endif diff --git a/third_party/lib/libm/s_sinf.c b/third_party/lib/libm/s_sinf.c new file mode 100644 index 000000000..30c055c39 --- /dev/null +++ b/third_party/lib/libm/s_sinf.c @@ -0,0 +1,88 @@ +/* s_sinf.c -- float version of s_sin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "math.h" +#define INLINE_KERNEL_COSDF +#define INLINE_KERNEL_SINDF +#define INLINE_REM_PIO2F +#include "math_private.h" +#include "e_rem_pio2f.c" +#include "k_cosf.c" +#include "k_sinf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float +sinf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix<0x39800000) /* |x| < 2**-12 */ + if (((int)x)==0) return x; /* x with inexact if x != 0 */ + return __kernel_sindf(x); + } + if (ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix<=0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (hx>0) + return __kernel_cosdf(x - s1pio2); + else + return -__kernel_cosdf(x + s1pio2); + } else + return __kernel_sindf((hx > 0 ? s2pio2 : -s2pio2) - x); + } + if (ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix<=0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (hx>0) + return -__kernel_cosdf(x - s3pio2); + else + return __kernel_cosdf(x + s3pio2); + } else + return __kernel_sindf(x + (hx > 0 ? -s4pio2 : s4pio2)); + } + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + switch (n&3) { + case 0: + return __kernel_sindf(y); + case 1: + return __kernel_cosdf(y); + case 2: + return __kernel_sindf(-y); + default: + return -__kernel_cosdf(y); + } + } +} diff --git a/third_party/lib/libm/s_tan.c b/third_party/lib/libm/s_tan.c new file mode 100644 index 000000000..36b1138e5 --- /dev/null +++ b/third_party/lib/libm/s_tan.c @@ -0,0 +1,84 @@ +/* @(#)s_tan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __kernel_tan ... tangent function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include + +#include "math.h" +#define INLINE_REM_PIO2 +#include "math_private.h" +#include "e_rem_pio2.c" + +double +tan(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if (ix <= 0x3fe921fb) { + if (ix<0x3e400000) /* x < 2**-27 */ + if ((int)x==0) return x; /* generate inexact */ + return __kernel_tan(x,z,1); + } + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; /* NaN */ + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even + -1 -- n odd */ + } +} +#if SUPPORT_LONG_DOUBLE +#if (LDBL_MANT_DIG == 53) +__weak_reference(tan, tanl); +#endif +#endif diff --git a/third_party/lib/libm/s_tanf.c b/third_party/lib/libm/s_tanf.c new file mode 100644 index 000000000..abd60a22d --- /dev/null +++ b/third_party/lib/libm/s_tanf.c @@ -0,0 +1,72 @@ +/* s_tanf.c -- float version of s_tan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "math.h" +#define INLINE_KERNEL_TANDF +#define INLINE_REM_PIO2F +#include "math_private.h" +#include "e_rem_pio2f.c" +#include "k_tanf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float +tanf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix<0x39800000) /* |x| < 2**-12 */ + if (((int)x)==0) return x; /* x with inexact if x != 0 */ + return __kernel_tandf(x,1); + } + if (ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix<=0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __kernel_tandf(x + (hx>0 ? -t1pio2 : t1pio2), -1); + else + return __kernel_tandf(x + (hx>0 ? -t2pio2 : t2pio2), 1); + } + if (ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix<=0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __kernel_tandf(x + (hx>0 ? -t3pio2 : t3pio2), -1); + else + return __kernel_tandf(x + (hx>0 ? -t4pio2 : t4pio2), 1); + } + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + /* integer parameter: 1 -- n even; -1 -- n odd */ + return __kernel_tandf(y,1-((n&1)<<1)); + } +} diff --git a/third_party/lib/libm/s_trunc.c b/third_party/lib/libm/s_trunc.c new file mode 100644 index 000000000..bc996d1a7 --- /dev/null +++ b/third_party/lib/libm/s_trunc.c @@ -0,0 +1,69 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * trunc(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to trunc(x). + */ + +#include + +#include "math.h" +#include "math_private.h" + +static const double huge = 1.0e300; + +double +trunc(double x) +{ + int32_t i0,i1,j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */ + i0 &= 0x80000000U; + i1 = 0; + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) /* raise inexact flag */ + i1 &= (~i); + } + INSERT_WORDS(x,i0,i1); + return x; +} + +#ifdef SUPPORT_LONG_DOUBLE +#if LDBL_MANT_DIG == 53 +__weak_reference(trunc, truncl); +#endif +#endif diff --git a/third_party/lib/safeint/BUILD.gn b/third_party/lib/safeint/BUILD.gn new file mode 100644 index 000000000..87dfa4607 --- /dev/null +++ b/third_party/lib/safeint/BUILD.gn @@ -0,0 +1,22 @@ +config("_safeint_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +module("safeint") { + public_configs = [ ":_safeint_config" ] + public = [ + "include/safeint/safe_conversions.h", + "include/safeint/safe_conversions_impl.h", + "include/safeint/safe_math.h", + "include/safeint/safe_math_impl.h", + ] + sources = [ + "safe_numerics_unittest.cpp", + ] + deps = [ + "//kernel/lib/libc", + "//kernel/lib/unittest", + "//kernel/lib/utils", + ] +} diff --git a/third_party/lib/safeint/LICENSE b/third_party/lib/safeint/LICENSE new file mode 100644 index 000000000..a32e00ce6 --- /dev/null +++ b/third_party/lib/safeint/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/lib/safeint/README.fuchsia b/third_party/lib/safeint/README.fuchsia new file mode 100644 index 000000000..b89d42d15 --- /dev/null +++ b/third_party/lib/safeint/README.fuchsia @@ -0,0 +1,13 @@ +Source: https://chromium.googlesource.com/chromium/src/base +Commit Hash: 8dd3b80be263c2da37d1b2c5854865b97202b263 +License: BSD-style + +Modifications: +- Removed dependency on base/logging.h +- Updated include references +- Changed namespace from base to safeint +- Added rules.mk +- Moved headers into include path +- Reanmed safe_numerics_unittest.cc to safe_numerics_unittest.cpp +- Wired safe_numerics_unittest.cpp into unittest system +- Removed all float stuff diff --git a/third_party/lib/safeint/include/safeint/safe_conversions.h b/third_party/lib/safeint/include/safeint/safe_conversions.h new file mode 100644 index 000000000..9a6e4e2ea --- /dev/null +++ b/third_party/lib/safeint/include/safeint/safe_conversions.h @@ -0,0 +1,161 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define BASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include +#include + +#include +#include + +#include + +namespace safeint { + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template +inline constexpr bool IsValueInRangeForNumericType(Src value) { + return internal::DstRangeRelationToSrcRange(value) == + internal::RANGE_VALID; +} + +// Convenience function for determining if a numeric value is negative without +// throwing compiler warnings on: unsigned(value) < 0. +template +constexpr typename utils::enable_if::is_signed, bool>::type +IsValueNegative(T value) { + static_assert(utils::numeric_limits::is_specialized, + "Argument must be numeric."); + return value < 0; +} + +template +constexpr typename utils::enable_if::is_signed, + bool>::type IsValueNegative(T) { + static_assert(utils::numeric_limits::is_specialized, + "Argument must be numeric."); + return false; +} + +// checked_cast<> is analogous to static_cast<> for numeric types, +// except that it CHECKs that the specified numeric conversion will not +// overflow or underflow. NaN source will always trigger a CHECK. +template +inline Dst checked_cast(Src value) { + ASSERT(IsValueInRangeForNumericType(value)); + return static_cast(value); +} + +// HandleNaN will cause this class to CHECK(false). +struct SaturatedCastNaNBehaviorCheck { + template + static T HandleNaN() { + ASSERT(false); + return T(); + } +}; + +// HandleNaN will return 0 in this case. +struct SaturatedCastNaNBehaviorReturnZero { + template + static constexpr T HandleNaN() { + return T(); + } +}; + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will defer the behavior to a +// specified class. By default, it will return 0. +template +inline Dst saturated_cast(Src value) { + switch (internal::DstRangeRelationToSrcRange(value)) { + case internal::RANGE_VALID: + return static_cast(value); + + case internal::RANGE_UNDERFLOW: + return utils::numeric_limits::min(); + + case internal::RANGE_OVERFLOW: + return utils::numeric_limits::max(); + + // Should fail only on attempting to assign NaN to a saturated integer. + case internal::RANGE_INVALID: + return NaNHandler::template HandleNaN(); + } + + ASSERT(false); + return static_cast(value); +} + +// strict_cast<> is analogous to static_cast<> for numeric types, except that +// it will cause a compile failure if the destination type is not large enough +// to contain any value in the source type. It performs no runtime checking. +template +inline constexpr Dst strict_cast(Src value) { + static_assert(utils::numeric_limits::is_specialized, + "Argument must be numeric."); + static_assert(utils::numeric_limits::is_specialized, + "Result must be numeric."); + static_assert((internal::StaticDstRangeRelationToSrcRange::value == + internal::NUMERIC_RANGE_CONTAINED), + "The numeric conversion is out of range for this type. You " + "should probably use one of the following conversion " + "mechanisms on the value you want to pass:\n" + "- safeint::checked_cast\n" + "- safeint::saturated_cast\n" + "- safeint::CheckedNumeric"); + + return static_cast(value); +} + +// StrictNumeric implements compile time range checking between numeric types by +// wrapping assignment operations in a strict_cast. This class is intended to be +// used for function arguments and return types, to ensure the destination type +// can always contain the source type. This is essentially the same as enforcing +// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied +// incrementally at API boundaries, making it easier to convert code so that it +// compiles cleanly with truncation warnings enabled. +// This template should introduce no runtime overhead, but it also provides no +// runtime checking of any of the associated mathematical operations. Use +// CheckedNumeric for runtime range checks of the actual value being assigned. +template +class StrictNumeric { + public: + typedef T type; + + constexpr StrictNumeric() : value_(0) {} + + // Copy constructor. + template + constexpr StrictNumeric(const StrictNumeric& rhs) + : value_(strict_cast(rhs.value_)) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to StrictNumerics to make them easier to use. + template + constexpr StrictNumeric(Src value) + : value_(strict_cast(value)) {} + + // The numeric cast operator basically handles all the magic. + template + constexpr operator Dst() const { + return strict_cast(value_); + } + + private: + const T value_; +}; + +// Explicitly make a shorter size_t typedef for convenience. +typedef StrictNumeric SizeT; + +} // namespace safeint + +#endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/third_party/lib/safeint/include/safeint/safe_conversions_impl.h b/third_party/lib/safeint/include/safeint/safe_conversions_impl.h new file mode 100644 index 000000000..cc7ad6c0a --- /dev/null +++ b/third_party/lib/safeint/include/safeint/safe_conversions_impl.h @@ -0,0 +1,257 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include +#include + +#include + +namespace safeint { +namespace internal { + +// The std library doesn't provide a binary max_exponent for integers, however +// we can compute one by adding one to the number of non-sign bits. This allows +// for accurate range comparisons between floating point and integer types. +template +struct MaxExponent { + static_assert(utils::numeric_limits::is_specialized, + "Argument must have numeric_limits defined"); + static const int value = sizeof(NumericType) * 8 + 1 - + utils::numeric_limits::is_signed; +}; + +enum IntegerRepresentation { + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED +}; + +// A range for a given nunmeric Src type is contained for a given numeric Dst +// type if both numeric_limits::max() <= numeric_limits::max() and +// numeric_limits::min() >= numeric_limits::min() are true. +// We implement this as template specializations rather than simple static +// comparisons to ensure type correctness in our comparisons. +enum NumericRangeRepresentation { + NUMERIC_RANGE_NOT_CONTAINED, + NUMERIC_RANGE_CONTAINED +}; + +// Helper templates to statically determine if our destination type can contain +// maximum and minimum values represented by the source type. + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = utils::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = + utils::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED > +struct StaticDstRangeRelationToSrcRange; + +// Same sign: Dst is guaranteed to contain Src only if its range is equal or +// larger. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = + MaxExponent::value >= MaxExponent::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Unsigned to signed: Dst is guaranteed to contain source only if its range is +// larger. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = + MaxExponent::value > MaxExponent::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Signed to unsigned: Dst cannot be statically determined to contain Src. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; +}; + +enum RangeConstraint { + RANGE_VALID = 0x0, // Value can be represented by the destination type. + RANGE_UNDERFLOW = 0x1, // Value would overflow. + RANGE_OVERFLOW = 0x2, // Value would underflow. + RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). +}; + +// Helper function for coercing an int back to a RangeContraint. +inline constexpr RangeConstraint GetRangeConstraint( + int integer_range_constraint) { + // TODO(jschuh): Once we get full C++14 support we want this + // assert(integer_range_constraint >= RANGE_VALID && + // integer_range_constraint <= RANGE_INVALID) + return static_cast(integer_range_constraint); +} + +// This function creates a RangeConstraint from an upper and lower bound +// check by taking advantage of the fact that only NaN can be out of range in +// both directions at once. +constexpr inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, + bool is_in_lower_bound) { + return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | + (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); +} + +// The following helper template addresses a corner case in range checks for +// conversion from a floating-point type to an integral type of smaller range +// but larger precision (e.g. float -> unsigned). The problem is as follows: +// 1. Integral maximum is always one less than a power of two, so it must be +// truncated to fit the mantissa of the floating point. The direction of +// rounding is implementation defined, but by default it's always IEEE +// floats, which round to nearest and thus result in a value of larger +// magnitude than the integral value. +// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX +// // is 4294967295u. +// 2. If the floating point value is equal to the promoted integral maximum +// value, a range check will erroneously pass. +// Example: (4294967296f <= 4294967295u) // This is true due to a precision +// // loss in rounding up to float. +// 3. When the floating point value is then converted to an integral, the +// resulting value is out of range for the target integral type and +// thus is implementation defined. +// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. +// To fix this bug we manually truncate the maximum value when the destination +// type is an integral of larger precision than the source floating-point type, +// such that the resulting maximum is represented exactly as a floating point. +template +struct NarrowingRange { + typedef typename utils::numeric_limits SrcLimits; + typedef typename utils::numeric_limits DstLimits; + // The following logic avoids warnings where the max function is + // instantiated with invalid values for a bit shift (even though + // such a function can never be called). + static const int shift = 0; + + static constexpr Dst max() { + // We use UINTMAX_C below to avoid compiler warnings about shifting floating + // points. Since it's a compile time calculation, it shouldn't have any + // performance impact. + return DstLimits::max() - static_cast((UINTMAX_C(1) << shift) - 1); + } + + static constexpr Dst min() { + return DstLimits::min(); + } +}; + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = utils::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = utils::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = + StaticDstRangeRelationToSrcRange::value > +struct DstRangeRelationToSrcRangeImpl; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range is statically determined to contain Src: Nothing to check. +template +struct DstRangeRelationToSrcRangeImpl { + static constexpr RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static constexpr RangeConstraint Check(Src value) { + return GetRangeConstraint((value <= NarrowingRange::max()), + (value >= NarrowingRange::min())); + } +}; + +// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static constexpr RangeConstraint Check(Src value) { + return GetRangeConstraint(value <= NarrowingRange::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static constexpr RangeConstraint Check(Src value) { + return sizeof(Dst) > sizeof(Src) + ? RANGE_VALID + : GetRangeConstraint( + value <= static_cast(NarrowingRange::max()), + true); + } +}; + +// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, +// and any negative value exceeds the lower boundary. +template +struct DstRangeRelationToSrcRangeImpl { + static constexpr RangeConstraint Check(Src value) { + return (MaxExponent::value >= MaxExponent::value) + ? GetRangeConstraint(true, value >= static_cast(0)) + : GetRangeConstraint( + value <= static_cast(NarrowingRange::max()), + value >= static_cast(0)); + } +}; + +template +inline constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) { + static_assert(utils::numeric_limits::is_specialized, + "Argument must be numeric."); + static_assert(utils::numeric_limits::is_specialized, + "Result must be numeric."); + return DstRangeRelationToSrcRangeImpl::Check(value); +} + +} // namespace internal +} // namespace safeint + +#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/third_party/lib/safeint/include/safeint/safe_math.h b/third_party/lib/safeint/include/safeint/safe_math.h new file mode 100644 index 000000000..e366cd5f0 --- /dev/null +++ b/third_party/lib/safeint/include/safeint/safe_math.h @@ -0,0 +1,288 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_MATH_H_ +#define BASE_NUMERICS_SAFE_MATH_H_ + +#include +#include +#include + +#include + +namespace safeint { + +namespace internal { + +// CheckedNumeric implements all the logic and operators for detecting integer +// boundary conditions such as overflow, underflow, and invalid conversions. +// The CheckedNumeric type implicitly converts from floating point and integer +// data types, and contains overloads for basic arithmetic operations (i.e.: +, +// -, *, /, %). +// +// The following methods convert from CheckedNumeric to standard numeric values: +// IsValid() - Returns true if the underlying numeric value is valid (i.e. has +// has not wrapped and is not the result of an invalid conversion). +// ValueOrDie() - Returns the underlying value. If the state is not valid this +// call will crash on a CHECK. +// ValueOrDefault() - Returns the current value, or the supplied default if the +// state is not valid. +// +// Bitwise operations are explicitly not supported, because correct +// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison +// operations are explicitly not supported because they could result in a crash +// on a CHECK condition. You should use patterns like the following for these +// operations: +// Bitwise operation: +// CheckedNumeric checked_int = untrusted_input_value; +// int x = checked_int.ValueOrDefault(0) | kFlagValues; +// Comparison: +// CheckedNumeric checked_size = untrusted_input_value; +// checked_size += HEADER LENGTH; +// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) +// Do stuff... +template +class CheckedNumeric { + static_assert(utils::numeric_limits::is_specialized, + "Argument must have numeric_limits defined"); + public: + typedef T type; + + CheckedNumeric() {} + + // Copy constructor. + template + CheckedNumeric(const CheckedNumeric& rhs) + : state_(rhs.ValueUnsafe(), rhs.validity()) {} + + template + CheckedNumeric(Src value, RangeConstraint validity) + : state_(value, validity) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template + CheckedNumeric(Src value) + : state_(value) { + static_assert(utils::numeric_limits::is_specialized, + "Argument must be numeric."); + } + + // This is not an explicit constructor because we want a seamless conversion + // from StrictNumeric types. + template + CheckedNumeric(StrictNumeric value) + : state_(static_cast(value)) { + } + + // IsValid() is the public API to test if a CheckedNumeric is currently valid. + bool IsValid() const { return validity() == RANGE_VALID; } + + // ValueOrDie() The primary accessor for the underlying value. If the current + // state is not valid it will CHECK and crash. + T ValueOrDie() const { + ASSERT(IsValid()); + return state_.value(); + } + + // ValueOrDefault(T default_value) A convenience method that returns the + // current value if the state is valid, and the supplied default_value for + // any other state. + T ValueOrDefault(T default_value) const { + return IsValid() ? state_.value() : default_value; + } + + // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for + // tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: current validity state (i.e. valid, overflow, underflow, nan). + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + RangeConstraint validity() const { return state_.validity(); } + + // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now + // for tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: the raw numeric value, regardless of the current state. + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + T ValueUnsafe() const { return state_.value(); } + + // Prototypes for the supported arithmetic operator overloads. + template CheckedNumeric& operator+=(Src rhs); + template CheckedNumeric& operator-=(Src rhs); + template CheckedNumeric& operator*=(Src rhs); + template CheckedNumeric& operator/=(Src rhs); + template CheckedNumeric& operator%=(Src rhs); + + CheckedNumeric operator-() const { + RangeConstraint validity; + T value = CheckedNeg(state_.value(), &validity); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric(value, validity); + } + + CheckedNumeric Abs() const { + RangeConstraint validity; + T value = CheckedAbs(state_.value(), &validity); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric(value, validity); + } + + // This function is available only for integral types. It returns an unsigned + // integer of the same width as the source type, containing the absolute value + // of the source, and properly handling signed min. + CheckedNumeric::type> UnsignedAbs() const { + return CheckedNumeric::type>( + CheckedUnsignedAbs(state_.value()), state_.validity()); + } + + CheckedNumeric& operator++() { + *this += 1; + return *this; + } + + CheckedNumeric operator++(int) { + CheckedNumeric value = *this; + *this += 1; + return value; + } + + CheckedNumeric& operator--() { + *this -= 1; + return *this; + } + + CheckedNumeric operator--(int) { + CheckedNumeric value = *this; + *this -= 1; + return value; + } + + // These static methods behave like a convenience cast operator targeting + // the desired CheckedNumeric type. As an optimization, a reference is + // returned when Src is the same type as T. + template + static CheckedNumeric cast( + Src u, + typename utils::enable_if::is_specialized, + int>::type = 0) { + return u; + } + + template + static CheckedNumeric cast( + const CheckedNumeric& u, + typename utils::enable_if::value, int>::type = 0) { + return u; + } + + static const CheckedNumeric& cast(const CheckedNumeric& u) { return u; } + + private: + template + struct UnderlyingType { + using type = NumericType; + }; + + template + struct UnderlyingType> { + using type = NumericType; + }; + + CheckedNumericState state_; +}; + +// This is the boilerplate for the standard arithmetic operator overloads. A +// macro isn't the prettiest solution, but it beats rewriting these five times. +// Some details worth noting are: +// * We apply the standard arithmetic promotions. +// * We skip range checks for floating points. +// * We skip range checks for destination integers with sufficient range. +// TODO(jschuh): extract these out into templates. +#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ + /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + RangeConstraint validity = RANGE_VALID; \ + T result = static_cast(Checked##NAME( \ + static_cast(lhs.ValueUnsafe()), \ + static_cast(rhs.ValueUnsafe()), \ + &validity)); \ + return CheckedNumeric( \ + result, \ + GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \ + } \ + /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ + template \ + template \ + CheckedNumeric& CheckedNumeric::operator COMPOUND_OP(Src rhs) { \ + *this = CheckedNumeric::cast(*this) \ + OP CheckedNumeric::type>::cast(rhs); \ + return *this; \ + } \ + /* Binary arithmetic operator for CheckedNumeric of different type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ + template ::is_specialized>::type* = nullptr> \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, Src rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs, \ + lhs.validity()); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ + template ::is_specialized>::type* = nullptr> \ + CheckedNumeric::type> operator OP( \ + Src lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs OP rhs.ValueUnsafe(), \ + rhs.validity()); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } + +BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) + +#undef BASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace safeint + +#endif // BASE_NUMERICS_SAFE_MATH_H_ diff --git a/third_party/lib/safeint/include/safeint/safe_math_impl.h b/third_party/lib/safeint/include/safeint/safe_math_impl.h new file mode 100644 index 000000000..925a96085 --- /dev/null +++ b/third_party/lib/safeint/include/safeint/safe_math_impl.h @@ -0,0 +1,451 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ +#define BASE_NUMERICS_SAFE_MATH_IMPL_H_ + +#include +#include + +#include +#include +#include + +#include + +namespace safeint { +namespace internal { + +template T abs(T n) { + if (n >= 0) { + return n; + } else { + return static_cast(-n); + } +} + +// Everything from here up to the floating point operations is portable C++, +// but it may not be fast. This code could be split based on +// platform/architecture and replaced with potentially faster implementations. + +// Integer promotion templates used by the portable checked integer arithmetic. +template +struct IntegerForSizeAndSign; +template <> +struct IntegerForSizeAndSign<1, true> { + typedef int8_t type; +}; +template <> +struct IntegerForSizeAndSign<1, false> { + typedef uint8_t type; +}; +template <> +struct IntegerForSizeAndSign<2, true> { + typedef int16_t type; +}; +template <> +struct IntegerForSizeAndSign<2, false> { + typedef uint16_t type; +}; +template <> +struct IntegerForSizeAndSign<4, true> { + typedef int32_t type; +}; +template <> +struct IntegerForSizeAndSign<4, false> { + typedef uint32_t type; +}; +template <> +struct IntegerForSizeAndSign<8, true> { + typedef int64_t type; +}; +template <> +struct IntegerForSizeAndSign<8, false> { + typedef uint64_t type; +}; + +// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to +// support 128-bit math, then the ArithmeticPromotion template below will need +// to be updated (or more likely replaced with a decltype expression). + +template +struct UnsignedIntegerForSize { + typedef typename utils::enable_if< + utils::numeric_limits::is_integer, + typename IntegerForSizeAndSign::type>::type type; +}; + +template +struct SignedIntegerForSize { + typedef typename utils::enable_if< + utils::numeric_limits::is_integer, + typename IntegerForSizeAndSign::type>::type type; +}; + +template +struct TwiceWiderInteger { + typedef typename utils::enable_if< + utils::numeric_limits::is_integer, + typename IntegerForSizeAndSign< + sizeof(Integer) * 2, + utils::numeric_limits::is_signed>::type>::type type; +}; + +template +struct PositionOfSignBit { + static const typename utils::enable_if::is_integer, + size_t>::type value = + 8 * sizeof(Integer) - 1; +}; + +// This is used for UnsignedAbs, where we need to support floating-point +// template instantiations even though we don't actually support the operations. +// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, +// so the float versions will not compile. +template ::is_integer> +struct UnsignedOrFloatForSize; + +template +struct UnsignedOrFloatForSize { + typedef typename UnsignedIntegerForSize::type type; +}; + +// Helper templates for integer manipulations. + +template +bool HasSignBit(T x) { + // Cast to unsigned since right shift on signed is undefined. + return !!(static_cast::type>(x) >> + PositionOfSignBit::value); +} + +// This wrapper undoes the standard integer promotions. +template +T BinaryComplement(T x) { + return ~x; +} + +// Here are the actual portable checked integer math implementations. +// TODO(jschuh): Break this code out from the enable_if pattern and find a clean +// way to coalesce things into the CheckedNumericState specializations below. + +template +typename utils::enable_if::is_integer, T>::type +CheckedAdd(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = ux + uy; + // Addition is valid if the sign of (x + y) is equal to either that of x or + // that of y. + if (utils::numeric_limits::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or overflow. + *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; + } + return static_cast(uresult); +} + +template +typename utils::enable_if::is_integer, T>::type +CheckedSub(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = ux - uy; + // Subtraction is valid if either x and y have same sign, or (x-y) and x have + // the same sign. + if (utils::numeric_limits::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or underflow. + *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; + } + return static_cast(uresult); +} + +// Integer multiplication is a bit complicated. In the fast case we just +// we just promote to a twice wider type, and range check the result. In the +// slow case we need to manually check that the result won't be truncated by +// checking with division against the appropriate bound. +template +typename utils::enable_if::is_integer && + sizeof(T) * 2 <= sizeof(uintmax_t), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + typedef typename TwiceWiderInteger::type IntermediateType; + IntermediateType tmp = + static_cast(x) * static_cast(y); + *validity = DstRangeRelationToSrcRange(tmp); + return static_cast(tmp); +} + +template +typename utils::enable_if::is_integer && + utils::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + // If either side is zero then the result will be zero. + if (!x || !y) { + return RANGE_VALID; + + } else if (x > 0) { + if (y > 0) + *validity = + x <= utils::numeric_limits::max() / y ? RANGE_VALID : RANGE_OVERFLOW; + else + *validity = y >= utils::numeric_limits::min() / x ? RANGE_VALID + : RANGE_UNDERFLOW; + + } else { + if (y > 0) + *validity = x >= utils::numeric_limits::min() / y ? RANGE_VALID + : RANGE_UNDERFLOW; + else + *validity = + y >= utils::numeric_limits::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } + + return x * y; +} + +template +typename utils::enable_if::is_integer && + !utils::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + *validity = (y == 0 || x <= utils::numeric_limits::max() / y) + ? RANGE_VALID + : RANGE_OVERFLOW; + return x * y; +} + +// Division just requires a check for an invalid negation on signed min/-1. +template +T CheckedDiv(T x, + T y, + RangeConstraint* validity, + typename utils::enable_if::is_integer, + int>::type = 0) { + if (utils::numeric_limits::is_signed && x == utils::numeric_limits::min() && + y == static_cast(-1)) { + *validity = RANGE_OVERFLOW; + return utils::numeric_limits::min(); + } + + *validity = RANGE_VALID; + return x / y; +} + +template +typename utils::enable_if::is_integer && + utils::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; + return x % y; +} + +template +typename utils::enable_if::is_integer && + !utils::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = RANGE_VALID; + return x % y; +} + +template +typename utils::enable_if::is_integer && + utils::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + *validity = + value != utils::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + // The negation of signed min is min, so catch that one. + return static_cast(-value); +} + +template +typename utils::enable_if::is_integer && + !utils::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + // The only legal unsigned negation is zero. + *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; + return static_cast( + -static_cast::type>(value)); +} + +template +typename utils::enable_if::is_integer && + utils::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + *validity = + value != utils::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast(abs(value)); +} + +template +typename utils::enable_if::is_integer && + !utils::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + // T is unsigned, so |value| must already be positive. + *validity = RANGE_VALID; + return value; +} + +template +typename utils::enable_if::is_integer && + utils::numeric_limits::is_signed, + typename UnsignedIntegerForSize::type>::type +CheckedUnsignedAbs(T value) { + typedef typename UnsignedIntegerForSize::type UnsignedT; + return value == utils::numeric_limits::min() + ? static_cast(static_cast(utils::numeric_limits::max()) + 1) + : static_cast(abs(value)); +} + +template +typename utils::enable_if::is_integer && + !utils::numeric_limits::is_signed, + T>::type +CheckedUnsignedAbs(T value) { + // T is unsigned, so |value| must already be positive. + return value; +} + +// Floats carry around their validity state with them, but integers do not. So, +// we wrap the underlying value in a specialization in order to hide that detail +// and expose an interface via accessors. +enum NumericRepresentation { + NUMERIC_INTEGER, + NUMERIC_UNKNOWN +}; + +template +struct GetNumericRepresentation { + static const NumericRepresentation value = + utils::numeric_limits::is_integer + ? NUMERIC_INTEGER + : NUMERIC_UNKNOWN; +}; + +template ::value> +class CheckedNumericState {}; + +// Integrals require quite a bit of additional housekeeping to manage state. +template +class CheckedNumericState { + private: + T value_; + RangeConstraint validity_; + + public: + template + friend class CheckedNumericState; + + CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} + + template + CheckedNumericState(Src value, RangeConstraint validity) + : value_(static_cast(value)), + validity_(GetRangeConstraint(validity | + DstRangeRelationToSrcRange(value))) { + static_assert(utils::numeric_limits::is_specialized, + "Argument must be numeric."); + } + + // Copy constructor. + template + CheckedNumericState(const CheckedNumericState& rhs) + : value_(static_cast(rhs.value())), + validity_(GetRangeConstraint( + rhs.validity() | DstRangeRelationToSrcRange(rhs.value()))) {} + + template + explicit CheckedNumericState( + Src value, + typename utils::enable_if::is_specialized, + int>::type = 0) + : value_(static_cast(value)), + validity_(DstRangeRelationToSrcRange(value)) {} + + RangeConstraint validity() const { return validity_; } + T value() const { return value_; } +}; + +// For integers less than 128-bit and floats 32-bit or larger, we can distil +// C/C++ arithmetic promotions down to two simple rules: +// 1. The type with the larger maximum exponent always takes precedence. +// 2. The resulting type must be promoted to at least an int. +// The following template specializations implement that promotion logic. +enum ArithmeticPromotionCategory { + LEFT_PROMOTION, + RIGHT_PROMOTION, + DEFAULT_PROMOTION +}; + +template ::value > MaxExponent::value) + ? (MaxExponent::value > MaxExponent::value + ? LEFT_PROMOTION + : DEFAULT_PROMOTION) + : (MaxExponent::value > MaxExponent::value + ? RIGHT_PROMOTION + : DEFAULT_PROMOTION) > +struct ArithmeticPromotion; + +template +struct ArithmeticPromotion { + typedef Lhs type; +}; + +template +struct ArithmeticPromotion { + typedef Rhs type; +}; + +template +struct ArithmeticPromotion { + typedef int type; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template +struct IsIntegerArithmeticSafe { + static const bool value = StaticDstRangeRelationToSrcRange::value == + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Lhs)) && + StaticDstRangeRelationToSrcRange::value != + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Rhs)); +}; + +} // namespace internal +} // namespace safeint + +#endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ diff --git a/third_party/lib/safeint/rules.mk b/third_party/lib/safeint/rules.mk new file mode 100644 index 000000000..f5339e959 --- /dev/null +++ b/third_party/lib/safeint/rules.mk @@ -0,0 +1,11 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +GLOBAL_INCLUDES += $(LOCAL_DIR)/source/include + +MODULE_SRCS += $(LOCAL_DIR)/safe_numerics_unittest.cpp +MODULE_DEPS += lib/unittest +MODULE_DEPS += lib/utils + +include make/module.mk diff --git a/third_party/lib/safeint/safe_numerics_unittest.cpp b/third_party/lib/safeint/safe_numerics_unittest.cpp new file mode 100644 index 000000000..dc80313f0 --- /dev/null +++ b/third_party/lib/safeint/safe_numerics_unittest.cpp @@ -0,0 +1,686 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#define PROVIDE_NUMERIC_LIMITS_UNSPECIALIZED +#include +#include + +#include + +#include +#include + +#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) +#include +#endif + +using utils::numeric_limits; +using safeint::CheckedNumeric; +using safeint::checked_cast; +using safeint::IsValueInRangeForNumericType; +using safeint::IsValueNegative; +using safeint::SizeT; +using safeint::StrictNumeric; +using safeint::saturated_cast; +using safeint::strict_cast; +using safeint::internal::MaxExponent; +using safeint::internal::RANGE_VALID; +using safeint::internal::RANGE_INVALID; +using safeint::internal::RANGE_OVERFLOW; +using safeint::internal::RANGE_UNDERFLOW; +using safeint::internal::SignedIntegerForSize; + +// These tests deliberately cause arithmetic overflows. If the compiler is +// aggressive enough, it can const fold these overflows. Disable warnings about +// overflows for const expressions. +#if defined(OS_WIN) +#pragma warning(disable:4756) +#endif + +// Helper macros to wrap displaying the conversion types and line numbers. +#define TEST_EXPECTED_VALIDITY(expected, actual) \ + EXPECT_EQ(expected, CheckedNumeric(actual).validity(), \ + "unexpected validity") + +#define TEST_EXPECTED_VALUE(expected, actual) \ + EXPECT_EQ(static_cast(expected), \ + CheckedNumeric(actual).ValueUnsafe(), \ + "unexpected value") + +#define EXPECT_EQ2(v1, v2) \ + EXPECT_EQ(v1, v2, "EXPECT_EQ fail") + +#define EXPECT_TRUE1(v1) \ + EXPECT_TRUE(v1, "EXPECT_TRUE fail") +#define EXPECT_FALSE1(v1) \ + EXPECT_FALSE(v1, "EXPECT_FALSE fail") + +// Signed integer arithmetic. +template +static bool TestSpecializedArithmetic( + const char* dst, + int line, + typename utils::enable_if::is_integer && + numeric_limits::is_signed, + int>::type = 0) { + typedef numeric_limits DstLimits; + BEGIN_TEST; + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, + -CheckedNumeric(DstLimits::min())); + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, + CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(-1).Abs()); + + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric(DstLimits::max()) + -1); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_VALIDITY( + RANGE_UNDERFLOW, + CheckedNumeric(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric(DstLimits::min()) - 1); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric(DstLimits::min()) - -1); + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, + CheckedNumeric(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_VALIDITY( + RANGE_UNDERFLOW, + CheckedNumeric(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric(DstLimits::min()) * 2); + + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, + CheckedNumeric(DstLimits::min()) / -1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(-1) / 2); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + TEST_EXPECTED_VALUE(-1, CheckedNumeric(-1) % 2); + TEST_EXPECTED_VALIDITY(RANGE_INVALID, CheckedNumeric(-1) % -2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); + END_TEST; +} + +// Unsigned integer arithmetic. +template +static bool TestSpecializedArithmetic( + const char* dst, + int line, + typename utils::enable_if::is_integer && + !numeric_limits::is_signed, + int>::type = 0) { + typedef numeric_limits DstLimits; + BEGIN_TEST; + TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric(DstLimits::min())); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric(DstLimits::min()) - 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) * 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) / 2); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric(DstLimits::min()).UnsignedAbs()); + TEST_EXPECTED_VALIDITY( + RANGE_VALID, + CheckedNumeric::type>( + utils::numeric_limits::type>::min()) + .UnsignedAbs()); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); + END_TEST; +} + +// Generic arithmetic tests. +template +static bool TestArithmetic(const char* dst, int line) { + typedef numeric_limits DstLimits; + + BEGIN_TEST; + EXPECT_EQ2(true, CheckedNumeric().IsValid()); + EXPECT_EQ2(false, + CheckedNumeric(CheckedNumeric(DstLimits::max()) * + DstLimits::max()).IsValid()); + EXPECT_EQ2(static_cast(0), CheckedNumeric().ValueOrDie()); + EXPECT_EQ2(static_cast(0), CheckedNumeric().ValueOrDefault(1)); + EXPECT_EQ2(static_cast(1), + CheckedNumeric(CheckedNumeric(DstLimits::max()) * + DstLimits::max()).ValueOrDefault(1)); + + // Test the operator combinations. + TEST_EXPECTED_VALUE(2, CheckedNumeric(1) + CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) - CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) * CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / CheckedNumeric(1)); + TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric(1)); + TEST_EXPECTED_VALUE(2, CheckedNumeric(1) + 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) - 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) * 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(2, checked_dst += 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst -= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst *= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst /= 1); + + // Generic negation. + TEST_EXPECTED_VALUE(0, -CheckedNumeric()); + TEST_EXPECTED_VALUE(-1, -CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, -CheckedNumeric(-1)); + TEST_EXPECTED_VALUE(static_cast(DstLimits::max() * -1), + -CheckedNumeric(DstLimits::max())); + + // Generic absolute value. + TEST_EXPECTED_VALUE(0, CheckedNumeric().Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1).Abs()); + TEST_EXPECTED_VALUE(DstLimits::max(), + CheckedNumeric(DstLimits::max()).Abs()); + + // Generic addition. + TEST_EXPECTED_VALUE(1, (CheckedNumeric() + 1)); + TEST_EXPECTED_VALUE(2, (CheckedNumeric(1) + 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(-1) + 1)); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric(DstLimits::min()) + 1); + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, CheckedNumeric(DstLimits::max()) + DstLimits::max()); + + // Generic subtraction. + TEST_EXPECTED_VALUE(-1, (CheckedNumeric() - 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(1) - 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric(-1) - 1)); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric(DstLimits::max()) - 1); + + // Generic multiplication. + TEST_EXPECTED_VALUE(0, (CheckedNumeric() * 1)); + TEST_EXPECTED_VALUE(1, (CheckedNumeric(1) * 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric(-1) * 2)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(0) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(-1) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(0) * -1)); + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, CheckedNumeric(DstLimits::max()) * DstLimits::max()); + + // Generic division. + TEST_EXPECTED_VALUE(0, CheckedNumeric() / 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / 1); + TEST_EXPECTED_VALUE(DstLimits::min() / 2, + CheckedNumeric(DstLimits::min()) / 2); + TEST_EXPECTED_VALUE(DstLimits::max() / 2, + CheckedNumeric(DstLimits::max()) / 2); + + TestSpecializedArithmetic(dst, line); + END_TEST; +} + +// Helper macro to wrap displaying the conversion types and line numbers. +#define TEST_ARITHMETIC(Dst) TestArithmetic(#Dst, __LINE__) + +BEGIN_TEST_CASE(SafeNumerics_SignedIntegerMath) + TEST_ARITHMETIC(int8_t); + TEST_ARITHMETIC(int); + TEST_ARITHMETIC(intptr_t); + TEST_ARITHMETIC(intmax_t); +END_TEST_CASE(SafeNumerics_SignedIntegerMath) + +BEGIN_TEST_CASE(SafeNumerics_UnsignedIntegerMath) + TEST_ARITHMETIC(uint8_t); + TEST_ARITHMETIC(unsigned int); + TEST_ARITHMETIC(uintptr_t); + TEST_ARITHMETIC(uintmax_t); +END_TEST_CASE(SafeNumerics_UnsignedIntegerMath) + +// Enumerates the five different conversions types we need to test. +enum NumericConversionType { + SIGN_PRESERVING_VALUE_PRESERVING, + SIGN_PRESERVING_NARROW, + SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, + SIGN_TO_UNSIGN_NARROW, + UNSIGN_TO_SIGN_NARROW_OR_EQUAL, +}; + +// Template covering the different conversion tests. +template +struct TestNumericConversion {}; + +// EXPECT_EQ2 wrappers providing specific detail on test failures. +#define TEST_EXPECTED_RANGE(expected, actual) \ + EXPECT_EQ(expected, \ + safeint::internal::DstRangeRelationToSrcRange(actual), \ + "Conversion test failed") + +template +struct TestNumericConversion { + static bool Test(const char *dst, const char *src, int line) { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + BEGIN_TEST; + // Integral to floating. + static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) || + // Not floating to integral and... + (!(DstLimits::is_integer && SrcLimits::is_iec559) && + // Same sign, same numeric, source is narrower or same. + ((SrcLimits::is_signed == DstLimits::is_signed && + sizeof(Dst) >= sizeof(Src)) || + // Or signed destination and source is smaller + (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), + "Comparison must be sign preserving and value preserving"); + + const CheckedNumeric checked_dst = SrcLimits::max(); + TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst); + if (MaxExponent::value > MaxExponent::value) { + if (MaxExponent::value >= MaxExponent::value * 2 - 1) { + // At least twice larger type. + TEST_EXPECTED_VALIDITY(RANGE_VALID, SrcLimits::max() * checked_dst); + + } else { // Larger, but not at least twice as large. + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, SrcLimits::max() * checked_dst); + TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst + 1); + } + } else { // Same width type. + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + 1); + } + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + if (SrcLimits::is_iec559) { + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } else if (numeric_limits::is_signed) { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + END_TEST; + } +}; + +template +struct TestNumericConversion { + static bool Test(const char *dst, const char *src, int line) { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + BEGIN_TEST; + static_assert(SrcLimits::is_signed == DstLimits::is_signed, + "Destination and source sign must be the same"); + static_assert(sizeof(Dst) < sizeof(Src) || + (DstLimits::is_integer && SrcLimits::is_iec559), + "Destination must be narrower than source"); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst - SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + if (SrcLimits::is_iec559) { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) { + if (SrcLimits::digits < DstLimits::digits) { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, + static_cast(DstLimits::max())); + } else { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::min())); + } + } else if (SrcLimits::is_signed) { + TEST_EXPECTED_VALUE(-1, checked_dst - static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + } else { + TEST_EXPECTED_VALIDITY(RANGE_INVALID, checked_dst - static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + END_TEST; + } +}; + +template +struct TestNumericConversion { + static bool Test(const char *dst, const char *src, int line) { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + BEGIN_TEST; + static_assert(sizeof(Dst) >= sizeof(Src), + "Destination must be equal or wider than source."); + static_assert(SrcLimits::is_signed, "Source must be signed"); + static_assert(!DstLimits::is_signed, "Destination must be unsigned"); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast(-1)); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast(-1)); + END_TEST; + } +}; + +template +struct TestNumericConversion { + static bool Test(const char *dst, const char *src, int line) { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + BEGIN_TEST; + static_assert((DstLimits::is_integer && SrcLimits::is_iec559) || + (sizeof(Dst) < sizeof(Src)), + "Destination must be narrower than source."); + static_assert(SrcLimits::is_signed, "Source must be signed."); + static_assert(!DstLimits::is_signed, "Destination must be unsigned."); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast(-1)); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast(-1)); + if (SrcLimits::is_iec559) { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) { + if (SrcLimits::digits < DstLimits::digits) { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, + static_cast(DstLimits::max())); + } else { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::min())); + } + } else { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + } + END_TEST; + } +}; + +template +struct TestNumericConversion { + static bool Test(const char *dst, const char *src, int line) { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + BEGIN_TEST; + static_assert(sizeof(Dst) <= sizeof(Src), + "Destination must be narrower or equal to source."); + static_assert(!SrcLimits::is_signed, "Source must be unsigned."); + static_assert(DstLimits::is_signed, "Destination must be signed."); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min()); + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + END_TEST; + } +}; + +// Helper macro to wrap displaying the conversion types and line numbers +#define TEST_NUMERIC_CONVERSION(d, s, t) \ + TestNumericConversion::Test(#d, #s, __LINE__) + +BEGIN_TEST_CASE(SafeNumerics_IntMinOperations) + TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +END_TEST_CASE(SafeNumerics_IntMinOperations) + +BEGIN_TEST_CASE(SafeNumerics_IntOperations) + TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +END_TEST_CASE(SafeNumerics_IntOperations) + +BEGIN_TEST_CASE(SafeNumerics_IntMaxOperations) + TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + + TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + + TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +END_TEST_CASE(SafeNumerics_IntMaxOperations) + +BEGIN_TEST_CASE(SafeNumerics_SizeTOperations) + TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +END_TEST_CASE(SafeNumerics_SizeTOperations) + +BEGIN_TEST_CASE(SafeNumerics_CastTests) +// MSVC catches and warns that we're forcing saturation in these tests. +// Since that's intentional, we need to shut this warning off. +#if defined(COMPILER_MSVC) +#pragma warning(disable : 4756) +#endif + + int small_positive = 1; + int small_negative = -1; + + BEGIN_TEST; + + // Just test that the casts compile, since the other tests cover logic. + EXPECT_EQ2(0, checked_cast(static_cast(0))); + EXPECT_EQ2(0, strict_cast(static_cast(0))); + EXPECT_EQ2(0, strict_cast(static_cast(0))); + EXPECT_EQ2(0U, strict_cast(static_cast(0))); + EXPECT_EQ2(1ULL, static_cast(StrictNumeric(1U))); + EXPECT_EQ2(1ULL, static_cast(SizeT(1U))); + EXPECT_EQ2(1U, static_cast(StrictNumeric(1U))); + + EXPECT_TRUE1(CheckedNumeric(StrictNumeric(1U)).IsValid()); + EXPECT_TRUE1(CheckedNumeric(StrictNumeric(1U)).IsValid()); + EXPECT_FALSE1(CheckedNumeric(StrictNumeric(-1)).IsValid()); + + EXPECT_TRUE1(IsValueNegative(-1)); + EXPECT_TRUE1(IsValueNegative(numeric_limits::min())); + EXPECT_FALSE1(IsValueNegative(numeric_limits::min())); + EXPECT_FALSE1(IsValueNegative(0)); + EXPECT_FALSE1(IsValueNegative(1)); + EXPECT_FALSE1(IsValueNegative(0u)); + EXPECT_FALSE1(IsValueNegative(1u)); + EXPECT_FALSE1(IsValueNegative(numeric_limits::max())); + EXPECT_FALSE1(IsValueNegative(numeric_limits::max())); + + // These casts and coercions will fail to compile: + // EXPECT_EQ2(0, strict_cast(static_cast(0))); + // EXPECT_EQ2(0, strict_cast(static_cast(0))); + // EXPECT_EQ2(1ULL, StrictNumeric(1)); + // EXPECT_EQ2(1, StrictNumeric(1U)); + + // Test various saturation corner cases. + EXPECT_EQ2(saturated_cast(small_negative), + static_cast(small_negative)); + EXPECT_EQ2(saturated_cast(small_positive), + static_cast(small_positive)); + EXPECT_EQ2(saturated_cast(small_negative), + static_cast(0)); + all_success &= all_ok; +END_TEST_CASE(SafeNumerics_CastTests) + +BEGIN_TEST_CASE(SafeNumerics_IsValueInRangeForNumericType) + BEGIN_TEST; + EXPECT_TRUE1(IsValueInRangeForNumericType(0)); + EXPECT_TRUE1(IsValueInRangeForNumericType(1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(2)); + EXPECT_FALSE1(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE1(IsValueInRangeForNumericType(UINT64_C(0xffffffff))); + EXPECT_FALSE1(IsValueInRangeForNumericType(UINT64_C(0x100000000))); + EXPECT_FALSE1(IsValueInRangeForNumericType(UINT64_C(0x100000001))); + EXPECT_FALSE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + EXPECT_FALSE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + + EXPECT_TRUE1(IsValueInRangeForNumericType(0)); + EXPECT_TRUE1(IsValueInRangeForNumericType(1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(2)); + EXPECT_TRUE1(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0x7fffffff)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0x7fffffffu)); + EXPECT_FALSE1(IsValueInRangeForNumericType(0x80000000u)); + EXPECT_FALSE1(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_FALSE1(IsValueInRangeForNumericType(INT64_C(0x80000000))); + EXPECT_FALSE1(IsValueInRangeForNumericType(INT64_C(0xffffffff))); + EXPECT_FALSE1(IsValueInRangeForNumericType(INT64_C(0x100000000))); + EXPECT_TRUE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + EXPECT_TRUE1(IsValueInRangeForNumericType( + static_cast(utils::numeric_limits::min()))); + EXPECT_FALSE1(IsValueInRangeForNumericType( + static_cast(utils::numeric_limits::min()) - 1)); + EXPECT_FALSE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + + EXPECT_TRUE1(IsValueInRangeForNumericType(0)); + EXPECT_TRUE1(IsValueInRangeForNumericType(1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(2)); + EXPECT_FALSE1(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE1(IsValueInRangeForNumericType(UINT64_C(0xffffffff))); + EXPECT_TRUE1(IsValueInRangeForNumericType(UINT64_C(0x100000000))); + EXPECT_TRUE1(IsValueInRangeForNumericType(UINT64_C(0x100000001))); + EXPECT_FALSE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + EXPECT_FALSE1(IsValueInRangeForNumericType(INT64_C(-1))); + EXPECT_FALSE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + + EXPECT_TRUE1(IsValueInRangeForNumericType(0)); + EXPECT_TRUE1(IsValueInRangeForNumericType(1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(2)); + EXPECT_TRUE1(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0x7fffffff)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0x7fffffffu)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0x80000000u)); + EXPECT_TRUE1(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE1(IsValueInRangeForNumericType(INT64_C(0x80000000))); + EXPECT_TRUE1(IsValueInRangeForNumericType(INT64_C(0xffffffff))); + EXPECT_TRUE1(IsValueInRangeForNumericType(INT64_C(0x100000000))); + EXPECT_TRUE1( + IsValueInRangeForNumericType(INT64_C(0x7fffffffffffffff))); + EXPECT_TRUE1( + IsValueInRangeForNumericType(UINT64_C(0x7fffffffffffffff))); + EXPECT_FALSE1( + IsValueInRangeForNumericType(UINT64_C(0x8000000000000000))); + EXPECT_FALSE1( + IsValueInRangeForNumericType(UINT64_C(0xffffffffffffffff))); + EXPECT_TRUE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + EXPECT_TRUE1(IsValueInRangeForNumericType( + static_cast(utils::numeric_limits::min()))); + EXPECT_TRUE1(IsValueInRangeForNumericType( + utils::numeric_limits::min())); + all_success &= all_ok; +END_TEST_CASE(SafeNumerics_IsValueInRangeForNumericType) + +BEGIN_TEST_CASE(SafeNumerics_CompoundNumericOperations) + BEGIN_TEST; + CheckedNumeric a = 1; + CheckedNumeric b = 2; + CheckedNumeric c = 3; + CheckedNumeric d = 4; + a += b; + EXPECT_EQ2(3, a.ValueOrDie()); + a -= c; + EXPECT_EQ2(0, a.ValueOrDie()); + d /= b; + EXPECT_EQ2(2, d.ValueOrDie()); + d *= d; + EXPECT_EQ2(4, d.ValueOrDie()); + + CheckedNumeric too_large = utils::numeric_limits::max(); + EXPECT_TRUE1(too_large.IsValid()); + too_large += d; + EXPECT_FALSE1(too_large.IsValid()); + too_large -= d; + EXPECT_FALSE1(too_large.IsValid()); + too_large /= d; + EXPECT_FALSE1(too_large.IsValid()); + all_success &= all_ok; +END_TEST_CASE(SafeNumerics_CompoundNumericOperations) diff --git a/third_party/udev/usb_bus/BUILD.gn b/third_party/udev/usb_bus/BUILD.gn new file mode 100644 index 000000000..1da0a4c65 --- /dev/null +++ b/third_party/udev/usb_bus/BUILD.gn @@ -0,0 +1,16 @@ +source_set("usb_bus") { + sources = [ + "generic_hub.c", + "usb_bus.c", + "usb_device.c", + "usb_device.h", + "usb_hub.c", + "usb_private.h", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//system/ulib/mxu", + "//third_party/ulib/musl", + ] +} diff --git a/third_party/udev/usb_bus/driver.mk b/third_party/udev/usb_bus/driver.mk new file mode 100644 index 000000000..7e56f21cf --- /dev/null +++ b/third_party/udev/usb_bus/driver.mk @@ -0,0 +1,7 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/usb_bus.c \ + $(LOCAL_DIR)/usb_device.c \ + $(LOCAL_DIR)/usb_hub.c \ + $(LOCAL_DIR)/generic_hub.c diff --git a/third_party/udev/usb_bus/generic_hub.c b/third_party/udev/usb_bus/generic_hub.c new file mode 100644 index 000000000..ac2a2c329 --- /dev/null +++ b/third_party/udev/usb_bus/generic_hub.c @@ -0,0 +1,205 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#define USB_DEBUG + +#include +#include +#include + +#include "generic_hub.h" +#include "usb_private.h" + +void generic_hub_destroy(generic_hub_t* hub) { + /* First, detach all devices behind this hub */ + int port; + for (port = 1; port <= hub->num_ports; ++port) { + mx_device_t* device = hub->ports[port]; + if (hub->ports[port]) { + hub->bus_protocol->detach_device(hub->busdev, device); + hub->ports[port] = NULL; + } + } + + /* Disable all ports */ + if (hub->hub_protocol->disable_port) { + for (port = 1; port <= hub->num_ports; ++port) + hub->hub_protocol->disable_port(hub->hubdev, port); + } + + free(hub->ports); + free(hub); +} + +static int +generic_hub_debounce(generic_hub_t* hub, const int port) { + const int step_ms = 1; /* linux uses 25ms, we're busy anyway */ + const int at_least_ms = 100; /* 100ms as in usb20 spec 9.1.2 */ + const int timeout_ms = 1500; /* linux uses this value */ + + int total_ms = 0; + int stable_ms = 0; + while (stable_ms < at_least_ms && total_ms < timeout_ms) { + usleep(1000 * step_ms); + + const int changed = hub->hub_protocol->port_status_changed(hub->hubdev, port); + const int connected = hub->hub_protocol->port_connected(hub->hubdev, port); + if (changed < 0 || connected < 0) + return -1; + + if (!changed && connected) { + stable_ms += step_ms; + } else { + usb_debug("generic_hub: Unstable connection at %d\n", + port); + stable_ms = 0; + } + total_ms += step_ms; + } + if (total_ms >= timeout_ms) + usb_debug("generic_hub: Debouncing timed out at %d\n", port); + return 0; /* ignore timeouts, try to always go on */ +} + +int generic_hub_wait_for_port(mx_device_t* device, const int port, + const int wait_for, + int (*const port_op)(mx_device_t*, int), + int timeout_steps, const int step_us) { + int state; + int step_ms; + if (step_us > 1000) { + step_ms = step_us / 1000; + } else { + step_ms = 1; + timeout_steps *= (1000 / step_us); + } + do { + state = port_op(device, port); + if (state < 0) + return -1; + else if (!!state == wait_for) + return timeout_steps; + usleep(1000 * step_ms); + --timeout_steps; + } while (timeout_steps); + return 0; +} + +int generic_hub_detach_dev(generic_hub_t* const hub, const int port) { + mx_device_t* device = hub->ports[port]; + if (!device) + return -1; + + hub->bus_protocol->detach_device(hub->busdev, device); + device_remove(device); + hub->ports[port] = NULL; + + return 0; +} + +int generic_hub_attach_dev(generic_hub_t* const hub, const int port) { + if (hub->ports[port]) + return 0; + + if (generic_hub_debounce(hub, port) < 0) + return -1; + + if (hub->hub_protocol->reset_port) { + if (hub->hub_protocol->reset_port(hub->hubdev, port) < 0) + return -1; + /* after reset the port will be enabled automatically */ + const int ret = generic_hub_wait_for_port( + /* time out after 1,000 * 10us = 10ms */ + hub->hubdev, port, 1, hub->hub_protocol->port_enabled, 1000, 10); + if (ret < 0) + return -1; + else if (!ret) + usb_debug( + "generic_hub: Port %d still " + "disabled after 10ms\n", + port); + } + + const usb_speed speed = hub->hub_protocol->port_speed(hub->hubdev, port); + if (hub->hub_protocol->reset_port) + usleep(1000 * 10); /* Reset recovery time + (usb20 spec 7.1.7.5) */ + hub->ports[port] = hub->bus_protocol->attach_device(hub->busdev, hub->hubdev, hub->hub_address, + port, speed); + + return 0; +} + +int generic_hub_scanport(generic_hub_t* const hub, const int port) { + if (hub->ports[port]) { + usb_debug("generic_hub: Detachment at port %d\n", port); + + const int ret = generic_hub_detach_dev(hub, port); + if (ret < 0) + return ret; + } + + if (hub->hub_protocol->port_connected(hub->hubdev, port)) { + usb_debug("generic_hub: Attachment at port %d\n", port); + + return generic_hub_attach_dev(hub, port); + } + + return 0; +} + +int generic_hub_init(generic_hub_t* hub, mx_device_t* hubdev, mx_device_t* busdev, int hub_address) { + usb_hub_protocol_t* hub_protocol; + usb_bus_protocol_t* bus_protocol; + device_get_protocol(hubdev, MX_PROTOCOL_USB_HUB, (void**)&hub_protocol); + device_get_protocol(busdev, MX_PROTOCOL_USB_BUS, (void**)&bus_protocol); + + hub->hub_address = hub_address; + hub->num_ports = hub_protocol->get_num_ports(hubdev); + hub->hubdev = hubdev; + hub->busdev = busdev; + hub->hub_protocol = hub_protocol; + hub->bus_protocol = bus_protocol; + + hub->ports = calloc(hub->num_ports + 1, sizeof(*hub->ports)); + if (!hub->ports) { + usb_debug("generic_hub: ERROR: Out of memory\n"); + return -1; + } + + /* Enable all ports */ + if (hub_protocol->enable_port) { + for (int port = 1; port <= hub->num_ports; ++port) + hub_protocol->enable_port(hubdev, port); + /* wait once for all ports */ + usleep(1000 * 20); + } + + return 0; +} diff --git a/third_party/udev/usb_bus/generic_hub.h b/third_party/udev/usb_bus/generic_hub.h new file mode 100644 index 000000000..0df0143cc --- /dev/null +++ b/third_party/udev/usb_bus/generic_hub.h @@ -0,0 +1,64 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __USB_HUB_H +#define __USB_HUB_H + +#include +#include +#include + +typedef struct generic_hub { + int num_ports; + /* port numbers are always 1 based, + so we waste one int for convenience */ + mx_device_t** ports; /* allocated to sizeof(*ports)*(num_ports+1) */ + + mx_device_t* hubdev; + mx_device_t* busdev; + int hub_address; + + usb_hub_protocol_t* hub_protocol; + usb_bus_protocol_t* bus_protocol; +} generic_hub_t; + +void generic_hub_destroy(generic_hub_t* hub); +int generic_hub_wait_for_port(mx_device_t* device, const int port, + const int wait_for, + int (*const port_op)(mx_device_t*, int), + int timeout_steps, const int step_us); + +int generic_hub_scanport(generic_hub_t* const hub, int port); + +int generic_hub_init(generic_hub_t* hub, mx_device_t* hubdev, mx_device_t* busdev, int hub_address); + +int generic_hub_attach_dev(generic_hub_t* const hub, const int port); +int generic_hub_detach_dev(generic_hub_t* const hub, const int port); + +#endif diff --git a/third_party/udev/usb_bus/usb_bus.c b/third_party/udev/usb_bus/usb_bus.c new file mode 100644 index 000000000..be9423e41 --- /dev/null +++ b/third_party/udev/usb_bus/usb_bus.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include + +#include "generic_hub.h" +#include "usb_device.h" +#include "usb_private.h" + +typedef struct usb_bus { + mx_device_t device; + + // device's HCI controller and protocol + mx_device_t* hcidev; + usb_hci_protocol_t* hci_protocol; + + // for root hub + generic_hub_t generic_hub; +} usb_bus_t; +#define get_usb_bus(dev) containerof(dev, usb_bus_t, device) + +static mx_device_t* usb_attach_device(mx_device_t* busdev, mx_device_t* hubdev, int hubaddress, + int port, usb_speed speed) { + static const char* speeds[] = {"full", "low", "high", "super"}; + usb_debug("%sspeed device\n", (speed < sizeof(speeds) / sizeof(char*)) + ? speeds[speed] + : "invalid value - no"); + usb_bus_t* bus = get_usb_bus(busdev); + + int address = bus->hci_protocol->set_address(bus->hcidev, speed, port, hubaddress); + if (address < 0) { + return NULL; + } + + mx_device_t* device = usb_create_device(bus->hcidev, address, speed); + if (device) { + device_add(device, &bus->device); + } + return device; +} + +static void usb_detach_device(mx_device_t* busdev, mx_device_t* device) { + usb_bus_t* bus = get_usb_bus(busdev); + + usb_device_protocol_t* device_protocol; + device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&device_protocol); + bus->hci_protocol->destroy_device(bus->hcidev, device_protocol->get_address(device)); +} + +void usb_root_hub_port_changed(mx_device_t* busdev, int port) { + usb_bus_t* bus = get_usb_bus(busdev); + generic_hub_scanport(&bus->generic_hub, port); +} + +usb_bus_protocol_t _bus_protocol = { + .attach_device = usb_attach_device, + .detach_device = usb_detach_device, + .root_hub_port_changed = usb_root_hub_port_changed, +}; + +mx_status_t usb_bus_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +mx_status_t usb_bus_close(mx_device_t* dev) { + return NO_ERROR; +} + +mx_status_t usb_bus_release(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_protocol_device_t usb_bus_device_proto = { + .get_protocol = device_base_get_protocol, + .open = usb_bus_open, + .close = usb_bus_close, + .release = usb_bus_release, +}; + +static mx_status_t usb_bus_probe(mx_driver_t* driver, mx_device_t* device) { + usb_hci_protocol_t* hci_protocol; + usb_hub_protocol_t* hub_protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_HCI, (void**)&hci_protocol)) { + return ERR_NOT_SUPPORTED; + } + if (device_get_protocol(device, MX_PROTOCOL_USB_HUB, (void**)&hub_protocol)) { + return ERR_NOT_SUPPORTED; + } + return NO_ERROR; +} + +static mx_status_t usb_bus_bind(mx_driver_t* driver, mx_device_t* device) { + usb_hci_protocol_t* hci_protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_HCI, (void**)&hci_protocol)) { + return ERR_NOT_SUPPORTED; + } + + usb_bus_t* bus = calloc(1, sizeof(usb_bus_t)); + if (!bus) { + printf("Not enough memory for usb_bus_t.\n"); + return ERR_NO_MEMORY; + } + + bus->hcidev = device; + bus->hci_protocol = hci_protocol; + + mx_status_t status = device_init(&bus->device, driver, "usb_bus", &usb_bus_device_proto); + if (status != NO_ERROR) { + free(bus); + return status; + } + + bus->device.protocol_id = MX_PROTOCOL_USB_BUS; + bus->device.protocol_ops = &_bus_protocol; + device_set_bindable(&bus->device, false); + device_add(&bus->device, device); + + hci_protocol->set_bus_device(device, &bus->device); + generic_hub_init(&bus->generic_hub, device, &bus->device, 0); + + return NO_ERROR; +} + +static mx_status_t usb_bus_unbind(mx_driver_t* drv, mx_device_t* dev) { + usb_bus_t* bus = get_usb_bus(dev); + bus->hci_protocol->set_bus_device(bus->hcidev, NULL); + + mx_device_t* child = NULL; + mx_device_t* temp = NULL; + list_for_every_entry_safe (&dev->device_list, child, temp, mx_device_t, node) { + device_remove(child); + } + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_USB_HCI, +}; + +mx_driver_t _driver_usb_bus BUILTIN_DRIVER = { + .name = "usb_bus", + .ops = { + .probe = usb_bus_probe, + .bind = usb_bus_bind, + .unbind = usb_bus_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/third_party/udev/usb_bus/usb_device.c b/third_party/udev/usb_bus/usb_device.c new file mode 100644 index 000000000..cb91263d5 --- /dev/null +++ b/third_party/udev/usb_bus/usb_device.c @@ -0,0 +1,528 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "usb_private.h" +#include "usb_device.h" + +#define NEXT_DESCRIPTOR(header) ((descriptor_header_t*)((void*)header + header->bLength)) + +#define DR_DESC (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) + +typedef struct usb_device { + mx_device_t device; + int address; + usb_speed speed; + + // device's HCI controller and protocol + mx_device_t* hcidev; + usb_hci_protocol_t* hci_protocol; + + // FIXME add code to free these + usb_device_config_t config; +} usb_device_t; +#define get_usb_device(dev) containerof(dev, usb_device_t, device) + +/* Normalize bInterval to log2 of microframes */ +static int +usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned char bInterval) { +#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1) + switch (speed) { + case LOW_SPEED: + switch (type) { + case USB_ENDPOINT_ISOCHRONOUS: + case USB_ENDPOINT_INTERRUPT: + return LOG2(bInterval) + 3; + default: + return 0; + } + case FULL_SPEED: + switch (type) { + case USB_ENDPOINT_ISOCHRONOUS: + return (bInterval - 1) + 3; + case USB_ENDPOINT_INTERRUPT: + return LOG2(bInterval) + 3; + default: + return 0; + } + case HIGH_SPEED: + switch (type) { + case USB_ENDPOINT_ISOCHRONOUS: + case USB_ENDPOINT_INTERRUPT: + return bInterval - 1; + default: + return LOG2(bInterval); + } + case SUPER_SPEED: + switch (type) { + case USB_ENDPOINT_ISOCHRONOUS: + case USB_ENDPOINT_INTERRUPT: + return bInterval - 1; + default: + return 0; + } + default: + return 0; + } +#undef LOG2 +} + +static int +count_interfaces(usb_configuration_descriptor_t* desc) { + int count = 0; + descriptor_header_t* header = NEXT_DESCRIPTOR(desc); + descriptor_header_t* end = (descriptor_header_t*)((void*)desc + desc->wTotalLength); + while (header < end) { + if (header->bDescriptorType == USB_DT_INTERFACE) + count++; + header = NEXT_DESCRIPTOR(header); + } + return count; +} + +static int +count_alt_interfaces(usb_interface_descriptor_t* desc, descriptor_header_t* end) { + int count = 0; + descriptor_header_t* header = NEXT_DESCRIPTOR(desc); + while (header < end) { + if (header->bDescriptorType == USB_DT_INTERFACE) { + usb_interface_descriptor_t* test = (usb_interface_descriptor_t*)header; + if (test->bInterfaceNumber == desc->bInterfaceNumber && test->bAlternateSetting != 0) { + count++; + } else { + break; + } + } + header = NEXT_DESCRIPTOR(header); + } + return count; +} + +mx_status_t usb_init_device(usb_device_t* dev) { + usb_device_config_t* device_config = &dev->config; + usb_device_descriptor_t* descriptor = malloc(sizeof(usb_device_descriptor_t)); + if (!descriptor || usb_get_descriptor(&dev->device, DR_DESC, USB_DT_DEVICE, 0, descriptor, sizeof(*descriptor)) != sizeof(*descriptor)) { + usb_debug("get_descriptor(USB_DT_DEVICE) failed\n"); + free(dev); + return -1; + } + device_config->descriptor = descriptor; + + usb_debug("* found device (0x%04x:0x%04x, USB %x.%x)\n", + descriptor->idVendor, descriptor->idProduct, + descriptor->bcdUSB >> 8, descriptor->bcdUSB & 0xff); + + int num_configurations = descriptor->bNumConfigurations; + if (num_configurations == 0) { + /* device isn't usable */ + usb_debug("... no usable configuration!\n"); + return -1; + } + + /* workaround for some USB devices: wait until they're ready, or + * they send a NAK when they're not allowed to do. 1ms is enough */ + usleep(1000 * 1); + device_config->num_configurations = num_configurations; + device_config->configurations = calloc(1, num_configurations * sizeof(usb_configuration_t)); + if (!device_config->configurations) { + usb_debug("could not allocate buffer for USB_DT_CONFIG\n"); + return -1; + } + for (int i = 0; i < num_configurations; i++) { + usb_configuration_t* config = &device_config->configurations[i]; + usb_configuration_descriptor_t desc; + if (usb_get_descriptor(&dev->device, DR_DESC, USB_DT_CONFIG, i, &desc, sizeof(desc)) != sizeof(desc)) { + usb_debug("first get_descriptor(USB_DT_CONFIG) failed\n"); + return -1; + } + + int length = desc.wTotalLength; + usb_configuration_descriptor_t* cd = malloc(length); + if (!cd) { + usb_debug("could not allocate usb_configuration_descriptor_t\n"); + return -1; + } + if (usb_get_descriptor(&dev->device, DR_DESC, USB_DT_CONFIG, 0, cd, length) != length) { + usb_debug("get_descriptor(USB_DT_CONFIG) failed\n"); + return -1; + } + if (cd->wTotalLength != length) { + usb_debug("configuration descriptor size changed, aborting\n"); + return -1; + } + config->descriptor = cd; + + // we can't use cd->bNumInterfaces since it doesn't account for alternate settings + config->num_interfaces = count_interfaces(cd); + usb_interface_t* interfaces = calloc(1, config->num_interfaces * sizeof(usb_interface_t)); + if (!interfaces) { + usb_debug("could not allocate interface list\n"); + return -1; + } + config->interfaces = interfaces; + + usb_endpoint_t* endpoints = NULL; + int endpoint_index = 0; + + usb_interface_descriptor_t* intf = NULL; + int intf_index = 0; + int alt_intf_index = 0; + usb_interface_t* current_interface = NULL; + descriptor_header_t* ptr = NEXT_DESCRIPTOR(cd); + descriptor_header_t* end = (descriptor_header_t*)((void*)cd + cd->wTotalLength); + + while (ptr < end) { + if (ptr->bDescriptorType == USB_DT_INTERFACE) { + intf = (usb_interface_descriptor_t*)ptr; + if (intf->bLength != sizeof(*intf)) { + usb_debug("Skipping broken USB_DT_INTERFACE\n"); + return -1; + } + + usb_interface_t* interface; + if (intf->bAlternateSetting == 0) { + interface = &interfaces[intf_index++]; + current_interface = interface; + alt_intf_index = 0; + int num_alt_interfaces = count_alt_interfaces(intf, end); + if (num_alt_interfaces > 0) { + interface->alt_interfaces = calloc(1, num_alt_interfaces * sizeof(usb_interface_t)); + if (!interface->alt_interfaces) { + usb_debug("could not allocate alt interface list\n"); + return -1; + } + } else { + interface->alt_interfaces = NULL; + } + interface->num_alt_interfaces = num_alt_interfaces; + } else { + if (current_interface == NULL) { + usb_debug("alternate interface with no current interface\n"); + return -1; + } + if (intf->bInterfaceNumber != current_interface->descriptor->bInterfaceNumber) { + usb_debug("alternate interface does not match current primary interface\n"); + return -1; + } + interface = ¤t_interface->alt_interfaces[alt_intf_index++]; + } + + interface->descriptor = intf; + // now create endpoint list + if (intf->bNumEndpoints == 0) { + endpoints = NULL; + } else { + endpoints = calloc(1, intf->bNumEndpoints * sizeof(usb_endpoint_t)); + if (!endpoints) { + usb_debug("could not allocate endpoint list\n"); + return -1; + } + } + interface->endpoints = endpoints; + interface->num_endpoints = intf->bNumEndpoints; + endpoint_index = 0; + } else if (ptr->bDescriptorType == USB_DT_ENDPOINT) { + usb_endpoint_descriptor_t* ed = (usb_endpoint_descriptor_t*)ptr; + if (ed->bLength != sizeof(*ed)) { + usb_debug("Skipping broken USB_DT_ENDPOINT\n"); + return -1; + } + if (endpoint_index >= intf->bNumEndpoints) { + usb_debug("more endpoints in this interface than expected\n"); + return -1; + } + if (!intf) { + usb_debug("endpoint descriptor with no interface, aborting\n"); + return -1; + } + usb_endpoint_t* ep = &endpoints[endpoint_index++]; + ep->descriptor = ed; + ep->endpoint = ed->bEndpointAddress; + ep->toggle = 0; + ep->maxpacketsize = ed->wMaxPacketSize; + ep->direction = ed->bEndpointAddress & USB_ENDPOINT_DIR_MASK; + ep->type = ed->bmAttributes & USB_ENDPOINT_TYPE_MASK; + ep->interval = usb_decode_interval(dev->speed, ep->type, + ed->bInterval); + } + + ptr = NEXT_DESCRIPTOR(ptr); + } + } + + if ((dev->hci_protocol->finish_device_config(dev->hcidev, dev->address, device_config)) || + usb_set_configuration(&dev->device) < 0) { + usb_debug("Could not finalize device configuration\n"); + return -1; + } + + return NO_ERROR; +} + +static usb_request_t* usb_alloc_request(mx_device_t* device, usb_endpoint_t* ep, uint16_t length) { + usb_device_t* dev = get_usb_device(device); + usb_request_t* request = dev->hci_protocol->alloc_request(dev->hcidev, length); + if (request) { + request->endpoint = ep; + } + return request; +} + +static void usb_free_request(mx_device_t* device, usb_request_t* request) { + usb_device_t* dev = get_usb_device(device); + dev->hci_protocol->free_request(dev->hcidev, request); +} + +static mx_status_t usb_control(mx_device_t* device, uint8_t request_type, uint8_t request, + uint16_t value, uint16_t index, void* data, uint16_t length) { + + usb_setup_t dr; + dr.bmRequestType = request_type; + dr.bRequest = request; + dr.wValue = value; + dr.wIndex = index; + dr.wLength = length; + + usb_device_t* dev = get_usb_device(device); + return dev->hci_protocol->control(dev->hcidev, dev->address, &dr, length, data); +} + +static mx_status_t usb_get_config(mx_device_t* device, usb_device_config_t** config) { + usb_device_t* dev = get_usb_device(device); + *config = &dev->config; + return NO_ERROR; +} + +static mx_status_t usb_queue_request(mx_device_t* device, usb_request_t* request) { + usb_device_t* dev = get_usb_device(device); + return dev->hci_protocol->queue_request(dev->hcidev, dev->address, request); +} + +static usb_speed usb_get_speed(mx_device_t* device) { + usb_device_t* dev = get_usb_device(device); + return dev->speed; +} + +static int usb_get_address(mx_device_t* device) { + usb_device_t* dev = get_usb_device(device); + return dev->address; +} + +usb_device_protocol_t _device_protocol = { + .alloc_request = usb_alloc_request, + .free_request = usb_free_request, + .control = usb_control, + .get_config = usb_get_config, + .queue_request = usb_queue_request, + .get_speed = usb_get_speed, + .get_address = usb_get_address, +}; + +static mx_status_t usb_device_probe(mx_driver_t* drv, mx_device_t* dev) { + //printf("usb_device_probe\n"); + return ERR_NOT_SUPPORTED; +} + +mx_driver_t _driver_usb_device BUILTIN_DRIVER = { + .name = "usb_device", + .ops = { + .probe = usb_device_probe, + }, +}; + +static mx_status_t usb_device_open(mx_device_t* dev, uint32_t flags) { + printf("usb_device_open\n"); + return NO_ERROR; +} + +static mx_status_t usb_device_close(mx_device_t* dev) { + printf("usb_device_close\n"); + return NO_ERROR; +} + +static void usb_interface_free(usb_interface_t* intf) { + for (int i = 0; i < intf->num_alt_interfaces; i++) { + usb_interface_t* alt = &intf->alt_interfaces[i]; + if (alt) { + usb_interface_free(alt); + } + } + free(intf->alt_interfaces); + free(intf->endpoints); +} + +static void usb_configuration_free(usb_configuration_t* config) { + for (int i = 0; i < config->num_interfaces; i++) { + usb_interface_t* intf = &config->interfaces[i]; + if (intf) { + usb_interface_free(intf); + } + } + free(config->interfaces); + free(config->descriptor); +} + +void usb_device_free(usb_device_t* dev) { +} + +static mx_status_t usb_device_release(mx_device_t* device) { + usb_device_t* dev = get_usb_device(device); + + printf("usb_device_release\n"); + free(dev->config.descriptor); + + for (int i = 0; i < dev->config.num_configurations; i++) { + usb_configuration_t* config = &dev->config.configurations[i]; + if (config) { + usb_configuration_free(config); + } + } + free(dev->config.configurations); + + return NO_ERROR; +} + +mx_protocol_device_t usb_device_proto = { + .get_protocol = device_base_get_protocol, + .open = usb_device_open, + .close = usb_device_close, + .release = usb_device_release, +}; + +mx_device_t* usb_create_device(mx_device_t* hcidev, int address, usb_speed speed) { + usb_device_t* dev = calloc(1, sizeof(usb_device_t)); + if (!dev) + return NULL; + + device_get_protocol(hcidev, MX_PROTOCOL_USB_HCI, (void**)&dev->hci_protocol); + dev->hcidev = hcidev; + dev->speed = speed; + dev->address = address; + + mx_status_t status = usb_init_device(dev); + if (status < 0) { + dev->hci_protocol->destroy_device(hcidev, address); + free(dev); + return NULL; + } + + char name[60]; + usb_device_descriptor_t* descriptor = dev->config.descriptor; + snprintf(name, sizeof(name), "usb_device[%04X:%04X %d %d %d]", + descriptor->idVendor, descriptor->idProduct, + descriptor->bDeviceClass, descriptor->bDeviceSubClass, descriptor->bDeviceProtocol); + + status = device_init(&dev->device, &_driver_usb_device, name, &usb_device_proto); + if (status < 0) { + free(dev); + return NULL; + } + dev->device.protocol_id = MX_PROTOCOL_USB_DEVICE; + dev->device.protocol_ops = &_device_protocol; + return &dev->device; +} + +int usb_set_feature(mx_device_t* device, int endp, int feature, int rtype) { + usb_device_t* dev = get_usb_device(device); + usb_setup_t dr; + + dr.bmRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | rtype; + dr.bRequest = USB_REQ_SET_FEATURE; + dr.wValue = feature; + dr.wIndex = endp; + dr.wLength = 0; + + return dev->hci_protocol->control(dev->hcidev, dev->address, &dr, 0, 0); +} + +int usb_get_status(mx_device_t* device, int intf, int rtype, int len, void* data) { + usb_device_t* dev = get_usb_device(device); + usb_setup_t dr; + + dr.bmRequestType = USB_DIR_IN | USB_TYPE_STANDARD | rtype; + dr.bRequest = USB_REQ_GET_STATUS; + dr.wValue = 0; + dr.wIndex = intf; + dr.wLength = len; + + return dev->hci_protocol->control(dev->hcidev, dev->address, &dr, len, data); +} + +int usb_get_descriptor(mx_device_t* device, int rtype, int desc_type, int desc_idx, + void* data, size_t len) { + usb_device_t* dev = get_usb_device(device); + usb_setup_t dr; + + dr.bmRequestType = rtype; + dr.bRequest = USB_REQ_GET_DESCRIPTOR; + dr.wValue = desc_type << 8 | desc_idx; + dr.wIndex = 0; + dr.wLength = len; + + return dev->hci_protocol->control(dev->hcidev, dev->address, &dr, len, data); +} + +int usb_set_configuration(mx_device_t* device) { + usb_device_t* dev = get_usb_device(device); + usb_setup_t dr; + + dr.bmRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + dr.bRequest = USB_REQ_SET_CONFIGURATION; + dr.wValue = dev->config.configurations[0].descriptor->bConfigurationValue; + dr.wIndex = 0; + dr.wLength = 0; + + return dev->hci_protocol->control(dev->hcidev, dev->address, &dr, 0, 0); +} + +int usb_clear_feature(mx_device_t* device, int endp, int feature, int rtype) { + usb_device_t* dev = get_usb_device(device); + usb_setup_t dr; + + dr.bmRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | rtype; + dr.bRequest = USB_REQ_CLEAR_FEATURE; + dr.wValue = feature; + dr.wIndex = endp; + dr.wLength = 0; + + return dev->hci_protocol->control(dev->hcidev, dev->address, &dr, 0, 0) < 0; +} + +int usb_clear_stall(mx_device_t* device, usb_endpoint_t* ep) { + int ret = usb_clear_feature(device, ep->endpoint, USB_ENDPOINT_HALT, + USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); + ep->toggle = 0; + return ret; +} diff --git a/third_party/udev/usb_bus/usb_device.h b/third_party/udev/usb_bus/usb_device.h new file mode 100644 index 000000000..1396179ff --- /dev/null +++ b/third_party/udev/usb_bus/usb_device.h @@ -0,0 +1,43 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +mx_device_t* usb_create_device(mx_device_t* hcidev, int address, usb_speed speed); + +int usb_set_feature(mx_device_t* device, int endp, int feature, int rtype); +int usb_get_status(mx_device_t* device, int endp, int rtype, int len, void* data); +int usb_get_descriptor(mx_device_t* device, int rtype, int descType, int descIdx, + void* data, size_t len); +int usb_set_configuration(mx_device_t* device); +int usb_clear_feature(mx_device_t* device, int endp, int feature, int rtype); +int usb_clear_stall(mx_device_t* device, usb_endpoint_t* ep); diff --git a/third_party/udev/usb_bus/usb_hub.c b/third_party/udev/usb_bus/usb_hub.c new file mode 100644 index 000000000..c7dfdc3d4 --- /dev/null +++ b/third_party/udev/usb_bus/usb_hub.c @@ -0,0 +1,430 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#define USB_DEBUG + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "generic_hub.h" +#include "usb_private.h" +#include "usb_device.h" + +#include + +#define INTR_REQ_COUNT 4 + +#define DR_PORT (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER) + +/* status (and status change) bits */ +#define PORT_CONNECTION 0x1 +#define PORT_ENABLE 0x2 +#define PORT_RESET 0x10 +/* feature selectors (for setting / clearing features) */ +#define SEL_PORT_RESET 0x4 +#define SEL_PORT_POWER 0x8 +#define SEL_C_PORT_CONNECTION 0x10 +/* request type (USB 3.0 hubs only) */ +#define SET_HUB_DEPTH 12 + +typedef struct usb_hub { + // the device we are publishing + mx_device_t hub_device; + + // Underlying USB device + mx_device_t* device; + usb_device_protocol_t* device_protocol; + + list_node_t free_intr_reqs; + mxr_mutex_t mutex; + + usb_speed speed; + int num_ports; + generic_hub_t generic_hub; +} usb_hub_t; +#define get_hub(dev) containerof(dev, usb_hub_t, hub_device) + +static void queue_interrupt_requests_locked(usb_hub_t* hub) { + list_node_t* node; + while ((node = list_remove_head(&hub->free_intr_reqs)) != NULL) { + usb_request_t* req = containerof(node, usb_request_t, node); + req->transfer_length = req->buffer_length; + mx_status_t status = hub->device_protocol->queue_request(hub->device, req); + if (status != NO_ERROR) { + printf("interrupt queue failed %d\n", status); + list_add_head(&hub->free_intr_reqs, &req->node); + break; + } + } +} + +static int +usb_hub_port_status_changed(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + + unsigned short buf[2]; + int ret = usb_get_status(hub->device, port, DR_PORT, sizeof(buf), buf); + if (ret >= 0) { + ret = buf[1] & PORT_CONNECTION; + if (ret) + usb_clear_feature(hub->device, port, SEL_C_PORT_CONNECTION, + DR_PORT); + } + return ret; +} + +static int +usb_hub_port_connected(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + + unsigned short buf[2]; + int ret = usb_get_status(hub->device, port, DR_PORT, sizeof(buf), buf); + if (ret >= 0) + ret = buf[0] & PORT_CONNECTION; + return ret; +} + +static int +usb_hub_port_in_reset(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + + unsigned short buf[2]; + int ret = usb_get_status(hub->device, port, DR_PORT, sizeof(buf), buf); + if (ret >= 0) + ret = buf[0] & PORT_RESET; + return ret; +} + +static int +usb_hub_port_enabled(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + + unsigned short buf[2]; + int ret = usb_get_status(hub->device, port, DR_PORT, sizeof(buf), buf); + if (ret >= 0) + ret = buf[0] & PORT_ENABLE; + return ret; +} + +static usb_speed +usb_hub_port_speed(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + + unsigned short buf[2]; + int ret = usb_get_status(hub->device, port, DR_PORT, sizeof(buf), buf); + if (ret >= 0 && (buf[0] & PORT_ENABLE)) { + /* SuperSpeed hubs can only have SuperSpeed devices. */ + if (hub->speed == SUPER_SPEED) + return SUPER_SPEED; + + /*[bit] 10 9 (USB 2.0 port status word) + * 0 0 full speed + * 0 1 low speed + * 1 0 high speed + * 1 1 invalid + */ + ret = (buf[0] >> 9) & 0x3; + if (ret != 0x3) + return ret; + } + return -1; +} + +static int +usb_hub_enable_port(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + return usb_set_feature(hub->device, port, SEL_PORT_POWER, DR_PORT); +} + +static int +usb_hub_start_port_reset(mx_device_t* device, const int port) { + usb_hub_t* hub = get_hub(device); + return usb_set_feature(hub->device, port, SEL_PORT_RESET, DR_PORT); +} + +static int +usb_hub_resetport(mx_device_t* device, const int port) { + if (usb_hub_start_port_reset(device, port) < 0) + return -1; + + /* wait for 10ms (usb20 spec 11.5.1.5: reset should take 10 to 20ms) */ + usleep(1000 * 10); + + // FIXME which device here? + /* now wait 12ms for the hub to finish the reset */ + const int ret = generic_hub_wait_for_port( + /* time out after 120 * 100us = 12ms */ + device, port, 0, usb_hub_port_in_reset, 120, 100); + if (ret < 0) + return -1; + else if (!ret) + usb_debug("generic_hub: Reset timed out at port %d\n", port); + + return 0; /* ignore timeouts, try to always go on */ +} + +static int usb_hub_get_num_ports(mx_device_t* device) { + usb_hub_t* hub = get_hub(device); + return hub->num_ports; +} + +// FIXME this is broken now +static void usb_hub_set_hub_depth(mx_device_t* device) { + printf("usb_hub_set_hub_depth\n"); + int hub_depth = 0; + mx_device_t* parent = device->parent; + while (parent) { + void* proto; + // stop when we find an HCI device, since we don't count root hub in this calculation + mx_status_t status = device_get_protocol(device, MX_PROTOCOL_USB_HCI, &proto); + if (status == NO_ERROR) + break; + status = device_get_protocol(device, MX_PROTOCOL_USB_HUB, &proto); + if (status == NO_ERROR) + hub_depth++; + parent = parent->parent; + } + printf("set hub depth %d\n", hub_depth); + + usb_device_protocol_t* device_proto; + device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&device_proto); + int ret = device_proto->control(device, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE, SET_HUB_DEPTH, hub_depth, 0, NULL, 0); + if (ret < 0) + usb_debug("Failed SET_HUB_DEPTH(%d): %d\n", hub_depth, ret); +} + +static usb_hub_protocol_t usb_hub_protocol = { + .port_status_changed = usb_hub_port_status_changed, + .port_connected = usb_hub_port_connected, + .port_enabled = usb_hub_port_enabled, + .port_speed = usb_hub_port_speed, + .enable_port = usb_hub_enable_port, + .disable_port = NULL, + .reset_port = usb_hub_resetport, + .get_num_ports = usb_hub_get_num_ports, +}; + +static void usb_hub_interrupt_complete(usb_request_t* request) { + usb_hub_t* hub = (usb_hub_t*)request->client_data; + + uint8_t* bitmap = request->buffer; + uint8_t* bitmap_end = bitmap + request->transfer_length; + + // bit zero is hub status + if (bitmap[0] & 1) { + // what to do here? + printf("usb_hub_interrupt_complete hub status changed\n"); + } + + int port = 1; + int bit = 1; + while (bitmap < bitmap_end) { + if (*bitmap & (1 << bit)) { + unsigned short buf[2]; + int ret = usb_get_status(hub->device, port, DR_PORT, sizeof(buf), buf); + + if (ret >= 0) { + if ((buf[0] & PORT_CONNECTION) && (buf[1] & PORT_CONNECTION)) { + generic_hub_attach_dev(&hub->generic_hub, port); + usb_clear_feature(hub->device, port, SEL_C_PORT_CONNECTION, DR_PORT); + } else if (!(buf[0] & PORT_CONNECTION) && (buf[1] & PORT_CONNECTION)) { + generic_hub_detach_dev(&hub->generic_hub, port); + usb_clear_feature(hub->device, port, SEL_C_PORT_CONNECTION, DR_PORT); + } + } + } + port++; + if (++bit == 8) { + bitmap++; + bit = 0; + } + } + + mxr_mutex_lock(&hub->mutex); + list_add_head(&hub->free_intr_reqs, &request->node); + queue_interrupt_requests_locked(hub); + mxr_mutex_unlock(&hub->mutex); +} + +static mx_status_t usb_hub_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t usb_hub_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t usb_hub_release(mx_device_t* device) { + usb_hub_t* hub = get_hub(device); + generic_hub_destroy(&hub->generic_hub); + free(hub); + + return NO_ERROR; +} + +static mx_protocol_device_t usb_hub_device_proto = { + .get_protocol = device_base_get_protocol, + .open = usb_hub_open, + .close = usb_hub_close, + .release = usb_hub_release, +}; + +static mx_status_t usb_hub_probe(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + + usb_device_config_t* device_config; + mx_status_t status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + if (device_config->descriptor->bDeviceClass != USB_CLASS_HUB) + return ERR_NOT_SUPPORTED; + return NO_ERROR; +} + +static mx_device_t* usb_get_bus(mx_device_t* device) { + while (device) { + usb_bus_protocol_t* bus_protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_BUS, (void**)&bus_protocol) == NO_ERROR) { + return device; + } + device = device->parent; + } + return NULL; +} + +static mx_status_t usb_hub_bind(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* device_protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&device_protocol)) { + return ERR_NOT_SUPPORTED; + } + + usb_device_config_t* device_config; + mx_status_t status = device_protocol->get_config(device, &device_config); + if (status < 0) + return status; + + // find our interrupt endpoint + usb_configuration_t* config = &device_config->configurations[0]; + usb_interface_t* intf = &config->interfaces[0]; + if (intf->num_endpoints != 1) { + printf("usb_ethernet_bind wrong number of endpoints: %d\n", intf->num_endpoints); + return ERR_NOT_SUPPORTED; + } + usb_endpoint_t* endp = &intf->endpoints[0]; + if (endp->type != USB_ENDPOINT_INTERRUPT) { + return ERR_NOT_SUPPORTED; + } + + usb_hub_t* hub = calloc(1, sizeof(usb_hub_t)); + if (!hub) { + printf("Not enough memory for usb_hub_t.\n"); + return ERR_NO_MEMORY; + } + + status = device_init(&hub->hub_device, driver, "usb_hub", &usb_hub_device_proto); + if (status != NO_ERROR) { + free(hub); + return status; + } + + hub->hub_device.protocol_id = MX_PROTOCOL_USB_HUB; + hub->hub_device.protocol_ops = &usb_hub_protocol; + + hub->device = device; + hub->device_protocol = device_protocol; + hub->speed = device_protocol->get_speed(device); + int address = device_protocol->get_address(device); + + int type = hub->speed == SUPER_SPEED ? 0x2a : 0x29; /* similar enough */ + usb_hub_descriptor_t desc; /* won't fit the whole thing, we don't care */ + if (usb_get_descriptor(hub->device, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, + type, 0, &desc, sizeof(desc)) < 0) { + usb_debug("get_descriptor(HUB) failed\n"); + return -1; + } + hub->num_ports = desc.bNbrPorts; + + list_initialize(&hub->free_intr_reqs); + for (int i = 0; i < INTR_REQ_COUNT; i++) { + usb_request_t* req = device_protocol->alloc_request(device, endp, endp->maxpacketsize); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = usb_hub_interrupt_complete; + req->client_data = hub; + list_add_head(&hub->free_intr_reqs, &req->node); + } + + if (hub->speed == SUPER_SPEED) + usb_hub_set_hub_depth(hub->device); + + generic_hub_init(&hub->generic_hub, &hub->hub_device, usb_get_bus(device), address); + device_set_bindable(&hub->hub_device, false); + device_add(&hub->hub_device, device); + + mxr_mutex_lock(&hub->mutex); + queue_interrupt_requests_locked(hub); + mxr_mutex_unlock(&hub->mutex); + + return NO_ERROR; +} + +static mx_status_t usb_hub_unbind(mx_driver_t* drv, mx_device_t* dev) { + mx_device_t* child = NULL; + mx_device_t* temp = NULL; + list_for_every_entry_safe (&dev->device_list, child, temp, mx_device_t, node) { + device_remove(child); + } + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_USB_DEVICE, +}; + +mx_driver_t _driver_usb_hub BUILTIN_DRIVER = { + .name = "usb_hub", + .ops = { + .probe = usb_hub_probe, + .bind = usb_hub_bind, + .unbind = usb_hub_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/third_party/udev/usb_bus/usb_private.h b/third_party/udev/usb_bus/usb_private.h new file mode 100644 index 000000000..bd71541cf --- /dev/null +++ b/third_party/udev/usb_bus/usb_private.h @@ -0,0 +1,42 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +static inline void usb_debug(const char* fmt, ...) { +#ifdef USB_DEBUG + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +#endif +} diff --git a/third_party/udev/usb_keyboard/BUILD.gn b/third_party/udev/usb_keyboard/BUILD.gn new file mode 100644 index 000000000..513875753 --- /dev/null +++ b/third_party/udev/usb_keyboard/BUILD.gn @@ -0,0 +1,10 @@ +source_set("usb_keyboard") { + sources = [ + "usb_keyboard.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//third_party/ulib/musl", + ] +} diff --git a/third_party/udev/usb_keyboard/driver.mk b/third_party/udev/usb_keyboard/driver.mk new file mode 100644 index 000000000..4268c8196 --- /dev/null +++ b/third_party/udev/usb_keyboard/driver.mk @@ -0,0 +1,4 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/usb_keyboard.c diff --git a/third_party/udev/usb_keyboard/usb_keyboard.c b/third_party/udev/usb_keyboard/usb_keyboard.c new file mode 100644 index 000000000..622cb4f47 --- /dev/null +++ b/third_party/udev/usb_keyboard/usb_keyboard.c @@ -0,0 +1,660 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2008-2010 coresystems GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define USB_DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define KEY_BREAK 0x101 +#define KEY_DOWN 0x102 +#define KEY_UP 0x103 +#define KEY_LEFT 0x104 +#define KEY_RIGHT 0x105 +#define KEY_HOME 0x106 +#define KEY_F1 0x109 +#define KEY_F2 0x10A +#define KEY_F3 0x10B +#define KEY_F4 0x10C +#define KEY_F5 0x10D +#define KEY_F6 0x10E +#define KEY_F7 0x10F +#define KEY_F8 0x110 +#define KEY_F9 0x111 +#define KEY_F10 0x112 +#define KEY_F11 0x113 +#define KEY_F12 0x114 +#define KEY_DC 0x14A +#define KEY_IC 0x14B +#define KEY_NPAGE 0x152 +#define KEY_PPAGE 0x153 +#define KEY_ENTER 0x157 +#define KEY_PRINT 0x15A +#define KEY_END 0x166 + +#define INTR_REQ_COUNT 8 +#define INTR_REQ_SIZE 8 + +enum { hid_subclass_none = 0, + hid_subclass_boot = 1 }; +typedef enum { hid_proto_boot = 0, + hid_proto_report = 1 } hid_proto; +enum { hid_boot_proto_none = 0, + hid_boot_proto_keyboard = + 1, + hid_boot_proto_mouse = 2 +}; +enum { GET_REPORT = 0x1, + GET_IDLE = 0x2, + GET_PROTOCOL = 0x3, + SET_REPORT = + 0x9, + SET_IDLE = 0xa, + SET_PROTOCOL = 0xb +}; + +typedef union { + struct { + uint8_t modifiers; + uint8_t repeats; + uint8_t keys[6]; + }; + uint8_t buffer[8]; +} usb_hid_keyboard_event_t; + +typedef struct { + mx_device_t device; + mx_device_t* usb_device; + usb_device_protocol_t* device_protocol; + + usb_endpoint_t* intr_ep; + usb_hid_descriptor_t descriptor; + + usb_hid_keyboard_event_t previous; + int lastkeypress; + int repeat_delay; + + list_node_t free_intr_reqs; + + pthread_mutex_t mutex; + pthread_cond_t cond; + // buffer for char driver read + char key_buffer[10]; + // index of first char in key_buffer + int key_buffer_head; + // number of chars in key_buffer + size_t key_buffer_count; +} kbd_device_t; +#define get_kbd_device(dev) containerof(dev, kbd_device_t, device) + +const char* countries[36][2] = { + {"not supported", "us"}, + {"Arabic", "ae"}, + {"Belgian", "be"}, + {"Canadian-Bilingual", "ca"}, + {"Canadian-French", "ca"}, + {"Czech Republic", "cz"}, + {"Danish", "dk"}, + {"Finnish", "fi"}, + {"French", "fr"}, + {"German", "de"}, + {"Greek", "gr"}, + {"Hebrew", "il"}, + {"Hungary", "hu"}, + {"International (ISO)", "iso"}, + {"Italian", "it"}, + {"Japan (Katakana)", "jp"}, + {"Korean", "us"}, + {"Latin American", "us"}, + {"Netherlands/Dutch", "nl"}, + {"Norwegian", "no"}, + {"Persian (Farsi)", "ir"}, + {"Poland", "pl"}, + {"Portuguese", "pt"}, + {"Russia", "ru"}, + {"Slovakia", "sl"}, + {"Spanish", "es"}, + {"Swedish", "se"}, + {"Swiss/French", "ch"}, + {"Swiss/German", "ch"}, + {"Switzerland", "ch"}, + {"Taiwan", "tw"}, + {"Turkish-Q", "tr"}, + {"UK", "uk"}, + {"US", "us"}, + {"Yugoslavia", "yu"}, + {"Turkish-F", "tr"}, + /* 36 - 255: Reserved */ +}; + +struct layout_maps { + const char* country; + const short map[4][0x80]; +}; + +static const struct layout_maps* map; + +#define KEY_F1 0x109 +#define KEY_F2 0x10A +#define KEY_F3 0x10B +#define KEY_F4 0x10C +#define KEY_F5 0x10D +#define KEY_F6 0x10E +#define KEY_F7 0x10F +#define KEY_F8 0x110 +#define KEY_F9 0x111 +#define KEY_F10 0x112 +#define KEY_F11 0x113 +#define KEY_F12 0x114 + +static const struct layout_maps keyboard_layouts[] = { + // #if IS_ENABLED(CONFIG_LP_PC_KEYBOARD_LAYOUT_US) + {.country = "us", .map = {{ + /* No modifier */ + -1, -1, -1, -1, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + /* 0x10 */ + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', + /* 0x20 */ + '3', '4', '5', '6', '7', '8', '9', '0', '\n', '\e', '\b', '\t', ' ', '-', '=', '[', + /* 0x30 */ + ']', '\\', -1, ';', '\'', '`', ',', '.', '/', -1 /* CapsLk */, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + /* 0x40 */ + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_PRINT, -1 /* ScrLk */, KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT, + /* 50 */ + KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+', KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME, + /* 60 */ + KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 70 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }, + { + /* Shift modifier */ + -1, -1, -1, -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + /* 0x10 */ + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', + /* 0x20 */ + '#', '$', '%', '^', '&', '*', '(', ')', '\n', '\e', '\b', '\t', ' ', '_', '+', '[', + /* 0x30 */ + ']', '\\', -1, ':', '\'', '`', ',', '.', '/', -1 /* CapsLk */, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + /* 0x40 */ + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_PRINT, -1 /* ScrLk */, KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT, + /* 50 */ + KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+', KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME, + /* 60 */ + KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 70 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }, + { + /* Alt */ + -1, -1, -1, -1, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + /* 0x10 */ + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', + /* 0x20 */ + '3', '4', '5', '6', '7', '8', '9', '0', '\n', '\e', '\b', '\t', ' ', '-', '=', '[', + /* 0x30 */ + ']', '\\', -1, ';', '\'', '`', ',', '.', '/', -1 /* CapsLk */, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + /* 0x40 */ + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_PRINT, -1 /* ScrLk */, KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT, + /* 50 */ + KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+', KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME, + /* 60 */ + KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 70 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }, + { + /* Shift+Alt modifier */ + -1, -1, -1, -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + /* 0x10 */ + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', + /* 0x20 */ + '#', '$', '%', '^', '&', '*', '(', ')', '\n', '\e', '\b', '\t', ' ', '-', '=', '[', + /* 0x30 */ + ']', '\\', -1, ':', '\'', '`', ',', '.', '/', -1 /* CapsLk */, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + /* 0x40 */ + KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_PRINT, -1 /* ScrLk */, KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT, + /* 50 */ + KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+', KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME, + /* 60 */ + KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 70 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }}}, + //#endif +}; + +#define MOD_SHIFT (1 << 0) +#define MOD_ALT (1 << 1) +#define MOD_CTRL (1 << 2) + +static void usb_hid_keyboard_queue(kbd_device_t* kbd, int ch) { + printf("got char: %c\n", ch); + pthread_mutex_lock(&kbd->mutex); + + int index; + if (kbd->key_buffer_count == 0) { + index = 0; + } else { + index = (kbd->key_buffer_head + kbd->key_buffer_count) % countof(kbd->key_buffer); + } + kbd->key_buffer[index] = ch; + + if (kbd->key_buffer_count < countof(kbd->key_buffer)) { + kbd->key_buffer_count++; + } else { + // we overflowed the buffer, so increment our head to the oldest char in the buffer + kbd->key_buffer_head = (kbd->key_buffer_head + 1) % countof(kbd->key_buffer); + } + pthread_cond_signal(&kbd->cond); + + pthread_mutex_unlock(&kbd->mutex); +} + +#define KEYBOARD_REPEAT_MS 30 +#define INITIAL_REPEAT_DELAY 10 +#define REPEAT_DELAY 2 + +static void +usb_hid_process_keyboard_event(kbd_device_t* kbd, + const usb_hid_keyboard_event_t* const current) { + const usb_hid_keyboard_event_t* const previous = &kbd->previous; + + int i, keypress = 0, modifiers = 0; + + if (current->modifiers & 0x01) /* Left-Ctrl */ + modifiers |= MOD_CTRL; + if (current->modifiers & 0x02) /* Left-Shift */ + modifiers |= MOD_SHIFT; + if (current->modifiers & 0x04) /* Left-Alt */ + modifiers |= MOD_ALT; + // if (current->modifiers & 0x08) /* Left-GUI */ + // ; + if (current->modifiers & 0x10) /* Right-Ctrl */ + modifiers |= MOD_CTRL; + if (current->modifiers & 0x20) /* Right-Shift */ + modifiers |= MOD_SHIFT; + if (current->modifiers & 0x40) /* Right-AltGr */ + modifiers |= MOD_ALT; + // if (current->modifiers & 0x80) /* Right-GUI */ + // ; + + if ((current->modifiers & 0x05) && ((current->keys[0] == 0x4c) || + (current->keys[0] == 0x63))) { + /* vulcan nerve pinch */ + // if (reset_handler) + // reset_handler(); + } + + /* Did the event change at all? */ + if (kbd->lastkeypress && + !memcmp(current, previous, sizeof(*current))) { + /* No. Then it's a key repeat event. */ + if (kbd->repeat_delay) { + kbd->repeat_delay--; + } else { + usb_hid_keyboard_queue(kbd, kbd->lastkeypress); + kbd->repeat_delay = REPEAT_DELAY; + } + + return; + } + + kbd->lastkeypress = 0; + + for (i = 0; i < 6; i++) { + int j; + int skip = 0; + // No more keys? skip + if (current->keys[i] == 0) + return; + + for (j = 0; j < 6; j++) { + if (current->keys[i] == previous->keys[j]) { + skip = 1; + break; + } + } + if (skip) + continue; + + /* Mask off MOD_CTRL */ + keypress = map->map[modifiers & 0x03][current->keys[i]]; + + if (modifiers & MOD_CTRL) { + switch (keypress) { + case 'a' ... 'z': + keypress &= 0x1f; + break; + default: + continue; + } + } + + if (keypress == -1) { + /* Debug: Print unknown keys */ + printf("usbhid: <%x> %x [ %x %x %x %x %x %x ] %d\n", + current->modifiers, current->repeats, + current->keys[0], current->keys[1], + current->keys[2], current->keys[3], + current->keys[4], current->keys[5], i); + + /* Unknown key? Try next one in the queue */ + continue; + } + + usb_hid_keyboard_queue(kbd, keypress); + + /* Remember for authentic key repeat */ + kbd->lastkeypress = keypress; + kbd->repeat_delay = INITIAL_REPEAT_DELAY; + } +} + +static void usb_keyboard_interrupt(const void* data, size_t length, void* context) { + if (length != 8) { + printf("usb_keyboard_interrupt: unexpected packet length %" PRIuPTR "\n", length); + return; + } + kbd_device_t* kbd = (kbd_device_t*)context; + usb_hid_keyboard_event_t current; + memcpy(¤t.buffer, data, 8); + usb_hid_process_keyboard_event(kbd, ¤t); + kbd->previous = current; +} + +static void queue_interrupt_requests_locked(kbd_device_t* kbd) { + list_node_t* node; + while ((node = list_remove_head(&kbd->free_intr_reqs)) != NULL) { + usb_request_t* req = containerof(node, usb_request_t, node); + req->transfer_length = req->buffer_length; + mx_status_t status = kbd->device_protocol->queue_request(kbd->usb_device, req); + if (status != NO_ERROR) { + printf("interrupt queue failed %d\n", status); + list_add_head(&kbd->free_intr_reqs, &req->node); + break; + } + } +} + +static void usb_keyboard_interrupt_complete(usb_request_t* request) { + kbd_device_t* kbd = (kbd_device_t*)request->client_data; + + if (request->status == NO_ERROR && request->transfer_length == INTR_REQ_SIZE) { + usb_hid_keyboard_event_t current; + memcpy(¤t.buffer, request->buffer, INTR_REQ_SIZE); + usb_hid_process_keyboard_event(kbd, ¤t); + kbd->previous = current; + } + + pthread_mutex_lock(&kbd->mutex); + list_add_head(&kbd->free_intr_reqs, &request->node); + queue_interrupt_requests_locked(kbd); + pthread_mutex_unlock(&kbd->mutex); +} + +static int usb_hid_set_layout(const char* country) { + /* FIXME should be per keyboard */ + size_t i; + + for (i = 0; i < ARRAY_SIZE(keyboard_layouts); i++) { + if (strncmp(keyboard_layouts[i].country, country, + strlen(keyboard_layouts[i].country))) + continue; + + /* Found, changing keyboard layout */ + map = &keyboard_layouts[i]; + printf(" Keyboard layout '%s'\n", map->country); + return 0; + } + + printf(" Keyboard layout '%s' not found, using '%s'\n", + country, map->country); + + /* Nothing found, not changed */ + return -1; +} + +static mx_status_t usb_keyboard_probe(mx_driver_t* driver, mx_device_t* device) { + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + return ERR_NOT_SUPPORTED; + } + + usb_device_config_t* device_config; + mx_status_t status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + usb_configuration_t* config = &device_config->configurations[0]; + usb_interface_t* intf = &config->interfaces[0]; + usb_interface_descriptor_t* interface = intf->descriptor; + + if (!(device_config->descriptor->bDeviceClass == USB_CLASS_HID || + (device_config->descriptor->bDeviceClass == 0 && interface->bInterfaceClass == USB_CLASS_HID))) + return ERR_NOT_SUPPORTED; + if (interface->bInterfaceSubClass != hid_subclass_boot) + return ERR_NOT_SUPPORTED; + if (interface->bInterfaceProtocol != hid_boot_proto_keyboard) + return ERR_NOT_SUPPORTED; + return NO_ERROR; +} + +static ssize_t usb_keyboard_read(mx_device_t* dev, void* buf, size_t count) { + char* buffer = buf; + kbd_device_t* kbd = get_kbd_device(dev); + + pthread_mutex_lock(&kbd->mutex); + + while (kbd->key_buffer_count == 0) { + pthread_cond_wait(&kbd->cond, &kbd->mutex); + } + + if (count > kbd->key_buffer_count) { + count = kbd->key_buffer_count; + } + + for (size_t i = 0; i < count; i++) { + *buffer++ = kbd->key_buffer[kbd->key_buffer_head++]; + if (kbd->key_buffer_head == countof(kbd->key_buffer)) { + kbd->key_buffer_head = 0; + } + } + + kbd->key_buffer_count -= count; + + pthread_mutex_unlock(&kbd->mutex); + + return count; +} + +static ssize_t usb_keyboard_write(mx_device_t* dev, const void* buf, size_t count) { + return ERR_NOT_SUPPORTED; +} + +static mx_protocol_char_t usb_keyboard_char_proto = { + .read = usb_keyboard_read, + .write = usb_keyboard_write, +}; + +static mx_status_t usb_keyboard_open(mx_device_t* dev, uint32_t flags) { + return NO_ERROR; +} + +static mx_status_t usb_keyboard_close(mx_device_t* dev) { + return NO_ERROR; +} + +static mx_status_t usb_keyboard_release(mx_device_t* device) { + kbd_device_t* kbd = get_kbd_device(device); + pthread_mutex_destroy(&kbd->mutex); + pthread_cond_destroy(&kbd->cond); + free(kbd); + + return NO_ERROR; +} + +static mx_protocol_device_t usb_keyboard_device_proto = { + .get_protocol = device_base_get_protocol, + .open = usb_keyboard_open, + .close = usb_keyboard_close, + .release = usb_keyboard_release, +}; + +static mx_status_t usb_keyboard_bind(mx_driver_t* driver, mx_device_t* device) { + kbd_device_t* kbd = calloc(1, sizeof(kbd_device_t)); + if (!kbd) { + printf("Not enough memory for USB HID device.\n"); + return ERR_NO_MEMORY; + } + + list_initialize(&kbd->free_intr_reqs); + pthread_mutex_init(&kbd->mutex, NULL); + pthread_cond_init(&kbd->cond, NULL); + + mx_status_t status = device_init(&kbd->device, driver, "usb_keyboard", &usb_keyboard_device_proto); + if (status != NO_ERROR) { + free(kbd); + return status; + } + kbd->device.protocol_id = MX_PROTOCOL_CHAR; + kbd->device.protocol_ops = &usb_keyboard_char_proto; + + // FIXME - free kbd if errors occur + + usb_device_protocol_t* protocol; + if (device_get_protocol(device, MX_PROTOCOL_USB_DEVICE, (void**)&protocol)) { + free(kbd); + return ERR_NOT_SUPPORTED; + } + kbd->usb_device = device; + kbd->device_protocol = protocol; + + usb_device_config_t* device_config; + status = protocol->get_config(device, &device_config); + if (status < 0) + return status; + + usb_configuration_t* config = &device_config->configurations[0]; + usb_interface_t* intf = &config->interfaces[0]; + usb_interface_descriptor_t* interface = intf->descriptor; + + printf(" configuring...\n"); + protocol->control(device, (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE), SET_PROTOCOL, + hid_proto_boot, interface->bInterfaceNumber, NULL, 0); + protocol->control(device, (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE), SET_IDLE, + (KEYBOARD_REPEAT_MS >> 2) << 8, interface->bInterfaceNumber, NULL, 0); + printf(" activating...\n"); + + if (protocol->control(device, (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE), USB_REQ_GET_DESCRIPTOR, + (0x21 << 8 | 0), 0, &kbd->descriptor, sizeof(kbd->descriptor) != sizeof(kbd->descriptor))) { + printf("get_descriptor(HID) failed\n"); + return ERR_GENERIC; + } + unsigned int countrycode = kbd->descriptor.bCountryCode; + /* 35 countries defined: */ + if (countrycode >= ARRAY_SIZE(countries)) + countrycode = 0; + printf(" Keyboard has %s layout (country code %02x)\n", + countries[countrycode][0], countrycode); + + /* Set keyboard layout accordingly */ + usb_hid_set_layout(countries[countrycode][1]); + + int i; + for (i = 0; i < intf->num_endpoints; i++) { + if (intf->endpoints[i].type != USB_ENDPOINT_INTERRUPT) + continue; + if (intf->endpoints[i].direction != USB_ENDPOINT_IN) + continue; + break; + } + if (i >= intf->num_endpoints) { + printf("Could not find HID endpoint\n"); + return ERR_GENERIC; + } + printf(" found endpoint %x for interrupt-in\n", i); + /* 20 buffers of 8 bytes, for every 10 msecs */ + kbd->intr_ep = &intf->endpoints[i]; + printf(" configuration done.\n"); + + for (int i = 0; i < INTR_REQ_COUNT; i++) { + usb_request_t* req = protocol->alloc_request(device, kbd->intr_ep, INTR_REQ_SIZE); + if (!req) + return ERR_NO_MEMORY; + req->complete_cb = usb_keyboard_interrupt_complete; + req->client_data = kbd; + list_add_head(&kbd->free_intr_reqs, &req->node); + } + + pthread_mutex_lock(&kbd->mutex); + queue_interrupt_requests_locked(kbd); + pthread_mutex_unlock(&kbd->mutex); + + printf("kbd add %s to %s\n", kbd->device.name, device->name); + device_add(&kbd->device, device); + + return NO_ERROR; +} + +static mx_status_t usb_keyboard_unbind(mx_driver_t* drv, mx_device_t* dev) { + mx_device_t* child = NULL; + mx_device_t* temp = NULL; + list_for_every_entry_safe (&dev->device_list, child, temp, mx_device_t, node) { + device_remove(child); + } + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_USB_DEVICE, +}; + +mx_driver_t _driver_usb_keyboard BUILTIN_DRIVER = { + .name = "usb_keyboard", + .ops = { + .probe = usb_keyboard_probe, + .bind = usb_keyboard_bind, + .unbind = usb_keyboard_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/third_party/udev/usb_xhci/BUILD.gn b/third_party/udev/usb_xhci/BUILD.gn new file mode 100644 index 000000000..6cf877152 --- /dev/null +++ b/third_party/udev/usb_xhci/BUILD.gn @@ -0,0 +1,20 @@ +source_set("usb_xhci") { + sources = [ + "usb_poll.c", + "usb_xhci.c", + "xhci.c", + "xhci_commands.c", + "xhci_debug.c", + "xhci_devconf.c", + "xhci_events.c", + "xhci_private.h", + "xhci_rh.c", + ] + deps = [ + "//system/ulib/ddk", + "//system/ulib/magenta", + "//system/ulib/mxu", + "//system/ulib/runtime", + "//third_party/ulib/musl", + ] +} diff --git a/third_party/udev/usb_xhci/driver.mk b/third_party/udev/usb_xhci/driver.mk new file mode 100644 index 000000000..fee8ce1dc --- /dev/null +++ b/third_party/udev/usb_xhci/driver.mk @@ -0,0 +1,11 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +DRIVER_SRCS += \ + $(LOCAL_DIR)/usb_xhci.c \ + $(LOCAL_DIR)/usb_poll.c \ + $(LOCAL_DIR)/xhci.c \ + $(LOCAL_DIR)/xhci_commands.c \ + $(LOCAL_DIR)/xhci_debug.c \ + $(LOCAL_DIR)/xhci_devconf.c \ + $(LOCAL_DIR)/xhci_events.c \ + $(LOCAL_DIR)/xhci_rh.c diff --git a/third_party/udev/usb_xhci/usb_poll.c b/third_party/udev/usb_xhci/usb_poll.c new file mode 100644 index 000000000..c5a61c820 --- /dev/null +++ b/third_party/udev/usb_xhci/usb_poll.c @@ -0,0 +1,36 @@ +#include +#include + +#include "usb_poll.h" + +static list_node_t poll_list = LIST_INITIAL_VALUE(poll_list); +static bool started = false; + +void poll_add(poll_node_t* node, poll_cb* cb, void* context) { + node->cb = cb; + node->context = context; + list_add_head(&poll_list, &node->node); +} +void poll_remove(poll_node_t* node) { + list_delete(&node->node); +} + +static void* usb_poll_thread(void* arg) { + while (1) { + poll_node_t* poll; + poll_node_t* temp; + list_for_every_entry_safe (&poll_list, poll, temp, poll_node_t, node) { + poll->cb(poll->context); + } + usleep(1000); + } + return NULL; +} + +void usb_poll_start(void) { + if (!started) { + pthread_t tid; + pthread_create(&tid, NULL, usb_poll_thread, NULL); + started = true; + } +} \ No newline at end of file diff --git a/third_party/udev/usb_xhci/usb_poll.h b/third_party/udev/usb_xhci/usb_poll.h new file mode 100644 index 000000000..76df26a99 --- /dev/null +++ b/third_party/udev/usb_xhci/usb_poll.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +typedef void poll_cb(void* context); + +typedef struct poll_node { + list_node_t node; + poll_cb* cb; + void* context; +} poll_node_t; + +void poll_add(poll_node_t* node, poll_cb* db, void* context); +void poll_remove(poll_node_t* node); + +void usb_poll_start(void); diff --git a/third_party/udev/usb_xhci/usb_xhci.c b/third_party/udev/usb_xhci/usb_xhci.c new file mode 100644 index 000000000..a9a68a9af --- /dev/null +++ b/third_party/udev/usb_xhci/usb_xhci.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "xhci_private.h" + +/** + * Driver for USB XHCI controller. + */ + +static void* xhci_irq_thread(void* arg) { + usb_xhci_t* xhci = (usb_xhci_t*)arg; + printf("xhci_irq_thread start\n"); + + while (xhci->pci->pci_wait_interrupt(xhci->irq_handle) == NO_ERROR) { + printf("got interrupt\n"); + } + printf("xhci_irq_thread done\n"); + return NULL; +} + +static mx_status_t xhci_open(mx_device_t* dev, uint32_t flags) { + printf("xhci_open\n"); + return NO_ERROR; +} + +static mx_status_t xhci_close(mx_device_t* dev) { + printf("xhci_close\n"); + return NO_ERROR; +} + +static mx_status_t xhci_release(mx_device_t* dev) { + printf("xhci_release\n"); + return NO_ERROR; +} + +mx_status_t xhci_get_protocol(mx_device_t* dev, uint32_t proto_id, void** proto) { + if (proto_id == MX_PROTOCOL_USB_HCI) { + *proto = &_xhci_protocol; + return NO_ERROR; + } + if (proto_id == MX_PROTOCOL_USB_HUB) { + *proto = &xhci_rh_hub_protocol; + return NO_ERROR; + } + return ERR_NOT_SUPPORTED; +} + +static mx_protocol_device_t xhci_device_proto = { + .get_protocol = xhci_get_protocol, + .open = xhci_open, + .close = xhci_close, + .release = xhci_release, +}; + +static mx_status_t usb_xhci_probe(mx_driver_t* drv, mx_device_t* dev) { + pci_protocol_t* pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) { + return ERR_NOT_SUPPORTED; + } + + const pci_config_t* pci_config; + mx_status_t status; + mx_handle_t cfg_handle = pci->get_config(dev, &pci_config); + if (cfg_handle < 0) { + printf("usb_xhci_probe failed to map config (err = %d)\n", cfg_handle); + status = cfg_handle; + } else { + if (pci_config->base_class == 0x0c && + pci_config->sub_class == 0x03 && + pci_config->program_interface == 0x30) { + printf("probe found XHCI\n"); + status = NO_ERROR; + } else { + status = ERR_NOT_SUPPORTED; + } + + _magenta_handle_close(cfg_handle); + } + + return status; +} + +static mx_status_t usb_xhci_bind(mx_driver_t* drv, mx_device_t* dev) { + mx_handle_t irq_handle = MX_HANDLE_INVALID; + mx_handle_t mmio_handle = MX_HANDLE_INVALID; + mx_handle_t cfg_handle = MX_HANDLE_INVALID; + io_alloc_t* io_alloc = NULL; + usb_xhci_t* xhci = NULL; + + pci_protocol_t* pci; + if (device_get_protocol(dev, MX_PROTOCOL_PCI, (void**)&pci)) { + return ERR_NOT_SUPPORTED; + } + + mx_status_t status = pci->claim_device(dev); + if (status < 0) { + printf("usb_xhci_bind claim_device failed %d\n", status); + return status; + } + + const pci_config_t* pci_config; + cfg_handle = pci->get_config(dev, &pci_config); + if (cfg_handle < 0) { + printf("usb_xhci_bind failed to fetch PCI config (err %d)\n", cfg_handle); + status = cfg_handle; + goto error_return; + } + + // create an IO memory allocator + io_alloc = io_alloc_init(1024 * 1024); + + // find our bar + int bar = -1; + for (uint i = 0; i < countof(pci_config->base_addresses); i++) { + if (pci_config->base_addresses[i]) { + bar = i; + break; + } + } + if (bar == -1) { + printf("usb_xhci_bind could not find bar\n"); + status = ERR_NOT_VALID; + goto error_return; + } + + // map our MMIO + void* mmio; + uint64_t mmio_len; + mmio_handle = pci->map_mmio(dev, bar, MX_CACHE_POLICY_UNCACHED_DEVICE, &mmio, &mmio_len); + if (mmio_handle < 0) { + status = mmio_handle; + goto error_return; + } + + // enable bus master + status = pci->enable_bus_master(dev, true); + if (status < 0) { + printf("usb_xhci_bind enable_bus_master failed %d\n", status); + goto error_return; + } + + // register for interrupts + status = pci->map_interrupt(dev, 0); + printf("map_interrupt returned %d\n", status); + if (status < 0) { + printf("usb_xhci_bind map_interrupt failed %d\n", status); + goto error_return; + } + irq_handle = status; + + xhci = malloc(sizeof(usb_xhci_t)); + if (!xhci) { + status = ERR_NO_MEMORY; + goto error_return; + } + + xhci->io_alloc = io_alloc; + xhci->mmio = mmio; + xhci->mmio_len = mmio_len; + xhci->irq_handle = irq_handle; + xhci->mmio_handle = mmio_handle; + xhci->cfg_handle = cfg_handle; + xhci->pci = pci; + status = xhci_startup(xhci); + if (status < 0) + goto error_return; + + mx_device_t* hcidev = &xhci->hcidev; + status = device_init(hcidev, drv, "xhci_usb", &xhci_device_proto); + hcidev->protocol_id = MX_PROTOCOL_USB_HCI; + if (status < 0) + goto error_return; + + device_add(hcidev, dev); + + pthread_create(&xhci->irq_thread, NULL, xhci_irq_thread, xhci); + usb_poll_start(); + + return NO_ERROR; + +error_return: + if (xhci) + free(xhci); + if (io_alloc) + io_alloc_free(io_alloc); + if (irq_handle != MX_HANDLE_INVALID) + _magenta_handle_close(irq_handle); + if (mmio_handle != MX_HANDLE_INVALID) + _magenta_handle_close(mmio_handle); + if (cfg_handle != MX_HANDLE_INVALID) + _magenta_handle_close(cfg_handle); + return status; +} + +static mx_status_t usb_xhci_unbind(mx_driver_t* drv, mx_device_t* dev) { + mx_device_t* child = NULL; + mx_device_t* temp = NULL; + list_for_every_entry_safe (&dev->device_list, child, temp, mx_device_t, node) { + device_remove(child); + } + return NO_ERROR; +} + +static mx_driver_binding_t binding = { + .protocol_id = MX_PROTOCOL_PCI, +}; + +mx_driver_t _driver_usb_xhci BUILTIN_DRIVER = { + .name = "usb_xhci", + .ops = { + .probe = usb_xhci_probe, + .bind = usb_xhci_bind, + .unbind = usb_xhci_unbind, + }, + .binding = &binding, + .binding_count = 1, +}; diff --git a/third_party/udev/usb_xhci/xhci.c b/third_party/udev/usb_xhci/xhci.c new file mode 100644 index 000000000..075287b33 --- /dev/null +++ b/third_party/udev/usb_xhci/xhci.c @@ -0,0 +1,795 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2010 Patrick Georgi + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#define XHCI_DEBUG +//#define XHCI_SPEW_DEBUG + +#include +#include +#include +#include +#include +#include + +#include "xhci_private.h" + +#define EPO_BUFFER_SIZE 2048 + +static void xhci_start(xhci_t* xhci); +static void xhci_stop(xhci_t* xhci); +static void xhci_reset(xhci_t* xhci); +static void xhci_reinit(xhci_t* xhci); +static int xhci_queue_request(mx_device_t* hcidev, int devaddr, usb_request_t* request); +static int xhci_control(mx_device_t* hcidev, int devaddr, usb_setup_t* devreq, + int dalen, uint8_t* data); + +/* + * Some structures must not cross page boundaries. To get this, + * we align them by their size (or the next greater power of 2). + */ +void* xhci_align(xhci_t* xhci, const size_t min_align, const size_t size) { + size_t align; + if (!(size & (size - 1))) + align = size; /* It's a power of 2 */ + else + align = 1 << ((sizeof(unsigned) << 3) - __builtin_clz(size)); + if (align < min_align) + align = min_align; + xhci_spew("Aligning %zu to %zu\n", size, align); + return xhci_memalign(xhci, align, size); +} + +void xhci_clear_trb(trb_t* const trb, const int pcs) { + trb->ptr_low = 0; + trb->ptr_high = 0; + trb->status = 0; + trb->control = !pcs; +} + +void xhci_init_cycle_ring(xhci_t* const xhci, transfer_ring_t* const tr, const size_t ring_size) { + memset((void*)tr->ring, 0, ring_size * sizeof(*tr->ring)); + TRB_SET(TT, &tr->ring[ring_size - 1], TRB_LINK); + TRB_SET(TC, &tr->ring[ring_size - 1], 1); + /* only one segment that points to itself */ + tr->ring[ring_size - 1].ptr_low = xhci_virt_to_phys(xhci, (mx_vaddr_t)tr->ring); + + tr->pcs = 1; + tr->cur = tr->ring; +} + +static long +xhci_handshake(volatile uint32_t* const reg, uint32_t mask, uint32_t wait_for, long timeout_ms) { + while ((*reg & mask) != wait_for && timeout_ms--) + usleep(1000); + return timeout_ms; +} + +static int +xhci_wait_ready(xhci_t* const xhci) { + xhci_debug("Waiting for controller to be ready... "); + if (!xhci_handshake(&xhci->opreg->usbsts, USBSTS_CNR, 0, 100L)) { + xhci_debug("timeout!\n"); + return -1; + } + xhci_debug("ok.\n"); + return 0; +} + +usbdev_t* init_device_entry(usb_xhci_t* hci, int i) { + xhci_t* const xhci = &hci->xhci; + usbdev_t* dev = calloc(1, sizeof(usbdev_t)); + if (!dev) { + xhci_debug("no memory to allocate device structure\n"); + return NULL; + } + xhci->devices[i] = dev; + dev->address = -1; + dev->hub = -1; + dev->port = -1; + dev->hci = hci; + list_initialize(&dev->req_queue); + + return dev; +} + +usb_request_t* xhci_alloc_request(mx_device_t* device, uint16_t length) { + xhci_t* const xhci = get_xhci(device); + usb_request_t* request = calloc(1, sizeof(usb_request_t)); + if (!request) + return NULL; + // buffers need not be aligned, but 64 byte alignment gives better performance + request->buffer = (uint8_t*)xhci_memalign(xhci, 64, length); + if (!request->buffer) { + printf("could not allocate request buffer\n"); + free(request); + return NULL; + } + request->buffer_length = length; + return request; +} + +void xhci_free_request(mx_device_t* device, usb_request_t* request) { + xhci_t* const xhci = get_xhci(device); + if (request) { + if (request->buffer) { + xhci_free(xhci, request->buffer); + } + free(request); + } +} + +void xhci_set_bus_device(mx_device_t* hcidev, mx_device_t* busdev) { + xhci_t* const xhci = get_xhci(hcidev); + if (busdev) { + xhci->bus_device = busdev; + device_get_protocol(busdev, MX_PROTOCOL_USB_BUS, (void**)&xhci->bus_protocol); + } else { + xhci->bus_device = NULL; + xhci->bus_protocol = NULL; + } +} + +usb_hci_protocol_t _xhci_protocol = { + .alloc_request = xhci_alloc_request, + .free_request = xhci_free_request, + .queue_request = xhci_queue_request, + .control = xhci_control, + .set_address = xhci_set_address, + .finish_device_config = xhci_finish_device_config, + .destroy_device = xhci_destroy_dev, + .set_bus_device = xhci_set_bus_device, +}; + +static void xhci_poll(void* context) { + xhci_t* xhci = (xhci_t*)context; + list_node_t completed_reqs; + + xhci_rh_check_status_changed(xhci); + + mxr_mutex_lock(&xhci->mutex); + xhci_handle_events(xhci); + // move contents of xhci->completed_reqs to a local list within the mutex + if (list_is_empty(&xhci->completed_reqs)) { + list_initialize(&completed_reqs); + } else { + xhci->completed_reqs.next->prev = &completed_reqs; + xhci->completed_reqs.prev->next = &completed_reqs; + completed_reqs.prev = xhci->completed_reqs.prev; + completed_reqs.next = xhci->completed_reqs.next; + + list_initialize(&xhci->completed_reqs); + } + mxr_mutex_unlock(&xhci->mutex); + + usb_request_t* request; + usb_request_t* prev; + list_for_every_entry_safe (&completed_reqs, request, prev, usb_request_t, node) { + list_delete(&request->node); + request->complete_cb(request); + } +} + +mx_status_t xhci_startup(usb_xhci_t* uxhci) { + xhci_debug("xhci_pci_startup\n"); + + xhci_t* xhci = &uxhci->xhci; + memset(xhci, 0, sizeof(*xhci)); + + xhci->io_alloc = io_alloc_init(1024 * 1024); + if (!xhci->io_alloc) + return ERR_NO_MEMORY; + xhci->ep0_buffer = xhci_malloc(xhci, EPO_BUFFER_SIZE); + + //FIXME roothub parent? + usbdev_t* rhdev = init_device_entry(uxhci, 0); + xhci->roothub = rhdev; + xhci->cr.ring = xhci_align(xhci, 64, COMMAND_RING_SIZE * sizeof(trb_t)); + xhci->er.ring = xhci_align(xhci, 64, EVENT_RING_SIZE * sizeof(trb_t)); + xhci->ev_ring_table = xhci_align(xhci, 64, sizeof(erst_entry_t)); + if (!xhci->roothub || !xhci->cr.ring || + !xhci->er.ring || !xhci->ev_ring_table) { + xhci_debug("Out of memory\n"); + goto _free_xhci; + } + + xhci->capreg = uxhci->mmio; + xhci->opreg = ((void*)xhci->capreg) + xhci->capreg->caplength; + xhci->hcrreg = ((void*)xhci->capreg) + xhci->capreg->rtsoff; + xhci->dbreg = ((void*)xhci->capreg) + xhci->capreg->dboff; + xhci_debug("caplen: 0x%" PRIx32 "\n", xhci->capreg->caplength); + xhci_debug("rtsoff: 0x%" PRIx32 "\n", xhci->capreg->rtsoff); + xhci_debug("dboff: 0x%" PRIx32 "\n", xhci->capreg->dboff); + + xhci_debug("hciversion: %0x.%02x\n", + xhci->capreg->hciver_hi, xhci->capreg->hciver_lo); + if ((xhci->capreg->hciversion < 0x96) || + (xhci->capreg->hciversion > 0x100)) { + xhci_debug("Unsupported xHCI version\n"); + goto _free_xhci; + } + + xhci_debug("context size: %dB\n", CTXSIZE(xhci)); + xhci_debug("maxslots: 0x%02x\n", xhci->capreg->MaxSlots); + xhci_debug("maxports: 0x%02x\n", xhci->capreg->MaxPorts); + const unsigned pagesize = xhci->opreg->pagesize << 12; + xhci_debug("pagesize: 0x%04x\n", pagesize); + + /* + * We haven't touched the hardware yet. So we allocate all dynamic + * structures at first and can still chicken out easily if we run out + * of memory. + */ + xhci->max_slots_en = xhci->capreg->MaxSlots & CONFIG_LP_MASK_MaxSlotsEn; + xhci->dcbaa = xhci_align(xhci, 64, (xhci->max_slots_en + 1) * sizeof(uint64_t)); + xhci->dev = malloc((xhci->max_slots_en + 1) * sizeof(*xhci->dev)); + if (!xhci->dcbaa || !xhci->dev) { + xhci_debug("Out of memory\n"); + goto _free_xhci; + } + memset(xhci->dcbaa, 0x00, (xhci->max_slots_en + 1) * sizeof(uint64_t)); + memset(xhci->dev, 0x00, (xhci->max_slots_en + 1) * sizeof(*xhci->dev)); + + /* + * Let dcbaa[0] point to another array of pointers, sp_ptrs. + * The pointers therein point to scratchpad buffers (pages). + */ + const size_t max_sp_bufs = xhci->capreg->Max_Scratchpad_Bufs_Hi << 5 | + xhci->capreg->Max_Scratchpad_Bufs_Lo; + xhci_debug("max scratchpad bufs: 0x%zx\n", max_sp_bufs); + if (max_sp_bufs) { + const size_t sp_ptrs_size = max_sp_bufs * sizeof(uint64_t); + xhci->sp_ptrs = xhci_align(xhci, 64, sp_ptrs_size); + if (!xhci->sp_ptrs) { + xhci_debug("Out of memory\n"); + goto _free_xhci_structs; + } + memset(xhci->sp_ptrs, 0x00, sp_ptrs_size); + for (size_t i = 0; i < max_sp_bufs; ++i) { + /* Could use mmap() here if we had it. + Maybe there is another way. */ + void* const page = xhci_memalign(xhci, pagesize, pagesize); + if (!page) { + xhci_debug("Out of memory\n"); + goto _free_xhci_structs; + } + xhci->sp_ptrs[i] = xhci_virt_to_phys(xhci, (mx_vaddr_t)page); + } + xhci->dcbaa[0] = xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->sp_ptrs); + } + + /* Now start working on the hardware */ + if (xhci_wait_ready(xhci)) { + goto _free_xhci_structs; + } + + /* TODO: Check if BIOS claims ownership (and hand over) */ + + xhci_reset(xhci); + xhci_reinit(xhci); + + xhci_rh_init(uxhci); + list_initialize(&xhci->completed_reqs); + poll_add(&xhci->poll_node, xhci_poll, xhci); + + return NO_ERROR; + +_free_xhci_structs: + if (xhci->sp_ptrs) { + for (size_t i = 0; i < max_sp_bufs; ++i) { + if (xhci->sp_ptrs[i]) + xhci_free_phys(xhci, xhci->sp_ptrs[i]); + } + } + free(xhci->sp_ptrs); + free(xhci->dcbaa); +_free_xhci: + xhci_free(xhci, (void*)xhci->ev_ring_table); + xhci_free(xhci, (void*)xhci->er.ring); + xhci_free(xhci, (void*)xhci->cr.ring); + free(xhci->roothub); + free(xhci->dev); + free(xhci); + /* _free_controller: */ + xhci_destroy_dev(&uxhci->hcidev, 0); + + return -1; +} + +static void +xhci_reset(xhci_t* const xhci) { + xhci_stop(xhci); + + xhci->opreg->usbcmd |= USBCMD_HCRST; + +/* Existing Intel xHCI controllers require a delay of 1 ms, + * after setting the CMD_RESET bit, and before accessing any + * HC registers. This allows the HC to complete the + * reset operation and be ready for HC register access. + * Without this delay, the subsequent HC register access, + * may result in a system hang very rarely. + */ +#if ARCH_X86_32 || ARCH_X86_64 + usleep(1000); +#endif + + xhci_debug("Resetting controller... "); + if (!xhci_handshake(&xhci->opreg->usbcmd, USBCMD_HCRST, 0, 1000L)) + xhci_debug("timeout!\n"); + else + xhci_debug("ok.\n"); +} + +static void +xhci_reinit(xhci_t* xhci) { + if (xhci_wait_ready(xhci)) + return; + + /* Enable all available slots */ + xhci->opreg->config = xhci->max_slots_en; + + /* Set DCBAA */ + xhci->opreg->dcbaap_lo = xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->dcbaa); + xhci->opreg->dcbaap_hi = 0; + + /* Initialize command ring */ + xhci_init_cycle_ring(xhci, &xhci->cr, COMMAND_RING_SIZE); + xhci_debug("command ring @%p (%p)\n", + xhci->cr.ring, (void*)xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->cr.ring)); + xhci->opreg->crcr_lo = xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->cr.ring) | CRCR_RCS; + xhci->opreg->crcr_hi = 0; + + /* Make sure interrupts are enabled */ + xhci->opreg->usbcmd |= USBCMD_INTE; + + /* Initialize event ring */ + xhci_reset_event_ring(&xhci->er); + xhci_debug("event ring @%p (%p)\n", + xhci->er.ring, (void*)xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->er.ring)); + xhci_debug("ERST Max: 0x%x -> 0x%x entries\n", + xhci->capreg->ERST_Max, 1 << xhci->capreg->ERST_Max); + memset((void*)xhci->ev_ring_table, 0x00, sizeof(erst_entry_t)); + xhci->ev_ring_table[0].seg_base_lo = xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->er.ring); + xhci->ev_ring_table[0].seg_base_hi = 0; + xhci->ev_ring_table[0].seg_size = EVENT_RING_SIZE; + + /* pass event ring table to hardware */ + wmb(); + /* Initialize primary interrupter */ + xhci->hcrreg->intrrs[0].erstsz = 1; + xhci_update_event_dq(xhci); + /* erstba has to be written at last */ + xhci->hcrreg->intrrs[0].erstba_lo = xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->ev_ring_table); + xhci->hcrreg->intrrs[0].erstba_hi = 0; + + /* enable interrupts */ + // xhci->hcrreg->intrrs[0].iman |= IMAN_IE; + + xhci_start(xhci); + +#ifdef USB_DEBUG + int i; + for (i = 0; i < 32; ++i) { + xhci_debug("NOOP run #%d\n", i); + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_NOOP); + + xhci_post_command(xhci); + + /* Wait for result in event ring */ + xhci_wait_for_command_done(xhci, cmd, 1); + xhci_debug("Command ring is %srunning\n", + (xhci->opreg->crcr_lo & CRCR_CRR) ? "" : "not "); + } +#endif +} + +/* FIXME +static void +xhci_shutdown(hci_t *const controller) +{ + int i; + + if (controller == 0) + return; + + detach_controller(controller); + + xhci_t *const xhci = XHCI_INST(controller); + xhci_stop(controller); + + if (xhci->sp_ptrs) { + size_t max_sp_bufs = xhci->capreg->Max_Scratchpad_Bufs_Hi << 5 | + xhci->capreg->Max_Scratchpad_Bufs_Lo; + for (i = 0; i < max_sp_bufs; ++i) { + if (xhci->sp_ptrs[i]) + xhci_free_phys(xhci, xhci->sp_ptrs[i]); + } + } + xhci_free(xhci, xhci->sp_ptrs); + xhci_free(xhci, xhci->dcbaa); + free(xhci->dev); + xhci_free(xhci, (void *)xhci->ev_ring_table); + xhci_free(xhci, (void *)xhci->er.ring); + xhci_free(xhci, (void *)xhci->cr.ring); + xhci_free(xhci, (void *)xhci->ep0_buffer); + io_alloc_free(xhci->io_alloc); + free(xhci); + free(controller); +} +*/ + +static void +xhci_start(xhci_t* xhci) { + xhci->opreg->usbcmd |= USBCMD_RS; + if (!xhci_handshake(&xhci->opreg->usbsts, USBSTS_HCH, 0, 1000L)) + xhci_debug("Controller didn't start within 1s\n"); +} + +static void +xhci_stop(xhci_t* xhci) { + xhci->opreg->usbcmd &= ~USBCMD_RS; + if (!xhci_handshake(&xhci->opreg->usbsts, + USBSTS_HCH, USBSTS_HCH, 1000L)) + xhci_debug("Controller didn't halt within 1s\n"); +} + +static int +xhci_reset_endpoint(xhci_t* xhci, int slot_id, usb_endpoint_t* const ep) { + const int ep_id = ep ? xhci_ep_id(ep) : 1; + epctx_t* const epctx = xhci->dev[slot_id].ctx.ep[ep_id]; + + xhci_debug("Resetting ID %d EP %d (ep state: %d)\n", + slot_id, ep_id, EC_GET(STATE, epctx)); + + /* Run Reset Endpoint Command if the EP is in Halted state */ + if (EC_GET(STATE, epctx) == 2) { + const int cc = xhci_cmd_reset_endpoint(xhci, slot_id, ep_id); + if (cc != CC_SUCCESS) { + xhci_debug("Reset Endpoint Command failed: %d\n", cc); + return 1; + } + } + + /* Clear TT buffer for bulk and control endpoints behind a TT */ + usbdev_t* dev = xhci->devices[slot_id]; + const int hub = dev->hub; + if (hub && dev->speed < HIGH_SPEED && + xhci->devices[hub]->speed == HIGH_SPEED) { + /* TODO */; + } + + /* Reset transfer ring if the endpoint is in the right state */ + const unsigned ep_state = EC_GET(STATE, epctx); + if (ep_state == 3 || ep_state == 4) { + transfer_ring_t* const tr = + xhci->dev[slot_id].transfer_rings[ep_id]; + const int cc = xhci_cmd_set_tr_dq(xhci, slot_id, ep_id, + tr->ring, 1); + if (cc != CC_SUCCESS) { + xhci_debug("Set TR Dequeue Command failed: %d\n", cc); + return 1; + } + xhci_init_cycle_ring(xhci, tr, TRANSFER_RING_SIZE); + } + + xhci_debug("Finished resetting ID %d EP %d (ep state: %d)\n", + slot_id, ep_id, EC_GET(STATE, epctx)); + + return 0; +} + +static void +xhci_enqueue_trb(xhci_t* const xhci, transfer_ring_t* const tr) { + const int chain = TRB_GET(CH, tr->cur); + TRB_SET(C, tr->cur, tr->pcs); + ++tr->cur; + + while (TRB_GET(TT, tr->cur) == TRB_LINK) { + xhci_spew("Handling LINK pointer\n"); + const int tc = TRB_GET(TC, tr->cur); + TRB_SET(CH, tr->cur, chain); + wmb(); + TRB_SET(C, tr->cur, tr->pcs); + tr->cur = (trb_t*)xhci_phys_to_virt(xhci, tr->cur->ptr_low); + if (tc) + tr->pcs ^= 1; + } +} + +static trb_t* +xhci_enqueue_td(xhci_t* const xhci, transfer_ring_t* const tr, const int ep, const size_t mps, + const int dalen, void* const data, const int dir) { + trb_t* trb = NULL; /* cur TRB */ + uint8_t* cur_start = data; /* cur data pointer */ + size_t length = dalen; /* remaining bytes */ + size_t packets = (length + mps - 1) / mps; /* remaining packets */ + size_t residue = 0; /* residue from last TRB */ + size_t trb_count = 0; /* TRBs added so far */ + + while (length || !trb_count /* enqueue at least one */) { + const size_t cur_end = ((size_t)cur_start + 0x10000) & ~0xffff; + size_t cur_length = cur_end - (size_t)cur_start; + if (length < cur_length) { + cur_length = length; + packets = 0; + length = 0; + } else if (1 /* !IS_ENABLED(CONFIG_LP_USB_XHCI_MTK_QUIRK) */) { + packets -= (residue + cur_length) / mps; + residue = (residue + cur_length) % mps; + length -= cur_length; + } + + trb = tr->cur; + xhci_clear_trb(trb, tr->pcs); + trb->ptr_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)cur_start); + TRB_SET(TL, trb, cur_length); + TRB_SET(TDS, trb, MIN(TRB_MAX_TD_SIZE, packets)); + TRB_SET(CH, trb, 1); + + if (length && 0 /* IS_ENABLED(CONFIG_LP_USB_XHCI_MTK_QUIRK) */) { + /* + * For MTK's xHCI controller, TDS defines a number of + * packets that remain to be transferred for a TD after + * processing all Max packets in all previous TRBs, that + * means don't include the current TRB's. + */ + packets -= (residue + cur_length) / mps; + residue = (residue + cur_length) % mps; + length -= cur_length; + } + + /* Check for first, data stage TRB */ + if (!trb_count && ep == 1) { + TRB_SET(DIR, trb, dir); + TRB_SET(TT, trb, TRB_DATA_STAGE); + } else { + TRB_SET(TT, trb, TRB_NORMAL); + } + /* + * This is a workaround for Synopsys DWC3. If the ENT flag is + * not set for the Normal and Data Stage TRBs. We get Event TRB + * with length 0x20d from the controller when we enqueue a TRB + * for the IN endpoint with length 0x200. + */ + if (!length) + TRB_SET(ENT, trb, 1); + + xhci_enqueue_trb(xhci, tr); + + cur_start += cur_length; + ++trb_count; + } + + trb = tr->cur; + xhci_clear_trb(trb, tr->pcs); + trb->ptr_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)trb); /* for easier debugging only */ + TRB_SET(TT, trb, TRB_EVENT_DATA); + TRB_SET(IOC, trb, 1); + + xhci_enqueue_trb(xhci, tr); + return trb; +} + +static int +xhci_control(mx_device_t* hcidev, int devaddr, usb_setup_t* const devreq, + const int dalen, unsigned char* const src) { + xhci_spew("xhci_control %02X %02X %04X %04X %04X\n", devreq->bmRequestType, devreq->bRequest, + devreq->wValue, devreq->wIndex, devreq->wLength); + unsigned char* data = src; + xhci_t* const xhci = get_xhci(hcidev); + epctx_t* const epctx = xhci->dev[devaddr].ctx.ep0; + transfer_ring_t* const tr = xhci->dev[devaddr].transfer_rings[1]; + bool out = ((devreq->bmRequestType & USB_DIR_MASK) == USB_DIR_OUT); + + const size_t off = (size_t)data & 0xffff; + if ((off + dalen) > ((TRANSFER_RING_SIZE - 4) << 16)) { + xhci_debug("Unsupported transfer size\n"); + return -1; + } + + mxr_mutex_lock(&xhci->mutex); + + if (dalen > 0) { + data = xhci->ep0_buffer; + if (dalen > EPO_BUFFER_SIZE) { + xhci_debug("Control transfer too large: %d\n", dalen); + mxr_mutex_unlock(&xhci->mutex); + return -1; + } + if (out) + memcpy(data, src, dalen); + } + + /* Reset endpoint if it's not running */ + const unsigned ep_state = EC_GET(STATE, epctx); + if (ep_state > 1) { + if (xhci_reset_endpoint(xhci, devaddr, NULL)) { + mxr_mutex_unlock(&xhci->mutex); + return -1; + } + } + + /* Fill and enqueue setup TRB */ + trb_t* const setup = tr->cur; + xhci_clear_trb(setup, tr->pcs); + setup->ptr_low = ((uint32_t*)devreq)[0]; + setup->ptr_high = ((uint32_t*)devreq)[1]; + TRB_SET(TL, setup, 8); + TRB_SET(TRT, setup, (dalen) + ? (out ? TRB_TRT_OUT_DATA : TRB_TRT_IN_DATA) + : TRB_TRT_NO_DATA); + TRB_SET(TT, setup, TRB_SETUP_STAGE); + TRB_SET(IDT, setup, 1); + TRB_SET(IOC, setup, 1); + xhci_enqueue_trb(xhci, tr); + + /* Fill and enqueue data TRBs (if any) */ + if (dalen) { + const unsigned mps = EC_GET(MPS, epctx); + const unsigned dt_dir = out ? TRB_DIR_OUT : TRB_DIR_IN; + xhci_enqueue_td(xhci, tr, 1, mps, dalen, data, dt_dir); + } + + /* Fill status TRB */ + trb_t* const status = tr->cur; + xhci_clear_trb(status, tr->pcs); + TRB_SET(DIR, status, out ? TRB_DIR_IN : TRB_DIR_OUT); + TRB_SET(TT, status, TRB_STATUS_STAGE); + TRB_SET(IOC, status, 1); + xhci_enqueue_trb(xhci, tr); + + /* Ring doorbell for EP0 */ + xhci->dbreg[devaddr] = 1; + + /* Wait for transfer events */ + int i, transferred = 0; + const int n_stages = 2 + !!dalen; + for (i = 0; i < n_stages; ++i) { + const int ret = xhci_wait_for_transfer(xhci, devaddr, 1); + transferred += ret; + if (ret < 0) { + if (ret == TIMEOUT) { + xhci_debug("Stopping ID %d EP 1\n", + devaddr); + xhci_cmd_stop_endpoint(xhci, devaddr, 1); + } + xhci_debug( + "Stage %d/%d failed: %d\n" + " trb ring: @%p\n" + " setup trb: @%p\n" + " status trb: @%p\n" + " ep state: %d -> %d\n" + " usbsts: 0x%08" PRIx32 "\n", + i, n_stages, ret, + tr->ring, setup, status, + ep_state, EC_GET(STATE, epctx), + xhci->opreg->usbsts); + mxr_mutex_unlock(&xhci->mutex); + return ret; + } + } + + if (!out && data != src) + memcpy(src, data, transferred); + mxr_mutex_unlock(&xhci->mutex); + return transferred; +} + +int xhci_get_descriptor(usbdev_t* dev, int rtype, int desc_type, int desc_idx, + void* data, size_t len) { + usb_setup_t dr; + + dr.bmRequestType = rtype; + dr.bRequest = USB_REQ_GET_DESCRIPTOR; + dr.wValue = desc_type << 8 | desc_idx; + dr.wIndex = 0; + dr.wLength = len; + + return xhci_control(&dev->hci->hcidev, dev->address, &dr, len, data); +} + +static int +xhci_queue_request(mx_device_t* hcidev, int slot_id, usb_request_t* request) { + if (request->endpoint->type != USB_ENDPOINT_BULK && request->endpoint->type != USB_ENDPOINT_INTERRUPT) { + return ERR_NOT_SUPPORTED; + } + + xhci_t* xhci = get_xhci(hcidev); + uint8_t* data = request->buffer; + size_t size = request->transfer_length; + usb_endpoint_t* ep = request->endpoint; + + const int ep_id = xhci_ep_id(ep); + epctx_t* const epctx = xhci->dev[slot_id].ctx.ep[ep_id]; + transfer_ring_t* const tr = xhci->dev[slot_id].transfer_rings[ep_id]; + + const size_t off = (size_t)data & 0xffff; + if ((off + request->transfer_length) > ((TRANSFER_RING_SIZE - 2) << 16)) { + xhci_debug("Unsupported transfer size\n"); + return ERR_TOO_BIG; + } + + mxr_mutex_lock(&xhci->mutex); + + /* Reset endpoint if it's not running */ + const unsigned ep_state = EC_GET(STATE, epctx); + if (ep_state > 1) { + if (xhci_reset_endpoint(xhci, slot_id, ep)) { + mxr_mutex_unlock(&xhci->mutex); + return ERR_OFFLINE; + } + } + + /* Enqueue transfer and ring doorbell */ + const unsigned mps = EC_GET(MPS, epctx); + const unsigned dir = (ep->direction == USB_ENDPOINT_OUT) ? TRB_DIR_OUT : TRB_DIR_IN; + request->driver_data = (void*)xhci_enqueue_td(xhci, tr, ep_id, mps, size, data, dir); + xhci->dbreg[slot_id] = ep_id; + + list_add_tail(&xhci->devices[slot_id]->req_queue, &request->node); + + mxr_mutex_unlock(&xhci->mutex); + return NO_ERROR; +} + +static trb_t* +xhci_next_trb(xhci_t* const xhci, trb_t* cur, int* const pcs) { + ++cur; + while (TRB_GET(TT, cur) == TRB_LINK) { + if (pcs && TRB_GET(TC, cur)) + *pcs ^= 1; + cur = (trb_t*)xhci_phys_to_virt(xhci, cur->ptr_low); + } + return cur; +} + +mx_paddr_t xhci_virt_to_phys(xhci_t* const xhci, mx_vaddr_t addr) { + return io_virt_to_phys(xhci->io_alloc, addr); +} + +mx_vaddr_t xhci_phys_to_virt(xhci_t* const xhci, mx_paddr_t addr) { + return io_phys_to_virt(xhci->io_alloc, addr); +} + +void* xhci_malloc(xhci_t* const xhci, size_t size) { + return io_malloc(xhci->io_alloc, size); +} + +void* xhci_memalign(xhci_t* const xhci, size_t alignment, size_t size) { + return io_memalign(xhci->io_alloc, alignment, size); +} + +void xhci_free(xhci_t* const xhci, void* addr) { + io_free(xhci->io_alloc, addr); +} + +void xhci_free_phys(xhci_t* const xhci, mx_paddr_t addr) { + io_free(xhci->io_alloc, (void*)io_phys_to_virt(xhci->io_alloc, addr)); +} diff --git a/third_party/udev/usb_xhci/xhci_commands.c b/third_party/udev/usb_xhci/xhci_commands.c new file mode 100644 index 000000000..17bc67d0c --- /dev/null +++ b/third_party/udev/usb_xhci/xhci_commands.c @@ -0,0 +1,187 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include "xhci_private.h" + +trb_t* +xhci_next_command_trb(xhci_t* const xhci) { + xhci_clear_trb(xhci->cr.cur, xhci->cr.pcs); + return xhci->cr.cur; +} + +void xhci_post_command(xhci_t* const xhci) { + xhci_debug("Command %d (@%p)\n", + TRB_GET(TT, xhci->cr.cur), xhci->cr.cur); + + TRB_SET(C, xhci->cr.cur, xhci->cr.pcs); + ++xhci->cr.cur; + + /* pass command trb to hardware */ + wmb(); + /* Ring the doorbell */ + xhci->dbreg[0] = 0; + + while (TRB_GET(TT, xhci->cr.cur) == TRB_LINK) { + xhci_debug("Handling LINK pointer (@%p)\n", xhci->cr.cur); + const int tc = TRB_GET(TC, xhci->cr.cur); + TRB_SET(C, xhci->cr.cur, xhci->cr.pcs); + xhci->cr.cur = (trb_t*)xhci_phys_to_virt(xhci, (mx_paddr_t)xhci->cr.cur->ptr_low); + if (tc) + xhci->cr.pcs ^= 1; + } +} + +static int +xhci_wait_for_command(xhci_t* const xhci, + const trb_t* const cmd_trb, + const int clear_event) { + int cc; + + cc = xhci_wait_for_command_done(xhci, cmd_trb, clear_event); + if (cc != TIMEOUT) + return cc; + + /* Abort command on timeout */ + xhci_debug("Aborting command (@%p), CRCR: 0x%x\n", + cmd_trb, xhci->opreg->crcr_lo); + xhci->opreg->crcr_lo |= CRCR_CS | CRCR_CA; + xhci->opreg->crcr_hi = 0; + cc = xhci_wait_for_command_aborted(xhci, cmd_trb); + + if (xhci->opreg->crcr_lo & CRCR_CRR) { + printf("xhci_wait_for_command: Command ring still running\n"); + exit(-1); + } + + return cc; +} + +/* + * xhci_cmd_* return >= 0: xhci completion code (cc) + * < 0: driver error code + */ + +int xhci_cmd_enable_slot(xhci_t* const xhci, int* const slot_id) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_ENABLE_SLOT); + xhci_post_command(xhci); + + int cc = xhci_wait_for_command(xhci, cmd, 0); + if (cc >= 0) { + if (cc == CC_SUCCESS) { + *slot_id = TRB_GET(ID, xhci->er.cur); + if (*slot_id > xhci->max_slots_en) + cc = CONTROLLER_ERROR; + } + xhci_advance_event_ring(xhci); + // xhci_handle_events_locked(xhci, NULL); + } + return cc; +} + +int xhci_cmd_disable_slot(xhci_t* const xhci, const int slot_id) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_DISABLE_SLOT); + TRB_SET(ID, cmd, slot_id); + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} + +int xhci_cmd_address_device(xhci_t* const xhci, + const int slot_id, + inputctx_t* const ic) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_ADDRESS_DEV); + TRB_SET(ID, cmd, slot_id); + cmd->ptr_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)ic->raw); + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} + +int xhci_cmd_configure_endpoint(xhci_t* const xhci, + const int slot_id, + const int config_id, + inputctx_t* const ic) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_CONFIGURE_EP); + TRB_SET(ID, cmd, slot_id); + cmd->ptr_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)ic->raw); + if (config_id == 0) + TRB_SET(DC, cmd, 1); + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} + +int xhci_cmd_evaluate_context(xhci_t* const xhci, + const int slot_id, + inputctx_t* const ic) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_EVAL_CTX); + TRB_SET(ID, cmd, slot_id); + cmd->ptr_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)ic->raw); + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} + +int xhci_cmd_reset_endpoint(xhci_t* const xhci, const int slot_id, const int ep) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_RESET_EP); + TRB_SET(ID, cmd, slot_id); + TRB_SET(EP, cmd, ep); + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} + +int xhci_cmd_stop_endpoint(xhci_t* const xhci, const int slot_id, const int ep) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_STOP_EP); + TRB_SET(ID, cmd, slot_id); + TRB_SET(EP, cmd, ep); + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} + +int xhci_cmd_set_tr_dq(xhci_t* const xhci, const int slot_id, const int ep, + trb_t* const dq_trb, const int dcs) { + trb_t* const cmd = xhci_next_command_trb(xhci); + TRB_SET(TT, cmd, TRB_CMD_SET_TR_DQ); + TRB_SET(ID, cmd, slot_id); + TRB_SET(EP, cmd, ep); + cmd->ptr_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)dq_trb) | dcs; + xhci_post_command(xhci); + + return xhci_wait_for_command(xhci, cmd, 1); +} diff --git a/third_party/udev/usb_xhci/xhci_debug.c b/third_party/udev/usb_xhci/xhci_debug.c new file mode 100644 index 000000000..e0e2206ac --- /dev/null +++ b/third_party/udev/usb_xhci/xhci_debug.c @@ -0,0 +1,123 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include "xhci_private.h" + +#ifdef XHCI_DUMPS + +void xhci_dump_slotctx(const slotctx_t* const sc) { + xhci_debug("Slot Context (@%p):\n", sc); + xhci_debug(" FIELD1\t0x%08" PRIx32 "\n", sc->f1); + xhci_debug(" FIELD2\t0x%08" PRIx32 "\n", sc->f2); + xhci_debug(" FIELD3\t0x%08" PRIx32 "\n", sc->f3); + xhci_debug(" FIELD4\t0x%08" PRIx32 "\n", sc->f4); + SC_DUMP(ROUTE, sc); + SC_DUMP(SPEED1, sc); + SC_DUMP(MTT, sc); + SC_DUMP(HUB, sc); + SC_DUMP(CTXENT, sc); + SC_DUMP(RHPORT, sc); + SC_DUMP(NPORTS, sc); + SC_DUMP(TTID, sc); + SC_DUMP(TTPORT, sc); + SC_DUMP(TTT, sc); + SC_DUMP(UADDR, sc); + SC_DUMP(STATE, sc); +} + +void xhci_dump_epctx(const epctx_t* const ec) { + xhci_debug("Endpoint Context (@%p):\n", ec); + xhci_debug(" FIELD1\t0x%08" PRIx32 "\n", ec->f1); + xhci_debug(" FIELD2\t0x%08" PRIx32 "\n", ec->f2); + xhci_debug(" TRDQ_L\t0x%08" PRIx32 "\n", ec->tr_dq_low); + xhci_debug(" TRDQ_H\t0x%08" PRIx32 "\n", ec->tr_dq_high); + xhci_debug(" FIELD5\t0x%08" PRIx32 "\n", ec->f5); + EC_DUMP(STATE, ec); + EC_DUMP(INTVAL, ec); + EC_DUMP(CERR, ec); + EC_DUMP(TYPE, ec); + EC_DUMP(MBS, ec); + EC_DUMP(MPS, ec); + EC_DUMP(DCS, ec); + EC_DUMP(AVRTRB, ec); + EC_DUMP(MXESIT, ec); +} + +void xhci_dump_devctx(const devctx_t* const dc, const u32 ctx_mask) { + int i; + if (ctx_mask & 1) + xhci_dump_slotctx(dc->slot); + for (i = 1; i <= SC_GET(CTXENT, dc->slot); ++i) { + if (ctx_mask & (1 << i)) + xhci_dump_epctx(dc->ep[i]); + } +} + +void xhci_dump_inputctx(const inputctx_t* const ic) { + xhci_debug("Input Control add: 0x%08" PRIx32 "\n", *ic->add); + xhci_debug("Input Control drop: 0x%08" PRIx32 "\n", *ic->drop); + xhci_dump_devctx(&ic->dev, *ic->add); +} + +void xhci_dump_transfer_trb(const trb_t* const cur) { + xhci_debug("Transfer TRB (@%p):\n", cur); + xhci_debug(" PTR_L\t0x%08" PRIx32 "\n", cur->ptr_low); + xhci_debug(" PTR_H\t0x%08" PRIx32 "\n", cur->ptr_high); + xhci_debug(" STATUS\t0x%08" PRIx32 "\n", cur->status); + xhci_debug(" CNTRL\t0x%08" PRIx32 "\n", cur->control); + TRB_DUMP(TL, cur); + TRB_DUMP(TDS, cur); + TRB_DUMP(C, cur); + TRB_DUMP(ISP, cur); + TRB_DUMP(CH, cur); + TRB_DUMP(IOC, cur); + TRB_DUMP(IDT, cur); + TRB_DUMP(TT, cur); + TRB_DUMP(DIR, cur); +} + +static const trb_t* +xhci_next_trb(const trb_t* const cur) { + if (TRB_GET(TT, cur) == TRB_LINK) + return (!cur->ptr_low) ? NULL : paddr_to_kvaddr(cur->ptr_low); + else + return cur + 1; +} + +void xhci_dump_transfer_trbs(const trb_t* const first, const trb_t* const last) { + const trb_t* cur; + for (cur = first; cur; cur = xhci_next_trb(cur)) { + xhci_dump_transfer_trb(cur); + if (cur == last) + break; + } +} + +#endif diff --git a/third_party/udev/usb_xhci/xhci_devconf.c b/third_party/udev/usb_xhci/xhci_devconf.c new file mode 100644 index 000000000..f371e5c8f --- /dev/null +++ b/third_party/udev/usb_xhci/xhci_devconf.c @@ -0,0 +1,514 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#define XHCI_DEBUG +//#define XHCI_SPEW_DEBUG + +#include "xhci_private.h" + +#include +#include +#include + +/* SetAddress() recovery interval (USB 2.0 specification 9.2.6.3 */ +#define SET_ADDRESS_MDELAY 2 + +static uint32_t +xhci_gen_route(xhci_t* const xhci, const int hubport, const int hubaddr) { + if (!hubaddr) + return 0; + uint32_t route_string = SC_GET(ROUTE, xhci->dev[hubaddr].ctx.slot); + int i; + for (i = 0; i < 20; i += 4) { + if (!(route_string & (0xf << i))) { + route_string |= (hubport & 0xf) << i; + break; + } + } + return route_string; +} + +static int +xhci_get_rh_port(xhci_t* const xhci, const int hubport, const int hubaddr) { + if (!hubaddr) + return hubport; + return SC_GET(RHPORT, xhci->dev[hubaddr].ctx.slot); +} + +static int +xhci_get_tt(xhci_t* const xhci, const usb_speed speed, + const int hubport, const int hubaddr, + int* const tt, int* const tt_port) { + if (!hubaddr) + return 0; + const slotctx_t* const slot = xhci->dev[hubaddr].ctx.slot; + if ((*tt = SC_GET(TTID, slot))) { + *tt_port = SC_GET(TTPORT, slot); + } else if (speed < HIGH_SPEED && + SC_GET(SPEED1, slot) - 1 == HIGH_SPEED) { + *tt = hubaddr; + *tt_port = hubport; + } + return *tt != 0; +} + +static void +xhci_reap_slots(xhci_t* const xhci, int skip_slot) { + int i; + + xhci_debug("xHC resource shortage, trying to reap old slots...\n"); + for (i = 1; i <= xhci->max_slots_en; i++) { + if (i == skip_slot) + continue; /* don't reap slot we were working on */ + if (xhci->dev[i].transfer_rings[1]) + continue; /* slot still in use */ + if (!xhci->dev[i].ctx.raw) + continue; /* slot already disabled */ + + const int cc = xhci_cmd_disable_slot(xhci, i); + if (cc != CC_SUCCESS) + xhci_debug("Failed to disable slot %d: %d\n", i, cc); + else + xhci_spew("Successfully reaped slot %d\n", i); + xhci->dcbaa[i] = 0; + xhci_free(xhci, xhci->dev[i].ctx.raw); + xhci->dev[i].ctx.raw = NULL; + } +} + +static inputctx_t* +xhci_make_inputctx(xhci_t* const xhci, const size_t ctxsize) { + int i; + const size_t size = (1 + NUM_EPS) * ctxsize; + inputctx_t* const ic = malloc(sizeof(*ic)); + void* dma_buffer = xhci_memalign(xhci, 64, size); + + if (!ic || !dma_buffer) { + free(ic); + xhci_free(xhci, dma_buffer); + return NULL; + } + + memset(dma_buffer, 0, size); + ic->drop = dma_buffer + 0; + ic->add = dma_buffer + 4; + dma_buffer += ctxsize; + for (i = 0; i < NUM_EPS; i++, dma_buffer += ctxsize) + ic->dev.ep[i] = dma_buffer; + + return ic; +} + +static int usb_decode_mps0(usb_speed speed, uint8_t bMaxPacketSize0) { + switch (speed) { + case LOW_SPEED: + if (bMaxPacketSize0 != 8) { + xhci_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0); + bMaxPacketSize0 = 8; + } + return bMaxPacketSize0; + case FULL_SPEED: + switch (bMaxPacketSize0) { + case 8: + case 16: + case 32: + case 64: + return bMaxPacketSize0; + default: + xhci_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0); + return 8; + } + case HIGH_SPEED: + if (bMaxPacketSize0 != 64) { + xhci_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0); + bMaxPacketSize0 = 64; + } + return bMaxPacketSize0; + case SUPER_SPEED: + if (bMaxPacketSize0 != 9) { + xhci_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0); + bMaxPacketSize0 = 9; + } + return 1 << bMaxPacketSize0; + default: /* GCC is stupid and cannot deal with enums correctly */ + return 8; + } +} + +int xhci_set_address(mx_device_t* hcidev, usb_speed speed, int hubport, int hubaddr) { + xhci_t* const xhci = get_xhci(hcidev); + const size_t ctxsize = CTXSIZE(xhci); + devinfo_t* di = NULL; + usbdev_t* dev = NULL; + int i; + + inputctx_t* const ic = xhci_make_inputctx(xhci, ctxsize); + transfer_ring_t* const tr = malloc(sizeof(*tr)); + if (tr) + tr->ring = xhci_align(xhci, 16, TRANSFER_RING_SIZE * sizeof(trb_t)); + if (!ic || !tr || !tr->ring) { + xhci_debug("Out of memory\n"); + goto _free_return; + } + + int slot_id; + int cc = xhci_cmd_enable_slot(xhci, &slot_id); + if (cc == CC_NO_SLOTS_AVAILABLE) { + xhci_reap_slots(xhci, 0); + cc = xhci_cmd_enable_slot(xhci, &slot_id); + } + if (cc != CC_SUCCESS) { + xhci_debug("Enable slot failed: %d\n", cc); + goto _free_return; + } else { + xhci_debug("Enabled slot %d\n", slot_id); + } + + di = &xhci->dev[slot_id]; + void* dma_buffer = xhci_memalign(xhci, 64, NUM_EPS * ctxsize); + if (!dma_buffer) + goto _disable_return; + memset(dma_buffer, 0, NUM_EPS * ctxsize); + for (i = 0; i < NUM_EPS; i++, dma_buffer += ctxsize) + di->ctx.ep[i] = dma_buffer; + + *ic->add = (1 << 0) /* Slot Context */ | (1 << 1) /* EP0 Context */; + + SC_SET(ROUTE, ic->dev.slot, xhci_gen_route(xhci, hubport, hubaddr)); + SC_SET(SPEED1, ic->dev.slot, speed + 1); + SC_SET(CTXENT, ic->dev.slot, 1); /* the endpoint 0 context */ + SC_SET(RHPORT, ic->dev.slot, xhci_get_rh_port(xhci, hubport, hubaddr)); + + int tt, tt_port; + if (xhci_get_tt(xhci, speed, hubport, hubaddr, &tt, &tt_port)) { + xhci_debug("TT for %d: %d[%d]\n", slot_id, tt, tt_port); + SC_SET(MTT, ic->dev.slot, SC_GET(MTT, xhci->dev[tt].ctx.slot)); + SC_SET(TTID, ic->dev.slot, tt); + SC_SET(TTPORT, ic->dev.slot, tt_port); + } + + di->transfer_rings[1] = tr; + xhci_init_cycle_ring(xhci, tr, TRANSFER_RING_SIZE); + + ic->dev.ep0->tr_dq_low = (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)tr->ring); + ic->dev.ep0->tr_dq_high = 0; + EC_SET(TYPE, ic->dev.ep0, EP_CONTROL); + EC_SET(AVRTRB, ic->dev.ep0, 8); + EC_SET(MPS, ic->dev.ep0, 8); + EC_SET(CERR, ic->dev.ep0, 3); + EC_SET(DCS, ic->dev.ep0, 1); + + xhci->dcbaa[slot_id] = xhci_virt_to_phys(xhci, (mx_vaddr_t)di->ctx.raw); + + cc = xhci_cmd_address_device(xhci, slot_id, ic); + if (cc == CC_RESOURCE_ERROR) { + xhci_reap_slots(xhci, slot_id); + cc = xhci_cmd_address_device(xhci, slot_id, ic); + } + if (cc != CC_SUCCESS) { + xhci_debug("Address device failed: %d\n", cc); + goto _disable_return; + } else { + xhci_debug("Addressed device %d (USB: %d)\n", + slot_id, SC_GET(UADDR, di->ctx.slot)); + } + usleep(SET_ADDRESS_MDELAY * 1000); + + dev = init_device_entry(get_usb_xhci(hcidev), slot_id); + if (!dev) + goto _disable_return; + + dev->address = slot_id; + dev->hub = hubaddr; + dev->port = hubport; + dev->speed = speed; + dev->ep0.endpoint = 0; + dev->ep0.toggle = 0; + dev->ep0.direction = 0; + dev->ep0.type = USB_ENDPOINT_CONTROL; + + uint8_t buf[8]; + if (xhci_get_descriptor(dev, USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, + USB_DT_DEVICE, 0, buf, sizeof(buf)) != sizeof(buf)) { + xhci_debug("first get_descriptor(DT_DEV) failed\n"); + goto _disable_return; + } + + dev->ep0.maxpacketsize = usb_decode_mps0(speed, buf[7]); + if (dev->ep0.maxpacketsize != 8) { + memset((void*)ic->dev.ep0, 0x00, ctxsize); + *ic->add = (1 << 1); /* EP0 Context */ + EC_SET(MPS, ic->dev.ep0, dev->ep0.maxpacketsize); + cc = xhci_cmd_evaluate_context(xhci, slot_id, ic); + if (cc == CC_RESOURCE_ERROR) { + xhci_reap_slots(xhci, slot_id); + cc = xhci_cmd_evaluate_context(xhci, slot_id, ic); + } + if (cc != CC_SUCCESS) { + xhci_debug("Context evaluation failed: %d\n", cc); + goto _disable_return; + } + } + + goto _free_ic_return; + +_disable_return: + xhci_cmd_disable_slot(xhci, slot_id); + xhci->dcbaa[slot_id] = 0; + xhci_destroy_dev(hcidev, slot_id); + dev = NULL; +_free_return: + if (tr) + xhci_free(xhci, (void*)tr->ring); + free(tr); + if (di) { + xhci_free(xhci, di->ctx.raw); + di->ctx.raw = 0; + } +_free_ic_return: + if (ic) { + xhci_free(xhci, ic->raw); + } + free(ic); + return (dev ? dev->address : -1); +} + +static int +xhci_finish_hub_config(usbdev_t* const dev, inputctx_t* const ic) { + int type = dev->speed == SUPER_SPEED ? 0x2a : 0x29; /* similar enough */ + usb_hub_descriptor_t desc; + + if (xhci_get_descriptor(dev, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, + type, 0, &desc, sizeof(desc)) < 0) { + xhci_debug("Failed to fetch hub descriptor\n"); + return COMMUNICATION_ERROR; + } + + SC_SET(HUB, ic->dev.slot, 1); + SC_SET(MTT, ic->dev.slot, 0); /* No support for Multi-TT */ + SC_SET(NPORTS, ic->dev.slot, desc.bNbrPorts); + if (dev->speed == HIGH_SPEED) + SC_SET(TTT, ic->dev.slot, + (desc.wHubCharacteristics >> 5) & 0x0003); + + return 0; +} + +static size_t +xhci_bound_interval(usbdev_t* dev, const usb_endpoint_t* const ep) { + if ((dev->speed == LOW_SPEED && + (ep->type == USB_ENDPOINT_ISOCHRONOUS || + ep->type == USB_ENDPOINT_INTERRUPT)) || + (dev->speed == FULL_SPEED && + ep->type == USB_ENDPOINT_INTERRUPT)) { + if (ep->interval < 3) + return 3; + else if (ep->interval > 11) + return 11; + else + return ep->interval; + } else { + if (ep->interval < 0) + return 0; + else if (ep->interval > 15) + return 15; + else + return ep->interval; + } +} + +static int +xhci_finish_ep_config(xhci_t* const xhci, usbdev_t* dev, const usb_endpoint_t* const ep, inputctx_t* const ic) { + const int ep_id = xhci_ep_id(ep); + xhci_debug("ep_id: %d\n", ep_id); + if (ep_id <= 1 || 32 <= ep_id) + return DRIVER_ERROR; + + transfer_ring_t* const tr = malloc(sizeof(*tr)); + if (tr) + tr->ring = xhci_align(xhci, 16, TRANSFER_RING_SIZE * sizeof(trb_t)); + if (!tr || !tr->ring) { + free(tr); + xhci_debug("Out of memory\n"); + return OUT_OF_MEMORY; + } + xhci->dev[dev->address].transfer_rings[ep_id] = tr; + xhci_init_cycle_ring(xhci, tr, TRANSFER_RING_SIZE); + + *ic->add |= (1 << ep_id); + if ((int)SC_GET(CTXENT, ic->dev.slot) < ep_id) + SC_SET(CTXENT, ic->dev.slot, ep_id); + + epctx_t* const epctx = ic->dev.ep[ep_id]; + xhci_debug("Filling epctx (@%p)\n", epctx); + epctx->tr_dq_low = xhci_virt_to_phys(xhci, (mx_vaddr_t)tr->ring); + epctx->tr_dq_high = 0; + EC_SET(INTVAL, epctx, xhci_bound_interval(dev, ep)); + EC_SET(CERR, epctx, 3); + EC_SET(TYPE, epctx, ep->type | ((ep->direction != USB_ENDPOINT_OUT) << 2)); + EC_SET(MPS, epctx, ep->maxpacketsize); + EC_SET(DCS, epctx, 1); + size_t avrtrb; + switch (ep->type) { + case USB_ENDPOINT_BULK: + case USB_ENDPOINT_ISOCHRONOUS: + avrtrb = 3 * 1024; + break; + case USB_ENDPOINT_INTERRUPT: + avrtrb = 1024; + break; + default: + avrtrb = 8; + break; + } + EC_SET(AVRTRB, epctx, avrtrb); + EC_SET(MXESIT, epctx, EC_GET(MPS, epctx) * EC_GET(MBS, epctx)); + + if (0 /*IS_ENABLED(CONFIG_LP_USB_XHCI_MTK_QUIRK) */) { + /* The MTK xHCI defines some extra SW parameters which are + * put into reserved DWs in Slot and Endpoint Contexts for + * synchronous endpoints. But for non-isochronous transfers, + * it is enough to set the following two fields to 1, and others + * are set to 0. + */ + EC_SET(BPKTS, epctx, 1); + EC_SET(BBM, epctx, 1); + } + return 0; +} + +int xhci_finish_device_config(mx_device_t* hcidev, int slot_id, usb_device_config_t* device_config) { + xhci_t* const xhci = get_xhci(hcidev); + devinfo_t* const di = &xhci->dev[slot_id]; + + int i, ret = 0; + + inputctx_t* const ic = xhci_make_inputctx(xhci, CTXSIZE(xhci)); + if (!ic) { + xhci_debug("Out of memory\n"); + return OUT_OF_MEMORY; + } + + *ic->add = (1 << 0); /* Slot Context */ + + xhci_dump_slotctx(di->ctx.slot); + ic->dev.slot->f1 = di->ctx.slot->f1; + ic->dev.slot->f2 = di->ctx.slot->f2; + ic->dev.slot->f3 = di->ctx.slot->f3; + /* f4 *must* be 0 in the Input Context... yeah, it's weird, I know. */ + + usbdev_t* dev = xhci->devices[slot_id]; + if (device_config->descriptor->bDeviceClass == USB_CLASS_HUB) { + ret = xhci_finish_hub_config(dev, ic); + if (ret) + goto _free_return; + } + + for (i = 0; i < device_config->num_configurations; i++) { + usb_configuration_t* config = &device_config->configurations[i]; + for (int j = 0; j < config->num_interfaces; j++) { + usb_interface_t* intf = &config->interfaces[j]; + for (int k = 0; k < intf->num_endpoints; k++) { + ret = xhci_finish_ep_config(xhci, dev, &intf->endpoints[k], ic); + if (ret) + goto _free_ep_ctx_return; + } + } + } + + xhci_dump_inputctx(ic); + + const int config_id = device_config->configurations[0].descriptor->bConfigurationValue; + xhci_debug("config_id: %d\n", config_id); + int cc = xhci_cmd_configure_endpoint(xhci, slot_id, config_id, ic); + if (cc == CC_RESOURCE_ERROR || cc == CC_BANDWIDTH_ERROR) { + xhci_reap_slots(xhci, slot_id); + cc = xhci_cmd_configure_endpoint(xhci, slot_id, config_id, ic); + } + if (cc != CC_SUCCESS) { + xhci_debug("Configure endpoint failed: %d\n", cc); + ret = CONTROLLER_ERROR; + goto _free_ep_ctx_return; + } else { + xhci_debug("Endpoints configured\n"); + } + + goto _free_return; + +_free_ep_ctx_return: + for (i = 2; i < 31; ++i) { + if (di->transfer_rings[i]) + xhci_free(xhci, (void*)di->transfer_rings[i]->ring); + free(di->transfer_rings[i]); + di->transfer_rings[i] = NULL; + } +_free_return: + xhci_free(xhci, ic->raw); + free(ic); + return ret; +} + +void xhci_destroy_dev(mx_device_t* hcidev, const int slot_id) { + xhci_t* const xhci = get_xhci(hcidev); + + if (slot_id <= 0 || slot_id > xhci->max_slots_en) + return; + + if (!xhci->devices[slot_id]) { + xhci_debug("xhci_destroy_dev slot %d is empty\n", slot_id); + return; + } + + inputctx_t* const ic = xhci_make_inputctx(xhci, CTXSIZE(xhci)); + if (!ic) { + xhci_debug("Out of memory, leaking resources!\n"); + return; + } + const int num_eps = xhci->devices[slot_id]->num_endp; + *ic->add = 0; /* Leave Slot/EP0 state as it is for now. */ + *ic->drop = (1 << num_eps) - 1; /* Drop all endpoints we can. */ + *ic->drop &= ~(1 << 1 | 1 << 0); /* Not allowed to drop EP0 or Slot. */ + int cc = xhci_cmd_evaluate_context(xhci, slot_id, ic); + if (cc != CC_SUCCESS) + xhci_debug("Failed to quiesce slot %d: %d\n", slot_id, cc); + cc = xhci_cmd_stop_endpoint(xhci, slot_id, 1); + if (cc != CC_SUCCESS) + xhci_debug("Failed to stop EP0 on slot %d: %d\n", slot_id, cc); + + int i; + devinfo_t* const di = &xhci->dev[slot_id]; + for (i = 1; i < num_eps; ++i) { + if (di->transfer_rings[i]) + xhci_free(xhci, (void*)di->transfer_rings[i]->ring); + free(di->transfer_rings[i]); + } + + xhci_spew("Stopped slot %d, but not disabling it yet.\n", slot_id); + di->transfer_rings[1] = NULL; +} diff --git a/third_party/udev/usb_xhci/xhci_events.c b/third_party/udev/usb_xhci/xhci_events.c new file mode 100644 index 000000000..52dd850b4 --- /dev/null +++ b/third_party/udev/usb_xhci/xhci_events.c @@ -0,0 +1,321 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#define XHCI_SPEW_DEBUG + +#include +#include "xhci_private.h" + +void xhci_reset_event_ring(event_ring_t* const er) { + int i; + for (i = 0; i < EVENT_RING_SIZE; ++i) + er->ring[i].control &= ~TRB_CYCLE; + er->cur = er->ring; + er->last = er->ring + EVENT_RING_SIZE; + er->ccs = 1; + er->adv = 1; +} + +static inline int +xhci_event_ready(const event_ring_t* const er) { + return (er->cur->control & TRB_CYCLE) == er->ccs; +} + +void xhci_update_event_dq(xhci_t* const xhci) { + if (xhci->er.adv) { + xhci_spew("Updating dq ptr: @%p(0x%08" PRIx32 ") -> %p\n", + xhci_phys_to_virt(xhci, xhci->hcrreg->intrrs[0].erdp_lo), + xhci->hcrreg->intrrs[0].erdp_lo, xhci->er.cur); + xhci->hcrreg->intrrs[0].erdp_lo = xhci_virt_to_phys(xhci, (mx_vaddr_t)xhci->er.cur); + xhci->hcrreg->intrrs[0].erdp_hi = 0; + xhci->er.adv = 0; + } +} + +void xhci_advance_event_ring(xhci_t* const xhci) { + xhci->er.cur++; + xhci->er.adv = 1; + if (xhci->er.cur == xhci->er.last) { + xhci_spew("Roll over in event ring\n"); + xhci->er.cur = xhci->er.ring; + xhci->er.ccs ^= 1; + xhci_update_event_dq(xhci); + } +} + +// must hold mutex when calling this +static void +xhci_handle_transfer_event(xhci_t* const xhci) { + const trb_t* const ev = xhci->er.cur; + const int cc = TRB_GET(CC, ev); + const int id = TRB_GET(ID, ev); + + if (id && id <= xhci->max_slots_en) { + trb_t* driver_trb = (trb_t*)xhci_phys_to_virt(xhci, (mx_paddr_t)ev->ptr_low); + usb_request_t* request; + usb_request_t* temp; + list_for_every_entry_safe (&xhci->devices[id]->req_queue, request, temp, usb_request_t, node) { + if (request->driver_data == driver_trb) { + if (cc == CC_SUCCESS || cc == CC_SHORT_PACKET) { + request->status = NO_ERROR; + request->transfer_length = TRB_GET(EVTL, ev); + } else { + request->status = -1; + request->transfer_length = 0; + } + list_delete(&request->node); + list_add_tail(&xhci->completed_reqs, &request->node); + break; + } + } + } else if (cc == CC_STOPPED || cc == CC_STOPPED_LENGTH_INVALID) { + /* Ignore 'Forced Stop Events' */ + } else { + xhci_debug( + "Warning: " + "Spurious transfer event for ID %d, EP %d:\n" + " Pointer: 0x%08x%08x\n" + " TL: 0x%06x\n" + " CC: %d\n", + id, ep, + ev->ptr_high, ev->ptr_low, + TRB_GET(EVTL, ev), cc); + } + xhci_advance_event_ring(xhci); +} + +static void +xhci_handle_command_completion_event(xhci_t* const xhci) { +#ifdef XHCI_DEBUG + const trb_t* const ev = xhci->er.cur; +#endif + + xhci_debug( + "Warning: Spurious command completion event:\n" + " Pointer: 0x%08x%08x\n" + " CC: %d\n" + " Slot ID: %d\n" + " Cycle: %d\n", + ev->ptr_high, ev->ptr_low, + TRB_GET(CC, ev), TRB_GET(ID, ev), ev->control & TRB_CYCLE); + xhci_advance_event_ring(xhci); +} + +static void +xhci_handle_host_controller_event(xhci_t* const xhci) { + const trb_t* const ev = xhci->er.cur; + + const int cc = TRB_GET(CC, ev); + switch (cc) { + case CC_EVENT_RING_FULL_ERROR: + xhci_debug("Event ring full! (@%p)\n", xhci->er.cur); + /* + * If we get here, we have processed the whole queue: + * xHC pushes this event, when it sees the ring full, + * full of other events. + * IMO it's save and necessary to update the dequeue + * pointer here. + */ + xhci_advance_event_ring(xhci); + xhci_update_event_dq(xhci); + break; + default: + xhci_debug("Warning: Spurious host controller event: %d\n", cc); + xhci_advance_event_ring(xhci); + break; + } +} + +/* handle standard types: + * - command completion event + * - port status change event + * - transfer event + * - host controller event + * must hold mutex when calling this + */ +static void +xhci_handle_event(xhci_t* const xhci) { + const trb_t* const ev = xhci->er.cur; + + const int trb_type = TRB_GET(TT, ev); + switch (trb_type) { + /* Either pass along the event or advance event ring */ + case TRB_EV_TRANSFER: + xhci_handle_transfer_event(xhci); + break; + case TRB_EV_CMD_CMPL: + xhci_handle_command_completion_event(xhci); + break; + case TRB_EV_PORTSC: + xhci_debug("Port Status Change Event for %d: %d\n", + TRB_GET(PORT, ev), TRB_GET(CC, ev)); + /* We ignore the event as we look for the PORTSC + registers instead, at a time when it suits _us_. */ + xhci_advance_event_ring(xhci); + break; + case TRB_EV_HOST: + xhci_handle_host_controller_event(xhci); + break; + default: + xhci_debug("Warning: Spurious event: %d, Completion Code: %d\n", + trb_type, TRB_GET(CC, ev)); + xhci_advance_event_ring(xhci); + break; + } +} + +// must hold mutex when calling this +void xhci_handle_events(xhci_t* const xhci) { + while (xhci_event_ready(&xhci->er)) + xhci_handle_event(xhci); + xhci_update_event_dq(xhci); +} + +static unsigned long +xhci_wait_for_event(const event_ring_t* const er, + unsigned long* const timeout_ms) { + while (!xhci_event_ready(er) && *timeout_ms) { + --*timeout_ms; + usleep(1000); + } + return *timeout_ms; +} + +static unsigned long +xhci_wait_for_event_type(xhci_t* const xhci, + uint32_t trb_type, + unsigned long* const timeout_ms) { + while (xhci_wait_for_event(&xhci->er, timeout_ms)) { + if (TRB_GET(TT, xhci->er.cur) == trb_type) + break; + + xhci_handle_event(xhci); + } + return *timeout_ms; +} + +/* returns cc of command in question (pointed to by `address`) */ +int xhci_wait_for_command_aborted(xhci_t* const xhci, const trb_t* const address) { + /* + * Specification says that something might be seriously wrong, if + * we don't get a response after 5s. Still, let the caller decide, + * what to do then. + */ + unsigned long timeout_ms = 5 * 1000; /* 5s */ + int cc = TIMEOUT; + /* + * Expects two command completion events: + * The first with CC == COMMAND_ABORTED should point to address, + * the second with CC == COMMAND_RING_STOPPED should point to new dq. + */ + while (xhci_wait_for_event_type(xhci, TRB_EV_CMD_CMPL, &timeout_ms)) { + if ((xhci->er.cur->ptr_low == (uint32_t)xhci_virt_to_phys(xhci, (mx_vaddr_t)address)) && + (xhci->er.cur->ptr_high == 0)) { + cc = (int)TRB_GET(CC, xhci->er.cur); + xhci_advance_event_ring(xhci); + break; + } + + xhci_handle_command_completion_event(xhci); + } + if (!timeout_ms) + xhci_debug("Warning: Timed out waiting for COMMAND_ABORTED.\n"); + while (xhci_wait_for_event_type(xhci, TRB_EV_CMD_CMPL, &timeout_ms)) { + if (TRB_GET(CC, xhci->er.cur) == CC_COMMAND_RING_STOPPED) { + xhci->cr.cur = (trb_t*)xhci_phys_to_virt(xhci, xhci->er.cur->ptr_low); + xhci_advance_event_ring(xhci); + break; + } + + xhci_handle_command_completion_event(xhci); + } + if (!timeout_ms) + xhci_debug( + "Warning: Timed out " + "waiting for COMMAND_RING_STOPPED.\n"); + xhci_update_event_dq(xhci); + return cc; +} + +/* + * returns cc of command in question (pointed to by `address`) + * caller should abort command if cc is TIMEOUT + */ +int xhci_wait_for_command_done(xhci_t* const xhci, + const trb_t* const address, + const int clear_event) { + /* + * The Address Device Command should take most time, as it has to + * communicate with the USB device. Set address processing shouldn't + * take longer than 50ms (at the slave). Let's take a timeout of + * 100ms. + */ + unsigned long timeout_ms = 100; /* 100ms */ + int cc = TIMEOUT; + while (xhci_wait_for_event_type(xhci, TRB_EV_CMD_CMPL, &timeout_ms)) { + if ((xhci->er.cur->ptr_low == xhci_virt_to_phys(xhci, (mx_vaddr_t)address)) && + (xhci->er.cur->ptr_high == 0)) { + cc = TRB_GET(CC, xhci->er.cur); + break; + } + + xhci_handle_command_completion_event(xhci); + } + if (!timeout_ms) { + xhci_debug("Warning: Timed out waiting for TRB_EV_CMD_CMPL.\n"); + } else if (clear_event) { + xhci_advance_event_ring(xhci); + } + xhci_update_event_dq(xhci); + return cc; +} + +/* returns amount of bytes transferred on success, negative CC on error */ +int xhci_wait_for_transfer(xhci_t* const xhci, uint32_t slot_id, uint32_t ep_id) { + xhci_spew("Waiting for transfer on ID %d EP %d\n", slot_id, ep_id); + /* 3s for all types of transfers */ /* TODO: test, wait longer? */ + unsigned long timeout_ms = 3 * 1000; + int ret = TIMEOUT; + while (xhci_wait_for_event_type(xhci, TRB_EV_TRANSFER, &timeout_ms)) { + if (TRB_GET(ID, xhci->er.cur) == slot_id && + TRB_GET(EP, xhci->er.cur) == ep_id) { + ret = -TRB_GET(CC, xhci->er.cur); + if (ret == -CC_SUCCESS || ret == -CC_SHORT_PACKET) + ret = TRB_GET(EVTL, xhci->er.cur); + xhci_advance_event_ring(xhci); + break; + } + + xhci_handle_transfer_event(xhci); + } + if (!timeout_ms) + xhci_debug("Warning: Timed out waiting for TRB_EV_TRANSFER.\n"); + xhci_update_event_dq(xhci); + return ret; +} diff --git a/third_party/udev/usb_xhci/xhci_private.h b/third_party/udev/usb_xhci/xhci_private.h new file mode 100644 index 000000000..ec98da17f --- /dev/null +++ b/third_party/udev/usb_xhci/xhci_private.h @@ -0,0 +1,644 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2010 Patrick Georgi + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb_poll.h" + +#ifdef XHCI_DEBUG +#define xhci_debug(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define xhci_debug(fmt, args...) \ + do { \ + } while (0) +#endif +#ifdef XHCI_SPEW_DEBUG +#define xhci_spew(fmt, args...) xhci_debug(fmt, ##args) +#else +#define xhci_spew(fmt, args...) \ + do { \ + } while (0) +#endif + +#define MASK(startbit, lenbit) (((1 << (lenbit)) - 1) << (startbit)) + +/* Make these high enough to not collide with negative XHCI CCs */ +#define TIMEOUT -65 +#define CONTROLLER_ERROR -66 +#define COMMUNICATION_ERROR -67 +#define OUT_OF_MEMORY -68 +#define DRIVER_ERROR -69 + +#define CC_SUCCESS 1 +#define CC_TRB_ERROR 5 +#define CC_STALL_ERROR 6 +#define CC_RESOURCE_ERROR 7 +#define CC_BANDWIDTH_ERROR 8 +#define CC_NO_SLOTS_AVAILABLE 9 +#define CC_SHORT_PACKET 13 +#define CC_EVENT_RING_FULL_ERROR 21 +#define CC_COMMAND_RING_STOPPED 24 +#define CC_COMMAND_ABORTED 25 +#define CC_STOPPED 26 +#define CC_STOPPED_LENGTH_INVALID 27 + +enum { + TRB_NORMAL = 1, + TRB_SETUP_STAGE = 2, + TRB_DATA_STAGE = 3, + TRB_STATUS_STAGE = 4, + TRB_LINK = 6, + TRB_EVENT_DATA = 7, + TRB_CMD_ENABLE_SLOT = 9, + TRB_CMD_DISABLE_SLOT = 10, + TRB_CMD_ADDRESS_DEV = 11, + TRB_CMD_CONFIGURE_EP = 12, + TRB_CMD_EVAL_CTX = 13, + TRB_CMD_RESET_EP = 14, + TRB_CMD_STOP_EP = 15, + TRB_CMD_SET_TR_DQ = 16, + TRB_CMD_NOOP = 23, + TRB_EV_TRANSFER = 32, + TRB_EV_CMD_CMPL = 33, + TRB_EV_PORTSC = 34, + TRB_EV_HOST = 37, +}; +enum { TRB_TRT_NO_DATA = 0, + TRB_TRT_OUT_DATA = 2, + TRB_TRT_IN_DATA = 3 }; +enum { TRB_DIR_OUT = 0, + TRB_DIR_IN = 1 }; + +#define TRB_PORT_FIELD ptr_low +#define TRB_PORT_START 24 +#define TRB_PORT_LEN 8 +#define TRB_TL_FIELD status /* TL - Transfer Length */ +#define TRB_TL_START 0 +#define TRB_TL_LEN 17 +#define TRB_EVTL_FIELD status /* EVTL - (Event TRB) Transfer Length */ +#define TRB_EVTL_START 0 +#define TRB_EVTL_LEN 24 +#define TRB_TDS_FIELD status /* TDS - TD Size */ +#define TRB_TDS_START 17 +#define TRB_TDS_LEN 5 +#define TRB_CC_FIELD status /* CC - Completion Code */ +#define TRB_CC_START 24 +#define TRB_CC_LEN 8 +#define TRB_C_FIELD control /* C - Cycle Bit */ +#define TRB_C_START 0 +#define TRB_C_LEN 1 +#define TRB_TC_FIELD control /* TC - Toggle Cycle */ +#define TRB_TC_START 1 +#define TRB_TC_LEN 1 +#define TRB_ENT_FIELD control /* ENT - Evaluate Next TRB */ +#define TRB_ENT_START 1 +#define TRB_ENT_LEN 1 +#define TRB_ISP_FIELD control /* ISP - Interrupt-on Short Packet */ +#define TRB_ISP_START 2 +#define TRB_ISP_LEN 1 +#define TRB_CH_FIELD control /* CH - Chain Bit */ +#define TRB_CH_START 4 +#define TRB_CH_LEN 1 +#define TRB_IOC_FIELD control /* IOC - Interrupt On Completion */ +#define TRB_IOC_START 5 +#define TRB_IOC_LEN 1 +#define TRB_IDT_FIELD control /* IDT - Immediate Data */ +#define TRB_IDT_START 6 +#define TRB_IDT_LEN 1 +#define TRB_DC_FIELD control /* DC - Deconfigure */ +#define TRB_DC_START 9 +#define TRB_DC_LEN 1 +#define TRB_TT_FIELD control /* TT - TRB Type */ +#define TRB_TT_START 10 +#define TRB_TT_LEN 6 +#define TRB_TRT_FIELD control /* TRT - Transfer Type */ +#define TRB_TRT_START 16 +#define TRB_TRT_LEN 2 +#define TRB_DIR_FIELD control /* DIR - Direction */ +#define TRB_DIR_START 16 +#define TRB_DIR_LEN 1 +#define TRB_EP_FIELD control /* EP - Endpoint ID */ +#define TRB_EP_START 16 +#define TRB_EP_LEN 5 +#define TRB_ID_FIELD control /* ID - Slot ID */ +#define TRB_ID_START 24 +#define TRB_ID_LEN 8 +#define TRB_MASK(tok) MASK(TRB_##tok##_START, TRB_##tok##_LEN) +#define TRB_GET(tok, trb) (((trb)->TRB_##tok##_FIELD & TRB_MASK(tok)) >> TRB_##tok##_START) +#define TRB_SET(tok, trb, to) (trb)->TRB_##tok##_FIELD = \ + (((trb)->TRB_##tok##_FIELD & ~TRB_MASK(tok)) | \ + (((to) << TRB_##tok##_START) & TRB_MASK(tok))) +#define TRB_DUMP(tok, trb) xhci_debug(" " #tok "\t0x%04" PRIx32 "\n", TRB_GET(tok, trb)) + +#define TRB_CYCLE (1 << 0) +typedef volatile struct trb { + uint32_t ptr_low; + uint32_t ptr_high; + uint32_t status; + uint32_t control; +} trb_t; + +#define TRB_MAX_TD_SIZE 0x1F /* bits 21:17 of TD Size in TRB */ + +#define EVENT_RING_SIZE 64 +typedef struct { + trb_t* ring; + trb_t* cur; + trb_t* last; + uint8_t ccs; + uint8_t adv; +} event_ring_t; + +/* Never raise this above 256 to prevent transfer event length overflow! */ +#define TRANSFER_RING_SIZE 32 +typedef struct { + trb_t* ring; + trb_t* cur; + uint8_t pcs; +} __attribute__((packed)) transfer_ring_t; + +#define COMMAND_RING_SIZE 4 +typedef transfer_ring_t command_ring_t; + +#define SC_ROUTE_FIELD f1 /* ROUTE - Route String */ +#define SC_ROUTE_START 0 +#define SC_ROUTE_LEN 20 +#define SC_SPEED1_FIELD f1 /* SPEED - Port speed plus one (compared to usb_speed enum) */ +#define SC_SPEED1_START 20 +#define SC_SPEED1_LEN 4 +#define SC_MTT_FIELD f1 /* MTT - Multi Transaction Translator */ +#define SC_MTT_START 25 +#define SC_MTT_LEN 1 +#define SC_HUB_FIELD f1 /* HUB - Is this a hub? */ +#define SC_HUB_START 26 +#define SC_HUB_LEN 1 +#define SC_CTXENT_FIELD f1 /* CTXENT - Context Entries (number of following ep contexts) */ +#define SC_CTXENT_START 27 +#define SC_CTXENT_LEN 5 +#define SC_RHPORT_FIELD f2 /* RHPORT - Root Hub Port Number */ +#define SC_RHPORT_START 16 +#define SC_RHPORT_LEN 8 +#define SC_NPORTS_FIELD f2 /* NPORTS - Number of Ports */ +#define SC_NPORTS_START 24 +#define SC_NPORTS_LEN 8 +#define SC_TTID_FIELD f3 /* TTID - TT Hub Slot ID */ +#define SC_TTID_START 0 +#define SC_TTID_LEN 8 +#define SC_TTPORT_FIELD f3 /* TTPORT - TT Port Number */ +#define SC_TTPORT_START 8 +#define SC_TTPORT_LEN 8 +#define SC_TTT_FIELD f3 /* TTT - TT Think Time */ +#define SC_TTT_START 16 +#define SC_TTT_LEN 2 +#define SC_UADDR_FIELD f4 /* UADDR - USB Device Address */ +#define SC_UADDR_START 0 +#define SC_UADDR_LEN 8 +#define SC_STATE_FIELD f4 /* STATE - Slot State */ +#define SC_STATE_START 27 +#define SC_STATE_LEN 8 +#define SC_MASK(tok) MASK(SC_##tok##_START, SC_##tok##_LEN) +#define SC_GET(tok, sc) (((sc)->SC_##tok##_FIELD & SC_MASK(tok)) >> SC_##tok##_START) +#define SC_SET(tok, sc, to) (sc)->SC_##tok##_FIELD = \ + (((sc)->SC_##tok##_FIELD & ~SC_MASK(tok)) | \ + (((to) << SC_##tok##_START) & SC_MASK(tok))) +#define SC_DUMP(tok, sc) xhci_debug(" " #tok "\t0x%04" PRIx32 "\n", SC_GET(tok, sc)) +typedef volatile struct slotctx { + uint32_t f1; + uint32_t f2; + uint32_t f3; + uint32_t f4; + uint32_t rsvd[4]; +} slotctx_t; + +#define EC_STATE_FIELD f1 /* STATE - Endpoint State */ +#define EC_STATE_START 0 +#define EC_STATE_LEN 3 +#define EC_INTVAL_FIELD f1 /* INTVAL - Interval */ +#define EC_INTVAL_START 16 +#define EC_INTVAL_LEN 8 +#define EC_CERR_FIELD f2 /* CERR - Error Count */ +#define EC_CERR_START 1 +#define EC_CERR_LEN 2 +#define EC_TYPE_FIELD f2 /* TYPE - EP Type */ +#define EC_TYPE_START 3 +#define EC_TYPE_LEN 3 +#define EC_MBS_FIELD f2 /* MBS - Max Burst Size */ +#define EC_MBS_START 8 +#define EC_MBS_LEN 8 +#define EC_MPS_FIELD f2 /* MPS - Max Packet Size */ +#define EC_MPS_START 16 +#define EC_MPS_LEN 16 +#define EC_DCS_FIELD tr_dq_low /* DCS - Dequeue Cycle State */ +#define EC_DCS_START 0 +#define EC_DCS_LEN 1 +#define EC_AVRTRB_FIELD f5 /* AVRTRB - Average TRB Length */ +#define EC_AVRTRB_START 0 +#define EC_AVRTRB_LEN 16 +#define EC_MXESIT_FIELD f5 /* MXESIT - Max ESIT Payload */ +#define EC_MXESIT_START 16 +#define EC_MXESIT_LEN 16 +#define EC_BPKTS_FIELD rsvd[0] /* BPKTS - packets tx in scheduled uframe */ +#define EC_BPKTS_START 0 +#define EC_BPKTS_LEN 6 +#define EC_BBM_FIELD rsvd[0] /* BBM - burst mode for scheduling */ +#define EC_BBM_START 11 +#define EC_BBM_LEN 1 + +#define EC_MASK(tok) MASK(EC_##tok##_START, EC_##tok##_LEN) +#define EC_GET(tok, ec) (((ec)->EC_##tok##_FIELD & EC_MASK(tok)) >> EC_##tok##_START) +#define EC_SET(tok, ec, to) (ec)->EC_##tok##_FIELD = \ + (((ec)->EC_##tok##_FIELD & ~EC_MASK(tok)) | \ + (((to) << EC_##tok##_START) & EC_MASK(tok))) +#define EC_DUMP(tok, ec) xhci_debug(" " #tok "\t0x%04" PRIx32 "\n", EC_GET(tok, ec)) +enum { EP_ISOC_OUT = 1, + EP_BULK_OUT = 2, + EP_INTR_OUT = 3, + EP_CONTROL = 4, + EP_ISOC_IN = 5, + EP_BULK_IN = 6, + EP_INTR_IN = 7 }; +typedef volatile struct epctx { + uint32_t f1; + uint32_t f2; + uint32_t tr_dq_low; + uint32_t tr_dq_high; + uint32_t f5; + uint32_t rsvd[3]; +} epctx_t; + +#define NUM_EPS 32 +#define CTXSIZE(xhci) ((xhci)->capreg->csz ? 64 : 32) + +typedef struct usbdev { + int num_endp; + usb_endpoint_t ep0; + int address; // usb address + int hub; // hub, device is attached to + int port; // port where device is attached + usb_speed speed; + struct usb_xhci* hci; + + list_node_t req_queue; +} usbdev_t; + +typedef union devctx { + /* set of pointers, so we can dynamically adjust Slot/EP context size */ + struct { + union { + slotctx_t* slot; + void* raw; /* Pointer to the whole dev context. */ + }; + epctx_t* ep0; + epctx_t* eps1_30[NUM_EPS - 2]; + }; + epctx_t* ep[NUM_EPS]; /* At index 0 it's actually the slotctx, + we have it like that so we can use + the ep_id directly as index. */ +} devctx_t; + +typedef struct inputctx { + union { /* The drop flags are located at the start of the */ + uint32_t* drop; /* structure, so a pointer to them is equivalent */ + void* raw; /* to a pointer to the whole (raw) input context. */ + }; + uint32_t* add; + devctx_t dev; +} inputctx_t; + +typedef struct devinfo { + devctx_t ctx; + transfer_ring_t* transfer_rings[NUM_EPS]; +} devinfo_t; + +typedef struct erst_entry { + uint32_t seg_base_lo; + uint32_t seg_base_hi; + uint32_t seg_size; + uint32_t rsvd; +} erst_entry_t; + +typedef struct xhci { + /* capreg is read-only, so no need for volatile, + and thus 32bit accesses can be assumed. */ + struct capreg { + uint8_t caplength; + uint8_t res1; + union { + uint16_t hciversion; + struct { + uint8_t hciver_lo; + uint8_t hciver_hi; + } __attribute__((packed)); + } __attribute__((packed)); + union { + uint32_t hcsparams1; + struct { + unsigned long MaxSlots : 7; + unsigned long MaxIntrs : 11; + unsigned long : 6; + unsigned long MaxPorts : 8; + } __attribute__((packed)); + } __attribute__((packed)); + union { + uint32_t hcsparams2; + struct { + unsigned long IST : 4; + unsigned long ERST_Max : 4; + unsigned long : 13; + unsigned long Max_Scratchpad_Bufs_Hi : 5; + unsigned long SPR : 1; + unsigned long Max_Scratchpad_Bufs_Lo : 5; + } __attribute__((packed)); + } __attribute__((packed)); + union { + uint32_t hcsparams3; + struct { + unsigned long u1latency : 8; + unsigned long : 8; + unsigned long u2latency : 16; + } __attribute__((packed)); + } __attribute__((packed)); + union { + uint32_t hccparams; + struct { + unsigned long ac64 : 1; + unsigned long bnc : 1; + unsigned long csz : 1; + unsigned long ppc : 1; + unsigned long pind : 1; + unsigned long lhrc : 1; + unsigned long ltc : 1; + unsigned long nss : 1; + unsigned long : 4; + unsigned long MaxPSASize : 4; + unsigned long xECP : 16; + } __attribute__((packed)); + } __attribute__((packed)); + uint32_t dboff; + uint32_t rtsoff; + } __attribute__((packed)) * capreg; + + /* opreg is R/W is most places, so volatile access is necessary. + volatile means that the compiler seeks byte writes if possible, + making bitfields unusable for MMIO register blocks. Yay C :-( */ + volatile struct opreg { + uint32_t usbcmd; +#define USBCMD_RS 1 << 0 +#define USBCMD_HCRST 1 << 1 +#define USBCMD_INTE 1 << 2 + uint32_t usbsts; +#define USBSTS_HCH 1 << 0 +#define USBSTS_HSE 1 << 2 +#define USBSTS_EINT 1 << 3 +#define USBSTS_PCD 1 << 4 +#define USBSTS_CNR 1 << 11 +#define USBSTS_PRSRV_MASK ((1 << 1) | 0xffffe000) + uint32_t pagesize; + uint8_t res1[0x13 - 0x0c + 1]; + uint32_t dnctrl; + uint32_t crcr_lo; + uint32_t crcr_hi; +#define CRCR_RCS 1 << 0 +#define CRCR_CS 1 << 1 +#define CRCR_CA 1 << 2 +#define CRCR_CRR 1 << 3 + uint8_t res2[0x2f - 0x20 + 1]; + uint32_t dcbaap_lo; + uint32_t dcbaap_hi; + uint32_t config; +#define CONFIG_LP_MASK_MaxSlotsEn 0xff + uint8_t res3[0x3ff - 0x3c + 1]; + struct { + uint32_t portsc; +#define PORTSC_CCS (1 << 0) +#define PORTSC_PED (1 << 1) +// BIT 2 rsvdZ +#define PORTSC_OCA (1 << 3) +#define PORTSC_PR (1 << 4) +#define PORTSC_PLS (1 << 5) +#define PORTSC_PLS_MASK MASK(5, 4) +#define PORTSC_PP (1 << 9) +#define PORTSC_PORT_SPEED_START 10 +#define PORTSC_PORT_SPEED (1 << PORTSC_PORT_SPEED_START) +#define PORTSC_PORT_SPEED_MASK MASK(PORTSC_PORT_SPEED_START, 4) +#define PORTSC_PIC (1 << 14) +#define PORTSC_PIC_MASK MASK(14, 2) +#define PORTSC_LWS (1 << 16) +#define PORTSC_CSC (1 << 17) +#define PORTSC_PEC (1 << 18) +#define PORTSC_WRC (1 << 19) +#define PORTSC_OCC (1 << 20) +#define PORTSC_PRC (1 << 21) +#define PORTSC_PLC (1 << 22) +#define PORTSC_CEC (1 << 23) +#define PORTSC_CAS (1 << 24) +#define PORTSC_WCE (1 << 25) +#define PORTSC_WDE (1 << 26) +#define PORTSC_WOE (1 << 27) +// BIT 29:28 rsvdZ +#define PORTSC_DR (1 << 30) +#define PORTSC_WPR (1 << 31) +#define PORTSC_RW_MASK (PORTSC_PR | PORTSC_PLS_MASK | PORTSC_PP | PORTSC_PIC_MASK | PORTSC_LWS | PORTSC_WCE | PORTSC_WDE | PORTSC_WOE) + uint32_t portpmsc; + uint32_t portli; + uint32_t res; + } __attribute__((packed)) prs[]; + } __attribute__((packed)) * opreg; + + /* R/W, volatile, MMIO -> no bitfields */ + volatile struct hcrreg { + uint32_t mfindex; + uint8_t res1[0x20 - 0x4]; + struct { + uint32_t iman; +#define IMAN_IP (1 << 0) +#define IMAN_IE (1 << 1) + uint32_t imod; + uint32_t erstsz; + uint32_t res; + uint32_t erstba_lo; + uint32_t erstba_hi; + uint32_t erdp_lo; + uint32_t erdp_hi; + } __attribute__((packed)) intrrs[]; // up to 1024, but maximum host specific, given in capreg->MaxIntrs + } __attribute__((packed)) * hcrreg; + + /* R/W, volatile, MMIO -> no bitfields */ + volatile uint32_t* dbreg; + + /* R/W, volatile, Memory -> bitfields allowed */ + uint64_t* dcbaa; /* pointers to sp_ptrs and output (device) contexts */ + uint64_t* sp_ptrs; /* pointers to scratchpad buffers */ + + command_ring_t cr; + event_ring_t er; + volatile erst_entry_t* ev_ring_table; + + usbdev_t* roothub; + + uint8_t max_slots_en; + devinfo_t* dev; /* array of devinfos by slot_id */ + + io_alloc_t* io_alloc; + uint8_t* ep0_buffer; + + usbdev_t* devices[128]; // dev 0 is root hub, 127 is last addressable + + poll_node_t poll_node; + + list_node_t completed_reqs; + + mx_device_t* bus_device; + usb_bus_protocol_t* bus_protocol; + int num_rh_ports; + + mxr_mutex_t mutex; +} xhci_t; + +typedef struct usb_xhci { + xhci_t xhci; + mx_device_t hcidev; // HCI device + + io_alloc_t* io_alloc; + void* mmio; + uint64_t mmio_len; + + pci_protocol_t* pci; + mx_handle_t irq_handle; + mx_handle_t mmio_handle; + mx_handle_t cfg_handle; + pthread_t irq_thread; +} usb_xhci_t; + +mx_status_t xhci_startup(usb_xhci_t* uxhci); + +#define get_usb_xhci(dev) (containerof(dev, usb_xhci_t, hcidev)) +#define get_xhci(dev) (&get_usb_xhci(dev)->xhci) + +mx_status_t xhci_rh_init(usb_xhci_t* uxhci); +void xhci_rh_check_status_changed(xhci_t* xhci); + +void* xhci_align(xhci_t* xhci, const size_t min_align, const size_t size); +void xhci_init_cycle_ring(xhci_t* const xhci, transfer_ring_t*, const size_t ring_size); +int xhci_set_address(mx_device_t* hcidev, usb_speed speed, int hubport, int hubaddr); +int xhci_finish_device_config(mx_device_t* hcidev, int devaddr, usb_device_config_t* config); +void xhci_destroy_dev(mx_device_t* hcidev, int slot_id); + +void xhci_reset_event_ring(event_ring_t*); +void xhci_advance_event_ring(xhci_t*); +void xhci_update_event_dq(xhci_t*); + +// must hold mutex when calling this +void xhci_handle_events(xhci_t* xhci); + +int xhci_wait_for_command_aborted(xhci_t*, const trb_t*); +int xhci_wait_for_command_done(xhci_t*, const trb_t*, int clear_event); +int xhci_wait_for_transfer(xhci_t*, uint32_t slot_id, uint32_t ep_id); + +void xhci_clear_trb(trb_t*, int pcs); + +trb_t* xhci_next_command_trb(xhci_t*); +void xhci_post_command(xhci_t*); +int xhci_cmd_enable_slot(xhci_t*, int* slot_id); +int xhci_cmd_disable_slot(xhci_t*, int slot_id); +int xhci_cmd_address_device(xhci_t*, int slot_id, inputctx_t*); +int xhci_cmd_configure_endpoint(xhci_t*, int slot_id, int config_id, inputctx_t*); +int xhci_cmd_evaluate_context(xhci_t*, int slot_id, inputctx_t*); +int xhci_cmd_reset_endpoint(xhci_t*, int slot_id, int ep); +int xhci_cmd_stop_endpoint(xhci_t*, int slot_id, int ep); +int xhci_cmd_set_tr_dq(xhci_t*, int slot_id, int ep, trb_t*, int dcs); + +static inline int xhci_ep_id(const usb_endpoint_t* const ep) { + return ((ep->endpoint & 0x7f) << 1) + (ep->direction == USB_ENDPOINT_IN); +} + +mx_paddr_t xhci_virt_to_phys(xhci_t* const xhci, mx_vaddr_t addr); +mx_vaddr_t xhci_phys_to_virt(xhci_t* const xhci, mx_paddr_t addr); +void* xhci_malloc(xhci_t* const xhci, size_t size); +void* xhci_memalign(xhci_t* const xhci, size_t alignment, size_t size); +void xhci_free(xhci_t* const xhci, void* addr); +void xhci_free_phys(xhci_t* const xhci, mx_paddr_t addr); + +usbdev_t* init_device_entry(usb_xhci_t* hci, int i); + +int xhci_get_descriptor(usbdev_t* dev, int rtype, int desc_type, int desc_idx, + void* data, size_t len); + +usb_hci_protocol_t _xhci_protocol; +usb_hub_protocol_t xhci_rh_hub_protocol; + +#if ARCH_X86_32 || ARCH_X86_64 +#define wmb() __asm__ volatile("sfence") +#else +// FIXME (voydanoff) +#define wmb() +#endif + +#define MIN(x, y) (x < y ? x : y) + +#ifdef XHCI_DUMPS +void xhci_dump_slotctx(const slotctx_t*); +void xhci_dump_epctx(const epctx_t*); +void xhci_dump_devctx(const devctx_t*, const uint32_t ctx_mask); +void xhci_dump_inputctx(const inputctx_t*); +void xhci_dump_transfer_trb(const trb_t*); +void xhci_dump_transfer_trbs(const trb_t* first, const trb_t* last); +#else +#define xhci_dump_slotctx(args...) \ + do { \ + } while (0) +#define xhci_dump_epctx(args...) \ + do { \ + } while (0) +#define xhci_dump_devctx(args...) \ + do { \ + } while (0) +#define xhci_dump_inputctx(args...) \ + do { \ + } while (0) +#define xhci_dump_transfer_trb(args...) \ + do { \ + } while (0) +#define xhci_dump_transfer_trbs(args...) \ + do { \ + } while (0) +#endif diff --git a/third_party/udev/usb_xhci/xhci_rh.c b/third_party/udev/usb_xhci/xhci_rh.c new file mode 100644 index 000000000..2e1a3a7a1 --- /dev/null +++ b/third_party/udev/usb_xhci/xhci_rh.c @@ -0,0 +1,202 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2013 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define USB_DEBUG + +#include +#include +#include + +#include "xhci_private.h" + +static int +xhci_rh_port_status_changed_internal(xhci_t* xhci, const int port) { + volatile uint32_t* const portsc = &xhci->opreg->prs[port - 1].portsc; + + const int changed = !!(*portsc & (PORTSC_CSC | PORTSC_PRC)); + /* always clear all the status change bits */ + *portsc = (*portsc & PORTSC_RW_MASK) | 0x00fe0000; + return changed; +} + +static int +xhci_rh_port_status_changed(mx_device_t* device, const int port) { + xhci_t* xhci = get_xhci(device); + return xhci_rh_port_status_changed_internal(xhci, port); +} + +void xhci_rh_check_status_changed(xhci_t* xhci) { + const int changed = !!(xhci->opreg->usbsts & USBSTS_PCD); + if (changed) { + printf("root hub status change\n"); + xhci->opreg->usbsts = + (xhci->opreg->usbsts & USBSTS_PRSRV_MASK) | USBSTS_PCD; + if (xhci->bus_device) { + for (int port = 1; port <= xhci->num_rh_ports; ++port) { + if (xhci_rh_port_status_changed_internal(xhci, port) == 1) { + xhci->bus_protocol->root_hub_port_changed(xhci->bus_device, port); + } + } + } else { + printf("no bus device in xhci_rh_check_status_changed\n"); + } + } +} + +static int +xhci_rh_port_connected(mx_device_t* device, const int port) { + xhci_t* const xhci = get_xhci(device); + volatile uint32_t* const portsc = &xhci->opreg->prs[port - 1].portsc; + + return *portsc & PORTSC_CCS; +} + +static int +xhci_rh_port_in_reset(mx_device_t* device, const int port) { + xhci_t* const xhci = get_xhci(device); + volatile uint32_t* const portsc = &xhci->opreg->prs[port - 1].portsc; + + return !!(*portsc & PORTSC_PR); +} + +static int +xhci_rh_port_enabled(mx_device_t* device, const int port) { + xhci_t* const xhci = get_xhci(device); + volatile uint32_t* const portsc = &xhci->opreg->prs[port - 1].portsc; + + return !!(*portsc & PORTSC_PED); +} + +static usb_speed +xhci_rh_port_speed(mx_device_t* device, const int port) { + xhci_t* const xhci = get_xhci(device); + volatile uint32_t* const portsc = &xhci->opreg->prs[port - 1].portsc; + + if (*portsc & PORTSC_PED) { + return ((*portsc & PORTSC_PORT_SPEED_MASK) >> PORTSC_PORT_SPEED_START) - 1; + } else { + return -1; + } +} + +static int +xhci_wait_for_port(mx_device_t* device, const int port, + const int wait_for, + int (*const port_op)(mx_device_t*, int), + int timeout_steps, const int step_us) { + int state; + int step_ms; + if (step_us > 1000) { + step_ms = step_us / 1000; + } else { + step_ms = 1; + timeout_steps *= (1000 / step_us); + } + do { + state = port_op(device, port); + if (state < 0) + return -1; + else if (!!state == wait_for) + return timeout_steps; + usleep(1000 * step_ms); + --timeout_steps; + } while (timeout_steps); + return 0; +} + +static int +xhci_rh_reset_port(mx_device_t* device, const int port) { + xhci_t* const xhci = get_xhci(device); + volatile uint32_t* const portsc = &xhci->opreg->prs[port - 1].portsc; + + /* Trigger port reset. */ + *portsc = (*portsc & PORTSC_RW_MASK) | PORTSC_PR; + + /* Wait for port_in_reset == 0, up to 150 * 1000us = 150ms */ + if (xhci_wait_for_port(device, port, 0, xhci_rh_port_in_reset, + 150, 1000) == 0) + xhci_debug("xhci_rh: Reset timed out at port %d\n", port); + else + /* Clear reset status bits, since port is out of reset. */ + *portsc = (*portsc & PORTSC_RW_MASK) | PORTSC_PRC | PORTSC_WRC; + + return 0; +} + +static int +xhci_rh_enable_port(mx_device_t* device, int port) { +#if 0 + usbdev_t* dev = get_usb_device(device); + if (IS_ENABLED(CONFIG_LP_USB_XHCI_MTK_QUIRK)) { + xhci_t *const xhci = XHCI_INST(dev->controller); + volatile uint32_t *const portsc = + &xhci->opreg->prs[port - 1].portsc; + + /* + * Before sending commands to a port, the Port Power in + * PORTSC register should be enabled on MTK's xHCI. + */ + *portsc = (*portsc & PORTSC_RW_MASK) | PORTSC_PP; + } +#endif + return 0; +} + +static int xhci_rh_get_num_ports(mx_device_t* device) { + xhci_t* xhci = get_xhci(device); + return xhci->num_rh_ports; +} + +usb_hub_protocol_t xhci_rh_hub_protocol = { + .port_status_changed = xhci_rh_port_status_changed, + .port_connected = xhci_rh_port_connected, + .port_enabled = xhci_rh_port_enabled, + .port_speed = xhci_rh_port_speed, + .enable_port = xhci_rh_enable_port, + .disable_port = NULL, + .reset_port = xhci_rh_reset_port, + .get_num_ports = xhci_rh_get_num_ports, +}; + +mx_status_t +xhci_rh_init(usb_xhci_t* uxhci) { + xhci_t* xhci = &uxhci->xhci; + usbdev_t* dev = xhci->roothub; + + /* we can set them here because a root hub _really_ shouldn't + appear elsewhere */ + dev->address = 0; + dev->hub = -1; + dev->port = -1; + + xhci->num_rh_ports = /* TODO: maybe we need to read extended caps */ + (xhci->capreg->hcsparams1 >> 24) & 0xff; + + return NO_ERROR; +} diff --git a/third_party/ulib/musl/BUILD.gn b/third_party/ulib/musl/BUILD.gn new file mode 100644 index 000000000..fe589363c --- /dev/null +++ b/third_party/ulib/musl/BUILD.gn @@ -0,0 +1,496 @@ +config("musl_config") { + cflags_c = [ + "-std=c11", + "-ffreestanding", + "-nostdinc", + "-Wa,--noexecstack", + "-fomit-frame-pointer", + "-fno-unwind-tables", + "-fno-asynchronous-unwind-tables", + "-ffunction-sections", + "-fdata-sections", + "-Werror=implicit-function-declaration", + "-Werror=implicit-int", + "-Werror=pointer-sign", + "-Wno-incompatible-pointer-types", + ] + if (is_clang) { + # TODO(kulakowski): fix these + cflags_c += [ + "-Wno-shift-op-parentheses", + "-Wno-logical-op-parentheses", + "-Wno-ignored-attributes", + "-Wno-tautological-compare", + "-Wno-bitwise-op-parentheses", + "-Wno-string-plus-int", + "-Wno-dangling-else", + ] + } + + defines = [ "_XOPEN_SOURCE=700" ] + + if (target_cpu == "arm") { + defines += [ "ARCH_ARM" ] + } else if (target_cpu == "arm64") { + defines += [ "ARCH_ARM64" ] + } else if (target_cpu == "x64") { + defines += [ "ARCH_X86_64" ] + } + + include_dirs = [] + + # Architecture specific includes, these need to come before the general + # includes. + if (target_cpu == "arm") { + include_dirs += [ "arch/arm" ] + } else if (target_cpu == "arm64") { + include_dirs += [ "arch/aarch64" ] + } else if (target_cpu == "x64") { + include_dirs += [ "arch/x86_64" ] + } + + # General includes, these need to come after the arch specific includes. + # src/internal must come before include. + include_dirs += [ + "arch/generic", + "src/internal", + "include", + "third_party/include", + "//system/ulib/global/include", + "//system/ulib/magenta/include", + "//system/ulib/runtime/include", + ] +} + +config("_musl_config") { + visibility = [ ":*" ] + defines = [ "WITH_LIBC_IO_HOOKS=1" ] + include_dirs = [ "include" ] +} + +# The C library is built as a complete static library rather than thin archive +# (or source set) so that it can be distributed as a part of toolchain. +static_library("musl") { + output_name = "libc" + public_configs = [ ":_musl_config" ] + complete_static_lib = true + deps = [ + "crt", + "magenta", + "src/complex", + "src/conf", + "src/crypt", + "src/ctype", + "src/dirent", + "src/env", + "src/errno", + "src/exit", + "src/fcntl", + "src/fenv", + "src/internal", + "src/locale", + "src/malloc", + "src/math", + "src/misc", + "src/mman", + "src/mq", + "src/multibyte", + "src/network", + "src/passwd", + "src/prng", + "src/process", + "src/regex", + "src/sched", + "src/setjmp", + "src/signal", + "src/stat", + "src/stdio", + "src/stdlib", + "src/string", + "src/temp", + "src/termios", + "src/thread", + "src/time", + "src/unistd", + "third_party/arch", + "third_party/complex", + "third_party/math", + + # These submodules either do not build or even make sense for Magenta, but + # we still list them for completeness and future reference; however, they + # might be removed in the future. + # + # "ldso", + # "src/aio", + # "src/ipc", + # "src/ldso", + # "src/legacy", + # "src/linux", + # "src/select", + + "//system/ulib/magenta", + "//system/ulib/runtime", + ] +} + +# For simplicity, musl places all its symbols in libc. To support +# linking against e.g. libm, either implicitly or with an explicit -lm +# flag, we build empty libraries. +static_library("libm") { + complete_static_lib = true +} + +copy("copy_include") { + sources = [ + "include/aio.h", + "include/alloca.h", + "include/ar.h", + "include/assert.h", + "include/byteswap.h", + "include/complex.h", + "include/cpio.h", + "include/crypt.h", + "include/ctype.h", + "include/dirent.h", + "include/dlfcn.h", + "include/elf.h", + "include/endian.h", + "include/err.h", + "include/errno.h", + "include/fcntl.h", + "include/features.h", + + #"include/alltypes.h.in", + "include/fenv.h", + "include/float.h", + "include/fmtmsg.h", + "include/fnmatch.h", + "include/ftw.h", + "include/getopt.h", + "include/glob.h", + "include/grp.h", + "include/iconv.h", + "include/ifaddrs.h", + "include/inttypes.h", + "include/iso646.h", + "include/langinfo.h", + "include/lastlog.h", + "include/libgen.h", + "include/libintl.h", + "include/limits.h", + "include/link.h", + "include/locale.h", + "include/malloc.h", + "include/math.h", + "include/memory.h", + "include/mntent.h", + "include/monetary.h", + "include/mqueue.h", + "include/netdb.h", + "include/nl_types.h", + "include/paths.h", + "include/poll.h", + "include/pthread.h", + "include/pty.h", + "include/pwd.h", + "include/regex.h", + "include/resolv.h", + "include/sched.h", + "include/search.h", + "include/semaphore.h", + "include/setjmp.h", + "include/shadow.h", + "include/signal.h", + "include/spawn.h", + "include/stdalign.h", + "include/stdarg.h", + "include/stdbool.h", + "include/stddef.h", + "include/stdint.h", + "include/stdio.h", + "include/stdio_ext.h", + "include/stdlib.h", + "include/stdnoreturn.h", + "include/string.h", + "include/strings.h", + "include/stropts.h", + "include/syscall.h", + "include/sysexits.h", + "include/syslog.h", + "include/tar.h", + "include/termios.h", + "include/tgmath.h", + "include/threads.h", + "include/time.h", + "include/uchar.h", + "include/ucontext.h", + "include/ulimit.h", + "include/unistd.h", + "include/utime.h", + "include/utmp.h", + "include/utmpx.h", + "include/values.h", + "include/wait.h", + "include/wchar.h", + "include/wctype.h", + "include/wordexp.h", + ] + outputs = [ + "${root_out_dir}/include/{{source_name_part}}.h", + ] +} + +copy("copy_include_sys") { + sources = [ + "include/sys/acct.h", + "include/sys/auxv.h", + "include/sys/cachectl.h", + "include/sys/dir.h", + "include/sys/epoll.h", + "include/sys/errno.h", + "include/sys/eventfd.h", + "include/sys/fanotify.h", + "include/sys/fcntl.h", + "include/sys/file.h", + "include/sys/fsuid.h", + "include/sys/inotify.h", + "include/sys/io.h", + "include/sys/ioctl.h", + "include/sys/ipc.h", + "include/sys/kd.h", + "include/sys/klog.h", + "include/sys/mman.h", + "include/sys/mount.h", + "include/sys/msg.h", + "include/sys/mtio.h", + "include/sys/param.h", + "include/sys/personality.h", + "include/sys/poll.h", + "include/sys/prctl.h", + "include/sys/procfs.h", + "include/sys/ptrace.h", + "include/sys/quota.h", + "include/sys/reboot.h", + "include/sys/reg.h", + "include/sys/resource.h", + "include/sys/select.h", + "include/sys/sem.h", + "include/sys/sendfile.h", + "include/sys/shm.h", + "include/sys/signal.h", + "include/sys/signalfd.h", + "include/sys/socket.h", + "include/sys/soundcard.h", + "include/sys/stat.h", + "include/sys/statfs.h", + "include/sys/statvfs.h", + "include/sys/stropts.h", + "include/sys/swap.h", + "include/sys/syscall.h", + "include/sys/sysinfo.h", + "include/sys/syslog.h", + "include/sys/sysmacros.h", + "include/sys/termios.h", + "include/sys/time.h", + "include/sys/timeb.h", + "include/sys/timerfd.h", + "include/sys/times.h", + "include/sys/timex.h", + "include/sys/ttydefaults.h", + "include/sys/types.h", + "include/sys/ucontext.h", + "include/sys/uio.h", + "include/sys/un.h", + "include/sys/user.h", + "include/sys/utsname.h", + "include/sys/vfs.h", + "include/sys/vt.h", + "include/sys/wait.h", + ] + outputs = [ + "${root_out_dir}/include/sys/{{source_name_part}}.h", + ] +} + +copy("copy_include_netinet") { + sources = [ + "include/netinet/ether.h", + "include/netinet/icmp6.h", + "include/netinet/if_ether.h", + "include/netinet/igmp.h", + "include/netinet/in.h", + "include/netinet/in_systm.h", + "include/netinet/ip.h", + "include/netinet/ip6.h", + "include/netinet/ip_icmp.h", + "include/netinet/tcp.h", + "include/netinet/udp.h", + ] + outputs = [ + "${root_out_dir}/include/netinet/{{source_name_part}}.h", + ] +} + +copy("copy_include_scsi") { + sources = [ + "include/scsi/scsi.h", + "include/scsi/scsi_ioctl.h", + "include/scsi/sg.h", + ] + outputs = [ + "${root_out_dir}/include/scsi/{{source_name_part}}.h", + ] +} + +copy("copy_include_arpa") { + sources = [ + "include/arpa/ftp.h", + "include/arpa/inet.h", + "include/arpa/nameser.h", + "include/arpa/nameser_compat.h", + "include/arpa/telnet.h", + "include/arpa/tftp.h", + ] + outputs = [ + "${root_out_dir}/include/arpa/{{source_name_part}}.h", + ] +} + +copy("copy_include_netpacket") { + sources = [ + "include/netpacket/packet.h", + ] + outputs = [ + "${root_out_dir}/include/netpacket/{{source_name_part}}.h", + ] +} + +copy("copy_include_net") { + sources = [ + "include/net/ethernet.h", + "include/net/if.h", + "include/net/if_arp.h", + "include/net/route.h", + ] + outputs = [ + "${root_out_dir}/include/net/{{source_name_part}}.h", + ] +} + +copy("copy_include_bits") { + sources = [ + "arch/generic/bits/errno.h", + "arch/generic/bits/poll.h", + "arch/generic/bits/resource.h", + "arch/generic/bits/sem.h", + "arch/generic/bits/statfs.h", + "arch/generic/bits/stdarg.h", + "arch/generic/bits/termios.h", + "include/bits/alltypes.h", + ] + if (current_cpu == "arm") { + sources += [ + "arch/arm/bits/endian.h", + "arch/arm/bits/fcntl.h", + "arch/arm/bits/fenv.h", + "arch/arm/bits/float.h", + "arch/arm/bits/limits.h", + "arch/arm/bits/posix.h", + "arch/arm/bits/reg.h", + "arch/arm/bits/setjmp.h", + "arch/arm/bits/signal.h", + "arch/arm/bits/stat.h", + "arch/arm/bits/stdint.h", + "arch/arm/bits/syscall.h", + "arch/arm/bits/user.h", + "arch/generic/bits/io.h", + "arch/generic/bits/ioctl.h", + "arch/generic/bits/ipc.h", + "arch/generic/bits/mman.h", + "arch/generic/bits/msg.h", + "arch/generic/bits/shm.h", + "arch/generic/bits/socket.h", + "include/bits/alltypes-arm.h", + ] + } else if (current_cpu == "arm64") { + sources += [ + "arch/aarch64/bits/endian.h", + "arch/aarch64/bits/fcntl.h", + "arch/aarch64/bits/fenv.h", + "arch/aarch64/bits/float.h", + "arch/aarch64/bits/ipc.h", + "arch/aarch64/bits/limits.h", + "arch/aarch64/bits/msg.h", + "arch/aarch64/bits/posix.h", + "arch/aarch64/bits/reg.h", + "arch/aarch64/bits/setjmp.h", + "arch/aarch64/bits/shm.h", + "arch/aarch64/bits/signal.h", + "arch/aarch64/bits/socket.h", + "arch/aarch64/bits/stat.h", + "arch/aarch64/bits/stdint.h", + "arch/aarch64/bits/syscall.h", + "arch/aarch64/bits/user.h", + "arch/generic/bits/io.h", + "arch/generic/bits/ioctl.h", + "arch/generic/bits/mman.h", + "include/bits/alltypes-aarch64.h", + ] + } else if (current_cpu == "x64") { + sources += [ + "arch/x86_64/bits/endian.h", + "arch/x86_64/bits/fcntl.h", + "arch/x86_64/bits/fenv.h", + "arch/x86_64/bits/float.h", + "arch/x86_64/bits/io.h", + "arch/x86_64/bits/ioctl.h", + "arch/x86_64/bits/ipc.h", + "arch/x86_64/bits/limits.h", + "arch/x86_64/bits/mman.h", + "arch/x86_64/bits/msg.h", + "arch/x86_64/bits/posix.h", + "arch/x86_64/bits/reg.h", + "arch/x86_64/bits/setjmp.h", + "arch/x86_64/bits/shm.h", + "arch/x86_64/bits/signal.h", + "arch/x86_64/bits/socket.h", + "arch/x86_64/bits/stat.h", + "arch/x86_64/bits/stdint.h", + "arch/x86_64/bits/syscall.h", + "arch/x86_64/bits/user.h", + "include/bits/alltypes-x86_64.h", + ] + } + outputs = [ + "${root_out_dir}/include/bits/{{source_name_part}}.h", + ] +} + +copy("copy_libs") { + deps = [ + ":libm", + ":musl", + ] + sources = [ + "${target_out_dir}/libc.a", + "${target_out_dir}/libm.a", + ] + outputs = [ + "${root_out_dir}/lib/{{source_name_part}}.a", + ] +} + +group("install") { + deps = [ + ":copy_include", + ":copy_include_arpa", + ":copy_include_bits", + ":copy_include_net", + ":copy_include_netinet", + ":copy_include_netpacket", + ":copy_include_scsi", + ":copy_include_sys", + ":copy_libs", + "crt:install", + ] +} diff --git a/third_party/ulib/musl/COPYRIGHT b/third_party/ulib/musl/COPYRIGHT new file mode 100644 index 000000000..f597e64de --- /dev/null +++ b/third_party/ulib/musl/COPYRIGHT @@ -0,0 +1,125 @@ +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- + +Authors/contributors include: + +Alex Dowad +Alexander Monakov +Anthony G. Basile +Arvid Picciani +Bobby Bingham +Boris Brezillon +Brent Cook +Chris Spiegel +Clément Vasseur +Daniel Micay +Denys Vlasenko +Emil Renner Berthing +Felix Fietkau +Felix Janda +Gianluca Anzolin +Hauke Mehrtens +Hiltjo Posthuma +Isaac Dunham +Jaydeep Patil +Jens Gustedt +Jeremy Huntwork +Jo-Philipp Wich +Joakim Sindholt +John Spencer +Josiah Worcester +Justin Cormack +Khem Raj +Kylie McClain +Luca Barbato +Luka Perkov +M Farkas-Dyck (Strake) +Mahesh Bodapati +Michael Forney +Natanael Copa +Nicholas J. Kain +orc +Pascal Cuoq +Petr Hosek +Pierre Carrier +Rich Felker +Richard Pennington +Shiz +sin +Solar Designer +Stefan Kristiansson +Szabolcs Nagy +Timo Teräs +Trutz Behn +Valentin Ochs +William Haddon + +Portions of this software are derived from third-party works licensed +under terms compatible with the above MIT license: + +Much of the math library code (third_party/math/* and +third_party/complex/*, and third_party/include/libm.h) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. + +The x86_64 files in third_party/arch were written by Nicholas J. Kain +and is licensed under the standard MIT terms. + +All other files which have no copyright comments are original works +produced specifically for use as part of this library, written either +by Rich Felker, the main author of the library, or by one or more +contibutors listed above. Details on authorship of individual files +can be found in the git version control history of the project. The +omission of copyright and license comments in each file is in the +interest of source tree size. + +In addition, permission is hereby granted for all public header files +(include/* and arch/*/bits/*) and crt files intended to be linked into +applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit +the copyright notice and permission notice otherwise required by the +license, and to use these files without any requirement of +attribution. These files include substantial contributions from: + +Bobby Bingham +John Spencer +Nicholas J. Kain +Rich Felker +Richard Pennington +Stefan Kristiansson +Szabolcs Nagy + +all of whom have explicitly granted such permission. + +This file previously contained text expressing a belief that most of +the files covered by the above exception were sufficiently trivial not +to be subject to copyright, resulting in confusion over whether it +negated the permissions granted in the license. In the spirit of +permissive licensing, and of not having licensing issues being an +obstacle to adoption, that text has been removed. diff --git a/third_party/ulib/musl/INSTALL b/third_party/ulib/musl/INSTALL new file mode 100644 index 000000000..526c3f62e --- /dev/null +++ b/third_party/ulib/musl/INSTALL @@ -0,0 +1,177 @@ + +Quick Installation Guide for musl libc +====================================== + +There are many different ways to install musl depending on your usage +case. This document covers only the build and installation of musl by +itself, which is useful for upgrading an existing musl-based system or +compiler toolchain, or for using the provided musl-gcc wrapper with an +existing non-musl-based compiler. + +Building complete native or cross-compiler toolchains is outside the +scope of this INSTALL file. More information can be found on the musl +website and community wiki. + + +Build Prerequisites +------------------- + +The only build-time prerequisites for musl are GNU Make and a +freestanding C99 compiler toolchain targeting the desired instruction +set architecture and ABI, with support for a minimal subset of "GNU C" +extensions consisting mainly of gcc-style inline assembly, weak +aliases, hidden visibility, and stand-alone assembly source files. + +GCC, LLVM/clang, Firm/cparser, and PCC have all successfully built +musl, but GCC is the most widely used/tested. Recent compiler (and +binutils) versions should be used if possible since some older +versions have bugs which affect musl. + +The system used to build musl does not need to be Linux-based, nor do +the Linux kernel headers need to be available. + + + +Supported Targets +----------------- + +musl can be built for the following CPU instruction set architecture +and ABI combinations: + +* i386 + * Minimum CPU model is actually 80486 unless kernel emulation of + the `cmpxchg` instruction is added + +* x86_64 + * ILP32 ABI (x32) is available as a separate arch but is still + experimental + +* ARM + * EABI, standard or hard-float VFP variant + * Little-endian default; big-endian variants also supported + * Compiler toolchains only support armv4t and later + +* AArch64 + * Little-endian default; big-endian variants also supported + +* MIPS + * ABI is o32 + * Big-endian default; little-endian variants also supported + * Default ABI variant uses FPU registers; alternate soft-float ABI + that does not use FPU registers or instructions is available + * MIPS2 or later, or kernel emulation of ll/sc (standard in Linux) + is required + +* MIPS64 + * ABI is n64 (LP64) + * Big-endian default; little-endian variants also supported + * Default ABI variant uses FPU registers; alternate soft-float ABI + that does not use FPU registers or instructions is available + +* PowerPC + * Only 32-bit is supported + * Compiler toolchain must provide 64-bit long double, not IBM + double-double or IEEE quad + * For dynamic linking, compiler toolchain must be configured for + "secure PLT" variant + +* SuperH (SH) + * Standard ELF ABI or FDPIC ABI (shared-text without MMU) + * Little-endian by default; big-engian variant also supported + * Full FPU ABI or soft-float ABI is supported, but the + single-precision-only FPU ABI is not + +* Microblaze + * Big-endian default; little-endian variants also supported + * Soft-float + * Requires support for lwx/swx instructions + +* OpenRISC 1000 (or1k) + + + +Build and Installation Procedure +-------------------------------- + +To build and install musl: + +1. Run the provided configure script from the top-level source + directory, passing on its command line any desired options. + +2. Run "make" to compile. + +3. Run "make install" with appropriate privileges to write to the + target locations. + +The configure script attempts to determine automatically the correct +target architecture based on the compiler being used. For some +compilers, this may not be possible. If detection fails or selects the +wrong architecture, you can provide an explicit selection on the +configure command line. + +By default, configure installs to a prefix of "/usr/local/musl". This +differs from the behavior of most configure scripts, and is chosen +specifically to avoid clashing with libraries already present on the +system. DO NOT set the prefix to "/usr", "/usr/local", or "/" unless +you're upgrading libc on an existing musl-based system. Doing so will +break your existing system when you run "make install" and it may be +difficult to recover. + + + +Notes on Dynamic Linking +------------------------ + +If dynamic linking is enabled, one file needs to be installed outside +of the installation prefix: /lib/ld-musl-$ARCH.so.1. This is the +dynamic linker. Its pathname is hard-coded into all dynamic-linked +programs, so for the sake of being able to share binaries between +systems, a consistent location should be used everywhere. Note that +the same applies to glibc and its dynamic linker, which is named +/lib/ld-linux.so.2 on i386 systems. + +If for some reason it is impossible to install the dynamic linker in +its standard location (for example, if you are installing without root +privileges), the --syslibdir option to configure can be used to +provide a different location + +At runtime, the dynamic linker needs to know the paths to search for +shared libraries. You should create a text file named +/etc/ld-musl-$ARCH.path (where $ARCH matches the architecture name +used in the dynamic linker) containing a list of directories where you +want the dynamic linker to search for shared libraries, separated by +colons or newlines. If the dynamic linker has been installed in a +non-default location, the path file also needs to reside at that +location (../etc relative to the chosen syslibdir). + +If you do not intend to use dynamic linking, you may disable it by +passing --disable-shared to configure; this also cuts the build time +in half. + + + +Checking for Successful Installation +------------------------------------ + +After installing, you should be able to use musl via the musl-gcc +wrapper. For example: + +cat > hello.c < +int main() +{ + printf("hello, world!\n"); + return 0; +} +EOF +/usr/local/musl/bin/musl-gcc hello.c +./a.out + +To configure autoconf-based program to compile and link against musl, +set the CC variable to musl-gcc when running configure, as in: + +CC=musl-gcc ./configure ... + +You will probably also want to use --prefix when building libraries to +ensure that they are installed under the musl prefix and not in the +main host system library directories. diff --git a/third_party/ulib/musl/README b/third_party/ulib/musl/README new file mode 100644 index 000000000..a30eb1127 --- /dev/null +++ b/third_party/ulib/musl/README @@ -0,0 +1,23 @@ + + musl libc + +musl, pronounced like the word "mussel", is an MIT-licensed +implementation of the standard C library targetting the Linux syscall +API, suitable for use in a wide range of deployment environments. musl +offers efficient static and dynamic linking support, lightweight code +and low runtime overhead, strong fail-safe guarantees under correct +usage, and correctness in the sense of standards conformance and +safety. musl is built on the principle that these goals are best +achieved through simple code that is easy to understand and maintain. + +The 1.1 release series for musl features coverage for all interfaces +defined in ISO C99 and POSIX 2008 base, along with a number of +non-standardized interfaces for compatibility with Linux, BSD, and +glibc functionality. + +For basic installation instructions, see the included INSTALL file. +Information on full musl-targeted compiler toolchains, system +bootstrapping, and Linux distributions built on musl can be found on +the project website: + + http://www.musl-libc.org/ diff --git a/third_party/ulib/musl/README.fuchsia.md b/third_party/ulib/musl/README.fuchsia.md new file mode 100644 index 000000000..52b4b5e41 --- /dev/null +++ b/third_party/ulib/musl/README.fuchsia.md @@ -0,0 +1,7 @@ +This is a copy of [musl](http://www.musl-libc.org/) +at commit 49631b7b6c8b8c055aae5b6948930c219b95fdef + +Support for the native musl build system, unused tooling, and +unsupported architectures have been removed. + +Support for `PTHREAD_PROCESS_SHARED` has been removed. diff --git a/third_party/ulib/musl/WHATSNEW b/third_party/ulib/musl/WHATSNEW new file mode 100644 index 000000000..62daa1c90 --- /dev/null +++ b/third_party/ulib/musl/WHATSNEW @@ -0,0 +1,1693 @@ +0.5.0 - initial release + + + +0.5.9 - signal ABI bugfix, various cleanup and fixes: + +sigset_t was wrongly defined as 1024 bytes instead of 1024 bits, +breaking the intended ABI compatibility with the LSB/glibc sigaction +structure. users should upgrade immediately and rebuild any libraries +or object files that might be using the incorrect definitions. + +improved security against DoS with tcb shadow passwords by checking +that the file opened was really an ordinary file. + +fixed a bug in the implementation of atomic ops that could have +allowed the compiler to incorrectly reorder them (in practice, gcc +with the default settings on i386 was not reordering them). + +greatly improved conformance to the C and POSIX standards regarding +what the standard header files make visible. _POSIX_C_SOURCE is now +needed to get POSIX functions in standard C headers, and _XOPEN_SOURCE +or _GNU_SOURCE are required to get XSI interfaces or GNU extensions, +respectively. + +many internal improvements have been made to the syscall-related code +in preparation for porting to x86_64 and other archs. + + + +0.6.0 - x86_64 port, various important bugs fixed + +new x86_64 (amd64) architecture port, contributed by Nicholas J. Kain, +along with PORTING guide. source tree layout and build system have +been improved to accommodate further ports. + +various bugs that were introduced while making the headers respect C +and POSIX namespace standards have been fixed. conformance to the +standards has been improved. + +fixed an inefficiency in qsort that triggered a bug (occasionaly +internal compiler error) in some versions of gcc. + +fixed a major bug in the printf %n specifier that prevented it from +working and caused memory corruption. + + + +0.7.0 - major improvements to posix conformance and completeness + +implemented posix shared memory and semaphore interfaces. + +implemented all remaining required pthread and clock interfaces. + +major fixes to signal semantics. + +greatly improved temporary file name generation for safety against +denial of service due to intentional name collisions. + +added syscall wrappers for the linux inotify interface. + +malloc(0) now returns a non-null pointer. + +fixed printf %n specifier (again), pthread_once (it was always +hanging), and non-default-type mutex behavior. + +added ucontext/sigcontext support in headers to facilitate building +libgcc with dwarf2 unwind support, and possibly other low-level tools. + +improved musl-gcc compiler wrapper. + +implemented many small missing functions here and there, minor header +fixes, etc. + + + +0.7.1 - improvements to completeness, bug fixes + +implemented flockfile, wprintf, and robust mutex functions. + +fixed stack corruption bug in times(), minor header bugs, and some +error return value bugs in thread interfaces. + + + +0.7.5 - new features, major optimization, and robustness + +implemented POSIX timers. + +optimized and simplified many thread-related functions. + +eliminated resource leak races in thread cancellation. (almost all +existing implementations, including glibc, have these leaks.) + +overhauled stdio implementation to take advantage of readv/writev for +reduced syscall load, and improved stdio's handling of error status. + +added syscall header and interface for applications to use and +greatly simplified internal system for making syscalls. + +strangthened tmpnam/tempnam/tmpfile filename generation and made the +straight C functions not depend on POSIX symbols. + +fixed pthread cancellation ABI on i386 to match the LSB/glibc ABI + +better double-free handling in malloc + +various minor bug fixes + + + +0.7.6 - major bug fixes + +fixed rare but serious under-allocation bug in malloc. + +fixed signedness bug in strchr that prevented finding high bytes. + +fixed serious parsing bugs in strtold. + +fixed statvfs syscall (it was always failing with EINVAL). + +fixed race condition in set*id() functions with threads (possible +deadlock). further audit still needed though. + +fseek no longer sets the stream error flag on failed seeks (this was +wrong and broke some programs, notably GNU m4). + +nl_langinfo is no longer a dummy function. (the functionality was +previously implemented but accidentally left unused). + +various small fixes have been made to the implementations and +prototypes for nonstandard and obsolete functions + + + +0.7.7 - more bug fixes and program-compatibility improvements + +fixed floating point formatting and rounding bugs in printf. + +fixed broken %N$ positional argument specifiers in printf. + +fixed misaligned read/overread bug in strchr which could lead to +crashes scanning tiny strings at the end of a page when the next page +is not readable, or on archs (not yet supported) that forbid +misaligned reads. + +fixed breakage of statvfs on x86_64 + +fixed crash in getmntent_r + +fixed bug in POSIX timers created with NULL sigevent argument + +improved semaphore performance, and sem_wait is now interruptable by +signals, as required by POSIX. + +added many compatibility and system-level interfaces, increasing the +proportion of busybox that works with musl. + + + +0.7.8 - more bug fixes and compatibility improvements + +fixed problems with ipv6 dns and address printing code that made ipv6 +support practically unusable, and some other getaddrinfo bugs. + +fixed broken sendmsg/recvmsg functions on x86_64 (caused by incorrect +msghdr structure). + +fixed broken sigsetjmp asm on x86_64. + +worked around a problem with input buffering on terminals reblocking +after getting a blank line, due to a bug in the linux readv syscall. + +various improvements to the "rsyscall" system used to implement +threaded setuid, setgid, etc. + +exiting/cancelling the a timer handler thread no longer kills the +timer. + +fixed incorrect trailing zeros on some %g conversions in printf. + +fixed buggy byte-swapping functions and moved them to inlines in +byteswap.h. + +many small improvements to header/application compatibility, support +for nonstandard macros, etc. + + + +0.7.9 release notes + +new pthread cancellation implementation: +- safe against resource-leak/side-effect-leak race conditions +- safe against interruption by signal handlers +- reduced bloat in all cancellable functions +- reduced bloat for blocking cancellation + +new interfaces implemented: +- realpath (limited functionality) +- wordexp (limited functionality) +- flock (nonstandard) +- forkpty (nonstandard) +- posix_fadvise +- posix_fallocate + +general bug fixes: +- syslog function failure to communicate with syslogd +- bug in siginfo_t definition if wait.h was included before signal.h +- incorrect struct definitions for most of sysv ipc +- pthread_exit/cancel on timer handler wrongly destroying the timer +- linux dup2 ebusy workaround +- obscure issues in non-threaded programs using some pthread functions +- getopt_long allowed mismatch in last char of option name +- incorrect parsing of obscure ip address forms +- initgroups not working reliably (uninitialized var) +- shadow pass treating empty expiry field as pass-expired-in-1970 +- bogus longjmp if pthread_exit was called from cancellation handlers + +x86_64-specific bug fixes: +- fcntl file locking +- thread stack alignment +- broken select timeouts due to incorrect timeval definition + + + +0.7.10 release notes + +new features: +- ipv6 numeric string parsing +- eventfd syscall wrappers + +optimizations: +- new qsort implementation using the smoothsort algorithm +- much smaller/faster sigset_t handling functions +- lowered spin count before futex wait in synchronization functions + +general bug fixes: +- incorrect floating point round-to-even behavior in printf +- major bugs in pthread barrier implementation +- off-by-one error in scanf %n results +- scanf failure to report EOF when scanning for literal text +- minor missing/incorrect prototype issues +- dependency on undefined call order in fclose + +compiler issue workarounds: +- incorrect inlining of variadic functions on recent gcc versions +- pcc preprocessor bug with recursive macro expansion + + + +0.7.11 release notes + +new features: +- integrated dynamic linker +- dynamic loading (dlopen/dlsym) (for dynamic-linked programs only) +- XSI search.h API +- POSIX message queues +- POSIX spawn interfaces +- BSD pseudo-random number generator API (random/srandom/initstate/etc.) +- floating point environment (limited usefulness due to gcc bugs) + +general bug fixes: +- possible crashes with wordexp due to uninitialized variable +- race condition in pthread_kill (also present and unfixed in glibc/nptl) +- pthread exit destructors called too late +- dangerous unbounded vla in glob +- brk/sbrk legacy functions mismatching legacy semantics +- wcsncpy dest buffer overflow +- strncat and wcsncat possible overflows due to double-termination + + + +0.7.12 release notes + +new features: +- support for textrels in shared objects +- rpath support in dynamic linker +- stdio_ext.h functions (for better gnu software compatibility) + +bug fixes: +- some compilers miscompiling dlopen due to misuse of longjmp +- safe handling of invalid long-double bit patterns (affects printf) +- workaround for bugs in linux mprotect syscall +- thread-safety for random() functions +- various minor issues + + + +0.8.0 release notes + +new features: +- chinese and japanese legacy charset support in iconv +- zero-syscall clock_gettime support (dynamic-linked x86_64 only) +- futex-based locking for stdio (previously used spinlocks) +- LD_PRELOAD and RTLD_NEXT support in dynamic linker +- strptime (mostly working but incomplete) +- posix aio (mostly working but not entirely conformant) +- memory streams (fmemopen, open_memstream, ...) +- stub/dummy implementations for various useless legacy functions +- if_nameindex + +security hardening: +- setuid, etc. should not longer be able to "partially fail" with threads +- ensure suid programs start with fd 0,1,2 open +- improved openpty/forkpty failure checks + +threads/synchronization bug fixes: +- dangerous spurious wakeup in pthread_join lead to early return +- race condition enabling async cancellation (delayed/lost cancellation) +- destruction/unmapping race conditions in semaphores, mutexes, rwlocks +- recursive rwlock_rdlock deadlock when a writer is waiting +- race condition in sigqueue with fork +- timer expiration thread exit wasn't running dtors +- timer threads weren't blocking signals +- close was wrongly cancellable after succeeding on some devices +- robust mutex list was not reset on fork + +general bug fixes: +- incorrect logic in fread (spurious blocking; crash on write-only files) +- many corner cases and overflow cases for strtol-family functions +- various printf integer formatting issues with flags/width/precision +- incorrect iconv return value on failure +- broken FD_* macros on 64-bit targets +- clock function returning wrong value (real time not cpu time) +- siglongjmp signal mask clobbering (off-by-one pointer error) +- dynamic linker weak symbol resolution issues +- fdopendir failure to set errno +- various minor header fixes + + + +0.8.1 release notes + +bug fixes: +- mismatching prototypes caused build failure on 64-bit +- other minor prototype errors in the headers have been fixed +- various other small omissions fixed + + + +0.8.2 release notes + +new features: +- ptrace syscall support + +bug fixes: +- const error (only a warning with many compilers) in lio_listio +- minor portability fixes aimed at supporting new arch targets + + + +0.8.3 release notes + +new features: +- arm port (experimental) +- better musl-gcc wrapper script for building against musl +- added clone system call + +bug fixes: +- numerous header file typos, copy/paste errors, omissions +- statfs and statvfs ABI are now LSB-conformant (and actually work) + + + +0.8.4 release notes + +new features: +- arm dynamic linker support +- process-shared pthread barriers now work +- efficient futex-requeue-based cond var broadcast +- more optional cancellation points are now cancellable +- printf accepts null pointers with %s, prints as "(null)" +- recursive mutexes are now fully reentrant +- __cxa_atexit support +- real vfork +- dynamic linker now gold-compatible +- prlimit syscall +- support for large limits with setrlimit/getrlimit (even on 32-bit) +- glob now supports GLOB_PERIOD option (GNU extension) + +bug fixes: +- many serious issues in condition variables +- rwlock failure-to-wake deadlock issues +- various small header files bugs/omissions +- wrong failure return for pthread_create +- path handling issues on execvp +- lock count corruption with robust recursive mutexes on owner death +- integer overflows in atoi, etc. reading most-negative value +- spurious mremaps on every realloc of large memory chunks +- pthread cancellation failure in single-threaded programs + +security: +- avoid fd_set overflow in dns lookups + + + +0.8.5 release notes + +new features: +- stdio operations are now cancellable (only when low-level io happens) +- global ctor/dtor support in main program start code and shared libs +- dynamic linker support for PIE executables (but missing startup code) +- vfork support on x86_64 +- complete set of locale_t functions (all ignore the locale argument) +- provide define float_t and double_t in math.h +- lighter/faster cancellation cleanup handler register/unregister + +bug fixes: +- gcc wrapper now supports -shared, -nostdlib, -nostartfiles +- removed one wrongly-classified character from iswspace set (zwsp) +- fixed crashes in dns lookup on some errors, e.g. resolv.conf missing +- "make install" no longer tries to build shared libc if disabled +- ptrace argument handling bugs fixed +- work around visibility-hidden bugs in gcc 3.x +- fix thread-pointer-loss issue when it's initialized in signal handlers +- various minor typo/misc fixes in headers + +compatibility: +- glob behaves more like traditional implementations w.r.t. GLOB_MARK +- added legacy futimes, lutimes functions +- more compatibility macros in sys/param.h (nonstandard header) +- setfs[ug]id syscall wrappers (linux specific) +- fgetpwent function (nonstandard) +- utmp.h matches traditional version more closely +- caddr_t now matches glibc type (void * instead of long) +- dummy (always-fail) dlopen and dlsym functions for static linked programs +- [efg]cvt functions (previously posix, removed from standard) +- get_current_dir_name function (nonstandard) + + + +0.8.6 release notes + +bug fixes: +- fix crash in dns lookups for all static-linked, non-threaded programs + + + +0.8.7 release notes + +new features: +- c++ support with g++'s libstdc++ +- c99 math library (float, long double, complex, etc.) +- numerous wchar_t functions +- a64l, l64a functions +- getdate function + +compatibility: +- c89 compatibility in math.h +- syscall.h alias for sys/syscall.h +- memory.h alias for string.h +- getcwd supports null buffer argument (auto-allocation) + +bug fixes: +- major fenv (floating point environment) fixes and optimizations +- strptime mishandling of day/month names +- strtoull wrongly rejecting the highest 16 possible values as overflow +- math.h constant expression fixes for INFINITY/NAN/etc. +- scanf mishandling of "0" with "%x" + + + +0.8.8 release notes + +new feature: +- major math correctness and performance improvements +- many math functions implemented in asm for i386 +- some math functions (mostly long double) in asm for x86_64 +- new floating point parser/converter with correct rounding +- implement wcstod, wcstof, and wcstold +- new scanf implementation - cleaner, faster, more correct +- minimal/incomplete strfmon implementation + +compatibility: +- header fixes for c++ +- regex code resync with TRE; support common regex extensions +- support for compiling apps with gcc's -funsigned-char +- sysconf now returns dynamic limits for open files, processes +- give dlerror proper error status stickiness +- make alloca work even with -fno-builtin + +critical security fixes: +- stack-based buffer overflow in fprintf on unbuffered files + +other bug fixes: +- rare gcc register allocation (miscompilation) bug in syscall wrappers +- printf was rejecting the valid (but redundant) %lf format specifier +- fixed big data bloat (missing const) in math functions +- many math fixes related to floating point exceptions and rounding +- corrected DECIMAL_DIG definitions +- tgammal was wrongly setting global signgam +- crash in wordfree with uninitialized we_offs +- fix wordexp not null-initializing the we_offs initial slots + + + +0.8.9 release notes + +bug fixes: +- major breakage in strtol and family: failure to accept leading spaces +- incorrect name for MATH_ERREXCEPT in math.h + +compatibility: +- prototypes for a few additional nonstandard functions + + + +0.8.10 release notes + +new features: +- correct over/underflow detection (ERANGE setting) for strtod +- new musl-gcc wrapper, specfile based, faster and more robust +- meaningful return strings for dlerror +- new iswalpha, iswpunct, and wcwidth; sync'd to Unicode 6.1 +- towupper/towlower sync'd with Unicode 6.1 +- new futex-based libc-internal locks instead of spinlocks +- experimental stack protector support (minimal; no random canary) +- experimental gdb shared library tracking support + +compatibility: +- getusershell family functions +- getresuid and getresgid syscall wrappers +- byte swapping macros in endian.h +- getdtablesize was wrongly declared in unistd.h for _XOPEN_SOURCE + +bug fixes: +- iconv_open wrongly rejecting most dest charsets (broken in 0.8.0) +- sysconf failure when correct value is -1 (broken in 0.8.8) +- scanf and strtod family functions overreading past NAN (4 bytes vs 3) +- scanf and strtod wrongly treating "0.00000000001", etc. as 0 +- many bugs in towupper/towlower (never seriously tested before) +- int8_t definition was wrong when gcc -funsigned-char was used + + + +0.9.0 release notes + +license change: MIT + +new features: +- configure script, improved build system +- full stack protector support +- PIE support on x86 and x86_64 +- new O(1) space, O(nm) time implementation of fnmatch +- improved support for sse2 floating point mode on x86 + +compatibility: +- added linux unshare syscall +- exp10/pow10 function +- sqrtl support on arm (previously missing) +- removed minimal linux/*.h headers that could conflict with real ones +- support for _LARGEFILE64_SOURCE (mapped to standard fcns with #define) +- better c89 compatibility in headers +- stub versions of sched_* functions (previously missing) +- pthread stacks no longer executable (compat with hardened kernels) +- new ar.h and lastlog.h (legacy junk) +- various other header improvements + +optimization: +- additional x86_64 math asm +- better formula for acos use in i386 asm + +bug fixes: +- large (up to a few %) errors in strtod for certain values due to bug +- mbsnrtowcs and wcsnrtombs were completely broken (bad exit logic) +- wide printf %.0s could fail due to uninitialized variable +- missing dlerror strings for dlsym in some cases + + + +0.9.1 release notes + +new features: +- dynamic linker can be used as a program to explicitly load/run executables +- ldd command, usable by making a symlink to the dynamic linker named ldd + +bug fixes: +- major bugs in POSIX BRE parsing inherited from TRE regex code +- character matching bug in regex on ARM: WCHAR_MAX was assumed to be signed +- various obscure fixes related to signals and pthread cancellation +- remquot subnormal remainder bug +- buggy macros in (nonstandard) sys/param.h +- major bug in pthread barriers on x86_64 (out of bounds write) +- utimes (legacy) function was making wrong syscall (utime instead of utimes) +- avoid using "old" syscalls that don't exist on arm eabi linux +- broken strrchr(str, 0) +- broken mbsinit(0) +- broken wcsncmp +- syntax error in nextafter macro in tgmath.h +- missing support for -pie in musl-gcc wrapper +- abort could wrongly fail to terminate the program in some cases + +compatibility: +- increase default thread stack size to 80k +- support _BSD_SOURCE feature test macro +- support _LARGEFILE64_SOURCE feature test macro (merely exposes alt names) +- lots of legacy-compatibility improvements in headers +- various minor GNU extension functions +- sysconf reporting number of available CPUs/cores +- various LSB/glibc ABI interfaces aimed at compatibility with some binaries +- use fistpll asm mnemonic instead of fistpq for compat with clang + + + +0.9.2 release notes + +bug fixes: +- pointer overflow in printf (crash on 32bit userspace, 64bit kernel) +- printf %ls over-read bug +- strtod failure to read -0x as negative zero +- flush stdio after dtors, not before +- wrong file position for buffered input streams on exit +- popen was broken when stdin/out were already closed +- broken wcwidth tables (missing many characters) +- fwrite: wrong return value of partial/failed write +- broken utf-16 conversions +- bad buffer length check in getlogin_r +- bad perror("") behavior; did not match perror(0) +- broken sysinfo syscall/structure +- stdint.h const macro signedness bugs +- broken include guards in some headers +- bogus localeconv values +- cancellation-safety for popen and pclose +- fma corner cases wrong on i386 +- fcntl F_GETOWN errno missing on failure. +- char signedness bug in dynamic linker broke dlopen on arm +- mprotect failure in dynamic linker caused crash instead of error + +build system: +- configure check to work around hacked-up gcc versions +- test for old binutils that can't support musl dynamic linker + +compatibility: +- make _GNU_SOURCE imply _LARGEFILE64_SOURCE +- syscall wrapper for lots of nonstandard and/or legacy linux syscalls +- versionsort stub +- timegm function (inverse of gmtime) +- various minor header tweaks +- make __freading/__fwriting semantics match traditional ones +- added gnulib-compatibility stdio interfaces +- added pthread_attr_setstack interface +- make strerror_r return partial string when buffer is too small +- duplocale should accept LC_GLOBAL_LOCALE +- align ptsname_r to upcoming posix requirements +- support invalid ld80 bit patterns as extra nans. + + + +0.9.3 release notes + +new features: +- mips (32-bit, o32 abi) port, currently static-linked only +- newly overhauled crypt implementation +- improved library pathname info for debugger from the dynamic linker +- getaddrinfo (and getservbyname) now support /etc/services lookups +- pipe2 syscall wrapper +- splice and vmsplice syscall wrappers +- syscall wrappers for extended attribute interfaces +- ioperm/iopl syscall wrappers on archs that support these operations + +bug fixes: +- dlsym RTLD_NEXT library search order was wrong +- multiple dlopen pathname and library name handling errors +- potential race condition in detached thread exit +- broken internal-lock-handling code not updated for futex-based __lock +- sem_trywait spurious EAGAIN errors arising from CAS failures +- workaround kernel bug in cmsghdr size_t vs socklen_t issue (64-bit) +- getservby* crash on null protocol argument +- logic error skipping failed interfaces in if_nameindex +- various minor header/declaration related issues + +arm-specific bug fixes: +- broken crti/crtn startup code when gcc crtbegin/end files are linked +- sigsetjmp tail call optimization failure broke the function +- incorrect little-endian assumptions in atomic.h functions +- use of blx instruction in asm (not supported on pre-v5 arm) + +build system: +- only use expensive -ffloat-store cflag on archs/compilers that need it +- make musl-gcc wrapper support -lgcc (mainly for self-hosting) + + + +0.9.4 release notes + +new features: +- blowfish crypt +- dynamic linking on mips +- arm hard float support +- BSD fgetln function in stdio +- minor header improvements for compatibility +- support for CROSS_COMPILE variable to configure +- legacy significand function +- better support for SUSv3-targeted programs + +performance: +- assembly (string ops based) memcpy for i386 and x86_64 +- reduce printf overhead + +bug fixes: +- failure of strtod, etc. to process extremely long strings correctly +- read overrun in wcsstr for short needles +- various major mips issues that prevented most software from working +- erroneous floating point exception behavior in i386/x86_64 exp asm +- crashes on null arguments to legacy err.h functions +- various header file/type issues +- extremely rare/obscure race condition with robust mutexes +- crypt now never returns null (most programs don't check, then crash) +- missing xattr remove functions + + + +0.9.5 release notes + +compatibility and headers: +- POSIX+XSI+BSD features enabled by default with no macros defined +- most programs can now be built without adding -D_GNU_SOURCE +- added C99 restrict keyword where required in all prototypes +- greater C89 compatibility +- cleaner, more-compatible public syscall.h +- many other header fixes +- support for compiling musl with clang/llvm + +new features: +- sha 256/512 password hash functions in crypt +- GNU hash support in dynamic linker +- partial C11 coverage +- dladdr function added +- dynamic linker reports all errors instead of exiting on first error +- syscall wrappers added for most remaining linux syscalls +- provide POSIX O_SEARCH open mode using linux O_PATH + +bug fixes: +- most atexit functions were being skipped when exiting +- some BSD functions were not being exposed under _BSD_SOURCE +- issues loading ssp-protected DSO into non-ssp program with dlopen + +debloating: +- eliminate .eh_frame (10-15% loaded size bloat) +- optimal inline syscall asm for ARM and MIPS +- no longer force -O3 for shared libs + + + +0.9.6 release notes + +bug fixes: +- serious breakage in definition of O_ACCMODE mask (missing a bit) + +new features: +- O_EXEC open mode +- md5 crypt hash function + + + +0.9.7 release notes + +new features: +- thread-local storage (__thread/_Thread_local) +- microblaze port +- getopt option parsing reset support +- vsyscall (sysenter, etc.) support on i386 (faster syscalls) +- memmem function (GNU extension) +- mips fenv support +- accept "nan(n-char-sequence)" in strtod/scanf family functions +- configure now supports compiling with pcc + +quality and correctness improvements: +- close-on-exec flag for all library-internal file descriptors +- cancellation-safety and corner-case overhaul in shm_open/sem_open +- close EINTR vs EINPROGRESS issue +- mark binaries as not requiring executable stack +- better gdb compatibility in dynamic linker +- support recursive dlopen (dlopen called from constructors) +- posix_spawn/system/popen no longer momentarily double commit charge +- all stdio functions wait for locks + +bug fixes: +- broken sysvipc *ctl functions on 64-bit archs +- broken shmdt on some archs +- getaddrinfo failure with port "0" +- dirname handling of trailing slash +- vfork race in posix_spawn + + + +0.9.8 release notes + +new features: +- powerpc port +- dl_iterate_phdr interface +- added mips-specific syscalls +- thread priority scheduling +- C11 CMPLX macro in complex.h +- x86 port io functions in sys/io.h + +compatibility: +- improved headers for trace/debugging/machine-access +- stub functions for unsupported thread-related functionality + +bug fixes: +- numerous math bugs (mostly exception flags and excess-precision issues) +- register clobber error in i386 vsyscall asm (did not affect most callers) +- various incorrect definitions in mips headers +- broken dlsym asm on mips +- empty prefix handling in configure script (--prefix="") +- ldso search path logic issues +- lock handling for stdio memory streams at exit time +- invalid SO_REUSEPORT definition in socket.h (not supported by Linux) +- broken redirection attempt to /dev/null in configure script + + + +0.9.9 release notes + +new features: +- tgamma implementation (no longer lgamma wrapper with low precision) +- various gnu extensions: sigandset, sigorset, etc. +- futimesat function (obsolete) +- various linux syscalls: arch_prctl, personality, etc. + +optimizations: +- hyperbolic, inverse hyperbolic, and inverse trig, bessel functions +- is* comparison macros in math.h now expand inline properly + +library bugs fixed: +- calling getenv from shared library ctors was broken +- invalid read in mmap-serviced aligned_alloc/memalign (possible crash) +- wrong errno result in fallback path of pipe2 +- various math functions raising spurious exceptions +- mmap errno value on invalid offsets +- backwards alignment logic in strlcpy +- integer overflows in bessel functions +- large (up to 60ulp) error in erfcf +- dlsym/dlclose crashing on invalid library handles +- failure to handle arch variations for cloexec/nonblock flags +- lio_listio wrong return value for LIO_WAIT mode +- dladdr failure to resolve PLT addresses +- time_t/struct tm conversion off-by-one-day in december +- malloc corruption on nonstandard kernels with non-page-aligned brk + +arch-specific bugs fixed: +- arm ctors/dtors were not working with recent gcc versions +- arm and mips setjmp/longjmp wrongly saved/restored fenv state +- loss of precision in i386/x86_64 expl + +header bugs fixed: +- incorrect PRI/SCN macros in inttypes.h for some types +- arm sys/user.h regressions +- failure of offsetof() to be an integer constant expression +- tgmath return value type problems + +header compatibility improvements: +- _GNU_SOURCE now enables everything; _ALL_SOURCE also works +- scsi/scsi.h and scsi/sg.h are now provided +- additional MAP_* flags for mmap +- additional F_* commands and flags for fcntl +- additional socket option, IPPROTO_* values, and multicase macros +- thread-related waitpid flags +- EHWPOISON added to errno.h +- additional macros for mount, swap, and reboot operations +- expose additional link.h structures +- always ensure sizeof(NULL)==sizeof(void *), even in c++ +- additional flags for poll, epoll, inotify, timerfd, timex, dlfcn +- register names in signal.h/ucontext.h for x86 +- ipc.h ipc_perm nonstandard struct field name compatibility improve + + + +0.9.10 release notes + +new features: +- getifaddrs +- pthread_getattr_np (widely used by garbage collectors) +- mkostemps, mkostemp, mkstemps functions (mkostemp is future-POSIX) +- strcasestr and strverscmp (previously stubs) + +improvements: +- major performance improvements in mbtowc +- avoid filling caller-provided thread stacks with large TLS +- debloat unnecessary static buffers +- robust posix_spawn based on CLONE_VM instead of vfork +- new system() and popen() based on posix_spawn +- better strerror strings +- further emulation of atomic close-on-exec/nonblock options for old kernels +- provide macro constants for new-ish kernel features + +compatibility: +- several nonstandard but widely-available pwd/grp/shadow functions +- program_invocation_[short_]name +- re-added useconds_t type used by some programs +- some legacy arpa headers +- dn_skipname function (legacy resolver API) +- additional ABI aliases for supporting glibc-linked libraries/binaries + +general bugs fixed: +- stale locks and bogus munmap call when pthread_create fails +- uninitialized argument to munmap when dynlink load_library fails +- incorrect error returns in gethostby*_r +- memory leak in gethostbyname family +- blank ai_canonname in getaddrinfo for non-CNAME records +- undefined HZ macro in scsi/sg.h +- wrong return value for wmemmove on forward-copy +- namespace conformance in strings.h +- various utmp.h bugs +- unnecessary DT_SONAME in libc.so caused problems on some systems +- multiple bugs in syslog, some possibly dangerous +- non-functional setpriority function +- slight mishandling of 0xf5 byte in UTF-8 decoder +- misaligned memory accesses in mbsrtowcs + +arch-specific bugs fixed: +- crash in shared library loading on arm +- missing __aeabi_atexit needed by arm eabi +- wrong float_t definition on x86_64 +- various low-impact type size/alignment mismatches in some headers +- epoll struct alignment wrong on non-x86[_64] archs +- broken pipe2 fallback code on mips with old kernels + + + +0.9.11 release notes + +new features: +- %m allocation modifier for scanf +- week number and ISO week-based-year functionality in strftime +- per-process and per-thread cputime clocks +- ethernet address conversion interfaces +- legacy classful ipv4 network address interfaces +- minimal dlinfo function (nonstandard) + +other improvements: +- dynamic linker path file can now use newlines to separate paths +- math optimizations for archs with extended precision (i386) +- musl-gcc wrapper now exposes gcc's intrinsic headers +- quality of rand and rand_r pseudo-random sequences +- support for large device minor numbers (greater than 8 bits) +- various header conformance and compatibility fixes + +directly user-visible bugs fixed: +- scanf losing characters on unbuffered streams and fmemopen streams +- failure of mbsrtowcs to record stop position when dest is full +- failure of iconv to convert to legacy codepages +- non-working pthread_[sg]etschedparam functions (wrong syscall arguments) + +other potentially-serious bugs fixed: +- resource leaks in sem_open +- various bugs in thread exit synchronization +- invalid access in aio notification after aiocb free/reuse +- synchronization in dynamic linker when new thread dlopens during ctors +- lack of error handling for failure to read dynamic linker path file +- creation by mmap or shmget of objects larger than PTRDIFF_MAX + +minor conformance bugs fixed: +- overflow handling for the clock function +- workaround for incorrect exceptions in fma due to compiler bugs +- workaround wrong kernel type for sem_nsems field in struct semid_ds + +arch-specific bugs fixed: +- x86_64 sigsetjmp clobbered the signal mask rather than saving it +- misaligned stack when calling ctors/dtors (crashing on x86_64) + + + +0.9.12 release notes + +new features: +- zoneinfo time zone support +- PIE support on all supported archs +- named sub-archs for endian and float ABI variants +- improved support for non-root installs of the dynamic linker +- ability to selectively build only performance-critical modules with -O3 +- simple buffer overflow detection in free/realloc +- inet_ntop now presents v4-mapped addresses in ::ffff:a.b.c.d form +- ldd now reports libc and the dynamic linker in its output + +compatibility: +- support for new init/fini array (needed for ctors/dtors on newer gcc) +- C++ ABI fully matches glibc/LSB, at least on x86 +- many added ABI compatibility symbols for using glibc-linked libs +- support for STB_GNU_UNIQUE symbol bindings (found in some C++ libs) +- macros/types for new Linux kernel features in headers + +bugs fixed: +- crashes in scanf on literal mismatches (regression from adding %m) +- dl_iterate_phdr was passing invalid phdr pointers to its callback +- getaddrinfo with null host and AF_UNSPEC was failing to report IPv6 +- integer overflows in date/time conversion code +- misinterpretation of pre-1930s dates as post-2038 on 32-bit archs +- make install failed to install bits headers if make was not run first +- shm_open was wrongly cancellable +- low- or no-impact heap corruption in memalign +- explicitly running the dynamic linker on PIE programs did not work +- missing macros and sysconf for some supported POSIX option groups +- missing close-on-exec flags for several internal fd uses + +arch-specific bugs: +- wrong SIG_ATOMIC_MIN/MAX macros on x86_64 +- erfcl was missing on archs where long double is same as double +- broken dynamic-model TLS in static-linked arm/mips/powerpc programs + + + +0.9.13 release notes + +new features: +- iconv support for EUC-KR and Big5 (including HKSCS) encodings +- field widths (POSIX 2008 feature) in strftime +- recursive rpath and $ORIGIN support in dynamic linker +- cpu affinity interfaces +- support for armhf (hardfloat) floating point environment (fenv) +- support for SSE fenv on i386 (for apps using -mfpmath=sse -msse2) +- strftime %s format (seconds since the epoch, future POSIX requirement) +- configure script now saves its command line as a comment in config.mak +- legacy functions valloc and euidaccess + +performance: +- optimized asm memcpy for arm +- optimized asm memset for i386 and x86_64 +- optimized C versions of memcpy and memset for all archs +- eliminated major spurious syscalls from posix_spawn +- some math asm for armhf (hardfloat) + +workarounds for: +- qemu-user's rt_sigaction syscall does not allow old to alias new +- qemu-user's madvise always succeeds (broke pthread_getattr_np) +- passing PT_INTERP to dlopen attempted to double-load libc +- gcc 4.8.x generating self-referential (infinite recursion) memcpy/memset +- linux's lack of support for fchdir, fchmod, fchown, fstat on O_PATH fds + +bugs fixed: +- failure to honor flags for fchmodat and faccessat (linux syscall api flaws) +- SIGEV_THREAD timer id corruption and race condition issues +- timer thread TLS incorrectly keeping values from previous expiry run +- ecvt/fcvt decimal position off-by-one +- in symbol-versioned libs, symbol resolved to oldest instead of newest +- posix_spawn not correctly reporting errno from exec failure +- "make install" was not atomic (overwrote files rather than replacing) +- integer overflows in strftime +- unset/empty TZ variable was mishandled +- strftime could crash if the struct tm did not have valid tm_zone field +- failure of fenv functions to handle invalid arguments (required by ISO C) +- failure of some math functions (C and i386 asm) to raise underflow flag +- broken dn_expand function (previously not used internally) +- race conditions with signals during fork +- incorrect access check in mktemp (obsolete function) +- unnecessary arbitrary limits on size of program headers in dynamic loader +- text formatting bugs in output of err.h functions + +arch-specific bugs: +- fesetenv(FE_DFL_ENV) crashed on i386 +- breakage of arm crt code when libc is compiled as thumb +- arm/armhf (hardfloat) misidentified by configure +- ambiguity of wait (exit status) macros on mips with signal number 127 +- wrong value of _NSIG and SIGRTMAX on mips + + + +0.9.14 release notes + +bugs fixed: +- failure to properly install dynamic linker with DESTDIR set (symlink wrong) +- rare deadlock in libc-internal locking routines +- dynamic linker used fallback paths wrongly on (possibly transient) errors +- popen broken when stdin or stdout was already closed in parent +- deadlock/memory-corruption in multithreaded set*id and setrlimit functions +- realpath failed when file was not readable +- readpath mistakenly had cancellation points in it +- crashes in scanf with invalid %m conversion specifiers +- misclassificiation of some invalid ld80 float representation in fpclassify +- various overflow and underflow flag issues in math functions +- domain handling errors for acoshf and acoshl +- wrong values for some sysconf properties +- lack of proper memory barriers on arm + +mips-specific bugs: +- broken sysv ipc structures +- multiple stack-related bugs in clone, leading to crashes in parent or child +- overflow writing sigset_t in multithreaded set*id and setrlimit functions + +other improvements: +- size and performance improvements to various math functions +- wait.h as a compatibility alias for sys/wait.h +- various header improvements +- support for runtime-variable page size on archs that need it (mainly mips) + + + +0.9.15 release notes + +new features: +- support for mixing IPv4 and v6 nameserver addresses in resolv.conf +- RFC 3678 multicast structures/macros in netinet/in.h +- putspent and fgetspent functions (shadow password API) +- timef function (obsolete, removed in POSIX 2008) +- fanotify syscalls (Linux-specific feature) +- semtimedop syscall (Linux-specific sysvipc extension) +- quotactl syscall and header (filesystem quotas support) +- drem and finite functions (obsolete BSD functions) +- getloadavg function (non-standard) +- herror function (non-standard and obsolete) +- libc.so now stores and prints its version information +- expose constants for new Linux features including O_TMPFILE +- implement FNM_LEADING_DIR option to fnmatch (GNU extension) +- posix_close function (accepted for inclusion in next POSIX issue) + +bugs fixed: +- buffer overflow in mbsrtowcs +- clobbering of gr_name in getgrnam_r and getgrgid_r +- execle ignoring the environment argument +- setenv crash on malloc failure +- out-of-bounds access in fnmatch with FNM_PATHNAME and certain patterns +- failure of malloc to set errno when failing to extend heap +- incorrect errno value from getcwd with zero size +- spurious failure in faccessat with AT_EACCESS flag with suid/sgid programs +- several fd leaks due to missing close-on-exec flag +- misspellings/typos in macro names in several headers +- incorrect failure return value in inet_pton +- various numeric ip address parsing and validation fixes +- namespace conformance issues in several headers +- minor header issues +- zombie processes left by faccessat with AT_EACCESS +- timezone file parser failing/crashing on 64-bit archs +- hang in localtime with near-overflowing time_t values on 64-bit archs +- timezone path search was only trying first path +- incorrect handling of excessive-length TZ environment strings +- timezone file loading was wrongly enforcing O_NOFOLLOW/rejecting symlinks +- iswspace was wrongly returning true for the null character +- various bugs in wordexp +- putgrent could write corrupt lines after write failures +- dn_expand misinterpreted in-packet offsets greater than 255 +- spurious strftime/wcsftime failure on len+1==bufsize case +- incorrect underflow flag in fma corner cases +- log*(0) wrongly returned +inf in downward-rounding mode +- failure of fchmod, fstat, fchdir, and fchown to produce EBADF + +arch-specific bugs fixed: +- i386: failure of fesetround to set sse rounding mode +- i386: floating point limit constants misinterpreted due to excess precision +- powerpc: broken thread pointer access when compiled with clang +- microblaze: dynamic linker entry point code possibly clobbering argv + +strict conformance issues: +- NULL definition re-aligned with POSIX (requires (void *) cast) +- alignment of math.h is* comparison functions with C11 annex F requirements + + + +1.0.0 release notes + +new features: +- support for mips softfloat ABI variant +- legacy setkey and encrypt API for DES +- support for BSD version of struct tcphdr in addition to GNU version +- added ipv6 and icmpv6 protocol lookups to getprotoent-family functions + +new experimental ports: +- sh (SuperH) +- x32 (ILP32 ABI for x86_64) + +compatibility: +- improved c89 compiler support in math.h +- eliminate some compiler warnings in public headers +- added some missing things for LFS64 APIs +- added fallback emulation of accept4 for older kernels + +bugs fixed: +- buffer overflow in printf when printing smallest denormal exactly +- rounding errors in printf in some just-over-halfway cases +- posix_spawn did not accept null pid pointer (crashed) +- ftello gave incorrect result for unflushed append-mode streams +- mishandling of n=0 case in wcsxfrm (wild buffer overrun) +- possible system breakage during libc upgrade due to install.sh bugs +- nftw FTW_MOUNT flag prevented walking any directories at all +- ptsname/ptsname_r returned negated error codes +- getprotoent function returned junk after listing valid protocols +- wrong error code from readdir when the directory has been deleted +- various prototype/argument-type fixes, mostly to legacy functions +- various header namespace violations + +arch-specific bugs fixed: +- fesetenv(FE_DFL_ENV) was broken on i386 and x86_64 +- strerror(EDQUOT) did not work on mips +- recvmsg/sendmsg were broken on powerpc +- sysv ipc was broken on powerpc and mips +- statfs/statvfs were broken on mips +- sigaltstack was broken on mips + + + +1.1.0 release notes + +new features: +- relro memory protection in dynamic linker +- malloc can now extend heap with mmap if brk fails +- vdso clock_gettime/gettimeofday/time acceleration on x86_64 +- thread/library-safe versions of search.h functions (nonstandard) +- getauxval function (nonstandard) +- sysconf extensions to query physical memory size + +bugs fixed: +- floating point printf output corruption from carry into uninitialized slot +- possible runaway carry overflow in printf floating point +- printf %g failure to strip trailing zeros in some cases +- search past end of haystack in memmem +- off-by-one error in confstr return value +- crashes in some near-empty static programs that use stack protector +- deadlock race in pthread_once +- non-working clock_gettime fallback for old kernels + +arch-specific bugs fixed: +- crash from missing syscall asm register clobbers on real microblaze kernel +- crash in all nontrivial dynamic linker use on microblaze +- incorrect rlimit constants on mips +- broken, possibly dangerous, use of getrlimit syscall on x32 in sysconf + + + +1.1.1 release notes + +new features: +- new options --preload and --library-path to dynamic linker +- public execvpe function (nonstandard extension) +- iconv support for cp437 and cp850 + +bugs fixed: +- false negatives with some periodic needles in strstr, wcsstr, and memmem +- crash on invalid zoneinfo files +- incorrect zero-padding of some outputs for strftime %s specifier +- misreporting of errors in configure script when $CC does not work at all +- treating not-yet-implemented strptime specifiers as errors + +compatibility: +- configure now detects serious constant-folding bug in gcc 4.9.0 +- removed __yield symbol (unused) that clashed with some compilers +- improvements to sysconf's handling of unsupported/invalid arguments + +arch-specific bugs fixed: +- misdetection of superh ABI variant by configure on gcc 3.x +- missing SO_RCVBUFFORCE and SO_SNDBUFFORCE in mips socket.h +- build regression on armv6 and later with -mthumb + + + +1.1.2 release notes + +new features: +- multi-protocol matches (tcp and udp) in getaddrinfo +- support for AI_V4MAPPED and AI_ALL flags to getaddrinfo +- reverse name lookups from /etc/hosts +- reverse service lookups from /etc/services +- support for service aliases in /etc/services +- ipsec and tunneling protocols to getprotoent-family functions +- res_send, res_mkquery, res_querydomain, and dn_comp functions +- ipv6 scope id handling for link-local scope addresses +- previously-unimplemented %C and %y in strptime now work +- vdso clock_gettime acceleration on i386 (new kernel feature) +- better O_CLOEXEC/SOCK_CLOEXEC fallbacks for old kernels + +bugs fixed: +- buffer overflow in dns response parsing (CVE-2014-3484) +- possible infinite loop in dns response parsing +- sendfile off_t 32/64-bit size mismatch +- incorrect end pointer in some cases when wcsrtombs stops early +- incorrect if_nametoindex return value when interface does not exist +- dummy "ent" function aliases that possibly shadowed real ones +- tmpfile fd leak on memory exhaustion +- getaddrinfo returning EAI_NONAME for some transient failures + +arch-specific bugs fixed: +- broken kernel side RLIM_INFINITY on mips +- incorrect syscall argument 6/7 types for pselect on x32 + + + +1.1.3 release notes + +new features: +- address sorting in getaddrinfo, etc. modeled on rfc 3484/6724 +- default timezone taken from /etc/localtime when $TZ is unset +- getopt double-colon extension for optional arguments +- support for TLSDESC-based (gnu2) TLS dialect on i386 and x86_64 +- sendmmsg/recvmmsg (linux-specific) +- fmtmsg (last mandatory XSI function that was missing) + +compatibility: +- treat dns rcode=2 as temporary failure, not negative result +- working thread-pointer for pre-2.6 kernels on i386 +- further ABI-compat symbols: __xmknod[at], __sysv_signal + +bugs fixed: +- memmem false positives/false negatives/crashes from invalid logic +- gethostby*_r not setting result pointer to null on failure +- aliasing violations in syscall.h SYSLOG_NAMES feature +- fanotify_mark syscall arguments wrong + +arch-specific bugs fixed: +- various subtle relocation bugs in powerpc and sh dynamic linker + + + +1.1.4 release notes + +new features: +- experimental locale support for LC_MESSAGES and LC_TIME +- non-stub gettext family functions for message translation +- or1k (OpenRISC 1000) port +- syslog options LOG_CONS and LOG_PERROR +- issetugid function (from OpenBSD) +- improved if_nameindex and getifaddrs functions + +compatibility: +- work around bug #61144 in gcc 4.9.0 and 4.9.1 +- support getauxval(AT_SECURE) even on kernels without AT_SECURE + +bugs fixed: +- empty dynamic linker error messages (regression in 1.1.3) +- if_nameindex omitted unconfigured and ipv6-only interfaces +- incorrect return value for fwide function +- failure of wide printf/scanf functions to set wide orientation +- multiple issues in legacy function getpass +- dynamic linker did not accept colon as a separator for LD_PRELOAD +- errno clobber in syslog caused wrong output for %m specifier +- crash in regexec for nonzero nmatch argument with REG_NOSUB +- minor bugs in rarely-used nl_langinfo item lookups + +arch-specific bugs fixed: +- broken relocations in mips dynamic linker (regression in 1.1.3) +- register state corruption in setjmp asm for microblaze +- broken struct stat st_ino field on microblaze +- broken struct stat st_dev field on big endian mips +- broken asm register constraints in atomics on powerpc +- missing barriers in atomics on mips, powerpc, microblaze, and sh + + + +1.1.5 release notes + +new features: +- full C11 coverage (threads, UTF-16/32 API, timespec_get, etc.) +- malloc_usable_size function (nonstandard) +- support for new F_OFD_* fcntl operations (linux 3.15, POSIX-future) +- new _DEFAULT_SOURCE feature test macro to request default profile + +performance: +- private-futex support +- redesigned cond var implementation with major performance improvement +- tweaked spinning in userspace before performing futex waits + +bugs fixed: +- failure of dn_expand to null-terminate name for crafted DNS packets +- corruption of cond var mutex state when switching mutexes +- use of uninitialized memory with application-provided thread stacks +- false ownership of orphaned mutexes due to tid reuse +- possible failure-to-wake for robust mutexes on owner death +- subtle errors in robust mutex unrecoverable status handling +- missing memory/compiler barrier spinning to obtain locks +- wrong behavior in various zero-length stdio operations +- buffer overflow in swab with odd argument +- incorrect sequence generation in the rand48 family of prng functions +- missing cancellation check in non-wait paths of sem_wait, pthread_join +- missing barrier in pthread_once fast path +- memory leak in regexec when input contains illegal sequence +- various parser bugs in regcomp +- wrong return value on overflow in some strtoul-family functions +- broken CPU_EQUAL macro in sched.h +- dlerror not working in static-linked programs +- mishandling of negative non-whole-hour TZ offsets +- incorrect case mappings for U+00DF +- namespace pollution via accidentally-non-static function named "dummy" +- missing __fpclassifyl and __signbitl definitions for ld64 archs + + + +1.1.6 release notes + +new features: +- getopt '-' flag for processing non-option arguments +- getopt_long argument permutation extension +- getopt_long abbreviated options +- ns_parserr and related DNS-packet-parsing functions +- fnmatch FNM_CASEFOLD extension +- support for translation of getopt error messages +- login_tty function (legacy) + +performance: +- efficient atomics on armv7+ targets +- pthread_once shrink-wrapping of fast path + +compatibility: +- baseline arm binaries now work on new cpus/kernels without kuser_helper +- dynamic linker now honors DT_RUNPATH without DT_RPATH (new binutils) +- arm asm is now compatible with clang's internal assembler +- suppress macro implementations of functions when headers are used in C++ +- increased message length limit for syslog + +bugs fixed: +- open ignored file creation mode argument for O_TMPFILE +- wrong printf formatting for %#.0o with value zero +- missing private state for uchar.h functions (null ps pointer) +- sched_getaffinity left uninitialized data in output bit array +- wrong return values for pthread_getaffinity_np and pthread_setaffinity_np +- buggy handling of multibyte option chars with arguments in getopt +- printf failed to report or stop on write errors +- printf failed to honor '+' modifier when printing NANs +- wcsnrtombs returned the wrong value in one code path +- syslog failed to check for connect error +- multi-threaded set*id() had spurious failures from ugly workaround code +- various minor header conformance bugs (signedness, constant expressions, ...) + +arch-specific bugs fixed: +- on or1k, some syscalls with 64-bit arguments were broken (misaligned) +- usage of sahf instruction on x86_64 crashed on some early cpu models + + + +1.1.7 release notes + +new features: +- alternate passwd/group backend support via nscd protocol +- masked cancellation mode extension (experimental) +- aio cancellation +- aarch64 port (experimental) + +performance: +- significant memset asm optimizations on i386 and x86_64 + +compatibility: +- suppress EINTR in semaphores for old kernels where futex restart is broken +- always set optarg in getopt_long +- support SOCK_RAW socket type in getaddrinfo +- report success instead of EINPROGRESS when close is interrupted + +bugs fixed: +- multithreaded set*id() was not async-signal safe, had various race bugs +- getspnam_r returned results for partial username matches +- wordexp bad character checker mis-counted parentheses +- close on fd with pending aio could lead to file corruption +- old aio implementation had numerous conformance bugs +- malloc init code could deadlock due to race condition +- pthread_exit did not disable cancellation +- pthread_cond_wait could wrongly consume signal on cancellation +- execvp wrongly stopped path search on EACCESS +- fsync, fdatasync, and msync were not honored as cancellation points +- fchmodat was subject to fd leak race (missing O_CLOEXEC) +- fchmodat failed to report EOPNOTSUPP in race path +- passwd/group lookup functions had various minor error-reporting bugs +- isatty had false-positives/device-state-corruption for OSS sound devices +- configure script failed to detect gcc with translated messages +- FLT_ROUNDS macro failed to reflect rounding mode changes in fenv + +arch-specific bugs fixed: +- mips fesetenv did not handle FE_DFL_ENV +- mips POLLWRNORM and POLLWRBAND macros had wrong values +- x32 pthread synchronization object type definitions were wrong +- powerpc minimum signal stack size was insufficient + + + +1.1.8 release notes + +bugs fixed: +- stack-based buffer overflow in inet_pton (CVE-2015-1817) +- regcomp crash/mem-corruption with illegal bytes after backslash +- regcomp wrongly allowed backrefs in ER +- regcomp miscompiled character class brace-repetitions +- regcomp wrongly processed \0 as an unmatchable backref +- new FLT_ROUNDS definition failed to work in C++ code + +arch-specific bugs fixed: +- aarch64 was missing max_align_t definition + + + +1.1.9 release notes + +new features: +- ability to protect libc code itself with stack protector +- sigsetjmp now restores signal mask after restoring context, not before +- thread-local dlerror status/messages +- dlerror messages are no longer truncated +- diagnostics for constraint violations with ctype.h macros + +optimizations: +- reduce cost of PIC on archs where PLT calls need a fixed GOT register +- spin locks no longer constantly invalidate cache lines while spinning +- code size reduction in static-linked TLS init + +bugs fixed: +- failure to process robust mutexes on detached-thread exit +- possible memory corruption due to robust mutex list on detached-thread exit +- crash on memory exhaustion in getgr* internals +- misaligned memory accesses in static binaries with low-alignment TLS blocks +- multiple cases of wrongful path search continuation after transient failure +- small memory leak on failure of dlopen with RPATH $ORIGIN +- several small math bugs related to exception flags with non-finite args +- mmap leak in sem_open failure path for link call +- duplocale clobbered new locale struct with memcpy of old +- futimes crashed with null timeval argument + +arch-specific bugs fixed: +- stack protector spuriously aborted after forking on x32 +- stack protector spuriously aborted with flockfile on powerpc +- theoretically-possible clobbering of syscall return value on mips +- random thread-pointer setup failure on sh (uninitialized return value) +- possible crash in dlsym on sh due to incorrectly-computed branch target +- broken fesetenv(FE_DFL_ENV) on mips +- dynamic linker name for sh ignored fpu/nofpu and endianness +- various minor aarch64 bugs +- dangling pointers in x32 syscall timespec fixup code + + + +1.1.10 release notes + +new features: +- fail-safe (allocation-free) C locale for newlocale to return +- all locale categories track requested locale name +- rcrt1.o start file for static PIE + +optimizations: +- inline atomics for sh4a +- removed heavy atomics from locale-related code paths +- removed global data accesses from CURRENT_LOCALE macro & callers +- dynamic linker stage 1 size reduction + +compatibility: +- better configure detection of unsupported compiler options +- support for more relocation types in libc.so, not currently used +- iconv_open accepts "" and "CHAR" as aliases for native (UTF-8) +- additional LFS64 macros in sys/resource.h + +regressions fixed: +- dynamic linker crash on NONE-type relocations (only mips affected) +- inability to build as thumb2 on arm +- failure to run under qemu-i386 user-level emulation +- inability to access globals from libc on powerpc +- PIE link errors in Scrt1.o under unusual usage on some archs + +other bugs fixed: +- failure of ungetc/ungetwc to work on FILE streams in EOF state +- possible null pointer dereference in gettext +- possible initial stack misalignment on mips with PIE + + + +1.1.11 release notes + +new features: +- byte-based C locale +- vdso clock_gettime on arm +- musl-clang wrapper +- sh2 nommu target support + +performance: +- major speed-up for dynamic linker symbol lookups with GNU hash + +compatibility: +- strverscmp now matches GNU behavior in corner cases +- empty TZ environment variable gives GMT rather than system default +- reconnection on syslog server socket loss (syslogd restart) +- mmap fallback in simple_malloc when brk fails +- support for %m and %s with null pointers in wide printf variants +- call frame information in i386 asm for improved debugger support + +bugs fixed: +- spurious errors from pwd/grp functions when nscd backend is absent +- possible invalid access on calloc with simple_malloc +- null pointer dereferences after calling uselocale((locale_t)0) +- erroneous support for cancellation in stdio caused data loss +- inconsistent handling of atexit called from atexit handler +- missing locking in error paths for ungetwc +- btowc mishandling of out-of-range non-EOF inputs +- negated return value of ns_skiprr, failure in related functions +- incorrect void return type for syncfs, missing error status +- possible failure of tempnam due to missing null termination +- negated tm_gmtoff field in struct tm +- off-by-one error in getsubopt leaving equals sign in value result + +arch-specific bugs fixed: +- soft deadlocks on i386/x86_64 due to missing barrier in internal locks +- regression in arm pre-v7 support for kernels with kuser helper removed +- runaway PC on mips detached thread exit (due to kernel regression) +- mismatched ABI for local-dynamic model TLS on mips and powerpc +- incorrect value of some SO_* constants on mips +- broken 64-bit syscall argument passing on aarch64 + + + +1.1.12 release notes + +new features: +- fdpic abi on sh2 for shareable text segment without mmu +- general fdpic elf support in dynamic linker +- CFI generation for x86_64 asm source files +- protection against silently building a libc.so with missing symbols + +compatibility: +- nl_langinfo(CODESET) now returns "ASCII" in byte-based C locale +- fixed build regression due to buggy .SECONDARY in some GNU make versions +- additional arm eabi functions needed by llvm arm backend +- added format argument attributes to gettext function prototypes +- static PIE no longer requires linking with -E/-rdynamic +- eliminated spurious protected-data warnings linking against libc.so +- avoided spurious fpu asm errors with some armhf toolchains + +bugs fixed: +- fclose of stdin/stdout caused deadlock at exit +- missing memory barrier in pthread_join +- open_[w]memstream produced no buffer when no writes took place +- uninitialized scopeid in address lookups from hosts file and ip literals +- ip literals for mismatching family (v4 vs v6) were queried as hostnames +- possible crash on OOM in regcomp +- incorrect contents in localeconv structure (-1 instead of CHAR_MAX) +- strftime mishandling of out-of-range struct tm members +- wrongful attribute((const)) on pthread_self and errno location function + +arch-specific bugs fixed: +- arm crt1 entry point failed to align stack pointer in some cases +- mips fesetround failed to actually set rounding mode +- i386 asm source CFI generation had multiple bugs + + + +1.1.13 release notes + +new features: +- out-of-tree builds +- search domains in resolv.conf +- sh arch supports j-core (j2) cas.l atomics +- dynamic linker includes arch/abi in output when run as a command +- header support for new kernel features through linux 4.4 +- mips vdso clock_gettime support +- regex BRE extensions: \|, \+, \? + +performance: +- improved atomics performance on all archs with ll/sc model +- atomic instructions are now inlined on armv6 +- use fpu sqrt for arm softfp abi on targets with vfp + +compatibility: +- getnameinfo now accepts sockaddr sizes larger than needed +- new default CFLAGS/LDFLAGS avoid entire classes of toolchain bugs +- explicit use of float_t/double_t avoids compiler float spill bugs +- i386 max_align_t definition now works with g++ 4.7's pseudo-c++11 +- all known protocols are added to protoent functions +- stub utmpname, utmpxname functions +- linker support for -Bsymbolic-functions is no longer mandatory +- regex parsing size limits increased +- malloc_usable_size now accepts null pointer input + +bugs fixed: +- potential single-byte heap overflow in getdelim +- mishandling of transient failure opening hosts, services, resolv.conf +- mremap was sometimes able to allocate objects larger than PTRDIFF_MAX +- nl_langinfo wrongly returned NULL instead of "" for invalid items +- out-of-bounds dynamic tls allocation due to pointer/index scaling error +- getifaddrs misreported point-to-point interface addresses +- tdelete left tsearch trees misbalanced +- tsearch crashed on allocation failure +- tsearch, tfind, and tdelete failed to handle null pointer input +- passing signal number 0 to sigaction resulted in a crash +- getdelim updated caller's size wrongly when realloc failed +- getdelim realloc strategy was wasteful +- if_nametoindex returned wrong value on failure +- missing ssp-suppression for some source files called from early-init +- various minor resolv.conf parsing bugs +- fwrite wrongly reported success on write errors in line-buffered flush +- fwrite and fread wrongly returned nmemb (not 0) when size was 0 + +nommu-specific bugs fix: +- failure to zero bss in FDPIC shared library loader +- unsafe writes to read-only file mapping in non-FDPIC library loader + +arch-specific bugs fixed: +- sh[eb]-nofpu-fdpic was using fpu-dependent setjmp/longjmp variants +- dynamic linker path file name was wrong for arm "softfp" targets +- mips siginfo_t and related macros were defined incorrectly +- possibly misaligned pointer globals on arm (from an asm source file) +- mips dynamic linker failed to provide info needed by debugger +- mips cancellation asm wrongly assumed validity of $gp register value + + + +1.1.14 release notes + +regressions fixed: +- treatment of empty string argument as error by puts and fputs +- make clean and distclean failure in unconfigured trees +- sh/fdpic dynamic linker entry point hang due to wrong code +- armhf (and arm softfp model) build failure with clang + +other bugs fixed: +- wrongly clamping (rather than failing) excessive rounds in crypt-sha* diff --git a/third_party/ulib/musl/arch/aarch64/atomic_arch.h b/third_party/ulib/musl/arch/aarch64/atomic_arch.h new file mode 100644 index 000000000..cfa5257a6 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/atomic_arch.h @@ -0,0 +1,70 @@ +#define a_ll a_ll +static inline int a_ll(volatile int* p) { + int v; + __asm__ __volatile__("ldaxr %w0,%1" : "=r"(v) : "Q"(*p)); + return v; +} + +#define a_sc a_sc +static inline int a_sc(volatile int* p, int v) { + int r; + __asm__ __volatile__("stlxr %w0,%w2,%1" : "=&r"(r), "=Q"(*p) : "r"(v) : "memory"); + return !r; +} + +#define a_barrier a_barrier +static inline void a_barrier(void) { + __asm__ __volatile__("dmb ish" : : : "memory"); +} + +#define a_cas a_cas +static inline int a_cas(volatile int* p, int t, int s) { + int old; + do { + old = a_ll(p); + if (old != t) { + a_barrier(); + break; + } + } while (!a_sc(p, s)); + return old; +} + +#define a_ll_p a_ll_p +static inline void* a_ll_p(volatile void* p) { + void* v; + __asm__ __volatile__("ldaxr %0, %1" : "=r"(v) : "Q"(*(void* volatile*)p)); + return v; +} + +#define a_sc_p a_sc_p +static inline int a_sc_p(volatile int* p, void* v) { + int r; + __asm__ __volatile__("stlxr %w0,%2,%1" + : "=&r"(r), "=Q"(*(void* volatile*)p) + : "r"(v) + : "memory"); + return !r; +} + +#define a_cas_p a_cas_p +static inline void* a_cas_p(volatile void* p, void* t, void* s) { + void* old; + do { + old = a_ll_p(p); + if (old != t) { + a_barrier(); + break; + } + } while (!a_sc_p(p, s)); + return old; +} + +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) { + __asm__(" rbit %0, %1\n" + " clz %0, %0\n" + : "=r"(x) + : "r"(x)); + return x; +} diff --git a/third_party/ulib/musl/arch/aarch64/bits/alltypes.h.in b/third_party/ulib/musl/arch/aarch64/bits/alltypes.h.in new file mode 100644 index 000000000..d56abdac9 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/alltypes.h.in @@ -0,0 +1,30 @@ +#define _Addr long +#define _Int64 long +#define _Reg long + +TYPEDEF __builtin_va_list va_list; +TYPEDEF __builtin_va_list __isoc_va_list; + +#ifndef __cplusplus +TYPEDEF unsigned wchar_t; +#endif +TYPEDEF unsigned wint_t; + +TYPEDEF int blksize_t; +TYPEDEF unsigned int nlink_t; + +TYPEDEF float float_t; +TYPEDEF double double_t; + +TYPEDEF struct { long long __ll; long double __ld; } max_align_t; + +TYPEDEF long time_t; +TYPEDEF long suseconds_t; + +TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t; +TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t; +TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t; +TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t; +TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t; diff --git a/third_party/ulib/musl/arch/aarch64/bits/endian.h b/third_party/ulib/musl/arch/aarch64/bits/endian.h new file mode 100644 index 000000000..7a74d2feb --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/endian.h @@ -0,0 +1,5 @@ +#if __AARCH64EB__ +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif diff --git a/third_party/ulib/musl/arch/aarch64/bits/fcntl.h b/third_party/ulib/musl/arch/aarch64/bits/fcntl.h new file mode 100644 index 000000000..b9420d080 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/fcntl.h @@ -0,0 +1,38 @@ +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 040000 +#define O_NOFOLLOW 0100000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 0200000 +#define O_LARGEFILE 0400000 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020040000 +#define O_NDELAY O_NONBLOCK + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 diff --git a/third_party/ulib/musl/arch/aarch64/bits/fenv.h b/third_party/ulib/musl/arch/aarch64/bits/fenv.h new file mode 100644 index 000000000..6bb1f56fe --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/fenv.h @@ -0,0 +1,19 @@ +#define FE_INVALID 1 +#define FE_DIVBYZERO 2 +#define FE_OVERFLOW 4 +#define FE_UNDERFLOW 8 +#define FE_INEXACT 16 +#define FE_ALL_EXCEPT 31 +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x800000 +#define FE_UPWARD 0x400000 +#define FE_TOWARDZERO 0xc00000 + +typedef unsigned int fexcept_t; + +typedef struct { + unsigned int __fpcr; + unsigned int __fpsr; +} fenv_t; + +#define FE_DFL_ENV ((const fenv_t*)-1) diff --git a/third_party/ulib/musl/arch/aarch64/bits/float.h b/third_party/ulib/musl/arch/aarch64/bits/float.h new file mode 100644 index 000000000..719c79085 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/float.h @@ -0,0 +1,16 @@ +#define FLT_EVAL_METHOD 0 + +#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L + +#define LDBL_MANT_DIG 113 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 33 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 36 diff --git a/third_party/ulib/musl/arch/aarch64/bits/ioctl.h b/third_party/ulib/musl/arch/aarch64/bits/ioctl.h new file mode 100644 index 000000000..f96302475 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/ioctl.h @@ -0,0 +1,213 @@ +#define _IOC(a, b, c, d) (((a) << 30) | ((b) << 8) | (c) | ((d) << 16)) +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IO(a, b) _IOC(_IOC_NONE, (a), (b), 0) +#define _IOW(a, b, c) _IOC(_IOC_WRITE, (a), (b), sizeof(c)) +#define _IOR(a, b, c) _IOC(_IOC_READ, (a), (b), sizeof(c)) +#define _IOWR(a, b, c) _IOC(_IOC_READ | _IOC_WRITE, (a), (b), sizeof(c)) + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCTTYGSTRUCT 0x5426 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN _IOR('T', 0x30, unsigned int) +#define TIOCSPTLCK _IOW('T', 0x31, int) +#define TIOCGDEV _IOR('T', 0x32, unsigned int) +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x40045436 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 0x80045438 +#define TIOCGPTLCK 0x80045439 +#define TIOCGEXCL 0x80045440 + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B + +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define FIOQSIZE 0x5460 + +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 +#define TIOCM_MODEM_BITS TIOCM_OUT2 + +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 +#define N_MASC 8 +#define N_R3964 9 +#define N_PROFIBUS_FDL 10 +#define N_IRDA 11 +#define N_SMSBLOCK 12 +#define N_HDLC 13 +#define N_SYNC_PPP 14 +#define N_HCI 15 +#define N_GIGASET_M101 16 +#define N_SLCAN 17 +#define N_PPS 18 +#define N_V253 19 +#define N_CAIF 20 +#define N_GSM0710 21 +#define N_TI_WL 22 +#define N_TRACESINK 23 +#define N_TRACEROUTER 24 + +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 +#define SIOCGSTAMPNS 0x8907 + +#define SIOCADDRT 0x890B +#define SIOCDELRT 0x890C +#define SIOCRTMSG 0x890D + +#define SIOCGIFNAME 0x8910 +#define SIOCSIFLINK 0x8911 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCSIFADDR 0x8916 +#define SIOCGIFDSTADDR 0x8917 +#define SIOCSIFDSTADDR 0x8918 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCSIFBRDADDR 0x891a +#define SIOCGIFNETMASK 0x891b +#define SIOCSIFNETMASK 0x891c +#define SIOCGIFMETRIC 0x891d +#define SIOCSIFMETRIC 0x891e +#define SIOCGIFMEM 0x891f +#define SIOCSIFMEM 0x8920 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCSIFHWADDR 0x8924 +#define SIOCGIFENCAP 0x8925 +#define SIOCSIFENCAP 0x8926 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFSLAVE 0x8929 +#define SIOCSIFSLAVE 0x8930 +#define SIOCADDMULTI 0x8931 +#define SIOCDELMULTI 0x8932 +#define SIOCGIFINDEX 0x8933 +#define SIOGIFINDEX SIOCGIFINDEX +#define SIOCSIFPFLAGS 0x8934 +#define SIOCGIFPFLAGS 0x8935 +#define SIOCDIFADDR 0x8936 +#define SIOCSIFHWBROADCAST 0x8937 +#define SIOCGIFCOUNT 0x8938 + +#define SIOCGIFBR 0x8940 +#define SIOCSIFBR 0x8941 + +#define SIOCGIFTXQLEN 0x8942 +#define SIOCSIFTXQLEN 0x8943 + +#define SIOCDARP 0x8953 +#define SIOCGARP 0x8954 +#define SIOCSARP 0x8955 + +#define SIOCDRARP 0x8960 +#define SIOCGRARP 0x8961 +#define SIOCSRARP 0x8962 + +#define SIOCGIFMAP 0x8970 +#define SIOCSIFMAP 0x8971 + +#define SIOCADDDLCI 0x8980 +#define SIOCDELDLCI 0x8981 + +#define SIOCDEVPRIVATE 0x89F0 +#define SIOCPROTOPRIVATE 0x89E0 diff --git a/third_party/ulib/musl/arch/aarch64/bits/ipc.h b/third_party/ulib/musl/arch/aarch64/bits/ipc.h new file mode 100644 index 000000000..df2ed2bf4 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/ipc.h @@ -0,0 +1,14 @@ +struct ipc_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + unsigned short __ipc_perm_seq; + + unsigned long __pad1; + unsigned long __pad2; +}; + +#define IPC_64 0 diff --git a/third_party/ulib/musl/arch/aarch64/bits/limits.h b/third_party/ulib/musl/arch/aarch64/bits/limits.h new file mode 100644 index 000000000..e365d62d1 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/limits.h @@ -0,0 +1,8 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define LONG_BIT 64 +#define PAGE_SIZE 4096 +#endif + +#define LONG_MAX 0x7fffffffffffffffL +#define LLONG_MAX 0x7fffffffffffffffLL diff --git a/third_party/ulib/musl/arch/aarch64/bits/msg.h b/third_party/ulib/musl/arch/aarch64/bits/msg.h new file mode 100644 index 000000000..bd84bd2f3 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/msg.h @@ -0,0 +1,13 @@ +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __pad1; + unsigned long __pad2; +}; diff --git a/third_party/ulib/musl/arch/aarch64/bits/posix.h b/third_party/ulib/musl/arch/aarch64/bits/posix.h new file mode 100644 index 000000000..8068ce98d --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/posix.h @@ -0,0 +1,2 @@ +#define _POSIX_V6_LP64_OFF64 1 +#define _POSIX_V7_LP64_OFF64 1 diff --git a/third_party/ulib/musl/arch/aarch64/bits/reg.h b/third_party/ulib/musl/arch/aarch64/bits/reg.h new file mode 100644 index 000000000..2633f39d7 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/reg.h @@ -0,0 +1,2 @@ +#undef __WORDSIZE +#define __WORDSIZE 64 diff --git a/third_party/ulib/musl/arch/aarch64/bits/sem.h b/third_party/ulib/musl/arch/aarch64/bits/sem.h new file mode 100644 index 000000000..d7aa74b75 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/sem.h @@ -0,0 +1,14 @@ +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t sem_ctime; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned short sem_nsems; + char __sem_nsems_pad[sizeof(time_t) - sizeof(short)]; +#else + char __sem_nsems_pad[sizeof(time_t) - sizeof(short)]; + unsigned short sem_nsems; +#endif + time_t __unused3; + time_t __unused4; +}; diff --git a/third_party/ulib/musl/arch/aarch64/bits/setjmp.h b/third_party/ulib/musl/arch/aarch64/bits/setjmp.h new file mode 100644 index 000000000..54bc2610c --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/setjmp.h @@ -0,0 +1 @@ +typedef unsigned long __jmp_buf[22]; diff --git a/third_party/ulib/musl/arch/aarch64/bits/shm.h b/third_party/ulib/musl/arch/aarch64/bits/shm.h new file mode 100644 index 000000000..8bb1c74cf --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/shm.h @@ -0,0 +1,24 @@ +#define SHMLBA 4096 + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __pad1; + unsigned long __pad2; +}; + +struct shminfo { + unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4]; +}; + +struct shm_info { + int __used_ids; + unsigned long shm_tot, shm_rss, shm_swp; + unsigned long __swap_attempts, __swap_successes; +}; diff --git a/third_party/ulib/musl/arch/aarch64/bits/signal.h b/third_party/ulib/musl/arch/aarch64/bits/signal.h new file mode 100644 index 000000000..5a5439a29 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/signal.h @@ -0,0 +1,105 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 6144 +#define SIGSTKSZ 12288 +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef unsigned long greg_t; +typedef unsigned long gregset_t[34]; + +typedef struct { + long double vregs[32]; + unsigned int fpsr; + unsigned int fpcr; +} fpregset_t; +typedef struct sigcontext { + unsigned long fault_address; + unsigned long regs[31]; + unsigned long sp, pc, pstate; + long double __reserved[256]; +} mcontext_t; + +#define FPSIMD_MAGIC 0x46508001 +#define ESR_MAGIC 0x45535201 +struct _aarch64_ctx { + unsigned int magic; + unsigned int size; +}; +struct fpsimd_context { + struct _aarch64_ctx head; + unsigned int fpsr; + unsigned int fpcr; + long double vregs[32]; +}; +struct esr_context { + struct _aarch64_ctx head; + unsigned long esr; +}; +#else +typedef struct { long double __regs[18 + 256]; } mcontext_t; +#endif + +struct sigaltstack { + void* ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct ucontext* uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +} ucontext_t; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#endif + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS + +#define _NSIG 65 diff --git a/third_party/ulib/musl/arch/aarch64/bits/socket.h b/third_party/ulib/musl/arch/aarch64/bits/socket.h new file mode 100644 index 000000000..aad18bf31 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/socket.h @@ -0,0 +1,33 @@ +#include + +struct msghdr { + void* msg_name; + socklen_t msg_namelen; + struct iovec* msg_iov; +#if __BYTE_ORDER == __BIG_ENDIAN + int __pad1, msg_iovlen; +#else + int msg_iovlen, __pad1; +#endif + void* msg_control; +#if __BYTE_ORDER == __BIG_ENDIAN + int __pad2; + socklen_t msg_controllen; +#else + socklen_t msg_controllen; + int __pad2; +#endif + int msg_flags; +}; + +struct cmsghdr { +#if __BYTE_ORDER == __BIG_ENDIAN + int __pad1; + socklen_t cmsg_len; +#else + socklen_t cmsg_len; + int __pad1; +#endif + int cmsg_level; + int cmsg_type; +}; diff --git a/third_party/ulib/musl/arch/aarch64/bits/stat.h b/third_party/ulib/musl/arch/aarch64/bits/stat.h new file mode 100644 index 000000000..0fe7e69ea --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/stat.h @@ -0,0 +1,18 @@ +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned long __pad; + off_t st_size; + blksize_t st_blksize; + int __pad2; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + unsigned __unused[2]; +}; diff --git a/third_party/ulib/musl/arch/aarch64/bits/stdint.h b/third_party/ulib/musl/arch/aarch64/bits/stdint.h new file mode 100644 index 000000000..7cac02579 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/stdint.h @@ -0,0 +1,20 @@ +typedef int32_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast16_t; +typedef uint32_t uint_fast32_t; + +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN + +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX + +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#define PTRDIFF_MIN INT64_MIN +#define PTRDIFF_MAX INT64_MAX +#define SIZE_MAX UINT64_MAX diff --git a/third_party/ulib/musl/arch/aarch64/bits/syscall.h b/third_party/ulib/musl/arch/aarch64/bits/syscall.h new file mode 100644 index 000000000..09855960c --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/syscall.h @@ -0,0 +1,166 @@ +#define SYS_getcwd 17 +#define SYS_dup 23 +#define SYS_dup3 24 +#define SYS_fcntl 25 +#define SYS_ioctl 29 +#define SYS_flock 32 +#define SYS_mknodat 33 +#define SYS_mkdirat 34 +#define SYS_unlinkat 35 +#define SYS_symlinkat 36 +#define SYS_linkat 37 +#define SYS_renameat 38 +#define SYS_statfs 43 +#define SYS_fstatfs 44 +#define SYS_truncate 45 +#define SYS_ftruncate 46 +#define SYS_fallocate 47 +#define SYS_faccessat 48 +#define SYS_chdir 49 +#define SYS_fchdir 50 +#define SYS_chroot 51 +#define SYS_fchmod 52 +#define SYS_fchmodat 53 +#define SYS_fchownat 54 +#define SYS_fchown 55 +#define SYS_openat 56 +#define SYS_close 57 +#define SYS_pipe2 59 +#define SYS_quotactl 60 +#define SYS_getdents64 61 +#define SYS_write 64 +#define SYS_readv 65 +#define SYS_writev 66 +#define SYS_pread64 67 +#define SYS_pwrite64 68 +#define SYS_preadv 69 +#define SYS_pwritev 70 +#define SYS_pselect6 72 +#define SYS_ppoll 73 +#define SYS_readlinkat 78 +#define SYS_fstatat 79 +#define SYS_fstat 80 +#define SYS_sync 81 +#define SYS_fsync 82 +#define SYS_fdatasync 83 +#define SYS_utimensat 88 +#define SYS_acct 89 +#define SYS_exit 93 +#define SYS_waitid 95 +#define SYS_set_tid_address 96 +#define SYS_set_robust_list 99 +#define SYS_nanosleep 101 +#define SYS_getitimer 102 +#define SYS_setitimer 103 +#define SYS_timer_create 107 +#define SYS_timer_gettime 108 +#define SYS_timer_getoverrun 109 +#define SYS_timer_settime 110 +#define SYS_timer_delete 111 +#define SYS_clock_settime 112 +#define SYS_clock_getres 114 +#define SYS_clock_nanosleep 115 +#define SYS_ptrace 117 +#define SYS_sched_setparam 118 +#define SYS_sched_setscheduler 119 +#define SYS_sched_getscheduler 120 +#define SYS_sched_getparam 121 +#define SYS_sched_setaffinity 122 +#define SYS_sched_getaffinity 123 +#define SYS_sched_yield 124 +#define SYS_sched_get_priority_max 125 +#define SYS_sched_get_priority_min 126 +#define SYS_sched_rr_get_interval 127 +#define SYS_kill 129 +#define SYS_tkill 130 +#define SYS_sigaltstack 132 +#define SYS_rt_sigsuspend 133 +#define SYS_rt_sigaction 134 +#define SYS_rt_sigprocmask 135 +#define SYS_rt_sigpending 136 +#define SYS_rt_sigtimedwait 137 +#define SYS_rt_sigqueueinfo 138 +#define SYS_setpriority 140 +#define SYS_getpriority 141 +#define SYS_setregid 143 +#define SYS_setgid 144 +#define SYS_setreuid 145 +#define SYS_setuid 146 +#define SYS_setresuid 147 +#define SYS_getresuid 148 +#define SYS_setresgid 149 +#define SYS_getresgid 150 +#define SYS_times 153 +#define SYS_setpgid 154 +#define SYS_getpgid 155 +#define SYS_getsid 156 +#define SYS_setsid 157 +#define SYS_getgroups 158 +#define SYS_setgroups 159 +#define SYS_uname 160 +#define SYS_sethostname 161 +#define SYS_setdomainname 162 +#define SYS_getrlimit 163 +#define SYS_getrusage 165 +#define SYS_umask 166 +#define SYS_prctl 167 +#define SYS_getcpu 168 +#define SYS_settimeofday 170 +#define SYS_adjtimex 171 +#define SYS_getpid 172 +#define SYS_getppid 173 +#define SYS_getuid 174 +#define SYS_geteuid 175 +#define SYS_getgid 176 +#define SYS_getegid 177 +#define SYS_gettid 178 +#define SYS_mq_open 180 +#define SYS_mq_unlink 181 +#define SYS_mq_timedsend 182 +#define SYS_mq_timedreceive 183 +#define SYS_mq_notify 184 +#define SYS_mq_getsetattr 185 +#define SYS_msgget 186 +#define SYS_msgctl 187 +#define SYS_msgrcv 188 +#define SYS_msgsnd 189 +#define SYS_semget 190 +#define SYS_semctl 191 +#define SYS_semtimedop 192 +#define SYS_semop 193 +#define SYS_shmget 194 +#define SYS_shmctl 195 +#define SYS_shmat 196 +#define SYS_shmdt 197 +#define SYS_socket 198 +#define SYS_socketpair 199 +#define SYS_bind 200 +#define SYS_listen 201 +#define SYS_accept 202 +#define SYS_connect 203 +#define SYS_getsockname 204 +#define SYS_getpeername 205 +#define SYS_sendto 206 +#define SYS_recvfrom 207 +#define SYS_setsockopt 208 +#define SYS_getsockopt 209 +#define SYS_shutdown 210 +#define SYS_sendmsg 211 +#define SYS_recvmsg 212 +#define SYS_brk 214 +#define SYS_clone 220 +#define SYS_execve 221 +#define SYS_mmap 222 +#define SYS_fadvise64 223 +#define SYS_mprotect 226 +#define SYS_msync 227 +#define SYS_mlock 228 +#define SYS_munlock 229 +#define SYS_mlockall 230 +#define SYS_munlockall 231 +#define SYS_mincore 232 +#define SYS_madvise 233 +#define SYS_accept4 242 +#define SYS_recvmmsg 243 +#define SYS_wait4 260 +#define SYS_prlimit64 261 diff --git a/third_party/ulib/musl/arch/aarch64/bits/user.h b/third_party/ulib/musl/arch/aarch64/bits/user.h new file mode 100644 index 000000000..70972e58f --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/bits/user.h @@ -0,0 +1,16 @@ +struct user_regs_struct { + unsigned long long regs[31]; + unsigned long long sp; + unsigned long long pc; + unsigned long long pstate; +}; + +struct user_fpsimd_struct { + long double vregs[32]; + unsigned int fpsr; + unsigned int fpcr; +}; + +#define ELF_NREG 34 +typedef unsigned long elf_greg_t, elf_gregset_t[ELF_NREG]; +typedef struct user_fpsimd_struct elf_fpregset_t; diff --git a/third_party/ulib/musl/arch/aarch64/crt_arch.h b/third_party/ulib/musl/arch/aarch64/crt_arch.h new file mode 100644 index 000000000..0ef01e16e --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/crt_arch.h @@ -0,0 +1,12 @@ +__asm__(".text \n" + ".global " START "\n" + ".type " START ",%function\n" START ":\n" + " mov x29, #0\n" + " mov x30, #0\n" + " mov x0, sp\n" + ".weak _DYNAMIC\n" + ".hidden _DYNAMIC\n" + " adrp x1, _DYNAMIC\n" + " add x1, x1, #:lo12:_DYNAMIC\n" + " and sp, x0, #-16\n" + " b " START "_c\n"); diff --git a/third_party/ulib/musl/arch/aarch64/pthread_arch.h b/third_party/ulib/musl/arch/aarch64/pthread_arch.h new file mode 100644 index 000000000..d4b3e7277 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/pthread_arch.h @@ -0,0 +1,7 @@ +#include +#include + +#define TLS_ABOVE_TP +#define TP_ADJ(p) ((char*)(p) + sizeof(struct pthread) - 16) + +#define MC_PC pc diff --git a/third_party/ulib/musl/arch/aarch64/reloc.h b/third_party/ulib/musl/arch/aarch64/reloc.h new file mode 100644 index 000000000..073d15f95 --- /dev/null +++ b/third_party/ulib/musl/arch/aarch64/reloc.h @@ -0,0 +1,25 @@ +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ENDIAN_SUFFIX "_be" +#else +#define ENDIAN_SUFFIX "" +#endif + +#define LDSO_ARCH "aarch64" ENDIAN_SUFFIX + +#define NO_LEGACY_INITFINI + +#define TPOFF_K 16 + +#define REL_SYMBOLIC R_AARCH64_ABS64 +#define REL_GOT R_AARCH64_GLOB_DAT +#define REL_PLT R_AARCH64_JUMP_SLOT +#define REL_RELATIVE R_AARCH64_RELATIVE +#define REL_COPY R_AARCH64_COPY +#define REL_DTPMOD R_AARCH64_TLS_DTPMOD64 +#define REL_DTPOFF R_AARCH64_TLS_DTPREL64 +#define REL_TPOFF R_AARCH64_TLS_TPREL64 +#define REL_TLSDESC R_AARCH64_TLSDESC + +#define CRTJMP(pc, sp) __asm__ __volatile__("mov sp,%1 ; br %0" : : "r"(pc), "r"(sp) : "memory") diff --git a/third_party/ulib/musl/arch/arm/atomic_arch.h b/third_party/ulib/musl/arch/arm/atomic_arch.h new file mode 100644 index 000000000..5b2b8f1ef --- /dev/null +++ b/third_party/ulib/musl/arch/arm/atomic_arch.h @@ -0,0 +1,71 @@ +__attribute__(( + __visibility__("hidden"))) extern const void* __arm_atomics[3]; /* gettp, cas, barrier */ + +#if ((__ARM_ARCH_6__ || __ARM_ARCH_6K__ || __ARM_ARCH_6ZK__) && !__thumb__) || __ARM_ARCH_7A__ || \ + __ARM_ARCH_7R__ || __ARM_ARCH >= 7 + +#define a_ll a_ll +static inline int a_ll(volatile int* p) { + int v; + __asm__ __volatile__("ldrex %0, %1" : "=r"(v) : "Q"(*p)); + return v; +} + +#define a_sc a_sc +static inline int a_sc(volatile int* p, int v) { + int r; + __asm__ __volatile__("strex %0,%2,%1" : "=&r"(r), "=Q"(*p) : "r"(v) : "memory"); + return !r; +} + +#if __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7 + +#define a_barrier a_barrier +static inline void a_barrier(void) { + __asm__ __volatile__("dmb ish" : : : "memory"); +} + +#endif + +#define a_pre_llsc a_barrier +#define a_post_llsc a_barrier + +#else + +#define a_cas a_cas +static inline int a_cas(volatile int* p, int t, int s) { + for (;;) { + register int r0 __asm__("r0") = t; + register int r1 __asm__("r1") = s; + register volatile int* r2 __asm__("r2") = p; + int old; + __asm__ __volatile__("bl __a_cas" + : "+r"(r0) + : "r"(r1), "r"(r2) + : "memory", "r3", "lr", "ip", "cc"); + if (!r0) return t; + if ((old = *p) != t) return old; + } +} + +#endif + +#ifndef a_barrier +#define a_barrier a_barrier +static inline void a_barrier(void) { + __asm__ __volatile__("bl __a_barrier" : : : "memory", "cc", "ip", "lr"); +} +#endif + +#define a_crash a_crash +static inline void a_crash(void) { + __asm__ __volatile__( +#ifndef __thumb__ + ".word 0xe7f000f0" +#else + ".short 0xdeff" +#endif + : + : + : "memory"); +} diff --git a/third_party/ulib/musl/arch/arm/bits/alltypes.h.in b/third_party/ulib/musl/arch/arm/bits/alltypes.h.in new file mode 100644 index 000000000..667963c7e --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/alltypes.h.in @@ -0,0 +1,26 @@ +#define _Addr int +#define _Int64 long long +#define _Reg int + +TYPEDEF __builtin_va_list va_list; +TYPEDEF __builtin_va_list __isoc_va_list; + +#ifndef __cplusplus +TYPEDEF unsigned wchar_t; +#endif + +TYPEDEF float float_t; +TYPEDEF double double_t; + +TYPEDEF struct { long long __ll; long double __ld; } max_align_t; + +TYPEDEF long time_t; +TYPEDEF long suseconds_t; + +TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t; +TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; +TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t; +TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t; +TYPEDEF struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t; diff --git a/third_party/ulib/musl/arch/arm/bits/endian.h b/third_party/ulib/musl/arch/arm/bits/endian.h new file mode 100644 index 000000000..5953724a0 --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/endian.h @@ -0,0 +1,5 @@ +#if __ARMEB__ +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif diff --git a/third_party/ulib/musl/arch/arm/bits/fcntl.h b/third_party/ulib/musl/arch/arm/bits/fcntl.h new file mode 100644 index 000000000..6796d1d6b --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/fcntl.h @@ -0,0 +1,40 @@ +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 040000 +#define O_NOFOLLOW 0100000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 0200000 +#define O_LARGEFILE 0400000 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020040000 +#define O_NDELAY O_NONBLOCK + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 12 +#define F_SETLK 13 +#define F_SETLKW 14 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 diff --git a/third_party/ulib/musl/arch/arm/bits/fenv.h b/third_party/ulib/musl/arch/arm/bits/fenv.h new file mode 100644 index 000000000..2bf18354e --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/fenv.h @@ -0,0 +1,21 @@ +#ifndef __ARM_PCS_VFP +#define FE_ALL_EXCEPT 0 +#define FE_TONEAREST 0 +#else +#define FE_INVALID 1 +#define FE_DIVBYZERO 2 +#define FE_OVERFLOW 4 +#define FE_UNDERFLOW 8 +#define FE_INEXACT 16 +#define FE_ALL_EXCEPT 31 +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x800000 +#define FE_UPWARD 0x400000 +#define FE_TOWARDZERO 0xc00000 +#endif + +typedef unsigned long fexcept_t; + +typedef struct { unsigned long __cw; } fenv_t; + +#define FE_DFL_ENV ((const fenv_t*)-1) diff --git a/third_party/ulib/musl/arch/arm/bits/float.h b/third_party/ulib/musl/arch/arm/bits/float.h new file mode 100644 index 000000000..c4a655e7b --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/float.h @@ -0,0 +1,16 @@ +#define FLT_EVAL_METHOD 0 + +#define LDBL_TRUE_MIN 4.94065645841246544177e-324L +#define LDBL_MIN 2.22507385850720138309e-308L +#define LDBL_MAX 1.79769313486231570815e+308L +#define LDBL_EPSILON 2.22044604925031308085e-16L + +#define LDBL_MANT_DIG 53 +#define LDBL_MIN_EXP (-1021) +#define LDBL_MAX_EXP 1024 + +#define LDBL_DIG 15 +#define LDBL_MIN_10_EXP (-307) +#define LDBL_MAX_10_EXP 308 + +#define DECIMAL_DIG 17 diff --git a/third_party/ulib/musl/arch/arm/bits/limits.h b/third_party/ulib/musl/arch/arm/bits/limits.h new file mode 100644 index 000000000..17ee07a39 --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/limits.h @@ -0,0 +1,8 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define PAGE_SIZE 4096 +#define LONG_BIT 32 +#endif + +#define LONG_MAX 0x7fffffffL +#define LLONG_MAX 0x7fffffffffffffffLL diff --git a/third_party/ulib/musl/arch/arm/bits/posix.h b/third_party/ulib/musl/arch/arm/bits/posix.h new file mode 100644 index 000000000..8897d37d7 --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/posix.h @@ -0,0 +1,2 @@ +#define _POSIX_V6_ILP32_OFFBIG 1 +#define _POSIX_V7_ILP32_OFFBIG 1 diff --git a/third_party/ulib/musl/arch/arm/bits/reg.h b/third_party/ulib/musl/arch/arm/bits/reg.h new file mode 100644 index 000000000..0c7bffca0 --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/reg.h @@ -0,0 +1,3 @@ +#undef __WORDSIZE +#define __WORDSIZE 32 +/* FIXME */ diff --git a/third_party/ulib/musl/arch/arm/bits/setjmp.h b/third_party/ulib/musl/arch/arm/bits/setjmp.h new file mode 100644 index 000000000..55e3a95bb --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/setjmp.h @@ -0,0 +1 @@ +typedef unsigned long long __jmp_buf[32]; diff --git a/third_party/ulib/musl/arch/arm/bits/signal.h b/third_party/ulib/musl/arch/arm/bits/signal.h new file mode 100644 index 000000000..08dc3ecce --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/signal.h @@ -0,0 +1,84 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef int greg_t, gregset_t[18]; +typedef struct sigcontext { + unsigned long trap_no, error_code, oldmask; + unsigned long arm_r0, arm_r1, arm_r2, arm_r3; + unsigned long arm_r4, arm_r5, arm_r6, arm_r7; + unsigned long arm_r8, arm_r9, arm_r10, arm_fp; + unsigned long arm_ip, arm_sp, arm_lr, arm_pc; + unsigned long arm_cpsr, fault_address; +} mcontext_t; +#else +typedef struct { unsigned long __regs[21]; } mcontext_t; +#endif + +struct sigaltstack { + void* ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext* uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; + unsigned long long uc_regspace[64]; +} ucontext_t; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#endif + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS + +#define _NSIG 65 diff --git a/third_party/ulib/musl/arch/arm/bits/stat.h b/third_party/ulib/musl/arch/arm/bits/stat.h new file mode 100644 index 000000000..75d16bf6f --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/stat.h @@ -0,0 +1,21 @@ +/* copied from kernel definition, but with padding replaced + * by the corresponding correctly-sized userspace types. */ + +struct stat { + dev_t st_dev; + int __st_dev_padding; + long __st_ino_truncated; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + int __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + ino_t st_ino; +}; diff --git a/third_party/ulib/musl/arch/arm/bits/stdint.h b/third_party/ulib/musl/arch/arm/bits/stdint.h new file mode 100644 index 000000000..93ec5df8f --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/stdint.h @@ -0,0 +1,20 @@ +typedef int32_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast16_t; +typedef uint32_t uint_fast32_t; + +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN + +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX + +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#define SIZE_MAX UINT32_MAX diff --git a/third_party/ulib/musl/arch/arm/bits/syscall.h b/third_party/ulib/musl/arch/arm/bits/syscall.h new file mode 100644 index 000000000..1c240edec --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/syscall.h @@ -0,0 +1,167 @@ +#define SYS_exit 1 +#define SYS_write 4 +#define SYS_close 6 +#define SYS_execve 11 +#define SYS_chdir 12 +#define SYS_getpid 20 +#define SYS_setuid 23 +#define SYS_getuid 24 +#define SYS_ptrace 26 +#define SYS_sync 36 +#define SYS_kill 37 +#define SYS_dup 41 +#define SYS_times 43 +#define SYS_brk 45 +#define SYS_setgid 46 +#define SYS_getgid 47 +#define SYS_geteuid 49 +#define SYS_getegid 50 +#define SYS_acct 51 +#define SYS_ioctl 54 +#define SYS_fcntl 55 +#define SYS_setpgid 57 +#define SYS_umask 60 +#define SYS_chroot 61 +#define SYS_getppid 64 +#define SYS_setsid 66 +#define SYS_setreuid 70 +#define SYS_setregid 71 +#define SYS_sethostname 74 +#define SYS_getrusage 77 +#define SYS_settimeofday 79 +#define SYS_getgroups 80 +#define SYS_setgroups 81 +#define SYS_truncate 92 +#define SYS_ftruncate 93 +#define SYS_fchmod 94 +#define SYS_fchown 95 +#define SYS_getpriority 96 +#define SYS_setpriority 97 +#define SYS_statfs 99 +#define SYS_fstatfs 100 +#define SYS_setitimer 104 +#define SYS_getitimer 105 +#define SYS_fstat 108 +#define SYS_wait4 114 +#define SYS_fsync 118 +#define SYS_clone 120 +#define SYS_setdomainname 121 +#define SYS_uname 122 +#define SYS_adjtimex 124 +#define SYS_mprotect 125 +#define SYS_quotactl 131 +#define SYS_getpgid 132 +#define SYS_fchdir 133 +#define SYS_getdents 141 +#define SYS_flock 143 +#define SYS_msync 144 +#define SYS_readv 145 +#define SYS_writev 146 +#define SYS_getsid 147 +#define SYS_fdatasync 148 +#define SYS_mlock 150 +#define SYS_munlock 151 +#define SYS_mlockall 152 +#define SYS_munlockall 153 +#define SYS_sched_setparam 154 +#define SYS_sched_getparam 155 +#define SYS_sched_setscheduler 156 +#define SYS_sched_getscheduler 157 +#define SYS_sched_yield 158 +#define SYS_sched_get_priority_max 159 +#define SYS_sched_get_priority_min 160 +#define SYS_sched_rr_get_interval 161 +#define SYS_nanosleep 162 +#define SYS_setresuid 164 +#define SYS_getresuid 165 +#define SYS_setresgid 170 +#define SYS_getresgid 171 +#define SYS_prctl 172 +#define SYS_rt_sigaction 174 +#define SYS_rt_sigprocmask 175 +#define SYS_rt_sigpending 176 +#define SYS_rt_sigtimedwait 177 +#define SYS_rt_sigqueueinfo 178 +#define SYS_rt_sigsuspend 179 +#define SYS_pread64 180 +#define SYS_pwrite64 181 +#define SYS_getcwd 183 +#define SYS_sigaltstack 186 +#define SYS_ugetrlimit 191 +#define SYS_mmap2 192 +#define SYS_mincore 219 +#define SYS_madvise 220 +#define SYS_gettid 224 +#define SYS_tkill 238 +#define SYS_sched_setaffinity 241 +#define SYS_sched_getaffinity 242 +#define SYS_set_tid_address 256 +#define SYS_timer_create 257 +#define SYS_timer_settime 258 +#define SYS_timer_gettime 259 +#define SYS_timer_getoverrun 260 +#define SYS_timer_delete 261 +#define SYS_clock_settime 262 +#define SYS_clock_getres 264 +#define SYS_clock_nanosleep 265 +#define SYS_fadvise64_64 270 +#define SYS_mq_open 274 +#define SYS_mq_unlink 275 +#define SYS_mq_timedsend 276 +#define SYS_mq_timedreceive 277 +#define SYS_mq_notify 278 +#define SYS_mq_getsetattr 279 +#define SYS_waitid 280 +#define SYS_socket 281 +#define SYS_bind 282 +#define SYS_connect 283 +#define SYS_listen 284 +#define SYS_accept 285 +#define SYS_getsockname 286 +#define SYS_getpeername 287 +#define SYS_socketpair 288 +#define SYS_sendto 290 +#define SYS_recvfrom 292 +#define SYS_shutdown 293 +#define SYS_setsockopt 294 +#define SYS_getsockopt 295 +#define SYS_sendmsg 296 +#define SYS_recvmsg 297 +#define SYS_semop 298 +#define SYS_semget 299 +#define SYS_semctl 300 +#define SYS_msgsnd 301 +#define SYS_msgrcv 302 +#define SYS_msgget 303 +#define SYS_msgctl 304 +#define SYS_shmat 305 +#define SYS_shmdt 306 +#define SYS_shmget 307 +#define SYS_shmctl 308 +#define SYS_semtimedop 312 +#define SYS_openat 322 +#define SYS_mkdirat 323 +#define SYS_mknodat 324 +#define SYS_fchownat 325 +#define SYS_fstatat64 327 +#define SYS_unlinkat 328 +#define SYS_renameat 329 +#define SYS_linkat 330 +#define SYS_symlinkat 331 +#define SYS_readlinkat 332 +#define SYS_fchmodat 333 +#define SYS_faccessat 334 +#define SYS_pselect6 335 +#define SYS_ppoll 336 +#define SYS_set_robust_list 338 +#define SYS_getcpu 345 +#define SYS_utimensat 348 +#define SYS_fallocate 352 +#define SYS_dup3 358 +#define SYS_pipe2 359 +#define SYS_preadv 361 +#define SYS_pwritev 362 +#define SYS_recvmmsg 365 +#define SYS_accept4 366 +#define SYS_prlimit64 369 +#define SYS_sendmmsg 374 diff --git a/third_party/ulib/musl/arch/arm/bits/user.h b/third_party/ulib/musl/arch/arm/bits/user.h new file mode 100644 index 000000000..2fb12ffed --- /dev/null +++ b/third_party/ulib/musl/arch/arm/bits/user.h @@ -0,0 +1,36 @@ +typedef struct user_fpregs { + struct fp_reg { + unsigned sign1 : 1; + unsigned unused : 15; + unsigned sign2 : 1; + unsigned exponent : 14; + unsigned j : 1; + unsigned mantissa1 : 31; + unsigned mantissa0 : 32; + } fpregs[8]; + unsigned fpsr : 32; + unsigned fpcr : 32; + unsigned char ftype[8]; + unsigned int init_flag; +} elf_fpregset_t; + +struct user_regs { + unsigned long uregs[18]; +}; +#define ELF_NGREG 18 +typedef unsigned long elf_greg_t, elf_gregset_t[ELF_NGREG]; + +struct user { + struct user_regs regs; + int u_fpvalid; + unsigned long u_tsize, u_dsize, u_ssize; + unsigned long start_code, start_stack; + long signal; + int reserved; + struct user_regs* u_ar0; + unsigned long magic; + char u_comm[32]; + int u_debugreg[8]; + struct user_fpregs u_fp; + struct user_fpregs* u_fp0; +}; diff --git a/third_party/ulib/musl/arch/arm/crt_arch.h b/third_party/ulib/musl/arch/arm/crt_arch.h new file mode 100644 index 000000000..531aad492 --- /dev/null +++ b/third_party/ulib/musl/arch/arm/crt_arch.h @@ -0,0 +1,15 @@ +__asm__(".text \n" + ".global " START " \n" + ".type " START ",%function \n" START ": \n" + " mov fp, #0 \n" + " mov lr, #0 \n" + " ldr a2, 1f \n" + " add a2, pc, a2 \n" + " mov a1, sp \n" + "2: and ip, a1, #-16 \n" + " mov sp, ip \n" + " bl " START "_c \n" + ".weak _DYNAMIC \n" + ".hidden _DYNAMIC \n" + ".align 2 \n" + "1: .word _DYNAMIC-2b \n"); diff --git a/third_party/ulib/musl/arch/arm/pthread_arch.h b/third_party/ulib/musl/arch/arm/pthread_arch.h new file mode 100644 index 000000000..9b8f502dd --- /dev/null +++ b/third_party/ulib/musl/arch/arm/pthread_arch.h @@ -0,0 +1,6 @@ +#include + +#define TLS_ABOVE_TP +#define TP_ADJ(p) ((char*)(p) + sizeof(struct pthread) - 8) + +#define MC_PC arm_pc diff --git a/third_party/ulib/musl/arch/arm/reloc.h b/third_party/ulib/musl/arch/arm/reloc.h new file mode 100644 index 000000000..4785c3066 --- /dev/null +++ b/third_party/ulib/musl/arch/arm/reloc.h @@ -0,0 +1,31 @@ +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ENDIAN_SUFFIX "eb" +#else +#define ENDIAN_SUFFIX "" +#endif + +#if __ARM_PCS_VFP +#define FP_SUFFIX "hf" +#else +#define FP_SUFFIX "" +#endif + +#define LDSO_ARCH "arm" ENDIAN_SUFFIX FP_SUFFIX + +#define NO_LEGACY_INITFINI + +#define TPOFF_K 8 + +#define REL_SYMBOLIC R_ARM_ABS32 +#define REL_GOT R_ARM_GLOB_DAT +#define REL_PLT R_ARM_JUMP_SLOT +#define REL_RELATIVE R_ARM_RELATIVE +#define REL_COPY R_ARM_COPY +#define REL_DTPMOD R_ARM_TLS_DTPMOD32 +#define REL_DTPOFF R_ARM_TLS_DTPOFF32 +#define REL_TPOFF R_ARM_TLS_TPOFF32 +//#define REL_TLSDESC R_ARM_TLS_DESC + +#define CRTJMP(pc, sp) __asm__ __volatile__("mov sp,%1 ; bx %0" : : "r"(pc), "r"(sp) : "memory") diff --git a/third_party/ulib/musl/arch/generic/bits/errno.h b/third_party/ulib/musl/arch/generic/bits/errno.h new file mode 100644 index 000000000..b9ebc31bf --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/errno.h @@ -0,0 +1,134 @@ +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 diff --git a/third_party/ulib/musl/arch/generic/bits/fcntl.h b/third_party/ulib/musl/arch/generic/bits/fcntl.h new file mode 100644 index 000000000..7c6add09c --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/fcntl.h @@ -0,0 +1,40 @@ +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020200000 +#define O_NDELAY O_NONBLOCK + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 12 +#define F_SETLK 13 +#define F_SETLKW 14 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 diff --git a/third_party/ulib/musl/arch/generic/bits/fenv.h b/third_party/ulib/musl/arch/generic/bits/fenv.h new file mode 100644 index 000000000..65e95323f --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/fenv.h @@ -0,0 +1,8 @@ +#define FE_ALL_EXCEPT 0 +#define FE_TONEAREST 0 + +typedef unsigned long fexcept_t; + +typedef struct { unsigned long __cw; } fenv_t; + +#define FE_DFL_ENV ((const fenv_t*)-1) diff --git a/third_party/ulib/musl/arch/generic/bits/io.h b/third_party/ulib/musl/arch/generic/bits/io.h new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/arch/generic/bits/ioctl.h b/third_party/ulib/musl/arch/generic/bits/ioctl.h new file mode 100644 index 000000000..66525bf71 --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/ioctl.h @@ -0,0 +1,197 @@ +#define _IOC(a, b, c, d) (((a) << 30) | ((b) << 8) | (c) | ((d) << 16)) +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IO(a, b) _IOC(_IOC_NONE, (a), (b), 0) +#define _IOW(a, b, c) _IOC(_IOC_WRITE, (a), (b), sizeof(c)) +#define _IOR(a, b, c) _IOC(_IOC_READ, (a), (b), sizeof(c)) +#define _IOWR(a, b, c) _IOC(_IOC_READ | _IOC_WRITE, (a), (b), sizeof(c)) + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCTTYGSTRUCT 0x5426 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGPTN 0x80045430 +#define TIOCSPTLCK 0x40045431 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B + +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define TIOCGHAYESESP 0x545E +#define TIOCSHAYESESP 0x545F +#define FIOQSIZE 0x5460 + +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 +#define TIOCM_MODEM_BITS TIOCM_OUT2 + +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 +#define N_MASC 8 +#define N_R3964 9 +#define N_PROFIBUS_FDL 10 +#define N_IRDA 11 +#define N_SMSBLOCK 12 +#define N_HDLC 13 +#define N_SYNC_PPP 14 +#define N_HCI 15 + +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 + +#define SIOCADDRT 0x890B +#define SIOCDELRT 0x890C +#define SIOCRTMSG 0x890D + +#define SIOCGIFNAME 0x8910 +#define SIOCSIFLINK 0x8911 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCSIFADDR 0x8916 +#define SIOCGIFDSTADDR 0x8917 +#define SIOCSIFDSTADDR 0x8918 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCSIFBRDADDR 0x891a +#define SIOCGIFNETMASK 0x891b +#define SIOCSIFNETMASK 0x891c +#define SIOCGIFMETRIC 0x891d +#define SIOCSIFMETRIC 0x891e +#define SIOCGIFMEM 0x891f +#define SIOCSIFMEM 0x8920 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCSIFHWADDR 0x8924 +#define SIOCGIFENCAP 0x8925 +#define SIOCSIFENCAP 0x8926 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFSLAVE 0x8929 +#define SIOCSIFSLAVE 0x8930 +#define SIOCADDMULTI 0x8931 +#define SIOCDELMULTI 0x8932 +#define SIOCGIFINDEX 0x8933 +#define SIOGIFINDEX SIOCGIFINDEX +#define SIOCSIFPFLAGS 0x8934 +#define SIOCGIFPFLAGS 0x8935 +#define SIOCDIFADDR 0x8936 +#define SIOCSIFHWBROADCAST 0x8937 +#define SIOCGIFCOUNT 0x8938 + +#define SIOCGIFBR 0x8940 +#define SIOCSIFBR 0x8941 + +#define SIOCGIFTXQLEN 0x8942 +#define SIOCSIFTXQLEN 0x8943 + +#define SIOCDARP 0x8953 +#define SIOCGARP 0x8954 +#define SIOCSARP 0x8955 + +#define SIOCDRARP 0x8960 +#define SIOCGRARP 0x8961 +#define SIOCSRARP 0x8962 + +#define SIOCGIFMAP 0x8970 +#define SIOCSIFMAP 0x8971 + +#define SIOCADDDLCI 0x8980 +#define SIOCDELDLCI 0x8981 + +#define SIOCDEVPRIVATE 0x89F0 +#define SIOCPROTOPRIVATE 0x89E0 diff --git a/third_party/ulib/musl/arch/generic/bits/ipc.h b/third_party/ulib/musl/arch/generic/bits/ipc.h new file mode 100644 index 000000000..ff5c0bc3f --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/ipc.h @@ -0,0 +1,13 @@ +struct ipc_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; + long __pad1; + long __pad2; +}; + +#define IPC_64 0x100 diff --git a/third_party/ulib/musl/arch/generic/bits/mman.h b/third_party/ulib/musl/arch/generic/bits/mman.h new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/arch/generic/bits/msg.h b/third_party/ulib/musl/arch/generic/bits/msg.h new file mode 100644 index 000000000..129c1918f --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/msg.h @@ -0,0 +1,15 @@ +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + int __unused1; + time_t msg_rtime; + int __unused2; + time_t msg_ctime; + int __unused3; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; diff --git a/third_party/ulib/musl/arch/generic/bits/poll.h b/third_party/ulib/musl/arch/generic/bits/poll.h new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/arch/generic/bits/resource.h b/third_party/ulib/musl/arch/generic/bits/resource.h new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/arch/generic/bits/sem.h b/third_party/ulib/musl/arch/generic/bits/sem.h new file mode 100644 index 000000000..3c0e96184 --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/sem.h @@ -0,0 +1,16 @@ +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t __unused1; + time_t sem_ctime; + time_t __unused2; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned short sem_nsems; + char __sem_nsems_pad[sizeof(time_t) - sizeof(short)]; +#else + char __sem_nsems_pad[sizeof(time_t) - sizeof(short)]; + unsigned short sem_nsems; +#endif + time_t __unused3; + time_t __unused4; +}; diff --git a/third_party/ulib/musl/arch/generic/bits/shm.h b/third_party/ulib/musl/arch/generic/bits/shm.h new file mode 100644 index 000000000..dad7b5540 --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/shm.h @@ -0,0 +1,27 @@ +#define SHMLBA 4096 + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + int __unused1; + time_t shm_dtime; + int __unused2; + time_t shm_ctime; + int __unused3; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __pad1; + unsigned long __pad2; +}; + +struct shminfo { + unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4]; +}; + +struct shm_info { + int __used_ids; + unsigned long shm_tot, shm_rss, shm_swp; + unsigned long __swap_attempts, __swap_successes; +}; diff --git a/third_party/ulib/musl/arch/generic/bits/socket.h b/third_party/ulib/musl/arch/generic/bits/socket.h new file mode 100644 index 000000000..fabe67246 --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/socket.h @@ -0,0 +1,15 @@ +struct msghdr { + void* msg_name; + socklen_t msg_namelen; + struct iovec* msg_iov; + int msg_iovlen; + void* msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; diff --git a/third_party/ulib/musl/arch/generic/bits/statfs.h b/third_party/ulib/musl/arch/generic/bits/statfs.h new file mode 100644 index 000000000..656aa8da5 --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/statfs.h @@ -0,0 +1,7 @@ +struct statfs { + unsigned long f_type, f_bsize; + fsblkcnt_t f_blocks, f_bfree, f_bavail; + fsfilcnt_t f_files, f_ffree; + fsid_t f_fsid; + unsigned long f_namelen, f_frsize, f_flags, f_spare[4]; +}; diff --git a/third_party/ulib/musl/arch/generic/bits/stdarg.h b/third_party/ulib/musl/arch/generic/bits/stdarg.h new file mode 100644 index 000000000..efdd1f9b9 --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/stdarg.h @@ -0,0 +1,4 @@ +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) diff --git a/third_party/ulib/musl/arch/generic/bits/termios.h b/third_party/ulib/musl/arch/generic/bits/termios.h new file mode 100644 index 000000000..1a06f762e --- /dev/null +++ b/third_party/ulib/musl/arch/generic/bits/termios.h @@ -0,0 +1,159 @@ +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t __c_ispeed; + speed_t __c_ospeed; +}; + +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +#define B0 0000000 +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 + +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +#define CBAUD 0010017 + +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +#define ISIG 0000001 +#define ICANON 0000002 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 + +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define CBAUDEX 0010000 +#define CRTSCTS 020000000000 +#define EXTPROC 0200000 +#define XTABS 0014000 +#endif diff --git a/third_party/ulib/musl/arch/x32/atomic_arch.h b/third_party/ulib/musl/arch/x32/atomic_arch.h new file mode 100644 index 000000000..990d474db --- /dev/null +++ b/third_party/ulib/musl/arch/x32/atomic_arch.h @@ -0,0 +1,79 @@ +#define a_cas a_cas +static inline int a_cas(volatile int* p, int t, int s) { + __asm__ __volatile__("lock ; cmpxchg %3, %1" : "=a"(t), "=m"(*p) : "a"(t), "r"(s) : "memory"); + return t; +} + +#define a_swap a_swap +static inline int a_swap(volatile int* p, int v) { + __asm__ __volatile__("xchg %0, %1" : "=r"(v), "=m"(*p) : "0"(v) : "memory"); + return v; +} + +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int* p, int v) { + __asm__ __volatile__("lock ; xadd %0, %1" : "=r"(v), "=m"(*p) : "0"(v) : "memory"); + return v; +} + +#define a_and a_and +static inline void a_and(volatile int* p, int v) { + __asm__ __volatile__("lock ; and %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_or a_or +static inline void a_or(volatile int* p, int v) { + __asm__ __volatile__("lock ; or %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_and_64 a_and_64 +static inline void a_and_64(volatile uint64_t* p, uint64_t v) { + __asm__ __volatile("lock ; and %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_or_64 a_or_64 +static inline void a_or_64(volatile uint64_t* p, uint64_t v) { + __asm__ __volatile__("lock ; or %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_inc a_inc +static inline void a_inc(volatile int* p) { + __asm__ __volatile__("lock ; incl %0" : "=m"(*p) : "m"(*p) : "memory"); +} + +#define a_dec a_dec +static inline void a_dec(volatile int* p) { + __asm__ __volatile__("lock ; decl %0" : "=m"(*p) : "m"(*p) : "memory"); +} + +#define a_store a_store +static inline void a_store(volatile int* p, int x) { + __asm__ __volatile__("mov %1, %0 ; lock ; orl $0,(%%rsp)" : "=m"(*p) : "r"(x) : "memory"); +} + +#define a_barrier a_barrier +static inline void a_barrier(void) { + __asm__ __volatile__("" : : : "memory"); +} + +#define a_spin a_spin +static inline void a_spin(void) { + __asm__ __volatile__("pause" : : : "memory"); +} + +#define a_crash a_crash +static inline void a_crash(void) { + __asm__ __volatile__("hlt" : : : "memory"); +} + +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) { + __asm__("bsf %1,%0" : "=r"(x) : "r"(x)); + return x; +} + +#define a_ctz_l a_ctz_l +static inline int a_ctz_l(unsigned long x) { + __asm__("bsf %1,%0" : "=r"(x) : "r"(x)); + return x; +} diff --git a/third_party/ulib/musl/arch/x32/bits/alltypes.h.in b/third_party/ulib/musl/arch/x32/bits/alltypes.h.in new file mode 100644 index 000000000..16391295b --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/alltypes.h.in @@ -0,0 +1,31 @@ +#define _Addr int +#define _Int64 long long +#define _Reg long long + +TYPEDEF __builtin_va_list va_list; +TYPEDEF __builtin_va_list __isoc_va_list; + +#ifndef __cplusplus +TYPEDEF long wchar_t; +#endif + +#if defined(__FLT_EVAL_METHOD__) && __FLT_EVAL_METHOD__ == 2 +TYPEDEF long double float_t; +TYPEDEF long double double_t; +#else +TYPEDEF float float_t; +TYPEDEF double double_t; +#endif + +TYPEDEF struct { long long __ll; long double __ld; } max_align_t; + +TYPEDEF long long time_t; +TYPEDEF long long suseconds_t; + +TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t; +TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; +TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t; +TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t; +TYPEDEF struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t; diff --git a/third_party/ulib/musl/arch/x32/bits/endian.h b/third_party/ulib/musl/arch/x32/bits/endian.h new file mode 100644 index 000000000..172c338f5 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/endian.h @@ -0,0 +1 @@ +#define __BYTE_ORDER __LITTLE_ENDIAN diff --git a/third_party/ulib/musl/arch/x32/bits/fcntl.h b/third_party/ulib/musl/arch/x32/bits/fcntl.h new file mode 100644 index 000000000..c3fca266e --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/fcntl.h @@ -0,0 +1,40 @@ +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_LARGEFILE 0 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020200000 +#define O_NDELAY O_NONBLOCK + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 diff --git a/third_party/ulib/musl/arch/x32/bits/fenv.h b/third_party/ulib/musl/arch/x32/bits/fenv.h new file mode 100644 index 000000000..5cea203ee --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/fenv.h @@ -0,0 +1,34 @@ +#define FE_INVALID 1 +#define __FE_DENORM 2 +#define FE_DIVBYZERO 4 +#define FE_OVERFLOW 8 +#define FE_UNDERFLOW 16 +#define FE_INEXACT 32 + +#define FE_ALL_EXCEPT 63 + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xc00 + +typedef unsigned short fexcept_t; + +typedef struct { + unsigned short __control_word; + unsigned short __unused1; + unsigned short __status_word; + unsigned short __unused2; + unsigned short __tags; + unsigned short __unused3; + unsigned int __eip; + unsigned short __cs_selector; + unsigned int __opcode : 11; + unsigned int __unused4 : 5; + unsigned int __data_offset; + unsigned short __data_selector; + unsigned short __unused5; + unsigned int __mxcsr; +} fenv_t; + +#define FE_DFL_ENV ((const fenv_t*)-1) diff --git a/third_party/ulib/musl/arch/x32/bits/float.h b/third_party/ulib/musl/arch/x32/bits/float.h new file mode 100644 index 000000000..f935e3435 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/float.h @@ -0,0 +1,20 @@ +#ifdef __FLT_EVAL_METHOD__ +#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#else +#define FLT_EVAL_METHOD 0 +#endif + +#define LDBL_TRUE_MIN 3.6451995318824746025e-4951L +#define LDBL_MIN 3.3621031431120935063e-4932L +#define LDBL_MAX 1.1897314953572317650e+4932L +#define LDBL_EPSILON 1.0842021724855044340e-19L + +#define LDBL_MANT_DIG 64 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 18 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 21 diff --git a/third_party/ulib/musl/arch/x32/bits/io.h b/third_party/ulib/musl/arch/x32/bits/io.h new file mode 100644 index 000000000..9ad19b80c --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/io.h @@ -0,0 +1,53 @@ +static __inline void outb(unsigned char __val, unsigned short __port) { + __asm__ volatile("outb %0,%1" : : "a"(__val), "dN"(__port)); +} + +static __inline void outw(unsigned short __val, unsigned short __port) { + __asm__ volatile("outw %0,%1" : : "a"(__val), "dN"(__port)); +} + +static __inline void outl(unsigned int __val, unsigned short __port) { + __asm__ volatile("outl %0,%1" : : "a"(__val), "dN"(__port)); +} + +static __inline unsigned char inb(unsigned short __port) { + unsigned char __val; + __asm__ volatile("inb %1,%0" : "=a"(__val) : "dN"(__port)); + return __val; +} + +static __inline unsigned short inw(unsigned short __port) { + unsigned short __val; + __asm__ volatile("inw %1,%0" : "=a"(__val) : "dN"(__port)); + return __val; +} + +static __inline unsigned int inl(unsigned short __port) { + unsigned int __val; + __asm__ volatile("inl %1,%0" : "=a"(__val) : "dN"(__port)); + return __val; +} + +static __inline void outsb(unsigned short __port, const void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; outsb" : "+S"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void outsw(unsigned short __port, const void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; outsw" : "+S"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void outsl(unsigned short __port, const void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; outsl" : "+S"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void insb(unsigned short __port, void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; insb" : "+D"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void insw(unsigned short __port, void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; insw" : "+D"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void insl(unsigned short __port, void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; insl" : "+D"(__buf), "+c"(__n) : "d"(__port)); +} diff --git a/third_party/ulib/musl/arch/x32/bits/ioctl.h b/third_party/ulib/musl/arch/x32/bits/ioctl.h new file mode 100644 index 000000000..66525bf71 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/ioctl.h @@ -0,0 +1,197 @@ +#define _IOC(a, b, c, d) (((a) << 30) | ((b) << 8) | (c) | ((d) << 16)) +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IO(a, b) _IOC(_IOC_NONE, (a), (b), 0) +#define _IOW(a, b, c) _IOC(_IOC_WRITE, (a), (b), sizeof(c)) +#define _IOR(a, b, c) _IOC(_IOC_READ, (a), (b), sizeof(c)) +#define _IOWR(a, b, c) _IOC(_IOC_READ | _IOC_WRITE, (a), (b), sizeof(c)) + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCTTYGSTRUCT 0x5426 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGPTN 0x80045430 +#define TIOCSPTLCK 0x40045431 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B + +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define TIOCGHAYESESP 0x545E +#define TIOCSHAYESESP 0x545F +#define FIOQSIZE 0x5460 + +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 +#define TIOCM_MODEM_BITS TIOCM_OUT2 + +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 +#define N_MASC 8 +#define N_R3964 9 +#define N_PROFIBUS_FDL 10 +#define N_IRDA 11 +#define N_SMSBLOCK 12 +#define N_HDLC 13 +#define N_SYNC_PPP 14 +#define N_HCI 15 + +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 + +#define SIOCADDRT 0x890B +#define SIOCDELRT 0x890C +#define SIOCRTMSG 0x890D + +#define SIOCGIFNAME 0x8910 +#define SIOCSIFLINK 0x8911 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCSIFADDR 0x8916 +#define SIOCGIFDSTADDR 0x8917 +#define SIOCSIFDSTADDR 0x8918 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCSIFBRDADDR 0x891a +#define SIOCGIFNETMASK 0x891b +#define SIOCSIFNETMASK 0x891c +#define SIOCGIFMETRIC 0x891d +#define SIOCSIFMETRIC 0x891e +#define SIOCGIFMEM 0x891f +#define SIOCSIFMEM 0x8920 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCSIFHWADDR 0x8924 +#define SIOCGIFENCAP 0x8925 +#define SIOCSIFENCAP 0x8926 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFSLAVE 0x8929 +#define SIOCSIFSLAVE 0x8930 +#define SIOCADDMULTI 0x8931 +#define SIOCDELMULTI 0x8932 +#define SIOCGIFINDEX 0x8933 +#define SIOGIFINDEX SIOCGIFINDEX +#define SIOCSIFPFLAGS 0x8934 +#define SIOCGIFPFLAGS 0x8935 +#define SIOCDIFADDR 0x8936 +#define SIOCSIFHWBROADCAST 0x8937 +#define SIOCGIFCOUNT 0x8938 + +#define SIOCGIFBR 0x8940 +#define SIOCSIFBR 0x8941 + +#define SIOCGIFTXQLEN 0x8942 +#define SIOCSIFTXQLEN 0x8943 + +#define SIOCDARP 0x8953 +#define SIOCGARP 0x8954 +#define SIOCSARP 0x8955 + +#define SIOCDRARP 0x8960 +#define SIOCGRARP 0x8961 +#define SIOCSRARP 0x8962 + +#define SIOCGIFMAP 0x8970 +#define SIOCSIFMAP 0x8971 + +#define SIOCADDDLCI 0x8980 +#define SIOCDELDLCI 0x8981 + +#define SIOCDEVPRIVATE 0x89F0 +#define SIOCPROTOPRIVATE 0x89E0 diff --git a/third_party/ulib/musl/arch/x32/bits/ipc.h b/third_party/ulib/musl/arch/x32/bits/ipc.h new file mode 100644 index 000000000..f7c093810 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/ipc.h @@ -0,0 +1,13 @@ +struct ipc_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; + long long __pad1; + long long __pad2; +}; + +#define IPC_64 0 diff --git a/third_party/ulib/musl/arch/x32/bits/limits.h b/third_party/ulib/musl/arch/x32/bits/limits.h new file mode 100644 index 000000000..17ee07a39 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/limits.h @@ -0,0 +1,8 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define PAGE_SIZE 4096 +#define LONG_BIT 32 +#endif + +#define LONG_MAX 0x7fffffffL +#define LLONG_MAX 0x7fffffffffffffffLL diff --git a/third_party/ulib/musl/arch/x32/bits/mman.h b/third_party/ulib/musl/arch/x32/bits/mman.h new file mode 100644 index 000000000..e498b6d6e --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/mman.h @@ -0,0 +1 @@ +#define MAP_32BIT 0x40 diff --git a/third_party/ulib/musl/arch/x32/bits/msg.h b/third_party/ulib/musl/arch/x32/bits/msg.h new file mode 100644 index 000000000..d29113f34 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/msg.h @@ -0,0 +1,15 @@ +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; + unsigned long msg_cbytes; + long __unused1; + msgqnum_t msg_qnum; + long __unused2; + msglen_t msg_qbytes; + long __unused3; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long long __unused[2]; +}; diff --git a/third_party/ulib/musl/arch/x32/bits/posix.h b/third_party/ulib/musl/arch/x32/bits/posix.h new file mode 100644 index 000000000..8068ce98d --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/posix.h @@ -0,0 +1,2 @@ +#define _POSIX_V6_LP64_OFF64 1 +#define _POSIX_V7_LP64_OFF64 1 diff --git a/third_party/ulib/musl/arch/x32/bits/reg.h b/third_party/ulib/musl/arch/x32/bits/reg.h new file mode 100644 index 000000000..53ede07b7 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/reg.h @@ -0,0 +1,29 @@ +#undef __WORDSIZE +#define __WORDSIZE 32 +#define R15 0 +#define R14 1 +#define R13 2 +#define R12 3 +#define RBP 4 +#define RBX 5 +#define R11 6 +#define R10 7 +#define R9 8 +#define R8 9 +#define RAX 10 +#define RCX 11 +#define RDX 12 +#define RSI 13 +#define RDI 14 +#define ORIG_RAX 15 +#define RIP 16 +#define CS 17 +#define EFLAGS 18 +#define RSP 19 +#define SS 20 +#define FS_BASE 21 +#define GS_BASE 22 +#define DS 23 +#define ES 24 +#define FS 25 +#define GS 26 diff --git a/third_party/ulib/musl/arch/x32/bits/setjmp.h b/third_party/ulib/musl/arch/x32/bits/setjmp.h new file mode 100644 index 000000000..a9262a647 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/setjmp.h @@ -0,0 +1 @@ +typedef unsigned long long __jmp_buf[8]; diff --git a/third_party/ulib/musl/arch/x32/bits/shm.h b/third_party/ulib/musl/arch/x32/bits/shm.h new file mode 100644 index 000000000..2abb5633d --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/shm.h @@ -0,0 +1,31 @@ +#define SHMLBA 4096 + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __pad0; + unsigned long long __pad1; + unsigned long long __pad2; +}; + +struct shminfo { + unsigned long shmmax, __pad0, shmmin, __pad1, shmmni, __pad2, shmseg, __pad3, shmall, __pad4; + unsigned long long __unused[4]; +}; + +struct shm_info { + int __used_ids; + int __pad_ids; + unsigned long shm_tot, __pad0, shm_rss, __pad1, shm_swp, __pad2; + unsigned long __swap_attempts, __pad3, __swap_successes, __pad4; +} +#ifdef __GNUC__ +__attribute__((__aligned__(8))) +#endif +; diff --git a/third_party/ulib/musl/arch/x32/bits/signal.h b/third_party/ulib/musl/arch/x32/bits/signal.h new file mode 100644 index 000000000..5ca710485 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/signal.h @@ -0,0 +1,127 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#endif + +#ifdef _GNU_SOURCE +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef long long greg_t, gregset_t[23]; +typedef struct _fpstate { + unsigned short cwd, swd, ftw, fop; + unsigned long long rip, rdp; + unsigned mxcsr, mxcr_mask; + struct { + unsigned short significand[4], exponent, padding[3]; + } _st[8]; + struct { + unsigned element[4]; + } _xmm[16]; + unsigned padding[24]; +} * fpregset_t; +struct sigcontext { + unsigned long long r8, r9, r10, r11, r12, r13, r14, r15; + unsigned long long rdi, rsi, rbp, rbx, rdx, rax, rcx, rsp, rip, eflags; + unsigned short cs, gs, fs, __pad0; + unsigned long long err, trapno, oldmask, cr2; + struct _fpstate* fpstate; + unsigned long long __reserved1[8]; +}; +typedef struct { + gregset_t gregs; + fpregset_t fpregs; + unsigned long long __reserved1[8]; +} mcontext_t; +#else +typedef struct { unsigned long long __space[32]; } mcontext_t; +#endif + +struct sigaltstack { + void* ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext* uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; + unsigned long long __fpregs_mem[64]; +} ucontext_t; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#endif + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS + +#define _NSIG 65 diff --git a/third_party/ulib/musl/arch/x32/bits/socket.h b/third_party/ulib/musl/arch/x32/bits/socket.h new file mode 100644 index 000000000..e92e0aa9c --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/socket.h @@ -0,0 +1,16 @@ +struct msghdr { + void* msg_name; + socklen_t msg_namelen; + struct iovec* msg_iov; + int msg_iovlen, __pad1; + void* msg_control; + socklen_t msg_controllen, __pad2; + int msg_flags; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int __pad1; + int cmsg_level; + int cmsg_type; +}; diff --git a/third_party/ulib/musl/arch/x32/bits/stat.h b/third_party/ulib/musl/arch/x32/bits/stat.h new file mode 100644 index 000000000..5cc83e576 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/stat.h @@ -0,0 +1,22 @@ +/* copied from kernel definition, but with padding replaced + * by the corresponding correctly-sized userspace types. */ + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long long __unused[3]; +}; diff --git a/third_party/ulib/musl/arch/x32/bits/statfs.h b/third_party/ulib/musl/arch/x32/bits/statfs.h new file mode 100644 index 000000000..88893315e --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/statfs.h @@ -0,0 +1,9 @@ +struct statfs { + unsigned long f_type, __pad0, f_bsize, __pad1; + fsblkcnt_t f_blocks, f_bfree, f_bavail; + fsfilcnt_t f_files, f_ffree; + fsid_t f_fsid; + unsigned long f_namelen, __pad2, f_frsize, __pad3; + unsigned long f_flags, __pad4; + unsigned long long f_spare[4]; +}; diff --git a/third_party/ulib/musl/arch/x32/bits/stdint.h b/third_party/ulib/musl/arch/x32/bits/stdint.h new file mode 100644 index 000000000..93ec5df8f --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/stdint.h @@ -0,0 +1,20 @@ +typedef int32_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast16_t; +typedef uint32_t uint_fast32_t; + +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN + +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX + +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#define SIZE_MAX UINT32_MAX diff --git a/third_party/ulib/musl/arch/x32/bits/syscall.h b/third_party/ulib/musl/arch/x32/bits/syscall.h new file mode 100644 index 000000000..4481d9be4 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/syscall.h @@ -0,0 +1,542 @@ +#define __X32_SYSCALL_BIT 0x40000000 +#define __NR_read (__X32_SYSCALL_BIT + 0) +#define __NR_write (__X32_SYSCALL_BIT + 1) +#define __NR_open (__X32_SYSCALL_BIT + 2) +#define __NR_close (__X32_SYSCALL_BIT + 3) +#define __NR_stat (__X32_SYSCALL_BIT + 4) +#define __NR_fstat (__X32_SYSCALL_BIT + 5) +#define __NR_lstat (__X32_SYSCALL_BIT + 6) +#define __NR_poll (__X32_SYSCALL_BIT + 7) +#define __NR_lseek (__X32_SYSCALL_BIT + 8) +#define __NR_mmap (__X32_SYSCALL_BIT + 9) +#define __NR_mprotect (__X32_SYSCALL_BIT + 10) +#define __NR_munmap (__X32_SYSCALL_BIT + 11) +#define __NR_brk (__X32_SYSCALL_BIT + 12) +#define __NR_rt_sigprocmask (__X32_SYSCALL_BIT + 14) +#define __NR_pread64 (__X32_SYSCALL_BIT + 17) +#define __NR_pwrite64 (__X32_SYSCALL_BIT + 18) +#define __NR_access (__X32_SYSCALL_BIT + 21) +#define __NR_pipe (__X32_SYSCALL_BIT + 22) +#define __NR_select (__X32_SYSCALL_BIT + 23) +#define __NR_sched_yield (__X32_SYSCALL_BIT + 24) +#define __NR_mremap (__X32_SYSCALL_BIT + 25) +#define __NR_msync (__X32_SYSCALL_BIT + 26) +#define __NR_mincore (__X32_SYSCALL_BIT + 27) +#define __NR_madvise (__X32_SYSCALL_BIT + 28) +#define __NR_shmget (__X32_SYSCALL_BIT + 29) +#define __NR_shmat (__X32_SYSCALL_BIT + 30) +#define __NR_shmctl (__X32_SYSCALL_BIT + 31) +#define __NR_dup (__X32_SYSCALL_BIT + 32) +#define __NR_dup2 (__X32_SYSCALL_BIT + 33) +#define __NR_pause (__X32_SYSCALL_BIT + 34) +#define __NR_nanosleep (__X32_SYSCALL_BIT + 35) +#define __NR_getitimer (__X32_SYSCALL_BIT + 36) +#define __NR_alarm (__X32_SYSCALL_BIT + 37) +#define __NR_setitimer (__X32_SYSCALL_BIT + 38) +#define __NR_getpid (__X32_SYSCALL_BIT + 39) +#define __NR_socket (__X32_SYSCALL_BIT + 41) +#define __NR_connect (__X32_SYSCALL_BIT + 42) +#define __NR_accept (__X32_SYSCALL_BIT + 43) +#define __NR_sendto (__X32_SYSCALL_BIT + 44) +#define __NR_shutdown (__X32_SYSCALL_BIT + 48) +#define __NR_bind (__X32_SYSCALL_BIT + 49) +#define __NR_listen (__X32_SYSCALL_BIT + 50) +#define __NR_getsockname (__X32_SYSCALL_BIT + 51) +#define __NR_getpeername (__X32_SYSCALL_BIT + 52) +#define __NR_socketpair (__X32_SYSCALL_BIT + 53) +#define __NR_clone (__X32_SYSCALL_BIT + 56) +#define __NR_fork (__X32_SYSCALL_BIT + 57) +#define __NR_vfork (__X32_SYSCALL_BIT + 58) +#define __NR_exit (__X32_SYSCALL_BIT + 60) +#define __NR_wait4 (__X32_SYSCALL_BIT + 61) +#define __NR_kill (__X32_SYSCALL_BIT + 62) +#define __NR_uname (__X32_SYSCALL_BIT + 63) +#define __NR_semget (__X32_SYSCALL_BIT + 64) +#define __NR_semop (__X32_SYSCALL_BIT + 65) +#define __NR_semctl (__X32_SYSCALL_BIT + 66) +#define __NR_shmdt (__X32_SYSCALL_BIT + 67) +#define __NR_msgget (__X32_SYSCALL_BIT + 68) +#define __NR_msgsnd (__X32_SYSCALL_BIT + 69) +#define __NR_msgrcv (__X32_SYSCALL_BIT + 70) +#define __NR_msgctl (__X32_SYSCALL_BIT + 71) +#define __NR_fcntl (__X32_SYSCALL_BIT + 72) +#define __NR_flock (__X32_SYSCALL_BIT + 73) +#define __NR_fsync (__X32_SYSCALL_BIT + 74) +#define __NR_fdatasync (__X32_SYSCALL_BIT + 75) +#define __NR_truncate (__X32_SYSCALL_BIT + 76) +#define __NR_ftruncate (__X32_SYSCALL_BIT + 77) +#define __NR_getdents (__X32_SYSCALL_BIT + 78) +#define __NR_getcwd (__X32_SYSCALL_BIT + 79) +#define __NR_chdir (__X32_SYSCALL_BIT + 80) +#define __NR_fchdir (__X32_SYSCALL_BIT + 81) +#define __NR_rename (__X32_SYSCALL_BIT + 82) +#define __NR_mkdir (__X32_SYSCALL_BIT + 83) +#define __NR_rmdir (__X32_SYSCALL_BIT + 84) +#define __NR_creat (__X32_SYSCALL_BIT + 85) +#define __NR_link (__X32_SYSCALL_BIT + 86) +#define __NR_unlink (__X32_SYSCALL_BIT + 87) +#define __NR_symlink (__X32_SYSCALL_BIT + 88) +#define __NR_readlink (__X32_SYSCALL_BIT + 89) +#define __NR_chmod (__X32_SYSCALL_BIT + 90) +#define __NR_fchmod (__X32_SYSCALL_BIT + 91) +#define __NR_chown (__X32_SYSCALL_BIT + 92) +#define __NR_fchown (__X32_SYSCALL_BIT + 93) +#define __NR_lchown (__X32_SYSCALL_BIT + 94) +#define __NR_umask (__X32_SYSCALL_BIT + 95) +#define __NR_gettimeofday (__X32_SYSCALL_BIT + 96) +#define __NR_getrlimit (__X32_SYSCALL_BIT + 97) +#define __NR_getrusage (__X32_SYSCALL_BIT + 98) +#define __NR_times (__X32_SYSCALL_BIT + 100) +#define __NR_getuid (__X32_SYSCALL_BIT + 102) +#define __NR_getgid (__X32_SYSCALL_BIT + 104) +#define __NR_setuid (__X32_SYSCALL_BIT + 105) +#define __NR_setgid (__X32_SYSCALL_BIT + 106) +#define __NR_geteuid (__X32_SYSCALL_BIT + 107) +#define __NR_getegid (__X32_SYSCALL_BIT + 108) +#define __NR_setpgid (__X32_SYSCALL_BIT + 109) +#define __NR_getppid (__X32_SYSCALL_BIT + 110) +#define __NR_getpgrp (__X32_SYSCALL_BIT + 111) +#define __NR_setsid (__X32_SYSCALL_BIT + 112) +#define __NR_setreuid (__X32_SYSCALL_BIT + 113) +#define __NR_setregid (__X32_SYSCALL_BIT + 114) +#define __NR_getgroups (__X32_SYSCALL_BIT + 115) +#define __NR_setgroups (__X32_SYSCALL_BIT + 116) +#define __NR_setresuid (__X32_SYSCALL_BIT + 117) +#define __NR_getresuid (__X32_SYSCALL_BIT + 118) +#define __NR_setresgid (__X32_SYSCALL_BIT + 119) +#define __NR_getresgid (__X32_SYSCALL_BIT + 120) +#define __NR_getpgid (__X32_SYSCALL_BIT + 121) +#define __NR_getsid (__X32_SYSCALL_BIT + 124) +#define __NR_rt_sigsuspend (__X32_SYSCALL_BIT + 130) +#define __NR_utime (__X32_SYSCALL_BIT + 132) +#define __NR_mknod (__X32_SYSCALL_BIT + 133) +#define __NR_personality (__X32_SYSCALL_BIT + 135) +#define __NR_ustat (__X32_SYSCALL_BIT + 136) +#define __NR_statfs (__X32_SYSCALL_BIT + 137) +#define __NR_fstatfs (__X32_SYSCALL_BIT + 138) +#define __NR_sysfs (__X32_SYSCALL_BIT + 139) +#define __NR_getpriority (__X32_SYSCALL_BIT + 140) +#define __NR_setpriority (__X32_SYSCALL_BIT + 141) +#define __NR_sched_setparam (__X32_SYSCALL_BIT + 142) +#define __NR_sched_getparam (__X32_SYSCALL_BIT + 143) +#define __NR_sched_setscheduler (__X32_SYSCALL_BIT + 144) +#define __NR_sched_getscheduler (__X32_SYSCALL_BIT + 145) +#define __NR_sched_get_priority_max (__X32_SYSCALL_BIT + 146) +#define __NR_sched_get_priority_min (__X32_SYSCALL_BIT + 147) +#define __NR_sched_rr_get_interval (__X32_SYSCALL_BIT + 148) +#define __NR_mlock (__X32_SYSCALL_BIT + 149) +#define __NR_munlock (__X32_SYSCALL_BIT + 150) +#define __NR_mlockall (__X32_SYSCALL_BIT + 151) +#define __NR_munlockall (__X32_SYSCALL_BIT + 152) +#define __NR_modify_ldt (__X32_SYSCALL_BIT + 154) +#define __NR_prctl (__X32_SYSCALL_BIT + 157) +#define __NR_arch_prctl (__X32_SYSCALL_BIT + 158) +#define __NR_adjtimex (__X32_SYSCALL_BIT + 159) +#define __NR_setrlimit (__X32_SYSCALL_BIT + 160) +#define __NR_chroot (__X32_SYSCALL_BIT + 161) +#define __NR_sync (__X32_SYSCALL_BIT + 162) +#define __NR_acct (__X32_SYSCALL_BIT + 163) +#define __NR_settimeofday (__X32_SYSCALL_BIT + 164) +#define __NR_sethostname (__X32_SYSCALL_BIT + 170) +#define __NR_setdomainname (__X32_SYSCALL_BIT + 171) +#define __NR_iopl (__X32_SYSCALL_BIT + 172) +#define __NR_ioperm (__X32_SYSCALL_BIT + 173) +#define __NR_quotactl (__X32_SYSCALL_BIT + 179) +#define __NR_getpmsg (__X32_SYSCALL_BIT + 181) +#define __NR_putpmsg (__X32_SYSCALL_BIT + 182) +#define __NR_afs_syscall (__X32_SYSCALL_BIT + 183) +#define __NR_tuxcall (__X32_SYSCALL_BIT + 184) +#define __NR_security (__X32_SYSCALL_BIT + 185) +#define __NR_gettid (__X32_SYSCALL_BIT + 186) +#define __NR_tkill (__X32_SYSCALL_BIT + 200) +#define __NR_time (__X32_SYSCALL_BIT + 201) +#define __NR_futex (__X32_SYSCALL_BIT + 202) +#define __NR_sched_setaffinity (__X32_SYSCALL_BIT + 203) +#define __NR_sched_getaffinity (__X32_SYSCALL_BIT + 204) +#define __NR_io_destroy (__X32_SYSCALL_BIT + 207) +#define __NR_io_getevents (__X32_SYSCALL_BIT + 208) +#define __NR_io_cancel (__X32_SYSCALL_BIT + 210) +#define __NR_lookup_dcookie (__X32_SYSCALL_BIT + 212) +#define __NR_getdents64 (__X32_SYSCALL_BIT + 217) +#define __NR_set_tid_address (__X32_SYSCALL_BIT + 218) +#define __NR_restart_syscall (__X32_SYSCALL_BIT + 219) +#define __NR_semtimedop (__X32_SYSCALL_BIT + 220) +#define __NR_fadvise64 (__X32_SYSCALL_BIT + 221) +#define __NR_timer_settime (__X32_SYSCALL_BIT + 223) +#define __NR_timer_gettime (__X32_SYSCALL_BIT + 224) +#define __NR_timer_getoverrun (__X32_SYSCALL_BIT + 225) +#define __NR_timer_delete (__X32_SYSCALL_BIT + 226) +#define __NR_clock_settime (__X32_SYSCALL_BIT + 227) +#define __NR_clock_gettime (__X32_SYSCALL_BIT + 228) +#define __NR_clock_getres (__X32_SYSCALL_BIT + 229) +#define __NR_clock_nanosleep (__X32_SYSCALL_BIT + 230) +#define __NR_exit_group (__X32_SYSCALL_BIT + 231) +#define __NR_tgkill (__X32_SYSCALL_BIT + 234) +#define __NR_utimes (__X32_SYSCALL_BIT + 235) +#define __NR_mbind (__X32_SYSCALL_BIT + 237) +#define __NR_set_mempolicy (__X32_SYSCALL_BIT + 238) +#define __NR_get_mempolicy (__X32_SYSCALL_BIT + 239) +#define __NR_mq_open (__X32_SYSCALL_BIT + 240) +#define __NR_mq_unlink (__X32_SYSCALL_BIT + 241) +#define __NR_mq_timedsend (__X32_SYSCALL_BIT + 242) +#define __NR_mq_timedreceive (__X32_SYSCALL_BIT + 243) +#define __NR_mq_getsetattr (__X32_SYSCALL_BIT + 245) +#define __NR_add_key (__X32_SYSCALL_BIT + 248) +#define __NR_request_key (__X32_SYSCALL_BIT + 249) +#define __NR_keyctl (__X32_SYSCALL_BIT + 250) +#define __NR_ioprio_set (__X32_SYSCALL_BIT + 251) +#define __NR_ioprio_get (__X32_SYSCALL_BIT + 252) +#define __NR_migrate_pages (__X32_SYSCALL_BIT + 256) +#define __NR_openat (__X32_SYSCALL_BIT + 257) +#define __NR_mkdirat (__X32_SYSCALL_BIT + 258) +#define __NR_mknodat (__X32_SYSCALL_BIT + 259) +#define __NR_fchownat (__X32_SYSCALL_BIT + 260) +#define __NR_futimesat (__X32_SYSCALL_BIT + 261) +#define __NR_newfstatat (__X32_SYSCALL_BIT + 262) +#define __NR_unlinkat (__X32_SYSCALL_BIT + 263) +#define __NR_renameat (__X32_SYSCALL_BIT + 264) +#define __NR_linkat (__X32_SYSCALL_BIT + 265) +#define __NR_symlinkat (__X32_SYSCALL_BIT + 266) +#define __NR_readlinkat (__X32_SYSCALL_BIT + 267) +#define __NR_fchmodat (__X32_SYSCALL_BIT + 268) +#define __NR_faccessat (__X32_SYSCALL_BIT + 269) +#define __NR_pselect6 (__X32_SYSCALL_BIT + 270) +#define __NR_ppoll (__X32_SYSCALL_BIT + 271) +#define __NR_sync_file_range (__X32_SYSCALL_BIT + 277) +#define __NR_utimensat (__X32_SYSCALL_BIT + 280) +#define __NR_fallocate (__X32_SYSCALL_BIT + 285) +#define __NR_accept4 (__X32_SYSCALL_BIT + 288) +#define __NR_dup3 (__X32_SYSCALL_BIT + 292) +#define __NR_pipe2 (__X32_SYSCALL_BIT + 293) +#define __NR_perf_event_open (__X32_SYSCALL_BIT + 298) +#define __NR_prlimit64 (__X32_SYSCALL_BIT + 302) +#define __NR_name_to_handle_at (__X32_SYSCALL_BIT + 303) +#define __NR_open_by_handle_at (__X32_SYSCALL_BIT + 304) +#define __NR_getcpu (__X32_SYSCALL_BIT + 309) +#define __NR_kcmp (__X32_SYSCALL_BIT + 312) +#define __NR_sched_setattr (__X32_SYSCALL_BIT + 314) +#define __NR_sched_getattr (__X32_SYSCALL_BIT + 315) +#define __NR_renameat2 (__X32_SYSCALL_BIT + 316) +#define __NR_seccomp (__X32_SYSCALL_BIT + 317) +#define __NR_getrandom (__X32_SYSCALL_BIT + 318) +#define __NR_memfd_create (__X32_SYSCALL_BIT + 319) +#define __NR_kexec_file_load (__X32_SYSCALL_BIT + 320) +#define __NR_bpf (__X32_SYSCALL_BIT + 321) +#define __NR_userfaultfd (__X32_SYSCALL_BIT + 323) +#define __NR_membarrier (__X32_SYSCALL_BIT + 324) +#define __NR_mlock2 (__X32_SYSCALL_BIT + 325) +#define __NR_copy_file_range (__X32_SYSCALL_BIT + 326) + +#define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512) +#define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) +#define __NR_ioctl (__X32_SYSCALL_BIT + 514) +#define __NR_readv (__X32_SYSCALL_BIT + 515) +#define __NR_writev (__X32_SYSCALL_BIT + 516) +#define __NR_recvfrom (__X32_SYSCALL_BIT + 517) +#define __NR_sendmsg (__X32_SYSCALL_BIT + 518) +#define __NR_recvmsg (__X32_SYSCALL_BIT + 519) +#define __NR_execve (__X32_SYSCALL_BIT + 520) +#define __NR_ptrace (__X32_SYSCALL_BIT + 521) +#define __NR_rt_sigpending (__X32_SYSCALL_BIT + 522) +#define __NR_rt_sigtimedwait (__X32_SYSCALL_BIT + 523) +#define __NR_rt_sigqueueinfo (__X32_SYSCALL_BIT + 524) +#define __NR_sigaltstack (__X32_SYSCALL_BIT + 525) +#define __NR_timer_create (__X32_SYSCALL_BIT + 526) +#define __NR_mq_notify (__X32_SYSCALL_BIT + 527) +#define __NR_kexec_load (__X32_SYSCALL_BIT + 528) +#define __NR_waitid (__X32_SYSCALL_BIT + 529) +#define __NR_set_robust_list (__X32_SYSCALL_BIT + 530) +#define __NR_get_robust_list (__X32_SYSCALL_BIT + 531) +#define __NR_move_pages (__X32_SYSCALL_BIT + 533) +#define __NR_preadv (__X32_SYSCALL_BIT + 534) +#define __NR_pwritev (__X32_SYSCALL_BIT + 535) +#define __NR_rt_tgsigqueueinfo (__X32_SYSCALL_BIT + 536) +#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537) +#define __NR_sendmmsg (__X32_SYSCALL_BIT + 538) +#define __NR_setsockopt (__X32_SYSCALL_BIT + 541) +#define __NR_getsockopt (__X32_SYSCALL_BIT + 542) +#define __NR_io_setup (__X32_SYSCALL_BIT + 543) +#define __NR_io_submit (__X32_SYSCALL_BIT + 544) +#define __NR_execveat (__X32_SYSCALL_BIT + 545) + +#undef __NR_fstatat +#undef __NR_pread +#undef __NR_pwrite +#undef __NR_getdents +#define __NR_fstatat __NR_newfstatat +#define __NR_pread __NR_pread64 +#define __NR_pwrite __NR_pwrite64 +#define __NR_getdents __NR_getdents64 +#define __NR_fadvise __NR_fadvise64 + +/* Repeat with SYS_ prefix */ + +#define SYS_read __NR_read +#define SYS_write __NR_write +#define SYS_open __NR_open +#define SYS_close __NR_close +#define SYS_stat __NR_stat +#define SYS_fstat __NR_fstat +#define SYS_lstat __NR_lstat +#define SYS_poll __NR_poll +#define SYS_lseek __NR_lseek +#define SYS_mmap __NR_mmap +#define SYS_mprotect __NR_mprotect +#define SYS_munmap __NR_munmap +#define SYS_brk __NR_brk +#define SYS_rt_sigprocmask __NR_rt_sigprocmask +#define SYS_pread64 __NR_pread64 +#define SYS_pwrite64 __NR_pwrite64 +#define SYS_access __NR_access +#define SYS_pipe __NR_pipe +#define SYS_select __NR_select +#define SYS_sched_yield __NR_sched_yield +#define SYS_mremap __NR_mremap +#define SYS_msync __NR_msync +#define SYS_mincore __NR_mincore +#define SYS_madvise __NR_madvise +#define SYS_shmget __NR_shmget +#define SYS_shmat __NR_shmat +#define SYS_shmctl __NR_shmctl +#define SYS_dup __NR_dup +#define SYS_dup2 __NR_dup2 +#define SYS_pause __NR_pause +#define SYS_nanosleep __NR_nanosleep +#define SYS_getitimer __NR_getitimer +#define SYS_alarm __NR_alarm +#define SYS_setitimer __NR_setitimer +#define SYS_getpid __NR_getpid +#define SYS_socket __NR_socket +#define SYS_connect __NR_connect +#define SYS_accept __NR_accept +#define SYS_sendto __NR_sendto +#define SYS_shutdown __NR_shutdown +#define SYS_bind __NR_bind +#define SYS_listen __NR_listen +#define SYS_getsockname __NR_getsockname +#define SYS_getpeername __NR_getpeername +#define SYS_socketpair __NR_socketpair +#define SYS_clone __NR_clone +#define SYS_fork __NR_fork +#define SYS_vfork __NR_vfork +#define SYS_exit __NR_exit +#define SYS_wait4 __NR_wait4 +#define SYS_kill __NR_kill +#define SYS_uname __NR_uname +#define SYS_semget __NR_semget +#define SYS_semop __NR_semop +#define SYS_semctl __NR_semctl +#define SYS_shmdt __NR_shmdt +#define SYS_msgget __NR_msgget +#define SYS_msgsnd __NR_msgsnd +#define SYS_msgrcv __NR_msgrcv +#define SYS_msgctl __NR_msgctl +#define SYS_fcntl __NR_fcntl +#define SYS_flock __NR_flock +#define SYS_fsync __NR_fsync +#define SYS_fdatasync __NR_fdatasync +#define SYS_truncate __NR_truncate +#define SYS_ftruncate __NR_ftruncate +#define SYS_getdents __NR_getdents +#define SYS_getcwd __NR_getcwd +#define SYS_chdir __NR_chdir +#define SYS_fchdir __NR_fchdir +#define SYS_rename __NR_rename +#define SYS_mkdir __NR_mkdir +#define SYS_rmdir __NR_rmdir +#define SYS_creat __NR_creat +#define SYS_link __NR_link +#define SYS_unlink __NR_unlink +#define SYS_symlink __NR_symlink +#define SYS_readlink __NR_readlink +#define SYS_chmod __NR_chmod +#define SYS_fchmod __NR_fchmod +#define SYS_chown __NR_chown +#define SYS_fchown __NR_fchown +#define SYS_lchown __NR_lchown +#define SYS_umask __NR_umask +#define SYS_gettimeofday __NR_gettimeofday +#define SYS_getrlimit __NR_getrlimit +#define SYS_getrusage __NR_getrusage +#define SYS_times __NR_times +#define SYS_getuid __NR_getuid +#define SYS_getgid __NR_getgid +#define SYS_setuid __NR_setuid +#define SYS_setgid __NR_setgid +#define SYS_geteuid __NR_geteuid +#define SYS_getegid __NR_getegid +#define SYS_setpgid __NR_setpgid +#define SYS_getppid __NR_getppid +#define SYS_getpgrp __NR_getpgrp +#define SYS_setsid __NR_setsid +#define SYS_setreuid __NR_setreuid +#define SYS_setregid __NR_setregid +#define SYS_getgroups __NR_getgroups +#define SYS_setgroups __NR_setgroups +#define SYS_setresuid __NR_setresuid +#define SYS_getresuid __NR_getresuid +#define SYS_setresgid __NR_setresgid +#define SYS_getresgid __NR_getresgid +#define SYS_getpgid __NR_getpgid +#define SYS_getsid __NR_getsid +#define SYS_rt_sigsuspend __NR_rt_sigsuspend +#define SYS_utime __NR_utime +#define SYS_mknod __NR_mknod +#define SYS_personality __NR_personality +#define SYS_ustat __NR_ustat +#define SYS_statfs __NR_statfs +#define SYS_fstatfs __NR_fstatfs +#define SYS_sysfs __NR_sysfs +#define SYS_getpriority __NR_getpriority +#define SYS_setpriority __NR_setpriority +#define SYS_sched_setparam __NR_sched_setparam +#define SYS_sched_getparam __NR_sched_getparam +#define SYS_sched_setscheduler __NR_sched_setscheduler +#define SYS_sched_getscheduler __NR_sched_getscheduler +#define SYS_sched_get_priority_max __NR_sched_get_priority_max +#define SYS_sched_get_priority_min __NR_sched_get_priority_min +#define SYS_sched_rr_get_interval __NR_sched_rr_get_interval +#define SYS_mlock __NR_mlock +#define SYS_munlock __NR_munlock +#define SYS_mlockall __NR_mlockall +#define SYS_munlockall __NR_munlockall +#define SYS_modify_ldt __NR_modify_ldt +#define SYS_prctl __NR_prctl +#define SYS_arch_prctl __NR_arch_prctl +#define SYS_adjtimex __NR_adjtimex +#define SYS_setrlimit __NR_setrlimit +#define SYS_chroot __NR_chroot +#define SYS_sync __NR_sync +#define SYS_acct __NR_acct +#define SYS_settimeofday __NR_settimeofday +#define SYS_sethostname __NR_sethostname +#define SYS_setdomainname __NR_setdomainname +#define SYS_iopl __NR_iopl +#define SYS_ioperm __NR_ioperm +#define SYS_quotactl __NR_quotactl +#define SYS_getpmsg __NR_getpmsg +#define SYS_putpmsg __NR_putpmsg +#define SYS_afs_syscall __NR_afs_syscall +#define SYS_tuxcall __NR_tuxcall +#define SYS_security __NR_security +#define SYS_gettid __NR_gettid +#define SYS_tkill __NR_tkill +#define SYS_time __NR_time +#define SYS_futex __NR_futex +#define SYS_sched_setaffinity __NR_sched_setaffinity +#define SYS_sched_getaffinity __NR_sched_getaffinity +#define SYS_io_destroy __NR_io_destroy +#define SYS_io_getevents __NR_io_getevents +#define SYS_io_cancel __NR_io_cancel +#define SYS_lookup_dcookie __NR_lookup_dcookie +#define SYS_getdents64 __NR_getdents64 +#define SYS_set_tid_address __NR_set_tid_address +#define SYS_restart_syscall __NR_restart_syscall +#define SYS_semtimedop __NR_semtimedop +#define SYS_fadvise64 __NR_fadvise64 +#define SYS_timer_settime __NR_timer_settime +#define SYS_timer_gettime __NR_timer_gettime +#define SYS_timer_getoverrun __NR_timer_getoverrun +#define SYS_timer_delete __NR_timer_delete +#define SYS_clock_settime __NR_clock_settime +#define SYS_clock_gettime __NR_clock_gettime +#define SYS_clock_getres __NR_clock_getres +#define SYS_clock_nanosleep __NR_clock_nanosleep +#define SYS_exit_group __NR_exit_group +#define SYS_tgkill __NR_tgkill +#define SYS_utimes __NR_utimes +#define SYS_mbind __NR_mbind +#define SYS_set_mempolicy __NR_set_mempolicy +#define SYS_get_mempolicy __NR_get_mempolicy +#define SYS_mq_open __NR_mq_open +#define SYS_mq_unlink __NR_mq_unlink +#define SYS_mq_timedsend __NR_mq_timedsend +#define SYS_mq_timedreceive __NR_mq_timedreceive +#define SYS_mq_getsetattr __NR_mq_getsetattr +#define SYS_add_key __NR_add_key +#define SYS_request_key __NR_request_key +#define SYS_keyctl __NR_keyctl +#define SYS_ioprio_set __NR_ioprio_set +#define SYS_ioprio_get __NR_ioprio_get +#define SYS_migrate_pages __NR_migrate_pages +#define SYS_openat __NR_openat +#define SYS_mkdirat __NR_mkdirat +#define SYS_mknodat __NR_mknodat +#define SYS_fchownat __NR_fchownat +#define SYS_futimesat __NR_futimesat +#define SYS_newfstatat __NR_newfstatat +#define SYS_unlinkat __NR_unlinkat +#define SYS_renameat __NR_renameat +#define SYS_linkat __NR_linkat +#define SYS_symlinkat __NR_symlinkat +#define SYS_readlinkat __NR_readlinkat +#define SYS_fchmodat __NR_fchmodat +#define SYS_faccessat __NR_faccessat +#define SYS_pselect6 __NR_pselect6 +#define SYS_ppoll __NR_ppoll +#define SYS_sync_file_range __NR_sync_file_range +#define SYS_utimensat __NR_utimensat +#define SYS_fallocate __NR_fallocate +#define SYS_accept4 __NR_accept4 +#define SYS_dup3 __NR_dup3 +#define SYS_pipe2 __NR_pipe2 +#define SYS_perf_event_open __NR_perf_event_open +#define SYS_prlimit64 __NR_prlimit64 +#define SYS_name_to_handle_at __NR_name_to_handle_at +#define SYS_open_by_handle_at __NR_open_by_handle_at +#define SYS_getcpu __NR_getcpu +#define SYS_kcmp __NR_kcmp +#define SYS_sched_setattr __NR_sched_setattr +#define SYS_sched_getattr __NR_sched_getattr +#define SYS_renameat2 __NR_renameat2 +#define SYS_seccomp __NR_seccomp +#define SYS_getrandom __NR_getrandom +#define SYS_memfd_create __NR_memfd_create +#define SYS_kexec_file_load __NR_kexec_file_load +#define SYS_bpf __NR_bpf +#define SYS_userfaultfd __NR_userfaultfd +#define SYS_membarrier __NR_membarrier +#define SYS_mlock2 __NR_mlock2 +#define SYS_copy_file_range __NR_copy_file_range + +#define SYS_rt_sigaction __NR_rt_sigaction +#define SYS_rt_sigreturn __NR_rt_sigreturn +#define SYS_ioctl __NR_ioctl +#define SYS_readv __NR_readv +#define SYS_writev __NR_writev +#define SYS_recvfrom __NR_recvfrom +#define SYS_sendmsg __NR_sendmsg +#define SYS_recvmsg __NR_recvmsg +#define SYS_execve __NR_execve +#define SYS_ptrace __NR_ptrace +#define SYS_rt_sigpending __NR_rt_sigpending +#define SYS_rt_sigtimedwait __NR_rt_sigtimedwait +#define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo +#define SYS_sigaltstack __NR_sigaltstack +#define SYS_timer_create __NR_timer_create +#define SYS_mq_notify __NR_mq_notify +#define SYS_kexec_load __NR_kexec_load +#define SYS_waitid __NR_waitid +#define SYS_set_robust_list __NR_set_robust_list +#define SYS_get_robust_list __NR_get_robust_list +#define SYS_move_pages __NR_move_pages +#define SYS_preadv __NR_preadv +#define SYS_pwritev __NR_pwritev +#define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo +#define SYS_recvmmsg __NR_recvmmsg +#define SYS_sendmmsg __NR_sendmmsg +#define SYS_setsockopt __NR_setsockopt +#define SYS_getsockopt __NR_getsockopt +#define SYS_io_setup __NR_io_setup +#define SYS_io_submit __NR_io_submit +#define SYS_execveat __NR_execveat + +#undef SYS_fstatat +#undef SYS_pread +#undef SYS_pwrite +#undef SYS_getdents +#define SYS_fstatat SYS_newfstatat +#define SYS_pread SYS_pread64 +#define SYS_pwrite SYS_pwrite64 +#define SYS_getdents SYS_getdents64 +#define SYS_fadvise SYS_fadvise64 diff --git a/third_party/ulib/musl/arch/x32/bits/user.h b/third_party/ulib/musl/arch/x32/bits/user.h new file mode 100644 index 000000000..ea1f73d86 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/bits/user.h @@ -0,0 +1,41 @@ +#undef __WORDSIZE +#define __WORDSIZE 64 + +typedef struct user_fpregs_struct { + uint16_t cwd, swd, ftw, fop; + uint64_t rip, rdp; + uint32_t mxcsr, mxcr_mask; + uint32_t st_space[32], xmm_space[64], padding[24]; +} elf_fpregset_t; + +struct user_regs_struct { + unsigned long r15, r14, r13, r12, rbp, rbx, r11, r10, r9, r8; + unsigned long rax, rcx, rdx, rsi, rdi, orig_rax, rip; + unsigned long cs, eflags, rsp, ss, fs_base, gs_base, ds, es, fs, gs; +}; +#define ELF_NGREG 27 +typedef unsigned long long elf_greg_t, elf_gregset_t[ELF_NGREG]; + +struct user { + struct user_regs_struct regs; + int u_fpvalid; + struct user_fpregs_struct i387; + unsigned long u_tsize; + unsigned long u_dsize; + unsigned long u_ssize; + unsigned long start_code; + unsigned long start_stack; + long signal; + int reserved; + struct user_regs_struct* u_ar0; + struct user_fpregs_struct* u_fpstate; + unsigned long magic; + char u_comm[32]; + unsigned long u_debugreg[8]; +}; + +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) diff --git a/third_party/ulib/musl/arch/x32/crt_arch.h b/third_party/ulib/musl/arch/x32/crt_arch.h new file mode 100644 index 000000000..820c9ae7f --- /dev/null +++ b/third_party/ulib/musl/arch/x32/crt_arch.h @@ -0,0 +1,9 @@ +__asm__(".text \n" + ".global " START " \n" START ": \n" + " xor %rbp,%rbp \n" + " mov %rsp,%rdi \n" + ".weak _DYNAMIC \n" + ".hidden _DYNAMIC \n" + " lea _DYNAMIC(%rip),%rsi \n" + " andq $-16,%rsp \n" + " call " START "_c \n"); diff --git a/third_party/ulib/musl/arch/x32/pthread_arch.h b/third_party/ulib/musl/arch/x32/pthread_arch.h new file mode 100644 index 000000000..46568b836 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/pthread_arch.h @@ -0,0 +1,5 @@ +#define TP_ADJ(p) (p) + +#define MC_PC gregs[REG_RIP] + +#define CANARY canary2 diff --git a/third_party/ulib/musl/arch/x32/reloc.h b/third_party/ulib/musl/arch/x32/reloc.h new file mode 100644 index 000000000..1cf06e389 --- /dev/null +++ b/third_party/ulib/musl/arch/x32/reloc.h @@ -0,0 +1,36 @@ +#define LDSO_ARCH "x32" + +/* FIXME: x32 is very strange in its use of 64-bit relocation types in + * a 32-bit environment. As long as the memory at reloc_addr is + * zero-filled prior to relocations, just treating 64-bit relocations + * as operating on 32-bit slots should be fine, but this should be + * checked. In particular, R_X86_64_64, R_X86_64_DTPOFF64, and + * R_X86_64_TPOFF64 may need checking. */ + +/* The R_X86_64_64, R_X86_64_DTPOFF32, and R_X86_64_TPOFF32 reloc types + * were previously mapped in the switch table form of this file; however, + * they do not seem to be used/usable for anything. If needed, new + * mappings will have to be added. */ + +#define REL_SYMBOLIC R_X86_64_32 +#define REL_OFFSET R_X86_64_PC32 +#define REL_GOT R_X86_64_GLOB_DAT +#define REL_PLT R_X86_64_JUMP_SLOT +#define REL_RELATIVE R_X86_64_RELATIVE +#define REL_COPY R_X86_64_COPY +#define REL_DTPMOD R_X86_64_DTPMOD64 +#define REL_DTPOFF R_X86_64_DTPOFF64 +#define REL_TPOFF R_X86_64_TPOFF64 + +#define CRTJMP(pc, sp) \ + __asm__ __volatile__("mov %1,%%esp ; jmp *%0" \ + : \ + : "r"((uint64_t)(uintptr_t)pc), "r"(sp) \ + : "memory") + +#define GETFUNCSYM(fp, sym, got) \ + __asm__(".hidden " #sym "\n" \ + " lea " #sym "(%%rip),%0\n" \ + : "=r"(*fp) \ + : \ + : "memory") diff --git a/third_party/ulib/musl/arch/x86_64/atomic_arch.h b/third_party/ulib/musl/arch/x86_64/atomic_arch.h new file mode 100644 index 000000000..cc91cbe5c --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/atomic_arch.h @@ -0,0 +1,82 @@ +#define a_cas a_cas +static inline int a_cas(volatile int* p, int t, int s) { + __asm__ __volatile__("lock ; cmpxchg %3, %1" : "=a"(t), "=m"(*p) : "a"(t), "r"(s) : "memory"); + return t; +} + +#define a_cas_p a_cas_p +static inline void* a_cas_p(volatile void* p, void* t, void* s) { + __asm__("lock ; cmpxchg %3, %1" + : "=a"(t), "=m"(*(void* volatile*)p) + : "a"(t), "r"(s) + : "memory"); + return t; +} + +#define a_swap a_swap +static inline int a_swap(volatile int* p, int v) { + __asm__ __volatile__("xchg %0, %1" : "=r"(v), "=m"(*p) : "0"(v) : "memory"); + return v; +} + +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int* p, int v) { + __asm__ __volatile__("lock ; xadd %0, %1" : "=r"(v), "=m"(*p) : "0"(v) : "memory"); + return v; +} + +#define a_and a_and +static inline void a_and(volatile int* p, int v) { + __asm__ __volatile__("lock ; and %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_or a_or +static inline void a_or(volatile int* p, int v) { + __asm__ __volatile__("lock ; or %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_and_64 a_and_64 +static inline void a_and_64(volatile uint64_t* p, uint64_t v) { + __asm__ __volatile("lock ; and %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_or_64 a_or_64 +static inline void a_or_64(volatile uint64_t* p, uint64_t v) { + __asm__ __volatile__("lock ; or %1, %0" : "=m"(*p) : "r"(v) : "memory"); +} + +#define a_inc a_inc +static inline void a_inc(volatile int* p) { + __asm__ __volatile__("lock ; incl %0" : "=m"(*p) : "m"(*p) : "memory"); +} + +#define a_dec a_dec +static inline void a_dec(volatile int* p) { + __asm__ __volatile__("lock ; decl %0" : "=m"(*p) : "m"(*p) : "memory"); +} + +#define a_store a_store +static inline void a_store(volatile int* p, int x) { + __asm__ __volatile__("mov %1, %0 ; lock ; orl $0,(%%rsp)" : "=m"(*p) : "r"(x) : "memory"); +} + +#define a_barrier a_barrier +static inline void a_barrier(void) { + __asm__ __volatile__("" : : : "memory"); +} + +#define a_spin a_spin +static inline void a_spin(void) { + __asm__ __volatile__("pause" : : : "memory"); +} + +#define a_crash a_crash +static inline void a_crash(void) { + __asm__ __volatile__("hlt" : : : "memory"); +} + +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) { + __asm__("bsf %1,%0" : "=r"(x) : "r"(x)); + return x; +} diff --git a/third_party/ulib/musl/arch/x86_64/bits/alltypes.h.in b/third_party/ulib/musl/arch/x86_64/bits/alltypes.h.in new file mode 100644 index 000000000..dc551d472 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/alltypes.h.in @@ -0,0 +1,31 @@ +#define _Addr long +#define _Int64 long +#define _Reg long + +TYPEDEF __builtin_va_list va_list; +TYPEDEF __builtin_va_list __isoc_va_list; + +#ifndef __cplusplus +TYPEDEF int wchar_t; +#endif + +#if defined(__FLT_EVAL_METHOD__) && __FLT_EVAL_METHOD__ == 2 +TYPEDEF long double float_t; +TYPEDEF long double double_t; +#else +TYPEDEF float float_t; +TYPEDEF double double_t; +#endif + +TYPEDEF struct { long long __ll; long double __ld; } max_align_t; + +TYPEDEF long time_t; +TYPEDEF long suseconds_t; + +TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t; +TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t; +TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t; +TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t; +TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t; diff --git a/third_party/ulib/musl/arch/x86_64/bits/endian.h b/third_party/ulib/musl/arch/x86_64/bits/endian.h new file mode 100644 index 000000000..172c338f5 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/endian.h @@ -0,0 +1 @@ +#define __BYTE_ORDER __LITTLE_ENDIAN diff --git a/third_party/ulib/musl/arch/x86_64/bits/fcntl.h b/third_party/ulib/musl/arch/x86_64/bits/fcntl.h new file mode 100644 index 000000000..c3fca266e --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/fcntl.h @@ -0,0 +1,40 @@ +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_LARGEFILE 0 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020200000 +#define O_NDELAY O_NONBLOCK + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 diff --git a/third_party/ulib/musl/arch/x86_64/bits/fenv.h b/third_party/ulib/musl/arch/x86_64/bits/fenv.h new file mode 100644 index 000000000..5cea203ee --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/fenv.h @@ -0,0 +1,34 @@ +#define FE_INVALID 1 +#define __FE_DENORM 2 +#define FE_DIVBYZERO 4 +#define FE_OVERFLOW 8 +#define FE_UNDERFLOW 16 +#define FE_INEXACT 32 + +#define FE_ALL_EXCEPT 63 + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xc00 + +typedef unsigned short fexcept_t; + +typedef struct { + unsigned short __control_word; + unsigned short __unused1; + unsigned short __status_word; + unsigned short __unused2; + unsigned short __tags; + unsigned short __unused3; + unsigned int __eip; + unsigned short __cs_selector; + unsigned int __opcode : 11; + unsigned int __unused4 : 5; + unsigned int __data_offset; + unsigned short __data_selector; + unsigned short __unused5; + unsigned int __mxcsr; +} fenv_t; + +#define FE_DFL_ENV ((const fenv_t*)-1) diff --git a/third_party/ulib/musl/arch/x86_64/bits/float.h b/third_party/ulib/musl/arch/x86_64/bits/float.h new file mode 100644 index 000000000..f935e3435 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/float.h @@ -0,0 +1,20 @@ +#ifdef __FLT_EVAL_METHOD__ +#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#else +#define FLT_EVAL_METHOD 0 +#endif + +#define LDBL_TRUE_MIN 3.6451995318824746025e-4951L +#define LDBL_MIN 3.3621031431120935063e-4932L +#define LDBL_MAX 1.1897314953572317650e+4932L +#define LDBL_EPSILON 1.0842021724855044340e-19L + +#define LDBL_MANT_DIG 64 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 18 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 21 diff --git a/third_party/ulib/musl/arch/x86_64/bits/io.h b/third_party/ulib/musl/arch/x86_64/bits/io.h new file mode 100644 index 000000000..9ad19b80c --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/io.h @@ -0,0 +1,53 @@ +static __inline void outb(unsigned char __val, unsigned short __port) { + __asm__ volatile("outb %0,%1" : : "a"(__val), "dN"(__port)); +} + +static __inline void outw(unsigned short __val, unsigned short __port) { + __asm__ volatile("outw %0,%1" : : "a"(__val), "dN"(__port)); +} + +static __inline void outl(unsigned int __val, unsigned short __port) { + __asm__ volatile("outl %0,%1" : : "a"(__val), "dN"(__port)); +} + +static __inline unsigned char inb(unsigned short __port) { + unsigned char __val; + __asm__ volatile("inb %1,%0" : "=a"(__val) : "dN"(__port)); + return __val; +} + +static __inline unsigned short inw(unsigned short __port) { + unsigned short __val; + __asm__ volatile("inw %1,%0" : "=a"(__val) : "dN"(__port)); + return __val; +} + +static __inline unsigned int inl(unsigned short __port) { + unsigned int __val; + __asm__ volatile("inl %1,%0" : "=a"(__val) : "dN"(__port)); + return __val; +} + +static __inline void outsb(unsigned short __port, const void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; outsb" : "+S"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void outsw(unsigned short __port, const void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; outsw" : "+S"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void outsl(unsigned short __port, const void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; outsl" : "+S"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void insb(unsigned short __port, void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; insb" : "+D"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void insw(unsigned short __port, void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; insw" : "+D"(__buf), "+c"(__n) : "d"(__port)); +} + +static __inline void insl(unsigned short __port, void* __buf, unsigned long __n) { + __asm__ volatile("cld; rep; insl" : "+D"(__buf), "+c"(__n) : "d"(__port)); +} diff --git a/third_party/ulib/musl/arch/x86_64/bits/ioctl.h b/third_party/ulib/musl/arch/x86_64/bits/ioctl.h new file mode 100644 index 000000000..66525bf71 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/ioctl.h @@ -0,0 +1,197 @@ +#define _IOC(a, b, c, d) (((a) << 30) | ((b) << 8) | (c) | ((d) << 16)) +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IO(a, b) _IOC(_IOC_NONE, (a), (b), 0) +#define _IOW(a, b, c) _IOC(_IOC_WRITE, (a), (b), sizeof(c)) +#define _IOR(a, b, c) _IOC(_IOC_READ, (a), (b), sizeof(c)) +#define _IOWR(a, b, c) _IOC(_IOC_READ | _IOC_WRITE, (a), (b), sizeof(c)) + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCTTYGSTRUCT 0x5426 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGPTN 0x80045430 +#define TIOCSPTLCK 0x40045431 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B + +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define TIOCGHAYESESP 0x545E +#define TIOCSHAYESESP 0x545F +#define FIOQSIZE 0x5460 + +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 +#define TIOCM_MODEM_BITS TIOCM_OUT2 + +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 +#define N_MASC 8 +#define N_R3964 9 +#define N_PROFIBUS_FDL 10 +#define N_IRDA 11 +#define N_SMSBLOCK 12 +#define N_HDLC 13 +#define N_SYNC_PPP 14 +#define N_HCI 15 + +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 + +#define SIOCADDRT 0x890B +#define SIOCDELRT 0x890C +#define SIOCRTMSG 0x890D + +#define SIOCGIFNAME 0x8910 +#define SIOCSIFLINK 0x8911 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCSIFADDR 0x8916 +#define SIOCGIFDSTADDR 0x8917 +#define SIOCSIFDSTADDR 0x8918 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCSIFBRDADDR 0x891a +#define SIOCGIFNETMASK 0x891b +#define SIOCSIFNETMASK 0x891c +#define SIOCGIFMETRIC 0x891d +#define SIOCSIFMETRIC 0x891e +#define SIOCGIFMEM 0x891f +#define SIOCSIFMEM 0x8920 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCSIFHWADDR 0x8924 +#define SIOCGIFENCAP 0x8925 +#define SIOCSIFENCAP 0x8926 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFSLAVE 0x8929 +#define SIOCSIFSLAVE 0x8930 +#define SIOCADDMULTI 0x8931 +#define SIOCDELMULTI 0x8932 +#define SIOCGIFINDEX 0x8933 +#define SIOGIFINDEX SIOCGIFINDEX +#define SIOCSIFPFLAGS 0x8934 +#define SIOCGIFPFLAGS 0x8935 +#define SIOCDIFADDR 0x8936 +#define SIOCSIFHWBROADCAST 0x8937 +#define SIOCGIFCOUNT 0x8938 + +#define SIOCGIFBR 0x8940 +#define SIOCSIFBR 0x8941 + +#define SIOCGIFTXQLEN 0x8942 +#define SIOCSIFTXQLEN 0x8943 + +#define SIOCDARP 0x8953 +#define SIOCGARP 0x8954 +#define SIOCSARP 0x8955 + +#define SIOCDRARP 0x8960 +#define SIOCGRARP 0x8961 +#define SIOCSRARP 0x8962 + +#define SIOCGIFMAP 0x8970 +#define SIOCSIFMAP 0x8971 + +#define SIOCADDDLCI 0x8980 +#define SIOCDELDLCI 0x8981 + +#define SIOCDEVPRIVATE 0x89F0 +#define SIOCPROTOPRIVATE 0x89E0 diff --git a/third_party/ulib/musl/arch/x86_64/bits/ipc.h b/third_party/ulib/musl/arch/x86_64/bits/ipc.h new file mode 100644 index 000000000..b56314305 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/ipc.h @@ -0,0 +1,13 @@ +struct ipc_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; + long __pad1; + long __pad2; +}; + +#define IPC_64 0 diff --git a/third_party/ulib/musl/arch/x86_64/bits/limits.h b/third_party/ulib/musl/arch/x86_64/bits/limits.h new file mode 100644 index 000000000..677f35b15 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/limits.h @@ -0,0 +1,8 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define PAGE_SIZE 4096 +#define LONG_BIT 64 +#endif + +#define LONG_MAX 0x7fffffffffffffffL +#define LLONG_MAX 0x7fffffffffffffffLL diff --git a/third_party/ulib/musl/arch/x86_64/bits/mman.h b/third_party/ulib/musl/arch/x86_64/bits/mman.h new file mode 100644 index 000000000..e498b6d6e --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/mman.h @@ -0,0 +1 @@ +#define MAP_32BIT 0x40 diff --git a/third_party/ulib/musl/arch/x86_64/bits/msg.h b/third_party/ulib/musl/arch/x86_64/bits/msg.h new file mode 100644 index 000000000..9b3f7e5e5 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/msg.h @@ -0,0 +1,12 @@ +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; diff --git a/third_party/ulib/musl/arch/x86_64/bits/posix.h b/third_party/ulib/musl/arch/x86_64/bits/posix.h new file mode 100644 index 000000000..8068ce98d --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/posix.h @@ -0,0 +1,2 @@ +#define _POSIX_V6_LP64_OFF64 1 +#define _POSIX_V7_LP64_OFF64 1 diff --git a/third_party/ulib/musl/arch/x86_64/bits/reg.h b/third_party/ulib/musl/arch/x86_64/bits/reg.h new file mode 100644 index 000000000..12d43c5e6 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/reg.h @@ -0,0 +1,29 @@ +#undef __WORDSIZE +#define __WORDSIZE 64 +#define R15 0 +#define R14 1 +#define R13 2 +#define R12 3 +#define RBP 4 +#define RBX 5 +#define R11 6 +#define R10 7 +#define R9 8 +#define R8 9 +#define RAX 10 +#define RCX 11 +#define RDX 12 +#define RSI 13 +#define RDI 14 +#define ORIG_RAX 15 +#define RIP 16 +#define CS 17 +#define EFLAGS 18 +#define RSP 19 +#define SS 20 +#define FS_BASE 21 +#define GS_BASE 22 +#define DS 23 +#define ES 24 +#define FS 25 +#define GS 26 diff --git a/third_party/ulib/musl/arch/x86_64/bits/setjmp.h b/third_party/ulib/musl/arch/x86_64/bits/setjmp.h new file mode 100644 index 000000000..63973a800 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/setjmp.h @@ -0,0 +1 @@ +typedef unsigned long __jmp_buf[8]; diff --git a/third_party/ulib/musl/arch/x86_64/bits/shm.h b/third_party/ulib/musl/arch/x86_64/bits/shm.h new file mode 100644 index 000000000..8bb1c74cf --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/shm.h @@ -0,0 +1,24 @@ +#define SHMLBA 4096 + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __pad1; + unsigned long __pad2; +}; + +struct shminfo { + unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4]; +}; + +struct shm_info { + int __used_ids; + unsigned long shm_tot, shm_rss, shm_swp; + unsigned long __swap_attempts, __swap_successes; +}; diff --git a/third_party/ulib/musl/arch/x86_64/bits/signal.h b/third_party/ulib/musl/arch/x86_64/bits/signal.h new file mode 100644 index 000000000..204fb2f3f --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/signal.h @@ -0,0 +1,127 @@ +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#endif + +#ifdef _GNU_SOURCE +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef long long greg_t, gregset_t[23]; +typedef struct _fpstate { + unsigned short cwd, swd, ftw, fop; + unsigned long long rip, rdp; + unsigned mxcsr, mxcr_mask; + struct { + unsigned short significand[4], exponent, padding[3]; + } _st[8]; + struct { + unsigned element[4]; + } _xmm[16]; + unsigned padding[24]; +} * fpregset_t; +struct sigcontext { + unsigned long r8, r9, r10, r11, r12, r13, r14, r15; + unsigned long rdi, rsi, rbp, rbx, rdx, rax, rcx, rsp, rip, eflags; + unsigned short cs, gs, fs, __pad0; + unsigned long err, trapno, oldmask, cr2; + struct _fpstate* fpstate; + unsigned long __reserved1[8]; +}; +typedef struct { + gregset_t gregs; + fpregset_t fpregs; + unsigned long long __reserved1[8]; +} mcontext_t; +#else +typedef struct { unsigned long __space[32]; } mcontext_t; +#endif + +struct sigaltstack { + void* ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext* uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; + unsigned long __fpregs_mem[64]; +} ucontext_t; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#endif + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS + +#define _NSIG 65 diff --git a/third_party/ulib/musl/arch/x86_64/bits/socket.h b/third_party/ulib/musl/arch/x86_64/bits/socket.h new file mode 100644 index 000000000..e92e0aa9c --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/socket.h @@ -0,0 +1,16 @@ +struct msghdr { + void* msg_name; + socklen_t msg_namelen; + struct iovec* msg_iov; + int msg_iovlen, __pad1; + void* msg_control; + socklen_t msg_controllen, __pad2; + int msg_flags; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int __pad1; + int cmsg_level; + int cmsg_type; +}; diff --git a/third_party/ulib/musl/arch/x86_64/bits/stat.h b/third_party/ulib/musl/arch/x86_64/bits/stat.h new file mode 100644 index 000000000..d3b34472f --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/stat.h @@ -0,0 +1,22 @@ +/* copied from kernel definition, but with padding replaced + * by the corresponding correctly-sized userspace types. */ + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __unused[3]; +}; diff --git a/third_party/ulib/musl/arch/x86_64/bits/stdint.h b/third_party/ulib/musl/arch/x86_64/bits/stdint.h new file mode 100644 index 000000000..7cac02579 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/stdint.h @@ -0,0 +1,20 @@ +typedef int32_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast16_t; +typedef uint32_t uint_fast32_t; + +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN + +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX + +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#define PTRDIFF_MIN INT64_MIN +#define PTRDIFF_MAX INT64_MAX +#define SIZE_MAX UINT64_MAX diff --git a/third_party/ulib/musl/arch/x86_64/bits/syscall.h b/third_party/ulib/musl/arch/x86_64/bits/syscall.h new file mode 100644 index 000000000..607eedbf5 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/syscall.h @@ -0,0 +1,166 @@ +#define SYS_write 1 +#define SYS_close 3 +#define SYS_fstat 5 +#define SYS_mmap 9 +#define SYS_mprotect 10 +#define SYS_brk 12 +#define SYS_rt_sigaction 13 +#define SYS_rt_sigprocmask 14 +#define SYS_ioctl 16 +#define SYS_pread64 17 +#define SYS_pwrite64 18 +#define SYS_readv 19 +#define SYS_writev 20 +#define SYS_sched_yield 24 +#define SYS_msync 26 +#define SYS_mincore 27 +#define SYS_madvise 28 +#define SYS_shmget 29 +#define SYS_shmat 30 +#define SYS_shmctl 31 +#define SYS_dup 32 +#define SYS_nanosleep 35 +#define SYS_getitimer 36 +#define SYS_setitimer 38 +#define SYS_getpid 39 +#define SYS_socket 41 +#define SYS_connect 42 +#define SYS_accept 43 +#define SYS_sendto 44 +#define SYS_recvfrom 45 +#define SYS_sendmsg 46 +#define SYS_recvmsg 47 +#define SYS_shutdown 48 +#define SYS_bind 49 +#define SYS_listen 50 +#define SYS_getsockname 51 +#define SYS_getpeername 52 +#define SYS_socketpair 53 +#define SYS_setsockopt 54 +#define SYS_getsockopt 55 +#define SYS_clone 56 +#define SYS_execve 59 +#define SYS_exit 60 +#define SYS_wait4 61 +#define SYS_kill 62 +#define SYS_uname 63 +#define SYS_semget 64 +#define SYS_semop 65 +#define SYS_semctl 66 +#define SYS_shmdt 67 +#define SYS_msgget 68 +#define SYS_msgsnd 69 +#define SYS_msgrcv 70 +#define SYS_msgctl 71 +#define SYS_fcntl 72 +#define SYS_flock 73 +#define SYS_fsync 74 +#define SYS_fdatasync 75 +#define SYS_truncate 76 +#define SYS_ftruncate 77 +#define SYS_getdents 78 +#define SYS_getcwd 79 +#define SYS_chdir 80 +#define SYS_fchdir 81 +#define SYS_fchmod 91 +#define SYS_fchown 93 +#define SYS_umask 95 +#define SYS_getrlimit 97 +#define SYS_getrusage 98 +#define SYS_times 100 +#define SYS_ptrace 101 +#define SYS_getuid 102 +#define SYS_getgid 104 +#define SYS_setuid 105 +#define SYS_setgid 106 +#define SYS_geteuid 107 +#define SYS_getegid 108 +#define SYS_setpgid 109 +#define SYS_getppid 110 +#define SYS_setsid 112 +#define SYS_setreuid 113 +#define SYS_setregid 114 +#define SYS_getgroups 115 +#define SYS_setgroups 116 +#define SYS_setresuid 117 +#define SYS_getresuid 118 +#define SYS_setresgid 119 +#define SYS_getresgid 120 +#define SYS_getpgid 121 +#define SYS_getsid 124 +#define SYS_rt_sigpending 127 +#define SYS_rt_sigtimedwait 128 +#define SYS_rt_sigqueueinfo 129 +#define SYS_rt_sigsuspend 130 +#define SYS_sigaltstack 131 +#define SYS_statfs 137 +#define SYS_fstatfs 138 +#define SYS_getpriority 140 +#define SYS_setpriority 141 +#define SYS_sched_setparam 142 +#define SYS_sched_getparam 143 +#define SYS_sched_setscheduler 144 +#define SYS_sched_getscheduler 145 +#define SYS_sched_get_priority_max 146 +#define SYS_sched_get_priority_min 147 +#define SYS_sched_rr_get_interval 148 +#define SYS_mlock 149 +#define SYS_munlock 150 +#define SYS_mlockall 151 +#define SYS_munlockall 152 +#define SYS_prctl 157 +#define SYS_adjtimex 159 +#define SYS_chroot 161 +#define SYS_sync 162 +#define SYS_acct 163 +#define SYS_settimeofday 164 +#define SYS_sethostname 170 +#define SYS_setdomainname 171 +#define SYS_quotactl 179 +#define SYS_gettid 186 +#define SYS_tkill 200 +#define SYS_sched_setaffinity 203 +#define SYS_sched_getaffinity 204 +#define SYS_set_tid_address 218 +#define SYS_semtimedop 220 +#define SYS_fadvise64 221 +#define SYS_timer_create 222 +#define SYS_timer_settime 223 +#define SYS_timer_gettime 224 +#define SYS_timer_getoverrun 225 +#define SYS_timer_delete 226 +#define SYS_clock_settime 227 +#define SYS_clock_getres 229 +#define SYS_clock_nanosleep 230 +#define SYS_mq_open 240 +#define SYS_mq_unlink 241 +#define SYS_mq_timedsend 242 +#define SYS_mq_timedreceive 243 +#define SYS_mq_notify 244 +#define SYS_mq_getsetattr 245 +#define SYS_waitid 247 +#define SYS_openat 257 +#define SYS_mkdirat 258 +#define SYS_mknodat 259 +#define SYS_fchownat 260 +#define SYS_newfstatat 262 +#define SYS_unlinkat 263 +#define SYS_renameat 264 +#define SYS_linkat 265 +#define SYS_symlinkat 266 +#define SYS_readlinkat 267 +#define SYS_fchmodat 268 +#define SYS_faccessat 269 +#define SYS_pselect6 270 +#define SYS_ppoll 271 +#define SYS_set_robust_list 273 +#define SYS_utimensat 280 +#define SYS_fallocate 285 +#define SYS_accept4 288 +#define SYS_dup3 292 +#define SYS_pipe2 293 +#define SYS_preadv 295 +#define SYS_pwritev 296 +#define SYS_recvmmsg 299 +#define SYS_prlimit64 302 +#define SYS_getcpu 309 diff --git a/third_party/ulib/musl/arch/x86_64/bits/user.h b/third_party/ulib/musl/arch/x86_64/bits/user.h new file mode 100644 index 000000000..ea1f73d86 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/bits/user.h @@ -0,0 +1,41 @@ +#undef __WORDSIZE +#define __WORDSIZE 64 + +typedef struct user_fpregs_struct { + uint16_t cwd, swd, ftw, fop; + uint64_t rip, rdp; + uint32_t mxcsr, mxcr_mask; + uint32_t st_space[32], xmm_space[64], padding[24]; +} elf_fpregset_t; + +struct user_regs_struct { + unsigned long r15, r14, r13, r12, rbp, rbx, r11, r10, r9, r8; + unsigned long rax, rcx, rdx, rsi, rdi, orig_rax, rip; + unsigned long cs, eflags, rsp, ss, fs_base, gs_base, ds, es, fs, gs; +}; +#define ELF_NGREG 27 +typedef unsigned long long elf_greg_t, elf_gregset_t[ELF_NGREG]; + +struct user { + struct user_regs_struct regs; + int u_fpvalid; + struct user_fpregs_struct i387; + unsigned long u_tsize; + unsigned long u_dsize; + unsigned long u_ssize; + unsigned long start_code; + unsigned long start_stack; + long signal; + int reserved; + struct user_regs_struct* u_ar0; + struct user_fpregs_struct* u_fpstate; + unsigned long magic; + char u_comm[32]; + unsigned long u_debugreg[8]; +}; + +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) diff --git a/third_party/ulib/musl/arch/x86_64/crt_arch.h b/third_party/ulib/musl/arch/x86_64/crt_arch.h new file mode 100644 index 000000000..820c9ae7f --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/crt_arch.h @@ -0,0 +1,9 @@ +__asm__(".text \n" + ".global " START " \n" START ": \n" + " xor %rbp,%rbp \n" + " mov %rsp,%rdi \n" + ".weak _DYNAMIC \n" + ".hidden _DYNAMIC \n" + " lea _DYNAMIC(%rip),%rsi \n" + " andq $-16,%rsp \n" + " call " START "_c \n"); diff --git a/third_party/ulib/musl/arch/x86_64/pthread_arch.h b/third_party/ulib/musl/arch/x86_64/pthread_arch.h new file mode 100644 index 000000000..d571a14fa --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/pthread_arch.h @@ -0,0 +1,6 @@ +#include +#include + +#define TP_ADJ(p) (p) + +#define MC_PC gregs[REG_RIP] diff --git a/third_party/ulib/musl/arch/x86_64/reloc.h b/third_party/ulib/musl/arch/x86_64/reloc.h new file mode 100644 index 000000000..3c64de8e6 --- /dev/null +++ b/third_party/ulib/musl/arch/x86_64/reloc.h @@ -0,0 +1,22 @@ +#define LDSO_ARCH "x86_64" + +#define REL_SYMBOLIC R_X86_64_64 +#define REL_OFFSET32 R_X86_64_PC32 +#define REL_GOT R_X86_64_GLOB_DAT +#define REL_PLT R_X86_64_JUMP_SLOT +#define REL_RELATIVE R_X86_64_RELATIVE +#define REL_COPY R_X86_64_COPY +#define REL_DTPMOD R_X86_64_DTPMOD64 +#define REL_DTPOFF R_X86_64_DTPOFF64 +#define REL_TPOFF R_X86_64_TPOFF64 +#define REL_TLSDESC R_X86_64_TLSDESC + +#define CRTJMP(pc, sp) \ + __asm__ __volatile__("mov %1,%%rsp ; jmp *%0" : : "r"(pc), "r"(sp) : "memory") + +#define GETFUNCSYM(fp, sym, got) \ + __asm__(".hidden " #sym "\n" \ + " lea " #sym "(%%rip),%0\n" \ + : "=r"(*fp) \ + : \ + : "memory") diff --git a/third_party/ulib/musl/crt/BUILD.gn b/third_party/ulib/musl/crt/BUILD.gn new file mode 100644 index 000000000..ba26a8960 --- /dev/null +++ b/third_party/ulib/musl/crt/BUILD.gn @@ -0,0 +1,105 @@ +source_set("crt") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "..:musl_config" ] + cflags = [] + cflags += [ + "-DCRT", + "-fno-stack-protector", + ] + sources = [ + "Scrt1.c", + "crt1.c", + "rcrt1.c", + ] + if (target_cpu == "arm") { + sources += [ + "arm/crti.s", + "arm/crtn.s", + ] + } else if (target_cpu == "arm64") { + sources += [ + "aarch64/crti.s", + "aarch64/crtn.s", + ] + } else if (target_cpu == "x64") { + sources += [ + "x86_64/crti.s", + "x86_64/crtn.s", + ] + } else { + sources += [ + "crti.c", + "crtn.c", + ] + } +} + +template("copy_objects") { + assert(defined(invoker.input_dir), "input_dir must be defined") + assert(defined(invoker.output_dir), "output_dir must be defined") + object_prefix = "" + if (defined(invoker.object_prefix)) { + object_prefix = invoker.object_prefix + } + foreach(file, invoker.sources) { + copy("copy_${file}") { + sources = [ + rebase_path("${invoker.input_dir}/${object_prefix}${file}", + "", + target_out_dir), + ] + outputs = [ + "${invoker.output_dir}/${file}", + ] + deps = [ + ":crt", + ] + } + } + group(target_name) { + deps = [ + ":crt", + ] + foreach(file, invoker.sources) { + deps += [ ":copy_${file}" ] + } + } +} + +copy_objects("copy_crt_objects") { + sources = [ + "Scrt1.o", + "crt1.o", + "rcrt1.o", + ] + object_prefix = "crt." + input_dir = "." + output_dir = "${root_out_dir}/lib" +} + +copy_objects("copy_crt_arch_objects") { + sources = [ + "crti.o", + "crtn.o", + ] + object_prefix = "crt." + if (target_cpu == "arm") { + input_dir = "arm" + } else if (target_cpu == "arm64") { + input_dir = "aarch64" + } else if (target_cpu == "x64") { + input_dir = "x86_64" + } else { + input_dir = "." + } + output_dir = "${root_out_dir}/lib" +} + +group("install") { + deps = [ + ":copy_crt_arch_objects", + ":copy_crt_objects", + ] +} diff --git a/third_party/ulib/musl/crt/Scrt1.c b/third_party/ulib/musl/crt/Scrt1.c new file mode 100644 index 000000000..822f10bb1 --- /dev/null +++ b/third_party/ulib/musl/crt/Scrt1.c @@ -0,0 +1 @@ +#include "crt1.c" diff --git a/third_party/ulib/musl/crt/aarch64/crti.s b/third_party/ulib/musl/crt/aarch64/crti.s new file mode 100644 index 000000000..775df0ac0 --- /dev/null +++ b/third_party/ulib/musl/crt/aarch64/crti.s @@ -0,0 +1,13 @@ +.section .init +.global _init +.type _init,%function +_init: + stp x29,x30,[sp,-16]! + mov x29,sp + +.section .fini +.global _fini +.type _fini,%function +_fini: + stp x29,x30,[sp,-16]! + mov x29,sp diff --git a/third_party/ulib/musl/crt/aarch64/crtn.s b/third_party/ulib/musl/crt/aarch64/crtn.s new file mode 100644 index 000000000..73cab6926 --- /dev/null +++ b/third_party/ulib/musl/crt/aarch64/crtn.s @@ -0,0 +1,7 @@ +.section .init + ldp x29,x30,[sp],#16 + ret + +.section .fini + ldp x29,x30,[sp],#16 + ret diff --git a/third_party/ulib/musl/crt/arm/crti.s b/third_party/ulib/musl/crt/arm/crti.s new file mode 100644 index 000000000..18dc1e419 --- /dev/null +++ b/third_party/ulib/musl/crt/arm/crti.s @@ -0,0 +1,13 @@ +.syntax unified + +.section .init +.global _init +.type _init,%function +_init: + push {r0,lr} + +.section .fini +.global _fini +.type _fini,%function +_fini: + push {r0,lr} diff --git a/third_party/ulib/musl/crt/arm/crtn.s b/third_party/ulib/musl/crt/arm/crtn.s new file mode 100644 index 000000000..dc020f92e --- /dev/null +++ b/third_party/ulib/musl/crt/arm/crtn.s @@ -0,0 +1,9 @@ +.syntax unified + +.section .init + pop {r0,lr} + bx lr + +.section .fini + pop {r0,lr} + bx lr diff --git a/third_party/ulib/musl/crt/crt1.c b/third_party/ulib/musl/crt/crt1.c new file mode 100644 index 000000000..dd01575cd --- /dev/null +++ b/third_party/ulib/musl/crt/crt1.c @@ -0,0 +1,11 @@ +#include + +#include + +int main(int, char**, void*); +__NO_RETURN int __libc_start_main(int (*)(int, char**, void*), void* arg); + +__SECTION(".crt") +void _start(void* arg) { + __libc_start_main(main, arg); +} diff --git a/third_party/ulib/musl/crt/crti.c b/third_party/ulib/musl/crt/crti.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/crt/crtn.c b/third_party/ulib/musl/crt/crtn.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/crt/rcrt1.c b/third_party/ulib/musl/crt/rcrt1.c new file mode 100644 index 000000000..3dcf05063 --- /dev/null +++ b/third_party/ulib/musl/crt/rcrt1.c @@ -0,0 +1,12 @@ +#define START "_start" +#define _dlstart_c _start_c +#include "../ldso/dlstart.c" + +int main(); +void _init() __attribute__((weak)); +void _fini() __attribute__((weak)); +_Noreturn int __libc_start_main(int (*)(), int, char**, void (*)(), void (*)(), void (*)()); + +__attribute__((__visibility__("hidden"))) _Noreturn void __dls2(unsigned char* base, size_t* sp) { + __libc_start_main(main, *sp, (void*)(sp + 1), _init, _fini, 0); +} diff --git a/third_party/ulib/musl/crt/rules.mk b/third_party/ulib/musl/crt/rules.mk new file mode 100644 index 000000000..4315bf24a --- /dev/null +++ b/third_party/ulib/musl/crt/rules.mk @@ -0,0 +1,22 @@ +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/crt1.c \ + +ifeq ($(ARCH),arm64) +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/aarch64/crti.s \ + $(GET_LOCAL_DIR)/aarch64/crtn.s \ + +else ifeq ($(ARCH),arm) +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/arm/crti.s \ + $(GET_LOCAL_DIR)/arm/crtn.s \ + +else ifeq ($(SUBARCH),x86-64) +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/x86_64/crti.s \ + $(GET_LOCAL_DIR)/x86_64/crtn.s \ + +else +error Unsupported architecture for musl build! + +endif diff --git a/third_party/ulib/musl/crt/x32/crti.s b/third_party/ulib/musl/crt/x32/crti.s new file mode 100644 index 000000000..4788968b2 --- /dev/null +++ b/third_party/ulib/musl/crt/x32/crti.s @@ -0,0 +1,9 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax diff --git a/third_party/ulib/musl/crt/x32/crtn.s b/third_party/ulib/musl/crt/x32/crtn.s new file mode 100644 index 000000000..29198b775 --- /dev/null +++ b/third_party/ulib/musl/crt/x32/crtn.s @@ -0,0 +1,7 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret diff --git a/third_party/ulib/musl/crt/x86_64/crti.s b/third_party/ulib/musl/crt/x86_64/crti.s new file mode 100644 index 000000000..4788968b2 --- /dev/null +++ b/third_party/ulib/musl/crt/x86_64/crti.s @@ -0,0 +1,9 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax diff --git a/third_party/ulib/musl/crt/x86_64/crtn.s b/third_party/ulib/musl/crt/x86_64/crtn.s new file mode 100644 index 000000000..29198b775 --- /dev/null +++ b/third_party/ulib/musl/crt/x86_64/crtn.s @@ -0,0 +1,7 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret diff --git a/third_party/ulib/musl/include/aio.h b/third_party/ulib/musl/include/aio.h new file mode 100644 index 000000000..e62b037e8 --- /dev/null +++ b/third_party/ulib/musl/include/aio.h @@ -0,0 +1,69 @@ +#ifndef _AIO_H +#define _AIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define __NEED_ssize_t +#define __NEED_off_t + +#include + +struct aiocb { + int aio_fildes, aio_lio_opcode, aio_reqprio; + volatile void* aio_buf; + size_t aio_nbytes; + struct sigevent aio_sigevent; + void* __td; + int __lock[2]; + volatile int __err; + ssize_t __ret; + off_t aio_offset; + void *__next, *__prev; + char __dummy4[32 - 2 * sizeof(void*)]; +}; + +#define AIO_CANCELED 0 +#define AIO_NOTCANCELED 1 +#define AIO_ALLDONE 2 + +#define LIO_READ 0 +#define LIO_WRITE 1 +#define LIO_NOP 2 + +#define LIO_WAIT 0 +#define LIO_NOWAIT 1 + +int aio_read(struct aiocb*); +int aio_write(struct aiocb*); +int aio_error(const struct aiocb*); +ssize_t aio_return(struct aiocb*); +int aio_cancel(int, struct aiocb*); +int aio_suspend(const struct aiocb* const[], int, const struct timespec*); +int aio_fsync(int, struct aiocb*); + +int lio_listio(int, struct aiocb* __restrict const* __restrict, int, struct sigevent* __restrict); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define aiocb64 aiocb +#define aio_read64 aio_read +#define aio_write64 aio_write +#define aio_error64 aio_error +#define aio_return64 aio_return +#define aio_cancel64 aio_cancel +#define aio_suspend64 aio_suspend +#define aio_fsync64 aio_fsync +#define lio_listio64 lio_listio +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/alloca.h b/third_party/ulib/musl/include/alloca.h new file mode 100644 index 000000000..8dfb52ef2 --- /dev/null +++ b/third_party/ulib/musl/include/alloca.h @@ -0,0 +1,21 @@ +#ifndef _ALLOCA_H +#define _ALLOCA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#include + +void* alloca(size_t); + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/alltypes.h.in b/third_party/ulib/musl/include/alltypes.h.in new file mode 100644 index 000000000..6a9c105fb --- /dev/null +++ b/third_party/ulib/musl/include/alltypes.h.in @@ -0,0 +1,75 @@ +TYPEDEF unsigned _Addr size_t; +TYPEDEF unsigned _Addr uintptr_t; +TYPEDEF _Addr ptrdiff_t; +TYPEDEF _Addr ssize_t; +TYPEDEF _Addr intptr_t; +TYPEDEF _Addr regoff_t; +TYPEDEF _Reg register_t; + +TYPEDEF signed char int8_t; +TYPEDEF short int16_t; +TYPEDEF int int32_t; +TYPEDEF _Int64 int64_t; +TYPEDEF _Int64 intmax_t; +TYPEDEF unsigned char uint8_t; +TYPEDEF unsigned short uint16_t; +TYPEDEF unsigned int uint32_t; +TYPEDEF unsigned _Int64 uint64_t; +TYPEDEF unsigned _Int64 u_int64_t; +TYPEDEF unsigned _Int64 uintmax_t; + +TYPEDEF unsigned mode_t; +TYPEDEF unsigned _Reg nlink_t; +TYPEDEF _Int64 off_t; +TYPEDEF unsigned _Int64 ino_t; +TYPEDEF unsigned _Int64 dev_t; +TYPEDEF long blksize_t; +TYPEDEF _Int64 blkcnt_t; +TYPEDEF unsigned _Int64 fsblkcnt_t; +TYPEDEF unsigned _Int64 fsfilcnt_t; + +TYPEDEF unsigned wint_t; +TYPEDEF unsigned long wctype_t; + +TYPEDEF void * timer_t; +TYPEDEF int clockid_t; +TYPEDEF long clock_t; +STRUCT timeval { time_t tv_sec; suseconds_t tv_usec; }; +STRUCT timespec { time_t tv_sec; long tv_nsec; }; + +TYPEDEF int pid_t; +TYPEDEF unsigned id_t; +TYPEDEF unsigned uid_t; +TYPEDEF unsigned gid_t; +TYPEDEF int key_t; +TYPEDEF unsigned useconds_t; + +#ifdef __cplusplus +TYPEDEF unsigned long pthread_t; +#else +TYPEDEF struct __pthread * pthread_t; +#endif +TYPEDEF int pthread_once_t; +TYPEDEF unsigned pthread_key_t; +TYPEDEF int pthread_spinlock_t; +TYPEDEF struct { unsigned __attr; } pthread_mutexattr_t; +TYPEDEF struct { unsigned __attr; } pthread_condattr_t; +TYPEDEF struct { unsigned __attr; } pthread_barrierattr_t; +TYPEDEF struct { unsigned __attr[2]; } pthread_rwlockattr_t; + +TYPEDEF struct _IO_FILE FILE; + +TYPEDEF struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; + +TYPEDEF struct __locale_struct * locale_t; + +TYPEDEF struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; + +STRUCT iovec { void *iov_base; size_t iov_len; }; + +TYPEDEF unsigned socklen_t; +TYPEDEF unsigned short sa_family_t; + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/third_party/ulib/musl/include/ar.h b/third_party/ulib/musl/include/ar.h new file mode 100644 index 000000000..18423d7d2 --- /dev/null +++ b/third_party/ulib/musl/include/ar.h @@ -0,0 +1,25 @@ +#ifndef _AR_H +#define _AR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6], ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/arpa/ftp.h b/third_party/ulib/musl/include/arpa/ftp.h new file mode 100644 index 000000000..19e9f94a2 --- /dev/null +++ b/third_party/ulib/musl/include/arpa/ftp.h @@ -0,0 +1,35 @@ +#ifndef _ARPA_FTP_H +#define _ARPA_FTP_H +#define PRELIM 1 +#define COMPLETE 2 +#define CONTINUE 3 +#define TRANSIENT 4 +#define ERROR 5 +#define TYPE_A 1 +#define TYPE_E 2 +#define TYPE_I 3 +#define TYPE_L 4 +#define FORM_N 1 +#define FORM_T 2 +#define FORM_C 3 +#define STRU_F 1 +#define STRU_R 2 +#define STRU_P 3 +#define MODE_S 1 +#define MODE_B 2 +#define MODE_C 3 +#define REC_ESC '\377' +#define REC_EOR '\001' +#define REC_EOF '\002' +#define BLK_EOR 0x80 +#define BLK_EOF 0x40 +#define BLK_ERRORS 0x20 +#define BLK_RESTART 0x10 +#define BLK_BYTECOUNT 2 +#ifdef FTP_NAMES +char* modenames[] = {"0", "Stream", "Block", "Compressed"}; +char* strunames[] = {"0", "File", "Record", "Page"}; +char* typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local"}; +char* formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control"}; +#endif +#endif diff --git a/third_party/ulib/musl/include/arpa/inet.h b/third_party/ulib/musl/include/arpa/inet.h new file mode 100644 index 000000000..8edb63e89 --- /dev/null +++ b/third_party/ulib/musl/include/arpa/inet.h @@ -0,0 +1,36 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +in_addr_t inet_addr(const char*); +in_addr_t inet_network(const char*); +char* inet_ntoa(struct in_addr); +int inet_pton(int, const char* __restrict, void* __restrict); +const char* inet_ntop(int, const void* __restrict, char* __restrict, socklen_t); + +int inet_aton(const char*, struct in_addr*); +struct in_addr inet_makeaddr(in_addr_t, in_addr_t); +in_addr_t inet_lnaof(struct in_addr); +in_addr_t inet_netof(struct in_addr); + +#undef INET_ADDRSTRLEN +#undef INET6_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/arpa/nameser.h b/third_party/ulib/musl/include/arpa/nameser.h new file mode 100644 index 000000000..280006ccf --- /dev/null +++ b/third_party/ulib/musl/include/arpa/nameser.h @@ -0,0 +1,451 @@ +#ifndef _ARPA_NAMESER_H +#define _ARPA_NAMESER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __NAMESER 19991006 +#define NS_PACKETSZ 512 +#define NS_MAXDNAME 1025 +#define NS_MAXMSG 65535 +#define NS_MAXCDNAME 255 +#define NS_MAXLABEL 63 +#define NS_HFIXEDSZ 12 +#define NS_QFIXEDSZ 4 +#define NS_RRFIXEDSZ 10 +#define NS_INT32SZ 4 +#define NS_INT16SZ 2 +#define NS_INT8SZ 1 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#define NS_CMPRSFLGS 0xc0 +#define NS_DEFAULTPORT 53 + +typedef enum __ns_sect { + ns_s_qd = 0, + ns_s_zn = 0, + ns_s_an = 1, + ns_s_pr = 1, + ns_s_ns = 2, + ns_s_ud = 2, + ns_s_ar = 3, + ns_s_max = 4 +} ns_sect; + +typedef struct __ns_msg { + const unsigned char *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max]; + const unsigned char* _sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char* _msg_ptr; +} ns_msg; + +struct _ns_flagdata { + int mask, shift; +}; +extern const struct _ns_flagdata _ns_flagdata[]; + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) +#define ns_msg_getflag(handle, flag) \ + (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) + +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + const unsigned char* rdata; +} ns_rr; + +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +typedef enum __ns_flag { + ns_f_qr, + ns_f_opcode, + ns_f_aa, + ns_f_tc, + ns_f_rd, + ns_f_ra, + ns_f_z, + ns_f_ad, + ns_f_cd, + ns_f_rcode, + ns_f_max +} ns_flag; + +typedef enum __ns_opcode { + ns_o_query = 0, + ns_o_iquery = 1, + ns_o_status = 2, + ns_o_notify = 4, + ns_o_update = 5, + ns_o_max = 6 +} ns_opcode; + +typedef enum __ns_rcode { + ns_r_noerror = 0, + ns_r_formerr = 1, + ns_r_servfail = 2, + ns_r_nxdomain = 3, + ns_r_notimpl = 4, + ns_r_refused = 5, + ns_r_yxdomain = 6, + ns_r_yxrrset = 7, + ns_r_nxrrset = 8, + ns_r_notauth = 9, + ns_r_notzone = 10, + ns_r_max = 11, + ns_r_badvers = 16, + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +typedef enum __ns_update_operation { + ns_uop_delete = 0, + ns_uop_add = 1, + ns_uop_max = 2 +} ns_update_operation; + +struct ns_tsig_key { + char name[NS_MAXDNAME], alg[NS_MAXDNAME]; + unsigned char* data; + int len; +}; +typedef struct ns_tsig_key ns_tsig_key; + +struct ns_tcp_tsig_state { + int counter; + struct dst_key* key; + void* ctx; + unsigned char sig[NS_PACKETSZ]; + int siglen; +}; +typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; + +#define NS_TSIG_FUDGE 300 +#define NS_TSIG_TCP_COUNT 100 +#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" + +#define NS_TSIG_ERROR_NO_TSIG -10 +#define NS_TSIG_ERROR_NO_SPACE -11 +#define NS_TSIG_ERROR_FORMERR -12 + +typedef enum __ns_type { + ns_t_invalid = 0, + ns_t_a = 1, + ns_t_ns = 2, + ns_t_md = 3, + ns_t_mf = 4, + ns_t_cname = 5, + ns_t_soa = 6, + ns_t_mb = 7, + ns_t_mg = 8, + ns_t_mr = 9, + ns_t_null = 10, + ns_t_wks = 11, + ns_t_ptr = 12, + ns_t_hinfo = 13, + ns_t_minfo = 14, + ns_t_mx = 15, + ns_t_txt = 16, + ns_t_rp = 17, + ns_t_afsdb = 18, + ns_t_x25 = 19, + ns_t_isdn = 20, + ns_t_rt = 21, + ns_t_nsap = 22, + ns_t_nsap_ptr = 23, + ns_t_sig = 24, + ns_t_key = 25, + ns_t_px = 26, + ns_t_gpos = 27, + ns_t_aaaa = 28, + ns_t_loc = 29, + ns_t_nxt = 30, + ns_t_eid = 31, + ns_t_nimloc = 32, + ns_t_srv = 33, + ns_t_atma = 34, + ns_t_naptr = 35, + ns_t_kx = 36, + ns_t_cert = 37, + ns_t_a6 = 38, + ns_t_dname = 39, + ns_t_sink = 40, + ns_t_opt = 41, + ns_t_apl = 42, + ns_t_tkey = 249, + ns_t_tsig = 250, + ns_t_ixfr = 251, + ns_t_axfr = 252, + ns_t_mailb = 253, + ns_t_maila = 254, + ns_t_any = 255, + ns_t_zxfr = 256, + ns_t_max = 65536 +} ns_type; + +#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || (t) == ns_t_mailb || (t) == ns_t_maila) +#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || (t) == ns_t_zxfr) + +typedef enum __ns_class { + ns_c_invalid = 0, + ns_c_in = 1, + ns_c_2 = 2, + ns_c_chaos = 3, + ns_c_hs = 4, + ns_c_none = 254, + ns_c_any = 255, + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_key_types { + ns_kt_rsa = 1, + ns_kt_dh = 2, + ns_kt_dsa = 3, + ns_kt_private = 254 +} ns_key_types; + +typedef enum __ns_cert_types { + cert_t_pkix = 1, + cert_t_spki = 2, + cert_t_pgp = 3, + cert_t_url = 253, + cert_t_oid = 254 +} ns_cert_types; + +#define NS_KEY_TYPEMASK 0xC000 +#define NS_KEY_TYPE_AUTH_CONF 0x0000 +#define NS_KEY_TYPE_CONF_ONLY 0x8000 +#define NS_KEY_TYPE_AUTH_ONLY 0x4000 +#define NS_KEY_TYPE_NO_KEY 0xC000 +#define NS_KEY_NO_AUTH 0x8000 +#define NS_KEY_NO_CONF 0x4000 +#define NS_KEY_RESERVED2 0x2000 +#define NS_KEY_EXTENDED_FLAGS 0x1000 +#define NS_KEY_RESERVED4 0x0800 +#define NS_KEY_RESERVED5 0x0400 +#define NS_KEY_NAME_TYPE 0x0300 +#define NS_KEY_NAME_USER 0x0000 +#define NS_KEY_NAME_ENTITY 0x0200 +#define NS_KEY_NAME_ZONE 0x0100 +#define NS_KEY_NAME_RESERVED 0x0300 +#define NS_KEY_RESERVED8 0x0080 +#define NS_KEY_RESERVED9 0x0040 +#define NS_KEY_RESERVED10 0x0020 +#define NS_KEY_RESERVED11 0x0010 +#define NS_KEY_SIGNATORYMASK 0x000F +#define NS_KEY_RESERVED_BITMASK \ + (NS_KEY_RESERVED2 | NS_KEY_RESERVED4 | NS_KEY_RESERVED5 | NS_KEY_RESERVED8 | \ + NS_KEY_RESERVED9 | NS_KEY_RESERVED10 | NS_KEY_RESERVED11) +#define NS_KEY_RESERVED_BITMASK2 0xFFFF +#define NS_ALG_MD5RSA 1 +#define NS_ALG_DH 2 +#define NS_ALG_DSA 3 +#define NS_ALG_DSS NS_ALG_DSA +#define NS_ALG_EXPIRE_ONLY 253 +#define NS_ALG_PRIVATE_OID 254 + +#define NS_KEY_PROT_TLS 1 +#define NS_KEY_PROT_EMAIL 2 +#define NS_KEY_PROT_DNSSEC 3 +#define NS_KEY_PROT_IPSEC 4 +#define NS_KEY_PROT_ANY 255 + +#define NS_MD5RSA_MIN_BITS 512 +#define NS_MD5RSA_MAX_BITS 4096 +#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS + 7 / 8) * 2 + 3) +#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES + 2) / 3) * 4) +#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS + 7) / 8) +#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS + 7) / 8) + +#define NS_DSA_SIG_SIZE 41 +#define NS_DSA_MIN_SIZE 213 +#define NS_DSA_MAX_BYTES 405 + +#define NS_SIG_TYPE 0 +#define NS_SIG_ALG 2 +#define NS_SIG_LABELS 3 +#define NS_SIG_OTTL 4 +#define NS_SIG_EXPIR 8 +#define NS_SIG_SIGNED 12 +#define NS_SIG_FOOT 16 +#define NS_SIG_SIGNER 18 +#define NS_NXT_BITS 8 +#define NS_NXT_BIT_SET(n, p) (p[(n) / NS_NXT_BITS] |= (0x80 >> ((n) % NS_NXT_BITS))) +#define NS_NXT_BIT_CLEAR(n, p) (p[(n) / NS_NXT_BITS] &= ~(0x80 >> ((n) % NS_NXT_BITS))) +#define NS_NXT_BIT_ISSET(n, p) (p[(n) / NS_NXT_BITS] & (0x80 >> ((n) % NS_NXT_BITS))) +#define NS_NXT_MAX 127 + +#define NS_OPT_DNSSEC_OK 0x8000U +#define NS_OPT_NSID 3 + +#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp) += 2) - 2)) +#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp) += 4) - 4)) +#define NS_PUT16(s, cp) ns_put16((s), ((cp) += 2) - 2) +#define NS_PUT32(l, cp) ns_put32((l), ((cp) += 4) - 4) + +unsigned ns_get16(const unsigned char*); +unsigned long ns_get32(const unsigned char*); +void ns_put16(unsigned, unsigned char*); +void ns_put32(unsigned long, unsigned char*); + +int ns_initparse(const unsigned char*, int, ns_msg*); +int ns_parserr(ns_msg*, ns_sect, int, ns_rr*); +int ns_skiprr(const unsigned char*, const unsigned char*, ns_sect, int); +int ns_name_uncompress(const unsigned char*, const unsigned char*, const unsigned char*, char*, + size_t); + +#define __BIND 19950621 + +typedef struct { + unsigned id : 16; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned qr : 1; + unsigned opcode : 4; + unsigned aa : 1; + unsigned tc : 1; + unsigned rd : 1; + unsigned ra : 1; + unsigned unused : 1; + unsigned ad : 1; + unsigned cd : 1; + unsigned rcode : 4; +#else + unsigned rd : 1; + unsigned tc : 1; + unsigned aa : 1; + unsigned opcode : 4; + unsigned qr : 1; + unsigned rcode : 4; + unsigned cd : 1; + unsigned ad : 1; + unsigned unused : 1; + unsigned ra : 1; +#endif + unsigned qdcount : 16; + unsigned ancount : 16; + unsigned nscount : 16; + unsigned arcount : 16; +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INT32SZ NS_INT32SZ +#define INT16SZ NS_INT16SZ +#define INT8SZ NS_INT8SZ +#define INADDRSZ NS_INADDRSZ +#define IN6ADDRSZ NS_IN6ADDRSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define S_ZONE ns_s_zn +#define S_PREREQ ns_s_pr +#define S_UPDATE ns_s_ud +#define S_ADDT ns_s_ar + +#define QUERY ns_o_query +#define IQUERY ns_o_iquery +#define STATUS ns_o_status +#define NS_NOTIFY_OP ns_o_notify +#define NS_UPDATE_OP ns_o_update + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone + +#define DELETE ns_uop_delete +#define ADD ns_uop_add + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_DNAME ns_t_dname +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/arpa/nameser_compat.h b/third_party/ulib/musl/include/arpa/nameser_compat.h new file mode 100644 index 000000000..ee3b1a901 --- /dev/null +++ b/third_party/ulib/musl/include/arpa/nameser_compat.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/arpa/telnet.h b/third_party/ulib/musl/include/arpa/telnet.h new file mode 100644 index 000000000..8b5e5fa8e --- /dev/null +++ b/third_party/ulib/musl/include/arpa/telnet.h @@ -0,0 +1,277 @@ +#ifndef _ARPA_TELNET_H +#define _ARPA_TELNET_H + +#define IAC 255 +#define DONT 254 +#define DO 253 +#define WONT 252 +#define WILL 251 +#define SB 250 +#define GA 249 +#define EL 248 +#define EC 247 +#define AYT 246 +#define AO 245 +#define IP 244 +#define BREAK 243 +#define DM 242 +#define NOP 241 +#define SE 240 +#define EOR 239 +#define ABORT 238 +#define SUSP 237 +#define xEOF 236 + +#define SYNCH 242 + +#define telcmds \ + ((char[][6]){ \ + "EOF", "SUSP", "ABORT", "EOR", "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", \ + "EC", "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0}) + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && (unsigned int)(x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +#define TELOPT_BINARY 0 +#define TELOPT_ECHO 1 +#define TELOPT_RCP 2 +#define TELOPT_SGA 3 +#define TELOPT_NAMS 4 +#define TELOPT_STATUS 5 +#define TELOPT_TM 6 +#define TELOPT_RCTE 7 +#define TELOPT_NAOL 8 +#define TELOPT_NAOP 9 +#define TELOPT_NAOCRD 10 +#define TELOPT_NAOHTS 11 +#define TELOPT_NAOHTD 12 +#define TELOPT_NAOFFD 13 +#define TELOPT_NAOVTS 14 +#define TELOPT_NAOVTD 15 +#define TELOPT_NAOLFD 16 +#define TELOPT_XASCII 17 +#define TELOPT_LOGOUT 18 +#define TELOPT_BM 19 +#define TELOPT_DET 20 +#define TELOPT_SUPDUP 21 +#define TELOPT_SUPDUPOUTPUT 22 +#define TELOPT_SNDLOC 23 +#define TELOPT_TTYPE 24 +#define TELOPT_EOR 25 +#define TELOPT_TUID 26 +#define TELOPT_OUTMRK 27 +#define TELOPT_TTYLOC 28 +#define TELOPT_3270REGIME 29 +#define TELOPT_X3PAD 30 +#define TELOPT_NAWS 31 +#define TELOPT_TSPEED 32 +#define TELOPT_LFLOW 33 +#define TELOPT_LINEMODE 34 +#define TELOPT_XDISPLOC 35 +#define TELOPT_OLD_ENVIRON 36 +#define TELOPT_AUTHENTICATION 37 /* Authenticate */ +#define TELOPT_ENCRYPT 38 +#define TELOPT_NEW_ENVIRON 39 +#define TELOPT_EXOPL 255 + +#define NTELOPTS (1 + TELOPT_NEW_ENVIRON) +#ifdef TELOPTS +char* telopts[NTELOPTS + 1] = { + "BINARY", + "ECHO", + "RCP", + "SUPPRESS GO AHEAD", + "NAME", + "STATUS", + "TIMING MARK", + "RCTE", + "NAOL", + "NAOP", + "NAOCRD", + "NAOHTS", + "NAOHTD", + "NAOFFD", + "NAOVTS", + "NAOVTD", + "NAOLFD", + "EXTEND ASCII", + "LOGOUT", + "BYTE MACRO", + "DATA ENTRY TERMINAL", + "SUPDUP", + "SUPDUP OUTPUT", + "SEND LOCATION", + "TERMINAL TYPE", + "END OF RECORD", + "TACACS UID", + "OUTPUT MARKING", + "TTYLOC", + "3270 REGIME", + "X.3 PAD", + "NAWS", + "TSPEED", + "LFLOW", + "LINEMODE", + "XDISPLOC", + "OLD-ENVIRON", + "AUTHENTICATION", + "ENCRYPT", + "NEW-ENVIRON", + 0, +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_NEW_ENVIRON +#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +#define TELQUAL_IS 0 +#define TELQUAL_SEND 1 +#define TELQUAL_INFO 2 +#define TELQUAL_REPLY 2 +#define TELQUAL_NAME 3 + +#define LFLOW_OFF 0 +#define LFLOW_ON 1 +#define LFLOW_RESTART_ANY 2 +#define LFLOW_RESTART_XON 3 + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +#define SLC_NAMELIST \ + "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, +#ifdef SLC_NAMES +char* slc_names[] = {SLC_NAMELIST}; +#else +extern char* slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define OLD_ENV_VAR 1 +#define OLD_ENV_VALUE 0 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define ENV_ESC 2 +#define ENV_USERVAR 3 + +#define AUTH_WHO_CLIENT 0 +#define AUTH_WHO_SERVER 1 +#define AUTH_WHO_MASK 1 + +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_CNT 5 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +char* authtype_names[] = { + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, +}; +#else +extern char* authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +#define ENCRYPT_IS 0 +#define ENCRYPT_SUPPORT 1 +#define ENCRYPT_REPLY 2 +#define ENCRYPT_START 3 +#define ENCRYPT_END 4 +#define ENCRYPT_REQSTART 5 +#define ENCRYPT_REQEND 6 +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +char* encrypt_names[] = { + "IS", "SUPPORT", "REPLY", "START", "END", "REQUEST-START", + "REQUEST-END", "ENC-KEYID", "DEC-KEYID", 0, +}; +char* enctype_names[] = { + "ANY", "DES_CFB64", "DES_OFB64", 0, +}; +#else +extern char* encrypt_names[]; +extern char* enctype_names[]; +#endif + +#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] + +#endif diff --git a/third_party/ulib/musl/include/arpa/tftp.h b/third_party/ulib/musl/include/arpa/tftp.h new file mode 100644 index 000000000..12efe9e16 --- /dev/null +++ b/third_party/ulib/musl/include/arpa/tftp.h @@ -0,0 +1,30 @@ +#ifndef _ARPA_TFTP_H +#define _ARPA_TFTP_H +#define SEGSIZE 512 +#define RRQ 01 +#define WRQ 02 +#define DATA 03 +#define ACK 04 +#define ERROR 05 +struct tftphdr { + short th_opcode; + union { + unsigned short tu_block; + short tu_code; + char tu_stuff[1]; + } th_u; + char th_data[1]; +}; +#define th_block th_u.tu_block +#define th_code th_u.tu_code +#define th_stuff th_u.tu_stuff +#define th_msg th_data +#define EUNDEF 0 +#define ENOTFOUND 1 +#define EACCESS 2 +#define ENOSPACE 3 +#define EBADOP 4 +#define EBADID 5 +#define EEXISTS 6 +#define ENOUSER 7 +#endif diff --git a/third_party/ulib/musl/include/assert.h b/third_party/ulib/musl/include/assert.h new file mode 100644 index 000000000..ac39defc3 --- /dev/null +++ b/third_party/ulib/musl/include/assert.h @@ -0,0 +1,23 @@ +#include + +#undef assert + +#ifdef NDEBUG +#define assert(x) (void)0 +#else +#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__), 0))) +#endif + +#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) +#define static_assert _Static_assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void __assert_fail(const char*, const char*, int, const char*); + +#ifdef __cplusplus +} +#endif diff --git a/third_party/ulib/musl/include/bits/alltypes-aarch64.h b/third_party/ulib/musl/include/bits/alltypes-aarch64.h new file mode 100644 index 000000000..f153262cd --- /dev/null +++ b/third_party/ulib/musl/include/bits/alltypes-aarch64.h @@ -0,0 +1,401 @@ +#define _Addr long +#define _Int64 long long +#define _Reg long + +#if defined(__NEED_va_list) && !defined(__DEFINED_va_list) +typedef __builtin_va_list va_list; +#define __DEFINED_va_list +#endif + +#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list) +typedef __builtin_va_list __isoc_va_list; +#define __DEFINED___isoc_va_list +#endif + + +#ifndef __cplusplus +#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t) +typedef unsigned wchar_t; +#define __DEFINED_wchar_t +#endif + +#endif +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + + +#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t) +typedef int blksize_t; +#define __DEFINED_blksize_t +#endif + +#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t) +typedef unsigned int nlink_t; +#define __DEFINED_nlink_t +#endif + + +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef float float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef double double_t; +#define __DEFINED_double_t +#endif + + +#if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t) +typedef struct { long long __ll; long double __ld; } max_align_t; +#define __DEFINED_max_align_t +#endif + + +#if defined(__NEED_time_t) && !defined(__DEFINED_time_t) +typedef long time_t; +#define __DEFINED_time_t +#endif + +#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t) +typedef long suseconds_t; +#define __DEFINED_suseconds_t +#endif + + +#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t) +typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t; +#define __DEFINED_pthread_attr_t +#endif + +#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t) +typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t; +#define __DEFINED_pthread_mutex_t +#endif + +#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t) +typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t; +#define __DEFINED_mtx_t +#endif + +#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t; +#define __DEFINED_pthread_cond_t +#endif + +#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t; +#define __DEFINED_cnd_t +#endif + +#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t) +typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t; +#define __DEFINED_pthread_rwlock_t +#endif + +#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t) +typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t; +#define __DEFINED_pthread_barrier_t +#endif + +#if defined(__NEED_size_t) && !defined(__DEFINED_size_t) +typedef unsigned _Addr size_t; +#define __DEFINED_size_t +#endif + +#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t) +typedef unsigned _Addr uintptr_t; +#define __DEFINED_uintptr_t +#endif + +#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t) +typedef _Addr ptrdiff_t; +#define __DEFINED_ptrdiff_t +#endif + +#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t) +typedef _Addr ssize_t; +#define __DEFINED_ssize_t +#endif + +#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t) +typedef _Addr intptr_t; +#define __DEFINED_intptr_t +#endif + +#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t) +typedef _Addr regoff_t; +#define __DEFINED_regoff_t +#endif + +#if defined(__NEED_register_t) && !defined(__DEFINED_register_t) +typedef _Reg register_t; +#define __DEFINED_register_t +#endif + + +#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t) +typedef signed char int8_t; +#define __DEFINED_int8_t +#endif + +#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t) +typedef short int16_t; +#define __DEFINED_int16_t +#endif + +#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t) +typedef int int32_t; +#define __DEFINED_int32_t +#endif + +#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t) +typedef _Int64 int64_t; +#define __DEFINED_int64_t +#endif + +#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t) +typedef _Int64 intmax_t; +#define __DEFINED_intmax_t +#endif + +#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t) +typedef unsigned char uint8_t; +#define __DEFINED_uint8_t +#endif + +#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t) +typedef unsigned short uint16_t; +#define __DEFINED_uint16_t +#endif + +#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t) +typedef unsigned int uint32_t; +#define __DEFINED_uint32_t +#endif + +#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t) +typedef unsigned _Int64 uint64_t; +#define __DEFINED_uint64_t +#endif + +#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t) +typedef unsigned _Int64 u_int64_t; +#define __DEFINED_u_int64_t +#endif + +#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t) +typedef unsigned _Int64 uintmax_t; +#define __DEFINED_uintmax_t +#endif + + +#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t) +typedef unsigned mode_t; +#define __DEFINED_mode_t +#endif + +#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t) +typedef unsigned _Reg nlink_t; +#define __DEFINED_nlink_t +#endif + +#if defined(__NEED_off_t) && !defined(__DEFINED_off_t) +typedef _Int64 off_t; +#define __DEFINED_off_t +#endif + +#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t) +typedef unsigned _Int64 ino_t; +#define __DEFINED_ino_t +#endif + +#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t) +typedef unsigned _Int64 dev_t; +#define __DEFINED_dev_t +#endif + +#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t) +typedef long blksize_t; +#define __DEFINED_blksize_t +#endif + +#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t) +typedef _Int64 blkcnt_t; +#define __DEFINED_blkcnt_t +#endif + +#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t) +typedef unsigned _Int64 fsblkcnt_t; +#define __DEFINED_fsblkcnt_t +#endif + +#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t) +typedef unsigned _Int64 fsfilcnt_t; +#define __DEFINED_fsfilcnt_t +#endif + + +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + +#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) +typedef unsigned long wctype_t; +#define __DEFINED_wctype_t +#endif + + +#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t) +typedef void * timer_t; +#define __DEFINED_timer_t +#endif + +#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t) +typedef int clockid_t; +#define __DEFINED_clockid_t +#endif + +#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t) +typedef long clock_t; +#define __DEFINED_clock_t +#endif + +#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval) +struct timeval { time_t tv_sec; suseconds_t tv_usec; }; +#define __DEFINED_struct_timeval +#endif + +#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec) +struct timespec { time_t tv_sec; long tv_nsec; }; +#define __DEFINED_struct_timespec +#endif + + +#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t) +typedef int pid_t; +#define __DEFINED_pid_t +#endif + +#if defined(__NEED_id_t) && !defined(__DEFINED_id_t) +typedef unsigned id_t; +#define __DEFINED_id_t +#endif + +#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t) +typedef unsigned uid_t; +#define __DEFINED_uid_t +#endif + +#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t) +typedef unsigned gid_t; +#define __DEFINED_gid_t +#endif + +#if defined(__NEED_key_t) && !defined(__DEFINED_key_t) +typedef int key_t; +#define __DEFINED_key_t +#endif + +#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t) +typedef unsigned useconds_t; +#define __DEFINED_useconds_t +#endif + + +#ifdef __cplusplus +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef unsigned long pthread_t; +#define __DEFINED_pthread_t +#endif + +#else +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef struct __pthread * pthread_t; +#define __DEFINED_pthread_t +#endif + +#endif +#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t) +typedef int pthread_once_t; +#define __DEFINED_pthread_once_t +#endif + +#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t) +typedef unsigned pthread_key_t; +#define __DEFINED_pthread_key_t +#endif + +#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t) +typedef int pthread_spinlock_t; +#define __DEFINED_pthread_spinlock_t +#endif + +#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t) +typedef struct { unsigned __attr; } pthread_mutexattr_t; +#define __DEFINED_pthread_mutexattr_t +#endif + +#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t) +typedef struct { unsigned __attr; } pthread_condattr_t; +#define __DEFINED_pthread_condattr_t +#endif + +#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t) +typedef struct { unsigned __attr; } pthread_barrierattr_t; +#define __DEFINED_pthread_barrierattr_t +#endif + +#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t) +typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t; +#define __DEFINED_pthread_rwlockattr_t +#endif + + +#if defined(__NEED_FILE) && !defined(__DEFINED_FILE) +typedef struct _IO_FILE FILE; +#define __DEFINED_FILE +#endif + + +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + + +#if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t) +typedef struct __locale_struct * locale_t; +#define __DEFINED_locale_t +#endif + + +#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t) +typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; +#define __DEFINED_sigset_t +#endif + + +#if defined(__NEED_struct_iovec) && !defined(__DEFINED_struct_iovec) +struct iovec { void *iov_base; size_t iov_len; }; +#define __DEFINED_struct_iovec +#endif + + +#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t) +typedef unsigned socklen_t; +#define __DEFINED_socklen_t +#endif + +#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t) +typedef unsigned short sa_family_t; +#define __DEFINED_sa_family_t +#endif + + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/third_party/ulib/musl/include/bits/alltypes-arm.h b/third_party/ulib/musl/include/bits/alltypes-arm.h new file mode 100644 index 000000000..a2a0bb222 --- /dev/null +++ b/third_party/ulib/musl/include/bits/alltypes-arm.h @@ -0,0 +1,385 @@ +#define _Addr int +#define _Int64 long long +#define _Reg int + +#if defined(__NEED_va_list) && !defined(__DEFINED_va_list) +typedef __builtin_va_list va_list; +#define __DEFINED_va_list +#endif + +#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list) +typedef __builtin_va_list __isoc_va_list; +#define __DEFINED___isoc_va_list +#endif + + +#ifndef __cplusplus +#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t) +typedef unsigned wchar_t; +#define __DEFINED_wchar_t +#endif + +#endif + +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef float float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef double double_t; +#define __DEFINED_double_t +#endif + + +#if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t) +typedef struct { long long __ll; long double __ld; } max_align_t; +#define __DEFINED_max_align_t +#endif + + +#if defined(__NEED_time_t) && !defined(__DEFINED_time_t) +typedef long time_t; +#define __DEFINED_time_t +#endif + +#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t) +typedef long suseconds_t; +#define __DEFINED_suseconds_t +#endif + + +#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t) +typedef struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t; +#define __DEFINED_pthread_attr_t +#endif + +#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t) +typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; +#define __DEFINED_pthread_mutex_t +#endif + +#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t) +typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t; +#define __DEFINED_mtx_t +#endif + +#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t; +#define __DEFINED_pthread_cond_t +#endif + +#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t; +#define __DEFINED_cnd_t +#endif + +#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t) +typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t; +#define __DEFINED_pthread_rwlock_t +#endif + +#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t) +typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t; +#define __DEFINED_pthread_barrier_t +#endif + +#if defined(__NEED_size_t) && !defined(__DEFINED_size_t) +typedef unsigned _Addr size_t; +#define __DEFINED_size_t +#endif + +#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t) +typedef unsigned _Addr uintptr_t; +#define __DEFINED_uintptr_t +#endif + +#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t) +typedef _Addr ptrdiff_t; +#define __DEFINED_ptrdiff_t +#endif + +#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t) +typedef _Addr ssize_t; +#define __DEFINED_ssize_t +#endif + +#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t) +typedef _Addr intptr_t; +#define __DEFINED_intptr_t +#endif + +#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t) +typedef _Addr regoff_t; +#define __DEFINED_regoff_t +#endif + +#if defined(__NEED_register_t) && !defined(__DEFINED_register_t) +typedef _Reg register_t; +#define __DEFINED_register_t +#endif + + +#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t) +typedef signed char int8_t; +#define __DEFINED_int8_t +#endif + +#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t) +typedef short int16_t; +#define __DEFINED_int16_t +#endif + +#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t) +typedef int int32_t; +#define __DEFINED_int32_t +#endif + +#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t) +typedef _Int64 int64_t; +#define __DEFINED_int64_t +#endif + +#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t) +typedef _Int64 intmax_t; +#define __DEFINED_intmax_t +#endif + +#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t) +typedef unsigned char uint8_t; +#define __DEFINED_uint8_t +#endif + +#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t) +typedef unsigned short uint16_t; +#define __DEFINED_uint16_t +#endif + +#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t) +typedef unsigned int uint32_t; +#define __DEFINED_uint32_t +#endif + +#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t) +typedef unsigned _Int64 uint64_t; +#define __DEFINED_uint64_t +#endif + +#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t) +typedef unsigned _Int64 u_int64_t; +#define __DEFINED_u_int64_t +#endif + +#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t) +typedef unsigned _Int64 uintmax_t; +#define __DEFINED_uintmax_t +#endif + + +#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t) +typedef unsigned mode_t; +#define __DEFINED_mode_t +#endif + +#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t) +typedef unsigned _Reg nlink_t; +#define __DEFINED_nlink_t +#endif + +#if defined(__NEED_off_t) && !defined(__DEFINED_off_t) +typedef _Int64 off_t; +#define __DEFINED_off_t +#endif + +#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t) +typedef unsigned _Int64 ino_t; +#define __DEFINED_ino_t +#endif + +#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t) +typedef unsigned _Int64 dev_t; +#define __DEFINED_dev_t +#endif + +#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t) +typedef long blksize_t; +#define __DEFINED_blksize_t +#endif + +#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t) +typedef _Int64 blkcnt_t; +#define __DEFINED_blkcnt_t +#endif + +#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t) +typedef unsigned _Int64 fsblkcnt_t; +#define __DEFINED_fsblkcnt_t +#endif + +#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t) +typedef unsigned _Int64 fsfilcnt_t; +#define __DEFINED_fsfilcnt_t +#endif + + +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + +#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) +typedef unsigned long wctype_t; +#define __DEFINED_wctype_t +#endif + + +#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t) +typedef void * timer_t; +#define __DEFINED_timer_t +#endif + +#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t) +typedef int clockid_t; +#define __DEFINED_clockid_t +#endif + +#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t) +typedef long clock_t; +#define __DEFINED_clock_t +#endif + +#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval) +struct timeval { time_t tv_sec; suseconds_t tv_usec; }; +#define __DEFINED_struct_timeval +#endif + +#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec) +struct timespec { time_t tv_sec; long tv_nsec; }; +#define __DEFINED_struct_timespec +#endif + + +#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t) +typedef int pid_t; +#define __DEFINED_pid_t +#endif + +#if defined(__NEED_id_t) && !defined(__DEFINED_id_t) +typedef unsigned id_t; +#define __DEFINED_id_t +#endif + +#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t) +typedef unsigned uid_t; +#define __DEFINED_uid_t +#endif + +#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t) +typedef unsigned gid_t; +#define __DEFINED_gid_t +#endif + +#if defined(__NEED_key_t) && !defined(__DEFINED_key_t) +typedef int key_t; +#define __DEFINED_key_t +#endif + +#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t) +typedef unsigned useconds_t; +#define __DEFINED_useconds_t +#endif + + +#ifdef __cplusplus +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef unsigned long pthread_t; +#define __DEFINED_pthread_t +#endif + +#else +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef struct __pthread * pthread_t; +#define __DEFINED_pthread_t +#endif + +#endif +#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t) +typedef int pthread_once_t; +#define __DEFINED_pthread_once_t +#endif + +#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t) +typedef unsigned pthread_key_t; +#define __DEFINED_pthread_key_t +#endif + +#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t) +typedef int pthread_spinlock_t; +#define __DEFINED_pthread_spinlock_t +#endif + +#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t) +typedef struct { unsigned __attr; } pthread_mutexattr_t; +#define __DEFINED_pthread_mutexattr_t +#endif + +#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t) +typedef struct { unsigned __attr; } pthread_condattr_t; +#define __DEFINED_pthread_condattr_t +#endif + +#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t) +typedef struct { unsigned __attr; } pthread_barrierattr_t; +#define __DEFINED_pthread_barrierattr_t +#endif + +#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t) +typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t; +#define __DEFINED_pthread_rwlockattr_t +#endif + + +#if defined(__NEED_FILE) && !defined(__DEFINED_FILE) +typedef struct _IO_FILE FILE; +#define __DEFINED_FILE +#endif + + +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + + +#if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t) +typedef struct __locale_struct * locale_t; +#define __DEFINED_locale_t +#endif + + +#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t) +typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; +#define __DEFINED_sigset_t +#endif + + +#if defined(__NEED_struct_iovec) && !defined(__DEFINED_struct_iovec) +struct iovec { void *iov_base; size_t iov_len; }; +#define __DEFINED_struct_iovec +#endif + + +#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t) +typedef unsigned socklen_t; +#define __DEFINED_socklen_t +#endif + +#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t) +typedef unsigned short sa_family_t; +#define __DEFINED_sa_family_t +#endif + + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/third_party/ulib/musl/include/bits/alltypes-x86_64.h b/third_party/ulib/musl/include/bits/alltypes-x86_64.h new file mode 100644 index 000000000..e2373bc51 --- /dev/null +++ b/third_party/ulib/musl/include/bits/alltypes-x86_64.h @@ -0,0 +1,398 @@ +#define _Addr long +#define _Int64 long long +#define _Reg long + +#if defined(__NEED_va_list) && !defined(__DEFINED_va_list) +typedef __builtin_va_list va_list; +#define __DEFINED_va_list +#endif + +#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list) +typedef __builtin_va_list __isoc_va_list; +#define __DEFINED___isoc_va_list +#endif + + +#ifndef __cplusplus +#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t) +typedef int wchar_t; +#define __DEFINED_wchar_t +#endif + +#endif + +#if defined(__FLT_EVAL_METHOD__) && __FLT_EVAL_METHOD__ == 2 +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef long double float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef long double double_t; +#define __DEFINED_double_t +#endif + +#else +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef float float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef double double_t; +#define __DEFINED_double_t +#endif + +#endif + +#if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t) +typedef struct { long long __ll; long double __ld; } max_align_t; +#define __DEFINED_max_align_t +#endif + + +#if defined(__NEED_time_t) && !defined(__DEFINED_time_t) +typedef long time_t; +#define __DEFINED_time_t +#endif + +#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t) +typedef long suseconds_t; +#define __DEFINED_suseconds_t +#endif + + +#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t) +typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t; +#define __DEFINED_pthread_attr_t +#endif + +#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t) +typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t; +#define __DEFINED_pthread_mutex_t +#endif + +#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t) +typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t; +#define __DEFINED_mtx_t +#endif + +#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t; +#define __DEFINED_pthread_cond_t +#endif + +#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t; +#define __DEFINED_cnd_t +#endif + +#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t) +typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t; +#define __DEFINED_pthread_rwlock_t +#endif + +#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t) +typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t; +#define __DEFINED_pthread_barrier_t +#endif + +#if defined(__NEED_size_t) && !defined(__DEFINED_size_t) +typedef unsigned _Addr size_t; +#define __DEFINED_size_t +#endif + +#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t) +typedef unsigned _Addr uintptr_t; +#define __DEFINED_uintptr_t +#endif + +#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t) +typedef _Addr ptrdiff_t; +#define __DEFINED_ptrdiff_t +#endif + +#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t) +typedef _Addr ssize_t; +#define __DEFINED_ssize_t +#endif + +#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t) +typedef _Addr intptr_t; +#define __DEFINED_intptr_t +#endif + +#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t) +typedef _Addr regoff_t; +#define __DEFINED_regoff_t +#endif + +#if defined(__NEED_register_t) && !defined(__DEFINED_register_t) +typedef _Reg register_t; +#define __DEFINED_register_t +#endif + + +#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t) +typedef signed char int8_t; +#define __DEFINED_int8_t +#endif + +#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t) +typedef short int16_t; +#define __DEFINED_int16_t +#endif + +#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t) +typedef int int32_t; +#define __DEFINED_int32_t +#endif + +#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t) +typedef _Int64 int64_t; +#define __DEFINED_int64_t +#endif + +#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t) +typedef _Int64 intmax_t; +#define __DEFINED_intmax_t +#endif + +#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t) +typedef unsigned char uint8_t; +#define __DEFINED_uint8_t +#endif + +#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t) +typedef unsigned short uint16_t; +#define __DEFINED_uint16_t +#endif + +#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t) +typedef unsigned int uint32_t; +#define __DEFINED_uint32_t +#endif + +#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t) +typedef unsigned _Int64 uint64_t; +#define __DEFINED_uint64_t +#endif + +#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t) +typedef unsigned _Int64 u_int64_t; +#define __DEFINED_u_int64_t +#endif + +#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t) +typedef unsigned _Int64 uintmax_t; +#define __DEFINED_uintmax_t +#endif + + +#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t) +typedef unsigned mode_t; +#define __DEFINED_mode_t +#endif + +#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t) +typedef unsigned _Reg nlink_t; +#define __DEFINED_nlink_t +#endif + +#if defined(__NEED_off_t) && !defined(__DEFINED_off_t) +typedef _Int64 off_t; +#define __DEFINED_off_t +#endif + +#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t) +typedef unsigned _Int64 ino_t; +#define __DEFINED_ino_t +#endif + +#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t) +typedef unsigned _Int64 dev_t; +#define __DEFINED_dev_t +#endif + +#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t) +typedef long blksize_t; +#define __DEFINED_blksize_t +#endif + +#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t) +typedef _Int64 blkcnt_t; +#define __DEFINED_blkcnt_t +#endif + +#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t) +typedef unsigned _Int64 fsblkcnt_t; +#define __DEFINED_fsblkcnt_t +#endif + +#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t) +typedef unsigned _Int64 fsfilcnt_t; +#define __DEFINED_fsfilcnt_t +#endif + + +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + +#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) +typedef unsigned long wctype_t; +#define __DEFINED_wctype_t +#endif + + +#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t) +typedef void * timer_t; +#define __DEFINED_timer_t +#endif + +#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t) +typedef int clockid_t; +#define __DEFINED_clockid_t +#endif + +#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t) +typedef long clock_t; +#define __DEFINED_clock_t +#endif + +#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval) +struct timeval { time_t tv_sec; suseconds_t tv_usec; }; +#define __DEFINED_struct_timeval +#endif + +#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec) +struct timespec { time_t tv_sec; long tv_nsec; }; +#define __DEFINED_struct_timespec +#endif + + +#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t) +typedef int pid_t; +#define __DEFINED_pid_t +#endif + +#if defined(__NEED_id_t) && !defined(__DEFINED_id_t) +typedef unsigned id_t; +#define __DEFINED_id_t +#endif + +#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t) +typedef unsigned uid_t; +#define __DEFINED_uid_t +#endif + +#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t) +typedef unsigned gid_t; +#define __DEFINED_gid_t +#endif + +#if defined(__NEED_key_t) && !defined(__DEFINED_key_t) +typedef int key_t; +#define __DEFINED_key_t +#endif + +#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t) +typedef unsigned useconds_t; +#define __DEFINED_useconds_t +#endif + + +#ifdef __cplusplus +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef unsigned long pthread_t; +#define __DEFINED_pthread_t +#endif + +#else +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef struct __pthread * pthread_t; +#define __DEFINED_pthread_t +#endif + +#endif +#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t) +typedef int pthread_once_t; +#define __DEFINED_pthread_once_t +#endif + +#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t) +typedef unsigned pthread_key_t; +#define __DEFINED_pthread_key_t +#endif + +#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t) +typedef int pthread_spinlock_t; +#define __DEFINED_pthread_spinlock_t +#endif + +#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t) +typedef struct { unsigned __attr; } pthread_mutexattr_t; +#define __DEFINED_pthread_mutexattr_t +#endif + +#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t) +typedef struct { unsigned __attr; } pthread_condattr_t; +#define __DEFINED_pthread_condattr_t +#endif + +#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t) +typedef struct { unsigned __attr; } pthread_barrierattr_t; +#define __DEFINED_pthread_barrierattr_t +#endif + +#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t) +typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t; +#define __DEFINED_pthread_rwlockattr_t +#endif + + +#if defined(__NEED_FILE) && !defined(__DEFINED_FILE) +typedef struct _IO_FILE FILE; +#define __DEFINED_FILE +#endif + + +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + + +#if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t) +typedef struct __locale_struct * locale_t; +#define __DEFINED_locale_t +#endif + + +#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t) +typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; +#define __DEFINED_sigset_t +#endif + + +#if defined(__NEED_struct_iovec) && !defined(__DEFINED_struct_iovec) +struct iovec { void *iov_base; size_t iov_len; }; +#define __DEFINED_struct_iovec +#endif + + +#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t) +typedef unsigned socklen_t; +#define __DEFINED_socklen_t +#endif + +#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t) +typedef unsigned short sa_family_t; +#define __DEFINED_sa_family_t +#endif + + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/third_party/ulib/musl/include/bits/alltypes.h b/third_party/ulib/musl/include/bits/alltypes.h new file mode 100644 index 000000000..f4bce1e70 --- /dev/null +++ b/third_party/ulib/musl/include/bits/alltypes.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "alltypes-x86_64.h" +#elif defined(__aarch64__) +#include "alltypes-aarch64.h" +#elif defined(__arm__) +#include "alltypes-arm.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/endian.h b/third_party/ulib/musl/include/bits/endian.h new file mode 100644 index 000000000..a4240afec --- /dev/null +++ b/third_party/ulib/musl/include/bits/endian.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/endian.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/endian.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/endian.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/errno.h b/third_party/ulib/musl/include/bits/errno.h new file mode 100644 index 000000000..54a496c20 --- /dev/null +++ b/third_party/ulib/musl/include/bits/errno.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/errno.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/errno.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/errno.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/fcntl.h b/third_party/ulib/musl/include/bits/fcntl.h new file mode 100644 index 000000000..971c9320d --- /dev/null +++ b/third_party/ulib/musl/include/bits/fcntl.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/fcntl.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/fcntl.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/fcntl.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/fenv.h b/third_party/ulib/musl/include/bits/fenv.h new file mode 100644 index 000000000..c356c9210 --- /dev/null +++ b/third_party/ulib/musl/include/bits/fenv.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/fenv.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/fenv.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/fenv.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/float.h b/third_party/ulib/musl/include/bits/float.h new file mode 100644 index 000000000..20c005ea1 --- /dev/null +++ b/third_party/ulib/musl/include/bits/float.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/float.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/float.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/float.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/io.h b/third_party/ulib/musl/include/bits/io.h new file mode 100644 index 000000000..5d34bb974 --- /dev/null +++ b/third_party/ulib/musl/include/bits/io.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/io.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/io.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/io.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/ioctl.h b/third_party/ulib/musl/include/bits/ioctl.h new file mode 100644 index 000000000..0cfe58ce5 --- /dev/null +++ b/third_party/ulib/musl/include/bits/ioctl.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/ioctl.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/ioctl.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/ioctl.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/ipc.h b/third_party/ulib/musl/include/bits/ipc.h new file mode 100644 index 000000000..f6409740f --- /dev/null +++ b/third_party/ulib/musl/include/bits/ipc.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/ipc.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/ipc.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/ipc.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/limits.h b/third_party/ulib/musl/include/bits/limits.h new file mode 100644 index 000000000..5e269f5e2 --- /dev/null +++ b/third_party/ulib/musl/include/bits/limits.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/limits.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/limits.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/limits.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/mman.h b/third_party/ulib/musl/include/bits/mman.h new file mode 100644 index 000000000..66978cfe8 --- /dev/null +++ b/third_party/ulib/musl/include/bits/mman.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/mman.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/mman.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/mman.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/msg.h b/third_party/ulib/musl/include/bits/msg.h new file mode 100644 index 000000000..1355cb4a7 --- /dev/null +++ b/third_party/ulib/musl/include/bits/msg.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/msg.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/msg.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/msg.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/poll.h b/third_party/ulib/musl/include/bits/poll.h new file mode 100644 index 000000000..389496dac --- /dev/null +++ b/third_party/ulib/musl/include/bits/poll.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/poll.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/poll.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/poll.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/posix.h b/third_party/ulib/musl/include/bits/posix.h new file mode 100644 index 000000000..06627102e --- /dev/null +++ b/third_party/ulib/musl/include/bits/posix.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/posix.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/posix.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/posix.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/reg.h b/third_party/ulib/musl/include/bits/reg.h new file mode 100644 index 000000000..89286f58a --- /dev/null +++ b/third_party/ulib/musl/include/bits/reg.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/reg.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/reg.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/reg.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/resource.h b/third_party/ulib/musl/include/bits/resource.h new file mode 100644 index 000000000..981186259 --- /dev/null +++ b/third_party/ulib/musl/include/bits/resource.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/resource.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/resource.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/resource.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/sem.h b/third_party/ulib/musl/include/bits/sem.h new file mode 100644 index 000000000..93c558e19 --- /dev/null +++ b/third_party/ulib/musl/include/bits/sem.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/sem.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/sem.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/sem.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/setjmp.h b/third_party/ulib/musl/include/bits/setjmp.h new file mode 100644 index 000000000..3c5257a39 --- /dev/null +++ b/third_party/ulib/musl/include/bits/setjmp.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/setjmp.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/setjmp.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/setjmp.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/shm.h b/third_party/ulib/musl/include/bits/shm.h new file mode 100644 index 000000000..a6b1112ce --- /dev/null +++ b/third_party/ulib/musl/include/bits/shm.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/shm.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/shm.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/shm.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/signal.h b/third_party/ulib/musl/include/bits/signal.h new file mode 100644 index 000000000..a9ca9f91f --- /dev/null +++ b/third_party/ulib/musl/include/bits/signal.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/signal.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/signal.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/signal.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/socket.h b/third_party/ulib/musl/include/bits/socket.h new file mode 100644 index 000000000..3ad477b10 --- /dev/null +++ b/third_party/ulib/musl/include/bits/socket.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/socket.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/socket.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/socket.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/stat.h b/third_party/ulib/musl/include/bits/stat.h new file mode 100644 index 000000000..99b9f63b3 --- /dev/null +++ b/third_party/ulib/musl/include/bits/stat.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/stat.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/stat.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/stat.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/statfs.h b/third_party/ulib/musl/include/bits/statfs.h new file mode 100644 index 000000000..0ef5df26f --- /dev/null +++ b/third_party/ulib/musl/include/bits/statfs.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/statfs.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/statfs.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/statfs.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/stdarg.h b/third_party/ulib/musl/include/bits/stdarg.h new file mode 100644 index 000000000..0110e9b10 --- /dev/null +++ b/third_party/ulib/musl/include/bits/stdarg.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/stdarg.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/stdarg.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/stdarg.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/stdint.h b/third_party/ulib/musl/include/bits/stdint.h new file mode 100644 index 000000000..3aaa451cf --- /dev/null +++ b/third_party/ulib/musl/include/bits/stdint.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/stdint.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/stdint.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/stdint.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/syscall.h b/third_party/ulib/musl/include/bits/syscall.h new file mode 100644 index 000000000..d3cfa118c --- /dev/null +++ b/third_party/ulib/musl/include/bits/syscall.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/syscall.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/syscall.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/syscall.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/termios.h b/third_party/ulib/musl/include/bits/termios.h new file mode 100644 index 000000000..247839667 --- /dev/null +++ b/third_party/ulib/musl/include/bits/termios.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/generic/bits/termios.h" +#elif defined(__aarch64__) +#include "../../arch/generic/bits/termios.h" +#elif defined(__arm__) +#include "../../arch/generic/bits/termios.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/bits/user.h b/third_party/ulib/musl/include/bits/user.h new file mode 100644 index 000000000..10b57ab35 --- /dev/null +++ b/third_party/ulib/musl/include/bits/user.h @@ -0,0 +1,9 @@ +#if defined(__x86_64__) +#include "../../arch/x86_64/bits/user.h" +#elif defined(__aarch64__) +#include "../../arch/aarch64/bits/user.h" +#elif defined(__arm__) +#include "../../arch/arm/bits/user.h" +#else +#error Unsupported architecture! +#endif diff --git a/third_party/ulib/musl/include/byteswap.h b/third_party/ulib/musl/include/byteswap.h new file mode 100644 index 000000000..70d92290f --- /dev/null +++ b/third_party/ulib/musl/include/byteswap.h @@ -0,0 +1,24 @@ +#ifndef _BYTESWAP_H +#define _BYTESWAP_H + +#include +#include + +static __inline uint16_t __bswap_16(uint16_t __x) { + return __x << 8 | __x >> 8; +} + +static __inline uint32_t __bswap_32(uint32_t __x) { + return __x >> 24 | ((__x >> 8) & 0xff00) | ((__x << 8) & 0xff0000) | + __x << 24; +} + +static __inline uint64_t __bswap_64(uint64_t __x) { + return ((uint64_t)__bswap_32(__x)) << 32 | __bswap_32(__x >> 32); +} + +#define bswap_16(x) __bswap_16(x) +#define bswap_32(x) __bswap_32(x) +#define bswap_64(x) __bswap_64(x) + +#endif diff --git a/third_party/ulib/musl/include/complex.h b/third_party/ulib/musl/include/complex.h new file mode 100644 index 000000000..8ca628760 --- /dev/null +++ b/third_party/ulib/musl/include/complex.h @@ -0,0 +1,137 @@ +#ifndef _COMPLEX_H +#define _COMPLEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define complex _Complex +#ifdef __GNUC__ +#define _Complex_I (__extension__(0.0f + 1.0fi)) +#else +#define _Complex_I (0.0f + 1.0fi) +#endif +#define I _Complex_I + +double complex cacos(double complex); +float complex cacosf(float complex); +long double complex cacosl(long double complex); + +double complex casin(double complex); +float complex casinf(float complex); +long double complex casinl(long double complex); + +double complex catan(double complex); +float complex catanf(float complex); +long double complex catanl(long double complex); + +double complex ccos(double complex); +float complex ccosf(float complex); +long double complex ccosl(long double complex); + +double complex csin(double complex); +float complex csinf(float complex); +long double complex csinl(long double complex); + +double complex ctan(double complex); +float complex ctanf(float complex); +long double complex ctanl(long double complex); + +double complex cacosh(double complex); +float complex cacoshf(float complex); +long double complex cacoshl(long double complex); + +double complex casinh(double complex); +float complex casinhf(float complex); +long double complex casinhl(long double complex); + +double complex catanh(double complex); +float complex catanhf(float complex); +long double complex catanhl(long double complex); + +double complex ccosh(double complex); +float complex ccoshf(float complex); +long double complex ccoshl(long double complex); + +double complex csinh(double complex); +float complex csinhf(float complex); +long double complex csinhl(long double complex); + +double complex ctanh(double complex); +float complex ctanhf(float complex); +long double complex ctanhl(long double complex); + +double complex cexp(double complex); +float complex cexpf(float complex); +long double complex cexpl(long double complex); + +double complex clog(double complex); +float complex clogf(float complex); +long double complex clogl(long double complex); + +double cabs(double complex); +float cabsf(float complex); +long double cabsl(long double complex); + +double complex cpow(double complex, double complex); +float complex cpowf(float complex, float complex); +long double complex cpowl(long double complex, long double complex); + +double complex csqrt(double complex); +float complex csqrtf(float complex); +long double complex csqrtl(long double complex); + +double carg(double complex); +float cargf(float complex); +long double cargl(long double complex); + +double cimag(double complex); +float cimagf(float complex); +long double cimagl(long double complex); + +double complex conj(double complex); +float complex conjf(float complex); +long double complex conjl(long double complex); + +double complex cproj(double complex); +float complex cprojf(float complex); +long double complex cprojl(long double complex); + +double creal(double complex); +float crealf(float complex); +long double creall(long double complex); + +#ifndef __cplusplus +#define __CIMAG(x, t) \ + (+(union { \ + _Complex t __z; \ + t __xy[2]; \ + }){(_Complex t)(x)} \ + .__xy[1]) + +#define creal(x) ((double)(x)) +#define crealf(x) ((float)(x)) +#define creall(x) ((long double)(x)) + +#define cimag(x) __CIMAG(x, double) +#define cimagf(x) __CIMAG(x, float) +#define cimagl(x) __CIMAG(x, long double) +#endif + +#if __STDC_VERSION__ >= 201112L +#if defined(_Imaginary_I) +#define __CMPLX(x, y, t) ((t)(x) + _Imaginary_I * (t)(y)) +#elif defined(__clang__) +#define __CMPLX(x, y, t) (+(_Complex t){(t)(x), (t)(y)}) +#else +#define __CMPLX(x, y, t) (__builtin_complex((t)(x), (t)(y))) +#endif +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/cpio.h b/third_party/ulib/musl/include/cpio.h new file mode 100644 index 000000000..7d7238799 --- /dev/null +++ b/third_party/ulib/musl/include/cpio.h @@ -0,0 +1,29 @@ +#ifndef _CPIO_H +#define _CPIO_H + +#define MAGIC "070707" + +#define C_IRUSR 000400 +#define C_IWUSR 000200 +#define C_IXUSR 000100 +#define C_IRGRP 000040 +#define C_IWGRP 000020 +#define C_IXGRP 000010 +#define C_IROTH 000004 +#define C_IWOTH 000002 +#define C_IXOTH 000001 + +#define C_ISUID 004000 +#define C_ISGID 002000 +#define C_ISVTX 001000 + +#define C_ISBLK 060000 +#define C_ISCHR 020000 +#define C_ISDIR 040000 +#define C_ISFIFO 010000 +#define C_ISSOCK 0140000 +#define C_ISLNK 0120000 +#define C_ISCTG 0110000 +#define C_ISREG 0100000 + +#endif diff --git a/third_party/ulib/musl/include/crypt.h b/third_party/ulib/musl/include/crypt.h new file mode 100644 index 000000000..f72a4a4d6 --- /dev/null +++ b/third_party/ulib/musl/include/crypt.h @@ -0,0 +1,20 @@ +#ifndef _CRYPT_H +#define _CRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct crypt_data { + int initialized; + char __buf[256]; +}; + +char* crypt(const char*, const char*); +char* crypt_r(const char*, const char*, struct crypt_data*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/ctype.h b/third_party/ulib/musl/include/ctype.h new file mode 100644 index 000000000..48b0945ee --- /dev/null +++ b/third_party/ulib/musl/include/ctype.h @@ -0,0 +1,72 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int isalnum(int); +int isalpha(int); +int isblank(int); +int iscntrl(int); +int isdigit(int); +int isgraph(int); +int islower(int); +int isprint(int); +int ispunct(int); +int isspace(int); +int isupper(int); +int isxdigit(int); +int tolower(int); +int toupper(int); + +#ifndef __cplusplus +static __inline int __isspace(int _c) { + return _c == ' ' || (unsigned)_c - '\t' < 5; +} + +#define isalpha(a) (0 ? isalpha(a) : (((unsigned)(a) | 32) - 'a') < 26) +#define isdigit(a) (0 ? isdigit(a) : ((unsigned)(a) - '0') < 10) +#define islower(a) (0 ? islower(a) : ((unsigned)(a) - 'a') < 26) +#define isupper(a) (0 ? isupper(a) : ((unsigned)(a) - 'A') < 26) +#define isprint(a) (0 ? isprint(a) : ((unsigned)(a)-0x20) < 0x5f) +#define isgraph(a) (0 ? isgraph(a) : ((unsigned)(a)-0x21) < 0x5e) +#define isspace(a) __isspace(a) +#endif + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define __NEED_locale_t +#include + +int isalnum_l(int, locale_t); +int isalpha_l(int, locale_t); +int isblank_l(int, locale_t); +int iscntrl_l(int, locale_t); +int isdigit_l(int, locale_t); +int isgraph_l(int, locale_t); +int islower_l(int, locale_t); +int isprint_l(int, locale_t); +int ispunct_l(int, locale_t); +int isspace_l(int, locale_t); +int isupper_l(int, locale_t); +int isxdigit_l(int, locale_t); +int tolower_l(int, locale_t); +int toupper_l(int, locale_t); + +int isascii(int); +int toascii(int); +#define _tolower(a) ((a) | 0x20) +#define _toupper(a) ((a)&0x5f) +#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/dirent.h b/third_party/ulib/musl/include/dirent.h new file mode 100644 index 000000000..2b4839821 --- /dev/null +++ b/third_party/ulib/musl/include/dirent.h @@ -0,0 +1,79 @@ +#ifndef _DIRENT_H +#define _DIRENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_ino_t +#define __NEED_off_t +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#define __NEED_size_t +#endif + +#include + +typedef struct __dirstream DIR; + +struct dirent { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + +#define d_fileno d_ino + +int closedir(DIR*); +DIR* fdopendir(int); +DIR* opendir(const char*); +struct dirent* readdir(DIR*); +int readdir_r(DIR* __restrict, struct dirent* __restrict, struct dirent** __restrict); +void rewinddir(DIR*); +void seekdir(DIR*, long); +long telldir(DIR*); +int dirfd(DIR*); + +int alphasort(const struct dirent**, const struct dirent**); +int scandir(const char*, struct dirent***, int (*)(const struct dirent*), + int (*)(const struct dirent**, const struct dirent**)); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 +#define IFTODT(x) ((x) >> 12 & 017) +#define DTTOIF(x) ((x) << 12) +int getdents(int, struct dirent*, size_t); +#endif + +#ifdef _GNU_SOURCE +int versionsort(const struct dirent**, const struct dirent**); +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define dirent64 dirent +#define readdir64 readdir +#define readdir64_r readdir_r +#define scandir64 scandir +#define alphasort64 alphasort +#define versionsort64 versionsort +#define off64_t off_t +#define ino64_t ino_t +#define getdents64 getdents +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/dlfcn.h b/third_party/ulib/musl/include/dlfcn.h new file mode 100644 index 000000000..2c7e5d3fb --- /dev/null +++ b/third_party/ulib/musl/include/dlfcn.h @@ -0,0 +1,42 @@ +#ifndef _DLFCN_H +#define _DLFCN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_NOLOAD 4 +#define RTLD_NODELETE 4096 +#define RTLD_GLOBAL 256 +#define RTLD_LOCAL 0 + +#define RTLD_NEXT ((void*)-1) +#define RTLD_DEFAULT ((void*)0) + +#define RTLD_DI_LINKMAP 2 + +int dlclose(void*); +char* dlerror(void); +void* dlopen(const char*, int); +void* dlsym(void* __restrict, const char* __restrict); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef struct { + const char* dli_fname; + void* dli_fbase; + const char* dli_sname; + void* dli_saddr; +} Dl_info; +int dladdr(const void*, Dl_info*); +int dlinfo(void*, int, void*); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/elf.h b/third_party/ulib/musl/include/elf.h new file mode 100644 index 000000000..f15b1a690 --- /dev/null +++ b/third_party/ulib/musl/include/elf.h @@ -0,0 +1,2582 @@ +#ifndef _ELF_H +#define _ELF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define EI_DATA 5 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 +#define ELFDATANUM 3 + +#define EI_VERSION 6 + +#define EI_OSABI 7 +#define ELFOSABI_NONE 0 +#define ELFOSABI_SYSV 0 +#define ELFOSABI_HPUX 1 +#define ELFOSABI_NETBSD 2 +#define ELFOSABI_LINUX 3 +#define ELFOSABI_GNU 3 +#define ELFOSABI_SOLARIS 6 +#define ELFOSABI_AIX 7 +#define ELFOSABI_IRIX 8 +#define ELFOSABI_FREEBSD 9 +#define ELFOSABI_TRU64 10 +#define ELFOSABI_MODESTO 11 +#define ELFOSABI_OPENBSD 12 +#define ELFOSABI_ARM 97 +#define ELFOSABI_STANDALONE 255 + +#define EI_ABIVERSION 8 + +#define EI_PAD 9 + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_NUM 5 +#define ET_LOOS 0xfe00 +#define ET_HIOS 0xfeff +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_860 7 +#define EM_MIPS 8 +#define EM_S370 9 +#define EM_MIPS_RS3_LE 10 + +#define EM_PARISC 15 +#define EM_VPP500 17 +#define EM_SPARC32PLUS 18 +#define EM_960 19 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_S390 22 + +#define EM_V800 36 +#define EM_FR20 37 +#define EM_RH32 38 +#define EM_RCE 39 +#define EM_ARM 40 +#define EM_FAKE_ALPHA 41 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_TRICORE 44 +#define EM_ARC 45 +#define EM_H8_300 46 +#define EM_H8_300H 47 +#define EM_H8S 48 +#define EM_H8_500 49 +#define EM_IA_64 50 +#define EM_MIPS_X 51 +#define EM_COLDFIRE 52 +#define EM_68HC12 53 +#define EM_MMA 54 +#define EM_PCP 55 +#define EM_NCPU 56 +#define EM_NDR1 57 +#define EM_STARCORE 58 +#define EM_ME16 59 +#define EM_ST100 60 +#define EM_TINYJ 61 +#define EM_X86_64 62 +#define EM_PDSP 63 + +#define EM_FX66 66 +#define EM_ST9PLUS 67 +#define EM_ST7 68 +#define EM_68HC16 69 +#define EM_68HC11 70 +#define EM_68HC08 71 +#define EM_68HC05 72 +#define EM_SVX 73 +#define EM_ST19 74 +#define EM_VAX 75 +#define EM_CRIS 76 +#define EM_JAVELIN 77 +#define EM_FIREPATH 78 +#define EM_ZSP 79 +#define EM_MMIX 80 +#define EM_HUANY 81 +#define EM_PRISM 82 +#define EM_AVR 83 +#define EM_FR30 84 +#define EM_D10V 85 +#define EM_D30V 86 +#define EM_V850 87 +#define EM_M32R 88 +#define EM_MN10300 89 +#define EM_MN10200 90 +#define EM_PJ 91 +#define EM_OR1K 92 +#define EM_ARC_A5 93 +#define EM_XTENSA 94 +#define EM_AARCH64 183 +#define EM_TILEPRO 188 +#define EM_MICROBLAZE 189 +#define EM_TILEGX 191 +#define EM_NUM 192 +#define EM_ALPHA 0x9026 + +#define EV_NONE 0 +#define EV_CURRENT 1 +#define EV_NUM 2 + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_BEFORE 0xff00 + +#define SHN_AFTER 0xff01 + +#define SHN_HIPROC 0xff1f +#define SHN_LOOS 0xff20 +#define SHN_HIOS 0xff3f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xffff + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_NUM 19 +#define SHT_LOOS 0x60000000 +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 +#define SHT_GNU_HASH 0x6ffffff6 +#define SHT_GNU_LIBLIST 0x6ffffff7 +#define SHT_CHECKSUM 0x6ffffff8 +#define SHT_LOSUNW 0x6ffffffa +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd +#define SHT_GNU_verneed 0x6ffffffe +#define SHT_GNU_versym 0x6fffffff +#define SHT_HISUNW 0x6fffffff +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0x8fffffff + +#define SHF_WRITE (1 << 0) +#define SHF_ALLOC (1 << 1) +#define SHF_EXECINSTR (1 << 2) +#define SHF_MERGE (1 << 4) +#define SHF_STRINGS (1 << 5) +#define SHF_INFO_LINK (1 << 6) +#define SHF_LINK_ORDER (1 << 7) +#define SHF_OS_NONCONFORMING (1 << 8) + +#define SHF_GROUP (1 << 9) +#define SHF_TLS (1 << 10) +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xf0000000 +#define SHF_ORDERED (1 << 30) +#define SHF_EXCLUDE (1U << 31) + +#define GRP_COMDAT 0x1 + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Section st_shndx; +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Section st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +typedef struct { + Elf32_Half si_boundto; + Elf32_Half si_flags; +} Elf32_Syminfo; + +typedef struct { + Elf64_Half si_boundto; + Elf64_Half si_flags; +} Elf64_Syminfo; + +#define SYMINFO_BT_SELF 0xffff +#define SYMINFO_BT_PARENT 0xfffe +#define SYMINFO_BT_LOWRESERVE 0xff00 + +#define SYMINFO_FLG_DIRECT 0x0001 +#define SYMINFO_FLG_PASSTHRU 0x0002 +#define SYMINFO_FLG_COPY 0x0004 +#define SYMINFO_FLG_LAZYLOAD 0x0008 + +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +#define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4) +#define ELF32_ST_TYPE(val) ((val)&0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) + +#define ELF64_ST_BIND(val) ELF32_ST_BIND(val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type)) + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_NUM 3 +#define STB_LOOS 10 +#define STB_GNU_UNIQUE 10 +#define STB_HIOS 12 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_NUM 7 +#define STT_LOOS 10 +#define STT_GNU_IFUNC 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define STN_UNDEF 0 + +#define ELF32_ST_VISIBILITY(o) ((o)&0x03) +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) + +#define STV_DEFAULT 0 +#define STV_INTERNAL 1 +#define STV_HIDDEN 2 +#define STV_PROTECTED 3 + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val)&0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) +#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type)) + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_NUM 8 +#define PT_LOOS 0x60000000 +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_STACK 0x6474e551 +#define PT_GNU_RELRO 0x6474e552 +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa +#define PT_SUNWSTACK 0x6ffffffb +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +#define PN_XNUM 0xffff + +#define PF_X (1 << 0) +#define PF_W (1 << 1) +#define PF_R (1 << 2) +#define PF_MASKOS 0x0ff00000 +#define PF_MASKPROC 0xf0000000 + +#define NT_PRSTATUS 1 +#define NT_FPREGSET 2 +#define NT_PRPSINFO 3 +#define NT_PRXREG 4 +#define NT_TASKSTRUCT 4 +#define NT_PLATFORM 5 +#define NT_AUXV 6 +#define NT_GWINDOWS 7 +#define NT_ASRS 8 +#define NT_PSTATUS 10 +#define NT_PSINFO 13 +#define NT_PRCRED 14 +#define NT_UTSNAME 15 +#define NT_LWPSTATUS 16 +#define NT_LWPSINFO 17 +#define NT_PRFPXREG 20 +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f +#define NT_PPC_VMX 0x100 +#define NT_PPC_SPE 0x101 +#define NT_PPC_VSX 0x102 +#define NT_386_TLS 0x200 +#define NT_386_IOPERM 0x201 +#define NT_X86_XSTATE 0x202 +#define NT_S390_HIGH_GPRS 0x300 +#define NT_S390_TIMER 0x301 +#define NT_S390_TODCMP 0x302 +#define NT_S390_TODPREG 0x303 +#define NT_S390_CTRS 0x304 +#define NT_S390_PREFIX 0x305 +#define NT_S390_LAST_BREAK 0x306 +#define NT_S390_SYSTEM_CALL 0x307 +#define NT_S390_TDB 0x308 +#define NT_ARM_VFP 0x400 +#define NT_ARM_TLS 0x401 +#define NT_ARM_HW_BREAK 0x402 +#define NT_ARM_HW_WATCH 0x403 +#define NT_METAG_CBUF 0x500 +#define NT_METAG_RPIPE 0x501 +#define NT_METAG_TLS 0x502 +#define NT_VERSION 1 + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_NUM 34 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff +#define DT_PROCNUM DT_MIPS_NUM + +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc +#define DT_POSFLAG_1 0x6ffffdfd + +#define DT_SYMINSZ 0x6ffffdfe +#define DT_SYMINENT 0x6ffffdff +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) +#define DT_VALNUM 12 + +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 +#define DT_GNU_LIBLIST 0x6ffffef9 +#define DT_CONFIG 0x6ffffefa +#define DT_DEPAUDIT 0x6ffffefb +#define DT_AUDIT 0x6ffffefc +#define DT_PLTPAD 0x6ffffefd +#define DT_MOVETAB 0x6ffffefe +#define DT_SYMINFO 0x6ffffeff +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) +#define DT_ADDRNUM 11 + +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc + +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe + +#define DT_VERNEEDNUM 0x6fffffff +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) +#define DT_VERSIONTAGNUM 16 + +#define DT_AUXILIARY 0x7ffffffd +#define DT_FILTER 0x7fffffff +#define DT_EXTRATAGIDX(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1) +#define DT_EXTRANUM 3 + +#define DF_ORIGIN 0x00000001 +#define DF_SYMBOLIC 0x00000002 +#define DF_TEXTREL 0x00000004 +#define DF_BIND_NOW 0x00000008 +#define DF_STATIC_TLS 0x00000010 + +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONFALT 0x00002000 +#define DF_1_ENDFILTEE 0x00004000 +#define DF_1_DISPRELDNE 0x00008000 +#define DF_1_DISPRELPND 0x00010000 +#define DF_1_NODIRECT 0x00020000 +#define DF_1_IGNMULDEF 0x00040000 +#define DF_1_NOKSYMS 0x00080000 +#define DF_1_NOHDR 0x00100000 +#define DF_1_EDITED 0x00200000 +#define DF_1_NORELOC 0x00400000 +#define DF_1_SYMINTPOSE 0x00800000 +#define DF_1_GLOBAUDIT 0x01000000 +#define DF_1_SINGLETON 0x02000000 + +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +#define DF_P1_LAZYLOAD 0x00000001 +#define DF_P1_GROUPPERM 0x00000002 + +typedef struct { + Elf32_Half vd_version; + Elf32_Half vd_flags; + Elf32_Half vd_ndx; + Elf32_Half vd_cnt; + Elf32_Word vd_hash; + Elf32_Word vd_aux; + Elf32_Word vd_next; +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; + Elf64_Half vd_flags; + Elf64_Half vd_ndx; + Elf64_Half vd_cnt; + Elf64_Word vd_hash; + Elf64_Word vd_aux; + Elf64_Word vd_next; +} Elf64_Verdef; + +#define VER_DEF_NONE 0 +#define VER_DEF_CURRENT 1 +#define VER_DEF_NUM 2 + +#define VER_FLG_BASE 0x1 +#define VER_FLG_WEAK 0x2 + +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 +#define VER_NDX_LORESERVE 0xff00 +#define VER_NDX_ELIMINATE 0xff01 + +typedef struct { + Elf32_Word vda_name; + Elf32_Word vda_next; +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; + Elf64_Word vda_next; +} Elf64_Verdaux; + +typedef struct { + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + +#define VER_NEED_NONE 0 +#define VER_NEED_CURRENT 1 +#define VER_NEED_NUM 2 + +typedef struct { + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + +#define VER_FLG_WEAK 0x2 + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 +#define AT_CLKTCK 17 + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 + +#define AT_FPUCW 18 + +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 + +#define AT_IGNOREPPC 22 + +#define AT_SECURE 23 + +#define AT_BASE_PLATFORM 24 + +#define AT_RANDOM 25 + +#define AT_HWCAP2 26 + +#define AT_EXECFN 31 + +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +#define ELF_NOTE_GNU "GNU" + +#define ELF_NOTE_PAGESIZE_HINT 1 + +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG + +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +#define NT_GNU_BUILD_ID 3 +#define NT_GNU_GOLD_VERSION 4 + +typedef struct { + Elf32_Xword m_value; + Elf32_Word m_info; + Elf32_Word m_poffset; + Elf32_Half m_repeat; + Elf32_Half m_stride; +} Elf32_Move; + +typedef struct { + Elf64_Xword m_value; + Elf64_Xword m_info; + Elf64_Xword m_poffset; + Elf64_Half m_repeat; + Elf64_Half m_stride; +} Elf64_Move; + +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char)(info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM(info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE(info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO(sym, size) + +#define EF_CPU32 0x00810000 + +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 +#define R_68K_NUM 23 + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 +#define R_386_TLS_IE 15 +#define R_386_TLS_GOTIE 16 +#define R_386_TLS_LE 17 +#define R_386_TLS_GD 18 +#define R_386_TLS_LDM 19 +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 +#define R_386_TLS_GD_PUSH 25 +#define R_386_TLS_GD_CALL 26 +#define R_386_TLS_GD_POP 27 +#define R_386_TLS_LDM_32 28 +#define R_386_TLS_LDM_PUSH 29 +#define R_386_TLS_LDM_CALL 30 +#define R_386_TLS_LDM_POP 31 +#define R_386_TLS_LDO_32 32 +#define R_386_TLS_IE_32 33 +#define R_386_TLS_LE_32 34 +#define R_386_TLS_DTPMOD32 35 +#define R_386_TLS_DTPOFF32 36 +#define R_386_TLS_TPOFF32 37 +#define R_386_SIZE32 38 +#define R_386_TLS_GOTDESC 39 +#define R_386_TLS_DESC_CALL 40 +#define R_386_TLS_DESC 41 +#define R_386_IRELATIVE 42 +#define R_386_NUM 43 + +#define STT_SPARC_REGISTER 13 + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 +#define EF_SPARC_SUN_US1 0x000200 +#define EF_SPARC_HAL_R1 0x000400 +#define EF_SPARC_SUN_US3 0x000800 + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 + +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 +#define R_SPARC_GNU_VTINHERIT 250 +#define R_SPARC_GNU_VTENTRY 251 +#define R_SPARC_REV32 252 + +#define R_SPARC_NUM 253 + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +#define EF_MIPS_NOREORDER 1 +#define EF_MIPS_PIC 2 +#define EF_MIPS_CPIC 4 +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_NAN2008 1024 +#define EF_MIPS_ARCH 0xf0000000 + +#define EF_MIPS_ARCH_1 0x00000000 +#define EF_MIPS_ARCH_2 0x10000000 +#define EF_MIPS_ARCH_3 0x20000000 +#define EF_MIPS_ARCH_4 0x30000000 +#define EF_MIPS_ARCH_5 0x40000000 +#define EF_MIPS_ARCH_32 0x50000000 +#define EF_MIPS_ARCH_64 0x60000000 +#define EF_MIPS_ARCH_32R2 0x70000000 +#define EF_MIPS_ARCH_64R2 0x80000000 + +#define E_MIPS_ARCH_1 0x00000000 +#define E_MIPS_ARCH_2 0x10000000 +#define E_MIPS_ARCH_3 0x20000000 +#define E_MIPS_ARCH_4 0x30000000 +#define E_MIPS_ARCH_5 0x40000000 +#define E_MIPS_ARCH_32 0x50000000 +#define E_MIPS_ARCH_64 0x60000000 + +#define SHN_MIPS_ACOMMON 0xff00 +#define SHN_MIPS_TEXT 0xff01 +#define SHN_MIPS_DATA 0xff02 +#define SHN_MIPS_SCOMMON 0xff03 +#define SHN_MIPS_SUNDEFINED 0xff04 + +#define SHT_MIPS_LIBLIST 0x70000000 +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 +#define SHT_MIPS_DEBUG 0x70000005 +#define SHT_MIPS_REGINFO 0x70000006 +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +#define SHF_MIPS_GPREL 0x10000000 +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +#define STB_MIPS_SPLIT_COMMON 13 + +typedef union { + struct { + Elf32_Word gt_current_g_value; + Elf32_Word gt_unused; + } gt_header; + struct { + Elf32_Word gt_g_value; + Elf32_Word gt_bytes; + } gt_entry; +} Elf32_gptab; + +typedef struct { + Elf32_Word ri_gprmask; + Elf32_Word ri_cprmask[4]; + Elf32_Sword ri_gp_value; +} Elf32_RegInfo; + +typedef struct { + unsigned char kind; + + unsigned char size; + Elf32_Section section; + + Elf32_Word info; +} Elf_Options; + +#define ODK_NULL 0 +#define ODK_REGINFO 1 +#define ODK_EXCEPTIONS 2 +#define ODK_PAD 3 +#define ODK_HWPATCH 4 +#define ODK_FILL 5 +#define ODK_TAGS 6 +#define ODK_HWAND 7 +#define ODK_HWOR 8 + +#define OEX_FPU_MIN 0x1f +#define OEX_FPU_MAX 0x1f00 +#define OEX_PAGE0 0x10000 +#define OEX_SMM 0x20000 +#define OEX_FPDBUG 0x40000 +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +#define OHW_R4KEOP 0x1 +#define OHW_R8KPFETCH 0x2 +#define OHW_R5KEOP 0x4 +#define OHW_R5KCVTL 0x8 + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +typedef struct { + Elf32_Word hwp_flags1; + Elf32_Word hwp_flags2; +} Elf_Options_Hw; + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 +#define R_MIPS_TLS_DTPREL32 39 +#define R_MIPS_TLS_DTPMOD64 40 +#define R_MIPS_TLS_DTPREL64 41 +#define R_MIPS_TLS_GD 42 +#define R_MIPS_TLS_LDM 43 +#define R_MIPS_TLS_DTPREL_HI16 44 +#define R_MIPS_TLS_DTPREL_LO16 45 +#define R_MIPS_TLS_GOTTPREL 46 +#define R_MIPS_TLS_TPREL32 47 +#define R_MIPS_TLS_TPREL64 48 +#define R_MIPS_TLS_TPREL_HI16 49 +#define R_MIPS_TLS_TPREL_LO16 50 +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 + +#define R_MIPS_NUM 128 + +#define PT_MIPS_REGINFO 0x70000000 +#define PT_MIPS_RTPROC 0x70000001 +#define PT_MIPS_OPTIONS 0x70000002 + +#define PF_MIPS_LOCAL 0x10000000 + +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 +#define DT_MIPS_DELTA_CLASS 0x70000017 +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 + +#define DT_MIPS_DELTA_INSTANCE 0x70000019 +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a + +#define DT_MIPS_DELTA_RELOC 0x7000001b +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c + +#define DT_MIPS_DELTA_SYM 0x7000001d + +#define DT_MIPS_DELTA_SYM_NO 0x7000001e + +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 + +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 + +#define DT_MIPS_CXX_FLAGS 0x70000022 +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 +#define DT_MIPS_INTERFACE 0x7000002a +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d + +#define DT_MIPS_PERF_SUFFIX 0x7000002e + +#define DT_MIPS_COMPACT_SIZE 0x7000002f +#define DT_MIPS_GP_VALUE 0x70000030 +#define DT_MIPS_AUX_DYNAMIC 0x70000031 + +#define DT_MIPS_PLTGOT 0x70000032 + +#define DT_MIPS_RWPLT 0x70000034 +#define DT_MIPS_NUM 0x35 + +#define RHF_NONE 0 +#define RHF_QUICKSTART (1 << 0) +#define RHF_NOTPOT (1 << 1) +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +typedef struct { + Elf32_Word l_name; + Elf32_Word l_time_stamp; + Elf32_Word l_checksum; + Elf32_Word l_version; + Elf32_Word l_flags; +} Elf32_Lib; + +typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) +#define LL_IGNORE_INT_VER (1 << 1) +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +typedef Elf32_Addr Elf32_Conflict; + +#define EF_PARISC_TRAPNIL 0x00010000 +#define EF_PARISC_EXT 0x00020000 +#define EF_PARISC_LSB 0x00040000 +#define EF_PARISC_WIDE 0x00080000 +#define EF_PARISC_NO_KABP 0x00100000 + +#define EF_PARISC_LAZYSWAP 0x00400000 +#define EF_PARISC_ARCH 0x0000ffff + +#define EFA_PARISC_1_0 0x020b +#define EFA_PARISC_1_1 0x0210 +#define EFA_PARISC_2_0 0x0214 + +#define SHN_PARISC_ANSI_COMMON 0xff00 + +#define SHN_PARISC_HUGE_COMMON 0xff01 + +#define SHT_PARISC_EXT 0x70000000 +#define SHT_PARISC_UNWIND 0x70000001 +#define SHT_PARISC_DOC 0x70000002 + +#define SHF_PARISC_SHORT 0x20000000 +#define SHF_PARISC_HUGE 0x40000000 +#define SHF_PARISC_SBP 0x80000000 + +#define STT_PARISC_MILLICODE 13 + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +#define R_PARISC_NONE 0 +#define R_PARISC_DIR32 1 +#define R_PARISC_DIR21L 2 +#define R_PARISC_DIR17R 3 +#define R_PARISC_DIR17F 4 +#define R_PARISC_DIR14R 6 +#define R_PARISC_PCREL32 9 +#define R_PARISC_PCREL21L 10 +#define R_PARISC_PCREL17R 11 +#define R_PARISC_PCREL17F 12 +#define R_PARISC_PCREL14R 14 +#define R_PARISC_DPREL21L 18 +#define R_PARISC_DPREL14R 22 +#define R_PARISC_GPREL21L 26 +#define R_PARISC_GPREL14R 30 +#define R_PARISC_LTOFF21L 34 +#define R_PARISC_LTOFF14R 38 +#define R_PARISC_SECREL32 41 +#define R_PARISC_SEGBASE 48 +#define R_PARISC_SEGREL32 49 +#define R_PARISC_PLTOFF21L 50 +#define R_PARISC_PLTOFF14R 54 +#define R_PARISC_LTOFF_FPTR32 57 +#define R_PARISC_LTOFF_FPTR21L 58 +#define R_PARISC_LTOFF_FPTR14R 62 +#define R_PARISC_FPTR64 64 +#define R_PARISC_PLABEL32 65 +#define R_PARISC_PLABEL21L 66 +#define R_PARISC_PLABEL14R 70 +#define R_PARISC_PCREL64 72 +#define R_PARISC_PCREL22F 74 +#define R_PARISC_PCREL14WR 75 +#define R_PARISC_PCREL14DR 76 +#define R_PARISC_PCREL16F 77 +#define R_PARISC_PCREL16WF 78 +#define R_PARISC_PCREL16DF 79 +#define R_PARISC_DIR64 80 +#define R_PARISC_DIR14WR 83 +#define R_PARISC_DIR14DR 84 +#define R_PARISC_DIR16F 85 +#define R_PARISC_DIR16WF 86 +#define R_PARISC_DIR16DF 87 +#define R_PARISC_GPREL64 88 +#define R_PARISC_GPREL14WR 91 +#define R_PARISC_GPREL14DR 92 +#define R_PARISC_GPREL16F 93 +#define R_PARISC_GPREL16WF 94 +#define R_PARISC_GPREL16DF 95 +#define R_PARISC_LTOFF64 96 +#define R_PARISC_LTOFF14WR 99 +#define R_PARISC_LTOFF14DR 100 +#define R_PARISC_LTOFF16F 101 +#define R_PARISC_LTOFF16WF 102 +#define R_PARISC_LTOFF16DF 103 +#define R_PARISC_SECREL64 104 +#define R_PARISC_SEGREL64 112 +#define R_PARISC_PLTOFF14WR 115 +#define R_PARISC_PLTOFF14DR 116 +#define R_PARISC_PLTOFF16F 117 +#define R_PARISC_PLTOFF16WF 118 +#define R_PARISC_PLTOFF16DF 119 +#define R_PARISC_LTOFF_FPTR64 120 +#define R_PARISC_LTOFF_FPTR14WR 123 +#define R_PARISC_LTOFF_FPTR14DR 124 +#define R_PARISC_LTOFF_FPTR16F 125 +#define R_PARISC_LTOFF_FPTR16WF 126 +#define R_PARISC_LTOFF_FPTR16DF 127 +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 +#define R_PARISC_IPLT 129 +#define R_PARISC_EPLT 130 +#define R_PARISC_TPREL32 153 +#define R_PARISC_TPREL21L 154 +#define R_PARISC_TPREL14R 158 +#define R_PARISC_LTOFF_TP21L 162 +#define R_PARISC_LTOFF_TP14R 166 +#define R_PARISC_LTOFF_TP14F 167 +#define R_PARISC_TPREL64 216 +#define R_PARISC_TPREL14WR 219 +#define R_PARISC_TPREL14DR 220 +#define R_PARISC_TPREL16F 221 +#define R_PARISC_TPREL16WF 222 +#define R_PARISC_TPREL16DF 223 +#define R_PARISC_LTOFF_TP64 224 +#define R_PARISC_LTOFF_TP14WR 227 +#define R_PARISC_LTOFF_TP14DR 228 +#define R_PARISC_LTOFF_TP16F 229 +#define R_PARISC_LTOFF_TP16WF 230 +#define R_PARISC_LTOFF_TP16DF 231 +#define R_PARISC_GNU_VTENTRY 232 +#define R_PARISC_GNU_VTINHERIT 233 +#define R_PARISC_TLS_GD21L 234 +#define R_PARISC_TLS_GD14R 235 +#define R_PARISC_TLS_GDCALL 236 +#define R_PARISC_TLS_LDM21L 237 +#define R_PARISC_TLS_LDM14R 238 +#define R_PARISC_TLS_LDMCALL 239 +#define R_PARISC_TLS_LDO21L 240 +#define R_PARISC_TLS_LDO14R 241 +#define R_PARISC_TLS_DTPMOD32 242 +#define R_PARISC_TLS_DTPMOD64 243 +#define R_PARISC_TLS_DTPOFF32 244 +#define R_PARISC_TLS_DTPOFF64 245 +#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE 255 + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + +#define EF_ALPHA_32BIT 1 +#define EF_ALPHA_CANRELAX 2 + +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +#define SHF_ALPHA_GPREL 0x10000000 + +#define STO_ALPHA_NOPV 0x80 +#define STO_ALPHA_STD_GPLOAD 0x88 + +#define R_ALPHA_NONE 0 +#define R_ALPHA_REFLONG 1 +#define R_ALPHA_REFQUAD 2 +#define R_ALPHA_GPREL32 3 +#define R_ALPHA_LITERAL 4 +#define R_ALPHA_LITUSE 5 +#define R_ALPHA_GPDISP 6 +#define R_ALPHA_BRADDR 7 +#define R_ALPHA_HINT 8 +#define R_ALPHA_SREL16 9 +#define R_ALPHA_SREL32 10 +#define R_ALPHA_SREL64 11 +#define R_ALPHA_GPRELHIGH 17 +#define R_ALPHA_GPRELLOW 18 +#define R_ALPHA_GPREL16 19 +#define R_ALPHA_COPY 24 +#define R_ALPHA_GLOB_DAT 25 +#define R_ALPHA_JMP_SLOT 26 +#define R_ALPHA_RELATIVE 27 +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define R_ALPHA_NUM 46 + +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + +#define DT_ALPHA_PLTRO (DT_LOPROC + 0) +#define DT_ALPHA_NUM 1 + +#define EF_PPC_EMB 0x80000000 + +#define EF_PPC_RELOCATABLE 0x00010000 +#define EF_PPC_RELOCATABLE_LIB 0x00008000 + +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 +#define R_PPC_GOT_DTPREL16 91 +#define R_PPC_GOT_DTPREL16_LO 92 +#define R_PPC_GOT_DTPREL16_HI 93 +#define R_PPC_GOT_DTPREL16_HA 94 + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + +#define R_PPC_DIAB_SDA21_LO 180 +#define R_PPC_DIAB_SDA21_HI 181 +#define R_PPC_DIAB_SDA21_HA 182 +#define R_PPC_DIAB_RELSDA_LO 183 +#define R_PPC_DIAB_RELSDA_HI 184 +#define R_PPC_DIAB_RELSDA_HA 185 + +#define R_PPC_IRELATIVE 248 + +#define R_PPC_REL16 249 +#define R_PPC_REL16_LO 250 +#define R_PPC_REL16_HI 251 +#define R_PPC_REL16_HA 252 + +#define R_PPC_TOC16 255 + +#define DT_PPC_GOT (DT_LOPROC + 0) +#define DT_PPC_NUM 1 + +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 +#define R_PPC64_ADDR24 R_PPC_ADDR24 +#define R_PPC64_ADDR16 R_PPC_ADDR16 +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA +#define R_PPC64_ADDR14 R_PPC_ADDR14 +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 +#define R_PPC64_REL14 R_PPC_REL14 +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 +#define R_PPC64_ADDR64 38 +#define R_PPC64_ADDR16_HIGHER 39 +#define R_PPC64_ADDR16_HIGHERA 40 +#define R_PPC64_ADDR16_HIGHEST 41 +#define R_PPC64_ADDR16_HIGHESTA 42 +#define R_PPC64_UADDR64 43 +#define R_PPC64_REL64 44 +#define R_PPC64_PLT64 45 +#define R_PPC64_PLTREL64 46 +#define R_PPC64_TOC16 47 +#define R_PPC64_TOC16_LO 48 +#define R_PPC64_TOC16_HI 49 +#define R_PPC64_TOC16_HA 50 +#define R_PPC64_TOC 51 +#define R_PPC64_PLTGOT16 52 +#define R_PPC64_PLTGOT16_LO 53 +#define R_PPC64_PLTGOT16_HI 54 +#define R_PPC64_PLTGOT16_HA 55 + +#define R_PPC64_ADDR16_DS 56 +#define R_PPC64_ADDR16_LO_DS 57 +#define R_PPC64_GOT16_DS 58 +#define R_PPC64_GOT16_LO_DS 59 +#define R_PPC64_PLT16_LO_DS 60 +#define R_PPC64_SECTOFF_DS 61 +#define R_PPC64_SECTOFF_LO_DS 62 +#define R_PPC64_TOC16_DS 63 +#define R_PPC64_TOC16_LO_DS 64 +#define R_PPC64_PLTGOT16_DS 65 +#define R_PPC64_PLTGOT16_LO_DS 66 + +#define R_PPC64_TLS 67 +#define R_PPC64_DTPMOD64 68 +#define R_PPC64_TPREL16 69 +#define R_PPC64_TPREL16_LO 70 +#define R_PPC64_TPREL16_HI 71 +#define R_PPC64_TPREL16_HA 72 +#define R_PPC64_TPREL64 73 +#define R_PPC64_DTPREL16 74 +#define R_PPC64_DTPREL16_LO 75 +#define R_PPC64_DTPREL16_HI 76 +#define R_PPC64_DTPREL16_HA 77 +#define R_PPC64_DTPREL64 78 +#define R_PPC64_GOT_TLSGD16 79 +#define R_PPC64_GOT_TLSGD16_LO 80 +#define R_PPC64_GOT_TLSGD16_HI 81 +#define R_PPC64_GOT_TLSGD16_HA 82 +#define R_PPC64_GOT_TLSLD16 83 +#define R_PPC64_GOT_TLSLD16_LO 84 +#define R_PPC64_GOT_TLSLD16_HI 85 +#define R_PPC64_GOT_TLSLD16_HA 86 +#define R_PPC64_GOT_TPREL16_DS 87 +#define R_PPC64_GOT_TPREL16_LO_DS 88 +#define R_PPC64_GOT_TPREL16_HI 89 +#define R_PPC64_GOT_TPREL16_HA 90 +#define R_PPC64_GOT_DTPREL16_DS 91 +#define R_PPC64_GOT_DTPREL16_LO_DS 92 +#define R_PPC64_GOT_DTPREL16_HI 93 +#define R_PPC64_GOT_DTPREL16_HA 94 +#define R_PPC64_TPREL16_DS 95 +#define R_PPC64_TPREL16_LO_DS 96 +#define R_PPC64_TPREL16_HIGHER 97 +#define R_PPC64_TPREL16_HIGHERA 98 +#define R_PPC64_TPREL16_HIGHEST 99 +#define R_PPC64_TPREL16_HIGHESTA 100 +#define R_PPC64_DTPREL16_DS 101 +#define R_PPC64_DTPREL16_LO_DS 102 +#define R_PPC64_DTPREL16_HIGHER 103 +#define R_PPC64_DTPREL16_HIGHERA 104 +#define R_PPC64_DTPREL16_HIGHEST 105 +#define R_PPC64_DTPREL16_HIGHESTA 106 + +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 +#define R_PPC64_REL16_LO 250 +#define R_PPC64_REL16_HI 251 +#define R_PPC64_REL16_HA 252 + +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +#define EF_ARM_ABI_FLOAT_SOFT 0x200 +#define EF_ARM_ABI_FLOAT_HARD 0x400 + +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags)&EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +#define STT_ARM_TFUNC STT_LOPROC +#define STT_ARM_16BIT STT_HIPROC + +#define SHF_ARM_ENTRYSECT 0x10000000 +#define SHF_ARM_COMDEF 0x80000000 + +#define PF_ARM_SB 0x10000000 + +#define PF_ARM_PI 0x20000000 +#define PF_ARM_ABS 0x40000000 + +#define PT_ARM_EXIDX (PT_LOPROC + 1) + +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) + +#define R_AARCH64_NONE 0 +#define R_AARCH64_ABS64 257 +#define R_AARCH64_ABS32 258 +#define R_AARCH64_ABS16 259 +#define R_AARCH64_PREL64 260 +#define R_AARCH64_PREL32 261 +#define R_AARCH64_PREL16 262 +#define R_AARCH64_MOVW_UABS_G0 263 +#define R_AARCH64_MOVW_UABS_G0_NC 264 +#define R_AARCH64_MOVW_UABS_G1 265 +#define R_AARCH64_MOVW_UABS_G1_NC 266 +#define R_AARCH64_MOVW_UABS_G2 267 +#define R_AARCH64_MOVW_UABS_G2_NC 268 +#define R_AARCH64_MOVW_UABS_G3 269 +#define R_AARCH64_MOVW_SABS_G0 270 +#define R_AARCH64_MOVW_SABS_G1 271 +#define R_AARCH64_MOVW_SABS_G2 272 +#define R_AARCH64_LD_PREL_LO19 273 +#define R_AARCH64_ADR_PREL_LO21 274 +#define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 +#define R_AARCH64_ADD_ABS_LO12_NC 277 +#define R_AARCH64_LDST8_ABS_LO12_NC 278 +#define R_AARCH64_TSTBR14 279 +#define R_AARCH64_CONDBR19 280 +#define R_AARCH64_JUMP26 282 +#define R_AARCH64_CALL26 283 +#define R_AARCH64_LDST16_ABS_LO12_NC 284 +#define R_AARCH64_LDST32_ABS_LO12_NC 285 +#define R_AARCH64_LDST64_ABS_LO12_NC 286 +#define R_AARCH64_MOVW_PREL_G0 287 +#define R_AARCH64_MOVW_PREL_G0_NC 288 +#define R_AARCH64_MOVW_PREL_G1 289 +#define R_AARCH64_MOVW_PREL_G1_NC 290 +#define R_AARCH64_MOVW_PREL_G2 291 +#define R_AARCH64_MOVW_PREL_G2_NC 292 +#define R_AARCH64_MOVW_PREL_G3 293 +#define R_AARCH64_LDST128_ABS_LO12_NC 299 +#define R_AARCH64_MOVW_GOTOFF_G0 300 +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 +#define R_AARCH64_MOVW_GOTOFF_G1 302 +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 +#define R_AARCH64_MOVW_GOTOFF_G2 304 +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 +#define R_AARCH64_MOVW_GOTOFF_G3 306 +#define R_AARCH64_GOTREL64 307 +#define R_AARCH64_GOTREL32 308 +#define R_AARCH64_GOT_LD_PREL19 309 +#define R_AARCH64_LD64_GOTOFF_LO15 310 +#define R_AARCH64_ADR_GOT_PAGE 311 +#define R_AARCH64_LD64_GOT_LO12_NC 312 +#define R_AARCH64_LD64_GOTPAGE_LO15 313 +#define R_AARCH64_TLSGD_ADR_PREL21 512 +#define R_AARCH64_TLSGD_ADR_PAGE21 513 +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 +#define R_AARCH64_TLSGD_MOVW_G1 515 +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 +#define R_AARCH64_TLSLD_ADR_PREL21 517 +#define R_AARCH64_TLSLD_ADR_PAGE21 518 +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 +#define R_AARCH64_TLSLD_MOVW_G1 520 +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 +#define R_AARCH64_TLSLD_LD_PREL19 522 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 +#define R_AARCH64_TLSDESC_LD_PREL19 560 +#define R_AARCH64_TLSDESC_ADR_PREL21 561 +#define R_AARCH64_TLSDESC_ADR_PAGE21 562 +#define R_AARCH64_TLSDESC_LD64_LO12 563 +#define R_AARCH64_TLSDESC_ADD_LO12 564 +#define R_AARCH64_TLSDESC_OFF_G1 565 +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 +#define R_AARCH64_TLSDESC_LDR 567 +#define R_AARCH64_TLSDESC_ADD 568 +#define R_AARCH64_TLSDESC_CALL 569 +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 +#define R_AARCH64_COPY 1024 +#define R_AARCH64_GLOB_DAT 1025 +#define R_AARCH64_JUMP_SLOT 1026 +#define R_AARCH64_RELATIVE 1027 +#define R_AARCH64_TLS_DTPMOD64 1028 +#define R_AARCH64_TLS_DTPREL64 1029 +#define R_AARCH64_TLS_TPREL64 1030 +#define R_AARCH64_TLSDESC 1031 + +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_TLS_DESC 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 +#define R_ARM_TLS_DTPOFF32 18 +#define R_ARM_TLS_TPOFF32 19 +#define R_ARM_COPY 20 +#define R_ARM_GLOB_DAT 21 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_RELATIVE 23 +#define R_ARM_GOTOFF 24 +#define R_ARM_GOTPC 25 +#define R_ARM_GOT32 26 +#define R_ARM_PLT32 27 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_BASE_ABS 31 +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_TARGET1 38 +#define R_ARM_SBREL31 39 +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_MOVW_PREL_NC 45 +#define R_ARM_MOVT_PREL 46 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +#define R_ARM_THM_MOVW_PREL_NC 49 +#define R_ARM_THM_MOVT_PREL 50 +#define R_ARM_THM_JUMP19 51 +#define R_ARM_THM_JUMP6 52 +#define R_ARM_THM_ALU_PREL_11_0 53 +#define R_ARM_THM_PC12 54 +#define R_ARM_ABS32_NOI 55 +#define R_ARM_REL32_NOI 56 +#define R_ARM_ALU_PC_G0_NC 57 +#define R_ARM_ALU_PC_G0 58 +#define R_ARM_ALU_PC_G1_NC 59 +#define R_ARM_ALU_PC_G1 60 +#define R_ARM_ALU_PC_G2 61 +#define R_ARM_LDR_PC_G1 62 +#define R_ARM_LDR_PC_G2 63 +#define R_ARM_LDRS_PC_G0 64 +#define R_ARM_LDRS_PC_G1 65 +#define R_ARM_LDRS_PC_G2 66 +#define R_ARM_LDC_PC_G0 67 +#define R_ARM_LDC_PC_G1 68 +#define R_ARM_LDC_PC_G2 69 +#define R_ARM_ALU_SB_G0_NC 70 +#define R_ARM_ALU_SB_G0 71 +#define R_ARM_ALU_SB_G1_NC 72 +#define R_ARM_ALU_SB_G1 73 +#define R_ARM_ALU_SB_G2 74 +#define R_ARM_LDR_SB_G0 75 +#define R_ARM_LDR_SB_G1 76 +#define R_ARM_LDR_SB_G2 77 +#define R_ARM_LDRS_SB_G0 78 +#define R_ARM_LDRS_SB_G1 79 +#define R_ARM_LDRS_SB_G2 80 +#define R_ARM_LDC_SB_G0 81 +#define R_ARM_LDC_SB_G1 82 +#define R_ARM_LDC_SB_G2 83 +#define R_ARM_MOVW_BREL_NC 84 +#define R_ARM_MOVT_BREL 85 +#define R_ARM_MOVW_BREL 86 +#define R_ARM_THM_MOVW_BREL_NC 87 +#define R_ARM_THM_MOVT_BREL 88 +#define R_ARM_THM_MOVW_BREL 89 +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_PLT32_ABS 94 +#define R_ARM_GOT_ABS 95 +#define R_ARM_GOT_PREL 96 +#define R_ARM_GOT_BREL12 97 +#define R_ARM_GOTOFF12 98 +#define R_ARM_GOTRELAX 99 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 +#define R_ARM_THM_PC9 103 +#define R_ARM_TLS_GD32 104 + +#define R_ARM_TLS_LDM32 105 + +#define R_ARM_TLS_LDO32 106 + +#define R_ARM_TLS_IE32 107 + +#define R_ARM_TLS_LE32 108 +#define R_ARM_TLS_LDO12 109 +#define R_ARM_TLS_LE12 110 +#define R_ARM_TLS_IE12GP 111 +#define R_ARM_ME_TOO 128 +#define R_ARM_THM_TLS_DESCSEQ 129 +#define R_ARM_THM_TLS_DESCSEQ16 129 +#define R_ARM_THM_TLS_DESCSEQ32 130 +#define R_ARM_THM_GOT_BREL12 131 +#define R_ARM_IRELATIVE 160 +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_ARM_NUM 256 + +#define EF_IA_64_MASKOS 0x0000000f +#define EF_IA_64_ABI64 0x00000010 +#define EF_IA_64_ARCH 0xff000000 + +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) +#define PT_IA_64_UNWIND (PT_LOPROC + 1) +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +#define PF_IA_64_NORECOV 0x80000000 + +#define SHT_IA_64_EXT (SHT_LOPROC + 0) +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) + +#define SHF_IA_64_SHORT 0x10000000 +#define SHF_IA_64_NORECOV 0x20000000 + +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +#define R_IA64_NONE 0x00 +#define R_IA64_IMM14 0x21 +#define R_IA64_IMM22 0x22 +#define R_IA64_IMM64 0x23 +#define R_IA64_DIR32MSB 0x24 +#define R_IA64_DIR32LSB 0x25 +#define R_IA64_DIR64MSB 0x26 +#define R_IA64_DIR64LSB 0x27 +#define R_IA64_GPREL22 0x2a +#define R_IA64_GPREL64I 0x2b +#define R_IA64_GPREL32MSB 0x2c +#define R_IA64_GPREL32LSB 0x2d +#define R_IA64_GPREL64MSB 0x2e +#define R_IA64_GPREL64LSB 0x2f +#define R_IA64_LTOFF22 0x32 +#define R_IA64_LTOFF64I 0x33 +#define R_IA64_PLTOFF22 0x3a +#define R_IA64_PLTOFF64I 0x3b +#define R_IA64_PLTOFF64MSB 0x3e +#define R_IA64_PLTOFF64LSB 0x3f +#define R_IA64_FPTR64I 0x43 +#define R_IA64_FPTR32MSB 0x44 +#define R_IA64_FPTR32LSB 0x45 +#define R_IA64_FPTR64MSB 0x46 +#define R_IA64_FPTR64LSB 0x47 +#define R_IA64_PCREL60B 0x48 +#define R_IA64_PCREL21B 0x49 +#define R_IA64_PCREL21M 0x4a +#define R_IA64_PCREL21F 0x4b +#define R_IA64_PCREL32MSB 0x4c +#define R_IA64_PCREL32LSB 0x4d +#define R_IA64_PCREL64MSB 0x4e +#define R_IA64_PCREL64LSB 0x4f +#define R_IA64_LTOFF_FPTR22 0x52 +#define R_IA64_LTOFF_FPTR64I 0x53 +#define R_IA64_LTOFF_FPTR32MSB 0x54 +#define R_IA64_LTOFF_FPTR32LSB 0x55 +#define R_IA64_LTOFF_FPTR64MSB 0x56 +#define R_IA64_LTOFF_FPTR64LSB 0x57 +#define R_IA64_SEGREL32MSB 0x5c +#define R_IA64_SEGREL32LSB 0x5d +#define R_IA64_SEGREL64MSB 0x5e +#define R_IA64_SEGREL64LSB 0x5f +#define R_IA64_SECREL32MSB 0x64 +#define R_IA64_SECREL32LSB 0x65 +#define R_IA64_SECREL64MSB 0x66 +#define R_IA64_SECREL64LSB 0x67 +#define R_IA64_REL32MSB 0x6c +#define R_IA64_REL32LSB 0x6d +#define R_IA64_REL64MSB 0x6e +#define R_IA64_REL64LSB 0x6f +#define R_IA64_LTV32MSB 0x74 +#define R_IA64_LTV32LSB 0x75 +#define R_IA64_LTV64MSB 0x76 +#define R_IA64_LTV64LSB 0x77 +#define R_IA64_PCREL21BI 0x79 +#define R_IA64_PCREL22 0x7a +#define R_IA64_PCREL64I 0x7b +#define R_IA64_IPLTMSB 0x80 +#define R_IA64_IPLTLSB 0x81 +#define R_IA64_COPY 0x84 +#define R_IA64_SUB 0x85 +#define R_IA64_LTOFF22X 0x86 +#define R_IA64_LDXMOV 0x87 +#define R_IA64_TPREL14 0x91 +#define R_IA64_TPREL22 0x92 +#define R_IA64_TPREL64I 0x93 +#define R_IA64_TPREL64MSB 0x96 +#define R_IA64_TPREL64LSB 0x97 +#define R_IA64_LTOFF_TPREL22 0x9a +#define R_IA64_DTPMOD64MSB 0xa6 +#define R_IA64_DTPMOD64LSB 0xa7 +#define R_IA64_LTOFF_DTPMOD22 0xaa +#define R_IA64_DTPREL14 0xb1 +#define R_IA64_DTPREL22 0xb2 +#define R_IA64_DTPREL64I 0xb3 +#define R_IA64_DTPREL32MSB 0xb4 +#define R_IA64_DTPREL32LSB 0xb5 +#define R_IA64_DTPREL64MSB 0xb6 +#define R_IA64_DTPREL64LSB 0xb7 +#define R_IA64_LTOFF_DTPREL22 0xba + +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +#define R_SH_GOT20 201 +#define R_SH_GOTOFF20 202 +#define R_SH_GOTFUNCDESC 203 +#define R_SH_GOTFUNCDEST20 204 +#define R_SH_GOTOFFFUNCDESC 205 +#define R_SH_GOTOFFFUNCDEST20 206 +#define R_SH_FUNCDESC 207 +#define R_SH_FUNCDESC_VALUE 208 + +#define R_SH_NUM 256 + +#define R_390_NONE 0 +#define R_390_8 1 +#define R_390_12 2 +#define R_390_16 3 +#define R_390_32 4 +#define R_390_PC32 5 +#define R_390_GOT12 6 +#define R_390_GOT32 7 +#define R_390_PLT32 8 +#define R_390_COPY 9 +#define R_390_GLOB_DAT 10 +#define R_390_JMP_SLOT 11 +#define R_390_RELATIVE 12 +#define R_390_GOTOFF32 13 +#define R_390_GOTPC 14 +#define R_390_GOT16 15 +#define R_390_PC16 16 +#define R_390_PC16DBL 17 +#define R_390_PLT16DBL 18 +#define R_390_PC32DBL 19 +#define R_390_PLT32DBL 20 +#define R_390_GOTPCDBL 21 +#define R_390_64 22 +#define R_390_PC64 23 +#define R_390_GOT64 24 +#define R_390_PLT64 25 +#define R_390_GOTENT 26 +#define R_390_GOTOFF16 27 +#define R_390_GOTOFF64 28 +#define R_390_GOTPLT12 29 +#define R_390_GOTPLT16 30 +#define R_390_GOTPLT32 31 +#define R_390_GOTPLT64 32 +#define R_390_GOTPLTENT 33 +#define R_390_PLTOFF16 34 +#define R_390_PLTOFF32 35 +#define R_390_PLTOFF64 36 +#define R_390_TLS_LOAD 37 +#define R_390_TLS_GDCALL 38 + +#define R_390_TLS_LDCALL 39 + +#define R_390_TLS_GD32 40 + +#define R_390_TLS_GD64 41 + +#define R_390_TLS_GOTIE12 42 + +#define R_390_TLS_GOTIE32 43 + +#define R_390_TLS_GOTIE64 44 + +#define R_390_TLS_LDM32 45 + +#define R_390_TLS_LDM64 46 + +#define R_390_TLS_IE32 47 + +#define R_390_TLS_IE64 48 + +#define R_390_TLS_IEENT 49 + +#define R_390_TLS_LE32 50 + +#define R_390_TLS_LE64 51 + +#define R_390_TLS_LDO32 52 + +#define R_390_TLS_LDO64 53 + +#define R_390_TLS_DTPMOD 54 +#define R_390_TLS_DTPOFF 55 +#define R_390_TLS_TPOFF 56 + +#define R_390_20 57 +#define R_390_GOT20 58 +#define R_390_GOTPLT20 59 +#define R_390_TLS_GOTIE20 60 + +#define R_390_NUM 61 + +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 + +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DTPMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 + +#define R_X86_64_TLSLD 20 + +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 + +#define R_X86_64_TPOFF32 23 +#define R_X86_64_PC64 24 +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_GOT64 27 +#define R_X86_64_GOTPCREL64 28 +#define R_X86_64_GOTPC64 29 +#define R_X86_64_GOTPLT64 30 +#define R_X86_64_PLTOFF64 31 +#define R_X86_64_SIZE32 32 +#define R_X86_64_SIZE64 33 + +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL 35 + +#define R_X86_64_TLSDESC 36 +#define R_X86_64_IRELATIVE 37 +#define R_X86_64_RELATIVE64 38 +#define R_X86_64_NUM 39 + +#define R_MN10300_NONE 0 +#define R_MN10300_32 1 +#define R_MN10300_16 2 +#define R_MN10300_8 3 +#define R_MN10300_PCREL32 4 +#define R_MN10300_PCREL16 5 +#define R_MN10300_PCREL8 6 +#define R_MN10300_GNU_VTINHERIT 7 +#define R_MN10300_GNU_VTENTRY 8 +#define R_MN10300_24 9 +#define R_MN10300_GOTPC32 10 +#define R_MN10300_GOTPC16 11 +#define R_MN10300_GOTOFF32 12 +#define R_MN10300_GOTOFF24 13 +#define R_MN10300_GOTOFF16 14 +#define R_MN10300_PLT32 15 +#define R_MN10300_PLT16 16 +#define R_MN10300_GOT32 17 +#define R_MN10300_GOT24 18 +#define R_MN10300_GOT16 19 +#define R_MN10300_COPY 20 +#define R_MN10300_GLOB_DAT 21 +#define R_MN10300_JMP_SLOT 22 +#define R_MN10300_RELATIVE 23 + +#define R_MN10300_NUM 24 + +#define R_M32R_NONE 0 +#define R_M32R_16 1 +#define R_M32R_32 2 +#define R_M32R_24 3 +#define R_M32R_10_PCREL 4 +#define R_M32R_18_PCREL 5 +#define R_M32R_26_PCREL 6 +#define R_M32R_HI16_ULO 7 +#define R_M32R_HI16_SLO 8 +#define R_M32R_LO16 9 +#define R_M32R_SDA16 10 +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 + +#define R_M32R_16_RELA 33 +#define R_M32R_32_RELA 34 +#define R_M32R_24_RELA 35 +#define R_M32R_10_PCREL_RELA 36 +#define R_M32R_18_PCREL_RELA 37 +#define R_M32R_26_PCREL_RELA 38 +#define R_M32R_HI16_ULO_RELA 39 +#define R_M32R_HI16_SLO_RELA 40 +#define R_M32R_LO16_RELA 41 +#define R_M32R_SDA16_RELA 42 +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 +#define R_M32R_REL32 45 + +#define R_M32R_GOT24 48 +#define R_M32R_26_PLTREL 49 +#define R_M32R_COPY 50 +#define R_M32R_GLOB_DAT 51 +#define R_M32R_JMP_SLOT 52 +#define R_M32R_RELATIVE 53 +#define R_M32R_GOTOFF 54 +#define R_M32R_GOTPC24 55 +#define R_M32R_GOT16_HI_ULO 56 + +#define R_M32R_GOT16_HI_SLO 57 + +#define R_M32R_GOT16_LO 58 +#define R_M32R_GOTPC_HI_ULO 59 + +#define R_M32R_GOTPC_HI_SLO 60 + +#define R_M32R_GOTPC_LO 61 + +#define R_M32R_GOTOFF_HI_ULO 62 + +#define R_M32R_GOTOFF_HI_SLO 63 + +#define R_M32R_GOTOFF_LO 64 +#define R_M32R_NUM 256 + +#define R_MICROBLAZE_NONE 0 +#define R_MICROBLAZE_32 1 +#define R_MICROBLAZE_32_PCREL 2 +#define R_MICROBLAZE_64_PCREL 3 +#define R_MICROBLAZE_32_PCREL_LO 4 +#define R_MICROBLAZE_64 5 +#define R_MICROBLAZE_32_LO 6 +#define R_MICROBLAZE_SRO32 7 +#define R_MICROBLAZE_SRW32 8 +#define R_MICROBLAZE_64_NONE 9 +#define R_MICROBLAZE_32_SYM_OP_SYM 10 +#define R_MICROBLAZE_GNU_VTINHERIT 11 +#define R_MICROBLAZE_GNU_VTENTRY 12 +#define R_MICROBLAZE_GOTPC_64 13 +#define R_MICROBLAZE_GOT_64 14 +#define R_MICROBLAZE_PLT_64 15 +#define R_MICROBLAZE_REL 16 +#define R_MICROBLAZE_JUMP_SLOT 17 +#define R_MICROBLAZE_GLOB_DAT 18 +#define R_MICROBLAZE_GOTOFF_64 19 +#define R_MICROBLAZE_GOTOFF_32 20 +#define R_MICROBLAZE_COPY 21 +#define R_MICROBLAZE_TLS 22 +#define R_MICROBLAZE_TLSGD 23 +#define R_MICROBLAZE_TLSLD 24 +#define R_MICROBLAZE_TLSDTPMOD32 25 +#define R_MICROBLAZE_TLSDTPREL32 26 +#define R_MICROBLAZE_TLSDTPREL64 27 +#define R_MICROBLAZE_TLSGOTTPREL32 28 +#define R_MICROBLAZE_TLSTPREL32 29 + +#define R_OR1K_NONE 0 +#define R_OR1K_32 1 +#define R_OR1K_16 2 +#define R_OR1K_8 3 +#define R_OR1K_LO_16_IN_INSN 4 +#define R_OR1K_HI_16_IN_INSN 5 +#define R_OR1K_INSN_REL_26 6 +#define R_OR1K_GNU_VTENTRY 7 +#define R_OR1K_GNU_VTINHERIT 8 +#define R_OR1K_32_PCREL 9 +#define R_OR1K_16_PCREL 10 +#define R_OR1K_8_PCREL 11 +#define R_OR1K_GOTPC_HI16 12 +#define R_OR1K_GOTPC_LO16 13 +#define R_OR1K_GOT16 14 +#define R_OR1K_PLT26 15 +#define R_OR1K_GOTOFF_HI16 16 +#define R_OR1K_GOTOFF_LO16 17 +#define R_OR1K_COPY 18 +#define R_OR1K_GLOB_DAT 19 +#define R_OR1K_JMP_SLOT 20 +#define R_OR1K_RELATIVE 21 +#define R_OR1K_TLS_GD_HI16 22 +#define R_OR1K_TLS_GD_LO16 23 +#define R_OR1K_TLS_LDM_HI16 24 +#define R_OR1K_TLS_LDM_LO16 25 +#define R_OR1K_TLS_LDO_HI16 26 +#define R_OR1K_TLS_LDO_LO16 27 +#define R_OR1K_TLS_IE_HI16 28 +#define R_OR1K_TLS_IE_LO16 29 +#define R_OR1K_TLS_LE_HI16 30 +#define R_OR1K_TLS_LE_LO16 31 +#define R_OR1K_TLS_TPOFF 32 +#define R_OR1K_TLS_DTPOFF 33 +#define R_OR1K_TLS_DTPMOD 34 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/endian.h b/third_party/ulib/musl/include/endian.h new file mode 100644 index 000000000..1824563df --- /dev/null +++ b/third_party/ulib/musl/include/endian.h @@ -0,0 +1,79 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 + +#if defined(__GNUC__) && defined(__BYTE_ORDER__) +#define __BYTE_ORDER __BYTE_ORDER__ +#else +#include +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define BIG_ENDIAN __BIG_ENDIAN +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#define PDP_ENDIAN __PDP_ENDIAN +#define BYTE_ORDER __BYTE_ORDER + +#include + +static __inline uint16_t __bswap16(uint16_t __x) { + return (uint16_t)(__x << 8 | __x >> 8); +} + +static __inline uint32_t __bswap32(uint32_t __x) { + return (uint32_t)(__x >> 24 | ((__x >> 8) & 0xff00) | ((__x << 8) & 0xff0000) | __x << 24); +} + +static __inline uint64_t __bswap64(uint64_t __x) { + return ((uint64_t)__bswap32((uint32_t)__x)) << 32 | (uint64_t)__bswap32((uint32_t)(__x >> 32)); +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htobe16(x) __bswap16(x) +#define be16toh(x) __bswap16(x) +#define betoh16(x) __bswap16(x) +#define htobe32(x) __bswap32(x) +#define be32toh(x) __bswap32(x) +#define betoh32(x) __bswap32(x) +#define htobe64(x) __bswap64(x) +#define be64toh(x) __bswap64(x) +#define betoh64(x) __bswap64(x) +#define htole16(x) (uint16_t)(x) +#define le16toh(x) (uint16_t)(x) +#define letoh16(x) (uint16_t)(x) +#define htole32(x) (uint32_t)(x) +#define le32toh(x) (uint32_t)(x) +#define letoh32(x) (uint32_t)(x) +#define htole64(x) (uint64_t)(x) +#define le64toh(x) (uint64_t)(x) +#define letoh64(x) (uint64_t)(x) +#else +#define htobe16(x) (uint16_t)(x) +#define be16toh(x) (uint16_t)(x) +#define betoh16(x) (uint16_t)(x) +#define htobe32(x) (uint32_t)(x) +#define be32toh(x) (uint32_t)(x) +#define betoh32(x) (uint32_t)(x) +#define htobe64(x) (uint64_t)(x) +#define be64toh(x) (uint64_t)(x) +#define betoh64(x) (uint64_t)(x) +#define htole16(x) __bswap16(x) +#define le16toh(x) __bswap16(x) +#define letoh16(x) __bswap16(x) +#define htole32(x) __bswap32(x) +#define le32toh(x) __bswap32(x) +#define letoh32(x) __bswap32(x) +#define htole64(x) __bswap64(x) +#define le64toh(x) __bswap64(x) +#define letoh64(x) __bswap64(x) +#endif + +#endif + +#endif diff --git a/third_party/ulib/musl/include/err.h b/third_party/ulib/musl/include/err.h new file mode 100644 index 000000000..82795fe05 --- /dev/null +++ b/third_party/ulib/musl/include/err.h @@ -0,0 +1,25 @@ +#ifndef _ERR_H +#define _ERR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void warn(const char*, ...); +void vwarn(const char*, va_list); +void warnx(const char*, ...); +void vwarnx(const char*, va_list); + +_Noreturn void err(int, const char*, ...); +_Noreturn void verr(int, const char*, va_list); +_Noreturn void errx(int, const char*, ...); +_Noreturn void verrx(int, const char*, va_list); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/errno.h b/third_party/ulib/musl/include/errno.h new file mode 100644 index 000000000..18f31d23b --- /dev/null +++ b/third_party/ulib/musl/include/errno.h @@ -0,0 +1,23 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +int* __errno_location(void); +#define errno (*__errno_location()) + +#ifdef _GNU_SOURCE +extern char *program_invocation_short_name, *program_invocation_name; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/fcntl.h b/third_party/ulib/musl/include/fcntl.h new file mode 100644 index 000000000..a485a1b5e --- /dev/null +++ b/third_party/ulib/musl/include/fcntl.h @@ -0,0 +1,187 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_mode_t + +#ifdef _GNU_SOURCE +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_struct_iovec +#endif + +#include + +#include + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +int creat(const char*, mode_t); +int fcntl(int, int, ...); +int open(const char*, int, ...); +int openat(int, const char*, int, ...); +int posix_fadvise(int, off_t, off_t, int); +int posix_fallocate(int, off_t, off_t); + +#define O_SEARCH O_PATH +#define O_EXEC O_PATH + +#define O_ACCMODE (03 | O_SEARCH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_DUPFD_CLOEXEC 1030 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD (-100) +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#ifndef S_IRUSR +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXU 0700 +#define S_IRGRP 0040 +#define S_IWGRP 0020 +#define S_IXGRP 0010 +#define S_IRWXG 0070 +#define S_IROTH 0004 +#define S_IWOTH 0002 +#define S_IXOTH 0001 +#define S_IRWXO 0007 +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 + +#define FAPPEND O_APPEND +#define FFSYNC O_FSYNC +#define FASYNC O_ASYNC +#define FNONBLOCK O_NONBLOCK +#define FNDELAY O_NDELAY + +#define F_OK 0 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_ULOCK 0 +#define F_LOCK 1 +#define F_TLOCK 2 +#define F_TEST 3 + +#define F_SETLEASE 1024 +#define F_GETLEASE 1025 +#define F_NOTIFY 1026 +#define F_CANCELLK 1029 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 + +#define DN_ACCESS 0x00000001 +#define DN_MODIFY 0x00000002 +#define DN_CREATE 0x00000004 +#define DN_DELETE 0x00000008 +#define DN_RENAME 0x00000010 +#define DN_ATTRIB 0x00000020 +#define DN_MULTISHOT 0x80000000 + +int lockf(int, int, off_t); +#endif + +#if defined(_GNU_SOURCE) +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 +#define F_OWNER_GID 2 +struct f_owner_ex { + int type; + pid_t pid; +}; +#define FALLOC_FL_KEEP_SIZE 1 +#define FALLOC_FL_PUNCH_HOLE 2 +#define SYNC_FILE_RANGE_WAIT_BEFORE 1 +#define SYNC_FILE_RANGE_WRITE 2 +#define SYNC_FILE_RANGE_WAIT_AFTER 4 +#define SPLICE_F_MOVE 1 +#define SPLICE_F_NONBLOCK 2 +#define SPLICE_F_MORE 4 +#define SPLICE_F_GIFT 8 +int fallocate(int, int, off_t, off_t); +#define fallocate64 fallocate +ssize_t readahead(int, off_t, size_t); +int sync_file_range(int, off_t, off_t, unsigned); +ssize_t vmsplice(int, const struct iovec*, size_t, unsigned); +ssize_t splice(int, off_t*, int, off_t*, size_t, unsigned); +ssize_t tee(int, int, size_t, unsigned); +#define loff_t off_t +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define F_GETLK64 F_GETLK +#define F_SETLK64 F_SETLK +#define F_SETLKW64 F_SETLKW +#define flock64 flock +#define open64 open +#define openat64 openat +#define creat64 creat +#define lockf64 lockf +#define posix_fadvise64 posix_fadvise +#define posix_fallocate64 posix_fallocate +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/features.h b/third_party/ulib/musl/include/features.h new file mode 100644 index 000000000..ba4f62841 --- /dev/null +++ b/third_party/ulib/musl/include/features.h @@ -0,0 +1,35 @@ +#ifndef _FEATURES_H +#define _FEATURES_H + +#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE 1 +#endif + +#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE) +#define _BSD_SOURCE 1 +#endif + +#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE) && \ + !defined(_GNU_SOURCE) && !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__) +#define _BSD_SOURCE 1 +#define _XOPEN_SOURCE 700 +#endif + +#if __STDC_VERSION__ >= 199901L +#define __restrict restrict +#elif !defined(__GNUC__) +#define __restrict +#endif + +#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) +#define __inline inline +#endif + +#if __STDC_VERSION__ >= 201112L +#elif defined(__GNUC__) +#define _Noreturn __attribute__((__noreturn__)) +#else +#define _Noreturn +#endif + +#endif diff --git a/third_party/ulib/musl/include/fenv.h b/third_party/ulib/musl/include/fenv.h new file mode 100644 index 000000000..d045a27c7 --- /dev/null +++ b/third_party/ulib/musl/include/fenv.h @@ -0,0 +1,27 @@ +#ifndef _FENV_H +#define _FENV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int feclearexcept(int); +int fegetexceptflag(fexcept_t*, int); +int feraiseexcept(int); +int fesetexceptflag(const fexcept_t*, int); +int fetestexcept(int); + +int fegetround(void); +int fesetround(int); + +int fegetenv(fenv_t*); +int feholdexcept(fenv_t*); +int fesetenv(const fenv_t*); +int feupdateenv(const fenv_t*); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/float.h b/third_party/ulib/musl/include/float.h new file mode 100644 index 000000000..713aadb90 --- /dev/null +++ b/third_party/ulib/musl/include/float.h @@ -0,0 +1,52 @@ +#ifndef _FLOAT_H +#define _FLOAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int __flt_rounds(void); +#define FLT_ROUNDS (__flt_rounds()) + +#define FLT_RADIX 2 + +#define FLT_TRUE_MIN 1.40129846432481707092e-45F +#define FLT_MIN 1.17549435082228750797e-38F +#define FLT_MAX 3.40282346638528859812e+38F +#define FLT_EPSILON 1.1920928955078125e-07F + +#define FLT_MANT_DIG 24 +#define FLT_MIN_EXP (-125) +#define FLT_MAX_EXP 128 +#define FLT_HAS_SUBNORM 1 + +#define FLT_DIG 6 +#define FLT_DECIMAL_DIG 9 +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_10_EXP 38 + +#define DBL_TRUE_MIN 4.94065645841246544177e-324 +#define DBL_MIN 2.22507385850720138309e-308 +#define DBL_MAX 1.79769313486231570815e+308 +#define DBL_EPSILON 2.22044604925031308085e-16 + +#define DBL_MANT_DIG 53 +#define DBL_MIN_EXP (-1021) +#define DBL_MAX_EXP 1024 +#define DBL_HAS_SUBNORM 1 + +#define DBL_DIG 15 +#define DBL_DECIMAL_DIG 17 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_10_EXP 308 + +#define LDBL_HAS_SUBNORM 1 +#define LDBL_DECIMAL_DIG DECIMAL_DIG + +#include + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/fmtmsg.h b/third_party/ulib/musl/include/fmtmsg.h new file mode 100644 index 000000000..6e28040ad --- /dev/null +++ b/third_party/ulib/musl/include/fmtmsg.h @@ -0,0 +1,47 @@ +#ifndef _FMTMSG_H +#define _FMTMSG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MM_HARD 1 +#define MM_SOFT 2 +#define MM_FIRM 4 + +#define MM_APPL 8 +#define MM_UTIL 16 +#define MM_OPSYS 32 + +#define MM_RECOVER 64 +#define MM_NRECOV 128 + +#define MM_PRINT 256 +#define MM_CONSOLE 512 + +#define MM_NULLMC 0L + +#define MM_HALT 1 +#define MM_ERROR 2 +#define MM_WARNING 3 +#define MM_INFO 4 +#define MM_NOSEV 0 + +#define MM_OK 0 +#define MM_NOTOK (-1) +#define MM_NOMSG 1 +#define MM_NOCON 4 + +#define MM_NULLLBL ((char*)0) +#define MM_NULLTXT ((char*)0) +#define MM_NULLACT ((char*)0) +#define MM_NULLTAG ((char*)0) +#define MM_NULLSEV 0 + +int fmtmsg(long, const char*, int, const char*, const char*, const char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/fnmatch.h b/third_party/ulib/musl/include/fnmatch.h new file mode 100644 index 000000000..11117d703 --- /dev/null +++ b/third_party/ulib/musl/include/fnmatch.h @@ -0,0 +1,24 @@ +#ifndef _FNMATCH_H +#define _FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define FNM_PATHNAME 0x1 +#define FNM_NOESCAPE 0x2 +#define FNM_PERIOD 0x4 +#define FNM_LEADING_DIR 0x8 +#define FNM_CASEFOLD 0x10 +#define FNM_FILE_NAME FNM_PATHNAME + +#define FNM_NOMATCH 1 +#define FNM_NOSYS (-1) + +int fnmatch(const char*, const char*, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/ftw.h b/third_party/ulib/musl/include/ftw.h new file mode 100644 index 000000000..48d4d827a --- /dev/null +++ b/third_party/ulib/musl/include/ftw.h @@ -0,0 +1,41 @@ +#ifndef _FTW_H +#define _FTW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define FTW_F 1 +#define FTW_D 2 +#define FTW_DNR 3 +#define FTW_NS 4 +#define FTW_SL 5 +#define FTW_DP 6 +#define FTW_SLN 7 + +#define FTW_PHYS 1 +#define FTW_MOUNT 2 +#define FTW_CHDIR 4 +#define FTW_DEPTH 8 + +struct FTW { + int base; + int level; +}; + +int ftw(const char*, int (*)(const char*, const struct stat*, int), int); +int nftw(const char*, int (*)(const char*, const struct stat*, int, struct FTW*), int, int); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define ftw64 ftw +#define nftw64 nftw +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/getopt.h b/third_party/ulib/musl/include/getopt.h new file mode 100644 index 000000000..587d0ff68 --- /dev/null +++ b/third_party/ulib/musl/include/getopt.h @@ -0,0 +1,30 @@ +#ifndef _GETOPT_H +#define _GETOPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int getopt(int, char* const[], const char*); +extern char* optarg; +extern int optind, opterr, optopt, optreset; + +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; + +int getopt_long(int, char* const*, const char*, const struct option*, int*); +int getopt_long_only(int, char* const*, const char*, const struct option*, int*); + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/glob.h b/third_party/ulib/musl/include/glob.h new file mode 100644 index 000000000..a455be5a2 --- /dev/null +++ b/third_party/ulib/musl/include/glob.h @@ -0,0 +1,49 @@ +#ifndef _GLOB_H +#define _GLOB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t + +#include + +typedef struct { + size_t gl_pathc; + char** gl_pathv; + size_t gl_offs; + int __dummy1; + void* __dummy2[5]; +} glob_t; + +int glob(const char* __restrict, int, int (*)(const char*, int), glob_t* __restrict); +void globfree(glob_t*); + +#define GLOB_ERR 0x01 +#define GLOB_MARK 0x02 +#define GLOB_NOSORT 0x04 +#define GLOB_DOOFFS 0x08 +#define GLOB_NOCHECK 0x10 +#define GLOB_APPEND 0x20 +#define GLOB_NOESCAPE 0x40 +#define GLOB_PERIOD 0x80 + +#define GLOB_NOSPACE 1 +#define GLOB_ABORTED 2 +#define GLOB_NOMATCH 3 +#define GLOB_NOSYS 4 + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define glob64 glob +#define globfree64 globfree +#define glob64_t glob_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/grp.h b/third_party/ulib/musl/include/grp.h new file mode 100644 index 000000000..8f16b0256 --- /dev/null +++ b/third_party/ulib/musl/include/grp.h @@ -0,0 +1,51 @@ +#ifndef _GRP_H +#define _GRP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#define __NEED_gid_t + +#ifdef _GNU_SOURCE +#define __NEED_FILE +#endif + +#include + +struct group { + char* gr_name; + char* gr_passwd; + gid_t gr_gid; + char** gr_mem; +}; + +struct group* getgrgid(gid_t); +struct group* getgrnam(const char*); + +int getgrgid_r(gid_t, struct group*, char*, size_t, struct group**); +int getgrnam_r(const char*, struct group*, char*, size_t, struct group**); + +struct group* getgrent(void); +void endgrent(void); +void setgrent(void); + +#ifdef _GNU_SOURCE +struct group* fgetgrent(FILE* stream); +int putgrent(const struct group*, FILE*); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int getgrouplist(const char*, gid_t, gid_t*, int*); +int setgroups(size_t, const gid_t*); +int initgroups(const char*, gid_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/iconv.h b/third_party/ulib/musl/include/iconv.h new file mode 100644 index 000000000..a9789a740 --- /dev/null +++ b/third_party/ulib/musl/include/iconv.h @@ -0,0 +1,24 @@ +#ifndef _ICONV_H +#define _ICONV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t + +#include + +typedef void* iconv_t; + +iconv_t iconv_open(const char*, const char*); +size_t iconv(iconv_t, char** __restrict, size_t* __restrict, char** __restrict, size_t* __restrict); +int iconv_close(iconv_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/ifaddrs.h b/third_party/ulib/musl/include/ifaddrs.h new file mode 100644 index 000000000..45904a7fd --- /dev/null +++ b/third_party/ulib/musl/include/ifaddrs.h @@ -0,0 +1,34 @@ +#ifndef _IFADDRS_H +#define _IFADDRS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct ifaddrs { + struct ifaddrs* ifa_next; + char* ifa_name; + unsigned ifa_flags; + struct sockaddr* ifa_addr; + struct sockaddr* ifa_netmask; + union { + struct sockaddr* ifu_broadaddr; + struct sockaddr* ifu_dstaddr; + } ifa_ifu; + void* ifa_data; +}; +#define ifa_broadaddr ifa_ifu.ifu_broadaddr +#define ifa_dstaddr ifa_ifu.ifu_dstaddr + +void freeifaddrs(struct ifaddrs* ifp); +int getifaddrs(struct ifaddrs** ifap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/inttypes.h b/third_party/ulib/musl/include/inttypes.h new file mode 100644 index 000000000..b860b4da1 --- /dev/null +++ b/third_party/ulib/musl/include/inttypes.h @@ -0,0 +1,228 @@ +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __NEED_wchar_t +#include + +typedef struct { intmax_t quot, rem; } imaxdiv_t; + +intmax_t imaxabs(intmax_t); +imaxdiv_t imaxdiv(intmax_t, intmax_t); + +intmax_t strtoimax(const char* __restrict, char** __restrict, int); +uintmax_t strtoumax(const char* __restrict, char** __restrict, int); + +intmax_t wcstoimax(const wchar_t* __restrict, wchar_t** __restrict, int); +uintmax_t wcstoumax(const wchar_t* __restrict, wchar_t** __restrict, int); + +#if UINTPTR_MAX == UINT64_MAX +#define __PRI64 "l" +#define __PRIPTR "l" +#else +#define __PRI64 "ll" +#define __PRIPTR "" +#endif + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 __PRI64 "d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 __PRI64 "d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 __PRI64 "d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 __PRI64 "i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 __PRI64 "i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 __PRI64 "i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 __PRI64 "o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 __PRI64 "o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 __PRI64 "o" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 __PRI64 "u" + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 __PRI64 "u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 __PRI64 "u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 __PRI64 "x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 __PRI64 "x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 __PRI64 "x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 __PRI64 "X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 __PRI64 "X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 __PRI64 "X" + +#define PRIdMAX __PRI64 "d" +#define PRIiMAX __PRI64 "i" +#define PRIoMAX __PRI64 "o" +#define PRIuMAX __PRI64 "u" +#define PRIxMAX __PRI64 "x" +#define PRIXMAX __PRI64 "X" + +#define PRIdPTR __PRIPTR "d" +#define PRIiPTR __PRIPTR "i" +#define PRIoPTR __PRIPTR "o" +#define PRIuPTR __PRIPTR "u" +#define PRIxPTR __PRIPTR "x" +#define PRIXPTR __PRIPTR "X" + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 __PRI64 "d" + +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 __PRI64 "d" + +#define SCNdFAST8 "hhd" +#define SCNdFAST16 "d" +#define SCNdFAST32 "d" +#define SCNdFAST64 __PRI64 "d" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 __PRI64 "i" + +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 __PRI64 "i" + +#define SCNiFAST8 "hhi" +#define SCNiFAST16 "i" +#define SCNiFAST32 "i" +#define SCNiFAST64 __PRI64 "i" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 __PRI64 "u" + +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 __PRI64 "u" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 "u" +#define SCNuFAST32 "u" +#define SCNuFAST64 __PRI64 "u" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 __PRI64 "o" + +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 __PRI64 "o" + +#define SCNoFAST8 "hho" +#define SCNoFAST16 "o" +#define SCNoFAST32 "o" +#define SCNoFAST64 __PRI64 "o" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 __PRI64 "x" + +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 __PRI64 "x" + +#define SCNxFAST8 "hhx" +#define SCNxFAST16 "x" +#define SCNxFAST32 "x" +#define SCNxFAST64 __PRI64 "x" + +#define SCNdMAX __PRI64 "d" +#define SCNiMAX __PRI64 "i" +#define SCNoMAX __PRI64 "o" +#define SCNuMAX __PRI64 "u" +#define SCNxMAX __PRI64 "x" + +#define SCNdPTR __PRIPTR "d" +#define SCNiPTR __PRIPTR "i" +#define SCNoPTR __PRIPTR "o" +#define SCNuPTR __PRIPTR "u" +#define SCNxPTR __PRIPTR "x" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/iso646.h b/third_party/ulib/musl/include/iso646.h new file mode 100644 index 000000000..559a85670 --- /dev/null +++ b/third_party/ulib/musl/include/iso646.h @@ -0,0 +1,20 @@ +#ifndef _ISO646_H +#define _ISO646_H + +#ifndef __cplusplus + +#define and&& +#define and_eq &= +#define bitand& +#define bitor | +#define compl~ +#define not! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= + +#endif + +#endif diff --git a/third_party/ulib/musl/include/langinfo.h b/third_party/ulib/musl/include/langinfo.h new file mode 100644 index 000000000..f20a6c98c --- /dev/null +++ b/third_party/ulib/musl/include/langinfo.h @@ -0,0 +1,92 @@ +#ifndef _LANGINFO_H +#define _LANGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __NEED_locale_t + +#include + +#define ABDAY_1 0x20000 +#define ABDAY_2 0x20001 +#define ABDAY_3 0x20002 +#define ABDAY_4 0x20003 +#define ABDAY_5 0x20004 +#define ABDAY_6 0x20005 +#define ABDAY_7 0x20006 + +#define DAY_1 0x20007 +#define DAY_2 0x20008 +#define DAY_3 0x20009 +#define DAY_4 0x2000A +#define DAY_5 0x2000B +#define DAY_6 0x2000C +#define DAY_7 0x2000D + +#define ABMON_1 0x2000E +#define ABMON_2 0x2000F +#define ABMON_3 0x20010 +#define ABMON_4 0x20011 +#define ABMON_5 0x20012 +#define ABMON_6 0x20013 +#define ABMON_7 0x20014 +#define ABMON_8 0x20015 +#define ABMON_9 0x20016 +#define ABMON_10 0x20017 +#define ABMON_11 0x20018 +#define ABMON_12 0x20019 + +#define MON_1 0x2001A +#define MON_2 0x2001B +#define MON_3 0x2001C +#define MON_4 0x2001D +#define MON_5 0x2001E +#define MON_6 0x2001F +#define MON_7 0x20020 +#define MON_8 0x20021 +#define MON_9 0x20022 +#define MON_10 0x20023 +#define MON_11 0x20024 +#define MON_12 0x20025 + +#define AM_STR 0x20026 +#define PM_STR 0x20027 + +#define D_T_FMT 0x20028 +#define D_FMT 0x20029 +#define T_FMT 0x2002A +#define T_FMT_AMPM 0x2002B + +#define ERA 0x2002C +#define ERA_D_FMT 0x2002E +#define ALT_DIGITS 0x2002F +#define ERA_D_T_FMT 0x20030 +#define ERA_T_FMT 0x20031 + +#define CODESET 14 + +#define CRNCYSTR 0x4000F + +#define RADIXCHAR 0x10000 +#define THOUSEP 0x10001 +#define YESEXPR 0x50000 +#define NOEXPR 0x50001 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define YESSTR 0x50002 +#define NOSTR 0x50003 +#endif + +char* nl_langinfo(nl_item); +char* nl_langinfo_l(nl_item, locale_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/lastlog.h b/third_party/ulib/musl/include/lastlog.h new file mode 100644 index 000000000..5fa45ee47 --- /dev/null +++ b/third_party/ulib/musl/include/lastlog.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/libgen.h b/third_party/ulib/musl/include/libgen.h new file mode 100644 index 000000000..3f3fb437a --- /dev/null +++ b/third_party/ulib/musl/include/libgen.h @@ -0,0 +1,15 @@ +#ifndef _LIBGEN_H +#define _LIBGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +char* dirname(char*); +char* basename(char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/libintl.h b/third_party/ulib/musl/include/libintl.h new file mode 100644 index 000000000..9e6b2585b --- /dev/null +++ b/third_party/ulib/musl/include/libintl.h @@ -0,0 +1,33 @@ +#ifndef _LIBINTL_H +#define _LIBINTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __USE_GNU_GETTEXT 1 +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 1 : -1) + +#if __GNUC__ >= 3 +#define __fa(n) __attribute__((__format_arg__(n))) +#else +#define __fa(n) +#endif + +char* gettext(const char*) __fa(1); +char* dgettext(const char*, const char*) __fa(2); +char* dcgettext(const char*, const char*, int) __fa(2); +char* ngettext(const char*, const char*, unsigned long) __fa(1) __fa(2); +char* dngettext(const char*, const char*, const char*, unsigned long) __fa(2) __fa(3); +char* dcngettext(const char*, const char*, const char*, unsigned long, int) __fa(2) __fa(3); +char* textdomain(const char*); +char* bindtextdomain(const char*, const char*); +char* bind_textdomain_codeset(const char*, const char*); + +#undef __fa + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/limits.h b/third_party/ulib/musl/include/limits.h new file mode 100644 index 000000000..0eb89b877 --- /dev/null +++ b/third_party/ulib/musl/include/limits.h @@ -0,0 +1,154 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#include + +/* Most limits are system-specific */ + +#include + +/* Support signed or unsigned plain-char */ + +#if '\0' - 1 > 0 +#define CHAR_MIN 0 +#define CHAR_MAX 255 +#else +#define CHAR_MIN (-128) +#define CHAR_MAX 127 +#endif + +/* Some universal constants... */ + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define SHRT_MIN (-1 - 0x7fff) +#define SHRT_MAX 0x7fff +#define USHRT_MAX 0xffff +#define INT_MIN (-1 - 0x7fffffff) +#define INT_MAX 0x7fffffff +#define UINT_MAX 0xffffffffU +#define LONG_MIN (-LONG_MAX - 1) +#define ULONG_MAX (2UL * LONG_MAX + 1) +#define LLONG_MIN (-LLONG_MAX - 1) +#define ULLONG_MAX (2ULL * LLONG_MAX + 1) + +#define MB_LEN_MAX 4 + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define PIPE_BUF 4096 +#ifdef PAGE_SIZE +#define PAGESIZE PAGE_SIZE +#endif +#define FILESIZEBITS 64 +#define NAME_MAX 255 +#define SYMLINK_MAX 255 +#define PATH_MAX 4096 +#define NZERO 20 +#define NGROUPS_MAX 32 +#define ARG_MAX 131072 +#define IOV_MAX 1024 +#define SYMLOOP_MAX 40 +#define WORD_BIT 32 +#define SSIZE_MAX LONG_MAX +#define TZNAME_MAX 6 +#define TTY_NAME_MAX 32 +#define HOST_NAME_MAX 255 + +/* Implementation choices... */ + +#define PTHREAD_KEYS_MAX 128 +#define PTHREAD_STACK_MIN 2048 +#define PTHREAD_DESTRUCTOR_ITERATIONS 4 +#define SEM_VALUE_MAX 0x7fffffff +#define SEM_NSEMS_MAX 256 +#define DELAYTIMER_MAX 0x7fffffff +#define MQ_PRIO_MAX 32768 +#define LOGIN_NAME_MAX 256 + +/* Arbitrary numbers... */ + +#define BC_BASE_MAX 99 +#define BC_DIM_MAX 2048 +#define BC_SCALE_MAX 99 +#define BC_STRING_MAX 1000 +#define CHARCLASS_NAME_MAX 14 +#define COLL_WEIGHTS_MAX 2 +#define EXPR_NEST_MAX 32 +#define LINE_MAX 4096 +#define RE_DUP_MAX 255 + +#define NL_ARGMAX 9 +#define NL_LANGMAX 32 +#define NL_MSGMAX 32767 +#define NL_SETMAX 255 +#define NL_TEXTMAX 2048 + +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE + 0 < 700) + +#define NL_NMAX 16 + +#endif + +/* POSIX/SUS requirements follow. These numbers come directly + * from SUS and have nothing to do with the host system. */ + +#define _POSIX_AIO_LISTIO_MAX 2 +#define _POSIX_AIO_MAX 1 +#define _POSIX_ARG_MAX 4096 +#define _POSIX_CHILD_MAX 25 +#define _POSIX_CLOCKRES_MIN 20000000 +#define _POSIX_DELAYTIMER_MAX 32 +#define _POSIX_HOST_NAME_MAX 255 +#define _POSIX_LINK_MAX 8 +#define _POSIX_LOGIN_NAME_MAX 9 +#define _POSIX_MAX_CANON 255 +#define _POSIX_MAX_INPUT 255 +#define _POSIX_MQ_OPEN_MAX 8 +#define _POSIX_MQ_PRIO_MAX 32 +#define _POSIX_NAME_MAX 14 +#define _POSIX_NGROUPS_MAX 8 +#define _POSIX_OPEN_MAX 20 +#define _POSIX_PATH_MAX 256 +#define _POSIX_PIPE_BUF 512 +#define _POSIX_RE_DUP_MAX 255 +#define _POSIX_RTSIG_MAX 8 +#define _POSIX_SEM_NSEMS_MAX 256 +#define _POSIX_SEM_VALUE_MAX 32767 +#define _POSIX_SIGQUEUE_MAX 32 +#define _POSIX_SSIZE_MAX 32767 +#define _POSIX_STREAM_MAX 8 +#define _POSIX_SS_REPL_MAX 4 +#define _POSIX_SYMLINK_MAX 255 +#define _POSIX_SYMLOOP_MAX 8 +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +#define _POSIX_THREAD_KEYS_MAX 128 +#define _POSIX_THREAD_THREADS_MAX 64 +#define _POSIX_TIMER_MAX 32 +#define _POSIX_TRACE_EVENT_NAME_MAX 30 +#define _POSIX_TRACE_NAME_MAX 8 +#define _POSIX_TRACE_SYS_MAX 8 +#define _POSIX_TRACE_USER_EVENT_MAX 32 +#define _POSIX_TTY_NAME_MAX 9 +#define _POSIX_TZNAME_MAX 6 +#define _POSIX2_BC_BASE_MAX 99 +#define _POSIX2_BC_DIM_MAX 2048 +#define _POSIX2_BC_SCALE_MAX 99 +#define _POSIX2_BC_STRING_MAX 1000 +#define _POSIX2_CHARCLASS_NAME_MAX 14 +#define _POSIX2_COLL_WEIGHTS_MAX 2 +#define _POSIX2_EXPR_NEST_MAX 32 +#define _POSIX2_LINE_MAX 2048 +#define _POSIX2_RE_DUP_MAX 255 + +#define _XOPEN_IOV_MAX 16 +#define _XOPEN_NAME_MAX 255 +#define _XOPEN_PATH_MAX 1024 + +#endif diff --git a/third_party/ulib/musl/include/link.h b/third_party/ulib/musl/include/link.h new file mode 100644 index 000000000..ef263d7be --- /dev/null +++ b/third_party/ulib/musl/include/link.h @@ -0,0 +1,54 @@ +#ifndef _LINK_H +#define _LINK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define __NEED_size_t +#define __NEED_uint32_t +#include + +#if UINTPTR_MAX > 0xffffffff +#define ElfW(type) Elf64_##type +#else +#define ElfW(type) Elf32_##type +#endif + +/* this is the same everywhere except alpha and s390 */ +typedef uint32_t Elf_Symndx; + +struct dl_phdr_info { + ElfW(Addr) dlpi_addr; + const char* dlpi_name; + const ElfW(Phdr) * dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void* dlpi_tls_data; +}; + +struct link_map { + ElfW(Addr) l_addr; + char* l_name; + ElfW(Dyn) * l_ld; + struct link_map *l_next, *l_prev; +}; + +struct r_debug { + int r_version; + struct link_map* r_map; + ElfW(Addr) r_brk; + enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state; + ElfW(Addr) r_ldbase; +}; + +int dl_iterate_phdr(int (*)(struct dl_phdr_info*, size_t, void*), void*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/locale.h b/third_party/ulib/musl/include/locale.h new file mode 100644 index 000000000..1f54116af --- /dev/null +++ b/third_party/ulib/musl/include/locale.h @@ -0,0 +1,83 @@ +#ifndef _LOCALE_H +#define _LOCALE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define LC_CTYPE 0 +#define LC_NUMERIC 1 +#define LC_TIME 2 +#define LC_COLLATE 3 +#define LC_MONETARY 4 +#define LC_MESSAGES 5 +#define LC_ALL 6 + +struct lconv { + char* decimal_point; + char* thousands_sep; + char* grouping; + + char* int_curr_symbol; + char* currency_symbol; + char* mon_decimal_point; + char* mon_thousands_sep; + char* mon_grouping; + char* positive_sign; + char* negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; + +char* setlocale(int, const char*); +struct lconv* localeconv(void); + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define __NEED_locale_t + +#include + +#define LC_GLOBAL_LOCALE ((locale_t)-1) + +#define LC_CTYPE_MASK (1 << LC_CTYPE) +#define LC_NUMERIC_MASK (1 << LC_NUMERIC) +#define LC_TIME_MASK (1 << LC_TIME) +#define LC_COLLATE_MASK (1 << LC_COLLATE) +#define LC_MONETARY_MASK (1 << LC_MONETARY) +#define LC_MESSAGES_MASK (1 << LC_MESSAGES) +#define LC_ALL_MASK 0x7fffffff + +locale_t duplocale(locale_t); +void freelocale(locale_t); +locale_t newlocale(int, const char*, locale_t); +locale_t uselocale(locale_t); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/malloc.h b/third_party/ulib/musl/include/malloc.h new file mode 100644 index 000000000..74ccfd62d --- /dev/null +++ b/third_party/ulib/musl/include/malloc.h @@ -0,0 +1,25 @@ +#ifndef _MALLOC_H +#define _MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t + +#include + +void* malloc(size_t); +void* calloc(size_t, size_t); +void* realloc(void*, size_t); +void free(void*); +void* valloc(size_t); +void* memalign(size_t, size_t); + +size_t malloc_usable_size(void*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/math.h b/third_party/ulib/musl/include/math.h new file mode 100644 index 000000000..608b915bd --- /dev/null +++ b/third_party/ulib/musl/include/math.h @@ -0,0 +1,439 @@ +#ifndef _MATH_H +#define _MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_float_t +#define __NEED_double_t +#include + +#if 100 * __GNUC__ + __GNUC_MINOR__ >= 303 +#define NAN __builtin_nanf("") +#define INFINITY __builtin_inff() +#else +#define NAN (0.0f / 0.0f) +#define INFINITY 1e5000f +#endif + +#define HUGE_VALF INFINITY +#define HUGE_VAL ((double)INFINITY) +#define HUGE_VALL ((long double)INFINITY) + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling 2 + +#define FP_ILOGBNAN (-1 - (int)(((unsigned)-1) >> 1)) +#define FP_ILOGB0 FP_ILOGBNAN + +#define FP_NAN 0 +#define FP_INFINITE 1 +#define FP_ZERO 2 +#define FP_SUBNORMAL 3 +#define FP_NORMAL 4 + +int __fpclassify(double); +int __fpclassifyf(float); +int __fpclassifyl(long double); + +static __inline unsigned __FLOAT_BITS(float __f) { + union { + float __f; + unsigned __i; + } __u; + __u.__f = __f; + return __u.__i; +} +static __inline unsigned long long __DOUBLE_BITS(double __f) { + union { + double __f; + unsigned long long __i; + } __u; + __u.__f = __f; + return __u.__i; +} + +#define fpclassify(x) \ + (sizeof(x) == sizeof(float) ? __fpclassifyf(x) : sizeof(x) == sizeof(double) \ + ? __fpclassify(x) \ + : __fpclassifyl(x)) + +#define isinf(x) \ + (sizeof(x) == sizeof(float) \ + ? (__FLOAT_BITS(x) & 0x7fffffff) == 0x7f800000 \ + : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) == 0x7ffULL << 52 \ + : __fpclassifyl(x) == FP_INFINITE) + +#define isnan(x) \ + (sizeof(x) == sizeof(float) \ + ? (__FLOAT_BITS(x) & 0x7fffffff) > 0x7f800000 \ + : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) > 0x7ffULL << 52 \ + : __fpclassifyl(x) == FP_NAN) + +#define isnormal(x) \ + (sizeof(x) == sizeof(float) \ + ? ((__FLOAT_BITS(x) + 0x00800000) & 0x7fffffff) >= 0x01000000 \ + : sizeof(x) == sizeof(double) \ + ? ((__DOUBLE_BITS(x) + (1ULL << 52)) & -1ULL >> 1) >= 1ULL << 53 \ + : __fpclassifyl(x) == FP_NORMAL) + +#define isfinite(x) \ + (sizeof(x) == sizeof(float) \ + ? (__FLOAT_BITS(x) & 0x7fffffff) < 0x7f800000 \ + : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) < 0x7ffULL << 52 \ + : __fpclassifyl(x) > FP_INFINITE) + +int __signbit(double); +int __signbitf(float); +int __signbitl(long double); + +#define signbit(x) \ + (sizeof(x) == sizeof(float) \ + ? (int)(__FLOAT_BITS(x) >> 31) \ + : sizeof(x) == sizeof(double) ? (int)(__DOUBLE_BITS(x) >> 63) : __signbitl(x)) + +#define isunordered(x, y) (isnan((x)) ? ((void)(y), 1) : isnan((y))) + +#define __ISREL_DEF(rel, op, type) \ + static __inline int __is##rel(type __x, type __y) { \ + return !isunordered(__x, __y) && __x op __y; \ + } + +__ISREL_DEF(lessf, <, float_t) +__ISREL_DEF(less, <, double_t) +__ISREL_DEF(lessl, <, long double) +__ISREL_DEF(lessequalf, <=, float_t) +__ISREL_DEF(lessequal, <=, double_t) +__ISREL_DEF(lessequall, <=, long double) +__ISREL_DEF(lessgreaterf, !=, float_t) +__ISREL_DEF(lessgreater, !=, double_t) +__ISREL_DEF(lessgreaterl, !=, long double) +__ISREL_DEF(greaterf, >, float_t) +__ISREL_DEF(greater, >, double_t) +__ISREL_DEF(greaterl, >, long double) +__ISREL_DEF(greaterequalf, >=, float_t) +__ISREL_DEF(greaterequal, >=, double_t) +__ISREL_DEF(greaterequall, >=, long double) + +#define __tg_pred_2(x, y, p) \ + (sizeof((x) + (y)) == sizeof(float) ? p##f(x, y) : sizeof((x) + (y)) == sizeof(double) \ + ? p(x, y) \ + : p##l(x, y)) + +#define isless(x, y) __tg_pred_2(x, y, __isless) +#define islessequal(x, y) __tg_pred_2(x, y, __islessequal) +#define islessgreater(x, y) __tg_pred_2(x, y, __islessgreater) +#define isgreater(x, y) __tg_pred_2(x, y, __isgreater) +#define isgreaterequal(x, y) __tg_pred_2(x, y, __isgreaterequal) + +double acos(double); +float acosf(float); +long double acosl(long double); + +double acosh(double); +float acoshf(float); +long double acoshl(long double); + +double asin(double); +float asinf(float); +long double asinl(long double); + +double asinh(double); +float asinhf(float); +long double asinhl(long double); + +double atan(double); +float atanf(float); +long double atanl(long double); + +double atan2(double, double); +float atan2f(float, float); +long double atan2l(long double, long double); + +double atanh(double); +float atanhf(float); +long double atanhl(long double); + +double cbrt(double); +float cbrtf(float); +long double cbrtl(long double); + +double ceil(double); +float ceilf(float); +long double ceill(long double); + +double copysign(double, double); +float copysignf(float, float); +long double copysignl(long double, long double); + +double cos(double); +float cosf(float); +long double cosl(long double); + +double cosh(double); +float coshf(float); +long double coshl(long double); + +double erf(double); +float erff(float); +long double erfl(long double); + +double erfc(double); +float erfcf(float); +long double erfcl(long double); + +double exp(double); +float expf(float); +long double expl(long double); + +double exp2(double); +float exp2f(float); +long double exp2l(long double); + +double expm1(double); +float expm1f(float); +long double expm1l(long double); + +double fabs(double); +float fabsf(float); +long double fabsl(long double); + +double fdim(double, double); +float fdimf(float, float); +long double fdiml(long double, long double); + +double floor(double); +float floorf(float); +long double floorl(long double); + +double fma(double, double, double); +float fmaf(float, float, float); +long double fmal(long double, long double, long double); + +double fmax(double, double); +float fmaxf(float, float); +long double fmaxl(long double, long double); + +double fmin(double, double); +float fminf(float, float); +long double fminl(long double, long double); + +double fmod(double, double); +float fmodf(float, float); +long double fmodl(long double, long double); + +double frexp(double, int*); +float frexpf(float, int*); +long double frexpl(long double, int*); + +double hypot(double, double); +float hypotf(float, float); +long double hypotl(long double, long double); + +int ilogb(double); +int ilogbf(float); +int ilogbl(long double); + +double ldexp(double, int); +float ldexpf(float, int); +long double ldexpl(long double, int); + +double lgamma(double); +float lgammaf(float); +long double lgammal(long double); + +long long llrint(double); +long long llrintf(float); +long long llrintl(long double); + +long long llround(double); +long long llroundf(float); +long long llroundl(long double); + +double log(double); +float logf(float); +long double logl(long double); + +double log10(double); +float log10f(float); +long double log10l(long double); + +double log1p(double); +float log1pf(float); +long double log1pl(long double); + +double log2(double); +float log2f(float); +long double log2l(long double); + +double logb(double); +float logbf(float); +long double logbl(long double); + +long lrint(double); +long lrintf(float); +long lrintl(long double); + +long lround(double); +long lroundf(float); +long lroundl(long double); + +double modf(double, double*); +float modff(float, float*); +long double modfl(long double, long double*); + +double nan(const char*); +float nanf(const char*); +long double nanl(const char*); + +double nearbyint(double); +float nearbyintf(float); +long double nearbyintl(long double); + +double nextafter(double, double); +float nextafterf(float, float); +long double nextafterl(long double, long double); + +double nexttoward(double, long double); +float nexttowardf(float, long double); +long double nexttowardl(long double, long double); + +double pow(double, double); +float powf(float, float); +long double powl(long double, long double); + +double remainder(double, double); +float remainderf(float, float); +long double remainderl(long double, long double); + +double remquo(double, double, int*); +float remquof(float, float, int*); +long double remquol(long double, long double, int*); + +double rint(double); +float rintf(float); +long double rintl(long double); + +double round(double); +float roundf(float); +long double roundl(long double); + +double scalbln(double, long); +float scalblnf(float, long); +long double scalblnl(long double, long); + +double scalbn(double, int); +float scalbnf(float, int); +long double scalbnl(long double, int); + +double sin(double); +float sinf(float); +long double sinl(long double); + +double sinh(double); +float sinhf(float); +long double sinhl(long double); + +double sqrt(double); +float sqrtf(float); +long double sqrtl(long double); + +double tan(double); +float tanf(float); +long double tanl(long double); + +double tanh(double); +float tanhf(float); +long double tanhl(long double); + +double tgamma(double); +float tgammaf(float); +long double tgammal(long double); + +double trunc(double); +float truncf(float); +long double truncl(long double); + +#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) +#undef MAXFLOAT +#define MAXFLOAT 3.40282346638528859812e+38F +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log_2 e */ +#define M_LOG10E 0.43429448190325182765 /* log_10 e */ +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +extern int signgam; + +double j0(double); +double j1(double); +double jn(int, double); + +double y0(double); +double y1(double); +double yn(int, double); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define HUGE 3.40282346638528859812e+38F + +double drem(double, double); +float dremf(float, float); + +int finite(double); +int finitef(float); + +double scalb(double, double); +float scalbf(float, float); + +double significand(double); +float significandf(float); + +double lgamma_r(double, int*); +float lgammaf_r(float, int*); + +float j0f(float); +float j1f(float); +float jnf(int, float); + +float y0f(float); +float y1f(float); +float ynf(int, float); +#endif + +#ifdef _GNU_SOURCE +long double lgammal_r(long double, int*); + +void sincos(double, double*, double*); +void sincosf(float, float*, float*); +void sincosl(long double, long double*, long double*); + +double exp10(double); +float exp10f(float); +long double exp10l(long double); + +double pow10(double); +float pow10f(float); +long double pow10l(long double); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/memory.h b/third_party/ulib/musl/include/memory.h new file mode 100644 index 000000000..3b2f59002 --- /dev/null +++ b/third_party/ulib/musl/include/memory.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/mntent.h b/third_party/ulib/musl/include/mntent.h new file mode 100644 index 000000000..451356be9 --- /dev/null +++ b/third_party/ulib/musl/include/mntent.h @@ -0,0 +1,43 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_FILE +#include + +#define MOUNTED "/etc/mtab" + +#define MNTTYPE_IGNORE "ignore" +#define MNTTYPE_NFS "nfs" +#define MNTTYPE_SWAP "swap" +#define MNTOPT_DEFAULTS "defaults" +#define MNTOPT_RO "ro" +#define MNTOPT_RW "rw" +#define MNTOPT_SUID "suid" +#define MNTOPT_NOSUID "nosuid" +#define MNTOPT_NOAUTO "noauto" + +struct mntent { + char* mnt_fsname; + char* mnt_dir; + char* mnt_type; + char* mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +FILE* setmntent(const char*, const char*); +int endmntent(FILE*); +struct mntent* getmntent(FILE*); +struct mntent* getmntent_r(FILE*, struct mntent*, char*, int); +int addmntent(FILE*, const struct mntent*); +char* hasmntopt(const struct mntent*, const char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/monetary.h b/third_party/ulib/musl/include/monetary.h new file mode 100644 index 000000000..01394d70d --- /dev/null +++ b/third_party/ulib/musl/include/monetary.h @@ -0,0 +1,23 @@ +#ifndef _MONETARY_H +#define _MONETARY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_ssize_t +#define __NEED_size_t +#define __NEED_locale_t + +#include + +ssize_t strfmon(char* __restrict, size_t, const char* __restrict, ...); +ssize_t strfmon_l(char* __restrict, size_t, locale_t, const char* __restrict, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/mqueue.h b/third_party/ulib/musl/include/mqueue.h new file mode 100644 index 000000000..84f028119 --- /dev/null +++ b/third_party/ulib/musl/include/mqueue.h @@ -0,0 +1,37 @@ +#ifndef _MQUEUE_H +#define _MQUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_pthread_attr_t +#define __NEED_time_t +#define __NEED_struct_timespec +#include + +typedef int mqd_t; +struct mq_attr { + long mq_flags, mq_maxmsg, mq_msgsize, mq_curmsgs, __unused[4]; +}; +struct sigevent; + +int mq_close(mqd_t); +int mq_getattr(mqd_t, struct mq_attr*); +int mq_notify(mqd_t, const struct sigevent*); +mqd_t mq_open(const char*, int, ...); +ssize_t mq_receive(mqd_t, char*, size_t, unsigned*); +int mq_send(mqd_t, const char*, size_t, unsigned); +int mq_setattr(mqd_t, const struct mq_attr* __restrict, struct mq_attr* __restrict); +ssize_t mq_timedreceive(mqd_t, char* __restrict, size_t, unsigned* __restrict, + const struct timespec* __restrict); +int mq_timedsend(mqd_t, const char*, size_t, unsigned, const struct timespec*); +int mq_unlink(const char*); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/net/ethernet.h b/third_party/ulib/musl/include/net/ethernet.h new file mode 100644 index 000000000..b5a214a39 --- /dev/null +++ b/third_party/ulib/musl/include/net/ethernet.h @@ -0,0 +1,53 @@ +#ifndef _NET_ETHERNET_H +#define _NET_ETHERNET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct ether_addr { + uint8_t ether_addr_octet[ETH_ALEN]; +}; + +struct ether_header { + uint8_t ether_dhost[ETH_ALEN]; + uint8_t ether_shost[ETH_ALEN]; + uint16_t ether_type; +}; + +#define ETHERTYPE_PUP 0x0200 +#define ETHERTYPE_SPRITE 0x0500 +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_REVARP 0x8035 +#define ETHERTYPE_AT 0x809B +#define ETHERTYPE_AARP 0x80F3 +#define ETHERTYPE_VLAN 0x8100 +#define ETHERTYPE_IPX 0x8137 +#define ETHERTYPE_IPV6 0x86dd +#define ETHERTYPE_LOOPBACK 0x9000 + +#define ETHER_ADDR_LEN ETH_ALEN +#define ETHER_TYPE_LEN 2 +#define ETHER_CRC_LEN 4 +#define ETHER_HDR_LEN ETH_HLEN +#define ETHER_MIN_LEN (ETH_ZLEN + ETHER_CRC_LEN) +#define ETHER_MAX_LEN (ETH_FRAME_LEN + ETHER_CRC_LEN) + +#define ETHER_IS_VALID_LEN(foo) ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +#define ETHERTYPE_TRAIL 0x1000 +#define ETHERTYPE_NTRAILER 16 + +#define ETHERMTU ETH_DATA_LEN +#define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/net/if.h b/third_party/ulib/musl/include/net/if.h new file mode 100644 index 000000000..2d0389a06 --- /dev/null +++ b/third_party/ulib/musl/include/net/if.h @@ -0,0 +1,132 @@ +#ifndef _NET_IF_H +#define _NET_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define IF_NAMESIZE 16 + +struct if_nameindex { + unsigned int if_index; + char* if_name; +}; + +unsigned int if_nametoindex(const char*); +char* if_indextoname(unsigned int, char*); +struct if_nameindex* if_nameindex(void); +void if_freenameindex(struct if_nameindex*); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#include + +#define IFF_UP 0x1 +#define IFF_BROADCAST 0x2 +#define IFF_DEBUG 0x4 +#define IFF_LOOPBACK 0x8 +#define IFF_POINTOPOINT 0x10 +#define IFF_NOTRAILERS 0x20 +#define IFF_RUNNING 0x40 +#define IFF_NOARP 0x80 +#define IFF_PROMISC 0x100 +#define IFF_ALLMULTI 0x200 +#define IFF_MASTER 0x400 +#define IFF_SLAVE 0x800 +#define IFF_MULTICAST 0x1000 +#define IFF_PORTSEL 0x2000 +#define IFF_AUTOMEDIA 0x4000 +#define IFF_DYNAMIC 0x8000 +#define IFF_LOWER_UP 0x10000 +#define IFF_DORMANT 0x20000 +#define IFF_ECHO 0x40000 +#define IFF_VOLATILE \ + (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST | IFF_ECHO | IFF_MASTER | IFF_SLAVE | \ + IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT) + +struct ifaddr { + struct sockaddr ifa_addr; + union { + struct sockaddr ifu_broadaddr; + struct sockaddr ifu_dstaddr; + } ifa_ifu; + struct iface* ifa_ifp; + struct ifaddr* ifa_next; +}; + +#define ifa_broadaddr ifa_ifu.ifu_broadaddr +#define ifa_dstaddr ifa_ifu.ifu_dstaddr + +struct ifmap { + unsigned long int mem_start; + unsigned long int mem_end; + unsigned short int base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +#define IFHWADDRLEN 6 +#define IFNAMSIZ IF_NAMESIZE + +struct ifreq { + union { + char ifrn_name[IFNAMSIZ]; + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short int ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; + char ifru_newname[IFNAMSIZ]; + void* ifru_data; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name +#define ifr_hwaddr ifr_ifru.ifru_hwaddr +#define ifr_addr ifr_ifru.ifru_addr +#define ifr_dstaddr ifr_ifru.ifru_dstaddr +#define ifr_broadaddr ifr_ifru.ifru_broadaddr +#define ifr_netmask ifr_ifru.ifru_netmask +#define ifr_flags ifr_ifru.ifru_flags +#define ifr_metric ifr_ifru.ifru_ivalue +#define ifr_mtu ifr_ifru.ifru_mtu +#define ifr_map ifr_ifru.ifru_map +#define ifr_slave ifr_ifru.ifru_slave +#define ifr_data ifr_ifru.ifru_data +#define ifr_ifindex ifr_ifru.ifru_ivalue +#define ifr_bandwidth ifr_ifru.ifru_ivalue +#define ifr_qlen ifr_ifru.ifru_ivalue +#define ifr_newname ifr_ifru.ifru_newname +#define _IOT_ifreq _IOT(_IOTS(char), IFNAMSIZ, _IOTS(char), 16, 0, 0) +#define _IOT_ifreq_short _IOT(_IOTS(char), IFNAMSIZ, _IOTS(short), 1, 0, 0) +#define _IOT_ifreq_int _IOT(_IOTS(char), IFNAMSIZ, _IOTS(int), 1, 0, 0) + +struct ifconf { + int ifc_len; + union { + void* ifcu_buf; + struct ifreq* ifcu_req; + } ifc_ifcu; +}; + +#define ifc_buf ifc_ifcu.ifcu_buf +#define ifc_req ifc_ifcu.ifcu_req +#define _IOT_ifconf _IOT(_IOTS(struct ifconf), 1, 0, 0, 0, 0) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/net/if_arp.h b/third_party/ulib/musl/include/net/if_arp.h new file mode 100644 index 000000000..d605f0aac --- /dev/null +++ b/third_party/ulib/musl/include/net/if_arp.h @@ -0,0 +1,136 @@ +/* Nonstandard header */ +#ifndef _NET_IF_ARP_H +#define _NET_IF_ARP_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define MAX_ADDR_LEN 7 + +#define ARPOP_REQUEST 1 +#define ARPOP_REPLY 2 +#define ARPOP_RREQUEST 3 +#define ARPOP_RREPLY 4 +#define ARPOP_InREQUEST 8 +#define ARPOP_InREPLY 9 +#define ARPOP_NAK 10 + +struct arphdr { + uint16_t ar_hrd; + uint16_t ar_pro; + uint8_t ar_hln; + uint8_t ar_pln; + uint16_t ar_op; +}; + +#define ARPHRD_NETROM 0 +#define ARPHRD_ETHER 1 +#define ARPHRD_EETHER 2 +#define ARPHRD_AX25 3 +#define ARPHRD_PRONET 4 +#define ARPHRD_CHAOS 5 +#define ARPHRD_IEEE802 6 +#define ARPHRD_ARCNET 7 +#define ARPHRD_APPLETLK 8 +#define ARPHRD_DLCI 15 +#define ARPHRD_ATM 19 +#define ARPHRD_METRICOM 23 +#define ARPHRD_IEEE1394 24 +#define ARPHRD_EUI64 27 +#define ARPHRD_INFINIBAND 32 +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 +#define ARPHRD_ADAPT 264 +#define ARPHRD_ROSE 270 +#define ARPHRD_X25 271 +#define ARPHRD_HWX25 272 +#define ARPHRD_CAN 280 +#define ARPHRD_PPP 512 +#define ARPHRD_CISCO 513 +#define ARPHRD_HDLC ARPHRD_CISCO +#define ARPHRD_LAPB 516 +#define ARPHRD_DDCMP 517 +#define ARPHRD_RAWHDLC 518 + +#define ARPHRD_TUNNEL 768 +#define ARPHRD_TUNNEL6 769 +#define ARPHRD_FRAD 770 +#define ARPHRD_SKIP 771 +#define ARPHRD_LOOPBACK 772 +#define ARPHRD_LOCALTLK 773 +#define ARPHRD_FDDI 774 +#define ARPHRD_BIF 775 +#define ARPHRD_SIT 776 +#define ARPHRD_IPDDP 777 +#define ARPHRD_IPGRE 778 +#define ARPHRD_PIMREG 779 +#define ARPHRD_HIPPI 780 +#define ARPHRD_ASH 781 +#define ARPHRD_ECONET 782 +#define ARPHRD_IRDA 783 +#define ARPHRD_FCPP 784 +#define ARPHRD_FCAL 785 +#define ARPHRD_FCPL 786 +#define ARPHRD_FCFABRIC 787 +#define ARPHRD_IEEE802_TR 800 +#define ARPHRD_IEEE80211 801 +#define ARPHRD_IEEE80211_PRISM 802 +#define ARPHRD_IEEE80211_RADIOTAP 803 +#define ARPHRD_IEEE802154 804 +#define ARPHRD_IEEE802154_MONITOR 805 +#define ARPHRD_PHONET 820 +#define ARPHRD_PHONET_PIPE 821 +#define ARPHRD_CAIF 822 +#define ARPHRD_IP6GRE 823 +#define ARPHRD_NETLINK 824 + +#define ARPHRD_VOID 0xFFFF +#define ARPHRD_NONE 0xFFFE + +struct arpreq { + struct sockaddr arp_pa; + struct sockaddr arp_ha; + int arp_flags; + struct sockaddr arp_netmask; + char arp_dev[16]; +}; + +struct arpreq_old { + struct sockaddr arp_pa; + struct sockaddr arp_ha; + int arp_flags; + struct sockaddr arp_netmask; +}; + +#define ATF_COM 0x02 +#define ATF_PERM 0x04 +#define ATF_PUBL 0x08 +#define ATF_USETRAILERS 0x10 +#define ATF_NETMASK 0x20 +#define ATF_DONTPUB 0x40 +#define ATF_MAGIC 0x80 + +#define ARPD_UPDATE 0x01 +#define ARPD_LOOKUP 0x02 +#define ARPD_FLUSH 0x03 + +struct arpd_request { + unsigned short req; + uint32_t ip; + unsigned long dev; + unsigned long stamp; + unsigned long updated; + unsigned char ha[MAX_ADDR_LEN]; +}; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/net/route.h b/third_party/ulib/musl/include/net/route.h new file mode 100644 index 000000000..3e1bdd0f9 --- /dev/null +++ b/third_party/ulib/musl/include/net/route.h @@ -0,0 +1,119 @@ +#ifndef _NET_ROUTE_H +#define _NET_ROUTE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +struct rtentry { + unsigned long int rt_pad1; + struct sockaddr rt_dst; + struct sockaddr rt_gateway; + struct sockaddr rt_genmask; + unsigned short int rt_flags; + short int rt_pad2; + unsigned long int rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short int rt_pad4[sizeof(long) / 2 - 1]; + short int rt_metric; + char* rt_dev; + unsigned long int rt_mtu; + unsigned long int rt_window; + unsigned short int rt_irtt; +}; + +#define rt_mss rt_mtu + +struct in6_rtmsg { + struct in6_addr rtmsg_dst; + struct in6_addr rtmsg_src; + struct in6_addr rtmsg_gateway; + uint32_t rtmsg_type; + uint16_t rtmsg_dst_len; + uint16_t rtmsg_src_len; + uint32_t rtmsg_metric; + unsigned long int rtmsg_info; + uint32_t rtmsg_flags; + int rtmsg_ifindex; +}; + +#define RTF_UP 0x0001 +#define RTF_GATEWAY 0x0002 + +#define RTF_HOST 0x0004 +#define RTF_REINSTATE 0x0008 +#define RTF_DYNAMIC 0x0010 +#define RTF_MODIFIED 0x0020 +#define RTF_MTU 0x0040 +#define RTF_MSS RTF_MTU +#define RTF_WINDOW 0x0080 +#define RTF_IRTT 0x0100 +#define RTF_REJECT 0x0200 +#define RTF_STATIC 0x0400 +#define RTF_XRESOLVE 0x0800 +#define RTF_NOFORWARD 0x1000 +#define RTF_THROW 0x2000 +#define RTF_NOPMTUDISC 0x4000 + +#define RTF_DEFAULT 0x00010000 +#define RTF_ALLONLINK 0x00020000 +#define RTF_ADDRCONF 0x00040000 + +#define RTF_LINKRT 0x00100000 +#define RTF_NONEXTHOP 0x00200000 + +#define RTF_CACHE 0x01000000 +#define RTF_FLOW 0x02000000 +#define RTF_POLICY 0x04000000 + +#define RTCF_VALVE 0x00200000 +#define RTCF_MASQ 0x00400000 +#define RTCF_NAT 0x00800000 +#define RTCF_DOREDIRECT 0x01000000 +#define RTCF_LOG 0x02000000 +#define RTCF_DIRECTSRC 0x04000000 + +#define RTF_LOCAL 0x80000000 +#define RTF_INTERFACE 0x40000000 +#define RTF_MULTICAST 0x20000000 +#define RTF_BROADCAST 0x10000000 +#define RTF_NAT 0x08000000 + +#define RTF_ADDRCLASSMASK 0xF8000000 +#define RT_ADDRCLASS(flags) ((uint32_t)flags >> 23) + +#define RT_TOS(tos) ((tos)&IPTOS_TOS_MASK) + +#define RT_LOCALADDR(flags) ((flags & RTF_ADDRCLASSMASK) == (RTF_LOCAL | RTF_INTERFACE)) + +#define RT_CLASS_UNSPEC 0 +#define RT_CLASS_DEFAULT 253 + +#define RT_CLASS_MAIN 254 +#define RT_CLASS_LOCAL 255 +#define RT_CLASS_MAX 255 + +#define RTMSG_ACK NLMSG_ACK +#define RTMSG_OVERRUN NLMSG_OVERRUN + +#define RTMSG_NEWDEVICE 0x11 +#define RTMSG_DELDEVICE 0x12 +#define RTMSG_NEWROUTE 0x21 +#define RTMSG_DELROUTE 0x22 +#define RTMSG_NEWRULE 0x31 +#define RTMSG_DELRULE 0x32 +#define RTMSG_CONTROL 0x40 + +#define RTMSG_AR_FAILED 0x51 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netdb.h b/third_party/ulib/musl/include/netdb.h new file mode 100644 index 000000000..d49b61247 --- /dev/null +++ b/third_party/ulib/musl/include/netdb.h @@ -0,0 +1,155 @@ +#ifndef _NETDB_H +#define _NETDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_size_t +#include +#endif + +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr* ai_addr; + char* ai_canonname; + struct addrinfo* ai_next; +}; + +#define IPPORT_RESERVED 1024 + +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_V4MAPPED 0x08 +#define AI_ALL 0x10 +#define AI_ADDRCONFIG 0x20 +#define AI_NUMERICSERV 0x400 + +#define NI_NUMERICHOST 0x01 +#define NI_NUMERICSERV 0x02 +#define NI_NOFQDN 0x04 +#define NI_NAMEREQD 0x08 +#define NI_DGRAM 0x10 +#define NI_NUMERICSCOPE 0x100 + +#define EAI_BADFLAGS -1 +#define EAI_NONAME -2 +#define EAI_AGAIN -3 +#define EAI_FAIL -4 +#define EAI_FAMILY -6 +#define EAI_SOCKTYPE -7 +#define EAI_SERVICE -8 +#define EAI_MEMORY -10 +#define EAI_SYSTEM -11 +#define EAI_OVERFLOW -12 + +int getaddrinfo(const char* __restrict, const char* __restrict, const struct addrinfo* __restrict, + struct addrinfo** __restrict); +void freeaddrinfo(struct addrinfo*); +int getnameinfo(const struct sockaddr* __restrict, socklen_t, char* __restrict, socklen_t, + char* __restrict, socklen_t, int); +const char* gai_strerror(int); + +/* Legacy functions follow (marked OBsolete in SUS) */ + +struct netent { + char* n_name; + char** n_aliases; + int n_addrtype; + uint32_t n_net; +}; + +struct hostent { + char* h_name; + char** h_aliases; + int h_addrtype; + int h_length; + char** h_addr_list; +}; +#define h_addr h_addr_list[0] + +struct servent { + char* s_name; + char** s_aliases; + int s_port; + char* s_proto; +}; + +struct protoent { + char* p_name; + char** p_aliases; + int p_proto; +}; + +void sethostent(int); +void endhostent(void); +struct hostent* gethostent(void); + +void setnetent(int); +void endnetent(void); +struct netent* getnetent(void); +struct netent* getnetbyaddr(uint32_t, int); +struct netent* getnetbyname(const char*); + +void setservent(int); +void endservent(void); +struct servent* getservent(void); +struct servent* getservbyname(const char*, const char*); +struct servent* getservbyport(int, const char*); + +void setprotoent(int); +void endprotoent(void); +struct protoent* getprotoent(void); +struct protoent* getprotobyname(const char*); +struct protoent* getprotobynumber(int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_POSIX_SOURCE) || \ + (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE + 0 < 200809L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE + 0 < 700) +struct hostent* gethostbyname(const char*); +struct hostent* gethostbyaddr(const void*, socklen_t, int); +int* __h_errno_location(void); +#define h_errno (*__h_errno_location()) +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 +#define NO_ADDRESS NO_DATA +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +void herror(const char*); +const char* hstrerror(int); +int gethostbyname_r(const char*, struct hostent*, char*, size_t, struct hostent**, int*); +int gethostbyname2_r(const char*, int, struct hostent*, char*, size_t, struct hostent**, int*); +struct hostent* gethostbyname2(const char*, int); +int gethostbyaddr_r(const void*, socklen_t, int, struct hostent*, char*, size_t, struct hostent**, + int*); +int getservbyport_r(int, const char*, struct servent*, char*, size_t, struct servent**); +int getservbyname_r(const char*, const char*, struct servent*, char*, size_t, struct servent**); +#define EAI_NODATA -5 +#define EAI_ADDRFAMILY -9 +#define EAI_INPROGRESS -100 +#define EAI_CANCELED -101 +#define EAI_NOTCANCELED -102 +#define EAI_ALLDONE -103 +#define EAI_INTR -104 +#define EAI_IDN_ENCODE -105 +#define NI_MAXHOST 255 +#define NI_MAXSERV 32 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/ether.h b/third_party/ulib/musl/include/netinet/ether.h new file mode 100644 index 000000000..f8a8c8ded --- /dev/null +++ b/third_party/ulib/musl/include/netinet/ether.h @@ -0,0 +1,22 @@ +#ifndef _NETINET_ETHER_H +#define _NETINET_ETHER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +char* ether_ntoa(const struct ether_addr*); +struct ether_addr* ether_aton(const char*); +char* ether_ntoa_r(const struct ether_addr*, char*); +struct ether_addr* ether_aton_r(const char*, struct ether_addr*); +int ether_line(const char*, struct ether_addr*, char*); +int ether_ntohost(char*, const struct ether_addr*); +int ether_hostton(const char*, struct ether_addr*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/icmp6.h b/third_party/ulib/musl/include/netinet/icmp6.h new file mode 100644 index 000000000..12147eee3 --- /dev/null +++ b/third_party/ulib/musl/include/netinet/icmp6.h @@ -0,0 +1,303 @@ +#ifndef _NETINET_ICMP6_H +#define _NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define ICMP6_FILTER 1 + +#define ICMP6_FILTER_BLOCK 1 +#define ICMP6_FILTER_PASS 2 +#define ICMP6_FILTER_BLOCKOTHERS 3 +#define ICMP6_FILTER_PASSONLY 4 + +struct icmp6_filter { + uint32_t icmp6_filt[8]; +}; + +struct icmp6_hdr { + uint8_t icmp6_type; + uint8_t icmp6_code; + uint16_t icmp6_cksum; + union { + uint32_t icmp6_un_data32[1]; + uint16_t icmp6_un_data16[2]; + uint8_t icmp6_un_data8[4]; + } icmp6_dataun; +}; + +#define icmp6_data32 icmp6_dataun.icmp6_un_data32 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8 +#define icmp6_pptr icmp6_data32[0] +#define icmp6_mtu icmp6_data32[0] +#define icmp6_id icmp6_data16[0] +#define icmp6_seq icmp6_data16[1] +#define icmp6_maxdelay icmp6_data16[0] + +#define ICMP6_DST_UNREACH 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAM_PROB 4 + +#define ICMP6_INFOMSG_MASK 0x80 + +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 +#define MLD_LISTENER_QUERY 130 +#define MLD_LISTENER_REPORT 131 +#define MLD_LISTENER_REDUCTION 132 + +#define ICMP6_DST_UNREACH_NOROUTE 0 +#define ICMP6_DST_UNREACH_ADMIN 1 +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 +#define ICMP6_DST_UNREACH_ADDR 3 +#define ICMP6_DST_UNREACH_NOPORT 4 + +#define ICMP6_TIME_EXCEED_TRANSIT 0 +#define ICMP6_TIME_EXCEED_REASSEMBLY 1 + +#define ICMP6_PARAMPROB_HEADER 0 +#define ICMP6_PARAMPROB_NEXTHEADER 1 +#define ICMP6_PARAMPROB_OPTION 2 + +#define ICMP6_FILTER_WILLPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type)&31))) == 0) + +#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type)&31))) != 0) + +#define ICMP6_FILTER_SETPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type)&31)))) + +#define ICMP6_FILTER_SETBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type)&31)))) + +#define ICMP6_FILTER_SETPASSALL(filterp) memset(filterp, 0, sizeof(struct icmp6_filter)); + +#define ICMP6_FILTER_SETBLOCKALL(filterp) memset(filterp, 0xFF, sizeof(struct icmp6_filter)); + +#define ND_ROUTER_SOLICIT 133 +#define ND_ROUTER_ADVERT 134 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define ND_REDIRECT 137 + +struct nd_router_solicit { + struct icmp6_hdr nd_rs_hdr; +}; + +#define nd_rs_type nd_rs_hdr.icmp6_type +#define nd_rs_code nd_rs_hdr.icmp6_code +#define nd_rs_cksum nd_rs_hdr.icmp6_cksum +#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0] + +struct nd_router_advert { + struct icmp6_hdr nd_ra_hdr; + uint32_t nd_ra_reachable; + uint32_t nd_ra_retransmit; +}; + +#define nd_ra_type nd_ra_hdr.icmp6_type +#define nd_ra_code nd_ra_hdr.icmp6_code +#define nd_ra_cksum nd_ra_hdr.icmp6_cksum +#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] +#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] +#define ND_RA_FLAG_MANAGED 0x80 +#define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_HOME_AGENT 0x20 +#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] + +struct nd_neighbor_solicit { + struct icmp6_hdr nd_ns_hdr; + struct in6_addr nd_ns_target; +}; + +#define nd_ns_type nd_ns_hdr.icmp6_type +#define nd_ns_code nd_ns_hdr.icmp6_code +#define nd_ns_cksum nd_ns_hdr.icmp6_cksum +#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0] + +struct nd_neighbor_advert { + struct icmp6_hdr nd_na_hdr; + struct in6_addr nd_na_target; +}; + +#define nd_na_type nd_na_hdr.icmp6_type +#define nd_na_code nd_na_hdr.icmp6_code +#define nd_na_cksum nd_na_hdr.icmp6_cksum +#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] +#if __BYTE_ORDER == __BIG_ENDIAN +#define ND_NA_FLAG_ROUTER 0x80000000 +#define ND_NA_FLAG_SOLICITED 0x40000000 +#define ND_NA_FLAG_OVERRIDE 0x20000000 +#else +#define ND_NA_FLAG_ROUTER 0x00000080 +#define ND_NA_FLAG_SOLICITED 0x00000040 +#define ND_NA_FLAG_OVERRIDE 0x00000020 +#endif + +struct nd_redirect { + struct icmp6_hdr nd_rd_hdr; + struct in6_addr nd_rd_target; + struct in6_addr nd_rd_dst; +}; + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +struct nd_opt_hdr { + uint8_t nd_opt_type; + uint8_t nd_opt_len; +}; + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +struct nd_opt_prefix_info { + uint8_t nd_opt_pi_type; + uint8_t nd_opt_pi_len; + uint8_t nd_opt_pi_prefix_len; + uint8_t nd_opt_pi_flags_reserved; + uint32_t nd_opt_pi_valid_time; + uint32_t nd_opt_pi_preferred_time; + uint32_t nd_opt_pi_reserved2; + struct in6_addr nd_opt_pi_prefix; +}; + +#define ND_OPT_PI_FLAG_ONLINK 0x80 +#define ND_OPT_PI_FLAG_AUTO 0x40 +#define ND_OPT_PI_FLAG_RADDR 0x20 + +struct nd_opt_rd_hdr { + uint8_t nd_opt_rh_type; + uint8_t nd_opt_rh_len; + uint16_t nd_opt_rh_reserved1; + uint32_t nd_opt_rh_reserved2; +}; + +struct nd_opt_mtu { + uint8_t nd_opt_mtu_type; + uint8_t nd_opt_mtu_len; + uint16_t nd_opt_mtu_reserved; + uint32_t nd_opt_mtu_mtu; +}; + +struct mld_hdr { + struct icmp6_hdr mld_icmp6_hdr; + struct in6_addr mld_addr; +}; + +#define mld_type mld_icmp6_hdr.icmp6_type +#define mld_code mld_icmp6_hdr.icmp6_code +#define mld_cksum mld_icmp6_hdr.icmp6_cksum +#define mld_maxdelay mld_icmp6_hdr.icmp6_data16[0] +#define mld_reserved mld_icmp6_hdr.icmp6_data16[1] + +#define ICMP6_ROUTER_RENUMBERING 138 + +struct icmp6_router_renum { + struct icmp6_hdr rr_hdr; + uint8_t rr_segnum; + uint8_t rr_flags; + uint16_t rr_maxdelay; + uint32_t rr_reserved; +}; + +#define rr_type rr_hdr.icmp6_type +#define rr_code rr_hdr.icmp6_code +#define rr_cksum rr_hdr.icmp6_cksum +#define rr_seqnum rr_hdr.icmp6_data32[0] + +#define ICMP6_RR_FLAGS_TEST 0x80 +#define ICMP6_RR_FLAGS_REQRESULT 0x40 +#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20 +#define ICMP6_RR_FLAGS_SPECSITE 0x10 +#define ICMP6_RR_FLAGS_PREVDONE 0x08 + +struct rr_pco_match { + uint8_t rpm_code; + uint8_t rpm_len; + uint8_t rpm_ordinal; + uint8_t rpm_matchlen; + uint8_t rpm_minlen; + uint8_t rpm_maxlen; + uint16_t rpm_reserved; + struct in6_addr rpm_prefix; +}; + +#define RPM_PCO_ADD 1 +#define RPM_PCO_CHANGE 2 +#define RPM_PCO_SETGLOBAL 3 + +struct rr_pco_use { + uint8_t rpu_uselen; + uint8_t rpu_keeplen; + uint8_t rpu_ramask; + uint8_t rpu_raflags; + uint32_t rpu_vltime; + uint32_t rpu_pltime; + uint32_t rpu_flags; + struct in6_addr rpu_prefix; +}; + +#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x20 +#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10 + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000 +#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000 +#else +#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80 +#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40 +#endif + +struct rr_result { + uint16_t rrr_flags; + uint8_t rrr_ordinal; + uint8_t rrr_matchedlen; + uint32_t rrr_ifid; + struct in6_addr rrr_prefix; +}; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ICMP6_RR_RESULT_FLAGS_OOB 0x0002 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001 +#else +#define ICMP6_RR_RESULT_FLAGS_OOB 0x0200 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 +#endif + +struct nd_opt_adv_interval { + uint8_t nd_opt_adv_interval_type; + uint8_t nd_opt_adv_interval_len; + uint16_t nd_opt_adv_interval_reserved; + uint32_t nd_opt_adv_interval_ival; +}; + +struct nd_opt_home_agent_info { + uint8_t nd_opt_home_agent_info_type; + uint8_t nd_opt_home_agent_info_len; + uint16_t nd_opt_home_agent_info_reserved; + uint16_t nd_opt_home_agent_info_preference; + uint16_t nd_opt_home_agent_info_lifetime; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/if_ether.h b/third_party/ulib/musl/include/netinet/if_ether.h new file mode 100644 index 000000000..47d497c7c --- /dev/null +++ b/third_party/ulib/musl/include/netinet/if_ether.h @@ -0,0 +1,128 @@ +#ifndef _NETINET_IF_ETHER_H +#define _NETINET_IF_ETHER_H + +#include +#include + +#define ETH_ALEN 6 +#define ETH_HLEN 14 +#define ETH_ZLEN 60 +#define ETH_DATA_LEN 1500 +#define ETH_FRAME_LEN 1514 +#define ETH_FCS_LEN 4 + +#define ETH_P_LOOP 0x0060 +#define ETH_P_PUP 0x0200 +#define ETH_P_PUPAT 0x0201 +#define ETH_P_IP 0x0800 +#define ETH_P_X25 0x0805 +#define ETH_P_ARP 0x0806 +#define ETH_P_BPQ 0x08FF +#define ETH_P_IEEEPUP 0x0a00 +#define ETH_P_IEEEPUPAT 0x0a01 +#define ETH_P_BATMAN 0x4305 +#define ETH_P_DEC 0x6000 +#define ETH_P_DNA_DL 0x6001 +#define ETH_P_DNA_RC 0x6002 +#define ETH_P_DNA_RT 0x6003 +#define ETH_P_LAT 0x6004 +#define ETH_P_DIAG 0x6005 +#define ETH_P_CUST 0x6006 +#define ETH_P_SCA 0x6007 +#define ETH_P_TEB 0x6558 +#define ETH_P_RARP 0x8035 +#define ETH_P_ATALK 0x809B +#define ETH_P_AARP 0x80F3 +#define ETH_P_8021Q 0x8100 +#define ETH_P_IPX 0x8137 +#define ETH_P_IPV6 0x86DD +#define ETH_P_PAUSE 0x8808 +#define ETH_P_SLOW 0x8809 +#define ETH_P_WCCP 0x883E +#define ETH_P_MPLS_UC 0x8847 +#define ETH_P_MPLS_MC 0x8848 +#define ETH_P_ATMMPOA 0x884c +#define ETH_P_PPP_DISC 0x8863 +#define ETH_P_PPP_SES 0x8864 +#define ETH_P_LINK_CTL 0x886c +#define ETH_P_ATMFATE 0x8884 +#define ETH_P_PAE 0x888E +#define ETH_P_AOE 0x88A2 +#define ETH_P_8021AD 0x88A8 +#define ETH_P_802_EX1 0x88B5 +#define ETH_P_TIPC 0x88CA +#define ETH_P_8021AH 0x88E7 +#define ETH_P_MVRP 0x88F5 +#define ETH_P_1588 0x88F7 +#define ETH_P_PRP 0x88FB +#define ETH_P_FCOE 0x8906 +#define ETH_P_TDLS 0x890D +#define ETH_P_FIP 0x8914 +#define ETH_P_80221 0x8917 +#define ETH_P_LOOPBACK 0x9000 +#define ETH_P_QINQ1 0x9100 +#define ETH_P_QINQ2 0x9200 +#define ETH_P_QINQ3 0x9300 +#define ETH_P_EDSA 0xDADA +#define ETH_P_AF_IUCV 0xFBFB + +#define ETH_P_802_3_MIN 0x0600 + +#define ETH_P_802_3 0x0001 +#define ETH_P_AX25 0x0002 +#define ETH_P_ALL 0x0003 +#define ETH_P_802_2 0x0004 +#define ETH_P_SNAP 0x0005 +#define ETH_P_DDCMP 0x0006 +#define ETH_P_WAN_PPP 0x0007 +#define ETH_P_PPP_MP 0x0008 +#define ETH_P_LOCALTALK 0x0009 +#define ETH_P_CAN 0x000C +#define ETH_P_CANFD 0x000D +#define ETH_P_PPPTALK 0x0010 +#define ETH_P_TR_802_2 0x0011 +#define ETH_P_MOBITEX 0x0015 +#define ETH_P_CONTROL 0x0016 +#define ETH_P_IRDA 0x0017 +#define ETH_P_ECONET 0x0018 +#define ETH_P_HDLC 0x0019 +#define ETH_P_ARCNET 0x001A +#define ETH_P_DSA 0x001B +#define ETH_P_TRAILER 0x001C +#define ETH_P_PHONET 0x00F5 +#define ETH_P_IEEE802154 0x00F6 +#define ETH_P_CAIF 0x00F7 + +struct ethhdr { + uint8_t h_dest[ETH_ALEN]; + uint8_t h_source[ETH_ALEN]; + uint16_t h_proto; +}; + +#include +#include + +struct ether_arp { + struct arphdr ea_hdr; + uint8_t arp_sha[ETH_ALEN]; + uint8_t arp_spa[4]; + uint8_t arp_tha[ETH_ALEN]; + uint8_t arp_tpa[4]; +}; +#define arp_hrd ea_hdr.ar_hrd +#define arp_pro ea_hdr.ar_pro +#define arp_hln ea_hdr.ar_hln +#define arp_pln ea_hdr.ar_pln +#define arp_op ea_hdr.ar_op + +#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \ + do { \ + (enaddr)[0] = 0x01; \ + (enaddr)[1] = 0x00; \ + (enaddr)[2] = 0x5e; \ + (enaddr)[3] = ((uint8_t*)ipaddr)[1] & 0x7f; \ + (enaddr)[4] = ((uint8_t*)ipaddr)[2]; \ + (enaddr)[5] = ((uint8_t*)ipaddr)[3]; \ + } while (0) + +#endif diff --git a/third_party/ulib/musl/include/netinet/igmp.h b/third_party/ulib/musl/include/netinet/igmp.h new file mode 100644 index 000000000..dd8b377a1 --- /dev/null +++ b/third_party/ulib/musl/include/netinet/igmp.h @@ -0,0 +1,45 @@ +#ifndef _NETINET_IGMP_H +#define _NETINET_IGMP_H + +#include +#include + +struct igmp { + uint8_t igmp_type; + uint8_t igmp_code; + uint16_t igmp_cksum; + struct in_addr igmp_group; +}; + +#define IGMP_MINLEN 8 + +#define IGMP_MEMBERSHIP_QUERY 0x11 +#define IGMP_V1_MEMBERSHIP_REPORT 0x12 +#define IGMP_V2_MEMBERSHIP_REPORT 0x16 +#define IGMP_V2_LEAVE_GROUP 0x17 + +#define IGMP_DVMRP 0x13 +#define IGMP_PIM 0x14 +#define IGMP_TRACE 0x15 + +#define IGMP_MTRACE_RESP 0x1e +#define IGMP_MTRACE 0x1f + +#define IGMP_MAX_HOST_REPORT_DELAY 10 +#define IGMP_TIMER_SCALE 10 + +#define IGMP_DELAYING_MEMBER 1 +#define IGMP_IDLE_MEMBER 2 +#define IGMP_LAZY_MEMBER 3 +#define IGMP_SLEEPING_MEMBER 4 +#define IGMP_AWAKENING_MEMBER 5 + +#define IGMP_v1_ROUTER 1 +#define IGMP_v2_ROUTER 2 + +#define IGMP_HOST_MEMBERSHIP_QUERY IGMP_MEMBERSHIP_QUERY +#define IGMP_HOST_MEMBERSHIP_REPORT IGMP_V1_MEMBERSHIP_REPORT +#define IGMP_HOST_NEW_MEMBERSHIP_REPORT IGMP_V2_MEMBERSHIP_REPORT +#define IGMP_HOST_LEAVE_MESSAGE IGMP_V2_LEAVE_GROUP + +#endif diff --git a/third_party/ulib/musl/include/netinet/in.h b/third_party/ulib/musl/include/netinet/in.h new file mode 100644 index 000000000..16a6bb23c --- /dev/null +++ b/third_party/ulib/musl/include/netinet/in.h @@ -0,0 +1,397 @@ +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t sin_zero[8]; +}; + +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_NONE ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) + +#define INADDR_UNSPEC_GROUP ((in_addr_t)0xe0000000) +#define INADDR_ALLHOSTS_GROUP ((in_addr_t)0xe0000001) +#define INADDR_ALLRTRS_GROUP ((in_addr_t)0xe0000002) +#define INADDR_MAX_LOCAL_GROUP ((in_addr_t)0xe00000ff) + +#define IN6ADDR_ANY_INIT \ + { \ + { \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } \ + } \ + } +#define IN6ADDR_LOOPBACK_INIT \ + { \ + { \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } \ + } \ + } + +extern const struct in6_addr in6addr_any, in6addr_loopback; + +#undef INET_ADDRSTRLEN +#undef INET6_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_IPIP 4 +#define IPPROTO_TCP 6 +#define IPPROTO_EGP 8 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_TP 29 +#define IPPROTO_DCCP 33 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_RSVP 46 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_MTP 92 +#define IPPROTO_BEETPH 94 +#define IPPROTO_ENCAP 98 +#define IPPROTO_PIM 103 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_MH 135 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MPLS 137 +#define IPPROTO_RAW 255 +#define IPPROTO_MAX 256 + +#define IN6_IS_ADDR_UNSPECIFIED(a) \ + (((uint32_t*)(a))[0] == 0 && ((uint32_t*)(a))[1] == 0 && ((uint32_t*)(a))[2] == 0 && \ + ((uint32_t*)(a))[3] == 0) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((uint32_t*)(a))[0] == 0 && ((uint32_t*)(a))[1] == 0 && ((uint32_t*)(a))[2] == 0 && \ + ((uint8_t*)(a))[12] == 0 && ((uint8_t*)(a))[13] == 0 && ((uint8_t*)(a))[14] == 0 && \ + ((uint8_t*)(a))[15] == 1) + +#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t*)(a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((uint8_t*)(a))[0]) == 0xfe && (((uint8_t*)(a))[1] & 0xc0) == 0x80) + +#define IN6_IS_ADDR_SITELOCAL(a) \ + ((((uint8_t*)(a))[0]) == 0xfe && (((uint8_t*)(a))[1] & 0xc0) == 0xc0) + +#define IN6_IS_ADDR_V4MAPPED(a) \ + (((uint32_t*)(a))[0] == 0 && ((uint32_t*)(a))[1] == 0 && ((uint8_t*)(a))[8] == 0 && \ + ((uint8_t*)(a))[9] == 0 && ((uint8_t*)(a))[10] == 0xff && ((uint8_t*)(a))[11] == 0xff) + +#define IN6_IS_ADDR_V4COMPAT(a) \ + (((uint32_t*)(a))[0] == 0 && ((uint32_t*)(a))[1] == 0 && ((uint32_t*)(a))[2] == 0 && \ + ((uint8_t*)(a))[15] > 1) + +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t*)(a))[1] & 0xf) == 0x1)) + +#define IN6_IS_ADDR_MC_LINKLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t*)(a))[1] & 0xf) == 0x2)) + +#define IN6_IS_ADDR_MC_SITELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t*)(a))[1] & 0xf) == 0x5)) + +#define IN6_IS_ADDR_MC_ORGLOCAL(a) (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t*)(a))[1] & 0xf) == 0x8)) + +#define IN6_IS_ADDR_MC_GLOBAL(a) (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t*)(a))[1] & 0xf) == 0xe)) + +#define __ARE_4_EQUAL(a, b) \ + (!((0 [a] - 0 [b]) | (1 [a] - 1 [b]) | (2 [a] - 2 [b]) | (3 [a] - 3 [b]))) +#define IN6_ARE_ADDR_EQUAL(a, b) __ARE_4_EQUAL((const uint32_t*)(a), (const uint32_t*)(b)) + +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_ROUTER_ALERT 5 +#define IP_RECVOPTS 6 +#define IP_RETOPTS 7 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_PMTUDISC 10 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_RECVTOS 13 +#define IP_MTU 14 +#define IP_FREEBIND 15 +#define IP_IPSEC_POLICY 16 +#define IP_XFRM_POLICY 17 +#define IP_PASSSEC 18 +#define IP_TRANSPARENT 19 +#define IP_ORIGDSTADDR 20 +#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR +#define IP_MINTTL 21 +#define IP_NODEFRAG 22 +#define IP_CHECKSUM 23 +#define IP_BIND_ADDRESS_NO_PORT 24 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_MSFILTER 41 +#define IP_MULTICAST_ALL 49 +#define IP_UNICAST_IF 50 + +#define IP_RECVRETOPTS IP_RETOPTS + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_WANT 1 +#define IP_PMTUDISC_DO 2 +#define IP_PMTUDISC_PROBE 3 +#define IP_PMTUDISC_INTERFACE 4 +#define IP_PMTUDISC_OMIT 5 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_DEFAULT_MULTICAST_LOOP 1 +#define IP_MAX_MEMBERSHIPS 20 + +struct ip_opts { + struct in_addr ip_dst; + char ip_opts[40]; +}; + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_LEAVE_GROUP 45 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 +#define MCAST_MSFILTER 48 + +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; + uint32_t imsf_fmode; + uint32_t imsf_numsrc; + struct in_addr imsf_slist[1]; +}; +#define IP_MSFILTER_SIZE(numsrc) \ + (sizeof(struct ip_msfilter) - sizeof(struct in_addr) + (numsrc) * sizeof(struct in_addr)) + +struct group_req { + uint32_t gr_interface; + struct sockaddr_storage gr_group; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +struct group_filter { + uint32_t gf_interface; + struct sockaddr_storage gf_group; + uint32_t gf_fmode; + uint32_t gf_numsrc; + struct sockaddr_storage gf_slist[1]; +}; +#define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct sockaddr_storage) + \ + (numsrc) * sizeof(struct sockaddr_storage)) + +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + unsigned ipi6_ifindex; +}; + +struct ip6_mtuinfo { + struct sockaddr_in6 ip6m_addr; + uint32_t ip6m_mtu; +}; +#endif + +#define IPV6_ADDRFORM 1 +#define IPV6_2292PKTINFO 2 +#define IPV6_2292HOPOPTS 3 +#define IPV6_2292DSTOPTS 4 +#define IPV6_2292RTHDR 5 +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_CHECKSUM 7 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_NEXTHOP 9 +#define IPV6_AUTHHDR 10 +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_ROUTER_ALERT 22 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_JOIN_ANYCAST 27 +#define IPV6_LEAVE_ANYCAST 28 +#define IPV6_IPSEC_POLICY 34 +#define IPV6_XFRM_POLICY 35 +#define IPV6_HDRINCL 36 + +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_RECVHOPOPTS 53 +#define IPV6_HOPOPTS 54 +#define IPV6_RTHDRDSTOPTS 55 +#define IPV6_RECVRTHDR 56 +#define IPV6_RTHDR 57 +#define IPV6_RECVDSTOPTS 58 +#define IPV6_DSTOPTS 59 +#define IPV6_RECVPATHMTU 60 +#define IPV6_PATHMTU 61 +#define IPV6_DONTFRAG 62 +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 +#define IPV6_AUTOFLOWLABEL 70 +#define IPV6_ADDR_PREFERENCES 72 +#define IPV6_MINHOPCOUNT 73 +#define IPV6_ORIGDSTADDR 74 +#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR +#define IPV6_TRANSPARENT 75 +#define IPV6_UNICAST_IF 76 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#define IPV6_RXHOPOPTS IPV6_HOPOPTS +#define IPV6_RXDSTOPTS IPV6_DSTOPTS + +#define IPV6_PMTUDISC_DONT 0 +#define IPV6_PMTUDISC_WANT 1 +#define IPV6_PMTUDISC_DO 2 +#define IPV6_PMTUDISC_PROBE 3 +#define IPV6_PMTUDISC_INTERFACE 4 +#define IPV6_PMTUDISC_OMIT 5 + +#define IPV6_PREFER_SRC_TMP 0x0001 +#define IPV6_PREFER_SRC_PUBLIC 0x0002 +#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 +#define IPV6_PREFER_SRC_COA 0x0004 +#define IPV6_PREFER_SRC_HOME 0x0400 +#define IPV6_PREFER_SRC_CGA 0x0008 +#define IPV6_PREFER_SRC_NONCGA 0x0800 + +#define IPV6_RTHDR_LOOSE 0 +#define IPV6_RTHDR_STRICT 1 + +#define IPV6_RTHDR_TYPE_0 0 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/in_systm.h b/third_party/ulib/musl/include/netinet/in_systm.h new file mode 100644 index 000000000..a7b417722 --- /dev/null +++ b/third_party/ulib/musl/include/netinet/in_systm.h @@ -0,0 +1,9 @@ +#ifndef _NETINET_IN_SYSTM_H +#define _NETINET_IN_SYSTM_H + +#include + +typedef uint16_t n_short; +typedef uint32_t n_long, n_time; + +#endif diff --git a/third_party/ulib/musl/include/netinet/ip.h b/third_party/ulib/musl/include/netinet/ip.h new file mode 100644 index 000000000..fcaa988dc --- /dev/null +++ b/third_party/ulib/musl/include/netinet/ip.h @@ -0,0 +1,198 @@ +#ifndef _NETINET_IP_H +#define _NETINET_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct timestamp { + uint8_t len; + uint8_t ptr; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int flags : 4; + unsigned int overflow : 4; +#else + unsigned int overflow : 4; + unsigned int flags : 4; +#endif + uint32_t data[9]; +}; + +struct iphdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ihl : 4; + unsigned int version : 4; +#else + unsigned int version : 4; + unsigned int ihl : 4; +#endif + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; +}; + +struct ip { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ip_hl : 4; + unsigned int ip_v : 4; +#else + unsigned int ip_v : 4; + unsigned int ip_hl : 4; +#endif + uint8_t ip_tos; + uint16_t ip_len; + uint16_t ip_id; + uint16_t ip_off; + uint8_t ip_ttl; + uint8_t ip_p; + uint16_t ip_sum; + struct in_addr ip_src, ip_dst; +}; + +#define IP_RF 0x8000 +#define IP_DF 0x4000 +#define IP_MF 0x2000 +#define IP_OFFMASK 0x1fff + +struct ip_timestamp { + uint8_t ipt_code; + uint8_t ipt_len; + uint8_t ipt_ptr; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ipt_flg : 4; + unsigned int ipt_oflw : 4; +#else + unsigned int ipt_oflw : 4; + unsigned int ipt_flg : 4; +#endif + uint32_t data[9]; +}; + +#define IPVERSION 4 +#define IP_MAXPACKET 65535 + +#define IPTOS_ECN_MASK 0x03 +#define IPTOS_ECN(x) ((x)&IPTOS_ECN_MASK) +#define IPTOS_ECN_NOT_ECT 0x00 +#define IPTOS_ECN_ECT1 0x01 +#define IPTOS_ECN_ECT0 0x02 +#define IPTOS_ECN_CE 0x03 + +#define IPTOS_DSCP_MASK 0xfc +#define IPTOS_DSCP(x) ((x)&IPTOS_DSCP_MASK) +#define IPTOS_DSCP_AF11 0x28 +#define IPTOS_DSCP_AF12 0x30 +#define IPTOS_DSCP_AF13 0x38 +#define IPTOS_DSCP_AF21 0x48 +#define IPTOS_DSCP_AF22 0x50 +#define IPTOS_DSCP_AF23 0x58 +#define IPTOS_DSCP_AF31 0x68 +#define IPTOS_DSCP_AF32 0x70 +#define IPTOS_DSCP_AF33 0x78 +#define IPTOS_DSCP_AF41 0x88 +#define IPTOS_DSCP_AF42 0x90 +#define IPTOS_DSCP_AF43 0x98 +#define IPTOS_DSCP_EF 0xb8 + +#define IPTOS_CLASS_MASK 0xe0 +#define IPTOS_CLASS(x) ((x)&IPTOS_CLASS_MASK) +#define IPTOS_CLASS_CS0 0x00 +#define IPTOS_CLASS_CS1 0x20 +#define IPTOS_CLASS_CS2 0x40 +#define IPTOS_CLASS_CS3 0x60 +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS5 0xa0 +#define IPTOS_CLASS_CS6 0xc0 +#define IPTOS_CLASS_CS7 0xe0 +#define IPTOS_CLASS_DEFAULT IPTOS_CLASS_CS0 + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + +#define IPOPT_COPY 0x80 +#define IPOPT_CLASS_MASK 0x60 +#define IPOPT_NUMBER_MASK 0x1f + +#define IPOPT_COPIED(o) ((o)&IPOPT_COPY) +#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) +#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_MEASUREMENT IPOPT_DEBMEAS +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 +#define IPOPT_END IPOPT_EOL +#define IPOPT_NOP 1 +#define IPOPT_NOOP IPOPT_NOP + +#define IPOPT_RR 7 +#define IPOPT_TS 68 +#define IPOPT_TIMESTAMP IPOPT_TS +#define IPOPT_SECURITY 130 +#define IPOPT_SEC IPOPT_SECURITY +#define IPOPT_LSRR 131 +#define IPOPT_SATID 136 +#define IPOPT_SID IPOPT_SATID +#define IPOPT_SSRR 137 +#define IPOPT_RA 148 + +#define IPOPT_OPTVAL 0 +#define IPOPT_OLEN 1 +#define IPOPT_OFFSET 2 +#define IPOPT_MINOFF 4 + +#define MAX_IPOPTLEN 40 + +#define IPOPT_TS_TSONLY 0 +#define IPOPT_TS_TSANDADDR 1 +#define IPOPT_TS_PRESPEC 3 + +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +#define MAXTTL 255 +#define IPDEFTTL 64 +#define IPFRAGTTL 60 +#define IPTTLDEC 1 + +#define IP_MSS 576 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/ip6.h b/third_party/ulib/musl/include/netinet/ip6.h new file mode 100644 index 000000000..773d4ac1f --- /dev/null +++ b/third_party/ulib/musl/include/netinet/ip6.h @@ -0,0 +1,142 @@ +#ifndef _NETINET_IP6_H +#define _NETINET_IP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct ip6_hdr { + union { + struct ip6_hdrctl { + uint32_t ip6_un1_flow; + uint16_t ip6_un1_plen; + uint8_t ip6_un1_nxt; + uint8_t ip6_un1_hlim; + } ip6_un1; + uint8_t ip6_un2_vfc; + } ip6_ctlun; + struct in6_addr ip6_src; + struct in6_addr ip6_dst; +}; + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +struct ip6_ext { + uint8_t ip6e_nxt; + uint8_t ip6e_len; +}; + +struct ip6_hbh { + uint8_t ip6h_nxt; + uint8_t ip6h_len; +}; + +struct ip6_dest { + uint8_t ip6d_nxt; + uint8_t ip6d_len; +}; + +struct ip6_rthdr { + uint8_t ip6r_nxt; + uint8_t ip6r_len; + uint8_t ip6r_type; + uint8_t ip6r_segleft; +}; + +struct ip6_rthdr0 { + uint8_t ip6r0_nxt; + uint8_t ip6r0_len; + uint8_t ip6r0_type; + uint8_t ip6r0_segleft; + uint8_t ip6r0_reserved; + uint8_t ip6r0_slmap[3]; + struct in6_addr ip6r0_addr[]; +}; + +struct ip6_frag { + uint8_t ip6f_nxt; + uint8_t ip6f_reserved; + uint16_t ip6f_offlg; + uint32_t ip6f_ident; +}; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define IP6F_OFF_MASK 0xfff8 +#define IP6F_RESERVED_MASK 0x0006 +#define IP6F_MORE_FRAG 0x0001 +#else +#define IP6F_OFF_MASK 0xf8ff +#define IP6F_RESERVED_MASK 0x0600 +#define IP6F_MORE_FRAG 0x0100 +#endif + +struct ip6_opt { + uint8_t ip6o_type; + uint8_t ip6o_len; +}; + +#define IP6OPT_TYPE(o) ((o)&0xc0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xc0 +#define IP6OPT_TYPE_MUTABLE 0x20 + +#define IP6OPT_PAD1 0 +#define IP6OPT_PADN 1 + +#define IP6OPT_JUMBO 0xc2 +#define IP6OPT_NSAP_ADDR 0xc3 +#define IP6OPT_TUNNEL_LIMIT 0x04 +#define IP6OPT_ROUTER_ALERT 0x05 + +struct ip6_opt_jumbo { + uint8_t ip6oj_type; + uint8_t ip6oj_len; + uint8_t ip6oj_jumbo_len[4]; +}; +#define IP6OPT_JUMBO_LEN 6 + +struct ip6_opt_nsap { + uint8_t ip6on_type; + uint8_t ip6on_len; + uint8_t ip6on_src_nsap_len; + uint8_t ip6on_dst_nsap_len; +}; + +struct ip6_opt_tunnel { + uint8_t ip6ot_type; + uint8_t ip6ot_len; + uint8_t ip6ot_encap_limit; +}; + +struct ip6_opt_router { + uint8_t ip6or_type; + uint8_t ip6or_len; + uint8_t ip6or_value[2]; +}; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define IP6_ALERT_MLD 0x0000 +#define IP6_ALERT_RSVP 0x0001 +#define IP6_ALERT_AN 0x0002 +#else +#define IP6_ALERT_MLD 0x0000 +#define IP6_ALERT_RSVP 0x0100 +#define IP6_ALERT_AN 0x0200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/ip_icmp.h b/third_party/ulib/musl/include/netinet/ip_icmp.h new file mode 100644 index 000000000..3c1c28a67 --- /dev/null +++ b/third_party/ulib/musl/include/netinet/ip_icmp.h @@ -0,0 +1,189 @@ +#ifndef _NETINET_IP_ICMP_H +#define _NETINET_IP_ICMP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct icmphdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + struct { + uint16_t id; + uint16_t sequence; + } echo; + uint32_t gateway; + struct { + uint16_t __unused; + uint16_t mtu; + } frag; + } un; +}; + +#define ICMP_ECHOREPLY 0 +#define ICMP_DEST_UNREACH 3 +#define ICMP_SOURCE_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETERPROB 12 +#define ICMP_TIMESTAMP 13 +#define ICMP_TIMESTAMPREPLY 14 +#define ICMP_INFO_REQUEST 15 +#define ICMP_INFO_REPLY 16 +#define ICMP_ADDRESS 17 +#define ICMP_ADDRESSREPLY 18 +#define NR_ICMP_TYPES 18 + +#define ICMP_NET_UNREACH 0 +#define ICMP_HOST_UNREACH 1 +#define ICMP_PROT_UNREACH 2 +#define ICMP_PORT_UNREACH 3 +#define ICMP_FRAG_NEEDED 4 +#define ICMP_SR_FAILED 5 +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 +#define ICMP_PREC_VIOLATION 14 +#define ICMP_PREC_CUTOFF 15 +#define NR_ICMP_UNREACH 15 + +#define ICMP_REDIR_NET 0 +#define ICMP_REDIR_HOST 1 +#define ICMP_REDIR_NETTOS 2 +#define ICMP_REDIR_HOSTTOS 3 + +#define ICMP_EXC_TTL 0 +#define ICMP_EXC_FRAGTIME 1 + +struct icmp_ra_addr { + uint32_t ira_addr; + uint32_t ira_preference; +}; + +struct icmp { + uint8_t icmp_type; + uint8_t icmp_code; + uint16_t icmp_cksum; + union { + uint8_t ih_pptr; + struct in_addr ih_gwaddr; + struct ih_idseq { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + uint32_t ih_void; + + struct ih_pmtu { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + uint8_t irt_num_addrs; + uint8_t irt_wpa; + uint16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; + union { + struct { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } id_ts; + struct { + struct ip idi_ip; + } id_ip; + struct icmp_ra_addr id_radv; + uint32_t id_mask; + uint8_t id_data[1]; + } icmp_dun; +}; + +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data + +#define ICMP_MINLEN 8 +#define ICMP_TSLEN (8 + 3 * sizeof(n_time)) +#define ICMP_MASKLEN 12 +#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + +#define ICMP_UNREACH 3 +#define ICMP_SOURCEQUENCH 4 +#define ICMP_ROUTERADVERT 9 +#define ICMP_ROUTERSOLICIT 10 +#define ICMP_TIMXCEED 11 +#define ICMP_PARAMPROB 12 +#define ICMP_TSTAMP 13 +#define ICMP_TSTAMPREPLY 14 +#define ICMP_IREQ 15 +#define ICMP_IREQREPLY 16 +#define ICMP_MASKREQ 17 +#define ICMP_MASKREPLY 18 +#define ICMP_MAXTYPE 18 + +#define ICMP_UNREACH_NET 0 +#define ICMP_UNREACH_HOST 1 +#define ICMP_UNREACH_PROTOCOL 2 +#define ICMP_UNREACH_PORT 3 +#define ICMP_UNREACH_NEEDFRAG 4 +#define ICMP_UNREACH_SRCFAIL 5 +#define ICMP_UNREACH_NET_UNKNOWN 6 +#define ICMP_UNREACH_HOST_UNKNOWN 7 +#define ICMP_UNREACH_ISOLATED 8 +#define ICMP_UNREACH_NET_PROHIB 9 +#define ICMP_UNREACH_HOST_PROHIB 10 +#define ICMP_UNREACH_TOSNET 11 +#define ICMP_UNREACH_TOSHOST 12 +#define ICMP_UNREACH_FILTER_PROHIB 13 +#define ICMP_UNREACH_HOST_PRECEDENCE 14 +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 + +#define ICMP_REDIRECT_NET 0 +#define ICMP_REDIRECT_HOST 1 +#define ICMP_REDIRECT_TOSNET 2 +#define ICMP_REDIRECT_TOSHOST 3 + +#define ICMP_TIMXCEED_INTRANS 0 +#define ICMP_TIMXCEED_REASS 1 + +#define ICMP_PARAMPROB_OPTABSENT 1 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || (type) == ICMP_ROUTERADVERT || \ + (type) == ICMP_ROUTERSOLICIT || (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || (type) == ICMP_MASKREQ || \ + (type) == ICMP_MASKREPLY) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/tcp.h b/third_party/ulib/musl/include/netinet/tcp.h new file mode 100644 index 000000000..222574500 --- /dev/null +++ b/third_party/ulib/musl/include/netinet/tcp.h @@ -0,0 +1,202 @@ +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#include + +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 +#define TCP_CORK 3 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_KEEPCNT 6 +#define TCP_SYNCNT 7 +#define TCP_LINGER2 8 +#define TCP_DEFER_ACCEPT 9 +#define TCP_WINDOW_CLAMP 10 +#define TCP_INFO 11 +#define TCP_QUICKACK 12 +#define TCP_CONGESTION 13 +#define TCP_MD5SIG 14 +#define TCP_THIN_LINEAR_TIMEOUTS 16 +#define TCP_THIN_DUPACK 17 +#define TCP_USER_TIMEOUT 18 +#define TCP_REPAIR 19 +#define TCP_REPAIR_QUEUE 20 +#define TCP_QUEUE_SEQ 21 +#define TCP_REPAIR_OPTIONS 22 +#define TCP_FASTOPEN 23 +#define TCP_TIMESTAMP 24 +#define TCP_NOTSENT_LOWAT 25 +#define TCP_CC_INFO 26 +#define TCP_SAVE_SYN 27 +#define TCP_SAVED_SYN 28 + +#define TCP_ESTABLISHED 1 +#define TCP_SYN_SENT 2 +#define TCP_SYN_RECV 3 +#define TCP_FIN_WAIT1 4 +#define TCP_FIN_WAIT2 5 +#define TCP_TIME_WAIT 6 +#define TCP_CLOSE 7 +#define TCP_CLOSE_WAIT 8 +#define TCP_LAST_ACK 9 +#define TCP_LISTEN 10 +#define TCP_CLOSING 11 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOPT_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 +#define TCPOPT_SACK 5 +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_MAXSEG 4 +#define TCPOLEN_TIMESTAMP 10 + +#define SOL_TCP 6 + +#include +#include +#include +#include + +typedef uint32_t tcp_seq; + +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + +struct tcphdr { +#ifdef _GNU_SOURCE +#ifdef __GNUC__ + __extension__ +#endif + union { + struct { + + uint16_t source; + uint16_t dest; + uint32_t seq; + uint32_t ack_seq; +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint16_t res1 : 4; + uint16_t doff : 4; + uint16_t fin : 1; + uint16_t syn : 1; + uint16_t rst : 1; + uint16_t psh : 1; + uint16_t ack : 1; + uint16_t urg : 1; + uint16_t res2 : 2; +#else + uint16_t doff : 4; + uint16_t res1 : 4; + uint16_t res2 : 2; + uint16_t urg : 1; + uint16_t ack : 1; + uint16_t psh : 1; + uint16_t rst : 1; + uint16_t syn : 1; + uint16_t fin : 1; +#endif + uint16_t window; + uint16_t check; + uint16_t urg_ptr; + }; + struct { +#endif + + uint16_t th_sport; + uint16_t th_dport; + uint32_t th_seq; + uint32_t th_ack; +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint8_t th_x2 : 4; + uint8_t th_off : 4; +#else + uint8_t th_off : 4; + uint8_t th_x2 : 4; +#endif + uint8_t th_flags; + uint16_t th_win; + uint16_t th_sum; + uint16_t th_urp; + +#ifdef _GNU_SOURCE + }; + }; +#endif +}; +#endif + +#ifdef _GNU_SOURCE +#define TCPI_OPT_TIMESTAMPS 1 +#define TCPI_OPT_SACK 2 +#define TCPI_OPT_WSCALE 4 +#define TCPI_OPT_ECN 8 + +#define TCP_CA_Open 0 +#define TCP_CA_Disorder 1 +#define TCP_CA_CWR 2 +#define TCP_CA_Recovery 3 +#define TCP_CA_Loss 4 + +struct tcp_info { + uint8_t tcpi_state; + uint8_t tcpi_ca_state; + uint8_t tcpi_retransmits; + uint8_t tcpi_probes; + uint8_t tcpi_backoff; + uint8_t tcpi_options; + uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; + uint32_t tcpi_rto; + uint32_t tcpi_ato; + uint32_t tcpi_snd_mss; + uint32_t tcpi_rcv_mss; + uint32_t tcpi_unacked; + uint32_t tcpi_sacked; + uint32_t tcpi_lost; + uint32_t tcpi_retrans; + uint32_t tcpi_fackets; + uint32_t tcpi_last_data_sent; + uint32_t tcpi_last_ack_sent; + uint32_t tcpi_last_data_recv; + uint32_t tcpi_last_ack_recv; + uint32_t tcpi_pmtu; + uint32_t tcpi_rcv_ssthresh; + uint32_t tcpi_rtt; + uint32_t tcpi_rttvar; + uint32_t tcpi_snd_ssthresh; + uint32_t tcpi_snd_cwnd; + uint32_t tcpi_advmss; + uint32_t tcpi_reordering; + uint32_t tcpi_rcv_rtt; + uint32_t tcpi_rcv_space; + uint32_t tcpi_total_retrans; + uint64_t tcpi_pacing_rate; + uint64_t tcpi_max_pacing_rate; + uint64_t tcpi_bytes_acked; + uint64_t tcpi_bytes_received; + uint32_t tcpi_segs_out; + uint32_t tcpi_segs_in; +}; + +#define TCP_MD5SIG_MAXKEYLEN 80 + +struct tcp_md5sig { + struct sockaddr_storage tcpm_addr; + uint16_t __tcpm_pad1; + uint16_t tcpm_keylen; + uint32_t __tcpm_pad2; + uint8_t tcpm_key[TCP_MD5SIG_MAXKEYLEN]; +}; + +#endif + +#endif diff --git a/third_party/ulib/musl/include/netinet/udp.h b/third_party/ulib/musl/include/netinet/udp.h new file mode 100644 index 000000000..b658a3dd5 --- /dev/null +++ b/third_party/ulib/musl/include/netinet/udp.h @@ -0,0 +1,38 @@ +#ifndef _NETINET_UDP_H +#define _NETINET_UDP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifdef _GNU_SOURCE +#define uh_sport source +#define uh_dport dest +#define uh_ulen len +#define uh_sum check +#endif + +struct udphdr { + uint16_t uh_sport; + uint16_t uh_dport; + uint16_t uh_ulen; + uint16_t uh_sum; +}; + +#define UDP_CORK 1 +#define UDP_ENCAP 100 + +#define UDP_ENCAP_ESPINUDP_NON_IKE 1 +#define UDP_ENCAP_ESPINUDP 2 +#define UDP_ENCAP_L2TPINUDP 3 + +#define SOL_UDP 17 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/netpacket/packet.h b/third_party/ulib/musl/include/netpacket/packet.h new file mode 100644 index 000000000..a01e68cf1 --- /dev/null +++ b/third_party/ulib/musl/include/netpacket/packet.h @@ -0,0 +1,61 @@ +#ifndef _NETPACKET_PACKET_H +#define _NETPACKET_PACKET_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct sockaddr_ll { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[8]; +}; + +struct packet_mreq { + int mr_ifindex; + unsigned short int mr_type, mr_alen; + unsigned char mr_address[8]; +}; + +#define PACKET_HOST 0 +#define PACKET_BROADCAST 1 +#define PACKET_MULTICAST 2 +#define PACKET_OTHERHOST 3 +#define PACKET_OUTGOING 4 +#define PACKET_LOOPBACK 5 +#define PACKET_FASTROUTE 6 + +#define PACKET_ADD_MEMBERSHIP 1 +#define PACKET_DROP_MEMBERSHIP 2 +#define PACKET_RECV_OUTPUT 3 +#define PACKET_RX_RING 5 +#define PACKET_STATISTICS 6 +#define PACKET_COPY_THRESH 7 +#define PACKET_AUXDATA 8 +#define PACKET_ORIGDEV 9 +#define PACKET_VERSION 10 +#define PACKET_HDRLEN 11 +#define PACKET_RESERVE 12 +#define PACKET_TX_RING 13 +#define PACKET_LOSS 14 +#define PACKET_VNET_HDR 15 +#define PACKET_TX_TIMESTAMP 16 +#define PACKET_TIMESTAMP 17 +#define PACKET_FANOUT 18 +#define PACKET_TX_HAS_OFF 19 +#define PACKET_QDISC_BYPASS 20 +#define PACKET_ROLLOVER_STATS 21 +#define PACKET_FANOUT_DATA 22 + +#define PACKET_MR_MULTICAST 0 +#define PACKET_MR_PROMISC 1 +#define PACKET_MR_ALLMULTI 2 +#define PACKET_MR_UNICAST 3 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/nl_types.h b/third_party/ulib/musl/include/nl_types.h new file mode 100644 index 000000000..ee498270e --- /dev/null +++ b/third_party/ulib/musl/include/nl_types.h @@ -0,0 +1,22 @@ +#ifndef _NL_TYPES_H +#define _NL_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NL_SETD 1 +#define NL_CAT_LOCALE 1 + +typedef int nl_item; +typedef void* nl_catd; + +nl_catd catopen(const char*, int); +char* catgets(nl_catd, int, int, const char*); +int catclose(nl_catd); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/paths.h b/third_party/ulib/musl/include/paths.h new file mode 100644 index 000000000..1c0433be1 --- /dev/null +++ b/third_party/ulib/musl/include/paths.h @@ -0,0 +1,31 @@ +#ifndef _PATHS_H +#define _PATHS_H + +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" +#define _PATH_STDPATH "/bin:/usr/bin:/sbin:/usr/sbin" + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CONSOLE "/dev/console" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_KLOG "/proc/kmsg" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_MAILDIR "/var/mail" +#define _PATH_MAN "/usr/share/man" +#define _PATH_MNTTAB "/etc/fstab" +#define _PATH_MOUNTED "/etc/mtab" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_SENDMAIL "/usr/sbin/sendmail" +#define _PATH_SHADOW "/etc/shadow" +#define _PATH_SHELLS "/etc/shells" +#define _PATH_TTY "/dev/tty" +#define _PATH_UTMP "/dev/null/utmp" +#define _PATH_VI "/usr/bin/vi" +#define _PATH_WTMP "/dev/null/wtmp" + +#define _PATH_DEV "/dev/" +#define _PATH_TMP "/tmp/" +#define _PATH_VARDB "/var/lib/misc/" +#define _PATH_VARRUN "/var/run/" +#define _PATH_VARTMP "/var/tmp/" + +#endif diff --git a/third_party/ulib/musl/include/poll.h b/third_party/ulib/musl/include/poll.h new file mode 100644 index 000000000..ad9377b39 --- /dev/null +++ b/third_party/ulib/musl/include/poll.h @@ -0,0 +1,51 @@ +#ifndef _POLL_H +#define _POLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 +#define POLLRDNORM 0x040 +#define POLLRDBAND 0x080 +#ifndef POLLWRNORM +#define POLLWRNORM 0x100 +#define POLLWRBAND 0x200 +#endif +#ifndef POLLMSG +#define POLLMSG 0x400 +#define POLLRDHUP 0x2000 +#endif + +typedef unsigned long nfds_t; + +struct pollfd { + int fd; + short events; + short revents; +}; + +int poll(struct pollfd*, nfds_t, int); + +#ifdef _GNU_SOURCE +#define __NEED_time_t +#define __NEED_struct_timespec +#define __NEED_sigset_t +#include +int ppoll(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/pthread.h b/third_party/ulib/musl/include/pthread.h new file mode 100644 index 000000000..6ed99a354 --- /dev/null +++ b/third_party/ulib/musl/include/pthread.h @@ -0,0 +1,233 @@ +#ifndef _PTHREAD_H +#define _PTHREAD_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_time_t +#define __NEED_clockid_t +#define __NEED_struct_timespec +#define __NEED_sigset_t +#define __NEED_pthread_t +#define __NEED_pthread_attr_t +#define __NEED_pthread_mutexattr_t +#define __NEED_pthread_condattr_t +#define __NEED_pthread_rwlockattr_t +#define __NEED_pthread_barrierattr_t +#define __NEED_pthread_mutex_t +#define __NEED_pthread_cond_t +#define __NEED_pthread_rwlock_t +#define __NEED_pthread_barrier_t +#define __NEED_pthread_spinlock_t +#define __NEED_pthread_key_t +#define __NEED_pthread_once_t +#define __NEED_size_t + +#include + +#include +#include + +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_DEFAULT 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_ERRORCHECK 2 + +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + +#define PTHREAD_PRIO_NONE 0 +#define PTHREAD_PRIO_INHERIT 1 +#define PTHREAD_PRIO_PROTECT 2 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +#define PTHREAD_PROCESS_PRIVATE 0 + +#define PTHREAD_MUTEX_INITIALIZER \ + { \ + { \ + { 0 } \ + } \ + } +#define PTHREAD_RWLOCK_INITIALIZER \ + { \ + { \ + { 0 } \ + } \ + } +#define PTHREAD_COND_INITIALIZER \ + { \ + { \ + { 0 } \ + } \ + } +#define PTHREAD_ONCE_INIT 0 + +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +#define PTHREAD_CANCELED ((void*)-1) + +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) + +int pthread_create(pthread_t* __restrict, const pthread_attr_t* __restrict, void* (*)(void*), + void* __restrict); +int pthread_detach(pthread_t); +_Noreturn void pthread_exit(void*); +int pthread_join(pthread_t, void**); + +pthread_t pthread_self(void); + +int pthread_equal(pthread_t, pthread_t); +#ifndef __cplusplus +#define pthread_equal(x, y) ((x) == (y)) +#endif + +int pthread_setcancelstate(int, int*); +int pthread_setcanceltype(int, int*); +void pthread_testcancel(void); +int pthread_cancel(pthread_t); + +int pthread_getschedparam(pthread_t, int* __restrict, struct sched_param* __restrict); +int pthread_setschedparam(pthread_t, int, const struct sched_param*); +int pthread_setschedprio(pthread_t, int); + +int pthread_once(pthread_once_t*, void (*)(void)); + +int pthread_mutex_init(pthread_mutex_t* __restrict, const pthread_mutexattr_t* __restrict); +int pthread_mutex_lock(pthread_mutex_t*); +int pthread_mutex_unlock(pthread_mutex_t*); +int pthread_mutex_trylock(pthread_mutex_t*); +int pthread_mutex_timedlock(pthread_mutex_t* __restrict, const struct timespec* __restrict); +int pthread_mutex_destroy(pthread_mutex_t*); +int pthread_mutex_consistent(pthread_mutex_t*); + +int pthread_mutex_getprioceiling(const pthread_mutex_t* __restrict, int* __restrict); +int pthread_mutex_setprioceiling(pthread_mutex_t* __restrict, int, int* __restrict); + +int pthread_cond_init(pthread_cond_t* __restrict, const pthread_condattr_t* __restrict); +int pthread_cond_destroy(pthread_cond_t*); +int pthread_cond_wait(pthread_cond_t* __restrict, pthread_mutex_t* __restrict); +int pthread_cond_timedwait(pthread_cond_t* __restrict, pthread_mutex_t* __restrict, + const struct timespec* __restrict); +int pthread_cond_broadcast(pthread_cond_t*); +int pthread_cond_signal(pthread_cond_t*); + +int pthread_rwlock_init(pthread_rwlock_t* __restrict, const pthread_rwlockattr_t* __restrict); +int pthread_rwlock_destroy(pthread_rwlock_t*); +int pthread_rwlock_rdlock(pthread_rwlock_t*); +int pthread_rwlock_tryrdlock(pthread_rwlock_t*); +int pthread_rwlock_timedrdlock(pthread_rwlock_t* __restrict, const struct timespec* __restrict); +int pthread_rwlock_wrlock(pthread_rwlock_t*); +int pthread_rwlock_trywrlock(pthread_rwlock_t*); +int pthread_rwlock_timedwrlock(pthread_rwlock_t* __restrict, const struct timespec* __restrict); +int pthread_rwlock_unlock(pthread_rwlock_t*); + +int pthread_spin_init(pthread_spinlock_t*, int); +int pthread_spin_destroy(pthread_spinlock_t*); +int pthread_spin_lock(pthread_spinlock_t*); +int pthread_spin_trylock(pthread_spinlock_t*); +int pthread_spin_unlock(pthread_spinlock_t*); + +int pthread_barrier_init(pthread_barrier_t* __restrict, const pthread_barrierattr_t* __restrict, + unsigned); +int pthread_barrier_destroy(pthread_barrier_t*); +int pthread_barrier_wait(pthread_barrier_t*); + +int pthread_key_create(pthread_key_t*, void (*)(void*)); +int pthread_key_delete(pthread_key_t); +void* pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void*); + +int pthread_attr_init(pthread_attr_t*); +int pthread_attr_destroy(pthread_attr_t*); + +int pthread_attr_getguardsize(const pthread_attr_t* __restrict, size_t* __restrict); +int pthread_attr_setguardsize(pthread_attr_t*, size_t); +int pthread_attr_getstacksize(const pthread_attr_t* __restrict, size_t* __restrict); +int pthread_attr_setstacksize(pthread_attr_t*, size_t); +int pthread_attr_getdetachstate(const pthread_attr_t*, int*); +int pthread_attr_setdetachstate(pthread_attr_t*, int); +int pthread_attr_getstack(const pthread_attr_t* __restrict, void** __restrict, size_t* __restrict); +int pthread_attr_setstack(pthread_attr_t*, void*, size_t); +int pthread_attr_getscope(const pthread_attr_t* __restrict, int* __restrict); +int pthread_attr_setscope(pthread_attr_t*, int); +int pthread_attr_getschedpolicy(const pthread_attr_t* __restrict, int* __restrict); +int pthread_attr_setschedpolicy(pthread_attr_t*, int); +int pthread_attr_getschedparam(const pthread_attr_t* __restrict, struct sched_param* __restrict); +int pthread_attr_setschedparam(pthread_attr_t* __restrict, const struct sched_param* __restrict); +int pthread_attr_getinheritsched(const pthread_attr_t* __restrict, int* __restrict); +int pthread_attr_setinheritsched(pthread_attr_t*, int); + +int pthread_mutexattr_destroy(pthread_mutexattr_t*); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t* __restrict, int* __restrict); +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t* __restrict, int* __restrict); +int pthread_mutexattr_getrobust(const pthread_mutexattr_t* __restrict, int* __restrict); +int pthread_mutexattr_gettype(const pthread_mutexattr_t* __restrict, int* __restrict); +int pthread_mutexattr_init(pthread_mutexattr_t*); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); +int pthread_mutexattr_setrobust(pthread_mutexattr_t*, int); +int pthread_mutexattr_settype(pthread_mutexattr_t*, int); + +int pthread_condattr_init(pthread_condattr_t*); +int pthread_condattr_destroy(pthread_condattr_t*); +int pthread_condattr_setclock(pthread_condattr_t*, clockid_t); +int pthread_condattr_getclock(const pthread_condattr_t* __restrict, clockid_t* __restrict); + +int pthread_rwlockattr_init(pthread_rwlockattr_t*); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t*); + +int pthread_barrierattr_destroy(pthread_barrierattr_t*); +int pthread_barrierattr_init(pthread_barrierattr_t*); + +int pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); + +int pthread_getconcurrency(void); +int pthread_setconcurrency(int); + +int pthread_getcpuclockid(pthread_t, clockid_t*); + +struct __ptcb { + void (*__f)(void*); + void* __x; + struct __ptcb* __next; +}; + +void _pthread_cleanup_push(struct __ptcb*, void (*)(void*), void*); +void _pthread_cleanup_pop(struct __ptcb*, int); + +#define pthread_cleanup_push(f, x) \ + do { \ + struct __ptcb __cb; \ + _pthread_cleanup_push(&__cb, f, x); +#define pthread_cleanup_pop(r) \ + _pthread_cleanup_pop(&__cb, (r)); \ + } \ + while (0) + +#ifdef _GNU_SOURCE +struct cpu_set_t; +int pthread_getaffinity_np(pthread_t, size_t, struct cpu_set_t*); +int pthread_setaffinity_np(pthread_t, size_t, const struct cpu_set_t*); +int pthread_getattr_np(pthread_t, pthread_attr_t*); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/pty.h b/third_party/ulib/musl/include/pty.h new file mode 100644 index 000000000..d95a68e35 --- /dev/null +++ b/third_party/ulib/musl/include/pty.h @@ -0,0 +1,18 @@ +#ifndef _PTY_H +#define _PTY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +int openpty(int*, int*, char*, const struct termios*, const struct winsize*); +int forkpty(int*, char*, const struct termios*, const struct winsize*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/pwd.h b/third_party/ulib/musl/include/pwd.h new file mode 100644 index 000000000..ed7458500 --- /dev/null +++ b/third_party/ulib/musl/include/pwd.h @@ -0,0 +1,48 @@ +#ifndef _PWD_H +#define _PWD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#define __NEED_uid_t +#define __NEED_gid_t + +#ifdef _GNU_SOURCE +#define __NEED_FILE +#endif + +#include + +struct passwd { + char* pw_name; + char* pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char* pw_gecos; + char* pw_dir; + char* pw_shell; +}; + +void setpwent(void); +void endpwent(void); +struct passwd* getpwent(void); + +struct passwd* getpwuid(uid_t); +struct passwd* getpwnam(const char*); +int getpwuid_r(uid_t, struct passwd*, char*, size_t, struct passwd**); +int getpwnam_r(const char*, struct passwd*, char*, size_t, struct passwd**); + +#ifdef _GNU_SOURCE +struct passwd* fgetpwent(FILE*); +int putpwent(const struct passwd*, FILE*); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/regex.h b/third_party/ulib/musl/include/regex.h new file mode 100644 index 000000000..fec3636e6 --- /dev/null +++ b/third_party/ulib/musl/include/regex.h @@ -0,0 +1,62 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_regoff_t +#define __NEED_size_t + +#include + +typedef struct re_pattern_buffer { + size_t re_nsub; + void *__opaque, *__padding[4]; + size_t __nsub2; + char __padding2; +} regex_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +#define REG_EXTENDED 1 +#define REG_ICASE 2 +#define REG_NEWLINE 4 +#define REG_NOSUB 8 + +#define REG_NOTBOL 1 +#define REG_NOTEOL 2 + +#define REG_OK 0 +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 + +#define REG_ENOSYS -1 + +int regcomp(regex_t* __restrict, const char* __restrict, int); +int regexec(const regex_t* __restrict, const char* __restrict, size_t, regmatch_t* __restrict, int); +void regfree(regex_t*); + +size_t regerror(int, const regex_t* __restrict, char* __restrict, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/resolv.h b/third_party/ulib/musl/include/resolv.h new file mode 100644 index 000000000..4b3f5a834 --- /dev/null +++ b/third_party/ulib/musl/include/resolv.h @@ -0,0 +1,143 @@ +#ifndef _RESOLV_H +#define _RESOLV_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXNS 3 +#define MAXDFLSRCH 3 +#define MAXDNSRCH 6 +#define LOCALDOMAINPARTS 2 + +#define RES_TIMEOUT 5 +#define MAXRESOLVSORT 10 +#define RES_MAXNDOTS 15 +#define RES_MAXRETRANS 30 +#define RES_MAXRETRY 5 +#define RES_DFLRETRY 2 +#define RES_MAXTIME 65535 + +/* unused; purely for broken apps */ +typedef struct __res_state { + int retrans; + int retry; + unsigned long options; + int nscount; + struct sockaddr_in nsaddr_list[MAXNS]; +#define nsaddr nsaddr_list[0] + unsigned short id; + char* dnsrch[MAXDNSRCH + 1]; + char defdname[256]; + unsigned long pfcode; + unsigned ndots : 4; + unsigned nsort : 4; + unsigned ipv6_unavail : 1; + unsigned unused : 23; + struct { + struct in_addr addr; + uint32_t mask; + } sort_list[MAXRESOLVSORT]; + void* qhook; + void* rhook; + int res_h_errno; + int _vcsock; + unsigned _flags; + union { + char pad[52]; + struct { + uint16_t nscount; + uint16_t nsmap[MAXNS]; + int nssocks[MAXNS]; + uint16_t nscount6; + uint16_t nsinit; + struct sockaddr_in6* nsaddrs[MAXNS]; + unsigned int _initstamp[2]; + } _ext; + } _u; +} * res_state; + +#define __RES 19991006 + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +struct res_sym { + int number; + char* name; + char* humanname; +}; + +#define RES_F_VC 0x00000001 +#define RES_F_CONN 0x00000002 +#define RES_F_EDNS0ERR 0x00000004 + +#define RES_EXHAUSTIVE 0x00000001 + +#define RES_INIT 0x00000001 +#define RES_DEBUG 0x00000002 +#define RES_AAONLY 0x00000004 +#define RES_USEVC 0x00000008 +#define RES_PRIMARY 0x00000010 +#define RES_IGNTC 0x00000020 +#define RES_RECURSE 0x00000040 +#define RES_DEFNAMES 0x00000080 +#define RES_STAYOPEN 0x00000100 +#define RES_DNSRCH 0x00000200 +#define RES_INSECURE1 0x00000400 +#define RES_INSECURE2 0x00000800 +#define RES_NOALIASES 0x00001000 +#define RES_USE_INET6 0x00002000 +#define RES_ROTATE 0x00004000 +#define RES_NOCHECKNAME 0x00008000 +#define RES_KEEPTSIG 0x00010000 +#define RES_BLAST 0x00020000 +#define RES_USEBSTRING 0x00040000 +#define RES_NOIP6DOTINT 0x00080000 +#define RES_USE_EDNS0 0x00100000 +#define RES_SNGLKUP 0x00200000 +#define RES_SNGLKUPREOP 0x00400000 +#define RES_USE_DNSSEC 0x00800000 + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH | RES_NOIP6DOTINT) + +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 + +struct __res_state* __res_state(void); +#define _res (*__res_state()) + +int res_init(void); +int res_query(const char*, int, int, unsigned char*, int); +int res_querydomain(const char*, const char*, int, int, unsigned char*, int); +int res_search(const char*, int, int, unsigned char*, int); +int res_mkquery(int, const char*, int, int, const unsigned char*, int, const unsigned char*, + unsigned char*, int); +int res_send(const unsigned char*, int, unsigned char*, int); +int dn_comp(const char*, unsigned char*, int, unsigned char**, unsigned char**); +int dn_expand(const unsigned char*, const unsigned char*, const unsigned char*, char*, int); +int dn_skipname(const unsigned char*, const unsigned char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sched.h b/third_party/ulib/musl/include/sched.h new file mode 100644 index 000000000..99fdfb924 --- /dev/null +++ b/third_party/ulib/musl/include/sched.h @@ -0,0 +1,133 @@ +#ifndef _SCHED_H +#define _SCHED_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_struct_timespec +#define __NEED_pid_t +#define __NEED_time_t + +#ifdef _GNU_SOURCE +#define __NEED_size_t +#endif + +#include + +struct sched_param { + int sched_priority; + int sched_ss_low_priority; + struct timespec sched_ss_repl_period; + struct timespec sched_ss_init_budget; + int sched_ss_max_repl; +}; + +int sched_get_priority_max(int); +int sched_get_priority_min(int); +int sched_getparam(pid_t, struct sched_param*); +int sched_getscheduler(pid_t); +int sched_rr_get_interval(pid_t, struct timespec*); +int sched_setparam(pid_t, const struct sched_param*); +int sched_setscheduler(pid_t, int, const struct sched_param*); +int sched_yield(void); + +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 +#define SCHED_RESET_ON_FORK 0x40000000 + +#ifdef _GNU_SOURCE +#define CSIGNAL 0x000000ff +#define CLONE_VM 0x00000100 +#define CLONE_FS 0x00000200 +#define CLONE_FILES 0x00000400 +#define CLONE_SIGHAND 0x00000800 +#define CLONE_PTRACE 0x00002000 +#define CLONE_VFORK 0x00004000 +#define CLONE_PARENT 0x00008000 +#define CLONE_THREAD 0x00010000 +#define CLONE_NEWNS 0x00020000 +#define CLONE_SYSVSEM 0x00040000 +#define CLONE_SETTLS 0x00080000 +#define CLONE_PARENT_SETTID 0x00100000 +#define CLONE_CHILD_CLEARTID 0x00200000 +#define CLONE_DETACHED 0x00400000 +#define CLONE_UNTRACED 0x00800000 +#define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_NEWUTS 0x04000000 +#define CLONE_NEWIPC 0x08000000 +#define CLONE_NEWUSER 0x10000000 +#define CLONE_NEWPID 0x20000000 +#define CLONE_NEWNET 0x40000000 +#define CLONE_IO 0x80000000 +int clone(int (*)(void*), void*, int, void*, ...); +int unshare(int); +int setns(int, int); + +void* memcpy(void* __restrict, const void* __restrict, size_t); +int memcmp(const void*, const void*, size_t); +void* calloc(size_t, size_t); +void free(void*); + +typedef struct cpu_set_t { unsigned long __bits[128 / sizeof(long)]; } cpu_set_t; +int __sched_cpucount(size_t, const cpu_set_t*); +int sched_getcpu(void); +int sched_getaffinity(pid_t, size_t, cpu_set_t*); +int sched_setaffinity(pid_t, size_t, const cpu_set_t*); + +#define __CPU_op_S(i, size, set, op) \ + ((i) / 8U >= (size) \ + ? 0 \ + : ((set)->__bits[(i) / 8 / sizeof(long)] op(1UL << ((i) % (8 * sizeof(long)))))) + +#define CPU_SET_S(i, size, set) __CPU_op_S(i, size, set, |=) +#define CPU_CLR_S(i, size, set) __CPU_op_S(i, size, set, &= ~) +#define CPU_ISSET_S(i, size, set) __CPU_op_S(i, size, set, &) + +#define __CPU_op_func_S(func, op) \ + static __inline void __CPU_##func##_S(size_t __size, cpu_set_t* __dest, \ + const cpu_set_t* __src1, const cpu_set_t* __src2) { \ + size_t __i; \ + for (__i = 0; __i < __size / sizeof(long); __i++) \ + __dest->__bits[__i] = __src1->__bits[__i] op __src2->__bits[__i]; \ + } + +__CPU_op_func_S(AND, &) __CPU_op_func_S(OR, |) __CPU_op_func_S(XOR, ^) + +#define CPU_AND_S(a, b, c, d) __CPU_AND_S(a, b, c, d) +#define CPU_OR_S(a, b, c, d) __CPU_OR_S(a, b, c, d) +#define CPU_XOR_S(a, b, c, d) __CPU_XOR_S(a, b, c, d) + +#define CPU_COUNT_S(size, set) __sched_cpucount(size, set) +#define CPU_ZERO_S(size, set) memset(set, 0, size) +#define CPU_EQUAL_S(size, set1, set2) (!memcmp(set1, set2, size)) + +#define CPU_ALLOC_SIZE(n) \ + (sizeof(long) * ((n) / (8 * sizeof(long)) + \ + ((n) % (8 * sizeof(long)) + 8 * sizeof(long) - 1) / (8 * sizeof(long)))) +#define CPU_ALLOC(n) ((cpu_set_t*)calloc(1, CPU_ALLOC_SIZE(n))) +#define CPU_FREE(set) free(set) + +#define CPU_SETSIZE 128 + +#define CPU_SET(i, set) CPU_SET_S(i, sizeof(cpu_set_t), set) +#define CPU_CLR(i, set) CPU_CLR_S(i, sizeof(cpu_set_t), set) +#define CPU_ISSET(i, set) CPU_ISSET_S(i, sizeof(cpu_set_t), set) +#define CPU_AND(d, s1, s2) CPU_AND_S(sizeof(cpu_set_t), d, s1, s2) +#define CPU_OR(d, s1, s2) CPU_OR_S(sizeof(cpu_set_t), d, s1, s2) +#define CPU_XOR(d, s1, s2) CPU_XOR_S(sizeof(cpu_set_t), d, s1, s2) +#define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t), set) +#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t), set) +#define CPU_EQUAL(s1, s2) CPU_EQUAL_S(sizeof(cpu_set_t), s1, s2) + +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/scsi/scsi.h b/third_party/ulib/musl/include/scsi/scsi.h new file mode 100644 index 000000000..5d042b872 --- /dev/null +++ b/third_party/ulib/musl/include/scsi/scsi.h @@ -0,0 +1,149 @@ +#ifndef _SCSI_SCSI_H +#define _SCSI_SCSI_H + +#define TEST_UNIT_READY 0x00 +#define REZERO_UNIT 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define READ_BLOCK_LIMITS 0x05 +#define REASSIGN_BLOCKS 0x07 +#define READ_6 0x08 +#define WRITE_6 0x0a +#define SEEK_6 0x0b +#define READ_REVERSE 0x0f +#define WRITE_FILEMARKS 0x10 +#define SPACE 0x11 +#define INQUIRY 0x12 +#define RECOVER_BUFFERED_DATA 0x14 +#define MODE_SELECT 0x15 +#define RESERVE 0x16 +#define RELEASE 0x17 +#define COPY 0x18 +#define ERASE 0x19 +#define MODE_SENSE 0x1a +#define START_STOP 0x1b +#define RECEIVE_DIAGNOSTIC 0x1c +#define SEND_DIAGNOSTIC 0x1d +#define ALLOW_MEDIUM_REMOVAL 0x1e +#define SET_WINDOW 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2a +#define SEEK_10 0x2b +#define WRITE_VERIFY 0x2e +#define VERIFY 0x2f +#define SEARCH_HIGH 0x30 +#define SEARCH_EQUAL 0x31 +#define SEARCH_LOW 0x32 +#define SET_LIMITS 0x33 +#define PRE_FETCH 0x34 +#define READ_POSITION 0x34 +#define SYNCHRONIZE_CACHE 0x35 +#define LOCK_UNLOCK_CACHE 0x36 +#define READ_DEFECT_DATA 0x37 +#define MEDIUM_SCAN 0x38 +#define COMPARE 0x39 +#define COPY_VERIFY 0x3a +#define WRITE_BUFFER 0x3b +#define READ_BUFFER 0x3c +#define UPDATE_BLOCK 0x3d +#define READ_LONG 0x3e +#define WRITE_LONG 0x3f +#define CHANGE_DEFINITION 0x40 +#define WRITE_SAME 0x41 +#define READ_TOC 0x43 +#define LOG_SELECT 0x4c +#define LOG_SENSE 0x4d +#define MODE_SELECT_10 0x55 +#define RESERVE_10 0x56 +#define RELEASE_10 0x57 +#define MODE_SENSE_10 0x5a +#define PERSISTENT_RESERVE_IN 0x5e +#define PERSISTENT_RESERVE_OUT 0x5f +#define MOVE_MEDIUM 0xa5 +#define READ_12 0xa8 +#define WRITE_12 0xaa +#define WRITE_VERIFY_12 0xae +#define SEARCH_HIGH_12 0xb0 +#define SEARCH_EQUAL_12 0xb1 +#define SEARCH_LOW_12 0xb2 +#define READ_ELEMENT_STATUS 0xb8 +#define SEND_VOLUME_TAG 0xb6 +#define WRITE_LONG_2 0xea +#define GOOD 0x00 +#define CHECK_CONDITION 0x01 +#define CONDITION_GOOD 0x02 +#define BUSY 0x04 +#define INTERMEDIATE_GOOD 0x08 +#define INTERMEDIATE_C_GOOD 0x0a +#define RESERVATION_CONFLICT 0x0c +#define COMMAND_TERMINATED 0x11 +#define QUEUE_FULL 0x14 +#define STATUS_MASK 0x3e +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define BLANK_CHECK 0x08 +#define COPY_ABORTED 0x0a +#define ABORTED_COMMAND 0x0b +#define VOLUME_OVERFLOW 0x0d +#define MISCOMPARE 0x0e +#define TYPE_DISK 0x00 +#define TYPE_TAPE 0x01 +#define TYPE_PROCESSOR 0x03 +#define TYPE_WORM 0x04 +#define TYPE_ROM 0x05 +#define TYPE_SCANNER 0x06 +#define TYPE_MOD 0x07 +#define TYPE_MEDIUM_CHANGER 0x08 +#define TYPE_ENCLOSURE 0x0d +#define TYPE_NO_LUN 0x7f +#define COMMAND_COMPLETE 0x00 +#define EXTENDED_MESSAGE 0x01 +#define EXTENDED_MODIFY_DATA_POINTER 0x00 +#define EXTENDED_SDTR 0x01 +#define EXTENDED_EXTENDED_IDENTIFY 0x02 +#define EXTENDED_WDTR 0x03 +#define SAVE_POINTERS 0x02 +#define RESTORE_POINTERS 0x03 +#define DISCONNECT 0x04 +#define INITIATOR_ERROR 0x05 +#define ABORT 0x06 +#define MESSAGE_REJECT 0x07 +#define NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define LINKED_CMD_COMPLETE 0x0a +#define LINKED_FLG_CMD_COMPLETE 0x0b +#define BUS_DEVICE_RESET 0x0c +#define INITIATE_RECOVERY 0x0f +#define RELEASE_RECOVERY 0x10 +#define SIMPLE_QUEUE_TAG 0x20 +#define HEAD_OF_QUEUE_TAG 0x21 +#define ORDERED_QUEUE_TAG 0x22 +#define SCSI_IOCTL_GET_IDLUN 0x5382 +#define SCSI_IOCTL_TAGGED_ENABLE 0x5383 +#define SCSI_IOCTL_TAGGED_DISABLE 0x5384 +#define SCSI_IOCTL_PROBE_HOST 0x5385 +#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386 + +struct ccs_modesel_head { + unsigned char _r1; + unsigned char medium; + unsigned char _r2; + unsigned char block_desc_length; + unsigned char density; + unsigned char number_blocks_hi; + unsigned char number_blocks_med; + unsigned char number_blocks_lo; + unsigned char _r3; + unsigned char block_length_hi; + unsigned char block_length_med; + unsigned char block_length_lo; +}; + +#endif diff --git a/third_party/ulib/musl/include/scsi/scsi_ioctl.h b/third_party/ulib/musl/include/scsi/scsi_ioctl.h new file mode 100644 index 000000000..22df7feff --- /dev/null +++ b/third_party/ulib/musl/include/scsi/scsi_ioctl.h @@ -0,0 +1,11 @@ +#ifndef _SCSI_IOCTL_H +#define _SCSI_IOCTL_H +#define SCSI_IOCTL_SEND_COMMAND 1 +#define SCSI_IOCTL_TEST_UNIT_READY 2 +#define SCSI_IOCTL_BENCHMARK_COMMAND 3 +#define SCSI_IOCTL_SYNC 4 +#define SCSI_IOCTL_START_UNIT 5 +#define SCSI_IOCTL_STOP_UNIT 6 +#define SCSI_IOCTL_DOORLOCK 0x5380 +#define SCSI_IOCTL_DOORUNLOCK 0x5381 +#endif diff --git a/third_party/ulib/musl/include/scsi/sg.h b/third_party/ulib/musl/include/scsi/sg.h new file mode 100644 index 000000000..a21791e5a --- /dev/null +++ b/third_party/ulib/musl/include/scsi/sg.h @@ -0,0 +1,129 @@ +#ifndef _SCSI_SG_H +#define _SCSI_SG_H + +#define SG_DXFER_NONE -1 +#define SG_DXFER_TO_DEV -2 +#define SG_DXFER_FROM_DEV -3 +#define SG_DXFER_TO_FROM_DEV -4 +#define SG_FLAG_DIRECT_IO 1 +#define SG_FLAG_LUN_INHIBIT 2 +#define SG_FLAG_NO_DXFER 0x10000 +#define SG_INFO_OK_MASK 0x1 +#define SG_INFO_OK 0x0 +#define SG_INFO_CHECK 0x1 +#define SG_INFO_DIRECT_IO_MASK 0x6 +#define SG_INFO_INDIRECT_IO 0x0 +#define SG_INFO_DIRECT_IO 0x2 +#define SG_INFO_MIXED_IO 0x4 +#define SG_EMULATED_HOST 0x2203 +#define SG_SET_TRANSFORM 0x2204 +#define SG_GET_TRANSFORM 0x2205 +#define SG_SET_RESERVED_SIZE 0x2275 +#define SG_GET_RESERVED_SIZE 0x2272 +#define SG_GET_SCSI_ID 0x2276 +#define SG_SET_FORCE_LOW_DMA 0x2279 +#define SG_GET_LOW_DMA 0x227a +#define SG_SET_FORCE_PACK_ID 0x227b +#define SG_GET_PACK_ID 0x227c +#define SG_GET_NUM_WAITING 0x227d +#define SG_GET_SG_TABLESIZE 0x227F +#define SG_GET_VERSION_NUM 0x2282 +#define SG_SCSI_RESET 0x2284 +#define SG_SCSI_RESET_NOTHING 0 +#define SG_SCSI_RESET_DEVICE 1 +#define SG_SCSI_RESET_BUS 2 +#define SG_SCSI_RESET_HOST 3 +#define SG_IO 0x2285 +#define SG_GET_REQUEST_TABLE 0x2286 +#define SG_SET_KEEP_ORPHAN 0x2287 +#define SG_GET_KEEP_ORPHAN 0x2288 +#define SG_SCATTER_SZ (8 * 4096) +#define SG_DEFAULT_RETRIES 1 +#define SG_DEF_FORCE_LOW_DMA 0 +#define SG_DEF_FORCE_PACK_ID 0 +#define SG_DEF_KEEP_ORPHAN 0 +#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ +#define SG_MAX_QUEUE 16 +#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE +#define SG_MAX_SENSE 16 +#define SG_SET_TIMEOUT 0x2201 +#define SG_GET_TIMEOUT 0x2202 +#define SG_GET_COMMAND_Q 0x2270 +#define SG_SET_COMMAND_Q 0x2271 +#define SG_SET_DEBUG 0x227e +#define SG_NEXT_CMD_LEN 0x2283 +#define SG_DEFAULT_TIMEOUT (60 * 100) /* 60*HZ */ +#define SG_DEF_COMMAND_Q 0 +#define SG_DEF_UNDERRUN_FLAG 0 + +typedef struct sg_iovec { + void* iov_base; + unsigned long iov_len; +} sg_iovec_t; + +typedef struct sg_io_hdr { + int interface_id; + int dxfer_direction; + unsigned char cmd_len; + unsigned char mx_sb_len; + unsigned short iovec_count; + unsigned dxfer_len; + void* dxferp; + unsigned char* cmdp; + unsigned char* sbp; + unsigned timeout; + unsigned flags; + int pack_id; + void* usr_ptr; + unsigned char status; + unsigned char masked_status; + unsigned char msg_status; + unsigned char sb_len_wr; + unsigned short host_status; + unsigned short driver_status; + int resid; + unsigned int duration; + unsigned int info; +} sg_io_hdr_t; + +struct sg_scsi_id { + int host_no; + int channel; + int scsi_id; + int lun; + int scsi_type; + short h_cmd_per_lun; + short d_queue_depth; + int unused[2]; +}; + +typedef struct sg_req_info { + char req_state; + char orphan; + char sg_io_owned; + char problem; + int pack_id; + void* usr_ptr; + unsigned duration; + int unused; +} sg_req_info_t; + +typedef struct sg_io_hdr Sg_io_hdr; +typedef struct sg_io_vec Sg_io_vec; +typedef struct sg_scsi_id Sg_scsi_id; +typedef struct sg_req_info Sg_req_info; + +struct sg_header { + int pack_len; + int reply_len; + int pack_id; + int result; + unsigned twelve_byte : 1; + unsigned target_status : 5; + unsigned host_status : 8; + unsigned driver_status : 8; + unsigned other_flags : 10; + unsigned char sense_buffer[SG_MAX_SENSE]; +}; + +#endif diff --git a/third_party/ulib/musl/include/search.h b/third_party/ulib/musl/include/search.h new file mode 100644 index 000000000..96c87ff99 --- /dev/null +++ b/third_party/ulib/musl/include/search.h @@ -0,0 +1,61 @@ +#ifndef _SEARCH_H +#define _SEARCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#include + +typedef enum { FIND, ENTER } ACTION; +typedef enum { preorder, postorder, endorder, leaf } VISIT; + +typedef struct entry { + char* key; + void* data; +} ENTRY; + +int hcreate(size_t); +void hdestroy(void); +ENTRY* hsearch(ENTRY, ACTION); + +#ifdef _GNU_SOURCE +struct hsearch_data { + struct __tab* __tab; + unsigned int __unused1; + unsigned int __unused2; +}; + +int hcreate_r(size_t, struct hsearch_data*); +void hdestroy_r(struct hsearch_data*); +int hsearch_r(ENTRY, ACTION, ENTRY**, struct hsearch_data*); +#endif + +void insque(void*, void*); +void remque(void*); + +void* lsearch(const void*, void*, size_t*, size_t, int (*)(const void*, const void*)); +void* lfind(const void*, const void*, size_t*, size_t, int (*)(const void*, const void*)); + +void* tdelete(const void* __restrict, void** __restrict, int (*)(const void*, const void*)); +void* tfind(const void*, void* const*, int (*)(const void*, const void*)); +void* tsearch(const void*, void**, int (*)(const void*, const void*)); +void twalk(const void*, void (*)(const void*, VISIT, int)); + +#ifdef _GNU_SOURCE +struct qelem { + struct qelem *q_forw, *q_back; + char q_data[1]; +}; + +void tdestroy(void*, void (*)(void*)); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/semaphore.h b/third_party/ulib/musl/include/semaphore.h new file mode 100644 index 000000000..debddf698 --- /dev/null +++ b/third_party/ulib/musl/include/semaphore.h @@ -0,0 +1,34 @@ +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_time_t +#define __NEED_struct_timespec +#include + +#include + +#define SEM_FAILED ((sem_t*)0) + +// TODO(kulakowski) __val[2] is the process private bit, and hence unused on magenta +typedef struct { volatile int __val[4 * sizeof(long) / sizeof(int)]; } sem_t; + +int sem_close(sem_t*); +int sem_destroy(sem_t*); +int sem_getvalue(sem_t* __restrict, int* __restrict); +int sem_init(sem_t*, int, unsigned); +sem_t* sem_open(const char*, int, ...); +int sem_post(sem_t*); +int sem_timedwait(sem_t* __restrict, const struct timespec* __restrict); +int sem_trywait(sem_t*); +int sem_unlink(const char*); +int sem_wait(sem_t*); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/setjmp.h b/third_party/ulib/musl/include/setjmp.h new file mode 100644 index 000000000..579620069 --- /dev/null +++ b/third_party/ulib/musl/include/setjmp.h @@ -0,0 +1,39 @@ +#ifndef _SETJMP_H +#define _SETJMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +typedef struct __jmp_buf_tag { + __jmp_buf __jb; + unsigned long __fl; + unsigned long __ss[128 / sizeof(long)]; +} jmp_buf[1]; + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef jmp_buf sigjmp_buf; +int sigsetjmp(sigjmp_buf, int); +_Noreturn void siglongjmp(sigjmp_buf, int); +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int _setjmp(jmp_buf); +_Noreturn void _longjmp(jmp_buf, int); +#endif + +int setjmp(jmp_buf); +_Noreturn void longjmp(jmp_buf, int); + +#define setjmp setjmp + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/shadow.h b/third_party/ulib/musl/include/shadow.h new file mode 100644 index 000000000..fed01541c --- /dev/null +++ b/third_party/ulib/musl/include/shadow.h @@ -0,0 +1,44 @@ +#ifndef _SHADOW_H +#define _SHADOW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_FILE +#define __NEED_size_t + +#include + +#define SHADOW "/etc/shadow" + +struct spwd { + char* sp_namp; + char* sp_pwdp; + long sp_lstchg; + long sp_min; + long sp_max; + long sp_warn; + long sp_inact; + long sp_expire; + unsigned long sp_flag; +}; + +void setspent(void); +void endspent(void); +struct spwd* getspent(void); +struct spwd* fgetspent(FILE*); +struct spwd* sgetspent(const char*); +int putspent(const struct spwd*, FILE*); + +struct spwd* getspnam(const char*); +int getspnam_r(const char*, struct spwd*, char*, size_t, struct spwd**); + +int lckpwdf(void); +int ulckpwdf(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/signal.h b/third_party/ulib/musl/include/signal.h new file mode 100644 index 000000000..7b4a8c373 --- /dev/null +++ b/third_party/ulib/musl/include/signal.h @@ -0,0 +1,267 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#ifdef _GNU_SOURCE +#define __ucontext ucontext +#endif + +#define __NEED_size_t +#define __NEED_pid_t +#define __NEED_uid_t +#define __NEED_struct_timespec +#define __NEED_pthread_t +#define __NEED_pthread_attr_t +#define __NEED_time_t +#define __NEED_clock_t +#define __NEED_sigset_t + +#include + +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +typedef struct sigaltstack stack_t; + +#endif + +#include + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define SIG_HOLD ((void (*)(int))2) + +#define FPE_INTDIV 1 +#define FPE_INTOVF 2 +#define FPE_FLTDIV 3 +#define FPE_FLTOVF 4 +#define FPE_FLTUND 5 +#define FPE_FLTRES 6 +#define FPE_FLTINV 7 +#define FPE_FLTSUB 8 + +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 + +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 +#define SEGV_BNDERR 3 + +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +union sigval { + int sival_int; + void* sival_ptr; +}; + +typedef struct { +#ifdef __SI_SWAP_ERRNO_CODE + int si_signo, si_code, si_errno; +#else + int si_signo, si_errno, si_code; +#endif + union { + char __pad[128 - 2 * sizeof(int) - sizeof(long)]; + struct { + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + struct { + void* si_addr; + short si_addr_lsb; + struct { + void* si_lower; + void* si_upper; + } __addr_bnd; + } __sigfault; + struct { + long si_band; + int si_fd; + } __sigpoll; + struct { + void* si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value +#define si_addr __si_fields.__sigfault.si_addr +#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__addr_bnd.si_upper +#define si_band __si_fields.__sigpoll.si_band +#define si_fd __si_fields.__sigpoll.si_fd +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int +#define si_call_addr __si_fields.__sigsys.si_call_addr +#define si_syscall __si_fields.__sigsys.si_syscall +#define si_arch __si_fields.__sigsys.si_arch + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t*, void*); + } __sa_handler; + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; +#define sa_handler __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + +struct sigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + void (*sigev_notify_function)(union sigval); + pthread_attr_t* sigev_notify_attributes; + char __pad[56 - 3 * sizeof(long)]; +}; + +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 + +int __libc_current_sigrtmin(void); +int __libc_current_sigrtmax(void); + +#define SIGRTMIN (__libc_current_sigrtmin()) +#define SIGRTMAX (__libc_current_sigrtmax()) + +int kill(pid_t, int); + +int sigemptyset(sigset_t*); +int sigfillset(sigset_t*); +int sigaddset(sigset_t*, int); +int sigdelset(sigset_t*, int); +int sigismember(const sigset_t*, int); + +int sigprocmask(int, const sigset_t* __restrict, sigset_t* __restrict); +int sigsuspend(const sigset_t*); +int sigaction(int, const struct sigaction* __restrict, struct sigaction* __restrict); +int sigpending(sigset_t*); +int sigwait(const sigset_t* __restrict, int* __restrict); +int sigwaitinfo(const sigset_t* __restrict, siginfo_t* __restrict); +int sigtimedwait(const sigset_t* __restrict, siginfo_t* __restrict, + const struct timespec* __restrict); +int sigqueue(pid_t, int, const union sigval); + +int pthread_sigmask(int, const sigset_t* __restrict, sigset_t* __restrict); +int pthread_kill(pthread_t, int); + +void psiginfo(const siginfo_t*, const char*); +void psignal(int, const char*); + +#endif + +#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +int killpg(pid_t, int); +int sigaltstack(const stack_t* __restrict, stack_t* __restrict); +int sighold(int); +int sigignore(int); +int siginterrupt(int, int); +int sigpause(int); +int sigrelse(int); +void (*sigset(int, void (*)(int)))(int); +#define TRAP_BRKPT 1 +#define TRAP_TRACE 2 +#define POLL_IN 1 +#define POLL_OUT 2 +#define POLL_MSG 3 +#define POLL_ERR 4 +#define POLL_PRI 5 +#define POLL_HUP 6 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 +#endif + +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#define NSIG _NSIG +typedef void (*sig_t)(int); +#endif + +#ifdef _GNU_SOURCE +typedef void (*sighandler_t)(int); +void (*bsd_signal(int, void (*)(int)))(int); +int sigisemptyset(const sigset_t*); +int sigorset(sigset_t*, const sigset_t*, const sigset_t*); +int sigandset(sigset_t*, const sigset_t*, const sigset_t*); + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#endif + +#define SIG_ERR ((void (*)(int)) - 1) +#define SIG_DFL ((void (*)(int))0) +#define SIG_IGN ((void (*)(int))1) + +typedef int sig_atomic_t; + +void (*signal(int, void (*)(int)))(int); +int raise(int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/spawn.h b/third_party/ulib/musl/include/spawn.h new file mode 100644 index 000000000..2e1027c93 --- /dev/null +++ b/third_party/ulib/musl/include/spawn.h @@ -0,0 +1,79 @@ +#ifndef _SPAWN_H +#define _SPAWN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_mode_t +#define __NEED_pid_t +#define __NEED_sigset_t + +#include + +struct sched_param; + +#define POSIX_SPAWN_RESETIDS 1 +#define POSIX_SPAWN_SETPGROUP 2 +#define POSIX_SPAWN_SETSIGDEF 4 +#define POSIX_SPAWN_SETSIGMASK 8 +#define POSIX_SPAWN_SETSCHEDPARAM 16 +#define POSIX_SPAWN_SETSCHEDULER 32 + +typedef struct { + int __flags; + pid_t __pgrp; + sigset_t __def, __mask; + int __prio, __pol, __pad[16]; +} posix_spawnattr_t; + +typedef struct { + int __pad0[2]; + void* __actions; + int __pad[16]; +} posix_spawn_file_actions_t; + +int posix_spawn(pid_t* __restrict, const char* __restrict, const posix_spawn_file_actions_t*, + const posix_spawnattr_t* __restrict, char* const* __restrict, + char* const* __restrict); +int posix_spawnp(pid_t* __restrict, const char* __restrict, const posix_spawn_file_actions_t*, + const posix_spawnattr_t* __restrict, char* const* __restrict, + char* const* __restrict); + +int posix_spawnattr_init(posix_spawnattr_t*); +int posix_spawnattr_destroy(posix_spawnattr_t*); + +int posix_spawnattr_setflags(posix_spawnattr_t*, short); +int posix_spawnattr_getflags(const posix_spawnattr_t* __restrict, short* __restrict); + +int posix_spawnattr_setpgroup(posix_spawnattr_t*, pid_t); +int posix_spawnattr_getpgroup(const posix_spawnattr_t* __restrict, pid_t* __restrict); + +int posix_spawnattr_setsigmask(posix_spawnattr_t* __restrict, const sigset_t* __restrict); +int posix_spawnattr_getsigmask(const posix_spawnattr_t* __restrict, sigset_t* __restrict); + +int posix_spawnattr_setsigdefault(posix_spawnattr_t* __restrict, const sigset_t* __restrict); +int posix_spawnattr_getsigdefault(const posix_spawnattr_t* __restrict, sigset_t* __restrict); + +int posix_spawnattr_setschedparam(posix_spawnattr_t* __restrict, + const struct sched_param* __restrict); +int posix_spawnattr_getschedparam(const posix_spawnattr_t* __restrict, + struct sched_param* __restrict); +int posix_spawnattr_setschedpolicy(posix_spawnattr_t*, int); +int posix_spawnattr_getschedpolicy(const posix_spawnattr_t* __restrict, int* __restrict); + +int posix_spawn_file_actions_init(posix_spawn_file_actions_t*); +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t*); + +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* __restrict, int, + const char* __restrict, int, mode_t); +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t*, int); +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t*, int, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdalign.h b/third_party/ulib/musl/include/stdalign.h new file mode 100644 index 000000000..f18c08b62 --- /dev/null +++ b/third_party/ulib/musl/include/stdalign.h @@ -0,0 +1,20 @@ +#ifndef _STDALIGN_H +#define _STDALIGN_H + +#ifndef __cplusplus + +/* this whole header only works in C11 or with compiler extensions */ +#if __STDC_VERSION__ < 201112L && defined(__GNUC__) +#define _Alignas(t) __attribute__((__aligned__(t))) +#define _Alignof(t) __alignof__(t) +#endif + +#define alignas _Alignas +#define alignof _Alignof + +#endif + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif diff --git a/third_party/ulib/musl/include/stdarg.h b/third_party/ulib/musl/include/stdarg.h new file mode 100644 index 000000000..16ffc88a4 --- /dev/null +++ b/third_party/ulib/musl/include/stdarg.h @@ -0,0 +1,25 @@ +#ifndef _STDARG_H +#define _STDARG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_va_list + +#include + +#if __GNUC__ >= 3 +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) +#else +#include +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdbool.h b/third_party/ulib/musl/include/stdbool.h new file mode 100644 index 000000000..a9d7ab787 --- /dev/null +++ b/third_party/ulib/musl/include/stdbool.h @@ -0,0 +1,14 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus + +#define true 1 +#define false 0 +#define bool _Bool + +#endif + +#define __bool_true_false_are_defined 1 + +#endif diff --git a/third_party/ulib/musl/include/stddef.h b/third_party/ulib/musl/include/stddef.h new file mode 100644 index 000000000..194bdc976 --- /dev/null +++ b/third_party/ulib/musl/include/stddef.h @@ -0,0 +1,25 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define __NEED_ptrdiff_t +#define __NEED_size_t +#define __NEED_wchar_t +#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L +#define __NEED_max_align_t +#endif + +#include + +#if __GNUC__ > 3 +#define offsetof(type, member) __builtin_offsetof(type, member) +#else +#define offsetof(type, member) ((size_t)((char*)&(((type*)0)->member) - (char*)0)) +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdint.h b/third_party/ulib/musl/include/stdint.h new file mode 100644 index 000000000..4616a48ce --- /dev/null +++ b/third_party/ulib/musl/include/stdint.h @@ -0,0 +1,117 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#define __NEED_int8_t +#define __NEED_int16_t +#define __NEED_int32_t +#define __NEED_int64_t + +#define __NEED_uint8_t +#define __NEED_uint16_t +#define __NEED_uint32_t +#define __NEED_uint64_t + +#define __NEED_intptr_t +#define __NEED_uintptr_t + +#define __NEED_intmax_t +#define __NEED_uintmax_t + +#include + +typedef int8_t int_fast8_t; +typedef int64_t int_fast64_t; + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; + +typedef uint8_t uint_fast8_t; +typedef uint64_t uint_fast64_t; + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +#define INT8_MIN (-1 - 0x7f) +#define INT16_MIN (-1 - 0x7fff) +#define INT32_MIN (-1 - 0x7fffffff) +#define INT64_MIN (-1 - 0x7fffffffffffffff) + +#define INT8_MAX (0x7f) +#define INT16_MAX (0x7fff) +#define INT32_MAX (0x7fffffff) +#define INT64_MAX (0x7fffffffffffffff) + +#define UINT8_MAX (0xff) +#define UINT16_MAX (0xffff) +#define UINT32_MAX (0xffffffffu) +#define UINT64_MAX (0xffffffffffffffffu) + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST64_MAX INT64_MAX + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +#define WINT_MIN 0U +#define WINT_MAX UINT32_MAX + +#if L'\0' - 1 > 0 +#define WCHAR_MAX (0xffffffffu + L'\0') +#define WCHAR_MIN (0 + L'\0') +#else +#define WCHAR_MAX (0x7fffffff + L'\0') +#define WCHAR_MIN (-1 - 0x7fffffff + L'\0') +#endif + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#include + +#define INT8_C(c) c +#define INT16_C(c) c +#define INT32_C(c) c + +#define UINT8_C(c) c +#define UINT16_C(c) c +#define UINT32_C(c) c##U + +#if UINTPTR_MAX == UINT64_MAX +#define INT64_C(c) c##L +#define UINT64_C(c) c##UL +#define INTMAX_C(c) c##L +#define UINTMAX_C(c) c##UL +#else +#define INT64_C(c) c##LL +#define UINT64_C(c) c##ULL +#define INTMAX_C(c) c##LL +#define UINTMAX_C(c) c##ULL +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdio.h b/third_party/ulib/musl/include/stdio.h new file mode 100644 index 000000000..258952b74 --- /dev/null +++ b/third_party/ulib/musl/include/stdio.h @@ -0,0 +1,202 @@ +#ifndef _STDIO_H +#define _STDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __printflike(__fmt,__varargs) __attribute__((__format__ (__printf__, __fmt, __varargs))) +#define __scanflike(__fmt,__varargs) __attribute__((__format__ (__scanf__, __fmt, __varargs))) + +#define __NEED_FILE +#define __NEED___isoc_va_list +#define __NEED_size_t + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_ssize_t +#define __NEED_off_t +#define __NEED_va_list +#endif + +#include + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#undef EOF +#define EOF (-1) + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 + +#define BUFSIZ 1024 +#define FILENAME_MAX 4096 +#define FOPEN_MAX 1000 +#define TMP_MAX 10000 +#define L_tmpnam 20 + +typedef union _G_fpos64_t { + char __opaque[16]; + double __align; +} fpos_t; + +extern FILE* const stdin; +extern FILE* const stdout; +extern FILE* const stderr; + +#define stdin (stdin) +#define stdout (stdout) +#define stderr (stderr) + +FILE* fopen(const char* __restrict, const char* __restrict); +FILE* freopen(const char* __restrict, const char* __restrict, FILE* __restrict); +int fclose(FILE*); + +int remove(const char*); +int rename(const char*, const char*); + +int feof(FILE*); +int ferror(FILE*); +int fflush(FILE*); +void clearerr(FILE*); + +int fseek(FILE*, long, int); +long ftell(FILE*); +void rewind(FILE*); + +int fgetpos(FILE* __restrict, fpos_t* __restrict); +int fsetpos(FILE*, const fpos_t*); + +size_t fread(void* __restrict, size_t, size_t, FILE* __restrict); +size_t fwrite(const void* __restrict, size_t, size_t, FILE* __restrict); + +int fgetc(FILE*); +int getc(FILE*); +int getchar(void); +int ungetc(int, FILE*); + +int fputc(int, FILE*); +int putc(int, FILE*); +int putchar(int); + +char* fgets(char* __restrict, int, FILE* __restrict); +#if __STDC_VERSION__ < 201112L +char* gets(char*); +#endif + +int fputs(const char* __restrict, FILE* __restrict); +int puts(const char*); + +int printf(const char* __restrict, ...) __printflike(1, 2); +int fprintf(FILE* __restrict, const char* __restrict, ...) __printflike(2, 3); +int sprintf(char* __restrict, const char* __restrict, ...) __printflike(2, 3); +int snprintf(char* __restrict, size_t, const char* __restrict, ...) __printflike(3, 4); + +int vprintf(const char* __restrict, __isoc_va_list) __printflike(1, 0); +int vfprintf(FILE* __restrict, const char* __restrict, __isoc_va_list) __printflike(2, 0); +int vsprintf(char* __restrict, const char* __restrict, __isoc_va_list) __printflike(2, 0); +int vsnprintf(char* __restrict, size_t, const char* __restrict, __isoc_va_list) __printflike(3, 0); + +int scanf(const char* __restrict, ...) __scanflike(1, 2); +int fscanf(FILE* __restrict, const char* __restrict, ...) __scanflike(2, 3); +int sscanf(const char* __restrict, const char* __restrict, ...) __scanflike(2, 3); +int vscanf(const char* __restrict, __isoc_va_list) __scanflike(1, 0); +int vfscanf(FILE* __restrict, const char* __restrict, __isoc_va_list) __scanflike(2, 0); +int vsscanf(const char* __restrict, const char* __restrict, __isoc_va_list) __scanflike(2, 0); + +void perror(const char*); + +int setvbuf(FILE* __restrict, char* __restrict, int, size_t); +void setbuf(FILE* __restrict, char* __restrict); + +char* tmpnam(char*); +FILE* tmpfile(void); + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +FILE* fmemopen(void* __restrict, size_t, const char* __restrict); +FILE* open_memstream(char**, size_t*); +FILE* fdopen(int, const char*); +FILE* popen(const char*, const char*); +int pclose(FILE*); +int fileno(FILE*); +int fseeko(FILE*, off_t, int); +off_t ftello(FILE*); +int dprintf(int, const char* __restrict, ...) __printflike(2, 3); +int vdprintf(int, const char* __restrict, __isoc_va_list) __printflike(2, 0); +void flockfile(FILE*); +int ftrylockfile(FILE*); +void funlockfile(FILE*); +int getc_unlocked(FILE*); +int getchar_unlocked(void); +int putc_unlocked(int, FILE*); +int putchar_unlocked(int); +ssize_t getdelim(char** __restrict, size_t* __restrict, int, FILE* __restrict); +ssize_t getline(char** __restrict, size_t* __restrict, FILE* __restrict); +int renameat(int, const char*, int, const char*); +char* ctermid(char*); +#define L_ctermid 20 +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define P_tmpdir "/tmp" +char* tempnam(const char*, const char*); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define L_cuserid 20 +char* cuserid(char*); +void setlinebuf(FILE*); +void setbuffer(FILE*, char*, size_t); +int fgetc_unlocked(FILE*); +int fputc_unlocked(int, FILE*); +int fflush_unlocked(FILE*); +size_t fread_unlocked(void*, size_t, size_t, FILE*); +size_t fwrite_unlocked(const void*, size_t, size_t, FILE*); +void clearerr_unlocked(FILE*); +int feof_unlocked(FILE*); +int ferror_unlocked(FILE*); +int fileno_unlocked(FILE*); +int getw(FILE*); +int putw(int, FILE*); +char* fgetln(FILE*, size_t*); +int asprintf(char**, const char*, ...) __printflike(2, 3); +int vasprintf(char**, const char*, __isoc_va_list) __printflike(2, 0); +#endif + +#ifdef _GNU_SOURCE +char* fgets_unlocked(char*, int, FILE*); +int fputs_unlocked(const char*, FILE*); +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define tmpfile64 tmpfile +#define fopen64 fopen +#define freopen64 freopen +#define fseeko64 fseeko +#define ftello64 ftello +#define fgetpos64 fgetpos +#define fsetpos64 fsetpos +#define fpos64_t fpos_t +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdio_ext.h b/third_party/ulib/musl/include/stdio_ext.h new file mode 100644 index 000000000..3b8bdc119 --- /dev/null +++ b/third_party/ulib/musl/include/stdio_ext.h @@ -0,0 +1,34 @@ +#ifndef _STDIO_EXT_H +#define _STDIO_EXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define FSETLOCKING_QUERY 0 +#define FSETLOCKING_INTERNAL 1 +#define FSETLOCKING_BYCALLER 2 + +void _flushlbf(void); +int __fsetlocking(FILE*, int); +int __fwriting(FILE*); +int __freading(FILE*); +int __freadable(FILE*); +int __fwritable(FILE*); +int __flbf(FILE*); +size_t __fbufsize(FILE*); +size_t __fpending(FILE*); +int __fpurge(FILE*); + +size_t __freadahead(FILE*); +const char* __freadptr(FILE*, size_t*); +void __freadptrinc(FILE*, size_t); +void __fseterr(FILE*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdlib.h b/third_party/ulib/musl/include/stdlib.h new file mode 100644 index 000000000..8573e7663 --- /dev/null +++ b/third_party/ulib/musl/include/stdlib.h @@ -0,0 +1,170 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#define __NEED_wchar_t + +#include + +int atoi(const char*); +long atol(const char*); +long long atoll(const char*); +double atof(const char*); + +float strtof(const char* __restrict, char** __restrict); +double strtod(const char* __restrict, char** __restrict); +long double strtold(const char* __restrict, char** __restrict); + +long strtol(const char* __restrict, char** __restrict, int); +unsigned long strtoul(const char* __restrict, char** __restrict, int); +long long strtoll(const char* __restrict, char** __restrict, int); +unsigned long long strtoull(const char* __restrict, char** __restrict, int); + +int rand(void); +void srand(unsigned); + +void* malloc(size_t); +void* calloc(size_t, size_t); +void* realloc(void*, size_t); +void free(void*); +void* aligned_alloc(size_t alignment, size_t size); + +_Noreturn void abort(void); +int atexit(void (*)(void)); +_Noreturn void exit(int); +_Noreturn void _Exit(int); +int at_quick_exit(void (*)(void)); +_Noreturn void quick_exit(int); + +char* getenv(const char*); + +int system(const char*); + +void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*)); +void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); + +int abs(int); +long labs(long); +long long llabs(long long); + +typedef struct { int quot, rem; } div_t; +typedef struct { long quot, rem; } ldiv_t; +typedef struct { long long quot, rem; } lldiv_t; + +div_t div(int, int); +ldiv_t ldiv(long, long); +lldiv_t lldiv(long long, long long); + +int mblen(const char*, size_t); +int mbtowc(wchar_t* __restrict, const char* __restrict, size_t); +int wctomb(char*, wchar_t); +size_t mbstowcs(wchar_t* __restrict, const char* __restrict, size_t); +size_t wcstombs(char* __restrict, const wchar_t* __restrict, size_t); + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +size_t __ctype_get_mb_cur_max(void); +#define MB_CUR_MAX (__ctype_get_mb_cur_max()) + +#define RAND_MAX (0x7fffffff) + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WEXITSTATUS(s) (((s)&0xff00) >> 8) +#define WTERMSIG(s) ((s)&0x7f) +#define WSTOPSIG(s) WEXITSTATUS(s) +#define WIFEXITED(s) (!WTERMSIG(s)) +#define WIFSTOPPED(s) ((short)((((s)&0xffff) * 0x10001) >> 8) > 0x7f00) +#define WIFSIGNALED(s) (((s)&0xffff) - 1U < 0xffu) + +int posix_memalign(void**, size_t, size_t); +int setenv(const char*, const char*, int); +int unsetenv(const char*); +int mkstemp(char*); +int mkostemp(char*, int); +char* mkdtemp(char*); +int getsubopt(char**, char* const*, char**); +int rand_r(unsigned*); + +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +char* realpath(const char* __restrict, char* __restrict); +long int random(void); +void srandom(unsigned int); +char* initstate(unsigned int, char*, size_t); +char* setstate(char*); +int putenv(char*); +int posix_openpt(int); +int grantpt(int); +int unlockpt(int); +char* ptsname(int); +char* l64a(long); +long a64l(const char*); +void setkey(const char*); +double drand48(void); +double erand48(unsigned short[3]); +long int lrand48(void); +long int nrand48(unsigned short[3]); +long mrand48(void); +long jrand48(unsigned short[3]); +void srand48(long); +unsigned short* seed48(unsigned short[3]); +void lcong48(unsigned short[7]); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#include +char* mktemp(char*); +int mkstemps(char*, int); +int mkostemps(char*, int, int); +void* valloc(size_t); +void* memalign(size_t, size_t); +int getloadavg(double*, int); +int clearenv(void); +#define WCOREDUMP(s) ((s)&0x80) +#define WIFCONTINUED(s) ((s) == 0xffff) +#endif + +#ifdef _GNU_SOURCE +int ptsname_r(int, char*, size_t); +char* ecvt(double, int, int*, int*); +char* fcvt(double, int, int*, int*); +char* gcvt(double, int, char*); +struct __locale_struct; +float strtof_l(const char* __restrict, char** __restrict, struct __locale_struct*); +double strtod_l(const char* __restrict, char** __restrict, struct __locale_struct*); +long double strtold_l(const char* __restrict, char** __restrict, struct __locale_struct*); +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define mkstemp64 mkstemp +#define mkostemp64 mkostemp +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define mkstemps64 mkstemps +#define mkostemps64 mkostemps +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/stdnoreturn.h b/third_party/ulib/musl/include/stdnoreturn.h new file mode 100644 index 000000000..5c6aeeb00 --- /dev/null +++ b/third_party/ulib/musl/include/stdnoreturn.h @@ -0,0 +1,7 @@ +#ifndef _STDNORETURN_H +#define _STDNORETURN_H +#ifndef __cplusplus +#include +#define noreturn _Noreturn +#endif +#endif diff --git a/third_party/ulib/musl/include/string.h b/third_party/ulib/musl/include/string.h new file mode 100644 index 000000000..34eb38992 --- /dev/null +++ b/third_party/ulib/musl/include/string.h @@ -0,0 +1,103 @@ +#ifndef _STRING_H +#define _STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_locale_t +#endif + +#include + +void* memcpy(void* __restrict, const void* __restrict, size_t); +void* memmove(void*, const void*, size_t); +void* memset(void*, int, size_t); +int memcmp(const void*, const void*, size_t); +void* memchr(const void*, int, size_t); + +char* strcpy(char* __restrict, const char* __restrict); +char* strncpy(char* __restrict, const char* __restrict, size_t); + +char* strcat(char* __restrict, const char* __restrict); +char* strncat(char* __restrict, const char* __restrict, size_t); + +int strcmp(const char*, const char*); +int strncmp(const char*, const char*, size_t); + +int strcoll(const char*, const char*); +size_t strxfrm(char* __restrict, const char* __restrict, size_t); + +char* strchr(const char*, int); +char* strrchr(const char*, int); + +size_t strcspn(const char*, const char*); +size_t strspn(const char*, const char*); +char* strpbrk(const char*, const char*); +char* strstr(const char*, const char*); +char* strtok(char* __restrict, const char* __restrict); + +size_t strlen(const char*); + +char* strerror(int); + +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#include +#endif + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +char* strtok_r(char* __restrict, const char* __restrict, char** __restrict); +int strerror_r(int, char*, size_t); +char* stpcpy(char* __restrict, const char* __restrict); +char* stpncpy(char* __restrict, const char* __restrict, size_t); +size_t strnlen(const char*, size_t); +char* strdup(const char*); +char* strndup(const char*, size_t); +char* strsignal(int); +char* strerror_l(int, locale_t); +int strcoll_l(const char*, const char*, locale_t); +size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale_t); +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +void* memccpy(void* __restrict, const void* __restrict, int, size_t); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +char* strsep(char**, const char*); +size_t strlcat(char*, const char*, size_t); +size_t strlcpy(char*, const char*, size_t); +#endif + +#ifdef _GNU_SOURCE +#define strdupa(x) strcpy(alloca(strlen(x) + 1), x) +int strverscmp(const char*, const char*); +int strcasecmp_l(const char*, const char*, locale_t); +int strncasecmp_l(const char*, const char*, size_t, locale_t); +char* strchrnul(const char*, int); +char* strcasestr(const char*, const char*); +void* memmem(const void*, size_t, const void*, size_t); +void* memrchr(const void*, int, size_t); +void* mempcpy(void*, const void*, size_t); +#ifndef __cplusplus +char* basename(void); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/strings.h b/third_party/ulib/musl/include/strings.h new file mode 100644 index 000000000..8c5665e33 --- /dev/null +++ b/third_party/ulib/musl/include/strings.h @@ -0,0 +1,38 @@ +#ifndef _STRINGS_H +#define _STRINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#define __NEED_locale_t +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_POSIX_SOURCE) || \ + (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE + 0 < 200809L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE + 0 < 700) +int bcmp(const void*, const void*, size_t); +void bcopy(const void*, void*, size_t); +void bzero(void*, size_t); +char* index(const char*, int); +char* rindex(const char*, int); +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int ffs(int); +int ffsl(long); +int ffsll(long long); +#endif + +int strcasecmp(const char*, const char*); +int strncasecmp(const char*, const char*, size_t); + +int strcasecmp_l(const char*, const char*, locale_t); +int strncasecmp_l(const char*, const char*, size_t, locale_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/stropts.h b/third_party/ulib/musl/include/stropts.h new file mode 100644 index 000000000..82d3502b8 --- /dev/null +++ b/third_party/ulib/musl/include/stropts.h @@ -0,0 +1,139 @@ +#ifndef _STROPTS_H +#define _STROPTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __SID ('S' << 8) + +#define I_NREAD (__SID | 1) +#define I_PUSH (__SID | 2) +#define I_POP (__SID | 3) +#define I_LOOK (__SID | 4) +#define I_FLUSH (__SID | 5) +#define I_SRDOPT (__SID | 6) +#define I_GRDOPT (__SID | 7) +#define I_STR (__SID | 8) +#define I_SETSIG (__SID | 9) +#define I_GETSIG (__SID | 10) +#define I_FIND (__SID | 11) +#define I_LINK (__SID | 12) +#define I_UNLINK (__SID | 13) +#define I_PEEK (__SID | 15) +#define I_FDINSERT (__SID | 16) +#define I_SENDFD (__SID | 17) +#define I_RECVFD (__SID | 14) +#define I_SWROPT (__SID | 19) +#define I_GWROPT (__SID | 20) +#define I_LIST (__SID | 21) +#define I_PLINK (__SID | 22) +#define I_PUNLINK (__SID | 23) +#define I_FLUSHBAND (__SID | 28) +#define I_CKBAND (__SID | 29) +#define I_GETBAND (__SID | 30) +#define I_ATMARK (__SID | 31) +#define I_SETCLTIME (__SID | 32) +#define I_GETCLTIME (__SID | 33) +#define I_CANPUT (__SID | 34) + +#define FMNAMESZ 8 + +#define FLUSHR 0x01 +#define FLUSHW 0x02 +#define FLUSHRW 0x03 +#define FLUSHBAND 0x04 + +#define S_INPUT 0x0001 +#define S_HIPRI 0x0002 +#define S_OUTPUT 0x0004 +#define S_MSG 0x0008 +#define S_ERROR 0x0010 +#define S_HANGUP 0x0020 +#define S_RDNORM 0x0040 +#define S_WRNORM S_OUTPUT +#define S_RDBAND 0x0080 +#define S_WRBAND 0x0100 +#define S_BANDURG 0x0200 + +#define RS_HIPRI 0x01 + +#define RNORM 0x0000 +#define RMSGD 0x0001 +#define RMSGN 0x0002 +#define RPROTDAT 0x0004 +#define RPROTDIS 0x0008 +#define RPROTNORM 0x0010 +#define RPROTMASK 0x001C + +#define SNDZERO 0x001 +#define SNDPIPE 0x002 + +#define ANYMARK 0x01 +#define LASTMARK 0x02 + +#define MUXID_ALL (-1) + +#define MSG_HIPRI 0x01 +#define MSG_ANY 0x02 +#define MSG_BAND 0x04 + +#define MORECTL 1 +#define MOREDATA 2 + +struct bandinfo { + unsigned char bi_pri; + int bi_flag; +}; + +struct strbuf { + int maxlen; + int len; + char* buf; +}; + +struct strpeek { + struct strbuf ctlbuf; + struct strbuf databuf; + unsigned flags; +}; + +struct strfdinsert { + struct strbuf ctlbuf; + struct strbuf databuf; + unsigned flags; + int fildes; + int offset; +}; + +struct strioctl { + int ic_cmd; + int ic_timout; + int ic_len; + char* ic_dp; +}; + +struct strrecvfd { + int fd; + int uid; + int gid; + char __fill[8]; +}; + +struct str_mlist { + char l_name[FMNAMESZ + 1]; +}; + +struct str_list { + int sl_nmods; + struct str_mlist* sl_modlist; +}; + +int isastream(int); +int ioctl(int, int, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/acct.h b/third_party/ulib/musl/include/sys/acct.h new file mode 100644 index 000000000..d12f090bd --- /dev/null +++ b/third_party/ulib/musl/include/sys/acct.h @@ -0,0 +1,72 @@ +#ifndef _SYS_ACCT_H +#define _SYS_ACCT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define ACCT_COMM 16 + +typedef uint16_t comp_t; + +struct acct { + char ac_flag; + uint16_t ac_uid; + uint16_t ac_gid; + uint16_t ac_tty; + uint32_t ac_btime; + comp_t ac_utime; + comp_t ac_stime; + comp_t ac_etime; + comp_t ac_mem; + comp_t ac_io; + comp_t ac_rw; + comp_t ac_minflt; + comp_t ac_majflt; + comp_t ac_swaps; + uint32_t ac_exitcode; + char ac_comm[ACCT_COMM + 1]; + char ac_pad[10]; +}; + +struct acct_v3 { + char ac_flag; + char ac_version; + uint16_t ac_tty; + uint32_t ac_exitcode; + uint32_t ac_uid; + uint32_t ac_gid; + uint32_t ac_pid; + uint32_t ac_ppid; + uint32_t ac_btime; + float ac_etime; + comp_t ac_utime; + comp_t ac_stime; + comp_t ac_mem; + comp_t ac_io; + comp_t ac_rw; + comp_t ac_minflt; + comp_t ac_majflt; + comp_t ac_swaps; + char ac_comm[ACCT_COMM]; +}; + +#define AFORK 1 +#define ASU 2 +#define ACORE 8 +#define AXSIG 16 +#define ACCT_BYTEORDER (128 * (__BYTE_ORDER == __BIG_ENDIAN)) +#define AHZ 100 + +int acct(const char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/auxv.h b/third_party/ulib/musl/include/sys/auxv.h new file mode 100644 index 000000000..6dcf9adc2 --- /dev/null +++ b/third_party/ulib/musl/include/sys/auxv.h @@ -0,0 +1,16 @@ +#ifndef _SYS_AUXV_H +#define _SYS_AUXV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +unsigned long getauxval(unsigned long); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/cachectl.h b/third_party/ulib/musl/include/sys/cachectl.h new file mode 100644 index 000000000..edbda58ba --- /dev/null +++ b/third_party/ulib/musl/include/sys/cachectl.h @@ -0,0 +1,22 @@ +#ifndef _SYS_CACHECTL_H +#define _SYS_CACHECTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICACHE (1 << 0) +#define DCACHE (1 << 1) +#define BCACHE (ICACHE | DCACHE) +#define CACHEABLE 0 +#define UNCACHEABLE 1 + +int cachectl(void*, int, int); +int cacheflush(void*, int, int); +int _flush_cache(void*, int, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/dir.h b/third_party/ulib/musl/include/sys/dir.h new file mode 100644 index 000000000..9ba1c79e2 --- /dev/null +++ b/third_party/ulib/musl/include/sys/dir.h @@ -0,0 +1,2 @@ +#include +#define direct dirent diff --git a/third_party/ulib/musl/include/sys/epoll.h b/third_party/ulib/musl/include/sys/epoll.h new file mode 100644 index 000000000..48504d781 --- /dev/null +++ b/third_party/ulib/musl/include/sys/epoll.h @@ -0,0 +1,66 @@ +#ifndef _SYS_EPOLL_H +#define _SYS_EPOLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define __NEED_sigset_t + +#include + +#define EPOLL_CLOEXEC O_CLOEXEC +#define EPOLL_NONBLOCK O_NONBLOCK + +enum EPOLL_EVENTS { __EPOLL_DUMMY }; +#define EPOLLIN 0x001 +#define EPOLLPRI 0x002 +#define EPOLLOUT 0x004 +#define EPOLLRDNORM 0x040 +#define EPOLLRDBAND 0x080 +#define EPOLLWRNORM 0x100 +#define EPOLLWRBAND 0x200 +#define EPOLLMSG 0x400 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 +#define EPOLLRDHUP 0x2000 +#define EPOLLEXCLUSIVE (1U << 28) +#define EPOLLWAKEUP (1U << 29) +#define EPOLLONESHOT (1U << 30) +#define EPOLLET (1U << 31) + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 + +typedef union epoll_data { + void* ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event { + uint32_t events; + epoll_data_t data; +} +#ifdef __x86_64__ +__attribute__((__packed__)) +#endif +; + +int epoll_create(int); +int epoll_create1(int); +int epoll_ctl(int, int, int, struct epoll_event*); +int epoll_wait(int, struct epoll_event*, int, int); +int epoll_pwait(int, struct epoll_event*, int, int, const sigset_t*); + +#ifdef __cplusplus +} +#endif + +#endif /* sys/epoll.h */ diff --git a/third_party/ulib/musl/include/sys/errno.h b/third_party/ulib/musl/include/sys/errno.h new file mode 100644 index 000000000..35a3e5a2a --- /dev/null +++ b/third_party/ulib/musl/include/sys/errno.h @@ -0,0 +1,2 @@ +#warning redirecting incorrect #include to +#include diff --git a/third_party/ulib/musl/include/sys/eventfd.h b/third_party/ulib/musl/include/sys/eventfd.h new file mode 100644 index 000000000..546a2b586 --- /dev/null +++ b/third_party/ulib/musl/include/sys/eventfd.h @@ -0,0 +1,25 @@ +#ifndef _SYS_EVENTFD_H +#define _SYS_EVENTFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef uint64_t eventfd_t; + +#define EFD_SEMAPHORE 1 +#define EFD_CLOEXEC O_CLOEXEC +#define EFD_NONBLOCK O_NONBLOCK + +int eventfd(unsigned int, int); +int eventfd_read(int, eventfd_t*); +int eventfd_write(int, eventfd_t); + +#ifdef __cplusplus +} +#endif + +#endif /* sys/eventfd.h */ diff --git a/third_party/ulib/musl/include/sys/fanotify.h b/third_party/ulib/musl/include/sys/fanotify.h new file mode 100644 index 000000000..4de0f112e --- /dev/null +++ b/third_party/ulib/musl/include/sys/fanotify.h @@ -0,0 +1,81 @@ +#ifndef _FANOTIFY_H +#define _FANOTIFY_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct fanotify_event_metadata { + unsigned event_len; + unsigned char vers; + unsigned char reserved; + unsigned short metadata_len; + unsigned long long mask +#ifdef __GNUC__ + __attribute__((__aligned__(8))) +#endif + ; + int fd; + int pid; +}; + +struct fanotify_response { + int fd; + unsigned response; +}; + +#define FAN_ACCESS 0x01 +#define FAN_MODIFY 0x02 +#define FAN_CLOSE_WRITE 0x08 +#define FAN_CLOSE_NOWRITE 0x10 +#define FAN_OPEN 0x20 +#define FAN_Q_OVERFLOW 0x4000 +#define FAN_OPEN_PERM 0x10000 +#define FAN_ACCESS_PERM 0x20000 +#define FAN_ONDIR 0x40000000 +#define FAN_EVENT_ON_CHILD 0x08000000 +#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) +#define FAN_CLOEXEC 0x01 +#define FAN_NONBLOCK 0x02 +#define FAN_CLASS_NOTIF 0 +#define FAN_CLASS_CONTENT 0x04 +#define FAN_CLASS_PRE_CONTENT 0x08 +#define FAN_ALL_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | FAN_CLASS_PRE_CONTENT) +#define FAN_UNLIMITED_QUEUE 0x10 +#define FAN_UNLIMITED_MARKS 0x20 +#define FAN_ALL_INIT_FLAGS \ + (FAN_CLOEXEC | FAN_NONBLOCK | FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS) +#define FAN_MARK_ADD 0x01 +#define FAN_MARK_REMOVE 0x02 +#define FAN_MARK_DONT_FOLLOW 0x04 +#define FAN_MARK_ONLYDIR 0x08 +#define FAN_MARK_MOUNT 0x10 +#define FAN_MARK_IGNORED_MASK 0x20 +#define FAN_MARK_IGNORED_SURV_MODIFY 0x40 +#define FAN_MARK_FLUSH 0x80 +#define FAN_ALL_MARK_FLAGS \ + (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_DONT_FOLLOW | FAN_MARK_ONLYDIR | FAN_MARK_MOUNT | \ + FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY | FAN_MARK_FLUSH) +#define FAN_ALL_EVENTS (FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN) +#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_ACCESS_PERM) +#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_Q_OVERFLOW) +#define FANOTIFY_METADATA_VERSION 3 +#define FAN_ALLOW 0x01 +#define FAN_DENY 0x02 +#define FAN_NOFD -1 +#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) +#define FAN_EVENT_NEXT(meta, len) \ + ((len) -= (meta)->event_len, \ + (struct fanotify_event_metadata*)(((char*)(meta)) + (meta)->event_len)) +#define FAN_EVENT_OK(meta, len) \ + ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \ + (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \ + (long)(meta)->event_len <= (long)(len)) + +int fanotify_init(unsigned, unsigned); +int fanotify_mark(int, unsigned, unsigned long long, int, const char*); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/fcntl.h b/third_party/ulib/musl/include/sys/fcntl.h new file mode 100644 index 000000000..3dd928ef6 --- /dev/null +++ b/third_party/ulib/musl/include/sys/fcntl.h @@ -0,0 +1,2 @@ +#warning redirecting incorrect #include to +#include diff --git a/third_party/ulib/musl/include/sys/file.h b/third_party/ulib/musl/include/sys/file.h new file mode 100644 index 000000000..5497b3ae2 --- /dev/null +++ b/third_party/ulib/musl/include/sys/file.h @@ -0,0 +1,21 @@ +#ifndef _SYS_FILE_H +#define _SYS_FILE_H +#ifdef __cplusplus +extern "C" { +#endif + +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#define L_SET 0 +#define L_INCR 1 +#define L_XTND 2 + +int flock(int, int); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/fsuid.h b/third_party/ulib/musl/include/sys/fsuid.h new file mode 100644 index 000000000..c7a9b8faa --- /dev/null +++ b/third_party/ulib/musl/include/sys/fsuid.h @@ -0,0 +1,20 @@ +#ifndef _SYS_FSUID_H +#define _SYS_FSUID_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_uid_t +#define __NEED_gid_t + +#include + +int setfsuid(uid_t); +int setfsgid(gid_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/inotify.h b/third_party/ulib/musl/include/sys/inotify.h new file mode 100644 index 000000000..9448bd4ce --- /dev/null +++ b/third_party/ulib/musl/include/sys/inotify.h @@ -0,0 +1,57 @@ +#ifndef _SYS_INOTIFY_H +#define _SYS_INOTIFY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +struct inotify_event { + int wd; + uint32_t mask, cookie, len; + char name[]; +}; + +#define IN_CLOEXEC O_CLOEXEC +#define IN_NONBLOCK O_NONBLOCK + +#define IN_ACCESS 0x00000001 +#define IN_MODIFY 0x00000002 +#define IN_ATTRIB 0x00000004 +#define IN_CLOSE_WRITE 0x00000008 +#define IN_CLOSE_NOWRITE 0x00000010 +#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) +#define IN_OPEN 0x00000020 +#define IN_MOVED_FROM 0x00000040 +#define IN_MOVED_TO 0x00000080 +#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) +#define IN_CREATE 0x00000100 +#define IN_DELETE 0x00000200 +#define IN_DELETE_SELF 0x00000400 +#define IN_MOVE_SELF 0x00000800 +#define IN_ALL_EVENTS 0x00000fff + +#define IN_UNMOUNT 0x00002000 +#define IN_Q_OVERFLOW 0x00004000 +#define IN_IGNORED 0x00008000 + +#define IN_ONLYDIR 0x01000000 +#define IN_DONT_FOLLOW 0x02000000 +#define IN_EXCL_UNLINK 0x04000000 +#define IN_MASK_ADD 0x20000000 + +#define IN_ISDIR 0x40000000 +#define IN_ONESHOT 0x80000000 + +int inotify_init(void); +int inotify_init1(int); +int inotify_add_watch(int, const char*, uint32_t); +int inotify_rm_watch(int, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/io.h b/third_party/ulib/musl/include/sys/io.h new file mode 100644 index 000000000..648dd6764 --- /dev/null +++ b/third_party/ulib/musl/include/sys/io.h @@ -0,0 +1,17 @@ +#ifndef _SYS_IO_H +#define _SYS_IO_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +int iopl(int); +int ioperm(unsigned long, unsigned long, int); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/ioctl.h b/third_party/ulib/musl/include/sys/ioctl.h new file mode 100644 index 000000000..9901d7e8a --- /dev/null +++ b/third_party/ulib/musl/include/sys/ioctl.h @@ -0,0 +1,14 @@ +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int ioctl(int, int, ...); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/ipc.h b/third_party/ulib/musl/include/sys/ipc.h new file mode 100644 index 000000000..7c439fb55 --- /dev/null +++ b/third_party/ulib/musl/include/sys/ipc.h @@ -0,0 +1,42 @@ +#ifndef _SYS_IPC_H +#define _SYS_IPC_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_mode_t +#define __NEED_key_t + +#include + +#define __ipc_perm_key __key +#define __ipc_perm_seq __seq + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __key key +#define __seq seq +#endif + +#include + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t)0) + +key_t ftok(const char*, int); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/kd.h b/third_party/ulib/musl/include/sys/kd.h new file mode 100644 index 000000000..793fd59fe --- /dev/null +++ b/third_party/ulib/musl/include/sys/kd.h @@ -0,0 +1,8 @@ +#ifndef _SYS_KD_H +#define _SYS_KD_H + +#define _LINUX_TYPES_H +#include +#undef _LINUX_TYPES_H + +#endif diff --git a/third_party/ulib/musl/include/sys/klog.h b/third_party/ulib/musl/include/sys/klog.h new file mode 100644 index 000000000..f3a8115b1 --- /dev/null +++ b/third_party/ulib/musl/include/sys/klog.h @@ -0,0 +1,14 @@ +#ifndef _SYS_KLOG_H +#define _SYS_KLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +int klogctl(int, char*, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/mman.h b/third_party/ulib/musl/include/sys/mman.h new file mode 100644 index 000000000..04a4e0ef6 --- /dev/null +++ b/third_party/ulib/musl/include/sys/mman.h @@ -0,0 +1,118 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_mode_t +#define __NEED_size_t +#define __NEED_off_t + +#if defined(_GNU_SOURCE) +#define __NEED_ssize_t +#endif + +#include + +#define MAP_FAILED ((void*)-1) + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_TYPE 0x0f +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS MAP_ANON +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_FILE 0 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MS_ASYNC 1 +#define MS_INVALIDATE 2 +#define MS_SYNC 4 + +#define MCL_CURRENT 1 +#define MCL_FUTURE 2 +#define MCL_ONFAULT 4 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 +#endif + +#include + +void* mmap(void*, size_t, int, int, int, off_t); +int munmap(void*, size_t); + +int mprotect(void*, size_t, int); +int msync(void*, size_t, int); + +int posix_madvise(void*, size_t, int); + +int mlock(const void*, size_t); +int munlock(const void*, size_t); +int mlockall(int); +int munlockall(void); + +#ifdef _GNU_SOURCE +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 +void* mremap(void*, size_t, size_t, int, ...); +int remap_file_pages(void*, size_t, int, size_t, int); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MLOCK_ONFAULT 0x01 +int madvise(void*, size_t, int); +int mincore(void*, size_t, unsigned char*); +#endif + +int shm_open(const char*, int, mode_t); +int shm_unlink(const char*); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define mmap64 mmap +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/mount.h b/third_party/ulib/musl/include/sys/mount.h new file mode 100644 index 000000000..bb28d1867 --- /dev/null +++ b/third_party/ulib/musl/include/sys/mount.h @@ -0,0 +1,73 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define BLKROSET _IO(0x12, 93) +#define BLKROGET _IO(0x12, 94) +#define BLKRRPART _IO(0x12, 95) +#define BLKGETSIZE _IO(0x12, 96) +#define BLKFLSBUF _IO(0x12, 97) +#define BLKRASET _IO(0x12, 98) +#define BLKRAGET _IO(0x12, 99) +#define BLKFRASET _IO(0x12, 100) +#define BLKFRAGET _IO(0x12, 101) +#define BLKSECTSET _IO(0x12, 102) +#define BLKSECTGET _IO(0x12, 103) +#define BLKSSZGET _IO(0x12, 104) +#define BLKBSZGET _IOR(0x12, 112, size_t) +#define BLKBSZSET _IOW(0x12, 113, size_t) +#define BLKGETSIZE64 _IOR(0x12, 114, size_t) + +#define MS_RDONLY 1 +#define MS_NOSUID 2 +#define MS_NODEV 4 +#define MS_NOEXEC 8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT 32 +#define MS_MANDLOCK 64 +#define MS_DIRSYNC 128 +#define MS_NOATIME 1024 +#define MS_NODIRATIME 2048 +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_SILENT 32768 +#define MS_POSIXACL (1 << 16) +#define MS_UNBINDABLE (1 << 17) +#define MS_PRIVATE (1 << 18) +#define MS_SLAVE (1 << 19) +#define MS_SHARED (1 << 20) +#define MS_RELATIME (1 << 21) +#define MS_KERNMOUNT (1 << 22) +#define MS_I_VERSION (1 << 23) +#define MS_STRICTATIME (1 << 24) +#define MS_LAZYTIME (1 << 25) +#define MS_NOSEC (1 << 28) +#define MS_BORN (1 << 29) +#define MS_ACTIVE (1 << 30) +#define MS_NOUSER (1U << 31) + +#define MS_RMT_MASK (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME) + +#define MS_MGC_VAL 0xc0ed0000 +#define MS_MGC_MSK 0xffff0000 + +#define MNT_FORCE 1 +#define MNT_DETACH 2 +#define MNT_EXPIRE 4 +#define UMOUNT_NOFOLLOW 8 + +int mount(const char*, const char*, const char*, unsigned long, const void*); +int umount(const char*); +int umount2(const char*, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/msg.h b/third_party/ulib/musl/include/sys/msg.h new file mode 100644 index 000000000..05fed8694 --- /dev/null +++ b/third_party/ulib/musl/include/sys/msg.h @@ -0,0 +1,52 @@ +#ifndef _SYS_MSG_H +#define _SYS_MSG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_pid_t +#define __NEED_key_t +#define __NEED_time_t +#define __NEED_size_t +#define __NEED_ssize_t + +#include + +typedef unsigned long msgqnum_t; +typedef unsigned long msglen_t; + +#include + +#define __msg_cbytes msg_cbytes + +#define MSG_NOERROR 010000 +#define MSG_EXCEPT 020000 + +#define MSG_STAT 11 +#define MSG_INFO 12 + +struct msginfo { + int msgpool, msgmap, msgmax, msgmnb, msgmni, msgssz, msgtql; + unsigned short msgseg; +}; + +int msgctl(int, int, struct msqid_ds*); +int msgget(key_t, int); +ssize_t msgrcv(int, void*, size_t, long, int); +int msgsnd(int, const void*, size_t, int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +struct msgbuf { + long mtype; + char mtext[1]; +}; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/mtio.h b/third_party/ulib/musl/include/sys/mtio.h new file mode 100644 index 000000000..36166b4f8 --- /dev/null +++ b/third_party/ulib/musl/include/sys/mtio.h @@ -0,0 +1,185 @@ +#ifndef _SYS_MTIO_H +#define _SYS_MTIO_H + +#include +#include + +struct mtop { + short mt_op; + int mt_count; +}; + +#define _IOT_mtop _IOT(_IOTS(short), 1, _IOTS(int), 1, 0, 0) +#define _IOT_mtget _IOT(_IOTS(long), 7, 0, 0, 0, 0) +#define _IOT_mtpos _IOT_SIMPLE(long) +#define _IOT_mtconfiginfo _IOT(_IOTS(long), 2, _IOTS(short), 3, _IOTS(long), 1) + +#define MTRESET 0 +#define MTFSF 1 +#define MTBSF 2 +#define MTFSR 3 +#define MTBSR 4 +#define MTWEOF 5 +#define MTREW 6 +#define MTOFFL 7 +#define MTNOP 8 +#define MTRETEN 9 +#define MTBSFM 10 +#define MTFSFM 11 +#define MTEOM 12 +#define MTERASE 13 +#define MTRAS1 14 +#define MTRAS2 15 +#define MTRAS3 16 +#define MTSETBLK 20 +#define MTSETDENSITY 21 +#define MTSEEK 22 +#define MTTELL 23 +#define MTSETDRVBUFFER 24 +#define MTFSS 25 +#define MTBSS 26 +#define MTWSM 27 +#define MTLOCK 28 +#define MTUNLOCK 29 +#define MTLOAD 30 +#define MTUNLOAD 31 +#define MTCOMPRESSION 32 +#define MTSETPART 33 +#define MTMKPART 34 + +struct mtget { + long mt_type; + long mt_resid; + long mt_dsreg; + long mt_gstat; + long mt_erreg; + int mt_fileno; + int mt_blkno; +}; + +#define MT_ISUNKNOWN 0x01 +#define MT_ISQIC02 0x02 +#define MT_ISWT5150 0x03 +#define MT_ISARCHIVE_5945L2 0x04 +#define MT_ISCMSJ500 0x05 +#define MT_ISTDC3610 0x06 +#define MT_ISARCHIVE_VP60I 0x07 +#define MT_ISARCHIVE_2150L 0x08 +#define MT_ISARCHIVE_2060L 0x09 +#define MT_ISARCHIVESC499 0x0A +#define MT_ISQIC02_ALL_FEATURES 0x0F +#define MT_ISWT5099EEN24 0x11 +#define MT_ISTEAC_MT2ST 0x12 +#define MT_ISEVEREX_FT40A 0x32 +#define MT_ISDDS1 0x51 +#define MT_ISDDS2 0x52 +#define MT_ISSCSI1 0x71 +#define MT_ISSCSI2 0x72 +#define MT_ISFTAPE_UNKNOWN 0x800000 +#define MT_ISFTAPE_FLAG 0x800000 + +struct mt_tape_info { + long t_type; + char* t_name; +}; + +#define MT_TAPE_INFO \ + { \ + {MT_ISUNKNOWN, "Unknown type of tape device"}, \ + {MT_ISQIC02, "Generic QIC-02 tape streamer"}, {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \ + {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, {MT_ISCMSJ500, "CMS Jumbo 500"}, \ + {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \ + {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \ + {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \ + {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \ + {MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \ + {MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \ + {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \ + {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \ + {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, {MT_ISSCSI1, "Generic SCSI-1 tape"}, \ + {MT_ISSCSI2, "Generic SCSI-2 tape"}, { \ + 0, 0 \ + } \ + } + +struct mtpos { + long mt_blkno; +}; + +struct mtconfiginfo { + long mt_type; + long ifc_type; + unsigned short irqnr; + unsigned short dmanr; + unsigned short port; + unsigned long debug; + unsigned have_dens : 1; + unsigned have_bsf : 1; + unsigned have_fsr : 1; + unsigned have_bsr : 1; + unsigned have_eod : 1; + unsigned have_seek : 1; + unsigned have_tell : 1; + unsigned have_ras1 : 1; + unsigned have_ras2 : 1; + unsigned have_ras3 : 1; + unsigned have_qfa : 1; + unsigned pad1 : 5; + char reserved[10]; +}; + +#define MTIOCTOP _IOW('m', 1, struct mtop) +#define MTIOCGET _IOR('m', 2, struct mtget) +#define MTIOCPOS _IOR('m', 3, struct mtpos) + +#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) +#define MTIOCSETCONFIG _IOW('m', 5, struct mtconfiginfo) + +#define GMT_EOF(x) ((x)&0x80000000) +#define GMT_BOT(x) ((x)&0x40000000) +#define GMT_EOT(x) ((x)&0x20000000) +#define GMT_SM(x) ((x)&0x10000000) +#define GMT_EOD(x) ((x)&0x08000000) +#define GMT_WR_PROT(x) ((x)&0x04000000) +#define GMT_ONLINE(x) ((x)&0x01000000) +#define GMT_D_6250(x) ((x)&0x00800000) +#define GMT_D_1600(x) ((x)&0x00400000) +#define GMT_D_800(x) ((x)&0x00200000) +#define GMT_DR_OPEN(x) ((x)&0x00040000) +#define GMT_IM_REP_EN(x) ((x)&0x00010000) + +#define MT_ST_BLKSIZE_SHIFT 0 +#define MT_ST_BLKSIZE_MASK 0xffffff +#define MT_ST_DENSITY_SHIFT 24 +#define MT_ST_DENSITY_MASK 0xff000000 +#define MT_ST_SOFTERR_SHIFT 0 +#define MT_ST_SOFTERR_MASK 0xffff +#define MT_ST_OPTIONS 0xf0000000 +#define MT_ST_BOOLEANS 0x10000000 +#define MT_ST_SETBOOLEANS 0x30000000 +#define MT_ST_CLEARBOOLEANS 0x40000000 +#define MT_ST_WRITE_THRESHOLD 0x20000000 +#define MT_ST_DEF_BLKSIZE 0x50000000 +#define MT_ST_DEF_OPTIONS 0x60000000 +#define MT_ST_BUFFER_WRITES 0x1 +#define MT_ST_ASYNC_WRITES 0x2 +#define MT_ST_READ_AHEAD 0x4 +#define MT_ST_DEBUGGING 0x8 +#define MT_ST_TWO_FM 0x10 +#define MT_ST_FAST_MTEOM 0x20 +#define MT_ST_AUTO_LOCK 0x40 +#define MT_ST_DEF_WRITES 0x80 +#define MT_ST_CAN_BSR 0x100 +#define MT_ST_NO_BLKLIMS 0x200 +#define MT_ST_CAN_PARTITIONS 0x400 +#define MT_ST_SCSI2LOGICAL 0x800 +#define MT_ST_CLEAR_DEFAULT 0xfffff +#define MT_ST_DEF_DENSITY (MT_ST_DEF_OPTIONS | 0x100000) +#define MT_ST_DEF_COMPRESSION (MT_ST_DEF_OPTIONS | 0x200000) +#define MT_ST_DEF_DRVBUFFER (MT_ST_DEF_OPTIONS | 0x300000) +#define MT_ST_HPLOADER_OFFSET 10000 +#ifndef DEFTAPE +#define DEFTAPE "/dev/tape" +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/param.h b/third_party/ulib/musl/include/sys/param.h new file mode 100644 index 000000000..7bc47e4bf --- /dev/null +++ b/third_party/ulib/musl/include/sys/param.h @@ -0,0 +1,35 @@ +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#define MAXSYMLINKS 20 +#define MAXHOSTNAMELEN 64 +#define MAXNAMLEN 255 +#define MAXPATHLEN 4096 +#define NBBY 8 +#define NGROUPS 32 +#define CANBSIZE 255 +#define NOFILE 256 +#define NCARGS 131072 +#define DEV_BSIZE 512 +#define NOGROUP (-1) + +#undef MIN +#undef MAX +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define __bitop(x, i, o) ((x)[(i) / 8] o(1 << (i) % 8)) +#define setbit(x, i) __bitop(x, i, |=) +#define clrbit(x, i) __bitop(x, i, &= ~) +#define isset(x, i) __bitop(x, i, &) +#define isclr(x, i) !isset(x, i) + +#define howmany(n, d) (((n) + ((d)-1)) / (d)) +#define roundup(n, d) (howmany(n, d) * (d)) +#define powerof2(n) !(((n)-1) & (n)) + +#include +#include +#include + +#endif diff --git a/third_party/ulib/musl/include/sys/personality.h b/third_party/ulib/musl/include/sys/personality.h new file mode 100644 index 000000000..badcbf4cb --- /dev/null +++ b/third_party/ulib/musl/include/sys/personality.h @@ -0,0 +1,46 @@ +#ifndef _PERSONALITY_H +#define _PERSONALITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ADDR_NO_RANDOMIZE 0x0040000 +#define MMAP_PAGE_ZERO 0x0100000 +#define ADDR_COMPAT_LAYOUT 0x0200000 +#define READ_IMPLIES_EXEC 0x0400000 +#define ADDR_LIMIT_32BIT 0x0800000 +#define SHORT_INODE 0x1000000 +#define WHOLE_SECONDS 0x2000000 +#define STICKY_TIMEOUTS 0x4000000 +#define ADDR_LIMIT_3GB 0x8000000 + +#define PER_LINUX 0 +#define PER_LINUX_32BIT ADDR_LIMIT_32BIT +#define PER_SVR4 (1 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO) +#define PER_SVR3 (2 | STICKY_TIMEOUTS | SHORT_INODE) +#define PER_SCOSVR3 (3 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE) +#define PER_OSR5 (3 | STICKY_TIMEOUTS | WHOLE_SECONDS) +#define PER_WYSEV386 (4 | STICKY_TIMEOUTS | SHORT_INODE) +#define PER_ISCR4 (5 | STICKY_TIMEOUTS) +#define PER_BSD 6 +#define PER_SUNOS (6 | STICKY_TIMEOUTS) +#define PER_XENIX (7 | STICKY_TIMEOUTS | SHORT_INODE) +#define PER_LINUX32 8 +#define PER_LINUX32_3GB (8 | ADDR_LIMIT_3GB) +#define PER_IRIX32 (9 | STICKY_TIMEOUTS) +#define PER_IRIXN32 (0xa | STICKY_TIMEOUTS) +#define PER_IRIX64 (0x0b | STICKY_TIMEOUTS) +#define PER_RISCOS 0xc +#define PER_SOLARIS (0xd | STICKY_TIMEOUTS) +#define PER_UW7 (0xe | STICKY_TIMEOUTS | MMAP_PAGE_ZERO) +#define PER_OSF4 0xf +#define PER_HPUX 0x10 +#define PER_MASK 0xff + +int personality(unsigned long); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/poll.h b/third_party/ulib/musl/include/sys/poll.h new file mode 100644 index 000000000..99170401d --- /dev/null +++ b/third_party/ulib/musl/include/sys/poll.h @@ -0,0 +1,2 @@ +#warning redirecting incorrect #include to +#include diff --git a/third_party/ulib/musl/include/sys/prctl.h b/third_party/ulib/musl/include/sys/prctl.h new file mode 100644 index 000000000..d6d413f8a --- /dev/null +++ b/third_party/ulib/musl/include/sys/prctl.h @@ -0,0 +1,139 @@ +#ifndef _SYS_PRCTL_H +#define _SYS_PRCTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define PR_SET_PDEATHSIG 1 +#define PR_GET_PDEATHSIG 2 +#define PR_GET_DUMPABLE 3 +#define PR_SET_DUMPABLE 4 +#define PR_GET_UNALIGN 5 +#define PR_SET_UNALIGN 6 +#define PR_UNALIGN_NOPRINT 1 +#define PR_UNALIGN_SIGBUS 2 +#define PR_GET_KEEPCAPS 7 +#define PR_SET_KEEPCAPS 8 +#define PR_GET_FPEMU 9 +#define PR_SET_FPEMU 10 +#define PR_FPEMU_NOPRINT 1 +#define PR_FPEMU_SIGFPE 2 +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +#define PR_FP_EXC_SW_ENABLE 0x80 +#define PR_FP_EXC_DIV 0x010000 +#define PR_FP_EXC_OVF 0x020000 +#define PR_FP_EXC_UND 0x040000 +#define PR_FP_EXC_RES 0x080000 +#define PR_FP_EXC_INV 0x100000 +#define PR_FP_EXC_DISABLED 0 +#define PR_FP_EXC_NONRECOV 1 +#define PR_FP_EXC_ASYNC 2 +#define PR_FP_EXC_PRECISE 3 +#define PR_GET_TIMING 13 +#define PR_SET_TIMING 14 +#define PR_TIMING_STATISTICAL 0 +#define PR_TIMING_TIMESTAMP 1 +#define PR_SET_NAME 15 +#define PR_GET_NAME 16 +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +#define PR_ENDIAN_BIG 0 +#define PR_ENDIAN_LITTLE 1 +#define PR_ENDIAN_PPC_LITTLE 2 +#define PR_GET_SECCOMP 21 +#define PR_SET_SECCOMP 22 +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 +#define PR_GET_TSC 25 +#define PR_SET_TSC 26 +#define PR_TSC_ENABLE 1 +#define PR_TSC_SIGSEGV 2 +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 +#define PR_SET_TIMERSLACK 29 +#define PR_GET_TIMERSLACK 30 + +#define PR_TASK_PERF_EVENTS_DISABLE 31 +#define PR_TASK_PERF_EVENTS_ENABLE 32 + +#define PR_MCE_KILL 33 +#define PR_MCE_KILL_CLEAR 0 +#define PR_MCE_KILL_SET 1 +#define PR_MCE_KILL_LATE 0 +#define PR_MCE_KILL_EARLY 1 +#define PR_MCE_KILL_DEFAULT 2 +#define PR_MCE_KILL_GET 34 + +#define PR_SET_MM 35 +#define PR_SET_MM_START_CODE 1 +#define PR_SET_MM_END_CODE 2 +#define PR_SET_MM_START_DATA 3 +#define PR_SET_MM_END_DATA 4 +#define PR_SET_MM_START_STACK 5 +#define PR_SET_MM_START_BRK 6 +#define PR_SET_MM_BRK 7 +#define PR_SET_MM_ARG_START 8 +#define PR_SET_MM_ARG_END 9 +#define PR_SET_MM_ENV_START 10 +#define PR_SET_MM_ENV_END 11 +#define PR_SET_MM_AUXV 12 +#define PR_SET_MM_EXE_FILE 13 +#define PR_SET_MM_MAP 14 +#define PR_SET_MM_MAP_SIZE 15 + +struct prctl_mm_map { + uint64_t start_code; + uint64_t end_code; + uint64_t start_data; + uint64_t end_data; + uint64_t start_brk; + uint64_t brk; + uint64_t start_stack; + uint64_t arg_start; + uint64_t arg_end; + uint64_t env_start; + uint64_t env_end; + uint64_t* auxv; + uint32_t auxv_size; + uint32_t exe_fd; +}; + +#define PR_SET_PTRACER 0x59616d61 +#define PR_SET_PTRACER_ANY (-1UL) + +#define PR_SET_CHILD_SUBREAPER 36 +#define PR_GET_CHILD_SUBREAPER 37 + +#define PR_SET_NO_NEW_PRIVS 38 +#define PR_GET_NO_NEW_PRIVS 39 + +#define PR_GET_TID_ADDRESS 40 + +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +#define PR_FP_MODE_FR (1 << 0) +#define PR_FP_MODE_FRE (1 << 1) + +#define PR_CAP_AMBIENT 47 +#define PR_CAP_AMBIENT_IS_SET 1 +#define PR_CAP_AMBIENT_RAISE 2 +#define PR_CAP_AMBIENT_LOWER 3 +#define PR_CAP_AMBIENT_CLEAR_ALL 4 + +int prctl(int, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/procfs.h b/third_party/ulib/musl/include/sys/procfs.h new file mode 100644 index 000000000..1228533f9 --- /dev/null +++ b/third_party/ulib/musl/include/sys/procfs.h @@ -0,0 +1,64 @@ +#ifndef _SYS_PROCFS_H +#define _SYS_PROCFS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; + short int pr_cursig; + unsigned long int pr_sigpend; + unsigned long int pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + elf_gregset_t pr_reg; + int pr_fpvalid; +}; + +#define ELF_PRARGSZ 80 + +struct elf_prpsinfo { + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + unsigned long int pr_flag; +#if UINTPTR_MAX == 0xffffffff + unsigned short int pr_uid; + unsigned short int pr_gid; +#else + unsigned int pr_uid; + unsigned int pr_gid; +#endif + int pr_pid, pr_ppid, pr_pgrp, pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +}; + +typedef void* psaddr_t; +typedef elf_gregset_t prgregset_t; +typedef elf_fpregset_t prfpregset_t; +typedef pid_t lwpid_t; +typedef struct elf_prstatus prstatus_t; +typedef struct elf_prpsinfo prpsinfo_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/ptrace.h b/third_party/ulib/musl/include/sys/ptrace.h new file mode 100644 index 000000000..602bfb016 --- /dev/null +++ b/third_party/ulib/musl/include/sys/ptrace.h @@ -0,0 +1,100 @@ +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define PTRACE_TRACEME 0 +#define PT_TRACE_ME PTRACE_TRACEME + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_POKEUSER 6 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420a +#define PTRACE_SETSIGMASK 0x420b +#define PTRACE_SECCOMP_GET_FILTER 0x420c + +#define PT_READ_I PTRACE_PEEKTEXT +#define PT_READ_D PTRACE_PEEKDATA +#define PT_READ_U PTRACE_PEEKUSER +#define PT_WRITE_I PTRACE_POKETEXT +#define PT_WRITE_D PTRACE_POKEDATA +#define PT_WRITE_U PTRACE_POKEUSER +#define PT_CONTINUE PTRACE_CONT +#define PT_KILL PTRACE_KILL +#define PT_STEP PTRACE_SINGLESTEP +#define PT_GETREGS PTRACE_GETREGS +#define PT_SETREGS PTRACE_SETREGS +#define PT_GETFPREGS PTRACE_GETFPREGS +#define PT_SETFPREGS PTRACE_SETFPREGS +#define PT_ATTACH PTRACE_ATTACH +#define PT_DETACH PTRACE_DETACH +#define PT_GETFPXREGS PTRACE_GETFPXREGS +#define PT_SETFPXREGS PTRACE_SETFPXREGS +#define PT_SYSCALL PTRACE_SYSCALL +#define PT_SETOPTIONS PTRACE_SETOPTIONS +#define PT_GETEVENTMSG PTRACE_GETEVENTMSG +#define PT_GETSIGINFO PTRACE_GETSIGINFO +#define PT_SETSIGINFO PTRACE_SETSIGINFO + +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +struct ptrace_peeksiginfo_args { + uint64_t off; + uint32_t flags; + int32_t nr; +}; + +long ptrace(int, ...); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/quota.h b/third_party/ulib/musl/include/sys/quota.h new file mode 100644 index 000000000..044a07c9a --- /dev/null +++ b/third_party/ulib/musl/include/sys/quota.h @@ -0,0 +1,102 @@ +#ifndef _SYS_QUOTA_H +#define _SYS_QUOTA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define _LINUX_QUOTA_VERSION 2 + +#define dbtob(num) ((num) << 10) +#define btodb(num) ((num) >> 10) +#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / 1024) + +#define MAX_IQ_TIME 604800 +#define MAX_DQ_TIME 604800 + +#define MAXQUOTAS 2 +#define USRQUOTA 0 +#define GRPQUOTA 1 + +#define INITQFNAMES {"user", "group", "undefined"}; + +#define QUOTAFILENAME "quota" +#define QUOTAGROUP "staff" + +#define NR_DQHASH 43 +#define NR_DQUOTS 256 + +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type)&SUBCMDMASK)) + +#define Q_SYNC 0x800001 +#define Q_QUOTAON 0x800002 +#define Q_QUOTAOFF 0x800003 +#define Q_GETFMT 0x800004 +#define Q_GETINFO 0x800005 +#define Q_SETINFO 0x800006 +#define Q_GETQUOTA 0x800007 +#define Q_SETQUOTA 0x800008 + +#define QFMT_VFS_OLD 1 +#define QFMT_VFS_V0 2 +#define QFMT_OCFS2 3 +#define QFMT_VFS_V1 4 + +#define QIF_BLIMITS 1 +#define QIF_SPACE 2 +#define QIF_ILIMITS 4 +#define QIF_INODES 8 +#define QIF_BTIME 16 +#define QIF_ITIME 32 +#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) +#define QIF_USAGE (QIF_SPACE | QIF_INODES) +#define QIF_TIMES (QIF_BTIME | QIF_ITIME) +#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) + +struct dqblk { + uint64_t dqb_bhardlimit; + uint64_t dqb_bsoftlimit; + uint64_t dqb_curspace; + uint64_t dqb_ihardlimit; + uint64_t dqb_isoftlimit; + uint64_t dqb_curinodes; + uint64_t dqb_btime; + uint64_t dqb_itime; + uint32_t dqb_valid; +}; + +#define dq_bhardlimit dq_dqb.dqb_bhardlimit +#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit +#define dq_curspace dq_dqb.dqb_curspace +#define dq_valid dq_dqb.dqb_valid +#define dq_ihardlimit dq_dqb.dqb_ihardlimit +#define dq_isoftlimit dq_dqb.dqb_isoftlimit +#define dq_curinodes dq_dqb.dqb_curinodes +#define dq_btime dq_dqb.dqb_btime +#define dq_itime dq_dqb.dqb_itime + +#define dqoff(UID) ((long long)(UID) * sizeof(struct dqblk)) + +#define IIF_BGRACE 1 +#define IIF_IGRACE 2 +#define IIF_FLAGS 4 +#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) + +struct dqinfo { + uint64_t dqi_bgrace; + uint64_t dqi_igrace; + uint32_t dqi_flags; + uint32_t dqi_valid; +}; + +int quotactl(int, const char*, int, char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/reboot.h b/third_party/ulib/musl/include/sys/reboot.h new file mode 100644 index 000000000..726ddcda9 --- /dev/null +++ b/third_party/ulib/musl/include/sys/reboot.h @@ -0,0 +1,20 @@ +#ifndef _SYS_REBOOT_H +#define _SYS_REBOOT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +int reboot(int); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/reg.h b/third_party/ulib/musl/include/sys/reg.h new file mode 100644 index 000000000..b47452d00 --- /dev/null +++ b/third_party/ulib/musl/include/sys/reg.h @@ -0,0 +1,9 @@ +#ifndef _SYS_REG_H +#define _SYS_REG_H + +#include +#include + +#include + +#endif diff --git a/third_party/ulib/musl/include/sys/resource.h b/third_party/ulib/musl/include/sys/resource.h new file mode 100644 index 000000000..660d74c2e --- /dev/null +++ b/third_party/ulib/musl/include/sys/resource.h @@ -0,0 +1,110 @@ +#ifndef _SYS_RESOURCE_H +#define _SYS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __NEED_id_t + +#ifdef _GNU_SOURCE +#define __NEED_pid_t +#endif + +#include +#include + +typedef unsigned long long rlim_t; + +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; +}; + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + /* linux extentions, but useful */ + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; + /* room for more... */ + long __reserved[16]; +}; + +int getrlimit(int, struct rlimit*); +int setrlimit(int, const struct rlimit*); +int getrusage(int, struct rusage*); + +int getpriority(int, id_t); +int setpriority(int, id_t, int); + +#ifdef _GNU_SOURCE +int prlimit(pid_t, int, const struct rlimit*, struct rlimit*); +#define prlimit64 prlimit +#endif + +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +#define PRIO_PROCESS 0 +#define PRIO_PGRP 1 +#define PRIO_USER 2 + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN 1 + +#define RLIM_INFINITY (~0ULL) +#define RLIM_SAVED_CUR RLIM_INFINITY +#define RLIM_SAVED_MAX RLIM_INFINITY + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#ifndef RLIMIT_RSS +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#endif +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_NLIMITS 15 + +#define RLIM_NLIMITS RLIMIT_NLIMITS + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define RLIM64_INFINITY RLIM_INFINITY +#define RLIM64_SAVED_CUR RLIM_SAVED_CUR +#define RLIM64_SAVED_MAX RLIM_SAVED_MAX +#define getrlimit64 getrlimit +#define setrlimit64 setrlimit +#define rlimit64 rlimit +#define rlim64_t rlim_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/select.h b/third_party/ulib/musl/include/sys/select.h new file mode 100644 index 000000000..9b3145cc9 --- /dev/null +++ b/third_party/ulib/musl/include/sys/select.h @@ -0,0 +1,50 @@ +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#define __NEED_time_t +#define __NEED_suseconds_t +#define __NEED_struct_timeval +#define __NEED_struct_timespec +#define __NEED_sigset_t + +#include + +#define FD_SETSIZE 1024 + +typedef unsigned long fd_mask; + +typedef struct { unsigned long fds_bits[FD_SETSIZE / 8 / sizeof(long)]; } fd_set; + +#define FD_ZERO(s) \ + do { \ + int __i; \ + unsigned long* __b = (s)->fds_bits; \ + for (__i = sizeof(fd_set) / sizeof(long); __i; __i--) \ + *__b++ = 0; \ + } while (0) +#define FD_SET(d, s) \ + ((s)->fds_bits[(d) / (8 * sizeof(long))] |= (1UL << ((d) % (8 * sizeof(long))))) +#define FD_CLR(d, s) \ + ((s)->fds_bits[(d) / (8 * sizeof(long))] &= ~(1UL << ((d) % (8 * sizeof(long))))) +#define FD_ISSET(d, s) \ + !!((s)->fds_bits[(d) / (8 * sizeof(long))] & (1UL << ((d) % (8 * sizeof(long))))) + +int select(int, fd_set* __restrict, fd_set* __restrict, fd_set* __restrict, + struct timeval* __restrict); +int pselect(int, fd_set* __restrict, fd_set* __restrict, fd_set* __restrict, + const struct timespec* __restrict, const sigset_t* __restrict); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define NFDBITS (8 * (int)sizeof(long)) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/sem.h b/third_party/ulib/musl/include/sys/sem.h new file mode 100644 index 000000000..62f032b87 --- /dev/null +++ b/third_party/ulib/musl/include/sys/sem.h @@ -0,0 +1,67 @@ +#ifndef _SYS_SEM_H +#define _SYS_SEM_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#define __NEED_pid_t +#define __NEED_time_t +#ifdef _GNU_SOURCE +#define __NEED_struct_timespec +#endif +#include + +#include + +#define SEM_UNDO 0x1000 +#define GETPID 11 +#define GETVAL 12 +#define GETALL 13 +#define GETNCNT 14 +#define GETZCNT 15 +#define SETVAL 16 +#define SETALL 17 + +#include + +#include + +#define _SEM_SEMUN_UNDEFINED 1 + +#define SEM_STAT 18 +#define SEM_INFO 19 + +struct seminfo { + int semmap; + int semmni; + int semmns; + int semmnu; + int semmsl; + int semopm; + int semume; + int semusz; + int semvmx; + int semaem; +}; + +struct sembuf { + unsigned short sem_num; + short sem_op; + short sem_flg; +}; + +int semctl(int, int, int, ...); +int semget(key_t, int, int); +int semop(int, struct sembuf*, size_t); + +#ifdef _GNU_SOURCE +int semtimedop(int, struct sembuf*, size_t, const struct timespec*); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/sendfile.h b/third_party/ulib/musl/include/sys/sendfile.h new file mode 100644 index 000000000..5b27ee7f5 --- /dev/null +++ b/third_party/ulib/musl/include/sys/sendfile.h @@ -0,0 +1,22 @@ +#ifndef _SYS_SENDFILE_H +#define _SYS_SENDFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +ssize_t sendfile(int, int, off_t*, size_t); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define sendfile64 sendfile +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/shm.h b/third_party/ulib/musl/include/sys/shm.h new file mode 100644 index 000000000..7e66d7a3f --- /dev/null +++ b/third_party/ulib/musl/include/sys/shm.h @@ -0,0 +1,54 @@ +#ifndef _SYS_SHM_H +#define _SYS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_time_t +#define __NEED_size_t +#define __NEED_pid_t + +#include + +#include + +#ifdef _GNU_SOURCE +#define __used_ids used_ids +#define __swap_attempts swap_attempts +#define __swap_successes swap_successes +#endif + +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +typedef unsigned long shmatt_t; + +void* shmat(int, const void*, int); +int shmctl(int, int, struct shmid_ds*); +int shmdt(const void*); +int shmget(key_t, size_t, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/signal.h b/third_party/ulib/musl/include/sys/signal.h new file mode 100644 index 000000000..45bdcc648 --- /dev/null +++ b/third_party/ulib/musl/include/sys/signal.h @@ -0,0 +1,2 @@ +#warning redirecting incorrect #include to +#include diff --git a/third_party/ulib/musl/include/sys/signalfd.h b/third_party/ulib/musl/include/sys/signalfd.h new file mode 100644 index 000000000..6fdbf1a1d --- /dev/null +++ b/third_party/ulib/musl/include/sys/signalfd.h @@ -0,0 +1,45 @@ +#ifndef _SYS_SIGNALFD_H +#define _SYS_SIGNALFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __NEED_sigset_t + +#include + +#define SFD_CLOEXEC O_CLOEXEC +#define SFD_NONBLOCK O_NONBLOCK + +int signalfd(int, const sigset_t*, int); + +struct signalfd_siginfo { + uint32_t ssi_signo; + int32_t ssi_errno; + int32_t ssi_code; + uint32_t ssi_pid; + uint32_t ssi_uid; + int32_t ssi_fd; + uint32_t ssi_tid; + uint32_t ssi_band; + uint32_t ssi_overrun; + uint32_t ssi_trapno; + int32_t ssi_status; + int32_t ssi_int; + uint64_t ssi_ptr; + uint64_t ssi_utime; + uint64_t ssi_stime; + uint64_t ssi_addr; + uint16_t ssi_addr_lsb; + uint8_t pad[128 - 12 * 4 - 4 * 8 - 2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/socket.h b/third_party/ulib/musl/include/sys/socket.h new file mode 100644 index 000000000..662e40281 --- /dev/null +++ b/third_party/ulib/musl/include/sys/socket.h @@ -0,0 +1,325 @@ +#ifndef _SYS_SOCKET_H +#define _SYS_SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_socklen_t +#define __NEED_sa_family_t +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_uid_t +#define __NEED_pid_t +#define __NEED_gid_t +#define __NEED_struct_iovec + +#include + +#include + +#ifdef _GNU_SOURCE +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct timespec; + +int sendmmsg(int, struct mmsghdr*, unsigned int, unsigned int); +int recvmmsg(int, struct mmsghdr*, unsigned int, unsigned int, struct timespec*); +#endif + +struct linger { + int l_onoff; + int l_linger; +}; + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#ifndef SOCK_STREAM +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#endif + +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 +#define SOCK_DCCP 6 +#define SOCK_PACKET 10 + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 02000000 +#define SOCK_NONBLOCK 04000 +#endif + +#define PF_UNSPEC 0 +#define PF_LOCAL 1 +#define PF_UNIX PF_LOCAL +#define PF_FILE PF_LOCAL +#define PF_INET 2 +#define PF_AX25 3 +#define PF_IPX 4 +#define PF_APPLETALK 5 +#define PF_NETROM 6 +#define PF_BRIDGE 7 +#define PF_ATMPVC 8 +#define PF_X25 9 +#define PF_INET6 10 +#define PF_ROSE 11 +#define PF_DECnet 12 +#define PF_NETBEUI 13 +#define PF_SECURITY 14 +#define PF_KEY 15 +#define PF_NETLINK 16 +#define PF_ROUTE PF_NETLINK +#define PF_PACKET 17 +#define PF_ASH 18 +#define PF_ECONET 19 +#define PF_ATMSVC 20 +#define PF_RDS 21 +#define PF_SNA 22 +#define PF_IRDA 23 +#define PF_PPPOX 24 +#define PF_WANPIPE 25 +#define PF_LLC 26 +#define PF_IB 27 +#define PF_MPLS 28 +#define PF_CAN 29 +#define PF_TIPC 30 +#define PF_BLUETOOTH 31 +#define PF_IUCV 32 +#define PF_RXRPC 33 +#define PF_ISDN 34 +#define PF_PHONET 35 +#define PF_IEEE802154 36 +#define PF_CAIF 37 +#define PF_ALG 38 +#define PF_NFC 39 +#define PF_VSOCK 40 +#define PF_MAX 41 + +#define AF_UNSPEC PF_UNSPEC +#define AF_LOCAL PF_LOCAL +#define AF_UNIX AF_LOCAL +#define AF_FILE AF_LOCAL +#define AF_INET PF_INET +#define AF_AX25 PF_AX25 +#define AF_IPX PF_IPX +#define AF_APPLETALK PF_APPLETALK +#define AF_NETROM PF_NETROM +#define AF_BRIDGE PF_BRIDGE +#define AF_ATMPVC PF_ATMPVC +#define AF_X25 PF_X25 +#define AF_INET6 PF_INET6 +#define AF_ROSE PF_ROSE +#define AF_DECnet PF_DECnet +#define AF_NETBEUI PF_NETBEUI +#define AF_SECURITY PF_SECURITY +#define AF_KEY PF_KEY +#define AF_NETLINK PF_NETLINK +#define AF_ROUTE PF_ROUTE +#define AF_PACKET PF_PACKET +#define AF_ASH PF_ASH +#define AF_ECONET PF_ECONET +#define AF_ATMSVC PF_ATMSVC +#define AF_RDS PF_RDS +#define AF_SNA PF_SNA +#define AF_IRDA PF_IRDA +#define AF_PPPOX PF_PPPOX +#define AF_WANPIPE PF_WANPIPE +#define AF_LLC PF_LLC +#define AF_IB PF_IB +#define AF_MPLS PF_MPLS +#define AF_CAN PF_CAN +#define AF_TIPC PF_TIPC +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_IUCV PF_IUCV +#define AF_RXRPC PF_RXRPC +#define AF_ISDN PF_ISDN +#define AF_PHONET PF_PHONET +#define AF_IEEE802154 PF_IEEE802154 +#define AF_CAIF PF_CAIF +#define AF_ALG PF_ALG +#define AF_NFC PF_NFC +#define AF_VSOCK PF_VSOCK +#define AF_MAX PF_MAX + +#ifndef SO_DEBUG +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +#define SO_REUSEPORT 15 +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 +#define SO_ACCEPTCONN 30 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 +#endif + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 +#define SO_GET_FILTER SO_ATTACH_FILTER + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_PEERSEC 31 +#define SO_PASSSEC 34 +#define SO_TIMESTAMPNS 35 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SO_MARK 36 +#define SO_TIMESTAMPING 37 +#define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 +#define SO_NOFCS 43 +#define SO_LOCK_FILTER 44 +#define SO_SELECT_ERR_QUEUE 45 +#define SO_BUSY_POLL 46 +#define SO_MAX_PACING_RATE 47 +#define SO_BPF_EXTENSIONS 48 +#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#define SO_ATTACH_REUSEPORT_CBPF 51 +#define SO_ATTACH_REUSEPORT_EBPF 52 + +#ifndef SOL_SOCKET +#define SOL_SOCKET 1 +#endif + +#define SOL_IP 0 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 + +#define SOL_RAW 255 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 +#define SOL_AAL 265 +#define SOL_IRDA 266 + +#define SOMAXCONN 128 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC 0x0008 +#define MSG_PROXY 0x0010 +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 +#define MSG_EOR 0x0080 +#define MSG_WAITALL 0x0100 +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 +#define MSG_WAITFORONE 0x10000 +#define MSG_FASTOPEN 0x20000000 +#define MSG_CMSG_CLOEXEC 0x40000000 + +#define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) +#define __CMSG_NEXT(cmsg) ((unsigned char*)(cmsg) + __CMSG_LEN(cmsg)) +#define __MHDR_END(mhdr) ((unsigned char*)(mhdr)->msg_control + (mhdr)->msg_controllen) + +#define CMSG_DATA(cmsg) ((unsigned char*)(((struct cmsghdr*)(cmsg)) + 1)) +#define CMSG_NXTHDR(mhdr, cmsg) \ + ((cmsg)->cmsg_len < sizeof(struct cmsghdr) \ + ? (struct cmsghdr*)0 \ + : (__CMSG_NEXT(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) \ + ? (struct cmsghdr*)0 \ + : ((struct cmsghdr*)__CMSG_NEXT(cmsg)))) +#define CMSG_FIRSTHDR(mhdr) \ + ((size_t)(mhdr)->msg_controllen >= sizeof(struct cmsghdr) \ + ? (struct cmsghdr*)(mhdr)->msg_control \ + : (struct cmsghdr*)0) + +#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & (size_t) ~(sizeof(size_t) - 1)) +#define CMSG_SPACE(len) (CMSG_ALIGN(len) + CMSG_ALIGN(sizeof(struct cmsghdr))) +#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) + +#define SCM_RIGHTS 0x01 +#define SCM_CREDENTIALS 0x02 + +struct sockaddr { + sa_family_t sa_family; + char sa_data[14]; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + unsigned long __ss_align; + char __ss_padding[128 - 2 * sizeof(unsigned long)]; +}; + +int socket(int, int, int); +int socketpair(int, int, int, int[2]); + +int shutdown(int, int); + +int bind(int, const struct sockaddr*, socklen_t); +int connect(int, const struct sockaddr*, socklen_t); +int listen(int, int); +int accept(int, struct sockaddr* __restrict, socklen_t* __restrict); +int accept4(int, struct sockaddr* __restrict, socklen_t* __restrict, int); + +int getsockname(int, struct sockaddr* __restrict, socklen_t* __restrict); +int getpeername(int, struct sockaddr* __restrict, socklen_t* __restrict); + +ssize_t send(int, const void*, size_t, int); +ssize_t recv(int, void*, size_t, int); +ssize_t sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t); +ssize_t recvfrom(int, void* __restrict, size_t, int, struct sockaddr* __restrict, + socklen_t* __restrict); +ssize_t sendmsg(int, const struct msghdr*, int); +ssize_t recvmsg(int, struct msghdr*, int); + +int getsockopt(int, int, int, void* __restrict, socklen_t* __restrict); +int setsockopt(int, int, int, const void*, socklen_t); + +int sockatmark(int); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/soundcard.h b/third_party/ulib/musl/include/sys/soundcard.h new file mode 100644 index 000000000..fade986fe --- /dev/null +++ b/third_party/ulib/musl/include/sys/soundcard.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sys/stat.h b/third_party/ulib/musl/include/sys/stat.h new file mode 100644 index 000000000..071a7d6f2 --- /dev/null +++ b/third_party/ulib/musl/include/sys/stat.h @@ -0,0 +1,113 @@ +#ifndef _SYS_STAT_H +#define _SYS_STAT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_dev_t +#define __NEED_ino_t +#define __NEED_mode_t +#define __NEED_nlink_t +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_off_t +#define __NEED_time_t +#define __NEED_blksize_t +#define __NEED_blkcnt_t +#define __NEED_struct_timespec + +#include + +#include + +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec + +#define S_IFMT 0170000 + +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFBLK 0060000 +#define S_IFREG 0100000 +#define S_IFIFO 0010000 +#define S_IFLNK 0120000 +#define S_IFSOCK 0140000 + +#define S_TYPEISMQ(buf) 0 +#define S_TYPEISSEM(buf) 0 +#define S_TYPEISSHM(buf) 0 +#define S_TYPEISTMO(buf) 0 + +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR) +#define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK) +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO) +#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK) + +#ifndef S_IRUSR +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXU 0700 +#define S_IRGRP 0040 +#define S_IWGRP 0020 +#define S_IXGRP 0010 +#define S_IRWXG 0070 +#define S_IROTH 0004 +#define S_IWOTH 0002 +#define S_IXOTH 0001 +#define S_IRWXO 0007 +#endif + +#define UTIME_NOW 0x3fffffff +#define UTIME_OMIT 0x3ffffffe + +int stat(const char* __restrict, struct stat* __restrict); +int fstat(int, struct stat*); +int lstat(const char* __restrict, struct stat* __restrict); +int fstatat(int, const char* __restrict, struct stat* __restrict, int); +int chmod(const char*, mode_t); +int fchmod(int, mode_t); +int fchmodat(int, const char*, mode_t, int); +mode_t umask(mode_t); +int mkdir(const char*, mode_t); +int mknod(const char*, mode_t, dev_t); +int mkfifo(const char*, mode_t); +int mkdirat(int, const char*, mode_t); +int mknodat(int, const char*, mode_t, dev_t); +int mkfifoat(int, const char*, mode_t); + +int futimens(int, const struct timespec[2]); +int utimensat(int, const char*, const struct timespec[2], int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int lchmod(const char*, mode_t); +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define stat64 stat +#define fstat64 fstat +#define lstat64 lstat +#define fstatat64 fstatat +#define blkcnt64_t blkcnt_t +#define fsblkcnt64_t fsblkcnt_t +#define fsfilcnt64_t fsfilcnt_t +#define ino64_t ino_t +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/statfs.h b/third_party/ulib/musl/include/sys/statfs.h new file mode 100644 index 000000000..dffeb26a3 --- /dev/null +++ b/third_party/ulib/musl/include/sys/statfs.h @@ -0,0 +1,30 @@ +#ifndef _SYS_STATFS_H +#define _SYS_STATFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +typedef struct __fsid_t { int __val[2]; } fsid_t; + +#include + +int statfs(const char*, struct statfs*); +int fstatfs(int, struct statfs*); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define statfs64 statfs +#define fstatfs64 fstatfs +#define fsblkcnt64_t fsblkcnt_t +#define fsfilcnt64_t fsfilcnt_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/statvfs.h b/third_party/ulib/musl/include/sys/statvfs.h new file mode 100644 index 000000000..b90e5b578 --- /dev/null +++ b/third_party/ulib/musl/include/sys/statvfs.h @@ -0,0 +1,57 @@ +#ifndef _SYS_STATVFS_H +#define _SYS_STATVFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_fsblkcnt_t +#define __NEED_fsfilcnt_t +#include + +#include + +struct statvfs { + unsigned long f_bsize, f_frsize; + fsblkcnt_t f_blocks, f_bfree, f_bavail; + fsfilcnt_t f_files, f_ffree, f_favail; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned long f_fsid; + unsigned : 8 * (2 * sizeof(int) - sizeof(long)); +#else + unsigned : 8 * (2 * sizeof(int) - sizeof(long)); + unsigned long f_fsid; +#endif + unsigned long f_flag, f_namemax; + int __reserved[6]; +}; + +int statvfs(const char* __restrict, struct statvfs* __restrict); +int fstatvfs(int, struct statvfs*); + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_NODEV 4 +#define ST_NOEXEC 8 +#define ST_SYNCHRONOUS 16 +#define ST_MANDLOCK 64 +#define ST_WRITE 128 +#define ST_APPEND 256 +#define ST_IMMUTABLE 512 +#define ST_NOATIME 1024 +#define ST_NODIRATIME 2048 + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define statvfs64 statvfs +#define fstatvfs64 fstatvfs +#define fsblkcnt64_t fsblkcnt_t +#define fsfilcnt64_t fsfilcnt_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/stropts.h b/third_party/ulib/musl/include/sys/stropts.h new file mode 100644 index 000000000..5b5bc02f4 --- /dev/null +++ b/third_party/ulib/musl/include/sys/stropts.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sys/swap.h b/third_party/ulib/musl/include/sys/swap.h new file mode 100644 index 000000000..7529227b5 --- /dev/null +++ b/third_party/ulib/musl/include/sys/swap.h @@ -0,0 +1,20 @@ +#ifndef _SYS_SWAP_H +#define _SYS_SWAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SWAP_FLAG_PREFER 0x8000 +#define SWAP_FLAG_PRIO_MASK 0x7fff +#define SWAP_FLAG_PRIO_SHIFT 0 +#define SWAP_FLAG_DISCARD 0x10000 + +int swapon(const char*, int); +int swapoff(const char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/syscall.h b/third_party/ulib/musl/include/sys/syscall.h new file mode 100644 index 000000000..24987ddf2 --- /dev/null +++ b/third_party/ulib/musl/include/sys/syscall.h @@ -0,0 +1,6 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +#include + +#endif diff --git a/third_party/ulib/musl/include/sys/sysinfo.h b/third_party/ulib/musl/include/sys/sysinfo.h new file mode 100644 index 000000000..325b7339b --- /dev/null +++ b/third_party/ulib/musl/include/sys/sysinfo.h @@ -0,0 +1,36 @@ +#ifndef _SYS_SYSINFO_H +#define _SYS_SYSINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SI_LOAD_SHIFT 16 + +struct sysinfo { + unsigned long uptime; + unsigned long loads[3]; + unsigned long totalram; + unsigned long freeram; + unsigned long sharedram; + unsigned long bufferram; + unsigned long totalswap; + unsigned long freeswap; + unsigned short procs, pad; + unsigned long totalhigh; + unsigned long freehigh; + unsigned mem_unit; + char __reserved[256]; +}; + +int sysinfo(struct sysinfo*); +int get_nprocs_conf(void); +int get_nprocs(void); +long get_phys_pages(void); +long get_avphys_pages(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/syslog.h b/third_party/ulib/musl/include/sys/syslog.h new file mode 100644 index 000000000..7761eceeb --- /dev/null +++ b/third_party/ulib/musl/include/sys/syslog.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sys/sysmacros.h b/third_party/ulib/musl/include/sys/sysmacros.h new file mode 100644 index 000000000..1c808d627 --- /dev/null +++ b/third_party/ulib/musl/include/sys/sysmacros.h @@ -0,0 +1,11 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#define major(x) ((unsigned)((((x) >> 31 >> 1) & 0xfffff000) | (((x) >> 8) & 0x00000fff))) +#define minor(x) ((unsigned)((((x) >> 12) & 0xffffff00) | ((x)&0x000000ff))) + +#define makedev(x, y) \ + ((((x)&0xfffff000ULL) << 32) | (((x)&0x00000fffULL) << 8) | (((y)&0xffffff00ULL) << 12) | \ + (((y)&0x000000ffULL))) + +#endif diff --git a/third_party/ulib/musl/include/sys/termios.h b/third_party/ulib/musl/include/sys/termios.h new file mode 100644 index 000000000..f5f751f04 --- /dev/null +++ b/third_party/ulib/musl/include/sys/termios.h @@ -0,0 +1,2 @@ +#warning redirecting incorrect #include to +#include diff --git a/third_party/ulib/musl/include/sys/time.h b/third_party/ulib/musl/include/sys/time.h new file mode 100644 index 000000000..263bd76f5 --- /dev/null +++ b/third_party/ulib/musl/include/sys/time.h @@ -0,0 +1,64 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +int gettimeofday(struct timeval* __restrict, void* __restrict); + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; + +int getitimer(int, struct itimerval*); +int setitimer(int, const struct itimerval* __restrict, struct itimerval* __restrict); +int utimes(const char*, const struct timeval[2]); + +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; +int futimes(int, const struct timeval[2]); +int futimesat(int, const char*, const struct timeval[2]); +int lutimes(const char*, const struct timeval[2]); +int settimeofday(const struct timeval*, const struct timezone*); +int adjtime(const struct timeval*, struct timeval*); +#define timerisset(t) ((t)->tv_sec || (t)->tv_usec) +#define timerclear(t) ((t)->tv_sec = (t)->tv_usec = 0) +#define timercmp(s, t, op) \ + ((s)->tv_sec == (t)->tv_sec ? (s)->tv_usec op(t)->tv_usec : (s)->tv_sec op(t)->tv_sec) +#define timeradd(s, t, a) \ + (void)((a)->tv_sec = (s)->tv_sec + (t)->tv_sec, \ + ((a)->tv_usec = (s)->tv_usec + (t)->tv_usec) >= 1000000 && \ + ((a)->tv_usec -= 1000000, (a)->tv_sec++)) +#define timersub(s, t, a) \ + (void)((a)->tv_sec = (s)->tv_sec - (t)->tv_sec, \ + ((a)->tv_usec = (s)->tv_usec - (t)->tv_usec) < 0 && \ + ((a)->tv_usec += 1000000, (a)->tv_sec--)) +#endif + +#if defined(_GNU_SOURCE) +#define TIMEVAL_TO_TIMESPEC(tv, ts) \ + ((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000, (void)0) +#define TIMESPEC_TO_TIMEVAL(tv, ts) \ + ((tv)->tv_sec = (ts)->tv_sec, (tv)->tv_usec = (ts)->tv_nsec / 1000, (void)0) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/timeb.h b/third_party/ulib/musl/include/sys/timeb.h new file mode 100644 index 000000000..55b329f52 --- /dev/null +++ b/third_party/ulib/musl/include/sys/timeb.h @@ -0,0 +1,22 @@ +#ifndef _SYS_TIMEB_H +#define _SYS_TIMEB_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_time_t + +#include + +struct timeb { + time_t time; + unsigned short millitm; + short timezone, dstflag; +}; + +int ftime(struct timeb*); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/timerfd.h b/third_party/ulib/musl/include/sys/timerfd.h new file mode 100644 index 000000000..34506620c --- /dev/null +++ b/third_party/ulib/musl/include/sys/timerfd.h @@ -0,0 +1,26 @@ +#ifndef _SYS_TIMERFD_H +#define _SYS_TIMERFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define TFD_NONBLOCK O_NONBLOCK +#define TFD_CLOEXEC O_CLOEXEC + +#define TFD_TIMER_ABSTIME 1 + +struct itimerspec; + +int timerfd_create(int, int); +int timerfd_settime(int, int, const struct itimerspec*, struct itimerspec*); +int timerfd_gettime(int, struct itimerspec*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/times.h b/third_party/ulib/musl/include/sys/times.h new file mode 100644 index 000000000..b2b8a47bc --- /dev/null +++ b/third_party/ulib/musl/include/sys/times.h @@ -0,0 +1,24 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_clock_t +#include + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +clock_t times(struct tms*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/timex.h b/third_party/ulib/musl/include/sys/timex.h new file mode 100644 index 000000000..4b7bdf85c --- /dev/null +++ b/third_party/ulib/musl/include/sys/timex.h @@ -0,0 +1,99 @@ +#ifndef _SYS_TIMEX_H +#define _SYS_TIMEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_clockid_t + +#include + +#include + +struct ntptimeval { + struct timeval time; + long maxerror, esterror; +}; + +struct timex { + unsigned modes; + long offset, freq, maxerror, esterror; + int status; + long constant, precision, tolerance; + struct timeval time; + long tick, ppsfreq, jitter; + int shift; + long stabil, jitcnt, calcnt, errcnt, stbcnt; + int tai; + int __padding[11]; +}; + +#define ADJ_OFFSET 0x0001 +#define ADJ_FREQUENCY 0x0002 +#define ADJ_MAXERROR 0x0004 +#define ADJ_ESTERROR 0x0008 +#define ADJ_STATUS 0x0010 +#define ADJ_TIMECONST 0x0020 +#define ADJ_TAI 0x0080 +#define ADJ_SETOFFSET 0x0100 +#define ADJ_MICRO 0x1000 +#define ADJ_NANO 0x2000 +#define ADJ_TICK 0x4000 +#define ADJ_OFFSET_SINGLESHOT 0x8001 +#define ADJ_OFFSET_SS_READ 0xa001 + +#define MOD_OFFSET ADJ_OFFSET +#define MOD_FREQUENCY ADJ_FREQUENCY +#define MOD_MAXERROR ADJ_MAXERROR +#define MOD_ESTERROR ADJ_ESTERROR +#define MOD_STATUS ADJ_STATUS +#define MOD_TIMECONST ADJ_TIMECONST +#define MOD_CLKB ADJ_TICK +#define MOD_CLKA ADJ_OFFSET_SINGLESHOT +#define MOD_TAI ADJ_TAI +#define MOD_MICRO ADJ_MICRO +#define MOD_NANO ADJ_NANO + +#define STA_PLL 0x0001 +#define STA_PPSFREQ 0x0002 +#define STA_PPSTIME 0x0004 +#define STA_FLL 0x0008 + +#define STA_INS 0x0010 +#define STA_DEL 0x0020 +#define STA_UNSYNC 0x0040 +#define STA_FREQHOLD 0x0080 + +#define STA_PPSSIGNAL 0x0100 +#define STA_PPSJITTER 0x0200 +#define STA_PPSWANDER 0x0400 +#define STA_PPSERROR 0x0800 + +#define STA_CLOCKERR 0x1000 +#define STA_NANO 0x2000 +#define STA_MODE 0x4000 +#define STA_CLK 0x8000 + +#define STA_RONLY \ + (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR | STA_CLOCKERR | STA_NANO | \ + STA_MODE | STA_CLK) + +#define TIME_OK 0 +#define TIME_INS 1 +#define TIME_DEL 2 +#define TIME_OOP 3 +#define TIME_WAIT 4 +#define TIME_ERROR 5 +#define TIME_BAD TIME_ERROR + +#define MAXTC 6 + +int adjtimex(struct timex*); +int clock_adjtime(clockid_t, struct timex*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/ttydefaults.h b/third_party/ulib/musl/include/sys/ttydefaults.h new file mode 100644 index 000000000..6b86e1dbe --- /dev/null +++ b/third_party/ulib/musl/include/sys/ttydefaults.h @@ -0,0 +1,39 @@ +#ifndef _SYS_TTYDEFAULTS_H +#define _SYS_TTYDEFAULTS_H + +#define TTYDEF_IFLAG (BRKINT | ISTRIP | ICRNL | IMAXBEL | IXON | IXANY) +#define TTYDEF_OFLAG (OPOST | ONLCR | XTABS) +#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE | ECHOKE | ECHOCTL) +#define TTYDEF_CFLAG (CREAD | CS7 | PARENB | HUPCL) +#define TTYDEF_SPEED (B9600) +#define CTRL(x) (x & 037) +#define CEOF CTRL('d') + +#ifdef _POSIX_VDISABLE +#define CEOL _POSIX_VDISABLE +#define CSTATUS _POSIX_VDISABLE +#else +#define CEOL '\0' +#define CSTATUS '\0' +#endif + +#define CERASE 0177 +#define CINTR CTRL('c') +#define CKILL CTRL('u') +#define CMIN 1 +#define CQUIT 034 +#define CSUSP CTRL('z') +#define CTIME 0 +#define CDSUSP CTRL('y') +#define CSTART CTRL('q') +#define CSTOP CTRL('s') +#define CLNEXT CTRL('v') +#define CDISCARD CTRL('o') +#define CWERASE CTRL('w') +#define CREPRINT CTRL('r') +#define CEOT CEOF +#define CBRK CEOL +#define CRPRNT CREPRINT +#define CFLUSH CDISCARD + +#endif diff --git a/third_party/ulib/musl/include/sys/types.h b/third_party/ulib/musl/include/sys/types.h new file mode 100644 index 000000000..cf20b0c60 --- /dev/null +++ b/third_party/ulib/musl/include/sys/types.h @@ -0,0 +1,86 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_ino_t +#define __NEED_dev_t +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_mode_t +#define __NEED_nlink_t +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_time_t +#define __NEED_timer_t +#define __NEED_clockid_t + +#define __NEED_blkcnt_t +#define __NEED_fsblkcnt_t +#define __NEED_fsfilcnt_t + +#define __NEED_id_t +#define __NEED_key_t +#define __NEED_clock_t +#define __NEED_suseconds_t +#define __NEED_blksize_t + +#define __NEED_pthread_t +#define __NEED_pthread_attr_t +#define __NEED_pthread_mutexattr_t +#define __NEED_pthread_condattr_t +#define __NEED_pthread_rwlockattr_t +#define __NEED_pthread_barrierattr_t +#define __NEED_pthread_mutex_t +#define __NEED_pthread_cond_t +#define __NEED_pthread_rwlock_t +#define __NEED_pthread_barrier_t +#define __NEED_pthread_spinlock_t +#define __NEED_pthread_key_t +#define __NEED_pthread_once_t +#define __NEED_useconds_t + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_int8_t +#define __NEED_int16_t +#define __NEED_int32_t +#define __NEED_int64_t +#define __NEED_u_int64_t +#define __NEED_register_t +#endif + +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +typedef unsigned char u_int8_t; +typedef unsigned short u_int16_t; +typedef unsigned u_int32_t; +typedef char* caddr_t; +typedef unsigned char u_char; +typedef unsigned short u_short, ushort; +typedef unsigned u_int, uint; +typedef unsigned long u_long, ulong; +typedef long long quad_t; +typedef unsigned long long u_quad_t; +#include +#include +#include +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define blkcnt64_t blkcnt_t +#define fsblkcnt64_t fsblkcnt_t +#define fsfilcnt64_t fsfilcnt_t +#define ino64_t ino_t +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/ucontext.h b/third_party/ulib/musl/include/sys/ucontext.h new file mode 100644 index 000000000..5fdbd63db --- /dev/null +++ b/third_party/ulib/musl/include/sys/ucontext.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sys/uio.h b/third_party/ulib/musl/include/sys/uio.h new file mode 100644 index 000000000..018e83c36 --- /dev/null +++ b/third_party/ulib/musl/include/sys/uio.h @@ -0,0 +1,50 @@ +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_struct_iovec + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_off_t +#endif + +#ifdef _GNU_SOURCE +#define __NEED_pid_t +#endif + +#include + +#define UIO_MAXIOV 1024 + +ssize_t readv(int, const struct iovec*, int); +ssize_t writev(int, const struct iovec*, int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +ssize_t preadv(int, const struct iovec*, int, off_t); +ssize_t pwritev(int, const struct iovec*, int, off_t); +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define preadv64 preadv +#define pwritev64 pwritev +#define off64_t off_t +#endif +#endif + +#ifdef _GNU_SOURCE +ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, + unsigned long, unsigned long); +ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, + unsigned long, unsigned long); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/un.h b/third_party/ulib/musl/include/sys/un.h new file mode 100644 index 000000000..4c45433ac --- /dev/null +++ b/third_party/ulib/musl/include/sys/un.h @@ -0,0 +1,31 @@ +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_sa_family_t +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_size_t +#endif + +#include + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +size_t strlen(const char*); +#define SUN_LEN(s) (2 + strlen((s)->sun_path)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/user.h b/third_party/ulib/musl/include/sys/user.h new file mode 100644 index 000000000..96a034009 --- /dev/null +++ b/third_party/ulib/musl/include/sys/user.h @@ -0,0 +1,16 @@ +#ifndef _SYS_USER_H +#define _SYS_USER_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/sys/utsname.h b/third_party/ulib/musl/include/sys/utsname.h new file mode 100644 index 000000000..8126ca197 --- /dev/null +++ b/third_party/ulib/musl/include/sys/utsname.h @@ -0,0 +1,29 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +#ifdef _GNU_SOURCE + char domainname[65]; +#else + char __domainname[65]; +#endif +}; + +int uname(struct utsname*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/sys/vfs.h b/third_party/ulib/musl/include/sys/vfs.h new file mode 100644 index 000000000..a899db276 --- /dev/null +++ b/third_party/ulib/musl/include/sys/vfs.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sys/vt.h b/third_party/ulib/musl/include/sys/vt.h new file mode 100644 index 000000000..834abfbc8 --- /dev/null +++ b/third_party/ulib/musl/include/sys/vt.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sys/wait.h b/third_party/ulib/musl/include/sys/wait.h new file mode 100644 index 000000000..c912f1715 --- /dev/null +++ b/third_party/ulib/musl/include/sys/wait.h @@ -0,0 +1,54 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_pid_t +#define __NEED_id_t +#include + +typedef enum { P_ALL = 0, P_PID = 1, P_PGID = 2 } idtype_t; + +pid_t wait(int*); +pid_t waitpid(pid_t, int*, int); + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#include +int waitid(idtype_t, id_t, siginfo_t*, int); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#include +pid_t wait3(int*, int, struct rusage*); +pid_t wait4(pid_t, int*, int, struct rusage*); +#endif + +#define WNOHANG 1 +#define WUNTRACED 2 + +#define WSTOPPED 2 +#define WEXITED 4 +#define WCONTINUED 8 +#define WNOWAIT 0x1000000 + +#define __WNOTHREAD 0x20000000 +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#define WEXITSTATUS(s) (((s)&0xff00) >> 8) +#define WTERMSIG(s) ((s)&0x7f) +#define WSTOPSIG(s) WEXITSTATUS(s) +#define WCOREDUMP(s) ((s)&0x80) +#define WIFEXITED(s) (!WTERMSIG(s)) +#define WIFSTOPPED(s) ((short)((((s)&0xffff) * 0x10001) >> 8) > 0x7f00) +#define WIFSIGNALED(s) (((s)&0xffff) - 1U < 0xffu) +#define WIFCONTINUED(s) ((s) == 0xffff) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/syscall.h b/third_party/ulib/musl/include/syscall.h new file mode 100644 index 000000000..4c3057844 --- /dev/null +++ b/third_party/ulib/musl/include/syscall.h @@ -0,0 +1 @@ +#include diff --git a/third_party/ulib/musl/include/sysexits.h b/third_party/ulib/musl/include/sysexits.h new file mode 100644 index 000000000..17a9eec98 --- /dev/null +++ b/third_party/ulib/musl/include/sysexits.h @@ -0,0 +1,21 @@ +#ifndef _SYSEXITS_H +#define _SYSEXITS_H +#define EX_OK 0 +#define EX__BASE 64 +#define EX_USAGE 64 +#define EX_DATAERR 65 +#define EX_NOINPUT 66 +#define EX_NOUSER 67 +#define EX_NOHOST 68 +#define EX_UNAVAILABLE 69 +#define EX_SOFTWARE 70 +#define EX_OSERR 71 +#define EX_OSFILE 72 +#define EX_CANTCREAT 73 +#define EX_IOERR 74 +#define EX_TEMPFAIL 75 +#define EX_PROTOCOL 76 +#define EX_NOPERM 77 +#define EX_CONFIG 78 +#define EX__MAX 78 +#endif diff --git a/third_party/ulib/musl/include/syslog.h b/third_party/ulib/musl/include/syslog.h new file mode 100644 index 000000000..dd333e55c --- /dev/null +++ b/third_party/ulib/musl/include/syslog.h @@ -0,0 +1,121 @@ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#define LOG_PRIMASK 7 +#define LOG_PRI(p) ((p)&LOG_PRIMASK) +#define LOG_MAKEPRI(f, p) (((f) << 3) | (p)) + +#define LOG_MASK(p) (1 << (p)) +#define LOG_UPTO(p) ((1 << ((p) + 1)) - 1) + +#define LOG_KERN (0 << 3) +#define LOG_USER (1 << 3) +#define LOG_MAIL (2 << 3) +#define LOG_DAEMON (3 << 3) +#define LOG_AUTH (4 << 3) +#define LOG_SYSLOG (5 << 3) +#define LOG_LPR (6 << 3) +#define LOG_NEWS (7 << 3) +#define LOG_UUCP (8 << 3) +#define LOG_CRON (9 << 3) +#define LOG_AUTHPRIV (10 << 3) +#define LOG_FTP (11 << 3) + +#define LOG_LOCAL0 (16 << 3) +#define LOG_LOCAL1 (17 << 3) +#define LOG_LOCAL2 (18 << 3) +#define LOG_LOCAL3 (19 << 3) +#define LOG_LOCAL4 (20 << 3) +#define LOG_LOCAL5 (21 << 3) +#define LOG_LOCAL6 (22 << 3) +#define LOG_LOCAL7 (23 << 3) + +#define LOG_NFACILITIES 24 +#define LOG_FACMASK 0x3f8 +#define LOG_FAC(p) (((p)&LOG_FACMASK) >> 3) + +#define LOG_PID 0x01 +#define LOG_CONS 0x02 +#define LOG_ODELAY 0x04 +#define LOG_NDELAY 0x08 +#define LOG_NOWAIT 0x10 +#define LOG_PERROR 0x20 + +void closelog(void); +void openlog(const char*, int, int); +int setlogmask(int); +void syslog(int, const char*, ...); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define _PATH_LOG "/dev/log" +#define __NEED_va_list +#include +void vsyslog(int, const char*, va_list); +#if defined(SYSLOG_NAMES) +#define INTERNAL_NOPRI 0x10 +#define INTERNAL_MARK (LOG_NFACILITIES << 3) +typedef struct { + char* c_name; + int c_val; +} CODE; +#define prioritynames \ + ((CODE*)(const CODE[]){{"alert", LOG_ALERT}, \ + {"crit", LOG_CRIT}, \ + {"debug", LOG_DEBUG}, \ + {"emerg", LOG_EMERG}, \ + {"err", LOG_ERR}, \ + {"error", LOG_ERR}, \ + {"info", LOG_INFO}, \ + {"none", INTERNAL_NOPRI}, \ + {"notice", LOG_NOTICE}, \ + {"panic", LOG_EMERG}, \ + {"warn", LOG_WARNING}, \ + {"warning", LOG_WARNING}, \ + {0, -1}}) +#define facilitynames \ + ((CODE*)(const CODE[]){{"auth", LOG_AUTH}, \ + {"authpriv", LOG_AUTHPRIV}, \ + {"cron", LOG_CRON}, \ + {"daemon", LOG_DAEMON}, \ + {"ftp", LOG_FTP}, \ + {"kern", LOG_KERN}, \ + {"lpr", LOG_LPR}, \ + {"mail", LOG_MAIL}, \ + {"mark", INTERNAL_MARK}, \ + {"news", LOG_NEWS}, \ + {"security", LOG_AUTH}, \ + {"syslog", LOG_SYSLOG}, \ + {"user", LOG_USER}, \ + {"uucp", LOG_UUCP}, \ + {"local0", LOG_LOCAL0}, \ + {"local1", LOG_LOCAL1}, \ + {"local2", LOG_LOCAL2}, \ + {"local3", LOG_LOCAL3}, \ + {"local4", LOG_LOCAL4}, \ + {"local5", LOG_LOCAL5}, \ + {"local6", LOG_LOCAL6}, \ + {"local7", LOG_LOCAL7}, \ + {0, -1}}) +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/tar.h b/third_party/ulib/musl/include/tar.h new file mode 100644 index 000000000..70ea81b49 --- /dev/null +++ b/third_party/ulib/musl/include/tar.h @@ -0,0 +1,33 @@ +#ifndef _TAR_H +#define _TAR_H + +#define TSUID 04000 +#define TSGID 02000 +#define TSVTX 01000 +#define TUREAD 00400 +#define TUWRITE 00200 +#define TUEXEC 00100 +#define TGREAD 00040 +#define TGWRITE 00020 +#define TGEXEC 00010 +#define TOREAD 00004 +#define TOWRITE 00002 +#define TOEXEC 00001 + +#define REGTYPE '0' +#define AREGTYPE '\0' +#define LNKTYPE '1' +#define SYMTYPE '2' +#define CHRTYPE '3' +#define BLKTYPE '4' +#define DIRTYPE '5' +#define FIFOTYPE '6' +#define CONTTYPE '7' + +#define TMAGIC "ustar" +#define TMAGLEN 6 + +#define TVERSION "00" +#define TVERSLEN 2 + +#endif diff --git a/third_party/ulib/musl/include/termios.h b/third_party/ulib/musl/include/termios.h new file mode 100644 index 000000000..993101509 --- /dev/null +++ b/third_party/ulib/musl/include/termios.h @@ -0,0 +1,46 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_pid_t + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 + +#include + +speed_t cfgetospeed(const struct termios*); +speed_t cfgetispeed(const struct termios*); +int cfsetospeed(struct termios*, speed_t); +int cfsetispeed(struct termios*, speed_t); + +int tcgetattr(int, struct termios*); +int tcsetattr(int, int, const struct termios*); + +int tcsendbreak(int, int); +int tcdrain(int); +int tcflush(int, int); +int tcflow(int, int); + +pid_t tcgetsid(int); + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +void cfmakeraw(struct termios*); +int cfsetspeed(struct termios*, speed_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/tgmath.h b/third_party/ulib/musl/include/tgmath.h new file mode 100644 index 000000000..299272afb --- /dev/null +++ b/third_party/ulib/musl/include/tgmath.h @@ -0,0 +1,264 @@ +#ifndef _TGMATH_H +#define _TGMATH_H + +/* +the return types are only correct with gcc (__GNUC__) +otherwise they are long double or long double complex + +the long double version of a function is never chosen when +sizeof(double) == sizeof(long double) +(but the return type is set correctly with gcc) +*/ + +#include +#include + +#define __IS_FP(x) (sizeof((x) + 1ULL) == sizeof((x) + 1.0f)) +#define __IS_CX(x) (__IS_FP(x) && sizeof(x) == sizeof((x) + I)) +#define __IS_REAL(x) (__IS_FP(x) && 2 * sizeof(x) == sizeof((x) + I)) + +#define __FLT(x) (__IS_REAL(x) && sizeof(x) == sizeof(float)) +#define __LDBL(x) \ + (__IS_REAL(x) && sizeof(x) == sizeof(long double) && sizeof(long double) != sizeof(double)) + +#define __FLTCX(x) (__IS_CX(x) && sizeof(x) == sizeof(float complex)) +#define __DBLCX(x) (__IS_CX(x) && sizeof(x) == sizeof(double complex)) +#define __LDBLCX(x) \ + (__IS_CX(x) && sizeof(x) == sizeof(long double complex) && \ + sizeof(long double) != sizeof(double)) + +/* return type */ + +#ifdef __GNUC__ +/* +the result must be casted to the right type +(otherwise the result type is determined by the conversion +rules applied to all the function return types so it is long +double or long double complex except for integral functions) + +this cannot be done in c99, so the typeof gcc extension is +used and that the type of ?: depends on wether an operand is +a null pointer constant or not +(in c11 _Generic can be used) + +the c arguments below must be integer constant expressions +so they can be in null pointer constants +(__IS_FP above was carefully chosen this way) +*/ +/* if c then t else void */ +#define __type1(c, t) __typeof__(*(0 ? (t*)0 : (void*)!(c))) +/* if c then t1 else t2 */ +#define __type2(c, t1, t2) __typeof__(*(0 ? (__type1(c, t1)*)0 : (__type1(!(c), t2)*)0)) +/* cast to double when x is integral, otherwise use typeof(x) */ +#define __RETCAST(x) (__type2(__IS_FP(x), __typeof__(x), double)) +/* 2 args case, should work for complex types (cpow) */ +#define __RETCAST_2(x, y) \ + (__type2(__IS_FP(x) && __IS_FP(y), __typeof__((x) + (y)), __typeof__((x) + (y) + 1.0))) +/* 3 args case (fma only) */ +#define __RETCAST_3(x, y, z) \ + (__type2(__IS_FP(x) && __IS_FP(y) && __IS_FP(z), __typeof__((x) + (y) + (z)), \ + __typeof__((x) + (y) + (z) + 1.0))) +/* drop complex from the type of x */ +/* TODO: wrong when sizeof(long double)==sizeof(double) */ +#define __RETCAST_REAL(x) \ + (__type2(__IS_FP(x) && sizeof((x) + I) == sizeof(float complex), float, \ + __type2(sizeof((x) + 1.0 + I) == sizeof(double complex), double, long double))) +/* add complex to the type of x */ +#define __RETCAST_CX(x) (__typeof__(__RETCAST(x) 0 + I)) +#else +#define __RETCAST(x) +#define __RETCAST_2(x, y) +#define __RETCAST_3(x, y, z) +#define __RETCAST_REAL(x) +#define __RETCAST_CX(x) +#endif + +/* function selection */ + +#define __tg_real_nocast(fun, x) (__FLT(x) ? fun##f(x) : __LDBL(x) ? fun##l(x) : fun(x)) + +#define __tg_real(fun, x) (__RETCAST(x) __tg_real_nocast(fun, x)) + +#define __tg_real_2_1(fun, x, y) \ + (__RETCAST(x)(__FLT(x) ? fun##f(x, y) : __LDBL(x) ? fun##l(x, y) : fun(x, y))) + +#define __tg_real_2(fun, x, y) \ + (__RETCAST_2(x, y)(__FLT(x) && __FLT(y) ? fun##f(x, y) : __LDBL((x) + (y)) ? fun##l(x, y) \ + : fun(x, y))) + +#define __tg_complex(fun, x) \ + (__RETCAST_CX(x)(__FLTCX((x) + I) && __IS_FP(x) ? fun##f(x) : __LDBLCX((x) + I) ? fun##l(x) \ + : fun(x))) + +#define __tg_complex_retreal(fun, x) \ + (__RETCAST_REAL(x)(__FLTCX((x) + I) && __IS_FP(x) ? fun##f(x) : __LDBLCX((x) + I) ? fun##l(x) \ + : fun(x))) + +#define __tg_real_complex(fun, x) \ + (__RETCAST(x)(__FLTCX(x) \ + ? c##fun##f(x) \ + : __DBLCX(x) ? c##fun(x) : __LDBLCX(x) \ + ? c##fun##l(x) \ + : __FLT(x) ? fun##f(x) \ + : __LDBL(x) ? fun##l(x) : fun(x))) + +/* special cases */ + +#define __tg_real_remquo(x, y, z) \ + (__RETCAST_2(x, y)(__FLT(x) && __FLT(y) ? remquof(x, y, z) : __LDBL((x) + (y)) \ + ? remquol(x, y, z) \ + : remquo(x, y, z))) + +#define __tg_real_fma(x, y, z) \ + (__RETCAST_3(x, y, z)(__FLT(x) && __FLT(y) && __FLT(z) \ + ? fmaf(x, y, z) \ + : __LDBL((x) + (y) + (z)) ? fmal(x, y, z) : fma(x, y, z))) + +#define __tg_real_complex_pow(x, y) \ + (__RETCAST_2(x, y)(__FLTCX((x) + (y)) && __IS_FP(x) && __IS_FP(y) \ + ? cpowf(x, y) \ + : __FLTCX((x) + (y)) ? cpow(x, y) : __DBLCX((x) + (y)) \ + ? cpow(x, y) \ + : __LDBLCX((x) + (y)) \ + ? cpowl(x, y) \ + : __FLT(x) && __FLT(y) \ + ? powf(x, y) \ + : __LDBL((x) + (y)) \ + ? powl(x, y) \ + : pow(x, y))) + +#define __tg_real_complex_fabs(x) \ + (__RETCAST_REAL(x)(__FLTCX(x) \ + ? cabsf(x) \ + : __DBLCX(x) ? cabs(x) : __LDBLCX(x) ? cabsl(x) \ + : __FLT(x) ? fabsf(x) \ + : __LDBL(x) ? fabsl(x) \ + : fabs(x))) + +/* suppress any macros in math.h or complex.h */ + +#undef acos +#undef acosh +#undef asin +#undef asinh +#undef atan +#undef atan2 +#undef atanh +#undef carg +#undef cbrt +#undef ceil +#undef cimag +#undef conj +#undef copysign +#undef cos +#undef cosh +#undef cproj +#undef creal +#undef erf +#undef erfc +#undef exp +#undef exp2 +#undef expm1 +#undef fabs +#undef fdim +#undef floor +#undef fma +#undef fmax +#undef fmin +#undef fmod +#undef frexp +#undef hypot +#undef ilogb +#undef ldexp +#undef lgamma +#undef llrint +#undef llround +#undef log +#undef log10 +#undef log1p +#undef log2 +#undef logb +#undef lrint +#undef lround +#undef nearbyint +#undef nextafter +#undef nexttoward +#undef pow +#undef remainder +#undef remquo +#undef rint +#undef round +#undef scalbln +#undef scalbn +#undef sin +#undef sinh +#undef sqrt +#undef tan +#undef tanh +#undef tgamma +#undef trunc + +/* tg functions */ + +#define acos(x) __tg_real_complex(acos, (x)) +#define acosh(x) __tg_real_complex(acosh, (x)) +#define asin(x) __tg_real_complex(asin, (x)) +#define asinh(x) __tg_real_complex(asinh, (x)) +#define atan(x) __tg_real_complex(atan, (x)) +#define atan2(x, y) __tg_real_2(atan2, (x), (y)) +#define atanh(x) __tg_real_complex(atanh, (x)) +#define carg(x) __tg_complex_retreal(carg, (x)) +#define cbrt(x) __tg_real(cbrt, (x)) +#define ceil(x) __tg_real(ceil, (x)) +#define cimag(x) __tg_complex_retreal(cimag, (x)) +#define conj(x) __tg_complex(conj, (x)) +#define copysign(x, y) __tg_real_2(copysign, (x), (y)) +#define cos(x) __tg_real_complex(cos, (x)) +#define cosh(x) __tg_real_complex(cosh, (x)) +#define cproj(x) __tg_complex(cproj, (x)) +#define creal(x) __tg_complex_retreal(creal, (x)) +#define erf(x) __tg_real(erf, (x)) +#define erfc(x) __tg_real(erfc, (x)) +#define exp(x) __tg_real_complex(exp, (x)) +#define exp2(x) __tg_real(exp2, (x)) +#define expm1(x) __tg_real(expm1, (x)) +#define fabs(x) __tg_real_complex_fabs(x) +#define fdim(x, y) __tg_real_2(fdim, (x), (y)) +#define floor(x) __tg_real(floor, (x)) +#define fma(x, y, z) __tg_real_fma((x), (y), (z)) +#define fmax(x, y) __tg_real_2(fmax, (x), (y)) +#define fmin(x, y) __tg_real_2(fmin, (x), (y)) +#define fmod(x, y) __tg_real_2(fmod, (x), (y)) +#define frexp(x, y) __tg_real_2_1(frexp, (x), (y)) +#define hypot(x, y) __tg_real_2(hypot, (x), (y)) +#define ilogb(x) __tg_real_nocast(ilogb, (x)) +#define ldexp(x, y) __tg_real_2_1(ldexp, (x), (y)) +#define lgamma(x) __tg_real(lgamma, (x)) +#define llrint(x) __tg_real_nocast(llrint, (x)) +#define llround(x) __tg_real_nocast(llround, (x)) +#define log(x) __tg_real_complex(log, (x)) +#define log10(x) __tg_real(log10, (x)) +#define log1p(x) __tg_real(log1p, (x)) +#define log2(x) __tg_real(log2, (x)) +#define logb(x) __tg_real(logb, (x)) +#define lrint(x) __tg_real_nocast(lrint, (x)) +#define lround(x) __tg_real_nocast(lround, (x)) +#define nearbyint(x) __tg_real(nearbyint, (x)) +#define nextafter(x, y) __tg_real_2(nextafter, (x), (y)) +#define nexttoward(x, y) __tg_real_2(nexttoward, (x), (y)) +#define pow(x, y) __tg_real_complex_pow((x), (y)) +#define remainder(x, y) __tg_real_2(remainder, (x), (y)) +#define remquo(x, y, z) __tg_real_remquo((x), (y), (z)) +#define rint(x) __tg_real(rint, (x)) +#define round(x) __tg_real(round, (x)) +#define scalbln(x, y) __tg_real_2_1(scalbln, (x), (y)) +#define scalbn(x, y) __tg_real_2_1(scalbn, (x), (y)) +#define sin(x) __tg_real_complex(sin, (x)) +#define sinh(x) __tg_real_complex(sinh, (x)) +#define sqrt(x) __tg_real_complex(sqrt, (x)) +#define tan(x) __tg_real_complex(tan, (x)) +#define tanh(x) __tg_real_complex(tanh, (x)) +#define tgamma(x) __tg_real(tgamma, (x)) +#define trunc(x) __tg_real(trunc, (x)) + +#endif diff --git a/third_party/ulib/musl/include/threads.h b/third_party/ulib/musl/include/threads.h new file mode 100644 index 000000000..4f7792121 --- /dev/null +++ b/third_party/ulib/musl/include/threads.h @@ -0,0 +1,87 @@ +#ifndef _THREADS_H +#define _THREADS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +typedef unsigned long thrd_t; +#else +typedef struct __pthread* thrd_t; +#define thread_local _Thread_local +#endif + +typedef int once_flag; +typedef unsigned tss_t; +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +#define __NEED_cnd_t +#define __NEED_mtx_t + +#include + +#define TSS_DTOR_ITERATIONS 4 + +enum { + thrd_success = 0, + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_timedout = 4, +}; + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +#define ONCE_FLAG_INIT 0 + +int thrd_create(thrd_t*, thrd_start_t, void*); +_Noreturn void thrd_exit(int); + +int thrd_detach(thrd_t); +int thrd_join(thrd_t, int*); + +int thrd_sleep(const struct timespec*, struct timespec*); +void thrd_yield(void); + +thrd_t thrd_current(void); +int thrd_equal(thrd_t, thrd_t); +#ifndef __cplusplus +#define thrd_equal(A, B) ((A) == (B)) +#endif + +void call_once(once_flag*, void (*)(void)); + +int mtx_init(mtx_t*, int); +void mtx_destroy(mtx_t*); + +int mtx_lock(mtx_t*); +int mtx_timedlock(mtx_t* __restrict, const struct timespec* __restrict); +int mtx_trylock(mtx_t*); +int mtx_unlock(mtx_t*); + +int cnd_init(cnd_t*); +void cnd_destroy(cnd_t*); + +int cnd_broadcast(cnd_t*); +int cnd_signal(cnd_t*); + +int cnd_timedwait(cnd_t* __restrict, mtx_t* __restrict, const struct timespec* __restrict); +int cnd_wait(cnd_t*, mtx_t*); + +int tss_create(tss_t*, tss_dtor_t); +void tss_delete(tss_t key); + +int tss_set(tss_t, void*); +void* tss_get(tss_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/time.h b/third_party/ulib/musl/include/time.h new file mode 100644 index 000000000..283539acb --- /dev/null +++ b/third_party/ulib/musl/include/time.h @@ -0,0 +1,132 @@ +#ifndef _TIME_H +#define _TIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#define __NEED_time_t +#define __NEED_clock_t +#define __NEED_struct_timespec + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_clockid_t +#define __NEED_timer_t +#define __NEED_pid_t +#define __NEED_locale_t +#endif + +#include + +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#define __tm_gmtoff tm_gmtoff +#define __tm_zone tm_zone +#endif + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long __tm_gmtoff; + const char* __tm_zone; +}; + +clock_t clock(void); +time_t time(time_t*); +double difftime(time_t, time_t); +time_t mktime(struct tm*); +size_t strftime(char* __restrict, size_t, const char* __restrict, const struct tm* __restrict); +struct tm* gmtime(const time_t*); +struct tm* localtime(const time_t*); +char* asctime(const struct tm*); +char* ctime(const time_t*); +int timespec_get(struct timespec*, int); + +#define CLOCKS_PER_SEC 1000000L + +#define TIME_UTC 1 + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +size_t strftime_l(char* __restrict, size_t, const char* __restrict, const struct tm* __restrict, + locale_t); + +struct tm* gmtime_r(const time_t* __restrict, struct tm* __restrict); +struct tm* localtime_r(const time_t* __restrict, struct tm* __restrict); +char* asctime_r(const struct tm* __restrict, char* __restrict); +char* ctime_r(const time_t*, char*); + +void tzset(void); + +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 +#define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 +#define CLOCK_SGI_CYCLE 10 +#define CLOCK_TAI 11 + +#define TIMER_ABSTIME 1 + +int nanosleep(const struct timespec*, struct timespec*); +int clock_getres(clockid_t, struct timespec*); +int clock_gettime(clockid_t, struct timespec*); +int clock_settime(clockid_t, const struct timespec*); +int clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*); +int clock_getcpuclockid(pid_t, clockid_t*); + +struct sigevent; +int timer_create(clockid_t, struct sigevent* __restrict, timer_t* __restrict); +int timer_delete(timer_t); +int timer_settime(timer_t, int, const struct itimerspec* __restrict, struct itimerspec* __restrict); +int timer_gettime(timer_t, struct itimerspec*); +int timer_getoverrun(timer_t); + +#endif + +#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +char* strptime(const char* __restrict, const char* __restrict, struct tm* __restrict); +extern int daylight; +extern long timezone; +extern char* tzname[2]; +extern int getdate_err; +struct tm* getdate(const char*); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int stime(const time_t*); +time_t timegm(struct tm*); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/uchar.h b/third_party/ulib/musl/include/uchar.h new file mode 100644 index 000000000..ddff44cf3 --- /dev/null +++ b/third_party/ulib/musl/include/uchar.h @@ -0,0 +1,27 @@ +#ifndef _UCHAR_H +#define _UCHAR_H + +#ifdef __cplusplus +extern "C" { +#else +typedef unsigned short char16_t; +typedef unsigned char32_t; +#endif + +#define __NEED_mbstate_t +#define __NEED_size_t + +#include +#include + +size_t c16rtomb(char* __restrict, char16_t, mbstate_t* __restrict); +size_t mbrtoc16(char16_t* __restrict, const char* __restrict, size_t, mbstate_t* __restrict); + +size_t c32rtomb(char* __restrict, char32_t, mbstate_t* __restrict); +size_t mbrtoc32(char32_t* __restrict, const char* __restrict, size_t, mbstate_t* __restrict); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/ucontext.h b/third_party/ulib/musl/include/ucontext.h new file mode 100644 index 000000000..5164ef187 --- /dev/null +++ b/third_party/ulib/musl/include/ucontext.h @@ -0,0 +1,25 @@ +#ifndef _UCONTEXT_H +#define _UCONTEXT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define NGREG (sizeof(gregset_t) / sizeof(greg_t)) +#endif + +struct __ucontext; + +int getcontext(struct __ucontext*); +void makecontext(struct __ucontext*, void (*)(void), int, ...); +int setcontext(const struct __ucontext*); +int swapcontext(struct __ucontext*, const struct __ucontext*); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/third_party/ulib/musl/include/ulimit.h b/third_party/ulib/musl/include/ulimit.h new file mode 100644 index 000000000..e0201401e --- /dev/null +++ b/third_party/ulib/musl/include/ulimit.h @@ -0,0 +1,17 @@ +#ifndef _ULIMIT_H +#define _ULIMIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define UL_GETFSIZE 1 +#define UL_SETFSIZE 2 + +long ulimit(int, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/unistd.h b/third_party/ulib/musl/include/unistd.h new file mode 100644 index 000000000..548db5d03 --- /dev/null +++ b/third_party/ulib/musl/include/unistd.h @@ -0,0 +1,463 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_intptr_t +#define __NEED_useconds_t + +#include + +int pipe(int[2]); +int pipe2(int[2], int); +int close(int); +int posix_close(int, int); +int dup(int); +int dup2(int, int); +int dup3(int, int, int); +off_t lseek(int, off_t, int); +int fsync(int); +int fdatasync(int); + +ssize_t read(int, void*, size_t); +ssize_t write(int, const void*, size_t); +ssize_t pread(int, void*, size_t, off_t); +ssize_t pwrite(int, const void*, size_t, off_t); + +int chown(const char*, uid_t, gid_t); +int fchown(int, uid_t, gid_t); +int lchown(const char*, uid_t, gid_t); +int fchownat(int, const char*, uid_t, gid_t, int); + +int link(const char*, const char*); +int linkat(int, const char*, int, const char*, int); +int symlink(const char*, const char*); +int symlinkat(const char*, int, const char*); +ssize_t readlink(const char* __restrict, char* __restrict, size_t); +ssize_t readlinkat(int, const char* __restrict, char* __restrict, size_t); +int unlink(const char*); +int unlinkat(int, const char*, int); +int rmdir(const char*); +int truncate(const char*, off_t); +int ftruncate(int, off_t); + +#define F_OK 0 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 + +int access(const char*, int); +int faccessat(int, const char*, int, int); + +int chdir(const char*); +int fchdir(int); +char* getcwd(char*, size_t); + +unsigned alarm(unsigned); +unsigned sleep(unsigned); +int pause(void); + +pid_t fork(void); +int execve(const char*, char* const[], char* const[]); +int execv(const char*, char* const[]); +int execle(const char*, const char*, ...); +int execl(const char*, const char*, ...); +int execvp(const char*, char* const[]); +int execlp(const char*, const char*, ...); +int fexecve(int, char* const[], char* const[]); +_Noreturn void _exit(int); + +pid_t getpid(void); +pid_t getppid(void); +pid_t getpgrp(void); +pid_t getpgid(pid_t); +int setpgid(pid_t, pid_t); +pid_t setsid(void); +pid_t getsid(pid_t); +char* ttyname(int); +int ttyname_r(int, char*, size_t); +int isatty(int); +pid_t tcgetpgrp(int); +int tcsetpgrp(int, pid_t); + +uid_t getuid(void); +uid_t geteuid(void); +gid_t getgid(void); +gid_t getegid(void); +int getgroups(int, gid_t[]); +int setuid(uid_t); +int setreuid(uid_t, uid_t); +int seteuid(uid_t); +int setgid(gid_t); +int setregid(gid_t, gid_t); +int setegid(gid_t); + +char* getlogin(void); +int getlogin_r(char*, size_t); +int gethostname(char*, size_t); +char* ctermid(char*); + +int getopt(int, char* const[], const char*); +extern char* optarg; +extern int optind, opterr, optopt; + +long pathconf(const char*, int); +long fpathconf(int, int); +long sysconf(int); +size_t confstr(int, char*, size_t); + +#define F_ULOCK 0 +#define F_LOCK 1 +#define F_TLOCK 2 +#define F_TEST 3 + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int lockf(int, int, off_t); +long gethostid(void); +int nice(int); +void sync(void); +pid_t setpgrp(void); +char* crypt(const char*, const char*); +void encrypt(char*, int); +void swab(const void* __restrict, void* __restrict, ssize_t); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE + 0 < 700) +int usleep(unsigned); +unsigned ualarm(unsigned, unsigned); +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define L_SET 0 +#define L_INCR 1 +#define L_XTND 2 +int brk(void*); +void* sbrk(intptr_t); +pid_t vfork(void); +int vhangup(void); +int chroot(const char*); +int getpagesize(void); +int getdtablesize(void); +int sethostname(const char*, size_t); +int getdomainname(char*, size_t); +int setdomainname(const char*, size_t); +int setgroups(size_t, const gid_t*); +char* getpass(const char*); +int daemon(int, int); +void setusershell(void); +void endusershell(void); +char* getusershell(void); +int acct(const char*); +long syscall(long, ...); +int execvpe(const char*, char* const[], char* const[]); +int issetugid(void); +#endif + +#ifdef _GNU_SOURCE +extern char** environ; +int setresuid(uid_t, uid_t, uid_t); +int setresgid(gid_t, gid_t, gid_t); +int getresuid(uid_t*, uid_t*, uid_t*); +int getresgid(gid_t*, gid_t*, gid_t*); +char* get_current_dir_name(void); +int syncfs(int); +int euidaccess(const char*, int); +int eaccess(const char*, int); +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define lseek64 lseek +#define pread64 pread +#define pwrite64 pwrite +#define truncate64 truncate +#define ftruncate64 ftruncate +#define lockf64 lockf +#define off64_t off_t +#endif + +#define POSIX_CLOSE_RESTART 0 + +#define _XOPEN_VERSION 700 +#define _XOPEN_UNIX 1 +#define _XOPEN_ENH_I18N 1 + +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION _POSIX_VERSION + +#define _POSIX_ADVISORY_INFO _POSIX_VERSION +#define _POSIX_CHOWN_RESTRICTED 1 +#define _POSIX_IPV6 _POSIX_VERSION +#define _POSIX_JOB_CONTROL 1 +#define _POSIX_MAPPED_FILES _POSIX_VERSION +#define _POSIX_MEMLOCK _POSIX_VERSION +#define _POSIX_MEMLOCK_RANGE _POSIX_VERSION +#define _POSIX_MEMORY_PROTECTION _POSIX_VERSION +#define _POSIX_MESSAGE_PASSING _POSIX_VERSION +#define _POSIX_FSYNC _POSIX_VERSION +#define _POSIX_NO_TRUNC 1 +#define _POSIX_RAW_SOCKETS _POSIX_VERSION +#define _POSIX_REALTIME_SIGNALS _POSIX_VERSION +#define _POSIX_REGEXP 1 +#define _POSIX_SAVED_IDS 1 +#define _POSIX_SHELL 1 +#define _POSIX_SPAWN _POSIX_VERSION +#define _POSIX_VDISABLE 0 + +#define _POSIX_THREADS _POSIX_VERSION +#define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION +#define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#define _POSIX_THREAD_ATTR_STACKADDR _POSIX_VERSION +#define _POSIX_THREAD_ATTR_STACKSIZE _POSIX_VERSION +#define _POSIX_THREAD_PRIORITY_SCHEDULING _POSIX_VERSION +#define _POSIX_THREAD_CPUTIME _POSIX_VERSION +#define _POSIX_TIMERS _POSIX_VERSION +#define _POSIX_TIMEOUTS _POSIX_VERSION +#define _POSIX_MONOTONIC_CLOCK _POSIX_VERSION +#define _POSIX_CPUTIME _POSIX_VERSION +#define _POSIX_CLOCK_SELECTION _POSIX_VERSION +#define _POSIX_BARRIERS _POSIX_VERSION +#define _POSIX_SPIN_LOCKS _POSIX_VERSION +#define _POSIX_READER_WRITER_LOCKS _POSIX_VERSION +#define _POSIX_ASYNCHRONOUS_IO _POSIX_VERSION +#define _POSIX_SEMAPHORES _POSIX_VERSION +#define _POSIX_SHARED_MEMORY_OBJECTS _POSIX_VERSION + +#define _POSIX2_C_BIND _POSIX_VERSION + +#include + +#define _PC_LINK_MAX 0 +#define _PC_MAX_CANON 1 +#define _PC_MAX_INPUT 2 +#define _PC_NAME_MAX 3 +#define _PC_PATH_MAX 4 +#define _PC_PIPE_BUF 5 +#define _PC_CHOWN_RESTRICTED 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 +#define _PC_SYNC_IO 9 +#define _PC_ASYNC_IO 10 +#define _PC_PRIO_IO 11 +#define _PC_SOCK_MAXBUF 12 +#define _PC_FILESIZEBITS 13 +#define _PC_REC_INCR_XFER_SIZE 14 +#define _PC_REC_MAX_XFER_SIZE 15 +#define _PC_REC_MIN_XFER_SIZE 16 +#define _PC_REC_XFER_ALIGN 17 +#define _PC_ALLOC_SIZE_MIN 18 +#define _PC_SYMLINK_MAX 19 +#define _PC_2_SYMLINKS 20 + +#define _SC_ARG_MAX 0 +#define _SC_CHILD_MAX 1 +#define _SC_CLK_TCK 2 +#define _SC_NGROUPS_MAX 3 +#define _SC_OPEN_MAX 4 +#define _SC_STREAM_MAX 5 +#define _SC_TZNAME_MAX 6 +#define _SC_JOB_CONTROL 7 +#define _SC_SAVED_IDS 8 +#define _SC_REALTIME_SIGNALS 9 +#define _SC_PRIORITY_SCHEDULING 10 +#define _SC_TIMERS 11 +#define _SC_ASYNCHRONOUS_IO 12 +#define _SC_PRIORITIZED_IO 13 +#define _SC_SYNCHRONIZED_IO 14 +#define _SC_FSYNC 15 +#define _SC_MAPPED_FILES 16 +#define _SC_MEMLOCK 17 +#define _SC_MEMLOCK_RANGE 18 +#define _SC_MEMORY_PROTECTION 19 +#define _SC_MESSAGE_PASSING 20 +#define _SC_SEMAPHORES 21 +#define _SC_SHARED_MEMORY_OBJECTS 22 +#define _SC_AIO_LISTIO_MAX 23 +#define _SC_AIO_MAX 24 +#define _SC_AIO_PRIO_DELTA_MAX 25 +#define _SC_DELAYTIMER_MAX 26 +#define _SC_MQ_OPEN_MAX 27 +#define _SC_MQ_PRIO_MAX 28 +#define _SC_VERSION 29 +#define _SC_PAGE_SIZE 30 +#define _SC_PAGESIZE 30 /* !! */ +#define _SC_RTSIG_MAX 31 +#define _SC_SEM_NSEMS_MAX 32 +#define _SC_SEM_VALUE_MAX 33 +#define _SC_SIGQUEUE_MAX 34 +#define _SC_TIMER_MAX 35 +#define _SC_BC_BASE_MAX 36 +#define _SC_BC_DIM_MAX 37 +#define _SC_BC_SCALE_MAX 38 +#define _SC_BC_STRING_MAX 39 +#define _SC_COLL_WEIGHTS_MAX 40 +#define _SC_EXPR_NEST_MAX 42 +#define _SC_LINE_MAX 43 +#define _SC_RE_DUP_MAX 44 +#define _SC_2_VERSION 46 +#define _SC_2_C_BIND 47 +#define _SC_2_C_DEV 48 +#define _SC_2_FORT_DEV 49 +#define _SC_2_FORT_RUN 50 +#define _SC_2_SW_DEV 51 +#define _SC_2_LOCALEDEF 52 +#define _SC_UIO_MAXIOV 60 /* !! */ +#define _SC_IOV_MAX 60 +#define _SC_THREADS 67 +#define _SC_THREAD_SAFE_FUNCTIONS 68 +#define _SC_GETGR_R_SIZE_MAX 69 +#define _SC_GETPW_R_SIZE_MAX 70 +#define _SC_LOGIN_NAME_MAX 71 +#define _SC_TTY_NAME_MAX 72 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 73 +#define _SC_THREAD_KEYS_MAX 74 +#define _SC_THREAD_STACK_MIN 75 +#define _SC_THREAD_THREADS_MAX 76 +#define _SC_THREAD_ATTR_STACKADDR 77 +#define _SC_THREAD_ATTR_STACKSIZE 78 +#define _SC_THREAD_PRIORITY_SCHEDULING 79 +#define _SC_THREAD_PRIO_INHERIT 80 +#define _SC_THREAD_PRIO_PROTECT 81 +#define _SC_THREAD_PROCESS_SHARED 82 +#define _SC_NPROCESSORS_CONF 83 +#define _SC_NPROCESSORS_ONLN 84 +#define _SC_PHYS_PAGES 85 +#define _SC_AVPHYS_PAGES 86 +#define _SC_ATEXIT_MAX 87 +#define _SC_PASS_MAX 88 +#define _SC_XOPEN_VERSION 89 +#define _SC_XOPEN_XCU_VERSION 90 +#define _SC_XOPEN_UNIX 91 +#define _SC_XOPEN_CRYPT 92 +#define _SC_XOPEN_ENH_I18N 93 +#define _SC_XOPEN_SHM 94 +#define _SC_2_CHAR_TERM 95 +#define _SC_2_UPE 97 +#define _SC_XOPEN_XPG2 98 +#define _SC_XOPEN_XPG3 99 +#define _SC_XOPEN_XPG4 100 +#define _SC_NZERO 109 +#define _SC_XBS5_ILP32_OFF32 125 +#define _SC_XBS5_ILP32_OFFBIG 126 +#define _SC_XBS5_LP64_OFF64 127 +#define _SC_XBS5_LPBIG_OFFBIG 128 +#define _SC_XOPEN_LEGACY 129 +#define _SC_XOPEN_REALTIME 130 +#define _SC_XOPEN_REALTIME_THREADS 131 +#define _SC_ADVISORY_INFO 132 +#define _SC_BARRIERS 133 +#define _SC_CLOCK_SELECTION 137 +#define _SC_CPUTIME 138 +#define _SC_THREAD_CPUTIME 139 +#define _SC_MONOTONIC_CLOCK 149 +#define _SC_READER_WRITER_LOCKS 153 +#define _SC_SPIN_LOCKS 154 +#define _SC_REGEXP 155 +#define _SC_SHELL 157 +#define _SC_SPAWN 159 +#define _SC_SPORADIC_SERVER 160 +#define _SC_THREAD_SPORADIC_SERVER 161 +#define _SC_TIMEOUTS 164 +#define _SC_TYPED_MEMORY_OBJECTS 165 +#define _SC_2_PBS 168 +#define _SC_2_PBS_ACCOUNTING 169 +#define _SC_2_PBS_LOCATE 170 +#define _SC_2_PBS_MESSAGE 171 +#define _SC_2_PBS_TRACK 172 +#define _SC_SYMLOOP_MAX 173 +#define _SC_STREAMS 174 +#define _SC_2_PBS_CHECKPOINT 175 +#define _SC_V6_ILP32_OFF32 176 +#define _SC_V6_ILP32_OFFBIG 177 +#define _SC_V6_LP64_OFF64 178 +#define _SC_V6_LPBIG_OFFBIG 179 +#define _SC_HOST_NAME_MAX 180 +#define _SC_TRACE 181 +#define _SC_TRACE_EVENT_FILTER 182 +#define _SC_TRACE_INHERIT 183 +#define _SC_TRACE_LOG 184 + +#define _SC_IPV6 235 +#define _SC_RAW_SOCKETS 236 +#define _SC_V7_ILP32_OFF32 237 +#define _SC_V7_ILP32_OFFBIG 238 +#define _SC_V7_LP64_OFF64 239 +#define _SC_V7_LPBIG_OFFBIG 240 +#define _SC_SS_REPL_MAX 241 +#define _SC_TRACE_EVENT_NAME_MAX 242 +#define _SC_TRACE_NAME_MAX 243 +#define _SC_TRACE_SYS_MAX 244 +#define _SC_TRACE_USER_EVENT_MAX 245 +#define _SC_XOPEN_STREAMS 246 +#define _SC_THREAD_ROBUST_PRIO_INHERIT 247 +#define _SC_THREAD_ROBUST_PRIO_PROTECT 248 + +#define _CS_PATH 0 +#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 +#define _CS_GNU_LIBC_VERSION 2 +#define _CS_GNU_LIBPTHREAD_VERSION 3 +#define _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS 4 +#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS 5 + +#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS 1116 +#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS 1117 +#define _CS_POSIX_V6_ILP32_OFF32_LIBS 1118 +#define _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS 1119 +#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS 1120 +#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS 1121 +#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS 1122 +#define _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS 1123 +#define _CS_POSIX_V6_LP64_OFF64_CFLAGS 1124 +#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS 1125 +#define _CS_POSIX_V6_LP64_OFF64_LIBS 1126 +#define _CS_POSIX_V6_LP64_OFF64_LINTFLAGS 1127 +#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS 1128 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS 1129 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS 1130 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS 1131 +#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS 1132 +#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS 1133 +#define _CS_POSIX_V7_ILP32_OFF32_LIBS 1134 +#define _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS 1135 +#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS 1136 +#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS 1137 +#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS 1138 +#define _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS 1139 +#define _CS_POSIX_V7_LP64_OFF64_CFLAGS 1140 +#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS 1141 +#define _CS_POSIX_V7_LP64_OFF64_LIBS 1142 +#define _CS_POSIX_V7_LP64_OFF64_LINTFLAGS 1143 +#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS 1144 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS 1145 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS 1146 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/utime.h b/third_party/ulib/musl/include/utime.h new file mode 100644 index 000000000..7479bf85c --- /dev/null +++ b/third_party/ulib/musl/include/utime.h @@ -0,0 +1,23 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_time_t + +#include + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +int utime(const char*, const struct utimbuf*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/utmp.h b/third_party/ulib/musl/include/utmp.h new file mode 100644 index 000000000..dae556963 --- /dev/null +++ b/third_party/ulib/musl/include/utmp.h @@ -0,0 +1,52 @@ +#ifndef _UTMP_H +#define _UTMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define ACCOUNTING 9 +#define UT_NAMESIZE 32 +#define UT_HOSTSIZE 256 +#define UT_LINESIZE 32 + +struct lastlog { + time_t ll_time; + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; +}; + +#define ut_time ut_tv.tv_sec +#define ut_name ut_user +#define ut_addr ut_addr_v6[0] +#define utmp utmpx +#define e_exit __e_exit +#define e_termination __e_termination + +void endutent(void); +struct utmp* getutent(void); +struct utmp* getutid(const struct utmp*); +struct utmp* getutline(const struct utmp*); +struct utmp* pututline(const struct utmp*); +void setutent(void); + +void updwtmp(const char*, const struct utmp*); +int utmpname(const char*); + +int login_tty(int); + +#define _PATH_UTMP "/dev/null/utmp" +#define _PATH_WTMP "/dev/null/wtmp" + +#define UTMP_FILE _PATH_UTMP +#define WTMP_FILE _PATH_WTMP +#define UTMP_FILENAME _PATH_UTMP +#define WTMP_FILENAME _PATH_WTMP + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/utmpx.h b/third_party/ulib/musl/include/utmpx.h new file mode 100644 index 000000000..1e999d39c --- /dev/null +++ b/third_party/ulib/musl/include/utmpx.h @@ -0,0 +1,62 @@ +#ifndef _UTMPX_H +#define _UTMPX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_pid_t +#define __NEED_time_t +#define __NEED_suseconds_t +#define __NEED_struct_timeval + +#include + +struct utmpx { + short ut_type; + pid_t ut_pid; + char ut_line[32]; + char ut_id[4]; + char ut_user[32]; + char ut_host[256]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + long ut_session; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +void endutxent(void); +struct utmpx* getutxent(void); +struct utmpx* getutxid(const struct utmpx*); +struct utmpx* getutxline(const struct utmpx*); +struct utmpx* pututxline(const struct utmpx*); +void setutxent(void); + +#if defined(_BSD_SOURCE) | defined(_GNU_SOURCE) +#define e_exit __e_exit +#define e_termination __e_termination +void updwtmpx(const char*, const struct utmpx*); +int utmpxname(const char*); +#endif + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/values.h b/third_party/ulib/musl/include/values.h new file mode 100644 index 000000000..76d408027 --- /dev/null +++ b/third_party/ulib/musl/include/values.h @@ -0,0 +1,39 @@ +#ifndef _VALUES_H +#define _VALUES_H + +#include + +#define CHARBITS (sizeof(char) * 8) +#define SHORTBITS (sizeof(short) * 8) +#define INTBITS (sizeof(int) * 8) +#define LONGBITS (sizeof(long) * 8) +#define PTRBITS (sizeof(char*) * 8) +#define DOUBLEBITS (sizeof(double) * 8) +#define FLOATBITS (sizeof(float) * 8) + +#define MINSHORT SHRT_MIN +#define MININT INT_MIN +#define MINLONG LONG_MIN + +#define MAXSHORT SHRT_MAX +#define MAXINT INT_MAX +#define MAXLONG LONG_MAX + +#define HIBITS MINSHORT +#define HIBITL MINLONG + +#include + +#define MAXDOUBLE DBL_MAX +#undef MAXFLOAT +#define MAXFLOAT FLT_MAX +#define MINDOUBLE DBL_MIN +#define MINFLOAT FLT_MIN +#define DMINEXP DBL_MIN_EXP +#define FMINEXP FLT_MIN_EXP +#define DMAXEXP DBL_MAX_EXP +#define FMAXEXP FLT_MAX_EXP + +#define BITSPERBYTE CHAR_BIT + +#endif diff --git a/third_party/ulib/musl/include/wait.h b/third_party/ulib/musl/include/wait.h new file mode 100644 index 000000000..98396e2d2 --- /dev/null +++ b/third_party/ulib/musl/include/wait.h @@ -0,0 +1,2 @@ +#warning redirecting incorrect #include to +#include diff --git a/third_party/ulib/musl/include/wchar.h b/third_party/ulib/musl/include/wchar.h new file mode 100644 index 000000000..bb14df42d --- /dev/null +++ b/third_party/ulib/musl/include/wchar.h @@ -0,0 +1,186 @@ +#ifndef _WCHAR_H +#define _WCHAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_FILE +#define __NEED___isoc_va_list +#define __NEED_size_t +#define __NEED_wchar_t +#define __NEED_wint_t +#define __NEED_mbstate_t + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_locale_t +#define __NEED_va_list +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_wctype_t +#endif + +#include + +#if L'\0' - 1 > 0 +#define WCHAR_MAX (0xffffffffu + L'\0') +#define WCHAR_MIN (0 + L'\0') +#else +#define WCHAR_MAX (0x7fffffff + L'\0') +#define WCHAR_MIN (-1 - 0x7fffffff + L'\0') +#endif + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#undef WEOF +#define WEOF 0xffffffffU + +wchar_t* wcscpy(wchar_t* __restrict, const wchar_t* __restrict); +wchar_t* wcsncpy(wchar_t* __restrict, const wchar_t* __restrict, size_t); + +wchar_t* wcscat(wchar_t* __restrict, const wchar_t* __restrict); +wchar_t* wcsncat(wchar_t* __restrict, const wchar_t* __restrict, size_t); + +int wcscmp(const wchar_t*, const wchar_t*); +int wcsncmp(const wchar_t*, const wchar_t*, size_t); + +int wcscoll(const wchar_t*, const wchar_t*); +size_t wcsxfrm(wchar_t* __restrict, const wchar_t* __restrict, size_t n); + +wchar_t* wcschr(const wchar_t*, wchar_t); +wchar_t* wcsrchr(const wchar_t*, wchar_t); + +size_t wcscspn(const wchar_t*, const wchar_t*); +size_t wcsspn(const wchar_t*, const wchar_t*); +wchar_t* wcspbrk(const wchar_t*, const wchar_t*); + +wchar_t* wcstok(wchar_t* __restrict, const wchar_t* __restrict, wchar_t** __restrict); + +size_t wcslen(const wchar_t*); + +wchar_t* wcsstr(const wchar_t* __restrict, const wchar_t* __restrict); +wchar_t* wcswcs(const wchar_t*, const wchar_t*); + +wchar_t* wmemchr(const wchar_t*, wchar_t, size_t); +int wmemcmp(const wchar_t*, const wchar_t*, size_t); +wchar_t* wmemcpy(wchar_t* __restrict, const wchar_t* __restrict, size_t); +wchar_t* wmemmove(wchar_t*, const wchar_t*, size_t); +wchar_t* wmemset(wchar_t*, wchar_t, size_t); + +wint_t btowc(int); +int wctob(wint_t); + +int mbsinit(const mbstate_t*); +size_t mbrtowc(wchar_t* __restrict, const char* __restrict, size_t, mbstate_t* __restrict); +size_t wcrtomb(char* __restrict, wchar_t, mbstate_t* __restrict); + +size_t mbrlen(const char* __restrict, size_t, mbstate_t* __restrict); + +size_t mbsrtowcs(wchar_t* __restrict, const char** __restrict, size_t, mbstate_t* __restrict); +size_t wcsrtombs(char* __restrict, const wchar_t** __restrict, size_t, mbstate_t* __restrict); + +float wcstof(const wchar_t* __restrict, wchar_t** __restrict); +double wcstod(const wchar_t* __restrict, wchar_t** __restrict); +long double wcstold(const wchar_t* __restrict, wchar_t** __restrict); + +long wcstol(const wchar_t* __restrict, wchar_t** __restrict, int); +unsigned long wcstoul(const wchar_t* __restrict, wchar_t** __restrict, int); + +long long wcstoll(const wchar_t* __restrict, wchar_t** __restrict, int); +unsigned long long wcstoull(const wchar_t* __restrict, wchar_t** __restrict, int); + +int fwide(FILE*, int); + +int wprintf(const wchar_t* __restrict, ...); +int fwprintf(FILE* __restrict, const wchar_t* __restrict, ...); +int swprintf(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...); + +int vwprintf(const wchar_t* __restrict, __isoc_va_list); +int vfwprintf(FILE* __restrict, const wchar_t* __restrict, __isoc_va_list); +int vswprintf(wchar_t* __restrict, size_t, const wchar_t* __restrict, __isoc_va_list); + +int wscanf(const wchar_t* __restrict, ...); +int fwscanf(FILE* __restrict, const wchar_t* __restrict, ...); +int swscanf(const wchar_t* __restrict, const wchar_t* __restrict, ...); + +int vwscanf(const wchar_t* __restrict, __isoc_va_list); +int vfwscanf(FILE* __restrict, const wchar_t* __restrict, __isoc_va_list); +int vswscanf(const wchar_t* __restrict, const wchar_t* __restrict, __isoc_va_list); + +wint_t fgetwc(FILE*); +wint_t getwc(FILE*); +wint_t getwchar(void); + +wint_t fputwc(wchar_t, FILE*); +wint_t putwc(wchar_t, FILE*); +wint_t putwchar(wchar_t); + +wchar_t* fgetws(wchar_t* __restrict, int, FILE* __restrict); +int fputws(const wchar_t* __restrict, FILE* __restrict); + +wint_t ungetwc(wint_t, FILE*); + +struct tm; +size_t wcsftime(wchar_t* __restrict, size_t, const wchar_t* __restrict, + const struct tm* __restrict); + +#undef iswdigit + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +FILE* open_wmemstream(wchar_t**, size_t*); +size_t mbsnrtowcs(wchar_t* __restrict, const char** __restrict, size_t, size_t, + mbstate_t* __restrict); +size_t wcsnrtombs(char* __restrict, const wchar_t** __restrict, size_t, size_t, + mbstate_t* __restrict); +wchar_t* wcsdup(const wchar_t*); +size_t wcsnlen(const wchar_t*, size_t); +wchar_t* wcpcpy(wchar_t* __restrict, const wchar_t* __restrict); +wchar_t* wcpncpy(wchar_t* __restrict, const wchar_t* __restrict, size_t); +int wcscasecmp(const wchar_t*, const wchar_t*); +int wcscasecmp_l(const wchar_t*, const wchar_t*, locale_t); +int wcsncasecmp(const wchar_t*, const wchar_t*, size_t); +int wcsncasecmp_l(const wchar_t*, const wchar_t*, size_t, locale_t); +int wcscoll_l(const wchar_t*, const wchar_t*, locale_t); +size_t wcsxfrm_l(wchar_t* __restrict, const wchar_t* __restrict, size_t n, locale_t); +#endif + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +int wcwidth(wchar_t); +int wcswidth(const wchar_t*, size_t); +int iswalnum(wint_t); +int iswalpha(wint_t); +int iswblank(wint_t); +int iswcntrl(wint_t); +int iswdigit(wint_t); +int iswgraph(wint_t); +int iswlower(wint_t); +int iswprint(wint_t); +int iswpunct(wint_t); +int iswspace(wint_t); +int iswupper(wint_t); +int iswxdigit(wint_t); +int iswctype(wint_t, wctype_t); +wint_t towlower(wint_t); +wint_t towupper(wint_t); +wctype_t wctype(const char*); + +#ifndef __cplusplus +#undef iswdigit +#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a) - '0') < 10) +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/wctype.h b/third_party/ulib/musl/include/wctype.h new file mode 100644 index 000000000..25fcd08e3 --- /dev/null +++ b/third_party/ulib/musl/include/wctype.h @@ -0,0 +1,79 @@ +#ifndef _WCTYPE_H +#define _WCTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_wint_t +#define __NEED_wctype_t + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_locale_t +#endif + +#include + +typedef const int* wctrans_t; + +#undef WEOF +#define WEOF 0xffffffffU + +#undef iswdigit + +int iswalnum(wint_t); +int iswalpha(wint_t); +int iswblank(wint_t); +int iswcntrl(wint_t); +int iswdigit(wint_t); +int iswgraph(wint_t); +int iswlower(wint_t); +int iswprint(wint_t); +int iswpunct(wint_t); +int iswspace(wint_t); +int iswupper(wint_t); +int iswxdigit(wint_t); +int iswctype(wint_t, wctype_t); +wint_t towctrans(wint_t, wctrans_t); +wint_t towlower(wint_t); +wint_t towupper(wint_t); +wctrans_t wctrans(const char*); +wctype_t wctype(const char*); + +#ifndef __cplusplus +#undef iswdigit +#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a) - '0') < 10) +#endif + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +int iswalnum_l(wint_t, locale_t); +int iswalpha_l(wint_t, locale_t); +int iswblank_l(wint_t, locale_t); +int iswcntrl_l(wint_t, locale_t); +int iswdigit_l(wint_t, locale_t); +int iswgraph_l(wint_t, locale_t); +int iswlower_l(wint_t, locale_t); +int iswprint_l(wint_t, locale_t); +int iswpunct_l(wint_t, locale_t); +int iswspace_l(wint_t, locale_t); +int iswupper_l(wint_t, locale_t); +int iswxdigit_l(wint_t, locale_t); +int iswctype_l(wint_t, wctype_t, locale_t); +wint_t towlower_l(wint_t, locale_t); +wint_t towupper_l(wint_t, locale_t); +wint_t towctrans_l(wint_t, wctrans_t, locale_t); +wctrans_t wctrans_l(const char*, locale_t); +wctype_t wctype_l(const char*, locale_t); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/include/wordexp.h b/third_party/ulib/musl/include/wordexp.h new file mode 100644 index 000000000..26c460dbb --- /dev/null +++ b/third_party/ulib/musl/include/wordexp.h @@ -0,0 +1,41 @@ +#ifndef _WORDEXP_H +#define _WORDEXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_size_t + +#include + +#define WRDE_DOOFFS 1 +#define WRDE_APPEND 2 +#define WRDE_NOCMD 4 +#define WRDE_REUSE 8 +#define WRDE_SHOWERR 16 +#define WRDE_UNDEF 32 + +typedef struct { + size_t we_wordc; + char** we_wordv; + size_t we_offs; +} wordexp_t; + +#define WRDE_NOSYS -1 +#define WRDE_NOSPACE 1 +#define WRDE_BADCHAR 2 +#define WRDE_BADVAL 3 +#define WRDE_CMDSUB 4 +#define WRDE_SYNTAX 5 + +int wordexp(const char* __restrict, wordexp_t* __restrict, int); +void wordfree(wordexp_t*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/ulib/musl/ldso/BUILD.gn b/third_party/ulib/musl/ldso/BUILD.gn new file mode 100644 index 000000000..1fc17521b --- /dev/null +++ b/third_party/ulib/musl/ldso/BUILD.gn @@ -0,0 +1,9 @@ +source_set("ldso") { + configs = [] + configs = [ "//gnbuild:no_stack_protector" ] + + sources = [ + "dlstart.c", + "dynlink.c", + ] +} diff --git a/third_party/ulib/musl/ldso/dlstart.c b/third_party/ulib/musl/ldso/dlstart.c new file mode 100644 index 000000000..107625dd6 --- /dev/null +++ b/third_party/ulib/musl/ldso/dlstart.c @@ -0,0 +1,153 @@ +#include "dynlink.h" +#include + +#ifndef START +#define START "_dlstart" +#endif + +#define SHARED + +#include "crt_arch.h" + +#ifndef GETFUNCSYM +#define GETFUNCSYM(fp, sym, got) \ + do { \ + __attribute__((__visibility__("hidden"))) void sym(unsigned char*, size_t*); \ + static void (*static_func_ptr)(unsigned char*, size_t*) = sym; \ + __asm__ __volatile__("" : "+m"(static_func_ptr) : : "memory"); \ + *(fp) = static_func_ptr; \ + } while (0) +#endif + +__attribute__((__visibility__("hidden"))) void _dlstart_c(size_t* sp, size_t* dynv) { + size_t i, aux[AUX_CNT], dyn[DYN_CNT]; + size_t *rel, rel_size, base; + + int argc = *sp; + char** argv = (void*)(sp + 1); + + for (i = argc + 1; argv[i]; i++) + ; + size_t* auxv = (void*)(argv + i + 1); + + for (i = 0; i < AUX_CNT; i++) + aux[i] = 0; + for (i = 0; auxv[i]; i += 2) + if (auxv[i] < AUX_CNT) aux[auxv[i]] = auxv[i + 1]; + +#if DL_FDPIC + struct fdpic_loadseg *segs, fakeseg; + size_t j; + if (dynv) { + /* crt_arch.h entry point asm is responsible for reserving + * space and moving the extra fdpic arguments to the stack + * vector where they are easily accessible from C. */ + segs = ((struct fdpic_loadmap*)(sp[-1] ? sp[-1] : sp[-2]))->segs; + } else { + /* If dynv is null, the entry point was started from loader + * that is not fdpic-aware. We can assume normal fixed- + * displacement ELF loading was performed, but when ldso was + * run as a command, finding the Ehdr is a heursitic: we + * have to assume Phdrs start in the first 4k of the file. */ + base = aux[AT_BASE]; + if (!base) base = aux[AT_PHDR] & -4096; + segs = &fakeseg; + segs[0].addr = base; + segs[0].p_vaddr = 0; + segs[0].p_memsz = -1; + Ehdr* eh = (void*)base; + Phdr* ph = (void*)(base + eh->e_phoff); + size_t phnum = eh->e_phnum; + size_t phent = eh->e_phentsize; + while (phnum-- && ph->p_type != PT_DYNAMIC) + ph = (void*)((size_t)ph + phent); + dynv = (void*)(base + ph->p_vaddr); + } +#endif + + for (i = 0; i < DYN_CNT; i++) + dyn[i] = 0; + for (i = 0; dynv[i]; i += 2) + if (dynv[i] < DYN_CNT) dyn[dynv[i]] = dynv[i + 1]; + +#if DL_FDPIC + for (i = 0; i < DYN_CNT; i++) { + if (i == DT_RELASZ || i == DT_RELSZ) continue; + if (!dyn[i]) continue; + for (j = 0; dyn[i] - segs[j].p_vaddr >= segs[j].p_memsz; j++) + ; + dyn[i] += segs[j].addr - segs[j].p_vaddr; + } + base = 0; + + const Sym* syms = (void*)dyn[DT_SYMTAB]; + + rel = (void*)dyn[DT_RELA]; + rel_size = dyn[DT_RELASZ]; + for (; rel_size; rel += 3, rel_size -= 3 * sizeof(size_t)) { + if (!IS_RELATIVE(rel[1], syms)) continue; + for (j = 0; rel[0] - segs[j].p_vaddr >= segs[j].p_memsz; j++) + ; + size_t* rel_addr = (void*)(rel[0] + segs[j].addr - segs[j].p_vaddr); + if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { + *rel_addr += + segs[rel_addr[1]].addr - segs[rel_addr[1]].p_vaddr + syms[R_SYM(rel[1])].st_value; + rel_addr[1] = dyn[DT_PLTGOT]; + } else { + size_t val = syms[R_SYM(rel[1])].st_value; + for (j = 0; val - segs[j].p_vaddr >= segs[j].p_memsz; j++) + ; + *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val; + } + } +#else + /* If the dynamic linker is invoked as a command, its load + * address is not available in the aux vector. Instead, compute + * the load address as the difference between &_DYNAMIC and the + * virtual address in the PT_DYNAMIC program header. */ + base = aux[AT_BASE]; + if (!base) { + size_t phnum = aux[AT_PHNUM]; + size_t phentsize = aux[AT_PHENT]; + Phdr* ph = (void*)aux[AT_PHDR]; + for (i = phnum; i--; ph = (void*)((char*)ph + phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + base = (size_t)dynv - ph->p_vaddr; + break; + } + } + } + + /* MIPS uses an ugly packed form for GOT relocations. Since we + * can't make function calls yet and the code is tiny anyway, + * it's simply inlined here. */ + if (NEED_MIPS_GOT_RELOCS) { + size_t local_cnt = 0; + size_t* got = (void*)(base + dyn[DT_PLTGOT]); + for (i = 0; dynv[i]; i += 2) + if (dynv[i] == DT_MIPS_LOCAL_GOTNO) local_cnt = dynv[i + 1]; + for (i = 0; i < local_cnt; i++) + got[i] += base; + } + + rel = (void*)(base + dyn[DT_REL]); + rel_size = dyn[DT_RELSZ]; + for (; rel_size; rel += 2, rel_size -= 2 * sizeof(size_t)) { + if (!IS_RELATIVE(rel[1], 0)) continue; + size_t* rel_addr = (void*)(base + rel[0]); + *rel_addr += base; + } + + rel = (void*)(base + dyn[DT_RELA]); + rel_size = dyn[DT_RELASZ]; + for (; rel_size; rel += 3, rel_size -= 3 * sizeof(size_t)) { + if (!IS_RELATIVE(rel[1], 0)) continue; + size_t* rel_addr = (void*)(base + rel[0]); + *rel_addr = base + rel[2]; + } +#endif + + stage2_func dls2; + GETFUNCSYM(&dls2, __dls2, base + dyn[DT_PLTGOT]); + dls2((void*)base, sp); +} diff --git a/third_party/ulib/musl/ldso/dynlink.c b/third_party/ulib/musl/ldso/dynlink.c new file mode 100644 index 000000000..d2521c6eb --- /dev/null +++ b/third_party/ulib/musl/ldso/dynlink.c @@ -0,0 +1,1838 @@ +#define _GNU_SOURCE +#include "dynlink.h" +#include "libc.h" +#include "pthread_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void error(const char*, ...); + +#define MAXP2(a, b) (-(-(a) & -(b))) +#define ALIGN(x, y) ((x) + (y)-1 & -(y)) + +struct debug { + int ver; + void* head; + void (*bp)(void); + int state; + void* base; +}; + +struct td_index { + size_t args[2]; + struct td_index* next; +}; + +struct dso { +#if DL_FDPIC + struct fdpic_loadmap* loadmap; +#else + unsigned char* base; +#endif + char* name; + size_t* dynv; + struct dso *next, *prev; + + Phdr* phdr; + int phnum; + size_t phentsize; + int refcnt; + Sym* syms; + uint32_t* hashtab; + uint32_t* ghashtab; + int16_t* versym; + char* strings; + unsigned char* map; + size_t map_len; + dev_t dev; + ino_t ino; + signed char global; + char relocated; + char constructed; + char kernel_mapped; + struct dso **deps, *needed_by; + char *rpath_orig, *rpath; + struct tls_module tls; + size_t tls_id; + size_t relro_start, relro_end; + void** new_dtv; + unsigned char* new_tls; + volatile int new_dtv_idx, new_tls_idx; + struct td_index* td_index; + struct dso* fini_next; + char* shortname; +#if DL_FDPIC + unsigned char* base; +#else + struct fdpic_loadmap* loadmap; +#endif + struct funcdesc { + void* addr; + size_t* got; + } * funcdescs; + size_t* got; + char buf[]; +}; + +struct symdef { + Sym* sym; + struct dso* dso; +}; + +int __init_tp(void*); +void __init_libc(char**, char*); +void* __copy_tls(unsigned char*); + +static struct builtin_tls { + char c; + struct pthread pt; + void* space[16]; +} builtin_tls[1]; +#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) + +#define ADDEND_LIMIT 4096 +static size_t *saved_addends, *apply_addends_to; + +static struct dso ldso; +static struct dso *head, *tail, *fini_head; +static char *env_path, *sys_path; +static unsigned long long gencnt; +static int runtime; +static int ldd_mode; +static int ldso_fail; +static int noload; +static jmp_buf* rtld_fail; +static pthread_rwlock_t lock; +static struct debug debug; +static struct tls_module* tls_tail; +static size_t tls_cnt, tls_offset, tls_align = MIN_TLS_ALIGN; +static size_t static_tls_cnt; +static pthread_mutex_t init_fini_lock = {._m_type = PTHREAD_MUTEX_RECURSIVE}; +static struct fdpic_loadmap* app_loadmap; +static struct fdpic_dummy_loadmap app_dummy_loadmap; + +struct debug* _dl_debug_addr = &debug; + +__attribute__((__visibility__("hidden"))) void (*const __init_array_start)(void) = 0, + (*const __fini_array_start)(void) = 0; + +__attribute__((__visibility__("hidden"))) extern void (*const __init_array_end)(void), + (*const __fini_array_end)(void); + +weak_alias(__init_array_start, __init_array_end); +weak_alias(__fini_array_start, __fini_array_end); + +static int dl_strcmp(const char* l, const char* r) { + for (; *l == *r && *l; l++, r++) + ; + return *(unsigned char*)l - *(unsigned char*)r; +} +#define strcmp(l, r) dl_strcmp(l, r) + +/* Compute load address for a virtual address in a given dso. */ +#if DL_FDPIC +static void* laddr(const struct dso* p, size_t v) { + size_t j = 0; + if (!p->loadmap) return p->base + v; + for (j = 0; v - p->loadmap->segs[j].p_vaddr >= p->loadmap->segs[j].p_memsz; j++) + ; + return (void*)(v - p->loadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); +} +#define fpaddr(p, v) ((void (*)(void)) & (struct funcdesc){laddr(p, v), (p)->got}) +#else +#define laddr(p, v) (void*)((p)->base + (v)) +#define fpaddr(p, v) ((void (*)(void))laddr(p, v)) +#endif + +static void decode_vec(size_t* v, size_t* a, size_t cnt) { + size_t i; + for (i = 0; i < cnt; i++) + a[i] = 0; + for (; v[0]; v += 2) + if (v[0] - 1 < cnt - 1) { + a[0] |= 1UL << v[0]; + a[v[0]] = v[1]; + } +} + +static int search_vec(size_t* v, size_t* r, size_t key) { + for (; v[0] != key; v += 2) + if (!v[0]) return 0; + *r = v[1]; + return 1; +} + +static uint32_t sysv_hash(const char* s0) { + const unsigned char* s = (void*)s0; + uint_fast32_t h = 0; + while (*s) { + h = 16 * h + *s++; + h ^= h >> 24 & 0xf0; + } + return h & 0xfffffff; +} + +static uint32_t gnu_hash(const char* s0) { + const unsigned char* s = (void*)s0; + uint_fast32_t h = 5381; + for (; *s; s++) + h += h * 32 + *s; + return h; +} + +static Sym* sysv_lookup(const char* s, uint32_t h, struct dso* dso) { + size_t i; + Sym* syms = dso->syms; + uint32_t* hashtab = dso->hashtab; + char* strings = dso->strings; + for (i = hashtab[2 + h % hashtab[0]]; i; i = hashtab[2 + hashtab[0] + i]) { + if ((!dso->versym || dso->versym[i] >= 0) && (!strcmp(s, strings + syms[i].st_name))) + return syms + i; + } + return 0; +} + +static Sym* gnu_lookup(uint32_t h1, uint32_t* hashtab, struct dso* dso, const char* s) { + uint32_t nbuckets = hashtab[0]; + uint32_t* buckets = hashtab + 4 + hashtab[2] * (sizeof(size_t) / 4); + uint32_t i = buckets[h1 % nbuckets]; + + if (!i) return 0; + + uint32_t* hashval = buckets + nbuckets + (i - hashtab[1]); + + for (h1 |= 1;; i++) { + uint32_t h2 = *hashval++; + if ((h1 == (h2 | 1)) && (!dso->versym || dso->versym[i] >= 0) && + !strcmp(s, dso->strings + dso->syms[i].st_name)) + return dso->syms + i; + if (h2 & 1) break; + } + + return 0; +} + +static Sym* gnu_lookup_filtered(uint32_t h1, uint32_t* hashtab, struct dso* dso, const char* s, + uint32_t fofs, size_t fmask) { + const size_t* bloomwords = (const void*)(hashtab + 4); + size_t f = bloomwords[fofs & (hashtab[2] - 1)]; + if (!(f & fmask)) return 0; + + f >>= (h1 >> hashtab[3]) % (8 * sizeof f); + if (!(f & 1)) return 0; + + return gnu_lookup(h1, hashtab, dso, s); +} + +#define OK_TYPES \ + (1 << STT_NOTYPE | 1 << STT_OBJECT | 1 << STT_FUNC | 1 << STT_COMMON | 1 << STT_TLS) +#define OK_BINDS (1 << STB_GLOBAL | 1 << STB_WEAK | 1 << STB_GNU_UNIQUE) + +#ifndef ARCH_SYM_REJECT_UND +#define ARCH_SYM_REJECT_UND(s) 0 +#endif + +static struct symdef find_sym(struct dso* dso, const char* s, int need_def) { + uint32_t h = 0, gh, gho, *ght; + size_t ghm = 0; + struct symdef def = {0}; + for (; dso; dso = dso->next) { + Sym* sym; + if (!dso->global) continue; + if ((ght = dso->ghashtab)) { + if (!ghm) { + gh = gnu_hash(s); + int maskbits = 8 * sizeof ghm; + gho = gh / maskbits; + ghm = 1ul << gh % maskbits; + } + sym = gnu_lookup_filtered(gh, ght, dso, s, gho, ghm); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, dso); + } + if (!sym) continue; + if (!sym->st_shndx) + if (need_def || (sym->st_info & 0xf) == STT_TLS || ARCH_SYM_REJECT_UND(sym)) continue; + if (!sym->st_value) + if ((sym->st_info & 0xf) != STT_TLS) continue; + if (!(1 << (sym->st_info & 0xf) & OK_TYPES)) continue; + if (!(1 << (sym->st_info >> 4) & OK_BINDS)) continue; + + if (def.sym && sym->st_info >> 4 == STB_WEAK) continue; + def.sym = sym; + def.dso = dso; + if (sym->st_info >> 4 == STB_GLOBAL) break; + } + return def; +} + +__attribute__((__visibility__("hidden"))) ptrdiff_t __tlsdesc_static(void), __tlsdesc_dynamic(void); + +static void do_relocs(struct dso* dso, size_t* rel, size_t rel_size, size_t stride) { + unsigned char* base = dso->base; + Sym* syms = dso->syms; + char* strings = dso->strings; + Sym* sym; + const char* name; + void* ctx; + int type; + int sym_index; + struct symdef def; + size_t* reloc_addr; + size_t sym_val; + size_t tls_val; + size_t addend; + int skip_relative = 0, reuse_addends = 0, save_slot = 0; + + if (dso == &ldso) { + /* Only ldso's REL table needs addend saving/reuse. */ + if (rel == apply_addends_to) reuse_addends = 1; + skip_relative = 1; + } + + for (; rel_size; rel += stride, rel_size -= stride * sizeof(size_t)) { + if (skip_relative && IS_RELATIVE(rel[1], dso->syms)) continue; + type = R_TYPE(rel[1]); + if (type == REL_NONE) continue; + sym_index = R_SYM(rel[1]); + reloc_addr = laddr(dso, rel[0]); + if (sym_index) { + sym = syms + sym_index; + name = strings + sym->st_name; + ctx = type == REL_COPY ? head->next : head; + def = (sym->st_info & 0xf) == STT_SECTION ? (struct symdef){.dso = dso, .sym = sym} + : find_sym(ctx, name, type == REL_PLT); + if (!def.sym && (sym->st_shndx != SHN_UNDEF || sym->st_info >> 4 != STB_WEAK)) { + error("Error relocating %s: %s: symbol not found", dso->name, name); + if (runtime) longjmp(*rtld_fail, 1); + continue; + } + } else { + sym = 0; + def.sym = 0; + def.dso = dso; + } + + if (stride > 2) { + addend = rel[2]; + } else if (type == REL_GOT || type == REL_PLT || type == REL_COPY) { + addend = 0; + } else if (reuse_addends) { + /* Save original addend in stage 2 where the dso + * chain consists of just ldso; otherwise read back + * saved addend since the inline one was clobbered. */ + if (head == &ldso) saved_addends[save_slot] = *reloc_addr; + addend = saved_addends[save_slot++]; + } else { + addend = *reloc_addr; + } + + sym_val = def.sym ? (size_t)laddr(def.dso, def.sym->st_value) : 0; + tls_val = def.sym ? def.sym->st_value : 0; + + switch (type) { + case REL_NONE: + break; + case REL_OFFSET: + addend -= (size_t)reloc_addr; + case REL_SYMBOLIC: + case REL_GOT: + case REL_PLT: + *reloc_addr = sym_val + addend; + break; + case REL_RELATIVE: + *reloc_addr = (size_t)base + addend; + break; + case REL_SYM_OR_REL: + if (sym) + *reloc_addr = sym_val + addend; + else + *reloc_addr = (size_t)base + addend; + break; + case REL_COPY: + memcpy(reloc_addr, (void*)sym_val, sym->st_size); + break; + case REL_OFFSET32: + *(uint32_t*)reloc_addr = sym_val + addend - (size_t)reloc_addr; + break; + case REL_FUNCDESC: + *reloc_addr = def.sym ? (size_t)(def.dso->funcdescs + (def.sym - def.dso->syms)) : 0; + break; + case REL_FUNCDESC_VAL: + if ((sym->st_info & 0xf) == STT_SECTION) + *reloc_addr += sym_val; + else + *reloc_addr = sym_val; + reloc_addr[1] = def.sym ? (size_t)def.dso->got : 0; + break; + case REL_DTPMOD: + *reloc_addr = def.dso->tls_id; + break; + case REL_DTPOFF: + *reloc_addr = tls_val + addend - DTP_OFFSET; + break; +#ifdef TLS_ABOVE_TP + case REL_TPOFF: + *reloc_addr = tls_val + def.dso->tls.offset + TPOFF_K + addend; + break; +#else + case REL_TPOFF: + *reloc_addr = tls_val - def.dso->tls.offset + addend; + break; + case REL_TPOFF_NEG: + *reloc_addr = def.dso->tls.offset - tls_val + addend; + break; +#endif + case REL_TLSDESC: + if (stride < 3) addend = reloc_addr[1]; + if (runtime && def.dso->tls_id >= static_tls_cnt) { + struct td_index* new = malloc(sizeof *new); + if (!new) { + error("Error relocating %s: cannot allocate TLSDESC for %s", dso->name, + sym ? name : "(local)"); + longjmp(*rtld_fail, 1); + } + new->next = dso->td_index; + dso->td_index = new; + new->args[0] = def.dso->tls_id; + new->args[1] = tls_val + addend; + reloc_addr[0] = (size_t)__tlsdesc_dynamic; + reloc_addr[1] = (size_t) new; + } else { + reloc_addr[0] = (size_t)__tlsdesc_static; +#ifdef TLS_ABOVE_TP + reloc_addr[1] = tls_val + def.dso->tls.offset + TPOFF_K + addend; +#else + reloc_addr[1] = tls_val - def.dso->tls.offset + addend; +#endif + } + break; + default: + error("Error relocating %s: unsupported relocation type %d", dso->name, type); + if (runtime) longjmp(*rtld_fail, 1); + continue; + } + } +} + +/* A huge hack: to make up for the wastefulness of shared libraries + * needing at least a page of dirty memory even if they have no global + * data, we reclaim the gaps at the beginning and end of writable maps + * and "donate" them to the heap by setting up minimal malloc + * structures and then freeing them. */ + +static void reclaim(struct dso* dso, size_t start, size_t end) { + size_t *a, *z; + if (start >= dso->relro_start && start < dso->relro_end) start = dso->relro_end; + if (end >= dso->relro_start && end < dso->relro_end) end = dso->relro_start; + start = start + 6 * sizeof(size_t) - 1 & -4 * sizeof(size_t); + end = (end & -4 * sizeof(size_t)) - 2 * sizeof(size_t); + if (start > end || end - start < 4 * sizeof(size_t)) return; + a = laddr(dso, start); + z = laddr(dso, end); + a[-2] = 1; + a[-1] = z[0] = end - start + 2 * sizeof(size_t) | 1; + z[1] = 1; + free(a); +} + +static void reclaim_gaps(struct dso* dso) { + Phdr* ph = dso->phdr; + size_t phcnt = dso->phnum; + + if (DL_FDPIC) return; // FIXME + for (; phcnt--; ph = (void*)((char*)ph + dso->phentsize)) { + if (ph->p_type != PT_LOAD) continue; + if ((ph->p_flags & (PF_R | PF_W)) != (PF_R | PF_W)) continue; + reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr); + reclaim(dso, ph->p_vaddr + ph->p_memsz, + ph->p_vaddr + ph->p_memsz + PAGE_SIZE - 1 & -PAGE_SIZE); + } +} + +static void* mmap_fixed(void* p, size_t n, int prot, int flags, int fd, off_t off) { + static int no_map_fixed; + char* q; + if (!no_map_fixed) { + q = mmap(p, n, prot, flags | MAP_FIXED, fd, off); + if (!DL_NOMMU_SUPPORT || q != MAP_FAILED || errno != EINVAL) return q; + no_map_fixed = 1; + } + /* Fallbacks for MAP_FIXED failure on NOMMU kernels. */ + if (flags & MAP_ANONYMOUS) { + memset(p, 0, n); + return p; + } + ssize_t r; + if (lseek(fd, off, SEEK_SET) < 0) return MAP_FAILED; + for (q = p; n; q += r, off += r, n -= r) { + r = read(fd, q, n); + if (r < 0 && errno != EINTR) return MAP_FAILED; + if (!r) { + memset(q, 0, n); + break; + } + } + return p; +} + +static void unmap_library(struct dso* dso) { + if (dso->loadmap) { + size_t i; + for (i = 0; i < dso->loadmap->nsegs; i++) { + if (!dso->loadmap->segs[i].p_memsz) continue; + munmap((void*)dso->loadmap->segs[i].addr, dso->loadmap->segs[i].p_memsz); + } + free(dso->loadmap); + } else if (dso->map && dso->map_len) { + munmap(dso->map, dso->map_len); + } +} + +static void* map_library(int fd, struct dso* dso) { + Ehdr buf[(896 + sizeof(Ehdr)) / sizeof(Ehdr)]; + void* allocated_buf = 0; + size_t phsize; + size_t addr_min = SIZE_MAX, addr_max = 0, map_len; + size_t this_min, this_max; + size_t nsegs = 0; + off_t off_start; + Ehdr* eh; + Phdr *ph, *ph0; + unsigned prot; + unsigned char *map = MAP_FAILED, *base; + size_t dyn = 0; + size_t tls_image = 0; + size_t i; + + ssize_t l = read(fd, buf, sizeof buf); + eh = buf; + if (l < 0) return 0; + if (l < sizeof *eh || (eh->e_type != ET_DYN && eh->e_type != ET_EXEC)) goto noexec; + phsize = eh->e_phentsize * eh->e_phnum; + if (phsize > sizeof buf - sizeof *eh) { + allocated_buf = malloc(phsize); + if (!allocated_buf) return 0; + l = pread(fd, allocated_buf, phsize, eh->e_phoff); + if (l < 0) goto error; + if (l != phsize) goto noexec; + ph = ph0 = allocated_buf; + } else if (eh->e_phoff + phsize > l) { + l = pread(fd, buf + 1, phsize, eh->e_phoff); + if (l < 0) goto error; + if (l != phsize) goto noexec; + ph = ph0 = (void*)(buf + 1); + } else { + ph = ph0 = (void*)((char*)buf + eh->e_phoff); + } + for (i = eh->e_phnum; i; i--, ph = (void*)((char*)ph + eh->e_phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + dyn = ph->p_vaddr; + } else if (ph->p_type == PT_TLS) { + tls_image = ph->p_vaddr; + dso->tls.align = ph->p_align; + dso->tls.len = ph->p_filesz; + dso->tls.size = ph->p_memsz; + } else if (ph->p_type == PT_GNU_RELRO) { + dso->relro_start = ph->p_vaddr & -PAGE_SIZE; + dso->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; + } + if (ph->p_type != PT_LOAD) continue; + nsegs++; + if (ph->p_vaddr < addr_min) { + addr_min = ph->p_vaddr; + off_start = ph->p_offset; + prot = + (((ph->p_flags & PF_R) ? PROT_READ : 0) | ((ph->p_flags & PF_W) ? PROT_WRITE : 0) | + ((ph->p_flags & PF_X) ? PROT_EXEC : 0)); + } + if (ph->p_vaddr + ph->p_memsz > addr_max) { + addr_max = ph->p_vaddr + ph->p_memsz; + } + } + if (!dyn) goto noexec; + if (DL_FDPIC && !(eh->e_flags & FDPIC_CONSTDISP_FLAG)) { + dso->loadmap = calloc(1, sizeof *dso->loadmap + nsegs * sizeof *dso->loadmap->segs); + if (!dso->loadmap) goto error; + dso->loadmap->nsegs = nsegs; + for (ph = ph0, i = 0; i < nsegs; ph = (void*)((char*)ph + eh->e_phentsize)) { + if (ph->p_type != PT_LOAD) continue; + prot = + (((ph->p_flags & PF_R) ? PROT_READ : 0) | ((ph->p_flags & PF_W) ? PROT_WRITE : 0) | + ((ph->p_flags & PF_X) ? PROT_EXEC : 0)); + map = mmap(0, ph->p_memsz + (ph->p_vaddr & PAGE_SIZE - 1), prot, MAP_PRIVATE, fd, + ph->p_offset & -PAGE_SIZE); + if (map == MAP_FAILED) { + unmap_library(dso); + goto error; + } + dso->loadmap->segs[i].addr = (size_t)map + (ph->p_vaddr & PAGE_SIZE - 1); + dso->loadmap->segs[i].p_vaddr = ph->p_vaddr; + dso->loadmap->segs[i].p_memsz = ph->p_memsz; + i++; + if (prot & PROT_WRITE) { + size_t brk = (ph->p_vaddr & PAGE_SIZE - 1) + ph->p_filesz; + size_t pgbrk = brk + PAGE_SIZE - 1 & -PAGE_SIZE; + size_t pgend = brk + ph->p_memsz - ph->p_filesz + PAGE_SIZE - 1 & -PAGE_SIZE; + if (pgend > pgbrk && + mmap_fixed(map + pgbrk, pgend - pgbrk, prot, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, + off_start) == MAP_FAILED) + goto error; + memset(map + brk, 0, pgbrk - brk); + } + } + map = (void*)dso->loadmap->segs[0].addr; + map_len = 0; + goto done_mapping; + } + addr_max += PAGE_SIZE - 1; + addr_max &= -PAGE_SIZE; + addr_min &= -PAGE_SIZE; + off_start &= -PAGE_SIZE; + map_len = addr_max - addr_min + off_start; + /* The first time, we map too much, possibly even more than + * the length of the file. This is okay because we will not + * use the invalid part; we just need to reserve the right + * amount of virtual address space to map over later. */ + map = DL_NOMMU_SUPPORT ? mmap((void*)addr_min, map_len, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + : mmap((void*)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start); + if (map == MAP_FAILED) goto error; + dso->map = map; + dso->map_len = map_len; + /* If the loaded file is not relocatable and the requested address is + * not available, then the load operation must fail. */ + if (eh->e_type != ET_DYN && addr_min && map != (void*)addr_min) { + errno = EBUSY; + goto error; + } + base = map - addr_min; + dso->phdr = 0; + dso->phnum = 0; + for (ph = ph0, i = eh->e_phnum; i; i--, ph = (void*)((char*)ph + eh->e_phentsize)) { + if (ph->p_type != PT_LOAD) continue; + /* Check if the programs headers are in this load segment, and + * if so, record the address for use by dl_iterate_phdr. */ + if (!dso->phdr && eh->e_phoff >= ph->p_offset && + eh->e_phoff + phsize <= ph->p_offset + ph->p_filesz) { + dso->phdr = (void*)(base + ph->p_vaddr + (eh->e_phoff - ph->p_offset)); + dso->phnum = eh->e_phnum; + dso->phentsize = eh->e_phentsize; + } + /* Reuse the existing mapping for the lowest-address LOAD */ + if ((ph->p_vaddr & -PAGE_SIZE) == addr_min && !DL_NOMMU_SUPPORT) continue; + this_min = ph->p_vaddr & -PAGE_SIZE; + this_max = ph->p_vaddr + ph->p_memsz + PAGE_SIZE - 1 & -PAGE_SIZE; + off_start = ph->p_offset & -PAGE_SIZE; + prot = (((ph->p_flags & PF_R) ? PROT_READ : 0) | ((ph->p_flags & PF_W) ? PROT_WRITE : 0) | + ((ph->p_flags & PF_X) ? PROT_EXEC : 0)); + if (mmap_fixed(base + this_min, this_max - this_min, prot, MAP_PRIVATE | MAP_FIXED, fd, + off_start) == MAP_FAILED) + goto error; + if (ph->p_memsz > ph->p_filesz) { + size_t brk = (size_t)base + ph->p_vaddr + ph->p_filesz; + size_t pgbrk = brk + PAGE_SIZE - 1 & -PAGE_SIZE; + memset((void*)brk, 0, pgbrk - brk & PAGE_SIZE - 1); + if (pgbrk - (size_t)base < this_max && + mmap_fixed((void*)pgbrk, (size_t)base + this_max - pgbrk, prot, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) + goto error; + } + } + for (i = 0; ((size_t*)(base + dyn))[i]; i += 2) + if (((size_t*)(base + dyn))[i] == DT_TEXTREL) { + if (mprotect(map, map_len, PROT_READ | PROT_WRITE | PROT_EXEC) && errno != ENOSYS) + goto error; + break; + } +done_mapping: + dso->base = base; + dso->dynv = laddr(dso, dyn); + if (dso->tls.size) dso->tls.image = laddr(dso, tls_image); + if (!runtime) reclaim_gaps(dso); + free(allocated_buf); + return map; +noexec: + errno = ENOEXEC; +error: + if (map != MAP_FAILED) unmap_library(dso); + free(allocated_buf); + return 0; +} + +static int path_open(const char* name, const char* s, char* buf, size_t buf_size) { + size_t l; + int fd; + for (;;) { + s += strspn(s, ":\n"); + l = strcspn(s, ":\n"); + if (l - 1 >= INT_MAX) return -1; + if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) { + if ((fd = open(buf, O_RDONLY | O_CLOEXEC)) >= 0) return fd; + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + case ENAMETOOLONG: + break; + default: + /* Any negative value but -1 will inhibit + * futher path search. */ + return -2; + } + } + s += l; + } +} + +static int fixup_rpath(struct dso* p, char* buf, size_t buf_size) { + size_t n, l; + const char *s, *t, *origin; + char* d; + if (p->rpath || !p->rpath_orig) return 0; + if (!strchr(p->rpath_orig, '$')) { + p->rpath = p->rpath_orig; + return 0; + } + n = 0; + s = p->rpath_orig; + while ((t = strchr(s, '$'))) { + if (strncmp(t, "$ORIGIN", 7) && strncmp(t, "${ORIGIN}", 9)) return 0; + s = t + 1; + n++; + } + if (n > SSIZE_MAX / PATH_MAX) return 0; + + if (p->kernel_mapped) { + /* $ORIGIN searches cannot be performed for the main program + * when it is suid/sgid/AT_SECURE. This is because the + * pathname is under the control of the caller of execve. + * For libraries, however, $ORIGIN can be processed safely + * since the library's pathname came from a trusted source + * (either system paths or a call to dlopen). */ + if (libc.secure) return 0; + l = readlink("/proc/self/exe", buf, buf_size); + if (l == -1) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + break; + default: + return -1; + } + if (l >= buf_size) return 0; + buf[l] = 0; + origin = buf; + } else { + origin = p->name; + } + t = strrchr(origin, '/'); + l = t ? t - origin : 0; + p->rpath = malloc(strlen(p->rpath_orig) + n * l + 1); + if (!p->rpath) return -1; + + d = p->rpath; + s = p->rpath_orig; + while ((t = strchr(s, '$'))) { + memcpy(d, s, t - s); + d += t - s; + memcpy(d, origin, l); + d += l; + /* It was determined previously that the '$' is followed + * either by "ORIGIN" or "{ORIGIN}". */ + s = t + 7 + 2 * (t[1] == '{'); + } + strcpy(d, s); + return 0; +} + +static void decode_dyn(struct dso* p) { + size_t dyn[DYN_CNT]; + decode_vec(p->dynv, dyn, DYN_CNT); + p->syms = laddr(p, dyn[DT_SYMTAB]); + p->strings = laddr(p, dyn[DT_STRTAB]); + if (dyn[0] & (1 << DT_HASH)) p->hashtab = laddr(p, dyn[DT_HASH]); + if (dyn[0] & (1 << DT_RPATH)) p->rpath_orig = p->strings + dyn[DT_RPATH]; + if (dyn[0] & (1 << DT_RUNPATH)) p->rpath_orig = p->strings + dyn[DT_RUNPATH]; + if (dyn[0] & (1 << DT_PLTGOT)) p->got = laddr(p, dyn[DT_PLTGOT]); + if (search_vec(p->dynv, dyn, DT_GNU_HASH)) p->ghashtab = laddr(p, *dyn); + if (search_vec(p->dynv, dyn, DT_VERSYM)) p->versym = laddr(p, *dyn); +} + +static size_t count_syms(struct dso* p) { + if (p->hashtab) return p->hashtab[1]; + + size_t nsym, i; + uint32_t* buckets = p->ghashtab + 4 + (p->ghashtab[2] * sizeof(size_t) / 4); + uint32_t* hashval; + for (i = nsym = 0; i < p->ghashtab[0]; i++) { + if (buckets[i] > nsym) nsym = buckets[i]; + } + if (nsym) { + hashval = buckets + p->ghashtab[0] + (nsym - p->ghashtab[1]); + do + nsym++; + while (!(*hashval++ & 1)); + } + return nsym; +} + +static void* dl_mmap(size_t n) { + void* p; + int prot = PROT_READ | PROT_WRITE, flags = MAP_ANONYMOUS | MAP_PRIVATE; +#ifdef SYS_mmap2 + p = (void*)__syscall(SYS_mmap2, 0, n, prot, flags, -1, 0); +#else + p = (void*)__syscall(SYS_mmap, 0, n, prot, flags, -1, 0); +#endif + return p == MAP_FAILED ? 0 : p; +} + +static void makefuncdescs(struct dso* p) { + static int self_done; + size_t nsym = count_syms(p); + size_t i, size = nsym * sizeof(*p->funcdescs); + + if (!self_done) { + p->funcdescs = dl_mmap(size); + self_done = 1; + } else { + p->funcdescs = malloc(size); + } + if (!p->funcdescs) { + if (!runtime) a_crash(); + error("Error allocating function descriptors for %s", p->name); + longjmp(*rtld_fail, 1); + } + for (i = 0; i < nsym; i++) { + if ((p->syms[i].st_info & 0xf) == STT_FUNC && p->syms[i].st_shndx) { + p->funcdescs[i].addr = laddr(p, p->syms[i].st_value); + p->funcdescs[i].got = p->got; + } else { + p->funcdescs[i].addr = 0; + p->funcdescs[i].got = 0; + } + } +} + +static struct dso* load_library(const char* name, struct dso* needed_by) { + char buf[2 * NAME_MAX + 2]; + const char* pathname; + unsigned char* map; + struct dso *p, temp_dso = {0}; + int fd; + struct stat st; + size_t alloc_size; + int n_th = 0; + int is_self = 0; + + if (!*name) { + errno = EINVAL; + return 0; + } + + /* Catch and block attempts to reload the implementation itself */ + if (name[0] == 'l' && name[1] == 'i' && name[2] == 'b') { + static const char *rp, reserved[] = "c\0pthread\0rt\0m\0dl\0util\0xnet\0"; + char* z = strchr(name, '.'); + if (z) { + size_t l = z - name; + for (rp = reserved; *rp && strncmp(name + 3, rp, l - 3); rp += strlen(rp) + 1) + ; + if (*rp) { + if (ldd_mode) { + /* Track which names have been resolved + * and only report each one once. */ + static unsigned reported; + unsigned mask = 1U << (rp - reserved); + if (!(reported & mask)) { + reported |= mask; + dprintf(1, "\t%s => %s (%p)\n", name, ldso.name, ldso.base); + } + } + is_self = 1; + } + } + } + if (!strcmp(name, ldso.name)) is_self = 1; + if (is_self) { + if (!ldso.prev) { + tail->next = &ldso; + ldso.prev = tail; + tail = ldso.next ? ldso.next : &ldso; + } + return &ldso; + } + if (strchr(name, '/')) { + pathname = name; + fd = open(name, O_RDONLY | O_CLOEXEC); + } else { + /* Search for the name to see if it's already loaded */ + for (p = head->next; p; p = p->next) { + if (p->shortname && !strcmp(p->shortname, name)) { + p->refcnt++; + return p; + } + } + if (strlen(name) > NAME_MAX) return 0; + fd = -1; + if (env_path) fd = path_open(name, env_path, buf, sizeof buf); + for (p = needed_by; fd == -1 && p; p = p->needed_by) { + if (fixup_rpath(p, buf, sizeof buf) < 0) fd = -2; /* Inhibit further search. */ + if (p->rpath) fd = path_open(name, p->rpath, buf, sizeof buf); + } + if (fd == -1) { + if (!sys_path) { + char* prefix = 0; + size_t prefix_len; + if (ldso.name[0] == '/') { + char *s, *t, *z; + for (s = t = z = ldso.name; *s; s++) + if (*s == '/') z = t, t = s; + prefix_len = z - ldso.name; + if (prefix_len < PATH_MAX) prefix = ldso.name; + } + if (!prefix) { + prefix = ""; + prefix_len = 0; + } + char etc_ldso_path[prefix_len + 1 + sizeof "/etc/ld-musl-" LDSO_ARCH ".path"]; + snprintf(etc_ldso_path, sizeof etc_ldso_path, "%.*s/etc/ld-musl-" LDSO_ARCH ".path", + (int)prefix_len, prefix); + FILE* f = fopen(etc_ldso_path, "rbe"); + if (f) { + if (getdelim(&sys_path, (size_t[1]){0}, 0, f) <= 0) { + free(sys_path); + sys_path = ""; + } + fclose(f); + } else if (errno != ENOENT) { + sys_path = ""; + } + } + if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib"; + fd = path_open(name, sys_path, buf, sizeof buf); + } + pathname = buf; + } + if (fd < 0) return 0; + if (fstat(fd, &st) < 0) { + close(fd); + return 0; + } + for (p = head->next; p; p = p->next) { + if (p->dev == st.st_dev && p->ino == st.st_ino) { + /* If this library was previously loaded with a + * pathname but a search found the same inode, + * setup its shortname so it can be found by name. */ + if (!p->shortname && pathname != name) p->shortname = strrchr(p->name, '/') + 1; + close(fd); + p->refcnt++; + return p; + } + } + map = noload ? 0 : map_library(fd, &temp_dso); + close(fd); + if (!map) return 0; + + /* Allocate storage for the new DSO. When there is TLS, this + * storage must include a reservation for all pre-existing + * threads to obtain copies of both the new TLS, and an + * extended DTV capable of storing an additional slot for + * the newly-loaded DSO. */ + alloc_size = sizeof *p + strlen(pathname) + 1; + if (runtime && temp_dso.tls.image) { + /* TODO(kulakowski) DSO TLS API */ + /* + size_t per_th = temp_dso.tls.size + temp_dso.tls.align + sizeof(void*) * (tls_cnt + 3); + n_th = libc.threads_minus_1 + 1; + if (n_th > SSIZE_MAX / per_th) + alloc_size = SIZE_MAX; + else + alloc_size += n_th * per_th; + */ + a_crash(); + } + p = calloc(1, alloc_size); + if (!p) { + unmap_library(&temp_dso); + return 0; + } + memcpy(p, &temp_dso, sizeof temp_dso); + decode_dyn(p); + p->dev = st.st_dev; + p->ino = st.st_ino; + p->refcnt = 1; + p->needed_by = needed_by; + p->name = p->buf; + strcpy(p->name, pathname); + /* Add a shortname only if name arg was not an explicit pathname. */ + if (pathname != name) p->shortname = strrchr(p->name, '/') + 1; + if (p->tls.image) { + p->tls_id = ++tls_cnt; + tls_align = MAXP2(tls_align, p->tls.align); +#ifdef TLS_ABOVE_TP + p->tls.offset = tls_offset + ((tls_align - 1) & -(tls_offset + (uintptr_t)p->tls.image)); + tls_offset += p->tls.size; +#else + tls_offset += p->tls.size + p->tls.align - 1; + tls_offset -= (tls_offset + (uintptr_t)p->tls.image) & (p->tls.align - 1); + p->tls.offset = tls_offset; +#endif + p->new_dtv = + (void*)(-sizeof(size_t) & (uintptr_t)(p->name + strlen(p->name) + sizeof(size_t))); + p->new_tls = (void*)(p->new_dtv + n_th * (tls_cnt + 1)); + if (tls_tail) + tls_tail->next = &p->tls; + else + libc.tls_head = &p->tls; + tls_tail = &p->tls; + } + + tail->next = p; + p->prev = tail; + tail = p; + + if (DL_FDPIC) makefuncdescs(p); + + if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, pathname, p->base); + + return p; +} + +static void load_deps(struct dso* p) { + size_t i, ndeps = 0; + struct dso ***deps = &p->deps, **tmp, *dep; + for (; p; p = p->next) { + for (i = 0; p->dynv[i]; i += 2) { + if (p->dynv[i] != DT_NEEDED) continue; + dep = load_library(p->strings + p->dynv[i + 1], p); + if (!dep) { + error("Error loading shared library %s: %m (needed by %s)", + p->strings + p->dynv[i + 1], p->name); + if (runtime) longjmp(*rtld_fail, 1); + continue; + } + if (runtime) { + tmp = realloc(*deps, sizeof(*tmp) * (ndeps + 2)); + if (!tmp) longjmp(*rtld_fail, 1); + tmp[ndeps++] = dep; + tmp[ndeps] = 0; + *deps = tmp; + } + } + } +} + +static void load_preload(char* s) { + int tmp; + char* z; + for (z = s; *z; s = z) { + for (; *s && (isspace(*s) || *s == ':'); s++) + ; + for (z = s; *z && !isspace(*z) && *z != ':'; z++) + ; + tmp = *z; + *z = 0; + load_library(s, 0); + *z = tmp; + } +} + +static void make_global(struct dso* p) { + for (; p; p = p->next) + p->global = 1; +} + +static void do_mips_relocs(struct dso* p, size_t* got) { + size_t i, j, rel[2]; + unsigned char* base = p->base; + i = 0; + search_vec(p->dynv, &i, DT_MIPS_LOCAL_GOTNO); + if (p == &ldso) { + got += i; + } else { + while (i--) + *got++ += (size_t)base; + } + j = 0; + search_vec(p->dynv, &j, DT_MIPS_GOTSYM); + i = 0; + search_vec(p->dynv, &i, DT_MIPS_SYMTABNO); + Sym* sym = p->syms + j; + rel[0] = (unsigned char*)got - base; + for (i -= j; i; i--, sym++, rel[0] += sizeof(size_t)) { + rel[1] = R_INFO(sym - p->syms, R_MIPS_JUMP_SLOT); + do_relocs(p, rel, sizeof rel, 2); + } +} + +static void reloc_all(struct dso* p) { + size_t dyn[DYN_CNT]; + for (; p; p = p->next) { + if (p->relocated) continue; + decode_vec(p->dynv, dyn, DYN_CNT); + if (NEED_MIPS_GOT_RELOCS) do_mips_relocs(p, laddr(p, dyn[DT_PLTGOT])); + do_relocs(p, laddr(p, dyn[DT_JMPREL]), dyn[DT_PLTRELSZ], 2 + (dyn[DT_PLTREL] == DT_RELA)); + do_relocs(p, laddr(p, dyn[DT_REL]), dyn[DT_RELSZ], 2); + do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3); + + if (head != &ldso && p->relro_start != p->relro_end && + mprotect(laddr(p, p->relro_start), p->relro_end - p->relro_start, PROT_READ) && + errno != ENOSYS) { + error("Error relocating %s: RELRO protection failed: %m", p->name); + if (runtime) longjmp(*rtld_fail, 1); + } + + p->relocated = 1; + } +} + +static void kernel_mapped_dso(struct dso* p) { + size_t min_addr = -1, max_addr = 0, cnt; + Phdr* ph = p->phdr; + for (cnt = p->phnum; cnt--; ph = (void*)((char*)ph + p->phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + p->dynv = laddr(p, ph->p_vaddr); + } else if (ph->p_type == PT_GNU_RELRO) { + p->relro_start = ph->p_vaddr & -PAGE_SIZE; + p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; + } + if (ph->p_type != PT_LOAD) continue; + if (ph->p_vaddr < min_addr) min_addr = ph->p_vaddr; + if (ph->p_vaddr + ph->p_memsz > max_addr) max_addr = ph->p_vaddr + ph->p_memsz; + } + min_addr &= -PAGE_SIZE; + max_addr = (max_addr + PAGE_SIZE - 1) & -PAGE_SIZE; + p->map = p->base + min_addr; + p->map_len = max_addr - min_addr; + p->kernel_mapped = 1; +} + +void __libc_exit_fini(void) { + struct dso* p; + size_t dyn[DYN_CNT]; + for (p = fini_head; p; p = p->fini_next) { + if (!p->constructed) continue; + decode_vec(p->dynv, dyn, DYN_CNT); + if (dyn[0] & (1 << DT_FINI_ARRAY)) { + size_t n = dyn[DT_FINI_ARRAYSZ] / sizeof(size_t); + size_t* fn = (size_t*)laddr(p, dyn[DT_FINI_ARRAY]) + n; + while (n--) + ((void (*)(void)) * --fn)(); + } +#ifndef NO_LEGACY_INITFINI + if ((dyn[0] & (1 << DT_FINI)) && dyn[DT_FINI]) fpaddr(p, dyn[DT_FINI])(); +#endif + } +} + +static void do_init_fini(struct dso* p) { + size_t dyn[DYN_CNT]; + /* Allow recursive calls that arise when a library calls + * dlopen from one of its constructors, but block any + * other threads until all ctors have finished. */ + pthread_mutex_lock(&init_fini_lock); + for (; p; p = p->prev) { + if (p->constructed) continue; + p->constructed = 1; + decode_vec(p->dynv, dyn, DYN_CNT); + if (dyn[0] & ((1 << DT_FINI) | (1 << DT_FINI_ARRAY))) { + p->fini_next = fini_head; + fini_head = p; + } +#ifndef NO_LEGACY_INITFINI + if ((dyn[0] & (1 << DT_INIT)) && dyn[DT_INIT]) fpaddr(p, dyn[DT_INIT])(); +#endif + if (dyn[0] & (1 << DT_INIT_ARRAY)) { + size_t n = dyn[DT_INIT_ARRAYSZ] / sizeof(size_t); + size_t* fn = laddr(p, dyn[DT_INIT_ARRAY]); + while (n--) + ((void (*)(void)) * fn++)(); + } + } + pthread_mutex_unlock(&init_fini_lock); +} + +void __libc_start_init(void) { + do_init_fini(tail); +} + +static void dl_debug_state(void) {} + +weak_alias(dl_debug_state, _dl_debug_state); + +void __init_tls(size_t* auxv) {} + +__attribute__((__visibility__("hidden"))) void* __tls_get_new(size_t* v) { + pthread_t self = __pthread_self(); + + /* Block signals to make accessing new TLS async-signal-safe */ + sigset_t set; + __block_all_sigs(&set); + if (v[0] <= (size_t)self->dtv[0]) { + __restore_sigs(&set); + return (char*)self->dtv[v[0]] + v[1] + DTP_OFFSET; + } + + /* This is safe without any locks held because, if the caller + * is able to request the Nth entry of the DTV, the DSO list + * must be valid at least that far out and it was synchronized + * at program startup or by an already-completed call to dlopen. */ + struct dso* p; + for (p = head; p->tls_id != v[0]; p = p->next) + ; + + /* Get new DTV space from new DSO if needed */ + if (v[0] > (size_t)self->dtv[0]) { + void** newdtv = p->new_dtv + (v[0] + 1) * a_fetch_add(&p->new_dtv_idx, 1); + memcpy(newdtv, self->dtv, ((size_t)self->dtv[0] + 1) * sizeof(void*)); + newdtv[0] = (void*)v[0]; + self->dtv = self->dtv_copy = newdtv; + } + + /* Get new TLS memory from all new DSOs up to the requested one */ + unsigned char* mem; + for (p = head;; p = p->next) { + if (!p->tls_id || self->dtv[p->tls_id]) continue; + mem = p->new_tls + (p->tls.size + p->tls.align) * a_fetch_add(&p->new_tls_idx, 1); + mem += ((uintptr_t)p->tls.image - (uintptr_t)mem) & (p->tls.align - 1); + self->dtv[p->tls_id] = mem; + memcpy(mem, p->tls.image, p->tls.len); + if (p->tls_id == v[0]) break; + } + __restore_sigs(&set); + return mem + v[1] + DTP_OFFSET; +} + +static void update_tls_size(void) { + libc.tls_cnt = tls_cnt; + libc.tls_align = tls_align; + libc.tls_size = + ALIGN((1 + tls_cnt) * sizeof(void*) + tls_offset + sizeof(struct pthread) + tls_align * 2, + tls_align); +} + +/* Stage 1 of the dynamic linker is defined in dlstart.c. It calls the + * following stage 2 and stage 3 functions via primitive symbolic lookup + * since it does not have access to their addresses to begin with. */ + +/* Stage 2 of the dynamic linker is called after relative relocations + * have been processed. It can make function calls to static functions + * and access string literals and static data, but cannot use extern + * symbols. Its job is to perform symbolic relocations on the dynamic + * linker itself, but some of the relocations performed may need to be + * replaced later due to copy relocations in the main program. */ + +__attribute__((__visibility__("hidden"))) void __dls2(unsigned char* base, size_t* sp) { + if (DL_FDPIC) { + void* p1 = (void*)sp[-2]; + void* p2 = (void*)sp[-1]; + if (!p1) { + size_t *auxv, aux[AUX_CNT]; + for (auxv = sp + 1 + *sp + 1; *auxv; auxv++) + ; + auxv++; + decode_vec(auxv, aux, AUX_CNT); + if (aux[AT_BASE]) + ldso.base = (void*)aux[AT_BASE]; + else + ldso.base = (void*)(aux[AT_PHDR] & -4096); + } + app_loadmap = p2 ? p1 : 0; + ldso.loadmap = p2 ? p2 : p1; + ldso.base = laddr(&ldso, 0); + } else { + ldso.base = base; + } + Ehdr* ehdr = (void*)ldso.base; + ldso.name = ldso.shortname = "libc.so"; + ldso.global = 1; + ldso.phnum = ehdr->e_phnum; + ldso.phdr = laddr(&ldso, ehdr->e_phoff); + ldso.phentsize = ehdr->e_phentsize; + kernel_mapped_dso(&ldso); + decode_dyn(&ldso); + + if (DL_FDPIC) makefuncdescs(&ldso); + + /* Prepare storage for to save clobbered REL addends so they + * can be reused in stage 3. There should be very few. If + * something goes wrong and there are a huge number, abort + * instead of risking stack overflow. */ + size_t dyn[DYN_CNT]; + decode_vec(ldso.dynv, dyn, DYN_CNT); + size_t* rel = laddr(&ldso, dyn[DT_REL]); + size_t rel_size = dyn[DT_RELSZ]; + size_t symbolic_rel_cnt = 0; + apply_addends_to = rel; + for (; rel_size; rel += 2, rel_size -= 2 * sizeof(size_t)) + if (!IS_RELATIVE(rel[1], ldso.syms)) symbolic_rel_cnt++; + if (symbolic_rel_cnt >= ADDEND_LIMIT) a_crash(); + size_t addends[symbolic_rel_cnt + 1]; + saved_addends = addends; + + head = &ldso; + reloc_all(&ldso); + + ldso.relocated = 0; + + /* Call dynamic linker stage-3, __dls3, looking it up + * symbolically as a barrier against moving the address + * load across the above relocation processing. */ + struct symdef dls3_def = find_sym(&ldso, "__dls3", 0); + if (DL_FDPIC) + ((stage3_func)&ldso.funcdescs[dls3_def.sym - ldso.syms])(sp); + else + ((stage3_func)laddr(&ldso, dls3_def.sym->st_value))(sp); +} + +/* Stage 3 of the dynamic linker is called with the dynamic linker/libc + * fully functional. Its job is to load (if not already loaded) and + * process dependencies and relocations for the main application and + * transfer control to its entry point. */ + +_Noreturn void __dls3(size_t* sp) { + static struct dso app, vdso; + size_t aux[AUX_CNT], *auxv; + size_t i; + char* env_preload = 0; + size_t vdso_base; + int argc = *sp; + char** argv = (void*)(sp + 1); + char** argv_orig = argv; + char** envp = argv + argc + 1; + + /* Find aux vector just past environ[] and use it to initialize + * global data that may be needed before we can make syscalls. */ + __environ = envp; + for (i = argc + 1; argv[i]; i++) + ; + libc.auxv = auxv = (void*)(argv + i + 1); + decode_vec(auxv, aux, AUX_CNT); + __hwcap = aux[AT_HWCAP]; + libc.page_size = aux[AT_PAGESZ]; + libc.secure = ((aux[0] & 0x7800) != 0x7800 || aux[AT_UID] != aux[AT_EUID] || + aux[AT_GID] != aux[AT_EGID] || aux[AT_SECURE]); + + /* Setup early thread pointer in builtin_tls for ldso/libc itself to + * use during dynamic linking. If possible it will also serve as the + * thread pointer at runtime. */ + libc.tls_size = sizeof builtin_tls; + libc.tls_align = tls_align; + if (__init_tp(__copy_tls((void*)builtin_tls)) < 0) { + a_crash(); + } + + /* Only trust user/env if kernel says we're not suid/sgid */ + if (!libc.secure) { + env_path = getenv("LD_LIBRARY_PATH"); + env_preload = getenv("LD_PRELOAD"); + } + + /* If the main program was already loaded by the kernel, + * AT_PHDR will point to some location other than the dynamic + * linker's program headers. */ + if (aux[AT_PHDR] != (size_t)ldso.phdr) { + size_t interp_off = 0; + size_t tls_image = 0; + /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */ + Phdr* phdr = app.phdr = (void*)aux[AT_PHDR]; + app.phnum = aux[AT_PHNUM]; + app.phentsize = aux[AT_PHENT]; + for (i = aux[AT_PHNUM]; i; i--, phdr = (void*)((char*)phdr + aux[AT_PHENT])) { + if (phdr->p_type == PT_PHDR) + app.base = (void*)(aux[AT_PHDR] - phdr->p_vaddr); + else if (phdr->p_type == PT_INTERP) + interp_off = (size_t)phdr->p_vaddr; + else if (phdr->p_type == PT_TLS) { + tls_image = phdr->p_vaddr; + app.tls.len = phdr->p_filesz; + app.tls.size = phdr->p_memsz; + app.tls.align = phdr->p_align; + } + } + if (DL_FDPIC) app.loadmap = app_loadmap; + if (app.tls.size) app.tls.image = laddr(&app, tls_image); + if (interp_off) ldso.name = laddr(&app, interp_off); + if ((aux[0] & (1UL << AT_EXECFN)) && strncmp((char*)aux[AT_EXECFN], "/proc/", 6)) + app.name = (char*)aux[AT_EXECFN]; + else + app.name = argv[0]; + kernel_mapped_dso(&app); + } else { + int fd; + char* ldname = argv[0]; + size_t l = strlen(ldname); + if (l >= 3 && !strcmp(ldname + l - 3, "ldd")) ldd_mode = 1; + argv++; + while (argv[0] && argv[0][0] == '-' && argv[0][1] == '-') { + char* opt = argv[0] + 2; + *argv++ = (void*)-1; + if (!*opt) { + break; + } else if (!memcmp(opt, "list", 5)) { + ldd_mode = 1; + } else if (!memcmp(opt, "library-path", 12)) { + if (opt[12] == '=') + env_path = opt + 13; + else if (opt[12]) + *argv = 0; + else if (*argv) + env_path = *argv++; + } else if (!memcmp(opt, "preload", 7)) { + if (opt[7] == '=') + env_preload = opt + 8; + else if (opt[7]) + *argv = 0; + else if (*argv) + env_preload = *argv++; + } else { + argv[0] = 0; + } + } + argv[-1] = (void*)(argc - (argv - argv_orig)); + if (!argv[0]) { + dprintf(2, "musl libc (" LDSO_ARCH ")\n" + "Dynamic Program Loader\n" + "Usage: %s [options] [--] pathname%s\n", + ldname, ldd_mode ? "" : " [args]"); + _exit(1); + } + fd = open(argv[0], O_RDONLY); + if (fd < 0) { + dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno)); + _exit(1); + } + runtime = 1; + Ehdr* ehdr = (void*)map_library(fd, &app); + if (!ehdr) { + dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]); + _exit(1); + } + runtime = 0; + close(fd); + ldso.name = ldname; + app.name = argv[0]; + aux[AT_ENTRY] = (size_t)laddr(&app, ehdr->e_entry); + /* Find the name that would have been used for the dynamic + * linker had ldd not taken its place. */ + if (ldd_mode) { + for (i = 0; i < app.phnum; i++) { + if (app.phdr[i].p_type == PT_INTERP) ldso.name = laddr(&app, app.phdr[i].p_vaddr); + } + dprintf(1, "\t%s (%p)\n", ldso.name, ldso.base); + } + } + if (app.tls.size) { + libc.tls_head = tls_tail = &app.tls; + app.tls_id = tls_cnt = 1; +#ifdef TLS_ABOVE_TP + app.tls.offset = 0; + tls_offset = + app.tls.size + (-((uintptr_t)app.tls.image + app.tls.size) & (app.tls.align - 1)); +#else + tls_offset = app.tls.offset = + app.tls.size + (-((uintptr_t)app.tls.image + app.tls.size) & (app.tls.align - 1)); +#endif + tls_align = MAXP2(tls_align, app.tls.align); + } + app.global = 1; + decode_dyn(&app); + if (DL_FDPIC) { + makefuncdescs(&app); + if (!app.loadmap) { + app.loadmap = (void*)&app_dummy_loadmap; + app.loadmap->nsegs = 1; + app.loadmap->segs[0].addr = (size_t)app.map; + app.loadmap->segs[0].p_vaddr = (size_t)app.map - (size_t)app.base; + app.loadmap->segs[0].p_memsz = app.map_len; + } + argv[-3] = (void*)app.loadmap; + } + + /* Attach to vdso, if provided by the kernel */ + if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR)) { + Ehdr* ehdr = (void*)vdso_base; + Phdr* phdr = vdso.phdr = (void*)(vdso_base + ehdr->e_phoff); + vdso.phnum = ehdr->e_phnum; + vdso.phentsize = ehdr->e_phentsize; + for (i = ehdr->e_phnum; i; i--, phdr = (void*)((char*)phdr + ehdr->e_phentsize)) { + if (phdr->p_type == PT_DYNAMIC) vdso.dynv = (void*)(vdso_base + phdr->p_offset); + if (phdr->p_type == PT_LOAD) + vdso.base = (void*)(vdso_base - phdr->p_vaddr + phdr->p_offset); + } + vdso.name = ""; + vdso.shortname = "linux-gate.so.1"; + vdso.global = 1; + vdso.relocated = 1; + decode_dyn(&vdso); + vdso.prev = &ldso; + ldso.next = &vdso; + } + + /* Initial dso chain consists only of the app. */ + head = tail = &app; + + /* Donate unused parts of app and library mapping to malloc */ + reclaim_gaps(&app); + reclaim_gaps(&ldso); + + /* Load preload/needed libraries, add their symbols to the global + * namespace, and perform all remaining relocations. */ + if (env_preload) load_preload(env_preload); + load_deps(&app); + make_global(&app); + + for (i = 0; app.dynv[i]; i += 2) { + if (!DT_DEBUG_INDIRECT && app.dynv[i] == DT_DEBUG) app.dynv[i + 1] = (size_t)&debug; + if (DT_DEBUG_INDIRECT && app.dynv[i] == DT_DEBUG_INDIRECT) { + size_t* ptr = (size_t*)app.dynv[i + 1]; + *ptr = (size_t)&debug; + } + } + + /* The main program must be relocated LAST since it may contin + * copy relocations which depend on libraries' relocations. */ + reloc_all(app.next); + reloc_all(&app); + + update_tls_size(); + if (libc.tls_size > sizeof builtin_tls || tls_align > MIN_TLS_ALIGN) { + void* initial_tls = calloc(libc.tls_size, 1); + if (!initial_tls) { + dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n", argv[0], + libc.tls_size); + _exit(127); + } + if (__init_tp(__copy_tls(initial_tls)) < 0) { + a_crash(); + } + } else { + size_t tmp_tls_size = libc.tls_size; + pthread_t self = __pthread_self(); + /* Temporarily set the tls size to the full size of + * builtin_tls so that __copy_tls will use the same layout + * as it did for before. Then check, just to be safe. */ + libc.tls_size = sizeof builtin_tls; + if (__copy_tls((void*)builtin_tls) != self) a_crash(); + libc.tls_size = tmp_tls_size; + } + static_tls_cnt = tls_cnt; + + if (ldso_fail) _exit(127); + if (ldd_mode) _exit(0); + + /* Switch to runtime mode: any further failures in the dynamic + * linker are a reportable failure rather than a fatal startup + * error. */ + runtime = 1; + + debug.ver = 1; + debug.bp = dl_debug_state; + debug.head = head; + debug.base = ldso.base; + debug.state = 0; + _dl_debug_state(); + + errno = 0; + + CRTJMP((void*)aux[AT_ENTRY], argv - 1); + for (;;) + ; +} + +void* dlopen(const char* file, int mode) { + struct dso* volatile p, *orig_tail, *next; + struct tls_module* orig_tls_tail; + size_t orig_tls_cnt, orig_tls_offset, orig_tls_align; + size_t i; + int cs; + jmp_buf jb; + + if (!file) return head; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + pthread_rwlock_wrlock(&lock); + __inhibit_ptc(); + + p = 0; + orig_tls_tail = tls_tail; + orig_tls_cnt = tls_cnt; + orig_tls_offset = tls_offset; + orig_tls_align = tls_align; + orig_tail = tail; + noload = mode & RTLD_NOLOAD; + + rtld_fail = &jb; + if (setjmp(*rtld_fail)) { + /* Clean up anything new that was (partially) loaded */ + if (p && p->deps) + for (i = 0; p->deps[i]; i++) + if (p->deps[i]->global < 0) p->deps[i]->global = 0; + for (p = orig_tail->next; p; p = next) { + next = p->next; + while (p->td_index) { + void* tmp = p->td_index->next; + free(p->td_index); + p->td_index = tmp; + } + free(p->funcdescs); + if (p->rpath != p->rpath_orig) free(p->rpath); + free(p->deps); + unmap_library(p); + free(p); + } + if (!orig_tls_tail) libc.tls_head = 0; + tls_tail = orig_tls_tail; + tls_cnt = orig_tls_cnt; + tls_offset = orig_tls_offset; + tls_align = orig_tls_align; + tail = orig_tail; + tail->next = 0; + p = 0; + goto end; + } else + p = load_library(file, head); + + if (!p) { + error(noload ? "Library %s is not already loaded" : "Error loading shared library %s: %m", + file); + goto end; + } + + /* First load handling */ + if (!p->deps) { + load_deps(p); + if (p->deps) + for (i = 0; p->deps[i]; i++) + if (!p->deps[i]->global) p->deps[i]->global = -1; + if (!p->global) p->global = -1; + reloc_all(p); + if (p->deps) + for (i = 0; p->deps[i]; i++) + if (p->deps[i]->global < 0) p->deps[i]->global = 0; + if (p->global < 0) p->global = 0; + } + + if (mode & RTLD_GLOBAL) { + if (p->deps) + for (i = 0; p->deps[i]; i++) + p->deps[i]->global = 1; + p->global = 1; + } + + update_tls_size(); + _dl_debug_state(); + orig_tail = tail; +end: + __release_ptc(); + if (p) gencnt++; + pthread_rwlock_unlock(&lock); + if (p) do_init_fini(orig_tail); + pthread_setcancelstate(cs, 0); + return p; +} + +__attribute__((__visibility__("hidden"))) int __dl_invalid_handle(void* h) { + struct dso* p; + for (p = head; p; p = p->next) + if (h == p) return 0; + error("Invalid library handle %p", (void*)h); + return 1; +} + +static void* addr2dso(size_t a) { + struct dso* p; + size_t i; + if (DL_FDPIC) + for (p = head; p; p = p->next) { + i = count_syms(p); + if (a - (size_t)p->funcdescs < i * sizeof(*p->funcdescs)) return p; + } + for (p = head; p; p = p->next) { + if (DL_FDPIC && p->loadmap) { + for (i = 0; i < p->loadmap->nsegs; i++) { + if (a - p->loadmap->segs[i].p_vaddr < p->loadmap->segs[i].p_memsz) return p; + } + } else { + if (a - (size_t)p->map < p->map_len) return p; + } + } + return 0; +} + +void* __tls_get_addr(size_t*); + +static void* do_dlsym(struct dso* p, const char* s, void* ra) { + size_t i; + uint32_t h = 0, gh = 0, *ght; + Sym* sym; + if (p == head || p == RTLD_DEFAULT || p == RTLD_NEXT) { + if (p == RTLD_DEFAULT) { + p = head; + } else if (p == RTLD_NEXT) { + p = addr2dso((size_t)ra); + if (!p) p = head; + p = p->next; + } + struct symdef def = find_sym(p, s, 0); + if (!def.sym) goto failed; + if ((def.sym->st_info & 0xf) == STT_TLS) + return __tls_get_addr((size_t[]){def.dso->tls_id, def.sym->st_value}); + if (DL_FDPIC && (def.sym->st_info & 0xf) == STT_FUNC) + return def.dso->funcdescs + (def.sym - def.dso->syms); + return laddr(def.dso, def.sym->st_value); + } + if (__dl_invalid_handle(p)) return 0; + if ((ght = p->ghashtab)) { + gh = gnu_hash(s); + sym = gnu_lookup(gh, ght, p, s); + } else { + h = sysv_hash(s); + sym = sysv_lookup(s, h, p); + } + if (sym && (sym->st_info & 0xf) == STT_TLS) + return __tls_get_addr((size_t[]){p->tls_id, sym->st_value}); + if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info & 0xf) == STT_FUNC) + return p->funcdescs + (sym - p->syms); + if (sym && sym->st_value && (1 << (sym->st_info & 0xf) & OK_TYPES)) + return laddr(p, sym->st_value); + if (p->deps) + for (i = 0; p->deps[i]; i++) { + if ((ght = p->deps[i]->ghashtab)) { + if (!gh) gh = gnu_hash(s); + sym = gnu_lookup(gh, ght, p->deps[i], s); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, p->deps[i]); + } + if (sym && (sym->st_info & 0xf) == STT_TLS) + return __tls_get_addr((size_t[]){p->deps[i]->tls_id, sym->st_value}); + if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info & 0xf) == STT_FUNC) + return p->deps[i]->funcdescs + (sym - p->deps[i]->syms); + if (sym && sym->st_value && (1 << (sym->st_info & 0xf) & OK_TYPES)) + return laddr(p->deps[i], sym->st_value); + } +failed: + error("Symbol not found: %s", s); + return 0; +} + +int dladdr(const void* addr, Dl_info* info) { + struct dso* p; + Sym *sym, *bestsym; + uint32_t nsym; + char* strings; + void* best = 0; + + pthread_rwlock_rdlock(&lock); + p = addr2dso((size_t)addr); + pthread_rwlock_unlock(&lock); + + if (!p) return 0; + + sym = p->syms; + strings = p->strings; + nsym = count_syms(p); + + if (DL_FDPIC) { + size_t idx = ((size_t)addr - (size_t)p->funcdescs) / sizeof(*p->funcdescs); + if (idx < nsym && (sym[idx].st_info & 0xf) == STT_FUNC) { + best = p->funcdescs + idx; + bestsym = sym + idx; + } + } + + if (!best) + for (; nsym; nsym--, sym++) { + if (sym->st_value && (1 << (sym->st_info & 0xf) & OK_TYPES) && + (1 << (sym->st_info >> 4) & OK_BINDS)) { + void* symaddr = laddr(p, sym->st_value); + if (symaddr > addr || symaddr < best) continue; + best = symaddr; + bestsym = sym; + if (addr == symaddr) break; + } + } + + if (!best) return 0; + + if (DL_FDPIC && (bestsym->st_info & 0xf) == STT_FUNC) best = p->funcdescs + (bestsym - p->syms); + + info->dli_fname = p->name; + info->dli_fbase = p->base; + info->dli_sname = strings + bestsym->st_name; + info->dli_saddr = best; + + return 1; +} + +__attribute__((__visibility__("hidden"))) void* __dlsym(void* restrict p, const char* restrict s, + void* restrict ra) { + void* res; + pthread_rwlock_rdlock(&lock); + res = do_dlsym(p, s, ra); + pthread_rwlock_unlock(&lock); + return res; +} + +int dl_iterate_phdr(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), + void* data) { + struct dso* current; + struct dl_phdr_info info; + int ret = 0; + for (current = head; current;) { + info.dlpi_addr = (uintptr_t)current->base; + info.dlpi_name = current->name; + info.dlpi_phdr = current->phdr; + info.dlpi_phnum = current->phnum; + info.dlpi_adds = gencnt; + info.dlpi_subs = 0; + info.dlpi_tls_modid = current->tls_id; + info.dlpi_tls_data = current->tls.image; + + ret = (callback)(&info, sizeof(info), data); + + if (ret != 0) break; + + pthread_rwlock_rdlock(&lock); + current = current->next; + pthread_rwlock_unlock(&lock); + } + return ret; +} + +__attribute__((__visibility__("hidden"))) void __dl_vseterr(const char*, va_list); + +static void error(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + if (!runtime) { + vdprintf(2, fmt, ap); + dprintf(2, "\n"); + ldso_fail = 1; + va_end(ap); + return; + } + __dl_vseterr(fmt, ap); + va_end(ap); +} diff --git a/third_party/ulib/musl/magenta/BUILD.gn b/third_party/ulib/musl/magenta/BUILD.gn new file mode 100644 index 000000000..fc4c4ae8d --- /dev/null +++ b/third_party/ulib/musl/magenta/BUILD.gn @@ -0,0 +1,15 @@ +source_set("magenta") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "..:musl_config" ] + sources = [ + "debug.c", + "io.c", + "io.h", + "linuxisms.c", + "new.cpp", + "new.h", + "pure_virtual.c", + ] +} diff --git a/third_party/ulib/musl/magenta/debug.c b/third_party/ulib/musl/magenta/debug.c new file mode 100644 index 000000000..6a7321bce --- /dev/null +++ b/third_party/ulib/musl/magenta/debug.c @@ -0,0 +1,18 @@ +#include +#include + +#include + +void _panic(void* caller, const char* fmt, ...) { + printf("panic (caller %p): ", caller); + + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + + // call the exit syscall in a loop to satisfy NO_RETURN compiler semantics + for (;;) { + _magenta_exit(1); + } +} diff --git a/third_party/ulib/musl/magenta/debug.h b/third_party/ulib/musl/magenta/debug.h new file mode 100644 index 000000000..59ad7a8db --- /dev/null +++ b/third_party/ulib/musl/magenta/debug.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void _panic(void* caller, const char* fmt, ...) __PRINTFLIKE(2, 3) __NO_RETURN; +#define panic(x...) _panic(__GET_CALLER(), x) diff --git a/third_party/ulib/musl/magenta/io.c b/third_party/ulib/musl/magenta/io.c new file mode 100644 index 000000000..e130b786e --- /dev/null +++ b/third_party/ulib/musl/magenta/io.c @@ -0,0 +1,21 @@ +#include "io.h" + +#include + +#define ERR_NOT_SUPPORTED (-24) + +ssize_t io_write(io_handle_t* io, const char* buf, size_t len) { + assert(io->magic == IO_HANDLE_MAGIC); + + if (!io->hooks->write) return ERR_NOT_SUPPORTED; + + return io->hooks->write(io, buf, len); +} + +ssize_t io_read(io_handle_t* io, char* buf, size_t len) { + assert(io->magic == IO_HANDLE_MAGIC); + + if (!io->hooks->read) return ERR_NOT_SUPPORTED; + + return io->hooks->read(io, buf, len); +} diff --git a/third_party/ulib/musl/magenta/io.h b/third_party/ulib/musl/magenta/io.h new file mode 100644 index 000000000..1e34451b8 --- /dev/null +++ b/third_party/ulib/musl/magenta/io.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +/* LK specific calls to register to get input/output of the main console */ + +__BEGIN_CDECLS + +/* the underlying handle to talk to io devices */ +struct io_handle; +typedef struct io_handle_hooks { + ssize_t (*write)(struct io_handle* handle, const char* buf, size_t len); + ssize_t (*read)(struct io_handle* handle, char* buf, size_t len); +} io_handle_hooks_t; + +#define IO_HANDLE_MAGIC (0x696f6820) // "ioh " + +typedef struct io_handle { + uint32_t magic; + const io_handle_hooks_t* hooks; +} io_handle_t; + +/* routines to call through the io handle */ +ssize_t io_write(io_handle_t* io, const char* buf, size_t len); +ssize_t io_read(io_handle_t* io, char* buf, size_t len); + +/* initialization routine */ +#define IO_HANDLE_INITIAL_VALUE(_hooks) \ + { .magic = IO_HANDLE_MAGIC, .hooks = _hooks } + +static inline void io_handle_init(io_handle_t* io, io_handle_hooks_t* hooks) { + *io = (io_handle_t)IO_HANDLE_INITIAL_VALUE(hooks); +} + +__END_CDECLS diff --git a/third_party/ulib/musl/magenta/linuxisms.c b/third_party/ulib/musl/magenta/linuxisms.c new file mode 100644 index 000000000..c1ecfc2cc --- /dev/null +++ b/third_party/ulib/musl/magenta/linuxisms.c @@ -0,0 +1,6 @@ +#include "debug.h" +#include "syscall.h" + +long __linux_syscall(const char* fn, int ln, syscall_arg_t nr, ...) { + panic("\nFATAL: %s: %d: Linux Syscalls Not Supported (#%ld)\n", fn, ln, nr); +} diff --git a/third_party/ulib/musl/magenta/new.cpp b/third_party/ulib/musl/magenta/new.cpp new file mode 100644 index 000000000..e6231978c --- /dev/null +++ b/third_party/ulib/musl/magenta/new.cpp @@ -0,0 +1,25 @@ +#include + +void* operator new(size_t s) { + return ::malloc(s); +} + +void* operator new[](size_t s) { + return ::malloc(s); +} + +void* operator new(size_t, void* p) { + return p; +} + +void* operator new[](size_t, void* p) { + return p; +} + +void operator delete(void* p) { + ::free(p); +} + +void operator delete[](void* p) { + ::free(p); +} diff --git a/third_party/ulib/musl/magenta/pure_virtual.c b/third_party/ulib/musl/magenta/pure_virtual.c new file mode 100644 index 000000000..0a2ebd3ac --- /dev/null +++ b/third_party/ulib/musl/magenta/pure_virtual.c @@ -0,0 +1 @@ +void __cxa_pure_virtual(void) {} diff --git a/third_party/ulib/musl/rules.mk b/third_party/ulib/musl/rules.mk new file mode 100644 index 000000000..b7177aad0 --- /dev/null +++ b/third_party/ulib/musl/rules.mk @@ -0,0 +1,1310 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_COMPILEFLAGS := \ + -I$(LOCAL_DIR)/src/internal \ + -I$(LOCAL_DIR)/include \ + -I$(LOCAL_DIR)/third_party/include \ + +ifeq ($(ARCH),arm64) +MODULE_COMPILEFLAGS += -I$(LOCAL_DIR)/arch/aarch64 +else ifeq ($(ARCH),arm) +MODULE_COMPILEFLAGS += -I$(LOCAL_DIR)/arch/arm +else ifeq ($(SUBARCH),x86-64) +MODULE_COMPILEFLAGS += -I$(LOCAL_DIR)/arch/x86_64 +else +error Unsupported architecture for musl build! +endif + +MODULE_DEPS := \ + ulib/magenta ulib/runtime + +# The following are, more or less, from the upstream musl build. The +# _XOPEN_SOURCE value in particular is taken from there, and is +# necessary for many POSIX declarations to be visible internally. You +# can read about the semantics of it and the other feature test macros +# in |man 7 feature_test_macros| on Linux. musl exposes the minimum +# set of declarations or macro definitions allowed by those macros +# fairly carefully. + +# TODO(kulakowski) Clean up the junkier -Wno flags below. +MODULE_CFLAGS := \ + -D_XOPEN_SOURCE=700 \ + -Wno-maybe-uninitialized \ + -Wno-sign-compare \ + -Wno-strict-prototypes \ + -Wno-unused-value \ + -Wno-parentheses \ + -Wno-discarded-qualifiers \ + -Wno-empty-body \ + -Wno-error \ + -Wno-unused-but-set-variable \ + -Wno-missing-braces \ + -Wno-type-limits \ + -Werror=strict-prototypes \ + +MODULE_SRCS += \ + $(LOCAL_DIR)/ldso/dlstart.c \ + $(LOCAL_DIR)/ldso/dynlink.c \ + $(LOCAL_DIR)/magenta/debug.c \ + $(LOCAL_DIR)/magenta/io.c \ + $(LOCAL_DIR)/magenta/linuxisms.c \ + $(LOCAL_DIR)/magenta/new.cpp \ + $(LOCAL_DIR)/magenta/pure_virtual.c \ + $(LOCAL_DIR)/src/aio/aio.c \ + $(LOCAL_DIR)/src/aio/aio_suspend.c \ + $(LOCAL_DIR)/src/aio/lio_listio.c \ + $(LOCAL_DIR)/src/complex/cabs.c \ + $(LOCAL_DIR)/src/complex/cabsf.c \ + $(LOCAL_DIR)/src/complex/cabsl.c \ + $(LOCAL_DIR)/src/complex/cacos.c \ + $(LOCAL_DIR)/src/complex/cacosf.c \ + $(LOCAL_DIR)/src/complex/cacosh.c \ + $(LOCAL_DIR)/src/complex/cacoshf.c \ + $(LOCAL_DIR)/src/complex/cacoshl.c \ + $(LOCAL_DIR)/src/complex/cacosl.c \ + $(LOCAL_DIR)/src/complex/carg.c \ + $(LOCAL_DIR)/src/complex/cargf.c \ + $(LOCAL_DIR)/src/complex/cargl.c \ + $(LOCAL_DIR)/src/complex/casin.c \ + $(LOCAL_DIR)/src/complex/casinf.c \ + $(LOCAL_DIR)/src/complex/casinh.c \ + $(LOCAL_DIR)/src/complex/casinhf.c \ + $(LOCAL_DIR)/src/complex/casinhl.c \ + $(LOCAL_DIR)/src/complex/casinl.c \ + $(LOCAL_DIR)/src/complex/catanh.c \ + $(LOCAL_DIR)/src/complex/catanhf.c \ + $(LOCAL_DIR)/src/complex/catanhl.c \ + $(LOCAL_DIR)/src/complex/ccos.c \ + $(LOCAL_DIR)/src/complex/ccosf.c \ + $(LOCAL_DIR)/src/complex/ccoshl.c \ + $(LOCAL_DIR)/src/complex/ccosl.c \ + $(LOCAL_DIR)/src/complex/cexpl.c \ + $(LOCAL_DIR)/src/complex/cimag.c \ + $(LOCAL_DIR)/src/complex/cimagf.c \ + $(LOCAL_DIR)/src/complex/cimagl.c \ + $(LOCAL_DIR)/src/complex/clog.c \ + $(LOCAL_DIR)/src/complex/clogf.c \ + $(LOCAL_DIR)/src/complex/clogl.c \ + $(LOCAL_DIR)/src/complex/conj.c \ + $(LOCAL_DIR)/src/complex/conjf.c \ + $(LOCAL_DIR)/src/complex/conjl.c \ + $(LOCAL_DIR)/src/complex/cpow.c \ + $(LOCAL_DIR)/src/complex/cpowf.c \ + $(LOCAL_DIR)/src/complex/cpowl.c \ + $(LOCAL_DIR)/src/complex/cproj.c \ + $(LOCAL_DIR)/src/complex/cprojf.c \ + $(LOCAL_DIR)/src/complex/cprojl.c \ + $(LOCAL_DIR)/src/complex/creal.c \ + $(LOCAL_DIR)/src/complex/crealf.c \ + $(LOCAL_DIR)/src/complex/creall.c \ + $(LOCAL_DIR)/src/complex/csin.c \ + $(LOCAL_DIR)/src/complex/csinf.c \ + $(LOCAL_DIR)/src/complex/csinhl.c \ + $(LOCAL_DIR)/src/complex/csinl.c \ + $(LOCAL_DIR)/src/complex/csqrtl.c \ + $(LOCAL_DIR)/src/complex/ctan.c \ + $(LOCAL_DIR)/src/complex/ctanf.c \ + $(LOCAL_DIR)/src/complex/ctanhl.c \ + $(LOCAL_DIR)/src/complex/ctanl.c \ + $(LOCAL_DIR)/third_party/complex/__cexp.c \ + $(LOCAL_DIR)/third_party/complex/__cexpf.c \ + $(LOCAL_DIR)/third_party/complex/catan.c \ + $(LOCAL_DIR)/third_party/complex/catanf.c \ + $(LOCAL_DIR)/third_party/complex/catanl.c \ + $(LOCAL_DIR)/third_party/complex/ccosh.c \ + $(LOCAL_DIR)/third_party/complex/ccoshf.c \ + $(LOCAL_DIR)/third_party/complex/cexp.c \ + $(LOCAL_DIR)/third_party/complex/cexpf.c \ + $(LOCAL_DIR)/third_party/complex/csinh.c \ + $(LOCAL_DIR)/third_party/complex/csinhf.c \ + $(LOCAL_DIR)/third_party/complex/csqrt.c \ + $(LOCAL_DIR)/third_party/complex/csqrtf.c \ + $(LOCAL_DIR)/third_party/complex/ctanh.c \ + $(LOCAL_DIR)/third_party/complex/ctanhf.c \ + $(LOCAL_DIR)/src/conf/confstr.c \ + $(LOCAL_DIR)/src/conf/fpathconf.c \ + $(LOCAL_DIR)/src/conf/legacy.c \ + $(LOCAL_DIR)/src/conf/pathconf.c \ + $(LOCAL_DIR)/src/conf/sysconf.c \ + $(LOCAL_DIR)/src/crypt/crypt.c \ + $(LOCAL_DIR)/src/crypt/crypt_r.c \ + $(LOCAL_DIR)/src/crypt/encrypt.c \ + $(LOCAL_DIR)/src/ctype/__ctype_b_loc.c \ + $(LOCAL_DIR)/src/ctype/__ctype_get_mb_cur_max.c \ + $(LOCAL_DIR)/src/ctype/__ctype_tolower_loc.c \ + $(LOCAL_DIR)/src/ctype/__ctype_toupper_loc.c \ + $(LOCAL_DIR)/src/ctype/isalnum.c \ + $(LOCAL_DIR)/src/ctype/isalpha.c \ + $(LOCAL_DIR)/src/ctype/isascii.c \ + $(LOCAL_DIR)/src/ctype/isblank.c \ + $(LOCAL_DIR)/src/ctype/iscntrl.c \ + $(LOCAL_DIR)/src/ctype/isdigit.c \ + $(LOCAL_DIR)/src/ctype/isgraph.c \ + $(LOCAL_DIR)/src/ctype/islower.c \ + $(LOCAL_DIR)/src/ctype/isprint.c \ + $(LOCAL_DIR)/src/ctype/ispunct.c \ + $(LOCAL_DIR)/src/ctype/isspace.c \ + $(LOCAL_DIR)/src/ctype/isupper.c \ + $(LOCAL_DIR)/src/ctype/iswalnum.c \ + $(LOCAL_DIR)/src/ctype/iswalpha.c \ + $(LOCAL_DIR)/src/ctype/iswblank.c \ + $(LOCAL_DIR)/src/ctype/iswcntrl.c \ + $(LOCAL_DIR)/src/ctype/iswctype.c \ + $(LOCAL_DIR)/src/ctype/iswdigit.c \ + $(LOCAL_DIR)/src/ctype/iswgraph.c \ + $(LOCAL_DIR)/src/ctype/iswlower.c \ + $(LOCAL_DIR)/src/ctype/iswprint.c \ + $(LOCAL_DIR)/src/ctype/iswpunct.c \ + $(LOCAL_DIR)/src/ctype/iswspace.c \ + $(LOCAL_DIR)/src/ctype/iswupper.c \ + $(LOCAL_DIR)/src/ctype/iswxdigit.c \ + $(LOCAL_DIR)/src/ctype/isxdigit.c \ + $(LOCAL_DIR)/src/ctype/toascii.c \ + $(LOCAL_DIR)/src/ctype/tolower.c \ + $(LOCAL_DIR)/src/ctype/toupper.c \ + $(LOCAL_DIR)/src/ctype/towctrans.c \ + $(LOCAL_DIR)/src/ctype/wcswidth.c \ + $(LOCAL_DIR)/src/ctype/wctrans.c \ + $(LOCAL_DIR)/src/ctype/wcwidth.c \ + $(LOCAL_DIR)/src/dirent/__getdents.c \ + $(LOCAL_DIR)/src/dirent/alphasort.c \ + $(LOCAL_DIR)/src/dirent/closedir.c \ + $(LOCAL_DIR)/src/dirent/dirfd.c \ + $(LOCAL_DIR)/src/dirent/fdopendir.c \ + $(LOCAL_DIR)/src/dirent/opendir.c \ + $(LOCAL_DIR)/src/dirent/readdir.c \ + $(LOCAL_DIR)/src/dirent/readdir_r.c \ + $(LOCAL_DIR)/src/dirent/rewinddir.c \ + $(LOCAL_DIR)/src/dirent/scandir.c \ + $(LOCAL_DIR)/src/dirent/seekdir.c \ + $(LOCAL_DIR)/src/dirent/telldir.c \ + $(LOCAL_DIR)/src/dirent/versionsort.c \ + $(LOCAL_DIR)/src/env/__environ.c \ + $(LOCAL_DIR)/src/env/__init_tls.c \ + $(LOCAL_DIR)/src/env/__libc_start_main.c \ + $(LOCAL_DIR)/src/env/__reset_tls.c \ + $(LOCAL_DIR)/src/env/__stack_chk_fail.c \ + $(LOCAL_DIR)/src/env/clearenv.c \ + $(LOCAL_DIR)/src/env/getenv.c \ + $(LOCAL_DIR)/src/env/putenv.c \ + $(LOCAL_DIR)/src/env/setenv.c \ + $(LOCAL_DIR)/src/env/unsetenv.c \ + $(LOCAL_DIR)/src/errno/__errno_location.c \ + $(LOCAL_DIR)/src/errno/strerror.c \ + $(LOCAL_DIR)/src/exit/_Exit.c \ + $(LOCAL_DIR)/src/exit/abort.c \ + $(LOCAL_DIR)/src/exit/assert.c \ + $(LOCAL_DIR)/src/exit/at_quick_exit.c \ + $(LOCAL_DIR)/src/exit/atexit.c \ + $(LOCAL_DIR)/src/exit/exit.c \ + $(LOCAL_DIR)/src/exit/quick_exit.c \ + $(LOCAL_DIR)/src/fcntl/creat.c \ + $(LOCAL_DIR)/src/fcntl/fcntl.c \ + $(LOCAL_DIR)/src/fcntl/open.c \ + $(LOCAL_DIR)/src/fcntl/openat.c \ + $(LOCAL_DIR)/src/fcntl/posix_fadvise.c \ + $(LOCAL_DIR)/src/fcntl/posix_fallocate.c \ + $(LOCAL_DIR)/src/fenv/__flt_rounds.c \ + $(LOCAL_DIR)/src/fenv/fegetexceptflag.c \ + $(LOCAL_DIR)/src/fenv/feholdexcept.c \ + $(LOCAL_DIR)/src/fenv/fesetexceptflag.c \ + $(LOCAL_DIR)/src/fenv/fesetround.c \ + $(LOCAL_DIR)/src/fenv/feupdateenv.c \ + $(LOCAL_DIR)/src/internal/floatscan.c \ + $(LOCAL_DIR)/src/internal/intscan.c \ + $(LOCAL_DIR)/src/internal/libc.c \ + $(LOCAL_DIR)/src/internal/procfdname.c \ + $(LOCAL_DIR)/src/internal/shgetc.c \ + $(LOCAL_DIR)/src/internal/syscall_ret.c \ + $(LOCAL_DIR)/src/internal/vdso.c \ + $(LOCAL_DIR)/src/ipc/ftok.c \ + $(LOCAL_DIR)/src/ipc/msgctl.c \ + $(LOCAL_DIR)/src/ipc/msgget.c \ + $(LOCAL_DIR)/src/ipc/msgrcv.c \ + $(LOCAL_DIR)/src/ipc/msgsnd.c \ + $(LOCAL_DIR)/src/ipc/semctl.c \ + $(LOCAL_DIR)/src/ipc/semget.c \ + $(LOCAL_DIR)/src/ipc/semop.c \ + $(LOCAL_DIR)/src/ipc/semtimedop.c \ + $(LOCAL_DIR)/src/ipc/shmat.c \ + $(LOCAL_DIR)/src/ipc/shmctl.c \ + $(LOCAL_DIR)/src/ipc/shmdt.c \ + $(LOCAL_DIR)/src/ipc/shmget.c \ + $(LOCAL_DIR)/src/ldso/__dlsym.c \ + $(LOCAL_DIR)/src/ldso/dl_iterate_phdr.c \ + $(LOCAL_DIR)/src/ldso/dladdr.c \ + $(LOCAL_DIR)/src/ldso/dlclose.c \ + $(LOCAL_DIR)/src/ldso/dlerror.c \ + $(LOCAL_DIR)/src/ldso/dlinfo.c \ + $(LOCAL_DIR)/src/ldso/dlopen.c \ + $(LOCAL_DIR)/src/legacy/cuserid.c \ + $(LOCAL_DIR)/src/legacy/daemon.c \ + $(LOCAL_DIR)/src/legacy/err.c \ + $(LOCAL_DIR)/src/legacy/euidaccess.c \ + $(LOCAL_DIR)/src/legacy/ftw.c \ + $(LOCAL_DIR)/src/legacy/futimes.c \ + $(LOCAL_DIR)/src/legacy/getdtablesize.c \ + $(LOCAL_DIR)/src/legacy/getloadavg.c \ + $(LOCAL_DIR)/src/legacy/getpagesize.c \ + $(LOCAL_DIR)/src/legacy/getpass.c \ + $(LOCAL_DIR)/src/legacy/getusershell.c \ + $(LOCAL_DIR)/src/legacy/isastream.c \ + $(LOCAL_DIR)/src/legacy/lutimes.c \ + $(LOCAL_DIR)/src/legacy/ulimit.c \ + $(LOCAL_DIR)/src/legacy/utmpx.c \ + $(LOCAL_DIR)/src/legacy/valloc.c \ + $(LOCAL_DIR)/src/linux/adjtime.c \ + $(LOCAL_DIR)/src/linux/brk.c \ + $(LOCAL_DIR)/src/linux/cache.c \ + $(LOCAL_DIR)/src/linux/chroot.c \ + $(LOCAL_DIR)/src/linux/flock.c \ + $(LOCAL_DIR)/src/linux/prctl.c \ + $(LOCAL_DIR)/src/linux/ptrace.c \ + $(LOCAL_DIR)/src/linux/quotactl.c \ + $(LOCAL_DIR)/src/linux/sbrk.c \ + $(LOCAL_DIR)/src/linux/setgroups.c \ + $(LOCAL_DIR)/src/linux/sethostname.c \ + $(LOCAL_DIR)/src/linux/settimeofday.c \ + $(LOCAL_DIR)/src/linux/stime.c \ + $(LOCAL_DIR)/src/linux/utimes.c \ + $(LOCAL_DIR)/src/linux/wait3.c \ + $(LOCAL_DIR)/src/linux/wait4.c \ + $(LOCAL_DIR)/src/locale/__lctrans.c \ + $(LOCAL_DIR)/src/locale/__mo_lookup.c \ + $(LOCAL_DIR)/src/locale/bind_textdomain_codeset.c \ + $(LOCAL_DIR)/src/locale/c_locale.c \ + $(LOCAL_DIR)/src/locale/catclose.c \ + $(LOCAL_DIR)/src/locale/catgets.c \ + $(LOCAL_DIR)/src/locale/catopen.c \ + $(LOCAL_DIR)/src/locale/dcngettext.c \ + $(LOCAL_DIR)/src/locale/duplocale.c \ + $(LOCAL_DIR)/src/locale/freelocale.c \ + $(LOCAL_DIR)/src/locale/iconv.c \ + $(LOCAL_DIR)/src/locale/langinfo.c \ + $(LOCAL_DIR)/src/locale/locale_map.c \ + $(LOCAL_DIR)/src/locale/localeconv.c \ + $(LOCAL_DIR)/src/locale/newlocale.c \ + $(LOCAL_DIR)/src/locale/pleval.c \ + $(LOCAL_DIR)/src/locale/setlocale.c \ + $(LOCAL_DIR)/src/locale/strcoll.c \ + $(LOCAL_DIR)/src/locale/strfmon.c \ + $(LOCAL_DIR)/src/locale/strxfrm.c \ + $(LOCAL_DIR)/src/locale/textdomain.c \ + $(LOCAL_DIR)/src/locale/uselocale.c \ + $(LOCAL_DIR)/src/locale/wcscoll.c \ + $(LOCAL_DIR)/src/locale/wcsxfrm.c \ + $(LOCAL_DIR)/src/malloc/__brk.c \ + $(LOCAL_DIR)/src/malloc/aligned_alloc.c \ + $(LOCAL_DIR)/src/malloc/calloc.c \ + $(LOCAL_DIR)/src/malloc/expand_heap.c \ + $(LOCAL_DIR)/src/malloc/lite_malloc.c \ + $(LOCAL_DIR)/src/malloc/malloc.c \ + $(LOCAL_DIR)/src/malloc/malloc_usable_size.c \ + $(LOCAL_DIR)/src/malloc/memalign.c \ + $(LOCAL_DIR)/src/malloc/posix_memalign.c \ + $(LOCAL_DIR)/src/math/__expo2.c \ + $(LOCAL_DIR)/src/math/__expo2f.c \ + $(LOCAL_DIR)/src/math/__fpclassify.c \ + $(LOCAL_DIR)/src/math/__fpclassifyf.c \ + $(LOCAL_DIR)/src/math/__fpclassifyl.c \ + $(LOCAL_DIR)/src/math/__invtrigl.c \ + $(LOCAL_DIR)/src/math/__signbit.c \ + $(LOCAL_DIR)/src/math/__signbitf.c \ + $(LOCAL_DIR)/src/math/__signbitl.c \ + $(LOCAL_DIR)/src/math/acosh.c \ + $(LOCAL_DIR)/src/math/acoshf.c \ + $(LOCAL_DIR)/src/math/acoshl.c \ + $(LOCAL_DIR)/src/math/asinh.c \ + $(LOCAL_DIR)/src/math/asinhf.c \ + $(LOCAL_DIR)/src/math/asinhl.c \ + $(LOCAL_DIR)/src/math/atanh.c \ + $(LOCAL_DIR)/src/math/atanhf.c \ + $(LOCAL_DIR)/src/math/atanhl.c \ + $(LOCAL_DIR)/src/math/ceil.c \ + $(LOCAL_DIR)/src/math/ceilf.c \ + $(LOCAL_DIR)/src/math/copysign.c \ + $(LOCAL_DIR)/src/math/copysignf.c \ + $(LOCAL_DIR)/src/math/copysignl.c \ + $(LOCAL_DIR)/src/math/cosh.c \ + $(LOCAL_DIR)/src/math/coshf.c \ + $(LOCAL_DIR)/src/math/coshl.c \ + $(LOCAL_DIR)/src/math/cosl.c \ + $(LOCAL_DIR)/src/math/exp10.c \ + $(LOCAL_DIR)/src/math/exp10f.c \ + $(LOCAL_DIR)/src/math/exp10l.c \ + $(LOCAL_DIR)/src/math/fdim.c \ + $(LOCAL_DIR)/src/math/fdimf.c \ + $(LOCAL_DIR)/src/math/fdiml.c \ + $(LOCAL_DIR)/src/math/finite.c \ + $(LOCAL_DIR)/src/math/finitef.c \ + $(LOCAL_DIR)/src/math/floor.c \ + $(LOCAL_DIR)/src/math/floorf.c \ + $(LOCAL_DIR)/src/math/fmax.c \ + $(LOCAL_DIR)/src/math/fmaxf.c \ + $(LOCAL_DIR)/src/math/fmaxl.c \ + $(LOCAL_DIR)/src/math/fmin.c \ + $(LOCAL_DIR)/src/math/fminf.c \ + $(LOCAL_DIR)/src/math/fminl.c \ + $(LOCAL_DIR)/src/math/fmod.c \ + $(LOCAL_DIR)/src/math/fmodf.c \ + $(LOCAL_DIR)/src/math/frexp.c \ + $(LOCAL_DIR)/src/math/frexpf.c \ + $(LOCAL_DIR)/src/math/frexpl.c \ + $(LOCAL_DIR)/src/math/hypot.c \ + $(LOCAL_DIR)/src/math/hypotf.c \ + $(LOCAL_DIR)/src/math/hypotl.c \ + $(LOCAL_DIR)/src/math/ilogb.c \ + $(LOCAL_DIR)/src/math/ilogbf.c \ + $(LOCAL_DIR)/src/math/ilogbl.c \ + $(LOCAL_DIR)/src/math/ldexp.c \ + $(LOCAL_DIR)/src/math/ldexpf.c \ + $(LOCAL_DIR)/src/math/ldexpl.c \ + $(LOCAL_DIR)/src/math/lgamma.c \ + $(LOCAL_DIR)/src/math/lgammaf.c \ + $(LOCAL_DIR)/src/math/llround.c \ + $(LOCAL_DIR)/src/math/llroundf.c \ + $(LOCAL_DIR)/src/math/llroundl.c \ + $(LOCAL_DIR)/src/math/logb.c \ + $(LOCAL_DIR)/src/math/logbf.c \ + $(LOCAL_DIR)/src/math/logbl.c \ + $(LOCAL_DIR)/src/math/lround.c \ + $(LOCAL_DIR)/src/math/lroundf.c \ + $(LOCAL_DIR)/src/math/lroundl.c \ + $(LOCAL_DIR)/src/math/modf.c \ + $(LOCAL_DIR)/src/math/modff.c \ + $(LOCAL_DIR)/src/math/modfl.c \ + $(LOCAL_DIR)/src/math/nan.c \ + $(LOCAL_DIR)/src/math/nanf.c \ + $(LOCAL_DIR)/src/math/nanl.c \ + $(LOCAL_DIR)/src/math/nearbyint.c \ + $(LOCAL_DIR)/src/math/nearbyintf.c \ + $(LOCAL_DIR)/src/math/nearbyintl.c \ + $(LOCAL_DIR)/src/math/nextafter.c \ + $(LOCAL_DIR)/src/math/nextafterf.c \ + $(LOCAL_DIR)/src/math/nextafterl.c \ + $(LOCAL_DIR)/src/math/nexttoward.c \ + $(LOCAL_DIR)/src/math/nexttowardf.c \ + $(LOCAL_DIR)/src/math/nexttowardl.c \ + $(LOCAL_DIR)/src/math/remainder.c \ + $(LOCAL_DIR)/src/math/remainderf.c \ + $(LOCAL_DIR)/src/math/remquo.c \ + $(LOCAL_DIR)/src/math/remquof.c \ + $(LOCAL_DIR)/src/math/remquol.c \ + $(LOCAL_DIR)/src/math/rint.c \ + $(LOCAL_DIR)/src/math/rintf.c \ + $(LOCAL_DIR)/src/math/round.c \ + $(LOCAL_DIR)/src/math/roundf.c \ + $(LOCAL_DIR)/src/math/roundl.c \ + $(LOCAL_DIR)/src/math/scalbln.c \ + $(LOCAL_DIR)/src/math/scalblnf.c \ + $(LOCAL_DIR)/src/math/scalblnl.c \ + $(LOCAL_DIR)/src/math/scalbn.c \ + $(LOCAL_DIR)/src/math/scalbnf.c \ + $(LOCAL_DIR)/src/math/scalbnl.c \ + $(LOCAL_DIR)/src/math/signgam.c \ + $(LOCAL_DIR)/src/math/significand.c \ + $(LOCAL_DIR)/src/math/significandf.c \ + $(LOCAL_DIR)/src/math/sincosl.c \ + $(LOCAL_DIR)/src/math/sinh.c \ + $(LOCAL_DIR)/src/math/sinhf.c \ + $(LOCAL_DIR)/src/math/sinhl.c \ + $(LOCAL_DIR)/src/math/sinl.c \ + $(LOCAL_DIR)/src/math/tanh.c \ + $(LOCAL_DIR)/src/math/tanhf.c \ + $(LOCAL_DIR)/src/math/tanhl.c \ + $(LOCAL_DIR)/src/math/tanl.c \ + $(LOCAL_DIR)/src/math/tgamma.c \ + $(LOCAL_DIR)/src/math/tgammaf.c \ + $(LOCAL_DIR)/src/math/trunc.c \ + $(LOCAL_DIR)/src/math/truncf.c \ + $(LOCAL_DIR)/src/misc/a64l.c \ + $(LOCAL_DIR)/src/misc/basename.c \ + $(LOCAL_DIR)/src/misc/dirname.c \ + $(LOCAL_DIR)/src/misc/ffs.c \ + $(LOCAL_DIR)/src/misc/ffsl.c \ + $(LOCAL_DIR)/src/misc/ffsll.c \ + $(LOCAL_DIR)/src/misc/forkpty.c \ + $(LOCAL_DIR)/src/misc/get_current_dir_name.c \ + $(LOCAL_DIR)/src/misc/getauxval.c \ + $(LOCAL_DIR)/src/misc/getdomainname.c \ + $(LOCAL_DIR)/src/misc/gethostid.c \ + $(LOCAL_DIR)/src/misc/getopt.c \ + $(LOCAL_DIR)/src/misc/getopt_long.c \ + $(LOCAL_DIR)/src/misc/getpriority.c \ + $(LOCAL_DIR)/src/misc/getresgid.c \ + $(LOCAL_DIR)/src/misc/getresuid.c \ + $(LOCAL_DIR)/src/misc/getrlimit.c \ + $(LOCAL_DIR)/src/misc/getrusage.c \ + $(LOCAL_DIR)/src/misc/getsubopt.c \ + $(LOCAL_DIR)/src/misc/initgroups.c \ + $(LOCAL_DIR)/src/misc/ioctl.c \ + $(LOCAL_DIR)/src/misc/issetugid.c \ + $(LOCAL_DIR)/src/misc/lockf.c \ + $(LOCAL_DIR)/src/misc/login_tty.c \ + $(LOCAL_DIR)/src/misc/mntent.c \ + $(LOCAL_DIR)/src/misc/nftw.c \ + $(LOCAL_DIR)/src/misc/openpty.c \ + $(LOCAL_DIR)/src/misc/ptsname.c \ + $(LOCAL_DIR)/src/misc/pty.c \ + $(LOCAL_DIR)/src/misc/realpath.c \ + $(LOCAL_DIR)/src/misc/setdomainname.c \ + $(LOCAL_DIR)/src/misc/setpriority.c \ + $(LOCAL_DIR)/src/misc/setrlimit.c \ + $(LOCAL_DIR)/src/misc/syscall.c \ + $(LOCAL_DIR)/src/misc/syslog.c \ + $(LOCAL_DIR)/src/misc/uname.c \ + $(LOCAL_DIR)/src/misc/wordexp.c \ + $(LOCAL_DIR)/src/mman/madvise.c \ + $(LOCAL_DIR)/src/mman/mincore.c \ + $(LOCAL_DIR)/src/mman/mlock.c \ + $(LOCAL_DIR)/src/mman/mlockall.c \ + $(LOCAL_DIR)/src/mman/mmap.c \ + $(LOCAL_DIR)/src/mman/mprotect.c \ + $(LOCAL_DIR)/src/mman/mremap.c \ + $(LOCAL_DIR)/src/mman/msync.c \ + $(LOCAL_DIR)/src/mman/munlock.c \ + $(LOCAL_DIR)/src/mman/munlockall.c \ + $(LOCAL_DIR)/src/mman/munmap.c \ + $(LOCAL_DIR)/src/mman/posix_madvise.c \ + $(LOCAL_DIR)/src/mman/shm_open.c \ + $(LOCAL_DIR)/src/mq/mq_close.c \ + $(LOCAL_DIR)/src/mq/mq_getattr.c \ + $(LOCAL_DIR)/src/mq/mq_notify.c \ + $(LOCAL_DIR)/src/mq/mq_open.c \ + $(LOCAL_DIR)/src/mq/mq_receive.c \ + $(LOCAL_DIR)/src/mq/mq_send.c \ + $(LOCAL_DIR)/src/mq/mq_setattr.c \ + $(LOCAL_DIR)/src/mq/mq_timedreceive.c \ + $(LOCAL_DIR)/src/mq/mq_timedsend.c \ + $(LOCAL_DIR)/src/mq/mq_unlink.c \ + $(LOCAL_DIR)/src/multibyte/c16rtomb.c \ + $(LOCAL_DIR)/src/multibyte/c32rtomb.c \ + $(LOCAL_DIR)/src/multibyte/mbrtoc16.c \ + $(LOCAL_DIR)/src/multibyte/mbrtoc32.c \ + $(LOCAL_DIR)/src/multibyte/mbstowcs.c \ + $(LOCAL_DIR)/src/multibyte/wcstombs.c \ + $(LOCAL_DIR)/src/network/accept.c \ + $(LOCAL_DIR)/src/network/accept4.c \ + $(LOCAL_DIR)/src/network/bind.c \ + $(LOCAL_DIR)/src/network/connect.c \ + $(LOCAL_DIR)/src/network/dn_comp.c \ + $(LOCAL_DIR)/src/network/dn_expand.c \ + $(LOCAL_DIR)/src/network/dn_skipname.c \ + $(LOCAL_DIR)/src/network/dns_parse.c \ + $(LOCAL_DIR)/src/network/ent.c \ + $(LOCAL_DIR)/src/network/ether.c \ + $(LOCAL_DIR)/src/network/freeaddrinfo.c \ + $(LOCAL_DIR)/src/network/gai_strerror.c \ + $(LOCAL_DIR)/src/network/getaddrinfo.c \ + $(LOCAL_DIR)/src/network/gethostbyaddr.c \ + $(LOCAL_DIR)/src/network/gethostbyaddr_r.c \ + $(LOCAL_DIR)/src/network/gethostbyname.c \ + $(LOCAL_DIR)/src/network/gethostbyname2.c \ + $(LOCAL_DIR)/src/network/gethostbyname2_r.c \ + $(LOCAL_DIR)/src/network/gethostbyname_r.c \ + $(LOCAL_DIR)/src/network/getifaddrs.c \ + $(LOCAL_DIR)/src/network/getnameinfo.c \ + $(LOCAL_DIR)/src/network/getpeername.c \ + $(LOCAL_DIR)/src/network/getservbyname.c \ + $(LOCAL_DIR)/src/network/getservbyname_r.c \ + $(LOCAL_DIR)/src/network/getservbyport.c \ + $(LOCAL_DIR)/src/network/getservbyport_r.c \ + $(LOCAL_DIR)/src/network/getsockname.c \ + $(LOCAL_DIR)/src/network/getsockopt.c \ + $(LOCAL_DIR)/src/network/h_errno.c \ + $(LOCAL_DIR)/src/network/herror.c \ + $(LOCAL_DIR)/src/network/hstrerror.c \ + $(LOCAL_DIR)/src/network/htonl.c \ + $(LOCAL_DIR)/src/network/htons.c \ + $(LOCAL_DIR)/src/network/if_freenameindex.c \ + $(LOCAL_DIR)/src/network/if_indextoname.c \ + $(LOCAL_DIR)/src/network/if_nameindex.c \ + $(LOCAL_DIR)/src/network/if_nametoindex.c \ + $(LOCAL_DIR)/src/network/in6addr_any.c \ + $(LOCAL_DIR)/src/network/in6addr_loopback.c \ + $(LOCAL_DIR)/src/network/inet_addr.c \ + $(LOCAL_DIR)/src/network/inet_aton.c \ + $(LOCAL_DIR)/src/network/inet_legacy.c \ + $(LOCAL_DIR)/src/network/inet_ntoa.c \ + $(LOCAL_DIR)/src/network/inet_ntop.c \ + $(LOCAL_DIR)/src/network/inet_pton.c \ + $(LOCAL_DIR)/src/network/listen.c \ + $(LOCAL_DIR)/src/network/lookup_ipliteral.c \ + $(LOCAL_DIR)/src/network/lookup_name.c \ + $(LOCAL_DIR)/src/network/lookup_serv.c \ + $(LOCAL_DIR)/src/network/netlink.c \ + $(LOCAL_DIR)/src/network/netname.c \ + $(LOCAL_DIR)/src/network/ns_parse.c \ + $(LOCAL_DIR)/src/network/ntohl.c \ + $(LOCAL_DIR)/src/network/ntohs.c \ + $(LOCAL_DIR)/src/network/proto.c \ + $(LOCAL_DIR)/src/network/recv.c \ + $(LOCAL_DIR)/src/network/recvfrom.c \ + $(LOCAL_DIR)/src/network/recvmmsg.c \ + $(LOCAL_DIR)/src/network/recvmsg.c \ + $(LOCAL_DIR)/src/network/res_init.c \ + $(LOCAL_DIR)/src/network/res_mkquery.c \ + $(LOCAL_DIR)/src/network/res_msend.c \ + $(LOCAL_DIR)/src/network/res_query.c \ + $(LOCAL_DIR)/src/network/res_querydomain.c \ + $(LOCAL_DIR)/src/network/res_send.c \ + $(LOCAL_DIR)/src/network/res_state.c \ + $(LOCAL_DIR)/src/network/resolvconf.c \ + $(LOCAL_DIR)/src/network/send.c \ + $(LOCAL_DIR)/src/network/sendmmsg.c \ + $(LOCAL_DIR)/src/network/sendmsg.c \ + $(LOCAL_DIR)/src/network/sendto.c \ + $(LOCAL_DIR)/src/network/serv.c \ + $(LOCAL_DIR)/src/network/setsockopt.c \ + $(LOCAL_DIR)/src/network/shutdown.c \ + $(LOCAL_DIR)/src/network/sockatmark.c \ + $(LOCAL_DIR)/src/network/socket.c \ + $(LOCAL_DIR)/src/network/socketpair.c \ + $(LOCAL_DIR)/src/passwd/fgetgrent.c \ + $(LOCAL_DIR)/src/passwd/fgetpwent.c \ + $(LOCAL_DIR)/src/passwd/fgetspent.c \ + $(LOCAL_DIR)/src/passwd/getgr_a.c \ + $(LOCAL_DIR)/src/passwd/getgr_r.c \ + $(LOCAL_DIR)/src/passwd/getgrent.c \ + $(LOCAL_DIR)/src/passwd/getgrent_a.c \ + $(LOCAL_DIR)/src/passwd/getgrouplist.c \ + $(LOCAL_DIR)/src/passwd/getpw_a.c \ + $(LOCAL_DIR)/src/passwd/getpw_r.c \ + $(LOCAL_DIR)/src/passwd/getpwent.c \ + $(LOCAL_DIR)/src/passwd/getpwent_a.c \ + $(LOCAL_DIR)/src/passwd/getspent.c \ + $(LOCAL_DIR)/src/passwd/getspnam.c \ + $(LOCAL_DIR)/src/passwd/getspnam_r.c \ + $(LOCAL_DIR)/src/passwd/lckpwdf.c \ + $(LOCAL_DIR)/src/passwd/nscd_query.c \ + $(LOCAL_DIR)/src/passwd/putgrent.c \ + $(LOCAL_DIR)/src/passwd/putpwent.c \ + $(LOCAL_DIR)/src/passwd/putspent.c \ + $(LOCAL_DIR)/src/prng/__rand48_step.c \ + $(LOCAL_DIR)/src/prng/__seed48.c \ + $(LOCAL_DIR)/src/prng/drand48.c \ + $(LOCAL_DIR)/src/prng/lcong48.c \ + $(LOCAL_DIR)/src/prng/lrand48.c \ + $(LOCAL_DIR)/src/prng/mrand48.c \ + $(LOCAL_DIR)/src/prng/rand.c \ + $(LOCAL_DIR)/src/prng/rand_r.c \ + $(LOCAL_DIR)/src/prng/seed48.c \ + $(LOCAL_DIR)/src/prng/srand48.c \ + $(LOCAL_DIR)/src/process/execl.c \ + $(LOCAL_DIR)/src/process/execle.c \ + $(LOCAL_DIR)/src/process/execlp.c \ + $(LOCAL_DIR)/src/process/execv.c \ + $(LOCAL_DIR)/src/process/execve.c \ + $(LOCAL_DIR)/src/process/execvp.c \ + $(LOCAL_DIR)/src/process/fexecve.c \ + $(LOCAL_DIR)/src/process/fork.c \ + $(LOCAL_DIR)/src/process/posix_spawn.c \ + $(LOCAL_DIR)/src/process/posix_spawn_file_actions_addclose.c \ + $(LOCAL_DIR)/src/process/posix_spawn_file_actions_adddup2.c \ + $(LOCAL_DIR)/src/process/posix_spawn_file_actions_addopen.c \ + $(LOCAL_DIR)/src/process/posix_spawn_file_actions_destroy.c \ + $(LOCAL_DIR)/src/process/posix_spawn_file_actions_init.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_destroy.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_getflags.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_getpgroup.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_getsigdefault.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_getsigmask.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_init.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_sched.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_setflags.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_setpgroup.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_setsigdefault.c \ + $(LOCAL_DIR)/src/process/posix_spawnattr_setsigmask.c \ + $(LOCAL_DIR)/src/process/posix_spawnp.c \ + $(LOCAL_DIR)/src/process/system.c \ + $(LOCAL_DIR)/src/process/wait.c \ + $(LOCAL_DIR)/src/process/waitid.c \ + $(LOCAL_DIR)/src/process/waitpid.c \ + $(LOCAL_DIR)/src/regex/fnmatch.c \ + $(LOCAL_DIR)/src/regex/glob.c \ + $(LOCAL_DIR)/src/sched/affinity.c \ + $(LOCAL_DIR)/src/sched/sched_cpucount.c \ + $(LOCAL_DIR)/src/sched/sched_get_priority_max.c \ + $(LOCAL_DIR)/src/sched/sched_getcpu.c \ + $(LOCAL_DIR)/src/sched/sched_getparam.c \ + $(LOCAL_DIR)/src/sched/sched_getscheduler.c \ + $(LOCAL_DIR)/src/sched/sched_rr_get_interval.c \ + $(LOCAL_DIR)/src/sched/sched_setparam.c \ + $(LOCAL_DIR)/src/sched/sched_setscheduler.c \ + $(LOCAL_DIR)/src/sched/sched_yield.c \ + $(LOCAL_DIR)/src/select/poll.c \ + $(LOCAL_DIR)/src/select/pselect.c \ + $(LOCAL_DIR)/src/select/select.c \ + $(LOCAL_DIR)/src/setjmp/longjmp.c \ + $(LOCAL_DIR)/src/setjmp/setjmp.c \ + $(LOCAL_DIR)/src/signal/block.c \ + $(LOCAL_DIR)/src/signal/getitimer.c \ + $(LOCAL_DIR)/src/signal/kill.c \ + $(LOCAL_DIR)/src/signal/killpg.c \ + $(LOCAL_DIR)/src/signal/psiginfo.c \ + $(LOCAL_DIR)/src/signal/psignal.c \ + $(LOCAL_DIR)/src/signal/raise.c \ + $(LOCAL_DIR)/src/signal/setitimer.c \ + $(LOCAL_DIR)/src/signal/sigaction.c \ + $(LOCAL_DIR)/src/signal/sigaddset.c \ + $(LOCAL_DIR)/src/signal/sigaltstack.c \ + $(LOCAL_DIR)/src/signal/sigandset.c \ + $(LOCAL_DIR)/src/signal/sigdelset.c \ + $(LOCAL_DIR)/src/signal/sigemptyset.c \ + $(LOCAL_DIR)/src/signal/sigfillset.c \ + $(LOCAL_DIR)/src/signal/sighold.c \ + $(LOCAL_DIR)/src/signal/sigignore.c \ + $(LOCAL_DIR)/src/signal/siginterrupt.c \ + $(LOCAL_DIR)/src/signal/sigisemptyset.c \ + $(LOCAL_DIR)/src/signal/sigismember.c \ + $(LOCAL_DIR)/src/signal/siglongjmp.c \ + $(LOCAL_DIR)/src/signal/signal.c \ + $(LOCAL_DIR)/src/signal/sigorset.c \ + $(LOCAL_DIR)/src/signal/sigpause.c \ + $(LOCAL_DIR)/src/signal/sigpending.c \ + $(LOCAL_DIR)/src/signal/sigprocmask.c \ + $(LOCAL_DIR)/src/signal/sigqueue.c \ + $(LOCAL_DIR)/src/signal/sigrelse.c \ + $(LOCAL_DIR)/src/signal/sigrtmax.c \ + $(LOCAL_DIR)/src/signal/sigrtmin.c \ + $(LOCAL_DIR)/src/signal/sigset.c \ + $(LOCAL_DIR)/src/signal/sigsetjmp.c \ + $(LOCAL_DIR)/src/signal/sigsetjmp_tail.c \ + $(LOCAL_DIR)/src/signal/sigsuspend.c \ + $(LOCAL_DIR)/src/signal/sigtimedwait.c \ + $(LOCAL_DIR)/src/signal/sigwait.c \ + $(LOCAL_DIR)/src/signal/sigwaitinfo.c \ + $(LOCAL_DIR)/src/stat/__xstat.c \ + $(LOCAL_DIR)/src/stat/chmod.c \ + $(LOCAL_DIR)/src/stat/fchmod.c \ + $(LOCAL_DIR)/src/stat/fchmodat.c \ + $(LOCAL_DIR)/src/stat/fstatat.c \ + $(LOCAL_DIR)/src/stat/futimens.c \ + $(LOCAL_DIR)/src/stat/futimesat.c \ + $(LOCAL_DIR)/src/stat/lchmod.c \ + $(LOCAL_DIR)/src/stat/lstat.c \ + $(LOCAL_DIR)/src/stat/mkdir.c \ + $(LOCAL_DIR)/src/stat/mkdirat.c \ + $(LOCAL_DIR)/src/stat/mkfifo.c \ + $(LOCAL_DIR)/src/stat/mkfifoat.c \ + $(LOCAL_DIR)/src/stat/mknod.c \ + $(LOCAL_DIR)/src/stat/mknodat.c \ + $(LOCAL_DIR)/src/stat/statvfs.c \ + $(LOCAL_DIR)/src/stat/umask.c \ + $(LOCAL_DIR)/src/stat/utimensat.c \ + $(LOCAL_DIR)/src/stdio/__fclose_ca.c \ + $(LOCAL_DIR)/src/stdio/__fdopen.c \ + $(LOCAL_DIR)/src/stdio/__fmodeflags.c \ + $(LOCAL_DIR)/src/stdio/__fopen_rb_ca.c \ + $(LOCAL_DIR)/src/stdio/__lockfile.c \ + $(LOCAL_DIR)/src/stdio/__overflow.c \ + $(LOCAL_DIR)/src/stdio/__stdio_close.c \ + $(LOCAL_DIR)/src/stdio/__stdio_exit.c \ + $(LOCAL_DIR)/src/stdio/__stdio_read.c \ + $(LOCAL_DIR)/src/stdio/__stdio_seek.c \ + $(LOCAL_DIR)/src/stdio/__stdio_write.c \ + $(LOCAL_DIR)/src/stdio/__stdout_write.c \ + $(LOCAL_DIR)/src/stdio/__string_read.c \ + $(LOCAL_DIR)/src/stdio/__toread.c \ + $(LOCAL_DIR)/src/stdio/__towrite.c \ + $(LOCAL_DIR)/src/stdio/__uflow.c \ + $(LOCAL_DIR)/src/stdio/asprintf.c \ + $(LOCAL_DIR)/src/stdio/clearerr.c \ + $(LOCAL_DIR)/src/stdio/dprintf.c \ + $(LOCAL_DIR)/src/stdio/ext.c \ + $(LOCAL_DIR)/src/stdio/ext2.c \ + $(LOCAL_DIR)/src/stdio/fclose.c \ + $(LOCAL_DIR)/src/stdio/feof.c \ + $(LOCAL_DIR)/src/stdio/ferror.c \ + $(LOCAL_DIR)/src/stdio/fflush.c \ + $(LOCAL_DIR)/src/stdio/fgetc.c \ + $(LOCAL_DIR)/src/stdio/fgetln.c \ + $(LOCAL_DIR)/src/stdio/fgetpos.c \ + $(LOCAL_DIR)/src/stdio/fgets.c \ + $(LOCAL_DIR)/src/stdio/fgetwc.c \ + $(LOCAL_DIR)/src/stdio/fgetws.c \ + $(LOCAL_DIR)/src/stdio/fileno.c \ + $(LOCAL_DIR)/src/stdio/flockfile.c \ + $(LOCAL_DIR)/src/stdio/fmemopen.c \ + $(LOCAL_DIR)/src/stdio/fopen.c \ + $(LOCAL_DIR)/src/stdio/fprintf.c \ + $(LOCAL_DIR)/src/stdio/fputc.c \ + $(LOCAL_DIR)/src/stdio/fputs.c \ + $(LOCAL_DIR)/src/stdio/fputwc.c \ + $(LOCAL_DIR)/src/stdio/fputws.c \ + $(LOCAL_DIR)/src/stdio/fread.c \ + $(LOCAL_DIR)/src/stdio/freopen.c \ + $(LOCAL_DIR)/src/stdio/fscanf.c \ + $(LOCAL_DIR)/src/stdio/fseek.c \ + $(LOCAL_DIR)/src/stdio/fsetpos.c \ + $(LOCAL_DIR)/src/stdio/ftell.c \ + $(LOCAL_DIR)/src/stdio/ftrylockfile.c \ + $(LOCAL_DIR)/src/stdio/funlockfile.c \ + $(LOCAL_DIR)/src/stdio/fwide.c \ + $(LOCAL_DIR)/src/stdio/fwprintf.c \ + $(LOCAL_DIR)/src/stdio/fwrite.c \ + $(LOCAL_DIR)/src/stdio/fwscanf.c \ + $(LOCAL_DIR)/src/stdio/getc.c \ + $(LOCAL_DIR)/src/stdio/getc_unlocked.c \ + $(LOCAL_DIR)/src/stdio/getchar.c \ + $(LOCAL_DIR)/src/stdio/getchar_unlocked.c \ + $(LOCAL_DIR)/src/stdio/getdelim.c \ + $(LOCAL_DIR)/src/stdio/getline.c \ + $(LOCAL_DIR)/src/stdio/gets.c \ + $(LOCAL_DIR)/src/stdio/getw.c \ + $(LOCAL_DIR)/src/stdio/getwc.c \ + $(LOCAL_DIR)/src/stdio/getwchar.c \ + $(LOCAL_DIR)/src/stdio/ofl.c \ + $(LOCAL_DIR)/src/stdio/ofl_add.c \ + $(LOCAL_DIR)/src/stdio/open_memstream.c \ + $(LOCAL_DIR)/src/stdio/open_wmemstream.c \ + $(LOCAL_DIR)/src/stdio/pclose.c \ + $(LOCAL_DIR)/src/stdio/perror.c \ + $(LOCAL_DIR)/src/stdio/popen.c \ + $(LOCAL_DIR)/src/stdio/printf.c \ + $(LOCAL_DIR)/src/stdio/putc.c \ + $(LOCAL_DIR)/src/stdio/putc_unlocked.c \ + $(LOCAL_DIR)/src/stdio/putchar.c \ + $(LOCAL_DIR)/src/stdio/putchar_unlocked.c \ + $(LOCAL_DIR)/src/stdio/puts.c \ + $(LOCAL_DIR)/src/stdio/putw.c \ + $(LOCAL_DIR)/src/stdio/putwc.c \ + $(LOCAL_DIR)/src/stdio/putwchar.c \ + $(LOCAL_DIR)/src/stdio/remove.c \ + $(LOCAL_DIR)/src/stdio/rename.c \ + $(LOCAL_DIR)/src/stdio/rewind.c \ + $(LOCAL_DIR)/src/stdio/scanf.c \ + $(LOCAL_DIR)/src/stdio/setbuf.c \ + $(LOCAL_DIR)/src/stdio/setbuffer.c \ + $(LOCAL_DIR)/src/stdio/setlinebuf.c \ + $(LOCAL_DIR)/src/stdio/setvbuf.c \ + $(LOCAL_DIR)/src/stdio/snprintf.c \ + $(LOCAL_DIR)/src/stdio/sprintf.c \ + $(LOCAL_DIR)/src/stdio/sscanf.c \ + $(LOCAL_DIR)/src/stdio/stderr.c \ + $(LOCAL_DIR)/src/stdio/stdin.c \ + $(LOCAL_DIR)/src/stdio/stdout.c \ + $(LOCAL_DIR)/src/stdio/swprintf.c \ + $(LOCAL_DIR)/src/stdio/swscanf.c \ + $(LOCAL_DIR)/src/stdio/tempnam.c \ + $(LOCAL_DIR)/src/stdio/tmpfile.c \ + $(LOCAL_DIR)/src/stdio/tmpnam.c \ + $(LOCAL_DIR)/src/stdio/ungetc.c \ + $(LOCAL_DIR)/src/stdio/ungetwc.c \ + $(LOCAL_DIR)/src/stdio/vasprintf.c \ + $(LOCAL_DIR)/src/stdio/vdprintf.c \ + $(LOCAL_DIR)/src/stdio/vfprintf.c \ + $(LOCAL_DIR)/src/stdio/vfscanf.c \ + $(LOCAL_DIR)/src/stdio/vfwprintf.c \ + $(LOCAL_DIR)/src/stdio/vfwscanf.c \ + $(LOCAL_DIR)/src/stdio/vprintf.c \ + $(LOCAL_DIR)/src/stdio/vscanf.c \ + $(LOCAL_DIR)/src/stdio/vsnprintf.c \ + $(LOCAL_DIR)/src/stdio/vsprintf.c \ + $(LOCAL_DIR)/src/stdio/vsscanf.c \ + $(LOCAL_DIR)/src/stdio/vswprintf.c \ + $(LOCAL_DIR)/src/stdio/vswscanf.c \ + $(LOCAL_DIR)/src/stdio/vwprintf.c \ + $(LOCAL_DIR)/src/stdio/vwscanf.c \ + $(LOCAL_DIR)/src/stdio/wprintf.c \ + $(LOCAL_DIR)/src/stdio/wscanf.c \ + $(LOCAL_DIR)/src/stdlib/abs.c \ + $(LOCAL_DIR)/src/stdlib/atof.c \ + $(LOCAL_DIR)/src/stdlib/atoi.c \ + $(LOCAL_DIR)/src/stdlib/atol.c \ + $(LOCAL_DIR)/src/stdlib/atoll.c \ + $(LOCAL_DIR)/src/stdlib/bsearch.c \ + $(LOCAL_DIR)/src/stdlib/div.c \ + $(LOCAL_DIR)/src/stdlib/ecvt.c \ + $(LOCAL_DIR)/src/stdlib/fcvt.c \ + $(LOCAL_DIR)/src/stdlib/gcvt.c \ + $(LOCAL_DIR)/src/stdlib/imaxabs.c \ + $(LOCAL_DIR)/src/stdlib/imaxdiv.c \ + $(LOCAL_DIR)/src/stdlib/labs.c \ + $(LOCAL_DIR)/src/stdlib/ldiv.c \ + $(LOCAL_DIR)/src/stdlib/llabs.c \ + $(LOCAL_DIR)/src/stdlib/lldiv.c \ + $(LOCAL_DIR)/src/stdlib/strtod.c \ + $(LOCAL_DIR)/src/stdlib/strtol.c \ + $(LOCAL_DIR)/src/stdlib/wcstod.c \ + $(LOCAL_DIR)/src/stdlib/wcstol.c \ + $(LOCAL_DIR)/src/temp/__randname.c \ + $(LOCAL_DIR)/src/temp/mkdtemp.c \ + $(LOCAL_DIR)/src/temp/mkostemp.c \ + $(LOCAL_DIR)/src/temp/mkostemps.c \ + $(LOCAL_DIR)/src/temp/mkstemp.c \ + $(LOCAL_DIR)/src/temp/mkstemps.c \ + $(LOCAL_DIR)/src/temp/mktemp.c \ + $(LOCAL_DIR)/src/termios/cfgetospeed.c \ + $(LOCAL_DIR)/src/termios/cfmakeraw.c \ + $(LOCAL_DIR)/src/termios/cfsetospeed.c \ + $(LOCAL_DIR)/src/termios/tcdrain.c \ + $(LOCAL_DIR)/src/termios/tcflow.c \ + $(LOCAL_DIR)/src/termios/tcflush.c \ + $(LOCAL_DIR)/src/termios/tcgetattr.c \ + $(LOCAL_DIR)/src/termios/tcgetsid.c \ + $(LOCAL_DIR)/src/termios/tcsendbreak.c \ + $(LOCAL_DIR)/src/termios/tcsetattr.c \ + $(LOCAL_DIR)/src/thread/__timedwait.c \ + $(LOCAL_DIR)/src/thread/__tls_get_addr.c \ + $(LOCAL_DIR)/src/thread/__wait.c \ + $(LOCAL_DIR)/src/thread/call_once.c \ + $(LOCAL_DIR)/src/thread/cnd_broadcast.c \ + $(LOCAL_DIR)/src/thread/cnd_destroy.c \ + $(LOCAL_DIR)/src/thread/cnd_init.c \ + $(LOCAL_DIR)/src/thread/cnd_signal.c \ + $(LOCAL_DIR)/src/thread/cnd_timedwait.c \ + $(LOCAL_DIR)/src/thread/cnd_wait.c \ + $(LOCAL_DIR)/src/thread/lock_ptc.c \ + $(LOCAL_DIR)/src/thread/mtx_destroy.c \ + $(LOCAL_DIR)/src/thread/mtx_init.c \ + $(LOCAL_DIR)/src/thread/mtx_lock.c \ + $(LOCAL_DIR)/src/thread/mtx_timedlock.c \ + $(LOCAL_DIR)/src/thread/mtx_trylock.c \ + $(LOCAL_DIR)/src/thread/mtx_unlock.c \ + $(LOCAL_DIR)/src/thread/pthread_atfork.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_get.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_init.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setdetachstate.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setguardsize.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setinheritsched.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setschedparam.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setschedpolicy.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setscope.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setstack.c \ + $(LOCAL_DIR)/src/thread/pthread_attr_setstacksize.c \ + $(LOCAL_DIR)/src/thread/pthread_barrier_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_barrier_init.c \ + $(LOCAL_DIR)/src/thread/pthread_barrier_wait.c \ + $(LOCAL_DIR)/src/thread/pthread_barrierattr_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_barrierattr_init.c \ + $(LOCAL_DIR)/src/thread/pthread_cancel.c \ + $(LOCAL_DIR)/src/thread/pthread_cleanup_push.c \ + $(LOCAL_DIR)/src/thread/pthread_cond_broadcast.c \ + $(LOCAL_DIR)/src/thread/pthread_cond_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_cond_init.c \ + $(LOCAL_DIR)/src/thread/pthread_cond_signal.c \ + $(LOCAL_DIR)/src/thread/pthread_cond_timedwait.c \ + $(LOCAL_DIR)/src/thread/pthread_cond_wait.c \ + $(LOCAL_DIR)/src/thread/pthread_condattr_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_condattr_init.c \ + $(LOCAL_DIR)/src/thread/pthread_condattr_setclock.c \ + $(LOCAL_DIR)/src/thread/pthread_create.c \ + $(LOCAL_DIR)/src/thread/pthread_detach.c \ + $(LOCAL_DIR)/src/thread/pthread_equal.c \ + $(LOCAL_DIR)/src/thread/pthread_getattr_np.c \ + $(LOCAL_DIR)/src/thread/pthread_getconcurrency.c \ + $(LOCAL_DIR)/src/thread/pthread_getcpuclockid.c \ + $(LOCAL_DIR)/src/thread/pthread_getschedparam.c \ + $(LOCAL_DIR)/src/thread/pthread_getspecific.c \ + $(LOCAL_DIR)/src/thread/pthread_join.c \ + $(LOCAL_DIR)/src/thread/pthread_key_create.c \ + $(LOCAL_DIR)/src/thread/pthread_kill.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_consistent.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_getprioceiling.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_init.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_lock.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_setprioceiling.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_timedlock.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_trylock.c \ + $(LOCAL_DIR)/src/thread/pthread_mutex_unlock.c \ + $(LOCAL_DIR)/src/thread/pthread_mutexattr_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_mutexattr_init.c \ + $(LOCAL_DIR)/src/thread/pthread_mutexattr_setprotocol.c \ + $(LOCAL_DIR)/src/thread/pthread_mutexattr_setrobust.c \ + $(LOCAL_DIR)/src/thread/pthread_mutexattr_settype.c \ + $(LOCAL_DIR)/src/thread/pthread_once.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_init.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_rdlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_timedrdlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_timedwrlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_tryrdlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_trywrlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_unlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlock_wrlock.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlockattr_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_rwlockattr_init.c \ + $(LOCAL_DIR)/src/thread/pthread_self.c \ + $(LOCAL_DIR)/src/thread/pthread_setcancelstate.c \ + $(LOCAL_DIR)/src/thread/pthread_setcanceltype.c \ + $(LOCAL_DIR)/src/thread/pthread_setconcurrency.c \ + $(LOCAL_DIR)/src/thread/pthread_setschedparam.c \ + $(LOCAL_DIR)/src/thread/pthread_setschedprio.c \ + $(LOCAL_DIR)/src/thread/pthread_setspecific.c \ + $(LOCAL_DIR)/src/thread/pthread_sigmask.c \ + $(LOCAL_DIR)/src/thread/pthread_spin_destroy.c \ + $(LOCAL_DIR)/src/thread/pthread_spin_init.c \ + $(LOCAL_DIR)/src/thread/pthread_spin_lock.c \ + $(LOCAL_DIR)/src/thread/pthread_spin_trylock.c \ + $(LOCAL_DIR)/src/thread/pthread_spin_unlock.c \ + $(LOCAL_DIR)/src/thread/pthread_testcancel.c \ + $(LOCAL_DIR)/src/thread/sem_destroy.c \ + $(LOCAL_DIR)/src/thread/sem_getvalue.c \ + $(LOCAL_DIR)/src/thread/sem_init.c \ + $(LOCAL_DIR)/src/thread/sem_open.c \ + $(LOCAL_DIR)/src/thread/sem_post.c \ + $(LOCAL_DIR)/src/thread/sem_timedwait.c \ + $(LOCAL_DIR)/src/thread/sem_trywait.c \ + $(LOCAL_DIR)/src/thread/sem_unlink.c \ + $(LOCAL_DIR)/src/thread/sem_wait.c \ + $(LOCAL_DIR)/src/thread/thrd_create.c \ + $(LOCAL_DIR)/src/thread/thrd_exit.c \ + $(LOCAL_DIR)/src/thread/thrd_join.c \ + $(LOCAL_DIR)/src/thread/thrd_sleep.c \ + $(LOCAL_DIR)/src/thread/thrd_yield.c \ + $(LOCAL_DIR)/src/thread/tls.c \ + $(LOCAL_DIR)/src/thread/tss_create.c \ + $(LOCAL_DIR)/src/thread/tss_delete.c \ + $(LOCAL_DIR)/src/thread/tss_set.c \ + $(LOCAL_DIR)/src/thread/vmlock.c \ + $(LOCAL_DIR)/src/time/__asctime.c \ + $(LOCAL_DIR)/src/time/__map_file.c \ + $(LOCAL_DIR)/src/time/__month_to_secs.c \ + $(LOCAL_DIR)/src/time/__secs_to_tm.c \ + $(LOCAL_DIR)/src/time/__tm_to_secs.c \ + $(LOCAL_DIR)/src/time/__tz.c \ + $(LOCAL_DIR)/src/time/__year_to_secs.c \ + $(LOCAL_DIR)/src/time/asctime.c \ + $(LOCAL_DIR)/src/time/asctime_r.c \ + $(LOCAL_DIR)/src/time/clock.c \ + $(LOCAL_DIR)/src/time/clock_getcpuclockid.c \ + $(LOCAL_DIR)/src/time/clock_getres.c \ + $(LOCAL_DIR)/src/time/clock_gettime.c \ + $(LOCAL_DIR)/src/time/clock_nanosleep.c \ + $(LOCAL_DIR)/src/time/clock_settime.c \ + $(LOCAL_DIR)/src/time/ctime.c \ + $(LOCAL_DIR)/src/time/ctime_r.c \ + $(LOCAL_DIR)/src/time/difftime.c \ + $(LOCAL_DIR)/src/time/ftime.c \ + $(LOCAL_DIR)/src/time/getdate.c \ + $(LOCAL_DIR)/src/time/gettimeofday.c \ + $(LOCAL_DIR)/src/time/gmtime.c \ + $(LOCAL_DIR)/src/time/gmtime_r.c \ + $(LOCAL_DIR)/src/time/localtime.c \ + $(LOCAL_DIR)/src/time/localtime_r.c \ + $(LOCAL_DIR)/src/time/mktime.c \ + $(LOCAL_DIR)/src/time/nanosleep.c \ + $(LOCAL_DIR)/src/time/strftime.c \ + $(LOCAL_DIR)/src/time/strptime.c \ + $(LOCAL_DIR)/src/time/time.c \ + $(LOCAL_DIR)/src/time/timegm.c \ + $(LOCAL_DIR)/src/time/timer_create.c \ + $(LOCAL_DIR)/src/time/timer_delete.c \ + $(LOCAL_DIR)/src/time/timer_getoverrun.c \ + $(LOCAL_DIR)/src/time/timer_gettime.c \ + $(LOCAL_DIR)/src/time/timer_settime.c \ + $(LOCAL_DIR)/src/time/times.c \ + $(LOCAL_DIR)/src/time/timespec_get.c \ + $(LOCAL_DIR)/src/time/utime.c \ + $(LOCAL_DIR)/src/time/wcsftime.c \ + $(LOCAL_DIR)/src/unistd/_exit.c \ + $(LOCAL_DIR)/src/unistd/access.c \ + $(LOCAL_DIR)/src/unistd/acct.c \ + $(LOCAL_DIR)/src/unistd/alarm.c \ + $(LOCAL_DIR)/src/unistd/chdir.c \ + $(LOCAL_DIR)/src/unistd/chown.c \ + $(LOCAL_DIR)/src/unistd/close.c \ + $(LOCAL_DIR)/src/unistd/ctermid.c \ + $(LOCAL_DIR)/src/unistd/dup.c \ + $(LOCAL_DIR)/src/unistd/dup2.c \ + $(LOCAL_DIR)/src/unistd/dup3.c \ + $(LOCAL_DIR)/src/unistd/faccessat.c \ + $(LOCAL_DIR)/src/unistd/fchdir.c \ + $(LOCAL_DIR)/src/unistd/fchown.c \ + $(LOCAL_DIR)/src/unistd/fchownat.c \ + $(LOCAL_DIR)/src/unistd/fdatasync.c \ + $(LOCAL_DIR)/src/unistd/fsync.c \ + $(LOCAL_DIR)/src/unistd/ftruncate.c \ + $(LOCAL_DIR)/src/unistd/getcwd.c \ + $(LOCAL_DIR)/src/unistd/getegid.c \ + $(LOCAL_DIR)/src/unistd/geteuid.c \ + $(LOCAL_DIR)/src/unistd/getgid.c \ + $(LOCAL_DIR)/src/unistd/getgroups.c \ + $(LOCAL_DIR)/src/unistd/gethostname.c \ + $(LOCAL_DIR)/src/unistd/getlogin.c \ + $(LOCAL_DIR)/src/unistd/getlogin_r.c \ + $(LOCAL_DIR)/src/unistd/getpgid.c \ + $(LOCAL_DIR)/src/unistd/getpgrp.c \ + $(LOCAL_DIR)/src/unistd/getpid.c \ + $(LOCAL_DIR)/src/unistd/getppid.c \ + $(LOCAL_DIR)/src/unistd/getsid.c \ + $(LOCAL_DIR)/src/unistd/getuid.c \ + $(LOCAL_DIR)/src/unistd/isatty.c \ + $(LOCAL_DIR)/src/unistd/lchown.c \ + $(LOCAL_DIR)/src/unistd/link.c \ + $(LOCAL_DIR)/src/unistd/linkat.c \ + $(LOCAL_DIR)/src/unistd/nice.c \ + $(LOCAL_DIR)/src/unistd/pause.c \ + $(LOCAL_DIR)/src/unistd/pipe2.c \ + $(LOCAL_DIR)/src/unistd/posix_close.c \ + $(LOCAL_DIR)/src/unistd/pread.c \ + $(LOCAL_DIR)/src/unistd/preadv.c \ + $(LOCAL_DIR)/src/unistd/pwrite.c \ + $(LOCAL_DIR)/src/unistd/pwritev.c \ + $(LOCAL_DIR)/src/unistd/readlink.c \ + $(LOCAL_DIR)/src/unistd/readlinkat.c \ + $(LOCAL_DIR)/src/unistd/readv.c \ + $(LOCAL_DIR)/src/unistd/renameat.c \ + $(LOCAL_DIR)/src/unistd/rmdir.c \ + $(LOCAL_DIR)/src/unistd/setegid.c \ + $(LOCAL_DIR)/src/unistd/seteuid.c \ + $(LOCAL_DIR)/src/unistd/setgid.c \ + $(LOCAL_DIR)/src/unistd/setpgid.c \ + $(LOCAL_DIR)/src/unistd/setpgrp.c \ + $(LOCAL_DIR)/src/unistd/setregid.c \ + $(LOCAL_DIR)/src/unistd/setresgid.c \ + $(LOCAL_DIR)/src/unistd/setresuid.c \ + $(LOCAL_DIR)/src/unistd/setreuid.c \ + $(LOCAL_DIR)/src/unistd/setsid.c \ + $(LOCAL_DIR)/src/unistd/setuid.c \ + $(LOCAL_DIR)/src/unistd/setxid.c \ + $(LOCAL_DIR)/src/unistd/sleep.c \ + $(LOCAL_DIR)/src/unistd/symlink.c \ + $(LOCAL_DIR)/src/unistd/symlinkat.c \ + $(LOCAL_DIR)/src/unistd/sync.c \ + $(LOCAL_DIR)/src/unistd/tcgetpgrp.c \ + $(LOCAL_DIR)/src/unistd/tcsetpgrp.c \ + $(LOCAL_DIR)/src/unistd/truncate.c \ + $(LOCAL_DIR)/src/unistd/ttyname.c \ + $(LOCAL_DIR)/src/unistd/ttyname_r.c \ + $(LOCAL_DIR)/src/unistd/ualarm.c \ + $(LOCAL_DIR)/src/unistd/unlink.c \ + $(LOCAL_DIR)/src/unistd/unlinkat.c \ + $(LOCAL_DIR)/src/unistd/usleep.c \ + $(LOCAL_DIR)/src/unistd/writev.c \ + $(LOCAL_DIR)/third_party/math/__cos.c \ + $(LOCAL_DIR)/third_party/math/__cosdf.c \ + $(LOCAL_DIR)/third_party/math/__cosl.c \ + $(LOCAL_DIR)/third_party/math/__polevll.c \ + $(LOCAL_DIR)/third_party/math/__rem_pio2.c \ + $(LOCAL_DIR)/third_party/math/__rem_pio2_large.c \ + $(LOCAL_DIR)/third_party/math/__rem_pio2f.c \ + $(LOCAL_DIR)/third_party/math/__rem_pio2l.c \ + $(LOCAL_DIR)/third_party/math/__sin.c \ + $(LOCAL_DIR)/third_party/math/__sindf.c \ + $(LOCAL_DIR)/third_party/math/__sinl.c \ + $(LOCAL_DIR)/third_party/math/__tan.c \ + $(LOCAL_DIR)/third_party/math/__tandf.c \ + $(LOCAL_DIR)/third_party/math/__tanl.c \ + $(LOCAL_DIR)/third_party/math/acos.c \ + $(LOCAL_DIR)/third_party/math/acosf.c \ + $(LOCAL_DIR)/third_party/math/asin.c \ + $(LOCAL_DIR)/third_party/math/asinf.c \ + $(LOCAL_DIR)/third_party/math/atan.c \ + $(LOCAL_DIR)/third_party/math/atan2.c \ + $(LOCAL_DIR)/third_party/math/atan2f.c \ + $(LOCAL_DIR)/third_party/math/atanf.c \ + $(LOCAL_DIR)/third_party/math/cbrt.c \ + $(LOCAL_DIR)/third_party/math/cbrtf.c \ + $(LOCAL_DIR)/third_party/math/cbrtl.c \ + $(LOCAL_DIR)/third_party/math/cos.c \ + $(LOCAL_DIR)/third_party/math/cosf.c \ + $(LOCAL_DIR)/third_party/math/erf.c \ + $(LOCAL_DIR)/third_party/math/erff.c \ + $(LOCAL_DIR)/third_party/math/erfl.c \ + $(LOCAL_DIR)/third_party/math/exp.c \ + $(LOCAL_DIR)/third_party/math/exp2.c \ + $(LOCAL_DIR)/third_party/math/exp2f.c \ + $(LOCAL_DIR)/third_party/math/expf.c \ + $(LOCAL_DIR)/third_party/math/expm1.c \ + $(LOCAL_DIR)/third_party/math/expm1f.c \ + $(LOCAL_DIR)/third_party/math/fma.c \ + $(LOCAL_DIR)/third_party/math/fmaf.c \ + $(LOCAL_DIR)/third_party/math/fmal.c \ + $(LOCAL_DIR)/third_party/math/j0.c \ + $(LOCAL_DIR)/third_party/math/j0f.c \ + $(LOCAL_DIR)/third_party/math/j1.c \ + $(LOCAL_DIR)/third_party/math/j1f.c \ + $(LOCAL_DIR)/third_party/math/jn.c \ + $(LOCAL_DIR)/third_party/math/jnf.c \ + $(LOCAL_DIR)/third_party/math/lgamma_r.c \ + $(LOCAL_DIR)/third_party/math/lgammaf_r.c \ + $(LOCAL_DIR)/third_party/math/lgammal.c \ + $(LOCAL_DIR)/third_party/math/log.c \ + $(LOCAL_DIR)/third_party/math/log10.c \ + $(LOCAL_DIR)/third_party/math/log10f.c \ + $(LOCAL_DIR)/third_party/math/log1p.c \ + $(LOCAL_DIR)/third_party/math/log1pf.c \ + $(LOCAL_DIR)/third_party/math/log2.c \ + $(LOCAL_DIR)/third_party/math/log2f.c \ + $(LOCAL_DIR)/third_party/math/logf.c \ + $(LOCAL_DIR)/third_party/math/pow.c \ + $(LOCAL_DIR)/third_party/math/powf.c \ + $(LOCAL_DIR)/third_party/math/powl.c \ + $(LOCAL_DIR)/third_party/math/scalb.c \ + $(LOCAL_DIR)/third_party/math/scalbf.c \ + $(LOCAL_DIR)/third_party/math/sin.c \ + $(LOCAL_DIR)/third_party/math/sincos.c \ + $(LOCAL_DIR)/third_party/math/sincosf.c \ + $(LOCAL_DIR)/third_party/math/sinf.c \ + $(LOCAL_DIR)/third_party/math/tan.c \ + $(LOCAL_DIR)/third_party/math/tanf.c \ + $(LOCAL_DIR)/third_party/math/tgammal.c \ + +# Thef following are not built until we have mxio and libc standing in +# proper relation to each other. +# $(LOCAL_DIR)/src/stat/fstat.c \ +# $(LOCAL_DIR)/src/stat/stat.c \ +# $(LOCAL_DIR)/src/unistd/lseek.c \ +# $(LOCAL_DIR)/src/unistd/pipe.c \ +# $(LOCAL_DIR)/src/unistd/read.c \ +# $(LOCAL_DIR)/src/unistd/write.c \ + +# so mxio knows to use the new hooks +GLOBAL_CFLAGS += -DWITH_LIBC_IO_HOOKS + +ifeq ($(ARCH),arm64) +MODULE_SRCS += \ + $(LOCAL_DIR)/src/fenv/aarch64/fenv.s \ + $(LOCAL_DIR)/src/internal/syscall.c \ + $(LOCAL_DIR)/src/ldso/aarch64/dlsym.s \ + $(LOCAL_DIR)/src/ldso/aarch64/tlsdesc.s \ + $(LOCAL_DIR)/src/math/aarch64/fabs.s \ + $(LOCAL_DIR)/src/math/aarch64/fabsf.s \ + $(LOCAL_DIR)/src/math/aarch64/sqrt.s \ + $(LOCAL_DIR)/src/math/aarch64/sqrtf.s \ + $(LOCAL_DIR)/src/math/ceill.c \ + $(LOCAL_DIR)/src/math/fabsl.c \ + $(LOCAL_DIR)/src/math/floorl.c \ + $(LOCAL_DIR)/src/math/fmodl.c \ + $(LOCAL_DIR)/src/math/llrint.c \ + $(LOCAL_DIR)/src/math/llrintf.c \ + $(LOCAL_DIR)/src/math/llrintl.c \ + $(LOCAL_DIR)/src/math/lrint.c \ + $(LOCAL_DIR)/src/math/lrintf.c \ + $(LOCAL_DIR)/src/math/lrintl.c \ + $(LOCAL_DIR)/src/math/remainderl.c \ + $(LOCAL_DIR)/src/math/rintl.c \ + $(LOCAL_DIR)/src/math/sqrtl.c \ + $(LOCAL_DIR)/src/math/truncl.c \ + $(LOCAL_DIR)/src/process/vfork.c \ + $(LOCAL_DIR)/src/setjmp/aarch64/longjmp.s \ + $(LOCAL_DIR)/src/setjmp/aarch64/setjmp.s \ + $(LOCAL_DIR)/src/signal/aarch64/restore.s \ + $(LOCAL_DIR)/src/signal/aarch64/sigsetjmp.s \ + $(LOCAL_DIR)/src/thread/aarch64/__unmapself.s \ + $(LOCAL_DIR)/src/thread/aarch64/clone.s \ + $(LOCAL_DIR)/src/thread/aarch64/syscall_cp.s \ + $(LOCAL_DIR)/third_party/math/acosl.c \ + $(LOCAL_DIR)/third_party/math/asinl.c \ + $(LOCAL_DIR)/third_party/math/atan2l.c \ + $(LOCAL_DIR)/third_party/math/atanl.c \ + $(LOCAL_DIR)/third_party/math/exp2l.c \ + $(LOCAL_DIR)/third_party/math/expl.c \ + $(LOCAL_DIR)/third_party/math/expm1l.c \ + $(LOCAL_DIR)/third_party/math/log10l.c \ + $(LOCAL_DIR)/third_party/math/log1pl.c \ + $(LOCAL_DIR)/third_party/math/log2l.c \ + $(LOCAL_DIR)/third_party/math/logl.c \ + +else ifeq ($(ARCH),arm) +MODULE_SRCS += \ + $(LOCAL_DIR)/src/exit/arm/__aeabi_atexit.c \ + $(LOCAL_DIR)/src/fenv/arm/fenv-hf.S \ + $(LOCAL_DIR)/src/fenv/fenv.c \ + $(LOCAL_DIR)/src/internal/syscall.c \ + $(LOCAL_DIR)/src/ldso/arm/dlsym.s \ + $(LOCAL_DIR)/src/ldso/arm/find_exidx.c \ + $(LOCAL_DIR)/src/ldso/tlsdesc.c \ + $(LOCAL_DIR)/src/math/ceill.c \ + $(LOCAL_DIR)/src/math/fabs.c \ + $(LOCAL_DIR)/src/math/fabsf.c \ + $(LOCAL_DIR)/src/math/fabsl.c \ + $(LOCAL_DIR)/src/math/floorl.c \ + $(LOCAL_DIR)/src/math/fmodl.c \ + $(LOCAL_DIR)/src/math/llrint.c \ + $(LOCAL_DIR)/src/math/llrintf.c \ + $(LOCAL_DIR)/src/math/llrintl.c \ + $(LOCAL_DIR)/src/math/lrint.c \ + $(LOCAL_DIR)/src/math/lrintf.c \ + $(LOCAL_DIR)/src/math/lrintl.c \ + $(LOCAL_DIR)/src/math/remainderl.c \ + $(LOCAL_DIR)/src/math/rintl.c \ + $(LOCAL_DIR)/src/math/sqrtl.c \ + $(LOCAL_DIR)/src/math/truncl.c \ + $(LOCAL_DIR)/src/process/vfork.c \ + $(LOCAL_DIR)/src/setjmp/arm/longjmp.s \ + $(LOCAL_DIR)/src/setjmp/arm/setjmp.s \ + $(LOCAL_DIR)/src/signal/arm/restore.s \ + $(LOCAL_DIR)/src/signal/arm/sigsetjmp.s \ + $(LOCAL_DIR)/src/thread/arm/__unmapself.s \ + $(LOCAL_DIR)/src/thread/arm/atomics.s \ + $(LOCAL_DIR)/src/thread/arm/clone.s \ + $(LOCAL_DIR)/src/thread/arm/syscall_cp.s \ + $(LOCAL_DIR)/third_party/math/acosl.c \ + $(LOCAL_DIR)/third_party/math/asinl.c \ + $(LOCAL_DIR)/third_party/math/atan2l.c \ + $(LOCAL_DIR)/third_party/math/atanl.c \ + $(LOCAL_DIR)/third_party/math/exp2l.c \ + $(LOCAL_DIR)/third_party/math/expl.c \ + $(LOCAL_DIR)/third_party/math/expm1l.c \ + $(LOCAL_DIR)/third_party/math/log10l.c \ + $(LOCAL_DIR)/third_party/math/log1pl.c \ + $(LOCAL_DIR)/third_party/math/log2l.c \ + $(LOCAL_DIR)/third_party/math/logl.c \ + $(LOCAL_DIR)/third_party/math/sqrt.c \ + $(LOCAL_DIR)/third_party/math/sqrtf.c \ + +else ifeq ($(SUBARCH),x86-64) +MODULE_SRCS += \ + $(LOCAL_DIR)/src/fenv/x86_64/fenv.s \ + $(LOCAL_DIR)/src/ldso/x86_64/dlsym.s \ + $(LOCAL_DIR)/src/ldso/x86_64/tlsdesc.s \ + $(LOCAL_DIR)/src/math/x86_64/__invtrigl.s \ + $(LOCAL_DIR)/src/math/x86_64/acosl.s \ + $(LOCAL_DIR)/src/math/x86_64/asinl.s \ + $(LOCAL_DIR)/src/math/x86_64/atan2l.s \ + $(LOCAL_DIR)/src/math/x86_64/atanl.s \ + $(LOCAL_DIR)/src/math/x86_64/ceill.s \ + $(LOCAL_DIR)/src/math/x86_64/exp2l.s \ + $(LOCAL_DIR)/src/math/x86_64/expl.s \ + $(LOCAL_DIR)/src/math/x86_64/expm1l.s \ + $(LOCAL_DIR)/src/math/x86_64/fabs.s \ + $(LOCAL_DIR)/src/math/x86_64/fabsf.s \ + $(LOCAL_DIR)/src/math/x86_64/fabsl.s \ + $(LOCAL_DIR)/src/math/x86_64/floorl.s \ + $(LOCAL_DIR)/src/math/x86_64/fmodl.s \ + $(LOCAL_DIR)/src/math/x86_64/llrint.s \ + $(LOCAL_DIR)/src/math/x86_64/llrintf.s \ + $(LOCAL_DIR)/src/math/x86_64/llrintl.s \ + $(LOCAL_DIR)/src/math/x86_64/log10l.s \ + $(LOCAL_DIR)/src/math/x86_64/log1pl.s \ + $(LOCAL_DIR)/src/math/x86_64/log2l.s \ + $(LOCAL_DIR)/src/math/x86_64/logl.s \ + $(LOCAL_DIR)/src/math/x86_64/lrint.s \ + $(LOCAL_DIR)/src/math/x86_64/lrintf.s \ + $(LOCAL_DIR)/src/math/x86_64/lrintl.s \ + $(LOCAL_DIR)/src/math/x86_64/remainderl.s \ + $(LOCAL_DIR)/src/math/x86_64/rintl.s \ + $(LOCAL_DIR)/src/math/x86_64/sqrt.s \ + $(LOCAL_DIR)/src/math/x86_64/sqrtf.s \ + $(LOCAL_DIR)/src/math/x86_64/sqrtl.s \ + $(LOCAL_DIR)/src/math/x86_64/truncl.s \ + $(LOCAL_DIR)/src/process/x86_64/vfork.s \ + $(LOCAL_DIR)/src/signal/x86_64/restore.s \ + $(LOCAL_DIR)/src/signal/x86_64/sigsetjmp.s \ + $(LOCAL_DIR)/third_party/arch/x86_64/__unmapself.s \ + $(LOCAL_DIR)/src/thread/x86_64/clone.s \ + $(LOCAL_DIR)/src/thread/x86_64/syscall_cp.s \ + $(LOCAL_DIR)/third_party/arch/x86_64/longjmp.s \ + $(LOCAL_DIR)/third_party/arch/x86_64/setjmp.s \ + +else +error Unsupported architecture for musl build! + +endif + +# Include src/string sources +include $(LOCAL_DIR)/src/string/rules.mk + +# Include crt sources +include $(LOCAL_DIR)/crt/rules.mk + +include make/module.mk diff --git a/third_party/ulib/musl/src/aio/BUILD.gn b/third_party/ulib/musl/src/aio/BUILD.gn new file mode 100644 index 000000000..969c39081 --- /dev/null +++ b/third_party/ulib/musl/src/aio/BUILD.gn @@ -0,0 +1,11 @@ +source_set("aio") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "aio.c", + "aio_suspend.c", + "lio_listio.c", + ] +} diff --git a/third_party/ulib/musl/src/aio/aio.c b/third_party/ulib/musl/src/aio/aio.c new file mode 100644 index 000000000..c04646471 --- /dev/null +++ b/third_party/ulib/musl/src/aio/aio.c @@ -0,0 +1,366 @@ +#include "atomic.h" +#include "libc.h" +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include +#include +#include +#include +#include + +/* The following is a threads-based implementation of AIO with minimal + * dependence on implementation details. Most synchronization is + * performed with pthread primitives, but atomics and futex operations + * are used for notification in a couple places where the pthread + * primitives would be inefficient or impractical. + * + * For each fd with outstanding aio operations, an aio_queue structure + * is maintained. These are reference-counted and destroyed by the last + * aio worker thread to exit. Accessing any member of the aio_queue + * structure requires a lock on the aio_queue. Adding and removing aio + * queues themselves requires a write lock on the global map object, + * a 4-level table mapping file descriptor numbers to aio queues. A + * read lock on the map is used to obtain locks on existing queues by + * excluding destruction of the queue by a different thread while it is + * being locked. + * + * Each aio queue has a list of active threads/operations. Presently there + * is a one to one relationship between threads and operations. The only + * members of the aio_thread structure which are accessed by other threads + * are the linked list pointers, op (which is immutable), running (which + * is updated atomically), and err (which is synchronized via running), + * so no locking is necessary. Most of the other other members are used + * for sharing data between the main flow of execution and cancellation + * cleanup handler. + * + * Taking any aio locks requires having all signals blocked. This is + * necessary because aio_cancel is needed by close, and close is required + * to be async-signal safe. All aio worker threads run with all signals + * blocked permanently. + */ + +struct aio_args { + struct aiocb* cb; + int op; + int err; + sem_t sem; +}; + +struct aio_thread { + pthread_t td; + struct aiocb* cb; + struct aio_thread *next, *prev; + struct aio_queue* q; + volatile int running; + int err, op; + ssize_t ret; +}; + +struct aio_queue { + int fd, seekable, append, ref, init; + pthread_mutex_t lock; + pthread_cond_t cond; + struct aio_thread* head; +}; + +static pthread_rwlock_t maplock = PTHREAD_RWLOCK_INITIALIZER; +static struct aio_queue***** map; +static volatile int aio_fd_cnt; +volatile int __aio_fut; + +static struct aio_queue* __aio_get_queue(int fd, int need) { + if (fd < 0) return 0; + int a = fd >> 24; + unsigned char b = fd >> 16, c = fd >> 8, d = fd; + struct aio_queue* q = 0; + pthread_rwlock_rdlock(&maplock); + if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q = map[a][b][c][d])) && need) { + pthread_rwlock_unlock(&maplock); + pthread_rwlock_wrlock(&maplock); + if (!map) map = calloc(sizeof *map, (-1U / 2 + 1) >> 24); + if (!map) goto out; + if (!map[a]) map[a] = calloc(sizeof **map, 256); + if (!map[a]) goto out; + if (!map[a][b]) map[a][b] = calloc(sizeof ***map, 256); + if (!map[a][b]) goto out; + if (!map[a][b][c]) map[a][b][c] = calloc(sizeof ****map, 256); + if (!map[a][b][c]) goto out; + if (!(q = map[a][b][c][d])) { + map[a][b][c][d] = q = calloc(sizeof *****map, 1); + if (q) { + q->fd = fd; + pthread_mutex_init(&q->lock, 0); + pthread_cond_init(&q->cond, 0); + a_inc(&aio_fd_cnt); + } + } + } + if (q) pthread_mutex_lock(&q->lock); +out: + pthread_rwlock_unlock(&maplock); + return q; +} + +static void __aio_unref_queue(struct aio_queue* q) { + if (q->ref > 1) { + q->ref--; + pthread_mutex_unlock(&q->lock); + return; + } + + /* This is potentially the last reference, but a new reference + * may arrive since we cannot free the queue object without first + * taking the maplock, which requires releasing the queue lock. */ + pthread_mutex_unlock(&q->lock); + pthread_rwlock_wrlock(&maplock); + pthread_mutex_lock(&q->lock); + if (q->ref == 1) { + int fd = q->fd; + int a = fd >> 24; + unsigned char b = fd >> 16, c = fd >> 8, d = fd; + map[a][b][c][d] = 0; + a_dec(&aio_fd_cnt); + pthread_rwlock_unlock(&maplock); + pthread_mutex_unlock(&q->lock); + free(q); + } else { + q->ref--; + pthread_rwlock_unlock(&maplock); + pthread_mutex_unlock(&q->lock); + } +} + +static void cleanup(void* ctx) { + struct aio_thread* at = ctx; + struct aio_queue* q = at->q; + struct aiocb* cb = at->cb; + struct sigevent sev = cb->aio_sigevent; + + /* There are four potential types of waiters we could need to wake: + * 1. Callers of aio_cancel/close. + * 2. Callers of aio_suspend with a single aiocb. + * 3. Callers of aio_suspend with a list. + * 4. AIO worker threads waiting for sequenced operations. + * Types 1-3 are notified via atomics/futexes, mainly for AS-safety + * considerations. Type 4 is notified later via a cond var. */ + + cb->__ret = at->ret; + if (a_swap(&at->running, 0) < 0) __wake(&at->running, -1); + if (a_swap(&cb->__err, at->err) != EINPROGRESS) __wake(&cb->__err, -1); + if (a_swap(&__aio_fut, 0)) __wake(&__aio_fut, -1); + + pthread_mutex_lock(&q->lock); + + if (at->next) at->next->prev = at->prev; + if (at->prev) + at->prev->next = at->next; + else + q->head = at->next; + + /* Signal aio worker threads waiting for sequenced operations. */ + pthread_cond_broadcast(&q->cond); + + __aio_unref_queue(q); + + if (sev.sigev_notify == SIGEV_SIGNAL) { + siginfo_t si = {.si_signo = sev.sigev_signo, + .si_value = sev.sigev_value, + .si_code = SI_ASYNCIO, + .si_pid = getpid(), + .si_uid = getuid()}; + __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si); + } + if (sev.sigev_notify == SIGEV_THREAD) { + a_store(&__pthread_self()->cancel, 0); + sev.sigev_notify_function(sev.sigev_value); + } +} + +static void* io_thread_func(void* ctx) { + struct aio_thread at, *p; + + struct aio_args* args = ctx; + struct aiocb* cb = args->cb; + int fd = cb->aio_fildes; + int op = args->op; + void* buf = (void*)cb->aio_buf; + size_t len = cb->aio_nbytes; + off_t off = cb->aio_offset; + + struct aio_queue* q = __aio_get_queue(fd, 1); + ssize_t ret; + + args->err = q ? 0 : EAGAIN; + sem_post(&args->sem); + if (!q) return 0; + + at.op = op; + at.running = 1; + at.ret = -1; + at.err = ECANCELED; + at.q = q; + at.td = __pthread_self(); + at.cb = cb; + at.prev = 0; + if ((at.next = q->head)) at.next->prev = &at; + q->head = &at; + q->ref++; + + if (!q->init) { + int seekable = lseek(fd, 0, SEEK_CUR) >= 0; + q->seekable = seekable; + q->append = !seekable || (fcntl(fd, F_GETFL) & O_APPEND); + q->init = 1; + } + + pthread_cleanup_push(cleanup, &at); + + /* Wait for sequenced operations. */ + if (op != LIO_READ && (op != LIO_WRITE || q->append)) { + for (;;) { + for (p = at.next; p && p->op != LIO_WRITE; p = p->next) + ; + if (!p) break; + pthread_cond_wait(&q->cond, &q->lock); + } + } + + pthread_mutex_unlock(&q->lock); + + switch (op) { + case LIO_WRITE: + ret = q->append ? write(fd, buf, len) : pwrite(fd, buf, len, off); + break; + case LIO_READ: + ret = !q->seekable ? read(fd, buf, len) : pread(fd, buf, len, off); + break; + case O_SYNC: + ret = fsync(fd); + break; + case O_DSYNC: + ret = fdatasync(fd); + break; + } + at.ret = ret; + at.err = ret < 0 ? errno : 0; + + pthread_cleanup_pop(1); + + return 0; +} + +static int submit(struct aiocb* cb, int op) { + int ret = 0; + pthread_attr_t a; + sigset_t allmask, origmask; + pthread_t td; + struct aio_args args = {.cb = cb, .op = op}; + sem_init(&args.sem, 0, 0); + + if (cb->aio_sigevent.sigev_notify == SIGEV_THREAD) { + if (cb->aio_sigevent.sigev_notify_attributes) + a = *cb->aio_sigevent.sigev_notify_attributes; + else + pthread_attr_init(&a); + } else { + pthread_attr_init(&a); + pthread_attr_setstacksize(&a, PTHREAD_STACK_MIN); + pthread_attr_setguardsize(&a, 0); + } + pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); + sigfillset(&allmask); + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); + cb->__err = EINPROGRESS; + if (pthread_create(&td, &a, io_thread_func, &args)) { + errno = EAGAIN; + ret = -1; + } + pthread_sigmask(SIG_SETMASK, &origmask, 0); + + if (!ret) { + while (sem_wait(&args.sem)) + ; + if (args.err) { + errno = args.err; + ret = -1; + } + } + + return ret; +} + +int aio_read(struct aiocb* cb) { + return submit(cb, LIO_READ); +} + +int aio_write(struct aiocb* cb) { + return submit(cb, LIO_WRITE); +} + +int aio_fsync(int op, struct aiocb* cb) { + if (op != O_SYNC && op != O_DSYNC) { + errno = EINVAL; + return -1; + } + return submit(cb, op); +} + +ssize_t aio_return(struct aiocb* cb) { + return cb->__ret; +} + +int aio_error(const struct aiocb* cb) { + a_barrier(); + return cb->__err & 0x7fffffff; +} + +int aio_cancel(int fd, struct aiocb* cb) { + sigset_t allmask, origmask; + int ret = AIO_ALLDONE; + struct aio_thread* p; + struct aio_queue* q; + + /* Unspecified behavior case. Report an error. */ + if (cb && fd != cb->aio_fildes) { + errno = EINVAL; + return -1; + } + + sigfillset(&allmask); + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); + + if (!(q = __aio_get_queue(fd, 0))) { + if (fcntl(fd, F_GETFD) < 0) ret = -1; + goto done; + } + + for (p = q->head; p; p = p->next) { + if (cb && cb != p->cb) continue; + /* Transition target from running to running-with-waiters */ + if (a_cas(&p->running, 1, -1)) { + pthread_cancel(p->td); + __wait(&p->running, 0, -1); + if (p->err == ECANCELED) ret = AIO_CANCELED; + } + } + + pthread_mutex_unlock(&q->lock); +done: + pthread_sigmask(SIG_SETMASK, &origmask, 0); + return ret; +} + +int __aio_close(int fd) { + a_barrier(); + if (aio_fd_cnt) aio_cancel(fd, 0); + return fd; +} + +LFS64(aio_cancel); +LFS64(aio_error); +LFS64(aio_fsync); +LFS64(aio_read); +LFS64(aio_write); +LFS64(aio_return); diff --git a/third_party/ulib/musl/src/aio/aio_suspend.c b/third_party/ulib/musl/src/aio/aio_suspend.c new file mode 100644 index 000000000..aa022fc16 --- /dev/null +++ b/third_party/ulib/musl/src/aio/aio_suspend.c @@ -0,0 +1,77 @@ +#include "atomic.h" +#include "libc.h" +#include "pthread_impl.h" +#include +#include +#include + +extern volatile int __aio_fut; + +int aio_suspend(const struct aiocb* const cbs[], int cnt, const struct timespec* ts) { + int i, tid = 0, ret, expect = 0; + struct timespec at; + volatile int dummy_fut, *pfut; + int nzcnt = 0; + const struct aiocb* cb = 0; + + pthread_testcancel(); + + if (cnt < 0) { + errno = EINVAL; + return -1; + } + + for (i = 0; i < cnt; i++) + if (cbs[i]) { + if (aio_error(cbs[i]) != EINPROGRESS) return 0; + nzcnt++; + cb = cbs[i]; + } + + if (ts) { + clock_gettime(CLOCK_MONOTONIC, &at); + at.tv_sec += ts->tv_sec; + if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) { + at.tv_nsec -= 1000000000; + at.tv_sec++; + } + } + + for (;;) { + for (i = 0; i < cnt; i++) + if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS) return 0; + + switch (nzcnt) { + case 0: + pfut = &dummy_fut; + break; + case 1: + pfut = (void*)&cb->__err; + expect = EINPROGRESS | 0x80000000; + a_cas(pfut, EINPROGRESS, expect); + break; + default: + pfut = &__aio_fut; + if (!tid) tid = __pthread_self()->tid; + expect = a_cas(pfut, 0, tid); + if (!expect) expect = tid; + /* Need to recheck the predicate before waiting. */ + for (i = 0; i < cnt; i++) + if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS) return 0; + break; + } + + ret = __timedwait_cp(pfut, expect, CLOCK_MONOTONIC, ts ? &at : 0); + + switch (ret) { + case ETIMEDOUT: + ret = EAGAIN; + case ECANCELED: + case EINTR: + errno = ret; + return -1; + } + } +} + +LFS64(aio_suspend); diff --git a/third_party/ulib/musl/src/aio/lio_listio.c b/third_party/ulib/musl/src/aio/lio_listio.c new file mode 100644 index 000000000..e4ac8591c --- /dev/null +++ b/third_party/ulib/musl/src/aio/lio_listio.c @@ -0,0 +1,137 @@ +#include "libc.h" +#include "pthread_impl.h" +#include +#include +#include +#include + +struct lio_state { + struct sigevent* sev; + int cnt; + struct aiocb* cbs[]; +}; + +static int lio_wait(struct lio_state* st) { + int i, err, got_err = 0; + int cnt = st->cnt; + struct aiocb** cbs = st->cbs; + + for (;;) { + for (i = 0; i < cnt; i++) { + if (!cbs[i]) continue; + err = aio_error(cbs[i]); + if (err == EINPROGRESS) break; + if (err) got_err = 1; + cbs[i] = 0; + } + if (i == cnt) { + if (got_err) { + errno = EIO; + return -1; + } + return 0; + } + if (aio_suspend((void*)cbs, cnt, 0)) return -1; + } +} + +static void notify_signal(struct sigevent* sev) { + siginfo_t si = {.si_signo = sev->sigev_signo, + .si_value = sev->sigev_value, + .si_code = SI_ASYNCIO, + .si_pid = getpid(), + .si_uid = getuid()}; + __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si); +} + +static void* wait_thread(void* p) { + struct lio_state* st = p; + struct sigevent* sev = st->sev; + lio_wait(st); + free(st); + switch (sev->sigev_notify) { + case SIGEV_SIGNAL: + notify_signal(sev); + break; + case SIGEV_THREAD: + sev->sigev_notify_function(sev->sigev_value); + break; + } + return 0; +} + +int lio_listio(int mode, struct aiocb* restrict const* restrict cbs, int cnt, + struct sigevent* restrict sev) { + int i, ret; + struct lio_state* st = 0; + + if (cnt < 0) { + errno = EINVAL; + return -1; + } + + if (mode == LIO_WAIT || (sev && sev->sigev_notify != SIGEV_NONE)) { + if (!(st = malloc(sizeof *st + cnt * sizeof *cbs))) { + errno = EAGAIN; + return -1; + } + st->cnt = cnt; + st->sev = sev; + memcpy(st->cbs, (void*)cbs, cnt * sizeof *cbs); + } + + for (i = 0; i < cnt; i++) { + if (!cbs[i]) continue; + switch (cbs[i]->aio_lio_opcode) { + case LIO_READ: + ret = aio_read(cbs[i]); + break; + case LIO_WRITE: + ret = aio_write(cbs[i]); + break; + default: + continue; + } + if (ret) { + free(st); + errno = EAGAIN; + return -1; + } + } + + if (mode == LIO_WAIT) { + ret = lio_wait(st); + free(st); + return ret; + } + + if (st) { + pthread_attr_t a; + sigset_t set; + pthread_t td; + + if (sev->sigev_notify == SIGEV_THREAD) { + if (sev->sigev_notify_attributes) + a = *sev->sigev_notify_attributes; + else + pthread_attr_init(&a); + } else { + pthread_attr_init(&a); + pthread_attr_setstacksize(&a, PAGE_SIZE); + pthread_attr_setguardsize(&a, 0); + } + pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); + sigfillset(&set); + pthread_sigmask(SIG_BLOCK, &set, &set); + if (pthread_create(&td, &a, wait_thread, st)) { + free(st); + errno = EAGAIN; + return -1; + } + pthread_sigmask(SIG_SETMASK, &set, 0); + } + + return 0; +} + +LFS64(lio_listio); diff --git a/third_party/ulib/musl/src/complex/BUILD.gn b/third_party/ulib/musl/src/complex/BUILD.gn new file mode 100644 index 000000000..b6f2db669 --- /dev/null +++ b/third_party/ulib/musl/src/complex/BUILD.gn @@ -0,0 +1,61 @@ +source_set("complex") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "cabs.c", + "cabsf.c", + "cabsl.c", + "cacos.c", + "cacosf.c", + "cacosh.c", + "cacoshf.c", + "cacoshl.c", + "cacosl.c", + "carg.c", + "cargf.c", + "cargl.c", + "casin.c", + "casinf.c", + "casinh.c", + "casinhf.c", + "casinhl.c", + "casinl.c", + "catanh.c", + "catanhf.c", + "catanhl.c", + "ccos.c", + "ccosf.c", + "ccoshl.c", + "ccosl.c", + "cexpl.c", + "cimag.c", + "cimagf.c", + "cimagl.c", + "clog.c", + "clogf.c", + "clogl.c", + "conj.c", + "conjf.c", + "conjl.c", + "cpow.c", + "cpowf.c", + "cpowl.c", + "cproj.c", + "cprojf.c", + "cprojl.c", + "creal.c", + "crealf.c", + "creall.c", + "csin.c", + "csinf.c", + "csinhl.c", + "csinl.c", + "csqrtl.c", + "ctan.c", + "ctanf.c", + "ctanhl.c", + "ctanl.c", + ] +} diff --git a/third_party/ulib/musl/src/complex/cabs.c b/third_party/ulib/musl/src/complex/cabs.c new file mode 100644 index 000000000..9b67c777b --- /dev/null +++ b/third_party/ulib/musl/src/complex/cabs.c @@ -0,0 +1,5 @@ +#include "libm.h" + +double cabs(double complex z) { + return hypot(creal(z), cimag(z)); +} diff --git a/third_party/ulib/musl/src/complex/cabsf.c b/third_party/ulib/musl/src/complex/cabsf.c new file mode 100644 index 000000000..4096a1a32 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cabsf.c @@ -0,0 +1,5 @@ +#include "libm.h" + +float cabsf(float complex z) { + return hypotf(crealf(z), cimagf(z)); +} diff --git a/third_party/ulib/musl/src/complex/cabsl.c b/third_party/ulib/musl/src/complex/cabsl.c new file mode 100644 index 000000000..330e5dc67 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cabsl.c @@ -0,0 +1,11 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cabsl(long double complex z) { + return cabs(z); +} +#else +long double cabsl(long double complex z) { + return hypotl(creall(z), cimagl(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/cacos.c b/third_party/ulib/musl/src/complex/cacos.c new file mode 100644 index 000000000..263850a1a --- /dev/null +++ b/third_party/ulib/musl/src/complex/cacos.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME: Hull et al. "Implementing the complex arcsine and arccosine functions using exception +// handling" 1997 + +/* acos(z) = pi/2 - asin(z) */ + +double complex cacos(double complex z) { + z = casin(z); + return CMPLX(M_PI_2 - creal(z), -cimag(z)); +} diff --git a/third_party/ulib/musl/src/complex/cacosf.c b/third_party/ulib/musl/src/complex/cacosf.c new file mode 100644 index 000000000..57f485906 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cacosf.c @@ -0,0 +1,8 @@ +#include "libm.h" + +// FIXME + +float complex cacosf(float complex z) { + z = casinf(z); + return CMPLXF((float)M_PI_2 - crealf(z), -cimagf(z)); +} diff --git a/third_party/ulib/musl/src/complex/cacosh.c b/third_party/ulib/musl/src/complex/cacosh.c new file mode 100644 index 000000000..a1bc8b74f --- /dev/null +++ b/third_party/ulib/musl/src/complex/cacosh.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* acosh(z) = i acos(z) */ + +double complex cacosh(double complex z) { + z = cacos(z); + return CMPLX(-cimag(z), creal(z)); +} diff --git a/third_party/ulib/musl/src/complex/cacoshf.c b/third_party/ulib/musl/src/complex/cacoshf.c new file mode 100644 index 000000000..865123874 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cacoshf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex cacoshf(float complex z) { + z = cacosf(z); + return CMPLXF(-cimagf(z), crealf(z)); +} diff --git a/third_party/ulib/musl/src/complex/cacoshl.c b/third_party/ulib/musl/src/complex/cacoshl.c new file mode 100644 index 000000000..2384f866c --- /dev/null +++ b/third_party/ulib/musl/src/complex/cacoshl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cacoshl(long double complex z) { + return cacosh(z); +} +#else +long double complex cacoshl(long double complex z) { + z = cacosl(z); + return CMPLXL(-cimagl(z), creall(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/cacosl.c b/third_party/ulib/musl/src/complex/cacosl.c new file mode 100644 index 000000000..27f8fc227 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cacosl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cacosl(long double complex z) { + return cacos(z); +} +#else +// FIXME +#define PI_2 1.57079632679489661923132169163975144L +long double complex cacosl(long double complex z) { + z = casinl(z); + return CMPLXL(PI_2 - creall(z), -cimagl(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/carg.c b/third_party/ulib/musl/src/complex/carg.c new file mode 100644 index 000000000..0d5541236 --- /dev/null +++ b/third_party/ulib/musl/src/complex/carg.c @@ -0,0 +1,5 @@ +#include "libm.h" + +double carg(double complex z) { + return atan2(cimag(z), creal(z)); +} diff --git a/third_party/ulib/musl/src/complex/cargf.c b/third_party/ulib/musl/src/complex/cargf.c new file mode 100644 index 000000000..4e243a0dd --- /dev/null +++ b/third_party/ulib/musl/src/complex/cargf.c @@ -0,0 +1,5 @@ +#include "libm.h" + +float cargf(float complex z) { + return atan2f(cimagf(z), crealf(z)); +} diff --git a/third_party/ulib/musl/src/complex/cargl.c b/third_party/ulib/musl/src/complex/cargl.c new file mode 100644 index 000000000..d6b08a476 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cargl.c @@ -0,0 +1,11 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cargl(long double complex z) { + return carg(z); +} +#else +long double cargl(long double complex z) { + return atan2l(cimagl(z), creall(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/casin.c b/third_party/ulib/musl/src/complex/casin.c new file mode 100644 index 000000000..cc568819e --- /dev/null +++ b/third_party/ulib/musl/src/complex/casin.c @@ -0,0 +1,15 @@ +#include "libm.h" + +// FIXME + +/* asin(z) = -i log(i z + sqrt(1 - z*z)) */ + +double complex casin(double complex z) { + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = CMPLX(1.0 - (x - y) * (x + y), -2.0 * x * y); + return clog(CMPLX(-y, x) + csqrt(w)); +} diff --git a/third_party/ulib/musl/src/complex/casinf.c b/third_party/ulib/musl/src/complex/casinf.c new file mode 100644 index 000000000..c591fef00 --- /dev/null +++ b/third_party/ulib/musl/src/complex/casinf.c @@ -0,0 +1,13 @@ +#include "libm.h" + +// FIXME + +float complex casinf(float complex z) { + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = CMPLXF(1.0 - (x - y) * (x + y), -2.0 * x * y); + return clogf(CMPLXF(-y, x) + csqrtf(w)); +} diff --git a/third_party/ulib/musl/src/complex/casinh.c b/third_party/ulib/musl/src/complex/casinh.c new file mode 100644 index 000000000..e1c918307 --- /dev/null +++ b/third_party/ulib/musl/src/complex/casinh.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* asinh(z) = -i asin(i z) */ + +double complex casinh(double complex z) { + z = casin(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/third_party/ulib/musl/src/complex/casinhf.c b/third_party/ulib/musl/src/complex/casinhf.c new file mode 100644 index 000000000..802cd8eba --- /dev/null +++ b/third_party/ulib/musl/src/complex/casinhf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex casinhf(float complex z) { + z = casinf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/third_party/ulib/musl/src/complex/casinhl.c b/third_party/ulib/musl/src/complex/casinhl.c new file mode 100644 index 000000000..6b6ac607f --- /dev/null +++ b/third_party/ulib/musl/src/complex/casinhl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex casinhl(long double complex z) { + return casinh(z); +} +#else +long double complex casinhl(long double complex z) { + z = casinl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/casinl.c b/third_party/ulib/musl/src/complex/casinl.c new file mode 100644 index 000000000..3e1577de2 --- /dev/null +++ b/third_party/ulib/musl/src/complex/casinl.c @@ -0,0 +1,18 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex casinl(long double complex z) { + return casin(z); +} +#else +// FIXME +long double complex casinl(long double complex z) { + long double complex w; + long double x, y; + + x = creall(z); + y = cimagl(z); + w = CMPLXL(1.0 - (x - y) * (x + y), -2.0 * x * y); + return clogl(CMPLXL(-y, x) + csqrtl(w)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/catanh.c b/third_party/ulib/musl/src/complex/catanh.c new file mode 100644 index 000000000..ddbd28834 --- /dev/null +++ b/third_party/ulib/musl/src/complex/catanh.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* atanh = -i atan(i z) */ + +double complex catanh(double complex z) { + z = catan(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/third_party/ulib/musl/src/complex/catanhf.c b/third_party/ulib/musl/src/complex/catanhf.c new file mode 100644 index 000000000..c0d282824 --- /dev/null +++ b/third_party/ulib/musl/src/complex/catanhf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex catanhf(float complex z) { + z = catanf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/third_party/ulib/musl/src/complex/catanhl.c b/third_party/ulib/musl/src/complex/catanhl.c new file mode 100644 index 000000000..01532f3ad --- /dev/null +++ b/third_party/ulib/musl/src/complex/catanhl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex catanhl(long double complex z) { + return catanh(z); +} +#else +long double complex catanhl(long double complex z) { + z = catanl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/ccos.c b/third_party/ulib/musl/src/complex/ccos.c new file mode 100644 index 000000000..8338959d6 --- /dev/null +++ b/third_party/ulib/musl/src/complex/ccos.c @@ -0,0 +1,7 @@ +#include "libm.h" + +/* cos(z) = cosh(i z) */ + +double complex ccos(double complex z) { + return ccosh(CMPLX(-cimag(z), creal(z))); +} diff --git a/third_party/ulib/musl/src/complex/ccosf.c b/third_party/ulib/musl/src/complex/ccosf.c new file mode 100644 index 000000000..0c9bf7e90 --- /dev/null +++ b/third_party/ulib/musl/src/complex/ccosf.c @@ -0,0 +1,5 @@ +#include "libm.h" + +float complex ccosf(float complex z) { + return ccoshf(CMPLXF(-cimagf(z), crealf(z))); +} diff --git a/third_party/ulib/musl/src/complex/ccoshl.c b/third_party/ulib/musl/src/complex/ccoshl.c new file mode 100644 index 000000000..be7ff0c3a --- /dev/null +++ b/third_party/ulib/musl/src/complex/ccoshl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +// FIXME +long double complex ccoshl(long double complex z) { + return ccosh(z); +} diff --git a/third_party/ulib/musl/src/complex/ccosl.c b/third_party/ulib/musl/src/complex/ccosl.c new file mode 100644 index 000000000..9f8a06fbb --- /dev/null +++ b/third_party/ulib/musl/src/complex/ccosl.c @@ -0,0 +1,11 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex ccosl(long double complex z) { + return ccos(z); +} +#else +long double complex ccosl(long double complex z) { + return ccoshl(CMPLXL(-cimagl(z), creall(z))); +} +#endif diff --git a/third_party/ulib/musl/src/complex/cexpl.c b/third_party/ulib/musl/src/complex/cexpl.c new file mode 100644 index 000000000..cdc58aebd --- /dev/null +++ b/third_party/ulib/musl/src/complex/cexpl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +// FIXME +long double complex cexpl(long double complex z) { + return cexp(z); +} diff --git a/third_party/ulib/musl/src/complex/cimag.c b/third_party/ulib/musl/src/complex/cimag.c new file mode 100644 index 000000000..4d80365a8 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cimag.c @@ -0,0 +1,5 @@ +#include "libm.h" + +double(cimag)(double complex z) { + return cimag(z); +} diff --git a/third_party/ulib/musl/src/complex/cimagf.c b/third_party/ulib/musl/src/complex/cimagf.c new file mode 100644 index 000000000..3fcff1bc2 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cimagf.c @@ -0,0 +1,5 @@ +#include "libm.h" + +float(cimagf)(float complex z) { + return cimagf(z); +} diff --git a/third_party/ulib/musl/src/complex/cimagl.c b/third_party/ulib/musl/src/complex/cimagl.c new file mode 100644 index 000000000..9c2e25831 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cimagl.c @@ -0,0 +1,5 @@ +#include "libm.h" + +long double(cimagl)(long double complex z) { + return cimagl(z); +} diff --git a/third_party/ulib/musl/src/complex/clog.c b/third_party/ulib/musl/src/complex/clog.c new file mode 100644 index 000000000..20cbf177b --- /dev/null +++ b/third_party/ulib/musl/src/complex/clog.c @@ -0,0 +1,13 @@ +#include "libm.h" + +// FIXME + +/* log(z) = log(|z|) + i arg(z) */ + +double complex clog(double complex z) { + double r, phi; + + r = cabs(z); + phi = carg(z); + return CMPLX(log(r), phi); +} diff --git a/third_party/ulib/musl/src/complex/clogf.c b/third_party/ulib/musl/src/complex/clogf.c new file mode 100644 index 000000000..4e1c63867 --- /dev/null +++ b/third_party/ulib/musl/src/complex/clogf.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME + +float complex clogf(float complex z) { + float r, phi; + + r = cabsf(z); + phi = cargf(z); + return CMPLXF(logf(r), phi); +} diff --git a/third_party/ulib/musl/src/complex/clogl.c b/third_party/ulib/musl/src/complex/clogl.c new file mode 100644 index 000000000..e8f726f27 --- /dev/null +++ b/third_party/ulib/musl/src/complex/clogl.c @@ -0,0 +1,16 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex clogl(long double complex z) { + return clog(z); +} +#else +// FIXME +long double complex clogl(long double complex z) { + long double r, phi; + + r = cabsl(z); + phi = cargl(z); + return CMPLXL(logl(r), phi); +} +#endif diff --git a/third_party/ulib/musl/src/complex/conj.c b/third_party/ulib/musl/src/complex/conj.c new file mode 100644 index 000000000..6a7792bd6 --- /dev/null +++ b/third_party/ulib/musl/src/complex/conj.c @@ -0,0 +1,5 @@ +#include "libm.h" + +double complex conj(double complex z) { + return CMPLX(creal(z), -cimag(z)); +} diff --git a/third_party/ulib/musl/src/complex/conjf.c b/third_party/ulib/musl/src/complex/conjf.c new file mode 100644 index 000000000..e40ffa3cb --- /dev/null +++ b/third_party/ulib/musl/src/complex/conjf.c @@ -0,0 +1,5 @@ +#include "libm.h" + +float complex conjf(float complex z) { + return CMPLXF(crealf(z), -cimagf(z)); +} diff --git a/third_party/ulib/musl/src/complex/conjl.c b/third_party/ulib/musl/src/complex/conjl.c new file mode 100644 index 000000000..9e31d113e --- /dev/null +++ b/third_party/ulib/musl/src/complex/conjl.c @@ -0,0 +1,5 @@ +#include "libm.h" + +long double complex conjl(long double complex z) { + return CMPLXL(creall(z), -cimagl(z)); +} diff --git a/third_party/ulib/musl/src/complex/cpow.c b/third_party/ulib/musl/src/complex/cpow.c new file mode 100644 index 000000000..ee0ac79a4 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cpow.c @@ -0,0 +1,7 @@ +#include "libm.h" + +/* pow(z, c) = exp(c log(z)), See C99 G.6.4.1 */ + +double complex cpow(double complex z, double complex c) { + return cexp(c * clog(z)); +} diff --git a/third_party/ulib/musl/src/complex/cpowf.c b/third_party/ulib/musl/src/complex/cpowf.c new file mode 100644 index 000000000..512c5e443 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cpowf.c @@ -0,0 +1,5 @@ +#include "libm.h" + +float complex cpowf(float complex z, float complex c) { + return cexpf(c * clogf(z)); +} diff --git a/third_party/ulib/musl/src/complex/cpowl.c b/third_party/ulib/musl/src/complex/cpowl.c new file mode 100644 index 000000000..6844af4c2 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cpowl.c @@ -0,0 +1,11 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cpowl(long double complex z, long double complex c) { + return cpow(z, c); +} +#else +long double complex cpowl(long double complex z, long double complex c) { + return cexpl(c * clogl(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/cproj.c b/third_party/ulib/musl/src/complex/cproj.c new file mode 100644 index 000000000..b10da0025 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cproj.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double complex cproj(double complex z) { + if (isinf(creal(z)) || isinf(cimag(z))) return CMPLX(INFINITY, copysign(0.0, creal(z))); + return z; +} diff --git a/third_party/ulib/musl/src/complex/cprojf.c b/third_party/ulib/musl/src/complex/cprojf.c new file mode 100644 index 000000000..83e314527 --- /dev/null +++ b/third_party/ulib/musl/src/complex/cprojf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex cprojf(float complex z) { + if (isinf(crealf(z)) || isinf(cimagf(z))) return CMPLXF(INFINITY, copysignf(0.0, crealf(z))); + return z; +} diff --git a/third_party/ulib/musl/src/complex/cprojl.c b/third_party/ulib/musl/src/complex/cprojl.c new file mode 100644 index 000000000..790f229df --- /dev/null +++ b/third_party/ulib/musl/src/complex/cprojl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cprojl(long double complex z) { + return cproj(z); +} +#else +long double complex cprojl(long double complex z) { + if (isinf(creall(z)) || isinf(cimagl(z))) return CMPLXL(INFINITY, copysignl(0.0, creall(z))); + return z; +} +#endif diff --git a/third_party/ulib/musl/src/complex/creal.c b/third_party/ulib/musl/src/complex/creal.c new file mode 100644 index 000000000..9137f5c39 --- /dev/null +++ b/third_party/ulib/musl/src/complex/creal.c @@ -0,0 +1,5 @@ +#include + +double(creal)(double complex z) { + return creal(z); +} diff --git a/third_party/ulib/musl/src/complex/crealf.c b/third_party/ulib/musl/src/complex/crealf.c new file mode 100644 index 000000000..6e23386b8 --- /dev/null +++ b/third_party/ulib/musl/src/complex/crealf.c @@ -0,0 +1,5 @@ +#include + +float(crealf)(float complex z) { + return crealf(z); +} diff --git a/third_party/ulib/musl/src/complex/creall.c b/third_party/ulib/musl/src/complex/creall.c new file mode 100644 index 000000000..dd96d437d --- /dev/null +++ b/third_party/ulib/musl/src/complex/creall.c @@ -0,0 +1,5 @@ +#include + +long double(creall)(long double complex z) { + return creall(z); +} diff --git a/third_party/ulib/musl/src/complex/csin.c b/third_party/ulib/musl/src/complex/csin.c new file mode 100644 index 000000000..8204e9041 --- /dev/null +++ b/third_party/ulib/musl/src/complex/csin.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* sin(z) = -i sinh(i z) */ + +double complex csin(double complex z) { + z = csinh(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/third_party/ulib/musl/src/complex/csinf.c b/third_party/ulib/musl/src/complex/csinf.c new file mode 100644 index 000000000..3f0b3ba05 --- /dev/null +++ b/third_party/ulib/musl/src/complex/csinf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex csinf(float complex z) { + z = csinhf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/third_party/ulib/musl/src/complex/csinhl.c b/third_party/ulib/musl/src/complex/csinhl.c new file mode 100644 index 000000000..982e91945 --- /dev/null +++ b/third_party/ulib/musl/src/complex/csinhl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +// FIXME +long double complex csinhl(long double complex z) { + return csinh(z); +} diff --git a/third_party/ulib/musl/src/complex/csinl.c b/third_party/ulib/musl/src/complex/csinl.c new file mode 100644 index 000000000..5456974a9 --- /dev/null +++ b/third_party/ulib/musl/src/complex/csinl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex csinl(long double complex z) { + return csin(z); +} +#else +long double complex csinl(long double complex z) { + z = csinhl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/third_party/ulib/musl/src/complex/csqrtl.c b/third_party/ulib/musl/src/complex/csqrtl.c new file mode 100644 index 000000000..e3139cf97 --- /dev/null +++ b/third_party/ulib/musl/src/complex/csqrtl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +// FIXME +long double complex csqrtl(long double complex z) { + return csqrt(z); +} diff --git a/third_party/ulib/musl/src/complex/ctan.c b/third_party/ulib/musl/src/complex/ctan.c new file mode 100644 index 000000000..998c02502 --- /dev/null +++ b/third_party/ulib/musl/src/complex/ctan.c @@ -0,0 +1,8 @@ +#include "libm.h" + +/* tan(z) = -i tanh(i z) */ + +double complex ctan(double complex z) { + z = ctanh(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/third_party/ulib/musl/src/complex/ctanf.c b/third_party/ulib/musl/src/complex/ctanf.c new file mode 100644 index 000000000..77651a9d6 --- /dev/null +++ b/third_party/ulib/musl/src/complex/ctanf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float complex ctanf(float complex z) { + z = ctanhf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/third_party/ulib/musl/src/complex/ctanhl.c b/third_party/ulib/musl/src/complex/ctanhl.c new file mode 100644 index 000000000..d62b74356 --- /dev/null +++ b/third_party/ulib/musl/src/complex/ctanhl.c @@ -0,0 +1,6 @@ +#include "libm.h" + +// FIXME +long double complex ctanhl(long double complex z) { + return ctanh(z); +} diff --git a/third_party/ulib/musl/src/complex/ctanl.c b/third_party/ulib/musl/src/complex/ctanl.c new file mode 100644 index 000000000..b4e50c3b1 --- /dev/null +++ b/third_party/ulib/musl/src/complex/ctanl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex ctanl(long double complex z) { + return ctan(z); +} +#else +long double complex ctanl(long double complex z) { + z = ctanhl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/third_party/ulib/musl/src/conf/BUILD.gn b/third_party/ulib/musl/src/conf/BUILD.gn new file mode 100644 index 000000000..ed735c592 --- /dev/null +++ b/third_party/ulib/musl/src/conf/BUILD.gn @@ -0,0 +1,13 @@ +source_set("conf") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "confstr.c", + "fpathconf.c", + "legacy.c", + "pathconf.c", + "sysconf.c", + ] +} diff --git a/third_party/ulib/musl/src/conf/confstr.c b/third_party/ulib/musl/src/conf/confstr.c new file mode 100644 index 000000000..da409e606 --- /dev/null +++ b/third_party/ulib/musl/src/conf/confstr.c @@ -0,0 +1,16 @@ +#include +#include +#include + +size_t confstr(int name, char* buf, size_t len) { + const char* s = ""; + if (!name) { + s = "/bin:/usr/bin"; + } else if ((name & ~4U) != 1 && name - _CS_POSIX_V6_ILP32_OFF32_CFLAGS > 31U) { + errno = EINVAL; + return 0; + } + // snprintf is overkill but avoid wasting code size to implement + // this completely useless function and its truncation semantics + return snprintf(buf, len, "%s", s) + 1; +} diff --git a/third_party/ulib/musl/src/conf/fpathconf.c b/third_party/ulib/musl/src/conf/fpathconf.c new file mode 100644 index 000000000..134bb1163 --- /dev/null +++ b/third_party/ulib/musl/src/conf/fpathconf.c @@ -0,0 +1,32 @@ +#include +#include +#include + +long fpathconf(int fd, int name) { + static const short values[] = {[_PC_LINK_MAX] = _POSIX_LINK_MAX, + [_PC_MAX_CANON] = _POSIX_MAX_CANON, + [_PC_MAX_INPUT] = _POSIX_MAX_INPUT, + [_PC_NAME_MAX] = NAME_MAX, + [_PC_PATH_MAX] = PATH_MAX, + [_PC_PIPE_BUF] = PIPE_BUF, + [_PC_CHOWN_RESTRICTED] = 1, + [_PC_NO_TRUNC] = 1, + [_PC_VDISABLE] = 0, + [_PC_SYNC_IO] = 1, + [_PC_ASYNC_IO] = -1, + [_PC_PRIO_IO] = -1, + [_PC_SOCK_MAXBUF] = -1, + [_PC_FILESIZEBITS] = FILESIZEBITS, + [_PC_REC_INCR_XFER_SIZE] = 4096, + [_PC_REC_MAX_XFER_SIZE] = 4096, + [_PC_REC_MIN_XFER_SIZE] = 4096, + [_PC_REC_XFER_ALIGN] = 4096, + [_PC_ALLOC_SIZE_MIN] = 4096, + [_PC_SYMLINK_MAX] = SYMLINK_MAX, + [_PC_2_SYMLINKS] = 1}; + if (name >= sizeof(values) / sizeof(values[0])) { + errno = EINVAL; + return -1; + } + return values[name]; +} diff --git a/third_party/ulib/musl/src/conf/legacy.c b/third_party/ulib/musl/src/conf/legacy.c new file mode 100644 index 000000000..9cb2dc353 --- /dev/null +++ b/third_party/ulib/musl/src/conf/legacy.c @@ -0,0 +1,18 @@ +#include +#include + +int get_nprocs_conf() { + return sysconf(_SC_NPROCESSORS_CONF); +} + +int get_nprocs() { + return sysconf(_SC_NPROCESSORS_ONLN); +} + +long get_phys_pages() { + return sysconf(_SC_PHYS_PAGES); +} + +long get_avphys_pages() { + return sysconf(_SC_AVPHYS_PAGES); +} diff --git a/third_party/ulib/musl/src/conf/pathconf.c b/third_party/ulib/musl/src/conf/pathconf.c new file mode 100644 index 000000000..4ad53f453 --- /dev/null +++ b/third_party/ulib/musl/src/conf/pathconf.c @@ -0,0 +1,5 @@ +#include + +long pathconf(const char* path, int name) { + return fpathconf(-1, name); +} diff --git a/third_party/ulib/musl/src/conf/sysconf.c b/third_party/ulib/musl/src/conf/sysconf.c new file mode 100644 index 000000000..e5009899e --- /dev/null +++ b/third_party/ulib/musl/src/conf/sysconf.c @@ -0,0 +1,217 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include +#include +#include + +#define JT(x) (-256 | (x)) +#define VER JT(1) +#define JT_ARG_MAX JT(2) +#define JT_MQ_PRIO_MAX JT(3) +#define JT_PAGE_SIZE JT(4) +#define JT_SEM_VALUE_MAX JT(5) +#define JT_NPROCESSORS_CONF JT(6) +#define JT_NPROCESSORS_ONLN JT(7) +#define JT_PHYS_PAGES JT(8) +#define JT_AVPHYS_PAGES JT(9) +#define JT_ZERO JT(10) + +#define RLIM(x) (-32768 | (RLIMIT_##x)) + +long sysconf(int name) { + static const short values[] = { + [_SC_ARG_MAX] = JT_ARG_MAX, + [_SC_CHILD_MAX] = RLIM(NPROC), + [_SC_CLK_TCK] = 100, + [_SC_NGROUPS_MAX] = 32, + [_SC_OPEN_MAX] = RLIM(NOFILE), + [_SC_STREAM_MAX] = -1, + [_SC_TZNAME_MAX] = TZNAME_MAX, + [_SC_JOB_CONTROL] = 1, + [_SC_SAVED_IDS] = 1, + [_SC_REALTIME_SIGNALS] = 1, + [_SC_PRIORITY_SCHEDULING] = -1, + [_SC_TIMERS] = VER, + [_SC_ASYNCHRONOUS_IO] = VER, + [_SC_PRIORITIZED_IO] = -1, + [_SC_SYNCHRONIZED_IO] = -1, + [_SC_FSYNC] = VER, + [_SC_MAPPED_FILES] = VER, + [_SC_MEMLOCK] = VER, + [_SC_MEMLOCK_RANGE] = VER, + [_SC_MEMORY_PROTECTION] = VER, + [_SC_MESSAGE_PASSING] = VER, + [_SC_SEMAPHORES] = VER, + [_SC_SHARED_MEMORY_OBJECTS] = VER, + [_SC_AIO_LISTIO_MAX] = -1, + [_SC_AIO_MAX] = -1, + [_SC_AIO_PRIO_DELTA_MAX] = JT_ZERO, /* ?? */ + [_SC_DELAYTIMER_MAX] = _POSIX_DELAYTIMER_MAX, + [_SC_MQ_OPEN_MAX] = -1, + [_SC_MQ_PRIO_MAX] = JT_MQ_PRIO_MAX, + [_SC_VERSION] = VER, + [_SC_PAGE_SIZE] = JT_PAGE_SIZE, + [_SC_RTSIG_MAX] = _NSIG - 1 - 31 - 3, + [_SC_SEM_NSEMS_MAX] = SEM_NSEMS_MAX, + [_SC_SEM_VALUE_MAX] = JT_SEM_VALUE_MAX, + [_SC_SIGQUEUE_MAX] = -1, + [_SC_TIMER_MAX] = -1, + [_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX, + [_SC_BC_DIM_MAX] = _POSIX2_BC_DIM_MAX, + [_SC_BC_SCALE_MAX] = _POSIX2_BC_SCALE_MAX, + [_SC_BC_STRING_MAX] = _POSIX2_BC_STRING_MAX, + [_SC_COLL_WEIGHTS_MAX] = COLL_WEIGHTS_MAX, + [_SC_EXPR_NEST_MAX] = -1, + [_SC_LINE_MAX] = -1, + [_SC_RE_DUP_MAX] = RE_DUP_MAX, + [_SC_2_VERSION] = VER, + [_SC_2_C_BIND] = VER, + [_SC_2_C_DEV] = -1, + [_SC_2_FORT_DEV] = -1, + [_SC_2_FORT_RUN] = -1, + [_SC_2_SW_DEV] = -1, + [_SC_2_LOCALEDEF] = -1, + [_SC_IOV_MAX] = IOV_MAX, + [_SC_THREADS] = VER, + [_SC_THREAD_SAFE_FUNCTIONS] = VER, + [_SC_GETGR_R_SIZE_MAX] = -1, + [_SC_GETPW_R_SIZE_MAX] = -1, + [_SC_LOGIN_NAME_MAX] = 256, + [_SC_TTY_NAME_MAX] = TTY_NAME_MAX, + [_SC_THREAD_DESTRUCTOR_ITERATIONS] = PTHREAD_DESTRUCTOR_ITERATIONS, + [_SC_THREAD_KEYS_MAX] = PTHREAD_KEYS_MAX, + [_SC_THREAD_STACK_MIN] = PTHREAD_STACK_MIN, + [_SC_THREAD_THREADS_MAX] = -1, + [_SC_THREAD_ATTR_STACKADDR] = VER, + [_SC_THREAD_ATTR_STACKSIZE] = VER, + [_SC_THREAD_PRIORITY_SCHEDULING] = VER, + [_SC_THREAD_PRIO_INHERIT] = -1, + [_SC_THREAD_PRIO_PROTECT] = -1, + [_SC_THREAD_PROCESS_SHARED] = VER, + [_SC_NPROCESSORS_CONF] = JT_NPROCESSORS_CONF, + [_SC_NPROCESSORS_ONLN] = JT_NPROCESSORS_ONLN, + [_SC_PHYS_PAGES] = JT_PHYS_PAGES, + [_SC_AVPHYS_PAGES] = JT_AVPHYS_PAGES, + [_SC_ATEXIT_MAX] = -1, + [_SC_PASS_MAX] = -1, + [_SC_XOPEN_VERSION] = _XOPEN_VERSION, + [_SC_XOPEN_XCU_VERSION] = _XOPEN_VERSION, + [_SC_XOPEN_UNIX] = 1, + [_SC_XOPEN_CRYPT] = -1, + [_SC_XOPEN_ENH_I18N] = 1, + [_SC_XOPEN_SHM] = 1, + [_SC_2_CHAR_TERM] = -1, + [_SC_2_UPE] = -1, + [_SC_XOPEN_XPG2] = -1, + [_SC_XOPEN_XPG3] = -1, + [_SC_XOPEN_XPG4] = -1, + [_SC_NZERO] = NZERO, + [_SC_XBS5_ILP32_OFF32] = -1, + [_SC_XBS5_ILP32_OFFBIG] = sizeof(long) == 4 ? 1 : JT_ZERO, + [_SC_XBS5_LP64_OFF64] = sizeof(long) == 8 ? 1 : JT_ZERO, + [_SC_XBS5_LPBIG_OFFBIG] = -1, + [_SC_XOPEN_LEGACY] = -1, + [_SC_XOPEN_REALTIME] = -1, + [_SC_XOPEN_REALTIME_THREADS] = -1, + [_SC_ADVISORY_INFO] = VER, + [_SC_BARRIERS] = VER, + [_SC_CLOCK_SELECTION] = VER, + [_SC_CPUTIME] = VER, + [_SC_THREAD_CPUTIME] = VER, + [_SC_MONOTONIC_CLOCK] = VER, + [_SC_READER_WRITER_LOCKS] = VER, + [_SC_SPIN_LOCKS] = VER, + [_SC_REGEXP] = 1, + [_SC_SHELL] = 1, + [_SC_SPAWN] = VER, + [_SC_SPORADIC_SERVER] = -1, + [_SC_THREAD_SPORADIC_SERVER] = -1, + [_SC_TIMEOUTS] = VER, + [_SC_TYPED_MEMORY_OBJECTS] = -1, + [_SC_2_PBS] = -1, + [_SC_2_PBS_ACCOUNTING] = -1, + [_SC_2_PBS_LOCATE] = -1, + [_SC_2_PBS_MESSAGE] = -1, + [_SC_2_PBS_TRACK] = -1, + [_SC_SYMLOOP_MAX] = SYMLOOP_MAX, + [_SC_STREAMS] = JT_ZERO, + [_SC_2_PBS_CHECKPOINT] = -1, + [_SC_V6_ILP32_OFF32] = -1, + [_SC_V6_ILP32_OFFBIG] = sizeof(long) == 4 ? 1 : JT_ZERO, + [_SC_V6_LP64_OFF64] = sizeof(long) == 8 ? 1 : JT_ZERO, + [_SC_V6_LPBIG_OFFBIG] = -1, + [_SC_HOST_NAME_MAX] = HOST_NAME_MAX, + [_SC_TRACE] = -1, + [_SC_TRACE_EVENT_FILTER] = -1, + [_SC_TRACE_INHERIT] = -1, + [_SC_TRACE_LOG] = -1, + + [_SC_IPV6] = VER, + [_SC_RAW_SOCKETS] = VER, + [_SC_V7_ILP32_OFF32] = -1, + [_SC_V7_ILP32_OFFBIG] = sizeof(long) == 4 ? 1 : JT_ZERO, + [_SC_V7_LP64_OFF64] = sizeof(long) == 8 ? 1 : JT_ZERO, + [_SC_V7_LPBIG_OFFBIG] = -1, + [_SC_SS_REPL_MAX] = -1, + [_SC_TRACE_EVENT_NAME_MAX] = -1, + [_SC_TRACE_NAME_MAX] = -1, + [_SC_TRACE_SYS_MAX] = -1, + [_SC_TRACE_USER_EVENT_MAX] = -1, + [_SC_XOPEN_STREAMS] = JT_ZERO, + [_SC_THREAD_ROBUST_PRIO_INHERIT] = -1, + [_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, + }; + + if (name >= sizeof(values) / sizeof(values[0]) || !values[name]) { + errno = EINVAL; + return -1; + } else if (values[name] >= -1) { + return values[name]; + } else if (values[name] < -256) { + struct rlimit lim; + getrlimit(values[name] & 16383, &lim); + return lim.rlim_cur > LONG_MAX ? LONG_MAX : lim.rlim_cur; + } + + switch ((unsigned char)values[name]) { + case VER & 255: + return _POSIX_VERSION; + case JT_ARG_MAX & 255: + return ARG_MAX; + case JT_MQ_PRIO_MAX & 255: + return MQ_PRIO_MAX; + case JT_PAGE_SIZE & 255: + return PAGE_SIZE; + case JT_SEM_VALUE_MAX & 255: + return SEM_VALUE_MAX; + case JT_NPROCESSORS_CONF & 255: + case JT_NPROCESSORS_ONLN & 255:; + unsigned char set[128] = {1}; + int i, cnt; + __syscall(SYS_sched_getaffinity, 0, sizeof set, set); + for (i = cnt = 0; i < sizeof set; i++) + for (; set[i]; set[i] &= set[i] - 1, cnt++) + ; + return cnt; + case JT_PHYS_PAGES & 255: + case JT_AVPHYS_PAGES & 255:; + unsigned long long mem; + int __lsysinfo(struct sysinfo*); + struct sysinfo si; + __lsysinfo(&si); + if (!si.mem_unit) si.mem_unit = 1; + if (name == _SC_PHYS_PAGES) + mem = si.totalram; + else + mem = si.freeram + si.bufferram; + mem *= si.mem_unit; + mem /= PAGE_SIZE; + return (mem > LONG_MAX) ? LONG_MAX : mem; + case JT_ZERO & 255: + return 0; + } + return values[name]; +} diff --git a/third_party/ulib/musl/src/crypt/BUILD.gn b/third_party/ulib/musl/src/crypt/BUILD.gn new file mode 100644 index 000000000..fe18726f4 --- /dev/null +++ b/third_party/ulib/musl/src/crypt/BUILD.gn @@ -0,0 +1,11 @@ +source_set("crypt") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "crypt.c", + "crypt_r.c", + "encrypt.c", + ] +} diff --git a/third_party/ulib/musl/src/crypt/crypt.c b/third_party/ulib/musl/src/crypt/crypt.c new file mode 100644 index 000000000..0bc987e1f --- /dev/null +++ b/third_party/ulib/musl/src/crypt/crypt.c @@ -0,0 +1,15 @@ +#include +#include + +char* __crypt_r(const char*, const char*, struct crypt_data*); + +char* crypt(const char* key, const char* salt) { + /* This buffer is sufficiently large for all + * currently-supported hash types. It needs to be updated if + * longer hashes are added. The cast to struct crypt_data * is + * purely to meet the public API requirements of the crypt_r + * function; the implementation of crypt_r uses the object + * purely as a char buffer. */ + static char buf[128]; + return __crypt_r(key, salt, (struct crypt_data*)buf); +} diff --git a/third_party/ulib/musl/src/crypt/crypt_r.c b/third_party/ulib/musl/src/crypt/crypt_r.c new file mode 100644 index 000000000..59c89985f --- /dev/null +++ b/third_party/ulib/musl/src/crypt/crypt_r.c @@ -0,0 +1,27 @@ +#include "libc.h" +#include + +struct crypt_data; + +char* __crypt_des(const char*, const char*, char*); +char* __crypt_md5(const char*, const char*, char*); +char* __crypt_blowfish(const char*, const char*, char*); +char* __crypt_sha256(const char*, const char*, char*); +char* __crypt_sha512(const char*, const char*, char*); + +char* __crypt_r(const char* key, const char* salt, struct crypt_data* data) { + /* Per the crypt_r API, the caller has provided a pointer to + * struct crypt_data; however, this implementation does not + * use the structure to store any internal state, and treats + * it purely as a char buffer for storing the result. */ + char* output = (char*)data; + if (salt[0] == '$' && salt[1] && salt[2]) { + if (salt[1] == '1' && salt[2] == '$') return __crypt_md5(key, salt, output); + if (salt[1] == '2' && salt[3] == '$') return __crypt_blowfish(key, salt, output); + if (salt[1] == '5' && salt[2] == '$') return __crypt_sha256(key, salt, output); + if (salt[1] == '6' && salt[2] == '$') return __crypt_sha512(key, salt, output); + } + return __crypt_des(key, salt, output); +} + +weak_alias(__crypt_r, crypt_r); diff --git a/third_party/ulib/musl/src/crypt/encrypt.c b/third_party/ulib/musl/src/crypt/encrypt.c new file mode 100644 index 000000000..f73bf56db --- /dev/null +++ b/third_party/ulib/musl/src/crypt/encrypt.c @@ -0,0 +1,56 @@ +#include +#include +#include + +struct expanded_key { + uint32_t l[16], r[16]; +}; + +void __des_setkey(const unsigned char* key, struct expanded_key* ekey); +void __do_des(uint32_t l_in, uint32_t r_in, uint32_t* l_out, uint32_t* r_out, uint32_t count, + uint32_t saltbits, const struct expanded_key* ekey); + +static struct expanded_key __encrypt_key; + +void setkey(const char* key) { + unsigned char bkey[8]; + int i, j; + + for (i = 0; i < 8; i++) { + bkey[i] = 0; + for (j = 7; j >= 0; j--, key++) + bkey[i] |= (uint32_t)(*key & 1) << j; + } + + __des_setkey(bkey, &__encrypt_key); +} + +void encrypt(char* block, int edflag) { + struct expanded_key decrypt_key, *key; + uint32_t b[2]; + int i, j; + char* p; + + p = block; + for (i = 0; i < 2; i++) { + b[i] = 0; + for (j = 31; j >= 0; j--, p++) + b[i] |= (uint32_t)(*p & 1) << j; + } + + key = &__encrypt_key; + if (edflag) { + key = &decrypt_key; + for (i = 0; i < 16; i++) { + decrypt_key.l[i] = __encrypt_key.l[15 - i]; + decrypt_key.r[i] = __encrypt_key.r[15 - i]; + } + } + + __do_des(b[0], b[1], b, b + 1, 1, 0, key); + + p = block; + for (i = 0; i < 2; i++) + for (j = 31; j >= 0; j--) + *p++ = b[i] >> j & 1; +} diff --git a/third_party/ulib/musl/src/ctype/BUILD.gn b/third_party/ulib/musl/src/ctype/BUILD.gn new file mode 100644 index 000000000..b009e0f3c --- /dev/null +++ b/third_party/ulib/musl/src/ctype/BUILD.gn @@ -0,0 +1,45 @@ +source_set("ctype") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__ctype_b_loc.c", + "__ctype_get_mb_cur_max.c", + "__ctype_tolower_loc.c", + "__ctype_toupper_loc.c", + "isalnum.c", + "isalpha.c", + "isascii.c", + "isblank.c", + "iscntrl.c", + "isdigit.c", + "isgraph.c", + "islower.c", + "isprint.c", + "ispunct.c", + "isspace.c", + "isupper.c", + "iswalnum.c", + "iswalpha.c", + "iswblank.c", + "iswcntrl.c", + "iswctype.c", + "iswdigit.c", + "iswgraph.c", + "iswlower.c", + "iswprint.c", + "iswpunct.c", + "iswspace.c", + "iswupper.c", + "iswxdigit.c", + "isxdigit.c", + "toascii.c", + "tolower.c", + "toupper.c", + "towctrans.c", + "wcswidth.c", + "wctrans.c", + "wcwidth.c", + ] +} diff --git a/third_party/ulib/musl/src/ctype/__ctype_b_loc.c b/third_party/ulib/musl/src/ctype/__ctype_b_loc.c new file mode 100644 index 000000000..13f5344ea --- /dev/null +++ b/third_party/ulib/musl/src/ctype/__ctype_b_loc.c @@ -0,0 +1,59 @@ +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define X(x) x +#else +#define X(x) (((x) / 256 | (x)*256) % 65536) +#endif + +static const unsigned short table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), + X(0x200), X(0x200), X(0x320), X(0x220), X(0x220), X(0x220), X(0x220), X(0x200), X(0x200), + X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), + X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x160), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), + X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x8d5), X(0x8d5), X(0x8d5), X(0x8d5), X(0x8d5), + X(0x8d5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), + X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), + X(0x8c5), X(0x8c5), X(0x8c5), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8c6), X(0x8c6), X(0x8c6), + X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), + X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x200), 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; + +static const unsigned short* const ptable = table + 128; + +const unsigned short** __ctype_b_loc(void) { + return (void*)&ptable; +} diff --git a/third_party/ulib/musl/src/ctype/__ctype_get_mb_cur_max.c b/third_party/ulib/musl/src/ctype/__ctype_get_mb_cur_max.c new file mode 100644 index 000000000..2627f1f78 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/__ctype_get_mb_cur_max.c @@ -0,0 +1,6 @@ +#include "locale_impl.h" +#include + +size_t __ctype_get_mb_cur_max() { + return MB_CUR_MAX; +} diff --git a/third_party/ulib/musl/src/ctype/__ctype_tolower_loc.c b/third_party/ulib/musl/src/ctype/__ctype_tolower_loc.c new file mode 100644 index 000000000..8ed598084 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/__ctype_tolower_loc.c @@ -0,0 +1,31 @@ +#include + +static const int32_t table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 91, 92, 93, 94, 95, 96, 'a', 'b', 'c', + 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', 123, 124, 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +static const int32_t* const ptable = table + 128; + +const int32_t** __ctype_tolower_loc(void) { + return (void*)&ptable; +} diff --git a/third_party/ulib/musl/src/ctype/__ctype_toupper_loc.c b/third_party/ulib/musl/src/ctype/__ctype_toupper_loc.c new file mode 100644 index 000000000..fccd7ac12 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/__ctype_toupper_loc.c @@ -0,0 +1,31 @@ +#include + +static const int32_t table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 91, 92, 93, 94, 95, 96, 'A', 'B', 'C', + 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 123, 124, 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +static const int32_t* const ptable = table + 128; + +const int32_t** __ctype_toupper_loc(void) { + return (void*)&ptable; +} diff --git a/third_party/ulib/musl/src/ctype/alpha.h b/third_party/ulib/musl/src/ctype/alpha.h new file mode 100644 index 000000000..cbdcedaa1 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/alpha.h @@ -0,0 +1,132 @@ +18, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 17, 34, 35, 36, 17, 37, 38, 39, + 40, 41, 42, 43, 44, 17, 45, 46, 47, 16, 16, 48, 16, 16, 16, 16, 16, 16, 16, 49, 50, 51, 16, 52, + 53, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 54, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 55, 17, 17, 17, 17, 56, 17, 57, 58, 59, + 60, 61, 62, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 63, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 17, 64, 65, 17, 66, 67, 68, 69, 70, 71, 72, 73, 16, 16, 16, 74, + 75, 76, 77, 78, 16, 16, 16, 79, 80, 16, 16, 16, 16, 81, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, + 17, 17, 82, 83, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 84, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, + 17, 85, 16, 16, 16, 16, 86, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 87, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 88, 89, 90, 91, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 92, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, + 0, 0, 0, 0, 0, 0, 254, 255, 255, 7, 254, 255, 255, 7, 0, 0, 0, 0, 0, 4, 32, 4, 255, 255, 127, + 255, 255, 255, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 195, 255, 3, 0, 31, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32, 0, 0, 0, 0, 0, 223, 60, 64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 3, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 0, 254, 255, 255, 255, 127, 2, 254, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 191, + 182, 0, 255, 255, 255, 7, 7, 0, 0, 0, 255, 7, 255, 255, 255, 255, 255, 255, 255, 254, 255, 195, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 31, 254, 225, 255, 159, 0, 0, + 255, 255, 255, 255, 255, 255, 0, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 3, 0, 255, 255, 255, 255, 255, 7, 48, 4, 255, 255, 255, 252, 255, 31, 0, 0, 255, 255, 255, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 253, 31, 0, 0, 0, 0, 0, 0, 240, 3, 255, 127, 255, 255, 255, 255, 255, + 255, 255, 239, 255, 223, 225, 255, 207, 255, 254, 254, 238, 159, 249, 255, 255, 253, 197, 227, + 159, 89, 128, 176, 207, 255, 3, 0, 238, 135, 249, 255, 255, 253, 109, 195, 135, 25, 2, 94, 192, + 255, 63, 0, 238, 191, 251, 255, 255, 253, 237, 227, 191, 27, 1, 0, 207, 255, 0, 0, 238, 159, + 249, 255, 255, 253, 237, 227, 159, 25, 192, 176, 207, 255, 2, 0, 236, 199, 61, 214, 24, 199, + 255, 195, 199, 29, 129, 0, 192, 255, 0, 0, 238, 223, 253, 255, 255, 253, 239, 227, 223, 29, 96, + 3, 207, 255, 0, 0, 236, 223, 253, 255, 255, 253, 239, 227, 223, 29, 96, 64, 207, 255, 6, 0, 236, + 223, 253, 255, 255, 255, 255, 231, 223, 93, 128, 0, 207, 255, 0, 252, 236, 255, 127, 252, 255, + 255, 251, 47, 127, 128, 95, 255, 0, 0, 12, 0, 254, 255, 255, 255, 255, 127, 255, 7, 63, 32, 255, + 3, 0, 0, 0, 0, 150, 37, 240, 254, 174, 236, 255, 59, 95, 32, 255, 243, 0, 0, 0, 0, 1, 0, 0, 0, + 255, 3, 0, 0, 255, 254, 255, 255, 255, 31, 254, 255, 3, 255, 255, 254, 255, 255, 255, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 127, 249, 255, 3, 255, 255, 231, 193, 255, 255, + 127, 64, 255, 51, 255, 255, 255, 255, 191, 32, 255, 255, 255, 255, 255, 247, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 61, 127, 61, 255, 255, 255, 255, 255, 61, 255, 255, 255, 255, 61, 127, + 61, 255, 127, 255, 255, 255, 255, 255, 255, 255, 61, 255, 255, 255, 255, 255, 255, 255, 255, + 135, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 254, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 159, 255, 255, 254, 255, 255, 7, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 199, 1, 0, 255, 223, 15, 0, 255, 255, 15, 0, 255, 255, 15, 0, 255, 223, 13, 0, + 255, 255, 255, 255, 255, 255, 207, 255, 255, 1, 128, 16, 255, 3, 0, 0, 0, 0, 255, 3, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 7, 255, 255, 255, 255, + 255, 255, 255, 255, 63, 0, 255, 255, 255, 31, 255, 15, 255, 1, 192, 255, 255, 255, 255, 63, 31, + 0, 255, 255, 255, 255, 255, 15, 255, 255, 255, 3, 255, 3, 0, 0, 0, 0, 255, 255, 255, 15, 255, + 255, 255, 255, 255, 255, 255, 127, 254, 255, 31, 0, 255, 3, 255, 3, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 255, 255, 255, 255, 255, 255, 239, 255, 239, 15, 255, 3, 0, 0, 0, 0, 255, 255, 255, + 255, 255, 243, 255, 255, 255, 255, 255, 255, 191, 255, 3, 0, 255, 255, 255, 255, 255, 255, 63, + 0, 255, 227, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 111, 0, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 63, 63, 255, 255, 255, 255, 63, 63, + 255, 170, 255, 255, 255, 63, 255, 255, 255, 255, 255, 255, 223, 95, 220, 31, 207, 15, 255, 31, + 220, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 0, 255, 31, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 132, 252, 47, 62, 80, 189, 255, 243, 224, 67, 0, 0, 255, 255, 255, 255, 255, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 3, 0, 0, 255, 255, 255, 255, 255, 127, 255, 255, + 255, 255, 255, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 31, 120, 12, 0, 255, 255, 255, 255, 191, 32, 255, 255, 255, 255, 255, 255, 255, 128, 0, 0, + 255, 255, 127, 0, 127, 127, 127, 127, 127, 127, 127, 127, 255, 255, 255, 255, 0, 0, 0, 0, 0, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, + 254, 3, 62, 31, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 224, 254, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 247, 224, 255, 255, 255, 255, 63, 254, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 127, 0, 0, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, 255, 63, 255, 31, 255, 255, 255, 15, 0, 0, 255, 255, 255, 255, 255, + 127, 240, 143, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 128, 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 121, 15, 0, 255, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 187, 247, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, + 15, 0, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 255, 3, 0, 0, 252, 8, 255, 255, 255, 255, + 255, 7, 255, 255, 255, 255, 7, 0, 255, 255, 255, 31, 255, 255, 255, 255, 255, 255, 247, 255, 0, + 128, 255, 3, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 127, 0, 255, 63, 255, 3, 255, 255, 127, + 4, 255, 255, 255, 255, 255, 255, 255, 127, 5, 0, 0, 56, 255, 255, 60, 0, 126, 126, 126, 0, 127, + 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 7, 255, 3, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 15, 0, 255, 255, 127, 248, 255, 255, 255, 255, 255, 15, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 3, 0, 0, 0, 0, 127, 0, 248, 224, 255, 253, 127, 95, 219, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 3, 0, 0, 0, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 63, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 252, 255, 255, 255, 255, 255, 255, + 0, 0, 0, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 0, 255, 3, 254, 255, 255, 7, 254, + 255, 255, 7, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 252, 252, 252, 28, 0, + 0, 0, 0, 255, 239, 255, 255, 127, 255, 255, 183, 255, 63, 255, 63, 0, 0, 0, 0, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, + 255, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 31, 255, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, + 255, 255, 255, 127, 0, 0, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 255, 255, 255, 63, 255, 255, 255, + 255, 15, 255, 62, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 63, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 253, 255, 255, + 255, 255, 191, 145, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 255, 255, 63, 0, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, + 192, 0, 0, 0, 0, 0, 0, 0, 0, 111, 240, 239, 254, 255, 255, 15, 0, 0, 0, 0, 0, 255, 255, 255, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 63, 0, 255, 255, + 63, 0, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, + 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 192, 255, 0, 0, 252, 255, 255, 255, 255, 255, + 255, 1, 0, 0, 255, 255, 255, 1, 255, 3, 255, 255, 255, 255, 255, 255, 199, 255, 0, 0, 0, 0, 0, + 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 30, 0, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 63, 0, 255, 3, 0, 0, 0, 0, 0, 0, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, + 255, 255, 255, 255, 31, 0, 255, 255, 255, 255, 255, 127, 0, 0, 248, 255, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 223, 255, 255, 255, 255, 255, 255, + 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255, 255, 255, 255, 255, 191, 231, 223, 223, + 255, 255, 255, 123, 95, 252, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 255, 255, 255, 253, 255, 255, 247, 255, + 255, 255, 247, 255, 255, 223, 255, 255, 255, 223, 255, 255, 127, 255, 255, 255, 127, 255, 255, + 255, 253, 255, 255, 255, 253, 255, 255, 247, 207, 255, 255, 255, 255, 255, 255, 239, 255, 255, + 255, 150, 254, 247, 10, 132, 234, 150, 170, 150, 247, 247, 94, 255, 251, 255, 15, 238, 251, 255, + 15, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/third_party/ulib/musl/src/ctype/isalnum.c b/third_party/ulib/musl/src/ctype/isalnum.c new file mode 100644 index 000000000..7f6e27601 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isalnum.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int isalnum(int c) { + return isalpha(c) || isdigit(c); +} + +int __isalnum_l(int c, locale_t l) { + return isalnum(c); +} + +weak_alias(__isalnum_l, isalnum_l); diff --git a/third_party/ulib/musl/src/ctype/isalpha.c b/third_party/ulib/musl/src/ctype/isalpha.c new file mode 100644 index 000000000..f3612a502 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isalpha.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef isalpha + +int isalpha(int c) { + return ((unsigned)c | 32) - 'a' < 26; +} + +int __isalpha_l(int c, locale_t l) { + return isalpha(c); +} + +weak_alias(__isalpha_l, isalpha_l); diff --git a/third_party/ulib/musl/src/ctype/isascii.c b/third_party/ulib/musl/src/ctype/isascii.c new file mode 100644 index 000000000..90bea2b8f --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isascii.c @@ -0,0 +1,6 @@ +#include +#undef isascii + +int isascii(int c) { + return !(c & ~0x7f); +} diff --git a/third_party/ulib/musl/src/ctype/isblank.c b/third_party/ulib/musl/src/ctype/isblank.c new file mode 100644 index 000000000..bf3a6cc69 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isblank.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int isblank(int c) { + return (c == ' ' || c == '\t'); +} + +int __isblank_l(int c, locale_t l) { + return isblank(c); +} + +weak_alias(__isblank_l, isblank_l); diff --git a/third_party/ulib/musl/src/ctype/iscntrl.c b/third_party/ulib/musl/src/ctype/iscntrl.c new file mode 100644 index 000000000..b8e010946 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iscntrl.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int iscntrl(int c) { + return (unsigned)c < 0x20 || c == 0x7f; +} + +int __iscntrl_l(int c, locale_t l) { + return iscntrl(c); +} + +weak_alias(__iscntrl_l, iscntrl_l); diff --git a/third_party/ulib/musl/src/ctype/isdigit.c b/third_party/ulib/musl/src/ctype/isdigit.c new file mode 100644 index 000000000..d45206ada --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isdigit.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef isdigit + +int isdigit(int c) { + return (unsigned)c - '0' < 10; +} + +int __isdigit_l(int c, locale_t l) { + return isdigit(c); +} + +weak_alias(__isdigit_l, isdigit_l); diff --git a/third_party/ulib/musl/src/ctype/isgraph.c b/third_party/ulib/musl/src/ctype/isgraph.c new file mode 100644 index 000000000..cf0b0646f --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isgraph.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef isgraph + +int isgraph(int c) { + return (unsigned)c - 0x21 < 0x5e; +} + +int __isgraph_l(int c, locale_t l) { + return isgraph(c); +} + +weak_alias(__isgraph_l, isgraph_l); diff --git a/third_party/ulib/musl/src/ctype/islower.c b/third_party/ulib/musl/src/ctype/islower.c new file mode 100644 index 000000000..965564727 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/islower.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef islower + +int islower(int c) { + return (unsigned)c - 'a' < 26; +} + +int __islower_l(int c, locale_t l) { + return islower(c); +} + +weak_alias(__islower_l, islower_l); diff --git a/third_party/ulib/musl/src/ctype/isprint.c b/third_party/ulib/musl/src/ctype/isprint.c new file mode 100644 index 000000000..03a91b374 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isprint.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef isprint + +int isprint(int c) { + return (unsigned)c - 0x20 < 0x5f; +} + +int __isprint_l(int c, locale_t l) { + return isprint(c); +} + +weak_alias(__isprint_l, isprint_l); diff --git a/third_party/ulib/musl/src/ctype/ispunct.c b/third_party/ulib/musl/src/ctype/ispunct.c new file mode 100644 index 000000000..3e12a5ed3 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/ispunct.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int ispunct(int c) { + return isgraph(c) && !isalnum(c); +} + +int __ispunct_l(int c, locale_t l) { + return ispunct(c); +} + +weak_alias(__ispunct_l, ispunct_l); diff --git a/third_party/ulib/musl/src/ctype/isspace.c b/third_party/ulib/musl/src/ctype/isspace.c new file mode 100644 index 000000000..d0d4f31a9 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isspace.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef isspace + +int isspace(int c) { + return c == ' ' || (unsigned)c - '\t' < 5; +} + +int __isspace_l(int c, locale_t l) { + return isspace(c); +} + +weak_alias(__isspace_l, isspace_l); diff --git a/third_party/ulib/musl/src/ctype/isupper.c b/third_party/ulib/musl/src/ctype/isupper.c new file mode 100644 index 000000000..07bbe24f4 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isupper.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#undef isupper + +int isupper(int c) { + return (unsigned)c - 'A' < 26; +} + +int __isupper_l(int c, locale_t l) { + return isupper(c); +} + +weak_alias(__isupper_l, isupper_l); diff --git a/third_party/ulib/musl/src/ctype/iswalnum.c b/third_party/ulib/musl/src/ctype/iswalnum.c new file mode 100644 index 000000000..71628dcfa --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswalnum.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int iswalnum(wint_t wc) { + return iswdigit(wc) || iswalpha(wc); +} + +int __iswalnum_l(wint_t c, locale_t l) { + return iswalnum(c); +} + +weak_alias(__iswalnum_l, iswalnum_l); diff --git a/third_party/ulib/musl/src/ctype/iswalpha.c b/third_party/ulib/musl/src/ctype/iswalpha.c new file mode 100644 index 000000000..0b07a2abd --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswalpha.c @@ -0,0 +1,18 @@ +#include "libc.h" +#include + +static const unsigned char table[] = { +#include "alpha.h" +}; + +int iswalpha(wint_t wc) { + if (wc < 0x20000U) return (table[table[wc >> 8] * 32 + ((wc & 255) >> 3)] >> (wc & 7)) & 1; + if (wc < 0x2fffeU) return 1; + return 0; +} + +int __iswalpha_l(wint_t c, locale_t l) { + return iswalpha(c); +} + +weak_alias(__iswalpha_l, iswalpha_l); diff --git a/third_party/ulib/musl/src/ctype/iswblank.c b/third_party/ulib/musl/src/ctype/iswblank.c new file mode 100644 index 000000000..ae11380cf --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswblank.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#include + +int iswblank(wint_t wc) { + return isblank(wc); +} + +int __iswblank_l(wint_t c, locale_t l) { + return iswblank(c); +} + +weak_alias(__iswblank_l, iswblank_l); diff --git a/third_party/ulib/musl/src/ctype/iswcntrl.c b/third_party/ulib/musl/src/ctype/iswcntrl.c new file mode 100644 index 000000000..02d8c3df7 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswcntrl.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include + +int iswcntrl(wint_t wc) { + return (unsigned)wc < 32 || (unsigned)(wc - 0x7f) < 33 || (unsigned)(wc - 0x2028) < 2 || + (unsigned)(wc - 0xfff9) < 3; +} + +int __iswcntrl_l(wint_t c, locale_t l) { + return iswcntrl(c); +} + +weak_alias(__iswcntrl_l, iswcntrl_l); diff --git a/third_party/ulib/musl/src/ctype/iswctype.c b/third_party/ulib/musl/src/ctype/iswctype.c new file mode 100644 index 000000000..8c775ce9b --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswctype.c @@ -0,0 +1,78 @@ +#include "libc.h" +#include +#include + +#define WCTYPE_ALNUM 1 +#define WCTYPE_ALPHA 2 +#define WCTYPE_BLANK 3 +#define WCTYPE_CNTRL 4 +#define WCTYPE_DIGIT 5 +#define WCTYPE_GRAPH 6 +#define WCTYPE_LOWER 7 +#define WCTYPE_PRINT 8 +#define WCTYPE_PUNCT 9 +#define WCTYPE_SPACE 10 +#define WCTYPE_UPPER 11 +#define WCTYPE_XDIGIT 12 + +int iswctype(wint_t wc, wctype_t type) { + switch (type) { + case WCTYPE_ALNUM: + return iswalnum(wc); + case WCTYPE_ALPHA: + return iswalpha(wc); + case WCTYPE_BLANK: + return iswblank(wc); + case WCTYPE_CNTRL: + return iswcntrl(wc); + case WCTYPE_DIGIT: + return iswdigit(wc); + case WCTYPE_GRAPH: + return iswgraph(wc); + case WCTYPE_LOWER: + return iswlower(wc); + case WCTYPE_PRINT: + return iswprint(wc); + case WCTYPE_PUNCT: + return iswpunct(wc); + case WCTYPE_SPACE: + return iswspace(wc); + case WCTYPE_UPPER: + return iswupper(wc); + case WCTYPE_XDIGIT: + return iswxdigit(wc); + } + return 0; +} + +wctype_t wctype(const char* s) { + int i; + const char* p; + /* order must match! */ + static const char names[] = "alnum\0" + "alpha\0" + "blank\0" + "cntrl\0" + "digit\0" + "graph\0" + "lower\0" + "print\0" + "punct\0" + "space\0" + "upper\0" + "xdigit"; + for (i = 1, p = names; *p; i++, p += 6) + if (*s == *p && !strcmp(s, p)) return i; + return 0; +} + +int __iswctype_l(wint_t c, wctype_t t, locale_t l) { + return iswctype(c, t); +} + +wctype_t __wctype_l(const char* s, locale_t l) { + return wctype(s); +} + +weak_alias(__iswctype_l, iswctype_l); +weak_alias(__wctype_l, wctype_l); diff --git a/third_party/ulib/musl/src/ctype/iswdigit.c b/third_party/ulib/musl/src/ctype/iswdigit.c new file mode 100644 index 000000000..2d605ce49 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswdigit.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include + +#undef iswdigit + +int iswdigit(wint_t wc) { + return (unsigned)wc - '0' < 10; +} + +int __iswdigit_l(wint_t c, locale_t l) { + return iswdigit(c); +} + +weak_alias(__iswdigit_l, iswdigit_l); diff --git a/third_party/ulib/musl/src/ctype/iswgraph.c b/third_party/ulib/musl/src/ctype/iswgraph.c new file mode 100644 index 000000000..4de276937 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswgraph.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include + +int iswgraph(wint_t wc) { + /* ISO C defines this function as: */ + return !iswspace(wc) && iswprint(wc); +} + +int __iswgraph_l(wint_t c, locale_t l) { + return iswgraph(c); +} + +weak_alias(__iswgraph_l, iswgraph_l); diff --git a/third_party/ulib/musl/src/ctype/iswlower.c b/third_party/ulib/musl/src/ctype/iswlower.c new file mode 100644 index 000000000..74671baa3 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswlower.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int iswlower(wint_t wc) { + return towupper(wc) != wc; +} + +int __iswlower_l(wint_t c, locale_t l) { + return iswlower(c); +} + +weak_alias(__iswlower_l, iswlower_l); diff --git a/third_party/ulib/musl/src/ctype/iswprint.c b/third_party/ulib/musl/src/ctype/iswprint.c new file mode 100644 index 000000000..bbc6de6b2 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswprint.c @@ -0,0 +1,22 @@ +#include "libc.h" +#include + +/* Consider all legal codepoints as printable except for: + * - C0 and C1 control characters + * - U+2028 and U+2029 (line/para break) + * - U+FFF9 through U+FFFB (interlinear annotation controls) + * The following code is optimized heavily to make hot paths for the + * expected printable characters. */ + +int iswprint(wint_t wc) { + if (wc < 0xffU) return (wc + 1 & 0x7f) >= 0x21; + if (wc < 0x2028U || wc - 0x202aU < 0xd800 - 0x202a || wc - 0xe000U < 0xfff9 - 0xe000) return 1; + if (wc - 0xfffcU > 0x10ffff - 0xfffc || (wc & 0xfffe) == 0xfffe) return 0; + return 1; +} + +int __iswprint_l(wint_t c, locale_t l) { + return iswprint(c); +} + +weak_alias(__iswprint_l, iswprint_l); diff --git a/third_party/ulib/musl/src/ctype/iswpunct.c b/third_party/ulib/musl/src/ctype/iswpunct.c new file mode 100644 index 000000000..cd7953870 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswpunct.c @@ -0,0 +1,17 @@ +#include "libc.h" +#include + +static const unsigned char table[] = { +#include "punct.h" +}; + +int iswpunct(wint_t wc) { + if (wc < 0x20000U) return (table[table[wc >> 8] * 32 + ((wc & 255) >> 3)] >> (wc & 7)) & 1; + return 0; +} + +int __iswpunct_l(wint_t c, locale_t l) { + return iswpunct(c); +} + +weak_alias(__iswpunct_l, iswpunct_l); diff --git a/third_party/ulib/musl/src/ctype/iswspace.c b/third_party/ulib/musl/src/ctype/iswspace.c new file mode 100644 index 000000000..2b78ece56 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswspace.c @@ -0,0 +1,20 @@ +#include "libc.h" +#include +#include + +/* Our definition of whitespace is the Unicode White_Space property, + * minus non-breaking spaces (U+00A0, U+2007, and U+202F) and script- + * specific characters with non-blank glyphs (U+1680 and U+180E). */ + +int iswspace(wint_t wc) { + static const wchar_t spaces[] = {' ', '\t', '\n', '\r', 11, 12, 0x0085, 0x2000, + 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2008, 0x2009, + 0x200a, 0x2028, 0x2029, 0x205f, 0x3000, 0}; + return wc && wcschr(spaces, wc); +} + +int __iswspace_l(wint_t c, locale_t l) { + return iswspace(c); +} + +weak_alias(__iswspace_l, iswspace_l); diff --git a/third_party/ulib/musl/src/ctype/iswupper.c b/third_party/ulib/musl/src/ctype/iswupper.c new file mode 100644 index 000000000..97a2d9b8a --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswupper.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int iswupper(wint_t wc) { + return towlower(wc) != wc; +} + +int __iswupper_l(wint_t c, locale_t l) { + return iswupper(c); +} + +weak_alias(__iswupper_l, iswupper_l); diff --git a/third_party/ulib/musl/src/ctype/iswxdigit.c b/third_party/ulib/musl/src/ctype/iswxdigit.c new file mode 100644 index 000000000..5b3fd804e --- /dev/null +++ b/third_party/ulib/musl/src/ctype/iswxdigit.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int iswxdigit(wint_t wc) { + return (unsigned)(wc - '0') < 10 || (unsigned)((wc | 32) - 'a') < 6; +} + +int __iswxdigit_l(wint_t c, locale_t l) { + return iswxdigit(c); +} + +weak_alias(__iswxdigit_l, iswxdigit_l); diff --git a/third_party/ulib/musl/src/ctype/isxdigit.c b/third_party/ulib/musl/src/ctype/isxdigit.c new file mode 100644 index 000000000..e66632430 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/isxdigit.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +int isxdigit(int c) { + return isdigit(c) || ((unsigned)c | 32) - 'a' < 6; +} + +int __isxdigit_l(int c, locale_t l) { + return isxdigit(c); +} + +weak_alias(__isxdigit_l, isxdigit_l); diff --git a/third_party/ulib/musl/src/ctype/nonspacing.h b/third_party/ulib/musl/src/ctype/nonspacing.h new file mode 100644 index 000000000..32e3bc141 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/nonspacing.h @@ -0,0 +1,70 @@ +16, 16, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 16, 32, 16, 16, 16, 33, 34, + 35, 36, 37, 38, 39, 16, 16, 40, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 41, 42, 16, 16, 43, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 16, 45, + 46, 47, 48, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 49, 16, 16, 50, 51, 16, 52, 16, 16, 16, 16, 16, 16, 16, + 16, 53, 16, 16, 16, 16, 16, 54, 55, 16, 16, 16, 16, 56, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 57, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 58, 59, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, + 255, 255, 191, 182, 0, 0, 0, 0, 0, 0, 0, 31, 0, 255, 7, 0, 0, 0, 0, 0, 248, 255, 255, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 191, 159, 61, 0, 0, 0, 128, 2, 0, 0, 0, 255, 255, 255, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 1, 0, 0, 0, 0, 0, 0, 248, 15, 0, 0, 0, 192, 251, 239, + 62, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 127, 7, 0, + 0, 0, 0, 0, 0, 20, 254, 33, 254, 0, 12, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 16, 30, 32, 0, 0, 12, 0, + 0, 0, 6, 0, 0, 0, 0, 0, 0, 16, 134, 57, 2, 0, 0, 0, 35, 0, 6, 0, 0, 0, 0, 0, 0, 16, 190, 33, 0, + 0, 12, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 144, 30, 32, 64, 0, 12, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 193, 61, 96, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 144, 64, 48, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 32, 0, 0, 12, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 7, 128, 127, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 242, 27, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 160, 2, 0, 0, 0, 0, 0, 0, + 254, 127, 223, 224, 255, 254, 255, 255, 255, 31, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, + 253, 102, 0, 0, 0, 195, 1, 0, 30, 0, 100, 32, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 28, 0, 0, 0, 28, 0, 0, 0, 12, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 176, 63, 64, 254, 15, 32, 0, + 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 135, 1, 4, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 128, 1, 0, 0, 0, 0, 0, 0, 64, 127, 229, 31, 248, 159, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 208, 23, 4, 0, 0, 0, 0, 248, 15, 0, 3, 0, 0, 0, 60, + 11, 0, 0, 0, 0, 0, 0, 64, 163, 3, 0, 0, 0, 0, 0, 0, 240, 207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 247, 255, 253, 33, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 127, 0, 0, 240, 0, 248, 0, 0, 0, 124, 0, 0, 0, 0, + 0, 0, 31, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, + 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 247, 63, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 68, 8, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 255, 255, + 3, 0, 0, 0, 0, 0, 192, 63, 0, 0, 128, 255, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 200, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 102, 0, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 193, + 2, 0, 0, 0, 0, 48, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 110, 240, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 255, 127, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 120, 38, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 128, 239, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 192, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 128, 3, 248, 255, 231, 15, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/third_party/ulib/musl/src/ctype/punct.h b/third_party/ulib/musl/src/ctype/punct.h new file mode 100644 index 000000000..7a5a13e6f --- /dev/null +++ b/third_party/ulib/musl/src/ctype/punct.h @@ -0,0 +1,121 @@ +18, 16, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 16, 16, 34, 35, 16, 36, 37, 38, + 39, 40, 41, 42, 43, 16, 44, 45, 46, 17, 47, 48, 17, 17, 49, 17, 17, 17, 50, 51, 52, 53, 54, 55, + 56, 57, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 58, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 59, 16, 60, 61, 62, + 63, 64, 65, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 66, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 67, 16, 16, 68, 16, 69, 70, 71, 16, 72, 16, 73, 16, 16, 16, 16, 74, + 75, 76, 77, 16, 16, 78, 16, 79, 80, 16, 16, 16, 16, 81, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 82, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 83, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 84, 85, 86, 87, 16, 16, 88, 89, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 90, 16, 91, 92, 93, 94, 95, 96, 97, 98, 16, + 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, + 0, 0, 254, 255, 0, 252, 1, 0, 0, 248, 1, 0, 0, 120, 0, 0, 0, 0, 255, 251, 223, 251, 0, 0, 128, + 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, + 252, 255, 224, 175, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 223, 255, 255, 255, 255, + 255, 32, 64, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 252, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 252, 0, 0, 0, 0, 0, 134, 254, 255, 255, 255, 0, 64, 73, 0, 0, 0, 0, 0, 24, 0, 223, 255, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 1, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 224, 1, 30, 0, 96, + 255, 191, 0, 0, 0, 0, 0, 0, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 248, 207, 3, 0, 0, 0, 3, 0, 32, 255, 127, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 30, 0, 48, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, + 0, 32, 0, 0, 0, 0, 252, 15, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 0, 32, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 255, 0, 0, + 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 63, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 128, 0, 128, 192, 223, 0, 12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 0, 252, 255, 255, 0, + 0, 0, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0, 0, 0, 192, 255, 223, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128, 6, 0, 252, 0, 0, 24, 62, 0, 0, 128, 191, 0, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 31, 0, 0, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 1, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, + 0, 0, 0, 0, 16, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 254, 127, + 47, 0, 0, 255, 3, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 196, 255, 255, 255, 255, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 224, 159, 0, 0, 0, + 0, 127, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 0, 252, 255, 255, 255, + 31, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 64, 0, 12, 240, 0, 0, 0, 0, 0, 0, 192, 248, 0, 0, 0, 0, + 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 255, 255, 33, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 127, 0, 0, 240, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 3, 224, 0, 224, 0, 224, 0, 96, + 128, 248, 255, 255, 255, 252, 255, 255, 255, 255, 255, 127, 31, 252, 241, 127, 255, 127, 0, 0, + 255, 255, 255, 3, 0, 0, 255, 255, 255, 255, 1, 0, 123, 3, 208, 193, 175, 66, 0, 12, 31, 188, + 255, 255, 0, 0, 0, 0, 0, 2, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 255, 255, 255, 255, 127, 0, + 0, 0, 255, 7, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 252, + 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 31, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 135, 3, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, 255, 127, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 251, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, + 0, 255, 15, 30, 255, 255, 255, 1, 252, 193, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, 15, 0, 0, 0, 255, 255, 255, 127, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, + 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, + 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 192, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 15, + 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 255, 127, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 8, 0, 0, 0, 15, 255, 3, 0, 0, 0, + 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 192, 0, 0, 255, 255, 3, 7, 0, 0, 0, 0, 0, 248, 0, + 0, 0, 0, 8, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 255, 63, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 240, 0, 0, 128, 11, 0, 0, 0, 0, 0, 0, 0, 128, 2, 0, 0, 192, 0, 0, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 255, 255, 255, 3, 127, 0, 255, 255, 255, 255, 247, 255, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 128, 254, 255, 0, 252, 1, 0, 0, 248, 1, 0, 0, 248, 63, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 48, 135, 255, 255, 255, 255, 255, 143, 255, 0, 0, 0, 0, + 0, 0, 224, 255, 255, 7, 255, 15, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 128, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 192, 143, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 135, 255, 0, 255, 1, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 63, 252, 255, 63, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 254, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 225, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 63, 0, 255, 255, 255, 255, 127, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, + 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 8, 0, 0, 0, 8, 0, 0, 32, 0, 0, 0, 32, 0, 0, 128, 0, 0, 0, 128, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 255, 255, 255, 255, 255, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 15, 0, 255, 127, 254, 127, 254, 255, 254, 255, 0, 0, 0, 0, 255, 7, 255, 255, 255, + 127, 255, 255, 255, 255, 255, 255, 255, 15, 255, 255, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 192, 255, 255, 255, 7, 0, 255, 255, 255, 255, 255, 7, 255, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 1, 0, 191, 255, 255, 255, 255, 255, 255, + 255, 255, 31, 255, 255, 15, 0, 255, 255, 255, 255, 223, 7, 0, 0, 255, 255, 1, 0, 255, 255, 255, + 255, 255, 255, 255, 127, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 30, 255, 255, 255, 255, 255, 255, 255, 63, 15, 0, + 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 255, 255, + 255, 255, 255, 255, 225, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, + 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/third_party/ulib/musl/src/ctype/toascii.c b/third_party/ulib/musl/src/ctype/toascii.c new file mode 100644 index 000000000..be5f94800 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/toascii.c @@ -0,0 +1,6 @@ +#include + +/* nonsense function that should NEVER be used! */ +int toascii(int c) { + return c & 0x7f; +} diff --git a/third_party/ulib/musl/src/ctype/tolower.c b/third_party/ulib/musl/src/ctype/tolower.c new file mode 100644 index 000000000..45d7f5653 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/tolower.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include + +int tolower(int c) { + if (isupper(c)) return c | 32; + return c; +} + +int __tolower_l(int c, locale_t l) { + return tolower(c); +} + +weak_alias(__tolower_l, tolower_l); diff --git a/third_party/ulib/musl/src/ctype/toupper.c b/third_party/ulib/musl/src/ctype/toupper.c new file mode 100644 index 000000000..93e1da5fb --- /dev/null +++ b/third_party/ulib/musl/src/ctype/toupper.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include + +int toupper(int c) { + if (islower(c)) return c & 0x5f; + return c; +} + +int __toupper_l(int c, locale_t l) { + return toupper(c); +} + +weak_alias(__toupper_l, toupper_l); diff --git a/third_party/ulib/musl/src/ctype/towctrans.c b/third_party/ulib/musl/src/ctype/towctrans.c new file mode 100644 index 000000000..cdf705bf3 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/towctrans.c @@ -0,0 +1,241 @@ +#include "libc.h" +#include + +#define CASEMAP(u1, u2, l) \ + { (u1), (l) - (u1), (u2) - (u1) + 1 } +#define CASELACE(u1, u2) CASEMAP((u1), (u2), (u1) + 1) + +static const struct { + unsigned short upper; + signed char lower; + unsigned char len; +} casemaps[] = {CASEMAP('A', 'Z', 'a'), CASEMAP(0xc0, 0xde, 0xe0), + + CASELACE(0x0100, 0x012e), CASELACE(0x0132, 0x0136), + CASELACE(0x0139, 0x0147), CASELACE(0x014a, 0x0176), + CASELACE(0x0179, 0x017d), + + CASELACE(0x370, 0x372), CASEMAP(0x391, 0x3a1, 0x3b1), + CASEMAP(0x3a3, 0x3ab, 0x3c3), CASEMAP(0x400, 0x40f, 0x450), + CASEMAP(0x410, 0x42f, 0x430), + + CASELACE(0x460, 0x480), CASELACE(0x48a, 0x4be), + CASELACE(0x4c1, 0x4cd), CASELACE(0x4d0, 0x50e), + + CASELACE(0x514, 0x526), CASEMAP(0x531, 0x556, 0x561), + + CASELACE(0x01a0, 0x01a4), CASELACE(0x01b3, 0x01b5), + CASELACE(0x01cd, 0x01db), CASELACE(0x01de, 0x01ee), + CASELACE(0x01f8, 0x021e), CASELACE(0x0222, 0x0232), + CASELACE(0x03d8, 0x03ee), + + CASELACE(0x1e00, 0x1e94), CASELACE(0x1ea0, 0x1efe), + + CASEMAP(0x1f08, 0x1f0f, 0x1f00), CASEMAP(0x1f18, 0x1f1d, 0x1f10), + CASEMAP(0x1f28, 0x1f2f, 0x1f20), CASEMAP(0x1f38, 0x1f3f, 0x1f30), + CASEMAP(0x1f48, 0x1f4d, 0x1f40), + + CASEMAP(0x1f68, 0x1f6f, 0x1f60), CASEMAP(0x1f88, 0x1f8f, 0x1f80), + CASEMAP(0x1f98, 0x1f9f, 0x1f90), CASEMAP(0x1fa8, 0x1faf, 0x1fa0), + CASEMAP(0x1fb8, 0x1fb9, 0x1fb0), CASEMAP(0x1fba, 0x1fbb, 0x1f70), + CASEMAP(0x1fc8, 0x1fcb, 0x1f72), CASEMAP(0x1fd8, 0x1fd9, 0x1fd0), + CASEMAP(0x1fda, 0x1fdb, 0x1f76), CASEMAP(0x1fe8, 0x1fe9, 0x1fe0), + CASEMAP(0x1fea, 0x1feb, 0x1f7a), CASEMAP(0x1ff8, 0x1ff9, 0x1f78), + CASEMAP(0x1ffa, 0x1ffb, 0x1f7c), + + CASELACE(0x246, 0x24e), CASELACE(0x510, 0x512), + CASEMAP(0x2160, 0x216f, 0x2170), CASEMAP(0x2c00, 0x2c2e, 0x2c30), + CASELACE(0x2c67, 0x2c6b), CASELACE(0x2c80, 0x2ce2), + CASELACE(0x2ceb, 0x2ced), + + CASELACE(0xa640, 0xa66c), CASELACE(0xa680, 0xa696), + + CASELACE(0xa722, 0xa72e), CASELACE(0xa732, 0xa76e), + CASELACE(0xa779, 0xa77b), CASELACE(0xa77e, 0xa786), + + CASELACE(0xa790, 0xa792), CASELACE(0xa7a0, 0xa7a8), + + CASEMAP(0xff21, 0xff3a, 0xff41), {0, 0, 0}}; + +static const unsigned short pairs[][2] = {{'I', 0x0131}, + {'S', 0x017f}, + {0x0130, 'i'}, + {0x0178, 0x00ff}, + {0x0181, 0x0253}, + {0x0182, 0x0183}, + {0x0184, 0x0185}, + {0x0186, 0x0254}, + {0x0187, 0x0188}, + {0x0189, 0x0256}, + {0x018a, 0x0257}, + {0x018b, 0x018c}, + {0x018e, 0x01dd}, + {0x018f, 0x0259}, + {0x0190, 0x025b}, + {0x0191, 0x0192}, + {0x0193, 0x0260}, + {0x0194, 0x0263}, + {0x0196, 0x0269}, + {0x0197, 0x0268}, + {0x0198, 0x0199}, + {0x019c, 0x026f}, + {0x019d, 0x0272}, + {0x019f, 0x0275}, + {0x01a6, 0x0280}, + {0x01a7, 0x01a8}, + {0x01a9, 0x0283}, + {0x01ac, 0x01ad}, + {0x01ae, 0x0288}, + {0x01af, 0x01b0}, + {0x01b1, 0x028a}, + {0x01b2, 0x028b}, + {0x01b7, 0x0292}, + {0x01b8, 0x01b9}, + {0x01bc, 0x01bd}, + {0x01c4, 0x01c6}, + {0x01c4, 0x01c5}, + {0x01c5, 0x01c6}, + {0x01c7, 0x01c9}, + {0x01c7, 0x01c8}, + {0x01c8, 0x01c9}, + {0x01ca, 0x01cc}, + {0x01ca, 0x01cb}, + {0x01cb, 0x01cc}, + {0x01f1, 0x01f3}, + {0x01f1, 0x01f2}, + {0x01f2, 0x01f3}, + {0x01f4, 0x01f5}, + {0x01f6, 0x0195}, + {0x01f7, 0x01bf}, + {0x0220, 0x019e}, + {0x0386, 0x03ac}, + {0x0388, 0x03ad}, + {0x0389, 0x03ae}, + {0x038a, 0x03af}, + {0x038c, 0x03cc}, + {0x038e, 0x03cd}, + {0x038f, 0x03ce}, + {0x0399, 0x0345}, + {0x0399, 0x1fbe}, + {0x03a3, 0x03c2}, + {0x03f7, 0x03f8}, + {0x03fa, 0x03fb}, + {0x1e60, 0x1e9b}, + {0x1e9e, 0xdf}, + + {0x1f59, 0x1f51}, + {0x1f5b, 0x1f53}, + {0x1f5d, 0x1f55}, + {0x1f5f, 0x1f57}, + {0x1fbc, 0x1fb3}, + {0x1fcc, 0x1fc3}, + {0x1fec, 0x1fe5}, + {0x1ffc, 0x1ff3}, + + {0x23a, 0x2c65}, + {0x23b, 0x23c}, + {0x23d, 0x19a}, + {0x23e, 0x2c66}, + {0x241, 0x242}, + {0x243, 0x180}, + {0x244, 0x289}, + {0x245, 0x28c}, + {0x3f4, 0x3b8}, + {0x3f9, 0x3f2}, + {0x3fd, 0x37b}, + {0x3fe, 0x37c}, + {0x3ff, 0x37d}, + {0x4c0, 0x4cf}, + + {0x2126, 0x3c9}, + {0x212a, 'k'}, + {0x212b, 0xe5}, + {0x2132, 0x214e}, + {0x2183, 0x2184}, + {0x2c60, 0x2c61}, + {0x2c62, 0x26b}, + {0x2c63, 0x1d7d}, + {0x2c64, 0x27d}, + {0x2c6d, 0x251}, + {0x2c6e, 0x271}, + {0x2c6f, 0x250}, + {0x2c70, 0x252}, + {0x2c72, 0x2c73}, + {0x2c75, 0x2c76}, + {0x2c7e, 0x23f}, + {0x2c7f, 0x240}, + {0x2cf2, 0x2cf3}, + + {0xa77d, 0x1d79}, + {0xa78b, 0xa78c}, + {0xa78d, 0x265}, + {0xa7aa, 0x266}, + + {0x10c7, 0x2d27}, + {0x10cd, 0x2d2d}, + + /* bogus greek 'symbol' letters */ + {0x376, 0x377}, + {0x39c, 0xb5}, + {0x392, 0x3d0}, + {0x398, 0x3d1}, + {0x3a6, 0x3d5}, + {0x3a0, 0x3d6}, + {0x39a, 0x3f0}, + {0x3a1, 0x3f1}, + {0x395, 0x3f5}, + {0x3cf, 0x3d7}, + + {0, 0}}; + +static wchar_t __towcase(wchar_t wc, int lower) { + int i; + int lmul = 2 * lower - 1; + int lmask = lower - 1; + /* no letters with case in these large ranges */ + if (!iswalpha(wc) || (unsigned)wc - 0x0600 <= 0x0fff - 0x0600 || + (unsigned)wc - 0x2e00 <= 0xa63f - 0x2e00 || (unsigned)wc - 0xa800 <= 0xfeff - 0xa800) + return wc; + /* special case because the diff between upper/lower is too big */ + if (lower && (unsigned)wc - 0x10a0 < 0x2e) + if (wc > 0x10c5 && wc != 0x10c7 && wc != 0x10cd) + return wc; + else + return wc + 0x2d00 - 0x10a0; + if (!lower && (unsigned)wc - 0x2d00 < 0x26) + if (wc > 0x2d25 && wc != 0x2d27 && wc != 0x2d2d) + return wc; + else + return wc + 0x10a0 - 0x2d00; + for (i = 0; casemaps[i].len; i++) { + int base = casemaps[i].upper + (lmask & casemaps[i].lower); + if ((unsigned)wc - base < casemaps[i].len) { + if (casemaps[i].lower == 1) return wc + lower - ((wc - casemaps[i].upper) & 1); + return wc + lmul * casemaps[i].lower; + } + } + for (i = 0; pairs[i][1 - lower]; i++) { + if (pairs[i][1 - lower] == wc) return pairs[i][lower]; + } + if ((unsigned)wc - (0x10428 - 0x28 * lower) < 0x28) return wc - 0x28 + 0x50 * lower; + return wc; +} + +wint_t towupper(wint_t wc) { + return __towcase(wc, 0); +} + +wint_t towlower(wint_t wc) { + return __towcase(wc, 1); +} + +wint_t __towupper_l(wint_t c, locale_t l) { + return towupper(c); +} + +wint_t __towlower_l(wint_t c, locale_t l) { + return towlower(c); +} + +weak_alias(__towupper_l, towupper_l); +weak_alias(__towlower_l, towlower_l); diff --git a/third_party/ulib/musl/src/ctype/wcswidth.c b/third_party/ulib/musl/src/ctype/wcswidth.c new file mode 100644 index 000000000..ec79bab6f --- /dev/null +++ b/third_party/ulib/musl/src/ctype/wcswidth.c @@ -0,0 +1,8 @@ +#include + +int wcswidth(const wchar_t* wcs, size_t n) { + int l = 0, k = 0; + for (; n-- && *wcs && (k = wcwidth(*wcs)) >= 0; l += k, wcs++) + ; + return (k < 0) ? k : l; +} diff --git a/third_party/ulib/musl/src/ctype/wctrans.c b/third_party/ulib/musl/src/ctype/wctrans.c new file mode 100644 index 000000000..df5753ddd --- /dev/null +++ b/third_party/ulib/musl/src/ctype/wctrans.c @@ -0,0 +1,26 @@ +#include "libc.h" +#include +#include + +wctrans_t wctrans(const char* class) { + if (!strcmp(class, "toupper")) return (wctrans_t)1; + if (!strcmp(class, "tolower")) return (wctrans_t)2; + return 0; +} + +wint_t towctrans(wint_t wc, wctrans_t trans) { + if (trans == (wctrans_t)1) return towupper(wc); + if (trans == (wctrans_t)2) return towlower(wc); + return wc; +} + +wctrans_t __wctrans_l(const char* s, locale_t l) { + return wctrans(s); +} + +wint_t __towctrans_l(wint_t c, wctrans_t t, locale_t l) { + return towctrans(c, t); +} + +weak_alias(__wctrans_l, wctrans_l); +weak_alias(__towctrans_l, towctrans_l); diff --git a/third_party/ulib/musl/src/ctype/wcwidth.c b/third_party/ulib/musl/src/ctype/wcwidth.c new file mode 100644 index 000000000..60575e736 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/wcwidth.c @@ -0,0 +1,22 @@ +#include + +static const unsigned char table[] = { +#include "nonspacing.h" +}; + +static const unsigned char wtable[] = { +#include "wide.h" +}; + +int wcwidth(wchar_t wc) { + if (wc < 0xffU) return (wc + 1 & 0x7f) >= 0x21 ? 1 : wc ? -1 : 0; + if ((wc & 0xfffeffffU) < 0xfffe) { + if ((table[table[wc >> 8] * 32 + ((wc & 255) >> 3)] >> (wc & 7)) & 1) return 0; + if ((wtable[wtable[wc >> 8] * 32 + ((wc & 255) >> 3)] >> (wc & 7)) & 1) return 2; + return 1; + } + if ((wc & 0xfffe) == 0xfffe) return -1; + if (wc - 0x20000U < 0x20000) return 2; + if (wc == 0xe0001 || wc - 0xe0020U < 0x5f || wc - 0xe0100 < 0xef) return 0; + return 1; +} diff --git a/third_party/ulib/musl/src/ctype/wide.h b/third_party/ulib/musl/src/ctype/wide.h new file mode 100644 index 000000000..c735d2384 --- /dev/null +++ b/third_party/ulib/musl/src/ctype/wide.h @@ -0,0 +1,45 @@ +16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 19, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 21, 22, + 23, 24, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 25, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 26, 16, 16, 16, 16, + 27, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 28, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 16, 16, 16, 29, 30, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 31, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 248, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 251, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, + 0, 255, 15, 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 127, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 255, 255, 255, + 255, 63, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 255, 255, 255, 255, 255, 7, + 255, 255, 255, 255, 15, 0, 255, 255, 255, 255, 255, 127, 255, 255, 255, 255, 255, 0, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 255, 255, 255, 255, 255, 255, 127, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 15, 0, 255, 255, 127, 248, 255, 255, 255, 255, 255, 15, 0, 0, 255, 3, 0, 0, + 255, 255, 255, 255, 247, 255, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 127, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 255, 255, 255, 255, 255, 7, 255, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/third_party/ulib/musl/src/dirent/BUILD.gn b/third_party/ulib/musl/src/dirent/BUILD.gn new file mode 100644 index 000000000..8416cb6b1 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/BUILD.gn @@ -0,0 +1,21 @@ +source_set("dirent") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__getdents.c", + "alphasort.c", + "closedir.c", + "dirfd.c", + "fdopendir.c", + "opendir.c", + "readdir.c", + "readdir_r.c", + "rewinddir.c", + "scandir.c", + "seekdir.c", + "telldir.c", + "versionsort.c", + ] +} diff --git a/third_party/ulib/musl/src/dirent/__dirent.h b/third_party/ulib/musl/src/dirent/__dirent.h new file mode 100644 index 000000000..14771d8b9 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/__dirent.h @@ -0,0 +1,16 @@ +#include "libc.h" + +#define __NEED_off_t + +#include + +#include + +struct __dirstream { + int fd; + off_t tell; + int buf_pos; + int buf_end; + mxr_mutex_t lock; + char buf[2048]; +}; diff --git a/third_party/ulib/musl/src/dirent/__getdents.c b/third_party/ulib/musl/src/dirent/__getdents.c new file mode 100644 index 000000000..bcdad7fd7 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/__getdents.c @@ -0,0 +1,11 @@ +#include "libc.h" +#include "syscall.h" +#include + +int __getdents(int fd, struct dirent* buf, size_t len) { + return syscall(SYS_getdents, fd, buf, len); +} + +weak_alias(__getdents, getdents); + +LFS64(getdents); diff --git a/third_party/ulib/musl/src/dirent/alphasort.c b/third_party/ulib/musl/src/dirent/alphasort.c new file mode 100644 index 000000000..c24a113cf --- /dev/null +++ b/third_party/ulib/musl/src/dirent/alphasort.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include +#include + +int alphasort(const struct dirent** a, const struct dirent** b) { + return strcoll((*a)->d_name, (*b)->d_name); +} + +LFS64(alphasort); diff --git a/third_party/ulib/musl/src/dirent/closedir.c b/third_party/ulib/musl/src/dirent/closedir.c new file mode 100644 index 000000000..a17dec82e --- /dev/null +++ b/third_party/ulib/musl/src/dirent/closedir.c @@ -0,0 +1,10 @@ +#include "__dirent.h" +#include "libc.h" +#include +#include + +int closedir(DIR* dir) { + int ret = close(dir->fd); + free(dir); + return ret; +} diff --git a/third_party/ulib/musl/src/dirent/dirfd.c b/third_party/ulib/musl/src/dirent/dirfd.c new file mode 100644 index 000000000..99143d29d --- /dev/null +++ b/third_party/ulib/musl/src/dirent/dirfd.c @@ -0,0 +1,6 @@ +#include "__dirent.h" +#include + +int dirfd(DIR* d) { + return d->fd; +} diff --git a/third_party/ulib/musl/src/dirent/fdopendir.c b/third_party/ulib/musl/src/dirent/fdopendir.c new file mode 100644 index 000000000..35fe58965 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/fdopendir.c @@ -0,0 +1,26 @@ +#include "__dirent.h" +#include +#include +#include +#include +#include + +DIR* fdopendir(int fd) { + DIR* dir; + struct stat st; + + if (fstat(fd, &st) < 0) { + return 0; + } + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return 0; + } + if (!(dir = calloc(1, sizeof *dir))) { + return 0; + } + + fcntl(fd, F_SETFD, FD_CLOEXEC); + dir->fd = fd; + return dir; +} diff --git a/third_party/ulib/musl/src/dirent/opendir.c b/third_party/ulib/musl/src/dirent/opendir.c new file mode 100644 index 000000000..5bd3bf474 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/opendir.c @@ -0,0 +1,19 @@ +#define _GNU_SOURCE +#include "__dirent.h" +#include "syscall.h" +#include +#include +#include + +DIR* opendir(const char* name) { + int fd; + DIR* dir; + + if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)) < 0) return 0; + if (!(dir = calloc(1, sizeof *dir))) { + __syscall(SYS_close, fd); + return 0; + } + dir->fd = fd; + return dir; +} diff --git a/third_party/ulib/musl/src/dirent/readdir.c b/third_party/ulib/musl/src/dirent/readdir.c new file mode 100644 index 000000000..1ff767d8f --- /dev/null +++ b/third_party/ulib/musl/src/dirent/readdir.c @@ -0,0 +1,27 @@ +#include "__dirent.h" +#include "libc.h" +#include "syscall.h" +#include +#include + +int __getdents(int, struct dirent*, size_t); + +struct dirent* readdir(DIR* dir) { + struct dirent* de; + + if (dir->buf_pos >= dir->buf_end) { + int len = __syscall(SYS_getdents, dir->fd, dir->buf, sizeof dir->buf); + if (len <= 0) { + if (len < 0 && len != -ENOENT) errno = -len; + return 0; + } + dir->buf_end = len; + dir->buf_pos = 0; + } + de = (void*)(dir->buf + dir->buf_pos); + dir->buf_pos += de->d_reclen; + dir->tell = de->d_off; + return de; +} + +LFS64(readdir); diff --git a/third_party/ulib/musl/src/dirent/readdir_r.c b/third_party/ulib/musl/src/dirent/readdir_r.c new file mode 100644 index 000000000..785c32284 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/readdir_r.c @@ -0,0 +1,30 @@ +#include "__dirent.h" +#include "libc.h" +#include +#include +#include + +int readdir_r(DIR* restrict dir, struct dirent* restrict buf, struct dirent** restrict result) { + struct dirent* de; + int errno_save = errno; + int ret; + + mxr_mutex_lock(&dir->lock); + errno = 0; + de = readdir(dir); + if ((ret = errno)) { + mxr_mutex_unlock(&dir->lock); + return ret; + } + errno = errno_save; + if (de) + memcpy(buf, de, de->d_reclen); + else + buf = NULL; + + mxr_mutex_unlock(&dir->lock); + *result = buf; + return 0; +} + +LFS64_2(readdir_r, readdir64_r); diff --git a/third_party/ulib/musl/src/dirent/rewinddir.c b/third_party/ulib/musl/src/dirent/rewinddir.c new file mode 100644 index 000000000..40a7341a4 --- /dev/null +++ b/third_party/ulib/musl/src/dirent/rewinddir.c @@ -0,0 +1,12 @@ +#include "__dirent.h" +#include "libc.h" +#include +#include + +void rewinddir(DIR* dir) { + mxr_mutex_lock(&dir->lock); + lseek(dir->fd, 0, SEEK_SET); + dir->buf_pos = dir->buf_end = 0; + dir->tell = 0; + mxr_mutex_unlock(&dir->lock); +} diff --git a/third_party/ulib/musl/src/dirent/scandir.c b/third_party/ulib/musl/src/dirent/scandir.c new file mode 100644 index 000000000..4435ae57f --- /dev/null +++ b/third_party/ulib/musl/src/dirent/scandir.c @@ -0,0 +1,48 @@ +#include "libc.h" +#include +#include +#include +#include +#include +#include + +int scandir(const char* path, struct dirent*** res, int (*sel)(const struct dirent*), + int (*cmp)(const struct dirent**, const struct dirent**)) { + DIR* d = opendir(path); + struct dirent *de, **names = 0, **tmp; + size_t cnt = 0, len = 0; + int old_errno = errno; + + if (!d) return -1; + + while ((errno = 0), (de = readdir(d))) { + if (sel && !sel(de)) continue; + if (cnt >= len) { + len = 2 * len + 1; + if (len > SIZE_MAX / sizeof *names) break; + tmp = realloc(names, len * sizeof *names); + if (!tmp) break; + names = tmp; + } + names[cnt] = malloc(de->d_reclen); + if (!names[cnt]) break; + memcpy(names[cnt++], de, de->d_reclen); + } + + closedir(d); + + if (errno) { + if (names) + while (cnt-- > 0) + free(names[cnt]); + free(names); + return -1; + } + errno = old_errno; + + if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void*, const void*))cmp); + *res = names; + return cnt; +} + +LFS64(scandir); diff --git a/third_party/ulib/musl/src/dirent/seekdir.c b/third_party/ulib/musl/src/dirent/seekdir.c new file mode 100644 index 000000000..dc7cd64ba --- /dev/null +++ b/third_party/ulib/musl/src/dirent/seekdir.c @@ -0,0 +1,11 @@ +#include "__dirent.h" +#include "libc.h" +#include +#include + +void seekdir(DIR* dir, long off) { + mxr_mutex_lock(&dir->lock); + dir->tell = lseek(dir->fd, off, SEEK_SET); + dir->buf_pos = dir->buf_end = 0; + mxr_mutex_unlock(&dir->lock); +} diff --git a/third_party/ulib/musl/src/dirent/telldir.c b/third_party/ulib/musl/src/dirent/telldir.c new file mode 100644 index 000000000..310fa896a --- /dev/null +++ b/third_party/ulib/musl/src/dirent/telldir.c @@ -0,0 +1,6 @@ +#include "__dirent.h" +#include + +long telldir(DIR* dir) { + return dir->tell; +} diff --git a/third_party/ulib/musl/src/dirent/versionsort.c b/third_party/ulib/musl/src/dirent/versionsort.c new file mode 100644 index 000000000..53e47878d --- /dev/null +++ b/third_party/ulib/musl/src/dirent/versionsort.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include "libc.h" +#include +#include + +int versionsort(const struct dirent** a, const struct dirent** b) { + return strverscmp((*a)->d_name, (*b)->d_name); +} + +#undef versionsort64 +LFS64(versionsort); diff --git a/third_party/ulib/musl/src/env/BUILD.gn b/third_party/ulib/musl/src/env/BUILD.gn new file mode 100644 index 000000000..a50a01d34 --- /dev/null +++ b/third_party/ulib/musl/src/env/BUILD.gn @@ -0,0 +1,32 @@ +source_set("env") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__environ.c", + "__reset_tls.c", + "clearenv.c", + "getenv.c", + "putenv.c", + "setenv.c", + "unsetenv.c", + ] + deps = [ + ":env_no_stack_protector", + ] +} + +source_set("env_no_stack_protector") { + visibility = [ ":env" ] + configs = [] + configs += [ + "../../:musl_config", + "//gnbuild:no_stack_protector", + ] + sources = [ + "__init_tls.c", + "__libc_start_main.c", + "__stack_chk_fail.c", + ] +} diff --git a/third_party/ulib/musl/src/env/__environ.c b/third_party/ulib/musl/src/env/__environ.c new file mode 100644 index 000000000..58fc44025 --- /dev/null +++ b/third_party/ulib/musl/src/env/__environ.c @@ -0,0 +1,6 @@ +#include "libc.h" + +char** __environ = 0; +weak_alias(__environ, ___environ); +weak_alias(__environ, _environ); +weak_alias(__environ, environ); diff --git a/third_party/ulib/musl/src/env/__init_tls.c b/third_party/ulib/musl/src/env/__init_tls.c new file mode 100644 index 000000000..2964db4b5 --- /dev/null +++ b/third_party/ulib/musl/src/env/__init_tls.c @@ -0,0 +1,40 @@ +#include "atomic.h" +#include "libc.h" +#include "pthread_impl.h" +#include +#include +#include +#include + +#define ROUND(x) (((x) + PAGE_SIZE - 1) & -PAGE_SIZE) + +void* __mmap(void*, size_t, int, int, int, off_t); + +int __init_tp(pthread_t thread) { + thread->self = thread; + //TODO: Get and set thread ID + //thread->tid = __syscall(SYS_set_tid_address, &thread->tid); + thread->locale = &libc.global_locale; + thread->robust_list.head = &thread->robust_list.head; + return 0; +} + +static void* __mmap_wrapper(size_t len) { + void* p = __mmap(NULL, len, PROT_WRITE | PROT_READ, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (p == MAP_FAILED) + a_crash(); + return p; +} + +mxr_tls_t __pthread_key; + +static void static_init_tls(void) { + __pthread_key = mxr_tls_allocate(); + size_t len = ROUND(sizeof(struct pthread)); + pthread_t thread = __mmap_wrapper(len); + mxr_tls_set(__pthread_key, thread); + if(__init_tp(thread)) + a_crash(); +} +weak_alias(static_init_tls, __init_tls); diff --git a/third_party/ulib/musl/src/env/__libc_start_main.c b/third_party/ulib/musl/src/env/__libc_start_main.c new file mode 100644 index 000000000..969cbb1b2 --- /dev/null +++ b/third_party/ulib/musl/src/env/__libc_start_main.c @@ -0,0 +1,78 @@ +#include "libc.h" +#include +#include + +#include + +void __init_tls(void); +void __mxr_thread_main(void); + +static void dummy(void) {} +weak_alias(dummy, _init); + +__attribute__((__weak__, __visibility__("hidden"))) extern void (*const __init_array_start)(void), + (*const __init_array_end)(void); + +static void dummy1(void* p) {} +weak_alias(dummy1, __init_ssp); + +#define AUX_CNT 38 + +void __init_security(void) { +// TODO(kulakowski) Re-enable this once we have file descriptors up. +#if 0 + if (aux[AT_UID] == aux[AT_EUID] && aux[AT_GID] == aux[AT_EGID] && !aux[AT_SECURE]) return; + + struct pollfd pfd[3] = {{.fd = 0}, {.fd = 1}, {.fd = 2}}; +#ifdef SYS_poll + __syscall(SYS_poll, pfd, 3, 0); +#else + __syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG / 8); +#endif + for (i = 0; i < 3; i++) + if (pfd[i].revents & POLLNVAL) + if (__sys_open("/dev/null", O_RDWR) < 0) a_crash(); + libc.secure = 1; +#endif +} + +static void libc_start_init(void) { + _init(); + uintptr_t a = (uintptr_t)&__init_array_start; + for (; a < (uintptr_t)&__init_array_end; a += sizeof(void (*)(void))) + (*(void (**)(void))a)(); +} +weak_alias(libc_start_init, __libc_start_init); + +// hook for extension libraries to init +static void libc_extensions_init(mx_proc_info_t* pi) { } +weak_alias(libc_extensions_init, __libc_extensions_init); + +// hook to let certain very low level processes muck +// with arg before things start +static void* libc_intercept_arg(void* arg) { + return arg; +} +weak_alias(libc_intercept_arg, __libc_intercept_arg); + +int __libc_start_main(int (*main)(int,char**,void*), void* arg) { + arg = __libc_intercept_arg(arg); + + // extract process startup information from message pipe in arg + mx_proc_info_t* pi = mxr_process_parse_args(arg); + + __mxr_thread_main(); + + // TODO(kulakowski) Set up environment + __init_tls(); + // TODO(kulakowski) Set up ssp once kernel randomness exists + // __init_ssp((void*)aux[AT_RANDOM]); + __init_security(); + __libc_start_init(); + + // allow companion libraries a chance to poke at this + __libc_extensions_init(pi); + + // Pass control to the application + exit(main(pi->argc, pi->argv, NULL)); +} diff --git a/third_party/ulib/musl/src/env/__reset_tls.c b/third_party/ulib/musl/src/env/__reset_tls.c new file mode 100644 index 000000000..f3abe615f --- /dev/null +++ b/third_party/ulib/musl/src/env/__reset_tls.c @@ -0,0 +1,15 @@ +#include "libc.h" +#include "pthread_impl.h" +#include + +void __reset_tls(void) { + pthread_t self = __pthread_self(); + struct tls_module* p; + size_t i, n = (size_t)self->dtv[0]; + if (n) + for (p = libc.tls_head, i = 1; i <= n; i++, p = p->next) { + if (!self->dtv[i]) continue; + memcpy(self->dtv[i], p->image, p->len); + memset((char*)self->dtv[i] + p->len, 0, p->size - p->len); + } +} diff --git a/third_party/ulib/musl/src/env/__stack_chk_fail.c b/third_party/ulib/musl/src/env/__stack_chk_fail.c new file mode 100644 index 000000000..9bae371c6 --- /dev/null +++ b/third_party/ulib/musl/src/env/__stack_chk_fail.c @@ -0,0 +1,22 @@ +#include "pthread_impl.h" +#include +#include + +uintptr_t __stack_chk_guard; + +void __init_ssp(void* entropy) { + if (entropy) + memcpy(&__stack_chk_guard, entropy, sizeof(uintptr_t)); + else + __stack_chk_guard = (uintptr_t)&__stack_chk_guard * 1103515245; + + __pthread_self()->CANARY = __stack_chk_guard; +} + +void __stack_chk_fail(void) { + a_crash(); +} + +__attribute__((__visibility__("hidden"))) void __stack_chk_fail_local(void); + +weak_alias(__stack_chk_fail, __stack_chk_fail_local); diff --git a/third_party/ulib/musl/src/env/clearenv.c b/third_party/ulib/musl/src/env/clearenv.c new file mode 100644 index 000000000..cdcd0b09c --- /dev/null +++ b/third_party/ulib/musl/src/env/clearenv.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include + +extern char** __environ; + +int clearenv() { + __environ[0] = 0; + return 0; +} diff --git a/third_party/ulib/musl/src/env/getenv.c b/third_party/ulib/musl/src/env/getenv.c new file mode 100644 index 000000000..67423054b --- /dev/null +++ b/third_party/ulib/musl/src/env/getenv.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include +#include + +char* getenv(const char* name) { + int i; + size_t l = strlen(name); + if (!__environ || !*name || strchr(name, '=')) return NULL; + for (i = 0; __environ[i] && (strncmp(name, __environ[i], l) || __environ[i][l] != '='); i++) + ; + if (__environ[i]) return __environ[i] + l + 1; + return NULL; +} diff --git a/third_party/ulib/musl/src/env/putenv.c b/third_party/ulib/musl/src/env/putenv.c new file mode 100644 index 000000000..bbd890ada --- /dev/null +++ b/third_party/ulib/musl/src/env/putenv.c @@ -0,0 +1,58 @@ +#include +#include + +extern char** __environ; +char** __env_map; + +int __putenv(char* s, int a) { + int i = 0, j = 0; + char* z = strchr(s, '='); + char** newenv = 0; + char** newmap = 0; + static char** oldenv; + + if (!z) return unsetenv(s); + if (z == s) return -1; + for (; __environ[i] && memcmp(s, __environ[i], z - s + 1); i++) + ; + if (a) { + if (!__env_map) { + __env_map = calloc(2, sizeof(char*)); + if (__env_map) __env_map[0] = s; + } else { + for (; __env_map[j] && __env_map[j] != __environ[i]; j++) + ; + if (!__env_map[j]) { + newmap = realloc(__env_map, sizeof(char*) * (j + 2)); + if (newmap) { + __env_map = newmap; + __env_map[j] = s; + __env_map[j + 1] = NULL; + } + } else { + free(__env_map[j]); + __env_map[j] = s; + } + } + } + if (!__environ[i]) { + newenv = malloc(sizeof(char*) * (i + 2)); + if (!newenv) { + if (a && __env_map) __env_map[j] = 0; + return -1; + } + memcpy(newenv, __environ, sizeof(char*) * i); + newenv[i] = s; + newenv[i + 1] = 0; + __environ = newenv; + free(oldenv); + oldenv = __environ; + } + + __environ[i] = s; + return 0; +} + +int putenv(char* s) { + return __putenv(s, 0); +} diff --git a/third_party/ulib/musl/src/env/setenv.c b/third_party/ulib/musl/src/env/setenv.c new file mode 100644 index 000000000..894a7e8b0 --- /dev/null +++ b/third_party/ulib/musl/src/env/setenv.c @@ -0,0 +1,29 @@ +#include +#include +#include + +int __putenv(char* s, int a); + +int setenv(const char* var, const char* value, int overwrite) { + char* s; + int l1, l2; + + if (!var || !*var || strchr(var, '=')) { + errno = EINVAL; + return -1; + } + if (!overwrite && getenv(var)) return 0; + + l1 = strlen(var); + l2 = strlen(value); + s = malloc(l1 + l2 + 2); + if (s) { + memcpy(s, var, l1); + s[l1] = '='; + memcpy(s + l1 + 1, value, l2); + s[l1 + l2 + 1] = 0; + if (!__putenv(s, 1)) return 0; + } + free(s); + return -1; +} diff --git a/third_party/ulib/musl/src/env/unsetenv.c b/third_party/ulib/musl/src/env/unsetenv.c new file mode 100644 index 000000000..18369a172 --- /dev/null +++ b/third_party/ulib/musl/src/env/unsetenv.c @@ -0,0 +1,32 @@ +#include +#include +#include + +extern char** __environ; +extern char** __env_map; + +int unsetenv(const char* name) { + int i, j; + size_t l = strlen(name); + + if (!*name || strchr(name, '=')) { + errno = EINVAL; + return -1; + } +again: + for (i = 0; __environ[i] && (memcmp(name, __environ[i], l) || __environ[i][l] != '='); i++) + ; + if (__environ[i]) { + if (__env_map) { + for (j = 0; __env_map[j] && __env_map[j] != __environ[i]; j++) + ; + free(__env_map[j]); + for (; __env_map[j]; j++) + __env_map[j] = __env_map[j + 1]; + } + for (; __environ[i]; i++) + __environ[i] = __environ[i + 1]; + goto again; + } + return 0; +} diff --git a/third_party/ulib/musl/src/errno/BUILD.gn b/third_party/ulib/musl/src/errno/BUILD.gn new file mode 100644 index 000000000..48e799346 --- /dev/null +++ b/third_party/ulib/musl/src/errno/BUILD.gn @@ -0,0 +1,10 @@ +source_set("errno") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__errno_location.c", + "strerror.c", + ] +} diff --git a/third_party/ulib/musl/src/errno/__errno_location.c b/third_party/ulib/musl/src/errno/__errno_location.c new file mode 100644 index 000000000..086194df9 --- /dev/null +++ b/third_party/ulib/musl/src/errno/__errno_location.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int* __errno_location(void) { + return mxr_tls_get(MXR_TLS_SLOT_ERRNO); +} diff --git a/third_party/ulib/musl/src/errno/__strerror.h b/third_party/ulib/musl/src/errno/__strerror.h new file mode 100644 index 000000000..94771fc5a --- /dev/null +++ b/third_party/ulib/musl/src/errno/__strerror.h @@ -0,0 +1,104 @@ +/* This file is sorted such that 'errors' which represent exceptional + * conditions under which a correct program may fail come first, followed + * by messages that indicate an incorrect program or system failure. The + * macro E() along with double-inclusion is used to ensure that ordering + * of the strings remains synchronized. */ + +E(EILSEQ, "Illegal byte sequence") +E(EDOM, "Domain error") +E(ERANGE, "Result not representable") + +E(ENOTTY, "Not a tty") +E(EACCES, "Permission denied") +E(EPERM, "Operation not permitted") +E(ENOENT, "No such file or directory") +E(ESRCH, "No such process") +E(EEXIST, "File exists") + +E(EOVERFLOW, "Value too large for data type") +E(ENOSPC, "No space left on device") +E(ENOMEM, "Out of memory") + +E(EBUSY, "Resource busy") +E(EINTR, "Interrupted system call") +E(EAGAIN, "Resource temporarily unavailable") +E(ESPIPE, "Invalid seek") + +E(EXDEV, "Cross-device link") +E(EROFS, "Read-only file system") +E(ENOTEMPTY, "Directory not empty") + +E(ECONNRESET, "Connection reset by peer") +E(ETIMEDOUT, "Operation timed out") +E(ECONNREFUSED, "Connection refused") +E(EHOSTDOWN, "Host is down") +E(EHOSTUNREACH, "Host is unreachable") +E(EADDRINUSE, "Address in use") + +E(EPIPE, "Broken pipe") +E(EIO, "I/O error") +E(ENXIO, "No such device or address") +E(ENOTBLK, "Block device required") +E(ENODEV, "No such device") +E(ENOTDIR, "Not a directory") +E(EISDIR, "Is a directory") +E(ETXTBSY, "Text file busy") +E(ENOEXEC, "Exec format error") + +E(EINVAL, "Invalid argument") + +E(E2BIG, "Argument list too long") +E(ELOOP, "Symbolic link loop") +E(ENAMETOOLONG, "Filename too long") +E(ENFILE, "Too many open files in system") +E(EMFILE, "No file descriptors available") +E(EBADF, "Bad file descriptor") +E(ECHILD, "No child process") +E(EFAULT, "Bad address") +E(EFBIG, "File too large") +E(EMLINK, "Too many links") +E(ENOLCK, "No locks available") + +E(EDEADLK, "Resource deadlock would occur") +E(ENOTRECOVERABLE, "State not recoverable") +E(EOWNERDEAD, "Previous owner died") +E(ECANCELED, "Operation canceled") +E(ENOSYS, "Function not implemented") +E(ENOMSG, "No message of desired type") +E(EIDRM, "Identifier removed") +E(ENOSTR, "Device not a stream") +E(ENODATA, "No data available") +E(ETIME, "Device timeout") +E(ENOSR, "Out of streams resources") +E(ENOLINK, "Link has been severed") +E(EPROTO, "Protocol error") +E(EBADMSG, "Bad message") +E(EBADFD, "File descriptor in bad state") +E(ENOTSOCK, "Not a socket") +E(EDESTADDRREQ, "Destination address required") +E(EMSGSIZE, "Message too large") +E(EPROTOTYPE, "Protocol wrong type for socket") +E(ENOPROTOOPT, "Protocol not available") +E(EPROTONOSUPPORT, "Protocol not supported") +E(ESOCKTNOSUPPORT, "Socket type not supported") +E(ENOTSUP, "Not supported") +E(EPFNOSUPPORT, "Protocol family not supported") +E(EAFNOSUPPORT, "Address family not supported by protocol") +E(EADDRNOTAVAIL, "Address not available") +E(ENETDOWN, "Network is down") +E(ENETUNREACH, "Network unreachable") +E(ENETRESET, "Connection reset by network") +E(ECONNABORTED, "Connection aborted") +E(ENOBUFS, "No buffer space available") +E(EISCONN, "Socket is connected") +E(ENOTCONN, "Socket not connected") +E(ESHUTDOWN, "Cannot send after socket shutdown") +E(EALREADY, "Operation already in progress") +E(EINPROGRESS, "Operation in progress") +E(ESTALE, "Stale file handle") +E(EREMOTEIO, "Remote I/O error") +E(EDQUOT, "Quota exceeded") +E(ENOMEDIUM, "No medium found") +E(EMEDIUMTYPE, "Wrong medium type") + +E(0, "No error information") diff --git a/third_party/ulib/musl/src/errno/strerror.c b/third_party/ulib/musl/src/errno/strerror.c new file mode 100644 index 000000000..15b446d42 --- /dev/null +++ b/third_party/ulib/musl/src/errno/strerror.c @@ -0,0 +1,40 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +#define E(a, b) ((unsigned char)a), +static const unsigned char errid[] = { +#include "__strerror.h" +}; + +#undef E +#define E(a, b) b "\0" +static const char errmsg[] = +#include "__strerror.h" + ; + +char* __strerror_l(int e, locale_t loc) { + const char* s; + int i; + /* mips has one error code outside of the 8-bit range due to a + * historical typo, so we just remap it. */ + if (EDQUOT == 1133) { + if (e == 109) + e = -1; + else if (e == EDQUOT) + e = 109; + } + for (i = 0; errid[i] && errid[i] != e; i++) + ; + for (s = errmsg; i; s++, i--) + for (; *s; s++) + ; + return (char*)LCTRANS(s, LC_MESSAGES, loc); +} + +char* strerror(int e) { + return __strerror_l(e, CURRENT_LOCALE); +} + +weak_alias(__strerror_l, strerror_l); diff --git a/third_party/ulib/musl/src/exit/BUILD.gn b/third_party/ulib/musl/src/exit/BUILD.gn new file mode 100644 index 000000000..8d7b9655b --- /dev/null +++ b/third_party/ulib/musl/src/exit/BUILD.gn @@ -0,0 +1,18 @@ +source_set("exit") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "_Exit.c", + "abort.c", + "assert.c", + "at_quick_exit.c", + "atexit.c", + "exit.c", + "quick_exit.c", + ] + if (target_cpu == "arm") { + sources += [ "arm/__aeabi_atexit.c" ] + } +} diff --git a/third_party/ulib/musl/src/exit/_Exit.c b/third_party/ulib/musl/src/exit/_Exit.c new file mode 100644 index 000000000..4c2aac84b --- /dev/null +++ b/third_party/ulib/musl/src/exit/_Exit.c @@ -0,0 +1,9 @@ +#include + +#include + +_Noreturn void _Exit(int ec) { + for (;;) { + _magenta_exit(ec); + } +} diff --git a/third_party/ulib/musl/src/exit/abort.c b/third_party/ulib/musl/src/exit/abort.c new file mode 100644 index 000000000..bf47dd148 --- /dev/null +++ b/third_party/ulib/musl/src/exit/abort.c @@ -0,0 +1,10 @@ +#include + +#include + +_Noreturn void abort(void) { + // TODO(kulakowski) This can (and should) be more robust. + for (;;) { + _magenta_exit(-1); + } +} diff --git a/third_party/ulib/musl/src/exit/arm/__aeabi_atexit.c b/third_party/ulib/musl/src/exit/arm/__aeabi_atexit.c new file mode 100644 index 000000000..b3d0d9470 --- /dev/null +++ b/third_party/ulib/musl/src/exit/arm/__aeabi_atexit.c @@ -0,0 +1,5 @@ +int __cxa_atexit(void (*func)(void*), void* arg, void* dso); + +int __aeabi_atexit(void* obj, void (*func)(void*), void* d) { + return __cxa_atexit(func, obj, d); +} diff --git a/third_party/ulib/musl/src/exit/assert.c b/third_party/ulib/musl/src/exit/assert.c new file mode 100644 index 000000000..67d2cc782 --- /dev/null +++ b/third_party/ulib/musl/src/exit/assert.c @@ -0,0 +1,8 @@ +#include +#include + +void __assert_fail(const char* expr, const char* file, int line, const char* func) { + fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); + fflush(NULL); + abort(); +} diff --git a/third_party/ulib/musl/src/exit/at_quick_exit.c b/third_party/ulib/musl/src/exit/at_quick_exit.c new file mode 100644 index 000000000..975815866 --- /dev/null +++ b/third_party/ulib/musl/src/exit/at_quick_exit.c @@ -0,0 +1,29 @@ +#include "libc.h" +#include + +#include + +#define COUNT 32 + +static void (*funcs[COUNT])(void); +static int count; +static mxr_mutex_t lock; + +void __funcs_on_quick_exit(void) { + void (*func)(void); + mxr_mutex_lock(&lock); + while (count > 0) { + func = funcs[--count]; + mxr_mutex_unlock(&lock); + func(); + mxr_mutex_lock(&lock); + } +} + +int at_quick_exit(void (*func)(void)) { + if (count == 32) return -1; + mxr_mutex_lock(&lock); + funcs[count++] = func; + mxr_mutex_unlock(&lock); + return 0; +} diff --git a/third_party/ulib/musl/src/exit/atexit.c b/third_party/ulib/musl/src/exit/atexit.c new file mode 100644 index 000000000..2dc22700c --- /dev/null +++ b/third_party/ulib/musl/src/exit/atexit.c @@ -0,0 +1,69 @@ +#include "libc.h" +#include +#include + +#include + +void* __dso_handle = NULL; + +/* Ensure that at least 32 atexit handlers can be registered without malloc */ +#define COUNT 32 + +static struct fl { + struct fl* next; + void (*f[COUNT])(void*); + void* a[COUNT]; +} builtin, *head; + +static int slot; +static mxr_mutex_t lock; + +void __funcs_on_exit(void) { + void (*func)(void*), *arg; + mxr_mutex_lock(&lock); + for (; head; head = head->next, slot = COUNT) + while (slot-- > 0) { + func = head->f[slot]; + arg = head->a[slot]; + mxr_mutex_unlock(&lock); + func(arg); + mxr_mutex_lock(&lock); + } +} + +void __cxa_finalize(void* dso) {} + +int __cxa_atexit(void (*func)(void*), void* arg, void* dso) { + mxr_mutex_lock(&lock); + + /* Defer initialization of head so it can be in BSS */ + if (!head) head = &builtin; + + /* If the current function list is full, add a new one */ + if (slot == COUNT) { + struct fl* new_fl = calloc(sizeof(struct fl), 1); + if (!new_fl) { + mxr_mutex_unlock(&lock); + return -1; + } + new_fl->next = head; + head = new_fl; + slot = 0; + } + + /* Append function to the list. */ + head->f[slot] = func; + head->a[slot] = arg; + slot++; + + mxr_mutex_unlock(&lock); + return 0; +} + +static void call(void* p) { + ((void (*)(void))(uintptr_t)p)(); +} + +int atexit(void (*func)(void)) { + return __cxa_atexit(call, (void*)(uintptr_t)func, __dso_handle); +} diff --git a/third_party/ulib/musl/src/exit/exit.c b/third_party/ulib/musl/src/exit/exit.c new file mode 100644 index 000000000..e53baedac --- /dev/null +++ b/third_party/ulib/musl/src/exit/exit.c @@ -0,0 +1,30 @@ +#include "libc.h" +#include +#include + +static void dummy(void) {} + +/* atexit.c and __stdio_exit.c override these. the latter is linked + * as a consequence of linking either __toread.c or __towrite.c. */ +weak_alias(dummy, __funcs_on_exit); +weak_alias(dummy, __stdio_exit); +weak_alias(dummy, _fini); + +__attribute__((__weak__, __visibility__("hidden"))) extern void (*const __fini_array_start)(void), + (*const __fini_array_end)(void); + +static void libc_exit_fini(void) { + uintptr_t a = (uintptr_t)&__fini_array_end; + for (; a > (uintptr_t)&__fini_array_start; a -= sizeof(void (*)(void))) + (*(void (**)(void))(a - sizeof(void (*)(void))))(); + _fini(); +} + +weak_alias(libc_exit_fini, __libc_exit_fini); + +_Noreturn void exit(int code) { + __funcs_on_exit(); + __libc_exit_fini(); + __stdio_exit(); + _Exit(code); +} diff --git a/third_party/ulib/musl/src/exit/quick_exit.c b/third_party/ulib/musl/src/exit/quick_exit.c new file mode 100644 index 000000000..1eacf7887 --- /dev/null +++ b/third_party/ulib/musl/src/exit/quick_exit.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include + +static void dummy(void) {} +weak_alias(dummy, __funcs_on_quick_exit); + +_Noreturn void quick_exit(int code) { + __funcs_on_quick_exit(); + _Exit(code); +} diff --git a/third_party/ulib/musl/src/fcntl/BUILD.gn b/third_party/ulib/musl/src/fcntl/BUILD.gn new file mode 100644 index 000000000..bcc0ab936 --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/BUILD.gn @@ -0,0 +1,14 @@ +source_set("fcntl") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "creat.c", + "fcntl.c", + "open.c", + "openat.c", + "posix_fadvise.c", + "posix_fallocate.c", + ] +} diff --git a/third_party/ulib/musl/src/fcntl/creat.c b/third_party/ulib/musl/src/fcntl/creat.c new file mode 100644 index 000000000..886515841 --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/creat.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include + +int creat(const char* filename, mode_t mode) { + return open(filename, O_CREAT | O_WRONLY | O_TRUNC, mode); +} + +LFS64(creat); diff --git a/third_party/ulib/musl/src/fcntl/fcntl.c b/third_party/ulib/musl/src/fcntl/fcntl.c new file mode 100644 index 000000000..aa45001ed --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/fcntl.c @@ -0,0 +1,47 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +int fcntl(int fd, int cmd, ...) { + unsigned long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, unsigned long); + va_end(ap); + if (cmd == F_SETFL) arg |= O_LARGEFILE; + if (cmd == F_SETLKW) return syscall(SYS_fcntl, fd, cmd, (void*)arg); + if (cmd == F_GETOWN) { + struct f_owner_ex ex; + int ret = __syscall(SYS_fcntl, fd, F_GETOWN_EX, &ex); + if (ret == -EINVAL) return __syscall(SYS_fcntl, fd, cmd, (void*)arg); + if (ret) return __syscall_ret(ret); + return ex.type == F_OWNER_PGRP ? -ex.pid : ex.pid; + } + if (cmd == F_DUPFD_CLOEXEC) { + int ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, arg); + if (ret != -EINVAL) { + if (ret >= 0) __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC); + return __syscall_ret(ret); + } + ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, 0); + if (ret != -EINVAL) { + if (ret >= 0) __syscall(SYS_close, ret); + return __syscall_ret(-EINVAL); + } + ret = __syscall(SYS_fcntl, fd, F_DUPFD, arg); + if (ret >= 0) __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC); + return __syscall_ret(ret); + } + switch (cmd) { + case F_SETLK: + case F_GETLK: + case F_GETOWN_EX: + case F_SETOWN_EX: + return syscall(SYS_fcntl, fd, cmd, (void*)arg); + default: + return syscall(SYS_fcntl, fd, cmd, arg); + } +} diff --git a/third_party/ulib/musl/src/fcntl/open.c b/third_party/ulib/musl/src/fcntl/open.c new file mode 100644 index 000000000..4195c319f --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/open.c @@ -0,0 +1,28 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +static int io_open(const char* filename, int flags, int mode) { + return -1; +} +weak_alias(io_open, __libc_io_open); + +int open(const char* filename, int flags, ...) { + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + } + + int fd = __libc_io_open(filename, flags, mode); + // TODO(kulakowski) Implement O_CLOEXEC semantics + // if (fd >= 0 && (flags & O_CLOEXEC)) __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); + + return __syscall_ret(fd); +} + +LFS64(open); diff --git a/third_party/ulib/musl/src/fcntl/openat.c b/third_party/ulib/musl/src/fcntl/openat.c new file mode 100644 index 000000000..f2a5197b6 --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/openat.c @@ -0,0 +1,19 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int openat(int fd, const char* filename, int flags, ...) { + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + } + + return syscall(SYS_openat, fd, filename, flags | O_LARGEFILE, mode); +} + +LFS64(openat); diff --git a/third_party/ulib/musl/src/fcntl/posix_fadvise.c b/third_party/ulib/musl/src/fcntl/posix_fadvise.c new file mode 100644 index 000000000..d252572e2 --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/posix_fadvise.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +int posix_fadvise(int fd, off_t base, off_t len, int advice) { + return -(__syscall(SYS_fadvise, fd, base, len, advice)); +} + +LFS64(posix_fadvise); diff --git a/third_party/ulib/musl/src/fcntl/posix_fallocate.c b/third_party/ulib/musl/src/fcntl/posix_fallocate.c new file mode 100644 index 000000000..375f79732 --- /dev/null +++ b/third_party/ulib/musl/src/fcntl/posix_fallocate.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +int posix_fallocate(int fd, off_t base, off_t len) { + return -__syscall(SYS_fallocate, fd, 0, base, len); +} + +LFS64(posix_fallocate); diff --git a/third_party/ulib/musl/src/fenv/BUILD.gn b/third_party/ulib/musl/src/fenv/BUILD.gn new file mode 100644 index 000000000..a3de4e912 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/BUILD.gn @@ -0,0 +1,23 @@ +source_set("fenv") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__flt_rounds.c", + "fegetexceptflag.c", + "feholdexcept.c", + "fesetexceptflag.c", + "fesetround.c", + "feupdateenv.c", + ] + if (target_cpu == "arm") { + sources += [ "arm/fenv.c" ] + } else if (target_cpu == "arm64") { + sources += [ "aarch64/fenv.s" ] + } else if (target_cpu == "x64") { + sources += [ "x86_64/fenv.s" ] + } else { + sources += [ "fenv.c" ] + } +} diff --git a/third_party/ulib/musl/src/fenv/__flt_rounds.c b/third_party/ulib/musl/src/fenv/__flt_rounds.c new file mode 100644 index 000000000..a700c4f3f --- /dev/null +++ b/third_party/ulib/musl/src/fenv/__flt_rounds.c @@ -0,0 +1,22 @@ +#include +#include + +int __flt_rounds() { + switch (fegetround()) { +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + return 0; +#endif + case FE_TONEAREST: + return 1; +#ifdef FE_UPWARD + case FE_UPWARD: + return 2; +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + return 3; +#endif + } + return -1; +} diff --git a/third_party/ulib/musl/src/fenv/aarch64/fenv.s b/third_party/ulib/musl/src/fenv/aarch64/fenv.s new file mode 100644 index 000000000..f0db5d9d1 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/aarch64/fenv.s @@ -0,0 +1,67 @@ +.global fegetround +.type fegetround,%function +fegetround: + mrs x0, fpcr + and w0, w0, #0xc00000 + ret + +.global __fesetround +.type __fesetround,%function +__fesetround: + mrs x1, fpcr + bic w1, w1, #0xc00000 + orr w1, w1, w0 + msr fpcr, x1 + mov w0, #0 + ret + +.global fetestexcept +.type fetestexcept,%function +fetestexcept: + and w0, w0, #0x1f + mrs x1, fpsr + and w0, w0, w1 + ret + +.global feclearexcept +.type feclearexcept,%function +feclearexcept: + and w0, w0, #0x1f + mrs x1, fpsr + bic w1, w1, w0 + msr fpsr, x1 + mov w0, #0 + ret + +.global feraiseexcept +.type feraiseexcept,%function +feraiseexcept: + and w0, w0, #0x1f + mrs x1, fpsr + orr w1, w1, w0 + msr fpsr, x1 + mov w0, #0 + ret + +.global fegetenv +.type fegetenv,%function +fegetenv: + mrs x1, fpcr + mrs x2, fpsr + stp w1, w2, [x0] + mov w0, #0 + ret + +// TODO preserve some bits +.global fesetenv +.type fesetenv,%function +fesetenv: + mov x1, #0 + mov x2, #0 + cmn x0, #1 + b.eq 1f + ldp w1, w2, [x0] +1: msr fpcr, x1 + msr fpsr, x2 + mov w0, #0 + ret diff --git a/third_party/ulib/musl/src/fenv/arm/fenv-hf.S b/third_party/ulib/musl/src/fenv/arm/fenv-hf.S new file mode 100644 index 000000000..f55d798a6 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/arm/fenv-hf.S @@ -0,0 +1,69 @@ +#if __ARM_PCS_VFP + +.syntax unified +.fpu vfp + +.global fegetround +.type fegetround,%function +fegetround: + fmrx r0, fpscr + and r0, r0, #0xc00000 + bx lr + +.global __fesetround +.type __fesetround,%function +__fesetround: + fmrx r3, fpscr + bic r3, r3, #0xc00000 + orr r3, r3, r0 + fmxr fpscr, r3 + mov r0, #0 + bx lr + +.global fetestexcept +.type fetestexcept,%function +fetestexcept: + and r0, r0, #0x1f + fmrx r3, fpscr + and r0, r0, r3 + bx lr + +.global feclearexcept +.type feclearexcept,%function +feclearexcept: + and r0, r0, #0x1f + fmrx r3, fpscr + bic r3, r3, r0 + fmxr fpscr, r3 + mov r0, #0 + bx lr + +.global feraiseexcept +.type feraiseexcept,%function +feraiseexcept: + and r0, r0, #0x1f + fmrx r3, fpscr + orr r3, r3, r0 + fmxr fpscr, r3 + mov r0, #0 + bx lr + +.global fegetenv +.type fegetenv,%function +fegetenv: + fmrx r3, fpscr + str r3, [r0] + mov r0, #0 + bx lr + +.global fesetenv +.type fesetenv,%function +fesetenv: + cmn r0, #1 + moveq r3, #0 + ldrne r3, [r0] + fmxr fpscr, r3 + mov r0, #0 + bx lr + +#endif diff --git a/third_party/ulib/musl/src/fenv/arm/fenv.c b/third_party/ulib/musl/src/fenv/arm/fenv.c new file mode 100644 index 000000000..ad295f58c --- /dev/null +++ b/third_party/ulib/musl/src/fenv/arm/fenv.c @@ -0,0 +1,3 @@ +#if !__ARM_PCS_VFP +#include "../fenv.c" +#endif diff --git a/third_party/ulib/musl/src/fenv/fegetexceptflag.c b/third_party/ulib/musl/src/fenv/fegetexceptflag.c new file mode 100644 index 000000000..5f65063c0 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/fegetexceptflag.c @@ -0,0 +1,6 @@ +#include + +int fegetexceptflag(fexcept_t* fp, int mask) { + *fp = fetestexcept(mask); + return 0; +} diff --git a/third_party/ulib/musl/src/fenv/feholdexcept.c b/third_party/ulib/musl/src/fenv/feholdexcept.c new file mode 100644 index 000000000..0845c413e --- /dev/null +++ b/third_party/ulib/musl/src/fenv/feholdexcept.c @@ -0,0 +1,7 @@ +#include + +int feholdexcept(fenv_t* envp) { + fegetenv(envp); + feclearexcept(FE_ALL_EXCEPT); + return 0; +} diff --git a/third_party/ulib/musl/src/fenv/fenv.c b/third_party/ulib/musl/src/fenv/fenv.c new file mode 100644 index 000000000..71f144e0b --- /dev/null +++ b/third_party/ulib/musl/src/fenv/fenv.c @@ -0,0 +1,31 @@ +#include + +/* Dummy functions for archs lacking fenv implementation */ + +int feclearexcept(int mask) { + return 0; +} + +int feraiseexcept(int mask) { + return 0; +} + +int fetestexcept(int mask) { + return 0; +} + +int fegetround(void) { + return FE_TONEAREST; +} + +int __fesetround(int r) { + return 0; +} + +int fegetenv(fenv_t* envp) { + return 0; +} + +int fesetenv(const fenv_t* envp) { + return 0; +} diff --git a/third_party/ulib/musl/src/fenv/fesetexceptflag.c b/third_party/ulib/musl/src/fenv/fesetexceptflag.c new file mode 100644 index 000000000..fb9be06f2 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/fesetexceptflag.c @@ -0,0 +1,7 @@ +#include + +int fesetexceptflag(const fexcept_t* fp, int mask) { + feclearexcept(~*fp & mask); + feraiseexcept(*fp & mask); + return 0; +} diff --git a/third_party/ulib/musl/src/fenv/fesetround.c b/third_party/ulib/musl/src/fenv/fesetround.c new file mode 100644 index 000000000..2ba258475 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/fesetround.c @@ -0,0 +1,22 @@ +#include + +/* __fesetround wrapper for arch independent argument check */ + +int __fesetround(int); + +int fesetround(int r) { + if (r & + ~(FE_TONEAREST +#ifdef FE_DOWNWARD + | FE_DOWNWARD +#endif +#ifdef FE_UPWARD + | FE_UPWARD +#endif +#ifdef FE_TOWARDZERO + | FE_TOWARDZERO +#endif + )) + return -1; + return __fesetround(r); +} diff --git a/third_party/ulib/musl/src/fenv/feupdateenv.c b/third_party/ulib/musl/src/fenv/feupdateenv.c new file mode 100644 index 000000000..344bfa734 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/feupdateenv.c @@ -0,0 +1,8 @@ +#include + +int feupdateenv(const fenv_t* envp) { + int ex = fetestexcept(FE_ALL_EXCEPT); + fesetenv(envp); + feraiseexcept(ex); + return 0; +} diff --git a/third_party/ulib/musl/src/fenv/x32/fenv.s b/third_party/ulib/musl/src/fenv/x32/fenv.s new file mode 100644 index 000000000..45310465c --- /dev/null +++ b/third_party/ulib/musl/src/fenv/x32/fenv.s @@ -0,0 +1,97 @@ +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + # maintain exceptions in the sse mxcsr, clear x87 exceptions + mov %edi,%ecx + and $0x3f,%ecx + fnstsw %ax + test %eax,%ecx + jz 1f + fnclex +1: stmxcsr -8(%esp) + and $0x3f,%eax + or %eax,-8(%esp) + test %ecx,-8(%esp) + jz 1f + not %ecx + and %ecx,-8(%esp) + ldmxcsr -8(%esp) +1: xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + and $0x3f,%edi + stmxcsr -8(%esp) + or %edi,-8(%esp) + ldmxcsr -8(%esp) + xor %eax,%eax + ret + +.global __fesetround +.type __fesetround,@function +__fesetround: + push %rax + xor %eax,%eax + mov %edi,%ecx + fnstcw (%esp) + andb $0xf3,1(%esp) + or %ch,1(%esp) + fldcw (%esp) + stmxcsr (%esp) + shl $3,%ch + andb $0x9f,1(%esp) + or %ch,1(%esp) + ldmxcsr (%esp) + pop %rcx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %rax + stmxcsr (%esp) + pop %rax + shr $3,%eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + xor %eax,%eax + fnstenv (%edi) + stmxcsr 28(%edi) + ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + xor %eax,%eax + inc %edi + jz 1f + fldenv -1(%edi) + ldmxcsr 27(%edi) + ret +1: push %rax + push %rax + pushq $0xffff + pushq $0x37f + fldenv (%esp) + pushq $0x1f80 + ldmxcsr (%esp) + add $40,%esp + ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + and $0x3f,%edi + push %rax + stmxcsr (%esp) + pop %rsi + fnstsw %ax + or %esi,%eax + and %edi,%eax + ret diff --git a/third_party/ulib/musl/src/fenv/x86_64/fenv.s b/third_party/ulib/musl/src/fenv/x86_64/fenv.s new file mode 100644 index 000000000..b5aeaf4f4 --- /dev/null +++ b/third_party/ulib/musl/src/fenv/x86_64/fenv.s @@ -0,0 +1,97 @@ +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + # maintain exceptions in the sse mxcsr, clear x87 exceptions + mov %edi,%ecx + and $0x3f,%ecx + fnstsw %ax + test %eax,%ecx + jz 1f + fnclex +1: stmxcsr -8(%rsp) + and $0x3f,%eax + or %eax,-8(%rsp) + test %ecx,-8(%rsp) + jz 1f + not %ecx + and %ecx,-8(%rsp) + ldmxcsr -8(%rsp) +1: xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + and $0x3f,%edi + stmxcsr -8(%rsp) + or %edi,-8(%rsp) + ldmxcsr -8(%rsp) + xor %eax,%eax + ret + +.global __fesetround +.type __fesetround,@function +__fesetround: + push %rax + xor %eax,%eax + mov %edi,%ecx + fnstcw (%rsp) + andb $0xf3,1(%rsp) + or %ch,1(%rsp) + fldcw (%rsp) + stmxcsr (%rsp) + shl $3,%ch + andb $0x9f,1(%rsp) + or %ch,1(%rsp) + ldmxcsr (%rsp) + pop %rcx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %rax + stmxcsr (%rsp) + pop %rax + shr $3,%eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + xor %eax,%eax + fnstenv (%rdi) + stmxcsr 28(%rdi) + ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + xor %eax,%eax + inc %rdi + jz 1f + fldenv -1(%rdi) + ldmxcsr 27(%rdi) + ret +1: push %rax + push %rax + pushq $0xffff + pushq $0x37f + fldenv (%rsp) + pushq $0x1f80 + ldmxcsr (%rsp) + add $40,%rsp + ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + and $0x3f,%edi + push %rax + stmxcsr (%rsp) + pop %rsi + fnstsw %ax + or %esi,%eax + and %edi,%eax + ret diff --git a/third_party/ulib/musl/src/internal/BUILD.gn b/third_party/ulib/musl/src/internal/BUILD.gn new file mode 100644 index 000000000..e2fa41df5 --- /dev/null +++ b/third_party/ulib/musl/src/internal/BUILD.gn @@ -0,0 +1,18 @@ +source_set("internal") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "floatscan.c", + "intscan.c", + "libc.c", + "procfdname.c", + "shgetc.c", + "syscall_ret.c", + "vdso.c", + + # We do not currently generate the version number. + # "version.c", + ] +} diff --git a/third_party/ulib/musl/src/internal/__invtrigl.h b/third_party/ulib/musl/src/internal/__invtrigl.h new file mode 100644 index 000000000..91a8a3b61 --- /dev/null +++ b/third_party/ulib/musl/src/internal/__invtrigl.h @@ -0,0 +1,6 @@ +/* shared by acosl, asinl and atan2l */ +#define pio2_hi __pio2_hi +#define pio2_lo __pio2_lo +extern const long double pio2_hi, pio2_lo; + +long double __invtrigl_R(long double z); diff --git a/third_party/ulib/musl/src/internal/atomic.h b/third_party/ulib/musl/src/internal/atomic.h new file mode 100644 index 000000000..c13c163dd --- /dev/null +++ b/third_party/ulib/musl/src/internal/atomic.h @@ -0,0 +1,284 @@ +#ifndef _ATOMIC_H +#define _ATOMIC_H + +#include + +#include "atomic_arch.h" + +#ifdef a_ll + +#ifndef a_pre_llsc +#define a_pre_llsc() +#endif + +#ifndef a_post_llsc +#define a_post_llsc() +#endif + +#ifndef a_cas +#define a_cas a_cas +static inline int a_cas(volatile int* p, int t, int s) { + int old; + a_pre_llsc(); + do + old = a_ll(p); + while (old == t && !a_sc(p, s)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int* p, int v) { + int old; + a_pre_llsc(); + do + old = a_ll(p); + while (!a_sc(p, v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int* p, int v) { + int old; + a_pre_llsc(); + do + old = a_ll(p); + while (!a_sc(p, (unsigned)old + v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int* p, int v) { + int old; + a_pre_llsc(); + do + old = a_ll(p); + while (!a_sc(p, old & v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int* p, int v) { + int old; + a_pre_llsc(); + do + old = a_ll(p); + while (!a_sc(p, old | v)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifdef a_ll_p + +#ifndef a_cas_p +#define a_cas_p a_cas_p +static inline void* a_cas_p(volatile void* p, void* t, void* s) { + void* old; + a_pre_llsc(); + do + old = a_ll_p(p); + while (old == t && !a_sc_p(p, s)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifndef a_cas +#error missing definition of a_cas +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int* p, int v) { + int old; + do + old = *p; + while (a_cas(p, old, v) != old); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int* p, int v) { + int old; + do + old = *p; + while (a_cas(p, old, (unsigned)old + v) != old); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int* p, int v) { + int old; + do + old = *p; + while (a_cas(p, old, old & v) != old); + return old; +} +#endif +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int* p, int v) { + int old; + do + old = *p; + while (a_cas(p, old, old | v) != old); + return old; +} +#endif + +#ifndef a_and +#define a_and a_and +static inline void a_and(volatile int* p, int v) { + a_fetch_and(p, v); +} +#endif + +#ifndef a_or +#define a_or a_or +static inline void a_or(volatile int* p, int v) { + a_fetch_or(p, v); +} +#endif + +#ifndef a_inc +#define a_inc a_inc +static inline void a_inc(volatile int* p) { + a_fetch_add(p, 1); +} +#endif + +#ifndef a_dec +#define a_dec a_dec +static inline void a_dec(volatile int* p) { + a_fetch_add(p, -1); +} +#endif + +#ifndef a_store +#define a_store a_store +static inline void a_store(volatile int* p, int v) { +#ifdef a_barrier + a_barrier(); + *p = v; + a_barrier(); +#else + a_swap(p, v); +#endif +} +#endif + +#ifndef a_barrier +#define a_barrier a_barrier +static void a_barrier(void) { + volatile int tmp = 0; + a_cas(&tmp, 0, 0); +} +#endif + +#ifndef a_spin +#define a_spin a_barrier +#endif + +#ifndef a_and_64 +#define a_and_64 a_and_64 +static inline void a_and_64(volatile uint64_t* p, uint64_t v) { + union { + uint64_t v; + uint32_t r[2]; + } u = {v}; + if (u.r[0] + 1) a_and((int*)p, u.r[0]); + if (u.r[1] + 1) a_and((int*)p + 1, u.r[1]); +} +#endif + +#ifndef a_or_64 +#define a_or_64 a_or_64 +static inline void a_or_64(volatile uint64_t* p, uint64_t v) { + union { + uint64_t v; + uint32_t r[2]; + } u = {v}; + if (u.r[0]) a_or((int*)p, u.r[0]); + if (u.r[1]) a_or((int*)p + 1, u.r[1]); +} +#endif + +#ifndef a_cas_p +typedef char a_cas_p_undefined_but_pointer_not_32bit[-sizeof(char) == 0xffffffff ? 1 : -1]; +#define a_cas_p a_cas_p +static inline void* a_cas_p(volatile void* p, void* t, void* s) { + return (void*)a_cas((volatile int*)p, (int)t, (int)s); +} +#endif + +#ifndef a_or_l +#define a_or_l a_or_l +static inline void a_or_l(volatile void* p, long v) { + if (sizeof(long) == sizeof(int)) + a_or(p, v); + else + a_or_64(p, v); +} +#endif + +#ifndef a_crash +#define a_crash a_crash +static inline void a_crash(void) { + *(volatile char*)0 = 0; +} +#endif + +#ifndef a_ctz_64 +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) { + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 62, 5, 39, 46, 44, 42, + 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, + 23, 58, 17, 10, 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12}; + static const char debruijn32[32] = {0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, + 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, + 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x >> 32; + return 32 + debruijn32[(y & -y) * 0x076be629 >> 27]; + } + return debruijn32[(y & -y) * 0x076be629 >> 27]; + } + return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; +} +#endif + +#ifndef a_ctz_l +#define a_ctz_l a_ctz_l +static inline int a_ctz_l(unsigned long x) { + static const char debruijn32[32] = {0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, + 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, + 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; + if (sizeof(long) == 8) return a_ctz_64(x); + return debruijn32[(x & -x) * 0x076be629 >> 27]; +} +#endif + +#endif diff --git a/third_party/ulib/musl/src/internal/dynlink.h b/third_party/ulib/musl/src/internal/dynlink.h new file mode 100644 index 000000000..9b111f4ec --- /dev/null +++ b/third_party/ulib/musl/src/internal/dynlink.h @@ -0,0 +1,99 @@ +#ifndef _INTERNAL_RELOC_H +#define _INTERNAL_RELOC_H + +#include +#include +#include +#include + +#if UINTPTR_MAX == 0xffffffff +typedef Elf32_Ehdr Ehdr; +typedef Elf32_Phdr Phdr; +typedef Elf32_Sym Sym; +#define R_TYPE(x) ((x)&255) +#define R_SYM(x) ((x) >> 8) +#define R_INFO ELF32_R_INFO +#else +typedef Elf64_Ehdr Ehdr; +typedef Elf64_Phdr Phdr; +typedef Elf64_Sym Sym; +#define R_TYPE(x) ((x)&0x7fffffff) +#define R_SYM(x) ((x) >> 32) +#define R_INFO ELF64_R_INFO +#endif + +/* These enum constants provide unmatchable default values for + * any relocation type the arch does not use. */ +enum { + REL_NONE = 0, + REL_SYMBOLIC = -100, + REL_GOT, + REL_PLT, + REL_RELATIVE, + REL_OFFSET, + REL_OFFSET32, + REL_COPY, + REL_SYM_OR_REL, + REL_DTPMOD, + REL_DTPOFF, + REL_TPOFF, + REL_TPOFF_NEG, + REL_TLSDESC, + REL_FUNCDESC, + REL_FUNCDESC_VAL, +}; + +struct fdpic_loadseg { + uintptr_t addr, p_vaddr, p_memsz; +}; + +struct fdpic_loadmap { + unsigned short version, nsegs; + struct fdpic_loadseg segs[]; +}; + +struct fdpic_dummy_loadmap { + unsigned short version, nsegs; + struct fdpic_loadseg segs[1]; +}; + +#include "reloc.h" + +#ifndef FDPIC_CONSTDISP_FLAG +#define FDPIC_CONSTDISP_FLAG 0 +#endif + +#ifndef DL_FDPIC +#define DL_FDPIC 0 +#endif + +#ifndef DL_NOMMU_SUPPORT +#define DL_NOMMU_SUPPORT 0 +#endif + +#if !DL_FDPIC +#define IS_RELATIVE(x, s) \ + ((R_TYPE(x) == REL_RELATIVE) || (R_TYPE(x) == REL_SYM_OR_REL && !R_SYM(x))) +#else +#define IS_RELATIVE(x, s) \ + (((R_TYPE(x) == REL_FUNCDESC_VAL) || (R_TYPE(x) == REL_SYMBOLIC)) && \ + (((s)[R_SYM(x)].st_info & 0xf) == STT_SECTION)) +#endif + +#ifndef NEED_MIPS_GOT_RELOCS +#define NEED_MIPS_GOT_RELOCS 0 +#endif + +#ifndef DT_DEBUG_INDIRECT +#define DT_DEBUG_INDIRECT 0 +#endif + +#define AUX_CNT 32 +#define DYN_CNT 32 + +typedef void (*stage2_func)(unsigned char*, size_t*); +// stage3_funcs should be __attribute__((noreturn)), but this cannot +// be expressed in the typedef. +typedef void (*stage3_func)(size_t*); + +#endif diff --git a/third_party/ulib/musl/src/internal/fdpic_crt.h b/third_party/ulib/musl/src/internal/fdpic_crt.h new file mode 100644 index 000000000..fb748d02b --- /dev/null +++ b/third_party/ulib/musl/src/internal/fdpic_crt.h @@ -0,0 +1,26 @@ +#include + +__attribute__((__visibility__("hidden"))) void* __fdpic_fixup(void* map, uintptr_t* a, + uintptr_t* z) { + /* If map is a null pointer, the program was loaded by a + * non-FDPIC-aware ELF loader, and fixups are not needed, + * but the value for the GOT pointer is. */ + if (!map) return (void*)z[-1]; + + struct { + unsigned short version, nsegs; + struct fdpic_loadseg { + uintptr_t addr, p_vaddr, p_memsz; + } segs[]; + }* lm = map; + int nsegs = lm->nsegs, rseg = 0, vseg = 0; + for (;;) { + while (*a - lm->segs[rseg].p_vaddr >= lm->segs[rseg].p_memsz) + if (++rseg == nsegs) rseg = 0; + uintptr_t* r = (uintptr_t*)(*a + lm->segs[rseg].addr - lm->segs[rseg].p_vaddr); + if (++a == z) return r; + while (*r - lm->segs[vseg].p_vaddr >= lm->segs[vseg].p_memsz) + if (++vseg == nsegs) vseg = 0; + *r += lm->segs[vseg].addr - lm->segs[vseg].p_vaddr; + } +} diff --git a/third_party/ulib/musl/src/internal/floatscan.c b/third_party/ulib/musl/src/internal/floatscan.c new file mode 100644 index 000000000..1f1e3f201 --- /dev/null +++ b/third_party/ulib/musl/src/internal/floatscan.c @@ -0,0 +1,507 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "floatscan.h" +#include "shgetc.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 + +#define LD_B1B_DIG 2 +#define LD_B1B_MAX 9007199, 254740991 +#define KMAX 128 + +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +#define LD_B1B_DIG 3 +#define LD_B1B_MAX 18, 446744073, 709551615 +#define KMAX 2048 + +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 + +#define LD_B1B_DIG 4 +#define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191 +#define KMAX 2048 + +#else +#error Unsupported long double representation +#endif + +#define MASK (KMAX - 1) + +#define CONCAT2(x, y) x##y +#define CONCAT(x, y) CONCAT2(x, y) + +static long long scanexp(FILE* f, int pok) { + int c; + int x; + long long y; + int neg = 0; + + c = shgetc(f); + if (c == '+' || c == '-') { + neg = (c == '-'); + c = shgetc(f); + if (c - '0' >= 10U && pok) shunget(f); + } + if (c - '0' >= 10U) { + shunget(f); + return LLONG_MIN; + } + for (x = 0; c - '0' < 10U && x < INT_MAX / 10; c = shgetc(f)) + x = 10 * x + c - '0'; + for (y = x; c - '0' < 10U && y < LLONG_MAX / 100; c = shgetc(f)) + y = 10 * y + c - '0'; + for (; c - '0' < 10U; c = shgetc(f)) + ; + shunget(f); + return neg ? -y : y; +} + +static long double decfloat(FILE* f, int c, int bits, int emin, int sign, int pok) { + uint32_t x[KMAX]; + static const uint32_t th[] = {LD_B1B_MAX}; + int i, j, k, a, z; + long long lrp = 0, dc = 0; + long long e10 = 0; + int lnz = 0; + int gotdig = 0, gotrad = 0; + int rp; + int e2; + int emax = -emin - bits + 3; + int denormal = 0; + long double y; + long double frac = 0; + long double bias = 0; + static const int p10s[] = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; + + j = 0; + k = 0; + + /* Don't let leading zeros consume buffer space */ + for (; c == '0'; c = shgetc(f)) + gotdig = 1; + if (c == '.') { + gotrad = 1; + for (c = shgetc(f); c == '0'; c = shgetc(f)) + gotdig = 1, lrp--; + } + + x[0] = 0; + for (; c - '0' < 10U || c == '.'; c = shgetc(f)) { + if (c == '.') { + if (gotrad) break; + gotrad = 1; + lrp = dc; + } else if (k < KMAX - 3) { + dc++; + if (c != '0') lnz = dc; + if (j) + x[k] = x[k] * 10 + c - '0'; + else + x[k] = c - '0'; + if (++j == 9) { + k++; + j = 0; + } + gotdig = 1; + } else { + dc++; + if (c != '0') x[KMAX - 4] |= 1; + } + } + if (!gotrad) lrp = dc; + + if (gotdig && (c | 32) == 'e') { + e10 = scanexp(f, pok); + if (e10 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e10 = 0; + } + lrp += e10; + } else if (c >= 0) { + shunget(f); + } + if (!gotdig) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp == dc && dc < 10 && (bits > 30 || x[0] >> bits == 0)) return sign * (long double)x[0]; + if (lrp > -emin / 2) { + errno = ERANGE; + return sign * LDBL_MAX * LDBL_MAX; + } + if (lrp < emin - 2 * LDBL_MANT_DIG) { + errno = ERANGE; + return sign * LDBL_MIN * LDBL_MIN; + } + + /* Align incomplete final B1B digit */ + if (j) { + for (; j < 9; j++) + x[k] *= 10; + k++; + j = 0; + } + + a = 0; + z = k; + e2 = 0; + rp = lrp; + + /* Optimize small to mid-size integers (even in exp. notation) */ + if (lnz < 9 && lnz <= rp && rp < 18) { + if (rp == 9) return sign * (long double)x[0]; + if (rp < 9) return sign * (long double)x[0] / p10s[8 - rp]; + int bitlim = bits - 3 * (int)(rp - 9); + if (bitlim > 30 || x[0] >> bitlim == 0) return sign * (long double)x[0] * p10s[rp - 10]; + } + + /* Align radix point to B1B digit boundary */ + if (rp % 9) { + int rpm9 = rp >= 0 ? rp % 9 : rp % 9 + 9; + int p10 = p10s[8 - rpm9]; + uint32_t carry = 0; + for (k = a; k != z; k++) { + uint32_t tmp = x[k] % p10; + x[k] = x[k] / p10 + carry; + carry = 1000000000 / p10 * tmp; + if (k == a && !x[k]) { + a = (a + 1 & MASK); + rp -= 9; + } + } + if (carry) x[z++] = carry; + rp += 9 - rpm9; + } + + /* Upscale until desired number of bits are left of radix point */ + while (rp < 9 * LD_B1B_DIG || (rp == 9 * LD_B1B_DIG && x[a] < th[0])) { + uint32_t carry = 0; + e2 -= 29; + for (k = (z - 1 & MASK);; k = (k - 1 & MASK)) { + uint64_t tmp = ((uint64_t)x[k] << 29) + carry; + if (tmp > 1000000000) { + carry = tmp / 1000000000; + x[k] = tmp % 1000000000; + } else { + carry = 0; + x[k] = tmp; + } + if (k == (z - 1 & MASK) && k != a && !x[k]) z = k; + if (k == a) break; + } + if (carry) { + rp += 9; + a = (a - 1 & MASK); + if (a == z) { + z = (z - 1 & MASK); + x[z - 1 & MASK] |= x[z]; + } + x[a] = carry; + } + } + + /* Downscale until exactly number of bits are left of radix point */ + for (;;) { + uint32_t carry = 0; + int sh = 1; + for (i = 0; i < LD_B1B_DIG; i++) { + k = (a + i & MASK); + if (k == z || x[k] < th[i]) { + i = LD_B1B_DIG; + break; + } + if (x[a + i & MASK] > th[i]) break; + } + if (i == LD_B1B_DIG && rp == 9 * LD_B1B_DIG) break; + /* FIXME: find a way to compute optimal sh */ + if (rp > 9 + 9 * LD_B1B_DIG) sh = 9; + e2 += sh; + for (k = a; k != z; k = (k + 1 & MASK)) { + uint32_t tmp = x[k] & (1 << sh) - 1; + x[k] = (x[k] >> sh) + carry; + carry = (1000000000 >> sh) * tmp; + if (k == a && !x[k]) { + a = (a + 1 & MASK); + i--; + rp -= 9; + } + } + if (carry) { + if ((z + 1 & MASK) != a) { + x[z] = carry; + z = (z + 1 & MASK); + } else + x[z - 1 & MASK] |= 1; + } + } + + /* Assemble desired bits into floating point variable */ + for (y = i = 0; i < LD_B1B_DIG; i++) { + if ((a + i & MASK) == z) x[(z = (z + 1 & MASK)) - 1] = 0; + y = 1000000000.0L * y + x[a + i & MASK]; + } + + y *= sign; + + /* Limit precision for denormal results */ + if (bits > LDBL_MANT_DIG + e2 - emin) { + bits = LDBL_MANT_DIG + e2 - emin; + if (bits < 0) bits = 0; + denormal = 1; + } + + /* Calculate bias term to force rounding, move out lower bits */ + if (bits < LDBL_MANT_DIG) { + bias = copysignl(scalbn(1, 2 * LDBL_MANT_DIG - bits - 1), y); + frac = fmodl(y, scalbn(1, LDBL_MANT_DIG - bits)); + y -= frac; + y += bias; + } + + /* Process tail of decimal input so it can affect rounding */ + if ((a + i & MASK) != z) { + uint32_t t = x[a + i & MASK]; + if (t < 500000000 && (t || (a + i + 1 & MASK) != z)) + frac += 0.25 * sign; + else if (t > 500000000) + frac += 0.75 * sign; + else if (t == 500000000) { + if ((a + i + 1 & MASK) == z) + frac += 0.5 * sign; + else + frac += 0.75 * sign; + } + if (LDBL_MANT_DIG - bits >= 2 && !fmodl(frac, 1)) frac++; + } + + y += frac; + y -= bias; + + if ((e2 + LDBL_MANT_DIG & INT_MAX) > emax - 5) { + if (fabs(y) >= CONCAT(0x1p, LDBL_MANT_DIG)) { + if (denormal && bits == LDBL_MANT_DIG + e2 - emin) denormal = 0; + y *= 0.5; + e2++; + } + if (e2 + LDBL_MANT_DIG > emax || (denormal && frac)) errno = ERANGE; + } + + return scalbnl(y, e2); +} + +static long double hexfloat(FILE* f, int bits, int emin, int sign, int pok) { + uint32_t x = 0; + long double y = 0; + long double scale = 1; + long double bias = 0; + int gottail = 0, gotrad = 0, gotdig = 0; + long long rp = 0; + long long dc = 0; + long long e2 = 0; + int d; + int c; + + c = shgetc(f); + + /* Skip leading zeros */ + for (; c == '0'; c = shgetc(f)) + gotdig = 1; + + if (c == '.') { + gotrad = 1; + c = shgetc(f); + /* Count zeros after the radix point before significand */ + for (rp = 0; c == '0'; c = shgetc(f), rp--) + gotdig = 1; + } + + for (; c - '0' < 10U || (c | 32) - 'a' < 6U || c == '.'; c = shgetc(f)) { + if (c == '.') { + if (gotrad) break; + rp = dc; + gotrad = 1; + } else { + gotdig = 1; + if (c > '9') + d = (c | 32) + 10 - 'a'; + else + d = c - '0'; + if (dc < 8) { + x = x * 16 + d; + } else if (dc < LDBL_MANT_DIG / 4 + 1) { + y += d * (scale /= 16); + } else if (d && !gottail) { + y += 0.5 * scale; + gottail = 1; + } + dc++; + } + } + if (!gotdig) { + shunget(f); + if (pok) { + shunget(f); + if (gotrad) shunget(f); + } else { + shlim(f, 0); + } + return sign * 0.0; + } + if (!gotrad) rp = dc; + while (dc < 8) + x *= 16, dc++; + if ((c | 32) == 'p') { + e2 = scanexp(f, pok); + if (e2 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e2 = 0; + } + } else { + shunget(f); + } + e2 += 4 * rp - 32; + + if (!x) return sign * 0.0; + if (e2 > -emin) { + errno = ERANGE; + return sign * LDBL_MAX * LDBL_MAX; + } + if (e2 < emin - 2 * LDBL_MANT_DIG) { + errno = ERANGE; + return sign * LDBL_MIN * LDBL_MIN; + } + + while (x < 0x80000000) { + if (y >= 0.5) { + x += x + 1; + y += y - 1; + } else { + x += x; + y += y; + } + e2--; + } + + if (bits > 32 + e2 - emin) { + bits = 32 + e2 - emin; + if (bits < 0) bits = 0; + } + + if (bits < LDBL_MANT_DIG) bias = copysignl(scalbn(1, 32 + LDBL_MANT_DIG - bits - 1), sign); + + if (bits < 32 && y && !(x & 1)) x++, y = 0; + + y = bias + sign * (long double)x + sign * y; + y -= bias; + + if (!y) errno = ERANGE; + + return scalbnl(y, e2); +} + +long double __floatscan(FILE* f, int prec, int pok) { + int sign = 1; + size_t i; + int bits; + int emin; + int c; + + switch (prec) { + case 0: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP - bits; + break; + case 1: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP - bits; + break; + case 2: + bits = LDBL_MANT_DIG; + emin = LDBL_MIN_EXP - bits; + break; + default: + return 0; + } + + while (isspace((c = shgetc(f)))) + ; + + if (c == '+' || c == '-') { + sign -= 2 * (c == '-'); + c = shgetc(f); + } + + for (i = 0; i < 8 && (c | 32) == "infinity"[i]; i++) + if (i < 7) c = shgetc(f); + if (i == 3 || i == 8 || (i > 3 && pok)) { + if (i != 8) { + shunget(f); + if (pok) + for (; i > 3; i--) + shunget(f); + } + return sign * INFINITY; + } + if (!i) + for (i = 0; i < 3 && (c | 32) == "nan"[i]; i++) + if (i < 2) c = shgetc(f); + if (i == 3) { + if (shgetc(f) != '(') { + shunget(f); + return NAN; + } + for (i = 1;; i++) { + c = shgetc(f); + if (c - '0' < 10U || c - 'A' < 26U || c - 'a' < 26U || c == '_') continue; + if (c == ')') return NAN; + shunget(f); + if (!pok) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + while (i--) + shunget(f); + return NAN; + } + return NAN; + } + + if (i) { + shunget(f); + errno = EINVAL; + shlim(f, 0); + return 0; + } + + if (c == '0') { + c = shgetc(f); + if ((c | 32) == 'x') return hexfloat(f, bits, emin, sign, pok); + shunget(f); + c = '0'; + } + + return decfloat(f, c, bits, emin, sign, pok); +} diff --git a/third_party/ulib/musl/src/internal/floatscan.h b/third_party/ulib/musl/src/internal/floatscan.h new file mode 100644 index 000000000..55c65905d --- /dev/null +++ b/third_party/ulib/musl/src/internal/floatscan.h @@ -0,0 +1,8 @@ +#ifndef FLOATSCAN_H +#define FLOATSCAN_H + +#include + +long double __floatscan(FILE*, int, int); + +#endif diff --git a/third_party/ulib/musl/src/internal/intscan.c b/third_party/ulib/musl/src/internal/intscan.c new file mode 100644 index 000000000..f1f847fc0 --- /dev/null +++ b/third_party/ulib/musl/src/internal/intscan.c @@ -0,0 +1,100 @@ +#include "shgetc.h" +#include +#include +#include + +/* Lookup table for digit values. -1==255>=36 -> invalid */ +static const unsigned char table[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, + -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +unsigned long long __intscan(FILE* f, unsigned base, int pok, unsigned long long lim) { + const unsigned char* val = table + 1; + int c, neg = 0; + unsigned x; + unsigned long long y; + if (base > 36) { + errno = EINVAL; + return 0; + } + while (isspace((c = shgetc(f)))) + ; + if (c == '+' || c == '-') { + neg = -(c == '-'); + c = shgetc(f); + } + if ((base == 0 || base == 16) && c == '0') { + c = shgetc(f); + if ((c | 32) == 'x') { + c = shgetc(f); + if (val[c] >= 16) { + shunget(f); + if (pok) + shunget(f); + else + shlim(f, 0); + return 0; + } + base = 16; + } else if (base == 0) { + base = 8; + } + } else { + if (base == 0) base = 10; + if (val[c] >= base) { + shunget(f); + shlim(f, 0); + errno = EINVAL; + return 0; + } + } + if (base == 10) { + for (x = 0; c - '0' < 10U && x <= UINT_MAX / 10 - 1; c = shgetc(f)) + x = x * 10 + (c - '0'); + for (y = x; c - '0' < 10U && y <= ULLONG_MAX / 10 && 10 * y <= ULLONG_MAX - (c - '0'); + c = shgetc(f)) + y = y * 10 + (c - '0'); + if (c - '0' >= 10U) goto done; + } else if (!(base & base - 1)) { + int bs = "\0\1\2\4\7\3\6\5"[(0x17 * base) >> 5 & 7]; + for (x = 0; val[c] < base && x <= UINT_MAX / 32; c = shgetc(f)) + x = x << bs | val[c]; + for (y = x; val[c] < base && y <= ULLONG_MAX >> bs; c = shgetc(f)) + y = y << bs | val[c]; + } else { + for (x = 0; val[c] < base && x <= UINT_MAX / 36 - 1; c = shgetc(f)) + x = x * base + val[c]; + for (y = x; val[c] < base && y <= ULLONG_MAX / base && base * y <= ULLONG_MAX - val[c]; + c = shgetc(f)) + y = y * base + val[c]; + } + if (val[c] < base) { + for (; val[c] < base; c = shgetc(f)) + ; + errno = ERANGE; + y = lim; + if (lim & 1) neg = 0; + } +done: + shunget(f); + if (y >= lim) { + if (!(lim & 1) && !neg) { + errno = ERANGE; + return lim - 1; + } else if (y > lim) { + errno = ERANGE; + return lim; + } + } + return (y ^ neg) - neg; +} diff --git a/third_party/ulib/musl/src/internal/intscan.h b/third_party/ulib/musl/src/internal/intscan.h new file mode 100644 index 000000000..3326a1b46 --- /dev/null +++ b/third_party/ulib/musl/src/internal/intscan.h @@ -0,0 +1,8 @@ +#ifndef INTSCAN_H +#define INTSCAN_H + +#include + +unsigned long long __intscan(FILE*, unsigned, int, unsigned long long); + +#endif diff --git a/third_party/ulib/musl/src/internal/ksigaction.h b/third_party/ulib/musl/src/internal/ksigaction.h new file mode 100644 index 000000000..4d4ebb0eb --- /dev/null +++ b/third_party/ulib/musl/src/internal/ksigaction.h @@ -0,0 +1,11 @@ +/* This is the structure used for the rt_sigaction syscall on most archs, + * but it can be overridden by a file with the same name in the top-level + * arch dir for a given arch, if necessary. */ +struct k_sigaction { + void (*handler)(int); + unsigned long flags; + void (*restorer)(void); + unsigned mask[2]; +}; + +void __restore(void), __restore_rt(void); diff --git a/third_party/ulib/musl/src/internal/libc.c b/third_party/ulib/musl/src/internal/libc.c new file mode 100644 index 000000000..befd2701a --- /dev/null +++ b/third_party/ulib/musl/src/internal/libc.c @@ -0,0 +1,10 @@ +#include "libc.h" + +struct __libc __libc; + +size_t __hwcap; +size_t __sysinfo; +char *__progname = 0, *__progname_full = 0; + +weak_alias(__progname, program_invocation_short_name); +weak_alias(__progname_full, program_invocation_name); diff --git a/third_party/ulib/musl/src/internal/libc.h b/third_party/ulib/musl/src/internal/libc.h new file mode 100644 index 000000000..6e836ebc6 --- /dev/null +++ b/third_party/ulib/musl/src/internal/libc.h @@ -0,0 +1,62 @@ +#ifndef LIBC_H +#define LIBC_H + +#include +#include +#include +#include + +struct __locale_map; + +struct __locale_struct { + const struct __locale_map* volatile cat[6]; +}; + +struct tls_module { + struct tls_module* next; + void* image; + size_t len, size, align, offset; +}; + +struct __libc { + int threaded; + int secure; + size_t* auxv; + struct tls_module* tls_head; + size_t tls_size, tls_align, tls_cnt; + size_t page_size; + struct __locale_struct global_locale; +}; + +#ifdef __PIC__ +#define ATTR_LIBC_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define ATTR_LIBC_VISIBILITY +#endif + +extern struct __libc __libc ATTR_LIBC_VISIBILITY; +#define libc __libc + +extern size_t __hwcap ATTR_LIBC_VISIBILITY; +extern size_t __sysinfo ATTR_LIBC_VISIBILITY; +extern char *__progname, *__progname_full; + +int __lockfile(FILE*) ATTR_LIBC_VISIBILITY; +void __unlockfile(FILE*) ATTR_LIBC_VISIBILITY; + +int __setxid(int, int, int, int); + +extern char** __environ; + +ssize_t __magenta_io_write(int fd, const void* buf, size_t count); + +#undef weak_alias +#define weak_alias(old, new) extern __typeof(old) new __attribute__((weak, alias(#old))) + +#undef LFS64_2 +#define LFS64_2(x, y) weak_alias(x, y) + +#undef LFS64 +#define LFS64(x) LFS64_2(x, x##64) + +#endif diff --git a/third_party/ulib/musl/src/internal/locale_impl.h b/third_party/ulib/musl/src/internal/locale_impl.h new file mode 100644 index 000000000..ee9ebc0fc --- /dev/null +++ b/third_party/ulib/musl/src/internal/locale_impl.h @@ -0,0 +1,40 @@ +#ifndef _LOCALE_IMPL_H +#define _LOCALE_IMPL_H + +#include "libc.h" +#include "pthread_impl.h" +#include +#include + +#define LOCALE_NAME_MAX 15 + +struct __locale_map { + const void* map; + size_t map_size; + char name[LOCALE_NAME_MAX + 1]; + const struct __locale_map* next; +}; + +extern const struct __locale_map __c_dot_utf8; +extern const struct __locale_struct __c_locale; +extern const struct __locale_struct __c_dot_utf8_locale; + +const struct __locale_map* __get_locale(int, const char*); +const char* __mo_lookup(const void*, size_t, const char*); +const char* __lctrans(const char*, const struct __locale_map*); +const char* __lctrans_cur(const char*); + +#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)]) +#define LCTRANS_CUR(msg) __lctrans_cur(msg) + +#define C_LOCALE ((locale_t)&__c_locale) +#define UTF8_LOCALE ((locale_t)&__c_dot_utf8_locale) + +#define CURRENT_LOCALE (__pthread_self()->locale) + +#define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE]) + +#undef MB_CUR_MAX +#define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1) + +#endif diff --git a/third_party/ulib/musl/src/internal/malloc_impl.h b/third_party/ulib/musl/src/internal/malloc_impl.h new file mode 100644 index 000000000..b5a854c8f --- /dev/null +++ b/third_party/ulib/musl/src/internal/malloc_impl.h @@ -0,0 +1,24 @@ +#pragma once + +#define HEAP_DEBUG 1 + +struct chunk { + // psize is the size of the previous chunk, csize of this one + // size is the distance (in bytes) from this chunk header to the next one. + size_t psize, csize; + // These pointers only exist in freed chunks + struct chunk *next, *prev; +}; + +// psize and csize +#define OVERHEAD (2 * sizeof(size_t)) +#define MEM_SIZE_FROM_CHUNK(c) (CHUNK_SIZE(c) - OVERHEAD) +#define CHUNK_SIZE(c) ((c)->csize & -2) +#define CHUNK_PSIZE(c) ((c)->psize & -2) +#define PREV_CHUNK(c) ((struct chunk*)((char*)(c)-CHUNK_PSIZE(c))) +#define NEXT_CHUNK(c) ((struct chunk*)((char*)(c) + CHUNK_SIZE(c))) +#define MEM_TO_CHUNK(p) (struct chunk*)((char*)(p)-OVERHEAD) +#define CHUNK_TO_MEM(c) (void*)((char*)(c) + OVERHEAD) + +#define C_INUSE ((size_t)1) +#define IS_MMAPPED(c) !((c)->csize & (C_INUSE)) diff --git a/third_party/ulib/musl/src/internal/procfdname.c b/third_party/ulib/musl/src/internal/procfdname.c new file mode 100644 index 000000000..b1ac2386f --- /dev/null +++ b/third_party/ulib/musl/src/internal/procfdname.c @@ -0,0 +1,15 @@ +void __procfdname(char* buf, unsigned fd) { + unsigned i, j; + for (i = 0; (buf[i] = "/proc/self/fd/"[i]); i++) + ; + if (!fd) { + buf[i] = '0'; + buf[i + 1] = 0; + return; + } + for (j = fd; j; j /= 10, i++) + ; + buf[i] = 0; + for (; fd; fd /= 10) + buf[--i] = '0' + fd % 10; +} diff --git a/third_party/ulib/musl/src/internal/pthread_impl.h b/third_party/ulib/musl/src/internal/pthread_impl.h new file mode 100644 index 000000000..fae1a1239 --- /dev/null +++ b/third_party/ulib/musl/src/internal/pthread_impl.h @@ -0,0 +1,161 @@ +#ifndef _PTHREAD_IMPL_H +#define _PTHREAD_IMPL_H + +#include "atomic.h" +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include + +#include +#include +#include + +#define pthread __pthread + +struct __mx_thread_info { + void* (*func)(void*); + void* arg; + void* tls; + int errno_value; +}; + +struct pthread { + struct pthread* self; + void **dtv, *unused1, *unused2; + uintptr_t sysinfo; + uintptr_t canary, canary2; + pid_t tid, pid; + int tsd_used; + volatile int cancel, canceldisable, cancelasync; + int detached; + unsigned char* map_base; + size_t map_size; + void* stack; + size_t stack_size; + void* start_arg; + void* (*start)(void*); + void* result; + struct __ptcb* cancelbuf; + void** tsd; + pthread_attr_t attr; + volatile int dead; + struct { + volatile void* volatile head; + long off; + volatile void* volatile pending; + } robust_list; + int unblock_cancel; + volatile int timer_id; + locale_t locale; + mxr_mutex_t killlock; + mxr_mutex_t exitlock; + mxr_mutex_t startlock; + unsigned long sigmask[_NSIG / 8 / sizeof(long)]; + char* dlerror_buf; + int dlerror_flag; + void* stdio_locks; + uintptr_t canary_at_end; + void** dtv_copy; + mx_handle_t handle; + struct __mx_thread_info mx_thread_info; +}; + +struct __timer { + int timerid; + pthread_t thread; +}; + +#define __SU (sizeof(size_t) / sizeof(int)) + +#define _a_stacksize __u.__s[0] +#define _a_guardsize __u.__s[1] +#define _a_stackaddr __u.__s[2] +#define _a_detach __u.__i[3 * __SU + 0] +#define _a_sched __u.__i[3 * __SU + 1] +#define _a_policy __u.__i[3 * __SU + 2] +#define _a_prio __u.__i[3 * __SU + 3] +#define _m_type __u.__i[0] +#define _m_lock __u.__vi[1] +#define _m_waiters __u.__vi[2] +#define _m_prev __u.__p[3] +#define _m_next __u.__p[4] +#define _m_count __u.__i[5] +#define _c_shared __u.__p[0] +#define _c_seq __u.__vi[2] +#define _c_waiters __u.__vi[3] +#define _c_clock __u.__i[4] +#define _c_lock __u.__vi[8] +#define _c_head __u.__p[1] +#define _c_tail __u.__p[5] +#define _rw_lock __u.__vi[0] +#define _rw_waiters __u.__vi[1] +#define _rw_shared __u.__i[2] +#define _b_lock __u.__vi[0] +#define _b_waiters __u.__vi[1] +#define _b_limit __u.__i[2] +#define _b_count __u.__vi[3] +#define _b_waiters2 __u.__vi[4] +#define _b_inst __u.__p[3] + +#include "pthread_arch.h" + +#ifndef CANARY +#define CANARY canary +#endif + +#ifndef DTP_OFFSET +#define DTP_OFFSET 0 +#endif + +#define SIGTIMER 32 +#define SIGCANCEL 33 +#define SIGSYNCCALL 34 + +#define SIGALL_SET ((sigset_t*)(const unsigned long long[2]){-1, -1}) +#define SIGPT_SET \ + ((sigset_t*)(const unsigned long[_NSIG / 8 / sizeof(long)]){[sizeof(long) == 4] = \ + 3UL \ + << (32 * (sizeof(long) > 4))}) +#define SIGTIMER_SET ((sigset_t*)(const unsigned long[_NSIG / 8 / sizeof(long)]){0x80000000}) + +pthread_t __pthread_self_init(void); + +extern mxr_tls_t __pthread_key; +static inline struct pthread* __pthread_self(void) { + return mxr_tls_get(__pthread_key); +} + +int __clone(int (*)(void*), void*, int, void*, ...); +int __libc_sigaction(int, const struct sigaction*, struct sigaction*); +int __libc_sigprocmask(int, const sigset_t*, sigset_t*); +void __unmapself(void*, size_t); + +void __vm_wait(void); +void __vm_lock(void); +void __vm_unlock(void); + +int __timedwait(volatile int*, int, clockid_t, const struct timespec*); +int __timedwait_cp(volatile int*, int, clockid_t, const struct timespec*); +void __wait(volatile int*, volatile int*, int); +static inline void __wake(volatile void* addr, int cnt) { + if (cnt < 0) cnt = INT_MAX; + _magenta_futex_wake((void*)addr, cnt); +} + +void __acquire_ptc(void); +void __release_ptc(void); +void __inhibit_ptc(void); + +void __block_all_sigs(void*); +void __block_app_sigs(void*); +void __restore_sigs(void*); + +#define DEFAULT_STACK_SIZE 81920 +#define DEFAULT_GUARD_SIZE PAGE_SIZE + +#define __ATTRP_C11_THREAD ((void*)(uintptr_t)-1) + +#endif diff --git a/third_party/ulib/musl/src/internal/shgetc.c b/third_party/ulib/musl/src/internal/shgetc.c new file mode 100644 index 000000000..cd7f6e150 --- /dev/null +++ b/third_party/ulib/musl/src/internal/shgetc.c @@ -0,0 +1,25 @@ +#include "shgetc.h" + +void __shlim(FILE* f, off_t lim) { + f->shlim = lim; + f->shcnt = f->rend - f->rpos; + if (lim && f->shcnt > lim) + f->shend = f->rpos + lim; + else + f->shend = f->rend; +} + +int __shgetc(FILE* f) { + int c; + if (f->shlim && f->shcnt >= f->shlim || (c = __uflow(f)) < 0) { + f->shend = 0; + return EOF; + } + if (f->shlim && f->rend - f->rpos > f->shlim - f->shcnt - 1) + f->shend = f->rpos + (f->shlim - f->shcnt - 1); + else + f->shend = f->rend; + if (f->rend) f->shcnt += f->rend - f->rpos + 1; + if (f->rpos[-1] != c) f->rpos[-1] = c; + return c; +} diff --git a/third_party/ulib/musl/src/internal/shgetc.h b/third_party/ulib/musl/src/internal/shgetc.h new file mode 100644 index 000000000..96c278017 --- /dev/null +++ b/third_party/ulib/musl/src/internal/shgetc.h @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +void __shlim(FILE*, off_t); +int __shgetc(FILE*); + +#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->rend)) +#define shlim(f, lim) __shlim((f), (lim)) +#define shgetc(f) (((f)->rpos < (f)->shend) ? *(f)->rpos++ : __shgetc(f)) +#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0) diff --git a/third_party/ulib/musl/src/internal/stdio_impl.h b/third_party/ulib/musl/src/internal/stdio_impl.h new file mode 100644 index 000000000..bbae52f20 --- /dev/null +++ b/third_party/ulib/musl/src/internal/stdio_impl.h @@ -0,0 +1,99 @@ +#ifndef _STDIO_IMPL_H +#define _STDIO_IMPL_H + +#include "libc.h" +#include "syscall.h" +#include + +#define UNGET 8 + +#define FFINALLOCK(f) ((f)->lock >= 0 ? __lockfile((f)) : 0) +#define FLOCK(f) int __need_unlock = ((f)->lock >= 0 ? __lockfile((f)) : 0) +#define FUNLOCK(f) \ + if (__need_unlock) \ + __unlockfile((f)); \ + else + +#define F_PERM 1 +#define F_NORD 4 +#define F_NOWR 8 +#define F_EOF 16 +#define F_ERR 32 +#define F_SVB 64 +#define F_APP 128 + +struct _IO_FILE { + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE*); + unsigned char *wend, *wpos; + unsigned char* mustbezero_1; + unsigned char* wbase; + size_t (*read)(FILE*, unsigned char*, size_t); + size_t (*write)(FILE*, const unsigned char*, size_t); + off_t (*seek)(FILE*, off_t, int); + unsigned char* buf; + size_t buf_size; + FILE *prev, *next; + int fd; + int pipe_pid; + long lockcount; + short dummy3; + signed char mode; + signed char lbf; + volatile int lock; + volatile int waiters; + void* cookie; + off_t off; + char* getln_buf; + void* mustbezero_2; + unsigned char* shend; + off_t shlim, shcnt; + FILE *prev_locked, *next_locked; + struct __locale_struct* locale; +}; + +size_t __stdio_read(FILE*, unsigned char*, size_t); +size_t __stdio_write(FILE*, const unsigned char*, size_t); +size_t __stdout_write(FILE*, const unsigned char*, size_t); +off_t __stdio_seek(FILE*, off_t, int); +int __stdio_close(FILE*); + +size_t __string_read(FILE*, unsigned char*, size_t); + +int __toread(FILE*); +int __towrite(FILE*); + +#if defined(__PIC__) && (100 * __GNUC__ + __GNUC_MINOR__ >= 303) +__attribute__((visibility("protected"))) +#endif +int __overflow(FILE *, int), __uflow(FILE *); + +int __fseeko(FILE*, off_t, int); +int __fseeko_unlocked(FILE*, off_t, int); +off_t __ftello(FILE*); +off_t __ftello_unlocked(FILE*); +size_t __fwritex(const unsigned char*, size_t, FILE*); +int __putc_unlocked(int, FILE*); + +FILE* __fdopen(int, const char*); +int __fmodeflags(const char*); + +FILE* __ofl_add(FILE* f); +FILE** __ofl_lock(void); +void __ofl_unlock(void); + +#define feof(f) ((f)->flags & F_EOF) +#define ferror(f) ((f)->flags & F_ERR) + +#define getc_unlocked(f) (((f)->rpos < (f)->rend) ? *(f)->rpos++ : __uflow((f))) + +#define putc_unlocked(c, f) \ + (((unsigned char)(c) != (f)->lbf && (f)->wpos < (f)->wend) ? *(f)->wpos++ = (c) \ + : __overflow((f), (c))) + +/* Caller-allocated FILE * operations */ +FILE* __fopen_rb_ca(const char*, FILE*, unsigned char*, size_t); +int __fclose_ca(FILE*); + +#endif diff --git a/third_party/ulib/musl/src/internal/syscall.c b/third_party/ulib/musl/src/internal/syscall.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/internal/syscall.h b/third_party/ulib/musl/src/internal/syscall.h new file mode 100644 index 000000000..b279a65cb --- /dev/null +++ b/third_party/ulib/musl/src/internal/syscall.h @@ -0,0 +1,71 @@ +#ifndef _INTERNAL_SYSCALL_H +#define _INTERNAL_SYSCALL_H + +#include +#include + +#ifndef SYSCALL_RLIM_INFINITY +#define SYSCALL_RLIM_INFINITY (~0ULL) +#endif + +#ifndef SYSCALL_MMAP2_UNIT +#define SYSCALL_MMAP2_UNIT 4096ULL +#endif + +typedef long syscall_arg_t; + +long __linux_syscall(const char* fn, int ln, syscall_arg_t nr, ...); +long __syscall_ret(unsigned long r); + +#define __syscall(nr...) __linux_syscall(__FILE__, __LINE__, nr) + +#define __SYSCALL_NARGS_X(a, b, c, d, e, f, g, h, n, ...) n +#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define syscall(...) __syscall_ret(__syscall(__VA_ARGS__)) + +/* fixup legacy 32-bit-vs-lfs64 junk */ + +#ifdef SYS_getdents64 +#undef SYS_getdents +#define SYS_getdents SYS_getdents64 +#endif + +#if defined(SYS_newfstatat) +#undef SYS_fstatat +#define SYS_fstatat SYS_newfstatat +#elif defined(SYS_fstatat64) +#undef SYS_fstatat +#define SYS_fstatat SYS_fstatat64 +#endif + +#ifdef SYS_ugetrlimit +#undef SYS_getrlimit +#define SYS_getrlimit SYS_ugetrlimit +#endif + +#ifdef SYS_pread64 +#undef SYS_pread +#undef SYS_pwrite +#define SYS_pread SYS_pread64 +#define SYS_pwrite SYS_pwrite64 +#endif + +#ifdef SYS_fadvise64_64 +#undef SYS_fadvise +#define SYS_fadvise SYS_fadvise64_64 +#elif defined(SYS_fadvise64) +#undef SYS_fadvise +#define SYS_fadvise SYS_fadvise64 +#endif + +#define __sys_open2(x, pn, fl) __syscall(SYS_openat, AT_FDCWD, pn, (fl) | O_LARGEFILE) +#define __sys_open3(x, pn, fl, mo) __syscall(SYS_openat, AT_FDCWD, pn, (fl) | O_LARGEFILE, mo) + +#define __sys_open(...) __SYSCALL_DISP(__sys_open, , __VA_ARGS__) +#define sys_open(...) __syscall_ret(__sys_open(__VA_ARGS__)) + +#endif diff --git a/third_party/ulib/musl/src/internal/syscall_ret.c b/third_party/ulib/musl/src/internal/syscall_ret.c new file mode 100644 index 000000000..d62b5fd0c --- /dev/null +++ b/third_party/ulib/musl/src/internal/syscall_ret.c @@ -0,0 +1,10 @@ +#include "syscall.h" +#include + +long __syscall_ret(unsigned long r) { + if (r > -4096UL) { + errno = -r; + return -1; + } + return r; +} diff --git a/third_party/ulib/musl/src/internal/vdso.c b/third_party/ulib/musl/src/internal/vdso.c new file mode 100644 index 000000000..3b0796a35 --- /dev/null +++ b/third_party/ulib/musl/src/internal/vdso.c @@ -0,0 +1,95 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include + +#ifdef VDSO_USEFUL + +#if ULONG_MAX == 0xffffffff +typedef Elf32_Ehdr Ehdr; +typedef Elf32_Phdr Phdr; +typedef Elf32_Sym Sym; +typedef Elf32_Verdef Verdef; +typedef Elf32_Verdaux Verdaux; +#else +typedef Elf64_Ehdr Ehdr; +typedef Elf64_Phdr Phdr; +typedef Elf64_Sym Sym; +typedef Elf64_Verdef Verdef; +typedef Elf64_Verdaux Verdaux; +#endif + +static int checkver(Verdef* def, int vsym, const char* vername, char* strings) { + vsym &= 0x7fff; + for (;;) { + if (!(def->vd_flags & VER_FLG_BASE) && (def->vd_ndx & 0x7fff) == vsym) break; + if (def->vd_next == 0) return 0; + def = (Verdef*)((char*)def + def->vd_next); + } + Verdaux* aux = (Verdaux*)((char*)def + def->vd_aux); + return !strcmp(vername, strings + aux->vda_name); +} + +#define OK_TYPES (1 << STT_NOTYPE | 1 << STT_OBJECT | 1 << STT_FUNC | 1 << STT_COMMON) +#define OK_BINDS (1 << STB_GLOBAL | 1 << STB_WEAK | 1 << STB_GNU_UNIQUE) + +void* __vdsosym(const char* vername, const char* name) { + size_t i; + for (i = 0; libc.auxv[i] != AT_SYSINFO_EHDR; i += 2) + if (!libc.auxv[i]) return 0; + Ehdr* eh = (void*)libc.auxv[i + 1]; + Phdr* ph = (void*)((char*)eh + eh->e_phoff); + size_t *dynv = 0, base = -1; + for (i = 0; i < eh->e_phnum; i++, ph = (void*)((char*)ph + eh->e_phentsize)) { + if (ph->p_type == PT_LOAD) + base = (size_t)eh + ph->p_offset - ph->p_vaddr; + else if (ph->p_type == PT_DYNAMIC) + dynv = (void*)((char*)eh + ph->p_offset); + } + if (!dynv || base == (size_t)-1) return 0; + + char* strings = 0; + Sym* syms = 0; + uint32_t* hashtab = 0; + uint16_t* versym = 0; + Verdef* verdef = 0; + + for (i = 0; dynv[i]; i += 2) { + void* p = (void*)(base + dynv[i + 1]); + switch (dynv[i]) { + case DT_STRTAB: + strings = p; + break; + case DT_SYMTAB: + syms = p; + break; + case DT_HASH: + hashtab = p; + break; + case DT_VERSYM: + versym = p; + break; + case DT_VERDEF: + verdef = p; + break; + } + } + + if (!strings || !syms || !hashtab) return 0; + if (!verdef) versym = 0; + + for (i = 0; i < hashtab[1]; i++) { + if (!(1 << (syms[i].st_info & 0xf) & OK_TYPES)) continue; + if (!(1 << (syms[i].st_info >> 4) & OK_BINDS)) continue; + if (!syms[i].st_shndx) continue; + if (strcmp(name, strings + syms[i].st_name)) continue; + if (versym && !checkver(verdef, versym[i], vername, strings)) continue; + return (void*)(base + syms[i].st_value); + } + + return 0; +} + +#endif diff --git a/third_party/ulib/musl/src/internal/vis.h b/third_party/ulib/musl/src/internal/vis.h new file mode 100644 index 000000000..d65ff7a34 --- /dev/null +++ b/third_party/ulib/musl/src/internal/vis.h @@ -0,0 +1,26 @@ +/* This file is only used if enabled in the build system, in which case it is + * included automatically via command line options. It is not included + * explicitly by any source files or other headers. Its purpose is to + * override default visibilities to reduce the size and performance costs + * of position-independent code. */ + +#if !defined(CRT) && !defined(__ASSEMBLER__) + +/* Conceptually, all symbols should be protected, but some toolchains + * fail to support copy relocations for protected data, so exclude all + * exported data symbols. */ + +__attribute__((__visibility__("default"))) extern struct _IO_FILE *const stdin, *const stdout, + *const stderr; + +__attribute__((__visibility__("default"))) extern int optind, opterr, optopt, optreset, __optreset, + getdate_err, h_errno, daylight, __daylight, signgam, __signgam; + +__attribute__((__visibility__("default"))) extern long timezone, __timezone; + +__attribute__((__visibility__("default"))) extern char *optarg, **environ, **__environ, *tzname[2], + *__tzname[2], *__progname, *__progname_full; + +#pragma GCC visibility push(protected) + +#endif diff --git a/third_party/ulib/musl/src/ipc/BUILD.gn b/third_party/ulib/musl/src/ipc/BUILD.gn new file mode 100644 index 000000000..1f92ee68f --- /dev/null +++ b/third_party/ulib/musl/src/ipc/BUILD.gn @@ -0,0 +1,21 @@ +source_set("ipc") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "ftok.c", + "msgctl.c", + "msgget.c", + "msgrcv.c", + "msgsnd.c", + "semctl.c", + "semget.c", + "semop.c", + "semtimedop.c", + "shmat.c", + "shmctl.c", + "shmdt.c", + "shmget.c", + ] +} diff --git a/third_party/ulib/musl/src/ipc/ftok.c b/third_party/ulib/musl/src/ipc/ftok.c new file mode 100644 index 000000000..3c8489cd6 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/ftok.c @@ -0,0 +1,9 @@ +#include +#include + +key_t ftok(const char* path, int id) { + struct stat st; + if (stat(path, &st) < 0) return -1; + + return ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xff) << 24)); +} diff --git a/third_party/ulib/musl/src/ipc/ipc.h b/third_party/ulib/musl/src/ipc/ipc.h new file mode 100644 index 000000000..874e58a91 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/ipc.h @@ -0,0 +1,12 @@ +#define IPCOP_semop 1 +#define IPCOP_semget 2 +#define IPCOP_semctl 3 +#define IPCOP_semtimedop 4 +#define IPCOP_msgsnd 11 +#define IPCOP_msgrcv 12 +#define IPCOP_msgget 13 +#define IPCOP_msgctl 14 +#define IPCOP_shmat 21 +#define IPCOP_shmdt 22 +#define IPCOP_shmget 23 +#define IPCOP_shmctl 24 diff --git a/third_party/ulib/musl/src/ipc/msgctl.c b/third_party/ulib/musl/src/ipc/msgctl.c new file mode 100644 index 000000000..be31f7d59 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/msgctl.c @@ -0,0 +1,7 @@ +#include "ipc.h" +#include "syscall.h" +#include + +int msgctl(int q, int cmd, struct msqid_ds* buf) { + return syscall(SYS_msgctl, q, cmd | IPC_64, buf); +} diff --git a/third_party/ulib/musl/src/ipc/msgget.c b/third_party/ulib/musl/src/ipc/msgget.c new file mode 100644 index 000000000..6aa58e812 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/msgget.c @@ -0,0 +1,7 @@ +#include "ipc.h" +#include "syscall.h" +#include + +int msgget(key_t k, int flag) { + return syscall(SYS_msgget, k, flag); +} diff --git a/third_party/ulib/musl/src/ipc/msgrcv.c b/third_party/ulib/musl/src/ipc/msgrcv.c new file mode 100644 index 000000000..f4697ba1b --- /dev/null +++ b/third_party/ulib/musl/src/ipc/msgrcv.c @@ -0,0 +1,8 @@ +#include "ipc.h" +#include "libc.h" +#include "syscall.h" +#include + +ssize_t msgrcv(int q, void* m, size_t len, long type, int flag) { + return syscall(SYS_msgrcv, q, m, len, type, flag); +} diff --git a/third_party/ulib/musl/src/ipc/msgsnd.c b/third_party/ulib/musl/src/ipc/msgsnd.c new file mode 100644 index 000000000..121a8aec6 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/msgsnd.c @@ -0,0 +1,8 @@ +#include "ipc.h" +#include "libc.h" +#include "syscall.h" +#include + +int msgsnd(int q, const void* m, size_t len, int flag) { + return syscall(SYS_msgsnd, q, m, len, flag); +} diff --git a/third_party/ulib/musl/src/ipc/semctl.c b/third_party/ulib/musl/src/ipc/semctl.c new file mode 100644 index 000000000..0f941f9f0 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/semctl.c @@ -0,0 +1,29 @@ +#include "ipc.h" +#include "syscall.h" +#include +#include + +union semun { + int val; + struct semid_ds* buf; + unsigned short* array; +}; + +int semctl(int id, int num, int cmd, ...) { + union semun arg = {0}; + va_list ap; + switch (cmd) { + case SETVAL: + case GETALL: + case SETALL: + case IPC_STAT: + case IPC_SET: + case IPC_INFO: + case SEM_INFO: + case SEM_STAT: + va_start(ap, cmd); + arg = va_arg(ap, union semun); + va_end(ap); + } + return syscall(SYS_semctl, id, num, cmd | IPC_64, arg.buf); +} diff --git a/third_party/ulib/musl/src/ipc/semget.c b/third_party/ulib/musl/src/ipc/semget.c new file mode 100644 index 000000000..7c9a99346 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/semget.c @@ -0,0 +1,14 @@ +#include "ipc.h" +#include "syscall.h" +#include +#include +#include + +int semget(key_t key, int n, int fl) { + /* The kernel uses the wrong type for the sem_nsems member + * of struct semid_ds, and thus might not check that the + * n fits in the correct (per POSIX) userspace type, so + * we have to check here. */ + if (n > USHRT_MAX) return __syscall_ret(-EINVAL); + return syscall(SYS_semget, key, n, fl); +} diff --git a/third_party/ulib/musl/src/ipc/semop.c b/third_party/ulib/musl/src/ipc/semop.c new file mode 100644 index 000000000..7be0e6f69 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/semop.c @@ -0,0 +1,7 @@ +#include "ipc.h" +#include "syscall.h" +#include + +int semop(int id, struct sembuf* buf, size_t n) { + return syscall(SYS_semop, id, buf, n); +} diff --git a/third_party/ulib/musl/src/ipc/semtimedop.c b/third_party/ulib/musl/src/ipc/semtimedop.c new file mode 100644 index 000000000..131b26df7 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/semtimedop.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "ipc.h" +#include "syscall.h" +#include + +int semtimedop(int id, struct sembuf* buf, size_t n, const struct timespec* ts) { + return syscall(SYS_semtimedop, id, buf, n, ts); +} diff --git a/third_party/ulib/musl/src/ipc/shmat.c b/third_party/ulib/musl/src/ipc/shmat.c new file mode 100644 index 000000000..6b790db5f --- /dev/null +++ b/third_party/ulib/musl/src/ipc/shmat.c @@ -0,0 +1,7 @@ +#include "ipc.h" +#include "syscall.h" +#include + +void* shmat(int id, const void* addr, int flag) { + return (void*)syscall(SYS_shmat, id, addr, flag); +} diff --git a/third_party/ulib/musl/src/ipc/shmctl.c b/third_party/ulib/musl/src/ipc/shmctl.c new file mode 100644 index 000000000..52dc4fade --- /dev/null +++ b/third_party/ulib/musl/src/ipc/shmctl.c @@ -0,0 +1,7 @@ +#include "ipc.h" +#include "syscall.h" +#include + +int shmctl(int id, int cmd, struct shmid_ds* buf) { + return syscall(SYS_shmctl, id, cmd | IPC_64, buf); +} diff --git a/third_party/ulib/musl/src/ipc/shmdt.c b/third_party/ulib/musl/src/ipc/shmdt.c new file mode 100644 index 000000000..bbb038dbd --- /dev/null +++ b/third_party/ulib/musl/src/ipc/shmdt.c @@ -0,0 +1,7 @@ +#include "ipc.h" +#include "syscall.h" +#include + +int shmdt(const void* addr) { + return syscall(SYS_shmdt, addr); +} diff --git a/third_party/ulib/musl/src/ipc/shmget.c b/third_party/ulib/musl/src/ipc/shmget.c new file mode 100644 index 000000000..12440ade2 --- /dev/null +++ b/third_party/ulib/musl/src/ipc/shmget.c @@ -0,0 +1,9 @@ +#include "ipc.h" +#include "syscall.h" +#include +#include + +int shmget(key_t key, size_t size, int flag) { + if (size > PTRDIFF_MAX) size = SIZE_MAX; + return syscall(SYS_shmget, key, size, flag); +} diff --git a/third_party/ulib/musl/src/ldso/BUILD.gn b/third_party/ulib/musl/src/ldso/BUILD.gn new file mode 100644 index 000000000..cb5c0aafd --- /dev/null +++ b/third_party/ulib/musl/src/ldso/BUILD.gn @@ -0,0 +1,36 @@ +source_set("ldso") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__dlsym.c", + "dl_iterate_phdr.c", + "dladdr.c", + "dlclose.c", + "dlerror.c", + "dlinfo.c", + "dlopen.c", + ] + if (target_cpu == "arm") { + sources += [ + "arm/dlsym.s", + "arm/tlsdesc.s", + ] + } else if (target_cpu == "arm64") { + sources += [ + "aarch64/dlsym.s", + "aarch64/tlsdesc.s", + ] + } else if (target_cpu == "x64") { + sources += [ + "x86_64/dlsym.s", + "x86_64/tlsdesc.s", + ] + } else { + sources += [ + "dlsym.c", + "tlsdesc.c", + ] + } +} diff --git a/third_party/ulib/musl/src/ldso/__dlsym.c b/third_party/ulib/musl/src/ldso/__dlsym.c new file mode 100644 index 000000000..5c2b07e96 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/__dlsym.c @@ -0,0 +1,11 @@ +#include "libc.h" +#include + +__attribute__((__visibility__("hidden"))) void __dl_seterr(const char*, ...); + +static void* stub_dlsym(void* restrict p, const char* restrict s, void* restrict ra) { + __dl_seterr("Symbol not found: %s", s); + return 0; +} + +weak_alias(stub_dlsym, __dlsym); diff --git a/third_party/ulib/musl/src/ldso/aarch64/dlsym.s b/third_party/ulib/musl/src/ldso/aarch64/dlsym.s new file mode 100644 index 000000000..abaae4d51 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/aarch64/dlsym.s @@ -0,0 +1,6 @@ +.global dlsym +.hidden __dlsym +.type dlsym,%function +dlsym: + mov x2,x30 + b __dlsym diff --git a/third_party/ulib/musl/src/ldso/aarch64/tlsdesc.s b/third_party/ulib/musl/src/ldso/aarch64/tlsdesc.s new file mode 100644 index 000000000..8ed5c2678 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/aarch64/tlsdesc.s @@ -0,0 +1,96 @@ +// size_t __tlsdesc_static(size_t *a) +// { +// return a[1]; +// } +.global __tlsdesc_static +.hidden __tlsdesc_static +.type __tlsdesc_static,@function +__tlsdesc_static: + ldr x0,[x0,#8] + ret + +.hidden __tls_get_new + +// size_t __tlsdesc_dynamic(size_t *a) +// { +// struct {size_t modidx,off;} *p = (void*)a[1]; +// size_t *dtv = *(size_t**)(tp + 16 - 8); +// if (p->modidx <= dtv[0]) +// return dtv[p->modidx] + p->off - tp; +// return __tls_get_new(p) - tp; +// } +.global __tlsdesc_dynamic +.hidden __tlsdesc_dynamic +.type __tlsdesc_dynamic,@function +__tlsdesc_dynamic: + stp x1,x2,[sp,#-32]! + stp x3,x4,[sp,#16] + mrs x1,tpidr_el0 // tp + ldr x0,[x0,#8] // p + ldr x2,[x0] // p->modidx + add x3,x1,#8 + ldr x3,[x3] // dtv + ldr x4,[x3] // dtv[0] + cmp x2,x4 + b.hi 1f + ldr x2,[x3,x2,lsl #3] // dtv[p->modidx] + ldr x0,[x0,#8] // p->off + add x0,x0,x2 +2: sub x0,x0,x1 + ldp x3,x4,[sp,#16] + ldp x1,x2,[sp],#32 + ret + + // save all registers __tls_get_new may clobber + // update sp in two steps because offset must be in [-512,509] +1: stp x29,x30,[sp,#-160]! + stp x5,x6,[sp,#16] + stp x7,x8,[sp,#32] + stp x9,x10,[sp,#48] + stp x11,x12,[sp,#64] + stp x13,x14,[sp,#80] + stp x15,x16,[sp,#96] + stp x17,x18,[sp,#112] + stp q0,q1,[sp,#128] + stp q2,q3,[sp,#-480]! + stp q4,q5,[sp,#32] + stp q6,q7,[sp,#64] + stp q8,q9,[sp,#96] + stp q10,q11,[sp,#128] + stp q12,q13,[sp,#160] + stp q14,q15,[sp,#192] + stp q16,q17,[sp,#224] + stp q18,q19,[sp,#256] + stp q20,q21,[sp,#288] + stp q22,q23,[sp,#320] + stp q24,q25,[sp,#352] + stp q26,q27,[sp,#384] + stp q28,q29,[sp,#416] + stp q30,q31,[sp,#448] + bl __tls_get_new + mrs x1,tpidr_el0 + ldp q4,q5,[sp,#32] + ldp q6,q7,[sp,#64] + ldp q8,q9,[sp,#96] + ldp q10,q11,[sp,#128] + ldp q12,q13,[sp,#160] + ldp q14,q15,[sp,#192] + ldp q16,q17,[sp,#224] + ldp q18,q19,[sp,#256] + ldp q20,q21,[sp,#288] + ldp q22,q23,[sp,#320] + ldp q24,q25,[sp,#352] + ldp q26,q27,[sp,#384] + ldp q28,q29,[sp,#416] + ldp q30,q31,[sp,#448] + ldp q2,q3,[sp],#480 + ldp x5,x6,[sp,#16] + ldp x7,x8,[sp,#32] + ldp x9,x10,[sp,#48] + ldp x11,x12,[sp,#64] + ldp x13,x14,[sp,#80] + ldp x15,x16,[sp,#96] + ldp x17,x18,[sp,#112] + ldp q0,q1,[sp,#128] + ldp x29,x30,[sp],#160 + b 2b diff --git a/third_party/ulib/musl/src/ldso/arm/dlsym.s b/third_party/ulib/musl/src/ldso/arm/dlsym.s new file mode 100644 index 000000000..2652c348d --- /dev/null +++ b/third_party/ulib/musl/src/ldso/arm/dlsym.s @@ -0,0 +1,8 @@ +.syntax unified +.text +.global dlsym +.hidden __dlsym +.type dlsym,%function +dlsym: + mov r2,lr + b __dlsym diff --git a/third_party/ulib/musl/src/ldso/arm/find_exidx.c b/third_party/ulib/musl/src/ldso/arm/find_exidx.c new file mode 100644 index 000000000..dff8c4407 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/arm/find_exidx.c @@ -0,0 +1,39 @@ +#define _GNU_SOURCE +#include +#include + +struct find_exidx_data { + uintptr_t pc, exidx_start; + int exidx_len; +}; + +static int find_exidx(struct dl_phdr_info* info, size_t size, void* ptr) { + struct find_exidx_data* data = ptr; + const ElfW(Phdr)* phdr = info->dlpi_phdr; + uintptr_t addr, exidx_start = 0; + int i, match = 0, exidx_len = 0; + + for (i = info->dlpi_phnum; i > 0; i--, phdr++) { + addr = info->dlpi_addr + phdr->p_vaddr; + switch (phdr->p_type) { + case PT_LOAD: + match |= data->pc >= addr && data->pc < addr + phdr->p_memsz; + break; + case PT_ARM_EXIDX: + exidx_start = addr; + exidx_len = phdr->p_memsz; + break; + } + } + data->exidx_start = exidx_start; + data->exidx_len = exidx_len; + return match; +} + +uintptr_t __gnu_Unwind_Find_exidx(uintptr_t pc, int* pcount) { + struct find_exidx_data data; + data.pc = pc; + if (dl_iterate_phdr(find_exidx, &data) <= 0) return 0; + *pcount = data.exidx_len / 8; + return data.exidx_start; +} diff --git a/third_party/ulib/musl/src/ldso/dl_iterate_phdr.c b/third_party/ulib/musl/src/ldso/dl_iterate_phdr.c new file mode 100644 index 000000000..143611288 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dl_iterate_phdr.c @@ -0,0 +1,41 @@ +#include "libc.h" +#include +#include + +#define AUX_CNT 38 + +static int static_dl_iterate_phdr(int (*callback)(struct dl_phdr_info* info, size_t size, + void* data), + void* data) { + unsigned char* p; + ElfW(Phdr) * phdr, *tls_phdr = 0; + size_t base = 0; + size_t n; + struct dl_phdr_info info; + size_t i, aux[AUX_CNT]; + + for (i = 0; libc.auxv[i]; i += 2) + if (libc.auxv[i] < AUX_CNT) aux[libc.auxv[i]] = libc.auxv[i + 1]; + + for (p = (void*)aux[AT_PHDR], n = aux[AT_PHNUM]; n; n--, p += aux[AT_PHENT]) { + phdr = (void*)p; + if (phdr->p_type == PT_PHDR) base = aux[AT_PHDR] - phdr->p_vaddr; + if (phdr->p_type == PT_TLS) tls_phdr = phdr; + } + info.dlpi_addr = base; + info.dlpi_name = "/proc/self/exe"; + info.dlpi_phdr = (void*)aux[AT_PHDR]; + info.dlpi_phnum = aux[AT_PHNUM]; + info.dlpi_adds = 0; + info.dlpi_subs = 0; + if (tls_phdr) { + info.dlpi_tls_modid = 1; + info.dlpi_tls_data = (void*)(base + tls_phdr->p_vaddr); + } else { + info.dlpi_tls_modid = 0; + info.dlpi_tls_data = 0; + } + return (callback)(&info, sizeof(info), data); +} + +weak_alias(static_dl_iterate_phdr, dl_iterate_phdr); diff --git a/third_party/ulib/musl/src/ldso/dladdr.c b/third_party/ulib/musl/src/ldso/dladdr.c new file mode 100644 index 000000000..2558cee1c --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dladdr.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include "libc.h" +#include + +static int stub_dladdr(const void* addr, Dl_info* info) { + return 0; +} + +weak_alias(stub_dladdr, dladdr); diff --git a/third_party/ulib/musl/src/ldso/dlclose.c b/third_party/ulib/musl/src/ldso/dlclose.c new file mode 100644 index 000000000..87956d224 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dlclose.c @@ -0,0 +1,7 @@ +#include + +__attribute__((__visibility__("hidden"))) int __dl_invalid_handle(void*); + +int dlclose(void* p) { + return __dl_invalid_handle(p); +} diff --git a/third_party/ulib/musl/src/ldso/dlerror.c b/third_party/ulib/musl/src/ldso/dlerror.c new file mode 100644 index 000000000..b2e1a6895 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dlerror.c @@ -0,0 +1,54 @@ +#include "libc.h" +#include "pthread_impl.h" +#include +#include +#include + +char* dlerror() { + pthread_t self = __pthread_self(); + if (!self->dlerror_flag) return 0; + self->dlerror_flag = 0; + char* s = self->dlerror_buf; + if (s == (void*)-1) + return "Dynamic linker failed to allocate memory for error message"; + else + return s; +} + +void __dl_thread_cleanup(void) { + pthread_t self = __pthread_self(); + if (self->dlerror_buf != (void*)-1) free(self->dlerror_buf); +} + +__attribute__((__visibility__("hidden"))) void __dl_vseterr(const char* fmt, va_list ap) { + va_list ap2; + va_copy(ap2, ap); + pthread_t self = __pthread_self(); + if (self->dlerror_buf != (void*)-1) free(self->dlerror_buf); + size_t len = vsnprintf(0, 0, fmt, ap2); + va_end(ap2); + char* buf = malloc(len + 1); + if (buf) { + vsnprintf(buf, len + 1, fmt, ap); + } else { + buf = (void*)-1; + } + self->dlerror_buf = buf; + self->dlerror_flag = 1; +} + +__attribute__((__visibility__("hidden"))) void __dl_seterr(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + __dl_vseterr(fmt, ap); + va_end(ap); +} + +__attribute__((__visibility__("hidden"))) int __dl_invalid_handle(void*); + +static int stub_invalid_handle(void* h) { + __dl_seterr("Invalid library handle %p", (void*)h); + return 1; +} + +weak_alias(stub_invalid_handle, __dl_invalid_handle); diff --git a/third_party/ulib/musl/src/ldso/dlinfo.c b/third_party/ulib/musl/src/ldso/dlinfo.c new file mode 100644 index 000000000..5cfc27c95 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dlinfo.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include + +__attribute__((__visibility__("hidden"))) int __dl_invalid_handle(void*); + +__attribute__((__visibility__("hidden"))) void __dl_seterr(const char*, ...); + +int dlinfo(void* dso, int req, void* res) { + if (__dl_invalid_handle(dso)) return -1; + if (req != RTLD_DI_LINKMAP) { + __dl_seterr("Unsupported request %d", req); + return -1; + } + *(struct link_map**)res = dso; + return 0; +} diff --git a/third_party/ulib/musl/src/ldso/dlopen.c b/third_party/ulib/musl/src/ldso/dlopen.c new file mode 100644 index 000000000..ecc07bf27 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dlopen.c @@ -0,0 +1,11 @@ +#include "libc.h" +#include + +__attribute__((__visibility__("hidden"))) void __dl_seterr(const char*, ...); + +static void* stub_dlopen(const char* file, int mode) { + __dl_seterr("Dynamic loading not supported"); + return 0; +} + +weak_alias(stub_dlopen, dlopen); diff --git a/third_party/ulib/musl/src/ldso/dlsym.c b/third_party/ulib/musl/src/ldso/dlsym.c new file mode 100644 index 000000000..c55d537d2 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/dlsym.c @@ -0,0 +1,7 @@ +#include + +void* __dlsym(void* restrict, const char* restrict, void* restrict); + +void* dlsym(void* restrict p, const char* restrict s) { + return __dlsym(p, s, 0); +} diff --git a/third_party/ulib/musl/src/ldso/tlsdesc.c b/third_party/ulib/musl/src/ldso/tlsdesc.c new file mode 100644 index 000000000..ec198cd61 --- /dev/null +++ b/third_party/ulib/musl/src/ldso/tlsdesc.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include + +__attribute__((__visibility__("hidden"))) ptrdiff_t __tlsdesc_static(void), __tlsdesc_dynamic(void); + +ptrdiff_t __tlsdesc_static(void) { + return 0; +} + +weak_alias(__tlsdesc_static, __tlsdesc_dynamic); diff --git a/third_party/ulib/musl/src/ldso/x32/dlsym.s b/third_party/ulib/musl/src/ldso/x32/dlsym.s new file mode 100644 index 000000000..d840b955c --- /dev/null +++ b/third_party/ulib/musl/src/ldso/x32/dlsym.s @@ -0,0 +1,7 @@ +.text +.global dlsym +.hidden __dlsym +.type dlsym,@function +dlsym: + mov (%rsp),%rdx + jmp __dlsym diff --git a/third_party/ulib/musl/src/ldso/x86_64/dlsym.s b/third_party/ulib/musl/src/ldso/x86_64/dlsym.s new file mode 100644 index 000000000..d840b955c --- /dev/null +++ b/third_party/ulib/musl/src/ldso/x86_64/dlsym.s @@ -0,0 +1,7 @@ +.text +.global dlsym +.hidden __dlsym +.type dlsym,@function +dlsym: + mov (%rsp),%rdx + jmp __dlsym diff --git a/third_party/ulib/musl/src/ldso/x86_64/tlsdesc.s b/third_party/ulib/musl/src/ldso/x86_64/tlsdesc.s new file mode 100644 index 000000000..8238c3ebf --- /dev/null +++ b/third_party/ulib/musl/src/ldso/x86_64/tlsdesc.s @@ -0,0 +1,44 @@ +.text +.global __tlsdesc_static +.hidden __tlsdesc_static +.type __tlsdesc_static,@function +__tlsdesc_static: + mov 8(%rax),%rax + ret + +.hidden __tls_get_new + +.global __tlsdesc_dynamic +.hidden __tlsdesc_dynamic +.type __tlsdesc_dynamic,@function +__tlsdesc_dynamic: + mov 8(%rax),%rax + push %rdx + mov %fs:8,%rdx + push %rcx + mov (%rax),%rcx + cmp %rcx,(%rdx) + jc 1f + mov 8(%rax),%rax + add (%rdx,%rcx,8),%rax +2: pop %rcx + sub %fs:0,%rax + pop %rdx + ret +1: push %rdi + push %rdi + push %rsi + push %r8 + push %r9 + push %r10 + push %r11 + mov %rax,%rdi + call __tls_get_new + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rsi + pop %rdi + pop %rdi + jmp 2b diff --git a/third_party/ulib/musl/src/legacy/BUILD.gn b/third_party/ulib/musl/src/legacy/BUILD.gn new file mode 100644 index 000000000..853d4f053 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/BUILD.gn @@ -0,0 +1,24 @@ +source_set("legacy") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "cuserid.c", + "daemon.c", + "err.c", + "euidaccess.c", + "ftw.c", + "futimes.c", + "getdtablesize.c", + "getloadavg.c", + "getpagesize.c", + "getpass.c", + "getusershell.c", + "isastream.c", + "lutimes.c", + "ulimit.c", + "utmpx.c", + "valloc.c", + ] +} diff --git a/third_party/ulib/musl/src/legacy/cuserid.c b/third_party/ulib/musl/src/legacy/cuserid.c new file mode 100644 index 000000000..a3fd23498 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/cuserid.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include +#include +#include + +char* cuserid(char* buf) { + struct passwd pw, *ppw; + long pwb[256]; + if (getpwuid_r(geteuid(), &pw, (void*)pwb, sizeof pwb, &ppw)) return 0; + snprintf(buf, L_cuserid, "%s", pw.pw_name); + return buf; +} diff --git a/third_party/ulib/musl/src/legacy/daemon.c b/third_party/ulib/musl/src/legacy/daemon.c new file mode 100644 index 000000000..7c507f53a --- /dev/null +++ b/third_party/ulib/musl/src/legacy/daemon.c @@ -0,0 +1,36 @@ +#define _GNU_SOURCE +#include +#include + +int daemon(int nochdir, int noclose) { + if (!nochdir && chdir("/")) return -1; + if (!noclose) { + int fd, failed = 0; + if ((fd = open("/dev/null", O_RDWR)) < 0) return -1; + if (dup2(fd, 0) < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) failed++; + if (fd > 2) close(fd); + if (failed) return -1; + } + + switch (fork()) { + case 0: + break; + case -1: + return -1; + default: + _exit(0); + } + + if (setsid() < 0) return -1; + + switch (fork()) { + case 0: + break; + case -1: + return -1; + default: + _exit(0); + } + + return 0; +} diff --git a/third_party/ulib/musl/src/legacy/err.c b/third_party/ulib/musl/src/legacy/err.c new file mode 100644 index 000000000..b13e33709 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/err.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +extern char* __progname; + +void vwarn(const char* fmt, va_list ap) { + fprintf(stderr, "%s: ", __progname); + if (fmt) { + vfprintf(stderr, fmt, ap); + fputs(": ", stderr); + } + perror(0); +} + +void vwarnx(const char* fmt, va_list ap) { + fprintf(stderr, "%s: ", __progname); + if (fmt) vfprintf(stderr, fmt, ap); + putc('\n', stderr); +} + +_Noreturn void verr(int status, const char* fmt, va_list ap) { + vwarn(fmt, ap); + exit(status); +} + +_Noreturn void verrx(int status, const char* fmt, va_list ap) { + vwarnx(fmt, ap); + exit(status); +} + +void warn(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} + +void warnx(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +_Noreturn void err(int status, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + verr(status, fmt, ap); + va_end(ap); +} + +_Noreturn void errx(int status, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + verrx(status, fmt, ap); + va_end(ap); +} diff --git a/third_party/ulib/musl/src/legacy/euidaccess.c b/third_party/ulib/musl/src/legacy/euidaccess.c new file mode 100644 index 000000000..c5d59ad33 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/euidaccess.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include "libc.h" +#include +#include + +int euidaccess(const char* filename, int amode) { + return faccessat(AT_FDCWD, filename, amode, AT_EACCESS); +} + +weak_alias(euidaccess, eaccess); diff --git a/third_party/ulib/musl/src/legacy/ftw.c b/third_party/ulib/musl/src/legacy/ftw.c new file mode 100644 index 000000000..adb96b8ff --- /dev/null +++ b/third_party/ulib/musl/src/legacy/ftw.c @@ -0,0 +1,11 @@ +#include "libc.h" +#include + +int ftw(const char* path, int (*fn)(const char*, const struct stat*, int), int fd_limit) { + /* The following cast assumes that calling a function with one + * argument more than it needs behaves as expected. This is + * actually undefined, but works on all real-world machines. */ + return nftw(path, (int (*)(const char*, const struct stat*, int, struct FTW*))fn, fd_limit, FTW_PHYS); +} + +LFS64(ftw); diff --git a/third_party/ulib/musl/src/legacy/futimes.c b/third_party/ulib/musl/src/legacy/futimes.c new file mode 100644 index 000000000..e34f35dbb --- /dev/null +++ b/third_party/ulib/musl/src/legacy/futimes.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include +#include + +int futimes(int fd, const struct timeval tv[2]) { + struct timespec times[2]; + if (!tv) return futimens(fd, 0); + times[0].tv_sec = tv[0].tv_sec; + times[0].tv_nsec = tv[0].tv_usec * 1000; + times[1].tv_sec = tv[1].tv_sec; + times[1].tv_nsec = tv[1].tv_usec * 1000; + return futimens(fd, times); +} diff --git a/third_party/ulib/musl/src/legacy/getdtablesize.c b/third_party/ulib/musl/src/legacy/getdtablesize.c new file mode 100644 index 000000000..cbeb57e40 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/getdtablesize.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include +#include +#include + +int getdtablesize(void) { + struct rlimit rl; + getrlimit(RLIMIT_NOFILE, &rl); + return rl.rlim_max < INT_MAX ? rl.rlim_max : INT_MAX; +} diff --git a/third_party/ulib/musl/src/legacy/getloadavg.c b/third_party/ulib/musl/src/legacy/getloadavg.c new file mode 100644 index 000000000..acceee8b7 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/getloadavg.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include +#include + +int getloadavg(double* a, int n) { + struct sysinfo si; + if (n <= 0) return n ? -1 : 0; + sysinfo(&si); + if (n > 3) n = 3; + for (int i = 0; i < n; i++) + a[i] = 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[i]; + return n; +} diff --git a/third_party/ulib/musl/src/legacy/getpagesize.c b/third_party/ulib/musl/src/legacy/getpagesize.c new file mode 100644 index 000000000..aab2043b2 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/getpagesize.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "libc.h" +#include + +int getpagesize(void) { + return PAGE_SIZE; +} diff --git a/third_party/ulib/musl/src/legacy/getpass.c b/third_party/ulib/musl/src/legacy/getpass.c new file mode 100644 index 000000000..a3a965492 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/getpass.c @@ -0,0 +1,39 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +char* getpass(const char* prompt) { + int fd; + struct termios s, t; + ssize_t l; + static char password[128]; + + if ((fd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC)) < 0) return 0; + + tcgetattr(fd, &t); + s = t; + t.c_lflag &= ~(ECHO | ISIG); + t.c_lflag |= ICANON; + t.c_iflag &= ~(INLCR | IGNCR); + t.c_iflag |= ICRNL; + tcsetattr(fd, TCSAFLUSH, &t); + tcdrain(fd); + + dprintf(fd, "%s", prompt); + + l = read(fd, password, sizeof password); + if (l >= 0) { + if (l > 0 && password[l - 1] == '\n') l--; + password[l] = 0; + } + + tcsetattr(fd, TCSAFLUSH, &s); + + dprintf(fd, "\n"); + close(fd); + + return l < 0 ? 0 : password; +} diff --git a/third_party/ulib/musl/src/legacy/getusershell.c b/third_party/ulib/musl/src/legacy/getusershell.c new file mode 100644 index 000000000..e80f3bb93 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/getusershell.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE +#include +#include + +static const char defshells[] = "/bin/sh\n/bin/csh\n"; + +static char* line; +static size_t linesize; +static FILE* f; + +void endusershell(void) { + if (f) fclose(f); + f = 0; +} + +void setusershell(void) { + if (!f) f = fopen("/etc/shells", "rbe"); + if (!f) f = fmemopen((void*)defshells, sizeof defshells - 1, "rb"); +} + +char* getusershell(void) { + ssize_t l; + if (!f) setusershell(); + if (!f) return 0; + l = getline(&line, &linesize, f); + if (l <= 0) return 0; + if (line[l - 1] == '\n') line[l - 1] = 0; + return line; +} diff --git a/third_party/ulib/musl/src/legacy/isastream.c b/third_party/ulib/musl/src/legacy/isastream.c new file mode 100644 index 000000000..c9cd2ec79 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/isastream.c @@ -0,0 +1,6 @@ +#include +#include + +int isastream(int fd) { + return fcntl(fd, F_GETFD) < 0 ? -1 : 0; +} diff --git a/third_party/ulib/musl/src/legacy/lutimes.c b/third_party/ulib/musl/src/legacy/lutimes.c new file mode 100644 index 000000000..7187a874c --- /dev/null +++ b/third_party/ulib/musl/src/legacy/lutimes.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include +#include +#include + +int lutimes(const char* filename, const struct timeval tv[2]) { + struct timespec times[2]; + times[0].tv_sec = tv[0].tv_sec; + times[0].tv_nsec = tv[0].tv_usec * 1000; + times[1].tv_sec = tv[1].tv_sec; + times[1].tv_nsec = tv[1].tv_usec * 1000; + return utimensat(AT_FDCWD, filename, times, AT_SYMLINK_NOFOLLOW); +} diff --git a/third_party/ulib/musl/src/legacy/ulimit.c b/third_party/ulib/musl/src/legacy/ulimit.c new file mode 100644 index 000000000..3395f4c77 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/ulimit.c @@ -0,0 +1,18 @@ +#include +#include +#include + +long ulimit(int cmd, ...) { + struct rlimit rl; + getrlimit(RLIMIT_FSIZE, &rl); + if (cmd == UL_SETFSIZE) { + long val; + va_list ap; + va_start(ap, cmd); + val = va_arg(ap, long); + va_end(ap); + rl.rlim_cur = 512ULL * val; + if (setrlimit(RLIMIT_FSIZE, &rl)) return -1; + } + return rl.rlim_cur / 512; +} diff --git a/third_party/ulib/musl/src/legacy/utmpx.c b/third_party/ulib/musl/src/legacy/utmpx.c new file mode 100644 index 000000000..6423fdf71 --- /dev/null +++ b/third_party/ulib/musl/src/legacy/utmpx.c @@ -0,0 +1,41 @@ +#include "libc.h" +#include +#include +#include + +void endutxent(void) {} + +void setutxent(void) {} + +struct utmpx* getutxent(void) { + return NULL; +} + +struct utmpx* getutxid(const struct utmpx* ut) { + return NULL; +} + +struct utmpx* getutxline(const struct utmpx* ut) { + return NULL; +} + +struct utmpx* pututxline(const struct utmpx* ut) { + return NULL; +} + +void updwtmpx(const char* f, const struct utmpx* u) {} + +int __utmpxname(const char* f) { + errno = ENOTSUP; + return -1; +} + +weak_alias(endutxent, endutent); +weak_alias(setutxent, setutent); +weak_alias(getutxent, getutent); +weak_alias(getutxid, getutid); +weak_alias(getutxline, getutline); +weak_alias(pututxline, pututline); +weak_alias(updwtmpx, updwtmp); +weak_alias(__utmpxname, utmpname); +weak_alias(__utmpxname, utmpxname); diff --git a/third_party/ulib/musl/src/legacy/valloc.c b/third_party/ulib/musl/src/legacy/valloc.c new file mode 100644 index 000000000..673b0a30e --- /dev/null +++ b/third_party/ulib/musl/src/legacy/valloc.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include "libc.h" +#include + +void* valloc(size_t size) { + return memalign(PAGE_SIZE, size); +} diff --git a/third_party/ulib/musl/src/linux/BUILD.gn b/third_party/ulib/musl/src/linux/BUILD.gn new file mode 100644 index 000000000..cb8b38074 --- /dev/null +++ b/third_party/ulib/musl/src/linux/BUILD.gn @@ -0,0 +1,63 @@ +source_set("linux") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "adjtime.c", + "adjtimex.c", + "arch_prctl.c", + "brk.c", + "cache.c", + "cap.c", + "chroot.c", + "clock_adjtime.c", + "clone.c", + "epoll.c", + "eventfd.c", + "fallocate.c", + "fanotify.c", + "flock.c", + "inotify.c", + "ioperm.c", + "iopl.c", + "klogctl.c", + "module.c", + "mount.c", + "personality.c", + "pivot_root.c", + "ppoll.c", + "prctl.c", + "prlimit.c", + "process_vm.c", + "ptrace.c", + "quotactl.c", + "readahead.c", + "reboot.c", + "remap_file_pages.c", + "sbrk.c", + "sendfile.c", + "setfsgid.c", + "setfsuid.c", + "setgroups.c", + "sethostname.c", + "setns.c", + "settimeofday.c", + "signalfd.c", + "splice.c", + "stime.c", + "swap.c", + "sync_file_range.c", + "syncfs.c", + "sysinfo.c", + "tee.c", + "timerfd.c", + "unshare.c", + "utimes.c", + "vhangup.c", + "vmsplice.c", + "wait3.c", + "wait4.c", + "xattr.c", + ] +} diff --git a/third_party/ulib/musl/src/linux/adjtime.c b/third_party/ulib/musl/src/linux/adjtime.c new file mode 100644 index 000000000..0c23ac12a --- /dev/null +++ b/third_party/ulib/musl/src/linux/adjtime.c @@ -0,0 +1,26 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include +#include + +int adjtime(const struct timeval* in, struct timeval* out) { + struct timex tx = {0}; + if (in) { + if (in->tv_sec > 1000 || in->tv_usec > 1000000000) { + errno = EINVAL; + return -1; + } + tx.offset = in->tv_sec * 1000000 + in->tv_usec; + tx.modes = ADJ_OFFSET_SINGLESHOT; + } + if (syscall(SYS_adjtimex, &tx) < 0) return -1; + if (out) { + out->tv_sec = tx.offset / 1000000; + if ((out->tv_usec = tx.offset % 1000000) < 0) { + out->tv_sec--; + out->tv_usec += 1000000; + } + } + return 0; +} diff --git a/third_party/ulib/musl/src/linux/brk.c b/third_party/ulib/musl/src/linux/brk.c new file mode 100644 index 000000000..7c0e201c2 --- /dev/null +++ b/third_party/ulib/musl/src/linux/brk.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int brk(void* end) { + return __syscall_ret(-ENOMEM); +} diff --git a/third_party/ulib/musl/src/linux/cache.c b/third_party/ulib/musl/src/linux/cache.c new file mode 100644 index 000000000..96779df6e --- /dev/null +++ b/third_party/ulib/musl/src/linux/cache.c @@ -0,0 +1,16 @@ +#include "libc.h" +#include "syscall.h" + +#ifdef SYS_cacheflush +int _flush_cache(void* addr, int len, int op) { + return syscall(SYS_cacheflush, addr, len, op); +} +weak_alias(_flush_cache, cacheflush); +#endif + +#ifdef SYS_cachectl +int __cachectl(void* addr, int len, int op) { + return syscall(SYS_cachectl, addr, len, op); +} +weak_alias(__cachectl, cachectl); +#endif diff --git a/third_party/ulib/musl/src/linux/chroot.c b/third_party/ulib/musl/src/linux/chroot.c new file mode 100644 index 000000000..af249a8bf --- /dev/null +++ b/third_party/ulib/musl/src/linux/chroot.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int chroot(const char* path) { + return syscall(SYS_chroot, path); +} diff --git a/third_party/ulib/musl/src/linux/flock.c b/third_party/ulib/musl/src/linux/flock.c new file mode 100644 index 000000000..580ca7197 --- /dev/null +++ b/third_party/ulib/musl/src/linux/flock.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int flock(int fd, int op) { + return syscall(SYS_flock, fd, op); +} diff --git a/third_party/ulib/musl/src/linux/prctl.c b/third_party/ulib/musl/src/linux/prctl.c new file mode 100644 index 000000000..2401831ea --- /dev/null +++ b/third_party/ulib/musl/src/linux/prctl.c @@ -0,0 +1,14 @@ +#include "syscall.h" +#include +#include + +int prctl(int op, ...) { + unsigned long x[4]; + int i; + va_list ap; + va_start(ap, op); + for (i = 0; i < 4; i++) + x[i] = va_arg(ap, unsigned long); + va_end(ap); + return syscall(SYS_prctl, op, x[0], x[1], x[2], x[3]); +} diff --git a/third_party/ulib/musl/src/linux/ptrace.c b/third_party/ulib/musl/src/linux/ptrace.c new file mode 100644 index 000000000..80954f08d --- /dev/null +++ b/third_party/ulib/musl/src/linux/ptrace.c @@ -0,0 +1,24 @@ +#include "syscall.h" +#include +#include +#include + +long ptrace(int req, ...) { + va_list ap; + pid_t pid; + void *addr, *data, *addr2; + long ret, result; + + va_start(ap, req); + pid = va_arg(ap, pid_t); + addr = va_arg(ap, void*); + data = va_arg(ap, void*); + addr2 = va_arg(ap, void*); + va_end(ap); + + if (req - 1U < 3) data = &result; + ret = syscall(SYS_ptrace, req, pid, addr, data, addr2); + + if (ret < 0 || req - 1U >= 3) return ret; + return result; +} diff --git a/third_party/ulib/musl/src/linux/quotactl.c b/third_party/ulib/musl/src/linux/quotactl.c new file mode 100644 index 000000000..30bdb17be --- /dev/null +++ b/third_party/ulib/musl/src/linux/quotactl.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int quotactl(int cmd, const char* special, int id, char* addr) { + return syscall(SYS_quotactl, cmd, special, id, addr); +} diff --git a/third_party/ulib/musl/src/linux/sbrk.c b/third_party/ulib/musl/src/linux/sbrk.c new file mode 100644 index 000000000..421c40d71 --- /dev/null +++ b/third_party/ulib/musl/src/linux/sbrk.c @@ -0,0 +1,8 @@ +#include "syscall.h" +#include +#include + +void* sbrk(intptr_t inc) { + if (inc) return (void*)__syscall_ret(-ENOMEM); + return (void*)__syscall(SYS_brk, 0); +} diff --git a/third_party/ulib/musl/src/linux/setgroups.c b/third_party/ulib/musl/src/linux/setgroups.c new file mode 100644 index 000000000..930978e7d --- /dev/null +++ b/third_party/ulib/musl/src/linux/setgroups.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int setgroups(size_t count, const gid_t list[]) { + return syscall(SYS_setgroups, count, list); +} diff --git a/third_party/ulib/musl/src/linux/sethostname.c b/third_party/ulib/musl/src/linux/sethostname.c new file mode 100644 index 000000000..3fae04832 --- /dev/null +++ b/third_party/ulib/musl/src/linux/sethostname.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int sethostname(const char* name, size_t len) { + return syscall(SYS_sethostname, name, len); +} diff --git a/third_party/ulib/musl/src/linux/settimeofday.c b/third_party/ulib/musl/src/linux/settimeofday.c new file mode 100644 index 000000000..84a672415 --- /dev/null +++ b/third_party/ulib/musl/src/linux/settimeofday.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include "syscall.h" +#include + +int settimeofday(const struct timeval* tv, const struct timezone* tz) { + return syscall(SYS_settimeofday, tv, 0); +} diff --git a/third_party/ulib/musl/src/linux/stime.c b/third_party/ulib/musl/src/linux/stime.c new file mode 100644 index 000000000..7436e8c32 --- /dev/null +++ b/third_party/ulib/musl/src/linux/stime.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include +#include + +int stime(const time_t* t) { + struct timeval tv = {.tv_sec = *t, .tv_usec = 0}; + return settimeofday(&tv, (void*)0); +} diff --git a/third_party/ulib/musl/src/linux/utimes.c b/third_party/ulib/musl/src/linux/utimes.c new file mode 100644 index 000000000..62ac50faa --- /dev/null +++ b/third_party/ulib/musl/src/linux/utimes.c @@ -0,0 +1,9 @@ +#include "fcntl.h" +#include "syscall.h" +#include + +int __futimesat(int, const char*, const struct timeval[2]); + +int utimes(const char* path, const struct timeval times[2]) { + return __futimesat(AT_FDCWD, path, times); +} diff --git a/third_party/ulib/musl/src/linux/wait3.c b/third_party/ulib/musl/src/linux/wait3.c new file mode 100644 index 000000000..664ea563a --- /dev/null +++ b/third_party/ulib/musl/src/linux/wait3.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include + +pid_t wait3(int* status, int options, struct rusage* usage) { + return wait4(-1, status, options, usage); +} diff --git a/third_party/ulib/musl/src/linux/wait4.c b/third_party/ulib/musl/src/linux/wait4.c new file mode 100644 index 000000000..e3b5c7a41 --- /dev/null +++ b/third_party/ulib/musl/src/linux/wait4.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include + +pid_t wait4(pid_t pid, int* status, int options, struct rusage* usage) { + return syscall(SYS_wait4, pid, status, options, usage); +} diff --git a/third_party/ulib/musl/src/locale/BUILD.gn b/third_party/ulib/musl/src/locale/BUILD.gn new file mode 100644 index 000000000..cb859d61d --- /dev/null +++ b/third_party/ulib/musl/src/locale/BUILD.gn @@ -0,0 +1,32 @@ +source_set("locale") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__lctrans.c", + "__mo_lookup.c", + "bind_textdomain_codeset.c", + "c_locale.c", + "catclose.c", + "catgets.c", + "catopen.c", + "dcngettext.c", + "duplocale.c", + "freelocale.c", + "iconv.c", + "langinfo.c", + "locale_map.c", + "localeconv.c", + "newlocale.c", + "pleval.c", + "setlocale.c", + "strcoll.c", + "strfmon.c", + "strxfrm.c", + "textdomain.c", + "uselocale.c", + "wcscoll.c", + "wcsxfrm.c", + ] +} diff --git a/third_party/ulib/musl/src/locale/__lctrans.c b/third_party/ulib/musl/src/locale/__lctrans.c new file mode 100644 index 000000000..4995cb964 --- /dev/null +++ b/third_party/ulib/musl/src/locale/__lctrans.c @@ -0,0 +1,17 @@ +#include "libc.h" +#include "locale_impl.h" +#include + +static const char* dummy(const char* msg, const struct __locale_map* lm) { + return msg; +} + +weak_alias(dummy, __lctrans_impl); + +const char* __lctrans(const char* msg, const struct __locale_map* lm) { + return __lctrans_impl(msg, lm); +} + +const char* __lctrans_cur(const char* msg) { + return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES]); +} diff --git a/third_party/ulib/musl/src/locale/__mo_lookup.c b/third_party/ulib/musl/src/locale/__mo_lookup.c new file mode 100644 index 000000000..5ea68fa5d --- /dev/null +++ b/third_party/ulib/musl/src/locale/__mo_lookup.c @@ -0,0 +1,37 @@ +#include +#include + +static inline uint32_t swapc(uint32_t x, int c) { + return c ? x >> 24 | x >> 8 & 0xff00 | x << 8 & 0xff0000 | x << 24 : x; +} + +const char* __mo_lookup(const void* p, size_t size, const char* s) { + const uint32_t* mo = p; + int sw = *mo - 0x950412de; + uint32_t b = 0, n = swapc(mo[2], sw); + uint32_t o = swapc(mo[3], sw); + uint32_t t = swapc(mo[4], sw); + if (n >= size / 4 || o >= size - 4 * n || t >= size - 4 * n || ((o | t) % 4)) return 0; + o /= 4; + t /= 4; + for (;;) { + uint32_t ol = swapc(mo[o + 2 * (b + n / 2)], sw); + uint32_t os = swapc(mo[o + 2 * (b + n / 2) + 1], sw); + if (os >= size || ol >= size - os || ((char*)p)[os + ol]) return 0; + int sign = strcmp(s, (char*)p + os); + if (!sign) { + uint32_t tl = swapc(mo[t + 2 * (b + n / 2)], sw); + uint32_t ts = swapc(mo[t + 2 * (b + n / 2) + 1], sw); + if (ts >= size || tl >= size - ts || ((char*)p)[ts + tl]) return 0; + return (char*)p + ts; + } else if (n == 1) + return 0; + else if (sign < 0) + n /= 2; + else { + b += n / 2; + n -= n / 2; + } + } + return 0; +} diff --git a/third_party/ulib/musl/src/locale/big5.h b/third_party/ulib/musl/src/locale/big5.h new file mode 100644 index 000000000..768b326b7 --- /dev/null +++ b/third_party/ulib/musl/src/locale/big5.h @@ -0,0 +1,1066 @@ +12288, 65292, 12289, 12290, 65294, 8231, 65307, 65306, 65311, 65281, 65072, 8230, 8229, 65104, + 65105, 65106, 183, 65108, 65109, 65110, 65111, 65372, 8211, 65073, 8212, 65075, 9588, 65076, + 65103, 65288, 65289, 65077, 65078, 65371, 65373, 65079, 65080, 12308, 12309, 65081, 65082, + 12304, 12305, 65083, 65084, 12298, 12299, 65085, 65086, 12296, 12297, 65087, 65088, 12300, + 12301, 65089, 65090, 12302, 12303, 65091, 65092, 65113, 65114, 65115, 65116, 65117, 65118, 8216, + 8217, 8220, 8221, 12317, 12318, 8245, 8242, 65283, 65286, 65290, 8251, 167, 12291, 9675, 9679, + 9651, 9650, 9678, 9734, 9733, 9671, 9670, 9633, 9632, 9661, 9660, 12963, 8453, 175, 65507, + 65343, 717, 65097, 65098, 65101, 65102, 65099, 65100, 65119, 65120, 65121, 65291, 65293, 215, + 247, 177, 8730, 65308, 65310, 65309, 8806, 8807, 8800, 8734, 8786, 8801, 65122, 65123, 65124, + 65125, 65126, 65374, 8745, 8746, 8869, 8736, 8735, 8895, 13266, 13265, 8747, 8750, 8757, 8756, + 9792, 9794, 8853, 8857, 8593, 8595, 8592, 8594, 8598, 8599, 8601, 8600, 8741, 8739, 65295, + 65340, 8725, 65128, 65284, 65509, 12306, 65504, 65505, 65285, 65312, 8451, 8457, 65129, 65130, + 65131, 13269, 13212, 13213, 13214, 13262, 13217, 13198, 13199, 13252, 176, 20825, 20827, 20830, + 20829, 20833, 20835, 21991, 29929, 31950, 9601, 9602, 9603, 9604, 9605, 9606, 9607, 9608, 9615, + 9614, 9613, 9612, 9611, 9610, 9609, 9532, 9524, 9516, 9508, 9500, 9620, 9472, 9474, 9621, 9484, + 9488, 9492, 9496, 9581, 9582, 9584, 9583, 9552, 9566, 9578, 9569, 9698, 9699, 9701, 9700, 9585, + 9586, 9587, 65296, 65297, 65298, 65299, 65300, 65301, 65302, 65303, 65304, 65305, 8544, 8545, + 8546, 8547, 8548, 8549, 8550, 8551, 8552, 8553, 12321, 12322, 12323, 12324, 12325, 12326, 12327, + 12328, 12329, 21313, 21316, 21317, 65313, 65314, 65315, 65316, 65317, 65318, 65319, 65320, + 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, 65333, + 65334, 65335, 65336, 65337, 65338, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, + 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360, 65361, 65362, 65363, 65364, 65365, + 65366, 65367, 65368, 65369, 65370, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, + 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 945, 946, 947, 948, 949, 950, 951, + 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967, 968, 969, 12549, + 12550, 12551, 12552, 12553, 12554, 12555, 12556, 12557, 12558, 12559, 12560, 12561, 12562, + 12563, 12564, 12565, 12566, 12567, 12568, 12569, 12570, 12571, 12572, 12573, 12574, 12575, + 12576, 12577, 12578, 12579, 12580, 12581, 12582, 12583, 12584, 12585, 729, 713, 714, 711, 715, + 9216, 9217, 9218, 9219, 9220, 9221, 9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229, 9230, 9231, + 9232, 9233, 9234, 9235, 9236, 9237, 9238, 9239, 9240, 9241, 9242, 9243, 9244, 9245, 9246, 9247, + 9249, 8364, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19968, 20057, 19969, 19971, 20035, 20061, 20102, 20108, 20154, 20799, 20837, 20843, 20960, + 20992, 20993, 21147, 21269, 21313, 21340, 21448, 19977, 19979, 19976, 19978, 20011, 20024, + 20961, 20037, 20040, 20063, 20062, 20110, 20129, 20800, 20995, 21242, 21315, 21449, 21475, + 22303, 22763, 22805, 22823, 22899, 23376, 23377, 23379, 23544, 23567, 23586, 23608, 23665, + 24029, 24037, 24049, 24050, 24051, 24062, 24178, 24318, 24331, 24339, 25165, 19985, 19984, + 19981, 20013, 20016, 20025, 20043, 23609, 20104, 20113, 20117, 20114, 20116, 20130, 20161, + 20160, 20163, 20166, 20167, 20173, 20170, 20171, 20164, 20803, 20801, 20839, 20845, 20846, + 20844, 20887, 20982, 20998, 20999, 21000, 21243, 21246, 21247, 21270, 21305, 21320, 21319, + 21317, 21342, 21380, 21451, 21450, 21453, 22764, 22825, 22827, 22826, 22829, 23380, 23569, + 23588, 23610, 23663, 24052, 24187, 24319, 24340, 24341, 24515, 25096, 25142, 25163, 25166, + 25903, 25991, 26007, 26020, 26041, 26085, 26352, 26376, 26408, 27424, 27490, 27513, 27595, + 27604, 27611, 27663, 27700, 28779, 29226, 29238, 29243, 29255, 29273, 29275, 29356, 29579, + 19993, 19990, 19989, 19988, 19992, 20027, 20045, 20047, 20046, 20197, 20184, 20180, 20181, + 20182, 20183, 20195, 20196, 20185, 20190, 20805, 20804, 20873, 20874, 20908, 20985, 20986, + 20984, 21002, 21152, 21151, 21253, 21254, 21271, 21277, 20191, 21322, 21321, 21345, 21344, + 21359, 21358, 21435, 21487, 21476, 21491, 21484, 21486, 21481, 21480, 21500, 21496, 21493, + 21483, 21478, 21482, 21490, 21489, 21488, 21477, 21485, 21499, 22235, 22234, 22806, 22830, + 22833, 22900, 22902, 23381, 23427, 23612, 24040, 24039, 24038, 24066, 24067, 24179, 24188, + 24321, 24344, 24343, 24517, 25098, 25171, 25172, 25170, 25169, 26021, 26086, 26414, 26412, + 26410, 26411, 26413, 27491, 27597, 27665, 27664, 27704, 27713, 27712, 27710, 29359, 29572, + 29577, 29916, 29926, 29976, 29983, 29992, 29993, 30000, 30001, 30002, 30003, 30091, 30333, + 30382, 30399, 30446, 30683, 30690, 30707, 31034, 31166, 31348, 31435, 19998, 19999, 20050, + 20051, 20073, 20121, 20132, 20134, 20133, 20223, 20233, 20249, 20234, 20245, 20237, 20240, + 20241, 20239, 20210, 20214, 20219, 20208, 20211, 20221, 20225, 20235, 20809, 20807, 20806, + 20808, 20840, 20849, 20877, 20912, 21015, 21009, 21010, 21006, 21014, 21155, 21256, 21281, + 21280, 21360, 21361, 21513, 21519, 21516, 21514, 21520, 21505, 21515, 21508, 21521, 21517, + 21512, 21507, 21518, 21510, 21522, 22240, 22238, 22237, 22323, 22320, 22312, 22317, 22316, + 22319, 22313, 22809, 22810, 22839, 22840, 22916, 22904, 22915, 22909, 22905, 22914, 22913, + 23383, 23384, 23431, 23432, 23429, 23433, 23546, 23574, 23673, 24030, 24070, 24182, 24180, + 24335, 24347, 24537, 24534, 25102, 25100, 25101, 25104, 25187, 25179, 25176, 25910, 26089, + 26088, 26092, 26093, 26354, 26355, 26377, 26429, 26420, 26417, 26421, 27425, 27492, 27515, + 27670, 27741, 27735, 27737, 27743, 27744, 27728, 27733, 27745, 27739, 27725, 27726, 28784, + 29279, 29277, 30334, 31481, 31859, 31992, 32566, 32650, 32701, 32769, 32771, 32780, 32786, + 32819, 32895, 32905, 32907, 32908, 33251, 33258, 33267, 33276, 33292, 33307, 33311, 33390, + 33394, 33406, 34411, 34880, 34892, 34915, 35199, 38433, 20018, 20136, 20301, 20303, 20295, + 20311, 20318, 20276, 20315, 20309, 20272, 20304, 20305, 20285, 20282, 20280, 20291, 20308, + 20284, 20294, 20323, 20316, 20320, 20271, 20302, 20278, 20313, 20317, 20296, 20314, 20812, + 20811, 20813, 20853, 20918, 20919, 21029, 21028, 21033, 21034, 21032, 21163, 21161, 21162, + 21164, 21283, 21363, 21365, 21533, 21549, 21534, 21566, 21542, 21582, 21543, 21574, 21571, + 21555, 21576, 21570, 21531, 21545, 21578, 21561, 21563, 21560, 21550, 21557, 21558, 21536, + 21564, 21568, 21553, 21547, 21535, 21548, 22250, 22256, 22244, 22251, 22346, 22353, 22336, + 22349, 22343, 22350, 22334, 22352, 22351, 22331, 22767, 22846, 22941, 22930, 22952, 22942, + 22947, 22937, 22934, 22925, 22948, 22931, 22922, 22949, 23389, 23388, 23386, 23387, 23436, + 23435, 23439, 23596, 23616, 23617, 23615, 23614, 23696, 23697, 23700, 23692, 24043, 24076, + 24207, 24199, 24202, 24311, 24324, 24351, 24420, 24418, 24439, 24441, 24536, 24524, 24535, + 24525, 24561, 24555, 24568, 24554, 25106, 25105, 25220, 25239, 25238, 25216, 25206, 25225, + 25197, 25226, 25212, 25214, 25209, 25203, 25234, 25199, 25240, 25198, 25237, 25235, 25233, + 25222, 25913, 25915, 25912, 26097, 26356, 26463, 26446, 26447, 26448, 26449, 26460, 26454, + 26462, 26441, 26438, 26464, 26451, 26455, 27493, 27599, 27714, 27742, 27801, 27777, 27784, + 27785, 27781, 27803, 27754, 27770, 27792, 27760, 27788, 27752, 27798, 27794, 27773, 27779, + 27762, 27774, 27764, 27782, 27766, 27789, 27796, 27800, 27778, 28790, 28796, 28797, 28792, + 29282, 29281, 29280, 29380, 29378, 29590, 29996, 29995, 30007, 30008, 30338, 30447, 30691, + 31169, 31168, 31167, 31350, 31995, 32597, 32918, 32915, 32925, 32920, 32923, 32922, 32946, + 33391, 33426, 33419, 33421, 35211, 35282, 35328, 35895, 35910, 35925, 35997, 36196, 36208, + 36275, 36523, 36554, 36763, 36784, 36802, 36806, 36805, 36804, 24033, 37009, 37026, 37034, + 37030, 37027, 37193, 37318, 37324, 38450, 38446, 38449, 38442, 38444, 20006, 20054, 20083, + 20107, 20123, 20126, 20139, 20140, 20335, 20381, 20365, 20339, 20351, 20332, 20379, 20363, + 20358, 20355, 20336, 20341, 20360, 20329, 20347, 20374, 20350, 20367, 20369, 20346, 20820, + 20818, 20821, 20841, 20855, 20854, 20856, 20925, 20989, 21051, 21048, 21047, 21050, 21040, + 21038, 21046, 21057, 21182, 21179, 21330, 21332, 21331, 21329, 21350, 21367, 21368, 21369, + 21462, 21460, 21463, 21619, 21621, 21654, 21624, 21653, 21632, 21627, 21623, 21636, 21650, + 21638, 21628, 21648, 21617, 21622, 21644, 21658, 21602, 21608, 21643, 21629, 21646, 22266, + 22403, 22391, 22378, 22377, 22369, 22374, 22372, 22396, 22812, 22857, 22855, 22856, 22852, + 22868, 22974, 22971, 22996, 22969, 22958, 22993, 22982, 22992, 22989, 22987, 22995, 22986, + 22959, 22963, 22994, 22981, 23391, 23396, 23395, 23447, 23450, 23448, 23452, 23449, 23451, + 23578, 23624, 23621, 23622, 23735, 23713, 23736, 23721, 23723, 23729, 23731, 24088, 24090, + 24086, 24085, 24091, 24081, 24184, 24218, 24215, 24220, 24213, 24214, 24310, 24358, 24359, + 24361, 24448, 24449, 24447, 24444, 24541, 24544, 24573, 24565, 24575, 24591, 24596, 24623, + 24629, 24598, 24618, 24597, 24609, 24615, 24617, 24619, 24603, 25110, 25109, 25151, 25150, + 25152, 25215, 25289, 25292, 25284, 25279, 25282, 25273, 25298, 25307, 25259, 25299, 25300, + 25291, 25288, 25256, 25277, 25276, 25296, 25305, 25287, 25293, 25269, 25306, 25265, 25304, + 25302, 25303, 25286, 25260, 25294, 25918, 26023, 26044, 26106, 26132, 26131, 26124, 26118, + 26114, 26126, 26112, 26127, 26133, 26122, 26119, 26381, 26379, 26477, 26507, 26517, 26481, + 26524, 26483, 26487, 26503, 26525, 26519, 26479, 26480, 26495, 26505, 26494, 26512, 26485, + 26522, 26515, 26492, 26474, 26482, 27427, 27494, 27495, 27519, 27667, 27675, 27875, 27880, + 27891, 27825, 27852, 27877, 27827, 27837, 27838, 27836, 27874, 27819, 27861, 27859, 27832, + 27844, 27833, 27841, 27822, 27863, 27845, 27889, 27839, 27835, 27873, 27867, 27850, 27820, + 27887, 27868, 27862, 27872, 28821, 28814, 28818, 28810, 28825, 29228, 29229, 29240, 29256, + 29287, 29289, 29376, 29390, 29401, 29399, 29392, 29609, 29608, 29599, 29611, 29605, 30013, + 30109, 30105, 30106, 30340, 30402, 30450, 30452, 30693, 30717, 31038, 31040, 31041, 31177, + 31176, 31354, 31353, 31482, 31998, 32596, 32652, 32651, 32773, 32954, 32933, 32930, 32945, + 32929, 32939, 32937, 32948, 32938, 32943, 33253, 33278, 33293, 33459, 33437, 33433, 33453, + 33469, 33439, 33465, 33457, 33452, 33445, 33455, 33464, 33443, 33456, 33470, 33463, 34382, + 34417, 21021, 34920, 36555, 36814, 36820, 36817, 37045, 37048, 37041, 37046, 37319, 37329, + 38263, 38272, 38428, 38464, 38463, 38459, 38468, 38466, 38585, 38632, 38738, 38750, 20127, + 20141, 20142, 20449, 20405, 20399, 20415, 20448, 20433, 20431, 20445, 20419, 20406, 20440, + 20447, 20426, 20439, 20398, 20432, 20420, 20418, 20442, 20430, 20446, 20407, 20823, 20882, + 20881, 20896, 21070, 21059, 21066, 21069, 21068, 21067, 21063, 21191, 21193, 21187, 21185, + 21261, 21335, 21371, 21402, 21467, 21676, 21696, 21672, 21710, 21705, 21688, 21670, 21683, + 21703, 21698, 21693, 21674, 21697, 21700, 21704, 21679, 21675, 21681, 21691, 21673, 21671, + 21695, 22271, 22402, 22411, 22432, 22435, 22434, 22478, 22446, 22419, 22869, 22865, 22863, + 22862, 22864, 23004, 23000, 23039, 23011, 23016, 23043, 23013, 23018, 23002, 23014, 23041, + 23035, 23401, 23459, 23462, 23460, 23458, 23461, 23553, 23630, 23631, 23629, 23627, 23769, + 23762, 24055, 24093, 24101, 24095, 24189, 24224, 24230, 24314, 24328, 24365, 24421, 24456, + 24453, 24458, 24459, 24455, 24460, 24457, 24594, 24605, 24608, 24613, 24590, 24616, 24653, + 24688, 24680, 24674, 24646, 24643, 24684, 24683, 24682, 24676, 25153, 25308, 25366, 25353, + 25340, 25325, 25345, 25326, 25341, 25351, 25329, 25335, 25327, 25324, 25342, 25332, 25361, + 25346, 25919, 25925, 26027, 26045, 26082, 26149, 26157, 26144, 26151, 26159, 26143, 26152, + 26161, 26148, 26359, 26623, 26579, 26609, 26580, 26576, 26604, 26550, 26543, 26613, 26601, + 26607, 26564, 26577, 26548, 26586, 26597, 26552, 26575, 26590, 26611, 26544, 26585, 26594, + 26589, 26578, 27498, 27523, 27526, 27573, 27602, 27607, 27679, 27849, 27915, 27954, 27946, + 27969, 27941, 27916, 27953, 27934, 27927, 27963, 27965, 27966, 27958, 27931, 27893, 27961, + 27943, 27960, 27945, 27950, 27957, 27918, 27947, 28843, 28858, 28851, 28844, 28847, 28845, + 28856, 28846, 28836, 29232, 29298, 29295, 29300, 29417, 29408, 29409, 29623, 29642, 29627, + 29618, 29645, 29632, 29619, 29978, 29997, 30031, 30028, 30030, 30027, 30123, 30116, 30117, + 30114, 30115, 30328, 30342, 30343, 30344, 30408, 30406, 30403, 30405, 30465, 30457, 30456, + 30473, 30475, 30462, 30460, 30471, 30684, 30722, 30740, 30732, 30733, 31046, 31049, 31048, + 31047, 31161, 31162, 31185, 31186, 31179, 31359, 31361, 31487, 31485, 31869, 32002, 32005, + 32000, 32009, 32007, 32004, 32006, 32568, 32654, 32703, 32772, 32784, 32781, 32785, 32822, + 32982, 32997, 32986, 32963, 32964, 32972, 32993, 32987, 32974, 32990, 32996, 32989, 33268, + 33314, 33511, 33539, 33541, 33507, 33499, 33510, 33540, 33509, 33538, 33545, 33490, 33495, + 33521, 33537, 33500, 33492, 33489, 33502, 33491, 33503, 33519, 33542, 34384, 34425, 34427, + 34426, 34893, 34923, 35201, 35284, 35336, 35330, 35331, 35998, 36000, 36212, 36211, 36276, + 36557, 36556, 36848, 36838, 36834, 36842, 36837, 36845, 36843, 36836, 36840, 37066, 37070, + 37057, 37059, 37195, 37194, 37325, 38274, 38480, 38475, 38476, 38477, 38754, 38761, 38859, + 38893, 38899, 38913, 39080, 39131, 39135, 39318, 39321, 20056, 20147, 20492, 20493, 20515, + 20463, 20518, 20517, 20472, 20521, 20502, 20486, 20540, 20511, 20506, 20498, 20497, 20474, + 20480, 20500, 20520, 20465, 20513, 20491, 20505, 20504, 20467, 20462, 20525, 20522, 20478, + 20523, 20489, 20860, 20900, 20901, 20898, 20941, 20940, 20934, 20939, 21078, 21084, 21076, + 21083, 21085, 21290, 21375, 21407, 21405, 21471, 21736, 21776, 21761, 21815, 21756, 21733, + 21746, 21766, 21754, 21780, 21737, 21741, 21729, 21769, 21742, 21738, 21734, 21799, 21767, + 21757, 21775, 22275, 22276, 22466, 22484, 22475, 22467, 22537, 22799, 22871, 22872, 22874, + 23057, 23064, 23068, 23071, 23067, 23059, 23020, 23072, 23075, 23081, 23077, 23052, 23049, + 23403, 23640, 23472, 23475, 23478, 23476, 23470, 23477, 23481, 23480, 23556, 23633, 23637, + 23632, 23789, 23805, 23803, 23786, 23784, 23792, 23798, 23809, 23796, 24046, 24109, 24107, + 24235, 24237, 24231, 24369, 24466, 24465, 24464, 24665, 24675, 24677, 24656, 24661, 24685, + 24681, 24687, 24708, 24735, 24730, 24717, 24724, 24716, 24709, 24726, 25159, 25331, 25352, + 25343, 25422, 25406, 25391, 25429, 25410, 25414, 25423, 25417, 25402, 25424, 25405, 25386, + 25387, 25384, 25421, 25420, 25928, 25929, 26009, 26049, 26053, 26178, 26185, 26191, 26179, + 26194, 26188, 26181, 26177, 26360, 26388, 26389, 26391, 26657, 26680, 26696, 26694, 26707, + 26681, 26690, 26708, 26665, 26803, 26647, 26700, 26705, 26685, 26612, 26704, 26688, 26684, + 26691, 26666, 26693, 26643, 26648, 26689, 27530, 27529, 27575, 27683, 27687, 27688, 27686, + 27684, 27888, 28010, 28053, 28040, 28039, 28006, 28024, 28023, 27993, 28051, 28012, 28041, + 28014, 27994, 28020, 28009, 28044, 28042, 28025, 28037, 28005, 28052, 28874, 28888, 28900, + 28889, 28872, 28879, 29241, 29305, 29436, 29433, 29437, 29432, 29431, 29574, 29677, 29705, + 29678, 29664, 29674, 29662, 30036, 30045, 30044, 30042, 30041, 30142, 30149, 30151, 30130, + 30131, 30141, 30140, 30137, 30146, 30136, 30347, 30384, 30410, 30413, 30414, 30505, 30495, + 30496, 30504, 30697, 30768, 30759, 30776, 30749, 30772, 30775, 30757, 30765, 30752, 30751, + 30770, 31061, 31056, 31072, 31071, 31062, 31070, 31069, 31063, 31066, 31204, 31203, 31207, + 31199, 31206, 31209, 31192, 31364, 31368, 31449, 31494, 31505, 31881, 32033, 32023, 32011, + 32010, 32032, 32034, 32020, 32016, 32021, 32026, 32028, 32013, 32025, 32027, 32570, 32607, + 32660, 32709, 32705, 32774, 32792, 32789, 32793, 32791, 32829, 32831, 33009, 33026, 33008, + 33029, 33005, 33012, 33030, 33016, 33011, 33032, 33021, 33034, 33020, 33007, 33261, 33260, + 33280, 33296, 33322, 33323, 33320, 33324, 33467, 33579, 33618, 33620, 33610, 33592, 33616, + 33609, 33589, 33588, 33615, 33586, 33593, 33590, 33559, 33600, 33585, 33576, 33603, 34388, + 34442, 34474, 34451, 34468, 34473, 34444, 34467, 34460, 34928, 34935, 34945, 34946, 34941, + 34937, 35352, 35344, 35342, 35340, 35349, 35338, 35351, 35347, 35350, 35343, 35345, 35912, + 35962, 35961, 36001, 36002, 36215, 36524, 36562, 36564, 36559, 36785, 36865, 36870, 36855, + 36864, 36858, 36852, 36867, 36861, 36869, 36856, 37013, 37089, 37085, 37090, 37202, 37197, + 37196, 37336, 37341, 37335, 37340, 37337, 38275, 38498, 38499, 38497, 38491, 38493, 38500, + 38488, 38494, 38587, 39138, 39340, 39592, 39640, 39717, 39730, 39740, 20094, 20602, 20605, + 20572, 20551, 20547, 20556, 20570, 20553, 20581, 20598, 20558, 20565, 20597, 20596, 20599, + 20559, 20495, 20591, 20589, 20828, 20885, 20976, 21098, 21103, 21202, 21209, 21208, 21205, + 21264, 21263, 21273, 21311, 21312, 21310, 21443, 26364, 21830, 21866, 21862, 21828, 21854, + 21857, 21827, 21834, 21809, 21846, 21839, 21845, 21807, 21860, 21816, 21806, 21852, 21804, + 21859, 21811, 21825, 21847, 22280, 22283, 22281, 22495, 22533, 22538, 22534, 22496, 22500, + 22522, 22530, 22581, 22519, 22521, 22816, 22882, 23094, 23105, 23113, 23142, 23146, 23104, + 23100, 23138, 23130, 23110, 23114, 23408, 23495, 23493, 23492, 23490, 23487, 23494, 23561, + 23560, 23559, 23648, 23644, 23645, 23815, 23814, 23822, 23835, 23830, 23842, 23825, 23849, + 23828, 23833, 23844, 23847, 23831, 24034, 24120, 24118, 24115, 24119, 24247, 24248, 24246, + 24245, 24254, 24373, 24375, 24407, 24428, 24425, 24427, 24471, 24473, 24478, 24472, 24481, + 24480, 24476, 24703, 24739, 24713, 24736, 24744, 24779, 24756, 24806, 24765, 24773, 24763, + 24757, 24796, 24764, 24792, 24789, 24774, 24799, 24760, 24794, 24775, 25114, 25115, 25160, + 25504, 25511, 25458, 25494, 25506, 25509, 25463, 25447, 25496, 25514, 25457, 25513, 25481, + 25475, 25499, 25451, 25512, 25476, 25480, 25497, 25505, 25516, 25490, 25487, 25472, 25467, + 25449, 25448, 25466, 25949, 25942, 25937, 25945, 25943, 21855, 25935, 25944, 25941, 25940, + 26012, 26011, 26028, 26063, 26059, 26060, 26062, 26205, 26202, 26212, 26216, 26214, 26206, + 26361, 21207, 26395, 26753, 26799, 26786, 26771, 26805, 26751, 26742, 26801, 26791, 26775, + 26800, 26755, 26820, 26797, 26758, 26757, 26772, 26781, 26792, 26783, 26785, 26754, 27442, + 27578, 27627, 27628, 27691, 28046, 28092, 28147, 28121, 28082, 28129, 28108, 28132, 28155, + 28154, 28165, 28103, 28107, 28079, 28113, 28078, 28126, 28153, 28088, 28151, 28149, 28101, + 28114, 28186, 28085, 28122, 28139, 28120, 28138, 28145, 28142, 28136, 28102, 28100, 28074, + 28140, 28095, 28134, 28921, 28937, 28938, 28925, 28911, 29245, 29309, 29313, 29468, 29467, + 29462, 29459, 29465, 29575, 29701, 29706, 29699, 29702, 29694, 29709, 29920, 29942, 29943, + 29980, 29986, 30053, 30054, 30050, 30064, 30095, 30164, 30165, 30133, 30154, 30157, 30350, + 30420, 30418, 30427, 30519, 30526, 30524, 30518, 30520, 30522, 30827, 30787, 30798, 31077, + 31080, 31085, 31227, 31378, 31381, 31520, 31528, 31515, 31532, 31526, 31513, 31518, 31534, + 31890, 31895, 31893, 32070, 32067, 32113, 32046, 32057, 32060, 32064, 32048, 32051, 32068, + 32047, 32066, 32050, 32049, 32573, 32670, 32666, 32716, 32718, 32722, 32796, 32842, 32838, + 33071, 33046, 33059, 33067, 33065, 33072, 33060, 33282, 33333, 33335, 33334, 33337, 33678, + 33694, 33688, 33656, 33698, 33686, 33725, 33707, 33682, 33674, 33683, 33673, 33696, 33655, + 33659, 33660, 33670, 33703, 34389, 24426, 34503, 34496, 34486, 34500, 34485, 34502, 34507, + 34481, 34479, 34505, 34899, 34974, 34952, 34987, 34962, 34966, 34957, 34955, 35219, 35215, + 35370, 35357, 35363, 35365, 35377, 35373, 35359, 35355, 35362, 35913, 35930, 36009, 36012, + 36011, 36008, 36010, 36007, 36199, 36198, 36286, 36282, 36571, 36575, 36889, 36877, 36890, + 36887, 36899, 36895, 36893, 36880, 36885, 36894, 36896, 36879, 36898, 36886, 36891, 36884, + 37096, 37101, 37117, 37207, 37326, 37365, 37350, 37347, 37351, 37357, 37353, 38281, 38506, + 38517, 38515, 38520, 38512, 38516, 38518, 38519, 38508, 38592, 38634, 38633, 31456, 31455, + 38914, 38915, 39770, 40165, 40565, 40575, 40613, 40635, 20642, 20621, 20613, 20633, 20625, + 20608, 20630, 20632, 20634, 26368, 20977, 21106, 21108, 21109, 21097, 21214, 21213, 21211, + 21338, 21413, 21883, 21888, 21927, 21884, 21898, 21917, 21912, 21890, 21916, 21930, 21908, + 21895, 21899, 21891, 21939, 21934, 21919, 21822, 21938, 21914, 21947, 21932, 21937, 21886, + 21897, 21931, 21913, 22285, 22575, 22570, 22580, 22564, 22576, 22577, 22561, 22557, 22560, + 22777, 22778, 22880, 23159, 23194, 23167, 23186, 23195, 23207, 23411, 23409, 23506, 23500, + 23507, 23504, 23562, 23563, 23601, 23884, 23888, 23860, 23879, 24061, 24133, 24125, 24128, + 24131, 24190, 24266, 24257, 24258, 24260, 24380, 24429, 24489, 24490, 24488, 24785, 24801, + 24754, 24758, 24800, 24860, 24867, 24826, 24853, 24816, 24827, 24820, 24936, 24817, 24846, + 24822, 24841, 24832, 24850, 25119, 25161, 25507, 25484, 25551, 25536, 25577, 25545, 25542, + 25549, 25554, 25571, 25552, 25569, 25558, 25581, 25582, 25462, 25588, 25578, 25563, 25682, + 25562, 25593, 25950, 25958, 25954, 25955, 26001, 26000, 26031, 26222, 26224, 26228, 26230, + 26223, 26257, 26234, 26238, 26231, 26366, 26367, 26399, 26397, 26874, 26837, 26848, 26840, + 26839, 26885, 26847, 26869, 26862, 26855, 26873, 26834, 26866, 26851, 26827, 26829, 26893, + 26898, 26894, 26825, 26842, 26990, 26875, 27454, 27450, 27453, 27544, 27542, 27580, 27631, + 27694, 27695, 27692, 28207, 28216, 28244, 28193, 28210, 28263, 28234, 28192, 28197, 28195, + 28187, 28251, 28248, 28196, 28246, 28270, 28205, 28198, 28271, 28212, 28237, 28218, 28204, + 28227, 28189, 28222, 28363, 28297, 28185, 28238, 28259, 28228, 28274, 28265, 28255, 28953, + 28954, 28966, 28976, 28961, 28982, 29038, 28956, 29260, 29316, 29312, 29494, 29477, 29492, + 29481, 29754, 29738, 29747, 29730, 29733, 29749, 29750, 29748, 29743, 29723, 29734, 29736, + 29989, 29990, 30059, 30058, 30178, 30171, 30179, 30169, 30168, 30174, 30176, 30331, 30332, + 30358, 30355, 30388, 30428, 30543, 30701, 30813, 30828, 30831, 31245, 31240, 31243, 31237, + 31232, 31384, 31383, 31382, 31461, 31459, 31561, 31574, 31558, 31568, 31570, 31572, 31565, + 31563, 31567, 31569, 31903, 31909, 32094, 32080, 32104, 32085, 32043, 32110, 32114, 32097, + 32102, 32098, 32112, 32115, 21892, 32724, 32725, 32779, 32850, 32901, 33109, 33108, 33099, + 33105, 33102, 33081, 33094, 33086, 33100, 33107, 33140, 33298, 33308, 33769, 33795, 33784, + 33805, 33760, 33733, 33803, 33729, 33775, 33777, 33780, 33879, 33802, 33776, 33804, 33740, + 33789, 33778, 33738, 33848, 33806, 33796, 33756, 33799, 33748, 33759, 34395, 34527, 34521, + 34541, 34516, 34523, 34532, 34512, 34526, 34903, 35009, 35010, 34993, 35203, 35222, 35387, + 35424, 35413, 35422, 35388, 35393, 35412, 35419, 35408, 35398, 35380, 35386, 35382, 35414, + 35937, 35970, 36015, 36028, 36019, 36029, 36033, 36027, 36032, 36020, 36023, 36022, 36031, + 36024, 36234, 36229, 36225, 36302, 36317, 36299, 36314, 36305, 36300, 36315, 36294, 36603, + 36600, 36604, 36764, 36910, 36917, 36913, 36920, 36914, 36918, 37122, 37109, 37129, 37118, + 37219, 37221, 37327, 37396, 37397, 37411, 37385, 37406, 37389, 37392, 37383, 37393, 38292, + 38287, 38283, 38289, 38291, 38290, 38286, 38538, 38542, 38539, 38525, 38533, 38534, 38541, + 38514, 38532, 38593, 38597, 38596, 38598, 38599, 38639, 38642, 38860, 38917, 38918, 38920, + 39143, 39146, 39151, 39145, 39154, 39149, 39342, 39341, 40643, 40653, 40657, 20098, 20653, + 20661, 20658, 20659, 20677, 20670, 20652, 20663, 20667, 20655, 20679, 21119, 21111, 21117, + 21215, 21222, 21220, 21218, 21219, 21295, 21983, 21992, 21971, 21990, 21966, 21980, 21959, + 21969, 21987, 21988, 21999, 21978, 21985, 21957, 21958, 21989, 21961, 22290, 22291, 22622, + 22609, 22616, 22615, 22618, 22612, 22635, 22604, 22637, 22602, 22626, 22610, 22603, 22887, + 23233, 23241, 23244, 23230, 23229, 23228, 23219, 23234, 23218, 23913, 23919, 24140, 24185, + 24265, 24264, 24338, 24409, 24492, 24494, 24858, 24847, 24904, 24863, 24819, 24859, 24825, + 24833, 24840, 24910, 24908, 24900, 24909, 24894, 24884, 24871, 24845, 24838, 24887, 25121, + 25122, 25619, 25662, 25630, 25642, 25645, 25661, 25644, 25615, 25628, 25620, 25613, 25654, + 25622, 25623, 25606, 25964, 26015, 26032, 26263, 26249, 26247, 26248, 26262, 26244, 26264, + 26253, 26371, 27028, 26989, 26970, 26999, 26976, 26964, 26997, 26928, 27010, 26954, 26984, + 26987, 26974, 26963, 27001, 27014, 26973, 26979, 26971, 27463, 27506, 27584, 27583, 27603, + 27645, 28322, 28335, 28371, 28342, 28354, 28304, 28317, 28359, 28357, 28325, 28312, 28348, + 28346, 28331, 28369, 28310, 28316, 28356, 28372, 28330, 28327, 28340, 29006, 29017, 29033, + 29028, 29001, 29031, 29020, 29036, 29030, 29004, 29029, 29022, 28998, 29032, 29014, 29242, + 29266, 29495, 29509, 29503, 29502, 29807, 29786, 29781, 29791, 29790, 29761, 29759, 29785, + 29787, 29788, 30070, 30072, 30208, 30192, 30209, 30194, 30193, 30202, 30207, 30196, 30195, + 30430, 30431, 30555, 30571, 30566, 30558, 30563, 30585, 30570, 30572, 30556, 30565, 30568, + 30562, 30702, 30862, 30896, 30871, 30872, 30860, 30857, 30844, 30865, 30867, 30847, 31098, + 31103, 31105, 33836, 31165, 31260, 31258, 31264, 31252, 31263, 31262, 31391, 31392, 31607, + 31680, 31584, 31598, 31591, 31921, 31923, 31925, 32147, 32121, 32145, 32129, 32143, 32091, + 32622, 32617, 32618, 32626, 32681, 32680, 32676, 32854, 32856, 32902, 32900, 33137, 33136, + 33144, 33125, 33134, 33139, 33131, 33145, 33146, 33126, 33285, 33351, 33922, 33911, 33853, + 33841, 33909, 33894, 33899, 33865, 33900, 33883, 33852, 33845, 33889, 33891, 33897, 33901, + 33862, 34398, 34396, 34399, 34553, 34579, 34568, 34567, 34560, 34558, 34555, 34562, 34563, + 34566, 34570, 34905, 35039, 35028, 35033, 35036, 35032, 35037, 35041, 35018, 35029, 35026, + 35228, 35299, 35435, 35442, 35443, 35430, 35433, 35440, 35463, 35452, 35427, 35488, 35441, + 35461, 35437, 35426, 35438, 35436, 35449, 35451, 35390, 35432, 35938, 35978, 35977, 36042, + 36039, 36040, 36036, 36018, 36035, 36034, 36037, 36321, 36319, 36328, 36335, 36339, 36346, + 36330, 36324, 36326, 36530, 36611, 36617, 36606, 36618, 36767, 36786, 36939, 36938, 36947, + 36930, 36948, 36924, 36949, 36944, 36935, 36943, 36942, 36941, 36945, 36926, 36929, 37138, + 37143, 37228, 37226, 37225, 37321, 37431, 37463, 37432, 37437, 37440, 37438, 37467, 37451, + 37476, 37457, 37428, 37449, 37453, 37445, 37433, 37439, 37466, 38296, 38552, 38548, 38549, + 38605, 38603, 38601, 38602, 38647, 38651, 38649, 38646, 38742, 38772, 38774, 38928, 38929, + 38931, 38922, 38930, 38924, 39164, 39156, 39165, 39166, 39347, 39345, 39348, 39649, 40169, + 40578, 40718, 40723, 40736, 20711, 20718, 20709, 20694, 20717, 20698, 20693, 20687, 20689, + 20721, 20686, 20713, 20834, 20979, 21123, 21122, 21297, 21421, 22014, 22016, 22043, 22039, + 22013, 22036, 22022, 22025, 22029, 22030, 22007, 22038, 22047, 22024, 22032, 22006, 22296, + 22294, 22645, 22654, 22659, 22675, 22666, 22649, 22661, 22653, 22781, 22821, 22818, 22820, + 22890, 22889, 23265, 23270, 23273, 23255, 23254, 23256, 23267, 23413, 23518, 23527, 23521, + 23525, 23526, 23528, 23522, 23524, 23519, 23565, 23650, 23940, 23943, 24155, 24163, 24149, + 24151, 24148, 24275, 24278, 24330, 24390, 24432, 24505, 24903, 24895, 24907, 24951, 24930, + 24931, 24927, 24922, 24920, 24949, 25130, 25735, 25688, 25684, 25764, 25720, 25695, 25722, + 25681, 25703, 25652, 25709, 25723, 25970, 26017, 26071, 26070, 26274, 26280, 26269, 27036, + 27048, 27029, 27073, 27054, 27091, 27083, 27035, 27063, 27067, 27051, 27060, 27088, 27085, + 27053, 27084, 27046, 27075, 27043, 27465, 27468, 27699, 28467, 28436, 28414, 28435, 28404, + 28457, 28478, 28448, 28460, 28431, 28418, 28450, 28415, 28399, 28422, 28465, 28472, 28466, + 28451, 28437, 28459, 28463, 28552, 28458, 28396, 28417, 28402, 28364, 28407, 29076, 29081, + 29053, 29066, 29060, 29074, 29246, 29330, 29334, 29508, 29520, 29796, 29795, 29802, 29808, + 29805, 29956, 30097, 30247, 30221, 30219, 30217, 30227, 30433, 30435, 30596, 30589, 30591, + 30561, 30913, 30879, 30887, 30899, 30889, 30883, 31118, 31119, 31117, 31278, 31281, 31402, + 31401, 31469, 31471, 31649, 31637, 31627, 31605, 31639, 31645, 31636, 31631, 31672, 31623, + 31620, 31929, 31933, 31934, 32187, 32176, 32156, 32189, 32190, 32160, 32202, 32180, 32178, + 32177, 32186, 32162, 32191, 32181, 32184, 32173, 32210, 32199, 32172, 32624, 32736, 32737, + 32735, 32862, 32858, 32903, 33104, 33152, 33167, 33160, 33162, 33151, 33154, 33255, 33274, + 33287, 33300, 33310, 33355, 33993, 33983, 33990, 33988, 33945, 33950, 33970, 33948, 33995, + 33976, 33984, 34003, 33936, 33980, 34001, 33994, 34623, 34588, 34619, 34594, 34597, 34612, + 34584, 34645, 34615, 34601, 35059, 35074, 35060, 35065, 35064, 35069, 35048, 35098, 35055, + 35494, 35468, 35486, 35491, 35469, 35489, 35475, 35492, 35498, 35493, 35496, 35480, 35473, + 35482, 35495, 35946, 35981, 35980, 36051, 36049, 36050, 36203, 36249, 36245, 36348, 36628, + 36626, 36629, 36627, 36771, 36960, 36952, 36956, 36963, 36953, 36958, 36962, 36957, 36955, + 37145, 37144, 37150, 37237, 37240, 37239, 37236, 37496, 37504, 37509, 37528, 37526, 37499, + 37523, 37532, 37544, 37500, 37521, 38305, 38312, 38313, 38307, 38309, 38308, 38553, 38556, + 38555, 38604, 38610, 38656, 38780, 38789, 38902, 38935, 38936, 39087, 39089, 39171, 39173, + 39180, 39177, 39361, 39599, 39600, 39654, 39745, 39746, 40180, 40182, 40179, 40636, 40763, + 40778, 20740, 20736, 20731, 20725, 20729, 20738, 20744, 20745, 20741, 20956, 21127, 21128, + 21129, 21133, 21130, 21232, 21426, 22062, 22075, 22073, 22066, 22079, 22068, 22057, 22099, + 22094, 22103, 22132, 22070, 22063, 22064, 22656, 22687, 22686, 22707, 22684, 22702, 22697, + 22694, 22893, 23305, 23291, 23307, 23285, 23308, 23304, 23534, 23532, 23529, 23531, 23652, + 23653, 23965, 23956, 24162, 24159, 24161, 24290, 24282, 24287, 24285, 24291, 24288, 24392, + 24433, 24503, 24501, 24950, 24935, 24942, 24925, 24917, 24962, 24956, 24944, 24939, 24958, + 24999, 24976, 25003, 24974, 25004, 24986, 24996, 24980, 25006, 25134, 25705, 25711, 25721, + 25758, 25778, 25736, 25744, 25776, 25765, 25747, 25749, 25769, 25746, 25774, 25773, 25771, + 25754, 25772, 25753, 25762, 25779, 25973, 25975, 25976, 26286, 26283, 26292, 26289, 27171, + 27167, 27112, 27137, 27166, 27161, 27133, 27169, 27155, 27146, 27123, 27138, 27141, 27117, + 27153, 27472, 27470, 27556, 27589, 27590, 28479, 28540, 28548, 28497, 28518, 28500, 28550, + 28525, 28507, 28536, 28526, 28558, 28538, 28528, 28516, 28567, 28504, 28373, 28527, 28512, + 28511, 29087, 29100, 29105, 29096, 29270, 29339, 29518, 29527, 29801, 29835, 29827, 29822, + 29824, 30079, 30240, 30249, 30239, 30244, 30246, 30241, 30242, 30362, 30394, 30436, 30606, + 30599, 30604, 30609, 30603, 30923, 30917, 30906, 30922, 30910, 30933, 30908, 30928, 31295, + 31292, 31296, 31293, 31287, 31291, 31407, 31406, 31661, 31665, 31684, 31668, 31686, 31687, + 31681, 31648, 31692, 31946, 32224, 32244, 32239, 32251, 32216, 32236, 32221, 32232, 32227, + 32218, 32222, 32233, 32158, 32217, 32242, 32249, 32629, 32631, 32687, 32745, 32806, 33179, + 33180, 33181, 33184, 33178, 33176, 34071, 34109, 34074, 34030, 34092, 34093, 34067, 34065, + 34083, 34081, 34068, 34028, 34085, 34047, 34054, 34690, 34676, 34678, 34656, 34662, 34680, + 34664, 34649, 34647, 34636, 34643, 34907, 34909, 35088, 35079, 35090, 35091, 35093, 35082, + 35516, 35538, 35527, 35524, 35477, 35531, 35576, 35506, 35529, 35522, 35519, 35504, 35542, + 35533, 35510, 35513, 35547, 35916, 35918, 35948, 36064, 36062, 36070, 36068, 36076, 36077, + 36066, 36067, 36060, 36074, 36065, 36205, 36255, 36259, 36395, 36368, 36381, 36386, 36367, + 36393, 36383, 36385, 36382, 36538, 36637, 36635, 36639, 36649, 36646, 36650, 36636, 36638, + 36645, 36969, 36974, 36968, 36973, 36983, 37168, 37165, 37159, 37169, 37255, 37257, 37259, + 37251, 37573, 37563, 37559, 37610, 37548, 37604, 37569, 37555, 37564, 37586, 37575, 37616, + 37554, 38317, 38321, 38660, 38662, 38663, 38665, 38752, 38797, 38795, 38799, 38945, 38955, + 38940, 39091, 39178, 39187, 39186, 39192, 39389, 39376, 39391, 39387, 39377, 39381, 39378, + 39385, 39607, 39662, 39663, 39719, 39749, 39748, 39799, 39791, 40198, 40201, 40195, 40617, + 40638, 40654, 22696, 40786, 20754, 20760, 20756, 20752, 20757, 20864, 20906, 20957, 21137, + 21139, 21235, 22105, 22123, 22137, 22121, 22116, 22136, 22122, 22120, 22117, 22129, 22127, + 22124, 22114, 22134, 22721, 22718, 22727, 22725, 22894, 23325, 23348, 23416, 23536, 23566, + 24394, 25010, 24977, 25001, 24970, 25037, 25014, 25022, 25034, 25032, 25136, 25797, 25793, + 25803, 25787, 25788, 25818, 25796, 25799, 25794, 25805, 25791, 25810, 25812, 25790, 25972, + 26310, 26313, 26297, 26308, 26311, 26296, 27197, 27192, 27194, 27225, 27243, 27224, 27193, + 27204, 27234, 27233, 27211, 27207, 27189, 27231, 27208, 27481, 27511, 27653, 28610, 28593, + 28577, 28611, 28580, 28609, 28583, 28595, 28608, 28601, 28598, 28582, 28576, 28596, 29118, + 29129, 29136, 29138, 29128, 29141, 29113, 29134, 29145, 29148, 29123, 29124, 29544, 29852, + 29859, 29848, 29855, 29854, 29922, 29964, 29965, 30260, 30264, 30266, 30439, 30437, 30624, + 30622, 30623, 30629, 30952, 30938, 30956, 30951, 31142, 31309, 31310, 31302, 31308, 31307, + 31418, 31705, 31761, 31689, 31716, 31707, 31713, 31721, 31718, 31957, 31958, 32266, 32273, + 32264, 32283, 32291, 32286, 32285, 32265, 32272, 32633, 32690, 32752, 32753, 32750, 32808, + 33203, 33193, 33192, 33275, 33288, 33368, 33369, 34122, 34137, 34120, 34152, 34153, 34115, + 34121, 34157, 34154, 34142, 34691, 34719, 34718, 34722, 34701, 34913, 35114, 35122, 35109, + 35115, 35105, 35242, 35238, 35558, 35578, 35563, 35569, 35584, 35548, 35559, 35566, 35582, + 35585, 35586, 35575, 35565, 35571, 35574, 35580, 35947, 35949, 35987, 36084, 36420, 36401, + 36404, 36418, 36409, 36405, 36667, 36655, 36664, 36659, 36776, 36774, 36981, 36980, 36984, + 36978, 36988, 36986, 37172, 37266, 37664, 37686, 37624, 37683, 37679, 37666, 37628, 37675, + 37636, 37658, 37648, 37670, 37665, 37653, 37678, 37657, 38331, 38567, 38568, 38570, 38613, + 38670, 38673, 38678, 38669, 38675, 38671, 38747, 38748, 38758, 38808, 38960, 38968, 38971, + 38967, 38957, 38969, 38948, 39184, 39208, 39198, 39195, 39201, 39194, 39405, 39394, 39409, + 39608, 39612, 39675, 39661, 39720, 39825, 40213, 40227, 40230, 40232, 40210, 40219, 40664, + 40660, 40845, 40860, 20778, 20767, 20769, 20786, 21237, 22158, 22144, 22160, 22149, 22151, + 22159, 22741, 22739, 22737, 22734, 23344, 23338, 23332, 23418, 23607, 23656, 23996, 23994, + 23997, 23992, 24171, 24396, 24509, 25033, 25026, 25031, 25062, 25035, 25138, 25140, 25806, + 25802, 25816, 25824, 25840, 25830, 25836, 25841, 25826, 25837, 25986, 25987, 26329, 26326, + 27264, 27284, 27268, 27298, 27292, 27355, 27299, 27262, 27287, 27280, 27296, 27484, 27566, + 27610, 27656, 28632, 28657, 28639, 28640, 28635, 28644, 28651, 28655, 28544, 28652, 28641, + 28649, 28629, 28654, 28656, 29159, 29151, 29166, 29158, 29157, 29165, 29164, 29172, 29152, + 29237, 29254, 29552, 29554, 29865, 29872, 29862, 29864, 30278, 30274, 30284, 30442, 30643, + 30634, 30640, 30636, 30631, 30637, 30703, 30967, 30970, 30964, 30959, 30977, 31143, 31146, + 31319, 31423, 31751, 31757, 31742, 31735, 31756, 31712, 31968, 31964, 31966, 31970, 31967, + 31961, 31965, 32302, 32318, 32326, 32311, 32306, 32323, 32299, 32317, 32305, 32325, 32321, + 32308, 32313, 32328, 32309, 32319, 32303, 32580, 32755, 32764, 32881, 32882, 32880, 32879, + 32883, 33222, 33219, 33210, 33218, 33216, 33215, 33213, 33225, 33214, 33256, 33289, 33393, + 34218, 34180, 34174, 34204, 34193, 34196, 34223, 34203, 34183, 34216, 34186, 34407, 34752, + 34769, 34739, 34770, 34758, 34731, 34747, 34746, 34760, 34763, 35131, 35126, 35140, 35128, + 35133, 35244, 35598, 35607, 35609, 35611, 35594, 35616, 35613, 35588, 35600, 35905, 35903, + 35955, 36090, 36093, 36092, 36088, 36091, 36264, 36425, 36427, 36424, 36426, 36676, 36670, + 36674, 36677, 36671, 36991, 36989, 36996, 36993, 36994, 36992, 37177, 37283, 37278, 37276, + 37709, 37762, 37672, 37749, 37706, 37733, 37707, 37656, 37758, 37740, 37723, 37744, 37722, + 37716, 38346, 38347, 38348, 38344, 38342, 38577, 38584, 38614, 38684, 38686, 38816, 38867, + 38982, 39094, 39221, 39425, 39423, 39854, 39851, 39850, 39853, 40251, 40255, 40587, 40655, + 40670, 40668, 40669, 40667, 40766, 40779, 21474, 22165, 22190, 22745, 22744, 23352, 24413, + 25059, 25139, 25844, 25842, 25854, 25862, 25850, 25851, 25847, 26039, 26332, 26406, 27315, + 27308, 27331, 27323, 27320, 27330, 27310, 27311, 27487, 27512, 27567, 28681, 28683, 28670, + 28678, 28666, 28689, 28687, 29179, 29180, 29182, 29176, 29559, 29557, 29863, 29887, 29973, + 30294, 30296, 30290, 30653, 30655, 30651, 30652, 30990, 31150, 31329, 31330, 31328, 31428, + 31429, 31787, 31783, 31786, 31774, 31779, 31777, 31975, 32340, 32341, 32350, 32346, 32353, + 32338, 32345, 32584, 32761, 32763, 32887, 32886, 33229, 33231, 33290, 34255, 34217, 34253, + 34256, 34249, 34224, 34234, 34233, 34214, 34799, 34796, 34802, 34784, 35206, 35250, 35316, + 35624, 35641, 35628, 35627, 35920, 36101, 36441, 36451, 36454, 36452, 36447, 36437, 36544, + 36681, 36685, 36999, 36995, 37000, 37291, 37292, 37328, 37780, 37770, 37782, 37794, 37811, + 37806, 37804, 37808, 37784, 37786, 37783, 38356, 38358, 38352, 38357, 38626, 38620, 38617, + 38619, 38622, 38692, 38819, 38822, 38829, 38905, 38989, 38991, 38988, 38990, 38995, 39098, + 39230, 39231, 39229, 39214, 39333, 39438, 39617, 39683, 39686, 39759, 39758, 39757, 39882, + 39881, 39933, 39880, 39872, 40273, 40285, 40288, 40672, 40725, 40748, 20787, 22181, 22750, + 22751, 22754, 23541, 40848, 24300, 25074, 25079, 25078, 25077, 25856, 25871, 26336, 26333, + 27365, 27357, 27354, 27347, 28699, 28703, 28712, 28698, 28701, 28693, 28696, 29190, 29197, + 29272, 29346, 29560, 29562, 29885, 29898, 29923, 30087, 30086, 30303, 30305, 30663, 31001, + 31153, 31339, 31337, 31806, 31807, 31800, 31805, 31799, 31808, 32363, 32365, 32377, 32361, + 32362, 32645, 32371, 32694, 32697, 32696, 33240, 34281, 34269, 34282, 34261, 34276, 34277, + 34295, 34811, 34821, 34829, 34809, 34814, 35168, 35167, 35158, 35166, 35649, 35676, 35672, + 35657, 35674, 35662, 35663, 35654, 35673, 36104, 36106, 36476, 36466, 36487, 36470, 36460, + 36474, 36468, 36692, 36686, 36781, 37002, 37003, 37297, 37294, 37857, 37841, 37855, 37827, + 37832, 37852, 37853, 37846, 37858, 37837, 37848, 37860, 37847, 37864, 38364, 38580, 38627, + 38698, 38695, 38753, 38876, 38907, 39006, 39000, 39003, 39100, 39237, 39241, 39446, 39449, + 39693, 39912, 39911, 39894, 39899, 40329, 40289, 40306, 40298, 40300, 40594, 40599, 40595, + 40628, 21240, 22184, 22199, 22198, 22196, 22204, 22756, 23360, 23363, 23421, 23542, 24009, + 25080, 25082, 25880, 25876, 25881, 26342, 26407, 27372, 28734, 28720, 28722, 29200, 29563, + 29903, 30306, 30309, 31014, 31018, 31020, 31019, 31431, 31478, 31820, 31811, 31821, 31983, + 31984, 36782, 32381, 32380, 32386, 32588, 32768, 33242, 33382, 34299, 34297, 34321, 34298, + 34310, 34315, 34311, 34314, 34836, 34837, 35172, 35258, 35320, 35696, 35692, 35686, 35695, + 35679, 35691, 36111, 36109, 36489, 36481, 36485, 36482, 37300, 37323, 37912, 37891, 37885, + 38369, 38704, 39108, 39250, 39249, 39336, 39467, 39472, 39479, 39477, 39955, 39949, 40569, + 40629, 40680, 40751, 40799, 40803, 40801, 20791, 20792, 22209, 22208, 22210, 22804, 23660, + 24013, 25084, 25086, 25885, 25884, 26005, 26345, 27387, 27396, 27386, 27570, 28748, 29211, + 29351, 29910, 29908, 30313, 30675, 31824, 32399, 32396, 32700, 34327, 34349, 34330, 34851, + 34850, 34849, 34847, 35178, 35180, 35261, 35700, 35703, 35709, 36115, 36490, 36493, 36491, + 36703, 36783, 37306, 37934, 37939, 37941, 37946, 37944, 37938, 37931, 38370, 38712, 38713, + 38706, 38911, 39015, 39013, 39255, 39493, 39491, 39488, 39486, 39631, 39764, 39761, 39981, + 39973, 40367, 40372, 40386, 40376, 40605, 40687, 40729, 40796, 40806, 40807, 20796, 20795, + 22216, 22218, 22217, 23423, 24020, 24018, 24398, 25087, 25892, 27402, 27489, 28753, 28760, + 29568, 29924, 30090, 30318, 30316, 31155, 31840, 31839, 32894, 32893, 33247, 35186, 35183, + 35324, 35712, 36118, 36119, 36497, 36499, 36705, 37192, 37956, 37969, 37970, 38717, 38718, + 38851, 38849, 39019, 39253, 39509, 39501, 39634, 39706, 40009, 39985, 39998, 39995, 40403, + 40407, 40756, 40812, 40810, 40852, 22220, 24022, 25088, 25891, 25899, 25898, 26348, 27408, + 29914, 31434, 31844, 31843, 31845, 32403, 32406, 32404, 33250, 34360, 34367, 34865, 35722, + 37008, 37007, 37987, 37984, 37988, 38760, 39023, 39260, 39514, 39515, 39511, 39635, 39636, + 39633, 40020, 40023, 40022, 40421, 40607, 40692, 22225, 22761, 25900, 28766, 30321, 30322, + 30679, 32592, 32648, 34870, 34873, 34914, 35731, 35730, 35734, 33399, 36123, 37312, 37994, + 38722, 38728, 38724, 38854, 39024, 39519, 39714, 39768, 40031, 40441, 40442, 40572, 40573, + 40711, 40823, 40818, 24307, 27414, 28771, 31852, 31854, 34875, 35264, 36513, 37313, 38002, + 38000, 39025, 39262, 39638, 39715, 40652, 28772, 30682, 35738, 38007, 38857, 39522, 39525, + 32412, 35740, 36522, 37317, 38013, 38014, 38012, 40055, 40056, 40695, 35924, 38015, 40474, + 29224, 39530, 39729, 40475, 40478, 31858, 9312, 9313, 9314, 9315, 9316, 9317, 9318, 9319, 9320, + 9321, 9332, 9333, 9334, 9335, 9336, 9337, 9338, 9339, 9340, 9341, 8560, 8561, 8562, 8563, 8564, + 8565, 8566, 8567, 8568, 8569, 20022, 20031, 20101, 20128, 20866, 20886, 20907, 21241, 21304, + 21353, 21430, 22794, 23424, 24027, 24186, 24191, 24308, 24400, 24417, 25908, 26080, 30098, + 30326, 36789, 38582, 168, 710, 12541, 12542, 12445, 12446, 0, 0, 12293, 12294, 12295, 12540, + 65339, 65341, 10045, 12353, 12354, 12355, 12356, 12357, 12358, 12359, 12360, 12361, 12362, + 12363, 12364, 12365, 12366, 12367, 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, + 12376, 12377, 12378, 12379, 12380, 12381, 12382, 12383, 12384, 12385, 12386, 12387, 12388, + 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, 12397, 12398, 12399, 12400, 12401, + 12402, 12403, 12404, 12405, 12406, 12407, 12408, 12409, 12410, 12411, 12412, 12413, 12414, + 12415, 12416, 12417, 12418, 12419, 12420, 12421, 12422, 12423, 12424, 12425, 12426, 12427, + 12428, 12429, 12430, 12431, 12432, 12433, 12434, 12435, 12449, 12450, 12451, 12452, 12453, + 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, + 12467, 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, + 12480, 12481, 12482, 12483, 12484, 12485, 12486, 12487, 12488, 12489, 12490, 12491, 12492, + 12493, 12494, 12495, 12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, + 12506, 12507, 12508, 12509, 12510, 12511, 12512, 12513, 12514, 12515, 12516, 12517, 12518, + 12519, 12520, 12521, 12522, 12523, 12524, 12525, 12526, 12527, 12528, 12529, 12530, 12531, + 12532, 12533, 12534, 1040, 1041, 1042, 1043, 1044, 1045, 1025, 1046, 1047, 1048, 1049, 1050, + 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, + 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1105, 1078, 1079, 1080, 1081, + 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, + 1098, 1099, 1100, 1101, 1102, 1103, 8679, 8632, 8633, 12751, 204, 20058, 138, 20994, 17553, + 40880, 20872, 40881, 30215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65506, 65508, 65287, 65282, 12849, 8470, + 8481, 12443, 12444, 11904, 11908, 11910, 11911, 11912, 11914, 11916, 11917, 11925, 11932, 11933, + 11941, 11943, 11946, 11948, 11950, 11958, 11964, 11966, 11974, 11978, 11980, 11981, 11983, + 11990, 11991, 11998, 12003, 0, 0, 0, 643, 592, 603, 596, 629, 339, 248, 331, 650, 618, 20034, + 20060, 20981, 21274, 21378, 19975, 19980, 20039, 20109, 22231, 64012, 23662, 24435, 19983, + 20871, 19982, 20014, 20115, 20162, 20169, 20168, 20888, 21244, 21356, 21433, 22304, 22787, + 22828, 23568, 24063, 26081, 27571, 27596, 27668, 29247, 20017, 20028, 20200, 20188, 20201, + 20193, 20189, 20186, 21004, 21276, 21324, 22306, 22307, 22807, 22831, 23425, 23428, 23570, + 23611, 23668, 23667, 24068, 24192, 24194, 24521, 25097, 25168, 27669, 27702, 27715, 27711, + 27707, 29358, 29360, 29578, 31160, 32906, 38430, 20238, 20248, 20268, 20213, 20244, 20209, + 20224, 20215, 20232, 20253, 20226, 20229, 20258, 20243, 20228, 20212, 20242, 20913, 21011, + 21001, 21008, 21158, 21282, 21279, 21325, 21386, 21511, 22241, 22239, 22318, 22314, 22324, + 22844, 22912, 22908, 22917, 22907, 22910, 22903, 22911, 23382, 23573, 23589, 23676, 23674, + 23675, 23678, 24031, 24181, 24196, 24322, 24346, 24436, 24533, 24532, 24527, 25180, 25182, + 25188, 25185, 25190, 25186, 25177, 25184, 25178, 25189, 26095, 26094, 26430, 26425, 26424, + 26427, 26426, 26431, 26428, 26419, 27672, 27718, 27730, 27740, 27727, 27722, 27732, 27723, + 27724, 28785, 29278, 29364, 29365, 29582, 29994, 30335, 31349, 32593, 33400, 33404, 33408, + 33405, 33407, 34381, 35198, 37017, 37015, 37016, 37019, 37012, 38434, 38436, 38432, 38435, + 20310, 20283, 20322, 20297, 20307, 20324, 20286, 20327, 20306, 20319, 20289, 20312, 20269, + 20275, 20287, 20321, 20879, 20921, 21020, 21022, 21025, 21165, 21166, 21257, 21347, 21362, + 21390, 21391, 21552, 21559, 21546, 21588, 21573, 21529, 21532, 21541, 21528, 21565, 21583, + 21569, 21544, 21540, 21575, 22254, 22247, 22245, 22337, 22341, 22348, 22345, 22347, 22354, + 22790, 22848, 22950, 22936, 22944, 22935, 22926, 22946, 22928, 22927, 22951, 22945, 23438, + 23442, 23592, 23594, 23693, 23695, 23688, 23691, 23689, 23698, 23690, 23686, 23699, 23701, + 24032, 24074, 24078, 24203, 24201, 24204, 24200, 24205, 24325, 24349, 24440, 24438, 24530, + 24529, 24528, 24557, 24552, 24558, 24563, 24545, 24548, 24547, 24570, 24559, 24567, 24571, + 24576, 24564, 25146, 25219, 25228, 25230, 25231, 25236, 25223, 25201, 25211, 25210, 25200, + 25217, 25224, 25207, 25213, 25202, 25204, 25911, 26096, 26100, 26099, 26098, 26101, 26437, + 26439, 26457, 26453, 26444, 26440, 26461, 26445, 26458, 26443, 27600, 27673, 27674, 27768, + 27751, 27755, 27780, 27787, 27791, 27761, 27759, 27753, 27802, 27757, 27783, 27797, 27804, + 27750, 27763, 27749, 27771, 27790, 28788, 28794, 29283, 29375, 29373, 29379, 29382, 29377, + 29370, 29381, 29589, 29591, 29587, 29588, 29586, 30010, 30009, 30100, 30101, 30337, 31037, + 32820, 32917, 32921, 32912, 32914, 32924, 33424, 33423, 33413, 33422, 33425, 33427, 33418, + 33411, 33412, 35960, 36809, 36799, 37023, 37025, 37029, 37022, 37031, 37024, 38448, 38440, + 38447, 38445, 20019, 20376, 20348, 20357, 20349, 20352, 20359, 20342, 20340, 20361, 20356, + 20343, 20300, 20375, 20330, 20378, 20345, 20353, 20344, 20368, 20380, 20372, 20382, 20370, + 20354, 20373, 20331, 20334, 20894, 20924, 20926, 21045, 21042, 21043, 21062, 21041, 21180, + 21258, 21259, 21308, 21394, 21396, 21639, 21631, 21633, 21649, 21634, 21640, 21611, 21626, + 21630, 21605, 21612, 21620, 21606, 21645, 21615, 21601, 21600, 21656, 21603, 21607, 21604, + 22263, 22265, 22383, 22386, 22381, 22379, 22385, 22384, 22390, 22400, 22389, 22395, 22387, + 22388, 22370, 22376, 22397, 22796, 22853, 22965, 22970, 22991, 22990, 22962, 22988, 22977, + 22966, 22972, 22979, 22998, 22961, 22973, 22976, 22984, 22964, 22983, 23394, 23397, 23443, + 23445, 23620, 23623, 23726, 23716, 23712, 23733, 23727, 23720, 23724, 23711, 23715, 23725, + 23714, 23722, 23719, 23709, 23717, 23734, 23728, 23718, 24087, 24084, 24089, 24360, 24354, + 24355, 24356, 24404, 24450, 24446, 24445, 24542, 24549, 24621, 24614, 24601, 24626, 24587, + 24628, 24586, 24599, 24627, 24602, 24606, 24620, 24610, 24589, 24592, 24622, 24595, 24593, + 24588, 24585, 24604, 25108, 25149, 25261, 25268, 25297, 25278, 25258, 25270, 25290, 25262, + 25267, 25263, 25275, 25257, 25264, 25272, 25917, 26024, 26043, 26121, 26108, 26116, 26130, + 26120, 26107, 26115, 26123, 26125, 26117, 26109, 26129, 26128, 26358, 26378, 26501, 26476, + 26510, 26514, 26486, 26491, 26520, 26502, 26500, 26484, 26509, 26508, 26490, 26527, 26513, + 26521, 26499, 26493, 26497, 26488, 26489, 26516, 27429, 27520, 27518, 27614, 27677, 27795, + 27884, 27883, 27886, 27865, 27830, 27860, 27821, 27879, 27831, 27856, 27842, 27834, 27843, + 27846, 27885, 27890, 27858, 27869, 27828, 27786, 27805, 27776, 27870, 27840, 27952, 27853, + 27847, 27824, 27897, 27855, 27881, 27857, 28820, 28824, 28805, 28819, 28806, 28804, 28817, + 28822, 28802, 28826, 28803, 29290, 29398, 29387, 29400, 29385, 29404, 29394, 29396, 29402, + 29388, 29393, 29604, 29601, 29613, 29606, 29602, 29600, 29612, 29597, 29917, 29928, 30015, + 30016, 30014, 30092, 30104, 30383, 30451, 30449, 30448, 30453, 30712, 30716, 30713, 30715, + 30714, 30711, 31042, 31039, 31173, 31352, 31355, 31483, 31861, 31997, 32821, 32911, 32942, + 32931, 32952, 32949, 32941, 33312, 33440, 33472, 33451, 33434, 33432, 33435, 33461, 33447, + 33454, 33468, 33438, 33466, 33460, 33448, 33441, 33449, 33474, 33444, 33475, 33462, 33442, + 34416, 34415, 34413, 34414, 35926, 36818, 36811, 36819, 36813, 36822, 36821, 36823, 37042, + 37044, 37039, 37043, 37040, 38457, 38461, 38460, 38458, 38467, 20429, 20421, 20435, 20402, + 20425, 20427, 20417, 20436, 20444, 20441, 20411, 20403, 20443, 20423, 20438, 20410, 20416, + 20409, 20460, 21060, 21065, 21184, 21186, 21309, 21372, 21399, 21398, 21401, 21400, 21690, + 21665, 21677, 21669, 21711, 21699, 33549, 21687, 21678, 21718, 21686, 21701, 21702, 21664, + 21616, 21692, 21666, 21694, 21618, 21726, 21680, 22453, 22430, 22431, 22436, 22412, 22423, + 22429, 22427, 22420, 22424, 22415, 22425, 22437, 22426, 22421, 22772, 22797, 22867, 23009, + 23006, 23022, 23040, 23025, 23005, 23034, 23037, 23036, 23030, 23012, 23026, 23031, 23003, + 23017, 23027, 23029, 23008, 23038, 23028, 23021, 23464, 23628, 23760, 23768, 23756, 23767, + 23755, 23771, 23774, 23770, 23753, 23751, 23754, 23766, 23763, 23764, 23759, 23752, 23750, + 23758, 23775, 23800, 24057, 24097, 24098, 24099, 24096, 24100, 24240, 24228, 24226, 24219, + 24227, 24229, 24327, 24366, 24406, 24454, 24631, 24633, 24660, 24690, 24670, 24645, 24659, + 24647, 24649, 24667, 24652, 24640, 24642, 24671, 24612, 24644, 24664, 24678, 24686, 25154, + 25155, 25295, 25357, 25355, 25333, 25358, 25347, 25323, 25337, 25359, 25356, 25336, 25334, + 25344, 25363, 25364, 25338, 25365, 25339, 25328, 25921, 25923, 26026, 26047, 26166, 26145, + 26162, 26165, 26140, 26150, 26146, 26163, 26155, 26170, 26141, 26164, 26169, 26158, 26383, + 26384, 26561, 26610, 26568, 26554, 26588, 26555, 26616, 26584, 26560, 26551, 26565, 26603, + 26596, 26591, 26549, 26573, 26547, 26615, 26614, 26606, 26595, 26562, 26553, 26574, 26599, + 26608, 26546, 26620, 26566, 26605, 26572, 26542, 26598, 26587, 26618, 26569, 26570, 26563, + 26602, 26571, 27432, 27522, 27524, 27574, 27606, 27608, 27616, 27680, 27681, 27944, 27956, + 27949, 27935, 27964, 27967, 27922, 27914, 27866, 27955, 27908, 27929, 27962, 27930, 27921, + 27904, 27933, 27970, 27905, 27928, 27959, 27907, 27919, 27968, 27911, 27936, 27948, 27912, + 27938, 27913, 27920, 28855, 28831, 28862, 28849, 28848, 28833, 28852, 28853, 28841, 29249, + 29257, 29258, 29292, 29296, 29299, 29294, 29386, 29412, 29416, 29419, 29407, 29418, 29414, + 29411, 29573, 29644, 29634, 29640, 29637, 29625, 29622, 29621, 29620, 29675, 29631, 29639, + 29630, 29635, 29638, 29624, 29643, 29932, 29934, 29998, 30023, 30024, 30119, 30122, 30329, + 30404, 30472, 30467, 30468, 30469, 30474, 30455, 30459, 30458, 30695, 30696, 30726, 30737, + 30738, 30725, 30736, 30735, 30734, 30729, 30723, 30739, 31050, 31052, 31051, 31045, 31044, + 31189, 31181, 31183, 31190, 31182, 31360, 31358, 31441, 31488, 31489, 31866, 31864, 31865, + 31871, 31872, 31873, 32003, 32008, 32001, 32600, 32657, 32653, 32702, 32775, 32782, 32783, + 32788, 32823, 32984, 32967, 32992, 32977, 32968, 32962, 32976, 32965, 32995, 32985, 32988, + 32970, 32981, 32969, 32975, 32983, 32998, 32973, 33279, 33313, 33428, 33497, 33534, 33529, + 33543, 33512, 33536, 33493, 33594, 33515, 33494, 33524, 33516, 33505, 33522, 33525, 33548, + 33531, 33526, 33520, 33514, 33508, 33504, 33530, 33523, 33517, 34423, 34420, 34428, 34419, + 34881, 34894, 34919, 34922, 34921, 35283, 35332, 35335, 36210, 36835, 36833, 36846, 36832, + 37105, 37053, 37055, 37077, 37061, 37054, 37063, 37067, 37064, 37332, 37331, 38484, 38479, + 38481, 38483, 38474, 38478, 20510, 20485, 20487, 20499, 20514, 20528, 20507, 20469, 20468, + 20531, 20535, 20524, 20470, 20471, 20503, 20508, 20512, 20519, 20533, 20527, 20529, 20494, + 20826, 20884, 20883, 20938, 20932, 20933, 20936, 20942, 21089, 21082, 21074, 21086, 21087, + 21077, 21090, 21197, 21262, 21406, 21798, 21730, 21783, 21778, 21735, 21747, 21732, 21786, + 21759, 21764, 21768, 21739, 21777, 21765, 21745, 21770, 21755, 21751, 21752, 21728, 21774, + 21763, 21771, 22273, 22274, 22476, 22578, 22485, 22482, 22458, 22470, 22461, 22460, 22456, + 22454, 22463, 22471, 22480, 22457, 22465, 22798, 22858, 23065, 23062, 23085, 23086, 23061, + 23055, 23063, 23050, 23070, 23091, 23404, 23463, 23469, 23468, 23555, 23638, 23636, 23788, + 23807, 23790, 23793, 23799, 23808, 23801, 24105, 24104, 24232, 24238, 24234, 24236, 24371, + 24368, 24423, 24669, 24666, 24679, 24641, 24738, 24712, 24704, 24722, 24705, 24733, 24707, + 24725, 24731, 24727, 24711, 24732, 24718, 25113, 25158, 25330, 25360, 25430, 25388, 25412, + 25413, 25398, 25411, 25572, 25401, 25419, 25418, 25404, 25385, 25409, 25396, 25432, 25428, + 25433, 25389, 25415, 25395, 25434, 25425, 25400, 25431, 25408, 25416, 25930, 25926, 26054, + 26051, 26052, 26050, 26186, 26207, 26183, 26193, 26386, 26387, 26655, 26650, 26697, 26674, + 26675, 26683, 26699, 26703, 26646, 26673, 26652, 26677, 26667, 26669, 26671, 26702, 26692, + 26676, 26653, 26642, 26644, 26662, 26664, 26670, 26701, 26682, 26661, 26656, 27436, 27439, + 27437, 27441, 27444, 27501, 32898, 27528, 27622, 27620, 27624, 27619, 27618, 27623, 27685, + 28026, 28003, 28004, 28022, 27917, 28001, 28050, 27992, 28002, 28013, 28015, 28049, 28045, + 28143, 28031, 28038, 27998, 28007, 28000, 28055, 28016, 28028, 27999, 28034, 28056, 27951, + 28008, 28043, 28030, 28032, 28036, 27926, 28035, 28027, 28029, 28021, 28048, 28892, 28883, + 28881, 28893, 28875, 32569, 28898, 28887, 28882, 28894, 28896, 28884, 28877, 28869, 28870, + 28871, 28890, 28878, 28897, 29250, 29304, 29303, 29302, 29440, 29434, 29428, 29438, 29430, + 29427, 29435, 29441, 29651, 29657, 29669, 29654, 29628, 29671, 29667, 29673, 29660, 29650, + 29659, 29652, 29661, 29658, 29655, 29656, 29672, 29918, 29919, 29940, 29941, 29985, 30043, + 30047, 30128, 30145, 30139, 30148, 30144, 30143, 30134, 30138, 30346, 30409, 30493, 30491, + 30480, 30483, 30482, 30499, 30481, 30485, 30489, 30490, 30498, 30503, 30755, 30764, 30754, + 30773, 30767, 30760, 30766, 30763, 30753, 30761, 30771, 30762, 30769, 31060, 31067, 31055, + 31068, 31059, 31058, 31057, 31211, 31212, 31200, 31214, 31213, 31210, 31196, 31198, 31197, + 31366, 31369, 31365, 31371, 31372, 31370, 31367, 31448, 31504, 31492, 31507, 31493, 31503, + 31496, 31498, 31502, 31497, 31506, 31876, 31889, 31882, 31884, 31880, 31885, 31877, 32030, + 32029, 32017, 32014, 32024, 32022, 32019, 32031, 32018, 32015, 32012, 32604, 32609, 32606, + 32608, 32605, 32603, 32662, 32658, 32707, 32706, 32704, 32790, 32830, 32825, 33018, 33010, + 33017, 33013, 33025, 33019, 33024, 33281, 33327, 33317, 33587, 33581, 33604, 33561, 33617, + 33573, 33622, 33599, 33601, 33574, 33564, 33570, 33602, 33614, 33563, 33578, 33544, 33596, + 33613, 33558, 33572, 33568, 33591, 33583, 33577, 33607, 33605, 33612, 33619, 33566, 33580, + 33611, 33575, 33608, 34387, 34386, 34466, 34472, 34454, 34445, 34449, 34462, 34439, 34455, + 34438, 34443, 34458, 34437, 34469, 34457, 34465, 34471, 34453, 34456, 34446, 34461, 34448, + 34452, 34883, 34884, 34925, 34933, 34934, 34930, 34944, 34929, 34943, 34927, 34947, 34942, + 34932, 34940, 35346, 35911, 35927, 35963, 36004, 36003, 36214, 36216, 36277, 36279, 36278, + 36561, 36563, 36862, 36853, 36866, 36863, 36859, 36868, 36860, 36854, 37078, 37088, 37081, + 37082, 37091, 37087, 37093, 37080, 37083, 37079, 37084, 37092, 37200, 37198, 37199, 37333, + 37346, 37338, 38492, 38495, 38588, 39139, 39647, 39727, 20095, 20592, 20586, 20577, 20574, + 20576, 20563, 20555, 20573, 20594, 20552, 20557, 20545, 20571, 20554, 20578, 20501, 20549, + 20575, 20585, 20587, 20579, 20580, 20550, 20544, 20590, 20595, 20567, 20561, 20944, 21099, + 21101, 21100, 21102, 21206, 21203, 21293, 21404, 21877, 21878, 21820, 21837, 21840, 21812, + 21802, 21841, 21858, 21814, 21813, 21808, 21842, 21829, 21772, 21810, 21861, 21838, 21817, + 21832, 21805, 21819, 21824, 21835, 22282, 22279, 22523, 22548, 22498, 22518, 22492, 22516, + 22528, 22509, 22525, 22536, 22520, 22539, 22515, 22479, 22535, 22510, 22499, 22514, 22501, + 22508, 22497, 22542, 22524, 22544, 22503, 22529, 22540, 22513, 22505, 22512, 22541, 22532, + 22876, 23136, 23128, 23125, 23143, 23134, 23096, 23093, 23149, 23120, 23135, 23141, 23148, + 23123, 23140, 23127, 23107, 23133, 23122, 23108, 23131, 23112, 23182, 23102, 23117, 23097, + 23116, 23152, 23145, 23111, 23121, 23126, 23106, 23132, 23410, 23406, 23489, 23488, 23641, + 23838, 23819, 23837, 23834, 23840, 23820, 23848, 23821, 23846, 23845, 23823, 23856, 23826, + 23843, 23839, 23854, 24126, 24116, 24241, 24244, 24249, 24242, 24243, 24374, 24376, 24475, + 24470, 24479, 24714, 24720, 24710, 24766, 24752, 24762, 24787, 24788, 24783, 24804, 24793, + 24797, 24776, 24753, 24795, 24759, 24778, 24767, 24771, 24781, 24768, 25394, 25445, 25482, + 25474, 25469, 25533, 25502, 25517, 25501, 25495, 25515, 25486, 25455, 25479, 25488, 25454, + 25519, 25461, 25500, 25453, 25518, 25468, 25508, 25403, 25503, 25464, 25477, 25473, 25489, + 25485, 25456, 25939, 26061, 26213, 26209, 26203, 26201, 26204, 26210, 26392, 26745, 26759, + 26768, 26780, 26733, 26734, 26798, 26795, 26966, 26735, 26787, 26796, 26793, 26741, 26740, + 26802, 26767, 26743, 26770, 26748, 26731, 26738, 26794, 26752, 26737, 26750, 26779, 26774, + 26763, 26784, 26761, 26788, 26744, 26747, 26769, 26764, 26762, 26749, 27446, 27443, 27447, + 27448, 27537, 27535, 27533, 27534, 27532, 27690, 28096, 28075, 28084, 28083, 28276, 28076, + 28137, 28130, 28087, 28150, 28116, 28160, 28104, 28128, 28127, 28118, 28094, 28133, 28124, + 28125, 28123, 28148, 28106, 28093, 28141, 28144, 28090, 28117, 28098, 28111, 28105, 28112, + 28146, 28115, 28157, 28119, 28109, 28131, 28091, 28922, 28941, 28919, 28951, 28916, 28940, + 28912, 28932, 28915, 28944, 28924, 28927, 28934, 28947, 28928, 28920, 28918, 28939, 28930, + 28942, 29310, 29307, 29308, 29311, 29469, 29463, 29447, 29457, 29464, 29450, 29448, 29439, + 29455, 29470, 29576, 29686, 29688, 29685, 29700, 29697, 29693, 29703, 29696, 29690, 29692, + 29695, 29708, 29707, 29684, 29704, 30052, 30051, 30158, 30162, 30159, 30155, 30156, 30161, + 30160, 30351, 30345, 30419, 30521, 30511, 30509, 30513, 30514, 30516, 30515, 30525, 30501, + 30523, 30517, 30792, 30802, 30793, 30797, 30794, 30796, 30758, 30789, 30800, 31076, 31079, + 31081, 31082, 31075, 31083, 31073, 31163, 31226, 31224, 31222, 31223, 31375, 31380, 31376, + 31541, 31559, 31540, 31525, 31536, 31522, 31524, 31539, 31512, 31530, 31517, 31537, 31531, + 31533, 31535, 31538, 31544, 31514, 31523, 31892, 31896, 31894, 31907, 32053, 32061, 32056, + 32054, 32058, 32069, 32044, 32041, 32065, 32071, 32062, 32063, 32074, 32059, 32040, 32611, + 32661, 32668, 32669, 32667, 32714, 32715, 32717, 32720, 32721, 32711, 32719, 32713, 32799, + 32798, 32795, 32839, 32835, 32840, 33048, 33061, 33049, 33051, 33069, 33055, 33068, 33054, + 33057, 33045, 33063, 33053, 33058, 33297, 33336, 33331, 33338, 33332, 33330, 33396, 33680, + 33699, 33704, 33677, 33658, 33651, 33700, 33652, 33679, 33665, 33685, 33689, 33653, 33684, + 33705, 33661, 33667, 33676, 33693, 33691, 33706, 33675, 33662, 33701, 33711, 33672, 33687, + 33712, 33663, 33702, 33671, 33710, 33654, 33690, 34393, 34390, 34495, 34487, 34498, 34497, + 34501, 34490, 34480, 34504, 34489, 34483, 34488, 34508, 34484, 34491, 34492, 34499, 34493, + 34494, 34898, 34953, 34965, 34984, 34978, 34986, 34970, 34961, 34977, 34975, 34968, 34983, + 34969, 34971, 34967, 34980, 34988, 34956, 34963, 34958, 35202, 35286, 35289, 35285, 35376, + 35367, 35372, 35358, 35897, 35899, 35932, 35933, 35965, 36005, 36221, 36219, 36217, 36284, + 36290, 36281, 36287, 36289, 36568, 36574, 36573, 36572, 36567, 36576, 36577, 36900, 36875, + 36881, 36892, 36876, 36897, 37103, 37098, 37104, 37108, 37106, 37107, 37076, 37099, 37100, + 37097, 37206, 37208, 37210, 37203, 37205, 37356, 37364, 37361, 37363, 37368, 37348, 37369, + 37354, 37355, 37367, 37352, 37358, 38266, 38278, 38280, 38524, 38509, 38507, 38513, 38511, + 38591, 38762, 38916, 39141, 39319, 20635, 20629, 20628, 20638, 20619, 20643, 20611, 20620, + 20622, 20637, 20584, 20636, 20626, 20610, 20615, 20831, 20948, 21266, 21265, 21412, 21415, + 21905, 21928, 21925, 21933, 21879, 22085, 21922, 21907, 21896, 21903, 21941, 21889, 21923, + 21906, 21924, 21885, 21900, 21926, 21887, 21909, 21921, 21902, 22284, 22569, 22583, 22553, + 22558, 22567, 22563, 22568, 22517, 22600, 22565, 22556, 22555, 22579, 22591, 22582, 22574, + 22585, 22584, 22573, 22572, 22587, 22881, 23215, 23188, 23199, 23162, 23202, 23198, 23160, + 23206, 23164, 23205, 23212, 23189, 23214, 23095, 23172, 23178, 23191, 23171, 23179, 23209, + 23163, 23165, 23180, 23196, 23183, 23187, 23197, 23530, 23501, 23499, 23508, 23505, 23498, + 23502, 23564, 23600, 23863, 23875, 23915, 23873, 23883, 23871, 23861, 23889, 23886, 23893, + 23859, 23866, 23890, 23869, 23857, 23897, 23874, 23865, 23881, 23864, 23868, 23858, 23862, + 23872, 23877, 24132, 24129, 24408, 24486, 24485, 24491, 24777, 24761, 24780, 24802, 24782, + 24772, 24852, 24818, 24842, 24854, 24837, 24821, 24851, 24824, 24828, 24830, 24769, 24835, + 24856, 24861, 24848, 24831, 24836, 24843, 25162, 25492, 25521, 25520, 25550, 25573, 25576, + 25583, 25539, 25757, 25587, 25546, 25568, 25590, 25557, 25586, 25589, 25697, 25567, 25534, + 25565, 25564, 25540, 25560, 25555, 25538, 25543, 25548, 25547, 25544, 25584, 25559, 25561, + 25906, 25959, 25962, 25956, 25948, 25960, 25957, 25996, 26013, 26014, 26030, 26064, 26066, + 26236, 26220, 26235, 26240, 26225, 26233, 26218, 26226, 26369, 26892, 26835, 26884, 26844, + 26922, 26860, 26858, 26865, 26895, 26838, 26871, 26859, 26852, 26870, 26899, 26896, 26867, + 26849, 26887, 26828, 26888, 26992, 26804, 26897, 26863, 26822, 26900, 26872, 26832, 26877, + 26876, 26856, 26891, 26890, 26903, 26830, 26824, 26845, 26846, 26854, 26868, 26833, 26886, + 26836, 26857, 26901, 26917, 26823, 27449, 27451, 27455, 27452, 27540, 27543, 27545, 27541, + 27581, 27632, 27634, 27635, 27696, 28156, 28230, 28231, 28191, 28233, 28296, 28220, 28221, + 28229, 28258, 28203, 28223, 28225, 28253, 28275, 28188, 28211, 28235, 28224, 28241, 28219, + 28163, 28206, 28254, 28264, 28252, 28257, 28209, 28200, 28256, 28273, 28267, 28217, 28194, + 28208, 28243, 28261, 28199, 28280, 28260, 28279, 28245, 28281, 28242, 28262, 28213, 28214, + 28250, 28960, 28958, 28975, 28923, 28974, 28977, 28963, 28965, 28962, 28978, 28959, 28968, + 28986, 28955, 29259, 29274, 29320, 29321, 29318, 29317, 29323, 29458, 29451, 29488, 29474, + 29489, 29491, 29479, 29490, 29485, 29478, 29475, 29493, 29452, 29742, 29740, 29744, 29739, + 29718, 29722, 29729, 29741, 29745, 29732, 29731, 29725, 29737, 29728, 29746, 29947, 29999, + 30063, 30060, 30183, 30170, 30177, 30182, 30173, 30175, 30180, 30167, 30357, 30354, 30426, + 30534, 30535, 30532, 30541, 30533, 30538, 30542, 30539, 30540, 30686, 30700, 30816, 30820, + 30821, 30812, 30829, 30833, 30826, 30830, 30832, 30825, 30824, 30814, 30818, 31092, 31091, + 31090, 31088, 31234, 31242, 31235, 31244, 31236, 31385, 31462, 31460, 31562, 31547, 31556, + 31560, 31564, 31566, 31552, 31576, 31557, 31906, 31902, 31912, 31905, 32088, 32111, 32099, + 32083, 32086, 32103, 32106, 32079, 32109, 32092, 32107, 32082, 32084, 32105, 32081, 32095, + 32078, 32574, 32575, 32613, 32614, 32674, 32672, 32673, 32727, 32849, 32847, 32848, 33022, + 32980, 33091, 33098, 33106, 33103, 33095, 33085, 33101, 33082, 33254, 33262, 33271, 33272, + 33273, 33284, 33340, 33341, 33343, 33397, 33595, 33743, 33785, 33827, 33728, 33768, 33810, + 33767, 33764, 33788, 33782, 33808, 33734, 33736, 33771, 33763, 33727, 33793, 33757, 33765, + 33752, 33791, 33761, 33739, 33742, 33750, 33781, 33737, 33801, 33807, 33758, 33809, 33798, + 33730, 33779, 33749, 33786, 33735, 33745, 33770, 33811, 33731, 33772, 33774, 33732, 33787, + 33751, 33762, 33819, 33755, 33790, 34520, 34530, 34534, 34515, 34531, 34522, 34538, 34525, + 34539, 34524, 34540, 34537, 34519, 34536, 34513, 34888, 34902, 34901, 35002, 35031, 35001, + 35000, 35008, 35006, 34998, 35004, 34999, 35005, 34994, 35073, 35017, 35221, 35224, 35223, + 35293, 35290, 35291, 35406, 35405, 35385, 35417, 35392, 35415, 35416, 35396, 35397, 35410, + 35400, 35409, 35402, 35404, 35407, 35935, 35969, 35968, 36026, 36030, 36016, 36025, 36021, + 36228, 36224, 36233, 36312, 36307, 36301, 36295, 36310, 36316, 36303, 36309, 36313, 36296, + 36311, 36293, 36591, 36599, 36602, 36601, 36582, 36590, 36581, 36597, 36583, 36584, 36598, + 36587, 36593, 36588, 36596, 36585, 36909, 36916, 36911, 37126, 37164, 37124, 37119, 37116, + 37128, 37113, 37115, 37121, 37120, 37127, 37125, 37123, 37217, 37220, 37215, 37218, 37216, + 37377, 37386, 37413, 37379, 37402, 37414, 37391, 37388, 37376, 37394, 37375, 37373, 37382, + 37380, 37415, 37378, 37404, 37412, 37401, 37399, 37381, 37398, 38267, 38285, 38284, 38288, + 38535, 38526, 38536, 38537, 38531, 38528, 38594, 38600, 38595, 38641, 38640, 38764, 38768, + 38766, 38919, 39081, 39147, 40166, 40697, 20099, 20100, 20150, 20669, 20671, 20678, 20654, + 20676, 20682, 20660, 20680, 20674, 20656, 20673, 20666, 20657, 20683, 20681, 20662, 20664, + 20951, 21114, 21112, 21115, 21116, 21955, 21979, 21964, 21968, 21963, 21962, 21981, 21952, + 21972, 21956, 21993, 21951, 21970, 21901, 21967, 21973, 21986, 21974, 21960, 22002, 21965, + 21977, 21954, 22292, 22611, 22632, 22628, 22607, 22605, 22601, 22639, 22613, 22606, 22621, + 22617, 22629, 22619, 22589, 22627, 22641, 22780, 23239, 23236, 23243, 23226, 23224, 23217, + 23221, 23216, 23231, 23240, 23227, 23238, 23223, 23232, 23242, 23220, 23222, 23245, 23225, + 23184, 23510, 23512, 23513, 23583, 23603, 23921, 23907, 23882, 23909, 23922, 23916, 23902, + 23912, 23911, 23906, 24048, 24143, 24142, 24138, 24141, 24139, 24261, 24268, 24262, 24267, + 24263, 24384, 24495, 24493, 24823, 24905, 24906, 24875, 24901, 24886, 24882, 24878, 24902, + 24879, 24911, 24873, 24896, 25120, 37224, 25123, 25125, 25124, 25541, 25585, 25579, 25616, + 25618, 25609, 25632, 25636, 25651, 25667, 25631, 25621, 25624, 25657, 25655, 25634, 25635, + 25612, 25638, 25648, 25640, 25665, 25653, 25647, 25610, 25626, 25664, 25637, 25639, 25611, + 25575, 25627, 25646, 25633, 25614, 25967, 26002, 26067, 26246, 26252, 26261, 26256, 26251, + 26250, 26265, 26260, 26232, 26400, 26982, 26975, 26936, 26958, 26978, 26993, 26943, 26949, + 26986, 26937, 26946, 26967, 26969, 27002, 26952, 26953, 26933, 26988, 26931, 26941, 26981, + 26864, 27000, 26932, 26985, 26944, 26991, 26948, 26998, 26968, 26945, 26996, 26956, 26939, + 26955, 26935, 26972, 26959, 26961, 26930, 26962, 26927, 27003, 26940, 27462, 27461, 27459, + 27458, 27464, 27457, 27547, 64013, 27643, 27644, 27641, 27639, 27640, 28315, 28374, 28360, + 28303, 28352, 28319, 28307, 28308, 28320, 28337, 28345, 28358, 28370, 28349, 28353, 28318, + 28361, 28343, 28336, 28365, 28326, 28367, 28338, 28350, 28355, 28380, 28376, 28313, 28306, + 28302, 28301, 28324, 28321, 28351, 28339, 28368, 28362, 28311, 28334, 28323, 28999, 29012, + 29010, 29027, 29024, 28993, 29021, 29026, 29042, 29048, 29034, 29025, 28994, 29016, 28995, + 29003, 29040, 29023, 29008, 29011, 28996, 29005, 29018, 29263, 29325, 29324, 29329, 29328, + 29326, 29500, 29506, 29499, 29498, 29504, 29514, 29513, 29764, 29770, 29771, 29778, 29777, + 29783, 29760, 29775, 29776, 29774, 29762, 29766, 29773, 29780, 29921, 29951, 29950, 29949, + 29981, 30073, 30071, 27011, 30191, 30223, 30211, 30199, 30206, 30204, 30201, 30200, 30224, + 30203, 30198, 30189, 30197, 30205, 30361, 30389, 30429, 30549, 30559, 30560, 30546, 30550, + 30554, 30569, 30567, 30548, 30553, 30573, 30688, 30855, 30874, 30868, 30863, 30852, 30869, + 30853, 30854, 30881, 30851, 30841, 30873, 30848, 30870, 30843, 31100, 31106, 31101, 31097, + 31249, 31256, 31257, 31250, 31255, 31253, 31266, 31251, 31259, 31248, 31395, 31394, 31390, + 31467, 31590, 31588, 31597, 31604, 31593, 31602, 31589, 31603, 31601, 31600, 31585, 31608, + 31606, 31587, 31922, 31924, 31919, 32136, 32134, 32128, 32141, 32127, 32133, 32122, 32142, + 32123, 32131, 32124, 32140, 32148, 32132, 32125, 32146, 32621, 32619, 32615, 32616, 32620, + 32678, 32677, 32679, 32731, 32732, 32801, 33124, 33120, 33143, 33116, 33129, 33115, 33122, + 33138, 26401, 33118, 33142, 33127, 33135, 33092, 33121, 33309, 33353, 33348, 33344, 33346, + 33349, 34033, 33855, 33878, 33910, 33913, 33935, 33933, 33893, 33873, 33856, 33926, 33895, + 33840, 33869, 33917, 33882, 33881, 33908, 33907, 33885, 34055, 33886, 33847, 33850, 33844, + 33914, 33859, 33912, 33842, 33861, 33833, 33753, 33867, 33839, 33858, 33837, 33887, 33904, + 33849, 33870, 33868, 33874, 33903, 33989, 33934, 33851, 33863, 33846, 33843, 33896, 33918, + 33860, 33835, 33888, 33876, 33902, 33872, 34571, 34564, 34551, 34572, 34554, 34518, 34549, + 34637, 34552, 34574, 34569, 34561, 34550, 34573, 34565, 35030, 35019, 35021, 35022, 35038, + 35035, 35034, 35020, 35024, 35205, 35227, 35295, 35301, 35300, 35297, 35296, 35298, 35292, + 35302, 35446, 35462, 35455, 35425, 35391, 35447, 35458, 35460, 35445, 35459, 35457, 35444, + 35450, 35900, 35915, 35914, 35941, 35940, 35942, 35974, 35972, 35973, 36044, 36200, 36201, + 36241, 36236, 36238, 36239, 36237, 36243, 36244, 36240, 36242, 36336, 36320, 36332, 36337, + 36334, 36304, 36329, 36323, 36322, 36327, 36338, 36331, 36340, 36614, 36607, 36609, 36608, + 36613, 36615, 36616, 36610, 36619, 36946, 36927, 36932, 36937, 36925, 37136, 37133, 37135, + 37137, 37142, 37140, 37131, 37134, 37230, 37231, 37448, 37458, 37424, 37434, 37478, 37427, + 37477, 37470, 37507, 37422, 37450, 37446, 37485, 37484, 37455, 37472, 37479, 37487, 37430, + 37473, 37488, 37425, 37460, 37475, 37456, 37490, 37454, 37459, 37452, 37462, 37426, 38303, + 38300, 38302, 38299, 38546, 38547, 38545, 38551, 38606, 38650, 38653, 38648, 38645, 38771, + 38775, 38776, 38770, 38927, 38925, 38926, 39084, 39158, 39161, 39343, 39346, 39344, 39349, + 39597, 39595, 39771, 40170, 40173, 40167, 40576, 40701, 20710, 20692, 20695, 20712, 20723, + 20699, 20714, 20701, 20708, 20691, 20716, 20720, 20719, 20707, 20704, 20952, 21120, 21121, + 21225, 21227, 21296, 21420, 22055, 22037, 22028, 22034, 22012, 22031, 22044, 22017, 22035, + 22018, 22010, 22045, 22020, 22015, 22009, 22665, 22652, 22672, 22680, 22662, 22657, 22655, + 22644, 22667, 22650, 22663, 22673, 22670, 22646, 22658, 22664, 22651, 22676, 22671, 22782, + 22891, 23260, 23278, 23269, 23253, 23274, 23258, 23277, 23275, 23283, 23266, 23264, 23259, + 23276, 23262, 23261, 23257, 23272, 23263, 23415, 23520, 23523, 23651, 23938, 23936, 23933, + 23942, 23930, 23937, 23927, 23946, 23945, 23944, 23934, 23932, 23949, 23929, 23935, 24152, + 24153, 24147, 24280, 24273, 24279, 24270, 24284, 24277, 24281, 24274, 24276, 24388, 24387, + 24431, 24502, 24876, 24872, 24897, 24926, 24945, 24947, 24914, 24915, 24946, 24940, 24960, + 24948, 24916, 24954, 24923, 24933, 24891, 24938, 24929, 24918, 25129, 25127, 25131, 25643, + 25677, 25691, 25693, 25716, 25718, 25714, 25715, 25725, 25717, 25702, 25766, 25678, 25730, + 25694, 25692, 25675, 25683, 25696, 25680, 25727, 25663, 25708, 25707, 25689, 25701, 25719, + 25971, 26016, 26273, 26272, 26271, 26373, 26372, 26402, 27057, 27062, 27081, 27040, 27086, + 27030, 27056, 27052, 27068, 27025, 27033, 27022, 27047, 27021, 27049, 27070, 27055, 27071, + 27076, 27069, 27044, 27092, 27065, 27082, 27034, 27087, 27059, 27027, 27050, 27041, 27038, + 27097, 27031, 27024, 27074, 27061, 27045, 27078, 27466, 27469, 27467, 27550, 27551, 27552, + 27587, 27588, 27646, 28366, 28405, 28401, 28419, 28453, 28408, 28471, 28411, 28462, 28425, + 28494, 28441, 28442, 28455, 28440, 28475, 28434, 28397, 28426, 28470, 28531, 28409, 28398, + 28461, 28480, 28464, 28476, 28469, 28395, 28423, 28430, 28483, 28421, 28413, 28406, 28473, + 28444, 28412, 28474, 28447, 28429, 28446, 28424, 28449, 29063, 29072, 29065, 29056, 29061, + 29058, 29071, 29051, 29062, 29057, 29079, 29252, 29267, 29335, 29333, 29331, 29507, 29517, + 29521, 29516, 29794, 29811, 29809, 29813, 29810, 29799, 29806, 29952, 29954, 29955, 30077, + 30096, 30230, 30216, 30220, 30229, 30225, 30218, 30228, 30392, 30593, 30588, 30597, 30594, + 30574, 30592, 30575, 30590, 30595, 30898, 30890, 30900, 30893, 30888, 30846, 30891, 30878, + 30885, 30880, 30892, 30882, 30884, 31128, 31114, 31115, 31126, 31125, 31124, 31123, 31127, + 31112, 31122, 31120, 31275, 31306, 31280, 31279, 31272, 31270, 31400, 31403, 31404, 31470, + 31624, 31644, 31626, 31633, 31632, 31638, 31629, 31628, 31643, 31630, 31621, 31640, 21124, + 31641, 31652, 31618, 31931, 31935, 31932, 31930, 32167, 32183, 32194, 32163, 32170, 32193, + 32192, 32197, 32157, 32206, 32196, 32198, 32203, 32204, 32175, 32185, 32150, 32188, 32159, + 32166, 32174, 32169, 32161, 32201, 32627, 32738, 32739, 32741, 32734, 32804, 32861, 32860, + 33161, 33158, 33155, 33159, 33165, 33164, 33163, 33301, 33943, 33956, 33953, 33951, 33978, + 33998, 33986, 33964, 33966, 33963, 33977, 33972, 33985, 33997, 33962, 33946, 33969, 34000, + 33949, 33959, 33979, 33954, 33940, 33991, 33996, 33947, 33961, 33967, 33960, 34006, 33944, + 33974, 33999, 33952, 34007, 34004, 34002, 34011, 33968, 33937, 34401, 34611, 34595, 34600, + 34667, 34624, 34606, 34590, 34593, 34585, 34587, 34627, 34604, 34625, 34622, 34630, 34592, + 34610, 34602, 34605, 34620, 34578, 34618, 34609, 34613, 34626, 34598, 34599, 34616, 34596, + 34586, 34608, 34577, 35063, 35047, 35057, 35058, 35066, 35070, 35054, 35068, 35062, 35067, + 35056, 35052, 35051, 35229, 35233, 35231, 35230, 35305, 35307, 35304, 35499, 35481, 35467, + 35474, 35471, 35478, 35901, 35944, 35945, 36053, 36047, 36055, 36246, 36361, 36354, 36351, + 36365, 36349, 36362, 36355, 36359, 36358, 36357, 36350, 36352, 36356, 36624, 36625, 36622, + 36621, 37155, 37148, 37152, 37154, 37151, 37149, 37146, 37156, 37153, 37147, 37242, 37234, + 37241, 37235, 37541, 37540, 37494, 37531, 37498, 37536, 37524, 37546, 37517, 37542, 37530, + 37547, 37497, 37527, 37503, 37539, 37614, 37518, 37506, 37525, 37538, 37501, 37512, 37537, + 37514, 37510, 37516, 37529, 37543, 37502, 37511, 37545, 37533, 37515, 37421, 38558, 38561, + 38655, 38744, 38781, 38778, 38782, 38787, 38784, 38786, 38779, 38788, 38785, 38783, 38862, + 38861, 38934, 39085, 39086, 39170, 39168, 39175, 39325, 39324, 39363, 39353, 39355, 39354, + 39362, 39357, 39367, 39601, 39651, 39655, 39742, 39743, 39776, 39777, 39775, 40177, 40178, + 40181, 40615, 20735, 20739, 20784, 20728, 20742, 20743, 20726, 20734, 20747, 20748, 20733, + 20746, 21131, 21132, 21233, 21231, 22088, 22082, 22092, 22069, 22081, 22090, 22089, 22086, + 22104, 22106, 22080, 22067, 22077, 22060, 22078, 22072, 22058, 22074, 22298, 22699, 22685, + 22705, 22688, 22691, 22703, 22700, 22693, 22689, 22783, 23295, 23284, 23293, 23287, 23286, + 23299, 23288, 23298, 23289, 23297, 23303, 23301, 23311, 23655, 23961, 23959, 23967, 23954, + 23970, 23955, 23957, 23968, 23964, 23969, 23962, 23966, 24169, 24157, 24160, 24156, 32243, + 24283, 24286, 24289, 24393, 24498, 24971, 24963, 24953, 25009, 25008, 24994, 24969, 24987, + 24979, 25007, 25005, 24991, 24978, 25002, 24993, 24973, 24934, 25011, 25133, 25710, 25712, + 25750, 25760, 25733, 25751, 25756, 25743, 25739, 25738, 25740, 25763, 25759, 25704, 25777, + 25752, 25974, 25978, 25977, 25979, 26034, 26035, 26293, 26288, 26281, 26290, 26295, 26282, + 26287, 27136, 27142, 27159, 27109, 27128, 27157, 27121, 27108, 27168, 27135, 27116, 27106, + 27163, 27165, 27134, 27175, 27122, 27118, 27156, 27127, 27111, 27200, 27144, 27110, 27131, + 27149, 27132, 27115, 27145, 27140, 27160, 27173, 27151, 27126, 27174, 27143, 27124, 27158, + 27473, 27557, 27555, 27554, 27558, 27649, 27648, 27647, 27650, 28481, 28454, 28542, 28551, + 28614, 28562, 28557, 28553, 28556, 28514, 28495, 28549, 28506, 28566, 28534, 28524, 28546, + 28501, 28530, 28498, 28496, 28503, 28564, 28563, 28509, 28416, 28513, 28523, 28541, 28519, + 28560, 28499, 28555, 28521, 28543, 28565, 28515, 28535, 28522, 28539, 29106, 29103, 29083, + 29104, 29088, 29082, 29097, 29109, 29085, 29093, 29086, 29092, 29089, 29098, 29084, 29095, + 29107, 29336, 29338, 29528, 29522, 29534, 29535, 29536, 29533, 29531, 29537, 29530, 29529, + 29538, 29831, 29833, 29834, 29830, 29825, 29821, 29829, 29832, 29820, 29817, 29960, 29959, + 30078, 30245, 30238, 30233, 30237, 30236, 30243, 30234, 30248, 30235, 30364, 30365, 30366, + 30363, 30605, 30607, 30601, 30600, 30925, 30907, 30927, 30924, 30929, 30926, 30932, 30920, + 30915, 30916, 30921, 31130, 31137, 31136, 31132, 31138, 31131, 27510, 31289, 31410, 31412, + 31411, 31671, 31691, 31678, 31660, 31694, 31663, 31673, 31690, 31669, 31941, 31944, 31948, + 31947, 32247, 32219, 32234, 32231, 32215, 32225, 32259, 32250, 32230, 32246, 32241, 32240, + 32238, 32223, 32630, 32684, 32688, 32685, 32749, 32747, 32746, 32748, 32742, 32744, 32868, + 32871, 33187, 33183, 33182, 33173, 33186, 33177, 33175, 33302, 33359, 33363, 33362, 33360, + 33358, 33361, 34084, 34107, 34063, 34048, 34089, 34062, 34057, 34061, 34079, 34058, 34087, + 34076, 34043, 34091, 34042, 34056, 34060, 34036, 34090, 34034, 34069, 34039, 34027, 34035, + 34044, 34066, 34026, 34025, 34070, 34046, 34088, 34077, 34094, 34050, 34045, 34078, 34038, + 34097, 34086, 34023, 34024, 34032, 34031, 34041, 34072, 34080, 34096, 34059, 34073, 34095, + 34402, 34646, 34659, 34660, 34679, 34785, 34675, 34648, 34644, 34651, 34642, 34657, 34650, + 34641, 34654, 34669, 34666, 34640, 34638, 34655, 34653, 34671, 34668, 34682, 34670, 34652, + 34661, 34639, 34683, 34677, 34658, 34663, 34665, 34906, 35077, 35084, 35092, 35083, 35095, + 35096, 35097, 35078, 35094, 35089, 35086, 35081, 35234, 35236, 35235, 35309, 35312, 35308, + 35535, 35526, 35512, 35539, 35537, 35540, 35541, 35515, 35543, 35518, 35520, 35525, 35544, + 35523, 35514, 35517, 35545, 35902, 35917, 35983, 36069, 36063, 36057, 36072, 36058, 36061, + 36071, 36256, 36252, 36257, 36251, 36384, 36387, 36389, 36388, 36398, 36373, 36379, 36374, + 36369, 36377, 36390, 36391, 36372, 36370, 36376, 36371, 36380, 36375, 36378, 36652, 36644, + 36632, 36634, 36640, 36643, 36630, 36631, 36979, 36976, 36975, 36967, 36971, 37167, 37163, + 37161, 37162, 37170, 37158, 37166, 37253, 37254, 37258, 37249, 37250, 37252, 37248, 37584, + 37571, 37572, 37568, 37593, 37558, 37583, 37617, 37599, 37592, 37609, 37591, 37597, 37580, + 37615, 37570, 37608, 37578, 37576, 37582, 37606, 37581, 37589, 37577, 37600, 37598, 37607, + 37585, 37587, 37557, 37601, 37574, 37556, 38268, 38316, 38315, 38318, 38320, 38564, 38562, + 38611, 38661, 38664, 38658, 38746, 38794, 38798, 38792, 38864, 38863, 38942, 38941, 38950, + 38953, 38952, 38944, 38939, 38951, 39090, 39176, 39162, 39185, 39188, 39190, 39191, 39189, + 39388, 39373, 39375, 39379, 39380, 39374, 39369, 39382, 39384, 39371, 39383, 39372, 39603, + 39660, 39659, 39667, 39666, 39665, 39750, 39747, 39783, 39796, 39793, 39782, 39798, 39797, + 39792, 39784, 39780, 39788, 40188, 40186, 40189, 40191, 40183, 40199, 40192, 40185, 40187, + 40200, 40197, 40196, 40579, 40659, 40719, 40720, 20764, 20755, 20759, 20762, 20753, 20958, + 21300, 21473, 22128, 22112, 22126, 22131, 22118, 22115, 22125, 22130, 22110, 22135, 22300, + 22299, 22728, 22717, 22729, 22719, 22714, 22722, 22716, 22726, 23319, 23321, 23323, 23329, + 23316, 23315, 23312, 23318, 23336, 23322, 23328, 23326, 23535, 23980, 23985, 23977, 23975, + 23989, 23984, 23982, 23978, 23976, 23986, 23981, 23983, 23988, 24167, 24168, 24166, 24175, + 24297, 24295, 24294, 24296, 24293, 24395, 24508, 24989, 25000, 24982, 25029, 25012, 25030, + 25025, 25036, 25018, 25023, 25016, 24972, 25815, 25814, 25808, 25807, 25801, 25789, 25737, + 25795, 25819, 25843, 25817, 25907, 25983, 25980, 26018, 26312, 26302, 26304, 26314, 26315, + 26319, 26301, 26299, 26298, 26316, 26403, 27188, 27238, 27209, 27239, 27186, 27240, 27198, + 27229, 27245, 27254, 27227, 27217, 27176, 27226, 27195, 27199, 27201, 27242, 27236, 27216, + 27215, 27220, 27247, 27241, 27232, 27196, 27230, 27222, 27221, 27213, 27214, 27206, 27477, + 27476, 27478, 27559, 27562, 27563, 27592, 27591, 27652, 27651, 27654, 28589, 28619, 28579, + 28615, 28604, 28622, 28616, 28510, 28612, 28605, 28574, 28618, 28584, 28676, 28581, 28590, + 28602, 28588, 28586, 28623, 28607, 28600, 28578, 28617, 28587, 28621, 28591, 28594, 28592, + 29125, 29122, 29119, 29112, 29142, 29120, 29121, 29131, 29140, 29130, 29127, 29135, 29117, + 29144, 29116, 29126, 29146, 29147, 29341, 29342, 29545, 29542, 29543, 29548, 29541, 29547, + 29546, 29823, 29850, 29856, 29844, 29842, 29845, 29857, 29963, 30080, 30255, 30253, 30257, + 30269, 30259, 30268, 30261, 30258, 30256, 30395, 30438, 30618, 30621, 30625, 30620, 30619, + 30626, 30627, 30613, 30617, 30615, 30941, 30953, 30949, 30954, 30942, 30947, 30939, 30945, + 30946, 30957, 30943, 30944, 31140, 31300, 31304, 31303, 31414, 31416, 31413, 31409, 31415, + 31710, 31715, 31719, 31709, 31701, 31717, 31706, 31720, 31737, 31700, 31722, 31714, 31708, + 31723, 31704, 31711, 31954, 31956, 31959, 31952, 31953, 32274, 32289, 32279, 32268, 32287, + 32288, 32275, 32270, 32284, 32277, 32282, 32290, 32267, 32271, 32278, 32269, 32276, 32293, + 32292, 32579, 32635, 32636, 32634, 32689, 32751, 32810, 32809, 32876, 33201, 33190, 33198, + 33209, 33205, 33195, 33200, 33196, 33204, 33202, 33207, 33191, 33266, 33365, 33366, 33367, + 34134, 34117, 34155, 34125, 34131, 34145, 34136, 34112, 34118, 34148, 34113, 34146, 34116, + 34129, 34119, 34147, 34110, 34139, 34161, 34126, 34158, 34165, 34133, 34151, 34144, 34188, + 34150, 34141, 34132, 34149, 34156, 34403, 34405, 34404, 34715, 34703, 34711, 34707, 34706, + 34696, 34689, 34710, 34712, 34681, 34695, 34723, 34693, 34704, 34705, 34717, 34692, 34708, + 34716, 34714, 34697, 35102, 35110, 35120, 35117, 35118, 35111, 35121, 35106, 35113, 35107, + 35119, 35116, 35103, 35313, 35552, 35554, 35570, 35572, 35573, 35549, 35604, 35556, 35551, + 35568, 35528, 35550, 35553, 35560, 35583, 35567, 35579, 35985, 35986, 35984, 36085, 36078, + 36081, 36080, 36083, 36204, 36206, 36261, 36263, 36403, 36414, 36408, 36416, 36421, 36406, + 36412, 36413, 36417, 36400, 36415, 36541, 36662, 36654, 36661, 36658, 36665, 36663, 36660, + 36982, 36985, 36987, 36998, 37114, 37171, 37173, 37174, 37267, 37264, 37265, 37261, 37263, + 37671, 37662, 37640, 37663, 37638, 37647, 37754, 37688, 37692, 37659, 37667, 37650, 37633, + 37702, 37677, 37646, 37645, 37579, 37661, 37626, 37669, 37651, 37625, 37623, 37684, 37634, + 37668, 37631, 37673, 37689, 37685, 37674, 37652, 37644, 37643, 37630, 37641, 37632, 37627, + 37654, 38332, 38349, 38334, 38329, 38330, 38326, 38335, 38325, 38333, 38569, 38612, 38667, + 38674, 38672, 38809, 38807, 38804, 38896, 38904, 38965, 38959, 38962, 39204, 39199, 39207, + 39209, 39326, 39406, 39404, 39397, 39396, 39408, 39395, 39402, 39401, 39399, 39609, 39615, + 39604, 39611, 39670, 39674, 39673, 39671, 39731, 39808, 39813, 39815, 39804, 39806, 39803, + 39810, 39827, 39826, 39824, 39802, 39829, 39805, 39816, 40229, 40215, 40224, 40222, 40212, + 40233, 40221, 40216, 40226, 40208, 40217, 40223, 40584, 40582, 40583, 40622, 40621, 40661, + 40662, 40698, 40722, 40765, 20774, 20773, 20770, 20772, 20768, 20777, 21236, 22163, 22156, + 22157, 22150, 22148, 22147, 22142, 22146, 22143, 22145, 22742, 22740, 22735, 22738, 23341, + 23333, 23346, 23331, 23340, 23335, 23334, 23343, 23342, 23419, 23537, 23538, 23991, 24172, + 24170, 24510, 24507, 25027, 25013, 25020, 25063, 25056, 25061, 25060, 25064, 25054, 25839, + 25833, 25827, 25835, 25828, 25832, 25985, 25984, 26038, 26074, 26322, 27277, 27286, 27265, + 27301, 27273, 27295, 27291, 27297, 27294, 27271, 27283, 27278, 27285, 27267, 27304, 27300, + 27281, 27263, 27302, 27290, 27269, 27276, 27282, 27483, 27565, 27657, 28620, 28585, 28660, + 28628, 28643, 28636, 28653, 28647, 28646, 28638, 28658, 28637, 28642, 28648, 29153, 29169, + 29160, 29170, 29156, 29168, 29154, 29555, 29550, 29551, 29847, 29874, 29867, 29840, 29866, + 29869, 29873, 29861, 29871, 29968, 29969, 29970, 29967, 30084, 30275, 30280, 30281, 30279, + 30372, 30441, 30645, 30635, 30642, 30647, 30646, 30644, 30641, 30632, 30704, 30963, 30973, + 30978, 30971, 30972, 30962, 30981, 30969, 30974, 30980, 31147, 31144, 31324, 31323, 31318, + 31320, 31316, 31322, 31422, 31424, 31425, 31749, 31759, 31730, 31744, 31743, 31739, 31758, + 31732, 31755, 31731, 31746, 31753, 31747, 31745, 31736, 31741, 31750, 31728, 31729, 31760, + 31754, 31976, 32301, 32316, 32322, 32307, 38984, 32312, 32298, 32329, 32320, 32327, 32297, + 32332, 32304, 32315, 32310, 32324, 32314, 32581, 32639, 32638, 32637, 32756, 32754, 32812, + 33211, 33220, 33228, 33226, 33221, 33223, 33212, 33257, 33371, 33370, 33372, 34179, 34176, + 34191, 34215, 34197, 34208, 34187, 34211, 34171, 34212, 34202, 34206, 34167, 34172, 34185, + 34209, 34170, 34168, 34135, 34190, 34198, 34182, 34189, 34201, 34205, 34177, 34210, 34178, + 34184, 34181, 34169, 34166, 34200, 34192, 34207, 34408, 34750, 34730, 34733, 34757, 34736, + 34732, 34745, 34741, 34748, 34734, 34761, 34755, 34754, 34764, 34743, 34735, 34756, 34762, + 34740, 34742, 34751, 34744, 34749, 34782, 34738, 35125, 35123, 35132, 35134, 35137, 35154, + 35127, 35138, 35245, 35247, 35246, 35314, 35315, 35614, 35608, 35606, 35601, 35589, 35595, + 35618, 35599, 35602, 35605, 35591, 35597, 35592, 35590, 35612, 35603, 35610, 35919, 35952, + 35954, 35953, 35951, 35989, 35988, 36089, 36207, 36430, 36429, 36435, 36432, 36428, 36423, + 36675, 36672, 36997, 36990, 37176, 37274, 37282, 37275, 37273, 37279, 37281, 37277, 37280, + 37793, 37763, 37807, 37732, 37718, 37703, 37756, 37720, 37724, 37750, 37705, 37712, 37713, + 37728, 37741, 37775, 37708, 37738, 37753, 37719, 37717, 37714, 37711, 37745, 37751, 37755, + 37729, 37726, 37731, 37735, 37760, 37710, 37721, 38343, 38336, 38345, 38339, 38341, 38327, + 38574, 38576, 38572, 38688, 38687, 38680, 38685, 38681, 38810, 38817, 38812, 38814, 38813, + 38869, 38868, 38897, 38977, 38980, 38986, 38985, 38981, 38979, 39205, 39211, 39212, 39210, + 39219, 39218, 39215, 39213, 39217, 39216, 39320, 39331, 39329, 39426, 39418, 39412, 39415, + 39417, 39416, 39414, 39419, 39421, 39422, 39420, 39427, 39614, 39678, 39677, 39681, 39676, + 39752, 39834, 39848, 39838, 39835, 39846, 39841, 39845, 39844, 39814, 39842, 39840, 39855, + 40243, 40257, 40295, 40246, 40238, 40239, 40241, 40248, 40240, 40261, 40258, 40259, 40254, + 40247, 40256, 40253, 32757, 40237, 40586, 40585, 40589, 40624, 40648, 40666, 40699, 40703, + 40740, 40739, 40738, 40788, 40864, 20785, 20781, 20782, 22168, 22172, 22167, 22170, 22173, + 22169, 22896, 23356, 23657, 23658, 24000, 24173, 24174, 25048, 25055, 25069, 25070, 25073, + 25066, 25072, 25067, 25046, 25065, 25855, 25860, 25853, 25848, 25857, 25859, 25852, 26004, + 26075, 26330, 26331, 26328, 27333, 27321, 27325, 27361, 27334, 27322, 27318, 27319, 27335, + 27316, 27309, 27486, 27593, 27659, 28679, 28684, 28685, 28673, 28677, 28692, 28686, 28671, + 28672, 28667, 28710, 28668, 28663, 28682, 29185, 29183, 29177, 29187, 29181, 29558, 29880, + 29888, 29877, 29889, 29886, 29878, 29883, 29890, 29972, 29971, 30300, 30308, 30297, 30288, + 30291, 30295, 30298, 30374, 30397, 30444, 30658, 30650, 30975, 30988, 30995, 30996, 30985, + 30992, 30994, 30993, 31149, 31148, 31327, 31772, 31785, 31769, 31776, 31775, 31789, 31773, + 31782, 31784, 31778, 31781, 31792, 32348, 32336, 32342, 32355, 32344, 32354, 32351, 32337, + 32352, 32343, 32339, 32693, 32691, 32759, 32760, 32885, 33233, 33234, 33232, 33375, 33374, + 34228, 34246, 34240, 34243, 34242, 34227, 34229, 34237, 34247, 34244, 34239, 34251, 34254, + 34248, 34245, 34225, 34230, 34258, 34340, 34232, 34231, 34238, 34409, 34791, 34790, 34786, + 34779, 34795, 34794, 34789, 34783, 34803, 34788, 34772, 34780, 34771, 34797, 34776, 34787, + 34724, 34775, 34777, 34817, 34804, 34792, 34781, 35155, 35147, 35151, 35148, 35142, 35152, + 35153, 35145, 35626, 35623, 35619, 35635, 35632, 35637, 35655, 35631, 35644, 35646, 35633, + 35621, 35639, 35622, 35638, 35630, 35620, 35643, 35645, 35642, 35906, 35957, 35993, 35992, + 35991, 36094, 36100, 36098, 36096, 36444, 36450, 36448, 36439, 36438, 36446, 36453, 36455, + 36443, 36442, 36449, 36445, 36457, 36436, 36678, 36679, 36680, 36683, 37160, 37178, 37179, + 37182, 37288, 37285, 37287, 37295, 37290, 37813, 37772, 37778, 37815, 37787, 37789, 37769, + 37799, 37774, 37802, 37790, 37798, 37781, 37768, 37785, 37791, 37773, 37809, 37777, 37810, + 37796, 37800, 37812, 37795, 37797, 38354, 38355, 38353, 38579, 38615, 38618, 24002, 38623, + 38616, 38621, 38691, 38690, 38693, 38828, 38830, 38824, 38827, 38820, 38826, 38818, 38821, + 38871, 38873, 38870, 38872, 38906, 38992, 38993, 38994, 39096, 39233, 39228, 39226, 39439, + 39435, 39433, 39437, 39428, 39441, 39434, 39429, 39431, 39430, 39616, 39644, 39688, 39684, + 39685, 39721, 39733, 39754, 39756, 39755, 39879, 39878, 39875, 39871, 39873, 39861, 39864, + 39891, 39862, 39876, 39865, 39869, 40284, 40275, 40271, 40266, 40283, 40267, 40281, 40278, + 40268, 40279, 40274, 40276, 40287, 40280, 40282, 40590, 40588, 40671, 40705, 40704, 40726, + 40741, 40747, 40746, 40745, 40744, 40780, 40789, 20788, 20789, 21142, 21239, 21428, 22187, + 22189, 22182, 22183, 22186, 22188, 22746, 22749, 22747, 22802, 23357, 23358, 23359, 24003, + 24176, 24511, 25083, 25863, 25872, 25869, 25865, 25868, 25870, 25988, 26078, 26077, 26334, + 27367, 27360, 27340, 27345, 27353, 27339, 27359, 27356, 27344, 27371, 27343, 27341, 27358, + 27488, 27568, 27660, 28697, 28711, 28704, 28694, 28715, 28705, 28706, 28707, 28713, 28695, + 28708, 28700, 28714, 29196, 29194, 29191, 29186, 29189, 29349, 29350, 29348, 29347, 29345, + 29899, 29893, 29879, 29891, 29974, 30304, 30665, 30666, 30660, 30705, 31005, 31003, 31009, + 31004, 30999, 31006, 31152, 31335, 31336, 31795, 31804, 31801, 31788, 31803, 31980, 31978, + 32374, 32373, 32376, 32368, 32375, 32367, 32378, 32370, 32372, 32360, 32587, 32586, 32643, + 32646, 32695, 32765, 32766, 32888, 33239, 33237, 33380, 33377, 33379, 34283, 34289, 34285, + 34265, 34273, 34280, 34266, 34263, 34284, 34290, 34296, 34264, 34271, 34275, 34268, 34257, + 34288, 34278, 34287, 34270, 34274, 34816, 34810, 34819, 34806, 34807, 34825, 34828, 34827, + 34822, 34812, 34824, 34815, 34826, 34818, 35170, 35162, 35163, 35159, 35169, 35164, 35160, + 35165, 35161, 35208, 35255, 35254, 35318, 35664, 35656, 35658, 35648, 35667, 35670, 35668, + 35659, 35669, 35665, 35650, 35666, 35671, 35907, 35959, 35958, 35994, 36102, 36103, 36105, + 36268, 36266, 36269, 36267, 36461, 36472, 36467, 36458, 36463, 36475, 36546, 36690, 36689, + 36687, 36688, 36691, 36788, 37184, 37183, 37296, 37293, 37854, 37831, 37839, 37826, 37850, + 37840, 37881, 37868, 37836, 37849, 37801, 37862, 37834, 37844, 37870, 37859, 37845, 37828, + 37838, 37824, 37842, 37863, 38269, 38362, 38363, 38625, 38697, 38699, 38700, 38696, 38694, + 38835, 38839, 38838, 38877, 38878, 38879, 39004, 39001, 39005, 38999, 39103, 39101, 39099, + 39102, 39240, 39239, 39235, 39334, 39335, 39450, 39445, 39461, 39453, 39460, 39451, 39458, + 39456, 39463, 39459, 39454, 39452, 39444, 39618, 39691, 39690, 39694, 39692, 39735, 39914, + 39915, 39904, 39902, 39908, 39910, 39906, 39920, 39892, 39895, 39916, 39900, 39897, 39909, + 39893, 39905, 39898, 40311, 40321, 40330, 40324, 40328, 40305, 40320, 40312, 40326, 40331, + 40332, 40317, 40299, 40308, 40309, 40304, 40297, 40325, 40307, 40315, 40322, 40303, 40313, + 40319, 40327, 40296, 40596, 40593, 40640, 40700, 40749, 40768, 40769, 40781, 40790, 40791, + 40792, 21303, 22194, 22197, 22195, 22755, 23365, 24006, 24007, 24302, 24303, 24512, 24513, + 25081, 25879, 25878, 25877, 25875, 26079, 26344, 26339, 26340, 27379, 27376, 27370, 27368, + 27385, 27377, 27374, 27375, 28732, 28725, 28719, 28727, 28724, 28721, 28738, 28728, 28735, + 28730, 28729, 28736, 28731, 28723, 28737, 29203, 29204, 29352, 29565, 29564, 29882, 30379, + 30378, 30398, 30445, 30668, 30670, 30671, 30669, 30706, 31013, 31011, 31015, 31016, 31012, + 31017, 31154, 31342, 31340, 31341, 31479, 31817, 31816, 31818, 31815, 31813, 31982, 32379, + 32382, 32385, 32384, 32698, 32767, 32889, 33243, 33241, 33291, 33384, 33385, 34338, 34303, + 34305, 34302, 34331, 34304, 34294, 34308, 34313, 34309, 34316, 34301, 34841, 34832, 34833, + 34839, 34835, 34838, 35171, 35174, 35257, 35319, 35680, 35690, 35677, 35688, 35683, 35685, + 35687, 35693, 36270, 36486, 36488, 36484, 36697, 36694, 36695, 36693, 36696, 36698, 37005, + 37187, 37185, 37303, 37301, 37298, 37299, 37899, 37907, 37883, 37920, 37903, 37908, 37886, + 37909, 37904, 37928, 37913, 37901, 37877, 37888, 37879, 37895, 37902, 37910, 37906, 37882, + 37897, 37880, 37898, 37887, 37884, 37900, 37878, 37905, 37894, 38366, 38368, 38367, 38702, + 38703, 38841, 38843, 38909, 38910, 39008, 39010, 39011, 39007, 39105, 39106, 39248, 39246, + 39257, 39244, 39243, 39251, 39474, 39476, 39473, 39468, 39466, 39478, 39465, 39470, 39480, + 39469, 39623, 39626, 39622, 39696, 39698, 39697, 39947, 39944, 39927, 39941, 39954, 39928, + 40000, 39943, 39950, 39942, 39959, 39956, 39945, 40351, 40345, 40356, 40349, 40338, 40344, + 40336, 40347, 40352, 40340, 40348, 40362, 40343, 40353, 40346, 40354, 40360, 40350, 40355, + 40383, 40361, 40342, 40358, 40359, 40601, 40603, 40602, 40677, 40676, 40679, 40678, 40752, + 40750, 40795, 40800, 40798, 40797, 40793, 40849, 20794, 20793, 21144, 21143, 22211, 22205, + 22206, 23368, 23367, 24011, 24015, 24305, 25085, 25883, 27394, 27388, 27395, 27384, 27392, + 28739, 28740, 28746, 28744, 28745, 28741, 28742, 29213, 29210, 29209, 29566, 29975, 30314, + 30672, 31021, 31025, 31023, 31828, 31827, 31986, 32394, 32391, 32392, 32395, 32390, 32397, + 32589, 32699, 32816, 33245, 34328, 34346, 34342, 34335, 34339, 34332, 34329, 34343, 34350, + 34337, 34336, 34345, 34334, 34341, 34857, 34845, 34843, 34848, 34852, 34844, 34859, 34890, + 35181, 35177, 35182, 35179, 35322, 35705, 35704, 35653, 35706, 35707, 36112, 36116, 36271, + 36494, 36492, 36702, 36699, 36701, 37190, 37188, 37189, 37305, 37951, 37947, 37942, 37929, + 37949, 37948, 37936, 37945, 37930, 37943, 37932, 37952, 37937, 38373, 38372, 38371, 38709, + 38714, 38847, 38881, 39012, 39113, 39110, 39104, 39256, 39254, 39481, 39485, 39494, 39492, + 39490, 39489, 39482, 39487, 39629, 39701, 39703, 39704, 39702, 39738, 39762, 39979, 39965, + 39964, 39980, 39971, 39976, 39977, 39972, 39969, 40375, 40374, 40380, 40385, 40391, 40394, + 40399, 40382, 40389, 40387, 40379, 40373, 40398, 40377, 40378, 40364, 40392, 40369, 40365, + 40396, 40371, 40397, 40370, 40570, 40604, 40683, 40686, 40685, 40731, 40728, 40730, 40753, + 40782, 40805, 40804, 40850, 20153, 22214, 22213, 22219, 22897, 23371, 23372, 24021, 24017, + 24306, 25889, 25888, 25894, 25890, 27403, 27400, 27401, 27661, 28757, 28758, 28759, 28754, + 29214, 29215, 29353, 29567, 29912, 29909, 29913, 29911, 30317, 30381, 31029, 31156, 31344, + 31345, 31831, 31836, 31833, 31835, 31834, 31988, 31985, 32401, 32591, 32647, 33246, 33387, + 34356, 34357, 34355, 34348, 34354, 34358, 34860, 34856, 34854, 34858, 34853, 35185, 35263, + 35262, 35323, 35710, 35716, 35714, 35718, 35717, 35711, 36117, 36501, 36500, 36506, 36498, + 36496, 36502, 36503, 36704, 36706, 37191, 37964, 37968, 37962, 37963, 37967, 37959, 37957, + 37960, 37961, 37958, 38719, 38883, 39018, 39017, 39115, 39252, 39259, 39502, 39507, 39508, + 39500, 39503, 39496, 39498, 39497, 39506, 39504, 39632, 39705, 39723, 39739, 39766, 39765, + 40006, 40008, 39999, 40004, 39993, 39987, 40001, 39996, 39991, 39988, 39986, 39997, 39990, + 40411, 40402, 40414, 40410, 40395, 40400, 40412, 40401, 40415, 40425, 40409, 40408, 40406, + 40437, 40405, 40413, 40630, 40688, 40757, 40755, 40754, 40770, 40811, 40853, 40866, 20797, + 21145, 22760, 22759, 22898, 23373, 24024, 34863, 24399, 25089, 25091, 25092, 25897, 25893, + 26006, 26347, 27409, 27410, 27407, 27594, 28763, 28762, 29218, 29570, 29569, 29571, 30320, + 30676, 31847, 31846, 32405, 33388, 34362, 34368, 34361, 34364, 34353, 34363, 34366, 34864, + 34866, 34862, 34867, 35190, 35188, 35187, 35326, 35724, 35726, 35723, 35720, 35909, 36121, + 36504, 36708, 36707, 37308, 37986, 37973, 37981, 37975, 37982, 38852, 38853, 38912, 39510, + 39513, 39710, 39711, 39712, 40018, 40024, 40016, 40010, 40013, 40011, 40021, 40025, 40012, + 40014, 40443, 40439, 40431, 40419, 40427, 40440, 40420, 40438, 40417, 40430, 40422, 40434, + 40432, 40418, 40428, 40436, 40435, 40424, 40429, 40642, 40656, 40690, 40691, 40710, 40732, + 40760, 40759, 40758, 40771, 40783, 40817, 40816, 40814, 40815, 22227, 22221, 23374, 23661, + 25901, 26349, 26350, 27411, 28767, 28769, 28765, 28768, 29219, 29915, 29925, 30677, 31032, + 31159, 31158, 31850, 32407, 32649, 33389, 34371, 34872, 34871, 34869, 34891, 35732, 35733, + 36510, 36511, 36512, 36509, 37310, 37309, 37314, 37995, 37992, 37993, 38629, 38726, 38723, + 38727, 38855, 38885, 39518, 39637, 39769, 40035, 40039, 40038, 40034, 40030, 40032, 40450, + 40446, 40455, 40451, 40454, 40453, 40448, 40449, 40457, 40447, 40445, 40452, 40608, 40734, + 40774, 40820, 40821, 40822, 22228, 25902, 26040, 27416, 27417, 27415, 27418, 28770, 29222, + 29354, 30680, 30681, 31033, 31849, 31851, 31990, 32410, 32408, 32411, 32409, 33248, 33249, + 34374, 34375, 34376, 35193, 35194, 35196, 35195, 35327, 35736, 35737, 36517, 36516, 36515, + 37998, 37997, 37999, 38001, 38003, 38729, 39026, 39263, 40040, 40046, 40045, 40459, 40461, + 40464, 40463, 40466, 40465, 40609, 40693, 40713, 40775, 40824, 40827, 40826, 40825, 22302, + 28774, 31855, 34876, 36274, 36518, 37315, 38004, 38008, 38006, 38005, 39520, 40052, 40051, + 40049, 40053, 40468, 40467, 40694, 40714, 40868, 28776, 28773, 31991, 34410, 34878, 34877, + 34879, 35742, 35996, 36521, 36553, 38731, 39027, 39028, 39116, 39265, 39339, 39524, 39526, + 39527, 39716, 40469, 40471, 40776, 25095, 27422, 29223, 34380, 36520, 38018, 38016, 38017, + 39529, 39528, 39726, 40473, 29225, 34379, 35743, 38019, 40057, 40631, 30325, 39531, 40058, + 40477, 28777, 28778, 40612, 40830, 40777, 40856, 30849, 37561, 35023, 22715, 24658, 31911, + 23290, 9556, 9574, 9559, 9568, 9580, 9571, 9562, 9577, 9565, 9554, 9572, 9557, 9566, 9578, 9569, + 9560, 9575, 9563, 9555, 9573, 9558, 9567, 9579, 9570, 9561, 9576, 9564, 9553, 9552, 9581, 9582, + 9584, 9583, 9619, diff --git a/third_party/ulib/musl/src/locale/bind_textdomain_codeset.c b/third_party/ulib/musl/src/locale/bind_textdomain_codeset.c new file mode 100644 index 000000000..0581ef268 --- /dev/null +++ b/third_party/ulib/musl/src/locale/bind_textdomain_codeset.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include + +char* bind_textdomain_codeset(const char* domainname, const char* codeset) { + if (codeset && strcasecmp(codeset, "UTF-8")) errno = EINVAL; + return NULL; +} diff --git a/third_party/ulib/musl/src/locale/c_locale.c b/third_party/ulib/musl/src/locale/c_locale.c new file mode 100644 index 000000000..992fa2c77 --- /dev/null +++ b/third_party/ulib/musl/src/locale/c_locale.c @@ -0,0 +1,10 @@ +#include "locale_impl.h" +#include + +static const uint32_t empty_mo[] = {0x950412de, 0, -1, -1, -1}; + +const struct __locale_map __c_dot_utf8 = { + .map = empty_mo, .map_size = sizeof empty_mo, .name = "C.UTF-8"}; + +const struct __locale_struct __c_locale = {0}; +const struct __locale_struct __c_dot_utf8_locale = {.cat[LC_CTYPE] = &__c_dot_utf8}; diff --git a/third_party/ulib/musl/src/locale/catclose.c b/third_party/ulib/musl/src/locale/catclose.c new file mode 100644 index 000000000..c932f3026 --- /dev/null +++ b/third_party/ulib/musl/src/locale/catclose.c @@ -0,0 +1,5 @@ +#include + +int catclose(nl_catd catd) { + return 0; +} diff --git a/third_party/ulib/musl/src/locale/catgets.c b/third_party/ulib/musl/src/locale/catgets.c new file mode 100644 index 000000000..07c6c6914 --- /dev/null +++ b/third_party/ulib/musl/src/locale/catgets.c @@ -0,0 +1,5 @@ +#include + +char* catgets(nl_catd catd, int set_id, int msg_id, const char* s) { + return (char*)s; +} diff --git a/third_party/ulib/musl/src/locale/catopen.c b/third_party/ulib/musl/src/locale/catopen.c new file mode 100644 index 000000000..03ab4be7d --- /dev/null +++ b/third_party/ulib/musl/src/locale/catopen.c @@ -0,0 +1,5 @@ +#include + +nl_catd catopen(const char* name, int oflag) { + return (nl_catd)-1; +} diff --git a/third_party/ulib/musl/src/locale/codepages.h b/third_party/ulib/musl/src/locale/codepages.h new file mode 100644 index 000000000..1e2b0a7d7 --- /dev/null +++ b/third_party/ulib/musl/src/locale/codepages.h @@ -0,0 +1,264 @@ +"iso88591\0" + "latin1\0" + "\0\200" + + "iso88592\0" + "\0\40" + "\0\330\20\313\32\0\244\21\10\0\0\34\122\310\42\240\0\100\212\50\0\334\60\13\33" + "\0\250\41\10\54\0\40\142\10\43\241\324\122\312\50\173\0\0\0\15\0\224\201\3\0" + "\76\0\200\4\0\112\0\0\0\20\102\264\21\7\0\0\334\1\0\0\177\124\2\300\45" + "\0\0\220\10\0\174\0\0\100\15\0\230\221\3\0\77\0\220\4\0\113\0\0\100\20" + "\103\270\41\7\0\0\340\1\0\0\200\130\2\0\46\0\0\240\210\54" + + "iso88593\0" + "\0\40" + "\0\130\21\13\0\0\4\100\5\0\0\170\121\210\23\140\0\20\200\50\0\134\1\0\0" + "\0\0\120\5\0\0\174\141\310\23\141\0\20\300\50\0\0\0\100\0\0\360\240\3\0" + "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\100\1\0\0\114\0\0\0\0\0\114\62\10\0" + "\0\0\0\100\0\0\364\260\3\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\104\1\0\0" + "\115\0\0\0\0\0\120\102\210\54" + + "iso88594\0" + "\0\40" + "\0\330\100\106\37\0\140\161\6\0\0\34\102\204\24\215\0\100\12\0\0\334\60\213\37" + "\0\144\201\6\54\0\40\122\304\24\216\314\121\12\35\62\0\0\0\0\0\0\0\0\27" + "\76\0\200\4\0\106\0\0\200\26\102\274\121\207\30\0\0\0\0\0\0\144\2\0\0" + "\0\74\22\11\0\63\0\0\0\0\0\0\0\100\27\77\0\220\4\0\107\0\0\300\26" + "\103\300\141\307\30\0\0\0\0\0\0\150\2\0\0\0\100\42\211\54" + + "iso88595\0" + "\0\40" + "\0\14\104\120\101\6\35\204\120\102\12\55\304\120\103\16\1\360\20\104" + "\21\111\64\21\105\25\131\164\21\106\31\151\264\21\107\35\171\364\21\110" + "\41\211\64\22\111\45\231\164\22\112\51\251\264\22\113\55\271\364\22\114" + "\61\311\64\23\115\65\331\164\23\116\71\351\264\23\117\75\371\364\23\120" + "\101\11\65\24\121\105\31\165\24\122\111\51\265\24\123\115\71\365\24\124" + "\127\106\45\325\124\124\125\145\325\125\130\145\245\325\126\134\15\320\225\127" + + "iso88596\0" + "\0\40" + "\0\4\20\100\0\0\4\20\100\0\1\4\20\100\0\224\1\20\100\0\1\4\20\100\0" + "\1\4\20\100\0\1\4\20\100\145\1\4\20\200\145\1\134\206\131\146" + "\232\155\306\131\147\236\175\6\132\150\242\215\106\132\151\246\235\206\132\152" + "\252\255\306\132\153\256\275\6\133\0\1\4\20\100\0\261\311\66\33\155" + "\265\331\166\33\156\271\351\266\33\157\275\371\366\33\160\301\11\67\134\0" + "\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0" + + "iso88597\0" + "\0\40" + "\0\24\151\44\0\124\126\11\0\0\0\0\260\13\0\0\0\20\300\220\0\0\0\0\0" + "\274\364\342\13\0\277\0\23\14\0\302\0\60\14\61\305\30\163\14\62" + "\311\50\263\14\63\315\70\363\14\64\321\110\63\15\65\325\130\23\300\65" + "\330\144\243\315\66\334\164\343\315\67\340\204\43\316\70\344\224\143\316\71" + "\350\244\243\316\72\354\264\343\316\73\360\304\43\317\74\364\324\143\317\75" + "\370\344\243\317\76\374\364\343\317\77\0\5\44\120\0" + + "iso88598\0" + "\0\40" + "\0\4\0\0\0\0\0\0\0\0\0\0\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\0\0" + "\0\0\0\100\0\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0" + "\1\4\20\100\0\1\4\20\100\0\1\4\20\0\221\164\325\145\327\135" + "\170\345\245\327\136\174\365\345\327\137\200\5\46\330\140\204\25\146\330\141" + "\210\45\246\330\142\214\65\346\130\0\1\374\10\144\0" + + "iso88599\0" + "\0\120" + "\116\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\170\121\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\117\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\174\141\10\0" + + "iso885910\0" + "\0\40" + "\0\330\100\204\24\132\140\41\6\0\147\10\161\110\43\244\0\20\311\34" + "\0\334\120\304\24\133\144\61\6\0\150\14\201\210\43\245\14\51\11\35\62\0\0\0\0" + "\0\0\0\0\27\76\0\200\4\0\106\0\0\0\0\0\274\121\7\0\0\0\0\300\43\0\144\2\0\0" + "\0\0\0\0\0\63\0\0\0\0\0\0\0\100\27\77\0\220\4\0\107\0\0\0\0\0\300\141\7\0" + "\0\0\0\0\44\0\150\2\0\0\0\0\0\0\31" + + "iso885911\0" + "tis620\0" + "\0\40" + "\0\100\27\235\164\323\121\127\235\165\327\141\227\235\166\333\161\327\235\167" + "\337\201\27\236\170\343\221\127\236\171\347\241\227\236\172" + "\353\261\327\236\173\357\301\27\237\174\363\321\127\237\175" + "\367\341\227\237\176\373\361\327\237\177\377\1\30\240\200\3\22\130\240\201" + "\7\42\230\140\0\1\4\20\200\202\13\62\330\240\203\17\102\30\241\204" + "\23\122\130\241\205\27\142\230\241\206\33\162\330\241\207\37\202\30\242\210" + "\43\222\130\242\211\1\4\20\100\0" + + "iso885913\0" + "\0\40" + "\0\44\11\0\0\0\50\11\0\0\15\0\320\7\0\0\0\0\300\2\0\0\0\0\0\110\2\0\0\0" + "\20\0\340\7\0\0\0\0\200\3\66\160\41\3\16\0\0\200\4\21\76\0\0\212\21" + "\122\210\241\305\31\207\264\361\6\0\165\0\0\0\0\231\254\21\110\44" + "\0\210\102\12\0\67\164\61\103\16\0\0\220\104\21\77\0\20\312\21" + "\123\214\261\5\32\210\270\1\7\0\166\0\0\0\0\232\260\41\210\44" + "\0\214\122\212\221" + + "iso885914\0" + "\0\40" + "\0\234\210\42\0\74\364\220\42\0\65\2\160\243\212\73\2\0\300\47" + "\53\262\10\105\24\55\272\10\300\213\66\302\210\143\214\74\346\250\243\214" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\233\0\0\0\0\0\0\0\300\214\0\0\0\0\0" + "\0\0\320\11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\234\0\0\0\0\0\0\0\0\215" + "\0\0\0\0\0\0\0\340\11\0" + + "iso885915\0" + "latin9\0" + "\0\44" + "\124\2\160\10\0\210\0\0\0\0\0\0\0\0\0\0\0\0\0\0\244\0\0\0\0\245\0\0\0\0" + "\171\350\361\11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + + "iso885916\0" + "\0\40" + "\0\330\160\303\32\124\52\171\10\0\210\0\260\12\0\240\0\20\212\50\0\0\340\3\33" + "\244\44\11\0\0\245\374\300\12\0\171\350\361\311\50\0\0\0\0\15\0\340\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\102\264\1\0\0\0\334\1\100\40\227\0\0\0\0\0\40\321\12\0" + "\0\0\0\100\15\0\344\0\0\0\0\0\0\0\0\0\0\0\0\0\103\270\1\0\0\0\340\1\200\40" + "\230\0\0\0\0\0\44\341\12\0" + + "cp1250\0" + "windows1250\0" + "\0\0" + "\124\6\160\144\0\112\72\271\44\223\1\74\171\10\224\201\54\102\12\50" + "\1\24\151\44\222\111\66\31\244\220\1\140\211\110\224\202\60\122\112\50" + "\0\300\22\313\32\0\330\0\0\0\0\0\120\10\0\0\0\0\200\50\0\0\60\13\33\0\0\0\0\0" + "\0\334\140\10\0\151\324\242\306\50\173\0\0\0\15\0\224\201\3\0\76\0\200\4\0" + "\112\0\0\0\20\102\264\21\7\0\0\334\1\0\0\177\124\2\300\45\0\0\220\10\0" + "\174\0\0\100\15\0\230\221\3\0\77\0\220\4\0\113\0\0\100\20\103\270\41\7\0" + "\0\340\1\0\0\200\130\2\0\46\0\0\240\210\54" + + "cp1251\0" + "windows1251\0" + "\0\0" + "\4\25\164\344\124\112\72\271\44\223\124\76\271\20\224\14\71\324\20\104" + "\122\25\151\44\222\111\66\31\244\220\1\140\231\125\224\132\161\265\225\127" + "\0\74\324\225\102\0\174\5\0\0\3\1\140\20\0\0\0\0\100\102\0\0\200\220\125" + "\140\1\0\0\0\121\135\111\25\0\130\35\124\325\125\21\111\64\21\105" + "\25\131\164\21\106\31\151\264\21\107\35\171\364\21\110\41\211\64\22\111" + "\45\231\164\22\112\51\251\264\22\113\55\271\364\22\114\61\311\64\23\115" + "\65\331\164\23\116\71\351\264\23\117\75\371\364\23\120\101\11\65\24\121" + "\105\31\165\24\122\111\51\265\24\123\115\71\365\24\124" + + "cp1252\0" + "windows1252\0" + "\0\0" + "\124\6\160\244\51\112\72\271\44\223\257\74\171\10\224\171\4\100\112\0" + "\1\24\151\44\222\111\66\31\244\220\264\140\211\110\224\172\4\120\312\47" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + + "cp1253\0" + "windows1253\0" + "\0\0" + "\124\6\160\244\51\112\72\271\44\223\1\74\31\0\224\1\4\20\100\0\1\24\151\44\222" + "\111\66\31\244\220\1\140\31\100\224\1\4\20\100\0\0\364\342\13\0\0\0\0\0\0" + "\0\0\20\0\0\0\0\0\300\220\0\0\0\0\0\274\0\0\0\0\277\0\23\14\0\302\0\60\14\61" + "\305\30\163\14\62\311\50\263\14\63\315\70\363\14\64\321\110\63\15\65" + "\325\130\23\300\65\330\144\243\315\66\334\164\343\315\67\340\204\43\316\70" + "\344\224\143\316\71\350\244\243\316\72\354\264\343\316\73\360\304\43\317\74" + "\364\324\143\317\75\370\344\243\317\76\374\364\343\317\77\0\5\44\120\0" + + "cp1254\0" + "windows1254\0" + "\0\0" + "\124\6\160\244\51\112\72\271\44\223\257\74\171\10\224\171\4\20\100\0" + "\1\24\151\44\222\111\66\31\244\220\264\140\211\110\224\172\4\20\300\47" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\116\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\170\121\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\117\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\174\141\10\0" + + "cp1255\0" + "windows1255\0" + "\0\0" + "\124\6\160\244\51\112\72\271\44\223\257\74\31\0\224\1\4\20\100\0" + "\1\24\151\44\222\111\66\31\244\220\264\140\31\100\224\1\4\20\100\0\0\0\0\0\0" + "\122\2\0\0\0\0\0\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\0\0\0\0\0\0\0" + "\141\211\65\26\131\145\231\165\26\132\151\251\25\300\132\154\265\345\326\133" + "\160\305\45\327\134\217\101\26\231\144\223\5\20\100\0\1\4\20\100\0" + "\164\325\145\327\135\170\345\245\327\136\174\365\345\327\137\200\5\46\330\140" + "\204\25\146\330\141\210\45\246\330\142\214\65\346\130\0\1\374\10\144\0" + + "cp1256\0" + "windows1256\0" + "\0\0" + "\124\26\167\244\51\112\72\271\44\223\257\74\111\34\224\171\30\227\334\161" + "\313\25\151\44\222\111\66\31\244\220\312\141\211\134\224\172\364\350\43\163" + "\0\120\6\0\0\0\0\0\0\0\0\0\320\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\120\31\0" + "\0\0\0\200\145\316\135\206\131\146\232\155\306\131\147\236\175\6\132\150" + "\242\215\106\132\151\246\235\206\132\152\252\255\306\32\0\255\271\366\32\154" + "\261\311\66\33\155\0\324\6\200\155\267\341\226\33\0\0\0\0\0\0\272\355\6\0\0" + "\274\365\346\333\157\0\0\27\34\0\302\1\60\34\0\0\374\10\344\163" + + "cp1257\0" + "windows1257\0" + "\0\0" + "\124\6\160\144\0\112\72\271\44\223\1\74\31\0\224\1\20\0\213\2\1\24\151\44\222" + "\111\66\31\244\220\1\140\31\100\224\1\30\60\113\0\0\4\0\0\0\0\4\0\0\0" + "\15\0\320\7\0\0\0\0\300\2\0\0\0\0\0\0\0\0\0\0\20\0\340\7\0\0\0\0\200\3" + "\66\160\41\3\16\0\0\200\4\21\76\0\0\212\21\122\210\241\305\31\207\264\361\6\0" + "\165\0\0\0\0\231\254\21\110\44\0\210\102\12\0\67\164\61\103\16\0\0\220\104\21" + "\77\0\20\312\21\123\214\261\5\32\210\270\1\7\0\166\0\0\0\0\232\260\41\210\44" + "\0\214\122\212\54" + + "cp1258\0" + "windows1258\0" + "\0\0" + "\124\6\160\244\51\112\72\271\44\223\257\74\31\0\224\171\4\20\100\0" + "\1\24\151\44\222\111\66\31\244\220\264\140\31\100\224\172\4\20\300\47" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\15\0\0\0\0\0\0\0\0\0\0\266\0\0\0\0\102\0\220\13\0" + "\0\234\2\0\0\0\0\0\0\0\0\244\202\13\0\0\0\0\100\15\0\0\0\0\0\0\0\0\0\0" + "\267\0\0\0\0\103\0\240\13\0\0\240\2\0\0\0\0\0\0\0\0\250\62\45\0" + + "koi8r\0" + "\0\0" + "\140\206\51\346\230\144\226\151\346\231\150\246\251\46\242\211\52\272\50\243" + "\215\72\372\250\227\220\146\251\345\226\134\166\51\300\227\7\40\220\300\3" + "\153\262\331\146\124\156\276\11\147\234\162\316\111\147\235" + "\166\336\211\147\236\172\356\311\347\100\175\372\371\47\240\201\12\72\50\241" + "\205\32\172\150\1\117\305\44\323\121\65\331\124\24\115\106\345\244\323\116" + "\74\365\344\323\117\100\101\25\224\120\103\21\165\323\114\115\61\205\123\122" + "\116\51\205\324\122\57\105\44\321\111\25\131\124\22\105\46\145\244\321\106" + "\34\165\344\321\107\40\301\24\222\110\43\221\164\321\104\55\261\204\121\112" + "\56\251\204\322\112" + + "koi8u\0" + "\0\0" + "\140\206\51\346\230\144\226\151\346\231\150\246\251\46\242\211\52\272\50\243" + "\215\72\372\250\227\220\146\251\345\226\134\166\51\300\227\7\40\220\300\3" + "\153\262\331\146\124\124\275\151\325\125\162\316\111\147\235" + "\166\202\205\147\236\172\356\311\347\100\6\371\211\120\102\201\12\72\50\241" + "\205\176\165\150\1\117\305\44\323\121\65\331\124\24\115\106\345\244\323\116" + "\74\365\344\323\117\100\101\25\224\120\103\21\165\323\114\115\61\205\123\122" + "\116\51\205\324\122\57\105\44\321\111\25\131\124\22\105\46\145\244\321\106" + "\34\165\344\321\107\40\301\24\222\110\43\221\164\321\104\55\261\204\121\112" + "\56\251\204\322\112" + + "cp437\0" + "\0\0" + "\27\300\100\202\7\37\164\0\202\10\45\230\60\102\12\50\234\100\101\5" + "\30\70\260\300\12\54\250\360\202\13\61\144\300\101\4\22\114\140\245\51" + "\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244" + "\215\72\372\150\230\147\362\331\147\234\160\372\311\246\234" + "\170\336\151\347\230\144\246\211\246\231\140\252\231\247\236" + "\165\276\111\150\240\173\256\171\250\240\203\376\11\50\235\163\266\351\246\241" + "\205\226\51\246\242\211\56\312\50\242\345\104\212\14\75\327\334\23\51\76" + "\332\64\323\15\72\221\352\223\116\244\221\106\332\45\227\136\176\371\300\226" + "\7\144\231\200\226\221\42\0\251\0" + + "cp850\0" + "\0\0" + "\27\300\100\202\7\37\164\0\202\10\45\230\60\102\12\50\234\100\101\5" + "\30\70\260\300\12\54\250\360\202\13\61\144\300\1\4\22\64\300\200\51" + "\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244" + "\215\72\372\150\230\147\106\32\151\244\5\370\311\246\234\170\106\60\301\230" + "\144\246\211\246\231\140\252\31\151\244\165\276\111\150\240" + "\173\256\171\150\244\221\106\32\151\244\221\176\21\151\244\221\226\51\246\242" + "\211\106\32\51\242\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244" + "\221\106\152\100\244\221\106\112\144\244\221\16\360\200\2\7\20\220\100\244" + "\221\42\0\251\0" diff --git a/third_party/ulib/musl/src/locale/dcngettext.c b/third_party/ulib/musl/src/locale/dcngettext.c new file mode 100644 index 000000000..8154d0d8a --- /dev/null +++ b/third_party/ulib/musl/src/locale/dcngettext.c @@ -0,0 +1,239 @@ +#include "atomic.h" +#include "libc.h" +#include "locale_impl.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +struct binding { + struct binding* next; + int dirlen; + volatile int active; + char* domainname; + char* dirname; + char buf[]; +}; + +static void* volatile bindings; + +static char* gettextdir(const char* domainname, size_t* dirlen) { + struct binding* p; + for (p = bindings; p; p = p->next) { + if (!strcmp(p->domainname, domainname) && p->active) { + *dirlen = p->dirlen; + return (char*)p->dirname; + } + } + return 0; +} + +char* bindtextdomain(const char* domainname, const char* dirname) { + static mxr_mutex_t lock; + struct binding *p, *q; + + if (!domainname) return 0; + if (!dirname) return gettextdir(domainname, &(size_t){0}); + + size_t domlen = strlen(domainname); + size_t dirlen = strlen(dirname); + if (domlen > NAME_MAX || dirlen >= PATH_MAX) { + errno = EINVAL; + return 0; + } + + mxr_mutex_lock(&lock); + + for (p = bindings; p; p = p->next) { + if (!strcmp(p->domainname, domainname) && !strcmp(p->dirname, dirname)) { + break; + } + } + + if (!p) { + p = malloc(sizeof *p + domlen + dirlen + 2); + if (!p) { + mxr_mutex_unlock(&lock); + return 0; + } + p->next = bindings; + p->dirlen = dirlen; + p->domainname = p->buf; + p->dirname = p->buf + domlen + 1; + memcpy(p->domainname, domainname, domlen + 1); + memcpy(p->dirname, dirname, dirlen + 1); + a_cas_p(&bindings, bindings, p); + } + + a_store(&p->active, 1); + + for (q = bindings; q; q = q->next) { + if (!strcmp(p->domainname, domainname) && q != p) a_store(&q->active, 0); + } + + mxr_mutex_unlock(&lock); + + return (char*)p->dirname; +} + +static const char catnames[][12] = { + "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_MESSAGES", +}; + +static const char catlens[] = {8, 10, 7, 10, 11, 11}; + +struct msgcat { + struct msgcat* next; + const void* map; + size_t map_size; + void* volatile plural_rule; + volatile int nplurals; + char name[]; +}; + +static char* dummy_gettextdomain(void) { + return "messages"; +} + +weak_alias(dummy_gettextdomain, __gettextdomain); + +const unsigned char* __map_file(const char*, size_t*); +int __munmap(void*, size_t); +unsigned long __pleval(const char*, unsigned long); + +char* dcngettext(const char* domainname, const char* msgid1, const char* msgid2, + unsigned long int n, int category) { + static struct msgcat* volatile cats; + struct msgcat* p; + struct __locale_struct* loc = CURRENT_LOCALE; + const struct __locale_map* lm; + const char *dirname, *locname, *catname; + size_t dirlen, loclen, catlen, domlen; + + if ((unsigned)category >= LC_ALL) goto notrans; + + if (!domainname) domainname = __gettextdomain(); + + domlen = strlen(domainname); + if (domlen > NAME_MAX) goto notrans; + + dirname = gettextdir(domainname, &dirlen); + if (!dirname) goto notrans; + + lm = loc->cat[category]; + if (!lm) { + notrans: + return (char*)((n == 1) ? msgid1 : msgid2); + } + locname = lm->name; + + catname = catnames[category]; + catlen = catlens[category]; + loclen = strlen(locname); + + size_t namelen = dirlen + 1 + loclen + 1 + catlen + 1 + domlen + 3; + char name[namelen + 1], *s = name; + + memcpy(s, dirname, dirlen); + s[dirlen] = '/'; + s += dirlen + 1; + memcpy(s, locname, loclen); + s[loclen] = '/'; + s += loclen + 1; + memcpy(s, catname, catlen); + s[catlen] = '/'; + s += catlen + 1; + memcpy(s, domainname, domlen); + s[domlen] = '.'; + s[domlen + 1] = 'm'; + s[domlen + 2] = 'o'; + s[domlen + 3] = 0; + + for (p = cats; p; p = p->next) + if (!strcmp(p->name, name)) break; + + if (!p) { + void* old_cats; + size_t map_size; + const void* map = __map_file(name, &map_size); + if (!map) goto notrans; + p = malloc(sizeof *p + namelen + 1); + if (!p) { + __munmap((void*)map, map_size); + goto notrans; + } + p->map = map; + p->map_size = map_size; + memcpy(p->name, name, namelen + 1); + do { + old_cats = cats; + p->next = old_cats; + } while (a_cas_p(&cats, old_cats, p) != old_cats); + } + + const char* trans = __mo_lookup(p->map, p->map_size, msgid1); + if (!trans) goto notrans; + + /* Non-plural-processing gettext forms pass a null pointer as + * msgid2 to request that dcngettext suppress plural processing. */ + if (!msgid2) return (char*)trans; + + if (!p->plural_rule) { + const char* rule = "n!=1;"; + unsigned long np = 2; + const char* r = __mo_lookup(p->map, p->map_size, ""); + char* z; + while (r && strncmp(r, "Plural-Forms:", 13)) { + z = strchr(r, '\n'); + r = z ? z + 1 : 0; + } + if (r) { + r += 13; + while (isspace(*r)) + r++; + if (!strncmp(r, "nplurals=", 9)) { + np = strtoul(r + 9, &z, 10); + r = z; + } + while (*r && *r != ';') + r++; + if (*r) { + r++; + while (isspace(*r)) + r++; + if (!strncmp(r, "plural=", 7)) rule = r + 7; + } + } + a_store(&p->nplurals, np); + a_cas_p(&p->plural_rule, 0, (void*)rule); + } + if (p->nplurals) { + unsigned long plural = __pleval(p->plural_rule, n); + if (plural > p->nplurals) goto notrans; + while (plural--) { + size_t rem = p->map_size - (trans - (char*)p->map); + size_t l = strnlen(trans, rem); + if (l + 1 >= rem) goto notrans; + trans += l + 1; + } + } + return (char*)trans; +} + +char* dcgettext(const char* domainname, const char* msgid, int category) { + return dcngettext(domainname, msgid, 0, 1, category); +} + +char* dngettext(const char* domainname, const char* msgid1, const char* msgid2, + unsigned long int n) { + return dcngettext(domainname, msgid1, msgid2, n, LC_MESSAGES); +} + +char* dgettext(const char* domainname, const char* msgid) { + return dcngettext(domainname, msgid, 0, 1, LC_MESSAGES); +} diff --git a/third_party/ulib/musl/src/locale/duplocale.c b/third_party/ulib/musl/src/locale/duplocale.c new file mode 100644 index 000000000..b51884630 --- /dev/null +++ b/third_party/ulib/musl/src/locale/duplocale.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +locale_t __duplocale(locale_t old) { + locale_t new = malloc(sizeof *new); + if (!new) return 0; + if (old == LC_GLOBAL_LOCALE) old = &libc.global_locale; + *new = *old; + return new; +} + +weak_alias(__duplocale, duplocale); diff --git a/third_party/ulib/musl/src/locale/freelocale.c b/third_party/ulib/musl/src/locale/freelocale.c new file mode 100644 index 000000000..0772806b2 --- /dev/null +++ b/third_party/ulib/musl/src/locale/freelocale.c @@ -0,0 +1,11 @@ +#include "libc.h" +#include "locale_impl.h" +#include + +int __loc_is_allocated(locale_t); + +void freelocale(locale_t l) { + if (__loc_is_allocated(l)) free(l); +} + +weak_alias(freelocale, __freelocale); diff --git a/third_party/ulib/musl/src/locale/gb18030.h b/third_party/ulib/musl/src/locale/gb18030.h new file mode 100644 index 000000000..689893f46 --- /dev/null +++ b/third_party/ulib/musl/src/locale/gb18030.h @@ -0,0 +1,1834 @@ +19970, 19972, 19973, 19974, 19983, 19986, 19991, 19999, 20000, 20001, 20003, 20006, 20009, 20014, + 20015, 20017, 20019, 20021, 20023, 20028, 20032, 20033, 20034, 20036, 20038, 20042, 20049, + 20053, 20055, 20058, 20059, 20066, 20067, 20068, 20069, 20071, 20072, 20074, 20075, 20076, + 20077, 20078, 20079, 20082, 20084, 20085, 20086, 20087, 20088, 20089, 20090, 20091, 20092, + 20093, 20095, 20096, 20097, 20098, 20099, 20100, 20101, 20103, 20106, 20112, 20118, 20119, + 20121, 20124, 20125, 20126, 20131, 20138, 20143, 20144, 20145, 20148, 20150, 20151, 20152, + 20153, 20156, 20157, 20158, 20168, 20172, 20175, 20176, 20178, 20186, 20187, 20188, 20192, + 20194, 20198, 20199, 20201, 20205, 20206, 20207, 20209, 20212, 20216, 20217, 20218, 20220, + 20222, 20224, 20226, 20227, 20228, 20229, 20230, 20231, 20232, 20235, 20236, 20242, 20243, + 20244, 20245, 20246, 20252, 20253, 20257, 20259, 20264, 20265, 20268, 20269, 20270, 20273, + 20275, 20277, 20279, 20281, 20283, 20286, 20287, 20288, 20289, 20290, 20292, 20293, 20295, + 20296, 20297, 20298, 20299, 20300, 20306, 20308, 20310, 20321, 20322, 20326, 20328, 20330, + 20331, 20333, 20334, 20337, 20338, 20341, 20343, 20344, 20345, 20346, 20349, 20352, 20353, + 20354, 20357, 20358, 20359, 20362, 20364, 20366, 20368, 20370, 20371, 20373, 20374, 20376, + 20377, 20378, 20380, 20382, 20383, 20385, 20386, 20388, 20395, 20397, 20400, 20401, 20402, + 20403, 20404, 20406, 20407, 20408, 20409, 20410, 20411, 20412, 20413, 20414, 20416, 20417, + 20418, 20422, 20423, 20424, 20425, 20427, 20428, 20429, 20434, 20435, 20436, 20437, 20438, + 20441, 20443, 20448, 20450, 20452, 20453, 20455, 20459, 20460, 20464, 20466, 20468, 20469, + 20470, 20471, 20473, 20475, 20476, 20477, 20479, 20480, 20481, 20482, 20483, 20484, 20485, + 20486, 20487, 20488, 20489, 20490, 20491, 20494, 20496, 20497, 20499, 20501, 20502, 20503, + 20507, 20509, 20510, 20512, 20514, 20515, 20516, 20519, 20523, 20527, 20528, 20529, 20530, + 20531, 20532, 20533, 20534, 20535, 20536, 20537, 20539, 20541, 20543, 20544, 20545, 20546, + 20548, 20549, 20550, 20553, 20554, 20555, 20557, 20560, 20561, 20562, 20563, 20564, 20566, + 20567, 20568, 20569, 20571, 20573, 20574, 20575, 20576, 20577, 20578, 20579, 20580, 20582, + 20583, 20584, 20585, 20586, 20587, 20589, 20590, 20591, 20592, 20593, 20594, 20595, 20596, + 20597, 20600, 20601, 20602, 20604, 20605, 20609, 20610, 20611, 20612, 20614, 20615, 20617, + 20618, 20619, 20620, 20622, 20623, 20624, 20625, 20626, 20627, 20628, 20629, 20630, 20631, + 20632, 20633, 20634, 20635, 20636, 20637, 20638, 20639, 20640, 20641, 20642, 20644, 20646, + 20650, 20651, 20653, 20654, 20655, 20656, 20657, 20659, 20660, 20661, 20662, 20663, 20664, + 20665, 20668, 20669, 20670, 20671, 20672, 20673, 20674, 20675, 20676, 20677, 20678, 20679, + 20680, 20681, 20682, 20683, 20684, 20685, 20686, 20688, 20689, 20690, 20691, 20692, 20693, + 20695, 20696, 20697, 20699, 20700, 20701, 20702, 20703, 20704, 20705, 20706, 20707, 20708, + 20709, 20712, 20713, 20714, 20715, 20719, 20720, 20721, 20722, 20724, 20726, 20727, 20728, + 20729, 20730, 20732, 20733, 20734, 20735, 20736, 20737, 20738, 20739, 20740, 20741, 20744, + 20745, 20746, 20748, 20749, 20750, 20751, 20752, 20753, 20755, 20756, 20757, 20758, 20759, + 20760, 20761, 20762, 20763, 20764, 20765, 20766, 20767, 20768, 20770, 20771, 20772, 20773, + 20774, 20775, 20776, 20777, 20778, 20779, 20780, 20781, 20782, 20783, 20784, 20785, 20786, + 20787, 20788, 20789, 20790, 20791, 20792, 20793, 20794, 20795, 20796, 20797, 20798, 20802, + 20807, 20810, 20812, 20814, 20815, 20816, 20818, 20819, 20823, 20824, 20825, 20827, 20829, + 20830, 20831, 20832, 20833, 20835, 20836, 20838, 20839, 20841, 20842, 20847, 20850, 20858, + 20862, 20863, 20867, 20868, 20870, 20871, 20874, 20875, 20878, 20879, 20880, 20881, 20883, + 20884, 20888, 20890, 20893, 20894, 20895, 20897, 20899, 20902, 20903, 20904, 20905, 20906, + 20909, 20910, 20916, 20920, 20921, 20922, 20926, 20927, 20929, 20930, 20931, 20933, 20936, + 20938, 20941, 20942, 20944, 20946, 20947, 20948, 20949, 20950, 20951, 20952, 20953, 20954, + 20956, 20958, 20959, 20962, 20963, 20965, 20966, 20967, 20968, 20969, 20970, 20972, 20974, + 20977, 20978, 20980, 20983, 20990, 20996, 20997, 21001, 21003, 21004, 21007, 21008, 21011, + 21012, 21013, 21020, 21022, 21023, 21025, 21026, 21027, 21029, 21030, 21031, 21034, 21036, + 21039, 21041, 21042, 21044, 21045, 21052, 21054, 21060, 21061, 21062, 21063, 21064, 21065, + 21067, 21070, 21071, 21074, 21075, 21077, 21079, 21080, 21081, 21082, 21083, 21085, 21087, + 21088, 21090, 21091, 21092, 21094, 21096, 21099, 21100, 21101, 21102, 21104, 21105, 21107, + 21108, 21109, 21110, 21111, 21112, 21113, 21114, 21115, 21116, 21118, 21120, 21123, 21124, + 21125, 21126, 21127, 21129, 21130, 21131, 21132, 21133, 21134, 21135, 21137, 21138, 21140, + 21141, 21142, 21143, 21144, 21145, 21146, 21148, 21156, 21157, 21158, 21159, 21166, 21167, + 21168, 21172, 21173, 21174, 21175, 21176, 21177, 21178, 21179, 21180, 21181, 21184, 21185, + 21186, 21188, 21189, 21190, 21192, 21194, 21196, 21197, 21198, 21199, 21201, 21203, 21204, + 21205, 21207, 21209, 21210, 21211, 21212, 21213, 21214, 21216, 21217, 21218, 21219, 21221, + 21222, 21223, 21224, 21225, 21226, 21227, 21228, 21229, 21230, 21231, 21233, 21234, 21235, + 21236, 21237, 21238, 21239, 21240, 21243, 21244, 21245, 21249, 21250, 21251, 21252, 21255, + 21257, 21258, 21259, 21260, 21262, 21265, 21266, 21267, 21268, 21272, 21275, 21276, 21278, + 21279, 21282, 21284, 21285, 21287, 21288, 21289, 21291, 21292, 21293, 21295, 21296, 21297, + 21298, 21299, 21300, 21301, 21302, 21303, 21304, 21308, 21309, 21312, 21314, 21316, 21318, + 21323, 21324, 21325, 21328, 21332, 21336, 21337, 21339, 21341, 21349, 21352, 21354, 21356, + 21357, 21362, 21366, 21369, 21371, 21372, 21373, 21374, 21376, 21377, 21379, 21383, 21384, + 21386, 21390, 21391, 21392, 21393, 21394, 21395, 21396, 21398, 21399, 21401, 21403, 21404, + 21406, 21408, 21409, 21412, 21415, 21418, 21419, 21420, 21421, 21423, 21424, 21425, 21426, + 21427, 21428, 21429, 21431, 21432, 21433, 21434, 21436, 21437, 21438, 21440, 21443, 21444, + 21445, 21446, 21447, 21454, 21455, 21456, 21458, 21459, 21461, 21466, 21468, 21469, 21470, + 21473, 21474, 21479, 21492, 21498, 21502, 21503, 21504, 21506, 21509, 21511, 21515, 21524, + 21528, 21529, 21530, 21532, 21538, 21540, 21541, 21546, 21552, 21555, 21558, 21559, 21562, + 21565, 21567, 21569, 21570, 21572, 21573, 21575, 21577, 21580, 21581, 21582, 21583, 21585, + 21594, 21597, 21598, 21599, 21600, 21601, 21603, 21605, 21607, 21609, 21610, 21611, 21612, + 21613, 21614, 21615, 21616, 21620, 21625, 21626, 21630, 21631, 21633, 21635, 21637, 21639, + 21640, 21641, 21642, 21645, 21649, 21651, 21655, 21656, 21660, 21662, 21663, 21664, 21665, + 21666, 21669, 21678, 21680, 21682, 21685, 21686, 21687, 21689, 21690, 21692, 21694, 21699, + 21701, 21706, 21707, 21718, 21720, 21723, 21728, 21729, 21730, 21731, 21732, 21739, 21740, + 21743, 21744, 21745, 21748, 21749, 21750, 21751, 21752, 21753, 21755, 21758, 21760, 21762, + 21763, 21764, 21765, 21768, 21770, 21771, 21772, 21773, 21774, 21778, 21779, 21781, 21782, + 21783, 21784, 21785, 21786, 21788, 21789, 21790, 21791, 21793, 21797, 21798, 21800, 21801, + 21803, 21805, 21810, 21812, 21813, 21814, 21816, 21817, 21818, 21819, 21821, 21824, 21826, + 21829, 21831, 21832, 21835, 21836, 21837, 21838, 21839, 21841, 21842, 21843, 21844, 21847, + 21848, 21849, 21850, 21851, 21853, 21854, 21855, 21856, 21858, 21859, 21864, 21865, 21867, + 21871, 21872, 21873, 21874, 21875, 21876, 21881, 21882, 21885, 21887, 21893, 21894, 21900, + 21901, 21902, 21904, 21906, 21907, 21909, 21910, 21911, 21914, 21915, 21918, 21920, 21921, + 21922, 21923, 21924, 21925, 21926, 21928, 21929, 21930, 21931, 21932, 21933, 21934, 21935, + 21936, 21938, 21940, 21942, 21944, 21946, 21948, 21951, 21952, 21953, 21954, 21955, 21958, + 21959, 21960, 21962, 21963, 21966, 21967, 21968, 21973, 21975, 21976, 21977, 21978, 21979, + 21982, 21984, 21986, 21991, 21993, 21997, 21998, 22000, 22001, 22004, 22006, 22008, 22009, + 22010, 22011, 22012, 22015, 22018, 22019, 22020, 22021, 22022, 22023, 22026, 22027, 22029, + 22032, 22033, 22034, 22035, 22036, 22037, 22038, 22039, 22041, 22042, 22044, 22045, 22048, + 22049, 22050, 22053, 22054, 22056, 22057, 22058, 22059, 22062, 22063, 22064, 22067, 22069, + 22071, 22072, 22074, 22076, 22077, 22078, 22080, 22081, 22082, 22083, 22084, 22085, 22086, + 22087, 22088, 22089, 22090, 22091, 22095, 22096, 22097, 22098, 22099, 22101, 22102, 22106, + 22107, 22109, 22110, 22111, 22112, 22113, 22115, 22117, 22118, 22119, 22125, 22126, 22127, + 22128, 22130, 22131, 22132, 22133, 22135, 22136, 22137, 22138, 22141, 22142, 22143, 22144, + 22145, 22146, 22147, 22148, 22151, 22152, 22153, 22154, 22155, 22156, 22157, 22160, 22161, + 22162, 22164, 22165, 22166, 22167, 22168, 22169, 22170, 22171, 22172, 22173, 22174, 22175, + 22176, 22177, 22178, 22180, 22181, 22182, 22183, 22184, 22185, 22186, 22187, 22188, 22189, + 22190, 22192, 22193, 22194, 22195, 22196, 22197, 22198, 22200, 22201, 22202, 22203, 22205, + 22206, 22207, 22208, 22209, 22210, 22211, 22212, 22213, 22214, 22215, 22216, 22217, 22219, + 22220, 22221, 22222, 22223, 22224, 22225, 22226, 22227, 22229, 22230, 22232, 22233, 22236, + 22243, 22245, 22246, 22247, 22248, 22249, 22250, 22252, 22254, 22255, 22258, 22259, 22262, + 22263, 22264, 22267, 22268, 22272, 22273, 22274, 22277, 22279, 22283, 22284, 22285, 22286, + 22287, 22288, 22289, 22290, 22291, 22292, 22293, 22294, 22295, 22296, 22297, 22298, 22299, + 22301, 22302, 22304, 22305, 22306, 22308, 22309, 22310, 22311, 22315, 22321, 22322, 22324, + 22325, 22326, 22327, 22328, 22332, 22333, 22335, 22337, 22339, 22340, 22341, 22342, 22344, + 22345, 22347, 22354, 22355, 22356, 22357, 22358, 22360, 22361, 22370, 22371, 22373, 22375, + 22380, 22382, 22384, 22385, 22386, 22388, 22389, 22392, 22393, 22394, 22397, 22398, 22399, + 22400, 22401, 22407, 22408, 22409, 22410, 22413, 22414, 22415, 22416, 22417, 22420, 22421, + 22422, 22423, 22424, 22425, 22426, 22428, 22429, 22430, 22431, 22437, 22440, 22442, 22444, + 22447, 22448, 22449, 22451, 22453, 22454, 22455, 22457, 22458, 22459, 22460, 22461, 22462, + 22463, 22464, 22465, 22468, 22469, 22470, 22471, 22472, 22473, 22474, 22476, 22477, 22480, + 22481, 22483, 22486, 22487, 22491, 22492, 22494, 22497, 22498, 22499, 22501, 22502, 22503, + 22504, 22505, 22506, 22507, 22508, 22510, 22512, 22513, 22514, 22515, 22517, 22518, 22519, + 22523, 22524, 22526, 22527, 22529, 22531, 22532, 22533, 22536, 22537, 22538, 22540, 22542, + 22543, 22544, 22546, 22547, 22548, 22550, 22551, 22552, 22554, 22555, 22556, 22557, 22559, + 22562, 22563, 22565, 22566, 22567, 22568, 22569, 22571, 22572, 22573, 22574, 22575, 22577, + 22578, 22579, 22580, 22582, 22583, 22584, 22585, 22586, 22587, 22588, 22589, 22590, 22591, + 22592, 22593, 22594, 22595, 22597, 22598, 22599, 22600, 22601, 22602, 22603, 22606, 22607, + 22608, 22610, 22611, 22613, 22614, 22615, 22617, 22618, 22619, 22620, 22621, 22623, 22624, + 22625, 22626, 22627, 22628, 22630, 22631, 22632, 22633, 22634, 22637, 22638, 22639, 22640, + 22641, 22642, 22643, 22644, 22645, 22646, 22647, 22648, 22649, 22650, 22651, 22652, 22653, + 22655, 22658, 22660, 22662, 22663, 22664, 22666, 22667, 22668, 22669, 22670, 22671, 22672, + 22673, 22676, 22677, 22678, 22679, 22680, 22683, 22684, 22685, 22688, 22689, 22690, 22691, + 22692, 22693, 22694, 22695, 22698, 22699, 22700, 22701, 22702, 22703, 22704, 22705, 22706, + 22707, 22708, 22709, 22710, 22711, 22712, 22713, 22714, 22715, 22717, 22718, 22719, 22720, + 22722, 22723, 22724, 22726, 22727, 22728, 22729, 22730, 22731, 22732, 22733, 22734, 22735, + 22736, 22738, 22739, 22740, 22742, 22743, 22744, 22745, 22746, 22747, 22748, 22749, 22750, + 22751, 22752, 22753, 22754, 22755, 22757, 22758, 22759, 22760, 22761, 22762, 22765, 22767, + 22769, 22770, 22772, 22773, 22775, 22776, 22778, 22779, 22780, 22781, 22782, 22783, 22784, + 22785, 22787, 22789, 22790, 22792, 22793, 22794, 22795, 22796, 22798, 22800, 22801, 22802, + 22803, 22807, 22808, 22811, 22813, 22814, 22816, 22817, 22818, 22819, 22822, 22824, 22828, + 22832, 22834, 22835, 22837, 22838, 22843, 22845, 22846, 22847, 22848, 22851, 22853, 22854, + 22858, 22860, 22861, 22864, 22866, 22867, 22873, 22875, 22876, 22877, 22878, 22879, 22881, + 22883, 22884, 22886, 22887, 22888, 22889, 22890, 22891, 22892, 22893, 22894, 22895, 22896, + 22897, 22898, 22901, 22903, 22906, 22907, 22908, 22910, 22911, 22912, 22917, 22921, 22923, + 22924, 22926, 22927, 22928, 22929, 22932, 22933, 22936, 22938, 22939, 22940, 22941, 22943, + 22944, 22945, 22946, 22950, 22951, 22956, 22957, 22960, 22961, 22963, 22964, 22965, 22966, + 22967, 22968, 22970, 22972, 22973, 22975, 22976, 22977, 22978, 22979, 22980, 22981, 22983, + 22984, 22985, 22988, 22989, 22990, 22991, 22997, 22998, 23001, 23003, 23006, 23007, 23008, + 23009, 23010, 23012, 23014, 23015, 23017, 23018, 23019, 23021, 23022, 23023, 23024, 23025, + 23026, 23027, 23028, 23029, 23030, 23031, 23032, 23034, 23036, 23037, 23038, 23040, 23042, + 23050, 23051, 23053, 23054, 23055, 23056, 23058, 23060, 23061, 23062, 23063, 23065, 23066, + 23067, 23069, 23070, 23073, 23074, 23076, 23078, 23079, 23080, 23082, 23083, 23084, 23085, + 23086, 23087, 23088, 23091, 23093, 23095, 23096, 23097, 23098, 23099, 23101, 23102, 23103, + 23105, 23106, 23107, 23108, 23109, 23111, 23112, 23115, 23116, 23117, 23118, 23119, 23120, + 23121, 23122, 23123, 23124, 23126, 23127, 23128, 23129, 23131, 23132, 23133, 23134, 23135, + 23136, 23137, 23139, 23140, 23141, 23142, 23144, 23145, 23147, 23148, 23149, 23150, 23151, + 23152, 23153, 23154, 23155, 23160, 23161, 23163, 23164, 23165, 23166, 23168, 23169, 23170, + 23171, 23172, 23173, 23174, 23175, 23176, 23177, 23178, 23179, 23180, 23181, 23182, 23183, + 23184, 23185, 23187, 23188, 23189, 23190, 23191, 23192, 23193, 23196, 23197, 23198, 23199, + 23200, 23201, 23202, 23203, 23204, 23205, 23206, 23207, 23208, 23209, 23211, 23212, 23213, + 23214, 23215, 23216, 23217, 23220, 23222, 23223, 23225, 23226, 23227, 23228, 23229, 23231, + 23232, 23235, 23236, 23237, 23238, 23239, 23240, 23242, 23243, 23245, 23246, 23247, 23248, + 23249, 23251, 23253, 23255, 23257, 23258, 23259, 23261, 23262, 23263, 23266, 23268, 23269, + 23271, 23272, 23274, 23276, 23277, 23278, 23279, 23280, 23282, 23283, 23284, 23285, 23286, + 23287, 23288, 23289, 23290, 23291, 23292, 23293, 23294, 23295, 23296, 23297, 23298, 23299, + 23300, 23301, 23302, 23303, 23304, 23306, 23307, 23308, 23309, 23310, 23311, 23312, 23313, + 23314, 23315, 23316, 23317, 23320, 23321, 23322, 23323, 23324, 23325, 23326, 23327, 23328, + 23329, 23330, 23331, 23332, 23333, 23334, 23335, 23336, 23337, 23338, 23339, 23340, 23341, + 23342, 23343, 23344, 23345, 23347, 23349, 23350, 23352, 23353, 23354, 23355, 23356, 23357, + 23358, 23359, 23361, 23362, 23363, 23364, 23365, 23366, 23367, 23368, 23369, 23370, 23371, + 23372, 23373, 23374, 23375, 23378, 23382, 23390, 23392, 23393, 23399, 23400, 23403, 23405, + 23406, 23407, 23410, 23412, 23414, 23415, 23416, 23417, 23419, 23420, 23422, 23423, 23426, + 23430, 23434, 23437, 23438, 23440, 23441, 23442, 23444, 23446, 23455, 23463, 23464, 23465, + 23468, 23469, 23470, 23471, 23473, 23474, 23479, 23482, 23483, 23484, 23488, 23489, 23491, + 23496, 23497, 23498, 23499, 23501, 23502, 23503, 23505, 23508, 23509, 23510, 23511, 23512, + 23513, 23514, 23515, 23516, 23520, 23522, 23523, 23526, 23527, 23529, 23530, 23531, 23532, + 23533, 23535, 23537, 23538, 23539, 23540, 23541, 23542, 23543, 23549, 23550, 23552, 23554, + 23555, 23557, 23559, 23560, 23563, 23564, 23565, 23566, 23568, 23570, 23571, 23575, 23577, + 23579, 23582, 23583, 23584, 23585, 23587, 23590, 23592, 23593, 23594, 23595, 23597, 23598, + 23599, 23600, 23602, 23603, 23605, 23606, 23607, 23619, 23620, 23622, 23623, 23628, 23629, + 23634, 23635, 23636, 23638, 23639, 23640, 23642, 23643, 23644, 23645, 23647, 23650, 23652, + 23655, 23656, 23657, 23658, 23659, 23660, 23661, 23664, 23666, 23667, 23668, 23669, 23670, + 23671, 23672, 23675, 23676, 23677, 23678, 23680, 23683, 23684, 23685, 23686, 23687, 23689, + 23690, 23691, 23694, 23695, 23698, 23699, 23701, 23709, 23710, 23711, 23712, 23713, 23716, + 23717, 23718, 23719, 23720, 23722, 23726, 23727, 23728, 23730, 23732, 23734, 23737, 23738, + 23739, 23740, 23742, 23744, 23746, 23747, 23749, 23750, 23751, 23752, 23753, 23754, 23756, + 23757, 23758, 23759, 23760, 23761, 23763, 23764, 23765, 23766, 23767, 23768, 23770, 23771, + 23772, 23773, 23774, 23775, 23776, 23778, 23779, 23783, 23785, 23787, 23788, 23790, 23791, + 23793, 23794, 23795, 23796, 23797, 23798, 23799, 23800, 23801, 23802, 23804, 23805, 23806, + 23807, 23808, 23809, 23812, 23813, 23816, 23817, 23818, 23819, 23820, 23821, 23823, 23824, + 23825, 23826, 23827, 23829, 23831, 23832, 23833, 23834, 23836, 23837, 23839, 23840, 23841, + 23842, 23843, 23845, 23848, 23850, 23851, 23852, 23855, 23856, 23857, 23858, 23859, 23861, + 23862, 23863, 23864, 23865, 23866, 23867, 23868, 23871, 23872, 23873, 23874, 23875, 23876, + 23877, 23878, 23880, 23881, 23885, 23886, 23887, 23888, 23889, 23890, 23891, 23892, 23893, + 23894, 23895, 23897, 23898, 23900, 23902, 23903, 23904, 23905, 23906, 23907, 23908, 23909, + 23910, 23911, 23912, 23914, 23917, 23918, 23920, 23921, 23922, 23923, 23925, 23926, 23927, + 23928, 23929, 23930, 23931, 23932, 23933, 23934, 23935, 23936, 23937, 23939, 23940, 23941, + 23942, 23943, 23944, 23945, 23946, 23947, 23948, 23949, 23950, 23951, 23952, 23953, 23954, + 23955, 23956, 23957, 23958, 23959, 23960, 23962, 23963, 23964, 23966, 23967, 23968, 23969, + 23970, 23971, 23972, 23973, 23974, 23975, 23976, 23977, 23978, 23979, 23980, 23981, 23982, + 23983, 23984, 23985, 23986, 23987, 23988, 23989, 23990, 23992, 23993, 23994, 23995, 23996, + 23997, 23998, 23999, 24000, 24001, 24002, 24003, 24004, 24006, 24007, 24008, 24009, 24010, + 24011, 24012, 24014, 24015, 24016, 24017, 24018, 24019, 24020, 24021, 24022, 24023, 24024, + 24025, 24026, 24028, 24031, 24032, 24035, 24036, 24042, 24044, 24045, 24048, 24053, 24054, + 24056, 24057, 24058, 24059, 24060, 24063, 24064, 24068, 24071, 24073, 24074, 24075, 24077, + 24078, 24082, 24083, 24087, 24094, 24095, 24096, 24097, 24098, 24099, 24100, 24101, 24104, + 24105, 24106, 24107, 24108, 24111, 24112, 24114, 24115, 24116, 24117, 24118, 24121, 24122, + 24126, 24127, 24128, 24129, 24131, 24134, 24135, 24136, 24137, 24138, 24139, 24141, 24142, + 24143, 24144, 24145, 24146, 24147, 24150, 24151, 24152, 24153, 24154, 24156, 24157, 24159, + 24160, 24163, 24164, 24165, 24166, 24167, 24168, 24169, 24170, 24171, 24172, 24173, 24174, + 24175, 24176, 24177, 24181, 24183, 24185, 24190, 24193, 24194, 24195, 24197, 24200, 24201, + 24204, 24205, 24206, 24210, 24216, 24219, 24221, 24225, 24226, 24227, 24228, 24232, 24233, + 24234, 24235, 24236, 24238, 24239, 24240, 24241, 24242, 24244, 24250, 24251, 24252, 24253, + 24255, 24256, 24257, 24258, 24259, 24260, 24261, 24262, 24263, 24264, 24267, 24268, 24269, + 24270, 24271, 24272, 24276, 24277, 24279, 24280, 24281, 24282, 24284, 24285, 24286, 24287, + 24288, 24289, 24290, 24291, 24292, 24293, 24294, 24295, 24297, 24299, 24300, 24301, 24302, + 24303, 24304, 24305, 24306, 24307, 24309, 24312, 24313, 24315, 24316, 24317, 24325, 24326, + 24327, 24329, 24332, 24333, 24334, 24336, 24338, 24340, 24342, 24345, 24346, 24348, 24349, + 24350, 24353, 24354, 24355, 24356, 24360, 24363, 24364, 24366, 24368, 24370, 24371, 24372, + 24373, 24374, 24375, 24376, 24379, 24381, 24382, 24383, 24385, 24386, 24387, 24388, 24389, + 24390, 24391, 24392, 24393, 24394, 24395, 24396, 24397, 24398, 24399, 24401, 24404, 24409, + 24410, 24411, 24412, 24414, 24415, 24416, 24419, 24421, 24423, 24424, 24427, 24430, 24431, + 24434, 24436, 24437, 24438, 24440, 24442, 24445, 24446, 24447, 24451, 24454, 24461, 24462, + 24463, 24465, 24467, 24468, 24470, 24474, 24475, 24477, 24478, 24479, 24480, 24482, 24483, + 24484, 24485, 24486, 24487, 24489, 24491, 24492, 24495, 24496, 24497, 24498, 24499, 24500, + 24502, 24504, 24505, 24506, 24507, 24510, 24511, 24512, 24513, 24514, 24519, 24520, 24522, + 24523, 24526, 24531, 24532, 24533, 24538, 24539, 24540, 24542, 24543, 24546, 24547, 24549, + 24550, 24552, 24553, 24556, 24559, 24560, 24562, 24563, 24564, 24566, 24567, 24569, 24570, + 24572, 24583, 24584, 24585, 24587, 24588, 24592, 24593, 24595, 24599, 24600, 24602, 24606, + 24607, 24610, 24611, 24612, 24620, 24621, 24622, 24624, 24625, 24626, 24627, 24628, 24630, + 24631, 24632, 24633, 24634, 24637, 24638, 24640, 24644, 24645, 24646, 24647, 24648, 24649, + 24650, 24652, 24654, 24655, 24657, 24659, 24660, 24662, 24663, 24664, 24667, 24668, 24670, + 24671, 24672, 24673, 24677, 24678, 24686, 24689, 24690, 24692, 24693, 24695, 24702, 24704, + 24705, 24706, 24709, 24710, 24711, 24712, 24714, 24715, 24718, 24719, 24720, 24721, 24723, + 24725, 24727, 24728, 24729, 24732, 24734, 24737, 24738, 24740, 24741, 24743, 24745, 24746, + 24750, 24752, 24755, 24757, 24758, 24759, 24761, 24762, 24765, 24766, 24767, 24768, 24769, + 24770, 24771, 24772, 24775, 24776, 24777, 24780, 24781, 24782, 24783, 24784, 24786, 24787, + 24788, 24790, 24791, 24793, 24795, 24798, 24801, 24802, 24803, 24804, 24805, 24810, 24817, + 24818, 24821, 24823, 24824, 24827, 24828, 24829, 24830, 24831, 24834, 24835, 24836, 24837, + 24839, 24842, 24843, 24844, 24848, 24849, 24850, 24851, 24852, 24854, 24855, 24856, 24857, + 24859, 24860, 24861, 24862, 24865, 24866, 24869, 24872, 24873, 24874, 24876, 24877, 24878, + 24879, 24880, 24881, 24882, 24883, 24884, 24885, 24886, 24887, 24888, 24889, 24890, 24891, + 24892, 24893, 24894, 24896, 24897, 24898, 24899, 24900, 24901, 24902, 24903, 24905, 24907, + 24909, 24911, 24912, 24914, 24915, 24916, 24918, 24919, 24920, 24921, 24922, 24923, 24924, + 24926, 24927, 24928, 24929, 24931, 24932, 24933, 24934, 24937, 24938, 24939, 24940, 24941, + 24942, 24943, 24945, 24946, 24947, 24948, 24950, 24952, 24953, 24954, 24955, 24956, 24957, + 24958, 24959, 24960, 24961, 24962, 24963, 24964, 24965, 24966, 24967, 24968, 24969, 24970, + 24972, 24973, 24975, 24976, 24977, 24978, 24979, 24981, 24982, 24983, 24984, 24985, 24986, + 24987, 24988, 24990, 24991, 24992, 24993, 24994, 24995, 24996, 24997, 24998, 25002, 25003, + 25005, 25006, 25007, 25008, 25009, 25010, 25011, 25012, 25013, 25014, 25016, 25017, 25018, + 25019, 25020, 25021, 25023, 25024, 25025, 25027, 25028, 25029, 25030, 25031, 25033, 25036, + 25037, 25038, 25039, 25040, 25043, 25045, 25046, 25047, 25048, 25049, 25050, 25051, 25052, + 25053, 25054, 25055, 25056, 25057, 25058, 25059, 25060, 25061, 25063, 25064, 25065, 25066, + 25067, 25068, 25069, 25070, 25071, 25072, 25073, 25074, 25075, 25076, 25078, 25079, 25080, + 25081, 25082, 25083, 25084, 25085, 25086, 25088, 25089, 25090, 25091, 25092, 25093, 25095, + 25097, 25107, 25108, 25113, 25116, 25117, 25118, 25120, 25123, 25126, 25127, 25128, 25129, + 25131, 25133, 25135, 25136, 25137, 25138, 25141, 25142, 25144, 25145, 25146, 25147, 25148, + 25154, 25156, 25157, 25158, 25162, 25167, 25168, 25173, 25174, 25175, 25177, 25178, 25180, + 25181, 25182, 25183, 25184, 25185, 25186, 25188, 25189, 25192, 25201, 25202, 25204, 25205, + 25207, 25208, 25210, 25211, 25213, 25217, 25218, 25219, 25221, 25222, 25223, 25224, 25227, + 25228, 25229, 25230, 25231, 25232, 25236, 25241, 25244, 25245, 25246, 25251, 25254, 25255, + 25257, 25258, 25261, 25262, 25263, 25264, 25266, 25267, 25268, 25270, 25271, 25272, 25274, + 25278, 25280, 25281, 25283, 25291, 25295, 25297, 25301, 25309, 25310, 25312, 25313, 25316, + 25322, 25323, 25328, 25330, 25333, 25336, 25337, 25338, 25339, 25344, 25347, 25348, 25349, + 25350, 25354, 25355, 25356, 25357, 25359, 25360, 25362, 25363, 25364, 25365, 25367, 25368, + 25369, 25372, 25382, 25383, 25385, 25388, 25389, 25390, 25392, 25393, 25395, 25396, 25397, + 25398, 25399, 25400, 25403, 25404, 25406, 25407, 25408, 25409, 25412, 25415, 25416, 25418, + 25425, 25426, 25427, 25428, 25430, 25431, 25432, 25433, 25434, 25435, 25436, 25437, 25440, + 25444, 25445, 25446, 25448, 25450, 25451, 25452, 25455, 25456, 25458, 25459, 25460, 25461, + 25464, 25465, 25468, 25469, 25470, 25471, 25473, 25475, 25476, 25477, 25478, 25483, 25485, + 25489, 25491, 25492, 25493, 25495, 25497, 25498, 25499, 25500, 25501, 25502, 25503, 25505, + 25508, 25510, 25515, 25519, 25521, 25522, 25525, 25526, 25529, 25531, 25533, 25535, 25536, + 25537, 25538, 25539, 25541, 25543, 25544, 25546, 25547, 25548, 25553, 25555, 25556, 25557, + 25559, 25560, 25561, 25562, 25563, 25564, 25565, 25567, 25570, 25572, 25573, 25574, 25575, + 25576, 25579, 25580, 25582, 25583, 25584, 25585, 25587, 25589, 25591, 25593, 25594, 25595, + 25596, 25598, 25603, 25604, 25606, 25607, 25608, 25609, 25610, 25613, 25614, 25617, 25618, + 25621, 25622, 25623, 25624, 25625, 25626, 25629, 25631, 25634, 25635, 25636, 25637, 25639, + 25640, 25641, 25643, 25646, 25647, 25648, 25649, 25650, 25651, 25653, 25654, 25655, 25656, + 25657, 25659, 25660, 25662, 25664, 25666, 25667, 25673, 25675, 25676, 25677, 25678, 25679, + 25680, 25681, 25683, 25685, 25686, 25687, 25689, 25690, 25691, 25692, 25693, 25695, 25696, + 25697, 25698, 25699, 25700, 25701, 25702, 25704, 25706, 25707, 25708, 25710, 25711, 25712, + 25713, 25714, 25715, 25716, 25717, 25718, 25719, 25723, 25724, 25725, 25726, 25727, 25728, + 25729, 25731, 25734, 25736, 25737, 25738, 25739, 25740, 25741, 25742, 25743, 25744, 25747, + 25748, 25751, 25752, 25754, 25755, 25756, 25757, 25759, 25760, 25761, 25762, 25763, 25765, + 25766, 25767, 25768, 25770, 25771, 25775, 25777, 25778, 25779, 25780, 25782, 25785, 25787, + 25789, 25790, 25791, 25793, 25795, 25796, 25798, 25799, 25800, 25801, 25802, 25803, 25804, + 25807, 25809, 25811, 25812, 25813, 25814, 25817, 25818, 25819, 25820, 25821, 25823, 25824, + 25825, 25827, 25829, 25831, 25832, 25833, 25834, 25835, 25836, 25837, 25838, 25839, 25840, + 25841, 25842, 25843, 25844, 25845, 25846, 25847, 25848, 25849, 25850, 25851, 25852, 25853, + 25854, 25855, 25857, 25858, 25859, 25860, 25861, 25862, 25863, 25864, 25866, 25867, 25868, + 25869, 25870, 25871, 25872, 25873, 25875, 25876, 25877, 25878, 25879, 25881, 25882, 25883, + 25884, 25885, 25886, 25887, 25888, 25889, 25890, 25891, 25892, 25894, 25895, 25896, 25897, + 25898, 25900, 25901, 25904, 25905, 25906, 25907, 25911, 25914, 25916, 25917, 25920, 25921, + 25922, 25923, 25924, 25926, 25927, 25930, 25931, 25933, 25934, 25936, 25938, 25939, 25940, + 25943, 25944, 25946, 25948, 25951, 25952, 25953, 25956, 25957, 25959, 25960, 25961, 25962, + 25965, 25966, 25967, 25969, 25971, 25973, 25974, 25976, 25977, 25978, 25979, 25980, 25981, + 25982, 25983, 25984, 25985, 25986, 25987, 25988, 25989, 25990, 25992, 25993, 25994, 25997, + 25998, 25999, 26002, 26004, 26005, 26006, 26008, 26010, 26013, 26014, 26016, 26018, 26019, + 26022, 26024, 26026, 26028, 26030, 26033, 26034, 26035, 26036, 26037, 26038, 26039, 26040, + 26042, 26043, 26046, 26047, 26048, 26050, 26055, 26056, 26057, 26058, 26061, 26064, 26065, + 26067, 26068, 26069, 26072, 26073, 26074, 26075, 26076, 26077, 26078, 26079, 26081, 26083, + 26084, 26090, 26091, 26098, 26099, 26100, 26101, 26104, 26105, 26107, 26108, 26109, 26110, + 26111, 26113, 26116, 26117, 26119, 26120, 26121, 26123, 26125, 26128, 26129, 26130, 26134, + 26135, 26136, 26138, 26139, 26140, 26142, 26145, 26146, 26147, 26148, 26150, 26153, 26154, + 26155, 26156, 26158, 26160, 26162, 26163, 26167, 26168, 26169, 26170, 26171, 26173, 26175, + 26176, 26178, 26180, 26181, 26182, 26183, 26184, 26185, 26186, 26189, 26190, 26192, 26193, + 26200, 26201, 26203, 26204, 26205, 26206, 26208, 26210, 26211, 26213, 26215, 26217, 26218, + 26219, 26220, 26221, 26225, 26226, 26227, 26229, 26232, 26233, 26235, 26236, 26237, 26239, + 26240, 26241, 26243, 26245, 26246, 26248, 26249, 26250, 26251, 26253, 26254, 26255, 26256, + 26258, 26259, 26260, 26261, 26264, 26265, 26266, 26267, 26268, 26270, 26271, 26272, 26273, + 26274, 26275, 26276, 26277, 26278, 26281, 26282, 26283, 26284, 26285, 26287, 26288, 26289, + 26290, 26291, 26293, 26294, 26295, 26296, 26298, 26299, 26300, 26301, 26303, 26304, 26305, + 26306, 26307, 26308, 26309, 26310, 26311, 26312, 26313, 26314, 26315, 26316, 26317, 26318, + 26319, 26320, 26321, 26322, 26323, 26324, 26325, 26326, 26327, 26328, 26330, 26334, 26335, + 26336, 26337, 26338, 26339, 26340, 26341, 26343, 26344, 26346, 26347, 26348, 26349, 26350, + 26351, 26353, 26357, 26358, 26360, 26362, 26363, 26365, 26369, 26370, 26371, 26372, 26373, + 26374, 26375, 26380, 26382, 26383, 26385, 26386, 26387, 26390, 26392, 26393, 26394, 26396, + 26398, 26400, 26401, 26402, 26403, 26404, 26405, 26407, 26409, 26414, 26416, 26418, 26419, + 26422, 26423, 26424, 26425, 26427, 26428, 26430, 26431, 26433, 26436, 26437, 26439, 26442, + 26443, 26445, 26450, 26452, 26453, 26455, 26456, 26457, 26458, 26459, 26461, 26466, 26467, + 26468, 26470, 26471, 26475, 26476, 26478, 26481, 26484, 26486, 26488, 26489, 26490, 26491, + 26493, 26496, 26498, 26499, 26501, 26502, 26504, 26506, 26508, 26509, 26510, 26511, 26513, + 26514, 26515, 26516, 26518, 26521, 26523, 26527, 26528, 26529, 26532, 26534, 26537, 26540, + 26542, 26545, 26546, 26548, 26553, 26554, 26555, 26556, 26557, 26558, 26559, 26560, 26562, + 26565, 26566, 26567, 26568, 26569, 26570, 26571, 26572, 26573, 26574, 26581, 26582, 26583, + 26587, 26591, 26593, 26595, 26596, 26598, 26599, 26600, 26602, 26603, 26605, 26606, 26610, + 26613, 26614, 26615, 26616, 26617, 26618, 26619, 26620, 26622, 26625, 26626, 26627, 26628, + 26630, 26637, 26640, 26642, 26644, 26645, 26648, 26649, 26650, 26651, 26652, 26654, 26655, + 26656, 26658, 26659, 26660, 26661, 26662, 26663, 26664, 26667, 26668, 26669, 26670, 26671, + 26672, 26673, 26676, 26677, 26678, 26682, 26683, 26687, 26695, 26699, 26701, 26703, 26706, + 26710, 26711, 26712, 26713, 26714, 26715, 26716, 26717, 26718, 26719, 26730, 26732, 26733, + 26734, 26735, 26736, 26737, 26738, 26739, 26741, 26744, 26745, 26746, 26747, 26748, 26749, + 26750, 26751, 26752, 26754, 26756, 26759, 26760, 26761, 26762, 26763, 26764, 26765, 26766, + 26768, 26769, 26770, 26772, 26773, 26774, 26776, 26777, 26778, 26779, 26780, 26781, 26782, + 26783, 26784, 26785, 26787, 26788, 26789, 26793, 26794, 26795, 26796, 26798, 26801, 26802, + 26804, 26806, 26807, 26808, 26809, 26810, 26811, 26812, 26813, 26814, 26815, 26817, 26819, + 26820, 26821, 26822, 26823, 26824, 26826, 26828, 26830, 26831, 26832, 26833, 26835, 26836, + 26838, 26839, 26841, 26843, 26844, 26845, 26846, 26847, 26849, 26850, 26852, 26853, 26854, + 26855, 26856, 26857, 26858, 26859, 26860, 26861, 26863, 26866, 26867, 26868, 26870, 26871, + 26872, 26875, 26877, 26878, 26879, 26880, 26882, 26883, 26884, 26886, 26887, 26888, 26889, + 26890, 26892, 26895, 26897, 26899, 26900, 26901, 26902, 26903, 26904, 26905, 26906, 26907, + 26908, 26909, 26910, 26913, 26914, 26915, 26917, 26918, 26919, 26920, 26921, 26922, 26923, + 26924, 26926, 26927, 26929, 26930, 26931, 26933, 26934, 26935, 26936, 26938, 26939, 26940, + 26942, 26944, 26945, 26947, 26948, 26949, 26950, 26951, 26952, 26953, 26954, 26955, 26956, + 26957, 26958, 26959, 26960, 26961, 26962, 26963, 26965, 26966, 26968, 26969, 26971, 26972, + 26975, 26977, 26978, 26980, 26981, 26983, 26984, 26985, 26986, 26988, 26989, 26991, 26992, + 26994, 26995, 26996, 26997, 26998, 27002, 27003, 27005, 27006, 27007, 27009, 27011, 27013, + 27018, 27019, 27020, 27022, 27023, 27024, 27025, 27026, 27027, 27030, 27031, 27033, 27034, + 27037, 27038, 27039, 27040, 27041, 27042, 27043, 27044, 27045, 27046, 27049, 27050, 27052, + 27054, 27055, 27056, 27058, 27059, 27061, 27062, 27064, 27065, 27066, 27068, 27069, 27070, + 27071, 27072, 27074, 27075, 27076, 27077, 27078, 27079, 27080, 27081, 27083, 27085, 27087, + 27089, 27090, 27091, 27093, 27094, 27095, 27096, 27097, 27098, 27100, 27101, 27102, 27105, + 27106, 27107, 27108, 27109, 27110, 27111, 27112, 27113, 27114, 27115, 27116, 27118, 27119, + 27120, 27121, 27123, 27124, 27125, 27126, 27127, 27128, 27129, 27130, 27131, 27132, 27134, + 27136, 27137, 27138, 27139, 27140, 27141, 27142, 27143, 27144, 27145, 27147, 27148, 27149, + 27150, 27151, 27152, 27153, 27154, 27155, 27156, 27157, 27158, 27161, 27162, 27163, 27164, + 27165, 27166, 27168, 27170, 27171, 27172, 27173, 27174, 27175, 27177, 27179, 27180, 27181, + 27182, 27184, 27186, 27187, 27188, 27190, 27191, 27192, 27193, 27194, 27195, 27196, 27199, + 27200, 27201, 27202, 27203, 27205, 27206, 27208, 27209, 27210, 27211, 27212, 27213, 27214, + 27215, 27217, 27218, 27219, 27220, 27221, 27222, 27223, 27226, 27228, 27229, 27230, 27231, + 27232, 27234, 27235, 27236, 27238, 27239, 27240, 27241, 27242, 27243, 27244, 27245, 27246, + 27247, 27248, 27250, 27251, 27252, 27253, 27254, 27255, 27256, 27258, 27259, 27261, 27262, + 27263, 27265, 27266, 27267, 27269, 27270, 27271, 27272, 27273, 27274, 27275, 27276, 27277, + 27279, 27282, 27283, 27284, 27285, 27286, 27288, 27289, 27290, 27291, 27292, 27293, 27294, + 27295, 27297, 27298, 27299, 27300, 27301, 27302, 27303, 27304, 27306, 27309, 27310, 27311, + 27312, 27313, 27314, 27315, 27316, 27317, 27318, 27319, 27320, 27321, 27322, 27323, 27324, + 27325, 27326, 27327, 27328, 27329, 27330, 27331, 27332, 27333, 27334, 27335, 27336, 27337, + 27338, 27339, 27340, 27341, 27342, 27343, 27344, 27345, 27346, 27347, 27348, 27349, 27350, + 27351, 27352, 27353, 27354, 27355, 27356, 27357, 27358, 27359, 27360, 27361, 27362, 27363, + 27364, 27365, 27366, 27367, 27368, 27369, 27370, 27371, 27372, 27373, 27374, 27375, 27376, + 27377, 27378, 27379, 27380, 27381, 27382, 27383, 27384, 27385, 27386, 27387, 27388, 27389, + 27390, 27391, 27392, 27393, 27394, 27395, 27396, 27397, 27398, 27399, 27400, 27401, 27402, + 27403, 27404, 27405, 27406, 27407, 27408, 27409, 27410, 27411, 27412, 27413, 27414, 27415, + 27416, 27417, 27418, 27419, 27420, 27421, 27422, 27423, 27429, 27430, 27432, 27433, 27434, + 27435, 27436, 27437, 27438, 27439, 27440, 27441, 27443, 27444, 27445, 27446, 27448, 27451, + 27452, 27453, 27455, 27456, 27457, 27458, 27460, 27461, 27464, 27466, 27467, 27469, 27470, + 27471, 27472, 27473, 27474, 27475, 27476, 27477, 27478, 27479, 27480, 27482, 27483, 27484, + 27485, 27486, 27487, 27488, 27489, 27496, 27497, 27499, 27500, 27501, 27502, 27503, 27504, + 27505, 27506, 27507, 27508, 27509, 27510, 27511, 27512, 27514, 27517, 27518, 27519, 27520, + 27525, 27528, 27532, 27534, 27535, 27536, 27537, 27540, 27541, 27543, 27544, 27545, 27548, + 27549, 27550, 27551, 27552, 27554, 27555, 27556, 27557, 27558, 27559, 27560, 27561, 27563, + 27564, 27565, 27566, 27567, 27568, 27569, 27570, 27574, 27576, 27577, 27578, 27579, 27580, + 27581, 27582, 27584, 27587, 27588, 27590, 27591, 27592, 27593, 27594, 27596, 27598, 27600, + 27601, 27608, 27610, 27612, 27613, 27614, 27615, 27616, 27618, 27619, 27620, 27621, 27622, + 27623, 27624, 27625, 27628, 27629, 27630, 27632, 27633, 27634, 27636, 27638, 27639, 27640, + 27642, 27643, 27644, 27646, 27647, 27648, 27649, 27650, 27651, 27652, 27656, 27657, 27658, + 27659, 27660, 27662, 27666, 27671, 27676, 27677, 27678, 27680, 27683, 27685, 27691, 27692, + 27693, 27697, 27699, 27702, 27703, 27705, 27706, 27707, 27708, 27710, 27711, 27715, 27716, + 27717, 27720, 27723, 27724, 27725, 27726, 27727, 27729, 27730, 27731, 27734, 27736, 27737, + 27738, 27746, 27747, 27749, 27750, 27751, 27755, 27756, 27757, 27758, 27759, 27761, 27763, + 27765, 27767, 27768, 27770, 27771, 27772, 27775, 27776, 27780, 27783, 27786, 27787, 27789, + 27790, 27793, 27794, 27797, 27798, 27799, 27800, 27802, 27804, 27805, 27806, 27808, 27810, + 27816, 27820, 27823, 27824, 27828, 27829, 27830, 27831, 27834, 27840, 27841, 27842, 27843, + 27846, 27847, 27848, 27851, 27853, 27854, 27855, 27857, 27858, 27864, 27865, 27866, 27868, + 27869, 27871, 27876, 27878, 27879, 27881, 27884, 27885, 27890, 27892, 27897, 27903, 27904, + 27906, 27907, 27909, 27910, 27912, 27913, 27914, 27917, 27919, 27920, 27921, 27923, 27924, + 27925, 27926, 27928, 27932, 27933, 27935, 27936, 27937, 27938, 27939, 27940, 27942, 27944, + 27945, 27948, 27949, 27951, 27952, 27956, 27958, 27959, 27960, 27962, 27967, 27968, 27970, + 27972, 27977, 27980, 27984, 27989, 27990, 27991, 27992, 27995, 27997, 27999, 28001, 28002, + 28004, 28005, 28007, 28008, 28011, 28012, 28013, 28016, 28017, 28018, 28019, 28021, 28022, + 28025, 28026, 28027, 28029, 28030, 28031, 28032, 28033, 28035, 28036, 28038, 28039, 28042, + 28043, 28045, 28047, 28048, 28050, 28054, 28055, 28056, 28057, 28058, 28060, 28066, 28069, + 28076, 28077, 28080, 28081, 28083, 28084, 28086, 28087, 28089, 28090, 28091, 28092, 28093, + 28094, 28097, 28098, 28099, 28104, 28105, 28106, 28109, 28110, 28111, 28112, 28114, 28115, + 28116, 28117, 28119, 28122, 28123, 28124, 28127, 28130, 28131, 28133, 28135, 28136, 28137, + 28138, 28141, 28143, 28144, 28146, 28148, 28149, 28150, 28152, 28154, 28157, 28158, 28159, + 28160, 28161, 28162, 28163, 28164, 28166, 28167, 28168, 28169, 28171, 28175, 28178, 28179, + 28181, 28184, 28185, 28187, 28188, 28190, 28191, 28194, 28198, 28199, 28200, 28202, 28204, + 28206, 28208, 28209, 28211, 28213, 28214, 28215, 28217, 28219, 28220, 28221, 28222, 28223, + 28224, 28225, 28226, 28229, 28230, 28231, 28232, 28233, 28234, 28235, 28236, 28239, 28240, + 28241, 28242, 28245, 28247, 28249, 28250, 28252, 28253, 28254, 28256, 28257, 28258, 28259, + 28260, 28261, 28262, 28263, 28264, 28265, 28266, 28268, 28269, 28271, 28272, 28273, 28274, + 28275, 28276, 28277, 28278, 28279, 28280, 28281, 28282, 28283, 28284, 28285, 28288, 28289, + 28290, 28292, 28295, 28296, 28298, 28299, 28300, 28301, 28302, 28305, 28306, 28307, 28308, + 28309, 28310, 28311, 28313, 28314, 28315, 28317, 28318, 28320, 28321, 28323, 28324, 28326, + 28328, 28329, 28331, 28332, 28333, 28334, 28336, 28339, 28341, 28344, 28345, 28348, 28350, + 28351, 28352, 28355, 28356, 28357, 28358, 28360, 28361, 28362, 28364, 28365, 28366, 28368, + 28370, 28374, 28376, 28377, 28379, 28380, 28381, 28387, 28391, 28394, 28395, 28396, 28397, + 28398, 28399, 28400, 28401, 28402, 28403, 28405, 28406, 28407, 28408, 28410, 28411, 28412, + 28413, 28414, 28415, 28416, 28417, 28419, 28420, 28421, 28423, 28424, 28426, 28427, 28428, + 28429, 28430, 28432, 28433, 28434, 28438, 28439, 28440, 28441, 28442, 28443, 28444, 28445, + 28446, 28447, 28449, 28450, 28451, 28453, 28454, 28455, 28456, 28460, 28462, 28464, 28466, + 28468, 28469, 28471, 28472, 28473, 28474, 28475, 28476, 28477, 28479, 28480, 28481, 28482, + 28483, 28484, 28485, 28488, 28489, 28490, 28492, 28494, 28495, 28496, 28497, 28498, 28499, + 28500, 28501, 28502, 28503, 28505, 28506, 28507, 28509, 28511, 28512, 28513, 28515, 28516, + 28517, 28519, 28520, 28521, 28522, 28523, 28524, 28527, 28528, 28529, 28531, 28533, 28534, + 28535, 28537, 28539, 28541, 28542, 28543, 28544, 28545, 28546, 28547, 28549, 28550, 28551, + 28554, 28555, 28559, 28560, 28561, 28562, 28563, 28564, 28565, 28566, 28567, 28568, 28569, + 28570, 28571, 28573, 28574, 28575, 28576, 28578, 28579, 28580, 28581, 28582, 28584, 28585, + 28586, 28587, 28588, 28589, 28590, 28591, 28592, 28593, 28594, 28596, 28597, 28599, 28600, + 28602, 28603, 28604, 28605, 28606, 28607, 28609, 28611, 28612, 28613, 28614, 28615, 28616, + 28618, 28619, 28620, 28621, 28622, 28623, 28624, 28627, 28628, 28629, 28630, 28631, 28632, + 28633, 28634, 28635, 28636, 28637, 28639, 28642, 28643, 28644, 28645, 28646, 28647, 28648, + 28649, 28650, 28651, 28652, 28653, 28656, 28657, 28658, 28659, 28660, 28661, 28662, 28663, + 28664, 28665, 28666, 28667, 28668, 28669, 28670, 28671, 28672, 28673, 28674, 28675, 28676, + 28677, 28678, 28679, 28680, 28681, 28682, 28683, 28684, 28685, 28686, 28687, 28688, 28690, + 28691, 28692, 28693, 28694, 28695, 28696, 28697, 28700, 28701, 28702, 28703, 28704, 28705, + 28706, 28708, 28709, 28710, 28711, 28712, 28713, 28714, 28715, 28716, 28717, 28718, 28719, + 28720, 28721, 28722, 28723, 28724, 28726, 28727, 28728, 28730, 28731, 28732, 28733, 28734, + 28735, 28736, 28737, 28738, 28739, 28740, 28741, 28742, 28743, 28744, 28745, 28746, 28747, + 28749, 28750, 28752, 28753, 28754, 28755, 28756, 28757, 28758, 28759, 28760, 28761, 28762, + 28763, 28764, 28765, 28767, 28768, 28769, 28770, 28771, 28772, 28773, 28774, 28775, 28776, + 28777, 28778, 28782, 28785, 28786, 28787, 28788, 28791, 28793, 28794, 28795, 28797, 28801, + 28802, 28803, 28804, 28806, 28807, 28808, 28811, 28812, 28813, 28815, 28816, 28817, 28819, + 28823, 28824, 28826, 28827, 28830, 28831, 28832, 28833, 28834, 28835, 28836, 28837, 28838, + 28839, 28840, 28841, 28842, 28848, 28850, 28852, 28853, 28854, 28858, 28862, 28863, 28868, + 28869, 28870, 28871, 28873, 28875, 28876, 28877, 28878, 28879, 28880, 28881, 28882, 28883, + 28884, 28885, 28886, 28887, 28890, 28892, 28893, 28894, 28896, 28897, 28898, 28899, 28901, + 28906, 28910, 28912, 28913, 28914, 28915, 28916, 28917, 28918, 28920, 28922, 28923, 28924, + 28926, 28927, 28928, 28929, 28930, 28931, 28932, 28933, 28934, 28935, 28936, 28939, 28940, + 28941, 28942, 28943, 28945, 28946, 28948, 28951, 28955, 28956, 28957, 28958, 28959, 28960, + 28961, 28962, 28963, 28964, 28965, 28967, 28968, 28969, 28970, 28971, 28972, 28973, 28974, + 28978, 28979, 28980, 28981, 28983, 28984, 28985, 28986, 28987, 28988, 28989, 28990, 28991, + 28992, 28993, 28994, 28995, 28996, 28998, 28999, 29000, 29001, 29003, 29005, 29007, 29008, + 29009, 29010, 29011, 29012, 29013, 29014, 29015, 29016, 29017, 29018, 29019, 29021, 29023, + 29024, 29025, 29026, 29027, 29029, 29033, 29034, 29035, 29036, 29037, 29039, 29040, 29041, + 29044, 29045, 29046, 29047, 29049, 29051, 29052, 29054, 29055, 29056, 29057, 29058, 29059, + 29061, 29062, 29063, 29064, 29065, 29067, 29068, 29069, 29070, 29072, 29073, 29074, 29075, + 29077, 29078, 29079, 29082, 29083, 29084, 29085, 29086, 29089, 29090, 29091, 29092, 29093, + 29094, 29095, 29097, 29098, 29099, 29101, 29102, 29103, 29104, 29105, 29106, 29108, 29110, + 29111, 29112, 29114, 29115, 29116, 29117, 29118, 29119, 29120, 29121, 29122, 29124, 29125, + 29126, 29127, 29128, 29129, 29130, 29131, 29132, 29133, 29135, 29136, 29137, 29138, 29139, + 29142, 29143, 29144, 29145, 29146, 29147, 29148, 29149, 29150, 29151, 29153, 29154, 29155, + 29156, 29158, 29160, 29161, 29162, 29163, 29164, 29165, 29167, 29168, 29169, 29170, 29171, + 29172, 29173, 29174, 29175, 29176, 29178, 29179, 29180, 29181, 29182, 29183, 29184, 29185, + 29186, 29187, 29188, 29189, 29191, 29192, 29193, 29194, 29195, 29196, 29197, 29198, 29199, + 29200, 29201, 29202, 29203, 29204, 29205, 29206, 29207, 29208, 29209, 29210, 29211, 29212, + 29214, 29215, 29216, 29217, 29218, 29219, 29220, 29221, 29222, 29223, 29225, 29227, 29229, + 29230, 29231, 29234, 29235, 29236, 29242, 29244, 29246, 29248, 29249, 29250, 29251, 29252, + 29253, 29254, 29257, 29258, 29259, 29262, 29263, 29264, 29265, 29267, 29268, 29269, 29271, + 29272, 29274, 29276, 29278, 29280, 29283, 29284, 29285, 29288, 29290, 29291, 29292, 29293, + 29296, 29297, 29299, 29300, 29302, 29303, 29304, 29307, 29308, 29309, 29314, 29315, 29317, + 29318, 29319, 29320, 29321, 29324, 29326, 29328, 29329, 29331, 29332, 29333, 29334, 29335, + 29336, 29337, 29338, 29339, 29340, 29341, 29342, 29344, 29345, 29346, 29347, 29348, 29349, + 29350, 29351, 29352, 29353, 29354, 29355, 29358, 29361, 29362, 29363, 29365, 29370, 29371, + 29372, 29373, 29374, 29375, 29376, 29381, 29382, 29383, 29385, 29386, 29387, 29388, 29391, + 29393, 29395, 29396, 29397, 29398, 29400, 29402, 29403, 58566, 58567, 58568, 58569, 58570, + 58571, 58572, 58573, 58574, 58575, 58576, 58577, 58578, 58579, 58580, 58581, 58582, 58583, + 58584, 58585, 58586, 58587, 58588, 58589, 58590, 58591, 58592, 58593, 58594, 58595, 58596, + 58597, 58598, 58599, 58600, 58601, 58602, 58603, 58604, 58605, 58606, 58607, 58608, 58609, + 58610, 58611, 58612, 58613, 58614, 58615, 58616, 58617, 58618, 58619, 58620, 58621, 58622, + 58623, 58624, 58625, 58626, 58627, 58628, 58629, 58630, 58631, 58632, 58633, 58634, 58635, + 58636, 58637, 58638, 58639, 58640, 58641, 58642, 58643, 58644, 58645, 58646, 58647, 58648, + 58649, 58650, 58651, 58652, 58653, 58654, 58655, 58656, 58657, 58658, 58659, 58660, 58661, + 12288, 12289, 12290, 183, 713, 711, 168, 12291, 12293, 8212, 65374, 8214, 8230, 8216, 8217, + 8220, 8221, 12308, 12309, 12296, 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12310, 12311, + 12304, 12305, 177, 215, 247, 8758, 8743, 8744, 8721, 8719, 8746, 8745, 8712, 8759, 8730, 8869, + 8741, 8736, 8978, 8857, 8747, 8750, 8801, 8780, 8776, 8765, 8733, 8800, 8814, 8815, 8804, 8805, + 8734, 8757, 8756, 9794, 9792, 176, 8242, 8243, 8451, 65284, 164, 65504, 65505, 8240, 167, 8470, + 9734, 9733, 9675, 9679, 9678, 9671, 9670, 9633, 9632, 9651, 9650, 8251, 8594, 8592, 8593, 8595, + 12307, 58662, 58663, 58664, 58665, 58666, 58667, 58668, 58669, 58670, 58671, 58672, 58673, + 58674, 58675, 58676, 58677, 58678, 58679, 58680, 58681, 58682, 58683, 58684, 58685, 58686, + 58687, 58688, 58689, 58690, 58691, 58692, 58693, 58694, 58695, 58696, 58697, 58698, 58699, + 58700, 58701, 58702, 58703, 58704, 58705, 58706, 58707, 58708, 58709, 58710, 58711, 58712, + 58713, 58714, 58715, 58716, 58717, 58718, 58719, 58720, 58721, 58722, 58723, 58724, 58725, + 58726, 58727, 58728, 58729, 58730, 58731, 58732, 58733, 58734, 58735, 58736, 58737, 58738, + 58739, 58740, 58741, 58742, 58743, 58744, 58745, 58746, 58747, 58748, 58749, 58750, 58751, + 58752, 58753, 58754, 58755, 58756, 58757, 8560, 8561, 8562, 8563, 8564, 8565, 8566, 8567, 8568, + 8569, 59238, 59239, 59240, 59241, 59242, 59243, 9352, 9353, 9354, 9355, 9356, 9357, 9358, 9359, + 9360, 9361, 9362, 9363, 9364, 9365, 9366, 9367, 9368, 9369, 9370, 9371, 9332, 9333, 9334, 9335, + 9336, 9337, 9338, 9339, 9340, 9341, 9342, 9343, 9344, 9345, 9346, 9347, 9348, 9349, 9350, 9351, + 9312, 9313, 9314, 9315, 9316, 9317, 9318, 9319, 9320, 9321, 8364, 59245, 12832, 12833, 12834, + 12835, 12836, 12837, 12838, 12839, 12840, 12841, 59246, 59247, 8544, 8545, 8546, 8547, 8548, + 8549, 8550, 8551, 8552, 8553, 8554, 8555, 59248, 59249, 58758, 58759, 58760, 58761, 58762, + 58763, 58764, 58765, 58766, 58767, 58768, 58769, 58770, 58771, 58772, 58773, 58774, 58775, + 58776, 58777, 58778, 58779, 58780, 58781, 58782, 58783, 58784, 58785, 58786, 58787, 58788, + 58789, 58790, 58791, 58792, 58793, 58794, 58795, 58796, 58797, 58798, 58799, 58800, 58801, + 58802, 58803, 58804, 58805, 58806, 58807, 58808, 58809, 58810, 58811, 58812, 58813, 58814, + 58815, 58816, 58817, 58818, 58819, 58820, 58821, 58822, 58823, 58824, 58825, 58826, 58827, + 58828, 58829, 58830, 58831, 58832, 58833, 58834, 58835, 58836, 58837, 58838, 58839, 58840, + 58841, 58842, 58843, 58844, 58845, 58846, 58847, 58848, 58849, 58850, 58851, 58852, 58853, + 65281, 65282, 65283, 65509, 65285, 65286, 65287, 65288, 65289, 65290, 65291, 65292, 65293, + 65294, 65295, 65296, 65297, 65298, 65299, 65300, 65301, 65302, 65303, 65304, 65305, 65306, + 65307, 65308, 65309, 65310, 65311, 65312, 65313, 65314, 65315, 65316, 65317, 65318, 65319, + 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, + 65333, 65334, 65335, 65336, 65337, 65338, 65339, 65340, 65341, 65342, 65343, 65344, 65345, + 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, + 65359, 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 65371, + 65372, 65373, 65507, 58854, 58855, 58856, 58857, 58858, 58859, 58860, 58861, 58862, 58863, + 58864, 58865, 58866, 58867, 58868, 58869, 58870, 58871, 58872, 58873, 58874, 58875, 58876, + 58877, 58878, 58879, 58880, 58881, 58882, 58883, 58884, 58885, 58886, 58887, 58888, 58889, + 58890, 58891, 58892, 58893, 58894, 58895, 58896, 58897, 58898, 58899, 58900, 58901, 58902, + 58903, 58904, 58905, 58906, 58907, 58908, 58909, 58910, 58911, 58912, 58913, 58914, 58915, + 58916, 58917, 58918, 58919, 58920, 58921, 58922, 58923, 58924, 58925, 58926, 58927, 58928, + 58929, 58930, 58931, 58932, 58933, 58934, 58935, 58936, 58937, 58938, 58939, 58940, 58941, + 58942, 58943, 58944, 58945, 58946, 58947, 58948, 58949, 12353, 12354, 12355, 12356, 12357, + 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, 12367, 12368, 12369, 12370, + 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, 12381, 12382, 12383, + 12384, 12385, 12386, 12387, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, + 12397, 12398, 12399, 12400, 12401, 12402, 12403, 12404, 12405, 12406, 12407, 12408, 12409, + 12410, 12411, 12412, 12413, 12414, 12415, 12416, 12417, 12418, 12419, 12420, 12421, 12422, + 12423, 12424, 12425, 12426, 12427, 12428, 12429, 12430, 12431, 12432, 12433, 12434, 12435, + 59250, 59251, 59252, 59253, 59254, 59255, 59256, 59257, 59258, 59259, 59260, 58950, 58951, + 58952, 58953, 58954, 58955, 58956, 58957, 58958, 58959, 58960, 58961, 58962, 58963, 58964, + 58965, 58966, 58967, 58968, 58969, 58970, 58971, 58972, 58973, 58974, 58975, 58976, 58977, + 58978, 58979, 58980, 58981, 58982, 58983, 58984, 58985, 58986, 58987, 58988, 58989, 58990, + 58991, 58992, 58993, 58994, 58995, 58996, 58997, 58998, 58999, 59000, 59001, 59002, 59003, + 59004, 59005, 59006, 59007, 59008, 59009, 59010, 59011, 59012, 59013, 59014, 59015, 59016, + 59017, 59018, 59019, 59020, 59021, 59022, 59023, 59024, 59025, 59026, 59027, 59028, 59029, + 59030, 59031, 59032, 59033, 59034, 59035, 59036, 59037, 59038, 59039, 59040, 59041, 59042, + 59043, 59044, 59045, 12449, 12450, 12451, 12452, 12453, 12454, 12455, 12456, 12457, 12458, + 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, 12467, 12468, 12469, 12470, 12471, + 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, 12481, 12482, 12483, 12484, + 12485, 12486, 12487, 12488, 12489, 12490, 12491, 12492, 12493, 12494, 12495, 12496, 12497, + 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, 12507, 12508, 12509, 12510, + 12511, 12512, 12513, 12514, 12515, 12516, 12517, 12518, 12519, 12520, 12521, 12522, 12523, + 12524, 12525, 12526, 12527, 12528, 12529, 12530, 12531, 12532, 12533, 12534, 59261, 59262, + 59263, 59264, 59265, 59266, 59267, 59268, 59046, 59047, 59048, 59049, 59050, 59051, 59052, + 59053, 59054, 59055, 59056, 59057, 59058, 59059, 59060, 59061, 59062, 59063, 59064, 59065, + 59066, 59067, 59068, 59069, 59070, 59071, 59072, 59073, 59074, 59075, 59076, 59077, 59078, + 59079, 59080, 59081, 59082, 59083, 59084, 59085, 59086, 59087, 59088, 59089, 59090, 59091, + 59092, 59093, 59094, 59095, 59096, 59097, 59098, 59099, 59100, 59101, 59102, 59103, 59104, + 59105, 59106, 59107, 59108, 59109, 59110, 59111, 59112, 59113, 59114, 59115, 59116, 59117, + 59118, 59119, 59120, 59121, 59122, 59123, 59124, 59125, 59126, 59127, 59128, 59129, 59130, + 59131, 59132, 59133, 59134, 59135, 59136, 59137, 59138, 59139, 59140, 59141, 913, 914, 915, 916, + 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, + 937, 59269, 59270, 59271, 59272, 59273, 59274, 59275, 59276, 945, 946, 947, 948, 949, 950, 951, + 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967, 968, 969, 59277, + 59278, 59279, 59280, 59281, 59282, 59283, 65077, 65078, 65081, 65082, 65087, 65088, 65085, + 65086, 65089, 65090, 65091, 65092, 59284, 59285, 65083, 65084, 65079, 65080, 65073, 59286, + 65075, 65076, 59287, 59288, 59289, 59290, 59291, 59292, 59293, 59294, 59295, 59142, 59143, + 59144, 59145, 59146, 59147, 59148, 59149, 59150, 59151, 59152, 59153, 59154, 59155, 59156, + 59157, 59158, 59159, 59160, 59161, 59162, 59163, 59164, 59165, 59166, 59167, 59168, 59169, + 59170, 59171, 59172, 59173, 59174, 59175, 59176, 59177, 59178, 59179, 59180, 59181, 59182, + 59183, 59184, 59185, 59186, 59187, 59188, 59189, 59190, 59191, 59192, 59193, 59194, 59195, + 59196, 59197, 59198, 59199, 59200, 59201, 59202, 59203, 59204, 59205, 59206, 59207, 59208, + 59209, 59210, 59211, 59212, 59213, 59214, 59215, 59216, 59217, 59218, 59219, 59220, 59221, + 59222, 59223, 59224, 59225, 59226, 59227, 59228, 59229, 59230, 59231, 59232, 59233, 59234, + 59235, 59236, 59237, 1040, 1041, 1042, 1043, 1044, 1045, 1025, 1046, 1047, 1048, 1049, 1050, + 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, + 1067, 1068, 1069, 1070, 1071, 59296, 59297, 59298, 59299, 59300, 59301, 59302, 59303, 59304, + 59305, 59306, 59307, 59308, 59309, 59310, 1072, 1073, 1074, 1075, 1076, 1077, 1105, 1078, 1079, + 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, + 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 59311, 59312, 59313, 59314, 59315, 59316, 59317, + 59318, 59319, 59320, 59321, 59322, 59323, 714, 715, 729, 8211, 8213, 8229, 8245, 8453, 8457, + 8598, 8599, 8600, 8601, 8725, 8735, 8739, 8786, 8806, 8807, 8895, 9552, 9553, 9554, 9555, 9556, + 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, + 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9581, 9582, 9583, 9584, 9585, 9586, 9587, 9601, + 9602, 9603, 9604, 9605, 9606, 9607, 9608, 9609, 9610, 9611, 9612, 9613, 9614, 9615, 9619, 9620, + 9621, 9660, 9661, 9698, 9699, 9700, 9701, 9737, 8853, 12306, 12317, 12318, 59324, 59325, 59326, + 59327, 59328, 59329, 59330, 59331, 59332, 59333, 59334, 257, 225, 462, 224, 275, 233, 283, 232, + 299, 237, 464, 236, 333, 243, 466, 242, 363, 250, 468, 249, 470, 472, 474, 476, 252, 234, 593, + 59335, 324, 328, 505, 609, 59337, 59338, 59339, 59340, 12549, 12550, 12551, 12552, 12553, 12554, + 12555, 12556, 12557, 12558, 12559, 12560, 12561, 12562, 12563, 12564, 12565, 12566, 12567, + 12568, 12569, 12570, 12571, 12572, 12573, 12574, 12575, 12576, 12577, 12578, 12579, 12580, + 12581, 12582, 12583, 12584, 12585, 59341, 59342, 59343, 59344, 59345, 59346, 59347, 59348, + 59349, 59350, 59351, 59352, 59353, 59354, 59355, 59356, 59357, 59358, 59359, 59360, 59361, + 12321, 12322, 12323, 12324, 12325, 12326, 12327, 12328, 12329, 12963, 13198, 13199, 13212, + 13213, 13214, 13217, 13252, 13262, 13265, 13266, 13269, 65072, 65506, 65508, 59362, 8481, 12849, + 59363, 8208, 59364, 59365, 59366, 12540, 12443, 12444, 12541, 12542, 12294, 12445, 12446, 65097, + 65098, 65099, 65100, 65101, 65102, 65103, 65104, 65105, 65106, 65108, 65109, 65110, 65111, + 65113, 65114, 65115, 65116, 65117, 65118, 65119, 65120, 65121, 65122, 65123, 65124, 65125, + 65126, 65128, 65129, 65130, 65131, 12350, 12272, 12273, 12274, 12275, 12276, 12277, 12278, + 12279, 12280, 12281, 12282, 12283, 12295, 59380, 59381, 59382, 59383, 59384, 59385, 59386, + 59387, 59388, 59389, 59390, 59391, 59392, 9472, 9473, 9474, 9475, 9476, 9477, 9478, 9479, 9480, + 9481, 9482, 9483, 9484, 9485, 9486, 9487, 9488, 9489, 9490, 9491, 9492, 9493, 9494, 9495, 9496, + 9497, 9498, 9499, 9500, 9501, 9502, 9503, 9504, 9505, 9506, 9507, 9508, 9509, 9510, 9511, 9512, + 9513, 9514, 9515, 9516, 9517, 9518, 9519, 9520, 9521, 9522, 9523, 9524, 9525, 9526, 9527, 9528, + 9529, 9530, 9531, 9532, 9533, 9534, 9535, 9536, 9537, 9538, 9539, 9540, 9541, 9542, 9543, 9544, + 9545, 9546, 9547, 59393, 59394, 59395, 59396, 59397, 59398, 59399, 59400, 59401, 59402, 59403, + 59404, 59405, 59406, 59407, 29404, 29405, 29407, 29410, 29411, 29412, 29413, 29414, 29415, + 29418, 29419, 29429, 29430, 29433, 29437, 29438, 29439, 29440, 29442, 29444, 29445, 29446, + 29447, 29448, 29449, 29451, 29452, 29453, 29455, 29456, 29457, 29458, 29460, 29464, 29465, + 29466, 29471, 29472, 29475, 29476, 29478, 29479, 29480, 29485, 29487, 29488, 29490, 29491, + 29493, 29494, 29498, 29499, 29500, 29501, 29504, 29505, 29506, 29507, 29508, 29509, 29510, + 29511, 29512, 29513, 29514, 29515, 29516, 29518, 29519, 29521, 29523, 29524, 29525, 29526, + 29528, 29529, 29530, 29531, 29532, 29533, 29534, 29535, 29537, 29538, 29539, 29540, 29541, + 29542, 29543, 29544, 29545, 29546, 29547, 29550, 29552, 29553, 57344, 57345, 57346, 57347, + 57348, 57349, 57350, 57351, 57352, 57353, 57354, 57355, 57356, 57357, 57358, 57359, 57360, + 57361, 57362, 57363, 57364, 57365, 57366, 57367, 57368, 57369, 57370, 57371, 57372, 57373, + 57374, 57375, 57376, 57377, 57378, 57379, 57380, 57381, 57382, 57383, 57384, 57385, 57386, + 57387, 57388, 57389, 57390, 57391, 57392, 57393, 57394, 57395, 57396, 57397, 57398, 57399, + 57400, 57401, 57402, 57403, 57404, 57405, 57406, 57407, 57408, 57409, 57410, 57411, 57412, + 57413, 57414, 57415, 57416, 57417, 57418, 57419, 57420, 57421, 57422, 57423, 57424, 57425, + 57426, 57427, 57428, 57429, 57430, 57431, 57432, 57433, 57434, 57435, 57436, 57437, 29554, + 29555, 29556, 29557, 29558, 29559, 29560, 29561, 29562, 29563, 29564, 29565, 29567, 29568, + 29569, 29570, 29571, 29573, 29574, 29576, 29578, 29580, 29581, 29583, 29584, 29586, 29587, + 29588, 29589, 29591, 29592, 29593, 29594, 29596, 29597, 29598, 29600, 29601, 29603, 29604, + 29605, 29606, 29607, 29608, 29610, 29612, 29613, 29617, 29620, 29621, 29622, 29624, 29625, + 29628, 29629, 29630, 29631, 29633, 29635, 29636, 29637, 29638, 29639, 29643, 29644, 29646, + 29650, 29651, 29652, 29653, 29654, 29655, 29656, 29658, 29659, 29660, 29661, 29663, 29665, + 29666, 29667, 29668, 29670, 29672, 29674, 29675, 29676, 29678, 29679, 29680, 29681, 29683, + 29684, 29685, 29686, 29687, 57438, 57439, 57440, 57441, 57442, 57443, 57444, 57445, 57446, + 57447, 57448, 57449, 57450, 57451, 57452, 57453, 57454, 57455, 57456, 57457, 57458, 57459, + 57460, 57461, 57462, 57463, 57464, 57465, 57466, 57467, 57468, 57469, 57470, 57471, 57472, + 57473, 57474, 57475, 57476, 57477, 57478, 57479, 57480, 57481, 57482, 57483, 57484, 57485, + 57486, 57487, 57488, 57489, 57490, 57491, 57492, 57493, 57494, 57495, 57496, 57497, 57498, + 57499, 57500, 57501, 57502, 57503, 57504, 57505, 57506, 57507, 57508, 57509, 57510, 57511, + 57512, 57513, 57514, 57515, 57516, 57517, 57518, 57519, 57520, 57521, 57522, 57523, 57524, + 57525, 57526, 57527, 57528, 57529, 57530, 57531, 29688, 29689, 29690, 29691, 29692, 29693, + 29694, 29695, 29696, 29697, 29698, 29700, 29703, 29704, 29707, 29708, 29709, 29710, 29713, + 29714, 29715, 29716, 29717, 29718, 29719, 29720, 29721, 29724, 29725, 29726, 29727, 29728, + 29729, 29731, 29732, 29735, 29737, 29739, 29741, 29743, 29745, 29746, 29751, 29752, 29753, + 29754, 29755, 29757, 29758, 29759, 29760, 29762, 29763, 29764, 29765, 29766, 29767, 29768, + 29769, 29770, 29771, 29772, 29773, 29774, 29775, 29776, 29777, 29778, 29779, 29780, 29782, + 29784, 29789, 29792, 29793, 29794, 29795, 29796, 29797, 29798, 29799, 29800, 29801, 29802, + 29803, 29804, 29806, 29807, 29809, 29810, 29811, 29812, 29813, 29816, 29817, 29818, 57532, + 57533, 57534, 57535, 57536, 57537, 57538, 57539, 57540, 57541, 57542, 57543, 57544, 57545, + 57546, 57547, 57548, 57549, 57550, 57551, 57552, 57553, 57554, 57555, 57556, 57557, 57558, + 57559, 57560, 57561, 57562, 57563, 57564, 57565, 57566, 57567, 57568, 57569, 57570, 57571, + 57572, 57573, 57574, 57575, 57576, 57577, 57578, 57579, 57580, 57581, 57582, 57583, 57584, + 57585, 57586, 57587, 57588, 57589, 57590, 57591, 57592, 57593, 57594, 57595, 57596, 57597, + 57598, 57599, 57600, 57601, 57602, 57603, 57604, 57605, 57606, 57607, 57608, 57609, 57610, + 57611, 57612, 57613, 57614, 57615, 57616, 57617, 57618, 57619, 57620, 57621, 57622, 57623, + 57624, 57625, 29819, 29820, 29821, 29823, 29826, 29828, 29829, 29830, 29832, 29833, 29834, + 29836, 29837, 29839, 29841, 29842, 29843, 29844, 29845, 29846, 29847, 29848, 29849, 29850, + 29851, 29853, 29855, 29856, 29857, 29858, 29859, 29860, 29861, 29862, 29866, 29867, 29868, + 29869, 29870, 29871, 29872, 29873, 29874, 29875, 29876, 29877, 29878, 29879, 29880, 29881, + 29883, 29884, 29885, 29886, 29887, 29888, 29889, 29890, 29891, 29892, 29893, 29894, 29895, + 29896, 29897, 29898, 29899, 29900, 29901, 29902, 29903, 29904, 29905, 29907, 29908, 29909, + 29910, 29911, 29912, 29913, 29914, 29915, 29917, 29919, 29921, 29925, 29927, 29928, 29929, + 29930, 29931, 29932, 29933, 29936, 29937, 29938, 57626, 57627, 57628, 57629, 57630, 57631, + 57632, 57633, 57634, 57635, 57636, 57637, 57638, 57639, 57640, 57641, 57642, 57643, 57644, + 57645, 57646, 57647, 57648, 57649, 57650, 57651, 57652, 57653, 57654, 57655, 57656, 57657, + 57658, 57659, 57660, 57661, 57662, 57663, 57664, 57665, 57666, 57667, 57668, 57669, 57670, + 57671, 57672, 57673, 57674, 57675, 57676, 57677, 57678, 57679, 57680, 57681, 57682, 57683, + 57684, 57685, 57686, 57687, 57688, 57689, 57690, 57691, 57692, 57693, 57694, 57695, 57696, + 57697, 57698, 57699, 57700, 57701, 57702, 57703, 57704, 57705, 57706, 57707, 57708, 57709, + 57710, 57711, 57712, 57713, 57714, 57715, 57716, 57717, 57718, 57719, 29939, 29941, 29944, + 29945, 29946, 29947, 29948, 29949, 29950, 29952, 29953, 29954, 29955, 29957, 29958, 29959, + 29960, 29961, 29962, 29963, 29964, 29966, 29968, 29970, 29972, 29973, 29974, 29975, 29979, + 29981, 29982, 29984, 29985, 29986, 29987, 29988, 29990, 29991, 29994, 29998, 30004, 30006, + 30009, 30012, 30013, 30015, 30017, 30018, 30019, 30020, 30022, 30023, 30025, 30026, 30029, + 30032, 30033, 30034, 30035, 30037, 30038, 30039, 30040, 30045, 30046, 30047, 30048, 30049, + 30050, 30051, 30052, 30055, 30056, 30057, 30059, 30060, 30061, 30062, 30063, 30064, 30065, + 30067, 30069, 30070, 30071, 30074, 30075, 30076, 30077, 30078, 30080, 30081, 30082, 30084, + 30085, 30087, 57720, 57721, 57722, 57723, 57724, 57725, 57726, 57727, 57728, 57729, 57730, + 57731, 57732, 57733, 57734, 57735, 57736, 57737, 57738, 57739, 57740, 57741, 57742, 57743, + 57744, 57745, 57746, 57747, 57748, 57749, 57750, 57751, 57752, 57753, 57754, 57755, 57756, + 57757, 57758, 57759, 57760, 57761, 57762, 57763, 57764, 57765, 57766, 57767, 57768, 57769, + 57770, 57771, 57772, 57773, 57774, 57775, 57776, 57777, 57778, 57779, 57780, 57781, 57782, + 57783, 57784, 57785, 57786, 57787, 57788, 57789, 57790, 57791, 57792, 57793, 57794, 57795, + 57796, 57797, 57798, 57799, 57800, 57801, 57802, 57803, 57804, 57805, 57806, 57807, 57808, + 57809, 57810, 57811, 57812, 57813, 30088, 30089, 30090, 30092, 30093, 30094, 30096, 30099, + 30101, 30104, 30107, 30108, 30110, 30114, 30118, 30119, 30120, 30121, 30122, 30125, 30134, + 30135, 30138, 30139, 30143, 30144, 30145, 30150, 30155, 30156, 30158, 30159, 30160, 30161, + 30163, 30167, 30169, 30170, 30172, 30173, 30175, 30176, 30177, 30181, 30185, 30188, 30189, + 30190, 30191, 30194, 30195, 30197, 30198, 30199, 30200, 30202, 30203, 30205, 30206, 30210, + 30212, 30214, 30215, 30216, 30217, 30219, 30221, 30222, 30223, 30225, 30226, 30227, 30228, + 30230, 30234, 30236, 30237, 30238, 30241, 30243, 30247, 30248, 30252, 30254, 30255, 30257, + 30258, 30262, 30263, 30265, 30266, 30267, 30269, 30273, 30274, 30276, 57814, 57815, 57816, + 57817, 57818, 57819, 57820, 57821, 57822, 57823, 57824, 57825, 57826, 57827, 57828, 57829, + 57830, 57831, 57832, 57833, 57834, 57835, 57836, 57837, 57838, 57839, 57840, 57841, 57842, + 57843, 57844, 57845, 57846, 57847, 57848, 57849, 57850, 57851, 57852, 57853, 57854, 57855, + 57856, 57857, 57858, 57859, 57860, 57861, 57862, 57863, 57864, 57865, 57866, 57867, 57868, + 57869, 57870, 57871, 57872, 57873, 57874, 57875, 57876, 57877, 57878, 57879, 57880, 57881, + 57882, 57883, 57884, 57885, 57886, 57887, 57888, 57889, 57890, 57891, 57892, 57893, 57894, + 57895, 57896, 57897, 57898, 57899, 57900, 57901, 57902, 57903, 57904, 57905, 57906, 57907, + 30277, 30278, 30279, 30280, 30281, 30282, 30283, 30286, 30287, 30288, 30289, 30290, 30291, + 30293, 30295, 30296, 30297, 30298, 30299, 30301, 30303, 30304, 30305, 30306, 30308, 30309, + 30310, 30311, 30312, 30313, 30314, 30316, 30317, 30318, 30320, 30321, 30322, 30323, 30324, + 30325, 30326, 30327, 30329, 30330, 30332, 30335, 30336, 30337, 30339, 30341, 30345, 30346, + 30348, 30349, 30351, 30352, 30354, 30356, 30357, 30359, 30360, 30362, 30363, 30364, 30365, + 30366, 30367, 30368, 30369, 30370, 30371, 30373, 30374, 30375, 30376, 30377, 30378, 30379, + 30380, 30381, 30383, 30384, 30387, 30389, 30390, 30391, 30392, 30393, 30394, 30395, 30396, + 30397, 30398, 30400, 30401, 30403, 21834, 38463, 22467, 25384, 21710, 21769, 21696, 30353, + 30284, 34108, 30702, 33406, 30861, 29233, 38552, 38797, 27688, 23433, 20474, 25353, 26263, + 23736, 33018, 26696, 32942, 26114, 30414, 20985, 25942, 29100, 32753, 34948, 20658, 22885, + 25034, 28595, 33453, 25420, 25170, 21485, 21543, 31494, 20843, 30116, 24052, 25300, 36299, + 38774, 25226, 32793, 22365, 38712, 32610, 29240, 30333, 26575, 30334, 25670, 20336, 36133, + 25308, 31255, 26001, 29677, 25644, 25203, 33324, 39041, 26495, 29256, 25198, 25292, 20276, + 29923, 21322, 21150, 32458, 37030, 24110, 26758, 27036, 33152, 32465, 26834, 30917, 34444, + 38225, 20621, 35876, 33502, 32990, 21253, 35090, 21093, 30404, 30407, 30409, 30411, 30412, + 30419, 30421, 30425, 30426, 30428, 30429, 30430, 30432, 30433, 30434, 30435, 30436, 30438, + 30439, 30440, 30441, 30442, 30443, 30444, 30445, 30448, 30451, 30453, 30454, 30455, 30458, + 30459, 30461, 30463, 30464, 30466, 30467, 30469, 30470, 30474, 30476, 30478, 30479, 30480, + 30481, 30482, 30483, 30484, 30485, 30486, 30487, 30488, 30491, 30492, 30493, 30494, 30497, + 30499, 30500, 30501, 30503, 30506, 30507, 30508, 30510, 30512, 30513, 30514, 30515, 30516, + 30521, 30523, 30525, 30526, 30527, 30530, 30532, 30533, 30534, 30536, 30537, 30538, 30539, + 30540, 30541, 30542, 30543, 30546, 30547, 30548, 30549, 30550, 30551, 30552, 30553, 30556, + 34180, 38649, 20445, 22561, 39281, 23453, 25265, 25253, 26292, 35961, 40077, 29190, 26479, + 30865, 24754, 21329, 21271, 36744, 32972, 36125, 38049, 20493, 29384, 22791, 24811, 28953, + 34987, 22868, 33519, 26412, 31528, 23849, 32503, 29997, 27893, 36454, 36856, 36924, 40763, + 27604, 37145, 31508, 24444, 30887, 34006, 34109, 27605, 27609, 27606, 24065, 24199, 30201, + 38381, 25949, 24330, 24517, 36767, 22721, 33218, 36991, 38491, 38829, 36793, 32534, 36140, + 25153, 20415, 21464, 21342, 36776, 36777, 36779, 36941, 26631, 24426, 33176, 34920, 40150, + 24971, 21035, 30250, 24428, 25996, 28626, 28392, 23486, 25672, 20853, 20912, 26564, 19993, + 31177, 39292, 28851, 30557, 30558, 30559, 30560, 30564, 30567, 30569, 30570, 30573, 30574, + 30575, 30576, 30577, 30578, 30579, 30580, 30581, 30582, 30583, 30584, 30586, 30587, 30588, + 30593, 30594, 30595, 30598, 30599, 30600, 30601, 30602, 30603, 30607, 30608, 30611, 30612, + 30613, 30614, 30615, 30616, 30617, 30618, 30619, 30620, 30621, 30622, 30625, 30627, 30628, + 30630, 30632, 30635, 30637, 30638, 30639, 30641, 30642, 30644, 30646, 30647, 30648, 30649, + 30650, 30652, 30654, 30656, 30657, 30658, 30659, 30660, 30661, 30662, 30663, 30664, 30665, + 30666, 30667, 30668, 30670, 30671, 30672, 30673, 30674, 30675, 30676, 30677, 30678, 30680, + 30681, 30682, 30685, 30686, 30687, 30688, 30689, 30692, 30149, 24182, 29627, 33760, 25773, + 25320, 38069, 27874, 21338, 21187, 25615, 38082, 31636, 20271, 24091, 33334, 33046, 33162, + 28196, 27850, 39539, 25429, 21340, 21754, 34917, 22496, 19981, 24067, 27493, 31807, 37096, + 24598, 25830, 29468, 35009, 26448, 25165, 36130, 30572, 36393, 37319, 24425, 33756, 34081, + 39184, 21442, 34453, 27531, 24813, 24808, 28799, 33485, 33329, 20179, 27815, 34255, 25805, + 31961, 27133, 26361, 33609, 21397, 31574, 20391, 20876, 27979, 23618, 36461, 25554, 21449, + 33580, 33590, 26597, 30900, 25661, 23519, 23700, 24046, 35815, 25286, 26612, 35962, 25600, + 25530, 34633, 39307, 35863, 32544, 38130, 20135, 38416, 39076, 26124, 29462, 30694, 30696, + 30698, 30703, 30704, 30705, 30706, 30708, 30709, 30711, 30713, 30714, 30715, 30716, 30723, + 30724, 30725, 30726, 30727, 30728, 30730, 30731, 30734, 30735, 30736, 30739, 30741, 30745, + 30747, 30750, 30752, 30753, 30754, 30756, 30760, 30762, 30763, 30766, 30767, 30769, 30770, + 30771, 30773, 30774, 30781, 30783, 30785, 30786, 30787, 30788, 30790, 30792, 30793, 30794, + 30795, 30797, 30799, 30801, 30803, 30804, 30808, 30809, 30810, 30811, 30812, 30814, 30815, + 30816, 30817, 30818, 30819, 30820, 30821, 30822, 30823, 30824, 30825, 30831, 30832, 30833, + 30834, 30835, 30836, 30837, 30838, 30840, 30841, 30842, 30843, 30845, 30846, 30847, 30848, + 30849, 30850, 30851, 22330, 23581, 24120, 38271, 20607, 32928, 21378, 25950, 30021, 21809, + 20513, 36229, 25220, 38046, 26397, 22066, 28526, 24034, 21557, 28818, 36710, 25199, 25764, + 25507, 24443, 28552, 37108, 33251, 36784, 23576, 26216, 24561, 27785, 38472, 36225, 34924, + 25745, 31216, 22478, 27225, 25104, 21576, 20056, 31243, 24809, 28548, 35802, 25215, 36894, + 39563, 31204, 21507, 30196, 25345, 21273, 27744, 36831, 24347, 39536, 32827, 40831, 20360, + 23610, 36196, 32709, 26021, 28861, 20805, 20914, 34411, 23815, 23456, 25277, 37228, 30068, + 36364, 31264, 24833, 31609, 20167, 32504, 30597, 19985, 33261, 21021, 20986, 27249, 21416, + 36487, 38148, 38607, 28353, 38500, 26970, 30852, 30853, 30854, 30856, 30858, 30859, 30863, + 30864, 30866, 30868, 30869, 30870, 30873, 30877, 30878, 30880, 30882, 30884, 30886, 30888, + 30889, 30890, 30891, 30892, 30893, 30894, 30895, 30901, 30902, 30903, 30904, 30906, 30907, + 30908, 30909, 30911, 30912, 30914, 30915, 30916, 30918, 30919, 30920, 30924, 30925, 30926, + 30927, 30929, 30930, 30931, 30934, 30935, 30936, 30938, 30939, 30940, 30941, 30942, 30943, + 30944, 30945, 30946, 30947, 30948, 30949, 30950, 30951, 30953, 30954, 30955, 30957, 30958, + 30959, 30960, 30961, 30963, 30965, 30966, 30968, 30969, 30971, 30972, 30973, 30974, 30975, + 30976, 30978, 30979, 30980, 30982, 30983, 30984, 30985, 30986, 30987, 30988, 30784, 20648, + 30679, 25616, 35302, 22788, 25571, 24029, 31359, 26941, 20256, 33337, 21912, 20018, 30126, + 31383, 24162, 24202, 38383, 21019, 21561, 28810, 25462, 38180, 22402, 26149, 26943, 37255, + 21767, 28147, 32431, 34850, 25139, 32496, 30133, 33576, 30913, 38604, 36766, 24904, 29943, + 35789, 27492, 21050, 36176, 27425, 32874, 33905, 22257, 21254, 20174, 19995, 20945, 31895, + 37259, 31751, 20419, 36479, 31713, 31388, 25703, 23828, 20652, 33030, 30209, 31929, 28140, + 32736, 26449, 23384, 23544, 30923, 25774, 25619, 25514, 25387, 38169, 25645, 36798, 31572, + 30249, 25171, 22823, 21574, 27513, 20643, 25140, 24102, 27526, 20195, 36151, 34955, 24453, + 36910, 30989, 30990, 30991, 30992, 30993, 30994, 30996, 30997, 30998, 30999, 31000, 31001, + 31002, 31003, 31004, 31005, 31007, 31008, 31009, 31010, 31011, 31013, 31014, 31015, 31016, + 31017, 31018, 31019, 31020, 31021, 31022, 31023, 31024, 31025, 31026, 31027, 31029, 31030, + 31031, 31032, 31033, 31037, 31039, 31042, 31043, 31044, 31045, 31047, 31050, 31051, 31052, + 31053, 31054, 31055, 31056, 31057, 31058, 31060, 31061, 31064, 31065, 31073, 31075, 31076, + 31078, 31081, 31082, 31083, 31084, 31086, 31088, 31089, 31090, 31091, 31092, 31093, 31094, + 31097, 31099, 31100, 31101, 31102, 31103, 31106, 31107, 31110, 31111, 31112, 31113, 31115, + 31116, 31117, 31118, 31120, 31121, 31122, 24608, 32829, 25285, 20025, 21333, 37112, 25528, + 32966, 26086, 27694, 20294, 24814, 28129, 35806, 24377, 34507, 24403, 25377, 20826, 33633, + 26723, 20992, 25443, 36424, 20498, 23707, 31095, 23548, 21040, 31291, 24764, 36947, 30423, + 24503, 24471, 30340, 36460, 28783, 30331, 31561, 30634, 20979, 37011, 22564, 20302, 28404, + 36842, 25932, 31515, 29380, 28068, 32735, 23265, 25269, 24213, 22320, 33922, 31532, 24093, + 24351, 36882, 32532, 39072, 25474, 28359, 30872, 28857, 20856, 38747, 22443, 30005, 20291, + 30008, 24215, 24806, 22880, 28096, 27583, 30857, 21500, 38613, 20939, 20993, 25481, 21514, + 38035, 35843, 36300, 29241, 30879, 34678, 36845, 35853, 21472, 31123, 31124, 31125, 31126, + 31127, 31128, 31129, 31131, 31132, 31133, 31134, 31135, 31136, 31137, 31138, 31139, 31140, + 31141, 31142, 31144, 31145, 31146, 31147, 31148, 31149, 31150, 31151, 31152, 31153, 31154, + 31156, 31157, 31158, 31159, 31160, 31164, 31167, 31170, 31172, 31173, 31175, 31176, 31178, + 31180, 31182, 31183, 31184, 31187, 31188, 31190, 31191, 31193, 31194, 31195, 31196, 31197, + 31198, 31200, 31201, 31202, 31205, 31208, 31210, 31212, 31214, 31217, 31218, 31219, 31220, + 31221, 31222, 31223, 31225, 31226, 31228, 31230, 31231, 31233, 31236, 31237, 31239, 31240, + 31241, 31242, 31244, 31247, 31248, 31249, 31250, 31251, 31253, 31254, 31256, 31257, 31259, + 31260, 19969, 30447, 21486, 38025, 39030, 40718, 38189, 23450, 35746, 20002, 19996, 20908, + 33891, 25026, 21160, 26635, 20375, 24683, 20923, 27934, 20828, 25238, 26007, 38497, 35910, + 36887, 30168, 37117, 30563, 27602, 29322, 29420, 35835, 22581, 30585, 36172, 26460, 38208, + 32922, 24230, 28193, 22930, 31471, 30701, 38203, 27573, 26029, 32526, 22534, 20817, 38431, + 23545, 22697, 21544, 36466, 25958, 39039, 22244, 38045, 30462, 36929, 25479, 21702, 22810, + 22842, 22427, 36530, 26421, 36346, 33333, 21057, 24816, 22549, 34558, 23784, 40517, 20420, + 39069, 35769, 23077, 24694, 21380, 25212, 36943, 37122, 39295, 24681, 32780, 20799, 32819, + 23572, 39285, 27953, 20108, 31261, 31263, 31265, 31266, 31268, 31269, 31270, 31271, 31272, + 31273, 31274, 31275, 31276, 31277, 31278, 31279, 31280, 31281, 31282, 31284, 31285, 31286, + 31288, 31290, 31294, 31296, 31297, 31298, 31299, 31300, 31301, 31303, 31304, 31305, 31306, + 31307, 31308, 31309, 31310, 31311, 31312, 31314, 31315, 31316, 31317, 31318, 31320, 31321, + 31322, 31323, 31324, 31325, 31326, 31327, 31328, 31329, 31330, 31331, 31332, 31333, 31334, + 31335, 31336, 31337, 31338, 31339, 31340, 31341, 31342, 31343, 31345, 31346, 31347, 31349, + 31355, 31356, 31357, 31358, 31362, 31365, 31367, 31369, 31370, 31371, 31372, 31374, 31375, + 31376, 31379, 31380, 31385, 31386, 31387, 31390, 31393, 31394, 36144, 21457, 32602, 31567, + 20240, 20047, 38400, 27861, 29648, 34281, 24070, 30058, 32763, 27146, 30718, 38034, 32321, + 20961, 28902, 21453, 36820, 33539, 36137, 29359, 39277, 27867, 22346, 33459, 26041, 32938, + 25151, 38450, 22952, 20223, 35775, 32442, 25918, 33778, 38750, 21857, 39134, 32933, 21290, + 35837, 21536, 32954, 24223, 27832, 36153, 33452, 37210, 21545, 27675, 20998, 32439, 22367, + 28954, 27774, 31881, 22859, 20221, 24575, 24868, 31914, 20016, 23553, 26539, 34562, 23792, + 38155, 39118, 30127, 28925, 36898, 20911, 32541, 35773, 22857, 20964, 20315, 21542, 22827, + 25975, 32932, 23413, 25206, 25282, 36752, 24133, 27679, 31526, 20239, 20440, 26381, 31395, + 31396, 31399, 31401, 31402, 31403, 31406, 31407, 31408, 31409, 31410, 31412, 31413, 31414, + 31415, 31416, 31417, 31418, 31419, 31420, 31421, 31422, 31424, 31425, 31426, 31427, 31428, + 31429, 31430, 31431, 31432, 31433, 31434, 31436, 31437, 31438, 31439, 31440, 31441, 31442, + 31443, 31444, 31445, 31447, 31448, 31450, 31451, 31452, 31453, 31457, 31458, 31460, 31463, + 31464, 31465, 31466, 31467, 31468, 31470, 31472, 31473, 31474, 31475, 31476, 31477, 31478, + 31479, 31480, 31483, 31484, 31486, 31488, 31489, 31490, 31493, 31495, 31497, 31500, 31501, + 31502, 31504, 31506, 31507, 31510, 31511, 31512, 31514, 31516, 31517, 31519, 31521, 31522, + 31523, 31527, 31529, 31533, 28014, 28074, 31119, 34993, 24343, 29995, 25242, 36741, 20463, + 37340, 26023, 33071, 33105, 24220, 33104, 36212, 21103, 35206, 36171, 22797, 20613, 20184, + 38428, 29238, 33145, 36127, 23500, 35747, 38468, 22919, 32538, 21648, 22134, 22030, 35813, + 25913, 27010, 38041, 30422, 28297, 24178, 29976, 26438, 26577, 31487, 32925, 36214, 24863, + 31174, 25954, 36195, 20872, 21018, 38050, 32568, 32923, 32434, 23703, 28207, 26464, 31705, + 30347, 39640, 33167, 32660, 31957, 25630, 38224, 31295, 21578, 21733, 27468, 25601, 25096, + 40509, 33011, 30105, 21106, 38761, 33883, 26684, 34532, 38401, 38548, 38124, 20010, 21508, + 32473, 26681, 36319, 32789, 26356, 24218, 32697, 31535, 31536, 31538, 31540, 31541, 31542, + 31543, 31545, 31547, 31549, 31551, 31552, 31553, 31554, 31555, 31556, 31558, 31560, 31562, + 31565, 31566, 31571, 31573, 31575, 31577, 31580, 31582, 31583, 31585, 31587, 31588, 31589, + 31590, 31591, 31592, 31593, 31594, 31595, 31596, 31597, 31599, 31600, 31603, 31604, 31606, + 31608, 31610, 31612, 31613, 31615, 31617, 31618, 31619, 31620, 31622, 31623, 31624, 31625, + 31626, 31627, 31628, 31630, 31631, 31633, 31634, 31635, 31638, 31640, 31641, 31642, 31643, + 31646, 31647, 31648, 31651, 31652, 31653, 31662, 31663, 31664, 31666, 31667, 31669, 31670, + 31671, 31673, 31674, 31675, 31676, 31677, 31678, 31679, 31680, 31682, 31683, 31684, 22466, + 32831, 26775, 24037, 25915, 21151, 24685, 40858, 20379, 36524, 20844, 23467, 24339, 24041, + 27742, 25329, 36129, 20849, 38057, 21246, 27807, 33503, 29399, 22434, 26500, 36141, 22815, + 36764, 33735, 21653, 31629, 20272, 27837, 23396, 22993, 40723, 21476, 34506, 39592, 35895, + 32929, 25925, 39038, 22266, 38599, 21038, 29916, 21072, 23521, 25346, 35074, 20054, 25296, + 24618, 26874, 20851, 23448, 20896, 35266, 31649, 39302, 32592, 24815, 28748, 36143, 20809, + 24191, 36891, 29808, 35268, 22317, 30789, 24402, 40863, 38394, 36712, 39740, 35809, 30328, + 26690, 26588, 36330, 36149, 21053, 36746, 28378, 26829, 38149, 37101, 22269, 26524, 35065, + 36807, 21704, 31685, 31688, 31689, 31690, 31691, 31693, 31694, 31695, 31696, 31698, 31700, + 31701, 31702, 31703, 31704, 31707, 31708, 31710, 31711, 31712, 31714, 31715, 31716, 31719, + 31720, 31721, 31723, 31724, 31725, 31727, 31728, 31730, 31731, 31732, 31733, 31734, 31736, + 31737, 31738, 31739, 31741, 31743, 31744, 31745, 31746, 31747, 31748, 31749, 31750, 31752, + 31753, 31754, 31757, 31758, 31760, 31761, 31762, 31763, 31764, 31765, 31767, 31768, 31769, + 31770, 31771, 31772, 31773, 31774, 31776, 31777, 31778, 31779, 31780, 31781, 31784, 31785, + 31787, 31788, 31789, 31790, 31791, 31792, 31793, 31794, 31795, 31796, 31797, 31798, 31799, + 31801, 31802, 31803, 31804, 31805, 31806, 31810, 39608, 23401, 28023, 27686, 20133, 23475, + 39559, 37219, 25000, 37039, 38889, 21547, 28085, 23506, 20989, 21898, 32597, 32752, 25788, + 25421, 26097, 25022, 24717, 28938, 27735, 27721, 22831, 26477, 33322, 22741, 22158, 35946, + 27627, 37085, 22909, 32791, 21495, 28009, 21621, 21917, 33655, 33743, 26680, 31166, 21644, + 20309, 21512, 30418, 35977, 38402, 27827, 28088, 36203, 35088, 40548, 36154, 22079, 40657, + 30165, 24456, 29408, 24680, 21756, 20136, 27178, 34913, 24658, 36720, 21700, 28888, 34425, + 40511, 27946, 23439, 24344, 32418, 21897, 20399, 29492, 21564, 21402, 20505, 21518, 21628, + 20046, 24573, 29786, 22774, 33899, 32993, 34676, 29392, 31946, 28246, 31811, 31812, 31813, + 31814, 31815, 31816, 31817, 31818, 31819, 31820, 31822, 31823, 31824, 31825, 31826, 31827, + 31828, 31829, 31830, 31831, 31832, 31833, 31834, 31835, 31836, 31837, 31838, 31839, 31840, + 31841, 31842, 31843, 31844, 31845, 31846, 31847, 31848, 31849, 31850, 31851, 31852, 31853, + 31854, 31855, 31856, 31857, 31858, 31861, 31862, 31863, 31864, 31865, 31866, 31870, 31871, + 31872, 31873, 31874, 31875, 31876, 31877, 31878, 31879, 31880, 31882, 31883, 31884, 31885, + 31886, 31887, 31888, 31891, 31892, 31894, 31897, 31898, 31899, 31904, 31905, 31907, 31910, + 31911, 31912, 31913, 31915, 31916, 31917, 31919, 31920, 31924, 31925, 31926, 31927, 31928, + 31930, 31931, 24359, 34382, 21804, 25252, 20114, 27818, 25143, 33457, 21719, 21326, 29502, + 28369, 30011, 21010, 21270, 35805, 27088, 24458, 24576, 28142, 22351, 27426, 29615, 26707, + 36824, 32531, 25442, 24739, 21796, 30186, 35938, 28949, 28067, 23462, 24187, 33618, 24908, + 40644, 30970, 34647, 31783, 30343, 20976, 24822, 29004, 26179, 24140, 24653, 35854, 28784, + 25381, 36745, 24509, 24674, 34516, 22238, 27585, 24724, 24935, 21321, 24800, 26214, 36159, + 31229, 20250, 28905, 27719, 35763, 35826, 32472, 33636, 26127, 23130, 39746, 27985, 28151, + 35905, 27963, 20249, 28779, 33719, 25110, 24785, 38669, 36135, 31096, 20987, 22334, 22522, + 26426, 30072, 31293, 31215, 31637, 31935, 31936, 31938, 31939, 31940, 31942, 31945, 31947, + 31950, 31951, 31952, 31953, 31954, 31955, 31956, 31960, 31962, 31963, 31965, 31966, 31969, + 31970, 31971, 31972, 31973, 31974, 31975, 31977, 31978, 31979, 31980, 31981, 31982, 31984, + 31985, 31986, 31987, 31988, 31989, 31990, 31991, 31993, 31994, 31996, 31997, 31998, 31999, + 32000, 32001, 32002, 32003, 32004, 32005, 32006, 32007, 32008, 32009, 32011, 32012, 32013, + 32014, 32015, 32016, 32017, 32018, 32019, 32020, 32021, 32022, 32023, 32024, 32025, 32026, + 32027, 32028, 32029, 32030, 32031, 32033, 32035, 32036, 32037, 32038, 32040, 32041, 32042, + 32044, 32045, 32046, 32048, 32049, 32050, 32051, 32052, 32053, 32054, 32908, 39269, 36857, + 28608, 35749, 40481, 23020, 32489, 32521, 21513, 26497, 26840, 36753, 31821, 38598, 21450, + 24613, 30142, 27762, 21363, 23241, 32423, 25380, 20960, 33034, 24049, 34015, 25216, 20864, + 23395, 20238, 31085, 21058, 24760, 27982, 23492, 23490, 35745, 35760, 26082, 24524, 38469, + 22931, 32487, 32426, 22025, 26551, 22841, 20339, 23478, 21152, 33626, 39050, 36158, 30002, + 38078, 20551, 31292, 20215, 26550, 39550, 23233, 27516, 30417, 22362, 23574, 31546, 38388, + 29006, 20860, 32937, 33392, 22904, 32516, 33575, 26816, 26604, 30897, 30839, 25315, 25441, + 31616, 20461, 21098, 20943, 33616, 27099, 37492, 36341, 36145, 35265, 38190, 31661, 20214, + 32055, 32056, 32057, 32058, 32059, 32060, 32061, 32062, 32063, 32064, 32065, 32066, 32067, + 32068, 32069, 32070, 32071, 32072, 32073, 32074, 32075, 32076, 32077, 32078, 32079, 32080, + 32081, 32082, 32083, 32084, 32085, 32086, 32087, 32088, 32089, 32090, 32091, 32092, 32093, + 32094, 32095, 32096, 32097, 32098, 32099, 32100, 32101, 32102, 32103, 32104, 32105, 32106, + 32107, 32108, 32109, 32111, 32112, 32113, 32114, 32115, 32116, 32117, 32118, 32120, 32121, + 32122, 32123, 32124, 32125, 32126, 32127, 32128, 32129, 32130, 32131, 32132, 32133, 32134, + 32135, 32136, 32137, 32138, 32139, 32140, 32141, 32142, 32143, 32144, 32145, 32146, 32147, + 32148, 32149, 32150, 32151, 32152, 20581, 33328, 21073, 39279, 28176, 28293, 28071, 24314, + 20725, 23004, 23558, 27974, 27743, 30086, 33931, 26728, 22870, 35762, 21280, 37233, 38477, + 34121, 26898, 30977, 28966, 33014, 20132, 37066, 27975, 39556, 23047, 22204, 25605, 38128, + 30699, 20389, 33050, 29409, 35282, 39290, 32564, 32478, 21119, 25945, 37237, 36735, 36739, + 21483, 31382, 25581, 25509, 30342, 31224, 34903, 38454, 25130, 21163, 33410, 26708, 26480, + 25463, 30571, 31469, 27905, 32467, 35299, 22992, 25106, 34249, 33445, 30028, 20511, 20171, + 30117, 35819, 23626, 24062, 31563, 26020, 37329, 20170, 27941, 35167, 32039, 38182, 20165, + 35880, 36827, 38771, 26187, 31105, 36817, 28908, 28024, 32153, 32154, 32155, 32156, 32157, + 32158, 32159, 32160, 32161, 32162, 32163, 32164, 32165, 32167, 32168, 32169, 32170, 32171, + 32172, 32173, 32175, 32176, 32177, 32178, 32179, 32180, 32181, 32182, 32183, 32184, 32185, + 32186, 32187, 32188, 32189, 32190, 32191, 32192, 32193, 32194, 32195, 32196, 32197, 32198, + 32199, 32200, 32201, 32202, 32203, 32204, 32205, 32206, 32207, 32208, 32209, 32210, 32211, + 32212, 32213, 32214, 32215, 32216, 32217, 32218, 32219, 32220, 32221, 32222, 32223, 32224, + 32225, 32226, 32227, 32228, 32229, 32230, 32231, 32232, 32233, 32234, 32235, 32236, 32237, + 32238, 32239, 32240, 32241, 32242, 32243, 32244, 32245, 32246, 32247, 32248, 32249, 32250, + 23613, 21170, 33606, 20834, 33550, 30555, 26230, 40120, 20140, 24778, 31934, 31923, 32463, + 20117, 35686, 26223, 39048, 38745, 22659, 25964, 38236, 24452, 30153, 38742, 31455, 31454, + 20928, 28847, 31384, 25578, 31350, 32416, 29590, 38893, 20037, 28792, 20061, 37202, 21417, + 25937, 26087, 33276, 33285, 21646, 23601, 30106, 38816, 25304, 29401, 30141, 23621, 39545, + 33738, 23616, 21632, 30697, 20030, 27822, 32858, 25298, 25454, 24040, 20855, 36317, 36382, + 38191, 20465, 21477, 24807, 28844, 21095, 25424, 40515, 23071, 20518, 30519, 21367, 32482, + 25733, 25899, 25225, 25496, 20500, 29237, 35273, 20915, 35776, 32477, 22343, 33740, 38055, + 20891, 21531, 23803, 32251, 32252, 32253, 32254, 32255, 32256, 32257, 32258, 32259, 32260, + 32261, 32262, 32263, 32264, 32265, 32266, 32267, 32268, 32269, 32270, 32271, 32272, 32273, + 32274, 32275, 32276, 32277, 32278, 32279, 32280, 32281, 32282, 32283, 32284, 32285, 32286, + 32287, 32288, 32289, 32290, 32291, 32292, 32293, 32294, 32295, 32296, 32297, 32298, 32299, + 32300, 32301, 32302, 32303, 32304, 32305, 32306, 32307, 32308, 32309, 32310, 32311, 32312, + 32313, 32314, 32316, 32317, 32318, 32319, 32320, 32322, 32323, 32324, 32325, 32326, 32328, + 32329, 32330, 32331, 32332, 32333, 32334, 32335, 32336, 32337, 32338, 32339, 32340, 32341, + 32342, 32343, 32344, 32345, 32346, 32347, 32348, 32349, 20426, 31459, 27994, 37089, 39567, + 21888, 21654, 21345, 21679, 24320, 25577, 26999, 20975, 24936, 21002, 22570, 21208, 22350, + 30733, 30475, 24247, 24951, 31968, 25179, 25239, 20130, 28821, 32771, 25335, 28900, 38752, + 22391, 33499, 26607, 26869, 30933, 39063, 31185, 22771, 21683, 21487, 28212, 20811, 21051, + 23458, 35838, 32943, 21827, 22438, 24691, 22353, 21549, 31354, 24656, 23380, 25511, 25248, + 21475, 25187, 23495, 26543, 21741, 31391, 33510, 37239, 24211, 35044, 22840, 22446, 25358, + 36328, 33007, 22359, 31607, 20393, 24555, 23485, 27454, 21281, 31568, 29378, 26694, 30719, + 30518, 26103, 20917, 20111, 30420, 23743, 31397, 33909, 22862, 39745, 20608, 32350, 32351, + 32352, 32353, 32354, 32355, 32356, 32357, 32358, 32359, 32360, 32361, 32362, 32363, 32364, + 32365, 32366, 32367, 32368, 32369, 32370, 32371, 32372, 32373, 32374, 32375, 32376, 32377, + 32378, 32379, 32380, 32381, 32382, 32383, 32384, 32385, 32387, 32388, 32389, 32390, 32391, + 32392, 32393, 32394, 32395, 32396, 32397, 32398, 32399, 32400, 32401, 32402, 32403, 32404, + 32405, 32406, 32407, 32408, 32409, 32410, 32412, 32413, 32414, 32430, 32436, 32443, 32444, + 32470, 32484, 32492, 32505, 32522, 32528, 32542, 32567, 32569, 32571, 32572, 32573, 32574, + 32575, 32576, 32577, 32579, 32582, 32583, 32584, 32585, 32586, 32587, 32588, 32589, 32590, + 32591, 32594, 32595, 39304, 24871, 28291, 22372, 26118, 25414, 22256, 25324, 25193, 24275, + 38420, 22403, 25289, 21895, 34593, 33098, 36771, 21862, 33713, 26469, 36182, 34013, 23146, + 26639, 25318, 31726, 38417, 20848, 28572, 35888, 25597, 35272, 25042, 32518, 28866, 28389, + 29701, 27028, 29436, 24266, 37070, 26391, 28010, 25438, 21171, 29282, 32769, 20332, 23013, + 37226, 28889, 28061, 21202, 20048, 38647, 38253, 34174, 30922, 32047, 20769, 22418, 25794, + 32907, 31867, 27882, 26865, 26974, 20919, 21400, 26792, 29313, 40654, 31729, 29432, 31163, + 28435, 29702, 26446, 37324, 40100, 31036, 33673, 33620, 21519, 26647, 20029, 21385, 21169, + 30782, 21382, 21033, 20616, 20363, 20432, 32598, 32601, 32603, 32604, 32605, 32606, 32608, + 32611, 32612, 32613, 32614, 32615, 32619, 32620, 32621, 32623, 32624, 32627, 32629, 32630, + 32631, 32632, 32634, 32635, 32636, 32637, 32639, 32640, 32642, 32643, 32644, 32645, 32646, + 32647, 32648, 32649, 32651, 32653, 32655, 32656, 32657, 32658, 32659, 32661, 32662, 32663, + 32664, 32665, 32667, 32668, 32672, 32674, 32675, 32677, 32678, 32680, 32681, 32682, 32683, + 32684, 32685, 32686, 32689, 32691, 32692, 32693, 32694, 32695, 32698, 32699, 32702, 32704, + 32706, 32707, 32708, 32710, 32711, 32712, 32713, 32715, 32717, 32719, 32720, 32721, 32722, + 32723, 32726, 32727, 32729, 32730, 32731, 32732, 32733, 32734, 32738, 32739, 30178, 31435, + 31890, 27813, 38582, 21147, 29827, 21737, 20457, 32852, 33714, 36830, 38256, 24265, 24604, + 28063, 24088, 25947, 33080, 38142, 24651, 28860, 32451, 31918, 20937, 26753, 31921, 33391, + 20004, 36742, 37327, 26238, 20142, 35845, 25769, 32842, 20698, 30103, 29134, 23525, 36797, + 28518, 20102, 25730, 38243, 24278, 26009, 21015, 35010, 28872, 21155, 29454, 29747, 26519, + 30967, 38678, 20020, 37051, 40158, 28107, 20955, 36161, 21533, 25294, 29618, 33777, 38646, + 40836, 38083, 20278, 32666, 20940, 28789, 38517, 23725, 39046, 21478, 20196, 28316, 29705, + 27060, 30827, 39311, 30041, 21016, 30244, 27969, 26611, 20845, 40857, 32843, 21657, 31548, + 31423, 32740, 32743, 32744, 32746, 32747, 32748, 32749, 32751, 32754, 32756, 32757, 32758, + 32759, 32760, 32761, 32762, 32765, 32766, 32767, 32770, 32775, 32776, 32777, 32778, 32782, + 32783, 32785, 32787, 32794, 32795, 32797, 32798, 32799, 32801, 32803, 32804, 32811, 32812, + 32813, 32814, 32815, 32816, 32818, 32820, 32825, 32826, 32828, 32830, 32832, 32833, 32836, + 32837, 32839, 32840, 32841, 32846, 32847, 32848, 32849, 32851, 32853, 32854, 32855, 32857, + 32859, 32860, 32861, 32862, 32863, 32864, 32865, 32866, 32867, 32868, 32869, 32870, 32871, + 32872, 32875, 32876, 32877, 32878, 32879, 32880, 32882, 32883, 32884, 32885, 32886, 32887, + 32888, 32889, 32890, 32891, 32892, 32893, 38534, 22404, 25314, 38471, 27004, 23044, 25602, + 31699, 28431, 38475, 33446, 21346, 39045, 24208, 28809, 25523, 21348, 34383, 40065, 40595, + 30860, 38706, 36335, 36162, 40575, 28510, 31108, 24405, 38470, 25134, 39540, 21525, 38109, + 20387, 26053, 23653, 23649, 32533, 34385, 27695, 24459, 29575, 28388, 32511, 23782, 25371, + 23402, 28390, 21365, 20081, 25504, 30053, 25249, 36718, 20262, 20177, 27814, 32438, 35770, + 33821, 34746, 32599, 36923, 38179, 31657, 39585, 35064, 33853, 27931, 39558, 32476, 22920, + 40635, 29595, 30721, 34434, 39532, 39554, 22043, 21527, 22475, 20080, 40614, 21334, 36808, + 33033, 30610, 39314, 34542, 28385, 34067, 26364, 24930, 28459, 32894, 32897, 32898, 32901, + 32904, 32906, 32909, 32910, 32911, 32912, 32913, 32914, 32916, 32917, 32919, 32921, 32926, + 32931, 32934, 32935, 32936, 32940, 32944, 32947, 32949, 32950, 32952, 32953, 32955, 32965, + 32967, 32968, 32969, 32970, 32971, 32975, 32976, 32977, 32978, 32979, 32980, 32981, 32984, + 32991, 32992, 32994, 32995, 32998, 33006, 33013, 33015, 33017, 33019, 33022, 33023, 33024, + 33025, 33027, 33028, 33029, 33031, 33032, 33035, 33036, 33045, 33047, 33049, 33051, 33052, + 33053, 33055, 33056, 33057, 33058, 33059, 33060, 33061, 33062, 33063, 33064, 33065, 33066, + 33067, 33069, 33070, 33072, 33075, 33076, 33077, 33079, 33081, 33082, 33083, 33084, 33085, + 33087, 35881, 33426, 33579, 30450, 27667, 24537, 33725, 29483, 33541, 38170, 27611, 30683, + 38086, 21359, 33538, 20882, 24125, 35980, 36152, 20040, 29611, 26522, 26757, 37238, 38665, + 29028, 27809, 30473, 23186, 38209, 27599, 32654, 26151, 23504, 22969, 23194, 38376, 38391, + 20204, 33804, 33945, 27308, 30431, 38192, 29467, 26790, 23391, 30511, 37274, 38753, 31964, + 36855, 35868, 24357, 31859, 31192, 35269, 27852, 34588, 23494, 24130, 26825, 30496, 32501, + 20885, 20813, 21193, 23081, 32517, 38754, 33495, 25551, 30596, 34256, 31186, 28218, 24217, + 22937, 34065, 28781, 27665, 25279, 30399, 25935, 24751, 38397, 26126, 34719, 40483, 38125, + 21517, 21629, 35884, 25720, 33088, 33089, 33090, 33091, 33092, 33093, 33095, 33097, 33101, + 33102, 33103, 33106, 33110, 33111, 33112, 33115, 33116, 33117, 33118, 33119, 33121, 33122, + 33123, 33124, 33126, 33128, 33130, 33131, 33132, 33135, 33138, 33139, 33141, 33142, 33143, + 33144, 33153, 33155, 33156, 33157, 33158, 33159, 33161, 33163, 33164, 33165, 33166, 33168, + 33170, 33171, 33172, 33173, 33174, 33175, 33177, 33178, 33182, 33183, 33184, 33185, 33186, + 33188, 33189, 33191, 33193, 33195, 33196, 33197, 33198, 33199, 33200, 33201, 33202, 33204, + 33205, 33206, 33207, 33208, 33209, 33212, 33213, 33214, 33215, 33220, 33221, 33223, 33224, + 33225, 33227, 33229, 33230, 33231, 33232, 33233, 33234, 33235, 25721, 34321, 27169, 33180, + 30952, 25705, 39764, 25273, 26411, 33707, 22696, 40664, 27819, 28448, 23518, 38476, 35851, + 29279, 26576, 25287, 29281, 20137, 22982, 27597, 22675, 26286, 24149, 21215, 24917, 26408, + 30446, 30566, 29287, 31302, 25343, 21738, 21584, 38048, 37027, 23068, 32435, 27670, 20035, + 22902, 32784, 22856, 21335, 30007, 38590, 22218, 25376, 33041, 24700, 38393, 28118, 21602, + 39297, 20869, 23273, 33021, 22958, 38675, 20522, 27877, 23612, 25311, 20320, 21311, 33147, + 36870, 28346, 34091, 25288, 24180, 30910, 25781, 25467, 24565, 23064, 37247, 40479, 23615, + 25423, 32834, 23421, 21870, 38218, 38221, 28037, 24744, 26592, 29406, 20957, 23425, 33236, + 33237, 33238, 33239, 33240, 33241, 33242, 33243, 33244, 33245, 33246, 33247, 33248, 33249, + 33250, 33252, 33253, 33254, 33256, 33257, 33259, 33262, 33263, 33264, 33265, 33266, 33269, + 33270, 33271, 33272, 33273, 33274, 33277, 33279, 33283, 33287, 33288, 33289, 33290, 33291, + 33294, 33295, 33297, 33299, 33301, 33302, 33303, 33304, 33305, 33306, 33309, 33312, 33316, + 33317, 33318, 33319, 33321, 33326, 33330, 33338, 33340, 33341, 33343, 33344, 33345, 33346, + 33347, 33349, 33350, 33352, 33354, 33356, 33357, 33358, 33360, 33361, 33362, 33363, 33364, + 33365, 33366, 33367, 33369, 33371, 33372, 33373, 33374, 33376, 33377, 33378, 33379, 33380, + 33381, 33382, 33383, 33385, 25319, 27870, 29275, 25197, 38062, 32445, 33043, 27987, 20892, + 24324, 22900, 21162, 24594, 22899, 26262, 34384, 30111, 25386, 25062, 31983, 35834, 21734, + 27431, 40485, 27572, 34261, 21589, 20598, 27812, 21866, 36276, 29228, 24085, 24597, 29750, + 25293, 25490, 29260, 24472, 28227, 27966, 25856, 28504, 30424, 30928, 30460, 30036, 21028, + 21467, 20051, 24222, 26049, 32810, 32982, 25243, 21638, 21032, 28846, 34957, 36305, 27873, + 21624, 32986, 22521, 35060, 36180, 38506, 37197, 20329, 27803, 21943, 30406, 30768, 25256, + 28921, 28558, 24429, 34028, 26842, 30844, 31735, 33192, 26379, 40527, 25447, 30896, 22383, + 30738, 38713, 25209, 25259, 21128, 29749, 27607, 33386, 33387, 33388, 33389, 33393, 33397, + 33398, 33399, 33400, 33403, 33404, 33408, 33409, 33411, 33413, 33414, 33415, 33417, 33420, + 33424, 33427, 33428, 33429, 33430, 33434, 33435, 33438, 33440, 33442, 33443, 33447, 33458, + 33461, 33462, 33466, 33467, 33468, 33471, 33472, 33474, 33475, 33477, 33478, 33481, 33488, + 33494, 33497, 33498, 33501, 33506, 33511, 33512, 33513, 33514, 33516, 33517, 33518, 33520, + 33522, 33523, 33525, 33526, 33528, 33530, 33532, 33533, 33534, 33535, 33536, 33546, 33547, + 33549, 33552, 33554, 33555, 33558, 33560, 33561, 33565, 33566, 33567, 33568, 33569, 33570, + 33571, 33572, 33573, 33574, 33577, 33578, 33582, 33584, 33586, 33591, 33595, 33597, 21860, + 33086, 30130, 30382, 21305, 30174, 20731, 23617, 35692, 31687, 20559, 29255, 39575, 39128, + 28418, 29922, 31080, 25735, 30629, 25340, 39057, 36139, 21697, 32856, 20050, 22378, 33529, + 33805, 24179, 20973, 29942, 35780, 23631, 22369, 27900, 39047, 23110, 30772, 39748, 36843, + 31893, 21078, 25169, 38138, 20166, 33670, 33889, 33769, 33970, 22484, 26420, 22275, 26222, + 28006, 35889, 26333, 28689, 26399, 27450, 26646, 25114, 22971, 19971, 20932, 28422, 26578, + 27791, 20854, 26827, 22855, 27495, 30054, 23822, 33040, 40784, 26071, 31048, 31041, 39569, + 36215, 23682, 20062, 20225, 21551, 22865, 30732, 22120, 27668, 36804, 24323, 27773, 27875, + 35755, 25488, 33598, 33599, 33601, 33602, 33604, 33605, 33608, 33610, 33611, 33612, 33613, + 33614, 33619, 33621, 33622, 33623, 33624, 33625, 33629, 33634, 33648, 33649, 33650, 33651, + 33652, 33653, 33654, 33657, 33658, 33662, 33663, 33664, 33665, 33666, 33667, 33668, 33671, + 33672, 33674, 33675, 33676, 33677, 33679, 33680, 33681, 33684, 33685, 33686, 33687, 33689, + 33690, 33693, 33695, 33697, 33698, 33699, 33700, 33701, 33702, 33703, 33708, 33709, 33710, + 33711, 33717, 33723, 33726, 33727, 33730, 33731, 33732, 33734, 33736, 33737, 33739, 33741, + 33742, 33744, 33745, 33746, 33747, 33749, 33751, 33753, 33754, 33755, 33758, 33762, 33763, + 33764, 33766, 33767, 33768, 33771, 33772, 33773, 24688, 27965, 29301, 25190, 38030, 38085, + 21315, 36801, 31614, 20191, 35878, 20094, 40660, 38065, 38067, 21069, 28508, 36963, 27973, + 35892, 22545, 23884, 27424, 27465, 26538, 21595, 33108, 32652, 22681, 34103, 24378, 25250, + 27207, 38201, 25970, 24708, 26725, 30631, 20052, 20392, 24039, 38808, 25772, 32728, 23789, + 20431, 31373, 20999, 33540, 19988, 24623, 31363, 38054, 20405, 20146, 31206, 29748, 21220, + 33465, 25810, 31165, 23517, 27777, 38738, 36731, 27682, 20542, 21375, 28165, 25806, 26228, + 27696, 24773, 39031, 35831, 24198, 29756, 31351, 31179, 19992, 37041, 29699, 27714, 22234, + 37195, 27845, 36235, 21306, 34502, 26354, 36527, 23624, 39537, 28192, 33774, 33775, 33779, + 33780, 33781, 33782, 33783, 33786, 33787, 33788, 33790, 33791, 33792, 33794, 33797, 33799, + 33800, 33801, 33802, 33808, 33810, 33811, 33812, 33813, 33814, 33815, 33817, 33818, 33819, + 33822, 33823, 33824, 33825, 33826, 33827, 33833, 33834, 33835, 33836, 33837, 33838, 33839, + 33840, 33842, 33843, 33844, 33845, 33846, 33847, 33849, 33850, 33851, 33854, 33855, 33856, + 33857, 33858, 33859, 33860, 33861, 33863, 33864, 33865, 33866, 33867, 33868, 33869, 33870, + 33871, 33872, 33874, 33875, 33876, 33877, 33878, 33880, 33885, 33886, 33887, 33888, 33890, + 33892, 33893, 33894, 33895, 33896, 33898, 33902, 33903, 33904, 33906, 33908, 33911, 33913, + 33915, 33916, 21462, 23094, 40843, 36259, 21435, 22280, 39079, 26435, 37275, 27849, 20840, + 30154, 25331, 29356, 21048, 21149, 32570, 28820, 30264, 21364, 40522, 27063, 30830, 38592, + 35033, 32676, 28982, 29123, 20873, 26579, 29924, 22756, 25880, 22199, 35753, 39286, 25200, + 32469, 24825, 28909, 22764, 20161, 20154, 24525, 38887, 20219, 35748, 20995, 22922, 32427, + 25172, 20173, 26085, 25102, 33592, 33993, 33635, 34701, 29076, 28342, 23481, 32466, 20887, + 25545, 26580, 32905, 33593, 34837, 20754, 23418, 22914, 36785, 20083, 27741, 20837, 35109, + 36719, 38446, 34122, 29790, 38160, 38384, 28070, 33509, 24369, 25746, 27922, 33832, 33134, + 40131, 22622, 36187, 19977, 21441, 33917, 33918, 33919, 33920, 33921, 33923, 33924, 33925, + 33926, 33930, 33933, 33935, 33936, 33937, 33938, 33939, 33940, 33941, 33942, 33944, 33946, + 33947, 33949, 33950, 33951, 33952, 33954, 33955, 33956, 33957, 33958, 33959, 33960, 33961, + 33962, 33963, 33964, 33965, 33966, 33968, 33969, 33971, 33973, 33974, 33975, 33979, 33980, + 33982, 33984, 33986, 33987, 33989, 33990, 33991, 33992, 33995, 33996, 33998, 33999, 34002, + 34004, 34005, 34007, 34008, 34009, 34010, 34011, 34012, 34014, 34017, 34018, 34020, 34023, + 34024, 34025, 34026, 34027, 34029, 34030, 34031, 34033, 34034, 34035, 34036, 34037, 34038, + 34039, 34040, 34041, 34042, 34043, 34045, 34046, 34048, 34049, 34050, 20254, 25955, 26705, + 21971, 20007, 25620, 39578, 25195, 23234, 29791, 33394, 28073, 26862, 20711, 33678, 30722, + 26432, 21049, 27801, 32433, 20667, 21861, 29022, 31579, 26194, 29642, 33515, 26441, 23665, + 21024, 29053, 34923, 38378, 38485, 25797, 36193, 33203, 21892, 27733, 25159, 32558, 22674, + 20260, 21830, 36175, 26188, 19978, 23578, 35059, 26786, 25422, 31245, 28903, 33421, 21242, + 38902, 23569, 21736, 37045, 32461, 22882, 36170, 34503, 33292, 33293, 36198, 25668, 23556, + 24913, 28041, 31038, 35774, 30775, 30003, 21627, 20280, 36523, 28145, 23072, 32453, 31070, + 27784, 23457, 23158, 29978, 32958, 24910, 28183, 22768, 29983, 29989, 29298, 21319, 32499, + 34051, 34052, 34053, 34054, 34055, 34056, 34057, 34058, 34059, 34061, 34062, 34063, 34064, + 34066, 34068, 34069, 34070, 34072, 34073, 34075, 34076, 34077, 34078, 34080, 34082, 34083, + 34084, 34085, 34086, 34087, 34088, 34089, 34090, 34093, 34094, 34095, 34096, 34097, 34098, + 34099, 34100, 34101, 34102, 34110, 34111, 34112, 34113, 34114, 34116, 34117, 34118, 34119, + 34123, 34124, 34125, 34126, 34127, 34128, 34129, 34130, 34131, 34132, 34133, 34135, 34136, + 34138, 34139, 34140, 34141, 34143, 34144, 34145, 34146, 34147, 34149, 34150, 34151, 34153, + 34154, 34155, 34156, 34157, 34158, 34159, 34160, 34161, 34163, 34165, 34166, 34167, 34168, + 34172, 34173, 34175, 34176, 34177, 30465, 30427, 21097, 32988, 22307, 24072, 22833, 29422, + 26045, 28287, 35799, 23608, 34417, 21313, 30707, 25342, 26102, 20160, 39135, 34432, 23454, + 35782, 21490, 30690, 20351, 23630, 39542, 22987, 24335, 31034, 22763, 19990, 26623, 20107, + 25325, 35475, 36893, 21183, 26159, 21980, 22124, 36866, 20181, 20365, 37322, 39280, 27663, + 24066, 24643, 23460, 35270, 35797, 25910, 25163, 39318, 23432, 23551, 25480, 21806, 21463, + 30246, 20861, 34092, 26530, 26803, 27530, 25234, 36755, 21460, 33298, 28113, 30095, 20070, + 36174, 23408, 29087, 34223, 26257, 26329, 32626, 34560, 40653, 40736, 23646, 26415, 36848, + 26641, 26463, 25101, 31446, 22661, 24246, 25968, 28465, 34178, 34179, 34182, 34184, 34185, + 34186, 34187, 34188, 34189, 34190, 34192, 34193, 34194, 34195, 34196, 34197, 34198, 34199, + 34200, 34201, 34202, 34205, 34206, 34207, 34208, 34209, 34210, 34211, 34213, 34214, 34215, + 34217, 34219, 34220, 34221, 34225, 34226, 34227, 34228, 34229, 34230, 34232, 34234, 34235, + 34236, 34237, 34238, 34239, 34240, 34242, 34243, 34244, 34245, 34246, 34247, 34248, 34250, + 34251, 34252, 34253, 34254, 34257, 34258, 34260, 34262, 34263, 34264, 34265, 34266, 34267, + 34269, 34270, 34271, 34272, 34273, 34274, 34275, 34277, 34278, 34279, 34280, 34282, 34283, + 34284, 34285, 34286, 34287, 34288, 34289, 34290, 34291, 34292, 34293, 34294, 34295, 34296, + 24661, 21047, 32781, 25684, 34928, 29993, 24069, 26643, 25332, 38684, 21452, 29245, 35841, + 27700, 30561, 31246, 21550, 30636, 39034, 33308, 35828, 30805, 26388, 28865, 26031, 25749, + 22070, 24605, 31169, 21496, 19997, 27515, 32902, 23546, 21987, 22235, 20282, 20284, 39282, + 24051, 26494, 32824, 24578, 39042, 36865, 23435, 35772, 35829, 25628, 33368, 25822, 22013, + 33487, 37221, 20439, 32032, 36895, 31903, 20723, 22609, 28335, 23487, 35785, 32899, 37240, + 33948, 31639, 34429, 38539, 38543, 32485, 39635, 30862, 23681, 31319, 36930, 38567, 31071, + 23385, 25439, 31499, 34001, 26797, 21766, 32553, 29712, 32034, 38145, 25152, 22604, 20182, + 23427, 22905, 22612, 34297, 34298, 34300, 34301, 34302, 34304, 34305, 34306, 34307, 34308, + 34310, 34311, 34312, 34313, 34314, 34315, 34316, 34317, 34318, 34319, 34320, 34322, 34323, + 34324, 34325, 34327, 34328, 34329, 34330, 34331, 34332, 34333, 34334, 34335, 34336, 34337, + 34338, 34339, 34340, 34341, 34342, 34344, 34346, 34347, 34348, 34349, 34350, 34351, 34352, + 34353, 34354, 34355, 34356, 34357, 34358, 34359, 34361, 34362, 34363, 34365, 34366, 34367, + 34368, 34369, 34370, 34371, 34372, 34373, 34374, 34375, 34376, 34377, 34378, 34379, 34380, + 34386, 34387, 34389, 34390, 34391, 34392, 34393, 34395, 34396, 34397, 34399, 34400, 34401, + 34403, 34404, 34405, 34406, 34407, 34408, 34409, 34410, 29549, 25374, 36427, 36367, 32974, + 33492, 25260, 21488, 27888, 37214, 22826, 24577, 27760, 22349, 25674, 36138, 30251, 28393, + 22363, 27264, 30192, 28525, 35885, 35848, 22374, 27631, 34962, 30899, 25506, 21497, 28845, + 27748, 22616, 25642, 22530, 26848, 33179, 21776, 31958, 20504, 36538, 28108, 36255, 28907, + 25487, 28059, 28372, 32486, 33796, 26691, 36867, 28120, 38518, 35752, 22871, 29305, 34276, + 33150, 30140, 35466, 26799, 21076, 36386, 38161, 25552, 39064, 36420, 21884, 20307, 26367, + 22159, 24789, 28053, 21059, 23625, 22825, 28155, 22635, 30000, 29980, 24684, 33300, 33094, + 25361, 26465, 36834, 30522, 36339, 36148, 38081, 24086, 21381, 21548, 28867, 34413, 34415, + 34416, 34418, 34419, 34420, 34421, 34422, 34423, 34424, 34435, 34436, 34437, 34438, 34439, + 34440, 34441, 34446, 34447, 34448, 34449, 34450, 34452, 34454, 34455, 34456, 34457, 34458, + 34459, 34462, 34463, 34464, 34465, 34466, 34469, 34470, 34475, 34477, 34478, 34482, 34483, + 34487, 34488, 34489, 34491, 34492, 34493, 34494, 34495, 34497, 34498, 34499, 34501, 34504, + 34508, 34509, 34514, 34515, 34517, 34518, 34519, 34522, 34524, 34525, 34528, 34529, 34530, + 34531, 34533, 34534, 34535, 34536, 34538, 34539, 34540, 34543, 34549, 34550, 34551, 34554, + 34555, 34556, 34557, 34559, 34561, 34564, 34565, 34566, 34571, 34572, 34574, 34575, 34576, + 34577, 34580, 34582, 27712, 24311, 20572, 20141, 24237, 25402, 33351, 36890, 26704, 37230, + 30643, 21516, 38108, 24420, 31461, 26742, 25413, 31570, 32479, 30171, 20599, 25237, 22836, + 36879, 20984, 31171, 31361, 22270, 24466, 36884, 28034, 23648, 22303, 21520, 20820, 28237, + 22242, 25512, 39059, 33151, 34581, 35114, 36864, 21534, 23663, 33216, 25302, 25176, 33073, + 40501, 38464, 39534, 39548, 26925, 22949, 25299, 21822, 25366, 21703, 34521, 27964, 23043, + 29926, 34972, 27498, 22806, 35916, 24367, 28286, 29609, 39037, 20024, 28919, 23436, 30871, + 25405, 26202, 30358, 24779, 23451, 23113, 19975, 33109, 27754, 29579, 20129, 26505, 32593, + 24448, 26106, 26395, 24536, 22916, 23041, 34585, 34587, 34589, 34591, 34592, 34596, 34598, + 34599, 34600, 34602, 34603, 34604, 34605, 34607, 34608, 34610, 34611, 34613, 34614, 34616, + 34617, 34618, 34620, 34621, 34624, 34625, 34626, 34627, 34628, 34629, 34630, 34634, 34635, + 34637, 34639, 34640, 34641, 34642, 34644, 34645, 34646, 34648, 34650, 34651, 34652, 34653, + 34654, 34655, 34657, 34658, 34662, 34663, 34664, 34665, 34666, 34667, 34668, 34669, 34671, + 34673, 34674, 34675, 34677, 34679, 34680, 34681, 34682, 34687, 34688, 34689, 34692, 34694, + 34695, 34697, 34698, 34700, 34702, 34703, 34704, 34705, 34706, 34708, 34709, 34710, 34712, + 34713, 34714, 34715, 34716, 34717, 34718, 34720, 34721, 34722, 34723, 34724, 24013, 24494, + 21361, 38886, 36829, 26693, 22260, 21807, 24799, 20026, 28493, 32500, 33479, 33806, 22996, + 20255, 20266, 23614, 32428, 26410, 34074, 21619, 30031, 32963, 21890, 39759, 20301, 28205, + 35859, 23561, 24944, 21355, 30239, 28201, 34442, 25991, 38395, 32441, 21563, 31283, 32010, + 38382, 21985, 32705, 29934, 25373, 34583, 28065, 31389, 25105, 26017, 21351, 25569, 27779, + 24043, 21596, 38056, 20044, 27745, 35820, 23627, 26080, 33436, 26791, 21566, 21556, 27595, + 27494, 20116, 25410, 21320, 33310, 20237, 20398, 22366, 25098, 38654, 26212, 29289, 21247, + 21153, 24735, 35823, 26132, 29081, 26512, 35199, 30802, 30717, 26224, 22075, 21560, 38177, + 29306, 34725, 34726, 34727, 34729, 34730, 34734, 34736, 34737, 34738, 34740, 34742, 34743, + 34744, 34745, 34747, 34748, 34750, 34751, 34753, 34754, 34755, 34756, 34757, 34759, 34760, + 34761, 34764, 34765, 34766, 34767, 34768, 34772, 34773, 34774, 34775, 34776, 34777, 34778, + 34780, 34781, 34782, 34783, 34785, 34786, 34787, 34788, 34790, 34791, 34792, 34793, 34795, + 34796, 34797, 34799, 34800, 34801, 34802, 34803, 34804, 34805, 34806, 34807, 34808, 34810, + 34811, 34812, 34813, 34815, 34816, 34817, 34818, 34820, 34821, 34822, 34823, 34824, 34825, + 34827, 34828, 34829, 34830, 34831, 34832, 34833, 34834, 34836, 34839, 34840, 34841, 34842, + 34844, 34845, 34846, 34847, 34848, 34851, 31232, 24687, 24076, 24713, 33181, 22805, 24796, + 29060, 28911, 28330, 27728, 29312, 27268, 34989, 24109, 20064, 23219, 21916, 38115, 27927, + 31995, 38553, 25103, 32454, 30606, 34430, 21283, 38686, 36758, 26247, 23777, 20384, 29421, + 19979, 21414, 22799, 21523, 25472, 38184, 20808, 20185, 40092, 32420, 21688, 36132, 34900, + 33335, 38386, 28046, 24358, 23244, 26174, 38505, 29616, 29486, 21439, 33146, 39301, 32673, + 23466, 38519, 38480, 32447, 30456, 21410, 38262, 39321, 31665, 35140, 28248, 20065, 32724, + 31077, 35814, 24819, 21709, 20139, 39033, 24055, 27233, 20687, 21521, 35937, 33831, 30813, + 38660, 21066, 21742, 22179, 38144, 28040, 23477, 28102, 26195, 34852, 34853, 34854, 34855, + 34856, 34857, 34858, 34859, 34860, 34861, 34862, 34863, 34864, 34865, 34867, 34868, 34869, + 34870, 34871, 34872, 34874, 34875, 34877, 34878, 34879, 34881, 34882, 34883, 34886, 34887, + 34888, 34889, 34890, 34891, 34894, 34895, 34896, 34897, 34898, 34899, 34901, 34902, 34904, + 34906, 34907, 34908, 34909, 34910, 34911, 34912, 34918, 34919, 34922, 34925, 34927, 34929, + 34931, 34932, 34933, 34934, 34936, 34937, 34938, 34939, 34940, 34944, 34947, 34950, 34951, + 34953, 34954, 34956, 34958, 34959, 34960, 34961, 34963, 34964, 34965, 34967, 34968, 34969, + 34970, 34971, 34973, 34974, 34975, 34976, 34977, 34979, 34981, 34982, 34983, 34984, 34985, + 34986, 23567, 23389, 26657, 32918, 21880, 31505, 25928, 26964, 20123, 27463, 34638, 38795, + 21327, 25375, 25658, 37034, 26012, 32961, 35856, 20889, 26800, 21368, 34809, 25032, 27844, + 27899, 35874, 23633, 34218, 33455, 38156, 27427, 36763, 26032, 24571, 24515, 20449, 34885, + 26143, 33125, 29481, 24826, 20852, 21009, 22411, 24418, 37026, 34892, 37266, 24184, 26447, + 24615, 22995, 20804, 20982, 33016, 21256, 27769, 38596, 29066, 20241, 20462, 32670, 26429, + 21957, 38152, 31168, 34966, 32483, 22687, 25100, 38656, 34394, 22040, 39035, 24464, 35768, + 33988, 37207, 21465, 26093, 24207, 30044, 24676, 32110, 23167, 32490, 32493, 36713, 21927, + 23459, 24748, 26059, 29572, 34988, 34990, 34991, 34992, 34994, 34995, 34996, 34997, 34998, + 35000, 35001, 35002, 35003, 35005, 35006, 35007, 35008, 35011, 35012, 35015, 35016, 35018, + 35019, 35020, 35021, 35023, 35024, 35025, 35027, 35030, 35031, 35034, 35035, 35036, 35037, + 35038, 35040, 35041, 35046, 35047, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35058, + 35061, 35062, 35063, 35066, 35067, 35069, 35071, 35072, 35073, 35075, 35076, 35077, 35078, + 35079, 35080, 35081, 35083, 35084, 35085, 35086, 35087, 35089, 35092, 35093, 35094, 35095, + 35096, 35100, 35101, 35102, 35103, 35104, 35106, 35107, 35108, 35110, 35111, 35112, 35113, + 35116, 35117, 35118, 35119, 35121, 35122, 35123, 35125, 35127, 36873, 30307, 30505, 32474, + 38772, 34203, 23398, 31348, 38634, 34880, 21195, 29071, 24490, 26092, 35810, 23547, 39535, + 24033, 27529, 27739, 35757, 35759, 36874, 36805, 21387, 25276, 40486, 40493, 21568, 20011, + 33469, 29273, 34460, 23830, 34905, 28079, 38597, 21713, 20122, 35766, 28937, 21693, 38409, + 28895, 28153, 30416, 20005, 30740, 34578, 23721, 24310, 35328, 39068, 38414, 28814, 27839, + 22852, 25513, 30524, 34893, 28436, 33395, 22576, 29141, 21388, 30746, 38593, 21761, 24422, + 28976, 23476, 35866, 39564, 27523, 22830, 40495, 31207, 26472, 25196, 20335, 30113, 32650, + 27915, 38451, 27687, 20208, 30162, 20859, 26679, 28478, 36992, 33136, 22934, 29814, 35128, + 35129, 35130, 35131, 35132, 35133, 35134, 35135, 35136, 35138, 35139, 35141, 35142, 35143, + 35144, 35145, 35146, 35147, 35148, 35149, 35150, 35151, 35152, 35153, 35154, 35155, 35156, + 35157, 35158, 35159, 35160, 35161, 35162, 35163, 35164, 35165, 35168, 35169, 35170, 35171, + 35172, 35173, 35175, 35176, 35177, 35178, 35179, 35180, 35181, 35182, 35183, 35184, 35185, + 35186, 35187, 35188, 35189, 35190, 35191, 35192, 35193, 35194, 35196, 35197, 35198, 35200, + 35202, 35204, 35205, 35207, 35208, 35209, 35210, 35211, 35212, 35213, 35214, 35215, 35216, + 35217, 35218, 35219, 35220, 35221, 35222, 35223, 35224, 35225, 35226, 35227, 35228, 35229, + 35230, 35231, 35232, 35233, 25671, 23591, 36965, 31377, 35875, 23002, 21676, 33280, 33647, + 35201, 32768, 26928, 22094, 32822, 29239, 37326, 20918, 20063, 39029, 25494, 19994, 21494, + 26355, 33099, 22812, 28082, 19968, 22777, 21307, 25558, 38129, 20381, 20234, 34915, 39056, + 22839, 36951, 31227, 20202, 33008, 30097, 27778, 23452, 23016, 24413, 26885, 34433, 20506, + 24050, 20057, 30691, 20197, 33402, 25233, 26131, 37009, 23673, 20159, 24441, 33222, 36920, + 32900, 30123, 20134, 35028, 24847, 27589, 24518, 20041, 30410, 28322, 35811, 35758, 35850, + 35793, 24322, 32764, 32716, 32462, 33589, 33643, 22240, 27575, 38899, 38452, 23035, 21535, + 38134, 28139, 23493, 39278, 23609, 24341, 38544, 35234, 35235, 35236, 35237, 35238, 35239, + 35240, 35241, 35242, 35243, 35244, 35245, 35246, 35247, 35248, 35249, 35250, 35251, 35252, + 35253, 35254, 35255, 35256, 35257, 35258, 35259, 35260, 35261, 35262, 35263, 35264, 35267, + 35277, 35283, 35284, 35285, 35287, 35288, 35289, 35291, 35293, 35295, 35296, 35297, 35298, + 35300, 35303, 35304, 35305, 35306, 35308, 35309, 35310, 35312, 35313, 35314, 35316, 35317, + 35318, 35319, 35320, 35321, 35322, 35323, 35324, 35325, 35326, 35327, 35329, 35330, 35331, + 35332, 35333, 35334, 35336, 35337, 35338, 35339, 35340, 35341, 35342, 35343, 35344, 35345, + 35346, 35347, 35348, 35349, 35350, 35351, 35352, 35353, 35354, 35355, 35356, 35357, 21360, + 33521, 27185, 23156, 40560, 24212, 32552, 33721, 33828, 33829, 33639, 34631, 36814, 36194, + 30408, 24433, 39062, 30828, 26144, 21727, 25317, 20323, 33219, 30152, 24248, 38605, 36362, + 34553, 21647, 27891, 28044, 27704, 24703, 21191, 29992, 24189, 20248, 24736, 24551, 23588, + 30001, 37038, 38080, 29369, 27833, 28216, 37193, 26377, 21451, 21491, 20305, 37321, 35825, + 21448, 24188, 36802, 28132, 20110, 30402, 27014, 34398, 24858, 33286, 20313, 20446, 36926, + 40060, 24841, 28189, 28180, 38533, 20104, 23089, 38632, 19982, 23679, 31161, 23431, 35821, + 32701, 29577, 22495, 33419, 37057, 21505, 36935, 21947, 23786, 24481, 24840, 27442, 29425, + 32946, 35465, 35358, 35359, 35360, 35361, 35362, 35363, 35364, 35365, 35366, 35367, 35368, + 35369, 35370, 35371, 35372, 35373, 35374, 35375, 35376, 35377, 35378, 35379, 35380, 35381, + 35382, 35383, 35384, 35385, 35386, 35387, 35388, 35389, 35391, 35392, 35393, 35394, 35395, + 35396, 35397, 35398, 35399, 35401, 35402, 35403, 35404, 35405, 35406, 35407, 35408, 35409, + 35410, 35411, 35412, 35413, 35414, 35415, 35416, 35417, 35418, 35419, 35420, 35421, 35422, + 35423, 35424, 35425, 35426, 35427, 35428, 35429, 35430, 35431, 35432, 35433, 35434, 35435, + 35436, 35437, 35438, 35439, 35440, 35441, 35442, 35443, 35444, 35445, 35446, 35447, 35448, + 35450, 35451, 35452, 35453, 35454, 35455, 35456, 28020, 23507, 35029, 39044, 35947, 39533, + 40499, 28170, 20900, 20803, 22435, 34945, 21407, 25588, 36757, 22253, 21592, 22278, 29503, + 28304, 32536, 36828, 33489, 24895, 24616, 38498, 26352, 32422, 36234, 36291, 38053, 23731, + 31908, 26376, 24742, 38405, 32792, 20113, 37095, 21248, 38504, 20801, 36816, 34164, 37213, + 26197, 38901, 23381, 21277, 30776, 26434, 26685, 21705, 28798, 23472, 36733, 20877, 22312, + 21681, 25874, 26242, 36190, 36163, 33039, 33900, 36973, 31967, 20991, 34299, 26531, 26089, + 28577, 34468, 36481, 22122, 36896, 30338, 28790, 29157, 36131, 25321, 21017, 27901, 36156, + 24590, 22686, 24974, 26366, 36192, 25166, 21939, 28195, 26413, 36711, 35457, 35458, 35459, + 35460, 35461, 35462, 35463, 35464, 35467, 35468, 35469, 35470, 35471, 35472, 35473, 35474, + 35476, 35477, 35478, 35479, 35480, 35481, 35482, 35483, 35484, 35485, 35486, 35487, 35488, + 35489, 35490, 35491, 35492, 35493, 35494, 35495, 35496, 35497, 35498, 35499, 35500, 35501, + 35502, 35503, 35504, 35505, 35506, 35507, 35508, 35509, 35510, 35511, 35512, 35513, 35514, + 35515, 35516, 35517, 35518, 35519, 35520, 35521, 35522, 35523, 35524, 35525, 35526, 35527, + 35528, 35529, 35530, 35531, 35532, 35533, 35534, 35535, 35536, 35537, 35538, 35539, 35540, + 35541, 35542, 35543, 35544, 35545, 35546, 35547, 35548, 35549, 35550, 35551, 35552, 35553, + 35554, 35555, 38113, 38392, 30504, 26629, 27048, 21643, 20045, 28856, 35784, 25688, 25995, + 23429, 31364, 20538, 23528, 30651, 27617, 35449, 31896, 27838, 30415, 26025, 36759, 23853, + 23637, 34360, 26632, 21344, 25112, 31449, 28251, 32509, 27167, 31456, 24432, 28467, 24352, + 25484, 28072, 26454, 19976, 24080, 36134, 20183, 32960, 30260, 38556, 25307, 26157, 25214, + 27836, 36213, 29031, 32617, 20806, 32903, 21484, 36974, 25240, 21746, 34544, 36761, 32773, + 38167, 34071, 36825, 27993, 29645, 26015, 30495, 29956, 30759, 33275, 36126, 38024, 20390, + 26517, 30137, 35786, 38663, 25391, 38215, 38453, 33976, 25379, 30529, 24449, 29424, 20105, + 24596, 25972, 25327, 27491, 25919, 35556, 35557, 35558, 35559, 35560, 35561, 35562, 35563, + 35564, 35565, 35566, 35567, 35568, 35569, 35570, 35571, 35572, 35573, 35574, 35575, 35576, + 35577, 35578, 35579, 35580, 35581, 35582, 35583, 35584, 35585, 35586, 35587, 35588, 35589, + 35590, 35592, 35593, 35594, 35595, 35596, 35597, 35598, 35599, 35600, 35601, 35602, 35603, + 35604, 35605, 35606, 35607, 35608, 35609, 35610, 35611, 35612, 35613, 35614, 35615, 35616, + 35617, 35618, 35619, 35620, 35621, 35623, 35624, 35625, 35626, 35627, 35628, 35629, 35630, + 35631, 35632, 35633, 35634, 35635, 35636, 35637, 35638, 35639, 35640, 35641, 35642, 35643, + 35644, 35645, 35646, 35647, 35648, 35649, 35650, 35651, 35652, 35653, 24103, 30151, 37073, + 35777, 33437, 26525, 25903, 21553, 34584, 30693, 32930, 33026, 27713, 20043, 32455, 32844, + 30452, 26893, 27542, 25191, 20540, 20356, 22336, 25351, 27490, 36286, 21482, 26088, 32440, + 24535, 25370, 25527, 33267, 33268, 32622, 24092, 23769, 21046, 26234, 31209, 31258, 36136, + 28825, 30164, 28382, 27835, 31378, 20013, 30405, 24544, 38047, 34935, 32456, 31181, 32959, + 37325, 20210, 20247, 33311, 21608, 24030, 27954, 35788, 31909, 36724, 32920, 24090, 21650, + 30385, 23449, 26172, 39588, 29664, 26666, 34523, 26417, 29482, 35832, 35803, 36880, 31481, + 28891, 29038, 25284, 30633, 22065, 20027, 33879, 26609, 21161, 34496, 36142, 38136, 31569, + 35654, 35655, 35656, 35657, 35658, 35659, 35660, 35661, 35662, 35663, 35664, 35665, 35666, + 35667, 35668, 35669, 35670, 35671, 35672, 35673, 35674, 35675, 35676, 35677, 35678, 35679, + 35680, 35681, 35682, 35683, 35684, 35685, 35687, 35688, 35689, 35690, 35691, 35693, 35694, + 35695, 35696, 35697, 35698, 35699, 35700, 35701, 35702, 35703, 35704, 35705, 35706, 35707, + 35708, 35709, 35710, 35711, 35712, 35713, 35714, 35715, 35716, 35717, 35718, 35719, 35720, + 35721, 35722, 35723, 35724, 35725, 35726, 35727, 35728, 35729, 35730, 35731, 35732, 35733, + 35734, 35735, 35736, 35737, 35738, 35739, 35740, 35741, 35742, 35743, 35756, 35761, 35771, + 35783, 35792, 35818, 35849, 35870, 20303, 27880, 31069, 39547, 25235, 29226, 25341, 19987, + 30742, 36716, 25776, 36186, 31686, 26729, 24196, 35013, 22918, 25758, 22766, 29366, 26894, + 38181, 36861, 36184, 22368, 32512, 35846, 20934, 25417, 25305, 21331, 26700, 29730, 33537, + 37196, 21828, 30528, 28796, 27978, 20857, 21672, 36164, 23039, 28363, 28100, 23388, 32043, + 20180, 31869, 28371, 23376, 33258, 28173, 23383, 39683, 26837, 36394, 23447, 32508, 24635, + 32437, 37049, 36208, 22863, 25549, 31199, 36275, 21330, 26063, 31062, 35781, 38459, 32452, + 38075, 32386, 22068, 37257, 26368, 32618, 23562, 36981, 26152, 24038, 20304, 26590, 20570, + 20316, 22352, 24231, 59408, 59409, 59410, 59411, 59412, 35896, 35897, 35898, 35899, 35900, + 35901, 35902, 35903, 35904, 35906, 35907, 35908, 35909, 35912, 35914, 35915, 35917, 35918, + 35919, 35920, 35921, 35922, 35923, 35924, 35926, 35927, 35928, 35929, 35931, 35932, 35933, + 35934, 35935, 35936, 35939, 35940, 35941, 35942, 35943, 35944, 35945, 35948, 35949, 35950, + 35951, 35952, 35953, 35954, 35956, 35957, 35958, 35959, 35963, 35964, 35965, 35966, 35967, + 35968, 35969, 35971, 35972, 35974, 35975, 35976, 35979, 35981, 35982, 35983, 35984, 35985, + 35986, 35987, 35989, 35990, 35991, 35993, 35994, 35995, 35996, 35997, 35998, 35999, 36000, + 36001, 36002, 36003, 36004, 36005, 36006, 36007, 36008, 36009, 36010, 36011, 36012, 36013, + 20109, 19980, 20800, 19984, 24319, 21317, 19989, 20120, 19998, 39730, 23404, 22121, 20008, + 31162, 20031, 21269, 20039, 22829, 29243, 21358, 27664, 22239, 32996, 39319, 27603, 30590, + 40727, 20022, 20127, 40720, 20060, 20073, 20115, 33416, 23387, 21868, 22031, 20164, 21389, + 21405, 21411, 21413, 21422, 38757, 36189, 21274, 21493, 21286, 21294, 21310, 36188, 21350, + 21347, 20994, 21000, 21006, 21037, 21043, 21055, 21056, 21068, 21086, 21089, 21084, 33967, + 21117, 21122, 21121, 21136, 21139, 20866, 32596, 20155, 20163, 20169, 20162, 20200, 20193, + 20203, 20190, 20251, 20211, 20258, 20324, 20213, 20261, 20263, 20233, 20267, 20318, 20327, + 25912, 20314, 20317, 36014, 36015, 36016, 36017, 36018, 36019, 36020, 36021, 36022, 36023, + 36024, 36025, 36026, 36027, 36028, 36029, 36030, 36031, 36032, 36033, 36034, 36035, 36036, + 36037, 36038, 36039, 36040, 36041, 36042, 36043, 36044, 36045, 36046, 36047, 36048, 36049, + 36050, 36051, 36052, 36053, 36054, 36055, 36056, 36057, 36058, 36059, 36060, 36061, 36062, + 36063, 36064, 36065, 36066, 36067, 36068, 36069, 36070, 36071, 36072, 36073, 36074, 36075, + 36076, 36077, 36078, 36079, 36080, 36081, 36082, 36083, 36084, 36085, 36086, 36087, 36088, + 36089, 36090, 36091, 36092, 36093, 36094, 36095, 36096, 36097, 36098, 36099, 36100, 36101, + 36102, 36103, 36104, 36105, 36106, 36107, 36108, 36109, 20319, 20311, 20274, 20285, 20342, + 20340, 20369, 20361, 20355, 20367, 20350, 20347, 20394, 20348, 20396, 20372, 20454, 20456, + 20458, 20421, 20442, 20451, 20444, 20433, 20447, 20472, 20521, 20556, 20467, 20524, 20495, + 20526, 20525, 20478, 20508, 20492, 20517, 20520, 20606, 20547, 20565, 20552, 20558, 20588, + 20603, 20645, 20647, 20649, 20666, 20694, 20742, 20717, 20716, 20710, 20718, 20743, 20747, + 20189, 27709, 20312, 20325, 20430, 40864, 27718, 31860, 20846, 24061, 40649, 39320, 20865, + 22804, 21241, 21261, 35335, 21264, 20971, 22809, 20821, 20128, 20822, 20147, 34926, 34980, + 20149, 33044, 35026, 31104, 23348, 34819, 32696, 20907, 20913, 20925, 20924, 36110, 36111, + 36112, 36113, 36114, 36115, 36116, 36117, 36118, 36119, 36120, 36121, 36122, 36123, 36124, + 36128, 36177, 36178, 36183, 36191, 36197, 36200, 36201, 36202, 36204, 36206, 36207, 36209, + 36210, 36216, 36217, 36218, 36219, 36220, 36221, 36222, 36223, 36224, 36226, 36227, 36230, + 36231, 36232, 36233, 36236, 36237, 36238, 36239, 36240, 36242, 36243, 36245, 36246, 36247, + 36248, 36249, 36250, 36251, 36252, 36253, 36254, 36256, 36257, 36258, 36260, 36261, 36262, + 36263, 36264, 36265, 36266, 36267, 36268, 36269, 36270, 36271, 36272, 36274, 36278, 36279, + 36281, 36283, 36285, 36288, 36289, 36290, 36293, 36295, 36296, 36297, 36298, 36301, 36304, + 36306, 36307, 36308, 20935, 20886, 20898, 20901, 35744, 35750, 35751, 35754, 35764, 35765, + 35767, 35778, 35779, 35787, 35791, 35790, 35794, 35795, 35796, 35798, 35800, 35801, 35804, + 35807, 35808, 35812, 35816, 35817, 35822, 35824, 35827, 35830, 35833, 35836, 35839, 35840, + 35842, 35844, 35847, 35852, 35855, 35857, 35858, 35860, 35861, 35862, 35865, 35867, 35864, + 35869, 35871, 35872, 35873, 35877, 35879, 35882, 35883, 35886, 35887, 35890, 35891, 35893, + 35894, 21353, 21370, 38429, 38434, 38433, 38449, 38442, 38461, 38460, 38466, 38473, 38484, + 38495, 38503, 38508, 38514, 38516, 38536, 38541, 38551, 38576, 37015, 37019, 37021, 37017, + 37036, 37025, 37044, 37043, 37046, 37050, 36309, 36312, 36313, 36316, 36320, 36321, 36322, + 36325, 36326, 36327, 36329, 36333, 36334, 36336, 36337, 36338, 36340, 36342, 36348, 36350, + 36351, 36352, 36353, 36354, 36355, 36356, 36358, 36359, 36360, 36363, 36365, 36366, 36368, + 36369, 36370, 36371, 36373, 36374, 36375, 36376, 36377, 36378, 36379, 36380, 36384, 36385, + 36388, 36389, 36390, 36391, 36392, 36395, 36397, 36400, 36402, 36403, 36404, 36406, 36407, + 36408, 36411, 36412, 36414, 36415, 36419, 36421, 36422, 36428, 36429, 36430, 36431, 36432, + 36435, 36436, 36437, 36438, 36439, 36440, 36442, 36443, 36444, 36445, 36446, 36447, 36448, + 36449, 36450, 36451, 36452, 36453, 36455, 36456, 36458, 36459, 36462, 36465, 37048, 37040, + 37071, 37061, 37054, 37072, 37060, 37063, 37075, 37094, 37090, 37084, 37079, 37083, 37099, + 37103, 37118, 37124, 37154, 37150, 37155, 37169, 37167, 37177, 37187, 37190, 21005, 22850, + 21154, 21164, 21165, 21182, 21759, 21200, 21206, 21232, 21471, 29166, 30669, 24308, 20981, + 20988, 39727, 21430, 24321, 30042, 24047, 22348, 22441, 22433, 22654, 22716, 22725, 22737, + 22313, 22316, 22314, 22323, 22329, 22318, 22319, 22364, 22331, 22338, 22377, 22405, 22379, + 22406, 22396, 22395, 22376, 22381, 22390, 22387, 22445, 22436, 22412, 22450, 22479, 22439, + 22452, 22419, 22432, 22485, 22488, 22490, 22489, 22482, 22456, 22516, 22511, 22520, 22500, + 22493, 36467, 36469, 36471, 36472, 36473, 36474, 36475, 36477, 36478, 36480, 36482, 36483, + 36484, 36486, 36488, 36489, 36490, 36491, 36492, 36493, 36494, 36497, 36498, 36499, 36501, + 36502, 36503, 36504, 36505, 36506, 36507, 36509, 36511, 36512, 36513, 36514, 36515, 36516, + 36517, 36518, 36519, 36520, 36521, 36522, 36525, 36526, 36528, 36529, 36531, 36532, 36533, + 36534, 36535, 36536, 36537, 36539, 36540, 36541, 36542, 36543, 36544, 36545, 36546, 36547, + 36548, 36549, 36550, 36551, 36552, 36553, 36554, 36555, 36556, 36557, 36559, 36560, 36561, + 36562, 36563, 36564, 36565, 36566, 36567, 36568, 36569, 36570, 36571, 36572, 36573, 36574, + 36575, 36576, 36577, 36578, 36579, 36580, 22539, 22541, 22525, 22509, 22528, 22558, 22553, + 22596, 22560, 22629, 22636, 22657, 22665, 22682, 22656, 39336, 40729, 25087, 33401, 33405, + 33407, 33423, 33418, 33448, 33412, 33422, 33425, 33431, 33433, 33451, 33464, 33470, 33456, + 33480, 33482, 33507, 33432, 33463, 33454, 33483, 33484, 33473, 33449, 33460, 33441, 33450, + 33439, 33476, 33486, 33444, 33505, 33545, 33527, 33508, 33551, 33543, 33500, 33524, 33490, + 33496, 33548, 33531, 33491, 33553, 33562, 33542, 33556, 33557, 33504, 33493, 33564, 33617, + 33627, 33628, 33544, 33682, 33596, 33588, 33585, 33691, 33630, 33583, 33615, 33607, 33603, + 33631, 33600, 33559, 33632, 33581, 33594, 33587, 33638, 33637, 36581, 36582, 36583, 36584, + 36585, 36586, 36587, 36588, 36589, 36590, 36591, 36592, 36593, 36594, 36595, 36596, 36597, + 36598, 36599, 36600, 36601, 36602, 36603, 36604, 36605, 36606, 36607, 36608, 36609, 36610, + 36611, 36612, 36613, 36614, 36615, 36616, 36617, 36618, 36619, 36620, 36621, 36622, 36623, + 36624, 36625, 36626, 36627, 36628, 36629, 36630, 36631, 36632, 36633, 36634, 36635, 36636, + 36637, 36638, 36639, 36640, 36641, 36642, 36643, 36644, 36645, 36646, 36647, 36648, 36649, + 36650, 36651, 36652, 36653, 36654, 36655, 36656, 36657, 36658, 36659, 36660, 36661, 36662, + 36663, 36664, 36665, 36666, 36667, 36668, 36669, 36670, 36671, 36672, 36673, 36674, 36675, + 36676, 33640, 33563, 33641, 33644, 33642, 33645, 33646, 33712, 33656, 33715, 33716, 33696, + 33706, 33683, 33692, 33669, 33660, 33718, 33705, 33661, 33720, 33659, 33688, 33694, 33704, + 33722, 33724, 33729, 33793, 33765, 33752, 22535, 33816, 33803, 33757, 33789, 33750, 33820, + 33848, 33809, 33798, 33748, 33759, 33807, 33795, 33784, 33785, 33770, 33733, 33728, 33830, + 33776, 33761, 33884, 33873, 33882, 33881, 33907, 33927, 33928, 33914, 33929, 33912, 33852, + 33862, 33897, 33910, 33932, 33934, 33841, 33901, 33985, 33997, 34000, 34022, 33981, 34003, + 33994, 33983, 33978, 34016, 33953, 33977, 33972, 33943, 34021, 34019, 34060, 29965, 34104, + 34032, 34105, 34079, 34106, 36677, 36678, 36679, 36680, 36681, 36682, 36683, 36684, 36685, + 36686, 36687, 36688, 36689, 36690, 36691, 36692, 36693, 36694, 36695, 36696, 36697, 36698, + 36699, 36700, 36701, 36702, 36703, 36704, 36705, 36706, 36707, 36708, 36709, 36714, 36736, + 36748, 36754, 36765, 36768, 36769, 36770, 36772, 36773, 36774, 36775, 36778, 36780, 36781, + 36782, 36783, 36786, 36787, 36788, 36789, 36791, 36792, 36794, 36795, 36796, 36799, 36800, + 36803, 36806, 36809, 36810, 36811, 36812, 36813, 36815, 36818, 36822, 36823, 36826, 36832, + 36833, 36835, 36839, 36844, 36847, 36849, 36850, 36852, 36853, 36854, 36858, 36859, 36860, + 36862, 36863, 36871, 36872, 36876, 36878, 36883, 36885, 36888, 34134, 34107, 34047, 34044, + 34137, 34120, 34152, 34148, 34142, 34170, 30626, 34115, 34162, 34171, 34212, 34216, 34183, + 34191, 34169, 34222, 34204, 34181, 34233, 34231, 34224, 34259, 34241, 34268, 34303, 34343, + 34309, 34345, 34326, 34364, 24318, 24328, 22844, 22849, 32823, 22869, 22874, 22872, 21263, + 23586, 23589, 23596, 23604, 25164, 25194, 25247, 25275, 25290, 25306, 25303, 25326, 25378, + 25334, 25401, 25419, 25411, 25517, 25590, 25457, 25466, 25486, 25524, 25453, 25516, 25482, + 25449, 25518, 25532, 25586, 25592, 25568, 25599, 25540, 25566, 25550, 25682, 25542, 25534, + 25669, 25665, 25611, 25627, 25632, 25612, 25638, 25633, 25694, 25732, 25709, 25750, 36889, + 36892, 36899, 36900, 36901, 36903, 36904, 36905, 36906, 36907, 36908, 36912, 36913, 36914, + 36915, 36916, 36919, 36921, 36922, 36925, 36927, 36928, 36931, 36933, 36934, 36936, 36937, + 36938, 36939, 36940, 36942, 36948, 36949, 36950, 36953, 36954, 36956, 36957, 36958, 36959, + 36960, 36961, 36964, 36966, 36967, 36969, 36970, 36971, 36972, 36975, 36976, 36977, 36978, + 36979, 36982, 36983, 36984, 36985, 36986, 36987, 36988, 36990, 36993, 36996, 36997, 36998, + 36999, 37001, 37002, 37004, 37005, 37006, 37007, 37008, 37010, 37012, 37014, 37016, 37018, + 37020, 37022, 37023, 37024, 37028, 37029, 37031, 37032, 37033, 37035, 37037, 37042, 37047, + 37052, 37053, 37055, 37056, 25722, 25783, 25784, 25753, 25786, 25792, 25808, 25815, 25828, + 25826, 25865, 25893, 25902, 24331, 24530, 29977, 24337, 21343, 21489, 21501, 21481, 21480, + 21499, 21522, 21526, 21510, 21579, 21586, 21587, 21588, 21590, 21571, 21537, 21591, 21593, + 21539, 21554, 21634, 21652, 21623, 21617, 21604, 21658, 21659, 21636, 21622, 21606, 21661, + 21712, 21677, 21698, 21684, 21714, 21671, 21670, 21715, 21716, 21618, 21667, 21717, 21691, + 21695, 21708, 21721, 21722, 21724, 21673, 21674, 21668, 21725, 21711, 21726, 21787, 21735, + 21792, 21757, 21780, 21747, 21794, 21795, 21775, 21777, 21799, 21802, 21863, 21903, 21941, + 21833, 21869, 21825, 21845, 21823, 21840, 21820, 37058, 37059, 37062, 37064, 37065, 37067, + 37068, 37069, 37074, 37076, 37077, 37078, 37080, 37081, 37082, 37086, 37087, 37088, 37091, + 37092, 37093, 37097, 37098, 37100, 37102, 37104, 37105, 37106, 37107, 37109, 37110, 37111, + 37113, 37114, 37115, 37116, 37119, 37120, 37121, 37123, 37125, 37126, 37127, 37128, 37129, + 37130, 37131, 37132, 37133, 37134, 37135, 37136, 37137, 37138, 37139, 37140, 37141, 37142, + 37143, 37144, 37146, 37147, 37148, 37149, 37151, 37152, 37153, 37156, 37157, 37158, 37159, + 37160, 37161, 37162, 37163, 37164, 37165, 37166, 37168, 37170, 37171, 37172, 37173, 37174, + 37175, 37176, 37178, 37179, 37180, 37181, 37182, 37183, 37184, 37185, 37186, 37188, 21815, + 21846, 21877, 21878, 21879, 21811, 21808, 21852, 21899, 21970, 21891, 21937, 21945, 21896, + 21889, 21919, 21886, 21974, 21905, 21883, 21983, 21949, 21950, 21908, 21913, 21994, 22007, + 21961, 22047, 21969, 21995, 21996, 21972, 21990, 21981, 21956, 21999, 21989, 22002, 22003, + 21964, 21965, 21992, 22005, 21988, 36756, 22046, 22024, 22028, 22017, 22052, 22051, 22014, + 22016, 22055, 22061, 22104, 22073, 22103, 22060, 22093, 22114, 22105, 22108, 22092, 22100, + 22150, 22116, 22129, 22123, 22139, 22140, 22149, 22163, 22191, 22228, 22231, 22237, 22241, + 22261, 22251, 22265, 22271, 22276, 22282, 22281, 22300, 24079, 24089, 24084, 24081, 24113, + 24123, 24124, 37189, 37191, 37192, 37201, 37203, 37204, 37205, 37206, 37208, 37209, 37211, + 37212, 37215, 37216, 37222, 37223, 37224, 37227, 37229, 37235, 37242, 37243, 37244, 37248, + 37249, 37250, 37251, 37252, 37254, 37256, 37258, 37262, 37263, 37267, 37268, 37269, 37270, + 37271, 37272, 37273, 37276, 37277, 37278, 37279, 37280, 37281, 37284, 37285, 37286, 37287, + 37288, 37289, 37291, 37292, 37296, 37297, 37298, 37299, 37302, 37303, 37304, 37305, 37307, + 37308, 37309, 37310, 37311, 37312, 37313, 37314, 37315, 37316, 37317, 37318, 37320, 37323, + 37328, 37330, 37331, 37332, 37333, 37334, 37335, 37336, 37337, 37338, 37339, 37341, 37342, + 37343, 37344, 37345, 37346, 37347, 37348, 37349, 24119, 24132, 24148, 24155, 24158, 24161, + 23692, 23674, 23693, 23696, 23702, 23688, 23704, 23705, 23697, 23706, 23708, 23733, 23714, + 23741, 23724, 23723, 23729, 23715, 23745, 23735, 23748, 23762, 23780, 23755, 23781, 23810, + 23811, 23847, 23846, 23854, 23844, 23838, 23814, 23835, 23896, 23870, 23860, 23869, 23916, + 23899, 23919, 23901, 23915, 23883, 23882, 23913, 23924, 23938, 23961, 23965, 35955, 23991, + 24005, 24435, 24439, 24450, 24455, 24457, 24460, 24469, 24473, 24476, 24488, 24493, 24501, + 24508, 34914, 24417, 29357, 29360, 29364, 29367, 29368, 29379, 29377, 29390, 29389, 29394, + 29416, 29423, 29417, 29426, 29428, 29431, 29441, 29427, 29443, 29434, 37350, 37351, 37352, + 37353, 37354, 37355, 37356, 37357, 37358, 37359, 37360, 37361, 37362, 37363, 37364, 37365, + 37366, 37367, 37368, 37369, 37370, 37371, 37372, 37373, 37374, 37375, 37376, 37377, 37378, + 37379, 37380, 37381, 37382, 37383, 37384, 37385, 37386, 37387, 37388, 37389, 37390, 37391, + 37392, 37393, 37394, 37395, 37396, 37397, 37398, 37399, 37400, 37401, 37402, 37403, 37404, + 37405, 37406, 37407, 37408, 37409, 37410, 37411, 37412, 37413, 37414, 37415, 37416, 37417, + 37418, 37419, 37420, 37421, 37422, 37423, 37424, 37425, 37426, 37427, 37428, 37429, 37430, + 37431, 37432, 37433, 37434, 37435, 37436, 37437, 37438, 37439, 37440, 37441, 37442, 37443, + 37444, 37445, 29435, 29463, 29459, 29473, 29450, 29470, 29469, 29461, 29474, 29497, 29477, + 29484, 29496, 29489, 29520, 29517, 29527, 29536, 29548, 29551, 29566, 33307, 22821, 39143, + 22820, 22786, 39267, 39271, 39272, 39273, 39274, 39275, 39276, 39284, 39287, 39293, 39296, + 39300, 39303, 39306, 39309, 39312, 39313, 39315, 39316, 39317, 24192, 24209, 24203, 24214, + 24229, 24224, 24249, 24245, 24254, 24243, 36179, 24274, 24273, 24283, 24296, 24298, 33210, + 24516, 24521, 24534, 24527, 24579, 24558, 24580, 24545, 24548, 24574, 24581, 24582, 24554, + 24557, 24568, 24601, 24629, 24614, 24603, 24591, 24589, 24617, 24619, 24586, 24639, 24609, + 24696, 24697, 24699, 24698, 24642, 37446, 37447, 37448, 37449, 37450, 37451, 37452, 37453, + 37454, 37455, 37456, 37457, 37458, 37459, 37460, 37461, 37462, 37463, 37464, 37465, 37466, + 37467, 37468, 37469, 37470, 37471, 37472, 37473, 37474, 37475, 37476, 37477, 37478, 37479, + 37480, 37481, 37482, 37483, 37484, 37485, 37486, 37487, 37488, 37489, 37490, 37491, 37493, + 37494, 37495, 37496, 37497, 37498, 37499, 37500, 37501, 37502, 37503, 37504, 37505, 37506, + 37507, 37508, 37509, 37510, 37511, 37512, 37513, 37514, 37515, 37516, 37517, 37519, 37520, + 37521, 37522, 37523, 37524, 37525, 37526, 37527, 37528, 37529, 37530, 37531, 37532, 37533, + 37534, 37535, 37536, 37537, 37538, 37539, 37540, 37541, 37542, 37543, 24682, 24701, 24726, + 24730, 24749, 24733, 24707, 24722, 24716, 24731, 24812, 24763, 24753, 24797, 24792, 24774, + 24794, 24756, 24864, 24870, 24853, 24867, 24820, 24832, 24846, 24875, 24906, 24949, 25004, + 24980, 24999, 25015, 25044, 25077, 24541, 38579, 38377, 38379, 38385, 38387, 38389, 38390, + 38396, 38398, 38403, 38404, 38406, 38408, 38410, 38411, 38412, 38413, 38415, 38418, 38421, + 38422, 38423, 38425, 38426, 20012, 29247, 25109, 27701, 27732, 27740, 27722, 27811, 27781, + 27792, 27796, 27788, 27752, 27753, 27764, 27766, 27782, 27817, 27856, 27860, 27821, 27895, + 27896, 27889, 27863, 27826, 27872, 27862, 27898, 27883, 27886, 27825, 27859, 27887, 27902, + 37544, 37545, 37546, 37547, 37548, 37549, 37551, 37552, 37553, 37554, 37555, 37556, 37557, + 37558, 37559, 37560, 37561, 37562, 37563, 37564, 37565, 37566, 37567, 37568, 37569, 37570, + 37571, 37572, 37573, 37574, 37575, 37577, 37578, 37579, 37580, 37581, 37582, 37583, 37584, + 37585, 37586, 37587, 37588, 37589, 37590, 37591, 37592, 37593, 37594, 37595, 37596, 37597, + 37598, 37599, 37600, 37601, 37602, 37603, 37604, 37605, 37606, 37607, 37608, 37609, 37610, + 37611, 37612, 37613, 37614, 37615, 37616, 37617, 37618, 37619, 37620, 37621, 37622, 37623, + 37624, 37625, 37626, 37627, 37628, 37629, 37630, 37631, 37632, 37633, 37634, 37635, 37636, + 37637, 37638, 37639, 37640, 37641, 27961, 27943, 27916, 27971, 27976, 27911, 27908, 27929, + 27918, 27947, 27981, 27950, 27957, 27930, 27983, 27986, 27988, 27955, 28049, 28015, 28062, + 28064, 27998, 28051, 28052, 27996, 28000, 28028, 28003, 28186, 28103, 28101, 28126, 28174, + 28095, 28128, 28177, 28134, 28125, 28121, 28182, 28075, 28172, 28078, 28203, 28270, 28238, + 28267, 28338, 28255, 28294, 28243, 28244, 28210, 28197, 28228, 28383, 28337, 28312, 28384, + 28461, 28386, 28325, 28327, 28349, 28347, 28343, 28375, 28340, 28367, 28303, 28354, 28319, + 28514, 28486, 28487, 28452, 28437, 28409, 28463, 28470, 28491, 28532, 28458, 28425, 28457, + 28553, 28557, 28556, 28536, 28530, 28540, 28538, 28625, 37642, 37643, 37644, 37645, 37646, + 37647, 37648, 37649, 37650, 37651, 37652, 37653, 37654, 37655, 37656, 37657, 37658, 37659, + 37660, 37661, 37662, 37663, 37664, 37665, 37666, 37667, 37668, 37669, 37670, 37671, 37672, + 37673, 37674, 37675, 37676, 37677, 37678, 37679, 37680, 37681, 37682, 37683, 37684, 37685, + 37686, 37687, 37688, 37689, 37690, 37691, 37692, 37693, 37695, 37696, 37697, 37698, 37699, + 37700, 37701, 37702, 37703, 37704, 37705, 37706, 37707, 37708, 37709, 37710, 37711, 37712, + 37713, 37714, 37715, 37716, 37717, 37718, 37719, 37720, 37721, 37722, 37723, 37724, 37725, + 37726, 37727, 37728, 37729, 37730, 37731, 37732, 37733, 37734, 37735, 37736, 37737, 37739, + 28617, 28583, 28601, 28598, 28610, 28641, 28654, 28638, 28640, 28655, 28698, 28707, 28699, + 28729, 28725, 28751, 28766, 23424, 23428, 23445, 23443, 23461, 23480, 29999, 39582, 25652, + 23524, 23534, 35120, 23536, 36423, 35591, 36790, 36819, 36821, 36837, 36846, 36836, 36841, + 36838, 36851, 36840, 36869, 36868, 36875, 36902, 36881, 36877, 36886, 36897, 36917, 36918, + 36909, 36911, 36932, 36945, 36946, 36944, 36968, 36952, 36962, 36955, 26297, 36980, 36989, + 36994, 37000, 36995, 37003, 24400, 24407, 24406, 24408, 23611, 21675, 23632, 23641, 23409, + 23651, 23654, 32700, 24362, 24361, 24365, 33396, 24380, 39739, 23662, 22913, 22915, 22925, + 22953, 22954, 22947, 37740, 37741, 37742, 37743, 37744, 37745, 37746, 37747, 37748, 37749, + 37750, 37751, 37752, 37753, 37754, 37755, 37756, 37757, 37758, 37759, 37760, 37761, 37762, + 37763, 37764, 37765, 37766, 37767, 37768, 37769, 37770, 37771, 37772, 37773, 37774, 37776, + 37777, 37778, 37779, 37780, 37781, 37782, 37783, 37784, 37785, 37786, 37787, 37788, 37789, + 37790, 37791, 37792, 37793, 37794, 37795, 37796, 37797, 37798, 37799, 37800, 37801, 37802, + 37803, 37804, 37805, 37806, 37807, 37808, 37809, 37810, 37811, 37812, 37813, 37814, 37815, + 37816, 37817, 37818, 37819, 37820, 37821, 37822, 37823, 37824, 37825, 37826, 37827, 37828, + 37829, 37830, 37831, 37832, 37833, 37835, 37836, 37837, 22935, 22986, 22955, 22942, 22948, + 22994, 22962, 22959, 22999, 22974, 23045, 23046, 23005, 23048, 23011, 23000, 23033, 23052, + 23049, 23090, 23092, 23057, 23075, 23059, 23104, 23143, 23114, 23125, 23100, 23138, 23157, + 33004, 23210, 23195, 23159, 23162, 23230, 23275, 23218, 23250, 23252, 23224, 23264, 23267, + 23281, 23254, 23270, 23256, 23260, 23305, 23319, 23318, 23346, 23351, 23360, 23573, 23580, + 23386, 23397, 23411, 23377, 23379, 23394, 39541, 39543, 39544, 39546, 39551, 39549, 39552, + 39553, 39557, 39560, 39562, 39568, 39570, 39571, 39574, 39576, 39579, 39580, 39581, 39583, + 39584, 39586, 39587, 39589, 39591, 32415, 32417, 32419, 32421, 32424, 32425, 37838, 37839, + 37840, 37841, 37842, 37843, 37844, 37845, 37847, 37848, 37849, 37850, 37851, 37852, 37853, + 37854, 37855, 37856, 37857, 37858, 37859, 37860, 37861, 37862, 37863, 37864, 37865, 37866, + 37867, 37868, 37869, 37870, 37871, 37872, 37873, 37874, 37875, 37876, 37877, 37878, 37879, + 37880, 37881, 37882, 37883, 37884, 37885, 37886, 37887, 37888, 37889, 37890, 37891, 37892, + 37893, 37894, 37895, 37896, 37897, 37898, 37899, 37900, 37901, 37902, 37903, 37904, 37905, + 37906, 37907, 37908, 37909, 37910, 37911, 37912, 37913, 37914, 37915, 37916, 37917, 37918, + 37919, 37920, 37921, 37922, 37923, 37924, 37925, 37926, 37927, 37928, 37929, 37930, 37931, + 37932, 37933, 37934, 32429, 32432, 32446, 32448, 32449, 32450, 32457, 32459, 32460, 32464, + 32468, 32471, 32475, 32480, 32481, 32488, 32491, 32494, 32495, 32497, 32498, 32525, 32502, + 32506, 32507, 32510, 32513, 32514, 32515, 32519, 32520, 32523, 32524, 32527, 32529, 32530, + 32535, 32537, 32540, 32539, 32543, 32545, 32546, 32547, 32548, 32549, 32550, 32551, 32554, + 32555, 32556, 32557, 32559, 32560, 32561, 32562, 32563, 32565, 24186, 30079, 24027, 30014, + 37013, 29582, 29585, 29614, 29602, 29599, 29647, 29634, 29649, 29623, 29619, 29632, 29641, + 29640, 29669, 29657, 39036, 29706, 29673, 29671, 29662, 29626, 29682, 29711, 29738, 29787, + 29734, 29733, 29736, 29744, 29742, 29740, 37935, 37936, 37937, 37938, 37939, 37940, 37941, + 37942, 37943, 37944, 37945, 37946, 37947, 37948, 37949, 37951, 37952, 37953, 37954, 37955, + 37956, 37957, 37958, 37959, 37960, 37961, 37962, 37963, 37964, 37965, 37966, 37967, 37968, + 37969, 37970, 37971, 37972, 37973, 37974, 37975, 37976, 37977, 37978, 37979, 37980, 37981, + 37982, 37983, 37984, 37985, 37986, 37987, 37988, 37989, 37990, 37991, 37992, 37993, 37994, + 37996, 37997, 37998, 37999, 38000, 38001, 38002, 38003, 38004, 38005, 38006, 38007, 38008, + 38009, 38010, 38011, 38012, 38013, 38014, 38015, 38016, 38017, 38018, 38019, 38020, 38033, + 38038, 38040, 38087, 38095, 38099, 38100, 38106, 38118, 38139, 38172, 38176, 29723, 29722, + 29761, 29788, 29783, 29781, 29785, 29815, 29805, 29822, 29852, 29838, 29824, 29825, 29831, + 29835, 29854, 29864, 29865, 29840, 29863, 29906, 29882, 38890, 38891, 38892, 26444, 26451, + 26462, 26440, 26473, 26533, 26503, 26474, 26483, 26520, 26535, 26485, 26536, 26526, 26541, + 26507, 26487, 26492, 26608, 26633, 26584, 26634, 26601, 26544, 26636, 26585, 26549, 26586, + 26547, 26589, 26624, 26563, 26552, 26594, 26638, 26561, 26621, 26674, 26675, 26720, 26721, + 26702, 26722, 26692, 26724, 26755, 26653, 26709, 26726, 26689, 26727, 26688, 26686, 26698, + 26697, 26665, 26805, 26767, 26740, 26743, 26771, 26731, 26818, 26990, 26876, 26911, 26912, + 26873, 38183, 38195, 38205, 38211, 38216, 38219, 38229, 38234, 38240, 38254, 38260, 38261, + 38263, 38264, 38265, 38266, 38267, 38268, 38269, 38270, 38272, 38273, 38274, 38275, 38276, + 38277, 38278, 38279, 38280, 38281, 38282, 38283, 38284, 38285, 38286, 38287, 38288, 38289, + 38290, 38291, 38292, 38293, 38294, 38295, 38296, 38297, 38298, 38299, 38300, 38301, 38302, + 38303, 38304, 38305, 38306, 38307, 38308, 38309, 38310, 38311, 38312, 38313, 38314, 38315, + 38316, 38317, 38318, 38319, 38320, 38321, 38322, 38323, 38324, 38325, 38326, 38327, 38328, + 38329, 38330, 38331, 38332, 38333, 38334, 38335, 38336, 38337, 38338, 38339, 38340, 38341, + 38342, 38343, 38344, 38345, 38346, 38347, 26916, 26864, 26891, 26881, 26967, 26851, 26896, + 26993, 26937, 26976, 26946, 26973, 27012, 26987, 27008, 27032, 27000, 26932, 27084, 27015, + 27016, 27086, 27017, 26982, 26979, 27001, 27035, 27047, 27067, 27051, 27053, 27092, 27057, + 27073, 27082, 27103, 27029, 27104, 27021, 27135, 27183, 27117, 27159, 27160, 27237, 27122, + 27204, 27198, 27296, 27216, 27227, 27189, 27278, 27257, 27197, 27176, 27224, 27260, 27281, + 27280, 27305, 27287, 27307, 29495, 29522, 27521, 27522, 27527, 27524, 27538, 27539, 27533, + 27546, 27547, 27553, 27562, 36715, 36717, 36721, 36722, 36723, 36725, 36726, 36728, 36727, + 36729, 36730, 36732, 36734, 36737, 36738, 36740, 36743, 36747, 38348, 38349, 38350, 38351, + 38352, 38353, 38354, 38355, 38356, 38357, 38358, 38359, 38360, 38361, 38362, 38363, 38364, + 38365, 38366, 38367, 38368, 38369, 38370, 38371, 38372, 38373, 38374, 38375, 38380, 38399, + 38407, 38419, 38424, 38427, 38430, 38432, 38435, 38436, 38437, 38438, 38439, 38440, 38441, + 38443, 38444, 38445, 38447, 38448, 38455, 38456, 38457, 38458, 38462, 38465, 38467, 38474, + 38478, 38479, 38481, 38482, 38483, 38486, 38487, 38488, 38489, 38490, 38492, 38493, 38494, + 38496, 38499, 38501, 38502, 38507, 38509, 38510, 38511, 38512, 38513, 38515, 38520, 38521, + 38522, 38523, 38524, 38525, 38526, 38527, 38528, 38529, 38530, 38531, 38532, 38535, 38537, + 38538, 36749, 36750, 36751, 36760, 36762, 36558, 25099, 25111, 25115, 25119, 25122, 25121, + 25125, 25124, 25132, 33255, 29935, 29940, 29951, 29967, 29969, 29971, 25908, 26094, 26095, + 26096, 26122, 26137, 26482, 26115, 26133, 26112, 28805, 26359, 26141, 26164, 26161, 26166, + 26165, 32774, 26207, 26196, 26177, 26191, 26198, 26209, 26199, 26231, 26244, 26252, 26279, + 26269, 26302, 26331, 26332, 26342, 26345, 36146, 36147, 36150, 36155, 36157, 36160, 36165, + 36166, 36168, 36169, 36167, 36173, 36181, 36185, 35271, 35274, 35275, 35276, 35278, 35279, + 35280, 35281, 29294, 29343, 29277, 29286, 29295, 29310, 29311, 29316, 29323, 29325, 29327, + 29330, 25352, 25394, 25520, 38540, 38542, 38545, 38546, 38547, 38549, 38550, 38554, 38555, + 38557, 38558, 38559, 38560, 38561, 38562, 38563, 38564, 38565, 38566, 38568, 38569, 38570, + 38571, 38572, 38573, 38574, 38575, 38577, 38578, 38580, 38581, 38583, 38584, 38586, 38587, + 38591, 38594, 38595, 38600, 38602, 38603, 38608, 38609, 38611, 38612, 38614, 38615, 38616, + 38617, 38618, 38619, 38620, 38621, 38622, 38623, 38625, 38626, 38627, 38628, 38629, 38630, + 38631, 38635, 38636, 38637, 38638, 38640, 38641, 38642, 38644, 38645, 38648, 38650, 38651, + 38652, 38653, 38655, 38658, 38659, 38661, 38666, 38667, 38668, 38672, 38673, 38674, 38676, + 38677, 38679, 38680, 38681, 38682, 38683, 38685, 38687, 38688, 25663, 25816, 32772, 27626, + 27635, 27645, 27637, 27641, 27653, 27655, 27654, 27661, 27669, 27672, 27673, 27674, 27681, + 27689, 27684, 27690, 27698, 25909, 25941, 25963, 29261, 29266, 29270, 29232, 34402, 21014, + 32927, 32924, 32915, 32956, 26378, 32957, 32945, 32939, 32941, 32948, 32951, 32999, 33000, + 33001, 33002, 32987, 32962, 32964, 32985, 32973, 32983, 26384, 32989, 33003, 33009, 33012, + 33005, 33037, 33038, 33010, 33020, 26389, 33042, 35930, 33078, 33054, 33068, 33048, 33074, + 33096, 33100, 33107, 33140, 33113, 33114, 33137, 33120, 33129, 33148, 33149, 33133, 33127, + 22605, 23221, 33160, 33154, 33169, 28373, 33187, 33194, 33228, 26406, 33226, 33211, 38689, + 38690, 38691, 38692, 38693, 38694, 38695, 38696, 38697, 38699, 38700, 38702, 38703, 38705, + 38707, 38708, 38709, 38710, 38711, 38714, 38715, 38716, 38717, 38719, 38720, 38721, 38722, + 38723, 38724, 38725, 38726, 38727, 38728, 38729, 38730, 38731, 38732, 38733, 38734, 38735, + 38736, 38737, 38740, 38741, 38743, 38744, 38746, 38748, 38749, 38751, 38755, 38756, 38758, + 38759, 38760, 38762, 38763, 38764, 38765, 38766, 38767, 38768, 38769, 38770, 38773, 38775, + 38776, 38777, 38778, 38779, 38781, 38782, 38783, 38784, 38785, 38786, 38787, 38788, 38790, + 38791, 38792, 38793, 38794, 38796, 38798, 38799, 38800, 38803, 38805, 38806, 38807, 38809, + 38810, 38811, 38812, 38813, 33217, 33190, 27428, 27447, 27449, 27459, 27462, 27481, 39121, + 39122, 39123, 39125, 39129, 39130, 27571, 24384, 27586, 35315, 26000, 40785, 26003, 26044, + 26054, 26052, 26051, 26060, 26062, 26066, 26070, 28800, 28828, 28822, 28829, 28859, 28864, + 28855, 28843, 28849, 28904, 28874, 28944, 28947, 28950, 28975, 28977, 29043, 29020, 29032, + 28997, 29042, 29002, 29048, 29050, 29080, 29107, 29109, 29096, 29088, 29152, 29140, 29159, + 29177, 29213, 29224, 28780, 28952, 29030, 29113, 25150, 25149, 25155, 25160, 25161, 31035, + 31040, 31046, 31049, 31067, 31068, 31059, 31066, 31074, 31063, 31072, 31087, 31079, 31098, + 31109, 31114, 31130, 31143, 31155, 24529, 24528, 38814, 38815, 38817, 38818, 38820, 38821, + 38822, 38823, 38824, 38825, 38826, 38828, 38830, 38832, 38833, 38835, 38837, 38838, 38839, + 38840, 38841, 38842, 38843, 38844, 38845, 38846, 38847, 38848, 38849, 38850, 38851, 38852, + 38853, 38854, 38855, 38856, 38857, 38858, 38859, 38860, 38861, 38862, 38863, 38864, 38865, + 38866, 38867, 38868, 38869, 38870, 38871, 38872, 38873, 38874, 38875, 38876, 38877, 38878, + 38879, 38880, 38881, 38882, 38883, 38884, 38885, 38888, 38894, 38895, 38896, 38897, 38898, + 38900, 38903, 38904, 38905, 38906, 38907, 38908, 38909, 38910, 38911, 38912, 38913, 38914, + 38915, 38916, 38917, 38918, 38919, 38920, 38921, 38922, 38923, 38924, 38925, 38926, 24636, + 24669, 24666, 24679, 24641, 24665, 24675, 24747, 24838, 24845, 24925, 25001, 24989, 25035, + 25041, 25094, 32896, 32895, 27795, 27894, 28156, 30710, 30712, 30720, 30729, 30743, 30744, + 30737, 26027, 30765, 30748, 30749, 30777, 30778, 30779, 30751, 30780, 30757, 30764, 30755, + 30761, 30798, 30829, 30806, 30807, 30758, 30800, 30791, 30796, 30826, 30875, 30867, 30874, + 30855, 30876, 30881, 30883, 30898, 30905, 30885, 30932, 30937, 30921, 30956, 30962, 30981, + 30964, 30995, 31012, 31006, 31028, 40859, 40697, 40699, 40700, 30449, 30468, 30477, 30457, + 30471, 30472, 30490, 30498, 30489, 30509, 30502, 30517, 30520, 30544, 30545, 30535, 30531, + 30554, 30568, 38927, 38928, 38929, 38930, 38931, 38932, 38933, 38934, 38935, 38936, 38937, + 38938, 38939, 38940, 38941, 38942, 38943, 38944, 38945, 38946, 38947, 38948, 38949, 38950, + 38951, 38952, 38953, 38954, 38955, 38956, 38957, 38958, 38959, 38960, 38961, 38962, 38963, + 38964, 38965, 38966, 38967, 38968, 38969, 38970, 38971, 38972, 38973, 38974, 38975, 38976, + 38977, 38978, 38979, 38980, 38981, 38982, 38983, 38984, 38985, 38986, 38987, 38988, 38989, + 38990, 38991, 38992, 38993, 38994, 38995, 38996, 38997, 38998, 38999, 39000, 39001, 39002, + 39003, 39004, 39005, 39006, 39007, 39008, 39009, 39010, 39011, 39012, 39013, 39014, 39015, + 39016, 39017, 39018, 39019, 39020, 39021, 39022, 30562, 30565, 30591, 30605, 30589, 30592, + 30604, 30609, 30623, 30624, 30640, 30645, 30653, 30010, 30016, 30030, 30027, 30024, 30043, + 30066, 30073, 30083, 32600, 32609, 32607, 35400, 32616, 32628, 32625, 32633, 32641, 32638, + 30413, 30437, 34866, 38021, 38022, 38023, 38027, 38026, 38028, 38029, 38031, 38032, 38036, + 38039, 38037, 38042, 38043, 38044, 38051, 38052, 38059, 38058, 38061, 38060, 38063, 38064, + 38066, 38068, 38070, 38071, 38072, 38073, 38074, 38076, 38077, 38079, 38084, 38088, 38089, + 38090, 38091, 38092, 38093, 38094, 38096, 38097, 38098, 38101, 38102, 38103, 38105, 38104, + 38107, 38110, 38111, 38112, 38114, 38116, 38117, 38119, 38120, 38122, 39023, 39024, 39025, + 39026, 39027, 39028, 39051, 39054, 39058, 39061, 39065, 39075, 39080, 39081, 39082, 39083, + 39084, 39085, 39086, 39087, 39088, 39089, 39090, 39091, 39092, 39093, 39094, 39095, 39096, + 39097, 39098, 39099, 39100, 39101, 39102, 39103, 39104, 39105, 39106, 39107, 39108, 39109, + 39110, 39111, 39112, 39113, 39114, 39115, 39116, 39117, 39119, 39120, 39124, 39126, 39127, + 39131, 39132, 39133, 39136, 39137, 39138, 39139, 39140, 39141, 39142, 39145, 39146, 39147, + 39148, 39149, 39150, 39151, 39152, 39153, 39154, 39155, 39156, 39157, 39158, 39159, 39160, + 39161, 39162, 39163, 39164, 39165, 39166, 39167, 39168, 39169, 39170, 39171, 39172, 39173, + 39174, 39175, 38121, 38123, 38126, 38127, 38131, 38132, 38133, 38135, 38137, 38140, 38141, + 38143, 38147, 38146, 38150, 38151, 38153, 38154, 38157, 38158, 38159, 38162, 38163, 38164, + 38165, 38166, 38168, 38171, 38173, 38174, 38175, 38178, 38186, 38187, 38185, 38188, 38193, + 38194, 38196, 38198, 38199, 38200, 38204, 38206, 38207, 38210, 38197, 38212, 38213, 38214, + 38217, 38220, 38222, 38223, 38226, 38227, 38228, 38230, 38231, 38232, 38233, 38235, 38238, + 38239, 38237, 38241, 38242, 38244, 38245, 38246, 38247, 38248, 38249, 38250, 38251, 38252, + 38255, 38257, 38258, 38259, 38202, 30695, 30700, 38601, 31189, 31213, 31203, 31211, 31238, + 23879, 31235, 31234, 31262, 31252, 39176, 39177, 39178, 39179, 39180, 39182, 39183, 39185, + 39186, 39187, 39188, 39189, 39190, 39191, 39192, 39193, 39194, 39195, 39196, 39197, 39198, + 39199, 39200, 39201, 39202, 39203, 39204, 39205, 39206, 39207, 39208, 39209, 39210, 39211, + 39212, 39213, 39215, 39216, 39217, 39218, 39219, 39220, 39221, 39222, 39223, 39224, 39225, + 39226, 39227, 39228, 39229, 39230, 39231, 39232, 39233, 39234, 39235, 39236, 39237, 39238, + 39239, 39240, 39241, 39242, 39243, 39244, 39245, 39246, 39247, 39248, 39249, 39250, 39251, + 39254, 39255, 39256, 39257, 39258, 39259, 39260, 39261, 39262, 39263, 39264, 39265, 39266, + 39268, 39270, 39283, 39288, 39289, 39291, 39294, 39298, 39299, 39305, 31289, 31287, 31313, + 40655, 39333, 31344, 30344, 30350, 30355, 30361, 30372, 29918, 29920, 29996, 40480, 40482, + 40488, 40489, 40490, 40491, 40492, 40498, 40497, 40502, 40504, 40503, 40505, 40506, 40510, + 40513, 40514, 40516, 40518, 40519, 40520, 40521, 40523, 40524, 40526, 40529, 40533, 40535, + 40538, 40539, 40540, 40542, 40547, 40550, 40551, 40552, 40553, 40554, 40555, 40556, 40561, + 40557, 40563, 30098, 30100, 30102, 30112, 30109, 30124, 30115, 30131, 30132, 30136, 30148, + 30129, 30128, 30147, 30146, 30166, 30157, 30179, 30184, 30182, 30180, 30187, 30183, 30211, + 30193, 30204, 30207, 30224, 30208, 30213, 30220, 30231, 30218, 30245, 30232, 30229, 30233, + 39308, 39310, 39322, 39323, 39324, 39325, 39326, 39327, 39328, 39329, 39330, 39331, 39332, + 39334, 39335, 39337, 39338, 39339, 39340, 39341, 39342, 39343, 39344, 39345, 39346, 39347, + 39348, 39349, 39350, 39351, 39352, 39353, 39354, 39355, 39356, 39357, 39358, 39359, 39360, + 39361, 39362, 39363, 39364, 39365, 39366, 39367, 39368, 39369, 39370, 39371, 39372, 39373, + 39374, 39375, 39376, 39377, 39378, 39379, 39380, 39381, 39382, 39383, 39384, 39385, 39386, + 39387, 39388, 39389, 39390, 39391, 39392, 39393, 39394, 39395, 39396, 39397, 39398, 39399, + 39400, 39401, 39402, 39403, 39404, 39405, 39406, 39407, 39408, 39409, 39410, 39411, 39412, + 39413, 39414, 39415, 39416, 39417, 30235, 30268, 30242, 30240, 30272, 30253, 30256, 30271, + 30261, 30275, 30270, 30259, 30285, 30302, 30292, 30300, 30294, 30315, 30319, 32714, 31462, + 31352, 31353, 31360, 31366, 31368, 31381, 31398, 31392, 31404, 31400, 31405, 31411, 34916, + 34921, 34930, 34941, 34943, 34946, 34978, 35014, 34999, 35004, 35017, 35042, 35022, 35043, + 35045, 35057, 35098, 35068, 35048, 35070, 35056, 35105, 35097, 35091, 35099, 35082, 35124, + 35115, 35126, 35137, 35174, 35195, 30091, 32997, 30386, 30388, 30684, 32786, 32788, 32790, + 32796, 32800, 32802, 32805, 32806, 32807, 32809, 32808, 32817, 32779, 32821, 32835, 32838, + 32845, 32850, 32873, 32881, 35203, 39032, 39040, 39043, 39418, 39419, 39420, 39421, 39422, + 39423, 39424, 39425, 39426, 39427, 39428, 39429, 39430, 39431, 39432, 39433, 39434, 39435, + 39436, 39437, 39438, 39439, 39440, 39441, 39442, 39443, 39444, 39445, 39446, 39447, 39448, + 39449, 39450, 39451, 39452, 39453, 39454, 39455, 39456, 39457, 39458, 39459, 39460, 39461, + 39462, 39463, 39464, 39465, 39466, 39467, 39468, 39469, 39470, 39471, 39472, 39473, 39474, + 39475, 39476, 39477, 39478, 39479, 39480, 39481, 39482, 39483, 39484, 39485, 39486, 39487, + 39488, 39489, 39490, 39491, 39492, 39493, 39494, 39495, 39496, 39497, 39498, 39499, 39500, + 39501, 39502, 39503, 39504, 39505, 39506, 39507, 39508, 39509, 39510, 39511, 39512, 39513, + 39049, 39052, 39053, 39055, 39060, 39066, 39067, 39070, 39071, 39073, 39074, 39077, 39078, + 34381, 34388, 34412, 34414, 34431, 34426, 34428, 34427, 34472, 34445, 34443, 34476, 34461, + 34471, 34467, 34474, 34451, 34473, 34486, 34500, 34485, 34510, 34480, 34490, 34481, 34479, + 34505, 34511, 34484, 34537, 34545, 34546, 34541, 34547, 34512, 34579, 34526, 34548, 34527, + 34520, 34513, 34563, 34567, 34552, 34568, 34570, 34573, 34569, 34595, 34619, 34590, 34597, + 34606, 34586, 34622, 34632, 34612, 34609, 34601, 34615, 34623, 34690, 34594, 34685, 34686, + 34683, 34656, 34672, 34636, 34670, 34699, 34643, 34659, 34684, 34660, 34649, 34661, 34707, + 34735, 34728, 34770, 39514, 39515, 39516, 39517, 39518, 39519, 39520, 39521, 39522, 39523, + 39524, 39525, 39526, 39527, 39528, 39529, 39530, 39531, 39538, 39555, 39561, 39565, 39566, + 39572, 39573, 39577, 39590, 39593, 39594, 39595, 39596, 39597, 39598, 39599, 39602, 39603, + 39604, 39605, 39609, 39611, 39613, 39614, 39615, 39619, 39620, 39622, 39623, 39624, 39625, + 39626, 39629, 39630, 39631, 39632, 39634, 39636, 39637, 39638, 39639, 39641, 39642, 39643, + 39644, 39645, 39646, 39648, 39650, 39651, 39652, 39653, 39655, 39656, 39657, 39658, 39660, + 39662, 39664, 39665, 39666, 39667, 39668, 39669, 39670, 39671, 39672, 39674, 39676, 39677, + 39678, 39679, 39680, 39681, 39682, 39684, 39685, 39686, 34758, 34696, 34693, 34733, 34711, + 34691, 34731, 34789, 34732, 34741, 34739, 34763, 34771, 34749, 34769, 34752, 34762, 34779, + 34794, 34784, 34798, 34838, 34835, 34814, 34826, 34843, 34849, 34873, 34876, 32566, 32578, + 32580, 32581, 33296, 31482, 31485, 31496, 31491, 31492, 31509, 31498, 31531, 31503, 31559, + 31544, 31530, 31513, 31534, 31537, 31520, 31525, 31524, 31539, 31550, 31518, 31576, 31578, + 31557, 31605, 31564, 31581, 31584, 31598, 31611, 31586, 31602, 31601, 31632, 31654, 31655, + 31672, 31660, 31645, 31656, 31621, 31658, 31644, 31650, 31659, 31668, 31697, 31681, 31692, + 31709, 31706, 31717, 31718, 31722, 31756, 31742, 31740, 31759, 31766, 31755, 39687, 39689, + 39690, 39691, 39692, 39693, 39694, 39696, 39697, 39698, 39700, 39701, 39702, 39703, 39704, + 39705, 39706, 39707, 39708, 39709, 39710, 39712, 39713, 39714, 39716, 39717, 39718, 39719, + 39720, 39721, 39722, 39723, 39724, 39725, 39726, 39728, 39729, 39731, 39732, 39733, 39734, + 39735, 39736, 39737, 39738, 39741, 39742, 39743, 39744, 39750, 39754, 39755, 39756, 39758, + 39760, 39762, 39763, 39765, 39766, 39767, 39768, 39769, 39770, 39771, 39772, 39773, 39774, + 39775, 39776, 39777, 39778, 39779, 39780, 39781, 39782, 39783, 39784, 39785, 39786, 39787, + 39788, 39789, 39790, 39791, 39792, 39793, 39794, 39795, 39796, 39797, 39798, 39799, 39800, + 39801, 39802, 39803, 31775, 31786, 31782, 31800, 31809, 31808, 33278, 33281, 33282, 33284, + 33260, 34884, 33313, 33314, 33315, 33325, 33327, 33320, 33323, 33336, 33339, 33331, 33332, + 33342, 33348, 33353, 33355, 33359, 33370, 33375, 33384, 34942, 34949, 34952, 35032, 35039, + 35166, 32669, 32671, 32679, 32687, 32688, 32690, 31868, 25929, 31889, 31901, 31900, 31902, + 31906, 31922, 31932, 31933, 31937, 31943, 31948, 31949, 31944, 31941, 31959, 31976, 33390, + 26280, 32703, 32718, 32725, 32741, 32737, 32742, 32745, 32750, 32755, 31992, 32119, 32166, + 32174, 32327, 32411, 40632, 40628, 36211, 36228, 36244, 36241, 36273, 36199, 36205, 35911, + 35913, 37194, 37200, 37198, 37199, 37220, 39804, 39805, 39806, 39807, 39808, 39809, 39810, + 39811, 39812, 39813, 39814, 39815, 39816, 39817, 39818, 39819, 39820, 39821, 39822, 39823, + 39824, 39825, 39826, 39827, 39828, 39829, 39830, 39831, 39832, 39833, 39834, 39835, 39836, + 39837, 39838, 39839, 39840, 39841, 39842, 39843, 39844, 39845, 39846, 39847, 39848, 39849, + 39850, 39851, 39852, 39853, 39854, 39855, 39856, 39857, 39858, 39859, 39860, 39861, 39862, + 39863, 39864, 39865, 39866, 39867, 39868, 39869, 39870, 39871, 39872, 39873, 39874, 39875, + 39876, 39877, 39878, 39879, 39880, 39881, 39882, 39883, 39884, 39885, 39886, 39887, 39888, + 39889, 39890, 39891, 39892, 39893, 39894, 39895, 39896, 39897, 39898, 39899, 37218, 37217, + 37232, 37225, 37231, 37245, 37246, 37234, 37236, 37241, 37260, 37253, 37264, 37261, 37265, + 37282, 37283, 37290, 37293, 37294, 37295, 37301, 37300, 37306, 35925, 40574, 36280, 36331, + 36357, 36441, 36457, 36277, 36287, 36284, 36282, 36292, 36310, 36311, 36314, 36318, 36302, + 36303, 36315, 36294, 36332, 36343, 36344, 36323, 36345, 36347, 36324, 36361, 36349, 36372, + 36381, 36383, 36396, 36398, 36387, 36399, 36410, 36416, 36409, 36405, 36413, 36401, 36425, + 36417, 36418, 36433, 36434, 36426, 36464, 36470, 36476, 36463, 36468, 36485, 36495, 36500, + 36496, 36508, 36510, 35960, 35970, 35978, 35973, 35992, 35988, 26011, 35286, 35294, 35290, + 35292, 39900, 39901, 39902, 39903, 39904, 39905, 39906, 39907, 39908, 39909, 39910, 39911, + 39912, 39913, 39914, 39915, 39916, 39917, 39918, 39919, 39920, 39921, 39922, 39923, 39924, + 39925, 39926, 39927, 39928, 39929, 39930, 39931, 39932, 39933, 39934, 39935, 39936, 39937, + 39938, 39939, 39940, 39941, 39942, 39943, 39944, 39945, 39946, 39947, 39948, 39949, 39950, + 39951, 39952, 39953, 39954, 39955, 39956, 39957, 39958, 39959, 39960, 39961, 39962, 39963, + 39964, 39965, 39966, 39967, 39968, 39969, 39970, 39971, 39972, 39973, 39974, 39975, 39976, + 39977, 39978, 39979, 39980, 39981, 39982, 39983, 39984, 39985, 39986, 39987, 39988, 39989, + 39990, 39991, 39992, 39993, 39994, 39995, 35301, 35307, 35311, 35390, 35622, 38739, 38633, + 38643, 38639, 38662, 38657, 38664, 38671, 38670, 38698, 38701, 38704, 38718, 40832, 40835, + 40837, 40838, 40839, 40840, 40841, 40842, 40844, 40702, 40715, 40717, 38585, 38588, 38589, + 38606, 38610, 30655, 38624, 37518, 37550, 37576, 37694, 37738, 37834, 37775, 37950, 37995, + 40063, 40066, 40069, 40070, 40071, 40072, 31267, 40075, 40078, 40080, 40081, 40082, 40084, + 40085, 40090, 40091, 40094, 40095, 40096, 40097, 40098, 40099, 40101, 40102, 40103, 40104, + 40105, 40107, 40109, 40110, 40112, 40113, 40114, 40115, 40116, 40117, 40118, 40119, 40122, + 40123, 40124, 40125, 40132, 40133, 40134, 40135, 40138, 40139, 39996, 39997, 39998, 39999, + 40000, 40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009, 40010, 40011, 40012, + 40013, 40014, 40015, 40016, 40017, 40018, 40019, 40020, 40021, 40022, 40023, 40024, 40025, + 40026, 40027, 40028, 40029, 40030, 40031, 40032, 40033, 40034, 40035, 40036, 40037, 40038, + 40039, 40040, 40041, 40042, 40043, 40044, 40045, 40046, 40047, 40048, 40049, 40050, 40051, + 40052, 40053, 40054, 40055, 40056, 40057, 40058, 40059, 40061, 40062, 40064, 40067, 40068, + 40073, 40074, 40076, 40079, 40083, 40086, 40087, 40088, 40089, 40093, 40106, 40108, 40111, + 40121, 40126, 40127, 40128, 40129, 40130, 40136, 40137, 40145, 40146, 40154, 40155, 40160, + 40161, 40140, 40141, 40142, 40143, 40144, 40147, 40148, 40149, 40151, 40152, 40153, 40156, + 40157, 40159, 40162, 38780, 38789, 38801, 38802, 38804, 38831, 38827, 38819, 38834, 38836, + 39601, 39600, 39607, 40536, 39606, 39610, 39612, 39617, 39616, 39621, 39618, 39627, 39628, + 39633, 39749, 39747, 39751, 39753, 39752, 39757, 39761, 39144, 39181, 39214, 39253, 39252, + 39647, 39649, 39654, 39663, 39659, 39675, 39661, 39673, 39688, 39695, 39699, 39711, 39715, + 40637, 40638, 32315, 40578, 40583, 40584, 40587, 40594, 37846, 40605, 40607, 40667, 40668, + 40669, 40672, 40671, 40674, 40681, 40679, 40677, 40682, 40687, 40738, 40748, 40751, 40761, + 40759, 40765, 40766, 40772, 40163, 40164, 40165, 40166, 40167, 40168, 40169, 40170, 40171, + 40172, 40173, 40174, 40175, 40176, 40177, 40178, 40179, 40180, 40181, 40182, 40183, 40184, + 40185, 40186, 40187, 40188, 40189, 40190, 40191, 40192, 40193, 40194, 40195, 40196, 40197, + 40198, 40199, 40200, 40201, 40202, 40203, 40204, 40205, 40206, 40207, 40208, 40209, 40210, + 40211, 40212, 40213, 40214, 40215, 40216, 40217, 40218, 40219, 40220, 40221, 40222, 40223, + 40224, 40225, 40226, 40227, 40228, 40229, 40230, 40231, 40232, 40233, 40234, 40235, 40236, + 40237, 40238, 40239, 40240, 40241, 40242, 40243, 40244, 40245, 40246, 40247, 40248, 40249, + 40250, 40251, 40252, 40253, 40254, 40255, 40256, 40257, 40258, 57908, 57909, 57910, 57911, + 57912, 57913, 57914, 57915, 57916, 57917, 57918, 57919, 57920, 57921, 57922, 57923, 57924, + 57925, 57926, 57927, 57928, 57929, 57930, 57931, 57932, 57933, 57934, 57935, 57936, 57937, + 57938, 57939, 57940, 57941, 57942, 57943, 57944, 57945, 57946, 57947, 57948, 57949, 57950, + 57951, 57952, 57953, 57954, 57955, 57956, 57957, 57958, 57959, 57960, 57961, 57962, 57963, + 57964, 57965, 57966, 57967, 57968, 57969, 57970, 57971, 57972, 57973, 57974, 57975, 57976, + 57977, 57978, 57979, 57980, 57981, 57982, 57983, 57984, 57985, 57986, 57987, 57988, 57989, + 57990, 57991, 57992, 57993, 57994, 57995, 57996, 57997, 57998, 57999, 58000, 58001, 40259, + 40260, 40261, 40262, 40263, 40264, 40265, 40266, 40267, 40268, 40269, 40270, 40271, 40272, + 40273, 40274, 40275, 40276, 40277, 40278, 40279, 40280, 40281, 40282, 40283, 40284, 40285, + 40286, 40287, 40288, 40289, 40290, 40291, 40292, 40293, 40294, 40295, 40296, 40297, 40298, + 40299, 40300, 40301, 40302, 40303, 40304, 40305, 40306, 40307, 40308, 40309, 40310, 40311, + 40312, 40313, 40314, 40315, 40316, 40317, 40318, 40319, 40320, 40321, 40322, 40323, 40324, + 40325, 40326, 40327, 40328, 40329, 40330, 40331, 40332, 40333, 40334, 40335, 40336, 40337, + 40338, 40339, 40340, 40341, 40342, 40343, 40344, 40345, 40346, 40347, 40348, 40349, 40350, + 40351, 40352, 40353, 40354, 58002, 58003, 58004, 58005, 58006, 58007, 58008, 58009, 58010, + 58011, 58012, 58013, 58014, 58015, 58016, 58017, 58018, 58019, 58020, 58021, 58022, 58023, + 58024, 58025, 58026, 58027, 58028, 58029, 58030, 58031, 58032, 58033, 58034, 58035, 58036, + 58037, 58038, 58039, 58040, 58041, 58042, 58043, 58044, 58045, 58046, 58047, 58048, 58049, + 58050, 58051, 58052, 58053, 58054, 58055, 58056, 58057, 58058, 58059, 58060, 58061, 58062, + 58063, 58064, 58065, 58066, 58067, 58068, 58069, 58070, 58071, 58072, 58073, 58074, 58075, + 58076, 58077, 58078, 58079, 58080, 58081, 58082, 58083, 58084, 58085, 58086, 58087, 58088, + 58089, 58090, 58091, 58092, 58093, 58094, 58095, 40355, 40356, 40357, 40358, 40359, 40360, + 40361, 40362, 40363, 40364, 40365, 40366, 40367, 40368, 40369, 40370, 40371, 40372, 40373, + 40374, 40375, 40376, 40377, 40378, 40379, 40380, 40381, 40382, 40383, 40384, 40385, 40386, + 40387, 40388, 40389, 40390, 40391, 40392, 40393, 40394, 40395, 40396, 40397, 40398, 40399, + 40400, 40401, 40402, 40403, 40404, 40405, 40406, 40407, 40408, 40409, 40410, 40411, 40412, + 40413, 40414, 40415, 40416, 40417, 40418, 40419, 40420, 40421, 40422, 40423, 40424, 40425, + 40426, 40427, 40428, 40429, 40430, 40431, 40432, 40433, 40434, 40435, 40436, 40437, 40438, + 40439, 40440, 40441, 40442, 40443, 40444, 40445, 40446, 40447, 40448, 40449, 40450, 58096, + 58097, 58098, 58099, 58100, 58101, 58102, 58103, 58104, 58105, 58106, 58107, 58108, 58109, + 58110, 58111, 58112, 58113, 58114, 58115, 58116, 58117, 58118, 58119, 58120, 58121, 58122, + 58123, 58124, 58125, 58126, 58127, 58128, 58129, 58130, 58131, 58132, 58133, 58134, 58135, + 58136, 58137, 58138, 58139, 58140, 58141, 58142, 58143, 58144, 58145, 58146, 58147, 58148, + 58149, 58150, 58151, 58152, 58153, 58154, 58155, 58156, 58157, 58158, 58159, 58160, 58161, + 58162, 58163, 58164, 58165, 58166, 58167, 58168, 58169, 58170, 58171, 58172, 58173, 58174, + 58175, 58176, 58177, 58178, 58179, 58180, 58181, 58182, 58183, 58184, 58185, 58186, 58187, + 58188, 58189, 40451, 40452, 40453, 40454, 40455, 40456, 40457, 40458, 40459, 40460, 40461, + 40462, 40463, 40464, 40465, 40466, 40467, 40468, 40469, 40470, 40471, 40472, 40473, 40474, + 40475, 40476, 40477, 40478, 40484, 40487, 40494, 40496, 40500, 40507, 40508, 40512, 40525, + 40528, 40530, 40531, 40532, 40534, 40537, 40541, 40543, 40544, 40545, 40546, 40549, 40558, + 40559, 40562, 40564, 40565, 40566, 40567, 40568, 40569, 40570, 40571, 40572, 40573, 40576, + 40577, 40579, 40580, 40581, 40582, 40585, 40586, 40588, 40589, 40590, 40591, 40592, 40593, + 40596, 40597, 40598, 40599, 40600, 40601, 40602, 40603, 40604, 40606, 40608, 40609, 40610, + 40611, 40612, 40613, 40615, 40616, 40617, 40618, 58190, 58191, 58192, 58193, 58194, 58195, + 58196, 58197, 58198, 58199, 58200, 58201, 58202, 58203, 58204, 58205, 58206, 58207, 58208, + 58209, 58210, 58211, 58212, 58213, 58214, 58215, 58216, 58217, 58218, 58219, 58220, 58221, + 58222, 58223, 58224, 58225, 58226, 58227, 58228, 58229, 58230, 58231, 58232, 58233, 58234, + 58235, 58236, 58237, 58238, 58239, 58240, 58241, 58242, 58243, 58244, 58245, 58246, 58247, + 58248, 58249, 58250, 58251, 58252, 58253, 58254, 58255, 58256, 58257, 58258, 58259, 58260, + 58261, 58262, 58263, 58264, 58265, 58266, 58267, 58268, 58269, 58270, 58271, 58272, 58273, + 58274, 58275, 58276, 58277, 58278, 58279, 58280, 58281, 58282, 58283, 40619, 40620, 40621, + 40622, 40623, 40624, 40625, 40626, 40627, 40629, 40630, 40631, 40633, 40634, 40636, 40639, + 40640, 40641, 40642, 40643, 40645, 40646, 40647, 40648, 40650, 40651, 40652, 40656, 40658, + 40659, 40661, 40662, 40663, 40665, 40666, 40670, 40673, 40675, 40676, 40678, 40680, 40683, + 40684, 40685, 40686, 40688, 40689, 40690, 40691, 40692, 40693, 40694, 40695, 40696, 40698, + 40701, 40703, 40704, 40705, 40706, 40707, 40708, 40709, 40710, 40711, 40712, 40713, 40714, + 40716, 40719, 40721, 40722, 40724, 40725, 40726, 40728, 40730, 40731, 40732, 40733, 40734, + 40735, 40737, 40739, 40740, 40741, 40742, 40743, 40744, 40745, 40746, 40747, 40749, 40750, + 40752, 40753, 58284, 58285, 58286, 58287, 58288, 58289, 58290, 58291, 58292, 58293, 58294, + 58295, 58296, 58297, 58298, 58299, 58300, 58301, 58302, 58303, 58304, 58305, 58306, 58307, + 58308, 58309, 58310, 58311, 58312, 58313, 58314, 58315, 58316, 58317, 58318, 58319, 58320, + 58321, 58322, 58323, 58324, 58325, 58326, 58327, 58328, 58329, 58330, 58331, 58332, 58333, + 58334, 58335, 58336, 58337, 58338, 58339, 58340, 58341, 58342, 58343, 58344, 58345, 58346, + 58347, 58348, 58349, 58350, 58351, 58352, 58353, 58354, 58355, 58356, 58357, 58358, 58359, + 58360, 58361, 58362, 58363, 58364, 58365, 58366, 58367, 58368, 58369, 58370, 58371, 58372, + 58373, 58374, 58375, 58376, 58377, 40754, 40755, 40756, 40757, 40758, 40760, 40762, 40764, + 40767, 40768, 40769, 40770, 40771, 40773, 40774, 40775, 40776, 40777, 40778, 40779, 40780, + 40781, 40782, 40783, 40786, 40787, 40788, 40789, 40790, 40791, 40792, 40793, 40794, 40795, + 40796, 40797, 40798, 40799, 40800, 40801, 40802, 40803, 40804, 40805, 40806, 40807, 40808, + 40809, 40810, 40811, 40812, 40813, 40814, 40815, 40816, 40817, 40818, 40819, 40820, 40821, + 40822, 40823, 40824, 40825, 40826, 40827, 40828, 40829, 40830, 40833, 40834, 40845, 40846, + 40847, 40848, 40849, 40850, 40851, 40852, 40853, 40854, 40855, 40856, 40860, 40861, 40862, + 40865, 40866, 40867, 40868, 40869, 63788, 63865, 63893, 63975, 63985, 58378, 58379, 58380, + 58381, 58382, 58383, 58384, 58385, 58386, 58387, 58388, 58389, 58390, 58391, 58392, 58393, + 58394, 58395, 58396, 58397, 58398, 58399, 58400, 58401, 58402, 58403, 58404, 58405, 58406, + 58407, 58408, 58409, 58410, 58411, 58412, 58413, 58414, 58415, 58416, 58417, 58418, 58419, + 58420, 58421, 58422, 58423, 58424, 58425, 58426, 58427, 58428, 58429, 58430, 58431, 58432, + 58433, 58434, 58435, 58436, 58437, 58438, 58439, 58440, 58441, 58442, 58443, 58444, 58445, + 58446, 58447, 58448, 58449, 58450, 58451, 58452, 58453, 58454, 58455, 58456, 58457, 58458, + 58459, 58460, 58461, 58462, 58463, 58464, 58465, 58466, 58467, 58468, 58469, 58470, 58471, + 64012, 64013, 64014, 64015, 64017, 64019, 64020, 64024, 64031, 64032, 64033, 64035, 64036, + 64039, 64040, 64041, 11905, 59414, 59415, 59416, 11908, 13427, 13383, 11912, 11915, 59422, + 13726, 13850, 13838, 11916, 11927, 14702, 14616, 59430, 14799, 14815, 14963, 14800, 59435, + 59436, 15182, 15470, 15584, 11943, 59441, 59442, 11946, 16470, 16735, 11950, 17207, 11955, + 11958, 11959, 59451, 17329, 17324, 11963, 17373, 17622, 18017, 17996, 59459, 18211, 18217, + 18300, 18317, 11978, 18759, 18810, 18813, 18818, 18819, 18821, 18822, 18847, 18843, 18871, + 18870, 59476, 59477, 19619, 19615, 19616, 19617, 19575, 19618, 19731, 19732, 19733, 19734, + 19735, 19736, 19737, 19886, 59492, 58472, 58473, 58474, 58475, 58476, 58477, 58478, 58479, + 58480, 58481, 58482, 58483, 58484, 58485, 58486, 58487, 58488, 58489, 58490, 58491, 58492, + 58493, 58494, 58495, 58496, 58497, 58498, 58499, 58500, 58501, 58502, 58503, 58504, 58505, + 58506, 58507, 58508, 58509, 58510, 58511, 58512, 58513, 58514, 58515, 58516, 58517, 58518, + 58519, 58520, 58521, 58522, 58523, 58524, 58525, 58526, 58527, 58528, 58529, 58530, 58531, + 58532, 58533, 58534, 58535, 58536, 58537, 58538, 58539, 58540, 58541, 58542, 58543, 58544, + 58545, 58546, 58547, 58548, 58549, 58550, 58551, 58552, 58553, 58554, 58555, 58556, 58557, + 58558, 58559, 58560, 58561, 58562, 58563, 58564, 58565, diff --git a/third_party/ulib/musl/src/locale/hkscs.h b/third_party/ulib/musl/src/locale/hkscs.h new file mode 100644 index 000000000..573892ddf --- /dev/null +++ b/third_party/ulib/musl/src/locale/hkscs.h @@ -0,0 +1,366 @@ +17392, 19506, 17923, 17830, 17784, 29287, 19831, 17843, 31921, 19682, 31941, 15253, 18230, 18244, + 19527, 19520, 17087, 13847, 29522, 28299, 28882, 19543, 41809, 18255, 17882, 19589, 31852, + 19719, 19108, 18081, 27427, 29221, 23124, 6755, 15878, 16225, 26189, 22267, 0, 32149, 22813, + 35769, 15860, 38708, 31727, 23515, 7518, 23204, 13861, 40624, 23249, 23479, 23804, 26478, 34195, + 39237, 29793, 29853, 14453, 7507, 13982, 24609, 16108, 22750, 15093, 31484, 40855, 16737, 35085, + 12778, 2698, 12894, 17162, 33924, 40854, 37935, 18736, 34323, 22678, 38730, 37400, 31184, 31282, + 26208, 27177, 34973, 29772, 31685, 26498, 31276, 21071, 36934, 13542, 29636, 23993, 29894, + 40903, 22451, 18735, 21580, 16689, 13966, 22552, 31346, 31589, 35727, 18094, 28296, 16769, + 23961, 31662, 9404, 40904, 9409, 9417, 9420, 40905, 34052, 13755, 16564, 40906, 17633, 44543, + 25281, 28782, 40907, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12736, 12737, 12738, 12739, 12740, 268, 12741, 209, 205, 12742, 12743, 203, + 8168, 12744, 202, 12745, 12746, 12747, 12748, 270, 12749, 12750, 256, 193, 461, 192, 274, 201, + 282, 200, 332, 211, 465, 210, 56320, 7870, 56324, 7872, 202, 257, 225, 462, 224, 593, 275, 233, + 283, 232, 299, 237, 464, 236, 333, 243, 466, 242, 363, 250, 468, 249, 470, 472, 474, 476, 252, + 56328, 7871, 56332, 7873, 234, 609, 9178, 9179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 41897, 4421, 0, 25866, 0, 0, 20029, 28381, 40270, 37343, 0, 0, 30517, 25745, 20250, + 20264, 20392, 20822, 20852, 20892, 20964, 21153, 21160, 21307, 21326, 21457, 21464, 22242, + 22768, 22788, 22791, 22834, 22836, 23398, 23454, 23455, 23706, 24198, 24635, 25993, 26622, + 26628, 26725, 27982, 28860, 30005, 32420, 32428, 32442, 32455, 32463, 32479, 32518, 32567, + 33402, 33487, 33647, 35270, 35774, 35810, 36710, 36711, 36718, 29713, 31996, 32205, 26950, + 31433, 21031, 0, 0, 0, 0, 37260, 30904, 37214, 32956, 0, 36107, 33014, 2535, 0, 0, 32927, 40647, + 19661, 40393, 40460, 19518, 40438, 28686, 40458, 41267, 13761, 0, 28314, 33342, 29977, 0, 18705, + 39532, 39567, 40857, 31111, 33900, 7626, 1488, 10982, 20004, 20097, 20096, 20103, 20159, 20203, + 20279, 13388, 20413, 15944, 20483, 20616, 13437, 13459, 13477, 20870, 22789, 20955, 20988, + 20997, 20105, 21113, 21136, 21287, 13767, 21417, 13649, 21424, 13651, 21442, 21539, 13677, + 13682, 13953, 21651, 21667, 21684, 21689, 21712, 21743, 21784, 21795, 21800, 13720, 21823, + 13733, 13759, 21975, 13765, 32132, 21797, 0, 3138, 3349, 20779, 21904, 11462, 14828, 833, 36422, + 19896, 38117, 16467, 32958, 30586, 11320, 14900, 18389, 33117, 27122, 19946, 25821, 3452, 4020, + 3285, 4340, 25741, 36478, 3734, 3083, 3940, 11433, 33366, 17619, 0, 3398, 39501, 33001, 18420, + 20135, 11458, 39602, 14951, 38388, 16365, 13574, 21191, 38868, 30920, 11588, 40302, 38933, 0, + 17369, 24741, 25780, 21731, 11596, 11210, 4215, 14843, 4207, 26330, 26390, 31136, 25834, 20562, + 3139, 36456, 8609, 35660, 1841, 0, 18443, 425, 16378, 22643, 11661, 0, 17864, 1276, 24727, 3916, + 3478, 21881, 16571, 17338, 0, 19124, 10854, 4253, 33194, 39157, 3484, 25465, 14846, 10101, + 36288, 22177, 25724, 15939, 0, 42497, 3593, 10959, 11465, 0, 4296, 14786, 14738, 14854, 33435, + 13688, 24137, 8391, 22098, 3889, 11442, 38688, 13500, 27709, 20027, 0, 0, 30068, 11915, 8712, + 42587, 36045, 3706, 3124, 26652, 32659, 4303, 10243, 10553, 13819, 20963, 3724, 3981, 3754, + 16275, 3888, 3399, 4431, 3660, 0, 3755, 2985, 3400, 4288, 4413, 16377, 9878, 25650, 4013, 13300, + 30265, 11214, 3454, 3455, 11345, 11349, 14872, 3736, 4295, 3886, 42546, 27472, 36050, 36249, + 36042, 38314, 21708, 33476, 21945, 0, 40643, 39974, 39606, 30558, 11758, 28992, 33133, 33004, + 23580, 25970, 33076, 14231, 21343, 32957, 37302, 3834, 3599, 3703, 3835, 13789, 19947, 13833, + 3286, 22191, 10165, 4297, 3600, 3704, 4216, 4424, 33287, 5205, 3705, 20048, 11684, 23124, 4125, + 4126, 4341, 4342, 22428, 3601, 30356, 33485, 4021, 3707, 20862, 14083, 4022, 4480, 21208, 41661, + 18906, 6202, 16759, 33404, 22681, 21096, 13850, 22333, 31666, 23400, 18432, 19244, 40743, 18919, + 39967, 39821, 23412, 12605, 22011, 13810, 22153, 20008, 22786, 7105, 63608, 38737, 134, 20059, + 20155, 13630, 23587, 24401, 24516, 14586, 25164, 25909, 27514, 27701, 27706, 28780, 29227, + 20012, 29357, 18665, 32594, 31035, 31993, 32595, 25194, 13505, 0, 25419, 32770, 32896, 26130, + 26961, 21341, 34916, 35265, 30898, 35744, 36125, 38021, 38264, 38271, 38376, 36367, 38886, + 39029, 39118, 39134, 39267, 38928, 40060, 40479, 40644, 27503, 63751, 20023, 135, 38429, 25143, + 38050, 0, 20539, 28158, 40051, 40870, 15817, 34959, 16718, 28791, 23797, 19232, 20941, 13657, + 23856, 24866, 35378, 36775, 37366, 29073, 26393, 29626, 12929, 41223, 15499, 6528, 19216, 30948, + 29698, 20910, 34575, 16393, 27235, 41658, 16931, 34319, 2671, 31274, 39239, 35562, 38741, 28749, + 21284, 8318, 37876, 30425, 35299, 40871, 30685, 20131, 20464, 20668, 20015, 20247, 40872, 21556, + 32139, 22674, 22736, 7606, 24210, 24217, 24514, 10002, 25995, 13305, 26905, 27203, 15459, 27903, + 0, 29184, 17669, 29580, 16091, 18963, 23317, 29881, 35715, 23716, 22165, 31379, 31724, 31939, + 32364, 33528, 34199, 40873, 34960, 40874, 36537, 40875, 36815, 34143, 39392, 37409, 40876, + 36281, 5183, 16497, 17058, 23066, 0, 0, 0, 39016, 26475, 17014, 22333, 0, 34262, 18811, 33471, + 28941, 19585, 28020, 23931, 27413, 28606, 40877, 40878, 23446, 40879, 26343, 32347, 28247, + 31178, 15752, 17603, 12886, 10134, 17306, 17718, 0, 23765, 15130, 35577, 23672, 15634, 13649, + 23928, 40882, 29015, 17752, 16620, 7715, 19575, 14712, 13386, 420, 27713, 35532, 20404, 569, + 22975, 33132, 38998, 39162, 24379, 2975, 0, 8641, 35181, 16642, 18107, 36985, 16135, 40883, + 41397, 16632, 14294, 18167, 27718, 16764, 34482, 29695, 17773, 14548, 21658, 17761, 17691, + 19849, 19579, 19830, 17898, 16328, 19215, 13921, 17630, 17597, 16877, 23870, 23880, 23894, + 15868, 14351, 23972, 23993, 14368, 14392, 24130, 24253, 24357, 24451, 14600, 14612, 14655, + 14669, 24791, 24893, 23781, 14729, 25015, 25017, 25039, 14776, 25132, 25232, 25317, 25368, + 14840, 22193, 14851, 25570, 25595, 25607, 25690, 14923, 25792, 23829, 22049, 40863, 14999, + 25990, 15037, 26111, 26195, 15090, 26258, 15138, 26390, 15170, 26532, 26624, 15192, 26698, + 26756, 15218, 15217, 15227, 26889, 26947, 29276, 26980, 27039, 27013, 15292, 27094, 15325, + 27237, 27252, 27249, 27266, 15340, 27289, 15346, 27307, 27317, 27348, 27382, 27521, 27585, + 27626, 27765, 27818, 15563, 27906, 27910, 27942, 28033, 15599, 28068, 28081, 28181, 28184, + 28201, 28294, 35264, 28347, 28386, 28378, 40831, 28392, 28393, 28452, 28468, 15686, 16193, + 28545, 28606, 15722, 15733, 29111, 23705, 15754, 28716, 15761, 28752, 28756, 28783, 28799, + 28809, 805, 17345, 13809, 3800, 16087, 22462, 28371, 28990, 22496, 13902, 27042, 35817, 23412, + 31305, 22753, 38105, 31333, 31357, 22956, 31419, 31408, 31426, 31427, 29137, 25741, 16842, + 31450, 31453, 31466, 16879, 21682, 23553, 31499, 31573, 31529, 21262, 23806, 31650, 31599, + 33692, 23476, 27775, 31696, 33825, 31634, 0, 23840, 15789, 23653, 33938, 31738, 0, 31797, 23745, + 31812, 31875, 18562, 31910, 26237, 17784, 31945, 31943, 31974, 31860, 31987, 31989, 0, 32359, + 17693, 28228, 32093, 28374, 29837, 32137, 32171, 28981, 32179, 0, 16471, 24617, 32228, 15635, + 32245, 6137, 32229, 33645, 0, 24865, 24922, 32366, 32402, 17195, 37996, 32295, 32576, 32577, + 32583, 31030, 25296, 39393, 32663, 25425, 32675, 5729, 104, 17756, 14182, 17667, 33594, 32762, + 25737, 0, 32776, 32797, 0, 32815, 41095, 27843, 32827, 32828, 32865, 10004, 18825, 26150, 15843, + 26344, 26405, 32935, 35400, 33031, 33050, 22704, 9974, 27775, 25752, 20408, 25831, 5258, 33304, + 6238, 27219, 19045, 19093, 17530, 33321, 2829, 27218, 15742, 20473, 5373, 34018, 33634, 27402, + 18855, 13616, 6003, 15864, 33450, 26907, 63892, 16859, 34123, 33488, 33562, 3606, 6068, 14017, + 12669, 13658, 33403, 33506, 33560, 16011, 28067, 27397, 27543, 13774, 15807, 33565, 21996, + 33669, 17675, 28069, 33708, 0, 33747, 13438, 28372, 27223, 34138, 13462, 28226, 12015, 33880, + 23524, 33905, 15827, 17636, 27303, 33866, 15541, 31064, 0, 27542, 28279, 28227, 34014, 0, 33681, + 17568, 33939, 34020, 23697, 16960, 23744, 17731, 34100, 23282, 28313, 17703, 34163, 17686, + 26559, 34326, 34341, 34363, 34241, 28808, 34306, 5506, 28877, 63922, 17770, 34344, 13896, 6306, + 21495, 29594, 34430, 34673, 41208, 34798, 11303, 34737, 34778, 34831, 22113, 34412, 26710, + 17935, 34885, 34886, 30176, 15801, 30180, 34910, 34972, 18011, 34996, 34997, 25537, 35013, + 30583, 30479, 35207, 35210, 0, 0, 35239, 35260, 35365, 35303, 31012, 31421, 35484, 30611, 37374, + 35472, 31321, 31465, 31546, 16271, 18195, 31544, 29052, 35596, 35615, 21552, 21861, 35647, + 35660, 35661, 35497, 19066, 35728, 35739, 35503, 5855, 17941, 34895, 35995, 32084, 32143, 63956, + 14117, 32083, 36054, 32152, 32189, 36114, 36099, 6416, 36059, 28764, 36113, 19657, 16080, 0, + 36265, 32770, 4116, 18826, 15228, 33212, 28940, 31463, 36525, 36534, 36547, 37588, 36633, 36653, + 33637, 33810, 36773, 37635, 41631, 2640, 36787, 18730, 35294, 34109, 15803, 24312, 12898, 36857, + 40980, 34492, 34049, 8997, 14720, 28375, 36919, 34108, 31422, 36961, 34156, 34315, 37032, 34579, + 37060, 34534, 37038, 0, 37223, 15088, 37289, 37316, 31916, 35123, 7817, 37390, 27807, 37441, + 37474, 21945, 0, 35526, 15515, 35596, 21979, 3377, 37676, 37739, 35553, 35819, 28815, 23235, + 35554, 35557, 18789, 37444, 35820, 35897, 35839, 37747, 37979, 36540, 38277, 38310, 37926, + 38304, 28662, 17081, 9850, 34520, 4732, 15918, 18911, 27676, 38523, 38550, 16748, 38563, 28373, + 25050, 38582, 30965, 35552, 38589, 21452, 18849, 27832, 628, 25616, 37039, 37093, 19153, 6421, + 13066, 38705, 34370, 38710, 18959, 17725, 17797, 19177, 28789, 23361, 38683, 0, 37333, 38743, + 23370, 37355, 38751, 37925, 20688, 12471, 12476, 38793, 38815, 38833, 38846, 38848, 38866, + 38880, 21612, 38894, 29724, 37939, 0, 38901, 37917, 31098, 19153, 38964, 38963, 38987, 39014, + 15118, 29045, 15697, 1584, 16732, 22278, 39114, 39095, 39112, 39111, 19199, 27943, 5843, 21936, + 39137, 39142, 39148, 37752, 39225, 18985, 19314, 38999, 39173, 39413, 39436, 39483, 39440, + 39512, 22309, 14020, 37041, 39893, 39648, 39650, 39685, 39668, 19470, 39700, 39725, 34304, + 20532, 39732, 27048, 14531, 12413, 39760, 39744, 40254, 23109, 6243, 39822, 16971, 39938, 39935, + 39948, 40552, 40404, 40887, 41362, 41387, 41185, 41251, 41439, 40318, 40323, 41268, 40462, + 26760, 40388, 8539, 41363, 41504, 6459, 41523, 40249, 41145, 41652, 40592, 40597, 40606, 40610, + 19764, 40618, 40623, 17252, 40641, 15200, 14821, 15645, 20274, 14270, 35883, 40706, 40712, + 19350, 37924, 28066, 40727, 0, 40761, 22175, 22154, 40773, 39352, 37003, 38898, 33919, 40802, + 40809, 31452, 40846, 29206, 19390, 18805, 18875, 29047, 18936, 17224, 19025, 29598, 35802, 6394, + 31135, 35198, 36406, 37737, 37875, 35396, 37612, 37761, 37835, 35180, 17593, 29207, 16107, + 30578, 31299, 28880, 17523, 17400, 29054, 6127, 28835, 6334, 13721, 16071, 6277, 21551, 6136, + 14114, 5883, 6201, 14049, 6004, 6353, 24395, 14115, 5824, 22363, 18981, 5118, 4776, 5062, 5302, + 34051, 13990, 0, 33877, 18836, 29029, 15921, 21852, 16123, 28754, 17652, 14062, 39325, 28454, + 26617, 14131, 15381, 15847, 22636, 6434, 26640, 16471, 14143, 16609, 16523, 16655, 27681, 21707, + 22174, 26289, 22162, 4063, 2984, 3597, 37830, 35603, 37788, 20216, 20779, 14361, 17462, 20156, + 1125, 895, 20299, 20362, 22097, 23144, 427, 971, 14745, 778, 1044, 13365, 20265, 704, 36531, + 629, 35546, 524, 20120, 20685, 20749, 20386, 20227, 18958, 16010, 20290, 20526, 20588, 20609, + 20428, 20453, 20568, 20732, 0, 0, 0, 0, 28278, 13717, 15929, 16063, 28018, 6276, 16009, 20904, + 20931, 1504, 17629, 1187, 1170, 1169, 36218, 35484, 1806, 21081, 21156, 2163, 21217, 0, 18042, + 29068, 17292, 3104, 18860, 4324, 27089, 3613, 0, 16094, 29849, 29716, 29782, 29592, 19342, + 19132, 16525, 21456, 13700, 29199, 16585, 21940, 837, 21709, 3014, 22301, 37469, 38644, 37734, + 22493, 22413, 22399, 13886, 22731, 23193, 35398, 5882, 5999, 5904, 23084, 22968, 37519, 23166, + 23247, 23058, 22854, 6643, 6241, 17045, 14069, 27909, 29763, 23073, 24195, 23169, 35799, 1043, + 37856, 29836, 4867, 28933, 18802, 37896, 35323, 37821, 14240, 23582, 23710, 24158, 24136, 6550, + 6524, 15086, 24269, 23375, 6403, 6404, 14081, 6304, 14045, 5886, 14035, 33066, 35399, 7610, + 13426, 35240, 24332, 24334, 6439, 6059, 23147, 5947, 23364, 34324, 30205, 34912, 24702, 10336, + 9771, 24539, 16056, 9647, 9662, 37000, 28531, 25024, 62, 70, 9755, 24985, 24984, 24693, 11419, + 11527, 18132, 37197, 25713, 18021, 11114, 14889, 11042, 13392, 39146, 11896, 25399, 42075, + 25782, 25393, 25553, 18915, 11623, 25252, 11425, 25659, 25963, 26994, 15348, 12430, 12973, + 18825, 12971, 21773, 13024, 6361, 37951, 26318, 12937, 12723, 15072, 16784, 21892, 35618, 21903, + 5884, 21851, 21541, 30958, 12547, 6186, 12852, 13412, 12815, 12674, 17097, 26254, 27940, 26219, + 19347, 26160, 30832, 7659, 26211, 13010, 13025, 26142, 22642, 14545, 14394, 14268, 15257, 14242, + 13310, 29904, 15254, 26511, 17962, 26806, 26654, 15300, 27326, 14435, 14293, 17543, 27187, + 27218, 27337, 27397, 6418, 25873, 26776, 27212, 15319, 27258, 27479, 16320, 15514, 37792, 37618, + 35818, 35531, 37513, 32798, 35292, 37991, 28069, 28427, 18924, 0, 16255, 15759, 28164, 16444, + 23101, 28170, 22599, 27940, 30786, 28987, 17178, 17014, 28913, 29264, 29319, 29332, 18319, + 18213, 20857, 19108, 1515, 29818, 16120, 13919, 19018, 18711, 24545, 16134, 16049, 19167, 35875, + 16181, 24743, 16115, 29900, 29756, 37767, 29751, 17567, 28138, 17745, 30083, 16227, 19673, + 19718, 16216, 30037, 30323, 42438, 15129, 29800, 35532, 18859, 18830, 15099, 15821, 19022, + 16127, 18885, 18675, 37370, 22322, 37698, 35555, 6244, 20703, 21025, 20967, 30584, 12850, 30478, + 30479, 30587, 18071, 14209, 14942, 18672, 29752, 29851, 16063, 19130, 19143, 16584, 19094, + 25006, 37639, 21889, 30750, 30861, 30856, 30930, 29648, 31065, 30529, 22243, 16654, 0, 33942, + 31141, 27181, 16122, 31290, 31220, 16750, 5862, 16690, 37429, 31217, 3404, 18828, 665, 15802, + 5998, 13719, 21867, 13680, 13994, 468, 3085, 31458, 23129, 9973, 23215, 23196, 23053, 603, + 30960, 23082, 23494, 31486, 16889, 31837, 31853, 16913, 23475, 24252, 24230, 31949, 18937, 6064, + 31886, 31868, 31918, 27314, 32220, 32263, 32211, 32590, 25185, 24924, 31560, 32151, 24194, + 17002, 27509, 2326, 26582, 78, 13775, 22468, 25618, 25592, 18786, 32733, 31527, 2092, 23273, + 23875, 31500, 24078, 39398, 34373, 39523, 27164, 13375, 14818, 18935, 26029, 39455, 26016, + 33920, 28967, 27857, 17642, 33079, 17410, 32966, 33033, 33090, 26548, 39107, 27202, 33378, + 33381, 27217, 33875, 28071, 34320, 29211, 23174, 16767, 6208, 23339, 6305, 23268, 6360, 34464, + 63932, 15759, 34861, 29730, 23042, 34926, 20293, 34951, 35007, 35046, 35173, 35149, 22147, + 35156, 30597, 30596, 35829, 35801, 35740, 35321, 16045, 33955, 18165, 18127, 14322, 35389, + 35356, 37960, 24397, 37419, 17028, 26068, 28969, 28868, 6213, 40301, 35999, 36073, 32220, 22938, + 30659, 23024, 17262, 14036, 36394, 36519, 19465, 36656, 36682, 17140, 27736, 28603, 8993, 18587, + 28537, 28299, 6106, 39913, 14005, 18735, 37051, 0, 21873, 18694, 37307, 37892, 35403, 16482, + 35580, 37927, 35869, 35899, 34021, 35371, 38297, 38311, 38295, 38294, 36148, 29765, 16066, + 18687, 19010, 17386, 16103, 12837, 38543, 36583, 36454, 36453, 16076, 18925, 19064, 16366, + 29714, 29803, 16124, 38721, 37040, 26695, 18973, 37011, 22495, 0, 37736, 35209, 35878, 35631, + 25534, 37562, 23313, 35689, 18748, 29689, 16923, 38811, 38769, 39224, 3878, 24001, 35781, 19122, + 38943, 38106, 37622, 38359, 37349, 17600, 35664, 19047, 35684, 39132, 35397, 16128, 37418, + 18725, 33812, 39227, 39245, 31494, 15869, 39323, 19311, 39338, 39516, 35685, 22728, 27279, + 39457, 23294, 39471, 39153, 19344, 39240, 39356, 19389, 19351, 37757, 22642, 4866, 22562, 18872, + 5352, 30788, 10015, 15800, 26821, 15741, 37976, 14631, 24912, 10113, 10603, 24839, 40015, 40019, + 40059, 39989, 39952, 39807, 39887, 40493, 39839, 41461, 41214, 40225, 19630, 16644, 40472, + 19632, 40204, 41396, 41197, 41203, 39215, 40357, 33981, 28178, 28639, 27522, 34300, 17715, + 28068, 28292, 28144, 33824, 34286, 28160, 14295, 24676, 31202, 13724, 13888, 18733, 18910, + 15714, 37851, 37566, 37704, 703, 30905, 37495, 37965, 20452, 13376, 36964, 21853, 30781, 30804, + 30902, 30795, 5975, 12745, 18753, 13978, 20338, 28634, 28633, 0, 28702, 21524, 16821, 22459, + 22771, 22410, 40214, 22487, 28980, 13487, 16812, 29163, 27712, 20375, 0, 6069, 35401, 24844, + 23246, 23051, 17084, 17544, 14124, 19323, 35324, 37819, 37816, 6358, 3869, 33906, 27840, 5139, + 17146, 11302, 17345, 22932, 15799, 26433, 32168, 24923, 24740, 18873, 18827, 35322, 37605, + 29666, 16105, 29876, 35683, 6303, 16097, 19123, 27352, 29683, 29691, 16086, 19006, 19092, 6105, + 19046, 935, 5156, 18917, 29768, 18710, 28837, 18806, 37508, 29670, 37727, 1278, 37681, 35534, + 35350, 37766, 35815, 21973, 18741, 35458, 29035, 18755, 3327, 22180, 1562, 3051, 3256, 21762, + 31172, 6138, 32254, 5826, 19024, 6226, 17710, 37889, 14090, 35520, 18861, 22960, 6335, 6275, + 29828, 23201, 14050, 15707, 14000, 37471, 23161, 35457, 6242, 37748, 15565, 2740, 19094, 14730, + 20724, 15721, 15692, 5020, 29045, 17147, 33304, 28175, 37092, 17643, 27991, 32335, 28775, 27823, + 15574, 16365, 15917, 28162, 28428, 15727, 1013, 30033, 14012, 13512, 18048, 16090, 18545, 22980, + 37486, 18750, 36673, 35868, 27584, 22546, 22472, 14038, 5202, 28926, 17250, 19057, 12259, 4784, + 9149, 26809, 26983, 5016, 13541, 31732, 14047, 35459, 14294, 13306, 19615, 27162, 13997, 27831, + 33854, 17631, 17614, 27942, 27985, 27778, 28638, 28439, 28937, 33597, 5946, 33773, 27776, 28755, + 6107, 22921, 23170, 6067, 23137, 23153, 6405, 16892, 14125, 23023, 5948, 14023, 29070, 37776, + 26266, 17061, 23150, 23083, 17043, 27179, 16121, 30518, 17499, 17098, 28957, 16985, 35297, + 20400, 27944, 23746, 17614, 32333, 17341, 27148, 16982, 4868, 28838, 28979, 17385, 15781, 27871, + 63525, 19023, 32357, 23019, 23855, 15859, 24412, 19037, 6111, 32164, 33830, 21637, 15098, 13056, + 532, 22398, 2261, 1561, 16357, 8094, 41654, 28675, 37211, 23920, 29583, 31955, 35417, 37920, + 20424, 32743, 29389, 29456, 31476, 29496, 29497, 22262, 29505, 29512, 16041, 31512, 36972, + 29173, 18674, 29665, 33270, 16074, 30476, 16081, 27810, 22269, 29721, 29726, 29727, 16098, + 16112, 16116, 16122, 29907, 16142, 16211, 30018, 30061, 30066, 30093, 16252, 30152, 30172, + 16320, 30285, 16343, 30324, 16348, 30330, 20316, 29064, 22051, 35200, 22633, 16413, 30531, + 16441, 26465, 16453, 13787, 30616, 16490, 16495, 23646, 30654, 30667, 22770, 30744, 28857, + 30748, 16552, 30777, 30791, 30801, 30822, 33864, 21813, 31027, 26627, 31026, 16643, 16649, + 31121, 31129, 36795, 31238, 36796, 16743, 31377, 16818, 31420, 33401, 16836, 31439, 31451, + 16847, 20001, 31586, 31596, 31611, 31762, 31771, 16992, 17018, 31867, 31900, 17036, 31928, + 17044, 31981, 36755, 28864, 3279, 32207, 32212, 32208, 32253, 32686, 32692, 29343, 17303, 32800, + 32805, 31545, 32814, 32817, 32852, 15820, 22452, 28832, 32951, 33001, 17389, 33036, 29482, + 33038, 33042, 30048, 33044, 17409, 15161, 33110, 33113, 33114, 17427, 22586, 33148, 33156, + 17445, 33171, 17453, 33189, 22511, 33217, 33252, 33364, 17551, 33446, 33398, 33482, 33496, + 33535, 17584, 33623, 38505, 27018, 33797, 28917, 33892, 24803, 33928, 17668, 33982, 34017, + 34040, 34064, 34104, 34130, 17723, 34159, 34160, 34272, 17783, 34418, 34450, 34482, 34543, + 38469, 34699, 17926, 17943, 34990, 35071, 35108, 35143, 35217, 31079, 35369, 35384, 35476, + 35508, 35921, 36052, 36082, 36124, 18328, 22623, 36291, 18413, 20206, 36410, 21976, 22356, + 36465, 22005, 36528, 18487, 36558, 36578, 36580, 36589, 36594, 36791, 36801, 36810, 36812, + 36915, 39364, 18605, 39136, 37395, 18718, 37416, 37464, 37483, 37553, 37550, 37567, 37603, + 37611, 37619, 37620, 37629, 37699, 37764, 37805, 18757, 18769, 40639, 37911, 21249, 37917, + 37933, 37950, 18794, 37972, 38009, 38189, 38306, 18855, 38388, 38451, 18917, 26528, 18980, + 38720, 18997, 38834, 38850, 22100, 19172, 24808, 39097, 19225, 39153, 22596, 39182, 39193, + 20916, 39196, 39223, 39234, 39261, 39266, 19312, 39365, 19357, 39484, 39695, 31363, 39785, + 39809, 39901, 39921, 39924, 19565, 39968, 14191, 7106, 40265, 39994, 40702, 22096, 40339, 40381, + 40384, 40444, 38134, 36790, 40571, 40620, 40625, 40637, 40646, 38108, 40674, 40689, 40696, + 31432, 40772, 148, 695, 928, 26906, 38083, 22956, 1239, 22592, 38081, 14265, 1493, 1557, 1654, + 5818, 22359, 29043, 2754, 2765, 3007, 21610, 63547, 3019, 21662, 3067, 3131, 3155, 3173, 3196, + 24807, 3213, 22138, 3253, 3293, 3309, 3439, 3506, 3528, 26965, 39983, 34725, 3588, 3598, 3799, + 3984, 3885, 3699, 23584, 4028, 24075, 4188, 4175, 4214, 26398, 4219, 4232, 4246, 13895, 4287, + 4307, 4399, 4411, 21348, 33965, 4835, 4981, 4918, 35713, 5495, 5657, 6083, 6087, 20088, 28859, + 6189, 6506, 6701, 6725, 7210, 7280, 7340, 7880, 25283, 7893, 7957, 29080, 26709, 8261, 27113, + 14024, 8828, 9175, 9210, 10026, 10353, 10575, 33533, 10599, 10643, 10965, 35237, 10984, 36768, + 11022, 38840, 11071, 38983, 39613, 11340, 0, 11400, 11447, 23528, 11528, 11538, 11703, 11669, + 11842, 12148, 12236, 12339, 12390, 13087, 13278, 24497, 26184, 26303, 31353, 13671, 13811, 0, + 18874, 0, 13850, 14102, 0, 838, 22709, 26382, 26904, 15015, 30295, 24546, 15889, 16057, 30206, + 8346, 18640, 19128, 16665, 35482, 17134, 17165, 16443, 17204, 17302, 19013, 1482, 20946, 1553, + 22943, 7848, 15294, 15615, 17412, 17622, 22408, 18036, 14747, 18223, 34280, 39369, 14178, 8643, + 35678, 35662, 0, 18450, 18683, 18965, 29193, 19136, 3192, 22885, 20133, 20358, 1913, 36570, + 20524, 21135, 22335, 29041, 21145, 21529, 16202, 19111, 21948, 21574, 21614, 27474, 0, 13427, + 21823, 30258, 21854, 18200, 21858, 21862, 22471, 18751, 22621, 20582, 13563, 13260, 0, 22787, + 18300, 35144, 23214, 23433, 23558, 7568, 22433, 29009, 0, 24834, 31762, 36950, 25010, 20378, + 35682, 25602, 25674, 23899, 27639, 0, 25732, 6428, 35562, 18934, 25736, 16367, 25874, 19392, + 26047, 26293, 10011, 37989, 22497, 24981, 23079, 63693, 0, 22201, 17697, 26364, 20074, 18740, + 38486, 28047, 27837, 13848, 35191, 26521, 26734, 25617, 26718, 0, 26823, 31554, 37056, 2577, + 26918, 0, 26937, 31301, 0, 27130, 39462, 27181, 13919, 25705, 33, 31107, 27188, 27483, 23852, + 13593, 0, 27549, 18128, 27812, 30011, 34917, 28078, 22710, 14108, 9613, 28747, 29133, 15444, + 29312, 29317, 37505, 8570, 29323, 37680, 29414, 18896, 27705, 38047, 29776, 3832, 34855, 35061, + 10534, 33907, 6065, 28344, 18986, 6176, 14756, 14009, 0, 0, 17727, 26294, 40109, 39076, 35139, + 30668, 30808, 22230, 16607, 5642, 14753, 14127, 33000, 5061, 29101, 33638, 31197, 37288, 0, + 19639, 28847, 35243, 31229, 31242, 31499, 32102, 16762, 31555, 31102, 32777, 28597, 41695, + 27139, 33560, 21410, 28167, 37823, 26678, 38749, 33135, 32803, 27061, 5101, 12847, 32840, 23941, + 35888, 32899, 22293, 38947, 35145, 23979, 18824, 26046, 27093, 21458, 19109, 16257, 15377, + 26422, 32912, 33012, 33070, 8097, 33103, 33161, 33199, 33306, 33542, 33583, 33674, 13770, 33896, + 34474, 18682, 25574, 35158, 30728, 37461, 35256, 17394, 35303, 17375, 35304, 35654, 35796, + 23032, 35849, 0, 36805, 37100, 0, 37136, 37180, 15863, 37214, 19146, 36816, 29327, 22155, 38119, + 38377, 38320, 38328, 38706, 39121, 39241, 39274, 39363, 39464, 39694, 40282, 40347, 32415, + 40696, 40739, 19620, 38215, 41619, 29090, 41727, 19857, 36882, 42443, 19868, 3228, 36798, 21953, + 36794, 9392, 36793, 19091, 17673, 32383, 28502, 27313, 20202, 13540, 35628, 30877, 14138, 36480, + 6133, 32804, 35692, 35737, 31294, 26287, 15851, 30293, 15543, 22069, 22870, 20122, 24193, 25176, + 22207, 3693, 36366, 23405, 16008, 19614, 25566, 0, 6134, 6267, 25904, 22061, 23626, 21530, + 21265, 15814, 40344, 19581, 22050, 22046, 32585, 24280, 22901, 15680, 34672, 19996, 4074, 3401, + 14010, 33047, 40286, 36120, 30267, 40005, 30286, 30649, 37701, 21554, 33096, 33527, 22053, + 33074, 33816, 32957, 21994, 31074, 22083, 21526, 3741, 13774, 22021, 22001, 26353, 33506, 13869, + 30004, 22000, 21946, 21655, 21874, 3137, 3222, 24272, 20808, 3702, 11362, 3746, 40619, 32090, + 21982, 4213, 25245, 38765, 21652, 36045, 29174, 37238, 25596, 25529, 25598, 21865, 11075, 40050, + 11955, 20890, 13535, 3495, 20903, 21581, 21790, 21779, 30310, 36397, 26762, 30129, 32950, 34820, + 34694, 35015, 33206, 33820, 4289, 17644, 29444, 18182, 23440, 33547, 26771, 22139, 9972, 32047, + 16803, 32115, 28368, 29366, 37232, 4569, 37384, 15612, 42665, 3756, 3833, 29286, 7330, 18254, + 20418, 32761, 4075, 16634, 40029, 25887, 11680, 18675, 18400, 40316, 4076, 3594, 0, 30115, 4077, + 0, 24648, 4487, 29091, 32398, 40272, 19994, 19972, 13687, 23309, 27826, 21351, 13996, 14812, + 21373, 13989, 17944, 22682, 19310, 33325, 21579, 22442, 23189, 2425, 0, 14930, 9317, 29556, + 40620, 19721, 39917, 15614, 40752, 19547, 20393, 38302, 40926, 33884, 15798, 29362, 26547, + 14112, 25390, 32037, 16119, 15916, 14890, 36872, 21196, 15988, 13946, 17897, 1166, 30272, 23280, + 3766, 30842, 32558, 22695, 16575, 22140, 39819, 23924, 30292, 42036, 40581, 19681, 0, 14331, + 24857, 12506, 17394, 0, 22109, 4777, 22439, 18787, 40454, 21044, 28846, 13741, 0, 40316, 31830, + 39737, 22494, 5996, 23635, 25811, 38096, 25397, 29028, 34477, 3368, 27938, 19170, 3441, 0, + 20990, 7951, 23950, 38659, 7633, 40577, 36940, 31519, 39682, 23761, 31651, 25192, 25397, 39679, + 31695, 39722, 31870, 0, 31810, 31878, 39957, 31740, 39689, 0, 39963, 18750, 40794, 21875, 23491, + 20477, 40600, 20466, 21088, 15878, 21201, 22375, 20566, 22967, 24082, 38856, 40363, 36700, + 21609, 38836, 39232, 38842, 21292, 24880, 26924, 21466, 39946, 40194, 19515, 38465, 27008, + 20646, 30022, 5997, 39386, 21107, 0, 37209, 38529, 37212, 0, 37201, 36503, 25471, 27939, 27338, + 22033, 37262, 30074, 25221, 1020, 29519, 31856, 23585, 15613, 0, 18713, 30422, 39837, 20010, + 3284, 33726, 34882, 0, 23626, 27072, 0, 22394, 21023, 24053, 20174, 27697, 498, 20281, 21660, + 21722, 21146, 36226, 13822, 0, 13811, 0, 27474, 37244, 40869, 39831, 38958, 39092, 39610, 40616, + 40580, 29050, 31508, 0, 27642, 34840, 32632, 0, 22048, 42570, 36471, 40787, 0, 36308, 36431, + 40476, 36353, 25218, 33661, 36392, 36469, 31443, 19063, 31294, 30936, 27882, 35431, 30215, + 35418, 40742, 27854, 34774, 30147, 41650, 30803, 63552, 36108, 29410, 29553, 35629, 29442, + 29937, 36075, 19131, 34351, 24506, 34976, 17591, 0, 6203, 28165, 0, 35454, 9499, 0, 24829, + 30311, 39639, 40260, 37742, 39823, 34805, 0, 0, 36087, 29484, 38689, 39856, 13782, 29362, 19463, + 31825, 39242, 24921, 24921, 19460, 40598, 24957, 0, 22367, 24943, 25254, 25145, 0, 14940, 25058, + 21418, 13301, 25444, 26626, 13778, 23895, 35778, 36826, 36409, 0, 20697, 7494, 30982, 21298, + 38456, 3899, 16485, 0, 30718, 0, 31938, 24346, 31962, 31277, 32870, 32867, 32077, 29957, 29938, + 35220, 33306, 26380, 32866, 29830, 32859, 29936, 33027, 30500, 35209, 26572, 30035, 28369, + 34729, 34766, 33224, 34700, 35401, 36013, 35651, 30507, 29944, 34010, 13877, 27058, 36262, 0, + 35241, 0, 28089, 34753, 16401, 29927, 15835, 29046, 24740, 24988, 15569, 0, 24695, 0, 32625, + 35629, 0, 24809, 19326, 21024, 15384, 15559, 24279, 30294, 21809, 6468, 4862, 39171, 28124, + 28845, 23745, 25005, 35343, 13943, 238, 26694, 20238, 17762, 23327, 25420, 40784, 40614, 25195, + 1351, 37595, 1503, 16325, 34124, 17077, 29679, 20917, 13897, 18754, 35300, 37700, 6619, 33518, + 15560, 30780, 26436, 25311, 18739, 35242, 672, 27571, 4869, 20395, 9453, 20488, 27945, 31364, + 13824, 19121, 9491, 0, 894, 24484, 896, 839, 28379, 1055, 0, 20737, 13434, 20750, 39020, 14147, + 33814, 18852, 1159, 20832, 13236, 20842, 3071, 8444, 741, 9520, 1422, 12851, 6531, 23426, 34685, + 1459, 15513, 20914, 20920, 40244, 20937, 20943, 20945, 15580, 20947, 19110, 20915, 20962, 21314, + 20973, 33741, 26942, 14125, 24443, 21003, 21030, 21052, 21173, 21079, 21140, 21177, 21189, + 31765, 34114, 21216, 34317, 27411, 0, 35550, 21833, 28377, 16256, 2388, 16364, 21299, 0, 3042, + 27851, 5926, 26651, 29653, 24650, 16042, 14540, 5864, 29149, 17570, 21357, 21364, 34475, 21374, + 0, 5526, 5651, 30694, 21395, 35483, 21408, 21419, 21422, 29607, 22386, 16217, 29596, 21441, + 21445, 27721, 20041, 22526, 21465, 15019, 2959, 21472, 16363, 11683, 21494, 3191, 21523, 28793, + 21803, 26199, 27995, 21613, 27475, 3444, 21853, 21647, 21668, 18342, 5901, 3805, 15796, 3405, + 35260, 9880, 21831, 19693, 21551, 29719, 21894, 21929, 0, 6359, 16442, 17746, 17461, 26291, + 4276, 22071, 26317, 12938, 26276, 26285, 22093, 22095, 30961, 22257, 38791, 21502, 22272, 22255, + 22253, 35686, 13859, 4687, 22342, 16805, 27758, 28811, 22338, 14001, 27774, 22502, 5142, 22531, + 5204, 17251, 22566, 19445, 22620, 22698, 13665, 22752, 22748, 4668, 22779, 23551, 22339, 41296, + 17016, 37843, 13729, 22815, 26790, 14019, 28249, 5694, 23076, 21843, 5778, 34053, 22985, 3406, + 27777, 27946, 6108, 23001, 6139, 6066, 28070, 28017, 6184, 5845, 23033, 28229, 23211, 23139, + 14054, 18857, 0, 14088, 23190, 29797, 23251, 28577, 9556, 15749, 6417, 14130, 5816, 24195, + 21200, 23414, 25992, 23420, 31246, 16388, 18525, 516, 23509, 24928, 6708, 22988, 1445, 23539, + 23453, 19728, 23557, 6980, 23571, 29646, 23572, 7333, 27432, 23625, 18653, 23685, 23785, 23791, + 23947, 7673, 7735, 23824, 23832, 23878, 7844, 23738, 24023, 33532, 14381, 18689, 8265, 8563, + 33415, 14390, 15298, 24110, 27274, 0, 24186, 17596, 3283, 21414, 20151, 0, 21416, 6001, 24073, + 24308, 33922, 24313, 24315, 14496, 24316, 26686, 37915, 24333, 449, 63636, 15070, 18606, 4922, + 24378, 26760, 9168, 0, 9329, 24419, 38845, 28270, 24434, 37696, 35382, 24487, 23990, 15711, + 21072, 8042, 28920, 9832, 37334, 670, 35369, 24625, 26245, 6263, 14691, 15815, 13881, 22416, + 10164, 31089, 15936, 24734, 0, 24755, 18818, 18831, 31315, 29860, 20705, 23200, 24932, 33828, + 24898, 63654, 28370, 24961, 20980, 1622, 24967, 23466, 16311, 10335, 25043, 35741, 39261, 25040, + 14642, 10624, 10433, 24611, 24924, 25886, 25483, 280, 25285, 6000, 25301, 11789, 25452, 18911, + 14871, 25656, 25592, 5006, 6140, 0, 28554, 11830, 38932, 16524, 22301, 25825, 25829, 38011, + 14950, 25658, 14935, 25933, 28438, 18984, 18979, 25989, 25965, 25951, 12414, 26037, 18752, + 19255, 26065, 16600, 6185, 26080, 26083, 24543, 13312, 26136, 12791, 12792, 26180, 12708, 12709, + 26187, 3701, 26215, 20966, 26227, 0, 7741, 12849, 34292, 12744, 21267, 30661, 10487, 39332, + 26370, 17308, 18977, 15147, 27130, 14274, 0, 26471, 26466, 16845, 37101, 26583, 17641, 26658, + 28240, 37436, 26625, 13286, 28064, 26717, 13423, 27105, 27147, 35551, 26995, 26819, 13773, + 26881, 26880, 15666, 14849, 13884, 15232, 26540, 26977, 35402, 17148, 26934, 27032, 15265, 969, + 33635, 20624, 27129, 13913, 8490, 27205, 14083, 27293, 15347, 26545, 27336, 37276, 15373, 27421, + 2339, 24798, 27445, 27508, 10189, 28341, 15067, 949, 6488, 14144, 21537, 15194, 27617, 16124, + 27612, 27703, 9355, 18673, 27473, 27738, 33318, 27769, 15804, 17605, 15805, 16804, 18700, 18688, + 15561, 14053, 15595, 3378, 39811, 12793, 9361, 32655, 26679, 27941, 28065, 28139, 28054, 27996, + 28284, 28420, 18815, 16517, 28274, 34099, 28532, 20935, 0, 0, 33838, 35617, 0, 15919, 29779, + 16258, 31180, 28239, 23185, 12363, 28664, 14093, 28573, 15920, 28410, 5271, 16445, 17749, 37872, + 28484, 28508, 15694, 28532, 37232, 15675, 28575, 16708, 28627, 16529, 16725, 16441, 16368, + 16308, 16703, 20959, 16726, 16727, 16704, 25053, 28747, 28798, 28839, 28801, 28876, 28885, + 28886, 28895, 16644, 15848, 29108, 29078, 17015, 28971, 28997, 23176, 29002, 0, 23708, 17253, + 29007, 37730, 17089, 28972, 17498, 18983, 18978, 29114, 35816, 28861, 29198, 37954, 29205, + 22801, 37955, 29220, 37697, 22021, 29230, 29248, 18804, 26813, 29269, 29271, 15957, 12356, + 26637, 28477, 29314, 0, 29483, 18467, 34859, 18669, 34820, 29480, 29486, 29647, 29610, 3130, + 27182, 29641, 29769, 16866, 5863, 18980, 26147, 14021, 18871, 18829, 18939, 29687, 29717, 26883, + 18982, 29753, 1475, 16087, 0, 10413, 29792, 36530, 29767, 29668, 29814, 33721, 29804, 14128, + 29812, 37873, 27180, 29826, 18771, 19084, 16735, 19065, 35727, 23366, 35843, 6302, 29896, 6536, + 29966, 0, 29982, 36569, 6731, 23511, 36524, 37765, 30029, 30026, 30055, 30062, 20354, 16132, + 19731, 30094, 29789, 30110, 30132, 30210, 30252, 30289, 30287, 30319, 30326, 25589, 30352, + 33263, 14328, 26897, 26894, 30369, 30373, 30391, 30412, 28575, 33890, 20637, 20861, 7708, 30494, + 30502, 30528, 25775, 21024, 30552, 12972, 30639, 35172, 35176, 5825, 30708, 0, 4982, 18962, + 26826, 30895, 30919, 30931, 38565, 31022, 21984, 30935, 31028, 30897, 30220, 36792, 34948, + 35627, 24707, 9756, 31110, 35072, 26882, 31104, 22615, 31133, 31545, 31036, 31145, 28202, 28966, + 16040, 31174, 37133, 31188, 1312, 17503, 21007, 47234, 248, 16384, 43296, 1102, 0, 0, 2868, 1, + 0, 0, 0, 0, 0, 0, 0, 3072, 64, 0, 0, 0, 1024, 88, 60, 0, 0, 23680, 56493, 48115, 17353, 60910, + 4004, 49446, 30363, 61426, 64478, 63482, 12815, 44868, 61438, 65277, 24593, 176, 8448, 33049, + 4128, 43144, 8544, 9321, 17408, 50313, 0, 16387, 53, 33859, 20785, 26771, 514, 0, 0, 0, 0, 0, + 16384, 256, 44160, 33380, 35904, 37025, 20484, 54368, 53760, 6186, 26781, 38709, 55375, 8440, + 33476, 10268, 30082, 660, 16440, 41376, 4293, 19825, 3524, 47512, 23390, 17153, 39327, 30723, + 57888, 2079, 393, 16585, 775, 39437, 21136, 20433, 892, 8450, 49184, 4974, 46467, 62939, 30693, + 20368, 39447, 5942, 12, 47726, 12041, 21600, 7680, 26744, 28706, 40534, 62245, 46990, 2839, + 59119, 6007, 7003, 4289, 36248, 6162, 53174, 12545, 6770, 11355, 49334, 57888, 23747, 7042, + 56032, 34254, 16598, 21673, 53259, 18447, 16452, 2320, 16596, 15278, 7780, 11076, 2071, 33414, + 6198, 35232, 40167, 2139, 900, 55810, 60560, 34779, 49029, 44450, 36509, 39069, 9504, 70, 40774, + 58239, 51669, 62596, 19926, 58118, 6326, 2322, 0, 1024, 0, 32, 0, 512, 0, 0, 0, 0, 8192, 0, 0, + 0, 0, 0, 0, 8, 36352, 28280, 16223, 56702, 63293, 39932, 44796, 65490, 27535, 59377, 47807, + 28334, 61207, 42972, 46654, 30645, 37577, 42455, 19126, 39790, 33209, 26445, 21758, 39921, + 65122, 21103, 14039, 49150, 17705, 63873, 26045, 17062, 57, 16896, 36704, 37888, 16448, 45010, + 53719, 219, 39072, 31666, 20998, 38944, 51222, 2365, 0, 1, 0, 2561, 2226, 128, 0, 34820, 5152, + 19472, 0, 4, 17569, 16, 321, 2048, 61504, 20447, 22582, 62961, 32949, 26613, 16512, 20480, + 16718, 33992, 23040, 55392, 11009, 20481, 5793, 16580, 28402, 44049, 14624, 49348, 1800, 2316, + 38552, 39876, 7184, 27800, 10886, 422, 4422, 58733, 50379, 37568, 8464, 4630, 29341, 27124, + 5902, 41514, 62593, 123, 41992, 36875, 11280, 14796, 330, 5872, 2571, 3136, 59933, 17420, 17678, + 2, diff --git a/third_party/ulib/musl/src/locale/iconv.c b/third_party/ulib/musl/src/locale/iconv.c new file mode 100644 index 000000000..caf15503f --- /dev/null +++ b/third_party/ulib/musl/src/locale/iconv.c @@ -0,0 +1,461 @@ +#include "locale_impl.h" +#include +#include +#include +#include +#include +#include +#include + +#define UTF_32BE 0300 +#define UTF_16LE 0301 +#define UTF_16BE 0302 +#define UTF_32LE 0303 +#define UCS2BE 0304 +#define UCS2LE 0305 +#define WCHAR_T 0306 +#define US_ASCII 0307 +#define UTF_8 0310 +#define EUC_JP 0320 +#define SHIFT_JIS 0321 +#define GB18030 0330 +#define GBK 0331 +#define GB2312 0332 +#define BIG5 0340 +#define EUC_KR 0350 + +/* Definitions of charmaps. Each charmap consists of: + * 1. Empty-string-terminated list of null-terminated aliases. + * 2. Special type code or number of elided entries. + * 3. Character table (size determined by field 2). */ + +static const unsigned char charmaps[] = "utf8\0char\0\0\310" + "wchart\0\0\306" + "ucs2\0ucs2be\0\0\304" + "ucs2le\0\0\305" + "utf16\0utf16be\0\0\302" + "utf16le\0\0\301" + "ucs4\0ucs4be\0utf32\0utf32be\0\0\300" + "ucs4le\0utf32le\0\0\303" + "ascii\0usascii\0iso646\0iso646us\0\0\307" + "eucjp\0\0\320" + "shiftjis\0sjis\0\0\321" + "gb18030\0\0\330" + "gbk\0\0\331" + "gb2312\0\0\332" + "big5\0bigfive\0cp950\0big5hkscs\0\0\340" + "euckr\0ksc5601\0ksx1001\0cp949\0\0\350" +#include "codepages.h" + ; + +static const unsigned short legacy_chars[] = { +#include "legacychars.h" +}; + +static const unsigned short jis0208[84][94] = { +#include "jis0208.h" +}; + +static const unsigned short gb18030[126][190] = { +#include "gb18030.h" +}; + +static const unsigned short big5[89][157] = { +#include "big5.h" +}; + +static const unsigned short hkscs[] = { +#include "hkscs.h" +}; + +static const unsigned short ksc[93][94] = { +#include "ksc.h" +}; + +static int fuzzycmp(const unsigned char* a, const unsigned char* b) { + for (; *a && *b; a++, b++) { + while (*a && (*a | 32U) - 'a' > 26 && *a - '0' > 10U) + a++; + if ((*a | 32U) != *b) return 1; + } + return *a != *b; +} + +static size_t find_charmap(const void* name) { + const unsigned char* s; + if (!*(char*)name) name = charmaps; /* "utf8" */ + for (s = charmaps; *s;) { + if (!fuzzycmp(name, s)) { + for (; *s; s += strlen((void*)s) + 1) + ; + return s + 1 - charmaps; + } + s += strlen((void*)s) + 1; + if (!*s) { + if (s[1] > 0200) + s += 2; + else + s += 2 + (128U - s[1]) / 4 * 5; + } + } + return -1; +} + +iconv_t iconv_open(const char* to, const char* from) { + size_t f, t; + + if ((t = find_charmap(to)) == -1 || (f = find_charmap(from)) == -1 || (charmaps[t] >= 0320)) { + errno = EINVAL; + return (iconv_t)-1; + } + + return (void*)(f << 16 | t); +} + +int iconv_close(iconv_t cd) { + return 0; +} + +static unsigned get_16(const unsigned char* s, int e) { + e &= 1; + return s[e] << 8 | s[1 - e]; +} + +static void put_16(unsigned char* s, unsigned c, int e) { + e &= 1; + s[e] = c >> 8; + s[1 - e] = c; +} + +static unsigned get_32(const unsigned char* s, int e) { + e &= 3; + return s[e] + 0U << 24 | s[e ^ 1] << 16 | s[e ^ 2] << 8 | s[e ^ 3]; +} + +static void put_32(unsigned char* s, unsigned c, int e) { + e &= 3; + s[e ^ 0] = c >> 24; + s[e ^ 1] = c >> 16; + s[e ^ 2] = c >> 8; + s[e ^ 3] = c; +} + +/* Adapt as needed */ +#define mbrtowc_utf8 mbrtowc +#define wctomb_utf8 wctomb + +size_t iconv(iconv_t cd0, char** restrict in, size_t* restrict inb, char** restrict out, + size_t* restrict outb) { + size_t x = 0; + unsigned long cd = (unsigned long)cd0; + unsigned to = cd & 0xffff; + unsigned from = cd >> 16; + const unsigned char* map = charmaps + from + 1; + const unsigned char* tomap = charmaps + to + 1; + mbstate_t st = {0}; + wchar_t wc; + unsigned c, d; + size_t k, l; + int err; + unsigned char type = map[-1]; + unsigned char totype = tomap[-1]; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + if (!in || !*in || !*inb) return 0; + + *ploc = UTF8_LOCALE; + + for (; *inb; *in += l, *inb -= l) { + c = *(unsigned char*)*in; + l = 1; + + if (c >= 128 || type - UTF_32BE < 7U) switch (type) { + case UTF_8: + l = mbrtowc_utf8(&wc, *in, *inb, &st); + if (!l) + l++; + else if (l == (size_t)-1) + goto ilseq; + else if (l == (size_t)-2) + goto starved; + c = wc; + break; + case US_ASCII: + goto ilseq; + case WCHAR_T: + l = sizeof(wchar_t); + if (*inb < l) goto starved; + c = *(wchar_t*)*in; + if (0) { + case UTF_32BE: + case UTF_32LE: + l = 4; + if (*inb < 4) goto starved; + c = get_32((void*)*in, type); + } + if (c - 0xd800u < 0x800u || c >= 0x110000u) goto ilseq; + break; + case UCS2BE: + case UCS2LE: + case UTF_16BE: + case UTF_16LE: + l = 2; + if (*inb < 2) goto starved; + c = get_16((void*)*in, type); + if ((unsigned)(c - 0xdc00) < 0x400) goto ilseq; + if ((unsigned)(c - 0xd800) < 0x400) { + if (type - UCS2BE < 2U) goto ilseq; + l = 4; + if (*inb < 4) goto starved; + d = get_16((void*)(*in + 2), type); + if ((unsigned)(d - 0xdc00) >= 0x400) goto ilseq; + c = ((c - 0xd7c0) << 10) + (d - 0xdc00); + } + break; + case SHIFT_JIS: + if (c - 0xa1 <= 0xdf - 0xa1) { + c += 0xff61 - 0xa1; + break; + } + l = 2; + if (*inb < 2) goto starved; + d = *((unsigned char*)*in + 1); + if (c - 129 <= 159 - 129) + c -= 129; + else if (c - 224 <= 239 - 224) + c -= 193; + else + goto ilseq; + c *= 2; + if (d - 64 <= 158 - 64) { + if (d == 127) goto ilseq; + if (d > 127) d--; + d -= 64; + } else if (d - 159 <= 252 - 159) { + c++; + d -= 159; + } + c = jis0208[c][d]; + if (!c) goto ilseq; + break; + case EUC_JP: + l = 2; + if (*inb < 2) goto starved; + d = *((unsigned char*)*in + 1); + if (c == 0x8e) { + c = d; + if (c - 0xa1 > 0xdf - 0xa1) goto ilseq; + c += 0xff61 - 0xa1; + break; + } + c -= 0xa1; + d -= 0xa1; + if (c >= 84 || d >= 94) goto ilseq; + c = jis0208[c][d]; + if (!c) goto ilseq; + break; + case GB2312: + if (c < 0xa1) goto ilseq; + case GBK: + case GB18030: + c -= 0x81; + if (c >= 126) goto ilseq; + l = 2; + if (*inb < 2) goto starved; + d = *((unsigned char*)*in + 1); + if (d < 0xa1 && type == GB2312) goto ilseq; + if (d - 0x40 >= 191 || d == 127) { + if (d - '0' > 9 || type != GB18030) goto ilseq; + l = 4; + if (*inb < 4) goto starved; + c = (10 * c + d - '0') * 1260; + d = *((unsigned char*)*in + 2); + if (d - 0x81 > 126) goto ilseq; + c += 10 * (d - 0x81); + d = *((unsigned char*)*in + 3); + if (d - '0' > 9) goto ilseq; + c += d - '0'; + c += 128; + for (d = 0; d <= c;) { + k = 0; + for (int i = 0; i < 126; i++) + for (int j = 0; j < 190; j++) + if (gb18030[i][j] - d <= c - d) k++; + d = c + 1; + c += k; + } + break; + } + d -= 0x40; + if (d > 63) d--; + c = gb18030[c][d]; + break; + case BIG5: + l = 2; + if (*inb < 2) goto starved; + d = *((unsigned char*)*in + 1); + if (d - 0x40 >= 0xff - 0x40 || d - 0x7f < 0xa1 - 0x7f) goto ilseq; + d -= 0x40; + if (d > 0x3e) d -= 0x22; + if (c - 0xa1 >= 0xfa - 0xa1) { + if (c - 0x87 >= 0xff - 0x87) goto ilseq; + if (c < 0xa1) + c -= 0x87; + else + c -= 0x87 + (0xfa - 0xa1); + c = (hkscs[4867 + (c * 157 + d) / 16] >> (c * 157 + d) % 16) % 2 << 17 | + hkscs[c * 157 + d]; + /* A few HKSCS characters map to pairs of UCS + * characters. These are mapped to surrogate + * range in the hkscs table then hard-coded + * here. Ugly, yes. */ + if (c / 256 == 0xdc) { + if (totype - 0300U > 8) + k = 2; + else + k = "\10\4\4\10\4\4\10\2\4"[totype - 0300]; + if (k > *outb) goto toobig; + x += iconv((iconv_t)(uintptr_t)to, &(char*){"\303\212\314\204" + "\303\212\314\214" + "\303\252\314\204" + "\303\252\314\214" + + c % 256}, + &(size_t){4}, out, outb); + continue; + } + if (!c) goto ilseq; + break; + } + c -= 0xa1; + c = big5[c][d] | (c == 0x27 && (d == 0x3a || d == 0x3c || d == 0x42)) << 17; + if (!c) goto ilseq; + break; + case EUC_KR: + l = 2; + if (*inb < 2) goto starved; + d = *((unsigned char*)*in + 1); + c -= 0xa1; + d -= 0xa1; + if (c >= 93 || d >= 94) { + c += (0xa1 - 0x81); + d += 0xa1; + if (c >= 93 || c >= 0xc6 - 0x81 && d > 0x52) goto ilseq; + if (d - 'A' < 26) + d = d - 'A'; + else if (d - 'a' < 26) + d = d - 'a' + 26; + else if (d - 0x81 < 0xff - 0x81) + d = d - 0x81 + 52; + else + goto ilseq; + if (c < 0x20) + c = 178 * c + d; + else + c = 178 * 0x20 + 84 * (c - 0x20) + d; + c += 0xac00; + for (d = 0xac00; d <= c;) { + k = 0; + for (int i = 0; i < 93; i++) + for (int j = 0; j < 94; j++) + if (ksc[i][j] - d <= c - d) k++; + d = c + 1; + c += k; + } + break; + } + c = ksc[c][d]; + if (!c) goto ilseq; + break; + default: + if (c < 128 + type) break; + c -= 128 + type; + c = legacy_chars[map[c * 5 / 4] >> 2 * c % 8 | + map[c * 5 / 4 + 1] << 8 - 2 * c % 8 & 1023]; + if (!c) c = *(unsigned char*)*in; + if (c == 1) goto ilseq; + } + + switch (totype) { + case WCHAR_T: + if (*outb < sizeof(wchar_t)) goto toobig; + *(wchar_t*)*out = c; + *out += sizeof(wchar_t); + *outb -= sizeof(wchar_t); + break; + case UTF_8: + if (*outb < 4) { + char tmp[4]; + k = wctomb_utf8(tmp, c); + if (*outb < k) goto toobig; + memcpy(*out, tmp, k); + } else + k = wctomb_utf8(*out, c); + *out += k; + *outb -= k; + break; + case US_ASCII: + if (c > 0x7f) subst: + x++, c = '*'; + default: + if (*outb < 1) goto toobig; + if (c < 128 + totype) { + revout: + *(*out)++ = c; + *outb -= 1; + break; + } + d = c; + for (c = 0; c < 128 - totype; c++) { + if (d == legacy_chars[tomap[c * 5 / 4] >> 2 * c % 8 | + tomap[c * 5 / 4 + 1] << 8 - 2 * c % 8 & 1023]) { + c += 128; + goto revout; + } + } + goto subst; + case UCS2BE: + case UCS2LE: + case UTF_16BE: + case UTF_16LE: + if (c < 0x10000 || type - UCS2BE < 2U) { + if (c >= 0x10000) c = 0xFFFD; + if (*outb < 2) goto toobig; + put_16((void*)*out, c, totype); + *out += 2; + *outb -= 2; + break; + } + if (*outb < 4) goto toobig; + c -= 0x10000; + put_16((void*)*out, (c >> 10) | 0xd800, totype); + put_16((void*)(*out + 2), (c & 0x3ff) | 0xdc00, totype); + *out += 4; + *outb -= 4; + break; + case UTF_32BE: + case UTF_32LE: + if (*outb < 4) goto toobig; + put_32((void*)*out, c, totype); + *out += 4; + *outb -= 4; + break; + } + } + *ploc = loc; + return x; +ilseq: + err = EILSEQ; + x = -1; + goto end; +toobig: + err = E2BIG; + x = -1; + goto end; +starved: + err = EINVAL; + x = -1; +end: + errno = err; + *ploc = loc; + return x; +} diff --git a/third_party/ulib/musl/src/locale/jis0208.h b/third_party/ulib/musl/src/locale/jis0208.h new file mode 100644 index 000000000..a385bbcbc --- /dev/null +++ b/third_party/ulib/musl/src/locale/jis0208.h @@ -0,0 +1,554 @@ +12288, 12289, 12290, 65292, 65294, 12539, 65306, 65307, 65311, 65281, 12443, 12444, 180, 65344, 168, + 65342, 65507, 65343, 12541, 12542, 12445, 12446, 12291, 20189, 12293, 12294, 12295, 12540, 8213, + 8208, 65295, 92, 12316, 8214, 65372, 8230, 8229, 8216, 8217, 8220, 8221, 65288, 65289, 12308, + 12309, 65339, 65341, 65371, 65373, 12296, 12297, 12298, 12299, 12300, 12301, 12302, 12303, + 12304, 12305, 65291, 8722, 177, 215, 247, 65309, 8800, 65308, 65310, 8806, 8807, 8734, 8756, + 9794, 9792, 176, 8242, 8243, 8451, 65509, 65284, 162, 163, 65285, 65283, 65286, 65290, 65312, + 167, 9734, 9733, 9675, 9679, 9678, 9671, 9670, 9633, 9632, 9651, 9650, 9661, 9660, 8251, 12306, + 8594, 8592, 8593, 8595, 12307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8712, 8715, 8838, 8839, 8834, + 8835, 8746, 8745, 0, 0, 0, 0, 0, 0, 0, 0, 8743, 8744, 172, 8658, 8660, 8704, 8707, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8736, 8869, 8978, 8706, 8711, 8801, 8786, 8810, 8811, 8730, 8765, 8733, + 8757, 8747, 8748, 0, 0, 0, 0, 0, 0, 0, 8491, 8240, 9839, 9837, 9834, 8224, 8225, 182, 0, 0, 0, + 0, 9711, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65296, 65297, 65298, 65299, 65300, 65301, + 65302, 65303, 65304, 65305, 0, 0, 0, 0, 0, 0, 0, 65313, 65314, 65315, 65316, 65317, 65318, + 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, + 65332, 65333, 65334, 65335, 65336, 65337, 65338, 0, 0, 0, 0, 0, 0, 65345, 65346, 65347, 65348, + 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360, 65361, + 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 0, 0, 0, 0, 12353, 12354, 12355, + 12356, 12357, 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, 12367, 12368, + 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, 12381, + 12382, 12383, 12384, 12385, 12386, 12387, 12388, 12389, 12390, 12391, 12392, 12393, 12394, + 12395, 12396, 12397, 12398, 12399, 12400, 12401, 12402, 12403, 12404, 12405, 12406, 12407, + 12408, 12409, 12410, 12411, 12412, 12413, 12414, 12415, 12416, 12417, 12418, 12419, 12420, + 12421, 12422, 12423, 12424, 12425, 12426, 12427, 12428, 12429, 12430, 12431, 12432, 12433, + 12434, 12435, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12449, 12450, 12451, 12452, 12453, 12454, 12455, + 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, 12467, 12468, + 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, 12481, + 12482, 12483, 12484, 12485, 12486, 12487, 12488, 12489, 12490, 12491, 12492, 12493, 12494, + 12495, 12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, 12507, + 12508, 12509, 12510, 12511, 12512, 12513, 12514, 12515, 12516, 12517, 12518, 12519, 12520, + 12521, 12522, 12523, 12524, 12525, 12526, 12527, 12528, 12529, 12530, 12531, 12532, 12533, + 12534, 0, 0, 0, 0, 0, 0, 0, 0, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, + 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 0, 0, 0, 0, 0, 0, 0, 0, 945, 946, 947, + 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967, + 968, 969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1040, 1041, 1042, 1043, 1044, 1045, 1025, 1046, 1047, 1048, 1049, + 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, + 1066, 1067, 1068, 1069, 1070, 1071, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1072, 1073, + 1074, 1075, 1076, 1077, 1105, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, + 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9472, 9474, 9484, 9488, 9496, 9492, 9500, 9516, 9508, 9524, + 9532, 9473, 9475, 9487, 9491, 9499, 9495, 9507, 9523, 9515, 9531, 9547, 9504, 9519, 9512, 9527, + 9535, 9501, 9520, 9509, 9528, 9538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20124, + 21782, 23043, 38463, 21696, 24859, 25384, 23030, 36898, 33909, 33564, 31312, 24746, 25569, + 28197, 26093, 33894, 33446, 39925, 26771, 22311, 26017, 25201, 23451, 22992, 34427, 39156, + 32098, 32190, 39822, 25110, 31903, 34999, 23433, 24245, 25353, 26263, 26696, 38343, 38797, + 26447, 20197, 20234, 20301, 20381, 20553, 22258, 22839, 22996, 23041, 23561, 24799, 24847, + 24944, 26131, 26885, 28858, 30031, 30064, 31227, 32173, 32239, 32963, 33806, 34915, 35586, + 36949, 36986, 21307, 20117, 20133, 22495, 32946, 37057, 30959, 19968, 22769, 28322, 36920, + 31282, 33576, 33419, 39983, 20801, 21360, 21693, 21729, 22240, 23035, 24341, 39154, 28139, + 32996, 34093, 38498, 38512, 38560, 38907, 21515, 21491, 23431, 28879, 32701, 36802, 38632, + 21359, 40284, 31418, 19985, 30867, 33276, 28198, 22040, 21764, 27421, 34074, 39995, 23013, + 21417, 28006, 29916, 38287, 22082, 20113, 36939, 38642, 33615, 39180, 21473, 21942, 23344, + 24433, 26144, 26355, 26628, 27704, 27891, 27945, 29787, 30408, 31310, 38964, 33521, 34907, + 35424, 37613, 28082, 30123, 30410, 39365, 24742, 35585, 36234, 38322, 27022, 21421, 20870, + 22290, 22576, 22852, 23476, 24310, 24616, 25513, 25588, 27839, 28436, 28814, 28948, 29017, + 29141, 29503, 32257, 33398, 33489, 34199, 36960, 37467, 40219, 22633, 26044, 27738, 29989, + 20985, 22830, 22885, 24448, 24540, 25276, 26106, 27178, 27431, 27572, 29579, 32705, 35158, + 40236, 40206, 40644, 23713, 27798, 33659, 20740, 23627, 25014, 33222, 26742, 29281, 20057, + 20474, 21368, 24681, 28201, 31311, 38899, 19979, 21270, 20206, 20309, 20285, 20385, 20339, + 21152, 21487, 22025, 22799, 23233, 23478, 23521, 31185, 26247, 26524, 26550, 27468, 27827, + 28779, 29634, 31117, 31166, 31292, 31623, 33457, 33499, 33540, 33655, 33775, 33747, 34662, + 35506, 22057, 36008, 36838, 36942, 38686, 34442, 20420, 23784, 25105, 29273, 30011, 33253, + 33469, 34558, 36032, 38597, 39187, 39381, 20171, 20250, 35299, 22238, 22602, 22730, 24315, + 24555, 24618, 24724, 24674, 25040, 25106, 25296, 25913, 39745, 26214, 26800, 28023, 28784, + 30028, 30342, 32117, 33445, 34809, 38283, 38542, 35997, 20977, 21182, 22806, 21683, 23475, + 23830, 24936, 27010, 28079, 30861, 33995, 34903, 35442, 37799, 39608, 28012, 39336, 34521, + 22435, 26623, 34510, 37390, 21123, 22151, 21508, 24275, 25313, 25785, 26684, 26680, 27579, + 29554, 30906, 31339, 35226, 35282, 36203, 36611, 37101, 38307, 38548, 38761, 23398, 23731, + 27005, 38989, 38990, 25499, 31520, 27179, 27263, 26806, 39949, 28511, 21106, 21917, 24688, + 25324, 27963, 28167, 28369, 33883, 35088, 36676, 19988, 39993, 21494, 26907, 27194, 38788, + 26666, 20828, 31427, 33970, 37340, 37772, 22107, 40232, 26658, 33541, 33841, 31909, 21000, + 33477, 29926, 20094, 20355, 20896, 23506, 21002, 21208, 21223, 24059, 21914, 22570, 23014, + 23436, 23448, 23515, 24178, 24185, 24739, 24863, 24931, 25022, 25563, 25954, 26577, 26707, + 26874, 27454, 27475, 27735, 28450, 28567, 28485, 29872, 29976, 30435, 30475, 31487, 31649, + 31777, 32233, 32566, 32752, 32925, 33382, 33694, 35251, 35532, 36011, 36996, 37969, 38291, + 38289, 38306, 38501, 38867, 39208, 33304, 20024, 21547, 23736, 24012, 29609, 30284, 30524, + 23721, 32747, 36107, 38593, 38929, 38996, 39000, 20225, 20238, 21361, 21916, 22120, 22522, + 22855, 23305, 23492, 23696, 24076, 24190, 24524, 25582, 26426, 26071, 26082, 26399, 26827, + 26820, 27231, 24112, 27589, 27671, 27773, 30079, 31048, 23395, 31232, 32000, 24509, 35215, + 35352, 36020, 36215, 36556, 36637, 39138, 39438, 39740, 20096, 20605, 20736, 22931, 23452, + 25135, 25216, 25836, 27450, 29344, 30097, 31047, 32681, 34811, 35516, 35696, 25516, 33738, + 38816, 21513, 21507, 21931, 26708, 27224, 35440, 30759, 26485, 40653, 21364, 23458, 33050, + 34384, 36870, 19992, 20037, 20167, 20241, 21450, 21560, 23470, 24339, 24613, 25937, 26429, + 27714, 27762, 27875, 28792, 29699, 31350, 31406, 31496, 32026, 31998, 32102, 26087, 29275, + 21435, 23621, 24040, 25298, 25312, 25369, 28192, 34394, 35377, 36317, 37624, 28417, 31142, + 39770, 20136, 20139, 20140, 20379, 20384, 20689, 20807, 31478, 20849, 20982, 21332, 21281, + 21375, 21483, 21932, 22659, 23777, 24375, 24394, 24623, 24656, 24685, 25375, 25945, 27211, + 27841, 29378, 29421, 30703, 33016, 33029, 33288, 34126, 37111, 37857, 38911, 39255, 39514, + 20208, 20957, 23597, 26241, 26989, 23616, 26354, 26997, 29577, 26704, 31873, 20677, 21220, + 22343, 24062, 37670, 26020, 27427, 27453, 29748, 31105, 31165, 31563, 32202, 33465, 33740, + 34943, 35167, 35641, 36817, 37329, 21535, 37504, 20061, 20534, 21477, 21306, 29399, 29590, + 30697, 33510, 36527, 39366, 39368, 39378, 20855, 24858, 34398, 21936, 31354, 20598, 23507, + 36935, 38533, 20018, 27355, 37351, 23633, 23624, 25496, 31391, 27795, 38772, 36705, 31402, + 29066, 38536, 31874, 26647, 32368, 26705, 37740, 21234, 21531, 34219, 35347, 32676, 36557, + 37089, 21350, 34952, 31041, 20418, 20670, 21009, 20804, 21843, 22317, 29674, 22411, 22865, + 24418, 24452, 24693, 24950, 24935, 25001, 25522, 25658, 25964, 26223, 26690, 28179, 30054, + 31293, 31995, 32076, 32153, 32331, 32619, 33550, 33610, 34509, 35336, 35427, 35686, 36605, + 38938, 40335, 33464, 36814, 39912, 21127, 25119, 25731, 28608, 38553, 26689, 20625, 27424, + 27770, 28500, 31348, 32080, 34880, 35363, 26376, 20214, 20537, 20518, 20581, 20860, 21048, + 21091, 21927, 22287, 22533, 23244, 24314, 25010, 25080, 25331, 25458, 26908, 27177, 29309, + 29356, 29486, 30740, 30831, 32121, 30476, 32937, 35211, 35609, 36066, 36562, 36963, 37749, + 38522, 38997, 39443, 40568, 20803, 21407, 21427, 24187, 24358, 28187, 28304, 29572, 29694, + 32067, 33335, 35328, 35578, 38480, 20046, 20491, 21476, 21628, 22266, 22993, 23396, 24049, + 24235, 24359, 25144, 25925, 26543, 28246, 29392, 31946, 34996, 32929, 32993, 33776, 34382, + 35463, 36328, 37431, 38599, 39015, 40723, 20116, 20114, 20237, 21320, 21577, 21566, 23087, + 24460, 24481, 24735, 26791, 27278, 29786, 30849, 35486, 35492, 35703, 37264, 20062, 39881, + 20132, 20348, 20399, 20505, 20502, 20809, 20844, 21151, 21177, 21246, 21402, 21475, 21521, + 21518, 21897, 22353, 22434, 22909, 23380, 23389, 23439, 24037, 24039, 24055, 24184, 24195, + 24218, 24247, 24344, 24658, 24908, 25239, 25304, 25511, 25915, 26114, 26179, 26356, 26477, + 26657, 26775, 27083, 27743, 27946, 28009, 28207, 28317, 30002, 30343, 30828, 31295, 31968, + 32005, 32024, 32094, 32177, 32789, 32771, 32943, 32945, 33108, 33167, 33322, 33618, 34892, + 34913, 35611, 36002, 36092, 37066, 37237, 37489, 30783, 37628, 38308, 38477, 38917, 39321, + 39640, 40251, 21083, 21163, 21495, 21512, 22741, 25335, 28640, 35946, 36703, 40633, 20811, + 21051, 21578, 22269, 31296, 37239, 40288, 40658, 29508, 28425, 33136, 29969, 24573, 24794, + 39592, 29403, 36796, 27492, 38915, 20170, 22256, 22372, 22718, 23130, 24680, 25031, 26127, + 26118, 26681, 26801, 28151, 30165, 32058, 33390, 39746, 20123, 20304, 21449, 21766, 23919, + 24038, 24046, 26619, 27801, 29811, 30722, 35408, 37782, 35039, 22352, 24231, 25387, 20661, + 20652, 20877, 26368, 21705, 22622, 22971, 23472, 24425, 25165, 25505, 26685, 27507, 28168, + 28797, 37319, 29312, 30741, 30758, 31085, 25998, 32048, 33756, 35009, 36617, 38555, 21092, + 22312, 26448, 32618, 36001, 20916, 22338, 38442, 22586, 27018, 32948, 21682, 23822, 22524, + 30869, 40442, 20316, 21066, 21643, 25662, 26152, 26388, 26613, 31364, 31574, 32034, 37679, + 26716, 39853, 31545, 21273, 20874, 21047, 23519, 25334, 25774, 25830, 26413, 27578, 34217, + 38609, 30352, 39894, 25420, 37638, 39851, 30399, 26194, 19977, 20632, 21442, 23665, 24808, + 25746, 25955, 26719, 29158, 29642, 29987, 31639, 32386, 34453, 35715, 36059, 37240, 39184, + 26028, 26283, 27531, 20181, 20180, 20282, 20351, 21050, 21496, 21490, 21987, 22235, 22763, + 22987, 22985, 23039, 23376, 23629, 24066, 24107, 24535, 24605, 25351, 25903, 23388, 26031, + 26045, 26088, 26525, 27490, 27515, 27663, 29509, 31049, 31169, 31992, 32025, 32043, 32930, + 33026, 33267, 35222, 35422, 35433, 35430, 35468, 35566, 36039, 36060, 38604, 39164, 27503, + 20107, 20284, 20365, 20816, 23383, 23546, 24904, 25345, 26178, 27425, 28363, 27835, 29246, + 29885, 30164, 30913, 31034, 32780, 32819, 33258, 33940, 36766, 27728, 40575, 24335, 35672, + 40235, 31482, 36600, 23437, 38635, 19971, 21489, 22519, 22833, 23241, 23460, 24713, 28287, + 28422, 30142, 36074, 23455, 34048, 31712, 20594, 26612, 33437, 23649, 34122, 32286, 33294, + 20889, 23556, 25448, 36198, 26012, 29038, 31038, 32023, 32773, 35613, 36554, 36974, 34503, + 37034, 20511, 21242, 23610, 26451, 28796, 29237, 37196, 37320, 37675, 33509, 23490, 24369, + 24825, 20027, 21462, 23432, 25163, 26417, 27530, 29417, 29664, 31278, 33131, 36259, 37202, + 39318, 20754, 21463, 21610, 23551, 25480, 27193, 32172, 38656, 22234, 21454, 21608, 23447, + 23601, 24030, 20462, 24833, 25342, 27954, 31168, 31179, 32066, 32333, 32722, 33261, 33311, + 33936, 34886, 35186, 35728, 36468, 36655, 36913, 37195, 37228, 38598, 37276, 20160, 20303, + 20805, 21313, 24467, 25102, 26580, 27713, 28171, 29539, 32294, 37325, 37507, 21460, 22809, + 23487, 28113, 31069, 32302, 31899, 22654, 29087, 20986, 34899, 36848, 20426, 23803, 26149, + 30636, 31459, 33308, 39423, 20934, 24490, 26092, 26991, 27529, 28147, 28310, 28516, 30462, + 32020, 24033, 36981, 37255, 38918, 20966, 21021, 25152, 26257, 26329, 28186, 24246, 32210, + 32626, 26360, 34223, 34295, 35576, 21161, 21465, 22899, 24207, 24464, 24661, 37604, 38500, + 20663, 20767, 21213, 21280, 21319, 21484, 21736, 21830, 21809, 22039, 22888, 22974, 23100, + 23477, 23558, 23567, 23569, 23578, 24196, 24202, 24288, 24432, 25215, 25220, 25307, 25484, + 25463, 26119, 26124, 26157, 26230, 26494, 26786, 27167, 27189, 27836, 28040, 28169, 28248, + 28988, 28966, 29031, 30151, 30465, 30813, 30977, 31077, 31216, 31456, 31505, 31911, 32057, + 32918, 33750, 33931, 34121, 34909, 35059, 35359, 35388, 35412, 35443, 35937, 36062, 37284, + 37478, 37758, 37912, 38556, 38808, 19978, 19976, 19998, 20055, 20887, 21104, 22478, 22580, + 22732, 23330, 24120, 24773, 25854, 26465, 26454, 27972, 29366, 30067, 31331, 33976, 35698, + 37304, 37664, 22065, 22516, 39166, 25325, 26893, 27542, 29165, 32340, 32887, 33394, 35302, + 39135, 34645, 36785, 23611, 20280, 20449, 20405, 21767, 23072, 23517, 23529, 24515, 24910, + 25391, 26032, 26187, 26862, 27035, 28024, 28145, 30003, 30137, 30495, 31070, 31206, 32051, + 33251, 33455, 34218, 35242, 35386, 36523, 36763, 36914, 37341, 38663, 20154, 20161, 20995, + 22645, 22764, 23563, 29978, 23613, 33102, 35338, 36805, 38499, 38765, 31525, 35535, 38920, + 37218, 22259, 21416, 36887, 21561, 22402, 24101, 25512, 27700, 28810, 30561, 31883, 32736, + 34928, 36930, 37204, 37648, 37656, 38543, 29790, 39620, 23815, 23913, 25968, 26530, 36264, + 38619, 25454, 26441, 26905, 33733, 38935, 38592, 35070, 28548, 25722, 23544, 19990, 28716, + 30045, 26159, 20932, 21046, 21218, 22995, 24449, 24615, 25104, 25919, 25972, 26143, 26228, + 26866, 26646, 27491, 28165, 29298, 29983, 30427, 31934, 32854, 22768, 35069, 35199, 35488, + 35475, 35531, 36893, 37266, 38738, 38745, 25993, 31246, 33030, 38587, 24109, 24796, 25114, + 26021, 26132, 26512, 30707, 31309, 31821, 32318, 33034, 36012, 36196, 36321, 36447, 30889, + 20999, 25305, 25509, 25666, 25240, 35373, 31363, 31680, 35500, 38634, 32118, 33292, 34633, + 20185, 20808, 21315, 21344, 23459, 23554, 23574, 24029, 25126, 25159, 25776, 26643, 26676, + 27849, 27973, 27927, 26579, 28508, 29006, 29053, 26059, 31359, 31661, 32218, 32330, 32680, + 33146, 33307, 33337, 34214, 35438, 36046, 36341, 36984, 36983, 37549, 37521, 38275, 39854, + 21069, 21892, 28472, 28982, 20840, 31109, 32341, 33203, 31950, 22092, 22609, 23720, 25514, + 26366, 26365, 26970, 29401, 30095, 30094, 30990, 31062, 31199, 31895, 32032, 32068, 34311, + 35380, 38459, 36961, 40736, 20711, 21109, 21452, 21474, 20489, 21930, 22766, 22863, 29245, + 23435, 23652, 21277, 24803, 24819, 25436, 25475, 25407, 25531, 25805, 26089, 26361, 24035, + 27085, 27133, 28437, 29157, 20105, 30185, 30456, 31379, 31967, 32207, 32156, 32865, 33609, + 33624, 33900, 33980, 34299, 35013, 36208, 36865, 36973, 37783, 38684, 39442, 20687, 22679, + 24974, 33235, 34101, 36104, 36896, 20419, 20596, 21063, 21363, 24687, 25417, 26463, 28204, + 36275, 36895, 20439, 23646, 36042, 26063, 32154, 21330, 34966, 20854, 25539, 23384, 23403, + 23562, 25613, 26449, 36956, 20182, 22810, 22826, 27760, 35409, 21822, 22549, 22949, 24816, + 25171, 26561, 33333, 26965, 38464, 39364, 39464, 20307, 22534, 23550, 32784, 23729, 24111, + 24453, 24608, 24907, 25140, 26367, 27888, 28382, 32974, 33151, 33492, 34955, 36024, 36864, + 36910, 38538, 40667, 39899, 20195, 21488, 22823, 31532, 37261, 38988, 40441, 28381, 28711, + 21331, 21828, 23429, 25176, 25246, 25299, 27810, 28655, 29730, 35351, 37944, 28609, 35582, + 33592, 20967, 34552, 21482, 21481, 20294, 36948, 36784, 22890, 33073, 24061, 31466, 36799, + 26842, 35895, 29432, 40008, 27197, 35504, 20025, 21336, 22022, 22374, 25285, 25506, 26086, + 27470, 28129, 28251, 28845, 30701, 31471, 31658, 32187, 32829, 32966, 34507, 35477, 37723, + 22243, 22727, 24382, 26029, 26262, 27264, 27573, 30007, 35527, 20516, 30693, 22320, 24347, + 24677, 26234, 27744, 30196, 31258, 32622, 33268, 34584, 36933, 39347, 31689, 30044, 31481, + 31569, 33988, 36880, 31209, 31378, 33590, 23265, 30528, 20013, 20210, 23449, 24544, 25277, + 26172, 26609, 27880, 34411, 34935, 35387, 37198, 37619, 39376, 27159, 28710, 29482, 33511, + 33879, 36015, 19969, 20806, 20939, 21899, 23541, 24086, 24115, 24193, 24340, 24373, 24427, + 24500, 25074, 25361, 26274, 26397, 28526, 29266, 30010, 30522, 32884, 33081, 33144, 34678, + 35519, 35548, 36229, 36339, 37530, 38263, 38914, 40165, 21189, 25431, 30452, 26389, 27784, + 29645, 36035, 37806, 38515, 27941, 22684, 26894, 27084, 36861, 37786, 30171, 36890, 22618, + 26626, 25524, 27131, 20291, 28460, 26584, 36795, 34086, 32180, 37716, 26943, 28528, 22378, + 22775, 23340, 32044, 29226, 21514, 37347, 40372, 20141, 20302, 20572, 20597, 21059, 35998, + 21576, 22564, 23450, 24093, 24213, 24237, 24311, 24351, 24716, 25269, 25402, 25552, 26799, + 27712, 30855, 31118, 31243, 32224, 33351, 35330, 35558, 36420, 36883, 37048, 37165, 37336, + 40718, 27877, 25688, 25826, 25973, 28404, 30340, 31515, 36969, 37841, 28346, 21746, 24505, + 25764, 36685, 36845, 37444, 20856, 22635, 22825, 23637, 24215, 28155, 32399, 29980, 36028, + 36578, 39003, 28857, 20253, 27583, 28593, 30000, 38651, 20814, 21520, 22581, 22615, 22956, + 23648, 24466, 26007, 26460, 28193, 30331, 33759, 36077, 36884, 37117, 37709, 30757, 30778, + 21162, 24230, 22303, 22900, 24594, 20498, 20826, 20908, 20941, 20992, 21776, 22612, 22616, + 22871, 23445, 23798, 23947, 24764, 25237, 25645, 26481, 26691, 26812, 26847, 30423, 28120, + 28271, 28059, 28783, 29128, 24403, 30168, 31095, 31561, 31572, 31570, 31958, 32113, 21040, + 33891, 34153, 34276, 35342, 35588, 35910, 36367, 36867, 36879, 37913, 38518, 38957, 39472, + 38360, 20685, 21205, 21516, 22530, 23566, 24999, 25758, 27934, 30643, 31461, 33012, 33796, + 36947, 37509, 23776, 40199, 21311, 24471, 24499, 28060, 29305, 30563, 31167, 31716, 27602, + 29420, 35501, 26627, 27233, 20984, 31361, 26932, 23626, 40182, 33515, 23493, 37193, 28702, + 22136, 23663, 24775, 25958, 27788, 35930, 36929, 38931, 21585, 26311, 37389, 22856, 37027, + 20869, 20045, 20970, 34201, 35598, 28760, 25466, 37707, 26978, 39348, 32260, 30071, 21335, + 26976, 36575, 38627, 27741, 20108, 23612, 24336, 36841, 21250, 36049, 32905, 34425, 24319, + 26085, 20083, 20837, 22914, 23615, 38894, 20219, 22922, 24525, 35469, 28641, 31152, 31074, + 23527, 33905, 29483, 29105, 24180, 24565, 25467, 25754, 29123, 31896, 20035, 24316, 20043, + 22492, 22178, 24745, 28611, 32013, 33021, 33075, 33215, 36786, 35223, 34468, 24052, 25226, + 25773, 35207, 26487, 27874, 27966, 29750, 30772, 23110, 32629, 33453, 39340, 20467, 24259, + 25309, 25490, 25943, 26479, 30403, 29260, 32972, 32954, 36649, 37197, 20493, 22521, 23186, + 26757, 26995, 29028, 29437, 36023, 22770, 36064, 38506, 36889, 34687, 31204, 30695, 33833, + 20271, 21093, 21338, 25293, 26575, 27850, 30333, 31636, 31893, 33334, 34180, 36843, 26333, + 28448, 29190, 32283, 33707, 39361, 40614, 20989, 31665, 30834, 31672, 32903, 31560, 27368, + 24161, 32908, 30033, 30048, 20843, 37474, 28300, 30330, 37271, 39658, 20240, 32624, 25244, + 31567, 38309, 40169, 22138, 22617, 34532, 38588, 20276, 21028, 21322, 21453, 21467, 24070, + 25644, 26001, 26495, 27710, 27726, 29256, 29359, 29677, 30036, 32321, 33324, 34281, 36009, + 31684, 37318, 29033, 38930, 39151, 25405, 26217, 30058, 30436, 30928, 34115, 34542, 21290, + 21329, 21542, 22915, 24199, 24444, 24754, 25161, 25209, 25259, 26000, 27604, 27852, 30130, + 30382, 30865, 31192, 32203, 32631, 32933, 34987, 35513, 36027, 36991, 38750, 39131, 27147, + 31800, 20633, 23614, 24494, 26503, 27608, 29749, 30473, 32654, 40763, 26570, 31255, 21305, + 30091, 39661, 24422, 33181, 33777, 32920, 24380, 24517, 30050, 31558, 36924, 26727, 23019, + 23195, 32016, 30334, 35628, 20469, 24426, 27161, 27703, 28418, 29922, 31080, 34920, 35413, + 35961, 24287, 25551, 30149, 31186, 33495, 37672, 37618, 33948, 34541, 39981, 21697, 24428, + 25996, 27996, 28693, 36007, 36051, 38971, 25935, 29942, 19981, 20184, 22496, 22827, 23142, + 23500, 20904, 24067, 24220, 24598, 25206, 25975, 26023, 26222, 28014, 29238, 31526, 33104, + 33178, 33433, 35676, 36000, 36070, 36212, 38428, 38468, 20398, 25771, 27494, 33310, 33889, + 34154, 37096, 23553, 26963, 39080, 33914, 34135, 20239, 21103, 24489, 24133, 26381, 31119, + 33145, 35079, 35206, 28149, 24343, 25173, 27832, 20175, 29289, 39826, 20998, 21563, 22132, + 22707, 24996, 25198, 28954, 22894, 31881, 31966, 32027, 38640, 25991, 32862, 19993, 20341, + 20853, 22592, 24163, 24179, 24330, 26564, 20006, 34109, 38281, 38491, 31859, 38913, 20731, + 22721, 30294, 30887, 21029, 30629, 34065, 31622, 20559, 22793, 29255, 31687, 32232, 36794, + 36820, 36941, 20415, 21193, 23081, 24321, 38829, 20445, 33303, 37610, 22275, 25429, 27497, + 29995, 35036, 36628, 31298, 21215, 22675, 24917, 25098, 26286, 27597, 31807, 33769, 20515, + 20472, 21253, 21574, 22577, 22857, 23453, 23792, 23791, 23849, 24214, 25265, 25447, 25918, + 26041, 26379, 27861, 27873, 28921, 30770, 32299, 32990, 33459, 33804, 34028, 34562, 35090, + 35370, 35914, 37030, 37586, 39165, 40179, 40300, 20047, 20129, 20621, 21078, 22346, 22952, + 24125, 24536, 24537, 25151, 26292, 26395, 26576, 26834, 20882, 32033, 32938, 33192, 35584, + 35980, 36031, 37502, 38450, 21536, 38956, 21271, 20693, 21340, 22696, 25778, 26420, 29287, + 30566, 31302, 37350, 21187, 27809, 27526, 22528, 24140, 22868, 26412, 32763, 20961, 30406, + 25705, 30952, 39764, 40635, 22475, 22969, 26151, 26522, 27598, 21737, 27097, 24149, 33180, + 26517, 39850, 26622, 40018, 26717, 20134, 20451, 21448, 25273, 26411, 27819, 36804, 20397, + 32365, 40639, 19975, 24930, 28288, 28459, 34067, 21619, 26410, 39749, 24051, 31637, 23724, + 23494, 34588, 28234, 34001, 31252, 33032, 22937, 31885, 27665, 30496, 21209, 22818, 28961, + 29279, 30683, 38695, 40289, 26891, 23167, 23064, 20901, 21517, 21629, 26126, 30431, 36855, + 37528, 40180, 23018, 29277, 28357, 20813, 26825, 32191, 32236, 38754, 40634, 25720, 27169, + 33538, 22916, 23391, 27611, 29467, 30450, 32178, 32791, 33945, 20786, 26408, 40665, 30446, + 26466, 21247, 39173, 23588, 25147, 31870, 36016, 21839, 24758, 32011, 38272, 21249, 20063, + 20918, 22812, 29242, 32822, 37326, 24357, 30690, 21380, 24441, 32004, 34220, 35379, 36493, + 38742, 26611, 34222, 37971, 24841, 24840, 27833, 30290, 35565, 36664, 21807, 20305, 20778, + 21191, 21451, 23461, 24189, 24736, 24962, 25558, 26377, 26586, 28263, 28044, 29494, 29495, + 30001, 31056, 35029, 35480, 36938, 37009, 37109, 38596, 34701, 22805, 20104, 20313, 19982, + 35465, 36671, 38928, 20653, 24188, 22934, 23481, 24248, 25562, 25594, 25793, 26332, 26954, + 27096, 27915, 28342, 29076, 29992, 31407, 32650, 32768, 33865, 33993, 35201, 35617, 36362, + 36965, 38525, 39178, 24958, 25233, 27442, 27779, 28020, 32716, 32764, 28096, 32645, 34746, + 35064, 26469, 33713, 38972, 38647, 27931, 32097, 33853, 37226, 20081, 21365, 23888, 27396, + 28651, 34253, 34349, 35239, 21033, 21519, 23653, 26446, 26792, 29702, 29827, 30178, 35023, + 35041, 37324, 38626, 38520, 24459, 29575, 31435, 33870, 25504, 30053, 21129, 27969, 28316, + 29705, 30041, 30827, 31890, 38534, 31452, 40845, 20406, 24942, 26053, 34396, 20102, 20142, + 20698, 20001, 20940, 23534, 26009, 26753, 28092, 29471, 30274, 30637, 31260, 31975, 33391, + 35538, 36988, 37327, 38517, 38936, 21147, 32209, 20523, 21400, 26519, 28107, 29136, 29747, + 33256, 36650, 38563, 40023, 40607, 29792, 22593, 28057, 32047, 39006, 20196, 20278, 20363, + 20919, 21169, 23994, 24604, 29618, 31036, 33491, 37428, 38583, 38646, 38666, 40599, 40802, + 26278, 27508, 21015, 21155, 28872, 35010, 24265, 24651, 24976, 28451, 29001, 31806, 32244, + 32879, 34030, 36899, 37676, 21570, 39791, 27347, 28809, 36034, 36335, 38706, 21172, 23105, + 24266, 24324, 26391, 27004, 27028, 28010, 28431, 29282, 29436, 31725, 32769, 32894, 34635, + 37070, 20845, 40595, 31108, 32907, 37682, 35542, 20525, 21644, 35441, 27498, 36036, 33031, + 24785, 26528, 40434, 20121, 20120, 39952, 35435, 34241, 34152, 26880, 28286, 30871, 33109, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 24332, 19984, 19989, 20010, 20017, 20022, 20028, 20031, 20034, 20054, + 20056, 20098, 20101, 35947, 20106, 33298, 24333, 20110, 20126, 20127, 20128, 20130, 20144, + 20147, 20150, 20174, 20173, 20164, 20166, 20162, 20183, 20190, 20205, 20191, 20215, 20233, + 20314, 20272, 20315, 20317, 20311, 20295, 20342, 20360, 20367, 20376, 20347, 20329, 20336, + 20369, 20335, 20358, 20374, 20760, 20436, 20447, 20430, 20440, 20443, 20433, 20442, 20432, + 20452, 20453, 20506, 20520, 20500, 20522, 20517, 20485, 20252, 20470, 20513, 20521, 20524, + 20478, 20463, 20497, 20486, 20547, 20551, 26371, 20565, 20560, 20552, 20570, 20566, 20588, + 20600, 20608, 20634, 20613, 20660, 20658, 20681, 20682, 20659, 20674, 20694, 20702, 20709, + 20717, 20707, 20718, 20729, 20725, 20745, 20737, 20738, 20758, 20757, 20756, 20762, 20769, + 20794, 20791, 20796, 20795, 20799, 20800, 20818, 20812, 20820, 20834, 31480, 20841, 20842, + 20846, 20864, 20866, 22232, 20876, 20873, 20879, 20881, 20883, 20885, 20886, 20900, 20902, + 20898, 20905, 20906, 20907, 20915, 20913, 20914, 20912, 20917, 20925, 20933, 20937, 20955, + 20960, 34389, 20969, 20973, 20976, 20981, 20990, 20996, 21003, 21012, 21006, 21031, 21034, + 21038, 21043, 21049, 21071, 21060, 21067, 21068, 21086, 21076, 21098, 21108, 21097, 21107, + 21119, 21117, 21133, 21140, 21138, 21105, 21128, 21137, 36776, 36775, 21164, 21165, 21180, + 21173, 21185, 21197, 21207, 21214, 21219, 21222, 39149, 21216, 21235, 21237, 21240, 21241, + 21254, 21256, 30008, 21261, 21264, 21263, 21269, 21274, 21283, 21295, 21297, 21299, 21304, + 21312, 21318, 21317, 19991, 21321, 21325, 20950, 21342, 21353, 21358, 22808, 21371, 21367, + 21378, 21398, 21408, 21414, 21413, 21422, 21424, 21430, 21443, 31762, 38617, 21471, 26364, + 29166, 21486, 21480, 21485, 21498, 21505, 21565, 21568, 21548, 21549, 21564, 21550, 21558, + 21545, 21533, 21582, 21647, 21621, 21646, 21599, 21617, 21623, 21616, 21650, 21627, 21632, + 21622, 21636, 21648, 21638, 21703, 21666, 21688, 21669, 21676, 21700, 21704, 21672, 21675, + 21698, 21668, 21694, 21692, 21720, 21733, 21734, 21775, 21780, 21757, 21742, 21741, 21754, + 21730, 21817, 21824, 21859, 21836, 21806, 21852, 21829, 21846, 21847, 21816, 21811, 21853, + 21913, 21888, 21679, 21898, 21919, 21883, 21886, 21912, 21918, 21934, 21884, 21891, 21929, + 21895, 21928, 21978, 21957, 21983, 21956, 21980, 21988, 21972, 22036, 22007, 22038, 22014, + 22013, 22043, 22009, 22094, 22096, 29151, 22068, 22070, 22066, 22072, 22123, 22116, 22063, + 22124, 22122, 22150, 22144, 22154, 22176, 22164, 22159, 22181, 22190, 22198, 22196, 22210, + 22204, 22209, 22211, 22208, 22216, 22222, 22225, 22227, 22231, 22254, 22265, 22272, 22271, + 22276, 22281, 22280, 22283, 22285, 22291, 22296, 22294, 21959, 22300, 22310, 22327, 22328, + 22350, 22331, 22336, 22351, 22377, 22464, 22408, 22369, 22399, 22409, 22419, 22432, 22451, + 22436, 22442, 22448, 22467, 22470, 22484, 22482, 22483, 22538, 22486, 22499, 22539, 22553, + 22557, 22642, 22561, 22626, 22603, 22640, 27584, 22610, 22589, 22649, 22661, 22713, 22687, + 22699, 22714, 22750, 22715, 22712, 22702, 22725, 22739, 22737, 22743, 22745, 22744, 22757, + 22748, 22756, 22751, 22767, 22778, 22777, 22779, 22780, 22781, 22786, 22794, 22800, 22811, + 26790, 22821, 22828, 22829, 22834, 22840, 22846, 31442, 22869, 22864, 22862, 22874, 22872, + 22882, 22880, 22887, 22892, 22889, 22904, 22913, 22941, 20318, 20395, 22947, 22962, 22982, + 23016, 23004, 22925, 23001, 23002, 23077, 23071, 23057, 23068, 23049, 23066, 23104, 23148, + 23113, 23093, 23094, 23138, 23146, 23194, 23228, 23230, 23243, 23234, 23229, 23267, 23255, + 23270, 23273, 23254, 23290, 23291, 23308, 23307, 23318, 23346, 23248, 23338, 23350, 23358, + 23363, 23365, 23360, 23377, 23381, 23386, 23387, 23397, 23401, 23408, 23411, 23413, 23416, + 25992, 23418, 23424, 23427, 23462, 23480, 23491, 23495, 23497, 23508, 23504, 23524, 23526, + 23522, 23518, 23525, 23531, 23536, 23542, 23539, 23557, 23559, 23560, 23565, 23571, 23584, + 23586, 23592, 23608, 23609, 23617, 23622, 23630, 23635, 23632, 23631, 23409, 23660, 23662, + 20066, 23670, 23673, 23692, 23697, 23700, 22939, 23723, 23739, 23734, 23740, 23735, 23749, + 23742, 23751, 23769, 23785, 23805, 23802, 23789, 23948, 23786, 23819, 23829, 23831, 23900, + 23839, 23835, 23825, 23828, 23842, 23834, 23833, 23832, 23884, 23890, 23886, 23883, 23916, + 23923, 23926, 23943, 23940, 23938, 23970, 23965, 23980, 23982, 23997, 23952, 23991, 23996, + 24009, 24013, 24019, 24018, 24022, 24027, 24043, 24050, 24053, 24075, 24090, 24089, 24081, + 24091, 24118, 24119, 24132, 24131, 24128, 24142, 24151, 24148, 24159, 24162, 24164, 24135, + 24181, 24182, 24186, 40636, 24191, 24224, 24257, 24258, 24264, 24272, 24271, 24278, 24291, + 24285, 24282, 24283, 24290, 24289, 24296, 24297, 24300, 24305, 24307, 24304, 24308, 24312, + 24318, 24323, 24329, 24413, 24412, 24331, 24337, 24342, 24361, 24365, 24376, 24385, 24392, + 24396, 24398, 24367, 24401, 24406, 24407, 24409, 24417, 24429, 24435, 24439, 24451, 24450, + 24447, 24458, 24456, 24465, 24455, 24478, 24473, 24472, 24480, 24488, 24493, 24508, 24534, + 24571, 24548, 24568, 24561, 24541, 24755, 24575, 24609, 24672, 24601, 24592, 24617, 24590, + 24625, 24603, 24597, 24619, 24614, 24591, 24634, 24666, 24641, 24682, 24695, 24671, 24650, + 24646, 24653, 24675, 24643, 24676, 24642, 24684, 24683, 24665, 24705, 24717, 24807, 24707, + 24730, 24708, 24731, 24726, 24727, 24722, 24743, 24715, 24801, 24760, 24800, 24787, 24756, + 24560, 24765, 24774, 24757, 24792, 24909, 24853, 24838, 24822, 24823, 24832, 24820, 24826, + 24835, 24865, 24827, 24817, 24845, 24846, 24903, 24894, 24872, 24871, 24906, 24895, 24892, + 24876, 24884, 24893, 24898, 24900, 24947, 24951, 24920, 24921, 24922, 24939, 24948, 24943, + 24933, 24945, 24927, 24925, 24915, 24949, 24985, 24982, 24967, 25004, 24980, 24986, 24970, + 24977, 25003, 25006, 25036, 25034, 25033, 25079, 25032, 25027, 25030, 25018, 25035, 32633, + 25037, 25062, 25059, 25078, 25082, 25076, 25087, 25085, 25084, 25086, 25088, 25096, 25097, + 25101, 25100, 25108, 25115, 25118, 25121, 25130, 25134, 25136, 25138, 25139, 25153, 25166, + 25182, 25187, 25179, 25184, 25192, 25212, 25218, 25225, 25214, 25234, 25235, 25238, 25300, + 25219, 25236, 25303, 25297, 25275, 25295, 25343, 25286, 25812, 25288, 25308, 25292, 25290, + 25282, 25287, 25243, 25289, 25356, 25326, 25329, 25383, 25346, 25352, 25327, 25333, 25424, + 25406, 25421, 25628, 25423, 25494, 25486, 25472, 25515, 25462, 25507, 25487, 25481, 25503, + 25525, 25451, 25449, 25534, 25577, 25536, 25542, 25571, 25545, 25554, 25590, 25540, 25622, + 25652, 25606, 25619, 25638, 25654, 25885, 25623, 25640, 25615, 25703, 25711, 25718, 25678, + 25898, 25749, 25747, 25765, 25769, 25736, 25788, 25818, 25810, 25797, 25799, 25787, 25816, + 25794, 25841, 25831, 33289, 25824, 25825, 25260, 25827, 25839, 25900, 25846, 25844, 25842, + 25850, 25856, 25853, 25880, 25884, 25861, 25892, 25891, 25899, 25908, 25909, 25911, 25910, + 25912, 30027, 25928, 25942, 25941, 25933, 25944, 25950, 25949, 25970, 25976, 25986, 25987, + 35722, 26011, 26015, 26027, 26039, 26051, 26054, 26049, 26052, 26060, 26066, 26075, 26073, + 26080, 26081, 26097, 26482, 26122, 26115, 26107, 26483, 26165, 26166, 26164, 26140, 26191, + 26180, 26185, 26177, 26206, 26205, 26212, 26215, 26216, 26207, 26210, 26224, 26243, 26248, + 26254, 26249, 26244, 26264, 26269, 26305, 26297, 26313, 26302, 26300, 26308, 26296, 26326, + 26330, 26336, 26175, 26342, 26345, 26352, 26357, 26359, 26383, 26390, 26398, 26406, 26407, + 38712, 26414, 26431, 26422, 26433, 26424, 26423, 26438, 26462, 26464, 26457, 26467, 26468, + 26505, 26480, 26537, 26492, 26474, 26508, 26507, 26534, 26529, 26501, 26551, 26607, 26548, + 26604, 26547, 26601, 26552, 26596, 26590, 26589, 26594, 26606, 26553, 26574, 26566, 26599, + 27292, 26654, 26694, 26665, 26688, 26701, 26674, 26702, 26803, 26667, 26713, 26723, 26743, + 26751, 26783, 26767, 26797, 26772, 26781, 26779, 26755, 27310, 26809, 26740, 26805, 26784, + 26810, 26895, 26765, 26750, 26881, 26826, 26888, 26840, 26914, 26918, 26849, 26892, 26829, + 26836, 26855, 26837, 26934, 26898, 26884, 26839, 26851, 26917, 26873, 26848, 26863, 26920, + 26922, 26906, 26915, 26913, 26822, 27001, 26999, 26972, 27000, 26987, 26964, 27006, 26990, + 26937, 26996, 26941, 26969, 26928, 26977, 26974, 26973, 27009, 26986, 27058, 27054, 27088, + 27071, 27073, 27091, 27070, 27086, 23528, 27082, 27101, 27067, 27075, 27047, 27182, 27025, + 27040, 27036, 27029, 27060, 27102, 27112, 27138, 27163, 27135, 27402, 27129, 27122, 27111, + 27141, 27057, 27166, 27117, 27156, 27115, 27146, 27154, 27329, 27171, 27155, 27204, 27148, + 27250, 27190, 27256, 27207, 27234, 27225, 27238, 27208, 27192, 27170, 27280, 27277, 27296, + 27268, 27298, 27299, 27287, 34327, 27323, 27331, 27330, 27320, 27315, 27308, 27358, 27345, + 27359, 27306, 27354, 27370, 27387, 27397, 34326, 27386, 27410, 27414, 39729, 27423, 27448, + 27447, 30428, 27449, 39150, 27463, 27459, 27465, 27472, 27481, 27476, 27483, 27487, 27489, + 27512, 27513, 27519, 27520, 27524, 27523, 27533, 27544, 27541, 27550, 27556, 27562, 27563, + 27567, 27570, 27569, 27571, 27575, 27580, 27590, 27595, 27603, 27615, 27628, 27627, 27635, + 27631, 40638, 27656, 27667, 27668, 27675, 27684, 27683, 27742, 27733, 27746, 27754, 27778, + 27789, 27802, 27777, 27803, 27774, 27752, 27763, 27794, 27792, 27844, 27889, 27859, 27837, + 27863, 27845, 27869, 27822, 27825, 27838, 27834, 27867, 27887, 27865, 27882, 27935, 34893, + 27958, 27947, 27965, 27960, 27929, 27957, 27955, 27922, 27916, 28003, 28051, 28004, 27994, + 28025, 27993, 28046, 28053, 28644, 28037, 28153, 28181, 28170, 28085, 28103, 28134, 28088, + 28102, 28140, 28126, 28108, 28136, 28114, 28101, 28154, 28121, 28132, 28117, 28138, 28142, + 28205, 28270, 28206, 28185, 28274, 28255, 28222, 28195, 28267, 28203, 28278, 28237, 28191, + 28227, 28218, 28238, 28196, 28415, 28189, 28216, 28290, 28330, 28312, 28361, 28343, 28371, + 28349, 28335, 28356, 28338, 28372, 28373, 28303, 28325, 28354, 28319, 28481, 28433, 28748, + 28396, 28408, 28414, 28479, 28402, 28465, 28399, 28466, 28364, 28478, 28435, 28407, 28550, + 28538, 28536, 28545, 28544, 28527, 28507, 28659, 28525, 28546, 28540, 28504, 28558, 28561, + 28610, 28518, 28595, 28579, 28577, 28580, 28601, 28614, 28586, 28639, 28629, 28652, 28628, + 28632, 28657, 28654, 28635, 28681, 28683, 28666, 28689, 28673, 28687, 28670, 28699, 28698, + 28532, 28701, 28696, 28703, 28720, 28734, 28722, 28753, 28771, 28825, 28818, 28847, 28913, + 28844, 28856, 28851, 28846, 28895, 28875, 28893, 28889, 28937, 28925, 28956, 28953, 29029, + 29013, 29064, 29030, 29026, 29004, 29014, 29036, 29071, 29179, 29060, 29077, 29096, 29100, + 29143, 29113, 29118, 29138, 29129, 29140, 29134, 29152, 29164, 29159, 29173, 29180, 29177, + 29183, 29197, 29200, 29211, 29224, 29229, 29228, 29232, 29234, 29243, 29244, 29247, 29248, + 29254, 29259, 29272, 29300, 29310, 29314, 29313, 29319, 29330, 29334, 29346, 29351, 29369, + 29362, 29379, 29382, 29380, 29390, 29394, 29410, 29408, 29409, 29433, 29431, 20495, 29463, + 29450, 29468, 29462, 29469, 29492, 29487, 29481, 29477, 29502, 29518, 29519, 40664, 29527, + 29546, 29544, 29552, 29560, 29557, 29563, 29562, 29640, 29619, 29646, 29627, 29632, 29669, + 29678, 29662, 29858, 29701, 29807, 29733, 29688, 29746, 29754, 29781, 29759, 29791, 29785, + 29761, 29788, 29801, 29808, 29795, 29802, 29814, 29822, 29835, 29854, 29863, 29898, 29903, + 29908, 29681, 29920, 29923, 29927, 29929, 29934, 29938, 29936, 29937, 29944, 29943, 29956, + 29955, 29957, 29964, 29966, 29965, 29973, 29971, 29982, 29990, 29996, 30012, 30020, 30029, + 30026, 30025, 30043, 30022, 30042, 30057, 30052, 30055, 30059, 30061, 30072, 30070, 30086, + 30087, 30068, 30090, 30089, 30082, 30100, 30106, 30109, 30117, 30115, 30146, 30131, 30147, + 30133, 30141, 30136, 30140, 30129, 30157, 30154, 30162, 30169, 30179, 30174, 30206, 30207, + 30204, 30209, 30192, 30202, 30194, 30195, 30219, 30221, 30217, 30239, 30247, 30240, 30241, + 30242, 30244, 30260, 30256, 30267, 30279, 30280, 30278, 30300, 30296, 30305, 30306, 30312, + 30313, 30314, 30311, 30316, 30320, 30322, 30326, 30328, 30332, 30336, 30339, 30344, 30347, + 30350, 30358, 30355, 30361, 30362, 30384, 30388, 30392, 30393, 30394, 30402, 30413, 30422, + 30418, 30430, 30433, 30437, 30439, 30442, 34351, 30459, 30472, 30471, 30468, 30505, 30500, + 30494, 30501, 30502, 30491, 30519, 30520, 30535, 30554, 30568, 30571, 30555, 30565, 30591, + 30590, 30585, 30606, 30603, 30609, 30624, 30622, 30640, 30646, 30649, 30655, 30652, 30653, + 30651, 30663, 30669, 30679, 30682, 30684, 30691, 30702, 30716, 30732, 30738, 31014, 30752, + 31018, 30789, 30862, 30836, 30854, 30844, 30874, 30860, 30883, 30901, 30890, 30895, 30929, + 30918, 30923, 30932, 30910, 30908, 30917, 30922, 30956, 30951, 30938, 30973, 30964, 30983, + 30994, 30993, 31001, 31020, 31019, 31040, 31072, 31063, 31071, 31066, 31061, 31059, 31098, + 31103, 31114, 31133, 31143, 40779, 31146, 31150, 31155, 31161, 31162, 31177, 31189, 31207, + 31212, 31201, 31203, 31240, 31245, 31256, 31257, 31264, 31263, 31104, 31281, 31291, 31294, + 31287, 31299, 31319, 31305, 31329, 31330, 31337, 40861, 31344, 31353, 31357, 31368, 31383, + 31381, 31384, 31382, 31401, 31432, 31408, 31414, 31429, 31428, 31423, 36995, 31431, 31434, + 31437, 31439, 31445, 31443, 31449, 31450, 31453, 31457, 31458, 31462, 31469, 31472, 31490, + 31503, 31498, 31494, 31539, 31512, 31513, 31518, 31541, 31528, 31542, 31568, 31610, 31492, + 31565, 31499, 31564, 31557, 31605, 31589, 31604, 31591, 31600, 31601, 31596, 31598, 31645, + 31640, 31647, 31629, 31644, 31642, 31627, 31634, 31631, 31581, 31641, 31691, 31681, 31692, + 31695, 31668, 31686, 31709, 31721, 31761, 31764, 31718, 31717, 31840, 31744, 31751, 31763, + 31731, 31735, 31767, 31757, 31734, 31779, 31783, 31786, 31775, 31799, 31787, 31805, 31820, + 31811, 31828, 31823, 31808, 31824, 31832, 31839, 31844, 31830, 31845, 31852, 31861, 31875, + 31888, 31908, 31917, 31906, 31915, 31905, 31912, 31923, 31922, 31921, 31918, 31929, 31933, + 31936, 31941, 31938, 31960, 31954, 31964, 31970, 39739, 31983, 31986, 31988, 31990, 31994, + 32006, 32002, 32028, 32021, 32010, 32069, 32075, 32046, 32050, 32063, 32053, 32070, 32115, + 32086, 32078, 32114, 32104, 32110, 32079, 32099, 32147, 32137, 32091, 32143, 32125, 32155, + 32186, 32174, 32163, 32181, 32199, 32189, 32171, 32317, 32162, 32175, 32220, 32184, 32159, + 32176, 32216, 32221, 32228, 32222, 32251, 32242, 32225, 32261, 32266, 32291, 32289, 32274, + 32305, 32287, 32265, 32267, 32290, 32326, 32358, 32315, 32309, 32313, 32323, 32311, 32306, + 32314, 32359, 32349, 32342, 32350, 32345, 32346, 32377, 32362, 32361, 32380, 32379, 32387, + 32213, 32381, 36782, 32383, 32392, 32393, 32396, 32402, 32400, 32403, 32404, 32406, 32398, + 32411, 32412, 32568, 32570, 32581, 32588, 32589, 32590, 32592, 32593, 32597, 32596, 32600, + 32607, 32608, 32616, 32617, 32615, 32632, 32642, 32646, 32643, 32648, 32647, 32652, 32660, + 32670, 32669, 32666, 32675, 32687, 32690, 32697, 32686, 32694, 32696, 35697, 32709, 32710, + 32714, 32725, 32724, 32737, 32742, 32745, 32755, 32761, 39132, 32774, 32772, 32779, 32786, + 32792, 32793, 32796, 32801, 32808, 32831, 32827, 32842, 32838, 32850, 32856, 32858, 32863, + 32866, 32872, 32883, 32882, 32880, 32886, 32889, 32893, 32895, 32900, 32902, 32901, 32923, + 32915, 32922, 32941, 20880, 32940, 32987, 32997, 32985, 32989, 32964, 32986, 32982, 33033, + 33007, 33009, 33051, 33065, 33059, 33071, 33099, 38539, 33094, 33086, 33107, 33105, 33020, + 33137, 33134, 33125, 33126, 33140, 33155, 33160, 33162, 33152, 33154, 33184, 33173, 33188, + 33187, 33119, 33171, 33193, 33200, 33205, 33214, 33208, 33213, 33216, 33218, 33210, 33225, + 33229, 33233, 33241, 33240, 33224, 33242, 33247, 33248, 33255, 33274, 33275, 33278, 33281, + 33282, 33285, 33287, 33290, 33293, 33296, 33302, 33321, 33323, 33336, 33331, 33344, 33369, + 33368, 33373, 33370, 33375, 33380, 33378, 33384, 33386, 33387, 33326, 33393, 33399, 33400, + 33406, 33421, 33426, 33451, 33439, 33467, 33452, 33505, 33507, 33503, 33490, 33524, 33523, + 33530, 33683, 33539, 33531, 33529, 33502, 33542, 33500, 33545, 33497, 33589, 33588, 33558, + 33586, 33585, 33600, 33593, 33616, 33605, 33583, 33579, 33559, 33560, 33669, 33690, 33706, + 33695, 33698, 33686, 33571, 33678, 33671, 33674, 33660, 33717, 33651, 33653, 33696, 33673, + 33704, 33780, 33811, 33771, 33742, 33789, 33795, 33752, 33803, 33729, 33783, 33799, 33760, + 33778, 33805, 33826, 33824, 33725, 33848, 34054, 33787, 33901, 33834, 33852, 34138, 33924, + 33911, 33899, 33965, 33902, 33922, 33897, 33862, 33836, 33903, 33913, 33845, 33994, 33890, + 33977, 33983, 33951, 34009, 33997, 33979, 34010, 34000, 33985, 33990, 34006, 33953, 34081, + 34047, 34036, 34071, 34072, 34092, 34079, 34069, 34068, 34044, 34112, 34147, 34136, 34120, + 34113, 34306, 34123, 34133, 34176, 34212, 34184, 34193, 34186, 34216, 34157, 34196, 34203, + 34282, 34183, 34204, 34167, 34174, 34192, 34249, 34234, 34255, 34233, 34256, 34261, 34269, + 34277, 34268, 34297, 34314, 34323, 34315, 34302, 34298, 34310, 34338, 34330, 34352, 34367, + 34381, 20053, 34388, 34399, 34407, 34417, 34451, 34467, 34473, 34474, 34443, 34444, 34486, + 34479, 34500, 34502, 34480, 34505, 34851, 34475, 34516, 34526, 34537, 34540, 34527, 34523, + 34543, 34578, 34566, 34568, 34560, 34563, 34555, 34577, 34569, 34573, 34553, 34570, 34612, + 34623, 34615, 34619, 34597, 34601, 34586, 34656, 34655, 34680, 34636, 34638, 34676, 34647, + 34664, 34670, 34649, 34643, 34659, 34666, 34821, 34722, 34719, 34690, 34735, 34763, 34749, + 34752, 34768, 38614, 34731, 34756, 34739, 34759, 34758, 34747, 34799, 34802, 34784, 34831, + 34829, 34814, 34806, 34807, 34830, 34770, 34833, 34838, 34837, 34850, 34849, 34865, 34870, + 34873, 34855, 34875, 34884, 34882, 34898, 34905, 34910, 34914, 34923, 34945, 34942, 34974, + 34933, 34941, 34997, 34930, 34946, 34967, 34962, 34990, 34969, 34978, 34957, 34980, 34992, + 35007, 34993, 35011, 35012, 35028, 35032, 35033, 35037, 35065, 35074, 35068, 35060, 35048, + 35058, 35076, 35084, 35082, 35091, 35139, 35102, 35109, 35114, 35115, 35137, 35140, 35131, + 35126, 35128, 35148, 35101, 35168, 35166, 35174, 35172, 35181, 35178, 35183, 35188, 35191, + 35198, 35203, 35208, 35210, 35219, 35224, 35233, 35241, 35238, 35244, 35247, 35250, 35258, + 35261, 35263, 35264, 35290, 35292, 35293, 35303, 35316, 35320, 35331, 35350, 35344, 35340, + 35355, 35357, 35365, 35382, 35393, 35419, 35410, 35398, 35400, 35452, 35437, 35436, 35426, + 35461, 35458, 35460, 35496, 35489, 35473, 35493, 35494, 35482, 35491, 35524, 35533, 35522, + 35546, 35563, 35571, 35559, 35556, 35569, 35604, 35552, 35554, 35575, 35550, 35547, 35596, + 35591, 35610, 35553, 35606, 35600, 35607, 35616, 35635, 38827, 35622, 35627, 35646, 35624, + 35649, 35660, 35663, 35662, 35657, 35670, 35675, 35674, 35691, 35679, 35692, 35695, 35700, + 35709, 35712, 35724, 35726, 35730, 35731, 35734, 35737, 35738, 35898, 35905, 35903, 35912, + 35916, 35918, 35920, 35925, 35938, 35948, 35960, 35962, 35970, 35977, 35973, 35978, 35981, + 35982, 35988, 35964, 35992, 25117, 36013, 36010, 36029, 36018, 36019, 36014, 36022, 36040, + 36033, 36068, 36067, 36058, 36093, 36090, 36091, 36100, 36101, 36106, 36103, 36111, 36109, + 36112, 40782, 36115, 36045, 36116, 36118, 36199, 36205, 36209, 36211, 36225, 36249, 36290, + 36286, 36282, 36303, 36314, 36310, 36300, 36315, 36299, 36330, 36331, 36319, 36323, 36348, + 36360, 36361, 36351, 36381, 36382, 36368, 36383, 36418, 36405, 36400, 36404, 36426, 36423, + 36425, 36428, 36432, 36424, 36441, 36452, 36448, 36394, 36451, 36437, 36470, 36466, 36476, + 36481, 36487, 36485, 36484, 36491, 36490, 36499, 36497, 36500, 36505, 36522, 36513, 36524, + 36528, 36550, 36529, 36542, 36549, 36552, 36555, 36571, 36579, 36604, 36603, 36587, 36606, + 36618, 36613, 36629, 36626, 36633, 36627, 36636, 36639, 36635, 36620, 36646, 36659, 36667, + 36665, 36677, 36674, 36670, 36684, 36681, 36678, 36686, 36695, 36700, 36706, 36707, 36708, + 36764, 36767, 36771, 36781, 36783, 36791, 36826, 36837, 36834, 36842, 36847, 36999, 36852, + 36869, 36857, 36858, 36881, 36885, 36897, 36877, 36894, 36886, 36875, 36903, 36918, 36917, + 36921, 36856, 36943, 36944, 36945, 36946, 36878, 36937, 36926, 36950, 36952, 36958, 36968, + 36975, 36982, 38568, 36978, 36994, 36989, 36993, 36992, 37002, 37001, 37007, 37032, 37039, + 37041, 37045, 37090, 37092, 25160, 37083, 37122, 37138, 37145, 37170, 37168, 37194, 37206, + 37208, 37219, 37221, 37225, 37235, 37234, 37259, 37257, 37250, 37282, 37291, 37295, 37290, + 37301, 37300, 37306, 37312, 37313, 37321, 37323, 37328, 37334, 37343, 37345, 37339, 37372, + 37365, 37366, 37406, 37375, 37396, 37420, 37397, 37393, 37470, 37463, 37445, 37449, 37476, + 37448, 37525, 37439, 37451, 37456, 37532, 37526, 37523, 37531, 37466, 37583, 37561, 37559, + 37609, 37647, 37626, 37700, 37678, 37657, 37666, 37658, 37667, 37690, 37685, 37691, 37724, + 37728, 37756, 37742, 37718, 37808, 37804, 37805, 37780, 37817, 37846, 37847, 37864, 37861, + 37848, 37827, 37853, 37840, 37832, 37860, 37914, 37908, 37907, 37891, 37895, 37904, 37942, + 37931, 37941, 37921, 37946, 37953, 37970, 37956, 37979, 37984, 37986, 37982, 37994, 37417, + 38000, 38005, 38007, 38013, 37978, 38012, 38014, 38017, 38015, 38274, 38279, 38282, 38292, + 38294, 38296, 38297, 38304, 38312, 38311, 38317, 38332, 38331, 38329, 38334, 38346, 28662, + 38339, 38349, 38348, 38357, 38356, 38358, 38364, 38369, 38373, 38370, 38433, 38440, 38446, + 38447, 38466, 38476, 38479, 38475, 38519, 38492, 38494, 38493, 38495, 38502, 38514, 38508, + 38541, 38552, 38549, 38551, 38570, 38567, 38577, 38578, 38576, 38580, 38582, 38584, 38585, + 38606, 38603, 38601, 38605, 35149, 38620, 38669, 38613, 38649, 38660, 38662, 38664, 38675, + 38670, 38673, 38671, 38678, 38681, 38692, 38698, 38704, 38713, 38717, 38718, 38724, 38726, + 38728, 38722, 38729, 38748, 38752, 38756, 38758, 38760, 21202, 38763, 38769, 38777, 38789, + 38780, 38785, 38778, 38790, 38795, 38799, 38800, 38812, 38824, 38822, 38819, 38835, 38836, + 38851, 38854, 38856, 38859, 38876, 38893, 40783, 38898, 31455, 38902, 38901, 38927, 38924, + 38968, 38948, 38945, 38967, 38973, 38982, 38991, 38987, 39019, 39023, 39024, 39025, 39028, + 39027, 39082, 39087, 39089, 39094, 39108, 39107, 39110, 39145, 39147, 39171, 39177, 39186, + 39188, 39192, 39201, 39197, 39198, 39204, 39200, 39212, 39214, 39229, 39230, 39234, 39241, + 39237, 39248, 39243, 39249, 39250, 39244, 39253, 39319, 39320, 39333, 39341, 39342, 39356, + 39391, 39387, 39389, 39384, 39377, 39405, 39406, 39409, 39410, 39419, 39416, 39425, 39439, + 39429, 39394, 39449, 39467, 39479, 39493, 39490, 39488, 39491, 39486, 39509, 39501, 39515, + 39511, 39519, 39522, 39525, 39524, 39529, 39531, 39530, 39597, 39600, 39612, 39616, 39631, + 39633, 39635, 39636, 39646, 39647, 39650, 39651, 39654, 39663, 39659, 39662, 39668, 39665, + 39671, 39675, 39686, 39704, 39706, 39711, 39714, 39715, 39717, 39719, 39720, 39721, 39722, + 39726, 39727, 39730, 39748, 39747, 39759, 39757, 39758, 39761, 39768, 39796, 39827, 39811, + 39825, 39830, 39831, 39839, 39840, 39848, 39860, 39872, 39882, 39865, 39878, 39887, 39889, + 39890, 39907, 39906, 39908, 39892, 39905, 39994, 39922, 39921, 39920, 39957, 39956, 39945, + 39955, 39948, 39942, 39944, 39954, 39946, 39940, 39982, 39963, 39973, 39972, 39969, 39984, + 40007, 39986, 40006, 39998, 40026, 40032, 40039, 40054, 40056, 40167, 40172, 40176, 40201, + 40200, 40171, 40195, 40198, 40234, 40230, 40367, 40227, 40223, 40260, 40213, 40210, 40257, + 40255, 40254, 40262, 40264, 40285, 40286, 40292, 40273, 40272, 40281, 40306, 40329, 40327, + 40363, 40303, 40314, 40346, 40356, 40361, 40370, 40388, 40385, 40379, 40376, 40378, 40390, + 40399, 40386, 40409, 40403, 40440, 40422, 40429, 40431, 40445, 40474, 40475, 40478, 40565, + 40569, 40573, 40577, 40584, 40587, 40588, 40594, 40597, 40593, 40605, 40613, 40617, 40632, + 40618, 40621, 38753, 40652, 40654, 40655, 40656, 40660, 40668, 40670, 40669, 40672, 40677, + 40680, 40687, 40692, 40694, 40695, 40697, 40699, 40700, 40701, 40711, 40712, 30391, 40725, + 40737, 40748, 40766, 40778, 40786, 40788, 40803, 40799, 40800, 40801, 40806, 40807, 40812, + 40810, 40823, 40818, 40822, 40853, 40860, 40864, 22575, 27079, 36953, 29796, 20956, 29081, diff --git a/third_party/ulib/musl/src/locale/ksc.h b/third_party/ulib/musl/src/locale/ksc.h new file mode 100644 index 000000000..b6478dbc2 --- /dev/null +++ b/third_party/ulib/musl/src/locale/ksc.h @@ -0,0 +1,641 @@ +12288, 12289, 12290, 183, 8229, 8230, 168, 12291, 173, 8213, 8741, 65340, 8764, 8216, 8217, 8220, + 8221, 12308, 12309, 12296, 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 177, + 215, 247, 8800, 8804, 8805, 8734, 8756, 176, 8242, 8243, 8451, 8491, 65504, 65505, 65509, 9794, + 9792, 8736, 8869, 8978, 8706, 8711, 8801, 8786, 167, 8251, 9734, 9733, 9675, 9679, 9678, 9671, + 9670, 9633, 9632, 9651, 9650, 9661, 9660, 8594, 8592, 8593, 8595, 8596, 12307, 8810, 8811, 8730, + 8765, 8733, 8757, 8747, 8748, 8712, 8715, 8838, 8839, 8834, 8835, 8746, 8745, 8743, 8744, 65506, + 8658, 8660, 8704, 8707, 180, 65374, 711, 728, 733, 730, 729, 184, 731, 161, 191, 720, 8750, + 8721, 8719, 164, 8457, 8240, 9665, 9664, 9655, 9654, 9828, 9824, 9825, 9829, 9831, 9827, 8857, + 9672, 9635, 9680, 9681, 9618, 9636, 9637, 9640, 9639, 9638, 9641, 9832, 9743, 9742, 9756, 9758, + 182, 8224, 8225, 8597, 8599, 8601, 8598, 8600, 9837, 9833, 9834, 9836, 12927, 12828, 8470, + 13255, 8482, 13250, 13272, 8481, 8364, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65281, 65282, 65283, 65284, 65285, 65286, 65287, 65288, 65289, 65290, 65291, + 65292, 65293, 65294, 65295, 65296, 65297, 65298, 65299, 65300, 65301, 65302, 65303, 65304, + 65305, 65306, 65307, 65308, 65309, 65310, 65311, 65312, 65313, 65314, 65315, 65316, 65317, + 65318, 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, + 65331, 65332, 65333, 65334, 65335, 65336, 65337, 65338, 65339, 65510, 65341, 65342, 65343, + 65344, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, + 65357, 65358, 65359, 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, + 65370, 65371, 65372, 65373, 65507, 12593, 12594, 12595, 12596, 12597, 12598, 12599, 12600, + 12601, 12602, 12603, 12604, 12605, 12606, 12607, 12608, 12609, 12610, 12611, 12612, 12613, + 12614, 12615, 12616, 12617, 12618, 12619, 12620, 12621, 12622, 12623, 12624, 12625, 12626, + 12627, 12628, 12629, 12630, 12631, 12632, 12633, 12634, 12635, 12636, 12637, 12638, 12639, + 12640, 12641, 12642, 12643, 12644, 12645, 12646, 12647, 12648, 12649, 12650, 12651, 12652, + 12653, 12654, 12655, 12656, 12657, 12658, 12659, 12660, 12661, 12662, 12663, 12664, 12665, + 12666, 12667, 12668, 12669, 12670, 12671, 12672, 12673, 12674, 12675, 12676, 12677, 12678, + 12679, 12680, 12681, 12682, 12683, 12684, 12685, 12686, 8560, 8561, 8562, 8563, 8564, 8565, + 8566, 8567, 8568, 8569, 0, 0, 0, 0, 0, 8544, 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, + 8553, 0, 0, 0, 0, 0, 0, 0, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, + 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 0, 0, 0, 0, 0, 0, 0, 0, 945, 946, 947, 948, + 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967, 968, + 969, 0, 0, 0, 0, 0, 0, 9472, 9474, 9484, 9488, 9496, 9492, 9500, 9516, 9508, 9524, 9532, 9473, + 9475, 9487, 9491, 9499, 9495, 9507, 9523, 9515, 9531, 9547, 9504, 9519, 9512, 9527, 9535, 9501, + 9520, 9509, 9528, 9538, 9490, 9489, 9498, 9497, 9494, 9493, 9486, 9485, 9502, 9503, 9505, 9506, + 9510, 9511, 9513, 9514, 9517, 9518, 9521, 9522, 9525, 9526, 9529, 9530, 9533, 9534, 9536, 9537, + 9539, 9540, 9541, 9542, 9543, 9544, 9545, 9546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13205, 13206, 13207, 8467, 13208, 13252, 13219, 13220, 13221, + 13222, 13209, 13210, 13211, 13212, 13213, 13214, 13215, 13216, 13217, 13218, 13258, 13197, + 13198, 13199, 13263, 13192, 13193, 13256, 13223, 13224, 13232, 13233, 13234, 13235, 13236, + 13237, 13238, 13239, 13240, 13241, 13184, 13185, 13186, 13187, 13188, 13242, 13243, 13244, + 13245, 13246, 13247, 13200, 13201, 13202, 13203, 13204, 8486, 13248, 13249, 13194, 13195, 13196, + 13270, 13253, 13229, 13230, 13231, 13275, 13225, 13226, 13227, 13228, 13277, 13264, 13267, + 13251, 13257, 13276, 13254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 198, 208, 170, 294, 0, + 306, 0, 319, 321, 216, 338, 186, 222, 358, 330, 0, 12896, 12897, 12898, 12899, 12900, 12901, + 12902, 12903, 12904, 12905, 12906, 12907, 12908, 12909, 12910, 12911, 12912, 12913, 12914, + 12915, 12916, 12917, 12918, 12919, 12920, 12921, 12922, 12923, 9424, 9425, 9426, 9427, 9428, + 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441, 9442, 9443, 9444, + 9445, 9446, 9447, 9448, 9449, 9312, 9313, 9314, 9315, 9316, 9317, 9318, 9319, 9320, 9321, 9322, + 9323, 9324, 9325, 9326, 189, 8531, 8532, 188, 190, 8539, 8540, 8541, 8542, 230, 273, 240, 295, + 305, 307, 312, 320, 322, 248, 339, 223, 254, 359, 331, 329, 12800, 12801, 12802, 12803, 12804, + 12805, 12806, 12807, 12808, 12809, 12810, 12811, 12812, 12813, 12814, 12815, 12816, 12817, + 12818, 12819, 12820, 12821, 12822, 12823, 12824, 12825, 12826, 12827, 9372, 9373, 9374, 9375, + 9376, 9377, 9378, 9379, 9380, 9381, 9382, 9383, 9384, 9385, 9386, 9387, 9388, 9389, 9390, 9391, + 9392, 9393, 9394, 9395, 9396, 9397, 9332, 9333, 9334, 9335, 9336, 9337, 9338, 9339, 9340, 9341, + 9342, 9343, 9344, 9345, 9346, 185, 178, 179, 8308, 8319, 8321, 8322, 8323, 8324, 12353, 12354, + 12355, 12356, 12357, 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, 12367, + 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, + 12381, 12382, 12383, 12384, 12385, 12386, 12387, 12388, 12389, 12390, 12391, 12392, 12393, + 12394, 12395, 12396, 12397, 12398, 12399, 12400, 12401, 12402, 12403, 12404, 12405, 12406, + 12407, 12408, 12409, 12410, 12411, 12412, 12413, 12414, 12415, 12416, 12417, 12418, 12419, + 12420, 12421, 12422, 12423, 12424, 12425, 12426, 12427, 12428, 12429, 12430, 12431, 12432, + 12433, 12434, 12435, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12449, 12450, 12451, 12452, 12453, 12454, + 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, 12467, + 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, + 12481, 12482, 12483, 12484, 12485, 12486, 12487, 12488, 12489, 12490, 12491, 12492, 12493, + 12494, 12495, 12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, + 12507, 12508, 12509, 12510, 12511, 12512, 12513, 12514, 12515, 12516, 12517, 12518, 12519, + 12520, 12521, 12522, 12523, 12524, 12525, 12526, 12527, 12528, 12529, 12530, 12531, 12532, + 12533, 12534, 0, 0, 0, 0, 0, 0, 0, 0, 1040, 1041, 1042, 1043, 1044, 1045, 1025, 1046, 1047, + 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, + 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1072, 1073, 1074, 1075, 1076, 1077, 1105, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, + 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, + 1103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 44032, 44033, 44036, 44039, 44040, 44041, 44042, 44048, 44049, 44050, + 44051, 44052, 44053, 44054, 44055, 44057, 44058, 44059, 44060, 44061, 44064, 44068, 44076, + 44077, 44079, 44080, 44081, 44088, 44089, 44092, 44096, 44107, 44109, 44116, 44120, 44124, + 44144, 44145, 44148, 44151, 44152, 44154, 44160, 44161, 44163, 44164, 44165, 44166, 44169, + 44170, 44171, 44172, 44176, 44180, 44188, 44189, 44191, 44192, 44193, 44200, 44201, 44202, + 44204, 44207, 44208, 44216, 44217, 44219, 44220, 44221, 44225, 44228, 44232, 44236, 44245, + 44247, 44256, 44257, 44260, 44263, 44264, 44266, 44268, 44271, 44272, 44273, 44275, 44277, + 44278, 44284, 44285, 44288, 44292, 44294, 44300, 44301, 44303, 44305, 44312, 44316, 44320, + 44329, 44332, 44333, 44340, 44341, 44344, 44348, 44356, 44357, 44359, 44361, 44368, 44372, + 44376, 44385, 44387, 44396, 44397, 44400, 44403, 44404, 44405, 44406, 44411, 44412, 44413, + 44415, 44417, 44418, 44424, 44425, 44428, 44432, 44444, 44445, 44452, 44471, 44480, 44481, + 44484, 44488, 44496, 44497, 44499, 44508, 44512, 44516, 44536, 44537, 44540, 44543, 44544, + 44545, 44552, 44553, 44555, 44557, 44564, 44592, 44593, 44596, 44599, 44600, 44602, 44608, + 44609, 44611, 44613, 44614, 44618, 44620, 44621, 44622, 44624, 44628, 44630, 44636, 44637, + 44639, 44640, 44641, 44645, 44648, 44649, 44652, 44656, 44664, 44665, 44667, 44668, 44669, + 44676, 44677, 44684, 44732, 44733, 44734, 44736, 44740, 44748, 44749, 44751, 44752, 44753, + 44760, 44761, 44764, 44776, 44779, 44781, 44788, 44792, 44796, 44807, 44808, 44813, 44816, + 44844, 44845, 44848, 44850, 44852, 44860, 44861, 44863, 44865, 44866, 44867, 44872, 44873, + 44880, 44892, 44893, 44900, 44901, 44921, 44928, 44932, 44936, 44944, 44945, 44949, 44956, + 44984, 44985, 44988, 44992, 44999, 45000, 45001, 45003, 45005, 45006, 45012, 45020, 45032, + 45033, 45040, 45041, 45044, 45048, 45056, 45057, 45060, 45068, 45072, 45076, 45084, 45085, + 45096, 45124, 45125, 45128, 45130, 45132, 45134, 45139, 45140, 45141, 45143, 45145, 45149, + 45180, 45181, 45184, 45188, 45196, 45197, 45199, 45201, 45208, 45209, 45210, 45212, 45215, + 45216, 45217, 45218, 45224, 45225, 45227, 45228, 45229, 45230, 45231, 45233, 45235, 45236, + 45237, 45240, 45244, 45252, 45253, 45255, 45256, 45257, 45264, 45265, 45268, 45272, 45280, + 45285, 45320, 45321, 45323, 45324, 45328, 45330, 45331, 45336, 45337, 45339, 45340, 45341, + 45347, 45348, 45349, 45352, 45356, 45364, 45365, 45367, 45368, 45369, 45376, 45377, 45380, + 45384, 45392, 45393, 45396, 45397, 45400, 45404, 45408, 45432, 45433, 45436, 45440, 45442, + 45448, 45449, 45451, 45453, 45458, 45459, 45460, 45464, 45468, 45480, 45516, 45520, 45524, + 45532, 45533, 45535, 45544, 45545, 45548, 45552, 45561, 45563, 45565, 45572, 45573, 45576, + 45579, 45580, 45588, 45589, 45591, 45593, 45600, 45620, 45628, 45656, 45660, 45664, 45672, + 45673, 45684, 45685, 45692, 45700, 45701, 45705, 45712, 45713, 45716, 45720, 45721, 45722, + 45728, 45729, 45731, 45733, 45734, 45738, 45740, 45744, 45748, 45768, 45769, 45772, 45776, + 45778, 45784, 45785, 45787, 45789, 45794, 45796, 45797, 45798, 45800, 45803, 45804, 45805, + 45806, 45807, 45811, 45812, 45813, 45815, 45816, 45817, 45818, 45819, 45823, 45824, 45825, + 45828, 45832, 45840, 45841, 45843, 45844, 45845, 45852, 45908, 45909, 45910, 45912, 45915, + 45916, 45918, 45919, 45924, 45925, 45927, 45929, 45931, 45934, 45936, 45937, 45940, 45944, + 45952, 45953, 45955, 45956, 45957, 45964, 45968, 45972, 45984, 45985, 45992, 45996, 46020, + 46021, 46024, 46027, 46028, 46030, 46032, 46036, 46037, 46039, 46041, 46043, 46045, 46048, + 46052, 46056, 46076, 46096, 46104, 46108, 46112, 46120, 46121, 46123, 46132, 46160, 46161, + 46164, 46168, 46176, 46177, 46179, 46181, 46188, 46208, 46216, 46237, 46244, 46248, 46252, + 46261, 46263, 46265, 46272, 46276, 46280, 46288, 46293, 46300, 46301, 46304, 46307, 46308, + 46310, 46316, 46317, 46319, 46321, 46328, 46356, 46357, 46360, 46363, 46364, 46372, 46373, + 46375, 46376, 46377, 46378, 46384, 46385, 46388, 46392, 46400, 46401, 46403, 46404, 46405, + 46411, 46412, 46413, 46416, 46420, 46428, 46429, 46431, 46432, 46433, 46496, 46497, 46500, + 46504, 46506, 46507, 46512, 46513, 46515, 46516, 46517, 46523, 46524, 46525, 46528, 46532, + 46540, 46541, 46543, 46544, 46545, 46552, 46572, 46608, 46609, 46612, 46616, 46629, 46636, + 46644, 46664, 46692, 46696, 46748, 46749, 46752, 46756, 46763, 46764, 46769, 46804, 46832, + 46836, 46840, 46848, 46849, 46853, 46888, 46889, 46892, 46895, 46896, 46904, 46905, 46907, + 46916, 46920, 46924, 46932, 46933, 46944, 46948, 46952, 46960, 46961, 46963, 46965, 46972, + 46973, 46976, 46980, 46988, 46989, 46991, 46992, 46993, 46994, 46998, 46999, 47000, 47001, + 47004, 47008, 47016, 47017, 47019, 47020, 47021, 47028, 47029, 47032, 47047, 47049, 47084, + 47085, 47088, 47092, 47100, 47101, 47103, 47104, 47105, 47111, 47112, 47113, 47116, 47120, + 47128, 47129, 47131, 47133, 47140, 47141, 47144, 47148, 47156, 47157, 47159, 47160, 47161, + 47168, 47172, 47185, 47187, 47196, 47197, 47200, 47204, 47212, 47213, 47215, 47217, 47224, + 47228, 47245, 47272, 47280, 47284, 47288, 47296, 47297, 47299, 47301, 47308, 47312, 47316, + 47325, 47327, 47329, 47336, 47337, 47340, 47344, 47352, 47353, 47355, 47357, 47364, 47384, + 47392, 47420, 47421, 47424, 47428, 47436, 47439, 47441, 47448, 47449, 47452, 47456, 47464, + 47465, 47467, 47469, 47476, 47477, 47480, 47484, 47492, 47493, 47495, 47497, 47498, 47501, + 47502, 47532, 47533, 47536, 47540, 47548, 47549, 47551, 47553, 47560, 47561, 47564, 47566, + 47567, 47568, 47569, 47570, 47576, 47577, 47579, 47581, 47582, 47585, 47587, 47588, 47589, + 47592, 47596, 47604, 47605, 47607, 47608, 47609, 47610, 47616, 47617, 47624, 47637, 47672, + 47673, 47676, 47680, 47682, 47688, 47689, 47691, 47693, 47694, 47699, 47700, 47701, 47704, + 47708, 47716, 47717, 47719, 47720, 47721, 47728, 47729, 47732, 47736, 47747, 47748, 47749, + 47751, 47756, 47784, 47785, 47787, 47788, 47792, 47794, 47800, 47801, 47803, 47805, 47812, + 47816, 47832, 47833, 47868, 47872, 47876, 47885, 47887, 47889, 47896, 47900, 47904, 47913, + 47915, 47924, 47925, 47926, 47928, 47931, 47932, 47933, 47934, 47940, 47941, 47943, 47945, + 47949, 47951, 47952, 47956, 47960, 47969, 47971, 47980, 48008, 48012, 48016, 48036, 48040, + 48044, 48052, 48055, 48064, 48068, 48072, 48080, 48083, 48120, 48121, 48124, 48127, 48128, + 48130, 48136, 48137, 48139, 48140, 48141, 48143, 48145, 48148, 48149, 48150, 48151, 48152, + 48155, 48156, 48157, 48158, 48159, 48164, 48165, 48167, 48169, 48173, 48176, 48177, 48180, + 48184, 48192, 48193, 48195, 48196, 48197, 48201, 48204, 48205, 48208, 48221, 48260, 48261, + 48264, 48267, 48268, 48270, 48276, 48277, 48279, 48281, 48282, 48288, 48289, 48292, 48295, + 48296, 48304, 48305, 48307, 48308, 48309, 48316, 48317, 48320, 48324, 48333, 48335, 48336, + 48337, 48341, 48344, 48348, 48372, 48373, 48374, 48376, 48380, 48388, 48389, 48391, 48393, + 48400, 48404, 48420, 48428, 48448, 48456, 48457, 48460, 48464, 48472, 48473, 48484, 48488, + 48512, 48513, 48516, 48519, 48520, 48521, 48522, 48528, 48529, 48531, 48533, 48537, 48538, + 48540, 48548, 48560, 48568, 48596, 48597, 48600, 48604, 48617, 48624, 48628, 48632, 48640, + 48643, 48645, 48652, 48653, 48656, 48660, 48668, 48669, 48671, 48708, 48709, 48712, 48716, + 48718, 48724, 48725, 48727, 48729, 48730, 48731, 48736, 48737, 48740, 48744, 48746, 48752, + 48753, 48755, 48756, 48757, 48763, 48764, 48765, 48768, 48772, 48780, 48781, 48783, 48784, + 48785, 48792, 48793, 48808, 48848, 48849, 48852, 48855, 48856, 48864, 48867, 48868, 48869, + 48876, 48897, 48904, 48905, 48920, 48921, 48923, 48924, 48925, 48960, 48961, 48964, 48968, + 48976, 48977, 48981, 49044, 49072, 49093, 49100, 49101, 49104, 49108, 49116, 49119, 49121, + 49212, 49233, 49240, 49244, 49248, 49256, 49257, 49296, 49297, 49300, 49304, 49312, 49313, + 49315, 49317, 49324, 49325, 49327, 49328, 49331, 49332, 49333, 49334, 49340, 49341, 49343, + 49344, 49345, 49349, 49352, 49353, 49356, 49360, 49368, 49369, 49371, 49372, 49373, 49380, + 49381, 49384, 49388, 49396, 49397, 49399, 49401, 49408, 49412, 49416, 49424, 49429, 49436, + 49437, 49438, 49439, 49440, 49443, 49444, 49446, 49447, 49452, 49453, 49455, 49456, 49457, + 49462, 49464, 49465, 49468, 49472, 49480, 49481, 49483, 49484, 49485, 49492, 49493, 49496, + 49500, 49508, 49509, 49511, 49512, 49513, 49520, 49524, 49528, 49541, 49548, 49549, 49550, + 49552, 49556, 49558, 49564, 49565, 49567, 49569, 49573, 49576, 49577, 49580, 49584, 49597, + 49604, 49608, 49612, 49620, 49623, 49624, 49632, 49636, 49640, 49648, 49649, 49651, 49660, + 49661, 49664, 49668, 49676, 49677, 49679, 49681, 49688, 49689, 49692, 49695, 49696, 49704, + 49705, 49707, 49709, 49711, 49713, 49714, 49716, 49736, 49744, 49745, 49748, 49752, 49760, + 49765, 49772, 49773, 49776, 49780, 49788, 49789, 49791, 49793, 49800, 49801, 49808, 49816, + 49819, 49821, 49828, 49829, 49832, 49836, 49837, 49844, 49845, 49847, 49849, 49884, 49885, + 49888, 49891, 49892, 49899, 49900, 49901, 49903, 49905, 49910, 49912, 49913, 49915, 49916, + 49920, 49928, 49929, 49932, 49933, 49939, 49940, 49941, 49944, 49948, 49956, 49957, 49960, + 49961, 49989, 50024, 50025, 50028, 50032, 50034, 50040, 50041, 50044, 50045, 50052, 50056, + 50060, 50112, 50136, 50137, 50140, 50143, 50144, 50146, 50152, 50153, 50157, 50164, 50165, + 50168, 50184, 50192, 50212, 50220, 50224, 50228, 50236, 50237, 50248, 50276, 50277, 50280, + 50284, 50292, 50293, 50297, 50304, 50324, 50332, 50360, 50364, 50409, 50416, 50417, 50420, + 50424, 50426, 50431, 50432, 50433, 50444, 50448, 50452, 50460, 50472, 50473, 50476, 50480, + 50488, 50489, 50491, 50493, 50500, 50501, 50504, 50505, 50506, 50508, 50509, 50510, 50515, + 50516, 50517, 50519, 50520, 50521, 50525, 50526, 50528, 50529, 50532, 50536, 50544, 50545, + 50547, 50548, 50549, 50556, 50557, 50560, 50564, 50567, 50572, 50573, 50575, 50577, 50581, + 50583, 50584, 50588, 50592, 50601, 50612, 50613, 50616, 50617, 50619, 50620, 50621, 50622, + 50628, 50629, 50630, 50631, 50632, 50633, 50634, 50636, 50638, 50640, 50641, 50644, 50648, + 50656, 50657, 50659, 50661, 50668, 50669, 50670, 50672, 50676, 50678, 50679, 50684, 50685, + 50686, 50687, 50688, 50689, 50693, 50694, 50695, 50696, 50700, 50704, 50712, 50713, 50715, + 50716, 50724, 50725, 50728, 50732, 50733, 50734, 50736, 50739, 50740, 50741, 50743, 50745, + 50747, 50752, 50753, 50756, 50760, 50768, 50769, 50771, 50772, 50773, 50780, 50781, 50784, + 50796, 50799, 50801, 50808, 50809, 50812, 50816, 50824, 50825, 50827, 50829, 50836, 50837, + 50840, 50844, 50852, 50853, 50855, 50857, 50864, 50865, 50868, 50872, 50873, 50874, 50880, + 50881, 50883, 50885, 50892, 50893, 50896, 50900, 50908, 50909, 50912, 50913, 50920, 50921, + 50924, 50928, 50936, 50937, 50941, 50948, 50949, 50952, 50956, 50964, 50965, 50967, 50969, + 50976, 50977, 50980, 50984, 50992, 50993, 50995, 50997, 50999, 51004, 51005, 51008, 51012, + 51018, 51020, 51021, 51023, 51025, 51026, 51027, 51028, 51029, 51030, 51031, 51032, 51036, + 51040, 51048, 51051, 51060, 51061, 51064, 51068, 51069, 51070, 51075, 51076, 51077, 51079, + 51080, 51081, 51082, 51086, 51088, 51089, 51092, 51094, 51095, 51096, 51098, 51104, 51105, + 51107, 51108, 51109, 51110, 51116, 51117, 51120, 51124, 51132, 51133, 51135, 51136, 51137, + 51144, 51145, 51148, 51150, 51152, 51160, 51165, 51172, 51176, 51180, 51200, 51201, 51204, + 51208, 51210, 51216, 51217, 51219, 51221, 51222, 51228, 51229, 51232, 51236, 51244, 51245, + 51247, 51249, 51256, 51260, 51264, 51272, 51273, 51276, 51277, 51284, 51312, 51313, 51316, + 51320, 51322, 51328, 51329, 51331, 51333, 51334, 51335, 51339, 51340, 51341, 51348, 51357, + 51359, 51361, 51368, 51388, 51389, 51396, 51400, 51404, 51412, 51413, 51415, 51417, 51424, + 51425, 51428, 51445, 51452, 51453, 51456, 51460, 51461, 51462, 51468, 51469, 51471, 51473, + 51480, 51500, 51508, 51536, 51537, 51540, 51544, 51552, 51553, 51555, 51564, 51568, 51572, + 51580, 51592, 51593, 51596, 51600, 51608, 51609, 51611, 51613, 51648, 51649, 51652, 51655, + 51656, 51658, 51664, 51665, 51667, 51669, 51670, 51673, 51674, 51676, 51677, 51680, 51682, + 51684, 51687, 51692, 51693, 51695, 51696, 51697, 51704, 51705, 51708, 51712, 51720, 51721, + 51723, 51724, 51725, 51732, 51736, 51753, 51788, 51789, 51792, 51796, 51804, 51805, 51807, + 51808, 51809, 51816, 51837, 51844, 51864, 51900, 51901, 51904, 51908, 51916, 51917, 51919, + 51921, 51923, 51928, 51929, 51936, 51948, 51956, 51976, 51984, 51988, 51992, 52000, 52001, + 52033, 52040, 52041, 52044, 52048, 52056, 52057, 52061, 52068, 52088, 52089, 52124, 52152, + 52180, 52196, 52199, 52201, 52236, 52237, 52240, 52244, 52252, 52253, 52257, 52258, 52263, + 52264, 52265, 52268, 52270, 52272, 52280, 52281, 52283, 52284, 52285, 52286, 52292, 52293, + 52296, 52300, 52308, 52309, 52311, 52312, 52313, 52320, 52324, 52326, 52328, 52336, 52341, + 52376, 52377, 52380, 52384, 52392, 52393, 52395, 52396, 52397, 52404, 52405, 52408, 52412, + 52420, 52421, 52423, 52425, 52432, 52436, 52452, 52460, 52464, 52481, 52488, 52489, 52492, + 52496, 52504, 52505, 52507, 52509, 52516, 52520, 52524, 52537, 52572, 52576, 52580, 52588, + 52589, 52591, 52593, 52600, 52616, 52628, 52629, 52632, 52636, 52644, 52645, 52647, 52649, + 52656, 52676, 52684, 52688, 52712, 52716, 52720, 52728, 52729, 52731, 52733, 52740, 52744, + 52748, 52756, 52761, 52768, 52769, 52772, 52776, 52784, 52785, 52787, 52789, 52824, 52825, + 52828, 52831, 52832, 52833, 52840, 52841, 52843, 52845, 52852, 52853, 52856, 52860, 52868, + 52869, 52871, 52873, 52880, 52881, 52884, 52888, 52896, 52897, 52899, 52900, 52901, 52908, + 52909, 52929, 52964, 52965, 52968, 52971, 52972, 52980, 52981, 52983, 52984, 52985, 52992, + 52993, 52996, 53000, 53008, 53009, 53011, 53013, 53020, 53024, 53028, 53036, 53037, 53039, + 53040, 53041, 53048, 53076, 53077, 53080, 53084, 53092, 53093, 53095, 53097, 53104, 53105, + 53108, 53112, 53120, 53125, 53132, 53153, 53160, 53168, 53188, 53216, 53217, 53220, 53224, + 53232, 53233, 53235, 53237, 53244, 53248, 53252, 53265, 53272, 53293, 53300, 53301, 53304, + 53308, 53316, 53317, 53319, 53321, 53328, 53332, 53336, 53344, 53356, 53357, 53360, 53364, + 53372, 53373, 53377, 53412, 53413, 53416, 53420, 53428, 53429, 53431, 53433, 53440, 53441, + 53444, 53448, 53449, 53456, 53457, 53459, 53460, 53461, 53468, 53469, 53472, 53476, 53484, + 53485, 53487, 53488, 53489, 53496, 53517, 53552, 53553, 53556, 53560, 53562, 53568, 53569, + 53571, 53572, 53573, 53580, 53581, 53584, 53588, 53596, 53597, 53599, 53601, 53608, 53612, + 53628, 53636, 53640, 53664, 53665, 53668, 53672, 53680, 53681, 53683, 53685, 53690, 53692, + 53696, 53720, 53748, 53752, 53767, 53769, 53776, 53804, 53805, 53808, 53812, 53820, 53821, + 53823, 53825, 53832, 53852, 53860, 53888, 53889, 53892, 53896, 53904, 53905, 53909, 53916, + 53920, 53924, 53932, 53937, 53944, 53945, 53948, 53951, 53952, 53954, 53960, 53961, 53963, + 53972, 53976, 53980, 53988, 53989, 54000, 54001, 54004, 54008, 54016, 54017, 54019, 54021, + 54028, 54029, 54030, 54032, 54036, 54038, 54044, 54045, 54047, 54048, 54049, 54053, 54056, + 54057, 54060, 54064, 54072, 54073, 54075, 54076, 54077, 54084, 54085, 54140, 54141, 54144, + 54148, 54156, 54157, 54159, 54160, 54161, 54168, 54169, 54172, 54176, 54184, 54185, 54187, + 54189, 54196, 54200, 54204, 54212, 54213, 54216, 54217, 54224, 54232, 54241, 54243, 54252, + 54253, 54256, 54260, 54268, 54269, 54271, 54273, 54280, 54301, 54336, 54340, 54364, 54368, + 54372, 54381, 54383, 54392, 54393, 54396, 54399, 54400, 54402, 54408, 54409, 54411, 54413, + 54420, 54441, 54476, 54480, 54484, 54492, 54495, 54504, 54508, 54512, 54520, 54523, 54525, + 54532, 54536, 54540, 54548, 54549, 54551, 54588, 54589, 54592, 54596, 54604, 54605, 54607, + 54609, 54616, 54617, 54620, 54624, 54629, 54632, 54633, 54635, 54637, 54644, 54645, 54648, + 54652, 54660, 54661, 54663, 54664, 54665, 54672, 54693, 54728, 54729, 54732, 54736, 54738, + 54744, 54745, 54747, 54749, 54756, 54757, 54760, 54764, 54772, 54773, 54775, 54777, 54784, + 54785, 54788, 54792, 54800, 54801, 54803, 54804, 54805, 54812, 54816, 54820, 54829, 54840, + 54841, 54844, 54848, 54853, 54856, 54857, 54859, 54861, 54865, 54868, 54869, 54872, 54876, + 54887, 54889, 54896, 54897, 54900, 54915, 54917, 54924, 54925, 54928, 54932, 54941, 54943, + 54945, 54952, 54956, 54960, 54969, 54971, 54980, 54981, 54984, 54988, 54993, 54996, 54999, + 55001, 55008, 55012, 55016, 55024, 55029, 55036, 55037, 55040, 55044, 55057, 55064, 55065, + 55068, 55072, 55080, 55081, 55083, 55085, 55092, 55093, 55096, 55100, 55108, 55111, 55113, + 55120, 55121, 55124, 55126, 55127, 55128, 55129, 55136, 55137, 55139, 55141, 55145, 55148, + 55152, 55156, 55164, 55165, 55169, 55176, 55177, 55180, 55184, 55192, 55193, 55195, 55197, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20285, + 20339, 20551, 20729, 21152, 21487, 21621, 21733, 22025, 23233, 23478, 26247, 26550, 26551, + 26607, 27468, 29634, 30146, 31292, 33499, 33540, 34903, 34952, 35382, 36040, 36303, 36603, + 36838, 39381, 21051, 21364, 21508, 24682, 24932, 27580, 29647, 33050, 35258, 35282, 38307, + 20355, 21002, 22718, 22904, 23014, 24178, 24185, 25031, 25536, 26438, 26604, 26751, 28567, + 30286, 30475, 30965, 31240, 31487, 31777, 32925, 33390, 33393, 35563, 38291, 20075, 21917, + 26359, 28212, 30883, 31469, 33883, 35088, 34638, 38824, 21208, 22350, 22570, 23884, 24863, + 25022, 25121, 25954, 26577, 27204, 28187, 29976, 30131, 30435, 30640, 32058, 37039, 37969, + 37970, 40853, 21283, 23724, 30002, 32987, 37440, 38296, 21083, 22536, 23004, 23713, 23831, + 24247, 24378, 24394, 24951, 27743, 30074, 30086, 31968, 32115, 32177, 32652, 33108, 33313, + 34193, 35137, 35611, 37628, 38477, 40007, 20171, 20215, 20491, 20977, 22607, 24887, 24894, + 24936, 25913, 27114, 28433, 30117, 30342, 30422, 31623, 33445, 33995, 63744, 37799, 38283, + 21888, 23458, 22353, 63745, 31923, 32697, 37301, 20520, 21435, 23621, 24040, 25298, 25454, + 25818, 25831, 28192, 28844, 31067, 36317, 36382, 63746, 36989, 37445, 37624, 20094, 20214, + 20581, 24062, 24314, 24838, 26967, 33137, 34388, 36423, 37749, 39467, 20062, 20625, 26480, + 26688, 20745, 21133, 21138, 27298, 30652, 37392, 40660, 21163, 24623, 36850, 20552, 25001, + 25581, 25802, 26684, 27268, 28608, 33160, 35233, 38548, 22533, 29309, 29356, 29956, 32121, + 32365, 32937, 35211, 35700, 36963, 40273, 25225, 27770, 28500, 32080, 32570, 35363, 20860, + 24906, 31645, 35609, 37463, 37772, 20140, 20435, 20510, 20670, 20742, 21185, 21197, 21375, + 22384, 22659, 24218, 24465, 24950, 25004, 25806, 25964, 26223, 26299, 26356, 26775, 28039, + 28805, 28913, 29855, 29861, 29898, 30169, 30828, 30956, 31455, 31478, 32069, 32147, 32789, + 32831, 33051, 33686, 35686, 36629, 36885, 37857, 38915, 38968, 39514, 39912, 20418, 21843, + 22586, 22865, 23395, 23622, 24760, 25106, 26690, 26800, 26856, 28330, 30028, 30328, 30926, + 31293, 31995, 32363, 32380, 35336, 35489, 35903, 38542, 40388, 21476, 21481, 21578, 21617, + 22266, 22993, 23396, 23611, 24235, 25335, 25911, 25925, 25970, 26272, 26543, 27073, 27837, + 30204, 30352, 30590, 31295, 32660, 32771, 32929, 33167, 33510, 33533, 33776, 34241, 34865, + 34996, 35493, 63747, 36764, 37678, 38599, 39015, 39640, 40723, 21741, 26011, 26354, 26767, + 31296, 35895, 40288, 22256, 22372, 23825, 26118, 26801, 26829, 28414, 29736, 34974, 39908, + 27752, 63748, 39592, 20379, 20844, 20849, 21151, 23380, 24037, 24656, 24685, 25329, 25511, + 25915, 29657, 31354, 34467, 36002, 38799, 20018, 23521, 25096, 26524, 29916, 31185, 33747, + 35463, 35506, 36328, 36942, 37707, 38982, 24275, 27112, 34303, 37101, 63749, 20896, 23448, + 23532, 24931, 26874, 27454, 28748, 29743, 29912, 31649, 32592, 33733, 35264, 36011, 38364, + 39208, 21038, 24669, 25324, 36866, 20362, 20809, 21281, 22745, 24291, 26336, 27960, 28826, + 29378, 29654, 31568, 33009, 37979, 21350, 25499, 32619, 20054, 20608, 22602, 22750, 24618, + 24871, 25296, 27088, 39745, 23439, 32024, 32945, 36703, 20132, 20689, 21676, 21932, 23308, + 23968, 24039, 25898, 25934, 26657, 27211, 29409, 30350, 30703, 32094, 32761, 33184, 34126, + 34527, 36611, 36686, 37066, 39171, 39509, 39851, 19992, 20037, 20061, 20167, 20465, 20855, + 21246, 21312, 21475, 21477, 21646, 22036, 22389, 22434, 23495, 23943, 24272, 25084, 25304, + 25937, 26552, 26601, 27083, 27472, 27590, 27628, 27714, 28317, 28792, 29399, 29590, 29699, + 30655, 30697, 31350, 32127, 32777, 33276, 33285, 33290, 33503, 34914, 35635, 36092, 36544, + 36881, 37041, 37476, 37558, 39378, 39493, 40169, 40407, 40860, 22283, 23616, 33738, 38816, + 38827, 40628, 21531, 31384, 32676, 35033, 36557, 37089, 22528, 23624, 25496, 31391, 23470, + 24339, 31353, 31406, 33422, 36524, 20518, 21048, 21240, 21367, 22280, 25331, 25458, 27402, + 28099, 30519, 21413, 29527, 34152, 36470, 38357, 26426, 27331, 28528, 35437, 36556, 39243, + 63750, 26231, 27512, 36020, 39740, 63751, 21483, 22317, 22862, 25542, 27131, 29674, 30789, + 31418, 31429, 31998, 33909, 35215, 36211, 36917, 38312, 21243, 22343, 30023, 31584, 33740, + 37406, 63752, 27224, 20811, 21067, 21127, 25119, 26840, 26997, 38553, 20677, 21156, 21220, + 25027, 26020, 26681, 27135, 29822, 31563, 33465, 33771, 35250, 35641, 36817, 39241, 63753, + 20170, 22935, 25810, 26129, 27278, 29748, 31105, 31165, 33449, 34942, 34943, 35167, 63754, + 37670, 20235, 21450, 24613, 25201, 27762, 32026, 32102, 20120, 20834, 30684, 32943, 20225, + 20238, 20854, 20864, 21980, 22120, 22331, 22522, 22524, 22804, 22855, 22931, 23492, 23696, + 23822, 24049, 24190, 24524, 25216, 26071, 26083, 26398, 26399, 26462, 26827, 26820, 27231, + 27450, 27683, 27773, 27778, 28103, 29592, 29734, 29738, 29826, 29859, 30072, 30079, 30849, + 30959, 31041, 31047, 31048, 31098, 31637, 32000, 32186, 32648, 32774, 32813, 32908, 35352, + 35663, 35912, 36215, 37665, 37668, 39138, 39249, 39438, 39439, 39525, 40594, 32202, 20342, + 21513, 25326, 26708, 37329, 21931, 20794, 63755, 63756, 23068, 25062, 63757, 25295, 25343, + 63758, 63759, 63760, 63761, 63762, 63763, 37027, 63764, 63765, 63766, 63767, 63768, 35582, + 63769, 63770, 63771, 63772, 26262, 63773, 29014, 63774, 63775, 38627, 63776, 25423, 25466, + 21335, 63777, 26511, 26976, 28275, 63778, 30007, 63779, 63780, 63781, 32013, 63782, 63783, + 34930, 22218, 23064, 63784, 63785, 63786, 63787, 63788, 20035, 63789, 20839, 22856, 26608, + 32784, 63790, 22899, 24180, 25754, 31178, 24565, 24684, 25288, 25467, 23527, 23511, 21162, + 63791, 22900, 24361, 24594, 63792, 63793, 63794, 29785, 63795, 63796, 63797, 63798, 63799, + 63800, 39377, 63801, 63802, 63803, 63804, 63805, 63806, 63807, 63808, 63809, 63810, 63811, + 28611, 63812, 63813, 33215, 36786, 24817, 63814, 63815, 33126, 63816, 63817, 23615, 63818, + 63819, 63820, 63821, 63822, 63823, 63824, 63825, 23273, 35365, 26491, 32016, 63826, 63827, + 63828, 63829, 63830, 63831, 33021, 63832, 63833, 23612, 27877, 21311, 28346, 22810, 33590, + 20025, 20150, 20294, 21934, 22296, 22727, 24406, 26039, 26086, 27264, 27573, 28237, 30701, + 31471, 31774, 32222, 34507, 34962, 37170, 37723, 25787, 28606, 29562, 30136, 36948, 21846, + 22349, 25018, 25812, 26311, 28129, 28251, 28525, 28601, 30192, 32835, 33213, 34113, 35203, + 35527, 35674, 37663, 27795, 30035, 31572, 36367, 36957, 21776, 22530, 22616, 24162, 25095, + 25758, 26848, 30070, 31958, 34739, 40680, 20195, 22408, 22382, 22823, 23565, 23729, 24118, + 24453, 25140, 25825, 29619, 33274, 34955, 36024, 38538, 40667, 23429, 24503, 24755, 20498, + 20992, 21040, 22294, 22581, 22615, 23566, 23648, 23798, 23947, 24230, 24466, 24764, 25361, + 25481, 25623, 26691, 26873, 27330, 28120, 28193, 28372, 28644, 29182, 30428, 30585, 31153, + 31291, 33796, 35241, 36077, 36339, 36424, 36867, 36884, 36947, 37117, 37709, 38518, 38876, + 27602, 28678, 29272, 29346, 29544, 30563, 31167, 31716, 32411, 35712, 22697, 24775, 25958, + 26109, 26302, 27788, 28958, 29129, 35930, 38931, 20077, 31361, 20189, 20908, 20941, 21205, + 21516, 24999, 26481, 26704, 26847, 27934, 28540, 30140, 30643, 31461, 33012, 33891, 37509, + 20828, 26007, 26460, 26515, 30168, 31431, 33651, 63834, 35910, 36887, 38957, 23663, 33216, + 33434, 36929, 36975, 37389, 24471, 23965, 27225, 29128, 30331, 31561, 34276, 35588, 37159, + 39472, 21895, 25078, 63835, 30313, 32645, 34367, 34746, 35064, 37007, 63836, 27931, 28889, + 29662, 32097, 33853, 63837, 37226, 39409, 63838, 20098, 21365, 27396, 27410, 28734, 29211, + 34349, 40478, 21068, 36771, 23888, 25829, 25900, 27414, 28651, 31811, 32412, 34253, 35172, + 35261, 25289, 33240, 34847, 24266, 26391, 28010, 29436, 29701, 29807, 34690, 37086, 20358, + 23821, 24480, 33802, 20919, 25504, 30053, 20142, 20486, 20841, 20937, 26753, 27153, 31918, + 31921, 31975, 33391, 35538, 36635, 37327, 20406, 20791, 21237, 21570, 24300, 24942, 25150, + 26053, 27354, 28670, 31018, 34268, 34851, 38317, 39522, 39530, 40599, 40654, 21147, 26310, + 27511, 28701, 31019, 36706, 38722, 24976, 25088, 25891, 28451, 29001, 29833, 32244, 32879, + 34030, 36646, 36899, 37706, 20925, 21015, 21155, 27916, 28872, 35010, 24265, 25986, 27566, + 28610, 31806, 29557, 20196, 20278, 22265, 63839, 23738, 23994, 24604, 29618, 31533, 32666, + 32718, 32838, 36894, 37428, 38646, 38728, 38936, 40801, 20363, 28583, 31150, 37300, 38583, + 21214, 63840, 25736, 25796, 27347, 28510, 28696, 29200, 30439, 32769, 34310, 34396, 36335, + 36613, 38706, 39791, 40442, 40565, 30860, 31103, 32160, 33737, 37636, 40575, 40595, 35542, + 22751, 24324, 26407, 28711, 29903, 31840, 32894, 20769, 28712, 29282, 30922, 36034, 36058, + 36084, 38647, 20102, 20698, 23534, 24278, 26009, 29134, 30274, 30637, 32842, 34044, 36988, + 39719, 40845, 22744, 23105, 23650, 27155, 28122, 28431, 30267, 32047, 32311, 34078, 35128, + 37860, 38475, 21129, 26066, 26611, 27060, 27969, 28316, 28687, 29705, 29792, 30041, 30244, + 30827, 35628, 39006, 20845, 25134, 38520, 20374, 20523, 23833, 28138, 32184, 36650, 24459, + 24900, 26647, 63841, 38534, 21202, 32907, 20956, 20940, 26974, 31260, 32190, 33777, 38517, + 20442, 21033, 21400, 21519, 21774, 23653, 24743, 26446, 26792, 28012, 29313, 29432, 29702, + 29827, 63842, 30178, 31852, 32633, 32696, 33673, 35023, 35041, 37324, 37328, 38626, 39881, + 21533, 28542, 29136, 29848, 34298, 36522, 38563, 40023, 40607, 26519, 28107, 29747, 33256, + 38678, 30764, 31435, 31520, 31890, 25705, 29802, 30194, 30908, 30952, 39340, 39764, 40635, + 23518, 24149, 28448, 33180, 33707, 37000, 19975, 21325, 23081, 24018, 24398, 24930, 25405, + 26217, 26364, 28415, 28459, 28771, 30622, 33836, 34067, 34875, 36627, 39237, 39995, 21788, + 25273, 26411, 27819, 33545, 35178, 38778, 20129, 22916, 24536, 24537, 26395, 32178, 32596, + 33426, 33579, 33725, 36638, 37017, 22475, 22969, 23186, 23504, 26151, 26522, 26757, 27599, + 29028, 32629, 36023, 36067, 36993, 39749, 33032, 35978, 38476, 39488, 40613, 23391, 27667, + 29467, 30450, 30431, 33804, 20906, 35219, 20813, 20885, 21193, 26825, 27796, 30468, 30496, + 32191, 32236, 38754, 40629, 28357, 34065, 20901, 21517, 21629, 26126, 26269, 26919, 28319, + 30399, 30609, 33559, 33986, 34719, 37225, 37528, 40180, 34946, 20398, 20882, 21215, 22982, + 24125, 24917, 25720, 25721, 26286, 26576, 27169, 27597, 27611, 29279, 29281, 29761, 30520, + 30683, 32791, 33468, 33541, 35584, 35624, 35980, 26408, 27792, 29287, 30446, 30566, 31302, + 40361, 27519, 27794, 22818, 26406, 33945, 21359, 22675, 22937, 24287, 25551, 26164, 26483, + 28218, 29483, 31447, 33495, 37672, 21209, 24043, 25006, 25035, 25098, 25287, 25771, 26080, + 26969, 27494, 27595, 28961, 29687, 30045, 32326, 33310, 33538, 34154, 35491, 36031, 38695, + 40289, 22696, 40664, 20497, 21006, 21563, 21839, 25991, 27766, 32010, 32011, 32862, 34442, + 38272, 38639, 21247, 27797, 29289, 21619, 23194, 23614, 23883, 24396, 24494, 26410, 26806, + 26979, 28220, 28228, 30473, 31859, 32654, 34183, 35598, 36855, 38753, 40692, 23735, 24758, + 24845, 25003, 25935, 26107, 26108, 27665, 27887, 29599, 29641, 32225, 38292, 23494, 34588, + 35600, 21085, 21338, 25293, 25615, 25778, 26420, 27192, 27850, 29632, 29854, 31636, 31893, + 32283, 33162, 33334, 34180, 36843, 38649, 39361, 20276, 21322, 21453, 21467, 25292, 25644, + 25856, 26001, 27075, 27886, 28504, 29677, 30036, 30242, 30436, 30460, 30928, 30971, 31020, + 32070, 33324, 34784, 36820, 38930, 39151, 21187, 25300, 25765, 28196, 28497, 30332, 36299, + 37297, 37474, 39662, 39747, 20515, 20621, 22346, 22952, 23592, 24135, 24439, 25151, 25918, + 26041, 26049, 26121, 26507, 27036, 28354, 30917, 32033, 32938, 33152, 33323, 33459, 33953, + 34444, 35370, 35607, 37030, 38450, 40848, 20493, 20467, 63843, 22521, 24472, 25308, 25490, + 26479, 28227, 28953, 30403, 32972, 32986, 35060, 35061, 35097, 36064, 36649, 37197, 38506, + 20271, 20336, 24091, 26575, 26658, 30333, 30334, 39748, 24161, 27146, 29033, 29140, 30058, + 63844, 32321, 34115, 34281, 39132, 20240, 31567, 32624, 38309, 20961, 24070, 26805, 27710, + 27726, 27867, 29359, 31684, 33539, 27861, 29754, 20731, 21128, 22721, 25816, 27287, 29863, + 30294, 30887, 34327, 38370, 38713, 63845, 21342, 24321, 35722, 36776, 36783, 37002, 21029, + 30629, 40009, 40712, 19993, 20482, 20853, 23643, 24183, 26142, 26170, 26564, 26821, 28851, + 29953, 30149, 31177, 31453, 36647, 39200, 39432, 20445, 22561, 22577, 23542, 26222, 27493, + 27921, 28282, 28541, 29668, 29995, 33769, 35036, 35091, 35676, 36628, 20239, 20693, 21264, + 21340, 23443, 24489, 26381, 31119, 33145, 33583, 34068, 35079, 35206, 36665, 36667, 39333, + 39954, 26412, 20086, 20472, 22857, 23553, 23791, 23792, 25447, 26834, 28925, 29090, 29739, + 32299, 34028, 34562, 36898, 37586, 40179, 19981, 20184, 20463, 20613, 21078, 21103, 21542, + 21648, 22496, 22827, 23142, 23386, 23413, 23500, 24220, 63846, 25206, 25975, 26023, 28014, + 28325, 29238, 31526, 31807, 32566, 33104, 33105, 33178, 33344, 33433, 33705, 35331, 36000, + 36070, 36091, 36212, 36282, 37096, 37340, 38428, 38468, 39385, 40167, 21271, 20998, 21545, + 22132, 22707, 22868, 22894, 24575, 24996, 25198, 26128, 27774, 28954, 30406, 31881, 31966, + 32027, 33452, 36033, 38640, 63847, 20315, 24343, 24447, 25282, 23849, 26379, 26842, 30844, + 32323, 40300, 19989, 20633, 21269, 21290, 21329, 22915, 23138, 24199, 24754, 24970, 25161, + 25209, 26000, 26503, 27047, 27604, 27606, 27607, 27608, 27832, 63848, 29749, 30202, 30738, + 30865, 31189, 31192, 31875, 32203, 32737, 32933, 33086, 33218, 33778, 34586, 35048, 35513, + 35692, 36027, 37145, 38750, 39131, 40763, 22188, 23338, 24428, 25996, 27315, 27567, 27996, + 28657, 28693, 29277, 29613, 36007, 36051, 38971, 24977, 27703, 32856, 39425, 20045, 20107, + 20123, 20181, 20282, 20284, 20351, 20447, 20735, 21490, 21496, 21766, 21987, 22235, 22763, + 22882, 23057, 23531, 23546, 23556, 24051, 24107, 24473, 24605, 25448, 26012, 26031, 26614, + 26619, 26797, 27515, 27801, 27863, 28195, 28681, 29509, 30722, 31038, 31040, 31072, 31169, + 31721, 32023, 32114, 32902, 33293, 33678, 34001, 34503, 35039, 35408, 35422, 35613, 36060, + 36198, 36781, 37034, 39164, 39391, 40605, 21066, 63849, 26388, 63850, 20632, 21034, 23665, + 25955, 27733, 29642, 29987, 30109, 31639, 33948, 37240, 38704, 20087, 25746, 27578, 29022, + 34217, 19977, 63851, 26441, 26862, 28183, 33439, 34072, 34923, 25591, 28545, 37394, 39087, + 19978, 20663, 20687, 20767, 21830, 21930, 22039, 23360, 23577, 23776, 24120, 24202, 24224, + 24258, 24819, 26705, 27233, 28248, 29245, 29248, 29376, 30456, 31077, 31665, 32724, 35059, + 35316, 35443, 35937, 36062, 38684, 22622, 29885, 36093, 21959, 63852, 31329, 32034, 33394, + 29298, 29983, 29989, 63853, 31513, 22661, 22779, 23996, 24207, 24246, 24464, 24661, 25234, + 25471, 25933, 26257, 26329, 26360, 26646, 26866, 29312, 29790, 31598, 32110, 32214, 32626, + 32997, 33298, 34223, 35199, 35475, 36893, 37604, 40653, 40736, 22805, 22893, 24109, 24796, + 26132, 26227, 26512, 27728, 28101, 28511, 30707, 30889, 33990, 37323, 37675, 20185, 20682, + 20808, 21892, 23307, 23459, 25159, 25982, 26059, 28210, 29053, 29697, 29764, 29831, 29887, + 30316, 31146, 32218, 32341, 32680, 33146, 33203, 33337, 34330, 34796, 35445, 36323, 36984, + 37521, 37925, 39245, 39854, 21352, 23633, 26964, 27844, 27945, 28203, 33292, 34203, 35131, + 35373, 35498, 38634, 40807, 21089, 26297, 27570, 32406, 34814, 36109, 38275, 38493, 25885, + 28041, 29166, 63854, 22478, 22995, 23468, 24615, 24826, 25104, 26143, 26207, 29481, 29689, + 30427, 30465, 31596, 32854, 32882, 33125, 35488, 37266, 19990, 21218, 27506, 27927, 31237, + 31545, 32048, 63855, 36016, 21484, 22063, 22609, 23477, 23567, 23569, 24034, 25152, 25475, + 25620, 26157, 26803, 27836, 28040, 28335, 28703, 28836, 29138, 29990, 30095, 30094, 30233, + 31505, 31712, 31787, 32032, 32057, 34092, 34157, 34311, 35380, 36877, 36961, 37045, 37559, + 38902, 39479, 20439, 23660, 26463, 28049, 31903, 32396, 35606, 36118, 36895, 23403, 24061, + 25613, 33984, 36956, 39137, 29575, 23435, 24730, 26494, 28126, 35359, 35494, 36865, 38924, + 21047, 63856, 28753, 30862, 37782, 34928, 37335, 20462, 21463, 22013, 22234, 22402, 22781, + 23234, 23432, 23723, 23744, 24101, 24833, 25101, 25163, 25480, 25628, 25910, 25976, 27193, + 27530, 27700, 27929, 28465, 29159, 29417, 29560, 29703, 29874, 30246, 30561, 31168, 31319, + 31466, 31929, 32143, 32172, 32353, 32670, 33065, 33585, 33936, 34010, 34282, 34966, 35504, + 35728, 36664, 36930, 36995, 37228, 37526, 37561, 38539, 38567, 38568, 38614, 38656, 38920, + 39318, 39635, 39706, 21460, 22654, 22809, 23408, 23487, 28113, 28506, 29087, 29729, 29881, + 32901, 33789, 24033, 24455, 24490, 24642, 26092, 26642, 26991, 27219, 27529, 27957, 28147, + 29667, 30462, 30636, 31565, 32020, 33059, 33308, 33600, 34036, 34147, 35426, 35524, 37255, + 37662, 38918, 39348, 25100, 34899, 36848, 37477, 23815, 23847, 23913, 29791, 33181, 34664, + 28629, 25342, 32722, 35126, 35186, 19998, 20056, 20711, 21213, 21319, 25215, 26119, 32361, + 34821, 38494, 20365, 21273, 22070, 22987, 23204, 23608, 23630, 23629, 24066, 24337, 24643, + 26045, 26159, 26178, 26558, 26612, 29468, 30690, 31034, 32709, 33940, 33997, 35222, 35430, + 35433, 35553, 35925, 35962, 22516, 23508, 24335, 24687, 25325, 26893, 27542, 28252, 29060, + 31698, 34645, 35672, 36606, 39135, 39166, 20280, 20353, 20449, 21627, 23072, 23480, 24892, + 26032, 26216, 29180, 30003, 31070, 32051, 33102, 33251, 33688, 34218, 34254, 34563, 35338, + 36523, 36763, 63857, 36805, 22833, 23460, 23526, 24713, 23529, 23563, 24515, 27777, 63858, + 28145, 28683, 29978, 33455, 35574, 20160, 21313, 63859, 38617, 27663, 20126, 20420, 20818, + 21854, 23077, 23784, 25105, 29273, 33469, 33706, 34558, 34905, 35357, 38463, 38597, 39187, + 40201, 40285, 22538, 23731, 23997, 24132, 24801, 24853, 25569, 27138, 28197, 37122, 37716, + 38990, 39952, 40823, 23433, 23736, 25353, 26191, 26696, 30524, 38593, 38797, 38996, 39839, + 26017, 35585, 36555, 38332, 21813, 23721, 24022, 24245, 26263, 30284, 33780, 38343, 22739, + 25276, 29390, 40232, 20208, 22830, 24591, 26171, 27523, 31207, 40230, 21395, 21696, 22467, + 23830, 24859, 26326, 28079, 30861, 33406, 38552, 38724, 21380, 25212, 25494, 28082, 32266, + 33099, 38989, 27387, 32588, 40367, 40474, 20063, 20539, 20918, 22812, 24825, 25590, 26928, + 29242, 32822, 63860, 37326, 24369, 63861, 63862, 32004, 33509, 33903, 33979, 34277, 36493, + 63863, 20335, 63864, 63865, 22756, 23363, 24665, 25562, 25880, 25965, 26264, 63866, 26954, + 27171, 27915, 28673, 29036, 30162, 30221, 31155, 31344, 63867, 32650, 63868, 35140, 63869, + 35731, 37312, 38525, 63870, 39178, 22276, 24481, 26044, 28417, 30208, 31142, 35486, 39341, + 39770, 40812, 20740, 25014, 25233, 27277, 33222, 20547, 22576, 24422, 28937, 35328, 35578, + 23420, 34326, 20474, 20796, 22196, 22852, 25513, 28153, 23978, 26989, 20870, 20104, 20313, + 63871, 63872, 63873, 22914, 63874, 63875, 27487, 27741, 63876, 29877, 30998, 63877, 33287, + 33349, 33593, 36671, 36701, 63878, 39192, 63879, 63880, 63881, 20134, 63882, 22495, 24441, + 26131, 63883, 63884, 30123, 32377, 35695, 63885, 36870, 39515, 22181, 22567, 23032, 23071, + 23476, 63886, 24310, 63887, 63888, 25424, 25403, 63889, 26941, 27783, 27839, 28046, 28051, + 28149, 28436, 63890, 28895, 28982, 29017, 63891, 29123, 29141, 63892, 30799, 30831, 63893, + 31605, 32227, 63894, 32303, 63895, 34893, 36575, 63896, 63897, 63898, 37467, 63899, 40182, + 63900, 63901, 63902, 24709, 28037, 63903, 29105, 63904, 63905, 38321, 21421, 63906, 63907, + 63908, 26579, 63909, 28814, 28976, 29744, 33398, 33490, 63910, 38331, 39653, 40573, 26308, + 63911, 29121, 33865, 63912, 63913, 22603, 63914, 63915, 23992, 24433, 63916, 26144, 26254, + 27001, 27054, 27704, 27891, 28214, 28481, 28634, 28699, 28719, 29008, 29151, 29552, 63917, + 29787, 63918, 29908, 30408, 31310, 32403, 63919, 63920, 33521, 35424, 36814, 63921, 37704, + 63922, 38681, 63923, 63924, 20034, 20522, 63925, 21000, 21473, 26355, 27757, 28618, 29450, + 30591, 31330, 33454, 34269, 34306, 63926, 35028, 35427, 35709, 35947, 63927, 37555, 63928, + 38675, 38928, 20116, 20237, 20425, 20658, 21320, 21566, 21555, 21978, 22626, 22714, 22887, + 23067, 23524, 24735, 63929, 25034, 25942, 26111, 26212, 26791, 27738, 28595, 28879, 29100, + 29522, 31613, 34568, 35492, 39986, 40711, 23627, 27779, 29508, 29577, 37434, 28331, 29797, + 30239, 31337, 32277, 34314, 20800, 22725, 25793, 29934, 29973, 30320, 32705, 37013, 38605, + 39252, 28198, 29926, 31401, 31402, 33253, 34521, 34680, 35355, 23113, 23436, 23451, 26785, + 26880, 28003, 29609, 29715, 29740, 30871, 32233, 32747, 33048, 33109, 33694, 35916, 38446, + 38929, 26352, 24448, 26106, 26505, 27754, 29579, 20525, 23043, 27498, 30702, 22806, 23916, + 24013, 29477, 30031, 63930, 63931, 20709, 20985, 22575, 22829, 22934, 23002, 23525, 63932, + 63933, 23970, 25303, 25622, 25747, 25854, 63934, 26332, 63935, 27208, 63936, 29183, 29796, + 63937, 31368, 31407, 32327, 32350, 32768, 33136, 63938, 34799, 35201, 35616, 36953, 63939, + 36992, 39250, 24958, 27442, 28020, 32287, 35109, 36785, 20433, 20653, 20887, 21191, 22471, + 22665, 23481, 24248, 24898, 27029, 28044, 28263, 28342, 29076, 29794, 29992, 29996, 32883, + 33592, 33993, 36362, 37780, 37854, 63940, 20110, 20305, 20598, 20778, 21448, 21451, 21491, + 23431, 23507, 23588, 24858, 24962, 26100, 29275, 29591, 29760, 30402, 31056, 31121, 31161, + 32006, 32701, 33419, 34261, 34398, 36802, 36935, 37109, 37354, 38533, 38632, 38633, 21206, + 24423, 26093, 26161, 26671, 29020, 31286, 37057, 38922, 20113, 63941, 27218, 27550, 28560, + 29065, 32792, 33464, 34131, 36939, 38549, 38642, 38907, 34074, 39729, 20112, 29066, 38596, + 20803, 21407, 21729, 22291, 22290, 22435, 23195, 23236, 23491, 24616, 24895, 25588, 27781, + 27961, 28274, 28304, 29232, 29503, 29783, 33489, 34945, 36677, 36960, 63942, 38498, 39000, + 40219, 26376, 36234, 37470, 20301, 20553, 20702, 21361, 22285, 22996, 23041, 23561, 24944, + 26256, 28205, 29234, 29771, 32239, 32963, 33806, 33894, 34111, 34655, 34907, 35096, 35586, + 36949, 38859, 39759, 20083, 20369, 20754, 20842, 63943, 21807, 21929, 23418, 23461, 24188, + 24189, 24254, 24736, 24799, 24840, 24841, 25540, 25912, 26377, 63944, 26580, 26586, 63945, + 26977, 26978, 27833, 27943, 63946, 28216, 63947, 28641, 29494, 29495, 63948, 29788, 30001, + 63949, 30290, 63950, 63951, 32173, 33278, 33848, 35029, 35480, 35547, 35565, 36400, 36418, + 36938, 36926, 36986, 37193, 37321, 37742, 63952, 63953, 22537, 63954, 27603, 32905, 32946, + 63955, 63956, 20801, 22891, 23609, 63957, 63958, 28516, 29607, 32996, 36103, 63959, 37399, + 38287, 63960, 63961, 63962, 63963, 32895, 25102, 28700, 32104, 34701, 63964, 22432, 24681, + 24903, 27575, 35518, 37504, 38577, 20057, 21535, 28139, 34093, 38512, 38899, 39150, 25558, + 27875, 37009, 20957, 25033, 33210, 40441, 20381, 20506, 20736, 23452, 24847, 25087, 25836, + 26885, 27589, 30097, 30691, 32681, 33380, 34191, 34811, 34915, 35516, 35696, 37291, 20108, + 20197, 20234, 63965, 63966, 22839, 23016, 63967, 24050, 24347, 24411, 24609, 63968, 63969, + 63970, 63971, 29246, 29669, 63972, 30064, 30157, 63973, 31227, 63974, 32780, 32819, 32900, + 33505, 33617, 63975, 63976, 36029, 36019, 36999, 63977, 63978, 39156, 39180, 63979, 63980, + 28727, 30410, 32714, 32716, 32764, 35610, 20154, 20161, 20995, 21360, 63981, 21693, 22240, + 23035, 23493, 24341, 24525, 28270, 63982, 63983, 32106, 33589, 63984, 34451, 35469, 63985, + 38765, 38775, 63986, 63987, 19968, 20314, 20350, 22777, 26085, 28322, 36920, 37808, 39353, + 20219, 22764, 22922, 23001, 24641, 63988, 63989, 31252, 63990, 33615, 36035, 20837, 21316, + 63991, 63992, 63993, 20173, 21097, 23381, 33471, 20180, 21050, 21672, 22985, 23039, 23376, + 23383, 23388, 24675, 24904, 28363, 28825, 29038, 29574, 29943, 30133, 30913, 32043, 32773, + 33258, 33576, 34071, 34249, 35566, 36039, 38604, 20316, 21242, 22204, 26027, 26152, 28796, + 28856, 29237, 32189, 33421, 37196, 38592, 40306, 23409, 26855, 27544, 28538, 30430, 23697, + 26283, 28507, 31668, 31786, 34870, 38620, 19976, 20183, 21280, 22580, 22715, 22767, 22892, + 23559, 24115, 24196, 24373, 25484, 26290, 26454, 27167, 27299, 27404, 28479, 29254, 63994, + 29520, 29835, 31456, 31911, 33144, 33247, 33255, 33674, 33900, 34083, 34196, 34255, 35037, + 36115, 37292, 38263, 38556, 20877, 21705, 22312, 23472, 25165, 26448, 26685, 26771, 28221, + 28371, 28797, 32289, 35009, 36001, 36617, 40779, 40782, 29229, 31631, 35533, 37658, 20295, + 20302, 20786, 21632, 22992, 24213, 25269, 26485, 26990, 27159, 27822, 28186, 29401, 29482, + 30141, 31672, 32053, 33511, 33785, 33879, 34295, 35419, 36015, 36487, 36889, 37048, 38606, + 40799, 21219, 21514, 23265, 23490, 25688, 25973, 28404, 29380, 63995, 30340, 31309, 31515, + 31821, 32318, 32735, 33659, 35627, 36042, 36196, 36321, 36447, 36842, 36857, 36969, 37841, + 20291, 20346, 20659, 20840, 20856, 21069, 21098, 22625, 22652, 22880, 23560, 23637, 24283, + 24731, 25136, 26643, 27583, 27656, 28593, 29006, 29728, 30000, 30008, 30033, 30322, 31564, + 31627, 31661, 31686, 32399, 35438, 36670, 36681, 37439, 37523, 37666, 37931, 38651, 39002, + 39019, 39198, 20999, 25130, 25240, 27993, 30308, 31434, 31680, 32118, 21344, 23742, 24215, + 28472, 28857, 31896, 38673, 39822, 40670, 25509, 25722, 34678, 19969, 20117, 20141, 20572, + 20597, 21576, 22979, 23450, 24128, 24237, 24311, 24449, 24773, 25402, 25919, 25972, 26060, + 26230, 26232, 26622, 26984, 27273, 27491, 27712, 28096, 28136, 28191, 28254, 28702, 28833, + 29582, 29693, 30010, 30555, 30855, 31118, 31243, 31357, 31934, 32142, 33351, 35330, 35562, + 35998, 37165, 37194, 37336, 37478, 37580, 37664, 38662, 38742, 38748, 38914, 40718, 21046, + 21137, 21884, 22564, 24093, 24351, 24716, 25552, 26799, 28639, 31085, 31532, 33229, 34234, + 35069, 35576, 36420, 37261, 38500, 38555, 38717, 38988, 40778, 20430, 20806, 20939, 21161, + 22066, 24340, 24427, 25514, 25805, 26089, 26177, 26362, 26361, 26397, 26781, 26839, 27133, + 28437, 28526, 29031, 29157, 29226, 29866, 30522, 31062, 31066, 31199, 31264, 31381, 31895, + 31967, 32068, 32368, 32903, 34299, 34468, 35412, 35519, 36249, 36481, 36896, 36973, 37347, + 38459, 38613, 40165, 26063, 31751, 36275, 37827, 23384, 23562, 21330, 25305, 29469, 20519, + 23447, 24478, 24752, 24939, 26837, 28121, 29742, 31278, 32066, 32156, 32305, 33131, 36394, + 36405, 37758, 37912, 20304, 22352, 24038, 24231, 25387, 32618, 20027, 20303, 20367, 20570, + 23005, 32964, 21610, 21608, 22014, 22863, 23449, 24030, 24282, 26205, 26417, 26609, 26666, + 27880, 27954, 28234, 28557, 28855, 29664, 30087, 31820, 32002, 32044, 32162, 33311, 34523, + 35387, 35461, 36208, 36490, 36659, 36913, 37198, 37202, 37956, 39376, 31481, 31909, 20426, + 20737, 20934, 22472, 23535, 23803, 26201, 27197, 27994, 28310, 28652, 28940, 30063, 31459, + 34850, 36897, 36981, 38603, 39423, 33537, 20013, 20210, 34886, 37325, 21373, 27355, 26987, + 27713, 33914, 22686, 24974, 26366, 25327, 28893, 29969, 30151, 32338, 33976, 35657, 36104, + 20043, 21482, 21675, 22320, 22336, 24535, 25345, 25351, 25711, 25903, 26088, 26234, 26525, + 26547, 27490, 27744, 27802, 28460, 30693, 30757, 31049, 31063, 32025, 32930, 33026, 33267, + 33437, 33463, 34584, 35468, 63996, 36100, 36286, 36978, 30452, 31257, 31287, 32340, 32887, + 21767, 21972, 22645, 25391, 25634, 26185, 26187, 26733, 27035, 27524, 27941, 28337, 29645, + 29800, 29857, 30043, 30137, 30433, 30494, 30603, 31206, 32265, 32285, 33275, 34095, 34967, + 35386, 36049, 36587, 36784, 36914, 37805, 38499, 38515, 38663, 20356, 21489, 23018, 23241, + 24089, 26702, 29894, 30142, 31209, 31378, 33187, 34541, 36074, 36300, 36845, 26015, 26389, + 63997, 22519, 28503, 32221, 36655, 37878, 38598, 24501, 25074, 28548, 19988, 20376, 20511, + 21449, 21983, 23919, 24046, 27425, 27492, 30923, 31642, 63998, 36425, 36554, 36974, 25417, + 25662, 30528, 31364, 37679, 38015, 40810, 25776, 28591, 29158, 29864, 29914, 31428, 31762, + 32386, 31922, 32408, 35738, 36106, 38013, 39184, 39244, 21049, 23519, 25830, 26413, 32046, + 20717, 21443, 22649, 24920, 24921, 25082, 26028, 31449, 35730, 35734, 20489, 20513, 21109, + 21809, 23100, 24288, 24432, 24884, 25950, 26124, 26166, 26274, 27085, 28356, 28466, 29462, + 30241, 31379, 33081, 33369, 33750, 33980, 20661, 22512, 23488, 23528, 24425, 25505, 30758, + 32181, 33756, 34081, 37319, 37365, 20874, 26613, 31574, 36012, 20932, 22971, 24765, 34389, + 20508, 63999, 21076, 23610, 24957, 25114, 25299, 25842, 26021, 28364, 30240, 33034, 36448, + 38495, 38587, 20191, 21315, 21912, 22825, 24029, 25797, 27849, 28154, 29588, 31359, 33307, + 34214, 36068, 36368, 36983, 37351, 38369, 38433, 38854, 20984, 21746, 21894, 24505, 25764, + 28552, 32180, 36639, 36685, 37941, 20681, 23574, 27838, 28155, 29979, 30651, 31805, 31844, + 35449, 35522, 22558, 22974, 24086, 25463, 29266, 30090, 30571, 35548, 36028, 36626, 24307, + 26228, 28152, 32893, 33729, 35531, 38737, 39894, 64000, 21059, 26367, 28053, 28399, 32224, + 35558, 36910, 36958, 39636, 21021, 21119, 21736, 24980, 25220, 25307, 26786, 26898, 26970, + 27189, 28818, 28966, 30813, 30977, 30990, 31186, 31245, 32918, 33400, 33493, 33609, 34121, + 35970, 36229, 37218, 37259, 37294, 20419, 22225, 29165, 30679, 34560, 35320, 23544, 24534, + 26449, 37032, 21474, 22618, 23541, 24740, 24961, 25696, 32317, 32880, 34085, 37507, 25774, + 20652, 23828, 26368, 22684, 25277, 25512, 26894, 27000, 27166, 28267, 30394, 31179, 33467, + 33833, 35535, 36264, 36861, 37138, 37195, 37276, 37648, 37656, 37786, 38619, 39478, 39949, + 19985, 30044, 31069, 31482, 31569, 31689, 32302, 33988, 36441, 36468, 36600, 36880, 26149, + 26943, 29763, 20986, 26414, 40668, 20805, 24544, 27798, 34802, 34909, 34935, 24756, 33205, + 33795, 36101, 21462, 21561, 22068, 23094, 23601, 28810, 32736, 32858, 33030, 33261, 36259, + 37257, 39519, 40434, 20596, 20164, 21408, 24827, 28204, 23652, 20360, 20516, 21988, 23769, + 24159, 24677, 26772, 27835, 28100, 29118, 30164, 30196, 30305, 31258, 31305, 32199, 32251, + 32622, 33268, 34473, 36636, 38601, 39347, 40786, 21063, 21189, 39149, 35242, 19971, 26578, + 28422, 20405, 23522, 26517, 27784, 28024, 29723, 30759, 37341, 37756, 34756, 31204, 31281, + 24555, 20182, 21668, 21822, 22702, 22949, 24816, 25171, 25302, 26422, 26965, 33333, 38464, + 39345, 39389, 20524, 21331, 21828, 22396, 64001, 25176, 64002, 25826, 26219, 26589, 28609, + 28655, 29730, 29752, 35351, 37944, 21585, 22022, 22374, 24392, 24986, 27470, 28760, 28845, + 32187, 35477, 22890, 33067, 25506, 30472, 32829, 36010, 22612, 25645, 27067, 23445, 24081, + 28271, 64003, 34153, 20812, 21488, 22826, 24608, 24907, 27526, 27760, 27888, 31518, 32974, + 33492, 36294, 37040, 39089, 64004, 25799, 28580, 25745, 25860, 20814, 21520, 22303, 35342, + 24927, 26742, 64005, 30171, 31570, 32113, 36890, 22534, 27084, 33151, 35114, 36864, 38969, + 20600, 22871, 22956, 25237, 36879, 39722, 24925, 29305, 38358, 22369, 23110, 24052, 25226, + 25773, 25850, 26487, 27874, 27966, 29228, 29750, 30772, 32631, 33453, 36315, 38935, 21028, + 22338, 26495, 29256, 29923, 36009, 36774, 37393, 38442, 20843, 21485, 25420, 20329, 21764, + 24726, 25943, 27803, 28031, 29260, 29437, 31255, 35207, 35997, 24429, 28558, 28921, 33192, + 24846, 20415, 20559, 25153, 29255, 31687, 32232, 32745, 36941, 38829, 39449, 36022, 22378, + 24179, 26544, 33805, 35413, 21536, 23318, 24163, 24290, 24330, 25987, 32954, 34109, 38281, + 38491, 20296, 21253, 21261, 21263, 21638, 21754, 22275, 24067, 24598, 25243, 25265, 25429, + 64006, 27873, 28006, 30129, 30770, 32990, 33071, 33502, 33889, 33970, 34957, 35090, 36875, + 37610, 39165, 39825, 24133, 26292, 26333, 28689, 29190, 64007, 20469, 21117, 24426, 24915, + 26451, 27161, 28418, 29922, 31080, 34920, 35961, 39111, 39108, 39491, 21697, 31263, 26963, + 35575, 35914, 39080, 39342, 24444, 25259, 30130, 30382, 34987, 36991, 38466, 21305, 24380, + 24517, 27852, 29644, 30050, 30091, 31558, 33534, 39325, 20047, 36924, 19979, 20309, 21414, + 22799, 24264, 26160, 27827, 29781, 33655, 34662, 36032, 36944, 38686, 39957, 22737, 23416, + 34384, 35604, 40372, 23506, 24680, 24717, 26097, 27735, 28450, 28579, 28698, 32597, 32752, + 38289, 38290, 38480, 38867, 21106, 36676, 20989, 21547, 21688, 21859, 21898, 27323, 28085, + 32216, 33382, 37532, 38519, 40569, 21512, 21704, 30418, 34532, 38308, 38356, 38492, 20130, + 20233, 23022, 23270, 24055, 24658, 25239, 26477, 26689, 27782, 28207, 32568, 32923, 33322, + 64008, 64009, 38917, 20133, 20565, 21683, 22419, 22874, 23401, 23475, 25032, 26999, 28023, + 28707, 34809, 35299, 35442, 35559, 36994, 39405, 39608, 21182, 26680, 20502, 24184, 26447, + 33607, 34892, 20139, 21521, 22190, 29670, 37141, 38911, 39177, 39255, 39321, 22099, 22687, + 34395, 35377, 25010, 27382, 29563, 36562, 27463, 38570, 39511, 22869, 29184, 36203, 38761, + 20436, 23796, 24358, 25080, 26203, 27883, 28843, 29572, 29625, 29694, 30505, 30541, 32067, + 32098, 32291, 33335, 34898, 64010, 36066, 37449, 39023, 23377, 31348, 34880, 38913, 23244, + 20448, 21332, 22846, 23805, 25406, 28025, 29433, 33029, 33031, 33698, 37583, 38960, 20136, + 20804, 21009, 22411, 24418, 27842, 28366, 28677, 28752, 28847, 29074, 29673, 29801, 33610, + 34722, 34913, 36872, 37026, 37795, 39336, 20846, 24407, 24800, 24935, 26291, 34137, 36426, + 37295, 38795, 20046, 20114, 21628, 22741, 22778, 22909, 23733, 24359, 25142, 25160, 26122, + 26215, 27627, 28009, 28111, 28246, 28408, 28564, 28640, 28649, 28765, 29392, 29733, 29786, + 29920, 30355, 31068, 31946, 32286, 32993, 33446, 33899, 33983, 34382, 34399, 34676, 35703, + 35946, 37804, 38912, 39013, 24785, 25110, 37239, 23130, 26127, 28151, 28222, 29759, 39746, + 24573, 24794, 31503, 21700, 24344, 27742, 27859, 27946, 28888, 32005, 34425, 35340, 40251, + 21270, 21644, 23301, 27194, 28779, 30069, 31117, 31166, 33457, 33775, 35441, 35649, 36008, + 38772, 64011, 25844, 25899, 30906, 30907, 31339, 20024, 21914, 22864, 23462, 24187, 24739, + 25563, 27489, 26213, 26707, 28185, 29029, 29872, 32008, 36996, 39529, 39973, 27963, 28369, + 29502, 35905, 38346, 20976, 24140, 24488, 24653, 24822, 24880, 24908, 26179, 26180, 27045, + 27841, 28255, 28361, 28514, 29004, 29852, 30343, 31681, 31783, 33618, 34647, 36945, 38541, + 40643, 21295, 22238, 24315, 24458, 24674, 24724, 25079, 26214, 26371, 27292, 28142, 28590, + 28784, 29546, 32362, 33214, 33588, 34516, 35496, 36036, 21123, 29554, 23446, 27243, 37892, + 21742, 22150, 23389, 25928, 25989, 26313, 26783, 28045, 28102, 29243, 32948, 37237, 39501, + 20399, 20505, 21402, 21518, 21564, 21897, 21957, 24127, 24460, 26429, 29030, 29661, 36869, + 21211, 21235, 22628, 22734, 28932, 29071, 29179, 34224, 35347, 26248, 34216, 21927, 26244, + 29002, 33841, 21321, 21913, 27585, 24409, 24509, 25582, 26249, 28999, 35569, 36637, 40638, + 20241, 25658, 28875, 30054, 34407, 24676, 35662, 40440, 20807, 20982, 21256, 27958, 33016, + 40657, 26133, 27427, 28824, 30165, 21507, 23673, 32007, 35350, 27424, 27453, 27462, 21560, + 24688, 27965, 32725, 33288, 20694, 20958, 21916, 22123, 22221, 23020, 23305, 24076, 24985, + 24984, 25137, 26206, 26342, 29081, 29113, 29114, 29351, 31143, 31232, 32690, 35440, diff --git a/third_party/ulib/musl/src/locale/langinfo.c b/third_party/ulib/musl/src/locale/langinfo.c new file mode 100644 index 000000000..d1fc017da --- /dev/null +++ b/third_party/ulib/musl/src/locale/langinfo.c @@ -0,0 +1,104 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +static const char c_time[] = "Sun\0" + "Mon\0" + "Tue\0" + "Wed\0" + "Thu\0" + "Fri\0" + "Sat\0" + "Sunday\0" + "Monday\0" + "Tuesday\0" + "Wednesday\0" + "Thursday\0" + "Friday\0" + "Saturday\0" + "Jan\0" + "Feb\0" + "Mar\0" + "Apr\0" + "May\0" + "Jun\0" + "Jul\0" + "Aug\0" + "Sep\0" + "Oct\0" + "Nov\0" + "Dec\0" + "January\0" + "February\0" + "March\0" + "April\0" + "May\0" + "June\0" + "July\0" + "August\0" + "September\0" + "October\0" + "November\0" + "December\0" + "AM\0" + "PM\0" + "%a %b %e %T %Y\0" + "%m/%d/%y\0" + "%H:%M:%S\0" + "%I:%M:%S %p\0" + "\0" + "\0" + "%m/%d/%y\0" + "0123456789\0" + "%a %b %e %T %Y\0" + "%H:%M:%S"; + +static const char c_messages[] = "^[yY]\0" + "^[nN]\0" + "yes\0" + "no"; +static const char c_numeric[] = ".\0" + ""; + +char* __nl_langinfo_l(nl_item item, locale_t loc) { + int cat = item >> 16; + int idx = item & 65535; + const char* str; + + if (item == CODESET) return MB_CUR_MAX == 1 ? "ASCII" : "UTF-8"; + + switch (cat) { + case LC_NUMERIC: + if (idx > 1) return ""; + str = c_numeric; + break; + case LC_TIME: + if (idx > 0x31) return ""; + str = c_time; + break; + case LC_MONETARY: + if (idx > 0) return ""; + str = ""; + break; + case LC_MESSAGES: + if (idx > 3) return ""; + str = c_messages; + break; + default: + return ""; + } + + for (; idx; idx--, str++) + for (; *str; str++) + ; + if (cat != LC_NUMERIC && *str) str = LCTRANS(str, cat, loc); + return (char*)str; +} + +char* __nl_langinfo(nl_item item) { + return __nl_langinfo_l(item, CURRENT_LOCALE); +} + +weak_alias(__nl_langinfo, nl_langinfo); +weak_alias(__nl_langinfo_l, nl_langinfo_l); diff --git a/third_party/ulib/musl/src/locale/legacychars.h b/third_party/ulib/musl/src/locale/legacychars.h new file mode 100644 index 000000000..f0291596f --- /dev/null +++ b/third_party/ulib/musl/src/locale/legacychars.h @@ -0,0 +1,39 @@ +0, 1, 160, 167, 168, 169, 175, 176, 178, 183, 184, 198, 215, 216, 230, 247, 248, 162, 163, 165, 196, + 197, 198, 199, 201, 214, 215, 216, 220, 224, 226, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 238, 239, 242, 244, 246, 248, 249, 251, 252, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 302, 303, 304, 305, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 321, 322, 323, 324, 325, 326, 327, 328, 330, + 331, 332, 333, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 402, 416, 417, 431, 432, 536, 537, + 538, 539, 710, 711, 728, 729, 731, 732, 733, 768, 769, 771, 777, 803, 890, 900, 901, 902, 904, + 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, + 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, + 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, + 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1025, 1026, 1027, 1028, 1029, 1030, 1031, + 1032, 1033, 1034, 1035, 1036, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, + 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, + 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, + 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, + 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, + 1114, 1115, 1116, 1118, 1119, 1168, 1169, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, + 1465, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1488, 1489, 1490, 1491, 1492, 1493, + 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, + 1510, 1511, 1512, 1513, 1514, 1520, 1521, 1522, 1523, 1524, 1548, 1563, 1567, 1569, 1570, 1571, + 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, + 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, + 1609, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1657, 1662, 1670, 1672, 1681, 1688, + 1705, 1711, 1722, 1726, 1729, 1746, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, + 3595, 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3604, 3605, 3606, 3607, 3608, 3609, 3610, + 3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3620, 3621, 3622, 3623, 3624, 3625, 3626, + 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3641, 3642, + 3647, 3648, 3649, 3650, 3651, 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662, + 3663, 3664, 3665, 3666, 3667, 3668, 3669, 3670, 3671, 3672, 3673, 3674, 3675, 7682, 7683, 7690, + 7691, 7710, 7711, 7744, 7745, 7766, 7767, 7776, 7777, 7786, 7787, 7808, 7809, 7810, 7811, 7812, + 7813, 7922, 7923, 8204, 8205, 8206, 8207, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8220, 8221, + 8222, 8224, 8225, 8226, 8230, 8240, 8249, 8250, 8362, 8363, 8364, 8367, 8359, 8470, 8482, 8729, + 8730, 8776, 8804, 8805, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, + 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, + 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, + 9608, 9612, 9616, 9617, 9618, 9619, 9632, diff --git a/third_party/ulib/musl/src/locale/locale_map.c b/third_party/ulib/musl/src/locale/locale_map.c new file mode 100644 index 000000000..0d0477c08 --- /dev/null +++ b/third_party/ulib/musl/src/locale/locale_map.c @@ -0,0 +1,106 @@ +#include "atomic.h" +#include "libc.h" +#include "locale_impl.h" +#include +#include + +const char* __lctrans_impl(const char* msg, const struct __locale_map* lm) { + const char* trans = 0; + if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg); + return trans ? trans : msg; +} + +const unsigned char* __map_file(const char*, size_t*); +int __munmap(void*, size_t); +char* __strchrnul(const char*, int); + +static const char envvars[][12] = { + "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_MESSAGES", +}; + +const struct __locale_map* __get_locale(int cat, const char* val) { + static mxr_mutex_t lock; + static void* volatile loc_head; + const struct __locale_map* p; + struct __locale_map* new = 0; + const char *path = 0, *z; + char buf[256]; + size_t l, n; + + if (!*val) { + (val = getenv("LC_ALL")) && *val || (val = getenv(envvars[cat])) && *val || + (val = getenv("LANG")) && *val || (val = "C.UTF-8"); + } + + /* Limit name length and forbid leading dot or any slashes. */ + for (n = 0; n < LOCALE_NAME_MAX && val[n] && val[n] != '/'; n++) + ; + if (val[0] == '.' || val[n]) val = "C.UTF-8"; + int builtin = (val[0] == 'C' && !val[1]) || !strcmp(val, "C.UTF-8") || !strcmp(val, "POSIX"); + + if (builtin) { + if (cat == LC_CTYPE && val[1] == '.') return (void*)&__c_dot_utf8; + return 0; + } + + for (p = loc_head; p; p = p->next) + if (!strcmp(val, p->name)) return p; + + mxr_mutex_lock(&lock); + + for (p = loc_head; p; p = p->next) + if (!strcmp(val, p->name)) { + mxr_mutex_unlock(&lock); + return p; + } + + if (!libc.secure) path = getenv("MUSL_LOCPATH"); + /* FIXME: add a default path? */ + + if (path) + for (; *path; path = z + !!*z) { + z = __strchrnul(path, ':'); + l = z - path - !!*z; + if (l >= sizeof buf - n - 2) continue; + memcpy(buf, path, l); + buf[l] = '/'; + memcpy(buf + l + 1, val, n); + buf[l + 1 + n] = 0; + size_t map_size; + const void* map = __map_file(buf, &map_size); + if (map) { + new = malloc(sizeof *new); + if (!new) { + __munmap((void*)map, map_size); + break; + } + new->map = map; + new->map_size = map_size; + memcpy(new->name, val, n); + new->name[n] = 0; + new->next = loc_head; + loc_head = new; + break; + } + } + + /* If no locale definition was found, make a locale map + * object anyway to store the name, which is kept for the + * sake of being able to do message translations at the + * application level. */ + if (!new && (new = malloc(sizeof *new))) { + new->map = __c_dot_utf8.map; + new->map_size = __c_dot_utf8.map_size; + memcpy(new->name, val, n); + new->name[n] = 0; + new->next = loc_head; + loc_head = new; + } + + /* For LC_CTYPE, never return a null pointer unless the + * requested name was "C" or "POSIX". */ + if (!new&& cat == LC_CTYPE) new = (void*)&__c_dot_utf8; + + mxr_mutex_unlock(&lock); + return new; +} diff --git a/third_party/ulib/musl/src/locale/localeconv.c b/third_party/ulib/musl/src/locale/localeconv.c new file mode 100644 index 000000000..b513bfcc7 --- /dev/null +++ b/third_party/ulib/musl/src/locale/localeconv.c @@ -0,0 +1,33 @@ +#include +#include + +static const struct lconv posix_lconv = { + .decimal_point = ".", + .thousands_sep = "", + .grouping = "", + .int_curr_symbol = "", + .currency_symbol = "", + .mon_decimal_point = "", + .mon_thousands_sep = "", + .mon_grouping = "", + .positive_sign = "", + .negative_sign = "", + .int_frac_digits = CHAR_MAX, + .frac_digits = CHAR_MAX, + .p_cs_precedes = CHAR_MAX, + .p_sep_by_space = CHAR_MAX, + .n_cs_precedes = CHAR_MAX, + .n_sep_by_space = CHAR_MAX, + .p_sign_posn = CHAR_MAX, + .n_sign_posn = CHAR_MAX, + .int_p_cs_precedes = CHAR_MAX, + .int_p_sep_by_space = CHAR_MAX, + .int_n_cs_precedes = CHAR_MAX, + .int_n_sep_by_space = CHAR_MAX, + .int_p_sign_posn = CHAR_MAX, + .int_n_sign_posn = CHAR_MAX, +}; + +struct lconv* localeconv(void) { + return (void*)&posix_lconv; +} diff --git a/third_party/ulib/musl/src/locale/newlocale.c b/third_party/ulib/musl/src/locale/newlocale.c new file mode 100644 index 000000000..4d18d4c55 --- /dev/null +++ b/third_party/ulib/musl/src/locale/newlocale.c @@ -0,0 +1,44 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +int __loc_is_allocated(locale_t loc) { + return loc && loc != C_LOCALE && loc != UTF8_LOCALE; +} + +locale_t __newlocale(int mask, const char* name, locale_t loc) { + int i, j; + struct __locale_struct tmp; + const struct __locale_map* lm; + + /* For locales with allocated storage, modify in-place. */ + if (__loc_is_allocated(loc)) { + for (i = 0; i < LC_ALL; i++) + if (mask & (1 << i)) loc->cat[i] = __get_locale(i, name); + return loc; + } + + /* Otherwise, build a temporary locale object, which will only + * be instantiated in allocated storage if it does not match + * one of the built-in static locales. This makes the common + * usage case for newlocale, getting a C locale with predictable + * behavior, very fast, and more importantly, fail-safe. */ + for (j = i = 0; i < LC_ALL; i++) { + if (loc && !(mask & (1 << i))) + lm = loc->cat[i]; + else + lm = __get_locale(i, mask & (1 << i) ? name : ""); + if (lm) j++; + tmp.cat[i] = lm; + } + + if (!j) return C_LOCALE; + if (j == 1 && tmp.cat[LC_CTYPE] == &__c_dot_utf8) return UTF8_LOCALE; + + if ((loc = malloc(sizeof *loc))) *loc = tmp; + + return loc; +} + +weak_alias(__newlocale, newlocale); diff --git a/third_party/ulib/musl/src/locale/pleval.c b/third_party/ulib/musl/src/locale/pleval.c new file mode 100644 index 000000000..99cca6cbb --- /dev/null +++ b/third_party/ulib/musl/src/locale/pleval.c @@ -0,0 +1,178 @@ +#include +#include + +/* +grammar: + +Start = Expr ';' +Expr = Or | Or '?' Expr ':' Expr +Or = And | Or '||' And +And = Eq | And '&&' Eq +Eq = Rel | Eq '==' Rel | Eq '!=' Rel +Rel = Add | Rel '<=' Add | Rel '>=' Add | Rel '<' Add | Rel '>' Add +Add = Mul | Add '+' Mul | Add '-' Mul +Mul = Prim | Mul '*' Prim | Mul '/' Prim | Mul '%' Prim +Prim = '(' Expr ')' | '!' Prim | decimal | 'n' + +internals: + +recursive descent expression evaluator with stack depth limit. +for binary operators an operator-precedence parser is used. +eval* functions store the result of the parsed subexpression +and return a pointer to the next non-space character. +*/ + +struct st { + unsigned long r; + unsigned long n; + int op; +}; + +static const char* skipspace(const char* s) { + while (isspace(*s)) + s++; + return s; +} + +static const char* evalexpr(struct st* st, const char* s, int d); + +static const char* evalprim(struct st* st, const char* s, int d) { + char* e; + if (--d < 0) return ""; + s = skipspace(s); + if (isdigit(*s)) { + st->r = strtoul(s, &e, 10); + if (e == s || st->r == -1) return ""; + return skipspace(e); + } + if (*s == 'n') { + st->r = st->n; + return skipspace(s + 1); + } + if (*s == '(') { + s = evalexpr(st, s + 1, d); + if (*s != ')') return ""; + return skipspace(s + 1); + } + if (*s == '!') { + s = evalprim(st, s + 1, d); + st->r = !st->r; + return s; + } + return ""; +} + +static int binop(struct st* st, int op, unsigned long left) { + unsigned long a = left, b = st->r; + switch (op) { + case 0: + st->r = a || b; + return 0; + case 1: + st->r = a && b; + return 0; + case 2: + st->r = a == b; + return 0; + case 3: + st->r = a != b; + return 0; + case 4: + st->r = a >= b; + return 0; + case 5: + st->r = a <= b; + return 0; + case 6: + st->r = a > b; + return 0; + case 7: + st->r = a < b; + return 0; + case 8: + st->r = a + b; + return 0; + case 9: + st->r = a - b; + return 0; + case 10: + st->r = a * b; + return 0; + case 11: + if (b) { + st->r = a % b; + return 0; + } + return 1; + case 12: + if (b) { + st->r = a / b; + return 0; + } + return 1; + } + return 1; +} + +static const char* parseop(struct st* st, const char* s) { + static const char opch[11] = "|&=!><+-*%/"; + static const char opch2[6] = "|&===="; + int i; + for (i = 0; i < 11; i++) + if (*s == opch[i]) { + /* note: >,< are accepted with or without = */ + if (i < 6 && s[1] == opch2[i]) { + st->op = i; + return s + 2; + } + if (i >= 4) { + st->op = i + 2; + return s + 1; + } + break; + } + st->op = 13; + return s; +} + +static const char* evalbinop(struct st* st, const char* s, int minprec, int d) { + static const char prec[14] = {1, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 0}; + unsigned long left; + int op; + d--; + s = evalprim(st, s, d); + s = parseop(st, s); + for (;;) { + /* + st->r (left hand side value) and st->op are now set, + get the right hand side or back out if op has low prec, + if op was missing then prec[op]==0 + */ + op = st->op; + if (prec[op] <= minprec) return s; + left = st->r; + s = evalbinop(st, s, prec[op], d); + if (binop(st, op, left)) return ""; + } +} + +static const char* evalexpr(struct st* st, const char* s, int d) { + unsigned long a, b; + if (--d < 0) return ""; + s = evalbinop(st, s, 0, d); + if (*s != '?') return s; + a = st->r; + s = evalexpr(st, s + 1, d); + if (*s != ':') return ""; + b = st->r; + s = evalexpr(st, s + 1, d); + st->r = a ? b : st->r; + return s; +} + +unsigned long __pleval(const char* s, unsigned long n) { + struct st st; + st.n = n; + s = evalexpr(&st, s, 100); + return *s == ';' ? st.r : -1; +} diff --git a/third_party/ulib/musl/src/locale/setlocale.c b/third_party/ulib/musl/src/locale/setlocale.c new file mode 100644 index 000000000..108d4a937 --- /dev/null +++ b/third_party/ulib/musl/src/locale/setlocale.c @@ -0,0 +1,71 @@ +#include "atomic.h" +#include "libc.h" +#include "locale_impl.h" +#include +#include +#include + +#include + +static char buf[LC_ALL * (LOCALE_NAME_MAX + 1)]; + +static char* setlocale_one_unlocked(int cat, const char* name) { + const struct __locale_map* lm; + + if (name) + libc.global_locale.cat[cat] = lm = __get_locale(cat, name); + else + lm = libc.global_locale.cat[cat]; + + return lm ? (char*)lm->name : "C"; +} + +char* __strchrnul(const char*, int); + +char* setlocale(int cat, const char* name) { + static mxr_mutex_t lock; + + if ((unsigned)cat > LC_ALL) return 0; + + mxr_mutex_lock(&lock); + + /* For LC_ALL, setlocale is required to return a string which + * encodes the current setting for all categories. The format of + * this string is unspecified, and only the following code, which + * performs both the serialization and deserialization, depends + * on the format, so it can easily be changed if needed. */ + if (cat == LC_ALL) { + int i; + if (name) { + char part[LOCALE_NAME_MAX + 1] = "C.UTF-8"; + const char* p = name; + for (i = 0; i < LC_ALL; i++) { + const char* z = __strchrnul(p, ';'); + if (z - p <= LOCALE_NAME_MAX) { + memcpy(part, p, z - p); + part[z - p] = 0; + if (*z) p = z + 1; + } + setlocale_one_unlocked(i, part); + } + } + char* s = buf; + for (i = 0; i < LC_ALL; i++) { + const struct __locale_map* lm = libc.global_locale.cat[i]; + const char* part = lm ? lm->name : "C"; + size_t l = strlen(part); + memcpy(s, part, l); + s[l] = ';'; + s += l + 1; + } + *--s = 0; + mxr_mutex_unlock(&lock); + return buf; + } + + char* ret = setlocale_one_unlocked(cat, name); + + mxr_mutex_unlock(&lock); + + return ret; +} diff --git a/third_party/ulib/musl/src/locale/strcoll.c b/third_party/ulib/musl/src/locale/strcoll.c new file mode 100644 index 000000000..b85aef0a1 --- /dev/null +++ b/third_party/ulib/musl/src/locale/strcoll.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +int __strcoll_l(const char* l, const char* r, locale_t loc) { + return strcmp(l, r); +} + +int strcoll(const char* l, const char* r) { + return __strcoll_l(l, r, CURRENT_LOCALE); +} + +weak_alias(__strcoll_l, strcoll_l); diff --git a/third_party/ulib/musl/src/locale/strfmon.c b/third_party/ulib/musl/src/locale/strfmon.c new file mode 100644 index 000000000..9b11aae25 --- /dev/null +++ b/third_party/ulib/musl/src/locale/strfmon.c @@ -0,0 +1,99 @@ +#include "locale_impl.h" +#include +#include +#include +#include +#include + +static ssize_t vstrfmon_l(char* s, size_t n, locale_t loc, const char* fmt, va_list ap) { + size_t l; + double x; + int fill, nogrp, negpar, nosym, left, intl; + int lp, rp, w, fw; + char* s0 = s; + for (; n && *fmt;) { + if (*fmt != '%') { + literal: + *s++ = *fmt++; + n--; + continue; + } + fmt++; + if (*fmt == '%') goto literal; + + fill = ' '; + nogrp = 0; + negpar = 0; + nosym = 0; + left = 0; + for (;; fmt++) { + switch (*fmt) { + case '=': + fill = *++fmt; + continue; + case '^': + nogrp = 1; + continue; + case '(': + negpar = 1; + case '+': + continue; + case '!': + nosym = 1; + continue; + case '-': + left = 1; + continue; + } + break; + } + + for (fw = 0; isdigit(*fmt); fmt++) + fw = 10 * fw + (*fmt - '0'); + lp = 0; + rp = 2; + if (*fmt == '#') + for (lp = 0, fmt++; isdigit(*fmt); fmt++) + lp = 10 * lp + (*fmt - '0'); + if (*fmt == '.') + for (rp = 0, fmt++; isdigit(*fmt); fmt++) + rp = 10 * rp + (*fmt - '0'); + + intl = *fmt++ == 'i'; + + w = lp + 1 + rp; + if (!left && fw > w) w = fw; + + x = va_arg(ap, double); + l = snprintf(s, n, "%*.*f", w, rp, x); + if (l >= n) { + errno = E2BIG; + return -1; + } + s += l; + n -= l; + } + return s - s0; +} + +ssize_t strfmon_l(char* restrict s, size_t n, locale_t loc, const char* restrict fmt, ...) { + va_list ap; + ssize_t ret; + + va_start(ap, fmt); + ret = vstrfmon_l(s, n, loc, fmt, ap); + va_end(ap); + + return ret; +} + +ssize_t strfmon(char* restrict s, size_t n, const char* restrict fmt, ...) { + va_list ap; + ssize_t ret; + + va_start(ap, fmt); + ret = vstrfmon_l(s, n, CURRENT_LOCALE, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/third_party/ulib/musl/src/locale/strxfrm.c b/third_party/ulib/musl/src/locale/strxfrm.c new file mode 100644 index 000000000..c406a9232 --- /dev/null +++ b/third_party/ulib/musl/src/locale/strxfrm.c @@ -0,0 +1,17 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +/* collate only by code points */ +size_t __strxfrm_l(char* restrict dest, const char* restrict src, size_t n, locale_t loc) { + size_t l = strlen(src); + if (n > l) strcpy(dest, src); + return l; +} + +size_t strxfrm(char* restrict dest, const char* restrict src, size_t n) { + return __strxfrm_l(dest, src, n, CURRENT_LOCALE); +} + +weak_alias(__strxfrm_l, strxfrm_l); diff --git a/third_party/ulib/musl/src/locale/textdomain.c b/third_party/ulib/musl/src/locale/textdomain.c new file mode 100644 index 000000000..fa4c157b2 --- /dev/null +++ b/third_party/ulib/musl/src/locale/textdomain.c @@ -0,0 +1,40 @@ +#include "atomic.h" +#include "libc.h" +#include +#include +#include +#include +#include + +static char* current_domain; + +char* __gettextdomain(void) { + return current_domain ? current_domain : "messages"; +} + +char* textdomain(const char* domainname) { + if (!domainname) return __gettextdomain(); + + size_t domlen = strlen(domainname); + if (domlen > NAME_MAX) { + errno = EINVAL; + return 0; + } + + if (!current_domain) { + current_domain = malloc(NAME_MAX + 1); + if (!current_domain) return 0; + } + + memcpy(current_domain, domainname, domlen + 1); + + return current_domain; +} + +char* gettext(const char* msgid) { + return dgettext(0, msgid); +} + +char* ngettext(const char* msgid1, const char* msgid2, unsigned long int n) { + return dngettext(0, msgid1, msgid2, n); +} diff --git a/third_party/ulib/musl/src/locale/uselocale.c b/third_party/ulib/musl/src/locale/uselocale.c new file mode 100644 index 000000000..00e6b9098 --- /dev/null +++ b/third_party/ulib/musl/src/locale/uselocale.c @@ -0,0 +1,15 @@ +#include "libc.h" +#include "locale_impl.h" +#include "pthread_impl.h" + +locale_t __uselocale(locale_t new) { + pthread_t self = __pthread_self(); + locale_t old = self->locale; + locale_t global = &libc.global_locale; + + if (new) self->locale = new == LC_GLOBAL_LOCALE ? global : new; + + return old == global ? LC_GLOBAL_LOCALE : old; +} + +weak_alias(__uselocale, uselocale); diff --git a/third_party/ulib/musl/src/locale/wcscoll.c b/third_party/ulib/musl/src/locale/wcscoll.c new file mode 100644 index 000000000..6ae161259 --- /dev/null +++ b/third_party/ulib/musl/src/locale/wcscoll.c @@ -0,0 +1,15 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +/* FIXME: stub */ +int __wcscoll_l(const wchar_t* l, const wchar_t* r, locale_t locale) { + return wcscmp(l, r); +} + +int wcscoll(const wchar_t* l, const wchar_t* r) { + return __wcscoll_l(l, r, CURRENT_LOCALE); +} + +weak_alias(__wcscoll_l, wcscoll_l); diff --git a/third_party/ulib/musl/src/locale/wcsxfrm.c b/third_party/ulib/musl/src/locale/wcsxfrm.c new file mode 100644 index 000000000..67e43b15b --- /dev/null +++ b/third_party/ulib/musl/src/locale/wcsxfrm.c @@ -0,0 +1,22 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include + +/* collate only by code points */ +size_t __wcsxfrm_l(wchar_t* restrict dest, const wchar_t* restrict src, size_t n, locale_t loc) { + size_t l = wcslen(src); + if (l < n) { + wmemcpy(dest, src, l + 1); + } else if (n) { + wmemcpy(dest, src, n - 1); + dest[n - 1] = 0; + } + return l; +} + +size_t wcsxfrm(wchar_t* restrict dest, const wchar_t* restrict src, size_t n) { + return __wcsxfrm_l(dest, src, n, CURRENT_LOCALE); +} + +weak_alias(__wcsxfrm_l, wcsxfrm_l); diff --git a/third_party/ulib/musl/src/malloc/BUILD.gn b/third_party/ulib/musl/src/malloc/BUILD.gn new file mode 100644 index 000000000..7057d0b43 --- /dev/null +++ b/third_party/ulib/musl/src/malloc/BUILD.gn @@ -0,0 +1,17 @@ +source_set("malloc") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__brk.c", + "aligned_alloc.c", + "calloc.c", + "expand_heap.c", + "lite_malloc.c", + "malloc.c", + "malloc_usable_size.c", + "memalign.c", + "posix_memalign.c", + ] +} diff --git a/third_party/ulib/musl/src/malloc/DESIGN b/third_party/ulib/musl/src/malloc/DESIGN new file mode 100644 index 000000000..58b0523ff --- /dev/null +++ b/third_party/ulib/musl/src/malloc/DESIGN @@ -0,0 +1,22 @@ + + +In principle, this memory allocator is roughly equivalent to Doug +Lea's dlmalloc with fine-grained locking. + + + +malloc: + +Uses a freelist binned by chunk size, with a bitmap to optimize +searching for the smallest non-empty bin which can satisfy an +allocation. If no free chunks are available, it creates a new chunk of +the requested size and attempts to merge it with any existing free +chunk immediately below the newly created chunk. + +Whether the chunk was obtained from a bin or newly created, it's +likely to be larger than the requested allocation. malloc always +finishes its work by passing the new chunk to realloc, which will +split it into two chunks and free the tail portion. + + + diff --git a/third_party/ulib/musl/src/malloc/__brk.c b/third_party/ulib/musl/src/malloc/__brk.c new file mode 100644 index 000000000..d7a8f362a --- /dev/null +++ b/third_party/ulib/musl/src/malloc/__brk.c @@ -0,0 +1,6 @@ +#include + +uintptr_t __brk(uintptr_t addr) { + // TODO(kulakowski) Implement brk? + return -1; +} diff --git a/third_party/ulib/musl/src/malloc/aligned_alloc.c b/third_party/ulib/musl/src/malloc/aligned_alloc.c new file mode 100644 index 000000000..c4db3af4d --- /dev/null +++ b/third_party/ulib/musl/src/malloc/aligned_alloc.c @@ -0,0 +1,7 @@ +#include + +void* __memalign(size_t, size_t); + +void* aligned_alloc(size_t align, size_t len) { + return __memalign(align, len); +} diff --git a/third_party/ulib/musl/src/malloc/calloc.c b/third_party/ulib/musl/src/malloc/calloc.c new file mode 100644 index 000000000..d96e6ba03 --- /dev/null +++ b/third_party/ulib/musl/src/malloc/calloc.c @@ -0,0 +1,12 @@ +#include +#include + +void* __malloc0(size_t); + +void* calloc(size_t m, size_t n) { + if (n && m > (size_t)-1 / n) { + errno = ENOMEM; + return 0; + } + return __malloc0(n * m); +} diff --git a/third_party/ulib/musl/src/malloc/expand_heap.c b/third_party/ulib/musl/src/malloc/expand_heap.c new file mode 100644 index 000000000..1855294d0 --- /dev/null +++ b/third_party/ulib/musl/src/malloc/expand_heap.c @@ -0,0 +1,72 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include + +/* This function returns true if the interval [old,new] + * intersects the 'len'-sized interval below &libc.auxv + * (interpreted as the main-thread stack) or below &b + * (the current stack). It is used to defend against + * buggy brk implementations that can cross the stack. */ + +static int traverses_stack_p(uintptr_t old, uintptr_t new) { + const uintptr_t len = 8 << 20; + uintptr_t a, b; + + b = (uintptr_t)libc.auxv; + a = b > len ? b - len : 0; + if (new > a && old < b) return 1; + + b = (uintptr_t)&b; + a = b > len ? b - len : 0; + if (new > a && old < b) return 1; + + return 0; +} + +uintptr_t __brk(uintptr_t); +void* __mmap(void*, size_t, int, int, int, off_t); + +/* Expand the heap in-place if brk can be used, or otherwise via mmap, + * using an exponential lower bound on growth by mmap to make + * fragmentation asymptotically irrelevant. The size argument is both + * an input and an output, since the caller needs to know the size + * allocated, which will be larger than requested due to page alignment + * and mmap minimum size rules. The caller is responsible for locking + * to prevent concurrent calls. */ + +void* __expand_heap(size_t* pn) { + static uintptr_t brk; + static unsigned mmap_step; + size_t n = *pn; + + if (n > SIZE_MAX / 2 - PAGE_SIZE) { + errno = ENOMEM; + return 0; + } + n += -n & PAGE_SIZE - 1; + + if (!brk) { + brk = __brk(0); + brk += -brk & PAGE_SIZE - 1; + } + + if (n < SIZE_MAX - brk && !traverses_stack_p(brk, brk + n) && + __brk(brk + n) == brk + n) { + *pn = n; + brk += n; + return (void*)(brk - n); + } + + size_t min = (size_t)PAGE_SIZE << mmap_step / 2; + if (n < min) n = min; + void* area = __mmap(0, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (area == MAP_FAILED) + return 0; + *pn = n; + mmap_step++; + + return area; +} diff --git a/third_party/ulib/musl/src/malloc/lite_malloc.c b/third_party/ulib/musl/src/malloc/lite_malloc.c new file mode 100644 index 000000000..fd3a2013b --- /dev/null +++ b/third_party/ulib/musl/src/malloc/lite_malloc.c @@ -0,0 +1,51 @@ +#include "libc.h" +#include +#include +#include +#include + +#include + +#define ALIGN 16 + +void* __expand_heap(size_t*); + +static void* __simple_malloc(size_t n) { + static char *cur, *end; + static mxr_mutex_t lock; + size_t align = 1, pad; + void* p; + + if (!n) n++; + while (align < n && align < ALIGN) + align += align; + + mxr_mutex_lock(&lock); + + pad = -(uintptr_t)cur & align - 1; + + if (n <= SIZE_MAX / 2 + ALIGN) n += pad; + + if (n > end - cur) { + size_t m = n; + char* new = __expand_heap(&m); + if (!new) { + mxr_mutex_unlock(&lock); + return 0; + } + if (new != end) { + cur = new; + n -= pad; + pad = 0; + } + end = new + m; + } + + p = cur + pad; + cur += n; + mxr_mutex_unlock(&lock); + return p; +} + +weak_alias(__simple_malloc, malloc); +weak_alias(__simple_malloc, __malloc0); diff --git a/third_party/ulib/musl/src/malloc/malloc.c b/third_party/ulib/musl/src/malloc/malloc.c new file mode 100644 index 000000000..544f5d2b9 --- /dev/null +++ b/third_party/ulib/musl/src/malloc/malloc.c @@ -0,0 +1,482 @@ +#define _GNU_SOURCE +#include "atomic.h" +#include "libc.h" +#include "malloc_impl.h" +#include "pthread_impl.h" +#include +#include +#include +#include +#include +#include + +#include + +#if defined(__GNUC__) && defined(__PIC__) +#define inline inline __attribute__((always_inline)) +#endif + +void* __mmap(void*, size_t, int, int, int, off_t); +int __munmap(void*, size_t); +void* __mremap(void*, size_t, size_t, int, ...); +int __madvise(void*, size_t, int); + +struct bin { + mxr_mutex_t lock; + struct chunk* head; + struct chunk* tail; +}; + +static struct { + volatile uint64_t binmap; + struct bin bins[64]; + mxr_mutex_t free_lock; +} mal; + +#define SIZE_ALIGN (4 * sizeof(size_t)) +#define SIZE_MASK (-SIZE_ALIGN) +#define MMAP_THRESHOLD (0x1c00 * SIZE_ALIGN) +#define DONTCARE 16 +#define RECLAIM 163840 + +#define FREE_FILL 0x77 + +#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head)) + +/* Synchronization tools */ + +static inline void lock_bin(int i) { + mxr_mutex_lock(&mal.bins[i].lock); + if (!mal.bins[i].head) mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); +} + +static inline void unlock_bin(int i) { + mxr_mutex_unlock(&mal.bins[i].lock); +} + +static int first_set(uint64_t x) { +#if 1 + return a_ctz_64(x); +#else + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 62, 5, 39, 46, 44, 42, + 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, + 23, 58, 17, 10, 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12}; + static const char debruijn32[32] = {0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, + 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, + 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x >> 32; + return 32 + debruijn32[(y & -y) * 0x076be629 >> 27]; + } + return debruijn32[(y & -y) * 0x076be629 >> 27]; + } + return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; +#endif +} + +static int bin_index(size_t x) { + x = x / SIZE_ALIGN - 1; + if (x <= 32) return x; + if (x > 0x1c00) return 63; + return ((union { + float v; + uint32_t r; + }){(int)x} + .r >> + 21) - + 496; +} + +static int bin_index_up(size_t x) { + x = x / SIZE_ALIGN - 1; + if (x <= 32) return x; + return ((union { + float v; + uint32_t r; + }){(int)x} + .r + + 0x1fffff >> + 21) - + 496; +} + +#if 0 +void __dump_heap(int x) +{ + struct chunk *c; + int i; + for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c)) + fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n", + c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)), + c->csize & 15, + NEXT_CHUNK(c)->psize & 15); + for (i=0; i<64; i++) { + if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) { + fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head); + if (!(mal.binmap & 1ULL<psize = 0 | C_INUSE; + } + + /* Record new heap end and fill in footer. */ + end = (char*)p + n; + w = MEM_TO_CHUNK(end); + w->psize = n | C_INUSE; + w->csize = 0 | C_INUSE; + + /* Fill in header, which may be new or may be replacing a + * zero-size sentinel header at the old end-of-heap. */ + w = MEM_TO_CHUNK(p); + w->csize = n | C_INUSE; + + mxr_mutex_unlock(&heap_lock); + + return w; +} + +static int adjust_size(size_t* n) { + /* Result of pointer difference must fit in ptrdiff_t. */ + if (*n - 1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) { + if (*n) { + errno = ENOMEM; + return -1; + } else { + *n = SIZE_ALIGN; + return 0; + } + } + *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK; + return 0; +} + +static void unbin(struct chunk* c, int i) { + if (c->prev == c->next) a_and_64(&mal.binmap, ~(1ULL << i)); + c->prev->next = c->next; + c->next->prev = c->prev; + c->csize |= C_INUSE; + NEXT_CHUNK(c)->psize |= C_INUSE; +} + +static int alloc_fwd(struct chunk* c) { + int i; + size_t k; + while (!((k = c->csize) & C_INUSE)) { + i = bin_index(k); + lock_bin(i); + if (c->csize == k) { + unbin(c, i); + unlock_bin(i); + return 1; + } + unlock_bin(i); + } + return 0; +} + +static int alloc_rev(struct chunk* c) { + int i; + size_t k; + while (!((k = c->psize) & C_INUSE)) { + i = bin_index(k); + lock_bin(i); + if (c->psize == k) { + unbin(PREV_CHUNK(c), i); + unlock_bin(i); + return 1; + } + unlock_bin(i); + } + return 0; +} + +/* pretrim - trims a chunk _prior_ to removing it from its bin. + * Must be called with i as the ideal bin for size n, j the bin + * for the _free_ chunk self, and bin j locked. */ +static int pretrim(struct chunk* self, size_t n, int i, int j) { + size_t n1; + struct chunk *next, *split; + + /* We cannot pretrim if it would require re-binning. */ + if (j < 40) return 0; + if (j < i + 3) { + if (j != 63) return 0; + n1 = CHUNK_SIZE(self); + if (n1 - n <= MMAP_THRESHOLD) return 0; + } else { + n1 = CHUNK_SIZE(self); + } + if (bin_index(n1 - n) != j) return 0; + + next = NEXT_CHUNK(self); + split = (void*)((char*)self + n); + + split->prev = self->prev; + split->next = self->next; + split->prev->next = split; + split->next->prev = split; + split->psize = n | C_INUSE; + split->csize = n1 - n; + next->psize = n1 - n; + self->csize = n | C_INUSE; + return 1; +} + +static void trim(struct chunk* self, size_t n) { + size_t n1 = CHUNK_SIZE(self); + struct chunk *next, *split; + + if (n >= n1 - DONTCARE) return; + + next = NEXT_CHUNK(self); + split = (void*)((char*)self + n); + + split->psize = n | C_INUSE; + split->csize = n1 - n | C_INUSE; + next->psize = n1 - n | C_INUSE; + self->csize = n | C_INUSE; + + free(CHUNK_TO_MEM(split)); +} + +void* malloc(size_t n) { + struct chunk* c; + int i, j; + + if (adjust_size(&n) < 0) return 0; + + if (n > MMAP_THRESHOLD) { + size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE; + char* base = __mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (base == (void*)-1) return 0; + c = (void*)(base + SIZE_ALIGN - OVERHEAD); + c->csize = len - (SIZE_ALIGN - OVERHEAD); + c->psize = SIZE_ALIGN - OVERHEAD; + return CHUNK_TO_MEM(c); + } + + i = bin_index_up(n); + for (;;) { + uint64_t mask = mal.binmap & -(1ULL << i); + if (!mask) { + c = expand_heap(n); + if (!c) return 0; + if (alloc_rev(c)) { + struct chunk* x = c; + c = PREV_CHUNK(c); + NEXT_CHUNK(x)->psize = c->csize = x->csize + CHUNK_SIZE(c); + } + break; + } + j = first_set(mask); + lock_bin(j); + c = mal.bins[j].head; + if (c != BIN_TO_CHUNK(j)) { + if (!pretrim(c, n, i, j)) unbin(c, j); + unlock_bin(j); + break; + } + unlock_bin(j); + } + + /* Now patch up in case we over-allocated */ + trim(c, n); + + return CHUNK_TO_MEM(c); +} + +void* __malloc0(size_t n) { + void* p = malloc(n); + if (p && !IS_MMAPPED(MEM_TO_CHUNK(p))) { + size_t* z; + n = (n + sizeof *z - 1) / sizeof *z; + for (z = p; n; n--, z++) + if (*z) *z = 0; + } + return p; +} + +void* realloc(void* p, size_t n) { + struct chunk *self, *next; + size_t n0, n1; + void* new; + + if (!p) return malloc(n); + + if (adjust_size(&n) < 0) return 0; + + self = MEM_TO_CHUNK(p); + n1 = n0 = CHUNK_SIZE(self); + + if (IS_MMAPPED(self)) { + size_t extra = self->psize; + char* base = (char*)self - extra; + size_t oldlen = n0 + extra; + size_t newlen = n + extra; + /* Crash on realloc of freed chunk */ + if (extra & 1) a_crash(); + if (newlen < PAGE_SIZE && (new = malloc(n))) { + memcpy(new, p, n - OVERHEAD); + free(p); + return new; + } + newlen = (newlen + PAGE_SIZE - 1) & -PAGE_SIZE; + if (oldlen == newlen) return p; + base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE); + if (base == (void*)-1) return newlen < oldlen ? p : 0; + self = (void*)(base + extra); + self->csize = newlen - extra; + return CHUNK_TO_MEM(self); + } + + next = NEXT_CHUNK(self); + + /* Crash on corrupted footer (likely from buffer overflow) */ + if (next->psize != self->csize) a_crash(); + + /* Merge adjacent chunks if we need more space. This is not + * a waste of time even if we fail to get enough space, because our + * subsequent call to free would otherwise have to do the merge. */ + if (n > n1 && alloc_fwd(next)) { + n1 += CHUNK_SIZE(next); + next = NEXT_CHUNK(next); + } + /* FIXME: find what's wrong here and reenable it..? */ + if (0 && n > n1 && alloc_rev(self)) { + self = PREV_CHUNK(self); + n1 += CHUNK_SIZE(self); + } + self->csize = n1 | C_INUSE; + next->psize = n1 | C_INUSE; + + /* If we got enough space, split off the excess and return */ + if (n <= n1) { + // memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD); + trim(self, n); + return CHUNK_TO_MEM(self); + } + + /* As a last resort, allocate a new chunk and copy to it. */ + new = malloc(n - OVERHEAD); + if (!new) return 0; + memcpy(new, p, n0 - OVERHEAD); + free(CHUNK_TO_MEM(self)); + return new; +} + +void free(void* p) { + struct chunk* self = MEM_TO_CHUNK(p); + struct chunk* next; + size_t final_size, new_size, size; + int reclaim = 0; + int i; + + if (!p) return; + + if (IS_MMAPPED(self)) { + size_t extra = self->psize; + char* base = (char*)self - extra; + size_t len = CHUNK_SIZE(self) + extra; + /* Crash on double free */ + if (extra & 1) a_crash(); + __munmap(base, len); + return; + } + +#if LK_DEBUGLEVEL > 1 + memset(p, FREE_FILL, CHUNK_SIZE(self) - OVERHEAD); +#endif + final_size = new_size = CHUNK_SIZE(self); + next = NEXT_CHUNK(self); + + /* Crash on corrupted footer (likely from buffer overflow) */ + if (next->psize != self->csize) a_crash(); + + for (;;) { + if (self->psize & next->csize & C_INUSE) { + self->csize = final_size | C_INUSE; + next->psize = final_size | C_INUSE; + i = bin_index(final_size); + lock_bin(i); + mxr_mutex_lock(&mal.free_lock); + if (self->psize & next->csize & C_INUSE) break; + mxr_mutex_unlock(&mal.free_lock); + unlock_bin(i); + } + + if (alloc_rev(self)) { + self = PREV_CHUNK(self); + size = CHUNK_SIZE(self); + final_size += size; + if (new_size + size > RECLAIM && (new_size + size ^ size) > size) reclaim = 1; + } + + if (alloc_fwd(next)) { + size = CHUNK_SIZE(next); + final_size += size; + if (new_size + size > RECLAIM && (new_size + size ^ size) > size) reclaim = 1; + next = NEXT_CHUNK(next); + } + } + + if (!(mal.binmap & 1ULL << i)) a_or_64(&mal.binmap, 1ULL << i); + + self->csize = final_size; + next->psize = final_size; + mxr_mutex_unlock(&mal.free_lock); + + self->next = BIN_TO_CHUNK(i); + self->prev = mal.bins[i].tail; + self->next->prev = self; + self->prev->next = self; + + /* Replace middle of large chunks with fresh zero pages */ + if (reclaim) { + uintptr_t a = (uintptr_t)self + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE; + uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE; +#if 1 + __madvise((void*)a, b - a, MADV_DONTNEED); +#else + __mmap((void*)a, b - a, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, + 0); +#endif + } + + unlock_bin(i); +} diff --git a/third_party/ulib/musl/src/malloc/malloc_usable_size.c b/third_party/ulib/musl/src/malloc/malloc_usable_size.c new file mode 100644 index 000000000..9ef71a8e4 --- /dev/null +++ b/third_party/ulib/musl/src/malloc/malloc_usable_size.c @@ -0,0 +1,8 @@ +#include +#include "malloc_impl.h" + +void* (*const __realloc_dep)(void*, size_t) = realloc; + +size_t malloc_usable_size(void* p) { + return p ? CHUNK_SIZE(MEM_TO_CHUNK(p)) - OVERHEAD : 0; +} diff --git a/third_party/ulib/musl/src/malloc/memalign.c b/third_party/ulib/musl/src/malloc/memalign.c new file mode 100644 index 000000000..f756acb4f --- /dev/null +++ b/third_party/ulib/musl/src/malloc/memalign.c @@ -0,0 +1,54 @@ +#include "libc.h" +#include +#include +#include + +/* This function should work with most dlmalloc-like chunk bookkeeping + * systems, but it's only guaranteed to work with the native implementation + * used in this library. */ + +void* __memalign(size_t align, size_t len) { + unsigned char *mem, *new, *end; + size_t header, footer; + + if ((align & -align) != align) { + errno = EINVAL; + return NULL; + } + + if (len > SIZE_MAX - align) { + errno = ENOMEM; + return NULL; + } + + if (align <= 4 * sizeof(size_t)) { + if (!(mem = malloc(len))) return NULL; + return mem; + } + + if (!(mem = malloc(len + align - 1))) return NULL; + + new = (void*)((uintptr_t)mem + align - 1 & -align); + if (new == mem) return mem; + + header = ((size_t*)mem)[-1]; + + if (!(header & 7)) { + ((size_t*)new)[-2] = ((size_t*)mem)[-2] + (new - mem); + ((size_t*)new)[-1] = ((size_t*)mem)[-1] - (new - mem); + return new; + } + + end = mem + (header & -8); + footer = ((size_t*)end)[-2]; + + ((size_t*)mem)[-1] = header & 7 | new - mem; + ((size_t*)new)[-2] = footer & 7 | new - mem; + ((size_t*)new)[-1] = header & 7 | end - new; + ((size_t*)end)[-2] = footer & 7 | end - new; + + free(mem); + return new; +} + +weak_alias(__memalign, memalign); diff --git a/third_party/ulib/musl/src/malloc/posix_memalign.c b/third_party/ulib/musl/src/malloc/posix_memalign.c new file mode 100644 index 000000000..80b35cc08 --- /dev/null +++ b/third_party/ulib/musl/src/malloc/posix_memalign.c @@ -0,0 +1,12 @@ +#include +#include + +void* __memalign(size_t, size_t); + +int posix_memalign(void** res, size_t align, size_t len) { + if (align < sizeof(void*)) return EINVAL; + void* mem = __memalign(align, len); + if (!mem) return errno; + *res = mem; + return 0; +} diff --git a/third_party/ulib/musl/src/math/BUILD.gn b/third_party/ulib/musl/src/math/BUILD.gn new file mode 100644 index 000000000..410042295 --- /dev/null +++ b/third_party/ulib/musl/src/math/BUILD.gn @@ -0,0 +1,222 @@ +source_set("math") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__expo2.c", + "__expo2f.c", + "__fpclassify.c", + "__fpclassifyf.c", + "__fpclassifyl.c", + "__signbit.c", + "__signbitf.c", + "__signbitl.c", + "acosh.c", + "acoshf.c", + "acoshl.c", + "asinh.c", + "asinhf.c", + "asinhl.c", + "atanh.c", + "atanhf.c", + "atanhl.c", + "ceil.c", + "ceilf.c", + "copysign.c", + "copysignf.c", + "copysignl.c", + "cosh.c", + "coshf.c", + "coshl.c", + "cosl.c", + "exp10.c", + "exp10f.c", + "exp10l.c", + "fdim.c", + "fdimf.c", + "fdiml.c", + "finite.c", + "finitef.c", + "floor.c", + "floorf.c", + "fmax.c", + "fmaxf.c", + "fmaxl.c", + "fmin.c", + "fminf.c", + "fminl.c", + "fmod.c", + "fmodf.c", + "frexp.c", + "frexpf.c", + "frexpl.c", + "hypot.c", + "hypotf.c", + "hypotl.c", + "ilogb.c", + "ilogbf.c", + "ilogbl.c", + "ldexp.c", + "ldexpf.c", + "ldexpl.c", + "lgamma.c", + "lgammaf.c", + "llround.c", + "llroundf.c", + "llroundl.c", + "logb.c", + "logbf.c", + "logbl.c", + "lround.c", + "lroundf.c", + "lroundl.c", + "modf.c", + "modff.c", + "modfl.c", + "nan.c", + "nanf.c", + "nanl.c", + "nearbyint.c", + "nearbyintf.c", + "nearbyintl.c", + "nextafter.c", + "nextafterf.c", + "nextafterl.c", + "nexttoward.c", + "nexttowardf.c", + "nexttowardl.c", + "remainder.c", + "remainderf.c", + "remquo.c", + "remquof.c", + "remquol.c", + "rint.c", + "rintf.c", + "round.c", + "roundf.c", + "roundl.c", + "scalbln.c", + "scalblnf.c", + "scalblnl.c", + "scalbn.c", + "scalbnf.c", + "scalbnl.c", + "signgam.c", + "significand.c", + "significandf.c", + "sincosl.c", + "sinh.c", + "sinhf.c", + "sinhl.c", + "sinl.c", + "tanh.c", + "tanhf.c", + "tanhl.c", + "tanl.c", + "tgamma.c", + "tgammaf.c", + "trunc.c", + "truncf.c", + ] + if (target_cpu == "arm") { + sources += [ + "__invtrigl.c", + "arm/fabs.c", + "arm/fabsf.c", + "arm/sqrt.c", + "arm/sqrtf.c", + "ceill.c", + "fabsl.c", + "floorl.c", + "fmodl.c", + "llrint.c", + "llrintf.c", + "llrintl.c", + "lrint.c", + "lrintf.c", + "lrintl.c", + "remainderl.c", + "rintl.c", + "sqrtl.c", + "truncl.c", + ] + } else if (target_cpu == "arm64") { + sources += [ + "__invtrigl.c", + "aarch64/fabs.s", + "aarch64/fabsf.s", + "aarch64/sqrt.s", + "aarch64/sqrtf.s", + "ceill.c", + "fabsl.c", + "floorl.c", + "fmodl.c", + "llrint.c", + "llrintf.c", + "llrintl.c", + "lrint.c", + "lrintf.c", + "lrintl.c", + "remainderl.c", + "rintl.c", + "sqrtl.c", + "truncl.c", + ] + } else if (target_cpu == "x64") { + sources += [ + "x86_64/__invtrigl.s", + "x86_64/acosl.s", + "x86_64/asinl.s", + "x86_64/atan2l.s", + "x86_64/atanl.s", + "x86_64/ceill.s", + "x86_64/exp2l.s", + "x86_64/expl.s", + "x86_64/expm1l.s", + "x86_64/fabs.s", + "x86_64/fabsf.s", + "x86_64/fabsl.s", + "x86_64/floorl.s", + "x86_64/fmodl.s", + "x86_64/llrint.s", + "x86_64/llrintf.s", + "x86_64/llrintl.s", + "x86_64/log10l.s", + "x86_64/log1pl.s", + "x86_64/log2l.s", + "x86_64/logl.s", + "x86_64/lrint.s", + "x86_64/lrintf.s", + "x86_64/lrintl.s", + "x86_64/remainderl.s", + "x86_64/rintl.s", + "x86_64/sqrt.s", + "x86_64/sqrtf.s", + "x86_64/sqrtl.s", + "x86_64/truncl.s", + ] + } else { + sources += [ + "__invtrigl.c", + "ceill.c", + "fabs.c", + "fabsf.c", + "fabsl.c", + "floorl.c", + "fmodl.c", + "llrint.c", + "llrintf.c", + "llrintl.c", + "lrint.c", + "lrintf.c", + "lrintl.c", + "remainderl.c", + "rintl.c", + "sqrt.c", + "sqrtf.c", + "sqrtl.c", + "truncl.c", + ] + } +} diff --git a/third_party/ulib/musl/src/math/__expo2.c b/third_party/ulib/musl/src/math/__expo2.c new file mode 100644 index 000000000..3ada99f4f --- /dev/null +++ b/third_party/ulib/musl/src/math/__expo2.c @@ -0,0 +1,15 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ +static const int k = 2043; +static const double kln2 = 0x1.62066151add8bp+10; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +double __expo2(double x) { + double scale; + + /* note that k is odd and scale*scale overflows */ + INSERT_WORDS(scale, (uint32_t)(0x3ff + k / 2) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/third_party/ulib/musl/src/math/__expo2f.c b/third_party/ulib/musl/src/math/__expo2f.c new file mode 100644 index 000000000..5d14abdab --- /dev/null +++ b/third_party/ulib/musl/src/math/__expo2f.c @@ -0,0 +1,15 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +static const int k = 235; +static const float kln2 = 0x1.45c778p+7f; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +float __expo2f(float x) { + float scale; + + /* note that k is odd and scale*scale overflows */ + SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k / 2) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + return expf(x - kln2) * scale * scale; +} diff --git a/third_party/ulib/musl/src/math/__fpclassify.c b/third_party/ulib/musl/src/math/__fpclassify.c new file mode 100644 index 000000000..cd4be0e2a --- /dev/null +++ b/third_party/ulib/musl/src/math/__fpclassify.c @@ -0,0 +1,13 @@ +#include +#include + +int __fpclassify(double x) { + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + if (!e) return u.i << 1 ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7ff) return u.i << 12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/third_party/ulib/musl/src/math/__fpclassifyf.c b/third_party/ulib/musl/src/math/__fpclassifyf.c new file mode 100644 index 000000000..d0958040e --- /dev/null +++ b/third_party/ulib/musl/src/math/__fpclassifyf.c @@ -0,0 +1,13 @@ +#include +#include + +int __fpclassifyf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + int e = u.i >> 23 & 0xff; + if (!e) return u.i << 1 ? FP_SUBNORMAL : FP_ZERO; + if (e == 0xff) return u.i << 9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/third_party/ulib/musl/src/math/__fpclassifyl.c b/third_party/ulib/musl/src/math/__fpclassifyl.c new file mode 100644 index 000000000..4372b3183 --- /dev/null +++ b/third_party/ulib/musl/src/math/__fpclassifyl.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __fpclassifyl(long double x) { + return __fpclassify(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int msb = u.i.m >> 63; + if (!e && !msb) return u.i.m ? FP_SUBNORMAL : FP_ZERO; + if (!msb) return FP_NAN; + if (e == 0x7fff) return u.i.m << 1 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + u.i.se = 0; + if (!e) return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} +#endif diff --git a/third_party/ulib/musl/src/math/__invtrigl.c b/third_party/ulib/musl/src/math/__invtrigl.c new file mode 100644 index 000000000..7fc63d5f1 --- /dev/null +++ b/third_party/ulib/musl/src/math/__invtrigl.c @@ -0,0 +1,60 @@ +#include "__invtrigl.h" +#include + +#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double pS0 = 1.66666666666666666631e-01L, pS1 = -4.16313987993683104320e-01L, + pS2 = 3.69068046323246813704e-01L, pS3 = -1.36213932016738603108e-01L, + pS4 = 1.78324189708471965733e-02L, pS5 = -2.19216428382605211588e-04L, + pS6 = -7.10526623669075243183e-06L, qS1 = -2.94788392796209867269e+00L, + qS2 = 3.27309890266528636716e+00L, qS3 = -1.68285799854822427013e+00L, + qS4 = 3.90699412641738801874e-01L, qS5 = -3.14365703596053263322e-02L; + +const long double pio2_hi = 1.57079632679489661926L; +const long double pio2_lo = -2.50827880633416601173e-20L; + +/* used in asinl() and acosl() */ +/* R(x^2) is a rational approximation of (asin(x)-x)/x^3 with Remez algorithm */ +long double __invtrigl_R(long double z) { + long double p, q; + p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * (pS5 + z * pS6)))))); + q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * (qS4 + z * qS5)))); + return p / q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +static const long double pS0 = 1.66666666666666666666666666666700314e-01L, + pS1 = -7.32816946414566252574527475428622708e-01L, + pS2 = 1.34215708714992334609030036562143589e+00L, + pS3 = -1.32483151677116409805070261790752040e+00L, + pS4 = 7.61206183613632558824485341162121989e-01L, + pS5 = -2.56165783329023486777386833928147375e-01L, + pS6 = 4.80718586374448793411019434585413855e-02L, + pS7 = -4.42523267167024279410230886239774718e-03L, + pS8 = 1.44551535183911458253205638280410064e-04L, + pS9 = -2.10558957916600254061591040482706179e-07L, + qS1 = -4.84690167848739751544716485245697428e+00L, + qS2 = 9.96619113536172610135016921140206980e+00L, + qS3 = -1.13177895428973036660836798461641458e+01L, + qS4 = 7.74004374389488266169304117714658761e+00L, + qS5 = -3.25871986053534084709023539900339905e+00L, + qS6 = 8.27830318881232209752469022352928864e-01L, + qS7 = -1.18768052702942805423330715206348004e-01L, + qS8 = 8.32600764660522313269101537926539470e-03L, + qS9 = -1.99407384882605586705979504567947007e-04L; + +const long double pio2_hi = 1.57079632679489661923132169163975140L; +const long double pio2_lo = 4.33590506506189051239852201302167613e-35L; + +long double __invtrigl_R(long double z) { + long double p, q; + p = z * (pS0 + + z * (pS1 + + z * (pS2 + + z * (pS3 + + z * (pS4 + z * (pS5 + z * (pS6 + z * (pS7 + z * (pS8 + z * pS9))))))))); + q = 1.0 + + z * (qS1 + + z * (qS2 + + z * (qS3 + z * (qS4 + z * (qS5 + z * (pS6 + z * (pS7 + z * (pS8 + z * pS9)))))))); + return p / q; +} +#endif diff --git a/third_party/ulib/musl/src/math/__signbit.c b/third_party/ulib/musl/src/math/__signbit.c new file mode 100644 index 000000000..9a61faa7e --- /dev/null +++ b/third_party/ulib/musl/src/math/__signbit.c @@ -0,0 +1,10 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbit(double x) { + union { + double d; + uint64_t i; + } y = {x}; + return y.i >> 63; +} diff --git a/third_party/ulib/musl/src/math/__signbitf.c b/third_party/ulib/musl/src/math/__signbitf.c new file mode 100644 index 000000000..a86bb8819 --- /dev/null +++ b/third_party/ulib/musl/src/math/__signbitf.c @@ -0,0 +1,10 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbitf(float x) { + union { + float f; + uint32_t i; + } y = {x}; + return y.i >> 31; +} diff --git a/third_party/ulib/musl/src/math/__signbitl.c b/third_party/ulib/musl/src/math/__signbitl.c new file mode 100644 index 000000000..edcbc7fc2 --- /dev/null +++ b/third_party/ulib/musl/src/math/__signbitl.c @@ -0,0 +1,12 @@ +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +int __signbitl(long double x) { + union ldshape u = {x}; + return u.i.se >> 15; +} +#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __signbitl(long double x) { + return __signbit(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/aarch64/fabs.s b/third_party/ulib/musl/src/math/aarch64/fabs.s new file mode 100644 index 000000000..8c04d0917 --- /dev/null +++ b/third_party/ulib/musl/src/math/aarch64/fabs.s @@ -0,0 +1,6 @@ +.text +.global fabs +.type fabs,%function +fabs: + fabs d0, d0 + ret diff --git a/third_party/ulib/musl/src/math/aarch64/fabsf.s b/third_party/ulib/musl/src/math/aarch64/fabsf.s new file mode 100644 index 000000000..6e96dd43e --- /dev/null +++ b/third_party/ulib/musl/src/math/aarch64/fabsf.s @@ -0,0 +1,6 @@ +.text +.global fabsf +.type fabsf,%function +fabsf: + fabs s0, s0 + ret diff --git a/third_party/ulib/musl/src/math/aarch64/sqrt.s b/third_party/ulib/musl/src/math/aarch64/sqrt.s new file mode 100644 index 000000000..1917e18d1 --- /dev/null +++ b/third_party/ulib/musl/src/math/aarch64/sqrt.s @@ -0,0 +1,6 @@ +.text +.global sqrt +.type sqrt,%function +sqrt: + fsqrt d0, d0 + ret diff --git a/third_party/ulib/musl/src/math/aarch64/sqrtf.s b/third_party/ulib/musl/src/math/aarch64/sqrtf.s new file mode 100644 index 000000000..1639497b0 --- /dev/null +++ b/third_party/ulib/musl/src/math/aarch64/sqrtf.s @@ -0,0 +1,6 @@ +.text +.global sqrtf +.type sqrtf,%function +sqrtf: + fsqrt s0, s0 + ret diff --git a/third_party/ulib/musl/src/math/acosh.c b/third_party/ulib/musl/src/math/acosh.c new file mode 100644 index 000000000..27d6d10e1 --- /dev/null +++ b/third_party/ulib/musl/src/math/acosh.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD == 2 +#undef sqrt +#define sqrt sqrtl +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +double acosh(double x) { + union { + double f; + uint64_t i; + } u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if (e < 0x3ff + 1) /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x - 1 + sqrt((x - 1) * (x - 1) + 2 * (x - 1))); + if (e < 0x3ff + 26) /* |x| < 0x1p26 */ + return log(2 * x - 1 / (x + sqrt(x * x - 1))); + /* |x| >= 0x1p26 or nan */ + return log(x) + 0.693147180559945309417232121458176568; +} diff --git a/third_party/ulib/musl/src/math/acoshf.c b/third_party/ulib/musl/src/math/acoshf.c new file mode 100644 index 000000000..8037fd647 --- /dev/null +++ b/third_party/ulib/musl/src/math/acoshf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD == 2 +#undef sqrtf +#define sqrtf sqrtl +#elif FLT_EVAL_METHOD == 1 +#undef sqrtf +#define sqrtf sqrt +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +float acoshf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + uint32_t a = u.i & 0x7fffffff; + + if (a < 0x3f800000 + (1 << 23)) /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x - 1 + sqrtf((x - 1) * (x - 1) + 2 * (x - 1))); + if (a < 0x3f800000 + (12 << 23)) /* |x| < 0x1p12 */ + return logf(2 * x - 1 / (x + sqrtf(x * x - 1))); + /* x >= 0x1p12 */ + return logf(x) + 0.693147180559945309417232121458176568f; +} diff --git a/third_party/ulib/musl/src/math/acoshl.c b/third_party/ulib/musl/src/math/acoshl.c new file mode 100644 index 000000000..34946ec3d --- /dev/null +++ b/third_party/ulib/musl/src/math/acoshl.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acoshl(long double x) { + return acosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* acosh(x) = log(x + sqrt(x*x-1)) */ +long double acoshl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (e < 0x3fff + 1) /* |x| < 2, invalid if x < 1 or nan */ + return log1pl(x - 1 + sqrtl((x - 1) * (x - 1) + 2 * (x - 1))); + if (e < 0x3fff + 32) /* |x| < 0x1p32 */ + return logl(2 * x - 1 / (x + sqrtl(x * x - 1))); + return logl(x) + 0.693147180559945309417232121458176568L; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double acoshl(long double x) { + return acosh(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/arm/fabs.c b/third_party/ulib/musl/src/math/arm/fabs.c new file mode 100644 index 000000000..0a0ef89c8 --- /dev/null +++ b/third_party/ulib/musl/src/math/arm/fabs.c @@ -0,0 +1,14 @@ +#include + +#if __ARM_PCS_VFP + +double fabs(double x) { + __asm__("vabs.f64 %P0, %P1" : "=w"(x) : "w"(x)); + return x; +} + +#else + +#include "../fabs.c" + +#endif diff --git a/third_party/ulib/musl/src/math/arm/fabsf.c b/third_party/ulib/musl/src/math/arm/fabsf.c new file mode 100644 index 000000000..49f6f1096 --- /dev/null +++ b/third_party/ulib/musl/src/math/arm/fabsf.c @@ -0,0 +1,14 @@ +#include + +#if __ARM_PCS_VFP && !BROKEN_VFP_ASM + +float fabsf(float x) { + __asm__("vabs.f32 %0, %1" : "=t"(x) : "t"(x)); + return x; +} + +#else + +#include "../fabsf.c" + +#endif diff --git a/third_party/ulib/musl/src/math/arm/sqrt.c b/third_party/ulib/musl/src/math/arm/sqrt.c new file mode 100644 index 000000000..cc0fc5dba --- /dev/null +++ b/third_party/ulib/musl/src/math/arm/sqrt.c @@ -0,0 +1,14 @@ +#include + +#if __ARM_PCS_VFP || (__VFP_FP__ && !__SOFTFP__) + +double sqrt(double x) { + __asm__("vsqrt.f64 %P0, %P1" : "=w"(x) : "w"(x)); + return x; +} + +#else + +#include "../sqrt.c" + +#endif diff --git a/third_party/ulib/musl/src/math/arm/sqrtf.c b/third_party/ulib/musl/src/math/arm/sqrtf.c new file mode 100644 index 000000000..26da3da88 --- /dev/null +++ b/third_party/ulib/musl/src/math/arm/sqrtf.c @@ -0,0 +1,14 @@ +#include + +#if (__ARM_PCS_VFP || (__VFP_FP__ && !__SOFTFP__)) && !BROKEN_VFP_ASM + +float sqrtf(float x) { + __asm__("vsqrt.f32 %0, %1" : "=t"(x) : "t"(x)); + return x; +} + +#else + +#include "../sqrtf.c" + +#endif diff --git a/third_party/ulib/musl/src/math/asinh.c b/third_party/ulib/musl/src/math/asinh.c new file mode 100644 index 000000000..de90c36ba --- /dev/null +++ b/third_party/ulib/musl/src/math/asinh.c @@ -0,0 +1,30 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +double asinh(double x) { + union { + double f; + uint64_t i; + } u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + + /* |x| */ + u.i &= (uint64_t)-1 / 2; + x = u.f; + + if (e >= 0x3ff + 26) { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + 0.693147180559945309417232121458176568; + } else if (e >= 0x3ff + 1) { + /* |x| >= 2 */ + x = log(2 * x + 1 / (sqrt(x * x + 1) + x)); + } else if (e >= 0x3ff - 26) { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x * x / (sqrt(x * x + 1) + 1)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/third_party/ulib/musl/src/math/asinhf.c b/third_party/ulib/musl/src/math/asinhf.c new file mode 100644 index 000000000..070a83b18 --- /dev/null +++ b/third_party/ulib/musl/src/math/asinhf.c @@ -0,0 +1,30 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +float asinhf(float x) { + union { + float f; + uint32_t i; + } u = {.f = x}; + uint32_t i = u.i & 0x7fffffff; + unsigned s = u.i >> 31; + + /* |x| */ + u.i = i; + x = u.f; + + if (i >= 0x3f800000 + (12 << 23)) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + 0.693147180559945309417232121458176568f; + } else if (i >= 0x3f800000 + (1 << 23)) { + /* |x| >= 2 */ + x = logf(2 * x + 1 / (sqrtf(x * x + 1) + x)); + } else if (i >= 0x3f800000 - (12 << 23)) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x * x / (sqrtf(x * x + 1) + 1)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/third_party/ulib/musl/src/math/asinhl.c b/third_party/ulib/musl/src/math/asinhl.c new file mode 100644 index 000000000..6a9578a09 --- /dev/null +++ b/third_party/ulib/musl/src/math/asinhl.c @@ -0,0 +1,38 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinhl(long double x) { + return asinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +long double asinhl(long double x) { + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e >= 0x3fff + 32) { + /* |x| >= 0x1p32 or inf or nan */ + x = logl(x) + 0.693147180559945309417232121458176568L; + } else if (e >= 0x3fff + 1) { + /* |x| >= 2 */ + x = logl(2 * x + 1 / (sqrtl(x * x + 1) + x)); + } else if (e >= 0x3fff - 32) { + /* |x| >= 0x1p-32 */ + x = log1pl(x + x * x / (sqrtl(x * x + 1) + 1)); + } else { + /* |x| < 0x1p-32, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double asinhl(long double x) { + return asinh(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/atanh.c b/third_party/ulib/musl/src/math/atanh.c new file mode 100644 index 000000000..afe0b909c --- /dev/null +++ b/third_party/ulib/musl/src/math/atanh.c @@ -0,0 +1,30 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +double atanh(double x) { + union { + double f; + uint64_t i; + } u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + double_t y; + + /* |x| */ + u.i &= (uint64_t)-1 / 2; + y = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { + /* handle underflow */ + if (e == 0) FORCE_EVAL((float)y); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5 * log1p(2 * y + 2 * y * y / (1 - y)); + } + } else { + /* avoid overflow */ + y = 0.5 * log1p(2 * (y / (1 - y))); + } + return s ? -y : y; +} diff --git a/third_party/ulib/musl/src/math/atanhf.c b/third_party/ulib/musl/src/math/atanhf.c new file mode 100644 index 000000000..828793f1f --- /dev/null +++ b/third_party/ulib/musl/src/math/atanhf.c @@ -0,0 +1,29 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +float atanhf(float x) { + union { + float f; + uint32_t i; + } u = {.f = x}; + unsigned s = u.i >> 31; + float_t y; + + /* |x| */ + u.i &= 0x7fffffff; + y = u.f; + + if (u.i < 0x3f800000 - (1 << 23)) { + if (u.i < 0x3f800000 - (32 << 23)) { + /* handle underflow */ + if (u.i < (1 << 23)) FORCE_EVAL((float)(y * y)); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5f * log1pf(2 * y + 2 * y * y / (1 - y)); + } + } else { + /* avoid overflow */ + y = 0.5f * log1pf(2 * (y / (1 - y))); + } + return s ? -y : y; +} diff --git a/third_party/ulib/musl/src/math/atanhl.c b/third_party/ulib/musl/src/math/atanhl.c new file mode 100644 index 000000000..379666d4a --- /dev/null +++ b/third_party/ulib/musl/src/math/atanhl.c @@ -0,0 +1,32 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanhl(long double x) { + return atanh(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +long double atanhl(long double x) { + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - LDBL_MANT_DIG / 2) { + /* handle underflow */ + if (e == 0) FORCE_EVAL((float)x); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5 * log1pl(2 * x + 2 * x * x / (1 - x)); + } + } else { + /* avoid overflow */ + x = 0.5 * log1pl(2 * (x / (1 - x))); + } + return s ? -x : x; +} +#endif diff --git a/third_party/ulib/musl/src/math/ceil.c b/third_party/ulib/musl/src/math/ceil.c new file mode 100644 index 000000000..22098af79 --- /dev/null +++ b/third_party/ulib/musl/src/math/ceil.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1 / EPS; + +double ceil(double x) { + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff + 52 || x == 0) return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff - 1) { + FORCE_EVAL(y); + return u.i >> 63 ? -0.0 : 1; + } + if (y < 0) return x + y + 1; + return x + y; +} diff --git a/third_party/ulib/musl/src/math/ceilf.c b/third_party/ulib/musl/src/math/ceilf.c new file mode 100644 index 000000000..c9382ffa4 --- /dev/null +++ b/third_party/ulib/musl/src/math/ceilf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +float ceilf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} diff --git a/third_party/ulib/musl/src/math/ceill.c b/third_party/ulib/musl/src/math/ceill.c new file mode 100644 index 000000000..8cd94022f --- /dev/null +++ b/third_party/ulib/musl/src/math/ceill.c @@ -0,0 +1,30 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double ceill(long double x) { + return ceil(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1 / LDBL_EPSILON; + +long double ceill(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff + LDBL_MANT_DIG - 1 || x == 0) return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff - 1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -0.0 : 1; + } + if (y < 0) return x + y + 1; + return x + y; +} +#endif diff --git a/third_party/ulib/musl/src/math/copysign.c b/third_party/ulib/musl/src/math/copysign.c new file mode 100644 index 000000000..3c3c05bd1 --- /dev/null +++ b/third_party/ulib/musl/src/math/copysign.c @@ -0,0 +1,11 @@ +#include "libm.h" + +double copysign(double x, double y) { + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + ux.i &= -1ULL / 2; + ux.i |= uy.i & 1ULL << 63; + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/copysignf.c b/third_party/ulib/musl/src/math/copysignf.c new file mode 100644 index 000000000..0c4dc0ee6 --- /dev/null +++ b/third_party/ulib/musl/src/math/copysignf.c @@ -0,0 +1,12 @@ +#include +#include + +float copysignf(float x, float y) { + union { + float f; + uint32_t i; + } ux = {x}, uy = {y}; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/copysignl.c b/third_party/ulib/musl/src/math/copysignl.c new file mode 100644 index 000000000..f8d76fe44 --- /dev/null +++ b/third_party/ulib/musl/src/math/copysignl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double copysignl(long double x, long double y) { + return copysign(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double copysignl(long double x, long double y) { + union ldshape ux = {x}, uy = {y}; + ux.i.se &= 0x7fff; + ux.i.se |= uy.i.se & 0x8000; + return ux.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/cosh.c b/third_party/ulib/musl/src/math/cosh.c new file mode 100644 index 000000000..53506abf0 --- /dev/null +++ b/third_party/ulib/musl/src/math/cosh.c @@ -0,0 +1,42 @@ +#include "libm.h" + +/* cosh(x) = (exp(x) + 1/exp(x))/2 + * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) + * = 1 + x*x/2 + o(x^4) + */ +double cosh(double x) { + union { + double f; + uint64_t i; + } u = {.f = x}; + uint32_t w; + double t; + + /* |x| */ + u.i &= (uint64_t)-1 / 2; + x = u.f; + w = u.i >> 32; + + /* |x| < log(2) */ + if (w < 0x3fe62e42) { + if (w < 0x3ff00000 - (26 << 20)) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1(x); + return 1 + t * t / (2 * (1 + t)); + } + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1 / t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} diff --git a/third_party/ulib/musl/src/math/coshf.c b/third_party/ulib/musl/src/math/coshf.c new file mode 100644 index 000000000..29a0f7433 --- /dev/null +++ b/third_party/ulib/musl/src/math/coshf.c @@ -0,0 +1,35 @@ +#include "libm.h" + +float coshf(float x) { + union { + float f; + uint32_t i; + } u = {.f = x}; + uint32_t w; + float t; + + /* |x| */ + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + /* |x| < log(2) */ + if (w < 0x3f317217) { + if (w < 0x3f800000 - (12 << 23)) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1f(x); + return 1 + t * t / (2 * (1 + t)); + } + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expf(x); + return 0.5f * (t + 1 / t); + } + + /* |x| > log(FLT_MAX) or nan */ + t = __expo2f(x); + return t; +} diff --git a/third_party/ulib/musl/src/math/coshl.c b/third_party/ulib/musl/src/math/coshl.c new file mode 100644 index 000000000..74bd129ca --- /dev/null +++ b/third_party/ulib/musl/src/math/coshl.c @@ -0,0 +1,44 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double coshl(long double x) { + return cosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double coshl(long double x) { + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + uint32_t w; + long double t; + + /* |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + /* |x| < log(2) */ + if (ex < 0x3fff - 1 || (ex == 0x3fff - 1 && w < 0xb17217f7)) { + if (ex < 0x3fff - 32) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1l(x); + return 1 + t * t / (2 * (1 + t)); + } + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff + 13 || (ex == 0x3fff + 13 && w < 0xb17217f7)) { + t = expl(x); + return 0.5 * (t + 1 / t); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5 * x); + return 0.5 * t * t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double coshl(long double x) { + return cosh(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/cosl.c b/third_party/ulib/musl/src/math/cosl.c new file mode 100644 index 000000000..1f967e906 --- /dev/null +++ b/third_party/ulib/musl/src/math/cosl.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cosl(long double x) { + return cos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double cosl(long double x) { + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) return x - x; + x = u.f; + if (x < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) /* raise inexact if x!=0 */ + return 1.0 + x; + return __cosl(x, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __cosl(hi, lo); + case 1: + return -__sinl(hi, lo, 1); + case 2: + return -__cosl(hi, lo); + case 3: + default: + return __sinl(hi, lo, 1); + } +} +#endif diff --git a/third_party/ulib/musl/src/math/exp10.c b/third_party/ulib/musl/src/math/exp10.c new file mode 100644 index 000000000..5a18dd51b --- /dev/null +++ b/third_party/ulib/musl/src/math/exp10.c @@ -0,0 +1,25 @@ +#define _GNU_SOURCE +#include "libc.h" +#include +#include + +double exp10(double x) { + static const double p10[] = {1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, + 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, + 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15}; + double n, y = modf(x, &n); + union { + double f; + uint64_t i; + } u = {n}; + /* fabs(n) < 16 without raising invalid on nan */ + if ((u.i >> 52 & 0x7ff) < 0x3ff + 4) { + if (!y) return p10[(int)n + 15]; + y = exp2(3.32192809488736234787031942948939 * y); + return y * p10[(int)n + 15]; + } + return pow(10.0, x); +} + +weak_alias(exp10, pow10); diff --git a/third_party/ulib/musl/src/math/exp10f.c b/third_party/ulib/musl/src/math/exp10f.c new file mode 100644 index 000000000..c02514d40 --- /dev/null +++ b/third_party/ulib/musl/src/math/exp10f.c @@ -0,0 +1,23 @@ +#define _GNU_SOURCE +#include "libc.h" +#include +#include + +float exp10f(float x) { + static const float p10[] = {1e-7f, 1e-6f, 1e-5f, 1e-4f, 1e-3f, 1e-2f, 1e-1f, 1, + 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7}; + float n, y = modff(x, &n); + union { + float f; + uint32_t i; + } u = {n}; + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u.i >> 23 & 0xff) < 0x7f + 3) { + if (!y) return p10[(int)n + 7]; + y = exp2f(3.32192809488736234787031942948939f * y); + return y * p10[(int)n + 7]; + } + return exp2(3.32192809488736234787031942948939 * x); +} + +weak_alias(exp10f, pow10f); diff --git a/third_party/ulib/musl/src/math/exp10l.c b/third_party/ulib/musl/src/math/exp10l.c new file mode 100644 index 000000000..dc6948f5d --- /dev/null +++ b/third_party/ulib/musl/src/math/exp10l.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "libm.h" +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp10l(long double x) { + return exp10(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double exp10l(long double x) { + static const long double p10[] = {1e-15L, 1e-14L, 1e-13L, 1e-12L, 1e-11L, 1e-10L, 1e-9L, 1e-8L, + 1e-7L, 1e-6L, 1e-5L, 1e-4L, 1e-3L, 1e-2L, 1e-1L, 1, + 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, + 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15}; + long double n, y = modfl(x, &n); + union ldshape u = {n}; + /* fabsl(n) < 16 without raising invalid on nan */ + if ((u.i.se & 0x7fff) < 0x3fff + 4) { + if (!y) return p10[(int)n + 15]; + y = exp2l(3.32192809488736234787031942948939L * y); + return y * p10[(int)n + 15]; + } + return powl(10.0, x); +} +#endif + +weak_alias(exp10l, pow10l); diff --git a/third_party/ulib/musl/src/math/fabs.c b/third_party/ulib/musl/src/math/fabs.c new file mode 100644 index 000000000..b384512c3 --- /dev/null +++ b/third_party/ulib/musl/src/math/fabs.c @@ -0,0 +1,11 @@ +#include +#include + +double fabs(double x) { + union { + double f; + uint64_t i; + } u = {x}; + u.i &= -1ULL / 2; + return u.f; +} diff --git a/third_party/ulib/musl/src/math/fabsf.c b/third_party/ulib/musl/src/math/fabsf.c new file mode 100644 index 000000000..62cb2643d --- /dev/null +++ b/third_party/ulib/musl/src/math/fabsf.c @@ -0,0 +1,11 @@ +#include +#include + +float fabsf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + u.i &= 0x7fffffff; + return u.f; +} diff --git a/third_party/ulib/musl/src/math/fabsl.c b/third_party/ulib/musl/src/math/fabsl.c new file mode 100644 index 000000000..2cf06e835 --- /dev/null +++ b/third_party/ulib/musl/src/math/fabsl.c @@ -0,0 +1,13 @@ +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fabsl(long double x) { + return fabs(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fabsl(long double x) { + union ldshape u = {x}; + + u.i.se &= 0x7fff; + return u.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/fdim.c b/third_party/ulib/musl/src/math/fdim.c new file mode 100644 index 000000000..de45b6528 --- /dev/null +++ b/third_party/ulib/musl/src/math/fdim.c @@ -0,0 +1,7 @@ +#include + +double fdim(double x, double y) { + if (isnan(x)) return x; + if (isnan(y)) return y; + return x > y ? x - y : 0; +} diff --git a/third_party/ulib/musl/src/math/fdimf.c b/third_party/ulib/musl/src/math/fdimf.c new file mode 100644 index 000000000..5d47b0ba8 --- /dev/null +++ b/third_party/ulib/musl/src/math/fdimf.c @@ -0,0 +1,7 @@ +#include + +float fdimf(float x, float y) { + if (isnan(x)) return x; + if (isnan(y)) return y; + return x > y ? x - y : 0; +} diff --git a/third_party/ulib/musl/src/math/fdiml.c b/third_party/ulib/musl/src/math/fdiml.c new file mode 100644 index 000000000..2a340b645 --- /dev/null +++ b/third_party/ulib/musl/src/math/fdiml.c @@ -0,0 +1,14 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fdiml(long double x, long double y) { + return fdim(x, y); +} +#else +long double fdiml(long double x, long double y) { + if (isnan(x)) return x; + if (isnan(y)) return y; + return x > y ? x - y : 0; +} +#endif diff --git a/third_party/ulib/musl/src/math/finite.c b/third_party/ulib/musl/src/math/finite.c new file mode 100644 index 000000000..db63e2684 --- /dev/null +++ b/third_party/ulib/musl/src/math/finite.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +int finite(double x) { + return isfinite(x); +} diff --git a/third_party/ulib/musl/src/math/finitef.c b/third_party/ulib/musl/src/math/finitef.c new file mode 100644 index 000000000..50588172d --- /dev/null +++ b/third_party/ulib/musl/src/math/finitef.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +int finitef(float x) { + return isfinite(x); +} diff --git a/third_party/ulib/musl/src/math/floor.c b/third_party/ulib/musl/src/math/floor.c new file mode 100644 index 000000000..78c3a6b61 --- /dev/null +++ b/third_party/ulib/musl/src/math/floor.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1 / EPS; + +double floor(double x) { + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff + 52 || x == 0) return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff - 1) { + FORCE_EVAL(y); + return u.i >> 63 ? -1 : 0; + } + if (y > 0) return x + y - 1; + return x + y; +} diff --git a/third_party/ulib/musl/src/math/floorf.c b/third_party/ulib/musl/src/math/floorf.c new file mode 100644 index 000000000..3817a9f41 --- /dev/null +++ b/third_party/ulib/musl/src/math/floorf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +float floorf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i = 0; + else if (u.i << 1) + u.f = -1.0; + } + return u.f; +} diff --git a/third_party/ulib/musl/src/math/floorl.c b/third_party/ulib/musl/src/math/floorl.c new file mode 100644 index 000000000..7eb364a74 --- /dev/null +++ b/third_party/ulib/musl/src/math/floorl.c @@ -0,0 +1,30 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double floorl(long double x) { + return floor(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1 / LDBL_EPSILON; + +long double floorl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff + LDBL_MANT_DIG - 1 || x == 0) return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff - 1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -1 : 0; + } + if (y > 0) return x + y - 1; + return x + y; +} +#endif diff --git a/third_party/ulib/musl/src/math/fmax.c b/third_party/ulib/musl/src/math/fmax.c new file mode 100644 index 000000000..19cbe2d0f --- /dev/null +++ b/third_party/ulib/musl/src/math/fmax.c @@ -0,0 +1,9 @@ +#include + +double fmax(double x, double y) { + if (isnan(x)) return y; + if (isnan(y)) return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/third_party/ulib/musl/src/math/fmaxf.c b/third_party/ulib/musl/src/math/fmaxf.c new file mode 100644 index 000000000..3755a1e4a --- /dev/null +++ b/third_party/ulib/musl/src/math/fmaxf.c @@ -0,0 +1,9 @@ +#include + +float fmaxf(float x, float y) { + if (isnan(x)) return y; + if (isnan(y)) return x; + /* handle signed zeroes, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/third_party/ulib/musl/src/math/fmaxl.c b/third_party/ulib/musl/src/math/fmaxl.c new file mode 100644 index 000000000..002b8778a --- /dev/null +++ b/third_party/ulib/musl/src/math/fmaxl.c @@ -0,0 +1,16 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmaxl(long double x, long double y) { + return fmax(x, y); +} +#else +long double fmaxl(long double x, long double y) { + if (isnan(x)) return y; + if (isnan(y)) return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) return signbit(x) ? y : x; + return x < y ? y : x; +} +#endif diff --git a/third_party/ulib/musl/src/math/fmin.c b/third_party/ulib/musl/src/math/fmin.c new file mode 100644 index 000000000..8fea5f516 --- /dev/null +++ b/third_party/ulib/musl/src/math/fmin.c @@ -0,0 +1,9 @@ +#include + +double fmin(double x, double y) { + if (isnan(x)) return y; + if (isnan(y)) return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/third_party/ulib/musl/src/math/fminf.c b/third_party/ulib/musl/src/math/fminf.c new file mode 100644 index 000000000..cd69cee89 --- /dev/null +++ b/third_party/ulib/musl/src/math/fminf.c @@ -0,0 +1,9 @@ +#include + +float fminf(float x, float y) { + if (isnan(x)) return y; + if (isnan(y)) return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/third_party/ulib/musl/src/math/fminl.c b/third_party/ulib/musl/src/math/fminl.c new file mode 100644 index 000000000..fa2f399df --- /dev/null +++ b/third_party/ulib/musl/src/math/fminl.c @@ -0,0 +1,16 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fminl(long double x, long double y) { + return fmin(x, y); +} +#else +long double fminl(long double x, long double y) { + if (isnan(x)) return y; + if (isnan(y)) return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) return signbit(x) ? x : y; + return x < y ? x : y; +} +#endif diff --git a/third_party/ulib/musl/src/math/fmod.c b/third_party/ulib/musl/src/math/fmod.c new file mode 100644 index 000000000..9f25a1465 --- /dev/null +++ b/third_party/ulib/musl/src/math/fmod.c @@ -0,0 +1,69 @@ +#include +#include + +double fmod(double x, double y) { + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + int ex = ux.i >> 52 & 0x7ff; + int ey = uy.i >> 52 & 0x7ff; + int sx = ux.i >> 63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i << 1 == 0 || isnan(y) || ex == 0x7ff) return (x * y) / (x * y); + if (uxi << 1 <= uy.i << 1) { + if (uxi << 1 == uy.i << 1) return 0 * x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) + ; + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) + ; + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) return 0 * x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) return 0 * x; + uxi = i; + } + for (; uxi >> 52 == 0; uxi <<= 1, ex--) + ; + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/fmodf.c b/third_party/ulib/musl/src/math/fmodf.c new file mode 100644 index 000000000..345010216 --- /dev/null +++ b/third_party/ulib/musl/src/math/fmodf.c @@ -0,0 +1,66 @@ +#include +#include + +float fmodf(float x, float y) { + union { + float f; + uint32_t i; + } ux = {x}, uy = {y}; + int ex = ux.i >> 23 & 0xff; + int ey = uy.i >> 23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; + + if (uy.i << 1 == 0 || isnan(y) || ex == 0xff) return (x * y) / (x * y); + if (uxi << 1 <= uy.i << 1) { + if (uxi << 1 == uy.i << 1) return 0 * x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi << 9; i >> 31 == 0; ex--, i <<= 1) + ; + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i << 9; i >> 31 == 0; ey--, i <<= 1) + ; + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) return 0 * x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) return 0 * x; + uxi = i; + } + for (; uxi >> 23 == 0; uxi <<= 1, ex--) + ; + + /* scale result up */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + ux.i = uxi; + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/fmodl.c b/third_party/ulib/musl/src/math/fmodl.c new file mode 100644 index 000000000..f22806536 --- /dev/null +++ b/third_party/ulib/musl/src/math/fmodl.c @@ -0,0 +1,97 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmodl(long double x, long double y) { + return fmod(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fmodl(long double x, long double y) { + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se & 0x8000; + + if (y == 0 || isnan(y) || ex == 0x7fff) return (x * y) / (x * y); + ux.i.se = ex; + uy.i.se = ey; + if (ux.f <= uy.f) { + if (ux.f == uy.f) return 0 * x; + return x; + } + + /* normalize x and y */ + if (!ex) { + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + +/* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + if (i == 0) return 0 * x; + mx = 2 * i; + } else if (2 * mx < mx) { + mx = 2 * mx - my; + } else { + mx = 2 * mx; + } + } + i = mx - my; + if (mx >= my) { + if (i == 0) return 0 * x; + mx = i; + } + for (; mx >> 63 == 0; mx *= 2, ex--) + ; + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL >> 16) | 1ULL << 48; + yhi = (uy.i2.hi & -1ULL >> 16) | 1ULL << 48; + xlo = ux.i2.lo; + ylo = uy.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) hi -= 1; + if (hi >> 63 == 0) { + if ((hi | lo) == 0) return 0 * x; + xhi = 2 * hi + (lo >> 63); + xlo = 2 * lo; + } else { + xhi = 2 * xhi + (xlo >> 63); + xlo = 2 * xlo; + } + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) hi -= 1; + if (hi >> 63 == 0) { + if ((hi | lo) == 0) return 0 * x; + xhi = hi; + xlo = lo; + } + for (; xhi >> 48 == 0; xhi = 2 * xhi + (xlo >> 63), xlo = 2 * xlo, ex--) + ; + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + + /* scale result */ + if (ex <= 0) { + ux.i.se = (ex + 120) | sx; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex | sx; + return ux.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/frexp.c b/third_party/ulib/musl/src/math/frexp.c new file mode 100644 index 000000000..570c0a0bf --- /dev/null +++ b/third_party/ulib/musl/src/math/frexp.c @@ -0,0 +1,26 @@ +#include +#include + +double frexp(double x, int* e) { + union { + double d; + uint64_t i; + } y = {x}; + int ee = y.i >> 52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x * 0x1p64, e); + *e -= 64; + } else + *e = 0; + return x; + } else if (ee == 0x7ff) { + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} diff --git a/third_party/ulib/musl/src/math/frexpf.c b/third_party/ulib/musl/src/math/frexpf.c new file mode 100644 index 000000000..2b8caa99c --- /dev/null +++ b/third_party/ulib/musl/src/math/frexpf.c @@ -0,0 +1,26 @@ +#include +#include + +float frexpf(float x, int* e) { + union { + float f; + uint32_t i; + } y = {x}; + int ee = y.i >> 23 & 0xff; + + if (!ee) { + if (x) { + x = frexpf(x * 0x1p64, e); + *e -= 64; + } else + *e = 0; + return x; + } else if (ee == 0xff) { + return x; + } + + *e = ee - 0x7e; + y.i &= 0x807ffffful; + y.i |= 0x3f000000ul; + return y.f; +} diff --git a/third_party/ulib/musl/src/math/frexpl.c b/third_party/ulib/musl/src/math/frexpl.c new file mode 100644 index 000000000..78a5289a6 --- /dev/null +++ b/third_party/ulib/musl/src/math/frexpl.c @@ -0,0 +1,28 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double frexpl(long double x, int* e) { + return frexp(x, e); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double frexpl(long double x, int* e) { + union ldshape u = {x}; + int ee = u.i.se & 0x7fff; + + if (!ee) { + if (x) { + x = frexpl(x * 0x1p120, e); + *e -= 120; + } else + *e = 0; + return x; + } else if (ee == 0x7fff) { + return x; + } + + *e = ee - 0x3ffe; + u.i.se &= 0x8000; + u.i.se |= 0x3ffe; + return u.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/hypot.c b/third_party/ulib/musl/src/math/hypot.c new file mode 100644 index 000000000..63dd9fac8 --- /dev/null +++ b/third_party/ulib/musl/src/math/hypot.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32 + 1) +#else +#define SPLIT (0x1p27 + 1) +#endif + +static void sq(double_t* hi, double_t* lo, double x) { + double_t xh, xl, xc; + + xc = (double_t)x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = (double_t)x * x; + *lo = xh * xh - *hi + 2 * xh * xl + xl * xl; +} + +double hypot(double x, double y) { + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}, ut; + int ex, ey; + double_t hx, lx, hy, ly, z; + + /* arrange |x| >= |y| */ + ux.i &= -1ULL >> 1; + uy.i &= -1ULL >> 1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + /* special cases */ + ex = ux.i >> 52; + ey = uy.i >> 52; + x = ux.f; + y = uy.f; + /* note: hypot(inf,nan) == inf */ + if (ey == 0x7ff) return y; + if (ex == 0x7ff || uy.i == 0) return x; + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if (ex - ey > 64) return x + y; + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1; + if (ex > 0x3ff + 510) { + z = 0x1p700; + x *= 0x1p-700; + y *= 0x1p-700; + } else if (ey < 0x3ff - 450) { + z = 0x1p-700; + x *= 0x1p700; + y *= 0x1p700; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z * sqrt(ly + lx + hy + hx); +} diff --git a/third_party/ulib/musl/src/math/hypotf.c b/third_party/ulib/musl/src/math/hypotf.c new file mode 100644 index 000000000..b1ced3f1c --- /dev/null +++ b/third_party/ulib/musl/src/math/hypotf.c @@ -0,0 +1,35 @@ +#include +#include + +float hypotf(float x, float y) { + union { + float f; + uint32_t i; + } ux = {x}, uy = {y}, ut; + float_t z; + + ux.i &= -1U >> 1; + uy.i &= -1U >> 1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + x = ux.f; + y = uy.f; + if (uy.i == 0xff << 23) return y; + if (ux.i >= 0xff << 23 || uy.i == 0 || ux.i - uy.i >= 25 << 23) return x + y; + + z = 1; + if (ux.i >= (0x7f + 60) << 23) { + z = 0x1p90f; + x *= 0x1p-90f; + y *= 0x1p-90f; + } else if (uy.i < (0x7f - 60) << 23) { + z = 0x1p-90f; + x *= 0x1p90f; + y *= 0x1p90f; + } + return z * sqrtf((double)x * x + (double)y * y); +} diff --git a/third_party/ulib/musl/src/math/hypotl.c b/third_party/ulib/musl/src/math/hypotl.c new file mode 100644 index 000000000..c857e28ce --- /dev/null +++ b/third_party/ulib/musl/src/math/hypotl.c @@ -0,0 +1,60 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double hypotl(long double x, long double y) { + return hypot(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32L + 1) +#elif LDBL_MANT_DIG == 113 +#define SPLIT (0x1p57L + 1) +#endif + +static void sq(long double* hi, long double* lo, long double x) { + long double xh, xl, xc; + xc = x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = x * x; + *lo = xh * xh - *hi + 2 * xh * xl + xl * xl; +} + +long double hypotl(long double x, long double y) { + union ldshape ux = {x}, uy = {y}; + int ex, ey; + long double hx, lx, hy, ly, z; + + ux.i.se &= 0x7fff; + uy.i.se &= 0x7fff; + if (ux.i.se < uy.i.se) { + ex = uy.i.se; + ey = ux.i.se; + x = uy.f; + y = ux.f; + } else { + ex = ux.i.se; + ey = uy.i.se; + x = ux.f; + y = uy.f; + } + + if (ex == 0x7fff && isinf(y)) return y; + if (ex == 0x7fff || y == 0) return x; + if (ex - ey > LDBL_MANT_DIG) return x + y; + + z = 1; + if (ex > 0x3fff + 8000) { + z = 0x1p10000L; + x *= 0x1p-10000L; + y *= 0x1p-10000L; + } else if (ey < 0x3fff - 8000) { + z = 0x1p-10000L; + x *= 0x1p10000L; + y *= 0x1p10000L; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z * sqrtl(ly + lx + hy + hx); +} +#endif diff --git a/third_party/ulib/musl/src/math/ilogb.c b/third_party/ulib/musl/src/math/ilogb.c new file mode 100644 index 000000000..85a5b7147 --- /dev/null +++ b/third_party/ulib/musl/src/math/ilogb.c @@ -0,0 +1,29 @@ +#include "libm.h" +#include + +int ilogb(double x) { + PRAGMA_STDC_FENV_ACCESS_ON + union { + double f; + uint64_t i; + } u = {x}; + uint64_t i = u.i; + int e = i >> 52 & 0x7ff; + + if (!e) { + i <<= 12; + if (i == 0) { + FORCE_EVAL(0 / 0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3ff; i >> 63 == 0; e--, i <<= 1) + ; + return e; + } + if (e == 0x7ff) { + FORCE_EVAL(0 / 0.0f); + return i << 12 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3ff; +} diff --git a/third_party/ulib/musl/src/math/ilogbf.c b/third_party/ulib/musl/src/math/ilogbf.c new file mode 100644 index 000000000..f65e3168b --- /dev/null +++ b/third_party/ulib/musl/src/math/ilogbf.c @@ -0,0 +1,29 @@ +#include "libm.h" +#include + +int ilogbf(float x) { + PRAGMA_STDC_FENV_ACCESS_ON + union { + float f; + uint32_t i; + } u = {x}; + uint32_t i = u.i; + int e = i >> 23 & 0xff; + + if (!e) { + i <<= 9; + if (i == 0) { + FORCE_EVAL(0 / 0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x7f; i >> 31 == 0; e--, i <<= 1) + ; + return e; + } + if (e == 0xff) { + FORCE_EVAL(0 / 0.0f); + return i << 9 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x7f; +} diff --git a/third_party/ulib/musl/src/math/ilogbl.c b/third_party/ulib/musl/src/math/ilogbl.c new file mode 100644 index 000000000..1f9f2d0b1 --- /dev/null +++ b/third_party/ulib/musl/src/math/ilogbl.c @@ -0,0 +1,53 @@ +#include "libm.h" +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int ilogbl(long double x) { + return ilogb(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) { + PRAGMA_STDC_FENV_ACCESS_ON + union ldshape u = {x}; + uint64_t m = u.i.m; + int e = u.i.se & 0x7fff; + + if (!e) { + if (m == 0) { + FORCE_EVAL(0 / 0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3fff + 1; m >> 63 == 0; e--, m <<= 1) + ; + return e; + } + if (e == 0x7fff) { + FORCE_EVAL(0 / 0.0f); + return m << 1 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) { + PRAGMA_STDC_FENV_ACCESS_ON + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (!e) { + if (x == 0) { + FORCE_EVAL(0 / 0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + x *= 0x1p120; + return ilogbl(x) - 120; + } + if (e == 0x7fff) { + FORCE_EVAL(0 / 0.0f); + u.i.se = 0; + return u.f ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#endif diff --git a/third_party/ulib/musl/src/math/ldexp.c b/third_party/ulib/musl/src/math/ldexp.c new file mode 100644 index 000000000..eb4c83473 --- /dev/null +++ b/third_party/ulib/musl/src/math/ldexp.c @@ -0,0 +1,5 @@ +#include + +double ldexp(double x, int n) { + return scalbn(x, n); +} diff --git a/third_party/ulib/musl/src/math/ldexpf.c b/third_party/ulib/musl/src/math/ldexpf.c new file mode 100644 index 000000000..1a141622a --- /dev/null +++ b/third_party/ulib/musl/src/math/ldexpf.c @@ -0,0 +1,5 @@ +#include + +float ldexpf(float x, int n) { + return scalbnf(x, n); +} diff --git a/third_party/ulib/musl/src/math/ldexpl.c b/third_party/ulib/musl/src/math/ldexpl.c new file mode 100644 index 000000000..1117dfd26 --- /dev/null +++ b/third_party/ulib/musl/src/math/ldexpl.c @@ -0,0 +1,5 @@ +#include + +long double ldexpl(long double x, int n) { + return scalbnl(x, n); +} diff --git a/third_party/ulib/musl/src/math/lgamma.c b/third_party/ulib/musl/src/math/lgamma.c new file mode 100644 index 000000000..274ce7318 --- /dev/null +++ b/third_party/ulib/musl/src/math/lgamma.c @@ -0,0 +1,8 @@ +#include + +extern int __signgam; +double __lgamma_r(double, int*); + +double lgamma(double x) { + return __lgamma_r(x, &__signgam); +} diff --git a/third_party/ulib/musl/src/math/lgammaf.c b/third_party/ulib/musl/src/math/lgammaf.c new file mode 100644 index 000000000..9b51b879b --- /dev/null +++ b/third_party/ulib/musl/src/math/lgammaf.c @@ -0,0 +1,8 @@ +#include + +extern int __signgam; +float __lgammaf_r(float, int*); + +float lgammaf(float x) { + return __lgammaf_r(x, &__signgam); +} diff --git a/third_party/ulib/musl/src/math/llrint.c b/third_party/ulib/musl/src/math/llrint.c new file mode 100644 index 000000000..a933079ce --- /dev/null +++ b/third_party/ulib/musl/src/math/llrint.c @@ -0,0 +1,7 @@ +#include + +/* uses LLONG_MAX > 2^53, see comments in lrint.c */ + +long long llrint(double x) { + return rint(x); +} diff --git a/third_party/ulib/musl/src/math/llrintf.c b/third_party/ulib/musl/src/math/llrintf.c new file mode 100644 index 000000000..24863a240 --- /dev/null +++ b/third_party/ulib/musl/src/math/llrintf.c @@ -0,0 +1,7 @@ +#include + +/* uses LLONG_MAX > 2^24, see comments in lrint.c */ + +long long llrintf(float x) { + return rintf(x); +} diff --git a/third_party/ulib/musl/src/math/llrintl.c b/third_party/ulib/musl/src/math/llrintl.c new file mode 100644 index 000000000..88118f6a1 --- /dev/null +++ b/third_party/ulib/musl/src/math/llrintl.c @@ -0,0 +1,31 @@ +#include "libm.h" +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long long llrintl(long double x) { + return llrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LLONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long long llrintl(long double x) { + PRAGMA_STDC_FENV_ACCESS_ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LLONG_MAX || x < LLONG_MIN)) feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long long llrintl(long double x) { + return rintl(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/llround.c b/third_party/ulib/musl/src/math/llround.c new file mode 100644 index 000000000..b5e9fde77 --- /dev/null +++ b/third_party/ulib/musl/src/math/llround.c @@ -0,0 +1,5 @@ +#include + +long long llround(double x) { + return round(x); +} diff --git a/third_party/ulib/musl/src/math/llroundf.c b/third_party/ulib/musl/src/math/llroundf.c new file mode 100644 index 000000000..34b308d7c --- /dev/null +++ b/third_party/ulib/musl/src/math/llroundf.c @@ -0,0 +1,5 @@ +#include + +long long llroundf(float x) { + return roundf(x); +} diff --git a/third_party/ulib/musl/src/math/llroundl.c b/third_party/ulib/musl/src/math/llroundl.c new file mode 100644 index 000000000..6abade41f --- /dev/null +++ b/third_party/ulib/musl/src/math/llroundl.c @@ -0,0 +1,5 @@ +#include + +long long llroundl(long double x) { + return roundl(x); +} diff --git a/third_party/ulib/musl/src/math/logb.c b/third_party/ulib/musl/src/math/logb.c new file mode 100644 index 000000000..05c2bcab2 --- /dev/null +++ b/third_party/ulib/musl/src/math/logb.c @@ -0,0 +1,14 @@ +#include + +/* +special cases: + logb(+-0) = -inf, and raise divbyzero + logb(+-inf) = +inf + logb(nan) = nan +*/ + +double logb(double x) { + if (!isfinite(x)) return x * x; + if (x == 0) return -1 / (x * x); + return ilogb(x); +} diff --git a/third_party/ulib/musl/src/math/logbf.c b/third_party/ulib/musl/src/math/logbf.c new file mode 100644 index 000000000..99828cdea --- /dev/null +++ b/third_party/ulib/musl/src/math/logbf.c @@ -0,0 +1,7 @@ +#include + +float logbf(float x) { + if (!isfinite(x)) return x * x; + if (x == 0) return -1 / (x * x); + return ilogbf(x); +} diff --git a/third_party/ulib/musl/src/math/logbl.c b/third_party/ulib/musl/src/math/logbl.c new file mode 100644 index 000000000..c121e7bb2 --- /dev/null +++ b/third_party/ulib/musl/src/math/logbl.c @@ -0,0 +1,12 @@ +#include +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logbl(long double x) { + return logb(x); +} +#else +long double logbl(long double x) { + if (!isfinite(x)) return x * x; + if (x == 0) return -1 / (x * x); + return ilogbl(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/lrint.c b/third_party/ulib/musl/src/math/lrint.c new file mode 100644 index 000000000..0c4f2b9e6 --- /dev/null +++ b/third_party/ulib/musl/src/math/lrint.c @@ -0,0 +1,43 @@ +#include "libm.h" +#include +#include + +/* +If the result cannot be represented (overflow, nan), then +lrint raises the invalid exception. + +Otherwise if the input was not an integer then the inexact +exception is raised. + +C99 is a bit vague about whether inexact exception is +allowed to be raised when invalid is raised. +(F.9 explicitly allows spurious inexact exceptions, F.9.6.5 +does not make it clear if that rule applies to lrint, but +IEEE 754r 7.8 seems to forbid spurious inexact exception in +the ineger conversion functions) + +So we try to make sure that no spurious inexact exception is +raised in case of an overflow. + +If the bit size of long > precision of double, then there +cannot be inexact rounding in case the result overflows, +otherwise LONG_MAX and LONG_MIN can be represented exactly +as a double. +*/ + +#if LONG_MAX < 1U << 53 && defined(FE_INEXACT) +long lrint(double x) { + PRAGMA_STDC_FENV_ACCESS_ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rint(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrint(double x) { + return rint(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/lrintf.c b/third_party/ulib/musl/src/math/lrintf.c new file mode 100644 index 000000000..632e96d70 --- /dev/null +++ b/third_party/ulib/musl/src/math/lrintf.c @@ -0,0 +1,7 @@ +#include + +/* uses LONG_MAX > 2^24, see comments in lrint.c */ + +long lrintf(float x) { + return rintf(x); +} diff --git a/third_party/ulib/musl/src/math/lrintl.c b/third_party/ulib/musl/src/math/lrintl.c new file mode 100644 index 000000000..b77301c00 --- /dev/null +++ b/third_party/ulib/musl/src/math/lrintl.c @@ -0,0 +1,31 @@ +#include "libm.h" +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long lrintl(long double x) { + return lrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long lrintl(long double x) { + PRAGMA_STDC_FENV_ACCESS_ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrintl(long double x) { + return rintl(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/lround.c b/third_party/ulib/musl/src/math/lround.c new file mode 100644 index 000000000..6b9b5b950 --- /dev/null +++ b/third_party/ulib/musl/src/math/lround.c @@ -0,0 +1,5 @@ +#include + +long lround(double x) { + return round(x); +} diff --git a/third_party/ulib/musl/src/math/lroundf.c b/third_party/ulib/musl/src/math/lroundf.c new file mode 100644 index 000000000..97fe403f5 --- /dev/null +++ b/third_party/ulib/musl/src/math/lroundf.c @@ -0,0 +1,5 @@ +#include + +long lroundf(float x) { + return roundf(x); +} diff --git a/third_party/ulib/musl/src/math/lroundl.c b/third_party/ulib/musl/src/math/lroundl.c new file mode 100644 index 000000000..b7c2825a0 --- /dev/null +++ b/third_party/ulib/musl/src/math/lroundl.c @@ -0,0 +1,5 @@ +#include + +long lroundl(long double x) { + return roundl(x); +} diff --git a/third_party/ulib/musl/src/math/modf.c b/third_party/ulib/musl/src/math/modf.c new file mode 100644 index 000000000..3177cd16a --- /dev/null +++ b/third_party/ulib/musl/src/math/modf.c @@ -0,0 +1,36 @@ +#include "libm.h" + +double modf(double x, double* iptr) { + union { + double f; + uint64_t i; + } u = {x}; + uint64_t mask; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff; + + /* no fractional part */ + if (e >= 52) { + *iptr = x; + if (e == 0x400 && u.i << 12 != 0) /* nan */ + return x; + u.i &= 1ULL << 63; + return u.f; + } + + /* no integral part*/ + if (e < 0) { + u.i &= 1ULL << 63; + *iptr = u.f; + return x; + } + + mask = -1ULL >> 12 >> e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 1ULL << 63; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/third_party/ulib/musl/src/math/modff.c b/third_party/ulib/musl/src/math/modff.c new file mode 100644 index 000000000..c5a280838 --- /dev/null +++ b/third_party/ulib/musl/src/math/modff.c @@ -0,0 +1,36 @@ +#include "libm.h" + +float modff(float x, float* iptr) { + union { + float f; + uint32_t i; + } u = {x}; + uint32_t mask; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + + /* no fractional part */ + if (e >= 23) { + *iptr = x; + if (e == 0x80 && u.i << 9 != 0) { /* nan */ + return x; + } + u.i &= 0x80000000; + return u.f; + } + /* no integral part */ + if (e < 0) { + u.i &= 0x80000000; + *iptr = u.f; + return x; + } + + mask = 0x007fffff >> e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 0x80000000; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/third_party/ulib/musl/src/math/modfl.c b/third_party/ulib/musl/src/math/modfl.c new file mode 100644 index 000000000..fd19e62cd --- /dev/null +++ b/third_party/ulib/musl/src/math/modfl.c @@ -0,0 +1,48 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double modfl(long double x, long double* iptr) { + double d; + long double r; + + r = modf(x, &d); + *iptr = d; + return r; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1 / LDBL_EPSILON; + +long double modfl(long double x, long double* iptr) { + union ldshape u = {x}; + int e = (u.i.se & 0x7fff) - 0x3fff; + int s = u.i.se >> 15; + long double absx; + long double y; + + /* no fractional part */ + if (e >= LDBL_MANT_DIG - 1) { + *iptr = x; + if (isnan(x)) return x; + return s ? -0.0 : 0.0; + } + + /* no integral part*/ + if (e < 0) { + *iptr = s ? -0.0 : 0.0; + return x; + } + + /* raises spurious inexact */ + absx = s ? -x : x; + y = absx + toint - toint - absx; + if (y == 0) { + *iptr = x; + return s ? -0.0 : 0.0; + } + if (y > 0) y -= 1; + if (s) y = -y; + *iptr = x + y; + return -y; +} +#endif diff --git a/third_party/ulib/musl/src/math/nan.c b/third_party/ulib/musl/src/math/nan.c new file mode 100644 index 000000000..858b0c58c --- /dev/null +++ b/third_party/ulib/musl/src/math/nan.c @@ -0,0 +1,5 @@ +#include + +double nan(const char* s) { + return NAN; +} diff --git a/third_party/ulib/musl/src/math/nanf.c b/third_party/ulib/musl/src/math/nanf.c new file mode 100644 index 000000000..d8c5a77b3 --- /dev/null +++ b/third_party/ulib/musl/src/math/nanf.c @@ -0,0 +1,5 @@ +#include + +float nanf(const char* s) { + return NAN; +} diff --git a/third_party/ulib/musl/src/math/nanl.c b/third_party/ulib/musl/src/math/nanl.c new file mode 100644 index 000000000..f6aac0dda --- /dev/null +++ b/third_party/ulib/musl/src/math/nanl.c @@ -0,0 +1,5 @@ +#include + +long double nanl(const char* s) { + return NAN; +} diff --git a/third_party/ulib/musl/src/math/nearbyint.c b/third_party/ulib/musl/src/math/nearbyint.c new file mode 100644 index 000000000..ab6f0e1a1 --- /dev/null +++ b/third_party/ulib/musl/src/math/nearbyint.c @@ -0,0 +1,19 @@ +#include +#include +#include "libm.h" + +/* nearbyint is the same as rint, but it must not raise the inexact exception */ + +double nearbyint(double x) { +#ifdef FE_INEXACT + PRAGMA_STDC_FENV_ACCESS_ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rint(x); +#ifdef FE_INEXACT + if (!e) feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/third_party/ulib/musl/src/math/nearbyintf.c b/third_party/ulib/musl/src/math/nearbyintf.c new file mode 100644 index 000000000..9662c080e --- /dev/null +++ b/third_party/ulib/musl/src/math/nearbyintf.c @@ -0,0 +1,17 @@ +#include +#include +#include "libm.h" + +float nearbyintf(float x) { +#ifdef FE_INEXACT + PRAGMA_STDC_FENV_ACCESS_ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintf(x); +#ifdef FE_INEXACT + if (!e) feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/third_party/ulib/musl/src/math/nearbyintl.c b/third_party/ulib/musl/src/math/nearbyintl.c new file mode 100644 index 000000000..5b3608ed5 --- /dev/null +++ b/third_party/ulib/musl/src/math/nearbyintl.c @@ -0,0 +1,24 @@ +#include +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nearbyintl(long double x) { + return nearbyint(x); +} +#else +#include +long double nearbyintl(long double x) { +#ifdef FE_INEXACT + PRAGMA_STDC_FENV_ACCESS_ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintl(x); +#ifdef FE_INEXACT + if (!e) feclearexcept(FE_INEXACT); +#endif + return x; +} +#endif diff --git a/third_party/ulib/musl/src/math/nextafter.c b/third_party/ulib/musl/src/math/nextafter.c new file mode 100644 index 000000000..8f1d63653 --- /dev/null +++ b/third_party/ulib/musl/src/math/nextafter.c @@ -0,0 +1,28 @@ +#include "libm.h" + +double nextafter(double x, double y) { + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + uint64_t ax, ay; + int e; + + if (isnan(x) || isnan(y)) return x + y; + if (ux.i == uy.i) return y; + ax = ux.i & -1ULL / 2; + ay = uy.i & -1ULL / 2; + if (ax == 0) { + if (ay == 0) return y; + ux.i = (uy.i & 1ULL << 63) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 1ULL << 63)) + ux.i--; + else + ux.i++; + e = ux.i >> 52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) FORCE_EVAL(x + x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) FORCE_EVAL(x * x + ux.f * ux.f); + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/nextafterf.c b/third_party/ulib/musl/src/math/nextafterf.c new file mode 100644 index 000000000..5f303d138 --- /dev/null +++ b/third_party/ulib/musl/src/math/nextafterf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float nextafterf(float x, float y) { + union { + float f; + uint32_t i; + } ux = {x}, uy = {y}; + uint32_t ax, ay, e; + + if (isnan(x) || isnan(y)) return x + y; + if (ux.i == uy.i) return y; + ax = ux.i & 0x7fffffff; + ay = uy.i & 0x7fffffff; + if (ax == 0) { + if (ay == 0) return y; + ux.i = (uy.i & 0x80000000) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 0x80000000)) + ux.i--; + else + ux.i++; + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) FORCE_EVAL(x + x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) FORCE_EVAL(x * x + ux.f * ux.f); + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/nextafterl.c b/third_party/ulib/musl/src/math/nextafterl.c new file mode 100644 index 000000000..a277e1164 --- /dev/null +++ b/third_party/ulib/musl/src/math/nextafterl.c @@ -0,0 +1,61 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nextafterl(long double x, long double y) { + return nextafter(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) { + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) return x + y; + if (x == y) return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.m = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i.m++; + if (ux.i.m << 1 == 0) { + ux.i.m = 1ULL << 63; + ux.i.se++; + } + } else { + if (ux.i.m << 1 == 0) { + ux.i.se--; + if (ux.i.se) ux.i.m = 0; + } + ux.i.m--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) FORCE_EVAL(x * x + ux.f * ux.f); + return ux.f; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) { + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) return x + y; + if (x == y) return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.lo = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i2.lo++; + if (ux.i2.lo == 0) ux.i2.hi++; + } else { + if (ux.i2.lo == 0) ux.i2.hi--; + ux.i2.lo--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) FORCE_EVAL(x * x + ux.f * ux.f); + return ux.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/nexttoward.c b/third_party/ulib/musl/src/math/nexttoward.c new file mode 100644 index 000000000..f7df915b6 --- /dev/null +++ b/third_party/ulib/musl/src/math/nexttoward.c @@ -0,0 +1,38 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double nexttoward(double x, long double y) { + return nextafter(x, y); +} +#else +double nexttoward(double x, long double y) { + union { + double f; + uint64_t i; + } ux = {x}; + int e; + + if (isnan(x) || isnan(y)) return x + y; + if (x == y) return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) ux.i |= 1ULL << 63; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i >> 52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) FORCE_EVAL(x + x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) FORCE_EVAL(x * x + ux.f * ux.f); + return ux.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/nexttowardf.c b/third_party/ulib/musl/src/math/nexttowardf.c new file mode 100644 index 000000000..66bd64c83 --- /dev/null +++ b/third_party/ulib/musl/src/math/nexttowardf.c @@ -0,0 +1,32 @@ +#include "libm.h" + +float nexttowardf(float x, long double y) { + union { + float f; + uint32_t i; + } ux = {x}; + uint32_t e; + + if (isnan(x) || isnan(y)) return x + y; + if (x == y) return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) ux.i |= 0x80000000; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) FORCE_EVAL(x + x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) FORCE_EVAL(x * x + ux.f * ux.f); + return ux.f; +} diff --git a/third_party/ulib/musl/src/math/nexttowardl.c b/third_party/ulib/musl/src/math/nexttowardl.c new file mode 100644 index 000000000..cd035af2d --- /dev/null +++ b/third_party/ulib/musl/src/math/nexttowardl.c @@ -0,0 +1,5 @@ +#include + +long double nexttowardl(long double x, long double y) { + return nextafterl(x, y); +} diff --git a/third_party/ulib/musl/src/math/remainder.c b/third_party/ulib/musl/src/math/remainder.c new file mode 100644 index 000000000..ab0d998b6 --- /dev/null +++ b/third_party/ulib/musl/src/math/remainder.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include + +double remainder(double x, double y) { + int q; + return remquo(x, y, &q); +} + +weak_alias(remainder, drem); diff --git a/third_party/ulib/musl/src/math/remainderf.c b/third_party/ulib/musl/src/math/remainderf.c new file mode 100644 index 000000000..7679ac9f1 --- /dev/null +++ b/third_party/ulib/musl/src/math/remainderf.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include + +float remainderf(float x, float y) { + int q; + return remquof(x, y, &q); +} + +weak_alias(remainderf, dremf); diff --git a/third_party/ulib/musl/src/math/remainderl.c b/third_party/ulib/musl/src/math/remainderl.c new file mode 100644 index 000000000..55222253d --- /dev/null +++ b/third_party/ulib/musl/src/math/remainderl.c @@ -0,0 +1,13 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remainderl(long double x, long double y) { + return remainder(x, y); +} +#else +long double remainderl(long double x, long double y) { + int q; + return remquol(x, y, &q); +} +#endif diff --git a/third_party/ulib/musl/src/math/remquo.c b/third_party/ulib/musl/src/math/remquo.c new file mode 100644 index 000000000..54bf0e997 --- /dev/null +++ b/third_party/ulib/musl/src/math/remquo.c @@ -0,0 +1,83 @@ +#include +#include + +double remquo(double x, double y, int* quo) { + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + int ex = ux.i >> 52 & 0x7ff; + int ey = uy.i >> 52 & 0x7ff; + int sx = ux.i >> 63; + int sy = uy.i >> 63; + uint32_t q; + uint64_t i; + uint64_t uxi = ux.i; + + *quo = 0; + if (uy.i << 1 == 0 || isnan(y) || ex == 0x7ff) return (x * y) / (x * y); + if (ux.i << 1 == 0) return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) + ; + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) + ; + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + q = 0; + if (ex < ey) { + if (ex + 1 == ey) goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -60; + else + for (; uxi >> 52 == 0; uxi <<= 1, ex--) + ; +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) y = -y; + if (ex == ey || (ex + 1 == ey && (2 * x > y || (2 * x == y && q % 2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx ^ sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/third_party/ulib/musl/src/math/remquof.c b/third_party/ulib/musl/src/math/remquof.c new file mode 100644 index 000000000..dbebf5ea7 --- /dev/null +++ b/third_party/ulib/musl/src/math/remquof.c @@ -0,0 +1,83 @@ +#include +#include + +float remquof(float x, float y, int* quo) { + union { + float f; + uint32_t i; + } ux = {x}, uy = {y}; + int ex = ux.i >> 23 & 0xff; + int ey = uy.i >> 23 & 0xff; + int sx = ux.i >> 31; + int sy = uy.i >> 31; + uint32_t q; + uint32_t i; + uint32_t uxi = ux.i; + + *quo = 0; + if (uy.i << 1 == 0 || isnan(y) || ex == 0xff) return (x * y) / (x * y); + if (ux.i << 1 == 0) return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi << 9; i >> 31 == 0; ex--, i <<= 1) + ; + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i << 9; i >> 31 == 0; ey--, i <<= 1) + ; + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + q = 0; + if (ex < ey) { + if (ex + 1 == ey) goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -30; + else + for (; uxi >> 23 == 0; uxi <<= 1, ex--) + ; +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) y = -y; + if (ex == ey || (ex + 1 == ey && (2 * x > y || (2 * x == y && q % 2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx ^ sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/third_party/ulib/musl/src/math/remquol.c b/third_party/ulib/musl/src/math/remquol.c new file mode 100644 index 000000000..eef88c873 --- /dev/null +++ b/third_party/ulib/musl/src/math/remquol.c @@ -0,0 +1,119 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remquol(long double x, long double y, int* quo) { + return remquo(x, y, quo); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double remquol(long double x, long double y, int* quo) { + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se >> 15; + int sy = uy.i.se >> 15; + uint32_t q; + + *quo = 0; + if (y == 0 || isnan(y) || ex == 0x7fff) return (x * y) / (x * y); + if (x == 0) return x; + + /* normalize x and y */ + if (!ex) { + ux.i.se = ex; + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.i.se = ey; + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + q = 0; + if (ex >= ey) { +/* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + mx = 2 * i; + q++; + q <<= 1; + } else if (2 * mx < mx) { + mx = 2 * mx - my; + q <<= 1; + q++; + } else { + mx = 2 * mx; + q <<= 1; + } + } + i = mx - my; + if (mx >= my) { + mx = i; + q++; + } + if (mx == 0) + ex = -120; + else + for (; mx >> 63 == 0; mx *= 2, ex--) + ; + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL >> 16) | 1ULL << 48; + yhi = (uy.i2.hi & -1ULL >> 16) | 1ULL << 48; + xlo = ux.i2.lo; + ylo = ux.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) hi -= 1; + if (hi >> 63 == 0) { + xhi = 2 * hi + (lo >> 63); + xlo = 2 * lo; + q++; + } else { + xhi = 2 * xhi + (xlo >> 63); + xlo = 2 * xlo; + } + q <<= 1; + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) hi -= 1; + if (hi >> 63 == 0) { + xhi = hi; + xlo = lo; + q++; + } + if ((xhi | xlo) == 0) + ex = -120; + else + for (; xhi >> 48 == 0; xhi = 2 * xhi + (xlo >> 63), xlo = 2 * xlo, ex--) + ; + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + } + + /* scale result and decide between |x| and |x|-|y| */ + if (ex <= 0) { + ux.i.se = ex + 120; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex; + x = ux.f; + if (sy) y = -y; + if (ex == ey || (ex + 1 == ey && (2 * x > y || (2 * x == y && q % 2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx ^ sy ? -(int)q : (int)q; + return sx ? -x : x; +} +#endif diff --git a/third_party/ulib/musl/src/math/rint.c b/third_party/ulib/musl/src/math/rint.c new file mode 100644 index 000000000..4ba79618b --- /dev/null +++ b/third_party/ulib/musl/src/math/rint.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1 / EPS; + +double rint(double x) { + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + int s = u.i >> 63; + double_t y; + + if (e >= 0x3ff + 52) return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) return s ? -0.0 : 0; + return y; +} diff --git a/third_party/ulib/musl/src/math/rintf.c b/third_party/ulib/musl/src/math/rintf.c new file mode 100644 index 000000000..b1990fd33 --- /dev/null +++ b/third_party/ulib/musl/src/math/rintf.c @@ -0,0 +1,30 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD == 0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1 / EPS; + +float rintf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + int e = u.i >> 23 & 0xff; + int s = u.i >> 31; + float_t y; + + if (e >= 0x7f + 23) return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) return s ? -0.0f : 0.0f; + return y; +} diff --git a/third_party/ulib/musl/src/math/rintl.c b/third_party/ulib/musl/src/math/rintl.c new file mode 100644 index 000000000..4a62d8773 --- /dev/null +++ b/third_party/ulib/musl/src/math/rintl.c @@ -0,0 +1,25 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double rintl(long double x) { + return rint(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1 / LDBL_EPSILON; + +long double rintl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff + LDBL_MANT_DIG - 1) return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) return 0 * x; + return y; +} +#endif diff --git a/third_party/ulib/musl/src/math/round.c b/third_party/ulib/musl/src/math/round.c new file mode 100644 index 000000000..b15d2e00d --- /dev/null +++ b/third_party/ulib/musl/src/math/round.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1 / EPS; + +double round(double x) { + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff + 52) return x; + if (u.i >> 63) x = -x; + if (e < 0x3ff - 1) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + toint); + return 0 * u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) y = -y; + return y; +} diff --git a/third_party/ulib/musl/src/math/roundf.c b/third_party/ulib/musl/src/math/roundf.c new file mode 100644 index 000000000..f229d1613 --- /dev/null +++ b/third_party/ulib/musl/src/math/roundf.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD == 0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1 / EPS; + +float roundf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + int e = u.i >> 23 & 0xff; + float_t y; + + if (e >= 0x7f + 23) return x; + if (u.i >> 31) x = -x; + if (e < 0x7f - 1) { + FORCE_EVAL(x + toint); + return 0 * u.f; + } + y = x + toint - toint - x; + if (y > 0.5f) + y = y + x - 1; + else if (y <= -0.5f) + y = y + x + 1; + else + y = y + x; + if (u.i >> 31) y = -y; + return y; +} diff --git a/third_party/ulib/musl/src/math/roundl.c b/third_party/ulib/musl/src/math/roundl.c new file mode 100644 index 000000000..0dbd5513c --- /dev/null +++ b/third_party/ulib/musl/src/math/roundl.c @@ -0,0 +1,32 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double roundl(long double x) { + return round(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1 / LDBL_EPSILON; + +long double roundl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff + LDBL_MANT_DIG - 1) return x; + if (u.i.se >> 15) x = -x; + if (e < 0x3fff - 1) { + FORCE_EVAL(x + toint); + return 0 * u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i.se >> 15) y = -y; + return y; +} +#endif diff --git a/third_party/ulib/musl/src/math/scalbln.c b/third_party/ulib/musl/src/math/scalbln.c new file mode 100644 index 000000000..9c01bc597 --- /dev/null +++ b/third_party/ulib/musl/src/math/scalbln.c @@ -0,0 +1,10 @@ +#include +#include + +double scalbln(double x, long n) { + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbn(x, n); +} diff --git a/third_party/ulib/musl/src/math/scalblnf.c b/third_party/ulib/musl/src/math/scalblnf.c new file mode 100644 index 000000000..b23ac49a4 --- /dev/null +++ b/third_party/ulib/musl/src/math/scalblnf.c @@ -0,0 +1,10 @@ +#include +#include + +float scalblnf(float x, long n) { + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnf(x, n); +} diff --git a/third_party/ulib/musl/src/math/scalblnl.c b/third_party/ulib/musl/src/math/scalblnl.c new file mode 100644 index 000000000..7ac6a7a70 --- /dev/null +++ b/third_party/ulib/musl/src/math/scalblnl.c @@ -0,0 +1,17 @@ +#include +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalblnl(long double x, long n) { + return scalbln(x, n); +} +#else +long double scalblnl(long double x, long n) { + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnl(x, n); +} +#endif diff --git a/third_party/ulib/musl/src/math/scalbn.c b/third_party/ulib/musl/src/math/scalbn.c new file mode 100644 index 000000000..f56116807 --- /dev/null +++ b/third_party/ulib/musl/src/math/scalbn.c @@ -0,0 +1,31 @@ +#include +#include + +double scalbn(double x, int n) { + union { + double f; + uint64_t i; + } u; + double_t y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) n = 1023; + } + } else if (n < -1022) { + y *= 0x1p-1022; + n += 1022; + if (n < -1022) { + y *= 0x1p-1022; + n += 1022; + if (n < -1022) n = -1022; + } + } + u.i = (uint64_t)(0x3ff + n) << 52; + x = y * u.f; + return x; +} diff --git a/third_party/ulib/musl/src/math/scalbnf.c b/third_party/ulib/musl/src/math/scalbnf.c new file mode 100644 index 000000000..395362d5b --- /dev/null +++ b/third_party/ulib/musl/src/math/scalbnf.c @@ -0,0 +1,31 @@ +#include +#include + +float scalbnf(float x, int n) { + union { + float f; + uint32_t i; + } u; + float_t y = x; + + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) n = 127; + } + } else if (n < -126) { + y *= 0x1p-126f; + n += 126; + if (n < -126) { + y *= 0x1p-126f; + n += 126; + if (n < -126) n = -126; + } + } + u.i = (uint32_t)(0x7f + n) << 23; + x = y * u.f; + return x; +} diff --git a/third_party/ulib/musl/src/math/scalbnl.c b/third_party/ulib/musl/src/math/scalbnl.c new file mode 100644 index 000000000..ab0d220a2 --- /dev/null +++ b/third_party/ulib/musl/src/math/scalbnl.c @@ -0,0 +1,32 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalbnl(long double x, int n) { + return scalbn(x, n); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double scalbnl(long double x, int n) { + union ldshape u; + + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) n = 16383; + } + } else if (n < -16382) { + x *= 0x1p-16382L; + n += 16382; + if (n < -16382) { + x *= 0x1p-16382L; + n += 16382; + if (n < -16382) n = -16382; + } + } + u.f = 1.0; + u.i.se = 0x3fff + n; + return x * u.f; +} +#endif diff --git a/third_party/ulib/musl/src/math/signgam.c b/third_party/ulib/musl/src/math/signgam.c new file mode 100644 index 000000000..1febcfbfe --- /dev/null +++ b/third_party/ulib/musl/src/math/signgam.c @@ -0,0 +1,6 @@ +#include "libc.h" +#include + +int __signgam = 0; + +weak_alias(__signgam, signgam); diff --git a/third_party/ulib/musl/src/math/significand.c b/third_party/ulib/musl/src/math/significand.c new file mode 100644 index 000000000..9f2eba0f2 --- /dev/null +++ b/third_party/ulib/musl/src/math/significand.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +double significand(double x) { + return scalbn(x, -ilogb(x)); +} diff --git a/third_party/ulib/musl/src/math/significandf.c b/third_party/ulib/musl/src/math/significandf.c new file mode 100644 index 000000000..47192b137 --- /dev/null +++ b/third_party/ulib/musl/src/math/significandf.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +float significandf(float x) { + return scalbnf(x, -ilogbf(x)); +} diff --git a/third_party/ulib/musl/src/math/sincosl.c b/third_party/ulib/musl/src/math/sincosl.c new file mode 100644 index 000000000..dcd675c3b --- /dev/null +++ b/third_party/ulib/musl/src/math/sincosl.c @@ -0,0 +1,58 @@ +#define _GNU_SOURCE +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +void sincosl(long double x, long double* sin, long double* cos) { + double sind, cosd; + sincos(x, &sind, &cosd); + *sin = sind; + *cos = cosd; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +void sincosl(long double x, long double* sin, long double* cos) { + union ldshape u = {x}; + unsigned n; + long double y[2], s, c; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) { + *sin = *cos = x - x; + return; + } + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) { + /* raise underflow if subnormal */ + if (u.i.se == 0) FORCE_EVAL(x * 0x1p-120f); + *sin = x; + /* raise inexact if x!=0 */ + *cos = 1.0 + x; + return; + } + *sin = __sinl(x, 0, 0); + *cos = __cosl(x, 0); + return; + } + n = __rem_pio2l(x, y); + s = __sinl(y[0], y[1], 1); + c = __cosl(y[0], y[1]); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} +#endif diff --git a/third_party/ulib/musl/src/math/sinh.c b/third_party/ulib/musl/src/math/sinh.c new file mode 100644 index 000000000..6db9334a5 --- /dev/null +++ b/third_party/ulib/musl/src/math/sinh.c @@ -0,0 +1,39 @@ +#include "libm.h" + +/* sinh(x) = (exp(x) - 1/exp(x))/2 + * = (exp(x)-1 + (exp(x)-1)/exp(x))/2 + * = x + x^3/6 + o(x^5) + */ +double sinh(double x) { + union { + double f; + uint64_t i; + } u = {.f = x}; + uint32_t w; + double t, h, absx; + + h = 0.5; + if (u.i >> 63) h = -h; + /* |x| */ + u.i &= (uint64_t)-1 / 2; + absx = u.f; + w = u.i >> 32; + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = expm1(absx); + if (w < 0x3ff00000) { + if (w < 0x3ff00000 - (26 << 20)) /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + return h * (2 * t - t * t / (t + 1)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h * (t + t / (t + 1)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2 * h * __expo2(absx); + return t; +} diff --git a/third_party/ulib/musl/src/math/sinhf.c b/third_party/ulib/musl/src/math/sinhf.c new file mode 100644 index 000000000..3e4cc34e7 --- /dev/null +++ b/third_party/ulib/musl/src/math/sinhf.c @@ -0,0 +1,31 @@ +#include "libm.h" + +float sinhf(float x) { + union { + float f; + uint32_t i; + } u = {.f = x}; + uint32_t w; + float t, h, absx; + + h = 0.5; + if (u.i >> 31) h = -h; + /* |x| */ + u.i &= 0x7fffffff; + absx = u.f; + w = u.i; + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expm1f(absx); + if (w < 0x3f800000) { + if (w < 0x3f800000 - (12 << 23)) return x; + return h * (2 * t - t * t / (t + 1)); + } + return h * (t + t / (t + 1)); + } + + /* |x| > logf(FLT_MAX) or nan */ + t = 2 * h * __expo2f(absx); + return t; +} diff --git a/third_party/ulib/musl/src/math/sinhl.c b/third_party/ulib/musl/src/math/sinhl.c new file mode 100644 index 000000000..84abf92ad --- /dev/null +++ b/third_party/ulib/musl/src/math/sinhl.c @@ -0,0 +1,38 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinhl(long double x) { + return sinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double sinhl(long double x) { + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + long double h, t, absx; + + h = 0.5; + if (u.i.se & 0x8000) h = -h; + /* |x| */ + u.i.se = ex; + absx = u.f; + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff + 13 || (ex == 0x3fff + 13 && u.i.m >> 32 < 0xb17217f7)) { + t = expm1l(absx); + if (ex < 0x3fff) { + if (ex < 0x3fff - 32) return x; + return h * (2 * t - t * t / (1 + t)); + } + return h * (t + t / (t + 1)); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5 * absx); + return h * t * t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double sinhl(long double x) { + return sinh(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/sinl.c b/third_party/ulib/musl/src/math/sinl.c new file mode 100644 index 000000000..b6b5b2759 --- /dev/null +++ b/third_party/ulib/musl/src/math/sinl.c @@ -0,0 +1,38 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinl(long double x) { + return sin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double sinl(long double x) { + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG / 2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x * 0x1p-120f : x + 0x1p120f); + return x; + } + return __sinl(x, 0.0, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __sinl(hi, lo, 1); + case 1: + return __cosl(hi, lo); + case 2: + return -__sinl(hi, lo, 1); + case 3: + default: + return -__cosl(hi, lo); + } +} +#endif diff --git a/third_party/ulib/musl/src/math/sqrtl.c b/third_party/ulib/musl/src/math/sqrtl.c new file mode 100644 index 000000000..8eedfee10 --- /dev/null +++ b/third_party/ulib/musl/src/math/sqrtl.c @@ -0,0 +1,6 @@ +#include + +long double sqrtl(long double x) { + /* FIXME: implement in C, this is for LDBL_MANT_DIG == 64 only */ + return sqrt(x); +} diff --git a/third_party/ulib/musl/src/math/tanh.c b/third_party/ulib/musl/src/math/tanh.c new file mode 100644 index 000000000..14fb24db4 --- /dev/null +++ b/third_party/ulib/musl/src/math/tanh.c @@ -0,0 +1,47 @@ +#include "libm.h" + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +double tanh(double x) { + union { + double f; + uint64_t i; + } u = {.f = x}; + uint32_t w; + int sign; + double_t t; + + /* x = |x| */ + sign = u.i >> 63; + u.i &= (uint64_t)-1 / 2; + x = u.f; + w = u.i >> 32; + + if (w > 0x3fe193ea) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x40340000) { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1 - 0 / x; + } else { + t = expm1(2 * x); + t = 1 - 2 / (t + 2); + } + } else if (w > 0x3fd058ae) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2 * x); + t = t / (t + 2); + } else if (w >= 0x00100000) { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2 * x); + t = -t / (t + 2); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + FORCE_EVAL((float)x); + t = x; + } + return sign ? -t : t; +} diff --git a/third_party/ulib/musl/src/math/tanhf.c b/third_party/ulib/musl/src/math/tanhf.c new file mode 100644 index 000000000..2a18440c7 --- /dev/null +++ b/third_party/ulib/musl/src/math/tanhf.c @@ -0,0 +1,41 @@ +#include "libm.h" + +float tanhf(float x) { + union { + float f; + uint32_t i; + } u = {.f = x}; + uint32_t w; + int sign; + float t; + + /* x = |x| */ + sign = u.i >> 31; + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + if (w > 0x3f0c9f54) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x41200000) { + /* |x| > 10 */ + t = 1 + 0 / x; + } else { + t = expm1f(2 * x); + t = 1 - 2 / (t + 2); + } + } else if (w > 0x3e82c578) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1f(2 * x); + t = t / (t + 2); + } else if (w >= 0x00800000) { + /* |x| >= 0x1p-126 */ + t = expm1f(-2 * x); + t = -t / (t + 2); + } else { + /* |x| is subnormal */ + FORCE_EVAL(x * x); + t = x; + } + return sign ? -t : t; +} diff --git a/third_party/ulib/musl/src/math/tanhl.c b/third_party/ulib/musl/src/math/tanhl.c new file mode 100644 index 000000000..58918327b --- /dev/null +++ b/third_party/ulib/musl/src/math/tanhl.c @@ -0,0 +1,45 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanhl(long double x) { + return tanh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double tanhl(long double x) { + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + unsigned sign = u.i.se & 0x8000; + uint32_t w; + long double t; + + /* x = |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + if (ex > 0x3ffe || (ex == 0x3ffe && w > 0x8c9f53d5)) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (ex >= 0x3fff + 5) { + /* |x| >= 32 */ + t = 1 + 0 / (x + 0x1p-120f); + } else { + t = expm1l(2 * x); + t = 1 - 2 / (t + 2); + } + } else if (ex > 0x3ffd || (ex == 0x3ffd && w > 0x82c577d4)) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1l(2 * x); + t = t / (t + 2); + } else { + /* |x| is small */ + t = expm1l(-2 * x); + t = -t / (t + 2); + } + return sign ? -t : t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tanhl(long double x) { + return tanh(x); +} +#endif diff --git a/third_party/ulib/musl/src/math/tanl.c b/third_party/ulib/musl/src/math/tanl.c new file mode 100644 index 000000000..dfd5219de --- /dev/null +++ b/third_party/ulib/musl/src/math/tanl.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanl(long double x) { + return tan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double tanl(long double x) { + union ldshape u = {x}; + long double y[2]; + unsigned n; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG / 2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x * 0x1p-120f : x + 0x1p120f); + return x; + } + return __tanl(x, 0, 0); + } + n = __rem_pio2l(x, y); + return __tanl(y[0], y[1], n & 1); +} +#endif diff --git a/third_party/ulib/musl/src/math/tgamma.c b/third_party/ulib/musl/src/math/tgamma.c new file mode 100644 index 000000000..5b4958502 --- /dev/null +++ b/third_party/ulib/musl/src/math/tgamma.c @@ -0,0 +1,236 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +#include "libm.h" + +static const double pi = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sinpi(double x) { + int n; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = 4 * x; + n = (n + 1) / 2; + x -= n * 0.5; + + x *= pi; + switch (n) { + default: /* case 4 */ + case 0: + return __sin(x, 0, 0); + case 1: + return __cos(x, 0); + case 2: + return __sin(-x, 0, 0); + case 3: + return -__cos(x, 0); + } +} + +#define N 12 +// static const double g = 6.024680040776729583740234375; +static const double gmhalf = 5.524680040776729583740234375; +static const double Snum[N + 1] = { + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +}; +static const double Sden[N + 1] = { + 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535, + 2637558, 357423, 32670, 1925, 66, 1, +}; +/* n! for small integer n */ +static const double fact[] = { + 1, + 1, + 2, + 6, + 24, + 120, + 720, + 5040.0, + 40320.0, + 362880.0, + 3628800.0, + 39916800.0, + 479001600.0, + 6227020800.0, + 87178291200.0, + 1307674368000.0, + 20922789888000.0, + 355687428096000.0, + 6402373705728000.0, + 121645100408832000.0, + 2432902008176640000.0, + 51090942171709440000.0, + 1124000727777607680000.0, +}; + +/* S(x) rational function for positive x */ +static double S(double x) { + double_t num = 0, den = 0; + int i; + + /* to avoid overflow handle large x differently */ + if (x < 8) + for (i = N; i >= 0; i--) { + num = num * x + Snum[i]; + den = den * x + Sden[i]; + } + else + for (i = 0; i <= N; i++) { + num = num / x + Snum[i]; + den = den / x + Sden[i]; + } + return num / den; +} + +double tgamma(double x) { + union { + double f; + uint64_t i; + } u = {x}; + double absx, y; + double_t dy, z, r; + uint32_t ix = u.i >> 32 & 0x7fffffff; + int sign = u.i >> 63; + + /* special cases */ + if (ix >= 0x7ff00000) /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + INFINITY; + if (ix < (0x3ff - 54) << 20) /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1 / x; + + /* integer arguments */ + /* raise inexact when non-integer */ + if (x == floor(x)) { + if (sign) return 0 / 0.0; + if (x <= sizeof fact / sizeof *fact) return fact[(int)x - 1]; + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if (ix >= 0x40670000) { /* |x| >= 184 */ + if (sign) { + FORCE_EVAL((float)(0x1p-126 / x)); + if (floor(x) * 0.5 == floor(x * 0.5)) return 0; + return -0.0; + } + x *= 0x1p1023; + return x; + } + + absx = sign ? -x : x; + + /* handle the error of x + g - 0.5 */ + y = absx + gmhalf; + if (absx > gmhalf) { + dy = y - absx; + dy -= gmhalf; + } else { + dy = y - gmhalf; + dy -= absx; + } + + z = absx - 0.5; + r = S(absx) * exp(-y); + if (x < 0) { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -pi / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (gmhalf + 0.5) * r / y; + z = pow(y, 0.5 * z); + y = r * z * z; + return y; +} + +#if 0 +double __lgamma_r(double x, int *sign) +{ + double r, absx; + + *sign = 1; + + /* special cases */ + if (!isfinite(x)) + /* lgamma(nan)=nan, lgamma(+-inf)=inf */ + return x*x; + + /* integer arguments */ + if (x == floor(x) && x <= 2) { + /* n <= 0: lgamma(n)=inf with divbyzero */ + /* n == 1,2: lgamma(n)=0 */ + if (x <= 0) + return 1/0.0; + return 0; + } + + absx = fabs(x); + + /* lgamma(x) ~ -log(|x|) for tiny |x| */ + if (absx < 0x1p-54) { + *sign = 1 - 2*!!signbit(x); + return -log(absx); + } + + /* use tgamma for smaller |x| */ + if (absx < 128) { + x = tgamma(x); + *sign = 1 - 2*!!signbit(x); + return log(fabs(x)); + } + + /* second term (log(S)-g) could be more precise here.. */ + /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */ + r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5)); + if (x < 0) { + /* reflection formula for negative x */ + x = sinpi(absx); + *sign = 2*!!signbit(x) - 1; + r = log(pi/(fabs(x)*absx)) - r; + } + return r; +} + +weak_alias(__lgamma_r, lgamma_r); +#endif diff --git a/third_party/ulib/musl/src/math/tgammaf.c b/third_party/ulib/musl/src/math/tgammaf.c new file mode 100644 index 000000000..05cc244ea --- /dev/null +++ b/third_party/ulib/musl/src/math/tgammaf.c @@ -0,0 +1,5 @@ +#include + +float tgammaf(float x) { + return tgamma(x); +} diff --git a/third_party/ulib/musl/src/math/trunc.c b/third_party/ulib/musl/src/math/trunc.c new file mode 100644 index 000000000..50ac46b1d --- /dev/null +++ b/third_party/ulib/musl/src/math/trunc.c @@ -0,0 +1,18 @@ +#include "libm.h" + +double trunc(double x) { + union { + double f; + uint64_t i; + } u = {x}; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12; + uint64_t m; + + if (e >= 52 + 12) return x; + if (e < 12) e = 1; + m = -1ULL >> e; + if ((u.i & m) == 0) return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/third_party/ulib/musl/src/math/truncf.c b/third_party/ulib/musl/src/math/truncf.c new file mode 100644 index 000000000..3cf9e08ad --- /dev/null +++ b/third_party/ulib/musl/src/math/truncf.c @@ -0,0 +1,18 @@ +#include "libm.h" + +float truncf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) return x; + if (e < 9) e = 1; + m = -1U >> e; + if ((u.i & m) == 0) return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/third_party/ulib/musl/src/math/truncl.c b/third_party/ulib/musl/src/math/truncl.c new file mode 100644 index 000000000..f7b30ae99 --- /dev/null +++ b/third_party/ulib/musl/src/math/truncl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double truncl(long double x) { + return trunc(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1 / LDBL_EPSILON; + +long double truncl(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff + LDBL_MANT_DIG - 1) return x; + if (e <= 0x3fff - 1) { + FORCE_EVAL(x + 0x1p120f); + return x * 0; + } + /* y = int(|x|) - |x|, where int(|x|) is an integer neighbor of |x| */ + if (s) x = -x; + y = x + toint - toint - x; + if (y > 0) y -= 1; + x += y; + return s ? -x : x; +} +#endif diff --git a/third_party/ulib/musl/src/math/x32/__invtrigl.s b/third_party/ulib/musl/src/math/x32/__invtrigl.s new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/math/x32/acosl.s b/third_party/ulib/musl/src/math/x32/acosl.s new file mode 100644 index 000000000..464ae4fe3 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/acosl.s @@ -0,0 +1,16 @@ +# see ../x86_64/acosl.s + +.global acosl +.type acosl,@function +acosl: + fldt 8(%esp) +1: fld %st(0) + fld1 + fsub %st(0),%st(1) + fadd %st(2) + fmulp + fsqrt + fabs + fxch %st(1) + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x32/asinl.s b/third_party/ulib/musl/src/math/x32/asinl.s new file mode 100644 index 000000000..7fe9f1276 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/asinl.s @@ -0,0 +1,12 @@ +.global asinl +.type asinl,@function +asinl: + fldt 8(%esp) +1: fld %st(0) + fld1 + fsub %st(0),%st(1) + fadd %st(2) + fmulp + fsqrt + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x32/atan2l.s b/third_party/ulib/musl/src/math/x32/atan2l.s new file mode 100644 index 000000000..1ead0788a --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/atan2l.s @@ -0,0 +1,7 @@ +.global atan2l +.type atan2l,@function +atan2l: + fldt 8(%esp) + fldt 24(%esp) + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x32/atanl.s b/third_party/ulib/musl/src/math/x32/atanl.s new file mode 100644 index 000000000..f475fe0e9 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/atanl.s @@ -0,0 +1,7 @@ +.global atanl +.type atanl,@function +atanl: + fldt 8(%esp) + fld1 + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x32/ceill.s b/third_party/ulib/musl/src/math/x32/ceill.s new file mode 100644 index 000000000..f5cfa3b30 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/ceill.s @@ -0,0 +1 @@ +# see floorl.s diff --git a/third_party/ulib/musl/src/math/x32/exp2l.s b/third_party/ulib/musl/src/math/x32/exp2l.s new file mode 100644 index 000000000..e9edb96f2 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/exp2l.s @@ -0,0 +1,83 @@ +.global expm1l +.type expm1l,@function +expm1l: + fldt 8(%esp) + fldl2e + fmulp + movl $0xc2820000,-4(%esp) + flds -4(%esp) + fucomip %st(1),%st + fld1 + jb 1f + # x*log2e <= -65, return -1 without underflow + fstp %st(1) + fchs + ret +1: fld %st(1) + fabs + fucomip %st(1),%st + fstp %st(0) + ja 1f + f2xm1 + ret +1: push %rax + call 1f + pop %rax + fld1 + fsubrp + ret + +.global exp2l +.type exp2l,@function +exp2l: + fldt 8(%esp) +1: fld %st(0) + sub $16,%esp + fstpt (%esp) + mov 8(%esp),%ax + and $0x7fff,%ax + cmp $0x3fff+13,%ax + jb 4f # |x| < 8192 + cmp $0x3fff+15,%ax + jae 3f # |x| >= 32768 + fsts (%esp) + cmpl $0xc67ff800,(%esp) + jb 2f # x > -16382 + movl $0x5f000000,(%esp) + flds (%esp) # 0x1p63 + fld %st(1) + fsub %st(1) + faddp + fucomip %st(1),%st + je 2f # x - 0x1p63 + 0x1p63 == x + movl $1,(%esp) + flds (%esp) # 0x1p-149 + fdiv %st(1) + fstps (%esp) # raise underflow +2: fld1 + fld %st(1) + frndint + fxch %st(2) + fsub %st(2) # st(0)=x-rint(x), st(1)=1, st(2)=rint(x) + f2xm1 + faddp # 2^(x-rint(x)) +1: fscale + fstp %st(1) + add $16,%esp + ret +3: xor %eax,%eax +4: cmp $0x3fff-64,%ax + fld1 + jb 1b # |x| < 0x1p-64 + fstpt (%esp) + fistl 8(%esp) + fildl 8(%esp) + fsubrp %st(1) + addl $0x3fff,8(%esp) + f2xm1 + fld1 + faddp # 2^(x-rint(x)) + fldt (%esp) # 2^rint(x) + fmulp + add $16,%esp + ret diff --git a/third_party/ulib/musl/src/math/x32/expl.s b/third_party/ulib/musl/src/math/x32/expl.s new file mode 100644 index 000000000..369f7bd21 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/expl.s @@ -0,0 +1,101 @@ +# exp(x) = 2^hi + 2^hi (2^lo - 1) +# where hi+lo = log2e*x with 128bit precision +# exact log2e*x calculation depends on nearest rounding mode +# using the exact multiplication method of Dekker and Veltkamp + +.global expl +.type expl,@function +expl: + fldt 8(%esp) + + # interesting case: 0x1p-32 <= |x| < 16384 + # check if (exponent|0x8000) is in [0xbfff-32, 0xbfff+13] + mov 16(%esp), %ax + or $0x8000, %ax + sub $0xbfdf, %ax + cmp $45, %ax + jbe 2f + test %ax, %ax + fld1 + js 1f + # if |x|>=0x1p14 or nan return 2^trunc(x) + fscale + fstp %st(1) + ret + # if |x|<0x1p-32 return 1+x +1: faddp + ret + + # should be 0x1.71547652b82fe178p0L == 0x3fff b8aa3b29 5c17f0bc + # it will be wrong on non-nearest rounding mode +2: fldl2e + sub $48, %esp + # hi = log2e_hi*x + # 2^hi = exp2l(hi) + fmul %st(1),%st + fld %st(0) + fstpt (%esp) + fstpt 16(%esp) + fstpt 32(%esp) + call exp2l@PLT + # if 2^hi == inf return 2^hi + fld %st(0) + fstpt (%esp) + cmpw $0x7fff, 8(%esp) + je 1f + fldt 32(%esp) + fldt 16(%esp) + # fpu stack: 2^hi x hi + # exact mult: x*log2e + fld %st(1) + # c = 0x1p32+1 + movq $0x41f0000000100000,%rax + pushq %rax + fldl (%esp) + # xh = x - c*x + c*x + # xl = x - xh + fmulp + fld %st(2) + fsub %st(1), %st + faddp + fld %st(2) + fsub %st(1), %st + # yh = log2e_hi - c*log2e_hi + c*log2e_hi + movq $0x3ff7154765200000,%rax + pushq %rax + fldl (%esp) + # fpu stack: 2^hi x hi xh xl yh + # lo = hi - xh*yh + xl*yh + fld %st(2) + fmul %st(1), %st + fsubp %st, %st(4) + fmul %st(1), %st + faddp %st, %st(3) + # yl = log2e_hi - yh + movq $0x3de705fc2f000000,%rax + pushq %rax + fldl (%esp) + # fpu stack: 2^hi x lo xh xl yl + # lo += xh*yl + xl*yl + fmul %st, %st(2) + fmulp %st, %st(1) + fxch %st(2) + faddp + faddp + # log2e_lo + movq $0xbfbe,%rax + pushq %rax + movq $0x82f0025f2dc582ee,%rax + pushq %rax + fldt (%esp) + add $40,%esp + # fpu stack: 2^hi x lo log2e_lo + # lo += log2e_lo*x + # return 2^hi + 2^hi (2^lo - 1) + fmulp %st, %st(2) + faddp + f2xm1 + fmul %st(1), %st + faddp +1: add $48, %esp + ret diff --git a/third_party/ulib/musl/src/math/x32/expm1l.s b/third_party/ulib/musl/src/math/x32/expm1l.s new file mode 100644 index 000000000..e773f0805 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/expm1l.s @@ -0,0 +1 @@ +# see exp2l.s diff --git a/third_party/ulib/musl/src/math/x32/fabs.s b/third_party/ulib/musl/src/math/x32/fabs.s new file mode 100644 index 000000000..5715005e3 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/fabs.s @@ -0,0 +1,9 @@ +.global fabs +.type fabs,@function +fabs: + xor %eax,%eax + dec %rax + shr %rax + movq %rax,%xmm1 + andpd %xmm1,%xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x32/fabsf.s b/third_party/ulib/musl/src/math/x32/fabsf.s new file mode 100644 index 000000000..501a1f175 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/fabsf.s @@ -0,0 +1,7 @@ +.global fabsf +.type fabsf,@function +fabsf: + mov $0x7fffffff,%eax + movq %rax,%xmm1 + andps %xmm1,%xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x32/fabsl.s b/third_party/ulib/musl/src/math/x32/fabsl.s new file mode 100644 index 000000000..4f215df5c --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/fabsl.s @@ -0,0 +1,6 @@ +.global fabsl +.type fabsl,@function +fabsl: + fldt 8(%esp) + fabs + ret diff --git a/third_party/ulib/musl/src/math/x32/floorl.s b/third_party/ulib/musl/src/math/x32/floorl.s new file mode 100644 index 000000000..78dcb6dad --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/floorl.s @@ -0,0 +1,27 @@ +.global floorl +.type floorl,@function +floorl: + fldt 8(%esp) +1: mov $0x7,%al +1: fstcw 8(%esp) + mov 9(%esp),%ah + mov %al,9(%esp) + fldcw 8(%esp) + frndint + mov %ah,9(%esp) + fldcw 8(%esp) + ret + +.global ceill +.type ceill,@function +ceill: + fldt 8(%esp) + mov $0xb,%al + jmp 1b + +.global truncl +.type truncl,@function +truncl: + fldt 8(%esp) + mov $0xf,%al + jmp 1b diff --git a/third_party/ulib/musl/src/math/x32/fmodl.s b/third_party/ulib/musl/src/math/x32/fmodl.s new file mode 100644 index 000000000..c3f790c9b --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/fmodl.s @@ -0,0 +1,11 @@ +.global fmodl +.type fmodl,@function +fmodl: + fldt 24(%esp) + fldt 8(%esp) +1: fprem + fnstsw %ax + testb $4,%ah + jnz 1b + fstp %st(1) + ret diff --git a/third_party/ulib/musl/src/math/x32/llrint.s b/third_party/ulib/musl/src/math/x32/llrint.s new file mode 100644 index 000000000..bf4764983 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/llrint.s @@ -0,0 +1,5 @@ +.global llrint +.type llrint,@function +llrint: + cvtsd2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x32/llrintf.s b/third_party/ulib/musl/src/math/x32/llrintf.s new file mode 100644 index 000000000..d7204ac0c --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/llrintf.s @@ -0,0 +1,5 @@ +.global llrintf +.type llrintf,@function +llrintf: + cvtss2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x32/llrintl.s b/third_party/ulib/musl/src/math/x32/llrintl.s new file mode 100644 index 000000000..09386079e --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/llrintl.s @@ -0,0 +1,7 @@ +.global llrintl +.type llrintl,@function +llrintl: + fldt 8(%esp) + fistpll 8(%esp) + mov 8(%esp),%rax + ret diff --git a/third_party/ulib/musl/src/math/x32/log10l.s b/third_party/ulib/musl/src/math/x32/log10l.s new file mode 100644 index 000000000..ef5bea3fb --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/log10l.s @@ -0,0 +1,7 @@ +.global log10l +.type log10l,@function +log10l: + fldlg2 + fldt 8(%esp) + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x32/log1pl.s b/third_party/ulib/musl/src/math/x32/log1pl.s new file mode 100644 index 000000000..2e64fd4bc --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/log1pl.s @@ -0,0 +1,15 @@ +.global log1pl +.type log1pl,@function +log1pl: + mov 14(%esp),%eax + fldln2 + and $0x7fffffff,%eax + fldt 8(%esp) + cmp $0x3ffd9400,%eax + ja 1f + fyl2xp1 + ret +1: fld1 + faddp + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x32/log2l.s b/third_party/ulib/musl/src/math/x32/log2l.s new file mode 100644 index 000000000..bf88e8e24 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/log2l.s @@ -0,0 +1,7 @@ +.global log2l +.type log2l,@function +log2l: + fld1 + fldt 8(%esp) + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x32/logl.s b/third_party/ulib/musl/src/math/x32/logl.s new file mode 100644 index 000000000..eff645068 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/logl.s @@ -0,0 +1,7 @@ +.global logl +.type logl,@function +logl: + fldln2 + fldt 8(%esp) + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x32/lrint.s b/third_party/ulib/musl/src/math/x32/lrint.s new file mode 100644 index 000000000..15fc2454b --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/lrint.s @@ -0,0 +1,5 @@ +.global lrint +.type lrint,@function +lrint: + cvtsd2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x32/lrintf.s b/third_party/ulib/musl/src/math/x32/lrintf.s new file mode 100644 index 000000000..488423d21 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/lrintf.s @@ -0,0 +1,5 @@ +.global lrintf +.type lrintf,@function +lrintf: + cvtss2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x32/lrintl.s b/third_party/ulib/musl/src/math/x32/lrintl.s new file mode 100644 index 000000000..ee97d1cfe --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/lrintl.s @@ -0,0 +1,7 @@ +.global lrintl +.type lrintl,@function +lrintl: + fldt 8(%esp) + fistpll 8(%esp) + mov 8(%esp),%rax + ret diff --git a/third_party/ulib/musl/src/math/x32/remainderl.s b/third_party/ulib/musl/src/math/x32/remainderl.s new file mode 100644 index 000000000..376ba0e2d --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/remainderl.s @@ -0,0 +1,11 @@ +.global remainderl +.type remainderl,@function +remainderl: + fldt 24(%esp) + fldt 8(%esp) +1: fprem1 + fnstsw %ax + testb $4,%ah + jnz 1b + fstp %st(1) + ret diff --git a/third_party/ulib/musl/src/math/x32/rintl.s b/third_party/ulib/musl/src/math/x32/rintl.s new file mode 100644 index 000000000..be1d2fa73 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/rintl.s @@ -0,0 +1,6 @@ +.global rintl +.type rintl,@function +rintl: + fldt 8(%esp) + frndint + ret diff --git a/third_party/ulib/musl/src/math/x32/sqrt.s b/third_party/ulib/musl/src/math/x32/sqrt.s new file mode 100644 index 000000000..d3c609f9f --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/sqrt.s @@ -0,0 +1,4 @@ +.global sqrt +.type sqrt,@function +sqrt: sqrtsd %xmm0, %xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x32/sqrtf.s b/third_party/ulib/musl/src/math/x32/sqrtf.s new file mode 100644 index 000000000..eec48c609 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/sqrtf.s @@ -0,0 +1,4 @@ +.global sqrtf +.type sqrtf,@function +sqrtf: sqrtss %xmm0, %xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x32/sqrtl.s b/third_party/ulib/musl/src/math/x32/sqrtl.s new file mode 100644 index 000000000..8d70856ec --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/sqrtl.s @@ -0,0 +1,5 @@ +.global sqrtl +.type sqrtl,@function +sqrtl: fldt 8(%esp) + fsqrt + ret diff --git a/third_party/ulib/musl/src/math/x32/truncl.s b/third_party/ulib/musl/src/math/x32/truncl.s new file mode 100644 index 000000000..f5cfa3b30 --- /dev/null +++ b/third_party/ulib/musl/src/math/x32/truncl.s @@ -0,0 +1 @@ +# see floorl.s diff --git a/third_party/ulib/musl/src/math/x86_64/__invtrigl.s b/third_party/ulib/musl/src/math/x86_64/__invtrigl.s new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/math/x86_64/acosl.s b/third_party/ulib/musl/src/math/x86_64/acosl.s new file mode 100644 index 000000000..d00b4b297 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/acosl.s @@ -0,0 +1,16 @@ +# use acos(x) = atan2(fabs(sqrt((1-x)*(1+x))), x) + +.global acosl +.type acosl,@function +acosl: + fldt 8(%rsp) +1: fld %st(0) + fld1 + fsub %st(0),%st(1) + fadd %st(2) + fmulp + fsqrt + fabs + fxch %st(1) + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x86_64/asinl.s b/third_party/ulib/musl/src/math/x86_64/asinl.s new file mode 100644 index 000000000..ed212d9a6 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/asinl.s @@ -0,0 +1,12 @@ +.global asinl +.type asinl,@function +asinl: + fldt 8(%rsp) +1: fld %st(0) + fld1 + fsub %st(0),%st(1) + fadd %st(2) + fmulp + fsqrt + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x86_64/atan2l.s b/third_party/ulib/musl/src/math/x86_64/atan2l.s new file mode 100644 index 000000000..e5f0a3deb --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/atan2l.s @@ -0,0 +1,7 @@ +.global atan2l +.type atan2l,@function +atan2l: + fldt 8(%rsp) + fldt 24(%rsp) + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x86_64/atanl.s b/third_party/ulib/musl/src/math/x86_64/atanl.s new file mode 100644 index 000000000..df76de5de --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/atanl.s @@ -0,0 +1,7 @@ +.global atanl +.type atanl,@function +atanl: + fldt 8(%rsp) + fld1 + fpatan + ret diff --git a/third_party/ulib/musl/src/math/x86_64/ceill.s b/third_party/ulib/musl/src/math/x86_64/ceill.s new file mode 100644 index 000000000..f5cfa3b30 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/ceill.s @@ -0,0 +1 @@ +# see floorl.s diff --git a/third_party/ulib/musl/src/math/x86_64/exp2l.s b/third_party/ulib/musl/src/math/x86_64/exp2l.s new file mode 100644 index 000000000..effab2bd4 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/exp2l.s @@ -0,0 +1,83 @@ +.global expm1l +.type expm1l,@function +expm1l: + fldt 8(%rsp) + fldl2e + fmulp + movl $0xc2820000,-4(%rsp) + flds -4(%rsp) + fucomip %st(1),%st + fld1 + jb 1f + # x*log2e <= -65, return -1 without underflow + fstp %st(1) + fchs + ret +1: fld %st(1) + fabs + fucomip %st(1),%st + fstp %st(0) + ja 1f + f2xm1 + ret +1: push %rax + call 1f + pop %rax + fld1 + fsubrp + ret + +.global exp2l +.type exp2l,@function +exp2l: + fldt 8(%rsp) +1: fld %st(0) + sub $16,%rsp + fstpt (%rsp) + mov 8(%rsp),%ax + and $0x7fff,%ax + cmp $0x3fff+13,%ax + jb 4f # |x| < 8192 + cmp $0x3fff+15,%ax + jae 3f # |x| >= 32768 + fsts (%rsp) + cmpl $0xc67ff800,(%rsp) + jb 2f # x > -16382 + movl $0x5f000000,(%rsp) + flds (%rsp) # 0x1p63 + fld %st(1) + fsub %st(1) + faddp + fucomip %st(1),%st + je 2f # x - 0x1p63 + 0x1p63 == x + movl $1,(%rsp) + flds (%rsp) # 0x1p-149 + fdiv %st(1) + fstps (%rsp) # raise underflow +2: fld1 + fld %st(1) + frndint + fxch %st(2) + fsub %st(2) # st(0)=x-rint(x), st(1)=1, st(2)=rint(x) + f2xm1 + faddp # 2^(x-rint(x)) +1: fscale + fstp %st(1) + add $16,%rsp + ret +3: xor %eax,%eax +4: cmp $0x3fff-64,%ax + fld1 + jb 1b # |x| < 0x1p-64 + fstpt (%rsp) + fistl 8(%rsp) + fildl 8(%rsp) + fsubrp %st(1) + addl $0x3fff,8(%rsp) + f2xm1 + fld1 + faddp # 2^(x-rint(x)) + fldt (%rsp) # 2^rint(x) + fmulp + add $16,%rsp + ret diff --git a/third_party/ulib/musl/src/math/x86_64/expl.s b/third_party/ulib/musl/src/math/x86_64/expl.s new file mode 100644 index 000000000..798261d28 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/expl.s @@ -0,0 +1,101 @@ +# exp(x) = 2^hi + 2^hi (2^lo - 1) +# where hi+lo = log2e*x with 128bit precision +# exact log2e*x calculation depends on nearest rounding mode +# using the exact multiplication method of Dekker and Veltkamp + +.global expl +.type expl,@function +expl: + fldt 8(%rsp) + + # interesting case: 0x1p-32 <= |x| < 16384 + # check if (exponent|0x8000) is in [0xbfff-32, 0xbfff+13] + mov 16(%rsp), %ax + or $0x8000, %ax + sub $0xbfdf, %ax + cmp $45, %ax + jbe 2f + test %ax, %ax + fld1 + js 1f + # if |x|>=0x1p14 or nan return 2^trunc(x) + fscale + fstp %st(1) + ret + # if |x|<0x1p-32 return 1+x +1: faddp + ret + + # should be 0x1.71547652b82fe178p0L == 0x3fff b8aa3b29 5c17f0bc + # it will be wrong on non-nearest rounding mode +2: fldl2e + subq $48, %rsp + # hi = log2e_hi*x + # 2^hi = exp2l(hi) + fmul %st(1),%st + fld %st(0) + fstpt (%rsp) + fstpt 16(%rsp) + fstpt 32(%rsp) + call exp2l@PLT + # if 2^hi == inf return 2^hi + fld %st(0) + fstpt (%rsp) + cmpw $0x7fff, 8(%rsp) + je 1f + fldt 32(%rsp) + fldt 16(%rsp) + # fpu stack: 2^hi x hi + # exact mult: x*log2e + fld %st(1) + # c = 0x1p32+1 + movq $0x41f0000000100000,%rax + pushq %rax + fldl (%rsp) + # xh = x - c*x + c*x + # xl = x - xh + fmulp + fld %st(2) + fsub %st(1), %st + faddp + fld %st(2) + fsub %st(1), %st + # yh = log2e_hi - c*log2e_hi + c*log2e_hi + movq $0x3ff7154765200000,%rax + pushq %rax + fldl (%rsp) + # fpu stack: 2^hi x hi xh xl yh + # lo = hi - xh*yh + xl*yh + fld %st(2) + fmul %st(1), %st + fsubp %st, %st(4) + fmul %st(1), %st + faddp %st, %st(3) + # yl = log2e_hi - yh + movq $0x3de705fc2f000000,%rax + pushq %rax + fldl (%rsp) + # fpu stack: 2^hi x lo xh xl yl + # lo += xh*yl + xl*yl + fmul %st, %st(2) + fmulp %st, %st(1) + fxch %st(2) + faddp + faddp + # log2e_lo + movq $0xbfbe,%rax + pushq %rax + movq $0x82f0025f2dc582ee,%rax + pushq %rax + fldt (%rsp) + addq $40,%rsp + # fpu stack: 2^hi x lo log2e_lo + # lo += log2e_lo*x + # return 2^hi + 2^hi (2^lo - 1) + fmulp %st, %st(2) + faddp + f2xm1 + fmul %st(1), %st + faddp +1: addq $48, %rsp + ret diff --git a/third_party/ulib/musl/src/math/x86_64/expm1l.s b/third_party/ulib/musl/src/math/x86_64/expm1l.s new file mode 100644 index 000000000..e773f0805 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/expm1l.s @@ -0,0 +1 @@ +# see exp2l.s diff --git a/third_party/ulib/musl/src/math/x86_64/fabs.s b/third_party/ulib/musl/src/math/x86_64/fabs.s new file mode 100644 index 000000000..5715005e3 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/fabs.s @@ -0,0 +1,9 @@ +.global fabs +.type fabs,@function +fabs: + xor %eax,%eax + dec %rax + shr %rax + movq %rax,%xmm1 + andpd %xmm1,%xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x86_64/fabsf.s b/third_party/ulib/musl/src/math/x86_64/fabsf.s new file mode 100644 index 000000000..501a1f175 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/fabsf.s @@ -0,0 +1,7 @@ +.global fabsf +.type fabsf,@function +fabsf: + mov $0x7fffffff,%eax + movq %rax,%xmm1 + andps %xmm1,%xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x86_64/fabsl.s b/third_party/ulib/musl/src/math/x86_64/fabsl.s new file mode 100644 index 000000000..4e7ab525e --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/fabsl.s @@ -0,0 +1,6 @@ +.global fabsl +.type fabsl,@function +fabsl: + fldt 8(%rsp) + fabs + ret diff --git a/third_party/ulib/musl/src/math/x86_64/floorl.s b/third_party/ulib/musl/src/math/x86_64/floorl.s new file mode 100644 index 000000000..80da46609 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/floorl.s @@ -0,0 +1,27 @@ +.global floorl +.type floorl,@function +floorl: + fldt 8(%rsp) +1: mov $0x7,%al +1: fstcw 8(%rsp) + mov 9(%rsp),%ah + mov %al,9(%rsp) + fldcw 8(%rsp) + frndint + mov %ah,9(%rsp) + fldcw 8(%rsp) + ret + +.global ceill +.type ceill,@function +ceill: + fldt 8(%rsp) + mov $0xb,%al + jmp 1b + +.global truncl +.type truncl,@function +truncl: + fldt 8(%rsp) + mov $0xf,%al + jmp 1b diff --git a/third_party/ulib/musl/src/math/x86_64/fmodl.s b/third_party/ulib/musl/src/math/x86_64/fmodl.s new file mode 100644 index 000000000..ea07b402f --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/fmodl.s @@ -0,0 +1,11 @@ +.global fmodl +.type fmodl,@function +fmodl: + fldt 24(%rsp) + fldt 8(%rsp) +1: fprem + fnstsw %ax + testb $4,%ah + jnz 1b + fstp %st(1) + ret diff --git a/third_party/ulib/musl/src/math/x86_64/llrint.s b/third_party/ulib/musl/src/math/x86_64/llrint.s new file mode 100644 index 000000000..bf4764983 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/llrint.s @@ -0,0 +1,5 @@ +.global llrint +.type llrint,@function +llrint: + cvtsd2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x86_64/llrintf.s b/third_party/ulib/musl/src/math/x86_64/llrintf.s new file mode 100644 index 000000000..d7204ac0c --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/llrintf.s @@ -0,0 +1,5 @@ +.global llrintf +.type llrintf,@function +llrintf: + cvtss2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x86_64/llrintl.s b/third_party/ulib/musl/src/math/x86_64/llrintl.s new file mode 100644 index 000000000..1ec0817d3 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/llrintl.s @@ -0,0 +1,7 @@ +.global llrintl +.type llrintl,@function +llrintl: + fldt 8(%rsp) + fistpll 8(%rsp) + mov 8(%rsp),%rax + ret diff --git a/third_party/ulib/musl/src/math/x86_64/log10l.s b/third_party/ulib/musl/src/math/x86_64/log10l.s new file mode 100644 index 000000000..48ea4af72 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/log10l.s @@ -0,0 +1,7 @@ +.global log10l +.type log10l,@function +log10l: + fldlg2 + fldt 8(%rsp) + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x86_64/log1pl.s b/third_party/ulib/musl/src/math/x86_64/log1pl.s new file mode 100644 index 000000000..955c9dbff --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/log1pl.s @@ -0,0 +1,15 @@ +.global log1pl +.type log1pl,@function +log1pl: + mov 14(%rsp),%eax + fldln2 + and $0x7fffffff,%eax + fldt 8(%rsp) + cmp $0x3ffd9400,%eax + ja 1f + fyl2xp1 + ret +1: fld1 + faddp + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x86_64/log2l.s b/third_party/ulib/musl/src/math/x86_64/log2l.s new file mode 100644 index 000000000..ba08b9fb6 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/log2l.s @@ -0,0 +1,7 @@ +.global log2l +.type log2l,@function +log2l: + fld1 + fldt 8(%rsp) + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x86_64/logl.s b/third_party/ulib/musl/src/math/x86_64/logl.s new file mode 100644 index 000000000..20dd1f819 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/logl.s @@ -0,0 +1,7 @@ +.global logl +.type logl,@function +logl: + fldln2 + fldt 8(%rsp) + fyl2x + ret diff --git a/third_party/ulib/musl/src/math/x86_64/lrint.s b/third_party/ulib/musl/src/math/x86_64/lrint.s new file mode 100644 index 000000000..15fc2454b --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/lrint.s @@ -0,0 +1,5 @@ +.global lrint +.type lrint,@function +lrint: + cvtsd2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x86_64/lrintf.s b/third_party/ulib/musl/src/math/x86_64/lrintf.s new file mode 100644 index 000000000..488423d21 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/lrintf.s @@ -0,0 +1,5 @@ +.global lrintf +.type lrintf,@function +lrintf: + cvtss2si %xmm0,%rax + ret diff --git a/third_party/ulib/musl/src/math/x86_64/lrintl.s b/third_party/ulib/musl/src/math/x86_64/lrintl.s new file mode 100644 index 000000000..d587b12b5 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/lrintl.s @@ -0,0 +1,7 @@ +.global lrintl +.type lrintl,@function +lrintl: + fldt 8(%rsp) + fistpll 8(%rsp) + mov 8(%rsp),%rax + ret diff --git a/third_party/ulib/musl/src/math/x86_64/remainderl.s b/third_party/ulib/musl/src/math/x86_64/remainderl.s new file mode 100644 index 000000000..cb3857b48 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/remainderl.s @@ -0,0 +1,11 @@ +.global remainderl +.type remainderl,@function +remainderl: + fldt 24(%rsp) + fldt 8(%rsp) +1: fprem1 + fnstsw %ax + testb $4,%ah + jnz 1b + fstp %st(1) + ret diff --git a/third_party/ulib/musl/src/math/x86_64/rintl.s b/third_party/ulib/musl/src/math/x86_64/rintl.s new file mode 100644 index 000000000..64e663cd2 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/rintl.s @@ -0,0 +1,6 @@ +.global rintl +.type rintl,@function +rintl: + fldt 8(%rsp) + frndint + ret diff --git a/third_party/ulib/musl/src/math/x86_64/sqrt.s b/third_party/ulib/musl/src/math/x86_64/sqrt.s new file mode 100644 index 000000000..d3c609f9f --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/sqrt.s @@ -0,0 +1,4 @@ +.global sqrt +.type sqrt,@function +sqrt: sqrtsd %xmm0, %xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x86_64/sqrtf.s b/third_party/ulib/musl/src/math/x86_64/sqrtf.s new file mode 100644 index 000000000..eec48c609 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/sqrtf.s @@ -0,0 +1,4 @@ +.global sqrtf +.type sqrtf,@function +sqrtf: sqrtss %xmm0, %xmm0 + ret diff --git a/third_party/ulib/musl/src/math/x86_64/sqrtl.s b/third_party/ulib/musl/src/math/x86_64/sqrtl.s new file mode 100644 index 000000000..23cd687d0 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/sqrtl.s @@ -0,0 +1,5 @@ +.global sqrtl +.type sqrtl,@function +sqrtl: fldt 8(%rsp) + fsqrt + ret diff --git a/third_party/ulib/musl/src/math/x86_64/truncl.s b/third_party/ulib/musl/src/math/x86_64/truncl.s new file mode 100644 index 000000000..f5cfa3b30 --- /dev/null +++ b/third_party/ulib/musl/src/math/x86_64/truncl.s @@ -0,0 +1 @@ +# see floorl.s diff --git a/third_party/ulib/musl/src/misc/BUILD.gn b/third_party/ulib/musl/src/misc/BUILD.gn new file mode 100644 index 000000000..2af4333b8 --- /dev/null +++ b/third_party/ulib/musl/src/misc/BUILD.gn @@ -0,0 +1,45 @@ +source_set("misc") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "a64l.c", + "basename.c", + "dirname.c", + "ffs.c", + "ffsl.c", + "ffsll.c", + "forkpty.c", + "get_current_dir_name.c", + "getauxval.c", + "getdomainname.c", + "gethostid.c", + "getopt.c", + "getopt_long.c", + "getpriority.c", + "getresgid.c", + "getresuid.c", + "getrlimit.c", + "getrusage.c", + "getsubopt.c", + "initgroups.c", + "ioctl.c", + "issetugid.c", + "lockf.c", + "login_tty.c", + "mntent.c", + "nftw.c", + "openpty.c", + "ptsname.c", + "pty.c", + "realpath.c", + "setdomainname.c", + "setpriority.c", + "setrlimit.c", + "syscall.c", + "syslog.c", + "uname.c", + "wordexp.c", + ] +} diff --git a/third_party/ulib/musl/src/misc/a64l.c b/third_party/ulib/musl/src/misc/a64l.c new file mode 100644 index 000000000..7d1df225c --- /dev/null +++ b/third_party/ulib/musl/src/misc/a64l.c @@ -0,0 +1,23 @@ +#include +#include +#include + +static const char digits[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +long a64l(const char* s) { + int e; + uint32_t x = 0; + for (e = 0; e < 36 && *s; e += 6, s++) + x |= (strchr(digits, *s) - digits) << e; + return x; +} + +char* l64a(long x0) { + static char s[7]; + char* p; + uint32_t x = x0; + for (p = s; x; p++, x >>= 6) + *p = digits[x & 63]; + *p = 0; + return s; +} diff --git a/third_party/ulib/musl/src/misc/basename.c b/third_party/ulib/musl/src/misc/basename.c new file mode 100644 index 000000000..1072628ab --- /dev/null +++ b/third_party/ulib/musl/src/misc/basename.c @@ -0,0 +1,16 @@ +#include "libc.h" +#include +#include + +char* basename(char* s) { + size_t i; + if (!s || !*s) return "."; + i = strlen(s) - 1; + for (; i && s[i] == '/'; i--) + s[i] = 0; + for (; i && s[i - 1] != '/'; i--) + ; + return s + i; +} + +weak_alias(basename, __xpg_basename); diff --git a/third_party/ulib/musl/src/misc/dirname.c b/third_party/ulib/musl/src/misc/dirname.c new file mode 100644 index 000000000..fac730997 --- /dev/null +++ b/third_party/ulib/musl/src/misc/dirname.c @@ -0,0 +1,16 @@ +#include +#include + +char* dirname(char* s) { + size_t i; + if (!s || !*s) return "."; + i = strlen(s) - 1; + for (; s[i] == '/'; i--) + if (!i) return "/"; + for (; s[i] != '/'; i--) + if (!i) return "."; + for (; s[i] == '/'; i--) + if (!i) return "/"; + s[i + 1] = 0; + return s; +} diff --git a/third_party/ulib/musl/src/misc/ffs.c b/third_party/ulib/musl/src/misc/ffs.c new file mode 100644 index 000000000..85a970c69 --- /dev/null +++ b/third_party/ulib/musl/src/misc/ffs.c @@ -0,0 +1,6 @@ +#include "atomic.h" +#include + +int ffs(int i) { + return i ? a_ctz_l(i) + 1 : 0; +} diff --git a/third_party/ulib/musl/src/misc/ffsl.c b/third_party/ulib/musl/src/misc/ffsl.c new file mode 100644 index 000000000..033192057 --- /dev/null +++ b/third_party/ulib/musl/src/misc/ffsl.c @@ -0,0 +1,6 @@ +#include "atomic.h" +#include + +int ffsl(long i) { + return i ? a_ctz_l(i) + 1 : 0; +} diff --git a/third_party/ulib/musl/src/misc/ffsll.c b/third_party/ulib/musl/src/misc/ffsll.c new file mode 100644 index 000000000..3d4bc9e72 --- /dev/null +++ b/third_party/ulib/musl/src/misc/ffsll.c @@ -0,0 +1,6 @@ +#include "atomic.h" +#include + +int ffsll(long long i) { + return i ? a_ctz_64(i) + 1 : 0; +} diff --git a/third_party/ulib/musl/src/misc/forkpty.c b/third_party/ulib/musl/src/misc/forkpty.c new file mode 100644 index 000000000..2c9352190 --- /dev/null +++ b/third_party/ulib/musl/src/misc/forkpty.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +int forkpty(int* pm, char* name, const struct termios* tio, const struct winsize* ws) { + int m, s, ec = 0, p[2], cs; + pid_t pid = -1; + sigset_t set, oldset; + + if (openpty(&m, &s, name, tio, ws) < 0) return -1; + + sigfillset(&set); + pthread_sigmask(SIG_BLOCK, &set, &oldset); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + if (pipe2(p, O_CLOEXEC)) { + close(s); + goto out; + } + + pid = fork(); + if (!pid) { + close(m); + close(p[0]); + if (login_tty(s)) { + write(p[1], &errno, sizeof errno); + _exit(127); + } + close(p[1]); + pthread_setcancelstate(cs, 0); + pthread_sigmask(SIG_SETMASK, &oldset, 0); + return 0; + } + close(s); + close(p[1]); + if (read(p[0], &ec, sizeof ec) > 0) { + int status; + waitpid(pid, &status, 0); + pid = -1; + errno = ec; + } + close(p[0]); + +out: + if (pid > 0) + *pm = m; + else + close(m); + + pthread_setcancelstate(cs, 0); + pthread_sigmask(SIG_SETMASK, &oldset, 0); + + return pid; +} diff --git a/third_party/ulib/musl/src/misc/get_current_dir_name.c b/third_party/ulib/musl/src/misc/get_current_dir_name.c new file mode 100644 index 000000000..3a880ba23 --- /dev/null +++ b/third_party/ulib/musl/src/misc/get_current_dir_name.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +char* get_current_dir_name(void) { + struct stat a, b; + char* res = getenv("PWD"); + if (res && *res && !stat(res, &a) && !stat(".", &b) && (a.st_dev == b.st_dev) && + (a.st_ino == b.st_ino)) + return strdup(res); + return getcwd(0, 0); +} diff --git a/third_party/ulib/musl/src/misc/getauxval.c b/third_party/ulib/musl/src/misc/getauxval.c new file mode 100644 index 000000000..9bc0e22c3 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getauxval.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include +#include + +unsigned long getauxval(unsigned long item) { + size_t* auxv = libc.auxv; + if (item == AT_SECURE) return libc.secure; + for (; *auxv; auxv += 2) + if (*auxv == item) return auxv[1]; + errno = ENOENT; + return 0; +} diff --git a/third_party/ulib/musl/src/misc/getdomainname.c b/third_party/ulib/musl/src/misc/getdomainname.c new file mode 100644 index 000000000..1f54285a3 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getdomainname.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +int getdomainname(char* name, size_t len) { + struct utsname temp; + uname(&temp); + if (!len || strlen(temp.domainname) >= len) { + errno = EINVAL; + return -1; + } + strcpy(name, temp.domainname); + return 0; +} diff --git a/third_party/ulib/musl/src/misc/gethostid.c b/third_party/ulib/musl/src/misc/gethostid.c new file mode 100644 index 000000000..1d2386356 --- /dev/null +++ b/third_party/ulib/musl/src/misc/gethostid.c @@ -0,0 +1,3 @@ +long gethostid(void) { + return 0; +} diff --git a/third_party/ulib/musl/src/misc/getopt.c b/third_party/ulib/musl/src/misc/getopt.c new file mode 100644 index 000000000..dfb266a64 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getopt.c @@ -0,0 +1,96 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include +#include +#include +#include + +char* optarg; +int optind = 1, opterr = 1, optopt, __optpos, __optreset = 0; + +#define optpos __optpos +weak_alias(__optreset, optreset); + +void __getopt_msg(const char* a, const char* b, const char* c, size_t l) { + FILE* f = stderr; + b = __lctrans_cur(b); + flockfile(f); + fputs(a, f) >= 0 && fwrite(b, strlen(b), 1, f) && fwrite(c, 1, l, f) == l&& putc('\n', f); + funlockfile(f); +} + +int getopt(int argc, char* const argv[], const char* optstring) { + int i; + wchar_t c, d; + int k, l; + char* optchar; + + if (!optind || __optreset) { + __optreset = 0; + __optpos = 0; + optind = 1; + } + + if (optind >= argc || !argv[optind]) return -1; + + if (argv[optind][0] != '-') { + if (optstring[0] == '-') { + optarg = argv[optind++]; + return 1; + } + return -1; + } + + if (!argv[optind][1]) return -1; + + if (argv[optind][1] == '-' && !argv[optind][2]) return optind++, -1; + + if (!optpos) optpos++; + if ((k = mbtowc(&c, argv[optind] + optpos, MB_LEN_MAX)) < 0) { + k = 1; + c = 0xfffd; /* replacement char */ + } + optchar = argv[optind] + optpos; + optopt = c; + optpos += k; + + if (!argv[optind][optpos]) { + optind++; + optpos = 0; + } + + if (optstring[0] == '-' || optstring[0] == '+') optstring++; + + i = 0; + d = 0; + do { + l = mbtowc(&d, optstring + i, MB_LEN_MAX); + if (l > 0) + i += l; + else + i++; + } while (l && d != c); + + if (d != c) { + if (optstring[0] != ':' && opterr) + __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); + return '?'; + } + if (optstring[i] == ':') { + if (optstring[i + 1] == ':') + optarg = 0; + else if (optind >= argc) { + if (optstring[0] == ':') return ':'; + if (opterr) __getopt_msg(argv[0], ": option requires an argument: ", optchar, k); + return '?'; + } + if (optstring[i + 1] != ':' || optpos) { + optarg = argv[optind++] + optpos; + optpos = 0; + } + } + return c; +} + +weak_alias(getopt, __posix_getopt); diff --git a/third_party/ulib/musl/src/misc/getopt_long.c b/third_party/ulib/musl/src/misc/getopt_long.c new file mode 100644 index 000000000..5ca6a6b06 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getopt_long.c @@ -0,0 +1,122 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +extern int __optpos, __optreset; + +static void permute(char* const* argv, int dest, int src) { + char** av = (char**)argv; + char* tmp = av[src]; + int i; + for (i = src; i > dest; i--) + av[i] = av[i - 1]; + av[dest] = tmp; +} + +void __getopt_msg(const char*, const char*, const char*, size_t); + +static int __getopt_long_core(int argc, char* const* argv, const char* optstring, + const struct option* longopts, int* idx, int longonly); + +static int __getopt_long(int argc, char* const* argv, const char* optstring, + const struct option* longopts, int* idx, int longonly) { + int ret, skipped, resumed; + if (!optind || __optreset) { + __optreset = 0; + __optpos = 0; + optind = 1; + } + if (optind >= argc || !argv[optind]) return -1; + skipped = optind; + if (optstring[0] != '+' && optstring[0] != '-') { + int i; + for (i = optind;; i++) { + if (i >= argc || !argv[i]) return -1; + if (argv[i][0] == '-' && argv[i][1]) break; + } + optind = i; + } + resumed = optind; + ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly); + if (resumed > skipped) { + int i, cnt = optind - resumed; + for (i = 0; i < cnt; i++) + permute(argv, skipped, optind - 1); + optind = skipped + cnt; + } + return ret; +} + +static int __getopt_long_core(int argc, char* const* argv, const char* optstring, + const struct option* longopts, int* idx, int longonly) { + optarg = 0; + if (longopts && argv[optind][0] == '-' && + ((longonly && argv[optind][1]) || (argv[optind][1] == '-' && argv[optind][2]))) { + int colon = optstring[optstring[0] == '+' || optstring[0] == '-'] == ':'; + int i, cnt, match; + char* opt; + for (cnt = i = 0; longopts[i].name; i++) { + const char* name = longopts[i].name; + opt = argv[optind] + 1; + if (*opt == '-') opt++; + for (; *name && *name == *opt; name++, opt++) + ; + if (*opt && *opt != '=') continue; + match = i; + if (!*name) { + cnt = 1; + break; + } + cnt++; + } + if (cnt == 1) { + i = match; + optind++; + optopt = longopts[i].val; + if (*opt == '=') { + if (!longopts[i].has_arg) { + if (colon || !opterr) return '?'; + __getopt_msg(argv[0], ": option does not take an argument: ", longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optarg = opt + 1; + } else if (longopts[i].has_arg == required_argument) { + if (!(optarg = argv[optind])) { + if (colon) return ':'; + if (!opterr) return '?'; + __getopt_msg(argv[0], ": option requires an argument: ", longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optind++; + } + if (idx) *idx = i; + if (longopts[i].flag) { + *longopts[i].flag = longopts[i].val; + return 0; + } + return longopts[i].val; + } + if (argv[optind][1] == '-') { + if (!colon && opterr) + __getopt_msg(argv[0], cnt ? ": option is ambiguous: " : ": unrecognized option: ", + argv[optind] + 2, strlen(argv[optind] + 2)); + optind++; + return '?'; + } + } + return getopt(argc, argv, optstring); +} + +int getopt_long(int argc, char* const* argv, const char* optstring, const struct option* longopts, + int* idx) { + return __getopt_long(argc, argv, optstring, longopts, idx, 0); +} + +int getopt_long_only(int argc, char* const* argv, const char* optstring, + const struct option* longopts, int* idx) { + return __getopt_long(argc, argv, optstring, longopts, idx, 1); +} diff --git a/third_party/ulib/musl/src/misc/getpriority.c b/third_party/ulib/musl/src/misc/getpriority.c new file mode 100644 index 000000000..310e47938 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getpriority.c @@ -0,0 +1,8 @@ +#include "syscall.h" +#include + +int getpriority(int which, id_t who) { + int ret = syscall(SYS_getpriority, which, who); + if (ret < 0) return ret; + return 20 - ret; +} diff --git a/third_party/ulib/musl/src/misc/getresgid.c b/third_party/ulib/musl/src/misc/getresgid.c new file mode 100644 index 000000000..7c694f236 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getresgid.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) { + return syscall(SYS_getresgid, rgid, egid, sgid); +} diff --git a/third_party/ulib/musl/src/misc/getresuid.c b/third_party/ulib/musl/src/misc/getresuid.c new file mode 100644 index 000000000..cc34dfdc1 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getresuid.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) { + return syscall(SYS_getresuid, ruid, euid, suid); +} diff --git a/third_party/ulib/musl/src/misc/getrlimit.c b/third_party/ulib/musl/src/misc/getrlimit.c new file mode 100644 index 000000000..0b338ea55 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getrlimit.c @@ -0,0 +1,27 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +#define FIX(x) \ + do { \ + if ((x) >= SYSCALL_RLIM_INFINITY) (x) = RLIM_INFINITY; \ + } while (0) + +int getrlimit(int resource, struct rlimit* rlim) { + unsigned long k_rlim[2]; + int ret = syscall(SYS_prlimit64, 0, resource, 0, rlim); + if (!ret) { + FIX(rlim->rlim_cur); + FIX(rlim->rlim_max); + } + if (!ret || errno != ENOSYS) return ret; + if (syscall(SYS_getrlimit, resource, k_rlim) < 0) return -1; + rlim->rlim_cur = k_rlim[0] == -1UL ? RLIM_INFINITY : k_rlim[0]; + rlim->rlim_max = k_rlim[1] == -1UL ? RLIM_INFINITY : k_rlim[1]; + FIX(rlim->rlim_cur); + FIX(rlim->rlim_max); + return 0; +} + +LFS64(getrlimit); diff --git a/third_party/ulib/musl/src/misc/getrusage.c b/third_party/ulib/musl/src/misc/getrusage.c new file mode 100644 index 000000000..293829e91 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getrusage.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int getrusage(int who, struct rusage* ru) { + return syscall(SYS_getrusage, who, ru); +} diff --git a/third_party/ulib/musl/src/misc/getsubopt.c b/third_party/ulib/musl/src/misc/getsubopt.c new file mode 100644 index 000000000..cc622fb76 --- /dev/null +++ b/third_party/ulib/musl/src/misc/getsubopt.c @@ -0,0 +1,25 @@ +#include +#include + +int getsubopt(char** opt, char* const* keys, char** val) { + char* s = *opt; + int i; + + *val = NULL; + *opt = strchr(s, ','); + if (*opt) + *(*opt)++ = 0; + else + *opt = s + strlen(s); + + for (i = 0; keys[i]; i++) { + size_t l = strlen(keys[i]); + if (strncmp(keys[i], s, l)) continue; + if (s[l] == '=') + *val = s + l + 1; + else if (s[l]) + continue; + return i; + } + return -1; +} diff --git a/third_party/ulib/musl/src/misc/initgroups.c b/third_party/ulib/musl/src/misc/initgroups.c new file mode 100644 index 000000000..c7dea70ca --- /dev/null +++ b/third_party/ulib/musl/src/misc/initgroups.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include +#include + +int initgroups(const char* user, gid_t gid) { + gid_t groups[NGROUPS_MAX]; + int count = NGROUPS_MAX; + if (getgrouplist(user, gid, groups, &count) < 0) return -1; + return setgroups(count, groups); +} diff --git a/third_party/ulib/musl/src/misc/ioctl.c b/third_party/ulib/musl/src/misc/ioctl.c new file mode 100644 index 000000000..4d15e78b9 --- /dev/null +++ b/third_party/ulib/musl/src/misc/ioctl.c @@ -0,0 +1,12 @@ +#include "syscall.h" +#include +#include + +int ioctl(int fd, int req, ...) { + void* arg; + va_list ap; + va_start(ap, req); + arg = va_arg(ap, void*); + va_end(ap); + return syscall(SYS_ioctl, fd, req, arg); +} diff --git a/third_party/ulib/musl/src/misc/issetugid.c b/third_party/ulib/musl/src/misc/issetugid.c new file mode 100644 index 000000000..f26915f69 --- /dev/null +++ b/third_party/ulib/musl/src/misc/issetugid.c @@ -0,0 +1,6 @@ +#include "libc.h" +#include + +int issetugid(void) { + return libc.secure; +} diff --git a/third_party/ulib/musl/src/misc/lockf.c b/third_party/ulib/musl/src/misc/lockf.c new file mode 100644 index 000000000..786cb833a --- /dev/null +++ b/third_party/ulib/musl/src/misc/lockf.c @@ -0,0 +1,28 @@ +#include "libc.h" +#include +#include +#include + +int lockf(int fd, int op, off_t size) { + struct flock l = { + .l_type = F_WRLCK, .l_whence = SEEK_CUR, .l_len = size, + }; + switch (op) { + case F_TEST: + l.l_type = F_RDLCK; + if (fcntl(fd, F_GETLK, &l) < 0) return -1; + if (l.l_type == F_UNLCK || l.l_pid == getpid()) return 0; + errno = EACCES; + return -1; + case F_ULOCK: + l.l_type = F_UNLCK; + case F_TLOCK: + return fcntl(fd, F_SETLK, &l); + case F_LOCK: + return fcntl(fd, F_SETLKW, &l); + } + errno = EINVAL; + return -1; +} + +LFS64(lockf); diff --git a/third_party/ulib/musl/src/misc/login_tty.c b/third_party/ulib/musl/src/misc/login_tty.c new file mode 100644 index 000000000..cd9a903e0 --- /dev/null +++ b/third_party/ulib/musl/src/misc/login_tty.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int login_tty(int fd) { + setsid(); + if (ioctl(fd, TIOCSCTTY, (char*)0)) return -1; + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) close(fd); + return 0; +} diff --git a/third_party/ulib/musl/src/misc/mntent.c b/third_party/ulib/musl/src/misc/mntent.c new file mode 100644 index 000000000..320b6e2cf --- /dev/null +++ b/third_party/ulib/musl/src/misc/mntent.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +FILE* setmntent(const char* name, const char* mode) { + return fopen(name, mode); +} + +int endmntent(FILE* f) { + if (f) fclose(f); + return 1; +} + +struct mntent* getmntent_r(FILE* f, struct mntent* mnt, char* linebuf, int buflen) { + int cnt, n[8]; + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + fgets(linebuf, buflen, f); + if (feof(f) || ferror(f)) return 0; + if (!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return 0; + } + cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", n, n + 1, n + 2, n + 3, + n + 4, n + 5, n + 6, n + 7, &mnt->mnt_freq, &mnt->mnt_passno); + } while (cnt < 2 || linebuf[n[0]] == '#'); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf + n[0]; + mnt->mnt_dir = linebuf + n[2]; + mnt->mnt_type = linebuf + n[4]; + mnt->mnt_opts = linebuf + n[6]; + + return mnt; +} + +struct mntent* getmntent(FILE* f) { + static char linebuf[256]; + static struct mntent mnt; + return getmntent_r(f, &mnt, linebuf, sizeof linebuf); +} + +int addmntent(FILE* f, const struct mntent* mnt) { + if (fseek(f, 0, SEEK_END)) return 1; + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, + mnt->mnt_opts, mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +char* hasmntopt(const struct mntent* mnt, const char* opt) { + return strstr(mnt->mnt_opts, opt); +} diff --git a/third_party/ulib/musl/src/misc/nftw.c b/third_party/ulib/musl/src/misc/nftw.c new file mode 100644 index 000000000..2e554eaf5 --- /dev/null +++ b/third_party/ulib/musl/src/misc/nftw.c @@ -0,0 +1,124 @@ +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include +#include + +struct history { + struct history* chain; + dev_t dev; + ino_t ino; + int level; + int base; +}; + +#undef dirfd +#define dirfd(d) (*(int*)d) + +static int do_nftw(char* path, int (*fn)(const char*, const struct stat*, int, struct FTW*), + int fd_limit, int flags, struct history* h) { + size_t l = strlen(path), j = l && path[l - 1] == '/' ? l - 1 : l; + struct stat st; + struct history new; + int type; + int r; + struct FTW lev; + char* name; + + if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { + if (!(flags & FTW_PHYS) && errno == ENOENT && !lstat(path, &st)) + type = FTW_SLN; + else if (errno != EACCES) + return -1; + else + type = FTW_NS; + } else if (S_ISDIR(st.st_mode)) { + if (access(path, R_OK) < 0) + type = FTW_DNR; + else if (flags & FTW_DEPTH) + type = FTW_DP; + else + type = FTW_D; + } else if (S_ISLNK(st.st_mode)) { + if (flags & FTW_PHYS) + type = FTW_SL; + else + type = FTW_SLN; + } else { + type = FTW_F; + } + + if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) return 0; + + new.chain = h; + new.dev = st.st_dev; + new.ino = st.st_ino; + new.level = h ? h->level + 1 : 0; + new.base = l + 1; + + lev.level = new.level; + lev.base = h ? h->base : (name = strrchr(path, '/')) ? name - path : 0; + + if (!(flags & FTW_DEPTH) && (r = fn(path, &st, type, &lev))) return r; + + for (; h; h = h->chain) + if (h->dev == st.st_dev && h->ino == st.st_ino) return 0; + + if ((type == FTW_D || type == FTW_DP) && fd_limit) { + DIR* d = opendir(path); + if (d) { + struct dirent* de; + while ((de = readdir(d))) { + if (de->d_name[0] == '.' && + (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))) + continue; + if (strlen(de->d_name) >= PATH_MAX - l) { + errno = ENAMETOOLONG; + closedir(d); + return -1; + } + path[j] = '/'; + strcpy(path + j + 1, de->d_name); + if ((r = do_nftw(path, fn, fd_limit - 1, flags, &new))) { + closedir(d); + return r; + } + } + closedir(d); + } else if (errno != EACCES) { + return -1; + } + } + + path[l] = 0; + if ((flags & FTW_DEPTH) && (r = fn(path, &st, type, &lev))) return r; + + return 0; +} + +int nftw(const char* path, int (*fn)(const char*, const struct stat*, int, struct FTW*), + int fd_limit, int flags) { + int r, cs; + size_t l; + char pathbuf[PATH_MAX + 1]; + + if (fd_limit <= 0) return 0; + + l = strlen(path); + if (l > PATH_MAX) { + errno = ENAMETOOLONG; + return -1; + } + memcpy(pathbuf, path, l + 1); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + r = do_nftw(pathbuf, fn, fd_limit, flags, NULL); + pthread_setcancelstate(cs, 0); + return r; +} + +LFS64(nftw); diff --git a/third_party/ulib/musl/src/misc/openpty.c b/third_party/ulib/musl/src/misc/openpty.c new file mode 100644 index 000000000..7f30c6213 --- /dev/null +++ b/third_party/ulib/musl/src/misc/openpty.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include + +/* Nonstandard, but vastly superior to the standard functions */ + +int openpty(int* pm, int* ps, char* name, const struct termios* tio, const struct winsize* ws) { + int m, s, n = 0, cs; + char buf[20]; + + m = open("/dev/ptmx", O_RDWR | O_NOCTTY); + if (m < 0) return -1; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + if (ioctl(m, TIOCSPTLCK, &n) || ioctl(m, TIOCGPTN, &n)) goto fail; + + if (!name) name = buf; + snprintf(name, sizeof buf, "/dev/pts/%d", n); + if ((s = open(name, O_RDWR | O_NOCTTY)) < 0) goto fail; + + if (tio) tcsetattr(s, TCSANOW, tio); + if (ws) ioctl(s, TIOCSWINSZ, ws); + + *pm = m; + *ps = s; + + pthread_setcancelstate(cs, 0); + return 0; +fail: + close(m); + pthread_setcancelstate(cs, 0); + return -1; +} diff --git a/third_party/ulib/musl/src/misc/ptsname.c b/third_party/ulib/musl/src/misc/ptsname.c new file mode 100644 index 000000000..b08d398b1 --- /dev/null +++ b/third_party/ulib/musl/src/misc/ptsname.c @@ -0,0 +1,14 @@ +#include +#include + +int __ptsname_r(int, char*, size_t); + +char* ptsname(int fd) { + static char buf[9 + sizeof(int) * 3 + 1]; + int err = __ptsname_r(fd, buf, sizeof buf); + if (err) { + errno = err; + return 0; + } + return buf; +} diff --git a/third_party/ulib/musl/src/misc/pty.c b/third_party/ulib/musl/src/misc/pty.c new file mode 100644 index 000000000..44b2b3eb2 --- /dev/null +++ b/third_party/ulib/musl/src/misc/pty.c @@ -0,0 +1,30 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include +#include + +int posix_openpt(int flags) { + return open("/dev/ptmx", flags); +} + +int grantpt(int fd) { + return 0; +} + +int unlockpt(int fd) { + int unlock = 0; + return ioctl(fd, TIOCSPTLCK, &unlock); +} + +int __ptsname_r(int fd, char* buf, size_t len) { + int pty, err; + if (!buf) len = 0; + if ((err = __syscall(SYS_ioctl, fd, TIOCGPTN, &pty))) return -err; + if (snprintf(buf, len, "/dev/pts/%d", pty) >= len) return ERANGE; + return 0; +} + +weak_alias(__ptsname_r, ptsname_r); diff --git a/third_party/ulib/musl/src/misc/realpath.c b/third_party/ulib/musl/src/misc/realpath.c new file mode 100644 index 000000000..6db6d228d --- /dev/null +++ b/third_party/ulib/musl/src/misc/realpath.c @@ -0,0 +1,44 @@ +#include "syscall.h" +#include +#include +#include +#include +#include +#include +#include + +void __procfdname(char*, unsigned); + +char* realpath(const char* restrict filename, char* restrict resolved) { + int fd; + ssize_t r; + struct stat st1, st2; + char buf[15 + 3 * sizeof(int)]; + char tmp[PATH_MAX]; + + if (!filename) { + errno = EINVAL; + return 0; + } + + fd = sys_open(filename, O_PATH | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) return 0; + __procfdname(buf, fd); + + r = readlink(buf, tmp, sizeof tmp - 1); + if (r < 0) goto err; + tmp[r] = 0; + + fstat(fd, &st1); + r = stat(tmp, &st2); + if (r < 0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { + if (!r) errno = ELOOP; + goto err; + } + + __syscall(SYS_close, fd); + return resolved ? strcpy(resolved, tmp) : strdup(tmp); +err: + __syscall(SYS_close, fd); + return 0; +} diff --git a/third_party/ulib/musl/src/misc/setdomainname.c b/third_party/ulib/musl/src/misc/setdomainname.c new file mode 100644 index 000000000..7cc384dc4 --- /dev/null +++ b/third_party/ulib/musl/src/misc/setdomainname.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int setdomainname(const char* name, size_t len) { + return syscall(SYS_setdomainname, name, len); +} diff --git a/third_party/ulib/musl/src/misc/setpriority.c b/third_party/ulib/musl/src/misc/setpriority.c new file mode 100644 index 000000000..6f2553f21 --- /dev/null +++ b/third_party/ulib/musl/src/misc/setpriority.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int setpriority(int which, id_t who, int prio) { + return syscall(SYS_setpriority, which, who, prio); +} diff --git a/third_party/ulib/musl/src/misc/setrlimit.c b/third_party/ulib/musl/src/misc/setrlimit.c new file mode 100644 index 000000000..50d2a9e5e --- /dev/null +++ b/third_party/ulib/musl/src/misc/setrlimit.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include + +int setrlimit(int resource, const struct rlimit* rlim) { + // TODO(kulakowski) Implement fake rlimit. + return -1; +} + +LFS64(setrlimit); diff --git a/third_party/ulib/musl/src/misc/syscall.c b/third_party/ulib/musl/src/misc/syscall.c new file mode 100644 index 000000000..0fd6915f5 --- /dev/null +++ b/third_party/ulib/musl/src/misc/syscall.c @@ -0,0 +1,18 @@ +#include "syscall.h" +#include + +#undef syscall + +long syscall(long n, ...) { + va_list ap; + syscall_arg_t a, b, c, d, e, f; + va_start(ap, n); + a = va_arg(ap, syscall_arg_t); + b = va_arg(ap, syscall_arg_t); + c = va_arg(ap, syscall_arg_t); + d = va_arg(ap, syscall_arg_t); + e = va_arg(ap, syscall_arg_t); + f = va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n, a, b, c, d, e, f)); +} diff --git a/third_party/ulib/musl/src/misc/syslog.c b/third_party/ulib/musl/src/misc/syslog.c new file mode 100644 index 000000000..7515ad569 --- /dev/null +++ b/third_party/ulib/musl/src/misc/syslog.c @@ -0,0 +1,137 @@ +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static mxr_mutex_t lock; +static char log_ident[32]; +static int log_opt; +static int log_facility = LOG_USER; +static int log_mask = 0xff; +static int log_fd = -1; + +int setlogmask(int maskpri) { + mxr_mutex_lock(&lock); + int ret = log_mask; + if (maskpri) log_mask = maskpri; + mxr_mutex_unlock(&lock); + return ret; +} + +static const struct { + short sun_family; + char sun_path[9]; +} log_addr = {AF_UNIX, "/dev/log"}; + +void closelog(void) { + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + mxr_mutex_lock(&lock); + close(log_fd); + log_fd = -1; + mxr_mutex_unlock(&lock); + pthread_setcancelstate(cs, 0); +} + +static void __openlog(void) { + log_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (log_fd >= 0) connect(log_fd, (void*)&log_addr, sizeof log_addr); +} + +void openlog(const char* ident, int opt, int facility) { + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + mxr_mutex_lock(&lock); + + if (ident) { + size_t n = strnlen(ident, sizeof log_ident - 1); + memcpy(log_ident, ident, n); + log_ident[n] = 0; + } else { + log_ident[0] = 0; + } + log_opt = opt; + log_facility = facility; + + if ((opt & LOG_NDELAY) && log_fd < 0) __openlog(); + + mxr_mutex_unlock(&lock); + pthread_setcancelstate(cs, 0); +} + +static int is_lost_conn(int e) { + return e == ECONNREFUSED || e == ECONNRESET || e == ENOTCONN || e == EPIPE; +} + +static void _vsyslog(int priority, const char* message, va_list ap) { + char timebuf[16]; + time_t now; + struct tm tm; + char buf[1024]; + int errno_save = errno; + int pid; + int l, l2; + int hlen; + int fd; + + if (log_fd < 0) __openlog(); + + if (!(priority & LOG_FACMASK)) priority |= log_facility; + + now = time(NULL); + gmtime_r(&now, &tm); + strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + + pid = (log_opt & LOG_PID) ? getpid() : 0; + l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", priority, timebuf, &hlen, log_ident, + "[" + !pid, pid, "]" + !pid); + errno = errno_save; + l2 = vsnprintf(buf + l, sizeof buf - l, message, ap); + if (l2 >= 0) { + if (l2 >= sizeof buf - l) + l = sizeof buf - 1; + else + l += l2; + if (buf[l - 1] != '\n') buf[l++] = '\n'; + if (send(log_fd, buf, l, 0) < 0 && + (!is_lost_conn(errno) || connect(log_fd, (void*)&log_addr, sizeof log_addr) < 0 || + send(log_fd, buf, l, 0) < 0) && + (log_opt & LOG_CONS)) { + fd = open("/dev/console", O_WRONLY | O_NOCTTY | O_CLOEXEC); + if (fd >= 0) { + dprintf(fd, "%.*s", l - hlen, buf + hlen); + close(fd); + } + } + if (log_opt & LOG_PERROR) dprintf(2, "%.*s", l - hlen, buf + hlen); + } +} + +void __vsyslog(int priority, const char* message, va_list ap) { + int cs; + if (!(log_mask & LOG_MASK(priority & 7)) || (priority & ~0x3ff)) return; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + mxr_mutex_lock(&lock); + _vsyslog(priority, message, ap); + mxr_mutex_unlock(&lock); + pthread_setcancelstate(cs, 0); +} + +void syslog(int priority, const char* message, ...) { + va_list ap; + va_start(ap, message); + __vsyslog(priority, message, ap); + va_end(ap); +} + +weak_alias(__vsyslog, vsyslog); diff --git a/third_party/ulib/musl/src/misc/uname.c b/third_party/ulib/musl/src/misc/uname.c new file mode 100644 index 000000000..5aed267f6 --- /dev/null +++ b/third_party/ulib/musl/src/misc/uname.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int uname(struct utsname* uts) { + return syscall(SYS_uname, uts); +} diff --git a/third_party/ulib/musl/src/misc/wordexp.c b/third_party/ulib/musl/src/misc/wordexp.c new file mode 100644 index 000000000..4eefd0b21 --- /dev/null +++ b/third_party/ulib/musl/src/misc/wordexp.c @@ -0,0 +1,193 @@ +#include "pthread_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void reap(pid_t pid) { + int status; + for (;;) { + if (waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) return; + } else { + if (WIFEXITED(status)) return; + } + } +} + +static char* getword(FILE* f) { + char* s = 0; + return getdelim(&s, (size_t[1]){0}, 0, f) < 0 ? 0 : s; +} + +static int do_wordexp(const char* s, wordexp_t* we, int flags) { + size_t i, l; + int sq = 0, dq = 0; + size_t np = 0; + char *w, **tmp; + char* redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null"; + int err = 0; + FILE* f; + size_t wc = 0; + char** wv = 0; + int p[2]; + pid_t pid; + sigset_t set; + + if (flags & WRDE_REUSE) wordfree(we); + + if (flags & WRDE_NOCMD) + for (i = 0; s[i]; i++) + switch (s[i]) { + case '\\': + if (!sq) i++; + break; + case '\'': + if (!dq) sq ^= 1; + break; + case '"': + if (!sq) dq ^= 1; + break; + case '(': + if (np) { + np++; + break; + } + case ')': + if (np) { + np--; + break; + } + case '\n': + case '|': + case '&': + case ';': + case '<': + case '>': + case '{': + case '}': + if (!(sq | dq | np)) return WRDE_BADCHAR; + break; + case '$': + if (sq) break; + if (s[i + 1] == '(' && s[i + 2] == '(') { + i += 2; + np += 2; + break; + } else if (s[i + 1] != '(') + break; + case '`': + if (sq) break; + return WRDE_CMDSUB; + } + + if (flags & WRDE_APPEND) { + wc = we->we_wordc; + wv = we->we_wordv; + } + + i = wc; + if (flags & WRDE_DOOFFS) { + if (we->we_offs > SIZE_MAX / sizeof(void*) / 4) goto nospace; + i += we->we_offs; + } else { + we->we_offs = 0; + } + + if (pipe2(p, O_CLOEXEC) < 0) goto nospace; + __block_all_sigs(&set); + pid = fork(); + __restore_sigs(&set); + if (pid < 0) { + close(p[0]); + close(p[1]); + goto nospace; + } + if (!pid) { + if (p[1] == 1) + fcntl(1, F_SETFD, 0); + else + dup2(p[1], 1); + execl("/bin/sh", "sh", "-c", "eval \"printf %s\\\\\\\\0 x $1 $2\"", "sh", s, redir, + (char*)0); + _exit(1); + } + close(p[1]); + + f = fdopen(p[0], "r"); + if (!f) { + close(p[0]); + kill(pid, SIGKILL); + reap(pid); + goto nospace; + } + + l = wv ? i + 1 : 0; + + free(getword(f)); + if (feof(f)) { + fclose(f); + reap(pid); + return WRDE_SYNTAX; + } + + while ((w = getword(f))) { + if (i + 1 >= l) { + l += l / 2 + 10; + tmp = realloc(wv, l * sizeof(char*)); + if (!tmp) break; + wv = tmp; + } + wv[i++] = w; + wv[i] = 0; + } + if (!feof(f)) err = WRDE_NOSPACE; + + fclose(f); + reap(pid); + + if (!wv) wv = calloc(i + 1, sizeof *wv); + + we->we_wordv = wv; + we->we_wordc = i; + + if (flags & WRDE_DOOFFS) { + if (wv) + for (i = we->we_offs; i; i--) + we->we_wordv[i - 1] = 0; + we->we_wordc -= we->we_offs; + } + return err; + +nospace: + if (!(flags & WRDE_APPEND)) { + we->we_wordc = 0; + we->we_wordv = 0; + } + return WRDE_NOSPACE; +} + +int wordexp(const char* restrict s, wordexp_t* restrict we, int flags) { + int r, cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + r = do_wordexp(s, we, flags); + pthread_setcancelstate(cs, 0); + return r; +} + +void wordfree(wordexp_t* we) { + size_t i; + if (!we->we_wordv) return; + for (i = 0; i < we->we_wordc; i++) + free(we->we_wordv[we->we_offs + i]); + free(we->we_wordv); + we->we_wordv = 0; + we->we_wordc = 0; +} diff --git a/third_party/ulib/musl/src/mman/BUILD.gn b/third_party/ulib/musl/src/mman/BUILD.gn new file mode 100644 index 000000000..1c16c5902 --- /dev/null +++ b/third_party/ulib/musl/src/mman/BUILD.gn @@ -0,0 +1,21 @@ +source_set("mman") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "madvise.c", + "mincore.c", + "mlock.c", + "mlockall.c", + "mmap.c", + "mprotect.c", + "mremap.c", + "msync.c", + "munlock.c", + "munlockall.c", + "munmap.c", + "posix_madvise.c", + "shm_open.c", + ] +} diff --git a/third_party/ulib/musl/src/mman/madvise.c b/third_party/ulib/musl/src/mman/madvise.c new file mode 100644 index 000000000..1dc1edc0d --- /dev/null +++ b/third_party/ulib/musl/src/mman/madvise.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include "syscall.h" +#include + +int __madvise(void* addr, size_t len, int advice) { + // TODO(kulakowski) Implement more mmap + return 0; +} + +weak_alias(__madvise, madvise); diff --git a/third_party/ulib/musl/src/mman/mincore.c b/third_party/ulib/musl/src/mman/mincore.c new file mode 100644 index 000000000..044a669a2 --- /dev/null +++ b/third_party/ulib/musl/src/mman/mincore.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int mincore(void* addr, size_t len, unsigned char* vec) { + return syscall(SYS_mincore, addr, len, vec); +} diff --git a/third_party/ulib/musl/src/mman/mlock.c b/third_party/ulib/musl/src/mman/mlock.c new file mode 100644 index 000000000..e16f4c636 --- /dev/null +++ b/third_party/ulib/musl/src/mman/mlock.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mlock(const void* addr, size_t len) { + return syscall(SYS_mlock, addr, len); +} diff --git a/third_party/ulib/musl/src/mman/mlockall.c b/third_party/ulib/musl/src/mman/mlockall.c new file mode 100644 index 000000000..d824aaec0 --- /dev/null +++ b/third_party/ulib/musl/src/mman/mlockall.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mlockall(int flags) { + return syscall(SYS_mlockall, flags); +} diff --git a/third_party/ulib/musl/src/mman/mmap.c b/third_party/ulib/musl/src/mman/mmap.c new file mode 100644 index 000000000..2baa8380f --- /dev/null +++ b/third_party/ulib/musl/src/mman/mmap.c @@ -0,0 +1,70 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include +#include +#include + +static void dummy(void) {} +weak_alias(dummy, __vm_wait); + +#define UNIT SYSCALL_MMAP2_UNIT +#define OFF_MASK ((-0x2000ULL << (8 * sizeof(long) - 1)) | (UNIT - 1)) + +static void* io_mmap(void* start, size_t len, int prot, int flags, int fd, off_t off) { + return (void*) MAP_FAILED; +} +weak_alias(io_mmap, __libc_io_mmap); + +void* __mmap(void* start, size_t len, int prot, int flags, int fd, off_t off) { + if (off & OFF_MASK) { + errno = EINVAL; + return MAP_FAILED; + } + if (len >= PTRDIFF_MAX) { + errno = ENOMEM; + return MAP_FAILED; + } + if (flags & MAP_FIXED) { + __vm_wait(); + } + + //printf("__mmap start %p, len %zu prot %u flags %u fd %d off %llx\n", start, len, prot, flags, fd, off); + + // look for a specific case that we can handle, from pthread_create + if ((flags & MAP_PRIVATE) && (flags & MAP_ANON) && (fd < 0)) { + // round up to page size + len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + mx_handle_t vmo = _magenta_vm_object_create(len); + if (vmo < 0) + return MAP_FAILED; + + // build magenta flags for this + uint32_t mx_flags = 0; + mx_flags |= (prot & PROT_READ) ? MX_VM_FLAG_PERM_READ : 0; + mx_flags |= (prot & PROT_WRITE) ? MX_VM_FLAG_PERM_WRITE : 0; + mx_flags |= (prot & PROT_EXEC) ? MX_VM_FLAG_PERM_EXECUTE : 0; + mx_flags |= (flags & MAP_FIXED) ? MX_VM_FLAG_FIXED : 0; + + mx_handle_t current_proc_handle = 0; /* TODO: get from TLS */ + + uintptr_t ptr = (uintptr_t)start; + mx_status_t status = _magenta_process_vm_map(current_proc_handle, vmo, 0, len, &ptr, mx_flags); + _magenta_handle_close(vmo); + if (status < 0) { + return MAP_FAILED; + } + + return (void *)ptr; + } else { + // let someone else get a shot at this + return __libc_io_mmap(start, len, prot, flags, fd, off); + } +} + +weak_alias(__mmap, mmap); + +LFS64(mmap); diff --git a/third_party/ulib/musl/src/mman/mprotect.c b/third_party/ulib/musl/src/mman/mprotect.c new file mode 100644 index 000000000..08b887aa0 --- /dev/null +++ b/third_party/ulib/musl/src/mman/mprotect.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include "syscall.h" +#include + +int __mprotect(void* addr, size_t len, int prot) { + size_t start, end; + start = (size_t)addr & -PAGE_SIZE; + end = (size_t)((char*)addr + len + PAGE_SIZE - 1) & -PAGE_SIZE; + return syscall(SYS_mprotect, start, end - start, prot); +} + +weak_alias(__mprotect, mprotect); diff --git a/third_party/ulib/musl/src/mman/mremap.c b/third_party/ulib/musl/src/mman/mremap.c new file mode 100644 index 000000000..bc470b556 --- /dev/null +++ b/third_party/ulib/musl/src/mman/mremap.c @@ -0,0 +1,33 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include +#include + +static void dummy(void) {} +weak_alias(dummy, __vm_wait); + +void* __mremap(void* old_addr, size_t old_len, size_t new_len, int flags, ...) { + va_list ap; + void* new_addr = 0; + + if (new_len >= PTRDIFF_MAX) { + errno = ENOMEM; + return MAP_FAILED; + } + + if (flags & MREMAP_FIXED) { + __vm_wait(); + va_start(ap, flags); + new_addr = va_arg(ap, void*); + va_end(ap); + } + + // TODO(kulakowski) Implement more mmap + return NULL; +} + +weak_alias(__mremap, mremap); diff --git a/third_party/ulib/musl/src/mman/msync.c b/third_party/ulib/musl/src/mman/msync.c new file mode 100644 index 000000000..efffac884 --- /dev/null +++ b/third_party/ulib/musl/src/mman/msync.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int msync(void* start, size_t len, int flags) { + return syscall(SYS_msync, start, len, flags); +} diff --git a/third_party/ulib/musl/src/mman/munlock.c b/third_party/ulib/musl/src/mman/munlock.c new file mode 100644 index 000000000..ce3457148 --- /dev/null +++ b/third_party/ulib/musl/src/mman/munlock.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int munlock(const void* addr, size_t len) { + return syscall(SYS_munlock, addr, len); +} diff --git a/third_party/ulib/musl/src/mman/munlockall.c b/third_party/ulib/musl/src/mman/munlockall.c new file mode 100644 index 000000000..270a512bf --- /dev/null +++ b/third_party/ulib/musl/src/mman/munlockall.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int munlockall(void) { + return syscall(SYS_munlockall); +} diff --git a/third_party/ulib/musl/src/mman/munmap.c b/third_party/ulib/musl/src/mman/munmap.c new file mode 100644 index 000000000..d119252d6 --- /dev/null +++ b/third_party/ulib/musl/src/mman/munmap.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "syscall.h" +#include + +static void dummy(void) {} +weak_alias(dummy, __vm_wait); + +int __munmap(void* start, size_t len) { + __vm_wait(); + // TODO(kulakowski) Implement more mmap + return 0; +} + +weak_alias(__munmap, munmap); diff --git a/third_party/ulib/musl/src/mman/posix_madvise.c b/third_party/ulib/musl/src/mman/posix_madvise.c new file mode 100644 index 000000000..06ea04f7f --- /dev/null +++ b/third_party/ulib/musl/src/mman/posix_madvise.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include + +int posix_madvise(void* addr, size_t len, int advice) { + if (advice == MADV_DONTNEED) return 0; + return -__syscall(SYS_madvise, addr, len, advice); +} diff --git a/third_party/ulib/musl/src/mman/shm_open.c b/third_party/ulib/musl/src/mman/shm_open.c new file mode 100644 index 000000000..3945b5336 --- /dev/null +++ b/third_party/ulib/musl/src/mman/shm_open.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include + +char* __strchrnul(const char*, int); + +char* __shm_mapname(const char* name, char* buf) { + char* p; + while (*name == '/') + name++; + if (*(p = __strchrnul(name, '/')) || p == name || + (p - name <= 2 && name[0] == '.' && p[-1] == '.')) { + errno = EINVAL; + return 0; + } + if (p - name > NAME_MAX) { + errno = ENAMETOOLONG; + return 0; + } + memcpy(buf, "/dev/shm/", 9); + memcpy(buf + 9, name, p - name + 1); + return buf; +} + +int shm_open(const char* name, int flag, mode_t mode) { + int cs; + char buf[NAME_MAX + 10]; + if (!(name = __shm_mapname(name, buf))) return -1; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + int fd = open(name, flag | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK, mode); + pthread_setcancelstate(cs, 0); + return fd; +} + +int shm_unlink(const char* name) { + char buf[NAME_MAX + 10]; + if (!(name = __shm_mapname(name, buf))) return -1; + return unlink(name); +} diff --git a/third_party/ulib/musl/src/mq/BUILD.gn b/third_party/ulib/musl/src/mq/BUILD.gn new file mode 100644 index 000000000..6b94ac7b1 --- /dev/null +++ b/third_party/ulib/musl/src/mq/BUILD.gn @@ -0,0 +1,18 @@ +source_set("mq") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "mq_close.c", + "mq_getattr.c", + "mq_notify.c", + "mq_open.c", + "mq_receive.c", + "mq_send.c", + "mq_setattr.c", + "mq_timedreceive.c", + "mq_timedsend.c", + "mq_unlink.c", + ] +} diff --git a/third_party/ulib/musl/src/mq/mq_close.c b/third_party/ulib/musl/src/mq/mq_close.c new file mode 100644 index 000000000..a292f4274 --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_close.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mq_close(mqd_t mqd) { + return syscall(SYS_close, mqd); +} diff --git a/third_party/ulib/musl/src/mq/mq_getattr.c b/third_party/ulib/musl/src/mq/mq_getattr.c new file mode 100644 index 000000000..ade73971c --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_getattr.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mq_getattr(mqd_t mqd, struct mq_attr* attr) { + return mq_setattr(mqd, 0, attr); +} diff --git a/third_party/ulib/musl/src/mq/mq_notify.c b/third_party/ulib/musl/src/mq/mq_notify.c new file mode 100644 index 000000000..5c6aa2977 --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_notify.c @@ -0,0 +1,71 @@ +#include "syscall.h" +#include +#include +#include +#include +#include +#include + +struct args { + pthread_barrier_t barrier; + int sock; + const struct sigevent* sev; +}; + +static void* start(void* p) { + struct args* args = p; + char buf[32]; + ssize_t n; + int s = args->sock; + void (*func)(union sigval) = args->sev->sigev_notify_function; + union sigval val = args->sev->sigev_value; + + pthread_barrier_wait(&args->barrier); + n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL | MSG_WAITALL); + close(s); + if (n == sizeof buf && buf[sizeof buf - 1] == 1) func(val); + return 0; +} + +int mq_notify(mqd_t mqd, const struct sigevent* sev) { + struct args args = {.sev = sev}; + pthread_attr_t attr; + pthread_t td; + int s; + struct sigevent sev2; + static const char zeros[32]; + + if (!sev || sev->sigev_notify != SIGEV_THREAD) return syscall(SYS_mq_notify, mqd, sev); + + s = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, 0); + if (s < 0) return -1; + args.sock = s; + + if (sev->sigev_notify_attributes) + attr = *sev->sigev_notify_attributes; + else + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_barrier_init(&args.barrier, 0, 2); + + if (pthread_create(&td, &attr, start, &args)) { + __syscall(SYS_close, s); + errno = EAGAIN; + return -1; + } + + pthread_barrier_wait(&args.barrier); + pthread_barrier_destroy(&args.barrier); + + sev2.sigev_notify = SIGEV_THREAD; + sev2.sigev_signo = s; + sev2.sigev_value.sival_ptr = (void*)&zeros; + + if (syscall(SYS_mq_notify, mqd, &sev2) < 0) { + pthread_cancel(td); + __syscall(SYS_close, s); + return -1; + } + + return 0; +} diff --git a/third_party/ulib/musl/src/mq/mq_open.c b/third_party/ulib/musl/src/mq/mq_open.c new file mode 100644 index 000000000..8d8fbbc96 --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_open.c @@ -0,0 +1,18 @@ +#include "syscall.h" +#include +#include +#include + +mqd_t mq_open(const char* name, int flags, ...) { + mode_t mode = 0; + struct mq_attr* attr = 0; + if (*name == '/') name++; + if (flags & O_CREAT) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + attr = va_arg(ap, struct mq_attr*); + va_end(ap); + } + return syscall(SYS_mq_open, name, flags, mode, attr); +} diff --git a/third_party/ulib/musl/src/mq/mq_receive.c b/third_party/ulib/musl/src/mq/mq_receive.c new file mode 100644 index 000000000..bf2782dfd --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_receive.c @@ -0,0 +1,5 @@ +#include + +ssize_t mq_receive(mqd_t mqd, char* msg, size_t len, unsigned* prio) { + return mq_timedreceive(mqd, msg, len, prio, 0); +} diff --git a/third_party/ulib/musl/src/mq/mq_send.c b/third_party/ulib/musl/src/mq/mq_send.c new file mode 100644 index 000000000..5341a633c --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_send.c @@ -0,0 +1,5 @@ +#include + +int mq_send(mqd_t mqd, const char* msg, size_t len, unsigned prio) { + return mq_timedsend(mqd, msg, len, prio, 0); +} diff --git a/third_party/ulib/musl/src/mq/mq_setattr.c b/third_party/ulib/musl/src/mq/mq_setattr.c new file mode 100644 index 000000000..024c1c21b --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_setattr.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mq_setattr(mqd_t mqd, const struct mq_attr* restrict new, struct mq_attr* restrict old) { + return syscall(SYS_mq_getsetattr, mqd, new, old); +} diff --git a/third_party/ulib/musl/src/mq/mq_timedreceive.c b/third_party/ulib/musl/src/mq/mq_timedreceive.c new file mode 100644 index 000000000..5e6495a21 --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_timedreceive.c @@ -0,0 +1,7 @@ +#include "syscall.h" +#include + +ssize_t mq_timedreceive(mqd_t mqd, char* restrict msg, size_t len, unsigned* restrict prio, + const struct timespec* restrict at) { + return syscall(SYS_mq_timedreceive, mqd, msg, len, prio, at); +} diff --git a/third_party/ulib/musl/src/mq/mq_timedsend.c b/third_party/ulib/musl/src/mq/mq_timedsend.c new file mode 100644 index 000000000..001f4bb39 --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_timedsend.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mq_timedsend(mqd_t mqd, const char* msg, size_t len, unsigned prio, const struct timespec* at) { + return syscall(SYS_mq_timedsend, mqd, msg, len, prio, at); +} diff --git a/third_party/ulib/musl/src/mq/mq_unlink.c b/third_party/ulib/musl/src/mq/mq_unlink.c new file mode 100644 index 000000000..e9939da95 --- /dev/null +++ b/third_party/ulib/musl/src/mq/mq_unlink.c @@ -0,0 +1,15 @@ +#include "syscall.h" +#include +#include + +int mq_unlink(const char* name) { + int ret; + if (*name == '/') name++; + ret = __syscall(SYS_mq_unlink, name); + if (ret < 0) { + if (ret == -EPERM) ret = -EACCES; + errno = -ret; + return -1; + } + return ret; +} diff --git a/third_party/ulib/musl/src/multibyte/BUILD.gn b/third_party/ulib/musl/src/multibyte/BUILD.gn new file mode 100644 index 000000000..2af048f7f --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/BUILD.gn @@ -0,0 +1,14 @@ +source_set("multibyte") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "c16rtomb.c", + "c32rtomb.c", + "mbrtoc16.c", + "mbrtoc32.c", + "mbstowcs.c", + "wcstombs.c", + ] +} diff --git a/third_party/ulib/musl/src/multibyte/c16rtomb.c b/third_party/ulib/musl/src/multibyte/c16rtomb.c new file mode 100644 index 000000000..7f48bd4bb --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/c16rtomb.c @@ -0,0 +1,36 @@ +#include +#include +#include + +size_t c16rtomb(char* restrict s, char16_t c16, mbstate_t* restrict ps) { + static unsigned internal_state; + if (!ps) ps = (void*)&internal_state; + unsigned* x = (unsigned*)ps; + wchar_t wc; + + if (!s) { + if (*x) goto ilseq; + return 1; + } + + if (!*x && c16 - 0xd800u < 0x400) { + *x = c16 - 0xd7c0 << 10; + return 0; + } + + if (*x) { + if (c16 - 0xdc00u >= 0x400) + goto ilseq; + else + wc = *x + c16 - 0xdc00; + *x = 0; + } else { + wc = c16; + } + return wcrtomb(s, wc, 0); + +ilseq: + *x = 0; + errno = EILSEQ; + return -1; +} diff --git a/third_party/ulib/musl/src/multibyte/c32rtomb.c b/third_party/ulib/musl/src/multibyte/c32rtomb.c new file mode 100644 index 000000000..e45d3b8d5 --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/c32rtomb.c @@ -0,0 +1,6 @@ +#include +#include + +size_t c32rtomb(char* restrict s, char32_t c32, mbstate_t* restrict ps) { + return wcrtomb(s, c32, ps); +} diff --git a/third_party/ulib/musl/src/multibyte/mbrtoc16.c b/third_party/ulib/musl/src/multibyte/mbrtoc16.c new file mode 100644 index 000000000..585752006 --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/mbrtoc16.c @@ -0,0 +1,29 @@ +#include +#include + +size_t mbrtoc16(char16_t* restrict pc16, const char* restrict s, size_t n, mbstate_t* restrict ps) { + static unsigned internal_state; + if (!ps) ps = (void*)&internal_state; + unsigned* pending = (unsigned*)ps; + + if (!s) return mbrtoc16(0, "", 1, ps); + + /* mbrtowc states for partial UTF-8 characters have the high bit set; + * we use nonzero states without high bit for pending surrogates. */ + if ((int)*pending > 0) { + if (pc16) *pc16 = *pending; + *pending = 0; + return -3; + } + + wchar_t wc; + size_t ret = mbrtowc(&wc, s, n, ps); + if (ret <= 4) { + if (wc >= 0x10000) { + *pending = (wc & 0x3ff) + 0xdc00; + wc = 0xd7c0 + (wc >> 10); + } + if (pc16) *pc16 = wc; + } + return ret; +} diff --git a/third_party/ulib/musl/src/multibyte/mbrtoc32.c b/third_party/ulib/musl/src/multibyte/mbrtoc32.c new file mode 100644 index 000000000..6a3f7d779 --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/mbrtoc32.c @@ -0,0 +1,12 @@ +#include +#include + +size_t mbrtoc32(char32_t* restrict pc32, const char* restrict s, size_t n, mbstate_t* restrict ps) { + static unsigned internal_state; + if (!ps) ps = (void*)&internal_state; + if (!s) return mbrtoc32(0, "", 1, ps); + wchar_t wc; + size_t ret = mbrtowc(&wc, s, n, ps); + if (ret <= 4 && pc32) *pc32 = wc; + return ret; +} diff --git a/third_party/ulib/musl/src/multibyte/mbstowcs.c b/third_party/ulib/musl/src/multibyte/mbstowcs.c new file mode 100644 index 000000000..6c3a8d5e3 --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/mbstowcs.c @@ -0,0 +1,6 @@ +#include +#include + +size_t mbstowcs(wchar_t* restrict ws, const char* restrict s, size_t wn) { + return mbsrtowcs(ws, (void*)&s, wn, 0); +} diff --git a/third_party/ulib/musl/src/multibyte/wcstombs.c b/third_party/ulib/musl/src/multibyte/wcstombs.c new file mode 100644 index 000000000..e43f27d17 --- /dev/null +++ b/third_party/ulib/musl/src/multibyte/wcstombs.c @@ -0,0 +1,6 @@ +#include +#include + +size_t wcstombs(char* restrict s, const wchar_t* restrict ws, size_t n) { + return wcsrtombs(s, &(const wchar_t*){ws}, n, 0); +} diff --git a/third_party/ulib/musl/src/network/BUILD.gn b/third_party/ulib/musl/src/network/BUILD.gn new file mode 100644 index 000000000..9ccfd2a59 --- /dev/null +++ b/third_party/ulib/musl/src/network/BUILD.gn @@ -0,0 +1,84 @@ +source_set("network") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "accept.c", + "accept4.c", + "bind.c", + "connect.c", + "dn_comp.c", + "dn_expand.c", + "dn_skipname.c", + "dns_parse.c", + "ent.c", + "ether.c", + "freeaddrinfo.c", + "gai_strerror.c", + "getaddrinfo.c", + "gethostbyaddr.c", + "gethostbyaddr_r.c", + "gethostbyname.c", + "gethostbyname2.c", + "gethostbyname2_r.c", + "gethostbyname_r.c", + "getifaddrs.c", + "getnameinfo.c", + "getpeername.c", + "getservbyname.c", + "getservbyname_r.c", + "getservbyport.c", + "getservbyport_r.c", + "getsockname.c", + "getsockopt.c", + "h_errno.c", + "herror.c", + "hstrerror.c", + "htonl.c", + "htons.c", + "if_freenameindex.c", + "if_indextoname.c", + "if_nameindex.c", + "if_nametoindex.c", + "in6addr_any.c", + "in6addr_loopback.c", + "inet_addr.c", + "inet_aton.c", + "inet_legacy.c", + "inet_ntoa.c", + "inet_ntop.c", + "inet_pton.c", + "listen.c", + "lookup_ipliteral.c", + "lookup_name.c", + "lookup_serv.c", + "netlink.c", + "netname.c", + "ns_parse.c", + "ntohl.c", + "ntohs.c", + "proto.c", + "recv.c", + "recvfrom.c", + "recvmmsg.c", + "recvmsg.c", + "res_init.c", + "res_mkquery.c", + "res_msend.c", + "res_query.c", + "res_querydomain.c", + "res_send.c", + "res_state.c", + "send.c", + "sendmmsg.c", + "sendmsg.c", + "sendto.c", + "serv.c", + "setsockopt.c", + "shutdown.c", + "sockatmark.c", + "socket.c", + "socketpair.c", + ] +} diff --git a/third_party/ulib/musl/src/network/accept.c b/third_party/ulib/musl/src/network/accept.c new file mode 100644 index 000000000..1b87677b8 --- /dev/null +++ b/third_party/ulib/musl/src/network/accept.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int accept(int fd, struct sockaddr* restrict addr, socklen_t* restrict len) { + return syscall(SYS_accept, fd, addr, len, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/accept4.c b/third_party/ulib/musl/src/network/accept4.c new file mode 100644 index 000000000..27b26c196 --- /dev/null +++ b/third_party/ulib/musl/src/network/accept4.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +int accept4(int fd, struct sockaddr* restrict addr, socklen_t* restrict len, int flg) { + if (!flg) return accept(fd, addr, len); + int ret = syscall(SYS_accept4, fd, addr, len, flg, 0, 0); + if (ret >= 0 || (errno != ENOSYS && errno != EINVAL)) return ret; + ret = accept(fd, addr, len); + if (ret < 0) return ret; + if (flg & SOCK_CLOEXEC) __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC); + if (flg & SOCK_NONBLOCK) __syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK); + return ret; +} diff --git a/third_party/ulib/musl/src/network/bind.c b/third_party/ulib/musl/src/network/bind.c new file mode 100644 index 000000000..c4edf54c3 --- /dev/null +++ b/third_party/ulib/musl/src/network/bind.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int bind(int fd, const struct sockaddr* addr, socklen_t len) { + return syscall(SYS_bind, fd, addr, len, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/connect.c b/third_party/ulib/musl/src/network/connect.c new file mode 100644 index 000000000..809b291c2 --- /dev/null +++ b/third_party/ulib/musl/src/network/connect.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int connect(int fd, const struct sockaddr* addr, socklen_t len) { + return syscall(SYS_connect, fd, addr, len, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/dn_comp.c b/third_party/ulib/musl/src/network/dn_comp.c new file mode 100644 index 000000000..97b0e20ac --- /dev/null +++ b/third_party/ulib/musl/src/network/dn_comp.c @@ -0,0 +1,108 @@ +#include "libc.h" +#include +#include + +/* RFC 1035 message compression */ + +/* label start offsets of a compressed domain name s */ +static int getoffs(short* offs, const unsigned char* base, const unsigned char* s) { + int i = 0; + for (;;) { + while (*s & 0xc0) { + if ((*s & 0xc0) != 0xc0) return 0; + s = base + ((s[0] & 0x3f) << 8 | s[1]); + } + if (!*s) return i; + if (s - base >= 0x4000) return 0; + offs[i++] = s - base; + s += *s + 1; + } +} + +/* label lengths of an ascii domain name s */ +static int getlens(unsigned char* lens, const char* s, int l) { + int i = 0, j = 0, k = 0; + for (;;) { + for (; j < l && s[j] != '.'; j++) + ; + if (j - k - 1u > 62) return 0; + lens[i++] = j - k; + if (j == l) return i; + k = ++j; + } +} + +/* longest suffix match of an ascii domain with a compressed domain name dn */ +static int match(int* offset, const unsigned char* base, const unsigned char* dn, const char* end, + const unsigned char* lens, int nlen) { + int l, o, m = 0; + short offs[128]; + int noff = getoffs(offs, base, dn); + if (!noff) return 0; + for (;;) { + l = lens[--nlen]; + o = offs[--noff]; + end -= l; + if (l != base[o] || memcmp(base + o + 1, end, l)) return m; + *offset = o; + m += l; + if (nlen) m++; + if (!nlen || !noff) return m; + end--; + } +} + +int __dn_comp(const char* src, unsigned char* dst, int space, unsigned char** dnptrs, + unsigned char** lastdnptr) { + int i, j, n, m = 0, offset, bestlen = 0, bestoff; + unsigned char lens[127]; + unsigned char** p; + const char* end; + size_t l = strnlen(src, 255); + if (l && src[l - 1] == '.') l--; + if (l > 253 || space <= 0) return -1; + if (!l) { + *dst = 0; + return 1; + } + end = src + l; + n = getlens(lens, src, l); + if (!n) return -1; + + p = dnptrs; + if (p && *p) + for (p++; *p; p++) { + m = match(&offset, *dnptrs, *p, end, lens, n); + if (m > bestlen) { + bestlen = m; + bestoff = offset; + if (m == l) break; + } + } + + /* encode unmatched part */ + if (space < l - bestlen + 2 + (bestlen - 1 < l - 1)) return -1; + memcpy(dst + 1, src, l - bestlen); + for (i = j = 0; i < l - bestlen; i += lens[j++] + 1) + dst[i] = lens[j]; + + /* add tail */ + if (bestlen) { + dst[i++] = 0xc0 | bestoff >> 8; + dst[i++] = bestoff; + } else + dst[i++] = 0; + + /* save dst pointer */ + if (i > 2 && lastdnptr && dnptrs && *dnptrs) { + while (*p) + p++; + if (p + 1 < lastdnptr) { + *p++ = dst; + *p = 0; + } + } + return i; +} + +weak_alias(__dn_comp, dn_comp); diff --git a/third_party/ulib/musl/src/network/dn_expand.c b/third_party/ulib/musl/src/network/dn_expand.c new file mode 100644 index 000000000..1fc1d9d0d --- /dev/null +++ b/third_party/ulib/musl/src/network/dn_expand.c @@ -0,0 +1,35 @@ +#include "libc.h" +#include + +int __dn_expand(const unsigned char* base, const unsigned char* end, const unsigned char* src, + char* dest, int space) { + const unsigned char* p = src; + char *dend, *dbegin = dest; + int len = -1, i, j; + if (p == end || space <= 0) return -1; + dend = dest + (space > 254 ? 254 : space); + /* detect reference loop using an iteration counter */ + for (i = 0; i < end - base; i += 2) { + /* loop invariants: p= end - base) return -1; + p = base + j; + } else if (*p) { + if (dest != dbegin) *dest++ = '.'; + j = *p++; + if (j >= end - p || j >= dend - dest) return -1; + while (j--) + *dest++ = *p++; + } else { + *dest = 0; + if (len < 0) len = p + 1 - src; + return len; + } + } + return -1; +} + +weak_alias(__dn_expand, dn_expand); diff --git a/third_party/ulib/musl/src/network/dn_skipname.c b/third_party/ulib/musl/src/network/dn_skipname.c new file mode 100644 index 000000000..37ff0d95f --- /dev/null +++ b/third_party/ulib/musl/src/network/dn_skipname.c @@ -0,0 +1,14 @@ +#include + +int dn_skipname(const unsigned char* s, const unsigned char* end) { + const unsigned char* p; + for (p = s; p < end; p++) + if (!*p) + return p - s + 1; + else if (*p >= 192) + if (p + 1 < end) + return p - s + 2; + else + break; + return -1; +} diff --git a/third_party/ulib/musl/src/network/dns_parse.c b/third_party/ulib/musl/src/network/dns_parse.c new file mode 100644 index 000000000..1a2556897 --- /dev/null +++ b/third_party/ulib/musl/src/network/dns_parse.c @@ -0,0 +1,32 @@ +#include + +int __dns_parse(const unsigned char* r, int rlen, + int (*callback)(void*, int, const void*, int, const void*), void* ctx) { + int qdcount, ancount; + const unsigned char* p; + int len; + + if (rlen < 12) return -1; + if ((r[3] & 15)) return 0; + p = r + 12; + qdcount = r[4] * 256 + r[5]; + ancount = r[6] * 256 + r[7]; + if (qdcount + ancount > 64) return -1; + while (qdcount--) { + while (p - r < rlen && *p - 1U < 127) + p++; + if (*p > 193 || (*p == 193 && p[1] > 254) || p > r + rlen - 6) return -1; + p += 5 + !!*p; + } + while (ancount--) { + while (p - r < rlen && *p - 1U < 127) + p++; + if (*p > 193 || (*p == 193 && p[1] > 254) || p > r + rlen - 6) return -1; + p += 1 + !!*p; + len = p[8] * 256 + p[9]; + if (p + len > r + rlen) return -1; + if (callback(ctx, p[1], p + 10, len, r) < 0) return -1; + p += 10 + len; + } + return 0; +} diff --git a/third_party/ulib/musl/src/network/ent.c b/third_party/ulib/musl/src/network/ent.c new file mode 100644 index 000000000..7d8881aaa --- /dev/null +++ b/third_party/ulib/musl/src/network/ent.c @@ -0,0 +1,13 @@ +#include "libc.h" + +void sethostent(int x) {} + +void* gethostent(void) { + return 0; +} + +void endhostent(void) {} + +weak_alias(sethostent, setnetent); +weak_alias(gethostent, getnetent); +weak_alias(endhostent, endnetent); diff --git a/third_party/ulib/musl/src/network/ether.c b/third_party/ulib/musl/src/network/ether.c new file mode 100644 index 000000000..4287f8eb1 --- /dev/null +++ b/third_party/ulib/musl/src/network/ether.c @@ -0,0 +1,55 @@ +#include +#include +#include + +struct ether_addr* ether_aton_r(const char* x, struct ether_addr* p_a) { + struct ether_addr a; + char* y; + for (int ii = 0; ii < 6; ii++) { + unsigned long int n; + if (ii != 0) { + if (x[0] != ':') + return 0; /* bad format */ + else + x++; + } + n = strtoul(x, &y, 16); + x = y; + if (n > 0xFF) return 0; /* bad byte */ + a.ether_addr_octet[ii] = n; + } + if (x[0] != 0) return 0; /* bad format */ + *p_a = a; + return p_a; +} + +struct ether_addr* ether_aton(const char* x) { + static struct ether_addr a; + return ether_aton_r(x, &a); +} + +char* ether_ntoa_r(const struct ether_addr* p_a, char* x) { + char* y; + y = x; + for (int ii = 0; ii < 6; ii++) { + x += sprintf(x, ii == 0 ? "%.2X" : ":%.2X", p_a->ether_addr_octet[ii]); + } + return y; +} + +char* ether_ntoa(const struct ether_addr* p_a) { + static char x[18]; + return ether_ntoa_r(p_a, x); +} + +int ether_line(const char* l, struct ether_addr* e, char* hostname) { + return -1; +} + +int ether_ntohost(char* hostname, const struct ether_addr* e) { + return -1; +} + +int ether_hostton(const char* hostname, struct ether_addr* e) { + return -1; +} diff --git a/third_party/ulib/musl/src/network/freeaddrinfo.c b/third_party/ulib/musl/src/network/freeaddrinfo.c new file mode 100644 index 000000000..b9b5693b3 --- /dev/null +++ b/third_party/ulib/musl/src/network/freeaddrinfo.c @@ -0,0 +1,6 @@ +#include +#include + +void freeaddrinfo(struct addrinfo* p) { + free(p); +} diff --git a/third_party/ulib/musl/src/network/gai_strerror.c b/third_party/ulib/musl/src/network/gai_strerror.c new file mode 100644 index 000000000..d606c5275 --- /dev/null +++ b/third_party/ulib/musl/src/network/gai_strerror.c @@ -0,0 +1,25 @@ +#include "locale_impl.h" +#include + +static const char msgs[] = "Invalid flags\0" + "Name does not resolve\0" + "Try again\0" + "Non-recoverable error\0" + "Unknown error\0" + "Unrecognized address family or invalid length\0" + "Unrecognized socket type\0" + "Unrecognized service\0" + "Unknown error\0" + "Out of memory\0" + "System error\0" + "Overflow\0" + "\0Unknown error"; + +const char* gai_strerror(int ecode) { + const char* s; + for (s = msgs, ecode++; ecode && *s; ecode++, s++) + for (; *s; s++) + ; + if (!*s) s++; + return LCTRANS_CUR(s); +} diff --git a/third_party/ulib/musl/src/network/getaddrinfo.c b/third_party/ulib/musl/src/network/getaddrinfo.c new file mode 100644 index 000000000..f7f137891 --- /dev/null +++ b/third_party/ulib/musl/src/network/getaddrinfo.c @@ -0,0 +1,91 @@ +#include "lookup.h" +#include +#include +#include +#include +#include + +int getaddrinfo(const char* restrict host, const char* restrict serv, + const struct addrinfo* restrict hint, struct addrinfo** restrict res) { + struct service ports[MAXSERVS]; + struct address addrs[MAXADDRS]; + char canon[256], *outcanon; + int nservs, naddrs, nais, canon_len, i, j, k; + int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; + struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + } * out; + + if (!host && !serv) return EAI_NONAME; + + if (hint) { + family = hint->ai_family; + flags = hint->ai_flags; + proto = hint->ai_protocol; + socktype = hint->ai_socktype; + + const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_V4MAPPED | AI_ALL | + AI_ADDRCONFIG | AI_NUMERICSERV; + if ((flags & mask) != flags) return EAI_BADFLAGS; + + switch (family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + break; + default: + return EAI_FAMILY; + } + } + + nservs = __lookup_serv(ports, serv, proto, socktype, flags); + if (nservs < 0) return nservs; + + naddrs = __lookup_name(addrs, canon, host, family, flags); + if (naddrs < 0) return naddrs; + + nais = nservs * naddrs; + canon_len = strlen(canon); + out = calloc(1, nais * sizeof(*out) + canon_len + 1); + if (!out) return EAI_MEMORY; + + if (canon_len) { + outcanon = (void*)&out[nais]; + memcpy(outcanon, canon, canon_len + 1); + } else { + outcanon = 0; + } + + for (k = i = 0; i < naddrs; i++) + for (j = 0; j < nservs; j++, k++) { + out[k].ai = (struct addrinfo){.ai_family = addrs[i].family, + .ai_socktype = ports[j].socktype, + .ai_protocol = ports[j].proto, + .ai_addrlen = addrs[i].family == AF_INET + ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6), + .ai_addr = (void*)&out[k].sa, + .ai_canonname = outcanon, + .ai_next = &out[k + 1].ai}; + switch (addrs[i].family) { + case AF_INET: + out[k].sa.sin.sin_family = AF_INET; + out[k].sa.sin.sin_port = htons(ports[j].port); + memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4); + break; + case AF_INET6: + out[k].sa.sin6.sin6_family = AF_INET6; + out[k].sa.sin6.sin6_port = htons(ports[j].port); + out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid; + memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16); + break; + } + } + out[nais - 1].ai.ai_next = 0; + *res = &out->ai; + return 0; +} diff --git a/third_party/ulib/musl/src/network/gethostbyaddr.c b/third_party/ulib/musl/src/network/gethostbyaddr.c new file mode 100644 index 000000000..de79e4f3b --- /dev/null +++ b/third_party/ulib/musl/src/network/gethostbyaddr.c @@ -0,0 +1,22 @@ +#define _GNU_SOURCE + +#include +#include +#include + +struct hostent* gethostbyaddr(const void* a, socklen_t l, int af) { + static struct hostent* h; + size_t size = 63; + struct hostent* res; + int err; + do { + free(h); + h = malloc(size += size + 1); + if (!h) { + h_errno = NO_RECOVERY; + return 0; + } + err = gethostbyaddr_r(a, l, af, h, (void*)(h + 1), size - sizeof *h, &res, &h_errno); + } while (err == ERANGE); + return err ? 0 : h; +} diff --git a/third_party/ulib/musl/src/network/gethostbyaddr_r.c b/third_party/ulib/musl/src/network/gethostbyaddr_r.c new file mode 100644 index 000000000..287335c78 --- /dev/null +++ b/third_party/ulib/musl/src/network/gethostbyaddr_r.c @@ -0,0 +1,71 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +int gethostbyaddr_r(const void* a, socklen_t l, int af, struct hostent* h, char* buf, size_t buflen, + struct hostent** res, int* err) { + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa = {.sin.sin_family = af}; + socklen_t sl = af == AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; + int i; + + *res = 0; + + /* Load address argument into sockaddr structure */ + if (af == AF_INET6 && l == 16) + memcpy(&sa.sin6.sin6_addr, a, 16); + else if (af == AF_INET && l == 4) + memcpy(&sa.sin.sin_addr, a, 4); + else { + *err = NO_RECOVERY; + return EINVAL; + } + + /* Align buffer and check for space for pointers and ip address */ + i = (uintptr_t)buf & sizeof(char*) - 1; + if (!i) i = sizeof(char*); + if (buflen <= 5 * sizeof(char*) - i + l) return ERANGE; + buf += sizeof(char*) - i; + buflen -= 5 * sizeof(char*) - i + l; + + h->h_addr_list = (void*)buf; + buf += 2 * sizeof(char*); + h->h_aliases = (void*)buf; + buf += 2 * sizeof(char*); + + h->h_addr_list[0] = buf; + memcpy(h->h_addr_list[0], a, l); + buf += l; + h->h_addr_list[1] = 0; + h->h_aliases[0] = buf; + h->h_aliases[1] = 0; + + switch (getnameinfo((void*)&sa, sl, buf, buflen, 0, 0, 0)) { + case EAI_AGAIN: + *err = TRY_AGAIN; + return EAGAIN; + case EAI_OVERFLOW: + return ERANGE; + default: + case EAI_MEMORY: + case EAI_SYSTEM: + case EAI_FAIL: + *err = NO_RECOVERY; + return errno; + case 0: + break; + } + + h->h_addrtype = af; + h->h_length = l; + h->h_name = h->h_aliases[0]; + *res = h; + return 0; +} diff --git a/third_party/ulib/musl/src/network/gethostbyname.c b/third_party/ulib/musl/src/network/gethostbyname.c new file mode 100644 index 000000000..4cce1f3f3 --- /dev/null +++ b/third_party/ulib/musl/src/network/gethostbyname.c @@ -0,0 +1,62 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include + +struct hostent* gethostbyname(const char* name) { + return gethostbyname2(name, AF_INET); +} + +#if 0 +struct hostent *gethostbyname(const char *name) +{ + static struct hostent h; + static char *h_aliases[3]; + static char h_canon[256]; + static char *h_addr_list[10]; + static char h_addr_data[10][4]; + static const struct addrinfo hint = { + .ai_family = AF_INET, .ai_flags = AI_CANONNAME + }; + struct addrinfo *ai, *p; + int i; + + switch (getaddrinfo(name, 0, &hint, &ai)) { + case EAI_NONAME: + h_errno = HOST_NOT_FOUND; + break; + case EAI_AGAIN: + h_errno = TRY_AGAIN; + break; + case EAI_FAIL: + h_errno = NO_RECOVERY; + break; + default: + case EAI_MEMORY: + case EAI_SYSTEM: + h_errno = NO_DATA; + break; + case 0: + break; + } + + strcpy(h_canon, ai->ai_canonname); + h.h_name = h_canon; + h.h_aliases = h_aliases; + h.h_aliases[0] = h_canon; + h.h_aliases[1] = strcmp(h_canon, name) ? (char *)name : 0; + h.h_length = 4; + h.h_addr_list = h_addr_list; + for (i=0, p=ai; iai_next) { + h.h_addr_list[i] = h_addr_data[i]; + memcpy(h.h_addr_list[i], + &((struct sockaddr_in *)p->ai_addr)->sin_addr, 4); + } + h.h_addr_list[i] = 0; + h.h_addrtype = AF_INET; + freeaddrinfo(ai); + return &h; +} +#endif diff --git a/third_party/ulib/musl/src/network/gethostbyname2.c b/third_party/ulib/musl/src/network/gethostbyname2.c new file mode 100644 index 000000000..c0e9ea62b --- /dev/null +++ b/third_party/ulib/musl/src/network/gethostbyname2.c @@ -0,0 +1,23 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include + +struct hostent* gethostbyname2(const char* name, int af) { + static struct hostent* h; + size_t size = 63; + struct hostent* res; + int err; + do { + free(h); + h = malloc(size += size + 1); + if (!h) { + h_errno = NO_RECOVERY; + return 0; + } + err = gethostbyname2_r(name, af, h, (void*)(h + 1), size - sizeof *h, &res, &h_errno); + } while (err == ERANGE); + return err ? 0 : h; +} diff --git a/third_party/ulib/musl/src/network/gethostbyname2_r.c b/third_party/ulib/musl/src/network/gethostbyname2_r.c new file mode 100644 index 000000000..aff6998e7 --- /dev/null +++ b/third_party/ulib/musl/src/network/gethostbyname2_r.c @@ -0,0 +1,81 @@ +#define _GNU_SOURCE + +#include "lookup.h" +#include +#include +#include +#include +#include +#include + +int gethostbyname2_r(const char* name, int af, struct hostent* h, char* buf, size_t buflen, + struct hostent** res, int* err) { + struct address addrs[MAXADDRS]; + char canon[256]; + int i, cnt; + size_t align, need; + + *res = 0; + cnt = __lookup_name(addrs, canon, name, af, AI_CANONNAME); + if (cnt < 0) switch (cnt) { + case EAI_NONAME: + *err = HOST_NOT_FOUND; + return ENOENT; + case EAI_AGAIN: + *err = TRY_AGAIN; + return EAGAIN; + default: + case EAI_FAIL: + *err = NO_RECOVERY; + return EBADMSG; + case EAI_MEMORY: + case EAI_SYSTEM: + *err = NO_RECOVERY; + return errno; + case 0: + break; + } + + h->h_addrtype = af; + h->h_length = af == AF_INET6 ? 16 : 4; + + /* Align buffer */ + align = -(uintptr_t)buf & sizeof(char*) - 1; + + need = 4 * sizeof(char*); + need += (cnt + 1) * (sizeof(char*) + h->h_length); + need += strlen(name) + 1; + need += strlen(canon) + 1; + need += align; + + if (need > buflen) return ERANGE; + + buf += align; + h->h_aliases = (void*)buf; + buf += 3 * sizeof(char*); + h->h_addr_list = (void*)buf; + buf += (cnt + 1) * sizeof(char*); + + h->h_name = h->h_aliases[0] = buf; + strcpy(h->h_name, canon); + buf += strlen(h->h_name) + 1; + + if (strcmp(h->h_name, name)) { + h->h_aliases[1] = buf; + strcpy(h->h_aliases[1], name); + buf += strlen(h->h_aliases[1]) + 1; + } else + h->h_aliases[1] = 0; + + h->h_aliases[2] = 0; + + for (i = 0; i < cnt; i++) { + h->h_addr_list[i] = (void*)buf; + buf += h->h_length; + memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length); + } + h->h_addr_list[i] = 0; + + *res = h; + return 0; +} diff --git a/third_party/ulib/musl/src/network/gethostbyname_r.c b/third_party/ulib/musl/src/network/gethostbyname_r.c new file mode 100644 index 000000000..d6ea69790 --- /dev/null +++ b/third_party/ulib/musl/src/network/gethostbyname_r.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE + +#include +#include + +int gethostbyname_r(const char* name, struct hostent* h, char* buf, size_t buflen, + struct hostent** res, int* err) { + return gethostbyname2_r(name, AF_INET, h, buf, buflen, res, err); +} diff --git a/third_party/ulib/musl/src/network/getifaddrs.c b/third_party/ulib/musl/src/network/getifaddrs.c new file mode 100644 index 000000000..ff35dea92 --- /dev/null +++ b/third_party/ulib/musl/src/network/getifaddrs.c @@ -0,0 +1,219 @@ +#define _GNU_SOURCE +#include "netlink.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define IFADDRS_HASH_SIZE 64 + +/* getifaddrs() reports hardware addresses with PF_PACKET that implies + * struct sockaddr_ll. But e.g. Infiniband socket address length is + * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct + * to extend ssl_addr - callers should be able to still use it. */ +struct sockaddr_ll_hack { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[24]; +}; + +union sockany { + struct sockaddr sa; + struct sockaddr_ll_hack ll; + struct sockaddr_in v4; + struct sockaddr_in6 v6; +}; + +struct ifaddrs_storage { + struct ifaddrs ifa; + struct ifaddrs_storage* hash_next; + union sockany addr, netmask, ifu; + unsigned int index; + char name[IFNAMSIZ + 1]; +}; + +struct ifaddrs_ctx { + struct ifaddrs_storage* first; + struct ifaddrs_storage* last; + struct ifaddrs_storage* hash[IFADDRS_HASH_SIZE]; +}; + +void freeifaddrs(struct ifaddrs* ifp) { + struct ifaddrs* n; + while (ifp) { + n = ifp->ifa_next; + free(ifp); + ifp = n; + } +} + +static void copy_addr(struct sockaddr** r, int af, union sockany* sa, void* addr, size_t addrlen, + int ifindex) { + uint8_t* dst; + int len; + + switch (af) { + case AF_INET: + dst = (uint8_t*)&sa->v4.sin_addr; + len = 4; + break; + case AF_INET6: + dst = (uint8_t*)&sa->v6.sin6_addr; + len = 16; + if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) + sa->v6.sin6_scope_id = ifindex; + break; + default: + return; + } + if (addrlen < len) return; + sa->sa.sa_family = af; + memcpy(dst, addr, len); + *r = &sa->sa; +} + +static void gen_netmask(struct sockaddr** r, int af, union sockany* sa, int prefixlen) { + uint8_t addr[16] = {0}; + int i; + + if (prefixlen > 8 * sizeof(addr)) prefixlen = 8 * sizeof(addr); + i = prefixlen / 8; + memset(addr, 0xff, i); + if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8)); + copy_addr(r, af, sa, addr, sizeof(addr), 0); +} + +static void copy_lladdr(struct sockaddr** r, union sockany* sa, void* addr, size_t addrlen, + int ifindex, unsigned short hatype) { + if (addrlen > sizeof(sa->ll.sll_addr)) return; + sa->ll.sll_family = AF_PACKET; + sa->ll.sll_ifindex = ifindex; + sa->ll.sll_hatype = hatype; + sa->ll.sll_halen = addrlen; + memcpy(sa->ll.sll_addr, addr, addrlen); + *r = &sa->sa; +} + +static int netlink_msg_to_ifaddr(void* pctx, struct nlmsghdr* h) { + struct ifaddrs_ctx* ctx = pctx; + struct ifaddrs_storage *ifs, *ifs0; + struct ifinfomsg* ifi = NLMSG_DATA(h); + struct ifaddrmsg* ifa = NLMSG_DATA(h); + struct rtattr* rta; + int stats_len = 0; + + if (h->nlmsg_type == RTM_NEWLINK) { + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != IFLA_STATS) continue; + stats_len = RTA_DATALEN(rta); + break; + } + } else { + for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next) + if (ifs0->index == ifa->ifa_index) break; + if (!ifs0) return 0; + } + + ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len); + if (ifs == 0) return -1; + + if (h->nlmsg_type == RTM_NEWLINK) { + ifs->index = ifi->ifi_index; + ifs->ifa.ifa_flags = ifi->ifi_flags; + + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + case IFLA_ADDRESS: + copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), + ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_BROADCAST: + copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), + ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_STATS: + ifs->ifa.ifa_data = (void*)(ifs + 1); + memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta)); + break; + } + } + if (ifs->ifa.ifa_name) { + unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE; + ifs->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ifs; + } + } else { + ifs->ifa.ifa_name = ifs0->ifa.ifa_name; + ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; + for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFA_ADDRESS: + /* If ifa_addr is already set we, received an IFA_LOCAL before + * so treat this as destination address */ + if (ifs->ifa.ifa_addr) + copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), + RTA_DATALEN(rta), ifa->ifa_index); + else + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), + RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_BROADCAST: + copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), + RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LOCAL: + /* If ifa_addr is set and we get IFA_LOCAL, assume we have + * a point-to-point network. Move address to correct field. */ + if (ifs->ifa.ifa_addr) { + ifs->ifu = ifs->addr; + ifs->ifa.ifa_dstaddr = &ifs->ifu.sa; + memset(&ifs->addr, 0, sizeof(ifs->addr)); + } + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), + RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LABEL: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + } + } + if (ifs->ifa.ifa_addr) + gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen); + } + + if (ifs->ifa.ifa_name) { + if (!ctx->first) ctx->first = ifs; + if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa; + ctx->last = ifs; + } else { + free(ifs); + } + return 0; +} + +int getifaddrs(struct ifaddrs** ifap) { + struct ifaddrs_ctx _ctx, *ctx = &_ctx; + int r; + memset(ctx, 0, sizeof *ctx); + r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx); + if (r == 0) + *ifap = &ctx->first->ifa; + else + freeifaddrs(&ctx->first->ifa); + return r; +} diff --git a/third_party/ulib/musl/src/network/getnameinfo.c b/third_party/ulib/musl/src/network/getnameinfo.c new file mode 100644 index 000000000..8352d6ee0 --- /dev/null +++ b/third_party/ulib/musl/src/network/getnameinfo.c @@ -0,0 +1,189 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int __dns_parse(const unsigned char*, int, int (*)(void*, int, const void*, int, const void*), + void*); +int __dn_expand(const unsigned char*, const unsigned char*, const unsigned char*, char*, int); +int __res_mkquery(int, const char*, int, int, const unsigned char*, int, const unsigned char*, + unsigned char*, int); +int __res_send(const unsigned char*, int, unsigned char*, int); + +#define PTR_MAX (64 + sizeof ".in-addr.arpa") +#define RR_PTR 12 + +static char* itoa(char* p, unsigned x) { + p += 3 * sizeof(int); + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +static void mkptr4(char* s, const unsigned char* ip) { + sprintf(s, "%d.%d.%d.%d.in-addr.arpa", ip[3], ip[2], ip[1], ip[0]); +} + +static void mkptr6(char* s, const unsigned char* ip) { + static const char xdigits[] = "0123456789abcdef"; + int i; + for (i = 15; i >= 0; i--) { + *s++ = xdigits[ip[i] & 15]; + *s++ = '.'; + *s++ = xdigits[ip[i] >> 4]; + *s++ = '.'; + } + strcpy(s, "ip6.arpa"); +} + +static void reverse_hosts(char* buf, const unsigned char* a, unsigned scopeid, int family) { + char line[512], *p, *z; + unsigned char _buf[1032], atmp[16]; + struct address iplit; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) return; + if (family == AF_INET) { + memcpy(atmp + 12, a, 4); + memcpy(atmp, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + a = atmp; + } + while (fgets(line, sizeof line, f)) { + if ((p = strchr(line, '#'))) *p++ = '\n', *p = 0; + + for (p = line; *p && !isspace(*p); p++) + ; + *p++ = 0; + if (__lookup_ipliteral(&iplit, line, AF_UNSPEC) <= 0) continue; + + if (iplit.family == AF_INET) { + memcpy(iplit.addr + 12, iplit.addr, 4); + memcpy(iplit.addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + iplit.scopeid = 0; + } + + if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid) continue; + + for (; *p && isspace(*p); p++) + ; + for (z = p; *z && !isspace(*z); z++) + ; + *z = 0; + if (z - p < 256) { + memcpy(buf, p, z - p + 1); + break; + } + } + __fclose_ca(f); +} + +static void reverse_services(char* buf, int port, int dgram) { + unsigned long svport; + char line[128], *p, *z; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) return; + while (fgets(line, sizeof line, f)) { + if ((p = strchr(line, '#'))) *p++ = '\n', *p = 0; + + for (p = line; *p && !isspace(*p); p++) + ; + if (!*p) continue; + *p++ = 0; + svport = strtoul(p, &z, 10); + + if (svport != port || z == p) continue; + if (dgram && strncmp(z, "/udp", 4)) continue; + if (!dgram && strncmp(z, "/tcp", 4)) continue; + if (p - line > 32) continue; + + memcpy(buf, line, p - line); + break; + } + __fclose_ca(f); +} + +static int dns_parse_callback(void* c, int rr, const void* data, int len, const void* packet) { + if (rr != RR_PTR) return 0; + if (__dn_expand(packet, (const unsigned char*)packet + 512, data, c, 256) <= 0) *(char*)c = 0; + return 0; +} + +int getnameinfo(const struct sockaddr* restrict sa, socklen_t sl, char* restrict node, + socklen_t nodelen, char* restrict serv, socklen_t servlen, int flags) { + char ptr[PTR_MAX]; + char buf[256], num[3 * sizeof(int) + 1]; + int af = sa->sa_family; + unsigned char* a; + unsigned scopeid; + + switch (af) { + case AF_INET: + a = (void*)&((struct sockaddr_in*)sa)->sin_addr; + if (sl < sizeof(struct sockaddr_in)) return EAI_FAMILY; + mkptr4(ptr, a); + scopeid = 0; + break; + case AF_INET6: + a = (void*)&((struct sockaddr_in6*)sa)->sin6_addr; + if (sl < sizeof(struct sockaddr_in6)) return EAI_FAMILY; + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12)) + mkptr6(ptr, a); + else + mkptr4(ptr, a + 12); + scopeid = ((struct sockaddr_in6*)sa)->sin6_scope_id; + break; + default: + return EAI_FAMILY; + } + + if (node && nodelen) { + buf[0] = 0; + if (!(flags & NI_NUMERICHOST)) { + reverse_hosts(buf, a, scopeid, af); + } + if (!*buf && !(flags & NI_NUMERICHOST)) { + unsigned char query[18 + PTR_MAX], reply[512]; + int qlen = __res_mkquery(0, ptr, 1, RR_PTR, 0, 0, 0, query, sizeof query); + int rlen = __res_send(query, qlen, reply, sizeof reply); + buf[0] = 0; + if (rlen > 0) __dns_parse(reply, rlen, dns_parse_callback, buf); + } + if (!*buf) { + if (flags & NI_NAMEREQD) return EAI_NONAME; + inet_ntop(af, a, buf, sizeof buf); + if (scopeid) { + char *p = 0, tmp[IF_NAMESIZE + 1]; + if (!(flags & NI_NUMERICSCOPE) && + (IN6_IS_ADDR_LINKLOCAL(a) || IN6_IS_ADDR_MC_LINKLOCAL(a))) + p = if_indextoname(scopeid, tmp + 1); + if (!p) p = itoa(num, scopeid); + *--p = '%'; + strcat(buf, p); + } + } + if (strlen(buf) >= nodelen) return EAI_OVERFLOW; + strcpy(node, buf); + } + + if (serv && servlen) { + char* p = buf; + int port = ntohs(((struct sockaddr_in*)sa)->sin_port); + buf[0] = 0; + if (!(flags & NI_NUMERICSERV)) reverse_services(buf, port, flags & NI_DGRAM); + if (!*p) p = itoa(num, port); + if (strlen(p) >= servlen) return EAI_OVERFLOW; + strcpy(serv, p); + } + + return 0; +} diff --git a/third_party/ulib/musl/src/network/getpeername.c b/third_party/ulib/musl/src/network/getpeername.c new file mode 100644 index 000000000..db76dad7f --- /dev/null +++ b/third_party/ulib/musl/src/network/getpeername.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int getpeername(int fd, struct sockaddr* restrict addr, socklen_t* restrict len) { + return syscall(SYS_getpeername, fd, addr, len, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/getservbyname.c b/third_party/ulib/musl/src/network/getservbyname.c new file mode 100644 index 000000000..5827b7aa4 --- /dev/null +++ b/third_party/ulib/musl/src/network/getservbyname.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include + +struct servent* getservbyname(const char* name, const char* prots) { + static struct servent se; + static char* buf[2]; + struct servent* res; + if (getservbyname_r(name, prots, &se, (void*)buf, sizeof buf, &res)) return 0; + return &se; +} diff --git a/third_party/ulib/musl/src/network/getservbyname_r.c b/third_party/ulib/musl/src/network/getservbyname_r.c new file mode 100644 index 000000000..82a3c2bab --- /dev/null +++ b/third_party/ulib/musl/src/network/getservbyname_r.c @@ -0,0 +1,54 @@ +#define _GNU_SOURCE +#include "lookup.h" +#include +#include +#include +#include +#include +#include + +#define ALIGN \ + (sizeof(struct { \ + char a; \ + char* b; \ + }) - \ + sizeof(char*)) + +int getservbyname_r(const char* name, const char* prots, struct servent* se, char* buf, + size_t buflen, struct servent** res) { + struct service servs[MAXSERVS]; + int cnt, proto, align; + + /* Align buffer */ + align = -(uintptr_t)buf & ALIGN - 1; + if (buflen < 2 * sizeof(char*) + align) return ERANGE; + buf += align; + + if (!prots) + proto = 0; + else if (!strcmp(prots, "tcp")) + proto = IPPROTO_TCP; + else if (!strcmp(prots, "udp")) + proto = IPPROTO_UDP; + else + return EINVAL; + + cnt = __lookup_serv(servs, name, proto, 0, 0); + if (cnt < 0) switch (cnt) { + case EAI_MEMORY: + case EAI_SYSTEM: + return ENOMEM; + default: + return ENOENT; + } + + se->s_name = (char*)name; + se->s_aliases = (void*)buf; + se->s_aliases[0] = se->s_name; + se->s_aliases[1] = 0; + se->s_port = htons(servs[0].port); + se->s_proto = servs[0].proto == IPPROTO_TCP ? "tcp" : "udp"; + + *res = se; + return 0; +} diff --git a/third_party/ulib/musl/src/network/getservbyport.c b/third_party/ulib/musl/src/network/getservbyport.c new file mode 100644 index 000000000..d4b91919a --- /dev/null +++ b/third_party/ulib/musl/src/network/getservbyport.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include + +struct servent* getservbyport(int port, const char* prots) { + static struct servent se; + static long buf[32 / sizeof(long)]; + struct servent* res; + if (getservbyport_r(port, prots, &se, (void*)buf, sizeof buf, &res)) return 0; + return &se; +} diff --git a/third_party/ulib/musl/src/network/getservbyport_r.c b/third_party/ulib/musl/src/network/getservbyport_r.c new file mode 100644 index 000000000..80ab6cb06 --- /dev/null +++ b/third_party/ulib/musl/src/network/getservbyport_r.c @@ -0,0 +1,52 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +int getservbyport_r(int port, const char* prots, struct servent* se, char* buf, size_t buflen, + struct servent** res) { + int i; + struct sockaddr_in sin = { + .sin_family = AF_INET, .sin_port = port, + }; + + if (!prots) { + int r = getservbyport_r(port, "tcp", se, buf, buflen, res); + if (r) r = getservbyport_r(port, "udp", se, buf, buflen, res); + return r; + } + + /* Align buffer */ + i = (uintptr_t)buf & sizeof(char*) - 1; + if (!i) i = sizeof(char*); + if (buflen < 3 * sizeof(char*) - i) return ERANGE; + buf += sizeof(char*) - i; + buflen -= sizeof(char*) - i; + + if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return EINVAL; + + se->s_port = port; + se->s_proto = (char*)prots; + se->s_aliases = (void*)buf; + buf += 2 * sizeof(char*); + buflen -= 2 * sizeof(char*); + se->s_aliases[1] = 0; + se->s_aliases[0] = se->s_name = buf; + + switch (getnameinfo((void*)&sin, sizeof sin, 0, 0, buf, buflen, + strcmp(prots, "udp") ? 0 : NI_DGRAM)) { + case EAI_MEMORY: + case EAI_SYSTEM: + return ENOMEM; + default: + return ENOENT; + case 0: + break; + } + + *res = se; + return 0; +} diff --git a/third_party/ulib/musl/src/network/getsockname.c b/third_party/ulib/musl/src/network/getsockname.c new file mode 100644 index 000000000..b8bfc8417 --- /dev/null +++ b/third_party/ulib/musl/src/network/getsockname.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int getsockname(int fd, struct sockaddr* restrict addr, socklen_t* restrict len) { + return syscall(SYS_getsockname, fd, addr, len, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/getsockopt.c b/third_party/ulib/musl/src/network/getsockopt.c new file mode 100644 index 000000000..2a3594cbe --- /dev/null +++ b/third_party/ulib/musl/src/network/getsockopt.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int getsockopt(int fd, int level, int optname, void* restrict optval, socklen_t* restrict optlen) { + return syscall(SYS_getsockopt, fd, level, optname, optval, optlen, 0); +} diff --git a/third_party/ulib/musl/src/network/h_errno.c b/third_party/ulib/musl/src/network/h_errno.c new file mode 100644 index 000000000..c212d8ae0 --- /dev/null +++ b/third_party/ulib/musl/src/network/h_errno.c @@ -0,0 +1,8 @@ +#include + +#undef h_errno +int h_errno; + +int* __h_errno_location(void) { + return &h_errno; +} diff --git a/third_party/ulib/musl/src/network/herror.c b/third_party/ulib/musl/src/network/herror.c new file mode 100644 index 000000000..e6989393d --- /dev/null +++ b/third_party/ulib/musl/src/network/herror.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include +#include + +void herror(const char* msg) { + fprintf(stderr, "%s%s%s", msg ? msg : "", msg ? ": " : "", hstrerror(h_errno)); +} diff --git a/third_party/ulib/musl/src/network/hstrerror.c b/third_party/ulib/musl/src/network/hstrerror.c new file mode 100644 index 000000000..4570e37a4 --- /dev/null +++ b/third_party/ulib/musl/src/network/hstrerror.c @@ -0,0 +1,18 @@ +#define _GNU_SOURCE +#include "locale_impl.h" +#include + +static const char msgs[] = "Host not found\0" + "Try again\0" + "Non-recoverable error\0" + "Address not available\0" + "\0Unknown error"; + +const char* hstrerror(int ecode) { + const char* s; + for (s = msgs, ecode--; ecode && *s; ecode--, s++) + for (; *s; s++) + ; + if (!*s) s++; + return LCTRANS_CUR(s); +} diff --git a/third_party/ulib/musl/src/network/htonl.c b/third_party/ulib/musl/src/network/htonl.c new file mode 100644 index 000000000..3f4d37124 --- /dev/null +++ b/third_party/ulib/musl/src/network/htonl.c @@ -0,0 +1,10 @@ +#include +#include + +uint32_t htonl(uint32_t n) { + union { + int i; + char c; + } u = {1}; + return u.c ? bswap_32(n) : n; +} diff --git a/third_party/ulib/musl/src/network/htons.c b/third_party/ulib/musl/src/network/htons.c new file mode 100644 index 000000000..491e6a9e4 --- /dev/null +++ b/third_party/ulib/musl/src/network/htons.c @@ -0,0 +1,10 @@ +#include +#include + +uint16_t htons(uint16_t n) { + union { + int i; + char c; + } u = {1}; + return u.c ? bswap_16(n) : n; +} diff --git a/third_party/ulib/musl/src/network/if_freenameindex.c b/third_party/ulib/musl/src/network/if_freenameindex.c new file mode 100644 index 000000000..6c9f0bf90 --- /dev/null +++ b/third_party/ulib/musl/src/network/if_freenameindex.c @@ -0,0 +1,6 @@ +#include +#include + +void if_freenameindex(struct if_nameindex* idx) { + free(idx); +} diff --git a/third_party/ulib/musl/src/network/if_indextoname.c b/third_party/ulib/musl/src/network/if_indextoname.c new file mode 100644 index 000000000..b4d9bdc63 --- /dev/null +++ b/third_party/ulib/musl/src/network/if_indextoname.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include +#include +#include + +char* if_indextoname(unsigned index, char* name) { + struct ifreq ifr; + int fd, r; + + if ((fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) return 0; + ifr.ifr_ifindex = index; + r = ioctl(fd, SIOCGIFNAME, &ifr); + __syscall(SYS_close, fd); + return r < 0 ? 0 : strncpy(name, ifr.ifr_name, IF_NAMESIZE); +} diff --git a/third_party/ulib/musl/src/network/if_nameindex.c b/third_party/ulib/musl/src/network/if_nameindex.c new file mode 100644 index 000000000..5e20030f3 --- /dev/null +++ b/third_party/ulib/musl/src/network/if_nameindex.c @@ -0,0 +1,111 @@ +#define _GNU_SOURCE +#include "netlink.h" +#include +#include +#include +#include +#include +#include + +#define IFADDRS_HASH_SIZE 64 + +struct ifnamemap { + unsigned int hash_next; + unsigned int index; + unsigned char namelen; + char name[IFNAMSIZ]; +}; + +struct ifnameindexctx { + unsigned int num, allocated, str_bytes; + struct ifnamemap* list; + unsigned int hash[IFADDRS_HASH_SIZE]; +}; + +static int netlink_msg_to_nameindex(void* pctx, struct nlmsghdr* h) { + struct ifnameindexctx* ctx = pctx; + struct ifnamemap* map; + struct rtattr* rta; + unsigned int i; + int index, type, namelen, bucket; + + if (h->nlmsg_type == RTM_NEWLINK) { + struct ifinfomsg* ifi = NLMSG_DATA(h); + index = ifi->ifi_index; + type = IFLA_IFNAME; + rta = NLMSG_RTA(h, sizeof(*ifi)); + } else { + struct ifaddrmsg* ifa = NLMSG_DATA(h); + index = ifa->ifa_index; + type = IFA_LABEL; + rta = NLMSG_RTA(h, sizeof(*ifa)); + } + for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != type) continue; + + namelen = RTA_DATALEN(rta) - 1; + if (namelen > IFNAMSIZ) return 0; + + /* suppress duplicates */ + bucket = index % IFADDRS_HASH_SIZE; + i = ctx->hash[bucket]; + while (i) { + map = &ctx->list[i - 1]; + if (map->index == index && map->namelen == namelen && + memcmp(map->name, RTA_DATA(rta), namelen) == 0) + return 0; + i = map->hash_next; + } + + if (ctx->num >= ctx->allocated) { + size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8; + if (a > SIZE_MAX / sizeof *map) return -1; + map = realloc(ctx->list, a * sizeof *map); + if (!map) return -1; + ctx->list = map; + ctx->allocated = a; + } + map = &ctx->list[ctx->num]; + map->index = index; + map->namelen = namelen; + memcpy(map->name, RTA_DATA(rta), namelen); + ctx->str_bytes += namelen + 1; + ctx->num++; + map->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ctx->num; + return 0; + } + return 0; +} + +struct if_nameindex* if_nameindex() { + struct ifnameindexctx _ctx, *ctx = &_ctx; + struct if_nameindex *ifs = 0, *d; + struct ifnamemap* s; + char* p; + int i; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + memset(ctx, 0, sizeof(*ctx)); + if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, netlink_msg_to_nameindex, ctx) < 0) goto err; + + ifs = malloc(sizeof(struct if_nameindex[ctx->num + 1]) + ctx->str_bytes); + if (!ifs) goto err; + + p = (char*)(ifs + ctx->num + 1); + for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) { + d->if_index = s->index; + d->if_name = p; + memcpy(p, s->name, s->namelen); + p += s->namelen; + *p++ = 0; + } + d->if_index = 0; + d->if_name = 0; +err: + pthread_setcancelstate(cs, 0); + free(ctx->list); + errno = ENOBUFS; + return ifs; +} diff --git a/third_party/ulib/musl/src/network/if_nametoindex.c b/third_party/ulib/musl/src/network/if_nametoindex.c new file mode 100644 index 000000000..2f2ae3844 --- /dev/null +++ b/third_party/ulib/musl/src/network/if_nametoindex.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include +#include +#include + +unsigned if_nametoindex(const char* name) { + struct ifreq ifr; + int fd, r; + + if ((fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) return 0; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + r = ioctl(fd, SIOCGIFINDEX, &ifr); + __syscall(SYS_close, fd); + return r < 0 ? 0 : ifr.ifr_ifindex; +} diff --git a/third_party/ulib/musl/src/network/in6addr_any.c b/third_party/ulib/musl/src/network/in6addr_any.c new file mode 100644 index 000000000..995387fae --- /dev/null +++ b/third_party/ulib/musl/src/network/in6addr_any.c @@ -0,0 +1,3 @@ +#include + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; diff --git a/third_party/ulib/musl/src/network/in6addr_loopback.c b/third_party/ulib/musl/src/network/in6addr_loopback.c new file mode 100644 index 000000000..b96005b81 --- /dev/null +++ b/third_party/ulib/musl/src/network/in6addr_loopback.c @@ -0,0 +1,3 @@ +#include + +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; diff --git a/third_party/ulib/musl/src/network/inet_addr.c b/third_party/ulib/musl/src/network/inet_addr.c new file mode 100644 index 000000000..684ad4cba --- /dev/null +++ b/third_party/ulib/musl/src/network/inet_addr.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int __inet_aton(const char*, struct in_addr*); + +in_addr_t inet_addr(const char* p) { + struct in_addr a; + if (!__inet_aton(p, &a)) return -1; + return a.s_addr; +} diff --git a/third_party/ulib/musl/src/network/inet_aton.c b/third_party/ulib/musl/src/network/inet_aton.c new file mode 100644 index 000000000..86556cf3b --- /dev/null +++ b/third_party/ulib/musl/src/network/inet_aton.c @@ -0,0 +1,39 @@ +#include "libc.h" +#include +#include +#include +#include + +int __inet_aton(const char* s0, struct in_addr* dest) { + const char* s = s0; + unsigned char* d = (void*)dest; + unsigned long a[4] = {0}; + char* z; + int i; + + for (i = 0; i < 4; i++) { + a[i] = strtoul(s, &z, 0); + if (z == s || (*z && *z != '.') || !isdigit(*s)) return 0; + if (!*z) break; + s = z + 1; + } + if (i == 4) return 0; + switch (i) { + case 0: + a[1] = a[0] & 0xffffff; + a[0] >>= 24; + case 1: + a[2] = a[1] & 0xffff; + a[1] >>= 16; + case 2: + a[3] = a[2] & 0xff; + a[2] >>= 8; + } + for (i = 0; i < 4; i++) { + if (a[i] > 255) return 0; + d[i] = a[i]; + } + return 1; +} + +weak_alias(__inet_aton, inet_aton); diff --git a/third_party/ulib/musl/src/network/inet_legacy.c b/third_party/ulib/musl/src/network/inet_legacy.c new file mode 100644 index 000000000..57135f74f --- /dev/null +++ b/third_party/ulib/musl/src/network/inet_legacy.c @@ -0,0 +1,31 @@ +#include +#include +#include + +in_addr_t inet_network(const char* p) { + return ntohl(inet_addr(p)); +} + +struct in_addr inet_makeaddr(in_addr_t n, in_addr_t h) { + if (n < 256) + h |= n << 24; + else if (n < 65536) + h |= n << 16; + else + h |= n << 8; + return (struct in_addr){h}; +} + +in_addr_t inet_lnaof(struct in_addr in) { + uint32_t h = in.s_addr; + if (h >> 24 < 128) return h & 0xffffff; + if (h >> 24 < 192) return h & 0xffff; + return h & 0xff; +} + +in_addr_t inet_netof(struct in_addr in) { + uint32_t h = in.s_addr; + if (h >> 24 < 128) return h >> 24; + if (h >> 24 < 192) return h >> 16; + return h >> 8; +} diff --git a/third_party/ulib/musl/src/network/inet_ntoa.c b/third_party/ulib/musl/src/network/inet_ntoa.c new file mode 100644 index 000000000..a997fb5e6 --- /dev/null +++ b/third_party/ulib/musl/src/network/inet_ntoa.c @@ -0,0 +1,9 @@ +#include +#include + +char* inet_ntoa(struct in_addr in) { + static char buf[16]; + unsigned char* a = (void*)∈ + snprintf(buf, sizeof buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); + return buf; +} diff --git a/third_party/ulib/musl/src/network/inet_ntop.c b/third_party/ulib/musl/src/network/inet_ntop.c new file mode 100644 index 000000000..27b0022bb --- /dev/null +++ b/third_party/ulib/musl/src/network/inet_ntop.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +const char* inet_ntop(int af, const void* restrict a0, char* restrict s, socklen_t l) { + const unsigned char* a = a0; + int i, j, max, best; + char buf[100]; + + switch (af) { + case AF_INET: + if (snprintf(s, l, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]) < l) return s; + break; + case AF_INET6: + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12)) + snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%x:%x", 256 * a[0] + a[1], + 256 * a[2] + a[3], 256 * a[4] + a[5], 256 * a[6] + a[7], 256 * a[8] + a[9], + 256 * a[10] + a[11], 256 * a[12] + a[13], 256 * a[14] + a[15]); + else + snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", 256 * a[0] + a[1], + 256 * a[2] + a[3], 256 * a[4] + a[5], 256 * a[6] + a[7], 256 * a[8] + a[9], + 256 * a[10] + a[11], a[12], a[13], a[14], a[15]); + /* Replace longest /(^0|:)[:0]{2,}/ with "::" */ + for (i = best = 0, max = 2; buf[i]; i++) { + if (i && buf[i] != ':') continue; + j = strspn(buf + i, ":0"); + if (j > max) best = i, max = j; + } + if (max > 2) { + buf[best] = buf[best + 1] = ':'; + memmove(buf + best + 2, buf + best + max, i - best - max + 1); + } + if (strlen(buf) < l) { + strcpy(s, buf); + return s; + } + break; + default: + errno = EAFNOSUPPORT; + return 0; + } + errno = ENOSPC; + return 0; +} diff --git a/third_party/ulib/musl/src/network/inet_pton.c b/third_party/ulib/musl/src/network/inet_pton.c new file mode 100644 index 000000000..c4c1baf38 --- /dev/null +++ b/third_party/ulib/musl/src/network/inet_pton.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include + +static int hexval(unsigned c) { + if (c - '0' < 10) return c - '0'; + c |= 32; + if (c - 'a' < 6) return c - 'a' + 10; + return -1; +} + +int inet_pton(int af, const char* restrict s, void* restrict a0) { + uint16_t ip[8]; + unsigned char* a = a0; + int i, j, v, d, brk = -1, need_v4 = 0; + + if (af == AF_INET) { + for (i = 0; i < 4; i++) { + for (v = j = 0; j < 3 && isdigit(s[j]); j++) + v = 10 * v + s[j] - '0'; + if (j == 0 || (j > 1 && s[0] == '0') || v > 255) return 0; + a[i] = v; + if (s[j] == 0 && i == 3) return 1; + if (s[j] != '.') return 0; + s += j + 1; + } + return 0; + } else if (af != AF_INET6) { + errno = EAFNOSUPPORT; + return -1; + } + + if (*s == ':' && *++s != ':') return 0; + + for (i = 0;; i++) { + if (s[0] == ':' && brk < 0) { + brk = i; + ip[i & 7] = 0; + if (!*++s) break; + if (i == 7) return 0; + continue; + } + for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++) + v = 16 * v + d; + if (j == 0) return 0; + ip[i & 7] = v; + if (!s[j] && (brk >= 0 || i == 7)) break; + if (i == 7) return 0; + if (s[j] != ':') { + if (s[j] != '.' || (i < 6 && brk < 0)) return 0; + need_v4 = 1; + i++; + break; + } + s += j + 1; + } + if (brk >= 0) { + memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk)); + for (j = 0; j < 7 - i; j++) + ip[brk + j] = 0; + } + for (j = 0; j < 8; j++) { + *a++ = ip[j] >> 8; + *a++ = ip[j]; + } + if (need_v4 && inet_pton(AF_INET, (void*)s, a - 4) <= 0) return 0; + return 1; +} diff --git a/third_party/ulib/musl/src/network/listen.c b/third_party/ulib/musl/src/network/listen.c new file mode 100644 index 000000000..3b7653b37 --- /dev/null +++ b/third_party/ulib/musl/src/network/listen.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int listen(int fd, int backlog) { + return syscall(SYS_listen, fd, backlog, 0, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/lookup.h b/third_party/ulib/musl/src/network/lookup.h new file mode 100644 index 000000000..53935e688 --- /dev/null +++ b/third_party/ulib/musl/src/network/lookup.h @@ -0,0 +1,41 @@ +#ifndef LOOKUP_H +#define LOOKUP_H + +#include +#include + +struct address { + int family; + unsigned scopeid; + uint8_t addr[16]; + int sortkey; +}; + +struct service { + uint16_t port; + unsigned char proto, socktype; +}; + +#define MAXNS 3 + +struct resolvconf { + struct address ns[MAXNS]; + unsigned nns, attempts, ndots; + unsigned timeout; +}; + +/* The limit of 48 results is a non-sharp bound on the number of addresses + * that can fit in one 512-byte DNS packet full of v4 results and a second + * packet full of v6 results. Due to headers, the actual limit is lower. */ +#define MAXADDRS 48 +#define MAXSERVS 2 + +int __lookup_serv(struct service buf[static MAXSERVS], const char* name, int proto, int socktype, + int flags); +int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char* name, + int family, int flags); +int __lookup_ipliteral(struct address buf[static 1], const char* name, int family); + +int __get_resolv_conf(struct resolvconf*, char*, size_t); + +#endif diff --git a/third_party/ulib/musl/src/network/lookup_ipliteral.c b/third_party/ulib/musl/src/network/lookup_ipliteral.c new file mode 100644 index 000000000..2c105bf6b --- /dev/null +++ b/third_party/ulib/musl/src/network/lookup_ipliteral.c @@ -0,0 +1,55 @@ +#include "lookup.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int __inet_aton(const char*, struct in_addr*); + +int __lookup_ipliteral(struct address buf[static 1], const char* name, int family) { + struct in_addr a4; + struct in6_addr a6; + if (__inet_aton(name, &a4) > 0) { + if (family == AF_INET6) /* wrong family */ + return EAI_NONAME; + memcpy(&buf[0].addr, &a4, sizeof a4); + buf[0].family = AF_INET; + buf[0].scopeid = 0; + return 1; + } + + char tmp[64]; + char *p = strchr(name, '%'), *z; + unsigned long long scopeid = 0; + if (p && p - name < 64) { + memcpy(tmp, name, p - name); + tmp[p - name] = 0; + name = tmp; + } + + if (inet_pton(AF_INET6, name, &a6) <= 0) return 0; + if (family == AF_INET) /* wrong family */ + return EAI_NONAME; + + memcpy(&buf[0].addr, &a6, sizeof a6); + buf[0].family = AF_INET6; + if (p) { + if (isdigit(*++p)) + scopeid = strtoull(p, &z, 10); + else + z = p - 1; + if (*z) { + if (!IN6_IS_ADDR_LINKLOCAL(&a6) && !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) return EAI_NONAME; + scopeid = if_nametoindex(p); + if (!scopeid) return EAI_NONAME; + } + if (scopeid > UINT_MAX) return EAI_NONAME; + } + buf[0].scopeid = scopeid; + return 1; +} diff --git a/third_party/ulib/musl/src/network/lookup_name.c b/third_party/ulib/musl/src/network/lookup_name.c new file mode 100644 index 000000000..ef2807ec0 --- /dev/null +++ b/third_party/ulib/musl/src/network/lookup_name.c @@ -0,0 +1,384 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include "syscall.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int is_valid_hostname(const char* host) { + const unsigned char* s; + if (strnlen(host, 255) - 1 >= 254 || mbstowcs(0, host, 0) == -1) return 0; + for (s = (void*)host; *s >= 0x80 || *s == '.' || *s == '-' || isalnum(*s); s++) + ; + return !*s; +} + +static int name_from_null(struct address buf[static 2], const char* name, int family, int flags) { + int cnt = 0; + if (name) return 0; + if (flags & AI_PASSIVE) { + if (family != AF_INET6) buf[cnt++] = (struct address){.family = AF_INET}; + if (family != AF_INET) buf[cnt++] = (struct address){.family = AF_INET6}; + } else { + if (family != AF_INET6) + buf[cnt++] = (struct address){.family = AF_INET, .addr = {127, 0, 0, 1}}; + if (family != AF_INET) + buf[cnt++] = (struct address){.family = AF_INET6, .addr = {[15] = 1}}; + } + return cnt; +} + +static int name_from_numeric(struct address buf[static 1], const char* name, int family) { + return __lookup_ipliteral(buf, name, family); +} + +static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], + const char* name, int family) { + char line[512]; + size_t l = strlen(name); + int cnt = 0, badfam = 0; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return 0; + default: + return EAI_SYSTEM; + } + while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { + char *p, *z; + + if ((p = strchr(line, '#'))) *p++ = '\n', *p = 0; + for (p = line + 1; (p = strstr(p, name)) && (!isspace(p[-1]) || !isspace(p[l])); p++) + ; + if (!p) continue; + + /* Isolate IP address to parse */ + for (p = line; *p && !isspace(*p); p++) + ; + *p++ = 0; + switch (name_from_numeric(buf + cnt, line, family)) { + case 1: + cnt++; + break; + case 0: + continue; + default: + badfam = EAI_NONAME; + continue; + } + + /* Extract first name as canonical name */ + for (; *p && isspace(*p); p++) + ; + for (z = p; *z && !isspace(*z); z++) + ; + *z = 0; + if (is_valid_hostname(p)) memcpy(canon, p, z - p + 1); + } + __fclose_ca(f); + return cnt ? cnt : badfam; +} + +struct dpc_ctx { + struct address* addrs; + char* canon; + int cnt; +}; + +int __dns_parse(const unsigned char*, int, int (*)(void*, int, const void*, int, const void*), + void*); +int __dn_expand(const unsigned char*, const unsigned char*, const unsigned char*, char*, int); +int __res_mkquery(int, const char*, int, int, const unsigned char*, int, const unsigned char*, + unsigned char*, int); +int __res_msend_rc(int, const unsigned char* const*, const int*, unsigned char* const*, int*, int, + const struct resolvconf*); + +#define RR_A 1 +#define RR_CNAME 5 +#define RR_AAAA 28 + +static int dns_parse_callback(void* c, int rr, const void* data, int len, const void* packet) { + char tmp[256]; + struct dpc_ctx* ctx = c; + switch (rr) { + case RR_A: + if (len != 4) return -1; + ctx->addrs[ctx->cnt].family = AF_INET; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); + break; + case RR_AAAA: + if (len != 16) return -1; + ctx->addrs[ctx->cnt].family = AF_INET6; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); + break; + case RR_CNAME: + if (__dn_expand(packet, (const unsigned char*)packet + 512, data, tmp, sizeof tmp) > 0 && + is_valid_hostname(tmp)) + strcpy(ctx->canon, tmp); + break; + } + return 0; +} + +static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], + const char* name, int family, const struct resolvconf* conf) { + unsigned char qbuf[2][280], abuf[2][512]; + const unsigned char* qp[2] = {qbuf[0], qbuf[1]}; + unsigned char* ap[2] = {abuf[0], abuf[1]}; + int qlens[2], alens[2]; + int i, nq = 0; + struct dpc_ctx ctx = {.addrs = buf, .canon = canon}; + + if (family != AF_INET6) { + qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0, qbuf[nq], sizeof *qbuf); + nq++; + } + if (family != AF_INET) { + qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0, qbuf[nq], sizeof *qbuf); + nq++; + } + + if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) return EAI_SYSTEM; + + for (i = 0; i < nq; i++) + __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); + + if (ctx.cnt) return ctx.cnt; + if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN; + if ((abuf[0][3] & 15) == 0) return EAI_NONAME; + if ((abuf[0][3] & 15) == 3) return 0; + return EAI_FAIL; +} + +static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], + const char* name, int family) { + char search[256]; + struct resolvconf conf; + size_t l, dots; + char *p, *z; + + if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; + + /* Count dots, suppress search when >=ndots or name ends in + * a dot, which is an explicit request for global scope. */ + for (dots = l = 0; name[l]; l++) + if (name[l] == '.') dots++; + if (dots >= conf.ndots || name[l - 1] == '.') *search = 0; + + /* This can never happen; the caller already checked length. */ + if (l >= 256) return EAI_NONAME; + + /* Name with search domain appended is setup in canon[]. This both + * provides the desired default canonical name (if the requested + * name is not a CNAME record) and serves as a buffer for passing + * the full requested name to name_from_dns. */ + memcpy(canon, name, l); + canon[l] = '.'; + + for (p = search; *p; p = z) { + for (; isspace(*p); p++) + ; + for (z = p; *z && !isspace(*z); z++) + ; + if (z == p) break; + if (z - p < 256 - l - 1) { + memcpy(canon + l + 1, p, z - p); + canon[z - p + 1 + l] = 0; + int cnt = name_from_dns(buf, canon, canon, family, &conf); + if (cnt) return cnt; + } + } + + canon[l] = 0; + return name_from_dns(buf, canon, name, family, &conf); +} + +static const struct policy { + unsigned char addr[16]; + unsigned char len, mask; + unsigned char prec, label; +} defpolicy[] = { + {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0}, + {"\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4}, + {"\x20\2", 1, 0xff, 30, 2}, + {"\x20\1", 3, 0xff, 5, 5}, + {"\xfc", 0, 0xfe, 3, 13}, +#if 0 + /* These are deprecated and/or returned to the address + * pool, so despite the RFC, treating them as special + * is probably wrong. */ + { "", 11, 0xff, 1, 3 }, + { "\xfe\xc0", 1, 0xc0, 1, 11 }, + { "\x3f\xfe", 1, 0xff, 1, 12 }, +#endif + /* Last rule must match all addresses to stop loop. */ + {"", 0, 0, 40, 1}, +}; + +static const struct policy* policyof(const struct in6_addr* a) { + int i; + for (i = 0;; i++) { + if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) continue; + if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) != + defpolicy[i].addr[defpolicy[i].len]) + continue; + return defpolicy + i; + } +} + +static int labelof(const struct in6_addr* a) { + return policyof(a)->label; +} + +static int scopeof(const struct in6_addr* a) { + if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15; + if (IN6_IS_ADDR_LINKLOCAL(a)) return 2; + if (IN6_IS_ADDR_LOOPBACK(a)) return 2; + if (IN6_IS_ADDR_SITELOCAL(a)) return 5; + return 14; +} + +static int prefixmatch(const struct in6_addr* s, const struct in6_addr* d) { + /* FIXME: The common prefix length should be limited to no greater + * than the nominal length of the prefix portion of the source + * address. However the definition of the source prefix length is + * not clear and thus this limiting is not yet implemented. */ + unsigned i; + for (i = 0; i < 128 && !((s->s6_addr[i / 8] ^ d->s6_addr[i / 8]) & (128 >> (i % 8))); i++) + ; + return i; +} + +#define DAS_USABLE 0x40000000 +#define DAS_MATCHINGSCOPE 0x20000000 +#define DAS_MATCHINGLABEL 0x10000000 +#define DAS_PREC_SHIFT 20 +#define DAS_SCOPE_SHIFT 16 +#define DAS_PREFIX_SHIFT 8 +#define DAS_ORDER_SHIFT 0 + +static int addrcmp(const void* _a, const void* _b) { + const struct address *a = _a, *b = _b; + return b->sortkey - a->sortkey; +} + +int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char* name, + int family, int flags) { + int cnt = 0, i, j; + + *canon = 0; + if (name) { + /* reject empty name and check len so it fits into temp bufs */ + size_t l = strnlen(name, 255); + if (l - 1 >= 254) return EAI_NONAME; + memcpy(canon, name, l + 1); + } + + /* Procedurally, a request for v6 addresses with the v4-mapped + * flag set is like a request for unspecified family, followed + * by filtering of the results. */ + if (flags & AI_V4MAPPED) { + if (family == AF_INET6) + family = AF_UNSPEC; + else + flags -= AI_V4MAPPED; + } + + /* Try each backend until there's at least one result. */ + cnt = name_from_null(buf, name, family, flags); + if (!cnt) cnt = name_from_numeric(buf, name, family); + if (!cnt && !(flags & AI_NUMERICHOST)) { + cnt = name_from_hosts(buf, canon, name, family); + if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); + } + if (cnt <= 0) return cnt ? cnt : EAI_NONAME; + + /* Filter/transform results for v4-mapped lookup, if requested. */ + if (flags & AI_V4MAPPED) { + if (!(flags & AI_ALL)) { + /* If any v6 results exist, remove v4 results. */ + for (i = 0; i < cnt && buf[i].family != AF_INET6; i++) + ; + if (i < cnt) { + for (j = 0; i < cnt; i++) { + if (buf[i].family == AF_INET6) buf[j++] = buf[i]; + } + cnt = i = j; + } + } + /* Translate any remaining v4 results to v6 */ + for (i = 0; i < cnt; i++) { + if (buf[i].family != AF_INET) continue; + memcpy(buf[i].addr + 12, buf[i].addr, 4); + memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + buf[i].family = AF_INET6; + } + } + + /* No further processing is needed if there are fewer than 2 + * results or if there are only IPv4 results. */ + if (cnt < 2 || family == AF_INET) return cnt; + for (i = 0; buf[i].family == AF_INET; i++) + if (i == cnt) return cnt; + + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + /* The following implements a subset of RFC 3484/6724 destination + * address selection by generating a single 31-bit sort key for + * each address. Rules 3, 4, and 7 are omitted for having + * excessive runtime and code size cost and dubious benefit. + * So far the label/precedence table cannot be customized. */ + for (i = 0; i < cnt; i++) { + int key = 0; + struct sockaddr_in6 sa, + da = {.sin6_family = AF_INET6, .sin6_scope_id = buf[i].scopeid, .sin6_port = 65535}; + if (buf[i].family == AF_INET6) { + memcpy(da.sin6_addr.s6_addr, buf[i].addr, 16); + } else { + memcpy(da.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + memcpy(da.sin6_addr.s6_addr + 12, buf[i].addr, 4); + } + const struct policy* dpolicy = policyof(&da.sin6_addr); + int dscope = scopeof(&da.sin6_addr); + int dlabel = dpolicy->label; + int dprec = dpolicy->prec; + int prefixlen = 0; + int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); + if (fd >= 0) { + if (!connect(fd, (void*)&da, sizeof da)) { + key |= DAS_USABLE; + if (!getsockname(fd, (void*)&sa, &(socklen_t){sizeof sa})) { + if (dscope == scopeof(&sa.sin6_addr)) key |= DAS_MATCHINGSCOPE; + if (dlabel == labelof(&sa.sin6_addr)) key |= DAS_MATCHINGLABEL; + prefixlen = prefixmatch(&sa.sin6_addr, &da.sin6_addr); + } + } + close(fd); + } + key |= dprec << DAS_PREC_SHIFT; + key |= (15 - dscope) << DAS_SCOPE_SHIFT; + key |= prefixlen << DAS_PREFIX_SHIFT; + key |= (MAXADDRS - i) << DAS_ORDER_SHIFT; + buf[i].sortkey = key; + } + qsort(buf, cnt, sizeof *buf, addrcmp); + + pthread_setcancelstate(cs, 0); + + return cnt; +} diff --git a/third_party/ulib/musl/src/network/lookup_serv.c b/third_party/ulib/musl/src/network/lookup_serv.c new file mode 100644 index 000000000..afdf3f9af --- /dev/null +++ b/third_party/ulib/musl/src/network/lookup_serv.c @@ -0,0 +1,114 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include +#include +#include +#include +#include +#include +#include + +int __lookup_serv(struct service buf[static MAXSERVS], const char* name, int proto, int socktype, + int flags) { + char line[128]; + int cnt = 0; + char *p, *z = ""; + unsigned long port = 0; + + switch (socktype) { + case SOCK_STREAM: + switch (proto) { + case 0: + proto = IPPROTO_TCP; + case IPPROTO_TCP: + break; + default: + return EAI_SERVICE; + } + break; + case SOCK_DGRAM: + switch (proto) { + case 0: + proto = IPPROTO_UDP; + case IPPROTO_UDP: + break; + default: + return EAI_SERVICE; + } + case 0: + break; + default: + if (name) return EAI_SERVICE; + buf[0].port = 0; + buf[0].proto = proto; + buf[0].socktype = socktype; + return 1; + } + + if (name) { + if (!*name) return EAI_SERVICE; + port = strtoul(name, &z, 10); + } + if (!*z) { + if (port > 65535) return EAI_SERVICE; + if (proto != IPPROTO_UDP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + if (proto != IPPROTO_TCP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + return cnt; + } + + if (flags & AI_NUMERICSERV) return EAI_SERVICE; + + size_t l = strlen(name); + + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return EAI_SERVICE; + default: + return EAI_SYSTEM; + } + + while (fgets(line, sizeof line, f) && cnt < MAXSERVS) { + if ((p = strchr(line, '#'))) *p++ = '\n', *p = 0; + + /* Find service name */ + for (p = line; (p = strstr(p, name)); p++) { + if (p > line && !isspace(p[-1])) continue; + if (p[l] && !isspace(p[l])) continue; + break; + } + if (!p) continue; + + /* Skip past canonical name at beginning of line */ + for (p = line; *p && !isspace(*p); p++) + ; + + port = strtoul(p, &z, 10); + if (port > 65535 || z == p) continue; + if (!strncmp(z, "/udp", 4)) { + if (proto == IPPROTO_TCP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + if (!strncmp(z, "/tcp", 4)) { + if (proto == IPPROTO_UDP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + } + __fclose_ca(f); + return cnt > 0 ? cnt : EAI_SERVICE; +} diff --git a/third_party/ulib/musl/src/network/netlink.c b/third_party/ulib/musl/src/network/netlink.c new file mode 100644 index 000000000..062700a2e --- /dev/null +++ b/third_party/ulib/musl/src/network/netlink.c @@ -0,0 +1,51 @@ +#include "netlink.h" +#include +#include +#include +#include + +static int __netlink_enumerate(int fd, unsigned int seq, int type, int af, + int (*cb)(void* ctx, struct nlmsghdr* h), void* ctx) { + struct nlmsghdr* h; + union { + uint8_t buf[8192]; + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct nlmsghdr reply; + } u; + int r, ret; + + memset(&u.req, 0, sizeof(u.req)); + u.req.nlh.nlmsg_len = sizeof(u.req); + u.req.nlh.nlmsg_type = type; + u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + u.req.nlh.nlmsg_seq = seq; + u.req.g.rtgen_family = af; + r = send(fd, &u.req, sizeof(u.req), 0); + if (r < 0) return r; + + while (1) { + r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); + if (r <= 0) return -1; + for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) { + if (h->nlmsg_type == NLMSG_DONE) return 0; + if (h->nlmsg_type == NLMSG_ERROR) return -1; + ret = cb(ctx, h); + if (ret) return ret; + } + } +} + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void* ctx, struct nlmsghdr* h), + void* ctx) { + int fd, r; + + fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); + if (fd < 0) return -1; + r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx); + if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx); + __syscall(SYS_close, fd); + return r; +} diff --git a/third_party/ulib/musl/src/network/netlink.h b/third_party/ulib/musl/src/network/netlink.h new file mode 100644 index 000000000..9785ea632 --- /dev/null +++ b/third_party/ulib/musl/src/network/netlink.h @@ -0,0 +1,95 @@ +#include + +/* linux/netlink.h */ + +#define NETLINK_ROUTE 0 + +struct nlmsghdr { + uint32_t nlmsg_len; + uint16_t nlmsg_type; + uint16_t nlmsg_flags; + uint32_t nlmsg_seq; + uint32_t nlmsg_pid; +}; + +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 + +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT | NLM_F_MATCH) + +#define NLMSG_NOOP 0x1 +#define NLMSG_ERROR 0x2 +#define NLMSG_DONE 0x3 +#define NLMSG_OVERRUN 0x4 + +/* linux/rtnetlink.h */ + +#define RTM_NEWLINK 16 +#define RTM_GETLINK 18 +#define RTM_NEWADDR 20 +#define RTM_GETADDR 22 + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; + int ifi_index; + unsigned ifi_flags; + unsigned ifi_change; +}; + +/* linux/if_link.h */ + +#define IFLA_ADDRESS 1 +#define IFLA_BROADCAST 2 +#define IFLA_IFNAME 3 +#define IFLA_STATS 7 + +/* linux/if_addr.h */ + +struct ifaddrmsg { + uint8_t ifa_family; + uint8_t ifa_prefixlen; + uint8_t ifa_flags; + uint8_t ifa_scope; + uint32_t ifa_index; +}; + +#define IFA_ADDRESS 1 +#define IFA_LOCAL 2 +#define IFA_LABEL 3 +#define IFA_BROADCAST 4 + +/* musl */ + +#define NETLINK_ALIGN(len) (((len) + 3) & ~3) +#define NLMSG_DATA(nlh) ((void*)((char*)(nlh) + sizeof(struct nlmsghdr))) +#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len - sizeof(struct nlmsghdr)) +#define NLMSG_DATAEND(nlh) ((char*)(nlh) + (nlh)->nlmsg_len) +#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh) + NETLINK_ALIGN((nlh)->nlmsg_len)) +#define NLMSG_OK(nlh, end) ((char*)(end) - (char*)(nlh) >= sizeof(struct nlmsghdr)) + +#define RTA_DATA(rta) ((void*)((char*)(rta) + sizeof(struct rtattr))) +#define RTA_DATALEN(rta) ((rta)->rta_len - sizeof(struct rtattr)) +#define RTA_DATAEND(rta) ((char*)(rta) + (rta)->rta_len) +#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta) + NETLINK_ALIGN((rta)->rta_len)) +#define RTA_OK(nlh, end) ((char*)(end) - (char*)(rta) >= sizeof(struct rtattr)) + +#define NLMSG_RTA(nlh, len) ((void*)((char*)(nlh) + sizeof(struct nlmsghdr) + NETLINK_ALIGN(len))) +#define NLMSG_RTAOK(rta, nlh) RTA_OK(rta, NLMSG_DATAEND(nlh)) + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void* ctx, struct nlmsghdr* h), + void* ctx); diff --git a/third_party/ulib/musl/src/network/netname.c b/third_party/ulib/musl/src/network/netname.c new file mode 100644 index 000000000..927ed53bf --- /dev/null +++ b/third_party/ulib/musl/src/network/netname.c @@ -0,0 +1,9 @@ +#include + +struct netent* getnetbyaddr(uint32_t net, int type) { + return 0; +} + +struct netent* getnetbyname(const char* name) { + return 0; +} diff --git a/third_party/ulib/musl/src/network/ns_parse.c b/third_party/ulib/musl/src/network/ns_parse.c new file mode 100644 index 000000000..8430982f8 --- /dev/null +++ b/third_party/ulib/musl/src/network/ns_parse.c @@ -0,0 +1,150 @@ +#define _BSD_SOURCE +#include +#include +#include +#include + +const struct _ns_flagdata _ns_flagdata[16] = { + {0x8000, 15}, {0x7800, 11}, {0x0400, 10}, {0x0200, 9}, {0x0100, 8}, {0x0080, 7}, + {0x0040, 6}, {0x0020, 5}, {0x0010, 4}, {0x000f, 0}, {0x0000, 0}, {0x0000, 0}, + {0x0000, 0}, {0x0000, 0}, {0x0000, 0}, {0x0000, 0}, +}; + +unsigned ns_get16(const unsigned char* cp) { + return cp[0] << 8 | cp[1]; +} + +unsigned long ns_get32(const unsigned char* cp) { + return (unsigned)cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; +} + +void ns_put16(unsigned s, unsigned char* cp) { + *cp++ = s >> 8; + *cp++ = s; +} + +void ns_put32(unsigned long l, unsigned char* cp) { + *cp++ = l >> 24; + *cp++ = l >> 16; + *cp++ = l >> 8; + *cp++ = l; +} + +int ns_initparse(const unsigned char* msg, int msglen, ns_msg* handle) { + int i, r; + + handle->_msg = msg; + handle->_eom = msg + msglen; + if (msglen < (2 + ns_s_max) * NS_INT16SZ) goto bad; + NS_GET16(handle->_id, msg); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) + NS_GET16(handle->_counts[i], msg); + for (i = 0; i < ns_s_max; i++) { + if (handle->_counts[i]) { + handle->_sections[i] = msg; + r = ns_skiprr(msg, handle->_eom, i, handle->_counts[i]); + if (r < 0) return -1; + msg += r; + } else { + handle->_sections[i] = NULL; + } + } + if (msg != handle->_eom) goto bad; + handle->_sect = ns_s_max; + handle->_rrnum = -1; + handle->_msg_ptr = NULL; + return 0; +bad: + errno = EMSGSIZE; + return -1; +} + +int ns_skiprr(const unsigned char* ptr, const unsigned char* eom, ns_sect section, int count) { + const unsigned char* p = ptr; + int r; + + while (count--) { + r = dn_skipname(p, eom); + if (r < 0) goto bad; + if (r + 2 * NS_INT16SZ > eom - p) goto bad; + p += r + 2 * NS_INT16SZ; + if (section != ns_s_qd) { + if (NS_INT32SZ + NS_INT16SZ > eom - p) goto bad; + p += NS_INT32SZ; + NS_GET16(r, p); + if (r > eom - p) goto bad; + p += r; + } + } + return p - ptr; +bad: + errno = EMSGSIZE; + return -1; +} + +int ns_parserr(ns_msg* handle, ns_sect section, int rrnum, ns_rr* rr) { + int r; + + if (section < 0 || section >= ns_s_max) goto bad; + if (section != handle->_sect) { + handle->_sect = section; + handle->_rrnum = 0; + handle->_msg_ptr = handle->_sections[section]; + } + if (rrnum == -1) rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[section]) goto bad; + if (rrnum < handle->_rrnum) { + handle->_rrnum = 0; + handle->_msg_ptr = handle->_sections[section]; + } + if (rrnum > handle->_rrnum) { + r = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum); + if (r < 0) return -1; + handle->_msg_ptr += r; + handle->_rrnum = rrnum; + } + r = ns_name_uncompress(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (r < 0) return -1; + handle->_msg_ptr += r; + if (2 * NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size; + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section != ns_s_qd) { + if (NS_INT32SZ + NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size; + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (rr->rdlength > handle->_eom - handle->_msg_ptr) goto size; + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } else { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } + handle->_rrnum++; + if (handle->_rrnum > handle->_counts[section]) { + handle->_sect = section + 1; + if (handle->_sect == ns_s_max) { + handle->_rrnum = -1; + handle->_msg_ptr = NULL; + } else { + handle->_rrnum = 0; + } + } + return 0; +bad: + errno = ENODEV; + return -1; +size: + errno = EMSGSIZE; + return -1; +} + +int ns_name_uncompress(const unsigned char* msg, const unsigned char* eom, const unsigned char* src, + char* dst, size_t dstsiz) { + int r; + r = dn_expand(msg, eom, src, dst, dstsiz); + if (r < 0) errno = EMSGSIZE; + return r; +} diff --git a/third_party/ulib/musl/src/network/ntohl.c b/third_party/ulib/musl/src/network/ntohl.c new file mode 100644 index 000000000..51bf2f532 --- /dev/null +++ b/third_party/ulib/musl/src/network/ntohl.c @@ -0,0 +1,10 @@ +#include +#include + +uint32_t ntohl(uint32_t n) { + union { + int i; + char c; + } u = {1}; + return u.c ? bswap_32(n) : n; +} diff --git a/third_party/ulib/musl/src/network/ntohs.c b/third_party/ulib/musl/src/network/ntohs.c new file mode 100644 index 000000000..cce7f2c76 --- /dev/null +++ b/third_party/ulib/musl/src/network/ntohs.c @@ -0,0 +1,10 @@ +#include +#include + +uint16_t ntohs(uint16_t n) { + union { + int i; + char c; + } u = {1}; + return u.c ? bswap_16(n) : n; +} diff --git a/third_party/ulib/musl/src/network/proto.c b/third_party/ulib/musl/src/network/proto.c new file mode 100644 index 000000000..4827a301b --- /dev/null +++ b/third_party/ulib/musl/src/network/proto.c @@ -0,0 +1,79 @@ +#include +#include + +/* do we really need all these?? */ + +static int idx; +static const unsigned char protos[] = {"\000ip\0" + "\001icmp\0" + "\002igmp\0" + "\003ggp\0" + "\004ipencap\0" + "\005st\0" + "\006tcp\0" + "\010egp\0" + "\014pup\0" + "\021udp\0" + "\024hmp\0" + "\026xns-idp\0" + "\033rdp\0" + "\035iso-tp4\0" + "\044xtp\0" + "\045ddp\0" + "\046idpr-cmtp\0" + "\051ipv6\0" + "\053ipv6-route\0" + "\054ipv6-frag\0" + "\055idrp\0" + "\056rsvp\0" + "\057gre\0" + "\062esp\0" + "\063ah\0" + "\071skip\0" + "\072ipv6-icmp\0" + "\073ipv6-nonxt\0" + "\074ipv6-opts\0" + "\111rspf\0" + "\121vmtp\0" + "\131ospf\0" + "\136ipip\0" + "\142encap\0" + "\147pim\0" + "\377raw"}; + +void endprotoent(void) { + idx = 0; +} + +void setprotoent(int stayopen) { + idx = 0; +} + +struct protoent* getprotoent(void) { + static struct protoent p; + static const char* aliases; + if (idx >= sizeof protos) return NULL; + p.p_proto = protos[idx]; + p.p_name = (char*)&protos[idx + 1]; + p.p_aliases = (char**)&aliases; + idx += strlen(p.p_name) + 2; + return &p; +} + +struct protoent* getprotobyname(const char* name) { + struct protoent* p; + endprotoent(); + do + p = getprotoent(); + while (p && strcmp(name, p->p_name)); + return p; +} + +struct protoent* getprotobynumber(int num) { + struct protoent* p; + endprotoent(); + do + p = getprotoent(); + while (p && p->p_proto != num); + return p; +} diff --git a/third_party/ulib/musl/src/network/recv.c b/third_party/ulib/musl/src/network/recv.c new file mode 100644 index 000000000..f5ac90abd --- /dev/null +++ b/third_party/ulib/musl/src/network/recv.c @@ -0,0 +1,5 @@ +#include + +ssize_t recv(int fd, void* buf, size_t len, int flags) { + return recvfrom(fd, buf, len, flags, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/recvfrom.c b/third_party/ulib/musl/src/network/recvfrom.c new file mode 100644 index 000000000..5ef6f5ede --- /dev/null +++ b/third_party/ulib/musl/src/network/recvfrom.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t recvfrom(int fd, void* restrict buf, size_t len, int flags, struct sockaddr* restrict addr, + socklen_t* restrict alen) { + return syscall(SYS_recvfrom, fd, buf, len, flags, addr, alen); +} diff --git a/third_party/ulib/musl/src/network/recvmmsg.c b/third_party/ulib/musl/src/network/recvmmsg.c new file mode 100644 index 000000000..129133e19 --- /dev/null +++ b/third_party/ulib/musl/src/network/recvmmsg.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include + +int recvmmsg(int fd, struct mmsghdr* msgvec, unsigned int vlen, unsigned int flags, + struct timespec* timeout) { +#if LONG_MAX > INT_MAX + struct mmsghdr* mh = msgvec; + unsigned int i; + for (i = vlen; i; i--, mh++) + mh->msg_hdr.__pad1 = mh->msg_hdr.__pad2 = 0; +#endif + return syscall(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout); +} diff --git a/third_party/ulib/musl/src/network/recvmsg.c b/third_party/ulib/musl/src/network/recvmsg.c new file mode 100644 index 000000000..06bf023b2 --- /dev/null +++ b/third_party/ulib/musl/src/network/recvmsg.c @@ -0,0 +1,21 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +ssize_t recvmsg(int fd, struct msghdr* msg, int flags) { + ssize_t r; +#if LONG_MAX > INT_MAX + struct msghdr h, *orig = msg; + if (msg) { + h = *msg; + h.__pad1 = h.__pad2 = 0; + msg = &h; + } +#endif + r = syscall(SYS_recvmsg, fd, msg, flags, 0, 0, 0); +#if LONG_MAX > INT_MAX + if (orig) *orig = h; +#endif + return r; +} diff --git a/third_party/ulib/musl/src/network/res_init.c b/third_party/ulib/musl/src/network/res_init.c new file mode 100644 index 000000000..1f93d26e4 --- /dev/null +++ b/third_party/ulib/musl/src/network/res_init.c @@ -0,0 +1,5 @@ +#include + +int res_init() { + return 0; +} diff --git a/third_party/ulib/musl/src/network/res_mkquery.c b/third_party/ulib/musl/src/network/res_mkquery.c new file mode 100644 index 000000000..a42042d0a --- /dev/null +++ b/third_party/ulib/musl/src/network/res_mkquery.c @@ -0,0 +1,42 @@ +#include "libc.h" +#include +#include +#include + +int __res_mkquery(int op, const char* dname, int class, int type, const unsigned char* data, + int datalen, const unsigned char* newrr, unsigned char* buf, int buflen) { + int id, i, j; + unsigned char q[280]; + struct timespec ts; + size_t l = strnlen(dname, 255); + int n; + + if (l && dname[l - 1] == '.') l--; + n = 17 + l + !!l; + if (l > 253 || buflen < n || op > 15u || class > 255u || type > 255u) return -1; + + /* Construct query template - ID will be filled later */ + memset(q, 0, n); + q[2] = op * 8 + 1; + q[5] = 1; + memcpy((char*)q + 13, dname, l); + for (i = 13; q[i]; i = j + 1) { + for (j = i; q[j] && q[j] != '.'; j++) + ; + if (j - i - 1u > 62u) return -1; + q[i - 1] = j - i; + } + q[i + 1] = type; + q[i + 3] = class; + + /* Make a reasonably unpredictable id */ + clock_gettime(CLOCK_REALTIME, &ts); + id = ts.tv_nsec + ts.tv_nsec / 65536UL & 0xffff; + q[0] = id / 256; + q[1] = id; + + memcpy(buf, q, n); + return n; +} + +weak_alias(__res_mkquery, res_mkquery); diff --git a/third_party/ulib/musl/src/network/res_msend.c b/third_party/ulib/musl/src/network/res_msend.c new file mode 100644 index 000000000..7e2d0672b --- /dev/null +++ b/third_party/ulib/musl/src/network/res_msend.c @@ -0,0 +1,176 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include "syscall.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void cleanup(void* p) { + __syscall(SYS_close, (intptr_t)p); +} + +static unsigned long mtime(void) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (unsigned long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +} + +int __res_msend_rc(int nqueries, const unsigned char* const* queries, const int* qlens, + unsigned char* const* answers, int* alens, int asize, + const struct resolvconf* conf) { + int fd; + int timeout, attempts, retry_interval, servfail_retry; + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa = {0}, ns[MAXNS] = {{0}}; + socklen_t sl = sizeof sa.sin; + int nns = 0; + int family = AF_INET; + int rlen; + int next; + int i, j; + int cs; + struct pollfd pfd; + unsigned long t0, t1, t2; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + timeout = 1000 * conf->timeout; + attempts = conf->attempts; + + for (nns = 0; nns < conf->nns; nns++) { + const struct address* iplit = &conf->ns[nns]; + if (iplit->family == AF_INET) { + memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4); + ns[nns].sin.sin_port = htons(53); + ns[nns].sin.sin_family = AF_INET; + } else { + sl = sizeof sa.sin6; + memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16); + ns[nns].sin6.sin6_port = htons(53); + ns[nns].sin6.sin6_scope_id = iplit->scopeid; + ns[nns].sin6.sin6_family = family = AF_INET6; + } + } + + /* Get local address and open/bind a socket */ + sa.sin.sin_family = family; + fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + + /* Handle case where system lacks IPv6 support */ + if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { + fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + family = AF_INET; + } + if (fd < 0 || bind(fd, (void*)&sa, sl) < 0) return -1; + + /* Past this point, there are no errors. Each individual query will + * yield either no reply (indicated by zero length) or an answer + * packet which is up to the caller to interpret. */ + + pthread_cleanup_push(cleanup, (void*)(intptr_t)fd); + pthread_setcancelstate(cs, 0); + + /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ + if (family == AF_INET6) { + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); + for (i = 0; i < nns; i++) { + if (ns[i].sin.sin_family != AF_INET) continue; + memcpy(ns[i].sin6.sin6_addr.s6_addr + 12, &ns[i].sin.sin_addr, 4); + memcpy(ns[i].sin6.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + ns[i].sin6.sin6_family = AF_INET6; + ns[i].sin6.sin6_flowinfo = 0; + ns[i].sin6.sin6_scope_id = 0; + } + } + + memset(alens, 0, sizeof *alens * nqueries); + + pfd.fd = fd; + pfd.events = POLLIN; + retry_interval = timeout / attempts; + next = 0; + t0 = t2 = mtime(); + t1 = t2 - retry_interval; + + for (; t2 - t0 < timeout; t2 = mtime()) { + if (t2 - t1 >= retry_interval) { + /* Query all configured namservers in parallel */ + for (i = 0; i < nqueries; i++) + if (!alens[i]) + for (j = 0; j < nns; j++) + sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void*)&ns[j], sl); + t1 = t2; + servfail_retry = 2 * nqueries; + } + + /* Wait for a response, or until time to retry */ + if (poll(&pfd, 1, t1 + retry_interval - t2) <= 0) continue; + + while ((rlen = recvfrom(fd, answers[next], asize, 0, (void*)&sa, (socklen_t[1]){sl})) >= + 0) { + + /* Ignore non-identifiable packets */ + if (rlen < 4) continue; + + /* Ignore replies from addresses we didn't send to */ + for (j = 0; j < nns && memcmp(ns + j, &sa, sl); j++) + ; + if (j == nns) continue; + + /* Find which query this answer goes with, if any */ + for (i = next; i < nqueries && + (answers[next][0] != queries[i][0] || answers[next][1] != queries[i][1]); + i++) + ; + if (i == nqueries) continue; + if (alens[i]) continue; + + /* Only accept positive or negative responses; + * retry immediately on server failure, and ignore + * all other codes such as refusal. */ + switch (answers[next][3] & 15) { + case 0: + case 3: + break; + case 2: + if (servfail_retry && servfail_retry--) + sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void*)&ns[j], sl); + default: + continue; + } + + /* Store answer in the right slot, or update next + * available temp slot if it's already in place. */ + alens[i] = rlen; + if (i == next) + for (; next < nqueries && alens[next]; next++) + ; + else + memcpy(answers[i], answers[next], rlen); + + if (next == nqueries) goto out; + } + } +out: + pthread_cleanup_pop(1); + + return 0; +} + +int __res_msend(int nqueries, const unsigned char* const* queries, const int* qlens, + unsigned char* const* answers, int* alens, int asize) { + struct resolvconf conf; + if (__get_resolv_conf(&conf, 0, 0) < 0) return -1; + return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &conf); +} diff --git a/third_party/ulib/musl/src/network/res_query.c b/third_party/ulib/musl/src/network/res_query.c new file mode 100644 index 000000000..f5413d33c --- /dev/null +++ b/third_party/ulib/musl/src/network/res_query.c @@ -0,0 +1,17 @@ +#include "libc.h" +#include +#include + +int __res_mkquery(int, const char*, int, int, const unsigned char*, int, const unsigned char*, + unsigned char*, int); +int __res_send(const unsigned char*, int, unsigned char*, int); + +int __res_query(const char* name, int class, int type, unsigned char* dest, int len) { + unsigned char q[280]; + int ql = __res_mkquery(0, name, class, type, 0, 0, 0, q, sizeof q); + if (ql < 0) return ql; + return __res_send(q, ql, dest, len); +} + +weak_alias(__res_query, res_query); +weak_alias(__res_query, res_search); diff --git a/third_party/ulib/musl/src/network/res_querydomain.c b/third_party/ulib/musl/src/network/res_querydomain.c new file mode 100644 index 000000000..1e5173ddd --- /dev/null +++ b/third_party/ulib/musl/src/network/res_querydomain.c @@ -0,0 +1,14 @@ +#include +#include + +int res_querydomain(const char* name, const char* domain, int class, int type, unsigned char* dest, + int len) { + char tmp[255]; + size_t nl = strnlen(name, 255); + size_t dl = strnlen(domain, 255); + if (nl + dl + 1 > 254) return -1; + memcpy(tmp, name, nl); + tmp[nl] = '.'; + memcpy(tmp + nl + 1, domain, dl + 1); + return res_query(tmp, class, type, dest, len); +} diff --git a/third_party/ulib/musl/src/network/res_send.c b/third_party/ulib/musl/src/network/res_send.c new file mode 100644 index 000000000..64a833719 --- /dev/null +++ b/third_party/ulib/musl/src/network/res_send.c @@ -0,0 +1,11 @@ +#include "libc.h" +#include + +int __res_msend(int, const unsigned char* const*, const int*, unsigned char* const*, int*, int); + +int __res_send(const unsigned char* msg, int msglen, unsigned char* answer, int anslen) { + int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); + return r < 0 ? r : anslen; +} + +weak_alias(__res_send, res_send); diff --git a/third_party/ulib/musl/src/network/res_state.c b/third_party/ulib/musl/src/network/res_state.c new file mode 100644 index 000000000..0ae4d89fa --- /dev/null +++ b/third_party/ulib/musl/src/network/res_state.c @@ -0,0 +1,8 @@ +#include + +/* This is completely unused, and exists purely to satisfy broken apps. */ + +struct __res_state* __res_state() { + static struct __res_state res; + return &res; +} diff --git a/third_party/ulib/musl/src/network/resolvconf.c b/third_party/ulib/musl/src/network/resolvconf.c new file mode 100644 index 000000000..c62f506cc --- /dev/null +++ b/third_party/ulib/musl/src/network/resolvconf.c @@ -0,0 +1,94 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include +#include +#include +#include + +int __get_resolv_conf(struct resolvconf* conf, char* search, size_t search_sz) { + char line[256]; + unsigned char _buf[256]; + FILE *f, _f; + int nns = 0; + + conf->ndots = 1; + conf->timeout = 5; + conf->attempts = 2; + if (search) *search = 0; + + f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + goto no_resolv_conf; + default: + return -1; + } + + while (fgets(line, sizeof line, f)) { + char *p, *z; + if (!strchr(line, '\n') && !feof(f)) { + /* Ignore lines that get truncated rather than + * potentially misinterpreting them. */ + int c; + do + c = getc(f); + while (c != '\n' && c != EOF); + continue; + } + if (!strncmp(line, "options", 7) && isspace(line[7])) { + p = strstr(line, "ndots:"); + if (p && isdigit(p[6])) { + p += 6; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->ndots = x > 15 ? 15 : x; + } + p = strstr(line, "attempts:"); + if (p && isdigit(p[6])) { + p += 6; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->attempts = x > 10 ? 10 : x; + } + p = strstr(line, "timeout:"); + if (p && (isdigit(p[8]) || p[8] == '.')) { + p += 8; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->timeout = x > 60 ? 60 : x; + } + continue; + } + if (!strncmp(line, "nameserver", 10) && isspace(line[10])) { + if (nns >= MAXNS) continue; + for (p = line + 11; isspace(*p); p++) + ; + for (z = p; *z && !isspace(*z); z++) + ; + *z = 0; + if (__lookup_ipliteral(conf->ns + nns, p, AF_UNSPEC) > 0) nns++; + continue; + } + + if (!search) continue; + if ((strncmp(line, "domain", 6) && strncmp(line, "search", 6)) || !isspace(line[6])) + continue; + for (p = line + 7; isspace(*p); p++) + ; + size_t l = strlen(p); + /* This can never happen anyway with chosen buffer sizes. */ + if (l >= search_sz) continue; + memcpy(search, p, l + 1); + } + + __fclose_ca(f); + +no_resolv_conf: + if (!nns) { + __lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC); + nns = 1; + } + + conf->nns = nns; + + return 0; +} diff --git a/third_party/ulib/musl/src/network/send.c b/third_party/ulib/musl/src/network/send.c new file mode 100644 index 000000000..8a48e8a56 --- /dev/null +++ b/third_party/ulib/musl/src/network/send.c @@ -0,0 +1,5 @@ +#include + +ssize_t send(int fd, const void* buf, size_t len, int flags) { + return sendto(fd, buf, len, flags, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/sendmmsg.c b/third_party/ulib/musl/src/network/sendmmsg.c new file mode 100644 index 000000000..d245d840d --- /dev/null +++ b/third_party/ulib/musl/src/network/sendmmsg.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE +#include "syscall.h" +#include +#include +#include + +int sendmmsg(int fd, struct mmsghdr* msgvec, unsigned int vlen, unsigned int flags) { +#if LONG_MAX > INT_MAX + /* Can't use the syscall directly because the kernel has the wrong + * idea for the types of msg_iovlen, msg_controllen, and cmsg_len, + * and the cmsg blocks cannot be modified in-place. */ + int i; + if (vlen > IOV_MAX) vlen = IOV_MAX; /* This matches the kernel. */ + if (!vlen) return 0; + for (i = 0; i < vlen; i++) { + /* As an unfortunate inconsistency, the sendmmsg API uses + * unsigned int for the resulting msg_len, despite sendmsg + * returning ssize_t. However Linux limits the total bytes + * sent by sendmsg to INT_MAX, so the assignment is safe. */ + ssize_t r = sendmsg(fd, &msgvec[i].msg_hdr, flags); + if (r < 0) goto error; + msgvec[i].msg_len = r; + } +error: + return i ? i : -1; +#else + return syscall(SYS_sendmmsg, fd, msgvec, vlen, flags); +#endif +} diff --git a/third_party/ulib/musl/src/network/sendmsg.c b/third_party/ulib/musl/src/network/sendmsg.c new file mode 100644 index 000000000..75f1616c4 --- /dev/null +++ b/third_party/ulib/musl/src/network/sendmsg.c @@ -0,0 +1,29 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include + +ssize_t sendmsg(int fd, const struct msghdr* msg, int flags) { +#if LONG_MAX > INT_MAX + struct msghdr h; + struct cmsghdr chbuf[1024 / sizeof(struct cmsghdr) + 1], *c; + if (msg) { + h = *msg; + h.__pad1 = h.__pad2 = 0; + msg = &h; + if (h.msg_controllen) { + if (h.msg_controllen > 1024) { + errno = ENOMEM; + return -1; + } + memcpy(chbuf, h.msg_control, h.msg_controllen); + h.msg_control = chbuf; + for (c = CMSG_FIRSTHDR(&h); c; c = CMSG_NXTHDR(&h, c)) + c->__pad1 = 0; + } + } +#endif + return syscall(SYS_sendmsg, fd, msg, flags, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/sendto.c b/third_party/ulib/musl/src/network/sendto.c new file mode 100644 index 000000000..b60292971 --- /dev/null +++ b/third_party/ulib/musl/src/network/sendto.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t sendto(int fd, const void* buf, size_t len, int flags, const struct sockaddr* addr, + socklen_t alen) { + return syscall(SYS_sendto, fd, buf, len, flags, addr, alen); +} diff --git a/third_party/ulib/musl/src/network/serv.c b/third_party/ulib/musl/src/network/serv.c new file mode 100644 index 000000000..80ade606f --- /dev/null +++ b/third_party/ulib/musl/src/network/serv.c @@ -0,0 +1,9 @@ +#include + +void endservent(void) {} + +void setservent(int stayopen) {} + +struct servent* getservent(void) { + return 0; +} diff --git a/third_party/ulib/musl/src/network/setsockopt.c b/third_party/ulib/musl/src/network/setsockopt.c new file mode 100644 index 000000000..76c031d93 --- /dev/null +++ b/third_party/ulib/musl/src/network/setsockopt.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) { + return syscall(SYS_setsockopt, fd, level, optname, optval, optlen, 0); +} diff --git a/third_party/ulib/musl/src/network/shutdown.c b/third_party/ulib/musl/src/network/shutdown.c new file mode 100644 index 000000000..7729533b8 --- /dev/null +++ b/third_party/ulib/musl/src/network/shutdown.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int shutdown(int fd, int how) { + return syscall(SYS_shutdown, fd, how, 0, 0, 0, 0); +} diff --git a/third_party/ulib/musl/src/network/sockatmark.c b/third_party/ulib/musl/src/network/sockatmark.c new file mode 100644 index 000000000..93978176b --- /dev/null +++ b/third_party/ulib/musl/src/network/sockatmark.c @@ -0,0 +1,8 @@ +#include +#include + +int sockatmark(int s) { + int ret; + if (ioctl(s, SIOCATMARK, &ret) < 0) return -1; + return ret; +} diff --git a/third_party/ulib/musl/src/network/socket.c b/third_party/ulib/musl/src/network/socket.c new file mode 100644 index 000000000..381aa2791 --- /dev/null +++ b/third_party/ulib/musl/src/network/socket.c @@ -0,0 +1,16 @@ +#include "syscall.h" +#include +#include +#include + +int socket(int domain, int type, int protocol) { + int s = syscall(SYS_socket, domain, type, protocol, 0, 0, 0); + if (s < 0 && (errno == EINVAL || errno == EPROTONOSUPPORT) && + (type & (SOCK_CLOEXEC | SOCK_NONBLOCK))) { + s = syscall(SYS_socket, domain, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), protocol, 0, 0, 0); + if (s < 0) return s; + if (type & SOCK_CLOEXEC) __syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC); + if (type & SOCK_NONBLOCK) __syscall(SYS_fcntl, s, F_SETFL, O_NONBLOCK); + } + return s; +} diff --git a/third_party/ulib/musl/src/network/socketpair.c b/third_party/ulib/musl/src/network/socketpair.c new file mode 100644 index 000000000..6406d86e8 --- /dev/null +++ b/third_party/ulib/musl/src/network/socketpair.c @@ -0,0 +1,23 @@ +#include "syscall.h" +#include +#include +#include + +int socketpair(int domain, int type, int protocol, int fd[2]) { + int r = syscall(SYS_socketpair, domain, type, protocol, fd, 0, 0); + if (r < 0 && (errno == EINVAL || errno == EPROTONOSUPPORT) && + (type & (SOCK_CLOEXEC | SOCK_NONBLOCK))) { + r = syscall(SYS_socketpair, domain, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), protocol, fd, 0, + 0); + if (r < 0) return r; + if (type & SOCK_CLOEXEC) { + __syscall(SYS_fcntl, fd[0], F_SETFD, FD_CLOEXEC); + __syscall(SYS_fcntl, fd[1], F_SETFD, FD_CLOEXEC); + } + if (type & SOCK_NONBLOCK) { + __syscall(SYS_fcntl, fd[0], F_SETFL, O_NONBLOCK); + __syscall(SYS_fcntl, fd[1], F_SETFL, O_NONBLOCK); + } + } + return r; +} diff --git a/third_party/ulib/musl/src/passwd/BUILD.gn b/third_party/ulib/musl/src/passwd/BUILD.gn new file mode 100644 index 000000000..f45136a69 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/BUILD.gn @@ -0,0 +1,28 @@ +source_set("passwd") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "fgetgrent.c", + "fgetpwent.c", + "fgetspent.c", + "getgr_a.c", + "getgr_r.c", + "getgrent.c", + "getgrent_a.c", + "getgrouplist.c", + "getpw_a.c", + "getpw_r.c", + "getpwent.c", + "getpwent_a.c", + "getspent.c", + "getspnam.c", + "getspnam_r.c", + "lckpwdf.c", + "nscd_query.c", + "putgrent.c", + "putpwent.c", + "putspent.c", + ] +} diff --git a/third_party/ulib/musl/src/passwd/fgetgrent.c b/third_party/ulib/musl/src/passwd/fgetgrent.c new file mode 100644 index 000000000..69981ded3 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/fgetgrent.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include "pwf.h" + +struct group* fgetgrent(FILE* f) { + static char *line, **mem; + static struct group gr; + struct group* res; + size_t size = 0, nmem = 0; + __getgrent_a(f, &gr, &line, &size, &mem, &nmem, &res); + return res; +} diff --git a/third_party/ulib/musl/src/passwd/fgetpwent.c b/third_party/ulib/musl/src/passwd/fgetpwent.c new file mode 100644 index 000000000..561b8eb4d --- /dev/null +++ b/third_party/ulib/musl/src/passwd/fgetpwent.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include "pwf.h" + +struct passwd* fgetpwent(FILE* f) { + static char* line; + static struct passwd pw; + size_t size = 0; + struct passwd* res; + __getpwent_a(f, &pw, &line, &size, &res); + return res; +} diff --git a/third_party/ulib/musl/src/passwd/fgetspent.c b/third_party/ulib/musl/src/passwd/fgetspent.c new file mode 100644 index 000000000..ad14d86e0 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/fgetspent.c @@ -0,0 +1,14 @@ +#include "pwf.h" +#include + +struct spwd* fgetspent(FILE* f) { + static char* line; + static struct spwd sp; + size_t size = 0; + struct spwd* res = 0; + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + if (getline(&line, &size, f) >= 0 && __parsespent(line, &sp) >= 0) res = &sp; + pthread_setcancelstate(cs, 0); + return res; +} diff --git a/third_party/ulib/musl/src/passwd/getgr_a.c b/third_party/ulib/musl/src/passwd/getgr_a.c new file mode 100644 index 000000000..1377fbb40 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getgr_a.c @@ -0,0 +1,170 @@ +#include "nscd.h" +#include "pwf.h" +#include +#include +#include +#include + +static char* itoa(char* p, uint32_t x) { + // number of digits in a uint32_t + NUL + p += 11; + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +int __getgr_a(const char* name, gid_t gid, struct group* gr, char** buf, size_t* size, char*** mem, + size_t* nmem, struct group** res) { + FILE* f; + int rv = 0; + int cs; + + *res = 0; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + f = fopen("/etc/group", "rbe"); + if (!f) { + rv = errno; + goto done; + } + + while (!(rv = __getgrent_a(f, gr, buf, size, mem, nmem, res)) && *res) { + if (name && !strcmp(name, (*res)->gr_name) || !name && (*res)->gr_gid == gid) { + break; + } + } + fclose(f); + + if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) { + int32_t req = name ? GETGRBYNAME : GETGRBYGID; + int32_t i; + const char* key; + int32_t groupbuf[GR_LEN] = {0}; + size_t len = 0; + size_t grlist_len = 0; + char gidbuf[11] = {0}; + int swap = 0; + char* ptr; + + if (name) { + key = name; + } else { + if (gid > UINT32_MAX) { + rv = 0; + goto done; + } + key = itoa(gidbuf, gid); + } + + f = __nscd_query(req, key, groupbuf, sizeof groupbuf, &swap); + if (!f) { + rv = errno; + goto done; + } + + if (!groupbuf[GRFOUND]) { + rv = 0; + goto cleanup_f; + } + + if (!groupbuf[GRNAMELEN] || !groupbuf[GRPASSWDLEN]) { + rv = EIO; + goto cleanup_f; + } + + if (groupbuf[GRNAMELEN] > SIZE_MAX - groupbuf[GRPASSWDLEN]) { + rv = ENOMEM; + goto cleanup_f; + } + len = groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN]; + + for (i = 0; i < groupbuf[GRMEMCNT]; i++) { + uint32_t name_len; + if (fread(&name_len, sizeof name_len, 1, f) < 1) { + rv = ferror(f) ? errno : EIO; + goto cleanup_f; + } + if (swap) { + name_len = bswap_32(name_len); + } + if (name_len > SIZE_MAX - grlist_len || name_len > SIZE_MAX - len) { + rv = ENOMEM; + goto cleanup_f; + } + len += name_len; + grlist_len += name_len; + } + + if (len > *size || !*buf) { + char* tmp = realloc(*buf, len); + if (!tmp) { + rv = errno; + goto cleanup_f; + } + *buf = tmp; + *size = len; + } + + if (!fread(*buf, len, 1, f)) { + rv = ferror(f) ? errno : EIO; + goto cleanup_f; + } + + if (groupbuf[GRMEMCNT] + 1 > *nmem) { + if (groupbuf[GRMEMCNT] + 1 > SIZE_MAX / sizeof(char*)) { + rv = ENOMEM; + goto cleanup_f; + } + char** tmp = realloc(*mem, (groupbuf[GRMEMCNT] + 1) * sizeof(char*)); + if (!tmp) { + rv = errno; + goto cleanup_f; + } + *mem = tmp; + *nmem = groupbuf[GRMEMCNT] + 1; + } + + if (groupbuf[GRMEMCNT]) { + mem[0][0] = *buf + groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN]; + for (ptr = mem[0][0], i = 0; ptr != mem[0][0] + grlist_len; ptr++) + if (!*ptr) mem[0][++i] = ptr + 1; + mem[0][i] = 0; + + if (i != groupbuf[GRMEMCNT]) { + rv = EIO; + goto cleanup_f; + } + } else { + mem[0][0] = 0; + } + + gr->gr_name = *buf; + gr->gr_passwd = gr->gr_name + groupbuf[GRNAMELEN]; + gr->gr_gid = groupbuf[GRGID]; + gr->gr_mem = *mem; + + if (gr->gr_passwd[-1] || gr->gr_passwd[groupbuf[GRPASSWDLEN] - 1]) { + rv = EIO; + goto cleanup_f; + } + + if (name && strcmp(name, gr->gr_name) || !name && gid != gr->gr_gid) { + rv = EIO; + goto cleanup_f; + } + + *res = gr; + + cleanup_f: + fclose(f); + goto done; + } + +done: + pthread_setcancelstate(cs, 0); + if (rv) errno = rv; + return rv; +} diff --git a/third_party/ulib/musl/src/passwd/getgr_r.c b/third_party/ulib/musl/src/passwd/getgr_r.c new file mode 100644 index 000000000..554fa6676 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getgr_r.c @@ -0,0 +1,46 @@ +#include "pwf.h" +#include + +#define FIX(x) (gr->gr_##x = gr->gr_##x - line + buf) + +static int getgr_r(const char* name, gid_t gid, struct group* gr, char* buf, size_t size, + struct group** res) { + char* line = 0; + size_t len = 0; + char** mem = 0; + size_t nmem = 0; + int rv = 0; + size_t i; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + rv = __getgr_a(name, gid, gr, &line, &len, &mem, &nmem, res); + if (*res && size < len + (nmem + 1) * sizeof(char*) + 32) { + *res = 0; + rv = ERANGE; + } + if (*res) { + buf += (16 - (uintptr_t)buf) % 16; + gr->gr_mem = (void*)buf; + buf += (nmem + 1) * sizeof(char*); + memcpy(buf, line, len); + FIX(name); + FIX(passwd); + for (i = 0; mem[i]; i++) + gr->gr_mem[i] = mem[i] - line + buf; + gr->gr_mem[i] = 0; + } + free(mem); + free(line); + pthread_setcancelstate(cs, 0); + return rv; +} + +int getgrnam_r(const char* name, struct group* gr, char* buf, size_t size, struct group** res) { + return getgr_r(name, 0, gr, buf, size, res); +} + +int getgrgid_r(gid_t gid, struct group* gr, char* buf, size_t size, struct group** res) { + return getgr_r(0, gid, gr, buf, size, res); +} diff --git a/third_party/ulib/musl/src/passwd/getgrent.c b/third_party/ulib/musl/src/passwd/getgrent.c new file mode 100644 index 000000000..ab0bfe14c --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getgrent.c @@ -0,0 +1,35 @@ +#include "pwf.h" + +static FILE* f; +static char *line, **mem; +static struct group gr; + +void setgrent() { + if (f) fclose(f); + f = 0; +} + +weak_alias(setgrent, endgrent); + +struct group* getgrent() { + struct group* res; + size_t size = 0, nmem = 0; + if (!f) f = fopen("/etc/group", "rbe"); + if (!f) return 0; + __getgrent_a(f, &gr, &line, &size, &mem, &nmem, &res); + return res; +} + +struct group* getgrgid(gid_t gid) { + struct group* res; + size_t size = 0, nmem = 0; + __getgr_a(0, gid, &gr, &line, &size, &mem, &nmem, &res); + return res; +} + +struct group* getgrnam(const char* name) { + struct group* res; + size_t size = 0, nmem = 0; + __getgr_a(name, 0, &gr, &line, &size, &mem, &nmem, &res); + return res; +} diff --git a/third_party/ulib/musl/src/passwd/getgrent_a.c b/third_party/ulib/musl/src/passwd/getgrent_a.c new file mode 100644 index 000000000..e19719cd8 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getgrent_a.c @@ -0,0 +1,71 @@ +#include "pwf.h" +#include + +static unsigned atou(char** s) { + unsigned x; + for (x = 0; **s - '0' < 10U; ++*s) + x = 10 * x + (**s - '0'); + return x; +} + +int __getgrent_a(FILE* f, struct group* gr, char** line, size_t* size, char*** mem, size_t* nmem, + struct group** res) { + ssize_t l; + char *s, *mems; + size_t i; + int rv = 0; + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + for (;;) { + if ((l = getline(line, size, f)) < 0) { + rv = ferror(f) ? errno : 0; + free(*line); + *line = 0; + gr = 0; + goto end; + } + line[0][l - 1] = 0; + + s = line[0]; + gr->gr_name = s++; + if (!(s = strchr(s, ':'))) continue; + + *s++ = 0; + gr->gr_passwd = s; + if (!(s = strchr(s, ':'))) continue; + + *s++ = 0; + gr->gr_gid = atou(&s); + if (*s != ':') continue; + + *s++ = 0; + mems = s; + break; + } + + for (*nmem = !!*s; *s; s++) + if (*s == ',') ++*nmem; + free(*mem); + *mem = calloc(sizeof(char*), *nmem + 1); + if (!*mem) { + rv = errno; + free(*line); + *line = 0; + gr = 0; + goto end; + } + if (*mems) { + mem[0][0] = mems; + for (s = mems, i = 0; *s; s++) + if (*s == ',') *s++ = 0, mem[0][++i] = s; + mem[0][++i] = 0; + } else { + mem[0][0] = 0; + } + gr->gr_mem = *mem; +end: + pthread_setcancelstate(cs, 0); + *res = gr; + if (rv) errno = rv; + return rv; +} diff --git a/third_party/ulib/musl/src/passwd/getgrouplist.c b/third_party/ulib/musl/src/passwd/getgrouplist.c new file mode 100644 index 000000000..f85cd6000 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getgrouplist.c @@ -0,0 +1,79 @@ +#define _GNU_SOURCE +#include "nscd.h" +#include "pwf.h" +#include +#include +#include +#include +#include +#include +#include + +int getgrouplist(const char* user, gid_t gid, gid_t* groups, int* ngroups) { + int rv, nlim, ret = -1; + ssize_t i, n = 1; + struct group gr; + struct group* res; + FILE* f; + int swap = 0; + int32_t resp[INITGR_LEN]; + uint32_t* nscdbuf = 0; + char* buf = 0; + char** mem = 0; + size_t nmem = 0; + size_t size; + nlim = *ngroups; + if (nlim >= 1) *groups++ = gid; + + f = __nscd_query(GETINITGR, user, resp, sizeof resp, &swap); + if (!f) goto cleanup; + if (resp[INITGRFOUND]) { + nscdbuf = calloc(resp[INITGRNGRPS], sizeof(uint32_t)); + if (!nscdbuf) goto cleanup; + if (!fread(nscdbuf, sizeof(*nscdbuf) * resp[INITGRNGRPS], 1, f)) { + if (!ferror(f)) errno = EIO; + goto cleanup; + } + if (swap) { + for (i = 0; i < resp[INITGRNGRPS]; i++) + nscdbuf[i] = bswap_32(nscdbuf[i]); + } + } + fclose(f); + + f = fopen("/etc/group", "rbe"); + if (!f && errno != ENOENT && errno != ENOTDIR) goto cleanup; + + if (f) { + while (!(rv = __getgrent_a(f, &gr, &buf, &size, &mem, &nmem, &res)) && res) { + if (nscdbuf) + for (i = 0; i < resp[INITGRNGRPS]; i++) { + if (nscdbuf[i] == gr.gr_gid) nscdbuf[i] = gid; + } + for (i = 0; gr.gr_mem[i] && strcmp(user, gr.gr_mem[i]); i++) + ; + if (!gr.gr_mem[i]) continue; + if (++n <= nlim) *groups++ = gr.gr_gid; + } + if (rv) { + errno = rv; + goto cleanup; + } + } + if (nscdbuf) { + for (i = 0; i < resp[INITGRNGRPS]; i++) { + if (nscdbuf[i] != gid) + if (++n <= nlim) *groups++ = nscdbuf[i]; + } + } + + ret = n > nlim ? -1 : n; + *ngroups = n; + +cleanup: + if (f) fclose(f); + free(nscdbuf); + free(buf); + free(mem); + return ret; +} diff --git a/third_party/ulib/musl/src/passwd/getpw_a.c b/third_party/ulib/musl/src/passwd/getpw_a.c new file mode 100644 index 000000000..c8594d210 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getpw_a.c @@ -0,0 +1,140 @@ +#include "nscd.h" +#include "pwf.h" +#include +#include +#include +#include + +static char* itoa(char* p, uint32_t x) { + // number of digits in a uint32_t + NUL + p += 11; + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +int __getpw_a(const char* name, uid_t uid, struct passwd* pw, char** buf, size_t* size, + struct passwd** res) { + FILE* f; + int cs; + int rv = 0; + + *res = 0; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + f = fopen("/etc/passwd", "rbe"); + if (!f) { + rv = errno; + goto done; + } + + while (!(rv = __getpwent_a(f, pw, buf, size, res)) && *res) { + if (name && !strcmp(name, (*res)->pw_name) || !name && (*res)->pw_uid == uid) break; + } + fclose(f); + + if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) { + int32_t req = name ? GETPWBYNAME : GETPWBYUID; + const char* key; + int32_t passwdbuf[PW_LEN] = {0}; + size_t len = 0; + char uidbuf[11] = {0}; + + if (name) { + key = name; + } else { + /* uid outside of this range can't be queried with the + * nscd interface, but might happen if uid_t ever + * happens to be a larger type (this is not true as of + * now) + */ + if (uid > UINT32_MAX) { + rv = 0; + goto done; + } + key = itoa(uidbuf, uid); + } + + f = __nscd_query(req, key, passwdbuf, sizeof passwdbuf, (int[]){0}); + if (!f) { + rv = errno; + goto done; + } + + if (!passwdbuf[PWFOUND]) { + rv = 0; + goto cleanup_f; + } + + /* A zero length response from nscd is invalid. We ignore + * invalid responses and just report an error, rather than + * trying to do something with them. + */ + if (!passwdbuf[PWNAMELEN] || !passwdbuf[PWPASSWDLEN] || !passwdbuf[PWGECOSLEN] || + !passwdbuf[PWDIRLEN] || !passwdbuf[PWSHELLLEN]) { + rv = EIO; + goto cleanup_f; + } + + if ((passwdbuf[PWNAMELEN] | passwdbuf[PWPASSWDLEN] | passwdbuf[PWGECOSLEN] | + passwdbuf[PWDIRLEN] | passwdbuf[PWSHELLLEN]) >= SIZE_MAX / 8) { + rv = ENOMEM; + goto cleanup_f; + } + + len = passwdbuf[PWNAMELEN] + passwdbuf[PWPASSWDLEN] + passwdbuf[PWGECOSLEN] + + passwdbuf[PWDIRLEN] + passwdbuf[PWSHELLLEN]; + + if (len > *size || !*buf) { + char* tmp = realloc(*buf, len); + if (!tmp) { + rv = errno; + goto cleanup_f; + } + *buf = tmp; + *size = len; + } + + if (!fread(*buf, len, 1, f)) { + rv = ferror(f) ? errno : EIO; + goto cleanup_f; + } + + pw->pw_name = *buf; + pw->pw_passwd = pw->pw_name + passwdbuf[PWNAMELEN]; + pw->pw_gecos = pw->pw_passwd + passwdbuf[PWPASSWDLEN]; + pw->pw_dir = pw->pw_gecos + passwdbuf[PWGECOSLEN]; + pw->pw_shell = pw->pw_dir + passwdbuf[PWDIRLEN]; + pw->pw_uid = passwdbuf[PWUID]; + pw->pw_gid = passwdbuf[PWGID]; + + /* Don't assume that nscd made sure to null terminate strings. + * It's supposed to, but malicious nscd should be ignored + * rather than causing a crash. + */ + if (pw->pw_passwd[-1] || pw->pw_gecos[-1] || pw->pw_dir[-1] || + pw->pw_shell[passwdbuf[PWSHELLLEN] - 1]) { + rv = EIO; + goto cleanup_f; + } + + if (name && strcmp(name, pw->pw_name) || !name && uid != pw->pw_uid) { + rv = EIO; + goto cleanup_f; + } + + *res = pw; + cleanup_f: + fclose(f); + goto done; + } + +done: + pthread_setcancelstate(cs, 0); + if (rv) errno = rv; + return rv; +} diff --git a/third_party/ulib/musl/src/passwd/getpw_r.c b/third_party/ulib/musl/src/passwd/getpw_r.c new file mode 100644 index 000000000..0bb58ea4a --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getpw_r.c @@ -0,0 +1,39 @@ +#include "pwf.h" +#include + +#define FIX(x) (pw->pw_##x = pw->pw_##x - line + buf) + +static int getpw_r(const char* name, uid_t uid, struct passwd* pw, char* buf, size_t size, + struct passwd** res) { + char* line = 0; + size_t len = 0; + int rv = 0; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + rv = __getpw_a(name, uid, pw, &line, &len, res); + if (*res && size < len) { + *res = 0; + rv = ERANGE; + } + if (*res) { + memcpy(buf, line, len); + FIX(name); + FIX(passwd); + FIX(gecos); + FIX(dir); + FIX(shell); + } + free(line); + pthread_setcancelstate(cs, 0); + return rv; +} + +int getpwnam_r(const char* name, struct passwd* pw, char* buf, size_t size, struct passwd** res) { + return getpw_r(name, 0, pw, buf, size, res); +} + +int getpwuid_r(uid_t uid, struct passwd* pw, char* buf, size_t size, struct passwd** res) { + return getpw_r(0, uid, pw, buf, size, res); +} diff --git a/third_party/ulib/musl/src/passwd/getpwent.c b/third_party/ulib/musl/src/passwd/getpwent.c new file mode 100644 index 000000000..c1ba0ee73 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getpwent.c @@ -0,0 +1,33 @@ +#include "pwf.h" + +static FILE* f; +static char* line; +static struct passwd pw; +static size_t size; + +void setpwent() { + if (f) fclose(f); + f = 0; +} + +weak_alias(setpwent, endpwent); + +struct passwd* getpwent() { + struct passwd* res; + if (!f) f = fopen("/etc/passwd", "rbe"); + if (!f) return 0; + __getpwent_a(f, &pw, &line, &size, &res); + return res; +} + +struct passwd* getpwuid(uid_t uid) { + struct passwd* res; + __getpw_a(0, uid, &pw, &line, &size, &res); + return res; +} + +struct passwd* getpwnam(const char* name) { + struct passwd* res; + __getpw_a(name, 0, &pw, &line, &size, &res); + return res; +} diff --git a/third_party/ulib/musl/src/passwd/getpwent_a.c b/third_party/ulib/musl/src/passwd/getpwent_a.c new file mode 100644 index 000000000..b0ab2ee2b --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getpwent_a.c @@ -0,0 +1,59 @@ +#include "pwf.h" +#include + +static unsigned atou(char** s) { + unsigned x; + for (x = 0; **s - '0' < 10U; ++*s) + x = 10 * x + (**s - '0'); + return x; +} + +int __getpwent_a(FILE* f, struct passwd* pw, char** line, size_t* size, struct passwd** res) { + ssize_t l; + char* s; + int rv = 0; + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + for (;;) { + if ((l = getline(line, size, f)) < 0) { + rv = ferror(f) ? errno : 0; + free(*line); + *line = 0; + pw = 0; + break; + } + line[0][l - 1] = 0; + + s = line[0]; + pw->pw_name = s++; + if (!(s = strchr(s, ':'))) continue; + + *s++ = 0; + pw->pw_passwd = s; + if (!(s = strchr(s, ':'))) continue; + + *s++ = 0; + pw->pw_uid = atou(&s); + if (*s != ':') continue; + + *s++ = 0; + pw->pw_gid = atou(&s); + if (*s != ':') continue; + + *s++ = 0; + pw->pw_gecos = s; + if (!(s = strchr(s, ':'))) continue; + + *s++ = 0; + pw->pw_dir = s; + if (!(s = strchr(s, ':'))) continue; + + *s++ = 0; + pw->pw_shell = s; + break; + } + pthread_setcancelstate(cs, 0); + *res = pw; + if (rv) errno = rv; + return rv; +} diff --git a/third_party/ulib/musl/src/passwd/getspent.c b/third_party/ulib/musl/src/passwd/getspent.c new file mode 100644 index 000000000..2691b8767 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getspent.c @@ -0,0 +1,9 @@ +#include "pwf.h" + +void setspent() {} + +void endspent() {} + +struct spwd* getspent() { + return 0; +} diff --git a/third_party/ulib/musl/src/passwd/getspnam.c b/third_party/ulib/musl/src/passwd/getspnam.c new file mode 100644 index 000000000..c64365eed --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getspnam.c @@ -0,0 +1,16 @@ +#include "pwf.h" + +#define LINE_LIM 256 + +struct spwd* getspnam(const char* name) { + static struct spwd sp; + static char* line; + struct spwd* res; + int e; + + if (!line) line = malloc(LINE_LIM); + if (!line) return 0; + e = getspnam_r(name, &sp, line, LINE_LIM, &res); + if (e) errno = e; + return res; +} diff --git a/third_party/ulib/musl/src/passwd/getspnam_r.c b/third_party/ulib/musl/src/passwd/getspnam_r.c new file mode 100644 index 000000000..ab0d8c94c --- /dev/null +++ b/third_party/ulib/musl/src/passwd/getspnam_r.c @@ -0,0 +1,118 @@ +#include "pwf.h" +#include +#include +#include +#include +#include + +/* This implementation support Openwall-style TCB passwords in place of + * traditional shadow, if the appropriate directories and files exist. + * Thus, it is careful to avoid following symlinks or blocking on fifos + * which a malicious user might create in place of his or her TCB shadow + * file. It also avoids any allocation to prevent memory-exhaustion + * attacks via huge TCB shadow files. */ + +static long xatol(char** s) { + long x; + if (**s == ':' || **s == '\n') return -1; + for (x = 0; **s - '0' < 10U; ++*s) + x = 10 * x + (**s - '0'); + return x; +} + +int __parsespent(char* s, struct spwd* sp) { + sp->sp_namp = s; + if (!(s = strchr(s, ':'))) return -1; + *s = 0; + + sp->sp_pwdp = ++s; + if (!(s = strchr(s, ':'))) return -1; + *s = 0; + + s++; + sp->sp_lstchg = xatol(&s); + if (*s != ':') return -1; + + s++; + sp->sp_min = xatol(&s); + if (*s != ':') return -1; + + s++; + sp->sp_max = xatol(&s); + if (*s != ':') return -1; + + s++; + sp->sp_warn = xatol(&s); + if (*s != ':') return -1; + + s++; + sp->sp_inact = xatol(&s); + if (*s != ':') return -1; + + s++; + sp->sp_expire = xatol(&s); + if (*s != ':') return -1; + + s++; + sp->sp_flag = xatol(&s); + if (*s != '\n') return -1; + return 0; +} + +static void cleanup(void* p) { + fclose(p); +} + +int getspnam_r(const char* name, struct spwd* sp, char* buf, size_t size, struct spwd** res) { + char path[20 + NAME_MAX]; + FILE* f = 0; + int rv = 0; + int fd; + size_t k, l = strlen(name); + int skip = 0; + int cs; + + *res = 0; + + /* Disallow potentially-malicious user names */ + if (*name == '.' || strchr(name, '/') || !l) return EINVAL; + + /* Buffer size must at least be able to hold name, plus some.. */ + if (size < l + 100) return ERANGE; + + /* Protect against truncation */ + if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path) return EINVAL; + + fd = open(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_CLOEXEC); + if (fd >= 0) { + struct stat st = {0}; + errno = EINVAL; + if (fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + close(fd); + pthread_setcancelstate(cs, 0); + return errno; + } + } else { + f = fopen("/etc/shadow", "rbe"); + if (!f) return errno; + } + + pthread_cleanup_push(cleanup, f); + while (fgets(buf, size, f) && (k = strlen(buf)) > 0) { + if (skip || strncmp(name, buf, l) || buf[l] != ':') { + skip = buf[k - 1] != '\n'; + continue; + } + if (buf[k - 1] != '\n') { + rv = ERANGE; + break; + } + + if (__parsespent(buf, sp) < 0) continue; + *res = sp; + break; + } + pthread_cleanup_pop(1); + return rv; +} diff --git a/third_party/ulib/musl/src/passwd/lckpwdf.c b/third_party/ulib/musl/src/passwd/lckpwdf.c new file mode 100644 index 000000000..b6359e6fc --- /dev/null +++ b/third_party/ulib/musl/src/passwd/lckpwdf.c @@ -0,0 +1,9 @@ +#include + +int lckpwdf() { + return 0; +} + +int ulckpwdf() { + return 0; +} diff --git a/third_party/ulib/musl/src/passwd/nscd.h b/third_party/ulib/musl/src/passwd/nscd.h new file mode 100644 index 000000000..bfa6f4ab7 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/nscd.h @@ -0,0 +1,49 @@ +#ifndef NSCD_H +#define NSCD_H + +#include + +#define __NEED_FILE +#define __NEED_size_t + +#include + +#define NSCDVERSION 2 +#define GETPWBYNAME 0 +#define GETPWBYUID 1 +#define GETGRBYNAME 2 +#define GETGRBYGID 3 +#define GETINITGR 15 + +#define REQVERSION 0 +#define REQTYPE 1 +#define REQKEYLEN 2 +#define REQ_LEN 3 + +#define PWVERSION 0 +#define PWFOUND 1 +#define PWNAMELEN 2 +#define PWPASSWDLEN 3 +#define PWUID 4 +#define PWGID 5 +#define PWGECOSLEN 6 +#define PWDIRLEN 7 +#define PWSHELLLEN 8 +#define PW_LEN 9 + +#define GRVERSION 0 +#define GRFOUND 1 +#define GRNAMELEN 2 +#define GRPASSWDLEN 3 +#define GRGID 4 +#define GRMEMCNT 5 +#define GR_LEN 6 + +#define INITGRVERSION 0 +#define INITGRFOUND 1 +#define INITGRNGRPS 2 +#define INITGR_LEN 3 + +FILE* __nscd_query(int32_t req, const char* key, int32_t* buf, size_t len, int* swap); + +#endif diff --git a/third_party/ulib/musl/src/passwd/nscd_query.c b/third_party/ulib/musl/src/passwd/nscd_query.c new file mode 100644 index 000000000..293f465fd --- /dev/null +++ b/third_party/ulib/musl/src/passwd/nscd_query.c @@ -0,0 +1,93 @@ +#include "nscd.h" +#include +#include +#include +#include +#include +#include +#include + +static const struct { + short sun_family; + char sun_path[21]; +} addr = {AF_UNIX, "/var/run/nscd/socket"}; + +FILE* __nscd_query(int32_t req, const char* key, int32_t* buf, size_t len, int* swap) { + size_t i; + int fd; + FILE* f = 0; + int32_t req_buf[REQ_LEN] = {NSCDVERSION, req, strnlen(key, LOGIN_NAME_MAX) + 1}; + struct msghdr msg = { + .msg_iov = (struct iovec[]){{&req_buf, sizeof(req_buf)}, {(char*)key, strlen(key) + 1}}, + .msg_iovlen = 2}; + int errno_save = errno; + + *swap = 0; +retry: + memset(buf, 0, len); + buf[0] = NSCDVERSION; + + fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) return NULL; + + if (!(f = fdopen(fd, "r"))) { + close(fd); + return 0; + } + + if (req_buf[2] > LOGIN_NAME_MAX) return f; + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + /* If there isn't a running nscd we simulate a "not found" + * result and the caller is responsible for calling + * fclose on the (unconnected) socket. The value of + * errno must be left unchanged in this case. */ + if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) { + errno = errno_save; + return f; + } + goto error; + } + + if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 0) goto error; + + if (!fread(buf, len, 1, f)) { + /* If the VERSION entry mismatches nscd will disconnect. The + * most likely cause is that the endianness mismatched. So, we + * byteswap and try once more. (if we already swapped, just + * fail out) + */ + if (ferror(f)) goto error; + if (!*swap) { + fclose(f); + for (i = 0; i < sizeof(req_buf) / sizeof(req_buf[0]); i++) { + req_buf[i] = bswap_32(req_buf[i]); + } + *swap = 1; + goto retry; + } else { + errno = EIO; + goto error; + } + } + + if (*swap) { + for (i = 0; i < len / sizeof(buf[0]); i++) { + buf[i] = bswap_32(buf[i]); + } + } + + /* The first entry in every nscd response is the version number. This + * really shouldn't happen, and is evidence of some form of malformed + * response. + */ + if (buf[0] != NSCDVERSION) { + errno = EIO; + goto error; + } + + return f; +error: + fclose(f); + return 0; +} diff --git a/third_party/ulib/musl/src/passwd/putgrent.c b/third_party/ulib/musl/src/passwd/putgrent.c new file mode 100644 index 000000000..4c05a5d68 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/putgrent.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include +#include + +int putgrent(const struct group* gr, FILE* f) { + int r; + size_t i; + flockfile(f); + if ((r = fprintf(f, "%s:%s:%d:", gr->gr_name, gr->gr_passwd, gr->gr_gid)) < 0) goto done; + if (gr->gr_mem) + for (i = 0; gr->gr_mem[i]; i++) + if ((r = fprintf(f, "%s%s", i ? "," : "", gr->gr_mem[i])) < 0) goto done; + r = fputc('\n', f); +done: + funlockfile(f); + return r < 0 ? -1 : 0; +} diff --git a/third_party/ulib/musl/src/passwd/putpwent.c b/third_party/ulib/musl/src/passwd/putpwent.c new file mode 100644 index 000000000..fe0b24034 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/putpwent.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include +#include + +int putpwent(const struct passwd* pw, FILE* f) { + return fprintf(f, "%s:%s:%d:%d:%s:%s:%s\n", pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, + pw->pw_gecos, pw->pw_dir, pw->pw_shell) < 0 + ? -1 + : 0; +} diff --git a/third_party/ulib/musl/src/passwd/putspent.c b/third_party/ulib/musl/src/passwd/putspent.c new file mode 100644 index 000000000..e92ab5435 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/putspent.c @@ -0,0 +1,13 @@ +#include +#include + +#define NUM(n) ((n) == -1 ? 0 : -1), ((n) == -1 ? 0 : (n)) +#define STR(s) ((s) ? (s) : "") + +int putspent(const struct spwd* sp, FILE* f) { + return fprintf(f, "%s:%s:%.*ld:%.*ld:%.*ld:%.*ld:%.*ld:%.*ld:%.*lu\n", STR(sp->sp_namp), + STR(sp->sp_pwdp), NUM(sp->sp_lstchg), NUM(sp->sp_min), NUM(sp->sp_max), + NUM(sp->sp_warn), NUM(sp->sp_inact), NUM(sp->sp_expire), NUM(sp->sp_flag)) < 0 + ? -1 + : 0; +} diff --git a/third_party/ulib/musl/src/passwd/pwf.h b/third_party/ulib/musl/src/passwd/pwf.h new file mode 100644 index 000000000..ed0a3ea07 --- /dev/null +++ b/third_party/ulib/musl/src/passwd/pwf.h @@ -0,0 +1,18 @@ +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int __getpwent_a(FILE* f, struct passwd* pw, char** line, size_t* size, struct passwd** res); +int __getpw_a(const char* name, uid_t uid, struct passwd* pw, char** buf, size_t* size, + struct passwd** res); +int __getgrent_a(FILE* f, struct group* gr, char** line, size_t* size, char*** mem, size_t* nmem, + struct group** res); +int __getgr_a(const char* name, gid_t gid, struct group* gr, char** buf, size_t* size, char*** mem, + size_t* nmem, struct group** res); +int __parsespent(char* s, struct spwd* sp); diff --git a/third_party/ulib/musl/src/prng/BUILD.gn b/third_party/ulib/musl/src/prng/BUILD.gn new file mode 100644 index 000000000..f764ef542 --- /dev/null +++ b/third_party/ulib/musl/src/prng/BUILD.gn @@ -0,0 +1,18 @@ +source_set("prng") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__rand48_step.c", + "__seed48.c", + "drand48.c", + "lcong48.c", + "lrand48.c", + "mrand48.c", + "rand.c", + "rand_r.c", + "seed48.c", + "srand48.c", + ] +} diff --git a/third_party/ulib/musl/src/prng/__rand48_step.c b/third_party/ulib/musl/src/prng/__rand48_step.c new file mode 100644 index 000000000..b61d3d003 --- /dev/null +++ b/third_party/ulib/musl/src/prng/__rand48_step.c @@ -0,0 +1,12 @@ +#include + +uint64_t __rand48_step(unsigned short* xi, unsigned short* lc) { + uint64_t a, x; + x = xi[0] | xi[1] + 0U << 16 | xi[2] + 0ULL << 32; + a = lc[0] | lc[1] + 0U << 16 | lc[2] + 0ULL << 32; + x = a * x + lc[3]; + xi[0] = x; + xi[1] = x >> 16; + xi[2] = x >> 32; + return x & 0xffffffffffffull; +} diff --git a/third_party/ulib/musl/src/prng/__seed48.c b/third_party/ulib/musl/src/prng/__seed48.c new file mode 100644 index 000000000..a218ac345 --- /dev/null +++ b/third_party/ulib/musl/src/prng/__seed48.c @@ -0,0 +1 @@ +unsigned short __seed48[7] = {0, 0, 0, 0xe66d, 0xdeec, 0x5, 0xb}; diff --git a/third_party/ulib/musl/src/prng/drand48.c b/third_party/ulib/musl/src/prng/drand48.c new file mode 100644 index 000000000..51dcf2ecc --- /dev/null +++ b/third_party/ulib/musl/src/prng/drand48.c @@ -0,0 +1,17 @@ +#include +#include + +uint64_t __rand48_step(unsigned short* xi, unsigned short* lc); +extern unsigned short __seed48[7]; + +double erand48(unsigned short s[3]) { + union { + uint64_t u; + double f; + } x = {0x3ff0000000000000ULL | __rand48_step(s, __seed48 + 3) << 4}; + return x.f - 1.0; +} + +double drand48(void) { + return erand48(__seed48); +} diff --git a/third_party/ulib/musl/src/prng/lcong48.c b/third_party/ulib/musl/src/prng/lcong48.c new file mode 100644 index 000000000..f93e5ab01 --- /dev/null +++ b/third_party/ulib/musl/src/prng/lcong48.c @@ -0,0 +1,8 @@ +#include +#include + +extern unsigned short __seed48[7]; + +void lcong48(unsigned short p[7]) { + memcpy(__seed48, p, sizeof __seed48); +} diff --git a/third_party/ulib/musl/src/prng/lrand48.c b/third_party/ulib/musl/src/prng/lrand48.c new file mode 100644 index 000000000..b233d5546 --- /dev/null +++ b/third_party/ulib/musl/src/prng/lrand48.c @@ -0,0 +1,13 @@ +#include +#include + +uint64_t __rand48_step(unsigned short* xi, unsigned short* lc); +extern unsigned short __seed48[7]; + +long nrand48(unsigned short s[3]) { + return __rand48_step(s, __seed48 + 3) >> 17; +} + +long lrand48(void) { + return nrand48(__seed48); +} diff --git a/third_party/ulib/musl/src/prng/mrand48.c b/third_party/ulib/musl/src/prng/mrand48.c new file mode 100644 index 000000000..179f6838e --- /dev/null +++ b/third_party/ulib/musl/src/prng/mrand48.c @@ -0,0 +1,13 @@ +#include +#include + +uint64_t __rand48_step(unsigned short* xi, unsigned short* lc); +extern unsigned short __seed48[7]; + +long jrand48(unsigned short s[3]) { + return __rand48_step(s, __seed48 + 3) >> 16; +} + +long mrand48(void) { + return jrand48(__seed48); +} diff --git a/third_party/ulib/musl/src/prng/rand.c b/third_party/ulib/musl/src/prng/rand.c new file mode 100644 index 000000000..0eaa27607 --- /dev/null +++ b/third_party/ulib/musl/src/prng/rand.c @@ -0,0 +1,13 @@ +#include +#include + +static uint64_t seed; + +void srand(unsigned s) { + seed = s - 1; +} + +int rand(void) { + seed = 6364136223846793005ULL * seed + 1; + return seed >> 33; +} diff --git a/third_party/ulib/musl/src/prng/rand_r.c b/third_party/ulib/musl/src/prng/rand_r.c new file mode 100644 index 000000000..897cd5120 --- /dev/null +++ b/third_party/ulib/musl/src/prng/rand_r.c @@ -0,0 +1,13 @@ +#include + +static unsigned temper(unsigned x) { + x ^= x >> 11; + x ^= x << 7 & 0x9D2C5680; + x ^= x << 15 & 0xEFC60000; + x ^= x >> 18; + return x; +} + +int rand_r(unsigned* seed) { + return temper(*seed = *seed * 1103515245 + 12345) / 2; +} diff --git a/third_party/ulib/musl/src/prng/seed48.c b/third_party/ulib/musl/src/prng/seed48.c new file mode 100644 index 000000000..e30e656fc --- /dev/null +++ b/third_party/ulib/musl/src/prng/seed48.c @@ -0,0 +1,11 @@ +#include +#include + +extern unsigned short __seed48[7]; + +unsigned short* seed48(unsigned short* s) { + static unsigned short p[3]; + memcpy(p, __seed48, sizeof p); + memcpy(__seed48, s, sizeof p); + return p; +} diff --git a/third_party/ulib/musl/src/prng/srand48.c b/third_party/ulib/musl/src/prng/srand48.c new file mode 100644 index 000000000..457ad2d20 --- /dev/null +++ b/third_party/ulib/musl/src/prng/srand48.c @@ -0,0 +1,5 @@ +#include + +void srand48(long seed) { + seed48((unsigned short[3]){0x330e, seed, seed >> 16}); +} diff --git a/third_party/ulib/musl/src/process/BUILD.gn b/third_party/ulib/musl/src/process/BUILD.gn new file mode 100644 index 000000000..32791570a --- /dev/null +++ b/third_party/ulib/musl/src/process/BUILD.gn @@ -0,0 +1,43 @@ +source_set("process") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "execl.c", + "execle.c", + "execlp.c", + "execv.c", + "execve.c", + "execvp.c", + "fexecve.c", + "fork.c", + "posix_spawn.c", + "posix_spawn_file_actions_addclose.c", + "posix_spawn_file_actions_adddup2.c", + "posix_spawn_file_actions_addopen.c", + "posix_spawn_file_actions_destroy.c", + "posix_spawn_file_actions_init.c", + "posix_spawnattr_destroy.c", + "posix_spawnattr_getflags.c", + "posix_spawnattr_getpgroup.c", + "posix_spawnattr_getsigdefault.c", + "posix_spawnattr_getsigmask.c", + "posix_spawnattr_init.c", + "posix_spawnattr_sched.c", + "posix_spawnattr_setflags.c", + "posix_spawnattr_setpgroup.c", + "posix_spawnattr_setsigdefault.c", + "posix_spawnattr_setsigmask.c", + "posix_spawnp.c", + "system.c", + "wait.c", + "waitid.c", + "waitpid.c", + ] + if (target_cpu == "x64") { + sources += [ "x86_64/vfork.s" ] + } else { + sources += [ "vfork.c" ] + } +} diff --git a/third_party/ulib/musl/src/process/execl.c b/third_party/ulib/musl/src/process/execl.c new file mode 100644 index 000000000..d0e73fe31 --- /dev/null +++ b/third_party/ulib/musl/src/process/execl.c @@ -0,0 +1,22 @@ +#include +#include + +int execl(const char* path, const char* argv0, ...) { + int argc; + va_list ap; + va_start(ap, argv0); + for (argc = 1; va_arg(ap, const char*); argc++) + ; + va_end(ap); + { + int i; + char* argv[argc + 1]; + va_start(ap, argv0); + argv[0] = (char*)argv0; + for (i = 1; i < argc; i++) + argv[i] = va_arg(ap, char*); + argv[i] = NULL; + va_end(ap); + return execv(path, argv); + } +} diff --git a/third_party/ulib/musl/src/process/execle.c b/third_party/ulib/musl/src/process/execle.c new file mode 100644 index 000000000..5d9d824f7 --- /dev/null +++ b/third_party/ulib/musl/src/process/execle.c @@ -0,0 +1,23 @@ +#include +#include + +int execle(const char* path, const char* argv0, ...) { + int argc; + va_list ap; + va_start(ap, argv0); + for (argc = 1; va_arg(ap, const char*); argc++) + ; + va_end(ap); + { + int i; + char* argv[argc + 1]; + char** envp; + va_start(ap, argv0); + argv[0] = (char*)argv0; + for (i = 1; i <= argc; i++) + argv[i] = va_arg(ap, char*); + envp = va_arg(ap, char**); + va_end(ap); + return execve(path, argv, envp); + } +} diff --git a/third_party/ulib/musl/src/process/execlp.c b/third_party/ulib/musl/src/process/execlp.c new file mode 100644 index 000000000..3f97cc31d --- /dev/null +++ b/third_party/ulib/musl/src/process/execlp.c @@ -0,0 +1,22 @@ +#include +#include + +int execlp(const char* file, const char* argv0, ...) { + int argc; + va_list ap; + va_start(ap, argv0); + for (argc = 1; va_arg(ap, const char*); argc++) + ; + va_end(ap); + { + int i; + char* argv[argc + 1]; + va_start(ap, argv0); + argv[0] = (char*)argv0; + for (i = 1; i < argc; i++) + argv[i] = va_arg(ap, char*); + argv[i] = NULL; + va_end(ap); + return execvp(file, argv); + } +} diff --git a/third_party/ulib/musl/src/process/execv.c b/third_party/ulib/musl/src/process/execv.c new file mode 100644 index 000000000..89a698c79 --- /dev/null +++ b/third_party/ulib/musl/src/process/execv.c @@ -0,0 +1,7 @@ +#include + +extern char** __environ; + +int execv(const char* path, char* const argv[]) { + return execve(path, argv, __environ); +} diff --git a/third_party/ulib/musl/src/process/execve.c b/third_party/ulib/musl/src/process/execve.c new file mode 100644 index 000000000..41f26052f --- /dev/null +++ b/third_party/ulib/musl/src/process/execve.c @@ -0,0 +1,7 @@ +#include "syscall.h" +#include + +int execve(const char* path, char* const argv[], char* const envp[]) { + /* do we need to use environ if envp is null? */ + return syscall(SYS_execve, path, argv, envp); +} diff --git a/third_party/ulib/musl/src/process/execvp.c b/third_party/ulib/musl/src/process/execvp.c new file mode 100644 index 000000000..b1ff20c83 --- /dev/null +++ b/third_party/ulib/musl/src/process/execvp.c @@ -0,0 +1,54 @@ +#include "libc.h" +#include +#include +#include +#include +#include + +extern char** __environ; + +int __execvpe(const char* file, char* const argv[], char* const envp[]) { + const char *p, *z, *path = getenv("PATH"); + size_t l, k; + int seen_eacces = 0; + + errno = ENOENT; + if (!*file) return -1; + + if (strchr(file, '/')) return execve(file, argv, envp); + + if (!path) path = "/usr/local/bin:/bin:/usr/bin"; + k = strnlen(file, NAME_MAX + 1); + if (k > NAME_MAX) { + errno = ENAMETOOLONG; + return -1; + } + l = strnlen(path, PATH_MAX - 1) + 1; + + for (p = path;; p = z) { + char b[l + k + 1]; + z = strchr(p, ':'); + if (!z) z = p + strlen(p); + if (z - p >= l) { + if (!*z++) break; + continue; + } + memcpy(b, p, z - p); + b[z - p] = '/'; + memcpy(b + (z - p) + (z > p), file, k + 1); + execve(b, argv, envp); + if (errno == EACCES) + seen_eacces = 1; + else if (errno != ENOENT) + return -1; + if (!*z++) break; + } + if (seen_eacces) errno = EACCES; + return -1; +} + +int execvp(const char* file, char* const argv[]) { + return __execvpe(file, argv, __environ); +} + +weak_alias(__execvpe, execvpe); diff --git a/third_party/ulib/musl/src/process/fdop.h b/third_party/ulib/musl/src/process/fdop.h new file mode 100644 index 000000000..a41fc51cc --- /dev/null +++ b/third_party/ulib/musl/src/process/fdop.h @@ -0,0 +1,14 @@ +#define FDOP_CLOSE 1 +#define FDOP_DUP2 2 +#define FDOP_OPEN 3 + +#define __NEED_mode_t + +#include + +struct fdop { + struct fdop *next, *prev; + int cmd, fd, srcfd, oflag; + mode_t mode; + char path[]; +}; diff --git a/third_party/ulib/musl/src/process/fexecve.c b/third_party/ulib/musl/src/process/fexecve.c new file mode 100644 index 000000000..a63c28eca --- /dev/null +++ b/third_party/ulib/musl/src/process/fexecve.c @@ -0,0 +1,12 @@ +#include +#include + +void __procfdname(char*, unsigned); + +int fexecve(int fd, char* const argv[], char* const envp[]) { + char buf[15 + 3 * sizeof(int)]; + __procfdname(buf, fd); + execve(buf, argv, envp); + if (errno == ENOENT) errno = EBADF; + return -1; +} diff --git a/third_party/ulib/musl/src/process/fork.c b/third_party/ulib/musl/src/process/fork.c new file mode 100644 index 000000000..09c45dd96 --- /dev/null +++ b/third_party/ulib/musl/src/process/fork.c @@ -0,0 +1,31 @@ +#include "libc.h" +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include + +static void dummy(int x) {} + +weak_alias(dummy, __fork_handler); + +pid_t fork(void) { + pid_t ret; + sigset_t set; + __fork_handler(-1); + __block_all_sigs(&set); +#ifdef SYS_fork + ret = syscall(SYS_fork); +#else + ret = syscall(SYS_clone, SIGCHLD, 0); +#endif + if (!ret) { + pthread_t self = __pthread_self(); + self->tid = __syscall(SYS_gettid); + self->robust_list.off = 0; + self->robust_list.pending = 0; + } + __restore_sigs(&set); + __fork_handler(!ret); + return ret; +} diff --git a/third_party/ulib/musl/src/process/posix_spawn.c b/third_party/ulib/musl/src/process/posix_spawn.c new file mode 100644 index 000000000..77d62be33 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawn.c @@ -0,0 +1,187 @@ +#define _GNU_SOURCE +#include "fdop.h" +#include "libc.h" +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include +#include +#include +#include + +struct args { + int p[2]; + sigset_t oldmask; + const char* path; + int (*exec)(const char*, char* const*, char* const*); + const posix_spawn_file_actions_t* fa; + const posix_spawnattr_t* restrict attr; + char *const *argv, *const *envp; +}; + +void __get_handler_set(sigset_t*); + +static int __sys_dup2(int old, int new) { +#ifdef SYS_dup2 + return __syscall(SYS_dup2, old, new); +#else + if (old == new) { + int r = __syscall(SYS_fcntl, old, F_GETFD); + return r < 0 ? r : old; + } else { + return __syscall(SYS_dup3, old, new, 0); + } +#endif +} + +static int child(void* args_vp) { + int i, ret; + struct sigaction sa = {0}; + struct args* args = args_vp; + int p = args->p[1]; + const posix_spawn_file_actions_t* fa = args->fa; + const posix_spawnattr_t* restrict attr = args->attr; + sigset_t hset; + + close(args->p[0]); + + /* All signal dispositions must be either SIG_DFL or SIG_IGN + * before signals are unblocked. Otherwise a signal handler + * from the parent might get run in the child while sharing + * memory, with unpredictable and dangerous results. To + * reduce overhead, sigaction has tracked for us which signals + * potentially have a signal handler. */ + __get_handler_set(&hset); + for (i = 1; i < _NSIG; i++) { + if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) && sigismember(&attr->__def, i)) { + sa.sa_handler = SIG_DFL; + } else if (sigismember(&hset, i)) { + if (i - 32 < 3U) { + sa.sa_handler = SIG_IGN; + } else { + __libc_sigaction(i, 0, &sa); + if (sa.sa_handler == SIG_IGN) continue; + sa.sa_handler = SIG_DFL; + } + } else { + continue; + } + __libc_sigaction(i, &sa, 0); + } + + if (attr->__flags & POSIX_SPAWN_SETPGROUP) + if ((ret = __syscall(SYS_setpgid, 0, attr->__pgrp))) goto fail; + + /* Use syscalls directly because the library functions attempt + * to do a multi-threaded synchronized id-change, which would + * trash the parent's state. */ + if (attr->__flags & POSIX_SPAWN_RESETIDS) + if ((ret = __syscall(SYS_setgid, __syscall(SYS_getgid))) || + (ret = __syscall(SYS_setuid, __syscall(SYS_getuid)))) + goto fail; + + if (fa && fa->__actions) { + struct fdop* op; + int fd; + for (op = fa->__actions; op->next; op = op->next) + ; + for (; op; op = op->prev) { + /* It's possible that a file operation would clobber + * the pipe fd used for synchronizing with the + * parent. To avoid that, we dup the pipe onto + * an unoccupied fd. */ + if (op->fd == p) { + ret = __syscall(SYS_dup, p); + if (ret < 0) goto fail; + __syscall(SYS_close, p); + p = ret; + } + switch (op->cmd) { + case FDOP_CLOSE: + __syscall(SYS_close, op->fd); + break; + case FDOP_DUP2: + if ((ret = __sys_dup2(op->srcfd, op->fd)) < 0) goto fail; + break; + case FDOP_OPEN: + fd = __sys_open(op->path, op->oflag, op->mode); + if ((ret = fd) < 0) goto fail; + if (fd != op->fd) { + if ((ret = __sys_dup2(fd, op->fd)) < 0) goto fail; + __syscall(SYS_close, fd); + } + break; + } + } + } + + /* Close-on-exec flag may have been lost if we moved the pipe + * to a different fd. We don't use F_DUPFD_CLOEXEC above because + * it would fail on older kernels and atomicity is not needed -- + * in this process there are no threads or signal handlers. */ + __syscall(SYS_fcntl, p, F_SETFD, FD_CLOEXEC); + + pthread_sigmask(SIG_SETMASK, + (attr->__flags & POSIX_SPAWN_SETSIGMASK) ? &attr->__mask : &args->oldmask, 0); + + args->exec(args->path, args->argv, args->envp); + ret = -errno; + +fail: + /* Since sizeof errno < PIPE_BUF, the write is atomic. */ + ret = -ret; + if (ret) + while (__syscall(SYS_write, p, &ret, sizeof ret) < 0) + ; + _exit(127); +} + +int __posix_spawnx(pid_t* restrict res, const char* restrict path, + int (*exec)(const char*, char* const*, char* const*), + const posix_spawn_file_actions_t* fa, const posix_spawnattr_t* restrict attr, + char* const argv[restrict], char* const envp[restrict]) { + pid_t pid; + char stack[1024]; + int ec = 0, cs; + struct args args; + + if (pipe2(args.p, O_CLOEXEC)) return errno; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + args.path = path; + args.exec = exec; + args.fa = fa; + args.attr = attr ? attr : &(const posix_spawnattr_t){0}; + args.argv = argv; + args.envp = envp; + pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask); + + pid = __clone(child, stack + sizeof stack, CLONE_VM | CLONE_VFORK | SIGCHLD, &args); + close(args.p[1]); + + if (pid > 0) { + if (read(args.p[0], &ec, sizeof ec) != sizeof ec) + ec = 0; + else + waitpid(pid, &(int){0}, 0); + } else { + ec = -pid; + } + + close(args.p[0]); + + if (!ec && res) *res = pid; + + pthread_sigmask(SIG_SETMASK, &args.oldmask, 0); + pthread_setcancelstate(cs, 0); + + return ec; +} + +int posix_spawn(pid_t* restrict res, const char* restrict path, + const posix_spawn_file_actions_t* fa, const posix_spawnattr_t* restrict attr, + char* const argv[restrict], char* const envp[restrict]) { + return __posix_spawnx(res, path, execve, fa, attr, argv, envp); +} diff --git a/third_party/ulib/musl/src/process/posix_spawn_file_actions_addclose.c b/third_party/ulib/musl/src/process/posix_spawn_file_actions_addclose.c new file mode 100644 index 000000000..b8834a85b --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawn_file_actions_addclose.c @@ -0,0 +1,15 @@ +#include "fdop.h" +#include +#include +#include + +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t* fa, int fd) { + struct fdop* op = malloc(sizeof *op); + if (!op) return ENOMEM; + op->cmd = FDOP_CLOSE; + op->fd = fd; + if ((op->next = fa->__actions)) op->next->prev = op; + op->prev = 0; + fa->__actions = op; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawn_file_actions_adddup2.c b/third_party/ulib/musl/src/process/posix_spawn_file_actions_adddup2.c new file mode 100644 index 000000000..2a57a0637 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawn_file_actions_adddup2.c @@ -0,0 +1,16 @@ +#include "fdop.h" +#include +#include +#include + +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* fa, int srcfd, int fd) { + struct fdop* op = malloc(sizeof *op); + if (!op) return ENOMEM; + op->cmd = FDOP_DUP2; + op->srcfd = srcfd; + op->fd = fd; + if ((op->next = fa->__actions)) op->next->prev = op; + op->prev = 0; + fa->__actions = op; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawn_file_actions_addopen.c b/third_party/ulib/musl/src/process/posix_spawn_file_actions_addopen.c new file mode 100644 index 000000000..1356898a0 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawn_file_actions_addopen.c @@ -0,0 +1,20 @@ +#include "fdop.h" +#include +#include +#include +#include + +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* restrict fa, int fd, + const char* restrict path, int flags, mode_t mode) { + struct fdop* op = malloc(sizeof *op + strlen(path) + 1); + if (!op) return ENOMEM; + op->cmd = FDOP_OPEN; + op->fd = fd; + op->oflag = flags; + op->mode = mode; + strcpy(op->path, path); + if ((op->next = fa->__actions)) op->next->prev = op; + op->prev = 0; + fa->__actions = op; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawn_file_actions_destroy.c b/third_party/ulib/musl/src/process/posix_spawn_file_actions_destroy.c new file mode 100644 index 000000000..2d5f5b063 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawn_file_actions_destroy.c @@ -0,0 +1,13 @@ +#include "fdop.h" +#include +#include + +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* fa) { + struct fdop *op = fa->__actions, *next; + while (op) { + next = op->next; + free(op); + op = next; + } + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawn_file_actions_init.c b/third_party/ulib/musl/src/process/posix_spawn_file_actions_init.c new file mode 100644 index 000000000..98b59bf45 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawn_file_actions_init.c @@ -0,0 +1,6 @@ +#include + +int posix_spawn_file_actions_init(posix_spawn_file_actions_t* fa) { + fa->__actions = 0; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_destroy.c b/third_party/ulib/musl/src/process/posix_spawnattr_destroy.c new file mode 100644 index 000000000..5684c7935 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_destroy.c @@ -0,0 +1,5 @@ +#include + +int posix_spawnattr_destroy(posix_spawnattr_t* attr) { + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_getflags.c b/third_party/ulib/musl/src/process/posix_spawnattr_getflags.c new file mode 100644 index 000000000..072b9bae9 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_getflags.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_getflags(const posix_spawnattr_t* restrict attr, short* restrict flags) { + *flags = attr->__flags; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_getpgroup.c b/third_party/ulib/musl/src/process/posix_spawnattr_getpgroup.c new file mode 100644 index 000000000..fe20309a7 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_getpgroup.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_getpgroup(const posix_spawnattr_t* restrict attr, pid_t* restrict pgrp) { + *pgrp = attr->__pgrp; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_getsigdefault.c b/third_party/ulib/musl/src/process/posix_spawnattr_getsigdefault.c new file mode 100644 index 000000000..de6089d4b --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_getsigdefault.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_getsigdefault(const posix_spawnattr_t* restrict attr, sigset_t* restrict def) { + *def = attr->__def; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_getsigmask.c b/third_party/ulib/musl/src/process/posix_spawnattr_getsigmask.c new file mode 100644 index 000000000..9bca615eb --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_getsigmask.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_getsigmask(const posix_spawnattr_t* restrict attr, sigset_t* restrict mask) { + *mask = attr->__mask; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_init.c b/third_party/ulib/musl/src/process/posix_spawnattr_init.c new file mode 100644 index 000000000..db818d89c --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_init.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_init(posix_spawnattr_t* attr) { + *attr = (posix_spawnattr_t){0}; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_sched.c b/third_party/ulib/musl/src/process/posix_spawnattr_sched.c new file mode 100644 index 000000000..395db874f --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_sched.c @@ -0,0 +1,21 @@ +#include +#include +#include + +int posix_spawnattr_getschedparam(const posix_spawnattr_t* restrict attr, + struct sched_param* restrict schedparam) { + return ENOSYS; +} + +int posix_spawnattr_setschedparam(posix_spawnattr_t* restrict attr, + const struct sched_param* restrict schedparam) { + return ENOSYS; +} + +int posix_spawnattr_getschedpolicy(const posix_spawnattr_t* restrict attr, int* restrict policy) { + return ENOSYS; +} + +int posix_spawnattr_setschedpolicy(posix_spawnattr_t* attr, int policy) { + return ENOSYS; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_setflags.c b/third_party/ulib/musl/src/process/posix_spawnattr_setflags.c new file mode 100644 index 000000000..14d6cb4c5 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_setflags.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_setflags(posix_spawnattr_t* attr, short flags) { + attr->__flags = flags; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_setpgroup.c b/third_party/ulib/musl/src/process/posix_spawnattr_setpgroup.c new file mode 100644 index 000000000..d9a5daec8 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_setpgroup.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_setpgroup(posix_spawnattr_t* attr, pid_t pgrp) { + attr->__pgrp = pgrp; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_setsigdefault.c b/third_party/ulib/musl/src/process/posix_spawnattr_setsigdefault.c new file mode 100644 index 000000000..17a47f779 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_setsigdefault.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_setsigdefault(posix_spawnattr_t* restrict attr, const sigset_t* restrict def) { + attr->__def = *def; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnattr_setsigmask.c b/third_party/ulib/musl/src/process/posix_spawnattr_setsigmask.c new file mode 100644 index 000000000..a1eac6e70 --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnattr_setsigmask.c @@ -0,0 +1,6 @@ +#include + +int posix_spawnattr_setsigmask(posix_spawnattr_t* restrict attr, const sigset_t* restrict mask) { + attr->__mask = *mask; + return 0; +} diff --git a/third_party/ulib/musl/src/process/posix_spawnp.c b/third_party/ulib/musl/src/process/posix_spawnp.c new file mode 100644 index 000000000..48af10cfd --- /dev/null +++ b/third_party/ulib/musl/src/process/posix_spawnp.c @@ -0,0 +1,15 @@ +#include +#include + +int __execvpe(const char*, char* const*, char* const*); + +int __posix_spawnx(pid_t* restrict, const char* restrict, + int (*)(const char*, char* const*, char* const*), + const posix_spawn_file_actions_t*, const posix_spawnattr_t* restrict, + char* const* restrict, char* const* restrict); + +int posix_spawnp(pid_t* restrict res, const char* restrict file, + const posix_spawn_file_actions_t* fa, const posix_spawnattr_t* restrict attr, + char* const argv[restrict], char* const envp[restrict]) { + return __posix_spawnx(res, file, __execvpe, fa, attr, argv, envp); +} diff --git a/third_party/ulib/musl/src/process/system.c b/third_party/ulib/musl/src/process/system.c new file mode 100644 index 000000000..19831c434 --- /dev/null +++ b/third_party/ulib/musl/src/process/system.c @@ -0,0 +1,47 @@ +#include "libc.h" +#include "pthread_impl.h" +#include +#include +#include +#include +#include +#include + +extern char** __environ; + +int system(const char* cmd) { + pid_t pid; + sigset_t old, reset; + struct sigaction sa = {.sa_handler = SIG_IGN}, oldint, oldquit; + int status = 0x7f00, ret; + posix_spawnattr_t attr; + + pthread_testcancel(); + + if (!cmd) return 1; + + sigaction(SIGINT, &sa, &oldint); + sigaction(SIGQUIT, &sa, &oldquit); + sigaddset(&sa.sa_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &sa.sa_mask, &old); + + sigemptyset(&reset); + if (oldint.sa_handler != SIG_IGN) sigaddset(&reset, SIGINT); + if (oldquit.sa_handler != SIG_IGN) sigaddset(&reset, SIGQUIT); + posix_spawnattr_init(&attr); + posix_spawnattr_setsigmask(&attr, &old); + posix_spawnattr_setsigdefault(&attr, &reset); + posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); + ret = posix_spawn(&pid, "/bin/sh", 0, &attr, (char* []){"sh", "-c", (char*)cmd, 0}, __environ); + posix_spawnattr_destroy(&attr); + + if (!ret) + while (waitpid(pid, &status, 0) < 0 && errno == EINTR) + ; + sigaction(SIGINT, &oldint, NULL); + sigaction(SIGQUIT, &oldquit, NULL); + sigprocmask(SIG_SETMASK, &old, NULL); + + if (ret) errno = ret; + return status; +} diff --git a/third_party/ulib/musl/src/process/vfork.c b/third_party/ulib/musl/src/process/vfork.c new file mode 100644 index 000000000..7503fd308 --- /dev/null +++ b/third_party/ulib/musl/src/process/vfork.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include + +pid_t __vfork(void) { +/* vfork syscall cannot be made from C code */ +#ifdef SYS_fork + return syscall(SYS_fork); +#else + return syscall(SYS_clone, SIGCHLD, 0); +#endif +} + +weak_alias(__vfork, vfork); diff --git a/third_party/ulib/musl/src/process/wait.c b/third_party/ulib/musl/src/process/wait.c new file mode 100644 index 000000000..3c2734bfd --- /dev/null +++ b/third_party/ulib/musl/src/process/wait.c @@ -0,0 +1,5 @@ +#include + +pid_t wait(int* status) { + return waitpid((pid_t)-1, status, 0); +} diff --git a/third_party/ulib/musl/src/process/waitid.c b/third_party/ulib/musl/src/process/waitid.c new file mode 100644 index 000000000..a11da14f4 --- /dev/null +++ b/third_party/ulib/musl/src/process/waitid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int waitid(idtype_t type, id_t id, siginfo_t* info, int options) { + return syscall(SYS_waitid, type, id, info, options, 0); +} diff --git a/third_party/ulib/musl/src/process/waitpid.c b/third_party/ulib/musl/src/process/waitpid.c new file mode 100644 index 000000000..8f6651964 --- /dev/null +++ b/third_party/ulib/musl/src/process/waitpid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +pid_t waitpid(pid_t pid, int* status, int options) { + return syscall(SYS_wait4, pid, status, options, 0); +} diff --git a/third_party/ulib/musl/src/process/x32/vfork.s b/third_party/ulib/musl/src/process/x32/vfork.s new file mode 100644 index 000000000..1039f0f2f --- /dev/null +++ b/third_party/ulib/musl/src/process/x32/vfork.s @@ -0,0 +1,12 @@ +.global __vfork +.weak vfork +.type __vfork,@function +.type vfork,@function +__vfork: +vfork: + pop %rdx + mov $0x4000003a,%eax /* SYS_vfork */ + syscall + push %rdx + mov %rax,%rdi + jmp __syscall_ret diff --git a/third_party/ulib/musl/src/process/x86_64/vfork.s b/third_party/ulib/musl/src/process/x86_64/vfork.s new file mode 100644 index 000000000..27af46f5d --- /dev/null +++ b/third_party/ulib/musl/src/process/x86_64/vfork.s @@ -0,0 +1,12 @@ +.global __vfork +.weak vfork +.type __vfork,@function +.type vfork,@function +__vfork: +vfork: + pop %rdx + mov $58,%eax + syscall + push %rdx + mov %rax,%rdi + jmp __syscall_ret diff --git a/third_party/ulib/musl/src/regex/BUILD.gn b/third_party/ulib/musl/src/regex/BUILD.gn new file mode 100644 index 000000000..f51ce2544 --- /dev/null +++ b/third_party/ulib/musl/src/regex/BUILD.gn @@ -0,0 +1,10 @@ +source_set("regex") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "fnmatch.c", + "glob.c", + ] +} diff --git a/third_party/ulib/musl/src/regex/fnmatch.c b/third_party/ulib/musl/src/regex/fnmatch.c new file mode 100644 index 000000000..507791f26 --- /dev/null +++ b/third_party/ulib/musl/src/regex/fnmatch.c @@ -0,0 +1,315 @@ +/* + * An implementation of what I call the "Sea of Stars" algorithm for + * POSIX fnmatch(). The basic idea is that we factor the pattern into + * a head component (which we match first and can reject without ever + * measuring the length of the string), an optional tail component + * (which only exists if the pattern contains at least one star), and + * an optional "sea of stars", a set of star-separated components + * between the head and tail. After the head and tail matches have + * been removed from the input string, the components in the "sea of + * stars" are matched sequentially by searching for their first + * occurrence past the end of the previous match. + * + * - Rich Felker, April 2012 + */ + +#include "locale_impl.h" +#include +#include +#include +#include +#include + +#define END 0 +#define UNMATCHABLE -2 +#define BRACKET -3 +#define QUESTION -4 +#define STAR -5 + +static int str_next(const char* str, size_t n, size_t* step) { + if (!n) { + *step = 0; + return 0; + } + if (str[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, str, n); + if (k < 0) { + *step = 1; + return -1; + } + *step = k; + return wc; + } + *step = 1; + return str[0]; +} + +static int pat_next(const char* pat, size_t m, size_t* step, int flags) { + int esc = 0; + if (!m || !*pat) { + *step = 0; + return END; + } + *step = 1; + if (pat[0] == '\\' && pat[1] && !(flags & FNM_NOESCAPE)) { + *step = 2; + pat++; + esc = 1; + goto escaped; + } + if (pat[0] == '[') { + size_t k = 1; + if (k < m) + if (pat[k] == '^' || pat[k] == '!') k++; + if (k < m) + if (pat[k] == ']') k++; + for (; k < m && pat[k] && pat[k] != ']'; k++) { + if (k + 1 < m && pat[k + 1] && pat[k] == '[' && + (pat[k + 1] == ':' || pat[k + 1] == '.' || pat[k + 1] == '=')) { + int z = pat[k + 1]; + k += 2; + if (k < m && pat[k]) k++; + while (k < m && pat[k] && (pat[k - 1] != z || pat[k] != ']')) + k++; + if (k == m || !pat[k]) break; + } + } + if (k == m || !pat[k]) { + *step = 1; + return '['; + } + *step = k + 1; + return BRACKET; + } + if (pat[0] == '*') return STAR; + if (pat[0] == '?') return QUESTION; +escaped: + if (pat[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, pat, m); + if (k < 0) { + *step = 0; + return UNMATCHABLE; + } + *step = k + esc; + return wc; + } + return pat[0]; +} + +static int casefold(int k) { + int c = towupper(k); + return c == k ? towlower(k) : c; +} + +static int match_bracket(const char* p, int k, int kfold) { + wchar_t wc; + int inv = 0; + p++; + if (*p == '^' || *p == '!') { + inv = 1; + p++; + } + if (*p == ']') { + if (k == ']') return !inv; + p++; + } else if (*p == '-') { + if (k == '-') return !inv; + p++; + } + wc = p[-1]; + for (; *p != ']'; p++) { + if (p[0] == '-' && p[1] != ']') { + wchar_t wc2; + int l = mbtowc(&wc2, p + 1, 4); + if (l < 0) return 0; + if (wc <= wc2) + if ((unsigned)k - wc <= wc2 - wc || (unsigned)kfold - wc <= wc2 - wc) return !inv; + p += l - 1; + continue; + } + if (p[0] == '[' && (p[1] == ':' || p[1] == '.' || p[1] == '=')) { + const char* p0 = p + 2; + int z = p[1]; + p += 3; + while (p[-1] != z || p[0] != ']') + p++; + if (z == ':' && p - 1 - p0 < 16) { + char buf[16]; + memcpy(buf, p0, p - 1 - p0); + buf[p - 1 - p0] = 0; + if (iswctype(k, wctype(buf)) || iswctype(kfold, wctype(buf))) return !inv; + } + continue; + } + if (*p < 128U) { + wc = (unsigned char)*p; + } else { + int l = mbtowc(&wc, p, 4); + if (l < 0) return 0; + p += l - 1; + } + if (wc == k || wc == kfold) return !inv; + } + return inv; +} + +static int fnmatch_internal(const char* pat, size_t m, const char* str, size_t n, int flags) { + const char *p, *ptail, *endpat; + const char *s, *stail, *endstr; + size_t pinc, sinc, tailcnt = 0; + int c, k, kfold; + + if (flags & FNM_PERIOD) { + if (*str == '.' && *pat != '.') return FNM_NOMATCH; + } + for (;;) { + switch ((c = pat_next(pat, m, &pinc, flags))) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + pat++; + m--; + break; + default: + k = str_next(str, n, &sinc); + if (k <= 0) return (c == END) ? 0 : FNM_NOMATCH; + str += sinc; + n -= sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(pat, k, kfold)) return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + pat += pinc; + m -= pinc; + continue; + } + break; + } + + /* Compute real pat length if it was initially unknown/-1 */ + m = strnlen(pat, m); + endpat = pat + m; + + /* Find the last * in pat and count chars needed after it */ + for (p = ptail = pat; p < endpat; p += pinc) { + switch (pat_next(p, endpat - p, &pinc, flags)) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + tailcnt = 0; + ptail = p + 1; + break; + default: + tailcnt++; + break; + } + } + + /* Past this point we need not check for UNMATCHABLE in pat, + * because all of pat has already been parsed once. */ + + /* Compute real str length if it was initially unknown/-1 */ + n = strnlen(str, n); + endstr = str + n; + if (n < tailcnt) return FNM_NOMATCH; + + /* Find the final tailcnt chars of str, accounting for UTF-8. + * On illegal sequences we may get it wrong, but in that case + * we necessarily have a matching failure anyway. */ + for (s = endstr; s > str && tailcnt; tailcnt--) { + if (s[-1] < 128U || MB_CUR_MAX == 1) + s--; + else + while ((unsigned char)*--s - 0x80U < 0x40 && s > str) + ; + } + if (tailcnt) return FNM_NOMATCH; + stail = s; + + /* Check that the pat and str tails match */ + p = ptail; + for (;;) { + c = pat_next(p, endpat - p, &pinc, flags); + p += pinc; + if ((k = str_next(s, endstr - s, &sinc)) <= 0) { + if (c != END) return FNM_NOMATCH; + break; + } + s += sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(p - pinc, k, kfold)) return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + } + + /* We're all done with the tails now, so throw them out */ + endstr = stail; + endpat = ptail; + + /* Match pattern components until there are none left */ + while (pat < endpat) { + p = pat; + s = str; + for (;;) { + c = pat_next(p, endpat - p, &pinc, flags); + p += pinc; + /* Encountering * completes/commits a component */ + if (c == STAR) { + pat = p; + str = s; + break; + } + k = str_next(s, endstr - s, &sinc); + if (!k) return FNM_NOMATCH; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(p - pinc, k, kfold)) break; + } else if (c != QUESTION && k != c && kfold != c) { + break; + } + s += sinc; + } + if (c == STAR) continue; + /* If we failed, advance str, by 1 char if it's a valid + * char, or past all invalid bytes otherwise. */ + k = str_next(str, endstr - str, &sinc); + if (k > 0) + str += sinc; + else + for (str++; str_next(str, endstr - str, &sinc) < 0; str++) + ; + } + + return 0; +} + +int fnmatch(const char* pat, const char* str, int flags) { + const char *s, *p; + size_t inc; + int c; + if (flags & FNM_PATHNAME) + for (;;) { + for (s = str; *s && *s != '/'; s++) + ; + for (p = pat; (c = pat_next(p, -1, &inc, flags)) != END && c != '/'; p += inc) + ; + if (c != *s && (!*s || !(flags & FNM_LEADING_DIR))) return FNM_NOMATCH; + if (fnmatch_internal(pat, p - pat, str, s - str, flags)) return FNM_NOMATCH; + if (!c) return 0; + str = s + 1; + pat = p + inc; + } + else if (flags & FNM_LEADING_DIR) { + for (s = str; *s; s++) { + if (*s != '/') continue; + if (!fnmatch_internal(pat, -1, str, s - str, flags)) return 0; + } + } + return fnmatch_internal(pat, -1, str, -1, flags); +} diff --git a/third_party/ulib/musl/src/regex/glob.c b/third_party/ulib/musl/src/regex/glob.c new file mode 100644 index 000000000..2671d7092 --- /dev/null +++ b/third_party/ulib/musl/src/regex/glob.c @@ -0,0 +1,226 @@ +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct match { + struct match* next; + char name[1]; +}; + +static int is_literal(const char* p, int useesc) { + int bracket = 0; + for (; *p; p++) { + switch (*p) { + case '\\': + if (!useesc) break; + case '?': + case '*': + return 0; + case '[': + bracket = 1; + break; + case ']': + if (bracket) return 0; + break; + } + } + return 1; +} + +static int append(struct match** tail, const char* name, size_t len, int mark) { + struct match* new = malloc(sizeof(struct match) + len + 1); + if (!new) return -1; + (*tail)->next = new; + new->next = NULL; + strcpy(new->name, name); + if (mark) strcat(new->name, "/"); + *tail = new; + return 0; +} + +static int match_in_dir(const char* d, const char* p, int flags, + int (*errfunc)(const char* path, int err), struct match** tail) { + DIR* dir; + struct dirent de_buf, *de; + char pat[strlen(p) + 1]; + char* p2; + size_t l = strlen(d); + int literal; + int fnm_flags = + ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); + int error; + + if ((p2 = strchr(p, '/'))) { + strcpy(pat, p); + pat[p2 - p] = 0; + for (; *p2 == '/'; p2++) + ; + p = pat; + } + literal = is_literal(p, !(flags & GLOB_NOESCAPE)); + if (*d == '/' && !*(d + 1)) l = 0; + + /* rely on opendir failing for nondirectory objects */ + dir = opendir(*d ? d : "."); + error = errno; + if (!dir) { + /* this is not an error -- we let opendir call stat for us */ + if (error == ENOTDIR) return 0; + if (error == EACCES && !*p) { + struct stat st; + if (!stat(d, &st) && S_ISDIR(st.st_mode)) { + if (append(tail, d, l, l)) return GLOB_NOSPACE; + return 0; + } + } + if (errfunc(d, error) || (flags & GLOB_ERR)) return GLOB_ABORTED; + return 0; + } + if (!*p) { + error = append(tail, d, l, l) ? GLOB_NOSPACE : 0; + closedir(dir); + return error; + } + while (!(error = readdir_r(dir, &de_buf, &de)) && de) { + char namebuf[l + de->d_reclen + 2], *name = namebuf; + if (!literal && fnmatch(p, de->d_name, fnm_flags)) continue; + if (literal && strcmp(p, de->d_name)) continue; + if (p2 && de->d_type && !S_ISDIR(de->d_type << 12) && !S_ISLNK(de->d_type << 12)) continue; + if (*d) { + memcpy(name, d, l); + name[l] = '/'; + strcpy(name + l + 1, de->d_name); + } else { + name = de->d_name; + } + if (p2) { + if ((error = match_in_dir(name, p2, flags, errfunc, tail))) { + closedir(dir); + return error; + } + } else { + int mark = 0; + if (flags & GLOB_MARK) { + if (de->d_type && !S_ISLNK(de->d_type << 12)) + mark = S_ISDIR(de->d_type << 12); + else { + struct stat st; + stat(name, &st); + mark = S_ISDIR(st.st_mode); + } + } + if (append(tail, name, l + de->d_reclen + 1, mark)) { + closedir(dir); + return GLOB_NOSPACE; + } + } + } + closedir(dir); + if (error && (errfunc(d, error) || (flags & GLOB_ERR))) return GLOB_ABORTED; + return 0; +} + +static int ignore_err(const char* path, int err) { + return 0; +} + +static void freelist(struct match* head) { + struct match *match, *next; + for (match = head->next; match; match = next) { + next = match->next; + free(match); + } +} + +static int sort(const void* a, const void* b) { + return strcmp(*(const char**)a, *(const char**)b); +} + +int glob(const char* restrict pat, int flags, int (*errfunc)(const char* path, int err), + glob_t* restrict g) { + const char *p = pat, *d; + struct match head = {.next = NULL}, *tail = &head; + size_t cnt, i; + size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; + int error = 0; + + if (*p == '/') { + for (; *p == '/'; p++) + ; + d = "/"; + } else { + d = ""; + } + + if (strlen(p) > PATH_MAX) return GLOB_NOSPACE; + + if (!errfunc) errfunc = ignore_err; + + if (!(flags & GLOB_APPEND)) { + g->gl_offs = offs; + g->gl_pathc = 0; + g->gl_pathv = NULL; + } + + if (*p) error = match_in_dir(d, p, flags, errfunc, &tail); + if (error == GLOB_NOSPACE) { + freelist(&head); + return error; + } + + for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++) + ; + if (!cnt) { + if (flags & GLOB_NOCHECK) { + tail = &head; + if (append(&tail, pat, strlen(pat), 0)) return GLOB_NOSPACE; + cnt++; + } else + return GLOB_NOMATCH; + } + + if (flags & GLOB_APPEND) { + char** pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char*)); + if (!pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + g->gl_pathv = pathv; + offs += g->gl_pathc; + } else { + g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char*)); + if (!g->gl_pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + for (i = 0; i < offs; i++) + g->gl_pathv[i] = NULL; + } + for (i = 0, tail = head.next; i < cnt; tail = tail->next, i++) + g->gl_pathv[offs + i] = tail->name; + g->gl_pathv[offs + i] = NULL; + g->gl_pathc += cnt; + + if (!(flags & GLOB_NOSORT)) qsort(g->gl_pathv + offs, cnt, sizeof(char*), sort); + + return error; +} + +void globfree(glob_t* g) { + size_t i; + for (i = 0; i < g->gl_pathc; i++) + free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); + free(g->gl_pathv); + g->gl_pathc = 0; + g->gl_pathv = NULL; +} + +LFS64(glob); +LFS64(globfree); diff --git a/third_party/ulib/musl/src/sched/BUILD.gn b/third_party/ulib/musl/src/sched/BUILD.gn new file mode 100644 index 000000000..d6db40036 --- /dev/null +++ b/third_party/ulib/musl/src/sched/BUILD.gn @@ -0,0 +1,17 @@ +source_set("sched") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "affinity.c", + "sched_cpucount.c", + "sched_get_priority_max.c", + "sched_getparam.c", + "sched_getscheduler.c", + "sched_rr_get_interval.c", + "sched_setparam.c", + "sched_setscheduler.c", + "sched_yield.c", + ] +} diff --git a/third_party/ulib/musl/src/sched/affinity.c b/third_party/ulib/musl/src/sched/affinity.c new file mode 100644 index 000000000..85b5f6b3d --- /dev/null +++ b/third_party/ulib/musl/src/sched/affinity.c @@ -0,0 +1,28 @@ +#define _GNU_SOURCE +#include "pthread_impl.h" +#include "syscall.h" +#include +#include + +int sched_setaffinity(pid_t tid, size_t size, const cpu_set_t* set) { + return syscall(SYS_sched_setaffinity, tid, size, set); +} + +int pthread_setaffinity_np(pthread_t td, size_t size, const cpu_set_t* set) { + return -__syscall(SYS_sched_setaffinity, td->tid, size, set); +} + +static int do_getaffinity(pid_t tid, size_t size, cpu_set_t* set) { + long ret = __syscall(SYS_sched_getaffinity, tid, size, set); + if (ret < 0) return ret; + if (ret < size) memset((char*)set + ret, 0, size - ret); + return 0; +} + +int sched_getaffinity(pid_t tid, size_t size, cpu_set_t* set) { + return __syscall_ret(do_getaffinity(tid, size, set)); +} + +int pthread_getaffinity_np(pthread_t td, size_t size, cpu_set_t* set) { + return -do_getaffinity(td->tid, size, set); +} diff --git a/third_party/ulib/musl/src/sched/sched_cpucount.c b/third_party/ulib/musl/src/sched/sched_cpucount.c new file mode 100644 index 000000000..42dab386d --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_cpucount.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include + +int __sched_cpucount(size_t size, const cpu_set_t* set) { + size_t i, j, cnt = 0; + const unsigned char* p = (const void*)set; + for (i = 0; i < size; i++) + for (j = 0; j < 8; j++) + if (p[i] & (1 << j)) cnt++; + return cnt; +} diff --git a/third_party/ulib/musl/src/sched/sched_get_priority_max.c b/third_party/ulib/musl/src/sched/sched_get_priority_max.c new file mode 100644 index 000000000..d1bfd36e7 --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_get_priority_max.c @@ -0,0 +1,10 @@ +#include "syscall.h" +#include + +int sched_get_priority_max(int policy) { + return syscall(SYS_sched_get_priority_max, policy); +} + +int sched_get_priority_min(int policy) { + return syscall(SYS_sched_get_priority_min, policy); +} diff --git a/third_party/ulib/musl/src/sched/sched_getcpu.c b/third_party/ulib/musl/src/sched/sched_getcpu.c new file mode 100644 index 000000000..c1396a25e --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_getcpu.c @@ -0,0 +1,42 @@ +#define _GNU_SOURCE +#include "atomic.h" +#include "syscall.h" +#include +#include + +#ifdef VDSO_GETCPU_SYM + +void* __vdsosym(const char*, const char*); + +static void* volatile vdso_func; + +typedef long (*getcpu_f)(unsigned*, unsigned*, void*); + +static long getcpu_init(unsigned* cpu, unsigned* node, void* unused) { + void* p = __vdsosym(VDSO_GETCPU_VER, VDSO_GETCPU_SYM); + getcpu_f f = (getcpu_f)p; + a_cas_p(&vdso_func, (void*)getcpu_init, p); + return f ? f(cpu, node, unused) : -ENOSYS; +} + +static void* volatile vdso_func = (void*)getcpu_init; + +#endif + +int sched_getcpu(void) { + int r; + unsigned cpu; + +#ifdef VDSO_GETCPU_SYM + getcpu_f f = (getcpu_f)vdso_func; + if (f) { + r = f(&cpu, 0, 0); + if (!r) return cpu; + if (r != -ENOSYS) return __syscall_ret(r); + } +#endif + + r = __syscall(SYS_getcpu, &cpu, 0, 0); + if (!r) return cpu; + return __syscall_ret(r); +} diff --git a/third_party/ulib/musl/src/sched/sched_getparam.c b/third_party/ulib/musl/src/sched/sched_getparam.c new file mode 100644 index 000000000..f37cc45de --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_getparam.c @@ -0,0 +1,7 @@ +#include "syscall.h" +#include +#include + +int sched_getparam(pid_t pid, struct sched_param* param) { + return __syscall_ret(-ENOSYS); +} diff --git a/third_party/ulib/musl/src/sched/sched_getscheduler.c b/third_party/ulib/musl/src/sched/sched_getscheduler.c new file mode 100644 index 000000000..4a90bde98 --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_getscheduler.c @@ -0,0 +1,7 @@ +#include "syscall.h" +#include +#include + +int sched_getscheduler(pid_t pid) { + return __syscall_ret(-ENOSYS); +} diff --git a/third_party/ulib/musl/src/sched/sched_rr_get_interval.c b/third_party/ulib/musl/src/sched/sched_rr_get_interval.c new file mode 100644 index 000000000..e786f3d4a --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_rr_get_interval.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int sched_rr_get_interval(pid_t pid, struct timespec* ts) { + return syscall(SYS_sched_rr_get_interval, pid, ts); +} diff --git a/third_party/ulib/musl/src/sched/sched_setparam.c b/third_party/ulib/musl/src/sched/sched_setparam.c new file mode 100644 index 000000000..779bffd5a --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_setparam.c @@ -0,0 +1,7 @@ +#include "syscall.h" +#include +#include + +int sched_setparam(pid_t pid, const struct sched_param* param) { + return __syscall_ret(-ENOSYS); +} diff --git a/third_party/ulib/musl/src/sched/sched_setscheduler.c b/third_party/ulib/musl/src/sched/sched_setscheduler.c new file mode 100644 index 000000000..af93051d4 --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_setscheduler.c @@ -0,0 +1,7 @@ +#include "syscall.h" +#include +#include + +int sched_setscheduler(pid_t pid, int sched, const struct sched_param* param) { + return __syscall_ret(-ENOSYS); +} diff --git a/third_party/ulib/musl/src/sched/sched_yield.c b/third_party/ulib/musl/src/sched/sched_yield.c new file mode 100644 index 000000000..d4732068a --- /dev/null +++ b/third_party/ulib/musl/src/sched/sched_yield.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int sched_yield() { + return syscall(SYS_sched_yield); +} diff --git a/third_party/ulib/musl/src/select/BUILD.gn b/third_party/ulib/musl/src/select/BUILD.gn new file mode 100644 index 000000000..49a9be0db --- /dev/null +++ b/third_party/ulib/musl/src/select/BUILD.gn @@ -0,0 +1,11 @@ +source_set("select") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "poll.c", + "pselect.c", + "select.c", + ] +} diff --git a/third_party/ulib/musl/src/select/poll.c b/third_party/ulib/musl/src/select/poll.c new file mode 100644 index 000000000..d2061ace0 --- /dev/null +++ b/third_party/ulib/musl/src/select/poll.c @@ -0,0 +1,18 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +int poll(struct pollfd* fds, nfds_t n, int timeout) { +#ifdef SYS_poll + return syscall(SYS_poll, fds, n, timeout); +#else + return syscall( + SYS_ppoll, fds, n, + timeout >= 0 + ? &((struct timespec){.tv_sec = timeout / 1000, .tv_nsec = timeout % 1000 * 1000000}) + : 0, + 0, _NSIG / 8); +#endif +} diff --git a/third_party/ulib/musl/src/select/pselect.c b/third_party/ulib/musl/src/select/pselect.c new file mode 100644 index 000000000..e9b01bae3 --- /dev/null +++ b/third_party/ulib/musl/src/select/pselect.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +int pselect(int n, fd_set* restrict rfds, fd_set* restrict wfds, fd_set* restrict efds, + const struct timespec* restrict ts, const sigset_t* restrict mask) { + syscall_arg_t data[2] = {(uintptr_t)mask, _NSIG / 8}; + struct timespec ts_tmp; + if (ts) ts_tmp = *ts; + return syscall(SYS_pselect6, n, rfds, wfds, efds, ts ? &ts_tmp : 0, data); +} diff --git a/third_party/ulib/musl/src/select/select.c b/third_party/ulib/musl/src/select/select.c new file mode 100644 index 000000000..049a3f603 --- /dev/null +++ b/third_party/ulib/musl/src/select/select.c @@ -0,0 +1,24 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include +#include + +int select(int n, fd_set* restrict rfds, fd_set* restrict wfds, fd_set* restrict efds, + struct timeval* restrict tv) { +#ifdef SYS_select + return syscall(SYS_select, n, rfds, wfds, efds, tv); +#else + syscall_arg_t data[2] = {0, _NSIG / 8}; + struct timespec ts; + if (tv) { + if (tv->tv_sec < 0 || tv->tv_usec < 0) return __syscall_ret(-EINVAL); + time_t extra_secs = tv->tv_usec / 1000000; + ts.tv_nsec = tv->tv_usec % 1000000 * 1000; + const time_t max_time = (1ULL << 8 * sizeof(time_t) - 1) - 1; + ts.tv_sec = extra_secs > max_time - tv->tv_sec ? max_time : tv->tv_sec + extra_secs; + } + return syscall(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data); +#endif +} diff --git a/third_party/ulib/musl/src/setjmp/BUILD.gn b/third_party/ulib/musl/src/setjmp/BUILD.gn new file mode 100644 index 000000000..818d4dec6 --- /dev/null +++ b/third_party/ulib/musl/src/setjmp/BUILD.gn @@ -0,0 +1,25 @@ +source_set("setjmp") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [] + if (target_cpu == "arm") { + sources += [ + "arm/longjmp.s", + "arm/setjmp.s", + ] + } else if (target_cpu == "arm64") { + sources += [ + "aarch64/longjmp.s", + "aarch64/setjmp.s", + ] + } else if (target_cpu == "x64") { + # Defined in //third_party + } else { + sources += [ + "longjmp.c", + "setjmp.c", + ] + } +} diff --git a/third_party/ulib/musl/src/setjmp/aarch64/longjmp.s b/third_party/ulib/musl/src/setjmp/aarch64/longjmp.s new file mode 100644 index 000000000..7c4655fa9 --- /dev/null +++ b/third_party/ulib/musl/src/setjmp/aarch64/longjmp.s @@ -0,0 +1,24 @@ +.global _longjmp +.global longjmp +.type _longjmp,%function +.type longjmp,%function +_longjmp: +longjmp: + // IHI0055B_aapcs64.pdf 5.1.1, 5.1.2 callee saved registers + ldp x19, x20, [x0,#0] + ldp x21, x22, [x0,#16] + ldp x23, x24, [x0,#32] + ldp x25, x26, [x0,#48] + ldp x27, x28, [x0,#64] + ldp x29, x30, [x0,#80] + ldr x2, [x0,#104] + mov sp, x2 + ldp d8 , d9, [x0,#112] + ldp d10, d11, [x0,#128] + ldp d12, d13, [x0,#144] + ldp d14, d15, [x0,#160] + + mov x0, x1 + cbnz x1, 1f + mov x0, #1 +1: br x30 diff --git a/third_party/ulib/musl/src/setjmp/aarch64/setjmp.s b/third_party/ulib/musl/src/setjmp/aarch64/setjmp.s new file mode 100644 index 000000000..f49288aa1 --- /dev/null +++ b/third_party/ulib/musl/src/setjmp/aarch64/setjmp.s @@ -0,0 +1,24 @@ +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,@function +.type _setjmp,@function +.type setjmp,@function +__setjmp: +_setjmp: +setjmp: + // IHI0055B_aapcs64.pdf 5.1.1, 5.1.2 callee saved registers + stp x19, x20, [x0,#0] + stp x21, x22, [x0,#16] + stp x23, x24, [x0,#32] + stp x25, x26, [x0,#48] + stp x27, x28, [x0,#64] + stp x29, x30, [x0,#80] + mov x2, sp + str x2, [x0,#104] + stp d8, d9, [x0,#112] + stp d10, d11, [x0,#128] + stp d12, d13, [x0,#144] + stp d14, d15, [x0,#160] + mov x0, #0 + ret diff --git a/third_party/ulib/musl/src/setjmp/arm/longjmp.s b/third_party/ulib/musl/src/setjmp/arm/longjmp.s new file mode 100644 index 000000000..e28d8f31c --- /dev/null +++ b/third_party/ulib/musl/src/setjmp/arm/longjmp.s @@ -0,0 +1,40 @@ +.syntax unified +.global _longjmp +.global longjmp +.type _longjmp,%function +.type longjmp,%function +_longjmp: +longjmp: + mov ip,r0 + movs r0,r1 + moveq r0,#1 + ldmia ip!, {v1,v2,v3,v4,v5,v6,sl,fp,sp,lr} + + adr r1,1f + ldr r2,1f + ldr r1,[r1,r2] + + tst r1,#0x260 + beq 3f + tst r1,#0x20 + beq 2f + ldc p2, cr4, [ip], #48 +2: tst r1,#0x40 + beq 2f + .fpu vfp + vldmia ip!, {d8-d15} + .fpu softvfp + .eabi_attribute 10, 0 + .eabi_attribute 27, 0 +2: tst r1,#0x200 + beq 3f + ldcl p1, cr10, [ip], #8 + ldcl p1, cr11, [ip], #8 + ldcl p1, cr12, [ip], #8 + ldcl p1, cr13, [ip], #8 + ldcl p1, cr14, [ip], #8 + ldcl p1, cr15, [ip], #8 +3: bx lr + +.hidden __hwcap +1: .word __hwcap-1b diff --git a/third_party/ulib/musl/src/setjmp/arm/setjmp.s b/third_party/ulib/musl/src/setjmp/arm/setjmp.s new file mode 100644 index 000000000..87791634b --- /dev/null +++ b/third_party/ulib/musl/src/setjmp/arm/setjmp.s @@ -0,0 +1,42 @@ +.syntax unified +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,%function +.type _setjmp,%function +.type setjmp,%function +__setjmp: +_setjmp: +setjmp: + mov ip,r0 + stmia ip!,{v1,v2,v3,v4,v5,v6,sl,fp,sp,lr} + mov r0,#0 + + adr r1,1f + ldr r2,1f + ldr r1,[r1,r2] + + tst r1,#0x260 + beq 3f + tst r1,#0x20 + beq 2f + stc p2, cr4, [ip], #48 +2: tst r1,#0x40 + beq 2f + .fpu vfp + vstmia ip!, {d8-d15} + .fpu softvfp + .eabi_attribute 10, 0 + .eabi_attribute 27, 0 +2: tst r1,#0x200 + beq 3f + stcl p1, cr10, [ip], #8 + stcl p1, cr11, [ip], #8 + stcl p1, cr12, [ip], #8 + stcl p1, cr13, [ip], #8 + stcl p1, cr14, [ip], #8 + stcl p1, cr15, [ip], #8 +3: bx lr + +.hidden __hwcap +1: .word __hwcap-1b diff --git a/third_party/ulib/musl/src/setjmp/longjmp.c b/third_party/ulib/musl/src/setjmp/longjmp.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/setjmp/setjmp.c b/third_party/ulib/musl/src/setjmp/setjmp.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/signal/BUILD.gn b/third_party/ulib/musl/src/signal/BUILD.gn new file mode 100644 index 000000000..7d5ea79c8 --- /dev/null +++ b/third_party/ulib/musl/src/signal/BUILD.gn @@ -0,0 +1,56 @@ +source_set("signal") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "block.c", + "getitimer.c", + "kill.c", + "killpg.c", + "psiginfo.c", + "psignal.c", + "raise.c", + "setitimer.c", + "sigaction.c", + "sigaddset.c", + "sigaltstack.c", + "sigandset.c", + "sigdelset.c", + "sigemptyset.c", + "sigfillset.c", + "sighold.c", + "sigignore.c", + "siginterrupt.c", + "sigisemptyset.c", + "sigismember.c", + "siglongjmp.c", + "signal.c", + "sigorset.c", + "sigpause.c", + "sigpending.c", + "sigprocmask.c", + "sigqueue.c", + "sigrelse.c", + "sigrtmax.c", + "sigrtmin.c", + "sigset.c", + "sigsetjmp_tail.c", + "sigsuspend.c", + "sigtimedwait.c", + "sigwait.c", + "sigwaitinfo.c", + ] + + if (target_cpu == "x64") { + sources += [ + "x86_64/restore.s", + "x86_64/sigsetjmp.s", + ] + } else { + sources += [ + "restore.c", + "sigsetjmp.c", + ] + } +} diff --git a/third_party/ulib/musl/src/signal/aarch64/restore.s b/third_party/ulib/musl/src/signal/aarch64/restore.s new file mode 100644 index 000000000..d3d0243d4 --- /dev/null +++ b/third_party/ulib/musl/src/signal/aarch64/restore.s @@ -0,0 +1,8 @@ +.global __restore +.type __restore,%function +__restore: +.global __restore_rt +.type __restore_rt,%function +__restore_rt: + mov x8,#139 // SYS_rt_sigreturn + svc 0 diff --git a/third_party/ulib/musl/src/signal/aarch64/sigsetjmp.s b/third_party/ulib/musl/src/signal/aarch64/sigsetjmp.s new file mode 100644 index 000000000..75910c432 --- /dev/null +++ b/third_party/ulib/musl/src/signal/aarch64/sigsetjmp.s @@ -0,0 +1,21 @@ +.global sigsetjmp +.global __sigsetjmp +.type sigsetjmp,%function +.type __sigsetjmp,%function +sigsetjmp: +__sigsetjmp: + cbz x1,setjmp + + str x30,[x0,#176] + str x19,[x0,#176+8+8] + mov x19,x0 + + bl setjmp + + mov w1,w0 + mov x0,x19 + ldr x30,[x0,#176] + ldr x19,[x0,#176+8+8] + +.hidden __sigsetjmp_tail + b __sigsetjmp_tail diff --git a/third_party/ulib/musl/src/signal/arm/restore.s b/third_party/ulib/musl/src/signal/arm/restore.s new file mode 100644 index 000000000..22fb1a54f --- /dev/null +++ b/third_party/ulib/musl/src/signal/arm/restore.s @@ -0,0 +1,13 @@ +.syntax unified + +.global __restore +.type __restore,%function +__restore: + mov r7,#119 + swi 0x0 + +.global __restore_rt +.type __restore_rt,%function +__restore_rt: + mov r7,#173 + swi 0x0 diff --git a/third_party/ulib/musl/src/signal/arm/sigsetjmp.s b/third_party/ulib/musl/src/signal/arm/sigsetjmp.s new file mode 100644 index 000000000..318addba0 --- /dev/null +++ b/third_party/ulib/musl/src/signal/arm/sigsetjmp.s @@ -0,0 +1,23 @@ +.syntax unified +.global sigsetjmp +.global __sigsetjmp +.type sigsetjmp,%function +.type __sigsetjmp,%function +sigsetjmp: +__sigsetjmp: + tst r1,r1 + beq setjmp + + str lr,[r0,#256] + str r4,[r0,#260+8] + mov r4,r0 + + bl setjmp + + mov r1,r0 + mov r0,r4 + ldr lr,[r0,#256] + ldr r4,[r0,#260+8] + +.hidden __sigsetjmp_tail + b __sigsetjmp_tail diff --git a/third_party/ulib/musl/src/signal/block.c b/third_party/ulib/musl/src/signal/block.c new file mode 100644 index 000000000..5dd586658 --- /dev/null +++ b/third_party/ulib/musl/src/signal/block.c @@ -0,0 +1,41 @@ +#include "pthread_impl.h" +#include "syscall.h" +#include + +static const unsigned long all_mask[] = { +#if ULONG_MAX == 0xffffffff && _NSIG == 129 + -1UL, -1UL, -1UL, -1UL +#elif ULONG_MAX == 0xffffffff + -1UL, -1UL +#else + -1UL +#endif +}; + +static const unsigned long app_mask[] = { +#if ULONG_MAX == 0xffffffff +#if _NSIG == 65 + 0x7fffffff, 0xfffffffc +#else + 0x7fffffff, 0xfffffffc, -1UL, -1UL +#endif +#else +#if _NSIG == 65 + 0xfffffffc7fffffff +#else + 0xfffffffc7fffffff, -1UL +#endif +#endif +}; + +void __block_all_sigs(void* set) { + __syscall(SYS_rt_sigprocmask, SIG_BLOCK, &all_mask, set, _NSIG / 8); +} + +void __block_app_sigs(void* set) { + __syscall(SYS_rt_sigprocmask, SIG_BLOCK, &app_mask, set, _NSIG / 8); +} + +void __restore_sigs(void* set) { + __syscall(SYS_rt_sigprocmask, SIG_SETMASK, set, 0, _NSIG / 8); +} diff --git a/third_party/ulib/musl/src/signal/getitimer.c b/third_party/ulib/musl/src/signal/getitimer.c new file mode 100644 index 000000000..03d2e5b6e --- /dev/null +++ b/third_party/ulib/musl/src/signal/getitimer.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int getitimer(int which, struct itimerval* old) { + return syscall(SYS_getitimer, which, old); +} diff --git a/third_party/ulib/musl/src/signal/kill.c b/third_party/ulib/musl/src/signal/kill.c new file mode 100644 index 000000000..70f84aee5 --- /dev/null +++ b/third_party/ulib/musl/src/signal/kill.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int kill(pid_t pid, int sig) { + return syscall(SYS_kill, pid, sig); +} diff --git a/third_party/ulib/musl/src/signal/killpg.c b/third_party/ulib/musl/src/signal/killpg.c new file mode 100644 index 000000000..8a2cb919f --- /dev/null +++ b/third_party/ulib/musl/src/signal/killpg.c @@ -0,0 +1,10 @@ +#include +#include + +int killpg(pid_t pgid, int sig) { + if (pgid < 0) { + errno = EINVAL; + return -1; + } + return kill(-pgid, sig); +} diff --git a/third_party/ulib/musl/src/signal/psiginfo.c b/third_party/ulib/musl/src/signal/psiginfo.c new file mode 100644 index 000000000..356552bed --- /dev/null +++ b/third_party/ulib/musl/src/signal/psiginfo.c @@ -0,0 +1,11 @@ +#include +#include +#include + +void psiginfo(const siginfo_t* si, const char* msg) { + char* s = strsignal(si->si_signo); + if (msg) + fprintf(stderr, "%s: %s\n", msg, s); + else + fprintf(stderr, "%s\n", s); +} diff --git a/third_party/ulib/musl/src/signal/psignal.c b/third_party/ulib/musl/src/signal/psignal.c new file mode 100644 index 000000000..2de2753ce --- /dev/null +++ b/third_party/ulib/musl/src/signal/psignal.c @@ -0,0 +1,11 @@ +#include +#include +#include + +void psignal(int sig, const char* msg) { + char* s = strsignal(sig); + if (msg) + fprintf(stderr, "%s: %s\n", msg, s); + else + fprintf(stderr, "%s\n", s); +} diff --git a/third_party/ulib/musl/src/signal/raise.c b/third_party/ulib/musl/src/signal/raise.c new file mode 100644 index 000000000..08d20d5d9 --- /dev/null +++ b/third_party/ulib/musl/src/signal/raise.c @@ -0,0 +1,14 @@ +#include "pthread_impl.h" +#include "syscall.h" +#include +#include + +int raise(int sig) { + int tid, ret; + sigset_t set; + __block_app_sigs(&set); + tid = __syscall(SYS_gettid); + ret = syscall(SYS_tkill, tid, sig); + __restore_sigs(&set); + return ret; +} diff --git a/third_party/ulib/musl/src/signal/restore.c b/third_party/ulib/musl/src/signal/restore.c new file mode 100644 index 000000000..638a67b81 --- /dev/null +++ b/third_party/ulib/musl/src/signal/restore.c @@ -0,0 +1,6 @@ +/* These functions will not work, but suffice for targets where the + * kernel sigaction structure does not actually use sa_restorer. */ + +void __restore() {} + +void __restore_rt() {} diff --git a/third_party/ulib/musl/src/signal/setitimer.c b/third_party/ulib/musl/src/signal/setitimer.c new file mode 100644 index 000000000..a77f7e509 --- /dev/null +++ b/third_party/ulib/musl/src/signal/setitimer.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int setitimer(int which, const struct itimerval* restrict new, struct itimerval* restrict old) { + return syscall(SYS_setitimer, which, new, old); +} diff --git a/third_party/ulib/musl/src/signal/sigaction.c b/third_party/ulib/musl/src/signal/sigaction.c new file mode 100644 index 000000000..9c88d6725 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigaction.c @@ -0,0 +1,59 @@ +#include "ksigaction.h" +#include "libc.h" +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include + +static int unmask_done; +static unsigned long handler_set[_NSIG / (8 * sizeof(long))]; + +void __get_handler_set(sigset_t* set) { + memcpy(set, handler_set, sizeof handler_set); +} + +int __libc_sigaction(int sig, const struct sigaction* restrict sa, struct sigaction* restrict old) { + struct k_sigaction ksa, ksa_old; + if (sa) { + if ((uintptr_t)sa->sa_handler > 1UL) { + a_or_l(handler_set + (sig - 1) / (8 * sizeof(long)), + 1UL << (sig - 1) % (8 * sizeof(long))); + + /* If pthread_create has not yet been called, + * implementation-internal signals might not + * yet have been unblocked. They must be + * unblocked before any signal handler is + * installed, so that an application cannot + * receive an illegal sigset_t (with them + * blocked) as part of the ucontext_t passed + * to the signal handler. */ + if (!libc.threaded && !unmask_done) { + __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG / 8); + unmask_done = 1; + } + } + ksa.handler = sa->sa_handler; + ksa.flags = sa->sa_flags | SA_RESTORER; + ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore; + memcpy(&ksa.mask, &sa->sa_mask, sizeof ksa.mask); + } + if (syscall(SYS_rt_sigaction, sig, sa ? &ksa : 0, old ? &ksa_old : 0, sizeof ksa.mask)) + return -1; + if (old) { + old->sa_handler = ksa_old.handler; + old->sa_flags = ksa_old.flags; + memcpy(&old->sa_mask, &ksa_old.mask, sizeof ksa_old.mask); + } + return 0; +} + +int __sigaction(int sig, const struct sigaction* restrict sa, struct sigaction* restrict old) { + if (sig - 32U < 3 || sig - 1U >= _NSIG - 1) { + errno = EINVAL; + return -1; + } + return __libc_sigaction(sig, sa, old); +} + +weak_alias(__sigaction, sigaction); diff --git a/third_party/ulib/musl/src/signal/sigaddset.c b/third_party/ulib/musl/src/signal/sigaddset.c new file mode 100644 index 000000000..27ed054f7 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigaddset.c @@ -0,0 +1,12 @@ +#include +#include + +int sigaddset(sigset_t* set, int sig) { + unsigned s = sig - 1; + if (s >= _NSIG - 1 || sig - 32U < 3) { + errno = EINVAL; + return -1; + } + set->__bits[s / 8 / sizeof *set->__bits] |= 1UL << (s & 8 * sizeof *set->__bits - 1); + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sigaltstack.c b/third_party/ulib/musl/src/signal/sigaltstack.c new file mode 100644 index 000000000..ac59dae93 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigaltstack.c @@ -0,0 +1,17 @@ +#include "syscall.h" +#include +#include + +int sigaltstack(const stack_t* restrict ss, stack_t* restrict old) { + if (ss) { + if (ss->ss_size < MINSIGSTKSZ) { + errno = ENOMEM; + return -1; + } + if (ss->ss_flags & ~SS_DISABLE) { + errno = EINVAL; + return -1; + } + } + return syscall(SYS_sigaltstack, ss, old); +} diff --git a/third_party/ulib/musl/src/signal/sigandset.c b/third_party/ulib/musl/src/signal/sigandset.c new file mode 100644 index 000000000..df1f97ad0 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigandset.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include + +#define SST_SIZE (_NSIG / 8 / sizeof(long)) + +int sigandset(sigset_t* dest, const sigset_t* left, const sigset_t* right) { + unsigned long i = 0, *d = (void *)dest, *l = (void *)left, *r = (void *)right; + for (; i < SST_SIZE; i++) + d[i] = l[i] & r[i]; + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sigdelset.c b/third_party/ulib/musl/src/signal/sigdelset.c new file mode 100644 index 000000000..a4f174ff1 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigdelset.c @@ -0,0 +1,12 @@ +#include +#include + +int sigdelset(sigset_t* set, int sig) { + unsigned s = sig - 1; + if (s >= _NSIG - 1 || sig - 32U < 3) { + errno = EINVAL; + return -1; + } + set->__bits[s / 8 / sizeof *set->__bits] &= ~(1UL << (s & 8 * sizeof *set->__bits - 1)); + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sigemptyset.c b/third_party/ulib/musl/src/signal/sigemptyset.c new file mode 100644 index 000000000..4ecdb5bc9 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigemptyset.c @@ -0,0 +1,12 @@ +#include +#include + +int sigemptyset(sigset_t* set) { + set->__bits[0] = 0; + if (sizeof(long) == 4 || _NSIG > 65) set->__bits[1] = 0; + if (sizeof(long) == 4 && _NSIG > 65) { + set->__bits[2] = 0; + set->__bits[3] = 0; + } + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sigfillset.c b/third_party/ulib/musl/src/signal/sigfillset.c new file mode 100644 index 000000000..9f721b2ce --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigfillset.c @@ -0,0 +1,17 @@ +#include +#include + +int sigfillset(sigset_t* set) { +#if ULONG_MAX == 0xffffffff + set->__bits[0] = 0x7ffffffful; + set->__bits[1] = 0xfffffffcul; + if (_NSIG > 65) { + set->__bits[2] = 0xfffffffful; + set->__bits[3] = 0xfffffffful; + } +#else + set->__bits[0] = 0xfffffffc7ffffffful; + if (_NSIG > 65) set->__bits[1] = 0xfffffffffffffffful; +#endif + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sighold.c b/third_party/ulib/musl/src/signal/sighold.c new file mode 100644 index 000000000..1f1ef191e --- /dev/null +++ b/third_party/ulib/musl/src/signal/sighold.c @@ -0,0 +1,9 @@ +#include + +int sighold(int sig) { + sigset_t mask; + + sigemptyset(&mask); + if (sigaddset(&mask, sig) < 0) return -1; + return sigprocmask(SIG_BLOCK, &mask, 0); +} diff --git a/third_party/ulib/musl/src/signal/sigignore.c b/third_party/ulib/musl/src/signal/sigignore.c new file mode 100644 index 000000000..0e89778c9 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigignore.c @@ -0,0 +1,10 @@ +#include + +int sigignore(int sig) { + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + return sigaction(sig, &sa, 0); +} diff --git a/third_party/ulib/musl/src/signal/siginterrupt.c b/third_party/ulib/musl/src/signal/siginterrupt.c new file mode 100644 index 000000000..e5aac66fe --- /dev/null +++ b/third_party/ulib/musl/src/signal/siginterrupt.c @@ -0,0 +1,13 @@ +#include + +int siginterrupt(int sig, int flag) { + struct sigaction sa; + + sigaction(sig, 0, &sa); + if (flag) + sa.sa_flags &= ~SA_RESTART; + else + sa.sa_flags |= SA_RESTART; + + return sigaction(sig, &sa, 0); +} diff --git a/third_party/ulib/musl/src/signal/sigisemptyset.c b/third_party/ulib/musl/src/signal/sigisemptyset.c new file mode 100644 index 000000000..468db9ca9 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigisemptyset.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include +#include + +int sigisemptyset(const sigset_t* set) { + static const unsigned long zeroset[_NSIG / 8 / sizeof(long)]; + return !memcmp(set, &zeroset, _NSIG / 8); +} diff --git a/third_party/ulib/musl/src/signal/sigismember.c b/third_party/ulib/musl/src/signal/sigismember.c new file mode 100644 index 000000000..edb043ab3 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigismember.c @@ -0,0 +1,7 @@ +#include + +int sigismember(const sigset_t* set, int sig) { + unsigned s = sig - 1; + if (s >= _NSIG - 1) return 0; + return !!(set->__bits[s / 8 / sizeof *set->__bits] & 1UL << (s & 8 * sizeof *set->__bits - 1)); +} diff --git a/third_party/ulib/musl/src/signal/siglongjmp.c b/third_party/ulib/musl/src/signal/siglongjmp.c new file mode 100644 index 000000000..ad7b05147 --- /dev/null +++ b/third_party/ulib/musl/src/signal/siglongjmp.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" +#include "syscall.h" +#include +#include + +_Noreturn void siglongjmp(sigjmp_buf buf, int ret) { + longjmp(buf, ret); +} diff --git a/third_party/ulib/musl/src/signal/signal.c b/third_party/ulib/musl/src/signal/signal.c new file mode 100644 index 000000000..d40e39001 --- /dev/null +++ b/third_party/ulib/musl/src/signal/signal.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "syscall.h" +#include + +int __sigaction(int, const struct sigaction*, struct sigaction*); + +void (*signal(int sig, void (*func)(int)))(int) { + struct sigaction sa_old, sa = {.sa_handler = func, .sa_flags = SA_RESTART}; + if (__sigaction(sig, &sa, &sa_old) < 0) return SIG_ERR; + return sa_old.sa_handler; +} + +weak_alias(signal, bsd_signal); +weak_alias(signal, __sysv_signal); diff --git a/third_party/ulib/musl/src/signal/sigorset.c b/third_party/ulib/musl/src/signal/sigorset.c new file mode 100644 index 000000000..d108b13c7 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigorset.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include + +#define SST_SIZE (_NSIG / 8 / sizeof(long)) + +int sigorset(sigset_t* dest, const sigset_t* left, const sigset_t* right) { + unsigned long i = 0, *d = (void *)dest, *l = (void *)left, *r = (void *)right; + for (; i < SST_SIZE; i++) + d[i] = l[i] | r[i]; + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sigpause.c b/third_party/ulib/musl/src/signal/sigpause.c new file mode 100644 index 000000000..d3fba4de2 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigpause.c @@ -0,0 +1,8 @@ +#include + +int sigpause(int sig) { + sigset_t mask; + sigprocmask(0, 0, &mask); + sigdelset(&mask, sig); + return sigsuspend(&mask); +} diff --git a/third_party/ulib/musl/src/signal/sigpending.c b/third_party/ulib/musl/src/signal/sigpending.c new file mode 100644 index 000000000..56cf2c919 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigpending.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int sigpending(sigset_t* set) { + return syscall(SYS_rt_sigpending, set, _NSIG / 8); +} diff --git a/third_party/ulib/musl/src/signal/sigprocmask.c b/third_party/ulib/musl/src/signal/sigprocmask.c new file mode 100644 index 000000000..d1fc87994 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigprocmask.c @@ -0,0 +1,9 @@ +#include +#include + +int sigprocmask(int how, const sigset_t* restrict set, sigset_t* restrict old) { + int r = pthread_sigmask(how, set, old); + if (!r) return r; + errno = r; + return -1; +} diff --git a/third_party/ulib/musl/src/signal/sigqueue.c b/third_party/ulib/musl/src/signal/sigqueue.c new file mode 100644 index 000000000..942bb1939 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigqueue.c @@ -0,0 +1,21 @@ +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include + +int sigqueue(pid_t pid, int sig, const union sigval value) { + siginfo_t si; + sigset_t set; + int r; + memset(&si, 0, sizeof si); + si.si_signo = sig; + si.si_code = SI_QUEUE; + si.si_value = value; + si.si_uid = getuid(); + __block_app_sigs(&set); + si.si_pid = getpid(); + r = syscall(SYS_rt_sigqueueinfo, pid, sig, &si); + __restore_sigs(&set); + return r; +} diff --git a/third_party/ulib/musl/src/signal/sigrelse.c b/third_party/ulib/musl/src/signal/sigrelse.c new file mode 100644 index 000000000..bafdd440c --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigrelse.c @@ -0,0 +1,9 @@ +#include + +int sigrelse(int sig) { + sigset_t mask; + + sigemptyset(&mask); + if (sigaddset(&mask, sig) < 0) return -1; + return sigprocmask(SIG_UNBLOCK, &mask, 0); +} diff --git a/third_party/ulib/musl/src/signal/sigrtmax.c b/third_party/ulib/musl/src/signal/sigrtmax.c new file mode 100644 index 000000000..8994895c8 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigrtmax.c @@ -0,0 +1,5 @@ +#include + +int __libc_current_sigrtmax() { + return _NSIG - 1; +} diff --git a/third_party/ulib/musl/src/signal/sigrtmin.c b/third_party/ulib/musl/src/signal/sigrtmin.c new file mode 100644 index 000000000..087ffcd23 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigrtmin.c @@ -0,0 +1,3 @@ +int __libc_current_sigrtmin(void) { + return 35; +} diff --git a/third_party/ulib/musl/src/signal/sigset.c b/third_party/ulib/musl/src/signal/sigset.c new file mode 100644 index 000000000..53b56e860 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigset.c @@ -0,0 +1,21 @@ +#include + +void (*sigset(int sig, void (*handler)(int)))(int) { + struct sigaction sa, sa_old; + sigset_t mask; + + sigemptyset(&mask); + if (sigaddset(&mask, sig) < 0) return SIG_ERR; + + if (handler == SIG_HOLD) { + if (sigaction(sig, 0, &sa_old) < 0) return SIG_ERR; + if (sigprocmask(SIG_BLOCK, &mask, &mask) < 0) return SIG_ERR; + } else { + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, &sa_old) < 0) return SIG_ERR; + if (sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) return SIG_ERR; + } + return sigismember(&mask, sig) ? SIG_HOLD : sa_old.sa_handler; +} diff --git a/third_party/ulib/musl/src/signal/sigsetjmp.c b/third_party/ulib/musl/src/signal/sigsetjmp.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/signal/sigsetjmp_tail.c b/third_party/ulib/musl/src/signal/sigsetjmp_tail.c new file mode 100644 index 000000000..326bac0f1 --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigsetjmp_tail.c @@ -0,0 +1,9 @@ +#include "syscall.h" +#include +#include + +__attribute__((__visibility__("hidden"))) int __sigsetjmp_tail(sigjmp_buf jb, int ret) { + void* p = jb->__ss; + __syscall(SYS_rt_sigprocmask, SIG_SETMASK, ret ? p : 0, ret ? 0 : p, _NSIG / 8); + return ret; +} diff --git a/third_party/ulib/musl/src/signal/sigsuspend.c b/third_party/ulib/musl/src/signal/sigsuspend.c new file mode 100644 index 000000000..d4cef922b --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigsuspend.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int sigsuspend(const sigset_t* mask) { + return syscall(SYS_rt_sigsuspend, mask, _NSIG / 8); +} diff --git a/third_party/ulib/musl/src/signal/sigtimedwait.c b/third_party/ulib/musl/src/signal/sigtimedwait.c new file mode 100644 index 000000000..c65227d9b --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigtimedwait.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int sigtimedwait(const sigset_t* restrict mask, siginfo_t* restrict si, + const struct timespec* restrict timeout) { + int ret; + do + ret = syscall(SYS_rt_sigtimedwait, mask, si, timeout, _NSIG / 8); + while (ret < 0 && errno == EINTR); + return ret; +} diff --git a/third_party/ulib/musl/src/signal/sigwait.c b/third_party/ulib/musl/src/signal/sigwait.c new file mode 100644 index 000000000..7981fb3bb --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigwait.c @@ -0,0 +1,8 @@ +#include + +int sigwait(const sigset_t* restrict mask, int* restrict sig) { + siginfo_t si; + if (sigtimedwait(mask, &si, 0) < 0) return -1; + *sig = si.si_signo; + return 0; +} diff --git a/third_party/ulib/musl/src/signal/sigwaitinfo.c b/third_party/ulib/musl/src/signal/sigwaitinfo.c new file mode 100644 index 000000000..08e330aee --- /dev/null +++ b/third_party/ulib/musl/src/signal/sigwaitinfo.c @@ -0,0 +1,5 @@ +#include + +int sigwaitinfo(const sigset_t* restrict mask, siginfo_t* restrict si) { + return sigtimedwait(mask, si, 0); +} diff --git a/third_party/ulib/musl/src/signal/x32/restore.s b/third_party/ulib/musl/src/signal/x32/restore.s new file mode 100644 index 000000000..27cd3cef9 --- /dev/null +++ b/third_party/ulib/musl/src/signal/x32/restore.s @@ -0,0 +1,8 @@ +.global __restore_rt +.global __restore +.type __restore_rt,@function +.type __restore,@function +__restore_rt: +__restore: + movl $0x40000201, %eax /* SYS_rt_sigreturn */ + syscall diff --git a/third_party/ulib/musl/src/signal/x32/sigsetjmp.s b/third_party/ulib/musl/src/signal/x32/sigsetjmp.s new file mode 100644 index 000000000..1f02b0e50 --- /dev/null +++ b/third_party/ulib/musl/src/signal/x32/sigsetjmp.s @@ -0,0 +1,25 @@ +.global sigsetjmp +.global __sigsetjmp +.type sigsetjmp,@function +.type __sigsetjmp,@function +sigsetjmp: +__sigsetjmp: + test %esi,%esi + jz 1f + + popq 64(%rdi) + mov %rbx,72+8(%rdi) + mov %rdi,%rbx + + call setjmp@PLT + + pushq 64(%rbx) + movl $0, 4(%rsp) + mov %rbx,%rdi + mov %eax,%esi + mov 72+8(%rbx),%rbx + +.hidden __sigsetjmp_tail + jmp __sigsetjmp_tail + +1: jmp setjmp@PLT diff --git a/third_party/ulib/musl/src/signal/x86_64/restore.s b/third_party/ulib/musl/src/signal/x86_64/restore.s new file mode 100644 index 000000000..682af2dd8 --- /dev/null +++ b/third_party/ulib/musl/src/signal/x86_64/restore.s @@ -0,0 +1,8 @@ +.global __restore_rt +.global __restore +.type __restore_rt,@function +.type __restore,@function +__restore_rt: +__restore: + movl $15, %eax + syscall diff --git a/third_party/ulib/musl/src/signal/x86_64/sigsetjmp.s b/third_party/ulib/musl/src/signal/x86_64/sigsetjmp.s new file mode 100644 index 000000000..9a7695f96 --- /dev/null +++ b/third_party/ulib/musl/src/signal/x86_64/sigsetjmp.s @@ -0,0 +1,24 @@ +.global sigsetjmp +.global __sigsetjmp +.type sigsetjmp,@function +.type __sigsetjmp,@function +sigsetjmp: +__sigsetjmp: + test %esi,%esi + jz 1f + + popq 64(%rdi) + mov %rbx,72+8(%rdi) + mov %rdi,%rbx + + call setjmp@PLT + + pushq 64(%rbx) + mov %rbx,%rdi + mov %eax,%esi + mov 72+8(%rbx),%rbx + +.hidden __sigsetjmp_tail + jmp __sigsetjmp_tail + +1: jmp setjmp@PLT diff --git a/third_party/ulib/musl/src/stat/BUILD.gn b/third_party/ulib/musl/src/stat/BUILD.gn new file mode 100644 index 000000000..7da04ad5c --- /dev/null +++ b/third_party/ulib/musl/src/stat/BUILD.gn @@ -0,0 +1,32 @@ +source_set("stat") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__xstat.c", + "chmod.c", + "fchmod.c", + "fchmodat.c", + "fstatat.c", + "futimens.c", + "futimesat.c", + "lchmod.c", + "lstat.c", + "mkdir.c", + "mkdirat.c", + "mkfifo.c", + "mkfifoat.c", + "mknod.c", + "mknodat.c", + "statvfs.c", + "umask.c", + "utimensat.c", + + # The following are not built until we have mxio and libc standing in + # proper relation to each other. + # + # "fstat.c", + # "stat.c", + ] +} diff --git a/third_party/ulib/musl/src/stat/__xstat.c b/third_party/ulib/musl/src/stat/__xstat.c new file mode 100644 index 000000000..9cbc89d4e --- /dev/null +++ b/third_party/ulib/musl/src/stat/__xstat.c @@ -0,0 +1,31 @@ +#include "libc.h" +#include + +int __fxstat(int ver, int fd, struct stat* buf) { + return fstat(fd, buf); +} + +int __fxstatat(int ver, int fd, const char* path, struct stat* buf, int flag) { + return fstatat(fd, path, buf, flag); +} + +int __lxstat(int ver, const char* path, struct stat* buf) { + return lstat(path, buf); +} + +int __xstat(int ver, const char* path, struct stat* buf) { + return stat(path, buf); +} + +LFS64(__fxstat); +LFS64(__fxstatat); +LFS64(__lxstat); +LFS64(__xstat); + +int __xmknod(int ver, const char* path, mode_t mode, dev_t* dev) { + return mknod(path, mode, *dev); +} + +int __xmknodat(int ver, int fd, const char* path, mode_t mode, dev_t* dev) { + return mknodat(fd, path, mode, *dev); +} diff --git a/third_party/ulib/musl/src/stat/chmod.c b/third_party/ulib/musl/src/stat/chmod.c new file mode 100644 index 000000000..d512d0c8f --- /dev/null +++ b/third_party/ulib/musl/src/stat/chmod.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int chmod(const char* path, mode_t mode) { +#ifdef SYS_chmod + return syscall(SYS_chmod, path, mode); +#else + return syscall(SYS_fchmodat, AT_FDCWD, path, mode); +#endif +} diff --git a/third_party/ulib/musl/src/stat/fchmod.c b/third_party/ulib/musl/src/stat/fchmod.c new file mode 100644 index 000000000..f7138d5e7 --- /dev/null +++ b/third_party/ulib/musl/src/stat/fchmod.c @@ -0,0 +1,19 @@ +#include "syscall.h" +#include +#include +#include + +void __procfdname(char*, unsigned); + +int fchmod(int fd, mode_t mode) { + int ret = __syscall(SYS_fchmod, fd, mode); + if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0) return __syscall_ret(ret); + + char buf[15 + 3 * sizeof(int)]; + __procfdname(buf, fd); +#ifdef SYS_chmod + return syscall(SYS_chmod, buf, mode); +#else + return syscall(SYS_fchmodat, AT_FDCWD, buf, mode); +#endif +} diff --git a/third_party/ulib/musl/src/stat/fchmodat.c b/third_party/ulib/musl/src/stat/fchmodat.c new file mode 100644 index 000000000..9fb960103 --- /dev/null +++ b/third_party/ulib/musl/src/stat/fchmodat.c @@ -0,0 +1,37 @@ +#include "syscall.h" +#include +#include +#include + +void __procfdname(char*, unsigned); + +int fchmodat(int fd, const char* path, mode_t mode, int flag) { + if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag); + + if (flag != AT_SYMLINK_NOFOLLOW) return __syscall_ret(-EINVAL); + + struct stat st; + int ret, fd2; + char proc[15 + 3 * sizeof(int)]; + + if ((ret = __syscall(SYS_fstatat, fd, path, &st, flag))) return __syscall_ret(ret); + if (S_ISLNK(st.st_mode)) return __syscall_ret(-EOPNOTSUPP); + + if ((fd2 = __syscall(SYS_openat, fd, path, + O_RDONLY | O_PATH | O_NOFOLLOW | O_NOCTTY | O_CLOEXEC)) < 0) { + if (fd2 == -ELOOP) return __syscall_ret(-EOPNOTSUPP); + return __syscall_ret(fd2); + } + + __procfdname(proc, fd2); + ret = __syscall(SYS_fstatat, AT_FDCWD, proc, &st, 0); + if (!ret) { + if (S_ISLNK(st.st_mode)) + ret = -EOPNOTSUPP; + else + ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode); + } + + __syscall(SYS_close, fd2); + return __syscall_ret(ret); +} diff --git a/third_party/ulib/musl/src/stat/fstat.c b/third_party/ulib/musl/src/stat/fstat.c new file mode 100644 index 000000000..339ac2746 --- /dev/null +++ b/third_party/ulib/musl/src/stat/fstat.c @@ -0,0 +1,22 @@ +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +void __procfdname(char*, unsigned); + +int fstat(int fd, struct stat* st) { + int ret = __syscall(SYS_fstat, fd, st); + if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0) return __syscall_ret(ret); + + char buf[15 + 3 * sizeof(int)]; + __procfdname(buf, fd); +#ifdef SYS_stat + return syscall(SYS_stat, buf, st); +#else + return syscall(SYS_fstatat, AT_FDCWD, buf, st, 0); +#endif +} + +LFS64(fstat); diff --git a/third_party/ulib/musl/src/stat/fstatat.c b/third_party/ulib/musl/src/stat/fstatat.c new file mode 100644 index 000000000..6acd832a1 --- /dev/null +++ b/third_party/ulib/musl/src/stat/fstatat.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +int fstatat(int fd, const char* restrict path, struct stat* restrict buf, int flag) { + return syscall(SYS_fstatat, fd, path, buf, flag); +} + +LFS64(fstatat); diff --git a/third_party/ulib/musl/src/stat/futimens.c b/third_party/ulib/musl/src/stat/futimens.c new file mode 100644 index 000000000..94449399d --- /dev/null +++ b/third_party/ulib/musl/src/stat/futimens.c @@ -0,0 +1,5 @@ +#include + +int futimens(int fd, const struct timespec times[2]) { + return utimensat(fd, 0, times, 0); +} diff --git a/third_party/ulib/musl/src/stat/futimesat.c b/third_party/ulib/musl/src/stat/futimesat.c new file mode 100644 index 000000000..e80d0e705 --- /dev/null +++ b/third_party/ulib/musl/src/stat/futimesat.c @@ -0,0 +1,21 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +int __futimesat(int dirfd, const char* pathname, const struct timeval times[2]) { + struct timespec ts[2]; + if (times) { + int i; + for (i = 0; i < 2; i++) { + if (times[i].tv_usec >= 1000000ULL) return __syscall_ret(-EINVAL); + ts[i].tv_sec = times[i].tv_sec; + ts[i].tv_nsec = times[i].tv_usec * 1000; + } + } + return utimensat(dirfd, pathname, times ? ts : 0, 0); +} + +weak_alias(__futimesat, futimesat); diff --git a/third_party/ulib/musl/src/stat/lchmod.c b/third_party/ulib/musl/src/stat/lchmod.c new file mode 100644 index 000000000..4966123a2 --- /dev/null +++ b/third_party/ulib/musl/src/stat/lchmod.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include +#include + +int lchmod(const char* path, mode_t mode) { + return fchmodat(AT_FDCWD, path, mode, AT_SYMLINK_NOFOLLOW); +} diff --git a/third_party/ulib/musl/src/stat/lstat.c b/third_party/ulib/musl/src/stat/lstat.c new file mode 100644 index 000000000..a6b180fc6 --- /dev/null +++ b/third_party/ulib/musl/src/stat/lstat.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int lstat(const char* restrict path, struct stat* restrict buf) { +#ifdef SYS_lstat + return syscall(SYS_lstat, path, buf); +#else + return syscall(SYS_fstatat, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); +#endif +} + +LFS64(lstat); diff --git a/third_party/ulib/musl/src/stat/mkdir.c b/third_party/ulib/musl/src/stat/mkdir.c new file mode 100644 index 000000000..20776d896 --- /dev/null +++ b/third_party/ulib/musl/src/stat/mkdir.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int mkdir(const char* path, mode_t mode) { +#ifdef SYS_mkdir + return syscall(SYS_mkdir, path, mode); +#else + return syscall(SYS_mkdirat, AT_FDCWD, path, mode); +#endif +} diff --git a/third_party/ulib/musl/src/stat/mkdirat.c b/third_party/ulib/musl/src/stat/mkdirat.c new file mode 100644 index 000000000..6dc05f82d --- /dev/null +++ b/third_party/ulib/musl/src/stat/mkdirat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mkdirat(int fd, const char* path, mode_t mode) { + return syscall(SYS_mkdirat, fd, path, mode); +} diff --git a/third_party/ulib/musl/src/stat/mkfifo.c b/third_party/ulib/musl/src/stat/mkfifo.c new file mode 100644 index 000000000..ecc0d03cf --- /dev/null +++ b/third_party/ulib/musl/src/stat/mkfifo.c @@ -0,0 +1,5 @@ +#include + +int mkfifo(const char* path, mode_t mode) { + return mknod(path, mode | S_IFIFO, 0); +} diff --git a/third_party/ulib/musl/src/stat/mkfifoat.c b/third_party/ulib/musl/src/stat/mkfifoat.c new file mode 100644 index 000000000..b4f21c701 --- /dev/null +++ b/third_party/ulib/musl/src/stat/mkfifoat.c @@ -0,0 +1,5 @@ +#include + +int mkfifoat(int fd, const char* path, mode_t mode) { + return mknodat(fd, path, mode | S_IFIFO, 0); +} diff --git a/third_party/ulib/musl/src/stat/mknod.c b/third_party/ulib/musl/src/stat/mknod.c new file mode 100644 index 000000000..4a510c434 --- /dev/null +++ b/third_party/ulib/musl/src/stat/mknod.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int mknod(const char* path, mode_t mode, dev_t dev) { +#ifdef SYS_mknod + return syscall(SYS_mknod, path, mode, dev); +#else + return syscall(SYS_mknodat, AT_FDCWD, path, mode, dev); +#endif +} diff --git a/third_party/ulib/musl/src/stat/mknodat.c b/third_party/ulib/musl/src/stat/mknodat.c new file mode 100644 index 000000000..8cf41a0ec --- /dev/null +++ b/third_party/ulib/musl/src/stat/mknodat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int mknodat(int fd, const char* path, mode_t mode, dev_t dev) { + return syscall(SYS_mknodat, fd, path, mode, dev); +} diff --git a/third_party/ulib/musl/src/stat/stat.c b/third_party/ulib/musl/src/stat/stat.c new file mode 100644 index 000000000..571f4425b --- /dev/null +++ b/third_party/ulib/musl/src/stat/stat.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int stat(const char* restrict path, struct stat* restrict buf) { +#ifdef SYS_stat + return syscall(SYS_stat, path, buf); +#else + return syscall(SYS_fstatat, AT_FDCWD, path, buf, 0); +#endif +} + +LFS64(stat); diff --git a/third_party/ulib/musl/src/stat/statvfs.c b/third_party/ulib/musl/src/stat/statvfs.c new file mode 100644 index 000000000..d2b368db7 --- /dev/null +++ b/third_party/ulib/musl/src/stat/statvfs.c @@ -0,0 +1,59 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int __statfs(const char* path, struct statfs* buf) { + *buf = (struct statfs){0}; +#ifdef SYS_statfs64 + return syscall(SYS_statfs64, path, sizeof *buf, buf); +#else + return syscall(SYS_statfs, path, buf); +#endif +} + +int __fstatfs(int fd, struct statfs* buf) { + *buf = (struct statfs){0}; +#ifdef SYS_fstatfs64 + return syscall(SYS_fstatfs64, fd, sizeof *buf, buf); +#else + return syscall(SYS_fstatfs, fd, buf); +#endif +} + +weak_alias(__statfs, statfs); +weak_alias(__fstatfs, fstatfs); + +static void fixup(struct statvfs* out, const struct statfs* in) { + *out = (struct statvfs){0}; + out->f_bsize = in->f_bsize; + out->f_frsize = in->f_frsize ? in->f_frsize : in->f_bsize; + out->f_blocks = in->f_blocks; + out->f_bfree = in->f_bfree; + out->f_bavail = in->f_bavail; + out->f_files = in->f_files; + out->f_ffree = in->f_ffree; + out->f_favail = in->f_ffree; + out->f_fsid = in->f_fsid.__val[0]; + out->f_flag = in->f_flags; + out->f_namemax = in->f_namelen; +} + +int statvfs(const char* restrict path, struct statvfs* restrict buf) { + struct statfs kbuf; + if (__statfs(path, &kbuf) < 0) return -1; + fixup(buf, &kbuf); + return 0; +} + +int fstatvfs(int fd, struct statvfs* buf) { + struct statfs kbuf; + if (__fstatfs(fd, &kbuf) < 0) return -1; + fixup(buf, &kbuf); + return 0; +} + +LFS64(statvfs); +LFS64(statfs); +LFS64(fstatvfs); +LFS64(fstatfs); diff --git a/third_party/ulib/musl/src/stat/umask.c b/third_party/ulib/musl/src/stat/umask.c new file mode 100644 index 000000000..8fd567d28 --- /dev/null +++ b/third_party/ulib/musl/src/stat/umask.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +mode_t umask(mode_t mode) { + return syscall(SYS_umask, mode); +} diff --git a/third_party/ulib/musl/src/stat/utimensat.c b/third_party/ulib/musl/src/stat/utimensat.c new file mode 100644 index 000000000..cff1c332b --- /dev/null +++ b/third_party/ulib/musl/src/stat/utimensat.c @@ -0,0 +1,34 @@ +#include "syscall.h" +#include +#include +#include +#include + +int utimensat(int fd, const char* path, const struct timespec times[2], int flags) { + int r = __syscall(SYS_utimensat, fd, path, times, flags); +#ifdef SYS_futimesat + if (r != -ENOSYS || flags) return __syscall_ret(r); + struct timeval *tv = 0, tmp[2]; + if (times) { + int i; + tv = tmp; + for (i = 0; i < 2; i++) { + if (times[i].tv_nsec >= 1000000000ULL) { + if (times[i].tv_nsec == UTIME_NOW && times[1 - i].tv_nsec == UTIME_NOW) { + tv = 0; + break; + } + if (times[i].tv_nsec == UTIME_OMIT) return __syscall_ret(-ENOSYS); + return __syscall_ret(-EINVAL); + } + tmp[i].tv_sec = times[i].tv_sec; + tmp[i].tv_usec = times[i].tv_nsec / 1000; + } + } + + r = __syscall(SYS_futimesat, fd, path, tv); + if (r != -ENOSYS || fd != AT_FDCWD) return __syscall_ret(r); + r = __syscall(SYS_utimes, path, tv); +#endif + return __syscall_ret(r); +} diff --git a/third_party/ulib/musl/src/stdio/BUILD.gn b/third_party/ulib/musl/src/stdio/BUILD.gn new file mode 100644 index 000000000..b9f700f4b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/BUILD.gn @@ -0,0 +1,125 @@ +source_set("stdio") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__fclose_ca.c", + "__fdopen.c", + "__fmodeflags.c", + "__fopen_rb_ca.c", + "__lockfile.c", + "__overflow.c", + "__stdio_close.c", + "__stdio_exit.c", + "__stdio_read.c", + "__stdio_seek.c", + "__stdio_write.c", + "__stdout_write.c", + "__string_read.c", + "__toread.c", + "__towrite.c", + "__uflow.c", + "asprintf.c", + "clearerr.c", + "dprintf.c", + "ext.c", + "ext2.c", + "fclose.c", + "feof.c", + "ferror.c", + "fflush.c", + "fgetc.c", + "fgetln.c", + "fgetpos.c", + "fgets.c", + "fgetwc.c", + "fgetws.c", + "fileno.c", + + #"flockfile.c", + "fmemopen.c", + "fopen.c", + "fprintf.c", + "fputc.c", + "fputs.c", + "fputwc.c", + "fputws.c", + "fread.c", + "freopen.c", + "fscanf.c", + "fseek.c", + "fsetpos.c", + "ftell.c", + "ftrylockfile.c", + "funlockfile.c", + "fwide.c", + "fwprintf.c", + "fwrite.c", + "fwscanf.c", + "getc.c", + "getc_unlocked.c", + "getchar.c", + "getchar_unlocked.c", + "getdelim.c", + "getline.c", + "gets.c", + "getw.c", + "getwc.c", + "getwchar.c", + "ofl.c", + "ofl_add.c", + "open_memstream.c", + "open_wmemstream.c", + "pclose.c", + "perror.c", + "popen.c", + "printf.c", + "putc.c", + "putc_unlocked.c", + "putchar.c", + "putchar_unlocked.c", + "puts.c", + "putw.c", + "putwc.c", + "putwchar.c", + "remove.c", + "rename.c", + "rewind.c", + "scanf.c", + "setbuf.c", + "setbuffer.c", + "setlinebuf.c", + "setvbuf.c", + "snprintf.c", + "sprintf.c", + "sscanf.c", + "stderr.c", + "stdin.c", + "stdout.c", + "swprintf.c", + "swscanf.c", + "tempnam.c", + "tmpfile.c", + "tmpnam.c", + "ungetc.c", + "ungetwc.c", + "vasprintf.c", + "vdprintf.c", + "vfprintf.c", + "vfscanf.c", + "vfwprintf.c", + "vfwscanf.c", + "vprintf.c", + "vscanf.c", + "vsnprintf.c", + "vsprintf.c", + "vsscanf.c", + "vswprintf.c", + "vswscanf.c", + "vwprintf.c", + "vwscanf.c", + "wprintf.c", + "wscanf.c", + ] +} diff --git a/third_party/ulib/musl/src/stdio/__fclose_ca.c b/third_party/ulib/musl/src/stdio/__fclose_ca.c new file mode 100644 index 000000000..7242fa877 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__fclose_ca.c @@ -0,0 +1,5 @@ +#include "stdio_impl.h" + +int __fclose_ca(FILE* f) { + return f->close(f); +} diff --git a/third_party/ulib/musl/src/stdio/__fdopen.c b/third_party/ulib/musl/src/stdio/__fdopen.c new file mode 100644 index 000000000..9add71a5e --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__fdopen.c @@ -0,0 +1,57 @@ +#include "stdio_impl.h" +#include +#include +#include +#include +#include + +FILE* __fdopen(int fd, const char* mode) { + FILE* f; + struct winsize wsz; + + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + /* Allocate FILE+buffer or fail */ + if (!(f = malloc(sizeof *f + UNGET + BUFSIZ))) return 0; + + /* Zero-fill only the struct, not the buffer */ + memset(f, 0, sizeof *f); + + /* Impose mode restrictions */ + if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD; + + /* Apply close-on-exec flag */ + if (strchr(mode, 'e')) __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); + + /* Set append mode on fd if opened for append */ + if (*mode == 'a') { + int flags = __syscall(SYS_fcntl, fd, F_GETFL); + if (!(flags & O_APPEND)) __syscall(SYS_fcntl, fd, F_SETFL, flags | O_APPEND); + f->flags |= F_APP; + } + + f->fd = fd; + f->buf = (unsigned char*)f + sizeof *f + UNGET; + f->buf_size = BUFSIZ; + + /* Activate line buffered mode for terminals */ + f->lbf = EOF; + if (!(f->flags & F_NOWR) && !__syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz)) f->lbf = '\n'; + + /* Initialize op ptrs. No problem if some are unneeded. */ + f->read = __stdio_read; + f->write = __stdio_write; + f->seek = __stdio_seek; + f->close = __stdio_close; + + if (!libc.threaded) f->lock = -1; + + /* Add new FILE to open file list */ + return __ofl_add(f); +} + +weak_alias(__fdopen, fdopen); diff --git a/third_party/ulib/musl/src/stdio/__fmodeflags.c b/third_party/ulib/musl/src/stdio/__fmodeflags.c new file mode 100644 index 000000000..8d43e23af --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__fmodeflags.c @@ -0,0 +1,18 @@ +#include +#include + +int __fmodeflags(const char* mode) { + int flags; + if (strchr(mode, '+')) + flags = O_RDWR; + else if (*mode == 'r') + flags = O_RDONLY; + else + flags = O_WRONLY; + if (strchr(mode, 'x')) flags |= O_EXCL; + if (strchr(mode, 'e')) flags |= O_CLOEXEC; + if (*mode != 'r') flags |= O_CREAT; + if (*mode == 'w') flags |= O_TRUNC; + if (*mode == 'a') flags |= O_APPEND; + return flags; +} diff --git a/third_party/ulib/musl/src/stdio/__fopen_rb_ca.c b/third_party/ulib/musl/src/stdio/__fopen_rb_ca.c new file mode 100644 index 000000000..69c0190ab --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__fopen_rb_ca.c @@ -0,0 +1,21 @@ +#include "stdio_impl.h" +#include +#include + +FILE* __fopen_rb_ca(const char* filename, FILE* f, unsigned char* buf, size_t len) { + memset(f, 0, sizeof *f); + + f->fd = sys_open(filename, O_RDONLY | O_CLOEXEC); + if (f->fd < 0) return 0; + __syscall(SYS_fcntl, f->fd, F_SETFD, FD_CLOEXEC); + + f->flags = F_NOWR | F_PERM; + f->buf = buf + UNGET; + f->buf_size = len - UNGET; + f->read = __stdio_read; + f->seek = __stdio_seek; + f->close = __stdio_close; + f->lock = -1; + + return f; +} diff --git a/third_party/ulib/musl/src/stdio/__lockfile.c b/third_party/ulib/musl/src/stdio/__lockfile.c new file mode 100644 index 000000000..495a1206b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__lockfile.c @@ -0,0 +1,25 @@ +#include "pthread_impl.h" +#include "stdio_impl.h" + +int __lockfile(FILE* f) { + int owner, tid = __pthread_self()->tid; + if (f->lock == tid) return 0; + while ((owner = a_cas(&f->lock, 0, tid))) + __wait(&f->lock, &f->waiters, owner); + return 1; +} + +void __unlockfile(FILE* f) { + a_store(&f->lock, 0); + + /* The following read is technically invalid under situations + * of self-synchronized destruction. Another thread may have + * called fclose as soon as the above store has completed. + * Nonetheless, since FILE objects always live in memory + * obtained by malloc from the heap, it's safe to assume + * the dereferences below will not fault. In the worst case, + * a spurious syscall will be made. If the implementation of + * malloc changes, this assumption needs revisiting. */ + + if (f->waiters) __wake(&f->lock, 1); +} diff --git a/third_party/ulib/musl/src/stdio/__overflow.c b/third_party/ulib/musl/src/stdio/__overflow.c new file mode 100644 index 000000000..7f7b547b9 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__overflow.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +int __overflow(FILE* f, int _c) { + unsigned char c = _c; + if (!f->wend && __towrite(f)) return EOF; + if (f->wpos < f->wend && c != f->lbf) return *f->wpos++ = c; + if (f->write(f, &c, 1) != 1) return EOF; + return c; +} diff --git a/third_party/ulib/musl/src/stdio/__stdio_close.c b/third_party/ulib/musl/src/stdio/__stdio_close.c new file mode 100644 index 000000000..ba7c4f96f --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__stdio_close.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +static int dummy(int fd) { + return fd; +} + +weak_alias(dummy, __aio_close); + +int __stdio_close(FILE* f) { + return 0; +} diff --git a/third_party/ulib/musl/src/stdio/__stdio_exit.c b/third_party/ulib/musl/src/stdio/__stdio_exit.c new file mode 100644 index 000000000..073d0edb5 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__stdio_exit.c @@ -0,0 +1,23 @@ +#include "stdio_impl.h" + +static FILE* volatile dummy_file = 0; +weak_alias(dummy_file, __stdin_used); +weak_alias(dummy_file, __stdout_used); +weak_alias(dummy_file, __stderr_used); + +static void close_file(FILE* f) { + if (!f) return; + FFINALLOCK(f); + if (f->wpos > f->wbase) f->write(f, 0, 0); + if (f->rpos < f->rend) f->seek(f, f->rpos - f->rend, SEEK_CUR); +} + +void __stdio_exit(void) { + FILE* f; + for (f = *__ofl_lock(); f; f = f->next) + close_file(f); + close_file(__stdin_used); + close_file(__stdout_used); +} + +weak_alias(__stdio_exit, __stdio_exit_needed); diff --git a/third_party/ulib/musl/src/stdio/__stdio_read.c b/third_party/ulib/musl/src/stdio/__stdio_read.c new file mode 100644 index 000000000..ce16d710d --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__stdio_read.c @@ -0,0 +1,25 @@ +#include "stdio_impl.h" +#include + +static ssize_t io_readv(int fd, const struct iovec* iov, int num) { + return 0; +} +weak_alias(io_readv, __libc_io_readv); + +size_t __stdio_read(FILE* f, unsigned char* buf, size_t len) { + struct iovec iov[2] = {{.iov_base = buf, .iov_len = len - !!f->buf_size}, + {.iov_base = f->buf, .iov_len = f->buf_size}}; + ssize_t cnt; + + cnt = __libc_io_readv(f->fd, iov, 2); + if (cnt <= 0) { + f->flags |= F_EOF ^ ((F_ERR ^ F_EOF) & cnt); + return cnt; + } + if (cnt <= iov[0].iov_len) return cnt; + cnt -= iov[0].iov_len; + f->rpos = f->buf; + f->rend = f->buf + cnt; + if (f->buf_size) buf[len - 1] = *f->rpos++; + return len; +} diff --git a/third_party/ulib/musl/src/stdio/__stdio_seek.c b/third_party/ulib/musl/src/stdio/__stdio_seek.c new file mode 100644 index 000000000..fa93a45ef --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__stdio_seek.c @@ -0,0 +1,5 @@ +#include "stdio_impl.h" + +off_t __stdio_seek(FILE* f, off_t off, int whence) { + return (off_t)-1; +} diff --git a/third_party/ulib/musl/src/stdio/__stdio_write.c b/third_party/ulib/musl/src/stdio/__stdio_write.c new file mode 100644 index 000000000..7419c1192 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__stdio_write.c @@ -0,0 +1,39 @@ +#include "libc.h" +#include "stdio_impl.h" +#include + +static ssize_t io_write(int fd, const void* buf, size_t count) { + return count; +} + +weak_alias(io_write, __libc_io_write); + +size_t __stdio_write(FILE* f, const unsigned char* buf, size_t len) { + struct iovec iovs[2] = {{.iov_base = f->wbase, .iov_len = f->wpos - f->wbase}, + {.iov_base = (void*)buf, .iov_len = len}}; + struct iovec* iov = iovs; + size_t rem = iov[0].iov_len + iov[1].iov_len; + int iovcnt = 2; + ssize_t cnt = 0; + for (;;) { + cnt = __libc_io_write(f->fd, iov[0].iov_base, iov[0].iov_len); + if (cnt == rem) { + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; + return len; + } + if (cnt < 0) { + f->wpos = f->wbase = f->wend = 0; + f->flags |= F_ERR; + return iovcnt == 2 ? 0 : len - iov[0].iov_len; + } + rem -= cnt; + if (cnt >= iov[0].iov_len) { + cnt -= iov[0].iov_len; + iov++; + iovcnt--; + } + iov[0].iov_base = (char*)iov[0].iov_base + cnt; + iov[0].iov_len -= cnt; + } +} diff --git a/third_party/ulib/musl/src/stdio/__stdout_write.c b/third_party/ulib/musl/src/stdio/__stdout_write.c new file mode 100644 index 000000000..bc1d907c8 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__stdout_write.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" +#include + +size_t __stdout_write(FILE* f, const unsigned char* buf, size_t len) { + f->write = __stdio_write; + if (!(f->flags & F_SVB) && !isatty(f->fd)) f->lbf = -1; + return __stdio_write(f, buf, len); +} diff --git a/third_party/ulib/musl/src/stdio/__string_read.c b/third_party/ulib/musl/src/stdio/__string_read.c new file mode 100644 index 000000000..6974aafe3 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__string_read.c @@ -0,0 +1,15 @@ +#include "stdio_impl.h" +#include + +size_t __string_read(FILE* f, unsigned char* buf, size_t len) { + char* src = f->cookie; + size_t k = len + 256; + char* end = memchr(src, 0, k); + if (end) k = end - src; + if (k < len) len = k; + memcpy(buf, src, len); + f->rpos = (void*)(src + len); + f->rend = (void*)(src + k); + f->cookie = src + k; + return len; +} diff --git a/third_party/ulib/musl/src/stdio/__toread.c b/third_party/ulib/musl/src/stdio/__toread.c new file mode 100644 index 000000000..1baeaa93f --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__toread.c @@ -0,0 +1,19 @@ +#include + +int __toread(FILE* f) { + f->mode |= f->mode - 1; + if (f->wpos > f->wbase) f->write(f, 0, 0); + f->wpos = f->wbase = f->wend = 0; + if (f->flags & F_NORD) { + f->flags |= F_ERR; + return EOF; + } + f->rpos = f->rend = f->buf + f->buf_size; + return (f->flags & F_EOF) ? EOF : 0; +} + +void __stdio_exit_needed(void); + +void __toread_needs_stdio_exit(void) { + __stdio_exit_needed(); +} diff --git a/third_party/ulib/musl/src/stdio/__towrite.c b/third_party/ulib/musl/src/stdio/__towrite.c new file mode 100644 index 000000000..d96dc2378 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__towrite.c @@ -0,0 +1,23 @@ +#include "stdio_impl.h" + +int __towrite(FILE* f) { + f->mode |= f->mode - 1; + if (f->flags & (F_NOWR)) { + f->flags |= F_ERR; + return EOF; + } + /* Clear read buffer (easier than summoning nasal demons) */ + f->rpos = f->rend = 0; + + /* Activate write through the buffer. */ + f->wpos = f->wbase = f->buf; + f->wend = f->buf + f->buf_size; + + return 0; +} + +void __stdio_exit_needed(void); + +void __towrite_needs_stdio_exit(void) { + __stdio_exit_needed(); +} diff --git a/third_party/ulib/musl/src/stdio/__uflow.c b/third_party/ulib/musl/src/stdio/__uflow.c new file mode 100644 index 000000000..a467d3853 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/__uflow.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +/* This function assumes it will never be called if there is already + * data buffered for reading. */ + +int __uflow(FILE* f) { + unsigned char c; + if (!__toread(f) && f->read(f, &c, 1) == 1) return c; + return EOF; +} diff --git a/third_party/ulib/musl/src/stdio/asprintf.c b/third_party/ulib/musl/src/stdio/asprintf.c new file mode 100644 index 000000000..48103b7e2 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/asprintf.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include +#include + +int asprintf(char** s, const char* fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vasprintf(s, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/clearerr.c b/third_party/ulib/musl/src/stdio/clearerr.c new file mode 100644 index 000000000..04d7a71da --- /dev/null +++ b/third_party/ulib/musl/src/stdio/clearerr.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +void clearerr(FILE* f) { + FLOCK(f); + f->flags &= ~(F_EOF | F_ERR); + FUNLOCK(f); +} + +weak_alias(clearerr, clearerr_unlocked); diff --git a/third_party/ulib/musl/src/stdio/dprintf.c b/third_party/ulib/musl/src/stdio/dprintf.c new file mode 100644 index 000000000..8ffdc4d9f --- /dev/null +++ b/third_party/ulib/musl/src/stdio/dprintf.c @@ -0,0 +1,11 @@ +#include +#include + +int dprintf(int fd, const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vdprintf(fd, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/ext.c b/third_party/ulib/musl/src/stdio/ext.c new file mode 100644 index 000000000..fb0e35c98 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ext.c @@ -0,0 +1,47 @@ +#define _GNU_SOURCE +#include "stdio_impl.h" +#include + +void _flushlbf(void) { + fflush(0); +} + +int __fsetlocking(FILE* f, int type) { + return 0; +} + +int __fwriting(FILE* f) { + return (f->flags & F_NORD) || f->wend; +} + +int __freading(FILE* f) { + return (f->flags & F_NOWR) || f->rend; +} + +int __freadable(FILE* f) { + return !(f->flags & F_NORD); +} + +int __fwritable(FILE* f) { + return !(f->flags & F_NOWR); +} + +int __flbf(FILE* f) { + return f->lbf >= 0; +} + +size_t __fbufsize(FILE* f) { + return f->buf_size; +} + +size_t __fpending(FILE* f) { + return f->wend ? f->wpos - f->wbase : 0; +} + +int __fpurge(FILE* f) { + f->wpos = f->wbase = f->wend = 0; + f->rpos = f->rend = 0; + return 0; +} + +weak_alias(__fpurge, fpurge); diff --git a/third_party/ulib/musl/src/stdio/ext2.c b/third_party/ulib/musl/src/stdio/ext2.c new file mode 100644 index 000000000..6af68188f --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ext2.c @@ -0,0 +1,20 @@ +#include "stdio_impl.h" + +size_t __freadahead(FILE* f) { + return f->rend - f->rpos; +} + +const char* __freadptr(FILE* f, size_t* sizep) { + size_t size = f->rend - f->rpos; + if (!size) return 0; + *sizep = size; + return (const char*)f->rpos; +} + +void __freadptrinc(FILE* f, size_t inc) { + f->rpos += inc; +} + +void __fseterr(FILE* f) { + f->flags |= F_ERR; +} diff --git a/third_party/ulib/musl/src/stdio/fclose.c b/third_party/ulib/musl/src/stdio/fclose.c new file mode 100644 index 000000000..3512eb196 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fclose.c @@ -0,0 +1,33 @@ +#include "libc.h" +#include "stdio_impl.h" + +static void dummy(FILE* f) {} +weak_alias(dummy, __unlist_locked_file); + +int fclose(FILE* f) { + int r; + int perm; + + FLOCK(f); + + __unlist_locked_file(f); + + if (!(perm = f->flags & F_PERM)) { + FILE** head = __ofl_lock(); + if (f->prev) f->prev->next = f->next; + if (f->next) f->next->prev = f->prev; + if (*head == f) *head = f->next; + __ofl_unlock(); + } + + r = fflush(f); + r |= f->close(f); + + if (f->getln_buf) free(f->getln_buf); + if (!perm) + free(f); + else + FUNLOCK(f); + + return r; +} diff --git a/third_party/ulib/musl/src/stdio/feof.c b/third_party/ulib/musl/src/stdio/feof.c new file mode 100644 index 000000000..780391a0b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/feof.c @@ -0,0 +1,13 @@ +#include "stdio_impl.h" + +#undef feof + +int feof(FILE* f) { + FLOCK(f); + int ret = !!(f->flags & F_EOF); + FUNLOCK(f); + return ret; +} + +weak_alias(feof, feof_unlocked); +weak_alias(feof, _IO_feof_unlocked); diff --git a/third_party/ulib/musl/src/stdio/ferror.c b/third_party/ulib/musl/src/stdio/ferror.c new file mode 100644 index 000000000..32dccd5e1 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ferror.c @@ -0,0 +1,13 @@ +#include "stdio_impl.h" + +#undef ferror + +int ferror(FILE* f) { + FLOCK(f); + int ret = !!(f->flags & F_ERR); + FUNLOCK(f); + return ret; +} + +weak_alias(ferror, ferror_unlocked); +weak_alias(ferror, _IO_ferror_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fflush.c b/third_party/ulib/musl/src/stdio/fflush.c new file mode 100644 index 000000000..0f4096b35 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fflush.c @@ -0,0 +1,46 @@ +#include "stdio_impl.h" + +static int __fflush_unlocked(FILE* f) { + /* If writing, flush output */ + if (f->wpos > f->wbase) { + f->write(f, 0, 0); + if (!f->wpos) return EOF; + } + + /* If reading, sync position, per POSIX */ + if (f->rpos < f->rend) f->seek(f, f->rpos - f->rend, SEEK_CUR); + + /* Clear read and write modes */ + f->wpos = f->wbase = f->wend = 0; + f->rpos = f->rend = 0; + + return 0; +} + +/* stdout.c will override this if linked */ +static FILE* volatile dummy = 0; +weak_alias(dummy, __stdout_used); + +int fflush(FILE* f) { + int r; + + if (f) { + FLOCK(f); + r = __fflush_unlocked(f); + FUNLOCK(f); + return r; + } + + r = __stdout_used ? fflush(__stdout_used) : 0; + + for (f = *__ofl_lock(); f; f = f->next) { + FLOCK(f); + if (f->wpos > f->wbase) r |= __fflush_unlocked(f); + FUNLOCK(f); + } + __ofl_unlock(); + + return r; +} + +weak_alias(__fflush_unlocked, fflush_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fgetc.c b/third_party/ulib/musl/src/stdio/fgetc.c new file mode 100644 index 000000000..2f62ed109 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fgetc.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +int fgetc(FILE* f) { + int c; + if (f->lock < 0 || !__lockfile(f)) return getc_unlocked(f); + c = getc_unlocked(f); + __unlockfile(f); + return c; +} diff --git a/third_party/ulib/musl/src/stdio/fgetln.c b/third_party/ulib/musl/src/stdio/fgetln.c new file mode 100644 index 000000000..58a74dc00 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fgetln.c @@ -0,0 +1,20 @@ +#define _GNU_SOURCE +#include "stdio_impl.h" +#include + +char* fgetln(FILE* f, size_t* plen) { + char *ret = 0, *z; + ssize_t l; + FLOCK(f); + ungetc(getc_unlocked(f), f); + if ((z = memchr(f->rpos, '\n', f->rend - f->rpos))) { + ret = (char*)f->rpos; + *plen = ++z - ret; + f->rpos = (void*)z; + } else if ((l = getline(&f->getln_buf, (size_t[]){0}, f)) > 0) { + *plen = l; + ret = f->getln_buf; + } + FUNLOCK(f); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/fgetpos.c b/third_party/ulib/musl/src/stdio/fgetpos.c new file mode 100644 index 000000000..3f00919cf --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fgetpos.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int fgetpos(FILE* restrict f, fpos_t* restrict pos) { + off_t off = __ftello(f); + if (off < 0) return -1; + *(off_t*)pos = off; + return 0; +} + +LFS64(fgetpos); diff --git a/third_party/ulib/musl/src/stdio/fgets.c b/third_party/ulib/musl/src/stdio/fgets.c new file mode 100644 index 000000000..8221d091b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fgets.c @@ -0,0 +1,45 @@ +#include "stdio_impl.h" +#include + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +char* fgets(char* restrict s, int n, FILE* restrict f) { + char* p = s; + unsigned char* z; + size_t k; + int c; + + FLOCK(f); + + if (n-- <= 1) { + f->mode |= f->mode - 1; + FUNLOCK(f); + if (n) return 0; + *s = 0; + return s; + } + + while (n) { + z = memchr(f->rpos, '\n', f->rend - f->rpos); + k = z ? z - f->rpos + 1 : f->rend - f->rpos; + k = MIN(k, n); + memcpy(p, f->rpos, k); + f->rpos += k; + p += k; + n -= k; + if (z || !n) break; + if ((c = getc_unlocked(f)) < 0) { + if (p == s || !feof(f)) s = 0; + break; + } + n--; + if ((*p++ = c) == '\n') break; + } + if (s) *p = 0; + + FUNLOCK(f); + + return s; +} + +weak_alias(fgets, fgets_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fgetwc.c b/third_party/ulib/musl/src/stdio/fgetwc.c new file mode 100644 index 000000000..37bcd016e --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fgetwc.c @@ -0,0 +1,59 @@ +#include "locale_impl.h" +#include "stdio_impl.h" +#include +#include + +static wint_t __fgetwc_unlocked_internal(FILE* f) { + mbstate_t st = {0}; + wchar_t wc; + int c; + unsigned char b; + size_t l; + + /* Convert character from buffer if possible */ + if (f->rpos < f->rend) { + l = mbrtowc(&wc, (void*)f->rpos, f->rend - f->rpos, &st); + if (l + 2 >= 2) { + f->rpos += l + !l; /* l==0 means 1 byte, null */ + return wc; + } + if (l == -1) { + f->rpos++; + return WEOF; + } + } else + l = -2; + + /* Convert character byte-by-byte */ + while (l == -2) { + b = c = getc_unlocked(f); + if (c < 0) { + if (!mbsinit(&st)) errno = EILSEQ; + return WEOF; + } + l = mbrtowc(&wc, (void*)&b, 1, &st); + if (l == -1) return WEOF; + } + + return wc; +} + +wint_t __fgetwc_unlocked(FILE* f) { + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; + wchar_t wc = __fgetwc_unlocked_internal(f); + *ploc = loc; + return wc; +} + +wint_t fgetwc(FILE* f) { + wint_t c; + FLOCK(f); + c = __fgetwc_unlocked(f); + FUNLOCK(f); + return c; +} + +weak_alias(__fgetwc_unlocked, fgetwc_unlocked); +weak_alias(__fgetwc_unlocked, getwc_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fgetws.c b/third_party/ulib/musl/src/stdio/fgetws.c new file mode 100644 index 000000000..efc72ba54 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fgetws.c @@ -0,0 +1,27 @@ +#include "stdio_impl.h" +#include + +wint_t __fgetwc_unlocked(FILE*); + +wchar_t* fgetws(wchar_t* restrict s, int n, FILE* restrict f) { + wchar_t* p = s; + + if (!n--) return s; + + FLOCK(f); + + for (; n; n--) { + wint_t c = __fgetwc_unlocked(f); + if (c == WEOF) break; + *p++ = c; + if (c == '\n') break; + } + *p = 0; + if (ferror(f)) p = s; + + FUNLOCK(f); + + return (p == s) ? NULL : s; +} + +weak_alias(fgetws, fgetws_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fileno.c b/third_party/ulib/musl/src/stdio/fileno.c new file mode 100644 index 000000000..e414301b0 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fileno.c @@ -0,0 +1,12 @@ +#include "stdio_impl.h" + +int fileno(FILE* f) { + /* f->fd never changes, but the lock must be obtained and released + * anyway since this function cannot return while another thread + * holds the lock. */ + FLOCK(f); + FUNLOCK(f); + return f->fd; +} + +weak_alias(fileno, fileno_unlocked); diff --git a/third_party/ulib/musl/src/stdio/flockfile.c b/third_party/ulib/musl/src/stdio/flockfile.c new file mode 100644 index 000000000..913d8a656 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/flockfile.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" +#include "stdio_impl.h" + +void flockfile(FILE* f) { + while (ftrylockfile(f)) { + int owner = f->lock; + if (owner) __wait(&f->lock, &f->waiters, owner); + } +} diff --git a/third_party/ulib/musl/src/stdio/fmemopen.c b/third_party/ulib/musl/src/stdio/fmemopen.c new file mode 100644 index 000000000..d4c11c362 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fmemopen.c @@ -0,0 +1,113 @@ +#include "stdio_impl.h" +#include +#include +#include + +struct cookie { + size_t pos, len, size; + unsigned char* buf; + int mode; +}; + +static off_t mseek(FILE* f, off_t off, int whence) { + ssize_t base; + struct cookie* c = f->cookie; + if (whence > 2U) { + fail: + errno = EINVAL; + return -1; + } + base = (size_t[3]){0, c->pos, c->len}[whence]; + if (off < -base || off > (ssize_t)c->size - base) goto fail; + return c->pos = base + off; +} + +static size_t mread(FILE* f, unsigned char* buf, size_t len) { + struct cookie* c = f->cookie; + size_t rem = c->len - c->pos; + if (c->pos > c->len) rem = 0; + if (len > rem) { + len = rem; + f->flags |= F_EOF; + } + memcpy(buf, c->buf + c->pos, len); + c->pos += len; + rem -= len; + if (rem > f->buf_size) rem = f->buf_size; + f->rpos = f->buf; + f->rend = f->buf + rem; + memcpy(f->rpos, c->buf + c->pos, rem); + c->pos += rem; + return len; +} + +static size_t mwrite(FILE* f, const unsigned char* buf, size_t len) { + struct cookie* c = f->cookie; + size_t rem; + size_t len2 = f->wpos - f->wbase; + if (len2) { + f->wpos = f->wbase; + if (mwrite(f, f->wpos, len2) < len2) return 0; + } + if (c->mode == 'a') c->pos = c->len; + rem = c->size - c->pos; + if (len > rem) len = rem; + memcpy(c->buf + c->pos, buf, len); + c->pos += len; + if (c->pos > c->len) { + c->len = c->pos; + if (c->len < c->size) + c->buf[c->len] = 0; + else if ((f->flags & F_NORD) && c->size) + c->buf[c->size - 1] = 0; + } + return len; +} + +static int mclose(FILE* m) { + return 0; +} + +FILE* fmemopen(void* restrict buf, size_t size, const char* restrict mode) { + FILE* f; + struct cookie* c; + int plus = !!strchr(mode, '+'); + + if (!size || !strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + if (!buf && size > SIZE_MAX - sizeof(FILE) - BUFSIZ - UNGET) { + errno = ENOMEM; + return 0; + } + + f = calloc(sizeof *f + sizeof *c + UNGET + BUFSIZ + (buf ? 0 : size), 1); + if (!f) return 0; + f->cookie = c = (void*)(f + 1); + f->fd = -1; + f->lbf = EOF; + f->buf = (unsigned char*)(c + 1) + UNGET; + f->buf_size = BUFSIZ; + if (!buf) buf = f->buf + BUFSIZ; + + c->buf = buf; + c->size = size; + c->mode = *mode; + + if (!plus) f->flags = (*mode == 'r') ? F_NOWR : F_NORD; + if (*mode == 'r') + c->len = size; + else if (*mode == 'a') + c->len = c->pos = strnlen(buf, size); + + f->read = mread; + f->write = mwrite; + f->seek = mseek; + f->close = mclose; + + if (!libc.threaded) f->lock = -1; + + return __ofl_add(f); +} diff --git a/third_party/ulib/musl/src/stdio/fopen.c b/third_party/ulib/musl/src/stdio/fopen.c new file mode 100644 index 000000000..10b3bd4e4 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fopen.c @@ -0,0 +1,33 @@ +#include "stdio_impl.h" +#include +#include +#include +#include + +FILE* fopen(const char* restrict filename, const char* restrict mode) { + FILE* f; + int fd; + int flags; + + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + /* Compute the flags to pass to open() */ + flags = __fmodeflags(mode); + + fd = open(filename, flags, 0666); + if (fd < 0) return 0; + // TODO(kulakowski) Implement O_CLOEXEC semantics. + if (flags & O_CLOEXEC) __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); + + f = __fdopen(fd, mode); + if (f) return f; + + close(fd); + return 0; +} + +LFS64(fopen); diff --git a/third_party/ulib/musl/src/stdio/fprintf.c b/third_party/ulib/musl/src/stdio/fprintf.c new file mode 100644 index 000000000..75ed3d1da --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fprintf.c @@ -0,0 +1,11 @@ +#include +#include + +int fprintf(FILE* restrict f, const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/fputc.c b/third_party/ulib/musl/src/stdio/fputc.c new file mode 100644 index 000000000..6279ea639 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fputc.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int fputc(int c, FILE* f) { + if (f->lock < 0 || !__lockfile(f)) return putc_unlocked(c, f); + c = putc_unlocked(c, f); + __unlockfile(f); + return c; +} diff --git a/third_party/ulib/musl/src/stdio/fputs.c b/third_party/ulib/musl/src/stdio/fputs.c new file mode 100644 index 000000000..73a0935c3 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fputs.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" +#include + +int fputs(const char* restrict s, FILE* restrict f) { + size_t l = strlen(s); + return (fwrite(s, 1, l, f) == l) - 1; +} + +weak_alias(fputs, fputs_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fputwc.c b/third_party/ulib/musl/src/stdio/fputwc.c new file mode 100644 index 000000000..33c05bbae --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fputwc.c @@ -0,0 +1,40 @@ +#include "locale_impl.h" +#include "stdio_impl.h" +#include +#include +#include + +wint_t __fputwc_unlocked(wchar_t c, FILE* f) { + char mbc[MB_LEN_MAX]; + int l; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; + + if (isascii(c)) { + c = putc_unlocked(c, f); + } else if (f->wpos + MB_LEN_MAX < f->wend) { + l = wctomb((void*)f->wpos, c); + if (l < 0) + c = WEOF; + else + f->wpos += l; + } else { + l = wctomb(mbc, c); + if (l < 0 || __fwritex((void*)mbc, l, f) < l) c = WEOF; + } + if (c == WEOF) f->flags |= F_ERR; + *ploc = loc; + return c; +} + +wint_t fputwc(wchar_t c, FILE* f) { + FLOCK(f); + c = __fputwc_unlocked(c, f); + FUNLOCK(f); + return c; +} + +weak_alias(__fputwc_unlocked, fputwc_unlocked); +weak_alias(__fputwc_unlocked, putwc_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fputws.c b/third_party/ulib/musl/src/stdio/fputws.c new file mode 100644 index 000000000..1c1b7d9b5 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fputws.c @@ -0,0 +1,28 @@ +#include "locale_impl.h" +#include "stdio_impl.h" +#include + +int fputws(const wchar_t* restrict ws, FILE* restrict f) { + unsigned char buf[BUFSIZ]; + size_t l = 0; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + FLOCK(f); + + fwide(f, 1); + *ploc = f->locale; + + while (ws && (l = wcsrtombs((void*)buf, (void*)&ws, sizeof buf, 0)) + 1 > 1) + if (__fwritex(buf, l, f) < l) { + FUNLOCK(f); + *ploc = loc; + return -1; + } + + FUNLOCK(f); + + *ploc = loc; + return l; /* 0 or -1 */ +} + +weak_alias(fputws, fputws_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fread.c b/third_party/ulib/musl/src/stdio/fread.c new file mode 100644 index 000000000..e8a8b5e7b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fread.c @@ -0,0 +1,37 @@ +#include "stdio_impl.h" +#include + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +size_t fread(void* restrict destv, size_t size, size_t nmemb, FILE* restrict f) { + unsigned char* dest = destv; + size_t len = size * nmemb, l = len, k; + if (!size) nmemb = 0; + + FLOCK(f); + + f->mode |= f->mode - 1; + + if (f->rend - f->rpos > 0) { + /* First exhaust the buffer. */ + k = MIN(f->rend - f->rpos, l); + memcpy(dest, f->rpos, k); + f->rpos += k; + dest += k; + l -= k; + } + + /* Read the remainder directly */ + for (; l; l -= k, dest += k) { + k = __toread(f) ? 0 : f->read(f, dest, l); + if (k + 1 <= 1) { + FUNLOCK(f); + return (len - l) / size; + } + } + + FUNLOCK(f); + return nmemb; +} + +weak_alias(fread, fread_unlocked); diff --git a/third_party/ulib/musl/src/stdio/freopen.c b/third_party/ulib/musl/src/stdio/freopen.c new file mode 100644 index 000000000..68b82af26 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/freopen.c @@ -0,0 +1,53 @@ +#include "stdio_impl.h" +#include + +/* The basic idea of this implementation is to open a new FILE, + * hack the necessary parts of the new FILE into the old one, then + * close the new FILE. */ + +/* Locking IS necessary because another thread may provably hold the + * lock, via flockfile or otherwise, when freopen is called, and in that + * case, freopen cannot act until the lock is released. */ + +int __dup3(int, int, int); + +FILE* freopen(const char* restrict filename, const char* restrict mode, FILE* restrict f) { + int fl = __fmodeflags(mode); + FILE* f2; + + FLOCK(f); + + fflush(f); + + if (!filename) { + if (fl & O_CLOEXEC) __syscall(SYS_fcntl, f->fd, F_SETFD, FD_CLOEXEC); + fl &= ~(O_CREAT | O_EXCL | O_CLOEXEC); + if (syscall(SYS_fcntl, f->fd, F_SETFL, fl) < 0) goto fail; + } else { + f2 = fopen(filename, mode); + if (!f2) goto fail; + if (f2->fd == f->fd) + f2->fd = -1; /* avoid closing in fclose */ + else if (__dup3(f2->fd, f->fd, fl & O_CLOEXEC) < 0) + goto fail2; + + f->flags = (f->flags & F_PERM) | f2->flags; + f->read = f2->read; + f->write = f2->write; + f->seek = f2->seek; + f->close = f2->close; + + fclose(f2); + } + + FUNLOCK(f); + return f; + +fail2: + fclose(f2); +fail: + fclose(f); + return NULL; +} + +LFS64(freopen); diff --git a/third_party/ulib/musl/src/stdio/fscanf.c b/third_party/ulib/musl/src/stdio/fscanf.c new file mode 100644 index 000000000..dd8ebaeba --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fscanf.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include +#include + +int fscanf(FILE* restrict f, const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfscanf(f, fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(fscanf, __isoc99_fscanf); diff --git a/third_party/ulib/musl/src/stdio/fseek.c b/third_party/ulib/musl/src/stdio/fseek.c new file mode 100644 index 000000000..153508e76 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fseek.c @@ -0,0 +1,40 @@ +#include "stdio_impl.h" + +int __fseeko_unlocked(FILE* f, off_t off, int whence) { + /* Adjust relative offset for unread data in buffer, if any. */ + if (whence == SEEK_CUR) off -= f->rend - f->rpos; + + /* Flush write buffer, and report error on failure. */ + if (f->wpos > f->wbase) { + f->write(f, 0, 0); + if (!f->wpos) return -1; + } + + /* Leave writing mode */ + f->wpos = f->wbase = f->wend = 0; + + /* Perform the underlying seek. */ + if (f->seek(f, off, whence) < 0) return -1; + + /* If seek succeeded, file is seekable and we discard read buffer. */ + f->rpos = f->rend = 0; + f->flags &= ~F_EOF; + + return 0; +} + +int __fseeko(FILE* f, off_t off, int whence) { + int result; + FLOCK(f); + result = __fseeko_unlocked(f, off, whence); + FUNLOCK(f); + return result; +} + +int fseek(FILE* f, long off, int whence) { + return __fseeko(f, off, whence); +} + +weak_alias(__fseeko, fseeko); + +LFS64(fseeko); diff --git a/third_party/ulib/musl/src/stdio/fsetpos.c b/third_party/ulib/musl/src/stdio/fsetpos.c new file mode 100644 index 000000000..649ef7d5e --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fsetpos.c @@ -0,0 +1,7 @@ +#include "stdio_impl.h" + +int fsetpos(FILE* f, const fpos_t* pos) { + return __fseeko(f, *(const off_t*)pos, SEEK_SET); +} + +LFS64(fsetpos); diff --git a/third_party/ulib/musl/src/stdio/ftell.c b/third_party/ulib/musl/src/stdio/ftell.c new file mode 100644 index 000000000..c084bdc9a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ftell.c @@ -0,0 +1,32 @@ +#include "stdio_impl.h" +#include +#include + +off_t __ftello_unlocked(FILE* f) { + off_t pos = f->seek(f, 0, (f->flags & F_APP) && f->wpos > f->wbase ? SEEK_END : SEEK_CUR); + if (pos < 0) return pos; + + /* Adjust for data in buffer. */ + return pos - (f->rend - f->rpos) + (f->wpos - f->wbase); +} + +off_t __ftello(FILE* f) { + off_t pos; + FLOCK(f); + pos = __ftello_unlocked(f); + FUNLOCK(f); + return pos; +} + +long ftell(FILE* f) { + off_t pos = __ftello(f); + if (pos > LONG_MAX) { + errno = EOVERFLOW; + return -1; + } + return pos; +} + +weak_alias(__ftello, ftello); + +LFS64(ftello); diff --git a/third_party/ulib/musl/src/stdio/ftrylockfile.c b/third_party/ulib/musl/src/stdio/ftrylockfile.c new file mode 100644 index 000000000..eddc2d560 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ftrylockfile.c @@ -0,0 +1,37 @@ +#include "pthread_impl.h" +#include "stdio_impl.h" +#include + +void __do_orphaned_stdio_locks(void) { + FILE* f; + for (f = __pthread_self()->stdio_locks; f; f = f->next_locked) + a_store(&f->lock, 0x40000000); +} + +void __unlist_locked_file(FILE* f) { + if (f->lockcount) { + if (f->next_locked) f->next_locked->prev_locked = f->prev_locked; + if (f->prev_locked) + f->prev_locked->next_locked = f->next_locked; + else + __pthread_self()->stdio_locks = f->next_locked; + } +} + +int ftrylockfile(FILE* f) { + pthread_t self = __pthread_self(); + int tid = self->tid; + if (f->lock == tid) { + if (f->lockcount == LONG_MAX) return -1; + f->lockcount++; + return 0; + } + if (f->lock < 0) f->lock = 0; + if (f->lock || a_cas(&f->lock, 0, tid)) return -1; + f->lockcount = 1; + f->prev_locked = 0; + f->next_locked = self->stdio_locks; + if (f->next_locked) f->next_locked->prev_locked = f; + self->stdio_locks = f; + return 0; +} diff --git a/third_party/ulib/musl/src/stdio/funlockfile.c b/third_party/ulib/musl/src/stdio/funlockfile.c new file mode 100644 index 000000000..ce6f07103 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/funlockfile.c @@ -0,0 +1,14 @@ +#include "pthread_impl.h" +#include "stdio_impl.h" + +void __unlist_locked_file(FILE*); + +void funlockfile(FILE* f) { + if (f->lockcount == 1) { + __unlist_locked_file(f); + f->lockcount = 0; + __unlockfile(f); + } else { + f->lockcount--; + } +} diff --git a/third_party/ulib/musl/src/stdio/fwide.c b/third_party/ulib/musl/src/stdio/fwide.c new file mode 100644 index 000000000..80d4ae36b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fwide.c @@ -0,0 +1,13 @@ +#include "locale_impl.h" +#include "stdio_impl.h" + +int fwide(FILE* f, int mode) { + FLOCK(f); + if (mode) { + if (!f->locale) f->locale = MB_CUR_MAX == 1 ? C_LOCALE : UTF8_LOCALE; + if (!f->mode) f->mode = mode > 0 ? 1 : -1; + } + mode = f->mode; + FUNLOCK(f); + return mode; +} diff --git a/third_party/ulib/musl/src/stdio/fwprintf.c b/third_party/ulib/musl/src/stdio/fwprintf.c new file mode 100644 index 000000000..e90cf948a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fwprintf.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int fwprintf(FILE* restrict f, const wchar_t* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfwprintf(f, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/fwrite.c b/third_party/ulib/musl/src/stdio/fwrite.c new file mode 100644 index 000000000..bf09b2c6d --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fwrite.c @@ -0,0 +1,37 @@ +#include "stdio_impl.h" +#include + +size_t __fwritex(const unsigned char* restrict s, size_t l, FILE* restrict f) { + size_t i = 0; + + if (!f->wend && __towrite(f)) return 0; + + if (l > f->wend - f->wpos) return f->write(f, s, l); + + if (f->lbf >= 0) { + /* Match /^(.*\n|)/ */ + for (i = l; i && s[i - 1] != '\n'; i--) + ; + if (i) { + size_t n = f->write(f, s, i); + if (n < i) return n; + s += i; + l -= i; + } + } + + memcpy(f->wpos, s, l); + f->wpos += l; + return l + i; +} + +size_t fwrite(const void* restrict src, size_t size, size_t nmemb, FILE* restrict f) { + size_t k, l = size * nmemb; + if (!size) nmemb = 0; + FLOCK(f); + k = __fwritex(src, l, f); + FUNLOCK(f); + return k == l ? nmemb : k / size; +} + +weak_alias(fwrite, fwrite_unlocked); diff --git a/third_party/ulib/musl/src/stdio/fwscanf.c b/third_party/ulib/musl/src/stdio/fwscanf.c new file mode 100644 index 000000000..43bd65833 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/fwscanf.c @@ -0,0 +1,15 @@ +#include "libc.h" +#include +#include +#include + +int fwscanf(FILE* restrict f, const wchar_t* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfwscanf(f, fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(fwscanf, __isoc99_fwscanf); diff --git a/third_party/ulib/musl/src/stdio/getc.c b/third_party/ulib/musl/src/stdio/getc.c new file mode 100644 index 000000000..6aa2a295d --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getc.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +int getc(FILE* f) { + int c; + if (f->lock < 0 || !__lockfile(f)) return getc_unlocked(f); + c = getc_unlocked(f); + __unlockfile(f); + return c; +} + +weak_alias(getc, _IO_getc); diff --git a/third_party/ulib/musl/src/stdio/getc_unlocked.c b/third_party/ulib/musl/src/stdio/getc_unlocked.c new file mode 100644 index 000000000..62f1f36bc --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getc_unlocked.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int(getc_unlocked)(FILE* f) { + return getc_unlocked(f); +} + +weak_alias(getc_unlocked, fgetc_unlocked); +weak_alias(getc_unlocked, _IO_getc_unlocked); diff --git a/third_party/ulib/musl/src/stdio/getchar.c b/third_party/ulib/musl/src/stdio/getchar.c new file mode 100644 index 000000000..01ffb2fb7 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getchar.c @@ -0,0 +1,5 @@ +#include + +int getchar(void) { + return fgetc(stdin); +} diff --git a/third_party/ulib/musl/src/stdio/getchar_unlocked.c b/third_party/ulib/musl/src/stdio/getchar_unlocked.c new file mode 100644 index 000000000..53df00947 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getchar_unlocked.c @@ -0,0 +1,5 @@ +#include "stdio_impl.h" + +int getchar_unlocked(void) { + return getc_unlocked(stdin); +} diff --git a/third_party/ulib/musl/src/stdio/getdelim.c b/third_party/ulib/musl/src/stdio/getdelim.c new file mode 100644 index 000000000..f72893677 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getdelim.c @@ -0,0 +1,67 @@ +#include "stdio_impl.h" +#include +#include +#include + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +ssize_t getdelim(char** restrict s, size_t* restrict n, int delim, FILE* restrict f) { + char* tmp; + unsigned char* z; + size_t k; + size_t i = 0; + int c; + + FLOCK(f); + + if (!n || !s) { + f->flags |= F_ERR; + FUNLOCK(f); + errno = EINVAL; + return -1; + } + + if (!*s) *n = 0; + + for (;;) { + z = memchr(f->rpos, delim, f->rend - f->rpos); + k = z ? z - f->rpos + 1 : f->rend - f->rpos; + if (i + k + 1 >= *n) { + if (k >= SIZE_MAX / 2 - i) goto oom; + size_t m = i + k + 2; + if (!z && m < SIZE_MAX / 4) m += m / 2; + tmp = realloc(*s, m); + if (!tmp) { + m = i + k + 2; + tmp = realloc(*s, m); + if (!tmp) goto oom; + } + *s = tmp; + *n = m; + } + memcpy(*s + i, f->rpos, k); + f->rpos += k; + i += k; + if (z) break; + if ((c = getc_unlocked(f)) == EOF) { + if (!i || !feof(f)) { + FUNLOCK(f); + return -1; + } + break; + } + if (((*s)[i++] = c) == delim) break; + } + (*s)[i] = 0; + + FUNLOCK(f); + + return i; +oom: + f->flags |= F_ERR; + FUNLOCK(f); + errno = ENOMEM; + return -1; +} + +weak_alias(getdelim, __getdelim); diff --git a/third_party/ulib/musl/src/stdio/getline.c b/third_party/ulib/musl/src/stdio/getline.c new file mode 100644 index 000000000..d44cb8da0 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getline.c @@ -0,0 +1,5 @@ +#include + +ssize_t getline(char** restrict s, size_t* restrict n, FILE* restrict f) { + return getdelim(s, n, '\n', f); +} diff --git a/third_party/ulib/musl/src/stdio/gets.c b/third_party/ulib/musl/src/stdio/gets.c new file mode 100644 index 000000000..373a3fe3b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/gets.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" +#include +#include + +char* gets(char* s) { + char* ret = fgets(s, INT_MAX, stdin); + if (ret && s[strlen(s) - 1] == '\n') s[strlen(s) - 1] = 0; + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/getw.c b/third_party/ulib/musl/src/stdio/getw.c new file mode 100644 index 000000000..f40f882ac --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getw.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int getw(FILE* f) { + int x; + return fread(&x, sizeof x, 1, f) ? x : EOF; +} diff --git a/third_party/ulib/musl/src/stdio/getwc.c b/third_party/ulib/musl/src/stdio/getwc.c new file mode 100644 index 000000000..9050ad231 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getwc.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" +#include + +wint_t getwc(FILE* f) { + return fgetwc(f); +} diff --git a/third_party/ulib/musl/src/stdio/getwchar.c b/third_party/ulib/musl/src/stdio/getwchar.c new file mode 100644 index 000000000..308499567 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/getwchar.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" +#include + +wint_t getwchar(void) { + return fgetwc(stdin); +} + +weak_alias(getwchar, getwchar_unlocked); diff --git a/third_party/ulib/musl/src/stdio/ofl.c b/third_party/ulib/musl/src/stdio/ofl.c new file mode 100644 index 000000000..7c4897284 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ofl.c @@ -0,0 +1,16 @@ +#include "libc.h" +#include "stdio_impl.h" + +#include + +static FILE* ofl_head; +static mxr_mutex_t ofl_lock; + +FILE** __ofl_lock(void) { + mxr_mutex_lock(&ofl_lock); + return &ofl_head; +} + +void __ofl_unlock(void) { + mxr_mutex_unlock(&ofl_lock); +} diff --git a/third_party/ulib/musl/src/stdio/ofl_add.c b/third_party/ulib/musl/src/stdio/ofl_add.c new file mode 100644 index 000000000..a83bde659 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ofl_add.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +FILE* __ofl_add(FILE* f) { + FILE** head = __ofl_lock(); + f->next = *head; + if (*head) (*head)->prev = f; + *head = f; + __ofl_unlock(); + return f; +} diff --git a/third_party/ulib/musl/src/stdio/open_memstream.c b/third_party/ulib/musl/src/stdio/open_memstream.c new file mode 100644 index 000000000..32f372349 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/open_memstream.c @@ -0,0 +1,86 @@ +#include "stdio_impl.h" +#include +#include +#include + +struct cookie { + char** bufp; + size_t* sizep; + size_t pos; + char* buf; + size_t len; + size_t space; +}; + +static off_t ms_seek(FILE* f, off_t off, int whence) { + ssize_t base; + struct cookie* c = f->cookie; + if (whence > 2U) { + fail: + errno = EINVAL; + return -1; + } + base = (size_t[3]){0, c->pos, c->len}[whence]; + if (off < -base || off > SSIZE_MAX - base) goto fail; + return c->pos = base + off; +} + +static size_t ms_write(FILE* f, const unsigned char* buf, size_t len) { + struct cookie* c = f->cookie; + size_t len2 = f->wpos - f->wbase; + char* newbuf; + if (len2) { + f->wpos = f->wbase; + if (ms_write(f, f->wbase, len2) < len2) return 0; + } + if (len + c->pos >= c->space) { + len2 = 2 * c->space + 1 | c->pos + len + 1; + newbuf = realloc(c->buf, len2); + if (!newbuf) return 0; + *c->bufp = c->buf = newbuf; + memset(c->buf + c->space, 0, len2 - c->space); + c->space = len2; + } + memcpy(c->buf + c->pos, buf, len); + c->pos += len; + if (c->pos >= c->len) c->len = c->pos; + *c->sizep = c->pos; + return len; +} + +static int ms_close(FILE* f) { + return 0; +} + +FILE* open_memstream(char** bufp, size_t* sizep) { + FILE* f; + struct cookie* c; + char* buf; + + if (!(f = malloc(sizeof *f + sizeof *c + BUFSIZ))) return 0; + if (!(buf = malloc(sizeof *buf))) { + free(f); + return 0; + } + memset(f, 0, sizeof *f + sizeof *c); + f->cookie = c = (void*)(f + 1); + + c->bufp = bufp; + c->sizep = sizep; + c->pos = c->len = c->space = *sizep = 0; + c->buf = *bufp = buf; + *buf = 0; + + f->flags = F_NORD; + f->fd = -1; + f->buf = (void*)(c + 1); + f->buf_size = BUFSIZ; + f->lbf = EOF; + f->write = ms_write; + f->seek = ms_seek; + f->close = ms_close; + + if (!libc.threaded) f->lock = -1; + + return __ofl_add(f); +} diff --git a/third_party/ulib/musl/src/stdio/open_wmemstream.c b/third_party/ulib/musl/src/stdio/open_wmemstream.c new file mode 100644 index 000000000..a3a80f3a0 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/open_wmemstream.c @@ -0,0 +1,88 @@ +#include "stdio_impl.h" +#include +#include +#include +#include + +struct cookie { + wchar_t** bufp; + size_t* sizep; + size_t pos; + wchar_t* buf; + size_t len; + size_t space; + mbstate_t mbs; +}; + +static off_t wms_seek(FILE* f, off_t off, int whence) { + ssize_t base; + struct cookie* c = f->cookie; + if (whence > 2U) { + fail: + errno = EINVAL; + return -1; + } + base = (size_t[3]){0, c->pos, c->len}[whence]; + if (off < -base || off > SSIZE_MAX / 4 - base) goto fail; + memset(&c->mbs, 0, sizeof c->mbs); + return c->pos = base + off; +} + +static size_t wms_write(FILE* f, const unsigned char* buf, size_t len) { + struct cookie* c = f->cookie; + size_t len2; + wchar_t* newbuf; + if (len + c->pos >= c->space) { + len2 = 2 * c->space + 1 | c->pos + len + 1; + if (len2 > SSIZE_MAX / 4) return 0; + newbuf = realloc(c->buf, len2 * 4); + if (!newbuf) return 0; + *c->bufp = c->buf = newbuf; + memset(c->buf + c->space, 0, 4 * (len2 - c->space)); + c->space = len2; + } + + len2 = mbsnrtowcs(c->buf + c->pos, (void*)&buf, len, c->space - c->pos, &c->mbs); + if (len2 == -1) return 0; + c->pos += len2; + if (c->pos >= c->len) c->len = c->pos; + *c->sizep = c->pos; + return len; +} + +static int wms_close(FILE* f) { + return 0; +} + +FILE* open_wmemstream(wchar_t** bufp, size_t* sizep) { + FILE* f; + struct cookie* c; + wchar_t* buf; + + if (!(f = malloc(sizeof *f + sizeof *c))) return 0; + if (!(buf = malloc(sizeof *buf))) { + free(f); + return 0; + } + memset(f, 0, sizeof *f + sizeof *c); + f->cookie = c = (void*)(f + 1); + + c->bufp = bufp; + c->sizep = sizep; + c->pos = c->len = c->space = *sizep = 0; + c->buf = *bufp = buf; + *buf = 0; + + f->flags = F_NORD; + f->fd = -1; + f->buf = (void*)(c + 1); + f->buf_size = 0; + f->lbf = EOF; + f->write = wms_write; + f->seek = wms_seek; + f->close = wms_close; + + if (!libc.threaded) f->lock = -1; + + return __ofl_add(f); +} diff --git a/third_party/ulib/musl/src/stdio/pclose.c b/third_party/ulib/musl/src/stdio/pclose.c new file mode 100644 index 000000000..2deb5218a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/pclose.c @@ -0,0 +1,13 @@ +#include "stdio_impl.h" +#include +#include + +int pclose(FILE* f) { + int status, r; + pid_t pid = f->pipe_pid; + fclose(f); + while ((r = __syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR) + ; + if (r < 0) return __syscall_ret(r); + return status; +} diff --git a/third_party/ulib/musl/src/stdio/perror.c b/third_party/ulib/musl/src/stdio/perror.c new file mode 100644 index 000000000..bf9ff2845 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/perror.c @@ -0,0 +1,21 @@ +#include "stdio_impl.h" +#include +#include +#include + +void perror(const char* msg) { + FILE* f = stderr; + char* errstr = strerror(errno); + + FLOCK(f); + + if (msg && *msg) { + fwrite(msg, strlen(msg), 1, f); + fputc(':', f); + fputc(' ', f); + } + fwrite(errstr, strlen(errstr), 1, f); + fputc('\n', f); + + FUNLOCK(f); +} diff --git a/third_party/ulib/musl/src/stdio/popen.c b/third_party/ulib/musl/src/stdio/popen.c new file mode 100644 index 000000000..23a9f3ed2 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/popen.c @@ -0,0 +1,71 @@ +#include "stdio_impl.h" +#include "syscall.h" +#include +#include +#include +#include +#include + +extern char** __environ; + +FILE* popen(const char* cmd, const char* mode) { + int p[2], op, e; + pid_t pid; + FILE* f; + posix_spawn_file_actions_t fa; + + if (*mode == 'r') { + op = 0; + } else if (*mode == 'w') { + op = 1; + } else { + errno = EINVAL; + return 0; + } + + if (pipe2(p, O_CLOEXEC)) return NULL; + f = fdopen(p[op], mode); + if (!f) { + __syscall(SYS_close, p[0]); + __syscall(SYS_close, p[1]); + return NULL; + } + FLOCK(f); + + /* If the child's end of the pipe happens to already be on the final + * fd number to which it will be assigned (either 0 or 1), it must + * be moved to a different fd. Otherwise, there is no safe way to + * remove the close-on-exec flag in the child without also creating + * a file descriptor leak race condition in the parent. */ + if (p[1 - op] == 1 - op) { + int tmp = fcntl(1 - op, F_DUPFD_CLOEXEC, 0); + if (tmp < 0) { + e = errno; + goto fail; + } + __syscall(SYS_close, p[1 - op]); + p[1 - op] = tmp; + } + + e = ENOMEM; + if (!posix_spawn_file_actions_init(&fa)) { + if (!posix_spawn_file_actions_adddup2(&fa, p[1 - op], 1 - op)) { + if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0, (char* []){"sh", "-c", (char*)cmd, 0}, + __environ))) { + posix_spawn_file_actions_destroy(&fa); + f->pipe_pid = pid; + if (!strchr(mode, 'e')) fcntl(p[op], F_SETFD, 0); + __syscall(SYS_close, p[1 - op]); + FUNLOCK(f); + return f; + } + } + posix_spawn_file_actions_destroy(&fa); + } +fail: + fclose(f); + __syscall(SYS_close, p[1 - op]); + + errno = e; + return 0; +} diff --git a/third_party/ulib/musl/src/stdio/printf.c b/third_party/ulib/musl/src/stdio/printf.c new file mode 100644 index 000000000..2784b962e --- /dev/null +++ b/third_party/ulib/musl/src/stdio/printf.c @@ -0,0 +1,11 @@ +#include +#include + +int printf(const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfprintf(stdout, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/putc.c b/third_party/ulib/musl/src/stdio/putc.c new file mode 100644 index 000000000..491e974ca --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putc.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int putc(int c, FILE* f) { + if (f->lock < 0 || !__lockfile(f)) return putc_unlocked(c, f); + c = putc_unlocked(c, f); + __unlockfile(f); + return c; +} + +weak_alias(putc, _IO_putc); diff --git a/third_party/ulib/musl/src/stdio/putc_unlocked.c b/third_party/ulib/musl/src/stdio/putc_unlocked.c new file mode 100644 index 000000000..5d7f2e68d --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putc_unlocked.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int(putc_unlocked)(int c, FILE* f) { + return putc_unlocked(c, f); +} + +weak_alias(putc_unlocked, fputc_unlocked); +weak_alias(putc_unlocked, _IO_putc_unlocked); diff --git a/third_party/ulib/musl/src/stdio/putchar.c b/third_party/ulib/musl/src/stdio/putchar.c new file mode 100644 index 000000000..7da0dc96b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putchar.c @@ -0,0 +1,5 @@ +#include + +int putchar(int c) { + return fputc(c, stdout); +} diff --git a/third_party/ulib/musl/src/stdio/putchar_unlocked.c b/third_party/ulib/musl/src/stdio/putchar_unlocked.c new file mode 100644 index 000000000..9941a2dee --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putchar_unlocked.c @@ -0,0 +1,5 @@ +#include "stdio_impl.h" + +int putchar_unlocked(int c) { + return putc_unlocked(c, stdout); +} diff --git a/third_party/ulib/musl/src/stdio/puts.c b/third_party/ulib/musl/src/stdio/puts.c new file mode 100644 index 000000000..ca520dbf9 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/puts.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +int puts(const char* s) { + int r; + FLOCK(stdout); + r = -(fputs(s, stdout) < 0 || putc_unlocked('\n', stdout) < 0); + FUNLOCK(stdout); + return r; +} diff --git a/third_party/ulib/musl/src/stdio/putw.c b/third_party/ulib/musl/src/stdio/putw.c new file mode 100644 index 000000000..55a7f4857 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putw.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +int putw(int x, FILE* f) { + return (int)fwrite(&x, sizeof x, 1, f) - 1; +} diff --git a/third_party/ulib/musl/src/stdio/putwc.c b/third_party/ulib/musl/src/stdio/putwc.c new file mode 100644 index 000000000..80901f57a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putwc.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" +#include + +wint_t putwc(wchar_t c, FILE* f) { + return fputwc(c, f); +} diff --git a/third_party/ulib/musl/src/stdio/putwchar.c b/third_party/ulib/musl/src/stdio/putwchar.c new file mode 100644 index 000000000..bfde7b3f7 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/putwchar.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" +#include + +wint_t putwchar(wchar_t c) { + return fputwc(c, stdout); +} + +weak_alias(putwchar, putwchar_unlocked); diff --git a/third_party/ulib/musl/src/stdio/remove.c b/third_party/ulib/musl/src/stdio/remove.c new file mode 100644 index 000000000..797eca9dc --- /dev/null +++ b/third_party/ulib/musl/src/stdio/remove.c @@ -0,0 +1,18 @@ +#include "syscall.h" +#include +#include +#include + +int remove(const char* path) { +#ifdef SYS_unlink + int r = __syscall(SYS_unlink, path); +#else + int r = __syscall(SYS_unlinkat, AT_FDCWD, path, 0); +#endif +#ifdef SYS_rmdir + if (r == -EISDIR) r = __syscall(SYS_rmdir, path); +#else + if (r == -EISDIR) r = __syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#endif + return __syscall_ret(r); +} diff --git a/third_party/ulib/musl/src/stdio/rename.c b/third_party/ulib/musl/src/stdio/rename.c new file mode 100644 index 000000000..eb91cda27 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/rename.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int rename(const char* old, const char* new) { +#ifdef SYS_rename + return syscall(SYS_rename, old, new); +#else + return syscall(SYS_renameat, AT_FDCWD, old, AT_FDCWD, new); +#endif +} diff --git a/third_party/ulib/musl/src/stdio/rewind.c b/third_party/ulib/musl/src/stdio/rewind.c new file mode 100644 index 000000000..338b3fe01 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/rewind.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +void rewind(FILE* f) { + FLOCK(f); + __fseeko_unlocked(f, 0, SEEK_SET); + f->flags &= ~F_ERR; + FUNLOCK(f); +} diff --git a/third_party/ulib/musl/src/stdio/scanf.c b/third_party/ulib/musl/src/stdio/scanf.c new file mode 100644 index 000000000..9f4550167 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/scanf.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include +#include + +int scanf(const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vscanf(fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(scanf, __isoc99_scanf); diff --git a/third_party/ulib/musl/src/stdio/setbuf.c b/third_party/ulib/musl/src/stdio/setbuf.c new file mode 100644 index 000000000..223768b6a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/setbuf.c @@ -0,0 +1,5 @@ +#include + +void setbuf(FILE* restrict f, char* restrict buf) { + setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/third_party/ulib/musl/src/stdio/setbuffer.c b/third_party/ulib/musl/src/stdio/setbuffer.c new file mode 100644 index 000000000..97971de39 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/setbuffer.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +void setbuffer(FILE* f, char* buf, size_t size) { + setvbuf(f, buf, buf ? _IOFBF : _IONBF, size); +} diff --git a/third_party/ulib/musl/src/stdio/setlinebuf.c b/third_party/ulib/musl/src/stdio/setlinebuf.c new file mode 100644 index 000000000..496debd87 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/setlinebuf.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +void setlinebuf(FILE* f) { + setvbuf(f, 0, _IOLBF, 0); +} diff --git a/third_party/ulib/musl/src/stdio/setvbuf.c b/third_party/ulib/musl/src/stdio/setvbuf.c new file mode 100644 index 000000000..4b5c319e8 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/setvbuf.c @@ -0,0 +1,23 @@ +#include "stdio_impl.h" + +/* This function makes no attempt to protect the user from his/her own + * stupidity. If called any time but when then ISO C standard specifically + * allows it, all hell can and will break loose, especially with threads! + * + * This implementation ignores all arguments except the buffering type, + * and uses the existing buffer allocated alongside the FILE object. + * In the case of stderr where the preexisting buffer is length 1, it + * is not possible to set line buffering or full buffering. */ + +int setvbuf(FILE* restrict f, char* restrict buf, int type, size_t size) { + f->lbf = EOF; + + if (type == _IONBF) + f->buf_size = 0; + else if (type == _IOLBF) + f->lbf = '\n'; + + f->flags |= F_SVB; + + return 0; +} diff --git a/third_party/ulib/musl/src/stdio/snprintf.c b/third_party/ulib/musl/src/stdio/snprintf.c new file mode 100644 index 000000000..5ee450fb5 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/snprintf.c @@ -0,0 +1,11 @@ +#include +#include + +int snprintf(char* restrict s, size_t n, const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsnprintf(s, n, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/sprintf.c b/third_party/ulib/musl/src/stdio/sprintf.c new file mode 100644 index 000000000..b406d4e1f --- /dev/null +++ b/third_party/ulib/musl/src/stdio/sprintf.c @@ -0,0 +1,11 @@ +#include +#include + +int sprintf(char* restrict s, const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsprintf(s, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/sscanf.c b/third_party/ulib/musl/src/stdio/sscanf.c new file mode 100644 index 000000000..084457782 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/sscanf.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include +#include + +int sscanf(const char* restrict s, const char* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsscanf(s, fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(sscanf, __isoc99_sscanf); diff --git a/third_party/ulib/musl/src/stdio/stderr.c b/third_party/ulib/musl/src/stdio/stderr.c new file mode 100644 index 000000000..56a8c4217 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/stderr.c @@ -0,0 +1,16 @@ +#include "stdio_impl.h" + +static unsigned char buf[UNGET]; +static FILE f = { + .buf = buf + UNGET, + .buf_size = 0, + .fd = 2, + .flags = F_PERM | F_NORD, + .lbf = -1, + .write = __stdio_write, + .seek = __stdio_seek, + .close = __stdio_close, + .lock = -1, +}; +FILE* const stderr = &f; +FILE* volatile __stderr_used = &f; diff --git a/third_party/ulib/musl/src/stdio/stdin.c b/third_party/ulib/musl/src/stdio/stdin.c new file mode 100644 index 000000000..42b5f44f6 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/stdin.c @@ -0,0 +1,15 @@ +#include "stdio_impl.h" + +static unsigned char buf[BUFSIZ + UNGET]; +static FILE f = { + .buf = buf + UNGET, + .buf_size = sizeof buf - UNGET, + .fd = 0, + .flags = F_PERM | F_NOWR, + .read = __stdio_read, + .seek = __stdio_seek, + .close = __stdio_close, + .lock = -1, +}; +FILE* const stdin = &f; +FILE* volatile __stdin_used = &f; diff --git a/third_party/ulib/musl/src/stdio/stdout.c b/third_party/ulib/musl/src/stdio/stdout.c new file mode 100644 index 000000000..225391e64 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/stdout.c @@ -0,0 +1,16 @@ +#include "stdio_impl.h" + +static unsigned char buf[BUFSIZ + UNGET]; +static FILE f = { + .buf = buf + UNGET, + .buf_size = sizeof buf - UNGET, + .fd = 1, + .flags = F_PERM | F_NORD, + .lbf = '\n', + .write = __stdout_write, + .seek = __stdio_seek, + .close = __stdio_close, + .lock = -1, +}; +FILE* const stdout = &f; +FILE* volatile __stdout_used = &f; diff --git a/third_party/ulib/musl/src/stdio/swprintf.c b/third_party/ulib/musl/src/stdio/swprintf.c new file mode 100644 index 000000000..408b5e6ec --- /dev/null +++ b/third_party/ulib/musl/src/stdio/swprintf.c @@ -0,0 +1,11 @@ +#include +#include + +int swprintf(wchar_t* restrict s, size_t n, const wchar_t* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vswprintf(s, n, fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/swscanf.c b/third_party/ulib/musl/src/stdio/swscanf.c new file mode 100644 index 000000000..39c621caa --- /dev/null +++ b/third_party/ulib/musl/src/stdio/swscanf.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include +#include + +int swscanf(const wchar_t* restrict s, const wchar_t* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vswscanf(s, fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(swscanf, __isoc99_swscanf); diff --git a/third_party/ulib/musl/src/stdio/tempnam.c b/third_party/ulib/musl/src/stdio/tempnam.c new file mode 100644 index 000000000..a10f3c22d --- /dev/null +++ b/third_party/ulib/musl/src/stdio/tempnam.c @@ -0,0 +1,48 @@ +#include "syscall.h" +#include +#include +#include +#include +#include +#include + +#define MAXTRIES 100 + +char* __randname(char*); + +char* tempnam(const char* dir, const char* pfx) { + char s[PATH_MAX]; + size_t l, dl, pl; + int try + ; + int r; + + if (!dir) dir = P_tmpdir; + if (!pfx) pfx = "temp"; + + dl = strlen(dir); + pl = strlen(pfx); + l = dl + 1 + pl + 1 + 6; + + if (l >= PATH_MAX) { + errno = ENAMETOOLONG; + return 0; + } + + memcpy(s, dir, dl); + s[dl] = '/'; + memcpy(s + dl + 1, pfx, pl); + s[dl + 1 + pl] = '_'; + s[l] = 0; + + for (try = 0; try < MAXTRIES; try ++) { + __randname(s + l - 6); +#ifdef SYS_lstat + r = __syscall(SYS_lstat, s, &(struct stat){0}); +#else + r = __syscall(SYS_fstatat, AT_FDCWD, s, &(struct stat){0}, AT_SYMLINK_NOFOLLOW); +#endif + if (r == -ENOENT) return strdup(s); + } + return 0; +} diff --git a/third_party/ulib/musl/src/stdio/tmpfile.c b/third_party/ulib/musl/src/stdio/tmpfile.c new file mode 100644 index 000000000..7a791fce0 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/tmpfile.c @@ -0,0 +1,32 @@ +#include "stdio_impl.h" +#include +#include + +#define MAXTRIES 100 + +char* __randname(char*); + +FILE* tmpfile(void) { + char s[] = "/tmp/tmpfile_XXXXXX"; + int fd; + FILE* f; + int try + ; + for (try = 0; try < MAXTRIES; try ++) { + __randname(s + 13); + fd = sys_open(s, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { +#ifdef SYS_unlink + __syscall(SYS_unlink, s); +#else + __syscall(SYS_unlinkat, AT_FDCWD, s, 0); +#endif + f = __fdopen(fd, "w+"); + if (!f) __syscall(SYS_close, fd); + return f; + } + } + return 0; +} + +LFS64(tmpfile); diff --git a/third_party/ulib/musl/src/stdio/tmpnam.c b/third_party/ulib/musl/src/stdio/tmpnam.c new file mode 100644 index 000000000..f552bb7bf --- /dev/null +++ b/third_party/ulib/musl/src/stdio/tmpnam.c @@ -0,0 +1,28 @@ +#include "syscall.h" +#include +#include +#include +#include +#include + +#define MAXTRIES 100 + +char* __randname(char*); + +char* tmpnam(char* buf) { + static char internal[L_tmpnam]; + char s[] = "/tmp/tmpnam_XXXXXX"; + int try + ; + int r; + for (try = 0; try < MAXTRIES; try ++) { + __randname(s + 12); +#ifdef SYS_lstat + r = __syscall(SYS_lstat, s, &(struct stat){0}); +#else + r = __syscall(SYS_fstatat, AT_FDCWD, s, &(struct stat){0}, AT_SYMLINK_NOFOLLOW); +#endif + if (r == -ENOENT) return strcpy(buf ? buf : internal, s); + } + return 0; +} diff --git a/third_party/ulib/musl/src/stdio/ungetc.c b/third_party/ulib/musl/src/stdio/ungetc.c new file mode 100644 index 000000000..3162636db --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ungetc.c @@ -0,0 +1,19 @@ +#include "stdio_impl.h" + +int ungetc(int c, FILE* f) { + if (c == EOF) return c; + + FLOCK(f); + + if (!f->rpos) __toread(f); + if (!f->rpos || f->rpos <= f->buf - UNGET) { + FUNLOCK(f); + return EOF; + } + + *--f->rpos = c; + f->flags &= ~F_EOF; + + FUNLOCK(f); + return c; +} diff --git a/third_party/ulib/musl/src/stdio/ungetwc.c b/third_party/ulib/musl/src/stdio/ungetwc.c new file mode 100644 index 000000000..e85a95270 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/ungetwc.c @@ -0,0 +1,36 @@ +#include "locale_impl.h" +#include "stdio_impl.h" +#include +#include +#include +#include + +wint_t ungetwc(wint_t c, FILE* f) { + unsigned char mbc[MB_LEN_MAX]; + int l; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + FLOCK(f); + + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; + + if (!f->rpos) __toread(f); + if (!f->rpos || c == WEOF || (l = wcrtomb((void*)mbc, c, 0)) < 0 || + f->rpos < f->buf - UNGET + l) { + FUNLOCK(f); + *ploc = loc; + return WEOF; + } + + if (isascii(c)) + *--f->rpos = c; + else + memcpy(f->rpos -= l, mbc, l); + + f->flags &= ~F_EOF; + + FUNLOCK(f); + *ploc = loc; + return c; +} diff --git a/third_party/ulib/musl/src/stdio/vasprintf.c b/third_party/ulib/musl/src/stdio/vasprintf.c new file mode 100644 index 000000000..15d63ee01 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vasprintf.c @@ -0,0 +1,14 @@ +#define _GNU_SOURCE +#include +#include +#include + +int vasprintf(char** s, const char* fmt, va_list ap) { + va_list ap2; + va_copy(ap2, ap); + int l = vsnprintf(0, 0, fmt, ap2); + va_end(ap2); + + if (l < 0 || !(*s = malloc(l + 1U))) return -1; + return vsnprintf(*s, l + 1U, fmt, ap); +} diff --git a/third_party/ulib/musl/src/stdio/vdprintf.c b/third_party/ulib/musl/src/stdio/vdprintf.c new file mode 100644 index 000000000..ec14e0818 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vdprintf.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +static size_t wrap_write(FILE* f, const unsigned char* buf, size_t len) { + return __stdio_write(f, buf, len); +} + +int vdprintf(int fd, const char* restrict fmt, va_list ap) { + FILE f = { + .fd = fd, .lbf = EOF, .write = wrap_write, .buf = (void*)fmt, .buf_size = 0, .lock = -1}; + return vfprintf(&f, fmt, ap); +} diff --git a/third_party/ulib/musl/src/stdio/vfprintf.c b/third_party/ulib/musl/src/stdio/vfprintf.c new file mode 100644 index 000000000..8846cfdf0 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vfprintf.c @@ -0,0 +1,804 @@ +#include "stdio_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Some useful macros */ + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM (1U << '#' - ' ') +#define ZERO_PAD (1U << '0' - ' ') +#define LEFT_ADJ (1U << '-' - ' ') +#define PAD_POS (1U << ' ' - ' ') +#define MARK_POS (1U << '+' - ' ') +#define GROUPED (1U << '\'' - ' ') + +#define FLAGMASK (ALT_FORM | ZERO_PAD | LEFT_ADJ | PAD_POS | MARK_POS | GROUPED) + +#if UINT_MAX == ULONG_MAX +#define LONG_IS_INT +#endif + +#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX +#define ODD_TYPES +#endif + +/* State machine to accept length modifiers + conversion specifiers. + * Result is 0 on failure, or an argument type to pop on success. */ + +enum { + BARE, + LPRE, + LLPRE, + HPRE, + HHPRE, + BIGLPRE, + ZTPRE, + JPRE, + STOP, + PTR, + INT, + UINT, + ULLONG, +#ifndef LONG_IS_INT + LONG, + ULONG, +#else +#define LONG INT +#define ULONG UINT +#endif + SHORT, + USHORT, + CHAR, + UCHAR, +#ifdef ODD_TYPES + LLONG, + SIZET, + IMAX, + UMAX, + PDIFF, + UIPTR, +#else +#define LLONG ULLONG +#define SIZET ULONG +#define IMAX LLONG +#define UMAX ULLONG +#define PDIFF LONG +#define UIPTR ULONG +#endif + DBL, + LDBL, + NOARG, + MAXSTATE +}; + +#define S(x) [(x) - 'A'] + +static const unsigned char states[]['z' - 'A' + 1] = { + { + /* 0: bare types */ + S('d') = INT, S('i') = INT, S('o') = UINT, S('u') = UINT, S('x') = UINT, + S('X') = UINT, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, + S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, S('c') = CHAR, + S('C') = INT, S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, + S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, S('z') = ZTPRE, + S('j') = JPRE, S('t') = ZTPRE, + }, + { + /* 1: l-prefixed */ + S('d') = LONG, S('i') = LONG, S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, + S('X') = ULONG, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, S('E') = DBL, + S('F') = DBL, S('G') = DBL, S('A') = DBL, S('c') = INT, S('s') = PTR, S('n') = PTR, + S('l') = LLPRE, + }, + { + /* 2: ll-prefixed */ + S('d') = LLONG, S('i') = LLONG, S('o') = ULLONG, S('u') = ULLONG, S('x') = ULLONG, + S('X') = ULLONG, S('n') = PTR, + }, + { + /* 3: h-prefixed */ + S('d') = SHORT, S('i') = SHORT, S('o') = USHORT, S('u') = USHORT, S('x') = USHORT, + S('X') = USHORT, S('n') = PTR, S('h') = HHPRE, + }, + { + /* 4: hh-prefixed */ + S('d') = CHAR, S('i') = CHAR, S('o') = UCHAR, S('u') = UCHAR, S('x') = UCHAR, + S('X') = UCHAR, S('n') = PTR, + }, + { + /* 5: L-prefixed */ + S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, S('E') = LDBL, S('F') = LDBL, + S('G') = LDBL, S('A') = LDBL, S('n') = PTR, + }, + { + /* 6: z- or t-prefixed (assumed to be same size) */ + S('d') = PDIFF, S('i') = PDIFF, S('o') = SIZET, S('u') = SIZET, S('x') = SIZET, + S('X') = SIZET, S('n') = PTR, + }, + { + /* 7: j-prefixed */ + S('d') = IMAX, S('i') = IMAX, S('o') = UMAX, S('u') = UMAX, S('x') = UMAX, S('X') = UMAX, + S('n') = PTR, + }}; + +#define OOB(x) ((unsigned)(x) - 'A' > 'z' - 'A') + +union arg { + uintmax_t i; + long double f; + void* p; +}; + +static void pop_arg(union arg* arg, int type, va_list* ap) { + /* Give the compiler a hint for optimizing the switch. */ + if ((unsigned)type > MAXSTATE) return; + switch (type) { + case PTR: + arg->p = va_arg(*ap, void*); + break; + case INT: + arg->i = va_arg(*ap, int); + break; + case UINT: + arg->i = va_arg(*ap, unsigned int); +#ifndef LONG_IS_INT + break; + case LONG: + arg->i = va_arg(*ap, long); + break; + case ULONG: + arg->i = va_arg(*ap, unsigned long); +#endif + break; + case ULLONG: + arg->i = va_arg(*ap, unsigned long long); + break; + case SHORT: + arg->i = (short)va_arg(*ap, int); + break; + case USHORT: + arg->i = (unsigned short)va_arg(*ap, int); + break; + case CHAR: + arg->i = (signed char)va_arg(*ap, int); + break; + case UCHAR: + arg->i = (unsigned char)va_arg(*ap, int); +#ifdef ODD_TYPES + break; + case LLONG: + arg->i = va_arg(*ap, long long); + break; + case SIZET: + arg->i = va_arg(*ap, size_t); + break; + case IMAX: + arg->i = va_arg(*ap, intmax_t); + break; + case UMAX: + arg->i = va_arg(*ap, uintmax_t); + break; + case PDIFF: + arg->i = va_arg(*ap, ptrdiff_t); + break; + case UIPTR: + arg->i = (uintptr_t)va_arg(*ap, void*); +#endif + break; + case DBL: + arg->f = va_arg(*ap, double); + break; + case LDBL: + arg->f = va_arg(*ap, long double); + } +} + +static void out(FILE* f, const char* s, size_t l) { + if (!(f->flags & F_ERR)) __fwritex((void*)s, l, f); +} + +static void pad(FILE* f, char c, int w, int l, int fl) { + char pad[256]; + if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; + l = w - l; + memset(pad, c, l > sizeof pad ? sizeof pad : l); + for (; l >= sizeof pad; l -= sizeof pad) + out(f, pad, sizeof pad); + out(f, pad, l); +} + +static const char xdigits[16] = {"0123456789ABCDEF"}; + +static char* fmt_x(uintmax_t x, char* s, int lower) { + for (; x; x >>= 4) + *--s = xdigits[(x & 15)] | lower; + return s; +} + +static char* fmt_o(uintmax_t x, char* s) { + for (; x; x >>= 3) + *--s = '0' + (x & 7); + return s; +} + +static char* fmt_u(uintmax_t x, char* s) { + unsigned long y; + for (; x > ULONG_MAX; x /= 10) + *--s = '0' + x % 10; + for (y = x; y; y /= 10) + *--s = '0' + y % 10; + return s; +} + +/* Do not override this check. The floating point printing code below + * depends on the float.h constants being right. If they are wrong, it + * may overflow the stack. */ +#if LDBL_MANT_DIG == 53 +typedef char compiler_defines_long_double_incorrectly[9 - (int)sizeof(long double)]; +#endif + +static int fmt_fp(FILE* f, long double y, int w, int p, int fl, int t) { + uint32_t big[(LDBL_MANT_DIG + 28) / 29 + 1 // mantissa expansion + + (LDBL_MAX_EXP + LDBL_MANT_DIG + 28 + 8) / 9]; // exponent expansion + uint32_t *a, *d, *r, *z; + int e2 = 0, e, i, j, l; + char buf[9 + LDBL_MANT_DIG / 4], *s; + const char* prefix = "-0X+0X 0X-0x+0x 0x"; + int pl; + char ebuf0[3 * sizeof(int)], *ebuf = &ebuf0[3 * sizeof(int)], *estr; + + pl = 1; + if (signbit(y)) { + y = -y; + } else if (fl & MARK_POS) { + prefix += 3; + } else if (fl & PAD_POS) { + prefix += 6; + } else + prefix++, pl = 0; + + if (!isfinite(y)) { + char* s = (t & 32) ? "inf" : "INF"; + if (y != y) s = (t & 32) ? "nan" : "NAN"; + pad(f, ' ', w, 3 + pl, fl & ~ZERO_PAD); + out(f, prefix, pl); + out(f, s, 3); + pad(f, ' ', w, 3 + pl, fl ^ LEFT_ADJ); + return MAX(w, 3 + pl); + } + + y = frexpl(y, &e2) * 2; + if (y) e2--; + + if ((t | 32) == 'a') { + long double round = 8.0; + int re; + + if (t & 32) prefix += 9; + pl += 2; + + if (p < 0 || p >= LDBL_MANT_DIG / 4 - 1) + re = 0; + else + re = LDBL_MANT_DIG / 4 - 1 - p; + + if (re) { + while (re--) + round *= 16; + if (*prefix == '-') { + y = -y; + y -= round; + y += round; + y = -y; + } else { + y += round; + y -= round; + } + } + + estr = fmt_u(e2 < 0 ? -e2 : e2, ebuf); + if (estr == ebuf) *--estr = '0'; + *--estr = (e2 < 0 ? '-' : '+'); + *--estr = t + ('p' - 'a'); + + s = buf; + do { + int x = y; + *s++ = xdigits[x] | (t & 32); + y = 16 * (y - x); + if (s - buf == 1 && (y || p > 0 || (fl & ALT_FORM))) *s++ = '.'; + } while (y); + + if (p && s - buf - 2 < p) + l = (p + 2) + (ebuf - estr); + else + l = (s - buf) + (ebuf - estr); + + pad(f, ' ', w, pl + l, fl); + out(f, prefix, pl); + pad(f, '0', w, pl + l, fl ^ ZERO_PAD); + out(f, buf, s - buf); + pad(f, '0', l - (ebuf - estr) - (s - buf), 0, 0); + out(f, estr, ebuf - estr); + pad(f, ' ', w, pl + l, fl ^ LEFT_ADJ); + return MAX(w, pl + l); + } + if (p < 0) p = 6; + + if (y) y *= 0x1p28, e2 -= 28; + + if (e2 < 0) + a = r = z = big; + else + a = r = z = big + sizeof(big) / sizeof(*big) - LDBL_MANT_DIG - 1; + + do { + *z = y; + y = 1000000000 * (y - *z++); + } while (y); + + while (e2 > 0) { + uint32_t carry = 0; + int sh = MIN(29, e2); + for (d = z - 1; d >= a; d--) { + uint64_t x = ((uint64_t)*d << sh) + carry; + *d = x % 1000000000; + carry = x / 1000000000; + } + if (carry) *--a = carry; + while (z > a && !z[-1]) + z--; + e2 -= sh; + } + while (e2 < 0) { + uint32_t carry = 0, *b; + int sh = MIN(9, -e2), need = 1 + (p + LDBL_MANT_DIG / 3 + 8) / 9; + for (d = a; d < z; d++) { + uint32_t rm = *d & (1 << sh) - 1; + *d = (*d >> sh) + carry; + carry = (1000000000 >> sh) * rm; + } + if (!*a) a++; + if (carry) *z++ = carry; + /* Avoid (slow!) computation past requested precision */ + b = (t | 32) == 'f' ? r : a; + if (z - b > need) z = b + need; + e2 += sh; + } + + if (a < z) + for (i = 10, e = 9 * (r - a); *a >= i; i *= 10, e++) + ; + else + e = 0; + + /* Perform rounding: j is precision after the radix (possibly neg) */ + j = p - ((t | 32) != 'f') * e - ((t | 32) == 'g' && p); + if (j < 9 * (z - r - 1)) { + uint32_t x; + /* We avoid C's broken division of negative numbers */ + d = r + 1 + ((j + 9 * LDBL_MAX_EXP) / 9 - LDBL_MAX_EXP); + j += 9 * LDBL_MAX_EXP; + j %= 9; + for (i = 10, j++; j < 9; i *= 10, j++) + ; + x = *d % i; + /* Are there any significant digits past j? */ + if (x || d + 1 != z) { + long double round = 2 / LDBL_EPSILON; + long double small; + if (*d / i & 1) round += 2; + if (x < i / 2) + small = 0x0.8p0; + else if (x == i / 2 && d + 1 == z) + small = 0x1.0p0; + else + small = 0x1.8p0; + if (pl && *prefix == '-') round *= -1, small *= -1; + *d -= x; + /* Decide whether to round by probing round+small */ + if (round + small != round) { + *d = *d + i; + while (*d > 999999999) { + *d-- = 0; + if (d < a) *--a = 0; + (*d)++; + } + for (i = 10, e = 9 * (r - a); *a >= i; i *= 10, e++) + ; + } + } + if (z > d + 1) z = d + 1; + } + for (; z > a && !z[-1]; z--) + ; + + if ((t | 32) == 'g') { + if (!p) p++; + if (p > e && e >= -4) { + t--; + p -= e + 1; + } else { + t -= 2; + p--; + } + if (!(fl & ALT_FORM)) { + /* Count trailing zeros in last place */ + if (z > a && z[-1]) + for (i = 10, j = 0; z[-1] % i == 0; i *= 10, j++) + ; + else + j = 9; + if ((t | 32) == 'f') + p = MIN(p, MAX(0, 9 * (z - r - 1) - j)); + else + p = MIN(p, MAX(0, 9 * (z - r - 1) + e - j)); + } + } + l = 1 + p + (p || (fl & ALT_FORM)); + if ((t | 32) == 'f') { + if (e > 0) l += e; + } else { + estr = fmt_u(e < 0 ? -e : e, ebuf); + while (ebuf - estr < 2) + *--estr = '0'; + *--estr = (e < 0 ? '-' : '+'); + *--estr = t; + l += ebuf - estr; + } + + pad(f, ' ', w, pl + l, fl); + out(f, prefix, pl); + pad(f, '0', w, pl + l, fl ^ ZERO_PAD); + + if ((t | 32) == 'f') { + if (a > r) a = r; + for (d = a; d <= r; d++) { + char* s = fmt_u(*d, buf + 9); + if (d != a) + while (s > buf) + *--s = '0'; + else if (s == buf + 9) + *--s = '0'; + out(f, s, buf + 9 - s); + } + if (p || (fl & ALT_FORM)) out(f, ".", 1); + for (; d < z && p > 0; d++, p -= 9) { + char* s = fmt_u(*d, buf + 9); + while (s > buf) + *--s = '0'; + out(f, s, MIN(9, p)); + } + pad(f, '0', p + 9, 9, 0); + } else { + if (z <= a) z = a + 1; + for (d = a; d < z && p >= 0; d++) { + char* s = fmt_u(*d, buf + 9); + if (s == buf + 9) *--s = '0'; + if (d != a) + while (s > buf) + *--s = '0'; + else { + out(f, s++, 1); + if (p > 0 || (fl & ALT_FORM)) out(f, ".", 1); + } + out(f, s, MIN(buf + 9 - s, p)); + p -= buf + 9 - s; + } + pad(f, '0', p + 18, 18, 0); + out(f, estr, ebuf - estr); + } + + pad(f, ' ', w, pl + l, fl ^ LEFT_ADJ); + + return MAX(w, pl + l); +} + +static int getint(char** s) { + int i; + for (i = 0; isdigit(**s); (*s)++) + i = 10 * i + (**s - '0'); + return i; +} + +static int printf_core(FILE* f, const char* fmt, va_list* ap, union arg* nl_arg, int* nl_type) { + char *a, *z, *s = (char *)fmt; + unsigned l10n = 0, fl; + int w, p; + union arg arg; + int argpos; + unsigned st, ps; + int cnt = 0, l = 0; + int i; + char buf[sizeof(uintmax_t) * 3 + 3 + LDBL_MANT_DIG / 4]; + const char* prefix; + int t, pl; + wchar_t wc[2]; + // TODO(kulakowski) Wide char string formatting + // wchar_t* ws; + // char mb[4]; + + for (;;) { + /* Update output count, end loop when fmt is exhausted */ + if (cnt >= 0) { + if (l > INT_MAX - cnt) { + errno = EOVERFLOW; + cnt = -1; + } else + cnt += l; + } + if (!*s) break; + + /* Handle literal text and %% format specifiers */ + for (a = s; *s && *s != '%'; s++) + ; + for (z = s; s[0] == '%' && s[1] == '%'; z++, s += 2) + ; + l = z - a; + if (f) out(f, a, l); + if (l) continue; + + if (isdigit(s[1]) && s[2] == '$') { + l10n = 1; + argpos = s[1] - '0'; + s += 3; + } else { + argpos = -1; + s++; + } + + /* Read modifier flags */ + for (fl = 0; (unsigned)*s - ' ' < 32 && (FLAGMASK & (1U << *s - ' ')); s++) + fl |= 1U << *s - ' '; + + /* Read field width */ + if (*s == '*') { + if (isdigit(s[1]) && s[2] == '$') { + l10n = 1; + nl_type[s[1] - '0'] = INT; + w = nl_arg[s[1] - '0'].i; + s += 3; + } else if (!l10n) { + w = f ? va_arg(*ap, int) : 0; + s++; + } else + return -1; + if (w < 0) fl |= LEFT_ADJ, w = -w; + } else if ((w = getint(&s)) < 0) + return -1; + + /* Read precision */ + if (*s == '.' && s[1] == '*') { + if (isdigit(s[2]) && s[3] == '$') { + nl_type[s[2] - '0'] = INT; + p = nl_arg[s[2] - '0'].i; + s += 4; + } else if (!l10n) { + p = f ? va_arg(*ap, int) : 0; + s += 2; + } else + return -1; + } else if (*s == '.') { + s++; + p = getint(&s); + } else + p = -1; + + /* Format specifier state machine */ + st = 0; + do { + if (OOB(*s)) return -1; + ps = st; + st = states[st] S(*s++); + } while (st - 1 < STOP); + if (!st) return -1; + + /* Check validity of argument type (nl/normal) */ + if (st == NOARG) { + if (argpos >= 0) return -1; + } else { + if (argpos >= 0) + nl_type[argpos] = st, arg = nl_arg[argpos]; + else if (f) + pop_arg(&arg, st, ap); + else + return 0; + } + + if (!f) continue; + + z = buf + sizeof(buf); + prefix = "-+ 0X0x"; + pl = 0; + t = s[-1]; + + /* Transform ls,lc -> S,C */ + if (ps && (t & 15) == 3) t &= ~32; + + /* - and 0 flags are mutually exclusive */ + if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; + + switch (t) { + case 'n': + switch (ps) { + case BARE: + *(int*)arg.p = cnt; + break; + case LPRE: + *(long*)arg.p = cnt; + break; + case LLPRE: + *(long long*)arg.p = cnt; + break; + case HPRE: + *(unsigned short*)arg.p = cnt; + break; + case HHPRE: + *(unsigned char*)arg.p = cnt; + break; + case ZTPRE: + *(size_t*)arg.p = cnt; + break; + case JPRE: + *(uintmax_t*)arg.p = cnt; + break; + } + continue; + case 'p': + p = MAX(p, 2 * sizeof(void*)); + t = 'x'; + fl |= ALT_FORM; + case 'x': + case 'X': + a = fmt_x(arg.i, z, t & 32); + if (arg.i && (fl & ALT_FORM)) prefix += (t >> 4), pl = 2; + if (0) { + case 'o': + a = fmt_o(arg.i, z); + if ((fl & ALT_FORM) && p < z - a + 1) p = z - a + 1; + } + if (0) { + case 'd': + case 'i': + pl = 1; + if (arg.i > INTMAX_MAX) { + arg.i = -arg.i; + } else if (fl & MARK_POS) { + prefix++; + } else if (fl & PAD_POS) { + prefix += 2; + } else + pl = 0; + case 'u': + a = fmt_u(arg.i, z); + } + if (p >= 0) fl &= ~ZERO_PAD; + if (!arg.i && !p) { + a = z; + break; + } + p = MAX(p, z - a + !arg.i); + break; + case 'c': + *(a = z - (p = 1)) = arg.i; + fl &= ~ZERO_PAD; + break; + case 'm': + if (1) + a = strerror(errno); + else + case 's': + a = arg.p ? arg.p : "(null)"; + z = memchr(a, 0, p); + if (!z) + z = a + p; + else + p = z - a; + fl &= ~ZERO_PAD; + break; + case 'C': + wc[0] = arg.i; + wc[1] = 0; + arg.p = wc; + p = -1; + // TODO(kulakowski) Wide char string formatting + // case 'S': + // ws = arg.p; + // for (i = l = 0; i < 0U + p && *ws && (l = wctomb(mb, *ws++)) >= 0 && l <= 0U + p - i; + // i += l) + // ; + // if (l < 0) return -1; + // p = i; + // pad(f, ' ', w, p, fl); + // ws = arg.p; + // for (i = 0; i < 0U + p && *ws && i + (l = wctomb(mb, *ws++)) <= p; i += l) + // out(f, mb, l); + // pad(f, ' ', w, p, fl ^ LEFT_ADJ); + // l = w > p ? w : p; + // continue; + case 'e': + case 'f': + case 'g': + case 'a': + case 'E': + case 'F': + case 'G': + case 'A': + l = fmt_fp(f, arg.f, w, p, fl, t); + continue; + } + + if (p < z - a) p = z - a; + if (w < pl + p) w = pl + p; + + pad(f, ' ', w, pl + p, fl); + out(f, prefix, pl); + pad(f, '0', w, pl + p, fl ^ ZERO_PAD); + pad(f, '0', p, z - a, 0); + out(f, a, z - a); + pad(f, ' ', w, pl + p, fl ^ LEFT_ADJ); + + l = w; + } + + if (f) return cnt; + if (!l10n) return 0; + + for (i = 1; i <= NL_ARGMAX && nl_type[i]; i++) + pop_arg(nl_arg + i, nl_type[i], ap); + for (; i <= NL_ARGMAX && !nl_type[i]; i++) + ; + if (i <= NL_ARGMAX) return -1; + return 1; +} + +int vfprintf(FILE* restrict f, const char* restrict fmt, va_list ap) { + va_list ap2; + int nl_type[NL_ARGMAX + 1] = {0}; + union arg nl_arg[NL_ARGMAX + 1]; + unsigned char internal_buf[80], *saved_buf = 0; + int olderr; + int ret; + + /* the copy allows passing va_list* even if va_list is an array */ + va_copy(ap2, ap); + if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { + va_end(ap2); + return -1; + } + + FLOCK(f); + olderr = f->flags & F_ERR; + if (f->mode < 1) f->flags &= ~F_ERR; + if (!f->buf_size) { + saved_buf = f->buf; + f->wpos = f->wbase = f->buf = internal_buf; + f->buf_size = sizeof internal_buf; + f->wend = internal_buf + sizeof internal_buf; + } + ret = printf_core(f, fmt, &ap2, nl_arg, nl_type); + if (saved_buf) { + f->write(f, 0, 0); + if (!f->wpos) ret = -1; + f->buf = saved_buf; + f->buf_size = 0; + f->wpos = f->wbase = f->wend = 0; + } + if (f->flags & F_ERR) ret = -1; + f->flags |= olderr; + FUNLOCK(f); + va_end(ap2); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/vfscanf.c b/third_party/ulib/musl/src/stdio/vfscanf.c new file mode 100644 index 000000000..ba5ebc5a2 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vfscanf.c @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "floatscan.h" +#include "intscan.h" +#include "shgetc.h" +#include "stdio_impl.h" + +#define SIZE_hh -2 +#define SIZE_h -1 +#define SIZE_def 0 +#define SIZE_l 1 +#define SIZE_L 2 +#define SIZE_ll 3 + +static void store_int(void* dest, int size, unsigned long long i) { + if (!dest) return; + switch (size) { + case SIZE_hh: + *(char*)dest = i; + break; + case SIZE_h: + *(short*)dest = i; + break; + case SIZE_def: + *(int*)dest = i; + break; + case SIZE_l: + *(long*)dest = i; + break; + case SIZE_ll: + *(long long*)dest = i; + break; + } +} + +static void* arg_n(va_list ap, unsigned int n) { + void* p; + unsigned int i; + va_list ap2; + va_copy(ap2, ap); + for (i = n; i > 1; i--) + va_arg(ap2, void*); + p = va_arg(ap2, void*); + va_end(ap2); + return p; +} + +int vfscanf(FILE* restrict f, const char* restrict fmt, va_list ap) { + int width; + int size; + int alloc; + int base; + const unsigned char* p; + int c, t; + char* s; + wchar_t* wcs; + mbstate_t st; + void* dest = NULL; + int invert; + int matches = 0; + unsigned long long x; + long double y; + off_t pos = 0; + unsigned char scanset[257]; + size_t i, k; + wchar_t wc; + + FLOCK(f); + + for (p = (const unsigned char*)fmt; *p; p++) { + + alloc = 0; + + if (isspace(*p)) { + while (isspace(p[1])) + p++; + shlim(f, 0); + while (isspace(shgetc(f))) + ; + shunget(f); + pos += shcnt(f); + continue; + } + if (*p != '%' || p[1] == '%') { + p += *p == '%'; + shlim(f, 0); + c = shgetc(f); + if (c != *p) { + shunget(f); + if (c < 0) goto input_fail; + goto match_fail; + } + pos++; + continue; + } + + p++; + if (*p == '*') { + dest = 0; + p++; + } else if (isdigit(*p) && p[1] == '$') { + dest = arg_n(ap, *p - '0'); + p += 2; + } else { + dest = va_arg(ap, void*); + } + + for (width = 0; isdigit(*p); p++) { + width = 10 * width + *p - '0'; + } + + if (*p == 'm') { + wcs = 0; + s = 0; + alloc = !!dest; + p++; + } else { + alloc = 0; + } + + size = SIZE_def; + switch (*p++) { + case 'h': + if (*p == 'h') + p++, size = SIZE_hh; + else + size = SIZE_h; + break; + case 'l': + if (*p == 'l') + p++, size = SIZE_ll; + else + size = SIZE_l; + break; + case 'j': + size = SIZE_ll; + break; + case 'z': + case 't': + size = SIZE_l; + break; + case 'L': + size = SIZE_L; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'a': + case 'e': + case 'f': + case 'g': + case 'A': + case 'E': + case 'F': + case 'G': + case 'X': + case 's': + case 'c': + case '[': + case 'S': + case 'C': + case 'p': + case 'n': + p--; + break; + default: + goto fmt_fail; + } + + t = *p; + + /* C or S */ + if ((t & 0x2f) == 3) { + t |= 32; + size = SIZE_l; + } + + switch (t) { + case 'c': + if (width < 1) width = 1; + case '[': + break; + case 'n': + store_int(dest, size, pos); + /* do not increment match count, etc! */ + continue; + default: + shlim(f, 0); + while (isspace(shgetc(f))) + ; + shunget(f); + pos += shcnt(f); + } + + shlim(f, width); + if (shgetc(f) < 0) goto input_fail; + shunget(f); + + switch (t) { + case 's': + case 'c': + case '[': + if (t == 'c' || t == 's') { + memset(scanset, -1, sizeof scanset); + scanset[0] = 0; + if (t == 's') { + scanset[1 + '\t'] = 0; + scanset[1 + '\n'] = 0; + scanset[1 + '\v'] = 0; + scanset[1 + '\f'] = 0; + scanset[1 + '\r'] = 0; + scanset[1 + ' '] = 0; + } + } else { + if (*++p == '^') + p++, invert = 1; + else + invert = 0; + memset(scanset, invert, sizeof scanset); + scanset[0] = 0; + if (*p == '-') + p++, scanset[1 + '-'] = 1 - invert; + else if (*p == ']') + p++, scanset[1 + ']'] = 1 - invert; + for (; *p != ']'; p++) { + if (!*p) goto fmt_fail; + if (*p == '-' && p[1] && p[1] != ']') + for (c = p++ [-1]; c < *p; c++) + scanset[1 + c] = 1 - invert; + scanset[1 + *p] = 1 - invert; + } + } + wcs = 0; + s = 0; + i = 0; + k = t == 'c' ? width + 1U : 31; + if (size == SIZE_l) { + if (alloc) { + wcs = malloc(k * sizeof(wchar_t)); + if (!wcs) goto alloc_fail; + } else { + wcs = dest; + } + st = (mbstate_t){0}; + while (scanset[(c = shgetc(f)) + 1]) { + switch (mbrtowc(&wc, &(char){c}, 1, &st)) { + case -1: + goto input_fail; + case -2: + continue; + } + if (wcs) wcs[i++] = wc; + if (alloc && i == k) { + k += k + 1; + wchar_t* tmp = realloc(wcs, k * sizeof(wchar_t)); + if (!tmp) goto alloc_fail; + wcs = tmp; + } + } + if (!mbsinit(&st)) goto input_fail; + } else if (alloc) { + s = malloc(k); + if (!s) goto alloc_fail; + while (scanset[(c = shgetc(f)) + 1]) { + s[i++] = c; + if (i == k) { + k += k + 1; + char* tmp = realloc(s, k); + if (!tmp) goto alloc_fail; + s = tmp; + } + } + } else if ((s = dest)) { + while (scanset[(c = shgetc(f)) + 1]) + s[i++] = c; + } else { + while (scanset[(c = shgetc(f)) + 1]) + ; + } + shunget(f); + if (!shcnt(f)) goto match_fail; + if (t == 'c' && shcnt(f) != width) goto match_fail; + if (alloc) { + if (size == SIZE_l) + *(wchar_t**)dest = wcs; + else + *(char**)dest = s; + } + if (t != 'c') { + if (wcs) wcs[i] = 0; + if (s) s[i] = 0; + } + break; + case 'p': + case 'X': + case 'x': + base = 16; + goto int_common; + case 'o': + base = 8; + goto int_common; + case 'd': + case 'u': + base = 10; + goto int_common; + case 'i': + base = 0; + int_common: + x = __intscan(f, base, 0, ULLONG_MAX); + if (!shcnt(f)) goto match_fail; + if (t == 'p' && dest) + *(void**)dest = (void*)(uintptr_t)x; + else + store_int(dest, size, x); + break; + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + y = __floatscan(f, size, 0); + if (!shcnt(f)) goto match_fail; + if (dest) switch (size) { + case SIZE_def: + *(float*)dest = y; + break; + case SIZE_l: + *(double*)dest = y; + break; + case SIZE_L: + *(long double*)dest = y; + break; + } + break; + } + + pos += shcnt(f); + if (dest) matches++; + } + if (0) { + fmt_fail: + alloc_fail: + input_fail: + if (!matches) matches--; + match_fail: + if (alloc) { + free(s); + free(wcs); + } + } + FUNLOCK(f); + return matches; +} + +weak_alias(vfscanf, __isoc99_vfscanf); diff --git a/third_party/ulib/musl/src/stdio/vfwprintf.c b/third_party/ulib/musl/src/stdio/vfwprintf.c new file mode 100644 index 000000000..1f04f99d3 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vfwprintf.c @@ -0,0 +1,446 @@ +#include "stdio_impl.h" +#include +#include +#include +#include +#include +#include +#include + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM (1U << '#' - ' ') +#define ZERO_PAD (1U << '0' - ' ') +#define LEFT_ADJ (1U << '-' - ' ') +#define PAD_POS (1U << ' ' - ' ') +#define MARK_POS (1U << '+' - ' ') +#define GROUPED (1U << '\'' - ' ') + +#define FLAGMASK (ALT_FORM | ZERO_PAD | LEFT_ADJ | PAD_POS | MARK_POS | GROUPED) + +#if UINT_MAX == ULONG_MAX +#define LONG_IS_INT +#endif + +#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX +#define ODD_TYPES +#endif + +/* State machine to accept length modifiers + conversion specifiers. + * Result is 0 on failure, or an argument type to pop on success. */ + +enum { + BARE, + LPRE, + LLPRE, + HPRE, + HHPRE, + BIGLPRE, + ZTPRE, + JPRE, + STOP, + PTR, + INT, + UINT, + ULLONG, +#ifndef LONG_IS_INT + LONG, + ULONG, +#else +#define LONG INT +#define ULONG UINT +#endif + SHORT, + USHORT, + CHAR, + UCHAR, +#ifdef ODD_TYPES + LLONG, + SIZET, + IMAX, + UMAX, + PDIFF, + UIPTR, +#else +#define LLONG ULLONG +#define SIZET ULONG +#define IMAX LLONG +#define UMAX ULLONG +#define PDIFF LONG +#define UIPTR ULONG +#endif + DBL, + LDBL, + NOARG, + MAXSTATE +}; + +#define S(x) [(x) - 'A'] + +static const unsigned char states[]['z' - 'A' + 1] = { + { + /* 0: bare types */ + S('d') = INT, S('i') = INT, S('o') = UINT, S('u') = UINT, S('x') = UINT, + S('X') = UINT, S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, + S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, S('c') = CHAR, + S('C') = INT, S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, + S('m') = NOARG, S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, S('z') = ZTPRE, + S('j') = JPRE, S('t') = ZTPRE, + }, + { + /* 1: l-prefixed */ + S('d') = LONG, S('i') = LONG, S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, + S('X') = ULONG, S('c') = INT, S('s') = PTR, S('n') = PTR, S('l') = LLPRE, + }, + { + /* 2: ll-prefixed */ + S('d') = LLONG, S('i') = LLONG, S('o') = ULLONG, S('u') = ULLONG, S('x') = ULLONG, + S('X') = ULLONG, S('n') = PTR, + }, + { + /* 3: h-prefixed */ + S('d') = SHORT, S('i') = SHORT, S('o') = USHORT, S('u') = USHORT, S('x') = USHORT, + S('X') = USHORT, S('n') = PTR, S('h') = HHPRE, + }, + { + /* 4: hh-prefixed */ + S('d') = CHAR, S('i') = CHAR, S('o') = UCHAR, S('u') = UCHAR, S('x') = UCHAR, + S('X') = UCHAR, S('n') = PTR, + }, + { + /* 5: L-prefixed */ + S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, S('E') = LDBL, S('F') = LDBL, + S('G') = LDBL, S('A') = LDBL, S('n') = PTR, + }, + { + /* 6: z- or t-prefixed (assumed to be same size) */ + S('d') = PDIFF, S('i') = PDIFF, S('o') = SIZET, S('u') = SIZET, S('x') = SIZET, + S('X') = SIZET, S('n') = PTR, + }, + { + /* 7: j-prefixed */ + S('d') = IMAX, S('i') = IMAX, S('o') = UMAX, S('u') = UMAX, S('x') = UMAX, S('X') = UMAX, + S('n') = PTR, + }}; + +#define OOB(x) ((unsigned)(x) - 'A' > 'z' - 'A') + +union arg { + uintmax_t i; + long double f; + void* p; +}; + +static void pop_arg(union arg* arg, int type, va_list* ap) { + /* Give the compiler a hint for optimizing the switch. */ + if ((unsigned)type > MAXSTATE) return; + switch (type) { + case PTR: + arg->p = va_arg(*ap, void*); + break; + case INT: + arg->i = va_arg(*ap, int); + break; + case UINT: + arg->i = va_arg(*ap, unsigned int); +#ifndef LONG_IS_INT + break; + case LONG: + arg->i = va_arg(*ap, long); + break; + case ULONG: + arg->i = va_arg(*ap, unsigned long); +#endif + break; + case ULLONG: + arg->i = va_arg(*ap, unsigned long long); + break; + case SHORT: + arg->i = (short)va_arg(*ap, int); + break; + case USHORT: + arg->i = (unsigned short)va_arg(*ap, int); + break; + case CHAR: + arg->i = (signed char)va_arg(*ap, int); + break; + case UCHAR: + arg->i = (unsigned char)va_arg(*ap, int); +#ifdef ODD_TYPES + break; + case LLONG: + arg->i = va_arg(*ap, long long); + break; + case SIZET: + arg->i = va_arg(*ap, size_t); + break; + case IMAX: + arg->i = va_arg(*ap, intmax_t); + break; + case UMAX: + arg->i = va_arg(*ap, uintmax_t); + break; + case PDIFF: + arg->i = va_arg(*ap, ptrdiff_t); + break; + case UIPTR: + arg->i = (uintptr_t)va_arg(*ap, void*); +#endif + break; + case DBL: + arg->f = va_arg(*ap, double); + break; + case LDBL: + arg->f = va_arg(*ap, long double); + } +} + +static void out(FILE* f, const wchar_t* s, size_t l) { + while (l-- && !(f->flags & F_ERR)) + fputwc(*s++, f); +} + +static int getint(wchar_t** s) { + int i; + for (i = 0; iswdigit(**s); (*s)++) + i = 10 * i + (**s - '0'); + return i; +} + +static const char sizeprefix['y' - 'a'] = {['a' - 'a'] = 'L', ['e' - 'a'] = 'L', ['f' - 'a'] = 'L', + ['g' - 'a'] = 'L', ['d' - 'a'] = 'j', ['i' - 'a'] = 'j', + ['o' - 'a'] = 'j', ['u' - 'a'] = 'j', ['x' - 'a'] = 'j', + ['p' - 'a'] = 'j'}; + +static int wprintf_core(FILE* f, const wchar_t* fmt, va_list* ap, union arg* nl_arg, int* nl_type) { + wchar_t *a, *z, *s = (wchar_t *)fmt; + unsigned l10n = 0, litpct, fl; + int w, p; + union arg arg; + int argpos; + unsigned st, ps; + int cnt = 0, l = 0; + int i; + int t; + char* bs; + char charfmt[16]; + wchar_t wc; + + for (;;) { + /* Update output count, end loop when fmt is exhausted */ + if (cnt >= 0) { + if (l > INT_MAX - cnt) { + if (!ferror(f)) errno = EOVERFLOW; + cnt = -1; + } else + cnt += l; + } + if (!*s) break; + + /* Handle literal text and %% format specifiers */ + for (a = s; *s && *s != '%'; s++) + ; + litpct = wcsspn(s, L"%") / 2; /* Optimize %%%% runs */ + z = s + litpct; + s += 2 * litpct; + l = z - a; + if (f) out(f, a, l); + if (l) continue; + + if (iswdigit(s[1]) && s[2] == '$') { + l10n = 1; + argpos = s[1] - '0'; + s += 3; + } else { + argpos = -1; + s++; + } + + /* Read modifier flags */ + for (fl = 0; (unsigned)*s - ' ' < 32 && (FLAGMASK & (1U << *s - ' ')); s++) + fl |= 1U << *s - ' '; + + /* Read field width */ + if (*s == '*') { + if (iswdigit(s[1]) && s[2] == '$') { + l10n = 1; + nl_type[s[1] - '0'] = INT; + w = nl_arg[s[1] - '0'].i; + s += 3; + } else if (!l10n) { + w = f ? va_arg(*ap, int) : 0; + s++; + } else + return -1; + if (w < 0) fl |= LEFT_ADJ, w = -w; + } else if ((w = getint(&s)) < 0) + return -1; + + /* Read precision */ + if (*s == '.' && s[1] == '*') { + if (isdigit(s[2]) && s[3] == '$') { + nl_type[s[2] - '0'] = INT; + p = nl_arg[s[2] - '0'].i; + s += 4; + } else if (!l10n) { + p = f ? va_arg(*ap, int) : 0; + s += 2; + } else + return -1; + } else if (*s == '.') { + s++; + p = getint(&s); + } else + p = -1; + + /* Format specifier state machine */ + st = 0; + do { + if (OOB(*s)) return -1; + ps = st; + st = states[st] S(*s++); + } while (st - 1 < STOP); + if (!st) return -1; + + /* Check validity of argument type (nl/normal) */ + if (st == NOARG) { + if (argpos >= 0) return -1; + } else { + if (argpos >= 0) + nl_type[argpos] = st, arg = nl_arg[argpos]; + else if (f) + pop_arg(&arg, st, ap); + else + return 0; + } + + if (!f) continue; + t = s[-1]; + if (ps && (t & 15) == 3) t &= ~32; + + switch (t) { + case 'n': + switch (ps) { + case BARE: + *(int*)arg.p = cnt; + break; + case LPRE: + *(long*)arg.p = cnt; + break; + case LLPRE: + *(long long*)arg.p = cnt; + break; + case HPRE: + *(unsigned short*)arg.p = cnt; + break; + case HHPRE: + *(unsigned char*)arg.p = cnt; + break; + case ZTPRE: + *(size_t*)arg.p = cnt; + break; + case JPRE: + *(uintmax_t*)arg.p = cnt; + break; + } + continue; + case 'c': + fputwc(btowc(arg.i), f); + l = 1; + continue; + case 'C': + fputwc(arg.i, f); + l = 1; + continue; + case 'S': + a = arg.p; + z = wmemchr(a, 0, p); + if (z) p = z - a; + if (w < p) w = p; + if (!(fl & LEFT_ADJ)) fprintf(f, "%*s", w - p, ""); + out(f, a, p); + if ((fl & LEFT_ADJ)) fprintf(f, "%*s", w - p, ""); + l = w; + continue; + case 'm': + arg.p = strerror(errno); + case 's': + if (!arg.p) arg.p = "(null)"; + bs = arg.p; + if (p < 0) p = INT_MAX; + for (i = l = 0; l < p && (i = mbtowc(&wc, bs, MB_LEN_MAX)) > 0; bs += i, l++) + ; + if (i < 0) return -1; + p = l; + if (w < p) w = p; + if (!(fl & LEFT_ADJ)) fprintf(f, "%*s", w - p, ""); + bs = arg.p; + while (l--) { + i = mbtowc(&wc, bs, MB_LEN_MAX); + bs += i; + fputwc(wc, f); + } + if ((fl & LEFT_ADJ)) fprintf(f, "%*s", w - p, ""); + l = w; + continue; + } + + snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c", "#" + !(fl & ALT_FORM), + "+" + !(fl & MARK_POS), "-" + !(fl & LEFT_ADJ), " " + !(fl & PAD_POS), + "0" + !(fl & ZERO_PAD), sizeprefix[(t | 32) - 'a'], t); + + switch (t | 32) { + case 'a': + case 'e': + case 'f': + case 'g': + l = fprintf(f, charfmt, w, p, arg.f); + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'p': + l = fprintf(f, charfmt, w, p, arg.i); + break; + } + } + + if (f) return cnt; + if (!l10n) return 0; + + for (i = 1; i <= NL_ARGMAX && nl_type[i]; i++) + pop_arg(nl_arg + i, nl_type[i], ap); + for (; i <= NL_ARGMAX && !nl_type[i]; i++) + ; + if (i <= NL_ARGMAX) return -1; + return 1; +} + +int vfwprintf(FILE* restrict f, const wchar_t* restrict fmt, va_list ap) { + va_list ap2; + int nl_type[NL_ARGMAX] = {0}; + union arg nl_arg[NL_ARGMAX]; + int olderr; + int ret; + + /* the copy allows passing va_list* even if va_list is an array */ + va_copy(ap2, ap); + if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { + va_end(ap2); + return -1; + } + + FLOCK(f); + fwide(f, 1); + olderr = f->flags & F_ERR; + f->flags &= ~F_ERR; + ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); + if (f->flags & F_ERR) ret = -1; + f->flags |= olderr; + FUNLOCK(f); + va_end(ap2); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/vfwscanf.c b/third_party/ulib/musl/src/stdio/vfwscanf.c new file mode 100644 index 000000000..bfc175bed --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vfwscanf.c @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "floatscan.h" +#include "intscan.h" +#include "libc.h" +#include "shgetc.h" +#include "stdio_impl.h" + +#define SIZE_hh -2 +#define SIZE_h -1 +#define SIZE_def 0 +#define SIZE_l 1 +#define SIZE_L 2 +#define SIZE_ll 3 + +static void store_int(void* dest, int size, unsigned long long i) { + if (!dest) return; + switch (size) { + case SIZE_hh: + *(char*)dest = i; + break; + case SIZE_h: + *(short*)dest = i; + break; + case SIZE_def: + *(int*)dest = i; + break; + case SIZE_l: + *(long*)dest = i; + break; + case SIZE_ll: + *(long long*)dest = i; + break; + } +} + +static void* arg_n(va_list ap, unsigned int n) { + void* p; + unsigned int i; + va_list ap2; + va_copy(ap2, ap); + for (i = n; i > 1; i--) + va_arg(ap2, void*); + p = va_arg(ap2, void*); + va_end(ap2); + return p; +} + +static int in_set(const wchar_t* set, int c) { + int j; + const wchar_t* p = set; + if (*p == '-') { + if (c == '-') return 1; + p++; + } else if (*p == ']') { + if (c == ']') return 1; + p++; + } + for (; *p && *p != ']'; p++) { + if (*p == '-' && p[1] && p[1] != ']') + for (j = p++ [-1]; j < *p; j++) + if (c == j) return 1; + if (c == *p) return 1; + } + return 0; +} + +#if 1 +#undef getwc +#define getwc(f) ((f)->rpos < (f)->rend && *(f)->rpos < 128 ? *(f)->rpos++ : (getwc)(f)) + +#undef ungetwc +#define ungetwc(c, f) ((f)->rend && (c) < 128U ? *--(f)->rpos : ungetwc((c), (f))) +#endif + +int vfwscanf(FILE* restrict f, const wchar_t* restrict fmt, va_list ap) { + int width; + int size; + int alloc; + const wchar_t* p; + int c, t; + char* s; + wchar_t* wcs; + void* dest = NULL; + int invert; + int matches = 0; + off_t pos = 0, cnt; + static const char size_pfx[][3] = {"hh", "h", "", "l", "L", "ll"}; + char tmp[3 * sizeof(int) + 10]; + const wchar_t* set; + size_t i, k; + + FLOCK(f); + + fwide(f, 1); + + for (p = fmt; *p; p++) { + + alloc = 0; + + if (iswspace(*p)) { + while (iswspace(p[1])) + p++; + while (iswspace((c = getwc(f)))) + pos++; + ungetwc(c, f); + continue; + } + if (*p != '%' || p[1] == '%') { + p += *p == '%'; + c = getwc(f); + if (c != *p) { + ungetwc(c, f); + if (c < 0) goto input_fail; + goto match_fail; + } + pos++; + continue; + } + + p++; + if (*p == '*') { + dest = 0; + p++; + } else if (iswdigit(*p) && p[1] == '$') { + dest = arg_n(ap, *p - '0'); + p += 2; + } else { + dest = va_arg(ap, void*); + } + + for (width = 0; iswdigit(*p); p++) { + width = 10 * width + *p - '0'; + } + + if (*p == 'm') { + wcs = 0; + s = 0; + alloc = !!dest; + p++; + } else { + alloc = 0; + } + + size = SIZE_def; + switch (*p++) { + case 'h': + if (*p == 'h') + p++, size = SIZE_hh; + else + size = SIZE_h; + break; + case 'l': + if (*p == 'l') + p++, size = SIZE_ll; + else + size = SIZE_l; + break; + case 'j': + size = SIZE_ll; + break; + case 'z': + case 't': + size = SIZE_l; + break; + case 'L': + size = SIZE_L; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'a': + case 'e': + case 'f': + case 'g': + case 'A': + case 'E': + case 'F': + case 'G': + case 'X': + case 's': + case 'c': + case '[': + case 'S': + case 'C': + case 'p': + case 'n': + p--; + break; + default: + goto fmt_fail; + } + + t = *p; + + /* Transform S,C -> ls,lc */ + if ((t & 0x2f) == 3) { + size = SIZE_l; + t |= 32; + } + + if (t != 'n') { + if (t != '[' && (t | 32) != 'c') + while (iswspace((c = getwc(f)))) + pos++; + else + c = getwc(f); + if (c < 0) goto input_fail; + ungetwc(c, f); + } + + switch (t) { + case 'n': + store_int(dest, size, pos); + /* do not increment match count, etc! */ + continue; + + case 's': + case 'c': + case '[': + if (t == 'c') { + if (width < 1) width = 1; + invert = 1; + set = L""; + } else if (t == 's') { + invert = 1; + set = (const wchar_t[]){' ', '\t', '\n', '\r', 11, 12, + 0x0085, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, + 0x2005, 0x2006, 0x2008, 0x2009, 0x200a, 0x2028, + 0x2029, 0x205f, 0x3000, 0}; + } else { + if (*++p == '^') + p++, invert = 1; + else + invert = 0; + set = p; + if (*p == ']') p++; + while (*p != ']') { + if (!*p) goto fmt_fail; + p++; + } + } + + s = (size == SIZE_def) ? dest : 0; + wcs = (size == SIZE_l) ? dest : 0; + + int gotmatch = 0; + + if (width < 1) width = -1; + + i = 0; + if (alloc) { + k = t == 'c' ? width + 1U : 31; + if (size == SIZE_l) { + wcs = malloc(k * sizeof(wchar_t)); + if (!wcs) goto alloc_fail; + } else { + s = malloc(k); + if (!s) goto alloc_fail; + } + } + while (width) { + if ((c = getwc(f)) < 0) break; + if (in_set(set, c) == invert) break; + if (wcs) { + wcs[i++] = c; + if (alloc && i == k) { + k += k + 1; + wchar_t* tmp = realloc(wcs, k * sizeof(wchar_t)); + if (!tmp) goto alloc_fail; + wcs = tmp; + } + } else if (size != SIZE_l) { + int l = wctomb(s ? s + i : tmp, c); + if (l < 0) goto input_fail; + i += l; + if (alloc && i > k - 4) { + k += k + 1; + char* tmp = realloc(s, k); + if (!tmp) goto alloc_fail; + s = tmp; + } + } + pos++; + width -= (width > 0); + gotmatch = 1; + } + if (width) { + ungetwc(c, f); + if (t == 'c' || !gotmatch) goto match_fail; + } + + if (alloc) { + if (size == SIZE_l) + *(wchar_t**)dest = wcs; + else + *(char**)dest = s; + } + if (t != 'c') { + if (wcs) wcs[i] = 0; + if (s) s[i] = 0; + } + break; + + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'a': + case 'e': + case 'f': + case 'g': + case 'A': + case 'E': + case 'F': + case 'G': + case 'X': + case 'p': + if (width < 1) width = 0; + snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln", 1 + !dest, "%*", width, + size_pfx[size + 2], t); + cnt = 0; + if (fscanf(f, tmp, dest ? dest : &cnt, &cnt) == -1) + goto input_fail; + else if (!cnt) + goto match_fail; + pos += cnt; + break; + default: + goto fmt_fail; + } + + if (dest) matches++; + } + if (0) { + fmt_fail: + alloc_fail: + input_fail: + if (!matches) matches--; + match_fail: + if (alloc) { + free(s); + free(wcs); + } + } + FUNLOCK(f); + return matches; +} + +weak_alias(vfwscanf, __isoc99_vfwscanf); diff --git a/third_party/ulib/musl/src/stdio/vprintf.c b/third_party/ulib/musl/src/stdio/vprintf.c new file mode 100644 index 000000000..d8727c1fa --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vprintf.c @@ -0,0 +1,5 @@ +#include + +int vprintf(const char* restrict fmt, va_list ap) { + return vfprintf(stdout, fmt, ap); +} diff --git a/third_party/ulib/musl/src/stdio/vscanf.c b/third_party/ulib/musl/src/stdio/vscanf.c new file mode 100644 index 000000000..bf1afdf35 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vscanf.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include +#include + +int vscanf(const char* restrict fmt, va_list ap) { + return vfscanf(stdin, fmt, ap); +} + +weak_alias(vscanf, __isoc99_vscanf); diff --git a/third_party/ulib/musl/src/stdio/vsnprintf.c b/third_party/ulib/musl/src/stdio/vsnprintf.c new file mode 100644 index 000000000..f9531b395 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vsnprintf.c @@ -0,0 +1,40 @@ +#include "stdio_impl.h" +#include +#include +#include +#include + +static size_t sn_write(FILE* f, const unsigned char* s, size_t l) { + size_t k = f->wend - f->wpos; + if (k > l) k = l; + memcpy(f->wpos, s, k); + f->wpos += k; + /* pretend to succeed, but discard extra data */ + return l; +} + +int vsnprintf(char* restrict s, size_t n, const char* restrict fmt, va_list ap) { + int r; + char b; + FILE f = {.lbf = EOF, .write = sn_write, .lock = -1}; + + if (n - 1 > INT_MAX - 1) { + if (n) { + errno = EOVERFLOW; + return -1; + } + s = &b; + n = 1; + } + + /* Ensure pointers don't wrap if "infinite" n is passed in */ + if (n > (char*)0 + SIZE_MAX - s - 1) n = (char*)0 + SIZE_MAX - s - 1; + f.buf_size = n; + f.buf = f.wpos = (void*)s; + f.wbase = f.wend = (void*)(s + n); + r = vfprintf(&f, fmt, ap); + + /* Null-terminate, overwriting last char if dest buffer is full */ + if (n) f.wpos[-(f.wpos == f.wend)] = 0; + return r; +} diff --git a/third_party/ulib/musl/src/stdio/vsprintf.c b/third_party/ulib/musl/src/stdio/vsprintf.c new file mode 100644 index 000000000..5225c1dad --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vsprintf.c @@ -0,0 +1,6 @@ +#include +#include + +int vsprintf(char* restrict s, const char* restrict fmt, va_list ap) { + return vsnprintf(s, INT_MAX, fmt, ap); +} diff --git a/third_party/ulib/musl/src/stdio/vsscanf.c b/third_party/ulib/musl/src/stdio/vsscanf.c new file mode 100644 index 000000000..45a63c695 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vsscanf.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include "stdio_impl.h" + +static size_t do_read(FILE* f, unsigned char* buf, size_t len) { + return __string_read(f, buf, len); +} + +int vsscanf(const char* restrict s, const char* restrict fmt, va_list ap) { + FILE f = {.buf = (void*)s, .cookie = (void*)s, .read = do_read, .lock = -1}; + return vfscanf(&f, fmt, ap); +} + +weak_alias(vsscanf, __isoc99_vsscanf); diff --git a/third_party/ulib/musl/src/stdio/vswprintf.c b/third_party/ulib/musl/src/stdio/vswprintf.c new file mode 100644 index 000000000..d3f7d529a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vswprintf.c @@ -0,0 +1,50 @@ +#include "stdio_impl.h" +#include +#include +#include +#include +#include + +struct cookie { + wchar_t* ws; + size_t l; +}; + +static size_t sw_write(FILE* f, const unsigned char* s, size_t l) { + size_t l0 = l; + int i = 0; + struct cookie* c = f->cookie; + if (s != f->wbase && sw_write(f, f->wbase, f->wpos - f->wbase) == -1) return -1; + while (c->l && l && (i = mbtowc(c->ws, (void*)s, l)) >= 0) { + s += i; + l -= i; + c->l--; + c->ws++; + } + *c->ws = 0; + return i < 0 ? i : l0; +} + +int vswprintf(wchar_t* restrict s, size_t n, const wchar_t* restrict fmt, va_list ap) { + int r; + FILE f; + unsigned char buf[256]; + struct cookie c = {s, n - 1}; + + memset(&f, 0, sizeof(FILE)); + f.lbf = EOF; + f.write = sw_write; + f.buf_size = sizeof buf; + f.buf = buf; + f.lock = -1; + f.cookie = &c; + if (!n) { + return -1; + } else if (n > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + r = vfwprintf(&f, fmt, ap); + sw_write(&f, 0, 0); + return r >= n ? -1 : r; +} diff --git a/third_party/ulib/musl/src/stdio/vswscanf.c b/third_party/ulib/musl/src/stdio/vswscanf.c new file mode 100644 index 000000000..6e6c83bae --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vswscanf.c @@ -0,0 +1,34 @@ +#include "libc.h" +#include "stdio_impl.h" +#include + +static size_t wstring_read(FILE* f, unsigned char* buf, size_t len) { + const wchar_t* src = f->cookie; + size_t k; + + if (!src) return 0; + + k = wcsrtombs((void*)f->buf, &src, f->buf_size, 0); + if (k == (size_t)-1) { + f->rpos = f->rend = 0; + return 0; + } + + f->rpos = f->buf; + f->rend = f->buf + k; + f->cookie = (void*)src; + + if (!len || !k) return 0; + + *buf = *f->rpos++; + return 1; +} + +int vswscanf(const wchar_t* restrict s, const wchar_t* restrict fmt, va_list ap) { + unsigned char buf[256]; + FILE f = { + .buf = buf, .buf_size = sizeof buf, .cookie = (void*)s, .read = wstring_read, .lock = -1}; + return vfwscanf(&f, fmt, ap); +} + +weak_alias(vswscanf, __isoc99_vswscanf); diff --git a/third_party/ulib/musl/src/stdio/vwprintf.c b/third_party/ulib/musl/src/stdio/vwprintf.c new file mode 100644 index 000000000..833b88335 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vwprintf.c @@ -0,0 +1,6 @@ +#include +#include + +int vwprintf(const wchar_t* restrict fmt, va_list ap) { + return vfwprintf(stdout, fmt, ap); +} diff --git a/third_party/ulib/musl/src/stdio/vwscanf.c b/third_party/ulib/musl/src/stdio/vwscanf.c new file mode 100644 index 000000000..43b68c95b --- /dev/null +++ b/third_party/ulib/musl/src/stdio/vwscanf.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include +#include +#include + +int vwscanf(const wchar_t* restrict fmt, va_list ap) { + return vfwscanf(stdin, fmt, ap); +} + +weak_alias(vwscanf, __isoc99_vwscanf); diff --git a/third_party/ulib/musl/src/stdio/wprintf.c b/third_party/ulib/musl/src/stdio/wprintf.c new file mode 100644 index 000000000..176a8267a --- /dev/null +++ b/third_party/ulib/musl/src/stdio/wprintf.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int wprintf(const wchar_t* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vwprintf(fmt, ap); + va_end(ap); + return ret; +} diff --git a/third_party/ulib/musl/src/stdio/wscanf.c b/third_party/ulib/musl/src/stdio/wscanf.c new file mode 100644 index 000000000..ef2e42b49 --- /dev/null +++ b/third_party/ulib/musl/src/stdio/wscanf.c @@ -0,0 +1,15 @@ +#include "libc.h" +#include +#include +#include + +int wscanf(const wchar_t* restrict fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vwscanf(fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(wscanf, __isoc99_wscanf); diff --git a/third_party/ulib/musl/src/stdlib/BUILD.gn b/third_party/ulib/musl/src/stdlib/BUILD.gn new file mode 100644 index 000000000..1511d885d --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/BUILD.gn @@ -0,0 +1,28 @@ +source_set("stdlib") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "abs.c", + "atof.c", + "atoi.c", + "atol.c", + "atoll.c", + "bsearch.c", + "div.c", + "ecvt.c", + "fcvt.c", + "gcvt.c", + "imaxabs.c", + "imaxdiv.c", + "labs.c", + "ldiv.c", + "llabs.c", + "lldiv.c", + "strtod.c", + "strtol.c", + "wcstod.c", + "wcstol.c", + ] +} diff --git a/third_party/ulib/musl/src/stdlib/abs.c b/third_party/ulib/musl/src/stdlib/abs.c new file mode 100644 index 000000000..edc9cffcb --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/abs.c @@ -0,0 +1,3 @@ +int abs(int a) { + return a > 0 ? a : -a; +} diff --git a/third_party/ulib/musl/src/stdlib/atof.c b/third_party/ulib/musl/src/stdlib/atof.c new file mode 100644 index 000000000..e99a001ec --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/atof.c @@ -0,0 +1,5 @@ +#include + +double atof(const char* s) { + return strtod(s, 0); +} diff --git a/third_party/ulib/musl/src/stdlib/atoi.c b/third_party/ulib/musl/src/stdlib/atoi.c new file mode 100644 index 000000000..acc452558 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/atoi.c @@ -0,0 +1,18 @@ +#include +#include + +int atoi(const char* s) { + int n = 0, neg = 0; + while (isspace(*s)) + s++; + switch (*s) { + case '-': + neg = 1; + case '+': + s++; + } + /* Compute n as a negative number to avoid overflow on INT_MIN */ + while (isdigit(*s)) + n = 10 * n - (*s++ - '0'); + return neg ? n : -n; +} diff --git a/third_party/ulib/musl/src/stdlib/atol.c b/third_party/ulib/musl/src/stdlib/atol.c new file mode 100644 index 000000000..619f264ba --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/atol.c @@ -0,0 +1,19 @@ +#include +#include + +long atol(const char* s) { + long n = 0; + int neg = 0; + while (isspace(*s)) + s++; + switch (*s) { + case '-': + neg = 1; + case '+': + s++; + } + /* Compute n as a negative number to avoid overflow on LONG_MIN */ + while (isdigit(*s)) + n = 10 * n - (*s++ - '0'); + return neg ? n : -n; +} diff --git a/third_party/ulib/musl/src/stdlib/atoll.c b/third_party/ulib/musl/src/stdlib/atoll.c new file mode 100644 index 000000000..33c82b31b --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/atoll.c @@ -0,0 +1,19 @@ +#include +#include + +long long atoll(const char* s) { + long long n = 0; + int neg = 0; + while (isspace(*s)) + s++; + switch (*s) { + case '-': + neg = 1; + case '+': + s++; + } + /* Compute n as a negative number to avoid overflow on LLONG_MIN */ + while (isdigit(*s)) + n = 10 * n - (*s++ - '0'); + return neg ? n : -n; +} diff --git a/third_party/ulib/musl/src/stdlib/bsearch.c b/third_party/ulib/musl/src/stdlib/bsearch.c new file mode 100644 index 000000000..9cfbbe49e --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/bsearch.c @@ -0,0 +1,25 @@ +#include + +void* bsearch(const void* key, const void* base, size_t nel, size_t width, + int (*cmp)(const void*, const void*)) { + void* try + ; + int sign; + while (nel > 0) { + try + = (char*)base + width * (nel / 2); + sign = cmp(key, try); + if (!sign) return try + ; + else if (nel == 1) + break; + else if (sign < 0) + nel /= 2; + else { + base = try + ; + nel -= nel / 2; + } + } + return NULL; +} diff --git a/third_party/ulib/musl/src/stdlib/div.c b/third_party/ulib/musl/src/stdlib/div.c new file mode 100644 index 000000000..399dd0cfa --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/div.c @@ -0,0 +1,5 @@ +#include + +div_t div(int num, int den) { + return (div_t){num / den, num % den}; +} diff --git a/third_party/ulib/musl/src/stdlib/ecvt.c b/third_party/ulib/musl/src/stdlib/ecvt.c new file mode 100644 index 000000000..3d776f923 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/ecvt.c @@ -0,0 +1,19 @@ +#define _GNU_SOURCE +#include +#include + +char* ecvt(double x, int n, int* dp, int* sign) { + static char buf[16]; + char tmp[32]; + int i, j; + + if (n - 1U > 15) n = 15; + sprintf(tmp, "%.*e", n - 1, x); + i = *sign = (tmp[0] == '-'); + for (j = 0; tmp[i] != 'e'; j += (tmp[i++] != '.')) + buf[j] = tmp[i]; + buf[j] = 0; + *dp = atoi(tmp + i + 1) + 1; + + return buf; +} diff --git a/third_party/ulib/musl/src/stdlib/fcvt.c b/third_party/ulib/musl/src/stdlib/fcvt.c new file mode 100644 index 000000000..73c0032b9 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/fcvt.c @@ -0,0 +1,26 @@ +#define _GNU_SOURCE +#include +#include +#include + +char* fcvt(double x, int n, int* dp, int* sign) { + char tmp[1500]; + int i, lz; + + if (n > 1400U) n = 1400; + sprintf(tmp, "%.*f", n, x); + i = (tmp[0] == '-'); + if (tmp[i] == '0') + lz = strspn(tmp + i + 2, "0"); + else + lz = -(int)strcspn(tmp + i, "."); + + if (n <= lz) { + *sign = i; + *dp = 1; + if (n > 14U) n = 14; + return "000000000000000" + 14 - n; + } + + return ecvt(x, n - lz, dp, sign); +} diff --git a/third_party/ulib/musl/src/stdlib/gcvt.c b/third_party/ulib/musl/src/stdlib/gcvt.c new file mode 100644 index 000000000..537d47a3b --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/gcvt.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include +#include + +char* gcvt(double x, int n, char* b) { + sprintf(b, "%.*g", n, x); + return b; +} diff --git a/third_party/ulib/musl/src/stdlib/imaxabs.c b/third_party/ulib/musl/src/stdlib/imaxabs.c new file mode 100644 index 000000000..a2e1833db --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/imaxabs.c @@ -0,0 +1,5 @@ +#include + +intmax_t imaxabs(intmax_t a) { + return a > 0 ? a : -a; +} diff --git a/third_party/ulib/musl/src/stdlib/imaxdiv.c b/third_party/ulib/musl/src/stdlib/imaxdiv.c new file mode 100644 index 000000000..362a1a714 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/imaxdiv.c @@ -0,0 +1,5 @@ +#include + +imaxdiv_t imaxdiv(intmax_t num, intmax_t den) { + return (imaxdiv_t){num / den, num % den}; +} diff --git a/third_party/ulib/musl/src/stdlib/labs.c b/third_party/ulib/musl/src/stdlib/labs.c new file mode 100644 index 000000000..75a2427b3 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/labs.c @@ -0,0 +1,3 @@ +long labs(long a) { + return a > 0 ? a : -a; +} diff --git a/third_party/ulib/musl/src/stdlib/ldiv.c b/third_party/ulib/musl/src/stdlib/ldiv.c new file mode 100644 index 000000000..5da2fc633 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/ldiv.c @@ -0,0 +1,5 @@ +#include + +ldiv_t ldiv(long num, long den) { + return (ldiv_t){num / den, num % den}; +} diff --git a/third_party/ulib/musl/src/stdlib/llabs.c b/third_party/ulib/musl/src/stdlib/llabs.c new file mode 100644 index 000000000..2fb713d6d --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/llabs.c @@ -0,0 +1,3 @@ +long long llabs(long long a) { + return a > 0 ? a : -a; +} diff --git a/third_party/ulib/musl/src/stdlib/lldiv.c b/third_party/ulib/musl/src/stdlib/lldiv.c new file mode 100644 index 000000000..1d2402f7a --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/lldiv.c @@ -0,0 +1,5 @@ +#include + +lldiv_t lldiv(long long num, long long den) { + return (lldiv_t){num / den, num % den}; +} diff --git a/third_party/ulib/musl/src/stdlib/strtod.c b/third_party/ulib/musl/src/stdlib/strtod.c new file mode 100644 index 000000000..6522ecca5 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/strtod.c @@ -0,0 +1,33 @@ +#include "floatscan.h" +#include "libc.h" +#include "shgetc.h" +#include "stdio_impl.h" +#include + +static long double strtox(const char* s, char** p, int prec) { + FILE f = {.buf = (void*)s, .rpos = (void*)s, .rend = (void*)-1, .lock = -1}; + shlim(&f, 0); + long double y = __floatscan(&f, prec, 1); + off_t cnt = shcnt(&f); + if (p) *p = cnt ? (char*)s + cnt : (char*)s; + return y; +} + +float strtof(const char* restrict s, char** restrict p) { + return strtox(s, p, 0); +} + +double strtod(const char* restrict s, char** restrict p) { + return strtox(s, p, 1); +} + +long double strtold(const char* restrict s, char** restrict p) { + return strtox(s, p, 2); +} + +weak_alias(strtof, strtof_l); +weak_alias(strtod, strtod_l); +weak_alias(strtold, strtold_l); +weak_alias(strtof, __strtof_l); +weak_alias(strtod, __strtod_l); +weak_alias(strtold, __strtold_l); diff --git a/third_party/ulib/musl/src/stdlib/strtol.c b/third_party/ulib/musl/src/stdlib/strtol.c new file mode 100644 index 000000000..6aa71380d --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/strtol.c @@ -0,0 +1,57 @@ +#include "intscan.h" +#include "libc.h" +#include "shgetc.h" +#include "stdio_impl.h" +#include +#include +#include + +static unsigned long long strtox(const char* s, char** p, int base, unsigned long long lim) { + /* FIXME: use a helper function or macro to setup the FILE */ + FILE f; + f.flags = 0; + f.buf = f.rpos = (void*)s; + if ((size_t)s > (size_t)-1 / 2) + f.rend = (void*)-1; + else + f.rend = (unsigned char*)s + (size_t)-1 / 2; + f.lock = -1; + shlim(&f, 0); + unsigned long long y = __intscan(&f, base, 1, lim); + if (p) { + size_t cnt = shcnt(&f); + *p = (char*)s + cnt; + } + return y; +} + +unsigned long long strtoull(const char* restrict s, char** restrict p, int base) { + return strtox(s, p, base, ULLONG_MAX); +} + +long long strtoll(const char* restrict s, char** restrict p, int base) { + return strtox(s, p, base, LLONG_MIN); +} + +unsigned long strtoul(const char* restrict s, char** restrict p, int base) { + return strtox(s, p, base, ULONG_MAX); +} + +long strtol(const char* restrict s, char** restrict p, int base) { + return strtox(s, p, base, 0UL + LONG_MIN); +} + +intmax_t strtoimax(const char* restrict s, char** restrict p, int base) { + return strtoll(s, p, base); +} + +uintmax_t strtoumax(const char* restrict s, char** restrict p, int base) { + return strtoull(s, p, base); +} + +weak_alias(strtol, __strtol_internal); +weak_alias(strtoul, __strtoul_internal); +weak_alias(strtoll, __strtoll_internal); +weak_alias(strtoull, __strtoull_internal); +weak_alias(strtoimax, __strtoimax_internal); +weak_alias(strtoumax, __strtoumax_internal); diff --git a/third_party/ulib/musl/src/stdlib/wcstod.c b/third_party/ulib/musl/src/stdlib/wcstod.c new file mode 100644 index 000000000..2df2e2557 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/wcstod.c @@ -0,0 +1,61 @@ +#include "floatscan.h" +#include "shgetc.h" +#include "stdio_impl.h" +#include +#include + +/* This read function heavily cheats. It knows: + * (1) len will always be 1 + * (2) non-ascii characters don't matter */ + +static size_t do_read(FILE* f, unsigned char* buf, size_t len) { + size_t i; + const wchar_t* wcs = f->cookie; + + if (!wcs[0]) wcs = L"@"; + for (i = 0; i < f->buf_size && wcs[i]; i++) + f->buf[i] = wcs[i] < 128 ? wcs[i] : '@'; + f->rpos = f->buf; + f->rend = f->buf + i; + f->cookie = (void*)(wcs + i); + + if (i && len) { + *buf = *f->rpos++; + return 1; + } + return 0; +} + +static long double wcstox(const wchar_t* s, wchar_t** p, int prec) { + wchar_t* t = (wchar_t*)s; + unsigned char buf[64]; + FILE f = {0}; + f.flags = 0; + f.rpos = f.rend = 0; + f.buf = buf + 4; + f.buf_size = sizeof buf - 4; + f.lock = -1; + f.read = do_read; + while (iswspace(*t)) + t++; + f.cookie = (void*)t; + shlim(&f, 0); + long double y = __floatscan(&f, prec, 1); + if (p) { + size_t cnt = shcnt(&f); + *p = cnt ? t + cnt : (wchar_t*)s; + } + return y; +} + +float wcstof(const wchar_t* restrict s, wchar_t** restrict p) { + return wcstox(s, p, 0); +} + +double wcstod(const wchar_t* restrict s, wchar_t** restrict p) { + return wcstox(s, p, 1); +} + +long double wcstold(const wchar_t* restrict s, wchar_t** restrict p) { + return wcstox(s, p, 2); +} diff --git a/third_party/ulib/musl/src/stdlib/wcstol.c b/third_party/ulib/musl/src/stdlib/wcstol.c new file mode 100644 index 000000000..f4316d096 --- /dev/null +++ b/third_party/ulib/musl/src/stdlib/wcstol.c @@ -0,0 +1,75 @@ +#include "intscan.h" +#include "shgetc.h" +#include "stdio_impl.h" +#include +#include +#include +#include + +/* This read function heavily cheats. It knows: + * (1) len will always be 1 + * (2) non-ascii characters don't matter */ + +static size_t do_read(FILE* f, unsigned char* buf, size_t len) { + size_t i; + const wchar_t* wcs = f->cookie; + + if (!wcs[0]) wcs = L"@"; + for (i = 0; i < f->buf_size && wcs[i]; i++) + f->buf[i] = wcs[i] < 128 ? wcs[i] : '@'; + f->rpos = f->buf; + f->rend = f->buf + i; + f->cookie = (void*)(wcs + i); + + if (i && len) { + *buf = *f->rpos++; + return 1; + } + return 0; +} + +static unsigned long long wcstox(const wchar_t* s, wchar_t** p, int base, unsigned long long lim) { + wchar_t* t = (wchar_t*)s; + unsigned char buf[64]; + FILE f = {0}; + f.flags = 0; + f.rpos = f.rend = 0; + f.buf = buf + 4; + f.buf_size = sizeof buf - 4; + f.lock = -1; + f.read = do_read; + while (iswspace(*t)) + t++; + f.cookie = (void*)t; + shlim(&f, 0); + unsigned long long y = __intscan(&f, base, 1, lim); + if (p) { + size_t cnt = shcnt(&f); + *p = cnt ? t + cnt : (wchar_t*)s; + } + return y; +} + +unsigned long long wcstoull(const wchar_t* restrict s, wchar_t** restrict p, int base) { + return wcstox(s, p, base, ULLONG_MAX); +} + +long long wcstoll(const wchar_t* restrict s, wchar_t** restrict p, int base) { + return wcstox(s, p, base, LLONG_MIN); +} + +unsigned long wcstoul(const wchar_t* restrict s, wchar_t** restrict p, int base) { + return wcstox(s, p, base, ULONG_MAX); +} + +long wcstol(const wchar_t* restrict s, wchar_t** restrict p, int base) { + return wcstox(s, p, base, 0UL + LONG_MIN); +} + +intmax_t wcstoimax(const wchar_t* restrict s, wchar_t** restrict p, int base) { + return wcstoll(s, p, base); +} + +uintmax_t wcstoumax(const wchar_t* restrict s, wchar_t** restrict p, int base) { + return wcstoull(s, p, base); +} diff --git a/third_party/ulib/musl/src/string/BUILD.gn b/third_party/ulib/musl/src/string/BUILD.gn new file mode 100644 index 000000000..02ae8e516 --- /dev/null +++ b/third_party/ulib/musl/src/string/BUILD.gn @@ -0,0 +1,118 @@ +source_set("string") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "bcmp.c", + "bcopy.c", + "bzero.c", + "index.c", + "memccpy.c", + "memchr.c", + "memcmp.c", + "memmem.c", + "mempcpy.c", + "memrchr.c", + "rindex.c", + "stpcpy.c", + "stpncpy.c", + "strcasecmp.c", + "strcasestr.c", + "strcat.c", + "strchr.c", + "strchrnul.c", + "strcmp.c", + "strcpy.c", + "strcspn.c", + "strdup.c", + "strerror_r.c", + "strlcat.c", + "strlcpy.c", + "strlen.c", + "strncasecmp.c", + "strncat.c", + "strncmp.c", + "strncpy.c", + "strndup.c", + "strnlen.c", + "strpbrk.c", + "strrchr.c", + "strsep.c", + "strsignal.c", + "strspn.c", + "strstr.c", + "strtok.c", + "strtok_r.c", + "strverscmp.c", + "swab.c", + "wcpcpy.c", + "wcpncpy.c", + "wcscasecmp.c", + "wcscasecmp_l.c", + "wcscat.c", + "wcschr.c", + "wcscmp.c", + "wcscpy.c", + "wcscspn.c", + "wcsdup.c", + "wcslen.c", + "wcsncasecmp.c", + "wcsncasecmp_l.c", + "wcsncat.c", + "wcsncmp.c", + "wcsncpy.c", + "wcsnlen.c", + "wcspbrk.c", + "wcsrchr.c", + "wcsspn.c", + "wcsstr.c", + "wcstok.c", + "wcswcs.c", + "wmemchr.c", + "wmemcmp.c", + "wmemcpy.c", + "wmemmove.c", + "wmemset.c", + ] + if (target_cpu == "arm") { + sources += [ + "arm/memcpy_le.S", + "memmove.c", + "memset.c", + ] + } else if (target_cpu == "arm64") { + sources += [ + "memcpy.c", + "memmove.c", + "memset.c", + ] + } else if (target_cpu == "x64") { + sources += [ + "x86_64/memcpy.s", + "x86_64/memmove.s", + "x86_64/memset.s", + ] + } else { + sources += [ "memmove.c" ] + deps = [ + ":string_no_stack_protector", + ] + } +} + +if (target_cpu != "arm" && target_cpu != "arm64" && target_cpu != "x64") { + source_set("string_no_stack_protector") { + visibility = [ ":string" ] + configs = [] + configs += [ + # Use relative path to make the build relocatable + "../..:musl_config", + "//gnbuild:no_stack_protector", + ] + sources = [ + "memcpy.c", + "memset.c", + ] + } +} diff --git a/third_party/ulib/musl/src/string/arm/__aeabi_memclr.c b/third_party/ulib/musl/src/string/arm/__aeabi_memclr.c new file mode 100644 index 000000000..5e0779d06 --- /dev/null +++ b/third_party/ulib/musl/src/string/arm/__aeabi_memclr.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include + +void __aeabi_memclr(void* dest, size_t n) { + memset(dest, 0, n); +} +weak_alias(__aeabi_memclr, __aeabi_memclr4); +weak_alias(__aeabi_memclr, __aeabi_memclr8); diff --git a/third_party/ulib/musl/src/string/arm/__aeabi_memcpy.c b/third_party/ulib/musl/src/string/arm/__aeabi_memcpy.c new file mode 100644 index 000000000..fa344a4d8 --- /dev/null +++ b/third_party/ulib/musl/src/string/arm/__aeabi_memcpy.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include + +void __aeabi_memcpy(void* restrict dest, const void* restrict src, size_t n) { + memcpy(dest, src, n); +} +weak_alias(__aeabi_memcpy, __aeabi_memcpy4); +weak_alias(__aeabi_memcpy, __aeabi_memcpy8); diff --git a/third_party/ulib/musl/src/string/arm/__aeabi_memmove.c b/third_party/ulib/musl/src/string/arm/__aeabi_memmove.c new file mode 100644 index 000000000..83dfa4c3c --- /dev/null +++ b/third_party/ulib/musl/src/string/arm/__aeabi_memmove.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include + +void __aeabi_memmove(void* dest, const void* src, size_t n) { + memmove(dest, src, n); +} +weak_alias(__aeabi_memmove, __aeabi_memmove4); +weak_alias(__aeabi_memmove, __aeabi_memmove8); diff --git a/third_party/ulib/musl/src/string/arm/__aeabi_memset.c b/third_party/ulib/musl/src/string/arm/__aeabi_memset.c new file mode 100644 index 000000000..d6bf5c9a9 --- /dev/null +++ b/third_party/ulib/musl/src/string/arm/__aeabi_memset.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include + +void __aeabi_memset(void* dest, size_t n, int c) { + memset(dest, c, n); +} +weak_alias(__aeabi_memset, __aeabi_memset4); +weak_alias(__aeabi_memset, __aeabi_memset8); diff --git a/third_party/ulib/musl/src/string/arm/memcpy.c b/third_party/ulib/musl/src/string/arm/memcpy.c new file mode 100644 index 000000000..041614f4b --- /dev/null +++ b/third_party/ulib/musl/src/string/arm/memcpy.c @@ -0,0 +1,3 @@ +#if __ARMEB__ +#include "../memcpy.c" +#endif diff --git a/third_party/ulib/musl/src/string/bcmp.c b/third_party/ulib/musl/src/string/bcmp.c new file mode 100644 index 000000000..b1bddf267 --- /dev/null +++ b/third_party/ulib/musl/src/string/bcmp.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include +#include + +int bcmp(const void* s1, const void* s2, size_t n) { + return memcmp(s1, s2, n); +} diff --git a/third_party/ulib/musl/src/string/bcopy.c b/third_party/ulib/musl/src/string/bcopy.c new file mode 100644 index 000000000..0298a9618 --- /dev/null +++ b/third_party/ulib/musl/src/string/bcopy.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include +#include + +void bcopy(const void* s1, void* s2, size_t n) { + memmove(s2, s1, n); +} diff --git a/third_party/ulib/musl/src/string/bzero.c b/third_party/ulib/musl/src/string/bzero.c new file mode 100644 index 000000000..c402da85b --- /dev/null +++ b/third_party/ulib/musl/src/string/bzero.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include +#include + +void bzero(void* s, size_t n) { + memset(s, 0, n); +} diff --git a/third_party/ulib/musl/src/string/index.c b/third_party/ulib/musl/src/string/index.c new file mode 100644 index 000000000..92779ba8e --- /dev/null +++ b/third_party/ulib/musl/src/string/index.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include +#include + +char* index(const char* s, int c) { + return strchr(s, c); +} diff --git a/third_party/ulib/musl/src/string/memccpy.c b/third_party/ulib/musl/src/string/memccpy.c new file mode 100644 index 000000000..09fd62f19 --- /dev/null +++ b/third_party/ulib/musl/src/string/memccpy.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t) - 1) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +void* memccpy(void* restrict dest, const void* restrict src, int c, size_t n) { + unsigned char* d = dest; + const unsigned char* s = src; + size_t *wd, k; + const size_t* ws; + + c = (unsigned char)c; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d = *s) != c; n--, s++, d++) + ; + if ((uintptr_t)s & ALIGN) goto tail; + k = ONES * c; + wd = (void*)d; + ws = (const void*)s; + for (; n >= sizeof(size_t) && !HASZERO(*ws ^ k); n -= sizeof(size_t), ws++, wd++) + *wd = *ws; + d = (void*)wd; + s = (const void*)ws; + } + for (; n && (*d = *s) != c; n--, s++, d++) + ; +tail: + if (*s == c) return d + 1; + return 0; +} diff --git a/third_party/ulib/musl/src/string/memchr.c b/third_party/ulib/musl/src/string/memchr.c new file mode 100644 index 000000000..ad4649efb --- /dev/null +++ b/third_party/ulib/musl/src/string/memchr.c @@ -0,0 +1,25 @@ +#include +#include +#include + +#define SS (sizeof(size_t)) +#define ALIGN (sizeof(size_t) - 1) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +void* memchr(const void* src, int c, size_t n) { + const unsigned char* s = src; + c = (unsigned char)c; + for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--) + ; + if (n && *s != c) { + const size_t* w; + size_t k = ONES * c; + for (w = (const void*)s; n >= SS && !HASZERO(*w ^ k); w++, n -= SS) + ; + for (s = (const void*)w; n && *s != c; s++, n--) + ; + } + return n ? (void*)s : 0; +} diff --git a/third_party/ulib/musl/src/string/memcmp.c b/third_party/ulib/musl/src/string/memcmp.c new file mode 100644 index 000000000..7573a5828 --- /dev/null +++ b/third_party/ulib/musl/src/string/memcmp.c @@ -0,0 +1,8 @@ +#include + +int memcmp(const void* vl, const void* vr, size_t n) { + const unsigned char *l = vl, *r = vr; + for (; n && *l == *r; n--, l++, r++) + ; + return n ? *l - *r : 0; +} diff --git a/third_party/ulib/musl/src/string/memcpy.c b/third_party/ulib/musl/src/string/memcpy.c new file mode 100644 index 000000000..53f5cb102 --- /dev/null +++ b/third_party/ulib/musl/src/string/memcpy.c @@ -0,0 +1,150 @@ +#include +#include +#include + +void* memcpy(void* restrict dest, const void* restrict src, size_t n) { + unsigned char* d = dest; + const unsigned char* s = src; + +#ifdef __GNUC__ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LS >> +#define RS << +#else +#define LS << +#define RS >> +#endif + + typedef uint32_t __attribute__((__may_alias__)) u32; + uint32_t w, x; + + for (; (uintptr_t)s % 4 && n; n--) + *d++ = *s++; + + if ((uintptr_t)d % 4 == 0) { + for (; n >= 16; s += 16, d += 16, n -= 16) { + *(u32*)(d + 0) = *(u32*)(s + 0); + *(u32*)(d + 4) = *(u32*)(s + 4); + *(u32*)(d + 8) = *(u32*)(s + 8); + *(u32*)(d + 12) = *(u32*)(s + 12); + } + if (n & 8) { + *(u32*)(d + 0) = *(u32*)(s + 0); + *(u32*)(d + 4) = *(u32*)(s + 4); + d += 8; + s += 8; + } + if (n & 4) { + *(u32*)(d + 0) = *(u32*)(s + 0); + d += 4; + s += 4; + } + if (n & 2) { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) { + *d = *s; + } + return dest; + } + + if (n >= 32) switch ((uintptr_t)d % 4) { + case 1: + w = *(u32*)s; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + n -= 3; + for (; n >= 17; s += 16, d += 16, n -= 16) { + x = *(u32*)(s + 1); + *(u32*)(d + 0) = (w LS 24) | (x RS 8); + w = *(u32*)(s + 5); + *(u32*)(d + 4) = (x LS 24) | (w RS 8); + x = *(u32*)(s + 9); + *(u32*)(d + 8) = (w LS 24) | (x RS 8); + w = *(u32*)(s + 13); + *(u32*)(d + 12) = (x LS 24) | (w RS 8); + } + break; + case 2: + w = *(u32*)s; + *d++ = *s++; + *d++ = *s++; + n -= 2; + for (; n >= 18; s += 16, d += 16, n -= 16) { + x = *(u32*)(s + 2); + *(u32*)(d + 0) = (w LS 16) | (x RS 16); + w = *(u32*)(s + 6); + *(u32*)(d + 4) = (x LS 16) | (w RS 16); + x = *(u32*)(s + 10); + *(u32*)(d + 8) = (w LS 16) | (x RS 16); + w = *(u32*)(s + 14); + *(u32*)(d + 12) = (x LS 16) | (w RS 16); + } + break; + case 3: + w = *(u32*)s; + *d++ = *s++; + n -= 1; + for (; n >= 19; s += 16, d += 16, n -= 16) { + x = *(u32*)(s + 3); + *(u32*)(d + 0) = (w LS 8) | (x RS 24); + w = *(u32*)(s + 7); + *(u32*)(d + 4) = (x LS 8) | (w RS 24); + x = *(u32*)(s + 11); + *(u32*)(d + 8) = (w LS 8) | (x RS 24); + w = *(u32*)(s + 15); + *(u32*)(d + 12) = (x LS 8) | (w RS 24); + } + break; + } + if (n & 16) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 8) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 4) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if (n & 2) { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) { + *d = *s; + } + return dest; +#endif + + for (; n; n--) + *d++ = *s++; + return dest; +} diff --git a/third_party/ulib/musl/src/string/memmem.c b/third_party/ulib/musl/src/string/memmem.c new file mode 100644 index 000000000..c66a8e31a --- /dev/null +++ b/third_party/ulib/musl/src/string/memmem.c @@ -0,0 +1,156 @@ +#define _GNU_SOURCE +#include +#include + +static char* twobyte_memmem(const unsigned char* h, size_t k, const unsigned char* n) { + uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; + for (h++, k--; k; k--, hw = hw << 8 | *++h) + if (hw == nw) return (char*)h - 1; + return 0; +} + +static char* threebyte_memmem(const unsigned char* h, size_t k, const unsigned char* n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8; + for (h += 2, k -= 2; k; k--, hw = (hw | *++h) << 8) + if (hw == nw) return (char*)h - 2; + return 0; +} + +static char* fourbyte_memmem(const unsigned char* h, size_t k, const unsigned char* n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + for (h += 3, k -= 3; k; k--, hw = hw << 8 | *++h) + if (hw == nw) return (char*)h - 3; + return 0; +} + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) + +static char* twoway_memmem(const unsigned char* h, const unsigned char* z, const unsigned char* n, + size_t l) { + size_t i, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = {0}; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (i = 0; i < l; i++) + BITOP(byteset, n[i], |=), shift[n[i]] = i + 1; + + /* Compute maximal suffix */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] > n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] < n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip + 1 > ms + 1) + ms = ip; + else + p = p0; + + /* Periodic needle? */ + if (memcmp(n, n + p, ms + 1)) { + mem0 = 0; + p = MAX(ms, l - ms - 1) + 1; + } else + mem0 = l - p; + mem = 0; + + /* Search loop */ + for (;;) { + /* If remainder of haystack is shorter than needle, done */ + if (z - h < l) return 0; + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l - 1], &)) { + k = l - shift[h[l - 1]]; + if (k) { + if (mem0 && mem && k < p) k = l - p; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k = MAX(ms + 1, mem); k < l && n[k] == h[k]; k++) + ; + if (k < l) { + h += k - ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) + ; + if (k <= mem) return (char*)h; + h += p; + mem = mem0; + } +} + +void* memmem(const void* h0, size_t k, const void* n0, size_t l) { + const unsigned char *h = h0, *n = n0; + + /* Return immediately on empty needle */ + if (!l) return (void*)h; + + /* Return immediately when needle is longer than haystack */ + if (k < l) return 0; + + /* Use faster algorithms for short needles */ + h = memchr(h0, *n, k); + if (!h || l == 1) return (void*)h; + k -= h - (const unsigned char*)h0; + if (k < l) return 0; + if (l == 2) return twobyte_memmem(h, k, n); + if (l == 3) return threebyte_memmem(h, k, n); + if (l == 4) return fourbyte_memmem(h, k, n); + + return twoway_memmem(h, h + k, n, l); +} diff --git a/third_party/ulib/musl/src/string/memmove.c b/third_party/ulib/musl/src/string/memmove.c new file mode 100644 index 000000000..446462854 --- /dev/null +++ b/third_party/ulib/musl/src/string/memmove.c @@ -0,0 +1,39 @@ +#include +#include + +#define WT size_t +#define WS (sizeof(WT)) + +void* memmove(void* dest, const void* src, size_t n) { + char* d = dest; + const char* s = src; + + if (d == s) return d; + if (s + n <= d || d + n <= s) return memcpy(d, s, n); + + if (d < s) { + if ((uintptr_t)s % WS == (uintptr_t)d % WS) { + while ((uintptr_t)d % WS) { + if (!n--) return dest; + *d++ = *s++; + } + for (; n >= WS; n -= WS, d += WS, s += WS) + *(WT*)d = *(WT*)s; + } + for (; n; n--) + *d++ = *s++; + } else { + if ((uintptr_t)s % WS == (uintptr_t)d % WS) { + while ((uintptr_t)(d + n) % WS) { + if (!n--) return dest; + d[n] = s[n]; + } + while (n >= WS) + n -= WS, *(WT*)(d + n) = *(WT*)(s + n); + } + while (n) + n--, d[n] = s[n]; + } + + return dest; +} diff --git a/third_party/ulib/musl/src/string/mempcpy.c b/third_party/ulib/musl/src/string/mempcpy.c new file mode 100644 index 000000000..7c701afef --- /dev/null +++ b/third_party/ulib/musl/src/string/mempcpy.c @@ -0,0 +1,6 @@ +#define _GNU_SOURCE +#include + +void* mempcpy(void* dest, const void* src, size_t n) { + return (char*)memcpy(dest, src, n) + n; +} diff --git a/third_party/ulib/musl/src/string/memrchr.c b/third_party/ulib/musl/src/string/memrchr.c new file mode 100644 index 000000000..3245d7330 --- /dev/null +++ b/third_party/ulib/musl/src/string/memrchr.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include + +void* __memrchr(const void* m, int c, size_t n) { + const unsigned char* s = m; + c = (unsigned char)c; + while (n--) + if (s[n] == c) return (void*)(s + n); + return 0; +} + +weak_alias(__memrchr, memrchr); diff --git a/third_party/ulib/musl/src/string/memset.c b/third_party/ulib/musl/src/string/memset.c new file mode 100644 index 000000000..53d3648d2 --- /dev/null +++ b/third_party/ulib/musl/src/string/memset.c @@ -0,0 +1,86 @@ +#include +#include + +void* memset(void* dest, int c, size_t n) { + unsigned char* s = dest; + size_t k; + + /* Fill head and tail with minimal branching. Each + * conditional ensures that all the subsequently used + * offsets are well-defined and in the dest region. */ + + if (!n) return dest; + s[0] = s[n - 1] = c; + if (n <= 2) return dest; + s[1] = s[n - 2] = c; + s[2] = s[n - 3] = c; + if (n <= 6) return dest; + s[3] = s[n - 4] = c; + if (n <= 8) return dest; + + /* Advance pointer to align it at a 4-byte boundary, + * and truncate n to a multiple of 4. The previous code + * already took care of any head/tail that get cut off + * by the alignment. */ + + k = -(uintptr_t)s & 3; + s += k; + n -= k; + n &= -4; + +#ifdef __GNUC__ + typedef uint32_t __attribute__((__may_alias__)) u32; + typedef uint64_t __attribute__((__may_alias__)) u64; + + u32 c32 = ((u32)-1) / 255 * (unsigned char)c; + + /* In preparation to copy 32 bytes at a time, aligned on + * an 8-byte bounary, fill head/tail up to 28 bytes each. + * As in the initial byte-based head/tail fill, each + * conditional below ensures that the subsequent offsets + * are valid (e.g. !(n<=24) implies n>=28). */ + + *(u32*)(s + 0) = c32; + *(u32*)(s + n - 4) = c32; + if (n <= 8) return dest; + *(u32*)(s + 4) = c32; + *(u32*)(s + 8) = c32; + *(u32*)(s + n - 12) = c32; + *(u32*)(s + n - 8) = c32; + if (n <= 24) return dest; + *(u32*)(s + 12) = c32; + *(u32*)(s + 16) = c32; + *(u32*)(s + 20) = c32; + *(u32*)(s + 24) = c32; + *(u32*)(s + n - 28) = c32; + *(u32*)(s + n - 24) = c32; + *(u32*)(s + n - 20) = c32; + *(u32*)(s + n - 16) = c32; + + /* Align to a multiple of 8 so we can fill 64 bits at a time, + * and avoid writing the same bytes twice as much as is + * practical without introducing additional branching. */ + + k = 24 + ((uintptr_t)s & 4); + s += k; + n -= k; + + /* If this loop is reached, 28 tail bytes have already been + * filled, so any remainder when n drops below 32 can be + * safely ignored. */ + + u64 c64 = c32 | ((u64)c32 << 32); + for (; n >= 32; n -= 32, s += 32) { + *(u64*)(s + 0) = c64; + *(u64*)(s + 8) = c64; + *(u64*)(s + 16) = c64; + *(u64*)(s + 24) = c64; + } +#else + /* Pure C fallback with no aliasing violations. */ + for (; n; n--, s++) + *s = c; +#endif + + return dest; +} diff --git a/third_party/ulib/musl/src/string/rindex.c b/third_party/ulib/musl/src/string/rindex.c new file mode 100644 index 000000000..38e019352 --- /dev/null +++ b/third_party/ulib/musl/src/string/rindex.c @@ -0,0 +1,7 @@ +#define _BSD_SOURCE +#include +#include + +char* rindex(const char* s, int c) { + return strrchr(s, c); +} diff --git a/third_party/ulib/musl/src/string/rules.mk b/third_party/ulib/musl/src/string/rules.mk new file mode 100644 index 000000000..24f6437fd --- /dev/null +++ b/third_party/ulib/musl/src/string/rules.mk @@ -0,0 +1,94 @@ +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/bcmp.c \ + $(GET_LOCAL_DIR)/bcopy.c \ + $(GET_LOCAL_DIR)/bzero.c \ + $(GET_LOCAL_DIR)/index.c \ + $(GET_LOCAL_DIR)/memccpy.c \ + $(GET_LOCAL_DIR)/memchr.c \ + $(GET_LOCAL_DIR)/memcmp.c \ + $(GET_LOCAL_DIR)/memmem.c \ + $(GET_LOCAL_DIR)/mempcpy.c \ + $(GET_LOCAL_DIR)/memrchr.c \ + $(GET_LOCAL_DIR)/rindex.c \ + $(GET_LOCAL_DIR)/stpcpy.c \ + $(GET_LOCAL_DIR)/stpncpy.c \ + $(GET_LOCAL_DIR)/strcasecmp.c \ + $(GET_LOCAL_DIR)/strcasestr.c \ + $(GET_LOCAL_DIR)/strcat.c \ + $(GET_LOCAL_DIR)/strchr.c \ + $(GET_LOCAL_DIR)/strchrnul.c \ + $(GET_LOCAL_DIR)/strcmp.c \ + $(GET_LOCAL_DIR)/strcpy.c \ + $(GET_LOCAL_DIR)/strcspn.c \ + $(GET_LOCAL_DIR)/strdup.c \ + $(GET_LOCAL_DIR)/strerror_r.c \ + $(GET_LOCAL_DIR)/strlcat.c \ + $(GET_LOCAL_DIR)/strlcpy.c \ + $(GET_LOCAL_DIR)/strlen.c \ + $(GET_LOCAL_DIR)/strncasecmp.c \ + $(GET_LOCAL_DIR)/strncat.c \ + $(GET_LOCAL_DIR)/strncmp.c \ + $(GET_LOCAL_DIR)/strncpy.c \ + $(GET_LOCAL_DIR)/strndup.c \ + $(GET_LOCAL_DIR)/strnlen.c \ + $(GET_LOCAL_DIR)/strpbrk.c \ + $(GET_LOCAL_DIR)/strrchr.c \ + $(GET_LOCAL_DIR)/strsep.c \ + $(GET_LOCAL_DIR)/strsignal.c \ + $(GET_LOCAL_DIR)/strspn.c \ + $(GET_LOCAL_DIR)/strstr.c \ + $(GET_LOCAL_DIR)/strtok.c \ + $(GET_LOCAL_DIR)/strtok_r.c \ + $(GET_LOCAL_DIR)/strverscmp.c \ + $(GET_LOCAL_DIR)/swab.c \ + $(GET_LOCAL_DIR)/wcpcpy.c \ + $(GET_LOCAL_DIR)/wcpncpy.c \ + $(GET_LOCAL_DIR)/wcscasecmp.c \ + $(GET_LOCAL_DIR)/wcscasecmp_l.c \ + $(GET_LOCAL_DIR)/wcscat.c \ + $(GET_LOCAL_DIR)/wcschr.c \ + $(GET_LOCAL_DIR)/wcscmp.c \ + $(GET_LOCAL_DIR)/wcscpy.c \ + $(GET_LOCAL_DIR)/wcscspn.c \ + $(GET_LOCAL_DIR)/wcsdup.c \ + $(GET_LOCAL_DIR)/wcslen.c \ + $(GET_LOCAL_DIR)/wcsncasecmp.c \ + $(GET_LOCAL_DIR)/wcsncasecmp_l.c \ + $(GET_LOCAL_DIR)/wcsncat.c \ + $(GET_LOCAL_DIR)/wcsncmp.c \ + $(GET_LOCAL_DIR)/wcsncpy.c \ + $(GET_LOCAL_DIR)/wcsnlen.c \ + $(GET_LOCAL_DIR)/wcspbrk.c \ + $(GET_LOCAL_DIR)/wcsrchr.c \ + $(GET_LOCAL_DIR)/wcsspn.c \ + $(GET_LOCAL_DIR)/wcsstr.c \ + $(GET_LOCAL_DIR)/wcstok.c \ + $(GET_LOCAL_DIR)/wcswcs.c \ + $(GET_LOCAL_DIR)/wmemchr.c \ + $(GET_LOCAL_DIR)/wmemcmp.c \ + $(GET_LOCAL_DIR)/wmemcpy.c \ + $(GET_LOCAL_DIR)/wmemmove.c \ + $(GET_LOCAL_DIR)/wmemset.c \ + +ifeq ($(ARCH),arm64) +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/memcpy.c \ + $(GET_LOCAL_DIR)/memmove.c \ + $(GET_LOCAL_DIR)/memset.c \ + +else ifeq ($(ARCH),arm) +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/memcpy.c \ + $(GET_LOCAL_DIR)/memmove.c \ + $(GET_LOCAL_DIR)/memset.c \ + +else ifeq ($(SUBARCH),x86-64) +MODULE_SRCS += \ + $(GET_LOCAL_DIR)/x86_64/memcpy.s \ + $(GET_LOCAL_DIR)/x86_64/memmove.s \ + $(GET_LOCAL_DIR)/x86_64/memset.s \ + +else +error Unsupported architecture for musl build! + +endif diff --git a/third_party/ulib/musl/src/string/stpcpy.c b/third_party/ulib/musl/src/string/stpcpy.c new file mode 100644 index 000000000..06f63d308 --- /dev/null +++ b/third_party/ulib/musl/src/string/stpcpy.c @@ -0,0 +1,31 @@ +#include "libc.h" +#include +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +char* __stpcpy(char* restrict d, const char* restrict s) { + size_t* wd; + const size_t* ws; + + if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) { + for (; (uintptr_t)s % ALIGN; s++, d++) + if (!(*d = *s)) return d; + wd = (void*)d; + ws = (const void*)s; + for (; !HASZERO(*ws); *wd++ = *ws++) + ; + d = (void*)wd; + s = (const void*)ws; + } + for (; (*d = *s); s++, d++) + ; + + return d; +} + +weak_alias(__stpcpy, stpcpy); diff --git a/third_party/ulib/musl/src/string/stpncpy.c b/third_party/ulib/musl/src/string/stpncpy.c new file mode 100644 index 000000000..c8bb36491 --- /dev/null +++ b/third_party/ulib/musl/src/string/stpncpy.c @@ -0,0 +1,33 @@ +#include "libc.h" +#include +#include +#include + +#define ALIGN (sizeof(size_t) - 1) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +char* __stpncpy(char* restrict d, const char* restrict s, size_t n) { + size_t* wd; + const size_t* ws; + + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d = *s); n--, s++, d++) + ; + if (!n || !*s) goto tail; + wd = (void*)d; + ws = (const void*)s; + for (; n >= sizeof(size_t) && !HASZERO(*ws); n -= sizeof(size_t), ws++, wd++) + *wd = *ws; + d = (void*)wd; + s = (const void*)ws; + } + for (; n && (*d = *s); n--, s++, d++) + ; +tail: + memset(d, 0, n); + return d; +} + +weak_alias(__stpncpy, stpncpy); diff --git a/third_party/ulib/musl/src/string/strcasecmp.c b/third_party/ulib/musl/src/string/strcasecmp.c new file mode 100644 index 000000000..f2c0f78e6 --- /dev/null +++ b/third_party/ulib/musl/src/string/strcasecmp.c @@ -0,0 +1,16 @@ +#include "libc.h" +#include +#include + +int strcasecmp(const char* _l, const char* _r) { + const unsigned char *l = (void *)_l, *r = (void *)_r; + for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++) + ; + return tolower(*l) - tolower(*r); +} + +int __strcasecmp_l(const char* l, const char* r, locale_t loc) { + return strcasecmp(l, r); +} + +weak_alias(__strcasecmp_l, strcasecmp_l); diff --git a/third_party/ulib/musl/src/string/strcasestr.c b/third_party/ulib/musl/src/string/strcasestr.c new file mode 100644 index 000000000..9f657a5cd --- /dev/null +++ b/third_party/ulib/musl/src/string/strcasestr.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include + +char* strcasestr(const char* h, const char* n) { + size_t l = strlen(n); + for (; *h; h++) + if (!strncasecmp(h, n, l)) return (char*)h; + return 0; +} diff --git a/third_party/ulib/musl/src/string/strcat.c b/third_party/ulib/musl/src/string/strcat.c new file mode 100644 index 000000000..79a5925ca --- /dev/null +++ b/third_party/ulib/musl/src/string/strcat.c @@ -0,0 +1,6 @@ +#include + +char* strcat(char* restrict dest, const char* restrict src) { + strcpy(dest + strlen(dest), src); + return dest; +} diff --git a/third_party/ulib/musl/src/string/strchr.c b/third_party/ulib/musl/src/string/strchr.c new file mode 100644 index 000000000..e48fb627b --- /dev/null +++ b/third_party/ulib/musl/src/string/strchr.c @@ -0,0 +1,8 @@ +#include + +char* __strchrnul(const char*, int); + +char* strchr(const char* s, int c) { + char* r = __strchrnul(s, c); + return *(unsigned char*)r == (unsigned char)c ? r : 0; +} diff --git a/third_party/ulib/musl/src/string/strchrnul.c b/third_party/ulib/musl/src/string/strchrnul.c new file mode 100644 index 000000000..2f3e04de7 --- /dev/null +++ b/third_party/ulib/musl/src/string/strchrnul.c @@ -0,0 +1,27 @@ +#include "libc.h" +#include +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +char* __strchrnul(const char* s, int c) { + size_t *w, k; + + c = (unsigned char)c; + if (!c) return (char*)s + strlen(s); + + for (; (uintptr_t)s % ALIGN; s++) + if (!*s || *(unsigned char*)s == c) return (char*)s; + k = ONES * c; + for (w = (void*)s; !HASZERO(*w) && !HASZERO(*w ^ k); w++) + ; + for (s = (void*)w; *s && *(unsigned char*)s != c; s++) + ; + return (char*)s; +} + +weak_alias(__strchrnul, strchrnul); diff --git a/third_party/ulib/musl/src/string/strcmp.c b/third_party/ulib/musl/src/string/strcmp.c new file mode 100644 index 000000000..f1bca8a2d --- /dev/null +++ b/third_party/ulib/musl/src/string/strcmp.c @@ -0,0 +1,7 @@ +#include + +int strcmp(const char* l, const char* r) { + for (; *l == *r && *l; l++, r++) + ; + return *(unsigned char*)l - *(unsigned char*)r; +} diff --git a/third_party/ulib/musl/src/string/strcpy.c b/third_party/ulib/musl/src/string/strcpy.c new file mode 100644 index 000000000..cafef8140 --- /dev/null +++ b/third_party/ulib/musl/src/string/strcpy.c @@ -0,0 +1,16 @@ +#include + +char* __stpcpy(char*, const char*); + +char* strcpy(char* restrict dest, const char* restrict src) { +#if 1 + __stpcpy(dest, src); + return dest; +#else + const unsigned char* s = src; + unsigned char* d = dest; + while ((*d++ = *s++)) + ; + return dest; +#endif +} diff --git a/third_party/ulib/musl/src/string/strcspn.c b/third_party/ulib/musl/src/string/strcspn.c new file mode 100644 index 000000000..c646f59dd --- /dev/null +++ b/third_party/ulib/musl/src/string/strcspn.c @@ -0,0 +1,20 @@ +#include + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) + +char* __strchrnul(const char*, int); + +size_t strcspn(const char* s, const char* c) { + const char* a = s; + size_t byteset[32 / sizeof(size_t)]; + + if (!c[0] || !c[1]) return __strchrnul(s, *c) - a; + + memset(byteset, 0, sizeof byteset); + for (; *c && BITOP(byteset, *(unsigned char*)c, |=); c++) + ; + for (; *s && !BITOP(byteset, *(unsigned char*)s, &); s++) + ; + return s - a; +} diff --git a/third_party/ulib/musl/src/string/strdup.c b/third_party/ulib/musl/src/string/strdup.c new file mode 100644 index 000000000..83f97ba08 --- /dev/null +++ b/third_party/ulib/musl/src/string/strdup.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include +#include + +char* __strdup(const char* s) { + size_t l = strlen(s); + char* d = malloc(l + 1); + if (!d) return NULL; + return memcpy(d, s, l + 1); +} + +weak_alias(__strdup, strdup); diff --git a/third_party/ulib/musl/src/string/strerror_r.c b/third_party/ulib/musl/src/string/strerror_r.c new file mode 100644 index 000000000..8660fa354 --- /dev/null +++ b/third_party/ulib/musl/src/string/strerror_r.c @@ -0,0 +1,19 @@ +#include "libc.h" +#include +#include + +int strerror_r(int err, char* buf, size_t buflen) { + char* msg = strerror(err); + size_t l = strlen(msg); + if (l >= buflen) { + if (buflen) { + memcpy(buf, msg, buflen - 1); + buf[buflen - 1] = 0; + } + return ERANGE; + } + memcpy(buf, msg, l + 1); + return 0; +} + +weak_alias(strerror_r, __xpg_strerror_r); diff --git a/third_party/ulib/musl/src/string/strlcat.c b/third_party/ulib/musl/src/string/strlcat.c new file mode 100644 index 000000000..e2a71d460 --- /dev/null +++ b/third_party/ulib/musl/src/string/strlcat.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include + +size_t strlcat(char* d, const char* s, size_t n) { + size_t l = strnlen(d, n); + if (l == n) return l + strlen(s); + return l + strlcpy(d + l, s, n - l); +} diff --git a/third_party/ulib/musl/src/string/strlcpy.c b/third_party/ulib/musl/src/string/strlcpy.c new file mode 100644 index 000000000..be56457b6 --- /dev/null +++ b/third_party/ulib/musl/src/string/strlcpy.c @@ -0,0 +1,35 @@ +#define _BSD_SOURCE +#include "libc.h" +#include +#include +#include + +#define ALIGN (sizeof(size_t) - 1) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +size_t strlcpy(char* d, const char* s, size_t n) { + char* d0 = d; + size_t* wd; + const size_t* ws; + + if (!n--) goto finish; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d = *s); n--, s++, d++) + ; + if (n && *s) { + wd = (void*)d; + ws = (const void*)s; + for (; n >= sizeof(size_t) && !HASZERO(*ws); n -= sizeof(size_t), ws++, wd++) + *wd = *ws; + d = (void*)wd; + s = (const void*)ws; + } + } + for (; n && (*d = *s); n--, s++, d++) + ; + *d = 0; +finish: + return d - d0 + strlen(s); +} diff --git a/third_party/ulib/musl/src/string/strlen.c b/third_party/ulib/musl/src/string/strlen.c new file mode 100644 index 000000000..9da46c3a6 --- /dev/null +++ b/third_party/ulib/musl/src/string/strlen.c @@ -0,0 +1,20 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1 / UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) +#define HASZERO(x) ((x)-ONES & ~(x)&HIGHS) + +size_t strlen(const char* s) { + const char* a = s; + const size_t* w; + for (; (uintptr_t)s % ALIGN; s++) + if (!*s) return s - a; + for (w = (const void*)s; !HASZERO(*w); w++) + ; + for (s = (const void*)w; *s; s++) + ; + return s - a; +} diff --git a/third_party/ulib/musl/src/string/strncasecmp.c b/third_party/ulib/musl/src/string/strncasecmp.c new file mode 100644 index 000000000..9a49e8c34 --- /dev/null +++ b/third_party/ulib/musl/src/string/strncasecmp.c @@ -0,0 +1,17 @@ +#include "libc.h" +#include +#include + +int strncasecmp(const char* _l, const char* _r, size_t n) { + const unsigned char *l = (void *)_l, *r = (void *)_r; + if (!n--) return 0; + for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--) + ; + return tolower(*l) - tolower(*r); +} + +int __strncasecmp_l(const char* l, const char* r, size_t n, locale_t loc) { + return strncasecmp(l, r, n); +} + +weak_alias(__strncasecmp_l, strncasecmp_l); diff --git a/third_party/ulib/musl/src/string/strncat.c b/third_party/ulib/musl/src/string/strncat.c new file mode 100644 index 000000000..962d9caa2 --- /dev/null +++ b/third_party/ulib/musl/src/string/strncat.c @@ -0,0 +1,10 @@ +#include + +char* strncat(char* restrict d, const char* restrict s, size_t n) { + char* a = d; + d += strlen(d); + while (n && *s) + n--, *d++ = *s++; + *d++ = 0; + return a; +} diff --git a/third_party/ulib/musl/src/string/strncmp.c b/third_party/ulib/musl/src/string/strncmp.c new file mode 100644 index 000000000..89efd2f2a --- /dev/null +++ b/third_party/ulib/musl/src/string/strncmp.c @@ -0,0 +1,9 @@ +#include + +int strncmp(const char* _l, const char* _r, size_t n) { + const unsigned char *l = (void *)_l, *r = (void *)_r; + if (!n--) return 0; + for (; *l && *r && n && *l == *r; l++, r++, n--) + ; + return *l - *r; +} diff --git a/third_party/ulib/musl/src/string/strncpy.c b/third_party/ulib/musl/src/string/strncpy.c new file mode 100644 index 000000000..8d028e56d --- /dev/null +++ b/third_party/ulib/musl/src/string/strncpy.c @@ -0,0 +1,8 @@ +#include + +char* __stpncpy(char*, const char*, size_t); + +char* strncpy(char* restrict d, const char* restrict s, size_t n) { + __stpncpy(d, s, n); + return d; +} diff --git a/third_party/ulib/musl/src/string/strndup.c b/third_party/ulib/musl/src/string/strndup.c new file mode 100644 index 000000000..5a778e14f --- /dev/null +++ b/third_party/ulib/musl/src/string/strndup.c @@ -0,0 +1,11 @@ +#include +#include + +char* strndup(const char* s, size_t n) { + size_t l = strnlen(s, n); + char* d = malloc(l + 1); + if (!d) return NULL; + memcpy(d, s, l); + d[l] = 0; + return d; +} diff --git a/third_party/ulib/musl/src/string/strnlen.c b/third_party/ulib/musl/src/string/strnlen.c new file mode 100644 index 000000000..ff3a95367 --- /dev/null +++ b/third_party/ulib/musl/src/string/strnlen.c @@ -0,0 +1,6 @@ +#include + +size_t strnlen(const char* s, size_t n) { + const char* p = memchr(s, 0, n); + return p ? p - s : n; +} diff --git a/third_party/ulib/musl/src/string/strpbrk.c b/third_party/ulib/musl/src/string/strpbrk.c new file mode 100644 index 000000000..61f255955 --- /dev/null +++ b/third_party/ulib/musl/src/string/strpbrk.c @@ -0,0 +1,6 @@ +#include + +char* strpbrk(const char* s, const char* b) { + s += strcspn(s, b); + return *s ? (char*)s : 0; +} diff --git a/third_party/ulib/musl/src/string/strrchr.c b/third_party/ulib/musl/src/string/strrchr.c new file mode 100644 index 000000000..dc8881530 --- /dev/null +++ b/third_party/ulib/musl/src/string/strrchr.c @@ -0,0 +1,7 @@ +#include + +void* __memrchr(const void*, int, size_t); + +char* strrchr(const char* s, int c) { + return __memrchr(s, c, strlen(s) + 1); +} diff --git a/third_party/ulib/musl/src/string/strsep.c b/third_party/ulib/musl/src/string/strsep.c new file mode 100644 index 000000000..cc0b0d768 --- /dev/null +++ b/third_party/ulib/musl/src/string/strsep.c @@ -0,0 +1,14 @@ +#define _GNU_SOURCE +#include + +char* strsep(char** str, const char* sep) { + char *s = *str, *end; + if (!s) return NULL; + end = s + strcspn(s, sep); + if (*end) + *end++ = 0; + else + end = 0; + *str = end; + return s; +} diff --git a/third_party/ulib/musl/src/string/strsignal.c b/third_party/ulib/musl/src/string/strsignal.c new file mode 100644 index 000000000..c386db3d5 --- /dev/null +++ b/third_party/ulib/musl/src/string/strsignal.c @@ -0,0 +1,90 @@ +#include "locale_impl.h" +#include +#include + +#if (SIGHUP == 1) && (SIGINT == 2) && (SIGQUIT == 3) && (SIGILL == 4) && (SIGTRAP == 5) && \ + (SIGABRT == 6) && (SIGBUS == 7) && (SIGFPE == 8) && (SIGKILL == 9) && (SIGUSR1 == 10) && \ + (SIGSEGV == 11) && (SIGUSR2 == 12) && (SIGPIPE == 13) && (SIGALRM == 14) && (SIGTERM == 15) && \ + (SIGSTKFLT == 16) && (SIGCHLD == 17) && (SIGCONT == 18) && (SIGSTOP == 19) && \ + (SIGTSTP == 20) && (SIGTTIN == 21) && (SIGTTOU == 22) && (SIGURG == 23) && (SIGXCPU == 24) && \ + (SIGXFSZ == 25) && (SIGVTALRM == 26) && (SIGPROF == 27) && (SIGWINCH == 28) && \ + (SIGPOLL == 29) && (SIGPWR == 30) && (SIGSYS == 31) + +#define sigmap(x) x + +#else + +static const char map[] = {[SIGHUP] = 1, [SIGINT] = 2, [SIGQUIT] = 3, [SIGILL] = 4, + [SIGTRAP] = 5, [SIGABRT] = 6, [SIGBUS] = 7, [SIGFPE] = 8, + [SIGKILL] = 9, [SIGUSR1] = 10, [SIGSEGV] = 11, [SIGUSR2] = 12, + [SIGPIPE] = 13, [SIGALRM] = 14, [SIGTERM] = 15, [SIGSTKFLT] = 16, + [SIGCHLD] = 17, [SIGCONT] = 18, [SIGSTOP] = 19, [SIGTSTP] = 20, + [SIGTTIN] = 21, [SIGTTOU] = 22, [SIGURG] = 23, [SIGXCPU] = 24, + [SIGXFSZ] = 25, [SIGVTALRM] = 26, [SIGPROF] = 27, [SIGWINCH] = 28, + [SIGPOLL] = 29, [SIGPWR] = 30, [SIGSYS] = 31}; + +#define sigmap(x) ((x) >= sizeof map ? (x) : map[(x)]) + +#endif + +static const char strings[] = "Unknown signal\0" + "Hangup\0" + "Interrupt\0" + "Quit\0" + "Illegal instruction\0" + "Trace/breakpoint trap\0" + "Aborted\0" + "Bus error\0" + "Arithmetic exception\0" + "Killed\0" + "User defined signal 1\0" + "Segmentation fault\0" + "User defined signal 2\0" + "Broken pipe\0" + "Alarm clock\0" + "Terminated\0" + "Stack fault\0" + "Child process status\0" + "Continued\0" + "Stopped (signal)\0" + "Stopped\0" + "Stopped (tty input)\0" + "Stopped (tty output)\0" + "Urgent I/O condition\0" + "CPU time limit exceeded\0" + "File size limit exceeded\0" + "Virtual timer expired\0" + "Profiling timer expired\0" + "Window changed\0" + "I/O possible\0" + "Power failure\0" + "Bad system call\0" + "RT32" + "\0RT33\0RT34\0RT35\0RT36\0RT37\0RT38\0RT39\0RT40" + "\0RT41\0RT42\0RT43\0RT44\0RT45\0RT46\0RT47\0RT48" + "\0RT49\0RT50\0RT51\0RT52\0RT53\0RT54\0RT55\0RT56" + "\0RT57\0RT58\0RT59\0RT60\0RT61\0RT62\0RT63\0RT64" +#if _NSIG > 65 + "\0RT65\0RT66\0RT67\0RT68\0RT69\0RT70\0RT71\0RT72" + "\0RT73\0RT74\0RT75\0RT76\0RT77\0RT78\0RT79\0RT80" + "\0RT81\0RT82\0RT83\0RT84\0RT85\0RT86\0RT87\0RT88" + "\0RT89\0RT90\0RT91\0RT92\0RT93\0RT94\0RT95\0RT96" + "\0RT97\0RT98\0RT99\0RT100\0RT101\0RT102\0RT103\0RT104" + "\0RT105\0RT106\0RT107\0RT108\0RT109\0RT110\0RT111\0RT112" + "\0RT113\0RT114\0RT115\0RT116\0RT117\0RT118\0RT119\0RT120" + "\0RT121\0RT122\0RT123\0RT124\0RT125\0RT126\0RT127\0RT128" +#endif + ""; + +char* strsignal(int signum) { + const char* s = strings; + + signum = sigmap(signum); + if (signum - 1U >= _NSIG - 1) signum = 0; + + for (; signum--; s++) + for (; *s; s++) + ; + + return (char*)LCTRANS_CUR(s); +} diff --git a/third_party/ulib/musl/src/string/strspn.c b/third_party/ulib/musl/src/string/strspn.c new file mode 100644 index 000000000..e9ea64833 --- /dev/null +++ b/third_party/ulib/musl/src/string/strspn.c @@ -0,0 +1,22 @@ +#include + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) + +size_t strspn(const char* s, const char* c) { + const char* a = s; + size_t byteset[32 / sizeof(size_t)] = {0}; + + if (!c[0]) return 0; + if (!c[1]) { + for (; *s == *c; s++) + ; + return s - a; + } + + for (; *c && BITOP(byteset, *(unsigned char*)c, |=); c++) + ; + for (; *s && BITOP(byteset, *(unsigned char*)s, &); s++) + ; + return s - a; +} diff --git a/third_party/ulib/musl/src/string/strstr.c b/third_party/ulib/musl/src/string/strstr.c new file mode 100644 index 000000000..1c8cf1266 --- /dev/null +++ b/third_party/ulib/musl/src/string/strstr.c @@ -0,0 +1,165 @@ +#include +#include + +static char* twobyte_strstr(const unsigned char* h, const unsigned char* n) { + uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; + for (h++; *h && hw != nw; hw = hw << 8 | *++h) + ; + return *h ? (char*)h - 1 : 0; +} + +static char* threebyte_strstr(const unsigned char* h, const unsigned char* n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8; + for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8) + ; + return *h ? (char*)h - 2 : 0; +} + +static char* fourbyte_strstr(const unsigned char* h, const unsigned char* n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + for (h += 3; *h && hw != nw; hw = hw << 8 | *++h) + ; + return *h ? (char*)h - 3 : 0; +} + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) + +static char* twoway_strstr(const unsigned char* h, const unsigned char* n) { + const unsigned char* z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = {0}; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (l = 0; n[l] && h[l]; l++) + BITOP(byteset, n[l], |=), shift[n[l]] = l + 1; + if (n[l]) return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] > n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] < n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip + 1 > ms + 1) + ms = ip; + else + p = p0; + + /* Periodic needle? */ + if (memcmp(n, n + p, ms + 1)) { + mem0 = 0; + p = MAX(ms, l - ms - 1) + 1; + } else + mem0 = l - p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z - h < l) { + /* Fast estimate for MIN(l,63) */ + size_t grow = l | 63; + const unsigned char* z2 = memchr(z, 0, grow); + if (z2) { + z = z2; + if (z - h < l) return 0; + } else + z += grow; + } + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l - 1], &)) { + k = l - shift[h[l - 1]]; + // printf("adv by %zu (on %c) at [%s] (%zu;l=%zu)\n", k, h[l-1], h, shift[h[l-1]], l); + if (k) { + if (mem0 && mem && k < p) k = l - p; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++) + ; + if (n[k]) { + h += k - ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) + ; + if (k <= mem) return (char*)h; + h += p; + mem = mem0; + } +} + +char* strstr(const char* h, const char* n) { + /* Return immediately on empty needle */ + if (!n[0]) return (char*)h; + + /* Use faster algorithms for short needles */ + h = strchr(h, *n); + if (!h || !n[1]) return (char*)h; + if (!h[1]) return 0; + if (!n[2]) return twobyte_strstr((void*)h, (void*)n); + if (!h[2]) return 0; + if (!n[3]) return threebyte_strstr((void*)h, (void*)n); + if (!h[3]) return 0; + if (!n[4]) return fourbyte_strstr((void*)h, (void*)n); + + return twoway_strstr((void*)h, (void*)n); +} diff --git a/third_party/ulib/musl/src/string/strtok.c b/third_party/ulib/musl/src/string/strtok.c new file mode 100644 index 000000000..34a27eb0b --- /dev/null +++ b/third_party/ulib/musl/src/string/strtok.c @@ -0,0 +1,14 @@ +#include + +char* strtok(char* restrict s, const char* restrict sep) { + static char* p; + if (!s && !(s = p)) return NULL; + s += strspn(s, sep); + if (!*s) return p = 0; + p = s + strcspn(s, sep); + if (*p) + *p++ = 0; + else + p = 0; + return s; +} diff --git a/third_party/ulib/musl/src/string/strtok_r.c b/third_party/ulib/musl/src/string/strtok_r.c new file mode 100644 index 000000000..71a63db1f --- /dev/null +++ b/third_party/ulib/musl/src/string/strtok_r.c @@ -0,0 +1,13 @@ +#include + +char* strtok_r(char* restrict s, const char* restrict sep, char** restrict p) { + if (!s && !(s = *p)) return NULL; + s += strspn(s, sep); + if (!*s) return *p = 0; + *p = s + strcspn(s, sep); + if (**p) + *(*p)++ = 0; + else + *p = 0; + return s; +} diff --git a/third_party/ulib/musl/src/string/strverscmp.c b/third_party/ulib/musl/src/string/strverscmp.c new file mode 100644 index 000000000..72d7c6f45 --- /dev/null +++ b/third_party/ulib/musl/src/string/strverscmp.c @@ -0,0 +1,35 @@ +#define _GNU_SOURCE +#include +#include + +int strverscmp(const char* l0, const char* r0) { + const unsigned char* l = (const void*)l0; + const unsigned char* r = (const void*)r0; + size_t i, dp, j; + int z = 1; + + /* Find maximal matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for (dp = i = 0; l[i] == r[i]; i++) { + int c = l[i]; + if (!c) return 0; + if (!isdigit(c)) + dp = i + 1, z = 1; + else if (c != '0') + z = 0; + } + + if (l[dp] != '0' && r[dp] != '0') { + /* If we're not looking at a digit sequence that began + * with a zero, longest digit string is greater. */ + for (j = i; isdigit(l[j]); j++) + if (!isdigit(r[j])) return 1; + if (isdigit(r[j])) return -1; + } else if (z && dp < i && (isdigit(l[i]) || isdigit(r[i]))) { + /* Otherwise, if common prefix of digit sequence is + * all zeros, digits order less than non-digits. */ + return (unsigned char)(l[i] - '0') - (unsigned char)(r[i] - '0'); + } + + return l[i] - r[i]; +} diff --git a/third_party/ulib/musl/src/string/swab.c b/third_party/ulib/musl/src/string/swab.c new file mode 100644 index 000000000..bac6af7bb --- /dev/null +++ b/third_party/ulib/musl/src/string/swab.c @@ -0,0 +1,12 @@ +#include + +void swab(const void* restrict _src, void* restrict _dest, ssize_t n) { + const char* src = _src; + char* dest = _dest; + for (; n > 1; n -= 2) { + dest[0] = src[1]; + dest[1] = src[0]; + dest += 2; + src += 2; + } +} diff --git a/third_party/ulib/musl/src/string/wcpcpy.c b/third_party/ulib/musl/src/string/wcpcpy.c new file mode 100644 index 000000000..beb3a129f --- /dev/null +++ b/third_party/ulib/musl/src/string/wcpcpy.c @@ -0,0 +1,5 @@ +#include + +wchar_t* wcpcpy(wchar_t* restrict d, const wchar_t* restrict s) { + return wcscpy(d, s) + wcslen(s); +} diff --git a/third_party/ulib/musl/src/string/wcpncpy.c b/third_party/ulib/musl/src/string/wcpncpy.c new file mode 100644 index 000000000..3f5d836ea --- /dev/null +++ b/third_party/ulib/musl/src/string/wcpncpy.c @@ -0,0 +1,5 @@ +#include + +wchar_t* wcpncpy(wchar_t* restrict d, const wchar_t* restrict s, size_t n) { + return wcsncpy(d, s, n) + wcsnlen(s, n); +} diff --git a/third_party/ulib/musl/src/string/wcscasecmp.c b/third_party/ulib/musl/src/string/wcscasecmp.c new file mode 100644 index 000000000..d3ff6342d --- /dev/null +++ b/third_party/ulib/musl/src/string/wcscasecmp.c @@ -0,0 +1,6 @@ +#include +#include + +int wcscasecmp(const wchar_t* l, const wchar_t* r) { + return wcsncasecmp(l, r, -1); +} diff --git a/third_party/ulib/musl/src/string/wcscasecmp_l.c b/third_party/ulib/musl/src/string/wcscasecmp_l.c new file mode 100644 index 000000000..d20a5bde6 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcscasecmp_l.c @@ -0,0 +1,5 @@ +#include + +int wcscasecmp_l(const wchar_t* l, const wchar_t* r, locale_t locale) { + return wcscasecmp(l, r); +} diff --git a/third_party/ulib/musl/src/string/wcscat.c b/third_party/ulib/musl/src/string/wcscat.c new file mode 100644 index 000000000..18083c062 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcscat.c @@ -0,0 +1,6 @@ +#include + +wchar_t* wcscat(wchar_t* restrict dest, const wchar_t* restrict src) { + wcscpy(dest + wcslen(dest), src); + return dest; +} diff --git a/third_party/ulib/musl/src/string/wcschr.c b/third_party/ulib/musl/src/string/wcschr.c new file mode 100644 index 000000000..0f83f4f80 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcschr.c @@ -0,0 +1,8 @@ +#include + +wchar_t* wcschr(const wchar_t* s, wchar_t c) { + if (!c) return (wchar_t*)s + wcslen(s); + for (; *s && *s != c; s++) + ; + return *s ? (wchar_t*)s : 0; +} diff --git a/third_party/ulib/musl/src/string/wcscmp.c b/third_party/ulib/musl/src/string/wcscmp.c new file mode 100644 index 000000000..1a073b0b4 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcscmp.c @@ -0,0 +1,7 @@ +#include + +int wcscmp(const wchar_t* l, const wchar_t* r) { + for (; *l == *r && *l && *r; l++, r++) + ; + return *l - *r; +} diff --git a/third_party/ulib/musl/src/string/wcscpy.c b/third_party/ulib/musl/src/string/wcscpy.c new file mode 100644 index 000000000..fc9631fc1 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcscpy.c @@ -0,0 +1,8 @@ +#include + +wchar_t* wcscpy(wchar_t* restrict d, const wchar_t* restrict s) { + wchar_t* a = d; + while ((*d++ = *s++)) + ; + return a; +} diff --git a/third_party/ulib/musl/src/string/wcscspn.c b/third_party/ulib/musl/src/string/wcscspn.c new file mode 100644 index 000000000..256a93cd2 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcscspn.c @@ -0,0 +1,10 @@ +#include + +size_t wcscspn(const wchar_t* s, const wchar_t* c) { + const wchar_t* a; + if (!c[0]) return wcslen(s); + if (!c[1]) return (s = wcschr(a = s, *c)) ? s - a : wcslen(a); + for (a = s; *s && !wcschr(c, *s); s++) + ; + return s - a; +} diff --git a/third_party/ulib/musl/src/string/wcsdup.c b/third_party/ulib/musl/src/string/wcsdup.c new file mode 100644 index 000000000..138349fae --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsdup.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include +#include + +wchar_t* wcsdup(const wchar_t* s) { + size_t l = wcslen(s); + wchar_t* d = malloc((l + 1) * sizeof(wchar_t)); + if (!d) return NULL; + return wmemcpy(d, s, l + 1); +} diff --git a/third_party/ulib/musl/src/string/wcslen.c b/third_party/ulib/musl/src/string/wcslen.c new file mode 100644 index 000000000..57833ee88 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcslen.c @@ -0,0 +1,8 @@ +#include + +size_t wcslen(const wchar_t* s) { + const wchar_t* a; + for (a = s; *s; s++) + ; + return s - a; +} diff --git a/third_party/ulib/musl/src/string/wcsncasecmp.c b/third_party/ulib/musl/src/string/wcsncasecmp.c new file mode 100644 index 000000000..504a1edfc --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsncasecmp.c @@ -0,0 +1,9 @@ +#include +#include + +int wcsncasecmp(const wchar_t* l, const wchar_t* r, size_t n) { + if (!n--) return 0; + for (; *l && *r && n && (*l == *r || towlower(*l) == towlower(*r)); l++, r++, n--) + ; + return towlower(*l) - towlower(*r); +} diff --git a/third_party/ulib/musl/src/string/wcsncasecmp_l.c b/third_party/ulib/musl/src/string/wcsncasecmp_l.c new file mode 100644 index 000000000..c3d52d85f --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsncasecmp_l.c @@ -0,0 +1,5 @@ +#include + +int wcsncasecmp_l(const wchar_t* l, const wchar_t* r, size_t n, locale_t locale) { + return wcsncasecmp(l, r, n); +} diff --git a/third_party/ulib/musl/src/string/wcsncat.c b/third_party/ulib/musl/src/string/wcsncat.c new file mode 100644 index 000000000..929c052c2 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsncat.c @@ -0,0 +1,10 @@ +#include + +wchar_t* wcsncat(wchar_t* restrict d, const wchar_t* restrict s, size_t n) { + wchar_t* a = d; + d += wcslen(d); + while (n && *s) + n--, *d++ = *s++; + *d++ = 0; + return a; +} diff --git a/third_party/ulib/musl/src/string/wcsncmp.c b/third_party/ulib/musl/src/string/wcsncmp.c new file mode 100644 index 000000000..cba6bb7c4 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsncmp.c @@ -0,0 +1,7 @@ +#include + +int wcsncmp(const wchar_t* l, const wchar_t* r, size_t n) { + for (; n && *l == *r && *l && *r; n--, l++, r++) + ; + return n ? *l - *r : 0; +} diff --git a/third_party/ulib/musl/src/string/wcsncpy.c b/third_party/ulib/musl/src/string/wcsncpy.c new file mode 100644 index 000000000..6645b980b --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsncpy.c @@ -0,0 +1,9 @@ +#include + +wchar_t* wcsncpy(wchar_t* restrict d, const wchar_t* restrict s, size_t n) { + wchar_t* a = d; + while (n && *s) + n--, *d++ = *s++; + wmemset(d, 0, n); + return a; +} diff --git a/third_party/ulib/musl/src/string/wcsnlen.c b/third_party/ulib/musl/src/string/wcsnlen.c new file mode 100644 index 000000000..02823f69f --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsnlen.c @@ -0,0 +1,7 @@ +#include + +size_t wcsnlen(const wchar_t* s, size_t n) { + const wchar_t* z = wmemchr(s, 0, n); + if (z) n = z - s; + return n; +} diff --git a/third_party/ulib/musl/src/string/wcspbrk.c b/third_party/ulib/musl/src/string/wcspbrk.c new file mode 100644 index 000000000..87e0f7ab7 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcspbrk.c @@ -0,0 +1,6 @@ +#include + +wchar_t* wcspbrk(const wchar_t* s, const wchar_t* b) { + s += wcscspn(s, b); + return *s ? (wchar_t*)s : NULL; +} diff --git a/third_party/ulib/musl/src/string/wcsrchr.c b/third_party/ulib/musl/src/string/wcsrchr.c new file mode 100644 index 000000000..0d933255e --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsrchr.c @@ -0,0 +1,8 @@ +#include + +wchar_t* wcsrchr(const wchar_t* s, wchar_t c) { + const wchar_t* p; + for (p = s + wcslen(s); p >= s && *p != c; p--) + ; + return p >= s ? (wchar_t*)p : 0; +} diff --git a/third_party/ulib/musl/src/string/wcsspn.c b/third_party/ulib/musl/src/string/wcsspn.c new file mode 100644 index 000000000..eeec6a165 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsspn.c @@ -0,0 +1,8 @@ +#include + +size_t wcsspn(const wchar_t* s, const wchar_t* c) { + const wchar_t* a; + for (a = s; *s && wcschr(c, *s); s++) + ; + return s - a; +} diff --git a/third_party/ulib/musl/src/string/wcsstr.c b/third_party/ulib/musl/src/string/wcsstr.c new file mode 100644 index 000000000..b69f835fa --- /dev/null +++ b/third_party/ulib/musl/src/string/wcsstr.c @@ -0,0 +1,116 @@ +#include + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static wchar_t* twoway_wcsstr(const wchar_t* h, const wchar_t* n) { + const wchar_t* z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + + /* Computing length of needle */ + for (l = 0; n[l] && h[l]; l++) + ; + if (n[l]) return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] > n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] < n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip + 1 > ms + 1) + ms = ip; + else + p = p0; + + /* Periodic needle? */ + if (wmemcmp(n, n + p, ms + 1)) { + mem0 = 0; + p = MAX(ms, l - ms - 1) + 1; + } else + mem0 = l - p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z - h < l) { + /* Fast estimate for MIN(l,63) */ + size_t grow = l | 63; + const wchar_t* z2 = wmemchr(z, 0, grow); + if (z2) { + z = z2; + if (z - h < l) return 0; + } else + z += grow; + } + + /* Compare right half */ + for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++) + ; + if (n[k]) { + h += k - ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) + ; + if (k <= mem) return (wchar_t*)h; + h += p; + mem = mem0; + } +} + +wchar_t* wcsstr(const wchar_t* restrict h, const wchar_t* restrict n) { + /* Return immediately on empty needle or haystack */ + if (!n[0]) return (wchar_t*)h; + if (!h[0]) return 0; + + /* Use faster algorithms for short needles */ + h = wcschr(h, *n); + if (!h || !n[1]) return (wchar_t*)h; + if (!h[1]) return 0; + + return twoway_wcsstr(h, n); +} diff --git a/third_party/ulib/musl/src/string/wcstok.c b/third_party/ulib/musl/src/string/wcstok.c new file mode 100644 index 000000000..2c4aa8668 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcstok.c @@ -0,0 +1,13 @@ +#include + +wchar_t* wcstok(wchar_t* restrict s, const wchar_t* restrict sep, wchar_t** restrict p) { + if (!s && !(s = *p)) return NULL; + s += wcsspn(s, sep); + if (!*s) return *p = 0; + *p = s + wcscspn(s, sep); + if (**p) + *(*p)++ = 0; + else + *p = 0; + return s; +} diff --git a/third_party/ulib/musl/src/string/wcswcs.c b/third_party/ulib/musl/src/string/wcswcs.c new file mode 100644 index 000000000..7b6ed6d80 --- /dev/null +++ b/third_party/ulib/musl/src/string/wcswcs.c @@ -0,0 +1,5 @@ +#include + +wchar_t* wcswcs(const wchar_t* haystack, const wchar_t* needle) { + return wcsstr(haystack, needle); +} diff --git a/third_party/ulib/musl/src/string/wmemchr.c b/third_party/ulib/musl/src/string/wmemchr.c new file mode 100644 index 000000000..3c0c80217 --- /dev/null +++ b/third_party/ulib/musl/src/string/wmemchr.c @@ -0,0 +1,7 @@ +#include + +wchar_t* wmemchr(const wchar_t* s, wchar_t c, size_t n) { + for (; n && *s != c; n--, s++) + ; + return n ? (wchar_t*)s : 0; +} diff --git a/third_party/ulib/musl/src/string/wmemcmp.c b/third_party/ulib/musl/src/string/wmemcmp.c new file mode 100644 index 000000000..0d6d03ca8 --- /dev/null +++ b/third_party/ulib/musl/src/string/wmemcmp.c @@ -0,0 +1,7 @@ +#include + +int wmemcmp(const wchar_t* l, const wchar_t* r, size_t n) { + for (; n && *l == *r; n--, l++, r++) + ; + return n ? *l - *r : 0; +} diff --git a/third_party/ulib/musl/src/string/wmemcpy.c b/third_party/ulib/musl/src/string/wmemcpy.c new file mode 100644 index 000000000..356383792 --- /dev/null +++ b/third_party/ulib/musl/src/string/wmemcpy.c @@ -0,0 +1,8 @@ +#include + +wchar_t* wmemcpy(wchar_t* restrict d, const wchar_t* restrict s, size_t n) { + wchar_t* a = d; + while (n--) + *d++ = *s++; + return a; +} diff --git a/third_party/ulib/musl/src/string/wmemmove.c b/third_party/ulib/musl/src/string/wmemmove.c new file mode 100644 index 000000000..ee94932cd --- /dev/null +++ b/third_party/ulib/musl/src/string/wmemmove.c @@ -0,0 +1,12 @@ +#include + +wchar_t* wmemmove(wchar_t* d, const wchar_t* s, size_t n) { + wchar_t* d0 = d; + if ((size_t)(d - s) < n) + while (n--) + d[n] = s[n]; + else + while (n--) + *d++ = *s++; + return d0; +} diff --git a/third_party/ulib/musl/src/string/wmemset.c b/third_party/ulib/musl/src/string/wmemset.c new file mode 100644 index 000000000..d0ab6be80 --- /dev/null +++ b/third_party/ulib/musl/src/string/wmemset.c @@ -0,0 +1,8 @@ +#include + +wchar_t* wmemset(wchar_t* d, wchar_t c, size_t n) { + wchar_t* ret = d; + while (n--) + *d++ = c; + return ret; +} diff --git a/third_party/ulib/musl/src/string/x86_64/memcpy.s b/third_party/ulib/musl/src/string/x86_64/memcpy.s new file mode 100644 index 000000000..3d960efa8 --- /dev/null +++ b/third_party/ulib/musl/src/string/x86_64/memcpy.s @@ -0,0 +1,25 @@ +.global memcpy +.global __memcpy_fwd +.hidden __memcpy_fwd +.type memcpy,@function +memcpy: +__memcpy_fwd: + mov %rdi,%rax + cmp $8,%rdx + jc 1f + test $7,%edi + jz 1f +2: movsb + dec %rdx + test $7,%edi + jnz 2b +1: mov %rdx,%rcx + shr $3,%rcx + rep + movsq + and $7,%edx + jz 1f +2: movsb + dec %edx + jnz 2b +1: ret diff --git a/third_party/ulib/musl/src/string/x86_64/memmove.s b/third_party/ulib/musl/src/string/x86_64/memmove.s new file mode 100644 index 000000000..172c02520 --- /dev/null +++ b/third_party/ulib/musl/src/string/x86_64/memmove.s @@ -0,0 +1,16 @@ +.global memmove +.type memmove,@function +memmove: + mov %rdi,%rax + sub %rsi,%rax + cmp %rdx,%rax +.hidden __memcpy_fwd + jae __memcpy_fwd + mov %rdx,%rcx + lea -1(%rdi,%rdx),%rdi + lea -1(%rsi,%rdx),%rsi + std + rep movsb + cld + lea 1(%rdi),%rax + ret diff --git a/third_party/ulib/musl/src/string/x86_64/memset.s b/third_party/ulib/musl/src/string/x86_64/memset.s new file mode 100644 index 000000000..2d3f5e52b --- /dev/null +++ b/third_party/ulib/musl/src/string/x86_64/memset.s @@ -0,0 +1,72 @@ +.global memset +.type memset,@function +memset: + movzbq %sil,%rax + mov $0x101010101010101,%r8 + imul %r8,%rax + + cmp $126,%rdx + ja 2f + + test %edx,%edx + jz 1f + + mov %sil,(%rdi) + mov %sil,-1(%rdi,%rdx) + cmp $2,%edx + jbe 1f + + mov %ax,1(%rdi) + mov %ax,(-1-2)(%rdi,%rdx) + cmp $6,%edx + jbe 1f + + mov %eax,(1+2)(%rdi) + mov %eax,(-1-2-4)(%rdi,%rdx) + cmp $14,%edx + jbe 1f + + mov %rax,(1+2+4)(%rdi) + mov %rax,(-1-2-4-8)(%rdi,%rdx) + cmp $30,%edx + jbe 1f + + mov %rax,(1+2+4+8)(%rdi) + mov %rax,(1+2+4+8+8)(%rdi) + mov %rax,(-1-2-4-8-16)(%rdi,%rdx) + mov %rax,(-1-2-4-8-8)(%rdi,%rdx) + cmp $62,%edx + jbe 1f + + mov %rax,(1+2+4+8+16)(%rdi) + mov %rax,(1+2+4+8+16+8)(%rdi) + mov %rax,(1+2+4+8+16+16)(%rdi) + mov %rax,(1+2+4+8+16+24)(%rdi) + mov %rax,(-1-2-4-8-16-32)(%rdi,%rdx) + mov %rax,(-1-2-4-8-16-24)(%rdi,%rdx) + mov %rax,(-1-2-4-8-16-16)(%rdi,%rdx) + mov %rax,(-1-2-4-8-16-8)(%rdi,%rdx) + +1: mov %rdi,%rax + ret + +2: test $15,%edi + mov %rdi,%r8 + mov %rax,-8(%rdi,%rdx) + mov %rdx,%rcx + jnz 2f + +1: shr $3,%rcx + rep + stosq + mov %r8,%rax + ret + +2: xor %edx,%edx + sub %edi,%edx + and $15,%edx + mov %rax,(%rdi) + mov %rax,8(%rdi) + sub %rdx,%rcx + add %rdx,%rdi + jmp 1b diff --git a/third_party/ulib/musl/src/temp/BUILD.gn b/third_party/ulib/musl/src/temp/BUILD.gn new file mode 100644 index 000000000..7c8827024 --- /dev/null +++ b/third_party/ulib/musl/src/temp/BUILD.gn @@ -0,0 +1,15 @@ +source_set("temp") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__randname.c", + "mkdtemp.c", + "mkostemp.c", + "mkostemps.c", + "mkstemp.c", + "mkstemps.c", + "mktemp.c", + ] +} diff --git a/third_party/ulib/musl/src/temp/__randname.c b/third_party/ulib/musl/src/temp/__randname.c new file mode 100644 index 000000000..539bbbf43 --- /dev/null +++ b/third_party/ulib/musl/src/temp/__randname.c @@ -0,0 +1,19 @@ +#include +#include + +int __clock_gettime(clockid_t, struct timespec*); + +/* This assumes that a check for the + template size has already been made */ +char* __randname(char* template) { + int i; + struct timespec ts; + unsigned long r; + + __clock_gettime(CLOCK_REALTIME, &ts); + r = ts.tv_nsec * 65537 ^ (uintptr_t)&ts / 16 + (uintptr_t) template; + for (i = 0; i < 6; i++, r >>= 5) + template[i] = 'A' + (r & 15) + (r & 16) * 2; + + return template; +} diff --git a/third_party/ulib/musl/src/temp/mkdtemp.c b/third_party/ulib/musl/src/temp/mkdtemp.c new file mode 100644 index 000000000..3803d15e6 --- /dev/null +++ b/third_party/ulib/musl/src/temp/mkdtemp.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +char* __randname(char*); + +char* mkdtemp(char* template) { + size_t l = strlen(template); + int retries = 100; + + if (l < 6 || memcmp(template + l - 6, "XXXXXX", 6)) { + errno = EINVAL; + return 0; + } + + do { + __randname(template + l - 6); + if (!mkdir(template, 0700)) return template; + } while (--retries && errno == EEXIST); + + memcpy(template + l - 6, "XXXXXX", 6); + return 0; +} diff --git a/third_party/ulib/musl/src/temp/mkostemp.c b/third_party/ulib/musl/src/temp/mkostemp.c new file mode 100644 index 000000000..998268dbf --- /dev/null +++ b/third_party/ulib/musl/src/temp/mkostemp.c @@ -0,0 +1,11 @@ +#define _BSD_SOURCE +#include "libc.h" +#include + +int __mkostemps(char*, int, int); + +int mkostemp(char* template, int flags) { + return __mkostemps(template, 0, flags); +} + +LFS64(mkostemp); diff --git a/third_party/ulib/musl/src/temp/mkostemps.c b/third_party/ulib/musl/src/temp/mkostemps.c new file mode 100644 index 000000000..299415bec --- /dev/null +++ b/third_party/ulib/musl/src/temp/mkostemps.c @@ -0,0 +1,29 @@ +#define _BSD_SOURCE +#include "libc.h" +#include +#include +#include +#include + +char* __randname(char*); + +int __mkostemps(char* template, int len, int flags) { + size_t l = strlen(template); + if (l < 6 || len > l - 6 || memcmp(template + l - len - 6, "XXXXXX", 6)) { + errno = EINVAL; + return -1; + } + + flags -= flags & O_ACCMODE; + int fd, retries = 100; + do { + __randname(template + l - len - 6); + if ((fd = open(template, flags | O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) return fd; + } while (--retries && errno == EEXIST); + + memcpy(template + l - len - 6, "XXXXXX", 6); + return -1; +} + +weak_alias(__mkostemps, mkostemps); +weak_alias(__mkostemps, mkostemps64); diff --git a/third_party/ulib/musl/src/temp/mkstemp.c b/third_party/ulib/musl/src/temp/mkstemp.c new file mode 100644 index 000000000..9c9911424 --- /dev/null +++ b/third_party/ulib/musl/src/temp/mkstemp.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include + +int __mkostemps(char*, int, int); + +int mkstemp(char* template) { + return __mkostemps(template, 0, 0); +} + +LFS64(mkstemp); diff --git a/third_party/ulib/musl/src/temp/mkstemps.c b/third_party/ulib/musl/src/temp/mkstemps.c new file mode 100644 index 000000000..8c4a3e136 --- /dev/null +++ b/third_party/ulib/musl/src/temp/mkstemps.c @@ -0,0 +1,11 @@ +#define _BSD_SOURCE +#include "libc.h" +#include + +int __mkostemps(char*, int, int); + +int mkstemps(char* template, int len) { + return __mkostemps(template, len, 0); +} + +LFS64(mkstemps); diff --git a/third_party/ulib/musl/src/temp/mktemp.c b/third_party/ulib/musl/src/temp/mktemp.c new file mode 100644 index 000000000..95220e460 --- /dev/null +++ b/third_party/ulib/musl/src/temp/mktemp.c @@ -0,0 +1,31 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +char* __randname(char*); + +char* mktemp(char* template) { + size_t l = strlen(template); + int retries = 100; + struct stat st; + + if (l < 6 || memcmp(template + l - 6, "XXXXXX", 6)) { + errno = EINVAL; + *template = 0; + return template; + } + + do { + __randname(template + l - 6); + if (stat(template, &st)) { + if (errno != ENOENT) *template = 0; + return template; + } + } while (--retries); + + *template = 0; + errno = EEXIST; + return template; +} diff --git a/third_party/ulib/musl/src/termios/BUILD.gn b/third_party/ulib/musl/src/termios/BUILD.gn new file mode 100644 index 000000000..36afee0bc --- /dev/null +++ b/third_party/ulib/musl/src/termios/BUILD.gn @@ -0,0 +1,18 @@ +source_set("termios") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "cfgetospeed.c", + "cfmakeraw.c", + "cfsetospeed.c", + "tcdrain.c", + "tcflow.c", + "tcflush.c", + "tcgetattr.c", + "tcgetsid.c", + "tcsendbreak.c", + "tcsetattr.c", + ] +} diff --git a/third_party/ulib/musl/src/termios/cfgetospeed.c b/third_party/ulib/musl/src/termios/cfgetospeed.c new file mode 100644 index 000000000..048ced33a --- /dev/null +++ b/third_party/ulib/musl/src/termios/cfgetospeed.c @@ -0,0 +1,10 @@ +#include +#include + +speed_t cfgetospeed(const struct termios* tio) { + return tio->c_cflag & CBAUD; +} + +speed_t cfgetispeed(const struct termios* tio) { + return cfgetospeed(tio); +} diff --git a/third_party/ulib/musl/src/termios/cfmakeraw.c b/third_party/ulib/musl/src/termios/cfmakeraw.c new file mode 100644 index 000000000..9e1a190dc --- /dev/null +++ b/third_party/ulib/musl/src/termios/cfmakeraw.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include + +void cfmakeraw(struct termios* t) { + t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + t->c_cflag &= ~(CSIZE | PARENB); + t->c_cflag |= CS8; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +} diff --git a/third_party/ulib/musl/src/termios/cfsetospeed.c b/third_party/ulib/musl/src/termios/cfsetospeed.c new file mode 100644 index 000000000..88596633d --- /dev/null +++ b/third_party/ulib/musl/src/termios/cfsetospeed.c @@ -0,0 +1,20 @@ +#include "libc.h" +#include +#include +#include + +int cfsetospeed(struct termios* tio, speed_t speed) { + if (speed & ~CBAUD) { + errno = EINVAL; + return -1; + } + tio->c_cflag &= ~CBAUD; + tio->c_cflag |= speed; + return 0; +} + +int cfsetispeed(struct termios* tio, speed_t speed) { + return speed ? cfsetospeed(tio, speed) : 0; +} + +weak_alias(cfsetospeed, cfsetspeed); diff --git a/third_party/ulib/musl/src/termios/tcdrain.c b/third_party/ulib/musl/src/termios/tcdrain.c new file mode 100644 index 000000000..c0cc4020d --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcdrain.c @@ -0,0 +1,8 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int tcdrain(int fd) { + return syscall(SYS_ioctl, fd, TCSBRK, 1); +} diff --git a/third_party/ulib/musl/src/termios/tcflow.c b/third_party/ulib/musl/src/termios/tcflow.c new file mode 100644 index 000000000..c0730052b --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcflow.c @@ -0,0 +1,6 @@ +#include +#include + +int tcflow(int fd, int action) { + return ioctl(fd, TCXONC, action); +} diff --git a/third_party/ulib/musl/src/termios/tcflush.c b/third_party/ulib/musl/src/termios/tcflush.c new file mode 100644 index 000000000..d62f02ba8 --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcflush.c @@ -0,0 +1,6 @@ +#include +#include + +int tcflush(int fd, int queue) { + return ioctl(fd, TCFLSH, queue); +} diff --git a/third_party/ulib/musl/src/termios/tcgetattr.c b/third_party/ulib/musl/src/termios/tcgetattr.c new file mode 100644 index 000000000..f2c0d8981 --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcgetattr.c @@ -0,0 +1,7 @@ +#include +#include + +int tcgetattr(int fd, struct termios* tio) { + if (ioctl(fd, TCGETS, tio)) return -1; + return 0; +} diff --git a/third_party/ulib/musl/src/termios/tcgetsid.c b/third_party/ulib/musl/src/termios/tcgetsid.c new file mode 100644 index 000000000..969524df1 --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcgetsid.c @@ -0,0 +1,8 @@ +#include +#include + +pid_t tcgetsid(int fd) { + int sid; + if (ioctl(fd, TIOCGSID, &sid) < 0) return -1; + return sid; +} diff --git a/third_party/ulib/musl/src/termios/tcsendbreak.c b/third_party/ulib/musl/src/termios/tcsendbreak.c new file mode 100644 index 000000000..0531162c4 --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcsendbreak.c @@ -0,0 +1,7 @@ +#include +#include + +int tcsendbreak(int fd, int dur) { + /* nonzero duration is implementation-defined, so ignore it */ + return ioctl(fd, TCSBRK, 0); +} diff --git a/third_party/ulib/musl/src/termios/tcsetattr.c b/third_party/ulib/musl/src/termios/tcsetattr.c new file mode 100644 index 000000000..7aefe90ed --- /dev/null +++ b/third_party/ulib/musl/src/termios/tcsetattr.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int tcsetattr(int fd, int act, const struct termios* tio) { + if (act < 0 || act > 2) { + errno = EINVAL; + return -1; + } + return ioctl(fd, TCSETS + act, tio); +} diff --git a/third_party/ulib/musl/src/thread/BUILD.gn b/third_party/ulib/musl/src/thread/BUILD.gn new file mode 100644 index 000000000..be7d0e716 --- /dev/null +++ b/third_party/ulib/musl/src/thread/BUILD.gn @@ -0,0 +1,165 @@ +source_set("thread") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__timedwait.c", + "__tls_get_addr.c", + "__wait.c", + "call_once.c", + "cnd_broadcast.c", + "cnd_destroy.c", + "cnd_init.c", + "cnd_signal.c", + "cnd_timedwait.c", + "cnd_wait.c", + "lock_ptc.c", + "mtx_destroy.c", + "mtx_init.c", + "mtx_lock.c", + "mtx_timedlock.c", + "mtx_trylock.c", + "mtx_unlock.c", + "pthread_atfork.c", + "pthread_attr_destroy.c", + "pthread_attr_get.c", + "pthread_attr_init.c", + "pthread_attr_setdetachstate.c", + "pthread_attr_setguardsize.c", + "pthread_attr_setinheritsched.c", + "pthread_attr_setschedparam.c", + "pthread_attr_setschedpolicy.c", + "pthread_attr_setscope.c", + "pthread_attr_setstack.c", + "pthread_attr_setstacksize.c", + + #"pthread_barrier_destroy.c", + "pthread_barrier_init.c", + + #"pthread_barrier_wait.c", + "pthread_barrierattr_destroy.c", + "pthread_barrierattr_init.c", + "pthread_cancel.c", + "pthread_cleanup_push.c", + "pthread_cond_broadcast.c", + "pthread_cond_destroy.c", + "pthread_cond_init.c", + "pthread_cond_signal.c", + "pthread_cond_timedwait.c", + "pthread_cond_wait.c", + "pthread_condattr_destroy.c", + "pthread_condattr_init.c", + "pthread_condattr_setclock.c", + "pthread_create.c", + "pthread_detach.c", + "pthread_equal.c", + "pthread_getattr_np.c", + "pthread_getconcurrency.c", + "pthread_getcpuclockid.c", + "pthread_getschedparam.c", + "pthread_getspecific.c", + "pthread_join.c", + "pthread_key_create.c", + "pthread_kill.c", + "pthread_mutex_consistent.c", + "pthread_mutex_destroy.c", + "pthread_mutex_getprioceiling.c", + "pthread_mutex_init.c", + "pthread_mutex_lock.c", + "pthread_mutex_setprioceiling.c", + "pthread_mutex_timedlock.c", + "pthread_mutex_trylock.c", + "pthread_mutex_unlock.c", + "pthread_mutexattr_destroy.c", + "pthread_mutexattr_init.c", + "pthread_mutexattr_setprotocol.c", + "pthread_mutexattr_setrobust.c", + "pthread_mutexattr_settype.c", + + #"pthread_once.c", + "pthread_rwlock_destroy.c", + "pthread_rwlock_init.c", + "pthread_rwlock_rdlock.c", + "pthread_rwlock_timedrdlock.c", + "pthread_rwlock_timedwrlock.c", + "pthread_rwlock_tryrdlock.c", + "pthread_rwlock_trywrlock.c", + "pthread_rwlock_unlock.c", + "pthread_rwlock_wrlock.c", + "pthread_rwlockattr_destroy.c", + "pthread_rwlockattr_init.c", + "pthread_self.c", + "pthread_setcancelstate.c", + "pthread_setcanceltype.c", + "pthread_setconcurrency.c", + "pthread_setschedparam.c", + "pthread_setschedprio.c", + "pthread_setspecific.c", + "pthread_sigmask.c", + "pthread_spin_destroy.c", + "pthread_spin_init.c", + "pthread_spin_lock.c", + "pthread_spin_trylock.c", + "pthread_spin_unlock.c", + "pthread_testcancel.c", + "sem_destroy.c", + "sem_getvalue.c", + "sem_init.c", + "sem_open.c", + "sem_post.c", + "sem_timedwait.c", + "sem_trywait.c", + "sem_unlink.c", + "sem_wait.c", + "thrd_create.c", + "thrd_exit.c", + "thrd_join.c", + "thrd_sleep.c", + "thrd_yield.c", + "tls.c", + "tss_create.c", + "tss_delete.c", + "tss_set.c", + "vmlock.c", + ] + + if (target_cpu == "arm") { + sources += [ + "arm/__unmapself.s", + "arm/atomics.s", + "arm/clone.s", + "arm/syscall_cp.s", + ] + } else if (target_cpu == "arm64") { + sources += [ + "aarch64/__unmapself.s", + "aarch64/clone.s", + "aarch64/syscall_cp.s", + ] + } else if (target_cpu == "x64") { + sources += [ + "x86_64/clone.s", + "x86_64/syscall_cp.s", + ] + } else { + sources += [ + "__unmapself.c", + "clone.c", + "syscall_cp.c", + ] + deps = [ + ":thread_no_stack_protector", + ] + } +} + +if (target_cpu != "arm" && target_cpu != "arm64" && target_cpu != "x64") { + source_set("thread_no_stack_protector") { + visibility = [ ":thread" ] + configs = [ "//gnbuild:no_stack_protector" ] + sources = [ + "__set_thread_area.c", + ] + } +} diff --git a/third_party/ulib/musl/src/thread/__timedwait.c b/third_party/ulib/musl/src/thread/__timedwait.c new file mode 100644 index 000000000..3397dc949 --- /dev/null +++ b/third_party/ulib/musl/src/thread/__timedwait.c @@ -0,0 +1,44 @@ +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include + +int __pthread_setcancelstate(int, int*); +int __clock_gettime(clockid_t, struct timespec*); + +#define NS_PER_S (1000000000ull) + +int __timedwait_cp(volatile int* addr, int val, clockid_t clk, const struct timespec* at) { + int r; + struct timespec to; + mx_time_t deadline = MX_TIME_INFINITE; + + if (at) { + if (at->tv_nsec >= NS_PER_S) return EINVAL; + if (__clock_gettime(clk, &to)) return EINVAL; + to.tv_sec = at->tv_sec - to.tv_sec; + if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) { + to.tv_sec--; + to.tv_nsec += NS_PER_S; + } + if (to.tv_sec < 0) return ETIMEDOUT; + deadline = to.tv_sec * NS_PER_S; + deadline += to.tv_nsec; + } + + r = _magenta_futex_wait((void*)addr, val, deadline); + // TODO(kulakowski): These return values probably don't make sense + // for a magenta call. + // if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0; + + return r; +} + +int __timedwait(volatile int* addr, int val, clockid_t clk, const struct timespec* at) { + int cs, r; + __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + r = __timedwait_cp(addr, val, clk, at); + __pthread_setcancelstate(cs, 0); + return r; +} diff --git a/third_party/ulib/musl/src/thread/__tls_get_addr.c b/third_party/ulib/musl/src/thread/__tls_get_addr.c new file mode 100644 index 000000000..485fd75b1 --- /dev/null +++ b/third_party/ulib/musl/src/thread/__tls_get_addr.c @@ -0,0 +1,13 @@ +#include "libc.h" +#include "pthread_impl.h" +#include + +__attribute__((__visibility__("hidden"))) void* __tls_get_new(size_t*); + +void* __tls_get_addr(size_t* v) { + pthread_t self = __pthread_self(); + if (v[0] <= (size_t)self->dtv[0]) return (char*)self->dtv[v[0]] + v[1] + DTP_OFFSET; + return __tls_get_new(v); +} + +weak_alias(__tls_get_addr, __tls_get_new); diff --git a/third_party/ulib/musl/src/thread/__unmapself.c b/third_party/ulib/musl/src/thread/__unmapself.c new file mode 100644 index 000000000..51a01f93e --- /dev/null +++ b/third_party/ulib/musl/src/thread/__unmapself.c @@ -0,0 +1,27 @@ +#include "atomic.h" +#include "pthread_impl.h" +#include "syscall.h" +/* cheat and reuse CRTJMP macro from dynlink code */ +#include "dynlink.h" + +static volatile int lock; +static void* unmap_base; +static size_t unmap_size; +static char shared_stack[256]; + +static void do_unmap() { + __syscall(SYS_munmap, unmap_base, unmap_size); + __syscall(SYS_exit); +} + +void __unmapself(void* base, size_t size) { + int tid = __pthread_self()->tid; + char* stack = shared_stack + sizeof shared_stack; + stack -= (uintptr_t)stack % 16; + while (lock || a_cas(&lock, 0, tid)) + a_spin(); + __syscall(SYS_set_tid_address, &lock); + unmap_base = base; + unmap_size = size; + CRTJMP(do_unmap, stack); +} diff --git a/third_party/ulib/musl/src/thread/__wait.c b/third_party/ulib/musl/src/thread/__wait.c new file mode 100644 index 000000000..a6a26d0f3 --- /dev/null +++ b/third_party/ulib/musl/src/thread/__wait.c @@ -0,0 +1,16 @@ +#include "pthread_impl.h" + +void __wait(volatile int* addr, volatile int* waiters, int val) { + int spins = 100; + while (spins-- && (!waiters || !*waiters)) { + if (*addr == val) + a_spin(); + else + return; + } + if (waiters) a_inc(waiters); + while (*addr == val) { + _magenta_futex_wait((void*)addr, val, MX_TIME_INFINITE); + } + if (waiters) a_dec(waiters); +} diff --git a/third_party/ulib/musl/src/thread/aarch64/__unmapself.s b/third_party/ulib/musl/src/thread/aarch64/__unmapself.s new file mode 100644 index 000000000..2c5d254f7 --- /dev/null +++ b/third_party/ulib/musl/src/thread/aarch64/__unmapself.s @@ -0,0 +1,7 @@ +.global __unmapself +.type __unmapself,%function +__unmapself: + mov x8,#215 // SYS_munmap + svc 0 + mov x8,#93 // SYS_exit + svc 0 diff --git a/third_party/ulib/musl/src/thread/aarch64/clone.s b/third_party/ulib/musl/src/thread/aarch64/clone.s new file mode 100644 index 000000000..50af913ce --- /dev/null +++ b/third_party/ulib/musl/src/thread/aarch64/clone.s @@ -0,0 +1,29 @@ +// __clone(func, stack, flags, arg, ptid, tls, ctid) +// x0, x1, w2, x3, x4, x5, x6 + +// syscall(SYS_clone, flags, stack, ptid, tls, ctid) +// x8, x0, x1, x2, x3, x4 + +.global __clone +.type __clone,%function +__clone: + // align stack and save func,arg + and x1,x1,#-16 + stp x0,x3,[x1,#-16]! + + // syscall + uxtw x0,w2 + mov x2,x4 + mov x3,x5 + mov x4,x6 + mov x8,#220 // SYS_clone + svc #0 + + cbz x0,1f + // parent + ret + // child +1: ldp x1,x0,[sp],#16 + blr x1 + mov x8,#93 // SYS_exit + svc #0 diff --git a/third_party/ulib/musl/src/thread/aarch64/syscall_cp.s b/third_party/ulib/musl/src/thread/aarch64/syscall_cp.s new file mode 100644 index 000000000..41db68af9 --- /dev/null +++ b/third_party/ulib/musl/src/thread/aarch64/syscall_cp.s @@ -0,0 +1,32 @@ +// __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z) +// x0 x1 x2 x3 x4 x5 x6 x7 + +// syscall(nr, u, v, w, x, y, z) +// x8 x0 x1 x2 x3 x4 x5 + +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_asm +.hidden __syscall_cp_asm +.type __syscall_cp_asm,%function +__syscall_cp_asm: +__cp_begin: + ldr w0,[x0] + cbnz w0,__cp_cancel + mov x8,x1 + mov x0,x2 + mov x1,x3 + mov x2,x4 + mov x3,x5 + mov x4,x6 + mov x5,x7 + svc 0 +__cp_end: + ret +__cp_cancel: + b __cancel diff --git a/third_party/ulib/musl/src/thread/arm/__unmapself.s b/third_party/ulib/musl/src/thread/arm/__unmapself.s new file mode 100644 index 000000000..29c2d07b1 --- /dev/null +++ b/third_party/ulib/musl/src/thread/arm/__unmapself.s @@ -0,0 +1,9 @@ +.syntax unified +.text +.global __unmapself +.type __unmapself,%function +__unmapself: + mov r7,#91 + svc 0 + mov r7,#1 + svc 0 diff --git a/third_party/ulib/musl/src/thread/arm/atomics.s b/third_party/ulib/musl/src/thread/arm/atomics.s new file mode 100644 index 000000000..673fc03b8 --- /dev/null +++ b/third_party/ulib/musl/src/thread/arm/atomics.s @@ -0,0 +1,113 @@ +.syntax unified +.text + +.global __a_barrier +.hidden __a_barrier +.type __a_barrier,%function +__a_barrier: + ldr ip,1f + ldr ip,[pc,ip] + add pc,pc,ip +1: .word __a_barrier_ptr-1b +.global __a_barrier_dummy +.hidden __a_barrier_dummy +__a_barrier_dummy: + bx lr +.global __a_barrier_oldkuser +.hidden __a_barrier_oldkuser +__a_barrier_oldkuser: + push {r0,r1,r2,r3,ip,lr} + mov r1,r0 + mov r2,sp + ldr ip,=0xffff0fc0 + mov lr,pc + mov pc,ip + pop {r0,r1,r2,r3,ip,lr} + bx lr +.global __a_barrier_v6 +.hidden __a_barrier_v6 +__a_barrier_v6: + mcr p15,0,r0,c7,c10,5 + bx lr +.global __a_barrier_v7 +.hidden __a_barrier_v7 +__a_barrier_v7: + .word 0xf57ff05b /* dmb ish */ + bx lr + +.global __a_cas +.hidden __a_cas +.type __a_cas,%function +__a_cas: + ldr ip,1f + ldr ip,[pc,ip] + add pc,pc,ip +1: .word __a_cas_ptr-1b +.global __a_cas_dummy +.hidden __a_cas_dummy +__a_cas_dummy: + mov r3,r0 + ldr r0,[r2] + subs r0,r3,r0 + streq r1,[r2] + bx lr +.global __a_cas_v6 +.hidden __a_cas_v6 +__a_cas_v6: + mov r3,r0 + mcr p15,0,r0,c7,c10,5 +1: .word 0xe1920f9f /* ldrex r0,[r2] */ + subs r0,r3,r0 + .word 0x01820f91 /* strexeq r0,r1,[r2] */ + teqeq r0,#1 + beq 1b + mcr p15,0,r0,c7,c10,5 + bx lr +.global __a_cas_v7 +.hidden __a_cas_v7 +__a_cas_v7: + mov r3,r0 + .word 0xf57ff05b /* dmb ish */ +1: .word 0xe1920f9f /* ldrex r0,[r2] */ + subs r0,r3,r0 + .word 0x01820f91 /* strexeq r0,r1,[r2] */ + teqeq r0,#1 + beq 1b + .word 0xf57ff05b /* dmb ish */ + bx lr + +.global __aeabi_read_tp +.type __aeabi_read_tp,%function +__aeabi_read_tp: + +.global __a_gettp +.hidden __a_gettp +.type __a_gettp,%function +__a_gettp: + ldr r0,1f + ldr r0,[pc,r0] + add pc,pc,r0 +1: .word __a_gettp_ptr-1b +.global __a_gettp_dummy +.hidden __a_gettp_dummy +__a_gettp_dummy: + mrc p15,0,r0,c13,c0,3 + bx lr + +.data +.align 2 + +.global __a_barrier_ptr +.hidden __a_barrier_ptr +__a_barrier_ptr: + .word 0 + +.global __a_cas_ptr +.hidden __a_cas_ptr +__a_cas_ptr: + .word 0 + +.global __a_gettp_ptr +.hidden __a_gettp_ptr +__a_gettp_ptr: + .word 0 diff --git a/third_party/ulib/musl/src/thread/arm/clone.s b/third_party/ulib/musl/src/thread/arm/clone.s new file mode 100644 index 000000000..fe2e0e60e --- /dev/null +++ b/third_party/ulib/musl/src/thread/arm/clone.s @@ -0,0 +1,31 @@ +.syntax unified +.text +.global __clone +.type __clone,%function +__clone: + stmfd sp!,{r4,r5,r6,r7} + mov r7,#120 + mov r6,r3 + mov r5,r0 + mov r0,r2 + and r1,r1,#-16 + ldr r2,[sp,#16] + ldr r3,[sp,#20] + ldr r4,[sp,#24] + svc 0 + tst r0,r0 + beq 1f + ldmfd sp!,{r4,r5,r6,r7} + bx lr + +1: mov r0,r6 + tst r5,#1 + bne 1f + mov lr,pc + mov pc,r5 +2: mov r7,#1 + svc 0 + +1: mov lr,pc + bx r5 + b 2b diff --git a/third_party/ulib/musl/src/thread/arm/syscall_cp.s b/third_party/ulib/musl/src/thread/arm/syscall_cp.s new file mode 100644 index 000000000..a5730c08b --- /dev/null +++ b/third_party/ulib/musl/src/thread/arm/syscall_cp.s @@ -0,0 +1,29 @@ +.syntax unified +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_asm +.hidden __syscall_cp_asm +.type __syscall_cp_asm,%function +__syscall_cp_asm: + mov ip,sp + stmfd sp!,{r4,r5,r6,r7,lr} +__cp_begin: + ldr r0,[r0] + cmp r0,#0 + blne __cp_cancel + mov r7,r1 + mov r0,r2 + mov r1,r3 + ldmfd ip,{r2,r3,r4,r5,r6} + svc 0 +__cp_end: + ldmfd sp!,{r4,r5,r6,r7,lr} + bx lr +__cp_cancel: + ldmfd sp!,{r4,r5,r6,r7,lr} + b __cancel diff --git a/third_party/ulib/musl/src/thread/call_once.c b/third_party/ulib/musl/src/thread/call_once.c new file mode 100644 index 000000000..fd17290a8 --- /dev/null +++ b/third_party/ulib/musl/src/thread/call_once.c @@ -0,0 +1,7 @@ +#include + +int __pthread_once(once_flag*, void (*)(void)); + +void call_once(once_flag* flag, void (*func)(void)) { + __pthread_once(flag, func); +} diff --git a/third_party/ulib/musl/src/thread/clone.c b/third_party/ulib/musl/src/thread/clone.c new file mode 100644 index 000000000..d1057c4e6 --- /dev/null +++ b/third_party/ulib/musl/src/thread/clone.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" +#include + +int __clone(int (*func)(void*), void* stack, int flags, void* arg, ...) { + return -ENOSYS; +} diff --git a/third_party/ulib/musl/src/thread/cnd_broadcast.c b/third_party/ulib/musl/src/thread/cnd_broadcast.c new file mode 100644 index 000000000..7b4803c53 --- /dev/null +++ b/third_party/ulib/musl/src/thread/cnd_broadcast.c @@ -0,0 +1,9 @@ +#include + +int __private_cond_signal(cnd_t*, int); + +int cnd_broadcast(cnd_t* c) { + /* This internal function never fails, and always returns zero, + * which matches the value thrd_success is defined with. */ + return __private_cond_signal(c, -1); +} diff --git a/third_party/ulib/musl/src/thread/cnd_destroy.c b/third_party/ulib/musl/src/thread/cnd_destroy.c new file mode 100644 index 000000000..8291755d7 --- /dev/null +++ b/third_party/ulib/musl/src/thread/cnd_destroy.c @@ -0,0 +1,5 @@ +#include + +void cnd_destroy(cnd_t* c) { + /* For private cv this is a no-op */ +} diff --git a/third_party/ulib/musl/src/thread/cnd_init.c b/third_party/ulib/musl/src/thread/cnd_init.c new file mode 100644 index 000000000..09dc664cd --- /dev/null +++ b/third_party/ulib/musl/src/thread/cnd_init.c @@ -0,0 +1,6 @@ +#include + +int cnd_init(cnd_t* c) { + *c = (cnd_t){0}; + return thrd_success; +} diff --git a/third_party/ulib/musl/src/thread/cnd_signal.c b/third_party/ulib/musl/src/thread/cnd_signal.c new file mode 100644 index 000000000..1750a5a1d --- /dev/null +++ b/third_party/ulib/musl/src/thread/cnd_signal.c @@ -0,0 +1,9 @@ +#include + +int __private_cond_signal(cnd_t*, int); + +int cnd_signal(cnd_t* c) { + /* This internal function never fails, and always returns zero, + * which matches the value thrd_success is defined with. */ + return __private_cond_signal(c, 1); +} diff --git a/third_party/ulib/musl/src/thread/cnd_timedwait.c b/third_party/ulib/musl/src/thread/cnd_timedwait.c new file mode 100644 index 000000000..145d4442e --- /dev/null +++ b/third_party/ulib/musl/src/thread/cnd_timedwait.c @@ -0,0 +1,17 @@ +#include +#include + +int __pthread_cond_timedwait(cnd_t* restrict, mtx_t* restrict, const struct timespec* restrict); + +int cnd_timedwait(cnd_t* restrict c, mtx_t* restrict m, const struct timespec* restrict ts) { + int ret = __pthread_cond_timedwait(c, m, ts); + switch (ret) { + /* May also return EINVAL or EPERM. */ + default: + return thrd_error; + case 0: + return thrd_success; + case ETIMEDOUT: + return thrd_timedout; + } +} diff --git a/third_party/ulib/musl/src/thread/cnd_wait.c b/third_party/ulib/musl/src/thread/cnd_wait.c new file mode 100644 index 000000000..57d16eb5e --- /dev/null +++ b/third_party/ulib/musl/src/thread/cnd_wait.c @@ -0,0 +1,8 @@ +#include + +int cnd_wait(cnd_t* c, mtx_t* m) { + /* Calling cnd_timedwait with a null pointer is an extension. + * It is convenient here to avoid duplication of the logic + * for return values. */ + return cnd_timedwait(c, m, 0); +} diff --git a/third_party/ulib/musl/src/thread/lock_ptc.c b/third_party/ulib/musl/src/thread/lock_ptc.c new file mode 100644 index 000000000..da840a466 --- /dev/null +++ b/third_party/ulib/musl/src/thread/lock_ptc.c @@ -0,0 +1,15 @@ +#include + +static pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; + +void __inhibit_ptc(void) { + pthread_rwlock_wrlock(&lock); +} + +void __acquire_ptc(void) { + pthread_rwlock_rdlock(&lock); +} + +void __release_ptc(void) { + pthread_rwlock_unlock(&lock); +} diff --git a/third_party/ulib/musl/src/thread/mtx_destroy.c b/third_party/ulib/musl/src/thread/mtx_destroy.c new file mode 100644 index 000000000..acd77ecbf --- /dev/null +++ b/third_party/ulib/musl/src/thread/mtx_destroy.c @@ -0,0 +1,3 @@ +#include + +void mtx_destroy(mtx_t* mtx) {} diff --git a/third_party/ulib/musl/src/thread/mtx_init.c b/third_party/ulib/musl/src/thread/mtx_init.c new file mode 100644 index 000000000..ca65171db --- /dev/null +++ b/third_party/ulib/musl/src/thread/mtx_init.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" +#include + +int mtx_init(mtx_t* m, int type) { + *m = (mtx_t){ + ._m_type = ((type & mtx_recursive) ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL), + }; + return thrd_success; +} diff --git a/third_party/ulib/musl/src/thread/mtx_lock.c b/third_party/ulib/musl/src/thread/mtx_lock.c new file mode 100644 index 000000000..95a06600a --- /dev/null +++ b/third_party/ulib/musl/src/thread/mtx_lock.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" +#include + +int mtx_lock(mtx_t* m) { + if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) return thrd_success; + /* Calling mtx_timedlock with a null pointer is an extension. + * It is convenient, here to avoid duplication of the logic + * for return values. */ + return mtx_timedlock(m, 0); +} diff --git a/third_party/ulib/musl/src/thread/mtx_timedlock.c b/third_party/ulib/musl/src/thread/mtx_timedlock.c new file mode 100644 index 000000000..a401099c3 --- /dev/null +++ b/third_party/ulib/musl/src/thread/mtx_timedlock.c @@ -0,0 +1,16 @@ +#include +#include + +int __pthread_mutex_timedlock(mtx_t* restrict, const struct timespec* restrict); + +int mtx_timedlock(mtx_t* restrict m, const struct timespec* restrict ts) { + int ret = __pthread_mutex_timedlock(m, ts); + switch (ret) { + default: + return thrd_error; + case 0: + return thrd_success; + case ETIMEDOUT: + return thrd_timedout; + } +} diff --git a/third_party/ulib/musl/src/thread/mtx_trylock.c b/third_party/ulib/musl/src/thread/mtx_trylock.c new file mode 100644 index 000000000..730a967cc --- /dev/null +++ b/third_party/ulib/musl/src/thread/mtx_trylock.c @@ -0,0 +1,19 @@ +#include "pthread_impl.h" +#include + +int __pthread_mutex_trylock(mtx_t*); + +int mtx_trylock(mtx_t* m) { + if (m->_m_type == PTHREAD_MUTEX_NORMAL) + return (a_cas(&m->_m_lock, 0, EBUSY) & EBUSY) ? thrd_busy : thrd_success; + + int ret = __pthread_mutex_trylock(m); + switch (ret) { + default: + return thrd_error; + case 0: + return thrd_success; + case EBUSY: + return thrd_busy; + } +} diff --git a/third_party/ulib/musl/src/thread/mtx_unlock.c b/third_party/ulib/musl/src/thread/mtx_unlock.c new file mode 100644 index 000000000..5a1a71f63 --- /dev/null +++ b/third_party/ulib/musl/src/thread/mtx_unlock.c @@ -0,0 +1,10 @@ +#include + +int __pthread_mutex_unlock(mtx_t*); + +int mtx_unlock(mtx_t* mtx) { + /* The only cases where pthread_mutex_unlock can return an + * error are undefined behavior for C11 mtx_unlock, so we can + * assume it does not return an error and simply tail call. */ + return __pthread_mutex_unlock(mtx); +} diff --git a/third_party/ulib/musl/src/thread/pthread_atfork.c b/third_party/ulib/musl/src/thread/pthread_atfork.c new file mode 100644 index 000000000..723fe5ff3 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_atfork.c @@ -0,0 +1,50 @@ +#include "libc.h" +#include + +#include + +static struct atfork_funcs { + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); + struct atfork_funcs *prev, *next; +} * funcs; + +static mxr_mutex_t lock; + +void __fork_handler(int who) { + struct atfork_funcs* p; + if (!funcs) return; + if (who < 0) { + mxr_mutex_lock(&lock); + for (p = funcs; p; p = p->next) { + if (p->prepare) p->prepare(); + funcs = p; + } + } else { + for (p = funcs; p; p = p->prev) { + if (!who && p->parent) + p->parent(); + else if (who && p->child) + p->child(); + funcs = p; + } + mxr_mutex_unlock(&lock); + } +} + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { + struct atfork_funcs* new = malloc(sizeof *new); + if (!new) return -1; + + mxr_mutex_lock(&lock); + new->next = funcs; + new->prev = 0; + new->prepare = prepare; + new->parent = parent; + new->child = child; + if (funcs) funcs->prev = new; + funcs = new; + mxr_mutex_unlock(&lock); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_destroy.c b/third_party/ulib/musl/src/thread/pthread_attr_destroy.c new file mode 100644 index 000000000..9ed1d3a47 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_attr_destroy(pthread_attr_t* a) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_get.c b/third_party/ulib/musl/src/thread/pthread_attr_get.c new file mode 100644 index 000000000..663d4fb50 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_get.c @@ -0,0 +1,63 @@ +#include "pthread_impl.h" + +int pthread_attr_getdetachstate(const pthread_attr_t* a, int* state) { + *state = a->_a_detach; + return 0; +} +int pthread_attr_getguardsize(const pthread_attr_t* restrict a, size_t* restrict size) { + *size = a->_a_guardsize + DEFAULT_GUARD_SIZE; + return 0; +} + +int pthread_attr_getinheritsched(const pthread_attr_t* restrict a, int* restrict inherit) { + *inherit = a->_a_sched; + return 0; +} + +int pthread_attr_getschedparam(const pthread_attr_t* restrict a, + struct sched_param* restrict param) { + param->sched_priority = a->_a_prio; + return 0; +} + +int pthread_attr_getschedpolicy(const pthread_attr_t* restrict a, int* restrict policy) { + *policy = a->_a_policy; + return 0; +} + +int pthread_attr_getscope(const pthread_attr_t* restrict a, int* restrict scope) { + *scope = PTHREAD_SCOPE_SYSTEM; + return 0; +} + +int pthread_attr_getstack(const pthread_attr_t* restrict a, void** restrict addr, + size_t* restrict size) { + if (!a->_a_stackaddr) return EINVAL; + *size = a->_a_stacksize + DEFAULT_STACK_SIZE; + *addr = (void*)(a->_a_stackaddr - *size); + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t* restrict a, size_t* restrict size) { + *size = a->_a_stacksize + DEFAULT_STACK_SIZE; + return 0; +} + +int pthread_condattr_getclock(const pthread_condattr_t* restrict a, clockid_t* restrict clk) { + *clk = a->__attr & 0x7fffffff; + return 0; +} + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t* restrict a, int* restrict protocol) { + *protocol = PTHREAD_PRIO_NONE; + return 0; +} +int pthread_mutexattr_getrobust(const pthread_mutexattr_t* restrict a, int* restrict robust) { + *robust = a->__attr / 4U % 2; + return 0; +} + +int pthread_mutexattr_gettype(const pthread_mutexattr_t* restrict a, int* restrict type) { + *type = a->__attr & 3; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_init.c b/third_party/ulib/musl/src/thread/pthread_attr_init.c new file mode 100644 index 000000000..751e9903c --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_init(pthread_attr_t* a) { + *a = (pthread_attr_t){0}; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setdetachstate.c b/third_party/ulib/musl/src/thread/pthread_attr_setdetachstate.c new file mode 100644 index 000000000..f979fd751 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setdetachstate.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setdetachstate(pthread_attr_t* a, int state) { + if (state > 1U) return EINVAL; + a->_a_detach = state; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setguardsize.c b/third_party/ulib/musl/src/thread/pthread_attr_setguardsize.c new file mode 100644 index 000000000..99de3c8a6 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setguardsize.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setguardsize(pthread_attr_t* a, size_t size) { + if (size > SIZE_MAX / 8) return EINVAL; + a->_a_guardsize = size - DEFAULT_GUARD_SIZE; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setinheritsched.c b/third_party/ulib/musl/src/thread/pthread_attr_setinheritsched.c new file mode 100644 index 000000000..adc775558 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setinheritsched.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setinheritsched(pthread_attr_t* a, int inherit) { + if (inherit > 1U) return EINVAL; + a->_a_sched = inherit; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setschedparam.c b/third_party/ulib/musl/src/thread/pthread_attr_setschedparam.c new file mode 100644 index 000000000..5106b1dc4 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setschedparam.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setschedparam(pthread_attr_t* restrict a, + const struct sched_param* restrict param) { + a->_a_prio = param->sched_priority; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setschedpolicy.c b/third_party/ulib/musl/src/thread/pthread_attr_setschedpolicy.c new file mode 100644 index 000000000..1a26424b9 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setschedpolicy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_setschedpolicy(pthread_attr_t* a, int policy) { + a->_a_policy = policy; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setscope.c b/third_party/ulib/musl/src/thread/pthread_attr_setscope.c new file mode 100644 index 000000000..f464200f4 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setscope.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" + +int pthread_attr_setscope(pthread_attr_t* a, int scope) { + switch (scope) { + case PTHREAD_SCOPE_SYSTEM: + return 0; + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + default: + return EINVAL; + } +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setstack.c b/third_party/ulib/musl/src/thread/pthread_attr_setstack.c new file mode 100644 index 000000000..1b9f688cd --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setstack.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_attr_setstack(pthread_attr_t* a, void* addr, size_t size) { + if (size - PTHREAD_STACK_MIN > SIZE_MAX / 4) return EINVAL; + a->_a_stackaddr = (size_t)addr + size; + a->_a_stacksize = size - DEFAULT_STACK_SIZE; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_attr_setstacksize.c b/third_party/ulib/musl/src/thread/pthread_attr_setstacksize.c new file mode 100644 index 000000000..14a20b8b6 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_attr_setstacksize.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_attr_setstacksize(pthread_attr_t* a, size_t size) { + if (size - PTHREAD_STACK_MIN > SIZE_MAX / 4) return EINVAL; + a->_a_stackaddr = 0; + a->_a_stacksize = size - DEFAULT_STACK_SIZE; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_barrier_destroy.c b/third_party/ulib/musl/src/thread/pthread_barrier_destroy.c new file mode 100644 index 000000000..a292a733f --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_barrier_destroy.c @@ -0,0 +1,14 @@ +#include "pthread_impl.h" + +int pthread_barrier_destroy(pthread_barrier_t* b) { + if (b->_b_limit < 0) { + if (b->_b_lock) { + int v; + a_or(&b->_b_lock, INT_MIN); + while ((v = b->_b_lock) & INT_MAX) + __wait(&b->_b_lock, 0, v); + } + __vm_wait(); + } + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_barrier_init.c b/third_party/ulib/musl/src/thread/pthread_barrier_init.c new file mode 100644 index 000000000..58a4ab801 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_barrier_init.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_barrier_init(pthread_barrier_t* restrict b, const pthread_barrierattr_t* restrict a, + unsigned count) { + if (count - 1 > INT_MAX - 1) return EINVAL; + *b = (pthread_barrier_t){._b_limit = count - 1 | (a ? a->__attr : 0)}; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_barrier_wait.c b/third_party/ulib/musl/src/thread/pthread_barrier_wait.c new file mode 100644 index 000000000..0c23b2c88 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_barrier_wait.c @@ -0,0 +1,105 @@ +#include "pthread_impl.h" + +static int pshared_barrier_wait(pthread_barrier_t* b) { + int limit = (b->_b_limit & INT_MAX) + 1; + int ret = 0; + int v, w; + + if (limit == 1) return PTHREAD_BARRIER_SERIAL_THREAD; + + while ((v = a_cas(&b->_b_lock, 0, limit))) + __wait(&b->_b_lock, &b->_b_waiters, v); + + /* Wait for threads to get to the barrier */ + if (++b->_b_count == limit) { + a_store(&b->_b_count, 0); + ret = PTHREAD_BARRIER_SERIAL_THREAD; + if (b->_b_waiters2) __wake(&b->_b_count, -1); + } else { + a_store(&b->_b_lock, 0); + if (b->_b_waiters) __wake(&b->_b_lock, 1); + while ((v = b->_b_count) > 0) + __wait(&b->_b_count, &b->_b_waiters2, v); + } + + __vm_lock(); + + /* Ensure all threads have a vm lock before proceeding */ + if (a_fetch_add(&b->_b_count, -1) == 1 - limit) { + a_store(&b->_b_count, 0); + if (b->_b_waiters2) __wake(&b->_b_count, -1); + } else { + while ((v = b->_b_count)) + __wait(&b->_b_count, &b->_b_waiters2, v); + } + + /* Perform a recursive unlock suitable for self-sync'd destruction */ + do { + v = b->_b_lock; + w = b->_b_waiters; + } while (a_cas(&b->_b_lock, v, v == INT_MIN + 1 ? 0 : v - 1) != v); + + /* Wake a thread waiting to reuse or destroy the barrier */ + if (v == INT_MIN + 1 || (v == 1 && w)) __wake(&b->_b_lock, 1); + + __vm_unlock(); + + return ret; +} + +struct instance { + volatile int count; + volatile int last; + volatile int waiters; + volatile int finished; +}; + +int pthread_barrier_wait(pthread_barrier_t* b) { + int limit = b->_b_limit; + struct instance* inst; + + /* Trivial case: count was set at 1 */ + if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD; + + /* Process-shared barriers require a separate, inefficient wait */ + if (limit < 0) return pshared_barrier_wait(b); + + /* Otherwise we need a lock on the barrier object */ + while (a_swap(&b->_b_lock, 1)) + __wait(&b->_b_lock, &b->_b_waiters, 1); + inst = b->_b_inst; + + /* First thread to enter the barrier becomes the "instance owner" */ + if (!inst) { + struct instance new_inst = {0}; + int spins = 200; + b->_b_inst = inst = &new_inst; + a_store(&b->_b_lock, 0); + if (b->_b_waiters) __wake(&b->_b_lock, 1); + while (spins-- && !inst->finished) + a_spin(); + a_inc(&inst->finished); + while (inst->finished == 1) + _magenta_futex_wait(&inst->finished, 1, MX_TIME_INFINITE); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + + /* Last thread to enter the barrier wakes all non-instance-owners */ + if (++inst->count == limit) { + b->_b_inst = 0; + a_store(&b->_b_lock, 0); + if (b->_b_waiters) __wake(&b->_b_lock, 1); + a_store(&inst->last, 1); + if (inst->waiters) __wake(&inst->last, -1); + } else { + a_store(&b->_b_lock, 0); + if (b->_b_waiters) __wake(&b->_b_lock, 1); + __wait(&inst->last, &inst->waiters, 0); + } + + /* Last thread to exit the barrier wakes the instance owner */ + if (a_fetch_add(&inst->count, -1) == 1 && a_fetch_add(&inst->finished, 1)) + __wake(&inst->finished, 1); + + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_barrierattr_destroy.c b/third_party/ulib/musl/src/thread/pthread_barrierattr_destroy.c new file mode 100644 index 000000000..d2e315fa9 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_barrierattr_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_barrierattr_destroy(pthread_barrierattr_t* a) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_barrierattr_init.c b/third_party/ulib/musl/src/thread/pthread_barrierattr_init.c new file mode 100644 index 000000000..c0aabd8bd --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_barrierattr_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_barrierattr_init(pthread_barrierattr_t* a) { + *a = (pthread_barrierattr_t){0}; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_cancel.c b/third_party/ulib/musl/src/thread/pthread_cancel.c new file mode 100644 index 000000000..a8cdf0756 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cancel.c @@ -0,0 +1,81 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "pthread_impl.h" +#include "syscall.h" +#include + +long __cancel(void) { + pthread_t self = __pthread_self(); + if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync) + pthread_exit(PTHREAD_CANCELED); + self->canceldisable = PTHREAD_CANCEL_DISABLE; + return -ECANCELED; +} + +long __syscall_cp_asm(volatile void*, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t); + +long __syscall_cp_c(syscall_arg_t nr, syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) { + pthread_t self; + long r; + int st; + + if ((st = (self = __pthread_self())->canceldisable) && + (st == PTHREAD_CANCEL_DISABLE || nr == SYS_close)) + return __syscall(nr, u, v, w, x, y, z); + + r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); + if (r == -EINTR && nr != SYS_close && self->cancel && + self->canceldisable != PTHREAD_CANCEL_DISABLE) + r = __cancel(); + return r; +} + +static void _sigaddset(sigset_t* set, int sig) { + unsigned s = sig - 1; + set->__bits[s / 8 / sizeof *set->__bits] |= 1UL << (s & 8 * sizeof *set->__bits - 1); +} + +__attribute__((__visibility__("hidden"))) extern const char __cp_begin[1], __cp_end[1], + __cp_cancel[1]; + +static void cancel_handler(int sig, siginfo_t* si, void* ctx) { + pthread_t self = __pthread_self(); + ucontext_t* uc = ctx; + uintptr_t pc = uc->uc_mcontext.MC_PC; + + a_barrier(); + if (!self->cancel || self->canceldisable == PTHREAD_CANCEL_DISABLE) return; + + _sigaddset(&uc->uc_sigmask, SIGCANCEL); + + if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { + uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel; + return; + } + + __syscall(SYS_tkill, self->tid, SIGCANCEL); +} + +void __testcancel(void) { + pthread_t self = __pthread_self(); + if (self->cancel && !self->canceldisable) __cancel(); +} + +static void init_cancellation(void) { + struct sigaction sa = {.sa_flags = SA_SIGINFO | SA_RESTART, .sa_sigaction = cancel_handler}; + memset(&sa.sa_mask, -1, _NSIG / 8); + __libc_sigaction(SIGCANCEL, &sa, 0); +} + +int pthread_cancel(pthread_t t) { + static int init; + if (!init) { + init_cancellation(); + init = 1; + } + a_store(&t->cancel, 1); + if (t == pthread_self() && !t->cancelasync) return 0; + return pthread_kill(t, SIGCANCEL); +} diff --git a/third_party/ulib/musl/src/thread/pthread_cleanup_push.c b/third_party/ulib/musl/src/thread/pthread_cleanup_push.c new file mode 100644 index 000000000..8ff751d95 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cleanup_push.c @@ -0,0 +1,16 @@ +#include "pthread_impl.h" + +static void dummy(struct __ptcb* cb) {} +weak_alias(dummy, __do_cleanup_push); +weak_alias(dummy, __do_cleanup_pop); + +void _pthread_cleanup_push(struct __ptcb* cb, void (*f)(void*), void* x) { + cb->__f = f; + cb->__x = x; + __do_cleanup_push(cb); +} + +void _pthread_cleanup_pop(struct __ptcb* cb, int run) { + __do_cleanup_pop(cb); + if (run) cb->__f(cb->__x); +} diff --git a/third_party/ulib/musl/src/thread/pthread_cond_broadcast.c b/third_party/ulib/musl/src/thread/pthread_cond_broadcast.c new file mode 100644 index 000000000..0e06c42cc --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cond_broadcast.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int __private_cond_signal(pthread_cond_t*, int); + +int pthread_cond_broadcast(pthread_cond_t* c) { + if (!c->_c_shared) return __private_cond_signal(c, -1); + if (!c->_c_waiters) return 0; + a_inc(&c->_c_seq); + __wake(&c->_c_seq, -1); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_cond_destroy.c b/third_party/ulib/musl/src/thread/pthread_cond_destroy.c new file mode 100644 index 000000000..2b44d8fc4 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cond_destroy.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_cond_destroy(pthread_cond_t* c) { + if (c->_c_shared && c->_c_waiters) { + int cnt; + a_or(&c->_c_waiters, 0x80000000); + a_inc(&c->_c_seq); + __wake(&c->_c_seq, -1); + while ((cnt = c->_c_waiters) & 0x7fffffff) + __wait(&c->_c_waiters, 0, cnt); + } + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_cond_init.c b/third_party/ulib/musl/src/thread/pthread_cond_init.c new file mode 100644 index 000000000..7ee589ace --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cond_init.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int pthread_cond_init(pthread_cond_t* restrict c, const pthread_condattr_t* restrict a) { + *c = (pthread_cond_t){0}; + if (a) { + c->_c_clock = a->__attr & 0x7fffffff; + if (a->__attr >> 31) c->_c_shared = (void*)-1; + } + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_cond_signal.c b/third_party/ulib/musl/src/thread/pthread_cond_signal.c new file mode 100644 index 000000000..f36c27214 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cond_signal.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int __private_cond_signal(pthread_cond_t*, int); + +int pthread_cond_signal(pthread_cond_t* c) { + if (!c->_c_shared) return __private_cond_signal(c, 1); + if (!c->_c_waiters) return 0; + a_inc(&c->_c_seq); + __wake(&c->_c_seq, 1); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_cond_timedwait.c b/third_party/ulib/musl/src/thread/pthread_cond_timedwait.c new file mode 100644 index 000000000..3f5ab357d --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cond_timedwait.c @@ -0,0 +1,199 @@ +#include "pthread_impl.h" + +void __pthread_testcancel(void); +int __pthread_mutex_lock(pthread_mutex_t*); +int __pthread_mutex_unlock(pthread_mutex_t*); +int __pthread_setcancelstate(int, int*); + +/* + * struct waiter + * + * Waiter objects have automatic storage on the waiting thread, and + * are used in building a linked list representing waiters currently + * waiting on the condition variable or a group of waiters woken + * together by a broadcast or signal; in the case of signal, this is a + * degenerate list of one member. + * + * Waiter lists attached to the condition variable itself are + * protected by the lock on the cv. Detached waiter lists are never + * modified again, but can only be traversed in reverse order, and are + * protected by the "barrier" locks in each node, which are unlocked + * in turn to control wake order. + * + * Since process-shared cond var semantics do not necessarily allow + * one thread to see another's automatic storage (they may be in + * different processes), the waiter list is not used for the + * process-shared case, but the structure is still used to store data + * needed by the cancellation cleanup handler. + */ + +struct waiter { + struct waiter *prev, *next; + volatile int state, barrier; + volatile int* notify; +}; + +/* Self-synchronized-destruction-safe lock functions */ + +static inline void lock(volatile int* l) { + if (a_cas(l, 0, 1)) { + a_cas(l, 1, 2); + do + __wait(l, 0, 2); + while (a_cas(l, 0, 2)); + } +} + +static inline void unlock(volatile int* l) { + if (a_swap(l, 0) == 2) __wake(l, 1); +} + +static inline void unlock_requeue(volatile int* l, volatile int* r, int w) { + a_store(l, 0); + if (w) + __wake(l, 1); + else + _magenta_futex_requeue((void*)l, /* wake count */ 0, /* l futex value */ 0, (void*)r, + /* requeue count */ 1); +} + +enum { + WAITING, + SIGNALED, + LEAVING, +}; + +int __pthread_cond_timedwait(pthread_cond_t* restrict c, pthread_mutex_t* restrict m, + const struct timespec* restrict ts) { + struct waiter node = {0}; + int e, seq, clock = c->_c_clock, cs, oldstate, tmp; + volatile int* fut; + + if ((m->_m_type & 15) && (m->_m_lock & INT_MAX) != __pthread_self()->tid) return EPERM; + + if (ts && ts->tv_nsec >= 1000000000UL) return EINVAL; + + __pthread_testcancel(); + + lock(&c->_c_lock); + + seq = node.barrier = 2; + fut = &node.barrier; + node.state = WAITING; + node.next = c->_c_head; + c->_c_head = &node; + if (!c->_c_tail) + c->_c_tail = &node; + else + node.next->prev = &node; + + unlock(&c->_c_lock); + + __pthread_mutex_unlock(m); + + __pthread_setcancelstate(PTHREAD_CANCEL_MASKED, &cs); + if (cs == PTHREAD_CANCEL_DISABLE) __pthread_setcancelstate(cs, 0); + + do + e = __timedwait_cp(fut, seq, clock, ts); + while (*fut == seq && (!e || e == EINTR)); + if (e == EINTR) e = 0; + + oldstate = a_cas(&node.state, WAITING, LEAVING); + + if (oldstate == WAITING) { + /* Access to cv object is valid because this waiter was not + * yet signaled and a new signal/broadcast cannot return + * after seeing a LEAVING waiter without getting notified + * via the futex notify below. */ + + lock(&c->_c_lock); + + if (c->_c_head == &node) + c->_c_head = node.next; + else if (node.prev) + node.prev->next = node.next; + if (c->_c_tail == &node) + c->_c_tail = node.prev; + else if (node.next) + node.next->prev = node.prev; + + unlock(&c->_c_lock); + + if (node.notify) { + if (a_fetch_add(node.notify, -1) == 1) __wake(node.notify, 1); + } + } else { + /* Lock barrier first to control wake order. */ + lock(&node.barrier); + } + +relock: + /* Errors locking the mutex override any existing error or + * cancellation, since the caller must see them to know the + * state of the mutex. */ + if ((tmp = pthread_mutex_lock(m))) e = tmp; + + if (oldstate == WAITING) goto done; + + if (!node.next) a_inc(&m->_m_waiters); + + /* Unlock the barrier that's holding back the next waiter, and + * either wake it or requeue it to the mutex. */ + if (node.prev) + unlock_requeue(&node.prev->barrier, &m->_m_lock, m->_m_type & 128); + else + a_dec(&m->_m_waiters); + + /* Since a signal was consumed, cancellation is not permitted. */ + if (e == ECANCELED) e = 0; + +done: + __pthread_setcancelstate(cs, 0); + + if (e == ECANCELED) { + __pthread_testcancel(); + __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + } + + return e; +} + +int __private_cond_signal(pthread_cond_t* c, int n) { + struct waiter *p, *first = 0; + volatile int ref = 0; + int cur; + + lock(&c->_c_lock); + for (p = c->_c_tail; n && p; p = p->prev) { + if (a_cas(&p->state, WAITING, SIGNALED) != WAITING) { + ref++; + p->notify = &ref; + } else { + n--; + if (!first) first = p; + } + } + /* Split the list, leaving any remainder on the cv. */ + if (p) { + if (p->next) p->next->prev = 0; + p->next = 0; + } else { + c->_c_head = 0; + } + c->_c_tail = p; + unlock(&c->_c_lock); + + /* Wait for any waiters in the LEAVING state to remove + * themselves from the list before returning or allowing + * signaled threads to proceed. */ + while ((cur = ref)) + __wait(&ref, 0, cur); + + /* Allow first signaled waiter, if any, to proceed. */ + if (first) unlock(&first->barrier); + + return 0; +} + +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait); diff --git a/third_party/ulib/musl/src/thread/pthread_cond_wait.c b/third_party/ulib/musl/src/thread/pthread_cond_wait.c new file mode 100644 index 000000000..a08f8288f --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_cond_wait.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_cond_wait(pthread_cond_t* restrict c, pthread_mutex_t* restrict m) { + return pthread_cond_timedwait(c, m, 0); +} diff --git a/third_party/ulib/musl/src/thread/pthread_condattr_destroy.c b/third_party/ulib/musl/src/thread/pthread_condattr_destroy.c new file mode 100644 index 000000000..a4e3148f5 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_condattr_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_condattr_destroy(pthread_condattr_t* a) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_condattr_init.c b/third_party/ulib/musl/src/thread/pthread_condattr_init.c new file mode 100644 index 000000000..02e7a04c0 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_condattr_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_condattr_init(pthread_condattr_t* a) { + *a = (pthread_condattr_t){0}; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_condattr_setclock.c b/third_party/ulib/musl/src/thread/pthread_condattr_setclock.c new file mode 100644 index 000000000..0a0eb38ab --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_condattr_setclock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_condattr_setclock(pthread_condattr_t* a, clockid_t clk) { + if (clk < 0 || clk - 2U < 2) return EINVAL; + a->__attr &= 0x80000000; + a->__attr |= clk; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_create.c b/third_party/ulib/musl/src/thread/pthread_create.c new file mode 100644 index 000000000..86fc13d3a --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_create.c @@ -0,0 +1,208 @@ +#define _GNU_SOURCE + +#include "pthread_impl.h" + +#include +#include +#include +#include +#include + +#define ROUND(x) (((x) + PAGE_SIZE - 1) & -PAGE_SIZE) + +/* pthread_key_create.c overrides this */ +static volatile size_t dummy = 0; +weak_alias(dummy, __pthread_tsd_size); + +static void dummy_0(void) {} +weak_alias(dummy_0, __acquire_ptc); +weak_alias(dummy_0, __dl_thread_cleanup); +weak_alias(dummy_0, __do_orphaned_stdio_locks); +weak_alias(dummy_0, __pthread_tsd_run_dtors); +weak_alias(dummy_0, __release_ptc); + +void* __mmap(void*, size_t, int, int, int, off_t); +int __munmap(void*, size_t); + +static int thread_entry(void* arg) { + struct __mx_thread_info* ei = arg; + if (ei->tls) { + mxr_tls_root_set(ei->tls); + mxr_tls_set(MXR_TLS_SLOT_ERRNO, &ei->errno_value); + } + ei->func(ei->arg); + _magenta_thread_exit(); + return 0; +} + +int pthread_create(pthread_t* restrict res, const pthread_attr_t* restrict attrp, + void* (*entry)(void*), void* restrict arg) { + mx_handle_t handle; + + mx_tls_root_t* self_tls = mxr_tls_root_get(); + size_t len; + mx_proc_info_t* proc = NULL; + if (self_tls) { + proc = self_tls->proc; + len = ROUND(sizeof(struct pthread) + sizeof(mx_tls_root_t) + (sizeof(void*) * (MX_TLS_MIN_SLOTS - 1)) + __pthread_tsd_size); + } else { + len = ROUND(sizeof(struct pthread)); + } + + void* map = __mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (map == MAP_FAILED) + return ERR_NO_MEMORY; + pthread_t thread = map; + thread->map_base = map; + thread->mx_thread_info.func = entry; + thread->mx_thread_info.arg = arg; + thread->map_size = len; + + if (self_tls) { + mx_tls_root_t* tls = map + sizeof(*thread); + tls->magic = MX_TLS_ROOT_MAGIC; + tls->flags = 0; + tls->maxslots = MX_TLS_MIN_SLOTS; + tls->proc = proc; + tls->self = tls; + + tls->slots[__pthread_key] = thread; + thread->mx_thread_info.tls = tls; + thread->tsd = map + len - __pthread_tsd_size; + } + + handle = _magenta_thread_create(thread_entry, &thread->mx_thread_info, + "musl", 5); + if (handle < 0) { + __munmap(map, len); + return handle; + } else { + thread->self = thread; + thread->handle = handle; + *res = thread; + return 0; + } +} + +_Noreturn void pthread_exit(void* result) { + pthread_t self = __pthread_self(); + sigset_t set; + + self->canceldisable = 1; + self->cancelasync = 0; + self->result = result; + + while (self->cancelbuf) { + void (*f)(void*) = self->cancelbuf->__f; + void* x = self->cancelbuf->__x; + self->cancelbuf = self->cancelbuf->__next; + f(x); + } + + __pthread_tsd_run_dtors(); + + mxr_mutex_lock(&self->exitlock); + + /* Mark this thread dead before decrementing count */ + mxr_mutex_lock(&self->killlock); + self->dead = 1; + + /* Block all signals before decrementing the live thread count. + * This is important to ensure that dynamically allocated TLS + * is not under-allocated/over-committed, and possibly for other + * reasons as well. */ + __block_all_sigs(&set); + + /* Wait to unlock the kill lock, which governs functions like + * pthread_kill which target a thread id, until signals have + * been blocked. This precludes observation of the thread id + * as a live thread (with application code running in it) after + * the thread was reported dead by ESRCH being returned. */ + mxr_mutex_unlock(&self->killlock); + + /* TODO(kulakowski) Thread exit process teardown. */ + /* It's impossible to determine whether this is "the last thread" + * until performing the atomic decrement, since multiple threads + * could exit at the same time. For the last thread, revert the + * decrement and unblock signals to give the atexit handlers and + * stdio cleanup code a consistent state. */ + /* if (a_fetch_add(&libc.threads_minus_1, -1) == 0) { */ + /* libc.threads_minus_1 = 0; */ + /* __restore_sigs(&set); */ + /* exit(0); */ + /* } */ + + /* Process robust list in userspace to handle non-pshared mutexes + * and the detached thread case where the robust list head will + * be invalid when the kernel would process it. */ + __vm_lock(); + volatile void* volatile* rp; + while ((rp = self->robust_list.head) && rp != &self->robust_list.head) { + pthread_mutex_t* m = (void*)((char*)rp - offsetof(pthread_mutex_t, _m_next)); + int waiters = m->_m_waiters; + self->robust_list.pending = rp; + self->robust_list.head = *rp; + int cont = a_swap(&m->_m_lock, self->tid | 0x40000000); + self->robust_list.pending = 0; + if (cont < 0 || waiters) __wake(&m->_m_lock, 1); + } + __vm_unlock(); + + __do_orphaned_stdio_locks(); + __dl_thread_cleanup(); + + if (self->detached && self->map_base) { + /* Detached threads must avoid the kernel clear_child_tid + * feature, since the virtual address will have been + * unmapped and possibly already reused by a new mapping + * at the time the kernel would perform the write. In + * the case of threads that started out detached, the + * initial clone flags are correct, but if the thread was + * detached later (== 2), we need to clear it here. */ + if (self->detached == 2) __syscall(SYS_set_tid_address, 0); + + /* Robust list will no longer be valid, and was already + * processed above, so unregister it with the kernel. */ + if (self->robust_list.off) __syscall(SYS_set_robust_list, 0, 3 * sizeof(long)); + + /* Since __unmapself bypasses the normal munmap code path, + * explicitly wait for vmlock holders first. */ + __vm_wait(); + + /* The following call unmaps the thread's stack mapping + * and then exits without touching the stack. */ + __unmapself(self->map_base, self->map_size); + } + + for (;;) + __syscall(SYS_exit, 0); +} + +int __mprotect(void*, size_t, int); + +void __do_cleanup_push(struct __ptcb* cb) { + struct pthread* self = __pthread_self(); + cb->__next = self->cancelbuf; + self->cancelbuf = cb; +} + +void __do_cleanup_pop(struct __ptcb* cb) { + __pthread_self()->cancelbuf = cb->__next; +} + +static int start_c11(void* p) { + pthread_t self = p; + int (*start)(void*) = (int (*)(void*))self->start; + pthread_exit((void*)(uintptr_t)start(self->start_arg)); + return 0; +} + +/* pthread_key_create.c overrides this */ +static void* dummy_tsd[1] = {0}; +weak_alias(dummy_tsd, __pthread_tsd_main); + +static FILE* volatile dummy_file = 0; +weak_alias(dummy_file, __stdin_used); +weak_alias(dummy_file, __stdout_used); +weak_alias(dummy_file, __stderr_used); diff --git a/third_party/ulib/musl/src/thread/pthread_detach.c b/third_party/ulib/musl/src/thread/pthread_detach.c new file mode 100644 index 000000000..b345b5699 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_detach.c @@ -0,0 +1,15 @@ +#include "pthread_impl.h" +#include + +int __pthread_join(pthread_t, void**); + +static int __pthread_detach(pthread_t t) { + /* Cannot detach a thread that's already exiting */ + if (!mxr_mutex_trylock(&t->exitlock)) return __pthread_join(t, 0); + t->detached = 2; + mxr_mutex_unlock(&t->exitlock); + return 0; +} + +weak_alias(__pthread_detach, pthread_detach); +weak_alias(__pthread_detach, thrd_detach); diff --git a/third_party/ulib/musl/src/thread/pthread_equal.c b/third_party/ulib/musl/src/thread/pthread_equal.c new file mode 100644 index 000000000..069206713 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_equal.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include +#include + +static int __pthread_equal(pthread_t a, pthread_t b) { + return a == b; +} + +weak_alias(__pthread_equal, pthread_equal); +weak_alias(__pthread_equal, thrd_equal); diff --git a/third_party/ulib/musl/src/thread/pthread_getattr_np.c b/third_party/ulib/musl/src/thread/pthread_getattr_np.c new file mode 100644 index 000000000..34a9b98ca --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_getattr_np.c @@ -0,0 +1,23 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "pthread_impl.h" +#include + +int pthread_getattr_np(pthread_t t, pthread_attr_t* a) { + *a = (pthread_attr_t){0}; + a->_a_detach = !!t->detached; + if (t->stack) { + a->_a_stackaddr = (uintptr_t)t->stack; + a->_a_stacksize = t->stack_size - DEFAULT_STACK_SIZE; + } else { + char* p = (void*)libc.auxv; + size_t l = PAGE_SIZE; + p += -(uintptr_t)p & PAGE_SIZE - 1; + a->_a_stackaddr = (uintptr_t)p; + while (mremap(p - l - PAGE_SIZE, PAGE_SIZE, 2 * PAGE_SIZE, 0) == MAP_FAILED && + errno == ENOMEM) + l += PAGE_SIZE; + a->_a_stacksize = l - DEFAULT_STACK_SIZE; + } + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_getconcurrency.c b/third_party/ulib/musl/src/thread/pthread_getconcurrency.c new file mode 100644 index 000000000..a1df9a07d --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_getconcurrency.c @@ -0,0 +1,5 @@ +#include + +int pthread_getconcurrency() { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_getcpuclockid.c b/third_party/ulib/musl/src/thread/pthread_getcpuclockid.c new file mode 100644 index 000000000..e3449cf7a --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_getcpuclockid.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_getcpuclockid(pthread_t t, clockid_t* clockid) { + *clockid = (-t->tid - 1) * 8U + 6; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_getschedparam.c b/third_party/ulib/musl/src/thread/pthread_getschedparam.c new file mode 100644 index 000000000..0bf48b067 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_getschedparam.c @@ -0,0 +1,16 @@ +#include "pthread_impl.h" + +int pthread_getschedparam(pthread_t t, int* restrict policy, struct sched_param* restrict param) { + int r; + mxr_mutex_lock(&t->killlock); + if (t->dead) { + r = ESRCH; + } else { + r = -__syscall(SYS_sched_getparam, t->tid, param); + if (!r) { + *policy = __syscall(SYS_sched_getscheduler, t->tid); + } + } + mxr_mutex_unlock(&t->killlock); + return r; +} diff --git a/third_party/ulib/musl/src/thread/pthread_getspecific.c b/third_party/ulib/musl/src/thread/pthread_getspecific.c new file mode 100644 index 000000000..52eecdc01 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_getspecific.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" +#include + +static void* __pthread_getspecific(pthread_key_t k) { + struct pthread* self = __pthread_self(); + return self->tsd[k]; +} + +weak_alias(__pthread_getspecific, pthread_getspecific); +weak_alias(__pthread_getspecific, tss_get); diff --git a/third_party/ulib/musl/src/thread/pthread_join.c b/third_party/ulib/musl/src/thread/pthread_join.c new file mode 100644 index 000000000..ade2537c1 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_join.c @@ -0,0 +1,20 @@ +#include + +#include "pthread_impl.h" + +#include + +int __munmap(void*, size_t); + +int pthread_join(pthread_t t, void** res) { + struct pthread* thread = (struct pthread*)t; + mx_status_t r = _magenta_handle_wait_one(thread->handle, + MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, + NULL, NULL); + if (r != 0) + return -1; + + __munmap(thread, thread->map_size); + + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_key_create.c b/third_party/ulib/musl/src/thread/pthread_key_create.c new file mode 100644 index 000000000..be663d530 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_key_create.c @@ -0,0 +1,51 @@ +#include "pthread_impl.h" + +volatile size_t __pthread_tsd_size = sizeof(void*) * PTHREAD_KEYS_MAX; +void* __pthread_tsd_main[PTHREAD_KEYS_MAX] = {0}; + +static void (*volatile keys[PTHREAD_KEYS_MAX])(void*); + +static void nodtor(void* dummy) {} + +int __pthread_key_create(pthread_key_t* k, void (*dtor)(void*)) { + unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; + unsigned j = i; + pthread_t self = __pthread_self(); + + /* This can only happen in the main thread before + * pthread_create has been called. */ + if (!self->tsd) self->tsd = __pthread_tsd_main; + + if (!dtor) dtor = nodtor; + do { + if (!a_cas_p(keys + j, 0, (void*)dtor)) { + *k = j; + return 0; + } + } while ((j = (j + 1) % PTHREAD_KEYS_MAX) != i); + return EAGAIN; +} + +int __pthread_key_delete(pthread_key_t k) { + keys[k] = 0; + return 0; +} + +void __pthread_tsd_run_dtors(void) { + pthread_t self = __pthread_self(); + int i, j, not_finished = self->tsd_used; + for (j = 0; not_finished && j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) { + not_finished = 0; + for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (self->tsd[i] && keys[i]) { + void* tmp = self->tsd[i]; + self->tsd[i] = 0; + keys[i](tmp); + not_finished = 1; + } + } + } +} + +weak_alias(__pthread_key_delete, pthread_key_delete); +weak_alias(__pthread_key_create, pthread_key_create); diff --git a/third_party/ulib/musl/src/thread/pthread_kill.c b/third_party/ulib/musl/src/thread/pthread_kill.c new file mode 100644 index 000000000..045f727af --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_kill.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_kill(pthread_t t, int sig) { + int r; + mxr_mutex_lock(&t->killlock); + r = t->dead ? ESRCH : -__syscall(SYS_tkill, t->tid, sig); + mxr_mutex_unlock(&t->killlock); + return r; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_consistent.c b/third_party/ulib/musl/src/thread/pthread_mutex_consistent.c new file mode 100644 index 000000000..baad8141b --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_consistent.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_mutex_consistent(pthread_mutex_t* m) { + if (!(m->_m_type & 8)) return EINVAL; + if ((m->_m_lock & 0x7fffffff) != __pthread_self()->tid) return EPERM; + m->_m_type &= ~8U; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_destroy.c b/third_party/ulib/musl/src/thread/pthread_mutex_destroy.c new file mode 100644 index 000000000..0453efd65 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_destroy.c @@ -0,0 +1,5 @@ +#include + +int pthread_mutex_destroy(pthread_mutex_t* mutex) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_getprioceiling.c b/third_party/ulib/musl/src/thread/pthread_mutex_getprioceiling.c new file mode 100644 index 000000000..712c7c31b --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_getprioceiling.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_mutex_getprioceiling(const pthread_mutex_t* restrict m, int* restrict ceiling) { + return EINVAL; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_init.c b/third_party/ulib/musl/src/thread/pthread_mutex_init.c new file mode 100644 index 000000000..19233ba19 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_mutex_init(pthread_mutex_t* restrict m, const pthread_mutexattr_t* restrict a) { + *m = (pthread_mutex_t){0}; + if (a) m->_m_type = a->__attr; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_lock.c b/third_party/ulib/musl/src/thread/pthread_mutex_lock.c new file mode 100644 index 000000000..aba940208 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_lock.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int __pthread_mutex_timedlock(pthread_mutex_t* restrict, const struct timespec* restrict); + +int __pthread_mutex_lock(pthread_mutex_t* m) { + if ((m->_m_type & 15) == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) return 0; + + return __pthread_mutex_timedlock(m, 0); +} + +weak_alias(__pthread_mutex_lock, pthread_mutex_lock); diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_setprioceiling.c b/third_party/ulib/musl/src/thread/pthread_mutex_setprioceiling.c new file mode 100644 index 000000000..163a1b68c --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_setprioceiling.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_mutex_setprioceiling(pthread_mutex_t* restrict m, int ceiling, int* restrict old) { + return EINVAL; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_timedlock.c b/third_party/ulib/musl/src/thread/pthread_mutex_timedlock.c new file mode 100644 index 000000000..17443a354 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_timedlock.c @@ -0,0 +1,31 @@ +#include "pthread_impl.h" + +int __pthread_mutex_timedlock(pthread_mutex_t* restrict m, const struct timespec* restrict at) { + if ((m->_m_type & 15) == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) return 0; + + int r, t; + + r = pthread_mutex_trylock(m); + if (r != EBUSY) return r; + + int spins = 100; + while (spins-- && m->_m_lock && !m->_m_waiters) + a_spin(); + + while ((r = pthread_mutex_trylock(m)) == EBUSY) { + if (!(r = m->_m_lock) || ((r & 0x40000000) && (m->_m_type & 4))) continue; + if ((m->_m_type & 3) == PTHREAD_MUTEX_ERRORCHECK && + (r & 0x7fffffff) == __pthread_self()->tid) + return EDEADLK; + + a_inc(&m->_m_waiters); + t = r | 0x80000000; + a_cas(&m->_m_lock, r, t); + r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at); + a_dec(&m->_m_waiters); + if (r && r != EINTR) break; + } + return r; +} + +weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock); diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_trylock.c b/third_party/ulib/musl/src/thread/pthread_mutex_trylock.c new file mode 100644 index 000000000..d3c27d406 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_trylock.c @@ -0,0 +1,54 @@ +#include "pthread_impl.h" + +int __pthread_mutex_trylock_owner(pthread_mutex_t* m) { + int old, own; + int type = m->_m_type & 15; + pthread_t self = __pthread_self(); + int tid = self->tid; + + old = m->_m_lock; + own = old & 0x7fffffff; + if (own == tid && (type & 3) == PTHREAD_MUTEX_RECURSIVE) { + if ((unsigned)m->_m_count >= INT_MAX) return EAGAIN; + m->_m_count++; + return 0; + } + if (own == 0x40000000) return ENOTRECOVERABLE; + + if (m->_m_type & 128) { + if (!self->robust_list.off) { + self->robust_list.off = (char*)&m->_m_lock - (char*)&m->_m_next; + __syscall(SYS_set_robust_list, &self->robust_list, 3 * sizeof(long)); + } + if (m->_m_waiters) tid |= 0x80000000; + self->robust_list.pending = &m->_m_next; + } + + if ((own && (!(own & 0x40000000) || !(type & 4))) || a_cas(&m->_m_lock, old, tid) != old) { + self->robust_list.pending = 0; + return EBUSY; + } + + volatile void* next = self->robust_list.head; + m->_m_next = next; + m->_m_prev = &self->robust_list.head; + if (next != &self->robust_list.head) + *(volatile void* volatile*)((char*)next - sizeof(void*)) = &m->_m_next; + self->robust_list.head = &m->_m_next; + self->robust_list.pending = 0; + + if (own) { + m->_m_count = 0; + m->_m_type |= 8; + return EOWNERDEAD; + } + + return 0; +} + +int __pthread_mutex_trylock(pthread_mutex_t* m) { + if ((m->_m_type & 15) == PTHREAD_MUTEX_NORMAL) return a_cas(&m->_m_lock, 0, EBUSY) & EBUSY; + return __pthread_mutex_trylock_owner(m); +} + +weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock); diff --git a/third_party/ulib/musl/src/thread/pthread_mutex_unlock.c b/third_party/ulib/musl/src/thread/pthread_mutex_unlock.c new file mode 100644 index 000000000..a02028d67 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutex_unlock.c @@ -0,0 +1,24 @@ +#include "pthread_impl.h" + +int __pthread_mutex_unlock(pthread_mutex_t* m) { + pthread_t self; + int waiters = m->_m_waiters; + int cont; + int type = m->_m_type & 15; + + if (type != PTHREAD_MUTEX_NORMAL) { + self = __pthread_self(); + if ((m->_m_lock & 0x7fffffff) != self->tid) return EPERM; + if ((type & 3) == PTHREAD_MUTEX_RECURSIVE && m->_m_count) return m->_m_count--, 0; + volatile void* prev = m->_m_prev; + volatile void* next = m->_m_next; + *(volatile void* volatile*)prev = next; + if (next != &self->robust_list.head) + *(volatile void* volatile*)((char*)next - sizeof(void*)) = prev; + } + cont = a_swap(&m->_m_lock, (type & 8) ? 0x40000000 : 0); + if (waiters || cont < 0) __wake(&m->_m_lock, 1); + return 0; +} + +weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock); diff --git a/third_party/ulib/musl/src/thread/pthread_mutexattr_destroy.c b/third_party/ulib/musl/src/thread/pthread_mutexattr_destroy.c new file mode 100644 index 000000000..4402292ce --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutexattr_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_destroy(pthread_mutexattr_t* a) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutexattr_init.c b/third_party/ulib/musl/src/thread/pthread_mutexattr_init.c new file mode 100644 index 000000000..9c8684a59 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutexattr_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_init(pthread_mutexattr_t* a) { + *a = (pthread_mutexattr_t){0}; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutexattr_setprotocol.c b/third_party/ulib/musl/src/thread/pthread_mutexattr_setprotocol.c new file mode 100644 index 000000000..8fcbad95c --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutexattr_setprotocol.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t* a, int protocol) { + if (protocol) return ENOTSUP; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutexattr_setrobust.c b/third_party/ulib/musl/src/thread/pthread_mutexattr_setrobust.c new file mode 100644 index 000000000..577bb875c --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutexattr_setrobust.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_setrobust(pthread_mutexattr_t* a, int robust) { + if (robust > 1U) return EINVAL; + a->__attr &= ~4; + a->__attr |= robust * 4; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_mutexattr_settype.c b/third_party/ulib/musl/src/thread/pthread_mutexattr_settype.c new file mode 100644 index 000000000..687ff1e18 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_mutexattr_settype.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_settype(pthread_mutexattr_t* a, int type) { + if ((unsigned)type > 2) return EINVAL; + a->__attr = (a->__attr & ~3) | type; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_once.c b/third_party/ulib/musl/src/thread/pthread_once.c new file mode 100644 index 000000000..faea17ee6 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_once.c @@ -0,0 +1,46 @@ +#include "pthread_impl.h" + +static void undo(void* control) { + /* Wake all waiters, since the waiter status is lost when + * resetting control to the initial state. */ + if (a_swap(control, 0) == 3) __wake(control, -1); +} + +int __pthread_once_full(pthread_once_t* control, void (*init)(void)) { + /* Try to enter initializing state. Four possibilities: + * 0 - we're the first or the other cancelled; run init + * 1 - another thread is running init; wait + * 2 - another thread finished running init; just return + * 3 - another thread is running init, waiters present; wait */ + + for (;;) + switch (a_cas(control, 0, 1)) { + case 0: + pthread_cleanup_push(undo, control); + init(); + pthread_cleanup_pop(0); + + if (a_swap(control, 2) == 3) __wake(control, -1); + return 0; + case 1: + /* If this fails, so will __wait. */ + a_cas(control, 1, 3); + case 3: + __wait(control, 0, 3); + continue; + case 2: + return 0; + } +} + +int __pthread_once(pthread_once_t* control, void (*init)(void)) { + /* Return immediately if init finished before, but ensure that + * effects of the init routine are visible to the caller. */ + if (*(volatile int*)control == 2) { + a_barrier(); + return 0; + } + return __pthread_once_full(control, init); +} + +weak_alias(__pthread_once, pthread_once); diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_destroy.c b/third_party/ulib/musl/src/thread/pthread_rwlock_destroy.c new file mode 100644 index 000000000..17532a7ae --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_rwlock_destroy(pthread_rwlock_t* rw) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_init.c b/third_party/ulib/musl/src/thread/pthread_rwlock_init.c new file mode 100644 index 000000000..7d61fcb73 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_rwlock_init(pthread_rwlock_t* restrict rw, const pthread_rwlockattr_t* restrict a) { + *rw = (pthread_rwlock_t){0}; + if (a) rw->_rw_shared = a->__attr[0] * 128; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_rdlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_rdlock.c new file mode 100644 index 000000000..aacd30168 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_rdlock.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_rwlock_rdlock(pthread_rwlock_t* rw) { + return pthread_rwlock_timedrdlock(rw, 0); +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_timedrdlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_timedrdlock.c new file mode 100644 index 000000000..14c3f7c2c --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,23 @@ +#include "pthread_impl.h" + +int pthread_rwlock_timedrdlock(pthread_rwlock_t* restrict rw, const struct timespec* restrict at) { + int r, t; + + r = pthread_rwlock_tryrdlock(rw); + if (r != EBUSY) return r; + + int spins = 100; + while (spins-- && rw->_rw_lock && !rw->_rw_waiters) + a_spin(); + + while ((r = pthread_rwlock_tryrdlock(rw)) == EBUSY) { + if (!(r = rw->_rw_lock) || (r & 0x7fffffff) != 0x7fffffff) continue; + t = r | 0x80000000; + a_inc(&rw->_rw_waiters); + a_cas(&rw->_rw_lock, r, t); + r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at); + a_dec(&rw->_rw_waiters); + if (r && r != EINTR) return r; + } + return r; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_timedwrlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_timedwrlock.c new file mode 100644 index 000000000..c7304a2f4 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,23 @@ +#include "pthread_impl.h" + +int pthread_rwlock_timedwrlock(pthread_rwlock_t* restrict rw, const struct timespec* restrict at) { + int r, t; + + r = pthread_rwlock_trywrlock(rw); + if (r != EBUSY) return r; + + int spins = 100; + while (spins-- && rw->_rw_lock && !rw->_rw_waiters) + a_spin(); + + while ((r = pthread_rwlock_trywrlock(rw)) == EBUSY) { + if (!(r = rw->_rw_lock)) continue; + t = r | 0x80000000; + a_inc(&rw->_rw_waiters); + a_cas(&rw->_rw_lock, r, t); + r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at); + a_dec(&rw->_rw_waiters); + if (r && r != EINTR) return r; + } + return r; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_tryrdlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_tryrdlock.c new file mode 100644 index 000000000..8ced65c98 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_tryrdlock.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" + +int pthread_rwlock_tryrdlock(pthread_rwlock_t* rw) { + int val, cnt; + do { + val = rw->_rw_lock; + cnt = val & 0x7fffffff; + if (cnt == 0x7fffffff) return EBUSY; + if (cnt == 0x7ffffffe) return EAGAIN; + } while (a_cas(&rw->_rw_lock, val, val + 1) != val); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_trywrlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_trywrlock.c new file mode 100644 index 000000000..5a59b98d3 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_trywrlock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_rwlock_trywrlock(pthread_rwlock_t* rw) { + if (a_cas(&rw->_rw_lock, 0, 0x7fffffff)) return EBUSY; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_unlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_unlock.c new file mode 100644 index 000000000..9cdc20c9a --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_unlock.c @@ -0,0 +1,16 @@ +#include "pthread_impl.h" + +int pthread_rwlock_unlock(pthread_rwlock_t* rw) { + int val, cnt, waiters, new; + + do { + val = rw->_rw_lock; + cnt = val & 0x7fffffff; + waiters = rw->_rw_waiters; + new = (cnt == 0x7fffffff || cnt == 1) ? 0 : val - 1; + } while (a_cas(&rw->_rw_lock, val, new) != val); + + if (!new && (waiters || val < 0)) __wake(&rw->_rw_lock, cnt); + + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlock_wrlock.c b/third_party/ulib/musl/src/thread/pthread_rwlock_wrlock.c new file mode 100644 index 000000000..eadf4578d --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlock_wrlock.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_rwlock_wrlock(pthread_rwlock_t* rw) { + return pthread_rwlock_timedwrlock(rw, 0); +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlockattr_destroy.c b/third_party/ulib/musl/src/thread/pthread_rwlockattr_destroy.c new file mode 100644 index 000000000..e6b9127d2 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlockattr_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t* a) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_rwlockattr_init.c b/third_party/ulib/musl/src/thread/pthread_rwlockattr_init.c new file mode 100644 index 000000000..16202ad69 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_rwlockattr_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_rwlockattr_init(pthread_rwlockattr_t* a) { + *a = (pthread_rwlockattr_t){0}; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_self.c b/third_party/ulib/musl/src/thread/pthread_self.c new file mode 100644 index 000000000..bc025b7ef --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_self.c @@ -0,0 +1,10 @@ +#include "libc.h" +#include "pthread_impl.h" +#include + +static pthread_t __pthread_self_internal(void) { + return __pthread_self(); +} + +weak_alias(__pthread_self_internal, pthread_self); +weak_alias(__pthread_self_internal, thrd_current); diff --git a/third_party/ulib/musl/src/thread/pthread_setcancelstate.c b/third_party/ulib/musl/src/thread/pthread_setcancelstate.c new file mode 100644 index 000000000..cfac26025 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_setcancelstate.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int __pthread_setcancelstate(int new, int* old) { + if (new > 2U) return EINVAL; + struct pthread* self = __pthread_self(); + if (old) *old = self->canceldisable; + self->canceldisable = new; + return 0; +} + +weak_alias(__pthread_setcancelstate, pthread_setcancelstate); diff --git a/third_party/ulib/musl/src/thread/pthread_setcanceltype.c b/third_party/ulib/musl/src/thread/pthread_setcanceltype.c new file mode 100644 index 000000000..24aa2b6c3 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_setcanceltype.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int pthread_setcanceltype(int new, int* old) { + struct pthread* self = __pthread_self(); + if (new > 1U) return EINVAL; + if (old) *old = self->cancelasync; + self->cancelasync = new; + if (new) pthread_testcancel(); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_setconcurrency.c b/third_party/ulib/musl/src/thread/pthread_setconcurrency.c new file mode 100644 index 000000000..00cd99e44 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_setconcurrency.c @@ -0,0 +1,8 @@ +#include +#include + +int pthread_setconcurrency(int val) { + if (val < 0) return EINVAL; + if (val > 0) return EAGAIN; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_setschedparam.c b/third_party/ulib/musl/src/thread/pthread_setschedparam.c new file mode 100644 index 000000000..964cecc18 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_setschedparam.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_setschedparam(pthread_t t, int policy, const struct sched_param* param) { + int r; + mxr_mutex_lock(&t->killlock); + r = t->dead ? ESRCH : -__syscall(SYS_sched_setscheduler, t->tid, policy, param); + mxr_mutex_unlock(&t->killlock); + return r; +} diff --git a/third_party/ulib/musl/src/thread/pthread_setschedprio.c b/third_party/ulib/musl/src/thread/pthread_setschedprio.c new file mode 100644 index 000000000..0a435da68 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_setschedprio.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_setschedprio(pthread_t t, int prio) { + int r; + mxr_mutex_lock(&t->killlock); + r = t->dead ? ESRCH : -__syscall(SYS_sched_setparam, t->tid, &prio); + mxr_mutex_unlock(&t->killlock); + return r; +} diff --git a/third_party/ulib/musl/src/thread/pthread_setspecific.c b/third_party/ulib/musl/src/thread/pthread_setspecific.c new file mode 100644 index 000000000..717a30632 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_setspecific.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int pthread_setspecific(pthread_key_t k, const void* x) { + struct pthread* self = __pthread_self(); + /* Avoid unnecessary COW */ + if (self->tsd[k] != x) { + self->tsd[k] = (void*)x; + self->tsd_used = 1; + } + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_sigmask.c b/third_party/ulib/musl/src/thread/pthread_sigmask.c new file mode 100644 index 000000000..e82afc443 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_sigmask.c @@ -0,0 +1,18 @@ +#include "syscall.h" +#include +#include + +int pthread_sigmask(int how, const sigset_t* restrict set, sigset_t* restrict old) { + int ret; + if ((unsigned)how - SIG_BLOCK > 2U) return EINVAL; + ret = -__syscall(SYS_rt_sigprocmask, how, set, old, _NSIG / 8); + if (!ret && old) { + if (sizeof old->__bits[0] == 8) { + old->__bits[0] &= ~0x380000000ULL; + } else { + old->__bits[0] &= ~0x80000000UL; + old->__bits[1] &= ~0x3UL; + } + } + return ret; +} diff --git a/third_party/ulib/musl/src/thread/pthread_spin_destroy.c b/third_party/ulib/musl/src/thread/pthread_spin_destroy.c new file mode 100644 index 000000000..a99a695ee --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_spin_destroy.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_spin_destroy(pthread_spinlock_t* s) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_spin_init.c b/third_party/ulib/musl/src/thread/pthread_spin_init.c new file mode 100644 index 000000000..ddf4ff22f --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_spin_init.c @@ -0,0 +1,5 @@ +#include "pthread_impl.h" + +int pthread_spin_init(pthread_spinlock_t* s, int shared) { + return *s = 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_spin_lock.c b/third_party/ulib/musl/src/thread/pthread_spin_lock.c new file mode 100644 index 000000000..f56bbbfe5 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_spin_lock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" +#include + +int pthread_spin_lock(pthread_spinlock_t* s) { + while (*(volatile int*)s || a_cas(s, 0, EBUSY)) + a_spin(); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_spin_trylock.c b/third_party/ulib/musl/src/thread/pthread_spin_trylock.c new file mode 100644 index 000000000..e80a91e08 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_spin_trylock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" +#include + +int pthread_spin_trylock(pthread_spinlock_t* s) { + return a_cas(s, 0, EBUSY); +} diff --git a/third_party/ulib/musl/src/thread/pthread_spin_unlock.c b/third_party/ulib/musl/src/thread/pthread_spin_unlock.c new file mode 100644 index 000000000..e1edf601c --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_spin_unlock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_unlock(pthread_spinlock_t* s) { + a_store(s, 0); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/pthread_testcancel.c b/third_party/ulib/musl/src/thread/pthread_testcancel.c new file mode 100644 index 000000000..dc8771766 --- /dev/null +++ b/third_party/ulib/musl/src/thread/pthread_testcancel.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include "pthread_impl.h" + +static void dummy(void) {} + +weak_alias(dummy, __testcancel); + +void __pthread_testcancel(void) { + __testcancel(); +} + +weak_alias(__pthread_testcancel, pthread_testcancel); diff --git a/third_party/ulib/musl/src/thread/sem_destroy.c b/third_party/ulib/musl/src/thread/sem_destroy.c new file mode 100644 index 000000000..9d2563d6b --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_destroy.c @@ -0,0 +1,5 @@ +#include + +int sem_destroy(sem_t* sem) { + return 0; +} diff --git a/third_party/ulib/musl/src/thread/sem_getvalue.c b/third_party/ulib/musl/src/thread/sem_getvalue.c new file mode 100644 index 000000000..4c1a346b7 --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_getvalue.c @@ -0,0 +1,7 @@ +#include + +int sem_getvalue(sem_t* restrict sem, int* restrict valp) { + int val = sem->__val[0]; + *valp = val < 0 ? 0 : val; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/sem_init.c b/third_party/ulib/musl/src/thread/sem_init.c new file mode 100644 index 000000000..f37708297 --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_init.c @@ -0,0 +1,14 @@ +#include +#include +#include + +int sem_init(sem_t* sem, int pshared, unsigned value) { + if (value > SEM_VALUE_MAX || pshared) { + errno = EINVAL; + return -1; + } + sem->__val[0] = value; + sem->__val[1] = 0; + sem->__val[2] = 0; + return 0; +} diff --git a/third_party/ulib/musl/src/thread/sem_open.c b/third_party/ulib/musl/src/thread/sem_open.c new file mode 100644 index 000000000..68e87f5eb --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_open.c @@ -0,0 +1,175 @@ +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +char* __shm_mapname(const char*, char*); + +static struct { + ino_t ino; + sem_t* sem; + int refcnt; +} * semtab; +static mxr_mutex_t lock; + +#define FLAGS (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) + +sem_t* sem_open(const char* name, int flags, ...) { + va_list ap; + mode_t mode; + unsigned value; + int fd, i, e, slot, first = 1, cnt, cs; + sem_t newsem; + void* map; + char tmp[64]; + struct timespec ts; + struct stat st; + char buf[NAME_MAX + 10]; + + if (!(name = __shm_mapname(name, buf))) return SEM_FAILED; + + mxr_mutex_lock(&lock); + /* Allocate table if we don't have one yet */ + if (!semtab && !(semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX))) { + mxr_mutex_unlock(&lock); + return SEM_FAILED; + } + + /* Reserve a slot in case this semaphore is not mapped yet; + * this is necessary because there is no way to handle + * failures after creation of the file. */ + slot = -1; + for (cnt = i = 0; i < SEM_NSEMS_MAX; i++) { + cnt += semtab[i].refcnt; + if (!semtab[i].sem && slot < 0) slot = i; + } + /* Avoid possibility of overflow later */ + if (cnt == INT_MAX || slot < 0) { + errno = EMFILE; + mxr_mutex_unlock(&lock); + return SEM_FAILED; + } + /* Dummy pointer to make a reservation */ + semtab[slot].sem = (sem_t*)-1; + mxr_mutex_unlock(&lock); + + flags &= (O_CREAT | O_EXCL); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + /* Early failure check for exclusive open; otherwise the case + * where the semaphore already exists is expensive. */ + if (flags == (O_CREAT | O_EXCL) && access(name, F_OK) == 0) { + errno = EEXIST; + goto fail; + } + + for (;;) { + /* If exclusive mode is not requested, try opening an + * existing file first and fall back to creation. */ + if (flags != (O_CREAT | O_EXCL)) { + fd = open(name, FLAGS); + if (fd >= 0) { + if (fstat(fd, &st) < 0 || + (map = mmap(0, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == + MAP_FAILED) { + close(fd); + goto fail; + } + close(fd); + break; + } + if (errno != ENOENT) goto fail; + } + if (!(flags & O_CREAT)) goto fail; + if (first) { + first = 0; + va_start(ap, flags); + mode = va_arg(ap, mode_t) & 0666; + value = va_arg(ap, unsigned); + va_end(ap); + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + goto fail; + } + sem_init(&newsem, 1, value); + } + /* Create a temp file with the new semaphore contents + * and attempt to atomically link it as the new name */ + clock_gettime(CLOCK_REALTIME, &ts); + snprintf(tmp, sizeof(tmp), "/dev/shm/tmp-%d", (int)ts.tv_nsec); + fd = open(tmp, O_CREAT | O_EXCL | FLAGS, mode); + if (fd < 0) { + if (errno == EEXIST) continue; + goto fail; + } + if (write(fd, &newsem, sizeof newsem) != sizeof newsem || fstat(fd, &st) < 0 || + (map = mmap(0, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == + MAP_FAILED) { + close(fd); + unlink(tmp); + goto fail; + } + close(fd); + e = link(tmp, name) ? errno : 0; + unlink(tmp); + if (!e) break; + munmap(map, sizeof(sem_t)); + /* Failure is only fatal when doing an exclusive open; + * otherwise, next iteration will try to open the + * existing file. */ + if (e != EEXIST || flags == (O_CREAT | O_EXCL)) goto fail; + } + + /* See if the newly mapped semaphore is already mapped. If + * so, unmap the new mapping and use the existing one. Otherwise, + * add it to the table of mapped semaphores. */ + mxr_mutex_lock(&lock); + for (i = 0; i < SEM_NSEMS_MAX && semtab[i].ino != st.st_ino; i++) + ; + if (i < SEM_NSEMS_MAX) { + munmap(map, sizeof(sem_t)); + semtab[slot].sem = 0; + slot = i; + map = semtab[i].sem; + } + semtab[slot].refcnt++; + semtab[slot].sem = map; + semtab[slot].ino = st.st_ino; + mxr_mutex_unlock(&lock); + pthread_setcancelstate(cs, 0); + return map; + +fail: + pthread_setcancelstate(cs, 0); + mxr_mutex_lock(&lock); + semtab[slot].sem = 0; + mxr_mutex_unlock(&lock); + return SEM_FAILED; +} + +int sem_close(sem_t* sem) { + int i; + mxr_mutex_lock(&lock); + for (i = 0; i < SEM_NSEMS_MAX && semtab[i].sem != sem; i++) + ; + if (!--semtab[i].refcnt) { + semtab[i].sem = 0; + semtab[i].ino = 0; + } + mxr_mutex_unlock(&lock); + munmap(sem, sizeof *sem); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/sem_post.c b/third_party/ulib/musl/src/thread/sem_post.c new file mode 100644 index 000000000..983ec1e26 --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_post.c @@ -0,0 +1,16 @@ +#include "pthread_impl.h" +#include + +int sem_post(sem_t* sem) { + int val, waiters; + do { + val = sem->__val[0]; + waiters = sem->__val[1]; + if (val == SEM_VALUE_MAX) { + errno = EOVERFLOW; + return -1; + } + } while (a_cas(sem->__val, val, val + 1 + (val < 0)) != val); + if (val < 0 || waiters) __wake(sem->__val, 1); + return 0; +} diff --git a/third_party/ulib/musl/src/thread/sem_timedwait.c b/third_party/ulib/musl/src/thread/sem_timedwait.c new file mode 100644 index 000000000..d091b9596 --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_timedwait.c @@ -0,0 +1,30 @@ +#include "pthread_impl.h" +#include + +static void cleanup(void* p) { + a_dec(p); +} + +int sem_timedwait(sem_t* restrict sem, const struct timespec* restrict at) { + pthread_testcancel(); + + if (!sem_trywait(sem)) return 0; + + int spins = 100; + while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) + a_spin(); + + while (sem_trywait(sem)) { + int r; + a_inc(sem->__val + 1); + a_cas(sem->__val, 0, -1); + pthread_cleanup_push(cleanup, (void*)(sem->__val + 1)); + r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at); + pthread_cleanup_pop(1); + if (r && r != EINTR) { + errno = r; + return -1; + } + } + return 0; +} diff --git a/third_party/ulib/musl/src/thread/sem_trywait.c b/third_party/ulib/musl/src/thread/sem_trywait.c new file mode 100644 index 000000000..55e3d3cf4 --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_trywait.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" +#include + +int sem_trywait(sem_t* sem) { + int val; + while ((val = sem->__val[0]) > 0) { + int new = val - 1 - (val == 1 && sem->__val[1]); + if (a_cas(sem->__val, val, new) == val) return 0; + } + errno = EAGAIN; + return -1; +} diff --git a/third_party/ulib/musl/src/thread/sem_unlink.c b/third_party/ulib/musl/src/thread/sem_unlink.c new file mode 100644 index 000000000..15c89d4ea --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_unlink.c @@ -0,0 +1,6 @@ +#include +#include + +int sem_unlink(const char* name) { + return shm_unlink(name); +} diff --git a/third_party/ulib/musl/src/thread/sem_wait.c b/third_party/ulib/musl/src/thread/sem_wait.c new file mode 100644 index 000000000..5809d7ea5 --- /dev/null +++ b/third_party/ulib/musl/src/thread/sem_wait.c @@ -0,0 +1,5 @@ +#include + +int sem_wait(sem_t* sem) { + return sem_timedwait(sem, 0); +} diff --git a/third_party/ulib/musl/src/thread/thrd_create.c b/third_party/ulib/musl/src/thread/thrd_create.c new file mode 100644 index 000000000..63c9a7716 --- /dev/null +++ b/third_party/ulib/musl/src/thread/thrd_create.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" +#include + +int __pthread_create(pthread_t* restrict, const pthread_attr_t* restrict, void* (*)(void*), + void* restrict); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) { + int ret = __pthread_create(thr, __ATTRP_C11_THREAD, (void* (*)(void*))func, arg); + switch (ret) { + case 0: + return thrd_success; + case EAGAIN: + return thrd_nomem; + default: + return thrd_error; + } +} diff --git a/third_party/ulib/musl/src/thread/thrd_exit.c b/third_party/ulib/musl/src/thread/thrd_exit.c new file mode 100644 index 000000000..1b2ab364c --- /dev/null +++ b/third_party/ulib/musl/src/thread/thrd_exit.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" +#include + +_Noreturn void __pthread_exit(void*); + +_Noreturn void thrd_exit(int result) { + __pthread_exit((void*)(intptr_t)result); +} diff --git a/third_party/ulib/musl/src/thread/thrd_join.c b/third_party/ulib/musl/src/thread/thrd_join.c new file mode 100644 index 000000000..dc3a0547e --- /dev/null +++ b/third_party/ulib/musl/src/thread/thrd_join.c @@ -0,0 +1,11 @@ +#include +#include + +int __pthread_join(thrd_t, void**); + +int thrd_join(thrd_t t, int* res) { + void* pthread_res; + __pthread_join(t, &pthread_res); + if (res) *res = (int)(intptr_t)pthread_res; + return thrd_success; +} diff --git a/third_party/ulib/musl/src/thread/thrd_sleep.c b/third_party/ulib/musl/src/thread/thrd_sleep.c new file mode 100644 index 000000000..fd250b1af --- /dev/null +++ b/third_party/ulib/musl/src/thread/thrd_sleep.c @@ -0,0 +1,15 @@ +#include "syscall.h" +#include +#include + +int thrd_sleep(const struct timespec* req, struct timespec* rem) { + int ret = __syscall(SYS_nanosleep, req, rem); + switch (ret) { + case 0: + return 0; + case -EINTR: + return -1; /* value specified by C11 */ + default: + return -2; + } +} diff --git a/third_party/ulib/musl/src/thread/thrd_yield.c b/third_party/ulib/musl/src/thread/thrd_yield.c new file mode 100644 index 000000000..e82e8f3aa --- /dev/null +++ b/third_party/ulib/musl/src/thread/thrd_yield.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +void thrd_yield() { + __syscall(SYS_sched_yield); +} diff --git a/third_party/ulib/musl/src/thread/tls.c b/third_party/ulib/musl/src/thread/tls.c new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/ulib/musl/src/thread/tss_create.c b/third_party/ulib/musl/src/thread/tss_create.c new file mode 100644 index 000000000..c56907fc1 --- /dev/null +++ b/third_party/ulib/musl/src/thread/tss_create.c @@ -0,0 +1,10 @@ +#include + +int __pthread_key_create(tss_t*, void (*)(void*)); + +int tss_create(tss_t* tss, tss_dtor_t dtor) { + /* Different error returns are possible. C glues them together into + * just failure notification. Can't be optimized to a tail call, + * unless thrd_error equals EAGAIN. */ + return __pthread_key_create(tss, dtor) ? thrd_error : thrd_success; +} diff --git a/third_party/ulib/musl/src/thread/tss_delete.c b/third_party/ulib/musl/src/thread/tss_delete.c new file mode 100644 index 000000000..7b6c0be11 --- /dev/null +++ b/third_party/ulib/musl/src/thread/tss_delete.c @@ -0,0 +1,7 @@ +#include + +int __pthread_key_delete(tss_t k); + +void tss_delete(tss_t key) { + __pthread_key_delete(key); +} diff --git a/third_party/ulib/musl/src/thread/tss_set.c b/third_party/ulib/musl/src/thread/tss_set.c new file mode 100644 index 000000000..a01274f41 --- /dev/null +++ b/third_party/ulib/musl/src/thread/tss_set.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" +#include + +int tss_set(tss_t k, void* x) { + struct pthread* self = __pthread_self(); + /* Avoid unnecessary COW */ + if (self->tsd[k] != x) { + self->tsd[k] = x; + self->tsd_used = 1; + } + return thrd_success; +} diff --git a/third_party/ulib/musl/src/thread/vmlock.c b/third_party/ulib/musl/src/thread/vmlock.c new file mode 100644 index 000000000..5c41c8b48 --- /dev/null +++ b/third_party/ulib/musl/src/thread/vmlock.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" + +static volatile int vmlock[2]; + +void __vm_wait() { + int tmp; + while ((tmp = vmlock[0])) + __wait(vmlock, vmlock + 1, tmp); +} + +void __vm_lock() { + a_inc(vmlock); +} + +void __vm_unlock() { + if (a_fetch_add(vmlock, -1) == 1 && vmlock[1]) __wake(vmlock, -1); +} diff --git a/third_party/ulib/musl/src/thread/x32/clone.s b/third_party/ulib/musl/src/thread/x32/clone.s new file mode 100644 index 000000000..eed461510 --- /dev/null +++ b/third_party/ulib/musl/src/thread/x32/clone.s @@ -0,0 +1,25 @@ +.text +.global __clone +.type __clone,@function +__clone: + movl $0x40000038,%eax /* SYS_clone */ + mov %rdi,%r11 + mov %rdx,%rdi + mov %r8,%rdx + mov %r9,%r8 + mov 8(%rsp),%r10 + mov %r11,%r9 + and $-16,%rsi + sub $8,%rsi + mov %rcx,(%rsi) + syscall + test %eax,%eax + jnz 1f + xor %ebp,%ebp + pop %rdi + call *%r9 + mov %eax,%edi + movl $0x4000003c,%eax /* SYS_exit */ + syscall + hlt +1: ret diff --git a/third_party/ulib/musl/src/thread/x32/syscall_cp.s b/third_party/ulib/musl/src/thread/x32/syscall_cp.s new file mode 100644 index 000000000..9805af0ae --- /dev/null +++ b/third_party/ulib/musl/src/thread/x32/syscall_cp.s @@ -0,0 +1,31 @@ +.text +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_internal +.hidden __syscall_cp_internal +.type __syscall_cp_internal,@function +__syscall_cp_internal: + +__cp_begin: + mov (%rdi),%eax + test %eax,%eax + jnz __cp_cancel + mov %rdi,%r11 + mov %rsi,%rax + mov %rdx,%rdi + mov %rcx,%rsi + mov %r8,%rdx + mov %r9,%r10 + mov 8(%rsp),%r8 + mov 16(%rsp),%r9 + mov %r11,8(%rsp) + syscall +__cp_end: + ret +__cp_cancel: + jmp __cancel diff --git a/third_party/ulib/musl/src/thread/x32/syscall_cp_fixup.c b/third_party/ulib/musl/src/thread/x32/syscall_cp_fixup.c new file mode 100644 index 000000000..9a8ea7940 --- /dev/null +++ b/third_party/ulib/musl/src/thread/x32/syscall_cp_fixup.c @@ -0,0 +1,50 @@ +#include + +__attribute__((__visibility__("hidden"))) long __syscall_cp_internal(volatile void*, long long, + long long, long long, + long long, long long, + long long, long long); + +struct __timespec { + long long tv_sec; + long tv_nsec; +}; +struct __timespec_kernel { + long long tv_sec; + long long tv_nsec; +}; +#define __tsc(X) ((struct __timespec*)(unsigned long)(X)) +#define __fixup(X) \ + do { \ + if (X) { \ + ts->tv_sec = __tsc(X)->tv_sec; \ + ts->tv_nsec = __tsc(X)->tv_nsec; \ + (X) = (unsigned long)ts; \ + } \ + } while (0) + +__attribute__((__visibility__("hidden"))) long __syscall_cp_asm(volatile void* foo, long long n, + long long a1, long long a2, + long long a3, long long a4, + long long a5, long long a6) { + struct __timespec_kernel ts[1]; + switch (n) { + case SYS_mq_timedsend: + case SYS_mq_timedreceive: + case SYS_pselect6: + __fixup(a5); + break; + case SYS_futex: + if ((a2 & (~128 /* FUTEX_PRIVATE_FLAG */)) == 0 /* FUTEX_WAIT */) __fixup(a4); + break; + case SYS_clock_nanosleep: + case SYS_rt_sigtimedwait: + case SYS_ppoll: + __fixup(a3); + break; + case SYS_nanosleep: + __fixup(a1); + break; + } + return __syscall_cp_internal(foo, n, a1, a2, a3, a4, a5, a6); +} diff --git a/third_party/ulib/musl/src/thread/x86_64/clone.s b/third_party/ulib/musl/src/thread/x86_64/clone.s new file mode 100644 index 000000000..ee59903a2 --- /dev/null +++ b/third_party/ulib/musl/src/thread/x86_64/clone.s @@ -0,0 +1,27 @@ +.text +.global __clone +.type __clone,@function +__clone: + xor %eax,%eax + mov $56,%al + mov %rdi,%r11 + mov %rdx,%rdi + mov %r8,%rdx + mov %r9,%r8 + mov 8(%rsp),%r10 + mov %r11,%r9 + and $-16,%rsi + sub $8,%rsi + mov %rcx,(%rsi) + syscall + test %eax,%eax + jnz 1f + xor %ebp,%ebp + pop %rdi + call *%r9 + mov %eax,%edi + xor %eax,%eax + mov $60,%al + syscall + hlt +1: ret diff --git a/third_party/ulib/musl/src/thread/x86_64/syscall_cp.s b/third_party/ulib/musl/src/thread/x86_64/syscall_cp.s new file mode 100644 index 000000000..4f101716d --- /dev/null +++ b/third_party/ulib/musl/src/thread/x86_64/syscall_cp.s @@ -0,0 +1,31 @@ +.text +.global __cp_begin +.hidden __cp_begin +.global __cp_end +.hidden __cp_end +.global __cp_cancel +.hidden __cp_cancel +.hidden __cancel +.global __syscall_cp_asm +.hidden __syscall_cp_asm +.type __syscall_cp_asm,@function +__syscall_cp_asm: + +__cp_begin: + mov (%rdi),%eax + test %eax,%eax + jnz __cp_cancel + mov %rdi,%r11 + mov %rsi,%rax + mov %rdx,%rdi + mov %rcx,%rsi + mov %r8,%rdx + mov %r9,%r10 + mov 8(%rsp),%r8 + mov 16(%rsp),%r9 + mov %r11,8(%rsp) + syscall +__cp_end: + ret +__cp_cancel: + jmp __cancel diff --git a/third_party/ulib/musl/src/time/BUILD.gn b/third_party/ulib/musl/src/time/BUILD.gn new file mode 100644 index 000000000..154d8ba57 --- /dev/null +++ b/third_party/ulib/musl/src/time/BUILD.gn @@ -0,0 +1,49 @@ +source_set("time") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__asctime.c", + "__map_file.c", + "__month_to_secs.c", + "__secs_to_tm.c", + "__tm_to_secs.c", + "__tz.c", + "__year_to_secs.c", + "asctime.c", + "asctime_r.c", + "clock.c", + "clock_getcpuclockid.c", + "clock_getres.c", + "clock_gettime.c", + "clock_nanosleep.c", + "clock_settime.c", + "ctime.c", + "ctime_r.c", + "difftime.c", + "ftime.c", + "getdate.c", + "gettimeofday.c", + "gmtime.c", + "gmtime_r.c", + "localtime.c", + "localtime_r.c", + "mktime.c", + "nanosleep.c", + "strftime.c", + "strptime.c", + "time.c", + "timegm.c", + + #"timer_create.c", + #"timer_delete.c", + "timer_getoverrun.c", + "timer_gettime.c", + "timer_settime.c", + "times.c", + "timespec_get.c", + "utime.c", + "wcsftime.c", + ] +} diff --git a/third_party/ulib/musl/src/time/__asctime.c b/third_party/ulib/musl/src/time/__asctime.c new file mode 100644 index 000000000..fb0e00786 --- /dev/null +++ b/third_party/ulib/musl/src/time/__asctime.c @@ -0,0 +1,24 @@ +#include "atomic.h" +#include +#include +#include + +const char* __nl_langinfo(nl_item); + +char* __asctime(const struct tm* restrict tm, char* restrict buf) { + /* FIXME: change __nl_langinfo to __nl_langinfo_l with explicit C + * locale once we have locales */ + if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", __nl_langinfo(ABDAY_1 + tm->tm_wday), + __nl_langinfo(ABMON_1 + tm->tm_mon), tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec, 1900 + tm->tm_year) >= 26) { + /* ISO C requires us to use the above format string, + * even if it will not fit in the buffer. Thus asctime_r + * is _supposed_ to crash if the fields in tm are too large. + * We follow this behavior and crash "gracefully" to warn + * application developers that they may not be so lucky + * on other implementations (e.g. stack smashing..). + */ + a_crash(); + } + return buf; +} diff --git a/third_party/ulib/musl/src/time/__map_file.c b/third_party/ulib/musl/src/time/__map_file.c new file mode 100644 index 000000000..4366562a2 --- /dev/null +++ b/third_party/ulib/musl/src/time/__map_file.c @@ -0,0 +1,19 @@ +#include "syscall.h" +#include +#include +#include + +void* __mmap(void*, size_t, int, int, int, off_t); + +const char unsigned* __map_file(const char* pathname, size_t* size) { + struct stat st; + const unsigned char* map = MAP_FAILED; + int fd = __sys_open(pathname, O_RDONLY | O_CLOEXEC | O_NONBLOCK); + if (fd < 0) return 0; + if (!__syscall(SYS_fstat, fd, &st)) { + map = __mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + *size = st.st_size; + } + __syscall(SYS_close, fd); + return map == MAP_FAILED ? 0 : map; +} diff --git a/third_party/ulib/musl/src/time/__month_to_secs.c b/third_party/ulib/musl/src/time/__month_to_secs.c new file mode 100644 index 000000000..9a478219e --- /dev/null +++ b/third_party/ulib/musl/src/time/__month_to_secs.c @@ -0,0 +1,8 @@ +int __month_to_secs(int month, int is_leap) { + static const int secs_through_month[] = {0, 31 * 86400, 59 * 86400, 90 * 86400, + 120 * 86400, 151 * 86400, 181 * 86400, 212 * 86400, + 243 * 86400, 273 * 86400, 304 * 86400, 334 * 86400}; + int t = secs_through_month[month]; + if (is_leap && month >= 2) t += 86400; + return t; +} diff --git a/third_party/ulib/musl/src/time/__secs_to_tm.c b/third_party/ulib/musl/src/time/__secs_to_tm.c new file mode 100644 index 000000000..1cb2701b5 --- /dev/null +++ b/third_party/ulib/musl/src/time/__secs_to_tm.c @@ -0,0 +1,78 @@ +#include "time_impl.h" +#include + +/* 2000-03-01 (mod 400 year, immediately after feb29 */ +#define LEAPOCH (946684800LL + 86400 * (31 + 29)) + +#define DAYS_PER_400Y (365 * 400 + 97) +#define DAYS_PER_100Y (365 * 100 + 24) +#define DAYS_PER_4Y (365 * 4 + 1) + +int __secs_to_tm(long long t, struct tm* tm) { + long long days, secs, years; + int remdays, remsecs, remyears; + int qc_cycles, c_cycles, q_cycles; + int months; + int wday, yday, leap; + static const char days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; + + /* Reject time_t values whose year would overflow int */ + if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) return -1; + + secs = t - LEAPOCH; + days = secs / 86400; + remsecs = secs % 86400; + if (remsecs < 0) { + remsecs += 86400; + days--; + } + + wday = (3 + days) % 7; + if (wday < 0) wday += 7; + + qc_cycles = days / DAYS_PER_400Y; + remdays = days % DAYS_PER_400Y; + if (remdays < 0) { + remdays += DAYS_PER_400Y; + qc_cycles--; + } + + c_cycles = remdays / DAYS_PER_100Y; + if (c_cycles == 4) c_cycles--; + remdays -= c_cycles * DAYS_PER_100Y; + + q_cycles = remdays / DAYS_PER_4Y; + if (q_cycles == 25) q_cycles--; + remdays -= q_cycles * DAYS_PER_4Y; + + remyears = remdays / 365; + if (remyears == 4) remyears--; + remdays -= remyears * 365; + + leap = !remyears && (q_cycles || !c_cycles); + yday = remdays + 31 + 28 + leap; + if (yday >= 365 + leap) yday -= 365 + leap; + + years = remyears + 4 * q_cycles + 100 * c_cycles + 400LL * qc_cycles; + + for (months = 0; days_in_month[months] <= remdays; months++) + remdays -= days_in_month[months]; + + if (years + 100 > INT_MAX || years + 100 < INT_MIN) return -1; + + tm->tm_year = years + 100; + tm->tm_mon = months + 2; + if (tm->tm_mon >= 12) { + tm->tm_mon -= 12; + tm->tm_year++; + } + tm->tm_mday = remdays + 1; + tm->tm_wday = wday; + tm->tm_yday = yday; + + tm->tm_hour = remsecs / 3600; + tm->tm_min = remsecs / 60 % 60; + tm->tm_sec = remsecs % 60; + + return 0; +} diff --git a/third_party/ulib/musl/src/time/__tm_to_secs.c b/third_party/ulib/musl/src/time/__tm_to_secs.c new file mode 100644 index 000000000..b8a049211 --- /dev/null +++ b/third_party/ulib/musl/src/time/__tm_to_secs.c @@ -0,0 +1,23 @@ +#include "time_impl.h" + +long long __tm_to_secs(const struct tm* tm) { + int is_leap; + long long year = tm->tm_year; + int month = tm->tm_mon; + if (month >= 12 || month < 0) { + int adj = month / 12; + month %= 12; + if (month < 0) { + adj--; + month += 12; + } + year += adj; + } + long long t = __year_to_secs(year, &is_leap); + t += __month_to_secs(month, is_leap); + t += 86400LL * (tm->tm_mday - 1); + t += 3600LL * tm->tm_hour; + t += 60LL * tm->tm_min; + t += tm->tm_sec; + return t; +} diff --git a/third_party/ulib/musl/src/time/__tz.c b/third_party/ulib/musl/src/time/__tz.c new file mode 100644 index 000000000..738869279 --- /dev/null +++ b/third_party/ulib/musl/src/time/__tz.c @@ -0,0 +1,430 @@ +#include "libc.h" +#include "time_impl.h" +#include +#include +#include +#include + +#include + +long __timezone = 0; +int __daylight = 0; +char* __tzname[2] = {0, 0}; + +weak_alias(__timezone, timezone); +weak_alias(__daylight, daylight); +weak_alias(__tzname, tzname); + +static char std_name[TZNAME_MAX + 1]; +static char dst_name[TZNAME_MAX + 1]; +const char __gmt[] = "GMT"; + +static int dst_off; +static int r0[5], r1[5]; + +static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end; +static size_t map_size; + +static char old_tz_buf[32]; +static char* old_tz = old_tz_buf; +static size_t old_tz_size = sizeof old_tz_buf; + +static mxr_mutex_t lock; + +static int getint(const char** p) { + unsigned x; + for (x = 0; **p - '0' < 10U; (*p)++) + x = **p - '0' + 10 * x; + return x; +} + +static int getoff(const char** p) { + int neg = 0; + if (**p == '-') { + ++*p; + neg = 1; + } else if (**p == '+') { + ++*p; + } + int off = 3600 * getint(p); + if (**p == ':') { + ++*p; + off += 60 * getint(p); + if (**p == ':') { + ++*p; + off += getint(p); + } + } + return neg ? -off : off; +} + +static void getrule(const char** p, int rule[5]) { + int r = rule[0] = **p; + + if (r != 'M') { + if (r == 'J') + ++*p; + else + rule[0] = 0; + rule[1] = getint(p); + } else { + ++*p; + rule[1] = getint(p); + ++*p; + rule[2] = getint(p); + ++*p; + rule[3] = getint(p); + } + + if (**p == '/') { + ++*p; + rule[4] = getoff(p); + } else { + rule[4] = 7200; + } +} + +static void getname(char* d, const char** p) { + int i; + if (**p == '<') { + ++*p; + for (i = 0; **p != '>' && i < TZNAME_MAX; i++) + d[i] = (*p)[i]; + ++*p; + } else { + for (i = 0; ((*p)[i] | 32) - 'a' < 26U && i < TZNAME_MAX; i++) + d[i] = (*p)[i]; + } + *p += i; + d[i] = 0; +} + +#define VEC(...) ((const unsigned char[]){__VA_ARGS__}) + +static uint32_t zi_read32(const unsigned char* z) { + return (unsigned)z[0] << 24 | z[1] << 16 | z[2] << 8 | z[3]; +} + +static size_t zi_dotprod(const unsigned char* z, const unsigned char* v, size_t n) { + size_t y; + uint32_t x; + for (y = 0; n; n--, z += 4, v++) { + x = zi_read32(z); + y += x * *v; + } + return y; +} + +int __munmap(void*, size_t); + +static void do_tzset(void) { + char buf[NAME_MAX + 25], *pathname = buf + 24; + const char* try + , *s, *p; + const unsigned char* map = 0; + size_t i; + static const char search[] = "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; + + s = getenv("TZ"); + if (!s) s = "/etc/localtime"; + if (!*s) s = __gmt; + + if (old_tz && !strcmp(s, old_tz)) return; + + if (zi) __munmap((void*)zi, map_size); + + /* Cache the old value of TZ to check if it has changed. Avoid + * free so as not to pull it into static programs. Growth + * strategy makes it so free would have minimal benefit anyway. */ + i = strlen(s); + if (i > PATH_MAX + 1) s = __gmt, i = 3; + if (i >= old_tz_size) { + old_tz_size *= 2; + if (i >= old_tz_size) old_tz_size = i + 1; + if (old_tz_size > PATH_MAX + 2) old_tz_size = PATH_MAX + 2; + old_tz = malloc(old_tz_size); + } + if (old_tz) memcpy(old_tz, s, i + 1); + + /* Non-suid can use an absolute tzfile pathname or a relative + * pathame beginning with "."; in secure mode, only the + * standard path will be searched. */ + if (*s == ':' || ((p = strchr(s, '/')) && !memchr(s, ',', p - s))) { + if (*s == ':') s++; + if (*s == '/' || *s == '.') { + if (!libc.secure || !strcmp(s, "/etc/localtime")) map = __map_file(s, &map_size); + } else { + size_t l = strlen(s); + if (l <= NAME_MAX && !strchr(s, '.')) { + memcpy(pathname, s, l + 1); + pathname[l] = 0; + for (try = search; !map && *try; try += l + 1) { + l = strlen(try); + memcpy(pathname - l, try, l); + map = __map_file(pathname - l, &map_size); + } + } + } + if (!map) s = __gmt; + } + if (map && (map_size < 44 || memcmp(map, "TZif", 4))) { + __munmap((void*)map, map_size); + map = 0; + s = __gmt; + } + + zi = map; + if (map) { + int scale = 2; + if (sizeof(time_t) > 4 && map[4] == '2') { + size_t skip = zi_dotprod(zi + 20, VEC(1, 1, 8, 5, 6, 1), 6); + trans = zi + skip + 44 + 44; + scale++; + } else { + trans = zi + 44; + } + index = trans + (zi_read32(trans - 12) << scale); + types = index + zi_read32(trans - 12); + abbrevs = types + 6 * zi_read32(trans - 8); + abbrevs_end = abbrevs + zi_read32(trans - 4); + if (zi[map_size - 1] == '\n') { + for (s = (const char*)zi + map_size - 2; *s != '\n'; s--) + ; + s++; + } else { + const unsigned char* p; + __tzname[0] = __tzname[1] = 0; + __daylight = __timezone = dst_off = 0; + for (i = 0; i < 5; i++) + r0[i] = r1[i] = 0; + for (p = types; p < abbrevs; p += 6) { + if (!p[4] && !__tzname[0]) { + __tzname[0] = (char*)abbrevs + p[5]; + __timezone = -zi_read32(p); + } + if (p[4] && !__tzname[1]) { + __tzname[1] = (char*)abbrevs + p[5]; + dst_off = -zi_read32(p); + __daylight = 1; + } + } + if (!__tzname[0]) __tzname[0] = __tzname[1]; + if (!__tzname[0]) __tzname[0] = (char*)__gmt; + if (!__daylight) { + __tzname[1] = __tzname[0]; + dst_off = __timezone; + } + return; + } + } + + if (!s) s = __gmt; + getname(std_name, &s); + __tzname[0] = std_name; + __timezone = getoff(&s); + getname(dst_name, &s); + __tzname[1] = dst_name; + if (dst_name[0]) { + __daylight = 1; + if (*s == '+' || *s == '-' || *s - '0' < 10U) + dst_off = getoff(&s); + else + dst_off = __timezone - 3600; + } else { + __daylight = 0; + dst_off = 0; + } + + if (*s == ',') s++, getrule(&s, r0); + if (*s == ',') s++, getrule(&s, r1); +} + +/* Search zoneinfo rules to find the one that applies to the given time, + * and determine alternate opposite-DST-status rule that may be needed. */ + +static size_t scan_trans(long long t, int local, size_t* alt) { + int scale = 3 - (trans == zi + 44); + uint64_t x; + int off = 0; + + size_t a = 0, n = (index - trans) >> scale, m; + + if (!n) { + if (alt) *alt = 0; + return 0; + } + + /* Binary search for 'most-recent rule before t'. */ + while (n > 1) { + m = a + n / 2; + x = zi_read32(trans + (m << scale)); + if (scale == 3) + x = x << 32 | zi_read32(trans + (m << scale) + 4); + else + x = (int32_t)x; + if (local) off = (int32_t)zi_read32(types + 6 * index[m - 1]); + if (t - off < (int64_t)x) { + n /= 2; + } else { + a = m; + n -= n / 2; + } + } + + /* First and last entry are special. First means to use lowest-index + * non-DST type. Last means to apply POSIX-style rule if available. */ + n = (index - trans) >> scale; + if (a == n - 1) return -1; + if (a == 0) { + x = zi_read32(trans + (a << scale)); + if (scale == 3) + x = x << 32 | zi_read32(trans + (a << scale) + 4); + else + x = (int32_t)x; + if (local) off = (int32_t)zi_read32(types + 6 * index[a - 1]); + if (t - off < (int64_t)x) { + for (a = 0; a < (abbrevs - types) / 6; a++) { + if (types[6 * a + 4] != types[4]) break; + } + if (a == (abbrevs - types) / 6) a = 0; + if (types[6 * a + 4]) { + *alt = a; + return 0; + } else { + *alt = 0; + return a; + } + } + } + + /* Try to find a neighboring opposite-DST-status rule. */ + if (alt) { + if (a && types[6 * index[a - 1] + 4] != types[6 * index[a] + 4]) + *alt = index[a - 1]; + else if (a + 1 < n && types[6 * index[a + 1] + 4] != types[6 * index[a] + 4]) + *alt = index[a + 1]; + else + *alt = index[a]; + } + + return index[a]; +} + +static int days_in_month(int m, int is_leap) { + if (m == 2) + return 28 + is_leap; + else + return 30 + ((0xad5 >> (m - 1)) & 1); +} + +/* Convert a POSIX DST rule plus year to seconds since epoch. */ + +static long long rule_to_secs(const int* rule, int year) { + int is_leap; + long long t = __year_to_secs(year, &is_leap); + int x, m, n, d; + if (rule[0] != 'M') { + x = rule[1]; + if (rule[0] == 'J' && (x < 60 || !is_leap)) x--; + t += 86400 * x; + } else { + m = rule[1]; + n = rule[2]; + d = rule[3]; + t += __month_to_secs(m - 1, is_leap); + int wday = (int)((t + 4 * 86400) % (7 * 86400)) / 86400; + int days = d - wday; + if (days < 0) days += 7; + if (n == 5 && days + 28 >= days_in_month(m, is_leap)) n = 4; + t += 86400 * (days + 7 * (n - 1)); + } + t += rule[4]; + return t; +} + +/* Determine the time zone in effect for a given time in seconds since the + * epoch. It can be given in local or universal time. The results will + * indicate whether DST is in effect at the queried time, and will give both + * the GMT offset for the active zone/DST rule and the opposite DST. This + * enables a caller to efficiently adjust for the case where an explicit + * DST specification mismatches what would be in effect at the time. */ + +void __secs_to_zone(long long t, int local, int* isdst, long* offset, long* oppoff, + const char** zonename) { + mxr_mutex_lock(&lock); + + do_tzset(); + + if (zi) { + size_t alt, i = scan_trans(t, local, &alt); + if (i != -1) { + *isdst = types[6 * i + 4]; + *offset = (int32_t)zi_read32(types + 6 * i); + *zonename = (const char*)abbrevs + types[6 * i + 5]; + if (oppoff) *oppoff = (int32_t)zi_read32(types + 6 * alt); + mxr_mutex_unlock(&lock); + return; + } + } + + if (!__daylight) goto std; + + /* FIXME: may be broken if DST changes right at year boundary? + * Also, this could be more efficient.*/ + long long y = t / 31556952 + 70; + while (__year_to_secs(y, 0) > t) + y--; + while (__year_to_secs(y + 1, 0) < t) + y++; + + long long t0 = rule_to_secs(r0, y); + long long t1 = rule_to_secs(r1, y); + + if (t0 < t1) { + if (!local) { + t0 += __timezone; + t1 += dst_off; + } + if (t >= t0 && t < t1) goto dst; + goto std; + } else { + if (!local) { + t1 += __timezone; + t0 += dst_off; + } + if (t >= t1 && t < t0) goto std; + goto dst; + } +std: + *isdst = 0; + *offset = -__timezone; + if (oppoff) *oppoff = -dst_off; + *zonename = __tzname[0]; + mxr_mutex_unlock(&lock); + return; +dst: + *isdst = 1; + *offset = -dst_off; + if (oppoff) *oppoff = -__timezone; + *zonename = __tzname[1]; + mxr_mutex_unlock(&lock); +} + +void __tzset(void) { + mxr_mutex_lock(&lock); + do_tzset(); + mxr_mutex_unlock(&lock); +} + +weak_alias(__tzset, tzset); + +const char* __tm_to_tzname(const struct tm* tm) { + const void* p = tm->__tm_zone; + mxr_mutex_lock(&lock); + do_tzset(); + if (p != __gmt && p != __tzname[0] && p != __tzname[1] && + (!zi || (uintptr_t)p - (uintptr_t)abbrevs >= abbrevs_end - abbrevs)) + p = ""; + mxr_mutex_unlock(&lock); + return p; +} diff --git a/third_party/ulib/musl/src/time/__year_to_secs.c b/third_party/ulib/musl/src/time/__year_to_secs.c new file mode 100644 index 000000000..beab94de2 --- /dev/null +++ b/third_party/ulib/musl/src/time/__year_to_secs.c @@ -0,0 +1,51 @@ +long long __year_to_secs(long long year, int* is_leap) { + if (year - 2ULL <= 136) { + int y = year; + int leaps = (y - 68) >> 2; + if (!((y - 68) & 3)) { + leaps--; + if (is_leap) *is_leap = 1; + } else if (is_leap) + *is_leap = 0; + return 31536000 * (y - 70) + 86400 * leaps; + } + + int cycles, centuries, leaps, rem; + + if (!is_leap) is_leap = &(int){0}; + cycles = (year - 100) / 400; + rem = (year - 100) % 400; + if (rem < 0) { + cycles--; + rem += 400; + } + if (!rem) { + *is_leap = 1; + centuries = 0; + leaps = 0; + } else { + if (rem >= 200) { + if (rem >= 300) + centuries = 3, rem -= 300; + else + centuries = 2, rem -= 200; + } else { + if (rem >= 100) + centuries = 1, rem -= 100; + else + centuries = 0; + } + if (!rem) { + *is_leap = 0; + leaps = 0; + } else { + leaps = rem / 4U; + rem %= 4U; + *is_leap = !rem; + } + } + + leaps += 97 * cycles + 24 * centuries - *is_leap; + + return (year - 100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; +} diff --git a/third_party/ulib/musl/src/time/asctime.c b/third_party/ulib/musl/src/time/asctime.c new file mode 100644 index 000000000..500a59022 --- /dev/null +++ b/third_party/ulib/musl/src/time/asctime.c @@ -0,0 +1,8 @@ +#include + +char* __asctime(const struct tm*, char*); + +char* asctime(const struct tm* tm) { + static char buf[26]; + return __asctime(tm, buf); +} diff --git a/third_party/ulib/musl/src/time/asctime_r.c b/third_party/ulib/musl/src/time/asctime_r.c new file mode 100644 index 000000000..39afe2768 --- /dev/null +++ b/third_party/ulib/musl/src/time/asctime_r.c @@ -0,0 +1,7 @@ +#include + +char* __asctime(const struct tm* restrict, char* restrict); + +char* asctime_r(const struct tm* restrict tm, char* restrict buf) { + return __asctime(tm, buf); +} diff --git a/third_party/ulib/musl/src/time/clock.c b/third_party/ulib/musl/src/time/clock.c new file mode 100644 index 000000000..03dd05f63 --- /dev/null +++ b/third_party/ulib/musl/src/time/clock.c @@ -0,0 +1,15 @@ +#include +#include + +int __clock_gettime(clockid_t, struct timespec*); + +clock_t clock() { + struct timespec ts; + + if (__clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) return -1; + + if (ts.tv_sec > LONG_MAX / 1000000 || ts.tv_nsec / 1000 > LONG_MAX - 1000000 * ts.tv_sec) + return -1; + + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} diff --git a/third_party/ulib/musl/src/time/clock_getcpuclockid.c b/third_party/ulib/musl/src/time/clock_getcpuclockid.c new file mode 100644 index 000000000..ea6785f00 --- /dev/null +++ b/third_party/ulib/musl/src/time/clock_getcpuclockid.c @@ -0,0 +1,13 @@ +#include "syscall.h" +#include +#include +#include + +int clock_getcpuclockid(pid_t pid, clockid_t* clk) { + struct timespec ts; + clockid_t id = (-pid - 1) * 8U + 2; + int ret = __syscall(SYS_clock_getres, id, &ts); + if (ret) return -ret; + *clk = id; + return 0; +} diff --git a/third_party/ulib/musl/src/time/clock_getres.c b/third_party/ulib/musl/src/time/clock_getres.c new file mode 100644 index 000000000..1b6b01f97 --- /dev/null +++ b/third_party/ulib/musl/src/time/clock_getres.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int clock_getres(clockid_t clk, struct timespec* ts) { + return syscall(SYS_clock_getres, clk, ts); +} diff --git a/third_party/ulib/musl/src/time/clock_gettime.c b/third_party/ulib/musl/src/time/clock_gettime.c new file mode 100644 index 000000000..0d17d34ea --- /dev/null +++ b/third_party/ulib/musl/src/time/clock_gettime.c @@ -0,0 +1,16 @@ +#include "libc.h" +#include +#include + +#include + +#define NS_PER_S (1000000000ull) + +int __clock_gettime(clockid_t clk, struct timespec* ts) { + mx_time_t now = _magenta_current_time(); + ts->tv_sec = now / NS_PER_S; + ts->tv_nsec = now % NS_PER_S; + return 0; +} + +weak_alias(__clock_gettime, clock_gettime); diff --git a/third_party/ulib/musl/src/time/clock_nanosleep.c b/third_party/ulib/musl/src/time/clock_nanosleep.c new file mode 100644 index 000000000..ecb8c15cc --- /dev/null +++ b/third_party/ulib/musl/src/time/clock_nanosleep.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int clock_nanosleep(clockid_t clk, int flags, const struct timespec* req, struct timespec* rem) { + return -syscall(SYS_clock_nanosleep, clk, flags, req, rem); +} diff --git a/third_party/ulib/musl/src/time/clock_settime.c b/third_party/ulib/musl/src/time/clock_settime.c new file mode 100644 index 000000000..88193c7f4 --- /dev/null +++ b/third_party/ulib/musl/src/time/clock_settime.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int clock_settime(clockid_t clk, const struct timespec* ts) { + return syscall(SYS_clock_settime, clk, ts); +} diff --git a/third_party/ulib/musl/src/time/ctime.c b/third_party/ulib/musl/src/time/ctime.c new file mode 100644 index 000000000..c0a3f4978 --- /dev/null +++ b/third_party/ulib/musl/src/time/ctime.c @@ -0,0 +1,5 @@ +#include + +char* ctime(const time_t* t) { + return asctime(localtime(t)); +} diff --git a/third_party/ulib/musl/src/time/ctime_r.c b/third_party/ulib/musl/src/time/ctime_r.c new file mode 100644 index 000000000..527ca357c --- /dev/null +++ b/third_party/ulib/musl/src/time/ctime_r.c @@ -0,0 +1,7 @@ +#include + +char* ctime_r(const time_t* t, char* buf) { + struct tm tm; + localtime_r(t, &tm); + return asctime_r(&tm, buf); +} diff --git a/third_party/ulib/musl/src/time/difftime.c b/third_party/ulib/musl/src/time/difftime.c new file mode 100644 index 000000000..d78ac3369 --- /dev/null +++ b/third_party/ulib/musl/src/time/difftime.c @@ -0,0 +1,5 @@ +#include + +double difftime(time_t t1, time_t t0) { + return t1 - t0; +} diff --git a/third_party/ulib/musl/src/time/ftime.c b/third_party/ulib/musl/src/time/ftime.c new file mode 100644 index 000000000..2c648fe27 --- /dev/null +++ b/third_party/ulib/musl/src/time/ftime.c @@ -0,0 +1,11 @@ +#include +#include + +int ftime(struct timeb* tp) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + tp->time = ts.tv_sec; + tp->millitm = ts.tv_nsec / 1000000; + tp->timezone = tp->dstflag = 0; + return 0; +} diff --git a/third_party/ulib/musl/src/time/getdate.c b/third_party/ulib/musl/src/time/getdate.c new file mode 100644 index 000000000..b6ef2eb50 --- /dev/null +++ b/third_party/ulib/musl/src/time/getdate.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +int getdate_err; + +struct tm* getdate(const char* s) { + static struct tm tmbuf; + struct tm* ret = 0; + char* datemsk = getenv("DATEMSK"); + FILE* f = 0; + char fmt[100], *p; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DEFERRED, &cs); + + if (!datemsk) { + getdate_err = 1; + goto out; + } + + f = fopen(datemsk, "rbe"); + if (!f) { + if (errno == ENOMEM) + getdate_err = 6; + else + getdate_err = 2; + goto out; + } + + while (fgets(fmt, sizeof fmt, f)) { + p = strptime(s, fmt, &tmbuf); + if (p && !*p) { + ret = &tmbuf; + goto out; + } + } + + getdate_err = 7; +out: + if (f) fclose(f); + pthread_setcancelstate(cs, 0); + return ret; +} diff --git a/third_party/ulib/musl/src/time/gettimeofday.c b/third_party/ulib/musl/src/time/gettimeofday.c new file mode 100644 index 000000000..1f68c8316 --- /dev/null +++ b/third_party/ulib/musl/src/time/gettimeofday.c @@ -0,0 +1,12 @@ +#include "syscall.h" +#include +#include + +int gettimeofday(struct timeval* restrict tv, void* restrict tz) { + struct timespec ts; + if (!tv) return 0; + clock_gettime(CLOCK_REALTIME, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = (int)ts.tv_nsec / 1000; + return 0; +} diff --git a/third_party/ulib/musl/src/time/gmtime.c b/third_party/ulib/musl/src/time/gmtime.c new file mode 100644 index 000000000..804887aa1 --- /dev/null +++ b/third_party/ulib/musl/src/time/gmtime.c @@ -0,0 +1,9 @@ +#include "time_impl.h" +#include + +struct tm* __gmtime_r(const time_t* restrict, struct tm* restrict); + +struct tm* gmtime(const time_t* t) { + static struct tm tm; + return __gmtime_r(t, &tm); +} diff --git a/third_party/ulib/musl/src/time/gmtime_r.c b/third_party/ulib/musl/src/time/gmtime_r.c new file mode 100644 index 000000000..e558e7a5a --- /dev/null +++ b/third_party/ulib/musl/src/time/gmtime_r.c @@ -0,0 +1,18 @@ +#include "libc.h" +#include "time_impl.h" +#include + +extern const char __gmt[]; + +struct tm* __gmtime_r(const time_t* restrict t, struct tm* restrict tm) { + if (__secs_to_tm(*t, tm) < 0) { + errno = EOVERFLOW; + return 0; + } + tm->tm_isdst = 0; + tm->__tm_gmtoff = 0; + tm->__tm_zone = __gmt; + return tm; +} + +weak_alias(__gmtime_r, gmtime_r); diff --git a/third_party/ulib/musl/src/time/localtime.c b/third_party/ulib/musl/src/time/localtime.c new file mode 100644 index 000000000..7fc4fe15e --- /dev/null +++ b/third_party/ulib/musl/src/time/localtime.c @@ -0,0 +1,8 @@ +#include "time_impl.h" + +struct tm* __localtime_r(const time_t* restrict, struct tm* restrict); + +struct tm* localtime(const time_t* t) { + static struct tm tm; + return __localtime_r(t, &tm); +} diff --git a/third_party/ulib/musl/src/time/localtime_r.c b/third_party/ulib/musl/src/time/localtime_r.c new file mode 100644 index 000000000..d40231624 --- /dev/null +++ b/third_party/ulib/musl/src/time/localtime_r.c @@ -0,0 +1,20 @@ +#include "libc.h" +#include "time_impl.h" +#include + +struct tm* __localtime_r(const time_t* restrict t, struct tm* restrict tm) { + /* Reject time_t values whose year would overflow int because + * __secs_to_zone cannot safely handle them. */ + if (*t < INT_MIN * 31622400LL || *t > INT_MAX * 31622400LL) { + errno = EOVERFLOW; + return 0; + } + __secs_to_zone(*t, 0, &tm->tm_isdst, &tm->__tm_gmtoff, 0, &tm->__tm_zone); + if (__secs_to_tm((long long)*t + tm->__tm_gmtoff, tm) < 0) { + errno = EOVERFLOW; + return 0; + } + return tm; +} + +weak_alias(__localtime_r, localtime_r); diff --git a/third_party/ulib/musl/src/time/mktime.c b/third_party/ulib/musl/src/time/mktime.c new file mode 100644 index 000000000..356636b34 --- /dev/null +++ b/third_party/ulib/musl/src/time/mktime.c @@ -0,0 +1,26 @@ +#include "time_impl.h" +#include + +time_t mktime(struct tm* tm) { + struct tm new; + long opp; + long long t = __tm_to_secs(tm); + + __secs_to_zone(t, 1, &new.tm_isdst, &new.__tm_gmtoff, &opp, &new.__tm_zone); + + if (tm->tm_isdst >= 0 && new.tm_isdst != tm->tm_isdst) t -= opp - new.__tm_gmtoff; + + t -= new.__tm_gmtoff; + if ((time_t)t != t) goto error; + + __secs_to_zone(t, 0, &new.tm_isdst, &new.__tm_gmtoff, &opp, &new.__tm_zone); + + if (__secs_to_tm(t + new.__tm_gmtoff, &new) < 0) goto error; + + *tm = new; + return t; + +error: + errno = EOVERFLOW; + return -1; +} diff --git a/third_party/ulib/musl/src/time/nanosleep.c b/third_party/ulib/musl/src/time/nanosleep.c new file mode 100644 index 000000000..8d8f66c91 --- /dev/null +++ b/third_party/ulib/musl/src/time/nanosleep.c @@ -0,0 +1,13 @@ +#include + +#include + +int nanosleep(const struct timespec* req, struct timespec* rem) { + // |rem| is currently unused in magenta, as it is only to be + // filled in on EINTR, which can't (yet!) happen. + + mx_time_t nanos = req->tv_sec * 1000000000ull; + nanos += req->tv_nsec; + + return _magenta_nanosleep(nanos); +} diff --git a/third_party/ulib/musl/src/time/strftime.c b/third_party/ulib/musl/src/time/strftime.c new file mode 100644 index 000000000..6881acf32 --- /dev/null +++ b/third_party/ulib/musl/src/time/strftime.c @@ -0,0 +1,274 @@ +#include "libc.h" +#include "locale_impl.h" +#include "time_impl.h" +#include +#include +#include +#include +#include +#include +#include + +const char* __nl_langinfo_l(nl_item, locale_t); + +static int is_leap(int y) { + /* Avoid overflow */ + if (y > INT_MAX - 1900) y -= 2000; + y += 1900; + return !(y % 4) && ((y % 100) || !(y % 400)); +} + +static int week_num(const struct tm* tm) { + int val = (tm->tm_yday + 7U - (tm->tm_wday + 6U) % 7) / 7; + /* If 1 Jan is just 1-3 days past Monday, + * the previous week is also in this year. */ + if ((tm->tm_wday + 371U - tm->tm_yday - 2) % 7 <= 2) val++; + if (!val) { + val = 52; + /* If 31 December of prev year a Thursday, + * or Friday of a leap year, then the + * prev year has 53 weeks. */ + int dec31 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 7; + if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year % 400 - 1))) val++; + } else if (val == 53) { + /* If 1 January is not a Thursday, and not + * a Wednesday of a leap year, then this + * year has only 52 weeks. */ + int jan1 = (tm->tm_wday + 371U - tm->tm_yday) % 7; + if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year))) val = 1; + } + return val; +} + +const char* __tm_to_tzname(const struct tm*); +size_t __strftime_l(char* restrict, size_t, const char* restrict, const struct tm* restrict, + locale_t); + +const char* __strftime_fmt_1(char (*s)[100], size_t* l, int f, const struct tm* tm, locale_t loc) { + nl_item item; + long long val; + const char* fmt = "-"; + int width = 2; + + switch (f) { + case 'a': + if (tm->tm_wday > 6U) goto string; + item = ABDAY_1 + tm->tm_wday; + goto nl_strcat; + case 'A': + if (tm->tm_wday > 6U) goto string; + item = DAY_1 + tm->tm_wday; + goto nl_strcat; + case 'h': + case 'b': + if (tm->tm_mon > 11U) goto string; + item = ABMON_1 + tm->tm_mon; + goto nl_strcat; + case 'B': + if (tm->tm_mon > 11U) goto string; + item = MON_1 + tm->tm_mon; + goto nl_strcat; + case 'c': + item = D_T_FMT; + goto nl_strftime; + case 'C': + val = (1900LL + tm->tm_year) / 100; + goto number; + case 'd': + val = tm->tm_mday; + goto number; + case 'D': + fmt = "%m/%d/%y"; + goto recu_strftime; + case 'e': + *l = snprintf(*s, sizeof *s, "%2d", tm->tm_mday); + return *s; + case 'F': + fmt = "%Y-%m-%d"; + goto recu_strftime; + case 'g': + case 'G': + val = tm->tm_year + 1900LL; + if (tm->tm_yday < 3 && week_num(tm) != 1) + val--; + else if (tm->tm_yday > 360 && week_num(tm) == 1) + val++; + if (f == 'g') + val %= 100; + else + width = 4; + goto number; + case 'H': + val = tm->tm_hour; + goto number; + case 'I': + val = tm->tm_hour; + if (!val) + val = 12; + else if (val > 12) + val -= 12; + goto number; + case 'j': + val = tm->tm_yday + 1; + width = 3; + goto number; + case 'm': + val = tm->tm_mon + 1; + goto number; + case 'M': + val = tm->tm_min; + goto number; + case 'n': + *l = 1; + return "\n"; + case 'p': + item = tm->tm_hour >= 12 ? PM_STR : AM_STR; + goto nl_strcat; + case 'r': + item = T_FMT_AMPM; + goto nl_strftime; + case 'R': + fmt = "%H:%M"; + goto recu_strftime; + case 's': + val = __tm_to_secs(tm) - tm->__tm_gmtoff; + width = 1; + goto number; + case 'S': + val = tm->tm_sec; + goto number; + case 't': + *l = 1; + return "\t"; + case 'T': + fmt = "%H:%M:%S"; + goto recu_strftime; + case 'u': + val = tm->tm_wday ? tm->tm_wday : 7; + width = 1; + goto number; + case 'U': + val = (tm->tm_yday + 7U - tm->tm_wday) / 7; + goto number; + case 'W': + val = (tm->tm_yday + 7U - (tm->tm_wday + 6U) % 7) / 7; + goto number; + case 'V': + val = week_num(tm); + goto number; + case 'w': + val = tm->tm_wday; + width = 1; + goto number; + case 'x': + item = D_FMT; + goto nl_strftime; + case 'X': + item = T_FMT; + goto nl_strftime; + case 'y': + val = tm->tm_year % 100; + goto number; + case 'Y': + val = tm->tm_year + 1900LL; + if (val >= 10000) { + *l = snprintf(*s, sizeof *s, "+%lld", val); + return *s; + } + width = 4; + goto number; + case 'z': + if (tm->tm_isdst < 0) { + *l = 0; + return ""; + } + *l = snprintf(*s, sizeof *s, "%+.2ld%.2d", (tm->__tm_gmtoff) / 3600, + abs(tm->__tm_gmtoff % 3600) / 60); + return *s; + case 'Z': + if (tm->tm_isdst < 0) { + *l = 0; + return ""; + } + fmt = __tm_to_tzname(tm); + goto string; + case '%': + *l = 1; + return "%"; + default: + return 0; + } +number: + *l = snprintf(*s, sizeof *s, "%0*lld", width, val); + return *s; +nl_strcat: + fmt = __nl_langinfo_l(item, loc); +string: + *l = strlen(fmt); + return fmt; +nl_strftime: + fmt = __nl_langinfo_l(item, loc); +recu_strftime: + *l = __strftime_l(*s, sizeof *s, fmt, tm, loc); + if (!*l) return 0; + return *s; +} + +size_t __strftime_l(char* restrict s, size_t n, const char* restrict f, + const struct tm* restrict tm, locale_t loc) { + size_t l, k; + char buf[100]; + char* p; + const char* t; + int plus; + unsigned long width; + for (l = 0; l < n; f++) { + if (!*f) { + s[l] = 0; + return l; + } + if (*f != '%') { + s[l++] = *f; + continue; + } + f++; + if ((plus = (*f == '+'))) f++; + width = strtoul(f, &p, 10); + if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { + if (!width && p != f) width = 1; + } else { + width = 0; + } + f = p; + if (*f == 'E' || *f == 'O') f++; + t = __strftime_fmt_1(&buf, &k, *f, tm, loc); + if (!t) break; + if (width) { + for (; *t == '+' || *t == '-' || (*t == '0' && t[1]); t++, k--) + ; + width--; + if (plus && tm->tm_year >= 10000 - 1900) + s[l++] = '+'; + else if (tm->tm_year < -1900) + s[l++] = '-'; + else + width++; + for (; width > k && l < n; width--) + s[l++] = '0'; + } + if (k > n - l) k = n - l; + memcpy(s + l, t, k); + l += k; + } + if (n) { + if (l == n) l = n - 1; + s[l] = 0; + } + return 0; +} + +size_t strftime(char* restrict s, size_t n, const char* restrict f, const struct tm* restrict tm) { + return __strftime_l(s, n, f, tm, CURRENT_LOCALE); +} + +weak_alias(__strftime_l, strftime_l); diff --git a/third_party/ulib/musl/src/time/strptime.c b/third_party/ulib/musl/src/time/strptime.c new file mode 100644 index 000000000..ac8cf866c --- /dev/null +++ b/third_party/ulib/musl/src/time/strptime.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include + +char* strptime(const char* restrict s, const char* restrict f, struct tm* restrict tm) { + int i, w, neg, adj, min, range, *dest, dummy; + const char* ex; + size_t len; + int want_century = 0, century = 0; + while (*f) { + if (*f != '%') { + if (isspace(*f)) + for (; *s && isspace(*s); s++) + ; + else if (*s != *f) + return 0; + else + s++; + f++; + continue; + } + f++; + if (*f == '+') f++; + if (isdigit(*f)) + w = strtoul(f, (void*)&f, 10); + else + w = -1; + adj = 0; + switch (*f++) { + case 'a': + case 'A': + dest = &tm->tm_wday; + min = ABDAY_1; + range = 7; + goto symbolic_range; + case 'b': + case 'B': + case 'h': + dest = &tm->tm_mon; + min = ABMON_1; + range = 12; + goto symbolic_range; + case 'c': + s = strptime(s, nl_langinfo(D_T_FMT), tm); + if (!s) return 0; + break; + case 'C': + dest = ¢ury; + if (w < 0) w = 2; + want_century |= 2; + goto numeric_digits; + case 'd': + case 'e': + dest = &tm->tm_mday; + min = 1; + range = 31; + goto numeric_range; + case 'D': + s = strptime(s, "%m/%d/%y", tm); + if (!s) return 0; + break; + case 'H': + dest = &tm->tm_hour; + min = 0; + range = 24; + goto numeric_range; + case 'I': + dest = &tm->tm_hour; + min = 1; + range = 12; + goto numeric_range; + case 'j': + dest = &tm->tm_yday; + min = 1; + range = 366; + goto numeric_range; + case 'm': + dest = &tm->tm_mon; + min = 1; + range = 12; + adj = 1; + goto numeric_range; + case 'M': + dest = &tm->tm_min; + min = 0; + range = 60; + goto numeric_range; + case 'n': + case 't': + for (; *s && isspace(*s); s++) + ; + break; + case 'p': + ex = nl_langinfo(AM_STR); + len = strlen(ex); + if (!strncasecmp(s, ex, len)) { + tm->tm_hour %= 12; + break; + } + ex = nl_langinfo(PM_STR); + len = strlen(ex); + if (!strncasecmp(s, ex, len)) { + tm->tm_hour %= 12; + tm->tm_hour += 12; + break; + } + return 0; + case 'r': + s = strptime(s, nl_langinfo(T_FMT_AMPM), tm); + if (!s) return 0; + break; + case 'R': + s = strptime(s, "%H:%M", tm); + if (!s) return 0; + break; + case 'S': + dest = &tm->tm_sec; + min = 0; + range = 61; + goto numeric_range; + case 'T': + s = strptime(s, "%H:%M:%S", tm); + if (!s) return 0; + break; + case 'U': + case 'W': + /* Throw away result, for now. (FIXME?) */ + dest = &dummy; + min = 0; + range = 54; + goto numeric_range; + case 'w': + dest = &tm->tm_wday; + min = 0; + range = 7; + goto numeric_range; + case 'x': + s = strptime(s, nl_langinfo(D_FMT), tm); + if (!s) return 0; + break; + case 'X': + s = strptime(s, nl_langinfo(T_FMT), tm); + if (!s) return 0; + break; + case 'y': + dest = &tm->tm_year; + w = 2; + want_century |= 1; + goto numeric_digits; + case 'Y': + dest = &tm->tm_year; + if (w < 0) w = 4; + adj = 1900; + want_century = 0; + goto numeric_digits; + case '%': + if (*s++ != '%') return 0; + break; + default: + return 0; + numeric_range: + if (!isdigit(*s)) return 0; + *dest = 0; + for (i = 1; i <= min + range && isdigit(*s); i *= 10) + *dest = *dest * 10 + *s++ - '0'; + if (*dest - min >= (unsigned)range) return 0; + *dest -= adj; + switch ((char*)dest - (char*)tm) { case offsetof(struct tm, tm_yday):; } + goto update; + numeric_digits: + neg = 0; + if (*s == '+') + s++; + else if (*s == '-') + neg = 1, s++; + if (!isdigit(*s)) return 0; + for (*dest = i = 0; i < w && isdigit(*s); i++) + *dest = *dest * 10 + *s++ - '0'; + if (neg) *dest = -*dest; + *dest -= adj; + goto update; + symbolic_range: + for (i = 2 * range - 1; i >= 0; i--) { + ex = nl_langinfo(min + i); + len = strlen(ex); + if (strncasecmp(s, ex, len)) continue; + s += len; + *dest = i % range; + break; + } + if (i < 0) return 0; + goto update; + update: + // FIXME + ; + } + } + if (want_century) { + if (want_century & 2) + tm->tm_year += century * 100 - 1900; + else if (tm->tm_year <= 68) + tm->tm_year += 100; + } + return (char*)s; +} diff --git a/third_party/ulib/musl/src/time/time.c b/third_party/ulib/musl/src/time/time.c new file mode 100644 index 000000000..67321defa --- /dev/null +++ b/third_party/ulib/musl/src/time/time.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include + +int __clock_gettime(clockid_t, struct timespec*); + +time_t time(time_t* t) { + struct timespec ts; + __clock_gettime(CLOCK_REALTIME, &ts); + if (t) *t = ts.tv_sec; + return ts.tv_sec; +} diff --git a/third_party/ulib/musl/src/time/time_impl.h b/third_party/ulib/musl/src/time/time_impl.h new file mode 100644 index 000000000..fae2defda --- /dev/null +++ b/third_party/ulib/musl/src/time/time_impl.h @@ -0,0 +1,9 @@ +#include + +int __days_in_month(int, int); +int __month_to_secs(int, int); +long long __year_to_secs(long long, int*); +long long __tm_to_secs(const struct tm*); +int __secs_to_tm(long long, struct tm*); +void __secs_to_zone(long long, int, int*, long*, long*, const char**); +const unsigned char* __map_file(const char*, size_t*); diff --git a/third_party/ulib/musl/src/time/timegm.c b/third_party/ulib/musl/src/time/timegm.c new file mode 100644 index 000000000..60f4f6558 --- /dev/null +++ b/third_party/ulib/musl/src/time/timegm.c @@ -0,0 +1,19 @@ +#define _GNU_SOURCE +#include "time_impl.h" +#include + +extern const char __gmt[]; + +time_t timegm(struct tm* tm) { + struct tm new; + long long t = __tm_to_secs(tm); + if (__secs_to_tm(t, &new) < 0) { + errno = EOVERFLOW; + return -1; + } + *tm = new; + tm->tm_isdst = 0; + tm->__tm_gmtoff = 0; + tm->__tm_zone = __gmt; + return t; +} diff --git a/third_party/ulib/musl/src/time/timer_create.c b/third_party/ulib/musl/src/time/timer_create.c new file mode 100644 index 000000000..3fb2b7139 --- /dev/null +++ b/third_party/ulib/musl/src/time/timer_create.c @@ -0,0 +1,128 @@ +#include "pthread_impl.h" +#include +#include + +struct ksigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + int sigev_tid; +}; + +struct start_args { + pthread_barrier_t b; + struct sigevent* sev; +}; + +static void dummy_1(pthread_t self) {} +weak_alias(dummy_1, __pthread_tsd_run_dtors); + +void __reset_tls(void); + +static void cleanup_fromsig(void* p) { + pthread_t self = __pthread_self(); + __pthread_tsd_run_dtors(self); + self->cancel = 0; + self->cancelbuf = 0; + self->canceldisable = 0; + self->cancelasync = 0; + self->unblock_cancel = 0; + __reset_tls(); + longjmp(p, 1); +} + +static void timer_handler(int sig, siginfo_t* si, void* ctx) { + pthread_t self = __pthread_self(); + jmp_buf jb; + void (*notify)(union sigval) = (void (*)(union sigval))self->start; + union sigval val = {.sival_ptr = self->start_arg}; + + if (!setjmp(jb) && si->si_code == SI_TIMER) { + pthread_cleanup_push(cleanup_fromsig, jb); + notify(val); + pthread_cleanup_pop(1); + } +} + +static void install_handler(void) { + struct sigaction sa = {.sa_sigaction = timer_handler, .sa_flags = SA_SIGINFO | SA_RESTART}; + __libc_sigaction(SIGTIMER, &sa, 0); +} + +static void* start(void* arg) { + pthread_t self = __pthread_self(); + struct start_args* args = arg; + int id; + + /* Reuse no-longer-needed thread structure fields to avoid + * needing the timer address in the signal handler. */ + self->start = (void* (*)(void*))args->sev->sigev_notify_function; + self->start_arg = args->sev->sigev_value.sival_ptr; + + pthread_barrier_wait(&args->b); + if ((id = self->timer_id) >= 0) { + __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGTIMER_SET, 0, _NSIG / 8); + __wait(&self->timer_id, 0, id); + __syscall(SYS_timer_delete, id); + } + return 0; +} + +int timer_create(clockid_t clk, struct sigevent* restrict evp, timer_t* restrict res) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_t td; + pthread_attr_t attr; + int r; + struct start_args args; + struct ksigevent ksev, *ksevp = 0; + int timerid; + sigset_t set; + + switch (evp ? evp->sigev_notify : SIGEV_SIGNAL) { + case SIGEV_NONE: + case SIGEV_SIGNAL: + if (evp) { + ksev.sigev_value = evp->sigev_value; + ksev.sigev_signo = evp->sigev_signo; + ksev.sigev_notify = evp->sigev_notify; + ksev.sigev_tid = 0; + ksevp = &ksev; + } + if (syscall(SYS_timer_create, clk, ksevp, &timerid) < 0) return -1; + *res = (void*)(intptr_t)timerid; + break; + case SIGEV_THREAD: + pthread_once(&once, install_handler); + if (evp->sigev_notify_attributes) + attr = *evp->sigev_notify_attributes; + else + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_barrier_init(&args.b, 0, 2); + args.sev = evp; + + __block_app_sigs(&set); + r = pthread_create(&td, &attr, start, &args); + __restore_sigs(&set); + if (r) { + errno = r; + return -1; + } + + ksev.sigev_value.sival_ptr = 0; + ksev.sigev_signo = SIGTIMER; + ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */ + ksev.sigev_tid = td->tid; + if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) timerid = -1; + td->timer_id = timerid; + pthread_barrier_wait(&args.b); + if (timerid < 0) return -1; + *res = (void*)(INTPTR_MIN | (uintptr_t)td >> 1); + break; + default: + errno = EINVAL; + return -1; + } + + return 0; +} diff --git a/third_party/ulib/musl/src/time/timer_delete.c b/third_party/ulib/musl/src/time/timer_delete.c new file mode 100644 index 000000000..52d0e4902 --- /dev/null +++ b/third_party/ulib/musl/src/time/timer_delete.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" +#include +#include + +int timer_delete(timer_t t) { + if ((intptr_t)t < 0) { + pthread_t td = (void*)((uintptr_t)t << 1); + a_store(&td->timer_id, td->timer_id | INT_MIN); + __wake(&td->timer_id, 1); + return 0; + } + return __syscall(SYS_timer_delete, t); +} diff --git a/third_party/ulib/musl/src/time/timer_getoverrun.c b/third_party/ulib/musl/src/time/timer_getoverrun.c new file mode 100644 index 000000000..bd654ee23 --- /dev/null +++ b/third_party/ulib/musl/src/time/timer_getoverrun.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" +#include +#include + +int timer_getoverrun(timer_t t) { + if ((intptr_t)t < 0) { + pthread_t td = (void*)((uintptr_t)t << 1); + t = (void*)(uintptr_t)(td->timer_id & INT_MAX); + } + return syscall(SYS_timer_getoverrun, t); +} diff --git a/third_party/ulib/musl/src/time/timer_gettime.c b/third_party/ulib/musl/src/time/timer_gettime.c new file mode 100644 index 000000000..03ab817c8 --- /dev/null +++ b/third_party/ulib/musl/src/time/timer_gettime.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" +#include +#include + +int timer_gettime(timer_t t, struct itimerspec* val) { + if ((intptr_t)t < 0) { + pthread_t td = (void*)((uintptr_t)t << 1); + t = (void*)(uintptr_t)(td->timer_id & INT_MAX); + } + return syscall(SYS_timer_gettime, t, val); +} diff --git a/third_party/ulib/musl/src/time/timer_settime.c b/third_party/ulib/musl/src/time/timer_settime.c new file mode 100644 index 000000000..5c2d3b6bd --- /dev/null +++ b/third_party/ulib/musl/src/time/timer_settime.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" +#include +#include + +int timer_settime(timer_t t, int flags, const struct itimerspec* restrict val, + struct itimerspec* restrict old) { + if ((intptr_t)t < 0) { + pthread_t td = (void*)((uintptr_t)t << 1); + t = (void*)(uintptr_t)(td->timer_id & INT_MAX); + } + return syscall(SYS_timer_settime, t, flags, val, old); +} diff --git a/third_party/ulib/musl/src/time/times.c b/third_party/ulib/musl/src/time/times.c new file mode 100644 index 000000000..f25238c2c --- /dev/null +++ b/third_party/ulib/musl/src/time/times.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +clock_t times(struct tms* tms) { + return __syscall(SYS_times, tms); +} diff --git a/third_party/ulib/musl/src/time/timespec_get.c b/third_party/ulib/musl/src/time/timespec_get.c new file mode 100644 index 000000000..0ae72bc21 --- /dev/null +++ b/third_party/ulib/musl/src/time/timespec_get.c @@ -0,0 +1,11 @@ +#include + +int __clock_gettime(clockid_t, struct timespec*); + +/* There is no other implemented value than TIME_UTC; all other values + * are considered erroneous. */ +int timespec_get(struct timespec* ts, int base) { + if (base != TIME_UTC) return 0; + int ret = __clock_gettime(CLOCK_REALTIME, ts); + return ret < 0 ? 0 : base; +} diff --git a/third_party/ulib/musl/src/time/utime.c b/third_party/ulib/musl/src/time/utime.c new file mode 100644 index 000000000..ee61e15a3 --- /dev/null +++ b/third_party/ulib/musl/src/time/utime.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int utime(const char* path, const struct utimbuf* times) { + return utimensat( + AT_FDCWD, path, + times ? ((struct timespec[2]){{.tv_sec = times->actime}, {.tv_sec = times->modtime}}) : 0, + 0); +} diff --git a/third_party/ulib/musl/src/time/wcsftime.c b/third_party/ulib/musl/src/time/wcsftime.c new file mode 100644 index 000000000..b2b4f3478 --- /dev/null +++ b/third_party/ulib/musl/src/time/wcsftime.c @@ -0,0 +1,72 @@ +#include "libc.h" +#include "locale_impl.h" +#include +#include +#include + +const char* __strftime_fmt_1(char (*s)[100], size_t* l, int f, const struct tm* tm, locale_t loc); + +size_t __wcsftime_l(wchar_t* restrict s, size_t n, const wchar_t* restrict f, + const struct tm* restrict tm, locale_t loc) { + size_t l, k; + char buf[100]; + wchar_t wbuf[100]; + wchar_t* p; + const char* t_mb; + const wchar_t* t; + int plus; + unsigned long width; + for (l = 0; l < n; f++) { + if (!*f) { + s[l] = 0; + return l; + } + if (*f != '%') { + s[l++] = *f; + continue; + } + f++; + if ((plus = (*f == '+'))) f++; + width = wcstoul(f, &p, 10); + if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { + if (!width && p != f) width = 1; + } else { + width = 0; + } + f = p; + if (*f == 'E' || *f == 'O') f++; + t_mb = __strftime_fmt_1(&buf, &k, *f, tm, loc); + if (!t_mb) break; + k = mbstowcs(wbuf, t_mb, sizeof wbuf / sizeof *wbuf); + if (k == (size_t)-1) return 0; + t = wbuf; + if (width) { + for (; *t == '+' || *t == '-' || (*t == '0' && t[1]); t++, k--) + ; + width--; + if (plus && tm->tm_year >= 10000 - 1900) + s[l++] = '+'; + else if (tm->tm_year < -1900) + s[l++] = '-'; + else + width++; + for (; width > k && l < n; width--) + s[l++] = '0'; + } + if (k >= n - l) k = n - l; + wmemcpy(s + l, t, k); + l += k; + } + if (n) { + if (l == n) l = n - 1; + s[l] = 0; + } + return 0; +} + +size_t wcsftime(wchar_t* restrict wcs, size_t n, const wchar_t* restrict f, + const struct tm* restrict tm) { + return __wcsftime_l(wcs, n, f, tm, CURRENT_LOCALE); +} + +weak_alias(__wcsftime_l, wcsftime_l); diff --git a/third_party/ulib/musl/src/unistd/BUILD.gn b/third_party/ulib/musl/src/unistd/BUILD.gn new file mode 100644 index 000000000..ca3c9040c --- /dev/null +++ b/third_party/ulib/musl/src/unistd/BUILD.gn @@ -0,0 +1,91 @@ +source_set("unistd") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "_exit.c", + "access.c", + "acct.c", + "alarm.c", + "chdir.c", + "chown.c", + "close.c", + "ctermid.c", + "dup.c", + "dup2.c", + "dup3.c", + "faccessat.c", + "fchdir.c", + "fchown.c", + "fchownat.c", + "fdatasync.c", + "fsync.c", + "ftruncate.c", + "getcwd.c", + "getegid.c", + "geteuid.c", + "getgid.c", + "getgroups.c", + "gethostname.c", + "getlogin.c", + "getlogin_r.c", + "getpgid.c", + "getpgrp.c", + "getpid.c", + "getppid.c", + "getsid.c", + "getuid.c", + "isatty.c", + "lchown.c", + "link.c", + "linkat.c", + "nice.c", + "pause.c", + "pipe2.c", + "posix_close.c", + "pread.c", + "preadv.c", + "pwrite.c", + "pwritev.c", + "readlink.c", + "readlinkat.c", + "readv.c", + "renameat.c", + "rmdir.c", + "setegid.c", + "seteuid.c", + "setgid.c", + "setpgid.c", + "setpgrp.c", + "setregid.c", + "setresgid.c", + "setresuid.c", + "setreuid.c", + "setsid.c", + "setuid.c", + "setxid.c", + "sleep.c", + "symlink.c", + "symlinkat.c", + "sync.c", + "tcgetpgrp.c", + "tcsetpgrp.c", + "truncate.c", + "ttyname.c", + "ttyname_r.c", + "ualarm.c", + "unlink.c", + "unlinkat.c", + "usleep.c", + "writev.c", + + # The following are not built until we have mxio and libc standing in + # proper relation to each other. + # + # "lseek.c", + # "pipe.c", + # "read.c", + # "write.c", + ] +} diff --git a/third_party/ulib/musl/src/unistd/_exit.c b/third_party/ulib/musl/src/unistd/_exit.c new file mode 100644 index 000000000..1e7ef70ae --- /dev/null +++ b/third_party/ulib/musl/src/unistd/_exit.c @@ -0,0 +1,6 @@ +#include +#include + +_Noreturn void _exit(int status) { + _Exit(status); +} diff --git a/third_party/ulib/musl/src/unistd/access.c b/third_party/ulib/musl/src/unistd/access.c new file mode 100644 index 000000000..11ce156e5 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/access.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int access(const char* filename, int amode) { +#ifdef SYS_access + return syscall(SYS_access, filename, amode); +#else + return syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/acct.c b/third_party/ulib/musl/src/unistd/acct.c new file mode 100644 index 000000000..b03738e81 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/acct.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include + +int acct(const char* filename) { + return syscall(SYS_acct, filename); +} diff --git a/third_party/ulib/musl/src/unistd/alarm.c b/third_party/ulib/musl/src/unistd/alarm.c new file mode 100644 index 000000000..3906c4aa2 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/alarm.c @@ -0,0 +1,9 @@ +#include "syscall.h" +#include +#include + +unsigned alarm(unsigned seconds) { + struct itimerval it = {.it_value.tv_sec = seconds}; + __syscall(SYS_setitimer, ITIMER_REAL, &it, &it); + return it.it_value.tv_sec + !!it.it_value.tv_usec; +} diff --git a/third_party/ulib/musl/src/unistd/chdir.c b/third_party/ulib/musl/src/unistd/chdir.c new file mode 100644 index 000000000..746459f26 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/chdir.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int chdir(const char* path) { + return syscall(SYS_chdir, path); +} diff --git a/third_party/ulib/musl/src/unistd/chown.c b/third_party/ulib/musl/src/unistd/chown.c new file mode 100644 index 000000000..52021801d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/chown.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int chown(const char* path, uid_t uid, gid_t gid) { +#ifdef SYS_chown + return syscall(SYS_chown, path, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, 0); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/close.c b/third_party/ulib/musl/src/unistd/close.c new file mode 100644 index 000000000..c7cd3228d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/close.c @@ -0,0 +1,20 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +static int io_close(int fd) { + return 0; +} +weak_alias(io_close, __libc_io_close); + +static int dummy(int fd) { + return fd; +} + +weak_alias(dummy, __aio_close); + +int close(int fd) { + fd = __aio_close(fd); + return __libc_io_close(fd); +} diff --git a/third_party/ulib/musl/src/unistd/ctermid.c b/third_party/ulib/musl/src/unistd/ctermid.c new file mode 100644 index 000000000..7fc93c4f2 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/ctermid.c @@ -0,0 +1,6 @@ +#include +#include + +char* ctermid(char* s) { + return s ? strcpy(s, "/dev/tty") : "/dev/tty"; +} diff --git a/third_party/ulib/musl/src/unistd/dup.c b/third_party/ulib/musl/src/unistd/dup.c new file mode 100644 index 000000000..395003394 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/dup.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int dup(int fd) { + return syscall(SYS_dup, fd); +} diff --git a/third_party/ulib/musl/src/unistd/dup2.c b/third_party/ulib/musl/src/unistd/dup2.c new file mode 100644 index 000000000..82fe4327d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/dup2.c @@ -0,0 +1,21 @@ +#include "syscall.h" +#include +#include +#include + +int dup2(int old, int new) { + int r; +#ifdef SYS_dup2 + while ((r = __syscall(SYS_dup2, old, new)) == -EBUSY) + ; +#else + if (old == new) { + r = __syscall(SYS_fcntl, old, F_GETFD); + if (r >= 0) return old; + } else { + while ((r = __syscall(SYS_dup3, old, new, 0)) == -EBUSY) + ; + } +#endif + return __syscall_ret(r); +} diff --git a/third_party/ulib/musl/src/unistd/dup3.c b/third_party/ulib/musl/src/unistd/dup3.c new file mode 100644 index 000000000..61e9cfc4d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/dup3.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include +#include + +int __dup3(int old, int new, int flags) { + int r; +#ifdef SYS_dup2 + if (old == new) return __syscall_ret(-EINVAL); + if (flags & O_CLOEXEC) { + while ((r = __syscall(SYS_dup3, old, new, flags)) == -EBUSY) + ; + if (r != -ENOSYS) return __syscall_ret(r); + } + while ((r = __syscall(SYS_dup2, old, new)) == -EBUSY) + ; + if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC); +#else + while ((r = __syscall(SYS_dup3, old, new, flags)) == -EBUSY) + ; +#endif + return __syscall_ret(r); +} + +weak_alias(__dup3, dup3); diff --git a/third_party/ulib/musl/src/unistd/faccessat.c b/third_party/ulib/musl/src/unistd/faccessat.c new file mode 100644 index 000000000..59adb5561 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/faccessat.c @@ -0,0 +1,56 @@ +#include "pthread_impl.h" +#include "syscall.h" +#include +#include +#include +#include + +struct ctx { + int fd; + const char* filename; + int amode; +}; + +static const int errors[] = {0, -EACCES, -ELOOP, -ENAMETOOLONG, -ENOENT, -ENOTDIR, -EROFS, + -EBADF, -EINVAL, -ETXTBSY, -EFAULT, -EIO, -ENOMEM, -EBUSY}; + +static int checker(void* p) { + struct ctx* c = p; + int ret; + int i; + if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1) || + __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1)) + __syscall(SYS_exit, 1); + ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0); + for (i = 0; i < sizeof errors / sizeof *errors - 1 && ret != errors[i]; i++) + ; + return i; +} + +int faccessat(int fd, const char* filename, int amode, int flag) { + if (!flag || (flag == AT_EACCESS && getuid() == geteuid() && getgid() == getegid())) + return syscall(SYS_faccessat, fd, filename, amode, flag); + + if (flag != AT_EACCESS) return __syscall_ret(-EINVAL); + + char stack[1024]; + sigset_t set; + pid_t pid; + int ret = -EBUSY; + struct ctx c = {.fd = fd, .filename = filename, .amode = amode}; + + __block_all_sigs(&set); + + pid = __clone(checker, stack + sizeof stack, 0, &c); + if (pid > 0) { + int status; + do { + __syscall(SYS_wait4, pid, &status, __WCLONE, 0); + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + if (WIFEXITED(status)) ret = errors[WEXITSTATUS(status)]; + } + + __restore_sigs(&set); + + return __syscall_ret(ret); +} diff --git a/third_party/ulib/musl/src/unistd/fchdir.c b/third_party/ulib/musl/src/unistd/fchdir.c new file mode 100644 index 000000000..255223b3b --- /dev/null +++ b/third_party/ulib/musl/src/unistd/fchdir.c @@ -0,0 +1,15 @@ +#include "syscall.h" +#include +#include +#include + +void __procfdname(char*, unsigned); + +int fchdir(int fd) { + int ret = __syscall(SYS_fchdir, fd); + if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0) return __syscall_ret(ret); + + char buf[15 + 3 * sizeof(int)]; + __procfdname(buf, fd); + return syscall(SYS_chdir, buf); +} diff --git a/third_party/ulib/musl/src/unistd/fchown.c b/third_party/ulib/musl/src/unistd/fchown.c new file mode 100644 index 000000000..ba0fce9af --- /dev/null +++ b/third_party/ulib/musl/src/unistd/fchown.c @@ -0,0 +1,19 @@ +#include "syscall.h" +#include +#include +#include + +void __procfdname(char*, unsigned); + +int fchown(int fd, uid_t uid, gid_t gid) { + int ret = __syscall(SYS_fchown, fd, uid, gid); + if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0) return __syscall_ret(ret); + + char buf[15 + 3 * sizeof(int)]; + __procfdname(buf, fd); +#ifdef SYS_chown + return syscall(SYS_chown, buf, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/fchownat.c b/third_party/ulib/musl/src/unistd/fchownat.c new file mode 100644 index 000000000..783182b81 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/fchownat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag) { + return syscall(SYS_fchownat, fd, path, uid, gid, flag); +} diff --git a/third_party/ulib/musl/src/unistd/fdatasync.c b/third_party/ulib/musl/src/unistd/fdatasync.c new file mode 100644 index 000000000..fa9847f6b --- /dev/null +++ b/third_party/ulib/musl/src/unistd/fdatasync.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int fdatasync(int fd) { + return syscall(SYS_fdatasync, fd); +} diff --git a/third_party/ulib/musl/src/unistd/fsync.c b/third_party/ulib/musl/src/unistd/fsync.c new file mode 100644 index 000000000..2f0fc5ef7 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/fsync.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int fsync(int fd) { + return syscall(SYS_fsync, fd); +} diff --git a/third_party/ulib/musl/src/unistd/ftruncate.c b/third_party/ulib/musl/src/unistd/ftruncate.c new file mode 100644 index 000000000..4625c172f --- /dev/null +++ b/third_party/ulib/musl/src/unistd/ftruncate.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +int ftruncate(int fd, off_t length) { + return syscall(SYS_ftruncate, fd, length); +} + +LFS64(ftruncate); diff --git a/third_party/ulib/musl/src/unistd/getcwd.c b/third_party/ulib/musl/src/unistd/getcwd.c new file mode 100644 index 000000000..ce89913ae --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getcwd.c @@ -0,0 +1,18 @@ +#include "syscall.h" +#include +#include +#include +#include + +char* getcwd(char* buf, size_t size) { + char tmp[PATH_MAX]; + if (!buf) { + buf = tmp; + size = PATH_MAX; + } else if (!size) { + errno = EINVAL; + return 0; + } + if (syscall(SYS_getcwd, buf, size) < 0) return 0; + return buf == tmp ? strdup(buf) : buf; +} diff --git a/third_party/ulib/musl/src/unistd/getegid.c b/third_party/ulib/musl/src/unistd/getegid.c new file mode 100644 index 000000000..79dc1de23 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getegid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +gid_t getegid(void) { + return __syscall(SYS_getegid); +} diff --git a/third_party/ulib/musl/src/unistd/geteuid.c b/third_party/ulib/musl/src/unistd/geteuid.c new file mode 100644 index 000000000..5046426a6 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/geteuid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +uid_t geteuid(void) { + return __syscall(SYS_geteuid); +} diff --git a/third_party/ulib/musl/src/unistd/getgid.c b/third_party/ulib/musl/src/unistd/getgid.c new file mode 100644 index 000000000..e8daf11ff --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getgid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +gid_t getgid(void) { + return __syscall(SYS_getgid); +} diff --git a/third_party/ulib/musl/src/unistd/getgroups.c b/third_party/ulib/musl/src/unistd/getgroups.c new file mode 100644 index 000000000..888777bee --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getgroups.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int getgroups(int count, gid_t list[]) { + return syscall(SYS_getgroups, count, list); +} diff --git a/third_party/ulib/musl/src/unistd/gethostname.c b/third_party/ulib/musl/src/unistd/gethostname.c new file mode 100644 index 000000000..b4eaf43b7 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/gethostname.c @@ -0,0 +1,13 @@ +#include +#include + +int gethostname(char* name, size_t len) { + size_t i; + struct utsname uts; + if (uname(&uts)) return -1; + if (len > sizeof uts.nodename) len = sizeof uts.nodename; + for (i = 0; i < len && (name[i] = uts.nodename[i]); i++) + ; + if (i == len) name[i - 1] = 0; + return 0; +} diff --git a/third_party/ulib/musl/src/unistd/getlogin.c b/third_party/ulib/musl/src/unistd/getlogin.c new file mode 100644 index 000000000..f04feb265 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getlogin.c @@ -0,0 +1,6 @@ +#include +#include + +char* getlogin(void) { + return getenv("LOGNAME"); +} diff --git a/third_party/ulib/musl/src/unistd/getlogin_r.c b/third_party/ulib/musl/src/unistd/getlogin_r.c new file mode 100644 index 000000000..d7a10127a --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getlogin_r.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int getlogin_r(char* name, size_t size) { + char* logname = getlogin(); + if (!logname) return ENXIO; /* or...? */ + if (strlen(logname) >= size) return ERANGE; + strcpy(name, logname); + return 0; +} diff --git a/third_party/ulib/musl/src/unistd/getpgid.c b/third_party/ulib/musl/src/unistd/getpgid.c new file mode 100644 index 000000000..2d550d3da --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getpgid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +pid_t getpgid(pid_t pid) { + return syscall(SYS_getpgid, pid); +} diff --git a/third_party/ulib/musl/src/unistd/getpgrp.c b/third_party/ulib/musl/src/unistd/getpgrp.c new file mode 100644 index 000000000..d19857b58 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getpgrp.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +pid_t getpgrp(void) { + return __syscall(SYS_getpgid, 0); +} diff --git a/third_party/ulib/musl/src/unistd/getpid.c b/third_party/ulib/musl/src/unistd/getpid.c new file mode 100644 index 000000000..9ae97fc3b --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getpid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +pid_t getpid(void) { + return __syscall(SYS_getpid); +} diff --git a/third_party/ulib/musl/src/unistd/getppid.c b/third_party/ulib/musl/src/unistd/getppid.c new file mode 100644 index 000000000..fbce60c0a --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getppid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +pid_t getppid(void) { + return __syscall(SYS_getppid); +} diff --git a/third_party/ulib/musl/src/unistd/getsid.c b/third_party/ulib/musl/src/unistd/getsid.c new file mode 100644 index 000000000..49442691f --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getsid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +pid_t getsid(pid_t pid) { + return syscall(SYS_getsid, pid); +} diff --git a/third_party/ulib/musl/src/unistd/getuid.c b/third_party/ulib/musl/src/unistd/getuid.c new file mode 100644 index 000000000..e713f710b --- /dev/null +++ b/third_party/ulib/musl/src/unistd/getuid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +uid_t getuid(void) { + return __syscall(SYS_getuid); +} diff --git a/third_party/ulib/musl/src/unistd/isatty.c b/third_party/ulib/musl/src/unistd/isatty.c new file mode 100644 index 000000000..4ce5c6478 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/isatty.c @@ -0,0 +1,6 @@ +#include + +int isatty(int fd) { + // TODO(kulakowski) Once we start implementing fds, revisit this. + return 1; +} diff --git a/third_party/ulib/musl/src/unistd/lchown.c b/third_party/ulib/musl/src/unistd/lchown.c new file mode 100644 index 000000000..68c6c2d6a --- /dev/null +++ b/third_party/ulib/musl/src/unistd/lchown.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int lchown(const char* path, uid_t uid, gid_t gid) { +#ifdef SYS_lchown + return syscall(SYS_lchown, path, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/link.c b/third_party/ulib/musl/src/unistd/link.c new file mode 100644 index 000000000..81646f537 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/link.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int link(const char* existing, const char* new) { +#ifdef SYS_link + return syscall(SYS_link, existing, new); +#else + return syscall(SYS_linkat, AT_FDCWD, existing, AT_FDCWD, new, 0); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/linkat.c b/third_party/ulib/musl/src/unistd/linkat.c new file mode 100644 index 000000000..4a97f7fd4 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/linkat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int linkat(int fd1, const char* existing, int fd2, const char* new, int flag) { + return syscall(SYS_linkat, fd1, existing, fd2, new, flag); +} diff --git a/third_party/ulib/musl/src/unistd/lseek.c b/third_party/ulib/musl/src/unistd/lseek.c new file mode 100644 index 000000000..07d874345 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/lseek.c @@ -0,0 +1,14 @@ +#include "libc.h" +#include "syscall.h" +#include + +off_t lseek(int fd, off_t offset, int whence) { +#ifdef SYS__llseek + off_t result; + return syscall(SYS__llseek, fd, offset >> 32, offset, &result, whence) ? -1 : result; +#else + return syscall(SYS_lseek, fd, offset, whence); +#endif +} + +LFS64(lseek); diff --git a/third_party/ulib/musl/src/unistd/nice.c b/third_party/ulib/musl/src/unistd/nice.c new file mode 100644 index 000000000..d40753d27 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/nice.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int nice(int inc) { +#ifdef SYS_nice + return syscall(SYS_nice, inc); +#else + return setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS, 0) + inc); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/pause.c b/third_party/ulib/musl/src/unistd/pause.c new file mode 100644 index 000000000..35f04f631 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/pause.c @@ -0,0 +1,12 @@ +#include "libc.h" +#include "syscall.h" +#include +#include + +int pause(void) { +#ifdef SYS_pause + return syscall(SYS_pause); +#else + return syscall(SYS_ppoll, 0, 0, 0, 0); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/pipe.c b/third_party/ulib/musl/src/unistd/pipe.c new file mode 100644 index 000000000..ce0e9f878 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/pipe.c @@ -0,0 +1,10 @@ +#include "syscall.h" +#include + +int pipe(int fd[2]) { +#ifdef SYS_pipe + return syscall(SYS_pipe, fd); +#else + return syscall(SYS_pipe2, fd, 0); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/pipe2.c b/third_party/ulib/musl/src/unistd/pipe2.c new file mode 100644 index 000000000..26f829e1f --- /dev/null +++ b/third_party/ulib/musl/src/unistd/pipe2.c @@ -0,0 +1,21 @@ +#include "syscall.h" +#include +#include +#include + +int pipe2(int fd[2], int flag) { + if (!flag) return pipe(fd); + int ret = __syscall(SYS_pipe2, fd, flag); + if (ret != -ENOSYS) return __syscall_ret(ret); + ret = pipe(fd); + if (ret) return ret; + if (flag & O_CLOEXEC) { + __syscall(SYS_fcntl, fd[0], F_SETFD, FD_CLOEXEC); + __syscall(SYS_fcntl, fd[1], F_SETFD, FD_CLOEXEC); + } + if (flag & O_NONBLOCK) { + __syscall(SYS_fcntl, fd[0], F_SETFL, O_NONBLOCK); + __syscall(SYS_fcntl, fd[1], F_SETFL, O_NONBLOCK); + } + return 0; +} diff --git a/third_party/ulib/musl/src/unistd/posix_close.c b/third_party/ulib/musl/src/unistd/posix_close.c new file mode 100644 index 000000000..3c373d4ed --- /dev/null +++ b/third_party/ulib/musl/src/unistd/posix_close.c @@ -0,0 +1,5 @@ +#include + +int posix_close(int fd, int flags) { + return close(fd); +} diff --git a/third_party/ulib/musl/src/unistd/pread.c b/third_party/ulib/musl/src/unistd/pread.c new file mode 100644 index 000000000..df6b499d5 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/pread.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t pread(int fd, void* buf, size_t size, off_t ofs) { + return syscall(SYS_pread, fd, buf, size, ofs); +} + +LFS64(pread); diff --git a/third_party/ulib/musl/src/unistd/preadv.c b/third_party/ulib/musl/src/unistd/preadv.c new file mode 100644 index 000000000..f59905a9d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/preadv.c @@ -0,0 +1,11 @@ +#define _BSD_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include + +ssize_t preadv(int fd, const struct iovec* iov, int count, off_t ofs) { + return syscall(SYS_preadv, fd, iov, count, (long)(ofs), (long)(ofs >> 32)); +} + +LFS64(preadv); diff --git a/third_party/ulib/musl/src/unistd/pwrite.c b/third_party/ulib/musl/src/unistd/pwrite.c new file mode 100644 index 000000000..383067f3c --- /dev/null +++ b/third_party/ulib/musl/src/unistd/pwrite.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t pwrite(int fd, const void* buf, size_t size, off_t ofs) { + return syscall(SYS_pwrite, fd, buf, size, ofs); +} + +LFS64(pwrite); diff --git a/third_party/ulib/musl/src/unistd/pwritev.c b/third_party/ulib/musl/src/unistd/pwritev.c new file mode 100644 index 000000000..ef511b4ed --- /dev/null +++ b/third_party/ulib/musl/src/unistd/pwritev.c @@ -0,0 +1,11 @@ +#define _BSD_SOURCE +#include "libc.h" +#include "syscall.h" +#include +#include + +ssize_t pwritev(int fd, const struct iovec* iov, int count, off_t ofs) { + return syscall(SYS_pwritev, fd, iov, count, (long)(ofs), (long)(ofs >> 32)); +} + +LFS64(pwritev); diff --git a/third_party/ulib/musl/src/unistd/read.c b/third_party/ulib/musl/src/unistd/read.c new file mode 100644 index 000000000..bc71f2df9 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/read.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t read(int fd, void* buf, size_t count) { + return syscall(SYS_read, fd, buf, count); +} diff --git a/third_party/ulib/musl/src/unistd/readlink.c b/third_party/ulib/musl/src/unistd/readlink.c new file mode 100644 index 000000000..8a9b6e9e2 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/readlink.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +ssize_t readlink(const char* restrict path, char* restrict buf, size_t bufsize) { +#ifdef SYS_readlink + return syscall(SYS_readlink, path, buf, bufsize); +#else + return syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/readlinkat.c b/third_party/ulib/musl/src/unistd/readlinkat.c new file mode 100644 index 000000000..703853979 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/readlinkat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +ssize_t readlinkat(int fd, const char* restrict path, char* restrict buf, size_t bufsize) { + return syscall(SYS_readlinkat, fd, path, buf, bufsize); +} diff --git a/third_party/ulib/musl/src/unistd/readv.c b/third_party/ulib/musl/src/unistd/readv.c new file mode 100644 index 000000000..a0514425a --- /dev/null +++ b/third_party/ulib/musl/src/unistd/readv.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t readv(int fd, const struct iovec* iov, int count) { + return syscall(SYS_readv, fd, iov, count); +} diff --git a/third_party/ulib/musl/src/unistd/renameat.c b/third_party/ulib/musl/src/unistd/renameat.c new file mode 100644 index 000000000..9349d2f1c --- /dev/null +++ b/third_party/ulib/musl/src/unistd/renameat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int renameat(int oldfd, const char* old, int newfd, const char* new) { + return syscall(SYS_renameat, oldfd, old, newfd, new); +} diff --git a/third_party/ulib/musl/src/unistd/rmdir.c b/third_party/ulib/musl/src/unistd/rmdir.c new file mode 100644 index 000000000..88899691f --- /dev/null +++ b/third_party/ulib/musl/src/unistd/rmdir.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int rmdir(const char* path) { +#ifdef SYS_rmdir + return syscall(SYS_rmdir, path); +#else + return syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/setegid.c b/third_party/ulib/musl/src/unistd/setegid.c new file mode 100644 index 000000000..bd698faa1 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setegid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int setegid(gid_t egid) { + return __setxid(SYS_setresgid, -1, egid, -1); +} diff --git a/third_party/ulib/musl/src/unistd/seteuid.c b/third_party/ulib/musl/src/unistd/seteuid.c new file mode 100644 index 000000000..fe1e08868 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/seteuid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int seteuid(uid_t euid) { + return __setxid(SYS_setresuid, -1, euid, -1); +} diff --git a/third_party/ulib/musl/src/unistd/setgid.c b/third_party/ulib/musl/src/unistd/setgid.c new file mode 100644 index 000000000..30638cc07 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setgid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int setgid(gid_t gid) { + return __setxid(SYS_setgid, gid, 0, 0); +} diff --git a/third_party/ulib/musl/src/unistd/setpgid.c b/third_party/ulib/musl/src/unistd/setpgid.c new file mode 100644 index 000000000..bb527713f --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setpgid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int setpgid(pid_t pid, pid_t pgid) { + return syscall(SYS_setpgid, pid, pgid); +} diff --git a/third_party/ulib/musl/src/unistd/setpgrp.c b/third_party/ulib/musl/src/unistd/setpgrp.c new file mode 100644 index 000000000..a856f419d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setpgrp.c @@ -0,0 +1,5 @@ +#include + +pid_t setpgrp(void) { + return setpgid(0, 0); +} diff --git a/third_party/ulib/musl/src/unistd/setregid.c b/third_party/ulib/musl/src/unistd/setregid.c new file mode 100644 index 000000000..f652612cc --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setregid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int setregid(gid_t rgid, gid_t egid) { + return __setxid(SYS_setregid, rgid, egid, 0); +} diff --git a/third_party/ulib/musl/src/unistd/setresgid.c b/third_party/ulib/musl/src/unistd/setresgid.c new file mode 100644 index 000000000..43d5e0c69 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setresgid.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include + +int setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + return __setxid(SYS_setresgid, rgid, egid, sgid); +} diff --git a/third_party/ulib/musl/src/unistd/setresuid.c b/third_party/ulib/musl/src/unistd/setresuid.c new file mode 100644 index 000000000..fbb57fc6c --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setresuid.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include "libc.h" +#include "syscall.h" +#include + +int setresuid(uid_t ruid, uid_t euid, uid_t suid) { + return __setxid(SYS_setresuid, ruid, euid, suid); +} diff --git a/third_party/ulib/musl/src/unistd/setreuid.c b/third_party/ulib/musl/src/unistd/setreuid.c new file mode 100644 index 000000000..6724a1d7b --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setreuid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int setreuid(uid_t ruid, uid_t euid) { + return __setxid(SYS_setreuid, ruid, euid, 0); +} diff --git a/third_party/ulib/musl/src/unistd/setsid.c b/third_party/ulib/musl/src/unistd/setsid.c new file mode 100644 index 000000000..f0ffe2f6a --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setsid.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +pid_t setsid(void) { + return syscall(SYS_setsid); +} diff --git a/third_party/ulib/musl/src/unistd/setuid.c b/third_party/ulib/musl/src/unistd/setuid.c new file mode 100644 index 000000000..2de8c7661 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setuid.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +int setuid(uid_t uid) { + return __setxid(SYS_setuid, uid, 0, 0); +} diff --git a/third_party/ulib/musl/src/unistd/setxid.c b/third_party/ulib/musl/src/unistd/setxid.c new file mode 100644 index 000000000..6644b3690 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/setxid.c @@ -0,0 +1,6 @@ +#include "libc.h" + +int __setxid(int nr, int id, int eid, int sid) { + // TODO(kulakowski) Implement fake ids. + return -1; +} diff --git a/third_party/ulib/musl/src/unistd/sleep.c b/third_party/ulib/musl/src/unistd/sleep.c new file mode 100644 index 000000000..7eae7a119 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/sleep.c @@ -0,0 +1,8 @@ +#include +#include + +unsigned sleep(unsigned seconds) { + struct timespec tv = {.tv_sec = seconds, .tv_nsec = 0}; + if (nanosleep(&tv, &tv)) return tv.tv_sec; + return 0; +} diff --git a/third_party/ulib/musl/src/unistd/symlink.c b/third_party/ulib/musl/src/unistd/symlink.c new file mode 100644 index 000000000..100fca30a --- /dev/null +++ b/third_party/ulib/musl/src/unistd/symlink.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int symlink(const char* existing, const char* new) { +#ifdef SYS_symlink + return syscall(SYS_symlink, existing, new); +#else + return syscall(SYS_symlinkat, existing, AT_FDCWD, new); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/symlinkat.c b/third_party/ulib/musl/src/unistd/symlinkat.c new file mode 100644 index 000000000..270cd8a02 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/symlinkat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int symlinkat(const char* existing, int fd, const char* new) { + return syscall(SYS_symlinkat, existing, fd, new); +} diff --git a/third_party/ulib/musl/src/unistd/sync.c b/third_party/ulib/musl/src/unistd/sync.c new file mode 100644 index 000000000..04c81f013 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/sync.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +void sync(void) { + __syscall(SYS_sync); +} diff --git a/third_party/ulib/musl/src/unistd/tcgetpgrp.c b/third_party/ulib/musl/src/unistd/tcgetpgrp.c new file mode 100644 index 000000000..87ce62108 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/tcgetpgrp.c @@ -0,0 +1,9 @@ +#include +#include +#include + +pid_t tcgetpgrp(int fd) { + int pgrp; + if (ioctl(fd, TIOCGPGRP, &pgrp) < 0) return -1; + return pgrp; +} diff --git a/third_party/ulib/musl/src/unistd/tcsetpgrp.c b/third_party/ulib/musl/src/unistd/tcsetpgrp.c new file mode 100644 index 000000000..a80d2d55d --- /dev/null +++ b/third_party/ulib/musl/src/unistd/tcsetpgrp.c @@ -0,0 +1,8 @@ +#include +#include +#include + +int tcsetpgrp(int fd, pid_t pgrp) { + int pgrp_int = pgrp; + return ioctl(fd, TIOCSPGRP, &pgrp_int); +} diff --git a/third_party/ulib/musl/src/unistd/truncate.c b/third_party/ulib/musl/src/unistd/truncate.c new file mode 100644 index 000000000..340b64b23 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/truncate.c @@ -0,0 +1,9 @@ +#include "libc.h" +#include "syscall.h" +#include + +int truncate(const char* path, off_t length) { + return syscall(SYS_truncate, path, length); +} + +LFS64(truncate); diff --git a/third_party/ulib/musl/src/unistd/ttyname.c b/third_party/ulib/musl/src/unistd/ttyname.c new file mode 100644 index 000000000..26ba51efb --- /dev/null +++ b/third_party/ulib/musl/src/unistd/ttyname.c @@ -0,0 +1,13 @@ +#include +#include +#include + +char* ttyname(int fd) { + static char buf[TTY_NAME_MAX]; + int result; + if ((result = ttyname_r(fd, buf, sizeof buf))) { + errno = result; + return NULL; + } + return buf; +} diff --git a/third_party/ulib/musl/src/unistd/ttyname_r.c b/third_party/ulib/musl/src/unistd/ttyname_r.c new file mode 100644 index 000000000..07eba421e --- /dev/null +++ b/third_party/ulib/musl/src/unistd/ttyname_r.c @@ -0,0 +1,23 @@ +#include +#include + +void __procfdname(char*, unsigned); + +int ttyname_r(int fd, char* name, size_t size) { + char procname[sizeof "/proc/self/fd/" + 3 * sizeof(int) + 2]; + ssize_t l; + + if (!isatty(fd)) return ENOTTY; + + __procfdname(procname, fd); + l = readlink(procname, name, size); + + if (l < 0) + return errno; + else if (l == size) + return ERANGE; + else { + name[l] = 0; + return 0; + } +} diff --git a/third_party/ulib/musl/src/unistd/ualarm.c b/third_party/ulib/musl/src/unistd/ualarm.c new file mode 100644 index 000000000..b56e56023 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/ualarm.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include +#include + +unsigned ualarm(unsigned value, unsigned interval) { + struct itimerval it = {.it_interval.tv_usec = interval, .it_value.tv_usec = value}; + setitimer(ITIMER_REAL, &it, &it); + return it.it_value.tv_sec * 1000000 + it.it_value.tv_usec; +} diff --git a/third_party/ulib/musl/src/unistd/unlink.c b/third_party/ulib/musl/src/unistd/unlink.c new file mode 100644 index 000000000..0f929fb6c --- /dev/null +++ b/third_party/ulib/musl/src/unistd/unlink.c @@ -0,0 +1,11 @@ +#include "syscall.h" +#include +#include + +int unlink(const char* path) { +#ifdef SYS_unlink + return syscall(SYS_unlink, path); +#else + return syscall(SYS_unlinkat, AT_FDCWD, path, 0); +#endif +} diff --git a/third_party/ulib/musl/src/unistd/unlinkat.c b/third_party/ulib/musl/src/unistd/unlinkat.c new file mode 100644 index 000000000..406e5bfb6 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/unlinkat.c @@ -0,0 +1,6 @@ +#include "syscall.h" +#include + +int unlinkat(int fd, const char* path, int flag) { + return syscall(SYS_unlinkat, fd, path, flag); +} diff --git a/third_party/ulib/musl/src/unistd/usleep.c b/third_party/ulib/musl/src/unistd/usleep.c new file mode 100644 index 000000000..3f4064d42 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/usleep.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include +#include + +int usleep(unsigned useconds) { + struct timespec tv = {.tv_sec = useconds / 1000000, .tv_nsec = (useconds % 1000000) * 1000}; + return nanosleep(&tv, &tv); +} diff --git a/third_party/ulib/musl/src/unistd/write.c b/third_party/ulib/musl/src/unistd/write.c new file mode 100644 index 000000000..446cb2660 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/write.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t write(int fd, const void* buf, size_t count) { + return syscall(SYS_write, fd, buf, count); +} diff --git a/third_party/ulib/musl/src/unistd/writev.c b/third_party/ulib/musl/src/unistd/writev.c new file mode 100644 index 000000000..a89849ba2 --- /dev/null +++ b/third_party/ulib/musl/src/unistd/writev.c @@ -0,0 +1,7 @@ +#include "libc.h" +#include "syscall.h" +#include + +ssize_t writev(int fd, const struct iovec* iov, int count) { + return syscall(SYS_writev, fd, iov, count); +} diff --git a/third_party/ulib/musl/third_party/arch/BUILD.gn b/third_party/ulib/musl/third_party/arch/BUILD.gn new file mode 100644 index 000000000..cfb340953 --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/BUILD.gn @@ -0,0 +1,13 @@ +source_set("arch") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [] + if (target_cpu == "x64") { + sources += [ + "x86_64/longjmp.s", + "x86_64/setjmp.s", + ] + } +} diff --git a/third_party/ulib/musl/third_party/arch/x32/__unmapself.s b/third_party/ulib/musl/third_party/arch/x32/__unmapself.s new file mode 100644 index 000000000..d9254601f --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/x32/__unmapself.s @@ -0,0 +1,10 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.text +.global __unmapself +.type __unmapself,@function +__unmapself: + movl $0x4000000b,%eax /* SYS_munmap */ + syscall /* munmap(arg2,arg3) */ + xor %rdi,%rdi /* exit() args: always return success */ + movl $0x4000003c,%eax /* SYS_exit */ + syscall /* exit(0) */ diff --git a/third_party/ulib/musl/third_party/arch/x32/longjmp.s b/third_party/ulib/musl/third_party/arch/x32/longjmp.s new file mode 100644 index 000000000..e175a4b96 --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/x32/longjmp.s @@ -0,0 +1,22 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.global _longjmp +.global longjmp +.type _longjmp,@function +.type longjmp,@function +_longjmp: +longjmp: + mov %rsi,%rax /* val will be longjmp return */ + test %rax,%rax + jnz 1f + inc %rax /* if val==0, val=1 per longjmp semantics */ +1: + mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */ + mov 8(%rdi),%rbp + mov 16(%rdi),%r12 + mov 24(%rdi),%r13 + mov 32(%rdi),%r14 + mov 40(%rdi),%r15 + mov 48(%rdi),%rdx /* this ends up being the stack pointer */ + mov %rdx,%rsp + mov 56(%rdi),%rdx /* this is the instruction pointer */ + jmp *%rdx /* goto saved address without altering rsp */ diff --git a/third_party/ulib/musl/third_party/arch/x32/setjmp.s b/third_party/ulib/musl/third_party/arch/x32/setjmp.s new file mode 100644 index 000000000..98f58b8d6 --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/x32/setjmp.s @@ -0,0 +1,22 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,@function +.type _setjmp,@function +.type setjmp,@function +__setjmp: +_setjmp: +setjmp: + mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */ + mov %rbp,8(%rdi) + mov %r12,16(%rdi) + mov %r13,24(%rdi) + mov %r14,32(%rdi) + mov %r15,40(%rdi) + lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */ + mov %rdx,48(%rdi) + mov (%rsp),%rdx /* save return addr ptr for new rip */ + mov %rdx,56(%rdi) + xor %rax,%rax /* always return 0 */ + ret diff --git a/third_party/ulib/musl/third_party/arch/x86_64/__unmapself.s b/third_party/ulib/musl/third_party/arch/x86_64/__unmapself.s new file mode 100644 index 000000000..e2689e650 --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/x86_64/__unmapself.s @@ -0,0 +1,10 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.text +.global __unmapself +.type __unmapself,@function +__unmapself: + movl $11,%eax /* SYS_munmap */ + syscall /* munmap(arg2,arg3) */ + xor %rdi,%rdi /* exit() args: always return success */ + movl $60,%eax /* SYS_exit */ + syscall /* exit(0) */ diff --git a/third_party/ulib/musl/third_party/arch/x86_64/longjmp.s b/third_party/ulib/musl/third_party/arch/x86_64/longjmp.s new file mode 100644 index 000000000..e175a4b96 --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/x86_64/longjmp.s @@ -0,0 +1,22 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.global _longjmp +.global longjmp +.type _longjmp,@function +.type longjmp,@function +_longjmp: +longjmp: + mov %rsi,%rax /* val will be longjmp return */ + test %rax,%rax + jnz 1f + inc %rax /* if val==0, val=1 per longjmp semantics */ +1: + mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */ + mov 8(%rdi),%rbp + mov 16(%rdi),%r12 + mov 24(%rdi),%r13 + mov 32(%rdi),%r14 + mov 40(%rdi),%r15 + mov 48(%rdi),%rdx /* this ends up being the stack pointer */ + mov %rdx,%rsp + mov 56(%rdi),%rdx /* this is the instruction pointer */ + jmp *%rdx /* goto saved address without altering rsp */ diff --git a/third_party/ulib/musl/third_party/arch/x86_64/setjmp.s b/third_party/ulib/musl/third_party/arch/x86_64/setjmp.s new file mode 100644 index 000000000..98f58b8d6 --- /dev/null +++ b/third_party/ulib/musl/third_party/arch/x86_64/setjmp.s @@ -0,0 +1,22 @@ +/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */ +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,@function +.type _setjmp,@function +.type setjmp,@function +__setjmp: +_setjmp: +setjmp: + mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */ + mov %rbp,8(%rdi) + mov %r12,16(%rdi) + mov %r13,24(%rdi) + mov %r14,32(%rdi) + mov %r15,40(%rdi) + lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */ + mov %rdx,48(%rdi) + mov (%rsp),%rdx /* save return addr ptr for new rip */ + mov %rdx,56(%rdi) + xor %rax,%rax /* always return 0 */ + ret diff --git a/third_party/ulib/musl/third_party/complex/BUILD.gn b/third_party/ulib/musl/third_party/complex/BUILD.gn new file mode 100644 index 000000000..b264251ba --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/BUILD.gn @@ -0,0 +1,23 @@ +source_set("complex") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__cexp.c", + "__cexpf.c", + "catan.c", + "catanf.c", + "catanl.c", + "ccosh.c", + "ccoshf.c", + "cexp.c", + "cexpf.c", + "csinh.c", + "csinhf.c", + "csqrt.c", + "csqrtf.c", + "ctanh.c", + "ctanhf.c", + ] +} diff --git a/third_party/ulib/musl/third_party/complex/__cexp.c b/third_party/ulib/musl/third_party/complex/__cexp.c new file mode 100644 index 000000000..f809d9423 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/__cexp.c @@ -0,0 +1,85 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_exp.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t k = 1799; /* constant for reduction */ +static const double kln2 = 1246.97177782734161156; /* k * ln2 */ + +/* + * Compute exp(x), scaled to avoid spurious overflow. An exponent is + * returned separately in 'expt'. + * + * Input: ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91 + * Output: 2**1023 <= y < 2**1024 + */ +static double __frexp_exp(double x, int* expt) { + double exp_x; + uint32_t hx; + + /* + * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to + * minimize |exp(kln2) - 2**k|. We also scale the exponent of + * exp_x to MAX_EXP so that the result can be multiplied by + * a tiny number without losing accuracy due to denormalization. + */ + exp_x = exp(x - kln2); + GET_HIGH_WORD(hx, exp_x); + *expt = (hx >> 20) - (0x3ff + 1023) + k; + SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20)); + return exp_x; +} + +/* + * __ldexp_cexp(x, expt) compute exp(x) * 2**expt. + * It is intended for large arguments (real part >= ln(DBL_MAX)) + * where care is needed to avoid overflow. + * + * The present implementation is narrowly tailored for our hyperbolic and + * exponential functions. We assume expt is small (0 or -1), and the caller + * has filtered out very large x, for which overflow would be inevitable. + */ +double complex __ldexp_cexp(double complex z, int expt) { + double x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = creal(z); + y = cimag(z); + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + + /* + * Arrange so that scale1 * scale2 == 2**expt. We use this to + * compensate for scalbn being horrendously slow. + */ + half_expt = expt / 2; + INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0); + half_expt = expt - half_expt; + INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0); + + return CMPLX(cos(y) * exp_x * scale1 * scale2, sin(y) * exp_x * scale1 * scale2); +} diff --git a/third_party/ulib/musl/third_party/complex/__cexpf.c b/third_party/ulib/musl/third_party/complex/__cexpf.c new file mode 100644 index 000000000..dc3818bd4 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/__cexpf.c @@ -0,0 +1,65 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_expf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t k = 235; /* constant for reduction */ +static const float kln2 = 162.88958740F; /* k * ln2 */ + +/* + * See __cexp.c for details. + * + * Input: ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7 + * Output: 2**127 <= y < 2**128 + */ +static float __frexp_expf(float x, int* expt) { + float exp_x; + uint32_t hx; + + exp_x = expf(x - kln2); + GET_FLOAT_WORD(hx, exp_x); + *expt = (hx >> 23) - (0x7f + 127) + k; + SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23)); + return exp_x; +} + +float complex __ldexp_cexpf(float complex z, int expt) { + float x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = crealf(z); + y = cimagf(z); + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + + half_expt = expt / 2; + SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23); + half_expt = expt - half_expt; + SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23); + + return CMPLXF(cosf(y) * exp_x * scale1 * scale2, sinf(y) * exp_x * scale1 * scale2); +} diff --git a/third_party/ulib/musl/third_party/complex/catan.c b/third_party/ulib/musl/third_party/complex/catan.c new file mode 100644 index 000000000..ae5a46491 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/catan.c @@ -0,0 +1,114 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catan.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * double complex catan(); + * double complex z, w; + * + * w = catan (z); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * catan(z) = -i catanh(iz). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include "libm.h" + +#define MAXNUM 1.0e308 + +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; + +static double _redupi(double x) { + double t; + long i; + + t = x / M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +double complex catan(double complex z) { + double complex w; + double a, t, x, x2, y; + + x = creal(z); + y = cimag(z); + + if (x == 0.0 && y > 1.0) goto ovrf; + + x2 = x * x; + a = 1.0 - x2 - (y * y); + if (a == 0.0) goto ovrf; + + t = 0.5 * atan2(2.0 * x, a); + w = _redupi(t); + + t = y - 1.0; + a = x2 + (t * t); + if (a == 0.0) goto ovrf; + + t = y + 1.0; + a = (x2 + t * t) / a; + w = w + (0.25 * log(a)) * I; + return w; + +ovrf: + // FIXME + w = MAXNUM + MAXNUM * I; + return w; +} diff --git a/third_party/ulib/musl/third_party/complex/catanf.c b/third_party/ulib/musl/third_party/complex/catanf.c new file mode 100644 index 000000000..3fcdb880a --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/catanf.c @@ -0,0 +1,110 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catanf.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * float complex catanf(); + * float complex z, w; + * + * w = catanf( z ); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-6 5.2e-8 + */ + +#include "libm.h" + +#define MAXNUMF 1.0e38F + +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; + +static float _redupif(float xx) { + float x, t; + long i; + + x = xx; + t = x / (float)M_PI; + if (t >= 0.0f) + t += 0.5f; + else + t -= 0.5f; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +float complex catanf(float complex z) { + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + if ((x == 0.0f) && (y > 1.0f)) goto ovrf; + + x2 = x * x; + a = 1.0f - x2 - (y * y); + if (a == 0.0f) goto ovrf; + + t = 0.5f * atan2f(2.0f * x, a); + w = _redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + if (a == 0.0f) goto ovrf; + + t = y + 1.0f; + a = (x2 + (t * t)) / a; + w = w + (0.25f * logf(a)) * I; + return w; + +ovrf: + // FIXME + w = MAXNUMF + MAXNUMF * I; + return w; +} diff --git a/third_party/ulib/musl/third_party/complex/catanl.c b/third_party/ulib/musl/third_party/complex/catanl.c new file mode 100644 index 000000000..1f59f6ec0 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/catanl.c @@ -0,0 +1,120 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catanl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * long double complex catanl(); + * long double complex z, w; + * + * w = catanl( z ); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include "libm.h" +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex catanl(long double complex z) { + return catan(z); +} +#else +static const long double PIL = 3.141592653589793238462643383279502884197169L; +static const long double DP1 = 3.14159265358979323829596852490908531763125L; +static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L; +static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L; + +static long double redupil(long double x) { + long double t; + long i; + + t = x / PIL; + if (t >= 0.0L) + t += 0.5L; + else + t -= 0.5L; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +long double complex catanl(long double complex z) { + long double complex w; + long double a, t, x, x2, y; + + x = creall(z); + y = cimagl(z); + + if ((x == 0.0L) && (y > 1.0L)) goto ovrf; + + x2 = x * x; + a = 1.0L - x2 - (y * y); + if (a == 0.0L) goto ovrf; + + t = atan2l(2.0L * x, a) * 0.5L; + w = redupil(t); + + t = y - 1.0L; + a = x2 + (t * t); + if (a == 0.0L) goto ovrf; + + t = y + 1.0L; + a = (x2 + (t * t)) / a; + w = w + (0.25L * logl(a)) * I; + return w; + +ovrf: + // FIXME + w = LDBL_MAX + LDBL_MAX * I; + return w; +} +#endif diff --git a/third_party/ulib/musl/third_party/complex/ccosh.c b/third_party/ulib/musl/third_party/complex/ccosh.c new file mode 100644 index 000000000..6d94acdaf --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/ccosh.c @@ -0,0 +1,134 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ccosh.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic cosine of a complex argument z = x + i y. + * + * cosh(z) = cosh(x+iy) + * = cosh(x) cos(y) + i sinh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "libm.h" + +static const double huge = 0x1p1023; + +double complex ccosh(double complex z) { + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) return CMPLX(cosh(x), x * y); + if (ix < 0x40360000) /* small x: normal case */ + return CMPLX(cosh(x) * cos(y), sinh(x) * sin(y)); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return CMPLX(h * cos(y), copysign(h, x) * sin(y)); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return CMPLX(creal(z), cimag(z) * copysign(1, x)); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return CMPLX(h * h * cos(y), h * sin(y)); + } + } + + /* + * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) return CMPLX(y - y, copysign(0, x * (y - y))); + + /* + * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0. + * + * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0. + * The sign of 0 in the result is unspecified. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) return CMPLX(x * x, copysign(0, x) * y); + return CMPLX(x * x, copysign(0, (x + x) * y)); + } + + /* + * cosh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * cosh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) return CMPLX(y - y, x * (y - y)); + + /* + * cosh(+-Inf + I NaN) = +Inf + I d(NaN). + * + * cosh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) return CMPLX(x * x, x * (y - y)); + return CMPLX((x * x) * cos(y), x * sin(y)); + } + + /* + * cosh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * cosh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * cosh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return CMPLX((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/third_party/ulib/musl/third_party/complex/ccoshf.c b/third_party/ulib/musl/third_party/complex/ccoshf.c new file mode 100644 index 000000000..4683ff2ec --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/ccoshf.c @@ -0,0 +1,84 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ccoshf.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic cosine of a complex argument. See s_ccosh.c for details. + */ + +#include "libm.h" + +static const float huge = 0x1p127; + +float complex ccoshf(float complex z) { + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) return CMPLXF(coshf(x), x * y); + if (ix < 0x41100000) /* small x: normal case */ + return CMPLXF(coshf(x) * cosf(y), sinhf(x) * sinf(y)); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return CMPLXF(h * cosf(y), copysignf(h, x) * sinf(y)); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return CMPLXF(crealf(z), cimagf(z) * copysignf(1, x)); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return CMPLXF(h * h * cosf(y), h * sinf(y)); + } + } + + if (ix == 0 && iy >= 0x7f800000) return CMPLXF(y - y, copysignf(0, x * (y - y))); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) return CMPLXF(x * x, copysignf(0, x) * y); + return CMPLXF(x * x, copysignf(0, (x + x) * y)); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) return CMPLXF(y - y, x * (y - y)); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) return CMPLXF(x * x, x * (y - y)); + return CMPLXF((x * x) * cosf(y), x * sinf(y)); + } + + return CMPLXF((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/third_party/ulib/musl/third_party/complex/cexp.c b/third_party/ulib/musl/third_party/complex/cexp.c new file mode 100644 index 000000000..ec112d8f0 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/cexp.c @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexp.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t exp_ovfl = 0x40862e42, /* high bits of MAX_EXP * ln2 ~= 710 */ + cexp_ovfl = 0x4096b8e4; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +double complex cexp(double complex z) { + double x, y, exp_x; + uint32_t hx, hy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hy, ly, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if ((hy | ly) == 0) return CMPLX(exp(x), y); + EXTRACT_WORDS(hx, lx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if (((hx & 0x7fffffff) | lx) == 0) return CMPLX(cos(y), sin(y)); + + if (hy >= 0x7ff00000) { + if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLX(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLX(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLX(x, y - y); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 709.7 and 1454.3, so we must scale to avoid + * overflow in exp(x). + */ + return __ldexp_cexp(z, 0); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = exp(x); + return CMPLX(exp_x * cos(y), exp_x * sin(y)); + } +} diff --git a/third_party/ulib/musl/third_party/complex/cexpf.c b/third_party/ulib/musl/third_party/complex/cexpf.c new file mode 100644 index 000000000..7866e3fdc --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/cexpf.c @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexpf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +static const uint32_t exp_ovfl = 0x42b17218, /* MAX_EXP * ln2 ~= 88.722839355 */ + cexp_ovfl = 0x43400074; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +float complex cexpf(float complex z) { + float x, y, exp_x; + uint32_t hx, hy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hy, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if (hy == 0) return CMPLXF(expf(x), y); + GET_FLOAT_WORD(hx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if ((hx & 0x7fffffff) == 0) return CMPLXF(cosf(y), sinf(y)); + + if (hy >= 0x7f800000) { + if ((hx & 0x7fffffff) != 0x7f800000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLXF(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLXF(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLXF(x, y - y); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 88.7 and 192, so we must scale to avoid + * overflow in expf(x). + */ + return __ldexp_cexpf(z, 0); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = expf(x); + return CMPLXF(exp_x * cosf(y), exp_x * sinf(y)); + } +} diff --git a/third_party/ulib/musl/third_party/complex/csinh.c b/third_party/ulib/musl/third_party/complex/csinh.c new file mode 100644 index 000000000..86354e65a --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/csinh.c @@ -0,0 +1,135 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csinh.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic sine of a complex argument z = x + i y. + * + * sinh(z) = sinh(x+iy) + * = sinh(x) cos(y) + i cosh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "libm.h" + +static const double huge = 0x1p1023; + +double complex csinh(double complex z) { + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) return CMPLX(sinh(x), y); + if (ix < 0x40360000) /* small x: normal case */ + return CMPLX(sinh(x) * cos(y), cosh(x) * sin(y)); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return CMPLX(copysign(h, x) * cos(y), h * sin(y)); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return CMPLX(creal(z) * copysign(1, x), cimag(z)); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return CMPLX(h * cos(y), h * h * sin(y)); + } + } + + /* + * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN). + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) return CMPLX(copysign(0, x * (y - y)), y - y); + + /* + * sinh(+-Inf +- I 0) = +-Inf + I +-0. + * + * sinh(NaN +- I 0) = d(NaN) + I +-0. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) return CMPLX(x, y); + return CMPLX(x, copysign(0, y)); + } + + /* + * sinh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * sinh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) return CMPLX(y - y, x * (y - y)); + + /* + * sinh(+-Inf + I NaN) = +-Inf + I d(NaN). + * The sign of Inf in the result is unspecified. Choice = normally + * the same as d(NaN). + * + * sinh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) return CMPLX(x * x, x * (y - y)); + return CMPLX(x * cos(y), INFINITY * sin(y)); + } + + /* + * sinh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * sinh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * sinh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return CMPLX((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/third_party/ulib/musl/third_party/complex/csinhf.c b/third_party/ulib/musl/third_party/complex/csinhf.c new file mode 100644 index 000000000..87f4b0884 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/csinhf.c @@ -0,0 +1,84 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csinhf.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic sine of a complex argument z. See s_csinh.c for details. + */ + +#include "libm.h" + +static const float huge = 0x1p127; + +float complex csinhf(float complex z) { + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) return CMPLXF(sinhf(x), y); + if (ix < 0x41100000) /* small x: normal case */ + return CMPLXF(sinhf(x) * cosf(y), coshf(x) * sinf(y)); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return CMPLXF(copysignf(h, x) * cosf(y), h * sinf(y)); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return CMPLXF(crealf(z) * copysignf(1, x), cimagf(z)); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return CMPLXF(h * cosf(y), h * h * sinf(y)); + } + } + + if (ix == 0 && iy >= 0x7f800000) return CMPLXF(copysignf(0, x * (y - y)), y - y); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) return CMPLXF(x, y); + return CMPLXF(x, copysignf(0, y)); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) return CMPLXF(y - y, x * (y - y)); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) return CMPLXF(x * x, x * (y - y)); + return CMPLXF(x * cosf(y), INFINITY * sinf(y)); + } + + return CMPLXF((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/third_party/ulib/musl/third_party/complex/csqrt.c b/third_party/ulib/musl/third_party/complex/csqrt.c new file mode 100644 index 000000000..29b48ef8d --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/csqrt.c @@ -0,0 +1,96 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrt.c */ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +PRAGMA_STDC_CX_LIMITED_RANGE_ON + +/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */ +#define THRESH 0x1.a827999fcef32p+1022 + +double complex csqrt(double complex z) { + double complex result; + double a, b; + double t; + int scale; + + a = creal(z); + b = cimag(z); + + /* Handle special cases. */ + if (z == 0) return CMPLX(0, b); + if (isinf(b)) return CMPLX(INFINITY, b); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return CMPLX(a, t); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return CMPLX(fabs(b - b), copysign(a, b)); + else + return CMPLX(a, copysign(b - b, b)); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabs(a) >= THRESH || fabs(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + result = CMPLX(t, b / (2 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + result = CMPLX(fabs(b) / (2 * t), copysign(t, b)); + } + + /* Rescale. */ + if (scale) result *= 2; + return result; +} diff --git a/third_party/ulib/musl/third_party/complex/csqrtf.c b/third_party/ulib/musl/third_party/complex/csqrtf.c new file mode 100644 index 000000000..2008d8611 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/csqrtf.c @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrtf.c */ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +PRAGMA_STDC_CX_LIMITED_RANGE_ON + +float complex csqrtf(float complex z) { + float a = crealf(z), b = cimagf(z); + double t; + + /* Handle special cases. */ + if (z == 0) return CMPLXF(0, b); + if (isinf(b)) return CMPLXF(INFINITY, b); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return CMPLXF(a, t); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrtf(inf + NaN i) = inf + NaN i + * csqrtf(inf + y i) = inf + 0 i + * csqrtf(-inf + NaN i) = NaN +- inf i + * csqrtf(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return CMPLXF(fabsf(b - b), copysignf(a, b)); + else + return CMPLXF(a, copysignf(b - b, b)); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* + * We compute t in double precision to avoid overflow and to + * provide correct rounding in nearly all cases. + * This is Algorithm 312, CACM vol 10, Oct 1967. + */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + return CMPLXF(t, b / (2.0 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + return CMPLXF(fabsf(b) / (2.0 * t), copysignf(t, b)); + } +} diff --git a/third_party/ulib/musl/third_party/complex/ctanh.c b/third_party/ulib/musl/third_party/complex/ctanh.c new file mode 100644 index 000000000..7c93bbf69 --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/ctanh.c @@ -0,0 +1,127 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic tangent of a complex argument z = x + i y. + * + * The algorithm is from: + * + * W. Kahan. Branch Cuts for Complex Elementary Functions or Much + * Ado About Nothing's Sign Bit. In The State of the Art in + * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987. + * + * Method: + * + * Let t = tan(x) + * beta = 1/cos^2(y) + * s = sinh(x) + * rho = cosh(x) + * + * We have: + * + * tanh(z) = sinh(z) / cosh(z) + * + * sinh(x) cos(y) + i cosh(x) sin(y) + * = --------------------------------- + * cosh(x) cos(y) + i sinh(x) sin(y) + * + * cosh(x) sinh(x) / cos^2(y) + i tan(y) + * = ------------------------------------- + * 1 + sinh^2(x) / cos^2(y) + * + * beta rho s + i t + * = ---------------- + * 1 + beta s^2 + * + * Modifications: + * + * I omitted the original algorithm's handling of overflow in tan(x) after + * verifying with nearpi.c that this can't happen in IEEE single or double + * precision. I also handle large x differently. + */ + +#include "libm.h" + +double complex ctanh(double complex z) { + double x, y; + double t, beta, s, rho, denom; + uint32_t hx, ix, lx; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; + + /* + * ctanh(NaN + i 0) = NaN + i 0 + * + * ctanh(NaN + i y) = NaN + i NaN for y != 0 + * + * The imaginary part has the sign of x*sin(2*y), but there's no + * special effort to get this right. + * + * ctanh(+-Inf +- i Inf) = +-1 +- 0 + * + * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite + * + * The imaginary part of the sign is unspecified. This special + * case is only needed to avoid a spurious invalid exception when + * y is infinite. + */ + if (ix >= 0x7ff00000) { + if ((ix & 0xfffff) | lx) /* x is NaN */ + return CMPLX(x, (y == 0 ? y : x * y)); + SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ + return CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))); + } + + /* + * ctanh(+-0 + i NAN) = +-0 + i NaN + * ctanh(+-0 +- i Inf) = +-0 + i NaN + * ctanh(x + i NAN) = NaN + i NaN + * ctanh(x +- i Inf) = NaN + i NaN + */ + if (!isfinite(y)) return CMPLX(x ? y - y : x, y - y); + + /* + * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the + * approximation sinh^2(huge) ~= exp(2*huge) / 4. + * We use a modified formula to avoid spurious overflow. + */ + if (ix >= 0x40360000) { /* x >= 22 */ + double exp_mx = exp(-fabs(x)); + return CMPLX(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_mx); + } + + /* Kahan's algorithm */ + t = tan(y); + beta = 1.0 + t * t; /* = 1 / cos^2(y) */ + s = sinh(x); + rho = sqrt(1 + s * s); /* = cosh(x) */ + denom = 1 + beta * s * s; + return CMPLX((beta * rho * s) / denom, t / denom); +} diff --git a/third_party/ulib/musl/third_party/complex/ctanhf.c b/third_party/ulib/musl/third_party/complex/ctanhf.c new file mode 100644 index 000000000..2bda92c7f --- /dev/null +++ b/third_party/ulib/musl/third_party/complex/ctanhf.c @@ -0,0 +1,63 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanhf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic tangent of a complex argument z. See s_ctanh.c for details. + */ + +#include "libm.h" + +float complex ctanhf(float complex z) { + float x, y; + float t, beta, s, rho, denom; + uint32_t hx, ix; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + + if (ix >= 0x7f800000) { + if (ix & 0x7fffff) return CMPLXF(x, (y == 0 ? y : x * y)); + SET_FLOAT_WORD(x, hx - 0x40000000); + return CMPLXF(x, copysignf(0, isinf(y) ? y : sinf(y) * cosf(y))); + } + + if (!isfinite(y)) return CMPLXF(ix ? y - y : x, y - y); + + if (ix >= 0x41300000) { /* x >= 11 */ + float exp_mx = expf(-fabsf(x)); + return CMPLXF(copysignf(1, x), 4 * sinf(y) * cosf(y) * exp_mx * exp_mx); + } + + t = tanf(y); + beta = 1.0 + t * t; + s = sinhf(x); + rho = sqrtf(1 + s * s); + denom = 1 + beta * s * s; + return CMPLXF((beta * rho * s) / denom, t / denom); +} diff --git a/third_party/ulib/musl/third_party/include/libm.h b/third_party/ulib/musl/third_party/include/libm.h new file mode 100644 index 000000000..ba13fe174 --- /dev/null +++ b/third_party/ulib/musl/third_party/include/libm.h @@ -0,0 +1,222 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef _LIBM_H +#define _LIBM_H + +#include +#include +#include +#include +#include + +// Clang does not support the C99 rounding mode pragma. Support seems +// unlikely to be coming soon, but for reference the clang/llvm bug +// tracking this fact may be found at: +// https://llvm.org/bugs/show_bug.cgi?id=8100 +#define PRAGMA_STDC_FENV_ACCESS_ON + +// GCC complains about the STDC CX_LIMITED_RANGE pragma. +#define PRAGMA_STDC_CX_LIMITED_RANGE_ON + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t m; + uint16_t se; + } i; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t lo; + uint32_t mid; + uint16_t top; + uint16_t se; + } i; + struct { + uint64_t lo; + uint64_t hi; + } i2; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t top; + uint32_t mid; + uint64_t lo; + } i; + struct { + uint64_t hi; + uint64_t lo; + } i2; +}; +#else +#error Unsupported long double representation +#endif + +#define FORCE_EVAL(x) \ + do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + } else { \ + volatile long double __x; \ + __x = (x); \ + } \ + } while (0) + +/* Get two 32 bit ints from a double. */ +#define EXTRACT_WORDS(hi, lo, d) \ + do { \ + union { \ + double f; \ + uint64_t i; \ + } __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ + (lo) = (uint32_t)__u.i; \ + } while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi, d) \ + do { \ + union { \ + double f; \ + uint64_t i; \ + } __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ + } while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo, d) \ + do { \ + union { \ + double f; \ + uint64_t i; \ + } __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ + } while (0) + +/* Set a double from two 32 bit ints. */ +#define INSERT_WORDS(d, hi, lo) \ + do { \ + union { \ + double f; \ + uint64_t i; \ + } __u; \ + __u.i = ((uint64_t)(hi) << 32) | (uint32_t)(lo); \ + (d) = __u.f; \ + } while (0) + +/* Set the more significant 32 bits of a double from an int. */ +#define SET_HIGH_WORD(d, hi) \ + do { \ + union { \ + double f; \ + uint64_t i; \ + } __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff; \ + __u.i |= (uint64_t)(hi) << 32; \ + (d) = __u.f; \ + } while (0) + +/* Set the less significant 32 bits of a double from an int. */ +#define SET_LOW_WORD(d, lo) \ + do { \ + union { \ + double f; \ + uint64_t i; \ + } __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff00000000ull; \ + __u.i |= (uint32_t)(lo); \ + (d) = __u.f; \ + } while (0) + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w, d) \ + do { \ + union { \ + float f; \ + uint32_t i; \ + } __u; \ + __u.f = (d); \ + (w) = __u.i; \ + } while (0) + +/* Set a float from a 32 bit int. */ +#define SET_FLOAT_WORD(d, w) \ + do { \ + union { \ + float f; \ + uint32_t i; \ + } __u; \ + __u.i = (w); \ + (d) = __u.f; \ + } while (0) + +#undef __CMPLX +#undef CMPLX +#undef CMPLXF +#undef CMPLXL + +#define __CMPLX(x, y, t) \ + ((union { \ + _Complex t __z; \ + t __xy[2]; \ + }){.__xy = {(x), (y)}} \ + .__z) + +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) + +/* fdlibm kernel functions */ + +int __rem_pio2_large(double*, double*, int, int, int); + +int __rem_pio2(double, double*); +double __sin(double, double, int); +double __cos(double, double); +double __tan(double, double, int); +double __expo2(double); +double complex __ldexp_cexp(double complex, int); + +int __rem_pio2f(float, double*); +float __sindf(double); +float __cosdf(double); +float __tandf(double, int); +float __expo2f(float); +float complex __ldexp_cexpf(float complex, int); + +int __rem_pio2l(long double, long double*); +long double __sinl(long double, long double, int); +long double __cosl(long double, long double); +long double __tanl(long double, long double, int); + +/* polynomial evaluation */ +long double __polevll(long double, const long double*, int); +long double __p1evll(long double, const long double*, int); + +#endif diff --git a/third_party/ulib/musl/third_party/math/BUILD.gn b/third_party/ulib/musl/third_party/math/BUILD.gn new file mode 100644 index 000000000..a2d691f69 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/BUILD.gn @@ -0,0 +1,89 @@ +source_set("math") { + configs = [] + + # Use relative path to make the build relocatable + configs += [ "../..:musl_config" ] + sources = [ + "__cos.c", + "__cosdf.c", + "__cosl.c", + "__polevll.c", + "__rem_pio2.c", + "__rem_pio2_large.c", + "__rem_pio2f.c", + "__rem_pio2l.c", + "__sin.c", + "__sindf.c", + "__sinl.c", + "__tan.c", + "__tandf.c", + "__tanl.c", + "acos.c", + "acosf.c", + "acosl.c", + "asin.c", + "asinf.c", + "asinl.c", + "atan.c", + "atan2.c", + "atan2f.c", + "atan2l.c", + "atanf.c", + "atanl.c", + "cbrt.c", + "cbrtf.c", + "cbrtl.c", + "cos.c", + "cosf.c", + "erf.c", + "erff.c", + "erfl.c", + "exp.c", + "exp2.c", + "exp2f.c", + "exp2l.c", + "expf.c", + "expl.c", + "expm1.c", + "expm1f.c", + "expm1l.c", + "fma.c", + "fmaf.c", + "fmal.c", + "j0.c", + "j0f.c", + "j1.c", + "j1f.c", + "jn.c", + "jnf.c", + "lgamma_r.c", + "lgammaf_r.c", + "lgammal.c", + "log.c", + "log10.c", + "log10f.c", + "log10l.c", + "log1p.c", + "log1pf.c", + "log1pl.c", + "log2.c", + "log2f.c", + "log2l.c", + "logf.c", + "logl.c", + "pow.c", + "powf.c", + "powl.c", + "scalb.c", + "scalbf.c", + "sin.c", + "sincos.c", + "sincosf.c", + "sinf.c", + "sqrt.c", + "sqrtf.c", + "tan.c", + "tanf.c", + "tgammal.c", + ] +} diff --git a/third_party/ulib/musl/third_party/math/__cos.c b/third_party/ulib/musl/third_party/math/__cos.c new file mode 100644 index 000000000..ef41a33ff --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__cos.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "libm.h" + +static const double C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ + C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ + C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ + C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ + C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ + C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double __cos(double x, double y) { + double_t hz, z, r, w; + + z = x * x; + w = z * z; + r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + hz = 0.5 * z; + w = 1.0 - hz; + return w + (((1.0 - w) - hz) + (z * r - x * y)); +} diff --git a/third_party/ulib/musl/third_party/math/__cosdf.c b/third_party/ulib/musl/third_party/math/__cosdf.c new file mode 100644 index 000000000..c6f38b07f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__cosdf.c @@ -0,0 +1,33 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ + C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ + C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ + C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +float __cosdf(double x) { + double_t r, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x * x; + w = z * z; + r = C2 + z * C3; + return ((1.0 + z * C0) + w * C1) + (w * z) * r; +} diff --git a/third_party/ulib/musl/third_party/math/__cosl.c b/third_party/ulib/musl/third_party/math/__cosl.c new file mode 100644 index 000000000..e46cd621d --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__cosl.c @@ -0,0 +1,96 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_cosl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_cosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-2.43e-23, 2.425e-23]: + * |cos(x) - c(x)| < 2**-75.1 + * + * The coefficients of c(x) were generated by a pari-gp script using + * a Remez algorithm that searches for the best higher coefficients + * after rounding leading coefficients to a specified precision. + * + * Simpler methods like Chebyshev or basic Remez barely suffice for + * cos() in 64-bit precision, because we want the coefficient of x^2 + * to be precisely -0.5 so that multiplying by it is exact, and plain + * rounding of the coefficients of a good polynomial approximation only + * gives this up to about 64-bit precision. Plain rounding also gives + * a mediocre approximation for the coefficient of x^4, but a rounding + * error of 0.5 ulps for this coefficient would only contribute ~0.01 + * ulps to the final error, so this is unimportant. Rounding errors in + * higher coefficients are even less important. + * + * In fact, coefficients above the x^4 one only need to have 53-bit + * precision, and this is more efficient. We get this optimization + * almost for free from the complications needed to search for the best + * higher coefficients. + */ +static const long double C1 = 0.0416666666666666666136L; /* 0xaaaaaaaaaaaaaa9b.0p-68 */ +static const double C2 = -0.0013888888888888874, /* -0x16c16c16c16c10.0p-62 */ + C3 = 0.000024801587301571716, /* 0x1a01a01a018e22.0p-68 */ + C4 = -0.00000027557319215507120, /* -0x127e4fb7602f22.0p-74 */ + C5 = 0.0000000020876754400407278, /* 0x11eed8caaeccf1.0p-81 */ + C6 = -1.1470297442401303e-11, /* -0x19393412bd1529.0p-89 */ + C7 = 4.7383039476436467e-14; /* 0x1aac9d9af5c43e.0p-97 */ +#define POLY(z) (z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * (C6 + z * C7))))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.80e-37, 1.79e-37]: + * |cos(x) - c(x))| < 2**-122.0 + * + * 113-bit precision requires more care than 64-bit precision, since + * simple methods give a minimax polynomial with coefficient for x^2 + * that is 1 ulp below 0.5, but we want it to be precisely 0.5. See + * above for more details. + */ +static const long double C1 = 0.04166666666666666666666666666666658424671L, + C2 = -0.001388888888888888888888888888863490893732L, + C3 = 0.00002480158730158730158730158600795304914210L, + C4 = -0.2755731922398589065255474947078934284324e-6L, + C5 = 0.2087675698786809897659225313136400793948e-8L, + C6 = -0.1147074559772972315817149986812031204775e-10L, + C7 = 0.4779477332386808976875457937252120293400e-13L; +static const double C8 = -0.1561920696721507929516718307820958119868e-15, + C9 = 0.4110317413744594971475941557607804508039e-18, + C10 = -0.8896592467191938803288521958313920156409e-21, + C11 = 0.1601061435794535138244346256065192782581e-23; +#define POLY(z) \ + (z * \ + (C1 + \ + z * (C2 + \ + z * (C3 + \ + z * (C4 + \ + z * (C5 + \ + z * (C6 + z * (C7 + z * (C8 + z * (C9 + z * (C10 + z * C11))))))))))) +#endif + +long double __cosl(long double x, long double y) { + long double hz, z, r, w; + + z = x * x; + r = POLY(z); + hz = 0.5 * z; + w = 1.0 - hz; + return w + (((1.0 - w) - hz) + (z * r - x * y)); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/__polevll.c b/third_party/ulib/musl/third_party/math/__polevll.c new file mode 100644 index 000000000..ffeea1398 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__polevll.c @@ -0,0 +1,91 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/polevll.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Evaluate polynomial + * + * + * SYNOPSIS: + * + * int N; + * long double x, y, coef[N+1], polevl[]; + * + * y = polevll( x, coef, N ); + * + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evll() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevll(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#else +/* + * Polynomial evaluator: + * P[0] x^n + P[1] x^(n-1) + ... + P[n] + */ +long double __polevll(long double x, const long double* P, int n) { + long double y; + + y = *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} + +/* + * Polynomial evaluator: + * x^n + P[0] x^(n-1) + P[1] x^(n-2) + ... + P[n] + */ +long double __p1evll(long double x, const long double* P, int n) { + long double y; + + n -= 1; + y = x + *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} +#endif diff --git a/third_party/ulib/musl/third_party/math/__rem_pio2.c b/third_party/ulib/musl/third_party/math/__rem_pio2.c new file mode 100644 index 000000000..a92e12450 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__rem_pio2.c @@ -0,0 +1,178 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double toint = 1.5 / EPS, + invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ + pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ + pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ + pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ + pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ + pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +int __rem_pio2(double x, double* y) { + union { + double f; + uint64_t i; + } u = {x}; + double_t z, w, t, r, fn; + double tx[3], ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i >> 63; + ix = u.i >> 32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z - y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z - y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2 * pio2_1; + y[0] = z - 2 * pio2_1t; + y[1] = (z - y[0]) - 2 * pio2_1t; + return 2; + } else { + z = x + 2 * pio2_1; + y[0] = z + 2 * pio2_1t; + y[1] = (z - y[0]) + 2 * pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3 * pio2_1; + y[0] = z - 3 * pio2_1t; + y[1] = (z - y[0]) - 3 * pio2_1t; + return 3; + } else { + z = x + 3 * pio2_1; + y[0] = z + 3 * pio2_1t; + y[1] = (z - y[0]) + 3 * pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4 * pio2_1; + y[0] = z - 4 * pio2_1t; + y[1] = (z - y[0]) - 4 * pio2_1t; + return 4; + } else { + z = x + 4 * pio2_1; + y[0] = z + 4 * pio2_1t; + y[1] = (z - y[0]) + 4 * pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ + medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = (double_t)x * invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn * pio2_1; + w = fn * pio2_1t; /* 1st round, good to 85 bits */ + y[0] = r - w; + u.f = y[0]; + ey = u.i >> 52 & 0x7ff; + ex = ix >> 20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn * pio2_2; + r = t - w; + w = fn * pio2_2t - ((t - r) - w); + y[0] = r - w; + u.f = y[0]; + ey = u.i >> 52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn * pio2_3; + r = t - w; + w = fn * pio2_3t - ((t - r) - w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1 >> 12; + u.i |= (uint64_t)(0x3ff + 23) << 52; + z = u.f; + for (i = 0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z - tx[i]) * 0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx, ty, (int)(ix >> 20) - (0x3ff + 23), i + 1, 1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} diff --git a/third_party/ulib/musl/third_party/math/__rem_pio2_large.c b/third_party/ulib/musl/third_party/math/__rem_pio2_large.c new file mode 100644 index 000000000..31271ce24 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__rem_pio2_large.c @@ -0,0 +1,416 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __rem_pio2_large(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __rem_pio2_large return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const int init_jk[] = {3, 4, 4, 6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, 0xDDAF44, 0xD15719, 0x053EA5, + 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, 0x433B15, 0xC614B5, 0x9D19C3, + 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, 0xF87C63, 0x57B07A, 0xE71517, + 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, 0x89E832, 0x60BFE6, 0xCDC4EF, + 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, 0x621283, 0x014883, 0x5B8EF5, + 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, 0xBDD76F, 0x63A62D, 0xCBBFF4, + 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, 0x10D5FD, 0xFCBE00, 0xCC941E, + 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, 0x90A772, 0x1FE76B, 0x96CB31, + 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, 0x25318D, 0x3974F7, 0x1C0530, + 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, 0x6863B2, 0x5F3EDD, 0x035D40, + 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, 0x17F987, 0x7D6B49, 0xBA271D, + 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, 0xFD9443, 0x8C860D, 0xDE4131, + 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, 0xB989C7, 0xBD4010, 0x04F2D2, + 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, 0x833F03, 0xF6F009, 0x8C402B, + 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, 0xABA1AE, 0x3115DF, 0xA1AE00, + 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, 0x8F1B57, 0x09CD36, 0xE9424E, + 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, 0xBA66AA, 0xCFCF76, 0x1D02D1, + 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, 0x0457B6, 0xB42D29, 0x7E804B, + 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, 0x86182A, 0xEABD4D, 0xAFE7B3, + 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, 0x845CB9, 0x496170, 0xE0566B, + 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, 0x2D408D, 0xA0CD4F, 0x99A520, + 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, 0xDEBE87, 0x2AFDDA, 0xB6256B, + 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, 0x86DD71, 0xB6DEC9, 0xF560BF, + 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, 0xD8649B, 0x31BED9, 0xC397A4, + 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, 0x35916F, 0xC5E008, 0x8DD7FF, + 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, 0x8AD874, 0x2C150D, 0x0C1881, + 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, 0x2D8912, 0x34576F, 0x89562C, + 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, 0xC8D91B, 0x0AFC81, 0x6A4AFB, + 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, 0xEEBC34, 0xCC5DE8, 0x605EDD, + 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, 0xFC0656, 0xAE79E5, 0x362289, + 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, 0x21CF98, 0xDC9F40, 0x5547DC, + 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, 0xE956FF, 0xCA0F1C, 0x8A59C5, + 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, 0x7BDBE5, 0xC23AC4, 0xEAF426, + 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, 0x237C7E, 0x32B90F, 0x8EF5A7, + 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, 0x5B2746, 0xED3400, 0x7700D2, + 0x55F4FC, 0x4D5901, 0x8071E0, +#endif +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) { + int32_t jz, jx, jv, jp, jk, carry, n, iq[20], i, j, k, m, q0, ih; + double z, fw, f[20], fq[20], q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx - 1; + jv = (e0 - 3) / 24; + if (jv < 0) jv = 0; + q0 = e0 - 24 * (jv + 1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv - jx; + m = jx + jk; + for (i = 0; i <= m; i++, j++) + f[i] = j < 0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i = 0; i <= jk; i++) { + for (j = 0, fw = 0.0; j <= jx; j++) + fw += x[j] * f[jx + i - j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--) { + fw = (double)(int32_t)(0x1p-24 * z); + iq[i] = (int32_t)(z - 0x1p24 * fw); + z = q[j - 1] + fw; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz - 1] >> (24 - q0); + n += i; + iq[jz - 1] -= i << (24 - q0); + ih = iq[jz - 1] >> (23 - q0); + } else if (q0 == 0) + ih = iq[jz - 1] >> 23; + else if (z >= 0.5) + ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; + carry = 0; + for (i = 0; i < jz; i++) { /* compute 1-q */ + j = iq[i]; + if (carry == 0) { + if (j != 0) { + carry = 1; + iq[i] = 0x1000000 - j; + } + } else + iq[i] = 0xffffff - j; + } + if (q0 > 0) { /* rare case: chance is 1 in 12 */ + switch (q0) { + case 1: + iq[jz - 1] &= 0x7fffff; + break; + case 2: + iq[jz - 1] &= 0x3fffff; + break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) z -= scalbn(1.0, q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i = jz - 1; i >= jk; i--) + j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k = 1; iq[jk - k] == 0; k++) + ; /* k = no. of terms needed */ + + for (i = jz + 1; i <= jz + k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx + i] = (double)ipio2[jv + i]; + for (j = 0, fw = 0.0; j <= jx; j++) + fw += x[j] * f[jx + i - j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24 * z); + iq[jz] = (int32_t)(z - 0x1p24 * fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0, q0); + for (i = jz; i >= 0; i--) { + q[i] = fw * (double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for (i = jz; i >= 0; i--) { + for (fw = 0.0, k = 0; k <= jp && k <= jz - i; k++) + fw += PIo2[k] * q[i + k]; + fq[jz - i] = fw; + } + + /* compress fq[] into y[] */ + switch (prec) { + case 0: + fw = 0.0; + for (i = jz; i >= 0; i--) + fw += fq[i]; + y[0] = ih == 0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i = jz; i >= 0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih == 0 ? fw : -fw; + fw = fq[0] - fw; + for (i = 1; i <= jz; i++) + fw += fq[i]; + y[1] = ih == 0 ? fw : -fw; + break; + case 3: /* painful */ + for (i = jz; i > 0; i--) { + fw = fq[i - 1] + fq[i]; + fq[i] += fq[i - 1] - fw; + fq[i - 1] = fw; + } + for (i = jz; i > 1; i--) { + fw = fq[i - 1] + fq[i]; + fq[i] += fq[i - 1] - fw; + fq[i - 1] = fw; + } + for (fw = 0.0, i = jz; i >= 2; i--) + fw += fq[i]; + if (ih == 0) { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; + } else { + y[0] = -fq[0]; + y[1] = -fq[1]; + y[2] = -fw; + } + } + return n & 7; +} diff --git a/third_party/ulib/musl/third_party/math/__rem_pio2f.c b/third_party/ulib/musl/third_party/math/__rem_pio2f.c new file mode 100644 index 000000000..3ae93b68a --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__rem_pio2f.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD == 2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ +static const double toint = 1.5 / EPS, + invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ + pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +int __rem_pio2f(float x, double* y) { + union { + float f; + uint32_t i; + } u = {x}; + double tx[1], ty[1]; + double_t fn; + uint32_t ix; + int n, sign, e0; + + ix = u.i & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = (double_t)x * invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn * pio2_1 - fn * pio2_1t; + return n; + } + if (ix >= 0x7f800000) { /* x is inf or NaN */ + *y = x - x; + return 0; + } + /* scale x into [2^23, 2^24-1] */ + sign = u.i >> 31; + e0 = (ix >> 23) - (0x7f + 23); /* e0 = ilogb(|x|)-23, positive */ + u.i = ix - (e0 << 23); + tx[0] = u.f; + n = __rem_pio2_large(tx, ty, e0, 1, 0); + if (sign) { + *y = -ty[0]; + return -n; + } + *y = ty[0]; + return n; +} diff --git a/third_party/ulib/musl/third_party/math/__rem_pio2l.c b/third_party/ulib/musl/third_party/math/__rem_pio2l.c new file mode 100644 index 000000000..dc685ea40 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__rem_pio2l.c @@ -0,0 +1,145 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +#include "libm.h" +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* ld80 and ld128 version of __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +static const long double toint = 1.5 / LDBL_EPSILON; + +#if LDBL_MANT_DIG == 64 +/* u ~< 0x1p25*pi/2 */ +#define SMALL(u) \ + (((u.i.se & 0x7fffU) << 16 | u.i.m >> 48) < ((0x3fff + 25) << 16 | 0x921f >> 1 | 0x8000)) +#define QUOBITS(x) ((uint32_t)(int32_t)x & 0x7fffffff) +#define ROUND1 22 +#define ROUND2 61 +#define NX 3 +#define NY 2 +/* + * invpio2: 64 bits of 2/pi + * pio2_1: first 39 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 39 bits of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 39 bits of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ + pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ + pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ +static const long double invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ + pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ + pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ + pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ +#elif LDBL_MANT_DIG == 113 +/* u ~< 0x1p45*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU) << 16 | u.i.top) < ((0x3fff + 45) << 16 | 0x921f)) +#define QUOBITS(x) ((uint32_t)(int64_t)x & 0x7fffffff) +#define ROUND1 51 +#define ROUND2 119 +#define NX 5 +#define NY 3 +static const long double + invpio2 = + 6.3661977236758134307553505349005747e-01L, /* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ + pio2_1 = + 1.5707963267948966192292994253909555e+00L, /* 0x1921fb54442d18469800000000000.0p-112 */ + pio2_1t = + 2.0222662487959507323996846200947577e-21L, /* 0x13198a2e03707344a4093822299f3.0p-181 */ + pio2_2 = + 2.0222662487959507323994779168837751e-21L, /* 0x13198a2e03707344a400000000000.0p-181 */ + pio2_2t = + 2.0670321098263988236496903051604844e-43L, /* 0x127044533e63a0105df531d89cd91.0p-254 */ + pio2_3 = + 2.0670321098263988236499468110329591e-43L, /* 0x127044533e63a0105e00000000000.0p-254 */ + pio2_3t = + -2.5650587247459238361625433492959285e-65L; /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */ +#endif + +int __rem_pio2l(long double x, long double* y) { + union ldshape u, uz; + long double z, w, t, r, fn; + double tx[NX], ty[NY]; + int ex, ey, n, i; + + u.f = x; + ex = u.i.se & 0x7fff; + if (SMALL(u)) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = x * invpio2 + toint - toint; + n = QUOBITS(fn); + r = x - fn * pio2_1; + w = fn * pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ + y[0] = r - w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND1) { /* 2nd iteration needed, good to 141/248 (ld80/ld128) */ + t = r; + w = fn * pio2_2; + r = t - w; + w = fn * pio2_2t - ((t - r) - w); + y[0] = r - w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND2) { /* 3rd iteration, good to 180/316 bits */ + t = r; /* will cover all possible cases (not verified for ld128) */ + w = fn * pio2_3; + r = t - w; + w = fn * pio2_3t - ((t - r) - w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ex == 0x7fff) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + uz.f = x; + uz.i.se = 0x3fff + 23; + z = uz.f; + for (i = 0; i < NX - 1; i++) { + tx[i] = (double)(int32_t)z; + z = (z - tx[i]) * 0x1p24; + } + tx[i] = z; + while (tx[i] == 0) + i--; + n = __rem_pio2_large(tx, ty, ex - 0x3fff - 23, i + 1, NY); + w = ty[1]; + if (NY == 3) w += ty[2]; + r = ty[0] + w; + /* TODO: for ld128 this does not follow the recommendation of the + comments of __rem_pio2_large which seem wrong if |ty[0]| > |ty[1]+ty[2]| */ + w -= r - ty[0]; + if (u.i.se >> 15) { + y[0] = -r; + y[1] = -w; + return -n; + } + y[0] = r; + y[1] = w; + return n; +} +#endif diff --git a/third_party/ulib/musl/third_party/math/__sin.c b/third_party/ulib/musl/third_party/math/__sin.c new file mode 100644 index 000000000..05f8313de --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__sin.c @@ -0,0 +1,62 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "libm.h" + +static const double S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ + S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ + S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ + S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ + S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ + S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double __sin(double x, double y, int iy) { + double_t z, r, v, w; + + z = x * x; + w = z * z; + r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + v = z * x; + if (iy == 0) + return x + v * (S1 + z * r); + else + return x - ((z * (0.5 * y - v * r) - y) - v * S1); +} diff --git a/third_party/ulib/musl/third_party/math/__sindf.c b/third_party/ulib/musl/third_party/math/__sindf.c new file mode 100644 index 000000000..049c48529 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__sindf.c @@ -0,0 +1,34 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ + S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ + S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ + S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +float __sindf(double x) { + double_t r, s, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x * x; + w = z * z; + r = S3 + z * S4; + s = z * x; + return (x + s * (S1 + z * S2)) + s * w * r; +} diff --git a/third_party/ulib/musl/third_party/math/__sinl.c b/third_party/ulib/musl/third_party/math/__sinl.c new file mode 100644 index 000000000..39295037d --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__sinl.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_sinl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_sinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.89e-22, 1.915e-22] + * |sin(x)/x - s(x)| < 2**-72.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double S1 = -0.166666666666666666671L; /* -0xaaaaaaaaaaaaaaab.0p-66 */ +static const double S2 = 0.0083333333333333332, /* 0x11111111111111.0p-59 */ + S3 = -0.00019841269841269427, /* -0x1a01a01a019f81.0p-65 */ + S4 = 0.0000027557319223597490, /* 0x171de3a55560f7.0p-71 */ + S5 = -0.000000025052108218074604, /* -0x1ae64564f16cad.0p-78 */ + S6 = 1.6059006598854211e-10, /* 0x161242b90243b5.0p-85 */ + S7 = -7.6429779983024564e-13, /* -0x1ae42ebd1b2e00.0p-93 */ + S8 = 2.6174587166648325e-15; /* 0x179372ea0b3f64.0p-101 */ +#define POLY(z) (S2 + z * (S3 + z * (S4 + z * (S5 + z * (S6 + z * (S7 + z * S8)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.53e-37, 1.659e-37] + * |sin(x)/x - s(x)| < 2**-122.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double S1 = -0.16666666666666666666666666666666666606732416116558L, + S2 = 0.0083333333333333333333333333333331135404851288270047L, + S3 = -0.00019841269841269841269841269839935785325638310428717L, + S4 = 0.27557319223985890652557316053039946268333231205686e-5L, + S5 = -0.25052108385441718775048214826384312253862930064745e-7L, + S6 = 0.16059043836821614596571832194524392581082444805729e-9L, + S7 = -0.76471637318198151807063387954939213287488216303768e-12L, + S8 = 0.28114572543451292625024967174638477283187397621303e-14L; +static const double S9 = -0.82206352458348947812512122163446202498005154296863e-17, + S10 = 0.19572940011906109418080609928334380560135358385256e-19, + S11 = -0.38680813379701966970673724299207480965452616911420e-22, + S12 = 0.64038150078671872796678569586315881020659912139412e-25; +#define POLY(z) \ + (S2 + \ + z * (S3 + \ + z * (S4 + \ + z * (S5 + \ + z * (S6 + \ + z * (S7 + z * (S8 + z * (S9 + z * (S10 + z * (S11 + z * S12)))))))))) +#endif + +long double __sinl(long double x, long double y, int iy) { + long double z, r, v; + + z = x * x; + v = z * x; + r = POLY(z); + if (iy == 0) return x + v * (S1 + z * r); + return x - ((z * (0.5 * y - v * r) - y) - v * S1); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/__tan.c b/third_party/ulib/musl/third_party/math/__tan.c new file mode 100644 index 000000000..59e3a666e --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__tan.c @@ -0,0 +1,109 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "libm.h" + +static const double T[] = + { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +}, + pio4 = 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ + pio4lo = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +double __tan(double x, double y, int odd) { + double_t z, r, v, w, s, a; + double w0, a0; + uint32_t hx; + int big, sign; + + GET_HIGH_WORD(hx, x); + big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if (big) { + sign = hx >> 31; + if (sign) { + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); + v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); + s = z * x; + r = y + z * (s * (r + v) + y) + s * T[0]; + w = x + r; + if (big) { + s = 1 - 2 * odd; + v = s - 2.0 * (x + (r - w * w / (w + s))); + return sign ? -v : v; + } + if (!odd) return w; + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + w0 = w; + SET_LOW_WORD(w0, 0); + v = r - (w0 - x); /* w0+v = r+x */ + a0 = a = -1.0 / w; + SET_LOW_WORD(a0, 0); + return a0 + a * (1.0 + a0 * w0 + a0 * v); +} diff --git a/third_party/ulib/musl/third_party/math/__tandf.c b/third_party/ulib/musl/third_party/math/__tandf.c new file mode 100644 index 000000000..edf7a7dd3 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__tandf.c @@ -0,0 +1,53 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +static const double T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ +}; + +float __tandf(double x, int odd) { + double_t z, r, w, s, t, u; + + z = x * x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4] + z * T[5]; + t = T[2] + z * T[3]; + w = z * z; + s = z * x; + u = T[0] + z * T[1]; + r = (x + s * u) + (s * w) * (t + w * r); + return odd ? -1.0 / r : r; +} diff --git a/third_party/ulib/musl/third_party/math/__tanl.c b/third_party/ulib/musl/third_party/math/__tanl.c new file mode 100644 index 000000000..6db896c86 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/__tanl.c @@ -0,0 +1,155 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_tanl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_tanl.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-2.25e-22, 1.921e-22] + * |tan(x)/x - t(x)| < 2**-71.9 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double T3 = 0.333333333333333333180L, /* 0xaaaaaaaaaaaaaaa5.0p-65 */ + T5 = 0.133333333333333372290L, /* 0x88888888888893c3.0p-66 */ + T7 = 0.0539682539682504975744L, /* 0xdd0dd0dd0dc13ba2.0p-68 */ + pio4 = 0.785398163397448309628L, /* 0xc90fdaa22168c235.0p-64 */ + pio4lo = -1.25413940316708300586e-20L; /* -0xece675d1fc8f8cbb.0p-130 */ +static const double T9 = 0.021869488536312216, /* 0x1664f4882cc1c2.0p-58 */ + T11 = 0.0088632355256619590, /* 0x1226e355c17612.0p-59 */ + T13 = 0.0035921281113786528, /* 0x1d6d3d185d7ff8.0p-61 */ + T15 = 0.0014558334756312418, /* 0x17da354aa3f96b.0p-62 */ + T17 = 0.00059003538700862256, /* 0x13559358685b83.0p-63 */ + T19 = 0.00023907843576635544, /* 0x1f56242026b5be.0p-65 */ + T21 = 0.000097154625656538905, /* 0x1977efc26806f4.0p-66 */ + T23 = 0.000038440165747303162, /* 0x14275a09b3ceac.0p-67 */ + T25 = 0.000018082171885432524, /* 0x12f5e563e5487e.0p-68 */ + T27 = 0.0000024196006108814377, /* 0x144c0d80cc6896.0p-71 */ + T29 = 0.0000078293456938132840, /* 0x106b59141a6cb3.0p-69 */ + T31 = -0.0000032609076735050182, /* -0x1b5abef3ba4b59.0p-71 */ + T33 = 0.0000023261313142559411; /* 0x13835436c0c87f.0p-71 */ +#define RPOLY(w) \ + (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + w * (T25 + w * (T29 + w * T33))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + w * (T27 + w * T31)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-3.37e-36, 1.982e-37] + * |tan(x)/x - t(x)| < 2**-117.8 (XXX should be ~1e-37) + * + * See __cosl.c for more details about the polynomial. + */ +static const long double T3 = 0x1.5555555555555555555555555553p-2L, + T5 = 0x1.1111111111111111111111111eb5p-3L, + T7 = 0x1.ba1ba1ba1ba1ba1ba1ba1b694cd6p-5L, + T9 = 0x1.664f4882c10f9f32d6bbe09d8bcdp-6L, + T11 = 0x1.226e355e6c23c8f5b4f5762322eep-7L, + T13 = 0x1.d6d3d0e157ddfb5fed8e84e27b37p-9L, + T15 = 0x1.7da36452b75e2b5fce9ee7c2c92ep-10L, + T17 = 0x1.355824803674477dfcf726649efep-11L, + T19 = 0x1.f57d7734d1656e0aceb716f614c2p-13L, + T21 = 0x1.967e18afcb180ed942dfdc518d6cp-14L, + T23 = 0x1.497d8eea21e95bc7e2aa79b9f2cdp-15L, + T25 = 0x1.0b132d39f055c81be49eff7afd50p-16L, + T27 = 0x1.b0f72d33eff7bfa2fbc1059d90b6p-18L, + T29 = 0x1.5ef2daf21d1113df38d0fbc00267p-19L, + T31 = 0x1.1c77d6eac0234988cdaa04c96626p-20L, + T33 = 0x1.cd2a5a292b180e0bdd701057dfe3p-22L, + T35 = 0x1.75c7357d0298c01a31d0a6f7d518p-23L, + T37 = 0x1.2f3190f4718a9a520f98f50081fcp-24L, + pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, + pio4lo = 0x1.cd129024e088a67cc74020bbea60p-116L; +static const double T39 = 0.000000028443389121318352, /* 0x1e8a7592977938.0p-78 */ + T41 = 0.000000011981013102001973, /* 0x19baa1b1223219.0p-79 */ + T43 = 0.0000000038303578044958070, /* 0x107385dfb24529.0p-80 */ + T45 = 0.0000000034664378216909893, /* 0x1dc6c702a05262.0p-81 */ + T47 = -0.0000000015090641701997785, /* -0x19ecef3569ebb6.0p-82 */ + T49 = 0.0000000029449552300483952, /* 0x194c0668da786a.0p-81 */ + T51 = -0.0000000022006995706097711, /* -0x12e763b8845268.0p-81 */ + T53 = 0.0000000015468200913196612, /* 0x1a92fc98c29554.0p-82 */ + T55 = -0.00000000061311613386849674, /* -0x151106cbc779a9.0p-83 */ + T57 = 1.4912469681508012e-10; /* 0x147edbdba6f43a.0p-85 */ +#define RPOLY(w) \ + (T5 + \ + w * (T9 + \ + w * (T13 + \ + w * (T17 + \ + w * (T21 + \ + w * (T25 + \ + w * (T29 + \ + w * (T33 + \ + w * (T37 + \ + w * (T41 + \ + w * (T45 + \ + w * (T49 + w * (T53 + w * T57))))))))))))) +#define VPOLY(w) \ + (T7 + \ + w * (T11 + \ + w * (T15 + \ + w * (T19 + \ + w * (T23 + \ + w * (T27 + \ + w * (T31 + \ + w * (T35 + \ + w * (T39 + \ + w * (T43 + w * (T47 + w * (T51 + w * T55)))))))))))) +#endif + +long double __tanl(long double x, long double y, int odd) { + long double z, r, v, w, s, a, t; + int big, sign; + + big = fabsl(x) >= 0.67434; + if (big) { + sign = 0; + if (x < 0) { + sign = 1; + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + r = RPOLY(w); + v = z * VPOLY(w); + s = z * x; + r = y + z * (s * (r + v) + y) + T3 * s; + w = x + r; + if (big) { + s = 1 - 2 * odd; + v = s - 2.0 * (x + (r - w * w / (w + s))); + return sign ? -v : v; + } + if (!odd) return w; + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + z = w; + z = z + 0x1p32 - 0x1p32; + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + t = t + 0x1p32 - 0x1p32; + s = 1.0 + t * z; + return t + a * (s + t * v); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/acos.c b/third_party/ulib/musl/third_party/math/acos.c new file mode 100644 index 000000000..fb05bfe85 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/acos.c @@ -0,0 +1,97 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include "libm.h" + +static const double pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ + pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ + pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ + pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ + pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ + pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ + pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ + pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ + qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ + qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ + qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ + qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) { + double_t p, q; + p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); + q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); + return p / q; +} + +double acos(double x) { + double z, w, s, c, df; + uint32_t hx, ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + + GET_LOW_WORD(lx, x); + if ((ix - 0x3ff00000 | lx) == 0) { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) return 2 * pio2_hi + 0x1p-120f; + return 0; + } + return 0 / (x - x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + if (ix <= 0x3c600000) /* |x| < 2**-57 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo - x * R(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1.0 + x) * 0.5; + s = sqrt(z); + w = R(z) * s - pio2_lo; + return 2 * (pio2_hi - (s + w)); + } + /* x > 0.5 */ + z = (1.0 - x) * 0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df, 0); + c = (z - df * df) / (s + df); + w = R(z) * s + c; + return 2 * (df + w); +} diff --git a/third_party/ulib/musl/third_party/math/acosf.c b/third_party/ulib/musl/third_party/math/acosf.c new file mode 100644 index 000000000..941852986 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/acosf.c @@ -0,0 +1,65 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ + pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ + pS0 = 1.6666586697e-01, pS1 = -4.2743422091e-02, pS2 = -8.6563630030e-03, + qS1 = -7.0662963390e-01; + +static float R(float z) { + float_t p, q; + p = z * (pS0 + z * (pS1 + z * pS2)); + q = 1.0f + z * qS1; + return p / q; +} + +float acosf(float x) { + float z, w, s, c, df; + uint32_t hx, ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3f800000) { + if (ix == 0x3f800000) { + if (hx >> 31) return 2 * pio2_hi + 0x1p-120f; + return 0; + } + return 0 / (x - x); + } + /* |x| < 0.5 */ + if (ix < 0x3f000000) { + if (ix <= 0x32800000) /* |x| < 2**-26 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo - x * R(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1 + x) * 0.5f; + s = sqrtf(z); + w = R(z) * s - pio2_lo; + return 2 * (pio2_hi - (s + w)); + } + /* x > 0.5 */ + z = (1 - x) * 0.5f; + s = sqrtf(z); + GET_FLOAT_WORD(hx, s); + SET_FLOAT_WORD(df, hx & 0xfffff000); + c = (z - df * df) / (s + df); + w = R(z) * s + c; + return 2 * (df + w); +} diff --git a/third_party/ulib/musl/third_party/math/acosl.c b/third_party/ulib/musl/third_party/math/acosl.c new file mode 100644 index 000000000..42d5ab826 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/acosl.c @@ -0,0 +1,62 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in acos.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acosl(long double x) { + return acos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double acosl(long double x) { + union ldshape u = {x}; + long double z, s, c, f; + uint16_t e = u.i.se & 0x7fff; + + /* |x| >= 1 or nan */ + if (e >= 0x3fff) { + if (x == 1) return 0; + if (x == -1) return 2 * pio2_hi + 0x1p-120f; + return 0 / (x - x); + } + /* |x| < 0.5 */ + if (e < 0x3fff - 1) { + if (e < 0x3fff - LDBL_MANT_DIG - 1) return pio2_hi + 0x1p-120f; + return pio2_hi - (__invtrigl_R(x * x) * x - pio2_lo + x); + } + /* x < -0.5 */ + if (u.i.se >> 15) { + z = (1 + x) * 0.5; + s = sqrtl(z); + return 2 * (pio2_hi - (__invtrigl_R(z) * s - pio2_lo + s)); + } + /* x > 0.5 */ + z = (1 - x) * 0.5; + s = sqrtl(z); + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f * f) / (s + f); + return 2 * (__invtrigl_R(z) * s + c + f); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/asin.c b/third_party/ulib/musl/third_party/math/asin.c new file mode 100644 index 000000000..9a91cdecb --- /dev/null +++ b/third_party/ulib/musl/third_party/math/asin.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +#include "libm.h" + +static const double pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ + pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ + /* coefficients for R(x^2) */ + pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ + pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ + pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ + pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ + pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ + pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ + qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ + qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ + qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ + qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) { + double_t p, q; + p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); + q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); + return p / q; +} + +double asin(double x) { + double z, r, s; + uint32_t hx, ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + GET_LOW_WORD(lx, x); + if ((ix - 0x3ff00000 | lx) == 0) /* asin(1) = +-pi/2 with inexact */ + return x * pio2_hi + 0x1p-120f; + return 0 / (x - x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if (ix < 0x3e500000 && ix >= 0x00100000) return x; + return x + x * R(x * x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabs(x)) * 0.5; + s = sqrt(z); + r = R(z); + if (ix >= 0x3fef3333) { /* if |x| > 0.975 */ + x = pio2_hi - (2 * (s + s * r) - pio2_lo); + } else { + double f, c; + /* f+c = sqrt(z) */ + f = s; + SET_LOW_WORD(f, 0); + c = (z - f * f) / (s + f); + x = 0.5 * pio2_hi - (2 * s * r - (pio2_lo - 2 * c) - (0.5 * pio2_hi - 2 * f)); + } + if (hx >> 31) return -x; + return x; +} diff --git a/third_party/ulib/musl/third_party/math/asinf.c b/third_party/ulib/musl/third_party/math/asinf.c new file mode 100644 index 000000000..3f49e74a4 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/asinf.c @@ -0,0 +1,54 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +#include "libm.h" + +static const double pio2 = 1.570796326794896558e+00; + +static const float + /* coefficients for R(x^2) */ + pS0 = 1.6666586697e-01, + pS1 = -4.2743422091e-02, pS2 = -8.6563630030e-03, qS1 = -7.0662963390e-01; + +static float R(float z) { + float_t p, q; + p = z * (pS0 + z * (pS1 + z * pS2)); + q = 1.0f + z * qS1; + return p / q; +} + +float asinf(float x) { + double s; + float z; + uint32_t hx, ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + if (ix >= 0x3f800000) { /* |x| >= 1 */ + if (ix == 0x3f800000) /* |x| == 1 */ + return x * pio2 + 0x1p-120f; /* asin(+-1) = +-pi/2 with inexact */ + return 0 / (x - x); /* asin(|x|>1) is NaN */ + } + if (ix < 0x3f000000) { /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000 && ix >= 0x00800000) return x; + return x + x * R(x * x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabsf(x)) * 0.5f; + s = sqrt(z); + x = pio2 - 2 * (s + s * R(z)); + if (hx >> 31) return -x; + return x; +} diff --git a/third_party/ulib/musl/third_party/math/asinl.c b/third_party/ulib/musl/third_party/math/asinl.c new file mode 100644 index 000000000..877e31c4f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/asinl.c @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in asin.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinl(long double x) { + return asin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLOSETO1(u) (u.i.m >> 56 >= 0xf7) +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLOSETO1(u) (u.i.top >= 0xee00) +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double asinl(long double x) { + union ldshape u = {x}; + long double z, r, s; + uint16_t e = u.i.se & 0x7fff; + int sign = u.i.se >> 15; + + if (e >= 0x3fff) { /* |x| >= 1 or nan */ + /* asin(+-1)=+-pi/2 with inexact */ + if (x == 1 || x == -1) return x * pio2_hi + 0x1p-120f; + return 0 / (x - x); + } + if (e < 0x3fff - 1) { /* |x| < 0.5 */ + if (e < 0x3fff - (LDBL_MANT_DIG + 1) / 2) { + /* return x with inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return x; + } + return x + x * __invtrigl_R(x * x); + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabsl(x)) * 0.5; + s = sqrtl(z); + r = __invtrigl_R(z); + if (CLOSETO1(u)) { + x = pio2_hi - (2 * (s + s * r) - pio2_lo); + } else { + long double f, c; + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f * f) / (s + f); + x = 0.5 * pio2_hi - (2 * s * r - (pio2_lo - 2 * c) - (0.5 * pio2_hi - 2 * f)); + } + return sign ? -x : x; +} +#endif diff --git a/third_party/ulib/musl/third_party/math/atan.c b/third_party/ulib/musl/third_party/math/atan.c new file mode 100644 index 000000000..bc21192c1 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/atan.c @@ -0,0 +1,111 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + +double atan(double x) { + double_t w, s1, s2, z; + uint32_t ix, sign; + int id; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x44100000) { /* if |x| >= 2^66 */ + if (isnan(x)) return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if (ix < 0x00100000) /* raise underflow for subnormal x */ + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0 * x - 1.0) / (2.0 + x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x - 1.0) / (x + 1.0); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; + x = (x - 1.5) / (1.0 + 1.5 * x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; + x = -1.0 / x; + } + } + } + /* end of argument reduction */ + z = x * x; + w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10]))))); + s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9])))); + if (id < 0) return x - x * (s1 + s2); + z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x); + return sign ? -z : z; +} diff --git a/third_party/ulib/musl/third_party/math/atan2.c b/third_party/ulib/musl/third_party/math/atan2.c new file mode 100644 index 000000000..1414ab99f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/atan2.c @@ -0,0 +1,116 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */ + pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double atan2(double y, double x) { + double z; + uint32_t m, lx, ly, ix, iy; + + if (isnan(x) || isnan(y)) return x + y; + EXTRACT_WORDS(ix, lx, x); + EXTRACT_WORDS(iy, ly, y); + if ((ix - 0x3ff00000 | lx) == 0) /* x = 1.0 */ + return atan(y); + m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix = ix & 0x7fffffff; + iy = iy & 0x7fffffff; + + /* when y = 0 */ + if ((iy | ly) == 0) { + switch (m) { + case 0: + case 1: + return y; /* atan(+-0,+anything)=+-0 */ + case 2: + return pi; /* atan(+0,-anything) = pi */ + case 3: + return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if ((ix | lx) == 0) return m & 1 ? -pi / 2 : pi / 2; + /* when x is INF */ + if (ix == 0x7ff00000) { + if (iy == 0x7ff00000) { + switch (m) { + case 0: + return pi / 4; /* atan(+INF,+INF) */ + case 1: + return -pi / 4; /* atan(-INF,+INF) */ + case 2: + return 3 * pi / 4; /* atan(+INF,-INF) */ + case 3: + return -3 * pi / 4; /* atan(-INF,-INF) */ + } + } else { + switch (m) { + case 0: + return 0.0; /* atan(+...,+INF) */ + case 1: + return -0.0; /* atan(-...,+INF) */ + case 2: + return pi; /* atan(+...,-INF) */ + case 3: + return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p64 */ + if (ix + (64 << 20) < iy || iy == 0x7ff00000) return m & 1 ? -pi / 2 : pi / 2; + + /* z = atan(|y/x|) without spurious underflow */ + if ((m & 2) && iy + (64 << 20) < ix) /* |y/x| < 0x1p-64, x<0 */ + z = 0; + else + z = atan(fabs(y / x)); + switch (m) { + case 0: + return z; /* atan(+,+) */ + case 1: + return -z; /* atan(-,+) */ + case 2: + return pi - (z - pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z - pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/third_party/ulib/musl/third_party/math/atan2f.c b/third_party/ulib/musl/third_party/math/atan2f.c new file mode 100644 index 000000000..449934b0f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/atan2f.c @@ -0,0 +1,92 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float pi = 3.1415927410e+00, /* 0x40490fdb */ + pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float atan2f(float y, float x) { + float z; + uint32_t m, ix, iy; + + if (isnan(x) || isnan(y)) return x + y; + GET_FLOAT_WORD(ix, x); + GET_FLOAT_WORD(iy, y); + if (ix == 0x3f800000) /* x=1.0 */ + return atanf(y); + m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy == 0) { + switch (m) { + case 0: + case 1: + return y; /* atan(+-0,+anything)=+-0 */ + case 2: + return pi; /* atan(+0,-anything) = pi */ + case 3: + return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if (ix == 0) return m & 1 ? -pi / 2 : pi / 2; + /* when x is INF */ + if (ix == 0x7f800000) { + if (iy == 0x7f800000) { + switch (m) { + case 0: + return pi / 4; /* atan(+INF,+INF) */ + case 1: + return -pi / 4; /* atan(-INF,+INF) */ + case 2: + return 3 * pi / 4; /*atan(+INF,-INF)*/ + case 3: + return -3 * pi / 4; /*atan(-INF,-INF)*/ + } + } else { + switch (m) { + case 0: + return 0.0f; /* atan(+...,+INF) */ + case 1: + return -0.0f; /* atan(-...,+INF) */ + case 2: + return pi; /* atan(+...,-INF) */ + case 3: + return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy || iy == 0x7f800000) return m & 1 ? -pi / 2 : pi / 2; + + /* z = atan(|y/x|) with correct underflow */ + if ((m & 2) && iy + (26 << 23) < ix) /*|y/x| < 0x1p-26, x < 0 */ + z = 0.0; + else + z = atanf(fabsf(y / x)); + switch (m) { + case 0: + return z; /* atan(+,+) */ + case 1: + return -z; /* atan(-,+) */ + case 2: + return pi - (z - pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z - pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/third_party/ulib/musl/third_party/math/atan2l.c b/third_party/ulib/musl/third_party/math/atan2l.c new file mode 100644 index 000000000..eb574ad84 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/atan2l.c @@ -0,0 +1,93 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2l.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* + * See comments in atan2.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atan2l(long double y, long double x) { + return atan2(y, x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" + +long double atan2l(long double y, long double x) { + union ldshape ux, uy; + long double z; + int m, ex, ey; + + if (isnan(x) || isnan(y)) return x + y; + if (x == 1) return atanl(y); + ux.f = x; + uy.f = y; + ex = ux.i.se & 0x7fff; + ey = uy.i.se & 0x7fff; + m = 2 * (ux.i.se >> 15) | uy.i.se >> 15; + if (y == 0) { + switch (m) { + case 0: + case 1: + return y; /* atan(+-0,+anything)=+-0 */ + case 2: + return 2 * pio2_hi; /* atan(+0,-anything) = pi */ + case 3: + return -2 * pio2_hi; /* atan(-0,-anything) =-pi */ + } + } + if (x == 0) return m & 1 ? -pio2_hi : pio2_hi; + if (ex == 0x7fff) { + if (ey == 0x7fff) { + switch (m) { + case 0: + return pio2_hi / 2; /* atan(+INF,+INF) */ + case 1: + return -pio2_hi / 2; /* atan(-INF,+INF) */ + case 2: + return 1.5 * pio2_hi; /* atan(+INF,-INF) */ + case 3: + return -1.5 * pio2_hi; /* atan(-INF,-INF) */ + } + } else { + switch (m) { + case 0: + return 0.0; /* atan(+...,+INF) */ + case 1: + return -0.0; /* atan(-...,+INF) */ + case 2: + return 2 * pio2_hi; /* atan(+...,-INF) */ + case 3: + return -2 * pio2_hi; /* atan(-...,-INF) */ + } + } + } + if (ex + 120 < ey || ey == 0x7fff) return m & 1 ? -pio2_hi : pio2_hi; + /* z = atan(|y/x|) without spurious underflow */ + if ((m & 2) && ey + 120 < ex) /* |y/x| < 0x1p-120, x<0 */ + z = 0.0; + else + z = atanl(fabsl(y / x)); + switch (m) { + case 0: + return z; /* atan(+,+) */ + case 1: + return -z; /* atan(-,+) */ + case 2: + return 2 * pio2_hi - (z - 2 * pio2_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z - 2 * pio2_lo) - 2 * pio2_hi; /* atan(-,-) */ + } +} +#endif diff --git a/third_party/ulib/musl/third_party/math/atanf.c b/third_party/ulib/musl/third_party/math/atanf.c new file mode 100644 index 000000000..b272173f2 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/atanf.c @@ -0,0 +1,85 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float atanhi[] = { + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { + 3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02, +}; + +float atanf(float x) { + float_t w, s1, s2, z; + uint32_t ix, sign; + int id; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x4c800000) { /* if |x| >= 2**26 */ + if (isnan(x)) return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + if (ix < 0x00800000) /* raise underflow for subnormal x */ + FORCE_EVAL(x * x); + return x; + } + id = -1; + } else { + x = fabsf(x); + if (ix < 0x3f980000) { /* |x| < 1.1875 */ + if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0f * x - 1.0f) / (2.0f + x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x - 1.0f) / (x + 1.0f); + } + } else { + if (ix < 0x401c0000) { /* |x| < 2.4375 */ + id = 2; + x = (x - 1.5f) / (1.0f + 1.5f * x); + } else { /* 2.4375 <= |x| < 2**26 */ + id = 3; + x = -1.0f / x; + } + } + } + /* end of argument reduction */ + z = x * x; + w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z * (aT[0] + w * (aT[2] + w * aT[4])); + s2 = w * (aT[1] + w * aT[3]); + if (id < 0) return x - x * (s1 + s2); + z = atanhi[id] - ((x * (s1 + s2) - atanlo[id]) - x); + return sign ? -z : z; +} diff --git a/third_party/ulib/musl/third_party/math/atanl.c b/third_party/ulib/musl/third_party/math/atanl.c new file mode 100644 index 000000000..6bd3a9a33 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/atanl.c @@ -0,0 +1,162 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in atan.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanl(long double x) { + return atan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +#if LDBL_MANT_DIG == 64 +#define EXPMAN(u) ((u.i.se & 0x7fff) << 8 | (u.i.m >> 55 & 0xff)) + +static const long double atanhi[] = { + 4.63647609000806116202e-01L, 7.85398163397448309628e-01L, 9.82793723247329067960e-01L, + 1.57079632679489661926e+00L, +}; + +static const long double atanlo[] = { + 1.18469937025062860669e-20L, -1.25413940316708300586e-20L, 2.55232234165405176172e-20L, + -2.50827880633416601173e-20L, +}; + +static const long double aT[] = { + 3.33333333333333333017e-01L, -1.99999999999999632011e-01L, 1.42857142857046531280e-01L, + -1.11111111100562372733e-01L, 9.09090902935647302252e-02L, -7.69230552476207730353e-02L, + 6.66661718042406260546e-02L, -5.88158892835030888692e-02L, 5.25499891539726639379e-02L, + -4.70119845393155721494e-02L, 4.03539201366454414072e-02L, -2.91303858419364158725e-02L, + 1.24822046299269234080e-02L, +}; + +static long double T_even(long double x) { + return aT[0] + + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * (aT[8] + x * (aT[10] + x * aT[12]))))); +} + +static long double T_odd(long double x) { + return aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * (aT[9] + x * aT[11])))); +} +#elif LDBL_MANT_DIG == 113 +#define EXPMAN(u) ((u.i.se & 0x7fff) << 8 | u.i.top >> 8) + +const long double atanhi[] = { + 4.63647609000806116214256231461214397e-01L, 7.85398163397448309615660845819875699e-01L, + 9.82793723247329067985710611014666038e-01L, 1.57079632679489661923132169163975140e+00L, +}; + +const long double atanlo[] = { + 4.89509642257333492668618435220297706e-36L, 2.16795253253094525619926100651083806e-35L, + -2.31288434538183565909319952098066272e-35L, 4.33590506506189051239852201302167613e-35L, +}; + +const long double aT[] = { + 3.33333333333333333333333333333333125e-01L, -1.99999999999999999999999999999180430e-01L, + 1.42857142857142857142857142125269827e-01L, -1.11111111111111111111110834490810169e-01L, + 9.09090909090909090908522355708623681e-02L, -7.69230769230769230696553844935357021e-02L, + 6.66666666666666660390096773046256096e-02L, -5.88235294117646671706582985209643694e-02L, + 5.26315789473666478515847092020327506e-02L, -4.76190476189855517021024424991436144e-02L, + 4.34782608678695085948531993458097026e-02L, -3.99999999632663469330634215991142368e-02L, + 3.70370363987423702891250829918659723e-02L, -3.44827496515048090726669907612335954e-02L, + 3.22579620681420149871973710852268528e-02L, -3.03020767654269261041647570626778067e-02L, + 2.85641979882534783223403715930946138e-02L, -2.69824879726738568189929461383741323e-02L, + 2.54194698498808542954187110873675769e-02L, -2.35083879708189059926183138130183215e-02L, + 2.04832358998165364349957325067131428e-02L, -1.54489555488544397858507248612362957e-02L, + 8.64492360989278761493037861575248038e-03L, -2.58521121597609872727919154569765469e-03L, +}; + +static long double T_even(long double x) { + return ( + aT[0] + + x * (aT[2] + + x * (aT[4] + + x * (aT[6] + + x * (aT[8] + + x * (aT[10] + + x * (aT[12] + + x * (aT[14] + + x * (aT[16] + + x * (aT[18] + x * (aT[20] + x * aT[22]))))))))))); +} + +static long double T_odd(long double x) { + return ( + aT[1] + + x * (aT[3] + + x * (aT[5] + + x * (aT[7] + + x * (aT[9] + + x * (aT[11] + + x * (aT[13] + + x * (aT[15] + + x * (aT[17] + + x * (aT[19] + x * (aT[21] + x * aT[23]))))))))))); +} +#endif + +long double atanl(long double x) { + union ldshape u = {x}; + long double w, s1, s2, z; + int id; + unsigned e = u.i.se & 0x7fff; + unsigned sign = u.i.se >> 15; + unsigned expman; + + if (e >= 0x3fff + LDBL_MANT_DIG + 1) { /* if |x| is large, atan(x)~=pi/2 */ + if (isnan(x)) return x; + return sign ? -atanhi[3] : atanhi[3]; + } + /* Extract the exponent and the first few bits of the mantissa. */ + expman = EXPMAN(u); + if (expman < ((0x3fff - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ + if (e < 0x3fff - (LDBL_MANT_DIG + 1) / 2) { /* if |x| is small, atanl(x)~=x */ + /* raise underflow if subnormal */ + if (e == 0) FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabsl(x); + if (expman < (0x3fff << 8) + 0x30) { /* |x| < 1.1875 */ + if (expman < ((0x3fff - 1) << 8) + 0x60) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0 * x - 1.0) / (2.0 + x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x - 1.0) / (x + 1.0); + } + } else { + if (expman < ((0x3fff + 1) << 8) + 0x38) { /* |x| < 2.4375 */ + id = 2; + x = (x - 1.5) / (1.0 + 1.5 * x); + } else { /* 2.4375 <= |x| */ + id = 3; + x = -1.0 / x; + } + } + } + /* end of argument reduction */ + z = x * x; + w = z * z; + /* break sum aT[i]z**(i+1) into odd and even poly */ + s1 = z * T_even(w); + s2 = w * T_odd(w); + if (id < 0) return x - x * (s1 + s2); + z = atanhi[id] - ((x * (s1 + s2) - atanlo[id]) - x); + return sign ? -z : z; +} +#endif diff --git a/third_party/ulib/musl/third_party/math/cbrt.c b/third_party/ulib/musl/third_party/math/cbrt.c new file mode 100644 index 000000000..2b879bc65 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/cbrt.c @@ -0,0 +1,102 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +#include +#include + +static const uint32_t B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */ + B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +static const double P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */ + P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */ + P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */ + P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */ + P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +double cbrt(double x) { + union { + double f; + uint64_t i; + } u = {x}; + double_t r, s, t, w; + uint32_t hx = u.i >> 32 & 0x7fffffff; + + if (hx >= 0x7ff00000) /* cbrt(NaN,INF) is itself */ + return x + x; + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if (hx < 0x00100000) { /* zero or subnormal? */ + u.f = x * 0x1p54; + hx = u.i >> 32 & 0x7fffffff; + if (hx == 0) return x; /* cbrt(0) is itself */ + hx = hx / 3 + B2; + } else + hx = hx / 3 + B1; + u.i &= 1ULL << 63; + u.i |= (uint64_t)hx << 32; + t = u.f; + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t * t) * (t / x); + t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + u.f = t; + u.i = (u.i + 0x80000000) & 0xffffffffc0000000ULL; + t = u.f; + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t * t; /* t*t is exact */ + r = x / s; /* error <= 0.5 ulps; |r| < |t| */ + w = t + t; /* t+t is exact */ + r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ + t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ + return t; +} diff --git a/third_party/ulib/musl/third_party/math/cbrtf.c b/third_party/ulib/musl/third_party/math/cbrtf.c new file mode 100644 index 000000000..450e96aa9 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/cbrtf.c @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +#include +#include + +static const unsigned B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +float cbrtf(float x) { + double_t r, T; + union { + float f; + uint32_t i; + } u = {x}; + uint32_t hx = u.i & 0x7fffffff; + + if (hx >= 0x7f800000) /* cbrt(NaN,INF) is itself */ + return x + x; + + /* rough cbrt to 5 bits */ + if (hx < 0x00800000) { /* zero or subnormal? */ + if (hx == 0) return x; /* cbrt(+-0) is itself */ + u.f = x * 0x1p24f; + hx = u.i & 0x7fffffff; + hx = hx / 3 + B2; + } else + hx = hx / 3 + B1; + u.i &= 0x80000000; + u.i |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + T = u.f; + r = T * T * T; + T = T * ((double_t)x + x + r) / (x + r + r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = T * T * T; + T = T * ((double_t)x + x + r) / (x + r + r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + return T; +} diff --git a/third_party/ulib/musl/third_party/math/cbrtl.c b/third_party/ulib/musl/third_party/math/cbrtl.c new file mode 100644 index 000000000..6f3c9ab32 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/cbrtl.c @@ -0,0 +1,123 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtl.c */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cbrtl(long double x) { + return cbrt(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +long double cbrtl(long double x) { + union ldshape u = {x}, v; + union { + float f; + uint32_t i; + } uft; + long double r, s, t, w; + double_t dr, dt, dx; + float_t ft; + int e = u.i.se & 0x7fff; + int sign = u.i.se & 0x8000; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (e == 0x7fff) return x + x; + if (e == 0) { + /* Adjust subnormal numbers. */ + u.f *= 0x1p120; + e = u.i.se & 0x7fff; + /* If x = +-0, then cbrt(x) = +-0. */ + if (e == 0) return x; + e -= 120; + } + e -= 0x3fff; + u.i.se = 0x3fff; + x = u.f; + switch (e % 3) { + case 1: + case -2: + x *= 2; + e--; + break; + case 2: + case -1: + x *= 4; + e -= 2; + break; + } + v.f = 1.0; + v.i.se = sign | (0x3fff + e / 3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + uft.f = x; + uft.i = (uft.i & 0x7fffffff) / 3 + B1; + ft = uft.f; + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + t = dt + (0x1.0p32L + 0x1.0p-31L) - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s = t * t; /* t*t is exact */ + r = x / s; /* error <= 0.5 ulps; |r| < |t| */ + w = t + t; /* t+t is exact */ + r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ + t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.f; + return t; +} +#endif diff --git a/third_party/ulib/musl/third_party/math/cos.c b/third_party/ulib/musl/third_party/math/cos.c new file mode 100644 index 000000000..f2bacf4d9 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/cos.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cosine function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double cos(double x) { + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */ + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0; + } + return __cos(x, 0); + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) return x - x; + + /* argument reduction */ + n = __rem_pio2(x, y); + switch (n & 3) { + case 0: + return __cos(y[0], y[1]); + case 1: + return -__sin(y[0], y[1], 1); + case 2: + return -__cos(y[0], y[1]); + default: + return __sin(y[0], y[1], 1); + } +} diff --git a/third_party/ulib/musl/third_party/math/cosf.c b/third_party/ulib/musl/third_party/math/cosf.c new file mode 100644 index 000000000..7939aae24 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/cosf.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double c1pio2 = 1 * M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + c2pio2 = 2 * M_PI_2, /* 0x400921FB, 0x54442D18 */ + c3pio2 = 3 * M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + c4pio2 = 4 * M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float cosf(float x) { + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } + return __cosdf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__cosdf(sign ? x + c2pio2 : x - c2pio2); + else { + if (sign) + return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); + } + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ + return __cosdf(sign ? x + c4pio2 : x - c4pio2); + else { + if (sign) + return __sindf(-x - c3pio2); + else + return __sindf(x - c3pio2); + } + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n & 3) { + case 0: + return __cosdf(y); + case 1: + return __sindf(-y); + case 2: + return -__cosdf(y); + default: + return __sindf(y); + } +} diff --git a/third_party/ulib/musl/third_party/math/erf.c b/third_party/ulib/musl/third_party/math/erf.c new file mode 100644 index 000000000..5dc22950f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/erf.c @@ -0,0 +1,266 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include "libm.h" + +static const double erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ + /* + * Coefficients for approximation to erf on [0,0.84375] + */ + efx8 = 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ + pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ + pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ + pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ + pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ + pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ + qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ + qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ + qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ + qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ + qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ + /* + * Coefficients for approximation to erf in [0.84375,1.25] + */ + pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ + pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ + pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ + pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ + pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ + pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ + pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ + qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ + qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ + qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ + qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ + qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ + qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ + /* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ + ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ + ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ + ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ + ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ + ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ + ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ + ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ + ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ + sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ + sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ + sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ + sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ + sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ + sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ + sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ + sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ + /* + * Coefficients for approximation to erfc in [1/.35,28] + */ + rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ + rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ + rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ + rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ + rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ + rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ + rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ + sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ + sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ + sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ + sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ + sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ + sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ + sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +static double erfc1(double x) { + double_t s, P, Q; + + s = fabs(x) - 1; + P = pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))); + Q = 1 + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))); + return 1 - erx - P / Q; +} + +static double erfc2(uint32_t ix, double x) { + double_t s, R, S; + double z; + + if (ix < 0x3ff40000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabs(x); + s = 1 / (x * x); + if (ix < 0x4006db6d) { /* |x| < 1/.35 ~ 2.85714 */ + R = ra0 + s * (ra1 + s * (ra2 + s * (ra3 + s * (ra4 + s * (ra5 + s * (ra6 + s * ra7)))))); + S = 1.0 + + s * (sa1 + + s * (sa2 + s * (sa3 + s * (sa4 + s * (sa5 + s * (sa6 + s * (sa7 + s * sa8))))))); + } else { /* |x| > 1/.35 */ + R = rb0 + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * rb6))))); + S = 1.0 + s * (sb1 + s * (sb2 + s * (sb3 + s * (sb4 + s * (sb5 + s * (sb6 + s * sb7)))))); + } + z = x; + SET_LOW_WORD(z, 0); + return exp(-z * z - 0.5625) * exp((z - x) * (z + x) + R / S) / x; +} + +double erf(double x) { + double r, s, z, y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1 - 2 * sign + 1 / x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3e300000) { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125 * (8 * x + efx8 * x); + } + z = x * x; + r = pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))); + s = 1.0 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))); + y = r / s; + return x + x * y; + } + if (ix < 0x40180000) /* 0.84375 <= |x| < 6 */ + y = 1 - erfc2(ix, x); + else + y = 1 - 0x1p-1022; + return sign ? -y : y; +} + +double erfc(double x) { + double r, s, z, y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2 * sign + 1 / x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3c700000) /* |x| < 2**-56 */ + return 1.0 - x; + z = x * x; + r = pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))); + s = 1.0 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))); + y = r / s; + if (sign || ix < 0x3fd00000) { /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if (ix < 0x403c0000) { /* 0.84375 <= |x| < 28 */ + return sign ? 2 - erfc2(ix, x) : erfc2(ix, x); + } + return sign ? 2 - 0x1p-1022 : 0x1p-1022 * 0x1p-1022; +} diff --git a/third_party/ulib/musl/third_party/math/erff.c b/third_party/ulib/musl/third_party/math/erff.c new file mode 100644 index 000000000..676e7aff2 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/erff.c @@ -0,0 +1,176 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float erx = 8.4506291151e-01, /* 0x3f58560b */ + /* + * Coefficients for approximation to erf on [0,0.84375] + */ + efx8 = 1.0270333290e+00, /* 0x3f8375d4 */ + pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ + pp1 = -3.2504209876e-01, /* 0xbea66beb */ + pp2 = -2.8481749818e-02, /* 0xbce9528f */ + pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ + pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ + qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ + qq2 = 6.5022252500e-02, /* 0x3d852a63 */ + qq3 = 5.0813062117e-03, /* 0x3ba68116 */ + qq4 = 1.3249473704e-04, /* 0x390aee49 */ + qq5 = -3.9602282413e-06, /* 0xb684e21a */ + /* + * Coefficients for approximation to erf in [0.84375,1.25] + */ + pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ + pa1 = 4.1485610604e-01, /* 0x3ed46805 */ + pa2 = -3.7220788002e-01, /* 0xbebe9208 */ + pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ + pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ + pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ + pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ + qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ + qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ + qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ + qa4 = 1.2617121637e-01, /* 0x3e013307 */ + qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ + qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ + /* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ + ra0 = -9.8649440333e-03, /* 0xbc21a093 */ + ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ + ra2 = -1.0558626175e+01, /* 0xc128f022 */ + ra3 = -6.2375331879e+01, /* 0xc2798057 */ + ra4 = -1.6239666748e+02, /* 0xc322658c */ + ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ + ra6 = -8.1287437439e+01, /* 0xc2a2932b */ + ra7 = -9.8143291473e+00, /* 0xc11d077e */ + sa1 = 1.9651271820e+01, /* 0x419d35ce */ + sa2 = 1.3765776062e+02, /* 0x4309a863 */ + sa3 = 4.3456588745e+02, /* 0x43d9486f */ + sa4 = 6.4538726807e+02, /* 0x442158c9 */ + sa5 = 4.2900814819e+02, /* 0x43d6810b */ + sa6 = 1.0863500214e+02, /* 0x42d9451f */ + sa7 = 6.5702495575e+00, /* 0x40d23f7c */ + sa8 = -6.0424413532e-02, /* 0xbd777f97 */ + /* + * Coefficients for approximation to erfc in [1/.35,28] + */ + rb0 = -9.8649431020e-03, /* 0xbc21a092 */ + rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ + rb2 = -1.7757955551e+01, /* 0xc18e104b */ + rb3 = -1.6063638306e+02, /* 0xc320a2ea */ + rb4 = -6.3756646729e+02, /* 0xc41f6441 */ + rb5 = -1.0250950928e+03, /* 0xc480230b */ + rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ + sb1 = 3.0338060379e+01, /* 0x41f2b459 */ + sb2 = 3.2579251099e+02, /* 0x43a2e571 */ + sb3 = 1.5367296143e+03, /* 0x44c01759 */ + sb4 = 3.1998581543e+03, /* 0x4547fdbb */ + sb5 = 2.5530502930e+03, /* 0x451f90ce */ + sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ + sb7 = -2.2440952301e+01; /* 0xc1b38712 */ + +static float erfc1(float x) { + float_t s, P, Q; + + s = fabsf(x) - 1; + P = pa0 + s * (pa1 + s * (pa2 + s * (pa3 + s * (pa4 + s * (pa5 + s * pa6))))); + Q = 1 + s * (qa1 + s * (qa2 + s * (qa3 + s * (qa4 + s * (qa5 + s * qa6))))); + return 1 - erx - P / Q; +} + +static float erfc2(uint32_t ix, float x) { + float_t s, R, S; + float z; + + if (ix < 0x3fa00000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabsf(x); + s = 1 / (x * x); + if (ix < 0x4036db6d) { /* |x| < 1/0.35 */ + R = ra0 + s * (ra1 + s * (ra2 + s * (ra3 + s * (ra4 + s * (ra5 + s * (ra6 + s * ra7)))))); + S = 1.0f + + s * (sa1 + + s * (sa2 + s * (sa3 + s * (sa4 + s * (sa5 + s * (sa6 + s * (sa7 + s * sa8))))))); + } else { /* |x| >= 1/0.35 */ + R = rb0 + s * (rb1 + s * (rb2 + s * (rb3 + s * (rb4 + s * (rb5 + s * rb6))))); + S = 1.0f + s * (sb1 + s * (sb2 + s * (sb3 + s * (sb4 + s * (sb5 + s * (sb6 + s * sb7)))))); + } + GET_FLOAT_WORD(ix, x); + SET_FLOAT_WORD(z, ix & 0xffffe000); + return expf(-z * z - 0.5625f) * expf((z - x) * (z + x) + R / S) / x; +} + +float erff(float x) { + float r, s, z, y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1 - 2 * sign + 1 / x; + } + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x31800000) { /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125f * (8 * x + efx8 * x); + } + z = x * x; + r = pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))); + s = 1 + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))); + y = r / s; + return x + x * y; + } + if (ix < 0x40c00000) /* |x| < 6 */ + y = 1 - erfc2(ix, x); + else + y = 1 - 0x1p-120f; + return sign ? -y : y; +} + +float erfcf(float x) { + float r, s, z, y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2 * sign + 1 / x; + } + + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x23800000) /* |x| < 2**-56 */ + return 1.0f - x; + z = x * x; + r = pp0 + z * (pp1 + z * (pp2 + z * (pp3 + z * pp4))); + s = 1.0f + z * (qq1 + z * (qq2 + z * (qq3 + z * (qq4 + z * qq5)))); + y = r / s; + if (sign || ix < 0x3e800000) /* x < 1/4 */ + return 1.0f - (x + x * y); + return 0.5f - (x - 0.5f + x * y); + } + if (ix < 0x41e00000) { /* |x| < 28 */ + return sign ? 2 - erfc2(ix, x) : erfc2(ix, x); + } + return sign ? 2 - 0x1p-120f : 0x1p-120f * 0x1p-120f; +} diff --git a/third_party/ulib/musl/third_party/math/erfl.c b/third_party/ulib/musl/third_party/math/erfl.c new file mode 100644 index 000000000..31867cf68 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/erfl.c @@ -0,0 +1,353 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_erfl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1(z)/S1(z)) + * z=1/x^2 + * erf(x) = 1 - erfc(x) + * + * 4. For x in [1/0.35,107] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2(z)/S2(z)) + * if -6.666 x >= 107 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double erfl(long double x) { + return erf(x); +} +long double erfcl(long double x) { + return erfc(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double erx = 0.845062911510467529296875L, + + /* + * Coefficients for approximation to erf on [0,0.84375] + */ + /* 8 * (2/sqrt(pi) - 1) */ + efx8 = 1.0270333367641005911692712249723613735048E0L, + pp[6] = + { + 1.122751350964552113068262337278335028553E6L, + -2.808533301997696164408397079650699163276E6L, + -3.314325479115357458197119660818768924100E5L, + -6.848684465326256109712135497895525446398E4L, + -2.657817695110739185591505062971929859314E3L, + -1.655310302737837556654146291646499062882E2L, +}, + qq[6] = + { + 8.745588372054466262548908189000448124232E6L, + 3.746038264792471129367533128637019611485E6L, + 7.066358783162407559861156173539693900031E5L, + 7.448928604824620999413120955705448117056E4L, + 4.511583986730994111992253980546131408924E3L, + 1.368902937933296323345610240009071254014E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + + /* + * Coefficients for approximation to erf in [0.84375,1.25] + */ + /* erf(x+1) = 0.845062911510467529296875 + pa(x)/qa(x) + -0.15625 <= x <= +.25 + Peak relative error 8.5e-22 */ + pa[8] = + { + -1.076952146179812072156734957705102256059E0L, + 1.884814957770385593365179835059971587220E2L, + -5.339153975012804282890066622962070115606E1L, + 4.435910679869176625928504532109635632618E1L, + 1.683219516032328828278557309642929135179E1L, + -2.360236618396952560064259585299045804293E0L, + 1.852230047861891953244413872297940938041E0L, + 9.394994446747752308256773044667843200719E-2L, +}, + qa[7] = + { + 4.559263722294508998149925774781887811255E2L, + 3.289248982200800575749795055149780689738E2L, + 2.846070965875643009598627918383314457912E2L, + 1.398715859064535039433275722017479994465E2L, + 6.060190733759793706299079050985358190726E1L, + 2.078695677795422351040502569964299664233E1L, + 4.641271134150895940966798357442234498546E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + + /* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ + /* erfc(1/x) = x exp (-1/x^2 - 0.5625 + ra(x^2)/sa(x^2)) + 1/2.85711669921875 < 1/x < 1/1.25 + Peak relative error 3.1e-21 */ + ra[] = + { + 1.363566591833846324191000679620738857234E-1L, + 1.018203167219873573808450274314658434507E1L, + 1.862359362334248675526472871224778045594E2L, + 1.411622588180721285284945138667933330348E3L, + 5.088538459741511988784440103218342840478E3L, + 8.928251553922176506858267311750789273656E3L, + 7.264436000148052545243018622742770549982E3L, + 2.387492459664548651671894725748959751119E3L, + 2.220916652813908085449221282808458466556E2L, +}, + sa[] = + { + -1.382234625202480685182526402169222331847E1L, + -3.315638835627950255832519203687435946482E2L, + -2.949124863912936259747237164260785326692E3L, + -1.246622099070875940506391433635999693661E4L, + -2.673079795851665428695842853070996219632E4L, + -2.880269786660559337358397106518918220991E4L, + -1.450600228493968044773354186390390823713E4L, + -2.874539731125893533960680525192064277816E3L, + -1.402241261419067750237395034116942296027E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + + /* + * Coefficients for approximation to erfc in [1/.35,107] + */ + /* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rb(x^2)/sb(x^2)) + 1/6.6666259765625 < 1/x < 1/2.85711669921875 + Peak relative error 4.2e-22 */ + rb[] = + { + -4.869587348270494309550558460786501252369E-5L, + -4.030199390527997378549161722412466959403E-3L, + -9.434425866377037610206443566288917589122E-2L, + -9.319032754357658601200655161585539404155E-1L, + -4.273788174307459947350256581445442062291E0L, + -8.842289940696150508373541814064198259278E0L, + -7.069215249419887403187988144752613025255E0L, + -1.401228723639514787920274427443330704764E0L, +}, + sb[] = + { + 4.936254964107175160157544545879293019085E-3L, + 1.583457624037795744377163924895349412015E-1L, + 1.850647991850328356622940552450636420484E0L, + 9.927611557279019463768050710008450625415E0L, + 2.531667257649436709617165336779212114570E1L, + 2.869752886406743386458304052862814690045E1L, + 1.182059497870819562441683560749192539345E1L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + /* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rc(x^2)/sc(x^2)) + 1/107 <= 1/x <= 1/6.6666259765625 + Peak relative error 1.1e-21 */ + rc[] = + { + -8.299617545269701963973537248996670806850E-5L, + -6.243845685115818513578933902532056244108E-3L, + -1.141667210620380223113693474478394397230E-1L, + -7.521343797212024245375240432734425789409E-1L, + -1.765321928311155824664963633786967602934E0L, + -1.029403473103215800456761180695263439188E0L, +}, + sc[] = { + 8.413244363014929493035952542677768808601E-3L, + 2.065114333816877479753334599639158060979E-1L, + 1.639064941530797583766364412782135680148E0L, + 4.936788463787115555582319302981666347450E0L, + 5.005177727208955487404729933261347679090E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}; + +static long double erfc1(long double x) { + long double s, P, Q; + + s = fabsl(x) - 1; + P = pa[0] + + s * (pa[1] + + s * (pa[2] + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7])))))); + Q = qa[0] + + s * (qa[1] + s * (qa[2] + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s)))))); + return 1 - erx - P / Q; +} + +static long double erfc2(uint32_t ix, long double x) { + union ldshape u; + long double s, z, R, S; + + if (ix < 0x3fffa000) /* 0.84375 <= |x| < 1.25 */ + return erfc1(x); + + x = fabsl(x); + s = 1 / (x * x); + if (ix < 0x4000b6db) { /* 1.25 <= |x| < 2.857 ~ 1/.35 */ + R = ra[0] + + s * (ra[1] + + s * (ra[2] + + s * (ra[3] + + s * (ra[4] + s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8]))))))); + S = sa[0] + + s * (sa[1] + + s * (sa[2] + + s * (sa[3] + + s * (sa[4] + + s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s)))))))); + } else if (ix < 0x4001d555) { /* 2.857 <= |x| < 6.6666259765625 */ + R = rb[0] + + s * (rb[1] + + s * (rb[2] + s * (rb[3] + s * (rb[4] + s * (rb[5] + s * (rb[6] + s * rb[7])))))); + S = sb[0] + + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] + s * (sb[5] + s * (sb[6] + s)))))); + } else { /* 6.666 <= |x| < 107 (erfc only) */ + R = rc[0] + s * (rc[1] + s * (rc[2] + s * (rc[3] + s * (rc[4] + s * rc[5])))); + S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] + s * (sc[4] + s)))); + } + u.f = x; + u.i.m &= -1ULL << 40; + z = u.f; + return expl(-z * z - 0.5625) * expl((z - x) * (z + x) + R / S) / x; +} + +long double erfl(long double x) { + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU) << 16 | u.i.m >> 48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1 - 2 * sign + 1 / x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fde8000) { /* |x| < 2**-33 */ + return 0.125 * (8 * x + efx8 * x); /* avoid underflow */ + } + z = x * x; + r = pp[0] + z * (pp[1] + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + return x + x * y; + } + if (ix < 0x4001d555) /* |x| < 6.6666259765625 */ + y = 1 - erfc2(ix, x); + else + y = 1 - 0x1p-16382L; + return sign ? -y : y; +} + +long double erfcl(long double x) { + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU) << 16 | u.i.m >> 48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) /* erfc(nan) = nan, erfc(+-inf) = 0,2 */ + return 2 * sign + 1 / x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fbe0000) /* |x| < 2**-65 */ + return 1.0 - x; + z = x * x; + r = pp[0] + z * (pp[1] + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + if (ix < 0x3ffd8000) /* x < 1/4 */ + return 1.0 - (x + x * y); + return 0.5 - (x - 0.5 + x * y); + } + if (ix < 0x4005d600) /* |x| < 107 */ + return sign ? 2 - erfc2(ix, x) : erfc2(ix, x); + y = 0x1p-16382L; + return sign ? 2 - y : y * y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double erfl(long double x) { + return erf(x); +} +long double erfcl(long double x) { + return erfc(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/exp.c b/third_party/ulib/musl/third_party/math/exp.c new file mode 100644 index 000000000..3d7f93cee --- /dev/null +++ b/third_party/ulib/musl/third_party/math/exp.c @@ -0,0 +1,129 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +#include "libm.h" + +static const double half[2] = {0.5, -0.5}, + ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ + P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ + P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ + P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ + P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ + P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +double exp(double x) { + double_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + sign = hx >> 31; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ + if (isnan(x)) return x; + if (x > 709.782712893383973096) { + /* overflow if x!=inf */ + x *= 0x1p1023; + return x; + } + if (x < -708.39641853226410622) { + /* underflow if x!=-inf */ + FORCE_EVAL((float)(-0x1p-149 / x)); + if (x < -745.13321910194110842) return 0; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ + k = (int)(invln2 * x + half[sign]); + else + k = 1 - sign - sign; + hi = x - k * ln2hi; /* k*ln2hi is exact here */ + lo = k * ln2lo; + x = hi - lo; + } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0; + } else { + /* inexact if x!=0 */ + FORCE_EVAL(0x1p1023 + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + y = 1 + (x * c / (2 - c) - lo + hi); + if (k == 0) return y; + return scalbn(y, k); +} diff --git a/third_party/ulib/musl/third_party/math/exp2.c b/third_party/ulib/musl/third_party/math/exp2.c new file mode 100644 index 000000000..78a5b7f46 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/exp2.c @@ -0,0 +1,246 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#define TBLSIZE 256 + +static const double redux = 0x1.8p52 / TBLSIZE, P1 = 0x1.62e42fefa39efp-1, + P2 = 0x1.ebfbdff82c575p-3, P3 = 0x1.c6b08d704a0a6p-5, P4 = 0x1.3b2ab88f70400p-7, + P5 = 0x1.5d88003875c74p-10; + +static const double tbl[TBLSIZE * 2] = { + /* exp2(z + eps) eps */ + 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, 0x1.6b052fa751744p-1, 0x1.8000p-50, + 0x1.6c012750bd9fep-1, -0x1.8780p-45, 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, + 0x1.6dfb23c651a29p-1, -0x1.8000p-50, 0x1.6ef9298593ae3p-1, -0x1.c000p-52, + 0x1.6ff7df9519386p-1, -0x1.fd80p-45, 0x1.70f7466f42da3p-1, -0x1.c880p-45, + 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, 0x1.72f8286eacf05p-1, -0x1.8300p-44, + 0x1.73f9a48a58152p-1, -0x1.0c00p-47, 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, + 0x1.75feb564267f1p-1, 0x1.3e00p-47, 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, + 0x1.780694fde5d38p-1, -0x1.d000p-50, 0x1.790b938ac1d00p-1, 0x1.3000p-49, + 0x1.7a11473eb0178p-1, -0x1.d000p-49, 0x1.7b17b0976d060p-1, 0x1.0400p-45, + 0x1.7c1ed0130c133p-1, 0x1.0000p-53, 0x1.7d26a62ff8636p-1, -0x1.6900p-45, + 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, 0x1.7f3878491c3e8p-1, -0x1.4580p-45, + 0x1.80427543e1b4ep-1, 0x1.3000p-44, 0x1.814d2add1071ap-1, 0x1.f000p-47, + 0x1.82589994ccd7ep-1, -0x1.1c00p-45, 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, + 0x1.8471a4623cab5p-1, 0x1.7100p-43, 0x1.857f4179f5bbcp-1, 0x1.2600p-45, + 0x1.868d99b4491afp-1, -0x1.2c40p-44, 0x1.879cad931a395p-1, -0x1.3000p-45, + 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, 0x1.89bd0a4785800p-1, -0x1.d000p-49, + 0x1.8ace5422aa223p-1, 0x1.3280p-44, 0x1.8be05bad619fap-1, 0x1.2b40p-43, + 0x1.8cf3216b54383p-1, -0x1.ed00p-45, 0x1.8e06a5e08664cp-1, -0x1.0500p-45, + 0x1.8f1ae99157807p-1, 0x1.8280p-45, 0x1.902fed0282c0ep-1, -0x1.cb00p-46, + 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, 0x1.925c353aa2ff9p-1, 0x1.5400p-48, + 0x1.93737b0cdc64ap-1, 0x1.7200p-46, 0x1.948b82b5f98aep-1, -0x1.9000p-47, + 0x1.95a44cbc852cbp-1, 0x1.5680p-45, 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, + 0x1.97d829fde4e2ap-1, -0x1.1000p-47, 0x1.98f33e47a23a3p-1, 0x1.d000p-45, + 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, + 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, 0x1.9d674194bb8c5p-1, -0x1.c000p-49, + 0x1.9e86319e3238ep-1, 0x1.7d00p-46, 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, + 0x1.a0c667b5de54dp-1, -0x1.5000p-48, 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, + 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, 0x1.a42c980460a5dp-1, -0x1.af00p-46, + 0x1.a5503b23e259bp-1, 0x1.b600p-47, 0x1.a674a8af46213p-1, 0x1.8880p-44, + 0x1.a799e1330b3a7p-1, 0x1.1200p-46, 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, + 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, 0x1.ab0e521356fb8p-1, 0x1.b700p-45, + 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, + 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, 0x1.afb4ce622f367p-1, 0x1.6500p-46, + 0x1.b0e07298db790p-1, 0x1.fd40p-45, 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, + 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, 0x1.b468415b747e7p-1, -0x1.8380p-44, + 0x1.b59728de5593ap-1, 0x1.8000p-54, 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, + 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, 0x1.b928cf22749b2p-1, -0x1.4c00p-47, + 0x1.ba5b030a10603p-1, -0x1.d700p-47, 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, + 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, + 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, 0x1.c06286141b2e9p-1, -0x1.1400p-46, + 0x1.c199bdd8552e0p-1, 0x1.be00p-47, 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, + 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, 0x1.c544778fafd15p-1, 0x1.9660p-44, + 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, + 0x1.c8f6d9406e733p-1, -0x1.a480p-46, 0x1.ca3405751c4dfp-1, 0x1.b000p-51, + 0x1.cb720dcef9094p-1, 0x1.1400p-47, 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, + 0x1.cdf0b555dc412p-1, 0x1.3600p-48, 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, + 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, + 0x1.d2f87080d8a85p-1, 0x1.d280p-46, 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, + 0x1.d5818dcfba491p-1, 0x1.f000p-50, 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, + 0x1.d80e316c9834ep-1, -0x1.cd80p-47, 0x1.d955d71ff6090p-1, 0x1.4c00p-48, + 0x1.da9e603db32aep-1, 0x1.f900p-48, 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, + 0x1.dd321f301b445p-1, -0x1.5200p-48, 0x1.de7d5641c05bfp-1, -0x1.d700p-46, + 0x1.dfc97337b9aecp-1, -0x1.6140p-46, 0x1.e11676b197d5ep-1, 0x1.b480p-47, + 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, + 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, 0x1.e653924676d68p-1, -0x1.5000p-49, + 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, 0x1.e8f7977cdb726p-1, -0x1.3700p-48, + 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, + 0x1.ecf482d8e680dp-1, 0x1.5500p-48, 0x1.ee4aaa2188514p-1, 0x1.6400p-51, + 0x1.efa1bee615a13p-1, -0x1.e800p-49, 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, + 0x1.f252b376bb963p-1, -0x1.c900p-45, 0x1.f3ac948dd7275p-1, 0x1.a000p-53, + 0x1.f50765b6e4524p-1, -0x1.4f00p-48, 0x1.f6632798844fdp-1, 0x1.a800p-51, + 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, 0x1.f91d802243c82p-1, -0x1.4600p-50, + 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, 0x1.fbdba3692d511p-1, -0x1.0e00p-51, + 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, + 0x1.0000000000000p+0, 0x0.0000p+0, 0x1.00b1afa5abcbep+0, -0x1.3400p-52, + 0x1.0163da9fb3303p+0, -0x1.2170p-46, 0x1.02168143b0282p+0, 0x1.a400p-52, + 0x1.02c9a3e77806cp+0, 0x1.f980p-49, 0x1.037d42e11bbcap+0, -0x1.7400p-51, + 0x1.04315e86e7f89p+0, 0x1.8300p-50, 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, + 0x1.059b0d315855ap+0, -0x1.2840p-47, 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, + 0x1.0706b29ddf71ap+0, 0x1.5240p-46, 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, + 0x1.0874518759bd0p+0, 0x1.6400p-49, 0x1.092bdf66607c8p+0, -0x1.0780p-47, + 0x1.09e3ecac6f383p+0, -0x1.8000p-54, 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, + 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, + 0x1.0cc922b724816p+0, 0x1.5200p-47, 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, + 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, + 0x1.0fb66affed2f0p+0, -0x1.d300p-47, 0x1.1073028d7234bp+0, 0x1.1500p-48, + 0x1.11301d0125b5bp+0, 0x1.c000p-49, 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, + 0x1.12abdc06c31d5p+0, 0x1.8400p-49, 0x1.136a814f2047dp+0, -0x1.ed00p-47, + 0x1.1429aaea92de9p+0, 0x1.8e00p-49, 0x1.14e95934f3138p+0, 0x1.b400p-49, + 0x1.15a98c8a58e71p+0, 0x1.5300p-47, 0x1.166a45471c3dfp+0, 0x1.3380p-47, + 0x1.172b83c7d5211p+0, 0x1.8d40p-45, 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, + 0x1.18af9388c8d93p+0, -0x1.c880p-46, 0x1.1972658375d66p+0, 0x1.1f00p-46, + 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, 0x1.1af99f81387e3p+0, -0x1.7390p-43, + 0x1.1bbe084045d54p+0, 0x1.4e40p-45, 0x1.1c82f95281c43p+0, -0x1.a200p-47, + 0x1.1d4873168b9b2p+0, 0x1.3800p-49, 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, + 0x1.1ed5022fcd938p+0, 0x1.1900p-47, 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, + 0x1.2063b88628d8fp+0, 0x1.d940p-45, 0x1.212be3578a81ep+0, 0x1.8000p-50, + 0x1.21f49917ddd41p+0, 0x1.b340p-45, 0x1.22bdda2791323p+0, 0x1.9f80p-46, + 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, 0x1.2451ffb821427p+0, 0x1.2300p-47, + 0x1.251ce4fb2a602p+0, -0x1.3480p-46, 0x1.25e85711eceb0p+0, 0x1.2700p-46, + 0x1.26b4565e27d16p+0, 0x1.1d00p-46, 0x1.2780e341de00fp+0, 0x1.1ee0p-44, + 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, 0x1.291ba7591bb30p+0, -0x1.3d80p-46, + 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, + 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, 0x1.2c57e39771af9p+0, -0x1.0800p-46, + 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, 0x1.2df961f641579p+0, -0x1.4200p-48, + 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, 0x1.2f9d24abd8822p+0, -0x1.6300p-46, + 0x1.306fe0a31b625p+0, -0x1.2360p-44, 0x1.31432edeea50bp+0, -0x1.0df8p-40, + 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, + 0x1.33c08b2641766p+0, 0x1.ed00p-46, 0x1.3496266e3fa27p+0, -0x1.c000p-50, + 0x1.356c55f929f0fp+0, -0x1.0d80p-44, 0x1.36431a2de88b9p+0, 0x1.2c80p-45, + 0x1.371a7373aaa39p+0, 0x1.0600p-45, 0x1.37f26231e74fep+0, -0x1.6600p-46, + 0x1.38cae6d05d838p+0, -0x1.ae00p-47, 0x1.39a401b713ec3p+0, -0x1.4720p-43, + 0x1.3a7db34e5a020p+0, 0x1.8200p-47, 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, + 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, 0x1.3d0e544ede122p+0, -0x1.7a00p-46, + 0x1.3dea64c1234bbp+0, 0x1.6300p-45, 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, + 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, 0x1.40822c367a0bbp+0, 0x1.5b80p-45, + 0x1.4160a21f72e95p+0, 0x1.ec00p-46, 0x1.423fb27094646p+0, -0x1.3600p-46, + 0x1.431f5d950a920p+0, 0x1.3980p-45, 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, + 0x1.44e0860618919p+0, -0x1.6c00p-48, 0x1.45c2042a7d201p+0, -0x1.bc00p-47, + 0x1.46a41ed1d0016p+0, -0x1.2800p-46, 0x1.4786d668b3326p+0, 0x1.0e00p-44, + 0x1.486a2b5c13c00p+0, -0x1.d400p-45, 0x1.494e1e192af04p+0, 0x1.c200p-47, + 0x1.4a32af0d7d372p+0, -0x1.e500p-46, 0x1.4b17dea6db801p+0, 0x1.7800p-47, + 0x1.4bfdad53629e1p+0, -0x1.3800p-46, 0x1.4ce41b817c132p+0, 0x1.0800p-47, + 0x1.4dcb299fddddbp+0, 0x1.c700p-45, 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, + 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, 0x1.508417f4531c1p+0, -0x1.8c00p-47, + 0x1.516daa2cf662ap+0, -0x1.a000p-48, 0x1.5257de83f51eap+0, 0x1.a080p-43, + 0x1.5342b569d4edap+0, -0x1.6d80p-45, 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, + 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, 0x1.56070dde9116bp+0, 0x1.4b00p-45, + 0x1.56f4736b529dep+0, 0x1.15a0p-43, 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, + 0x1.58d12d497c76fp+0, -0x1.3080p-45, 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, + 0x1.5ab07dd485427p+0, -0x1.4000p-51, 0x1.5ba11fba87af4p+0, 0x1.0080p-44, + 0x1.5c9268a59460bp+0, -0x1.6c80p-45, 0x1.5d84590998e3fp+0, 0x1.69a0p-43, + 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, 0x1.5f6a320dcebcap+0, 0x1.7700p-46, + 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, 0x1.6152ae6cdf715p+0, 0x1.1000p-47, + 0x1.6247eb03a5531p+0, -0x1.5d00p-46, 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, + 0x1.6434634ccc313p+0, -0x1.a800p-49, 0x1.652b9febc8efap+0, -0x1.8600p-45, + 0x1.6623882553397p+0, 0x1.1fe0p-40, 0x1.671c1c708328ep+0, -0x1.7200p-44, + 0x1.68155d44ca97ep+0, 0x1.6800p-49, 0x1.690f4b19e9471p+0, -0x1.9780p-45, +}; + +/* + * exp2(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.503 ulp for normalized results. + * + * Method: (accurate tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-64. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are + * virtual tables, interleaved in the real table tbl[]. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +double exp2(double x) { + double_t r, t, z; + uint32_t ix, i0; + union { + double f; + uint64_t i; + } u = {x}; + union { + uint32_t u; + int32_t i; + } k; + + /* Filter out exceptional cases. */ + ix = u.i >> 32 & 0x7fffffff; + if (ix >= 0x408ff000) { /* |x| >= 1022 or nan */ + if (ix >= 0x40900000 && u.i >> 63 == 0) { /* x >= 1024 or nan */ + /* overflow */ + x *= 0x1p1023; + return x; + } + if (ix >= 0x7ff00000) /* -inf or -nan */ + return -1 / x; + if (u.i >> 63) { /* x <= -1022 */ + /* underflow */ + if (x <= -1075 || x - 0x1p52 + 0x1p52 != x) FORCE_EVAL((float)(-0x1p-149 / x)); + if (x <= -1075) return 0; + } + } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[2 * i0]; /* exp2t[i0] */ + z -= tbl[2 * i0 + 1]; /* eps[i0] */ + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); + + return scalbn(r, k.i); +} diff --git a/third_party/ulib/musl/third_party/math/exp2f.c b/third_party/ulib/musl/third_party/math/exp2f.c new file mode 100644 index 000000000..850575de7 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/exp2f.c @@ -0,0 +1,114 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c */ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#define TBLSIZE 16 + +static const float redux = 0x1.8p23f / TBLSIZE, P1 = 0x1.62e430p-1f, P2 = 0x1.ebfbe0p-3f, + P3 = 0x1.c6b348p-5f, P4 = 0x1.3b2c9cp-7f; + +static const double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, 0x1.7a11473eb0187p-1, 0x1.8ace5422aa0dbp-1, 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, 0x1.c199bdd85529cp-1, 0x1.d5818dcfba487p-1, 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, 0x1.0b5586cf9890fp+0, 0x1.172b83c7d517bp+0, 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, 0x1.3dea64c123422p+0, 0x1.4bfdad5362a27p+0, 0x1.5ab07dd485429p+0, +}; + +/* + * exp2f(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2f(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLSIZE+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. + * Using double precision for everything except the reduction makes + * roundoff error insignificant and simplifies the scaling step. + * + * This method is due to Tang, but I do not use his suggested parameters: + * + * Tang, P. Table-driven Implementation of the Exponential Function + * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + */ +float exp2f(float x) { + double_t t, r, z; + union { + float f; + uint32_t i; + } u = {x}; + union { + double f; + uint64_t i; + } uk; + uint32_t ix, i0, k; + + /* Filter out exceptional cases. */ + ix = u.i & 0x7fffffff; + if (ix > 0x42fc0000) { /* |x| > 126 */ + if (ix > 0x7f800000) /* NaN */ + return x; + if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ + x *= 0x1p127f; + return x; + } + if (u.i >= 0x80000000) { /* x < -126 */ + if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) FORCE_EVAL(-0x1p-149f / x); + if (u.i >= 0xc3160000) /* x <= -150 */ + return 0; + } + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return 1.0f + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k = i0 / TBLSIZE; + uk.i = (uint64_t)(0x3ff + k) << 52; + i0 &= TBLSIZE - 1; + u.f -= redux; + z = x - u.f; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + r = exp2ft[i0]; + t = r * z; + r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); + + /* Scale by 2**k */ + return r * uk.f; +} diff --git a/third_party/ulib/musl/third_party/math/exp2l.c b/third_party/ulib/musl/third_party/math/exp2l.c new file mode 100644 index 000000000..d26151a03 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/exp2l.c @@ -0,0 +1,567 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c and /usr/src/lib/msun/ld128/s_exp2l.c */ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp2l(long double x) { + return exp2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const double redux = 0x1.8p63 / TBLSIZE, P1 = 0x1.62e42fefa39efp-1, + P2 = 0x1.ebfbdff82c58fp-3, P3 = 0x1.c6b08d7049fap-5, P4 = 0x1.3b2ab6fba4da5p-7, + P5 = 0x1.5d8804780a736p-10, P6 = 0x1.430918835e33dp-13; + +static const double tbl[TBLSIZE * 2] = { + 0x1.6a09e667f3bcdp-1, + -0x1.bdd3413b2648p-55, + 0x1.6c012750bdabfp-1, + -0x1.2895667ff0cp-57, + 0x1.6dfb23c651a2fp-1, + -0x1.bbe3a683c88p-58, + 0x1.6ff7df9519484p-1, + -0x1.83c0f25860fp-56, + 0x1.71f75e8ec5f74p-1, + -0x1.16e4786887bp-56, + 0x1.73f9a48a58174p-1, + -0x1.0a8d96c65d5p-55, + 0x1.75feb564267c9p-1, + -0x1.0245957316ep-55, + 0x1.780694fde5d3fp-1, + 0x1.866b80a0216p-55, + 0x1.7a11473eb0187p-1, + -0x1.41577ee0499p-56, + 0x1.7c1ed0130c132p-1, + 0x1.f124cd1164ep-55, + 0x1.7e2f336cf4e62p-1, + 0x1.05d02ba157ap-57, + 0x1.80427543e1a12p-1, + -0x1.27c86626d97p-55, + 0x1.82589994cce13p-1, + -0x1.d4c1dd41533p-55, + 0x1.8471a4623c7adp-1, + -0x1.8d684a341cep-56, + 0x1.868d99b4492edp-1, + -0x1.fc6f89bd4f68p-55, + 0x1.88ac7d98a6699p-1, + 0x1.994c2f37cb5p-55, + 0x1.8ace5422aa0dbp-1, + 0x1.6e9f156864bp-55, + 0x1.8cf3216b5448cp-1, + -0x1.0d55e32e9e4p-57, + 0x1.8f1ae99157736p-1, + 0x1.5cc13a2e397p-56, + 0x1.9145b0b91ffc6p-1, + -0x1.dd6792e5825p-55, + 0x1.93737b0cdc5e5p-1, + -0x1.75fc781b58p-58, + 0x1.95a44cbc8520fp-1, + -0x1.64b7c96a5fp-57, + 0x1.97d829fde4e5p-1, + -0x1.d185b7c1b86p-55, + 0x1.9a0f170ca07bap-1, + -0x1.173bd91cee6p-55, + 0x1.9c49182a3f09p-1, + 0x1.c7c46b071f2p-57, + 0x1.9e86319e32323p-1, + 0x1.824ca78e64cp-57, + 0x1.a0c667b5de565p-1, + -0x1.359495d1cd5p-55, + 0x1.a309bec4a2d33p-1, + 0x1.6305c7ddc368p-55, + 0x1.a5503b23e255dp-1, + -0x1.d2f6edb8d42p-55, + 0x1.a799e1330b358p-1, + 0x1.bcb7ecac564p-55, + 0x1.a9e6b5579fdbfp-1, + 0x1.0fac90ef7fdp-55, + 0x1.ac36bbfd3f37ap-1, + -0x1.f9234cae76dp-56, + 0x1.ae89f995ad3adp-1, + 0x1.7a1cd345dcc8p-55, + 0x1.b0e07298db666p-1, + -0x1.bdef54c80e4p-55, + 0x1.b33a2b84f15fbp-1, + -0x1.2805e3084d8p-58, + 0x1.b59728de5593ap-1, + -0x1.c71dfbbba6ep-55, + 0x1.b7f76f2fb5e47p-1, + -0x1.5584f7e54acp-57, + 0x1.ba5b030a1064ap-1, + -0x1.efcd30e5429p-55, + 0x1.bcc1e904bc1d2p-1, + 0x1.23dd07a2d9fp-56, + 0x1.bf2c25bd71e09p-1, + -0x1.efdca3f6b9c8p-55, + 0x1.c199bdd85529cp-1, + 0x1.11065895049p-56, + 0x1.c40ab5fffd07ap-1, + 0x1.b4537e083c6p-55, + 0x1.c67f12e57d14bp-1, + 0x1.2884dff483c8p-55, + 0x1.c8f6d9406e7b5p-1, + 0x1.1acbc48805cp-57, + 0x1.cb720dcef9069p-1, + 0x1.503cbd1e94ap-57, + 0x1.cdf0b555dc3fap-1, + -0x1.dd83b53829dp-56, + 0x1.d072d4a07897cp-1, + -0x1.cbc3743797a8p-55, + 0x1.d2f87080d89f2p-1, + -0x1.d487b719d858p-55, + 0x1.d5818dcfba487p-1, + 0x1.2ed02d75b37p-56, + 0x1.d80e316c98398p-1, + -0x1.11ec18bedep-55, + 0x1.da9e603db3285p-1, + 0x1.c2300696db5p-55, + 0x1.dd321f301b46p-1, + 0x1.2da5778f019p-55, + 0x1.dfc97337b9b5fp-1, + -0x1.1a5cd4f184b8p-55, + 0x1.e264614f5a129p-1, + -0x1.7b627817a148p-55, + 0x1.e502ee78b3ff6p-1, + 0x1.39e8980a9cdp-56, + 0x1.e7a51fbc74c83p-1, + 0x1.2d522ca0c8ep-55, + 0x1.ea4afa2a490dap-1, + -0x1.e9c23179c288p-55, + 0x1.ecf482d8e67f1p-1, + -0x1.c93f3b411ad8p-55, + 0x1.efa1bee615a27p-1, + 0x1.dc7f486a4b68p-55, + 0x1.f252b376bba97p-1, + 0x1.3a1a5bf0d8e8p-55, + 0x1.f50765b6e454p-1, + 0x1.9d3e12dd8a18p-55, + 0x1.f7bfdad9cbe14p-1, + -0x1.dbb12d00635p-55, + 0x1.fa7c1819e90d8p-1, + 0x1.74853f3a593p-56, + 0x1.fd3c22b8f71f1p-1, + 0x1.2eb74966578p-58, + 0x1p+0, + 0x0p+0, + 0x1.0163da9fb3335p+0, + 0x1.b61299ab8cd8p-54, + 0x1.02c9a3e778061p+0, + -0x1.19083535b08p-56, + 0x1.04315e86e7f85p+0, + -0x1.0a31c1977c98p-54, + 0x1.059b0d3158574p+0, + 0x1.d73e2a475b4p-55, + 0x1.0706b29ddf6dep+0, + -0x1.c91dfe2b13cp-55, + 0x1.0874518759bc8p+0, + 0x1.186be4bb284p-57, + 0x1.09e3ecac6f383p+0, + 0x1.14878183161p-54, + 0x1.0b5586cf9890fp+0, + 0x1.8a62e4adc61p-54, + 0x1.0cc922b7247f7p+0, + 0x1.01edc16e24f8p-54, + 0x1.0e3ec32d3d1a2p+0, + 0x1.03a1727c58p-59, + 0x1.0fb66affed31bp+0, + -0x1.b9bedc44ebcp-57, + 0x1.11301d0125b51p+0, + -0x1.6c51039449bp-54, + 0x1.12abdc06c31ccp+0, + -0x1.1b514b36ca8p-58, + 0x1.1429aaea92dep+0, + -0x1.32fbf9af1368p-54, + 0x1.15a98c8a58e51p+0, + 0x1.2406ab9eeabp-55, + 0x1.172b83c7d517bp+0, + -0x1.19041b9d78ap-55, + 0x1.18af9388c8deap+0, + -0x1.11023d1970f8p-54, + 0x1.1a35beb6fcb75p+0, + 0x1.e5b4c7b4969p-55, + 0x1.1bbe084045cd4p+0, + -0x1.95386352ef6p-54, + 0x1.1d4873168b9aap+0, + 0x1.e016e00a264p-54, + 0x1.1ed5022fcd91dp+0, + -0x1.1df98027bb78p-54, + 0x1.2063b88628cd6p+0, + 0x1.dc775814a85p-55, + 0x1.21f49917ddc96p+0, + 0x1.2a97e9494a6p-55, + 0x1.2387a6e756238p+0, + 0x1.9b07eb6c7058p-54, + 0x1.251ce4fb2a63fp+0, + 0x1.ac155bef4f5p-55, + 0x1.26b4565e27cddp+0, + 0x1.2bd339940eap-55, + 0x1.284dfe1f56381p+0, + -0x1.a4c3a8c3f0d8p-54, + 0x1.29e9df51fdee1p+0, + 0x1.612e8afad12p-55, + 0x1.2b87fd0dad99p+0, + -0x1.10adcd6382p-59, + 0x1.2d285a6e4030bp+0, + 0x1.0024754db42p-54, + 0x1.2ecafa93e2f56p+0, + 0x1.1ca0f45d524p-56, + 0x1.306fe0a31b715p+0, + 0x1.6f46ad23183p-55, + 0x1.32170fc4cd831p+0, + 0x1.a9ce78e1804p-55, + 0x1.33c08b26416ffp+0, + 0x1.327218436598p-54, + 0x1.356c55f929ff1p+0, + -0x1.b5cee5c4e46p-55, + 0x1.371a7373aa9cbp+0, + -0x1.63aeabf42ebp-54, + 0x1.38cae6d05d866p+0, + -0x1.e958d3c99048p-54, + 0x1.3a7db34e59ff7p+0, + -0x1.5e436d661f6p-56, + 0x1.3c32dc313a8e5p+0, + -0x1.efff8375d2ap-54, + 0x1.3dea64c123422p+0, + 0x1.ada0911f09fp-55, + 0x1.3fa4504ac801cp+0, + -0x1.7d023f956fap-54, + 0x1.4160a21f72e2ap+0, + -0x1.ef3691c309p-58, + 0x1.431f5d950a897p+0, + -0x1.1c7dde35f7ap-55, + 0x1.44e086061892dp+0, + 0x1.89b7a04ef8p-59, + 0x1.46a41ed1d0057p+0, + 0x1.c944bd1648a8p-54, + 0x1.486a2b5c13cdp+0, + 0x1.3c1a3b69062p-56, + 0x1.4a32af0d7d3dep+0, + 0x1.9cb62f3d1be8p-54, + 0x1.4bfdad5362a27p+0, + 0x1.d4397afec42p-56, + 0x1.4dcb299fddd0dp+0, + 0x1.8ecdbbc6a78p-54, + 0x1.4f9b2769d2ca7p+0, + -0x1.4b309d25958p-54, + 0x1.516daa2cf6642p+0, + -0x1.f768569bd94p-55, + 0x1.5342b569d4f82p+0, + -0x1.07abe1db13dp-55, + 0x1.551a4ca5d920fp+0, + -0x1.d689cefede6p-55, + 0x1.56f4736b527dap+0, + 0x1.9bb2c011d938p-54, + 0x1.58d12d497c7fdp+0, + 0x1.295e15b9a1ep-55, + 0x1.5ab07dd485429p+0, + 0x1.6324c0546478p-54, + 0x1.5c9268a5946b7p+0, + 0x1.c4b1b81698p-60, + 0x1.5e76f15ad2148p+0, + 0x1.ba6f93080e68p-54, + 0x1.605e1b976dc09p+0, + -0x1.3e2429b56de8p-54, + 0x1.6247eb03a5585p+0, + -0x1.383c17e40b48p-54, + 0x1.6434634ccc32p+0, + -0x1.c483c759d89p-55, + 0x1.6623882552225p+0, + -0x1.bb60987591cp-54, + 0x1.68155d44ca973p+0, + 0x1.038ae44f74p-57, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.511 ulp. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2l(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLBITS+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-6 minimax polynomial with maximum error under 2**-69. + * The table entries each have 104 bits of accuracy, encoded as + * a pair of double precision values. + */ +long double exp2l(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z; + uint32_t i0; + union { + uint32_t u; + int32_t i; + } k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 13) { /* |x| >= 8192 or x is NaN */ + if (u.i.se >= 0x3fff + 14 && u.i.se >> 15 == 0) /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1 / x; + if (x < -16382) { + if (x <= -16446 || x - 0x1p63 + 0x1p63 != x) /* underflow */ + FORCE_EVAL((float)(-0x1p-149 / x)); + if (x <= -16446) return 0; + } + } else if (e < 0x3fff - 64) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i.m + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */ + long double t_hi = tbl[2 * i0]; + long double t_lo = tbl[2 * i0 + 1]; + /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */ + r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * P6))))) + t_hi; + + return scalbnl(r, k.i); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const long double P1 = 0x1.62e42fefa39ef35793c7673007e6p-1L, + P2 = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L, + P3 = 0x1.c6b08d704a0bf8b33a762bad3459p-5L, + P4 = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L, + P5 = 0x1.5d87fe78a67311071dee13fd11d9p-10L, + P6 = 0x1.430912f86c7876f4b663b23c5fe5p-13L; + +static const double P7 = 0x1.ffcbfc588b041p-17, P8 = 0x1.62c0223a5c7c7p-20, + P9 = 0x1.b52541ff59713p-24, P10 = 0x1.e4cf56a391e22p-28, + redux = 0x1.8p112 / TBLSIZE; + +static const long double tbl[TBLSIZE] = { + 0x1.6a09e667f3bcc908b2fb1366dfeap-1L, 0x1.6c012750bdabeed76a99800f4edep-1L, + 0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L, 0x1.6ff7df9519483cf87e1b4f3e1e98p-1L, + 0x1.71f75e8ec5f73dd2370f2ef0b148p-1L, 0x1.73f9a48a58173bd5c9a4e68ab074p-1L, + 0x1.75feb564267c8bf6e9aa33a489a8p-1L, 0x1.780694fde5d3f619ae02808592a4p-1L, + 0x1.7a11473eb0186d7d51023f6ccb1ap-1L, 0x1.7c1ed0130c1327c49334459378dep-1L, + 0x1.7e2f336cf4e62105d02ba1579756p-1L, 0x1.80427543e1a11b60de67649a3842p-1L, + 0x1.82589994cce128acf88afab34928p-1L, 0x1.8471a4623c7acce52f6b97c6444cp-1L, + 0x1.868d99b4492ec80e41d90ac2556ap-1L, 0x1.88ac7d98a669966530bcdf2d4cc0p-1L, + 0x1.8ace5422aa0db5ba7c55a192c648p-1L, 0x1.8cf3216b5448bef2aa1cd161c57ap-1L, + 0x1.8f1ae991577362b982745c72eddap-1L, 0x1.9145b0b91ffc588a61b469f6b6a0p-1L, + 0x1.93737b0cdc5e4f4501c3f2540ae8p-1L, 0x1.95a44cbc8520ee9b483695a0e7fep-1L, + 0x1.97d829fde4e4f8b9e920f91e8eb6p-1L, 0x1.9a0f170ca07b9ba3109b8c467844p-1L, + 0x1.9c49182a3f0901c7c46b071f28dep-1L, 0x1.9e86319e323231824ca78e64c462p-1L, + 0x1.a0c667b5de564b29ada8b8cabbacp-1L, 0x1.a309bec4a2d3358c171f770db1f4p-1L, + 0x1.a5503b23e255c8b424491caf88ccp-1L, 0x1.a799e1330b3586f2dfb2b158f31ep-1L, + 0x1.a9e6b5579fdbf43eb243bdff53a2p-1L, 0x1.ac36bbfd3f379c0db966a3126988p-1L, + 0x1.ae89f995ad3ad5e8734d17731c80p-1L, 0x1.b0e07298db66590842acdfc6fb4ep-1L, + 0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L, 0x1.b59728de559398e3881111648738p-1L, + 0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L, 0x1.ba5b030a10649840cb3c6af5b74cp-1L, + 0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L, 0x1.bf2c25bd71e088408d7025190cd0p-1L, + 0x1.c199bdd85529c2220cb12a0916bap-1L, 0x1.c40ab5fffd07a6d14df820f17deap-1L, + 0x1.c67f12e57d14b4a2137fd20f2a26p-1L, 0x1.c8f6d9406e7b511acbc48805c3f6p-1L, + 0x1.cb720dcef90691503cbd1e949d0ap-1L, 0x1.cdf0b555dc3f9c44f8958fac4f12p-1L, + 0x1.d072d4a07897b8d0f22f21a13792p-1L, 0x1.d2f87080d89f18ade123989ea50ep-1L, + 0x1.d5818dcfba48725da05aeb66dff8p-1L, 0x1.d80e316c98397bb84f9d048807a0p-1L, + 0x1.da9e603db3285708c01a5b6d480cp-1L, 0x1.dd321f301b4604b695de3c0630c0p-1L, + 0x1.dfc97337b9b5eb968cac39ed284cp-1L, 0x1.e264614f5a128a12761fa17adc74p-1L, + 0x1.e502ee78b3ff6273d130153992d0p-1L, 0x1.e7a51fbc74c834b548b2832378a4p-1L, + 0x1.ea4afa2a490d9858f73a18f5dab4p-1L, 0x1.ecf482d8e67f08db0312fb949d50p-1L, + 0x1.efa1bee615a27771fd21a92dabb6p-1L, 0x1.f252b376bba974e8696fc3638f24p-1L, + 0x1.f50765b6e4540674f84b762861a6p-1L, 0x1.f7bfdad9cbe138913b4bfe72bd78p-1L, + 0x1.fa7c1819e90d82e90a7e74b26360p-1L, 0x1.fd3c22b8f71f10975ba4b32bd006p-1L, + 0x1.0000000000000000000000000000p+0L, 0x1.0163da9fb33356d84a66ae336e98p+0L, + 0x1.02c9a3e778060ee6f7caca4f7a18p+0L, 0x1.04315e86e7f84bd738f9a20da442p+0L, + 0x1.059b0d31585743ae7c548eb68c6ap+0L, 0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L, + 0x1.0874518759bc808c35f25d942856p+0L, 0x1.09e3ecac6f3834521e060c584d5cp+0L, + 0x1.0b5586cf9890f6298b92b7184200p+0L, 0x1.0cc922b7247f7407b705b893dbdep+0L, + 0x1.0e3ec32d3d1a2020742e4f8af794p+0L, 0x1.0fb66affed31af232091dd8a169ep+0L, + 0x1.11301d0125b50a4ebbf1aed9321cp+0L, 0x1.12abdc06c31cbfb92bad324d6f84p+0L, + 0x1.1429aaea92ddfb34101943b2588ep+0L, 0x1.15a98c8a58e512480d573dd562aep+0L, + 0x1.172b83c7d517adcdf7c8c50eb162p+0L, 0x1.18af9388c8de9bbbf70b9a3c269cp+0L, + 0x1.1a35beb6fcb753cb698f692d2038p+0L, 0x1.1bbe084045cd39ab1e72b442810ep+0L, + 0x1.1d4873168b9aa7805b8028990be8p+0L, 0x1.1ed5022fcd91cb8819ff61121fbep+0L, + 0x1.2063b88628cd63b8eeb0295093f6p+0L, 0x1.21f49917ddc962552fd29294bc20p+0L, + 0x1.2387a6e75623866c1fadb1c159c0p+0L, 0x1.251ce4fb2a63f3582ab7de9e9562p+0L, + 0x1.26b4565e27cdd257a673281d3068p+0L, 0x1.284dfe1f5638096cf15cf03c9fa0p+0L, + 0x1.29e9df51fdee12c25d15f5a25022p+0L, 0x1.2b87fd0dad98ffddea46538fca24p+0L, + 0x1.2d285a6e4030b40091d536d0733ep+0L, 0x1.2ecafa93e2f5611ca0f45d5239a4p+0L, + 0x1.306fe0a31b7152de8d5a463063bep+0L, 0x1.32170fc4cd8313539cf1c3009330p+0L, + 0x1.33c08b26416ff4c9c8610d96680ep+0L, 0x1.356c55f929ff0c94623476373be4p+0L, + 0x1.371a7373aa9caa7145502f45452ap+0L, 0x1.38cae6d05d86585a9cb0d9bed530p+0L, + 0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L, 0x1.3c32dc313a8e484001f228b58cf0p+0L, + 0x1.3dea64c12342235b41223e13d7eep+0L, 0x1.3fa4504ac801ba0bf701aa417b9cp+0L, + 0x1.4160a21f72e29f84325b8f3dbacap+0L, 0x1.431f5d950a896dc704439410b628p+0L, + 0x1.44e086061892d03136f409df0724p+0L, 0x1.46a41ed1d005772512f459229f0ap+0L, + 0x1.486a2b5c13cd013c1a3b69062f26p+0L, 0x1.4a32af0d7d3de672d8bcf46f99b4p+0L, + 0x1.4bfdad5362a271d4397afec42e36p+0L, 0x1.4dcb299fddd0d63b36ef1a9e19dep+0L, + 0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L, 0x1.516daa2cf6641c112f52c84d6066p+0L, + 0x1.5342b569d4f81df0a83c49d86bf4p+0L, 0x1.551a4ca5d920ec52ec620243540cp+0L, + 0x1.56f4736b527da66ecb004764e61ep+0L, 0x1.58d12d497c7fd252bc2b7343d554p+0L, + 0x1.5ab07dd48542958c93015191e9a8p+0L, 0x1.5c9268a5946b701c4b1b81697ed4p+0L, + 0x1.5e76f15ad21486e9be4c20399d12p+0L, 0x1.605e1b976dc08b076f592a487066p+0L, + 0x1.6247eb03a5584b1f0fa06fd2d9eap+0L, 0x1.6434634ccc31fc76f8714c4ee122p+0L, + 0x1.66238825522249127d9e29b92ea2p+0L, 0x1.68155d44ca973081c57227b9f69ep+0L, +}; + +static const float eps[TBLSIZE] = { + -0x1.5c50p-101, -0x1.5d00p-106, 0x1.8e90p-102, -0x1.5340p-103, 0x1.1bd0p-102, -0x1.4600p-105, + -0x1.7a40p-104, 0x1.d590p-102, -0x1.d590p-101, 0x1.b100p-103, -0x1.0d80p-105, 0x1.6b00p-103, + -0x1.9f00p-105, 0x1.c400p-103, 0x1.e120p-103, -0x1.c100p-104, -0x1.9d20p-103, 0x1.a800p-108, + 0x1.4c00p-106, -0x1.9500p-106, 0x1.6900p-105, -0x1.29d0p-100, 0x1.4c60p-103, 0x1.13a0p-102, + -0x1.5b60p-103, -0x1.1c40p-103, 0x1.db80p-102, 0x1.91a0p-102, 0x1.dc00p-105, 0x1.44c0p-104, + 0x1.9710p-102, 0x1.8760p-103, -0x1.a720p-103, 0x1.ed20p-103, -0x1.49c0p-102, -0x1.e000p-111, + 0x1.86a0p-103, 0x1.2b40p-103, -0x1.b400p-108, 0x1.1280p-99, -0x1.02d8p-102, -0x1.e3d0p-103, + -0x1.b080p-105, -0x1.f100p-107, -0x1.16c0p-105, -0x1.1190p-103, -0x1.a7d2p-100, 0x1.3450p-103, + -0x1.67c0p-105, 0x1.4b80p-104, -0x1.c4e0p-103, 0x1.6000p-108, -0x1.3f60p-105, 0x1.93f0p-104, + 0x1.5fe0p-105, 0x1.6f80p-107, -0x1.7600p-106, 0x1.21e0p-106, -0x1.3a40p-106, -0x1.40c0p-104, + -0x1.9860p-105, -0x1.5d40p-108, -0x1.1d70p-106, 0x1.2760p-105, 0x0.0000p+0, 0x1.21e2p-104, + -0x1.9520p-108, -0x1.5720p-106, -0x1.4810p-106, -0x1.be00p-109, 0x1.0080p-105, -0x1.5780p-108, + -0x1.d460p-105, -0x1.6140p-105, 0x1.4630p-104, 0x1.ad50p-103, 0x1.82e0p-105, 0x1.1d3cp-101, + 0x1.6100p-107, 0x1.ec30p-104, 0x1.f200p-108, 0x1.0b40p-103, 0x1.3660p-102, 0x1.d9d0p-103, + -0x1.02d0p-102, 0x1.b070p-103, 0x1.b9c0p-104, -0x1.01c0p-103, -0x1.dfe0p-103, 0x1.1b60p-104, + -0x1.ae94p-101, -0x1.3340p-104, 0x1.b3d8p-102, -0x1.6e40p-105, -0x1.3670p-103, 0x1.c140p-104, + 0x1.1840p-101, 0x1.1ab0p-102, -0x1.a400p-104, 0x1.1f00p-104, -0x1.7180p-103, 0x1.4ce0p-102, + 0x1.9200p-107, -0x1.54c0p-103, 0x1.1b80p-105, -0x1.1828p-101, 0x1.5720p-102, -0x1.a060p-100, + 0x1.9160p-102, 0x1.a280p-104, 0x1.3400p-107, 0x1.2b20p-102, 0x1.7800p-108, 0x1.cfd0p-101, + 0x1.2ef0p-102, -0x1.2760p-99, 0x1.b380p-104, 0x1.0048p-101, -0x1.60b0p-102, 0x1.a1ccp-100, + -0x1.a640p-104, -0x1.08a0p-101, 0x1.7e60p-102, 0x1.22c0p-103, -0x1.7200p-106, 0x1.f0f0p-102, + 0x1.eb4ep-99, 0x1.c6e0p-103, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.502 ulp. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-8 + 2**-98 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-10 minimax polynomial with maximum error under 2**-120. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-122. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +long double exp2l(long double x) { + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z, t; + uint32_t i0; + union { + uint32_t u; + int32_t i; + } k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 14) { /* |x| >= 16384 or x is NaN */ + if (u.i.se >= 0x3fff + 15 && u.i.se >> 15 == 0) /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1 / x; + if (x < -16382) { + if (x <= -16495 || x - 0x1p112 + 0x1p112 != x) /* underflow */ + FORCE_EVAL((float)(-0x1p-149 / x)); + if (x <= -16446) return 0; + } + } else if (e < 0x3fff - 114) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i2.lo + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; + z -= eps[i0]; + r = t + + t * z * + (P1 + + z * (P2 + + z * (P3 + + z * (P4 + z * (P5 + z * (P6 + z * (P7 + z * (P8 + z * (P9 + z * P10))))))))); + + return scalbnl(r, k.i); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/expf.c b/third_party/ulib/musl/third_party/math/expf.c new file mode 100644 index 000000000..3eeac7408 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/expf.c @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float half[2] = {0.5, -0.5}, ln2hi = 6.9314575195e-1f, /* 0x3f317200 */ + ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */ + invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */ + /* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ + P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */ + P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */ + +float expf(float x) { + float_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_FLOAT_WORD(hx, x); + sign = hx >> 31; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */ + /* overflow */ + x *= 0x1p127f; + return x; + } + if (sign) { + /* underflow */ + FORCE_EVAL(-0x1p-149f / x); + if (hx >= 0x42cff1b5) /* x <= -103.972084f */ + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */ + k = invln2 * x + half[sign]; + else + k = 1 - sign - sign; + hi = x - k * ln2hi; /* k*ln2hi is exact here */ + lo = k * ln2lo; + x = hi - lo; + } else if (hx > 0x39000000) { /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0; + } else { + /* raise inexact */ + FORCE_EVAL(0x1p127f + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * P2); + y = 1 + (x * c / (2 - c) - lo + hi); + if (k == 0) return y; + return scalbnf(y, k); +} diff --git a/third_party/ulib/musl/third_party/math/expl.c b/third_party/ulib/musl/third_party/math/expl.c new file mode 100644 index 000000000..51b67241b --- /dev/null +++ b/third_party/ulib/musl/third_party/math/expl.c @@ -0,0 +1,118 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expl(); + * + * y = expl( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form of degree 5/6 is used to approximate exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-10000 50000 1.12e-19 2.81e-20 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a long double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG MAXNUM + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expl(long double x) { + return exp(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +static const long double P[3] = { + 1.2617719307481059087798E-4L, 3.0299440770744196129956E-2L, 9.9999999999999999991025E-1L, +}; +static const long double Q[4] = { + 3.0019850513866445504159E-6L, 2.5244834034968410419224E-3L, 2.2726554820815502876593E-1L, + 2.0000000000000000000897E0L, +}; +static const long double LN2HI = 6.9314575195312500000000E-1L, LN2LO = 1.4286068203094172321215E-6L, + LOG2E = 1.4426950408889634073599E0L; + +long double expl(long double x) { + long double px, xx; + int k; + + if (isnan(x)) return x; + if (x > 11356.5234062941439488L) /* x > ln(2^16384 - 0.5) */ + return x * 0x1p16383L; + if (x < -11399.4985314888605581L) /* x < ln(2^-16446) */ + return -0x1p-16445L / x; + + /* Express e**x = e**f 2**k + * = e**(f + k ln(2)) + */ + px = floorl(LOG2E * x + 0.5); + k = px; + x -= px * LN2HI; + x -= px * LN2LO; + + /* rational approximation of the fractional part: + * e**x = 1 + 2x P(x**2)/(Q(x**2) - x P(x**2)) + */ + xx = x * x; + px = x * __polevll(xx, P, 2); + x = px / (__polevll(xx, Q, 3) - px); + x = 1.0 + 2.0 * x; + return scalbnl(x, k); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expl(long double x) { + return exp(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/expm1.c b/third_party/ulib/musl/third_party/math/expm1.c new file mode 100644 index 000000000..1012f1a7a --- /dev/null +++ b/third_party/ulib/musl/third_party/math/expm1.c @@ -0,0 +1,197 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Remez algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ + ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ + /* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ + Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ + Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ + Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ + Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ + Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double expm1(double x) { + double_t y, hi, lo, c, t, e, hxs, hfx, r1, twopk; + union { + double f; + uint64_t i; + } u = {x}; + uint32_t hx = u.i >> 32 & 0x7fffffff; + int k, sign = u.i >> 63; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if (isnan(x)) return x; + if (sign) return -1; + if (x > o_threshold) { + x *= 0x1p1023; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2 * x + (sign ? -0.5 : 0.5); + t = k; + hi = x - t * ln2_hi; /* t*ln2_hi is exact here */ + lo = t * ln2_lo; + } + x = hi - lo; + c = (hi - x) - lo; + } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */ + if (hx < 0x00100000) FORCE_EVAL((float)x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5 * x; + hxs = x * hfx; + r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t = 3.0 - r1 * hfx; + e = hxs * ((r1 - t) / (6.0 - x * t)); + if (k == 0) /* c is 0 */ + return x - (x * e - hxs); + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) return 0.5 * (x - e) - 0.5; + if (k == 1) { + if (x < -0.25) return -2.0 * (e - (x + 0.5)); + return 1.0 + 2.0 * (x - e); + } + u.i = (uint64_t)(0x3ff + k) << 52; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if (k == 1024) + y = y * 2.0 * 0x1p1023; + else + y = y * twopk; + return y - 1.0; + } + u.i = (uint64_t)(0x3ff - k) << 52; /* 2^-k */ + if (k < 20) + y = (x - e + (1 - u.f)) * twopk; + else + y = (x - (e + u.f) + 1) * twopk; + return y; +} diff --git a/third_party/ulib/musl/third_party/math/expm1f.c b/third_party/ulib/musl/third_party/math/expm1f.c new file mode 100644 index 000000000..2107df024 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/expm1f.c @@ -0,0 +1,108 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float o_threshold = 8.8721679688e+01, /* 0x42b17180 */ + ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ + ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ + invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ + /* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ + Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ + Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float expm1f(float x) { + float_t y, hi, lo, c, t, e, hxs, hfx, r1, twopk; + union { + float f; + uint32_t i; + } u = {x}; + uint32_t hx = u.i & 0x7fffffff; + int k, sign = u.i >> 31; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (sign) return -1; + if (x > o_threshold) { + x *= 0x1p127f; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2 * x + (sign ? -0.5f : 0.5f); + t = k; + hi = x - t * ln2_hi; /* t*ln2_hi is exact here */ + lo = t * ln2_lo; + } + x = hi - lo; + c = (hi - x) - lo; + } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (hx < 0x00800000) FORCE_EVAL(x * x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5f * x; + hxs = x * hfx; + r1 = 1.0f + hxs * (Q1 + hxs * Q2); + t = 3.0f - r1 * hfx; + e = hxs * ((r1 - t) / (6.0f - x * t)); + if (k == 0) /* c is 0 */ + return x - (x * e - hxs); + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) return 0.5f * (x - e) - 0.5f; + if (k == 1) { + if (x < -0.25f) return -2.0f * (e - (x + 0.5f)); + return 1.0f + 2.0f * (x - e); + } + u.i = (0x7f + k) << 23; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0f; + if (k == 128) + y = y * 2.0f * 0x1p127f; + else + y = y * twopk; + return y - 1.0f; + } + u.i = (0x7f - k) << 23; /* 2^-k */ + if (k < 23) + y = (x - e + (1 - u.f)) * twopk; + else + y = (x - (e + u.f) + 1) * twopk; + return y; +} diff --git a/third_party/ulib/musl/third_party/math/expm1l.c b/third_party/ulib/musl/third_party/math/expm1l.c new file mode 100644 index 000000000..ae0f6c8f2 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/expm1l.c @@ -0,0 +1,114 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, minus 1 + * Long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus 1. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expm1l(long double x) { + return expm1(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 3.4e-22 */ +static const long double P0 = -1.586135578666346600772998894928250240826E4L, + P1 = 2.642771505685952966904660652518429479531E3L, + P2 = -3.423199068835684263987132888286791620673E2L, + P3 = 1.800826371455042224581246202420972737840E1L, + P4 = -5.238523121205561042771939008061958820811E-1L, + Q0 = -9.516813471998079611319047060563358064497E4L, + Q1 = 3.964866271411091674556850458227710004570E4L, + Q2 = -7.207678383830091850230366618190187434796E3L, + Q3 = 7.206038318724600171970199625081491823079E2L, + Q4 = -4.002027679107076077238836622982900945173E1L, + /* Q5 = 1.000000000000000000000000000000000000000E0 */ + /* C1 + C2 = ln 2 */ + C1 = 6.93145751953125E-1L, C2 = 1.428606820309417232121458176568075500134E-6L, + /* ln 2^-65 */ + minarg = -4.5054566736396445112120088E1L, + /* ln 2^16384 */ + maxarg = 1.1356523406294143949492E4L; + +long double expm1l(long double x) { + long double px, qx, xx; + int k; + + if (isnan(x)) return x; + if (x > maxarg) return x * 0x1p16383L; /* overflow, unless x==inf */ + if (x == 0.0) return x; + if (x < minarg) return -1.0; + + xx = C1 + C2; + /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ + px = floorl(0.5 + x / xx); + k = px; + /* remainder times ln 2 */ + x -= px * C1; + x -= px * C2; + + /* Approximate exp(remainder ln 2).*/ + px = ((((P4 * x + P3) * x + P2) * x + P1) * x + P0) * x; + qx = ((((x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0; + xx = x * x; + qx = x + (0.5 * xx + xx * px / qx); + + /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 = 2^k qx + 2^k - 1. */ + px = scalbnl(1.0, k); + x = px * qx + (px - 1.0); + return x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expm1l(long double x) { + return expm1(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/fma.c b/third_party/ulib/musl/third_party/math/fma.c new file mode 100644 index 000000000..4ccce1e22 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/fma.c @@ -0,0 +1,443 @@ +#include "libm.h" +#include + +#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* exact add, assumes exponent_x >= exponent_y */ +static void add(long double* hi, long double* lo, long double x, long double y) { + long double r; + + r = x + y; + *hi = r; + r -= x; + *lo = y - r; +} + +/* exact mul, assumes no over/underflow */ +static void mul(long double* hi, long double* lo, long double x, long double y) { + static const long double c = 1.0 + 0x1p32L; + long double cx, xh, xl, cy, yh, yl; + + cx = c * x; + xh = (x - cx) + cx; + xl = x - xh; + cy = c * y; + yh = (y - cy) + cy; + yl = y - yh; + *hi = x * y; + *lo = (xh * yh - *hi) + xh * yl + xl * yh + xl * yl; +} + +/* +assume (long double)(hi+lo) == hi +return an adjusted hi so that rounding it to double (or less) precision is correct +*/ +static long double adjust(long double hi, long double lo) { + union ldshape uhi, ulo; + + if (lo == 0) return hi; + uhi.f = hi; + if (uhi.i.m & 0x3ff) return hi; + ulo.f = lo; + if ((uhi.i.se & 0x8000) == (ulo.i.se & 0x8000)) + uhi.i.m++; + else { + /* handle underflow and take care of ld80 implicit msb */ + if (uhi.i.m << 1 == 0) { + uhi.i.m = 0; + uhi.i.se--; + } + uhi.i.m--; + } + return uhi.f; +} + +/* adjusted add so the result is correct when rounded to double (or less) precision */ +static long double dadd(long double x, long double y) { + add(&x, &y, x, y); + return adjust(x, y); +} + +/* adjusted mul so the result is correct when rounded to double (or less) precision */ +static long double dmul(long double x, long double y) { + mul(&x, &y, x, y); + return adjust(x, y); +} + +static int getexp(long double x) { + union ldshape u; + u.f = x; + return u.i.se & 0x7fff; +} + +double fma(double x, double y, double z) { + PRAGMA_STDC_FENV_ACCESS_ON + long double hi, lo1, lo2, xy; + int round, ez, exy; + + /* handle +-inf,nan */ + if (!isfinite(x) || !isfinite(y)) return x * y + z; + if (!isfinite(z)) return z; + /* handle +-0 */ + if (x == 0.0 || y == 0.0) return x * y + z; + round = fegetround(); + if (z == 0.0) { + if (round == FE_TONEAREST) return dmul(x, y); + return x * y; + } + + /* exact mul and add require nearest rounding */ + /* spurious inexact exceptions may be raised */ + fesetround(FE_TONEAREST); + mul(&xy, &lo1, x, y); + exy = getexp(xy); + ez = getexp(z); + if (ez > exy) { + add(&hi, &lo2, z, xy); + } else if (ez > exy - 12) { + add(&hi, &lo2, xy, z); + if (hi == 0) { + /* + xy + z is 0, but it should be calculated with the + original rounding mode so the sign is correct, if the + compiler does not support FENV_ACCESS ON it does not + know about the changed rounding mode and eliminates + the xy + z below without the volatile memory access + */ + volatile double z_; + fesetround(round); + z_ = z; + return (xy + z_) + lo1; + } + } else { + /* + ez <= exy - 12 + the 12 extra bits (1guard, 11round+sticky) are needed so with + lo = dadd(lo1, lo2) + elo <= ehi - 11, and we use the last 10 bits in adjust so + dadd(hi, lo) + gives correct result when rounded to double + */ + hi = xy; + lo2 = z; + } + /* + the result is stored before return for correct precision and exceptions + + one corner case is when the underflow flag should be raised because + the precise result is an inexact subnormal double, but the calculated + long double result is an exact subnormal double + (so rounding to double does not raise exceptions) + + in nearest rounding mode dadd takes care of this: the last bit of the + result is adjusted so rounding sees an inexact value when it should + + in non-nearest rounding mode fenv is used for the workaround + */ + fesetround(round); + if (round == FE_TONEAREST) + z = dadd(hi, dadd(lo1, lo2)); + else { +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + z = hi + (lo1 + lo2); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (getexp(z) < 0x3fff - 1022 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + } + return z; +} +#else +/* origin: FreeBSD /usr/src/lib/msun/src/s_fma.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * A struct dd represents a floating-point number with twice the precision + * of a double. We maintain the invariant that "hi" stores the 53 high-order + * bits of the result. + */ +struct dd { + double hi; + double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(double a, double b) { + struct dd ret; + double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline double add_adjusted(double a, double b) { + struct dd sum; + union { + double f; + uint64_t i; + } uhi, ulo; + + sum = dd_add(a, b); + if (sum.lo != 0) { + uhi.f = sum.hi; + if ((uhi.i & 1) == 0) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + ulo.f = sum.lo; + uhi.i += 1 - ((uhi.i ^ ulo.i) >> 62); + sum.hi = uhi.f; + } + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline double add_and_denormalize(double a, double b, int scale) { + struct dd sum; + union { + double f; + uint64_t i; + } uhi, ulo; + int bits_lost; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + uhi.f = sum.hi; + bits_lost = -((int)(uhi.i >> 52) & 0x7ff) - scale + 1; + if ((bits_lost != 1) ^ (int)(uhi.i & 1)) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + ulo.f = sum.lo; + uhi.i += 1 - (((uhi.i ^ ulo.i) >> 62) & 2); + sum.hi = uhi.f; + } + } + return scalbn(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(double a, double b) { + static const double split = 0x1p27 + 1.0; + struct dd ret; + double ha, hb, la, lb, p, q; + + p = a * split; + ha = a - p; + ha += p; + la = a - ha; + + p = b * split; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + * + * This algorithm is sensitive to the rounding precision. FPUs such + * as the i387 must be set in double-precision mode if variables are + * to be stored in FP registers in order to avoid incorrect results. + * This is the default on FreeBSD, but not on many other systems. + * + * Hardware instructions should be used on architectures that support it, + * since this implementation will likely be several times slower. + */ +double fma(double x, double y, double z) { +PRAGMA_STDC_FENV_ACCESS_ON + double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) return (x * y + z); + if (!isfinite(z)) return (z); + if (x == 0.0 || y == 0.0) return (x * y + z); + if (z == 0.0) return (x * y); + + xs = frexp(x, &ex); + ys = frexp(y, &ey); + zs = frexp(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -DBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafter(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafter(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafter(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= DBL_MANT_DIG * 2) + zs = scalbn(zs, -spread); + else + zs = copysign(DBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile double vzs = zs; /* XXX gcc CSE bug workaround */ + return xy.hi + vzs + scalbn(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised properly, example in downward rounding: + * fma(0x1.000000001p-1000, 0x1.000000001p-30, -0x1p-1066) + */ + double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbn(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogb(ret) < -1022 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogb(r.hi) > -1023) + return scalbn(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/fmaf.c b/third_party/ulib/musl/third_party/math/fmaf.c new file mode 100644 index 000000000..1509adc1f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/fmaf.c @@ -0,0 +1,96 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include "libm.h" + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +float fmaf(float x, float y, float z) { + PRAGMA_STDC_FENV_ACCESS_ON + double xy, result; + union { + double f; + uint64_t i; + } u; + int e; + + xy = (double)x * y; + result = xy + z; + u.f = result; + e = u.i >> 52 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ((u.i & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + e == 0x7ff || /* NaN */ + result - xy == z || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + { +/* +underflow may not be raised correctly, example: +fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) +*/ +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT)) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + volatile float vz = z; + result = xy + vz; + if (fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else + feraiseexcept(FE_INEXACT); + } +#endif + z = result; + return z; + } + +/* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ +#ifdef FE_TOWARDZERO + fesetround(FE_TOWARDZERO); +#endif + volatile double vxy = xy; /* XXX work around gcc CSE bug */ + double adjusted_result = vxy + z; + fesetround(FE_TONEAREST); + if (result == adjusted_result) { + u.f = adjusted_result; + u.i++; + adjusted_result = u.f; + } + z = adjusted_result; + return z; +} diff --git a/third_party/ulib/musl/third_party/math/fmal.c b/third_party/ulib/musl/third_party/math/fmal.c new file mode 100644 index 000000000..42cd4c544 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/fmal.c @@ -0,0 +1,279 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmal.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmal(long double x, long double y, long double z) { + return fma(x, y, z); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include +#if LDBL_MANT_DIG == 64 +#define LASTBIT(u) (u.i.m & 1) +#define SPLIT (0x1p32L + 1) +#elif LDBL_MANT_DIG == 113 +#define LASTBIT(u) (u.i.lo & 1) +#define SPLIT (0x1p57L + 1) +#endif + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(long double a, long double b) { + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double add_adjusted(long double a, long double b) { + struct dd sum; + union ldshape u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.f = sum.hi; + if (!LASTBIT(u)) sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double add_and_denormalize(long double a, long double b, int scale) { + struct dd sum; + int bits_lost; + union ldshape u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.f = sum.hi; + bits_lost = -u.i.se - scale + 1; + if ((bits_lost != 1) ^ LASTBIT(u)) sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return scalbnl(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(long double a, long double b) { + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * SPLIT; + ha = a - p; + ha += p; + la = a - ha; + + p = b * SPLIT; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +long double fmal(long double x, long double y, long double z) { + PRAGMA_STDC_FENV_ACCESS_ON + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) return (x * y + z); + if (!isfinite(z)) return (z); + if (x == 0.0 || y == 0.0) return (x * y + z); + if (z == 0.0) return (x * y); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafterl(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafterl(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafterl(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = scalbnl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ + return xy.hi + vzs + scalbnl(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised correctly, example in downward rounding: + * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L) + */ + long double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbnl(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return scalbnl(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/j0.c b/third_party/ulib/musl/third_party/math/j0.c new file mode 100644 index 000000000..a98bcd4d9 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/j0.c @@ -0,0 +1,386 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +#include "libm.h" + +static double pzero(double), qzero(double); + +static const double invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ + tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +static double common(uint32_t ix, double x, int y0) { + double s, c, ss, cc, z; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if (y0) c = -c; + cc = s + c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if (ix < 0x7fe00000) { + ss = s - c; + z = -cos(2 * x); + if (s * c < 0) + cc = z / ss; + else + ss = z / cc; + if (ix < 0x48000000) { + if (y0) ss = -ss; + cc = pzero(x) * cc - qzero(x) * ss; + } + } + return invsqrtpi * cc / sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +static const double R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */ + R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */ + R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */ + R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */ + S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */ + S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */ + S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ + S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +double j0(double x) { + double z, r, s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if (ix >= 0x7ff00000) return 1 / (x * x); + x = fabs(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix, x, 0); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if (ix >= 0x3f200000) { /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1 + x / 2) * (1 - x / 2) + z * (r / s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if (ix >= 0x38000000) /* |x| >= 2**-127 */ + x = 0.25 * x * x; + return 1 - x; +} + +static const double u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */ + u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */ + u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */ + u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */ + u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */ + u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */ + u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */ + v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */ + v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */ + v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ + v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +double y0(double x) { + double z, u, v; + uint32_t ix, lx; + + EXTRACT_WORDS(ix, lx, x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix << 1 | lx) == 0) return -1 / 0.0; + if (ix >> 31) return 0 / 0.0; + if (ix >= 0x7ff00000) return 1 / x; + + if (ix >= 0x40000000) { /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix, x, 1); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if (ix >= 0x3e400000) { /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x * x; + u = u00 + z * (u01 + z * (u02 + z * (u03 + z * (u04 + z * (u05 + z * u06))))); + v = 1.0 + z * (v01 + z * (v02 + z * (v03 + z * v04))); + return u / v + tpi * (j0(x) * log(x)); + } + return u00 + tpi * log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const double pR8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +}; +static const double pS8[5] = { + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +}; + +static const double pR5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +}; +static const double pS5[5] = { + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +}; + +static const double pR3[6] = { + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +}; +static const double pS3[5] = { + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +}; + +static const double pR2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +}; +static const double pS2[5] = { + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +}; + +static double pzero(double x) { + const double *p, *q; + double_t z, r, s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000) { + p = pR8; + q = pS8; + } else if (ix >= 0x40122E8B) { + p = pR5; + q = pS5; + } else if (ix >= 0x4006DB6D) { + p = pR3; + q = pS3; + } else /*ix >= 0x40000000*/ { + p = pR2; + q = pS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const double qR8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +}; +static const double qS8[6] = { + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +}; + +static const double qR5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +}; +static const double qS5[6] = { + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +}; + +static const double qR3[6] = { + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +}; +static const double qS3[6] = { + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +}; + +static const double qR2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +}; +static const double qS2[6] = { + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +}; + +static double qzero(double x) { + const double *p, *q; + double_t s, r, z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000) { + p = qR8; + q = qS8; + } else if (ix >= 0x40122E8B) { + p = qR5; + q = qS5; + } else if (ix >= 0x4006DB6D) { + p = qR3; + q = qS3; + } else /*ix >= 0x40000000*/ { + p = qR2; + q = qS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-.125 + r / s) / x; +} diff --git a/third_party/ulib/musl/third_party/math/j0f.c b/third_party/ulib/musl/third_party/math/j0f.c new file mode 100644 index 000000000..db5378187 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/j0f.c @@ -0,0 +1,325 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float pzerof(float), qzerof(float); + +static const float invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ + tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y0) { + float z, s, c, ss, cc; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if (y0) c = -c; + cc = s + c; + if (ix < 0x7f000000) { + ss = s - c; + z = -cosf(2 * x); + if (s * c < 0) + cc = z / ss; + else + ss = z / cc; + if (ix < 0x58800000) { + if (y0) ss = -ss; + cc = pzerof(x) * cc - qzerof(x) * ss; + } + } + return invsqrtpi * cc / sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +static const float R02 = 1.5625000000e-02, /* 0x3c800000 */ + R03 = -1.8997929874e-04, /* 0xb947352e */ + R04 = 1.8295404516e-06, /* 0x35f58e88 */ + R05 = -4.6183270541e-09, /* 0xb19eaf3c */ + S01 = 1.5619102865e-02, /* 0x3c7fe744 */ + S02 = 1.1692678527e-04, /* 0x38f53697 */ + S03 = 5.1354652442e-07, /* 0x3509daa6 */ + S04 = 1.1661400734e-09; /* 0x30a045e8 */ + +float j0f(float x) { + float z, r, s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x7f800000) return 1 / (x * x); + x = fabsf(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, 0); + } + if (ix >= 0x3a000000) { /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1 + x / 2) * (1 - x / 2) + z * (r / s); + } + if (ix >= 0x21800000) /* |x| >= 2**-60 */ + x = 0.25f * x * x; + return 1 - x; +} + +static const float u00 = -7.3804296553e-02, /* 0xbd9726b5 */ + u01 = 1.7666645348e-01, /* 0x3e34e80d */ + u02 = -1.3818567619e-02, /* 0xbc626746 */ + u03 = 3.4745343146e-04, /* 0x39b62a69 */ + u04 = -3.8140706238e-06, /* 0xb67ff53c */ + u05 = 1.9559013964e-08, /* 0x32a802ba */ + u06 = -3.9820518410e-11, /* 0xae2f21eb */ + v01 = 1.2730483897e-02, /* 0x3c509385 */ + v02 = 7.6006865129e-05, /* 0x389f65e0 */ + v03 = 2.5915085189e-07, /* 0x348b216c */ + v04 = 4.4111031494e-10; /* 0x2ff280c2 */ + +float y0f(float x) { + float z, u, v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) return -1 / 0.0f; + if (ix >> 31) return 0 / 0.0f; + if (ix >= 0x7f800000) return 1 / x; + if (ix >= 0x40000000) { /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix, x, 1); + } + if (ix >= 0x39000000) { /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x * x; + u = u00 + z * (u01 + z * (u02 + z * (u03 + z * (u04 + z * (u05 + z * u06))))); + v = 1 + z * (v01 + z * (v02 + z * (v03 + z * v04))); + return u / v + tpi * (j0f(x) * logf(x)); + } + return u00 + tpi * logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const float pR8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +}; +static const float pS8[5] = { + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +}; +static const float pR5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +}; +static const float pS5[5] = { + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +}; + +static const float pR3[6] = { + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +}; +static const float pS3[5] = { + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +}; + +static const float pR2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +}; +static const float pS2[5] = { + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +}; + +static float pzerof(float x) { + const float *p, *q; + float_t z, r, s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000) { + p = pR8; + q = pS8; + } else if (ix >= 0x40f71c58) { + p = pR5; + q = pS5; + } else if (ix >= 0x4036db68) { + p = pR3; + q = pS3; + } else /*ix >= 0x40000000*/ { + p = pR2; + q = pS2; + } + z = 1.0f / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0f + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0f + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const float qR8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +}; +static const float qS8[6] = { + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +}; + +static const float qR5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +}; +static const float qS5[6] = { + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +}; + +static const float qR3[6] = { + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +}; +static const float qS3[6] = { + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +}; + +static const float qR2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +}; +static const float qS2[6] = { + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +}; + +static float qzerof(float x) { + const float *p, *q; + float_t s, r, z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000) { + p = qR8; + q = qS8; + } else if (ix >= 0x40f71c58) { + p = qR5; + q = qS5; + } else if (ix >= 0x4036db68) { + p = qR3; + q = qS3; + } else /*ix >= 0x40000000*/ { + p = qR2; + q = qS2; + } + z = 1.0f / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0f + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-.125f + r / s) / x; +} diff --git a/third_party/ulib/musl/third_party/math/j1.c b/third_party/ulib/musl/third_party/math/j1.c new file mode 100644 index 000000000..a4d6ac59c --- /dev/null +++ b/third_party/ulib/musl/third_party/math/j1.c @@ -0,0 +1,372 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +#include "libm.h" + +static double pone(double), qone(double); + +static const double invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ + tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +static double common(uint32_t ix, double x, int y1, int sign) { + double z, s, c, ss, cc; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if (y1) s = -s; + c = cos(x); + cc = s - c; + if (ix < 0x7fe00000) { + /* avoid overflow in 2*x */ + ss = -s - c; + z = cos(2 * x); + if (s * c > 0) + cc = z / ss; + else + ss = z / cc; + if (ix < 0x48000000) { + if (y1) ss = -ss; + cc = pone(x) * cc - qone(x) * ss; + } + } + if (sign) cc = -cc; + return invsqrtpi * cc / sqrt(x); +} + +/* R0/S0 on [0,2] */ +static const double r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */ + r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */ + r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ + r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */ + s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */ + s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */ + s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */ + s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ + s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +double j1(double x) { + double z, r, s; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) return 1 / (x * x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabs(x), 0, sign); + if (ix >= 0x38000000) { /* |x| >= 2**-127 */ + z = x * x; + r = z * (r00 + z * (r01 + z * (r02 + z * r03))); + s = 1 + z * (s01 + z * (s02 + z * (s03 + z * (s04 + z * s05)))); + z = r / s; + } else + /* avoid underflow, raise inexact if x!=0 */ + z = x; + return (0.5 + z) * x; +} + +static const double U0[5] = { + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +}; +static const double V0[5] = { + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +}; + +double y1(double x) { + double z, u, v; + uint32_t ix, lx; + + EXTRACT_WORDS(ix, lx, x); + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if ((ix << 1 | lx) == 0) return -1 / 0.0; + if (ix >> 31) return 0 / 0.0; + if (ix >= 0x7ff00000) return 1 / x; + + if (ix >= 0x40000000) /* x >= 2 */ + return common(ix, x, 1, 0); + if (ix < 0x3c900000) /* x < 2**-54 */ + return -tpi / x; + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + tpi * (j1(x) * log(x) - 1 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const double pr8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +}; +static const double ps8[5] = { + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +}; + +static const double pr5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +}; +static const double ps5[5] = { + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +}; + +static const double pr3[6] = { + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +}; +static const double ps3[5] = { + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +}; + +static const double pr2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +}; +static const double ps2[5] = { + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +}; + +static double pone(double x) { + const double *p, *q; + double_t z, r, s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000) { + p = pr8; + q = ps8; + } else if (ix >= 0x40122E8B) { + p = pr5; + q = ps5; + } else if (ix >= 0x4006DB6D) { + p = pr3; + q = ps3; + } else /*ix >= 0x40000000*/ { + p = pr2; + q = ps2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const double qr8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +}; +static const double qs8[6] = { + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +}; + +static const double qr5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +}; +static const double qs5[6] = { + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +}; + +static const double qr3[6] = { + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +}; +static const double qs3[6] = { + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +}; + +static const double qr2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +}; +static const double qs2[6] = { + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +}; + +static double qone(double x) { + const double *p, *q; + double_t s, r, z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000) { + p = qr8; + q = qs8; + } else if (ix >= 0x40122E8B) { + p = qr5; + q = qs5; + } else if (ix >= 0x4006DB6D) { + p = qr3; + q = qs3; + } else /*ix >= 0x40000000*/ { + p = qr2; + q = qs2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (.375 + r / s) / x; +} diff --git a/third_party/ulib/musl/third_party/math/j1f.c b/third_party/ulib/musl/third_party/math/j1f.c new file mode 100644 index 000000000..c189a6ac0 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/j1f.c @@ -0,0 +1,321 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float ponef(float), qonef(float); + +static const float invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ + tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y1, int sign) { + double z, s, c, ss, cc; + + s = sinf(x); + if (y1) s = -s; + c = cosf(x); + cc = s - c; + if (ix < 0x7f000000) { + ss = -s - c; + z = cosf(2 * x); + if (s * c > 0) + cc = z / ss; + else + ss = z / cc; + if (ix < 0x58800000) { + if (y1) ss = -ss; + cc = ponef(x) * cc - qonef(x) * ss; + } + } + if (sign) cc = -cc; + return invsqrtpi * cc / sqrtf(x); +} + +/* R0/S0 on [0,2] */ +static const float r00 = -6.2500000000e-02, /* 0xbd800000 */ + r01 = 1.4070566976e-03, /* 0x3ab86cfd */ + r02 = -1.5995563444e-05, /* 0xb7862e36 */ + r03 = 4.9672799207e-08, /* 0x335557d2 */ + s01 = 1.9153760746e-02, /* 0x3c9ce859 */ + s02 = 1.8594678841e-04, /* 0x3942fab6 */ + s03 = 1.1771846857e-06, /* 0x359dffc2 */ + s04 = 5.0463624390e-09, /* 0x31ad6446 */ + s05 = 1.2354227016e-11; /* 0x2d59567e */ + +float j1f(float x) { + float z, r, s; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) return 1 / (x * x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabsf(x), 0, sign); + if (ix >= 0x32000000) { /* |x| >= 2**-27 */ + z = x * x; + r = z * (r00 + z * (r01 + z * (r02 + z * r03))); + s = 1 + z * (s01 + z * (s02 + z * (s03 + z * (s04 + z * s05)))); + z = 0.5f + r / s; + } else + /* raise inexact if x!=0 */ + z = 0.5f + x; + return z * x; +} + +static const float U0[5] = { + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +}; +static const float V0[5] = { + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +}; + +float y1f(float x) { + float z, u, v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) return -1 / 0.0f; + if (ix >> 31) return 0 / 0.0f; + if (ix >= 0x7f800000) return 1 / x; + if (ix >= 0x40000000) /* |x| >= 2.0 */ + return common(ix, x, 1, 0); + if (ix < 0x32000000) /* x < 2**-27 */ + return -tpi / x; + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0f + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + tpi * (j1f(x) * logf(x) - 1.0f / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const float pr8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +}; +static const float ps8[5] = { + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +}; + +static const float pr5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +}; +static const float ps5[5] = { + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +}; + +static const float pr3[6] = { + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +}; +static const float ps3[5] = { + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +}; + +static const float pr2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +}; +static const float ps2[5] = { + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +}; + +static float ponef(float x) { + const float *p, *q; + float_t z, r, s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000) { + p = pr8; + q = ps8; + } else if (ix >= 0x40f71c58) { + p = pr5; + q = ps5; + } else if (ix >= 0x4036db68) { + p = pr3; + q = ps3; + } else /*ix >= 0x40000000*/ { + p = pr2; + q = ps2; + } + z = 1.0f / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0f + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0f + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const float qr8[6] = { + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +}; +static const float qs8[6] = { + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +}; + +static const float qr5[6] = { + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +}; +static const float qs5[6] = { + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +}; + +static const float qr3[6] = { + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +}; +static const float qs3[6] = { + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +}; + +static const float qr2[6] = { + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +}; +static const float qs2[6] = { + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +}; + +static float qonef(float x) { + const float *p, *q; + float_t s, r, z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000) { + p = qr8; + q = qs8; + } else if (ix >= 0x40f71c58) { + p = qr5; + q = qs5; + } else if (ix >= 0x4036db68) { + p = qr3; + q = qs3; + } else /*ix >= 0x40000000*/ { + p = qr2; + q = qs2; + } + z = 1.0f / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0f + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (.375f + r / s) / x; +} diff --git a/third_party/ulib/musl/third_party/math/jn.c b/third_party/ulib/musl/third_party/math/jn.c new file mode 100644 index 000000000..5ad93c5fc --- /dev/null +++ b/third_party/ulib/musl/third_party/math/jn.c @@ -0,0 +1,288 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +#include "libm.h" + +static const double invsqrtpi = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +double jn(int n, double x) { + uint32_t ix, lx; + int nm1, i, sign; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if ((ix | (lx | -lx) >> 31) > 0x7ff00000) /* nan */ + return x; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if (n == 0) return j0(x); + if (n < 0) { + nm1 = -(n + 1); + x = -x; + sign ^= 1; + } else + nm1 = n - 1; + if (nm1 == 0) return j1(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if ((ix | lx) == 0 || ix == 0x7ff00000) /* if x is 0 or inf */ + b = 0.0; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch (nm1 & 3) { + case 0: + temp = -cos(x) + sin(x); + break; + case 1: + temp = -cos(x) - sin(x); + break; + case 2: + temp = cos(x) - sin(x); + break; + default: + case 3: + temp = cos(x) + sin(x); + break; + } + b = invsqrtpi * temp / sqrt(x); + } else { + a = j0(x); + b = j1(x); + for (i = 0; i < nm1;) { + i++; + temp = b; + b = b * (2.0 * i / x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if (ix < 0x3e100000) { /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if (nm1 > 32) /* underflow */ + b = 0.0; + else { + temp = x * 0.5; + b = temp; + a = 1.0; + for (i = 2; i <= nm1 + 1; i++) { + a *= (double)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + double t, q0, q1, w, h, z, tmp, nf; + int k; + + nf = nm1 + 1.0; + w = 2 * nf / x; + h = 2 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while (q1 < 1.0e9) { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t = 0.0, i = k; i >= 0; i--) + t = 1 / (2 * (i + nf) / x - t); + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if (tmp < 7.09782712893383973096e+02) { + for (i = nm1; i > 0; i--) { + temp = b; + b = b * (2.0 * i) / x - a; + a = temp; + } + } else { + for (i = nm1; i > 0; i--) { + temp = b; + b = b * (2.0 * i) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p500) { + a /= b; + t /= b; + b = 1.0; + } + } + } + z = j0(x); + w = j1(x); + if (fabs(z) >= fabs(w)) + b = t * z / b; + else + b = t * w / a; + } + } + return sign ? -b : b; +} + +double yn(int n, double x) { + uint32_t ix, lx, ib; + int nm1, sign, i; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if ((ix | (lx | -lx) >> 31) > 0x7ff00000) /* nan */ + return x; + if (sign && (ix | lx) != 0) /* x < 0 */ + return 0 / 0.0; + if (ix == 0x7ff00000) return 0.0; + + if (n == 0) return y0(x); + if (n < 0) { + nm1 = -(n + 1); + sign = n & 1; + } else { + nm1 = n - 1; + sign = 0; + } + if (nm1 == 0) return sign ? -y1(x) : y1(x); + + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch (nm1 & 3) { + case 0: + temp = -sin(x) - cos(x); + break; + case 1: + temp = -sin(x) + cos(x); + break; + case 2: + temp = sin(x) + cos(x); + break; + default: + case 3: + temp = sin(x) - cos(x); + break; + } + b = invsqrtpi * temp / sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + GET_HIGH_WORD(ib, b); + for (i = 0; i < nm1 && ib != 0xfff00000;) { + i++; + temp = b; + b = (2.0 * i / x) * b - a; + GET_HIGH_WORD(ib, b); + a = temp; + } + } + return sign ? -b : b; +} diff --git a/third_party/ulib/musl/third_party/math/jnf.c b/third_party/ulib/musl/third_party/math/jnf.c new file mode 100644 index 000000000..1a35ad6e4 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/jnf.c @@ -0,0 +1,195 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +float jnf(int n, float x) { + uint32_t ix; + int nm1, sign, i; + float a, b, temp; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if (n == 0) return j0f(x); + if (n < 0) { + nm1 = -(n + 1); + x = -x; + sign ^= 1; + } else + nm1 = n - 1; + if (nm1 == 0) return j1f(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if (ix == 0 || ix == 0x7f800000) /* if x is 0 or inf */ + b = 0.0f; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + for (i = 0; i < nm1;) { + i++; + temp = b; + b = b * (2.0f * i / x) - a; + a = temp; + } + } else { + if (ix < 0x35800000) { /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if (nm1 > 8) /* underflow */ + nm1 = 8; + temp = 0.5f * x; + b = temp; + a = 1.0f; + for (i = 2; i <= nm1 + 1; i++) { + a *= (float)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b / a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + float t, q0, q1, w, h, z, tmp, nf; + int k; + + nf = nm1 + 1.0f; + w = 2 * nf / x; + h = 2 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0f; + k = 1; + while (q1 < 1.0e4f) { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t = 0.0f, i = k; i >= 0; i--) + t = 1.0f / (2 * (i + nf) / x - t); + a = t; + b = 1.0f; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if (tmp < 88.721679688f) { + for (i = nm1; i > 0; i--) { + temp = b; + b = 2.0f * i * b / x - a; + a = temp; + } + } else { + for (i = nm1; i > 0; i--) { + temp = b; + b = 2.0f * i * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p60f) { + a /= b; + t /= b; + b = 1.0f; + } + } + } + z = j0f(x); + w = j1f(x); + if (fabsf(z) >= fabsf(w)) + b = t * z / b; + else + b = t * w / a; + } + } + return sign ? -b : b; +} + +float ynf(int n, float x) { + uint32_t ix, ib; + int nm1, sign, i; + float a, b, temp; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + if (sign && ix != 0) /* x < 0 */ + return 0 / 0.0f; + if (ix == 0x7f800000) return 0.0f; + + if (n == 0) return y0f(x); + if (n < 0) { + nm1 = -(n + 1); + sign = n & 1; + } else { + nm1 = n - 1; + sign = 0; + } + if (nm1 == 0) return sign ? -y1f(x) : y1f(x); + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + GET_FLOAT_WORD(ib, b); + for (i = 0; i < nm1 && ib != 0xff800000;) { + i++; + temp = b; + b = (2.0f * i / x) * b - a; + GET_FLOAT_WORD(ib, b); + a = temp; + } + return sign ? -b : b; +} diff --git a/third_party/ulib/musl/third_party/math/lgamma_r.c b/third_party/ulib/musl/third_party/math/lgamma_r.c new file mode 100644 index 000000000..955764ce2 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/lgamma_r.c @@ -0,0 +1,290 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include "libc.h" +#include "libm.h" + +static const double pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ + a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ + a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ + a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ + a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ + a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ + a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ + a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ + a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ + a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ + a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ + a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ + a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ + tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ + tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ + /* tt = -(tail of tf) */ + tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ + t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ + t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ + t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ + t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ + t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ + t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ + t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ + t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ + t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ + t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ + t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ + t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ + t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ + t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ + t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ + u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ + u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ + u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ + u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ + u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ + u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ + v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ + v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ + v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ + v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ + v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ + s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ + s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ + s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ + s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ + s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ + s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ + s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ + r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ + r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ + r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ + r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ + r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ + r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ + w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ + w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ + w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ + w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ + w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ + w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ + w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sin_pi(double x) { + int n; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (int)(x * 4.0); + n = (n + 1) / 2; + x -= n * 0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: + return __sin(x, 0.0, 0); + case 1: + return __cos(x, 0.0); + case 2: + return __sin(-x, 0.0, 0); + case 3: + return -__cos(x, 0.0); + } +} + +double __lgamma_r(double x, int* signgamp) { + union { + double f; + uint64_t i; + } u = {x}; + double_t t, y, z, nadj, p, p1, p2, p3, q, r, w; + uint32_t ix; + int sign, i; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i >> 63; + ix = u.i >> 32 & 0x7fffffff; + if (ix >= 0x7ff00000) return x * x; + if (ix < (0x3ff - 70) << 20) { /* |x|<2**-70, return -log(|x|) */ + if (sign) { + x = -x; + *signgamp = -1; + } + return -log(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) /* -integer */ + return 1.0 / (x - x); + if (t > 0.0) + *signgamp = -1; + else + t = -t; + nadj = log(pi / (t * x)); + } + + /* purge off 1 and 2 */ + if ((ix == 0x3ff00000 || ix == 0x40000000) && (uint32_t)u.i == 0) r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if (ix >= 0x3FE76944) { + y = 1.0 - x; + i = 0; + } else if (ix >= 0x3FCDA661) { + y = x - (tc - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3FFBB4C3) { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if (ix >= 0x3FF3B4C4) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + z = y * y; + p1 = a0 + z * (a2 + z * (a4 + z * (a6 + z * (a8 + z * a10)))); + p2 = z * (a1 + z * (a3 + z * (a5 + z * (a7 + z * (a9 + z * a11))))); + p = y * p1 + p2; + r += (p - 0.5 * y); + break; + case 1: + z = y * y; + w = z * y; + p1 = t0 + w * (t3 + w * (t6 + w * (t9 + w * t12))); /* parallel comp */ + p2 = t1 + w * (t4 + w * (t7 + w * (t10 + w * t13))); + p3 = t2 + w * (t5 + w * (t8 + w * (t11 + w * t14))); + p = z * p1 - (tt - w * (p2 + y * p3)); + r += tf + p; + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * u5))))); + p2 = 1.0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * v5)))); + r += -0.5 * y + p1 / p2; + } + } else if (ix < 0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = 1.0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= y + 6.0; /* FALLTHRU */ + case 6: + z *= y + 5.0; /* FALLTHRU */ + case 5: + z *= y + 4.0; /* FALLTHRU */ + case 4: + z *= y + 3.0; /* FALLTHRU */ + case 3: + z *= y + 2.0; /* FALLTHRU */ + r += log(z); + break; + } + } else if (ix < 0x43900000) { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * w6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + if (sign) r = nadj - r; + return r; +} + +weak_alias(__lgamma_r, lgamma_r); diff --git a/third_party/ulib/musl/third_party/math/lgammaf_r.c b/third_party/ulib/musl/third_party/math/lgammaf_r.c new file mode 100644 index 000000000..9b05500cf --- /dev/null +++ b/third_party/ulib/musl/third_party/math/lgammaf_r.c @@ -0,0 +1,225 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libc.h" +#include "libm.h" + +static const float pi = 3.1415927410e+00, /* 0x40490fdb */ + a0 = 7.7215664089e-02, /* 0x3d9e233f */ + a1 = 3.2246702909e-01, /* 0x3ea51a66 */ + a2 = 6.7352302372e-02, /* 0x3d89f001 */ + a3 = 2.0580807701e-02, /* 0x3ca89915 */ + a4 = 7.3855509982e-03, /* 0x3bf2027e */ + a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ + a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ + a7 = 5.1006977446e-04, /* 0x3a05b634 */ + a8 = 2.2086278477e-04, /* 0x39679767 */ + a9 = 1.0801156895e-04, /* 0x38e28445 */ + a10 = 2.5214456400e-05, /* 0x37d383a2 */ + a11 = 4.4864096708e-05, /* 0x383c2c75 */ + tc = 1.4616321325e+00, /* 0x3fbb16c3 */ + tf = -1.2148628384e-01, /* 0xbdf8cdcd */ + /* tt = -(tail of tf) */ + tt = 6.6971006518e-09, /* 0x31e61c52 */ + t0 = 4.8383611441e-01, /* 0x3ef7b95e */ + t1 = -1.4758771658e-01, /* 0xbe17213c */ + t2 = 6.4624942839e-02, /* 0x3d845a15 */ + t3 = -3.2788541168e-02, /* 0xbd064d47 */ + t4 = 1.7970675603e-02, /* 0x3c93373d */ + t5 = -1.0314224288e-02, /* 0xbc28fcfe */ + t6 = 6.1005386524e-03, /* 0x3bc7e707 */ + t7 = -3.6845202558e-03, /* 0xbb7177fe */ + t8 = 2.2596477065e-03, /* 0x3b141699 */ + t9 = -1.4034647029e-03, /* 0xbab7f476 */ + t10 = 8.8108185446e-04, /* 0x3a66f867 */ + t11 = -5.3859531181e-04, /* 0xba0d3085 */ + t12 = 3.1563205994e-04, /* 0x39a57b6b */ + t13 = -3.1275415677e-04, /* 0xb9a3f927 */ + t14 = 3.3552918467e-04, /* 0x39afe9f7 */ + u0 = -7.7215664089e-02, /* 0xbd9e233f */ + u1 = 6.3282704353e-01, /* 0x3f2200f4 */ + u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ + u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ + u4 = 2.2896373272e-01, /* 0x3e6a7578 */ + u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ + v1 = 2.4559779167e+00, /* 0x401d2ebe */ + v2 = 2.1284897327e+00, /* 0x4008392d */ + v3 = 7.6928514242e-01, /* 0x3f44efdf */ + v4 = 1.0422264785e-01, /* 0x3dd572af */ + v5 = 3.2170924824e-03, /* 0x3b52d5db */ + s0 = -7.7215664089e-02, /* 0xbd9e233f */ + s1 = 2.1498242021e-01, /* 0x3e5c245a */ + s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ + s3 = 1.4635047317e-01, /* 0x3e15dce6 */ + s4 = 2.6642270386e-02, /* 0x3cda40e4 */ + s5 = 1.8402845599e-03, /* 0x3af135b4 */ + s6 = 3.1947532989e-05, /* 0x3805ff67 */ + r1 = 1.3920053244e+00, /* 0x3fb22d3b */ + r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ + r3 = 1.7193385959e-01, /* 0x3e300f6e */ + r4 = 1.8645919859e-02, /* 0x3c98bf54 */ + r5 = 7.7794247773e-04, /* 0x3a4beed6 */ + r6 = 7.3266842264e-06, /* 0x36f5d7bd */ + w0 = 4.1893854737e-01, /* 0x3ed67f1d */ + w1 = 8.3333335817e-02, /* 0x3daaaaab */ + w2 = -2.7777778450e-03, /* 0xbb360b61 */ + w3 = 7.9365057172e-04, /* 0x3a500cfd */ + w4 = -5.9518753551e-04, /* 0xba1c065c */ + w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ + w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static float sin_pi(float x) { + double_t y; + int n; + + /* spurious inexact if odd int */ + x = 2 * (x * 0.5f - floorf(x * 0.5f)); /* x mod 2.0 */ + + n = (int)(x * 4); + n = (n + 1) / 2; + y = x - n * 0.5f; + y *= 3.14159265358979323846; + switch (n) { + default: /* case 4: */ + case 0: + return __sindf(y); + case 1: + return __cosdf(y); + case 2: + return __sindf(-y); + case 3: + return -__cosdf(y); + } +} + +float __lgammaf_r(float x, int* signgamp) { + union { + float f; + uint32_t i; + } u = {x}; + float t, y, z, nadj, p, p1, p2, p3, q, r, w; + uint32_t ix; + int i, sign; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i >> 31; + ix = u.i & 0x7fffffff; + if (ix >= 0x7f800000) return x * x; + if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */ + if (sign) { + *signgamp = -1; + x = -x; + } + return -logf(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0f) /* -integer */ + return 1.0f / (x - x); + if (t > 0.0f) + *signgamp = -1; + else + t = -t; + nadj = logf(pi / (t * x)); + } + + /* purge off 1 and 2 */ + if (ix == 0x3f800000 || ix == 0x40000000) r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if (ix >= 0x3f3b4a20) { + y = 1.0f - x; + i = 0; + } else if (ix >= 0x3e6d3308) { + y = x - (tc - 1.0f); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0f; + if (ix >= 0x3fdda618) { /* [1.7316,2] */ + y = 2.0f - x; + i = 0; + } else if (ix >= 0x3F9da620) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0f; + i = 2; + } + } + switch (i) { + case 0: + z = y * y; + p1 = a0 + z * (a2 + z * (a4 + z * (a6 + z * (a8 + z * a10)))); + p2 = z * (a1 + z * (a3 + z * (a5 + z * (a7 + z * (a9 + z * a11))))); + p = y * p1 + p2; + r += p - 0.5f * y; + break; + case 1: + z = y * y; + w = z * y; + p1 = t0 + w * (t3 + w * (t6 + w * (t9 + w * t12))); /* parallel comp */ + p2 = t1 + w * (t4 + w * (t7 + w * (t10 + w * t13))); + p3 = t2 + w * (t5 + w * (t8 + w * (t11 + w * t14))); + p = z * p1 - (tt - w * (p2 + y * p3)); + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * u5))))); + p2 = 1.0f + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * v5)))); + r += -0.5f * y + p1 / p2; + } + } else if (ix < 0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x - (float)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = 1.0f + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6))))); + r = 0.5f * y + p / q; + z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= y + 6.0f; /* FALLTHRU */ + case 6: + z *= y + 5.0f; /* FALLTHRU */ + case 5: + z *= y + 4.0f; /* FALLTHRU */ + case 4: + z *= y + 3.0f; /* FALLTHRU */ + case 3: + z *= y + 2.0f; /* FALLTHRU */ + r += logf(z); + break; + } + } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0f / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * w6))))); + r = (x - 0.5f) * (t - 1.0f) + w; + } else /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0f); + if (sign) r = nadj - r; + return r; +} + +weak_alias(__lgammaf_r, lgammaf_r); diff --git a/third_party/ulib/musl/third_party/math/lgammal.c b/third_party/ulib/musl/third_party/math/lgammal.c new file mode 100644 index 000000000..f0a03135c --- /dev/null +++ b/third_party/ulib/musl/third_party/math/lgammal.c @@ -0,0 +1,349 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_lgammal.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* lgammal(x) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1)=lgamma(2)=0 + * lgamma(x) ~ -log(x) for tiny x + * lgamma(0) = lgamma(inf) = inf + * lgamma(-integer) = +-inf + * + */ + +#define _GNU_SOURCE +#include "libc.h" +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double __lgamma_r(double x, int* sg); + +long double __lgammal_r(long double x, int* sg) { + return __lgamma_r(x, sg); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double + pi = 3.14159265358979323846264L, + + /* lgam(1+x) = 0.5 x + x a(x)/b(x) + -0.268402099609375 <= x <= 0 + peak relative error 6.6e-22 */ + a0 = -6.343246574721079391729402781192128239938E2L, + a1 = 1.856560238672465796768677717168371401378E3L, + a2 = 2.404733102163746263689288466865843408429E3L, + a3 = 8.804188795790383497379532868917517596322E2L, + a4 = 1.135361354097447729740103745999661157426E2L, + a5 = 3.766956539107615557608581581190400021285E0L, + + b0 = 8.214973713960928795704317259806842490498E3L, + b1 = 1.026343508841367384879065363925870888012E4L, + b2 = 4.553337477045763320522762343132210919277E3L, + b3 = 8.506975785032585797446253359230031874803E2L, + b4 = 6.042447899703295436820744186992189445813E1L, + /* b5 = 1.000000000000000000000000000000000000000E0 */ + + tc = 1.4616321449683623412626595423257213284682E0L, + tf = -1.2148629053584961146050602565082954242826E-1, /* double precision */ + /* tt = (tail of tf), i.e. tf + tt has extended precision. */ + tt = 3.3649914684731379602768989080467587736363E-18L, + /* lgam ( 1.4616321449683623412626595423257213284682E0 ) = + -1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */ + + /* lgam (x + tc) = tf + tt + x g(x)/h(x) + -0.230003726999612341262659542325721328468 <= x + <= 0.2699962730003876587373404576742786715318 + peak relative error 2.1e-21 */ + g0 = 3.645529916721223331888305293534095553827E-18L, + g1 = 5.126654642791082497002594216163574795690E3L, + g2 = 8.828603575854624811911631336122070070327E3L, + g3 = 5.464186426932117031234820886525701595203E3L, + g4 = 1.455427403530884193180776558102868592293E3L, + g5 = 1.541735456969245924860307497029155838446E2L, + g6 = 4.335498275274822298341872707453445815118E0L, + + h0 = 1.059584930106085509696730443974495979641E4L, + h1 = 2.147921653490043010629481226937850618860E4L, + h2 = 1.643014770044524804175197151958100656728E4L, + h3 = 5.869021995186925517228323497501767586078E3L, + h4 = 9.764244777714344488787381271643502742293E2L, + h5 = 6.442485441570592541741092969581997002349E1L, + /* h6 = 1.000000000000000000000000000000000000000E0 */ + + /* lgam (x+1) = -0.5 x + x u(x)/v(x) + -0.100006103515625 <= x <= 0.231639862060546875 + peak relative error 1.3e-21 */ + u0 = -8.886217500092090678492242071879342025627E1L, + u1 = 6.840109978129177639438792958320783599310E2L, + u2 = 2.042626104514127267855588786511809932433E3L, + u3 = 1.911723903442667422201651063009856064275E3L, + u4 = 7.447065275665887457628865263491667767695E2L, + u5 = 1.132256494121790736268471016493103952637E2L, + u6 = 4.484398885516614191003094714505960972894E0L, + + v0 = 1.150830924194461522996462401210374632929E3L, + v1 = 3.399692260848747447377972081399737098610E3L, + v2 = 3.786631705644460255229513563657226008015E3L, + v3 = 1.966450123004478374557778781564114347876E3L, + v4 = 4.741359068914069299837355438370682773122E2L, + v5 = 4.508989649747184050907206782117647852364E1L, + /* v6 = 1.000000000000000000000000000000000000000E0 */ + + /* lgam (x+2) = .5 x + x s(x)/r(x) + 0 <= x <= 1 + peak relative error 7.2e-22 */ + s0 = 1.454726263410661942989109455292824853344E6L, + s1 = -3.901428390086348447890408306153378922752E6L, + s2 = -6.573568698209374121847873064292963089438E6L, + s3 = -3.319055881485044417245964508099095984643E6L, + s4 = -7.094891568758439227560184618114707107977E5L, + s5 = -6.263426646464505837422314539808112478303E4L, + s6 = -1.684926520999477529949915657519454051529E3L, + + r0 = -1.883978160734303518163008696712983134698E7L, + r1 = -2.815206082812062064902202753264922306830E7L, + r2 = -1.600245495251915899081846093343626358398E7L, + r3 = -4.310526301881305003489257052083370058799E6L, + r4 = -5.563807682263923279438235987186184968542E5L, + r5 = -3.027734654434169996032905158145259713083E4L, + r6 = -4.501995652861105629217250715790764371267E2L, + /* r6 = 1.000000000000000000000000000000000000000E0 */ + + /* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2) + x >= 8 + Peak relative error 1.51e-21 + w0 = LS2PI - 0.5 */ + w0 = 4.189385332046727417803e-1L, w1 = 8.333333333333331447505E-2L, + w2 = -2.777777777750349603440E-3L, w3 = 7.936507795855070755671E-4L, + w4 = -5.952345851765688514613E-4L, w5 = 8.412723297322498080632E-4L, + w6 = -1.880801938119376907179E-3L, w7 = 4.885026142432270781165E-3L; + +/* sin(pi*x) assuming x > 2^-1000, if sin(pi*x)==0 the sign is arbitrary */ +static long double sin_pi(long double x) { + int n; + + /* spurious inexact if odd int */ + x *= 0.5; + x = 2.0 * (x - floorl(x)); /* x mod 2.0 */ + + n = (int)(x * 4.0); + n = (n + 1) / 2; + x -= n * 0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: + return __sinl(x, 0.0, 0); + case 1: + return __cosl(x, 0.0); + case 2: + return __sinl(-x, 0.0, 0); + case 3: + return -__cosl(x, 0.0); + } +} + +long double __lgammal_r(long double x, int* sg) { + long double t, y, z, nadj, p, p1, p2, q, r, w; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU) << 16 | u.i.m >> 48; + int sign = u.i.se >> 15; + int i; + + *sg = 1; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + if (ix >= 0x7fff0000) return x * x; + if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */ + if (sign) { + *sg = -1; + x = -x; + } + return -logl(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) return 1.0 / (x - x); /* -integer */ + if (t > 0.0) + *sg = -1; + else + t = -t; + nadj = logl(pi / (t * x)); + } + + /* purge off 1 and 2 (so the sign is ok with downward rounding) */ + if ((ix == 0x3fff8000 || ix == 0x40008000) && u.i.m == 0) { + r = 0; + } else if (ix < 0x40008000) { /* x < 2.0 */ + if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */ + /* lgamma(x) = lgamma(x+1) - log(x) */ + r = -logl(x); + if (ix >= 0x3ffebb4a) { /* 7.31597900390625e-1 */ + y = x - 1.0; + i = 0; + } else if (ix >= 0x3ffced33) { /* 2.31639862060546875e-1 */ + y = x - (tc - 1.0); + i = 1; + } else { /* x < 0.23 */ + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3fffdda6) { /* 1.73162841796875 */ + /* [1.7316,2] */ + y = x - 2.0; + i = 0; + } else if (ix >= 0x3fff9da6) { /* 1.23162841796875 */ + /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + /* [0.9, 1.23] */ + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5)))); + p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y)))); + r += 0.5 * y + y * p1 / p2; + break; + case 1: + p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6))))); + p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y))))); + p = tt + y * p1 / p2; + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6)))))); + p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y))))); + r += (-0.5 * y + p1 / p2); + } + } else if (ix < 0x40028000) { /* 8.0 */ + /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y)))))); + r = 0.5 * y + p / q; + z = 1.0; + /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= (y + 6.0); /* FALLTHRU */ + case 6: + z *= (y + 5.0); /* FALLTHRU */ + case 5: + z *= (y + 4.0); /* FALLTHRU */ + case 4: + z *= (y + 3.0); /* FALLTHRU */ + case 3: + z *= (y + 2.0); /* FALLTHRU */ + r += logl(z); + break; + } + } else if (ix < 0x40418000) { /* 2^66 */ + /* 8.0 <= x < 2**66 */ + t = logl(x); + z = 1.0 / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7)))))); + r = (x - 0.5) * (t - 1.0) + w; + } else /* 2**66 <= x <= inf */ + r = x * (logl(x) - 1.0); + if (sign) r = nadj - r; + return r; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +double __lgamma_r(double x, int* sg); + +long double __lgammal_r(long double x, int* sg) { + return __lgamma_r(x, sg); +} +#endif + +extern int __signgam; + +long double lgammal(long double x) { + return __lgammal_r(x, &__signgam); +} + +weak_alias(__lgammal_r, lgammal_r); diff --git a/third_party/ulib/musl/third_party/math/log.c b/third_party/ulib/musl/third_party/math/log.c new file mode 100644 index 000000000..99b60beb0 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log.c @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +static const double ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ + ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log(double x) { + union { + double f; + uint64_t i; + } u = {x}; + double_t hfsq, f, s, z, R, w, t1, t2, dk; + uint32_t hx; + int k; + + hx = u.i >> 32; + k = 0; + if (hx < 0x00100000 || hx >> 31) { + if (u.i << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */ + if (hx >> 31) return (x - x) / 0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i >> 32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i << 32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx >> 20) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx << 32 | (u.i & 0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); + t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); + R = t2 + t1; + dk = k; + return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; +} diff --git a/third_party/ulib/musl/third_party/math/log10.c b/third_party/ulib/musl/third_party/math/log10.c new file mode 100644 index 000000000..2331bbedc --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log10.c @@ -0,0 +1,100 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +#include +#include + +static const double ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ + ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ + log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ + log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */ + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log10(double x) { + union { + double f; + uint64_t i; + } u = {x}; + double_t hfsq, f, s, z, R, w, t1, t2, dk, y, hi, lo, val_hi, val_lo; + uint32_t hx; + int k; + + hx = u.i >> 32; + k = 0; + if (hx < 0x00100000 || hx >> 31) { + if (u.i << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */ + if (hx >> 31) return (x - x) / 0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i >> 32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i << 32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx >> 20) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx << 32 | (u.i & 0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); + t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); + R = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1 << 32; + hi = u.f; + lo = f - hi - hfsq + s * (hfsq + R); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi * ivln10hi; + dk = k; + y = dk * log10_2hi; + val_lo = dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/third_party/ulib/musl/third_party/math/log10f.c b/third_party/ulib/musl/third_party/math/log10f.c new file mode 100644 index 000000000..bbe6c168d --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log10f.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +#include +#include + +static const float ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ + ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ + log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ + log10_2lo = 7.9034151668e-07, /* 0x355427db */ + /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ + Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ + Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ + Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ + Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log10f(float x) { + union { + float f; + uint32_t i; + } u = {x}; + float_t hfsq, f, s, z, R, w, t1, t2, dk, hi, lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix >> 31) { /* x < 2**-126 */ + if (ix << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */ + if (ix >> 31) return (x - x) / 0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix >> 23) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f / (2.0f + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * Lg4); + t2 = z * (Lg1 + w * Lg3); + R = t2 + t1; + hfsq = 0.5f * f * f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s * (hfsq + R); + dk = k; + return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi; +} diff --git a/third_party/ulib/musl/third_party/math/log10l.c b/third_party/ulib/musl/third_party/math/log10l.c new file mode 100644 index 000000000..5063ba5d1 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log10l.c @@ -0,0 +1,173 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log10l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Common logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.0e-20 2.6e-20 + * IEEE exp(+-10000) 30000 6.0e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns MINLOG + * log domain: x < 0; returns MINLOG + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log10l(long double x) { + return log10(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, 1.0767376367209449010438E1L, 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, 4.2401812743503691187826E2L, 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { + /* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, 1.9444210022760132894510E2L, 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, 2.0307734695595183428202E3L, 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, -7.1990767473014147232598E-1L, 1.0777257190312272158094E1L, + -3.5717684488096787370998E1L, +}; +static const long double S[4] = { + /* 1.00000000000000000000E0L,*/ + -2.6201045551331104417768E1L, 1.9361891836232102174846E2L, -4.2861221385716144629696E2L, +}; +/* log10(2) */ +#define L102A 0.3125L +#define L102B -1.1470004336018804786261e-2L +/* log10(e) */ +#define L10EA 0.5L +#define L10EB -6.5705518096748172348871e-2L + +#define SQRTH 0.70710678118654752440L + +long double log10l(long double x) { + long double y, z; + int e; + + if (isnan(x)) return x; + if (x <= 0.0) { + if (x == 0.0) return -1.0 / (x * x); + return (x - x) / 0.0; + } + if (x == INFINITY) return INFINITY; + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0 * x - 1.0; + } else { + x = x - 1.0; + } + z = x * x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5 * z; + +done: + /* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * (L10EB); + z += x * (L10EB); + z += e * (L102B); + z += y * (L10EA); + z += x * (L10EA); + z += e * (L102A); + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log10l(long double x) { + return log10(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/log1p.c b/third_party/ulib/musl/third_party/math/log1p.c new file mode 100644 index 000000000..13c64a16b --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log1p.c @@ -0,0 +1,121 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include "libm.h" + +static const double ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ + ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log1p(double x) { + union { + double f; + uint64_t i; + } u = {x}; + double_t hfsq, f, c, s, z, R, w, t1, t2, dk; + uint32_t hx, hu; + int k; + + hx = u.i >> 32; + k = 1; + if (hx < 0x3fda827a || hx >> 31) { /* 1+x < sqrt(2)+ */ + if (hx >= 0xbff00000) { /* x <= -1.0 */ + if (x == -1) return x / 0.0; /* log1p(-1) = -inf */ + return (x - x) / 0.0; /* log1p(x<-1) = NaN */ + } + if (hx << 1 < 0x3ca00000 << 1) { /* |x| < 2**-53 */ + /* underflow if subnormal */ + if ((hx & 0x7ff00000) == 0) FORCE_EVAL((float)x); + return x; + } + if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (hx >= 0x7ff00000) + return x; + if (k) { + u.f = 1 + x; + hu = u.i >> 32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (int)(hu >> 20) - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 54) { + c = k >= 2 ? 1 - (u.f - x) : x - (u.f - 1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu & 0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hu << 32 | (u.i & 0xffffffff); + f = u.f - 1; + } + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); + t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); + R = t2 + t1; + dk = k; + return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi; +} diff --git a/third_party/ulib/musl/third_party/math/log1pf.c b/third_party/ulib/musl/third_party/math/log1pf.c new file mode 100644 index 000000000..546fe3ab9 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log1pf.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ + ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ + /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ + Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ + Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ + Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ + Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log1pf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + float_t hfsq, f, c, s, z, R, w, t1, t2, dk; + uint32_t ix, iu; + int k; + + ix = u.i; + k = 1; + if (ix < 0x3ed413d0 || ix >> 31) { /* 1+x < sqrt(2)+ */ + if (ix >= 0xbf800000) { /* x <= -1.0 */ + if (x == -1) return x / 0.0f; /* log1p(-1)=+inf */ + return (x - x) / 0.0f; /* log1p(x<-1)=NaN */ + } + if (ix << 1 < 0x33800000 << 1) { /* |x| < 2**-24 */ + /* underflow if subnormal */ + if ((ix & 0x7f800000) == 0) FORCE_EVAL(x * x); + return x; + } + if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (ix >= 0x7f800000) + return x; + if (k) { + u.f = 1 + x; + iu = u.i; + iu += 0x3f800000 - 0x3f3504f3; + k = (int)(iu >> 23) - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 25) { + c = k >= 2 ? 1 - (u.f - x) : x - (u.f - 1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu & 0x007fffff) + 0x3f3504f3; + u.i = iu; + f = u.f - 1; + } + s = f / (2.0f + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * Lg4); + t2 = z * (Lg1 + w * Lg3); + R = t2 + t1; + hfsq = 0.5f * f * f; + dk = k; + return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi; +} diff --git a/third_party/ulib/musl/third_party/math/log1pl.c b/third_party/ulib/musl/third_party/math/log1pl.c new file mode 100644 index 000000000..755060346 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log1pl.c @@ -0,0 +1,158 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/s_log1pl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Relative error logarithm + * Natural logarithm of 1+x, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log1pl(long double x) { + return log1p(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, 4.9854102823193375972212E-1L, 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, 6.0949667980987787057556E1L, 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { + /* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, 8.3047565967967209469434E1L, 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, 2.1642788614495947685003E2L, 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, -7.1990767473014147232598E-1L, 1.0777257190312272158094E1L, + -3.5717684488096787370998E1L, +}; +static const long double S[4] = { + /* 1.00000000000000000000E0L,*/ + -2.6201045551331104417768E1L, 1.9361891836232102174846E2L, -4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double log1pl(long double xm1) { + long double x, y, z; + int e; + + if (isnan(xm1)) return xm1; + if (xm1 == INFINITY) return xm1; + if (xm1 == 0.0) return xm1; + + x = xm1 + 1.0; + + /* Test for domain errors. */ + if (x <= 0.0) { + if (x == 0.0) return -1 / (x * x); /* -inf with divbyzero */ + return 0 / 0.0f; /* nan with invalid */ + } + + /* Separate mantissa from exponent. + Use frexp so that denormal numbers will be handled properly. */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z^3 P(z)/Q(z), + where z = 2(x-1)/x+1) */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + if (e != 0) + x = 2.0 * x - 1.0; + else + x = xm1; + } else { + if (e != 0) + x = x - 1.0; + else + x = xm1; + } + z = x * x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5 * z; + z = z + x; + z = z + e * C1; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log1pl(long double x) { + return log1p(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/log2.c b/third_party/ulib/musl/third_party/math/log2.c new file mode 100644 index 000000000..81293a84b --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log2.c @@ -0,0 +1,121 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +#include +#include + +static const double ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ + ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */ + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log2(double x) { + union { + double f; + uint64_t i; + } u = {x}; + double_t hfsq, f, s, z, R, w, t1, t2, y, hi, lo, val_hi, val_lo; + uint32_t hx; + int k; + + hx = u.i >> 32; + k = 0; + if (hx < 0x00100000 || hx >> 31) { + if (u.i << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */ + if (hx >> 31) return (x - x) / 0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i >> 32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i << 32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx >> 20) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx << 32 | (u.i & 0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); + t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); + R = t2 + t1; + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1 << 32; + hi = u.f; + lo = f - hi - hfsq + s * (hfsq + R); + + val_hi = hi * ivln2hi; + val_lo = (lo + hi) * ivln2lo + lo * ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k; + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/third_party/ulib/musl/third_party/math/log2f.c b/third_party/ulib/musl/third_party/math/log2f.c new file mode 100644 index 000000000..2ae35c0f6 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log2f.c @@ -0,0 +1,73 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +#include +#include + +static const float ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */ + ivln2lo = -1.7605285393e-04, /* 0xb9389ad4 */ + /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ + Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ + Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ + Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ + Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log2f(float x) { + union { + float f; + uint32_t i; + } u = {x}; + float_t hfsq, f, s, z, R, w, t1, t2, hi, lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix >> 31) { /* x < 2**-126 */ + if (ix << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */ + if (ix >> 31) return (x - x) / 0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix >> 23) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f / (2.0f + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * Lg4); + t2 = z * (Lg1 + w * Lg3); + R = t2 + t1; + hfsq = 0.5f * f * f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s * (hfsq + R); + return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + k; +} diff --git a/third_party/ulib/musl/third_party/math/log2l.c b/third_party/ulib/musl/third_party/math/log2l.c new file mode 100644 index 000000000..0d8a58b52 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/log2l.c @@ -0,0 +1,164 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log2l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Base 2 logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.8e-20 2.7e-20 + * IEEE exp(+-10000) 70000 5.4e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log2l(long double x) { + return log2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, 1.0767376367209449010438E1L, 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, 4.2401812743503691187826E2L, 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { + /* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, 1.9444210022760132894510E2L, 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, 2.0307734695595183428202E3L, 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, -7.1990767473014147232598E-1L, 1.0777257190312272158094E1L, + -3.5717684488096787370998E1L, +}; +static const long double S[4] = { + /* 1.00000000000000000000E0L,*/ + -2.6201045551331104417768E1L, 1.9361891836232102174846E2L, -4.2861221385716144629696E2L, +}; +/* log2(e) - 1 */ +#define LOG2EA 4.4269504088896340735992e-1L + +#define SQRTH 0.70710678118654752440L + +long double log2l(long double x) { + long double y, z; + int e; + + if (isnan(x)) return x; + if (x == INFINITY) return x; + if (x <= 0.0) { + if (x == 0.0) return -1 / (x * x); /* -inf with divbyzero */ + return 0 / 0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0 * x - 1.0; + } else { + x = x - 1.0; + } + z = x * x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5 * z; + +done: + /* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * LOG2EA; + z += x * LOG2EA; + z += y; + z += x; + z += e; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log2l(long double x) { + return log2(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/logf.c b/third_party/ulib/musl/third_party/math/logf.c new file mode 100644 index 000000000..7c694193d --- /dev/null +++ b/third_party/ulib/musl/third_party/math/logf.c @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +static const float ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ + ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ + /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ + Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ + Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ + Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ + Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float logf(float x) { + union { + float f; + uint32_t i; + } u = {x}; + float_t hfsq, f, s, z, R, w, t1, t2, dk; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix >> 31) { /* x < 2**-126 */ + if (ix << 1 == 0) return -1 / (x * x); /* log(+-0)=-inf */ + if (ix >> 31) return (x - x) / 0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix >> 23) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f / (2.0f + f); + z = s * s; + w = z * z; + t1 = w * (Lg2 + w * Lg4); + t2 = z * (Lg1 + w * Lg3); + R = t2 + t1; + hfsq = 0.5f * f * f; + dk = k; + return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; +} diff --git a/third_party/ulib/musl/third_party/math/logl.c b/third_party/ulib/musl/third_party/math/logl.c new file mode 100644 index 000000000..3b722d3bc --- /dev/null +++ b/third_party/ulib/musl/third_party/math/logl.c @@ -0,0 +1,157 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_logl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Natural logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, logl(); + * + * y = logl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/(x+1), + * + * log(x) = log(1+z/2) - log(1-z/2) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 150000 8.71e-20 2.75e-20 + * IEEE exp(+-10000) 100000 5.39e-20 2.34e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logl(long double x) { + return log(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, 4.9854102823193375972212E-1L, 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, 6.0949667980987787057556E1L, 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { + /* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, 8.3047565967967209469434E1L, 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, 2.1642788614495947685003E2L, 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, -7.1990767473014147232598E-1L, 1.0777257190312272158094E1L, + -3.5717684488096787370998E1L, +}; +static const long double S[4] = { + /* 1.00000000000000000000E0L,*/ + -2.6201045551331104417768E1L, 1.9361891836232102174846E2L, -4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double logl(long double x) { + long double y, z; + int e; + + if (isnan(x)) return x; + if (x == INFINITY) return x; + if (x <= 0.0) { + if (x == 0.0) return -1 / (x * x); /* -inf with divbyzero */ + return 0 / 0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/(x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x * x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0 * x - 1.0; + } else { + x = x - 1.0; + } + z = x * x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5 * z; + /* Note, the sum of above terms does not exceed x/4, + * so it contributes at most about 1/4 lsb to the error. + */ + z = z + x; + z = z + e * C1; /* This sum has an error of 1/2 lsb. */ + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double logl(long double x) { + return log(x); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/pow.c b/third_party/ulib/musl/third_party/math/pow.c new file mode 100644 index 000000000..986feb9e1 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/pow.c @@ -0,0 +1,326 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. -1 ** +-INF is 1 + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double bp[] = + { + 1.0, 1.5, +}, + dp_h[] = + { + 0.0, 5.84962487220764160156e-01, +}, /* 0x3FE2B803, 0x40000000 */ + dp_l[] = + { + 0.0, 1.35003920212974897128e-08, +}, /* 0x3E4CFDEB, 0x43CFD006 */ + two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ + huge = 1.0e300, + tiny = 1.0e-300, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ + L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ + L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ + L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ + L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ + L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ + L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ + P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ + P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ + P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ + P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ + P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ + lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ + lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ + lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ + ovt = 8.0085662595372944372e-017, /* -(1024-log2(ovfl+.5ulp)) */ + cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ + cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ + cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ + ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ + ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ + ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double pow(double x, double y) { + double z, ax, z_h, z_l, p_h, p_l; + double y1, t1, t2, r, s, t, u, v, w; + int32_t i, j, k, yisint, n; + int32_t hx, hy, ix, iy; + uint32_t lx, ly; + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if ((iy | ly) == 0) return 1.0; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3ff00000 && lx == 0) return 1.0; + /* NaN if either arg is NaN */ + if (ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || iy > 0x7ff00000 || + (iy == 0x7ff00000 && ly != 0)) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x43400000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3ff00000) { + k = (iy >> 20) - 0x3ff; /* exponent */ + if (k > 20) { + j = ly >> (52 - k); + if ((j << (52 - k)) == ly) yisint = 2 - (j & 1); + } else if (ly == 0) { + j = iy >> (20 - k); + if ((j << (20 - k)) == iy) yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if (ly == 0) { + if (iy == 0x7ff00000) { /* y is +-inf */ + if (((ix - 0x3ff00000) | lx) == 0) /* (-1)**+-inf is 1 */ + return 1.0; + else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0 : -y; + } + if (iy == 0x3ff00000) { /* y is +-1 */ + if (hy >= 0) return x; + y = 1 / x; +#if FLT_EVAL_METHOD != 0 + { + union { + double f; + uint64_t i; + } u = {y}; + uint64_t i = u.i & -1ULL / 2; + if (i >> 52 == 0 && (i & (i - 1))) FORCE_EVAL((float)y); + } +#endif + return y; + } + if (hy == 0x40000000) /* y is 2 */ + return x * x; + if (hy == 0x3fe00000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if (lx == 0) { + if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0 / z; + if (hx < 0) { + if (((ix - 0x3ff00000) | yisint) == 0) { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + s = 1.0; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + if (yisint == 1) /* (x<0)**(odd int) */ + s = -1.0; + } + + /* |y| is huge */ + if (iy > 0x41e00000) { /* if |y| > 2**31 */ + if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */ + if (ix <= 0x3fefffff) return hy < 0 ? huge * huge : tiny * tiny; + if (ix >= 0x3ff00000) return hy > 0 ? huge * huge : tiny * tiny; + } + /* over/underflow if x is not close to one */ + if (ix < 0x3fefffff) return hy < 0 ? s * huge * huge : s * tiny * tiny; + if (ix > 0x3ff00000) return hy > 0 ? s * huge * huge : s * tiny * tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.0; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + u = ivln2_h * t; /* ivln2_h has 21 sig. bits */ + v = t * ivln2_l - w * ivln2; + t1 = u + v; + SET_LOW_WORD(t1, 0); + t2 = v - (t1 - u); + } else { + double ss, s2, s_h, s_l, t_h, t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00100000) { + ax *= two53; + n -= 53; + GET_HIGH_WORD(ix, ax); + } + n += ((ix) >> 20) - 0x3ff; + j = ix & 0x000fffff; + /* determine interval */ + ix = j | 0x3ff00000; /* normalize ix */ + if (j <= 0x3988E) /* |x|> 1) | 0x20000000) + 0x00080000 + (k << 18)); + t_l = ax - (t_h - bp[k]); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = ss * ss; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + ss); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + SET_LOW_WORD(t_h, 0); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = ss*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * ss; + /* 2/(3log2)*(ss+...) */ + p_h = u + v; + SET_LOW_WORD(p_h, 0); + p_l = v - (p_h - u); + z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l * p_h + p_l * cp + dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = ((z_h + z_l) + dp_h[k]) + t; + SET_LOW_WORD(t1, 0); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1, 0); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + EXTRACT_WORDS(j, i, z); + if (j >= 0x40900000) { /* z >= 1024 */ + if (((j - 0x40900000) | i) != 0) /* if z > 1024 */ + return s * huge * huge; /* overflow */ + if (p_l + ovt > z - p_h) return s * huge * huge; /* overflow */ + } else if ((j & 0x7fffffff) >= + 0x4090cc00) { /* z <= -1075 */ // FIXME: instead of abs(j) use unsigned j + if (((j - 0xc090cc00) | i) != 0) /* z < -1075 */ + return s * tiny * tiny; /* underflow */ + if (p_l <= z - p_h) return s * tiny * tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 20) - 0x3ff; + n = 0; + if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + t = 0.0; + SET_HIGH_WORD(t, n & ~(0x000fffff >> k)); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if (j < 0) n = -n; + p_h -= t; + } + t = p_l + p_h; + SET_LOW_WORD(t, 0); + u = t * lg2_h; + v = (p_l - (t - p_h)) * lg2 + t * lg2_l; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + GET_HIGH_WORD(j, z); + j += n << 20; + if ((j >> 20) <= 0) /* subnormal output */ + z = scalbn(z, n); + else + SET_HIGH_WORD(z, j); + return s * z; +} diff --git a/third_party/ulib/musl/third_party/math/powf.c b/third_party/ulib/musl/third_party/math/powf.c new file mode 100644 index 000000000..795bbf3d7 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/powf.c @@ -0,0 +1,258 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float bp[] = + { + 1.0, 1.5, +}, + dp_h[] = + { + 0.0, 5.84960938e-01, +}, /* 0x3f15c000 */ + dp_l[] = + { + 0.0, 1.56322085e-06, +}, /* 0x35d1cfdc */ + two24 = 16777216.0, /* 0x4b800000 */ + huge = 1.0e30, + tiny = 1.0e-30, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ + L1 = 6.0000002384e-01, /* 0x3f19999a */ + L2 = 4.2857143283e-01, /* 0x3edb6db7 */ + L3 = 3.3333334327e-01, /* 0x3eaaaaab */ + L4 = 2.7272811532e-01, /* 0x3e8ba305 */ + L5 = 2.3066075146e-01, /* 0x3e6c3255 */ + L6 = 2.0697501302e-01, /* 0x3e53f142 */ + P1 = 1.6666667163e-01, /* 0x3e2aaaab */ + P2 = -2.7777778450e-03, /* 0xbb360b61 */ + P3 = 6.6137559770e-05, /* 0x388ab355 */ + P4 = -1.6533901999e-06, /* 0xb5ddea0e */ + P5 = 4.1381369442e-08, /* 0x3331bb4c */ + lg2 = 6.9314718246e-01, /* 0x3f317218 */ + lg2_h = 6.93145752e-01, /* 0x3f317200 */ + lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ + ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ + cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ + cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ + cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ + ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ + ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ + ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float powf(float x, float y) { + float z, ax, z_h, z_l, p_h, p_l; + float y1, t1, t2, r, s, sn, t, u, v, w; + int32_t i, j, k, yisint, n; + int32_t hx, hy, ix, iy, is; + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if (iy == 0) return 1.0f; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3f800000) return 1.0f; + /* NaN if either arg is NaN */ + if (ix > 0x7f800000 || iy > 0x7f800000) return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x4b800000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3f800000) { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if ((j << (23 - k)) == iy) yisint = 2 - (j & 1); + } + } + + /* special value of y */ + if (iy == 0x7f800000) { /* y is +-inf */ + if (ix == 0x3f800000) /* (-1)**+-inf is 1 */ + return 1.0f; + else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0f; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0f : -y; + } + if (iy == 0x3f800000) /* y is +-1 */ + return hy >= 0 ? x : 1.0f / x; + if (hy == 0x40000000) /* y is 2 */ + return x * x; + if (hy == 0x3f000000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if (ix == 0x7f800000 || ix == 0 || ix == 0x3f800000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0f / z; + if (hx < 0) { + if (((ix - 0x3f800000) | yisint) == 0) { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + sn = 1.0f; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + if (yisint == 1) /* (x<0)**(odd int) */ + sn = -1.0f; + } + + /* |y| is huge */ + if (iy > 0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if (ix < 0x3f7ffff8) return hy < 0 ? sn * huge * huge : sn * tiny * tiny; + if (ix > 0x3f800007) return hy > 0 ? sn * huge * huge : sn * tiny * tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1; /* t has 20 trailing zeros */ + w = (t * t) * (0.5f - t * (0.333333333333f - t * 0.25f)); + u = ivln2_h * t; /* ivln2_h has 16 sig. bits */ + v = t * ivln2_l - w * ivln2; + t1 = u + v; + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = v - (t1 - u); + } else { + float s2, s_h, s_l, t_h, t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00800000) { + ax *= two24; + n -= 24; + GET_FLOAT_WORD(ix, ax); + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if (j <= 0x1cc471) /* |x|> 1) & 0xfffff000) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k << 21)); + t_l = ax - (t_h - bp[k]); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0f + s2 + r; + GET_FLOAT_WORD(is, t_h); + SET_FLOAT_WORD(t_h, is & 0xfffff000); + t_l = r - ((t_h - 3.0f) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + GET_FLOAT_WORD(is, p_h); + SET_FLOAT_WORD(p_h, is & 0xfffff000); + p_l = v - (p_h - u); + z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l * p_h + p_l * cp + dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h + z_l) + dp_h[k]) + t); + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is, y); + SET_FLOAT_WORD(y1, is & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + GET_FLOAT_WORD(j, z); + if (j > 0x43000000) /* if z > 128 */ + return sn * huge * huge; /* overflow */ + else if (j == 0x43000000) { /* if z == 128 */ + if (p_l + ovt > z - p_h) return sn * huge * huge; /* overflow */ + } else if ((j & 0x7fffffff) > + 0x43160000) /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * tiny * tiny; /* underflow */ + else if (j == 0xc3160000) { /* z == -150 */ + if (p_l <= z - p_h) return sn * tiny * tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if (i > 0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + SET_FLOAT_WORD(t, n & ~(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if (j < 0) n = -n; + p_h -= t; + } + t = p_l + p_h; + GET_FLOAT_WORD(is, t); + SET_FLOAT_WORD(t, is & 0xffff8000); + u = t * lg2_h; + v = (p_l - (t - p_h)) * lg2 + t * lg2_l; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0f) - (w + z * w); + z = 1.0f - (r - z); + GET_FLOAT_WORD(j, z); + j += n << 23; + if ((j >> 23) <= 0) /* subnormal output */ + z = scalbnf(z, n); + else + SET_FLOAT_WORD(z, j); + return sn * z; +} diff --git a/third_party/ulib/musl/third_party/math/powl.c b/third_party/ulib/musl/third_party/math/powl.c new file mode 100644 index 000000000..ffadc9da8 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/powl.c @@ -0,0 +1,444 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_powl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* powl.c + * + * Power function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, z, powl(); + * + * z = powl( x, y ); + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/32 and pseudo extended precision arithmetic to + * obtain several extra bits of accuracy in both the logarithm + * and the exponential. + * + * + * ACCURACY: + * + * The relative error of pow(x,y) can be estimated + * by y dl ln(2), where dl is the absolute error of + * the internally computed base 2 logarithm. At the ends + * of the approximation interval the logarithm equal 1/32 + * and its relative error is about 1 lsb = 1.1e-19. Hence + * the predicted relative error in the result is 2.3e-21 y . + * + * Relative error: + * arithmetic domain # trials peak rms + * + * IEEE +-1000 40000 2.8e-18 3.7e-19 + * .001 < x < 1000, with log(x) uniformly distributed. + * -1000 < y < 1000, y uniformly distributed. + * + * IEEE 0,8700 60000 6.5e-18 1.0e-18 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double powl(long double x, long double y) { + return pow(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* Table size */ +#define NXT 32 + +/* log(1+x) = x - .5x^2 + x^3 * P(z)/Q(z) + * on the domain 2^(-1/32) - 1 <= x <= 2^(1/32) - 1 + */ +static const long double P[] = { + 8.3319510773868690346226E-4L, 4.9000050881978028599627E-1L, 1.7500123722550302671919E0L, + 1.4000100839971580279335E0L, +}; +static const long double Q[] = { + /* 1.0000000000000000000000E0L,*/ + 5.2500282295834889175431E0L, 8.4000598057587009834666E0L, 4.2000302519914740834728E0L, +}; +/* A[i] = 2^(-i/32), rounded to IEEE long double precision. + * If i is even, A[i] + B[i/2] gives additional accuracy. + */ +static const long double A[33] = { + 1.0000000000000000000000E0L, 9.7857206208770013448287E-1L, 9.5760328069857364691013E-1L, + 9.3708381705514995065011E-1L, 9.1700404320467123175367E-1L, 8.9735453750155359320742E-1L, + 8.7812608018664974155474E-1L, 8.5930964906123895780165E-1L, 8.4089641525371454301892E-1L, + 8.2287773907698242225554E-1L, 8.0524516597462715409607E-1L, 7.8799042255394324325455E-1L, + 7.7110541270397041179298E-1L, 7.5458221379671136985669E-1L, 7.3841307296974965571198E-1L, + 7.2259040348852331001267E-1L, 7.0710678118654752438189E-1L, 6.9195494098191597746178E-1L, + 6.7712777346844636413344E-1L, 6.6261832157987064729696E-1L, 6.4841977732550483296079E-1L, + 6.3452547859586661129850E-1L, 6.2092890603674202431705E-1L, 6.0762367999023443907803E-1L, + 5.9460355750136053334378E-1L, 5.8186242938878875689693E-1L, 5.6939431737834582684856E-1L, + 5.5719337129794626814472E-1L, 5.4525386633262882960438E-1L, 5.3357020033841180906486E-1L, + 5.2213689121370692017331E-1L, 5.1094857432705833910408E-1L, 5.0000000000000000000000E-1L, +}; +static const long double B[17] = { + 0.0000000000000000000000E0L, 2.6176170809902549338711E-20L, -1.0126791927256478897086E-20L, + 1.3438228172316276937655E-21L, 1.2207982955417546912101E-20L, -6.3084814358060867200133E-21L, + 1.3164426894366316434230E-20L, -1.8527916071632873716786E-20L, 1.8950325588932570796551E-20L, + 1.5564775779538780478155E-20L, 6.0859793637556860974380E-21L, -2.0208749253662532228949E-20L, + 1.4966292219224761844552E-20L, 3.3540909728056476875639E-21L, -8.6987564101742849540743E-22L, + -1.2327176863327626135542E-20L, 0.0000000000000000000000E0L, +}; + +/* 2^x = 1 + x P(x), + * on the interval -1/32 <= x <= 0 + */ +static const long double R[] = { + 1.5089970579127659901157E-5L, 1.5402715328927013076125E-4L, 1.3333556028915671091390E-3L, + 9.6181291046036762031786E-3L, 5.5504108664798463044015E-2L, 2.4022650695910062854352E-1L, + 6.9314718055994530931447E-1L, +}; + +#define MEXP (NXT * 16384.0L) +/* The following if denormal numbers are supported, else -MEXP: */ +#define MNEXP (-NXT * (16384.0L + 64.0L)) +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992L + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +static const long double MAXLOGL = 1.1356523406294143949492E4L; +static const long double MINLOGL = -1.13994985314888605586758E4L; +static const long double LOGE2L = 6.9314718055994530941723E-1L; +static const long double huge = 0x1p10000L; +/* XXX Prevent gcc from erroneously constant folding this. */ +static const volatile long double twom10000 = 0x1p-10000L; + +static long double reducl(long double); +static long double powil(long double, int); + +long double powl(long double x, long double y) { + /* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ + int i, nflg, iyflg, yoddint; + long e; + volatile long double z = 0; + long double w = 0, W = 0, Wa = 0, Wb = 0, ya = 0, yb = 0, u = 0; + + /* make sure no invalid exception is raised by nan comparision */ + if (isnan(x)) { + if (!isnan(y) && y == 0.0) return 1.0; + return x; + } + if (isnan(y)) { + if (x == 1.0) return 1.0; + return y; + } + if (x == 1.0) return 1.0; /* 1**y = 1, even if y is nan */ + if (x == -1.0 && !isfinite(y)) return 1.0; /* -1**inf = 1 */ + if (y == 0.0) return 1.0; /* x**0 = 1, even if x is nan */ + if (y == 1.0) return x; + if (y >= LDBL_MAX) { + if (x > 1.0 || x < -1.0) return INFINITY; + if (x != 0.0) return 0.0; + } + if (y <= -LDBL_MAX) { + if (x > 1.0 || x < -1.0) return 0.0; + if (x != 0.0 || y == -INFINITY) return INFINITY; + } + if (x >= LDBL_MAX) { + if (y > 0.0) return INFINITY; + return 0.0; + } + + w = floorl(y); + + /* Set iyflg to 1 if y is an integer. */ + iyflg = 0; + if (w == y) iyflg = 1; + + /* Test for odd integer y. */ + yoddint = 0; + if (iyflg) { + ya = fabsl(y); + ya = floorl(0.5 * ya); + yb = 0.5 * fabsl(w); + if (ya != yb) yoddint = 1; + } + + if (x <= -LDBL_MAX) { + if (y > 0.0) { + if (yoddint) return -INFINITY; + return INFINITY; + } + if (y < 0.0) { + if (yoddint) return -0.0; + return 0.0; + } + } + nflg = 0; /* (x<0)**(odd int) */ + if (x <= 0.0) { + if (x == 0.0) { + if (y < 0.0) { + if (signbit(x) && yoddint) /* (-0.0)**(-odd int) = -inf, divbyzero */ + return -1.0 / 0.0; + /* (+-0.0)**(negative) = inf, divbyzero */ + return 1.0 / 0.0; + } + if (signbit(x) && yoddint) return -0.0; + return 0.0; + } + if (iyflg == 0) return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */ + /* (x<0)**(integer) */ + if (yoddint) nflg = 1; /* negate result */ + x = -x; + } + /* (+integer)**(integer) */ + if (iyflg && floorl(x) == x && fabsl(y) < 32768.0) { + w = powil(x, (int)y); + return nflg ? -w : w; + } + + /* separate significand from exponent */ + x = frexpl(x, &i); + e = i; + + /* find significand in antilog table A[] */ + i = 1; + if (x <= A[17]) i = 17; + if (x <= A[i + 8]) i += 8; + if (x <= A[i + 4]) i += 4; + if (x <= A[i + 2]) i += 2; + if (x >= A[1]) i = -1; + i += 1; + + /* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ + x -= A[i]; + x -= B[i / 2]; + x /= A[i]; + + /* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ + z = x * x; + w = x * (z * __polevll(x, P, 3) / __p1evll(x, Q, 3)); + w = w - 0.5 * z; + + /* Convert to base 2 logarithm: + * multiply by log2(e) = 1 + LOG2EA + */ + z = LOG2EA * w; + z += w; + z += LOG2EA * x; + z += x; + + /* Compute exponent term of the base 2 logarithm. */ + w = -i; + w /= NXT; + w += e; + /* Now base 2 log of x is w + z. */ + + /* Multiply base 2 log by y, in extended precision. */ + + /* separate y into large part ya + * and small part yb less than 1/NXT + */ + ya = reducl(y); + yb = y - ya; + + /* (w+z)(ya+yb) + * = w*ya + w*yb + z*y + */ + F = z * y + w * yb; + Fa = reducl(F); + Fb = F - Fa; + + G = Fa + w * ya; + Ga = reducl(G); + Gb = G - Ga; + + H = Fb + Gb; + Ha = reducl(H); + w = (Ga + Ha) * NXT; + + /* Test the power of 2 for overflow */ + if (w > MEXP) return huge * huge; /* overflow */ + if (w < MNEXP) return twom10000 * twom10000; /* underflow */ + + e = w; + Hb = H - Ha; + + if (Hb > 0.0) { + e += 1; + Hb -= 1.0 / NXT; /*0.0625L;*/ + } + + /* Now the product y * log2(x) = Hb + e/NXT. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ + z = Hb * __polevll(Hb, R, 6); /* z = 2**Hb - 1 */ + + /* Express e/NXT as an integer plus a negative number of (1/NXT)ths. + * Find lookup table entry for the fractional power of 2. + */ + if (e < 0) + i = 0; + else + i = 1; + i = e / NXT + i; + e = NXT * i - e; + w = A[e]; + z = w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ + z = z + w; + z = scalbnl(z, i); /* multiply by integer power of 2 */ + + if (nflg) z = -z; + return z; +} + +/* Find a multiple of 1/NXT that is within 1/NXT of x. */ +static long double reducl(long double x) { + long double t; + + t = x * NXT; + t = floorl(t); + t = t / NXT; + return t; +} + +/* + * Positive real raised to integer power, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, powil(); + * int n; + * + * y = powil( x, n ); + * + * + * DESCRIPTION: + * + * Returns argument x>0 raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * IEEE .001,1000 -1022,1023 50000 4.3e-17 7.8e-18 + * IEEE 1,2 -1022,1023 20000 3.9e-17 7.6e-18 + * IEEE .99,1.01 0,8700 10000 3.6e-16 7.2e-17 + * + * Returns MAXNUM on overflow, zero on underflow. + */ + +static long double powil(long double x, int nn) { + long double ww, y; + long double s; + int n, e, sign, lx; + + if (nn == 0) return 1.0; + + if (nn < 0) { + sign = -1; + n = -nn; + } else { + sign = 1; + n = nn; + } + + /* Overflow detection */ + + /* Calculate approximate logarithm of answer */ + s = x; + s = frexpl(s, &lx); + e = (lx - 1) * n; + if ((e == 0) || (e > 64) || (e < -64)) { + s = (s - 7.0710678118654752e-1L) / (s + 7.0710678118654752e-1L); + s = (2.9142135623730950L * s - 0.5 + lx) * nn * LOGE2L; + } else { + s = LOGE2L * e; + } + + if (s > MAXLOGL) return huge * huge; /* overflow */ + + if (s < MINLOGL) return twom10000 * twom10000; /* underflow */ + /* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ + if (s < -MAXLOGL + 2.0) { + x = 1.0 / x; + sign = -sign; + } + + /* First bit of the power */ + if (n & 1) + y = x; + else + y = 1.0; + + ww = x; + n >>= 1; + while (n) { + ww = ww * ww; /* arg to the 2-to-the-kth power */ + if (n & 1) /* if that bit is set, then include in product */ + y *= ww; + n >>= 1; + } + + if (sign < 0) y = 1.0 / y; + return y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double powl(long double x, long double y) { + return pow(x, y); +} +#endif diff --git a/third_party/ulib/musl/third_party/math/scalb.c b/third_party/ulib/musl/third_party/math/scalb.c new file mode 100644 index 000000000..dae47f22e --- /dev/null +++ b/third_party/ulib/musl/third_party/math/scalb.c @@ -0,0 +1,33 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalb.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * scalb(x, fn) is provide for + * passing various standard test suite. One + * should use scalbn() instead. + */ + +#define _GNU_SOURCE +#include + +double scalb(double x, double fn) { + if (isnan(x) || isnan(fn)) return x * fn; + if (!isfinite(fn)) { + if (fn > 0.0) + return x * fn; + else + return x / (-fn); + } + if (rint(fn) != fn) return (fn - fn) / (fn - fn); + if (fn > 65000.0) return scalbn(x, 65000); + if (-fn > 65000.0) return scalbn(x, -65000); + return scalbn(x, (int)fn); +} diff --git a/third_party/ulib/musl/third_party/math/scalbf.c b/third_party/ulib/musl/third_party/math/scalbf.c new file mode 100644 index 000000000..59e8cd573 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/scalbf.c @@ -0,0 +1,31 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalbf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include + +float scalbf(float x, float fn) { + if (isnan(x) || isnan(fn)) return x * fn; + if (!isfinite(fn)) { + if (fn > 0.0f) + return x * fn; + else + return x / (-fn); + } + if (rintf(fn) != fn) return (fn - fn) / (fn - fn); + if (fn > 65000.0f) return scalbnf(x, 65000); + if (-fn > 65000.0f) return scalbnf(x, -65000); + return scalbnf(x, (int)fn); +} diff --git a/third_party/ulib/musl/third_party/math/sin.c b/third_party/ulib/musl/third_party/math/sin.c new file mode 100644 index 000000000..c8f0d6478 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/sin.c @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cose function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double sin(double x) { + double y[2]; + uint32_t ix; + unsigned n; + + /* High word of x. */ + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e500000) { /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + FORCE_EVAL(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f); + return x; + } + return __sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) return x - x; + + /* argument reduction needed */ + n = __rem_pio2(x, y); + switch (n & 3) { + case 0: + return __sin(y[0], y[1], 1); + case 1: + return __cos(y[0], y[1]); + case 2: + return -__sin(y[0], y[1], 1); + default: + return -__cos(y[0], y[1]); + } +} diff --git a/third_party/ulib/musl/third_party/math/sincos.c b/third_party/ulib/musl/third_party/math/sincos.c new file mode 100644 index 000000000..13c23ce31 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/sincos.c @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +void sincos(double x, double* sin, double* cos) { + double y[2], s, c; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + /* if |x| < 2**-27 * sqrt(2) */ + if (ix < 0x3e46a09e) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f); + *sin = x; + *cos = 1.0; + return; + } + *sin = __sin(x, 0.0, 0); + *cos = __cos(x, 0.0); + return; + } + + /* sincos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) { + *sin = *cos = x - x; + return; + } + + /* argument reduction needed */ + n = __rem_pio2(x, y); + s = __sin(y[0], y[1], 1); + c = __cos(y[0], y[1]); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/third_party/ulib/musl/third_party/math/sincosf.c b/third_party/ulib/musl/third_party/math/sincosf.c new file mode 100644 index 000000000..0de7c65f7 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/sincosf.c @@ -0,0 +1,115 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double s1pio2 = 1 * M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + s2pio2 = 2 * M_PI_2, /* 0x400921FB, 0x54442D18 */ + s3pio2 = 3 * M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + s4pio2 = 4 * M_PI_2; /* 0x401921FB, 0x54442D18 */ + +void sincosf(float x, float* sin, float* cos) { + double y; + float_t s, c; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if (ix <= 0x3f490fda) { + /* |x| < 2**-12 */ + if (ix < 0x39800000) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f); + *sin = x; + *cos = 1.0f; + return; + } + *sin = __sindf(x); + *cos = __cosdf(x); + return; + } + + /* |x| ~<= 5*pi/4 */ + if (ix <= 0x407b53d1) { + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) { + *sin = -__cosdf(x + s1pio2); + *cos = __sindf(x + s1pio2); + } else { + *sin = __cosdf(s1pio2 - x); + *cos = __sindf(s1pio2 - x); + } + return; + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + *sin = -__sindf(sign ? x + s2pio2 : x - s2pio2); + *cos = -__cosdf(sign ? x + s2pio2 : x - s2pio2); + return; + } + + /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40e231d5) { + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) { + *sin = __cosdf(x + s3pio2); + *cos = -__sindf(x + s3pio2); + } else { + *sin = -__cosdf(x - s3pio2); + *cos = __sindf(x - s3pio2); + } + return; + } + *sin = __sindf(sign ? x + s4pio2 : x - s4pio2); + *cos = __cosdf(sign ? x + s4pio2 : x - s4pio2); + return; + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) { + *sin = *cos = x - x; + return; + } + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + s = __sindf(y); + c = __cosdf(y); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/third_party/ulib/musl/third_party/math/sinf.c b/third_party/ulib/musl/third_party/math/sinf.c new file mode 100644 index 000000000..0759add06 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/sinf.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double s1pio2 = 1 * M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + s2pio2 = 2 * M_PI_2, /* 0x400921FB, 0x54442D18 */ + s3pio2 = 3 * M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + s4pio2 = 4 * M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float sinf(float x) { + double y; + uint32_t ix; + int n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x / 0x1p120f : x + 0x1p120f); + return x; + } + return __sindf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) + return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); + } + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) + return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); + } + return __sindf(sign ? x + s4pio2 : x - s4pio2); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n & 3) { + case 0: + return __sindf(y); + case 1: + return __cosdf(y); + case 2: + return __sindf(-y); + default: + return -__cosdf(y); + } +} diff --git a/third_party/ulib/musl/third_party/math/sqrt.c b/third_party/ulib/musl/third_party/math/sqrt.c new file mode 100644 index 000000000..35bb55be5 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/sqrt.c @@ -0,0 +1,178 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + +#include "libm.h" + +static const double tiny = 1.0e-300; + +double sqrt(double x) { + double z; + int32_t sign = (int)0x80000000; + int32_t ix0, s0, q, m, t, i; + uint32_t r, t1, s1, ix1, q1; + + EXTRACT_WORDS(ix0, ix1, x); + + /* take care of Inf and NaN */ + if ((ix0 & 0x7ff00000) == 0x7ff00000) { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix0 <= 0) { + if (((ix0 & ~sign) | ix1) == 0) return x; /* sqrt(+-0) = +-0 */ + if (ix0 < 0) return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix0 >> 20; + if (m == 0) { /* subnormal x */ + while (ix0 == 0) { + m -= 21; + ix0 |= (ix1 >> 11); + ix1 <<= 21; + } + for (i = 0; (ix0 & 0x00100000) == 0; i++) + ix0 <<= 1; + m -= i - 1; + ix0 |= ix1 >> (32 - i); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s0 + r; + if (t <= ix0) { + s0 = t + r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31); + ix1 += ix1; + r >>= 1; + } + + r = sign; + while (r != 0) { + t1 = s1 + r; + t = s0; + if (t < ix0 || (t == ix0 && t1 <= ix1)) { + s1 = t1 + r; + if ((t1 & sign) == sign && (s1 & sign) == 0) s0++; + ix0 -= t; + if (ix1 < t1) ix0--; + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31); + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ((ix0 | ix1) != 0) { + z = 1.0 - tiny; /* raise inexact flag */ + if (z >= 1.0) { + z = 1.0 + tiny; + if (q1 == (uint32_t)0xffffffff) { + q1 = 0; + q++; + } else if (z > 1.0) { + if (q1 == (uint32_t)0xfffffffe) q++; + q1 += 2; + } else + q1 += q1 & 1; + } + } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) ix1 |= sign; + ix0 += m << 20; + INSERT_WORDS(z, ix0, ix1); + return z; +} diff --git a/third_party/ulib/musl/third_party/math/sqrtf.c b/third_party/ulib/musl/third_party/math/sqrtf.c new file mode 100644 index 000000000..eb119419f --- /dev/null +++ b/third_party/ulib/musl/third_party/math/sqrtf.c @@ -0,0 +1,81 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float tiny = 1.0e-30; + +float sqrtf(float x) { + float z; + int32_t sign = (int)0x80000000; + int32_t ix, s, q, m, t, i; + uint32_t r; + + GET_FLOAT_WORD(ix, x); + + /* take care of Inf and NaN */ + if ((ix & 0x7f800000) == 0x7f800000) + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + + /* take care of zero */ + if (ix <= 0) { + if ((ix & ~sign) == 0) return x; /* sqrt(+-0) = +-0 */ + if (ix < 0) return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix >> 23; + if (m == 0) { /* subnormal x */ + for (i = 0; (ix & 0x00800000) == 0; i++) + ix <<= 1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if (m & 1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t + r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix != 0) { + z = 1.0f - tiny; /* raise inexact flag */ + if (z >= 1.0f) { + z = 1.0f + tiny; + if (z > 1.0f) + q += 2; + else + q += q & 1; + } + } + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + SET_FLOAT_WORD(z, ix); + return z; +} diff --git a/third_party/ulib/musl/third_party/math/tan.c b/third_party/ulib/musl/third_party/math/tan.c new file mode 100644 index 000000000..6ca930100 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/tan.c @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __tan ... tangent function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double tan(double x) { + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e400000) { /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f); + return x; + } + return __tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) return x - x; + + /* argument reduction */ + n = __rem_pio2(x, y); + return __tan(y[0], y[1], n & 1); +} diff --git a/third_party/ulib/musl/third_party/math/tanf.c b/third_party/ulib/musl/third_party/math/tanf.c new file mode 100644 index 000000000..a5d55b2c8 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/tanf.c @@ -0,0 +1,61 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double t1pio2 = 1 * M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + t2pio2 = 2 * M_PI_2, /* 0x400921FB, 0x54442D18 */ + t3pio2 = 3 * M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + t4pio2 = 4 * M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float tanf(float x) { + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x / 0x1p120f : x + 0x1p120f); + return x; + } + return __tandf(x, 0); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __tandf((sign ? x + t1pio2 : x - t1pio2), 1); + else + return __tandf((sign ? x + t2pio2 : x - t2pio2), 0); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __tandf((sign ? x + t3pio2 : x - t3pio2), 1); + else + return __tandf((sign ? x + t4pio2 : x - t4pio2), 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) return x - x; + + /* argument reduction */ + n = __rem_pio2f(x, &y); + return __tandf(y, n & 1); +} diff --git a/third_party/ulib/musl/third_party/math/tgammal.c b/third_party/ulib/musl/third_party/math/tgammal.c new file mode 100644 index 000000000..efd9b3836 --- /dev/null +++ b/third_party/ulib/musl/third_party/math/tgammal.c @@ -0,0 +1,245 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_tgammal.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Gamma function + * + * + * SYNOPSIS: + * + * long double x, y, tgammal(); + * + * y = tgammal( x ); + * + * + * DESCRIPTION: + * + * Returns gamma function of the argument. The result is + * correctly signed. + * + * Arguments |x| <= 13 are reduced by recurrence and the function + * approximated by a rational function of degree 7/8 in the + * interval (2,3). Large arguments are handled by Stirling's + * formula. Large negative arguments are made positive using + * a reflection formula. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -40,+40 10000 3.6e-19 7.9e-20 + * IEEE -1755,+1755 10000 4.8e-18 6.5e-19 + * + * Accuracy for large arguments is dominated by error in powl(). + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tgammal(long double x) { + return tgamma(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* +tgamma(x+2) = tgamma(x+2) P(x)/Q(x) +0 <= x <= 1 +Relative error +n=7, d=8 +Peak error = 1.83e-20 +Relative error spread = 8.4e-23 +*/ +static const long double P[8] = { + 4.212760487471622013093E-5L, 4.542931960608009155600E-4L, 4.092666828394035500949E-3L, + 2.385363243461108252554E-2L, 1.113062816019361559013E-1L, 3.629515436640239168939E-1L, + 8.378004301573126728826E-1L, 1.000000000000000000009E0L, +}; +static const long double Q[9] = { + -1.397148517476170440917E-5L, 2.346584059160635244282E-4L, -1.237799246653152231188E-3L, + -7.955933682494738320586E-4L, 2.773706565840072979165E-2L, -4.633887671244534213831E-2L, + -2.243510905670329164562E-1L, 4.150160950588455434583E-1L, 9.999999999999999999908E-1L, +}; + +/* +static const long double P[] = { +-3.01525602666895735709e0L, +-3.25157411956062339893e1L, +-2.92929976820724030353e2L, +-1.70730828800510297666e3L, +-7.96667499622741999770e3L, +-2.59780216007146401957e4L, +-5.99650230220855581642e4L, +-7.15743521530849602425e4L +}; +static const long double Q[] = { + 1.00000000000000000000e0L, +-1.67955233807178858919e1L, + 8.85946791747759881659e1L, + 5.69440799097468430177e1L, +-1.98526250512761318471e3L, + 3.31667508019495079814e3L, + 1.60577839621734713377e4L, +-2.97045081369399940529e4L, +-7.15743521530849602412e4L +}; +*/ +#define MAXGAML 1755.455L +/*static const long double LOGPI = 1.14472988584940017414L;*/ + +/* Stirling's formula for the gamma function +tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) +z(x) = x +13 <= x <= 1024 +Relative error +n=8, d=0 +Peak error = 9.44e-21 +Relative error spread = 8.8e-4 +*/ +static const long double STIR[9] = { + 7.147391378143610789273E-4L, -2.363848809501759061727E-5L, -5.950237554056330156018E-4L, + 6.989332260623193171870E-5L, 7.840334842744753003862E-4L, -2.294719747873185405699E-4L, + -2.681327161876304418288E-3L, 3.472222222230075327854E-3L, 8.333333333333331800504E-2L, +}; + +#define MAXSTIR 1024.0L +static const long double SQTPI = 2.50662827463100050242E0L; + +/* 1/tgamma(x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 4.2e-23 + */ +static const long double S[9] = { + -1.193945051381510095614E-3L, 7.220599478036909672331E-3L, -9.622023360406271645744E-3L, + -4.219773360705915470089E-2L, 1.665386113720805206758E-1L, -4.200263503403344054473E-2L, + -6.558780715202540684668E-1L, 5.772156649015328608253E-1L, 1.000000000000000000000E0L, +}; + +/* 1/tgamma(-x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 5.16e-23 + * Relative error spread = 2.5e-24 + */ +static const long double SN[9] = { + 1.133374167243894382010E-3L, 7.220837261893170325704E-3L, 9.621911155035976733706E-3L, + -4.219773343731191721664E-2L, -1.665386113944413519335E-1L, -4.200263503402112910504E-2L, + 6.558780715202536547116E-1L, 5.772156649015328608727E-1L, -1.000000000000000000000E0L, +}; + +static const long double PIL = 3.1415926535897932384626L; + +/* Gamma function computed by Stirling's formula. + */ +static long double stirf(long double x) { + long double y, w, v; + + w = 1.0 / x; + /* For large x, use rational coefficients from the analytical expansion. */ + if (x > 1024.0) + w = (((((6.97281375836585777429E-5L * w + 7.84039221720066627474E-4L) * w - + 2.29472093621399176955E-4L) * + w - + 2.68132716049382716049E-3L) * + w + + 3.47222222222222222222E-3L) * + w + + 8.33333333333333333333E-2L) * + w + + 1.0; + else + w = 1.0 + w * __polevll(w, STIR, 8); + y = expl(x); + if (x > MAXSTIR) { /* Avoid overflow in pow() */ + v = powl(x, 0.5L * x - 0.25L); + y = v * (v / y); + } else { + y = powl(x, x - 0.5L) / y; + } + y = SQTPI * y * w; + return y; +} + +long double tgammal(long double x) { + long double p, q, z; + + if (!isfinite(x)) return x + INFINITY; + + q = fabsl(x); + if (q > 13.0) { + if (x < 0.0) { + p = floorl(q); + z = q - p; + if (z == 0) return 0 / z; + if (q > MAXGAML) { + z = 0; + } else { + if (z > 0.5) { + p += 1.0; + z = q - p; + } + z = q * sinl(PIL * z); + z = fabsl(z) * stirf(q); + z = PIL / z; + } + if (0.5 * p == floorl(q * 0.5)) z = -z; + } else if (x > MAXGAML) { + z = x * 0x1p16383L; + } else { + z = stirf(x); + } + return z; + } + + z = 1.0; + while (x >= 3.0) { + x -= 1.0; + z *= x; + } + while (x < -0.03125L) { + z /= x; + x += 1.0; + } + if (x <= 0.03125L) goto small; + while (x < 2.0) { + z /= x; + x += 1.0; + } + if (x == 2.0) return z; + + x -= 2.0; + p = __polevll(x, P, 7); + q = __polevll(x, Q, 8); + z = z * p / q; + return z; + +small: + /* z==1 if x was originally +-0 */ + if (x == 0 && z != 1) return x / x; + if (x < 0.0) { + x = -x; + q = z / (x * __polevll(x, SN, 8)); + } else + q = z / (x * __polevll(x, S, 8)); + return q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tgammal(long double x) { + return tgamma(x); +} +#endif diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 000000000..60a168d4c --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,2 @@ +bootserver +loglistener diff --git a/tools/BUILD.gn b/tools/BUILD.gn new file mode 100644 index 000000000..5ed4b33f0 --- /dev/null +++ b/tools/BUILD.gn @@ -0,0 +1,37 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +assert(host_toolchain == current_toolchain) + +executable("loglistener") { + configs = [] + sources = [ + "loglistener.c", + ] +} + +executable("mkbootfs") { + configs = [] + sources = [ + "mkbootfs.c", + ] +} + +executable("bootserver") { + configs = [] + sources = [ + "bootserver.c", + "netboot.h", + ] +} diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 000000000..ff8861dfe --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,24 @@ +# Copyright 2016 The Fuchsia Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all: bootserver loglistener + +bootserver: bootserver.c + gcc -Wall -o bootserver bootserver.c + +loglistener: loglistener.c + gcc -Wall -o loglistener loglistener.c + +clean: + rm -f bootserver loglistener diff --git a/tools/bootserver.c b/tools/bootserver.c new file mode 100644 index 000000000..9fa7a4bf6 --- /dev/null +++ b/tools/bootserver.c @@ -0,0 +1,252 @@ +// Copyright 2016 The Fuchsia Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "netboot.h" + +static uint32_t cookie = 1; +static char *appname; + +static int io(int s, nbmsg *msg, size_t len, nbmsg *ack) { + int retries = 5; + int r; + + msg->magic = NB_MAGIC; + msg->cookie = cookie++; + + for (;;) { + r = write(s, msg, len); + if (r < 0) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + continue; + } + fprintf(stderr, "\n%s: socket write error %d\n", appname, errno); + return -1; + } +again: + r = read(s, ack, 2048); + if (r < 0) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + retries--; + if (retries > 0) { + fprintf(stderr, "T"); + continue; + } + fprintf(stderr, "\n%s: timed out\n", appname); + } else { + fprintf(stderr, "\n%s: socket read error %d\n", appname, errno); + } + return -1; + } + if (r < sizeof(nbmsg)) { + fprintf(stderr, "Z"); + goto again; + } + if (ack->magic != NB_MAGIC) { + fprintf(stderr, "?"); + goto again; + } + if (ack->cookie != msg->cookie) { + fprintf(stderr, "C"); + goto again; + } + if (ack->arg != msg->arg) { + fprintf(stderr, "A"); + goto again; + } + if (ack->cmd == NB_ACK) return 0; + fprintf(stderr, "?"); + goto again; + } +} + +static void xfer(struct sockaddr_in6 *addr, const char *fn) { + char msgbuf[2048]; + char ackbuf[2048]; + char tmp[INET6_ADDRSTRLEN]; + struct timeval tv; + nbmsg *msg = (void*) msgbuf; + nbmsg *ack = (void*) ackbuf; + FILE *fp; + int s, r; + int count = 0; + + if ((fp = fopen(fn, "rb")) == NULL) { + fprintf(stderr, "%s: could not open file %s\n", appname, fn); + return; + } + if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + fprintf(stderr, "%s: cannot create socket %d\n", appname, errno); + goto done; + } + tv.tv_sec = 0; + tv.tv_usec = 250 * 1000; + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (connect(s, (void*) addr, sizeof(*addr)) < 0) { + fprintf(stderr, "%s: cannot connect to [%s]%d\n", appname, + inet_ntop(AF_INET6, &addr->sin6_addr, tmp, sizeof(tmp)), + ntohs(addr->sin6_port)); + goto done; + } + + msg->cmd = NB_SEND_FILE; + msg->arg = 0; + strcpy((void*) msg->data, "kernel.bin"); + if (io(s, msg, sizeof(nbmsg) + sizeof("kernel.bin"), ack)) { + fprintf(stderr, "%s: failed to start transfer\n", appname); + goto done; + } + + msg->cmd = NB_DATA; + msg->arg = 0; + do { + r = fread(msg->data, 1, 1024, fp); + if (r == 0) { + if (ferror(fp)) { + fprintf(stderr, "\n%s: error: reading '%s'\n", appname, fn); + goto done; + } + break; + } + count += r; + if (count >= (32*1024)) { + count = 0; + fprintf(stderr, "#"); + } + if (io(s, msg, sizeof(nbmsg) + r, ack)) { + fprintf(stderr, "\n%s: error: sending '%s'\n", appname, fn); + goto done; + } + msg->arg += r; + } while (r != 0); + + msg->cmd = NB_BOOT; + msg->arg = 0; + if (io(s, msg, sizeof(nbmsg), ack)) { + fprintf(stderr, "\n%s: failed to send boot command\n", appname); + } else { + fprintf(stderr, "\n%s: sent boot command\n", appname); + } +done: + if (s >= 0) close(s); + if (fp != NULL) fclose(fp); +} + +void usage(void) { + fprintf(stderr, + "usage: %s [